nyquist-3.05/0002755000175000000620000000000011537433132012167 5ustar stevestaffnyquist-3.05/lib/0002755000175000000620000000000011537433124012736 5ustar stevestaffnyquist-3.05/lib/time-delay-fns.lsp0000644000175000000620000000547411466723256016315 0ustar stevestaff;; a library of simple time delay functions (chorus, phaser, etc.) ;; ;; by Kathy Drye and Roger Dannenberg ;; phaser ;; The phaser uses all-pass filter to create the delay (defun phaser (s) (sim s (alpass s 1 20))) ;; an example ;(play (phaser (s-read "example1.wav"))) ;; nyq:snd-tapv -- handles multichannel input sounds ;; (defun nyq:snd-tapv (sound offset modulation maxdepth) (multichan-expand #'snd-tapv sound offset modulation maxdepth)) (defun delay-tapv (sound maxdelay delay depth rate saturation &optional (phase 0.0)) ;; delay a signal by delay plus a time-varying amount controlled ;; by an LFO (sine) and add to the original sound ;; delay + depth must be greater than zero and less than maxdelay ;; maxdelay is a scalar ;; rate is the frequency of the LFO ;; saturation is the amount of modulated signal added to the ;; original (normally 0 to 1) ;; (let ((modulation (sum delay (prod depth (lfo rate 10000.0 *sine-table* phase))))) ;; add sound with variable delay to sound with fixed delay (hp (sum (prod (nyq:snd-tapv sound 0.0 modulation maxdelay) saturation) sound) 10))) ;; flanger: ;; The flanging effect uses a time-varied delay ;; This version uses 0-20ms delay modulated at 0.2Hz, ;; with a saturation of 0.8. This flange does not use ;; feedback. (defun flange (input-sound) (delay-tapv input-sound .02 .01 .01 0.2 0.9)) ;; chorus effect ;; ;; chorus: ;; The chorus effect uses a time-varied delay ;; The delay is generally a longer delay with an lfo controlling ;; the delay operating around 0.3Hz (defun chorus (input-sound &key (delay 0.03) (depth 0.003) (rate 0.3) (saturation 1.0) (phase 0.0)) (delay-tapv input-sound (+ delay depth) delay depth rate saturation phase)) (defun stereo-chorus (input-sound &key (delay 0.03) (depth 0.003) (rate1 0.3) (rate2 0.1) (saturation 1.0)) (sim (pan (chorus input-sound :delay delay :depth depth :rate rate1 :saturation saturation) .3) (pan (chorus input-sound :delay delay :depth depth :rate rate1 :saturation saturation :phase 180.0) .7))) ;; examples ;(play (chorus (aref (s-read "example1.wav") 0))) ; ; you can apply different parameters to each channel using delay-tapv, ; e.g. here the rate is different on the left and right channels ; (works with mono or stereo input!) ;(play (delay-tapv (s-read "example1.wav") 0.1 0.05 0.005 (vector 0.4 0.1) 0.8)) ; ; the STEREO-CHORUS is intended for mono input. ;(play (stereo-chorus (mono-sound)) nyquist-3.05/lib/compress.lsp0000644000175000000620000003200111466723256015314 0ustar stevestaff; This code implements a compressor for noisy speech audio. ; There are actually two compressors that can be used in ; series. The first is ; a fairly standard one: it detects signal level with an RMS ; detector and used table-lookup to determine how much gain ; to place on the original signal at that point. One bit of ; cleverness here is that the RMS envelope is "followed" or ; enveloped using SND-FOLLOW, which does look-ahead to anticipate ; peaks before they happen. ; ; The other piece of high-tech is COMPRESS-MAP, which builds ; a map in terms of compression and expansion. What I recommend ; is figure out the noise floor on the signal you are compressing. ; Use a compression map that leaves the noise alone and boosts ; signals that are well above the noise floor. Alas, the COMPRESS-MAP ; function is not written in these terms, so some head-scratching is ; involved. Maybe I'll write another map generator if someone has a ; good application to test with. ; COMPRESS-MAP -- constructs a map for the compress function ; ; The map consists of two parts: a compression part and an expansion part. ; The intended use is to compress everything above compress-threshold by ; compress-ratio, and to downward expand everything below expand-ratio ; by expand-ratio. Thresholds are in dB and ratios are dB-per-dB. ; 0dB corresponds to a peak amplitude of 1.0 or rms amplitude of 0.7 ; If the input goes above 0dB, the output can optionally be limited ; by setting :limit (a keyword parameter) to T. This effectively changes ; the compression ratio to infinity at 0dB. If :limit is NIL ; (the default), then the compression-ratio continues to apply above 0dB. ; ; Another keyword parameter, :transition, sets the amount below the ; thresholds (in dB) that a smooth transition starts. The default is 0, ; meaning that there is no smooth transition. ; ; It is assumed that expand-threshold <= compress-threshold <= 0 ; The gain is unity at 0dB so if compression-ratio > 1, then gain ; will be greater than unity below 0dB ; RETURNS: a sound for use in the SHAPE function. The sound maps input ; dB to gain. Time 1.0 corresponds to 0dB, and Time 0.0 corresponds to ; -100 dB, and Time 2.0 corresponds to +100dB, so this is a ; 100hz "sample rate" sound. The sound gives gain in dB. ; Smooth transition equations: this is a parabola that makes a ; transition between two intersecting straight lines. The parabola ; matches the slope of the lines where it intersects them, and ; it intersects the first (left) line at location (u, v). The equation ; is: ; y = v + m(x-u) + d(s-m)((x-u)/d - (x-u)^2/(2d^2)) ; = v + m(x-u) + (s-m)((x-u) - (x-u)^2/(2d)) ; = v + m(x-u) + (s-m)((x-u) - (x-u)^2(s-m)/(4(b-v))) ; ; where s is the slope of the left line, the right line is expressed by ; y = mx+b, and ; d is the duration of the transition = 2(b-v)/(s-m) ; ; To show this is correct, show that (1) at the left intersection, the left ; line and the transition both pass through u,v and (2) have the same slope s, ; and show that (3) at the right intersection, the right line and the ; transition both meet at u+d and (4) have the same slope m. ; ; transition runs from u,v on left line to u+d on right line ; d = 2(v - mu - f)/(m - s), ; where right line is described by y = mx + f and left line slope = s ; c = (m - s)/2d ; b = s - 2cu ; a = v - bu - cu^2 ; ; transition is y = a + bx + cx^2 ; ; Now, show that curve meets left line at x = u ; (1) a + bx + cx^2 = v at x = u ; a + bu + cuu = v - bu - cuu + bu + cuu = v ; ; (2) slope at x = u is s: ; b + 2cu = s - 2cu + 2cu = s ; ; (3) curve meets right line at x = u + d ; a + b(u + d) + c(uu + 2ud + dd) = ; v - bu - cuu + bu + bd + cuu + 2cud + cdd = ; v + bd +2cud + cdd = ; v + (s - 2cu)d + 2cud + cdd = ; v + sd + cdd = ; v + sd + dd(m-s)/2d = ; v + sd + d(m-s)/2 = ; v + s(2(v - mu - f)/(m - s)) + (2(v - mu - f)/(m - s))(m-s)/2 = ; v + 2sv/(m-s) -2smu/(m-s) -2sf/(m-s) + v - mu - f = ; 2v + (2sv - 2smu - 2sf)/(m-s) - mu - f = ; 2v + 2s(v - mu - f)/(m-s) - mu - f = ; 2v + sd - mu - f ; try subtracting mx + b': ; 2v + sd - mu - f - m(u + d) - f = ; 2v + sd - 2mu - 2f - md = ; 2v + (s - m)d - 2mu - 2f = ; 2v + (s - m)2(v - mu - f) / (m - s) - 2mu - 2f = ; 0 ; (defun compress-map (compress-ratio compress-threshold expand-ratio expand-threshold &key (limit nil) (transition 0.0)) (display "compress-map" compress-ratio compress-threshold expand-ratio expand-threshold limit transition) (let (m s ; see equations above eupd ; eu + d cupd ; ct1 + d lim ; 0dB or infinity, depends on limit b2 ; y-intercept of the 1:1 part ea eb ec ca cb cc ; polynomial coefficients eu ev cu cv ; intersection points (u,v) ed cd ; d values lower-db upper-db ; function to compute map ; samples for map x ; loop value den ; denominator ) ; check input for good values: (cond ((> expand-threshold compress-threshold) (error "expand-threshold must be lower than compress threshold")) ((> compress-threshold 0) (error "compress-threshold must be at or below 0dB")) ((<= compress-ratio 0.0) (error "negative compress-ratio")) ((< expand-ratio 0.0) (error "negative expand-ratio")) ) ; set some constants (setf eu (- expand-threshold transition)) (setf cu (- compress-threshold transition)) (setf m (/ 1.0 compress-ratio)) (setf s expand-ratio) ; rename to match equations ; point where compression line intersects non-compression ; line is (* m compress-threshold), and cv is this point ; minus transition (since slope is one) (setf cv (- (* m compress-threshold) transition)) ; slope is 1 from compress-threshold to expand-threshold (setf ev (+ (* m compress-threshold) (- expand-threshold compress-threshold) (* s (- transition)))) ; the 1:1 part passes through cu,cv with slope of 1, so the y-intercept ; is cv-cu (setf b2 (- cv cu)) ; d = 2(v - mu - f)/(m - s) --note m = s, s = 1, f = 0 (setf den (- m 1.0)) (cond ((< (abs den) .001) (setf cd 0.0)) (t (setf cd (* 2 (- cv (* cu m)) (/ den))))) (setf cupd (+ cu cd)) (setf den (- 1.0 s)) (cond ((< (abs den) .001) (setf ed 0.0)) (t (setf ed (* 2 (- ev eu b2) (/ den))))) (setf eupd (+ eu ed)) ; ec = (1.0 - s)/(2*ed) (cond ((< (abs ed) 0.001) (setf ec 0.0)) (t (setf ec (/ (- 1.0 s) (* 2.0 ed))))) ; eb = s - 2*ec*eu (setf eb (- s (* 2.0 ec eu))) ; ea = ev - eb*eu - ec*eu*eu (setf ea (- ev (* eb eu) (* ec eu eu))) ; cc = (m - 1.0)/(2*cd) (cond ((< (abs cd) 0.001) (setf cc 0.0)) (t (setf cc (/ (- m 1.0) (* 2.0 cd))))) ; cb = s - 2*cc*cu (setf cb (- 1.0 (* 2.0 cc cu))) ; ca = cv - cb*cu - cc*cu*cu (setf ca (- cv (* cb cu) (* cc cu cu))) (cond (limit ; hard limit to 0dB (setf lim 0.0)) (t ; no hard limit, set limit to effectively infinity (setf lim 10000.0))) (display "compress-map" m s ; see equations above eupd ; et1 + d cupd ; ct1 + d lim ; 0dB or infinity, depends on limit b2 ; y-intercept of the 1:1 part ea eb ec ca cb cc ; polynomial coefficients eu ev cu cv ; intersection points (u,v) ed cd) ; d values ; now create function that goes 100dB below expansion threshold ; and up to 100dB (setf lower-db -100.0) (setf upper-db 100.0) (setf map (make-array 201)) (setf x lower-db) ; this should be an even integer (dotimes (i (length map)) (setf (aref map i) (cond ((< x eu) (+ ev (* s (- x eu)))) ((< x eupd) (+ ea (* eb x) (* ec x x))) ((< x cu) (+ cv (- x cu))) ((< x cupd) (+ ca (* cb x) (* cc x x))) ((< x lim) (* m x)) (t 0))) ; map[i] has the desired output dB, so subtract input dB to ; get gain: (setf (aref map i) (- (aref map i) x)) (cond ((and (> x (- eu 3)) (< x 0)) (format t "~A -> ~A~%" x (aref map i)))) (setf x (+ x 1))) ; return a sound (snd-from-array 0.0 100.0 map))) (defun db-average (input) (let (y) (setf y (mult input input)) ; first square input (setf y (snd-avg y 1000 500 op-average)) ; then time average (setf y (snd-log (scale 2.0 y))) ; peak normalization, then take log (setf y (scale (/ 10.0 (log 10.0)) y)) ; see below for scaling explanation y)) (defun compress (input map rise-time fall-time &optional (lookahead 0.0)) ; take the square of the input to get power (let ((in-squared (mult input input)) window avg env gain) (cond ((zerop lookahead) (setf lookahead rise-time))) ; compute the time-average (sort of a low-pass) of the square ; parameters give 50ms window and a 25ms step (setf window (round (* (snd-srate input) 0.05))) (setf avg (snd-avg in-squared window (/ window 2) op-average)) ; use follower to anticipate rise and trail off smoothly ; N.B.: the floor (2nd argument to snd-follow) should be the ; square of the noise floor, e.g. for a noise floor of 1/2^16, ; use 1/2^32 = about 4E-9. If the number is too small, you will ; not get expansion below the square root of the floor parameter. ; set lookahead to be number of samples in rise time: (setf lookahead (round (* lookahead (snd-srate avg)))) (setf env (snd-follow avg 0.000001 rise-time fall-time lookahead)) ; take logarithm to get dB instead of linear, also adjust for ; peak vs. average as follows: a sinusoid with peak of 1.0 has ; an average amplitude of 1/sqrt(2), we squared the signal, so ; the average amplitude should be 1/2, so multiply by 2 so ; that a sine with peak amplitude of 1 will get an average of 1 ; which will convert to 0dB (setf logenv (snd-log (scale 2.0 env))) ; tricky part: map converts dB of input to desired gain in dB ; this defines the character of the compressor ; map is scaled so that (0,2) corresponds to (-100dB, 100dB) ; so you need to scale input by .01. But first, we need to get dB: ; we have log(avg(x^2)), and we want dB = 20log10(sqrt(avg(x^2))) ; simplify dB to 10log10(avg(x^2)) = 10log(avg(x^2))/log(10), ; so scale by 10/log(10) * 0.01 = 0.1/log(10) (setf shaped-env (shape (setf gle (scale (/ 0.1 (log 10.0)) logenv)) map 1.0)) ; Go back to linear. To get from dB to linear, use: ; 20log(linear) = dB ; linear = exp(dB/20), ; so scale the result by 1/20 = 0.05 (setf gain (snd-exp (scale 0.05 shaped-env))) ; return the scaled input sound, ; another trick: avg signal will be delayed. Also, snd-follow ; has a delayed response because it's looking ahead in sound ; 20 = the number of samples of lookahead from snd-follow ; 88.2 = 44,100 (sample rate) / 500 (the step-size in avg) ; in other words, 44100/500 is the sample rate of the control ; signal looked at by follow ; "44100" should be replaced by the signal's sample rate ; = (snd-srate input) ; (setf gg gain) (sound-srate-abs (snd-srate input) ; set default sample rate for s-rest (mult (seq (s-rest (/ 20.0 (/ (snd-srate input) 500.0))) (cue input)) gain)))) ; this is an automatic gain control using peak detection for ; gain control -- the range parameter gives the maximum gain in dB ; the agc will attenuate peaks to 1.0. ; (defun agc (input range rise-time fall-time &optional (lookahead 0.0)) ; take the square of the input to get power (let (window avg env gain lookahead-samples) (cond ((zerop lookahead) (setf lookahead rise-time))) ; compute the time-average (sort of a low-pass) of the square ; parameters give 50ms window and a 25ms step (setf window (round (* (snd-srate input) 0.05))) (setf avg (snd-avg input window (/ window 2) op-peak)) ; use follower to anticipate rise and trail off smoothly ; set lookahead to be number of samples in rise time: (setf lookahead-samples (round (* lookahead (snd-srate avg)))) (setf env (snd-follow avg (db-to-linear (- range)) rise-time fall-time lookahead-samples)) (setf gain (snd-recip env)) ; return the scaled input sound, ; another trick: avg signal will be delayed. Also, snd-follow ; has a delayed response because it's looking ahead in sound ; 20 = the number of samples of lookahead from snd-follow ; 88.2 = 44,100 (sample rate) / 500 (the step-size in avg) ; in other words, 44100/500 is the sample rate of the control ; signal looked at by follow (sound-srate-abs (snd-srate input) ; set default sample rate for s-rest (mult (seq (s-rest lookahead) (cue input)) gain)) ;(vector ; (seq (s-rest lookahead) (cue input)) ; (mult (seq (s-rest lookahead) (cue input)) gain) ; (force-srate (snd-srate input) (scale 0.3 gain)))) )) nyquist-3.05/lib/dtmf.lsp0000644000175000000620000000221210144436365014406 0ustar stevestaff;; dtmf.lsp -- DTMF encoding functions ;; Rob Rost and Roger B. Dannenberg ;; This library takes a list of DTMF (touch-tone) digits and ;; synthesizes the correct audio. Example: ;; (speed-dial '(1 2 3 pound 5 6 star 7)) ;; Note how pound and star keys are entered. (setf dtmf-freqs '((star 941 1209) (0 941 1336) (pound 941 1477) (1 697 1209) (2 697 1336) (3 697 1477) (4 770 1209) (5 770 1336) (6 770 1477) (7 852 1209) (8 852 1336) (9 852 1477))) (defun dtmf-freq1 (key) (cadr (assoc key dtmf-freqs))) (defun dtmf-freq2 (key) (caddr (assoc key dtmf-freqs))) (defun dtmf-tone (key len space) (scale 0.5 (seq (stretch len (sim (hzosc (dtmf-freq1 key)) (hzosc (dtmf-freq2 key)))) (s-rest space)))) ; send it a list of digits and it returns the ; Sound object to dial that number (defun speed-dial (thelist) (cond ((null thelist) (s-rest 0)) (t (seq (dtmf-tone (car thelist) 0.2 0.1) (speed-dial (cdr thelist)))))) (defun dtmf-example () (play (speed-dial (list 4 1 2 5 5 5 1 2 1 2)))) (print "DTMF library loaded. Run (dtmf-example) for a sample output.") nyquist-3.05/lib/bandfx.lsp0000644000175000000620000001065610144436365014731 0ustar stevestaff;; bandfx -- audio effects based on separate frequency bands ;; ;; by Michael Mishkin and Roger B. Dannenberg ;; SEPARATE-INTO-BANDS -- separate sound s into frequency bands with ;; exponential spacing from p to p + inc * n. Filteres have a bandwidth ;; of inc and there are n bands. ;; The last band is not filtered. ;; (defun separate-into-bands (s p inc n) (let (bands width low-freq high-freq) (setf bands (make-array n)) (setf high-freq (step-to-hz p)) (dotimes (i (1- n)) (setf low-freq high-freq) (setf p (+ p inc)) (setf high-freq (step-to-hz p)) (setf width (- high-freq low-freq)) (setf (aref bands i) (reson s (+ low-freq (* 0.5 width)) width 1)) (setf s (areson s (+ low-freq (* 0.5 width)) width 1))) (setf (aref bands (1- n)) s) bands)) ;; SEPARATE-INTO-BANDS-RANGE -- separate signal s into num-bands bands ;; from the low to high step ;; (defun separate-into-bands-range (s low high num-bands) (let ((inc (/ (- high low) num-bands))) (separate-into-bands s low inc num-bands))) ;; RECONSTRUCT-FROM-BANDS -- reconstruct a signal from bands ;; (defun reconstruct-from-bands (bands) (let ((result (aref bands 0))) (dotimes (i (1- (length bands))) (setf result (sum result (aref bands (1+ i))))) result)) ;; BANDED-DELAY -- apply different delay to each band (channel) of bands. ;; del is the delay for the first band, and inc is the difference in ;; delay for each successive band. fb is the feedback for all delays. ;; (defun banded-delay (bands del inc fb wet) (let ((result (make-array (length bands)))) (dotimes (i (length bands)) (setf (aref result i) (sum (mult (- 1 wet) (aref bands i)) (mult wet (feedback-delay (aref bands i) del fb)))) (setf del (+ del inc))) result)) ;; APPLY-BANDED-DELAY -- apply banded delay effect to a sound ;; s is the sound to be processed ;; lowp, highp is the pitch range for the bands ;; num-bands is the number of bands ;; lowd, highd is the range of delays ;; fb is the feedback (same for all bands) ;; (note that if lowd > highd, delay decreases with increasing frequency) ;; (defun apply-banded-delay (s lowp highp num-bands lowd highd fb wet) (let (bands inc) (reconstruct-from-bands (banded-delay (separate-into-bands-range s lowp highp num-bands) lowd (/ (- highd lowd) num-bands) fb wet)))) (defun banded-bass-boost (bands num-boost gain) (let ((result (make-array (length bands)))) (dotimes (i (length bands)) (setf (aref result i) (scale (if (< i num-boost) gain 1.0) (aref bands i)))) result)) (defun apply-banded-bass-boost (s lowp highp num-bands num-boost gain) (reconstruct-from-bands (banded-bass-boost (separate-into-bands-range s lowp highp num-bands) num-boost gain))) (defun banded-treble-boost (bands num-boost gain) (let ((result (make-array (length bands))) (num-unity (- (length bands) num-boost))) (dotimes (i (length bands)) (setf (aref result i) (scale (if (< i num-unity) 1.0 gain) (aref bands i)))) result)) (defun apply-banded-treble-boost (s lowp highp num-bands num-boost gain) (reconstruct-from-bands (banded-treble-boost (separate-into-bands-range s lowp highp num-bands) num-boost gain))) ;; EXAMPLES ;; First, a few helper functions ;; CHECK-PIANO -- make sure pianosyn.lsp is loaded ;; (defun check-piano () (cond ((not (boundp '*pianosyn-path*)) (load "pianosyn")))) ;; PN-RIFF -- make a sound to which we can add effects ;; (defun pn-riff () (seq (seqrep (i 20) (set-logical-stop (piano-note 0.1 (+ (rem (* i 5) 48) c2) 100) 0.2)) (s-rest))) ;; Examples start with band-2. You can run examples in the IDE after ;; loading this file using the F2, F3, ... buttons in the IDE. (defun band-2 () (check-piano) (play (apply-banded-delay (pn-riff) c2 120 28 1.0 0.0 0.0 0.2))) (setfn f2 band-2) (defun band-3 () (check-piano) (play (apply-banded-delay (pn-riff) c2 120 28 0.0 1.0 0.0 0.2))) (setfn f3 band-3) (defun band-4 () (check-piano) (play (scale 0.4 (apply-banded-bass-boost (pn-riff) c2 120 28 5 10)))) (setfn f4 band-4) (defun band-5 () (check-piano) (play (scale 0.4 (apply-banded-treble-boost (pn-riff) c2 120 28 5 10)))) (setfn f5 band-5) (print "bandfx.lsp has been loaded. Try (f2) through (f5) for examples.") nyquist-3.05/lib/soften.lsp0000644000175000000620000000340610144436365014760 0ustar stevestaff;; soften.lsp -- this is code to "soften" harsh clipping ; ; it works by detecting peaks that exceed an absolute amplitude of 126/127 ; using SND-ONESHOT. Then the envelope is smoothed using SND-CHASE ; to produce a smooth cross-fade envelope. The envelope picks out the loud ; stuff to be filtered (try 4K) and an inverted envelope grabs the soft ; stuff which is unmodified except where the loud regions are clipped out. ; The sum of soft and filtered loud components is returned. ; ; Since clipping tends to generate harsh aliasing, the low-pass filter ; eliminates a lot of the problem, and the filter is usually on so ; briefly that you don't notice it. (defun square (x) (* x x)) ;; region for low-pass will be *soften-width* wide, with ;; *soften-crossfade* seconds of cross-fade (setf *soften-width* 0.02) (setf *soften-crossfade* 0.002) (defun soften-clipping (snd cutoff) (let (clip-region snd2 loud-stuff soft-stuff filtered-stuff) (setf clip-region (snd-oneshot (prod snd snd) (square (/ 126.0 127.0)) *soften-width*)) (setf clip-region (snd-chase clip-region *soften-crossfade* *soften-crossfade*)) ; s-rest needs a sample rate: (sound-srate-abs (snd-srate snd) (setf snd2 (seq (s-rest (/ *soften-width* 2)) (cue (scale 0.99 snd))) )) (setf loud-stuff (prod snd2 clip-region)) (setf soft-stuff (prod snd2 (sum 1 (scale -1 clip-region)))) (setf filtered-stuff (lp loud-stuff cutoff)) ; (vector filtered-stuff loud-stuff) (sum filtered-stuff soft-stuff) )) ;(defun tes () ; (sound-off) ; (let (snd) ; (setf snd (s-read "..\\..\\intro.aif")) ; (s-save (soften-clipping snd 4000) ny:all "temp.wav" :bits 16))) ; (tes) nyquist-3.05/lib/reverb.lsp0000644000175000000620000000340510144436365014746 0ustar stevestaff(defun reverb (x time) (multichan-expand #'reverb-mono x time)) (defun reverb-mono (ga irevfactor) (let (sr ilowpass idel ihz icsc acomball allp1 allp2 allp3 alow allp4 allp5 arevout) (setf sr (snd-srate ga)) (setf ilowpass 9000.000) ; frequency of lowpass filter (setf idel (list ; list of frequency/delay values (/ 1237.000 sr) (/ 1381.000 sr) (/ 1607.000 sr) (/ 1777.000 sr) (/ 1949.000 sr) (/ 2063.000 sr) (/ 307.000 sr) (/ 97.000 sr) (/ 71.000 sr) (/ 53.000 sr) (/ 47.000 sr) (/ 37.000 sr) (/ 31.000 sr))) ; Nyquist's comb filter uses Hz rather than delay as parameter, ; so take reciprocals to get Hz: (setf ihz (mapcar #'/ idel)) (setf icsc (list ; list of delay times (* irevfactor 0.822) (* irevfactor 0.802) (* irevfactor 0.773) (* irevfactor 0.753) (* irevfactor 0.753) (* irevfactor 0.753) (* irevfactor 0.7))) (setf acomball (sum (comb ga (nth 0 icsc) (nth 0 ihz)) (comb ga (nth 1 icsc) (nth 1 ihz)) (comb ga (nth 2 icsc) (nth 2 ihz)) (comb ga (nth 3 icsc) (nth 3 ihz)) (comb ga (nth 4 icsc) (nth 4 ihz)) (comb ga (nth 5 icsc) (nth 5 ihz)))) (setf allp1 (alpass acomball (nth 6 icsc) (nth 6 ihz))) (setf allp2 (alpass allp1 (nth 6 icsc) (nth 7 ihz))) (setf allp3 (alpass allp2 (nth 6 icsc) (nth 8 ihz))) (setf alow (lp allp3 ilowpass)) (setf allp4 (alpass alow (nth 6 icsc) (nth 9 ihz))) (setf allp5 (alpass allp4 (nth 6 icsc) (nth 11 ihz))) allp5 ; acomball )) nyquist-3.05/lib/statistics.lsp0000644000175000000620000003636611514640104015655 0ustar stevestaff;; statistics.lsp -- simple statistics functions ;; to compute statistics, create an object: ;; (setf stats (send statistics-class :new t)) ;; use t to retain the data and nil to not retain the data ;; then call (send stats :point x) for each x in the data set ;; call (send stats :print-stats) to print some statistics ;; see methods below for other methods, e.g. :get-mean ;; ;; to compute histograms, see comments below (setf statistics-class (send class :new '(count sum sum-sqr max min retain data))) (send statistics-class :answer :isnew '(ret) '((send self :init ret))) (send statistics-class :answer :init '(ret) '( (setf count 0 sum 0 sum-sqr 0 data nil max nil min nil retain ret data nil))) (send statistics-class :answer :point '(x) '( (incf count) (setf sum (+ sum x)) (setf sum-sqr (+ sum-sqr (* x x))) (setf max (if max (max max x) x)) (setf min (if min (min min x) x)) (if retain (push x data)))) (send statistics-class :answer :get-count '() '(count)) (send statistics-class :answer :get-data '() '(data)) (send statistics-class :answer :get-min '() '(min)) (send statistics-class :answer :get-max '() '(max)) (send statistics-class :answer :get-mean '() '( (if (> count 0) (/ (float sum) count) nil))) (send statistics-class :answer :get-stddev '() '( (if (> count 1) (sqrt (send self :get-variance)) nil))) (send statistics-class :answer :get-variance '() '( (if (> count 1) (/ (- sum-sqr (/ (* sum sum) (float count))) (1- count)) nil))) (send statistics-class :answer :print-stats '() '( (format t "Number of points: ~A~%Max: ~A~%Min: ~A~%" count max min) (if retain (format t "Median: ~A~%" (send self :get-median))) (format t "Mean: ~A~%Std.Dev.: ~A~%" (send self :get-mean) (send self :get-stddev)) )) (send statistics-class :answer :get-data '() '(data)) (send statistics-class :answer :get-median '() '( (let (i) (cond ((not retain) nil) ;; no data retained to examine ((< count 1) nil) ;; no data to compute from (t (setf data (bigsort data '<)) (cond ((oddp count) (nth (/ count 2) data)) (t (setf i (/ count 2)) (* 0.5 (+ (nth i data) (nth (1- i) data)))))))))) ;; This is the "usual estimator of the population kurtosis" based ;; on Wikipedia. In order for this to work, the statistics object ;; must be initialized to *retain* the data ;; (send statistics-class :answer :get-kurtosis '() '( (let ((x4 0) x2 (n (float count)) ; "n" is just a new name for count (mean (send self :get-mean)) (variance (send self :get-variance))) (dolist (x data) (setf x2 (* (- x mean) (- x mean))) (setf x4 (+ x4 (* x2 x2)))) (display "kurtosis" x4 (* variance variance) n) (if (> n 3) (- (* (/ (* (1+ n) n) (* (1- n) (- n 2) (- n 3))) (/ x4 (* variance variance))) (/ (* 3 (1- n) (1- n)) (* (- n 2) (- n 3)))) nil)))) ;; :FRACTION-IN-RANGE -- proportion of values in a range ;; (send statistics-class :answer :fraction-in-range '(low high) '( (let ((n 0)) (dolist (d data) (if (and (<= low d) (< d high)) (setf n (1+ n)))) (/ (float n) count)))) ;; The histogram-class. Make a histogram from data. ;; ;; To use histogram-class, first make an instance: ;; (setf my-histogram (send histogram-class :new)) ;; Then add points to the histogram. For each point x: ;; (send my-histogram :point x) ;; You can make a default histogram by calling: ;; (send my-histogram :configure-bins) ;; This will create the square root of N bins where N is the ;; number of points. The bins are evenly distributed across ;; the range of the data. ;; Alternatively, you can provide your own thresholds to ;; determine the bins by calling: ;; (send my-histogram :set-thresholds an-array) ;; Each element of an-array represents the lower bound for ;; elements in that bin. E.g. if x is a point, it goes in ;; bin 3 if (aref an-array 3) <= x < (aref an-array 4) ;; Note that nothing goes into bin L-1 where L is the length ;; of an-array. ;; To actually compute the histogram, call ;; (send my-histogram :make-hist) ;; And then you can print or plot it with: ;; (send my-histogram :print-hist) or ;; (send my-histogram :plot-hist) ;; You can change the thresholds with :set-thresholds or ;; :configure-bins without re-inserting all the points. ;; You can start over by calling ;; (send my-histogram :init) ;; but this probably has no advantage over making a new ;; instance. (setf histogram-class (send class :new '(stats counts thresholds))) (send histogram-class :answer :isnew '() '((send self :init))) (send histogram-class :answer :init '() '( (setf counts nil thresholds nil) ; create stats object and tell it to retain points (setf stats (send statistics-class :new t)))) (send histogram-class :answer :point '(x) '( (send stats :point x))) (send histogram-class :answer :configure-bins '() '( (let* ((nbins (round (sqrt (float (send stats :get-count))))) (minthreshold (send stats :get-min)) (step (/ (- (send stats :get-max) (send stats :get-min)) nbins))) (setf thresholds (make-array (1+ nbins))) (dotimes (i (1+ nbins)) (setf (aref thresholds i) (+ minthreshold (* i step))))) thresholds)) (send histogram-class :answer :set-thresholds '(array) '( (setf counts nil) (setf thresholds array))) (send histogram-class :answer :make-hist '(&key (verbose t)) '( (let* ((data (send stats :get-data)) (counter 0) (data-position 0)) (if (null thresholds) (send self :configure-bins)) (cond ((null counts) (setf counts (make-array (1- (length thresholds)))) (dotimes (i (length counts)) (setf (aref counts i) 0)))) (dolist (x data) (cond ((and verbose (> counter 100000)) (format t "make-hist ~A% done\n" (* 100 (/ data-position (float (send stats :get-count))))) (setf counter 0))) ; increment the right bin -- allows different bin sizes but ; could use a binary search for the right bin (dotimes (i (length counts)) (incf counter) (cond ((and (< x (aref thresholds (1+ i))) (>= x (aref thresholds i))) (incf (aref counts i)) (return)))) (incf data-position)) ))) (send histogram-class :answer :print-hist '() '( (if (null counts) (send self :make-hist)) (dotimes (i (length counts)) (format t "~A to ~A: ~A~%" (aref thresholds i) (aref thresholds (1+ i)) (aref counts i))))) (send histogram-class :answer :plot-hist '(&optional (offset 0)) '( (if (null counts) (send self :make-hist)) (s-plot (snd-from-array 0 (/ (- (aref thresholds 1) (aref thresholds 0))) counts)))) (send histogram-class :answer :get-min '() '( (send stats :get-min))) (send histogram-class :answer :get-max '() '( (send stats :get-max))) (send histogram-class :answer :get-count '() '( (send stats :get-count))) (send histogram-class :answer :get-counts '() '( counts)) (send histogram-class :answer :get-thresholds '() '( thresholds)) ;; Pearson correlation - direct (unstable) algorithm ;; ;; I created this to get the "true" answer when I was trying to ;; debug the more complex version below. All three algorithms here ;; now agree (within numerical roundoff), and I believe the ;; pearson-class below is the best implementation. -RBD ;; ;(setf upearson-class (send class :new '(sumxy sumx sumy sumxx sumyy n))) ; ;(send upearson-class :answer :isnew '() '((send self :init))) ;(send upearson-class :answer :init '() '( ; (setf sumxy 0 sumx 0 sumy 0 sumxx 0 sumyy 0 n 0))) ;(send upearson-class :answer :points '(x y) '( ; (setf sumxy (+ sumxy (* x y))) ; (setf sumx (+ sumx x)) ; (setf sumy (+ sumy y)) ; (setf sumxx (+ sumxx (* x x))) ; (setf sumyy (+ sumyy (* y y))) ; (setf n (+ n 1)))) ;(send upearson-class :answer :correlation '() '( ; (/ (- (* n sumxy) (* sumx sumy)) ; (* (sqrt (- (* n sumxx) (* sumx sumx))) ; (sqrt (- (* n sumyy) (* sumy sumy))))))) ;; Pearson correlation ;; (setf pearson-class (send class :new '(sum-sq-x sum-sq-y sum-coproduct mean-x mean-y n))) (send pearson-class :answer :isnew '() '((send self :init))) (send pearson-class :answer :init '() '( (setf n 0) (setf sum-sq-x 0 sum-sq-y 0 sum-coproduct 0))) (send pearson-class :answer :points '(x y) '( (cond ((zerop n) (setf mean-x x mean-y y n 1)) (t (setf n (1+ n)) (let* ((sweep (/ (- n 1.0) n)) (delta-x (- x mean-x)) (delta-y (- y mean-y))) (setf sum-sq-x (+ sum-sq-x (* delta-x delta-x sweep))) (setf sum-sq-y (+ sum-sq-y (* delta-y delta-y sweep))) (setf sum-coproduct (+ sum-coproduct (* delta-x delta-y sweep))) (setf mean-x (+ mean-x (/ delta-x n))) (setf mean-y (+ mean-y (/ delta-y n)))))))) (send pearson-class :answer :correlation '() '( (let* ((pop-sd-x (sqrt (/ sum-sq-x n))) (pop-sd-y (sqrt (/ sum-sq-y n))) (cov-x-y (/ sum-coproduct n))) (/ cov-x-y (* pop-sd-x pop-sd-y))))) ;; This is a very direct implementation of the algorithm below, ;; but it stores the points -- I created this for debugging but ;; I don't see any reason to use it now. -RBD ;(setf npearson-class (send class :new '(pts))) ;(send npearson-class :answer :isnew '() '((send self :init))) ;(send npearson-class :answer :init '() '((setf pts nil))) ;(send npearson-class :answer :points '(x y) '( ; (setf pts (cons (cons x y) pts)))) ;(send npearson-class :answer :correlation '() '( ; (setf pts (reverse pts)) ; (let ((sum-sq-x 0) (sum-sq-y 0) (sum-coproduct 0) (mean-x (caar pts)) ; (mean-y (cdar pts)) i (n (length pts))) ; (dotimes (j (1- n)) ; (let* ((i (+ j 2)) ; (sweep (/ (- i 1.0) i)) ; (delta-x (- (car (nth (1- i) pts)) mean-x)) ; (delta-y (- (cdr (nth (1- i) pts)) mean-y))) ; (setf sum-sq-x (+ sum-sq-x (* delta-x delta-x sweep))) ; (setf sum-sq-y (+ sum-sq-y (* delta-y delta-y sweep))) ; (setf sum-coproduct (+ sum-coproduct (* delta-x delta-y sweep))) ; (setf mean-x (+ mean-x (/ delta-x i))) ; (setf mean-y (+ mean-y (/ delta-y i))))) ; (let ((pop-sd-x (sqrt (/ sum-sq-x n))) ; (pop-sd-y (sqrt (/ sum-sq-y n))) ; (cov-x-y (/ sum-coproduct n))) ; (/ cov-x-y (* pop-sd-x pop-sd-y)))))) ;; the algorithm (from Wikipedia) ;sum_sq_x = 0 ;sum_sq_y = 0 ;sum_coproduct = 0 ;mean_x = x[1] ;mean_y = y[1] ;for i in 2 to N: ; sweep = (i - 1.0) / i ; delta_x = x[i] - mean_x ; delta_y = y[i] - mean_y ; sum_sq_x += delta_x * delta_x * sweep ; sum_sq_y += delta_y * delta_y * sweep ; sum_coproduct += delta_x * delta_y * sweep ; mean_x += delta_x / i ; mean_y += delta_y / i ;pop_sd_x = sqrt( sum_sq_x / N ) ;pop_sd_y = sqrt( sum_sq_y / N ) ;cov_x_y = sum_coproduct / N ;correlation = cov_x_y / (pop_sd_x * pop_sd_y) ;; Welch's t-test to test the null hypothesis that 2 population means are ;; equal when the variances might be unequal ;; ;; returns list: (welchs-t degrees-of-freedom) ;; (defun welchs-t-test (mean1 stddev1 n1 mean2 stddev2 n2) (let* ((var1 (* stddev1 stddev1)) (var2 (* stddev2 stddev2)) (num (- mean1 mean2)) (den (sqrt (+ (/ var1 n1) (/ var2 n2)))) (welchs-t (/ num den)) (dof-a (+ (/ var1 n1) (/ var2 n2))) (dof-num (* dof-a dof-a)) (dof-den (+ (/ (* var1 var1) (* n1 n1 (- n1 1))) (/ (* var2 var2) (* n2 n2 (- n2 1))))) (dof (/ dof-num dof-den))) (list welchs-t dof))) ;; Levene's test to assess the equality of variances in different samples ;; based on Wikipedia article. This implementation is for 2 groups. If the ;; 2 groups can be assumed to be normal (Gaussian), then the F-test should ;; be considered. ;; ;; A variation on Levene's test is the Brown-Forsythe test, which uses ;; medians instead of means. The optional parameter, brown-forsythe can ;; be set to true to get a Browne-Forsythe test instead of Levene's test. ;; ;; The verbose flag defaults to t and prints some useful information ;; ;; The input to levenes-test is a pair of lists of samples. The return ;; value is W (see Wikipedia for details) ;; (defun levenes-test (y1 y2 &optional brown-forsythe (verbose t)) (let* ((n1 (float (length y1))) (n2 (float (length y2))) (n (+ n1 n2)) m1 m2 z1 z2 z.. z1. z2. stat (den 0) w) ;; compute means or medians (cond (brown-forsythe (setf m1 (vector-median y1)) (setf m2 (vector-median y2))) (t (setf m1 (vector-mean y1)) (setf m2 (vector-mean y2)))) ;; compute zij (lists z1 and z2) (dolist (y1j y1) (push (abs (- y1j m1)) z1)) (dolist (y2j y2) (push (abs (- y2j m2)) z2)) ;; compute zi. sums (setf z1. (vector-sum-elements z1)) (setf z2. (vector-sum-elements z2)) ;; compute z.. (setf z.. (/ (+ z1. z2.) n)) ;; convert zi. variables from sums to means (setf z1. (/ z1. n1)) (setf z2. (/ z2. n2)) ;; compute the big denominator term (dolist (z1j z1) (let ((diff (- z1j z1.))) (setf den (+ den (* diff diff))))) (dolist (z2j z2) (let ((diff (- z2j z2.))) (setf den (+ den (* diff diff))))) ;; compute w (setf w (* (- n 2) (/ (+ (* n1 (* (- z1. z..) (- z1. z..))) (* n2 (* (- z2. z..) (- z2. z..)))) den))) ;; print info if verbose (cond (verbose (format t "Summary of ~A test results: Size of group 1: ~A, ~A: ~A Size of group 2: ~A, ~A: ~A W (result): ~A The significance of W is tested against F(alpha, 1, ~A), where alpha is the level of significance (usually 0.05 or 0.01), and ~A is N-2.~%" (if brown-forsythe "Brown-Forsythe" "Levene's") n1 (if brown-forsythe "Median" "Mean") m1 n2 (if brown-forsythe "Median" "Mean") m2 w (- n 2) (- n 2)))) w)) ;; a simple test for levenes-test ;; this program uses distributions.lsp, which must be explicitly loaded ;; (defun levenes-test-test () (let (y1 y2 y3) ;; make some data with sigma 0.1 and 0.2 (dotimes (i 50) (push (gaussian-dist 1.0 0.1) y1)) (dotimes (i 75) (push (gaussian-dist 1.0 0.2) y2)) (dotimes (i 75) (push (gaussian-dist 1.0 0.1) y3)) (format t "\nTHE FOLLOWING HAVE UNEQUAL VARIANCE\n") (levenes-test y1 y2) ;; levene's test (format t "\n") (levenes-test y1 y2 t) ;; brown-forsythe test (format t "\nTHE FOLLOWING HAVE EQUAL VARIANCE\n") (levenes-test y1 y3) ;; levene's test (format t "\n") (levenes-test y1 y3 t) ;; brown-forsythe test (format t "\n") 'done )) nyquist-3.05/lib/vectors.lsp0000644000175000000620000000626411514640104015142 0ustar stevestaff;; vectors.lsp -- a small simple vector package ;; ;; vectors are lists, not arrays ;; probably one should be able to use either form (list or array) ;; and functions should accept either (defun vector-from-array (x) (let (v (n (length x))) (dotimes (i n) (setf v (cons (aref x (- n i 1)) v))) v)) (defun vector-cosine (x y) (/ (vector-dot x y) (vector-norm x) (vector-norm y))) (defun vector-dot (x y) (let ((d 0)) (dolist (e x) (setf d (+ d (* e (car y)))) (setf y (cdr y))) d)) ;; VECTOR-NORM -- also Euclidean distance ;; (defun vector-norm (x) (sqrt (float (vector-sum-elements (vector-square x))))) (defun vector-sum-elements (x) (let ((sum 0)) (dolist (e x) (setf sum (+ sum e))) sum)) (defun vector-sum (a b) (let (v) (dolist (e a) (setf v (cons (+ e (car b)) v)) (setf b (cdr b))) (reverse v))) (defun vector-mean (x) (/ (vector-sum-elements x) (length x))) ;; vector-median uses statistics.lsp -- you must load this explicitly ;; before calling vector-median ;; (defun vector-median (x) (let ((stats (send statistics-class :new t))) (dolist (e x) (send stats :point e)) (send stats :get-median))) (defun vector-offset (x c) (let (v) (dolist (e x) (setf v (cons (+ e c) v))) (reverse v))) (defun vector-difference (a b) (let (v) (dolist (e a) (setf v (cons (- e (car b)) v)) (setf b (cdr b))) (reverse v))) (defun vector-divide (a b) (let (v) (dolist (e a) (setf v (cons (/ e (car b)) v)) (setf b (cdr b))) (reverse v))) (defun vector-scale (x c) (let (v) (dolist (e x) (setf v (cons (* e c) v))) (reverse v))) (defun vector-zero (len) (let (v) (dotimes (i len) (setf v (cons 0.0 v))))) (defun vector-square (a) (let (v) (dolist (e a) (setf v (cons (* e e) v))) (reverse v))) (defun vector-variance (x) (let ((n (length x)) (sum 0.0) (sum-sqr 0.0)) (dotimes (i n) (setf sum (+ sum (car x))) (setf sum-sqr (+ sum-sqr (* (car x) (car x)))) (setf x (cdr x))) (/ (- sum-sqr (/ (* sum sum) n)) (1- n)))) (defun vector-stddev (x) (sqrt (vector-variance x))) ;; compute autocorrelation with lag1 <= lag < lag2 ;; note that because of different overlap, the autocorrelation ;; will be over different numbers of points (but normalized ;; by dividing by the length). Note: It should be true that ;; 0 <= lag1 < lag2 < length(x) ;; Otherwise, nil is returned. ;; ;; Algorithm notes: len is length of input, ;; rsltlen is length of result. The range of lags is ;; from 0 to len - 1. ;; (defun vector-autocorrelation (x lag1 lag2) (prog ((len (length x)) rsltlen rslt y) ;; return nil if lag conditions are not satisfied (if (and (<= 0 lag1) (< lag1 lag2) (< lag2 len)) 'ok (return nil)) (setf rsltlen (- lag2 lag1)) (setf y (nthcdr lag1 x)) (dotimes (i rsltlen) (let ((xp x) (yp y) (sum 0.0) (alen (- len (+ lag1 i)))) (dotimes (j alen) (setf sum (+ sum (* (car xp) (car yp)))) (setf xp (cdr xp) yp (cdr yp))) (setf rslt (cons (/ sum alen) rslt)) (setf y (cdr y)))) (return (reverse rslt)))) nyquist-3.05/lib/surround.lsp0000644000175000000620000002160611466723256015353 0ustar stevestaff;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SURROUND.LSP -- Implements Dolby Pro-Logic encoding ; and a 2D Sound Positioning Scheme ;; ;; Dave Borel (dborel) with minor changes by ;; Roger B. Dannenberg ;; ;; Features: ;; -Dolby Pro-Logic panning ;; -Doppler for moving sounds ;; -Distance attenuation ;; -Atmospheric damping of high frequencies ;; -Progagation delay ;; -Test programs (setf config 1) ;Distance between listener and speakers ;--------------------------------------------------- ; Math Helpers ;--------------------------------------------------- ; ; Distance between two points ; (defun dist (x0 y0 x1 y1) (let* ( (rx (sum x1 (mult -1.0 x0))) (ry (sum y1 (mult -1.0 y0))) ) (s-sqrt (sum (mult rx rx) (mult ry ry))))) ; ; Raise x to each sample of snd ; (defun s-expt (x snd) (s-exp (mult (s-log x) snd))) ;--------------------------------------------------- ; Signal Processing ;--------------------------------------------------- ;; ;; DOLBY HELPERS: ;; ; ; Smooth FFT Frame Iterator ; (Inspired by Dannenberg's fft example) ; (defun raised-cosine () (scale 0.5 (sum (const 1) (lfo (/ 1.0 (get-duration 1)) 1 *sine-table* 270)))) (defun fft-window (frame-size) (control-srate-abs frame-size (raised-cosine))) (setf fft-class (send class :new '(sound length skip window))) (send fft-class :answer :next '() '( (snd-fft sound length skip window))) (send fft-class :answer :isnew '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp) (setf window (fft-window len)) )) (defun make-fft-iterator (sound length skip) (send fft-class :new (snd-copy sound) length skip)) ;; ;; SPATIALIZATION HELPERS: ;; ; ; Doppler effect ; (defun doppler (snd r) (let* ( (v (mult -1 (slope r))) (ratio (recip (sum 1 (mult v (recip 344.31))))) (map (integrate ratio)) ) (sound-warp map snd) )) ; ; Distance-based low-pass filter ; (see report) ; (defun absorb (snd r_m) (lp snd (mult 14763.67 (s-expt 0.97895 r_m)))) ; ; Distance-based attenuation ; (see report) ; (defun atten (snd r) ; (let* ( (log2_r (mult (s-log r) (recip (log 10.0)))) ; (db_ratio (mult 20 log2_r)) ; (ratio (db-to-linear db_ratio)) ) ; ; (mult (clip ratio 1.0) snd))) (mult snd (clip (recip (mult r r)) 1))) ; ; Top-level spatializer ; sound source at (x,y) ; speaker at (xs, ys) ; assumes listener at (0,0) ; ; You could use this with ; configurations other than ; pro-logic (e.g. 6.1, 7.1, etc) ; (defun stage (snd x y xs ys) (let* ( (r (dist x y 0 0)) (rs (dist xs ys 0 0)) (x_hat (mult x (recip r))) (y_hat (mult y (recip r))) (xs_hat (mult xs (recip rs))) (ys_hat (mult ys (recip rs))) (dot (sum (mult x_hat xs_hat) (mult y_hat ys_hat))) (overlap (mult 0.5 (sum dot (s-abs dot)))) ) (mult overlap snd))) ;--------------------------------------------------- ; Speaker Mixing ;--------------------------------------------------- ; ; Dolby Pro-Logic Encoder ; (defun prologic (left center right surround) (let* ( (c (scale 0.5 center)) (s (highpass2 (lowpass2 (scale 0.5 surround) 7000) 100) ) (slfe (scale 0.25 (lp surround 100))) (l (sim left center (mult -1.0 s) slfe)) (r (sim right center s slfe)) ) (vector l r))) ; ; Direct-to-speaker playback ; (defun pl_left (snd) (let ((s (mult 0 snd))) (prologic snd s s s))) (defun pl_center (snd) (let ((s (mult 0 snd))) (prologic s snd s s))) (defun pl_right (snd) (let ((s (mult 0 snd))) (prologic s s snd s))) (defun pl_rear (snd) (let ((s (mult 0 snd))) (prologic s s s snd))) ; ; Pans a sound across the surround speakers ; (no realistic imaging or attenuation) ; Works like pan but y specifies depth (defun pan2d (s_in x y) (let ((snd (scale 0.5 s_in))) (prologic (mult snd (sum 1.0 (mult -1.0 x) (sum 1 (mult -1.0 y))) );left (mult snd 0.0) ;center(null) (mult snd x (sum 1.0 (mult -1.0 y) )) ;right (mult snd y 0.5)))) ;rear ; ; Position a sound in the 2D soundstage ; Includes spatialization effects ; ; (x,y) may be (flonum, flonum) or (behavior, behavior) ; (defun position (s_in x y config) (let* ( (r_m (dist x y 0 0)) (r (mult r_m (recip config))) (spd_snd (/ 344.31 config)) (offset (if (soundp r_m) (/ (aref (snd-samples r 1) 0) spd_snd) (/ r spd_snd))) (snd (seq (s-rest offset) (if (soundp r_m) (atten (absorb (doppler s_in r_m) r_m) r) (atten (absorb s_in r_m) r)))) ) ; Two Notes: ; 1.) The center channel is automatically imaged correctly ; because sounds placed between the left-and-right channels ; distribute linearly between the two channels. ; ; 2.) Although the below settings assume that all speakers are ; equidistant from the listener, you can easily assume a ; different layout by modifying the xs and ys values in ; each channel's call to the stage function. ; (prologic (stage snd x y -.1913 -.4619) ;left (scale 0.0 snd) ;center (null) (stage snd x y .1913 -.4619) ;right (stage snd x y 0.0 .5 )))) ;rear ;--------------------------------------------------- ; Diagnostics ;--------------------------------------------------- ; ; Pro-Logic Channel Test Tones ; (defun pl_test () (play (prologic ( osc-note a3 ) (seq (s-rest 1.25) (osc-note b3)) (seq (s-rest 2.5 ) (osc-note c4)) (seq (s-rest 3.75) (osc-note d4)) ))) ; ; Pan Test ; (defun pan_test () (play (pan2d (seq (s-rest .25) (osc a3 .75) (s-rest .25) (osc b3 .75) (s-rest .25) (osc c4 .75) (s-rest .25) (osc d4 .75)) (pwl 0 0 0.99 0 1 1 2.99 1 3 0 4 0 4 ) (pwl 0 0 1.99 0 2 1 4 1 4 )))) ; ; Doppler test ; (defun dop () (play (doppler (osc c4 10) (pwl .25 0 .5 100 .75 100 1.0)))) ; ; Attenuation test ; (defun att () (play (atten (osc-note c4 4) (pwl 0 2 1 2 2 100 3 100 4 2 4 )))) ; ; Doppler positioning test (ambulance) ; (defun ambulance () (play (scale 0.2 (position (stretch 16 (fmosc c4 (mult 1000 (lfo 2)))) (pwl 0 -20 8 20 8 ) (pwl 0 0 8 ) config)))) ; ; Position test ; ; Make a sound orbit the listener (defun orbit_x (r t times) (let (k) (seqrep (k times) (pwl 0.0 0.0 (/ t 4) r (/ t 2) 0.0 (/ (* t 3) 4) (* -1 r) t 0.0 t ) ))) (defun orbit_y (r t times) (let (k) (seqrep (k times) (pwl 0.0 (* -1 r) (/ t 4.0) 0.0 (/ t 2.0) r (/ (* t 3.0)4.0) 0.0 t (* -1 r) t ) ))) (defun orbit (snd r t times) (position snd (orbit_x r t times) (orbit_y r t times) config)) ; Play some tones (defun pos_1 () (play (position (seq (s-rest .125) (osc a3 1.75) (s-rest .25) (osc b3 1.75) (s-rest .25) (osc c4 1.75) (s-rest .25) (osc d4 1.75) (s-rest .125)) (pwl 0 -5 1 5 2 5 3 -5 4 -5 5 5 6 5 7 -5 8 -5 8 ) (pwl 0 -5 1 -5 2 5 3 5 4 -5 5 -5 6 5 7 5 8 -5 8 ) config))) (defun pos_2 () (play (seq (orbit (seq (s-rest .125) (osc a3 1.75) (s-rest .25) (osc b3 1.75) (s-rest .25) (osc c4 1.75) (s-rest .25) (osc d4 1.75) (s-rest .125)) 5 8 1) (orbit (seq (s-rest .125) (osc a3 1.75) (s-rest .25) (osc b3 1.75) (s-rest .25) (osc c4 1.75) (s-rest .25) (osc d4 1.75) (s-rest .125)) 5 8 1)))) nyquist-3.05/lib/piano/0002755000175000000620000000000011537433124014044 5ustar stevestaffnyquist-3.05/lib/piano/pn07.cod0000644000175000000620000003305010144436365015321 0ustar stevestaffSYNCCNDNCOMMC L;lo=PART????????????>T?`>|A>!?1vZ>׭J>3;>-;>&>>b?#ۯ?>?>->e>p>`>j|=T>#>">6===-q=<= =C>T===Mq=`<(::v:::}j:㫸:_:d:ks:::N:m:ݷ:۷::ս: ::$: :R2:d:9:q::Ǚ:o,::/:n:I:Ę#:~:Þ::):=:HH::a:Q::ء: (:T:Ӭ:0:J::{:B:U5::U:_ :7j1 }Klq|T@ @4m)/{;?(?Mʼ^?(j-@'@D?˜޾G?K>?K2@!@H1mو?Fq 2?&>۩@@@5Q@ VRu?'9@O ¿`y@&J@;@2@Q@9_Si3Y@*<@@u@=)K> п>GM@iC@JGkۿR?|E@ZFk?xnh'@\i8 .?)n?+@u@@nB̴?Z?ѫ#@+??,g?]?~@@&?!;>X@΢@H@`@6g@f@0#s@=@j]J@67>&@J>A@l['@[@j@`@f8?n>Y<@P>̭N5@Z8?>=?A@k@n@@:q@(>N @:@ @59@c@<@YJٿ@9x@pBe?>l?"?P@ @Ԧ?3 @@V3> GRUP?@@@@@@@AAA A0A@APAAA?@@@@@@@AAA A0A@ApAACGMAG<=4=>>?lV?cj??_J?1M?te?J?.?7@?-P?2?;Oh?9?/?0?F?K?B?A?Hd\?K?Hm?Be?9]?4O?/D?/|g?1O?6?4 ?)?&V*?'P?$7r?"R>?!N?"?S?9d?%?9?j?̯? ?|?p8?"? ?aj? _? 9? m? k?D? ??ٺ>!>=v>z>d>b> >j>>ͳ>9>>x> >>>(:>>>J >w>>7>af> #>*>p?>s>>Qr>̕6>>ɺ>(>ȅ7>.>v>>¡>> >%>o>)3>W>U>0>->ox>>;>R>>n>">>>[>>2>qc>y>ȶ>?1> >7>u>b,>P4J>?y>2>%#o>=>2>=(=B=F;=)8=N=o====j=SV(=F=4R=)m=]=9=r=<<<<ч<<ͮ.y_?R?z??a%u?;R??'? >>>"><>Yy>>>?0R>T4>j>F> >2/>j>]l>@*>20>*b>V8>$>,U>>+>6>F~>Jn->OH>X!>h>nۅ>ng>m">o >nm>o\>d k>U>HV>C>=Q>7f>1!>.>.>1 >2.>5 >3>8{>:>?u>D/>Kb>QY>X3>Y@>[>Y}>X>T*>U3>S>S~N>Q5>OzY>K>J>G>E>B>A>?%E>=r>;>:>9yj>9Ֆ>8ٿ>9>9`>9{>9,>8x+>7>6q>4v>3>1/>/>->,x>*3>(>(>&>&z>%>#>">"|>!`H> o>W>k>>o_> >>>>+;>">=꒨=u=> ==m9=Bp="=F<9<8<дI-?G?x?7?Mw'?m??z?h+?TR?[?bJe?fI?k*e?l:2?ai?Y?V?[?Xn:?Tm.?M ?Pȷ?R?R?M?G??5???>?>ȩ?:?4?1,?.3?-i?-?,g?*?(?&?'hm?(V?*;?)??)/?).?*7?*F%?(?'?&e?&h ?&-?$m?#Uj?!x?!d? "?=e??o???b???v!?d?S??˹???Ő?pe??$3??? r? A? #b? Z? ? ?'? ?`0?{i?ʔ??\:??J?Y??>k>>Q>gH>p>-:>#>]>T>b;>l>>N>Y>*>>>߸>> !>>>v>#7>>ߣO>U>,>3>]>!>X>G>Ɨ>o>]=>M >< >-h>x>W>!=%=ۓ,=Ǩ=B=S=׋=H(=q_A=^;=Rq=Ku=E=D=G^=K=P;-=V=^_0=d4v=jD=oT=s=w=x=z=z,&=y=v-f=sS=oS7=k=e=]d=W`=N=EQ=<:=2='=P= S=<ͫ< <>E<<?d>>> >>!>>>;>Ǝ>ZZ>F;>٢>>Ͼ>W]>kv>A~>ݭ>ܸ>q~>Ǹ>w>m>W>>Є>@>^>Q>VK>H>'>;C>k>m>V7>U>0s>>@>e >$Z>x>t>l>'>o>x>>L>N&>%>7c>>T>>r_>k'>>M >>~ņ>nc>`Y>Q>E[>7c>)>b> >HG={==Z=YT=*==`=B=,=,=né?\?mI6?gZ?b ?dѢ?mru?z??v ?u?z?|Hd?os?]c2?\#?_?;?9-?6a?3?3x?1rc?/d?-?*?)ƫ?'V?&*?$e?#?"'?!w??J?y? ???F??L??D?X?B?%?? Q??C? ? U? *? ? ]Y?YG??1?4?D?F?W1?K???\>>@>Vi>u>>b>>>)>>gg>(>ꏗ>> }>煄>[>~>,>>߲>*>ݞz>'>ڋ>k>>վ>ӷ;>Ҡ>`>>->{>>h>>>P>!\>o&>\6+>H>5z>%>> Y=|=淞=m^=ȱ'=ju=n =m=-=c=!=ň=ˮ=щ==M=K=M=돶=)= ==Y=j=e=O1=Q>=x=E5==M=2=g=ݳY==ѻv=̈=o=>==Ũ=9==v=F=z=nT=~=j=tW=i@=]_=Q=Eۨ=;=0(=$==1=$=?y??0w?? v>S>:խ>X1>#?'Gn>V>{>ҭ>ad>f>+|>>.m><>>>~p*>I>>y.>gK>wZ>qj>o>c$>k~4>b>>c>V>i >a>Z5R>a\>o>kYv>hn>b.>d>g>]>XR>Z>VM>]`>O>J>Ct>J>Mo>MS>MI>O>L>Nc>Mv>LA>J>LW>G>M>L2>J>Bn>?1>91>9>0y>>1D>.ax>+~>',>!B>>4>>>^>˳>>e>F*> ǚ>i>>>3>i>(t==L==q=CC====Ƽ=Ѯ=ĝ-={==E=%===)'=+=YI=bW==i=<==;4=Z=5=H=F]=k=3'=a=kɞ=I=2=w??˯?HX?KM?Ks?Gw?@?7?5H?6C?7?6g?5?4U?2ͷ?2-x?2?2?2n?/O{?)}m?&+?%v?%p ?#?#1?!$?5??&? ;??R???-?A?U?!??o?s?l?$? ? ? w? ? r? ^??????؜?4?L???? >xP>>V>cl>>>>Ne>>+>Eu>>>P>a>>B>>@>ޞ>ܳ>5>ل>ו\>L>>ҩ>ϓ>ϙ >>˾>O>>|4>">b>>> >>B> 7>Hg>q>ejT>KD>3ca>Ր> (=oq=& ==U=mx=,]= >(> QH>n>7>b;>>> s>".>!_>"_>">!> lj>>>Y>>,4>F> )>Y >DN=z==Ⰵ=fW==w=3h=-=w =i=y=a^=J=4=!2={=-Ho<ʕ>=}>n?9*?e?q&?),?#?a?s??moL?P?N?^?_?U|?T@?YAb?`??`/?V?W͸?X?V?VM?V?U4?X-?WxL?Py?M_?=????C?A?AL?B??????*?=o?;F?8qV?9Z?8r?9m?9l;?9g@?9DS?8sO?8^?84?5-?2A?0V5?0?-i?-OX?,?-?+"?+tE?(;?)g?$0?$;?!?!p?37?:?{?d?/g?K???B?? D? ? O'??_?v? ?o>r>YH>@>>>yb>H>3>(+>:O>v>> >@e>> >>y>,>>>>o>+>`O>a%>>L>8>hy>^>>Y6>x>_S>B%o>),o>+>==>W>>p>'W>.g>> >Q>[a>kT>n]>qp>q>yFf>~F>c>>>,>{6~>r}>mj>i|>e>`>V%>K>>>2~>( >S>>=T=f=wA==?=dD/=<=p?9O??q_?7ϧ?*e?/?[qc?t?_u?F`s?7G?;?I#??0?2?/r?*?#????Vf? z~? ???>>_>>>>>Q>>>r4>#;>>m>>>b>2;>'>QC>>->>1Q>>ڌ>0>ڻi>ڔ>[>T%>אd>ӹ>>w>>1T>>g>I>>>j>T>3>&<>>&>i>3J>J>>>>]>w>Ԣ>U>;z>Y>>0>G>R1>a>> >9o>>>>N>Ϫ> >Qp> 6>W>(>>>>>>{7>>n4>>}:>|>t>v>n+>o>ht^>M>9>(>&Z>=M=e=|==w=w=====c>">.>[R>b>.Y>! >$y>* >*>&|>$>%>% >">/>>>S> v>.=T=̌=ЙY=6;==$===g=R)=@=0=+3=!=====z=!=&=.p=/5=-Ŭ=2Q=5O0=6c)=6R=4{=1!|=1_=.=*=(I6t`?~b??yF.?N?@L?P#M?W'?ZI?N?Da?Kf?K?VR?c?ZR?R?P?Q?MGO?J$?M?U"?SI?Lz?K?N?On"?P?Q%+?K3?Ef?D=???`>+>g>n>n> >L>>B>:>KD>^>J+>> >>tW>>#>䫅>m>1> r>>I>a>Jz>4>P:>S>>>A>я>,6> >^>>8>>D>Ø>9P>/>aF><>>`6>^>>1x>S>w;>qo>f3>`e>\>]R>Vu>Rw>X >\>\{>[>` >f>f)A>g>i[>ii>g>cf>bU>^>Y}u>S>N>G]'>?y>6P>,/>" >c> ===e===4=eP=9g= <ѱ<=9=1t;<H>) >>ٶ>{T? a>??"b?0R?F[?"J? .?(N?/X?,3p?;J0?B?R?[?a?dsH?n?xN?zY?|?{??q?r?a?\?LJW?Lc?9n?8O?,`?(=??"A?  ?"i?!F?%PO?(c?*?.":?62g?4?;?9s?=?88s?=6?4=?5?.'?)?"_?P?w?? ? T??;>_>K>Θ>|>u>>r>f>T>>0W??8?8?F?dD?/?L6?\>7>az>>>܇>j>/>>>=,>e>16>g>:>>q>=>>lO>6>T>He>[>>|>>yP>OL>#]>{>o>1N>c>>ww>q?>h>iM>` >`:F>C>>>> >">*0>G/>XI>UVA>v>e|>i0>>^-X>uS>rRS>O>^~>F >!-|>-z> ==U=vg==VK&?F?e|?~w??k?do?d7d?cU?Z$i?Ut?R?S;?I?CF?D.:?C=?:H?;x??BH?BcA??ƫ?=[???S??N?)8??|^? 9? Yc? 7? ? 2[?#S?/??6=?{?>i>E>+b>yE>n>">>L>D>ꘂ>O>H>R> >՚>>ְ>>q>}>̂w>>>]>>%x> >>>>">>u>>>sO>O>D>@V >COI>Xk>k'>}U>8N>>$>>>x7> F>>3>_> >>&>w u>a>HH>.Џ>,?=P==J=*=6p==I=;=a= =!= r==F=^K=L= =<==Co=D=D==Sc=N=I =y=s?.=tC=sYe=t]=wS=x}=v=w=q=o=d(_=\=PM=CY=3<$>p?&??u.?bl?U6)?Mή?Kn?J?M/???9?77?:`?Iw?Ca?L?H+?Sm?Q?]/?[,?aOA?]N?aB?Z`?ZC ?R?VF?K|H?N?D?E??T??j?@???H#?E?ME?H?M ?C?Bv>?59?2?&o?(@??'((?!?, ?% A?,?$O?'$? X?!o?l ?}?а?{?<?Od? 7?_?-??6?0?L?? >? ? ??$>텎>>؃>b>͐>,>˪e>6>Z>>FV>͜>8>v0>s> >(>>E>>>" > >M> >>'>>>>@8>p>>>>}>}>mQz>p1#>c>n >d>ro>i>u>bN>yn>o> > > >_>b>>k>X`>u>Jr>J>wcG>N >C>>>R=:>>9S=#='=L1=p==Z==P]=n==e=B== G=}'d=V =3==2?<#.<<=I=m=LU==1=+=2<><ұ<5>?'c??L$M??o?>ݖ>]>>q>>>2 >$>쀱>>>a>>no>ז@>"d>t>v;>s>?>o> > G>[>R]>X)>U?>f>>N>(>rr>B >Y >5>?\>E>>}+m>>>&K>*>>>N>fļ>?>>H|>Ps>d>5:>O>Ur>(o>$U>1>>dHQ>Q[>iO>>E> >.N>91>O%Z>*w>>=`=ڛ>M> >%>>)e=2D=`==>>J=='T=>=ۭ=^U=k=<=ފ=A%=)=1y=9=>==-=Ł(=n=[===\=N==X=C.=r.===<=`=o= &=8==Z~=n=;=A= =B==AP===џ'==V=x="=t?r==D-=Wm]=LI=8=+\|==~E?S??ka?BJO?Gz ?M?wO?e ?wf?w0?t ?{T?sM?xg?a;q?tX?] ?kM?^ ?t?qD?`?om0?cv?s<?T,?gB ?Z?kw?e?^g?_?R ?i,?K1>?[7?J.?X?CJ?Co?J!?<ڤ?E?.v?=.?(?: ?,J?+?#?G]?*??? A? >?R? +_?"9??:R? D>e?(>'E>i>i>5>W>>L>>f>> >R>I>>>">~>>t>S9>a >t>PYb>Sߐ>F{>9ݪ>9x>>.f> > H=Ӊ>===c6= 1=ŇN=z=H==D9=e=g==9a=n=ʌ===R=h==:>.> O>О>X>=[>>>>P6>&e>>>L>gX>Kt>5>3=7=fA==@=Q=rw;=fEc=j=z,/=mCB=M==kO=t=+=w=mn=\===/~={<$<<.TQE?_?^?S|?X??X]`???C ??ir?'?@=?qE?;>>U>B]>k>ڀ'>ޢ`>>ӎ:> c>>> >>>5>`>>"@>>z>8>">1>|=>y>law>{K>dj>f >P>F>@p>B>DS>? @><>2!;>/6>/1t>.>0>#y>>Z>%e>>!>'4>>>)f>>6oV>)}>'r>4z>.?w>,>3O>7 >'.>->>4 >1>A>:>C2>A>;>G T>KM>K>C>G>M>=a>K}>V>Z>[t>WM>_">R>ll>\K>hO>n7>oP>>c>S>G0+>$}>=޺==Y=)`===L>=C=}===YT=ń=}=wu=?C= G<5230Kbk^KX0[Y, JD1E;2fDYhqt4r#:Wn2^fGM{ so S9B8q'oXn:o\w%=WHB{yBF   ! ( l 59]?s;3$F LOQP BU6yH9:)2vZ++l :v"^  x P-H[KL5/=8 -"4RNMMI&G5m*T>N@}aRZ ZV  ! a Pn;C qk (_l*߅SH )1.&|  sS / Zd]jhݾ҄d3t=-($*&dbDi U}02=G`B=.L< >2(Җɶȧۿ^v;V)z6#?*CvPlLA*v"yi(P|j-o ;,W H $'Y'!s(y,*|CP..gG$"k+2Z?@<'2#i‘cΈAbТ^%32{,O(cQjgN 9fC #*CZ. ` v+Z .yj7IsD ]+G25VgkeWJ;r."X$18::1u%]:򹨱4rhxrA\ՉyR=5*:gW2S eC!h"_{ũ5 ?ϥ4 9 EÙ|ee3*c7?WH*P; F C9L]ϓq~ς֡| q#-36W64)/(3]= r ]y'3#4+_#@ {# Dז!wY%eBP7\߸2XGʄΜpTi ˴C=r4,;# L &\,e1p45530,J'#u pXD6.{  }t r:b% c i)ԋ> GzTQ *&u]^'%wUviI  c' :{kNN 1  + t4G $~`-k:7Z  GRF4PCu^E =) ;aH ,Fq?GM|! o"C~aFQ G\)^: v` qDk^!b"#$#"![z6 Y?_|8 ^ y(2Pp) z Hj31CZtWcj6Z #V?Eh*+x 5WNo2[imCK?`8  >!"$X$#"! PG) \#E &ymx5?+'!  kDFL{*<! hm[wy/<(R )/+US^9EW N<[wP~ [ CQ - { x J x3"zMAqn@:Kb#C ;  >8`nl=XzK9n3MkkzS^#Y(Qg qpo3t%X;&G~8;8)83ekvp  u b s 8  ' J E zr[ (&Ll)@[H,aE~T$=K1;h _mW:h R;gs5M/Dtmb@Y +Y_\QvN|SQ[@_~BW(VGTEb!\  3 XV  N  H < g S zD_f;WlgZwu(RgI,{ * 3 < z 6 d v P ^ #  G QBH)&E!fyaNXg-(Xv>f@SB^ V68*~7gQ P ;waXzr}_,@4Gk5y/n|BHFIy'gH Ae-Iw!3A-6 ]d3}m du|Lne@d0drFi\ !BEPy&-CBoSm(w'm[\;~_e91 kv\BZ`; ,~Q%#.ul+Mvl @yXMu6 w#T(  z-B%|="E8q xYv>GV90 #BE}>&)wX xtXvz,#`pAe  EY[J#iLu4jN5>E9R+< }f\`TmX9BAR:1K!1eG:8%,'ho#d_QJfOIui9W)B {c"glp=4e8a*gT3E\ =>O:&53yLtz8)m=ANbR4~<7_?ox=f@!J v\+hNO\])RBZ~~1R*; D$bN+1}c5u &UdHnw\s>nop,zw cXl^j|x]U3VvRX?n/QE/5    3 %phUDKx#@mh6 zjabwwJI4dURHr,*!A [C0V) $u,a~ 2w'h)0}wSN(!~H{HR}aVes|e%<Qd NU gRW&'   c &CP+:qX]+>iD,L^' |P|`;odnRMK:{j|\Qq>LW8r"vr,0%\QV1;}P6'e_%CcBdZ/y;lx`q\_ 9 XGu YA.pn Fpt%oc:/eW^]N vY:U8_@Phx(+]db<a?4Y5zTP07IX!q/[Lq=+}?Go/9 #9?\wWoSk \^#1{ $ pptq5aTr<;O^v Nv(r: tQ3i Qe'Am$ 2!;m l[GKk*6|wkD E =mv*I2 | ^b#JMfq4tv!SDU HP=/v JZrs\= kdBu#lh287'(n%QG9\b!t;32,6:fW mntYV@d-%VydSx['#vwlP(uHxa,RW  = ]wW*DV.LEE m|qN|DkFYBd![GYRmu#Gk,KrH$~[M +`iD:m)[SnRQ;3,'mjW'8AV$:5:iyDB4 .](6 tT (OYJr%^:@)1Y)"Kz'jxV63JTwGbN-JO ;8mTMxp5Bwp@iD.@A!$  lVUfc&S[4Eok {6 Lo[/)U L9sr}0?`]b_tW{xG"y2n=]H :McVwm,@PRI tZ Cv %J}zhJHy 1l%Su$:P]>ST-2.5"3j_R+ a}r}z6,IbhdR4'""#'.33457APUwnyquist-3.05/lib/piano/pn04.cod0000644000175000000620000003063410144436365015323 0ustar stevestaffSYNCCNDNCOMMB;o]PART>???????????v=>|>?XZ>!>ܼ?7N? C>'?"?A= ?`!>ޣJ>W?E>&z>>|>P&?G[?> *=M=8?4=D==U?X>O>q>w{>F=+=j="==p= =bw>ͩ>UF=@>>i>r>=ۨt=|>Iu>="ڱ=i>ul=Fl=e= =Qa >$D=W?4?=ۿ==eDc=-= e=2=<g<=0<=#= =,=;My.;Dη;Al;*v;\$;];'͒;3/;/_;-~;0;0?;0m;';([;,-d;!n0;#x;*;;(;)_;&T;;$2;"S; ;; Z;ҽ; ;';;;c;3;a; ;";v;i;;;6;;;q;\;.;q1;z;E;; ]P;7; M; ;; ; ;; ; ; ;–;;;:;::A; j;v;k::;$;l;#:o:i!:,:::}:;m:R3::5::F.:+P:&:::ئ:,::H: %:Y:Ǚ:๶:D!:::":-:q:~:@:Q:k:ۗ :6::C: %::D:ֶ:& :::׽:-:ص:ز: :ڞ:ڃ,:Ӱ:Ҏ::]::$::b:<:O:͟z::@FK"fNbۉ[>7`a"J|.D@ "?i$?O @} @ a3* %?y?"?ƶ @9Ľ~K>vS!wږ:?,3Ld=Ͽr@SS@uw?K>؍Fk?H@|W@@7DG@S̿U@88nC=$W+?L?{l@j9>x%)'?_?ԅT?|?3=S@_GX@H@ >fo@;PI``?_>t?濦,Z2W@R@ 6@x}@@Tлn[A?$A@@Q2@()??NT@,@ekwo_R?}>Q:0@~@x@oU3@ e>k@m\8?n ?{@Q7@,v @,?,?Kڢ@G:?->z?Ƕ>7@{@)#?d@ 5?@^-}@4{4@=JWp?&.?=Y@NR@@@y?Vk?*C@6?t?U[? Y@R@(v`j?@n6w@O'@L"@n?P7??r>N@R@m@hN@ގ?'?J @L3@.@mc>@@?>_@'U?\E?o?*@0$?֫/lu (H4@T@?@6zT@=@Oχ@@5&]@E?@@?:>ٙ?=?S ?ET@@p@J!?!i@Ii@?lC@O@**@`I?B?3@F-@Hj0?ei@@@ @@]@Tɠ@ӣ@2$@ac@@`@@?@֖@q?z:ƿ@'?,@7u@u(@p@=@ھ@p?%>lB??c?r?@e@=?r@=#-@GRUP?@@@@@@@AAA A0A`AAAAABBH?@@@@@@@AAA APAAAAAB BDCGMAG >K?zy?>>T>΍>)?&?#?'?! >?s3?7B?:?+??15?+9*?&?w7?#s? ?G??$3?!?!x??? N? ? ?|? ? ???t??? Ԇ?&?L?IC?>???֬??I>W>N>a>W6>Q>_D>|>>`>pJ><>x>&>o>>z>׶>J>ﲲ>> > V>O>>U9>>N>槙>A>f> >>>߷>ߜ >|>{M>1>>>l >(9>A>>^>>_n>d]>^&>t>Ǯl>{>>">?>>L>>FT>>>{I>v.>g>cL>W>R1d>G>A #>5 />2E>)>#Ԝ>>>m>G>E>̃=C=>d ?L?wS??dD??Y?? .B??6xB?P#?_\?Q?6,a?!B?A?ӆ?.??͆?t?o?? +??R?#?4N????H?e/>>L> >>>>~>>␎>ߨ>>R>>ݫ>3>>Q>f> >>p>*>&>>u>E>>>0>>&>@>T>>]x>>N>h>Bo>!>\b>l>>E>'>d>PG>>Y>Ķ>>>}>>t>>a>->Ԩ>(>}_>{*>x>vw,>t>r>qC>T\><>(ds>E>j=҈===u{===z=g9=W=MQ=F=?̴=:9s=7=3W=0c=+_=%%=!I1=:=CF=n=&=N=|=o>>jb>y+? ?P:?Ggj?7$?[fd??q?|?n$?g9?p?uG?q|?s$?q?uB?r?si{?lmp?d?a?a?^ѫ?]2?W?Uޗ?Q?P]?J?G?B?@?;?9?4?1ȼ?+{?)?$?#$?:????? ? h????jg>E>$j>>n>k>>hw>׉F>K>`>,>>>T>w>2>m>K>Y>8>֖>>%>Ɗ>GN>p>I>3>>>q>>}>}>>tA>t9>lh`>lJ>cH>cç>Zy>[K>Q>T>J}X>M53>C>)>D> ==3=Z=N=v\===Е=]?=7=='z=,=s=ů=e/===X=hj=1u=}B=r =g<=]=S=K=E%z>i֘>>{?o?7Ea?('? ?q?15?E]?Ra?`rO?l?xn?}K??{Ri?tOt?pr?pј?o<*?o̵?m?n<2?h?fw?c?d8.?b?`ޏ?^5?^H?Zy?YN?V?U~?S>N?R?P< ?N'?L@?K4?I69?Gڡ?E4Y?D$?AB?A(?>:?=?;N?:3?8J?7*?4$?3q?1i?/u?.U?- ?+=?)M?(?&?%e?#?"c? ?it? ?WZ??u????2??A\?? ? hz? ? f8?/??6k???>>>^>>.>*>[>>Z>>ˊ5>>aB>c>u!B>S>3>o!=p=u=`w=@=I=#Q=>y>Ze>%>/>7J><:B>=?>< .>6o#>.p>$M>+> ѓ=8=ݲ=q?P??~נ???r>>h>Ӕ>1?,?Q? R? G?c? %K? ? G? ?&??J???"?L?w>>ʨ>:>`> >>>+>\>>>Hg>W>>+>hl>c>>g>B>>O>>Vq>k>~>Մ>)>>l>>8>*>>>I>W>,>i>1>縮>P>汛> >K>Q>>U>>>v>E(>m>(>c>->r">M>ݹ>^>ܺb>>h>Չ*>`>Ԯ>>>%">ӏ~>ե >Ѧ>>i>Ŗ>m>Q> >_>>Wq>>>Z>u>{j>r0>f n>\7G>QF>E>=m>2P>)I> (>> ˮ>9=I"===]={=E>p?W??(i@?G?l?s?u q??h v?\Z?aeC?q͘?l,?o&?`y?b6?W5?\'?Rz?PZ?D?I?A9?F?@]?F;?>A>Ë>>>`>X>_>\>wk>_>k>>4>ےB>%k>O'>!>>{>g>>z>W>8C> >>]>$C0>5>H >a^>uf#>>!>> >>j7>>>Y>>>x>w>R>>>>=>M+>qF>f?Z?F?kk?{^??{`q?t4?u?t?l6?dHK?b)?_=.?^`?Z?V?S"?M8?F?C?=?<9?8 ?6d?2g?1h?/?-?*!?'?%3y?$6? N?is?"?Id?,?`e? d? ?D?>>~>q'>>>>A>V>߭>q>d\>>u>%Q>ʼ>ٷ>c>=>w>>>5>V6>tk>>>M>>">s>>>>>A>$>>S>7>>}s>y>t>o>i,>eû>_]>\>T1>R^>Jf>I>B.y>@>#> =C=a=&=;=+==g=S*=M=h= ===5G=uI=tt=eX=T=OB=@?u=4ђ=0=#| ==[= 6= T= W=m9>X?b\N??8z?3:??Rs?+?>>.>>r>y>>e>oC>?z*?:?? ?q?kF?N?s???^?? ?G?r??3? &?? 7??@D? <?? <>7?v>?Z>h>F'>]>'6>ˀ>,>>>MX>>5>!X>hj>M> y>4>>>i>>>B>>>vF|>D>k.> >`S\>Pc>L_>}ڵ>@>p\>4:,>Zb>#,>OCx>r>=(> z>1>>)=l>q =6>U=> E=y==.=gw=r= >=ƭ===K <>G>?H?rQS??hF?HK?I?Rby?Q~?H?F ?A$h?DB?;D?9>N?1Oz>X>ݜ>JS>>>>l>]>X>;>>=>; >tn>>M>Z>4N>>ܤ*>)>W>t>k >դ[>ɕ>qU>΂>̐>^C>>m*>>>c>>y>ϗ>#>,>>>9>.>>A>Μ>>>1>>d>C>&e>Y=4==…F====lt=G== > I> ">>"$>!!p>9>->.>ݧ>$ >(c2>*T&>(P>"!>>]?JW?&=Uf>??5>?%sm?m?6m?P?iH?g?| ??y?g?`.?Sz?EiT?8 2>y>!>>>>>K>C>Y>@>>>>:>N>>>>#> b>>&>u>j>"5>/>%>~+>};>rr>pc>eu>g>\e>X/>Q8>P>E>B>@&>78>5PF>8 f>6X>>>5>84'>4$ >3>0>0>2P!>0v>4>>2<@>1>/;(>0G>+s>+>&cx>*11>,>.h)>0$>>>I>d>kػ>f>Q>AS>7>)5>2>=ω=)5=-=`T=U!f=c=%=i=i=t>gN>>)l>3><7K>Cx>N>ZE>_ٛ>`Y? ?L( ?g?tT??}1?s3?f)?\T?Ss?M3?F??ݫ?7?1?)?$Q?!k?z?x?$?65?u??,? P? u?Ա??j?>T3>d>C>}<>+}>.>x>ۆ>>c>Z>Ǜ>³n>">ڤ>>n>l>>>>>u>k>>|>*>>t|>>RG>{>>uG>oT=>g >a Y>Y>R,>L#>E>?e>8W<>2;>,->'>#!> X>'">>z'>>M>N>}>> a3>>*>K= = = ===l=vP=.W=}==s=E==n=K= =j=|===.===P=4=}=z=m=G=q=O=:H=,H=4?)=3 = +=%===C?&(?2?_??sLS?a?b?aˋ?U$H?G?<?8hJ?=C?>?7?0C?3^?0?+ ?)d?*?+Z?*?*?(n?&?%?#m?!??~*?>??d??k.?>O?,?]?? >f? ? ,f? n{??=?9?n?"I>ָ>>Ħ>>Y>`>>N>e">cw>>y>->3>>>׆>$>A}>>.>8>>E>1>(>c3>>t>W >@>%j>->c>qc>0>?>>!>{>z> >}>zd>x+>uC>s<>p$>o>k>n9>{>>@>>E>>x>>o>C>>>{i>` >C}>(ve> )=r==zL==e==$>q> >f>0>>?N?m`?{V?a ?d>?^{?j?nr?{U8??t>?l%?g??gzQ?dؒ?n?iu?k?am?_ӆ?[Ha?]C?Ya2?Z$?R*?R?K#n?M?Mʈ?Rv?Rj?Rڳ?M2?G01?@L?:?>?=?EV?Bw?D5?<?8I>}>%>>b> >>Q^>A.>~U>Yu>'>[x=%=lS=>{=@=g=&=9=='e====|=R=Gc=='=?pQ?V?s?O'?_??h?UP?4?MH?KI?d?Ha?X?:?] ?Q+?n]?N4?W??(a?9?.?<[?:?; ?3;?.?5O?* ?7~F?%& ?6? ?31?"?2?$UF?0T?%\?1x??,G?/T?( _?(_?-z?*v?1[?"?11O??1P?>O>+>ֹZ>>>>>w>>2>=>>~7,>_>T>T>7d>eD>"> w=1=ۭ=ݹY=f=R= ==b=6=??K8? @>{?>?a0>>7Q>Τ>D|>q>y>>¶>V>>N~>F>:e>6E>ГR>i|>>>>tj>>:>eK>>~m>F>Jc> >\m>,>~>>@G>>v}>F>HX>yd>iz>V >f h>T>iF>>m>v>`Yq=6>R5r>>g=>:>>>D>*?> >F>>G=E>OH=Gx>Pq =z>N<=d>4>>2B> 6>@>+o> >%o=>1T=>%3=c>~=;>Yh==v=K=_>\=>=J>I= U=M=Ӵ==,m==-x<==>=Pl= ̌=A=Ḁ<= ?g?;>jZ>o(? ~U>>?z>>>y>f>r>m>p>h>TD>>;>S > >y.>>>6>8>>>*n>ƴ>>ķ>_>k>N>(>*>%>'>2>v>>>?>>>}`>>r7>R,>_>xV>sk>m>e/>W\7>Lfj>?=> > u>5>O?F>@>2n>74>)->>#*X> f>%p>>u>t9>$>+T>3>Q>N>-.> >8>.=%=>:>&>c>^|==͐O= >=|u>P>> y>S>ϐ> >t>]I> >S=jb====j=H%=1== ,=_=#=8H9=:%=J=R^=:=3)??Q4?k??w]??~[&?|l?x?wZ?w@f?u~?q?gp?e?]5?ZVX?S?M?I'?CK?B ?;?9(?1?.4?(h?#CG??(??^?*?>>J>n>>L>k8>>>9(>>T>>_>H>5>>~>6>2>>a>˙>W:>,>>>>>>W>X.>0&>>d>> >>k>_>Q>⁛>>c8> 2>4+>>P> >f>ʺ>Y> >F>(?x?١???!?ݚ??:F>Η>>>>t>R>>`h>W>pY>%8>>C>FJ>p}>%=5A=>+>cǙ>wO>A>>i >=>R=м==4=— =К=˶== =b(=82{?hm??dW?Y?j{4?eR?C ?4??v ?GB@?<\?R?Y??-??v>>=>̨>d>>@\>T6> >\>J>>y>Z>->@>z>/e>6>s?h?P?yO>q? z??"6H?$C?!?k?/ ?7?1W?(k?+ ?@?E?BF?/?) ?;2?:zf?2\?"?FR?% ?%)?˼?o>>?y0>U>,>(>4>>C>U>Q&>gQ>zm>cv>"r=(>>>+T>.>0>6e>&[>Y>ڱ>,>>>>J>a>g>y>{>Р>s>{>2Q>BO>j>>>N)I==;j>!2>66n> V=j=tt=@1>===i=wK=x=w=l=C9c=$<.= m=*=Tt?YhJ?f?r??oc?GE?FM?;'?-n?f?z> %>l>>>I>? ??!?%?M?S>t>r>>M>>O>U>Ι>>T>q>Ո>)>O>>®d>>>+2>Ǡ$>S>Ï:>/;>'>>M>n>(>>C>õ>l>!>>1>>ҵ>H>7:>>5>FJ>>J>>-M>n2>h?>P[G>K@>[Ζ>s>q>W>>oW>\;>>n>L>\>o>">o=g>oXY>s>l>i>fS>]/>K>A{>@>Bܤ>@>:>*;>>47r>L>,> c====HU=m=9 ==={͈=c=1=`=NK==04Q=Nw^<|=B=?D?J?P?U?[?a?g?m?s?y???????????????????????? ????"?'?,?1?6?;?A?F?K?P?U?Z?_?d?i?o?t?y?~???????????????????????????? ????"?'?,?1?6?;?A?F?K?P?U?Z?_?d?j?o?t?y?~???????????????????????????? ????"?'?,?1????????????????????? ? ?????#?'?+?0?4?8?=?A?E?J?N?R?W?[?_?d?h?l?q?u?y?~????????????????????????????????? ?????"?'?+?/?4?8??@?B?C?E?G?I?K?M?O?Q?S?U?W?Y?[?]?_?a?c?e?g?i?j?l?n?p?r?t?v?x?z?|?~????????????????????????????????????????????????????????????????????????????? ? ? ? ?????????????????!?"?#?$?%?&?'?)?*?+?,?-?.?0?1?2?3?4?5?6?8?9?:?;???;?8?5?2?0?-?*?'?$?"???????? ????????????????????????????????$? ?????? ???????????????????????????????????????~?{?w?s?p?l?i?e?a?^?Z?W?S?O?L?H?E?A?=?:?6?3?/?+?(?$?!?????? ????????????????????????????????????????{?x?t?p?m?i?f?b?^?[?/?+?&?"????? ?????????????????????????????????{?w?r?n?j?e?a?\?X?T?O?K?F?B?>?9?5?0?,?(?#????? ? ????????????????????????????????|?x?t?o?k?f?b?^?Y?U?P?L?H?C???;?6?2?-?)?%? ????? ???;?5?0?+?&?!???? ????????????????????????????{?v?p?k?f?a?\?V?Q?L?G?B??9?4?/?*?%????? ????????????????????F?@?:?4?.?(?"???? ????????????????????????{?u?o?i?c?]?W?Q?K?E???9?3?-?'?!???? ????????????????????????z?t?n?h?b?\?V?P?J?D?>?8?2?,?&? ????????????????????????????y?s?m?g?a?[?U?O?Q?J?D?=?6?/?)?"?????????????????????????y?r?k?d?^?W?P?I?B??7?/?(? ??? ???????????????????z?r?k?c?[?T?L?E?=?6?.?'???????????????????????y?q?i?b?Z?S?K?D??6?-?%??? ?????????????????~?v?m?e?]?T?L?D?;?3?*?"??? ?????????????????{?s?j?b?Z?Q?I?@?8?0?'?????????????????????x?p?g?_?W?N?F?=?5?-?$??? ?????????????????}?u?m?d?\?S?K?C?s?j?a?X?O?F??4?*? ?? ???????????????w?m?c?Y?P?F??2?'???????????????z?o?c?W?L?@?5?)???????????????|?q?e?Z?N?C?7?,? ?? ?????????????s?h?\?Q?E?:?.?#?? ????????|?p?c?W?K?>?2?&?? ????????????y?m?`?T?H??0?#?? ???????????y?l?_?R?D?7?*??????????????s?f?X?K?>?1?$?? ???????????z?l?_?R?E?8?+??????r?d?V?H?:?,?????????????x?j?\?N?@?2?$????????????}?o?b?T?F?8?*?????????????u?g?Y?K?>?0?"????????????{?m?_?Q?C?5?'?? ???????????s?e?W?I?;?-?????????????x?j?]?O?A?3?%?? ??????????y?k?\?M???0?!????????????q?b?S?E?6?'?? ??????????w?h?Z?K??.????????x?h?W?G?7?&???????????s?c?S?B?2?"???????????o?_?N?>?.?? ?????????{?j?Z?J?9?)?? ?????????v?f?U?E?5?%???????????q?a?Q?A?0? ??????????}?m?]?L??,??????????y?g?U?C?2? ??????????m?[?I?7?&??????????s?a?O?=?+??????????y?g?U?C?1?? ????????~?m?[?I?7?%??????????r?a?O?=?+??????????x?f?U?C?1?? ????????~?l?Z?H?7?%?????????y?f?T?A?.?? ????????t?a?N??*?????????s?_?K?7?"?????????l?X?D?/???? ???????u?`?K?6?!? ???????y?d?O?:?%????????|?g?R?=?(?????????k?V?A?,?????????n?Y?D?/?????????r?]?H?3?? ???????u?`?K?6?!? ???????y?d?O?:?%????????|?g?R?=?(?????????k?V?A?,???????)????????z?e?O?9?#? ???????t?_?I?3?????????n?Y?C?-????????~?h?S?=?'????????x?b?M?7?!? ???????r?\?G?1?????????l?V?A?+????????|?f?P?;?%????????v?`?J?5?? ???????p?Z?D?/?????????j?T?4?????????i?R??'????????k?T?=?%????????j?R?;?$? ???????h?Q?9?"? ??????~?g?O?8? ? ??????|?e?N?6????????{?c?L?5????????y?b?J?3????????x?`?I?1????????v?_?G?0????????t?]?F?.???????K?3????????q?Y?A?)????????g?O?7????????u?]?D?,????????j?R?:?"? ??????x?`?H?0????????n?V?>?%? ??????|?d?K?3????????r?Y?A?)????????g?O?7????????u?]?E?,????????k?S?:?"? ??????y?`?H?W?>?%? ??????u?\?C?*???????{?b?I?0????????h?O?6????????n?U??$? ??????p?V??"??????y?]?@?$??????{?_?C?'? ?????~?a?E?)? ??????d?H?+???????f?J?.???????i?L?0???????k?O?3????????r?U?8???????n?Q?4???????i?L?/???????d?G?*? ?????|?_?C?&? ?????x?[?>?!??????s?V?9???????n?Q?4???????j?M?0???????e?H?+??????}?`?C?&? ?????x?[?>?!??????t?W?:???????o?R?5???????j?M?0??}?_?A?$??????q?S?6???????e?G?*? ?????w?Y????????c?D?$??????h?I?*? ?????m?N?/??????s?S?4??????x?Y?9??????}?^?>???????c?D?$??????h?I?*? ?????m?N?/??????s?S?4??????x?Y?9??????}?^?>???????c?D?$???|?\???????o?L?*?????}?Z?8??????i?F?$?????w?U?2??????c?@??????q?O?,? ?????]?;??????l?I?'????????]?:??????f?B??????o?K?(?????w?T?1? ?????]?:??????f?B??????o?K?(?????w?T?1? ?????]?:??????f?B??????o?K?(?????w?T?1? ?????]?:??????f?B??????o?K?(?????w?T?1? ?????]?:??????f?????e?A??????h?D? ?????l?H?#?????o?K?'?????r?N?*?????v?Q?-? ????y?U?1? ????|?X?4??????[?7??????_?:??????b?>??????e?A??????h?D? ?????l?G?#?????o?K?'?????r?N?*?????u?Q?-? ????y?U?0? ?????m?H?$?????k?F?!?????i?D??????g?B??????d????????b?=??????`?;??????]?9??????[?6?????~?Y?4?????{?W?2? ????y?T?/? ????w?R?-?????u?P?+?????r?M?)?????p?K?&?????n?I?$?????l?G?"???? ????v?P?*?????n?H?"?????f?@??????^?8?????|?V?1? ????t?N?)?????l?G?!?????d????????]?7?????z?U?/? ????s?M?'?????k?E??????c?=??????[?5?????y?S?.?????q?L?&?????i?D??????b??????z?S?,?????g?@?????|?T?-?????i?A?????}?V?.?????j?C?????~?W?0? ????k?D????ߧ?.?????f?>?????v?N?%?????]?5? ????m?E?????|?T?,?????d?????ߞ?v?N?:?????m?E?????x?O?'?????Z?1? ????e??????j??????ߕ?k?@????ޗ?l?B?\?1?????X?-?????U?*????}?Q?&????y?N?#????v?K?????r?G?????o?D?????l?@?????h?=?????e?9?????a?6? ????^?3?????Z?/?????W?,?????T?(????{?P?%????x?M?!????t?I?????q?F????ߙ?n?B????ޕ?j?????g?;?????_?3?????W?+????{?O?#????r?F?????j?>?????b?6? ????Z?.????~?R?&????v?I?????m?A?????e?9? ????]?1?????U?)????y?M?!????p?D?????h??????^?1????}?Q?$????q?D?????d?7? ????W?*????w?J?????j?=?????]?0???ߩ?}?P?#???ޜ?p?C???ݼ?ݏ?c?6?~?P?#????l???????Z?-????v?I?????e?7? ????S?%????o?A?????]?0????y?K?????g?:? ????V?(????r?D?????`?2????|?N?!????j?? ???k?6????c?/????\?'????T?????L????y?D????q?=????i?5????b?-????Z?%????R?????J????w?C????p?;????h?3????`?+????X?$????Q???߲?~?I???ޫ?v?A? ??ݣ?n?9???ܛ?f?2???ۓ?_?*???ڌ?W?"??ٹ????O????y?C????m?7????a?,????U? ????J????t?>????h?2????\?'????P????z?E????n?9????c?-????W?!????K????u?@? ???i?4????^?(????R????|?F???ߦ?p?:???ޚ?d?/???ݎ?Y?#??ܸ?܂?M???۬?w?A? ??ڠ?k?5???ٕ?_????X?!???~?H????o?8????_?)????O????v?@? ???f?0????W? ???}?G????n?7????^?(????N????u??????e?/????U????|?F????l?6????]?&????M????t?=???ߚ?d?.???ދ?T???ݱ?{?E???ܢ?k?5???ے?\?%??ڹ?ڂ?L???٩?s?????a?*????N????q?:????]?&????J????m?6???ߑ?Z?"??޴?}?F???ݡ?i?2???܍?V???۰?y?B? ??ڝ?f?.???ى?R???ح????j?2????R????r?;????[?#???{?C? ???d?,????L????l?4????U????u?=????]?%???~?F????f?.????N????o?7????W????w??????`?(????H????h?0???߉?Q???ީ?q?9???ݑ?Y?"??ܲ?z?B? ??ۚ?b?*??ں?ڂ?K???٣?k?3???؋?S????s?:????W????t????ܒ?X???۬?r?9???ڌ?S???٦?m?3???؇?M???ס?4????J????a?'???x?>????T????k?1????H? ???_?$???u?;????R????i?.????E? ???\?"???s?8????O????f?,???}?B????Y????p?6????M????c?)??ߴ?z?@???ޑ?W???ݨ?m?3??ܾ?܄?J???ۛ?a?&??ڲ?w?=???َ?T???إ?k?0??׼?ׂ?G??????S????f?+???z??????R????f?+???z??????R????f?+???y?>????R????f?*???y?>????R????e?*???y?>????Q????e?*???y?>????Q????e?*??ߴ?x?=???ތ?Q???ݠ?e?)??ܳ?x?=???ی?Q???ڟ?d?)??ٳ?x?=???،?P???ן?d?)??J????[????k?/???|?@????P????a?%???q?5????F? ???V????g?+???w?;????L????\? ???m?1???}?A????R????b?&???r?7????G? ???W????h?,??ߴ?x?x??7E>?$)?(6>k#>]>6q"=f`+=qd=_n=$n='=)`TPƾJV??NYQ¿`k>@)@I .@\z@2|@=*@@@@?*?GRUP?@@@@@@@AA@?@@@@@@AA0AGMAGp;;4-;|2;"#n:;l;fTg;};< k;;錣<_=>g>AB>vN>ȴ??.H?1?i?F?Z?:?Nе?i?}6??p?Zd?G?:?/ ?ĕ?jq>%>h>?HV?Z?V?&?-w?1H?=?E ???12?%0???? |? ]?ֲ?Ռ? h? ? ?}N>#(>?[?'? ?A>>>o>>R>4>>D!>9J>ν>d>>M>;>l>>S">*>1f>N>,>mm>t,H>k(;>] >S>M">C+>9h>.4>'ω>!>y>>o> *>/==B==q="==8=wW=;===|q=nDV=Y׭=K==C=/R=":=-==<%<4<S<";K<#<<@<<a<}><N&<<)<Ц<8<"<);۲3;;њ;'Z;Ȋ;u;rX;ȃ;;;;Ya;;;ۯ;m;;W>;9;v;;;;lx;;(;b;;;?;;9[;;;;! ;;;c;;;; b;H;+;*;i;W;X;sz;j+;8;@;;;;t;i,; X;;/;UV;b,;K;^;;s; ;;M;;;;; V;);5;;e;aV;.;;;\;;ě;H;|;;;<;;;S;; ;~H0;C;q;;3;u;A^:7;/; :ܩ;(;g:/^::l":G;8==k=>=Y=R`>Aa>o[? ?mR?;M?8?4?=??Nkp?Wh?\J??yc?kq?xtB?{?bO?]?c?{g,?p;?P?gf7?sE?o?s?iv?b#?i?s?a}?_?e3h?l?l6i?l>?lM#?leQ?m?i^?f0?mu?bD?cx}?`>7i>h>>1>>>>Q>>>pj>_4s>Ni>?8>2&>%_>\> G>=(=օt==׻===b=q\1=c=`m=_=d=q =5=tv==bt=@===nY=u=='w=f=¶I=A=T=x={==== P=E==I;==̑=.=yx=s=l.=h=b=_=_z=`*=`d=dc=l=r=z!= ===_=J==I=="===~>=OC=?==P=h=0=C======D=zj==o=l=={=Q===з=r2==A=aS=1=%l= '==]]=W=#=r=3=z=!=|=x>g=t{R=r>l=ok6=m=m=m=p4=qa=t.=y0=}=pO=D== S=%={==q=h==>=X[=s= =#u==,===ޔ==;=*=Z==)l=,=i~=%={=-|===B=====0=X===i= =9==}=5M=|v=w2=s=m=g=b=\d=WA=QQ=Lt~=F.=@)=:t=4/=-='HC=!]B=nt=O=+}= V=(=<<3A>J>t>>9?|??-?.>՜=ŋ>?4>>A??Q?!?Ja?P? o?q?+<>>m>K>=>W>o>N>->>on>56>Hi>E=y===A=m====A!<<̇=!==9==I)===i=====0=m=&a=/=80=L&=~ ==o=====(Q=<==0O=Ү={=sd==k===/=$=G==x7=(=J=`v=H=v==h=6q=={=u=mp =c=^W=U#=Hr=@i%=7=-=&="{=n=Q= /= Vo=<ߛ<<_1 ;';CX;;Ґw;d;Ր;׃;f;a;;Fk;5;;;x;f;m;a;ϼ;;;>;$;; D;E6;'m;;y;D;J;^<<51<'<d<8<#<'v<,><,><.<.<+U<);;<)(F<1<1"<*gf>ۭ? ?w??!???!J?#h?)M?b?/?#>?A?: g?!?d>O?0.?PT?i&??x?voq?v?oײ?W:?F ?,r?)C?%?$?? ?7>>?>ԉ> >T,>>->>A>0>K>>j>d>c{>1>>w>j>]:>S:>A>Kz>K>Rl>r<>ʰ>x>>|>A>C>}>>}P>z>G>,>>>?t?? Y??m>>ߔ>)>J>n?=?0??Y?>>?>`>>>>0K>>}7>O >Y>ɮ>>>z>̉ >M>u>>>H6? T?Uw>ׄk>]$>>>T>=>$>=><9y>5t>/(7>v>X>/>J>@m>k=7=E=/0==d =I====5=C=L=ۄ=T!==M=q*=}==u=E|=*R=\=g===b== '===I=O==h='=t=]1=l==Ox=k=d4='W=='=$=o=FE=D^=PP=B8=M;ڰ;F;;Td;f;;ٛ;;;~;a;y<M< j;d;~<q<"< <|R< <-<:7<2<&<$8 ;KmE;Zo;3;mc;Gdf; ';(5;D;>;:;;; ::;:۝D::>f::;M;!;{;2; V;};T:F\;:N=:7:?:g:Nr: 2::": :\::::::# :::c:'9:F=:!::u<:m(:v :::/M:W5:B :qh:q :jn:&9::2It:F?:Oކ:f9|9gL9C9㐸: G9E9^99o9w:)9:+9?:^L:Zs:X:[:R::U:'::::˰,:4:Η:,:={:=N:0:qW:8:M::J:ع::; r:.:P:M:;A:C::Ǣ:^:c: ::x::::D:|l::):8:3:::0::Ă:d:;:zk:/:-8::>:/:Q:::ȡ:,:::g::y::4:::::'B:f:+9;,:B;"E;8:r/; ;::ˀ;;\}<LN>|*>:>y>`>D?z?/P?2=?0Γ?3{?@???8?;:3?MU0?V?bL?v?}?~g??pT?ie?a'_?[ [?Ni?M?OΘ?T?U?Q»?Q ?Ox?O"?I 5?G:?D?Db?Cg?=??6#?4?3o?01?*?$0?qJ? ?$?"?!jS? j? =?!k??2??g? A?f>q>i>c>>D>> >>̜>CA>>A>Ѵe>֧H>m>y>G>κ>0> S>>B>2>ǵ0>]>V@>>>c>B>P>(>>>>f>( >ƶ>>>>pJ>~>u+H>v>r4>t>__>[>\i>`K>eE>5d>-,[>*>j/=z=U$=k=[T=i=T$=X[<<#==)8=J=Ta=i/=5=FI=r =>=)==a==ו="=2=z=s.<=J===8==o==u@=&=L= =iZ=W= :=X=-aG<q<%<ݞ=t?=d= @==HU<<<;;ʪ ;;b;;w;p+:2:;f;;e;;;2;7; ;<;s;;;b;;;;5;w;;]M<::;ZҤ;);[;A<nV;t;ʎ;$;E ;];eX;Ej;Eod;[;Za;_B;p;9;=;l;v=;R;;z:<:URv:R:qV:*:ЪZ:G::: H:f: :k:ڑ:ȍ;{;"B;$;83:9:2:3c: :Ƃ:f/;;-;B#;F`!;L,;Pm;SV;Q;D;0B7;x; "+;; R;);B;R*;F;J۾;K;1;$; ;"~; ; {::K:!:D:; Z;;q; B::ޜ:,I::P::x:_:fF::s:y::M:JT:ǵ:r:ݔ:K:?::J':l: ::-:W::>:t::): B:_:m5::ɺ:4 :PcB:,p:[-:*-:AZ:XGe:,::7:5OJ:/X:'c:%:Bv:$:+; ;#+;4:Tn:O6: l:\s?9:R%9߂`:Q:?|:b:[G:>:y7M:J:sgH:zX:sp:ps_:N:nI:|U:iu:!?:l :k":Xi:Q:D\:R:4r:"^:5:*~: :9ɹT9㸩::آ9ka9΢9_:9֓ 8j99d"8n=9N9Zp9?09c^9?9y989ʏ99q9n999}9H999y: 9J:kO: w9:99:R:Y:99+X9)9m&9~y9p9 9_99h%999x9Ip969e#9gl9Ph99"Y9"9_88q98v99E2k9!k8 9`89+9N9-ڰ99v/99}95n59G9lh9p99Fמ99)9a9mO9`9_999d99Y9n.9W9}99B9a698G>9+9^;f; ;n; o;(;({:$<;8;J;a;=%w=*=؜>P>> =@>>FA=U1>Xr>XN>b? b?$]?A?M C?`?Uw4?]?Nho?]d3?@?QC?0?b?L?V 4?b?od?c]?W?lt?_B?q!?V?pԂ?^?fZ?a7b?Y?Y%6?Rͪ?UA?YeE?uO?m>?n?oZj??u?{6?m?rL4?[?^?[:?RJK?[.?X?c*??]?rz?k0_?zE?fb?i ?X ?Z*?P?MT?IR?G:?J?DX?O?E?RS?G;?P?E?IiY?=B?AB?3E ?2^?/`j?,9V?*)?#?+?*8?,\?&a.?/?(4?4?1j?6?/?(?!Q?E?*?%8??T?n?x?.???? {? B?"?q>ƶ>" >|>|^s>RN1>=S=n=2k=p=x=`=P> E> >a> >Y-=?[=w='-===n=&r<<[U:;n;-: Y::P:a99~::y:l~:y~:;:e;$; ;0D;T%;=c;^z;:V;=Dp;N;lW;M;x];~;z;;u};1#:9:&:7:F:OϜ::F::Н;;F:jy:G;s%;p)m:ul:Q;:E: ::h:j&h:<:*98391S9\?J9W9+ o9m<9|(9293<*8J8C89=%9B999G98R:,8h99Wz9W98N&9sX98ˆ8/9}9s!:t9I8)9AT9Lb9ȵ8PQ9׿*99R9^9#99J:&!: 9O97Y9{99>U9&":V29b9j?9LC9>I`:/:59Ha9#8֛8992Q9 9֝F9_9R:J9א99P/9:_99 :;A(e:ϔ;5O;M=;&#;Ns;P:; ;<:f=cz>0|?Pz?A?i5;?=?3i)?3?,g1?dq?`?ƛ?m??c$?k?G?I?;.0?>? BV?Z ?7?$2?\D?ۿ??O?}>&???_>>,> 8> ?>>cb>>҉>Qj>>>u>`i> >>>>ǡ>M>u>l>qs>,>}p>$ڞ>q4>/k>Qu>T>H/A>-=> =lB>B='>==qL=>\s=A=r=m=ż=޾y=>k=Q.= Q=>t=>Pj=e>J=yE= =T"=ٰ>%_>>0v>>X\>'>o>*Nr>ga>%T!>X2>Km>\ >K>q >Q>gh>|)>k>7>r&>~>sd>4>>X>>uy->mh>P>F=>"==i=O=w=3=ʹ==d9=B<~<<0<%+<]<<;7;3;j;oj;!-;EC;T;h;H;;NM;;& E;;;a;$; r;f:=::޲:y:t"; [:T0b;#r:; :~>; ":;];[;':כ;:::::9:w1:u_9?:{/:)(:*r99Ct9v9A9y:~:EP:fU:D:`::N:rp::N&:o:mi::NN9r:09~9%99d9oZ9!99o9b9ߚ9t9:9:*9Vd:w:=:5Q]:$F_:h:#:O:S9:"$: O: 7:P+9y~::)9{q9 9O9Тj99*969Vv9é9C9) 99v+: ):6(P9r:J9:+D9:.!909h979989@91?9B9;|*9Q378;9Y99@939`99q9#9:>19 9:9I9ƴ:0S9ޝ9ߕ999Y8'99a99`9b99:9H 9^9O99)y9C9;9W9:9ji99*^99!:9d9j+:\ ;S:H;x;;/;|:oj:,:w9D`::?V:7: p: dB97:*9l9nQn9Ӈ99=9A9=t9h9990a9 949K99 9P9=9l>9999<9%89e)9yf9)8$^9G9t;9_n9T~:9!99u08 819e{89q9;{9KY9i9ݱ8l9[K: 9;|999T9 97T9l:%99vO9lb89o9w,99fl9n9>9~x9Y99<9}4p99s8(8V9k3E9[C98 e99L?u9.i9(9i59h9?J9J9]k9`48ƭ29E.9' 9}p9 99{9p9h9ȵ:*9"k9jd99YA9^9YS9k9/99U99 9p9M9ҊT9fm9_9i;l9~)9`H9994:z99J9v;SID<>?&? ?j?C0?7? ?&? ?%"?/p?x1?kh?p??lu?Lm?\4?n.?V?O[}?n??.?oT?$?v?@?>9?.?@?`? ï?n?F?M`?1n>Г>??9>9><?l>3?>>턭>Ң? >>7?o?Q>0>>& >>>>p>ӖZ>=>֢;> >[>ǥ>>>=> ">>>>yX >Q>Ȉ>sr>I> >>>?>Eg>=>~>&|>DY>;&> =x>;=R=>/ =v= >n>ۆ=4>&*>J>=͐l>}>22>CX>'>*>gŅ> a>>/c>`E>L>5>>bI>>lK>>R>N,>(:>>Yr=p={> Ƨ==XS=zF=y]=nC=yq==͒=3=t= >W=>===t=C=V=v=F=R]U=9=0=f=,==N=Y=dY=$=-g=0=OԜ=bM=|=%= <|<<\=<<+H8<_<@y;;EI;;V.;;DF;4;;;;?;_;i;ՠ:;IB;v;g$ ;D;-;%;.;^;;;o:釰;=; ;;z;;Օ;G ;z;NX;-;+n;5:;:Ü;k; e:O:[;;R:3;-: :.:7;;::Ai:i:n0:S:7:Z&6:ۙ::ҿ:˼#:u:>; 9:"3::Y:m:h':1:::Ks:Co:kK::M :W:~1E:՘;::ώ1:IE:'::ĸ:]:n:D:zh:c-W::bi:b*:g{%:w:_::': 9:`::*Y:{7:U{: :j:u:m:Sa:[':]Z:,:n:K:u:U :C0:3::pq:J :v`:Ճ:\t:z#::k:j:TNb:0ir:Os:T::6/:;:l:(:$::\::^:9:n:Ow:Y]:t<:a4::.":3(%9:7B:::Lp:@::M:t::::-:v5:::4::Jb:cv:jH:o:Y:2::gR:T:I:O::]K:>v: :F9:2/:(W::9<:P:Bq:7P:Lq;;<#>;:H::c:PA#:Z:mS9):v:Sn9)4:҈:։:q:wr:$:v:+:r:f&:{:PV:ɧ|:R::0#:~K::A:5m::$:;:?˜:^9::X::;5o:V>Y:@::qz:{:%;:,:;:r:0w:[:+:B:s:v:::Sd:_::u:g:::N;;$;6;s;{;;c;u< L3P>Č>p>̛>>[w?&{|??t%?_?hދ?=T>">>H>>{>٤>q>$>,>L>e8>g>M>'h>> >>ʂ>>?>Y>be>|>}:>4GB>E>O>>u>Uܭ>\>U>6=6\==վ=w`>'>7y>*H==>1=A>7>!> 7>c=D>s==>>>>/*_>:>+>J>M3>')5>$>8C>:C>@p>?}>0Vf>?d>K[>I{_>4` >2;J>H>I>\ >UoX>X>r>r/>kf;>N@J>XR>OJ>P?&>2w>'w2>1\>>+>+{>/>)n>>(˙>@ B>?->+n><>Z>$ +>>:> > ==5={==n=2=zyy=<=h=V=;=N<敜:,::8:T: :;y9:m:%: :@:Ț::,:o':C:w::2:<:H:o:4:A::s:ήa:~:C:ؒ::@k:e;:Ǟb:jB::]l:ͺ:::`:!:غ:a:N:{:'Q:r:|S:_:::U: : :&H:::l:m:9:f:ʢ:E: :E:::DD:D:Z>:>:4z::N::D::Q:oW:P:Lg:J:t:u; :c:-:#:^:ɱ:::::ן:5:=:Nt:<:6: 1::|:ʶ:зP:::9:˟v:h:>N:a:=:͝::8:s::һ:::K:J:v;*; ;;|;F;Æ@;`;&H;C;Z;a;;M2:Kt:[:u:ι::f:3:Zy:I:::I:&:Ƅ^:؃:::N:l:僴:ÛE:6a:O^::9:D: ::yn;F:䕈::ަ:ѯ :U::;z:::^:':&::::X:Q:U6:g:ʼ:P:6: K:ӭ:z<:;:J;<,:<:^:;:v:&:=:s_:ֽ:t::)e;ě:˦::r!::ED::!::ڬ:n::e+:N:ƭ::cr:߷=:6:::}:˙:::l;:::]:":@y:۟(:I::::b{::B:*:: ::s:oG:;:r::*:(G:/:u:Xg:.;:C:K:::I::R]nyquist-3.05/lib/piano/att16000.pcm0000644000175000000620000003531410144436365015733 0ustar stevestaff ~j#U9On=F6HISrU6c-/}x wg&M"W>fb[>8u/I `t \z2j2C!`!,m #q3;VOM"9MOD8_,~ v  u  N +9G[}@2DPO=W*SP"!c!!0ncl0T.%Qυ!J'ԥ.47"vnbH/|.\U(@44* mV%ؾ&A%}!u&-F+T-7+ Ko u 5"I >E6 H +8 ޵X=ĥX;݆̉ - n x J V!'))U-},&\ +\1B3IkխBb] RaX 2hJnA$ f S ; X k k V ?$dYI'b~nRrS&Eiw  iJ1@M"O!. D7)G;v05 u s  |`_ v8oI#~$V" 9% ځ֟,%rnw^,8 \<Uiy 8X . l 7 > n Z F  pL & 2 )%_lKpށ'NuaTL*I k l29% Q~8'U2& BuV%(&R{H2d   (r$>:[1Xh;v*ld$1W; B L mK3T 1MCv|NXF=Gf7YdaQ|D; & m#?MS>5%'yG*ItuUK! Y #sZ C1AlUtBZT f'q\Ch^ 5  % a v 48f9r>USV[Jz5dj.mER^41}\A";`l)gs,>K(gWn%j'Tk $ BeI> Y|2M-0/.'F@OL3C C c S VPHaohx\3#6Ct:  , k  m sJR m y,)X[9XO$ a T  j lv~e}j:B;W+t$hXZ v<#$ChOH](1x=?S&1Fb@7ep#= 3JBq 0\;J+=Jd@+;B`kLj$Dm;8eD5ke EoOoGq*)ql?{<`8tb\p0.'er A.$CY Vzq K aT/3q qQ % S z  & ; J\/p+i-$LeY 0fk#0-)emB! )J:O#p YZ^ct1yLpM^G1Qif -tfA~`G)Isxw0W\06)J7bJunZD}#Q$..aigd g:u`FVN&2In jA9>I[h0p-"KOt 0P)4oXH}w=ae`i`7F8:2~B2K|itL1fX8OoxL:a NN.T LCF{r(|vy6![W#9vp >4B~2E3*z/clWxvW<" J IcDmqm"r%SP GpO)Phkl[d ~IIn %JO@| voN*}FEpA*MD\_~YPrxG *mXm<&{n<xQo$'Qa|1&?Ugk>5SeQ +&Su>/\kz=krl;[{FoV0`7_B-nFt[PH8c_VqA(x-h!1D@F>inP&#aW _:ocp#)^eTZ:uj`u( 0DnDMMk({Z)C=w|-g;MXZiF7}qLEcbbeJZqcq-xbsKD8d=Dlb$% *+z4Ddhe>5Y]c~#o<[xqekYafl^>`) {pT?\}Jk3zJ&5DsUlb-j}'kCmr6&(.K[V<!8#-pjaxu`{#":0k,cXMk`&!oOqFs\8Uh2P5@:)q|^rj Y\ u4$("bz("1H#wA~ OS16"=t` )k #jkYE&=| io!DNOK/3/rs*EAsoT D`c{r*/~ X:Sv Rd] G}c";%D?~rrYs#yW8NwO H#-hFb Cll ^mjV]#A`=vR?.CA]Qm; qR1HcmrO2M6I:c9N[&,pqU^VFAEP]: o,2Q- [U !hy:P&"Q.GsNka3n}^NfZ;81ULDbZxDc/Q |^I+NLM|aQ$$FRWCk CL'"<bqw{DrmpE:L"p_Id$HQyrkQf`'(zP,2s;'.++ DV#\S6hympoC d>SvrQ]zntoC74.F?\+C lFZ_PH{]kG?l|pvl#8WnE-z[PL/5 V6ERs-TbaIe 34(Ort:@R#_[9.84)eLm'<40~dW]7Z\tGJG/ oiuG  18Hf=bNk]fC.&81 2SR`Y ]aHv\vze[OI0"#W*NiU6 (6``OU8Xa[ # ,hb 3HNruJ![^@TUF@goSjH">7YPvosme]2*za3RkugWVq>.fy}l>@mg OUvo^Pfw)0'+/T~fbSVtttlX]cW8ScW1LRMS.2]CWDBi (,!`*9A4Rojh^/$% &uJOk3 JD  >vAdq&>2 " MuaLLCaD<>h~wN]mUgip !:LF:AZiZWH59Xzs:4tig~cDO= O{aI< 3G@IP5 !7)&k9)$*" &/a~3 GZQJGUsj5(-!+21*+76.;QY;,&  9F9 $/%H/-?;?F8A:$ED>OW>5Tm{tTUZVL%[O,"#*40)""=FFF1!<S<?[=!JfCD^<8O33H6  *'!& 4) +7 ?4-<?:<31M[; "1hmIv|x^sxpN7?YR79BGM=   zYd  (:nlO ,xyRa"1  &  #!@/)=:Qg4+53;.%$#=% , "%/#!EQ-! '&$9F?MX</AHESZJBA4.CYVF(4&) ).,,21/=E88B' #B7 % -( .83>6 8!  *.")(- -$ )35/$&237=/$3A9AXA%02%?  *  %"+N+  ! )5$*5+0%,EO?1-/<EAI]O+",#(''(#)+"    % #  ; 9IVTB>C@8;8:4   "%/427;.%,07EI* $3*"   &%    %  &9EC0)).0        !  $0(%)$!6E7,2*'1%  (1,)2'     )&  %% 661"!%%*!"(#  !*0((+##"#      & !     nyquist-3.05/lib/piano/pn16.cod0000644000175000000620000005123010144436365015321 0ustar stevestaffSYNCCNDNCOMMD\9oXPART??????[o5?ٸ?f?"5>>(h:>i=D===NZ=@S=62=-8y?S ?3toIF @_ц@v @k;@@i@)2>_?,&@)2@??x?GRUP?@@@@@@A?@@@@@@AGMAG;gp;u;c::oF:::";L ;7>];\<^; ;dS;2;7< e<<;+:a;3;ٿ>; ;$¨:. >>>?ì?%>>A????%u ?C?`M?yl??k?=Z(??+?Iw$?P?IY?R?dOy?o?v?}V?x?ii?ZU?KJ`?A???An?D?D8?JP?R?Q?F?:?=-?A??@:G??U?;???Bk[?8?0?6w?@M?@z?6?-?*m?'?"9?? ? .? ?>'?B?Q?!o ??g?"H-?u? @??? ?xX?? Ҝ?\ >B?R>c?a?m? qa>Ղ>f>O>Oe>)>Ī>C>!>>X>>>>>\>V>6[>h>t>u>x>iv>Xo>S>J>D>@>:>){>$2>#>}>g!> r> 9=x==B===,=à=V\==_,=w=m=l:= ===w=o=zE=|=pj=l=xM=w=j=k=rN=i36=g5=o=mR=iۇ=t݁=vW=o=n:=sr=n=opa=s@=w2=tB=z&==2=|t="n==|#=~.T=C=\=x=f=L=~$==@==~="=P=zc=|=}3=x[=s=y=u=oX+=q\=rb>=lō=l=n==h=d=c+=`G=Z=VM=X=V=PT=O=R=Jf=F^=GV=A=9=9(=7q0=1k=/Y=0h=,=&=%=#=r=r='== = = =Wh<<<0<с<ϫ<͙p<7`h<3%<.<(<#RA;>m;6`;4?;5;3{_;5ܙ;;h;;c;>>;H5;H;QT;Vyh;[4;fm;jN;l#;}Z;> ;W;4;;0;+;9;;,U;k;w;;U;ҳ;S/;ȕ&;ͤ;*;,>;4;`C; ;궈;M;;@;+f<Lx<-<_<*n<m< )L< j< ;<<+<<<<+<%<G<<nS<<< <:>:f:;;; ;;;;.,;!M;%++;*W;/͛;0F;4t;9e ;>>;>B ;Bz;F ;LT-;NA;O;U;V;X+i;]x;`r;d,O;gZ9;hP;k+;m-`;p;pL;v;tD;xg;yy;{ei;{;|;};q;\;[K; W;<;%;; D;T;q;~;.;;m;;!;=;3;-;;4W;];M;:;\; ;3&;}O;|* ;z;zH;w<-D.~=R><=?;??*F>߇/>Q>v>s >@>rm)>>>.><>d#*>|M?>>j@Y>dg>2c= Q>gcY>ٯ>ɪ=ѽ>m >5n>Q>{y>>×>V>xu>ӿI>7$>m |>;>T>>Ƴ>g>;W>6>W>>b>/>?0>a>>`>>N>"? ?]??9>??{? }? ? >K>>,?)>?O? ? ?8?ڻ?/?':?E?InA?T?Q#?^2?G?;\?,?H??w>j>ga>h>(>p<9>R&d>F>)f>==={=J>M>%(j>0>,>1>;>Ei4>F0>I{>X:>`> >] >Y&>c.>cj>ZC>X)>[>Za+>G,>J>Db>74>->/>+#>$j>>Mk>m>C>>U>}>[>W><>J> >hs=>==nE=&=====sm=UC=J=R==6lb=A=9]=,='= =- t=Q=t<ŧ<6CLm<&D;:;;;a;j;Њ;<<".<-<@^@<9R<1<5<2b<$?P<#<<;י;M;G;Ǧ;^u ;#':Ǵ::"f: 6Z:m;|;B+f;%;{;H;[<m<#2;tx;o;ls;f;4;?\;@;;;;;9Y;54;;;;t; D;8;;;w;f;c;b;Ji;F;>P;6;<;(;+9;/;.;4F;/ U;)6;1R;0G;*;&h;&;+ ;%{;5;+;&;0;! ;)7; ; ;;O;):::Q:u::/: :'9 9}[A89U9Y:60:[8=:?M:ͷ::0:ӧ:8:::曝::::;:u:Y;:x :s:c:':n:+:=:::\W:'N8:)-}:_A:\ :{.:x:@:::)::ée:|::y;gf;;?;c;;&;6p> >­? u?o*|?kJ?O?!hr>ψ>>s>?=*?c ?9?F?Yf?X?f'?ZB?>?"n?9??1€?Yt??ho?=m?/^? \>I>|? ?#J?4>h>ɕ> ? s? ܟ?>?%W ?_*?u?j? o?M?YQ?v?&?_>լ>?6?d?X,?D?!S ?.?("?L???H?)$?(?a??"T?-%?????c>x>X>D>{>h>@>>U>(=œ=0=٬=j>:Ţ=j>!==>==>>f>">->/=[^=Ϳ=\=`==6})=7=F%^={|=zl;;M< 5<{A#=)= H=iJ <<:<<<)-<}H;C<< <1;^-;vx;Q;%;;e;(;;mdq;kp;Ko;/-:::9n:8`;7;PC;|G;y8;;;!;Ҫ;;:;>;F;3;;;of;<:;):.;p;P;ZdF;a;\TE;S;;q;IR;;K;*;;6; ;;;;4);:;#; Q::Xe: .:F:::ܯ;;ff;;;$`f;!:;f;B;LR;0{;-D;SR;Ek;7; ;C );F9;+C;:K;{:lF:c:+Y:Th:1^:::]:I ::;I;K;Ib;r4;k;c;H;շ;nm;`;KTj;Zj;4|F;ܡ; :@:&:.:f_:G9s9b:P77::8:f:>;l; ;C;!u;up; ;0; (:::_:t:ct:@::9~9.?9x88&*9s"9LY: :zEo:e/f:q":se:m:Y):D:::h`:j:ú :ծ::F(:y::]::J9;h:3P:GM:C8]8049@{X9:k:,T[:m:T{:\o:.:::|w::(:::.:::O:*::6GY:)9sV9dS9:k9w-:3:dm:K`:7:K8::i:`}:[:D:j:~::yp::i9919~9or8j989a9:#v:L9:#J<:wJ:6:\:9 9ψ9&9V:":: >Y:-o:1:_:P[: ::]::7:8D::r:#R9 9!9599Z8m9`V99gp/:%:U:":9:7:%N9: v:O:1O:EE: 999|j96A9W9tn9R,9Ɔ9789vP&9;9:9l=959P9̏:8zO99k:WW9b9>9999Fd:9t99-s9B%8Oq99j9,9gT>>?,h??U?`>?+>J>3M?*?U>>pZ>>u'}>=f=@N>k>>Ѱ;? x?A89?WO?>?Ps2?2f?5L>N>_>>^h>Yj>>ǎf>׸D>^$>P>ӊ>;> >#?.?N?f?*? ^>>Q>(>>>&>ޟ>,>Ѡn>\/>= >9P>>A>>E? ,f? ?I ?62?s??* ?>;? e?" ??DX?@>̑>R>.>1>^>>8>9Z>aE>.J>k">{>N1R> *[=>9=Q=B=o~;l==/@==-=V=tg="=P!=J==ߑ=J=w=*c<< =$g=.=x ==o==*=T=|==q=5==,=>g=n=`=^=*=>=== \=1=5=q1===CQ=hm=Y=lS=P=K=7=7l#=V=+=j=<:l; 6$:1;|;4A:߹:-:-:%:׭:Ū:X;(Kn:'::Cy:CF::u 97:?:5:n:G:3oa:O:*_:+%9:7::6G:0:::*::w9:X|9j:B:iM,:::X:y:4:f:y::Y:?:F99I99d::J: _9{9S9.9|9J9^::h9|p:&99H:9E:"P 9 :?:2ޢ9t9IF:9s9a99ʶ9t9: yr9:9:]9P:ar+:~XS:\9:49:!659:!9X9O9Q9/909rk9E69/u(9@9͇: w8l: 8cb9ཻ9tm8x9:72919869F:09):8׋9#z9.\9V9ߍ7:99) 8y8BjO90t"93X9::59uv9 9:H9{9\:̫9]L8]8}9F9R9@99/7E9+:`999KA89ޮ%9ޝ9h99889q99й9'9ё89x[9%/:69#9 K9s99Ʀ9s{89899q9l9b9榶9YL9T59zZ9uL9799>9899.: 9,9+9^9h99ʞ89w}.:9;@9 &9M99Wx9s879T9<$9N9 o9s9m999kW8:c9'9-$9N=9 9z9 9:9c1998V9{w:&9H839b?86928&~9:9v9_49u 9}83p9K9*: L[9)m/89Me9;6X999C9iI7909ҁ9A9999q899ȵ9su99W9y99l9d99c9~9*9E$:]9D]9499B:$<9|93e}9/]9Y9S7o9T9H1999G9hn:9-9999>S99Ʈ75:9!d{9 9r99sk 9<98Rh9CL9Ξ9T#9gI/9Y8:9;99:(!9r 9@E97g99Sk:8) 99$/96w99ϭ9K9#9V89d98:_9U492Er8힨9j9o99N9 @9+²9;9m799cb9!9aW9I88f9]i9S999~ 969ݡ9׎$9:989?e8=888"989P99E7W9Xh]8y?9&Qz:'[(9V9 V8K929 r9X9C[9_#-:9 989L9nt39 99O&8}8z998V93?p9l89#j999H9>w9v8`٘8v:]9$9|v9Ly9"9 *9MLR9фX9z9a9q999z9n9J9Iv:8G9N.9|9#9x9Ow88Q89 E9<%"<;V:w;Fq;K/Y;"m;X6<4;E^;;#:;O";H;;v%;<*;;;ά]A>]O>`2=>n? O?0??~B?%?<?b?0J?,?Y?`=]?f??gB?-W>> >>> 6Y=qq@=:=8>x>o>2$k=+=С>Ơ>8>$>">nkr>>`>->>S'&>Rk>\G>*e>>Pp>~>>>o>`F>ؙ>#>>>o[1>A'>z >,>.>w>]>G =Ֆ|=6>!> > L=;=Ί=À=f== ^=DtJ:>bH>+>)><{2j<,><;l;;<;N9;d;iԴ;X; ;+I;;ہ;Y;;t<; ;W;n;[j*;;[;;-0;-:;m;;:<; ;:;;U, ;;Um;շ;`;x;Q;;;-e;--::ƨ;9:;::`9:9::T:O::0:㜡;j:[:# ;::ʛ:]:\:31: ::Q9G2:G9b9:s9:i%9::Qk:؄:\=:p::ʞ::: i:*99b9?de:9#:a:9vR:I:F[9 \:8@9+?:.:B|:79:(L:?Ό:C[8:!߫9WU989і?:919>q9ӕ9N3>:Y:+9ʮ:#:Q9ð89,ծ9>999by99E9:" 9܂92+9SV49)9=9m96:Z91S8ޏn9ߍ:)(9.&9:ؤ9Q9:9za9,9,8um9#I\9X 9e9a9c9$:0p9#9+?9L`9x9p99?9\8R8i99~Y9n959Z9f9:8+:9&U9QЧ99z9999j9 f{81_9U9*!8ܧ 9S9u99ل9689F6904S89`9g8i9'C9[9[9 9Y:89|9BE9988\9dW985W9[L99'9.9}98b%8P99.8}9nK9 8g\9-9^T9M9I989Ȱ9929Մ899q9 8;^8B99?929}9d 8;'9 8;929728g9@9WP99#9bp99999US9d99#688]990u9MX9 9 >99 9ˬ9CQ9:/͑9r^98%9x8wӾ98:t|9Tk88>9,9!9.91/99$8H8CH9E-999Y998P9H|8[g9*9I9#c9眵9V)895^98%989 8B9E)E9܏9:949989§8#q9OO9999q991d7@T949 9r798Y9ӻ9k8/9է99L9&!9B89lY969T99Y9,N849[8z9g99K9 =}9S9[k8:9kL_9U"9J8p8/7Yy8R9@8F896}8} 9!8+8Oc8g9c9~9oH: +9(8i}9=ۃ949-9 8:]^9C 9 c9|8n87ݡ9 g9 u9d8tG78V997nX8ȭ98k9'9@9qX9k9d9^9g!]8 9u8j9Jr: u99 99"9Ao!99.B9J9LR8|8}8^99798!x289_9 93.9&9<~9I99&s9G9A9 T9el9Z9XjZ9BN9RF9f9u8592ѽ9p9n9WQ<89z!8:99%9 9Ba8-9s88899gЁ909˷8"O9<9LA93m9G9>919gF99 w8F9Sv9&w93S98x#9 9h299c08a9\9d899r9t9^399:28y9<8798i9uZ]9}.9![9ty939{8:9299S9s8] [9xf8G9Is[995928ײ79+9i9瞼98/9e8=U=9iPR9z89h9r8*9998u9{9999;x;䲧;Cc;TK ;2;'|~>>u?S?c;? :?X ??q?>>O>?7?0cB?[]?j>X?Z$???/? >>T?/?.&?)l>J>??V?3>:>~8?9?KR?")>au> >>?= >j>'>#>Ȱ>ʼnj>k>q>l>~>>z>R b> >>_=>i==z>*>%}>>~{>s>(>-/X>?=>C3=>hS>Zz>4s>H=(>>8>mO>=ҕ>w@>>FM>bt>1G=> p<>P=$=T=+==h=U$w=@=>!~> ->>I=NT=E=P==%ц=;<=I<}=^Q=|Gp=A=L=C==[c==h:=/%e==oJ=1p=Q==b=F=~9=JB=vl<<<=W=!= dS< <:H9Z=:U:9B:V9n9:\*9929ɐT9f:/::: r:B\: 5s:EX9Z:9M 9) :$:#:=[9S9E:f&:hi9T: G93:2`9:b~9@::a:;8^L:1+999=:@U:RG:f929:z9U: ?x:T:?:S~9:9:+R9.D:]9E:.H9 :+:!9ڶt:s9u9:P{:.: h:Z9998968.O99:&Zx99-:gՀ: H:99e/9N39z:-^{:^:+p9B9E:H:%9w9Q:'R:4C9۰97I9:99G9WR:U:p:n&W:EY:7_:__9 9<:{9)z: :0N:Q:<9m9< : EQ:'gO9V:H:EKQ9:b:zP:?>9:<:9: :R:q::њ9:DE9Rx:~9Z9X9<9i:A: 9ys:FM]:591:?H9r99:\o99999[:K:S: ::q$:): :m::~:fu9(:9z9:: <::io:9 u:T,:: ^9A:1G::M:> :989Z9O:4c(9v~:vY:,:/9[:N\9;: S99:R`::D4{9r$:9 :{:${:*99I:o9i:e:4@::([:|q:,:P:N:B:]t:(g:C۽:"z::I :@:nN9w:09~:>[ :F:z:l:F@:8\9:90_:BE9+:ZX: k9ݿ`9F/:&{9e:":L:9I:8ֱ99#:U:26/:':@B9K\9:9~:B99/:K9/9 :2 :7Z<9o,:4WV9B::9:(:/: +:-C9t9~:/9:@: 9 9`899=:&5:AS:U:-_:P:5pU9+:9=:j1>:(:K m9j]:JA9!9i":(>9ߠ:=k:Mlb9K::099@79:n9?+99( :71:Ր:,)&:N:%:29K]:1z%:399ҕ>:2:#8:9\α:I:&Y:'A9?}9 p: :c:-:&Y:;d:99ΣI: 99P`:`: :9?9e9:*:s#:/:vc:vR:"Nh:F::y:$+:!099V:B9:`+:?:,F-:]H9F:7%:\:E:L9:M9~919a:N49^ɪ:%R@:'9:ve99:ec9 ©9z9M9 9L6:-?9^9~:,5A9;J< ;g;y<κ'>>p??G?F?$t??9j?2?L/?;M?KX>'?!?4 ?U?'@;? ??G? #?4ƻ?8?6!?!??? ?u3>>:>V/>mE>>i>'>>>j>>>}>>d>zp>y>%=>8>X>>IR6>8@|>84>">y.> x >.d >0iF=4> G>%=әX=C>,>>8>F>f>R]q>%>(>=~:> >(b> ؄>>k2>7>;1> $> >>@>/e>*>>(1>;%>p>^ 5>->===!==Љ:=;=#=s8=r_=UZ=cR=Bx=;5;˩L;;5;l;H;);Y;}[;6);z;;5s;s;;Ou2;I;0;;N;m;Q;X;3;R;S=;;T;tr;Kk;*i;u;Z;b;n;;T2;`;eP;Rs@;B#;R[-;e-;2-;L;`m;;;M ;Py_;J`;t*;>';*h;Pګ;;B";X;6q;(;CM;$<;gΑ;^#;TL;\;9;._;3;P7;;N:;YB;/;Te;,t;A;#!;%2;>;#;-8;H޳;(X;N=Z;N;;sf;Hg>;7x];;; ;J-o;2Z;@F;; ;B(;S;#};8o;0;Bd;!Z;];/X>;'a;&3e;f;;5y;'+0;8_;I;.A;-L;A [;/;$ ;>;;#+;;g;,k;;,:z:,; ; 2; ;0;/U;>`;6;;O R;1;O:p;.9;L;%?;Ĩ;A;J;7;=;1Y;y;C ;D;.v;;,d;1;3;";&9;(>;)݈;;::P;BР;:XQ;$;\;7;4;8O;;7;?X;C:I;KP;ec5; Qc;>Dk;?;`-';&;)p; ;%;K\;2<;;f:vo;ӳ;5;;;e;q;/4];3;|;M;,;";%;Mo; ;<;;}; e;;e;+X;B{);$;x=;h;9;;?!;:@Y;a;;!;T<;">;);;%;.;G;;C ;a;;8;*d;<;4/;&;:!;E;0d;3; ;^v;;=;0<;>P;(,';%s;:V;G;(;: ;^;[K;;;';"I;H;1;8d;.,;9E;,; ;;x;0:|;0:;5s;f; 1;KW;79T;';I!!;$T;f;F;K{;;*;1˘; Ġ;:W;9%;GN;3r; ;%`;,;/;;*;#;(;7!;.^;-;:;;;FF-;;,z;@2 ;.|;0;;$;+;;@K;`;P ;)~;Wv;*0g; ;;2(; ;;;co;'T;O;. ;53;2;S%;( ;>J;#; e;.;?;?U;/3;Y ;V;;;C;4;(4; ;>;WՂ;<|;&;:`;;';26;s ;AȈ;.p;';#I;@s;);$צ; ,F;P; ɏ;;*eC;!.;)R;T;A;(B;!V; ;p;M; >;%F;!`;H;4;!;, ;)':C;>; K;;l; ;%=;(; h>;&&;SϺ;p;";;6; `;62; ;;;2;k;'d;V;;S;:";J5y; ;;`;/;E^;6;;4;4;+;$7;8+;>/;+f;$ּ; 8;; ;ú;<;/!);E;0F;7}; 4;;%H;mA;";C;1p;8ȏ:;;*q;i;+״;8C-;$2;5-;:;*L:;;,9;K;;!|W;<4;0Q;% =;0 ;+|;B#L;'a;;t ;Ay;(;4;(I;A;*N;S;Ba;45;;;8#Knyquist-3.05/lib/piano/pn10.cod0000644000175000000620000003705410144436365015323 0ustar stevestaffSYNCCNDNCOMMCm:o PARTO???????????>6?Sڍ>.(?C;>QN>=>PhI>o=!WT=f>t>@7>;=91=P<+=N=<<<W;;o<&;;;);~u;rO; =;m҃;;[v;Tc;h~;Jov;M|;N;;e;>n_;2;8O;1n;5;,V;-.H;';!;6n;ӄ;6s%;;*G;/;v;ٓ;w4;; z4; E; e; (; ;;ĸ;({:L>?P3Lm@ *3*@?I?Δ@F@_]o#>㎾ @DE>f?@ Q.@QB@?S8@3[>F]?_k@b.߿K@} @:?7^?yM@@xW@{eryP?\@S@[m@;`@q@O4@VO@g?U=,s?@?kG?Ij@bM}@4@ @U@Cb@?@=[GRUP?@@@@@@@AAA A0A@Ap?@@@@@@@AAA A0A`BGMAG?%? ?91?3J??$Y?K?Y'?L?J?YH?eN?cf?_B?MXk?Ld?Z?]X?\?dD?j^?ns?rJ&?z??{`?s[+?l:?n?vܦ?{ ?tp?f?cDŽ?g`?eο?bD>?h$?m?j?jW?kf?ic?fU?b%?` ?al?e?g??fDf?a۳?``?d?g?bj?`d?_[?]1?\~?Y??V|?U?S%?PS?N?Ob?L?J<;?H?I?J?K?I6?G?H?J ?I?H?G%Z?H>(?H?H7?EU?Dx?C.R?A?@y?>.?> >>>N>\>>><>&>A> >>~eb>l>^3>N>?>2:>&B>> ]>-====3=ʫ=m=A=P=q¬=[C=C=0=D= <4???,?#?ʀ??B ??u???6>?X? ? ?z? ?T? ? ?]??1??p? ? n? ? ? h? :? ? ? +? ѳ? A??? c? Pz? \*? /{? X=? R? ?p?w?Ƨ?b~?F?74???@>b>> >>>x>9>>ƛ>S>u>>F]>i>>>> >>8)>e> >]>~>$>>쟝>>4p>S>鑚>j>J>>R> >@>*> >q>>z>m>>><> >>>>ޫ>'!>>"+>>'>z>Ӟ>?>|>`>>*>q#>VH>>>>97>E>F#>>>+>P9>g_>>5>,>>x->n>dX>Yũ>O,>F:5>3 >*Q>!u>->>>7=z=)=d=&=׶=kT=q=4=_b=,8=mt=Y(=FZ=2= D=H<1k<& m<<@<:;;|;6;;w;1S;c;P;*;׫;߄1;-;O;g<<&< <x<<<%<)<.D<3*<7M<;%Lh??n>F>.>e>T>3\(>aA=>N>8?R?R?*?Iz?4h?v?&D?7'?4 ?? r>^>pZx>6>j>e>j>e>}Z>*>&sZ==>T<>F>=SA=>K 2>`>>lִ>_~>EnL>&:>xd>[R}>#V>\d>lp>a>Pp>T>_>>+$> >R><>I?>s>>~>>6>rz>>U>>e*>,>>>ѫ>|>>>>Td>3>? c? ?>6?S> |>>>%>?Q*>F>vv>>G>n> >K> >㉄>>y>Fp>>J#>Jh>ӛ>vp>j>L> >c>>>>p>ܦ>3>>`}>C>>V>э>c>4>ϙ%>#>̪ >>û>>͆>f>m>>`>+c>>d>>57>>>~a>>_}>->U>0>">>5r>1>>>H>>>>t}>H>>>>'>b>^>>yW>y>t>>o>mU>kY>iF>eA>^>]1?>W >TK>M>I5>C>>>:^>8>3_>1 >,7>)ke>">>>> >B>===h==8=z==\="=κ==}=}=f==B=1 ===x={sL=pg=h$=Z=WW=N}=?o=8=6<=+i=#9= P>>"c=Ϧ=!_^=w>^| >>UH>b>dv>U\>ha>[>CE=7f=x=o==Q>=}>)>|>.>'>>d> >C>|>>Q>;<>>>˔>(>R>z>>>B>A>>>3>,>>#>>ƭ>b>{[>>>>">>׎>K>S>>>>>J>8>|>o>Z>jR>^>ӳ>n>ǹ>Yl>F>„> >ÿ?>;>´C><>O>%^>vx>z>>D>Њ>e>l)>Ь>u>Яy>϶>Ϝ>p>>;>>>˽>/?>Ǐ>m>r1>B>~o>ng>>ģ>> >j>>C>)>>a>C>;>>>>>+>˵>/>%>">>>UK>>>> >,>{>I>ť>>>`>>E>}>rK>h>_c>W>K>=y>2>'>kT>k}> ,>==;7=%=<====8==r=v=eW=V~D=H(=9{=1\L=+=,=+=-.=0=93=>%=G=N=WK=[@=_s=_j=^/=XH=V=LYs=Du=>=3;=+=#d= :.==N=5=e=1=D=u== =t<<<Α<8<@[3?>u?<{?>G>>`>V>f>vJ>>>>>">> >>>t>^_>Lw>>m>2)>(3>>p> >=/=/A==/===|=s=J==ڬ==Y=~4==#I=+=(==N===$z==PB=+=D=k=!"=MB=}X=zY]=sU=n=fy=]=SL=K=A=8i=0uU=&=r==<%<ւ=].=`j=cD=dc=e=e=fqz=eX:=f U=eD=f#=eG=c=b "=_=\=Y=W=T=R=Pc=N=LB=Hh=E=A===:=6J=1֦=-aF=(b="==\== =Ť=8<-<?a?c,{?e?e?c0?a7?_j?^?]E?\pn?[S?\?[l?Zx?Xt?Yy?Wb?W;?Vt?V;?UM?Sz?Q?NNf?M?J?J8?J ?L'?K?K|?I?H?Fj?C?A?>1?>7?>\?=?=?=B?=?<q?:t?8;?6ڸ?4?2?1?3?3 o?4(?2_?2(?0m?._?+?*L?)o?)y9?*>K?*@&?*j?*L?)`?'U?$$?#k3?"?! ?F??E?)?y??F??? ?:?X?\??? }?d?n??`? ? ? ?Z_?+?T? ?P?O?o?4?PL>>X>֊U> >>Zw>a>>r>\]N>@U>$>I==ն= =9>=z==33=1e=/=-o=,H=+=*g=(+=&d=%T=%*=$@=#_=!^==A=O =E=ƃ=v===>ӥD>n>-??;?9d+?:|?:I]?L?N?Uc?I?R?`?s?k?n?oE?dw?|m?uL??tHv?sY?grR?a^?Kۂ?Ib/?D?BI ?7)?=x?B?K{?OE?USE?R,?Io?;x0?3M?.z?)á?~???=W?@???Gz?7??G??k? 0?)? ߍ?? '?k?x?>\>M>>>Q>>+>k>,>n> >>i>>LY>G>H>G>>/>>>/7>N>>>>>Q>>f>/>0]>>l >u>KX>>>[>:>O>J0>s>D>q>;i>c>q>>8>>™>$,>:>d>:>S*>>;>0>su>*V>݌>A>>>K>q>@>>>t>>>K>>>>ew>s>w>j >Z8>NpJ>9.>% >6<>Fr>N/>U*>Mn!>8WQ>?>Du>A>A|>? >=>8L>)>%>)؝>)*>&C>" >H>3>=U=== 0=(?==o==}w=mt=SKl=7#= <<=<[po@>Pu>J>L>꾴>'p>>᣼> >>/>@>>J>u>H> >e>> >?>q>V>z>Хe> >a>X>>>>W>c>H>>x>B>$>>{V>O>47>x>ߒ>t>:>3V>>k>wj>>U>0->_=pS=={= =:K===1K="=`(=?p> > 7>޻>->S>O>L>>z>U>N> >>1====24=>f=,m=&=?=t=X3=Dac=+v=G===;F=="Q=*=Bϝ=U`=_=ys =a =i,= =4===AV=s=E=n=91=‚==k=== =h=.= ==~=0==xLs=o=kg=Z=SK`=L=<: =6=+==M==n=0-< <հ<ІG<?<?:sk?7Ԇ?5ƭ?6?5?7?6*,?7?62?;@?6 ?:?3?7+?.?1e?(d?)? \?"H???K2?Y?g?-b??(?g?Ϛ?{0?c??!?v!?.?? ? jP?h???> ?8>>A>}>q>a>B>s>/>%O>tB>k>>>8%>jg>Z>KR>4E>,>Ɍ>ͥ>Ř>d>m>H>8C>/>_>96>+k>ȩ>2>>>a>>O> >(>!>o>>>]>i>F>u>V>=I>'k>>4'=`=[\=u==;=%9=K==!X==B=%=w8== F==$=G=0h=ܨ=?={=2==W===d=S=]==v=GE=](= =M=/f=s0=W== =s/=^=Z====ݟ=Ԉ =o=&=ˇ=v=!=C=T=r=D ==g-=(=:F=m=at=JY@=7"=)=!3==3<?_? ?7?"?p?,WN?%'?32?+?7?+C-?0?#?'w???/??; ??N? j?]g?' ?|?'? ?!%?B???? ?M? ??G?ҏ?{?J?g?8%? ?PG?>?R>T?>??U???>e> >G>>d>|1>>}>a>ո#>T>!o>>C>K>͕>>>;>C>~>]h>ʷ>+>>̬>">>m>>Z`>I>>S>>M>>۴>xT>l>:]>>`>>8>>X >>>>>>)>>,>>Z>>x>e!>G>.C>'>>X>#w>=8=!=m=r=uO===i=p=S='===mD=g=mx=X=?=E =R=NB0=Rq)=Uv=kV=>3=T=E=c=E =7=sY= =A=α=!j==.=d=!==s ==q=====C=z==<<<<ѷ<<<<<W<.(<23??cf?v?m?\m?rg?We?]@?Aw?[?C ?TM&?&?6?p ?2a/?? P>>=?x>5?D??pN? ?GR?d>>Y&>g>>!q?>G?p>h> 4>)>t>{>Մ">>Q>8>}>>$>^>>>E>ӽ>>ٿ>+|>>>,>>N>+>x> >>>b>ϊ>U\>_>x>b>>>>N>>>TG>H>l+>!>.>>>Y>>9>>f,>6|5>> e>===5=l=:=r=2 =$>g>U> A>҂>$>%>>>>>> > D> f=== =-A=4=?=]=4=;J== = $==9=Z=#=ؖ=¿==="i=oT=z=;=U==xI={=V=fD=0=q=E=4/== =1=$.=$N=%r=t= =_= $<ь<<#<đ<<<<-H??.?qN?x?s?>#E>n;>\?5?af??c4?,">}>? a?6܏?^:?@r?H>)>ށZ??;P?F?O>P>>?$?M? ??ђ>@>? ?(n}?F ?&P?a>o +>%>?6{??{o>,><>V#?M?#\?c>>lbb>!>I=? ?j?Y>N>t>>? >>>>1>t]>y>>h>>>zg>t>oR>G><>> >g>`X>ŦQ>>r>>L >zQ>>e|>,>>U2>BDz>v>l>E>!>C>>5>V}>>>к>>G>g>Eš>@>w>1~>ɻ> >>0>Oa>DQ>Xs>j>{uC>je>!>)IB>Eĩ>f>l<>e>/>&>4F>62 >]>V4>K>>=kN=M=<==t1=ʚ=P1=د=f==ډV=9=k==h=d==;=^=o=c===x=`t==|a\=ѐ=m=ic=M=?=p(=O==Q=;=.<0&=%< =-<<;];>;dos;L;M;rY,;gW;4&;3;?V;,w;9;i;1@\:: s;";;E;;7u:}1;/:=; }:(;:;:˭:?|?:?`N?Xʺ?N^E?`{??/?Sni??hv?BC?KT?Qj?X?>U?1Q?V?bH?3?/?G?A`J?C?.5?T?A7???{?}Q?5?']h?$\?y?D?k?*_?"? ? ??C?$A?>ƴ?~U?,>_ >W`>$n>"f>>Տw>U>ٳ>x> %>u>B>>G>>F>TQ>U>?>!>4>)>->?>}>->:!>v5>W#$>V>%U>ft}>q>P>Q>>CJ> h>c>t?>&7>8:S>?j>.7>T7>%tL>>F>Uw>ŀ>9>;>_m>4:>P=ؾ>M_>?+=v={>'y>>5>=ޠ=>z==> <==׀{=諢=ޞ=ʏR====O=3=% ==&+==u==re=hb==L=?=_j=|=we==V0=c=j=8=N=*/=(=)\8===%=-b<_=&==g=<%==l<щ<<0ӗ<;&<HE>%?^\?Q>!z>?c{> =(?Rd{>⮂>??T6>q>E?4=J> >L>6>X\`>d2=N=^>d|=I>>T=>e>5b?I>_>S=<ޙd=c=w=d!5=>%J=;=D<=)V=AHs=KĀ=D<ԇ=0< ?~< ՙ:uJ:r{:mI:p2:o=:ql:k:o *:f:@:o::le:o*I:k:j?:nK(>&y]j? ?2z?\c?w x&?@ 対EuEb??QT?'KiV@۾qp>$?@ &? @&we8@Q̯ @2 ? >b@MĊ>=?vݿ}!?:?@$uH>ş@T8@0~f?b?q-^h\\?ج@p}\?tVU@-@?@K?֏j? >C,Cv@h?? ?_p@<@9_<0@&JvǾ '?@=@?m@?@KXv6@].@Z*S?@>2]@bǿ!=/@$@IG>WI@O@ft=I+?`->Dk?5R@K@7?;}r?Ĝw@~?|?x>@q @qHD@I@^;ھ??b=#@Mt@q`@0Z0@<@ @6@Y?!@-@3>@M@_L@W> ?g@0J@GW@KI?1@!վ5@w@ M@ZQ@G=^a@ @!V??)v@@5@s@$4?'"+?Lq@|=@-^vR0@-=1@ @?`@M @q@kj@?ۨ@taP@܊@({@@@uUi@eqv@Q@~?R-@@;d? @ ?&?F??14@M?Fþt`? ?l& @j@m?9l@cdY@I@@ !?x?0?B?@c9=@uB(o@-@L@@*-@U)^@$=c}@5?Ol??{y@?@{@n@ވ@w?>@>ҌGRUP?@@@@@@@AAA A0A@ApAAAAB?@@@@@@@AAA A0A`AAAABC|GMAG=)p=3:>!?C??q?T?B?N?dA?pjW?t?WY;?H9?f?lTL?[U?D?1 ?8g?J?K?@k?20?/!?/?.?(F?"? u?'K?'y?!?w??)o??6??3X??????? @? ? ?a?l??uv>*>f>>>c>">>>/>E>/>נ>@>ʤ>Q>~q>>H$>L>>Y>^>.>d>>%>@>|>˪>+>֗>3> ><1>>Z#>¡ >}>>>n>q>]>r>>>>ް>Pg>M>.>r>u>>5j>T%>Y>H_>~(%>o>^VB>IKw>/#>l> u>u==V=q====X=n =GD=0{+=-0=1=%=+<Ѭ Y>->͕?7j ?Bq?EwI?J?4?*E?<]f?CU ?`s??t(?[?X i?L?Be=?M4?N?I?G­?CV?::?4`?6?8?8B?<%?:k?6KQ?55?6?4m*?2p?0e?0?/?.?.*>?/n?.t?-%?,eO?+{?)g?(?(?'b?$R?#?#%*?#m? ? $g????J??#?v??_????E???%?V??w????,n? ? O9? M? )? !?s??[?d?|?4 ?l??ݨ?@?_g??>>>>>>3m>>lJ>p>>ý>-T>>eY>˅>7Q>>>[>Km>>>}(>n>aS>T>Gs><;>1ѝ>'>,>>U>>7=95==[=I=D-=+===/===x*=)J=S==2==N=J=jk>(???|H6??XD?B?6% ?. ?-????6? ?L?!J?'?(|?#??FG?̳???#kE?%^?%3?"? `>?Dm?cp? ?#6?$?#?"? 2?Q?q??F??W??#??r????3???ʸ?V?:?'?E? {? ? ? zv? ? ? ? Z? ? ch?L? ??c?8[?|X?-???+? ??Z?|??z??.?{>x>>/>U>a>\>cH>>C1>>l>sF>>7>">>m>>~>>V>dm>>v>D>T>Y>*>5>U>>B>>>x>iG>Zg>L6>>Z>1 >">9.> )==r=̴5==[==vM=P'=-o= Y<Ьk<x?8?oz??\%;? >l>C>MQ>Xh>>`(>>C>ֽ>f>[>Ƌ]>>>B>u>:>`>;>k>ˠ> >ȜT>>&>.U>6>ɸ,>>6>+>5>>)S>Ħn>71>>7>Ó>ç>ą>>á+>{>>š->j\>.>=>i>+V>>+>K>@n>%>_>>9S>C>>s>o>>>>u>a>A>m>>u>>W>6>*>,2>>֏>>\>>p>U>>>|A>>>@D>T>>>>m:>>Xr>>B>>4X>>\G>N>M>>|+Z>p>cȊ>X{>MՍ>D!>9H>0Cb>$@>>ق> >=!=[ ==ȯS===x9===a#=ti=c$=T=Jʢ=B]=;==7u3=3=1'=5$?=7=7T =9=>Z=,>^?*?d?I?6 ?,6??_2?$?dl?\j?N}?qU?x?l ?ki?d1R?fD?}v?vp?p?s ?kx?h?d?d?aAh?`?W)?a?^t?d??bO?g(p?a?a(?]W?aʖ?\n?`"?]R?^X?YW?]?W2?ZB?V?Y?U?XzP?U ?Y+??W!?Xw?U@?S?P?QD?Nm?PH?Mn%?NE?LOj?Nzs?HF?K!?F:?J#?F?F`?CK?AK?Ao?@?@??m?>P{?>`}?@9???;!0?=W?;&"?K>D>>3d>Hk>|>>t>>>>8k>>>[>m>h1>w{a>mP>gK>]>RJU>L>>CD>;%>1>*>$*>[>7> z> >s=D&=M?zH?6 ?Ab?Q?pX?=?v?i7?bE?c"?edY?i/?ot?t?sF?s?wuu?{??ϗ?~I?|?|+?{=?{?y?w-?vk?u)?s5?rxs?o?nm|?lv=?k?j?h(U?ecC?cc?a)?_L?]Zc?[ ?Zz?Y?V?U3?R?Q?O-)?M?K?I?Ge?Ey?C?BA?@^t?>G?=?;jO?9Pr?7 ?5??4,?26r?0?/?-?+I?*?(;?' g?%?#D?!hV? ????|i?Ʉ?&??Z?ʯ?z>?? ? u? q?O?&C?U? ?=>d]>>L>o>O>>9>FN>:>m >> c>>uQ>K%>#;\>n=7==t=sb=oX==¤ =͟={#>> >>>>g> > >====,=F=<;==L=h*=N=<gF?G?z??i_?R?S ?e:?t?w{X?v?sb?u\?s$?r?tK?t?t?q?nŵ?m=?mOs?n?ob?n?m?k~M?i?i?i?iOq?i&?h1?fw?e?d?c?c*?a[?aGB?`(?^?]r?[z?Z?Y?X?V?UA?Tr ?Sq?R+?Pg?O8?M3?L?Jt?I?H?Gץ?FM?E?Dfn?BX?A?@\Z??ƀ?>?=e?>>D>_>c>o>;>>>fJ>>jQ>v >c;>R>D1>7>+Y>"K>> ~>=:=b=~={~=e=/I=f*=Wd=Y=|"====_==Y$=={]=t>>$4>?&s?? ^>"?>?? >S~?@?7 ?9?8ּ?5V?J"?2J;?2Ա?*?"=??"&?(?, ?-A?(I_?}?4n?W?%?(?V?@?pM?r?>?p?9/??? ? 2???q? >"?>0>>>>> >>\>>>Y>>8Z>>>:>4>>>vp>nK>>z|>>ؒ>B@>ב>ڗ>ԇ>V>e>ӿ>̀>ЧQ>V>˨w>!>ӈ>ĕ>o>>=^>>N>2>Y>Y>x:>>~>>G>)>>>>0;>p>o>W>>R>2A>}>w>R(>7> >=ď9=3=;=x=ƹ===#=>y> >>>">"D>%s?>)g>%b>&I>$c>g>M>p>>t>m>X`>N>%>&t>'>*'`>*>)= =@u?!?x(?P[?;xp>q?? ?/S?HU?QƟ?YZP?\.z?X?L ?G5?T?h??~?|?xKL?u?uZ?y?v4?tQ?s?oG?o>?k?k7?iD?h?j?h?g?h [?g)%?e]?g>!?c?eN?c9?d^M?e?e?f?gO?f?g?h.?en?eR?eI?cz?b?^a?]?YE?Xs+?U|?UL?Q?Rn?O?P-?Mp?K?L-?J7?I`o?FW?FA?DG?Bbt?@ܲ?>Y?=?9?9?6?7+?4?4V?2?16?0s?/?.u?,?+p?)?)-?(?'?'?&-?'?&h}?'?&L?& ?%]?%n?$I?$=?#l?p?;? >#>>>i>ԵJ> E>?>;>c>,>'>F/>h>ZQ>A!>6dD>&.>/3>==m====U=`^=6y=#H=#=r==5R?7??g?@ ?6u?<%h?F?Vr ?bZ?g?c#?b,u?d0?fA?dT|?d?fkB?f?i k?iW?h?g?j?j ?j?j?i?h?hW?g]?d+?co?a?b3?c?cO ?bٗ?b\,?`?_E?]?]L?[?Z?XY?WT?UH?UU?T ?Sh?Rd?R ?P?Og8?N^(?MF8?L ?KM?J?Jt)?H?H̡?G?GY?F#?FY?E7o?F ?C?C?B1?B~?Ab?AQI?????=??&?%~?$J?#U}?"? ?Z? ?]?,?N?`?b+? ?e>.8>>3>>r>Ϟ >rc>#l>>#>>7>X> ">jO>}> ?>>>>">5>wd>kU>`">W|{>Mw>BE>8>0u>*y>#VZ>->#>`> > M>Έ=(>B5?X?l~?N?ZS%?l.?v?uā?yh?}A?s ?yVl??}ż?s?m1?q?j?n?f?Y"?OL?L#?FC?Ax?9V?2O?-?(2?%?G???}?,? ?B? ?8?#N?'?+:?3?3w?9^?9=?==?=A?@a?>%?Ah ?=?@?;?;Z?7t?5>>?1B?.h?)?%???7~?v? .?v? H? ? ? ;? ? D? u??gc???|?Ñ??y??K?? =r? `?|??a?k?D??f?S?d? ? ? ? ??٠?!>>>q>E?6?N>q>>>%>>>ێq>c>A>٭ >n>>3&>>*>>X>K>w>>>(P>, >z!>>>x>Q>b>n>^v>q>p>[ >YV>dy>\H>Nv>Qf[>R\=פ>?;Ns?|F??w?c2?>?P>->Ԩ?(?#\?1o?4?.?'$?? ?:?`?ʤ??.?g?\?A??? ? W?U?>>i>>x>>@>,>*K> >ʎ>T>6>>>/>?%>g>N">\><>>՘>m>>>Ν>>ɋl>O>>> >+>Ӝ+>2>z>R>>7>->%>>u>_>ʱ>8>N>!p>_>8>>>>>+>q>>p>>>>T>@W> >?B>U>;h>>j>" >w>>>>->@>>T>>u>~H >eC>UF>Qq>Z4>\kG>_>IWL>S\> !>Tv=L>M=:>4`=> =>A>u=>w=ē> 1-===q=)=u1= =~k=K^=V=LO=y==n3>F?&8?n??g?jo?b?3?/?&m[? L?1?????[y? ?^?!'?k]?"h?&*??? f>훉>3> 2>">???5?6?6>:>V>ޒ>K >V>֋>֭>v>>>*&>]>>3 >Y>>;>>ΐ>,>,^>>>>>>>v>T>#9>%>>>:>>}>7>oX>T>>>7>1>(>[>->>>n>ܙ>D>E>>]>Z>_>('>~k>n>e>T>HP>495>2>#oK>> j>Jj>-D>"q>1K>%bX>2>Sl>T%>R$>Q>D>'!>p>C=x=Γ=B=j=q=]=@=L=F=}=8={=>G>j?H??f ?WZ?Ev!?O ?C?Mz?CV6?>Q?y;?>耋>9>>؝>9>V>7>٨>lc>>>>>{>l>>>zH>>!>|<>yR>h>{>a>s>X]>]H]>EC>G>9R><>8>-r>0f>%>&d>>*>l>`>V=L:>=%> >> >>>> r>#X>64>/s>>1\>7>>>3>U>F>c>X>qAB>n5>0>>>Z>B>v>ܢ> >x>(> >>m >H>s==l="=b>>@k>U$]>Zh>Xv>Pr>CT>,>==ѵ=R==h<@= %= ?====E==1=Ѭ=uT=D>T?n0?(o??%^?4>j\?C?ȷ?:.?>m>E???>>S>? m?f>)>>?N?5>*>L!><>>*>>)M>R>mo>>>>b> >2>/>l>~>@> M>f>C>vSu>7>>>r.>;>=> >>A>R>I>>>+w>T!>K>>>~ >>^,>>o]>>YG=>>/>;>M}> "C>)]> C>T>BH>(Q>>>.>m=3>1p>Zt>p>oDm>E߅=>k>h>A>!Y>&[ >jx >>las>'>)+>li>X<}>C>>;>m>i >j>q>`>R">s>[>I>1>ke=ͥN=7g>!=\=@=/=C==ئ=מP=Չ=6> @=^>\=m=,=T3=Xu=̵=`n=85= 8<|<)<>F??0? ? (?o7?=_?h?8y?K>?.=?.T?5?-*B?? ?+?e>_? t? >2> >%>>E>dW&>6;>>#>;>>>Zd>~>>>B_>O >?>߉>͕>ˊ|??{ >m ?w?]}?(lv?X?tm?U?Ds?9?%?W?LѦ?&?):?+?AB?+i?&{?E?, ?6?$?T V?c?4|?.+?J.6?.?,?<ή?6t?'Y??>?!1?.2h?_?-?o?"#E?? ?lv? 4o?>N? >f>w>T>L>>!>Y>&>=>s>;7>BP>ZJ>@>ˇ3>>ݳ? >>>x>n>*>ٌ>Yj>C>?v0>[>'>'>w>>3<=/=>]>J v>]p>P->:e=F=|U1>>7 >2>;v> c=h=9d=;===#=>?.??s?>}?`T?y?,c?+?b?V>4>W>>ǵ>>?R?.>>;!>$>f>%h>S>v>k^>z>>>dD>>ژ>j> > >ە>w>ת>i>B>Z>I>:>~v>y5>h&>m>|66>>~>>r]>uy>n>mc>x><>I>>>^>;E> >>B>>>!>>>Fn>k>mf>~>>z>XY>r>L`P>!U>->B>bL>l>t%>O#R>,>>y>0ft>P>v>5>>~#>t>hB>rn>X>+>@z>>'>>>s]L>y>wEW>>Zf>;/B>8_> > D>= "= =V<>== ='=Ȯ=f6=X=ߦ#===}=z=^=+=tK=Q=*f=:Z=q={+8=/=-ׇ=}==E == I=K>?w?RA??h_?7V>'F>G?r?$"_?.C?%ϑ?$?3F?JH?J?5i%?>>>s>??? ??F>{>> >g>>IS>x>P>QN>>2>>> >>>I>y>Y>6>y/> i>d>)>>d>>ϱD>_f>ȇ.>K>)>>A>>(#>qL>>8>Q>J>|>֞>\>h>>]> >>>>>Z >_6(>>\>VJ>T>>xq>>*> >:>|>>p>{ >M>b$~>3H)>B>8>HX>g>p>y B>um">~2>>Ԩ>y;>om>a̾=:>&>=ّ>)T=g:===<=M=z=]n==0K==?t"=@=Xr=='== @+s^m|<^/dW!IpQmB~}N$ `I C  IGV80Kl[+]E R9(V ) }n%yA-m9(wj|P(SF((?@4 _Jb oxF0/wyzMp y hIRvj :KiS L"f(UosEE$c{0m]h7$gz>Zd2J]X+ :E: # Y6(  3 $ (_G?*P8xuTc j9@}asH]ߑk|c~=Y'`/1.("d)E~z {w jsn)|`ˆ̇ц$7>_2+($%%R cY)s_-b +6H@k@FPOH>-a9>7d7|t rEyE4~QZ{")%=n &@*/-J,Me7{qy2 't+/: @@>5.#RH0ͪ&ţg-XƈcU&ʌ% %0531,*{%F W(ٱY-IYmy. -z% ~V $Z? uoq- 6S@ T3&/3+:@k>>:6,"#- CK)A *2T|V * '.M474.+C'!Wv S)_‡VJӀvf۟YjF( hMxh#u `m zbF? O y[l3Þ^ d 2R?EB:0".ɟԹL!жjB5 t#=8%IV\fWM@/ӫ?ȥoɴ2V],xAO3S12( 67  o`7 K"!;/?P.`zn w}}Rui[NL==.#iP %X,5E;>>:;3 * T=&%7r ?%Y81dK6 !.HTdCʫЮb -EpE˛ɶŃC窹Yh{0Ŕ+F0 tXF# Z)/ 6N:ԑѷ7iV% _ &"*P04P666\4%1/,&Y` @ t  -%g-5b r;ndжdZ*M˴΃@2ceӸ9Q#rhnw֜بH>|+m5wVq\Gs< E%*-.^/*01123)1/ +&O 9B{$)s-f04~7:=@ABL@>(:4/ )o$n }?||iyz W!"V! y:' J0XK"} {Q"W&)+T,>,Q,/+')%!T! a9} 2  ] a \:BhՒқП,7+]()˰/\j,Ұ_ɊƦ9m ļȽEpt۴b7Krk"CT| z܏4'ؑ ]4E{ {&d,28=BDE?DBV=e731*#>c$r)(-D035{5543@0-*I'#CK) !cd?Z9 L@"Sw e  Yj1OCX@a{:b*];9} -BbXO< EvnF(՚+ѫ9-lۏIkGuj^qr ]03]:$.IKPz3]>7#t-Juid  |5 =|of\  { <.):: j,vE AysN_  , {"][T7[8clh[sBNsg.p~V 2f;HiKb in@F I}h<? 9}mv ~7 O4biOJaPK !]Uy $ Q;drh!^"l#&#$ $#"! kAG! tlLH] N +<-E=Om0 '6OLDKMuP+  bE\[}YGuJMb8Dic`< L#HD7YN;f <x87aa ^w) wb @ ; g y +!?$JNz$_%({+7}"iU `NCkLi)$^-.!HA-=B=NNS:C V 9 = wC 5 i V 6l^Q5 7:1wCT0=AIa;[T5 - = 6 $_QECR("EFPvp6]I6s6lOF ]D4vs %ymD KP2E'r2sSz0Z} 9"jk>d 9 ? S > X V 7 n + r   Y [ G 1 L,E :,z:3FD1&=LJ*$?}IwNx+k>({^q =jck;cVX `  y-v 1 m ! >  \ B 2 g  tk/"M\#%^t);fa 9_ m+k x * 2 2 E Y r 5 G f 2 1 * @ _   ? U 4Q k&PV4@#X/qikmOYlN]r,HOQbc|ASvV:s;p%7*1`Ih3 z:Lf\[vt-i$-7DO fV6~xCK7([Bm/roIM!["|^wCM%LtFe_;]&-_cX5-/d{VgJD[i= aZ7 u&Q" Gu%@p}V|u)Y1xE"B#{4(Y!+ ($d4XpqA4.j#'=@>h8f *nG#mX?IQ>dg&~ADt/oyxT& ;'^ P,:Px+q~VhavOx#)9f!j@<>C37O_LNT)GT_{~[(3U2<&7?  52zU-ZZ{/Hk*a[9jyNv,"3mgsbp H$-o~)WIshZTFy}7h.9 r\z) 8{xa ww9\'w9k39LKRF,?u5jbM0;7\Dan:;eBTCMYk? d}H!:#U kl PTQC0[Y gzRNRb+}` 42uc},P>:?k%;|h&<[= xO~P`( $1lbAm%qP}_9!3$m?{ Fxu2dN"zD.i }^L AUaOU`*H|naD/G0}'\ '  .  )YLaKjCOC:dA=T1% uzpp}&*bD|}sM;j`axgI[U[ t\ J(%V1<c=&-* x" `Zqj,U`*%,{|{uTT<&'z%_&&mSMfj{dD &<T4R'J^82g e]p[M$-aRt J6' )ah!FEUI+8N AR^9-v{rlL]V'Q=8l_p`[jEOS8H{go*MZV OGNLd-1c[q4 F*&F(~|`(-M}L0;F| ~w7-`XiUD(,/DTro2i[tW :c?ZXw 3+~5q)"j0Y)N0IBmMjuwGOwpB; V: C]T}os*6XNt2=kWtFa\{I8, g`_; Ctju t FNc^AS0LYr%IUq !Wmn|]p4CZ0Q^\ u84ViP{A_e;YX>hj+  X DT z L s W0Nz?TVX'Y3T&6LeC'Mf8Kw/Wn]V Oqi~`4-T @GGJ+K[fs*Mp 9? g*H3KPh`qv _4_i->dg~3E8}%R;W] OVc27etmGZZ@13,M,;yE ? " 1PVwt5X,,C F 0c HYqZ^nQ .1 uxn[b8(|ak#E#{W6O)|^ 1@={j.a <X -.( ZgVg;;r@bc-6I>h>V><m3Jb-s^.:g2uf\lZ163|Su5. *a"4t0do[2cw]}RHBxWuaw!CCT[wQ |\M=,I\(Z<3fnBs0i13K }7=&~?n7D5J/,_:[2giNV&k4:6; Yg=<@$|w,#u}e3Yn R&Tdxn#z]%}f5c7Lj6hjwHN)GN2u0=My2@[DaYwTDbW0Cs i:Pf*Fd)&v;'\hu06(v|A);w:" KpckTU:+40&;%*J{'TP.)@n~tr{T'9NbghdV@/%%#$%'/3233868@KSZobnyquist-3.05/lib/piano/rls22050.pcm0000644000175000000620000006647410144436365015760 0ustar stevestaff}yqfcZYWZROHLR]\VWQQSLH?<9<>AHID>357:8,  %231-06HQZ_ahpgnVPLQVUQC5.AbypXP?/ %5ISNA1/6BED;<<.2AYvpOJHPXYbnvx_Cl@.<\rlI*/0MX2c\]fB52?_W"/iE'*m |VOn^>bm (P[E1p) =*owl953D&fti]^j)=t[:2emX<! Ie[pUn/ G8Ovr$_bHI! A )  LBoR)Z6y0QgWW*Ja@eC/YfUX9_ #"JS + c|m(z;A ,nf;Y+u7j5{T*V G" }AZv))A)X4H>M4 L fsMw2{cu tpvF/*P|vzcKMkn { R Q  h LGMA4wrkG:K$|l~pQfK J6m} $ &iY'v)VphvExC*YcvO/oy]eGm 7(cxp@wYm `u \1@MO\4^'&:D@ & j eVM8)   5 " # t   @ -oXG= 'IMV:,8[) @ztS\ T h^?-5 W?Bkz~[oEJZߏFizXc7|C?G: }Y!P'e,Z/1u10.+(%_"g(W H`|MPq #u|| l eB`vzOi#]{h`xE‡ǹ̉ϬшӶ{b#E+7>X>g9X2-+)(&$$A%&%K 9 `4Wި&=xb=*1dlsh S$S+1v6H;-@8DGGEB&?> <9f3')6(@ I`GHܝ8qͺɩw̵ҐfɞH6ȉ1V4 )84 E*_ m#$).27s;>h?@BFLNPQOKGD">7H-e#=i? ?>]35yq^]3b{fqA pD0tPK2  .RZ  w"&)(]% >o4 #&9({*1+-K.,'SdC7n,yB^js}4 ) ~!'r*+,/4:>@A*@@S>;d53,#RDR؋-ͭʫKh++ƋZΆe+TJ$ʏ' k >%+04R5631.c,+*y(l% "B aAUW6#Oٵٚ\/Rߏ%HzZ Tn }%B)z I! h v(Cx)4B|# DZ f #6W@ x 8 tov*= {8`nP'y@l@ >><[:962,'"&5 ?AO(C/ / )4wW|jW 5 i&U $(+].L1+4677a41.,+C)'$!DH[Lr V&X*ό^űŠ$|XK̍ӄu.X,j۞acI"a~ -Rf(Icݘh( p `SSm 0| c`EC-5NBaF O { -}lV֡n6HܾzÞWeX _| `B )2V9?CEEB?):6M0*E"< B3fܰ=ɤyս.MܱIвijI#BK5W u#F.8!AXIQVZ\d[BWS*MG]@8/$ (OӧSWV>>,ȤͥmŮ//є\[ W,v7AIO3RWS;R.OKGRBy=y8b3V.~*F'$##$$& 'H(* +,-v,*o&" -7A,!Vr AE!#$$c"jHn:dn!M'A-4< DLM$U]chjyk{kcig,c]XSN~IwD>>940+y'#D9FTv97="I&+05789p:B;.;;C9Y682f.`*)% ^ F]xIV 4ɹ׶5=u"4)\c+CbNɿc5RuN#G8?7;%PP8ż _Rpn~Ø̳.րܥoz4a $>n>{7m eo4ozj5/qMSp+--:Vb?ߘ׺#P0}㦟n :ªpHtع2۾• ׎Z)% v#'+.111/,)'%"-i 18L2-($z ;> I nfdd4b N!<(V/7?GP2Xx`|gns_wz}[W}Rzup%ib[KSLD==6.(#lT} "g%Z(,1 5A8;=>?@><:<63 /*% mS r;(&7y%r-9;%9Y:-EaL: 5/ z!^!*Iy|g׭W»avC 񫳪Q0?GɫCͬ1mi"gj ] )PHڄo}ΙIV˗ɸł:E᪴WNg*$4œ-=(-HDu`p@"k9+22g N _r'X JC$ D[]P)->y 5S9֜Ԕѷ7Ϧ΁WGm ϩ~R$ _(& "&*R-024O5T66666[5f4#21./G,)&\"af n @ K q4 3 ].!9%j)-159?AWCEG_HJKKLMLKJ&GD#?;<6A1%,'Z#{i V#'+/3#6H8:8:63\/,)u&m# )O  H?s,CBܽ8ձ1˳n=m˾3Ĺ@Aγ`E'9.rϫ7¬kQbnѵ%cU5%jDM˷G΃\@D1Úemʤceӷ_7HK$qr~ +en#xH֟mة1 JL@{'-r5zs?NW6 5sA&٨Ҫs\ɛGDžqBF;ҺۜqC E}"%(s*,--.a./*/0011k12:233(210/-3+(&Q# T;t8HBn{""$'5)x+y-j/80246798:<4=>@ AABHBJA@?>+E5|L: |c {~h V!1!":"R"E!! v9)' H 39(C[7M#~t {N "W$\&')*]+Q+,?,N,T,J,/++(*<)'%#!T#{W ^ 4=}{3 0  K [ : a   `m;iC=e"פՎҕяР+Ϊ9ʹ&̹[.)/+˰c/+Zi++Aԟԗ~ҳѫb:ɋƧf84qgĹam˄̙ͭImu ۯd݀ިf>6=NXrmH"om@Tz5y܍@1to'#ؘن hG-~bD_I2NWE Py{C   Hu#&c),/258;;=@#BCDE EFAsk%]S}yd d "  K y\Kl$3P$t9GdU*Cc ;8^ 8k( Z6>{  q.tQyF$]dVR|*;.6 f ]Bx߹ݞiVBC)՝M-CѮQ8j'նi^ۑIj3H2D!-ti2n^q#v&yU\c.{1b=# .!IIPt x45X]<:,v?{*gKIzS|qmdHr$^M J  ?_ xk=  { v7,(;@}9?} | iC+swIEe A?qrAfPN_o ^ (xH[ & %ZH[BR>7NX}2_bm iZ&u@Pqi++szx'W4k\9;I`jxLB[^Qi n~CD:H}/j, |:> c9k?Iv b|k4  O0i*iLPbVmkO Kg3A_R--"PK"  (uB3AKQ+k6Y/   L '{:JEHBDnI Nlq~Q-a/  $`BP]ZWr}o\CIePxzI0$P`I66G\;\#;fO;fxi6A1gQ"aTFM P?]ruG{K(n+@4"`Y ub C 5 j u F)M;$3KlIMS y+ E]'8,z(~]1#,s;w#IhSf3F'C x_iQO6@Rn~nJ*&$/n.Z#daio/"-2! NA/m<6E;>KO7J1R8Cx s X M 6 p  @ w P|\lF ~  Y 1  z  f \ R ? t 5mI]T..j2!I6v:#2Sx ?yR+@:9CLF"dr @9"Y0U8g ) a  = K 3 2 xFq*Hl`mR*I*CT+e "E F"IRwsiu :Y>[zI4Z Ns3qlFQ ,GfCl z.],)D3-5w 3 .M j)"Di (<++|6|; 5LB r@\1&&{@0IbJ**$ Ar}^K'|vtNyJ.lE=A' Mz`s0:ffgO<3Gt bf<xf"TS`wwrS1ZQY=(9|csf;$o [r/*zp5I:hk8/RNh/8@JV=;Twh\Td[#i>wq0FkC`^Ta4Xq(r"pZ Vu?Dm8eWTkS a + ] 0 %6Fu3w8(  s 5 k " " e u ?   5 _ ^ ; 2 / h h :   p(Gg8eq/  mP[C#]y(Zq&o7;fd?t]4`` G+ q.ZlmB ={tx  @  , 1 2 6 / 5 E t  Y t t P 1 1 H u s g v 3 n g ,  * X { C \  \ = J U D 4hV4 n '8rSJUKzt5IA dq HYr1ppmFm6jQPXZCnl 'S ^ibw0s)I'O$O`a|d{|=?:VXqiXrg  =mrM;HniC&34  >)32wau~I! eR0 }}O<frH&;0}mfV=$g'Lv'o5U sW0s$qM ":u2zVVDGRS;c;&&7.av TEVspA]."~;brbC,)}I7$ GxOH^c^][9t^n^'*T_Zgr\ Y2@+-)- 2gp|`X=eJMoGZ\Uk89;hRKaw']5w$Ov%(  #K j! N Gs@(%>`nuZ6= y #~~ uZ%zVG4 yXE6"n< >(U}9<$@]H)" *i*%eG2U+n+p@E/.e0k8&%&1A>@=?Kj5yd/GkEj#k@pYK=-YB` O@bcFh8$!?.FYq0pEpxn{4WJ& {= %@Z7Nm-y:tMxz1Ko}\Xd@i0`|xv Ng{%0* ;\dQkJ?D<?t<B "1, %8GJYU$KPQISh)* MDtVO_n~C~5_(|kQ*9IRK0)?_$])6D?) 3vp1z[Vs+PV[[_{_2iCm5j(d$[<6@<"sRHB:2-9AIG:!  -@Kk}\MQw-"s)3= iQeju,eroz J# 1IqW*ISUGOpnlbUWVQ@7l|}N;agL/'7hJ Eu|Y-wI+V=x:wq f4?yav#9N]i'Nx 4kiM3-6LI0MSaE 1BBq076 lI_XN668<*)92\r#EYcn?l;H<vhPA"|RCEKGR[cn\? 4dv=G9",87 lS]Mlokpx c;.QOSBH0E\GW}Ffv~aRHSPPSdp* L~H`) 45!g2Istdaz\+0~\RM;$W"Z<X?Ik&9|{g9p%P;*^; {LPo|6m O \jr% !'2OnrbG=To~%inXLf}}^=:e7f(Ep=> "?[}= Hjwxwx1Se\Ja  #L{yB l+1 }fk Qzj`gM)BQRVcz7KYUTcp=KV| 5nk R_UA]1LE;0F&h\ d  &   3 +    ' * X&)Jd_CNdE6EjUAPlM+[??9(a$=j?Dj]D- y' Hr{vkkqM# $LdMCz~|{paO<8Nk~:bxucaveVHE]&V3Zn 1y]CL=' "9W-H<)c9\(/ -c "C|!UZ 80j_{WpK @hZ)3\adE+ "2-{zz|~zvaQSVL@'(' *okx}$j^S'@p&ro|rUCQeuheip{tfT?.*3=JQO5 'Rr'8JYYZ6s5hI  f3! b2q^VsyM 8.b*Q  {RU n|i{M1_iV7*! Vq=:n\^hnq`<[mTEFPTVA8;F^yhald$P]XUWeOwJNNMKV`0A/(^xW3%u0|;E4+|$gD:(~~^(Ckd& ,*K}zxR,2:;." $Cd~!X2w9c/^^?1WnfWYUBJ$M)1Z*opCkS\rxoV37e[XrV  )>..b 1>OXr CSb|p6]-\}6vxt}+]!$Ao}UPk3V@)UK31@I7 w@r=nLidtuVIFO?vqyYB1?Y} 6VT:A{}\E;GVX9iw%C.:%-M_V;xM7HR0s^Km4Crw7qz_S?8"6f|^F=N\L*Afi/Z6 Wo3nnC]YK&PhTTeubD@sjiyc<6=GSaq,0xw+6fAwP!}6l8t9 '*%7](\Ky?2@VlYx0EXa8\k{M 9t(u 5eec]u=|wK?m8pkrPe>isB ,Ls]([} >W31:Jm X2r$FI+Tt Tf#|?HWQkk{ Zp23fw%AC!V(0 ')Q^.Y3!8sI@7E7WN3m}U|<?^Vb9WJU`=qg~f|,9( @   W wR aPCT } J { t .,W]p.M{-p?h}TUlXn$%U/DV'#7MKNeoA&[Nc6^ MrT-0V6 @r,[M=T* Pq]4kk?\4 e,4O?_U 5->FE`![K,I1ZMV9et=)7OVp(; Bpr  c(*J~ K&3zyWJ[Ohc2C]rv/L >  b8i_h+%}@-b{f=?y4 *Gw5)|%WJ:Q.Th_ M/]N^)0e/H6iUx|o1GZAZ;62u.).JrE4uq;OwxA $ : Y %  1PgR^'u-Br3WZ,y] ,/ B"~W`E+/gb8G7^V$q_dM<*o(Oz V-@4(] u!@R3y<`DmxZ*i;264Ba%V6%+@| N_-(j*CRO(myY 6PP<.;|^G8CBl|f=s2}g6+Ma>:# eti=]%dwde2/z6M>sm AK @Q9=??"bj7 Lad/Gv aa&3&8Xh^.,t.[i [oaTQ/v69{/Q_ 3?J?L7zP5 bI]`T.s  $f'"e#wk3x*cYr1_%3GcuzL^4{gP.EyD utUIAqWbV,w"=C-)DQUV[azzNk {D "fAo8#9FD;4@I@0+_0y <-XT2ijQT (Kl|H1'6h7>_ 6*\- i=v@ 8Xk?#Lt+X+#ku |,pR~IhV7.[r6 9PD(h~S|dc}n<&~Z"chv7eXT*a6|hRDg7 l6fswI`NA+.IO5xZ+V=@L_x.~@vL[OFG]\!a t",sXSQ G>`nX.j5v?Cs d?kqNOe*=EOe*3(w[:f'd[ \izT27q7}](Ywf>o)n;xR:(#/Mh&o8bjTS\TH=-*.612,"Y9.##!-6L`z%>VjjP<.&)&!A\pw~{rnty{kT; '-:HMZccghgfd`UHC8,($'!#"(#$&&+)042142604786669=@ENKTT[dolynyquist-3.05/lib/piano/rls32000.pcm0000644000175000000620000011721210144436365015737 0ustar stevestaff|~~{ynjee[[YVY[SRNHJKUX`\ZUYPOSRNKKBB;<:;=B=IHIGB;507798:+'  $3035+/.28HLTZ^a`fnmkhnYNRKLRTVVNJ;2/1D_o~r\TND9,!  $*<CPSNF<.0/8@BFF@6?::0-:@SfxgRJIIKTWYYchwt|j]B,uY7/0CXlslZ5#+.03Oy6b$>dU)VwrUD26/:Mfxn="$EuxG.# M| !mYPSl!lU?%|:&sm*7Q]TD4( 7At#' 3optvs]-r>1nB)]nrm^b^bs-p5cunW?) DNO"Ynl\G9!FF>~%iovn%QY] \BMHP$KxoTxN<  = / )  l t ;6O1YCZ]0QJd|XrxN*X&~nuA5 1\uMVAl#e]>N= ;IOdv"IE^z \ ]j*~a"O)mS$LINm0 r~<Q@x h00@|@9E_U"c35C'YGsT'5W:E(2GcEv(V~'atpSx=AZ'AeX)Y#>}\'zjta =)3 q9$j'xBhFY=TK ! / | p  r DALO;TH89$E[esX /,)m VHE"O<3g4wW,m`QE -* Pns ( >qF(  1}fU,S Mj#Xi7*!b=ng$(.CT RJ2w>5dZTh@DPvi\c $JS8HA)}SgvSW_ CT&XB2* j  1 / !  B  E |   H LBM^9>sj"9Pg+T2Ehz8MI@:Eo ]?yn4  t X * %  A=@U%C o?*FqA^|3ߠ= =+PE+I r!Q%)p,/0111@0T.-)+(&$T"U nN 16 3v!b 'XUC h 48k K  FjX{5mAa wUop@LKrƆÙPؿJ#jk]YҝԚ܉{&ia \ *w3X:A>G?=9 4g0<-6+i*j)('%$$$%&&% !N & AZܚrNr K,;1x'h{ 6 Tmd!o'+036:#=A DF4G=<;x84.' WbE9R -VGJ:|Z[a%Jٮ0ab_WP/eP)8aГ9ȵ-.pȋ6 Kɾ8@oņyМqMOQ|MK4 L\3c"%)r,/269;=?/?@qAmCaF\JMP[QQNOMJSGEA>82<+$/ RBs<:&L C xuJlYuzPCj"-+d {@ (x/tp Lw S "&w}H@i! qYQ RT!)$'V()'%"`mwq,~!p#@%&(b)*+,-. -I*&hW1s0V!zly(Lq7> Xzm: "fD\"4&>)*+,1-9/-2:59=(?@A,A@@{?><#83-'l!w#u+ j()%ڧכgPͷnӶӬ|֙)X![T„儵2["}wJ̷ͩܰ vZpەN I T !%)-z0355)4/20.-T,Y+*)(w&L# = d|f_}:܅ڏtFْٿٚ@د ׇ&וئr=YGe9y Q L sV_*NpU ,H&D' P (It?s2pc;G:l.  GV | f :c&A h  70>72}g Z g$<4>e?G`4q;='|' `rFcs#'+-/02?36V93@'@?>=@<;!:@9704Y0,(% ! pJ MS5 L55'?"}.Rovi  U@l t#B&(*-.0246777F531K/?-,f+l*q)A'%#! 8sE?yj64 $$P#'ۑ4%͙Ƶ@Eh«̼m֍ۡ.H0;qu)0-#"AZMܽۆ ޓhRDaU dbZ6 NaS ( !D\1p I zIWeo?'ZAIKC 6Rsj t )EazG~XmӸN:ʌ>MĪ6gnٽ€áīƃKrx1CP6$*06 :>B#DfEEDB@Y=:730+&| 1Bb  65cۚ7ğ ˵װfIL3ηL(Ǡy~ݛ,$l \#+*2E9?sEfJPTtXZ\%\P[IY8VTRO JFA<60W)! QNwp*p0>פݥI*:̴$pƿΖK?B(00Q8>EJ6N,PRS;RQOMfJGjD@=>96<2/l,P)'f%$###$$%P&!&'()*+,-_-b,+_)]&#~I`B =2R+TP `"6 v&r !#h$z$$#! q<fj["c&*/~4;9D>DrJPV\'`dgijknkk$j hIeb_f[XTQMJ$FB?C;841o.K+,( %8" XnqiPZ ]]!]#''*.b14678939:D:;;;:864F1.+(%"?u} $rg )hx1٬ be(>~÷@ !5()M^v1KM8MlS|r(pjp *l)!$'%&<&>%$$"! ?C*m Da%1 e=e>}ޖܮU#.և բuՅkښiU$Yg((Ff+%ܿRH߽[!B|(~ W9""$%&'E'''''''''4&&%s% $$% %R%c%O%$##k""k"!!!n!M!" h 6ei K !",#$_&@(+/w3I75;>BlEIL/OQSUVVVUVSqPMJoFB>:l6t2/+(%{"s+ g ; sNX44 ,  b# '-2_7==BHNSTY_>diGmqktwy{}~~|zwtVplEgb]XgS(MHC>9|4/+%'# &NG A!#%(9*-036p8:<=>?.?=>=e@Day I l'`t@ޗTN؀biaϚ7g͝3p+,}ͅ[rhX|I[v ; IL2< #&(+%-v/1U2345f56Y66666n55433I2B1'/.[,*}(=%#M SuL6 K { ' D 6p  >   R 9;T !$'*-Y02358&:fP@AC!DEG,HDI1JJKZLLLM LLKJHFDA>;e840-*&#!C#pn "%^(*-0;2478:N;ay|qT0lK\d uG$Sz. !#&+(}*-0*258F:=4?jAgCޯfMxK+qf`&=O,t M[P67<GV'K߲MҪвRʋfypkȡ_4LѭG@~E PQ #`%')/*+,t-!-..q../B//05001$1l112I2233,3 221B0S/%-,s*)a'%$#"" &smt0nz(AQ!#j%+&(|)+V,-/70i1245=6O7i8{9:;<=>m?O@(@ArAB9BXB@AAj@?>=ό? ҚT^ԭԹԃ,KҺCV=˝hH9BXłĥ4¨=)xhĝG lj16əVʟh1̋Dͥ|FϥZл2Ѹ\ ԏO nضgڻPM{>ޯ)߹Sg#YgR 6gpR3n\[!DXZRUlڦلػr9$o٭ڵZfZ iwUeXH`WCBxI! Pt Ah>h%  A~Ez*!#&>(*,/1#3/5%78:<>c?A\BCD* p 5   0 o kC&vT",I5\GcaP2e'/=$&Gd(Z E& 8kfl m = # s7yw#l8y!H hRFO *Jhivm$8 f%_%.ߢ:gܒR٢(OoՅԙiљX7AcѻCLٴ:n`B7%Ii3667K5dm[ +Qex5Hp9@42^jd/w 0 _ lHEgy^.j8On    ~Ds[6 {spkh[D R8s`JZ~\ " @ [ #Lvkv% Y $ p # xx[ z2l\\3UI 4 } 3 ]1b5s HqxRDL8CbbK{2>b>  w +ps=p ~"^w Y <  "f{kSB4;E`0l{JOvxp02ZJ|/oF~Nh`Vo`*:7 p0)xy|6fiH6;BM^;*|< m=ZJ*> 1gtIE}GVCd.{Bc YGW_  _ 0bHcAM98}D^ W ^~[~w}@v$P(X3YhY;#X])F$P)gT]L np1y9yE{^N! 0 l3ua>Y  Z z 0nE#=vz/J}BC[MV b !\!"#"p""#(#d####$$$$####@"""4!!f  )?.W$a*71/6G f olxrf$:vPY2h + = P }   qJ<-y{Y28:CMPJ'mF(l.\n% o  T  1 F 2Jn26][z4R(S&W#?yAzV+f SOqE'  #N+AV]^S\f{siVG?S^nNy0cC5#k)_:eOG71>BXg.e&X$G=oPZ fR48g *Yo8{^.#=]xG #Mz#\R"o(:xtOP 7`52Bj07=GMOLHCB9>Kd?Sf1}3\&8ug|m]\n {hr}qK+1 n !w!">""#H##$S$$$$$$Q$###D""""G"!!!D 87[MM~KK./w bIa#zBYWr  n  e 3*!t"W KbG W6 5Yw'Iv4tI^1gBvFetwkIy3?o g0JqWu)oP l U 5  b3x4@f>mN}I!G6BHso/0aE {  [  7 @ n 1u#sHgp bVhVq2h)I]xC[i+\3Bw J ?#X F~Hh&}!lI}5[D~yU0C{8I`UiMS"zf[n;y4d5:>S^t|qUA*`g "D]XNvTt3sa^ijMMfbOm?97&fp),7@D5 )Hvf  l  @ w  ]  2 W  G h W*Mr~U#aL ~ ' i A ,  6 y _ [ Y J <  z Q %{U6e1oU6% <oD*#nB"|?T1"+;Pn!t+Il9`&7B<8:EDRB6odn+E9% *{LIU@b G  e  $ > I I 3 F MLm> o:|_ed2e3J<mA) ;a~b<EP(tG( ^4hr}khq~7If3I^r%WQ q?'c<o:vwby(IT>f*3 \J|"sqd;4g=+8.\uO/ilRz!zQ: %Oiz|np-n/qNN ,K@P^A$2g Qxry5y!`@x@0 nm/,+bE+j#_ ]2 $7;/%!1Y^>fltb<  h  w 2 4 g Z u K )  V  p _ I 8  x U 9  6 n     " = X p  c X L 7  k M A A 7 ( UP%Mx@!  ;Mn| $8;*F\e<!%6JIA)uS/V8'&&fB/7I__F!>+(9Y{}hWL1  |wwr]$6`;3bM:?B5 9[}5ec2&U{hbjgXG=39Kh /\d7Dj_SJ=ZRXfxvzq_F1 >R2dF6-_ral:g 3b@oI~{U!y}]42;^#1A^5/5VwI];Yk{hig6= !AT~|xkbYS]n!dHza'~+$.W4ZwKx^!l 8 Y - O $  G j k E   / @ ` i K < 2 + 6 ] z V 4  @ %Oha>ov<'&a%zLmVH2Ta n/Yg ,?S'x[.9xj/Mmc:fO{$r3Tbqiu3Fo>Q!X2?(is:FPx  ) 3 0 4 6 0 1 2 < J j  A i q { i M 8 . 3 D X | h i p  E p  f 9 !  & : f r H  _ #    c D @ J R V B G {_ZE%h%+"x5[mTMKWT46K,GO)LZ U)i=Z,znoqhHX1 pSSMR^VI5 rgq*Hi-X7hiPl0cf31Lq8Pa`cxJpy~y'C>:=S{@htgdWhW;   7Owv[G8DRpyA _l;&+87#?N.,.:. tj_xyR2   ueXB)w=bL@&GOxTRV`fibXRSg}xtpvy{=[jcU3*B@7 .@H8! ,>KN0 .Uki]QG33Lfg`G0 yE,R0wH$ 9E`oe1 '.AYujP%W`kZ(0^|;V{&>}U{hctJ$sP!t%=m,j'aGaq~ ,CTpoN85PpiA$4q/..DjN 'Ai$Zw0k4@`w"{tgZ?'-IRA K_M.w? +K]yaA%jj_J9'{gecozz{fS%Hl?G`dM+nP8! b`(zphcYH1Cr &AZx4f3k6`kAl;bWAm!#<_[L8q}^IGFORVC0[D,$$08- J xl"\BJUkumS"r]> Xo?}AP2p]E2)9]B;,^/qVFH\sh_`]_S@m\f~k8 !6ScZ[ggz}pM(b$9=:!$1(*.Cfpty\Y`N{fTFMa*LW`YX\u:{-cRQL)M{'O^f2Z{ :l -Jg', !\. {H E%?dlB2$'/L^nnt|rXA% zI u%) x}na8w]LG7 {bJF=& Gt VH=Vx@>4%  "?U[K- #+$5f$,' xeJ>0 ~`C%xEkNd8L`$yM- W6)$#(&4BA=A<>@DVkD}xii /COqX:X'fH0 naSN@8.!lPATh h:3XbeZ8xV:%MR}6@O_l1]!<^v}qqo9why}kG <YcmPA-#/:czK&Nmv^=" eL/)oIA(tF"ot{\8!i4  u`hy #1@RXcl{#C\w  !Ekn\G33+8ELH:e2 G]`N2 /AAF)[1zMY 4sYl[TVE6!,6;6<,$'5=0-Xp~!3NVaco})Qo0>FG0~rhYJB* y]FBCHJJIW]ZjmbS<.Qnyx 3@IA-")48:'cTUd :cjqmlo|?u0|S(9Vz8]{Am@KC5%V{VMF]u#Ickx~i\REOQQRMVZhp6 -\k;|V0  !742 W2@^y{tjdap4d|}}9If[SNK;) `Dt\E/sPACQl"$V|~whL&{EsP=8'h;j:aGLbw}M9.tJKzZCzO+k^VC1%k0 5\t}}wymlkoui@%"#<[dZ1 u7y}~z~~}xpfZP=;:J`n0Gfrzj`biqlVUBIHe(Dt;Vgp %F!o0DLE5)'(+EXt3EE7,Xt;}  d< !,+5Yy " >f 6`?p5i+0#n^b~KkrbA"  0Ol{^B :[^edV9, #):(z{zy}~{vxh]QRUWLI<*%)'"L{]{q S |ja[Q4`5!X#vnowv_MBKWg}sjcgept~|vpbZG<3)26?IMTPD+'Lcw)5?QWZ]YF!k@l4`-}tK.y]=uj[T`xrO. $2;,wS. lC $tRQZ| {n{Eo 3vD2Vz2~&r #Em +8S`ipiS5!(W $7TzEZcPB3-,05=BJSm{1l$5AGOQVa\ZH4%)4U~ olvrV(}mkyO$(HffeM>++ e6a?! _"sg\\dimqmfL1P,shPK@HLUSYM>69>ETh~~ribfod>'J\[YTUV]rN|&g;RKQNJMKY_j3B;)/Qoy_E*6o+k(9BE5"(&d*  oVA=3}~Z8 |Nq(\. (2B }y~rU:)2;;<3)$  5L_w=^|H{ )?^C^cT:%#9Slnh\VYXOAP0&G5- 4r,[pO0zcUUesvzk[I*3Mty[U`uC   #7<4$ .K| &,;@LU]r'GSXezO*6W}<Xp$W~|tuwCb#*8[xqV1m>mL"{\F;*v2mF420@GF:oI$qS&u]I uddp|yfPJEGOK2~pqypUI866N\{ *FWYK4,Ozv_PA>@MUZR5x/whr|"% _5 *=2$*CS^\O:{b3Bv=\?NZXK3oBi7}a7lP4% c0|Y.sis (C\Z\M=O6yTWRWnqmYD>Huz8w~wiQ4:8@FPY`i~8}.V:x4v+g9&WzxX8~SgCg>(,((/Lc6^x$Wg@<'>L_ju ae5^#hT]z#EXkk|i<Od0E&/Spg.o?b3\8&D}t/Ux A^{)yTLy_Ix)_0|r: EM{M LnrZ9;.Hvx~]@.05AEe@"q-\8EK;!WszumD|b1"`)]K@d dKFFgTW 2q'mOU:k&0) yPPR%uW3dK/!%S&(H'y +z=vT'N!L5X%Z]tK$ceXU\\~`/l|4 )C2}crT[ # v'd-k_:z7zuoX._#Kq1>(?L@xs{>%)6V:^6=Ou;VD.|P0!9]?^&XW< sV^(im- }>q9r4O<;=M27Rn  g  Q"DzB.N&h 8`M>C~n,,{.T%+^&X7c{tY-bVOAS=lF['A*j%Kfz{}_+Rm+XJZ k-!Il]]aoz..4=hJ*&?vRL^<;n<|x%  \ . Q V / r  2MnW9kWj/ \5CVaK'g 3)U!Y')t XYlPp[N5) /S{)h7AH:y@lv"V U @_q|fO/f-x f@,-DdL+?>+",O_7h17 H1cCz|T+! j0^"uH#^'AAfqdVB3YYAhH31=AmC#R2Fjwp[y"c@gf?"At1|BM /e"_2>i%6?9B>6!Ms|>o AQ d: =Xz+_;,.3"1NZihQ2z>f56f'c7dumcVWM?% p;;Q@{{`D6(u^+R{Y$6t7b3n6=a#ajM DVu lQcp $Kd**9L[px{i:b=.wlXN-,wKAts*gX t;"+Qd$oX\cH)_1@D:% ":LKYQT^YessQ0H xI3 9o<~A{/_~_!zV9 fC`wr]%LkW"J j .Ndu?dO~Y~8rY5Kmgt*nvH0.8EDA>45=HDE& br] Ff. G|B&C`IAmhEI 1PsPi'|O v#5- Z%|cFrFp?;M{3hL) Z:g1b%N"[cH0"5[|tEq*SVBx)SHrFjZ 5Wi_K4&Ba|_6$?PM<.[{<l{k^fzlK/%c0X5oagk|6rI=I+N[vdQGEg9p0&( jmTzrwY&K;y}<trC6mwuZ7tO@>?K[cw 7n(Nn0N\VNFDHYz{Y/ j;\c'gWP`G}5b1BbhnX:iI#uF9Hk @q2XndNPSi%*>CCRXt %04(ucQ8y-E :sT Bz<qiS;l]9}']@ars[@&IqQ+cR:0&%(?>>n>R8<=>b+>===\> =E= F<;;VXY;y;۞:q:a.;=w>_?>>z>ZO=D=Ʒ7>PO>A==J=m==w=f\?>'> >ae=/=>>P>_=?==A=@?=m)=D<;;M;%;Zv:#:la;:>?>>٥>i=X1=Q'V>,>x==` ==(=btg= ?>>܅>ql'=< >,>w=?s===U=W>=X)`?>ǿ>b>y=M;S> x>^== =\=?=M=A?>><>cE= #<=;>F==t=;{=X7=BB=;<`';(;=,;: :*:i;5$>!}?>>>1==" =gL>.o=c == Y=R=7=t1< ;;:;:b::3{;3ů>(?>Z>">==4=i>k=O=g=t=Gu=,=fk?>U>겵>==g=2w=D=t=yY=a==!=Xv?>>}>|===Kk=1=Z/1=a=O="a='=KK<^d ;qFz;31;lrc:e: :;/r>L?>>D>5>">G=4= =?=HZ==+== X==?>s>U>>2><' =`:=%0=/@=+===/lh[?>e>>1>>1y+9=A=݀= =/==B<[\=!<:gC;L5;.r;W:o::ǯ;,y>J-?>W>>> >#->G<}z<i<<}`=4=m/*<ץA='<-߆;>6T;-};Q\::u:;*#>,2?>H><=>.>,|>^G=nj?>9>>|>6;l>t4=JM =T?>*H?P>/>?:>X=l=mn< u?>J?>>I>_=s=V;u;<'=`WI?> ?.>.>RV>Y_=|=ьr;p:q<==Q?>?M>>[>F=E=<'C;;<\<)_j<O;6:;.);1A:S:/:ʽ;#>|?>?>2>do>&>_>`?>?K>>m݆>>,>+պ< C?>õ?8>x>v>ƿ>%QL>A<'?>? >'>>xs>5`l>W[=8?<<;T9:^;&8{;6~;#?,:::~;;\> ?>? 1>>e>#>EY>m=&=?>w? ]>Q>H>$>U=(>{=?'=<3B;];a>;W8:8c;;;\::j;:k;>{?>v? Ur>˫>4>Q>e j>=W+=6<<2\< <Ĵ:r-:;?r;8:ܧ:@}:p;,>;?>b?j>Z> >G>t\>9=p1=M<;<{;<8 4?>M@?A>Lz>?#>0>H=)b=d?g?>7?>Փ>&?W>>ur=&=z=:<h?>"5>e? '>=>="= = A>=Mt<N}?> ?> >;?6>]&>j===1;=4a?>s?>?{>q?>l>p=}=`'=B'=1-<<_#;l);w8c;\\m;:;F: 4;`(>?>d?>k>;?>>=[4==Sz=Hq?>?(t>>?!2> >S`= =V=c=^y?>?X>&>,?&B>b>|6=~=д=t=uZ=Ʉ=+<1g;;p*?;:;H::;[>R?>?>Ɛ>?+>>e=K=====:i?>}?>>B?0>x>=QV=j=(=w=|=JE|?>dw?>A>y?5߼>?C===Jp==)!=YV?>J?>b>?:> ? 1>===N\=5L=i;l-?>0?'>C>ͷ??>a?n>x=l===@=xՆ< <L;;$:;M :ޙ;>TF?>?J>>ʡ?D>~?y> r> =Y=M>=L:=A? i>>j?IYx>Z?>yJ>np=9==WY=#<<;;,z:h;(:z;>%??>m?!%?P>)?N$T>O?>E> '=c=uO=cH=#<.z<';;0+:گ; #:#;O>!?>z?"?\>M?R4>;?!F>NF>1=Ćr=P=n=<<3 h;^;5:b}; (:Y;>G?>?#P?*>ه?W>?%>"1>I|=̢=A=zv= ;;;1-:肰; 7: ;>?>>?$?>&?\T?m?*>'>=Զr=[= = <(d?>l?%I?>ນ?`#??/?>-:E> =z>=3=1<>]?>O6?&?R>CV?eE? L?3h>2r/>%(=">|==V<?>1?(?>?j;? A?8\&>7>*=[>z=G=ć<&?>b?) "? >2?n@??<>0'=>o=H=_=<~(;b;\.; a;&:q;}>s?>J?*? Ws>?sT?h?AM>A>5*_=I>j9=j=8=dR<;Κ;d;Js;et:;_S>_?>Ӿ?+? >?w?H?E>Fܭ>:3J>Jq> k>=W=e= <1;A;m;o;:OD;J:>J~?>?,? >C?|L ?_?J>KT>?3>:i>&r=Jj=$=<$;`;v;ҡ;:;>>?F > ?,B?΢>i??P2>Cb> ,>,g==팦=<-;.;9;;N;4z;>*?z>?*? >Q??RZ?N>Q|.>E)> E>/;=="=S<;rO;@;!h;U:r; o>@?vڒ>?(ղ? G>r??j?O6>Ru>F> )>2=uk=$=#<;ޣ;;$]r; :;; .g>?r>s7?' ? i>c??D?Oۜ>S>H*>(:>5==d=[F='<;s";;' ;'2:ɩ; >]?o>o?%Sz? [>???Pw>T>IwL>>7b===+<;/;;+\;Y:; >'?kq>G?#`? V>4?? !_?Q M>V+>J!>>:ݛ=>R=09<;;;/;:sq;)4>Z?g>Z?"?X>`?? 2?QK>W>LV>0>==W>]=4z1?d>? ?c>?? W?R8>X>MV>w7>@=>d=8<8<)(; ;7/;tv:g;>?aMK>,? ?u>&??!H?Rl>X>N\>>CQ.=ǔ>g== |<6<{;;;2;:;%s>m?^+>??>A7??!u?S7>Y>ON>Y>F0=).> g=A]><<;);?4;::ZT>8o?['>?;?g>^R??!?St>Z|>P>>Hk=̷> ex=E?X>>u?j?M>}??"HH?Sڹ>[o>Q>E)>K=@> `=J<ҥ<U;?;H;::> W?Up>?z?>:??"?T9>\0J>S>h>N=q=>Z=N<<R;;Mr~;:U:>?R+>?Z_?1>??"(?T>\J>T ;>>P=F>S?=R<݌<d;Q;Rb;:Y:i>'P?P>H8?$?hB>~??#&?T>]->U >>S=Ġ>K=Wog<<;A;Wy~;:c:Y>O?M>E??> ??#jA?U2S>^:I>V_>>VEw=?>B=[<\<Ĉ;Z;\^;f::qj>?K,D>,?4>>5b??#t?UyS>^>V>v>Xa=۸>:R=`ѥ?H>j?>S?>]??#?U>_kd>W>ł>[=0>2|=e()z?F>o?>>J??$!?U>_>XǪ>X>^==>+=i<.<$;˝?;m^#;:4:>?D\x>W?8>>H??$Y?V-S>`|>Yq> ?>`=?>%=n=<(;\;s;s;WI:x:P> ?B=>I?~>#u>۸??$?V^>`R>Z>!{>cT=k>!=sV=<,)Y;F|;yA;:)6:#I>?@1>F?V>g>n??$K?V<>ap>[V4>"P>f3= >!=x-=68?>6>NU?s>~P>1???$x?V>a>\%>#>h\=># Z=}= Z8<3;M;;w::.>/?_? ̉>5>\??%?V`>bHF>\<>$>k= >%#=4= !<7X; c;(G;::f>V"?:rd>z? R>>ↆ??%ED?VG>b >]>%>n7J=v7>')==<;;~;;:J:>?8 >$? >J>ᰩ??%m?W >cW>^w`>&W>py=>)3=8=Y?6>̋? 2>>???%g?W!(>cZG>_4a>'x>s!=tL>+AY=;=rf?5@!>? a[>OA> ??%?W1F>c>_E>(b>vU=">-S7=P=G~é?3>Ax? |>">+#??%V?W<>c>`9>)KC>y=>/i=F=W|}?2>?&>`>R!??%?WD'>d4I>aSj>*1>{= >1 =&= zK?0>ׯ?&>O>w??&t?WG>dq>b>+7>~W=N>3=r+=$~x,?/W>.?RM>|>ܜl??&+?WE>d >b.>+)>>>5=>=(+v C?->?l>램>ۿj??&D?W?>dS>cR>,>>>7|=u=+<__<F;<;^:3: >t%?,M>?Z>ꇕ>??&ZE?W5>e>c>->7>7>:+T==/hra?;>t>J??&nr?W'D>e+ >d>. >Z>>pe#?)>ֱ?>c>??&?W>eK>e4q>/>r{>J>>==7*n ?(y>R?e>V>9L??&?V>ef>eϙ>0a>>>>@j=x=;l9?'Hi>?N>LV>Rp??&?V>e|Y>fh&>1A>i>!>C>==?Ik@V?&"c>`?>D>i??&H?V)>e>f6>2!x>> >E=Dv=D <~<0;R;) :ix: >i?%>?^>?>})??&?Vo>ex>g>3c>tN> j>G==HRh ?#r>i?><>Ԏe??&?Vwe>e>h#Y>3>}> 2>Je?=x=Lf?">&?>;>Ӝ??&}?VK>e>h>4->W>I\>L]=(#=Q9~e=?!>O?f><>ҧ??& ?V<>e>i?>5b>-->>OY=s=U҅c? >v>>?>ѯn??&˰?U >e@>i4>6\>N>>>Q==Z<|b? G>(4>>C>г??&h?U_>e}=>jT>7hF>r>8>Ty==_T\<aT?15>H>Y>It>ϳ??&4?Um,>eg>jl>8LM>>J>W=R?=d?"<`"&?YV>>>P'>ΰq??&?U*a>eL>kb>91>>ڝ>Yȝ=I=iG4^?>c>>W>ͨ??&?T>e,z>k>:i>w>q>\S=߳=nm<] ?Ĵ>.>Q>`:>̜??&?T>e>lj)>;>R1>>_K=Y=s\ݙ?>2>Ѝ>i;>ˋ??&?TE>d>l>;>\>x>b" ==yz<,[d?S> >>r>v8??&?S>d>mlX>]>c=>eQ==~L<ZV?>?>>|A>[~??&?S>dr>m>=>ѣ>c>g= ='<)<{+<FT;6j:;9>Z\?G>>->ׅ>;d??&?S4>d5>ni>>>>R>k=V==<̺<< ;95:$q;t>Y;h?k>>W >֏d>??&z?RA>c>n>?}>>!t>n == Xsr?p>wb>q>՘>??&gh?Rd}>c>oc(>@>>#r=>q>==#=a<<%q<;>*:ݎ;pM>Wt?P\>om>$>ԡ>ĸ??&R?Q1>cZ>oދ>Aj>>%N">tx==?W q?>n> >Ө>??&:h?Q~8>c>pY->B4>>>'4>wƒ==yx<Vin?W>sg>4 >ү>@n??& ?Qg>b>p%>C>,>)&:>{(=w=Uw?n>>x>ѵ>??&w?P>bF>qL>D>>+#x>~=v/=1< << ];I4:*; U>UN?>>>й>??%?O>a>qk>E>K0>-,>>L=<<3<$;L8:"W; CG>T?#v>>>ϼ>V??%,?Oj>al>r=>F:>>/C.>>X=K<.Th?>͞>a>ν>??%?N >`!>r>GD>>1f>v>=A<L<<-F;R:;dN>T ?Z>>>ͼ>??%|?N9$>`v$>s.>H2>Qf>3>>o=ЭS?=>%>>̹A> ??%S?M%>_>s>IQ>d>5<>> O=E<4<H<6;Ygy:K;>Su?>]O>u>˳U>??%(w?L>_a>t>K>P~>8)Z>g>D=fS??>>I>ʪ>"??$?L9>^W>tr>L9w>>:>>P=~S\?>>EB>ɞ>??$?K>^+:>u q>Mf3>—>>s=DR?>3`>>ȏ>??$?J>]Z>u>N>Xa>?>"> =<{<<ž@R?t^>g>&>|>TR??$_>?I>\a>uS>O>.>B>i>=Jj=q8<0R(?h>5>u>e>??$%:?I >\>vwn>Q>>D?>>{==S?gU>V>>J>??#?HA>[S>v >R_a>>G>->" ==-1S4?p&>Z>6>*>??#?GZ>Z >wk>St>8 >JU>>%== v<4Sj?>F]> b>>9??#b?Fi>Y>w>U l>m>MC>A1>)}=8k=d<}6 >Q=a}?>n>n===ӯ=0;Q;L<I;э:f9;3\??D>=(,>=`Fz%*? >>=G@=We==;p;Ǟ;;@:M9;(??E>D4>(=[<=w>eJ?>> H==n=w=D;,Y;; &;R:99;??Fyz>K)>4=˲:+=>Q,>z>=>Y==ǁ=g=;&;q;@;T:9r p;2??Ga'>R>jL=ڳ;=Ԧ>=>->)=5=}X=:=j=i;^;;;:͘9.t;??HE >X̍>'=*]>j >M=W$=oG=~7=_{>o>y<w=m>>e6> =ܫX=at=r2=]<; ;N;;1S: 8%:P??J>f)>P> 'f<=>>>=1=T(&=d=l>>0===t>5>==F=W/=0c<`;;K\;3;?:8:??K>sW>،>@h=N>=Y>>vp>|===9@=If=qyZ>9>Pt=4V> .=>.>fZ==+I=;н=a;<;;;V;a_:u9Yo:??MO>>'>`f=M>4=i>>Q=2==.X=Rv<9$;;|«;x0;Q:f9J8:g,??N>0>|>o=f$>h=! >hM><[= ={= g=D >}^>= 7>%^A<>Ld>(!=v=S==5T<<;(;Z;U];4R:z9ʎr::VF??O>2>N> =4>.4;g">1w>=\9>`>m=>6<< >ť=,=B3M<<5=,ۓ>>=E>>%>ˍI>=>G<=5 = ==,<<<{>; >g=\>Oj=w=_r=$E:ɷ;::U:057R'{??SI >n>-> =ůV>W{l==:}=Ety<*8>|>U= >_o=r/> >l=>gH$=ܧ;e<:<4J,<<6xP<;8::::GF:g:\b?9ʄ??UQ>Z>؝ > 3=>o=]> >œf=<>v> =Rgd<ݪ: ; ;e<x;:c^9:;:w:—2:xi:(??V>Z>ݜ>=5>~,l>=W=-]{;ɍ:k>>Q>Z> >,{='=t<@Q;j:JC;N:|89::wq:w:}:jZ??Wݕ>5>|>؊>>t>:={=G< ;Wd;r\8;):%u3:=::`:):l:??Xy(>D> >ު> |>f>I>.=՚<~<U;`;\T*;J:7:t&d::Lx:ϑ3:N9:??Y>EE>=>䰪>>:>XGt>*"E=g<\">>y>>![>fi>@Л>o=S4>>s>>>t>W:>=>'y>0>!b>>u5>ma>$a=2ƴ>f>>&PT>]>cP>>4e=G<a?>?>+>>;\>t>E6=\<Ҫ2<<>)?lo>/x>>>%>UZ =pc?< >]?>4b>+l>\>P>eN=1H>?'>8>X>A>);>u== ==@<_;;R:}:M:&?:>;??]?>Ć>:?? W:>=y >z >O>|>V==8= =]C<(<Á;:ր: :f:f;Ŋ??^n'>ƽ>P? >A>>2>G> =h=~f===ԅ<]<);Vv:=s::L,:E;ɰ??^a>>_K?eF>FV]>>0>.>=A=*=$*i=';<<;R;:;:n;#??__>j??k>J>>>Ծ,>7=?T=4=/,=38??Fk>NP>>>ޘ>=zt=?-'=: =?<<9 ;;l:<@$;r:Q;1W??`G,>R??[>S9 >v>>U> =ĕ=I=E1=L fT??N>Wi!>T>'/>G>T=͒"=S=O=X?=4??a#>s4?7?EV>[>'>>z/>>=oO=^M=Z=d\== >yP??>_>">?p>=-=h=ek=pl'=0x?? >c>ŭ>p?>ķ==r=p'=|oB=ô<< 5;h2:c;Ҿ; !;Rv??b[>q?yn?">g>`>B? >˰4=O=|o=zň=3= fc<5t< C;zW:;L; %;XQG??bX>c?d?%>k>>6o?9>Ҕ====(y=(<< )<;:;.;$;^??c>Oj? M#?'>os*>ͦ>$?>f>} ==j===/ڕ<԰<(k; :1b;; R;d??c|*>4? 2?)>sG>:+>S?&x>#>=W=<==7<<0;:w;;;jȰ??c@>? ?+">w>G>? >ΐ>z=={&==?? ?->z>B??!ޘ>fQ> =t~===G<;L? S?.g>~y>׶??&':>[>x=b^==(=Oh<6P? 0?0o>b>!E?Z?*c>]>S=J=2=z=W<P%?;?2>ٳ>܁??.H?_>=-=F=L=_ʳ< <\';u;*;.;#.;??ex>?Vx?4v>>? ~y?2?>ޕ= w=n=.=hVx?'?6@>^L>$?_?69?1>j=I===pW=} ??7L>>g??:2? f>#2g=P==ĭ=x*?œ?9>)>埵??>? >&ǣ==G=p=[=^@??;F >x>Ά?_?Bķ?ɍ>*O3=R==1=ߟ=E<\<υ;w8;@;2V;??f>s?Rm?<4> >?-?Fz?ĩ>-+==g==0{= ?O?>l>µ>??J`?<>15=@=B=۪=0=j?׈??>_ > h?o?NR?\>4=̛ =+=c==<<->;B!;L\;:v;Y??g>5??Ai5>>(K??R?>7?=VU=;==e0=<<6m;);PÂ;=C;P??ga>Z?R?Bz>>&? "?U?\>;*==I=q==&bE? k?D=>>?#6B?YwN?!->>a=~=U==l=,L<?+?Ei>>?%hU?]T?#>Ak=s=_=4r==3=2?vW?F> >?'f?` ?&>D=">=h==1=:w(<<_`;̩,;a%;H^;@0??h>?'?H/w>>Z?)?d5?)p>G==pg>e=Ts=Aq[< >?+Ψ?g?,!>J&=w=w>==Hw>RY?-?k'?.>M==|>y<=ژ=O9> ?/T?nK?1l>P=”=> Py==WBF?_?1?q?4x>Ss=eK>Cq> '==^/?3?3?u>?63>VB> >>:=ŋ=f<ԟ??5ۤ?x?9!@>Y>R>H5>=ʎz=ns~<<<;;R;[ ;rD??i??-?O>T\?e?7?{`?;>[f>>>:=Ϡ[=v#??9Z?~}?>>^`2>H> M>==~<ܴ?>?9??>F>_#>> >=*)=xY<5ي?f?9v???>^>-> q~>=ڽP=B;a;7h?w?bya?b'? ?L>'+?S?9&Q???/>^w> e$><>=Y=j<-@<<5X;R;a; ?u'?_?y?1?KT>z.?9?8???HT>^v> > >R=H=C<<`<;|;r;a֔;?rp?]W???I>J>3?8X???`>^t> >>==E<<[??HC>/=>wW?7n???y">^B> Z{>>$=k=5= e<??F6>>U?7???q>^ > >|>=1==A?x?EI>>?74???>]֪> >Q> f==p=0<*?s?C>>`>?6 ???>]> `3>)O>!=:==O<<\vx;e;by;"?f:?RcE>6C?vm?Bc>>y?6y???9>]`u>>R>#t===xQ<3??@>@>P?6???>]!>>>$ === ;b ;?a[?N_>X???h>>6?5??@ >\ >y'>[>%=|== ><$??>&2>.>?5l??@#:>\>0>>&#Y=g=7$=-??<>>W?5??@;>\U`>?>>'5W==t=J<ڇ<; ;K);c4;u?[?H>YS? ?;bQ>)>J?4??@TF>\ %>D>o>(J> G==ۆ?&r?:>>?4j??@l>[I>h>[T>)c>=2=C=5<;;d;4m?XD?E>>ݱ? [ ?8>0Z>?4|??@>[q>*>J>*>J===<;e};e;?V?C>? ?7M>>W?3L??@>[ >>=>+>= =5&= l<,;3,;ex;?TՏ?A~>? ?5>A>"?3p??@>Z̭>>4<>,>=== <%:;R;ek;Q?S2?@NY>b? ?4>2>?39??@N>Zv>>.>-g>f=== X=!>I? f?3DT>\>j?2/??@>Z>Ue>->/z> +?=="=L>6? 6?1>>o?2}??A>Y=>(>0>0QR> =ĺ=%=m< h; ;gp;~2?N?;>+'? y?0>>s?2-??A>Ya >y> 7>1#> 9=Ȗf=(qs=H< ;;h!;a??M)?:?>&J?f?/@>>O{?1X>0>!C>2$>.=̆=+@=p<@;);h>;D?KŰ?8l>'?6?->>.?1??AS>X>>"T>4>=Ћ=.=#<;Z;id;(V?Jm?7k=>/?(_?,>E]>?1@???An}>X1>>#jR>5P>=ԧ =1 N=(P<;;j; R?Ig?6 >==??+:u>>?0??A>W$>>$2>6p>=ب=4 =,:n<;;j;?G܋?4m>P??)O>{>֯?0@??AE>WW>nh>%o>7g>=!=7=0i?kS?(>V>.?0T??A2>V>^>&<>9L>=j=:6=4<5;T;lH;?Eu?2>? ?'*>\>?0??A݁>Vp>S>'>:>P=*==g=9m<+K;C;mI;?DQ?0ؾ>[?V?%>X>ߎ;?/??A9>U>M>)(k><S>=ꏝ=@=><͏;؍;mD;?C7.?/>??$l>{>xX?/j;??B^>U{> L>*`@>=2> *===C:=B<r;;nǠ;i?B&#?.e.> ?P?# 8>n>c;?/??B4>T>!Q?>+>>z>"oL===Gh==G<غ;9l;o;Nc?A`?-4 >2??!>A>N?.Tx0>"[X>,>@xy>$0=Q=Jr=L<ރ};r;p+;3?@?,>iV?X? <>>:r?.~g??Bq>S>#k=>./>A}>' ==Nw=Qݤ??t>>&Y?./C??B>SeZ>$(>/>C>)>=Rb=VD<;ܛ;ru;?> ?n?by>4*>(?-??BV>R>%T>0>E#>, V>*=Uݭ=\ m<;;s;?=X?(>&?!?>=>?-??BЎ>RB+>&>2@>F>.P>=YH=ayh<;<;tD;ʍ?<|?'">m??x>%>?-?\??B`>Q>'p>3>Hmr>133> f=]=g s<5;=;u;M?;?&y>ڷ?&?(>.>?,Z??C>Q >)>5 >J >3ߝ> r=a=l=+;׌;v; ?:ݍ?%k>_>~?|>->Լ?,??C4>Plh>*Q>6W>K,>62>Y*=e=r=;+;x);{?:A?$`6>Xw>?j>->Ӥ+?,J_??CW>Ol>+>8 >M@>9l>R=j)=xx= #3;qJ;yf;ah?9^?#YO>خ >?ly>/>Ҋ?+C??C{P>Ow>,l>9>Oyc>`l=n]y=~Ҟ= }; I;z;F?8?"V'>>5N?۫>>o?+N??C>Nk[>.(>;I>QX>?C>=r==z;;|x;,{?80?!V>c3>}[?D>_>R?+Nn??CĻ>M>/2><>SB>BM@>]=wg8==L;;}a;?7\? Za>—>?>5K>3?*??C>L>0Z>>>U9>Ek>w=|=/=9;zb;~͈;?6?ao>%>?C>>.?*??D>L:+>2K>@T>W>K>H>"m=x = =C;;";*?6,?k>Պ>u? V> >?*I~??D9=>Ksq>3">Ba>YPE>Ks>%==)= ix;;;?5'?x>>? >=>?)#??Da>J>5>>CM>[p>OL>)=u==$];K;8;?5v?h>^>5@?>>ʜ|?)q??D>I>6Ǯ>E>]>R6>-4=!=Y=);e;;-?>_>\=j1=#=<"=O,>u==I>_ T>=+=Z{?=(=Ŷ><|<=&S;:J[;!y;0S:N:?>M>J>m=m<ͷf<=(= J;>5V>=g<<=e==?n=>DK>> e=%<2z;OU=r}=)=5= =FX<}`Q>!F >8>)Z>$>h> ,<&{< <=U=d=[=<@<3?=l;:2:t;:˧r:u?>hv>(4>>/2;zn>+h>!>C9;9y<.<`ť=L=C=h/=j<<]=s5;b:2ٽ:D; :ɟe:V?>琓>/{>&>V:R<錏<==3=W#>=O<<]=JC;q:5N:/; :Ⱦ:Ӿ?>>2[>+>i;= j;=c2=#=F;l=$ i>5>0r>|{M<c=&:s=Ai==5x=\<<2<>;M:=M:J0;:@:?>>8]>5>3<=q=?7;y===$ڮ=7><4)>:>>>?kZ>?>< =olmm>B>Dc>>E>I1>?>ذ>H)>M*><=>K>Rd>=w=3n<< <*T>N>W`>$==v==:(:f:Ε:J:hR?>ޙA>R>\>ά=!|X==>T>`,>f=/V =Ǐ=' .>Wu>e5h>m===df=7=;~:J>Z֗>i>I=J!=P=G=;Ѳ<;;pF:;<3T>]>n;>_=XZA=2=W=Y4.>`>r>,=ef==g\=v5ڌ>c]>w>=s?=E=vm= K<<6;%m :D];t:?:-1:dܹ::ǥ:=?> >f#>{y?=G>0==r<Uw>h>Q?=>>+=d=~*>ks> s? kh=u> 9=*=c<<<;u;+94d;"g;:c:|:/'::?>/#>nA(>.(?+=e>==°=|עc>p >I?=t >;==tw=<.= < 4U;⭘;iɸ;P;:hk::U:~?>>s~>`L?=>]=/ ==Uu=W=7<<_;(;h ;:l1:M:͌:?>֕>vK>q?=D[>n=\n==+e=@J=MU<1<;%;;#:r:)::E?>>x>~?=>$k=u =z=8=#=c!՚>>{>6?!&=>(=x>=E =0=y3">}>E?$=%>-d=g> r =R===ԯ>o>2?'=X{>1=A>م=_H=J =m<~.A;>0>{?+P=ƀ>5=@>,=k=W=&<<<ë;.;U͉:AE:$:ֿL:D?>>^>n?.=̛>:#u=ط>j=xd=d<=hp>>\?1=ҫ>>==S>"=aZ=p)=<< <;֜;la:AH:4T:ڌ_:`?>>>Dd?5=ذ">BD=x>(6=[=}=ұ>&>'?8#=ިq>F9=J>.=S==;X^><>}?;6=>Jd=d>4=<==Ұ<)>>D?>;=ue>M=>:n=}==ѳ >>?A3=I>QG=!*>@1j=[=d=a<f>">;?D]=>UL>7>Eߍ=*c=,{=<'U >,>Ii?F=\>XB>L>Kx=== ۆ>2]> `?I)> >\d>>P="=g>МY>3>?LM>h>_1> >Vm=5==>k<a>0">?OA>^>c0>p>[=#=,> < ==7L<.0;D;?:!::?>+>(A>9?Q> %>fy>I>a$=@=2> =>=.<=AV<5;;::J:?>>>?T> h>i;>>f@=Ǯ<=@>='= ڮ=K~ <=K;T; o:-:-:?>> >?W>>lk>z>k]e= e=l>= 8:==Uϡ>>7]?Y>S>o>Z>pe?=XF=Ǫ> a=u=G=`%|j>ۏ>֬?[>>rw>F>uX7=ה=>%'=D==j[>>p?^a>7>uL>*>z6J==>)>=V=$(=uC?5> >?`>LC>x>!>~r==ֶ>.%=A=*e= '!>r|>?b>;>{d>$R>==ےm>3@== =0s[=kg>Fb>=?e9L>~>~>&>)x==[>7߁=%/=6O=& >>0?gf>! >Y>)>n=΍=>>>#?iM>#>>+>E==(>A=. g=Bu= <>< Ņ;YZ;I; Ve:W?>^>>6?k>&*>f>-]>l=r=>>E3=2vp=H 0=.<&0<;c8;L@;R:5?>>h>H?m>(> ,>0@>=,j=>I=6ۆ=N=gP<<~};mb ;,;Z:؆B?>#>%> ?o>+>3U>2>0>=>Ng=;<=S=,(<1<|;w;#9$;n:1?>>?>?qy>-'>Q>4_>*>7 =o>R=?=ZO=<<;Ky;(q;4:?>Z>E>R?sT_>/5>f>7 >0>{=>W& =C=` =<<$;8;-Ԥ;:౪?>>A>IJy?u!>2Q>r>9;>,^>>>[v3=HH=f=<*+<*^;|;3c;:?>&>> ?v >4>s>;_>V> m>>_h=L<=l4 =r=>>b(?x>7u>k>=x>> >R>c=P[=rR"=Z&>4>Ȳ?z6>9Z>Z>?c>ߛ>8>>h*=U/q=xv=<<:O;`;Eb;:S?>z>>?{I>;>>>A>>Sm> >lS5=Yt|=~=)<ϟ>jt>A?}U>=.>>C>w>e> ,>pq=]x=i=cB<>w>́?~>@- >H>Er>3>p> >t=ac= =ݬ<<y>g>͊1?>B7>}>G%>>M0>F)>xS=e=`=.>/>ͤ?>C^>>G>>u&>E=>z=h==<>#>?>D>]>H>Ij>>?q>}E=k܏=O_=#< >?>EF>y>Ipb> `>>5>8=n5==b̆>?>0?>F>>n>J0D>>ں>&!>m=q5=,=;0;Y?yZ>>>E?>H>ak>Jt>~>7>>=t== <\L>ǽ>y?>I6J>R`>K>4p>]>> =w=P> >>δ?>Jf>A>LfG> >)_>>T=z=>{~S%>`>C?>K9>.>M ->> ?o>X>m=}y='C>BL< />3P>7?>L >H>M>Cz>!S>B>=_=6> <Գ<l;%;!;: ;b?t_>ɗs> >π?>NO>>N>>"fv>z>5y==I> PP>>(?>O?0>>OGP>!>#w>RQ>=jD=>̨<&>n>"?>P{>>O=>::>$>&>==>< >>{?>Qj>'>Pv>>%>h>=~5=3><͓ӝ>W>؉?>R>>Qg>}>&>V>d&= I=>.<-$>v>;#?>TD>yC>R@>>'>>{=d=>>dh>Ѣ?>Ug>X>R >x>(q>]>=1=f<>[<~.>V>?>Va>5>S>S >)>%\>Ov=Ɇ=3>!<6<< ;;N;P?pM!>>KV>ҁ?>X+">M>T5>>*/>>~=d= M>%"-<<<;c;Qz;?o >$>DO>?>Y>>T=>>+\>c>"=Y=>(]<%d^>@>um?>Zذ> >U>e>,> o>G==>+=6y<<#` ;SU;W`I;?oa>ɧO>A(>8?>\5>>VP!>a>->!/>=O=n>.=c< <'q; ;Zif;g?o*>>E>~a?>]>jq>W>>>/ >!>= = >2]=<<,@w;!;];M7?o>b>Lv> ?>^><>>W>4>0]>">Q=B=$>5;=,<\<0Ժ;ƅ9;`;@'?n>>W>՝?>`i+> >Xl>`7>1%x>#e>4=c=">9N.= !5<<5;x;dH;@?n>W>f.>4?>aً>>Y!>>24n>$>==w><\= tXx>xs>?>cO:>>Y׾>|>3De>$>r=7=E>@|K= <@̄)>V>u#?>dp>o>Zd> >4U>%>`=&=҃>D+=:E< 0B>>?>fKf>7>[E>>5g>&F>CD=t(=#>G=< >>?>gU>i>[w> >6{>&>=G=*>K=,<δ>>ف?>i_y> >\>>7>'v>"=!=ܓ>On=<-ό&> e>j>>]r>4>8>(d>k=g= )>Sx=N<^3s#>2>Z?>l^>A>^/ >>9L>)> ==|>W=<ϥ<^$;y9;;1O?o>iA>^>.?>n.>>^>FV>:>)>'=(=-?>[=<Dn>>ܔ?>o >>_>|>;>*}>=Ѣ= >_="b<{ Ӄ>/>i?>q">q>`l>VG>=>+0 >=F=~>d5=%/h< Ԩ|>>E?>s>>'>a/e>>>? >+6>&=k=`>>h=( <\Q>5F>(?>t>|>a>e>?d>,M>=l=@>m=*#?r7>"y>t>?>v->>b>S>@>-Fk>Q==5[>q=-#xA>g>?>x>>:>cU>s|>A>->O=(x=>%>v6=0K>%>?>zrb>>dNl>>B>.(>=VJ>. >z=4.W>L>?>|U>>e>>D>/]>@u=>G>=7@f<#>]>!?>~CU>6$>e> >ET=>0J>=ѐ>mU>_i=:~<<<q;أ;M)?u>|w>>?>q>ّ>f>X>F>0&>j=>|>==e=<6*>J#>3b?>>z >g>>G>1y>m=y> >}I=A3=<-%<%e;;;Tn?w9>>>V?>%>z>hm>'>IF>2/>6=<> &>"=D=c[<<);;X *?xf>}> ;>聶?>1_>>iI>+R>J\<>2G>R=S>>}}>=H8= S@>qm>鶸?>C>H>j(> >KC>3>=ӂ>>=K-=U>݋>Z?>\ >ܔ>k >?>L>4U>=a>V>t==O#=k>N>=?>z>l>k>>NV>5>ò= >n>\=Sdd=<<;1!;;fC?}F>>>?>~>>lc>W<>Oh>5>ũ`=ϩ>j9>W>=WL=/<@>@>N?> >>m5>>Qq>6>Ǫ=d> >e =[N=*<r>>V?>>>nb>r>R>7D>ɶ=/>>=_jX=y<&|>>7?~>>>n> >S>7.->߿=>A>=bo=!Z<[?>>M|>>o=S=Q.=]=(==>D?>C>Lҟ>w >\=> =F=DN=?X=p=c>+>L*>>Ė==/<ل=r=O=>>"<=tK=,n;;d7$:]=s?>{>K>[g>=>=,*<=S=\rSM<˸=hot=%M):ŋ;Fk7g:s]=0?>>J>Ϗ>ǔ2> P=<->d+>J>|>E > >j=<ٚ=K=\<(>V<:M=QRd=F: |;c6J:=?>>Id>>ʃ%>=;LX"<=w<:>I:< =E*=:ĝ;s@7fi9=C?>S>IF>3>#><>;+rh<0=~;Nj<=:x=a:#M;f7R9Z=?>U>Hd!>^>cy>{e><M.s<.=/%R<:;YA7n*9L;="?>>G>(>'>$ >Z!?<ğ=#<72: ;M8dI8@=U?>}1>G1>/>5->)>)#+q >F>!>ј>/ Q>4<>;G7e>FS>E>C>4+>?<-<\m<<]=~Z>Eu> J>TR>9D>JS=Z3<<[<>=Z6PT>D>>լ>>V/>U =)i9; 9$9I=?>F>DVw>$I>y>C_>`_=?D= q; ;</=C<&ʬ=>C">C>R>Ha>kp=T=%< B;Ǭ =<N<ђ<"9JL:)9uK9=jL?>5*>C?>->٠>M[>u =j\=@ͬ<;g=pVr;V-Y>Be>*>>RN>#==[e<];!"=?;5<<^x:$v:9Y9f=:?>&%>B0><>/>W9>&==Rl=u==(:,z= j;/<[>A>X>ra>\>B=<==!a:Y:]}:fPp9b>9=$Y?>>A*>O>ޱ2>`S>Q= ==?y;>/>>@>>[>e9>S9=D=Y=\;K6:a;a;;m+:Я9:9I=&?>>@+ >h>#>js>G=`=2=y;;ڡ<)f:V#;Rw;:9tҼ:$91=ٱ?> f>?>>W>o]>.=cP=AB= J<>?4>[>>t>+=K=y=#z<"q=:::J;B9U:Ko9E=ٻ?>>>{>>r>x>z==ҋb= <>U=1;*;)8#r;/#9:`8Ǿ=w.?>>>D>>T>}|>r=ͥ=ur=>=C>>>>?>E=g=8-=X">=]>>$!>`W>`=I=ӓ=Ϻb<'=;<=;+;k% :,:9Nr=u?>><>~Ԥ>B >>U=L>=<=Z;y><~B>~#>\O>> >L:>J0=<+=3<g_><>}6E>r>6>Æ<>> =9<&q=x<{f<8< 1; ::b:C=ͫQ?>(>;>|k >>v[>.> p>[><=<*x<-<;;;:ȋo:H=t?>8>;> >{q>)>D>V> +>J>n<w><<`>:?>z|>>X>Ы>`>>+ 9 2>:ro>z)>>>>,>!c>?H<>j<_>:>yXy>>N>+>>&e>&L>9>xm>>{>W>f>+> #)=ٳ>'<=Z<;܁P;QC; :@`=?>>9O>w>>I>v>#=>0!>%]=R9>1?>8>w&<>,>->Z>'z>5>+= (>:<&=~x#>8>vp>><>錙>+>:4>1PJ= >C<=!8< <Ç;hQ;&G;n=ß?>*>8?>u>>u>탂>0 >?^=>6=vC>L<7=*<ѳ<~;n;/;0=¡?>2>7>u >zT> >m>4>D>U<=3:>7>t]}>e>6c>IP>8>HP>A=&>^C>7@ >s>L(>H>6><>MRZ>F<=-2>gU<=EM>6>s>/>U>>?>Qѹ>L.=3Yl>p1(<-=Ni=<$c;1;W;|I=}?>W6>6>rb>]>`?F>C>V=m>QKA=9u>>xF<Ώ=W+r=<,Q;Fu;b;#=^?>a>6R>q>|>f7?p>GH>Zw>VQ=?y><,=_=$<3;9;m;|=.?>m=>6>q>>h?6>K:>^>[@M=E><0=h{=?W<;Z;};x]; =[?>y/>5>pv>>g?Q>N>c >`=K->>5wa>o>i>a?l>R?>g'>db=Qp><4=y= \>52/>oJ>7j>X? %>V>k0>i/=WR>">4>n >A>K? ן>YC>o&>n~=](> >4>n +>r>:? >]>s>rO=b>Y)==N=2K'>4nu>m?D>&6?'>` >v>w=h>==l)=85>41*>mW?m> ?>cZ>z>{Ux=nf,>= ==>>3>ltb? >f?]T>g:>~8>=t>k=a=j=C<}o<PC;$S<5=`?>>3>k?]>j>>=yx>=A=d=Ir>3&>kd_?>=?x+>m>>=;=>~K=ق==O<< $A;=<,Z=z?>>3O>jS?>Åg?>p>[>=`5>=%= =UOC%L>3Z>j^?f4>Y?xV>t>*>Ο=>Q_=(=j=[;t< p=d?>8>2>i"?>*9?k>w>>=>"=#=L=`VL>2v>ic? R>?]>z>C >A=7> ='VR=&=fca5>2>h|?^#>ʿ?ƒ>} >ѻ>]4=0>=+'y==l<=<";o8<9=?>vj>2bx>hs?!>̄?(>w>V> =?>9K=.==q7< <'65;#<>28>gc?J>E? >i>ћ>\=v>K=2==w/P<<+;>2c>g?E>#?>m>B>=>N"=6y5=9=|P<<0n/;>1>g?!>Ѽ?!&>2>'>(=X>@=:3=2=h>15>f?>r??"nB>>>?=2>#===Ða=>1>fH?>$ ?#>>[]>J=p>=A[=/!=\<<>q<OC>1>e?`>?$ >/u>8>=>L>Ϲ=EB)=r=E#>1iB>e}[?>|$?&q>v>>>?=\>l=HZ=SS=<,6H>1M>e??>"o?'I+>L>o>=2>.=L==<͖-Q >13>dp?!>?(o9>m>G>"=>ף=P=U=JH<8lm>1>d_?^>c?)>%>jP>[_=>'^=S1=Z=c<؛l>1S>d?b>I?*T>R>>^=u>ܛ/=W>=6~=r<6<[e<"<2=cL?> >0>c?q>x>>=>%=Z=ߚ2=*t<<_<'a<E>0>cZ=? >(W?,>>>=0>SA=^Ir=v=j<>0>cG??>㷝?-y>>>7=>㗂=aJ=HK=VT>0>b?r>C ?.DŽ>>o>R=H>=e==钱=0>0>blE?d>ʦ?/>>j>b=3>u=h=ԧ=r<;=a>04>b"8?O>Nj?0>d>H>g(=_R>'=l=.==]>0D>a?g>W?1>>>`m=> =ow=?E=}|=<<}~>0N>a?.>Jn?2}>ϗ>>Ns=0>=r5=g=&=<]1>0R>aS?Y>¯?3Y>>>1:=>=v=T=%=x= -^>0P>aa?>7?4/>>]>=1>f=y==V= (>0G>`׃?}>璘?4>> > =X>~=|=H=c=>09>`G?q>n?5>q>L>=xe>4g=|>[=S=M<<^]<܉r=W?>,>0$>`e?>}V?6>I>E(>K=Ȓ> =>V=>=<#Q<>0 >`0? >i?7E->}>/>m=ʧ>o=XP>U\==˜<<v>0>_f? 1U>C?7>>Y`>=̶>=>*= q=_>0>_η? N> ?8>8>Լ>)=ο>l,=>>=h= j>0”>_? j>?9O<>iK>FC>=J>{=%>==#<<>0a>_w@? >PU?9> >>0&=>(=@> E=='+<8'<9=qU=>0(>_Oy? >9?:>> >w=Ը>o=K> }4=n?=*q<1:>0>_*T? C>F?;F>|U>_> =֪?S%=[> =ǽS=. <\<= =E?>c>1>_? >:~?;> J> >e\=ؖ?=f1>>1W>^? q>?>e>=}V?r=8>=OV=5t<<܋==?>>13>^ʹ? J>j?T> >E=]?=up>=ΒE=8<<==e??>>1L>^!? O??='>>M>5[=8?qa=>;='=<6 >1hO>^+? ??=>n>pz>d2= ?=yq>;= =?< <==D?>9>1>^? ??>M>!>>=?P=:>Ф=B=C}f<<0*=C=?>e>1>^p)? g?S?>i>n>>"=㦉?=r4>=u=G-S<>1>^`? $?K?>>)>><=j1?=_>T=٤1=J>1>^R? )???I>T>>=(?d=_>==NN<r<[=+ý=N?>>2>^G? . ???o>>I>= ?=E>=k=Ro\<< =/̣=?>>27>^?? 0F???> >s%>=g?=B>l==V@Nj>2a>^:E? 0?6??@>|>Q->q-=>?1]=>*=6s=Z~>2>^7g? />??@9>{>%_>F =?e= >Uj=P=]>2>^7+? +?Q?@o>!>>=x?=Z>|=gH=aV<e>2P>^9? &?Y?@3>j>C> =!?=>=y=eF<<ӱ=D5==?>>3>^>? ?c?@>>f>.=?=F> ==iՕ<Fy>3N>^FJ? @??@>>>)=Fd?=g>!=*=mE<ϴ6y>3Y>^P? ?n?A!>>>ŵ=?o=w>"=]=qU<Җ>3>^]? J?.?A>K>P >W=T ?4=Z>#(==u<|%<؋=V2=?>>3>^m#? ? q?A'>r>i>?=+? =)>% ==z >4/+>^\? ? ?A/ >F>d>X%=J?=>&==~; =1?>M>4le>^8? #? mi?A/>>>= ?=U>'==4>4>^? n? R?A)>n>R>,6=)?=>(L=z=O<1>4>^? ? aO?A>7>>_=?&=>)=h=n<&<=m'=o?>z>5/>^? ? a?A >x>>J=?o[=79>*=R^=&<<=q=_?>+>5u>_? vX? M?@>2>m>>?<=|>+=8,=<W<ݡ=v=U?>d>5)>_$? [T? ?@>d>>Mb>Qn?=>+> =h<=Rs?>>6>>_H? >|? 2?@n>>R>y>R?l=>,ޔ>=Q<>6PM>_p ? ? {?@yb>3>/0>~>P?t=<>->=Ij<J<+==^E?>>6V>_?P??@D>>\8>->@i?"=w>.+>s=<'0<7==m?>O+>6X>_ƕ??z?@ H>z>j>>ߜ?'=>/">;=.<26<=>y?>Ǖw>#>r>>Gw>W;=04<$=^ٚ=P==)j=KB=O{=Μ%=;>zN`?>`L>*>r>H>[D;Ź=#M;=O==6====CT==N;>zo?>*>{>qn>I>_˷;&=Aa;<=[=}=m==7$!=wB= ;C>z?>k>>p`>K>cm<=p=^Y;Mߪ:[==2= ;=[Z=+==;>{Q;?>ƽ>>pL>L$>gg<4={:ed<=b=oŲ<=y1=j={?>Ɔ~>(>o@>M@[>kP{?>N>>o.>NV>o$|D#?>>a>n9>Oh>r<&5= ;_z=x=N=8K=M<=|?>>k>n>Pt9>vb<=<=<ْ=' <[=?<_=|5?>Ť{>>mJ>Q{*>y:<@g=v<&=< a=O <=0V<ȏ=u.<;4>}'?>j>^>l>R|>}<=}o1?>0g>F>lus>Sy>M<=ߘ z2;Qk<<5+=<=Ro}?>>w>k>Tp>9<=;<2>}?>ĺE>>ke>Uc5><ʡ=<U>*@~~o>>j^>VPI><>:^=o<};d<ֳM<% t=p<[;Jq>~}?>B>>jZ>W82>=A<> <>JN^=><:k:~!?>:>>i>X>RV<˰J>Z=gt;C:E<#i;3~?>>>iR>X}>u<;>i=&;\;z<ǚ:<׺_< n;/>6K?>É>s>hC>Y>Y=>Qy=ߚ:;p8?>K>d>hO >Z>P=Q>"<>=;B< <%Ћ;wuN_?> >U^>g>[r#>= >(d=k>E=<j<1ѵ;;#?>;>E'>gO>\;>!= >.=Y>I=(' ?>K>49>fщ>\>=K>4 =t>f+=#?>L>">fTj>];>z=x%>::=J>=X<͒<, ; +;?> >:>eQ>^v>=!>@RL=& j>̇>;:9w#>SE?>h>(>e]>>_*>UY=&u>ED=->>6Uj?>k>a>d1>_>=+l>K!=5X0>Z>0/<4<<3< < l;:'>?>E>>dj+>`> =0f>Q=>" = <>u?>>>c*>a(E>`e=51>Vm=DU#>ă>*p=I<<< C<< Fk:>?>`>>c{/>a>=9>[=Ko>7>3`=(5.3?>{V>$>c;>bb>=>>a=SF>d>;=68= tΆ?>6>{>bM>b8>2 =CN>f.=Z>>Z>D90=D= )<̫=ݴ?>>c>bd>c1>kM=G>kG&=ae>Ț>Lv"=Qs=?>$>J>a>d>=L:>pKK=hy> >T=_2=΅<=&϶= 0?>f >1>a7>d>ʊ=P[~>u;T=oy>`H>\=l=#x,=f=13=Q<;wx>?>s>Q>`>e>=TL>zD=ve>k>dp=y=+=v=;=%Ϩ< ;h>?>U>j>`W>eY>O=Xͤ>~=}>>l>l/=J=2hn=Cz=EΧ=3<#;>)?>>>_6>f u>)=\>j=6>K>sΜ==9=&q=P=AM5?>H>y>_zs>fzd><=`>:=[P?>{N==@ԝ=0]=Z0=NuA;?>>o>_ >f(>I3=d>^=?P>W=.=G.=:==dK=[<+;J!>K?>>>^>gL>Om=hd>=U?~ >%=M@=N=D=nX=h/U ?>m>k8>^7L>g*>OI=ll>Z=,A? M7>=UJ=UB=N=xWb=uu]?>">L >]͡>h h>H=pP>=^r? > =F=\ =XT=#=9eP?>+>,(>]d>ha{>;=s>=?>{M=!B=bE=aE==l?>> >\]>ha>(=w>%=?uP>=1=i=k9=B=<.;\>r ?>A8>>>\>i> ={ >.w=?6>.=m=o?6=tv== =v;m>w?>>8>\11>iG> =~x>-=?>p=(=u\=} ===ˁ<b>{7?>8>{>[̤>i >ȳ=>#6=?5N> =Ĩ={Y=A==m=8< >~y?>Z>>[i>i@>=>=S?>Ź==?==\==T<>?> +>]>[>iI>h=%>=m?&">ؕ=dZ=wq=5="r==<6>U?>>8>Z#>j2'>/o=v>=?!2>۳=Ԡ=D =Dc==o2=<m>?>p>i>ZD>j_>=:*>=lr?#>==N=v==="<#5H>?> >>Y@>j\>j=$>W,==]?&8>=p===H=='<)T>z?>>>Y>j>\=(b>6=?(|>==G#===6k=,<k?>>a>Y)v>j> =>2=?*>J=====ǥ=1<5>|y?>/>u>X>j>=>d!=u?,>&=v7=K==,= =6<;>x?>X>L>Xq>j>P=D>=?/>=)==b= =H=;Ys?>v>">Xt>k\>= >= ?1>8=Ə==(=L=z=@nS?>:>]>W+>k>~=ѣ>=V?3%I>=L=WO===ܙ=Eog?>(>>We>k'> = ~>Y=n?5$>>3Y==j=~=N=5=J63`u?>>>W>kJ>=7>=f?7> > i====暒=NX2?>?>t_>Vr>k A>=\>n=?8v>>+l===4 =|=SO ?>Z>F>VcA>k >8=v>8=O?:۸>55>A=԰==ޜ=J=XHE?>d>>V>j>=>!=̵x?k>Kd==R===\:?>@>>U>j>n\=>l5=?>q>ɒg> JY=S=Ět=V[=K=as.I?>>i>Ui>jb>`=I>=d?@+>˩c> ==a=H=먷=;=e!?>p>$>U>j|>6=>=Ӭ?A>Ͱ>&7=I==>\=jsb?>=m>Y(>TȦ>j{j>N=j >N=?C{>Ϩ!>===7>#=n<>?>>'v>Ty>jQ+>8=JP>1=!&?E\>я>Ԯ===t>=sG,<>1?>>>T+>j!>1= >I=L?F>g>=4=^=> =w<>?>5Q>>Sޒ>i*>x=>W=n?H_>0->U==>l8> [={I?>A>>S>if>=>\ =ކ?I>>?=)=٘>> =|<>?>>Y>SG>itw>0=j>V=?J>ؑ>g==Po>>=5<">?>(>$M>R>i0\>(B=>F=♦?LW">*>B5=ۃ=>>=L< >"?>>U>R>h>U=>,=䔑?M>۳>ϩ==ቲ>>=^@w?>r>>Rl>h>}K=[>=?Ny>-j>Q=K= J> >ʩ=jAq?>A>B>R&>hE>B=9>=m9?P(>ޗ<>Ȅ=kj=z> >v=p<>[w?>>H'>Q:>g3>=v>=J?QW>Q> 3=z^=i>>t-=q<%w>D"?>^w>U>Qj>g;>=>_Y=?Rz>;>!=x=#>>9=m+?>M>>QW>g+>=k > =??SY>v?>"=f=]p>>Z=c<>?>>>Q>f>p=֢>=?Tf>>$2=D+=>>=Td<}>?>Ep>`>P >fUH>=8h>\F=`?U>6>%p==`>}T>N.=??>>$>Ph>e>Q=s>= ?V>ǔ>&=}=>iE>w=%n<>c?>>>PR>ej>ҵ=>}L=?W}'>5>'=yc=7>Q>!~=<_>K?>'>w>P >d>=#X>=J?XZ>>(==n>6Y>#=?>Ǎ>m>Og>dk>`=^2>v=ک?Y-&>;>)==;>|>$= <Ǝ>~0?>f>/%>O>c?>=P>s=`?Y>W>*==M>>%=<%>~?>>>O^/>cW>d=>F=Q?Z>J>+==>!>'f=P<ņ>~T1?>>>O#>b>9=\>ş=P ?[^e>5>,9=?=7>#G>(^=<7>~ ?>Av>oR>N>b/'>K=I>"=?\X>^a>-l=&=->%x>* =}?>ީ>->N>a>={>4C=W?\>>.E=^n>6>'G!>+j=:<϶>}g?>{X>>Nz >`>=>oU>6?]'>i>/k=B>H>)>,(=C< >}@?>>>NC>`K>K=>Ơ[>?]>s>0,=>k>*ڒ>-=<֍8>|?>,>e>N>_>Q=֮>S>}?^v>5>0=c>>,>/=<>|?>NQ>!^>M٭>^6>=>?>?^>>1(=>$>._>08,=A|_?>>q>ME>^9N>V=~>>k?^>>2,@=|>&>0>1RV=<>|N?>>>Ms>]~:>8=cM>>C?_:>>2=U>4>1:>2bj=yL{?>>Ps>MB>\>s=)a>>x?_>>3Hd=>=>3#>3hh= 3{n?>> c>M1>[>(P=>g>Z4?_Z> >3o=> >5>r>4dQ={?>NY>>L>[->=X>>?_> N>47 =r>I>6&>5V#=$<{>zQ?>k>y>L>Z^/>>=A:>ƾ>]?`W>P>4x=>>8@>6==)zm?>}>/>LU>Y>>=b>ƕ:>6?`+|>>4v=>?I>:?>7=&:<>z?>>>L[>X!><=u>a>L}?`9>>5H=>>;>7=y?>>a>L/>W>=>$0>?`;>>5e=\>=>=>8=<}>y\?>A>P >L>Va>=u>ܖ>(t?`1>2>5V=> >? >9w==+>xs?>>>K܅>V>=>Ŋ>#?`b><>5=o>?%>@>:-@==4>x)?>l>;>K`>U>=j/>/<>?_>e>6+=>h>BO8>:x=J=>x<?>>i>KA>T>E~=>|>M?_o>>6,=>R>>C>;y==L>wC?>>>Kg(>S%>=)>Y>?_>Y>67=M>j>Eod><==H>wr?>'>̫>KB>R'}>{={L>>>?_T6>>67=L+>>F><=R?= >w E?>>}>K >Q#>1=>[> G?_@>>6,=:U>4>H(>= z=Ÿ/= ">v?>MU>,>J>PS>s=>> ?^>Qt>6=>>J>=C== e>v70?>?>۲>J>O |>=4>5> ?^D>脏>5A=!>>K>>=(=v>u~?>p>>J>Mx> =_5>> ?]>>5 =>M>M>>l=e==Ef>u\?>>7}>J>LH>=>> Pq?]U>滋>5z=M>o>Nyu>>=ǜW=$>t?>>P>Jy&>K><=>1> ~?\>l>5J=>G>O>?== >ty?>!>n>J[>>Jd>^=>qa> ?\8>䳏>4M=t>K>Q_>?]=*=>t?>">;>J>\>Iz>z=l>> ?[>>4=9>ݙ>R>?-= =R>sh?>?>>J">HM>2=&>> u?Z'>l>4:=YP>>T8>?\=B'=_>s?>L>>J>G>R=%>j> . ?Z6>1>3h=>O->U>?u=]=5<>r?>\>9>I>E>=wi> > K?Ysu>>3L=>s>W>@w=tM= >r%?>j>Q>I>D$>x=S>> d?XB>ތ>2Ĺ=4>>XaL>@&d=υ0=>qn?>v4>(>IO>Cf>}=&>> x?W~>!>21\=\>5>Y'>@0;=А= >q*?>z>1I>I>B>$=>g> ?V)>ۧ>1=t$>2>[g>@/=і=">p?>=>״>I>@>m=(>> ?UC>>0={.>Mk>\j>@%=җ=$rN>p'?>}>}h>I|*>?>tX=d>> {?T>؄f>03(=q>ˢ>]>@;=Ӓ%=&N>o?>:>"f>Ih>>,>V=>Z> ?S>>/rc=W>@>_>?=ԇ=(,s>o?>.s>ƭ>IU><%>3=>> ?R)>">.E=-?>>`Rd>?"=w=* B??|z= .=!? >q"=K>Uy=L=)> B=G^]??}="@<'q>=? >-Ja2==:>Lf*==|>=@??%><֢>=?Q>z; 9}<;=Z(>QC=.G>B,=^=u>s=8<?!?>n=_>=?F>;W;rC<&=C>A= &=>9==il=-{=1?~?>/~=8><ө?>Wy;. ;t<%i=+v@>0t:=>.¾==]]=鿏=(}?}q?>,w=X$)>;?:{>9Q<>#:xz=> =#+>$G={=QD=i= ?|U?>:?=ww>;'?V>T;~a<~ <L<>c<毉>c=r =E=,i=y?{>.?>G=>%>:7?n>;<W=^<=8 =0=Z?z*T=->9[?_>;c=Jd=,8=1=D?y?>a_=>8?>m<r=L<5=E=6=!4=n=7X?x ?>nZ==>7?>̯<6<T=2i< ===#j=D=({V=ǾF>6χ?>AC={>5?> _<~=/\=x;S=D/;I=C< <=<Ёq?t?>,\=W>5#$?>(*<=+=;=C;{=P=`>4N?=>5b'>>3{?(>5`>>2C?>(<ě=Vk=i*<<%e;ʁ=hh\L>>>1?t8>#%>>1 ? ]]>T(>G>0=?!BA>3>#p>/p?"">n=5=>`=/1=SZ<<';p<-<Z<'"u?mg?>@]>*>.Z?"E>= )=m>t=B'=xE>0>-t?#d>==R>p=Vni=Ia>7?Z>-?$B>W{==>&=io=<0;q<=T:;1j;)D?j_?>ɱ>=4>,K?%z?o="^a=X@>=|9=2>Dd>+?&F9?-Y=)=>'KN=d>^= <I>J\>*?' R?)=1K4=>.=>Mk=o<2 <;ӂ;6:l?h?>y>P>)_?'*?P=8=<3>6 =E> o="=Z= <cSޖ>V>);=?(?==?Q=\o>=N=W>,=.xb=4=ޯ<:<;Ω?fY?>@>\x>(zf?)I? =F=f>Du=LR>9=:=T=(>bS>'?)(? |=Mշ=[F>K=$>ETp=En=tf_=7^<<3<|=?e}D?>}|>h>&?*? S=T=9>Rz,=ޕ>Qim=P#==G.#<4=!n<"Ԫ?d?>Og>n>&??+^?-=[sg=>YX=| >]R=[5=ID=V5< =K<@ ?ds?>>tF>%?,?)^=bZ=׵x>`=_>i=f1==e <E=+<]!s?c_?>>y>$ɞ?,?=h`=Rs>fR=_>tX=q=,=s,<=><>$?-M?%=oy=َ>me$=ߥ>'=|_=ƅ= a<=Q::>#X?-9?=u_=J>s=ά>=xM=:=&%D>"H?.?={=$>zJ=ڊ>*==v='==v<c?`:??>>!?/?nl==>L=I>==y== =>!92?/M?Χ==9>hz=>=>x=P=U=6> ?01?(8=ƃ=4>x>>@?=G>==J=D<҉?^?? 1]>>I?0?{!=F>g>{>sj>q4=i> =*=(o=<9?^c??QK>%E?1<?a=~>e>s0> 0>h=>ɋ=E=1V=m<?]s??=>>v?1? =D>r>^>">=y>}==9L=*D> ?25O?K=>`>>v>'>=1>"=[u=Bu=C=?\C??$>>?2? *=> >#>>[=~>(=Í=J=[= ?\Ae?? 2>>r)?3?!=E> >>>=kg>/ =ɤ=S0==%?[Y??*>g>Ȟ?3>?"=Ԝ>BF>>> =D>5`=Ϣ=[hT=+=?[G??>]> _?3?$=U>w>ER> m>f=]>;=Յ=c=o= q0?Zϴ??>>yk?4Y?%"=Ȭ>>>#>=>A`=O=k}= ='13?Z\??A>2>?4?&9=->>>' >V=>G =v=s|\=N=-?YT?? >b>/e?5?'I=>> >*G>ϮV=@F>M=={Ql=V=47?Y^??!>>S?5p?(S= >߸>>-s4>=g>SN=G=="=;?6?Y:??#H>>?51?)V= <>d>~>02>=}>Yk=p=X>Z=A?X??$>p>J?6?*R=6w>!>hh>3>2=ց>_f==>=Ht2?XSe??&s> >?6_?+H=U>>Y>6>2~=r>dJ=S=> Q=O-?W??'>> ?66?,7=g >!>P>9>%=R>j0i>|P=L> =U?W??)x>>pb?6_?-=j_>#k>XO> =q>o>=#g>S=\!?WH??*v>>?7)G?.=_>%3>T>?F>2=>tU>h=>p=bz?V??,X>>;?7c?.ܖ=G(>&>`>B j>Z=$>z#>3=>g> =h?V!??-i>W>Z?7R?/= >(>r>D~>;=l>?+> =K>=oK?V`??/>%> ?7u?0~=>*J >>Gl>l=>#> ie='>!q=u?V??0a>>t?7V?1E=>+G>>J>@=>>=>"={?U??1X>>?8#?2=Y(>-w>>La>&=t>R>ӌ=ߌ>&="?U??2>R>Ln?8IT?2=>.>>O:?1=>h>=(>)e=Df?U`O??4N>+>/?8jq?3r=_>0y]>5>Q|?=(>a> =e>,=a?U)??5?>Õ>)1>šp>S=?M>>>/=)>0|=z?T??6_>(2>?8?4=>3Oe>m>V-h?N>">B> =9>3=&=?T:??7v?>ư> 7?8>?5d=w>4>->Xp?>>>s>8=>6l=?T+??8n>/>~&?8U?5=Q;>5>K>Z? > x>>ٸ=">9=4?Tu??96>ɤ> `?8*?6F=ş >7>k>̊>\ɐ? >>>5=>A> g?8׽?7`=>8x7>&>^? UE>H>N> s=n>?=?T2??;r>q> ޶?8?7=>9>Ϸb>`? > Y>>"-&=Ĵy>B=?T??I> V?8?8=4>:>;>b? > >2>#ٚ=ǎ>E=?S&??=8Y> > 9?8?8=J>;>Ҵ>>d? > U>>%y =[X>H=?S??> ">Z> J?8{?9-=R><> >f?14> A>}>' y=,>KfC=c?Sڪ??>؅>ѕ> ?8?9l=L>=$>Ձ6>hx?L>|>Oc>(=Й>N4=?S&???>X> D3?8?9=8>>P>ռ>j8\?]>->X>* L=x>Pb=|?St??@S>> ?8?:,=>?ڌ>H>kb?c>j>k>+t=<>S=c2?S??AI>`> B?8{!?:i=>@>Z>m?_>>}>,=ףr>VX =F ?S??A>$>?8\f?:ё=ϩ>A4>ڋv>o?Oe>>>.$r=&A>X2=$?SD??BDv>$>FJ?89j?;=]D>B`>۰>p?4>>S>/h=ܜ>[<=z?S??Bt>#,> ?8-?;[=>C">Ⱦ>r?U>#$>@>0(=>^(=?S;??Ca >p>O?7?;=ћ>Cب>m>s?>E>>1~=dA>`='?Sp??C<>>r?7?;˙=&>DC>">t?>_>2B>2=r>b=v=?Sw??DX>x>]?7?;t=Ңn>E$>>v(?]>t>!>3!=;>eW;=@'?T P??Dk>۽<>?7J?< =>E>ೡ>wep? >݃>>4n=2>g=?T"??E)j>܋+>pA?7"?FEw>k>xn?>>C8>5=^>i =z?T@t??E>OD>?6[?<[=î>FR>a;>y?J>>o>6=~*>l3C=ʄ?Ta??E3> >?6R?G:>>&>zý?؀>J>>7D=V>nd`=>?T??F>޹>?6??>G:>>{?\>>5>8=>p_=1?T??F[d>`>?5}?<=g@>HE>>|?Ԩ>x>>9H=v>r@=Ҥ?T܎??Fc>U>6?5?<=ԁ>HWa>,>}?Bl>fd>p>9=k>t=P?U ??F>D>?5I?H>>~u?O>K>$:>:7=a>v=b?UA??F/>]>\?4Q?H>J>=?Q>,> !>;Al=7>x2=ڝ?Uy??F>ᘢ>?4?I>ǫ>A?Js>1>%>;ϟ=>z=>?U??Ga>>?4-?<:L=`>I:o>8>Q?>>F>|h= ?U??G a>y>?3?<;=5]>IW>睿>P?> 5>̄><=l%>~9=q?V9o>3?3[?;=->IjU>> w>>=,$=>+=?V??F.>3^>O?2?;=ӵ>Iq>C>%?7>!<>YY>=J>Sg>ڏ=3?V??F>x=?2x?;=_>In|>>^>?(>!x> >=n>>{= ?W??Fb>ż=?1?;M]=>I`'>9>S?4>!ҳ>>>>>W=?Wn ??Fc>,=J?1?; =ҋ>IF>h>"?5>"#g>Ss>>F>>J$=*?W??Fj>0=?1?:= >I">>ۨ?+>"k>a>>l>C> =?X[??F/1>W=[?0~?:oG=>H>>?1>">im>>>0>˓=$d?X}??E>ty= i?/?:=>Ht>> ?>"^>>>>>4=?X??Eg>䇓=Q ?/g?9=;>Hto>i>? ># >O>>>6>4= H?YE??ECh>=H?.?9U@=υ>H$z>>?>#/>ñ>>>>У>J={z?Y??D>G=?.@ ?8=E>Gɕ>>?Wd>#J">>>h>da>=?Zs??Dw8>=1?-?8w=z>Gc>p>? @>#[>P\>>@&>>%$>%?Z??D>q=?-{?7G= >F>}>?;>#d2>Ď>> ,>yD>{>V?[6??Co>S=?,d?7=>FwF>;B>?UV>#c>Ŀ>=.>g>Q>G?[}Q??Br>+=)C?+?6=!P>E>>?>#Z,>>=z.>uW>>?[>??Bn>=?+?6m]=>E_ >/>?r>#G>>=*>>f&>܊?\z??AC>d=_?*cH?5= >D†>+>w?c>#,>&><$> X>B> ?\??A1>x=8O?)?5@=y>D>7>B,?d>#w>s> >bO>+v?]??@|>)=?(?4=Ƣ>Ch>:>?ʹ>">>;> #>M>O?^???>в=?(;q?3==`l>BW>Z>®?+>"7>e>;+> ~>F<> r ?^"???>m=^?'z?3JN=>A>>x?~>"c> >:> Է>> 6?_7??>FR>=?&D?2=±>A>w>&?ƛ>">Ģ>9> $<>> K?_ϝ??=t#>ኁ=/?%L?1u=E>@1>A>?>!->i>9-> m>n> J?`k??<> =N?% ?1=>?H>>~ذ?6(>!ns>$>8i> >d> 3?a ^??;>= ]?$N?0O=Bo>>T>H>~ ?]>! >>7> >>?ax??:.>=}?#x?/=%>=U>vf>}*?z3> >v>6d> $M>`>?bTd??9e>M=??"?.=>*>|>P?> ($>L>5@> T>&>'m?b!??86>ަ0=h?!?-I=U>;6>߭>{C?>S>™>4> >>9?c??7>={? ?,=}>:%>޷>z9E?>!}>L>3> :>>H}?d`??6>9:=]|?U?,2=X>8p>ݵ>y ?>>>2> ">Nb>U?> ?#=>5==Fѓ<'^=R)<<|>ں>;=+`=S2<ߜ2<=?>!1?2=xm>5?=^=^K0<=7<*d<ݧ>6>e.= = -3 ?2=>5?==k=u3<j=;,<{>>="=RCq?=/>4=a =B;=;XRb? 2=6>4R==6;ʾ6={_?!7=V>4Ah=% =;=m <<[=K.=ͭPk?##=@d>31=o=;zV=^v{?$=`>3=I= ;N[=Pb= ^<I=ڝ=?&=J>3@=F=; =A=*g;=Ҡ=x<2k<<;Ֆw?>D?'q2=Q#>2==ȷB:=2?=G]T;KO=ʈF=r< z?(=>2R==^83=$3@=c#:=V=J!/< <2===:o;=v=o:ڡ= ="?+=aD>1==Q:d=e=g;=a?,"=>1?=K=;A<=;=%<4?.Q=V>17=Ό=S;`n<=<=G<6c<.?/=p>0߰=I>kx;q<=#<;o=o:<;<];M~;nB?>/?0=">0t=>b;ʼn<|=P6?2E=%n>0.=ܔf> J;/?3=>/=">#~<p<3C=<>=z?<ʕ;x0f<;5ף;?>?4v=>/|=><O(;:={?6=3>/#=T><&3^;g=<=U=+,9;ڹ9#|:Ȉ?>q?7T=>.=l> P<7R9T=<̈J=B=M!:0;;:a: ?>f?8w=>.o=>$<&=0(=n\;9>;`;:$?>Y?9K=A>.a=>)w YK?:_=>-=* >-4=V= .=:;ť_:7;2%9?><?<(=M>-_=I>2`0=U*?=TD=N>->>6<<>0=<Š>=<94:;|:*?>m?>|=>,>>; <<-> =V<=EDq??'=>,M > >?J<%,[=!n?@w=[>+>d>Cy<<>*#=)h<*=?A=>+> }>G<,= >.i=1D0;=?B=M>+7> ^~>K 3=9:%> ?>?D =g>*ڱ> 7?>O 8_Z=@;f>w<<c?E2=>*}T>#>S T<<'m?F)=>*>)>W~<ʄ=L*>AO.=OO?G3=r>)>S>[QE=V<3y>X<04?H9=>)cn>K>_<=l?Z>I=]v<ٌ4>  ?I;=$>)>>bM=d{=>&<·y?J:l=}>(>>fm< n=E:>Qۀ=k=>,<٤<Ț?K56=o>(F>HS>j<=b8>U=r=/e>2<(?L,?=/$>'V>+>m<^=>Yw=yI=E>85p|B?M=>'>t%>p/=}=>]=պ=\0k>=<&:<;<~< a?>S?N=Y>''{>A>tf4== >`^=!=s>C =Z<<=<?>*?N=8>&>>w= 9.=H>d=I9=>H9=?O=F>&fk> >{ ==YR>g]=a=>MCH= <?P!=>&n>"mh>~>==,>jY=j=}l>R&R=<ʛh?Q=A>%%>#>#=O=>m=dt=W>V=4<tO?Rk=&>%B>%:>A%==?N>p=O =L >[x=<݀s<S<;s?>C9?S]n=M>$>&>u="=ؙ>s~=*e=Z>_= Z<<7?T2=Jc>$~y>'>D=&s=>v@m==̂>d0=%\A<%uܰ?U4=g>$>)4 >=*=b>x=_=M>hR=*^<_<#/>*w`>(/=/=Y=J>{n=`=!>lN=.=E8<<^?>pT?V=R:>#V>+>=3T=F>}ې=b=*>p#=3R@=u<37?Wb7= >">,s>=8 >a>==(>s-=7= W='?X$=>">.1>D=$>0!=m>i>wZ=?Xu=Yq>"*>/6>=@> ><=> >zu=@2=J&=<?>(?Yt= >!Ʈ>0R>۽=EN>0>9=>; >}>=D=_= aG?ZU=>!b>1f<>=I>|I>)=2>M>;=I3=== .)<?>V?[ .=` > *>2r>T=N,Y>z> )=u>@>=M^= y=??[=o> >3v>=R`>>ޒ=M>%>_=Qw&=$=N<?>?\d=> 2q>4s>=W>t>=>,z!>=U~n=)9=9<?>@?] !=f>̠>5h0>=[>#{>Z=>3*l>=Ys=-am=<11?>=?]=3>f>6U>N=_>(*J>=>9>=]W=1=L<?>S?^RU=Q>>79>=do>,>=ߦ>@>,=a)=5=k?^N=k]>`>8>;=h >0!>+=">GY>0 =d=:="`<)}?>"#?_=X>2Z>8Q>=ma>5U'>=`>Nm>=h=>&2=!w?`=A>>9>[=qܿ>9>=h`>U_>l=l4=BCa=#<?> ?`=p>cg>:2>^=vYA>>-l>|="">\]X>ű=os=FX=%]<[?>;?a==>z>;<>߮=z2>B>=̦>ch>{=s8u=Je=( <#?>K?a=>@>;>K=V>GO>=g>j >_=v=Nj=*3<^?>2?bNV=t4>*><>5=>K\>N=>qi>=y!=Rh=,=vH?b =>>=F>sl=,>P>x=p>x>)=}8=V]<=.80<ˢ?>?cO=!D>X>=>?=n>T>>=L> >=5U=ZJe=0#<Є?>+?c1=w>Q>>{>=9>Y>=<>G>S=a=^/=2H@?dB= >>? >=>]>=ʋ>^>*=L=b =3n<[?>?dU=$V>>?%>wG=8~>b>6=~>->Y==e=54 ?e&F=z>3>@>$=}5>f,>uB=>>uN=@+=i=7<:?ev=е>F>@>=£>k3>J*=j>>}==mt"=8?e=&>ۜ>@>iR=>oZ>=/>R>r=<=q1E=:o?f_=|>p]>A[>=O>t] >ɏ=2_> >T=j=tf=;i -?f=Ҿ>>A'>=;>x&>t =%>>#L==x==f>?g=(>>B>=߈>}>f= \>>ޖ==|8=>\?gw=~l>,>Bb>=(>>=~>>=E==@ =\C?>~?g=)>\>B> f=rI>l>=ӥb>>O=|=q=Ag=?>?h=)>S>B>}=>>=\>>==|=B=?>,?hl=m>>C!>=>^>g=p>w> =`=>=CȖ= "?>÷?hK=>y/>CQ>F=S>m>J=՛>r>e===D~= ?>Y?h=*j> >Cy>=h>ƚ>=$>s>X=c==Ei=a?>?i@=>>C:>=>!F>=֞5>{>= =n4=FW=?>?i= >/L>C>:=;>}>0=>>= = =GH=_?>?im=*a>>CZ>|=>۹>I=c>Ş>c==K=H<=X?>?i=>Q>C>=>;>">=ׯ>ɹ> ==y=I3=?>2?j&=ԭ>>C>?=*4>>#=>۹>== `=JC-="?>M?jW =)>s8>C>={>*>=>>===J+=ky?>LH?j=~>r>C<>7.=̾>e >=88>2>w=X=as=K+=!#?>?j*=ӛ>^>C>R=>ˤ>}_=G6>h>3=\==L)/=#?>_?j =(q>">C>fQ=r(>3>{1=F>ޣ>= N==L6=&?>{?j0=}6>P>C[>rU=>>x%=7v>#>T==% =M"@=)\?>m?k=>AT>C-J>v=p> >u=>.>}===ML=,!R?>W?k)4=&> >B%>sE=o>w>s9=>~:>zPU=5=>=M\=.?>u?k?={>^v>B">h0=ŗ>>pY8=׭>>v=Շ=Ġ=N'p=1?>a?kQ5=ϙ>>BsB>Uh=>>V>m\Z=a>0V>s]P=l=G&=N`=4?>w?k_=$>zc>B%>:=s>n>jC5=^>&>o==ū=N=7R?>?kj4=x`>>A>=˴>=>g =֚l>v>k==@/=N=:'i?>t?kq=̩> >Ars>=$>>c= gφ={==N=<?>?kt0= > ">A >I=~>+*>`N=Ֆ?M>cu=o=)7=N=??>j?ks=u> >@>=F>{>\=#?/>_Z=ڛ==N#=B?>?ko)=> :>@*>C=3;>>YR=V:?qa>Z=[,?kg=> >?>X=َ>8>UZ=ӟ? L>VK=)=h=NLx=H}?>S?k[ =q > R>?)&>=M>>Q{j=ح? w>Q==A=N =Kep?>F?kKz=> >>>Q=Hi>Ě>M = ?I>L=,'=)=M=NPX?>B?k8=> i>>>=>>>Ihf=)?>G=jO=C=Mc=Q>v?>+ ?k =lu> >=k>=>ɠ">E4y=* ?|>B_===LG=T/?>_?k=> ~d>r=d >%]>@E=&??>=u==-B=L|=W$R?> ??j]=> ><>>=>άM>7F=n={=K=Z?>w?j=g>>x>;gE>%=$>4>7=;?>1؆= =@=KZ=]?>?j=ú>>:o>=&>ӿH>3I=%?R>, 4== =JG=`.?>N#?jt=>W>9>=I>KS>.=ʀ?>&Q=$=O<=I=c?>1?jG4=ah>.R>9*>| =K#>>)=1>?!T>=$q==I5=f#?>?j=Ĵ>>8H>ޭ=>h>$4=o?#>=w=5=Ha(=i"?> ?i=>?a>7mq>9=>>=da?%>J== ==G}y=l-?>}??i=Z>u>6H>=x>>h=?(^'> ==1-=F=o<%?>|?ik=ŭ>O;>5B>W=ݹ>!>=Z?*Й>Y=/=_=E$=rM?>{]D?i*=>ֵ>4_>*=D)>X>=?-FK=L==#=Dx=ub3?>z?hd=S>]>3>XI=R>ON> '=?/>=D]=i4==CX=xz ?>xۦ?ht=Ʀ>>2>> >> =Y{?2;r=~=*==B*=={?>wy?hR=x>kP>1>o>=>V==?4=M|===@=~Z?>vNc?hS=L*>>0/>u>r>!g=i=;?7==^V== =?=i??^d>Jā>C=c4=T=a>R%>ty<<;=?=M==>=/=E=d>Yz> Tm<ݓ;<=,=;==l[==~= o<0??@Q?>gc>`3>#,= Pj>gd>%+=)|< = M=F<ё3=͏u=N=‘,<<??B(?>mX>o(>(=Fk;GI<듊=*<ǖ=EL=P=^Cp>vH>+=cM:ls>}\l>.@=:ͱHvx>1>0==W;z<a<yZ$>o>3N=|<V<8<0< -= =sΤ=|4L>$>6>=<=;3t??J(L?<>(>">8r=]>>;l=K>bq>==҄<; :G;7]=2s=<=`<=< |W??M? 9>>>@{=<< o;O;A=<=N<޽;e??N?!`>>~>B=<\%>g>Elw=>k>G]>~Z= 0};À=x>~>J>> =<>L&>3U>LG>8<=$x<>j>NL>|3=0x= >X>Q@>==S= 2>nj>Sx>">=I=*= 0<8r<<Y>>Uƞ>(Y=UĞ=:=W=_W> i>W&>.=a=J5='?= t<=7R;2f:YH;G???Zo?,u>ʋ>$>Z. >4=m>=Y=6=>6>\VU>:=y=h=EO="t==Ltn; T:9;??\X?.|>-">C>^v>@==x"9=S=-?=r=d; ;+ ;??]?/ȧ>Y>IH>`>FF=Y=C=b|=71=/%=|Ď<0 ;ٍ;Q??^?0B>J>Im>bb>K=J==p=B|=F=I>Cv>d!>Q==h=9=L=\q= <1;N<[??a?2>>7f>f;>W /===7=WAd=qٮ=<—<t^<0 ??b&i?4>y>%>>h>\=K==í=av==O< <yQ> >j{>b v=="=A=k=}=C=<6>>l>geA=_J=<==uP=$>=X=H'+>P>ni>ly=G=E==d==K=':6->ڟ>pD>q=> ==^=j==-=e=9<|a1A>oa>r>w.==#l=2=`==`=K,<IV>8>sf>|.====!=m=?=\<><0q??i?;*>M|>B>u>=)(=Ѻ=?====nC<<~??jD?<*>N>幤>wg>=]#=lz=5,=v=/n>ь=<;<8??kT?=(>J>p>y`>=σ= z=[= =7>z=w<<??l?>%>D,>"Q>z>:=ԝ==G= =)>> H=p<&h9>͟>|o>Zi=٩==׼==^>n&=2<Ε< ??nA?@>+>r>~ >C=ީ1=l=#=m=>=<o<ܕ??o?A9>#>->>=>=a=|=>;>=>n>9>Q==%=Ȥ= > a>!=o<>>>\>=W>^==G> >&p=,%<-(<]+??ra?Ci>D>>>.="B>=6=rX>}N>+LG=}=>S%>{>==ߊ>=Y=>'k>04=Ρ= qt=%??tV?E>>_>>&=> ">\=šg>L>4W=[=S=*V??u?Fb>ch?'>B>G*>=>>=Ɨ> Y>9==Ŏ= 6}??v?Gt>8?bg>g>_>d>>=ʅ>$\>>'1=+=m0=I??w?H> ?>&>nl>E>> =d>)_>B== H=c??x7?I;>c?Λ>E>uc>>x> ;=4>-|>G;=8Z=%=??y^?Ju>?4>>s> >N>=>280>K>w =+[= ??z3?K^7>e?.>>i> M&>^>gB=٦.>6>P>ѩ=0=%܅??{?LE >(?Za>%g>Wr> v>>B =H>:>Tj> ,=61=+Y??|t?M*m>p? >:>>">=ڞ>?(>X*>a=< ? >Q>>H>%Je>)=]>Cb>\t>=A.=5J??~Un?N>X? >>>>'[>|=ѕ>G>a>:=Gv=:??C?O> =? >l>@>>*p>!h=5>K>e.>=Mf=@9?O??P>F? #>>YD>Ƒ>- >$n=]n>Oj>i >y=R=Ep?~??P>?S>݌>n>:>.>&=ħ>R#>l/0>#U=WV=J4?}:??Pŀ>?(>>z>>0>()=G>V'>o=>'PF=\ =N&?}??Pk>?>>}d> >2>*.=[|>YQQ>r9C>+s=`=Sn?|6??P>G?0>Ԕ>v_>e>4x>,*I=x>\k->u!>.=e_=X?{W??Q> ?>>e>>68>>.r=f>_uz>w>2e#=jK=\?z{o??Q5>$??>>LE> z>7>0Q=r>bpg>z>6 =n=ar?y??QPr>X?V>>)Y>!E>9>1=>e\#>}j<>9=s*=f ?x??Qj>r?A>$>H>">;5>3=>h8>&>=JO=x.=j`?w??Q*>aZ?7>W>&>#D><.>5[>>k>J">@!=|Y=o??w%??Q9>M/?7>iJ>>$>>T >7N3>>m>'>Du==[=t3?vV??Q>6??>L>B>&4>?z>9 M>u>pv>L>H==x?uh??Q>?!>+~> >'>AH>:>G>s>>K='r=}?tI??QB>?\>>R>(/r>Bj>>u> F>O=c =+ ?s??Q>>?>>8>);>D>> >Y>x30>#B>RY=r=-?s2S??R>?i>>κ>*@>Ej>?)>H>z[>4>V==y?roh??R(>b?Ж>g>[>+=>Fg>A6>;>}>=>Y= =F?q??R>0>s?55>X>>,4>G,>B>|>r>>>]=2i=?p??RS/>H?>%>>\>-">I3 >DB>>>69>`t=^= ?p4??Rg>0?>h>s>. v>JbW>Ex>*>>&>c==l?oz??R{>?R >h>;>.>K>G,>p>!> >gO>==?n#??RD>?e>w@>>/3>L>H> 5>/>>ji=:=8?n ??RW>?>6>>0u>MN>I]> >=>X>no=+=&?mZp??R>N?U>u>KL>1a>NK>KRm> .>C>>q~p== X?lD??R>?>>?>2%>O>L> >D;>Z>t݋=2=wZ?k.??R>?T>c >>2]>P(>M> >>?>>x9=M=@?kM%??R>7?A >>y>3>Q%>O2> h>1>L>{=f8=U?j#??R>T?>>A>4I>R>Pn> %>m>>~=|=?i!??S >?x>r>k>4k>S`>Q> >>(S>==;?iR??S>?7>a>Œ>5>T2>R> ]>> >=t=2?h??S*\>}?UV>>¥>6/>Tq>S> >¿>`,>p==)?h ??S9V>0?>f>µ>6ĵ>U>U> =>>>=‚=j?gh??SG>?>,>¾>7R>VpE>V+I> ,>f>y%>=Q=!?f)??SU>!? >>¿>7F>W>W;\> 8>/\>#>c=i=C?f+??Sc>8??><>¸v>8[)>WY>XDT> \I>A>s>===#|?e??Sp>?t>\>©@>8}>X^>YF<> x>8>I>==X?d??S}>"?>f>’ >9II>X>ZA!> />fJ>O>M9==/?d]??S>(?Ծ>>r>9>Y{>[5 > X>~>+>==G?cu??S>v?N>>K>:_>Ye>\" > >> Q>R=~=G?c2??S>e?+X> l>{>:}>Zt>] > !>hn>`>0==׮?b??S>?R>>W>:ח>Z>][> >8>#>==j?b??S^>E?w>>9>;+ >[L>^> >A>>p=u=/?a$??S>+?d>>_!>;x>[>_a> k>6>/>=!=Ț?`C??Sˁ>?h>>>;>\_>`\<> K>*>d>A==7n?`e??S>M?>>>;>\M>a \> $>N>R>L=c=׉?_g??S>O?>~>Y><8>\'>a> >U>M>=={?_Qd??S>b? >|r>>\>b> |>N>>c==" ?^??S>_?!>{1>><>]x>cD> >> >%==?^D??S>m?5;>z7> ><_>],9>c> <}>9G>>j=Z={?]??S>?F^>ysz>><>]Nc>d> > > 2>`==-:?]= ??T>k?U>x=>o><>]g>e-1> u> 8>->==2?\??T >?a;>w>w,>=>]x>e> ?>n>>g=ț=?\<??T>_?j>uR>>=&>]S>fR> M>>>8=׿=[?[??T~>L?r9>tt$>@R>=#<>]>fڜ> qc>!U>>M=ٶH=$?[A ??T>F?w>s">>=#>]xP>g\> >rC>>s=۬=p?Zź??T!>?yU>q>>=[>]f>g8> >>>=ݢ= ?ZK??T&Z>!?y.>pk>0>=b>]L>hMB> >}>~{> =ߘQ=}?Yn??T*>?v>o;>p>= >]*1>h>y>C>L>N==P?Y\j??T.<>7?qr>m>>\>i#>>~>>i=k=(?X??T1>TA?i>l">C><5>\>ie>O>>3>=x=y?Xr??T4>2?_>j>><>\?>iv>p>>>,=n_=?W??T7>?S7>i#>>\H>j5 >2> >9>=c=͍?WL??T9&>j?D&>g>2>[>j%>W'>2J>h>m=Y=?W1??T:>&?2>fm>@>< >[>j>G>Q]>^>L=O>T?Vn??T<+>l?>dl>E>;O>[DY>k >߆>j>>=E>ϱ?VB??T=>du?>b6>A>;>Z>kF>>~>|>T=M=??R>:?>q=LeO>+hH=9W<&=i=|u===>;o>YD=RG>-x=='F>5=X>0>t>=]@>2n?>!X=c>4A >&=i]>6;BT>+5@=o'>9&;mT5C>/^=tp>;Q^<=gt<52<7=4<=O=¦<<2U??[>D'>4o=z2>=s<5<3&<= F('>8= >?4Gk>={=>A=P,;>H>A=M>C=.ý9d<4c< <$y=$R=b9;<??`>IY>FW=|>E7=M;;<qFK-p>JH=4>GV=lڥ;f;sG< ;E<=:Lk>O=J>IJ=;J;yM>SH=>Kg =<$;w<$v;#v<=:)<??dI>N>W= >M@=8P>[=>O=/QQ>_:=0>P״=T<ܐ:9g;Bt<UR>c}=;>RH=@v<;R%;5;;Qe<:S>g`=>TI|=޻b<;G;;?:¼T>k=>UF=<;5<P<Q::;%;jt<.D??jY>V>o=>W=C<<28;%;)??kQV>WO>s3=>Y-}>X|>w=Q>Z> =n<>&<G;1;y; ??m6>Y>{M&=>\@>~/= vUZq>=>]>M=[T[9>[=U>_-> 8=o<@A<9]#Q>,=>`>&=#^H>=x>a>-H=,8p<>~=T<]=<<<%f;6s??q#>_ld> =b>cH>3J=4< \=<=jF=<3 ;??r>`Z>x=R>d>:<=a>/=>e>@=Db>=>g 4>F=L<ӷ=5)_<n=-M=;c>=T>h9>M=T"<w=@n <=:Y=M[e>-N=>>i]>S==\6f<.=K<=GE=^6??vg>f>=E>jw>YL=c<9"=V=Ib=T=o<,g5C>`=c>k>_H=k= =a==`_=j <hJ>=>l>e0=rPs==lR?= =mHV=i^>x==>m>ko=ye= =v=6=y=><<ڗ??y>jp>D=>n|b>p)=+X==x= ==<\<??z>k>u=*>od>vr=w=;== =B=ρ<<.??{=>l>=O>pC>| =9=#=%=#R`==B<`<??{z>m8>W=θa>qW>R=&=$j2=>`=(==<[<,??|>n>=Г[>q>=Uk=)=G =-:=H=(oY>=g4>r>.=q=/T=@*=2h=="<p>xf=3>sW>={=44=)m=7=}= $<=<[??~>q>=q>t>l=r=9C==r>=׷>t>=W=?2=d=A="=٩<s>[7=n>u=>9=(=DZ==E{=Y=^S<{=<?~s?>tA>E=گ>uN>=l=I =`=Iؤ=v=t>=>u@>6=t=M=4=Mq=l=u>=)>u*>֭=F=R==Q=M=p<=GE?}?>u>=>uh>؛=?=VcD==Um\=(=Auu>t@="|>t> =Q=Z=I=Y=Խ>?<= ~Y?|I?>va3>2)=1>tH>[=PK=^==\=z>Pv>=;f>t]>l===c 7=3=` = ><=+?{?>wA>=?>t[>yp=w=g =͇0=c=ݍ> G=q=1+R?{3?>wJ>K=?j>t>H=߬=k F=6(=fǟ=> a=q=6%?zp?>x%>=9>sۂ> ==o:=N=it=U>2J=uf=<2?zI ?>x>=/>s>G=:=r=a=m=ꞙ>Q*= Al=AQ?yـ?>yi>6t=I>sA<>{.=̈=v==pL=@>f)= =G*?ym?>y->Ͽ= >rq>#=MZ=zlc=K=r=">qm==L<?y?>y>c=>r;>‚==~:=⨩=u= w>s==R?x?>zr>7=Ұ>r)>X!==e==x=t>!kT=VV=W?xAP?>z>}y=鯂>q>=g"==2={,U=N>$Z?=M=\?w?>{e>=ꇘ>qO9>g==Pl=`=}>p>'?==bX?w?>{>6=Z>pv>=== =?>W>*=q=g?w6B?>|]2>=)>p[T>S =?==:=J>6>,|= D=m$?v?>|ڎ>uz=>o>I==K=^=o>>/|="4=r?vv?>}Y >d=f>oM>=d===> >2}=%=w?vK?>}ذ>T=zn>n>q[=Y=u=b=> !>57=(b`=}F?v ?>~Y}>=6>n')>Q==x=5=> c3>7=+]=Q?u?>~x> =>m6>=im=r>}=|>l>: =-¾=<?u?>^>=>l>Aq==><=B>>=2=0p=Q?uE?>>=R >l=2>u=È=j >-=oi>q>?˧=3=X?u ?>4N>/=>k>=X=>{ =I>>B\o=54=?tq?>w>=>j֦>=*=5>o=>]>DU=8r=?t?>>=E>j>>=P=>=ߧ>;z>Gfu=;=\?tw;?>n>=>iV}>%=ij=>9~=>.>I===L?tLO?>E>X+=}>h>=C=/U> kE=K>G>LQ=@ie=r?t$?>>=>g>Z=J=s> F=>>N'=CP=]?t?>S>=#>f>=}=> =@>6x>Q%=Ev=?s?>>=2>f>=š#=b> 0= &>*>Sz=HX=;?s?>a>7=>e%B>d=ŴN=> /=>>UR=J=_?s?>6>d=@>d;>Ź=ŷs==%H> gL>X=M5= ?s?>>=>cJn>Ɣ=Ū=\}> }=>!>Zb=PC/=h?s?>=>~=>>bS*>f~=ō=u> =>#s>\\=R=ek?so?>R>ϻ=>aUK>1 =`=> =`>$Y(>^=UE=?sc?>>=,>`P>=$ =>R=>%>a =X*=i?sZ?>>=>_E>ɮ===>t=k>&>c7=Z=p?sU,?>l>= >^3>a=zp=W>;=A$>( c>e[=]o= ?sS?>> =s>](> = =>=w>);>gy=`w=ѫ?sT7?> >)=ؽ>[>˰=Ð=z>>=a>*c>i=b=?sX?>X:>-=9>Z՞>Lq==b>q=>+->k=eV=7?s`?>7>-=>Y>=g=D>B{=c>,>m3=gN=?sl?>>)I=6>Xt>m=)= > =>->oc=j=?sz?>J> v=E>W9>==s>D=->.>qY=mBu=X?s?>>0=>U>n=/=)>i=z>/Ȫ>s&=oz=?sZ?>.>s=}>T/>^=R=/>Gj=ܶ>0K>u=r@=B?s8?>D<>@=.!>S_D>R0=d=I>M=>1z>w=u3=̈}?s}?>">Д=s>R9>ϸ_=g=>>=>2@>yi0=wh=F?s*?>>m=>P>=X=Q>J=p>3>{H=z=?tA?>E>=>OD>m=:X=b>j=8>4>}"=}-=w?t@?> >e=->M>н+= \=>=^>5lW>~=؈=׌?tj?>v>8=d:>Lc>==>=>6F>b=B[=R?t?>N>=>J0>D={=@>=S*>7>F=$=_?t?> >=1>Ie4>}R=!=Ү> ,t=;>7>(e==V?tK?>:>=>Gڮ>Ѯ==^9> = >8>=H=?u5?>`_>X=>FH>:='=5>!)N=>9qD>=!=?upi?>{>~=9>D>=c=a>!=>:,C>=)=V?u>o=X>C ,>~=K=ق>"=>:>~=W =,&?u?>z>=s>Ac>$=;=J>"wy=r>;>f.==?v7?>>/f=+>?>.=t=>"=><7>7-= =?v?>;>`=>=<>1==>#8.=*5><>=n=?v ?> >~=><7>,==wm>#=v >=u>,=C=k?w?>E>2=>:nn>==}>#=>>> >7=-=?ws ?>e>=J>8> =K=>$,=>> >`=3=n?w?>>Q=>6±>=Q=h>$qF=>?$Q>$z==Z0?x&?>1w>-=>4@>K=_p=%>$n=:>?a>=V@>$?x?>>q=>2L>ў==>$=P>@$:>m=>?x?>>=i>1>i=i=>%=[>@>`=">s?yO?>k>}=>>/{>-=b=N7>%Ik=[>A B>2=Y>)?y?>>=>-j>= =v>%p3=P>Auk>M=e>?z)?>CC>u=>*n>Н=^w=>%=:>AU>=a >?zP?>>M=o>(m>I\==8>%S=J>B6>8=Z> ?{~?>>Y=SB>&J>==>%=>B\>==_> =?{?>>5=2>$>ψs=J#=֊>%ͷ=h>Bq>=)> ,?CB7??!h=:̣ =P=<ϲ=>J??!m=ǡ<.<=|=Xi;3>?=N =g<[;Y:H:x; 8;8?1???'=#>~ =SQ=P<`_;%;9;;:L L;x???(=> =W=K<%;;;Eb;:37;7???)=%>i=[,=<;ZZ;;΀;;!0U;q???)>!2>U=`4=i;}?US??*">>!=da=<F;9<;<+c;;Z?(??*>Z>j=h=…= < <6(;|>!l=l,=7=)<xu>%Ӿ=p=m=<&7>) =t=硂=)Ѐ<3(<<_<;;?+??,> r >. Q=xa=/=5 >2=|4==A4<[<9;m?xJ??-B> P>6 =|>K=M<[_<#>9=> a(=YG>=5=r>=eAzd>A`=st>i=pē<43<׬t>Eq=6>+=|'>I*=>!==<<2O< <鵿3>L=>&=F<)is>Pu=S>,5=<_=(<=<;9Z?z??1z8>>T=>1bt=9Jw>W=>6zc=ݍ>[=,>;|=<=`<=]>^o=#>@i=,<=<=`>a=B >EA?=^<1=%@<= ">e=g>J8= <=,$< =" >hb=90>N=<^=2L<=(Z<:\<3??\??4>>k=i>SF=<(V=8g<*=-y<,<???4}>3>nÜ=>W/=<$=>v,<=2<< ?Ç??5Y> >qz=s(>\41=b<ՒS=Dw< +=8?<<>??5s>!.>tR=̮>`=3<2=JlW<==><<;n>v??6( >">w%=>d˼=U<=PT:<=B<<>F??6]>#q>z=i>hD=Х ^??6n>$= >}Ѻ=>m O=E<=[<<m>??7T<>%>V= >q =N<,=a==Ra <<"J)>??7>%>=>t=Vb??8>&qg>=F>x~=_<7=m=ſ=\f<Ϙ<*3>??8u>'L>yQ=k>|='==r= =ar<|<.A>{??8>'Ó>'=>=x>=&=xE=aW=ft=a<2_p>??9/Z>(a>>{=>!=︚==}Ɩ==k\E=<6>RL??9>(K>aK=>==E===p8 = [<:̈>#y??9>)>=#>[= ,= =Q=$=u= D(??:=K>* >d=>M=b= I=&=[=yW=WUZ??:>*>=>> =T=N==~=չ??:>+`>;r=>:>=2C=G="==TpF??;?>+s]>a=>>=b=j=%=M=z??;>+۽>u=`0>D>==u_=)=3=R,<>=9>>=\1==,#=x="҇>??<7!>,>l= s>"> ===/,/>=<>> d== =2O==)??<ը>-1>Y=t>> ,= H=4=5^=#=-S#G??=#>-sk>=Q>>="=*=8hD=P=0ԅR??=o#>->;=1>^j>c=$Ĉ=f=;l=x7=4U\??=>-2>h=>>T8=&*==>lX==7v+??>>. >=S>>=)$=.=Af=J=;Yk<|>|??>K>.0>z9=>ڂ>=+K==D\8==>۴<r>bP??>>.L>X=>b>3=-j5==GL==B^O<>⻧??>>.ag>0=&>>N=/=*=J7==E=???S>.nl>=>>K=1/=q=M'==Id~<>???`>.s>ͺ=>>ʳ=3=z=O]==L???>.q>S=>m>B\=5==Rۆ=p=Pk<>v???f>.g>Pj=>>=7= =U==S4<`g>??@">.V]>=b>> =9h=Nb=X=w=Wt<4G>߆e??@a$>.=R>=>L>!y1=;=u=[Q=)=Z<\>N??@>.>c=%> >"==n=S=^==^~<>޸??@>-c>=k>>$ J=?P==`ܐ=`=bZ<">^??AM>-Ā>1=>f >%g=A+=ī=cl=5=e4<> ??AM>-><7=>>&I=B=>=fS:=*=i`<Һ> ??Ap>-M>̻=0>>'޿=Dk=k=i=x=l<>݃??A>-+>V=c/>>)/=F=1=k==p<#>Kz??A>,>9=>Y>*5=HS=Ԓ=n_X=Or=s<>??B%>,b>W4=q> >+T=J =Ȍ=q==w,O<^>??BX>,Q>ͬ=8>v>,lY=K6=˶ =s==z<>J>s??B6>+$>==p>/>-{=Mj=͝M=v>=d=~<9v??B>+3Z>=>&>.=O>=~=xu= =U<>ܲ??B>*> =,>nZ>/I=P =Xv={c==ܮ??C>*B>fr=>P>0y=RD =,r=}7=EO=kC<(>ܱ??CD#>)N>\=>݈>1h=S6==:=ٶ=/ܽ??Cow>)4> = >>2P=U]=5={b=h==<>-??C>(5>T=>!>3/1=V#=؁=|==<-w>@??CW>(> =>3>4[=X[=<`==s=<̕>??C>'d>=r>:>4=Y=]=.==Dl<>B??D,>&>G=B>7q>5=[>=ݝ=d=g= <|>y??D52>& >7!= >)0>6[=\C=E#==س=ϟ<>ݸ??DX>%P>_x=>0>7=^===C=w<څM>E??D{w>$5>L=>q>7=_`v=P==ͩV=[x<>Pg??D>#>=7>>8h=`X=M=%z==!<᮫>ީ ??D>"N>m=>>9=aj==O`=bv= 4??Di>" >=>@>9=cD=)=v=Ѷ6=u<>s??D>!A>ǂ= >>:-=d!====u<@> ??E> [Z>=>>:=e=$D==L=;`??E0>m$>Ì=?>4P>;3=f=C=ݷ=Վ.=<%>??EI>wQ>=>Y>;f=h===j= <>o??Eb>y>=A>K><>=i8=m ===X<>??EyA>t>=_>/><=jU9==-=1@=X⠔??E&>h+>m=$&>7><=kj=(>=C=[= o=x>E??E>S>G=\> >=5=ly=|>=V=ۀ=9=>??E(>8>i=>X>=]=m==gx=ܟj=,=g>??EE>>=@>I>==n= =u=ݸb=xI=>h??E>c>G=>>> =o} =Q=/=x=@= >/??E>>or=׏>>>@r=pp=>=A=خ== >??E >|Q>)=>>>o=q]N=>===ј= >??F>:]>@=P> >>=rC7===x=[=ˇ?>Ǧ===c:h=Dz==ߟ= b<]<9$=DZ=?>Ci="*=<<=g==Ts=jz=<4<<8p?>y=%4=z;<<Ԏ=&=_<< <H<2J?>v=)%x=fp;<<>@=,X=S =/=?<1<=g<=ލ=>]W=2=,ݾ=={<==3dC=5=f=9a="+<=|E=(~fj=84=y=a^=4<^<{a< ??=;<(=r =G <==Y8w<-at=BQ"=>]J=\;)!< =r;ay<<~R<%];=;RI;A??=TU<6u>=B;p<2=< a;4A<-;dE;LzF;I;qy??=YO'-=Қ<++;>{<1;&J;27;;R??"?=[<`8>/=8g= @A5=<;<X:;9$:ƕ:??)=by=>Ha =3Pb=XF=v+<V<+;(k:x;Hi:D9 ??0=iG=4>` =r<+g>u<J<-<-#<;S;;=:/??5(=mn =Q#>o>><;= v>B8<\=:}> < =)<<;;<;٨;O??;=sN={7>z>`==9>= =Hr<<%<qx;;T]???=vE=#m>>==W<Û<9 <N<n;we??B{=x=>>=/=f^>=!_=uy<œ> ='='>$E+=.N=U=R>'y=4=W= 4@9>*=;Q=d=<5J>.a=AR=:= L>1@=G==&[`<6<@->4d=M=^>=.$n>7}x=S;= m=6~< <<<??T==r>>:\=Y=d=>*<Ȧ<>=Y=_v=e$=F<9=e&>wL>@o=e*==N̺<1<=}<]]<5P??Yk=ը=޸2>>Cs=jś=T=V>FU=pI=ӭ=^u<<CQ>I-F=u==f-<%>K={ C==mҽ=<̞<$<\3??`G==>+>NR=#=6=ud=p=}>Qq='=9N=|0= <<Ճ>T=<='Q=(C=<??d=P>>Z>V====X`ތ>F>YT=&=ñ=x5=a<Х<ҟ[<>??gq =j>>hI>[ߥ= >==@>z>^_=>=M=!<<<%6??j=F> ]>~I>`=->G=)'=%E< k< n>r>c?h=l> ==*$< <6<??l=e> r>XZ>e=> =x=.<j\>.>gf=ȵ>M==3!y<U(>|>j= =>T==7<3>>֯>l{=C>r@==x=< <|=>X>n=>==@w<1=<П??rY*=\>D>P>p؏=v>lD='=Dt==5>~>r=N>]= M=ID=7z= {<,??tl=C>,n>>u =N>;=<=M={A= f<ȅT??ujm=c>>iK>w=x> =e5=Q=Y=M<*??v`=>\>>yF=^>"==VQ= =/1>>{=F>%#=C=Z= = $<ِR??x2=n> Z.>Xm>|7=>'[==^O===!>+>~=s>)(=v=c3=Z=Y<??y=>#$>>K= >+=Ġ^=gun=p=<??z= >$v>>/.=>-8=Ǐ=k5=~=!Z<??{w=j>%~>ŀ> "=>/=u=o"==$#m<??|4=r>&H>P>=>1=RO=t4==&<.??|=Ζ>(!\>$>=)>3?=%]=xKl=z=)S=R??}=>)@>y>J=]>5 ==|t=i=,dm=Tk??~;=7>*S]>B>Np=>79=կ=L=Qh=/M=[??~>=]>+YL>>#=>9v=e=\y= 1R=1= gk??l=,K>,R>맠>b=33>;D==i=" =4Z= x??l=>-?>C>.=b>= =ݶ=t=#=7*=?Z?=sA>-V>\<>=*%>>c@==:g=%Q=9vH=_h??=>.G|>gK>`=7>?===&!=;=4?~t?=e>.>j>=>@0="q==(,=>=?~(?=G>/,>f>0f=J>BC+=;==)=@HP==?} ?=S>/s>[>_=v>C=Q=E=*=B=%?}k?=>>/>H>=>D=c= =,[=D=!͘?}~?==y>0MK>.>^0=2>E=r===-9=G==$?|a?=y>0> >=4>G!=}=Q=/m=Ia.='?|M?="2>0> > =XH>HL==\=0l=K=*ѩ?|S5?=>1,>>/=f>Is#=G=%=1V=M=-?|! ?=>1h>|'>j=f>J==Y=3O=P;=0?{?=o9>1>=/>;}=>K=h==4e=Ri=4"?{m?=Y>1>>r=]>LA=|==5=Tԣ=7P ?{?=E>1>'>Q=Ђ>Mw=}=[=6=W#=:?{3?=>2T>T>L$==>Nq==-}=8I=Yt==?{Q?=_>2*>>=åN>OI={=\=9s=[=A?{>?=|>2;>铔>=M>Q>8==:f=^=Dh?{?= >2F>(">S=c>R>3==<=`w^=G1?{?=B6>2J>*>=ĺ>S>-===^.=b%=K4?{?=>2G>:>= >TJ>'=qB=>?=e2=N?{?=>2=>w>R=X>T>!=T=?=g}=R.?{?=~>2,>.>A=Ş>U> =;=AM=i=U?|+?=}oi>2s> >=ߪ>V>=&#=BZ=ldd=YYY?|^?=|>1_>>J=U>Wϡ> ={=C=na=]?|?=z">1<>b_>=Q>Xm>6==D=qD=`]?|j?=ys>1>!> =Ƃs>Y>=b=F N=s=dz?}*1m>>;=ƭ>ZS> =T=GE=v7W=hK?}~'?=vB>12>Nb>=>[g> ==H=x&=l+?}0]>⌱>=>\E> V=9=I={>H=p?~>?=s>0T>¦>&=>]!> 4==J=}=t?~+?=rr#>0S>#>s=%>]W> ܗ=,=L'=-=x%O? ,?=p>/,> >=5>^>ח=(6=M_=y=|B??=o>/>1:> =@>_>M=A=NN=ȴ=8??P=mW>/>%>C=*8>`R?>=E=O)==F;??N =kҴ>.J%>ܵ><=ƻA>`O>g==Pu=>=$??~=iK>-l>5>0==@s>`>o=ɯ=Q1==??~J=g>,>٧$>U=Ź>a"><=`=Q.=%=T??}r=el(>+J> >='S>aR>PO=q=R=*5='??|4=c2m>*>]D>,=ĉ>axv>=λ=S7=-M=`??| =`>)x>ԡ>=>a{>~A=e=S=.F=??{N=^>(\>t>5=(>a>!= =Tj=-#=??z=\>>'2z>>s =g>a>F=Ӳ*=T=)=~m??y=Y>%<>>@p=S>a>=T=U~=$=p=?=Ÿ;J:>(T >%[=r=C0=/:=;;R;%m?=O;->P>i=u=:v=(:Lp|;;Hlf;\?=wE<1>h>9=g2=14=!:[+;;>yT;Ƚ?> <>u=X=)0l=o:l?%;1;45|;h?>+<-E=ڔ=빑=;w?=F= :~;;~;E?>9m<Ԛ"=ÓY=e=-'=J=:;;V;Ă?>G<==?Q==<[:;;j;?>U =?=.=F=<.<:U;\L:Mp;I?>c`= =}=|E=qm=%=S64=s<邁=3l='?z=pn<M.=B<=PU<e=<7C=^F<:=lY*=l:=y<9<^< e=$jo=9 =;q;b<5S=˒=);;ܴ:j<h<.Q;s;9׆>;/]?>=I=R <#M;;<;%{;P:*F;H?> ==y<:;;x;Ҿ;.;+:j ;#?>I= =<<'l;oS;s;6s;J:;o?>K=J=:==v==#< 7I;&;H;d:zc;?>=6=ʮ=A~<:諏:;RI;:;?>ݸ=:=ݙ2=_1<}E;hԓ:C;[F;;;&c?>s~=‚=P=|U<Σ;%;<'h;e;; ;?>=^,>iZ=[<撴;];P;o!;Uk;2;h?>=%> =?>:=׮>== <,!<K;z;b;X5;z?>_=u>p==#=>%i0=V=".'=Z=-|<~*6D='=8'?V=K=D<^<;I;Ic;n(;G=A=OL<#<;;;;Й?? {=>P>=Z<ʚ<^; ;';C;*??>=L>XX> R)=d<<;Kj;;8;??l>P>`z>u=o)<β8>h'>=zfj>po>Y=y< ;>xB>!=<<O;˙;;;<??> V->5>'|=݌={ >ͤ>-@m={=4=Đ;zL;H<;ܬ??j>>>2R= }= )=5;;<;M??!>>E>8P= =={%;֎;|< +;x5??#W>D(>>>g===U`;3 ;H<<2??%>f4>>Cj==t1=.;u;6<<<rl??(>~>G>H=H=$AB=#;H;D|<C<t??*"!>>e>MF==)=)<;t"<$< K??,,z>B> q>S=?!=/=0;<;<*G< ??..>>sk>X&Z==5E=7< ;7<1Q<??0&> w>T>] =I=:=>c<;d<7F<??2>"\>*>a==@K=E94<;~<>k<??3>$7z>Y>f·=ơ=E=L <7;T&>>ks==K=R<qF;K'΁>C>p ==PX=Y<;c)>>t=ـ=U=`D<$X;ʝ2+<>O>xA=%=Z=gY<(z;<`<+*??<>,>Ի>}R=c=_=n*<,=;sn>.g>>Ȑ==d==te<1w;0>\>[===i+={<6 ;1E>>=ʝ=n=Ly<:;x<}D<3o>K>==s=4k>>=ɗ=xR=V59>ʸ>=1=}*=7^>[>===8J>>b=_==Lz:>z\>&J>:=a=;C>>z>=N=<\<<{>d>8>,=̥={p=D>Q>,>==߸>>>X>LD==C?,>bE>L> =/@=8@[>>ˬ> =?= pA\>>?)> p1=G=mN<| <kd<<L??U+>B.>->3>=G=< <ë<%C>V>>=?k=1<Ү<,<<??W\>DJ>n>T>Uv=.=<< E>t>>L===Fz>h>>v*==VVGB>J>>==<:<+v2HW>>&>{=Q=z<(>H>]>>>=`=w<<2I]I>>KJ>d==3<<6I}>>LF>=m=6<j<:ɗJ>]>A>1/==ҕ<*<>< KZ>>+>R='Q=#<>K>q> >=i=RiL>>ݷ>!0=YD=ܰT<}L>Q>s>"w== <L>G>a>#?=jD=k<M9>e>>$=j=<gM?8>>&#=ZS=$yM5?9>Q>'OV==퀠<N?ͩ>]>(s=)q=l<N3?[>cf>)A==7NX?>>*=ל=<`Ns?bO>G>+R="X=<[Nj?>>,=d=H<ȉN?Og>>-=><<}'=DN=?%>F>.6=>}<ρ<Nya?"Z>#>/=>*< NaW?>>0=u> <֙+N??*>s>1q=5>Z<0N?->m>2aB=F> /|<ϗ<~h= oW<??g >M%?y> >39=O> qMb?_> >4 =PM> 8<$MPr?_> >4=H>2<.<(=(;LT?6>>5=8>?<+L?h>ۓ>6R= ><^< =.=[??gY>L2?(>>7=^>4<,S<ڧ=0=??g>K?>~>7=>v<~<=3=??g}">KA ?W>?>8].=ɦ>.J?!>>8W=m>4<J&?b>w>9=,>=װ=j5??f>Is? >;~>:(=$>G=Ѻ=?"=#??f5>H?J>>: =̑c>3J=ϢH3'? >U2>;8]=7e> =gGx;?>>;=,> = <| =G5=#??et>F"?>A><,=j>"0C= <=J!=5??eD>E?ޮ>><=>#ْ= E d?0>3>==}>%=<=P= ]??d^>D&?*>M>=e=>'+=5<=S0=#??c_>C8?u>>= =n>(l=-)B@?E>y>>=>*}=I<Ƒ=Zx=(q??bÕ>A>?>>>`;=>>,%q=jm?>=>Du>͉= 6=M<* #<$Հ;k?>~=L=y> ʊ=?=XD===H>k===><<T;B1 ?>?P=f==G=P/=i&=@=S<< ;-u}?>y=<׺<\====|c;;N;iQ?> };]:=/==e=|;p;B:0?>AlMY=v<ʮ=}#=ӟ=f=Zy;;%r:%?>DN=M=Z=S _=+*=PQ=Jc;;̴:3ݯ?>&S==/=)=gSk=;f=:;1`;x9?>q==\ث=='<=.7)==;S;9>?>O==<4=< = 4Q;a~;i4:2 ?>ݩ>=5:<*<ΚG<i;>0;H:I?>Wt>"=dj< Ml<|>4=O<]<~t >F<=W>+&=;"s;Uh> 9=?U;:1Y<99:8;9%q?? >y}>%=eN<({;ͅ;9j8Q;QG?? ?>`>=n<@<;Q:REt9l;i^??>;>(h=o>2=`h<<;>4:*2:;wz??~>>;`=Y=<` ;дv;B:4;??ӱ>>D==': >M=@=?/=uEr>V=͘=W=<;;[ >; m??$>h>_>=o7w=%la<;;{";??'h>K>hqx> %=@=7<ˍ;G9;;??*>́>q->==H>y|>==Ye3L>>#>u=KX=j=oa;fi;2<ׇ??4>e2>>+h=W={=R;;ͤ<??7r>}9>>3w=>=@F= .;(^;ݠ<Z1??9>{a>7>;m+=C=}=,a<;;횝<0??_>P>CH=ИJ=>=9z<v;'<???>*>]>K = 1=W=Em<(<<#??B?mX>y]>Rv=Y==Qs< P<z<* ??EM?>+N>Z>==r=]\<)<7<1??H ? >0>a2=-=02=i|><2Bn< <89L??J? (>\>i >L==u7<:<& ڽ>pJ>=^O=f{Hd>wp/> Q= =>~{|> =&;=kg>b>|=c=XL<]҅*>">5==AS>>=钄=Gl><>"L==r>>&n_=Z=/<_~h>N_>*T==$-<M>>x>.*>^=H<o >c>2>=Z<~<~<"??g?.8>>>7g>}=Z(˓>9>:> @=G"3A>>>>'5=!<:<<??nY?5>>>B>9X=<<#<??pg?8]>>>f>Fe>>=Ξժ]>5>JL>7$=A<$<<;??td'?<>>>M>"=<9M>>Q%>=O<<<??x7n?Aa>܅N>S>TP> |=< <Ȋ<??z?C>ޫw>T>W>#=b*>{>[7>&P=YJ<ݾ`>>^lm>(=팏>o.>a>+G=.<ƶ[<D>x>c>-q=M>##>e&>.Ԙ=K<3>4>f>0-=gq<}y>}#>>4>g>1{= <Ӗ<4/I>?)>iL>2=ۤ<֯>8>j>3=<ɻ<üw<),?v ??M> >)2>k>5/> <<ƀ*>>lJ>6Zp>2<A>>n>7|> < ^< j<.?rU&??Nǿ>O[>>o+>8>QU>Ȥ>p3.>9>T >qw>q/>:>J>8;>r>;>n<<7.9>>s><>e<1<< ?m??PK> >˲>s>>=><<<^?l,P??P>1>f>t>>> V8>>us>?|> &dz>ͼ>v.>@\> <qT>_W>v>A7f> =>2>>>wf>B > y=1<:=r=?h7??Qv>>ϓ>x!>B > 6=<(k=Y*?g??Q >>%>x>Cx> ~=<=F?f??Q>I>в>y=>De#>=9<=:?fQ??Qy>z>:9>yf>E",>S= <T= 6?e??Q>>Ѽ>z3>Eٱ>= <B= 8e?e=??Q>>:g>zv>F>= e<'= B,?d??Q>>ҳ>{>G8>L!=&==S?dO??Q>0q>&>{^>GF>i=%=w=l?cd??Q>D>Ӗ>{>H>=i==V=R?cQ??Q>$q>h>{X>I V>!==g=!?c/Y??Q>>f%>|7>I>1=^p=m=?bm??Q>>L>|n+>JL>I =9= =%?b??Q,>Xp>#>|>J۱>v== =j?b`??Q>߯Z>| >|U>Ke>b== Y=?b-??Qb>A>ϴ>|>K>V== =!R?b??Q7>E >>|>Ll>n===#r3?ad??Qh>݃>i>|>LS>X=!=t.=%x?a/??QA;>ܹ>ְ[>|!>Maq>n=#ޝ=3,=(Uv?a??Q[>>>|Y>M&>=%n=H=*׃?a??P> >0m>|>ND|>b@='=ÿ=-d?aI??P>)r>j>|>N~>ך=*==/6?a??Pu>=>ןP>|0>O4>J=,0y=n=2?a??P7>G>W>|y^>Ox>=.YY=N=5U?a??O>I0>>|Dd>O>&s=0=6P=8n?b??O2>AF>%>|/>P0>y=2=%|=:?bM??O]>/>I>{>P>=5 =!==?b??O >>i>{m>PX>\W=7X=#=@?b??N >f>؅J>{B>Q%>A=9F=%$%=C6?c??NWd>>؜>z'>Qo&>=< ='5"=F?cl??Mz>І:>د>zAH>QQ>z/=>=)Of=I?c#??M2>A>ؾ>y>QV>@=@=+sJ=L?d7;??M!r>W>:>yG>R21>+=C~=--=PD?di??L>̗>>x>Rj>=F=/q=S\?e)??L7>1>)>x%>Rd>=H=2|=V?e??KB>ɿ>>w >Rϳ>#=KX=4j=Z%?fF(??K5y>A>>v+>R>pn=N1=6Ē=]?fp??J>ƶ>طf>v!I>S#>W=P =9*=a:?g??J}>>ئ#>u_'>SG,>=S=;=dD?hBX??I>z>ؐ>t>Sfg>I=V=>|=hg?it??H>ȏ>u0>s!>SE>,=Yg=@=lx?iX??HD>5>UV>rҰ>S>)=\=CD=pe?jN??Ge>9Y>0s>q>S> =_i=E=tjA?< B>K#P=y= = @= 4?==g=b===w=<6f<?=>0A=n==i#=О=V=<;==|s=&\<:= << !?=> ][=h[=i =(??=i==Y=}=<;=F[;D;֌T?=Ɉ=n=>0{=P=# Q<Ȋ=W<=,D;@;D?> zr=!v=1l<=C,`+<<8<=.<_=V;`I;̳?>-#<'\;h0|;W;3;%<)3< O<";;x ?>8<:v;@}< <<:;\E?>Ai<;.:\I=<0F;$/<:_,;"?>QB=JZ=vY<)b=cj8=P= <+;2;9;\::/V?>qݶ===$ <ň,<:@;;8?>yt=)=;Ⱥ<9==Rč=Id=Z=iy=<;;v%;e:?>>==<֓B;<5;8>;?>>=l=*ϔ<6;f;kz>,==8y= < ѳ>$=]=Fa=r<#<;?^;k?>[>.E5=m=Sw=/p<3k< ;;^?>>7==a==@q>AY6=V =ng =Pe\`>J=ʕ={b=`"*>S-=԰==p$<<<C;m?>t>]'=ި=h=71>f4=}==)>o%q=.=A=<=ql<;a< +?>>w==3=d<1=$j P>Zj>=X=,S>q>7==a +>> =l<=]<=A;>>H==<ʂ=K%?>>C?>V==([>Z>=:=;<3<=]Х<Ů>dc>^=Ħh=5<==f`<<`?>p>`$>! ==<+=pQ<0f%>N>%=:=<%=xx>.>)h=b=ޖ<=j<^<"?>k>>-y=s=2#=@=94<<-?>>[>1=n=뵂==>z>5u=Q=!= =<R>#0>9{a=e=t==2<by>>=8=V=T=F=g@>J>@=sy>j==<<~B?>>X>D}=>p=="<F<?>Y>:N>H=mZ>j=%=<6<?>W>ŝb>K|?=> X1=#ñ=I<<,?>>>N>>:Y='3=>9>R3>>=+n=}<.<Ȫd?>>sZ>Ut>>=/5=2<]8<υ?>9>Ҟ>Xu>>(=2=<>ռ>[9> >K=6=pl>g>^F> >=:L.=Fv>U>aț> bm>~==v=q >a>d9>4>!=A~=< E<?>mj>ᨌ>g >]>#=E=7+T>>jMP>>&[=H=Ʉ^<@)=?>>K>>m>f>(=K6=(=2=?> >>o> D>*=OkN= =“=I?>>m>r2>o>-0=R\= =7= ~?>A>W2>t>23>/w=V%`="&= n=?>'M>>w>>1=Ys[=$\= GH=h??M|>o>yxh>+>3=\L=="=??#><>{>>6=_3==f=P??>O~>} >D>8=c!=ў=Y=??U>>f> L>:'=fF=?==#8??>]>i>!f><&\=ib=O= ='l???>>"]>>=lto===+ ??&?4>>$>@=o|%==!v=/T???F>P>%->A܀=ry==$b =4 ??=q?Q>>&H>C=umv=='O=8U:???U>Ơ>'Y:>Eo=xW=<=*?X=<??;?R>~>(^1>G'*={6=e=-1d=@!??W?I>g>)W>H=~ %==0%=E-?? ?8W>*>*E>Jr=k==3F=I??W? >>+(>L[=̊='U=6=M??? >d>, >M4=(?=J=95=R[??J? f>>>,>O =~>=< =VӞ??o? >ޱ>->Pz=Й>=? /=[T??? |g>u>.A>Q=?>=B=_߂?? >.>S6-=d>*=E7=ds?? ? >>/>TQ=}>R=H=if?? ? ^>>0>Uƒ=>q=K"J=m?? ?i$>xp>0e>V=>NK=N-9=riI?? (?>>1 >X=Q4>$=Q:j=w#z?? T?>D>1R>Y;u=>z=TI={,?? yt?Q>>1>ZK=A>f=W[=Z.?? ?>>2P>[Pa=> x=Zo=Ň?? ?t>4>26>\H=;> 0=]=5?? `?>s>2_>]5=> y=`Q=x?? ?|B>t>3">^2=!> =c=$?? d?>>3F>^=-> ,J=f=h?? מ?g>>3gu>_=8> Ɔ=ig=%?? Ѩ?6>>3}>`p=?V> YP=m=X?? ł?7>%>3.>a!q=@> =p:=9?? ,?'>.>3>af== >h=s`=H?? ?>/>3yN>b_j=4_>=v0=a`?? {?;U>&p>3aD>b}=&>Y=y=8?? W ?>>3=>cm=>Ǎ=|=?? +?>>3>c=<>-==@'?? ?>ב>2Կ>dL=|>P==??? =?4k>>2>d^=>=:h=?? ?aW>v>2>>d=>3I=]=I?? A?S>8>1>e@(=k>{=qs=???^>d>1y>ey=:L>x==???x>>1>e.=t>==}??Q&?Ϣ>J>0>e=ɗ>'=L=C???>>/>ep=>Rc== ???%>>/hm>e'=D>ux==??(?}> >.ǖ>e=>=1=???>>.X>e=>H=ջ=g??Dc?\> Q>-c>e=W>=z=f???>~>,>e=>O=!"=H??G,?y>>+8>ee=>'=Ȉ=/?= <%<;E;R;,S:; ?> E<@<@<1Z;>;:J;m?><~ a<<^;<`=;͎;^U;?;;Y?>5<$U<]O<{^<;);4B;wI;% ?>!k<،<<<;a8;ɜ;!x;*RG?>$w%<1< 'w<̉<&<;;he;2*;3?>*m1<%<47-X<<4< e;<;CK;>[?>08=<'<;<ƞ;L;Ca?>3 7=lJ< <<<;Tu;I|.?>5כ= <82=R<;K===$s<"=h<<,;vZO;a?>@=S<=<<3ԁ;~ر;h?>C){=!U<^&= <%y <:;;oK{?>E =&;y<-=<+>?>H1=*J=.)<="<6ӎM=3&<7_=$<<Om3=7ka<=$Q=;1<=)T q=?"==-VGZ=D6==2NXzu=HMl=/=7}VZ=Ly= 9a=<8<_<9;i;D?>\?=P?=<=@^=T=9Z=E`=X=/z=J#b=\}==Nd'=a==S0r<}^t<L;;r?>f=e=g=W< <;?;Nr?>hD=i'=;=\<<#H;̒&;A?>j`=m-X="|=`k+<<;a;L?>l''=q-=%j*=dmc=u)=(2E=i'<<;ُ;Ω?>o=y d=*=m<<q;p=}W=-=qjrA==0c$=udthC=s=3=y<#<;;T?>uw=e=5/=}<<4;I;/?>wi=T=8X=_xt=A=:=<<;;א?>z@<=+==q=ý<4<;_;?>{6==@a=<<ħw<_B<?>|b=`=B=< a~0=t=E={<`<˷<<!Z?>kN==G=W<2<><< LH?>M=O=Jd=.7=w=Lqu=<ŗ?>m=Pn=N=:='W=Q5=w==S6=L<<ݖ<<*?>==U=kQ=y=X+.=_=j=Zo=e<J=5e=\= <4E==^S=u=Ö=a9=I<o==c@=ߔ<קƗ=H =edM=oQ<<<#<7?>9==gz=+<=<<%<;}?>du==i=}$<(=<(I=||=k=:=3=m=so< =}<,M(==oq=<긐==<._Y==q=R2<=m<0=K=s{=< m= <33Y`==u=n==w~9=t8<=;$<7<[?>=LY=y`<=!e=={;=(<o=<<&5=i=}=aL==v<>dFc=7=~==?J=5<@Q=ֽ=SD==G=W=sA=3=o==X[= V==K =!=n`S=Ť==v==+IR=:4=== gF=9==>== H=$=]V=e`=֫= =!bh >=@=29==U=#i=v==/= =$%,====X=&2=Іg= =+=K^=(S j~= =D==2=*<[M5 =ӌV='===+<^<=?>3= =F==HB=-G<`H=ֈ=p=Ӌ==/@DtK=="=Ÿ==0 )<={==Ɨ=La=2==}=qN==4o=c=&=D=!z=6*'=w==f=#W=7<9s/< R=ە= {<~<29;g;Z-;X?>Z= <~=<=!<$1=(cV<1)b_=/<ܴ<^;;7;~R4?>.(*=6t<22ܓ=>.<7=ES<g;F; ?><>=Lil<<`S;;S;?>@=So<$?>E`=ZfE<-QI]=aM<3M=h%i<8<3;4;;y?>Q=n<:UV=u<:< w;;;?>Z%=|Pl<8^,=uI<5'<ٙ;;o;}?>b!=; ?>f=K<'i=.;<m=\s<=(<;$;~?>qH=<=(<A;,;?>t=<5="< ;zT;˫?>xs={@=4Y\=Y ==<}=z<;E$;Z?>=)=W=m<,f='c<";۪;?>4y=[< S=*z<%;;?>=-v=s=."<(T<[X;l?>3=i=`=2[<+<<?>==K=6&<.<V3<$?>)=t*=6=:]<1<<ؠ<-?>6=&= =>3o<4< ^d<R?>Y== =B<7< }< 4?>h=ur= =E<:<s< ?>==z=I<><<@?>5q=ǥ=X=M|<@<<R?>_l=1N=3=QK=̵= =UO=2=i=X6=ѧ=K=\Om="=,=`xY=z= P=d?===h"=/==kvZ=}=!=o0<[$<-X<,?>R=^=#h=sP<^<0 5<._?>%*=y=%\'=w=:='5=zω4=j=)=~<7|?>j0=蒃=*T=$z==,==N=.=ޤ`=!=0gg=3=>=2;===4 =pG =T=5b=J<{z=M=7=#<~U"==9=x<c==;ND=<}=y===R=M=>w=8<o> ;=@ =U>=B~=*x<<`F>=DH/=<T->3=F=[>|z=GG={>N=I=vb>u=KdS=G<\>*=M(= <>=NU=>r=P=<>1$=RpK=*<*\>l=T0=R<<~<?>$> =U6=<<q> Wi=W=H> =Yl=M<=<> =[(= ܵ> Z=\=L> =^R=c<M> c=`W=<\]>;=b=3>b=ct=m<< <?>6W>i=e}=3z<<<~?>>=g3(=6P>=h~=:<<<4d?>О>=j=‚<>G>a=lM!=F>=mn=::CA?<_<: V:2;=ai:U2%?<X~: ?;ĩ;f:̫97;?h:;j?<;q@:WB:?%;@S:?jr<v;;?=в=C.=B<{a\=D<m=G<8<|<;ܾ?>u=I2#u$=KS<)<<bf;S?>k=MiY=OtM<;3<<#;U?>>=Qs.<<<'T;N?>{=SfxA=UN, L=W*I< |=X< 65=Z =\y<;\< <<<W?> 6=^&<V .=_< P=a_<SG=b؃=dj<7<%U=e<<=gF<9<3=h<<<[m<?>1=i<ǧ <<_'<-?>=k99<ʋ<@=ls=mc<_B=n=o3,=p<8<R/=q<1<ٽ<}c<;@?>n=r=s<0;<h<-< J?>=t<4<%=ur<<=v8zn=vb=wB =xD<=xܚ<1<7R<(<.w?>=yh=y<h=z]=}<.<<3 ?>X=zH=[n={$=<<<7O?>i={w=>O<5k={=nS={=rO=Ҍ<-<=m?>=|'= ==|K= ]=7#<#r=|c= M=<< =|pf=w=< =|qd=(= _- B=|f=8= <3 U=|P== ڤ n=|.==< #=|z=3=_?;,;6kw??<ϲ<,;A;0z;??<'<1b;;\;17i;AI%?<ڗ<6 ;-;2u;B'?<<:; ;3-;D?<; 2;Y ;^S?=#<;;]I^;`s?=_t<;.;e;d>?=!7<N;*;i;g?=$O ?=Y<;;G;?=[.;0;u;H?=bl<ʨ;;i;?=e+2<U;D;p?;F?=gq<~(;Xx;Έ;X?=i;?=pt><-<;ߟ;?=r<ۚ<;%;?=t<(<|;|;l?=w<;; ?=;=;暙?==W]Y;W?= A^:=;\;?= ];i;5;|s?<>U;(t;;?<;I7;6;?<-;j_;;t???<~c;Γ);!?>-<;S; ?>?r<(m;)3; ?> Gc E<;;h6?>:f<;(; ?>%x<|;Ւ9;?>޺<ȱc;;_?><;P4;?>q|< S;;+?>!,m<3;b;u`?>#ݾ&n)#<ۊ;;]?>+<ޝ;v;a{?>.B<;;T?>03;<;v;.5?>5p8 :ho<;ﳴ;I{?><<;0;?>?<;;ܣ?>A>CrE|<-;;z?>Gk=:;;k?>Iպ=m<k;eD?>Ki=s<9;g?>Mx=9f<;r?>O=<#B;a?>Qҵ=<!;?>S= Y< };?>Ur= < :; ?>Wk`= < (;,?>Y5= c<N;l?>Z]=<;A?>\k= #<O;?>^Z=X<*;^?>_=<;?>a=<;,?>c)a=6n<&<O?>dO={<H<+?>f-=o<<?>gI=i V=<<#O<c?>jk=x!<%<?>k=&<'{<?>m=<*B< _P?>nSI=<,%< ?>o6= Mp=!|<1< ?>q/="<4<?>s;=#<6N<Z?>t=$<9EE<͏?>us=&!n<;<D?>v='D{<><?>w+=(ex=)Cxb=*y=+Hz=,"{U=-|O=.|z=0 }o=1~=2<[9<$\?>~;=3$<^<&,?>1=4*=5.-=6.O=7-a(=8)b(x<;0?=@?=%<<Y?=/<"q<i?=<!"=4<-?>e=7gK<?>c=9<?>@==><?> =A =D=<Ӝ?> HN=F<?>=IV@<?>=K<?>=N-=Q]<*?>fx=T<3?>D~=V`<?>&?=Y =\du<'?>=_4=b <?>!ҏ=d #=g<?>%=j'=mh)=p?=an%k=?>="?>D = =?>= ?>k=?> ?=k?> =?> 8=b?> 4=?>w=~Y?>=?>=!?>gi=$lx?>9='#x?>W=)?>k=,?>~=/Y?>φ=2Z?>=5??> <=8-?>!s=;$?>#=>$?>%qB=A.?>'2=D@?>(I=G\%?>*=J?=?=?=@?=m?=?=3?=~?={?=xR?=u9w?=rB?=om?=l?=j)/?=g?=el ?=c@8?=a6:?=_N?=]?=[??=Z`?=X?=W?=V?=UC?=T?=T?=SC?=S C?=R?=R?=R|@?=R?=Rļ?=S?=S?=T/6?=T?=U?=V-?=W*?=Y/?=Z?=\?=]p?=_?=a~?=ca?=e?=h?=j?=m?=o?=r?=uc?=x?=|*?=fN?=t?=G ?=*[?=?=#?=9?=`?=?=?=;<?=?=!r?=?=KR?=?=?=?=j?=\ ?=^?=r?=z?=?=?=k&?=ӊ?=L?=?=r6?=D?==?=ة ?=܇?=w?=xI?=?=O?=߱?=#?=y6?=X?>+3?>o.?>?>?> m?> Ӳ?>A?>?>7?>?>O?>5?>;?>!2?>#?>& ?>)a?>,-7?>/?>17?>4?>7 ?>:?>=?>@;?>C5?>Fϥ?>Inyquist-3.05/lib/piano/rls44100.pcm0000644000175000000620000015517010144436365015750 0ustar stevestaff|vztpknkiikoci_e]X`Z`ifqqnklelh]fech]``ZWRRLNLNLMUQPX[Z]W[RRJGDFJILLMMC>6.!"""    ("66@M=IJAAAABFFU[_feqnttrv||zebceZaefhihl]cVLIACGRfwskgb]UJC83%(" +85>OLa]kf_[XIF>FDITUW[ZXXIOTOOLC@GOU_n}sc`]]^^elhpkpzwuiSD* jVCHCQbp~u^C/ -8=AF@LJd(Ln4H\z  qH1SoulXMKJJGVdtrH:9>a{]E<:-6&# #?b'!77* wogfm$<5$v`Y?+zD/`(L' ATftqi]OJ<50*'(a&a,5C7$UA pK&oM6+.QwZ<fvwztyBi*Zxs`QC),Lp-B3a{}p_WF8)xaI}7q W 1 5 F  W p # f '^|h) @mpWJ]IbjujqzDg{W?{N]I1)#\t;%A|d sqPx3,X:P9[agl r=g5 G   VS.{B1BdVZ&B ZtDDo!KQdN)n8Cuq .%e3=+&(j_uC46iG+AW_L8*"JrsNCWdaq*YYcM$kj%t=.bg,le6!L{mx+=-x"A%`` w[juK)JnN-CQcZe " g  f n   l 88}4| TF*LfqcE{oE[bFPwNq6Ta'h"S d/BT%/\4nb*P hD+EMfw(C*RA  rXfG)9B(6DdqB6!C7>m!JT)C4_(^7BF8r3~Fh7L )sad$GX@4+C}G aoudA% |uf(B+\+]c!vSg\+Eb>mkwvJ{ElD +XYg ^^ ? 3 |T2hpT!g\U7>/ :  , H M H @ 4 ? [ /: ~ ' _ Y L)\q/{qthgmV'ChWgBu2TEXo; :mFDTm^r,[EVk(`yhwa n  )u`-+E,+Q1 j j qT\@[=9tI T#]bnߣR`]9 ~ustvP`1$ -3&[y]unUd w5!k$'*%,t.\/01111\0/.-z,*n('%s#"!kEYq >gh*wK k6L ni;  3 > = )0 r A ~4"Z~ ]{)&n 8;\ߞ:t͕ȃ|sÒ§`w'Ÿ&_̧lѢҌ՟!ۆߓ'Mw= `\:$+2@7;>q?D>>$=x<;`963B.* $.-<- LqAX &\n#:}$6^`a޿ܲZO~هӘЯfɾ#Ɍg5CҨр6~ɰ^7OzȤȖKǐpP'x@Zо!; uMXN'&aDv$ :.84!$'[),T.035I79;=@>~?[?@=@ABDGILjNPQQQOMLIHF7D8A?;7^2-z(D#S~^T% iR . TkyI{O9u{3tqtvCw=xmY + \LH3fd[KF l4*By zR*]{g skE 2,4 eJh2"%' (}),)2(m'%." OUx:~IH !"E#$&O'()y*E+ +,-`-.#-,*'#d| c$5wqaXJ ;X.W*s)xL'&ps_2 G ; 2 fk!%')h*+o+,C,. /147j:2<>?@A0A@A@@@d?>=;y85I1=,(Q#eM sSdؚ@Ħ2ٯ!`s-$x4=?Ռk$䇪ƅńڅ8|+? i#[ 9(ʣ͑H,b9   N# %(+.p024a505K4321/.t-z,,++'*)(}&%+#,!  1TX !y.Pcd{Eٍ20fٖ٦n ؝!׽r,?׬gsߞ:U5%Ok u h}u v>k [6p-.jN:<#Z "/WQx-| g z I m\_7*QF7`YB<Ni-G3s f FTk w ` ] ,4Fwg.ufO A K E Y FZ`h#y& M>>M8 B +$)InqCTa5.wIpcP"0  $bh%pB!0$ &)+-/ 0.123;46w8:<>?@z@@?M>K=H%s/.f Xx-Q%d I aO"z7g' "$"&$()+j,.Y/1724#567777o6c53l103.-,,+N*)('&F$#\! URI%QhT{\& $\d2iZI r56`٬*4ϖfŻ–->f zUɰ̚ӊPp~:0`ab83\P p۩ۑ܂jޏjP+l/N\l+9V| lݤo3{ Giva KO\v3 "{<~>0Ln#n(OL&-m7$ 5:#U|KllRF Y n 68nt`cn֯u=ǮN&YǽTDi5âT^wpѿa- !jx gM %X).E2\619<<9742L0-+x)E'%#!czF9<@HRV^w!_7w9g7'< "G$L&)+.g0315678L89"9n9:D:;7;;;;F:v9[7694Y2h0l.a,K**'%# _!z !G@X{IR׸ eAz1 սŻйѷ7A-u&5&E^geJ,AeBM fЬ:FPfvBOP Q&~lDo+6@4 8"7"Sיp͐U&4qľAۻ ^rC輡VpֿBn –àĴṯ+|vܬnx 7[^>q  !<%>ik;y7qn& ! ep%+1qR{^k4 NW-:oN,Mm*E.%>x8TR\WC ߝݨ׻ՃЕěOW,7xg֣n' ;|ǩlޭGIkշ1xܽN“ħxԟ׍xV,  .;}s!#~%')+-l.0111110"/ -,+=)('w&O$#" W|xu}.d 7 V7@I&^}لIa֓֍G Uݳ"Y/&2CZdZ8 n\%!<#$v%u&&H&4%%S$$#B"x! pvYI D ^5(V@Hw-=L YNޒ6ڑv؊֞DբvnՉ`J|  R%:"`uEfbUd\pݲ(ܯ(ݸޔߣq&1ZFW5 ^ p{ "s#% &&'('o'''''''''''d'&&3%%\%$$$% %7%Q%\%V%1$$$8##_#""S"!!!!l!X!8!! x _ : ~Dhb<J ` !D!"1"#$&#'),Q.14u7V:$-;/8F5n20-+1(&$v"Q 78aE   E o   3g`=Y\0/@[r G!5$(S,/37;?CGKP'TRXu\`qd=gk npsWuwybz|W}~WQ~u}M{ywurp m ifUb_ [IWrSOL HID@=7952j.+(%#b!fM(y !"a#%S&(*,.13%5<7+8:u;<=>t>?+?;?>=<;:786431/ ,*(o%# dL h55ekkZ1nL{+Gi@$}12No/L|8x0mq%;ZNM/ X }/$| t!!U!c!$ @wtvw  `D"MݼڥקԯKÃTжn7;zլ8CE򩣩Z,3n;7~'G (xdWxؿ^G˻Q^d ! R +   #PDRx>ڀTeԤѪqjΑ>̾Qˎ6Rɫz3H9 Q۲]حAND喜Տb WL"uHӔ{)>ņٍ#&/" ?s:On&ןU ʐb_ӼzgH6sʹ[R3gJZ 9UdV+H]k"2{r'3 +W}xDSl|/RM׽֒Ձԋӣ1Ѳ7y*ϝSx(͞I̹p@ ˺˶*ą|ϣЛѻ t׻ٯۼJA2gU Y   "$&(z*I,-/801234@45Q566X6666666O55_443o211 0D/8.,+S)(&W$"  OXU e 6 @ B 8g)~, & `CR4$#!'#L%_'s)+-/135796:@)ALBfCDE}FrGWH#HIxJ JKK|KLYLLLLLLgKK J$HG|EDB?=;/86631.,)'O%# !"rb\} I!#%')+-/y1R346>789:;,{?w~!9Xܐdٽ؂zִnG>Z֕a؝`  AB 4Ws-w'oeqj3rk;.})FQLE)  j os+l4~uQݸ۫ٛ׮.Ҡ0΍nSShɒu "{$-%'#(m)*t+J+,- -n-..Y.../'/Q//0 0L0001(1d1112/2x22333"322m11^0//.&-(,$+ )('&F$#" "~J29Ee.8?7c!x "#n$%'+([)k*w+r,j-d.J/3001234x5O6678m919:;s<(<=>6>?z@@AAABBABMBDBAAm@@Z?>>'=9"! 5sEx/5ZH/>+SrjJ9Nv.X+1tj/}^ L !+!|!""/"H"J"E"B"#!!!w!( j ,o 2] !+  A d'/x*/q#eA rR=.4Ibkwm  9 r Y|G[ !;"M#`$W%4& &'(d) )*U*+K++,$,8,=,I,R,L,F,F,=,'+++{+#**6))(g'&%$#"!L px$U   [ 0:x7 6r/ O , _  F % F U W G 0  Y 4  " |T6YleW7+ f2;3],@uץ|ՇԵ2ҏщ Ф'r*Φo3ͯe!̷~X7&'&!/,&˧ˆ^>%%"6V˅d̿'͏qgk ю'ҷ8ӷdԙԾԸԐ^ҭ4ѥ ]ϔ4WɉȸLƝa2î,o&*a¬dCĴ1žNbUȺ_ɠ+mʞ1}P̕ZͦEΎ#gϫ/qк oKLi~֐׉wqoLۭ`ܮ6wVީc<2>JNpgcDNMk|}fT>$Qda#q3}t_#vA܍:ڰ)o*ؠp=)!Kؒ~6D~@zV f  Fq =p!J"$&b()+E,.^/1o24Y57)89;;<=? @ A'BBCDD|DE E(E9E=g;:S8745421/p-,:*('%%l#"\ B~2>"u'g5!"#E$q%&( )%*A+H,I-B.7/$00123>34l4525v55555555555G444433B22100"/b.-,,+,*E)p(''&I%u$#"! )D[dhB~+i W ( e z$`mLId/+h?39:ZwfX4#,/:DRm P;  <dlC@tm#e^Wo% U[xc- g =    % K ;t\Ig P!4g&O,s 5n%B[g^XB( lDbf 9~$x:_1 n;r</ Z8> ~\  P >n1JsTzG'!qm]0b/[R!{T9*5<(x,z3Dr f1 `.pCx ߽C7ݟjV?Iع/׉I՚MӺ-ҮIѭрO;llD~];# D  6 TQ6nG0x,yiJHd0eaB:GPx/x!`pGjZUQQZamtx xe;8z f  u*x R#Z - V )i^Ib3GhVL>::FMh0Z|`3b!{!hr>Yn\.c%V{5 fDW/iv0m&,3,x yx^+^S r4p6aK=9@EKTe{$m ^uOG]_^ZS&Qku~nGeT SolGI \;#[RsL&}2Wh+qPY|*<?iA v c W:>m89RBIyy@#s7=i|}|pV6 "T5Ge,JlOQfHVt2m$S (Pz ;m0G!Bb%U.u/vZ&u/Ul)O# "@f#U W?'2 s X :! \+IE%Pb(%g - b N o[6&<hx=`+~ZN!df+ T ! !`!!":"l""##!#O#s#####$$$$"$$$####K#"""F"!!i! p ckk ESK.(~i@L` l " m  R+tIMML0'p*ngIRaF  i 6 x Q  l  WG,{B~+bwa>0>;>MKUPJ*hR:!^,c0]$ ^ O  Q  V +.i9 LeG[N9JNx Ip'7(N |_V3SEpv gCuT,i1fD0  $;eB#@P^\bYW\eosxg]PI=QWbjV2{G|cF>3!S&gU4ycNLB80<@DQbkAa:\$e;I(rhiad^\:! vS!Jh6#X[%5G8&.D@;^G[p!w&N]:g3Myux=t7i5WrSG4Mm 06:;GJLRINFDDA8>AS_,Q"wJN(Hj3Wkz1rK " N + x$e {<T[%.!  v !A!!" "^""#)#b##$#$g$$$$$$$s$R$%####b#)""""y"H"!!!!`!+ s : Bi; vF NqJ\@)gSQSnAtIo)5n)8O L Z j g `CIz;/tHah#X3|W;( 9Ri%[voJ:xK%`qE-m@~4+r%=F_9w\\z0f E q 3  k , s ? s G _$^ <K?9)a(2vrJPg DOJWPY y5Y,M#|eC. 8`#X 5a*O}(Sz 2Z e/m$W*Oq:Yr!T{eN,f/R kaea,Gn'pFwmXai}N~-Qq/6:9JU[owzqXJ9+X%g&.A2K(k!D*~2Y~O!ud\_ghl*p+$,1! wQpD *i J?S3G;;HQ9VIO(oO6r+B_2x ; s  . Y  S v  5 T p  % A Y t T6Li|}Z>nTL# { B | X > - (  x = i [ [ [ S H ? ( q X 3 jNH]6hW=-$ g.kI3%# jH0 f:tU;*+3@RfyS!,BYx0Uk#(<?@=49ABHGSB7+ncft)@E6(#[2V0^-Rz 8Pj~  * ] + c  2 ? F N C 5  ^ 4 U {0EvI-kL!i`cdl.Rv*AID(aE0!Sl-ybK"g&fJ+hF,' H+Vor}xiiou )=E_q(DI`kz Mi2b_5 !T!Os4Yxfj /KQT> g1AH#h gKi &]-/^%p2o,O LfG, -3<-l3yb>x1`*i*Xn-sT2[++35{ZFSCjErf"x\=;8FZy~\,rY> qDI.hT6Xkr$_MD4E`0 {smj^_dm5f-NtID?z !8:@YYx-R`hnic]n4i$4=P_G 7P}C-qMz&gG#dY]9a#b'XMx )Rj{~GbDle%]+Mu] <  j ; 1 e  : u ,{Dz6Pm}o: |oD5 \  } ` D   v N /  , W n e N ) "   5 B Q k w j S K @ = 4 > O r  v Y E 2 $  M  8 g5NwZA"p2S</++4 O' |Y2ug\MB, i;A c4c6y83}s&tHpIo2o.qJ/$O,g1@Tm9k:Mz S9| E};Vem~xv'R)QnNW%GxPP&P;c,[Tk    - 5 > > ; ? D ? > < > ? J O f z E f x } r X M < ; < K S d r u u   ? _  t Q : * $ / 5 H e r N  m 9 #       k O L L X X c ` M 9 r>rfgS?(D*53#nCBl^[UXe_[5=YB(QjN0o3L*pV/ dDz`;{x{|xmN2 x^?- w_]]ZZehcXO<vsx "3G]w-Jg,vMS,mA,uU7#+((9HMgq~K'o %++:APlurdG.`8{NXtU0*QiO*Os*>X&_qlitmB+sU8 s8'LpCo +S5K_ss*>IXhcO>5ARnnZ8(!'Aq%7/.<MgB{3F`?ax!E{ ,9AXi!#|ylhWL3%  ->RRG03ckZO6$T5  ":K]msVB,rjjdYE?+#en`fcs|wyk_L* uN$c=#tDh'waS<#vXI8$p4 {V,ysqch]WL8-(Af&6M^u&Fp6` 9Uw5v6Xn+f8p%Gt%Jl  '5Qs3]y>u&Vu{jTCF@DKNRQF2*z^J9+! +61(# ],s{q@pR<CHSaqojX;fZG%~PwY4]-Co+m]OA-*N"}UD74,hD%o\I@AKWn~j_T_TWZQI5qaV\f}x[6&6M\XSS\c^rtxnU7&Sz-558# *$!, 'H_r{phjugVPTYy6bw|nZRA>GOk&?JSUUMSPdu/_ *^w 1\7_Dz.El$CTT`t8Rn.Np3@_j{uy~~! m@!\9p>% '<WvlL3("3JQacffqr|[R;-~R5 o4skq|  ysfaQ6j\I@=2&}o\J<97&?`z5Qt0Zy4E[urwrwu24)) 5HJO:$   8Y  eZI50)nbB7a;qeI8 X9nL!|KrY6&yc;-"-62.130+303>J[l(Mz}i^U\q 24IYysN8$ }Y:t^?3u_THE=4/$! z`J91BMgzd?#4HPVSN6nUA( Ak2Ur $,2CKW_n">e{ 6Hfhrodac\l&A>GA>;;CRRn# i8xvsQ5cUHB>KMVddpuoz^9 qL*eQ:o$]% b=- -4=@@I:/#&2;Ve8Ih&3174&&Kgxut`H#|nZLIFUc 1EGJMMMOPM^o}gP@%ynZG8'xbF$z\BtU;hN:2**-8/1'`OJ?4>11-,&#&)447@7?4,  ./?=O^sxldMH?E>YfTp9iPu$W|2f1^/FWYY_bksDRlecect Bz=m%3>Lkt&Hjxz 7;FCQEF;>EPgxj`ebY_JKKKNKLH;;/.}g^iru~r^H&  7HV\dP?5)+%E`zfD =UlwogM:#hUC-"~jN:8'tK4z}kket| q^D* ^4 oY\^m&/;HPR\dj{"3JZq   .Jdtt`SJ4+.#(0<CGB:(hG 1TU]T;/.9;=@*jK)}U6 Z0 8fwD mYVNQL:4$ *,85265$!!.57, 5\upm{ -ANRZa`lt% 0L`vvr .9BGB6)  /13=4)  |lZRP]i %OaiolnflozNv0f <i!.=Oh6Rh -Vm/EHI=5 $DksYNKEZk{0>cbnw~o`]RJGQRRRUIWR^`twI( /MqhPaC*  '=472# kN1% 1M`w}upffcj8\~~  c*c4fcXWQPL;/(p\E! o^R:1"    v`IFFL[q &(#h9~xlV@ zK+mWAC80e@c? cRKUfsc9 t;tS4mceo|yU* !'"--08AWcpvqk]MAFLXhw}+Xgwf^VUUtwriPB??Sj * &! -8Wm0;O]z D Hp02A\ZwEn!$" 8Meqx~|~ "8OZenq]]MZiy    +=Sl~dM1sW5 \;#yoom  7Yy{smhhs{sSA!! $2=NTWbY_\gmn0DFX]c``Z`_pvs )&6GSUUar  Ecyxq %J]fkf`SIOn 9MXVHMH<:?PoS0Wn<i'Qm   + * 0 0    ( 3 > < 6 3 %      % 3 8 6 '  ~_O1 &5CWdpmm`I0 }Y4q^OIB6 pW#xddYJ9)_'uhYI7  zgRMEJHG<1# kO-rF*odK.tL;vme_Q@:,[01Uk}xwztz~uX?.,)-1>[iooV<T"~vme]OGFEH_hx~ !9IWtzvnlnt|wec]TOWUi,#%4Dc=Zes|-6]-i -GURI9%5RvDz!!&)'fP4 +:79+    <Vo $,/-, !/Tm+Db %Bi+Fg"8D-3ynhvJa|ynXA((8JcvyfP3%%  %(>]hkoqqbT>81'0/0CB;"~psb\a\eb\YTL@22727,'4\~|N {(/'d1vqfk[Q0nK5, }U7w|}q`UOR`dt|rqqtqy}|qkcQLF;* '3?>DGRXW`^ZT>2 "1Ico (4<DJYadcjgd\?(]DsL!}X0  &(%tW>/%'0"|mW:'xtj^dm~rV?&  .9BH<#hU5 x_8! $&,-&lX^aq }}'Ha  0OKx#@Vs3fS$4Qj06AUckttqhR;0"8R}(().<Mg~2N_mm]TF@877:=CHLTTbo''    (;i)+<DNPV[Y^glfg^PB414<KguwxwdF|vsyX8%"*;Tontn]OF650+%$_;' }^H2q>}{mehdrps|yxxjZE-cB)vkWWOJOXU^_]eUIF+%3,3 N2 p^MDE<.~fI3pK!o? nJ. "(385 K*~lYE415& 8^0TwwfF6rb]Zep{|~xebK:'/=Qk sbZbdZ/  $/?B@7*& ,1Ke '06?FIU[^i|3HV\[jrKu (09Lf0P^r>]{x~x0Oe|#++6D^xj^BvX0lY7s[MG:. ](oN@885=EOKI=*_G,w]F"rbT>~rdloz{mXUMMJPVPG.vzsn`OI<99AR`j%=M[^[M?+  +H`r\YHBEBNSYaYV=U"unux%'+( jC2 &.>@5,!!/HN\e__N@,lP(<^2Re3]k 0Vz8_$8Lcty9c'EexJz ?^r{r`^UP?D91)&6Yf~ocSM@BGP^[^P?/hD(jLlS3 w`J8*"~Y8uS< qkty 4CYdVhPP?( vO(QoXV_P\lrwoiUDDBSt)n>l~qhU;8<>;LFRW]fft,b8P}Jw+^ ;e0h@dwiS9&|e6mV:{U? %&3(.(,9N_x/?bv*Ot|_FV55CLYeos'ZzW3sHf[Ud}!=N\mmp{pK/ f=sQ* %y^!5Pg|jGd?}a?xW=/zP }q2Mg*CZm 8t"OopBscR9 Wi yA h-}rVC tW[M20l .Mitr`G.s]~ @u A>i\D1041B@H^oC"]0Vr *7IIK?-~V+w+pR cJ&{~e@ E1YQn@]}ji<~\'+(v1B !l36i'~ c+,NAA!X &01& q%JV&zL3vbB2 oXH1& (7Rr!K|Aw<+7?HA7RW)?gM67]m:|G HV*-.*{v>@tdYJ e){6WnC,}U4#``1>foZb$zmfmxQ*YY7"&7 ? * ;    R  5  s.Rp 0_R$gnPjC R  | # K f w o S # z !$E.h+e X<\'rJ.K$v'O'h?_hH}U2:W7 UbV6'kQv0[CU$w(  >PJJb(nkrFy%U0YyKa. 6a+\'Oh|m]U>'(3<Qt4d I<YnS)rCZ\I#7S'o -L u[-3\h:_k:{W71s|F`#0J|x= /]U~!T3x/s'9Dp/<H{?ZxV5XEX+5BF0=;[ JU:iN1^ OfFmF :[w&J0JQnD|g"58-dAlpD{|_7$!'3Be]14GEC>C@$y|"RF0CseI35FwX@w 9VVD, vo[3 N 4dc4{,4Pf<AT^|L6k/o8y(HuI r- 8  Z 5fU.h%[t$Axw4?/Q)\wa5 vH:ps@+O#6=XqGb1$DvlSv tO02F3\O6arM+Qd^`!Gr(v82`>GlY"(bm&eI.!a;L`usv}fS(x:+'R;QLf8 .X.}/qb'u4%)=|CJ<>h=c,mhM33Fvrux: Fc % ^ b  6 G U D  W  E(pGP \DM[Io#l/J8(NO i /=QWW=# r5Q7Xt!}J( =.R0PGj:Tu_'fE y[3!@c 1E^p)Hu%086-T#~X+iLp7{J({=*s2[3T9Scowz}wr^P? `%5g"].v$d6X%N5J."6sg 6y'CTWC"r`4A@x#c5.J]tG}Q~b1olx'Lr+B>MC?0*$s2u%NU4d}2Ny>e:R^lsux}z}uVJ3eA @(p"_;/!2@Y| 0R904 4PzKx5]zq6$[X" ?f)Ew'mT!iD{I$wS6 P$uOz)F_e_TJ:0!^ G{lXB+%&,56_{f^,0|dT;ZihiU>Kz[9+ZkH2w-?]2 d? `33]=m@G7FA)7+1442&U j [t+Tr@ R"vY=!  ';Sh|3[q"P !$&,AIS_\R:'w?&eG-Or6\}/Lpxyyee\VIJI@7'}lM& 0SoA&nAyQ2wxE'i1u;{0kB~)W~~kVD2'] Z{ 1<hS#zz QGt%Bd ,_[S!WAkqZA+e&x%uTFNZep@Od 1<EVdgpj^AoR6({lgYLE55p;k7YHAii3Ir "W=Ob7gMMMPgFFh%.713uyv&=9BDM@EQMJX[oux}zwnX?)X1tK4& 2VG}:g( %AZt,Jbx8IdkbW:r4^_1{P #Y'FN_m>WnHq}uoz~ua1Z.p]H0{Bl`Ucq/d}dB( #)4:643.%()1?3<4##\_Gt  O~F *gI(g4HbmIV(Z\BzG (DU],o;v^=y#(T)j[D.sU0 kS,}+{(P!dP7 ^0Oms 6U+S"Lhvp]H2$ '>]pyjF!HJT7Yi9oF_*C\w|w>%8WXZG:*"5Lcq|tkA-09F@6( AZt|tkyKdutljVPXaq{xdE1  p3LdCvbTV]_h{+X#YLIy 7S'Tp|yh_NC=6@_}(fzG]<+\{Rweihv ;}rRB7"G!Vs~r_@Ef%|mkeQ1$jG<1156BLR^i!Kp8Li+?QLMA?99:EKpxzlM4wU2gIR)|iWLGFWsHf;]r#0A[Zc`L8$WF- oK4/4Pg5V0R]qwhLFAEMZq| #6<4?GJYn$,$ {l[S?3Z'{C0\(O}+Pz7]{p\I@!f+eJ+ryvx.O| 6S`lux{rm[G7`AveL2lYJ<.& &4ERai{C_-C[nycJRELLSQJCA90.""$"*0*%(-"$ dT;/*&'#28@NWcm(8AOX`lyw|zkcWC?3*( "" %;CRceisnztsqkekfkqnwwzwvkcULA0%   %$--?>DDITX]W`[`c`]c[b^X][OOFC;;83"(%""!"$"""*'/+-'+-+*++0+-'*00103-0--001383;8ADDGDGLLOOQWbbefkhllnyquist-3.05/lib/piano/att8000.pcm0000644000175000000620000001654610144436365015662 0ustar stevestaff *XCp;{ r}f` O8" =h)p#z@=Kd:P XAn! WbT]:24? F = ${ Y9.I95, e 0 Pf~=H=8* k+ k(=WMJ4TnW/iwv t =  y 0_9~?6'Q! aA݆V9!!m!(.Jmm' @N !44 56Ճq]jB}4HbHΙRc#ʟ"2$6ZvޜZ! # # .bc 4aRS+(X7^%>$e~4vfq(*U 8 #\(b'*36&-rqǮZ+t6!5f) N(} #.}(t `S ^ L/12|:8ZPTM!~ ^= $CqX d` _B3*4"/,Qh1n[M7y8J6  H% r Q (\%G )spB2y / ! 6 P'aWR    (ou#Z;FN+\,m( .NrG$He/xg!'TjS X@ d:l zD8JjM7w T R(0jd`:J YF+r^D .ouIa(+*r$UMP/<I W;BP# E _  4lHxzq3tU.oZ7Kgz5&$-hkn/ckD 8LWpX<5TDDa 0ivahsIMV!aLI(Zd`t' Z0%0 rL?gP Th-=#b4;,xk:QztqNIAwJ*ez^E@_b:oe)i/[vLs/fa@W2S4dD99BBZ eS\0wQv{z*1mFA/3[z/o3#Unf*SjT9V &yT8F0mn * dbz*W`pAS(<#>\h MbZGd|[|;fn[ :32[ZU\U $7up7ux*5zzIcd5HHsH{RaI3/Gl Kjn~#O6i"&yzvnM=WAKph c|Ta uCWv!)=" Qu.i$Qk;<Sg%v)qy5YXa"X!3h ofDH*QP?e u,CR _R!~=B|d2}Ar73hmM[?@Le(O)X%U# S'xI@RjD{LP7N:Xob&KOQ^i:Z V!\>swK8s]n%>cOG=~ 0 M`;qc$^SD)uqO)N3;uJfbO^[%Ai\K# l2qV\x ,,8rD-HN!#_l(-0x?toJ-lt,DR&Tn)5Ac)GhZ[B!KTOMKBH\v  Yg&\PZRS{}g V1w)s`]|<to=l =xP!-0~kXhhZKHX>Y'aHCl1:6SqT#Rg,AZrw<#Gm;t<g]\q$J=WTN234xiY1Nm-?K6!.7+ $_#%YF]c/#" -)1&PD-?  $!1*24.H.,BPCJqS\$ a%%1+8L/7IC9MR81@7# %&0.05<84X$p !kxp~M@T0Q3[xj{1)t]% 72#S8!;+" )  1E4  )2KJ8BSM<2WE-"+./<<9,3 $ 89*%$ !) )  (6 /82/CH5#. %B%#&!  1J11BKO! $     -MP?B6< (181)=A&- :B%0     "-#(?3(''  #0 2 "" !<#' &    '.&# "   nyquist-3.05/lib/piano/att44100.pcm0000644000175000000620000012101610144436365015730 0ustar stevestaff   %%e[o# 'kY%=+Em"e^m~0c{c M[DgPp[WU,?"8(o!cuAj=(p9\)RW?Vufll|F{1BG-vYN7ogk?% %{[u^V%Zyg!F{vXUSyKAmM]V'd5L4GVE@-0L-8{yJOz;pOp2\PJ}RkWn9Cp5Q&1PXMdxce j#wDC  wzDP+bLZ;i(m):p-{4XihVC7310.4WP4GebgUy-OHq5zrfA{~5*5+$dl!q4 #dtBf"A+q)BPM3Q Jn!u!r@r6`xyrdbr  U-IE*)Pz H z | K)wf[Waoualy?}A"Ded*shmK[iI.~M*]Mfa-C4m_/|gWn.SNH5aY}z[=)#%.:ENM9 ST+, &[G}Q =g rl t . a z S   v  Q 4 M g E 'Z>@`w/s,gE#bbag&BZ[_~7DWA$%":3GM !M" "3!!!} R5 =@ic O&E ķcYɢҏUKtcW#-8C@EOD ?8)ǏlHHԹ}/ZAKLD83 CJl $%#̋ dϧX5?Ѥ|O0K`7lpmdX[I;g/<'y%*q4zA"LT0TwL=*-۩>r*BSZPUG'1@D{Ǚ(nKR00;B{`F  $n" ^˺Ǧ2{"(~&8_L ["((A!`YE8޳֣ռ-'+H(`!ρ+l}|"&&$ ` u M]$0,v2 44{1*A8.Շ6JW} m! | Fz{d0^̨uZLu ov='g%FlҶiŀvM* #:.U9D;N?W_fj?idYM0?4u+&k# !%(*n(\"1 1_d2NnDuriϓ̲ʣSP7ݨ"Cݘژދ.IYU N\BSh e 5Gq!& )k+*(&O$`#$')+Z+*(&&"'*/ 35t530f+&} 8|lѿ|ČIË&ɗW_ٞ*oa%#ahp |oBp,@DUz0HQv@  #*B/3665H2v.|)$|& r&Z'ۤ'۰ߑs]W>B#R'n U Rq#a(+-:,, +Y+k,I-g--*[&N!?tC p{= """/!T l X#pdp   ZXX_0Vު.FXgӳYϤ|ݳ"TJb$QՕ.Rqr$ 0 C W z &,>k \ g  ;t + ?R ;",%(R)^)<(()%*,:-.-,_*~(%)!w@F}a3=g 4 *B-YI # yD_% vm, ) dNg 67}Z~ףعY4HԴօOg18g-c3|&pfXBT@P-)#7, ~@WJ\n f u@}T!( {xzpY >k  G)D K,lY  IihrNr p8k<<4 1  Y R " # o ? L k n J3B# P`6T ;;s8v%i[lqf uNS .V/@XS~,n}y%_|oc<D 8JIS%~Yy(Ijo); {0 {  >y   "BR!H#A7+.|9:Tv&8 ={ ` X29]XY\nr"KIhI~*9Sen;v7 X@{ L { B O ;  <c K ik7|/ - v^{d@ !"#$E$g$#f"M!r[e 9ٌh٪i~ϴ1c((E]?/buK [a4&9xT -a5S$ E O $ #h3_+P^P&~"/  6T0&+;" w+7c|{&  n^"\Mi"aOH'90ELߟ&lg\HWy#  Vx[5YOs&   3 7K n *L!A;5k C]ai za kL/<[e2w6 &:-C ca(a e.[bBuS~IEQ WV%k 2 F / H #R0JB~3q.jp = *[ |Zw!CClWcuML#*m0^FurlOj[Oog$jmr2g,~Dbm 1=}R;K/0c'#vSv ^  | B NG ( NDJm&dUX5U>- _ M }rHmFwC ;b.^4H_HTb-tB=8:rhB@ ',eRr wt}: H 2b_"* \gMIH] J{]h !X  j[j&,!Jh(*k]|k"?-SZYAywbdit2h)$zy* @ J yt 7   M @ 6 e d ^CV-?UGgc;&SSEDu"ek| gg RJGd8 tGov^~IoG`fn1Grct_e/&c^ `f;u|oO/PT8N<~H/(+;r]]M %h@hc>Jk:%D<e~V4d 2+>K:0x?m4WS 8|8/!:{><%vB+ :LYN:GCE& 7-'8U%B V!;f+5,T M 7X50o;4$SMo*A`+ F-6+-5Gn:/mh)LJ:ge2H-#JK]w 7UOwkwQse9BV T ' % ~ p a F m Y-R  j vX$J\;Rrrn*Rs@Ah -(@*Dczt6"    M R  < l    & = ktiM t  k;hp$ r/p7  m.W~5 24jQ^e ]d~WL8&x l ] _ bGG s + t <    ]|| )dDA0|O:kgD S}iEwOc,oCD62Wk{T6jwZh+-?f:/fyQ28~{Ly=#9Bf]2S FzHju\#-5:Dc3 -z)B7D_y)1gbGHfF;ENB@?/] quW: Ti,t(NzU g9|EdS~Mcd8b2L(R`Q6! 2QghG Y&>tUo{#Hi0:<)8 z"F47X\Ze<3w*.)9"#kY^Tkh V7b_XDJ{`,{7%N1KGKgfW /D z  ? t I E w F .  R S;y}5wJFRLJ>kZYs{cp'6/jd\1 Zzj0y$>B@lYE$ 0 H 6 # ) H f o a U p H &  NP f1q)>V/Fc6P4cr8DFim$*&`>K\S tyII`hGtbcmqv zE\   # v FI"2A>"_MoHH/7&)qf)6C|S)Yd~NLfsU% =G#^3\`=S]}~d$IL(P9&BVyb.BtI[4s^PLOZl,t+?;I>0^V[/|Oc*Bo<3JeiH/  k#iD s9AA;},3TH] fwB <!ctlh{w  f=3 rK|6\kh`D6lTZuGS)O==wVDbiLMP FAhh:he(b"Bj!\*sk p)7$4L3] w__1}Z.lG_\ji 4sw>8+4Ix,LR(j/sQ>9?JT\\Z_z2uXE)Mt4b{&)Q@6Y%"bm%N,\[GK/wk- d?*% fgF1)'-4@SreUYi~@g{~uo 2@. %qmb`bbiu]6skG`<]I8-= AP7 YqF,7 X0~an9pp(@9-zoA+GG6  Cs6pem>mMgZR<X+ ;SZ3Ali<"*T' pTjljNR| 9=0qQ%Op,$q3?-UZT^x8>C7KMJGB/Sro$H|vyqQ0"([ x7xt=j{m#H ;)QU@%;pe%D2t=%|E_M%0mwKIFK,+7+H} -W^.h|mK-(BrAz"#}v3G.Uw`3jZKA<6* O{7w: +A:_baK4{w@5&VaI#8'} {7i4|]wbVPH9# Zg>9`ZuCgxpbM)VIunJ0qV]L. YLkg;MUO sTGHNOKB@Uxmjpm]DVs&R=QD.W=>V{[Lr1MA9(_`.O 6^pFk:rZfD[iq{xQd!H}tK v9o9B#ZBT9Fs ;\wl:tE6Hp!;p)(z?D &5FU`fZB"tZ8?r=uha }K"pAi\]nY$?B;44?_PN  7MO5 o8 *<J\skWD4--9K]q~3~n]Bf8u =d{9c{pP}ae;+b m.!U G}kUEGXr&Z{C A ''_=+n3  2FW`X=jL)S$4{bqivv]C"x:2CMG;(@]vYB{@VK#F{/due> ,V}UrG `"0QedQ0%5CG:p pL?BEE@>BSj}~d5 5pen(v !3Ih!Mj|  !H0wd|AT*xP3$!()# #C^oq_C$ sJ!k][k%EJ'is ~svb"kpl~WmD )0/07I`mjWCKzP#sPVp,oLBQvy*67z1P\U3 y@S&FQI1hjn#^~SqZa( vM7:CRgsxmS4/FG6%+wT#GckbG,0Pp ":Rbmnkmx!)FhY1nhpdJ/}lT:& *=Va`PA>LisO65Jk0DK<3EPXh"yP.*R_G2'  yrykQ<219DOWblu~rdk|0TptgM6,8W|lN;48AGHA<:IadC&JweM6(!#,C\{{laYTU\dp~b3 #;KKB>:CPTL2hL@;3%^d"nL8/6Mt &,9T`eVG4 &A\t~}mT;%%?d'-&.FPOB/  '9JXhxzE 5Pl|tU#)AYku|}qbSNNU\js}y\<  )7??82.1=OX[R>& %:KV^fbZI+ {dQCDRn un},/( ,Ink_]i|dC*(1=Nc|_NCFPbt}iJ#{\B/%3EI3 hKDNg:eslr     ":Vrv[C3*%""&/>L\dmrqsw||ylV6zqlknrrk[H;78DMK7/Liyj^PKGM^wAg 1?KUTG(whkto^URV`ileWA,  *.! weWJ=0&)1D\vlS7 9[~&27-% #*,( ,AWpzcJ2!#4JbysU>39H]q~|u}}slnuxsprqhZE4$ xdPC=BM[hq}tjaQ?+'=UkvxzsnkqwxrfQC<47762.,07CUl)>JU]k~ -BH?+~gTHHMW_c`XSPMNA%}b\_gmh[M>:>L_py}zuroqxwulU6 (;LSV]hyk? =avzq_QKQd}2Mk#7>8+  jL86:@DGLT_sw[@+gXTWaehaXMIO\l| +3872.*&  C`nrpovtV=25AQVM=%5ObfdVG=64/#/>;"+69/" wgWOJVcs  ,3:?=8':bzxgZTX]a\N>49Ny r^]t}eQHEIJLJD@5& uohikpv}qZ@'  ,9<8+!(9Rbh_M=8Ii1Ngnh_\bwvbTHA8/+$&+27:8+,3, &>PTTQSY`e`V@*.G[ij\NGQjymc^^i}zohga^YSONNKD:/ &,$p\C0(-=Yvsh_XTL>( &+.5ANaijZB#.IZ^UG99AP]dc]X\hw   ##5Map~uM0 (4@GHJLS_p}~qbSC0 5IYbc^TG:(hXSSUSNE=;DQbovqf[RR_n kK8)#$/Ef$Hg{k]SMNXix~ojjvxZ:!   udXVa} ,?<)j]br 3AJS_eltvtne_ZVTUX`j{wW<+)2H]pvwwx~p[K?78CQctoT; 3MabQ-wolq{|naVQOW^jtzx{$-20-)&(*,,,2<Ocw|qhddb_ZSOOXbqwyuqqtzse\V_npd]\bdc\NB:9CUei]=}hYL@0 %:IRTRNLMQTQD2 *:JWjv)7EPUUOEA?@IYj"$)*,,'$gK5)*1<CC@948CS`koomighgh_Q=,!(*'    $)$ vaQHFJT]gu"87*4HQRE-  +F_rvgI% k_bk~ -:@=81+%  "#   &<UhswodXOMMMLIFDL]rlN<58CF?) vjinx{kYNLS_jnj`XRUezrhci{ '0<BHMMIE?::;@HOZfxwh\Z[YXTOH@:626<HSaoy~}p`I1 3Nfvwqfadny}raPGDHMPKA.$)>WmyzscVOIEB9, $2@IFBA@@ENQPK?2# %/773*$!(#{bL>5-*%#$&'+*$#('%%.9Ocu.4/#'8JS[[WRNLJIGHJPZerwvl\G2#'//-,%!!(163)  $/34*  "*-159=7+%.47;CKV[[RH:2-,))!   *8BEEC>4+!"     #'./-$)9FHC4 $*17@@A9*->GJE=::;@CA<0%(7BIHEA=>DLSYYUK=636@KXcirwzynbVRQSY\YZVUUPF:)  t[JIPe|'-+%"%$"#'+02532-)('$!(3>DFGDFHHHE<2'"!'4DNSPH<57@OWZQB1#&9N^fcUF<:DO[^YI2!"6GONE8/-08@HG@4&      "),*'$"#&%#  ,342+%+396-! 0:A<4/+-28=AA><99;<952//3>MU]ZTG5#  !.4.&" wjchnz   # *EXlv{{}xjb^ely{vx|}siZOC;44<COW[[TD?645;>BCDHILMJE:-        sf[UWfw &,0:G\pr`TOYl    g?uqtkXOR_s*12+   $'&   !" '5??:/'%'/6@A=4)  2JaigWD/)0453256::80)$*'!"$$  !1==1!  #*,#  ! "%'-/.*$#/?MSRJ=-"   $!  ',,%# &+5?EGBB=BHPVYTI<3-/4:DIGGCDHNSY[YRLHCBCBC=93-.27@KTYYYVQJB8, #.25.( #**$    $(,...-+++-/1330../6;ADF@=746;@B>7( %0=CB9/" %#  "*.0-# #.7975168<?>6(  #-6:3$    "  &,-1*&#  $'%#+/-%  &+,+'    "(,/344340/+% )+0233355;==83-&$&,4;@B@<9;?HSWXK>/&$(.352)  *9>=2!    #)'! "&%! $*9GOJ8   !!)585)  "% /670!  +13/&     #$   %+5@FNNNG?:50/.,,.06:AEDDB@ADKUZ]ZPC5*" "++)# $&$ %(%!&'"  "($"&,*"  '*%  %-+'       $" !"       .7:3$  '0:BEKPUXWTKEB===@BBF?=:989;97788;85-#     "!&$'),044222367;;951)&'(+./1157:BHJJD:-   $,341+'&#      "&**&        #&$   %,6<>CGGC>:/)!"$)+()*,..2.)#                  &!     "*-./,)%&'()'&$ !(.9AGC@91/-,140-&" !'-1//("     &+111.*%" "$).001,$   "       "(++'       '('# '/588442/'#"$%#%%')('# !$&('#"            "%)/00-+*'')-+)(# !$$$"  !"#          "'&    !!!     nyquist-3.05/lib/piano/pn17.cod0000644000175000000620000005340010144436365015323 0ustar stevestaffSYNCCNDNCOMMD79 IPART?????? {>Ʊ>->W >D>B:>(a> Mu>f>x?{K6޽'@4@ʳ??;@:@0?ph?g>?aa?# @}\GRUP?@@@@@@?@@@@@ApGMAG:T:;j:1:]S:9i9:ʾ:A9:H;:,'7:c:L,::BȔ:\{9ܰ:: :c~:m:U|:=O::tA:]:dW9Þt:i2:Y":+U6;`A<C'>0y>.>$>VlL> >Ǧ>>/???>B??>?_?wv??y?s~?q?ph?n]?f?`?d(?p _?uuJ?l?^?W\?a?q?y?x?o?`?_?p?|#?{i?r?j?f?>W?6қ?4w?3_?3?1J#?*_?'?"? ]?Q?u?E? ? >?ڳ?N?P >&>}C>>ޣ> > >>ҟb>>g>>`>Y>>8>m>Q>f{>>x>~>>v>W>>xs^>p>hK>b>X >Q>K,>D>=A>5>1>*er>$FF>ɾ>>i>W> :>=&=b=偀=g=;===S=j=p=={=3=K=o=z=jn =``=S=@=; W=3MR== =:==<<Ɛ<(<?g<®C<ü<ś<<< =;2=ڐ=$===P=:=2=͑==j=&==md=,===Z=r=]=?==4b==J=1====o==:====,=0(=H=;=H=½====V= IJ= <_<[,;< <F?<X<^;(;3;n;G;㏡;i;ډd;ء;3;C;Ď;p;;;A:;;;;;;];W;Q;2;uz;ky ;d2;Veg;Ko;G%;;;,;(;;ʹ; ;::O:6x:::::D2:4Y: v99YR8 9 9Y91::@5:Vj:s:::O:̰3:(::S;;;X;*;1;9R;GL;MP;T;_J;h;p;wP;G;;|;v;;;,;;9;F;T5;l;Q;";7; -; ;;ʎ;;;e;;0C;ށ*;D;;f;;;,; ; ;;;e<?<<<Z<#Q<m*<6<<1_<< < \< &&< !*< 8< < t< Ӌ< <Na<W<$<<•<<<0<<.<z<}<B<<0<<<<~5<<<<<+T< gt< 5G< #< < < t< < 4< < T<Z<<<τ<z<<<{K<<I<<R<];;P;R;E ;;;KO;8R;Q;O9;h;);;j;:F;h;;^;X;z;V_;>;;x;ߏI;2;ݹ%;۹;ָ;٣#;h;qQ;m;Mj;`;;Ѱ ;a/;+;;/;h$;Ȼ-;U;ƣ;\ ;Z; i;;;;m;6;u;>p;x;;;@;;G;s;7;;;;]s;(\;G;s;~;;;;i;;K<;;.;M;;~;;;;Z;L;ɱ;G;r;;ڡ; l;N;;|;w'j;w7;r:{;nA;kT\;hE~;a<;`;\9;UK;T;P~;JR;F;Fw;?Ā;;e;7Ӄ;1@;+n;(;%;4;?~;;Q;@; :;d;:s:$I:::%:עU:-:6:F}:O:V:: :I: :: :X&:\:uwX:zE:į:j: ;6;];8iC;4:<; ;q;;F ;J9:{;X@;_:4^::I;Q;); };;@;U;@;BC;;c:;;O;;y;2E' >e2?1c?G`?>>[=~d>>N>ɷa>)z? /??[???5D=>7>P?R{>>J>h? ?I>ui>M>>P?:!?7??!2?D?1E?I?Tc$?#~?3?P-?.M?5?I[?D?Eh?yp??g ?/?5 U?Pt?-?S| ?x?M?Ni?=5?2?H'?P?0?EN?IH?>>>F>Sm>?x? μ?U>|>ط>>i>u=8B=% >g>j>I|>>֑>k>v>|>IZ>ĺ>>>/->T*>f 7>~3t>j>S>vr>Z>W>EA>P=>O l>W:>>[1>l;>o_g>iZ>`>QM>4׏>&>u>!p>>i=L==q== K=1=1=K=W!=M=xY=Y=j=X==[= =rz=lp=t=d=x=^=O8M=?=6H===8B=$ G=*=6,=7+*=T=l)d=g8)=Y=X=F=:=?>=$=6=,j=#=ZF=== <= = o==y&=R~<=z=[=,{=*e="=<8<`L<;K&;(:;;<$#<%<h;!;P;A<.^<r4;N; ;2V:g;x2;;&;rw;;;;;H;;;>;A;:j);a;c;T;a;;=;Z;9;˯0;ߚ;k;;;?;K;;];sS^;L ;_;.y;i~;T;-R;dP;塊;ЏW;;;y;\;o;q;O;;£;~;;Q$;.;`L;>S;0;1;0;&;=;a;г;;;vJ;=;tu;d;;~;+;;q;;];;+d:3:̞;7)z;;Y";(;r;;;b ;36:-"9ى:!;;JF;|C;;0;;n(;Xe ;/:ɱ#9eh::2;,;pq;oB;;;;l;Zy;:º9; : t:ʼ0;;/yl;g;;F;`;v;Cz::U:pl::::oV:YQ;;;>;B;((; ;^:c):H/:2*::%~9)U:4l:2:A:HT:o: :w<:4:V:?P9c9ŐG::\::Τ:e::eQ: 9e:~`d:sM:R:":1:::J:zv:L:`:7.:,::5N::%n:0^::Y:ҝ::7:~;W:ҡ:O ::]:x:k:T:记:n;0;/x;(;!;&$;:hG:ޣo:1:c::l:l;L;+;;<:[::|:KA:K::M:zn:a::ۋ:Zm:::Su::G:OG:T:Q::.:ll::@:B<9N*9::$:sf: :_::=:::M:[Zn9:V&::y:6::qK:"`::I: :P6:;:z:L;::w:::p :L:# :l :!9:R^R:yp: 8:r:R:k:&^::f:B:459j9::j:H֭:UP:Zl:V:bJ :%Օ:HT:99(9X_9w:/9a:-99e9{9$28$989¯9v09P\9X9wE:D999 9j9;99ʬ9299:;: 9tK9K9L9\#99ɞ99J#W8ml9QY9^999^9bf:%:N99v3J95J38b9ۥ8I91W9ß9ǜ:9z9.9e9Rn92V9L9+B85892zd9C9!9ʥ9G99K9~9U9Ԟl9:49v9HK6919c9949q9$: _i:4/9 99L99wt9:9K999<:999n:99S€9 ;9<{8á7h0899:": 95n9V $9Y0L9ܥ97OE9N59}99~w9R:8Z99;x8}8a98P9A99a: 9I9 9~X9-9id: l9Fb::9T9H9س: 9:̱9)9H9B99A?:?89&9{:N9B9:co:#Û9@k9XO9$:$X999`:/:[9x9:9O999987a\: b99{9@9b t9b39dO9C89)S69A9|:9m98:H9x94d9Zn98ϫ9q8X9Y8>^9@8X&888Pr989;C;64:O:y<; hI;L0:;a;qQ6;;eU; ;;N;$h;s;"R;eW;;7O;|;;g<%F;;v;J;;k^;[L< ; </>oP=+=w>>Z>Ba>b?>Š>3>f>>ʹ? ?2@?.|?E}?c?8s?$S?>K?>m?c??U%?uY?:?[S?X{?R?E?V޸?.M8?TZ?J ?8?|?y?#?1?Cu6?/`??$??=?!#?t?!?o? ?? ?ښ?`F??$o?-W?1?B?E{p???:l{?+7?O?M? Y?j>{>Y>ݑ>mB>[>>>>#>A>ͯ>8>>nj>~H>>v>hh>=>>1>*>V\=x=e=9=;7=% =6V==)=d#=[ ==Y=<=E?=m@=r=qW=f?=E5=k=V=fb=\=4===z==={=*= =l =i>l=|=v]=hn=X=L6=D=<4~=8=>=*F=;ُQ;s;;;<;ܥ;q<\;;S< w|<;ᴨ;ZP<<z<<<;I+;\;}m;];>:\:9E;2;!:ѱv;P;-;;H;1.;S;*|-;%&;;UB2;1|;8";X;R:ح;:H;;AH:P;(h;>0:)}:8z;: :;-::Po:!: F:}=::3:_:9jR;x::$&:v&;: :;7r:;l:.;8:L: ;:S;::; Ǹ;c:}y:];0W~:U:){:!::J:W":#2:^C]:f9:/:V:40:.d'9.99:;:n:99":W<:D:8U :$:,( 9(9:(G:":w.::wަ9g::}:C:9<9q:):T9^:M:8{:H:g9e:^:ox:o:z:_Ax:X:H:P9jV:"k: I9o:39u<:: :Cʽ9:;G:d:a:O9ξ:K\5:q: /:*:3n:4e: ?:<.y9a9U:p:6d:$qF:]ѐ:>j9:*9]9D9љ9::nT9Ӂ:M3:!!:F:0:9Ğ:N:=4:O@:X2:,h]9:91:L[:}+:+N99i:99@s:%^9Ļs:s=:20:J"8-T9D:"q:9ڽ*9 :'9Z9Q9rH958D9$96Y:/9ߍ:[sr:3 V:$9939d9d999E9F:I : t9(19#z=:J[:K:3 9<%99@S9:"S9Y9R:eF93T8D9U$9s:%D*8B9 909Xb9C~9l9:':(u9 :rS9eb8+9~:9P9 9999PW8Tq91K}:H9e7W8+9 9ÓN99y99_[:/:4S9T 9H9x99 9$8:9+9r: :A-9܄8K99 :J*a8TI:!9;9]%9 9%9eI9:.@9y9?9 9!:+9Ӎ9!919j`929:/H9M9-׿9:,{9K8%q95:k9ֽ9e29L:9հ9Gc:I9X9E991^9J<9D@9UC8$9ڜ9S:$'9X89Ͱ9x9M9K8KC:QI"9q9)9G9T9nj89919m9l988[9~9o:9*8߂)9}:AH[9o9B9jm919B&9{v9Q 9S:r8~9٧9<9T9L9Q`8R9a9O8887^9 9!9=9> :.gj9k995h8Q89 :,U9o9J9:9Z 9E99]9s9:)-99i9 |:fJ9/:" 9@9If59%8,+9>9l *999l9h9x9}9l: 9 9^E99789F9<9{6:49.: T9A9I99Nh92m9mn:,Q9>9Y9U :P896j9ˠF:e9GG9^9t"8I9.:29!9fR9D9״9L9H&f9+8+9]: r999: ":8AJ99B9Y99B ":%99O:wR99^98'9TN9[9}9_99"89<999{89:969hT98І9`:38!)9gY9;bV9^9Wd9s3G9ݍ9=w9X99rP899J:9t8i89@s*9 9T8T9_9v9pl8y9l9 K98ٗC91Ы99Ӷ899„68t< I;/+;v;Gh<;);Nh7;וj;qy;o%#:i|;ȒL;<|<*;պ;;;M;e<<-~JML>Q>^?J?[> ?!?b (?$k6?;T>>d?=>ڌ>>U5>PS? va>Qa?Sd?c>BR=>c>?PW??cH+?4?(J?->f>>U&*>yM>!>(>i>.>ǣ>c>>Ԟ1?#M> 0>>>>H=Ę>sT>IQ??+%?d ?H?\T?=d?+>>ַG>+>R>>+>P{>A_>Q>w >D?>P>r>~~=5>E==ϭ>&>=9>>x>R^>u>c>$&>:D>_=?B>#T=T=r'=L===l==>=;#/=wf=~==g=SV=bk==y*6=c=t=B<=%/=j_=%=p=`vC1M:s;>;:h:y:ժ+9l;);HX:W:@2;V?::k9UD; G ;'7:ź;(;6`;X/:#;"2M:V:@?:v;Ro:\;ZT::A *;;$'^: L;F;;%F97: ;: :P::"E:9#;UX;:[:ώ; /_:z:}:i;:R :9i:; :):7Y!:R5:: ;2;:c::cE:90::):::1|:2٘:v:R:jw:r: :l::B/:v5::2f:C:9nj:99Ce#:)f::3:Y:@:4f9٩:A9nnc9:մ9t:^:nxd9E:-p;:L::9^:ȫ: w:pxr:I:q;:ܯ;;':9ח: U:po:}:h:1F; A:0:PsS9:̘::4:%:sF:+:#q:j#:0}:;;:":k:P:U4E:O9j:Ã::0;>:R::$:H:n:e:29H:PU9f: :Q:p:m:B:?E:Z`:2:D9,:: :;7:=m::3]:{C::=:[o::Bl_::::p:p=9/:4:::I:oN:$h::ja:Fs::`[: 2:95l:~#::ʪb:Q:ߡq:|:;q:x;:۰W: H:d~:Y:!:2J:v :Y:_:_: d:;s:~:x;;-:3J:5:Ng: ::C;:; ::j:K.;;ON:q;?:r:f :):C:؊:?::::x]:5:ME:i:k:B9c::::2:69y :`o:E9R92`:do:h,: :\:O:_k:}:::H]99_:+K:z9 :Y9D99vR93:s:[:[:U:k99:v:_::&:?::Ɓ:5:&:\:OG:RGX9Γ9n:DR:9Q:7<:r:Z:1^F:':i:,+:-9vs::*9 :s:9j:Qs:z0:L:or:29X:IS~:Ҋ:::iq9y:'9-::-Q:A)Y:0:::\9D::@:SF: :o:9h:'e8:֟:[c:˄:MW 9+8:Γ:9999995:e:pw9::Er:Va:1H::Y :: 9:-8:*08[::99p%:~:f9y9$9z:P::6:39ԓ:)X:G^:Cq:LH:_9A:=9:9v:/B:n9ĭ::@89:B:A:;: +9U:\q:u:̓99:+h: ::^ ;A:B9:sR9:=z:xj:m94:k:Fl: 4:MN.::MF94:*:k]9/:T:::.2}9ziQ9^:si:|yO:":Z:B9Ht::;S::6:::J:%9:-J:v.:0::=:%g:iX91 :AH:t:(::]¬::m:D:P[:{l:w:8~: k)::y0::EW9T:L::_:[v9څ::W:T-:vf: 9tI92:) :$V:j[:Fh::I:0:z}:%̢9{%::Ar:_: f 9y::xu:=:j:E:uF&9n9h|::a)9S:1d7:89=::іy:t:GD99_K: 9 9h::}a:K::.g:y95:hM: 91{9>1:9?':/= 9O:L:&:9:.N_:h:.0:Ma9b::w9:U8:E:0C=9d:?:8l:TX:?TK9)S:*:#9N:KU:V9&9:+mg:y::~;::&u:j4:q9#:6999M[:p9›$95::9: 9k:[:Vx(:^_a:RO:g7:":<:%H99Ӻ:X9: :oF:{9&&:9ޫ:$.[:9:a::7O):}:=J9:t;:U88Օ<*o<0d<L;<;j<#e<Ӳ;V;K$;*= h=i>tr>h-==l>}@?.G?>M?Il?>w`? s??Z>1= ??H?K?'?K{??[?c>k?2?H>ڶ>R?+|>>(z[>c?.?Z%>(9?:Q?\?>G#>K>`>im>o>n >R>k.5?>з>Y>}=T>>^>\zx>z>$=>>L >iK=i>L >KX>L>$ z>ޑ>>dJ>B1>D>>f>S =l>I>>>;>8>e=>G=ᮦ>[=='>p:P$-;c%;DB<<::;t;4+i:T:Ļ:R:C:-):D;*;x:;ũ::W;;?:;V;D ;=3M:N;+2;:f;\:G;Ƙ;:z:_;[;=@:t:|;G:V_;Cˡ:e9u/:;i5:r:H:(;(;l;4;FԶ:{:]:=: :g;m;Z;ہ;H998};4;#}:Q9);<7::;iU:WR:p:@Jl;#{:2::5d:87:@LB:?:2R::=::R:::::h:tw:+:$:-:g:(:S:i:t: :z%94:^$9d5:8:`?:~M:M- :k9KW:ܯ99Wm:w:Ao;::rt:Q:'n::\P :UA:W9ւ:U;29Ū`; :::y:;1/L;): ):1G:a=;٭:hݻ:)I9D:}M#:::1|9j;,c::9:n:{;?:s:;::ܱ:*::';::w:!:;UK::{;w :ګO:19!:g;';9 ;[; ):6:V9Fd:}94 :!9O;k;;^Wf;1:?); :+:v[::~t; &:Ψ:J:w:b:hh:6:: :\ N9:yL:::޳:::p.:?:S;;:]:h^: :n:!:x:{:]9N::K:Lr;:-I:%:3 :g:t:8: ip:x;;j9t -;14:5S:::q:Y=:1::(;/89!V:Vz:\9<:;B.;B:Z9Dm:GO:ۧ:xs:::%9:29K:9:v:9:K:<;$1:C::;c:@: ::Z|:I0:x;d;[#;:w:ߩ:;:U:b:];(:};e:E: ;4Z:m:;:!:Om;/:q::׋9Av:HK::+:/kA:s:`:%5:%9:!:\":#r;9F/:%68;':o: 3:;;m:+::cE:c:sR:la:Տ9W:k:f:w::q: :: :~l; e:9J:::!:ye9:^::b::/@=:; 9d_:n9N:h9:R::: ::9:Y:;]:E:If:ԏ:F8:f:B{:bn9ݰ; 9W:K:b|M:ʼnF9ݺK:b9֖:a:[9& ::9.K9 ;H:$::6 ::s; :::-9i:`919슥:9s:Uq:n"::9:,9::M:R98 :FA98:*9|^_:'9::R:: u:p:nh: T:3<1>Yx>!>???t?`#?O/?6W?s?MZ?h?H?J?E?(N?NZ?,?)?9? P>O?*?x>`?1>|>O>>٧?>9>?O>?%d>e>f>4z\>>*>ނ>>T\>7>l>Î >q>Y6y>$>}I,>=ߩ>8>C>>X>xd>e]>(ۯ>n>T>u@>)?=ȴ>mݟ>=>J>Ve`> => >Vm>$k>q=O=#>==ȏ=rZx=`@=e=nN=Gj=wO== =k=)"====Bs=n<<;`;>^;ut;?;i;I;f<_;;;@;ˁ;ۜ;;]D;;ǞN;;;c;BC;;u;.R;Ý;;;~j;;;ණ;;;P;X;;p;_;+;;;S;; ;g;v;`;;r<|<–;+;=;͹;z;; ;m;;6;Ū+;;K;;;C8;;3O;<;;{;(;j6;ur< 1;ޒ;;6;x;;C;CY;Z;#;E;H^;\ ;ؾ;Z;_R<;;ҽ;obH;u;t;;R;Ÿ1;\L;+;^L;4;+;;6;|-;;};; N;;;yG;T;;l$;yu;;H;ه;U;;;i%;n;6;R;&;0;7;՟;j;8;E;; 5;;;;PE;J;a;;^;";";6; ;p;J_;C^;X;;r; ;;S;*;Ž&;sOd;U;w;;;H; ;;zO;T;e0;{;;N;;s;;;L;W;i2;Di;x;;P;H;n%;; ;Ƥ4;oQ;eޔ;P;;';9l;Q;x;;Td;ao;4;;a;1;&;v;Q;;<;C;@;*K;;;;;k;D;Bi;;((;y;W;;;l#<Ap;\;"#<Y;Ř+;At;oW;+;Y;:;*;3;p;҈;ke;8;h:;ϑ;6 ;;m; ;<q; i;0;;tn;_y;H;V;d;ќ;?; ;|;r;;5;f;<N;YV;;Ң;< ];;<;;Y;%;;k;׈;j;v;";ɷl;n;x;;Э;B~; <;(3;K_;@J;6;4I;щ;P;;[%;N;#;;;;A;;y;?;;;;;I;Z;r;;/;!";^;M;;1;"t;n;;;>;`;;T;S2;\;xB;T;yj;#X;;M;;(;;O;1;;?;K3z;λ;CN;;~;;;;};;\:; ;t;;k;=J;;[;9;;;%;h;;;;.;?;S;L;I;;P;#;&;1;]4;|;5;(Z;;;v;; B;L`;;';_;E;p;MP;@5; ;֮7;;;Os;;t9;;;8;m;`;<&;{B;6;|;`;;cJ;;|[;z;o; ;;;;G;;;j#;;H~;};h;Z/;;0;ʀ;ę;#;;;N;);9;-;po;;;;_;;ٛ;@+;+;Ʌ;;R;ɷ;r*;d;B;T;7,;;|V;;;N;;a!h;;Ҽ;y;w;uP;|\;*;Z;;D;ö;;o;@;;;;;;у;&;{;;;;';>; K;;P!;$;};; f;:;sd;I;#;~; A; ?; r;>;^;8;;);VQ;;@f;3;:;1;f8;u|; ;;; ;ά;;};J;Y';NӐ;;@h;;;t;;q;Q;S;\;8;;;;^*;I;";";;';|;1;i;xq;u;};G&;[q;$w;=;Z0; ;p;(;g;i;*;;?;.;; ;O9;y;nN;r;ŔF;;j;;;BV;*;=;nk;>(;; ;3;m;;w;;;;B;F ;8;<;c;;;Z;W; H;{*;O_;L; ;9 ;6n;Ԙ;_W;:N;;%;8;]f;NH;;Y;f;;;I;;P;vk;t;I;9F;$;?;t;;V;`I;-;;-;~q;o;;a;C; ;,t;W;d;;;;;>;;;R; ;v;;l;;|q;;}j;w;;D;2;R;M;y;;;;Hi;W; ;`;FR;7];ާ;m;f;#;P7;K;3;;;~p;c;ư;;Q;m;u; ;;+;d<;8;lA;5E;:;;;L;?;;y ;<nyquist-3.05/lib/piano/att22050.pcm0000644000175000000620000005041010144436365015727 0ustar stevestaff  $\"k'+Endm1|eEOpYVV,>8rcr9[)YAY f}F1F-x8hk?&|s^UYwFzuSJm'65,0{zNqs[QK}RX:5&WedkvCE  xzQ+bJ[;')o,3jV83-XRGcfOr{BlWhSj09bL,J$?t6ruY)*{{ T . J m  N  t<r|S+w q"N~94 #i{893oVuNlU e   9   9TeJpMyu?gRB5[5$c5#"r #dAfB-BLK"rq7wqb ,DPy H {)wZ`vx~A"euhoh0NNbCm/|V.S6[*$:N9S} fs - T   u  3 N g &\>@~tF%a'[CW$:G "!!!|1idGŹVґuW#8BEO<)5`ch-M8 gcKX59".!E!jgsOzpuخ6?)Iӵ/ZKD9I $%̍ϧ|0`7pdI/:%4wLTw=-rBZPG&|'KQ0;^ " ]˺ǧ|"&8`[(!Y޴+Hb#*~&$ uM],v4185V{ y0̧L uGҷN#:9NA_j@dM04w&j !((\02_NEsϓ̳7ݧ"ݘ-I NCT e4H& +($a$)+(&!*350h&}{mѿ{JɘXٝ$iq~B-@zI #/65I.{$& &&ۣ(ߏ]~(n Sr#a+,+Y,I-*]!?<"!T mXe  [Y`0/FXh᳼}#Q0r   z>k \ ; ) "+(R)>(*--*}%*w~b= 4/YzB um- cg 7[פY4ԳO0g-c&ohA#7{BV]gwA"( |xqj Km hrQ q8<5 2 [ # ! o m 1" "a6;t6\f  ./Q}y`p= I'XIo / { y #CJ!8/|9&< 2;X[mrJI,f;W@{ L B Q  ;c K70 -_d "$E$"Mq[ 9g٩0)'F^/auK]5v -R N $3`^Q'~# T'+:"=pL8 > j' N S  [ j L k n v  1 %!hb%D_UFiwQ3ކH6O[Y*~RX: A qB`,e{{ n\NJ(&G|y[XOs   r )#:6k ]ha j0[7&Cc(f.\t V$ F I TIA4po = * CkL*l^vuN\N#kmr3,CSK/bwRv  N PCl'X5U> }DC9`/GR,t=;i)Q |: c)hJ\ {g ! j&,!ej]k.[Xxwdt}i(xy @ y 6  L @ e cWUHc%RE"zgfIcsFu]paf0bf.bauNO8?~.+p\^#jfd>:C:d~ e2 w  S R:w4wFL?Zry'4c0Zi%AlD . 7 ) d ` p H & Q1>dQ4dsDGhl+&>syIh sfozG]  # E!A!`mF/(6B(Xd}Nq% H3Z=\~eG(O8V.J^KY,s?G/^[|c)o4fE kj  sA;-[ @al{  ? L}ZlbFmtHNTKMQg:j=c9&Is+KW=F1# [dDx+CSbs*fL 3|B]p}\ E 0 5 8,AkK/h>bd1 6#IMa8gu|f  !~:II'R(E%jEpb/t%u3,&+XMrx5(|U)$tW-y vsj/6 ffewa"c*\6IQN\l0 0YB=7kjOBikN-J|Z`h4K{>5KDbRMziI,:|<" +wMU[}KxStpa#!\tq)643^x|l`374x,KR/r>@V[`2Y*s)(?[!&M-[Kv,>$ D(,@rVhg~p ? %b`hs`=P7 qF8X0pB-+H Cn>mM[<YS[A<+TkjR90RR&4>USy9CKJAUs%Fwo# 7xi H(V%9dD3u%|FLnIF+)9I Wim.AB"|wFW4XB5Ow+B9_c1zxWH 85aP9 Yg 9ZioMU K^M/Yl<T THP@Ulp^U'=C.E 'Ea[!Yr>j}#o i^ $C4AN6N7*JulF+:^4nB7>|cP~e*nUGkFX\{ ~'>m"F`<K%5cqv^"92M:]DU$z1t?.|G#Qe2$C9 o@EACj~55du3h!k!!2AUP$&$ Ap`%s!]k#Jsjq~WC/0IoVJ#O+KQy7y0]5@(P1m&Spa w;a,9_L6B Jkejxf& \LX(Vn_vveHeY9^D+dp<9YL{S 4y!- %4  bo rpvfhpW`2254Lt Rq!N0M_vj`yZ[`v|] Ba~-tBC 0}su1YD16{5nZgr<'/9Il@!HgndG iV] Vln|2Qq#*(/Ao~Zp"&>,j.&:qlbgs3iN37.LZ}]YPPoK&$iKkSKntG9 N}c93m +;@<4ey_k{X ifN""(%,#''G~M .3 X+ :*:|s'IVL/23=SZAl?Lok_SB(*PXqq=A58u6L6=''~cGL5Wspzz# ;`[eX&+8~S:@eQ ,^e\h(.=|oeB*:A=^zto\)pu2{zZ>:Stn4/G&TGkG0p"QkkxDWfJ~S(*T_ALr6IE=4Nh!R)E' xyR19NautjVuM,Wm:9HB<cBJe7 .]zaTZp3#JC;OML: ]#L/L ,ScF"@t}S$?&&EN/ (IhzP|UAi|tTN^s[!7?10M[> %J_cG zRDot~/,nl]{D1MaDQt|I\03F KP9l  :s\3%#/Mept{yVzkmt[;:M7LiQH^@ 0LT)wl_Q_kV, *"fJ0)EvR [3.%+ @pc3$Kys>8^~{|}luyqp[3eCBZsiQ+&VvyooybD573+8U+J^~,H,fIM``RO@d_m\=>_zzqpxk8'LWg>*J5@GTrx@  gS`gWK\| )83+! _roV2BV;NgV<4"/:60gMVr 4?7bhT^\>8w ]sdHGLE5wiluY' :7 'QgM:i0ei[wcH9(&0;,4%NTS`a@Fi]Hlzb^}{ibZONF.)%rE)>vt^T> *5Pi\#H_G9Qe]]x   " 5`~N'AHK_~~dB5ZdU9XUUE;PpqYSn i6"0gIiRNh}hww: tXa?)^s2K]mvn^VU`{x;)Howw\>9QuT4`QxmznVO^tx-1(',+>bqebZOWpyrsdWnc^e[B:Ti>iL0&JTOMSE:Vw 7QUH>Kj%*,$h5*;D87RkoighQ+('  $$ uQESg5*GQ. ,`uI ja}:>2& "  &TspWNMHE]O5A> wgxjNSjjXU{fj&9HLD:;GZwgZ[SI92<TlpJ 1gxfdx}aGGO@#(WxrWI?-#AG@AKR?" #83$%a>.&#(*#&&:b4$'H[WOIGJZqu[3..%(6( $5+  ",5<*.7BU[G1+' )BE>+    ".,9I3 $1?@*+HD9;C<%(CH?>KXU?2?XjvyaQS[XVP: sLQ|%,"%#,24-'$3DEEIE2!)CRI6AYQ18^aF:P_J!6OC//AG3  )*$!&# +4-+7.<=..7A?9<92/>W[G!  ./ jf{  "+Yv{k`lw}}hN:5EXZG76>CGNI:      tZXx&1IqaRl @ vvWRr (2  )  '?;'(6A5 3`gD*444:9)"("$ 1<"+# #(/)#@SJ.!  -'!,>FABPZJ20;JDEM[WLECC9.2?TZVJ8 .4')% $,.,,-12/0;DA77?@)$<A. & )1$ /:45==(  .9%  +/' '#1% %.& (0430+'1337=9-%,;A<:HXL/%-6)8;! #'  #$!+HK  (9)$.8""2/! "  $6HNG:0,-0;EC@DT^Q4" #,"&&%"'&"'*&& &+     $  " !   -9$ 3BKUWKA<?D@:8:88:4#   #%)03248;4*&,115AKC. $31("    "*%      '  -<CH>1  ))*-0+            %    ).,&'((!!0AF7/-2,"'1/" ,1.%")0/& !      (*#   &' '684/###%(&$(%        $//+'*,' $" "        '    !!    nyquist-3.05/lib/piano/pn20.cod0000644000175000000620000003171010144436365015315 0ustar stevestaffSYNCCNDNCOMME.79;%SPART???wo>^=̚=m=7ve?[?@WyGGRUP?@@@?@@GMAG:M8:,:7;; N:W(:0:ZW::lM:B:9p9u:-g5::D;,;A_; L::,::nm:::6:(:":;!:H: :9:^:):ˉ:];d;.G;:<:i" :P:`2::qj:`;2;Tw:d:1::::8:C:';k{;:G9 :F:߀:փ:*;Dne<===:=4=C>p>zJ>>J>65>?"a4?NRu?H??:d?Y;?g?L%?Y9?u?S .?(?#?9>8?q?j?K>9>r>%>Ţ>܊?s?%d?I_>T?F??*?a?p?2?3?b ??!>3? ?+O??;}?>K?,1?0}?1-?.'?%I=?"?,%?'? ?@?Z?_J?!?(֏? ? ?GQ?Tt?Mz?4>?Y? (>{>b>n>>aS>*>g2>+>ۋ >ڋ >?&h?6? @?nD?C? />>Oi>>)>R>Ã>> >6>~>! >({===>1>==rN=n6=8=g==b=&6=6"=(==vG |R=6=*q=R=y=<=8===Y=F2=AL=H==z==_=j=/=䇼=͋=g=r=K="=t= 9= !=&=><%q=z=tp<=!=ʸ=='=e=福=h=>iv=>ƪ> >F=o> > &>>=%u=_h=ܯ ==i=!=_=ğ`='=======X=u=v`=>=p=A|====G==y=jA=Qc= V=&g="ŷ=(g=-E==0Y6=2==h|=}r= =$e=M0=%q= =#[=#H=!u="b*=C9=Z== <;<۾.<;);h޻;v4%;"9;@;cp;N;};ņ;Җ; 8;R(;s;;[;p;t ;h&f;;&;M/;,D;)#:C:>::PV9fs0:::~i:$;5F;::U;>cB;-;;;_l;#:.;%;:}7:1;:\}9o*:5:O:J:_|o::Ǻ:M:K:v:U;; >; ; .;1l:z;_U ;'A;+;;6;IL;)M;-(;'?d;4;5:::::˯:zF:?:<:19rk:2:?:ҵ: :׼::F; ,y;g:;;;:Qj;';a;;3k:mv:V:t:VW:.:$::=:'5::z:4:|X:?:RI::1n;i1:#:;#; Ƌ; =;0R;q:F:;:b:o::Y:W9F:y:N}9?:].:p:2P:3:9: :::;UQ:o;H:uv:w:B;L:#:А;4V:C::@:ޥ:S@8}):qI: 499g9i:9G9#9:::F}::.T:y:%_::O:: :r74:?:w:`z:E999/8:Y9P9X@9+:Iu9b:W:rq:&O:6w:C:[:@):::H:;A::Ԁ:|H:7Ȯ:Ig::6 *:m:fޫ:>:>:]9W9~q:/Q::9:Dɶ:-:)#:ˀ:m, :9*=::>:y: :M::m:2!::wS:]:]z9,9-2:\:K8v\9|]9ў:>:99Z:9ңu9͛9L:b :B;:{J@:QoM:P:GK:0:}l94:3P:#: 99*:9 99b9M9yd:_q: 9@9F:[ݴ:B :iuL:0:r`:f :9,:ev 9q\:=92: :<(:`9o9X:R.::`9I9ϙ9%9u2+9w9: #9"1 9799x9q99kS979Vc9:$!:8Aq:9):FIB:3@:+s9<99:=8H9,b9N8=.9C99_9Q"9ʫ 8K9q9"9/9a: `93:P:2:89Y9u1:z9AY89[:+9T9)=9 99A=9O9_9PN99"m9R79΀9Q9ݸ}9:9:{N:t?:%=9^9j ::4i9)9P:%s:92df999 a9{5m9798k8G"49o99V 99c9AԘ9:Í:,9a:NF9#:&99a:÷9*8U(P9jr2989NX9g9BI 8n9p6J8K9u9; .9@8":9Y<9P989(`$99,9H99m8(9v9Wr: n89o9a9296|p89d9X7uWK879_c9S9h8}9uK]9ca89+B9f 9U9k9%_9˸::Z:Ϻ96:+~:^S9e:'d:YZ::v9\: >:P9o:>A:9P:g:3x:_|:39R:X*:4a:A9z:O:9[q99y:&Ȩ9ؓ:p:Fm:V(=:t9H9::)8x::ŗ:XY:5@9:J; z:G9cw:qU:Pw<:A::;%{:YF:<:`Ir:&9: ;n=&-=i =f0>AW>Mq=D>,>>u ?q>1 >v? #>x>>>M>>>>̱>'_>V?K?w?&?Y?z??k?vZ?['?Ot??v?RG>9?C?>#>V >j>؂?4V?DUD>fP>>>,=>>9>̄?;?7(v>>Tb>?=5>M_~?>?6w??)?Lׇ?y0j?\0?= ?NG?[ַ?jԳ?{?7f?9?n?C?w?FB?US?? ?,^?g?H}>?P-?3>|? ?0h>\=+>b>nT>Z>w>>v>>f>JA>+9>8>=}>-+=Fq>."->=m:=="=+=Xo=>q>L*=}>%>6f>]n>/=t=?[<$=<əq=<<=<\<8vv:9::*:u:; sx:[!:#i9A9::$y_9:|9L9(~:&:::m:.:ɤ87:bn: :9:*-:cq\:>):6o:6W99lS9:_&9O9v: $:9ɥ9B:CR::zm9F:s9u8#n:T9S::$p:h9ђ9x9aa:c%98:<96p:]T9o)99^:$@9FY9,92A9ޏs:R:.:t:VK99: 9u9(9ǻW:~989_9B9j:e:)59w:*:9:!>9tJ:UP:& 9g9P978tU9>c9:]:&\9k9Jd9D: 8:x899b9i:':,Y9L,9Z9g8ii9:YI8mK9p9q89:յ999W9X892b9h9H9nҫ9 8(9zv99g995Vw9|?8/X9:c8gC9) 9!8K9cU99?B/9y8ò9>K9x9K'8h9-"99R8 : 9-8dl7/v8F790899d7N3989X}9fe9&9298ވ9 T8͛9ޮ9S8N9Z59X 9(9u9j 9Q9.)9Fz9Cij9]9)j 979 988<8Ls:8b92~9 96Z91y`8h9c9yW9L9Np99.]899ki9)8ߺ499/k99v9L8v9:S9[;9RM8%<959$9=)8Y9K<9ז9b]8G+m8ݺ9A)8û9MJ9T8\8kU839T9-9N8<8ud98)99g67_8\8l9*s8MP9NS9 Pu8x9 88= 8p9 9W9$WY9T88ŭ8lj98QI98Q9\9$R9[9I88\9/(m8}98H998-9(E9G84f9v98q#9N8N98 9L7\989y h909 894988vl9v>9899"99raA8/9$v9>9Pa>9EW8:,98H8978{8<889f8ܽ9&=7M&[7pX899^\7859Rf8jjD8F8S88+9I7738ޅ888tv8*#88ߊ818Q9 9&89k8ڎ9489~I9@>S9Y^n79C!T9L98q8S7| 8k8Q9V788y9 B819s/m9J8WA8c9b9C698r99599$ѥ8T8297h893'88^*9!ߚ9;U9>8:8U8U8ɵ8Lҥ8>g8n99cX78 9=78N9849"G97`98Pi9J8x9\799,W8u88mK97s8[}8Nb99_d9-09[8Nj8A8d9v89vG8G09oz(993*9|~9r18\i9P98D98U9Ts(9I98PyS8`9Mf8p9s9P8^7y9&8o989.,9ݏ7ﱡ88l888ߩ9.8888}"S9OCx8~?7+9084928[D9?88p99*"9R8=8b8898a8n8uz89s8sP8)8^&=888c889_?9:8d9H90P8@N8i9>81y9X{8B&O86i89798ے9#U8=89S8l9D8e9$58k9&82t9K99o9:8If94\9v9& 8 -7i:8on919K9C9-8-M8~9ռ7n8zm8m98݉799 E8]:888 8b8u8p85'9 e)8|68L9E98.9";8[98}8=7 8 98I8j98q88|9HA8-9;:u::3:Ⱥ:O:qO::c$::F;|:03:>3:bn:7;::t:;e;;H;;Rh:w:; QU:;M9: ;;x:q:ܛ:s:O;SR;::N::2M:;S9;};;;P.:8;q*/;ޥ;ez;H;;F;/: +:\;%;;;1:*;UV;;R: ;Ԁ8ڧ>G>ǭ?k>#>D>>r>uR>K>U>>">/?%p?">>a(?3+?\p? \>:h>>f>ߋ>?}? y? 2?C?"[?>%6>r??'??>d?PoR?=?7t?3q?+V?8>?> \>I? /> E>->v>]>>W>>ǜ?&B?~??.Н?1D>? F>>>>>> >~?>ּ>)>(_>>>>jZ>l+S>>|C>4>>#=>>=^>XF>> Y>#> C>;w>$=T=^=^"=9g=+==L=3>= =Vr==!=]=wU :&6>:h:X:'3<:`/D:= q:t{:[9I:B<:2a:):Gj:A::\:A :$:c):{q::a:+b]:-:ٗ:#:G@:] H:B:5\:rV9o:;:X:M:h5:c:1|8:] ::2n9<:UD: ::2H:EZ:&:L:UZ:c:;:!:=:_M: y:P:K:H7:Y{:L':(f:@ n9N:\:^s:0:~Y:j+:K:5uP:m :0:&RT:IxO9:$]:>:r :|:l9 9Z:6>h:@Զ:ie:o~,:/+K:L:nDc9b:+:U09}:+r>:CX_9͝&:3:M:::>/:]:`:/:P%:Y%:uS.:P:.OF:'b:P:2+9z:!0h9C:Q1:c:o':1 :_c:=,:~:QQ:(":9:&`$:: :I:>H:c:G>:::#u:R.:Z:S:Xg:/a!:AQ:*rG:.uP:N:xc: P:*"9h:;19a:D:'T99y:>:!j!:<:.0::^:Bm>:: ߒ::5<:TJ ::8u::v}:C]0: : o:f:pt:(83:z:I3:::u:/:FR:3S9:XU:*:]:XW:: s4:g@:L:.::P:#:49:69K:U::!:M:zH&:%:Mg:He:o:%t,:@C:?]:rH:"e:B}:T:5:B,9KC:=Z}:*:O :0J:OT:+e:q:CIGIGFH??8320768:9:81+#   %!-:+292--.-/22@GISOX\[b_^cjkmojiio`OOORFKQRTVUVVHQB87.0/9D\dn|~{uiYVQMI@61&   #!$77@NJXOLHE92.+4,<?ABFGBF86>>8;5.+19>GQcj|vgVLJHHHINVSWYU`dcqtryzpcZI7*zjTB.1/2GPbjssg_J2 &*/-.76To(Gh|.?VtxQ' -Jdz|aXH852423CN]qxs]7###6]upS:(& .Sq #w`WQNSd$ vjZGA(uIB| i50?Q\YRH93, !\Fk)$o*g,mttn}pfG'~X9 %HsJD_lorqg\`b\_hs"Gq%Leurl[K:19[VZ*Mdnle[K@6%a c WY^3|kqg7|GwLTH|\^,.VEb-Kc n0h8 (UN][ U  -  b 0 n K 'QD JXL#|nC0?x){UXq_Xe@rh2 L$y<yX:tx(U! ={ ReN$_h>L!P}'T>GIPXwj6 X_z7 q  ^JO.u;/m5*7sz[ ~(LZIj3";q#1jm@KtkyNZ6nT);Fq&~ .mBK^d  _<#8C9!4\67h c" dKHf?<yk R|f",TlumlKi-M gA }}{c$TEcGAlp jjqxZ %MEi}Y1jN=L9a RdE>Gm@ 1 ] i : p  g 3 ^ 8 04;U6;!;PSD'_b1.^`2p s7{mj82nS^[?1?kWPuaEI`C# ?]YJg10O9k}D %cfIO#N (\%lS|mGsu"an#i!e@ t &+z._ybhu<p{b!!Px 3fc{<(zN[ odmNvxgP^ny)aeWij%SbcN'IH*#/n&P yog0d4D|5*U6Z ] * l  U EVDbG?;L` Z  % 2 - +   ' F {  ! 5 d D Q  \ [<^\?)*fKOj]/b`<+Qj#Kw CI PNIL.}x?1t0T>2Y#$;xt,j9}   M5 k*)K= '~tlc; 1Uw[5TkmS4i Zߩ@8rN aI X|9uJD >~}RVy-e< , = y>kU L#1&(*,./01l111c004/L.7,+*('%$ "!{ >mw+g% i \F\<>do;)zAIGD !y c +_S{*b6 6  p r.&y_>8D5d5Dy+fE\gc8ڇӡ_bȭŹķ*1&#S[ ΏЪvI[٬WaC{kWq  w%+j1u6:=?>=;m85w2u/-,H+G**))(U'\&K%D$$$$1$%]&/&&&.$"bN s 4Wj,ߏ!`7۠ܥHt!f?VY2-3kb<;v4ItSx t f "%)W,m/(1368::~~===˽o-0| Z6ĔLJ"Ӑ,* <l2'F   S g!2#&A(*-/$133C5N7^9_;/<>>??@I@ABDFI!KMOQ"QQPO`MKJ H?FDB@b=951},'#iMC2PhO ;T]1^qyq?%%mVQ9~VDisOc< ! 1djZ]{O $nc EjUCIlsT m 8tuQ<2~sy|LdS& .:b^39#PM2 Q,|6l j oY.E V$<t !#%'()&)(M'%\#S!,sD`/ANY !"4#y$%'(()*v+)+,-P-.--+)%! 6R=&}7MjkEiEw5c0 A/f^ E&!*$&(**++,C,-/v1t36_8;f=z?@2@AA,A @@@m@?c>T<:841,($ D"B= B,.A1֓*DЉ{buY)`B՛7ޔ֓O,劶hRh Č̏& ϡ;ꪡGG>ǧfWҶ^?@B2  p%"#$'C),/"1O34Z55@44210W/. -5,,++!*)('& $H"d iA+ e R -AR!Dێdٟ87hٖٿٶّ\؝,:;׬^Rڵ܉[L|Fg-KOPF 0  Hc, Rz*"tjWFg=HFH (y  2 6N6_u CsrgS&NxKJe2E29n%c.4 ju>j e c M v + \`%  qdxa 9 )  1 U`1FWD <-osp,WfPfCSpEyM`8zM.#d $ ~}/P X"%(!*i,e-/)0011242579;~=W>?@s@y@?a>}=<;;P:: 9`8W65 20[-*(E%#!}l*  n 0Y[U%Jhr&(jfS M*>9!b,=3K, %/- 0 @ d (}-u(y!#%j'9(*p+-8./1.23526P767777$643P10V/--,H+**R)('&@$#"B! MiDF;^ :;Hߺ~Yէϊ2x]Đ#k4s>ÙĽ7p=YӮ&ڋ-M<;N-!fMvJT|fs] ޴݋ܔ۔ۈf04ie?Xxg qUXro*0s`ރVhR߾Jp;44% h O D 35?AOnulGv 7mY  om!j@KVGO#(k} N>Y'Z"L+/  ) Q m '083BT` +Pft;dݠ?JvƮŎzĕKν¾-T]¾xǨɬYlmDFeb( #'q+/x3+69B.FIMJPSV1X}Z@[\<\]\[YXUSQ2NKIF B?<884 /*%} mAZ4$N}߬ĔK w>xXħէ l쥂3Ф+J5[ϫG$f"HǡV&3i"J TS; &e+1E6h;A?CGJMgOQ7RZSS;SRuQPLNMK/I2GDB@I=;9P642]0"-+*'('+&%$f#####$$w$%g%&''(C()*?++,O,-J-t-Y,,3+,)(6&H$/!*VX I]i l/u9q n4?~&<r Z ' _]T67 U!z"#$J$$$$>#i"^!%~(/+^cb"!$:' ),0 356y9=|A@E'I2MSQfUnY=\_beghijk'k}kkxk jRiWhfkdbm`"][QXVT!QOM2JHF(CAF><\975Z311 .,*(&$#$!  (@](B%f.OqGp0  5!#[%b'),h.1!3,46L7a8889>99:V:;8;;;;r:987P532*0U.t,*(&p$0!Gy6 L =*"0%o ՙ%eųû߽*V^ܱ_%vϴѵ۶ѷŸuD Da. -A_ΈОҭԪ֦ؒlU="!~{`6uL2f,; 7/AO,p/[aT2Mjgk ѹqG=ޚܱٖn׌֫֋֥׃C;s݉n:h!g3"  Pa9m "E#$%&,&O&6%%f$$;#""! -b[5 S {sY8Q=VU 0Q4ߟUکٟؿ_z&՜xuՎE X% Fw NTk37HT5nQ߾y ܵ1ݱxfYxyu;t?T_ Z B#pL "\#$%&x&'V'''''''''''''L&&&)%%e%$$$%%&%M%\%e%X%3$$$S###,""~"E"!!!!t!a!I!*! } e B H)kk.! & !!h!"F"#$%'U)#+7-{/2~57:J6"%L(, /36:H=AEsIKM'PTX\O_cvfilonqt v wyz|8}_~T%.~T}<{z2xRv7sqZnkhesb ^[?WT@PM>>?6?F?>> =NfBeEs=k`>) PD4o=UV^5j<[CS.=|Bo i3bE W !G!o![! q;H Ct S,oԴ U̯pOȽNݸg\߯tKS 9RvE #K@(eTέe# 4M'.iL[P܂)qq{?1 O ` + W C4:ljP4*>[ؼDӾd-:zGm ˲fʤ%Ƀŕ*œ ҶVX;ءq[J^ou ?#6 #D8^CퟴGٳI*ΤKNܛjZ{76J\`UX]TS\^rīCF e Wkf[BйQ ߭xSXQ S  (.;M<\X5 WfiTSNp  _oX$Jp+fa%zB} i a48) x7~G_ ׺֧ժ2҆ю!v2ϯl-Ρ_͖FS# 9k̫`|4Iԛ ל`A0PxN# p >j kC}!>#$&s(1)+{,./02234M45M556E66676666`6544a33%2|100./4.&,+*4('&%#"% w7=eGUa z a w   ; F K*~ \ A  9A^o!L#D%,'(*,.02t4G579=:<=[>?@ABCDEFGTHHIQIJZJK:KLLqLLMMLLL1KJIHGRED.BS@Z><< 975520.1+)'%y#! 'zv mhy3/l "\#%')Y+6- .02B35E679 : :;###J#"""""##)#R#v#####$$$$$!$%$<$\$s$$$%%W%%%%%%%%k%$$0##"!!R # pHZ-n6o)mS5u"$ qBZ C!"$A%'C(*x,0-/1t3I568:Z;=?@_ABDE%F1G9H-IIJKRKL>LtLoLHKKJJ%IYHgG`FCE CBV@?F=<:V865G32 0|.-e+*y)'&K$#"K!sqv xL{mXRB84$ ?osIޯ v4֘]9γ6|9 EjٿaYԽ>YG߷*+޳6OnծK?άP䫃#۪pG"8SxӪ-j;pp<Ա|$ʳp Fضf}wWu߻B$I= LÏ;ơǂbL:̜ImEχϵϷφ6Kʹ>kʂɝȮǷ#^í„ ƒ*įŠƨǼ8{&ЕӡFصڀJ?`$kYKqpT: Dm ?b!Fsݞ-ۂ:٠ ؂א֎^IPvֵ y؞Nۧ܀tg_S?*!v#Dd~"Z??V6#,!)& qEq t3b9S\WS9*x#MPpl=VG#@FS[UPH]}؟[cΨ̚͞˧Cȡ!{btDZ$ɍʂˠ,Ϟ3Ԭ֫ؾ\~-y?M.  R  !F"$u%'((Z)b*D++,P,-9--.+.b.../ /L/w//0&0b0011,1a11122U22233&3+3222311'0/..-0,A+@*4)+(&%$}#6! p[F?  _[ARO2m !#$?%m&'()*+,k-R.'./01h2<3 345g6678F89:V; ;C>?k@@@AXAAB1BPBWBLB$AAA@@?Y>==<#;$: 8765D321S0.-a,*)(U'*%$#"! Gq\ 1w6sIA#JitX)gI>wG 9wTg"j D !!g!!"!"A"R"P"L"J"1"!!!R! OS7x/m Lj~wkI ^:1#$CcO8=\:|]J88E[y(vk?r+ K~K(h$ 4!K"F#C$.$%&'N'()5)*c*+H++,,<,@,I,R,Z,Q,N,N,F,5,+++W***))(k'&&%*$(#" }LlA~vmw > x%w=  /_X  a + [ , e  . M [ _ T > ,   \ 9  K eAC&jt<(aLz~?\ݤ_ؼס֐ի(xQeЙ&ρ>λΏW!ͣ_!̍eH.,,*(70-˹˘vT8)*(=[˄˽L̚U͸#ΈlXj|n%qԠԥwCӶhҥ2Ѱ#ІJw̧>r;ũċ Ѿs0J…%}MĴ&ť*ƫ)ǣ}!iɣ"dʒT˜[̚O͐%lά6rϰ,fЩGџweiifP׽*ؙ فj6ۓ8܉ E݅Lޞ@ߜkRJ=-72}a*m(Qmu_P7!d0|#Sm>{+GEHF1V~7xw V SF7$& L!#u% &()+,-/T02$3t467a89;?@ABWCCDD}DEE#E7E?E6EDDDLCC!B]Av@o?6=<;)98N65o421-/.K,+F)(-&%#"A TC=P9[s1 !"#$%' ()%**+, ,-./0W1%123C34\455]555555555555d544y433/22100R/..3-e,++*0)o(''E&%%$8#k"!  2[j2lB  d8 JrVNDUff c>398Rm$i5 @v  / Q cs|}obX>v?3OS*1ku)dZCXk_]+"k f ?    6 b QY4 Mti0~-=aF 2e5Icd]VB*|]2a|)jbu<rC!f7}L0$ d(Xr7 ^3 d  W 0 Gx2^bQjPEP[X]q k>Z+ig> |Y'dn7SXd">jP`1 ]/|V- j߾O\Eܷ.۱2ڸ2پRQ׿*֛^/ө(ҴUѽѐd=::MoѣZOԈI ס~opwzݘޮ߼ 4j1n4o!&Y[w{MbCslA^y?4 vR[DM+sb06`+p} j 6  )0gDrjg~"x>  n 4  r R = .=!L?;fymW&tX6 da  % N {  FTP>#Y l0oP_0cX dF5c c|N"Fo"j?U_PeC%~'vcCP t#?OSswE oUB74;?EMXm(pKJs[\5kMw2Inz|nd>u,o K <_wv_>UtJ2`*n5iE#~v$J[u)k4ojxu9@OM>W l D % Rbi#C&%O,t*VzGQYI&/m !     04CT\uH SX8%R(rh~8m Hf+Z j&d,(Ms#Sx6}7m,IeAvE~-n =w81@CCSZTMVegS&Bt@ D  d 3e:I9w?afbsI 7 d n 8 n\=) k-h"UT$}{2nK N8> M !E!!""L"z""###G#i######$$$$$$$####h#0"""{"?"!!u!0 DMh&u0;4HF=;*^] n C  m 2  ZC #\o)tC+e9aHwI<8v + x 7 _ * 4 X5 SI TuaC-7<5DIJRMG*uSG*c9~R!e1 ~ : | H  a 1 w 5zP%EspIKKj!:s8k A8D*cXR_X=Z"~x*=q9|[:Z&iJ2$  (Dk9u0DS][`WSZ`hwutrcZMH=IWi.;Q XD z#9] } k9?W  v  R m?Tt%3vQs{jE/ Z !!f!!"1"g""#%#W##$ $H$y$$$$$$$z$W$9$####S# """""S"%!!!!y!R! z E e(e<Y*vChAdG2#belCY&Q2rM%Iug =a 0 M s  PF?XDv)~#m2Kz#e@tR:) 0H_r";Mq-V} +T{ R%cCw-Nm %@Xiqytt[C&p@Of0`> 6QiJ]P<Z6I-?[ / ^  Rl Z)z QGCwyP7f=GS^AbD4' Fu0v5 n ) i 3  | E e 5  y P &M_'\ x.7GQ5x63,1ND`C{9V g6EbUxU)_6 {cD2,Mr(Z'Ny -Px?b2S|?{6pJu4Tt .Ld!OwgT3%i5k*LYp/G!zE }1 ~V%wCCJJTI:5mcgq8EF6*8p 3T}?m,Op#;Rk|  B j + `   - > E M L ? 0  f >  v Bw2\hA)vU7 v_dcgq"<_%=HI9 dJ3* K r7s\Hq6|XA!nP3)#R!,Smr{}phmqw7?Nfu#<HQhmBb{2_ !z\5 0^Gj4Vvfi=NQS8s> q'?/.G=l?8o!8{Y]&t4k+y?rN8 ,1;2 i4nW4~<wE^"dJtV<vE"'5Ximyvply$Rt>g)\0]!#3Cg-HM[]G/%#=\2^{wsu-l)\?o8e-g. k@)d&[kn9v5q9_Cl!!mW< #/;<6-%#"0?gM$J]{^`ruN+{ 5 | / f $ g  @ ^  = d } ] F *  s M  y o ` V C = , c N A ,  . Q ~      # . B T f s x k [ X P C 1  r Y H C @ B 7 1 %  h sE)  bB&[:! -@I_o| $-:=3' j9~d=lO5&&3AKLE>0qhM4y\G5*%$)" zaH205?O\`_I00e(/# %@Qp{}j\VP<, }wuyqpe<u?yT=8*xZOA::DC3- !6Fdx>_|lE,.Irygeadmc\ND@515AOa|4R~.w I7DeU'e;o4OWRR\^uwq|utjXJ;'zH|W6?|[I96.h8rh_d~Bc};\y8Ut*UxuTCap)z^H*DG vN-fp-zfG1/.9LhzsS' vbJ1tM"{1,zt'yKqUBEVS s/\2 {z|skc`[PUXavEn =`W~8nU.-2JL_)HS\b]XQWl1`%*:I\6n.Dn!e;y?i>{ JR/l`'Nn*mJoHn8Ugqs 3Lp=`C*g=a-n ? U  k  ; m 0 e  O Jw $7We|k;pc?U D w \ B #  z T 2   ? Z n k U <     2 8 P c i V C = 3 0 ' , : P x q W @ /   H  K S&TxfL3x@fA- $j;{d@oZUC<+ Y/JvK ^4Pt x"8Z3lGPd&qQ/Am@w#2E[sBk )9_b2o 1d8OYbpifqz'U<[uJA $LuC~-h"Erd&s$O4Tl    # . - / + 6 3 0 / - / / : ; P ^  9 U g n t w l V C ; + - - ; D P m ~ { o c h f o  = [ u { ~ h H / !   # * A [ u | i M $ N %    r Z A = < F J N W I : "h6w\XVD2\'%#$ d:FrWNLGIVRO6fsN7#j6`E*UzJ!eM,kP1 w_>zpikokiX; r[?' uYOPPLMX\VLC9hehr{%6K`|(@]|MT Cx >~Ax%Md8s?{'>Pf5>U[a^\ow+Sh{wy~u+??:89;Md 7Ultidb[U]%eJ ?I^o\KB75JJ_vqC"h2^;-*.84*I j>.+&//<-xhg\e{kT?)  si_WK7. nBgNID*e8kA ~`KRQS^aegd^UQNQYivzovllxo~u %GQdj_\N5 #9A>OL;) 4MbkebWQKA4+5GVm~ne^RA.{Z=*! kD3iM2 " )<@OfjzX$e "$59Hdj~tdS6 [7yP!u6 z^@j )4'-:I`)\ *?OtA_t&K}45EYi{{ni`QG-"  )8LSI:+XkXR<) T6 %=L]l~qWC0qjjd\JA6$!cnacfh~u|}vg_K*tP(uQ5{TTzfWH-uZJ=* m5gBrwhgf[WL8. 3In,:P`u-Mr*Sx 1MhA}-Nd .f&[.Lu'Jg#)6JmEf2W1\ysePFJCHOQUUQ>2'lWF9*#$$.96.*S'zzsE}fHDIOYhvsqcK+l_R3vJhF&_2_X"tdXK:-/ Y/ qRG<:2dC(tcQHFPWk{xn`^fZ^bZRE+vh]bk|}a@'&3F[e_\[bleq}|v_D"2\*<<@@,  *2,)&6*  1Neuyrs|pa[[_qHmzi\TDMQ^v&@OY\`]X]YlzHs !&Lq8`*KsEr)=Vy#>X`al 0Lc|(Hg9D^q|}+-*  !$%"zR0$ \A$   _=(!6H_sU@6.$'-5MYbppsr}xcZC6pP4!!g0''% |y vqdO1xl]POE)'&"2_>_{,??JY`lq ;Z{+=Of{{wsvqw:L\WV@1   v} !Nv ',>NLcx/>MObqDeA`r5Rpyt~ #7DL[tj`[[^bk!3H[h2@Zq{}zxx;PYirw -24--' 4EWddddW:! k[MGACFFE7&L eJ:#kK;&    #$641/ 488FQFQXbTVg~,APTOXSSLNK\bg$03%&!!|Q( {WC&zh]TQS_^kvutX- fJqaK*[d1  wT@2& 5?EOPQXP@:.*'>CMfu8N_~ "-.1@BDGA3(  :]wxaH" wd[WUcp 6DVWZ\\\]a]`vs`Q8|jXJ<'pT5%~gL$eK- nWG@98:FB=>-t^YTEGK<@;:6+046=E?JLFNC;.'*,<;HKPbqyq[UMRMZo /e~4S%Vw?q8hRu8Q_icllsy#DZi}mtor5o0^ ##$$ ,5DK[w&7Yx%@FPOWZNQELQZpzokughhUVWWYXUWLFD:9'}mmw}m\>" ;P]fmjTI=3"$5/CdwsU,0Kav{uaK;#gZG3*,"tZFD8}WB&suo~ }lV=* Z9%  zccfm  &19EOXZbknz $7J\k  6Ogx}i]TE280+0:DKOJC5!iK& $B][d]C9#7@ABG8"qR4pO1 qM$ -XxI|e]XRWO?9,#22?97:;,#&(89GIB5*# &418>4*! viXRR]i|1Wbkomofjov} Mr)\'L|-6GXw3Oay)Mg1EFI?8#   0PvdRLHF[jy'4Pebovzi^[PKDLPRMUOIVP[^n}wM+  4TujT+vZ?'   -9040"r^<+ #;Rcx~zsogab_n0Js~zzq<oUc`VSQILC2)#aS8veVI2+  r]G@BDL^q$!pE" {{{xrkVC& Z7hT><7, |`?\:   uRJDQ_k~uP+tAuW;f]]dt{qP, !'$,1@S\ixpihYN=RRlvHm #8Kahpxtwyuryy|+CMY_l^TQBS`m   ':Mf|}aM4rX=|P2 ymeebt#Cewvphb_[el}|XE- ",7GIMWNRSWd^p!59DQSXUUOVTaner~%6CJIMZj| 3Rr{lqemx@RZ`\VMB;Mi{(<HOB=B9/03A]|"a -OdLq$Ic~x    $ $     & 0 1 + (        % , , $  tUH/,:MXdb`ZE1~\;|uiVG=;1#r]; oZXRE4)U!u_WF:%teOC>9=;:1&w[? xN-mZO1pP4&xkb\SN;2) ]2=Wgy{|}uvxhimglrp|jN6# !&6Q\abN5g:xxz|}}}{vy~vsmg]WMA:795JUbku/:Jfkr|ui``^dk}pocVUNFAIHQo~+?] 'DT\kpw!/WyP} '0CIIG:2'&!"'+7JUex 2;GE<0 '@doJ{~dK5  +*+$ $=Wi"#  :Xj&=]|'Kk 2Pu-6!$ti`[g{'G[u{lbO:" ->Vhv|jXD(  )BX[_bedUI3+'%(74, uz|zv}}zwysrbeUMUOTZPOKG>1$"+$+$ 4ZutL"vo"W'nh`X^NE( sV3'|X<|uknrp}mcRHCAPU^jysueeaheempw}~|yurmb^VF?;2&&215:@JJNUPMH3'%;T`m|&+79DOUVW]ZWR<"pN8{]7yS2~~vZC,"$maL0xjg]QW_lr^E1'.::-nSB mX3 "  kRNSXjyrov7Mn  .W?g"Qj (BR`eVNC82-,-027=>FIL[hz}-O!/8?GEPNPT]b\]UI=/'(+5C_{ oknp~kY>zrlhyoR5(6RfdjfVH@3**%iG*}fI9"|h8~sqa[_Zehfnronm_Q<% rW9!~sldOMIBAINKWTU\O@=46>:BJR_o}{ysdhbdopp\?" #>PZZ[YWTRZT\ku  'Hm4`$:JUJLQOKKNIOW]`j|0>E<.& (FVm{t`LA-#Dj;g '4:CF@7&*%*g=#  iWH=<:-{}~~t^C/bAuFqN2   '01"~?"|}u}}hZD7%/39>8@6.)'  &/FO^o{.C`m5Xt/BLi~'?Uf`]O<0  ,4IYknjjbZUW\WQP>-T8-&5V~#52("Cm&GipaF2"{m]XSYdosw{wp_\J7(,8Kc}m^SZZm_2   #.<:80$ (0Nc &/3>@FOVXat~2DPTT`jwLq'*6H_z7Q\p~"Db||yrxr}4Kau!"$+9IhveYC }aBn\A$ ~jUGA8*$}NqR=53219ALFE;)eI7t]I, m_Q@!vj_fjpvjTPJGHEOPJ?(wqunvi[KF9438BR\j);KXYWK>,(C[z~t^TN=?@>KOR]VSF)Lpjor~ "%&e?/ !*:<3*!!0EJVa[]QB5xdI$"=`*I\s"J`r 1Wx(Ip *9Napv +P+Gct{,V @Yl}ug\WPL<@8-+%6UbvqgXMF<@DJXYZVB7%dC)s`=waL,~cS>0$gE%iL6thlrx%=FaYXcKL?)dCX!{dQV[LXgmuni`HA@AQpSJq}{ugaF54:;7HCJVUabfuOv9Q{ 8] .]'Qt6i 3Wl|eP7( t[. u]H,zYB*  ##/())%0>Rcz"4Liw CegP2S4  &7DKXakp~.alF)uQ'x^YScz.FNbkjlxnJ2f@cH#=\%8Rf{uY4cBrX8 }_E3( _6{p:Pj 1J]p=tBae:yh[K-Z/b1i2rrS*|>tdAt K .JcqrgO=gg3T"m R[cXB0.3.:B>Nbp8n 4n(Lg '3CJGH5%W8VVSnT7{~gB!6~Zs[bt t^ a nQu( sH'}@ @nk9M?L{h1M)00$ Bu4U+ h>- }oX=/ eUC/% &1Ga "Kx#~I<#18AH?5k!8}!Iv/h[hc#^XBzO)Rh~ &Lj5 2Z|e/DK%~+~=owP3vR4$ }DM6RGdd<xmfku'a,>$>c)lG* h  ) (    R Q Y &7hZo=!.LBdlE[(X*5 &  @ ` n ~ g J  | %@CPq5b[`)u''z'],iD-,f/zp,Sy@G<Tl.)l&|3+dpR(fyk=77m x1}''~!HUh)n erlN}H{ Abg>a2 6^Ep )Mfws`ZL0&.7@Xw0],fNSU-o4v6Y[Z=3dX<vBqN2<~. _t5iC"pSW\]$W ig!b5,YdzC0Z*5}br;|!^LM?j;fH= Ao4Mpc/]jBt$oE{,O7CQslT7;6_WZ'6qe= Xpwg LdaV\q+Dm/=7,j=T"] H+je@(&&2:Ps ] |fO7%|IE$%K3|^E2#8Fq5j* 8U^O<"|uhI H$Q{ o.j[O Qa;X7U X'9hUJ*0Kcv ~ _   o :k ]_1o'foa=o#||Y[9Ad#m0T w JyY' N=YvB\8W2!*ErJ9[#j"k#9lo<ci:x'^t+r'UNT4BoQA\g"zy 73E| S*g3KYn}y}}iW- p9?S5!O](X0!4[eU Q\u6%'qR}  j<w7ID,}+`I4?RjNn|;~3bi D d V , H S \ C  c  B ;krs?x>O }3 Fk1v''NFQAU<EW_`P/l0_\/X$[8 Al>hy?C+r]\L?2&  #:Lr+O}+;BEG:+xV21j&Lm %H_~g3\?gE%<^'7K`w4Px %3<A?4r?~[0{a=o:_+53 v['<Mq"v!BXktyeYJ- ~O}2v6 a1>U5h7tBMKkZ]RtY Q/H\bZ=o rHz+>8Q6 *B[i;q1`X&zw>a%;MIXRJC45({@/b9[% '9c!Ea?e *N`kv~t^R;'iEY^cjI;1&3FRq:X9C;?)$%"5Qk4[5Txs5:$K3Os$@c6w M!*, lI^<zX?%Cs=Si#>\nrkbXI@3& b_Eq`K7117@@V;uXwZ(tS5QmvuucP yE hG:RzVFi$GvH)kJ|R. >e3]L8][C ).<C8>ABA8+Sz!7c#^"]0P(eK1  -9Pex)Nn)M!*/23($2GTXglj]H7g?*v`2##Gc! @}OC6u#PP%T{}jYH92* z15j7Vr]0$cKp:Sr !0Y0rTGs$LsmWC'h,4R}_T\gr{#;Zb| ##1(3BKTert}}sd<~bI8/"{xm_WN;$ -XIw3PsT?e[)AzE&-X|T(r[\\\n.c)Oo!4;FAD5%'.EJLQU\PT_\Wchr~kS@"^: iK>,  ;\:d 0R{B[t_?ydN9$xXG?8BVn>} S;8}7x(UmVA,$O$t5~`J6/2Jdv&>[q/M\vxqgS&l3q4W5e8 5g*DX`p~>Zn )Nt~oCM*~mYB-~I'sfkw=olH7/%06tX7pW/?O |N!ubL6"%\&Hf~ .Uo-Mw 7\uo_F;+#7Lh|hH!X.v7Y( 'BaLQ#Hd=RiX3,>VgefQH7$)7M`w~aC/.CIULD7*Pg~||&Mlz}zvd^fmzrUA1(#Ly3YUyh`fjltKs0a:},` !5Mj2\z{ogVOJDLiWt;` T^Do8,}ruv'V"yE$pGPQuzhHaR |vvhO6){WK@;C?GKIMKLPURWTX^ijjomvh~nyquist-3.05/lib/piano/pn15.cod0000644000175000000620000004737010144436365015332 0ustar stevestaffSYNCCNDNCOMMD\: .PART???????O.t?_S?F>>uD>ʈ>3H=(=7=b=QR?K@z @¿i?gn?d@#@vV@y?"@@x>H @W@d+VO@GRUP?@@@@@@@A?@@@@@@AAGMAG8=ǐ>U>ií>>G>i>1J=]ۜ=q>/>>)?? ?'T?>u>m>>ȭ>>?`(?e?i\?U? ?D?/?1?)u?.Ǖ?B}b?X?e?u?n?|??v?m`?hV?l ?t?w?r5?d?U@?Iv?GU?M"?Rt"?Q?Sq?XJC?Z¢?^?f?k/?j?h$M?i)?nO]?n^?m ?om?i?al?_R_?^?\?Z?Zk?\ ?[v?V?Qh?O&?Ek}?>?J>+>貍> >U>Jm>l4>W>Э> >@>>>>>I2>>v>R>yD>nL>aa>S>F>>}>6Ӻ>/L>*,>#Q>>>> u>.=E===Ӵ=zN==uI==E=i=9=?====y=j&=d~f=_R=W*=Q=M=My=K/=H_=J=QJ=U=Uj=V=Ya=]n=b|=i=p=wZ=x=}=/p=a=$==ν=Y==]=L=.=b=S5=i==:T=A=i=<="=I=,=s==P=H==4=ج= ====+^=l|==\=/=,=S==D)====E== ==0=e=2=̫=sb===}=y*=v=u3G=s`=o"=lx.=i=e=b=_=]^=Z=X=T=Q'=Mz=J[=H.$=E/q=Ah=>h=:.=7Ð=5-=3)=1em=/]=+=)=&=x=@R=B=F=3=====lL===[=<<<<1#<&L<X<< 2<%g%<*<.<3G<8<B>R>̄>>GV>>d*=n>|?U??v?Iq?=?D?F???fo?J?iH?f&?ch?|O?r"?^9?_+?hq,?P?Bir?U?I?7G[??Q?Cm?L?."?Q? ??)? [? ?i?>U?? ª?c??}??}>?>>.?9? >v>G>"e>s>>z>z>|>l>t[>3>>z[>f>>eW>Y>>p_>䍋>|><>և>fW>>>E>Ԫ>d>>u>>>T>r>>s5>v&>c^>ZI>RG>L>8>1H>%B>u>> > s=K=R=H==ݏr==$g=P===Ot=l=g|=^=m=Ro==h>>>y`>*>>0>p>4>y>>m> d>>z>>{`>>\)>$3>#I>(x>+u>,>.{>-"|>+>(>' >$cR> z>5>9>>3>>> y>>Q]>>==h=F=Q==Ѻ=Ҭ^=qL=Ě=_-===4l=2=S= ==,=\=/D=*=5Y=T=c===6=====|i=t(=n =m;=gi=a6-=W`=O=E~c=6B=+=". =N=[=Jθ;@9;L;Sq;ZgX;a+;eU;cy;g;h)8;];h;\6;^\;UO;Il;IŅ;:;7|;.!;%g;';;$;*;!S;;*; 5e;;;yb;U]::!:*:RN:۪:C:ْ:`::L;;M; x;m;B;;u;;+;{2;$d;m; ;(rK;%q;);$h;,H;2L;*r;15;*g;+W;%);e;!+;;};; @::::0:6:):ȶJ:|:P:X:#:-:d:z:^:g!b:;5>:#:x!9X99:+99n99p:9:9F:|\:&b::0:7v:Fp:U:\-:f:k:GB:sI::w):y:(:^;:l:R{:bj:C|:1 : #:3":<:fY>BCU>` >P>? f>>_.>>>y>?t?T??(e?B?d%l???a ?]7?c?]?R1?GC?@xU?>lT?9?3\?'~a? PP?~y? ?>A%>!>>>#? f? $? b? jz?|?h?n?|?&??;? d???#?m?m7??6?W?w??w????{?"??Y`? ,??5? (? 3?>>ﻈ>̈́>l>>> g> F>>n>ײ><> [>3 >L>R>>]U>NB> >>\>>>C>1>>+p>ܚ>>5>>,>/>,>>c>>o>e>>z>oM>T>@>#G>R>L>L> >=a=%==c=Â=d==̂A=6F=&=1 =C?=Y=p> >E(> 8B> C> > K> > >v>==+=1=.===%!=K=*D=S=͗==u=3=4=8j=X==7=%===4=4R=l=1S=a=@h=k===k=A=DY=s=y69=g4=V~o=J=Ar==v==4#=9O=1?=&m==o==)== =ݝ=G=O<=`== ===e=='= 2= q= 8=M =Y= v= N= Qg= @= ===~===q= =!=#=&Ug=*^=/=5S=;_~=>5=?~=>=?O=A=D=E*=D4=C[=C(==B2=="=71=38w=.7/=*;}='2=%==== Q=C2<<<|<:MU<6Z<1P;>V;Xyw;n ;~г;X;HZ;;( ;;W;;s;l;;{;m6;b;;\;%;7;C];;;U;;x;+;H;@;;t;Ӗ;;v;E;';d{;<;;~m;L;|z;~;B;xˏ;qr;a;Z$;Z;Z S;d;_;Ry;In;F%};@^;<<;8~;:;4 ;/t;!';;=;8;; };;):δ:::Mb:ϋD:PF::@$::4:W::C:k:R:W:B0: :H:::W::::1:ٟ:;:K:;zO;F; :;;CQ;G;;;&;4;);Q%;)LR;";) ;-L,;);/;+P;,V;/$;-;)r;+;* ;/r;/e;+; L;$˻;$;;;;;;Q;;r;;;Q&; ;/; ݃; ;2e:;&:E:sV::] :3:f@:w:w:y:G]:ǚ:V:I\::l::::3:Qf:A:Z:_: : x::&:{:":P :s::}ak::r :z=v:ih:tl:y}:B:v:]Lk:wF:}:}=):~:|^:p:_qu::wy:`^::u=:e:E:i':;::9:0b:!::{:{::F:::ɼ=B>>>3>?>~>G>X>&T?bX?.A?nz?eNH?iZ?r?^?U?W ?c1$?P?Iv?4 ?V?tQE??pf?l=}?D?<]?6R?'9??߯???a?#^?v?yM??$?34??6?A??8g?0A?'e?'c?%-????b?O?"M6?!]?r? Ƃ?^? ?t??NI>>oZ>>ҫ>β >>>u >7>\>@O>>C>>>>3|>W>1>>>a>>#>iH>LR>>1>#Y>k>>*>i>>>x>>-3>+>->c,>n>[r>3->L_>=A>v>Y=(=K_=--Y=o6>E==x=[=7=~W=[===(==+=Y<,Y=w&.===˽= =ͱ=ڠ==뻩=Ʒ> > O=[=Q=|^=s =Ҷ=^=<=H=~=V==d=?=Z=TT=n=d&=:=#=i==(==N==E=X1=PU=>H,=&9=="yU<<;4;;߁L;,;z<;;;Y;;U;>O:;(ߥ;;3;Ym;hv;͛;Ï ;;&K;(;8;mA;޿<,<)8;<&<0'<;r;g;a;;;;h;sh;PvU:kg:FE:;{;$;U;;;Hy;r4;a;;;;S;;6;;=;;&;gu;;5w;;y;6;Ҷ;Y;N;;+;D;t;;{uX;;]Z;Q;CN;S(;?;H;9;0p;ӝ;G;;|;t;w;;:];_;*";;;r;P)W;4H; h:::1:"$:"X:U(:u:rx:6: (:8V:a:FK::t[,: ::":f:}::!:<:6:0g:):::n:U:<:v:d:+:ؚ:׺:ñ: :<::l:ҹ:ԧ}:d:::V:u~::(::::e:i%:OR :1t99f99Uň989w#9I9G!9G8w9Vz9H[:fs::]:&:7: :$:_^:K::+::I:C::̰:J::!::@::Y:N:::~@<:L(::-:ʀ:Sy:6 :;o:9g:1ϫ:(i 9J9g:r:F6:1: 9W9 #98O9I9Ҽ9Ӛ9;U9IG 9-9C99t9 R9K9c8Kj9R999m9ئ999f99İ9ݚ9Wb99919>SC99(9 9;@9M99Z9 H999M7:9+9:u99h199-9O98?9$99Z9 D9GV9w8E-8G'9818ԯ8/9#99#9z9݆9x9Fȸ99ZH9k9U#9O_9.9<: :"9F9"9B9,9,9-9:9;m9kG}:*?9-:9m9ہ9w9J9T9~Y9_79G998=9N9 :8}9mm9*:9?69rU9S8897-9F9%]98f9e&M98 9E9M)989C99g 9Kfb98ư9s9Cj9C8u9P9'o9^9Q94b7I,9_)9949ɻb9C9i_9j9M9C\9|9kD9kr8>܈? z?85?O?Q?_?c?p?x-;??|b?|;?n?r?fLI?n#?h?gb\?b}?eǻ?f?`?VK?Ox?WSw?V?T ?Ka?F?Ez?ID?D:?E?B?=5?:?3?,e?)]}?%~?#5?$/B?#?#?9?+,? ???y"?? ?? 'E?t>z~>I><>D>pR>>a->F}>">^>绎>0>Q>>C>>>>i>nj>ª>p>#>>>>g>dX>:>9>>>p>0>@t>e?>>=>>>c>o>j>>>>9>$>>_>>xf>jT>lh>h>i<>mC>q,>jZ>h,>d2>]O>e>O"> i_>8==V=]===r=I==AI==v==˦=t="g>=:= =?==Л===\=A=+=1W==n=w=sN=rvf=J=Ct=/B=e= H<[:::`:hY:Q:(:?:iX:K:P!:N;:[ :br:0:~B:N:Tf:X8:~%:[y:RG:I7:9 :6˫:g:N[:m:V:,t:aC:>{:Z:My:O:e::P}9@9B*:%9::9P-9G9899c938B+9۳999o8ַ9g9ei9 9p695]9C9z9_9[9Q99 9G9q9:9J9S*8969O99t9FQ97I99J d8ڿ9զ9c9F8a9B9s9L999K989928=885919?͝97y9v9Sn8s8A99"<9w89|98O9g9m9j9AE9K7+CB8u8Ӿ8H84O8 8GM8q&8*F88@88͔8 8$xB8999P8Ͼ9B9Q9{8fW&838G9/9Nm8ɰ9^49פ9Vܳ9j/8|9,`9%G8]99 99j07N=8u9P9 /j959!@99K;p9i 89 u9;R9Ym9x9P88988O9w96.B9$G8|=89 9Uv998pk988T.88>;8e8m8j9)}99Y9ݽ8,90;9/48'8 h8J8]J9f99 W9Hy9:\99:[8A 9϶91[8k9894w9/7'88r8̠578|8_X89);>9-9h8G828Ƃ88e)9(9F8t89/9793958ދ8Js79+<8JU8<9`8t{8'X96:9@&9w)9: 8489!8Zk8~9`8N959Lt9&K9 848a98-7Ϡ8\38k8D87W!8i'99 87X8Ȗ8$9)W9-738W@9^ j9Q`?+? ?('? #??-m? ad?0rQ? s?E#?Z?Jg>-??A>y?>>IZf?(e?p~?fk?5r?G?(ei>l>>O>3> >>?o>?r>i>wu>Zo>x>lg>f>B>ٍ>Jy>~>>`>0>[g>>8>a7>>r>8>> >L>9>{.>q{>yB>'>=>>(>$v>>u>=5>#w =>[>nO>>E>Kp>R=<>>j>|>J>?r{>D>I>L{>RX~>j>|>>5>>/>>a> ><>Y>(>L>AU>a>>">f>o0>V;>ߛ>sf>>Y>E>>>(>=j>-P>.>$Vs=X=VE==^=#>^== @=E>!>x==<ݤ=,=<=<|==$v= ~=ZLf:B}{:tk: :;Zt:: :$::e9ӌ:Ik::pk9%93s9@8o9|:,:L!:.:~F:|x9P:]9 O::r`:-::9pw9:.:b9:<: :X:8:;V9 909:=T9_p9:G1:s:si:]F9Z96{9Q:]E;9_$:&O+8#9|99{`9:9:9:A9ZN9R9d9ľ99D 99g#9Wь9z:<9qh9p09FN9f:$R: w9::%|$97*9~:): 9:N!99n:& 489+9R9ʘ9k9Q9:@99VT:D9S:?H9C:P:6p888Y9 9Ao:59>9M9U9*V9#: [I:6/9iK99+1:'9ۅZ93x9c8*A9Z:%:4:;59zl:I;99]:: e9#789ǐh9g:*h9#9g~9|99!:xT9q9YW979):6:C99T999Ѹ:,78b:&U8:4+ 99 oX99O`:F9˭:+{H: ʣ9,:d9V:69:W9u?i9\9Oq9W/8?k9Of>8L9A8"8/9=9H<9]9m9^:X99X9۽?99s9+ : #9":/^: 99r9v|:_99cb?6ru?>?S?>?lmm>9>!u?g? ?^ۛ?N?\?GU?G$s??BA?u>[>?4B?7>?V >? >;?>>>>R>j?,_>8?>WZ5>#>2>(+>:->a>z>6>M> >"&>>ͽ>>R>>{=> >!>V>tUD?">c>ٝ@>p@>> >>~>Æ>S>}8>i >s>>>>t >x>\>>>>޺ >N>;x><>>>:>5L>_>7h>Y6>ĀR>>>m>6י> >+> }> >Ut>VA>>oq> >>8>,=>j>c>>?>8>~>J>x >u>*mE>l$>`>v>'b>t7=d=BT= ==g=!=ʜ=>=E>D=+>'B,=>> =L*>''>[>*>>L=====R=r3=xh=z_=,a=jF~==0=4<<<><<5;M;ڥ;;d;@<;ЏL;;T3;m;~0;_4;+;+i;̏;;J;̕;,;q;~;p;Pˍ;h;;%;qlZ;;( ;%Ţ;+;p@;0 +:?;BR;J;C\;dq3;e#u;lB:k`:;; \R:\;h;(};/;Bk;3wr;O;:;)_z::|:>1:\":x:!:~:-J9:_C::ђ:J:#::d:::u:j::X; R:[u:-::jX:HU:P:2:_xL:vnl:,:-:}:GG:n:6:e6:J::#:ZN:X;:G:8::e:)դ:W:Xo::>{::Y:ϳ:.[ :Tw:9<:{:`:d:Oއ:hoT:::S:P:V!:F:::O24:9)-:9r:D:Jm:g::R:`J:;8::%:2:j: ):!z:1::-N:D):q7:=w/:$,9:g:#U:}:=:G':&:yv:':$9=:b9v:SV:x9m:;c]9W:я:t:^U:=9:M*:_:q(&:9::m:d59:T9:FU:x:mw 9=9u:7O(:Y:5zY:5:7[: VX:V:amm: :o:: |3:3:< :a9):6:=:7:DA:FG9_2: ?$:Z>: :Z:Zd:3:X^::M:=:-::?:h:Hr:c9TU:(:TFT9p:t-:h}]:q:Tf:): u:a:O::b!:˳:!::smC:959ͩ:T:Yz:xx9e:N9I^9ŢV99ǥ:]:)=:49:Rq::9M::A:FU:EL:I{:1Q:9:B:bC:%)9J::GE9n9e:B :n>:Yg9:r9H:en:n:לe:H::]Ҟ:'Wq9::>:Z:&9:n:E9Ź>: 9:32:eǴ9:9w:[1-9˲j:}9j:):V:7:\A:$m9ƅ:\f:d:Vd:c:9:F":v%:;n:2Z::zl::@1:%U9|: T:v~9:mW:::F&::Y:)[:.:u:1:K 9:1_P:]:/: :+.:."::"|:K{E:= 9s:::iZ9C+:OO::9P:Nh :Pł9M9E:O1B:$:w::o::y:f}9:n:!G:2.:7:=-9:CR9?:39:*+/:>P2:,b:;: :5I:+/t9BK:H:x:0:::/:S::[:O59"89H:P 9 :lf?٭?.1??J~?X\?F# ?&?9۱?La+??jD?h4?RO ?F?K?A,?OP?eW?7?{?Z?*=?"[^? m?"F?%/^? ;@??? ׷>G>1>?%>`>o>۷>>4j>A>>>ț6>>>>>3>> >>>+>>>>fN>Q>c>}M>+|>>_;>7>>>:*>>]>Z>u>5>ap>S>>am>B'>|>:{>-m>)> >פ>>>!x>hD>->>>P>>.>m>S>E>>o>kG>>>-u>٤>>t>u>v>V>>b> >0>>[}>S><>[>Y>cSB>46>.A> z=a=^=]T=/Q=SD=zJ=NH=`=yS==wE=E-=Cf=Kc=7k=5&=2]=&X=O=;;S;;CO;M;;u;;v;UC;A;S;T;Z;py;p ;g;3;_;A!;;jK;I;+{; J;$|;8xK;.I;+;S;1;;;0;e:%@; ;?;@eZ;-0;?%K;2o;)7p;".h;6;"j;(;;&:Ux;;;&;; __;"J{; ;=;n;P;=d;2;I;!?;:;K;.bu;/Y;;*S; S;Z;; x; ?;Z;Ē; ;;X;o;K;!D;0;2;.a;; ;(z;; ܄;%:ʐ;;#k;T;,;g:ؙ; ;b:!;'':#;; q:;d; :;;; z;b;;/mM:(I;s<;:; :FN;i:s:+:ft;.4:):); ,::;;: :G;M;;4; ); o;S;;:;h`:]:9;K;/; :P::: u;O:l:E::7]: ;":I; 5r:z:t:j;;:O$:\l:8:zN:::x: ;9;;:::P::/;:;~z:::Wf:ڏ:l::r:::!T: :ϯ::; &:У::Y;;i:); ?B:;V::J:q:^;:.:ŝS:l; :-:ɪ:; ^;: ;; :f;:;z:: ;[:";o|:ۦ ; 4t:3;':;W::ߎ:֚:::P :4:̰:3T:S::_:{::ޖ:/^:;::8;] :1V:L:%;:ӥD:;:,;;@Y:܍ :Md:[:t:>:m:Յ: x;x::5:;j:Й:.:J=::+::4:8;@j:{:Ȼ:1r: %:>1;}:n>:ݼ:j:0:`X:/::y:K;:i::.::::5Q:3:L::;˨;cP;:`:^;3;b::[;5R:w;:rh:}::; q:Kv::&:?;Ƀ::!:!:w:Fd:C;H;^; p:h; ::p:+:w:!:T:p:6:w:8!:/; :YR; : %:#:8:$a:I#::$:뛮:; d:墦:::Ū;jI:˲n:`Y;/;n:F:D:::B;P;Ԑ:::?M:Ln:o!:G:K>:;^,:Mnyquist-3.05/lib/piano/dur.tab0000644000175000000620000020002010144436365015321 0ustar stevestaff@BBBBBrB$BBNBB,B~BɽBBBBBBۤB]BBBBBBBRBrB~BwB]B0BBB6BB/BBBBAB:$B5B1B-7B(B$BiBBBQB\mBgBqB|BRB~BB{BKBBBBXBݎBBByB4B BNBB"B+B3B:BBBJbBQBYRB`BgBnBuB|BBBBGBBBBBBrBBBB(BIBKB.BBBBBBBBBBpBB sB BBBBBB4B!B$ B&KB(kB*lB,NB.B/B1BpByBXB BBB0B=B BBiBB BBBBUBBBBBB\BBB)BBB~BB9BYBNBBB2BBBBlBBBBBBBBB,sB@BTBhB|vBB[BBɃBPBB[BB%B7BI;BZBlB}1B%BB}BBB BBBBaB-{BBwhBB-BDlB[BrBFBB%BEB1BB kB"B7BLBagBuB)B;BBB5BuBBVB$B7dBIB[BmoB BoBBBdBBUBBtB4B#B3BB9BQ'B_BneB|BBBhBB.BBB!BBBBB BhB$ B/zB:BEBPB[&BeBoByBBB}BBBbBBIBmB]BBBB BBB(B sBBjBB!B&B+B0B5_B9B> BBBEBIBLBP!BS!BUBXBZB]B_ B`Bb_BcBdBeBfBgBgkBgBgtBg)BfBeBeBcBbBaB__B]oB[KBXB^B5BPZBjBoB"BBBBB@B3BKBcB{GBBBBװB9BBB0{BFB[BpBBcBB+B9B BBB%+B8BJB]ABoBBOBB7BTB7BBPB BB)DB8BHBW/Bf BtBB>B2BBkBǰBԼBB&BBBBDB)B4B?BJBUTB_BiBsB}OBBBBB4BBBmB BrB؝BߏBGBB BBB{B BBBB B!DB%FB)B,B/B3 B5B8B:B=1B?+B@BBoBCBDBEBFBBFBFBFBFwBEBE7BD@BCBAB@B>!B)BG/BdBBsB BeBB[B*BFVBauB|UBBXB{B`BBkB1BJ{Bc%B{BBBUBBBBB6 BL>Bb3BwB`BBBLBBB BB0@BCBVBiEB{BBBBcBԬBBBB\B'jB7:BFBVBe.BtBBBBBuBBBBcBBBBcB)B4B?BJsBTB_BhBrB{B+BBB6BfBWB B}BűB̧B]BBBBB>B{ByB8BBB BBCBBBVBB"(B$3B%B'B(B)B*B+IB+B+B+B+B*mB)B(]B&B~jB~eBBAB'BBVBBB{lB{B{ǼB{'B|B|KB|uB|fB|ȚB|+B}B}@^B}gB}B}YB}B}B~B~ATB~cxB~B~B~B~BB"B@uB]uByBBB BBB =B+B"B.B9BCBNBXBaBk BtB|B5BIB ByBBaBBBBUBDžBbBB&B BܡBBBqBBB]BBBeBBg܈Bh3BhBhtBi4gBiBiFBj/0BjnBjBk#BktBkÛBluBl`Bl BlBmGBmBmRBn'mBnpBnBoBoIBoBoBp-Bp_BpBp0Bq)BqkBqBqBr-BrlBr|BrcBs&Bsc(BsBs7BtBtNBtBt3BtBu/BueBuVBulBvBv8BvkBvBvϴBwBw1Bw`BwBwBwBxBxDBxpBxjBxŨBx9ByBy@RBygByByBy`By2Bz#VBzFBziBzBz BzBzB{ YB{,B{JB{gxB{'B{)B{}B{$B{B| iB|"B|9B|Q:B|gB|}B|B|~B|]B|ΏB|B|B}B}B}$\B}3|B}AB}OB}\B}i7B}tB}B}dB}B}B}wB}#B}!B}qB}B} B}PB}B}B}B}ӨBb]bBbBcBcoBcBd#Bd{BdӖBe*Be:BeBf,BfYBfBg&BgyBgʉBhMBhkZBhBi RBiW`Bf:BfMBgBgIBgBgBhBhG_BhBhBhBi9)BisBiaBiRBj{BjUBjwBjJBjUBk+Bk_BkBk÷BkBl%:BlTBlBlBlBm _Bm7BmaBmBmvBmBnBn,BnSBnxBn5BnBn9BoBo(BoHBohBoBoBo9BoBo5BpBp3BpLBpeBp~BpuBpBpBpBp^BpBqBq#Bq4BqE9BqTBqcBqqBqBqBqTBqIBqvBqBqzBqPBq`BqӧBq'BqBqBRDRBRDBSfBSBS:BTRBTBUBU%BUBVM=BVBWBWsIBWӮBX3CBXBXBYM$BYzBZBZ_BZB[B[jB[sB\B\nB\B]3B]kB]5B^B^`B^"B_|B_OB_B_B`5B`B`ˍBa9Ba^Ba!Ba]Bb3BbygBb4Bc2BcE`BcBcLBd BdIBdBdgBeBeABe}wBeBeBf,8BfdBfBfӬBg Bg??BgsBgBgڇBh Bh=BhnBh4BhBh-Bi(qBiTBiBi`BieBiBj'BjNBju^BjUBj|BjBkZBk+BkLBknBk[BkBk}BkVBl_Bl#Bl?BlYBlshBlbBlBlBltBl0BlBm8Bm$Bm7BmHBmYBmiBmxBmEBmBmBmBmBm>BmBmՍBm}BmBmBmoBm BMBMwBMzBNThBN}BO-BO"BPBPmgBPFBQ>MBQ|BR BRqTBRBS9BSBSBT`/BTBU :BU~BUBV9BV3BVBWL!BWBWBXVBXBY4BYYBYUBZ"BZUBZ5BZ{B[HB[B[>B\5$B\3B\jB]B]dRB]B]B^>B^B^TB_B_VnB_8B_*B`DB``B`B`Ba?Ba]"Ba.BaaBbBbLBBbBbBbBc-Bcd3BcBcGBd Bd4BdgBdQBdȸBdHBe&BeTBeBeBeqBfBf-BfVlBf~fBfBfBfDBgBg9Bg\Bg~BgBg?BgBgBh\Bh9aBhUBhpBhaBhBhBhBhBi0BiBi-6Bi@BiSBieBiw&BiBiBiBiBiBiBiBiBi2BiBiBj Bj NBjBGܘBHPBHBI6qBIBJBJnBJXBKecBKҏBL>BLGBMBM~BMNBNOBQPBR.BRBRIBSFBSBSgBTW\BTrBUBU_BUvBV BV`BVBWBWYBWBWEBXJBX[BXBY3BYBY BZJBZ^BZ'BZB[5B[{eB[eB\B\GB\(B\˪B] MB]LB]B]B^B^B`B^}B^KB^B_*B_bB_B_B`B`9B`m B`B`}BahBa2sBaaBaBaWBaBbBb@_BbjNBb\BbBbBc KBc.BcSBcw_BcQBccBcݖBcBd]Bd;BdYBdv{BdpBdBdǽBdBdBe#Be'Be=BeRBefBezBe\BeBerBe.Be BeBe$BebBeBf ?BfBfBf$~Bf+~Bf1BBBC:eBCBD(BDBEBEBEBFmBFsBGNBGpBH-BHBIBIsBIޚBJHBJBKDBKBK2BLMBLBMRBMy9BM9BNBXBXBYoBYIBYBY8BZ BZFBZBZBZ$B[5kB[nB[CB[B\~B\KAB\B\B\ B]FB]JB]zB]OB]B^|B^38B^_ B^B^B^ B_YB_,B_SB_xB_3B_B_B`B`&B`FB`eB`.B`B` B`١B`OBaBa&Ba>BaUBal(BajBaBa;BaBanBa.BaBaBb Bb#Bb$_Bb/Bb:!BbCBbLFBbSBbZB=B>4B>B?+B?B@B@BA7BABABBnmBBBCTBCABD7BDBEBEBEBF\BFBG2#BGnBHBHk9BHѹBI7JBIBIBJbgBJ>BK%'BK"BK.BLBKBLzBLBMW BMqBN BNclBNBOBOgjBO6BPBPcBPBQBQV=BQsBQBRABR~BRBS#BSm'BSBSBTDmBTSBTIBURBUVlBUBUBV"BVYBVBVwBW BWMBWiBW2BW BX2BXiBXBX&BY YBYB:B;9B;,B<1nBB>SB?B?u^B?B@[B@=BA=BABByBBLBB*BCcBCBD8BD BE BEp8BE^BF;BFBGBGeaBGƻBH' BHBH BIBBIBIBJUXBJBKBK_BKMBL %BLaBLBMBMYBMBM BNJ*BNUBNBO1BO}BOfBPBPY-BPBPBQ,BQq8BQBQ|BR9.BRyBRBRBS6\BSsABS1BS+BT$0BT]?BTXBT|BUBU7BUl&BUsBUBV-BV3BVcBVBVBVBWTBWABWkBWtBW>BWBXBX-BXQBXtBXBXBXBX-BY_BY2BYNBYj3BYBYBYeBYBYeBYBZBZ"3BZ4BZFBZW^BZg,BZvBZBZBZBZBZBZBZB3B4ZB4B5bB5(B6eBB6^B7dB7B8_B8B9W"B9TB:JB:B;9B;=B<%BaB>[B?>B?B@xB@B@GBAWBA$BB'BBBBBCXBCBDBDBD"BE?BEDBEBFXuBFBGBGhWBGBHBHoYBH BIBImzBI6BJBJbBJBKKBKOBKBKBL2BL|tBLSBM 6BMTBMBMBN"BNeBNBNBO(BOgBOBOBPBPYBP BP!BQ;BQ&B>B>/B?\B?5B@&B@.B@BANBABB BBlfBBBC&2BCBCBD5LBDBDBE;IBEBEBF8)BFnBFۯBG+BG{'BG^BHBHbBHBHBIACBIgBIЇBJBJ[BJBJBK$BKfBKBKBL#BL`BLBLBM BMIBMBMBMBN#BNWBNqBNNBN(BOBOKBOyBOoBO8BOBP&BPOBPw?BPBPîBPbBQ BQ.BQPgBQq BQBQPBQBQBRBRBR9>BRQBRiTBRBR\BRBRXBRBRGBRBS(BSBSBS)cBS4BS?$BSHB*6B*æB+OUB+B,cB,(B-sB-/B.B/B/pB0 B0B1 ZB1B2B2B3 B3}B3(B4p)B4B5_ B5B6IB6B70_B7B8B8wB8B9^B98B:6B:2B; B;sB;aB<@B0B>B>B?MB?B@B@aB@BAdBAl-BABBBBmPBBBCBCeBCBDBDSBDBDVBE8BEBE9BFqBF[BFBFBG*BGmBGBGBH0BHoBHBHXBI&BI`BIBI,BJ BJA[BJvBJdBJBKFBKBBKsBKPBKЕBKBL*BLU+BLIBL^BLiBLjBMbBMBPBMf4BMBMBM˦BMcBN BN'BNDaBN_BNzBNBNBNBNWBNBOBONBO)BO:BOJBOZBOh)BOu7BO(B>[(B>B?B?YB?B?7B@NB@gB@BA:WBABABBGBBewBBBBBC:BCBCxBDIBDH BDBDZBEBEDjBEBE;BEBF/BFgBFBF.BG /BG>BGqBGBGӑBHBBH1BH_tBHBHeBHBI BI3XBIZBIBIBIɼBIBJBJ/_BJO BJmBJsBJBJÅBJBJWBKBK&BK=BKR=BKfNBKyPBKABK#BKBKBKgBK BKBKB B!nB"B"GB##B#tB$AB$HB%[B%B&pB&B'B(B(yB)(B)B*DB*B+B+IB,tB,B-B-pB.CB.~B.B/m7B/B0WB0eB1.(B>yHB>RB? FB?T$B?B?B@%9B@hB@.B@BA,BAkBABABB"BB]BBBBLBCsBCBCABD fBD>uBDnnBDRBDBDBE#wBENBEwxBEBE BESBFpBF6wBFYhBF{CBFBFBFPBFBG@BG/BGIBGcBG{BGBGBGBGЎBG4BGBH@BHBH"BH0,BH B>XB>B>B? ?B?CGB?{4B?B?B@QB@OB@/B@tB@BABA@BAmqBA+BABAKBBBBMB>BB>l_B>B>B>B?B?*B?MsB?oB?nB?B?B?B@B@ B@:B ?B B!7MB!OB"*%B"B#NB#B$B$tB$B%W/B%ƥB&4B& B' B'xB'^B(JB(B)#B)} B)B*C\B*B+B+dB+B,B,z(B,ԆB--B-B-ܕB.2BB.B.B/,BB/}?B/B0B0i.B0zB1B1JB1YB1B2!fB2fB2B2B3/qB3pB3nB3B4*B4fB4XB4B5DB5JyB5B5]B5 B6B6LB6}B6B6B7B72B7\^B7B7yB7EB7B8YB8AB8cB8B8oB8B8sB8B9B91B9JhB9aB9x[B9B9B9}B90B9ַB9B9BB:EB B =B sB B B kB]BqBB.BNJB_1BBBBBCBBccBB~oB ,BBBBB:BUB1dBBB#BjB B B B!moB!B"OLB"qB#,eB#'B$B$oB$JB%@IB%B& B&qB&ZB'6dB'=B'B(U\B(B)B)iB)NB*B*s!B*AB+0B+qB+{B,B,fB,B-B-O]B-B-B.-B.uB.vB/B/F)B/9B/B0 B0KDB0B0ƫB1B1=NB1vB1-B1TB2IB2Q B2B2B24B34B3GB3tB3B3KB3VB41B4FB4mRB4B4B4ٕB4IB5B5;B5Y@B5v1B5B5B5B5B5B6 B6hB62B6EB6VB6eB6tB6BX:BBBGB;B B +B B hB B B ;(B *BkBBB,B BPBVBpBBBdBB+(B9B:BBD,BfBIkB:BIB7BEeB^B< BB.B%BBBGBuBBVB.B 2B B! B!sB!VB"CB"B#B#rB#>B$6B$B$B%SdB%B& 5B&eLB&.B'B'lQB'B(B(hrB(B) |B)YB)B)wB*@ B*gB*ӎB+B+btB$VB$B%`B%VB%oB%B&B&ZB&B&NB'B'JB'B'B'B('JB([DB(B({B(B)B)LyB)xB)?B)DB) B*B*DB*iB*B*BB*ёB*B+tB+.B+J\B+erB+JB+B+>B+ZB+8B+B,8B,ZB,!=B,/AAMA3AAPAVAWA=AA:BB+FB6BiBPBxB>^BBpbBB\B1BJBW^B/B wB B B B [B 2B B AUB BKBBOBBOCB,BIB7B?XB6B/B+BBBBBrBBQBQB+BBUBhB B6BB'B`UBBB BRBvB8XBBSBDlBCBBE)B8BB:BBB $B pB WB!QB!KB!}B!֮B"B"]JB"B"B#B#[bB#B#B$ B$EOB$|B$B$B%B%M\B%~dB%)B%ܫB& B&5B&`B&B&NB&@B&B'#]B'FB'hoB'B'wB'ƖB'tB'B(fB(2{B(JMB(`B(v+B(5B(B(B(B(AATAfA cAeAA A_A AABAoAvAAMA=BbBBB1BB_uBBBhBBAGAEALAAACsAAA#Ah\A#AVA(AcAuAWAA6]B2AB B\BBBDBB/BeBGB BZBBhBBqBB u$B B sB B lB B `B B OB kB9BBLBBBkBBCLB:BB}9BHBHBB BnB?B,BBYB?BBBGmBBBCqBBB3BiBͭBBbXBBB7B|2BoBbBB BjBBIB7BqBBBBMBB.B]BABCBq,B2BB`B B @eB eB BB AB B `B!B!,WB!HB!d%B!~B!B!.B!GB!B!B!B"B"mA_AA-AA-AOAHAAXAdA7AKnA A A&rAj=AmAA%A_XAACAA*AWAAAuA^BB/B;B-BiBABbBOB$BYBۯB]BB[B"BU=B B IB B 8B 8B "B |B +B wB B TcB B,BBpBeB˥B0KBBBVkBBBpBXB&B|BB-kBmB"B(ByBpBBe BBBDBBӉBB\BB6B!_B`:BBBBNBBBB(,BB BBBBGfBrBBkBBB7B[4B}dBGBB#BBB/'BH8B_BvqBBtBB@B2AXA3VAלAmAgAA'Aބ AݜA4AAڊA)AvAAAKvAZA̝A =ACBB'BB BzB-BV8BB,JBRBBc]B`B, BcBcBO B_B [B fB OB GB pB 3B (B oB B B bB B B I]B B ܅B$BjSB9BB4BuBkBB0}BlB4B BBLBBB;B BGBuB|BBB BHSBnpB7BBBBB7BSBo-B?BB^BmB$BB BCA A&BXBqB(BvBlBBKB4AA,AbA>AbAA]AŅA*Ač_A9AJ]AȤA~AQ|ẠATA@-AЊOAѺAnAXkA՗A@AAE9AyA۫VARAA0%AVA{A✄A6A1AuAAA+A:^AFAOAUKAXAYAWAS/AKAAA5A%AvAAA̧AAAmhAH:A UAAgA]B2BBB^BBB~ B)B6BUBaBBBhBaBABCB*B3BBμB5BdSBB|B:B7BŒB B E"B dB JB B :B sB PB mB .B MB B MB B B ?4B kuB ZB B B B 4[B XwB {7B B B RB BB/6BHuB`YBvBBBVBqAxA>1A.A+pAA AzA'ALAAAs*AA)AĀAyA'8Av=A…A ARA͖AXAARAҌAwA*A'"AU_A؀A٩AϲAAA1oALAdAzA⍄A㝴A*AAA'AůA}AŽAA촀AaAAAwAaAHA-DAA AVAAzANA /AAAAJUA AABAHBB[BvB BdB>BpBaEBBBQBBB5B~BƾB HBRtBCBشBBY|BBBkBJBBB6B%BYiBvB&BxB lB FB qB UB kB B B AApAAbUAAHAA$~A*AAYFAAfAuWAΉA$AxAɤAAcPAŬAA59AuAʳnAjA&A\%AώAоA#AA>gAcjAօAץ3AAAGAAA(A4A>{AEHAIVAJAI5AEA>A4jA'AAA=AAAAAaAA ApAAg A*5AAAAc#ACAРA;A3A)A}A2 AAxA1AAN}AAyA ;AA%A$A5AGBB\1BB9B+BJBBB'B#3BUB'BBBB>BhBBBBB(!BJ=BjBQBIBBBB]B)oB?BSoBf]BwAA9ACA25AbAAkAHAo_AٱAA=AAAgAA÷AhAtTAzAAhvALA\ACA-AAAAAyA¯8AAA:A A抿A.AAn&A AxA8rAˢA\ AAtwAA큽A1AAAzAAfAVAGDAhAARAAHAEAAZJAA(ASgAAA3jAxAASA7 ApA!A}AAADAAGAH-AEA@A9A.yA!AAA ApAϴ AЕAtAQA*A&AAզAtCA?A\A7AّGAQAAɯA܁A6AAޘlAEAAA:nAAzAA㯶AF AٔAjQACAiA ASAA A9A鋙A.AwAAY%AŋA/%AAA[.AA9An AARAgAiACAHQAA AALAAAnA$ASAAlAAAAYAUAZTAևAOAƅA:QAOAAAASJAIA{AsAwA&BA{AArAAinA9A6A>gAAcA-A3+Ai[AAVA A&ANMAsAGAA A=AA6A+A9AF,AOAV$AYAZAYAT{AMABA5A&AeAAAʾAʬAˌNAhABAAAϿ5AЍAYA"AAӬAlA*uAoA֝ARAAصXAbRA AڳAXrA9Aܙ2A5_AοAeRAAߊA=AࣝA,/AA4AA2yA A$AA A{SAAQA渢AA~,AܾA8AzAA;A鋔AYA$PAlzAAiA4-Aq$ANAAAAխAAaA5AA5AWAAAA AKAtjAAAAJAA,hAACASPAbAoAxA{AAA,A~AwAmA`AQCA>A)AAADAŸAƕAoAFA1AAʻAˇAPAAڗAΛXAYLArAAтUA5AAӒ#AZA߭AwARA^AOAAAkAđAAn9AA AWAAOA'AgA夸AAOAJA|A櫬AA;A'AKApWDAsaAvf Aye%A|^ARYA EAA AtAAIAAgAtAA,A5AڥA-HA}A#A[A[AbA1A!2A]dAA`A(A2#A`PAA?AAAA:wAUAlAAA"AA^AGAbAůA.AAAAAACAk AS0A8qAAAaAjAˆA]A.AAɈAƒAY%AA݊AɛAVAAĬAwrA'jAԓA~A&}A=Am/A RAѨAB0AAlAAԌDAAՠzA&`A֩xA)Aק>A!AؙAAف#AA]AAA.'AےfAARxAܮMASA]AݰAAOaAޚaAA'AjAߪWARA!~AXAmA0A%AKACAj/AAeWAhSAk AnzAqAt 1Av$AyzA|5ASAAdAA̰A|A)AA{[A AA`A(A̖A-Aq>AtAwpnAzAA} 2A-AIA)AAYAAAP AAdA-\AqAAsA-6Af+ARAϭA:A-AXAAhAAAAA7AKA]WAlDAxdAA;AAAAHA~AtAgfAWADA/MAAAADAAspAJRAgAA(AARAA AAZ+AAAYA4AtA‘NA;ZAAć A(AdžAcAAǓ;A&AȷAEAAY^AAaAA_ AsAQAA7AΧA{A}AAGAЩAuAc AѻAAeAҵaAAMAӕAA@A\AԙAӌA A?ApA՟aAUA{AA>`AOQ>ARY3AU[AXXTA[OA^AAa- AdlAf4AicAlAotAr?]Au)Aw]Az|A}0AcADAAA0AyA*AADAAAEA+A^AAAjA A2ATAt)AA>AA"AaAA{A UAcAAAA AAAiAAAAKA}A_qA>RAfAA)AAnAAo9ArAuFkAwAzEA}+RAA)TAnAAA/(AiAPA3ALA7AdAAAA8AA4AM{AcAwAAdAcAAAAqAyAA(AAAtAaAJA1/AA/A~AAA^A1A'AϵAwAboA'AAAf`A aAחAA=AwAAAA4AA,AAfAAFA'-AJADA!AVAA]AMAYAӡAJA¾A0-AÞA AsAA=;AŝAAVAƯAvAW!AǧAA>aAȅAʔA }AKAɇAwA4A,'A]NAʋAʷaAwAz%NA|pA~AABAA*fAONAqoAA]A)A/AnAAAA'A.A1A2fA0nA+A$)AA AANAAAAAcA@7A&ANAŰAJAfA2*ApAAAFAA&AxA.AAA?rA,A A7MAٲAyRA*A;AGA AmAAATAAAA0AAuAnAAj A׮ABAAArxA:A/4AhAA5{A[AsA"AlOAAA8FAvA^A@A!ZATA;AAA:A+ANVA&A)A,A/A2A5A8A;n8A>EAAAACAF*AIjAL%rANIAQAT6_AV۝AY{TA\A^'Aa9EAcAfFAhkAk>gAmApAr+AtAwHYAy#A{fA~? AC)AcAA[AA˧AާAA[AAA)AA4AA -AAAAA6AAuAzoA[A:AAAA2AhA6AA AARaAeAϥA AAAAAXeA AAVAhAA:AAp)AAqA+nAAEAASAAWIAAOAA=2AAAAA^YAA% A?AA:XA?AbA6AZA0ABA`AAA"A^AALA=A/jA\AwAWAsAAA {A#oA&^A)HBA,,)A/ A1qA4A7A:MA=A?CABAE7oAGBAJAM-bAOɰAR`{ATAW}AZA\A^AauAcAfPAhAk~AmoAogArAt]HAvvAx!A{KA}LA{AAoA?AMAA(AAAIA AAAAkA/A2AtAAhAHA%AoA+A&A`ANAAAAq4A2AA Ag~A.AALA1AeAPA,zAApAsAAAAףAjAA AAAAA!A|AAAAv`AvAQA`A"3AFAAF(AAAQSAAACAA׈AOA`VAA AAPA(AAhAfA?Ag!AAASAIA9A$VA }A"*A%\A(A+gOA.1A0WA3#A6mtA9!JA;ϦA>xAAACAFRGAHjA@ABAEfAGAJ(ALANճAQ$ASmAUAWAZ'A\ZA^A`7AbKAdAg 5Ai Ak*xAm2{Ao5Aq2CAs*AucAw TAxAzA|A~A,lAA-AAAAi4A?1AzAAA|ADA KAVAAKMA9ApAsA&AA;A.AA|(AAA[A)AA"A?ADAA[AvAh?ATAiA^A`TAהAL AA-AA>AjAAΐA0)A A=ADA}AA@AAۂA$AkGAA8A.AjUATAٟA 4A>Al@AAyAA A*@@A"hA)AҊAA m,A2mANAAaAAAaA!A#A&/A(PA+IpA-0A0MA2ǏA5<.A7nA:MAAA2AC AEAHAJcALANCAQaAS?AUh~AW|AYA[XA]6A_AaAcAeAgAiއAkAmAoAqwAA׮A AeAA=A&AaA0AAA2A`}AYAAAA@u@3@@s@.Aa A%AAzA RA AAPFAcA+AAA 6A"A%:A'A*(JA,fA/-A1eA3ĺA6A8rA:A= A?PEAAaAC&AEAH,AJVxALzANAPAR8ATSAVAXAZA\fA^A`AbAd#AfoAA AyAIBAufAAAA A*r@@!B@иg@E@@@>@-@@g.@@CAA/AANTA A WAALA+A,jAkA0ATA A# A%MA'iA)ټA,A.PA0DA2A4A6A9GA;7A=KA?ZAAdqAChAEhAGb AIVAKF=AM0zAOyAPAAAATA MAAbAkAAGAAA~A#A@AAAPAAtAHAAA(AnArAA/{AjA AA A}@לd@@9@w@8@<@@ "AA CASA4A lA cA>AAARAAmA7AyA!fA#A& pA(MA*uA,A.AA0νA2A4#A6A8A:SAA@ABAD3AFAH_AJ4ALAM\AOAQUAS2ATAVvAX"UAYȫA[iA]A^A`. AaAcAAdýAf@Ag5Ai*AjAkAmbAnApAqlfArAtyAuG:AvAw+Ax[Az"[A{L+A|pA}9A~xAAgA AoAAm~AuA`A֙AIA]A([AAAbAbA'gAAA:AAA7 AA,AAbAhAKA(AeJAfAA A>'AmAAŏAAA5AUAsY@@!@s@@f@þ@ g@O@ӈ@ط@@X@U@ @@@ߞA^#AUA+dARA A 8ANAҳAAXAAAA%DA KA"mA$@A&PA(=A* A,ƲA.9A0ƞA2A4A6A8A:lA$A?AA-AC=AEW*AGAHџAJ'AL7AMAOAQ)ARAT\AUAWzAYAZA\+A]yA^A`YAaAc%{AdAeAg0AhAivAkAlMAmAn AoAq Ar=As^AtzAulAvAwAxAyAzhA{A|wA}A~rAVAAdA9AW}A/AQA}AA5PA-AzA55A_AAAfxA^AA0wAnAKA\AAMA(AA0AA*AO|AqsAA@A@iI@,@(@y~@@7@.Z@VW@t.@χ@ԑi@ِ@ކ @q"@R@(@@@pZAFAaLA?AA 8A vA KAA^A:A_%A~lAAAA A"ίA$σA&DA(A*A,A.A0iA2G7A4rA5A7A9A;MA= {A>CA@zAB*AC)AEzAGAHdAJLAKAMiANAPrAQASgAT`AVH AWAY#AZrA[A] :A^oqA_A`Ab>AcyAddAe)Ag Ah2wAiTAjpzAkAl/AmnAnAoApAqArAsRAtv AuZAv:AAwAw,AxAyAzKA{ A{)A|"A}2A}A~A)HAA/AynAADAGaAAAA6vAkAA!AA(8APAw)AAAڌA@x@5@@@ @A@k@@@@@Ƨo@˕G@y@R@"@h@@U@|@ @.@U@7AָA zA=9AhA A bAAAmAAA\AA A-A A"SA$A&lA(zA*QxA,"A-wA/A1yiA36A4NA6A8Q&A9A;A=>QA>دA@n AA`ACAEAFQAH AIAJ&ALdfAṂAO/APAQFAS;vATAUAWAXZAY6AZRA[lA](A^OA_qA`AaAbAcAdAeԽAfӶAgͬAhžAiAjyAkbAldGAm@*AnAnAoAp}Aq@dAq2ArAsjAtAtMAuh AvAvAw83AwAxTAx>Ay\AyيAzQ,AzA{1eA{A{A|\"A|A} :A}YA}EA}A~*DA~eA~5@>@@@h@#@D@[>@h@j@d@S,@8j@@9@Ǭ@jt@9@@h@-@_@ @@@X5@@A%XACA]pArA A xA AAAAAwAdAMA06AkAA A"YA$UA&?AACFABAD*AEyAFDAH/AIAJPALAM`ANAOAQARBASnATAUMAVՐAWAY?AZA[$A\A]>A^A_ A_LA`AaAbAcAdgAe:AfAfAgNAhUAiAiBAjuAk!(AkǯAliDAmAmAn0SAnAoFAoApIApAq8AqAr$ArzZAr۟As7AsPAsAt/7AtwAtTAtAu3Auhe@jR@tI@ =@@@@v@'@@D@r@D[@ C@j@~@)s@T@at@@rn@I@\b@¹@N@r"@3@@0@[@}AKAR]ATARAAJA >A -AAAA6AA`JA-AAAuA /A!tA#A%={A&-A(A*A+A-I,A.zA0^A1sA3aA4A6OA7A9+A:HA;A=O2A>A?AAG|AB}ACԞAEAFN"'A?QA@|AAABjACADAF AGAH#AI'AJ'UAK"=ALVAM AMANAOAPAQxARLvASASATAUn:AV*AVFAWAXCAXKAYAZ0FAZA[a A[4A\~A] A]A^A^A^JA_cA_ΉA`4sA`A`AaI[Aa AaAb3AbwFAbAbeAc'@AcXK@=!e@G-@Q'{@[$@d@n@xP@@@t]@%w@@kI@@C@ @d@D@Y@@@Q%@Đ@@w@@0`@@@Gp@D@8@#@@ۆ@@n!@)>@AAA[A!qAA A VA AAaANA]AAAJAj(AJAA_AQA A"rA#A%NA&A(A)vxA*ϒA,#A-sA.|A0A1FA2A3A4A6A7FbA8krA9A:bA;AA|A?oA@AA$ABACAD9AEAFAG_AH9AI AIݨAJAKoKAL1ALAMDANYAOAOAPXAPAQ{AR+AR ASKASԯATXATfAUS*AU2AV:AVAWAWrAWeAX* AX~AX&AYAYaUAYTAYAZ!AZLAZ|@(2@1@;@Ew@O_@Xf@b-@k@t@~H)A?!IA?A@ŕAAABWFAC$AC[ADAEBAEAFAGBAGAHAIAIAJ:AJĻAKJ!AKALFALjAM14AMXANANmANAO)dAOEAOҀAP APiAPIAPAQ'AQ^4AQAQ@@@'a@0@:Zo@C@M @VGZ@_q@h@q@z_@X@@x>@|@@\@b@@@ @"P@.s@1r@+N@@@@Ƿ]@˃@F@u@ֱ6@X@N@ጥ@@@@@D@L@&@bAAAN!AAq=AA A A A AlA4AFAAAkAAAgGAA.A9AvA CA!&A#xA$=8A%cgA&A'A(A)pA*A+A,A-^A.mA/A0A11A2A30A4{A5XA61jA7ZA7ԸA8A9eA:'iA:A;AQmA>A?6A@(A@AALAAAB]7ABAC\ACԖADHADAE"AEAEAFGAFAFAGCAGAG"AHAHTAHAHAHAI@.@ @ O@[@&@/ʌ@8@A@Jc@S"@\@eh@n@v@E@@@@@cn@}#@@@v@M@w-@[@6@@@@H!@=@ƛa@7@@U@I@N@۽@$P@⁹@*@!@d'@@F@@@*4@6ATAAA AAcqA jA ,A A nA9xAAAA`AkAُA7A@cAmAHAA?AA FA!A"(_A#12A$5A%5eA&0A''A(A)A)nA*cA+A,A-j\A.=bA/ A/A0A1\A2AA2aA3A44-A4A5 A6&A6A7\A7A8A9 A9A:-A:A; `A;@A;A<]A5A>A>aA?lA?^A?A?ئA@A@@bA@mA@0?ޕI?U@@ @F@@%"@.@7^@@@H@QD1@Y@b/@j@ry@{ @T@@@@ @w@V/@,@+@z@x@+@լ@v@3@@%@@@ȅ8@@C@ҕ@ @@W<@߆%@D@ɚ@&@@@@u@@@wA#AA#A>AAA1A yA A oA 8AogAAAeAA?lA[AsAAAA AAA AAeA r|A!Z-A"=zA#bA#A$A%A&lA'5A'A(A)uqA*,A*A+VA,8A,LA-A.A.HA/I}A/MA0dA0A1n`A1A2ftA2A3LA3A4!A4A4z@F`@NQ@Vn@^W@f @n҉@v@~@$e@;@w@@P @@_@V@6@9@@q@ @{@@@@B@r@@-9@j6@ɞ@`@@ @@#x@$<@f@ @@E@@t,@8@@@R@@iAASAAAAA9yAh!A|A A JA A A%A6IABAJyANAMuAHA? @W@<@@@$t@@@|@@8@@Җ@@J@z|@@\@֯@@@0@@#@ҫ@Շq@Zz@%@R@ @R@@@4<@@KS@A@@@@@q@ƾAAAtAA{A AA{A $A $tA A A `A AKArAeA"AjAAA A AApEA1AAA\AA AAaAAA@AQAj\A3AA CA |A! A!QA!A"kSA"؅A#AA#LA$A$cAA$lA%cA%_%A%A% A&51A&t!A&A&cA'A'EA'oA'pA'???,??Ì?+?䩶?@@ |@@@"vM@*Bd@1@9N@AD @H΅@PH~@W @_ +@fS@m&@t@{n@i8@@W@u@%@@@@]@8@Ț@@@+|@<@DY@Dw@<^@,@@@@Ƙ@_T@@@с@'@N@Z@@l@z@]@J@.a@A@@)_@l@@v@@'v@A@SA.A/vA,!A$A%A ~AAAAA }A U^A (A zA A *ANYA mAfADA2AA;A1AAr>A ^AcA4MAAKAhARAHAIAA/AAAj\AA'AAKA$ApAAAo7@E@L\@S@Zu@a@h@o@vC@|@:@u@V@@@O@ @$@5@?@@<@9f@*@@@@$@hE@)e@@@<@@v@@ʑ@)@ϋ:@J@eY@e@q@pz@ݹ@@3@d@捒@讒@Ǒ@؎@@@{@r@g@[@oM@@=@ ,@AAAnlA>A RAA5AXAA̓AA 2^A A 6A +A A htA A DA%AA:vAA??AA4AeAA%AAQA@AAfASA AXA`AA%AaeAAAcA*AS AwZAA?~?6]?Vh0?v5????|h??O??@\@ @@3@\{@&uw@-~@4x@;b@B=@I@O@Vo@] 0@c@j@p@vt@}/@H@@ީ@@@H@@@@r@Do@@@@@@AA^3AAAOAAAiAA?NAAPAlARVAZA DxA A 'A qA A ]A YA 0A q"A .A TA aA A fA.AkAeAEA >A7SA`AA.AīAD??ڟ?%ݯ?D&?c.????{?)9?ʸ_?):?{? @@@˄@ @wo@$6@*@1@8}@>!@E@Ks@Q*@X6@^F@dm@jv@p@v7@|u_@(@@@@@@]@@֠@ @1@!@n@@v@l@@@o@Շ@3@"@@ q@`<@t@@*@@-@?@J@M@I@=@* @@F@@ڐ4@V@@J@}+@%y@4@_\@@z@c@x?@@W>@`@@l@W@.@>q@u"@@@@@&@@6AAA@A{AiA[OAkA+AHAAGA,AAB)AAA>AZA\A=ATA6Ad'AAAAYAA%????)?4?QK?n??'?S?a?R?&??U?u?S@'@_@X@@O@!o@( 5@.TI@4@:Z@@W@F@L:@R @XS@^@dG@i@o+@u:@z@@@f@*@J@b@@}@@z@@Z@@@s@@ ^@J@@ @@@@@1@>@D@B @8@(L@\@@r@Ȝw@g"@*u@n@ϛ@HV@D@Ԍ@$@׳@<@ڽ@7@ݪ@*@x@h@*@xA@徨@@5k@e@@r@@ݹ@W@@@@R@2@@l@=@7@Y@"@7@@f@%@@J@@Q@ʈ@;@@e@c@AA$ACA^AvrA[????? -?&]?BT]?^2?y?q??h%?????ޒ?@#[@h @ @ƻ@@@$@*V@0i@6A@@ن@گ@ѵ@@q@ #@@-@@@@@@r@?0@@'@zw@*@ӽ@u@@H@0@g@4@@7@B@/@A@@D@'@f@P@n@o@R???????+?4]?N?i??iY?3K??t??H ?و{?i??@@ @d@$@@!{a@'@, @2<@7@@ }@ё@@I@@@H@@{@ @@/@@3@n@Է@3@‹@@'<@j@ǧ=@@ @3@T@n@΂>@ώ@Д=@ђ@Ҋ@{@e@H@%6@@3@ؐ@Q@ @ھ@j@$@ܮ@F@@`@@_@Ի@C@s@ @d@u@`@Hk@↖@@K@@:@VI?????????'?A?Y?r???L?=??E??k?0?(?^Z@@=@ @>@p@@"@(+.@-O@2e@7n@@V@hh@s5@wa@t@k@\@E@(@4@@Ȫ@r@4@@ˤa@R_@@͚y@4@@T@ @Z@ӭ@F@ѱ@@u:@ @;@h@Ӭ@@ @P@z#@Ԝ@Թ@Ι???????????4?L^|?c?zp?t?[/?i?#?[??J?֠?R5??j@g@@ Z@@@@9@#f@(3@,@1@6M@:z@?t@C@Hhv@LI@Q)[@Uv@Y?@]@b"@f,r@j:@n:@r.@v0@y@}@@@m@;!@'@@}@0@}@@&g@@T@t@i@@e @C@G@j@m@j@R@ 4@S@@ϙ@@1@Y@z@@?@_@@@@@]@<@h@C@@@@p@+@@*@7G@@ta@ ]@@ 5@@@’@c@i@˹@'S@|@h@@U@ő@@@@@@\@r*@ƁB???????????x?)?@&E?V3?lI??M?@/?̛?@??? ??l??T?o@@C\@ @@8@Ƕ@J8@"@'*@+]@/@4M@8Xl@@x.@{B@}@\@(@@l@ @P@H@L@@@@B@bi@|@@K@9@M@@@t@~$@c@C@@f@@o@L.@ @@qR@@,@a@@@@@(\@@@~@@\@@u@i@@@@@}@q@@@3z@Ru@k@~@O@@?????????????a??+?R ?e!r?wQ?NK???g???o?'X?ȕ?S?'?&}?n?C?@`k@W@ D@%8@0@@@:2@!@%@)@,@0@3'@6@:L@=@@ @D@GJ@JnH@M@P@S@V@Yx@\Y@_/@an@d@gl@j@lh@oF@q~@tI@v@y!@{{@}˖@@$@;@M{@Yw@_@`@[@Q@A@,L@B@@s@@mX@6n@@@p<@#@:@w@@h@MQ@ާ@ji@@q4@=@a@і@;@@@Y`@b@@D@@Ŭ@@0^@]Z@@@@ً@@0@%@@W????????????????#&^?5!?Fm?X?j?{f?G#?ŭ?/ ?7?8? ??)?t?Ͽ??*C??@??y?@!2@ @ BL@ @9 @@p@[@y@ @$'@'K@*l{@-B@0s@3 @6@9t|@@}\@@@] @?@'@@F@@@=E@h@rA@@@@@@#@@ri@ڛ@=@@m@Fq@*@ܘ@@]@@]@Q@@CY@ak@z2@@@@^@@@f???????????????? z?s?,n^?<;?M* ?]K?mEy?}?`W?!??f?6?[?z??5?V)?b?[$????f?t? ?f@@&@ I@ a+@o@@sQ@m_@]i@Co@r@ q@#m@&we@)+Y@+I@.u6@1 @3@6@8@:@=bw@?K@B @DQ@F@Ht@J6@M@O@Q"d@S"@U@Wq@X@Z@\^@^M@`@a*@c\@dJ@f@h\@i@k_@lk@mT@o @pl:@q@r@tx@u5@vO:@w^@xc@y_B@zP@{7@|(@|n@}@~p@&)@`@9J@@x@ @I@/@@K@ @-`@K@em@y@s@@r@@i@@}Z@i?????????????????9?E?$=?3ۀ?B?Q?`*?n?|D???$?f?28???#?(??l?γ?w? i???%?կ?_?J5@@@u@ (@ @q@@@@@@j@ @#>@%hE@'@)@,@.6"@0R@2d@4m@6m-@8c`@:P%@<3}@> i@?@A@Cb@E@F@Hb@I@Km@M@N,@Oh@Qe7@Rę@T@Ug@V0@W@Y@Z:@[XY@\lS@]v@^w@_o@`]@aB@b;@b9@c@dw@e-@e@f|@g>@gA@h,@h@i@i @i@j@c@jk@j@k3@k?@khH@k/@k@k@kU@k@kN@kz@kW@k+@j"??????????????????g"?Y?)w?+հ?9^?F>?T?a%?n!\?z?z? h?W?}Q?L??R?c\?0???/ ?ʵ?*?Վ~?Y? ?O?l?wJ?p?X?/1@y@r@$"@k@ @ @@@36@N@a@k@m>@e@UP@<@!@">@$@&@(9@)@+@-4@.<@0Z@1@3]q@4ш@6<@7<@8@:I@;@<@>@?4@@Y>@Au@B@CQ@D@E?@F{@Gb@H@@I7@I@JA@Ka @L@L#@M\r@M@N@Oq@Ou@O@Pe@Pǐ@Q!H@Qr.@Q@@Q@R/@R]@RM@RA@Rb@R@R+@R@R@R@Rj@R@6@R @Qu@QY???????????????????? ?z?$?0?@:@9J@9@9{@97L@8@8B???????????????????????8?)M]?30?>p?H?S?]BQ?gK?q6z?{?X? ??*???%7????>?~d??????ǽg?˒?Y"?C?ָ;?Q ?ڲ?U1???i??G??4?n?@n3@@:_@@9@3@w@ '@ @ 6@ ;@Y@pt@a@@|@~@oF@XL@9@@@@s@/I@A@@4u@Ѱ@gW@j@{@@r)@@ J@ @!@!U%@!@!I@"@"O@"z@"@"@"@"@"@"@"9@"!@"u@"4@"e`@"5@!@!h@!zB@!,@ 9@ zV@ ??????????????????????/5??1?"h?+?4?=?F:?O?XM?`?i\?q?y??? T??S??_???L ?]?N?d??j??? -?#?.?,?I?!??Ҙ3?Pm??ڗB?%?ߦ?t?~q?Ս??Z)?퇧?F?????uF?A?)?@)@9@@tM@)@آ@e@!8@@N@@_&@J@T@@ .@ ~@ @ @x@ @ Դ@ k@ M1@ @ @ @ @ @ -@ e@ @ @ o@ @ q@ @ @ `n@ *8@ @ @ ]@ @ @ SJ@@~@ .???????????????????????u? ???$^R?,?3=?;E?B?J ?QJ?Xok?_{?fm?mG?tb?z?R???(??Mþ?KS?I??F?Dx?Aw??mu?<Έ?:?7]?4=?1???????????????????????????|O?,+?+?^??}@2E5@-=@)%X@$@ @@.}@@W@ @@B??P?~?L??y1?!?a?0?d%?=>?"}??h??|a?l?]?Mvx?>D?.Z?e?;d?)W??????????????????????????????????????????????????????????????????????????????????????@e@_?@Z@UvY@PM@K,I@F@@@;e@6@1@,%@(P@#q@7@[@@@ |@1`@x9??5? ?ݲm?ԅ?f?V?S!?^?v??ҋ?3?e?w?fa[?UV?Df?3?"????????????????????????????????????????????????????????????????????????????????????????@}n@wC@qp@kϼ@f!@`{@Z@UG@O"@J2@D@?=@9'@4g@/@)v@$`@O@ن@@q@ IU@(@??F?{?i??Ep??[?+?*?'??;K?o?]B?J?8~?&`?T?g????????????????????????????????????????????????????????????????????????????????????@r@ٱ@S@Y@|@v@p|@j@d|@^sA@Xr@Rz@L@F@@f@:@5'@/d@)|@#@P/@2@@ @@?'?Q(? ??6?Ħ ?'&??^????y~@8(@1c@+@$@?@@@ @@??B?T??)?ą?,??E[???u ?^6~?G?1 ???????????????????????????????????????????????????????????????????????????????????@+@'@@@@@@*@Vx@@@@>@s@{@tT@m@eǶ@^@Wi@PL&@I:+@B3@;9@4I@-fC@&K@@)@L@ q@|?B??u?]?9z??P?m ???|?d?L{?4m??<}????????????????????????????????????????????????????????????????????????????????@0@@@q(@=@@#@ɴ@@@@@@@@@@y*@r@j]@b%@[/H@S@L3F@D @=i@6@.@'B@ l@MB@:@ 3@9?;?օ?-?ў?(????\E?J?R?j.?QX?7`?h????????????????????????????????????????????????????????????????????????????????@K+@̺@1U@î@2@h@N@X@{@,d@@@F@@ϝ@1@s@O@2@~8@vz@n@f@^ @V$@NIq@F{@>@7@/c@'H@ BP@@W @ @??FR?(?˵?'?P???$v?q?V?;Y0? ?s"??????????????????????????????????????????????????????????????????????????????nyquist-3.05/lib/piano/demo.mid0000644000175000000620000000310110144436365015457 0ustar stevestaffMThdXMTrkXQ '/MTrk~CC@CC@BB@C5C@FF@E5E@CC@BPB@CC@BB@CC@H5H@EE@G G@CC@CC@BB@C5C@FF@E5E@CC@BPB@CC@EE@FF@H5H@EE@CC@JJ@H5H@FF@E5E@FF@E5E@CC@BPB@CC@BB@CC@H5H@EE@G G@/MTrk~>>@>>@>>@>5>@>>@A5A@>>@>P>@>>@>>@::@?5?@>>@> >@>>@>>@>>@>5>@>>@A5A@>>@>P>@>>@>>@>>@?5?@>>@>>@AA@A5A@AA@A5A@AA@?5?@<<@>P>@>>@>>@::@?5?@>>@> >@/MTrk~::@::@99@:5:@::@<5<@::@9P9@::@99@77@757@66@7 7@::@::@99@:5:@::@<5<@::@9P9@::@99@77@757@66@::@::@959@::@<5<@>>@<5<@77@9P9@::@99@77@757@66@7 7@/MTrk~77@77@22@757@77@555@77@2P2@77@22@33@050@22@+ +@77@77@22@757@77@555@77@2P2@77@66@77@050@22@77@..@555@22@555@..@050@33@2P2@77@22@33@050@22@+ +@/nyquist-3.05/lib/piano/pn19.cod0000644000175000000620000004327010144436365015331 0ustar stevestaffSYNCCNDNCOMME `9lo'UPART ????i>CG>@==1=xem࿾̿@3?U@Փ@L@fGRUP?@@@@?@@@AGMAG:;E2$;WCL;ghv;+c;#;jQ;8~ :::M:;8+:;lSv;x:a;?q:'<ɲ<:!==)u==D=Q>;Q>5}>%*>!> ==j>.u>r=>"=ǯU>#>p*>>l>G>i>4>>>GE>?Bm?(?k?0?)?;e ?>w>v ?*?: ?'*?:U?^~?eY?k?w?q;?]T?E@?(J?'???? u>C? R>(? R>D?>5>Q$>>>`J>,>T>h>>1r>!>Z>j>>] >c=b>,>o>>E>s=d=3#>DQ>mB=ӡ_=p=<==O =P.=9F=F=z> =~z=p= ==1===+&==?t==I=L={0=S^=6&=: =4l=D=='z2=ne=<7a:R:bT: :]::N9Pu::<;#:b:׺D:a:L;A ;;_:m`9Cv:v; D;;0K:R;:U;Y[;B;t1:,;՞;K`;Vը:;)t9Ď;;6s;;:ݟ;; ;);1B;,-:B";|P;x?5;Ϟ:^+:;2T;3;O8J;&[/; ;(;܀;*}:t;G:;o:];Q\:;1:Q;T#::j:ģ;C;>;+I:;;:S;P;;;3.:;Y;$;% ; +:Ҩ:T;';>;Lp:1:a;);5;@i;A ;;ݖ;O;*_::;;.˞;P!:;A:߆!:g; O:t:::ɓ;;%9B;#:8: F; L:k8զ:e>:[::6:::l:q`:qP:i9{uq:c::%j:9:Q9)4:?w9;y:k:q 9؎::5:9n:K:G%:Yn9G :Q9Ng9v:4:H9_ :3p:-:WX8#Q9 5:K9_: 9 ::2hb9'9s:Py7㹾:?49:Ѩ9:+ 9v999׻/:u]::9X9:D!:k:0b:9q::bR<:oq9W\9ig:*:0H=::w:9:$:Kq :]:FŇ:}::&:l:l:Ie:?L ::&:ƅ:>:Z: s:U:T:'9>:s:p:-::8@::Ec:ə:J:Z-:b:cu:R:E::H#::oTc:]$:u:Rl:81:?:LJ:m:z:: ::ڙ:FD:c :Q*:C:`P:+E:KZ:{:34:~:*:;:sn!::W::@9O]::6::o:uu9}:99v:MV97:}:q:p:qy:0::$:[: |: 9R::S9:#b99*9M 1:r<9:b9X6-9{89ɕ:9}:9]999`n9$9l989:8`9[A:*X989K9|&9S9!f: 90 9a9΢:)9%9m9Wؙ:J>97F: "9:E9::W 9 9#:c:4?:9}:bE99.:R:*M8v_:D:i:#9E:Jw:U9:Oh:j:9-:UU:q:T:3m:U[:0d:%:l::ɚ:_`*:@::|:c{:]0:v|:Wݽ:d:ZR::wR:!:t:A&:f::q:b:؆:-:::N:K:D:Z:z:xɫ:2:*:2:Si:s:`:>:$:K~:T:g$C:j>:%:'"::{:/:QGE:R<:;::G:TZ:@Q:rP:n:6G:v :MS:=6:J::c|:L::iL:^H94:T!>:)%:A:,Ա:x9{9mH:.:)::*wQ98:PX{:@: :BM:BG9f9:R9J:9:-\29+79B`:0y9߃9: g:>{^9]df:999 9:1v 9ծ:_H9:[8Ӂ9ӣ#99 n:_99┩9P9L999MA9rH:94:g9S98cs99w9{9F9g9x9!259̿9+99͖9q:"998f:9#9.9H9{9C9:f89Go9:919):UO9:9:Q819-:{N:ϐ9u9iq: 9Qn:*P9P:)9:"{>:#r:+9-B: _:9:&Gp:'99: P:95:!9:59ÙE:Bk9ʥ:U!:vv:::6ޙ:>9\:B9q::%:2 9p9:!G::+:r:+$9r:):4Q::,9E:;sX9#:5E96:09u:,v:bX9뽼9:x: :N*: 9B: r:,:: @9 G:9:9`: 9Q9n999 |9Ѓ:"/9J99999),9o9d9Ù9'99Y9999 9 9D939Ъ99աo9(9ֶ9@9|9p<9q99>]9p9p9hV99WzV9t7>8k9u9)99(}9ї9%99J99|9&99X799&&92՚9 9fg8jg9G8ex99"ƣ9P8w9^9=; 8<899h8u9X.8-{89N8w9u89h1R9089;9<=!8C9Jx9pH8 {89V[\9dD7†8(9t^89D9968,9+9{9?tD9<9!89û9&9KtX9`5w9fM8tɨ;n ;T;:'G;DEE:W:+e :D-;;;+;-9+:E9:S8Ci;7<1=/M=^G.==> 1T>A> >X>)U>}C>e$>f[t>' >g?$-%?ST?b>??A? ? ?>@? w?QMj?'> ??>>Ӧ?3?B|~>ߩ->.C>?&1?1?\y??\h>b>?F?W? ??? l>>B>>@?g?R>>{ګ??5V?8/?:?/rv?{>?85?!JM? ?8?E!?$?r"??9^?>?+ڼ?*@5?^?M>hV??.:?6?s>[d>>Bm>?>>Z>#>o>k)I>]=>>צ>>O1>?>C>*98>h>>>N==؉>FU>S)_>5t>>W>F=ـ=F==C*=)=> )=J===x=̗> -=4=r=4=/=z,==d= =X>V>>8E>-sC>.,>v=j=>P>V &>:>\==i>0AD>1I>4I==ʢ}=.===w=N=I=+=3==:d=t=tX===Y=L==l+=$=+==a9===Y=sݯ='<9<*J<<<<&<_<3Ť;&;p;<O;hK;9;C*<<8ӓb<#< <=7R@;t;{;<;S;.;?y ;7Z;2;;4;L+i:;C;ɧ;~*;T; 4;q;s;0;Qv;Hi;; ;;9;Ta=;5[: ; ;Pr;g;M/:w:l:6;=@;rX2;w3o;9;;G.0;s1;;;\ ;Lr;\;8;Sj;;;Q;>;/;;y ;+):ͩL:̔;;E;: :=:-;;;*:n=:ֈ;;M;J];>j:v:;K;]`;z(;M;;;;wDx;;;};(m;0;R ;wO;y;B;+i; ;5;Ua;?y;M:>:W;!9;6c/;L:]:Qax::l;(9u; R:F]:n+:4;`;';/::Ѭ;+;3;6;7i:uS:ᬀ;;;_vd;Y;MC];B;;B6;[;Pch;+b::Z; ~;;Ǚ:J-:FK.:eo:uT:œ::59Y&:J):<:::P9f:3`:g::ڑ:{:A ::K;:C:PD:Pn:>; @;=::Г:hd:]c;V;:ƴ':@:Y::;:İS:Lf9Ή:0q::z:8:#z :8K9t:d:H:Yr9/8_h::B:_1:4r9R9u:m:U::H{:,H:s::Ҧ:`:H:dK;::Ĵ:OM::<: :u:\:}:c:$T9V49:U:ll:]:99 :,^:l:g:$969/B:g::Ss&99sf:':'::::::::o:y:!n:K:::p:f=i:%:@# :Ш:::PK::M:5:]:d::%*:/:O:K:z:c:;&9ک:z:g:q:U\:N{9ث:l0::-:SN^: :<^:v=:: n:W$~::V+:g%v:%::3: ]9^V:rB::X:%=d9KB9k:C :[ Q:ct:ِ9~::MS7:`W*:69t<:k:o:Af:R4:'E9^}9Ϝ:ɞ:e:) :*9b~9쿼:%/:W:;|999ߦ: :6rn:9`9z[.999ֵ=9C9l929Nx9E#: :999VL9w:#2,:7:8{999:p<9Mi9R9ǶC9I:u9Q995N8˗9Gc999 8%8tI9\ 9Ҁ 99,99TJ9CN"999 99B^999:J:[T:Ym9ϓ9յ:Q':"+]959s 999e:[::9>99N9Y9p9i(9^89699f9<9 <9;h99cc9`m9>W9i9c999D 9W949Ф9@:1::O9(9: v: 9w9 99:9a:ĕ999>9v^9 9䎽9U99.9998gO8!99a9z999:3999e9ߏ999.9 9;999%N9sq9_9C9ۚ9u9599!R9Y9tiv9c8W9 \9D9t)9P+7)8CsS95o9Ty9y?8q9f8/9 @/9 9y9 [09"99B9J99,)978ޚ9N99n809 .9CU9lh9 ?829*{8!?8J(9M9x 8T99D9 I97 9aCa988˺8 98%8g8й'9m!988s8sn9%92Ǭ9Z7ћt8"+94`9-~8,dZ9be89'9F9s 9Nq89-98"9#8919K88 ^9`>$9NkA9S989[9k9U9xJ99N964899X8>99N9f9c699P89&89z9e99&d8 9b99j8nJ8|8*89 /9{9X"9Gt8+899Cy9`8٬8ֆ9s8(9)9F8 89Jt9;H9099n8]909b 9L8׍9;fP8q99P9r9I8y9u(8:999fk9f8̋92U 9q8UP96U88h9/,8P9&p 88/9 N9A9~89{Gg8889u-9 u9q8f89T)9n888f?>8j7f8EY8p9.,8{ב8 9Gge8mY88^t8\8 7yp88$]8s8,)898+D89v8l6889*K87#;M?;W1;lM;o;f;G:#] :V5:G;;>2: ;Ni;6&;3E;Y; :ѐd=1>h> ʼn>+>>y]e>Nn>WL? r?O>=>2>c > >?1?ze?lC>>>>N>n<>[@>gF?&?A9q?2?Tw??e?-? l? >>>3?>^>>d>>u>V`:>V_? 6>0>>?x>>ٰ%??S?+Z?Kk?)>u>|>>>2> >R>&#>>=>H>7=P>V<>7>۬>>@`>H>V>>>a>ai>Dt=#>T>>>.>C>I?7?pD>> >^>>UǷ>>M>>>ۥ>= >;>s=g6>`>=t>=B>k=l=mb>>=@==2G=y<=mz==MI=h0>=)==e<8;-;-:j;a ;q;z%:>;l;L; G:(;@;;I;;Vv;h; ;3:x!;o(:2;;qp::aV:/&q::8';cX:k;cwV:=; ;3;'sb:wW:;m:K::׮:Jl:%G;%_:\;C:;+;j: R-:s=: ;6e:":u::R;B;|;B:Jm9Q:S:!;G#::r;+::f:%#9>.:6;;-:26:L9n;9}:*9:rZ::G:@9s::9?I:t.:~F:<ӻ;%:/:L<:j:@Dn:\­:@r9!},:`1: s[:JUq:c:W`:[9:Dd:#:8p:eYF:Sv:}:G7:N:UU89^-:/8}B#:Te9|d99Q*:v9h R8F:.>:99j9:y8:6xK9999I9:\: >:RHW9 V:)99-0:\9L9J:[F9n/: l9:*Έ9G8:9:8#]:nP:\f89d99XF9}w9Q:sl:/U99ìm9979|ܰ:\9BX9z:69N:?9S::x!9 :9 9.9z9cs9Ig96:6^9]k99O~8o`9:O99z9&"J8ӑ9!9I9~ 9: |9)899ά9r:=|999M:Un9`:/#:%8BN9Q9X:Gq919Kw9*8-d8S9: {9ii8t 93lC:N4989R9y8yV99:99$:͐9E99h99}:19099Ҍ939ç8nN9:$Be9/9I9w99|9118Jr9P{8҈L9Iq999999s98c995)9K 9G98_K8#89t909|N8:\9 8P9U9,86a9w98 }9Di:69g9H89}9lO9`9"kF9 X9998C9H:<99d9498Y8xE99* 9bd99.9aL9e%9Q=:89U9xV9+89*`98€:9d9l8s:'4+9t8199i9_)8h9^288H9e"9<9'm9Zf9y&9Q]9Z9) 9sbu9X96b969F j9k9j8ݘ9 9*6p98i9j9mc7q9c8:9/v9K88999 E91r9X9M98c 8ǣt929889E9%<9n9[\9M99Q 99m8\u89Q)9l9e990!9wZ9:ˎ899Z9js8\8C9-9$9ic8 9ױ:(9_j79{8D88w8z8v99Y99Cd9XG9N9w)8W7 I9!99)R9}$969˼80989 8c9I08:89|996c8A/s9)K`9)H9na9G'9E89i9[K8n99r9|9|9L<9P8E9fy9EK9=08:/9C8c79f<9O9F9i!99Y99t9Lͷ89J}987H9 W9(e83M:+I89A9:9И&9z9 9Y8l[99 K9P]9X78md969ǽs9A98VI7(݊9s5\9P9z9p99d9UE9~8A9C49* 88O@8(9 9b9A9v8r99FG9;i8919:H>8뺊89O99W09:9y8-x;9!Z8{9v9*c9s9E969 9 79:9 ^9Qm$9 9'-a9":Q88H9 X9_p9}=Y9:9293|99O9&8188v|9;9yi9'`9 p98{k999T8:9D?9B%9>9989wX9Y99Yq9O~9n8>9`9b9A9xR9m99P9188{8M9l796*9;9S9a18{c99tG99я9I89bZ8 8 9#s8͵9w8i9̧8ڀ9<X9]|93g98ᳪ929_su8κ9848y9POR89t:Y9h9Q)9S:8xM9Mo8929L>j9<"9Z²9V9QY9^}8o!8r;9A8`y9ώ9Ld9Z8]M989r48:8H9 9:9=9979p9 V9ms8^m99%979~9IPB9c0l7o89m98%Y9L9A=)9t8X88 f9S99An8Ӷ9%9W<>9 9>C928Yh928b8gD89 w9l!90a99f919E9J98y9 9ޢ98M98u8[z8-99բ9yu9 9e9dž9 9G795898J9 ,9O996949iR39*>8U-8 90>9}d9 8997939U999k{9H*9^9st9%9#\8 9V998\|9Je_99k&:2\8~P7b9g,9+9L9BZ899ێ91B9i9^l9T:888S~9779<`98 99M_859|9%L8v9>*9~19ª9`@98p9T8V89"9%tK9Gz8!"8V9$9?9v }929d%9|9Ǥ9,9$-G9=9.85Y9k9!9Z9v5 9W7;X8k9Gt89;99y99_}9~9i9b9Ņ8h 8b8#9iNW9k899w99_I98d9y9 8,,9y{9(8 9<+9g9kP9z9K7nS9&8.M8cS;?;</;7;/;C;O|<<;!U<;5B;;*Z; 2>S@>I=>8f>2M>Q>Vf>T '>6<>17?*14?N>e??8>>2??% B?2K>#>h;?($?E>@>+1>NZ?jb>A>>Y>>N>`>>>n.>C>3q> I>wS+>2>(>l>*>>TX1>\D>u>r>>G:>#>>%oc>)T>QJ>>O(?>>>G 3= >e>:>i>) >̚>N>>>6> >5>F>!>5W>t>'_C>>څ>$/>>q>>w>HY>T>4>@C>m>>ȣ>C>?>_~>>u>X>>Z9>/>>[9>;>>R&>+| >>=>e==, =e=Cۆ=O=5 =#=g==N=<=t=Ma=MV===nO=m˶=P=8| =Fj=+<%=&ׂ=:H=?<Ȯ-<^<1=<5<;< <-; <`:ڊ:c?:9;1;y|;a;Fjo;4W:;E;c;u;X6:;Hl;:::>:;#;{;9T;C::8;;G;#;d; u ;I:s;:{:^&:Z;qwM;D;0:dt;V;UB;o;I::~;D;H:܂z:d2::aE: :::X;(T4;O ;`::;=0:V:~:L;Y:t:I:*::M;D; H; :X:_:C;GR:M:;:E:M:)j:K}:W: ;:8:_::::T:W::G::S:4::W:::L::#V:s:.J:Q:ގ:T:p:m;.H:ga4:Z::o:8: :::! :::x; :B:Y;ʭ::7::;%;W:i;i:5:ܖ:~::f:zWj; QC:2::T:¸:{:;;z:F:N4:::1:nO:M::-::O}:}J :(W::M;::/V:::::::::w:#::ޏ::u<::^:yZE:ܓ8:r:::W:5:+:r :j:N:v:zg:,:Z:X:ϐ:E: :Cd:.B:7::R":ޓ0::T:?܊:U:%:Sw:X::::^::d:.:li:m: :'::x:%,:bt:{::?:b:W::&:F:}$:}P ::V:1G:e$:z1:::Y:E8:- ::«>:K:R:|::; :81:x:::ڎ::{:":::p::9T::>:}%::a:c[:V<:L:R:x:::6::q:!:A::s!:::: :q::A:n:p:w::f:Ĕ:::b:~;:o,:rn:\:W:3::V:h{:?:Ƀ:w0:;:~R:: :s:ʂ:q:M:j:>{::1:::Z:ٚ:A=:):2u:#:0:ݘ:<:5}:걌::ք:: ::hx:8:19:I:v :ҼI:&::n:h:::b:>:: :fő:fz:HS:m:_:_,:\:uѾ:ť:}:g::^2:::ܱ::=l::.:Д+::%*:y:20:i:F::P:BT:S::t::n:|:0:„:::::D:ϓ:mO:r$h:x:#d:ٚ0:д:\:\:%:1r::N:_:Y:2:AQ:\8:k:-R::::[::R:`:::2:\s:i::::c:޷:4:~":;::::{E:Ϫ::5::}::[::!:P:::{:+::li::3`::=t::cK::lW:IJ:j:w:Y:-@:Yz::F_::^:%:w#::h:۰:L:{:ٵ::p:k:*:PP:q:t::_e`:Ӑ:v:9:X:3::*::{:X':ޤ:$:n:: :SZ::b:r'::Rj::sX4::ݮN:A:W:G::ʾ:K:::9:AX::}:I:]H::p:Sg::{6^::zI:U:q:;:D:V:k:q::8:׷:: :̀':H::v:m:dv: x::y::::Y:q,::M0::F:Sx::s#::::a4:l):jE:F:ō::i:Q:e:ݖ: ,:*:z:Ɣ~::g :?:Br::p:E:::::N::: :/::d:b=:l:2:t:C :٘:h:7::䳫:y::˜:q4{:h:2:n܄:O:xB:wTF::V~:Q:-:K::5: ::4:^:3:D::e:dn :#*:q::h(:S:2:::n<:`;':$a:I8:::::I::YZ:6::]:ki:N:wv:+%:÷:`J:Ҭ:'/:)k:T:OV:x:Qe:2:ٚ4:=::P::\:::R:v:1:r o:~5:=:Xs::%:m=:x:q:N:o:G:Tz:$:v:֩:a::rOk:^:s::~:pJ::UT: ):*::h:^::̪::?::R::J: +:::::S: :s|:~:ޛ:.:):W!::X::::|::Y:::@$f:qU:k:y:(::gF:7:wg:":*:r[:6::x :i: :s:ƺ:,:dE: :2:JE:l:rB::*:: ::i:I::F:v:\:P:;:F:u::h:\ch:̛:4:rv:ɋW:i:sgu:·:ž ::::::::G:q:X:X:x::O:i:B::q::7:::zX: c:Tnyquist-3.05/lib/piano/pn18.cod0000644000175000000620000005430410144436365015330 0ustar stevestaffSYNCCNDNCOMMD9 (TPART ?????0O?$Ķ>^>o=a=>=)=po@/:=_@x3V?3= @N >84?ɇ>?ҹGRUP?@@@@@?@@@@A@GMAG;{z;"S:; W :Ϸ>z>:̔>l>!>6>>va>Gl>>Ak> >6?>+#>K->M>.>>v>7>W> ??!?$?c8?.?Ia?$R? ?%?2v~?.?-aS?C}?[?[?F6?9[?M*?a}?c·?bN?`#?\>-?^?V?I;?R?g?p34?n?jz?h?lU?yv,??u?Xw??y?=?JI?S?VJ?T*?Qj[?O)?HA?E^?DE?9C?&? ?'px?${??+\?A?K\?G"?@{?8?8t?i}?A?G?O5M?N?0?? (? k>GR>t>:>>f>D>_>F>M>>>'{>!>2>>L>r> `>8>>>t >tH>\r>g>[;>A >?+]>4+>> h>s>t> {> 9>W> > i> >>14==by=m= =c=F=1=6e=yi=I==v==&==|D1=0=m=YIi==|*={<==p=5H=hz=gf(=Sx="=2=#z==8S=&S=8=@=?=3l!==o=-= B=><@=a;/;k;j;(;;#;;;D;5;53;Ӎ;\;U;M;;!;b;;;n&;5;d;q;6;;m;7f;;;8;`;4;n0;K;;v*;>;;;g;ɋ;SR;;c; ;;6 ;۩;`3;?;sw;=Ҽ;L~;V;l;1^p;;j;ז;L;et;=F;%&;s1;J];.j;";I::Ij;;?;b;$;?}[;B;c;2}=:u:;@;2<;;@:˔4;&m:;;";3;@vZ;(;aE; 'N::;68;f;x;V3;!/;t:E;":;(;Ju;) :z;:e:+]: :߄:6:>;k:q?:8K::熏:—:؋;!;;GI; :P:z:<;(?;f; o :F; 6[:>:=;4:W;F; ;-5<;&|;0; ~.;,; ]; ;& ;'=;2Ϙ;N;%:x;:;;2:;Y;-; O:|:w; :ԫ\:k;.]';#v;v;s; :^r:}A:؄; b&:Z:N;ن::r::[::;c:^:::] :<:؟: :]:]:I::@F:}q:,::d΄:P:F:uG::s::Z1:.:7ν::.xL:[n:X#:[::?2G:: В:00b:b:xg:'}: :`s(:W:aX:e>Y:~"&:9&:!:_::?:r:G:::::g:: :~:h&:.:{df:`]: :Jn:5:O:Qi:[:d:S::u::{f:kvZ:f::k:U7:s2:ڊ:#:u: :m:;:N':WV:pQ:|x:{X:^L:VN:A(:N 1:\:7#%:z::@:F|@:M`;:N;:)˻:P:{:`p:L`::U i9 :Mh:Q%:*;:BM:V`:R5::'l/:"Y89ڬ:a:YR6:2:M::: :$R9E:' : }::Jgt:)9AK: :P'9 :,9A9G:~99]R99K99/z9[c:F95*9 999u~9ʗ@: 9㊓99MN9#F9+q949A9(*:#hE:::{9c: -9u:.ʴ:-:&: E:?:Pu9j: 8 :#:3:P:Rs:<9:$*:o>CK0>`>_>Md>JO>@>>' >][>>_>>9x7>pv4>Y'>|>A>!>$>>[>y>e> >j>=? 5=?Z?[?>?"%~?>>>">>>ŴH>22>>(>W>O>>D"2>!>!> >_g=X=S>D>Ve>4 A>=#=Cp> Y>&> ,=o =*O==yp=*===t=sG-==-!=H>kE> e===E=m(=Fb=Q=Qf=P=.=dҦ<߁*<=W=K@>> >C=P==~=<{>O>}>==x==Ǣ====L=]=Jm=߭=-~;=FZ =Qg=Ut=S]=>`S=(_=/u=KH.=qr=yj=i=Ga#=D]=LB=o{==b=N~=y=ZA==w~=q_/=z=҄=d=֙=rg=W=.I=== v=$2= tP<$<<U< 1<<3+;@^;q;:c;a;; 8';::5:@:;9*; .;; :ѹ::ڙt;;!;.;'߳:::l: ;;=;+~::0 : U:;U;S;:;; :::Ⱥ":jr;ْ:;:f:f:B:BH:sR:o:u~:g:c9:N:)U:Ƒ:f:!::ľ:3E:rR:r:Rq:g:uD;:3Zc:/:2:M !:S:ru:wb9ٿ9#9d9>:f:pN99sb89ҁZ:-:(g:@999:M:|:Ig:hۦ:KC%:?u:.$:(i:G:`_:l::y:ul:N?:Z0:_:ս:D::j:.zm:X-:2&:@p:@:b:6@F:$sS:k9t::Q1:W:P:A:ˏ9{s99OQ::7]:W : h^9%9D9&P9/::}9`9`8P.&9M9Q:1B9ɣ:#|6888"99N:(\k:#:?E9\9/?9;9K:P:>a:RF:9ܱq9`9::* :B:+69į9Ȍ9As9^;:::#9AA98PӃ8Z9b9plY99Fv9U909/9D93W9J988199U9[99J99f9im9Po9P29T99wr99/8w999999J8:9?9C999n.9Oi8`9& N8'>8P>99Ee9M9 C;8v898R9vF9̨8?[9Q[895w97 939Y{9.&828CQS9-R]9G99209988؊8Jk9_|k9̺996 9Nv99/8w9F99a9!9>79"&<83zG899P99?999 7B9ZM9 98Š59Q89}b88E996u96888j9` 9s90Fa888 9- 9iUM9[N9T=O9C.9Gj8&8R9^n99i&98 9^8ށ888j9 r94E9L68br8Y)8t V8$858߶8^29x28a8DZ9cl7]88+80o828]9t9h89o90I[7x8[8Os8|7p9(89=8C898z909<) 9+ 8ɏx8d8K8mX88&9s95X909A88g8z8,8Ż86848ǵ8a97B898s8 .7޾D8q8h80w8.80 X8d8 7{898]&9#/9]8-89 }78 8 C9R(9G7!8888Q7䨍8l8oJ8ED8,5o8395889>y8s2H8V,8U|828z8I88 8= 8f087o8 S988]7f8sZ88<;8:{8V9 4828i8 s8i8&KZ77P88$8809# >8H97u88B8F 88H"88o8(8 B88k38y7X(N8֬8t^8rM78 (8ّ8,wZ8(9 88d8?8'88j8~8q!8r88 }88:i8n278c8898P78yݶ8j8+8^+9n8F]8s8o79 [7ѫ 88V7g7隃88eW8>s8;7U7v8J87K`_8z!8_88~8t887F88+88x8d8k8_8M8+8aW8vb8W7&888h80H8$888f8K8197[:88A78k7$!77W3H8Ej8'87 8Lh8 S887#"m8Ҋ7_8z8Ay8zn\7ߏt8fB7F8xj8l8]7g8]8U8#֧889RM8E7*8Z88㲒80x8/B8'&88 8QЁ86>ę>>ߊ>Ϸ?Q>`>h*>Zf>5>.(>Ϧ?Z>ߙ}?&?JD?IY?XsZ??Y ?#m>>>>>=?%l?* ?JO?jH?k1?3??s?E/?.$?"*@?? p>#?(?M?S7?d+?\s?`?Z?gf?Q^? x? >L >j>=><x>N>?>Z>?H?"d? :???+u?$?>>a>P>>ZU>^>[\> ~>IW?Q>E>>N>En>>d]>!>B>A9Q>E >o>>->Hy>g? ~=I?B>y&>>u>N>c> t>>Y<v=V>;m>V:>>-:>c>r>7>8>=W#>V>Gk+>za>Wŧ>ܩ=z> =י==>+>$=U=W> @=e=ӤU='v=5Z<=W/=0 =W==,:@Q:};n;;3V:Ƒ:5v:#H::N.:A0:J:9KvI91:v': :|k+:<}:P ;:7::&:6x:CK:ʑ:0&:z 99*:ze:AN:y:H:_%:k :E:uj:ѝ:tor:@699¶: C ::):9t|9L>9*9k9o,:Ag: 9:_:0Q9ܷ.:6: :/ũ:2::A:^z9?: :5:A9:ڪ9979Q9PZ':X[::9K:7:W O:x1:_\9i:J99Y:*΁:A-9n9f: ,:}|9;:9i49>9:!::5P:t}9h9+9E{:DOa:= :Q:6c9E^::S:B8 :799 :j29_:9P%g9Ɠ9:"9X|:d99F9R99:999:u99F 9t֔9:u[8ɢ':h9fSS:=:":9v9:$$h9,9:K::9L9i9B9$ݥ9o9?|::\{99Z'9K9--9-9:Cw_9_:o998z6R9ma9`C9X909nl:9li997Z9yA9+99g9V,9'g89&{9q9py :9ժ9}:9k`99+z9 959?9!9G:G99ںz9ܽi9F9p9<99F869,9h9&i9 y:/b9@: xE8a9f9wt9,d(9X 9r9Y99D9":x99p9l:|91_9J999A9}9B9(S9g39l$7)9\3u9r99192(9[9*9z:n9:899Z698#M:K8x9: E: q9A:@p8_"9[9P`:ڣ9dR9"9P9+9'{9Vz9XQ9E9u9H 9:ѵ9- 9o9z"99a9^9d9b989^;9ٵ98A8p9':B8: w9N9P#:=9Z9}T9%889m9l 9:9k9a99999Qz98b999U9 99B92k9H9?)9Bs9ߖ909c9a99:.B9O`9#89 }9呀9{9i9c9k8I9>9":942973:99U9Oj9Ic9lr9H_9̵9/9ng9c>9T9?8.9Z8C889 9z9E9O9OO9Ӏ9Yd99"9S8{;88~0969m9Z9 9949,9Sk919T9a8: 9wt9b9SJ9 s}:#99sݖ9299)690'9}:^9tU9>j9D8:y9Tr+9^9NtG9 =;9z:R:<8n x9 :i9[s9 98v9\9ݳ999c|89\9Y,:8 8T8լ9W99A8>9ޢ89ai7\9Lʲ99ju9v98GP9s9Oa99%9OP9&`m8]d9u9G19_9u9B89N_9*9z9фb969K*E989&=9,]984969,9g9:9S99dS9}:9 >9P{8a#9G9+E9ذ9 I988É9BZ9v9Z!9=8: 993F9[9p9?59;,9ի9\959Xj8ϫ :%98RO9298 9899cd9ݯ9:d9/R79Q9:98 9qz998hh99˄9d8$9`99`"8v9l9:9]]9jP9c ;93w9ݯ9yR793q9x99 :9c8Z999#9+t9899jn9P98)9q9ǃ99^\9m8S89ex[9h9U9@$9:z9|929Hb9{V8:B99-9U/9ط9198q9P199܂`9*99X999*vR9n9W\,99r=8999::9B99j975*9g29'99z#99E"8R99l 9fQ9by:v989#J9cG957r9>"9xb991:8Lg889389m-8m49yJ9269=9Zj 99b90$89'9496:4S9O&99a9R9k9qf 9289b 9hN9!k9ɯ9X99-9Z8N:-<9X:9:[9i9W8h9A99v'9"-9{9 O99r9%99}\899To8,9x9x9>9gD9CS99fxr8: S8 99y8"9 X9 9c9.9x?h97 l999>r9}9 (99]9^9Ȧ9wzC96/93999ū*99<09rݠ9l9T]9d9vӀ9T> 978:9a9p9k89@*9o:19~8 8: G89f9)o9h99979U9T89<[9989Z9 ]9\"9 99)9 9@9W99#8s?89:1@9 p8H9988K9 9W`9Ŕ99\9ⵄ:R9 9Ä828_99xd^9fg9^$$9zr 9a:^9{99O929m,9-8I99Ju9wN;W;;(p<g;<m=+=f=>_=>o~> >ٝ>>>[`>m>>п]>>\>>P>kR?"?*KB>ڋ?j?h=?u/#?t?M_>/>[??6O??&? nC?1? ->y> > 7???EI?C?_?+>ٛ=2>C? ??$>׷}?M>(>]== >N>&>>t>y>oY>O>5>. >W[>]xh>>0=3J>M{>'>cOH>|>q> >=(>N>=j>Ѽ>ؒ> >>Ӥ>ʄ>2> >>`>Q_>^>ƳO>^>F>M> 2??C?L?>>l=d>i:=Wc> b>>i6>&>I>U>>>b=d<=\= >>>"=R>H}>c>c><>F>)td=W=*h< ښ<==}=;b=-=;=jZ=%=co=И=Tf==P<=-%${9ǩ`:t:/:V::?k:KK:y(::(ql:30<93:yO:z:::ޖ:d9ry:G::":kl::LX::::e3:;9I:nq:U:^,:6[:Wv::/P :J:{':HB:y9>q99-:T:E]:+:ɫ:R:ܞ9)a:>|9J9X:=:-9Ŏ:q:D:U58:{^:y:N{:;(9)Y::9e:;:#9M:S.9:Xt:):::9<:R:<:&:vz:s:^":B5:+:3::::e(:!~9ʣ9: 9|#:9:N9[:29::1:H-:Gi:29%x:c:s:%:a9$:h:ǔ:*H:I>:(':q:*:[:=::?t:0I:sw-:I:C:"F:=::Ϡ:1}3;K:K:#:.:S::qc: K9<3:z4:kU:>i:.:a:/::0N:#V9Ι:B::>b:O9]B9(8:":O:|:YQ:EM:9eE:\:9:/I:%:X:9l:49:I79:=:J::iD:o:t9s:@:ï:w:>:;C:9!:9:\:l:I:6:؟|::9-::PS:: 9_: 9IG;7:c9ze(:C:U9::8;{:FVO:ac: ?9d0:je:N::N}:5X9K:I9$:M::::r9:[m:Xz9`M9(:]::f: :Xϒ:Qq:a8qv9}":::3;9XRZ9w:: 9I::z͕:AHm:W9$:(q:"9:$9g:Gt:9C:F:,:74:Z :R29nf::TN: ::8:Xj:_:U:Y:8b;&`: -:G:@:'߰;$P::r:g:%:@8ҷ:9{:8y:I\9I&:p9;)::͕:hP:Q:29Q9:JR:R:#s:L:=::Sm9 8j:$:%V:@C:L:9ZѠ9ck,:t@:ca: : 9B:M:h?:/3:o::u:}:t99h:)91:sd9:n:4s=:a9V#:Hc9:Bq39O::[V::nQ:4?:_:#:h:% : 9:v;n9:y:::X:v%:H9֛ 9:i:^W::^'9:'::7I::@:^:E`:?9*9έ9YF9]=:<:%á;:{9-8(::|9cD: :#:TX:U:h:j':q 9::: :<:bK:A9R:`:ë:5:mT99ރ9K9]):>l::!E:t :.:=9h:w::lP:/::b\:::&V{:$n:::q-:_T:: b9`:::r:G:y:&G9w9ġ9:~:B:Hp9T891:w':on:CE9:::j799::B:y9б9y:L:?v9w:MK9Ȋ: :FO9:9:&:B:::3ċ:ܵc9^;T:e:`:`: ::Z;:r : }W:yU:S:F:n:99,:(:4N99 :b:T:9v:4c:at:N:1!:5293:_:6:ć:[69"e9:):N7:Щ:]9%:-I,:-::X:`:[ܽ:ZJ:pZ"99Յ:D:Qi99:\=:Zn:jr,:Ź:7=99:y/:9:,:):p9:k ::: 0):r:E4:c^::=X&9I>:A:Q9:`:S:.F::K:-Y:w:C):: R:9~:f:<:ye\::f:;q99U:0::^#9 x:.;:P::::":$/[9 r:Q 8|9Z :>`:7:|:3@,: c:&d:O:#Ś:0?:S:n9`:)^:9:n)9:r:^M:N:{:z:CNO:::x-9)::h: 8vc9:::GH:/9 :Yt:C:. :H:H:Ù9ϓ%:.:-W:*: R9v:X }9*;H:u9b:::A_:6:y:4::s:!:3: :+F':9:=:c@:i:c:&:b3:>L:.9v:r:~:=I9m9MC:9.:g8=83::5:֞9S.:,|:T~9ͥ*:p:":B9۰:bJ8z:9j: :X,9::8u:kI9 :V[::[:_:=:d09u:Gv:D:y::F:#%:e<9Ę:RNn9o:@i:IU:杝:{9M9ט:7:j:F:AH:VU:F9: 8|8:?;:m9q9s:,9U:h~[9::::u|:#|T:b9:U::1>: &:R[q:N:6:v9:0^:9jǽ:s.: :M-::[1:c: :s:|0:B: `9\9Qu::9-:o:l,::>^<Ȅw>[>U>Jl>wv>u&?+?A,]?H?v?ZB?? >>ް>w>>M>>>G.>\?6q? Uq?4&?95H>ߌ8?$,>z??;f? ?D|?]?E`>%? ?8>+?'?p;>[?#A?M>L_?Q>>&>>>֯>>v>?p>4>O[>}>rg>Ս>q>`u>Y>-k>>>D>!*>O>>>>#״>g4>hw>>^(,>SI>q= y>-c=>3>1>F>>q!>3># >Wl== >^>;>>o>b\>9j>k>>~>*\>"S>H>~>)>a?>M>=e=}==y4> > >=5=՝=Za=%<E==m=:=t=|"=%I==N=,7i= K=_]=.=U=cA=ʞ=B=nY=W<<,<d<N3<3LO< J<`4<<!~?;d;;S;{{;;0;ҭI;1d;z;.;-;n;[; B;V'f;k~;r;G;#w;*;W;3;;g;Q;};x;2c;B;;r2*;~+; ;';;G;Vi;zw;lL;2;jX;;-;.;a;;I>;X;;U;`>;~ <;;"5;;G;IJ;6;r6;W ];;U;p;;;cx;I;eF;;;:;7;/;;S5";;M;s;`2;KQ`;|;\[;;I~;i;%;>;/ ;`;uӞ;;I;0~;6>;%&;;7;;"ђ;~;{<;pV;;i;c;On;' w;N;;8 ;I;An;D;j ;Z;)s;B;j;JA;3d;};c3;bh;k9;`;l=;;P$;9Z&;w;[;Ep;jm;et;{MF;Q+;s;Q@;[?;R;}f;ZY;b;cd;;7o;tg,;b;;K2';4;;;?^z;u;;nt;P;Z(};U"M;|;F;|ۯ;fjC;r;/G;vqR;D;V;';E;a5;6};Y\;s;[ ;XX#;! ;9;TH;^E;y;Q;;Zs;v,d; ;_7;[P;3;#y;H;/7;wG; ;7;`;_I;k;-;;k;VU;;4z;K&s;hi;OA;U{;~;/-;C;NF;#!;_;Y3;;Ū;i;\$;b,;S;;uU;9;B;u;;q;j3;KH;Q7;#<;Ma;^-;3;;bh;q;UU:\;Ol;^MQ;O;y;o[;'*n;aW;<;T;_ |;Js;S-$; ;M;S1;R;^4;=;;$-;n;t ;6C!;#;D`;+;vt;~;Z;Rݚ;h;C;jJ;L;I;6;4;*6;E;x(;5;F;K;g;J;h),;1 Q;m;UX;1V;&ў;<,I;1h ;^;;:%;Jh;J;4-;,!;#U;}̰;Od;u;`]N; ;N;\;a";m'B;VP; ;n;TP;D;&;&ZL;Z;+;d3;X;\u;*hl;ty#;K;(;z;lS;f;*Ǡ;T;SH;V;O;e;.;kZ ;e;;>;=;k;sW;@t;EF@;X!;T;R];L;;]{; 0;\J;*;Ck;@8;w;L4;;*c;p;;*;$;C;&);];I;=_; ;O 7;@ތ;|; I;eY;z";Ec;[;vU;O[;;.;9> ;ɰ;t<;F;;R;aF7;];}; ;`%H; {B;yb;*;rѾ;Db;;>Q!;c;:;B7A;&;>H;NY;Y ;/?@;x;E;o;IG;d4#;R;d:;m;d;`?;9;``;dN:) ;C;T;N;8|;f3;4F;d[-;cP;9$;DY;L~;G;/;];VM;;Q;r;?q;Z;m;G!;^$;;c;H~;=[; S;E;];6k;`;}#;f5;:e;gq6;=y;>b;7/;F Y;sj;Ve~;#G;x;i;Z;-z;9;]F;\q;JR;(A,;p^;G;};I;M<;0:.i;f;#:";+G;;rT;^ȉ;;W;Ke;4d;\;@U;oJ;1;q;M;Lf#;Fp;/;BXg;n8;);N;;i;8=;;i;w;Hu;s;J;u;2%;L;;92;I/s;!;D";N~;E;Z;g;bQ;2o;i6;; ;I(;u^;+;(v;r ;euJ;k; ;?a%;)=;v;"w;A;\:;R=;vc;r;A^;N{;?;e _;Ek;~>R;s;V;@U;r;4y;ϫ;-(;X;gh;k+E;cW ;C|>;";3;Jn;L;;d;g= ;6;;q];Zy;D\-;ve;;7;];u;;B>; ;&;,x;[;2(<;#A;91;;L(;CS;jI;4S;bOL;`-N;_G;c;3;T;S;c;N;1j;<;U;$;k;6Q;zA;}ǫ;}ڡ;,;<;K;?;N;R);&};mtH;uT;);Lm;ީ;;q3l;,1;;h>;V;f/;E;;;h;};n;@[l;F.;?;+;f:X;8;2v2;%Z;T|;e;?W;M;_T;};pH;Q;&M(;FW;;Wi;W;B ;B/;h;k;<;S;<;m;r;^$;eK;I3;5u;qAq;4;zb;yt;b;n ;~; p;:;K/-;_̶;=u;{;t;=;Y(;v;;b[;&;Y;,;jy;d;;c ;6o?;?;V,;k;Q';|;f;(Z;X;!;J;]g+;N ;U;8k;x\;@7 ;;`;v؈;<;0[;D;;$;Sl:.[;u?; ;;3; ;;ݾ;T"};R;bj;aC;VQ>>'?S8 >N>=k>* >=L;<7`<'<@<<<< ;|;;^;f;);;z;;_;l#; ;;0??i\@I׹@-ͩAp0?2?#G?'@txY:x?}!@K"q'?nk?Bۯ'@@Ra@>@f(@??A)DH@@g?0? [?v!? 0U?,J@7$@>!{@"QGRUP?@@@@@@@AAAP?@@@@@@@AA@BGMAG<ʆ=->E>>ݏ>O>?:P?U?F?G ?/?%4?>4w>#>><}>-?j? ???M??r?LMg?P0$?Zҏ?Kq?C^$?8V?4?4?,?)q?))?1 ?\+>r>???2?k"?/[?>?Dl?Nu?Y6?RH?>N\?/?+g?%,? J?z?Mj>>?M?L>x> ;>;>z?? ??w?? i? >>瑠>Tg>6>Ǵ(>>>>>y>;c>c>>>.>ק>>/A>\>>b?S??}? ? ? 8?ׄ?[? W?>=??>>ٔi>S}>ط>Ӟ>ȭ>R>;r>} >>r6>©>c>v>?N>e>>>j>l(>N;>Ka7>:&>8Q>(Q>!{>I>o> >>F=_=t==dz====s=N8==_=.=ě=ܑ==l=e=,J=z==JM===e=a=z=R==4M=={l===P==4= =w`=b=q==$=_=_=M=}=@=7=UY=*==K=NZ==z====2 =8=N==P=-==\=<\=t=t==͆==\p= =xt=H=w=,=x===s=J==5==ث=='=>=y===d=\G=Br== = =;=7=5=3N,=1h=/p+=,C=*='_=%`!="= ۺ=ت=(=0p=E=8,=<==+= G= =====,<-u<+i <)4 <'4 <#< ]<x<<6k<<v<<'< p< L<<<L<n<;$;S;/;;0;ޏ;p;l;Hn;׽ ;e;҉;5;S;];v;\;;;7;;-;;z;2;5D;7;;Z;;;&k;;;; u;;ծ;(;k;~y;x,;wD;r]X;iS;b;jr;d9c;Wy;X;X;T;Jo;c=kR=8a>!R2>\3>y|= >?0>?Á?>?w?I?.a?Iر?.U?,t? >e'??5?[(?N?h7-??t?`H=?re?{n??o?_?`?[?\ݦ?g?d b?e?i?N?JC?Z?W?J%?Lw?N?Kw?U?\?QG?Hg?6j?3z1?4UZ?,:`?,y?5?@6?;@?D/H?Fv?Ht?E?Au?D?C?K'?Iރ?Gþ?B?Bk?G_?O_?I?NkL?QԒ?O ?Q?I;?@6?8A?4Z?4+?8H?55?.?09b?%?[?{???L?%!?%G?"B?"'?em?K?<1??y???$E?U:?#?-???uN?d? ?B? ?>>aL?>>U>>>>|>ۉ>P>K>>B>u>ߤ> >>ԃ>6>>n>p>*>6>Z>c>%>>>%N>$>>L>}w>Q>F>[>v|>la>fC>\&>S>K>Cb>= >5>/@>'>!1>>*>>>~=K1=; =TT=ݯ= r=H=~o=I===[=Y=C=f=p=z=f=S!===c=q=|L=y=y/=vo=vف=v=u=t=rK=r(=p=o'=n=nJ=m=k=kj=ie=h-=g'=f=e=b=aU=^=\[=Y=Ww{=Us=Q\F=N =I=E=A˻==R=9ڔ=4v=/|=*h=&=!HQ==f=>=s= C=&=L<^|>b>֋?T?7b?Y4??vQ?P?;U?Dɫ?F?2? ? h>盱>/>>ׯ>!c??1??o7?&`p?)J?'Z?$Q?!W?"|? ???v??[c>d>b]>. ?>>[>R>ho>g>Z >ߴ>F>>>>xb>~}> >tU>yX>7>>>׀>ng>>>ð >>#%>> 1>>i>T>>A,>n>K>?>b>>>?>W.>u>es>O>>>Ku> >|>>>>G> >>)G>O>><>H>>>.>S5>>>a>F>%>>'>>Q>|>H>\>>>E>Q>>z>z>2>5>}>d>z>>E>>>J>u>y6>Q>M|>'.3>#> =>6S=h>?=*=V=x===}=7==,=$n=I=3=J=&A=L =^==-==5==,=!={ =f|=d=D]=J=*=5<=!K=(p=)Q=+0=5c=81r=:=G?_=C=C)=F|=>q=7t=1u='_= ==T= =W<.F<ܚ}<<ʨ<:R<ٔ<j<ۉN:'&:yJ:::K:.:L:y:UU:DC:(݌:%2:6{:`q: :s:/:x:ܯp:~7:~::ƛ:ر|:::٣:_:":_?::::]:|S:QB:^:|::::'[:;r;h;;: :A:}k:ҽ:3::Z:s:e:nO:v:$:%;; MR;;u;~,;2;'; _;::F :,::A: :4:!:o:+C:ϣ:ଁ:{Q:c;;w7; ; ; /;a:#:ߑj:ON:ʹ::: :&:h:::6y:6:϶:s:Q1;~Y<=J>g > h>;>>>>;?-K?N??u(?5r? ? $??,ݴ?"=??H??6>{>>d>X>>>a>>t>٧>j>?>>:>)>>̺>ZO>>3>L>>> >>>>H_>й>>>h]>G>>ˮ>N>oK>>,>>O>4>}>y1>ws>c>\O>joH>fM>T. >E>5O>.>;k=E=>=.>>I>>Y =dw=ݻO>V>-=><>4>6K>B>Ex>N<>MB>O >W5>`>` >UD>T>b9>h>sZ>n->ql>g>dNU>Y2>SQ">K#!>I8>Gw>I)>K:>J>K>L[>G>DZe>F>F>P[>S->U3<>a*N>bD>V>L>A >7̿>'> i>>'>;W>(>S>\Y>n$>(>#X>=>'>>>0>C>u>i>u>>$>%>vx>u>iN>_w>ZE>SĊ>HD]>=>8g>,>'>)2>!> \>d> >t='=۽=݉=t==k==s==f#==qU=]ʍ=U=1X=5=%ڠ=(=tt<A9O9wA9;"9g9 :2T::::0:^:@:[u4::$:h:"w:Z4::::ƭ:_;;;,;*; p;;G;;;0G;80;;%;:;-;3;<:a;=;<;L;9;E|;@=m;;;?6u;>h;M;QK;O-4;@ج;Q ;QK;OX;S ;G:;=;@+;E<;Bz;Dy;,};,<;+;*U;'MP;,;_d; /;];; 8:匶:dh::h::l:ģ:y:o:M::3:`:^:^:P:;:8NG:A:A-:JM,:3y3:#w:I:` :M!:d-:]:Vֽ:pk:}k::9r:|x:~:|:q:^^:,::O::V#:v:b::*h::q:9:X:A:0<ƛ===l>W?9X??\?gG> ^>P==̮=ަ<(=-#=X>h]>m>w>Zٞ>bv>d+>]>[g>v>W>u#_>-2>J>j>#>>2>>)>)>>q>ߓ0>|>n>O>ğ> >->>>>G>|F>p>y[>n>n">UM><5>3>?>$==T=>>&>#<\>>3MY>*?>A:u>A>H >(">>B>> [>)T>7->>9%>9(>;F>9t>0^>>8><>9n>'ι>.>!>>Q0===d== =f=^==v>> >"dy>$>'>Γ>D>>%R>*%>7>1>2.>:N>J4>\>Y5a>xf>}>>>>->>+>>4>>>>S>+{>7> >ِ>y(>^>K5>Z>qԉ>o>Mhr>.>>"_>:>=}7==fj==q==rx=7=:=.=sչ=U=_@=s =e=R=G,.=I$==p=*=+,=<¼<t;W$;k;A_$;;i|;U;t;;g;S;q;_;;D ;;;<ا:B:O;:r:> :);+L:G:Ș;$0;"b;`u;';3;><;=;X;K0;`;fH;k;F=C;Eh;lQ7;I;m;2;!;.;); ;;2;Pd);L!;, 0;5;Pr;NR;DW;A|;n;=;;b;;!;;;;;m;R?;~;f;s;{;k4;Q;;B;iN;k;;3;;};;7;b;c;+D;K;I;4;';w;"3;y;;;;X;0;o;ݨ;pI;kN;;h;(;-;%;4;;;, ;;W; ;};;d;;e|;l,;s;p;iz;f;lG;aUq;N;Yt;M;^S;^ E;AQ;AT;F;Aݢ;6fL;:hC;,5;+;#;;'O;E;[;; ;;mv;^;::H:rk:: ::c::::R:R:,a:i6:pN:<:B :<:*:919K^9ۿD99F9;*9]9 Jd8?9'9l9f99k:,g: :t:=: :m::ч:f":_[:fts:Pmv:jo]:D:h:_:: :\/:::? :e:::::,::l:I:::::V::ŠT::ɪ::˶N:}C:Ӝ:% :k_::&:2-<-=>&b?S?#?/(?J?I H?/`^?????rz?<>MV>ߨQ? H?Q?-f?6Ќ?8?8??|?T L?aaN?c?r?yD?8>?4?5?,~?&?"$7?!j?U?? ?!?'?*?+0?2?3z?4v?.0V?)F?%?!-9?u??L?>?$??"? ?5?;???I^?N7? ? ???D ? "? d? R[?2?>>fs>敯>> >FA>%>>>1$>~><>z>/;>癏>I>>>b>b>*>p1>*>7u>̈>>>>~>U>*>>S]o>`R>Q>9>'!>"> "==S==6=|!$=T=8(= ;;S;;*;{ ;;z;ͨ;j;JH;獯;/;];3; ;H;y6;ݫ;_;y3;Ů;;L;$A;w;S;+5;;;J4;^;;;;^;;gT;;;J;;J;;v;oS; ;DQ;w;h;;;;,w;d;;@|;r~;A[;;{;ug;t;r;;vot;{;or;bK;\xo;Q;Sk;KP;V.;W;LY;H!;>lT;A;HO;A2;D;K9;=;w;=P;81~;>I;3*;35;6Q;8ʆ;=$;72;1?;2;+;/D;(%e;6ڲ;7/;4;2n;$;;;';!9-;#{;; ];'4;8;k; `;-;L:s; i;:U:::B~:O:u::G:r::]:c:[`:=:S^:F::t:X:::B:#::A::':k:a:#:B :+/:<+:::p:p: n:{::v\:::8:Ʉ\:::'t:/:ȠJ::›::v:ɼ::1:P&::\::+b:x::L?n?,&?xX?:?T=?91>/q>?$?Q?->3?0/?Gg+?]??~?hcv?T*?\?- ?'?a?1??=>>t> @? R?y?5?7?#?+x_?&?6ێ?^?@G?4R?S$?(f?8j?r?(w?$)?3.?+3W?!p?%?ei?5s? w?4e|?(e?3.?u)?)s?1?"%?7?"?x??B>Z>ז> >>>>>M>>>u>3>9>+3>n>B->>k6>v5>>>@>V>4>Ia>!>HW>_>G>,>>r>>>i>B>g>|>>1>:>>|>:e>>w!>i6>s1=>WM>>p>H>>F>YR>6k>y>[>FM>FA><6s>=f&>Qm>;>b>GL>l>Ac>>>=XR=ȅ> ->h+="Q> >)Y>2>hj> ze>ǧ>)t=(v=r>>B==L;==]X=JI=> =h=gv=K=ds==R= ==G==A3=o=}===@[=wk=v =x+=f=KK=6R=3=7U=2y=@==_=g== => =l=<#<=G<$<<O< K<<< < Z<er<<:<W<_<5;;<3;9j;;O;#;)G;;KV;p";g;_;; ;;;};,;9;!;#;ϫ;^;,;u;;;/;8;=;5 ;O;q;U\;#; ;;M;z;5;{;lH;;|ZF;vlD;p M;s ;V4S;bJ;h*;E;^#;W;Cn;C ;a;N^;@QF;F;1vd;2;P>;EqJ;$I=;);";+{i;`; ; ";U;!S:;;˸;l;g/;q;:~:2:6;N;C(::: :~:O;0;::':ǀ7::Иn: ::E&:e:S:T::ꎘ:ͰK::S:::[:ش^::Ѯ::_:D:e:G::R: :::O::L:wm:r:n:::-W::=:}:@:@:::s:P:\:3:a;=!>K>>A?3??->>k>R>g?\,>>>>->>>ݖ>>>ਙ>T<>">;>ܭ>ѧ>>+z>=>PF>:>YQ>Т>[b>l>#>Z>e>1>O>I>>t>M>+>>[>jw> >t<>>|>`>4>y7>$> >m>^>>o>Z>E>+Z|>zN> u1=Ш=ޫ=(T= D=P<=={O =_,=<=<= = <P<^;+; ;2:4;O;~:;:;; S; $;!:ѡ; :;b:;;U;.P;:Q;|:i;o; a;<;+':; X:m:.F;~:;@:̛:W:҅I:F; ::ԕ:?1:L:n:P:4:s::::7X:: :k::l%::8y: ::h#::z::O:{S::A:p:o:br:k:Z _:6:pu:[: :om:q^:Rj:q$:zj:@A:RW!:Ij0:- :8E9ߜ:=R:5)9z:Ft9[:9999:099:09:9k6b9Y:9?9GY9:G9@9c` 99y9d 9кh9z9FYw9{ 9R9@e9+968N9d99K99?q909997D8׸M98f9+'99D8[9]p9999j8S9ƨ8M8J96S8^9Q9 8SC89[9^u@9A8%E988!9858!8].Z9+U989Ӳ9S?88)9$:899/@9W9'?99I A89{m!89sձ9ri8jm9.i9+rA8W_899 9~j9=PC>~>>?Ҽ? c*?1>Ā>?">ց?>4?+>Q>?P>l?>A?>]9>Ȑ>ԆD>{T?4h>ڙ?#'>>/>'>y?ŋ?V>5>?.>J?!>z?>j>ǻ?s>?!>5?z>5>^>j)>\?->^5>'>%>F>`?|G>0>ʲa>_>K>޴>L> >b>>>u >>>>x>d>5>h>Y[>j>h>]>2X>>2>PY?>=>KEG>>j >>>\>>>x>I>>G>K=>q>4n>E>I>}>"b>{>OA>cYk>Hu>+|>`>>H>]>l>>=>=b>>GB>>NdB> ;>0>>G>l>->T=> k=с\>?=M#=۱=u=m=(=@p==@&=g8=\=v=F+G==7Z= =!*==\=X m=}=A==P=8YH=!؃= 3=.<Ԯw::-:D:w:$9n:B:+C:,9ӻ:w:|A:0L:hY9᥍:jN:d:X:`: ~q::|V:/:]:;:hj::iiW:S-:Y:'Ё:WY:E:y::!::2::1o{:_8:(:p-:6u:o:c&:^:<:RdP:n:I:::l:.nQ::vc:sY[:[O:/:w:h!:2hY9:b:h::@q:g[:X: V,: 7:8::WyH9nb:J::M:::%S:::f:?:l:2P}:1:{m:]::.-A9C~9j:P:3:(i:J9:D9_9P:C9:<%9ꇿ:w39:c/9L: {: :9\:a: y09(:4U: 9..:S :9+93:-B:!: %9{09ݽ[9̲:L%:n9ق:YM9O9G99O:)݄9ԣ999 :9:r9J:9Q>99r::9:9^09݆:39: ^:9*M:B:P:%:Y9999 969럄:5:E: F:ì99 !:9D:Ս9Y59n94:9g:vG.:H:<S9::VSC9>9j99Z:J[:$}9>J>r9>e>s?? r?C?#?6?;?MZ??tM?:B?.?a?O?N?a-?#?  ?[??f{?Y?9~[?vH?~I?I ?:i?N1?nY?Nh?P?m?O:?MY?3b?I?)@?P2??=>>u>Hu>>ډ.>m>M>k>>1>>Ҙ>>W>A>8y>w>>;u>>,>> >;#>}n>C)>>>OI>\>cg>>r>>MN{>h¶>H>">>n>*?>n7>#>`O=>(>gy>,>%M=>>>X>>e= =׭>>1->p==٤> %==0x=a=tj=dz=si=iD=K="==W===['|=fK===4K=>=' = ==J<=#=Ŷ=So=I|m=iK5=w=<{==\=7=0H=A;=(=[=<Հh<Ϸ<\<>f;h X;;[`P;1;<;8;H;MN;0*;D;;su:2::;):E$:":Wo:{;խ:n;w; `:F;:тM:ِ:=::͡3::P:(::p:eW:@W::k::F::N::S::^:ͱ::`:B::]:::M::ƺ:::~::3:q:e:::::A1: :|::ow:t::AO::O:qx:z7:׷:4:L:)m:U:d :s:8:":3::y :|3::u:E:,:W|:m'O::tk: :tɭ::`,:e:T:`r::aX:G::t?:oC:c:iv0:(:ZL:5_::z:.::j:[C:'1:is:0:%:|:j:t:: :$:s}:qM:!W:F::aU:jR:~S: !:<:B: *:::mj::_Dx:Y :hM :+:]:T:Qmg:~O::us1:{::r:mb:^X:e:Z::z]*:1:w#:<:':~F::io:`\:f:w:k;:1:].t:]P:{T:E:Sn:Xp:s::_yv:n:k>:]:j,:|:^:{B:y:Ii:z:{q:::M:|<:@:H:}9:`:x:v5:V:op:jS:\:4:K7:vY:u!n:m:q^: :fS:p@c:k%:׊:o*:::b:o=<:l:wܗ::M:[#:u@:q:^F:tē:o-:l,c:v:q>|:qm:C:K:[\::<[:gv::^G:kr:^d:K::e{a:d:x:h:nyquist-3.05/lib/piano/pn12.cod0000644000175000000620000004231010144436365015314 0ustar stevestaffSYNCCNDNCOMMC: H PART2????????{N >C6?? >'R?.e^>6?_? >>S===)<;=j=d)p<*=<= s@zXdˆ@f?yB@6@?@b @W}@5@\@u>>@>Q=L"@u؂@~@?iD>Cߡ@ @%@GRUP?@@@@@@@AA A0A`?@@@@@@@AA APBHGMAG>t>|?U(?Sz?n?0f?>?k??V>=>Dz?Gr?_?/aE?(? ?9Zf?Obg?N?N]?U_?9?? O? Z? Rm?e? y>>Bo>:R>l9>!B>?>8.>Y>>Y>>Q8&>> >>QE>PzU>/u>> w>JL >}5 >.p>[> hG=M>><*>C=> % >-@>>&+>:>-ao> Us==G!=s> t>6s>*>9$>N>vS>Ⱦ>u>AT>!l>4=6=.>>4m>Gc>@C>F*>>>/ >"6J>>T=,>>J[>E̶>@>9h>>$E3>$g>#V7>$$>H>>>> e> >_=3=1==!=vr>%ZK>NO>>v>ȿs>I?%?$k? UF?=y?g?gw?j.x?y ??{V?m^?m?u?in:?f?b!?Q?KM?PU?U?Q?L?OyK?H:a?F?K?N3l?M?a?J$?J?GE?;?65P?<7?8R?)Y?*?+h?$?9=?"{??#?nl?aR?x?Z?i?"???? Lj? ?t!?G?q?l+>V>M<>>H{>g>>L>$>=t>>:Y>|p>?>6>>h>>>_>w(>Z>m>>> ><>A>v>>H>>ą>>ׯ> >߫N>>۩K>k>٠>WP>:>>>N>y">ɂ>>3`>&#>>>>Y>h>Ï>{>>!A>_>>>10>>F>L3>>R5>p>_>x>a>Ȋ>:>>>@>pM>`Mn>Qv#>CS>4F>&> > >M==?=~='=j}=/=m=O=4if= =:{x:":x::.:C_: :::+::W;);;;O;,;;y; ;"[;%*;-`;/;5;;?;C;I;NO;Wt;^h;d;m=;tAN;z x;;;;j;L;Uz;;nP;H@;;f;;g);e<;ɐ;<;Ă;;?;a;9;;;@;;;;;;:;#;;;;;;Z;;\B;v;|;zj;{K;qȞ;rf;oI;i;d5;_r;[;]K;Vy;Re;P%;M;K*;Hy;GP;GDY;E8r;C;?`;Cn;C1;A;>.;@Ӎ;Ad;>;@S#;A;>8;@(;>)H;=;?;@*;?;@0;@;D;D8;DV;Dt;J6;I;J;N4;M&;RTs;XD>;W;^pe;`{>Iu>`>?G?/?5I?'"?&)?: ?Z?l9?yE?}??yw?jT?gE?ll?ka?_A?VUx?>?A*Y?C^?D?A?> ?;??8}?5D?3?0?/ ?.,:?,?,>~A>J >m>>y>!>>->#>G>>">K{>>c<>|>>>>>~>w/>o>g >_pC>W >P>H>@t>8>2 >+?B>$!>[>T >_> ^>.>c#=9=====ӄ==A=6=$=-=ʭ=pM====D=k=3$=P'= =w =p%6=g=a\m=[#=WQ =R&=N?=JY=Gu=E@=D=Cߓ=C=C@<=Ci=C׎=E<=F =Hf=JU=L=N=Q=Te5=W%=Z\=]=`J=c*Y=e=g=ir=lB=n=oP=q9=r>=sm=t{=u-=u=vG=v=v=v=w`i=wW=w=w=xV-=xp=x=y"7=yh=y=x=xby=w=w=vl=u\/=t5g=r=q=p <=n~k=l*=j==i^=g=ei=ce=a"=_=^+=\H=Z&=X=V=U=S=R=PCy=NP=MO?=KH=I:=H!=FY=DWr=B=@=>T=<Ѣ=:=8=7=4=2{c=0v=.=,=*=(m=&=$}=#4=!== =M5= ==W==#=pl=== = uP= q= _==` ==d==3D>ҙ?6?>*>a ?m?9?=?Q?R?ap?q1%?j?_ ?SL?O-?e?n?h8?j)Z?x0.??~?x3 ?s*?k?s?{?v?o3d?fU?e7E?d?f?e%?a?] ?\cn?Z?[g?TU,?PD*?N&?MKU?DԒ?:(q?50?4t?3J?0!*?)?'/?#@?)?-5?0p?*v?&?%w?)o?&&?%=???rx?!]?Q?IE?Ӭ?y?!?m?5+?1?\?O???z??p`?D?? w? ???a?l?X??d?Me?e_??? <? ? B? 0?i?? T? p? a? ? i? ? ? ],? ? (7? N? ?8?0?? O?h??;i? 1?S? ? $?F?.??? ? L??^??K?? >E>Z>>>>>:><>f>+>t>>b\>U>9v>,>!->>> ==ىz=ς=R===v=Y=SzQ=#= =?<< < *<&<w<('%<<&w<<'U<)#<J<3<<(<< 9<be<y<I<XM<O< Ȕ<\<;<c);he<_<< Ƈ<<>;T:;;;ǔ;e;ʿK;ߖ;fH;r <E<&; ;b;߼;נ;;-;!;;%;+;Զ;K;j2;Ŋ;;[;;;;;!r;ն;g+;; ;I;p;i;JC;^V;;N;B;-;#;>;M;;̈́5;;;;M;;0;;ڛ;۽3;߃;; );С$;;uo;;;AL;;6L;ji;Su;;Pc;^-;#;; ;o ;b;;;;q8;;~;;;;<;/;u;; R;Vm;v;;;;;G;>;fT;Z;;6;7; ;v5;k;gH;\6;iJ;k;|5D;yHk;k=q=`b[=y>+> ?n ?%??">!>? )#?,ӫ?N&?\.?m%?v?q?w???y,?q?s?t@?kT?d#q?_?X?]X=?]խ?Yf?T?Tȅ?R?L]?CB?=Tl?>?;؋?:??>C?>k?=nj?=a?;?2p?/?1Z?/M?,?+?)9o?%1?!Q?4?w??Ob>@>#J>0 >a>('>>,>>>т'>@ >Ҫ>\>2>˱>ls>Ö>T>>>A{>ke> >>e>q>a@>+!>q>>M>>>>"0>>s>>>l4>>,>~$&>zߋ>|'>}dv>wW >nU>n >lw >gBS>l>n>d>c>`Fn>\>X>]>Nw9>Gy>Cق>?>2>6r>+j>>]>Mj>Z>;B>;=l=R=$=:=e=Z == < <<[K<3<0<+<)]<(<<<b<<NA<6<=< <$<<:;.<;0;Q;Z;v; ;*;٨;r[;҈;ԅ$;=;;;d;;0;6;;;z;;;;;`;};>;; ;%;;);;3;j;5;`;;T;;;;;I;Ŭ;~;s>;N;R;-1;/;;vr;B;;t;^;6;;Z;x;;+<;f$;j;K;e;ɴ;;t;;\;b;C;; m;; ;;};&Y; ;;;;U;š;7;;,;;;=b;ek;#;b;HH;;;G;5 ;;P;Ē;y ;};Kv>:>CC>~?"?O ?"??x=?g?L ?>>w>¯>>>E>b>2>>5s>K>>B>>︶>>>>D> >>Y>ߒ>1>ט>Ҏ>j>>1>Ci>=>]>zH>F>>_>S>>>> >>Kt>t>;>CE>>HX>>7>h>@>X>&>>t >K>& R>9q>}=={E=KE=p=W==jO=Ze=Ch=&_=U=%=$T=.="q==H=$@=#` =2==%=>=;==J=D=IX=D=@O=A== 2=*M=$B =*5$=!.=4=&}==$=z*=|===+;=ވ=p{=)= .=t= ݉= <^=h=J<ܝ<<]b<̽XP>ow?R?A?8?'"?6IZ?Kps?M?IqG?D8I?Op?ky?{?z?yq??| ?lq?l{?o?v5^?gb?^-l?O?Wu?R ?U*?T?XI?T?T]?N?J?E?HE?H *?EBY?E?;??_?9\?;?7^???9????8?B?>?A]?;?<?5?5?17?1Q?/F?-T?+z?(?)?&G`?'*?#6?$͡?"R?$[ ? ?!??"q?#???_?eV?*?8?u??a?P??$? ?U? ? h%? ? ? p? |??s?[?>?*#> i?)B>W??G???4>>y>$>-^>>a'>n>>>㲪>`> >n>U>x>>)>r>>>92>kf>z>۾3>T>׸>.>>>q{>m%>ʐJ>>>'>S> M>6>y΃>m >Wd>M>: B>,>>> >==jG=ޗo=W=ͫ=ˑ=y=i==9=ŔU=,=UU=S=6j=R`===`=0<=` =uB=l=?==N==;f=#=3={=:w=d=o={B=g=|=u=q?Y=j=\d=[Q=U(=Ku=Dş=8=7<=.yP=&qE=#=== ==<%>&>v->#>??(r?9?#/?(}Y?F)?<2?M@?X$?mb??{?p(|?d?c?Vw?g\4?[?b^6?PZ?Y?M]?Z,?R?V ?LY?[ ?X?K]?S?J`?QC?AW?I8?;;?B\?4e?5DZ?+8?.?$8_? N??!? ^;?+? ~?O?? p?F?I?*?|? ?=?e>>$>>E>/>2>@v>z>O>>>{>>մ6>]'>$>T>>~u>Xr>$>> ><1>H>r7>Ž>>>_>Y^>>>X?>U>+R>;>@>P>j>*>>>y>^>x>C>v>>lg>kǣ>b>c6>bY>VF>]>F >dd>Cā>V>/>Hԃ>0;>U>:^>I><>DyA>B}w>=xO>?w>+T,>BZ>'>>>&>>=2>r>i=d>ؠ>>5>&> > >;>|> <> >>o=Yb=E=.==WU==̠=\=2=L====qߴ=WAZ=US===$==<6<֫]I?)?W?Uq? ?o ?Ma?K?_i?MS?/'?V?! ?8@?e?jl??J$?H^p?4?9?J'?[R?h?H?;?N?-(?10?I?D1&?@?1 ?$2?,ј?"Y?H,?<>`>->d?+>`?u>>x{>XX>>l>h>ԡ>v@>>4>n>>Ј>>>> >W>Z>>e>B>_>E>F>k>s>|W> >Qn>Z">>E/>%ap>Y$>3&>U_->>P> =с>40 =ۿ>(=Ƨ3===U=Ǔ=+>='==s=n=y=v=&=]=؀=d=A<͜M=j=X>H>>, >#,>1>55>-N>6>"W>$S>>«>=5==ѠF=4===V=wI=EYC=*=N<̨=B\<6;L;";y;[;b;);E\;4`;}\;H;?;F:_Q;L:*::ʮ:/&;:8#;+;2|; ;Q;G:9;m:1::(:9S9-:`#:0::H2:;p;&;MJ;.;#;Z6;NX;R|;T;);a&;=:\@; 0:W:|m;::v:3: X:[~:H:C:D;};;&c;E/;;AΦ;>;R;E:ϫ;-s; U; ; :ޞ:::X:s::O:Q:x:::Bl:,::x:K: ;:9:u:`<:=:{/::m":ZQ:!d::'>,:: m9@B9::k:;0:a,:PG:U:0w:ɶ:H*:k:-:M,::=::bP:g:w: z9ݲ9A:C(9,99q9eKu9A:?H9~9l:a̰:D8$:D8˔9-99So: :1o9ќ94E9S:ͯ90:*8/9/^98 9|8a9??8oFE:r9DW8ҍ;9ܛ9: 9P8̸9D:W9(:Eb>'?Au? 5?j >?<E?^ ?R>*?-?|ڞ>?0?4?[/?"?Q?? ?/?c?qC>œ?+a?yO>t?Műc?/v?b?P>㍛?2?->?R?6,? ^>c.? ?;(>1>š?Lk>>j?l_? u?Q>?)>*)>y???sJ>ʻ? .>?Q>?0>>?^L>i?`>l>>#>>$(>O>3x>>W>>o>sP>mK>װ>>u>f>a>B>>>>I|>g>S>D>>>>?>F>>>n4>>>h>٩>0j>>a2>b7>~>>*c> N>F;>Y >>O>p>X>P>[>a>yڛ>h.>d9>>>B>fa>R>n>_]>Rv>.>9d,=ކ)> =S>==ï=zn==U =W߃==j-=a=x=R==/i==C==2>=(=vb ==y2@=y==/ `:-;N>; u;=Y;&I:ĩD; ;h:U;̍:: :wM;w::q:*::4c:~,:!:Y:,4:Ŀ:ȗ:b&:ˠ:y[:X:N::CS::y:9:E`:!Å:pl9w:e:nW::^9ށ : T:9I:%::;:Rw::Ke:w:5:[gt::=N::I:^:":J:":%dw:I:G:Y;:'9:J:[:d:^:%:: :vÊ:8>:/:h":Um:ip:M^:_~:e:0:5b9ֳ:( :B:W%:.:if:Iz: 9:r:.:"8t:f:N:Mu:99:UB:$؇: :k9śe9 :: r:QJ:9b:?r:YF:A):: .: ::30:.@:^=+9A9[p9:YN?Jr??fW?kA?m$??l?o?f/p?[Sp?aI|?j ?>>>b-? \0?? ?U?M>W??87>h>न>5>>7?>v>>z>˛>>9>G>ˋ>>9>zA>:*>4>/X> @>j>>>>2>>Y>E>T>$>!=>8>Vk>u<>sG`> Z>mm>H>y>Y4>a:>i>vk>tD>uT\>q>l>np>x&>v>lM>X͆>K=>NX>TŒ>fm>qZ>h >j`>_'>b`>b;>^>\;>P>S#>M>S>`>j>Y`>Vl>H>NT>H>RU>N>;?K>8m>0Ҳ>7U>;e>= =m==A=z==VdP=Ofd==)=)ȡ=1=U=(=<;;{);#k;C;n0: ;!:8v::ݩ{:p:[::[::c::#:00:Y::N:~:Ha; |:0:bS:`|:F.:6::mM:o::ιo::̞:8:ÖS: :u:::I::f:Ĕ:\Z::$ ::h:::-W::T:Z:Ք::lY:9`:-:ټX:Ê::^:c:E:::Ļ:S:::T:$:m:!:iF:pM:,:e:S:J::P!:r:::%9:::::/:FV::t8:R::A:M:D::V:zz:o::^x:2:93:Lc::͝Y: :zc::,&:Y:&:ʚ1:,:]:H:l:b:U:#:Q:e:IU:_:::]:t):F:N: :?3: ::5:)l:$=:خ5:DJ:O :*:Ƒ:x:|:"X:::T::I:U:džT:>::I:х:ƱN:`3:H9:Z:nyquist-3.05/lib/piano/att48000.pcm0000644000175000000620000013014410144436365015735 0ustar stevestaff %&|dZk $V}@97<xL~b_l{?i}uF3 JLTiGus$t/RO 70 M}bx0D-*T-}@tRavtn-OM77 O)=V$s|sB*;e`< h\ Z^"D 40Zm:s8 ZWoF3#ugRi}r+>R$} X5THaJMUU4\|r2k84 $Y, "eN|vM PIym*a~X4o#Dzdy  , E%akBQ5t`0P a^B\jgXE8310//9g[0+1'Qj6Y!HO6U2rxc>b`[Oo sQN^y` 5h-nPNDh&?1Jwf&whvvpCa,b:n_GKYMN8 % B |  6 C N b V  #  R I :QdEGgGGoueWdf o%vp?e/u]Ob hF JS +>W$NBlvê)dM1;$zc]k4QQ`6,τ%/!{)35=@:<91` z dǫGO dd~jڶ&˹Ŋ3`C&L%M!E7% V@Eջ8/$=E&<&҈Rٜ54L_kpoh^/QC7,,&%*e3s>J>RtULQG97$k5 YڈLR44H~UZ[UTG4<3J$ǽ˒Ӥt xV( sߖU#$N XW 'ٯͼ8ˎG+6#=(s&P$DZW  'O)%nS[_lGgض29}?'+)"2Ϝ֮PR $N&&#>= 0cC 3d&X-2m441,K# ݂R}+  M _[^J[aۙiվ`WRY7k bӻξ[ q Ɋϴ% # Y'1o;EdNW ^ehijig+_UMI(==3+&#^!O #O&)*_(" Gy,quXIaـ$ѵJ;̺3ʳʺ˔i)Ӊ(ڱuY߂|ئF|$RPsY o JNbH,zG $(D*+"*%(%$9#$&) *++R)'&\&C'+/ 25-542.K)$}^cbݽ̳R=ÑBž E7 ԹX PL9Tp6xRAu9u>kc~;a:Ttٙi ?k-KT "[(f-146q6`42.L)%S  _OPb~7?ؾ 9+KFQX- ;,+!-&*,-G,++Q+l,3->--}+(a$O 0=3] s ]6 I")""D!| }3 IK2ro//V  y  qO 4!߽ެWE@l8$}2BIGuvV7jŻ̕z̨ɇɖh֯ݶ{6 1M u  n q dF g  >  FP ^e&!%') )f)(()]*,G-.-,+B)C&# dxP;e wWE*zIf8w>AL K)I% ?+* TY`[rؠҦ+Ma_pշݑ-6:I 1E\,g  &cYC#Sp/U+G  Wi_& r!zhhGMp 4ZkKQ nY;:jIW/ \ l  ] S  :  \ p R k o ] ` YU~T-znLv.J(n!a&f=>ulYzG (SEFf0~ ur~n~0/u,O*^f?zK8%XN]hp`{& S 1. Ua>m/G5'  :Hw2"7D<?SN*Hk 8a(rx L9 >-ZATb"`R':JdU|CdޣFdV>2xOB% F u   u  0 p q6`T  vn/&$1w 4PTBQ!d"#$$e$T##" '$( j {{upqٱب֍F\8{B8O1E #y\Bsv,orPM ?x^&e/E# J% e eN67KbP|t<7 .O4gF* 8eV ( ' ) b1d>  4 A k X U X 4 H   vg4,~V O e - V { z2 | ? "" <"TF],Zj>5'd^(]ނ|D Q=$XQ`0WZs<@T3F)|g(] DM n o x=8K*2NAbv X E$uw6PM7!R9;JoS[~/0^+1N  [I%+wNM`0- ;K!k )  #  K 08I}E(k 8(7p"8V/L K " yc%^U;Sbznj9]xwX`(%:LvS7nNAdDf  A B - L  qBG-PDL U hC[)D'#= bm}@C1GDU\VK<& !X[Aut4TH3iUH^TDt-k36X+!'`g;P'$r7$M=6uGE&9'M!8p)t ^ n k )<Z 4 Mp:w-9c~BqIB;}q?aK;)A$g0l?d t&1l9xTt%G~ #SIaU5./{ `t\7Q]8fTIGn - e R5*#rOr RXU 3 !%=z? 7j W>s<^+*LGb ^\U3g|h&9]2V2|&]4xH@eIVg1   yy3D `   " y \ 1 H v P &_w6`.U8#cY ;4vm@|URFz.aVbs]MnNa~:,aq=q]al 2d_:.hkA~qTZyr6O4()/MxT~b q/_9xE{'@);[~`j*0e%xpA8+z = G$7@9'kP_d@`[i/{f]*8lo(hr&9|CYQ2of *  y ) yg 9>EogJnCNo-c N .-Uw\2RE2z-8v2.N21/#_x":H*:P=MxRgMW k0OM U GhK' ` G $ X( J <5=L[ylqj |,=r\f7&H.=&! c*A^ysz>A h !  G % / C  @ l   k  6 w0MP2 h @ s~n)%}YQc+S<6]fo0>L VN7l_abWC-*CrL= MU x h U,  M  u A   Ee:!}o(c)P<fDp~nx2&(( dyeEJg9+eI?&^O'esY. =v#z"8kyV5/[/_u%{+;Iwl1 ('XGfug4M (B^SH)[w="Y R3dCyNxT==HM> Pcx#`.+:It biC:[dD4XHoUSS}do 0V4: >[^L2 /KdjY,B&SQq&pv%f+i oB,8#fDL#S'>PoJ+Y5=,L UF=&lH{;> 4-=0JE-V`8JHKbCdCk,|tZ   ? o +  i n  p ( A  xhgIc"IhjZWk-)|mJ}dJ ,LutP \=8H#_]E\h\: 7 G 7 % # < \ o i Z W | P " ! * gtIqIJ&R86j3oK|Aef6C(HP 3H\T#kVDRee<}f_iosym#uQB0 o V v 1H$+;B5BlE ,.]UqhuWgCZRI]ri9y3H75-?P=[Nv{eBP?(, &|#]c08wp9\HkLkXMKOXhv\'?;Ey@p=]?/dMxC+W64MeiPP PSa $au xElVc MoENB tQ`),&j(Lvx!n'vv;g-V[,L38HK$Il ?QJ26P``[QHM^v 7oX@T!K};!` c|h?8"OQ'!0Gv;08 _S$/3|`SYjz}e/_<$O%vI \/g>/wrbnGF$d$3PyJ /"0_f8KlHU+ 2hHo+?2%.8Q,u7p1=Q w? gK<:?IQZ]Z[i9vje2/b%xG+qy(>6IfL"$]O nJT_OC`H0tq? oH0%$bsQ9,('05ARo}cUXgyIk{~vny:>*Woc`baen{a+ku==^>  bB;;6EH;cw<71X!o2~jN~g3B6c6)w8@JA-   AmO&a|e3oer_WL3\1}Md68Z_8")ORo~[W+zqQLh"?8VK?bz+& K#'Q0U[TXz5?8(y@LLJGC5#T|EywyrY+H!) g y> uu8dy<"Y \4TT@(0[Z";{tn=& I?^W4 E)4Q<0F?:ZM*3Z +Q6Jr{hH.';d`3nVw; 7ZzjC}gXKB>8." %]w$L!;<E!bC3jjkQB# wbp&SbQ.YS u)TJp2o^UOG;'PqP"3fXh#Ol{tk[DZa++jD0 eJO Z=emU!>Zg#z\JFJONJA@S| uljpoaM-wBn(,DRABnH:D\N#-<7NA T9YoCZ7]a8{](q[b1Pals|xV;$HxU  c)klk; Z 9oVmB:R &Fc{oD Z9:Pz+P-'km" '3CS\ebP8{jN/?l)U&uu)g=|S%{g[]j7.@B<65:Sy(`5f  5IP@ [*%8DSet`N=1,,:J\mzg"zl\B]zv=byIjoR'j_rG=qQJ{&]|cPCFYo8hT$I")$cB.! _) &6IY`X@z_A W, /pEpitqYB"P):JMC8&)LczJ)^ DVM*Yw!ZtpT+@hH?}&v: .Lcf[B"!0?GE-cuQ@@DED?>CUj|lF %S(wjb"4Gc6Yp} !0`;{Emu?b:nL1$!')&'D]nseM/xR+{f[Zj;KAUrur}mctku1dtO'  +1015AWinfPAN}A#dNZUjKBMlq'~ Y@~&GZ\J&Tb%DQL<Gumi~Ey^.fWf'"bE;Gf5AL:Xu\hlTF<58B]q$IxTGRw/ba@4czxdE,wXILSZQ7+Rrymc`dq|,xhedR3+gn%}@ *5@`*/. |vprw'AS[T?Y @b|)HdrjS55[|y~dH7+').79<EPbuc?  2CUcknjibVE, g>{oP%i2)EYhnllqz2!5cZc',)((*/3<LaybZd  U.*5@:- v`7NvJ#8=-|omlid_cnxJ1SuHB, "+$x[+}4Tfj_E-)Ed~ .DYfmmkmu !&@^mF%tikzpU>&q_E0!#-AW_aTD>DYwsR83B]}/BKA+.BNT_r #uO0!AngN:+%  wrzkR@404=ISYdmu}jdp@`sreL8-3LmhM<37>FJE?:<LevU9!%Pyr\F3'!#*>Vqnc\VTV^fq~}U*4EMG@<9DPTO;\G?93" ?qf)YB3/:Qx!-&.I[cbRD2 7Pi{~zhR;%2Qw'-' "<MQN?.(7HTer{J 8Ql|xa7 5J_nv|~{l^RMNT[fqyvY<#  1:?=72.09IV[YK7" 3ERZagbYH+wbPDDNcnr)0+##4St   }g_]izhH/",4@Pds[LCEO^o|v^?lQ:,#':IF/ qRDGXsElqks    .C]v|cM9/($""&0<IXbhqqrsx|{yn]A% zqmlmqrpdUC:87CKL@#"xijp~|l[URU]hmh_O8'  )/#{i[OD8+%*1D[r|kT:#(Dd,55*$! "(,*"   !3E]skV>+#2H_snR>37DVjxwy~unlq}ytqptmdT@2%weSE?=5$ 0VsrcXTX]a^RE74>Y q_[nt^PHEIJLKFB;-" urjgjlqx~~r]D.  #0:;7+!%1I^fgZI<9Hd0Kcnjc]\g~xeWKC<3-)#&+16:91$ ,30  7JSTTQTY`e`ZH2!3H[ik_RHKZztib]^fyxohhb]\TQMNMKD;0"!*+$kXA/(,9Okri_ZUPD4 ")-17COaik_J09N][UG99=KXaea\Y^hu     "! -CXhsb>**4?GHILOWestgXL:* ":KZbc`WJ@1 s^TSTURNF=:@KYgrupe[TP[hy~_E4'##+>Z~9WsreYQMNXguznjitmN3   ~seYU\q1@:(zf\bq$6@JQ\dhqvusld`[UUTW]cpsV>,(.?Ugtuwvy~~jXH?87?L\l}|fN8 7ObbT6tnlpywj^UPNU\fpz|xy)01/-)'&),,,.5AUgytjeccb]YSOOW_kvywsqqtyyjaWWcrne][`dc`VI@99CRcibK(scVJ?1  -?JRSRPKMOSTK=-"2BN\nw *6DMTVSJC@?@IYj| "$'*+-)("{_F2*)09BEA>63:ES`iopmkfhfgf]Q>.#)*&     %)# vbRIFHOX`kx/:3%!;LRQE1  &=Wkvr_A!sa_fq&1<@=82,&! !""   $8NcnuvlaVNMNMNIFDFQbvuYB93;EE>*vjhmtwgVLKR\hnmd\URXh{ujcdq "+3?DHKNJGB;::;CIQZetyk_Y\ZYWTNGA97239ALVepy~}qcQ9$6Ofuxsjbbgr{|saRHCGJPOJ>,%&8Ofuyzo^UOIDC;1# $2?JHBAA?@GORQM@5)  #,5770'"  )$!jVD<3-)$$$'&**'! !'(%$&09Pbr(23+&5GPX[YTPMLIHGGINV_ltwuj]G4%"*0--+%#%+352&     )123)  (,.258=8, &.479@GPX\ZQH:1-,)(&     -9BDDB?9.(       !$*0/,$'3AHG@/ '-28A@@;." /@GKF@9:9<AD@<1& $/=DIGDA==AIQVZXSI<635=HR_eltw{}qgZTRQSZ[YZVTVTLA6%  oYJHN_u',,% "&#""%+/03531,))'$ ")4>DFGEDGFHHD:1("!#/>JOSOE<45=KTYWK=-!&7JZee]NB9:FOZ_ZP:(%8HONG;1--2:AIG@6(   $+-(&% !"%&$  (144.("  ,4970%   )6>A930+,17<AA?<:88;;9630-16COV]ZUI:+   #.4/'" }thehnx   # 3JZmv{}|xjc^bjqyvy{xpeXNC:549?ISY[[RC@7447<?BBFIILMJG?2'         znbYTWgt  !+,2<G[n}j\RO[k   sP*   wrrzvbROTbu#.11(    "'&"   # #0;@<8,&%'.5>B?90% (:QdigYH4#"+14642468:;5.'"))#"#$ '5=<1"   !(-&  ! "$&*.0.)$"+9GRSPH;+" $"    (,-&"!#+.:AFFBC>@GMTXXQF:3,.48AHHHFADHNSW[[UNKGBBDBC>:5-/039CLTYYZWSOF>5) ,053+&"(,'    $(+..-.-*+*//1331./-18=BDFA>9359>AA=5&  #,9BC?6+  $%   #*.0/' #,5:782477<?>7* *3880    "# !+,.0*&# %'& ',/,% #*,,*$   %*.1334440./'#'+-2252254;<=:40*$#'-3:@B@=:9<ALTWYMB3(&%*1342+"%1==;/     &)&   !%&$ "%*:GNM?+  !!  !" ,586,  %# *476*  !+241)"     $$ !%+4?ELNPJC>9301/-+./38<CEDEBAACIOY[^YOB5+# !***& "%& #'&#!&'##*%$(,*"  $))   $,,)#     !$"   "   "      *5:8-  '/7BCIORVXVSJEC>;=?A@DE><;987:976869:95/%     !!%#&)*-0452221569<:842)&()*,.021788AIJKG?6)  %,353-)'%!       $'++'         "%&   %,5;=AFGFA>8.)  "%++(**,.-10,&                       !&!    %,-..+($&''))'&$!'+5>EF@?81/-,031/*#!"',1//+$!    !'-101.,&#  #%*.112/'!  !        "%*+*%      &'(&   (/6896442-$# #%%$&%%)(($"!%%('#$!           # %+.00--,&')*-*))" !$$$##""$           "&("    !""    nyquist-3.05/lib/piano/pn03.cod0000644000175000000620000003036010144436365015316 0ustar stevestaffSYNCCNDNCOMMB\< IPART??????U\? )=9>);=?{>=?q4?^y>j>g?)?p?|?<]?>*?9?a>>8=m>N'>l?a,?SS3>>=Jn>]>*?;}=Nj>F<>fO>>nm?-sh=>ُ>>٤>>\>s>C0>``>*_==ޥ>,?5.>~>`Y> ?>Qώ> =j=e>F>G>+W4>QO>F>5?}>W=b=V>pN>>>0>:$2==_|<䀸>?{=f?GR=ɩ='>'=<6<b<6=;y= X<;;< ?x;F;H;Y9{;a;St;M%;Q ;I&;;;L(;i^;6s;0ܳ;/T;2o;4;0F;MbO;X;1w;3ۃ;z<< ;< ;1;)Y<;}m=;$c;2r;nt0;;;"\;م;!;'ړ;'ώ;H;N;1H;%;*;#o;*7l;'-;$;3t;-;!;;H;;ڨ;;M ;~;O;e;ۊ;]w;;;;N;; `;$;Z;2;q;*; ;};;;; ; k; ~0; ; I; :^;;`; D\;0>;;;6;~; o;; cO;;I;%; ";;;;"0;;7;;;d;;;;=:(;vS;zc;;x;;;l;F::{:M;:;:b;::]7:T<:X/:::::;:{;::C&:t:h::o:Ga::L:I:::E:l@:K::X:::Y:::r::E:ٲ::P:Y:4:: :::h:o#::a:od:@:P:޻:::om:盱::0:M: ;:ߺ:㊒::n:":b`:XV:H::*:I:H|:d:ݲ:ޙ:@??H@+rueF@ ?1?㘁?Π)ę@BAZ@K]?h#5>ו?@->kttM?,@NTFмY9z@d?*??)H?@3h?ɨ(?ϙ+@K@3F@%z?L0:A@2;|;??8'O?_0K>>nqi2@W]hi@?ω>?d@ k@;?Qo@6;N@?sh`ƂS{S>gӿ]8>?ͣ@{m"?c>f{@@ <6I?ji\N?f@?q>JD>d@[gM@?@U[@ K@2 뎣>H@Dm(f@bD@|?B9h@$@[>$?<@QxG @X@>[?@ mHPh?x?*?@m%?@*Ze@a}?]!tR=p@@4FI@v?ވ??D@vAl@=@7/JH ?k@nZ@5o?DA@D@CS@e->Q4A>A@qI@Yc"d?!U?@?Q=M5%/Tݾ,BпC>r@~t ?uk>Ě? >{@Pͥ@S;?a#\=#i 2@?̈vS???gMx@m@Cb@i,@3@ɿ9@uY@H/@&(z@ U?,@qp@@2w@`ǿ ?l=? @Hҍ@LB@N- !>^@d@??/F?+%@,@@?d@j)H@U@g;@$@|@$K@==@WK?g?@>@AITe@Z>!?UZB]l@{@@ @q@p@w@$?BTqu7?9?k7@F@}?z? @g%?@C"@XFM@̼#@>{&c?۶@`I@@W*@V:#d?>?ӗm@I@M@KB@VS-@*g@B@@3@+@?}X@Ĩ@ ??@ \=?n@@f8@:8Z@D@@ ~?T>_!_@@WI57Zi?G\?ʭ4@[@?gk@A>x@|>{o@0j@IwVvT3? ;@w@%؄@d2@OK@"?w?@}?پ?^?W@>]@@@@T?\5@3@y@L=/> %@'o@T%>E:@G@1=誆@˾=@@@\@^@٥vb?)@sJ1@T@|?Ϳ@zA@(?y@g@L0@>@2@>N@>1"@ @HW@@@s.=)G@.? ׼U@*/k@p{@@!@U @@D'GRUP?@@@@@@AA@ApAAAABBB0BLBpBB?@@@@@AA0A`AAAAABB,BHBlBBCGMAG P>??" ?-+?n?>}>mm>̎?I?0h"?:F?#?i?*??-? 0?v> ?.j> >>.>Z>>@.>u>>+>o>3>;>#M>?>,f>U >9P>PH>$,>G]=>61g>F>/>O>I|>xQd>{b>>iH>>ui>">uJF>>q9>`>po>>}%P>1h>q>{>X>j>n>z>v{ >P>qk>x>kU=>~>gv>rg]>c->y>XI>hD>S>p >^>eM>Pq>t >hy>yω>dh>s9>Zv>oR>a*>V">X*>Kv>P>H[6>H->@>GK>C#Y>4>*>1)>3˧>6G>%>^>&4>*>e#>7>=>6M=0i>.? O?\nP??{_?hf?e?i-?n?p92?fs?d6?b! ?^[?_H?a?b ?`0y?\+@?W*?SA?R?S ?QŚ?O˛?NA?Lj?MLH?M?M?K?J?J-R?J?K?Jm?Gi?E ?Cܢ?C,?D?D?C~?AS????z??Ь?@K??2?=?;8?9N?8?9?9d?8I?6?5K?4~?4w?40?3;?2|?1??0Z:?/?/tq?.?-mB?,RT?+?+.M?*h?)?(?(?'i?&?&A?%k?$8?#S?"?!ل?!9? ~? Z?C?;w?!??ڣ?|? ?>>{z>)6>؏>}{>˜>U >>g>%>_5>>>s>de>V>H>:>.??^?Oy?iy?o?^wj?R?H?F?TG?pv?/??w?tx?si?mԣ?l9?n?o^?tj?tۖ?t ?r?s?q?qd?n?j]?=?~>>aO>X>;>,Z>8>>z>>`>G>0H>Q>==ҡq=L=B=M=ɣ=%=/`>yI??o-??/(?9 ?1A?4?,h?%?;?B*?,?!Z??:^?A> >޴>Ե>d>O>H>ȗ> O>R>*>$>u>v(>Q> >>A>>ء>>h_>j>>+C>R>>Ĝ>>>R>>uS>>i>0>z>> >ņ>|>>t>y|>lz>tY>j^>o>bӎ>i|>Z>aN>SF>Vi>I>Ovt>B>J>;s>E>78>;A>/>8>->7A>.s>3$>+>.>%>+>$Ep>,>->*> =>=ɍu==N=s#f=9f97?Dt?Z?|>>՜>m>j?8e???_~?k+?u??z}?o"a?jQ?h?uR>?z??}b??w?ti?j{?j&?f?ie?fێ?hP?d?eJ?a_?`?]?[F:?X?X&a?U)?TQ ?Q ?RT?N?Oy?Lkn?K?G?H?EW?E)?B?BC??w#??^?=9n??>@b>ّ>>n>>dl>>8p1>=(= = =d=>>'&>B\s>_>yy> a>><>{>? ?>?;i?:,R?8?6P?4Dx?3W?1 ?/P?-?,G?*@?)?'?&?$?#Sk?!7? b??b!?L+?D?f/?/?)??:???? ?  ? &? ?W?~?C? ?3 ?HJ>'<>>>>>V>:>N>el>>v+>e:r>Yq)>O>Iɜ>Cn>? >=R>9>6D>4X>15>.>+>(>&>%$?(w??j'?el?xܻ?wxK?nEr?l)?o ?p7?p ?q ?k"L?eʻ?`,?]{?\?[?XS?T?OV?L?HU3?D1?A4?=d5?:7*?6x?3F?0?-?*?(?%l?"^? [? ?hx?Y????? `? ە? ,???ݝ>>k>G>l>->$>>>>7>-V>'>>G>h>l>Ir>ք>(>>Dv>>C>>>>>,>xT>r>k'>e>]E>Xv>P<>L>E&>A;>;Z>7љ>0>=$==5c>qN>+>2>-N6>0>>>D>8>#>>!)l>M> W=!*=ԋ=̘=k=l=Rl?-5?~K??w?p?i[?d?j"?mS?l?bv[?Xy?Le?C?79?,?%6W??h?0? P??>>g>!>9>>>>g>J>u>;>>=>;>Ѕ>M>W> >n>/>D>2%>>8>s>>2>>?>>>_3>>g>>~>5>I&>>>o>>>->E>>?>L>~>%o>]>o>>ռ>b>>u>o>f>]7n>T->K+>C<>9>2>)_>u>#$=|=Ue>8>Z/>g7>\ >D>>===̧=dW9==l[=c:=M==r$==f=#=z=??(O$?f?&.?X?V&:?=a?0{5?IG?-?-??!V?P ?Q? ?m?.??(? ??\C??'?>R^>>>m>(0>E>E>>3>>>$]>PQ> >>K>s>鎢>>2d>5>X>ۙL>ߥ>>e>>\>e>Ǔ>I1>>p!>->> >o>D>@r>ƻ>`>d_>ɢ >H>ˁ>'?>t> >ʴ>Dž>>>>8>>3><>[>H>`E>ɠx>WC>W>ɋv>Dz>> >>|M>P>WPl>V>T >O>)t>M=_=Q={E=U=8===(==0==??s?n?Zb?i^?{S?{ ?rN?Zo?X?>[?P&d?;?S?=nC?H۬?-#?+?#n???1>g>>!>P>x>>Yn>>oĖ>Y>\BJ>Lj>V%>2V>@g>8f>jڪ>v{=>[>>>>>>ևw>>C>߃>\>??  ? ?N?N?9?Qg??%??#? {?"Ϝ?/{?C??L??6?^?d??T? J>g? ->? />>UJ>;(>j>­>>!$>>6>> >`>~>u5>H>go>>j>>h>> }>)>u>=S=!=Y[=շ>0>=Ā=x~`?nD?7!?$I>?'H>4? >!>~->_A>p>=> 9Q>>g>3>s,>+l>o>q>ǽ>"> >3?S?i\????1!?ڵ?B??Q@? ?\N? #?W? 0?QH?#b?Ke?K?)uF?#&?)?4H? ?">3?g>$`?E>A> }>_>ô>>>Ҧ>4.>D>*Y> %==΀>0O>P!`>s>94>t>r>>>> >e>? >? >?8>ϪJ>#>W>o>l>:=>86>w>/->9ja=s>Ӝ>WF>K>;.=}=>64>9L> {=??m?E?F?X>?Iq>B>*> ? }>><>_>J$>>v$>W> >>x>PE>>zH>>`>|>$>jp>J>}>>J>>Q>#>\t>>?>YX>>O>4>؀>>6>S>!C>+>22>>m>t>>f@>D>m>X>2>)>EU>@m>%>~>%>l >=>>q>>\>K>^>>Q)>>>gI>9a>>g>r>a9>ȓ>Hs>t?9>>">O>=4>՞=0>'>q= Z=LN==q=WZ=LE=o!X=&====E==e=d=&]>p>e>>ό[>춣??A?2?'?.?3}?5 k?2?.u?& =??d?Ą>>p>5>a>xf>_A>YV>f> >>[u>>>N>>>>p/>>Ձ>#>>>:>>y>>U>~>s>a?>Ii>,X>f>> њ> 9>:>[>tj>%>>>մ>m>ٓ%>>+^>ڹ>ڌ#>>>;>>>>|>Y>=>&T?>+la>CL>i9>>6>}S>>E=1>o= =>nd>X*O==K>+\==iV>.4=u==g=+===N=?j?T?nn??5?0??? Cm>>>$>u>i>?A??6??&"?f??3F>(?Q>T?O>ں?<>y?!>>L>A>۶>>>~V>3>3>>P>P>S->5 >4>}I? }>)?W>}>张>~>J>>a>ǭ>[y>B>s>>]>>>>>>d>D>j^>IA>-?s>h? >D>~?c>? 7>',? >>>>v>v>ȿ>>?.=>?T6>F>܀>G#>d=>(>3> .><=}>^==Փ[=\>)*2=0>=> =?g?|@??&?f)?;C?Y>㥮?&???W?v?$Y?!]?(?#+?E?W>>e>4>v:>??*y?7?2?1F?#?݀>i>=~>>>&> >5>8>ڜF>(>FF>+>>&>#>&>5L>H>]>#>>>o%>j@>[> 8>xn>@>b>>}O>>w>(>x1>o>mt>|A>>P>>'>w>/>C>>>u >@><}>Eǐ>e>m@>"M> >S>>V>r>>]J>Yk>iI> z>>[Y>7>0t>)=G===> =X='> =f@==y!\<=<=<?e4E??#>޸|??:?*?w>.>|>ǃ0>q>3b>>OI>6>|>P>#>V>^>>u>F>k>->·>0>K>H>! >5>x>w->́>h>m>0H>J>.!>ƛ>/>΁>S>>V{>[H>%>u#>=1>g6>H?>A>=$>=3N>A`>3B>> 6>"o;>OC>Vc>u>k>J>K>8~B>.>7>>2>Q>T/>[>I^>=N= >>>,>8 >@X>76>20">0]>V>0>=>J>z=J=m!==h=q=y===m=l5=2q=2.Y='=ZK=%>瓶?[??Y`>>V?(U?5p?%?.K?J?e>>>c>=>S>>>e>>K`>Ŕ>w8>>F>>R>3>>Ӧ>>m>9>Z>G>^|4>R>>V>q>>>cl> >po>t\> >@=>`+>Lx >:#>X^>kQ)>>x>f>*>} >syL>}>J>g.)>T>I>Nq>f>+>>3>HA>R,>GҮ>Rq>e">m0>g>LI>d>=6Z>%ձ>D>J=> *>,>=<==|b=ZZ=x =8D=s)]= ұ=ZO= L= z=#a5?T,?p?{`?uv?]!?L+?6?F7S?o"?\a ?Gm?.n?8?5?B,?Y?G?) q? o?!?1?H!]?3??P??#?.c?'??=?: ????r> >ɺ>>M?͍>>>>Y>Q?? [?b>S><>->B>->5>8>>=/>n7>3>> >j>!>r>>>ة>9>ɹ>>s>o}><>ɑ>Y>=>>E>s>{>yQ>->^9>I++>q4>>`=/==ځ===});=~?=I=:=HK<== =<<$<?Wc?UXL?82?1D?oT?;?R2e?M&?Q?B0?J?Qt?NL?l|7??JU?F>?>Q? ?>I? ??Bk?$m>co>'>? X>KH>e:>դ?+.>>(>O>U>j>6>ż>>5>W> '>>h:>c>E>>>>˅>mئ>vT>6A>4>#3 ><>d%>{\>Z|>[>fI>V>(օ>'T>*>w>:>u>l>Zqi>Bx>;I>%w>5 ,>5>Iu,>( `> d><2>*==Z=ߢ="e>lG>u>>|==(=j=sf=f=u=@Z(=W)W==(==?`?9?@?e??M?=?{?8Y?@ ?C.?=?>>???>>>~a>{A>{)>,>&>>>p>>%?>>sz>T>*>i>Cm>͟>,>@>tg>x>I>p>>~_>I;>/<>T>g'>c=>E>F>c>8>D`>|P>[e>?@1>T&>>P)>z">LR>!>)݁>Oi>]>O$>&>%=>>/m>)>=X=[=>(>0i>"}(=|==>g>/[s>'b> 8====A=¢====Y =$we<,<#lx;;ݻS< nyquist-3.05/lib/piano/pn22.cod0000644000175000000620000001746010144436365015325 0ustar stevestaffSYNCCNDNCOMME`8oFPART?}>?DJGRUP?@GMAGX:I9f9i&:1:;:;:(:9mR:o:::i:jm:(: :c:O:.1:o;9::!::WQ::JR;3;Pp ;N;'9;Qm?; :2 :%:@\:M`:>+\:- :ʵ;*[;,Ӷ;X:;/;q/;8V:=;lQ;1|2;at;eb1;@):_:W;L';; ;C18; ;5;mӆ;|":7:`Q:M;-W;; : ~:MB;7~;/D3;;;/q:g˳:E:P:V ; 4:o: :s;#;i;J;:7:h:d:Ti:j.6:?:m;`YU3> X>^2>>&>>=>K?VN>:>>_2c=؀%=>$ >5>V>_(>c>K>OU>>!>4?>y>aR>q? r?,? >>c>>j?C>>??KL??!?x?SÃ?j*7?6?Jp? p??fN??E?*?A?Uo,?_n?OJ?7R2?;0?8_?Cz?lCc?O:?A?c]?n?\7Y?H#?8?Pt?JtJ?H?i?&L?B@??>?5?U?=q>? C?>N>2>k>a.>>;k>&>Bc8>?(=Q==1 ==<#=f=v<9'=/=*%=L|=>c==ڟC=Ό=5=u^>>a>D >=kR=B>=>'W>x > ===Ֆf==`=R=`=ݠ=HT==J(=-=C=γ=C==~O==}N=n==R=d;>?>o>x>!kQ>2>-=>*=2>.h>8>C3>30>7)>:a>AH>=>$n>&RD>&>>џ>|> >o==>_#=|==ڍc=J=+k==B=n=====Y=/=} =i2=="=ц.=3=W> 4>ʶ>t>>d>G>>\>,2>==֫=;h=b=M=[=cf===8=aV8=L=(=g=P==@[=4=,=nS=D>>>>>J>==o=٣=XU=?=$=?=*=,===P=tSY= =t=G=#=Dt=1<Ә,^<-<<νh: ;;;];;%;NI:;I;BV,9;$a;:/;:;1͓;;&]:׷;m;G;q;m;i&;.V;C;H;b;E;?0:Y;PC;;B;#; :C :ݵ%;`';ev;;Z;+.; ~j;p$E;;;*;$;n;B;;;0$;u^;ȟ;W;^;}];"P;&;x;WF;Uk;PW;;>;p";7Y;">;,v;^5;;t|;8V;  ;c;l;'L;^;a[ ;.N;3;,;f ;C;~;J 7;[K;ek5;;;l;H{;~ ;;];;q\ ;Q6G;;;;y;p;O9;i;u(;Tk;B#,;L;-;F;4|;T:`;;:O;!qB;z_:R::6:;Y;.;2;; Q;@M;L ;Ia;q;:o:>;!Pv:::έ;r:Ww8:]T:C$9 :5:eO9l::x>:O :c:|1:"NZ:y:i:l::~:Ex :^|:AF:59.:t:l0S:Sv::g:Nh:jǣ::p::-::UG:P:а:::v:a::<:ܪ:dU:.;:6::r4:SU:@5;: ::"::}x:: ::U:r::::̯G:54:7|:o:s:,]:: :J:و:J:,k:(::`::d*:f:: :¡;:g:w:W+:o:L:Yq::` :1:p::]::o:n:|::)|:?:,@:0 :i0: :O:,:0:E:RN!::W:/ɱ:Q:N!V:99yt9[99ٹ999d9(99!9Mfe9 s99>9 Z99:9y99 9d9939h89*9c89x93>l93?S9Gml91v89??9i9 49l9 94l(8p99mx9]j9Й9@8999|39eT99u(849 9lpD8,99p8,v9-9~9g9 !9Z8\9Є9f9(N9P"O9,8`99.@8:Pt9y9(9<9T:9$;9i9+9n9A9H99}9(996@8t8m@9z@89O9S39%W8<9 9-8S9u,8H9l9w9_I8"9t9<*[9"̎99!hx9N Y9.9a8s9CK9Eo889w889)_8Du9 k^9?9ifU8`L9 81V9 9Qu9 9r9(9DN898c9)38|9 8 Ga8 8u=9B9b9 99+88999Q8%9"98u6K8.j8 9yk99Mv8|~8K8X%9-9,98'8)B89 8^8)88܏F9,{9X8( 9#8|9,lK9W8d9 e9499(9Z98w9"8]9cd8908#989U8t8J8O8J 8f8S8ĖB88Z8P'9J8/h8Ђ88Df8e8FR8 8e%9@y9888f88y#H9F(89!8f .8n&8E 8]9=~8.8b9] 8IH9bħ8~U93S8Z988߼7p5989 h8i8tO8i!8s88馞8ɼ:8^9%88888m88 69 n8=99L88e 98#8j9 آ9,7x88ڽ89=9p89 8{8 989b7%8Xk8F8Xw88#9(u48;88k8594g98w8IY9O'8E9N888!8a8N8aJ]8̗9m89t:88PzK9.p8ɲ8/48ٮ9-8ɯ9{88)8V8g8G$88l88E]9ڡ9 -98g8o88sT908I8U8.E8N9; 838]R8*18d!98m(9 88.8|Z9?|L88E>8888w8L88:W8̊8T88f889"895z9֨8E8L=9@9;8̞8P 88 94/838X8x8IS&8Enyquist-3.05/lib/piano/rls16000.pcm0000644000175000000620000004750410144436365015747 0ustar stevestaffw~}qf]YWVMJR_WTPTLD;;<BGG;46:/ /41,:LZ_gmk]LOTUH24]~oSF+ +FQF//@H?<7.DeSFMV\jylFw<3YtW#-8v7 aUrA3;el"BJ  sLq T$5*&8[E&7w% rzYo--pj_d..xW%DZkI#EA>}u)\>GKQ#Jr  4 ( k 70BY[UH~rqL)Z%@8 C!XIFf$G| zG*SMLM/:AyfD@<e0? p$>/IDs*Q]t&C&~){u 7si(~nWUR  z  T=+QVs-LHS:21uUQI/ ;F).aW)r`9)a<o.DU'N/j0eVk? MJ0e{R@lbA ~c* 34:Tmf{2}ߨD1P.QX !j)/ 11<.+&w"Go9 " mm`` u=j } <+4VYuYyÑ˾"%Ҩ}!3>T<4I-**f(%$%&!6܍N&!G}sx I';06=D$G=EB><8. D< ?6J٩bW5~B.>k"S)3+-A2R9?A,@?<3^'< p׎=͛GYF9/s1rИJP ~%-35$2t.,S*(j# DQEaqmFپ7 حS~  vD7 p <KB F 715zpGD= [ s Mp;W &87oqXt Iw :8A9}b:! U#+7/2H6m<<@,?=7;94C,$W kq' wW e| &+/ 367517-+b)4%! DZ"  {ֹ@ј*`\0~Aޢ_m Yj 0d_ ] 0(5CEh;kh ^W UG0s?%kŠçƙ%֩h$0:B?EDx@B:3+Z  j\6֪ͺ^YrT̬׵m#2?K'TZ\KYRJA6(6[s ʸx$Yb7R^Zht(8JEUNLRROJqC=6/K)%##$&)')+-`,)=#[  Y:>[!$$!`l"+4n>JVa gjkie_?WPIB;n4.*'"]_ kp$*1689:;:61v+%O~UCIXه&@%#!*F 9 z9_yjܓF+rݎ>2A f[|uܿZDCP !y?$$&'''''0%% $%S%K$#b"i!!n! 5}c S!#&\, 3{;ABI9O8SVVSWMFp>T6B.(f"aR Y  LEE < >#K-^8CNZdmtz }|wpRgq]bRHt>C4J*#qO N#(Y-39<>?9=:50m*#/C~3eU/U cC !j .P(޿eQyӷݭتΩ.W`BϤC1t 30:;2͜BAx×L%䕈q#jO_˪3L0@di.3/A չWK)  $Q< NE/D^ ?nU7iN]\ϔ/l͏ς֤҃x= wZc#(-1o35j6X6654*24/,y(#-0[= = 2p  ]R_x" '-3&8F<@C4EHRJ KjLMLvJiFA;64Q-M&! s"(6-27:c<}=Q<;\840u,`(&L$#i""#7##$$$c$%h%%$#r!6jaZK $RI"&I+0U5:?CUFIjKLvKIFC7>94/+Z'##]"@< 0 uQ&Drחҽ |ÍY(ceL@DOoê7bݫ^9涜,zؽ]%EʇΞϛoOŦn¾ %˲Ϯ?e޾R}; >j7NSև׭َOv=S;x#\4(1gߋԼВ6xnlRkN$3# /x#'*,-.t./0>01p123$220<-*'$\a$vYd#&* ,/J14)6b8:<>~@.A}B?B>Ae?=:7N3u/+'$|!]T3g\um)gL"%P !"F"N!!7 )d Mo6f+ :m!$z&(*+,;,S,O,'+*e(&# j,+ q ]> 0 A R N +  3_Go!\H\>ѬmaήI̦?'5ˮI%jHϕҧԮԸ&BCˆ43n*Y=;ʪm7ͯ΃Mԛ{$YX#޶td9k3vHA^lsٿ v83x&`?:d6nF YD h<S$(-1D5K9<@BDGEE=DCA=n9140,='#l$gG} #&[),d/1p345555532x0.,J)'%# yb2q r.VCx4YS<  2|~O~o 4  ws51bP#aWF ]c U \pf.IGi#"ߗ(܈ٖ\ԍW=5hM0kO%]NU6vq##*WxM[/[5)?t}^zn}qOQ O ~br &Br  =W|nh?bS>iJ / t h + ~ fq~0H< o % !|f3jF:{9kDZ E|Rt D tP9G5Fl,QwAx\SJh %6*`% u[e9A`E"54 P,>K#jt;FM]{jM" 4 IWkI 4' >be>|I*PR[aKV.Y T>Z   t!_  -jr?~JlT^ o!d")"#2##$$##""*!] v| !6 o Zi`A c>x: J Z xS'7Q2EQ%i#' c | i/QMnvG0.B YMGB TZZ[yuTCdq.^0 #ZfA6Glf(,_zE7iyBZTOl5z[ f@o0?LKC;MK`u86H~s *B ~!"A"#$Z$$$I##<""A!!= 3TGy*}ZC;Y  \ ,H V1 6~)w:m@{Jth4;*!tc'a d .DF*VI*4=k !W  U . gmAXjyrR|+a<#S `M)6z. ,:S gPva~;3Bb~}W%_rOM=L.m_oyaOCv=HN-y r E  ^ E TSa s d , | t Y N  Mw{0l6 6?=zN#>lu/p<;<<KD bB!O^B L n  ? F   B7jckiF? 0\x5JE:ymq7gLu* nlvDg+RZ &  \0f,.UF#eCmJ5.kym3v RY?oo8(E|M9y72:Lq(*'8$3e hzoH  @ o ( r $  \ 1 r 7 ;   ' Y f I  e @ : L#yq V~  (:Wa"9L$q)R)%>8_BF+`fH|wV(=F?4 >| m\[fiX9:m cpe RCVi{nF8O-D)XjoqgCRW$/W,WA\anW[U"zN}iYZ)Ke2#=n3cT{ @ W$XI6F}XIt_!]'J   7  D \[~T 0 R M G g   L a 9 , a O  9 tE^e;!VqkDPhU#}y, $NowUlt2P~Dp 0dv>}dL!zaq|g$Af<b&h5WVo`GxC}898)rCl^ |?&DZDNS.y=$11EaVIknX :xCoD#vB,U lG^g]\<`6<`\p~me:4,+ (j|s]fUeHc.ZZ`6"YW,1_;~m O|*#-t w#kd/&Lmuo=> !y}WrL4vO7y( Q?y@ (VG (>.wK+y?Bk-zK|4$%5B=>FnLfCsVPGsSA)fEq3Wd8u1#""C_eCw|n?U' }/)Gz2XK b ZvDuuTeK~L~}vQq,-$Xc1vGA=hX`2&  1BSUASMOq!+ dQrRYt!4k#O6!=QH)6iU(>A#Fl}WdIZZ_WrCc;>A8A&RD=/2CH> /FffL_D@5)-'aiz3mo}""6d`0OTGbleUXPAutf>iQ+,gB S~Zb3e;mwut5 /sd5Qb(c )nV5-FI_K]0A> '?<XS199+ 9+4t"Mbo,u 3G/rV>X@IIU`kP 6s|D?+:& bTBpjq{>c>}>"q&J1_uG`-b~hNMTQ]`^cP "9O Cqcr>0=dTG)_nCm?V"{eqM303}JcD21y^#0Wtb@Lq kwRX~tFns.aQFDG79=:p  $  4 #  ! (o$DeTS`@*hN}Q"N;;lCXHhQ2'_zpky^%Be/'z|xdJ7Mr3chasYHQK[t(+GB) 3\8D4y \"-^ Dhu@ 2 _SZ 7oy7!XeR( .({z{eRTO9&(~~x GwaL5Pk~\EYgfo~ubH-,7IRB1h 7Q^Td ,#k&WvWel%7$J g"Qb v!xDP[5)r @cnN/&ZJ^=-0=Lk=)ANXaD(8nyK|pE.f^:&\ [Pp]donJKqPDNXJ6@W{gg}4/[YTbVqBONMWs8:3q_#zq*C4%XP8Xvf(,9}N-;9'9de#GJa7?jeWX7L,3 5k(uSgymD VYdt  );" X1CTxJZ{]>@v.}s i! A{P4itE'ke27G5El [neaFLE swW68*&5k@~/aq+Rln\QLh~_ ][7Y"/%Txx \&e#vt>NzpcVn-v-x<.AePu8:JIf |Yu IuN+o;t =q&U)0eFwOa-'r7 ><Kl[$8#22oW^[x"yN@Lwes9=3yzo8WkGGu]![BU8a08xoLZ3p5r(W>Z2~i_ h? 9~qn%o5fEv8p537<u(1*n7#)QRF4*\;b%r$s+;Z2n4G,#18tHbLZp | lly,/T]zRX:gaI0C!tU -ycU{[]e-JC*$ySy{"k0L$$uKGv_x-TD ;XM  y 8 P =eny[ )\HWs4L!kI#Y7E6nvxj{uZMAzb*Al'FRY3D`dYNI_$B %TNlj0w"FDxn-SD/cp8DL*d~E\]+I"@+ Zm?5=Oj(_Qk&MnR,A<,C1LD.!mng\ 3'e3DoiW,%+<@5<Yc {>Y A}7 .+5bc)2.plCt_S:^ _*MV%QaqC"]j>@H>ACG%1hYt/l"/Oqy0X(eG:X+sKyQ!;h[87B )KRW]xL|GBJ fOs,AFQ$ Q y9 \=:LepXK}u8fD^|nP . R;#Ue#b1+%N\kg2lBln: `f{B;9EKdQ(pN\]-*gVGK8{rs`ze,AycoSXh^En\|Ev{pEn4k4j>DZ~E U9[KDbP2WxTh&@JnS@BL \yNZ 3DQx5$rJz dQHyN / g#f~T%si$`:',Uy[BeRZP@,+430%\4( "3LhA^{tR8'*!<bu|you|w]8   #);IWcehfe_OB6'%$" %%#')-3124329666<AKMTVilpnyquist-3.05/lib/piano/att32000.pcm0000644000175000000620000007263410144436365015737 0ustar stevestaff  (~]h#R9,~YP^l<tJ6HGR`5tN V&7"uc)1}]{ w4 lvcG!70JoV j;  goEa 0+Y7L[CW5xrUK*]eH(];w'E^W?@Ia~L3kW+`)b:Hc &y-bSD,A>oB L (QPq$&w\\OjaE631.Ie:HGdrR". .'utM^?=3 I(zE wlxvZ_5v ( B U    ( P > B'NEan>k4uG5sal]?WDaQ= {~R w63Hk H ^   @  v q cFqO" Id{1R=dTM?4Djf 7)h34-2G  g sQp3%U!DR7^EtaKdTxxgb#7 DC^**( @ achZ\os$D4;>l,|0j34pE!L!b+o'tMe##mK008ROnKyP-#)8IO8Om2tC_{9z[L)p  y _  x J & W ,=F]nu!#IE):p F'EstbPI']<G%(!["=!!!5d7 qȻ))sȠ8թφ0^<!.I0 @VhQyʗךM&T+;IVbigi``P =/n&"_ b$)r)"m^Qh5 3`Ѕ[<ʡˀΆRؽݹ)ܩ5B7Bmv'f 7$)r+')U%#$'*+)' &9)(.353.'z6"GϝȍU>ĻǼԈJj*h;,xu]U\>;7*ڇ>q O( /4640~*=#>q 1VfؽaJg?%+YWZ =&[+-F,c+V+-/-+& p z ""O!+ OR><."k   "PXO l޽܌yқd!Ynb6ǦuLPˣC"a 8 l Q? x  pM Ab# ')_) (~)K+g-r.,*o&"j1j r(u#/: B5/?qI9Eҁ y?ՙ,dy }:3g\Hg^HOJ f fkovSl  HeE| c&l3$|L#1M ^ @ T @ S I d ( m q 1R CR|x&^$-9O;M%V|]t`gdYa-Dmn= `%;]uA t  HeH;GOU 2/ G@n' O8K 8Z:*:|SX}}+l[pN0Q;   u  o  G pa}q |yH0|f\ 0 Z!#u$H$X#" \ Uh`j@Vړ[bּҨk6 1bxfEo}S1U^b6|l# O-eeGumv. :[Awp^J_ : t q dw @ 8 v  c v C k m5 ~{J   6 y 5 5)U.`7g=r (4w| '?#3o* UvfDc[_ 73#  @ 6 G - szfYiPb;ze F #CC]NI$finWaaI_smW0`;dxV"O82>.5 k z  q < LF4BmZu"TdD\#u7|-/x7Eh9d|Ic*^n6tLx&OUXNh B 'vi%_B f G# I[3ftNr z9TX*JQj ez.>?Bjb]8uDikq Z: A  . 2 d 4 t } bFr hfu!X $&/ |@G@(J!( Q  _ c ]    iv6 d?7~=z` 'hk'r9/G0^CR9$xd-(fY/V1#Nk;V*!kAok[GX0g$c.6.|l r}H0 [ -68iQiGj^Wdm{b2K_A!$Hi[^ r4m4'q=+w4Q_msHDJ7d)w@+)vKE^mHtawD Q ) j C r }  | RN{( jYgn6>i Gbx6?J Y TP E 9 " : e k W u , y8F.fpHv?8]u+TM~-&VKOiB ebns){ # 8M3B*y?bg"p'IZtAI$  o=t F{^IB6o'>KJY_x(lTLRg ?Bqe5$~iS3BE5Xl6/IlJv8FVwQ f{-%arfd6s<)Y>qt ]V_>^x"(;_ R38Vi%]fy:?<'"p|FQ]mK$tYX^=i*zP dcRaB"5(lG,N?L)04[nm9  Y s   E ( A T|L|uY)U.&sT.m_2 h} 5BM5z.Z[Dj- $ 2nq.)5T 9Il,CEbP gSD0%2rKGNmnkSA_fZFh{*.~JwsN$3nSPlP\X`Or6V\c8e:K E*3 >-oob?c~xaPG6/BltH|'5^a>]=7L,HK(5YcXHRsi]A[;b4>{Yw$Zw/Wk$ .r v[dSh~ho(,xKh0pX3/KRk0W11Xq>rD C_B")7aO2`\=;GV^YeR$5=Gti4!89 ?u^RHQv% ]3$GT4'+6Fl[WmErqw+>ri`besUfi+c*!7&JW3l18 B+o@*'6\,I:PcJ}W?vx\O&4 m2Uy;"H1U}rbKz0;/ c%_,SI(ZUacFhFMGC*a3M){wvH *H(|uKxM)#cwFU7=(2u2%6`7@ /Q_91l(c[\|]0-^|e_' Dv]tZG>5" 6:E4QYNX{~nM%h!S \U"}?/8@Zq[PE+ rV\e4ixlT%ek+ntPU~?uPnDp*mKIONADwwjolPf 1uANLuABgSM8'HdF|e*LZoNfs~zEf At02=s(Qg7Z9` "Qxr1x=?s J/Z~)$:P`cH~`5L#hB[B XhZhQ@?55O>` >P5 |.%<RnwZ@/-?YsMmT)$}y8k/fuBna5 x[V~\ELkH[ ] !(T2f4P_S!pFx1 gPlp~\7X 0GK;6`Y.UBz erGOmK1')UgS%/BGAfCAEB=Igp4 J z:^SvW3#{b i+sB&#*$4[sgCW aZt7LNwt`[orEi,.00A^p^D[k$Ng>OCf2$v3YX.v%5AQ? $j{ Yw5_d'U:g$<0rljbbs}: ;o!\zY(384-?h#z}b[YSLShc<)"#qTMhtOFVsw_<7X  *Qs}jM41K$4<@<<7+reyt`cp|mA !|Zk`\qvmxZ# A]aZa5*l(</{  ZD9>Rr{C(Pcd^]j} 'OZ~udh@< ":D?>Qy~rxugY:xhVzxoZE9;MdwrR$.H=* p4} AdiK%1_ A^nmk| ,Xv;njY5|a>#%=ZaO=IqX4>g+FE?P^z U')f^<(  r~|W;08GUco}flKqpR21X}Q:5BHD:A_m< H_?) )Dkq`VT[j{]#DLB<@SQ/bD;.h6O52M+ 9XdW>%@e}|c?#%K%-ARJ2-DZoT ?g}f)1Rmyw`PNUdt`4&7@80/@T[N0'BTadYAy]FD^ n~.*&K c^n|M))7MlkNBMd{~b4~U6$"?J%UBU}=t{lu    >fuP6(%!(9N_mrrx}zkFskmqq`F88GM8DnuaQHKbX}3FTQ6}homYRWflbH+  )+}dR?-(0Lnb? %L +6-" $,( 'DcyX8!:ZzX96Kg|zyqmuwrro_F-gL>BQessgT9!7Yqyyoktwq[D85930,4B\|#>PZn&ED+ pUFMWb`VRMJ-_^gl^J;=Qkz|vqpwxoT(7NT\lK$^xv_NNh#Gq ,=6#  [;5>CIRb}wQ.jTVbgbUIO`x #285.+#Kjqns`=2=SS? ?^g^H;40 6= 28*gSJVk~&4<>7*_~{gVW^^O95T iZuwXGGILGB1qijowlI(  /<9((D`hV=;]Ehm`]miSE:.'%-6;3!!3) =QTQU_d\A$;XkbMHbxh__v{kgb\TNMK@2!*$z[;).Jr}k]UN8'-7F^jcC&L]VC8AUcaY[k # 'Kdyi7 !2BHIOZpwbN6>Wc`TB-lXRSRG<=OetqbSTe|vK2"%:d2an\NL\rpiqqF! |hU[{/>- ~b`y2DP^hsure]VVU_miA*-Ecuwv{nSA6>PhkH" 'JcX-xmo{saSPWcry{&10*'(+,-9Plqgca\SOTduxtps|m]Vfk^]ccYG:<QegB pXG4 3ISQMKQUI1/EZp,@PVPD@@Ne"%+,*#e@++7BC<4=PbopkgfhbK2$*'   %'x]JFL\i~45  *GRI) 8]uoFe`m "6@<3*" !# (JfusdTMMKIDH^~nH58EA"rhn|zaONZjmaWRclcn!.<EKLFA9;AKWjm\ZZXRH>636EUixt_?0WrxlbeuzfOEGMO@) +IlzudTKE>, /AHAA?FOOI7# .83*"#& pP<1+$$&(+# '(%-B^w21#+DS\WQMJIGJSctwnU8!)/-)"  *53#    !/5*  +/5<:*-57AO[ZO<2,*' 7BEC:. !!  #,/*#7FE2 *3?A>*!<GH>9:@B=, "5CIE@=DPXYQ?54AQ`kuytcTQS[ZYTTM?* _HNc(,&#$"#)/441,''$,<EGFGHHB4%!'9KSL=4;MZU@* *G_hYE:BS]X@#3JOD3,2<HG8%      )+'"!#&$ -33+! )68, .<?3-,4;B@<::<82//9LY[R>%  10%  zkcmz  $ "Ebu{}{h_cowx~rbNB55=MW\SB;37=ACFIMJ@/       |j[Tc{ (-:MioYP]~  j1zpyoUN`w 13#   #'   " 3?<0&&/;B:-+LfhV7!(35247:90%!*$$$ *=:&  %+'!!&,0-' .ERQF0"  $  %-("#+6CGC>BKUXM?/.3?IHFDJRZ\SKEBBB>6..5@NWYXRH;,-41''*#  "'.-/+,+.231-.3;CE@957@B;+!1AB9(  $!  $-0* ,89528<?9' -88$    "(-.($  !'%#..#'+,&   (-2543/,##,02346<>:0)$(1=A?;:?LXWD0#'-52)"4?:$    !)%  $'!")<MJ0    "   '87* $!'65((11("  "$ "*7DLOJ?71/,-.4<CED@AFRZ\R?.!  +*%"( !'&#' '$'-$&*  ),%     #" #       -:5"  )5BFOVXSJB=<?BDA<87::789;5-    "%&(,2522378<72('),0136<FJH=, $-50)&#      '+(     #%    #.;>DGB<2'#)))+-01)"                #$     $,,.*%'()&# '3AFB91.-30+# %-0.'    &-30,& #)001)           #),&   %(&  )39833+##%$&()'#!#)'"!           !*//-,'(,+($! %##!#!        #'!  ! !!    nyquist-3.05/lib/piano/pn21.cod0000644000175000000620000004346010144436365015323 0ustar stevestaffSYNCCNDNCOMME\9 QPART??}=)= G>M>>*>Y>>h>K>R??O>>W h>X=o?=b=L>>G>0V>zi>$a> >>>>.{?>>">R6J>' ?d$?"T?>Wu>B>>r?? >???xpm?_+-?4?Qb?V^?5>?(-[?:fO?1 ? O?7?9ۨ?&?# ?8M?D??@?;8`?*T? G>*?>>?>i>.>>(??UY? ?6>ޜ>>? u6>]v?>2? Q>=z>v>C>RmI>:>%|>e==Cު>"+=1~z=T<ѩ===)c>3o=o=3==>>>H%=DV>J> U>4N@>3 5>.<=˩= ==d=t7=W= =W=,=2kV=V:=cs=]=3$[==с=N>x4>0>SV>">92>9ܞ>NR>Q>J>FK>Sj>RX>0g)>> W> =7>>X#>V'>=d==ڠg=ڑ=u=T=)=g='_=dG=\*=es==== `="=o> =w>>>/>=y=+7> ''==d==h==j==h=Ï=Q=yU==W=yg:=C7%=1~=gK={e<l<,<BAb<h<;;R;;n;确; ><<ռ;N;6;];Y';f;;;2P; ;;NZ;O@;;j!;[;N:P:%;_;&:: :ބ;M;(j;E<;%.;4;;;¡;y;ą;b<;@;u;C];ߙ;;8C<,< ";; ;_b;V^;l;fJ;;;L;rQ;s7;N;.e:)::2;#};]Y;[:':2;vh;*"r;V[ ;I;; ;?;V4;h;-h_;".;;ji;l;ok;)u;;(:͎x;H>;7:1; O::ZJ:(;m;*:p::f:;G;;/;X;+;V;E;;H;xng;OR;;N=;;!;;2^;R6:f;D-;b3;%I;t;P::1;i;L؏;X:P;f;gb;;j;y;Z3;g ;C;;;[w;vz;;q;.;;SǕ;$m;g;|;V\;0;M:;F; ;-?;(޲;+;KԶ;*;;q ;8J;9;7|;;sۺ;\=;8Z;p?;*;s.e;;k;y;*;C;;;ݧ;fp;m;z;X;Yc;;l;J;6k;cM;*g;;;o:À:w;":5:O:Q:;;;*; ;:t:@;.; :E; :.::;%2::;i::3:ޣ:ڝ@:+:Mg:k9:,:k::99T9):> :9>:HM:B::[:C:x:0b::]gP:::E:::u:ڴ:r:Au::&:yο:::^:}P:: :K:+%:<:::]:: ::Qv:yi:V:4$:)D:1::W-:\=9y2:H 9:9":89x}:7?:>T::3;l:hl:[: ::?9::aM:l.K:Y:Y:L79W::\:.Y:-/:Ja:A:[:o9:wv:a;:y9H:S:l'D9tV:l:D9/f9ޱ:-g:r9z387:Y:i8:Cv:X(: N9ІH:g^:9!:6P::1wq: :!::J:+:q::BX:v:\:+:~-:{:ŵ::%s:M::0:+: ::ȍz;:7':u:n:::P;>; N:;+;#:$;:ؔ; T::ñ;A);,:[K:m:M :P::_z:1h:H:c:l::ș:+::P:r:^6:ŭ:::[:(::@:y:`A:c::*l:::hc :r:qG):} &:uV:Q:*l9ˤ^:G^:o-:aF:Tx:-:/JQ9:Tq:"$8]9X99g@9:9;e9p:44:C;: 9h3:h!: 9:9{:+]>9\9lg::4x*: :':>99d:+9Y9N9o9|9^9Q:: Ƴ99Y9=4:+99}͛99j9=97<909m9uy9p\+9998\9D999=m9+9 9+-9B9P9t:B9t99>99p9:.&v999톲:%:99d99M99:%98M8cR9_9h:9@09yt49ӂ:N9B9e+9699T^{9g9-f99w*9. 9DN::#Z9݁9y99&_9`969u9g8Ո9}9*X9?:9y89P::8:9^D69m:99_96R9:09MI9 :::*8:Ta:09Ȳ :^:Ү: %9:;B:O9R:2:_!:M:Y:+:` :6>99:B A9:m:&*:o\r:[z::5n: 9:/n:#S:O9999Ŀ:Z:<:KO98:::L: =K9Ф99V`9ٓ:^7:͆:99 9m`: :D99r0U9 9N9H9e 99w8р]9=99w9^8939ll99p8¤9_9Q9391ظ998$9c h9o98⨦9u9y:9e~89y 9d8_B9;.9e9Ŋ9x1+968z9@|'99|9o9)9989K99+p:9h'9Z9>99z׹8_99+8Y9+O9k9p99ѿ99k19{9q9q9E9*G9/wp83 9o98 9Q],99y8WX8$98+84Z89)h9'8n9ѷ99#D9#{9.t9)b"929d88~8899Sz939[9C949&u9Jз8jo<88N9C8k9 }9we9 )8Ql9g9N909Gݟ9b948^88J8 o8V/78g8V9U8F;8=9B99&9399$y9#8 l9 29~9G9`q9j9X=#99d9x2'8%9%9J8J9!'5999894~9g9$8{9B9J93=93!9_9w989@9l9W9=i]9LB99D9nCx9+j9v9H9(i9V8\q9~n97|9)9o:919v8@9zZ9O'9m\8*9 88z9$8999U;8q8 I8o9'!9!?8|8l9 8܌r7g89B68Gw89>&!8]98Şt9`8?8\9R88389V8<889;/9 ?8W9P9FgY8@8S9)dp8"d7s9A8ѿ8l9J89G8.9 9838V893-78d8#93e8 8ƿ958o 8t889"b8/8(B8M8T08a98}88Ӛ9"9 8{?9qM*8 88~h98M8}IN97٫8 D8 78>7u8WB9 ck78M8,8^998t9v8.88 8$387Ώ8898u+_8:Q87y88<88~98888W88pP8h88,7;8l939&8868S8'89 Ig8-8|8=m99C79%i8H8黱9 88s7H7E7ɴ6w9&88͐8.819!{8d8>887+888K{7R$8C8)987E8˲9(8]78(@7Q9 n884@897?7=7P9)o 9R8,&8B:8c8 Q{9 878&8I8_X!8S\8298΁7г78488K89877 8$`8X8z8ӕ7r88o8Q8zN88~8e_8D7798j-6w8c8sb8&8\{7t_8Y 7݊8 78S8"8#8G8 87778ra8B8Wѩ8w98y88Re882z88 D898h88EC78 8D8d8 .878Ȇ)8z8M(8p?8v8K8U8<888<8B88S8O7.B8s8L/8ueV8}8a7:88q-O8wY78Gv8#8wH797P8wBe8+o87n=88Ӵ8.8Í7ă78'{8'7n847%8;7] 88ap87ک_7=8,#88+# 8ԃ88/ f6ӫ88l}7W٭8H'8Imm7"F8p8b8"88c8^B8H 8-:8b\8S8]:8u{6k88 l88K788B8%8(`;8K_8W8@L8}-88. 88+77J9 8o7LF8b8w78K{7={8w g7F6Ŷ7&7@888 8ܕ8o8E 878[58Af8+-?888d88p78R8!6ǁ7 q768Q8h81q88F;7+&8UЯ8 18B77V88l67L>8`8%8\8(8t8\=8868@;8UN708Ar8_Y 8 87@8Wg7ř]8867>8b87878%36t68E888z788677Ɯ8~7O7yl7la8%8Nzi8M8-8867-8 e8G7ta7Qj8[88r8G'Q7ٷp8^7LO8R88p8@%Z8J8o8"=78P7e 8968W8E7t8lH87ĭv8Z8D7 8^d8D7߷"8+i8@8S8O6<788R8')7 "8l87 78!~8!8<8 T,8M7X7gA8b837˃8L=r86w8PY71y8:82e88BK47+8s88D7 C7аe8R7I8 Ú8-77:8O77J883z778 68f8+82u7Ȱ88d7PY8W 8"78a7b70p88788(`8U678C7I8&77%8^7z7G 8EPl6ek8r8l8U7_87jd8S8!868)7˰8Gn8}8'7ϑ8i|8d7y8]e8'777$@7EF88=8t8%Po7JI8&2j78>8htg816uw47 8|985wr6;7ͣ8n767a8+ 73788@<808O7D 82PE8BF8C8U6J88+8Z8 }8}+8y8888\@7$O8M78897y^7<68i8\*7}q8Hi84I7S88U?<7 78987T7 7p8J8&/77Ѭ8d 8~#7e8X8B68 8O7E8d78 Ҍ8z81>788cGq7{8 8 8x77H8D87(8G 8H7C8$7&8v8=8"8{76L7A827'8%Q.7D8Hf8?8;8#7,877870X8+8L68@8a8%F[8[ 777; 89&O?7 78887"W7I88^78L 77f 77ê8 O8{77,8?8*#77GS8F78t@8>^+757gI87V%7d788T7 G8C88,/8Y88(67C758!8@e7{"8J@077[4786p8J7(8k8MQ8G8~8/J7n}8u78S8-S+8?8i27 7|8pB+73G7{57&7!8f 7M7G82V8Lخ8{57|75|7N,8v8%8so6$R67 7@7J8HS78O6xn7Fi81F6=7y8y8e68::_:9ߦ:kmQ:;A;:Kf:&:0E:}Y:! :8::ї:F:w:/::d"]:*:;;/X;f::w:Δt:%::y6:IƊ:w:s/+: :T$:N4;0::Yy?:L:m~:81:a:3:BT:+G.:MQ:Ů0:U:d:A:::]:Y::W:j;<7=iF=}Z=H6=[=>6G[>-5>l=S=r=Z=~Q>B>0>j>>e>>uU>%> iE>{?>3??>Z>>>Ĝ>>-u>^X>t>Y>8>&>$*>>V>w>K>?$?DO??a??])?I?F >0>? ? v?8c ?@?P\?7?:?O?=x?GT?^4?,'??z ?^?HN?7?/c?|???>w> ">>=>(>V =r=9>>/>?J>RL/>YBW>>>S>R'?{? ?>)y>Κ??>ʚ>ׁ\>> >>j>J>S'S>g\Q>1I>*>v>Bd{>Xt>x >Z>H0X>K!><>,K>>سY!">>E=N>K>:>q >om+~v=|=>E1>Hq=]y=-V>=6{==0=`=d=g=Ė= =K^<|=y=ҕ==u==o =Sk=t==.=9s=O=78[=g :ѝl9: ::Xl:l:_f:a:_k:w:;Rf:W:H:^m:sm}:n:7I:Am:x::ag:9:F:Io:&'96::::':iR ::*p9:2::1Zd:dRE:FC: : 9%:no:@3a9X::zG::e:B:Y^:r v:#9::8b#: T:WQY9:/:1:Q: 996:wl:9E_: Or9̘: \: :&9N::._9r:q :%':Dsr9 :J :9 (9 :vC:0Y939:/:J9݂:pj:9<%9A9:539L9 9ԝ::95f9:0J:6Y9,@9 N9.99ya|9>9A|9dF9 9l: @9 v:,9:99l9'99 9׍:F9؄:Ǧ9ׄ]:0n9909D9 99z9%99':9|9n999{9949sU9::9o9B9ً9/9M9n|99X9yB8929 9~˺9R9?9)-9A9=9#a9}9OP9D99a9W9U9~9䗍9Wҫ9999'9^,9rO9B9Fr9h999ɖO9%D9J9K:h9>9Fv9<9I9ק9d^9~9dq9^949491Z99t09p9Ʊ 9o99b99d9iN9^9 9:9x999[9:9999U`9m99֌,9-909r9[t9L[9kO>9Qw9y9eٞ99^999}9o99v9Ѩ9O9Pk9C919Gy9"P9997?9PD9g(9999~99k9( 9v99999y&9r<::-9u]97::99J9b9D9ܲ9j!9|69Cs)9e99ts9rqp999~E9b6>9¿99N9 9j99N99p49|- 9cF9!99T9m9s!9c99V7989e9n[9[99j949`I999x9e9|;9z)9k9q9 '97?`99R87b9999w29x9`9t[9W93C99999qBf9{99E9a9"999;99KsO9E9cH9o999IZ9U*9]9E998,G9q 99939AE9L91Ⱦ999,9M93 9Z9i 9M~9999^ 9c89a99{K69`9q99N9999p9#99k9 9H9at9dz9s9R9599j9PO9b9Y9Џ94h9w79919oq9r99|9Q9S9{ _99s799} 9N9R9Z/9E9Fpo9|Ym99HD9B9 B9e!@9~9i:9I9|9t'9?9i;9x89v,9 99q59999v9%9oG992<969@#8+9:=9a9g 9v 99Ь9-[9:9XA9tb9XuM9W 9SM9909w9F9g99oΒ99+9l{93999T9lJ99"99T89ez9E9=r99o999U9S4G9j9|3992u99~?Y9989]9tg=9M^?9V9 9~9OO9Ж9۳939lY99D9q9SM979b &9@Ӊ99T999T9(9_r9j99D9l9j9b92D99у9I>9h9Bk99z>9?,9v9k~9V99n9zM9f99/9'Z99 9y9O9VB9>9a79C9 $9΃9Q9989i299Y`9B/9`9=@p9zD29?9>@9ob9~V9 9@9iD9e9P9u9.9t9hx9ClE9Y9M9f9-99s949M99BS9/9D\9M9J969ü399h99r99999K9J 909EK 999SW9~l9v(9l09^s`979c9e&99kG9>9#939S9q9tU9i9v9'999999f 9S399x99Ť99'9`9z'99y 999ѽ?9U939@993999f-9rw9X,9I?9Xn9*9n99-99499O*9̤999xI9[99oR9{n9O97989&199#9Q>9]z9q`9(9H.9=9P9[y9S@S9n&9b09D99g)19/9Q 9Zz9`9_9C995[9_9\9$9P9t19I~v9WW949M99h9n9uq9O9e9&9\99W9y9e9S9d9)9^9.9e9S9 9H9i]9099 99o9VB9L09 99W9ƞ99#9B99Z909 |.9/@909c9.9q9y9e9t9I99Y9AQ(9ֲ9r9+F:9l9;̖9]9H9Tޭ9V>9~9 999 89'9m9FP9<9zB9Xa9939{99wt9959 9sg9_O9 :9p96:9("9 9t9u999k99c{9-9I99NJJ9n!9i9F9$(9>9G9p)9óT9P9xd99GB9r9 @9>9g9c9v 9 9393[9B9H 9`9+9vD{9\Q9Wo9I9c99S90:9>N(9 ~x9&9am9Ax95z9/޵9yR9e9J'99MN99919c9I?x9tM[9vrL9P9]=9)9|*9T9M9G9J94y9f 9 9!9}M99 99Є999vs999M9(s9jP9Wp 9t9p99d9s*!9 9K9l9,I9I99w9 99bɅ99)19ܟ9T;9?99599o9.%9G9ho9Q-9c.19zIW9D9]99w9oA9*pq9bg979dQ9(9A9I9_9"9>9|9D9}e99a9;9J\9859f9+n9N9wk999:n9E9;94=19ͅ9tw9`9(;999$9ßI99Ub9 9 $9 9 J9-99iX9V9`9jI9p*969?993H9X99C9\C9 909ĥ39T9p96d99o9@9i?9C 9S%9f99n9 9ҷe9'd9hG'91 9 9;9m9L099_9I9;`9F !9`O9x&9t9ei9},99U9S99k09K99Fw9|9Z99tO9A9UZ999 99g99=9Q9A9vh9Ħ9 9_99z96909cS99K>96999s9h9Kq9{99p9<9E9K9c9o{9r}9Xt959Ve99ZS9&9D9219x9[P79z9Ek9>?9Dl99ߞ9l@9w9q9O*99h9E9u99to9-g9HY9S9z9v9\J92 9Km89V9m-9NM9i9R39u9qe9$Z99C969ծ9BQ9Ψ9!)90959c99y9X9 9m9^9Dh9H.9a'9v992929:9999{99Ύ9P9'9e9{9h99Q9u9/9zx9Z29z9'[9?G9 L8`9H9d9p@9vw999v$9F99F9ڿ9\994k9nE9F~9]9i@r9w9L99'?9UU9L99_99J9jl9y9t=9m 999n9I9h/9q]e9k9X9${9O9nf]9*99'9f9ʿ9$ 9It9F999!9^ի9-9R9S9999Y9 f9[9zT9p9vH9|9j9Q9 ;9]9Oa9[<9x8?9Zc9wI 9Fk99~s9u9s9^9{9t9s9_999 _9@9a9Gp9Bb9]@9̩'9 9E9lD9i99,999{9W9`999F99299o9:9Z9Q_9`9cf9^E9~929|9I\9$\9\ 9z99^9\_9[9yQ9x9,W9m9ry9(99mu9gB99did9j 99j99W99d99U499uX 9mw9B9W"9-d96^A9[9P8.9}9O9*99 9,9E59b9n99G9(9I9\9Hd9g&499k9g/9nxw9o9ݘ9H9D9}!}9]9*9 H999Zt9I9.9\u9ST9>959W9G09k99pB9V+9|9Ff&999T999~>9Acl9)F9!92Gb9uq9B9s99C)h9d&9};99Oп9J+99 %9999nG99*9cV9Vk9499M9(99U9I9 T9n4L99l&9;9?79WM99929K9]999Sna9S]9ڈ9Y$9Pe99x%9T9q-J9"9O,9_9Ro9Z19h919uO,9909+999<-N9^(9k9Hl9̬9s59@ 9`90P9l9w}9#9b79x9w9<9|99Vc]99j@99i9Q9Lj99><9u=9d8}9wz99(G9x9K99UO9jX9wߛ9^x999<)9q9999˦9GC999L9T9g9D9o9$99.9Q09-9Q999FJ99[/99 .9z9HD99{@95e9M9 99e9]9g99699a9f 9x9o969}9|9Nω99l9'9P9dw999rS,9p999c9 9R'99|9y99@9439!K9g9 99}99ݚB8#9>+9"9[49PM9QQ9x999]`9/ 9}9+99'9\w99Z9v9h99yr99X9ɓ929 99?9NF9w9$99B9u9'x9N~9n9ˡ99r9yM9v9-s9)G9vg9\5-9a;*99f94)?9]'9o9A99199&"99899Jm9T9qF9F9/99w9|9Ȃ(9sFP9{-9ac9Ax9-9go9b99ѫj9Dn999Wa9^9J9S.9 c9r9&@9OM9<9y999C9} 9d9099M9f9 9)9S299rt9Z99qJ999d9[9s9<9}%99w,09&9?9M^9.59\bJ9G99a^9֟9޺9I9i[9x9999Bv9AYU9?9|9:99p@9C99Z:F9y$9u99l9@9;9g9b99909tx99tO#99A99W&9 9T9&9x 9K!H9}9x89i9|"9r?va?E>? j?)o=h?>??!h? ?7ջ?M>>~!=>C>f>>_?8}?E7?l>&=o\=ojF=\r>8>?7 >3? Fd?N'>W$==L>?V>tT>{]> >_?>?U> >ng> ;>$>&> 2`>? >D,,>f>+@>Lҋ?ld>A>b3> =o>'C{>gY>*>z>3?N=6:>)9?(lR>K>1=t>=@=>h:=>mh>Y4>>I>D> >=Y-k>JB=<=<ˠ=[<==DT> => ?9>oi=?!>n=*Z=6= <=%=M=x>DR>==>G>c}=S>4|>* q>>>>ߧ(=V>>x=S?)p'>{>v+>B=n=Ra> y>J?=3w=GQ= >q=a47=S>LUA=n=6=ي=،==,@>?c>GJ>.>^>==^=ĺO>WE>>&P=i=h==>#p==foZ=Å=:=T ==1=<_g==r$=>n=.>!%=aN?'A$>=^U=oX>d=#z>;t=>U<>Q=Ł=;=6=:b=ezN=N_=G \=yW=V>0=qZ=]=w=Y=&i='O=&X==&j=*=,==%4==zd= =K=(,>(>m> >,\>c~>]>*>o[i==a=N=$)=4=֊=P[>M>Ϥ>o==8[=P>,=> ===D=Z=>_=Ų==ڔ=%=U=+ = (==Pp=0==L=tC===%===:=vz=\>+>> tU>#> > > %> gX> >_o>6>>;>>Y>X>>_> w>>=߳==>#<>c===>~>,>\===mS=w===#=Q=Z=$==㡲=Ѓ=a~='=%=P==݊>0=n=d~=Q= y=z=J=h=´===6.=z=3!=֯f=ڷ=d=:= ===<=%_=q=K=:=}=7=^=P=~ϻ=f=}=Z= =Mo={==]==|N=~l=|;=wPP=w==x=p=x5=+|=s=wG=x^=~=wO=sB=p=v0=qg=s(=qs=t5H=f)C=kLC=j=ey=j=qR=pP=kc=jm=o =fLD=z,=xu=b`=m==i =f=j~L=A=jK= =O=f=7C=z`h=h*==c`j=f==W=a#=YK=x=i@o=hL=^T=l=_(=a=\=g=[!W=jU=a=dJ=lc=c[=S|=_7=)=s!=wq=vϡ=^\=Yl=[S=W-=`U=]==m9=~=n=S/=U#=O=W=_>=]Y=NC=L=NW=O=J5=F=FI=L=P=W =Y+=_=OX=Rh#=GƤ=QG=Q]=Y=]===e=an=N=J=E =CY=F=V}=G0=F0=Qb=`N=A=?"'=E U=Av=E+=@o=@P=CR=FY=A_=@=A=:==,==6=; =Cm=C=Ch=F=Af=5ۯ=8=8=<:=="=9v=4e=8V=>/=8E=4b=7=A"=F=N=;[w=2O==E=>_=7=1\=2' =699=2=7 =0=1E=3j=1p~=2A=/*=2=5\=/G=/{=5Q=5=-=1=.=5y#=0=3=0=|=-=.A=2v=/.=)Xm=/*=-=21y=6=~B=1=-V='=/=*{9=,>5=.g-=+P='a!=*='=,$N=,4=(]=+'&=(C=-m=({=)W=-=+H='`=' ='.=(9=*l=':='ڡ=)Ϡ=,==)Q=%Q=!I="=%3=!T= =&='N7=%=e=%ą=%O=%=&=&fm=)5U="B="B="I=#= = b=#|=$="=#i="= =#kq=!=$=#. ="s =!=!=M=S=G==$b==[=+r=ҟ= o=="=%===! =_==&=-= =='==.=s===@=v=W=j=;=c=P=&=%= ==+=1=H=H= == s=!8= K==Q={k=&G=`===E===w@=Q====#=1==1==D=G{=u{===KT===K[=aa=]C=q=*W=D====W=9E=_ ==mt=n==;N=_8=9d=b=v==)=\===ˤ= ====L=<=1= b=o== == == =f0= l=ߧ=wp=== -==Ȣ==L=A== =+= == ==_= ==W=u2= =Hq= = U= 7= sp= = c= P= = = )= aP= = Mi= [= i= = := = ދ= = ==:= = ;= <\h%l,R>?_;9>-?@%p$R+?*>{s? m@yWCuXԨ@,?o@%'l@J\JO?@I[@Ai@'^@Ox )Ϳ!&n̿dKY /o?@G sL)Bt?T;@db@Oئ|-@."(J.C8G>E/??2@@0(6[">9?ȱ6@Si@Xk3zd֑=0??ῷ=f?*@9-s0>}? 3@&a@)1@𿕲􊮾m?4+?0(?[@@Jf>j?І*@-"?2=QO?+??M?$i?=T?8? @[@ @[dr? Q@:꾯r@G"FҿP(??]+@} F?GG?@8@k!f΃ź}z?\K@C@PIR-μ<?:?%@Y`ؿ+aJ|=>#>\Wj2?@iǐ}S >I@)k ʑB??wc?i?@:)ƾ>~?q@9@:A?ύ@FX >h>5?@pT=` ?9@L2>Ň?C%@b+@m$*,cW>@J!z>3e{:#>Ó@3P܄r#)? ?Ϻ@AP>ؘ@(^@/ѿ?B@j๽o [ͿDqQUG Ϳu ={5@&W@Jc?uG?5L@p连@iw@O?=t>?xgοS@_}@=1`ÿſ%?LA?b~J0H5ҿL4>V??iMBE艖?I@?1dEX @?@z;jS?v?\n? $>f@ @ ?_@J@ml@)G?꿛ph?Ĉ?R]@>v@@L׿%& L*w<~ѵ@?{:?#?HSW??4?N@8Qd?&n ?6>1?p? ] *@S@{7B.? kN@cW@8j@@?@?IAO>&@ Q@u?fˢ@nN?l@4?LH@WUmϣ*?IN@Mb@rP>y@2,@I@Y?l`%@L8??w?8>?$ǿw@0?;[@\>9H(?[>a&ܿa@h@5 D5??7#??ed?Q@*x @?h@vP@n@?F?@7?X?b@V󊿃/ȿ/Y?K8@ M@?s>I@qr0@@3X#@m]@D@pP@h?W??_7@&@n>H Q?L@crB?@<@"K@;@ULe@p?'@&m@v#@n?e@4@@}(@tN?η ?@̹@R?{?@a@.@@ ^@@TU@%?`@c@M@=%@'??~@e@*@o@%;@ g(@>@͇>?Dt?M?3]`? @kD@=g@?B@l?s?f\@+>%?+?8x@!CT?q$`p@#sE@@@$?NiLr?7^]?@7X@S?Q?.Z@CR^?S@w?;?g??5=!@iW*@0@3@-?@|ֳ@^>o@@C@5@4!@@RZ@?J?ͦ@x?_*>yl@fADd>ͳi?ב@鸾S@V!@)9@Z? 3@w@@T ?IY@@@9@vb@g@7@ ?1Qt@$6@5u@??@h?5O@;"@R;@ P>u?Noi z?=ts?m@y|>?P@(R?V>>@jX>B@@H@R@AZ#?@F?CMn@)%5?U@AU@CVJ@z@?>D@=? @?ff>U@bV@4@~%?a?[a?V@p2>W4?m ?G?]$?4-@@s&@P>mK@o1@K(@DI@o)@4VL>X ?{~?@N6[@#r?:c8?c?R>;?m,>{a@p@@Ek@?ҝ@U E:?U?>@)@@@@h@B@ӽ?@?H@@XR@H?Ŗ@?|@@?k7@4@gO@;??G@g>>?@I@)3@$+@~@~@#e6@^?'{Y?"/@F@??.+@p= w>O@E>w>@qU??t@(Oe@,=g@tg@@B@$@;@o@??]@Y6?um@@@?;@i@(z@? @%xu@~?V@@%@:@I@x?4 @>0@T@\@V?N>I@^k@&@ @ZI@@@@GRUP?@@A APAAABBB4BPBtBBBBCCC:CaCC@@@AA@AAABBB0BLBpBBBBCCC9C`CCDH@GMAG?o?w??^X?R +?Ze?]U?[|U?X?Z?]?]'?Z?K?K?JH?K5?Gۭ?FA?>8?= ?5?;z?7?V >{>ʸ>ݹ>pe>g>xf>>$>xC?`??e?aS?nQ?og?o?h ?]?Z?X{?V8 ?T`?QfJ?O?Ln2?I8?F?Fa?B?A?>-?;G?8=?7d?4]?35?1}?/z?-a?+?)?&?%/?"E?! ?A3?l?$?-]??w?j???'?? ]? ? ? k??w?5P?P5??>@>]>J>w>>C>$u><>>Ւ;>ti>&>$>>{4>t>fa>Um>P?Xd`??r?lN?m,?r?nwO?h?^?[Ϝ?X)?W>/?OE ?O?H?G,?BGh?A#Z?:ٜ?8?3?0?,?(͹?'?!?" ?\?V?eL?Dd?0Y?? g? ??4{??U>=>>6>C2>>Ȋ>=>k>yR>Z>ѥ>ͷ>ɘ,>#m>|E>.>>b>l>a>G>>q>x>>>E>~&1>T>&r.>G===(h=C$=%c.>>'>>>>㪲>᪮>U>>^>>>Ѳ>,>X>Ǜ>~C> >>>\>>>FV>~y>o'`>a>X2>QA>M#>Ey>:?Z!??rM?a#?mh?i?i0?[RW?[q?P)Z?N?GBX?DQ?9?6|?0VI?,/B?&??X?j? P??|>>> >У>ɣ5>'>]> q><>Ƨ>}>Ƣ>>>>>U>o>r>D>i>}&>lD>>p>}F->yf(>~> >Ht>>>>>>[>k>>6>/e>> >h>> E>;K>|hl>K}3>b> 5->w> ??X)??yO?|c?e.?]?P?.p?5!? ?>F>>>:>}>r>>+>=*>+>S?/]?١???%+?+q?- ?3^?2I?5k?:~?<>_?;?8 ?:R?1/?4I?-h?,0?"???U?r?~?h>>*p>8>[>&&> >·>>z>ӟJ>l>R>>y>s>İ>$|>ǯ>>o>q>>E>?s>b>7\J== ?d?y??o\?e&?Z,?Kd?:k ?%.?{>U,>>@>>>->> *>D>5>0>? ?K|?^v?$N ?+?0?2?6@?4?5s?3 L?.?)?"w??)? \>q>.>1>> >{x>>vA>h>j|>u9>>r>P>&>>ƻ>>s>w> >}>m>>o9>>>">pg>[~>>tk>E;>LF>?V>'ׇ>> -V??r6?-۾?\?2_?4?O> >J?E?J?t? p???2?$? [3? |=?q?>Ī>>|3>_>pW>c%>VP]>rq>L>`>f>4#>Ք6>\<>?>>>>] >Mg>%ǘ=o>oK>>e>Mfv>;,>f>h>xw>g>(>c>d`>^>H>A ?=R->=d=>V> H> >1=D0>n==-=mܘ=}=MD2=>T= L<>ۊU?O)?pI|?~+?Q??w;?qO?i?T?D7?654?&?^?gp? fE?e>>d>1>>F>@>V>>->o>>x[>a>;$ >>*==>u>>G>+>-Zu>"q>0>@Pq>7`f>(>><=څ=Ț=,==r=s=Z=Q(=ېj==>B>J>8>b=m=/==!4=#==SRR=h=N3p=9i?#?M?Xk?g?V_?BG?: ?L?/´??#?X~?B?Y|?n?C? wh?!??u?>`B>>l>>r?c>A>q>(>>f>p>bI? <>!>J6>]1>eD>>B>u> g>j>R>e>f>^><>>9>>>r>o>MV>lʈ>>t>xm>p> />O>*=2y==='=nZ="=I"O??o?Z? x>> >M5?A?+_?/@?>4> [>՚y>JN>??#>Y>W>M>a>d-> >r&>g>4>a>A>̩>>B>]> >>>F">{>g}>s>[>->a1>\:>;>v>̵>q>Xl>H߷>H>_5>M>>ɍ>>yw>=f(>$>1>G>]>g>\{>:&C>(>99>{==۰==r)A==6.?U ?:?"@?/b?/?a?6?wU??^2>>?62?L>A>2>?u>qJ>K>>߬>ѣ>t>>A>Ť>>_->>E>>C>SU>}>>s>n>y}>gg,>R">]#>hu>Q>PW>5>T>Cn> Z> q>C>< m> %=>*>1>.V=ү>==o=#=^=M =IU/=<^?4?U:H?@??SH?G>>4>?V>ߵ>`M> >u>$4>R>A>> B=È=:=h=*=b=&>==7U>=V=~.==Q===j==?\=5={=bm= =PK=ώ=Y==?o={=8=a=kU=O==re=c=Zk=S=I=L=A6T=*S=C<")>N>H><>>Ư>-o>w>>>1>>'>>>yd>b>_>a,|>SL>K>A>5d>&>3P>)>{> >q>>D>7=]g=e=+3=ٲ=i0=W;=ѿ=w==T====B=6=)===S{==@r<<7%<?zp?K6?5>7>>v>շ>v>M>B>U >c>Dž>ufu>}>VCw>^8>$.O>;8>>2> M=B>==Z==6S====oo=<(=]G=J={1=Q۸=fe=I3=w =VZ\=8==<6:=_=,V=2 =l=.g=`J>n_>p>>5>iT>:> >>>>=4>i>>ti>k)>>ZJp>\>C>(>!V>>)5>=}4=g!=k==W.==ϋ={=Ғ/={=(=Y==dq=?M=[;===ev=i=[=Y==L=G=O}=)Hg>D>>G>>J>j>>yk>t>TP>5BS>(@>ҥ>}=T==d=P=V=ӳw=t;=b=y=m=u=q =^d=Z=6n=8L=3=3g=+s1="f= +<|? E> )>g>>y=> >`>YZ>{>Y>`إ>B>,H>,ۗ=x==(N=פ=r==R)==Ŧ=Q==J=X<=x=0=7 =pg=E#=f0= =(]<O<0K=K<<=Nx=T=<Թ<%<ɝ<=[>)Q>&>>y>Va>NF>F>4d> 7> Q:>W=ؔ=*=z==k=cq=kJ===/=]l=4=U`='Ȟ<䣋=3Ė=? ??">>p>v> `>_I>n>ZF">8>> !:=xL>== M=_=)==R=w=m_=J=xհ="==}d>>V>r>>i>>Ai>7E> =>===>D>#=h >==ь>04=>Y>?(<`==YX=Bl=L>aAC=_<d<.<=><1=<=X=+B<`> -==|=>p>)=F=/>>ݫ>X=^=N= <=TXC=eH=f?:w>?|>)#?qT?:=.?M?>>Ƚ>?s=?e>$ؑ?'5=sU=q>?? MO>ñ=T\>h>2=- >a-)>D<>?JI>X> =L=ɟ>B >hyJ=F=Z1> =:">S={=Ru>L>:=批>)>>"0=>=r=n>>C>W=l> E=};=(==d>Q< =\=F~?z>7s>>w)?>8?%Q? Ԫ> ??!p>?X>>N?`3=? mK>;/?1=׽#>>Gϛ?'1? =1?*;>he >JQ>ٚ==q>c>*= >s>Xw=0>Qk>>=\x=9>ݗ>u,=u ==}n= >1>r=/>`KF=j=>>H r>>4ir>|>=ػ==W>2>>o>C=%>1==s/=ޗ=w>!=3l=g=އnyquist-3.05/lib/piano/att11025.pcm0000644000175000000620000002420410144436365015731 0ustar stevestaffi#gK?eO h`YT >SWXz=~ z ^EX6UJ\l_R uw* 2-`%f9un3 Lsg#2-Iw)| A s ,_p? |3(Wm`a ` ( ,  QWcj)mV)K}_v?X "  } X 4fN/[2N= -="-I| A7=*V\pI M"$KwUEs U;N7>M0kCAb!avϼ[`^d/e4TT,]Z8!m ="#%/!]%? g*@'$E ,Z1 ~Π{w݄l(#m3#{NjFMF&20(>Ϣ ݭݔ T8 !0+$L)(m*5&`EѥMɧ G < m_ #$*"ln l|O٥ոo]_|2l, ">6M-/V[Mod m @  t H"` r  6\Yݻrn=Z'd #^  $k?TS  tP >"f7'pI  w0 sFwR&vmTxJ<(U2[  P6kxtQ=+d91c @<pr53mmS? qI   o t .;/#%dGhDUCN?9quQX:gv/f0PrJO*2P xZ Hv $S/  R|$Q{*4 Hv2Y*EJ,   w E n_ T0Kg0 7 k } 1`)v#J44Gp_AwxhY8Ra#KfEk)M%Z}yqVe|i5<M)Cg*R67OTL~ V)t|z  o"&L-A?xh1/ Z < 1,`mUhD`\a5 . ='9ci:y';C[=|nKO\> bxgn/yv )Nof3Nl/ 8G1{qT9` Ky[|?.&W@>0U0JCK  9 7/uX{v#@ t#O ;oS8rhhGT3L5}@d> .#V. h 3`| )Pm$(In/Oyz]@8*fTAN#'3_q`t! 3 &RUMvO_+~?zk-1F[LJj+^%v"G],O1>F+tf`w#zk~C/qu@Mai8[X5M<3SP%6ZrC de' k }-$l<mHnH/4ShF<&z1CR BhI!JZryp93^Eag&E)>IA;`1Vvgzsjq{Nx w=Ew$D/X+w9lp[ 4KK0Gg2XAoT)l I9*jh&83:Ln1!QXKw?Hvk )`((2a/g-{dO~Y0iQu WPb(`/l'pg WDL_qxj4jJ}o%8E|=jh3aF["'bnqlRe/:N"5Yg`Xi%mJ3|w^4nf~;/HCqCoOs${.:^ w4p'2ekx/eS8*Z]Qn(LOn>|`5?7\z m!,#'  .},-}qJN 2 QXln`?+}o=885 >&d5q}#;\[/6i (he**{e)B]x\s5uAOp4QFI.%jyEiI%TCuGG2lT'J }/Rr}l q0m7C_>32dX3K;M<\-,TEpX$ P LTSiV^]90N> Ka zAv,0 qxFS>yE3 DGo! y9 Om~Sjs:OMP_@4Pe|Wi. #k,HM V2"*>aFr9~~orYCZOTxqd363I~&/EaQ@aZ?ysx9)U?wO}3$+9EuA VeLy 1.&#o4SLW215Ms ? `i\?v uhDIxh(9 QNje[c8'95"U\BjEd|}aQD&r(u^=*PZJGO_u "4!@K}BZTREPqT j$fHjPj;sb )r0_s`S}>D{Y<sb{yTat/),deYYyt~YceBW=L%TNFXPGI*%4;9PqgR* %QS+G/,t k}#<& 'rYLF4?uyjRkUf:L;GxeYH4T}H fgwbF@(zVB%FDN# 5$$?$*"*_|%&]MHXy1- 4 4  6,7UH*&G)# "+J #>,+E;;ABKV2YvaTZO tP-"#4-%3GH2(S6X19c;`4F.H * # ++ ::/7=:1>Z# 0jz"Z}]}h:DY7=GL   rY1rQ >uT( '!(:'B _D447(3"+ #.=J" &-EBX4:HMYBC.BYL2) +.-30D6>* <. % 1 94= .%  . / &%(31(178$<<JK$67"  ' $-I " '+$/!1! !$GF2,<DE\6 #!& & '&"+    .$ 1KX?A@989%  %0285&07J. 1) ,      .D@!!)-*        /'(!/F,3!'-  2%"0$  '" ( 64#%( ( .**'$!       nyquist-3.05/lib/piano/pn01.cod0000644000175000000620000003125010144436365015313 0ustar stevestaffSYNCCNDNCOMMB ?vV?}???0?f>DY>> ?oDz> Ē?>.?Dx?=Y+?N?N>>>>?(BS> >==v1z>?9?PD;?xh>w<**<c>ug>E>ȳ?<&}>>}>?-0>s>V>,s^>=><>z\h=>?LJ>2> =2Q?=>R>Tu>->w??+:==>C2=>>=b=q=>3LE?M>0=f=̈́>=>i =̮>d'>c'=x|=1?P=y?^>d]>Vv>Ԝ>=2=> >i>)> E=*=8M=Fo>FL=w =>,>j=>Q>N==m6> {=>&H?S>2g=P>==SՐ=&J<={7"<ގ>Jm=v> &>V>f=z=I>v?=C=1>{Pv=9݂=<~=>'c== >?1MA=^>>>T=>9=K2=#=L=ޑ==>\D> x{=U">R3>h>c=!=>=h===7=;>R=<> >N>2=ji=>=Ě= >4>!P=k">YL=2> b>b>>9>;ȧ>?[>Fn>?G>> I=lO===8====!===x)=E= =J>`=a=X===w8==ڜ=I=M==љ=G= =>=K==}=%)=h===0=٨= =7===$=t=R==*===uA=s='==E_==P=]==9=$=====B=|=+=6=N=u%==#l=$=>="=ө=$ ==;=h=h!==S==+'=n=,===n=]=b=.=}=X=Q=%=e= =|X=t=xp-=z=9B=x=xJ=u=r%=~'@=n=oZ=tv=tH\=sP=k^=k=i =m9=g=m=l=jB=nE=w6=nη=k =d=h@=h=dp=a{P=d=d{R=cH=d=av=bo=a=b=a=al=ap=]=]r=`e%=\J =XM=Y´=af=YXu=Q<=Th=WT=Sԑ=Uo=U{c=Tׂ=Z2=T`=T,=M=T=Rx^=S =MO=L=P=U4l=KU=PWH=Rt2=Mn=M =I=J=O=H=Jq=K{=GE=E=F=Gg=F=EQ=E=G=F|m=I=Ir}=@*z=Ce=D_=B =C=>b=?=?`=@a=<`===@=?J=A]C=>G=@f=C =>0==R=>w==}=;]=9=:=<=>r=0=9]=5^=8u=7=8=4=4{=3=5y=86=4M=0=4=2=3û=3=4O=7ˢ=45=0=0.=3u:=6I=87}=1=/u=2fM=Z=2T=,[=.e=-=0Xl=*F=+=1.=,A=1:*=+=-=,^=0K=.=D=/v=8J=(ٽ=,L='nB=+=1m=-{R=+*=.Q3=(=(=$H='`=%j='=$<=$nG=$&=!=(M=$M=!=&m='k==%~=#4=8QQ=9=!=$"="="_=(="=$=$]="q=$;= =Za=1== %9=D= cp=L== =T=4==\== ==M=F:=-="== Ҝ==-=t====MX=!F=_===U:=C=w={='=:=r=C==4=(G==13=Mb=&====G=@==Y=8=j=l=E{=0====='=i= =)=q= 8==_== f===խ= = N=)==J== ;= 1=g= V= "i=L=O= <<= = m-==m= = T= = )s=$= = = = SD= 9== =c= ߋ== 2= i|=K=>Z==O== Rq= 8=d==+==n=J=I=ZT=|==Ļ.6S?T?ӿ >]?l?՜?d@&@Kx?Jy?Hɾ@ d2@A0S??@*?A4=A_@@4ɉ@Tyf@:4?J?W>~3?SesDP/?M ?R2;2I=ÿxx?E=Qh@H`7'(@"k@DE?_E@Y@ >V@HGؗ@O@%ڿ[@ b _@Zif lF>>_-D?\?}>[Ҿΰ@Ъ?Q@I> /(@R?@2#VZ6I{g1z>c@N\@s@fS?Y3>?J@a"O@E@:]@R+P>+V%lL?J?OI֭?8 m " $?[@@ R@AX@b}?0@@L?XEw+{7@_EeQ?~3@f@Wo@iK@ d@9y?ӿfV?ʿ)ݣ??qu@0MB#@m[@ry@v#@ŝ>Y?&(zϿ@Y w@r@NjP\X?ؠ@PƘ+@ CP@W"@M?Oo?IP2@bYk>,?>Fd@h?'B>鸿? |w3濆?}>)= A?@C\\@N%e@vn?w ]?H?庿h-@x@k@F@m)>_?\?>w@̿؅ܓ@'?j@9_?С@!@@*p?8ց?fn? M ?}Lxz@6Ss?;C@3%?b@'@ \t?^p@ >O H@ g@/B@X@1@ m?MҘ@@k5@@!>,j@gFx'@`z@q@p @>T?3T>@5e=ٶ@?;@l5&?Y^B֝a?ѭ>@J@4P@G@gP@??Z@8P@Ni@cB~(?@ @dQ@.I?ɔ?@ ?dQ?O/@?? |@@0~@2m?A2<Z@(?_ :@x6k?N?a@f~e@U+@R3 _@UM?y@@;AC@LT?{S@ @}r)?@`" @Vu@ǖ@1a@v?@N@G@o@ >R&?٘y?||@I7@юP@*bҿBt?sМ5@8@`@R@r>@Jn@:@Dۿ??@R? S ~@Re@,3? @"B@=_@@ܵ@?@@8@$@Pk ?. (?@%H?[?yU??C׽@mg4K2@L>$@YI?7@^@@y@g?H@9@ݿ!+@@3JR@q@}@m@@ 8@d@)@NY?H-x@)D@O N@> <@@1R@@v?@7>f@R@Ϳ ޿O@K@Bty?N d?@,r?@D@/@4m@H?@>F?i >II@0H!,@#cy@G)?6|: y@@?+>L@@;>2Cw?uQ>?;3@ @Q,?{Y(q@[(@N.1@i0r<_?]t=:O@0?$n@?&@p?@Ga@$>I?c8A@N>R@e>P?@s?>_l@s~>W!?b?@@W|@ @@54@@ JO?T?_?<"8@@@@@GyU@YO@S)@Km@f_bh?A@@b@(??@c@@st?@ U ?/=??ٜ@@V@X@?Z@ZQ@Tq@?mM? @.>1@@?Ώ^?^@@C??Fݾ@y@bL@I@wL@8[@ )?>S1?A@B?:@"@ ?*q@i#@-c=@Uk=Vh @y?@@ @? @K@Uϧ@ ?`P@?V?.@eL?cS?l@d@n@?;IŁ@@J)@_s@7@!?$@eH@@@S@@?r?>"@`?#h@f@>TGRUP?@@A APAAAABBB0BLBpBBBBCCC?Cl@@@AA@ApAAAABB,BHBlBBBBCCC>CkDGMAG?~`M?N1 ?b??gc?QG|?_?^?[?\?`i?[ @?[?]U*?]w?\ۊ?_?[?Z|?W?Z?Xf?Xh?U[?U?SEk?T2?Rn?S?Q?Q ?N?R?N6?O?K1?L?JP?Kv?H=}?Ih?F:?Gz?E0?Eg?C!?D>?CS?El?B?C?ASV?A?>?@7?>?>zf?< ?=?<}B?=]?;|?:1?9՝?8?9"?8>?7$?5:?5\?5?5/;?3?,X?(4[?"@???Fz? ? ?>>nj>⛛>A?x-?qe?e~?yK??vs?c?]?RZ?RY&?E?D?;T?>W?8'?9m?2?5=?, ?+H?"K?"e~?iy?8*?XL??H?Ơ? +? '?(?1|??>> U>ȸ>b>M>\>>>ӗO>>C>N>Ǡ>>m>>>Z<>@>En>P9>>(>>U>>N>>U>\>O>ݞ>>\>5>>p>>o >s5>Z`>D >1>!>>ԗ=9g=/=k==~=?q4??yȈ?}?l.?T&?Rl?Sz?PI?G ?@5?>+;?;?;?8?6O?2?-O?)?%P?##?"? ?s??bO??‚?=?8??\? 2? ? ??e?>}>->>[>7>.>Y>N>{>19>ҭ>e>ˋ+>k>>7>k>U>>u>+>>E>]>J>S>;>>>#>>>>B>d>>uG>MB>7Uh>v>={=Ϡ={==| =e=V(=Eu?aKr?tC?v?tʼn?vI??}?w ?r?k0?e?b^?_xy?\>?Vp?T(?Q?MC?M;F?I0Q?I6 ?FyN?E?B?@)?>n?>>>Vp>Β>>>Ž>">l>Y>[>>x>wN>V>>>o>|>r)>]h>K;I>?>2>)9> U>>M0?D?9t??< ?I\E?bl?v???y)?ku?b?W?QP ?Hob?Ddp?>Ś?;?=f?@]??p1?@A?;?9v?1M?+8?(?'?)Z?)4?%@?"~? e???.??7?-? 3?E???pu>>V?2m>*>>H>>;>D> A>h>>u>٥l>؟3>>M>9>B>#>>Et>UL>(>>r>>>&>>>>X>>>S>od>Xc><,H>#g'>7===?}T ?d$?s.`?o2N??tl?|B?|ļ?l:?n ?hV6?c?e=?\?`?Xw,?`E?Re?Zs?F?G?C ?LP>g>M>ï>G}>>x>>s2+>V>7>$?= ?`K?<3?jD??E:?p)?a?m? u?xa?M?O2?B?CS?LA=??t?6?/)?P=?/X?#?;?=?8A? ?*?.h?7?ށ? ?<2?ZF?(? ?9Z?u?q?6?$??e? _?q?&q7>j?>9?>\@?^~?? AJ?U>s?E>? >U?od>?>$?ly>s> >L >U@?6>R*><>K?>K >'>pP>O>L>>0>i>>&t >/:=8>?W?N?Mx?T١?o?i^??r0p?zz?d,?b?N ?Km?S?PS?TV?D0?Jg?:t?9~~?/?*?)Z?#3o?+,V?(?.?,zf?-?.L?*?!?d??,?i[?d?t?.>1>??}?5p>P>>*>+>簟>0,>>!>>>>C0>ץe>>ȴ;>>T>_>G>͡->6>:>T>ԕ>߀>u>S>b>mP>;b>5K>>>8=W='=l?1t??[?G$? L? g? ?|>׵>}A?Ҝ>>?L?RL? >Ɛ>!=?s?? >>|>_5>މ>>>>?>gE>w>m3>4>`>Q9><>so>_>:>Q>UP>_{>I>>ew >56>->+D>!ʯ>#Hi>%>2z>J>0>h>*>nz>jm>/=E>(b>>>@=Y>d=K8=>?==\=Ԣ;=O=e=T=,=i#==TO=B@=CW?=AzR=== ?lY?m@?ot?sz?\B?Wf?Q?M5`?JV?C8?A???:E"?7c[?2Cx?/eW?-y?)?'?#?!+"? ??%???_? lu? ???>1>>e>>R>>:>W>l->ݑ>>d>>> >>Q>Ċ&>>>>I(>? >>>!>R>>J>sT`>Xs>:> 8>=`=6=Q=r=P=A3=|?&a?1?J?S3?WĢ?p?z=?}??uȓ?i?_8?V{?P@?Q'?K ?R#9?S?PC?D\?>.V?;V0?6?,W?$?"??%? 8?F??? ??)?r+? X?sr? ??ڈ>H>>l>>p>{>݀>o>\>>>>֠>>>D>:>F>i>O>>ª>>>'>>>>>r>i>>E>C>u>`>|*n>U>;x>Q>S[>u==I=]="=??x)?1?x ?/59?h?_?DzK??>0?:?[>-? ?}>?4k?";>?"?җ>ؘ?>yx>a? >f>K>e >0>> >[}>R+>p5>>`6>>W>>>6>\|> >~>4>o^>x>|'>Ӂ>>Y>V>S` >O>%4>X>t5q>zv>9>^>Q#>EZ|>!<>&>>>J#>c>a* >I6Q>*>> > (>%&> D=C==@===Pu=1Eh=+S??K??4d?*?$H?*v?" ??:?d?kA?>?\?Ku?>>Em>d>??"?P;>e>>R>->p>>@>k>>!>g>Ϟ>>`>+>n>:>8>>">>T>}>b>'>>>w>>{B>t>=>H>w>ہ>_V>->sO!>qn>wp>yo>t>[>J>]n>sB8>,A>%݇>"7>==j=/=@=,=_=X6G=(1V=!J??eJ?F?Jw?UXF?.T?,y?+??8??n>;> ?>x>ޒ>>.$> V>Y2>Z<>x>u>AL>χ>og>^>;>ם> >Rd>b>P>`>\>1>ws>bq>dC>zv>k>>4w>XJ>O>g>$u>E *>#F>>7#>?DX>_o>Һ>5Z>0M>"ľ>%^m> >Fn>p>8>=.>u>j>->+ۮ>"f>d>j> >Cr=l==2==v[=9L<;<Q>#c?,?&>v>6>d>~>>>@>>z>'>>>> ]>>A>>?>z>z>>>Tp>oQ>h>?z>+>/>7T>3>>= > 6> >B>1 >>((>#>>>B>!6>"w>>90>G>>>={=]=Tt=ϝL=֘4=jK==Ǫq=p=:9=Ŗ=$=O={=0==o[=p=ct= = = z<Q>>$>4n>r>>>D>/> >>c>*>tn>j>FL>Rȫ>L >O'>Da><>4>1A7>4>EI>Z>T>Q̱>F5>2>> Wu>=pz= -=N=r===c=h=Ӵn==U===Rz==1=K=p=އ=L)=%b=E=/=u=j׷=t=|=u!=v=PW=0=yu1=X9= =R)??y>>K>>>\>̯5>VB>P>>> >_E>t"}>v>K>k>>F>Rs>B~>|b>uH%>2>O+>dtA>:o>>9>/`> 5>>>|=>>&=/===#/==v*=L=?==9V=9=(==e===n==*=v=Q$=B=QVh>̫>>g3>>u_9>>>$>Q>f>~> >@>>>d>@> ɘ>'>>/y>.>">>t>"d >'m>->>,#>¸> Y>X_=_/=ɳw==>====2=ǒs=Z!=k=m===cH==|=q!=`&`=eu?=R=D)=Cz=M=M q=MH/=V_=W7A=;&>w>͐>m>r}>>c>Z>v!>[>G@>6Y]>1[>C>>>;6>>>E>9E>(h>.= ;>N=fu==*X=w=#=1=='=p=d+=f[s=@=Q+=2;=+=iG>=8=G%=K]=B=P=!d=Z==s<= <%==2D<̈_>\>1>HT> >Yr>pt>>v>@>2)>P >X >F>!>>t =K->>`=Js>cx==N=D=Y~>4ר=/=Q= ===6F= *=&=YB!=Bǧ>=2=JE='=?>4==Ld=Ǿ>-=a3=s<Ҭ=y/>%h=X'="c=_69=z=h=ׁ5<M?? C?$0>v?1>^>d>U>B? a>9>>?Dp>i> >x->+>E=$>=X>$>/=7>==6X=lB=q>>n=r>*c=4==I&=n>>=-=z>=*e=O> %0=c>6>Ww=>"S>==F>S=s=ը >1y==<=$UX<¥=[=?> =i:>:>i>7 =0"<==="==(= a<=<צA=<?t]? r4>??"q>>g>=Yi? 0? h?k1.>?N>=?6h?>?R2?8>g> =b> ~>4>G>* =c?#B=K>u?.>.B?!?=b6=>+'=:V> >y>l>zQ> >!=]=Y>~=a=T >v=űY>2>b/>WS? g> >w>>>.>=g>8`>'>(o>Mf}==zA^>&>H߉>>2Dx>0>>=.=^ ==>+>$=gN=dž=bg>9=D\P==`حnyquist-3.05/lib/piano/pn08.cod0000644000175000000620000003414410144436365015327 0ustar stevestaffSYNCCNDNCOMMC./;;PART~????????????>>Ν?My[? >?,>L=>ib>w?c?BA>k<>'[z> =E==Bɷ>Wj=)==<=QF>,=Q<+=<=-X=W=<<i9\??φ Lb @GC@5QZ@%~?譿?4UL2?m?@s@3@Ls@>6U?ԃ8? dl?|@ :L@=mw(%@*ĩ+?pGb?ŅY??ǩ@X=>A?ҴȿXҿ=ɖӿ=MJn?\@&@o4z@4@et ?@P@kd?@9G@T/i8@pv@|?͚n2/@MSc@=ʓ@i*A@?v?Dv@I7H@?r>&Z?KV=*?=I=@@@I??Do1@$k@E@@Km@-I?!>@ ??a@q@8 @U @@GRUP?@@@@@@@AAA A0A@APAA?@@@@@@@AAA A0A@ApABGMAG?3?As,?9JT?5?>D?LTn?h??z/?_C?M]k?Mp?\?g^?i?_z?J???>?Cr ?M&#?L?B?B"?K>?P?N'$?H?G?G3?8 ?.~?5?7?4k?3J?1V?1Ȅ?2?3?4?4u?2jF?0^?/K?0Y?0?,Yi?(In?(R?(n?(Xl?)^?'?'Z?(j?' ?(2?(/?%{?$o?%7?%L,?&?'?&@?#b?"?#?$kp?$W?#>?! ? ?? ?!I5?"Ri?![|?cH??g?g??_w?r?? ?y? `? (? m? ? ? ? #? ??W?[?)?p?8??>>E>m>>B>>hx>еT>)>>>EQ>>g>Z>P>->7>)>V>b>/>v[>>->!:>6>s>{>u>oR>j>d9>_>Z >UF>P%>Ks>F2>A>=e>8Ř>4I>0n>+f>'c>#>Bo>>u>C>g> > U>>====6==ޞ=i=Q=V==ĉT===t= "==F= =K==i===i==j=u===]=v=~@=S?R?kCe?{??xʕ?hA?Q?E>?4{?*Y?6*?II ?U?[?U[?U)?Y?Zv?T?K+?HL?ITe?I?J<?K e?OC?S?Pʙ?Pmh?V6?Zv?YE?U݌?R?QL?PB?O1?O_?O7Z?K ?IY?G?G`?G?H?IY ?G?FT?F?Dn?Bz?AH?AF??p{?> ?>A8><>u0>>>>>C >> >">>>/>>> >v>ܮ>->w>ؖh>{>դ0>&>">"#>/>+>+>>>>y >m#>a>W >M y>CB>:5>2>*>#.>>>> >=>==U=V=uc=ٯG=C5=_==¤===ZK=F==1=`===G===?g=5=A=@=N==N=/===2=)2==}Q=z=x=u=r=pe=mO=jy=g/=et=c88=_=]r=[p=X =Vt==TT=R =OA=NbT=K=I=F<=E1=C+=A7 =?z=\@>!??#=?,?8?.]?Jr?c^S?]?vy???s?`??P3?A?;?:I?Cp?H?L?EgS?9q?98?A#?J?N?Y$P?Zb?Ra%?MZ>?H~?F5?F?B?B?E?Dy?A߭?>W:??,?B?BP??o?=K?:R?;]?>?>y?;So?8?96j?8l?4+(?4)?5d?5+?3 ?3A?21q?3?2>?1K?2V?1*^?0\@?..?+~$?*m?*?+?(?'?%?$>q?!P?!o? N? ݂?G?Ў???5K?`??S?2?r?ʰ?I?!:?+?O?Yl?‚??Y? ? ? k8? # ? ??g?h?L?z? ?OY?Ƈ??RG?3?V>L/>TO>i >K>e>D>}y>f>$>I>k>%>ߕ>Їb>P><>0>vM>w>>>B>>wb>h>\>P>EН>;1>1D>'>u>T> >>w=E==\=ԏ==!=K=3=k=w=D=)A=va===={)=q=i=aɸ=X><=Qh=H=B Z=;X)=4=.i=(>= ==DO= [==?<`?q!H?n[?lZ?jpe?j ?jH?i9?g?g=?fT?f?d.?a?_h?_.B?^5?^QZ?]E?]?[?[5M?Y?X?XM?X?U?T?S0?Rb?Q?Pw?O7?O?N ?M ?K٤?KI?Ja1?JP?IK ?H?G"?G?GB3?GT?FH?EN?DcZ?C~_?By?B]?@?@??ű??,?>3?>E ?>s>; >C>Ƚ>Z>>$>8>, >B>;>>C>sP!>h/ >]>RZ>H=>@>7 >/s>'@> b>f>;> >Z>)=I===2W=SF=a"=;(=4=!=G=====rL==~=o3=b-=VP_=KF =>q=3y=)L=a=f= ,j=]rD>ϱ>>O>t>?W\?L?o?}1O?|F??t!H?sT|?z?|?t8?o?dЎ?Vz?T?R?O#?RR?R,?NoY?Ecz?>-N?9?9(?@S?Dd?G?@?:?2?)? đ?#x?%P?$i? 5??4???R?Ƌ?B?^P?V??y?? ~? Od? g? ? &? ?ʔ????i?U???>9>X>_m>a>X>I>dE>>b>)>q>d}>ܐ>Թ2>;>>> >4>>>K>>>>> >>>a>׀>>>u|>}>>>7>>>w>">x ~>uU?>nUH>k>fB>`I>_:>W>VOe>P>Qh>M->IW>DD >;1>6Le>=[m=u|g=91='J%=X}=/=xp==p=>DH> F>Qh>>y>C>>|>>e->2> > 1>===2=;=N=Z==/===Y=:B=W=;j===A=S=(=X=g==;9=*=yށ=s=hT=aK=W'=N"=D)==7=2}=-='L&= ==L=%=h?p?o= ?o?n!q?mF?kmu?iM?g?g-?eYW?c?a:?`X?^z?^f?]W?\ ?[?ZD?Y?Y?WH?Wq?U?VC?U?=#?;X?:>?98?8s?72?6!?5 ?4?2??2?16?1?0b?09Z?/?/$?.?.Y?-)?,Ԫ?+ ?&? ?.??CS? 2?Ơ>>>S>ͺ>r>A>2>m>>>D>>>,{>rYS>d>X>Kԗ>@O>4>*:~>'>f> ?>-==:^=&m=z=P=#=G=b=\='==x=f =SC =D=1=$.j=u=a=p?Ae????7?;?;Y?9?8?8P?7?6?6c?5#X?3vN?20?0p?-i?,?,I?+?*?);?(?'?%?#Z?"D?"?!S?!f? @???;?%?&?y>e>->*>n>]>>y;>>!>p>><>4>>>->>>m>U>>>>>>>v>G>[>->>zqi>oo>d>[ >Q]a>G>>>i>5. >,>#>>|> d>>=tu=s=?=Ρ={=@=)==O=0=b=A=c=b=z =r$=j=ct=\=U]=Po=J=F-=A=>o=;A6=9m=7=4=1=/=,l|=*g=)L=(='=%焔>\>p>=>_;>>2>>>=== B=J>5=>~>\>q>4>s> >a>#>>>3>]>? .? ;? .? W?ٷ?{3?????L?ζ? ;?v}???30?? 3? b?lA?>>>>>T> D>f>]>D>>>>>ܦ>U>>}%J>~>e>rvf>^>s$>[>}>n(>#>>r>`>>b>pF>>G>k>`>[>}>8>!>1>>$>c>C>">]>>U>g>>>o>2>>>>k>@>>U^>>>>>yYA>t\W>hc>ab>Ps>K>IE>I>=8>7[i>(zK=S!> >E>P>6b>x=b=o\==J=b=v'=<?Ph?3v*?7?/|a?12? ? ?\{??N? ?:?6c?=?Cg?B?G׏?F_?J“?JzV?VQ?YT?b?e?iu?h?f?e ?e~?qW?q ?p4 ?l?i?pV?rZ ?v?|Zh??~ ?|#?vW?x?uV?yUO?y ?{B?v?w<?uX?uK?q?r7?s?s?sK?n?s?ozk?vqX?s?tY?p?o?mQ?o?q?s a?r3?p|?p?ps?qX?s?q?q?po?p?r?v{?y?{ b?yG ?w?t?y?w72?|E?x?|U?trX?s?nP?p?n#?mtO?j)?f?c0?`-?`]?]D?]O}?Zz?X?T?V ?T{?V?T_?VQ?Sz?Te?SE?T?U{?W?Y~)?X ?X?XaE?Y??Xb?Z?[&?Yq?Y~?U ?U?JW?A?6u-?+}?*?!?T? ?-U?/>X>>3y>;F>>!\>8>e>>7>w:>l>]Q>M >?)h>1>>&Z>>%>>A==%=A==Ɔ=η==Kf===r=D=5=G=N=e= ={==B==a='==U_= =[=] =’=S==+t====P===@=/=$E==c~=k=&E=*==f=?={==W==="=Ā=բ=l=?u???}?qg?dc+?T7?F?> E??C?9S?4: ?:]}?>E?5@?/-?-?2x?6]?>?>+?B ?@k'?E\?F4?E ?>+>>?Q>ڤ>Q>>Ӵ >0>>~>>_a>L???"?`?kv?>'>1>r>>w> >֏d>ҿ|>>>DE>X#>ُ>,>6l>>>>u>>>>">t/>->I>)%>+>>b>>W>>><>W>O>H>>>>>c>W>>}>>}>zGZ>tF,>p>pa>n>w'>z$>HE>>&>L>f>M>y>k>>Y>B>>_Y><>V>@d>>|%>I>]&>`ƾ>0<>/ >:j>>->x>=\=·= =]=it=@=܊==W=c=~=P= ==h~=Pt=J=BK=6=1!=%+=PT=9=y=B=== 7=v&?7?8?8=?6C?5 ?3?5[e?.~?+O?%h?& ?s??O?.?d3?a6?QG???[`?/??o?i???mQ?g?Kh?;??ҹ?,?%? ? 8?8?S??Ю?>۝>$>>So>7>>0>>b>2a>>4>I>>q>S>>_>>]p>]R>ہ5>X>65>> p>>Q>>A >;>ܚ>->ކ>c> X>E>>a>J>>Q>,>>D >ٔF>>%>Ӑ>>f>X>z>Pr>ȋ>Y>p>R>v>;>^>>j>>`>|>kM>R>Lm>?>9l>4y>/>)*>>>%=8=ڹQ==p=v=n*=h=M==:====v`=n_C=v\=h=p=x=k?9=p=b=]C=Q]=LA=Q=N&=L=Xx=PBA=Nh=P=G=J=H==B\=E^=4b=0=4=,]=7nI=5ڵ=1<=3E=*w=$%N===O==:o=d= = D=ke<<.wT>p>>tU>>մ>b>z#>>>dH>>F[>>N>砆>V>">O>e3>2m>ԜZ>`>ϋN>>os>>ˆ>>ͮ>Ϸ>:(>{>}>>h>,>D>+>>P>;%>nv>`$>T^>M>@>9%>0>+>m>>>~>{><=R==J=l=c=-=F~=ɆN=U=F=a=:=k=w=b===;=Ȳ=o=uT=]=a==LI=O6=<=?=1z=2='=&^= =1=i@=kC=$5= 8=\= = c=_=\<=?(A?b@?yV??wO?\Gd?4R?4>TT>V> ?F?8O?V?g?^?N?,4=?L>2>ɀ ?^3?:?_Z?b?\s?:?>> >l? ?/3?E?LjM??Vp?">> y>}>>? ??% ?"+?>E>>_>>u>ِ??? ?? e;>)>z>t>nv>W>>>>,>>Z>>>>_>hE>>\>>^{>5>}>/>h7>SG,>ib>Z>4!>#>T>+>()>du>8>>7>0>Z=>s>N> >ؑ>u>Z8>;9> B>! <>'dY>Boh>Ri>`>^_>SL>@>,Gq>>">)p>A>N(>>C>D}o>-b> > >I>>K>>(I>9M>>>F>>=M=G="?==ދ=mE=g=l =Q&=V=K1l=Qv=8===%?L?F?Hð?L?.?fg?.5?WI?"Gn?5?Q?=?!?O? ?C^>?7T> ?Ӄ???B ?Q?? "?@>?d>UF? >8?>A? >>>|a>Z>mR>$>O>U>>}>й>K>>ѹZ>\>|>$>~Y><>%>Nc> >>H>>w>T> >F> D>>$)>p>9>Y>X+>>>>>ZH>K>>>->p>l >>zp>W>>K>>6>w}h>>}9>d>?c>V> o>o,>>aH>'>cms>y>%f>C>v>f!>Wj>ms>r.>p|>Y7>"(L>=M>%=> H>Y|=K_=S=r~==g===a`=YmX='9="=b`=v=fK=T]=_d=O =K͇=M=@=.=>`=:2=:x=9==$y!=' =#==9= = =#== {=?:O?8?/?-%?) ?%>?!0? l??-0?'?\??A?0?T{? P?. ?+>>>>>m>@>t<>ݜK>ݙ>O>>>f>ʖF>>H*>sj>@>>>W>>,>>G>D>>@>y>h>P{>>8>>G>>>)>z>}p1>~+>j>sr>i >sx>b>bG0>YR2>_b>>`W>S&>Uڀ>OZ>Rb;>PU>L{>F>C>E҉>?~?>;ۇ>83v>8QS>3||>/͢>(p>-{>*A>*>!C,>z>>>{>rm>>>wm>>>>Op>b>2>>έ>W>!> d>>^$>;>> 2>5>xO>@>L=D=}=GG=v= ==r=lP=[=T=xJ/=kgJ=^=X=F=?F=2M=1=%U=$ =J=~===y= bn==<뒑<#B<=ݳw>_?Z%?`Qw>5>^?WQ>+?.>HP??8f>E>1|?i?4n>?!#B?)??1>p>XH>%>=?-%?r>#>Wg>:>>>=>>$>?V T?¿?F>4>=D(>ϭ=_>v?U>\L>>gG>\/? >̹=P=P>V?4>Ĭ>)>!=^>DE=b=(0F=ok =t?bp>>?HCT>>h=t>,m>*-*>^O=f̕>*U,=-=3=]>1?,>i=>c >>>=ќ=VF>=+A<^Z=e7 = \=G=Vx=ev===K>aŌ=t7>>kޥ=s=n=>}>>d?+i==p=Ͱ=X>-=8(=l+=/=k>L}=ғ=T? >s>>U'>H?=ER>Og#=,=Q=~(===1=h>@ > =V>3߄=s,=}=s3@=I>SrB>>>?ǣ=>^2>>g{>qS>t>E?>\>*&=ԇ>}=w=ۊ> YJ= > Xf==ݴ>{">T>#m= +>,=ݤh=~T>=`=_5=G*==ֱ="=[=:2>Z=Ďo==ȗf=c===6{= =/===M=Z= = =3%=#=8== =/=C=}=f=="7==A1=(6==Vo=(==H==d===;=(=L===z====={=(=-===}#=j=fI=ʽ=s=}`={m=~=z==wU=x9=y=w=x=w=r=y=w =y=wX=v=tf=v@=uM=q=v4=o=o=lz=f{=n }=kj=oz7=mj=n"=l=h=pt=gt=fP=f-=gE=bڱ=g:=b=b=_=_@=`4>=[B=]0=_=` =_A=Z=Z=\O=Zc=^L=Z[=Z=^=[r2=UE=Wy=T_=QS=Y+=V<=[B=WF>=TĜ=ZY=UF=Qե=UV=Me=TK=U=T=Ne=Q5=Oy=Q7o=OX=Nax=O=Ne=Kgg=RPW=JQ=Ml=N|=N+=G#=H 5=I+=E=Ew=G=G=E$=L@U=K=G=D'c=H˃=JS=Gڗ=B n=@2=DF=F =CT=Y=Glm=@~=GG=E=D&=C_=Gm=C]=Dy=B#=B=@ =@l=@=Ci==[=@I"=?&8=:A=;ٴ=0=8=:\=<=4Ѿ==@=7=:==L=7=;d%=4í=8+=79=8r=65=2~=8$=;I=7=7=6$=3Da=1z=:=:=6 =5m=8B=4=6=3=0=4s=6,=4=6=3W=5=/`=3=~=5=3S=2tW=1i{=6 =.=0=, =1=3=1##=7+=2=2=3u=3=*A=09;=20=/=-=/l=-=2f@=/E=.=0=0Ϩ=5+=1=3=,N=4]|=-N}=0:1=0V=.=,'9=/=/?=3ܕ=/=.=-0=0*m=,[=/m=,Z=0=/#=/=1 =/( =.=2=/=0|t=-J=*b=,=+U=,!6=/=.=,`=.y=/=-Gv=,y=,z>>ս=:s1L@<$?Pg֧y@. {?9=#?.>Hm ?g@ ԿL!?S$)?q9@ C?yN@P? @?o ?l =>zҿ?x>i>ֿQB^>F%<-SQ@g?A_m@[aS?ܼ@m(@)9@Au̿>&?ۧʤ?ٿcyۂ>f??K>h >zI??P,* @5@?h@j@ED?7@6?T9?).@a&@TU8!ؽ@ Yї@|q@#V'@f? ?ː>@@ǐ? @qZ@J&?@Y@Ql?b~D@1吿g@r ֈ@*4(s2@E5H@#@3 {}?tU?Ta@m\>;=M>R?@xҿ@@R]F@f]@Rg;>1l>@1>UO'@QCk@B "@ u[u@B?߶@~@#@?Z@ 뿟nS@?]?m@X6x@{=ȿl?F`@A@v@4Q&@y@eK@q=?(G"@BWw@c=@Ê@a@&M=c{?g? 0w?gc> ]@m?@=3 ?m@&@e(@+v?!@>6M^@?cQ3@@_@%?A?߉@>K?r}@@𿋈CQ>?{@(mǿZ@}>@h V?t@)<@vv3@@` @ ᘿp}>ڋgaX@t@ig'?L“UC??V]u˾j@#"E@Jb@o@Q@!@+?j@`d.>DḊ< ?Ž>x-@<.=b?c@m=@>CM@`*>>@_@!H>+Oc@1?Ϊ@@>W31@l@ƃ@ֽ7@>@˽?k?D@?h ?I@"?f@b?s_= @qX?y@ x@]@)R@n.d@@e۶&@d@d@E Lt@@E@7N?V@n4?~@aʘ@;@@{N@(ܤ@/2z@Sh&@fE@?f9@mRn@3?0` @KI@)~v?F?+2Rs?vT@?@e4?0A@ 3@ſ @@@<|%\Y@{_@ÿ6=@c~@.>e@D@+@ x@6@ RE@T@b@@[g@#@@#6z?|%@(?ݸ@t*?@H;xX@@4@@G~@d?@#@>Ԟ@ @+@}ݎ?OV@nW@@(?@:>Q@2@X:;ve@>K ]@^n>Y @Jd@W@xB@t@@ EG@@+>QU?@kM@ r@߆?f>,?]@N?N@N@H@<@vO>!??"@!@XO??\Ax@|?Ib ?4<@J]@s>@I@H@?qL?u1}?e@k@->@@~t@T?E@3f?A@F@DѺ@o#?@*%@y?m@?g@(@# ?@j?F @@$?p@f@0??@Q@~GRUP?@@A APAAAAAB B B<BXB|BBBBCC;@@@AA@ApAAAABBB8BTBxBBBBCC:CGMAG?GL0??zƩ?w?p?c?^?`C?^?[Q?Y f?X?N?E,?Br?@Kc?>=?;?:!0?89?5K?3oN?1?/R?,?*8?(?'tz?&D+?%@2?$&?"ѿ?!???v<>^>=~>>>`T>9>o>)B> >y>>#>ݜK>۪>2>HI>Ԣ>7r>&>~>ɣ>Ǻ>B>>>7>9>Q>2>!>w>O>k>S>9>*L>Q>=&== =[="==O==M??h(?Q ?Q/?8??(C^??p?C ?=M?B?C̠?Gy?H?Ot?RD?P?Q ?R R?O ?N?NI?N 1?K?L!X?IV?H?E?D(?CV?AF?@#:?=?;?:&?8?6C?5 ?47?2Z?0?/?-?,K?*z?)e?'?%B?$B#?"T?!n?O?n*?eP?J??sN?*???[??Hc?- ?4? _? Z? ? ?)?i??H?RZ??f?h> >r>$>\>>R>><>>A>>K>d>s!>a>Q>DF>6>*U>i>@>Tv=??`M[??r?nB?w?sA?d%:?cߣ?]?T[?SO%?Ji?LG$?HU?FĮ?A1?DN?Aݔ?Ea?A.?A0?@a?>3??;5?:?9Y?9Y?7?8?6?8s?6c?7?6 E?7"K?4?5?1?3@@?0?/?,{?,?)O?*[?(?(?&I?&?$C?%W?"?#{)? ? ]?J????K????y??K/?d??B?ʐ???1?u?=? ?? c? ? ?>0>Y>^l>V>'>E>>HY>$j>>v>b>Q5>E>5>>(H>Z?eF?s?@?]?cZ?mO?rq?y ?tu?y[?w?zG?}4??~?zƅ?|BD?w?y1?x=?x`?wo?v(?u?rl?s90?nP1?mxN?ib?g?f/?cu?c.?`*?`,?]n$?]y?[5]?Z?Xd?XA?UF?T?RH.?Q?O?Oku?L-?L?I?Hk?F?De?DF/?Bw8?BW??q???=?>D>>7?>U>ϐ>>>>Q6>Y>yc>k+>`h>Y^?H~?uab?`?_n?t??x,?nX?j?bF?[u,?N#?B?7?2>?5f+?<?@\J?CT?@m~?=X?4N?-,?"Tc?>o??O??W???LO?7g? ?qL>6>>=>7>>/>y>>>> %>f>ˬ>>'>>ĹS>Nj">͈>ϭ>]>d>>G>>g>>X?>c>`> >><^>?>>> > >|>>~>:>>>H->n><>><>kL)>St>5M>\>w==3=d==qZ==fa==T===??Xy?<Գ?)o?F]?F ?A !?C3?%?&F?+?*C?3S?'H%?/n??'*?!E?'?&?"r? j?+J?N"??J ?z?/?&?)? ?m? ,???? ~? w?? ? ??I ??yO?B?Vx?}r??/>?> >>%?s>^?>A>G>>ͪ>ă>]>$}>7>$>>>棋>%>߬[>ɏ>3>j">|>X>!>>>qZ>>ݿ>>>>%>@$>:>=!>xȹ>n%>`>Y>K>Dn|>?&Z>2>(>>?gU? W?? -{?.D?-07?k#?CO?.E ?g?)?[E?J'?2? m?24?Vd?G ?%?GU?X??r?= ?7?2'??W?7m+?/?39?}$??ñ?+??5%?-ʩ?z?)]_?.?f'? ?~,?n?!m?Z?+?? R? v?&Z?&&?-? ԁ? ?X???p?->?%z??1A?>E>>?U?t?9>>_>5 >cn> >!>A>0>z>ԁ>ne+>K>~_>O5Q>>9i>,$l>=3==?}?GL?_"?7?!??0q?q$>Gl?p3?>x?g+?i?0G?Zc?2" ?NP?ʁ?ed??O?U?O=?Y?4?'A?)?3N?8!?CA? ԣ?N4O>Ъ/?DY\?$?DbD?9?)?#? ?(>u?C>' ???>}??K 4>F?1U>?'?ڬ?!?%>?5>˺s?5 >Ex?2>x? +O>G6??is>*y?qg>?>?$">f?>? >ĄB> #>‰>1>y>6>߽0>\>>U>q>4>4>E>'>R/>>Ƚ>N>dF=lA>(/H>F>c>T? y>>8>\>6[>D>G.>>>ڮ7>>> >V>պ>u>|>|>p>2>>a>l@>">{>R>dž->>ڢ@>>>!w>j>v>>R>>>>zch>e>]Q>Cʝ>;9>4>y>4x >?!>=>M>\z>O>A& >PXj>J>#a>"Mg> > >+g>> >>^>/J>C{7>J>Vd>S>^1>#~6=۟l=a= =fe=ʵ=So===Y=o=g==Ez= y=?.=.2=0ϔ?mq8??w ?g?n?Nҟ?g`?I^?Hh?D?((?3%??)?!8? z?>K?-?YA?S?_?kz?Nm?t-?A?gG?I?K$o?IS?v?E?  ?5???V>C?>֤? $>>ꓒ>>Y>?>>{>Ў>?$>N?ՠ>??/>d ?A>̎?4?> V? >>~> >7>>>C7>C>9>¼> >^>>߈>4>x>y>>M>g>6>g>x>7>a,>m>;>G>G>=d>===4==Z= =?v*?z?k؄?b?_OR?|3?j]U?w>>?rv?v??x?y?s?f9?hV?P?>?D>?,?/=?i?eD?"l???&j? "?,V?!r,?W?CO?? ?>u>>{>C >>>&>ӕ>d>&>v>>>AL>#>Ț>5>:>>$#>>1>o> >> >>U>u>>>>ie>.1>K'>>w[>i>1l>~!>>=S>>T>U>y>:>W>`G>8e>z_>V=2=i=u====:=Q=G_=B=2*<<ʼ?\݆???~U?}?y#?k?cU?bUU?^(?[?`4?c?i``?m(?b?T?H?>_>ª6>>>>Z>@>Ϸ>L">y><3>y'>ڋ>>g>r>H>I>>*>t>>H#>>>˲>>{>>{>o>Q>G >LN>Y>h>>>ʥ>6>>y>sAm>b"F>J!L>5>3>R[>I=+>*R={=e=y==p=T=7u=\d=t̜<=4xd=:< =??)ϼ??*?%?@? ??M?9#??!?">O>?>=>Ӵ>?>J>>j >>>=|>>>>4>'><>>U>ȳ>ɏ>E|>>>t >>?>kZ>҉>z>>>>jX>e'>I#l>@>O>kN>)>j>>~ã>iȄ>Kd >7 2>,>G>C{>e>mj>r>eU>G >E_>?o.>>&>1ի>4Z>;> =}=‡====qE=d=f+k=BGi=?%F=4*<<פ<-<<^I?kt??- ?ER?? ?!?#}?!? >2>W>iN>?-;??>>9>>.8>c>Tu>9>G>>o>>>'>7>X>s>!>!>P>k>>)>81>>>>"Y>Ĭ>>>>D>;>j>>r>i>`>y>}>>{h> >[>d>U>å>t!}>lZ>`>XC>Q>E>A>3>,>)K+>4.>6u><0>A`>23>7/>4_>A>r>A'=1~====@m=Y=iq= <<9A>>J-> 5>ƹ>k>>D>A>>>n>]>U>>">H> >J>>b>T>I&>">$Vn>Dv>T-I>^)>kߢ>U>.>S>O>'> r>X*>.>C >Go>W|>J >/>.> ===>>C>c>#> =$.==i=N==D}==T==Pj=s=d= =L= -==:?=~=K7x=D<9M;;^;b;4;,7:j??DK?9?C?53?% ?#?'Ʈ?>!>?2?>휜>>M>_v>>VL>q>g>y>&>>X>a>%>Zl>>X>->D^>X>]K:>d>v>t~>Rr>>U;>_H>V>> 0>9g>>1>?>U(>FZ>-=i9==H=k>u>>:B> =)=.=F=_======9=b="=d=V=Z*==p=;=/=/===Sy=-y=t<0<<<<pݰ^?b??>?u>,>^>ҍ1>k> >6>k^>>|\>vC>xT>>a%>mQ>Z>v$>w >mŊ>i>(>/>A>2>={>1=a=$Y=>H> 0> R|=p=~= ==W><=܋==H=Hs=G==o=x=ti =a$=wp=}=rY=XX=e=b.=e%=q==|===k=.e=@h=C{=i6T=.=0=.m=IbH=-O'=B_=9^=!tZ?_>>%>=>{>#>>J>>l>{>_wp>V>X=>R~>]JI>K>KK>Cm>;>3F >?>q>l=-={6=αV=%==t=܅===޶=,=*L=e=ܙ=;h=r=S==)=o=6=t====pȴ=j=s?=]=S=I=E= >> >P>>#>[>qa>Vz>Nw>J<>7S>>>>> O>5q=x=崚==>=Ը=ە=t=B=ox=I=N =j =YU=*t=.===])=>R==s=u==b0=,=#;L;j;U;6;Ԧ.<3<3t;;ܶ@;;;);??v[?nP?R,?)?(S>>ס|>ӻ> >l>!>eW}>ˏ>v>5>>7>Z>+j>y4T>(9>/k>(>[1>!̪>]f>F>hp>K=o<=݌>'S=P=6={< =,?=1zn=y =)AC>/?f>"2===5>=ZO>-{=C>=<> b=}mK=3T= gi>=$=G=82>R=}=<ҵ> =*?==*==]%=<=7=8=8bc>0??XV?#?sl>n>>>lY>r* >#>ŭ?6_?>>/}>1J? b=j>r{>ڤ>c>}}=+?d>|a>Ά>A>Ɉ2>=с>{>E=?>>*2=Zh>1g===m'>r>7>$6j>7]=y>=ms>">W>>f@=>-O==q=^>>pC>+=>r>1G= =G| =(5=|>_>|=f>,`=Y>4<>#/>5x=>V]>[==$k=>Z=!;==s U=E=X=6==g/?"?4N?>?M^? 3>r?1?.t? >>vt?,Δ>G>T(j>2?Vj>=h.=9=i>5y>or==ǐ>ib==J N=@==CU<l@"ͺ?HJ5@O@s9@ ˿R&?~?%/B@ -PK?ˆ?학@@%ӿ? )@K7k$r@DX@/""@K;>n[>>?P?^rƿU@Wz@4@'v><@ \=8A?? VϿ۶J@8@mzҿ.w?m(>NJ@EJQ?D h~??F?!@(?I_@5'c@g@F@ 5@%s@M`-@Zq@6R@z?\fH*[^>??A@gq@mO@@{|@d"?}H@hJO@y\@)@R?|@&@bX? ?dj@o?F?;=<@UU@D??ޠ?r@EEf?\*??뾊@'J>5? "k;V?@2~)?!Q? %@?%7?1q}@? @B@9@!@3@0>} `u?&->6@`?*?>!?0QZ?nkG@}o?@V g"f@C?@$"@_i?b@u>8Ⱦ@K?^#=)@-@ms@%\?@;P@Wd@@a!>@~?@]e?v??E?E@s?ɇ@1I@0@}@z@Up?t?@'t>~GRUP?@@@@@@@AA A0A@APAAAAA?@@@@@@AAA A0A@ApAAAACHGMAG?n$?w!?~(y??П?sO+?S(?>L>G>>>ܠ>->$>A>Z>>z>R>c>>4>.>q>uK>U{>Х>ɼ>7>0>T->0>_>.w>>>>D>\>{>oZ1>e>ZI>Qx>GX+>=>5>+D>#U>j>g> >p=h=ci==&=t=AV=IU=US===|ث=l{=^Ť=R=E=?3=6vH=4P=1=1T=3=5=8=>X?D1?2?-??m]??Z]?;?QVW?lg?_{b?n!?w]?fX??[?h^?d{?PW?F?<1?<9??,??P?,-,??h??? 9? :H?? ???>d>'>F>xi>Y>>A>%>f>3>yW>%><>:>>>6M>U>d>+>m>m >> >3=>j>k>zI>>%>q_>|>ڧ>Z?>]c>>>>>o>SG>G>r>t>+\>> >;>l>>*>K'>m>PY>E>h>؟>.>H>1\>v>O >>a3>)>> >,>p>>\I>@>>}y>zo>y>wI>tx>ts>qL>a>N^>>>+>3>F>==ݍ=˞==.=}==<=q9=m=b!=S=J==k=5=2=$6=!7=)f==HN=q=dJ<8=7?z?.ka?[(;?a2)?c1?kT?p"o?l?fAN?kp?t'?{?~F??~6?|?}%?}?{ F?v %?s?t]?s?q!?o?m?k`Q?kj?i:?fZ?c?b?a?_?]?\?\/?ZY?X?W4L?VG=?U?R?Pq?Oe6?NZ?M7?K?I?H>[?Fߺ?F&$?D ?C?BW?@???>}?=??/?\?E?r?e?@?+9?? ? ? ? d? +?Z@?E?6?1???5?>%>8>> 9>=>>g>R~>s>Kz>$'=m==o =(=6X===<0>>/?P>Fx>\`j>p`>>*i>i>#>_ >>ô>>\m>->4>d>~>)>W>~f>ZZ>7>W>s~>'>Z>>>E> >>>F>>=>vD^?\?qd?7X>> >Г?]?.?6l?+^?>?RQ?GW?F?V?[!?nڬ?uM?fR?g ??uY?}&?p?qf?m?u?o$@?r?n?y?p?p?`?d9?Y ?^r?OD?T3?LX?R,?L@?NH?E|?L?F?I?Ai?FM?;"?C?8+?<"?2?6`?-?2+?,t,?.V?+?-W?*?,?%З?)pe?!΢?'F??"?=V??W??RA?ѡ??R??y? {?q?? [n?ی?A?q?>6k?(> z>X> >̩>>z>H>83>R>๭>O>ڷ>>W>x>̉2>>> >MN>>ό>k>'>f>>>Y>>>q>Ef>n=%=>,#2>EA>\>s|>)>~>k>&>">b>k>7>u>K>aJ>x>==>M>.>>>>~>>>6>~>s>e>W[>J>9y>+d>`> =#==.u=G=vE=;?s?kY?6?CX?|??[x?b@X?]?P O?Ts?S?Qv?a?dS?^ ]?W?Ms?C?Npb?SN?Pb?P?M?EQ ?E?GK?G?F+?G ?F?A}?=?=EM?:p?:,?::?;?7?7w?3W?2};?-!?/?,i?+X?)?)i?'Ҿ?'?%8?$k?!&? ?.?M??{?T?|L?B?f???8? m? m? ? ?,?/???$?>>>g>)>^>l>>>>K>e>>Qx>>>>>2;>+>ʃ`>Vw>Y>>%>>>5H>[>>l>>gP>!>_;>>e>װ>>O>>V>LK> >eǝ>2g>>==Qx<=>==t>{P> >6:,>J >]>lY>{[>>,>[>>>?>>p>7>>>V>>>v>l>bmv>V>K6>>7>0M>%>> n===^=ǜ==n=Ӆ=WAp=+wO=(<?6>Br>>>?>>>>=>D>2>SU>Li>(>꾀>")>!>ީ+>X8>>b>@S>>@t>ZR>ڍ>>,>ل>T[>*>Ԓ>[l>l>u>2>!$>˨d>@>R>>ma>Ê>ъ>|l>d>4>y?>V>>>>E>k>.>e>i>ZI>;>z`>1>h>>Q> >Z>]>΅>>>p>>V>P&>8>2>4>>|>R>8Z> &>=&=J-= =RF=S&===ȣ=|>l>$D>4V>EV#>R6>]U>h+b>pm>v>yѥ>Mv>5>>7$>E>S>_>>}>yjm>s>l>b>YZ >Me>A>5>(L>> ={=)=KF==|> =?ۜ=n<<|<??v=?oՔ?qu2?iJ?_o?Ro@?N?Q#?TfR?R?M ?DR?;?6?4?6+?4B?/?)?&?"g??A?S0?\?+?? 8? n?z?KA?>>آ>@>)>c>>%>>>>Y>>Ê>w>=>>4W>\>lA>>t>9>>J>->|>+J>>>>>>y>V>,>>1K>b> >L>>>V>b>>=>!>b>!>|>z>w=>u>sy>sT>s_U>qV>o >m>m#>>l >kBE>iV>g>g>g>f>d>c>aݺ>a>_)>]ʩ>[̠>Z >XA>W=>U>T>R$>QЏ>Ov>N>> >,>X>=c=; ==u=u=`W=S]=Kα=L=V׳=j=|=<==#<=!S=."=P=Y=g=M=^=|7=rxN=j=bD=^=]=^%=[=SWW=J=>5=2=,y=)G=&=#F="==j=w=d=0|= :=>>Z>>ɨ>A>>E>>1 >m> i>>T>G>>;>WD>s>É>ۡ>[>0]>4>ΐ>gW>> :>>z>>[>M>X>}?>q>nb>n%>i>c6>i,>gO>fF>^d>eR>^>h6>f|>dhd>[P>` >_>\p>]Rb>an>a{>]Z>^L>S>P>Q>H >AǮ>;>;*B>4>/$>&>#D>">2">ː>(*>c>> > >jN>G>)=EE=[=Ǥ> ==p===*=U=$=$====q=dK>=>i>>>3>>>}>>s>>|>>i=l== i=l=o=q=n=><;<׷=&T=8m{=.=!J=$= 1=6== Yf<<=<8zM>C>>>E>!>m>t>'>N>>_>J>Ϣ>I>>B|>{>(>>(>%>>p>H>>>4>0>>>>>>Lz>H>>)>>W7>>$R>>z8>r>4>>~>}>w[>v">q\>n?>j=:>f^ >c>`!>^>Y>Yu>Uy>Ti>PB>Nyu>K>H7>F>D5:>AN^>>( ><->:,>8>7>%O>>:=E=^==M==h-=B$=ë=-v<ݠ]<\<s<Ӳ<{Q>.>>j>>[>j>Q>>8>?>>>P>@>">E]>[>>=3>"->(>y>1>K>A>ʄ>֔>o>F>Q>ѻG>Q>o>΍>,>>a>>I>>ְ>Ɨ>_>Ek>”> >f>><>ŝR>Ī>S>>&q>×>5>&>5>>'>#>mI>> >M]>>P>s>LM>4q>)w4>=T=j==΍===_k=w4=S4=`.=u==S=E=/ =)=|$=B=P=f===0=c==,=#=V=v=G=<= =====A===[=K====E>t?z?dP?X?:S?cK?k7W??jU~?^m?~`{?QRp?Y)P?O ?W?U ?RW?[\?^?VN?]Y?SɊ?M[?K ?D?AK?.)?4 ?*?--?'Ad?%-?"L?"PZ? 4?1?M>`4>kM>>,/>s>V>״E>>6>@ >; >}a>AQ>>>)>>> >^>9>bN>L>>>>>i>-1> >y>\>h[>}!>`}>v<>Z>kV`>[ >X>z>X>L.>UY>E#>R&h>C*>II>B >Fx>>}>>Hl>?ad>3>8z>+F>4> >0>+>(>j>"y>0>*>C>Pf>=>b> U>@>>>>>>t=/P=沠==Y=P=Dq=(====#=Y=P\=A=~h<ߦ<<ؓ<}n??9? o?#?+D?.?2b?2u?1 ?.?*?&l?!u??4?6,?؀? U? z?נ???-?M?A?PD?ǡ?$[?#|?z?JW??D? `?;?>R>S>t>W>ޏ,>`>{>\>-p>Ϥ>>x>4>,>w>F>ȼy>ǝ>>$>=>:>g%>>k>>3D>rq>0>k*>>E>i">*>>>> >y>si>lxf>e?>`'>Z>V>R>M0>KP>Gs>D>@q><^>6>3>->'?X>!>> > >\\> =}-=0=w=Q9=ѱ=Λ== ==}vW=n=X==i=}==SW>=s=z=|x=:==I=6=u='q=A==m,=F85= <-==/pb=\;=~Z====l=E==gj=L>="W<*<"<\<™<͖ ?Ol.?%?(?*?"I?? ?A*?U?!}? ?x?!N?>N>>Ӻy>P>?->8#?j>6> />>>J>ѭ>(>ŬY>>ɾQ> >Đs>>>>K>W>@>%>[>>>$>3>e>T>7>>>>>B>>'>D>j>>6>>2>G>9>>P>&>a>>#>N>%>>d>{>m>">?>A>a#>U>&>>F>>ۃ>3>xe>A>l*>ũ>_t>z>S>w>E->kF>6z>]ٞ>-WH>P +>#k,>ClZ>$M>8>kx>*m*>8>CA>~>K={>B>@rz>e>)>- >c >%*P=B=]->!?h>Cش>c>v>qE>c@>V->>n> +>>H=L=߻= =~=F>=|=j=x==)S==qe=I͔=H =6W===*Y=@===l={=>=C=@=RBc=<<߳n=O=7=K]G???(F? :? 2>T?'-?&(?B ?Q?M ?6Q?%y ?Lal?A2?w?P#a?qA?:?`3>?6?u?Q2J??Xa?kEr?HRj?aE?b ?yѯ?xg?i@?[z&?D@?Xٌ?Q?t2?\?i?E?RI?A?X?OQ?PZ?G`?4?/is?*߮?1A?26?8r?*?'QM?4x?2K?q?m=?u??.>kR? W>L ?F>)? ! >ͻm>tc>װ>'>t>۝f>ݥ>ʼ>>Ĕ>&>>V>>>Ř>#>ǂ>S#>r>i@>#>/#>(->Q>>ɬ>>>>S>N>ϲ>y>Ԁ>r>>b>g>>:P>hY> >+ >>`>>>>>>iE>aY$> r=ˀ>X>$/>s>v֯>>.>0>2>a>>o\&>(S>9*>c>Z>@2>>}>>T5>>'>N)i>Sԧ>oV>eJ^>=>Wy>2d@>H> J=% =1,=g=d=A1=~om=F= =81=k%#=Q=V==.==d=N??QV?G?O?&X?QQ?W?V/?{??W??;.> ?gm?Ȓ?v? >c?>ݢ?%aA>?>ˁ? DN>f>u>I>7>dT>m>&>-> >o(>>Oީ>Ej>J>f>CB>>Fg!>&>]>><>>@`>>\>>Љ>I>>3L>>> >`>>7w>SH> '>X>̵/>>>9>>>>> >O>>^>e/>H>{G>1 f>TV=l>GW=>5D=q>m>=> F>>>&.>0 >i>K>q>hD>}6>r>h>jm>uf>\>|I>(>>0U>v|>&>>ӣd>6>>->I>>{&>=>#>;pq>_k>>AX>D=f=q=a>F>,}>&>=h=> >A> > >=M=k=b>=ɂ1=\A+=;GA==j==r==}=w='==+d==J>}?%Z? Bl>>!>q>$Z>>>?>۰>=Z>>W>G>q>>>>>>>m>>>1>>Ձ>> >>fF>15>u>q$>ܿ>!>ԇX> >v>K+>r>a >г>k>Ō=>T>>.>u>`>y>ܛ>r>S>q>>#>~>Qy>(>_>X>P>K>ٜ>l>d>>?>>> *>T>fe>.>2)>nc>>C>y>\> >>&X>)s?>E>f>3?~>T>>&:>"G2>>d>u==,= => =(=)=#=; ==ƛ=э=ŭ;=)=8==z\=u=-^=G=B:3=9xx==_=QC=Jk='%=<<]<=<3>=>uI>>v>ܖ>>>>`>{>YF>/>8a>)>ë>d>r>c>U>}>pM>^]>l>>Y>wk^>~>h>W>Z0 >ZH>L>9>^>D(>G/X>\?>qs:>]Y>J>U>[_>>H> >my>]>>t.>bv>-?O??y?Qp?? ?%?? m?6?>>>F>>>> >Ln>1>>n >>lN>6@>7>ͬs>V >>R>_^>.=D=>92>>1>6~>@p>::>d{>  =/=„r==T=au>w=B=G=ߍ==8==B==@=5=#=2m=v=l84=e=^==Nm1=\=<\.= =>m=T=;=4=z#= Z??&S@>>2R>{>=/=> A>HTR==Fr=t1==Ae<@S+@JTH?tZ@) @Y@h@5?K@]m?vS@ 5@YI?f~@Q@pv^v@~̔@ɽ5ۨ4@L%>p@F?>S@Y!+@B@OA@Z#>e?J@/@T0@wɾ"@$@ *@@d@q@E@ GRUP?@@@@@@@AAA A0A`?@@@@@@@AAA APB|GMAG<===>+s? o?{Q??w?u?Uoq?BH~?%?$? Z?%B?"=?>???x?)?C%?R?NE?Z?t?l?Q6?I2?H;?CA?Kp;?ToF?H?Co[?Q1?Pһ?AL?׸?Bv?G?M?J>?EF?E?J?F:???C?EA?=+?8+(?%?=&?=Ƹ?>(A?=c????={&>>>>F>>G>>a\>f_>e;>q>n>s>,>k>2>>L>I>>k>0>w>p>jr>c0>]M>W|h>R>L[$>GMz>B>>=)>7">39>/P>*>'_v>#[>V+>>H>Q>\>Hv> ,v>G>0>7>ؐ=b=_==+= =]=p=[=M=ބ==|===[=j{=pW=ɼ=Q=%1==ţ =m=½==Q=̋=/0=a==1=W===ԟ=K=U=]=+=7==-=I&=/=2=1:=H=ާ=I==e=ӵ== ==={=vm=q?=lJ=f=aF_=\[=WRI=P=K/=FW0=@+=<2=6|=1W=,b=&G=!=:c==Y= Y= =,0<8g l>)&p>b.?]?;:>i>(>5>/>>3>m>C6> 4>m>ޒ>,>>P>s>h>Z>>U$>y>k>>>׍>p>_>h>->e >>>n=>ވ>>߫H> >D>|/>?qA??7?? 8z? ?a?{?RT?6?T?l??#t??O?1>>>>}>S>8>">>>E>k>>t>O>>%e>ڹx>ؾ>֛>->:8>"R>|A>>ڻ>k>>g>܆">6E>c7>a>>Kw>@;>>M >J>ɟ> >f>J>ͻ>>5>}>”>K>>">p>ݍ>>z>(>˻>E>uD>{>>>>J>\>6>5>Z>=>)>>e>>H>uH2>g>Z|>M&>B_>7>-7j>#E >m>">'=O=X=Ի=y= ====gm=Lr=46=#w= = ==G=rf= ȗ=-2=I=&~H=0=9=B[=K I=S6=Z`=a<=f1=k=ok=rD=ti=u'=t =t=q=n9=jrF=f==`J=[jW=T=N=F=>#=5f=,gH="t==;= <<㝿<δ=K=O= x="-=%=@=&/=(J=)=*^=++ =+;=+W=,=+^=+A@=*Uw=)u=(=&=%,=#="6= I=|=F==%=֟=Y =Z= W= ~=F=V=:T<]>8>2?nX?_??b{?`?N ?!>L>6s>R>b|=2>>I>ZG>=>mf4>Tz>>(>[>治>?%N?W? j?H?? HW?n?K=??'?*??H`??!(??[??8?TK?!N|?F>>>>">8>|>B@>ב>o>c>Ց>o>)>>>k>>/>`l>4>iv>>]>]>q>]T>ٓ>{>kR>ҵ>̆>Ӈ:>L>ڎl>R>ӿ~>}>>Ո>=>_> >>>9C>>|#>>3>->>~>>&>B>e>I>ͮ>:>Ơ >@>f->y>F>5>>u>>#>x>Wu>>>>k>Ĉ>9>k>D>w>L>> G>X>`>K>/W>|>">7>sr>P>>b>.">?>>>m>>>{>u#>pV>kpe>iQ/>b>aE>\M>Z[>Z>Xe>X>U>S>R>R>QG >Q>W>PY>N%>L[>Ib>F>CW>A0q>><5>;>8>8&>4>0c>.E>+j>(>%>"V>>l>V>F>`> g>>j>0=( =x=蜰=Ƅ==D=]=ė+===)R===4=P===eH="@=v=h=Zԕ=K=>9=/2=! ==~~<<;<<RBT>Į?5P?LN?|r?}h?t?mN?c,?j ?z??n?e9?k-|?qjf?s:B?qC?my?j?^ƀ?Z??Z?Z;?[i?]?]?`"?a,?`?Z?X$?W?V%?RX=?N?N?LC?GD?Hw?J?J0u?G?F?C?E|?D7b?Bmf?B ???=:P?<o?8?4\?1i?/ˤ?/n?/?/?.?-?,*?)\?('?'Z?'?%G?$oo?#ؙ?"*P? (? B?4?L??9?T?yo?6?*A??D7??`?}?}?$>o>>~>5>J>ro>U>}>k->V)>?>*Y>;>=~=*=={=ܻ======h=M=T=4?=[Z== =b>s>>Y>>>'C=w==k]=؝2=̖=Ð==O=E=ޱ=ži=Ÿ==x=== =uO=iL=f=en=c=[{H=P3=?l=*=zR>>>F?;)?_a?oUv??z+?v?sc?b?j[?~z?y?\0?K?Q?V9?P ?K6?LG}?M0?K?K?GU?AL?B~8?C ?Dv?>W?9t?5?2'?3B?7i?;-?7%?4}?3`?6?6?5?6S#?7`?8R?9?;?;?:n?9?;?;/?:l?4u?15?0?/?-?,߭?-!!?-?*?)+?'?%'?"7?"O?!{?!Tl?Y?o???q??@?:??)?|?1??T?R??S????$???&??O?߫?? ? X? ? ~^? $?y?_?0?e?o>>>Q>->>>>[>j>>>>QO>>>R>Z>J>d>l>A>ݭ> >?v>پ>h>j>o)>C>_4>A>:>> =fa=܁=._====U\>j>>Z> W@>">>.Y >1e>3>1>8M>7>6M>5>6>1>.E>,<>,>(˥>%գ>",> >k>Ξ>}> [>J=n=i=V=xP=l=C=Ƕ=7==+==6= =C=^==s=gQ=W'=Q=C&==Y=.3="==܎<< M< <ɹ`?_P??9&g??v?!9?>s >>>?>??7?%&?&?*?)?x'?$??#??$?*Y2?-}?0_)?4 ?7 ?7?:D?D @?I?Lf?J-?E?N `?S"?W&?Z[?_;?`?cH?`!?ae?Y!?R?HЕ?Ehe?@sY?>?;k???,>?_?n???;????`??-????:?(I? ?x? ? ? ? ?c?wA??>?D>~V>t>f><>ퟵ>>pD>>佐>><>b>kU>q>>\>p>Ӳ>>Ҿ>(>|>`>>e>3>ǃ>>o>>Œ>>>I>>>ͩ>>dPi>Fb>,h>=A==s7=&=i =5>="e=1r=6=S=R=Sd=]=BV==g===s=+v=}==`"=y=o=[K=H'=`=Y@a=A,==`^=$)=:<Ȧ<;#;B;;4;|;W,;;R;ш;fFB;FG;[ ;];Q;);.;#;G;<<'<#<R>u??fu?v?]??#>->s?>>?O^?-?*-?x?-7?$Q?&@#?9d??e?9?D_?R:?R`$?S?d_4?g?i?m??za^?s?d ?`?N ?Ni?:?6-?0B+?^?>/>$>C>>g->T>ڏ>n>hR>۠z>ox>>̊>լ>>>BO>H>s,> s>( >>͓>ĉ>vf>U>>>1>>>+%>>;>C0>Y>>e>,>>>>]>}>>>>g>>Á>B>I>S>>N>>>>>j>>{>>z>Z>tg>wh>pi>qb>je>n>jl[>l >yx4>[ >]>oS>b]">X>R>Oy>Q>Fs>9>>R>@>3>3m>1l>7>>9W>2>/t>=>CwP>B_>J>G>E>N0>L>J>P)>I{>=>?lv>@b>8:>1C>(t>!>/>> > h>U==R=8U=9=(=B==9=}=u=9= =\==,w= =l8=$=Q7=n=p=}=$z=v=(=>=L===4=,=&=Rs===5:=N=a=s=9=2=oGk=e=S=? =4<="=;=<띊<ƍ<ʍ#<z[?m?cm??F?R?Nߏ?L)?;K?,H?^S+??sՕ?Mg?Q?YV?[kY?Uϓ?R?N6?ZM?W;?R(?QHN?Z_?X-B?P?Nt?P8?N?GO?AP?@l?8?/O?+P?*A?,>?,?*)?(,?2M?0?1~?-?.?)K?,>?&6?$?Զ?E?XU?:??? D:?as?ɵ?nM?6???=?M?? ?vB?O? ??`?K?3?ՠ>.?> ?>>">>c?>]`>,>j>ꎗ> >>>؝>̐>Ȇ>>>6>S>w>$>$>>oz>F>&T>*O>U>bV> >5>b>>>~ >w$>pA>m`>f:>dF>[>Z|>Q>QE>Hɾ>I>A>B0`>84>8QV>/>-j{>#->>>>\==ҫz=@>e>Fj>(m>.o>@>CC=>Ii>Cn>>p>3k>,> Z>>^==4=k=͐d=7==K=ͻN=۪ =Φ(=a=O=ǣ,=I =v=U=@=t(=SP="}<9y==x=lπ=ZA=O@==}=/== V=<%<<#<<<);~S;;f<=q<=<|;n8`< n>>k~>??Q/>P>C?*+>>ɦ?3?k>> > >>y>$?ѐ>>>>k>'?؞? ?8??-o>>?,>q>>:F>3>r9>R>>x>ۣ> ??? >>[>">3>0wc>|>U>f>b>J> 5>ٲ[>mO>>l>L>>R> >Ni*>{>SQ>'>~>:>(>>*Q>>PP>[ >T d>(>>q>2>K>W>>'>{>_Ll>u>3>k,>'Tx>\*>\&>jg>>q>LS>v->=>^>}>8ɬ>b>Q>`Ew>.>f[>Qp>>d.>r >`>V >SN%>8>Jr>*>S}>#d>X'>W>+/>Kd>+&>F>#>>'_>3T> ڭ=>>> }=>>+>["Y>+>1/>ya>>I>x%>˸>b0>^>O>hY>>;P>Qj>G>> c>==\_===-,=)= += ,m=/=M$=cax=d=kp=#=z=I=Qa=gJ=g=x[=?==k=I ==kK=.=fY=31u<<]<?M?& ??*?@ҭ?!>=>>?Wv?VbP?D?a?P?zJ?A ?< ?(g?AF?#?EG?S?F?LR?[?&?1?0p#?2|^?1h?6(?4=?<Ł?+B?/VH? ?;8? V?e??6E?,??#?^>6>>> >8>L>>ܤg>U=>~)>~C>}>2>>>>>x>?>v>>* >,>P>ޠ>Ha9>R=p='>Qy>l>>L>3>4K>Z> >7>z>=>qt>wC>OU>ko>u=ϯ=R`=qu=y9=e|=RT=/=&1q= :{9;b;q|;i;I;Ɲ;[<-H<s<<%M]<$<1g<%ѯ<b<7q<.<Nj<;՗y;B;9;g;lyU;|5>;#S:/ :::Db:::4O;>; ;r ;VΫ;{<;> >ɬ:>?:Q?O?8%??tr?Z??P?Om?ip?6?-?Y@?/'?7.?y?J?_@?_?.*??L G?!?\5?v?7?ET?I=?9?A?E?#?rj?ĵ?!K??'a?;ٹ? ?*;? ?X??.??"?<"??*7h>\H?)`>9?8A>X>?? c? H>z%>a>? >8? >i>>p> >3g>?^>?E>*>>?:>>R>ɷ>m>">Ȧ>q>>\x>r>\>{i>>>/>Rm>u>r:>C>Y>>k@>Xz>P\>xЮ>m>>f>~O`>]w>K/>H >E>~7>|%>ϫ>B>Vv>'C>LC>F>[>ra2>\Ԑ>Yn8>.G>5>->`K>Kps>]V>e>QM>:b/>ZE>&>P >7>7y>X>Q>G`><>J;u>!>$ >'>0VB>t=>@==4=|נ==U=!E.=ad="D =7=@j=>up=)==$j=[=%*B=B='}=z==Y=="2='w= 1]<ݨ<߁;Ռ;;ڿ;;ѱ;+;;~Q;ڟJ;(;;K;;u;aʝ;;y;;o_;v26; ;ZM;=;;u;d ;6?;q6;k< ;;X;;Z;;hz;`;;;j;b:O;3::w;C;D\K:ݱN;t*;W;ݳ;[;D;d;A:u;0J;8;.;0%;-9;U;S;;+t:;g:R;:r:p=; 6;;.;;87Y:;x;P:Xx;:`_:O;Y::; ω:k;(:YO;;mN;;W:;#::P; 0,:;l:' ::n:b̓:I?:.8: :L:#:WEu>g?' ??K?K,?l?&m??2?*A?V|?g?adl>X?q?v?B-?H?>l?nɗ?OG?5H?Cq?g$?J2??J?G?Ik??$F?H]?U?M?KQ?2-?ru? ?(???>I? zz? !>>U??">>>B>>ܶ>T>M>O[>J>8>c>>J> >>>>i>>g >Z>s>>-v>V>ܘ>_1>U>xI`>>E>{(>>%h>>w>o>,>%K>s>oK>(`>vr>`^>`>l>nh>~C>`>}>rH>nr>e%W>hr>v|[>\>k>]>o+>k}>k>i7>b>|>>hk>OZa>f>\>i>F(>a >Ty$>Ue>O>B>a|>]}#>Y>R2>>^>_4>E>1>PL>Y>1b>F>$e> >>=4===+=v=j==X =====2=IY=[|=H=`[=-=a =M=,:==#=<8=^<<j;_;G;Z; ;);S!;2;; l;:g;{;&;$W;H3 ;i0;<@;Pd;:;S;,;7 ;;;h;; f;ֶ;;1$;;)j8;/wV;b1;ON; ;͘;Nw; ::_:!;&;?;wA; :U;I::%B; ::;:t8:GT:ցn:oL:f:$:+:o:~:3:;:}:L:Dn::+::빍::ψ::3:W:պ:x;;: ;}:L::ͭ::]:y::V$:M:U%nyquist-3.05/lib/piano/pn09.cod0000644000175000000620000003543010144436365015327 0ustar stevestaffSYNCCNDNCOMMC\; "PARTd????????????)n?=> ??_!>>nok>I ?P>ݕ>>c>-q>#==k=vp>+>;ު=J= >@===n;=,J@ @?o I@R?[?7@`b&?/pi@[6?i@7>(0 ?@?u@ lkǿe^B@X9?u>@RL?s}?SD=A ?n@SV{@Ji@n=I?S>9?%c?ę@IپEIAe ?/×?a> =@ ƾg??c?@.@b!|h?Wy @Z2@=@7@Vu@@>@ @? K>y;>?1-@Ӽ`E@?@ΰ@@)@[> ?0d?Ϲ?&k??w?)~>)>،?c?H?l~?v?k?b?3 ? g? {?4?FY?%t,? ?>?? > ? >?(>L>G^?$5?"0?!q??Y?Ue? *?H?m? ?|?? ?3?u-?& >"> 1>u>7>{>q>]x>>x>M>>T> >ݗ >԰>2>> >0>Ǘ>a>> >>߉Z>>>[>7>>h>T>,>ԭH>͊3>K>>ş>>R>p>l> >4>3>?>v>-> K>x>>>>L>>;>>>q>>@>>5>*g>q><>wc>>>>(>>>>f>R+>>V>>>G@>>A>>.>5&>B>>3>>>>>u>nO>hY>_>W?D>PD>F>>;>6f>/6>)4># >+>a>> >.=DL==5=_=Ռy==Nc=aP=j==P=<==G=E=zd=o`n=cb=Z;p=P/=D׌=:=0=)Nb= ===O== =;6I~?9R?d??jC?O=?M?Jl?@?D?@,?@·?Ep?B*?-(?K,?q?ɞ>?N? j?۾? 0?f???? ?K~?W?!?4?=?;X?????j?3? v? ۉ?? B? ? ? P? "? ? ? ? )?=?"T??Q??4??^l?>]>.n>> {>`>& >>l> \>j>:>&>>>g>>w>a>c*>>KE> >O6>I>n>7>>c>a>>9>d>d>K>>$>> >p>nw>b>&>8x>L*>o>Yy>B!>>╊>&>>:G>>h>*>|7>ް>>ݻ>ܼ>3>w>>٠>l>h>PE>ף>.>`>L>P>ɓ>->{>F >>>>u>>(>r>)>>2>i>{i>r9l>iC>_>V>NH>E>=?>4>,>$>Ք>> > =g=a={k=!==_=8=6=Yz=O==$=p=\=J=9^=(1=;=<<C<5< <<{<}RHG>t?T?>ZW?T?Vm?Y&?_?d?f ?fu?f?`?[?V?PB?W*?^J?`;?e:7?e?d?h`4?q?{m??|+ ?xߠ?xW?wA?veM?s?p?n?i"?dذ?b?`?_s?]&?VbN?Oa?LO?J؀?Gc?E;?BZ?> ?;j?83?7f?6l?5?4?3?2M?0#c?-?,W?+CG?)?'?%?_?#Z?"? ?ֿ?-?? ?G?lH????.b?'???)? ? ? "? `??w?gJ?L!?%?]??˸>Z>>>>A>>>FI>>4>Y>Q>^>~>>Ml>>%G>ڴ+>؟>֫V>!>>[>դ>>>}>2>+>OZ>c>>><>x>>>0>W>P>_R>>u`>^>HŸ>5>$d>>P2===~=σ=5===j=Or=6== ф<<ͳ<+_m? x?/[>U>q>̽>Ȳ??U??? }?*?Gh?eB??~k?j0X?fPu?Y+?J?@0V?1o?- q?E?`k?]a?NEw?G9?B\&?3?'?#G?&S=?(t?.Θ?6???4̈?1#:?'Œ?&? ????dm? ??X?,?^?n???(@??h??R ?xk>=>b>h>Gd>ݎ>;>>>nr>V>@R>)>jM>J0=遘=(==]=Z=sz=_2=Q=I=J=R=c=wCr= ==N==F==1==i|===>.A>p> > c>}>w>>f>>K:> > U>D,>0> >A[>h>b>a>>!>a>> ]n> c>k >ZL>>%>(>h">7k>>s>>R>c>3>*>4>^Q> z> y>T>>M=V=-=-= =M=G'=a=E=կ==:=o=к=l=%==ҍ=ِ=F"=Й=0=n=ͶB<(I=>1? N?A?R{g?F?C?Y?np?z?~?{?{??p?a?UN?VVM?W-?WV?V?N#?Q\?X9?W?U9?RDZ?S^Y?P?Ov?Pͤ?S7?Tm?SA?QV?MZ?Ec??K?=#?9J?6?2Wf?3?1b0?/?.PN?.?,?+k?+/?&y?#T? \?)?@?2???i? T? R? ??9?ڟ?W?f?jz>>{M>>&>>>!>40>>&>[>>U>>Y>4>f>)>m>>,r>>Pq>ѱ>/>L>ɖ>Az>>x>Î>>b4>i>0J>>7>Œ>>> >>>>>b>h>>$r>9>~>>_>G>g>>>>>)>>(>NX>nq>PGB>4>*>ML==}==b=/E3=<6m<2l<0%P<1 <3'<82<>p>r=?h?EhD??`?(k>}? ?e?B[? ~>m> 3>ר> >??? >Y ?{>>>>Ə?P?-I??%)?A=? `>?e? [?%?? ? a?`??? ? z? ? I7? z? {? ??x? m?"? ?Ў?a?,?rq?8>?>2>>!>>>R>ʚ>뽿>>G>6>T>\>G8>S>C>Ꮶ>q> e>> >趉>n>[>/>>!>2>>>>>C>l>>> >>$[>y>~>ӈ>17><>y>$3>k>fT>q$>]>O>=>\>W>>f8> >*>>틀><>4>xp>>5>A> x>*>/8>%>D >>iI>LW>5v>?>n=Ӓ=8=a8<=&(@=?L=24=Vݫ===5=ۿ>k>D>b>>>x"> >|>r> @>"Kj>Xq>D>`>>}>^>/><> =>==2===ф=M=JF==^=\==J=k7=h= =3==|==BP===ae==zs=oP=g=^e=Uч=WF=W=^u=a=_GO=a =VJ=MWB=K?=AW=AP=Dd=E =F:=E(Z=<=5=)`{=F=9V= =$v=0=9̞=@3v=B=B=<#=6%=/~=/ܒ=3&==,=G$&=N;=T:=Sh=Ol=K=G/=FX=K, =P\=V=\<;o;_9߀Mɦ>??/?L?dF ?{}Y??{fF?{&?{?uJ?u?s ?nŗ?g?c%?^`?P#&?G?FV}?G?F(?HZ?J ?Okj?Kf?GU?@s?; ?67?8am?9&3?77?2q?0j?/H?1?2y?1?/6.?-)?,K?*͐?*xU?+?*W?*K?&?%?"}?#=?!G?"7?????K???z?i?t?f?az?X?p?a?5 ?F?#"?f?U? )? ? &?W??:?u? ?L? ??@? >26>>D>B>s>*>X>>>tz>/>">A>0e>j>KH>">)>{>?>ު> I>܏>ْQ>">׺>ן">׀$>#>>e>a>7>̈́>ʐT>ǩ>w>F>>1>$>>-#>3/>J>r>>sI>V>D֦>*K >=I=^'=R=j=Wv%=<<+<֠<=b=*=E]=c`=|=)====(=zv=/===K=!=h==Q=m=:^=$=S=$====1= =^=6=w<=k8=c=X/=O=G=?=; =6-=3vT=05u=,g=,V=,=.F=.B=2B=4"=8==r=B=Jx=OL=X =_ =f=lu=r=zcy=~a==У=F=N5=&=1===j=== =S==uB===w=Ex=)=rj=--=(=N=Io=v='=N====Z="====ym=?< ;駧; ;Ӌ=ԩ>O>>c<<>b?C?m??i+?eڇ?T]?FM?CS?>??>0r>0>{>Z>i>>J>壣>X>>n}>'>5&>ݝ>ג>>Rk>Υ>3>V>g>Ra>>D}>> >NK>>*H>>>F>>>>Gb>>c>h>>9>m>>y~>>vS{>y>zr>~>v^%>z>s>r- >j,>l>`5>g>]>c>` >a8D>TZ>T>I>F>Bh>@>8f>9{z>0$D>-'*>+>'x>#D>&>`>>^> >>%> a>W>{>7>#>b>n8>>N>> >n> >S>N==t==Ƀ=٦= =L="=jr=D|F=7=!n%Λ?Ry?BVi>D>vȘ??=ΰ??q?[?S?o?i?p/?^u?OQ?'L?/#?mr?-5?(%?4ґ?&-?.?(%??E?!>V>9>M?>?@?0>fx>rO>5r>>X>?>v>g>h_>(ҳ>*F>?5>JA >T*>W2 >M>H|>DBf>L;>f">P>I|;>8`>^ >r>r>jV!>Uz><>,f>&p>"$;>"э> s > ==ij=M=k=ܘ=4=Q=uO=H=^=桼>>=V>:"> >+i>Q>!> >3=>)>2,>l)>A>ck>1>z> C=====>U==K=2>E>>=+> k> H>f`>>>:;>/>!>)W>?>4>>V0> c >>>c=o==s=e>Ɨ=>>>bj>5>&> ?K>'>>K>>%M>2>.cf>4s>3>:>;>9s>>;#>:j >;c>7r>5w>7Ѝ>4>.s >+8X>">o>>> > \==87=f="===b=ۧ=c4===s=nF=Q=/s)=2=u=<`=v.==-====8q=)=/l=?j====̺==|=o==14={=R=!='==x=|n=}=ken=\l=W=H =;=4h=!4==d"< W>t4?X?TP?Tx"?g(?Xkj?TI?j`S?{8?{C?v?y?va?~??v?l?c]?n?qkU?x?w?~K?}w?|E?~M ?w?s96?uT?w?q?ld?m'?jȫ?i=?h?i#q?gV?b?c?e\?gxl?i?h?k?j?nr?jt?m?gq?g1?aC?ah?[?Z?V?Qf?O?O~?Mn?MD?J?JX?I?H?J?F?EZ?AY???;}@?: ?7_(?5?2?2?08q?-p?+ ?*_?&b?&9|?!?!O??+?}u?2????+?(? ? P?J?;?X?Y>B>a>5>>k>8>M>ig>*>+>c>>>ćo><>]>ܟ>>7>'~>>>>>`>(>+>`~>> >@tK=^w=ķ;=^==P> D>m>+>5»>6>:h>2>/QM>$>O>">>=\}= =p==(==q=XXL=>=21=!=!=-dc=<<=B=J=O=\Z=Yr=[H=YA=_;=Xۄ=`M=f͙=aB$=_;=Z3=i=a=yjX=pfA=s=o(={=vMI=y =t=q=yq=r=rm=td=e=jXu=[u:=b=KZx=R=9\=C=(=1,=== '= n>)Y>c>x>Wa??/D??F?^??7?=?M]?N%?^p?W?l o?t?p>?r?m?oƼ?_3[?oɁ?a?qc?b^?u?l;??m8?{?jK?t ?dgB?m&?]l ?d(?X?]c?Z8?^B?a?a"e?f?_?c?R?[Ҽ?H?R?>?M?9?I#?8?Ii?:~?J?? ?H8?:y?>Y?3?31E?,-?)?&h? ?"??!??"?j?#w?)>mQ>3>>]b>!>P>s>i>>?>]>>؀>>>x<>(>4>m>&>8,>>`m>>eB>>>>>܅>>T4>7Y>V/>~F>ϭ>q:.>>j>xq>Z0>m>P>_>$1=ރ=B=r==3|=4>~>"z>>X6>U>X >a~>hg>s#>L>yj>}w>y>w>~WR>rM=>fD>]>S>N}>?>0Z>">No>f>=|==3=p=uC== ===>=`r>>T> > ֏> W>^>:>>>>%>Y>>!l>>M>%m>!Yn>#S>#>x>$h>#^>!'>" i>>>Pi>y0>I4>q>.$>.> V>$>×= =)=~==o=԰=0==̓==== =+ ={^=j3=^BQ=HB=:;=* == =<"<{< <<<9'<3<<?W?#ۖ?1?T ?Yl?b[m?nU?6?n,?t_?k??c ?]p?;0?>c9?7P?P?PKr?_?RM?O&?3Rv?*ݥ??&??J,?&?%?- ?a6? D?y? V>? ??Q? v;?\g?#=?N>>>(#> >p>>9?>^>v>2T>'>Q>m>ʒ>L>>I>dD>ѥ>>>>&>g>>#w>>I>6>>>G>1>!>>>>H>v>>m>,>I>>x>@&>)>;>6 >|;>:>c>r6R>d>s>pi->uk>pC>eL>\O>M>K>I&|>Md>O>Uӽ>P>Q Z>>c>>>*,x>1D>">0-%>&Y>1>'>,> 8>#>>"+>6>у>#>>:'>==2===YH=+==:&==x=޽==G5=؀==$@=>9=Yp=ڤ=v==3=:=|= ={=a==VH=8C==\=?^====h=y=s==gK=;=J.==~=ǹ===mu=C==T=ɬ= ==>!=e=)=g=t6=f3=R=>=2z=0 = m=0<=4K<R?Y?x?ո?|?{U??!_u>ŻC?a??)e?$?H?3?]&?EL??j8?0b?0? ? >'2?H?<^>?'*?>9>1?#?=?+>>j>>޼> ?L?(>0>5>a?j;?{>>> >>>ͯ>G>ԅ>t_>k>>>5S>چ>G>3#>M0b>>>|>t=>Xm>LC>B>F>>R>B>1>o1 >s>Y>g2.=3g>6>@>4>8>v> ^>X >OϾ>D>>lK>[=0>.n>=>G>W>;>>>]->>>YK>E=>S>wS>>fZ>?{r=Q>:>l.>zL>{;>*]>")r=>tW>}>>>>AF>X>a<*>SB[>$=Ҷ >A>*>76'> s>55>/+==8=?ix=: =yn=ǖ=="#=/$=V=&=i===z=BW=ݪ=xL=Ǭ,=4=5^=g=kV=|=~=@=OJ=<=i h=g;;zG;;;;߻; 3;Hy;Ѩf;╶<<;Ԁ<'l;a;;e;Rpn;6;H;J;V;;¡p;;̇2;Ȁ;C;P;;;;6;ҕ< X;<;0g??bٺ??j?{?mT?o?e>?{?a?;?K3?`?Hq*?.@e?K?E4?@ ?)1?*]{?7?/?l??%Z?$2?\B? u???U>?t? >T>؎>> >D> >ל> >g>6>–>> >×>>>W>;A>O>->An>>[c>R.>t>sZ>j>&Q>v>aL>xD8>g`O>>^4>_t>[>r >k>Z>bW>ef>bs>S>d%>jo>^6$>T>e9>pn>bȩ>g>h >fy>h7>j.>]Ub>an_>hK>e}>div>ej>o}>r#>d>jQ>>qz>aTc>{&0>50>wMr>v$>>͂>>x^\>> >~H>y{>O>>~>>|]>Ϊ>>zG>>4>>/)>}>>>u3>|>r*>a>M|f>;&>(>$>">j=>=h> >=>X=2v=B'=)====jF==k$=o6=w^x=O=]=C=KL===E=Fg=6\H=1og=(8=-G=Z=,= oU=ș<<*<2,""L'̅ TLFcC Pal@&B @ LHG1"8qɝP E*d+0yހ(*LSZ0x & M" .ֆG&vQԖGtUv*O֘e__MM讣i4'X[j=B+9Ig.~ |&_E$ @OD?\pu(qݙ~b2 x{޼m&]x4ŧC$_]w_{ )8"L%i om8QkQ)#(HYJhe=4'%*]\\>?8ubM^)c,XOE*ϒt(3 {aN)BU0;cu_ؼOG,rzzc4jԅdߧaN C >k1 g܊4OG̦=iEI󘗬UÞ*oŰ~pydz<b)YNQ0h\c.5lΩ-]f?ַG0O'e>O]L=)i1cjL\RRɮ4 Rpa, S(bkġ&~Xsiyna DviW͚q><;nҁ̞%!6QiB67$p$rj^?3Otͦ L.Ų\{bh܏}#,'/:ѯFJ&is]8Jtt('}>TE{DB.Ns\nk~CH.i-z hfW/wJP}<fŞيpOH˴4'SJ>jȚyk՚Uc}g0:OS۟]c\۽J| zc\u,H1wX榆x :\b0`6tˆZgWPma]=/KHM*,j{ּKKAxvJ.cZ1-b[wYɌNԪYEaD;7 QmoY2~|G]s-;TD^ڵZoTUi/} "ђYs{^V PG: gYC@X.yvk`:k9 *Ї&})UuXZD<2gdW,r)gm%aDE&f]2j ;a׍It|W-Ф`;`f_{uxe89rMr뫑P(ںZVG^0f/4`5Ft(D,UH!04V@0cY:(ѤhkENH #Qb楐5HPi-0x^:gbMFwAWNa)ͼe{'ZZC|H _e1~9]XƊVu~X>L/L̨#-L*m)oܵ{ zi2M!Q}) $T1Sa5C3h1 :0@r!:P ʣS 2r(<(x0p*-EDgC5,H} i6OZ]"WpŸY3)w,c_g< }ߦq!fܶli#NMͰ†C}5t*J(2hʃ㡀#f*#XgI'^ )AZC, "6xGf;u(T8~r/C[SBpk*9S@m*M=_2K.dGJljF:O*G|7yg xsVoTe}򠖍;OW| z\2<­" }>QJ3롘r 138 dQT0و ת2@`SD.A3cP]UeY=HŸJ<Ũ"AҖTsô|xA&sk~Vn~&z}g[ue p:V^4 ̱'gK8QiC0T`(@ Ʌ4qf  " nR4q &ƟC"j飽Ȧzˎ[F޼~zCXˤ4dgA-nA059Y/"xuW@nig=Z_Χ,1|+Ԭ,'r|K?Y$iZt+DU\َѬMLLfH(0o .n@X0QSb/ Y_cꎪ境_pd|vc δ5"K.F21KʟPy񼡎fxZɊk˭抳rF2c.Qp]t>5KW\U6Al( ODu3@`ʃ VO0(0`,GADT96MhcPDD(#}B~3%Rb0U0+#eCIT%m|S9HaN=xmD&:OnY ַ֚aO>m*'=wW he8rԸ-X:HRI}Aa ]&f4j Ħ, @*`*KLAD ViDR}`r`$L^qΜ}Y5*X2K+f0֯:y;'&^Dkw:}kTWv Z*G kuY)<9B'{r&a.bFRc2RWy5SΖteU2(@pqƀJ:"(mԸٌIոCpO֧z4t#R 4X&#,%+]׼n?֠|k_~ÛlYp=7CQQS>ni*=eFQ1" %]B:* 2Ԡ5#pc!цr*bHx," %JUh$љLJCɍPDm`Kc*E ӄb,S$U`oWX=4mfR~##Q=[N]v8˘+b/HOui}hvn._i6fC2UO8ni' =Oe[m6iV JXF7`F0iD8 52xSbi+ bHWٯQ"LT%!BU ]+ZȝvVYyű/lwX_i7"߃Pp՟/ jP!S8nig =(Fß̗IRϛC>gFA`l1fl"b0aEX@(_ 8e1C0#Sbc"a4s%]Pp!0;ț@% ""ekr:"Pao$OeF?;ҙ=2سffKcMx}}WS,b  w R<`)'d)t%SG;  fB6a [ƆĀsA{L80,$++rB0I ,4%K=R7c:qW4T†Őɇ/iZ'WMg?,[o>X'2uֻV|MQ+\| aO4nm&ͽՕc*7yGe` OBs 1BcH*f,@ <8<x̅* e%Ol./yQ$(93JZ(d ݇Ύyve| M%p[;]g.3?Z{=+I&vAXpXV.kSĨ`H]c#x 2,$ 22HƈcSL,2PYE@B/ <\BȄ9&FBҀ`E091 0 " /YY[S3ND_.4M0Zip~Z՜&OZ^O~Ӝ ϒHO,]1iԮWUQ6n,&ͽkVsU (`I@̜i10&SXɫp\ ?j 13! p_fjD!3Tm3,6p ).1 /`'јڒDZ8􅺢ޜ񙾾12Z=]V[,a1D][ ,"  J W@L Is4/DaF`&v$Vy~pZf!Q%BBp";>h (2+pKȫZNgR6X 9bRn.`h>xjK%c]:ԕzf؝Y3W_,EܮwGw_isO!W4nm:*fM=zq Xg::9/G]=ܠ*s~9ɔ,9bIq$1Ð :ŀ(h+q@ꦜkAAaQiXq81 !`Xҫ$I !)P81)J4롍 , 3ҍM+CfYφ4frO;ē|iԳ~Y5%| ecL5V uGng@0vD`ZF`qna!f6 i&7Bhii{Ld˂LlTBť7w9is3Db"WÀɵF򺸍mK6UXBSY 9KwU?4MU0n&ͽξ5=I>`b;/#?;޻jiٷ_.Hti9I&;>k G#b -HKhƲ*bFLJL$z Kr͏Jppx(  ۮW (1xono0'ց)2f( Aek,,Kh ɿoH?N}]?ǒ/SMhyý9ok"ji^oCd &1&LF2 FF`#6H Ff#00#љ  a 8&BQf v,V䧁6Č E,U䬂q/)($Ox:\(DY4nibݽnAJR3sa=A^X&*H8=OWn 9oipTmwu+ذ¸2r3ac]d<4ca)|&D֣A#"B0[`lj%(O@1Q9bNhWU􁑋(ӕDӓq.[FGzm=-v<8V|qI޷Q;kiutiꈍNi_^ Zr%S{w(%UFMՍ]ۥuˢ~c|+=VW157êZ֯%#u>!c1'7J}`!"pb pPjaK&;t8,tÀ` 92K¨HFP b7RB%O2sK3Ze@ $]U.$/(~j-ZR\? Ur}pL'Y&y u]O솃!lBeq!.;C׵XTպE\ax1׀tx|2O첗 '4H@XQ9F̘4:-hy9@)z!}YV9Z @!A̵̠`9x֚W2nmMc7l(bmIEE5|?o>ygƥ.s|=n~~֢ncnݤ|*Z& T@9AɁyy bh)4f`Xa Nׇ@;ᣘ9Ѫъ B0 0jHX;)h&Wr&_y bNgEC*"!.Slѭ|o<8yPXO ]>5orMr.]E'Y}ysWUS+N4CXȵpY45lFu rMMpB‰5DZwzBCA=\YS*n *f =F@l\dEe A,"7(=dEbppꯜjT,rx&Bzn|̱\jn5oד qveq4ì)]ܷGW?+2j}_UBg/IX#kʝL  ۍNUY[T(=\Ҏ&2АQQ{4 e6IADCYCmP5CMn^%5Pr5cbv7'ZaGr뼆~ti*J%B}L *a 4rt#_f2b B|d` LA'MXT y Ucu(Pek# !˝w!U6m鍣"* ͽW,x3ձ`Cn7:L %q[\^h9犟dic<]}KyĤ=ﻴwնs3gیHofP s fWfL$f  PO.h'0擊2#K-c"b @p&Y0T(("4&:@LiD6dKU6F,͘RSO)Iˆ?EHƙ>'>iqV MEqnaLOMy[Kni%f_Yh?Hѻ{jSmrK< vL&7qJZ`h`8 oQUycOH!RkzKVg^xrZ޲1EwZ]Wk]h~P&'k*$9ހK9__a=RK$pQkm=C5Ob]``bs98+xzl34f̑SLX2L`a9 349[33|7` @ E]1e 11C#1p' t "de8aaI1sS\Ղ.Ѿzm|X"##^СQ9#rhzFPΘ NfY~44ZcX]V $@APTD7Llx UB@$R)4MT|9|A|z< B1d܍c"z\SD0|2cȧ:Q@nl)%W_]2B*lB2 FœZYzd"-HTLTI;̩kD gt#$_w [WHlQnk{kYXz岭r[ i9Fᕌ 0!jKlǡd5JStڧlN=U3IE;u4`}(ԕJZ|\=~3ڼ}gtJ7g?M8N[qƭ|,*͹)$J@AJ Ef< lnTYbV쮜0zVǤj{lDWU66+hеyK~ZfvWYeT>"yXyT,(B#Y\J-L (4Kd}O59#:x{)ۨMOYLakiՀN ^B-(ܙCK'D i5v!QO neIpV,. 0&+9j5u͕Dh4!gvEݤryŸhUgE' ⍼OvoNg9/=@18dah@eZǴ)ͺE֤vmcuk]kMGYM$KH4D:#ϜaZa4c(l"QD(2dA.*U9-@ b*B&tWV*h̽NT( ը@iH-VCɝ:4Nٚ,&U .*i8e UBi^!;m56ln ڷ64)^ŬܞI|wLۇUTbvWwlÝPFDӗ1V SD0 T m$y$x:!, )ڀb"k|HR '& ͯ0#gI49.7˳ Ƴ=Fupei3GMʹc9ԳPmsVʁ+^&Ew), mY!bxKC i%C+,fBA:CN.d(s\Mw( (N SD ]牀YLa.'=*4\TGRѸ,MHu\==UxF l8x4c n 4㞛!I[yZ{i;u:Ӧ59ǽ+ƺ#CnR8ߟ]5J]MR)0zOeb>/&b8f5.Ep ` &r 6y`b#?V9@-1\$Q LbTI(4, ivsOAmyi&]ORa)=BJxKP Ah}6,FѝmLj3 T$Р-Qʷ>]<}5C=Q|L(h>≮lQp|@ɘ#2L PJbi֌lt1iZno{g 鯨z=1Y䟱@CӭwneVLz#Ud?5 g9Sn'Wix $7W e5Uq>-uNAjv-y3:š KILɻp $JrrFʠ+uu| `,a$:l2K쩨Rb %ݟDqPS;哵W3ck2aFv?KM%Eb 9ֺbQ|>p16jwoəWRa* =yY;4Fڢe˹'fW>V;>iO7l ™rea]"&)FjP"!͇TdG5CL q ${peFl410$ZL @n %}6 UcpiZ$/֏YxPTn;|O?b^ JѦms= u%#pܣֳ'@ Ҏ8с 8!*0c RC(IObhj _BV-Yg?RQlJ-2qn!]ϵE{ܖ[Gv'Mj{7hjCK9.|nтuS>niͪMLTGc M;WOM@ ʣc0St20840(0\hU0q ˚xd, bEP&V T}pP9iNnk@0`r93%^%= ѩina @iKGk=NUݫUo3YS2~$Z;ځju -URk'j} 3 )˚7ٽaIf!a#&D. e$A%e *] N a5SJ۳f0'VFvD5adz9V;\M/omO6R/<]嚷>eö _msu 9UW_5kXu<³&NW&E*`Ƀ@8KFHC"#9 e cJl$@qI{%+iao_/i=R̓`tt~י֠$(mJ9\古 c*|Zp1|.Ul>NcnH4V XMV=A8xjM5zC]U9Y7Tl/;pU,ӵS1+G侥\za} \mbt $B2dpfP$24P< עix_PfhرyO:ni'=uZ< FUu(:'h!0ʟr, eڟQ,iv*t/-Vnm6&53[Eߺ~6W\›r9ZYm> \@n$ @=&rGńG1luD@ Q8^5ō Àb1qb W33 e@@p)(_<)PsEՉA,XFڤMcn&i,>a5zK=)x;/o,6 e5{H 9?Cdk^8oi栁ߨ JJM2ZT,_4[ S]8J%T}ךxB%7S:ni:*fݽTl "pU)0H0cY;̀ cae\eyo2p|PQ D$%ҵˈ x3PJ8ٖyڋ[6Aʴ ! 'չ\0q 4F3[ڧ܏z%z]mTRƻ¦#^*ڕ}CaUWƼ\SsL3I4dSL)ųD)JS&sfA#!f* Q6niX& ͽ1T8bM1bJ"(T $,1*|D1!.@/J0B.~EUyM6PP*Kv$j(K-5d[lon<{hkT?u%6W֣Rx/?Ru~;hpwx -NW`07yaQIe>d{cjbrd D` ŁH*r7{'9q5 ݜ{܀mQ.N ).}T v Jᮧ@6 J(LitLddDՈRlj+I\"T=`@7W (^1nϸhȍov~;:\Pҩb;i1XǶ'^XѪ|ĩR8ͩ0Cf:V&2O p8d$ 5p˳TI28٦8t 8u^$hѰ)1Yr>*R4rȚ) c1i)# Ȕα2|r,Y_V㪃SR3i1F4q<ϏYL_HUlgS-]s>/VRWi?4`̭BnPWBm;&MͽUH H\ s T kb &) m+ L4y#p`+0,bh`46ze[xzMo]l4DWR~f˵R}-r8q0*Zm 4"jPPf2لa+hG,@ˠ BAX$3Vȏl4X H.)Ȭ(0v,LEdtMJQ@[8B63ʣ\OO zHPCTPad |ۡ%6W'T\:|̩^ٸ1=mXXy]GiKz5|҈0[E@ PnXRe%`uFh&Bdfz得CM67EXdOjIə+}p8V/I \qSc#\ГXƧO(N˪ͼ&,-ʦ܀Iz(+IXYH|0MUuy&*b[bVyp,iv}`\&azQ_Ro&f`'̠Q @- 4PpƼx' S@[Me i*iJhz PG=R"ؑe V`64 ^ԑYptDDЁ4h7 *ғҎJOXC< J@R5"v$>Np.P5\1<1,80531<23`E0h9SYxѰyə /BD%OȰ ¡pP{YDNV~A{FHDyQ7.sQe*omMNf03R&VfٜW>m፳Lݽ&:Wnutyi|"e_0Fb&hkUyl Ks̚Jg492A!٢ )d$QdɃbAD'dtҨe$ l aXvd~C,  4@cy3@Si?aS!KP$b*ry7Jw>/CqA{3EB;4/|>+^Կ sQ>Qo |ɿ}'ԓ4.ծn)RYgtJ^艊F5Q'B((Nl':16 ber/Ȕ (A X` CLDI`EB(` QDJVP)W*n *MX`p1`)B a@EixNcUjLyw:9)]g Q7=UPc{ꏽɾ nQnQV웒|}U}k ՟.ǻNPt3]*_v =f>&G1葢eОfP80ufbpXlLX "_<0rp"-@fv_d@ " AHXdC^f" BsIքRJ]wzz$*˴y~[ ßڻQ>|#1-$YwF\nd n]Omoϵ+6AJTrAdObP:LM2؄S K ƛԇL*S.n ͽz7%GYQ P &\a:RьT44 L|H:Jt#<U ~čbr6*!INk/8/՚4}]jO>'̭is}n#7 oXzt! -)I4=2V0R0Y1 `3s0\/2PO8 LC=|T،dX;0!e@ ,jʢF<8$xOV@T(I2SJh<\UPiio@ LO u iQC_۴Z>ڣ)9֠ycV.^$m–z=K[ o[ IqLt>2r\D‡%ά5j7 '7@("2-n1}yO*n#ͽ3:1҅uYxq:K dR)BQ&#X$ѐALJ] I)^s;-O 2p']yIz ص3^hS0M!!p@DYt=WHmam ͽg L;38I$fґ%&j`Q5#\N5﹧36ViZ1y>nw]gDf;Kj6ܵ՞e s21pcB#pa&"ƕi!AC)&x#0"82CT!a Y_! "q^2B~fu}TSsA85:ek(YuyL5k4]xNY(q6'/: )=&Y d Kuh @0ań00@<@+ $=AәW(ù%z=bR<-B#Шcg+@B a" F @0pDb(`cbh``<`(%jPHAX7/K)Ӧn  s`RLwK$CU)$SEP\iz˙ƿJQ:x{'|?Ad)0D[d?ֿ^c󉵷]t;Ic/rLA@8L gLKO<. ʌ0M Ã͎ ̌h͖Àc*B`Ddh`ndLF8,LMAK#8Sv; ?Oz<>y뫲Z'X".t^geK&.ݠ*a#;=/ǻ%Nqeyk^>u-NRUlwvݵ,( 1 6 Hz=#@ >l*&O]*HPexvwDžq{ØIf q0W8tIcWPl*ꍜ1TIa* σSd\C{N t#yfYdqW=.qUGa$ђʨ6Wn&CF#OI:j8 ANz1t4tqe/(?X%ݪ£ 1&;PLU($$FZ'0a$jHt@$SL=m8`ERe(G'h7/R#\31ThPr8PP0KcNѥrrv(M:"xhum P\h* 5 5Wx& L W2A䍩 ~PGvc5{c ء5zR:"~bD<6p. WPl卲} 1- V t&?0>l&|kOHW'}mIYv^#7o0 IqKbbŦPka d!˜|g>aB>c"&D@drƢ`(%z !Z$hDun(4Mm2QUBW9IQTr7=kg1ZZddIq]QWJmiM=Pt'8V›0 hg^bu f 6s9#95#Y0`3@aiZ(6(!"aa0B\&J8ΈT:bbdcE':*2Q`5(u=&Ơ$t hz CӁfw9aRW/T5+W{^nX)|9vsiWsE_t7'N)X&c RJ3H 2t#Yă] SliV~*D 1)2eMC1 ȶ1xEg QYxԂ.ͦlOMсCE+".~Ք HA0.pT\9aھkznhkv'߽PˀW0n M=%iY]lfoMUkmž߁;=02Ӧ&81"=fj#䟰Yp&[@ht;V5%UkvGU!ޡE6V[oK?}ߛ;חz26 lY#9PEgNsWY* `)QaIej4cF&f45$1',ه T١,1Ȕ m3 a`P"@T@(SUB@BBF4 #^gىAlc"4Q88SxFr1W8nmn*ͽ}$5L.DIW=e _K¤;מ6ޓA wt`;X]BE c-0$!ɰ`M|qٍ!PG!#b.~ɧRAS;[Qgp88P88VEa߹-w+j[x<ȿo+~7˹u[9{xb5ed+HW2fE4F_v=1e3SThE-〸\@GhIy>@[p,G#RL{(8"bU<4.SVK#NOO2i|qba^1F>e}.ے(;g=ٳGLmQWHmim**=G.c5.5\\隘O#i45ēu$ع]>qu3uנeyJ2"s’SZf@ PWgR \[TG& l"3ÅdxCcNm>A 6 Cā~Cm*M-2e~bbf,`ta`h<4G0$!šÑH RbƛSN`M{k..u2Tҕ10cSf~zըYX[k|бP2Ljz431501p0leif^, 6L5@Ii0Y1(i0X̼ X)!`Q?P+=oS+olōPT!G`<)`G`50y#[}g[>-OuW.7 1 EU2nNݽtKYX\x1ͨ( R,h%*djPW134XqJRf\ ,ήDzH#C4CXqe+0,J=jQV&$qidF$p `ꁨLt}Ɗb푉@B3zS0h etg`wn~ " 3 3,%GFyɃITipV',`;c@*dp=QH0Fd/WBZƸ Ai;o\b]tuQcoܘxnT;c:xXE+o6O}@6W>mO*ͽE;&nֱ @ B,I"f VfePn B!cL.0QS,Àq h7Na U91/Ҏۭd!'nb6J_>KM "ZrC5I]"CkV9ҕjIgÔoY}b qb 5X3rY[(]&mS{S0<3 L=(?L؄6@KG@F<2Ȁ-yDVk = B!AS `KS:C|#vMs*Yq=^,,۱LOEZ*uh_vM UDD+ jԎX7Vq4sV0Q.n* =p,aJ^,Q th6BNYvYc$Çk0 ^+oG&H썰j~Kes+i;\jmU ; r|SN0 $ʏ#0s! ,Pm@#ePxW6F '|bn3vu801RR(oȇ52*- u{Dlyfq\B]bN{ӕЦ E%vhy jZ .`CIC:(ygTcM * ([RX0TiRaN~UafPAA)mKt h􏃲B.)ۀAW4nim*捽-$ U}OQ>e#šѡ R(cG{*QA߾Z-W9'SS=06sjǯH*KT`ts =p6({gA Ưox`1x G6#fL#N,XrA9، :u^@C.5=z%#D̘J̠nk-gocCѽ3t袢a}/F_cބĞ æ}1M/צo!b3>ڽ[uM]x]|j>VCB0D3`vf ͐`Dr1S,,υ*Bd /%,8HmμÉ(ಓ dh=V[&C;>Pza~W4nim* =?d!r1dMDJ?_lnA75Xho}͝fkiJGg[W͝x+.w֚ޭqx\I)r[P0 L!`Q025%tR_d<l p@@ya((4Q}W,1?8й$u<.F'%r6eRZL5m. =3ם_YۋR9K{_=y-10jă6oAuWVs]u Ub8a=$@e1CMt ,0ABL0J06E hB&#Ӝyo;DH Usх,XAsl1یG S0n=έD!i9sb{v.se[ѾG<ˈXcOk:Lwŵg+y4jj 0;Ά#+ bS .w6 vb*e`Y@$!XPc-g3"D"Ef0!)& b ުc @bbdLq  "`վ86U mJXs*v3 Ezݯ iɄ-Oړ7zCdO? LMIM,/0)FD3l@#2p (2>L6_f DFH8H`9(iճ;4H>  [aX$m+țR^NZ%ƇR`2!S4ni;%ͽxŏ.OVwQ)"u5}#{|cxM-r]jσ{{f;-X4|>B0h8 p8@d4I,Ya`ö$HgI !1g'idzAD(e"8=Rtb n)pqMhql+VQ63Kjn d1[^'zkԅskr4?z|mo7'αTY1VsÎ"|?˄ EP0u2H1( 02v0 &5"-Hi$CC5Y#4L+4̝0Li*bBV ,"1],2+9qY͏'LN1W2ni*=bS{hSǁ0K@ve\[Q61hz\ڒx7;'׭$e8QlƱ>qڋ$HTk=5|^V!+D^iɦla C6D +k6qƎ~GUJɈzL8/ HS&sCh13s&0\(7%e` ;eɫMhl Z;u5D]SԲ.,?mOwԓiN12˧6Hpi\z;śo *A G_& υ)'AF-2# $15,>lG(&s 70k`<8Ijmv'cH#:+,h?W.n* = kDFg>Ҧ(mִg_a|(-{y6Y>bɻes[9Vϵc^|FmAaـΙgi>vbfk(b cP( 56d>JZgZ~d JHfrF90FNCthq edD@PC=1pp1A^HjvEхw>,M2h&ќtTttd2#YY(%x 䙎ZP $_Ğ5R(jsn+sZyko[9yui$d&:Ut #ٌF*2(*P`@hc*=!L#Xxa`8bpS4neD*J5X ` v`3ja'. fl`mC#. ln4: (2Hs63 P&931LqE$ PpDp3V /fP9Cӗ Á8p< c1(-n;N !J{Ŗl厵V){ǜ֭yk/ʛ|޿c7~8ur H>)b!ҁp8yh 9X3ۏՍL5dƄ 4&8Pb{,"LaDeMxxFn&Jb&2`i4Im 5<<|LX. S `8H( ЈXN>0,Lu^rnHJjPR;{u޵(cY2uc8%Qʵ=JuOa.1{'nYbOؽP)N4aj&uK\4U9f~k陜`of,pfX" Ffkg|g`8#Ed!FT5&`8J 0 *;e^,gAԹoӊ[$޷qwDJM&Xc(W<}̀#*n6 49q{ʠ6yͱEv"n̪󽯿/Ƌq5Mː{2eeo軖mo;ыs;)u T2JC%)6\/wIAՔDtia8%`-b s0 fjnc t܁Y-:) m}_=W YL)"3iR'da_hʡ.;Q\bO_ ~6D߇ [)~{aՓ=HMnX;s/ 4 S$NT*&ab. ((4*MIl:i  fŽ ʐ+=0Cу0*=[`@R$#JRE1,)fCyndl(.}9OHmh=R @Y|>s]WuIsǻ?IGӗyԛMP+6s8I򘃇">iywZĔl֕a0,di~8':̪4HK A%q2P]| C-.7i=S>&Y"QhTE sSLŶ4B"u(%2w}M֩&ɜ[Pp%~}Ӻ sGNo㋆qڱDQI+Vw ~Tn## `" cC$&B$LhKXS!LxgCn1āt"/DsL \aU>no /*=m^d˲qnrlI`P6ј rI@}\T5}FlέQgLʭ1Td s҂٣"Q+5L:q15 yT^p8$TeFq0C;"`jԘLy,}e#eJgz}^酆ta|p=G8V|Gk+O̚q}~?^Ţټԍ>ux'9uuYZTGm}ßx=+ QR34} Ba± x"Ɗ:*(dɈ2 I1QғXG䧇`AO>ni5*g=ߋ*ﳣI`74J=!P[5I>wgܵHEMgV};_n4MY1\Ro0ՙ >칆*( V~/ `Y0K966c$y1a PPk* u bA9f#FxLU 늖kP0b>UJPSv7nwԯF:0XWbS%38@[sɹ j]o?3t ܪԛ*H;lUӥ-8ƮϬCiъ`qTG4bl1 0X/9܈ 4 A>Ctx@b@yřS0H_h#1tȪ lzb eSNma)=?*v#B J18X.>gPPJgGe6}߫i.u-k'?I]ӯ-7>(r;ՋGFX` I* !1Ƌ ɒf C"`y I5ʶ4!g6#VDHD0H5͕1fA% /!aET:'Za*ݪ{\e4VQؕ(0<v7^+N8~5޻Wm84Ys;4˼Za37?릸ѻ@@"Ъ ` 0قxY/^5NAY=J_$!ĸ>,(esG sj\ѓ}|~V73S:niM1ޓ0:^LUoXAh2bR]DlFDp"3FV1a9Njp L@u3x4e`Gpt@FX;xQ섈"(E8b@Q l0dhR0{/:Lnnn>iz`&a@:V$@6uOJWCWd/(vHfF}a͆+ a`o1 8Q1QD܅"|˔eFttU%si-B,E`ܧٕȘDnU|hKA*hN0WsV'ĝݔ=znãS@ni- *' =O{]{X}VׁiՒNA+*s 6zEcy'3e\#eM12(ʆd20{q=9+pK8铲mͅQyBr«lHl|KiGUG24D\׶+N{rO4|Bu54zz{y TfXn( l ê(1qB+5OЀ`dk0O{v|) i1I8ni*i 1α\r[fTf8bH ዇Q!Ya(:a(\ɅA).{.̌l8Ȉ":u|M LVqPD@i8uG.Ts?noRꆖM tuۍ̶9ãڷ56[-Yk->_* jAm+@8bS ]ñH2 'Т r ӆ0s)-L)}8I"$nG&=j" zgRxRNlo1$=|Ia:t7'^YfG:Caep﷕ UY"]v-&Rxjsa)۸P#5A0X3Q:7?1 0 `PC*@pLL ^0a YC!pAAb@WKo, @!L8a(2|X.),?fC3^Fe@B4Dٺ}enRώSW?/ݤ* ~ WBmaI/jNUdsvړr)&ݯWM8k͏3&bL7<ю, Z4yt`QH#LBXDAh%D2"gh: A[E Қ=]}Vlp'oJ5,hLWCLa_I6/OO{Ӭ]y7[jQ7SS ?eN7׾t,kq j4f'8  $'?! 2Wy' ,FĠJ !!."8r/P4-RW 6#Pl^qu@D| 4-uA!CO4nm*%mVͷϷڹ}Yo*{$o~>{_/>;˖DzgvJ8,`DL`! 6"|+"MjHnױaA|Cm{wO$.40k2sѧ%JTޒTfg>Ղ0&@ o陚F#jE4"&11 @٘X n>4,y("?t@I1eh0p.\t`K+iNyl.=ZPоPedi^)65pc&;WDm*=vJL&ywQ62gq\vHon@!qAaPQ9q $c9a 7LR @R)0Ѣ6|UhNjA!`B=9b. . 2 ˵n HKQd%i)!gMKwT7n_']P'ܻHwS.SH{(sf>1rb75 +Jf[dԹenL:Qs- $z"2M=@$~ŸcK=2D@1=רN b lfuyY.'-#֮W.n ͪ =1<}4;rɖw\<=@+YTF+Km DrQ&A"⹌ V)T  DApmѰ|ˌ2!H3nD@8ѺÒg#Tԅʭ2gn&L[5_ߛ,OT^Mo뾖kem(qu/vHZvJ0%6FG13Ui?24z52H3071(33XR2t/M> 2EE T108!pQ@1+ ` >a|P40hTLF Z cFT%i?Mp,j"تU2n% =m[ȳiHO\hk${*܉T:R^j8fsڔ;񷉷 &`/][]ö淁tskBog $zs5 bEB &h*܈,(%JZfzLj 4&d ]#<xHI2%a, O2†ADp"iʔ9v_"Cm h.I*?G|^szM%Nl,oO+76 kESaܟ~vٙԹB&Ǟ }@ ;ɂq0*1sk B944e, g-F͓5GLD@2Blh 1#`(b|mi#em<O.nmf=QWOƒ,p<]pU2rS:jwoN&s8qyi9 e٩$ڟ>r}5}:&mّPsH#-C@`#' 3 C2^b JlbP%0PdD s Ɗ ,92915B'ב^CńQtpJq :O_Ǝ.S@)ZwثƳs<^PϮ.[ sy~ps=.\*nWjjXmw*}G*ݷmR΅Zw3ڞ8$`q(c(߁$؜bZ0Y1|XQ @+̖^2d҅$R! ؗU(n*MaA!S? B&'6kKZe.`Jhr]mE*s$kp\5~=A;{9;Z=gwt\,{}j ?2=j*WGZ)iZ_1s?b]6T`F6Ԥ3/F04C)M@0 uċXһL 0jL pXF  P7PK6\ Dś(_w YU{i!/*q2mDWݗR4?he~2;]x8Ý.7-]Ho>emqh@e2F.`/Ffh̍BPnOJBJDSN&REPuW2nmͼ"ImeW3z2JfYh$#l62wDk_r!b>W;¶:+QR:\u6uSF/%3R:jkơv U[7[3u&C )5)YQboB`o0Tgyxs N)&[c+K5Q*n*ͼEP Rcv<)al*O|- "<85 ǐYZ7jKmof QIr ]V\!9T›3`SHeY a~$qh\/)&1U9dfXaf&prD"CtLpBe ,x &@F+V!Qza @L1u2\B iNsliclgE@X! .Rm54;M(_0-r-j-{1؄ ?;GaY6Kpii~%vlZ;>E9S1Nyo]8xn|m7q#+\s]!YE1qG9@ba1X"2$x YEtH P,ۘCheAf~J"' >5$FX0%!iAr>B 既 ZdųQ"ҐeU*nf* ݽ@8VΙb_XW.Vc%joX;|109pcw2Of\{ u!u\3}>;{S]P $ /8 _ -p * :LaAĺ@6K1:3003Sa] S3 I qa̼8yjjMB<>j4M͞66y>h#5񬴾4"ni5-. 7o]Ee߭៰Ϸ .]5;˫t[qvNٗ]noLSP\d44\@4Q 13*KAH JK(!URLO%zI3UY_P1Y=,pΡ}HڇA5W*ngse&gnɋ~w_V?RH:TDcWI #J8UX PHȂ Ev`_42|/1L2;JBIbp!P"d 0dDg ad 2  3@P ]12P2{QQH$@eB ږg4MDU+N*]w\8sDf"kƃmWDڵgnw"\yIL<{Sq=۹)2|gL2[rE&Z:0`,Lityh*PF!^qPݯ˾WeY`_bd842Mԉ%a=y%Q(n*獬vS^Dmz }SNjET@RAH[/ ɾX]6fr "e@WT (.\Y ( 1!!눱fI`0skHI0B=JN8%1"`91KNզEU*nmҪf 1c{+;0G'D BG0tfs(V'"`P] _sr&DDc "\5-b@ņj*51 ">0,1&2>aK HMkXF6 LnR"Qx%!Ph>5j>c)w3Q5gSNH03y_'IhOTWډzvOau7 ;H  P3S`5@ `M"56Lҕ:SRSkɒ_QJURޘn?}GٜǤ *wU'0baV {a kq9VNw'w-9v)]LM8PPeW2nimfM1*L90y4#e 3lĠ   GLh! =",9/  a\?q"z]ZYwO0M iT؊\ĝYYفXel?php2a !"#=U4iBzΌmBOܹp9j$[` cL2Nilca=f@H2Pc8Ld5L#F6@wB,U*XjO3 H9$ՖcaWB9C!J8}]i).…:5嬞#V@^a/#UvhFg[a8^Q@%B16sZ-snf-+f  ŀYS0nmm*f ͱF%4iidA. <@h8j9tP醐(Kb k ŲZo& 3hq%T)7U &UKdYarxMPh uf ,5:YPP)4  :Tfqͽ765?+ݪ^\@Pfjqc@FY(e a5r4Ck7iI}TKi#;E(uSóS =s͂3CF&ȤU X$Ls:4r#B@g A !(>rP`@$ (!Z"V R\ǟ}Fό*\͸ZWohu8ԫ~_^7DY"my߬؟rWM87V~Z5-kivUˆW xNqUͦQOu6dL{^e)WcTd7t4 aAes0I Ca`5aa؈`1 `4D*7sA C@Gn@1$d`0g&3/W1P:b 1`@՚3'LTtD"cхՔ ȳ~.Ԣz[=hk z8Z!_Yꮲӊz¤~w͟w?,ڇ㼬(qVἄ[ G?ό_Q<޾ aCCs`><ƀhְ Ӏ?.nm=d=0  Np+D BRL<"e*0 @«qA c#^^`TOz2NDYd<a VDmJt¨6SsVfpwz,'+l~ 4H?$ݺyOIc*^oaԱjzŒ ڮw>7w]A@`V@dXS\J1H0 0he0TF & &>-:@1y0Z yӅ 0 FǀߙIz$p=~cUGr?\{j~Lɲo~7Ѭg|]ys^_.w>ܞZz]x [$c^MZ%{g`)ԻUaA'RDcFBU$nMݽ`x@B"ns@l0ɗyl&QH څ(*Mf-JQAmЎ!,ZGvfb` \>ZG8yy~Ӫ7M+O3 i )CRm#()Vq?Tr֬@AH.䜚.W;AҀԐ4TǾ0FƋ Á&J $73 cSؔlӅԃY#ToDc+&LHDe!10JTÐ1]9Yͩ9f[TN6Nahy g@Lf0+Y+p_0 <4Fc$&L B4c̟Z즌 DSQ/&px\UT8z^+Ka5A&ҵEF<#+\xȝi3l~>Gw񪓋=/oM97ƽ}kߒ M@&( 1 l0@Tƒ&*izcAP!lMS,nm ͽHPd@J,0Ej$ w,QF2 f@KJ&n.oi;w $g&';@$gp +R 0W>ġ$B ZK3"2#:lpq]E4&_IFM`2PrelV |JUtV[Vf_+VmLgݹmY=(nmӥe =t*!qJqw˿n?|oonxWK}OrZ#|P3b &d0)pTcS@(`!, L_$gLF<E ,:p1#@_c1o@r l?1̾Fآݗl(2YS,>N1~0pqq4g{ֺl=a%|KXٳ6MOd6 b& 5!Z3H40d8RuC-}, zheB@Fhʅ+ :0SS2a ʡvB]> Ԙ۾eBKگfM݋7(ni'e =cL)n7P2@i뷍Q\s~X/muw[GrƬk-˗wܜFv -"@ٚG.U{sC\fo].B7&nۥe ͽ˛,njT**<53Xݫ?{L&[ݮ'f6&,]mmS}C,0 .q ﳍ0dA;lMj~R+p6LHvƖtQ<,w[?v"%UziЫY+N;pF %".%F | ̠`"ui&$h+: M\.4 3X`q# 1] ɉcM|T6qE/`8F&8{MG(n̥d='Q=7 A,fwG!i$$1}3yujFx Q:t֜gmu~>A*`Б/:l0`*I NQH;)T WN4\df"#NFD V#CA !b䎂 1P|XNdmAc5X~_>aT.)$O>3TqᅩʲueFZ_tFk X$6nw+_?~+݀ L W/F)!& a6 R@PH2,.o r23fv_bi"p,̊*(ArDz犡 iLGi,Z8Cz5 N(ͽr t``#.se}9A(zx|g8]1|&u_CȅӿhǏbiu ޠx}la و8 0`oDE:G E<4`` hIYȘ4,MEJ JQFzZH3sL2bd(ϕ@EbfPAf@48)!ەR6iQD\:vԷeգ3ŢF~~}V[<:g."/.57]Q(?Wf;CYI`^á0d:US 5]2ASO$ -)\YYTxhI fP +.,JMݦLצٷҴ&[y7C%X٢a*]@&iwZ7l ;ni-"F/&Ċ6k @hDLXlFd0  B'8X` 0u 1!p{ `cF "4:`fP &ʹ#NMݽD4 10VԐac 4dܽ$Yx `I%" if6y0y3rgݪm@"@R.7Q.ъPP `%URptBJYRL ;bP짯+Rb% 2mV;r\4fsmg3po8uD\HSjjkقu5}SmgBmH ďś8Q=󿬎| 5.ubN(. hj E1qȤL"%VM^ 2"VD!؀G"n$dͽ8`h.BQ2An2P8X"NNUN.(<֜]6 Tc)j_!{]f+\)uo/lG~_/4UU#Eu)]c[)3.پq2-ua׍ϵ8!Je[UBɆR* 4 H!l`8HX0Gw^@cC4 )ycf'$nmH$ݽ !q0gc@vLT<ւT!L@-a;!c =.f?\Fm&r9.4 !#n}F_)iߒש7hhp+^#k0YiEoWޯw@a ͈N " D cB#FCS C3M11hكŊ ȴ,"LN]9!0fCBaD@!g2Y8na *|#hOU,maW&.RȤ2{ZW9xu&ӿ ԊcnOpSɾ]VqW( iD5y%ۗs;]tx2dov>Ta fbDcB`2bvctKE nW#tL1 PRyL-ӒLB`(#<}יO;6BL=eY.%JgZP;1\`b"1m#2,G{>EGCZ:fܳhI|BRy#KlG=k7945E!<8ixfB[$}ܯ impU$NO 3B9ąPKv[Wa]2*Ꝝ=: p\sVϙ֜!ukT i40Or"ZE6WPIl3a'KI߼rܯWT卲ƪ 1Ȥ|bCo褼gyaDHϗ π9QN.c-^Er1\.Jpg.R*N*E fCFlMHQ+iHrih cq.0qJ&H4W|j63J5Ͳ*݉F3smVSMxF/z+_-ZnCS0Jet鳑)U *g7b30*ᗐH LQ@I0#)1y1AgAV숫5ŀ/Lde *.\(8KmBΧ 8V8CIp"1@/b@W#ڽ+֤{]{Du)={Z? [VX-YBm퍢Ӫ荽1(S'wфoO@mlz`VHh"UP.g %pQ9 'i*`TP'svuFda4fɸR%|l@T'b_uaT/1]z}r@ZuK0ňc='p9S j:lJ.@D,"0֌ P ES@3tg_5@I`&| nM=4KJH1D Qa%-IG !/K+#-Z+,lj= EҙiRHӦUjзoz2sVGn6M jpvXvO@j+%YE~ F:yܵ%bEW@mӪMAfѨxl,-"4ӰH@4  M pLv.B*G]b;5u؁u3v$wx_5tjsR9~yԹih L;3 AI;tÁJ5HFaMKN"ј ͆R&_2&M2cEd1r00a#ဖM.kpn 6L]Ds𠡇Rw]#orφ9fsftLE"\e>i ?Bof#c7F8=m0f31Q2SDlEW@m퍢*ͽ=&dĤf="h _F89S8e,47TƨU3bj҈T^ϵAOXkmٍۖWjz6>GwUULfm"p>`a"hj y`^e.n&F aPʳ6gH4Q`s:.{295gSoL$9[Oj$"O .*h{iLJHDGd0^A;zVa-+SkQ^RBrb^*4Xr`lG6v ڀ M'wiV@cNxh,$3CAք' sEP <,~6Dq|W:ni* 1VHͫqK|e ٦[Ey2x :x4pdA2&)J=wUr=nqsžУQ>)KlKϬHyц -T2H2xj`03<8af| V < iHr!&&wDL㈞b! 3ڡV NeZnC_b犏QDlj>ɇ=}K)%pShko*ZQ4E~#UMS v_HTR> DJ T>ZtȟU@aѰU9:y)6g_ێl$ L($w*RX|D޸-߅Wp|ew.RZC;Yگ78YΘ.YtKêe֘|,c⍤8 08:0AdoN0@NR(!'fl?0>;fW@5gW4nm֪荬=\^ OEz֚ [qHG#w˹u|}ϥ6z,iwubŕNaMKuYy}ތ  /=>"#lgW>GBmfB!e!HT/h MH@BU02r < yx,ebp F% ZOH-J+īY1OcI`K q4h$GE' -פ3Hve 137`ܑlى#uwy$Y7Šթavb6B+ՙn,?bueu^+L~T7q|̰S!Pfp[ q0Lأ D5qVi(9"ᔟ}(rE9(.8ܦap"xU wm3%lC8g6M^>u?/NO;.i#x [AjVIXfqѠ\F[`<7!PтS s&,af ( 4BPimy绁W8ni/+&ͽ4@ⶑDbf 4s:HudLڵDD W*Ƹ!+d&bC2Q ~kʆyrwZvQSz6\oY` ڢ]qhb)? i M5t#(斀kqI*UL#t0 $%@`!0@MҀJo\dذ<ƕVe@} <QG@Γ`(3&} j>z9J'䖮i3 5uM!"Ϸ>Ϥg햖OaSvXtܱ͘@l@* 1`kHqdB d2f H6E ,A rÁW2nqݪ =ECU$[9Dw# FЕ0BCpNpl5۴6#:J|2m,ZS. w]mas>^Jt.݊iq]Z񭛏haǐ!-:cɝRe _2a|cs: -Cz xDFg `%2,ŔE݄0c 3wf^nB>[m䨰@/uJ'_GE@fY¦vM{L]w1i>ao{u{Cusuc=2^ۊcaxL6[p@P1l@$Tvh*iI&Ђ D!8ؐTsxD,1`7X~uY6nmJM=DلÀTmh*jC`yȦ-y@3x`TYIT FK~դʃ QvRZÃՒ+vsmJMj4Y εW*Z ixub;2jda?+GSl4xW2ni=;fƆ08P\73MT 0GH5<i 0|ewKWõ,S8L*$1i"nf*g}jGYVŠewۮ6oRfnJѯh/Fҽff8gwk47l_ er\%n!piyx1* pQ KH3BQu`V*P`$&TDT7biS>|]/Sf=>Mdt13N6EoS1ܷ܏{u#CF/oHhr|+/Rđn$` e-Sl^"*$OJ>Gt)By Pblx1W2nmͽ=a (0dSAE3Rf3N:@Ni 5p(I4jwLӂ"C-V(ymoL\Ħ gl7,LFS8Yq7eԳꖫoe.O3ʛs?.uDz_FKӾJm|cFQcS+0h}/0q-*D]TD,Ц6xC;Bѣ^gYI#ny`vꛬ&)-ī ҡW\ӑz=x0S>T.cص-+ bnY#z^?qm?ͽ&iRD `J--RT^qfi}٘ z{Lv1sa׾o.6s mmѢ+i XӍ9RA#[! S+srPƇxr@ò`Ba1h cӢΓÕCT($9 JUx&9 0`$@!+AQ͑A;1}= \~N M1-RKT;('^Zk[2λ:~Wϯސrlf>wҹfN꘭ ^vNz\l5= ?H<lS?M~2(%JQ3`tS t`MU,n8*ͽ*@,\L$H`U(Dž"@+gՈ T%m'41BUb1+k4泸M1[6=Ɛ[kd>MRےs9gwNGWslH!j gn#]ǜ9l܎yoWu@O#V2| `p3C4e 7N$)sH x `(  L E S?q"0KjoF֙T{FJ{ͣ ct[&Y/ڟXLVVL57h}7ڌ7Y~ZfMUs-%t}({Ќ44l L1iLIv Y.nq=)ͽB@a`iʔ q  "aL: pFa!Rp̋zbel֞HVbL~}\A`w1ZȦi`X4pG❣ ZqCuG^ fZnuŌNm]o"SpDaih (G 7u* 5v&*>Aý/qA=EU*7 My%W%B*oJ?- W)9%zY\Ňal;IykKI \Rp2X^Z)xhV|bƐ(Mhe( \5L\t|Y,(4D Y.{onkSBmam*獽=P5464V,Mr+CVՉWy-5ϗ Di[Cn-ivVMs­',y_rs`w::xnQbJVN[B+fUZ9K)lŏ,ʀ(q2 K (A @ꁰ\X%] Q4jvW& jei6޹G_™04:lN#Ы Iyw4䰅΢Ry -(laBUIjsJ_0NJ ь:@HFDɶ@I!%=b =IʜRg|xB.)۱ALem鍲 =qm[YkOQ{2͠|f.{\O;η#[<ĻV ftvm+8Pb2|G&K4S- Iٚ0pE,4`|E b*5$+ہsg+ 2`IaįxmH$3.OkFhlVBQ8ƶi ǃ_KO9j)bji(sTS˒QfD"CT((224߇)|5 ;(o1ASDo1 V. m卲٪Mͱq+mfo4ձ)b| I&1DO$31t"ɆBKܪ9,QɈ5VoCJG`aмz*,TVJQmG,0`qꇆP+D]ʧ̎ꄢ5].Yvn}n#W.MIbb}m5wW ܰY܌]<9;%3jHv%M(5kpAs+ ̈́: 0@&yx(_hQ L%p}`|jr49BGn;b+ dٷMK ;7*`>d:lEvm{XX`KJβ)o}W.nieͽ'GI}pӆ9 8{w%tyjƱ5ġ͡f\ű(YDGGL S#/ͳ4#c``lhdhqpVbP*OL`1`CIiR^0n,& LcroT9%ZQ[f !w4rU\-{ژG;r g{}Q=W)nRֳG5xr寡M` `6dcv`d;c1 ihgfe6cфi6aj``` baH"cx AaC 85L H91hC (HB00mS&u#2;P *2Bp *"gFBlA:y2!JDkR@s$dIT[˧H*AIcL귫tM;M_ ϳ9}M3vM7oc2GCQ2<=b֦1QO_2I!342#!0# ?1s.1c$e9L4 8p50cxܝ~ sU֒(zz,VueN݋;U&զvjg;/|-0/ĠJ֔ +ؿ)H@RxDMd!'DsC '3H,#k38RX 1`h"< L2<' Z2憹*,`ÙѩR[ q (R3"FG})^fP%1m`{ AÄ2nڦnmxwﯼn~[ ɬ.v3~MkSܝ]ws|=|SKRT"{#VKWaL=P*݇W[[7BDb@ҜRKKYH[Z|Tb rA5Ùt<"-4pW$j-f:u9y5jue=k8Qy!Mb4|QJQY},U,@nw4WAsdbtR=8\R͗ y0KgjuS҃Yu#ʦ4L';v?=Q|"}m>za)oZA0VV띊 mƘ@QHRv(Q"m+V5%4ţ>M7B)sE:X<M':R'tj )e}{j%STljM=&([7cs/NFL cqؙ {Ks0wekX{Xjk8k6n ܏¾IE5ZvHhK4<3@M0$M;kyJW#XLq_:j{Gz]a{R=T)mVu߆ĹJe)6uhA.e )ryK!% +c̑g9E:0P >O8I2cO^_DGGnzgF*bCؿe4ZC VM!/WRma*鍼V`yjɈj#}F>.ubj,IO%S2=+*xQ }܌nL̶Z1bј4P^ )Rq(:LDŽZ KV b#P4 B*4qPhȃDoB;@&3'aڌHnˣ42ωd%wO+ئT޲Qm+s{fM{{Z}M+ %f5۴h;%i.ҷ;kb8 t蘰^bSȒU*g3po4H1Q><:,0 De&4QvE%Isί2Ux@:*쒸t ]uHˊ.屙Rr_O 3dhEحU>nm,'M=؝n7=^EYj媺Iּ~lj_|_8ݛmZvsMorG@ >5H0C qi&\.Bfcfٌ8scT/@b[W}E]abu>S9?[IT)%Ӳ+Xg=gU_4HS6,Nj'^#w"X.X=6 Hu9߷%h dh |tfb@ (:a+4C <(D'8w`  0#FThsY:nmV+&ͽ:1i+.~!ETIā J6̤6*9J~t8a^.مWO˜H_-[kff>I-/Mwe޷E{#-^x/l fTڪvZ5 d/S hpx h 9ĄꔂvČXS.8hd@D"f~"H, EX:qfbavGJn.*IG4.]Ѯf֭-mLƙoRo;>=H)yx sζxoK/:O QrzB Ηj\OS4L!q `$0C"8Vరi&f3o13 n&"p1E'VʁK5p ?Ye$hI KTeO"HU $қY6nmf&MݽO8c3zy2f'k>M=>,'ÎumᗩCK~@   #qhCa$jeV0; +U?Ń*S@BB@0E70I3I">r8Ți ?Mr<WAn;~K+Aڿ]b͕=o{"F&\zo^4UUcFdzS:>O8CHwi{p?`p82m荼|Ҕex8Itt /N)Uᄈ Ft8\` u1 )&o BRaquwq2*A21}H%-ĥ=){TNC-ۀڮ~wBΦ6&*>-Xޛ^w gloĻYݯ.zOXO+)#NpIu+{4ᖘ,sɄEƝ L61|12и)#@QGxlajá kedy"*"eEcc6"c6C.';gҸc6D4ԃVPpO*3L-DCbc [qZts&=V]B$/9ܔ!ZA?#DVl@AS:ni٪' -F$` V2aA@졉QStL6BY 5NxG(NCIYqBLb2 -+#G'etAFm1 }<#Ḙ̑;pP:M^dkK?fƨ]x9kߖVj԰7'\D`2??oMݲ=:ѯJڀxfh>c0%H 3làT%<3 9 i."S&<NC-KLȀ)k=\ I16 qmתmᰴw(7. }vГ{~r:Kwjik W>651'Ծ*v.pGU0nm*fͽVjuht4H֕X!4DZ$0£בq &I"D)ڟAਜ*V_B h*@X3S|̭NA&ND*L3> 50lp$Є k5UBYXIyI'[A2GC+~CG=(8(c3\|~R}|k[߭۵b;(r*Zܠy-K٦٤@/a2F(,oP2!0f8M| Ƅc BJ:YWzj!& i& J8BLXE8l &" gkfzX3`@%00AaL@PZ\Yy\(khT7oWY67SSYybyRipSR3Df+k?WG X,|:L(M A`|2E cx0vB4` A0TX" -yAq0!4JRuQAJE~Q7檍2PTɛlY.nM+%ݽdXǦt,߲PZRnddxG vrkۺ%qLZưQh{־ Z_kfpZ]{m &q: !Vk|]U{ݳ.pie(Y0n荼~h">-z[W|v}Gmǟk, luV"˩[ѷmf }% 07Ͻ& 1f4-1IsL -&LR@aA0 єUXXAUNF7[ D2S2e4S]arjo+L]s4 TV(|^1G -t 0bpSrY՚X T\.Nw@LIVHmM}#H[dκڅ )'>vww<#DGkV"M.bM7I4o -U4mC} [0u˷ bf7p9  B:fҫjBD" 0oT1zTl*T< ؉Y XPH (9l1¯\"9TEڨ5gAl/g}b߂h~,_]^UI&UV^?qehbMGsMU@me*h SVYW8d)7; 0O*+0|ȡ2ЊfPBWK !ӕ>2`" FCh <:dc@iD'#*Vc:Q R! o2e[x;>92x—eb1uq]4Yڙ _,|n(Uws͹lz 5Ҧ`[e HD:@ 30g *Dh 8.ؔ3c"*JmJBٽ<0+9cyLS ZG6vv w˫33]|4כ:;V*:/ %D[uIC ΪͺouO=bItֱ Gb-Vj |BǘkD>[?L=O0nmmͼ\0Y Nh0(a3a111@`0h& 53@[2b 9H9RHmT"D e%IJ3OG5k'"XOӜ@ {sarGKf گ"7nU泬Aσ#<ᾪĪ4&q_ߣ ;Q0 V0Pr1ُ@`@!b{(iK b*&g Q04()KƀEJ_ݵ*܆Y!H xW8u*x,S_j"[L=IҪlsEzTS#{~6ZBو@Wa z (gJfbрBmh`pr@3k .z: 2 qDx&JHSS4pqG*GfnvFg+^Uw_6ykcxjMÎ#$8mTy+dH@$j1#& ^L3Păpdpg_F9W:mתfM=ZR ɑ<6$r"BA xXItT}]V(`¤T̝$bP՝v\Tw\gLùrޚO[i jKzk{C}OW똬xk|O]Bw~=M>$ZI|nG?@7 0z,꫃. YhBđCZ';x06oFؼ`dƅƽ' 2qD&Dԭa88d$AT91' Ast\?լ. ̲4ҦƩrFwrY|85n>zl^7<#mb>ֻe7>V쬀 Pèd19P3$ "H5 x h"gBO9Q*nmeͽXXжKRp~7W=^ {Uֱoo.v1<{fzJ;@,5S3Ha@`YN  TZ ) fTo)Xb`@FHLj4cp6Iؾ1I US@f#0(*+-*&#Z+xƮ*ٛ=9'{gE:BB< K;PKYѕoYKLB 8o|)[I@a3P31 EHӸ0@`0102{hR#B&}!Տ=n G,n(ͭ&P+W-JvݜajR/Tƻ (a啕gznXvg n(B])"̭9jik 2W0PRsGP@QeEGx dٰ&HJ2H( ` 8E<%e7 g"L q"s@"i&D:m\&u`p Oʲ}RV;-+[2!6}ȶ&cˈf4IH +NJkNgԯgT23ΣdR4P0d1i.0: /b,PyI, jN)4_2r7y 4Ā!UfA WW!DyCnQ$m U4fL8%g}50Ǫp=7w6Z-'~{>Pswi[M]0K Mٯt EF'wp, 6&(Y h4[qךZv^RiÎM<~`h ӂsUkٓ%gn,>opNٸN<\/S)7oᮠ `Qɝ@L3 $  d R!U2sCl8Hk " # ~;QaaQ:dAF1`yeO2f)ù_9z-NsCC,nmmͽ"?7Lh͌7yt~r:y7onݙ5l&vcAّrf-j A(0=0=Í|հdCH*[- gjT2< N&PL:nf@U(9~Jh,'&'8J#|'"H`PP\S?%4[u|u&VS<<g M%뙙-F'e36F!\E- 7&`HL`,BQ4@*6@k!LA00$ oY c5[]A 7L(Hnh .uK̭SO,nmѪ5gc5__*H7~ k^Y]g~mn0'] .˖">l3% )B}Â'PQ3.8< A8촆dҋ̘0#y T=vBL6qqP 6PŨFwmX:&l$\>Dnb̺nTz/)Id H"6RM66zWͯ'6b}6V&Wn/ 313!ٜG 9Bj9Aƣk<#PHH#0e&@x(TcFl@ C1ɀ `i: Qu4<^̬mؙVA\<ܳ"}S,nm)ݽEΰw̫J+\+G.2U4kZ_}1xc4]oXu?7@@h`(da2  &ƒRDIV !ɕDłd( 0"X 3BeQwQ{H@Z-4l*5:.Y]CⅯ6O[]I䇽o-^׍4?.y2׉3,h  0¼Σ,N)0x / VpllPp8`Ot @mL:1.LޚP\ I r= Ӥce`'-?RXvi=G*v/5j@" S(nm*eͽGqkn | `^|hW[}{|8Csfmlehuh[nI) t} M=L74B2H+-1LP092uy& IN*XP1Ѵ0#l091^VAJ>)S{e Oer&Mݨ'DqSk]`Ǻ;&}xZɜ^%,؋<`38  WuP@ZI~%ԙyjYژ5?nom L1.)>ںʖ}tr~W xv!♗Y6>1%( `oZdXf ܬ=i(c8=F )s!'@xfA@17`F`f_ԀS0QyȢ಩($̲jHO%n%ҫnjO#7wQC&n$ݽQ.F)Ɓy}ެݪz̛;o7]Ͻ xTgi!`abP Y8R 0,04 &\5 5 FQ&dƄND@m ŌXYu[c@dK ,BΫB{%Mՙa4%1,E"'W0#֮=zi_8$W{ڶժ|;1?;lg7wzjR^yl \ t:9M D 8 j2ٓ Y0$KbP Bf) $\Lb-0N5ކ>L;$N/+$ݽPt U409T)45,*ń3*\P$CLj+7HqfTų5nhڠ8跩FQbvCSВvh: ;7+qOv<^5[|aYo&}04`  $Ҵ LϪm!LXƓ @!p^Dz /2pcC&-K4 1b`aF d8a!1Y NK =A*L><2*ʑ-l,Z}P m@mQ.Zѐ*}_D9/8FQ wziXwos<(weu9g*E^.|5*Xx0Q=,Xŀ0f :fڅɇy C9~_`u$mJI, 0GʁDHp(Mx,H*Pʕ**D=Q$trd.!]øA#82cQL $XD`` AV#b+N{(P-q\ʚ%~eQ'pI4@d(i"i*lE/]WJwyf|{[ |_<,uBr(W5A3ՑgŚLyp'A@ 2tqW N*$ ݽJJ<+P| &j,؉(K0( TLz[DLLS j30Bid┩k66K ʼn\ƶDyrWv&ܭ>h>>g\Kflf,>s|23_Oߠ@\%@P@cQi$ўQq*`@&50ׂ [`K\;01P \Xi m&xW-m<9F lpX:k%u\R1QECuҽ|_[~ei딥e78a%, C@# ߄zHa,BiL HXANv0Z؆Ga3ogPQrlSS[-9rrN,iIڛ 5mjdfW+k\D\0|{ϑJR 04SR3O5QL4Ъ0X:Cb0,3 ] GK#+" p X(4 Aak6 h90` (I&P;@3 `*$0vb`<&qA G4J`.0@Xdžq$ D L>`10.F'C)*#Os $# itI@PHXy]d( ;XM*m9[ɧM3 ]_u~&'=KyZ#7ZLlnϵ(K, JsSWmuĦHhڞDZQ80x.01G+P3B;q-pQQfD$091H/0XFl KH)`hp1q =-ɡQ)J#qy^66SWG'܆_=2{vfsۄ-حEsre .XI SE= !2&DcIN+ˤdݽ(C2h@d0M"l.[ hpqUsoFIC\F"v"O&d}USyܣ3w^ν%j!A?:8w\d Bv29s$ EƩGɌaP, F&B2YA/XZaQP (2`7!$"^!0DM6`yT :%RL@|YVE8-^.y)Izk5qKsY2Mf)2yf3C]Lk՜bxؙ#$ni $$ tep-Kob2H- jj._6=2~B~݋\En[0ܾ> RF" f7e)Pb4@!,E<()[AxD#ȣ tpyBNJ`t.YC*Ph1X(pSPԶ;-8EA@Fu*cS!Y?0HؾtܰbLdn|fygC{xMO@P%<́N"p R01|" # `0`A`9#@*q ~(M%T`Q`s) FUKEMMl#\ijMԢQe!  qlo(njk$dMݱ&$2>8ƥ$Z[/9b?z;&W&r0S^`1<S0$ 0V01#c0A5@$0P #q0!nhxç8L ̋K.K1*TM5BS(K\52 ,ʨ:]@.6>B0_\Fz\escQ#[`./}M]8\ȩ0Mr֨w_ՍR[{:lcV4'yw;qЌSD:]f?}81[.Ыf@AcRb th cdaЀdqlFZgGC40c%$4Sq(x؉wLH* !U+ud;(* P bNT#FZCIOW̹-jeOTaNr!A_F`*$ O[La|ki6hRX5;|{9i' Hzm!1l$R1I~jK@Z9AͯNn&TJKd)&fO8Fni #J^u@Da2AP‡DI%$mAœ[C(5TŒkwEAj? ڴpWL![U+b8;ԺMij;UTʿmT=$~ܐvMf_#D47_}JjW-f-F@r4i6ԠkXT"Hqd Sv?F’ں~Ym_=RČ.-vSW2⑋l< >$3OaL=qkJ.f'[Z[ě>ռ癷uƽw֌3ˌ3 "1f2Bt/2sm}OFne*h =uE&a^mEbcMRd_Z`Ai&C,hpX[ a+$GNJIYfJ7=3ke̷s_e/I%Ӗu;|˻6gXRij54vJ5m+7ZjM' vʒ'½}0R7WCW6=DG d8EDlapG075~pd.@=vܘ*W(V;%:,P[;ɶ[]1~5\򹉪f,gU卯,SG޲1U^u<ݢ|-dӆk FYQYL΋[鬈@҉O$xoNy s(\8GHFX$ݾxMWBm*h٣tjs0*G͎oF͔UV8u~χ..z׭<9}K!( J2F0b:~DLdو..`9(t0h2MC LP+N| Y,bc! %#xv!&gHpw vX]1q^;bț1Y-)rBښ69C[;[,]E,Tc˭co4Ow#GY+G=K@mqCyX 1U@T||CD*\*lb083ĺ JR=]i}d쮠YU}ǚWS]k/:u4j7Uykq7MW Z6/RKl Trz03$ʦfF%1I0V4SFxv#J ˖ `jV8 fB1.RH<#Ś mBl {O>nigM=P~Qr& f.1;ڲWZt했˘Q6y;;o^qƒvw>q2L1ep$ 4`*na*cEm!j8pYLq!@FQޜ0CUsх_#3z"Q~n 'a&wMC +JCKD8~ Wo}^FifFi`c&sB (\q;pp bEĤtGASc޶IVXY:m&e@aCXsiSTk:Bgk\7ߓ~ڈn)wJU8nmߩ獽=ԑW3 h_74fJRHN7q3;@U5ō$ f Ū`ZVJLr1p&F."OSĈ 0"l2xmX6lذTد/4=LYN}6Օ״{#ex{>埮Á.-Iw=$2J7;{TSs-" *1QES C19%'74ʰilHMdӆ l)E#Ye0Pv0+5pPBKDY-zb"9DPjI@$9WM:*n> Gf)񼫾'g1SQnGlmI? `ɮ,FRNtm3Q98Ȉ]!8ɞtS@H@ rMir.2 XlM/-(Ju D7Y]LDwR}ɗ K6X&̳~D [FԎ K&u~OfikXۅt { UE~9L#LC9d 3R ۘѣ +`D\"E@r`8V8_4Ʒl/5c(tbgydZLMp]*FAk@pXgJ!)Sm=qH:n7wU6nm.ͽ7H:R;ͻVO#w-ZhH:{zBw7N,e N&/i5!\f1 $bd㑙@P4@T4 a:']h_aw5Rk ' x>yk;jsҳuY־Y>"j-u+Ρ@T22mz;gAE2LXhu1a  @" AޕN@ރLp ,$(h*#NL@'0D(kD0z9@ BP$;+Aum؜}aTtKo(#/6SU.nmm*f 5b3Q_ 7uOfgvcE%h;;;w;kW'w4ڪj7 P e8("SN0`7Sm1  XZmk! ("AQ@Hpr+UWb"7b"^0Bמ(Y`fr2FM~+2{ 46A' v;^]o13w-nLj}5;Ϙ>Dןr:7czo;ڶGݽ~%ӋL$ĀDÓ8BxC ԁzjDL)z5 Dv\F)fiK]x)ZDu|;swXyF|u­Z&^/\ÈH K\s7գ?s9R=Vf>Ey[Lh54aG" 37 *U`IaU2tZIn IgjQj%{ $6R(-%@μ`SL`xj7M;ut='"x1AI͉i"kXHXgϫ! KU[Lw< E 򡊕 +9zvQ<>Tqx,ڮ`z})",[}8P@hpҵ&Ss CDe!fN,8 I!rD4V`nab,]wIW0nmPMͽa㤡cF(,_($08`H3XuN_ohlh- f2VO辆ԡf;ak5,餒Ф5ǧS4cƣ?LZHջ5ir]l;~[X{ Kmefh)c* !31DCb)t<&ΉypW}a>Sc&/J]ze(n ^&DDj r;OBQXw'r_5ɪ'+)RR,]h5d-P.Q#C&m#_e5pO 80(4&Pf U\ ǁa0p S0H<0#@D g؅ ҙ,)Rc{S>m卻b%`уphBB~0Dr`rhy%&E 3v%4V]IRn\?V~տcbw:y(FuaW3vOA_Pؤ|4twg@2Z:3K;604S;\4a81I5,>a7 323L-2.0S/3H^4LJo04g!D.`BDEPa@T*dS@ *uD .PTh42ö#hA+T5$hTZAҚ,U#\$J.oZ˵{{}dm"Ye.*To|/)]Ga!Ud$e ;qNk9"{ gR8~ce ddal`b>nrpfX`[a,nZh` d6c`8`IcdD,p Z|f F!@AL4Đ,` s#0@B`;k Y˽Е]Iʤ6lՇ~|q¶lS'ik3ZM$ʑFsrժ]-8kP!^Rp3F󝻣 m9e *:Y7DH Oo\:|* #-|6_XR () B=.coMth1̈́.lt~[i?XpXc5~9ä /#j46D|L!n m(aX>Hɟ*`iܮ4J]?3Xt=SS4T~*ٞUTKi aCh-TEhal=#@3]W$d=F]յW rp9>|zF{_nŧPG}|Ssr,V*EZay?9Rx̩u`Ec1䶧9ZEM#fs8wG2Yn :>Υa.UEp:F. 1N)yRlhp@T:i PT )c [J(Y4iN RE|DBF;\G֞FH!]j7݌؃&eFJ,&ʑZMV1\ڔpV|иG֊XYf8X `c@  EeIdWiW^=}ꍜ1Q RtH秣AqAr?8dk*yeoC+c#dx(;  3NUWNmaϪ鍬=uN 1mb7,nS>=WBm͜jub|pc_uM03jDw*}ۖhP,{5V"E􉶆 @g}ʨ2ށI"1Dl@6:TAF CT $&Kyvc 0bdpcS,[o'p՛\&!H<^!.ú`M 4KmNA|fϤjgō4j'Ƴ= y*ty"}n\]A`U1 dP(2gٚHQ%Dg"$ ^BabU>Iݟ{I K-gk \ lXv-۪Ƌli4*v[ئv`@gol(vuTߠ W@mM΄$¥(kGhkbZl pb>.0i@Պr"MFn zDC& bs4vdn:x-_:67mR^tu+;ؙ6G ò`313Cr6Oc#0" d@qYHF$Et#:BIXy>$6SÌ'2"] =Vy8 I}YR؅3PdDn4S`,̓緧kgk+s[M^l8wKF_N)W>ni 獽=;#e+ IKu%JL 3Ž>\M2p8 /2$T0t@CP(dj4ፇQQ'iғ&Pr %f S %C (M hc(qJdɅ1pH蹟(ky`f!IW(SD" xK_ ͦj oIY׶~'n/[Aqz7uQ,!ffnxcf2eH 9QM}C ʉV逜&X!! $hKlfS\7/QhHFũJ n9F C^ӑ˜TV1/~'jf4}>P`)W8ni*g][=y1y:tBfT9?L2L$bLI20ɞn`s BDFLT%(jcàH%\~w񯙒}Iw={ #~v'qC:MiԡWnߘ3>fpr$`0d `4Bw] 9B'K#:"f`qoS?Cr&EvdHp!g eʒUݐ1]~Ν# `9r-#@\3Vg|A/muO%K~3)~\g01O꺇yF8dL?f<HB2`L25X#O m x^!@Eq` Hs% 3s 8@qD̴Vp 1Q`@}ޗlQ[)Hb7Ci*2@8{W4ni[MͽJ[7&&۞7Nٲ6;4Iw־"5oq'mWͲ#+5Q?m^c+eUF`K,L :m 1C0^js($eU Q,bM5k'&lS[&CGv;Zxdb-bSjDjnpc_~I:Dcz9}|EX5"44hУ?L|,LJ7bۻ7C4O3Cλ2MT+4Iȅ&& LHJ 0FÑ:bp1È,y(T $Q!@.#\9v@0qD$em0s'n6FOJHF'WO WFmacM=f]mS|\#=3&q&r11m9|/R, \) ",W;1jHIW m+JaxqH89!L‰RB&ZgQR4UǐDB/ia`]_t򇤥URr!s@/TS8PI'W)O-[iflk3R<=e3;;+=D/TtrkH(T$&j9`#U5̔Jdwd.p4rL O!IH/<Ľ1`Vcn$qFj͗<@"řNLcREW6^\FOPAoNU!ª\X OBm፻*獽=Ͽ4TE!{QTw|\R/)LL&6 *S=a3h>n1 $29Yk^L{ha(1ƃLvT4`.4;2$QkQ;bfIO?9>Q7]ptTj]vLQKWSɣ˄>!p<=]A 2b"bcg VJ:##D@`LJJ@d"PDPg\OI5)" f V9aqOO8e&sJPuDrxp1ۚ},6]Ic:f9\@b3}yV?Cv d?j]W2ni !Uj]m@J i02f`Bcfx$C$_ xXudG:WKWbf(E%*PbFS*0.L UW8 P{UuneEH^ύ9:ñPͅas+娯형n6 南O#+o7DUꏌJ*1L3%bGxEt#مfaGћaQEgjxi nb>c8A2J0€l JLb2 < @DjAy IcBn1hԌA.܇@ r$KUq|ڶogk+NcWdWj`ܻZƂ_o|$X;K؇{ߏnϸ W>mMaDmNV5챫zz&ٲؽ4]0T֠%~p3`@JR 18zXwÑ г0!JB 0QĉkcK4Rے,Ʌaڡ1B+4R}av5_Zi {΋ś1,8W۸ljdIP[ܷP^aMY"ӷ1}7 Bӭ}f77` Q"a S@m፺捽%6&KxCcB0tr1 >a@"Y/:,'0 0 7a% 4 (k)J:&V0C"g8uҙSDhҊ` sLw<"!KzidԷd\}|q]WmyϳLCo<,WLJci*֐5^BPX |pQ@c%tX"a CAXeh{؈2Hq[V1LNOb٥zzJ $VaQO-GrskEH'7G*jok&dy'9,^cW Q:#`{1A-B`C'c)3<  @ CmS0n*獽=$Dr uPS0asrPdG׋ FA{sq%A5| `Uډ_l`a5 C[6VƥC+M9Ԙ?<8.?ԑ}C|1=>/z|@ՠOgxU7D>y\ W@"&܌b~y؇fef*2zQ,{!`XY)/&Z#bi i"aKɁm9H%3=RK:(@"N̈́KS6##Zy03VcY~/үjoZ=dR|իQO9]1H !^庙!qɿ$.1p X-.@9ӦDRyӏJV(ҡF9S!"dryDA!EB1 30*$E[&p2gty8PA $b  ' .!F> I:|3ם;XG_6x/Kɶ:¢gک%ծmOojYJK}|p\yJ1y4xfqF/"d1'4"4 L3W0@".ʂFb%6dbvdM"PaYsP\g{TA yW\I]YS4ni=XsHp.IxY1>4~}?ƿ5CoV#q+X=q<쾶wmVlmܛ)ŠAhp[t{N`̉L@H,CO$\0H abҎ" A~ 8|M0\}ujns'A fgfbY ci"aOff&~gLM&2ӌO lo,y|*j[wlC]K.G_r[CS*S%S1AC}!D[?2H)(AC<ήNfħM+3t} L qv(F$Ų 1B * p3"$SBq2 Ϊ~=S4ni捽s8 辍$ZPk̡WAC R(f.j x,x_V.Tih9~gwÝ]o+GNLƛGN@-aaCBZL.bӚ&σV/|wZ5 *{^;-1vj6ר 0 tIdfP(`ca?,_BI _-,\JLs(ÁA&8@"K,n *捽(DD33YkPN4<az׃d6Lਜ਼)C8qg;;~Z?|L9`zΞs >Kkk61z?vhr^,> o *gN2ggˎ:J0t0  Ga(6xP@ P  A]{#!%dJS6Irb'076j12xM.Y[,m1˭-3|X~vVf<_3 N@/P,,"T#>,Lx@Px蜨tCRQJmaO"(UO2ni֪捽=VHAd.qH-BG="edMo)%$ҵMͪ}MLeqZfԋi64WymMYL`nedФenH$6m a`bp@0 Hyfg~dl&r*`A@,W0|$ -kDaqS(Ƀ93V QEܕJHX#E= J4 W`%]+zi2rR=2%Mi6S٩w/wg*˴9;+n۽C=Rw{yq$M@0P191+RB &o 20, T N2v)/W2ni*ᴙH@PX\5CHXUQ+ޗi( gFpc4T>_RUU5g]E=? &QR{@I Ld rG[ ſM. mbۖ<1nzR ۯK6/g0h^T;WT%.n9G p(-Z,SH^7; r,5f_Rh@.<7&.}6mtu/X{-15?zگ/. 4LLZLFL$9/6O˺aVFW*n>+%ͽ8k"3v0#G&Fis<0 q6G PtI^t-< ('OQ& # ᲄ+ K&ʃY5.c9_՞ux5rݮY~۷WGퟕH8`E4d#/o'p. o1X&fece&0VhbQc "@ ZTc 6becf(@ab"`Oцd FmZn&!p1eVI;zVҿVU$N eͽ,3By(͝@:7\c-&kɋ+x=@fcaFK f Psl(cG0dqRFř~u7T\sGm}JK@6Sx߷RF/$ g!9a3@A@A1S,@\>\I&BejkBP4 _2``;IфhA HK^mE=цpHꥈ xau阅xqnBJW.niF*%MͽupHpf9۩!}{y͜{ԟPI25 ni) ^+opl0$] G2Ā+r2`P*W  zSJ&]h9*,T"N6VxF4sZ h8"B h+ ccV!AU$T;F#QzjGPSD|S8ӎ?3>&Ǽzgx\n~dٛWti_AQq(e 2A,·6p£! B&62c`ufH,$nU  T ĝ Q @,/U_45P19!O50{`7ꢖ i5Ǟ0kUW0ni4*ͽwT4Gŋ"ϖi.So>i >3uԓRм&uN<PdZ07 CpDghh,(Bj325T2m;NCZ]Q'1&7;5;R2EfmjnHM;:Ojv:W{s;ctz)y&;і9i,*j7uyoE瓀 /q6(b#B+$qZB51ކ@BD#Ы(9$^1NKh@ATZI 0,@`O7$#E]KzY=1%\v؅Mx50 יI9iiPk絴wP?MqW:+f$O XEW7}&_>-s쐼;miJM,"j4A|sJ1`ǐ"##L`PH^HfjT0[^0!B10يƁ b„LHL9n{'@ο%+QZްkX"tұTV:t}|udF '~< <eԙQ.sbɥBAW2ni ͽ4`MDCBL2d~ b4 H2a`:s 80s͟@8tXalP#(d0 0QќEAeyuVWI?wQ.Qek[Nt :-Oe7㮩/ƫ-omcq-mf q\{snE yŀ*uyq!Ǯ{1A;k`fưF .>٬-*`Z2l1،+ÈPH(﹂B2g,h9#1F`J\ 2ܖjI3R;?xx^Y&L-58ǮD\<fXmuGa(ׯ@ S ECw.0z`тaT8$ E aBePaHF\*&<,.aAiưVƃA$AU~V^l.k_#!ir[.)7m]0%;/O.,z}g_Xgc8S٬{R]ϏfQ =GMSC c 3BA9@L2@K F0TZm`ՊT> 5"%*)1Y&FaLp֣@~QĢ!l)M&n%Mͽ"E[fz~bzzfn~8r#|1=ggeƾ<5;a[Z<^_X7>?@@`S92xbddFhpi 0c8(ÉT6 sJ  8P,J3`sm.f,Q0Mp(i c遒`EqJØ\tQ 83eE">X(gͩ$~cS97(ni̪eM=#cU2h?)ҒU6`^^CX=DgUq[a9me,?»f̙KOHDzc H3$ce ,-MuИ*&t 6 l9dn*6S*P*x YHbI1EJ0  8?UVUs.fn\|Utŋ+;x=>f_bb91]9wA8ܽ?pt9uV@HS a!]GS(k^!C + U8Vxagxs46( Rq "12#21m3$bBN?DXVz L%n HG&nm$$t heeQiLG䦔d:֗HF~jkg3=wYw GՈփ(PWhu5dc#BHQܦ $I@"pǎ0iϵ ʣ abC[d؈,,n<s~9!yVCV`F ~[FDلY+xzSL K[omN2L(^wܑif*b;|sCn:&ܳIj' $eaf=#2e  2FB࠮N4,1ͳVX{Q!9G3 X#FL w2@ӱ](BI׽Fѝo$b`V8h9#&nm$dͽ(#ЄfY Wl[mʩ ȵ'cKNM1qLņJ$a MDFzXdiX`𨨞 1#3LYml͚&}/?mޓ*A0Qsf;T.,ĀmAOn1!Ęb..bØ0,F:h@ћE $Ġd15PD@AF`"= &+[,OTbJ#&ni&ͽu+DsJpES$٘Mɻٳ~_4M5;RDž}}_9Ŷn խEgdbk!hiAF>;LkqG-p,z0a1XOEh0l0a13qR  7 0Y<ԁ3A +PhDF?9t3ÃdXv0(O@#iodycY~a׸;-/ƫ) Z3kw ]Y@ A )^+1؃Sތ0@TB#L aa(`ġ220B ى@`q@(B(Hx>$DƢqie% nm"#ͽt-RAfE{j 3b$W0UY3^ ,ov[QؼkɴYo3D߮gٮu@8;:֥6JKO "†t YQAR<3C0T2CPj̀ 0a`" <1рQba A han<jw[ NH{\,SpnXpd3v K {_'>fu|Y 0YR>V8ΡT!g9!1u1N0T0vI o!`f"L ǬìC, "j ^bH>8E2 c&ʅ"FHC e, `Q!"nq#Mͽt'1@$%SvZ}ZsgXrm5WamQo3N2''ufT򂎇Kxc~ørvW/Ns2"qf s" Fdչgg $lh@|Ta & xe!rؕ$,`1i$1`9`X,&:0dѰaΒAHcAA&,?)^a[ZcgŘ%I hA¥e)BQ-3sn3{~u6?WZX"[7~'sׯGdeU0G2 Bc ͌I_F0uMY&F\dMaXq#. U=1e@S !!݂=@cAhCX 0 EX '.\`J IEօ)DPL\jQbui̳vd=6z/;[jXb{xHl"D{M60͇cL:j%08$@NФ&TfhXp.FvB6Ð4[JL;1P+i04*$TxxcXL %=!jJĔf8S:z򷉤&<o?K5F`ekm|"\ aUEULDp0ܣv!0P`ȣUJ(-g`DS6 ?8r-Nm# ͽtp 80Raxb`cb!(c0 %D0(!*,4OيA"6 eU8kJSl$ >F{ U u[Ce KfXԳ)xqoOΤ [tgüە)Vt:?{,J݋1# ]"1CS 2,QC0E5_S p؍ a $M `!*r4?LB X$D׉X\cCXhН٘m(Z0Ѷs5;G'$E>ĸRRO̔:uחMm26;ձo뺇4@^>qOeJ qip"L& Dv#G+ALxY `T )\ $qX7D$ѓ/M &‚qee Q1 nŹYP#ZaRڴ[HM}Pio}wyC P~_Y]{}Iݤlۗ(H)oGhA?S̚6aYfD6DQ1U XܸN0hU L u1'$m$MtLtteB$A0ABV"bX!GhQxfi/eZDQlk6/3MKy۷~O\t÷˷Aڣw-wvA) hUnfPs bƦK~Ofv8oepHkaG7 |AN# bE .H 0LbC0h~063>}t< PY zEh,,k c.ItLL~hKa J4 E >O{zפ)bmqn qQp_,(bChx D6o 4b`!No 0cɾ=y#) 8%nxO*X`s,`Q -ec&@tgs`8L`(+`dGZ.|7^$A.#Wh%Rj{ĩ[RF7W j ?yvՙ[MyUZ'l܎ >pK?hG "P*0% ј i¦J**LT1H =996t; ydJ0#0SASl` ]e@TǴ(؂,J uAsoeԎK!>:ުj{xfNkiMڀa'N .#ͽtIrg-?H b઱!Y)h0b)k OxPDG | ,Nak"d BJ0.ftȂQP4B 0WJAȋ6D&6n, 6yY09֋qsZ_by|*Y3r}^sOmx@3 ( d38(C͊"LߒDa4+dhX(C1. GS8T$ə %Aڅ0cdvAh( ՐffŠ~EJ%"/L1y`dܜU';&RdkS.3{3R NpeE$KԂ B$e~E$m$#ͽtYHyTF*b#a" gN`FlUxLh[2StacԤ$`dEaek0XPHRe"h{Nv*Cv58VG9Dt{Iuj\xΜ1jt 04 Y‹Lؕu5&>0M:ER1R0à蕌<ƒDaCY1@46XbL\@c1yq %@)P !ca08, 0p ˝BhbEn bLC142@ #":} nq$$ ͽt3HAaS\+$N3bF6t~j\aGd^7X"opfy% yvAvAF($S~-g ;Z&RȻ~-^K ZcзK сƑc%HbK3.l;efWÉVW$U!Sڲ裏ޠlVJ#YlCkN #vcnV:af:~j.35{ &VNs<)mOzW"@81 13)0 2$,30ɔg N\1} U b 1Q9~<1 @\#hR"!H"# L#[kuJ^wkDh)V; TbG1WXuyfqnv7zc6cw߿ܯb/sc3(dAM{R1_eSݧJH>cɬr8؀i#"nmr#IatgjDb&fHBt! dcJ -E(Mt b5ь d>"pH la!R*dk$tpPbWΏ^S8ӭcDQF.ʑEvc%̒zYǙw v7/ߠ{6>K71[*&"6Vƀ`$,s8^yg iC!Y+ ApiËҍ[680H*"8gc,ǬVF.DdS!RѥAqap@`H8-&WDRz)g ̲]FXc)4&q`XfJ^RKe.RW{7̾~辋 G3Ns Ҧba-1ʎ՛ug2 5_@xTڐ Y ?C "*3pf3OM*0H ʠ%MH1% u1ب oF" -2X@G!SCRQB8?mI˜G>\F< }ξ͕Y L넆LftJ򹺖3Uw{c[u"V樇)om|Eƿ0Ũ/4hY@#kԱa]X)O&EFJs51SD E Cа9ƪ,paH2hTfFlbI$O"DV1Ɇ- ~>(L&"AUU,h:z:܍NʰQu=NSFTd\:5#nqY$# at"Ie'r NǶ3 k[ƤKZ¥뷲c*{b$ "Va"04` "c@y*,SI  FD422$, 1`12 GLd€k@ZuSУb ,u`: P.i'[+j%@_߹{|+3ř+43]XYiѲl2W/Y$_1&/<Ѩ0D`";1 IX"tQqP<90 X瘑`(`$BfID26|PġVlz Jt`^D0(#Ccb =WZkml՜L::i#$nm-$$Mt}4&^@0̊LtoJLCbg c,b ~0ØrCz܍9Bf 9aa@g,aPHhBTh\+ԥ֦HD*Ԁ)nt7b6VA3ajzdZye_d4QO1oIz|rƵ|Q?czܑ%$"Eկ}gu}HUYP c"# nm#ͽtWbs ;N Sf(`xk{JeiRpqaPi0`|fad 8zS - @RA0B8.@D/@L]34*[0[4B[, ~Zwar̫Q^_+xSrZ}:cP ɆL߼ѧYZ39@3;33.q+鄤QɉgagɗB` %qL 9sB Pc\aa``b?IS0hCx0$DSE)zؾ3_x[iS[jlGb+j痙nW})WPn " p5VTujWs[{gRegg A@&dba#fb,db*f#L ByTLԃ9c`⥍ 8L=J6 A ̄0 &P@%0H$S/f8HnޡDNjFȂ"jϫGVK0z5eʍycIeq;{\ʬ5Lmc឵cgcr8.(Lm>Y&連 Ę005} )iy1uN3X<Md$03\܌C)`peI1xá`Ahš S GҀb_0r4qD+)غuRQ`{v ١6^ȵN ?# atvҨކxem˥}7Ibsϰm\b gJ oԱXYfE>w '\?7Q1IIE!Hy10s2 4K0@LAc#' \0؄ .1 a "s 8$ Q`(` U"0Ӿvtk?='"CFa0KɦwǟE 8g{ퟯZ\}NI{9o\ΦXw~R%PIYw5?fB"JN`G ^dgbs*a!N $Mt٘;X<*>{\jlRߦ=z<,b.|Ï˵7X%>(u00ơNdQ&:^̨dDxo0oF (!42$.(P\!4H$e"DcXu-biއ&5,;HऄĘlNYUQH8x>"3߯kw/G1?p1Adա'xS+Ld O1S@$d#@ 4dѠ 3: .8لa1AcCt0`*H C$–Bt>U(OE~Hhv.gos>ktej/Zw[Mc~r,nm늬 #=q0p 4,251b8M (o BNNY2@dLc&iZ\af `nȐ`H2-FS ̙" Ib|b$#P JBfĔ(kswYk$xjӯ=ySU?3g%6t*+Vp0ܷڷ63Z3ʕxx.ſFh.+̌ B3јPLcV0ʣc )3` `9$!ƊhdC0Wzƣ[Nm"MP8"qt. peIX\%rwffzf8zvyy0n $cͱ6']" V70Bd34 ma#F\ya˄ 0@QFt  -4 P)@g7d wv߅!E}M½rãS{gλL>>53jg-{wmQ&w\j15cPH =L;K E n{ A9kO LGBi1dI鱀`y@a!!)),F!F* e‘1E1Hd1E0 /0 Ms xS F*(ɏpÁa 6>ksƣ*u/nܽ~S;b. VÉYÜ*= gk ^-Xk5ܭj9OsUU?%À nmz pW9z  \72h\4@!a5IǢ%Ff=A1D,@m08`Q9FFH($q* 043IS|Sʼnp(rn-'V,DI3O#M˷zbB2k nMLՄR*.65#N)ݾ}^K>u!Çvmh{1xu@AFMK*b8&egG " =c@;T!w0͌䈿%E `q L$RcBQY9RJXbP4|/'vQT\]+œӭ徆i:@+o_R®b.wXؠ0<2Ю003 12nqä#ͽt22s02h m̝ǀM L ҁdFaWc §Fv! 8 YlPIAF7v (xMK Z+]OMM2E>K̻@3.p4X3mBb{Ks2!(A6Ftg]N&$ƙ &gR~Fl"@-1y0V03|0+ ,#0P-/Ym 8KEso:|3N$v $V ==%0m/Ium/n\cww9u9^z8c+=SdҀ#no p TD2yc7*R:zLʀ+*7B=1K' C5Y m f@F…t 41Br7$Jr,2 <}ڊ bzQGfUYcmj-0, 8ggO=!>O޿ǗOk%+%翏Fr[? c2ъ1^Z6*Pk-b9,許 A"cj1j)` ̎LNnL^5Ï Q#fe@ PQX  4 AqXqJuUktB18mHĩ;RᆡTxL^Ng,W/J|ʙ]嘼I#ux;QKVUZ[E3"\z뜖c| &@U~N1*&d^&f`&n`F4bb603*3,Y*GAr~mGVT%&VH*u jJdtpBj !*5\ rs 5Lpczahd``a9a0x`6^p2V70,0 0!"IɊ@I M䎣b! ]y*6u)`ާ"? 7z"yªlvFaf5zYV\/ ϸ#m..n kԊEe,[[/K#?5iLM٣ 4mBn=6C1LiB8s%=WT"YX*MB@CAI,3yLPP<  $h1k߉0K|#!Y(gJ@P:)60f[<0?0 XbƦ|d<: Wݑ43f1A4MGߩ2ɤMyhe^vv_K$h"2gy6w;ɽŜa`NR@2DD%Q"uM5HISW]L=k@̝ [A$QN,h["k߇ Y1)T8@#(GR2$I^OI*=,α7_Y(6'ETZG<"CsQ`$$Æ*DapW"qѲe@cص@dG *p| 㟏zy6 O߽!ul85C O"Hi&\*۝V>eM/ ΰRzEۋk"o99ZĘ%bfji(nW4~#͡`RpsAR@`J<0Y Zp2C4B@k(mg=W"^Re#N(γIrlVX(m!$;lM,uTܴMOWe\{:IO\*k釽!w}mǴM|V,P~o+c>pŠA yIJs(w;w8s.׊S&ըv `^~t4Y_lΝ9=>̦hI8Sf [vV‹KhTfu˾es-M>6:kZpq0Ycc5Z+QP ]:|Eԡ0dXQ*a/u.rt R4(\Heԡ^{*n`r@bam@ #uP+XxsM `U`)c>v.C}shH:^:ݡڐJ +sÖ+L*@PH(bmOJme]=6z]i`;'#daEȳg ~O.Ӈ˭Vi/QkbtoY_p2FcL7@,$y+i(nfd90=ѐbf !ziy%]>` !GJ tϯ%wbJ^|\*`ɱZZ"UCW-^٘>ze=5 8)@Ļ v!vUBVƮS-I Tnߞ4&t|eL nkT€$)U#&qr Mqe@4^Y>4e҅ Ej`0|OFm卫 * =gAz-VQwQY1~^őhP8تFZջCi_YuGh^69j]M{[M0Wh[7Ui^[YaW=/fk4g;BUg6c2K3t-9K`díEd܊ سze@B薋8~TzCuM6jwie:v5G4#FbDYGZĕpݥ'qlυӆ\jԛzjV?V2ssSo@S{ ,88](if=NA͸VA,j0f9e0eģ$H\Ο $dl~ޕЖFT&VODm*hM=+aϢIpT>Y[cR;u]կ/jg{sԱw#r[-FkϽۅBlv鼭y$oXhf_a=:db$OX|*ac *50hY$[)0H%ØԆZ)H+D2$3)>z%\`,$<X!֠^(\9ÉF_fᔜ_-M=2T[7_Ӟ"x1>[;6nr*ՐЬ>@M2YPcE !Yct0O&dՒ*p8 γ6I,4(^Up+PsS~LN5F֗U#ᩧn[M Yh)0DZn:>"{iE{]4LˎͯE" 0Xr8 ܙt8 EW](D-K 1UtGoH?ְ;kaL 0qjɢF*16m[w-3UX׍-Qv.ӧ=#ߺjL.Pej=ƚ#ߖ4G:\ 0Ґ`( .V30f']RW\|?&9Jfυ;\v}-VGt nIϦW_dflaHLppmPD(l1aq† C<-.D^Zsq(h XjV$쥏V\^׽a&3+3 \0? YJƄ3=Y<]1'&q$syS:ni*' =zCv:oG=f7w*$'Llz>n=nz@ @  Lw0d L':L0LN *afd0XwA*p@Y P  ,t+ ``t97^5^N+:0(\ӆtGxW{3KN9tKɃf%}2nn+ۆZ[}6~5Zßy.Xkhji5<0svl8vMk0@3(tlSe?$bDF= C#fAC-L'ٙVqlz7-U:*I;$A,MMyt-J~ґ=ҨɳeTG^Λivư7IjVbO8n* =\.^M=JQo+&`GQx?y= N3H[cb 4H˃%) k08K!092 pXePAk @i<;)BZR>.Md9k9#A]xJ %#<&$1G[K.)喏ucY'޼ܵϗjM/kZEׅ訒8Ai/>^M +J1e:I*7ǭ g2LPy$R7qٖ  N*Ṗ!10 j:2z5(LmCb֣5%79~ף$)l--#z|({Y= XdsvZ}U4nm* ͽg߂,}kuHK%w#jg;[']NF':3+*HGx+Ab=5T\ M i MD ͉D`BPQ03cnٌ @ɒ!Z_1`AmUǥIيZh_kCK)ISIm0ӄ5M`E=WXgֵL NmroK>.[K3a=iyrLQ"imY7183t,1e*0Xi1& AAU0Gi(p' U(`bͪ vp$uxy*縄?YA0x=vd-tu ?[DXmBd'NNxOnO4n))=x.~12=YpۑgM]YeYn}|N(VE} CF$.l90l̢80!  o;Qvs@ƒۤ' @K%K `Өb:VX,|R ~+ uw2}U)ga!qn;jr3ykR׃5y]Wtykڷwum߃ RC_q i<f8^e2)A9 <D?D(2m݃||/;ESiqoBCsZff|54$}C ?.FV{8z ;_@BfSs`cc3FF!JF&nӉ5kwjfVfF qyojU3]iaZ %i1<¤CX Jr@%[!ŷb!p.L%Y[]S!B" l0#ɧ`Ƀv-bS|+O|^[βg[VT p_-=VuM8U0n)=Y|{ 􅻾׬GM>Y`{VO}'NA1# 6ЧH dغ<VxᨋfEE&\hA03 BDL%^-, @"?ދ~YfoL,cx9KR OGO#M؆ԣFJҭ g h=BLK6 `0h b"& &2L$( RA?l8`$)@ʃ2BJd`x]aumۊuLQgqׅVu?j!O0nm=~q̮/jiu+Ͷ]\fd+|-_گo]A L#5lC54 CLpˈH|f9Xr0$*<D .0bbt`,I HR M6%L*,f#_gHW:%fZ3ȣ\g`rw{Zh~%:R3x׽g}eiz>[ҳo\4wkK4*I(,gg hHz:lHid)Uİ$|# X, J3@]p2AU ^@Lp@!PKT" Rɔxy7uMX@Kr+ aaFpbѭ}W2nmWeݽ!zS+U:픷+;K_Y,$'4Z-]kW.vmJb' s'Mb "$h#a&aďڅbTrq$aPhȌM& tLXPh^p3Sd*Re3k!/5 ?[^?3kD(Y-kS5j(>t]SX6<&[ы?ד]&{vj5;﷍j}w $5%Kt'eݵV_W<Q tC91и cƖ&!f.z cID 0tE&wph=Sa!,IAȐ9 C1-NN%&a1U.nm'*f ͽVk6ݵ42"KY~OnyxsVÍז{(>>&C6X0Sȱ&5T⫸sax55"Ţ.:!pa 0*g 5DYtHX BPdd@x9ZeY0F7)\}JJ'Bq=u{ɇ07ns1-Z}5;Þ m;5:^W쉃DܸďmpӬbppV0`4 `1)xm4,{ӏHdaH±u50PH0 *>#4!X}0&.YS2nm1ݽŠ5C| *y zKU~%B~k\Zg]]N]ɎW:/Umfݬ1}Gfz{!GL:&|4 tff A f>vHR \RųpfD*(1U0ԽFaVO!ˤ"":uT| VA2ҳi;bEf<ݨT Q6 "EF^\.cRݵ~*b_vjOOƬ#a/&wdrv-]b+پ_nԗ Jfʾli>$6J"g &Dhar4b*`ehdb !@!bӉOo!U*n =ͽ 80P@ ]0%l*iZ*.@{NB! ~Ϊ]R0JT"(CQK]8YX[/kEf-54-K4/JnxMwұw 0cFgĎ^` |`061}0d75,0 MP ozTƔiٓ*<8r)mEIρ# 28@Ap`7(/j> 5ԉtu A:WM^ zfOK}gYq=/g-z{ͳVKwލفOzU8%KaLxx٦bVbB`Ps> $cPX(BMG(1FQ9uOQW.n*ͼ֤iLm MɗD{)CR6MF1Z(bID˟Oǧ]-Mf|5f%ɼ){[iHx3DoLѵ "Rwɸ魣 G[p5QPrG e))$BeF.Hb`0)#?i9`iHFLPͧ%#7G[=k)q XSq)qlPܭҾp*LRcgS}28h{vW WjCk2ΘZI-w32KwK4Vg;CIV?')ZOQṆ L5*0XcCKÃcɆidDL 8PTZ&@QBZpU.nmMͽuL ?]*1 (;m!}ՉZԻ[KBy]q|ͧ8z1:ܞ)p^6%Y [rǾkCKkl:dl 1@@).џ$CA!9>0J8.6g# q y  p88"LNB S74Z_r**s5}0,_CЦ$6{GƓ/ %fJ~&lDYRƍ͗Vjw;BssntnW0<<[n=\t1J3-qp!&'  nj <&pƁ#0##=uU*n*f =#gB R#> 5lgm82;7.v?]Aӎؕ|6 ^a4p1 ͂ 0s!!d&Bp 2@@0$TV̢M/g%RS[)0BٌJ[ty ȱHFibdUiQ"Rfwa]Ga-OA:SO0x19?^.7e'.b*e6o9ɝ]dj!@jm0q&2hhD`)Z> l$V* :%Ğ.*@ K8тO6nifM=B\W)D[]>Ͽ*{KY\8k*m'Mɪm=MC}65?>av8{˜(wjw՛q1˵Mا[ Eđ0^*̉1ϣo@Oc,:.9M&Pj. aG$q#E 5;&Y.j`8B$|PnC~]`P&Q$:TGór҄*g0t^'u%I<]7<(' P?1o#S f( % *Q5xFlDFcҹS$R%c@ T9Tђ``y`da cQOB#( )Ἰ IHoW2nmͽmΫI(٘uzP$8^I\ZG U?| ⼩<6&z&7#~ϠM<ۓάhlH0Pl:d t"i4t0U [ L, K^`(ba2aXt'Fj`0J)AP)L cbLdN@aʂFD.Vd$ ,TdS2-?d앨+Gn(*'SQ|3㿖5oGX%@\HMbsYYoόݩp_|s۷} Pʟ`š!.4g#YAj@q PJU&2Hx(2MD5PqU(u݀#'O9PwӀ `L0 `8pY` D !a8 iD7yr\Ra 8[qAH)CF"LA4nV)eŹ2CJfsRdfwSc$Lhhsd( ƉS8_4g<]INUUZlSuo3Y|sbI)?o`**w@ܖZuwU* +]p2E gJ-$ DR $IyV^JƋאU[aRL..W^dgh\ "4ۜǪ2j%-؛OZb \yDUKz$WrrRĮjs':݂)Gs+R xH+wogW]]2*=L: P13ǔ-,#@'ʣMoFG3k,es펜y*r򹒧'-I)g&c#hͦRH;j"@HNqDyYbFg gbdjBI2]FHFƎ\mLi'?<מ~PXyjø}?r;Ljz5o[KѡnmxK8dWoRw}nϋ9(uS:\yn?n^0`Ըr!WVlaꍜ1Zތq`M%(iH3BF T=L:~YQ̚O9;2{4Y=Vއ ynG]JP;(-RN;]T1j@LggFѡ͍͘3$'>Kȁo.*d"0.t5 [FbmPI?t R(%1+[K=1]aMU]2ˍUe2hcnP9EA'F̄bF^mS, %іDh4#:2j-2PX%񫒍8xGk2EJ"HPQeO~zdkށa8b ")TU=$.7ҽn/ }ƙ)4KmK=?4y%撧WNlMo3Z2PL4D+x<@9uRkgF*%0%NbI R Hx~É ra֥ĢJ͙uW B>>3ue'`rV k+Yʒwi~?pS:pqfi3jzGjmY冽鶷AJ#le_gX, X85bd-@SOPL"NbCo!إg oaJDwϘ>/8B".":5XHr,@2#ohrKVdu 6?'vM]$()k Ḋ0aWBm*鍜1)Kʕ0!"(TD! DZ`BX<Ύ,LZ24V`!u~i}@E'JFE24:PZ5/FԱҾ2J[,+vڿ3?;IJ{i;u:땠M7֍Gl0DOQD8,L2L-!, Dqf,a(`YTɎ̙9l B ( 4$ 03UоJ#KF̛q kKva25Pk5L7"c CYXHZP@޼tyuY֍ff5OnGeqvw gWBm퍣_+' ͽs"d61aDV4E RCaCˍ?Ԉ9tGe 2^VcS)~0xӽXj~ӐVZpiŮDIĈ(MoUd7 dP ÙTXēhP, 1B,gJd L815(^ za568dK%ݑYVtS *h fc]c~ vη\wi}+.?枳jL˸Y}mo Wm(WIu+T f4AIdKƹC0WJme獽=X4jffI% Bp0yй|HT& N,\_Af4T!в& 2j`#n uIYn"5[բ$)5[p%f$Ұ<5Oܯ5 {8}ow1_ͧ,M\Y/ 3(@U53Bs .9)ċȡ5&9ܜ9Ç  :A0X   j}ȉ$M.f3_DfPT=0r,[[/b/&J: TUZje^_[cvVc. ZwͫOfmA<ªUYojr? g' }Ԍ\֩øW:ni*gM=9jq`xaڇ`pp2dP)C$T`F!!@Y~'[(C(` hl-36q(0dDSbħHa M) Z$fbR Eu- aR->pl}x1KYߥ[22sǼ"w Lqz@UaE؈ð`QʲlB  ,ՌČGE$Ҍd~b!Æ(j!68FA:ǁ 0i8XQɘD~h1P@i]TkES f 9BD6wYZ!͑3b-vk)t@NjhC X\U_mN<>s<|ˍgK,r暇8WDmik*Mͽf)2{A饾2  b!5iFk*  QCɏg! tB" LW8#b$ơ lрpXVEZa jDi[PaRCoՁ`MR q*FXWZL"&& boWٳt#gxwYsbBfRJz汬l/Wuimܰ8rLo4#F/> 3rbcw2ș[^4RbB50$v9BEB HiXPs+_$,gyN!K],2!0[LTSs4la'W|kbg] õU4ni* =CٍN߇IRHGgKڧ  w&q`9xuFTE pLIV#N B + H~a"L 9qqL}ٳY C'Sg͘ґF PLL#7WUs)!F KL>gp|ΥrMIɛ&/:Υ@yѯ[ֳUGP20$󌷤ǁMFѤY+%Ah=*h#J-PX(PpScÜPAjYչ=$;Y :$\kC\R]N->lbݻ7ͮ-m'mW4nm*獼Efu&YlY=SBZAb"%>8 @э !+HuǃLt 3A,8 !ł- 'rL 0 D$SI"Pr^pI/4V4(X{Z]فaeܵ pIH"͘c kg2L`08 RNcd, 0H1)ahV Xa@Q;}C (0\,;~exPr7DkՇ;.$jQ!1綴^Иaseoᆟm>o_{Fߟp91>6Q.MW{ pʌ6Y/5/L3ỳ,Q/Lh>ƒtpBŔ4#\N1Éae1%3WMy$WLv/BYfڅh~;JpНPm"lc囹|cRkY%W4ni*M=eij6a8{ontWPc?4hUDO ՖmiԛjRT0̡2K\g3CME H[*W2Ҫ0TIR:IRGVJa fQQ+Ab2@od*4<1v?#37F"Iho|QV\=ɞ\5-8` !b[q?Mfd 3ø>Enk~Z7m({|č76ϦؼZV?c\WBmem=hMfaAF%M0hEX@<"u4^'`qJE 1&  *bZq#k{˭oya[|mpε;cfYskM;[m#=0ZC 4ȁ6 \1J@\4Q+ >V9X[@߄J IAAPLHP0e uD!30l;@8λԴ? '\%}HP]BYQ:6jI8k~:IMuD4f\@3&xۡq=iTK-|W2nmM=u85rc<D$+gH@@PqCjhQ8&PtAߊS"( r MZдF)A>C7Bw1ĶU2HHPk ނwcJ& DP~_,h0KqJZC1ʭc[0U8)Af,Y4W2^1UN :aAIBOE >1ȶX#>149S920J]bf<È2jr_K4ԠSQIgeE"ib$mF i(t9\3U@Œ8A;bYܵs)>?~cH`һ"}3Uh3t獀 rUfZf%FLb`ҥ0腐0zRS LpǀW>m卲ƪ獼1qdJi×uТ^4(2bthǸپNivc ~gvf8lŗqf4Y> 6L0 +7M 5Hx`a]36-PTd,$ PPD0pg EW4nim* 1"*C0EL]"ۆ\wb p$u&@~3q,Bt8ZwҚelRq6MMV~>)'%Q(y ,̑L1 u&M w zH. 0a0hq%JSR5UH_Ƃ̓ rZB &E]j)@ "0џ}X"'N֚ UbzDet:DQzǒy4r/7/&3|E>+umN-6c[~^0P1]c6C+ B#2m80ULxZ1P 46r ,@HH 0pbV"Gc PH6ɛtl( U!!0-*iS2nmmf =Ak>c.~W9{] JȞZ.Vf;Z/#rw:gs#V~?5.dO/7m@:2@'ƛ5^4B@ C;&f'f&!iҋ& 'Vvh6MA$DGp"ˈ\8] ֐4GPiĜ3WR22~CHȆ8)T˙ޱwwuD nO=z|jzY`fco~|o{7<5m4ҥUkoIALTQ@H \D4I8&4dDJĈGXk2 hK(ME|)n(W0nm) ܽ7=YnO6zС<*:aכ=Kկ?͏&uMkvذ, Mp'nf (QXb1@dp@RiGq>@)5ģ "0lPL`@LŞXRu*AA(!B!;Ma1bPIA9Zƞl_"RG)*hYs}"I,myԺDZ_}c˭!b툷wWmGا{57ⵚ k!̚QAX@# +O@ᰨ?䣆&dC bIA" 2u±pud(``8,%{4Q#?'7 ;1`,$s+uW2m٪=g/M=Nrdj-kWM5͍gkfp?yí͋ZjCa̽"<˞\)4- Bf0j J*; 1@Da(.$4TF=:S1/` ЉT[^aU*no *fM=pP,΀=YkZZird$_ Yp ʝjөJUu&TsT6l,byߐOԿ[W7-rU?А6(J<:Za]"M%[ %&I0z+?wpkɘro6#^ ³9b<)gvܜ~mMC i!(g}&`F. *N0 AL`paY(n  = LB@@ y :`ĀFqE#-`,6P+k8A!\֯C3Ŏ2BuJ yQ?36m+!'d)5c+=忹]Ɠx;_{>?S Kww>*nps؀+ҏ1}?^ @3n{㬷;˖o?Ʈ-Y֯v*pH_PIr r Y(EsUAtZ`aPaOP@ࡢ JL ! 0(C %1Qy1u1Cƫ kA;6*RM4'{wY񎲉k+tQ&QP5EX({:ỲЫ(zˇ=bKRM]ϥ3223)lK@@> 8&hB $LH*FHDL_ XJ4@IZFD™ \lD`Motؠ WFm =k:H) K%EF$\OFW]Sx9ooyUϾ5?0+ o'㝚k2N;D}k8 cf.eK^8,h &2d#P$3Q 8RdH\41#\H) ,=AąJ",:xh4b. sBB¨*%P~I؄G\˶BVrڃ?3e(l}S8f^xlc[cemڲxp"n/OWyVƶ<Ik}o Ӽ11-:`H(@P)`#ÌȀE½\dD0FjCi0l@9PMaXJP11[if2gW)bQFmͽ=g,z!-QH)\qpYd4^;M勎ŋvb6uǙu\?"#3š,(_n l.{@fthRp`dK(j~PR"4ָ],QQҵ=nYiVL*d'7FJ;.yy- 'ֵHu;Wu\昇4TlDq_hW[>|IƙZq86z`!s ~?`P̡#a.P-[EKg`~B0J(Xq`N`Zx ]l/qc J*D/bRDACϤ+Kk)&g([޸$ȵZh>I*v^WOHm荼[ mq{o=xVÎGiF՞oFS3 6awx eH0X7#1red@ !r":*2*Yk`g&A264!)|B_$SVO#>CM<&A -`Adf%=m>'?5L-E1jα;ltֱI]]FW>vϺ[۵΀ 1#?W 0Ҳ]92H@0цK*Z FPɠJP m"6#dAz'<:F U]ANlh-񤲦K%iBV F̓8?klf}9y#î3s1BzɧyOHm**h =cujOZ/i]fص9-eѕy<952AF&lwȈ$a PɤS^[00rЂ CpI4\fۑ,?RUP*$PPhKBfh(%9sy N-Id<\4n$Yx%:r͉]:/~,`Mfl7o԰k˧R6;8Inߦ?(|+B`O tY 0:Ly0ʎ("A d :2  s PBHˇ L *%D-eP4au` NL3YUM?Lҝ5[ TfS,aU댥8>`wO@ni荽=λnY M+s񼵴|@gTT~E-߅$b=E02s )#E,jA6!ѱd@@2hD2 &IYЖaeX=FGF?bKTeLݟ CMM{VgqxYNVȳX}ڹ|zx)Ocsx3>Զ˖1LƚGxCv۟m 1` m2  ބH**aFII4g2D*0x0)ƸBa )@Ww&<">5VݝkYF3iZg9xste93LRm_XԘ]iY@m* `GҒfRMBܮGjVW|Ϝ&>I4߻nP2:qEt@+(0G5Rt-ۇA bh5< urG$UyY-]ai 9ݎÖ 9 =L$`P) !Zm%^glt8}&U)/S4ڨ%~BE'TNtŠYkh 0pň`  Fa`fH <=OQbMO&Zż6B @(S\i -fe2KfD5El(N&@#+bw)>BUؼXfn-0m2ݯ!u,rCa,$pDD'?*3o{,L2fӱSDm卪*M=P*4c (M b}(fQ6 Tm1dFsa2pP _\y-102[4pGxQ@9i#CaZg9$x$%fŧ['zY!*le0Ql>X 4%-$5X]tw>oO0^WYpnm7Ӎq7qYǽܭ} ,As!KQQ!,FLLhLGdk /4 )(AAQ#ŐHƈ o;4s.Y+റT\2}IƼ쎦pޘz;k_I%qV>'թ_7wmmuhzrшzY=+l!Fx@BQmс1$%I`@yEqAэ: Ax K\ h%fbicFdᅏ (X,(N : nqxDeBgIL=hx d p#rǪ1!s7}Y5r,TjjoOr]iWY|fZ&XiyL3péW F$q` `4-U)T̘eI4R`a0P@k^q'JTX$d(NUu1deZ/O8nmZ*&ͽC$%T/Tu 8\L[tݲˬc^!|utͩvr ׊eQ&32A 1R8'EDL XƁ0P@ "lX2CAj .N:tQ{MiR,9Ý6܎jTkxP/Xsɍ3$;̝4q$l@ WZ\W.&[ Y4<p0t̢sH39@' L)9`q@&`a=ؾpL! P$Þ-9cHȠXمF BAXWo$RȃI* ၡ:nҚO@mM= 2EĊ,lg!7?xkQ.!bya2M`֮Q1*3'#&bqcڍ{2 DcL(rلF@2S3QC0+4Sh.!g0BXdq Ƽg21bb#@s;0qu_lAԬ, 21;͞=CU1~dPh:fqW]'28t4PuO:KƦL[[Sc~,eFBqudmضOڥ3n `HkbzT g3AU+-48b@y(ap  (0s1@J4F@*AaPYLtY@WZ҅eW2nmM*&ͽA .eVgCـO8.wZu%Wgu|gh޲nI) efY++Ďuv46oHۇ<{^=zӫcXp1 $3,Lh,OWL3^>am^#4a!N͖ul]5ŰW PfHhjĄpd Fk%Z"s1#R+C0+" &,ԾَS4nm) 1 0Lv Iqa[5j\|vT;E6ْLbba7V 4B_cN?\u7, gҽZE%|XvfqٜP 90`Q.Nz2PRX!03X§0c BJA6"G82 !(y!RØA(j+:.(|D<|$ujƇtqL?KVP 1:奸֊ljq_wV]g7mwlSvlwV}Z0lMjs,q͜?t0;X `vg.PVS &D dȔe4a8B Dl( `?&izƭs;7ā8xc"氢!d0* )n|) |AZN ;S(!k.2P;Nd2Du_m _iL3,i픣XOfoJ2rwAe_@o&Gix`g' traQ@qۀ5`1#PtD2D @},EUQ0n) =+B4Zz!E7>Z]w)|CIv:SLW;Jj%y{em}{Zĺݵvhnϧ=}/ Qm8cQ`dg `hRah84E 6 Dh-L,`84HhĐZ`@&ɌU U-P ,,hTVV}2`Y$c&KR>?〦ĸ0 Zn2tzK eh›sg}hk˞5l:bNwcizvr]=v#@ SKC(,Gcc Cwqa{Ysow϶.p]bM+`UL2S(00(  A020ѐ!=3t XƖo q@>IOi}=#v-ýk$Zg*& ! -4d`|(Q0Zp˦`&e2@B?wUO8ni1&dCU@x&H0edN ni/ہ eqy?!d0P녁 bNտ㴮zș&]j3lMNE=?;8]4Ud'0Nyԑᴯ~d~z@ XJf0Ȓt.]@ %0!"/  ¡#ZK fI@ # , ;!p`ԨP8|D&SGfiS58q"U#*>F@' efxϙ&Ng0uՂ%SSjLz4ʫ}K!aY;%՛ںRtr>NEB`c)0`@à5SԞ*D3g'jP,pj}-W6nimM1]^"-)҉Lg(qxg&I=rLaXsd0A]lh W F3ҧ6ev(?Nm+i7Y41# K\A \ID L80m$HLD! <aU-;vb@f- 7'f+ ޳EuS4P2ٗԊS7lbތTn/-6Mrf6!5EE m(鴚iLLMjZmw@ 8y m2idPBaɖ!AȎ͒`A^M`O#Pp"ryiCmuM: l~WA!`r|>GpġMa<,1sU9W>mMSF܋q?[ ZT]T=ЀehiHK~JlAA!+ A`h h (#. E`bi#I Zq %ei#1`v$٥kzˇ!K5&(ٜWU&`tß1s??˾3]1_'-i?8ni=|} 2?cpdž?*y%֚x@:Hh5PŠ n}9PA :1ptpPF%,|`䞣mGH.z(4EK`" `Q,@AC@UvINfpٳ! 6J QBo܆f(=6iI.6C=3Z;;{;Eg/'i/+iΌT Eg*@Y 8qCAq烃V`5!xTtb(*8ݜ%7yuxE9yyHCOlG*I[LGGQoiWkXjWm% 8e0H]W6ni)MffepJ@ ̎I6(x |HRC`0 JLP($$(H2x1 Tf``$&5baBp=0xS 1 Д0p1oc0"( œL@P D@X3JIVmT{MˬDŽ H ^RYN Z4PAQA(R@ C =Ӱ 4R@tfm*UVm&sNqr}WZla=MIJaCoiGViCk{$vuDR|i ūn!^ׇ֖ϓ%=*kb- d_<'H auaFps{IΝfB+τ1L4&*TւgM;O7es04!Pf&)e 5.l+5;N_jtt֩W{OZ/)_t|glƣmOܣ6OSfii\qeQfvS9 5a52Q͆#\ {Ot ٨cTfoM 74J[HIv[2 EA0ҴkJnѽiP< I=WJmiͭ=Q5sLy׆oYxmnX#ݣ/qhov{4SJH3Kؤ*5PPp` 4D`-f̖vB F$!s =*Ԇ2:D.I  %P,sꢹ +A;aFLQ UQg:n jܻ;s G1tU$p}oڛubh?eIJRWƽoV;{22OUf:D!wBʌh$((BK 2~1IiyR ΁84((/ @W@TQZ $U[29:Ckiڍ,umh--/M sHpQCФWBm荼˜zѿQ`)5ե51L>mw=Qmڳ,wMm9nmܪM11SlC%(!K,^QvE-~Ӛ;ybbzOurvj92,)Pa8`f)^1aHP,$F4p];a@޲$hq09&|x@D(‡URTת _AF &LF6603}M6K9[/n]SzomA:3U_ݨ agik1Y }80vq%w?%mYZPm*.^$s&Q360'030~ˀ'b;5P3  AT|ÂO&0 90y8 Q(" ( _ Dɦ[* PD1|wt>P!8WHDQy&dTN@)@#Z9CB[)2' LE 1D* =-قTvStM^U3p]Ұf柒 ?W>m荭=Z.jJe[,_j~RoVNU Zr<+Ҷ7PoqV, V62T96+SSʈ/(*ED^CI_ø[0l7F[`E (]gv6&C-CS8~n?vAh g} eںrA0Um+yMqq﹛pM.r>p/-=g[ҵ|QڒcτKFô35n @% 6UА s%kK4Y8ofՉBd^ck徦ZӻRҙ^Cja:(_X_f-|,@tҾe~Ü)WLmaM=5ҕgJΫuLO]HMiMyf Ɩ>pb%I~#C2h\&I `3(q&*anr*XQRI:!(YȬ( Hg#`2-;c(`q&Ѥ,OrȺAU+.gL  7(!}vUcMzeX6j%ىY!x_H\k· sb.їFi%D`pRF!$ #P1Y(CoО00@qa) R X( `F6>&/(2%#.{ {K>ņډ:}0Fo, ZfFsMCoWYW8nmV*ͽ LP[ۗm #視}jk޸po?owލ{k4:  3 L L\R: 3/A4  Ag!'DJ0vL!ٚZD0bKHE.K; 2F&20De1vW'msa5j1 (nYJż?vXh XvOc̹ˇy*}awW 5]EkET&"\HasXTaP3_wPPKֆL0A4ȠA(*!00"9 B ,Af3݃[nE24OY.+@/p5V LoN?W:nia+&ͽb(-gR\wg\aZzھH˕vxmOy!a®sG=Dw>!c.kmWR .0 1LA$L00РNIHP !ƇҠ Y)@XhrO`Ah! j!jB'(mN)bG229"!n3&ޠybj w|6bJk>oWN="MK< NԌχzHBcnJ!D $0Y 0 1@YXX.xdi0Q (К4$+vbF RQ VQ#]L$R%qW8nm R^..aG 2i.k>5E>uI& ^ٍ""77U,+KxF-$Jٮć P*bˉ"3 | (d 22H LJ% :9;ձ=gDA.[q,e\& jsCjg&\'V,Dl :EYGbcc=r,isvb}WFme*荬W"F΄W35824 =DC0N26,3r-"iA+G05ԋF^ U-$WQۯ8XjqnGS?%l,tˊjsP%A: xe.UdFj1gcݧ\{,ji~UkLjTN7(ƪ[j BݣMc:3cJSFád )@Q jK& 6b iDeƀAA :4^u(&H48L!-D渶 Ѩ]-yrSLpT9ƺ)WaW,n UMݽ'C"nE[&z=5Wl i¬-g[RgŲ/vw\9i?61o*lч+HV92~ 6"3ҔF`#9 SIHZ  2`wat]AiN&@2"(P L I"b#d-3Jj%x巶Y"wC̊y/u= hڥ])'QݵfAWW.w)]ڞ޻ṛ:=V1J}Wܳ(E+09|VD-0(D0@4񌌸, Ts&8tN|,` h"" J@M%W.ns +%ݽ ,0j$C0Z`$eJ~AH7grPwNbL[MH B2ѫrMXnF1$\K;(]6_anY-vjFZ^mSjoԀPXe4p 2̻8X$0HI0 &pA"A&L1!P0̀$  REA A ]?P(f%&8|V*Ä"˵Ȯ@l@.`q(l[Q{_pNh&2yCkZ="ݾ|3OD1*h᥵ `{Yd|u\}wv41}yG%W6\M&j9i{0#Wbe̚VˏI%ZyN=ͦu- P:$RXb|3R硷CF>#Z7[8h![b&ަ8h!H94/)F[(CQ X%r$P"`\tQ0{):{AH8< XՔ}͹1 nH`٨j"YIj+Pcք?B$nEL=m%uq[D1/O>h%2nKrѠH م3xbäWFma*M1$zY@Hl1ٛ}aA `PUN06e@К0!16jD9a6e   d$0PR1ias*15ك"*"::7+PX/|CfU|b%5/z.}g FuaU-LEeO+zrqExUaTp рH.,$hJRayX&xDа8`hE&e@'E-2즉U%)FV4pxע\+m(6d= ww?~*FUSZQ3]KQq&Dm]DnW2nm+%ݽuV$>ơڿJW8T:n>@x@t#(Hdt,120LK36 T!L &7ABT0S 1*lvL @Ihh 0a3#911qXZeD sHLd K2ճY*ny+%ݽ ,,f rڗ-VM0s"VEr!RIڶC4`.~ \Ll͐1]ΣpG.y(x׾ AsU̟* ?SFH `*}Q I}&Q6#TÒ h&CC]D[~IBCh6詸|2*& xrG="u*\lMî n+Z\**mW@w'5z&״zQy` M̸K Nw ʥi21|;@0ɫ   ̃J0&Hke(+1Em卺M1/JNDQi '[BaJ}')61\ YU?1^nƏR1rU2PjB|S%L&uBb@є.~-;kP#5ʤ *ET_$ zr}EYj蕬x.;-AM"f`չNr{|X`jFEߏ)}u.q)Ωf|xzr=+Mm{xNc0p4'y h[z+h('0I5 >10x=f"mW l2ɓA$\3D5Q,(|D=}(h*,`3DmM1NvbOLeD3(B9i?4w])cw鱯ٸWS||^(FHn & ƛP-k F+%]O /GW|)a[/e/Q䊭KI#rjjӍYBt.-Q<z+ W/T93KDȵ"!qR|/Y8ZdEɤOXnMP*$E(>%'T(#.5ʆ,CP@cT\P["J8uO0%ZE:OQ2--->LX4:ovVQS֒͵f*1esb_W^YR~~c3WJպŊ-eiem̍ucONqVZ;  |p }W>m፲* =aCE3AL@ 8@0,'- UmH !$ ,/K)% !Dt^T@FuOì9MԨKΗ rq(#E剓.,M2xvѶmf$MK,9Xi;BY4[.6Ƭ9]v-k7[t- d  ^Ѹ & '2tA`lŌG-`aF"8d@V`sAu)+قX2M fB!aaqh08Pё$Pm*gͼ: p @2( A˔US8k:*"F4 Ft)0D1lsAZcځѫ<~+4ƆfJ./LuLȜZ z-33d A]6{^*|\eg7AF>& f&(,x 56c/bqHQ$䦔B(B^kZ lʝ\k*{* xΆ.6dCX-)z3YfZ]׳O(يU|EDw~%G΁@]2.Փ49x``A,`Tݝ^v̀K2ni*fM1)XhE#EbREiF[D@@D/$=M:I).H.[$Ǵҭ'UڟVF :Ǎ>ɞw{;􆞳[Rkrxwg̺x[jD5 P<eхI1 .3($Pe21|(|a2&81SDcB|h"$Lċ(eĦVSn@!Ĭ1؃B c?zAΩB{=w>/ N ע|Gwg1,%&r>j(T]zufkm՛By+!9 Q|ag BᑅQI1I ? ɂL8,BGf'cDB%1K:42تMw#Y}X-P=CbR9K5(>qfrnwL=^x-)ω%X&1璴JJ]*5UoL9bfCA|bTp\ڀ]W2nib)% ݽK[v0Ya>>`EN(e1Jp45ʞ*4Mw^,Fk[up/r3Kry^_0dގ3Q MZMFB ! VP!1HKgE 5$OX}PNћ8%Bx 9߇$)sG-CNzj4;]d$ߨP-N2jy{V'.\\|MKe-ͬRVfQK V57 .CFqpӭPl0  OɑJb$8E{s%zW,ni* 1@zzYŐ1TCP@j#vn:E1(r|l+[r nbJUf8MKf_D ZU_UkCm];>7dRhΈ<e5aP\.$37b0&1p5(āFJA 0A#*΋4Ba& !`]a" Q 6P3@*7L0n*)vuy^#e4rrv;}54HdÃ_Ĭ4xx.]cZkmY\`^Sam08(D9 (5;300lÂ=U r9G z%Vq6Y1>cPڡ O0AsMu0YS0niC)% ݽa؍Dd k[ml 4^ XZ?kYcU&2)&y,02 @ql@s4@prIqT@[ Ǽ,fXd@PaqG#4 T1]it1EO,ni۪1΂Yì/ ZrЋBj;zYǹ}TdKO!vo3gG;tKh #D̓x0oaIfa@6 Ll6H!BT ZI@e @Rƒ !dRTV`x"@ lKܬb<6}hkQyx@uhcl6g*j6{F~cM y3f>q5ϚcN>*.ɭ9 ^,!10ñ-@1aa) a A t^#REC4`;аfEEf& L!#P쌒y$[{J`GJϠ'`+W1DJp:U߉O,niͽ=}aP{БU:z٦-NSkܭ{ܵq)q܃kz,EH3X^>b  6, " $pphZP"9 bg$"0"9@ZD!0L0Q$D,Aa"$v$sVuG䴔ҦKwD49gԷ: cFV)U^VY |Y-sͿzؐe ^Uݟץl]okKŎ1U@ 6>Փ09PQ d<`XXj!S4@ 11 :& Cf6,0BBB. @"`~5*Yuat;wG.niة1Hn&Ab.H$R&^.ȷ=b(i 'Ƞ,2v*E{;,tr.ӓ?8K/P`aI&- El8B[3I1`J"Gz HҟBkF>"lj0B (J̑.h9Qq\D)AlVhk];QI'0dЗO*nmܦ1!flEUI^2 &Ӻ_9pE֠U+>^oHM;ڞ{BԚԞzh@c !Cp0 F)|.@ªG;0#[hD@W<0FX"FPHCX/,N,f-JeJG)_A @1`LxЀTKvZg(1oE (XYU*ni)%.f?5z i(,xΏ~ㇱ)Px~ɦ.=oғZs3鉎3P0#3& 85Req 4"`B@^0" r10 ę 0% 0ISqe BΰRK#8咜ZcLPA=K!zmdH:Kћ>y/-'y ƺR,UY9^-SHa[Rf$R HFqT4*Y0=.+h 8xh .BW@t"As ϥe \v̹[KYހO.ni'1`6\$weS-!NC9#9eZ]:\OGwpHj! ~q@1GAD2`;`)HD" F9!V"" JI#X+!%BK" XGcLEdfN֤r5qǀɮsoZ{ kt##)SyB%WUĝa9&&R^ %V7nsr;O|],0X Lj GLq 2n}Zh˜j`X_Ѡ[(zb#JdϠ^@ RbRMBv iT%MX K57,ni*1DO(Q|5AmF6+^_SJϩv{}3iGTO|mYْ텀`xa) "!F0͙j wH@(Uh?M )@ ZH&%@QNB`눘K4{`(*z6BQ=wJnsE]uKYTCF/8m[;>5w+$\^C; g#j?=Ro3l`#?Xbj F"Yccq0T5*l@8(*c!(&a& P“8e s P\TJHyH*#;*ni*% =O(b.YaJwT2ѐz6Or o֫]9aƬ'kfWh}igđ0ˈ/#ߑtTrN=1״%.4"`8P(?M@x ` a*C* %IA(11I aDH6 Q1! HZ$sb1 騋$7U"nNy $duPTz"WvYQYL-# Vq|f% |I®}Lz=Ajh<YaAd Q14l,`&|"c*:obXC2H2c0Chc ,NZ;e@j8+$n& ͽn([ ɛYQܔy_Y$0̯/Uc\c1I] Ì~ݠj5zEZץ#Cn\(c=s5K3BC/U`(IUt@% E@`0hH`8 a8`" 1aphdĂEGd$ &(0a|0M0a9T(y6K '%U'/.iG雮iA,JU7۾ٖ&l]63ttu_.Z咰"m1AOImUvD# 30P@a^btJ)z(0dޗ2$BOD23v e%f! N Jݽ#0B($5D@ޖ扖e) [IFEn3Ւ[2h}vD̬t܇˘IźV|-3|*NQl}iK*(!ZU.nVmtpi/^S\M0(@lSA# BP!a 'aX1QXaT.?** O6.L0E+(nidݱ R&JW\BܛsGH㊋6+>S ʼh`Pp\z$^z[/aσ!I3(!Nտߓ]CUՙɮO|ş^*$6p 'jL D28X608CF )MAi'M!QT{|Dx k/Q.Ǵ (e; 33aΌdN|/.AYk(P@"fH峟[6obEn|ٖԾaօmӦ{-`1\6! UH BTaR ڱG8BО g2p0P2"hDąFPʷ X@ <7qY w;*ni*$1srqJ0IH'U6zKt2/b,?I?Mzq»[yE\^_t-K h!nbEg` '11MvZ%&+#Dޱeto;jR$¢}"H\D`ʑA$0`y8X @aKY2@c%*R0T1U ,8ф a8k@PA '2fEJYkS'{dcmEoJp=+ u%qLEl} v : grjՍJ-լj)eKxTA@Kɳ_7  !P 6 s E%S@ƀ<h AX 1:/͖9& ;#"n퍣L$tEY@P@8*Gji`ැ@inIDf丑5Jr),XUenTy*QfyiSnVg+ۭʮؕfU1j3gZoGڷka186u6m~$!̄,fbL x2\ L\aLsŠ% PL? LP,8Lt 4MiOͪ 1x0@3dq10203k6PpB O2eIb<뉮D`p0>ZCQa$0@d`dF` DF1IB(mZbAM5=﷬A@ `+GvsXP4:!U݀&C= &(EFZP&ȔŁ$R`hOon, r:?~Ytr[NG-G < 0RENZ%R,Xmqk&crEFH1$>ȥ4uXiTà o)n Zm:䃧(pRI [bi!*X#V^΋~AU6bwa~ܭTEi͕[%E a3Wd!#L'ĊcIhЊ]r`IX12!\nys x^ ǫ+^@ECm5)uWbOIުcԓ\a*h\g"c@L؀>[H|quQm\:͜=&@'aXRٌ(ڭm!wwNfvb%تL>zO[9nGK>@8_L# FZf> }{'ןBiesf̾#O3n[]*%_@<|bemULw=EI`hQXI(# x,PQ#8`O@X(X2${%]C-@lV<}0r] he)tp?J Z u ҕ+B|%b P1'4Qϟ9%xc?z&vt뗺׶[갳k0qy;Pa];,qvGlG·O(T *3@FN2#0ZYŁDSXqe/ept˄E9*c" }14bg-CJJy@4$Nq[S]X1_9|v jE?WNme*ͬ|*&WW{w Er=ʈr3%XHSIpΛJ]h4٠A P B$$AШ4㘲 V,p 0HHH fiבY&\uLX ɓeֶյ.ڵ~ƽi#&qP*{+:VCRC@(`>f2rFts0\|k!&~ʉ hBDD7aB1E B҈ AXaaf2 u!WMPb߉_iT.7Wml=޹$BJ76Tdʻ=[u݇;][S6-WBm =Z|glxf)"xX. ƥM  `_ŚoBPd>0M T(kHb2z_”dPAh(2Nϖ:<%t8 eXG3E|\"t0VRM 0yMpƣt'sM_ 5Ո&J9a1!rU-*vhKQy0]5 La( hIb p ,1i Q!x0T΀$ d@dA a¨P0 b@PwLPJzΧP3*W<;A8O`iku, pE߻0Ne_|_,~=xfQLs>~z0ʯEWJma荽Y(QJ&ktrڼ+2_v:Ep d@|oi)6fkjlh/A !A9!1UoRL 6JBFxXZ^b DV˗O[1wdi(+93qK_ t2tyVr->5&s% ܕӮe&wV(>۲(-gȰG4XPNޘJ$U x 2c^kcCa!&ZX*b5TH9`iт@8an)XARb P8À E+ NJI~BH@j/ipգ#dasrkՖCL7S--JTJˇӓIZy#ڇj \ =gwjMR hioLVWBm鍣*ͽ{E7 V@ YCHs%:v 0FχiHp2! c HY(P 80EE¢ݙhBCjbnkmNQ@BOsVq!Vm:|';GwO+DnW(^u5B˟p;|n<vpX"FK?ep^&HNMD ħ y+ M5) 4Tt;`E P0őP4( 6E*Ih0`*2Hfm *ͽ=EPl%Y$'(Va RLmJT<~щ5g^42 Wl[~m҄ 'Ic}Kɣ~ˬ'Ǽ\O|Ė|ukFY:ni獽+fڶK'kX*L0dB_*!aN@|99Bݓ2"0dA Pd*`Qa%mX0%{s`KgnijrlQFjD*jgOHI|5=*jҭbnmZ6;m+s 5hy}* ͽNgnf,HdsE9@՜۠YV |il@ 4 s9$ `Õ@aB0R^0YH$hrP #a0ZNw0C#& /iXz'$Yqηu򪥗+VEZ,,෼==ΗxpğNzl/{ͯ4>՘rW1}1mkԟ2ٱ_;UGz3b@Nzk&iijo$DM> 0@Qk(UQwhhx,HqUSp!qs B&m<m\ȲjU(€7Cut'Jf%z_ÊbGgQbma{ͫ:=t94B.Џ-IS C|Cl 5RBCDYxp+d+0fTk5lA &jح[ Ƒ;V¶C*Ӓ؜D.hk'n4\ɗ9eD+^}8~ܱfmvH8|ְխHz^}d k,vA{1ftUT:jAS$h 3X:gb&n G#92`ܠn<6@" жA`)L(Hx0` XZA`(B"a+޻S\ˤrΦڭx-,Wo{`HOf.cFU2;uW(Б^ikK g0CfF$ƇRh `la0Ʀ`As J# "C% b N1qqΥ'(SF-YzbһQYxmc/V|^pO8nm% ͽ~+m3C]>w+_]>[z&-aַPF)/2D5X˗?`=pO5`)?&hdjG)":`HT~F02:J`eTu z)f é#y&Z2Ψ2rYV$ L6)"foū rbs1ϓ7UYY𴹛N4 W>m֪M=V}Ktg lka֕Ғ">|] V0HPDpą`X8L 46 Sb =a|J0Ċ[Lc_·|jٹ6)a嚱jݽ܋X{{ؔ 6 ɖ9ILA,!0IAbɶ1X.\$>d `ϣ*I(\Vm#M*!**zeۧ{Evݜ%<;;_^3oH {8txFN8~v~/.c>,޵p3I0)4>hljFiRAf*20g$sADA*f`eD DC @4XU Gq=# [e *Vde/Yl`úfH@5(KMeJ@g/V 9AnCQW@m)Mͱ5')Ɇf1%{Oq8(sW5}`<OxJegto rntWfa3 ?7'c &_`(G3hTa#`b(p #9̣W0 `0Y`BGp;.Ty#wzvIPhT k0PzTҜSTLs ĵi۷ܥSxpݩ&^IXkܰHjEu+阘s6a3^قB,.gvy d &h3 MDeV ZIhA"BBܠU$D ]VXVsFc IAՎr"Y8_Z%U sP\hc/]%{u}$Rq\5\{]PmhsJ]!fNԽ騙F-AbPb1΁(Dx :6P $b1jI%v$!CcÀf,$ ( j&GDPa`Y01n2&˝ѻ:d.5OUt>^a"KiW!E{LtަWBm፳%="4=^nM>/oX,xY)Tr5Rv &;zJ> =0[[c[}}bVؒ7WG`$[HMRŇ onŸ .o*l+ HQ2cA :MB`"X6fC$s] lGisKT41Izl>Y܁*ߗtBY twy%p̅n#B7$Eh]U.nm* -%m^c>k$<_nnυ%;2(v:zbrbfu4D nE:,LK1]@4`Q.2g SRȾ0 n6"BICeYX:6)&lG/UV s+H +;1Do쳾wois6 ce"q4(@ PLQf(,82*(`P$#b3ҙ!Йn˩2Gt(DVX!j_iuh=6({rմNJֶDKqosz!3iѰ:`mK>]jܗcvIMkvMO4nm* =69k3nPNK6];*a. j0DSCb ihl02C#@@<[eAG}0Qc*؂ ,4R-G J"&)0C f\4[a@HB)~;!p-B9 Zo zNZtʮj~C)OkMs+U]zإyo{F3S.$ĵtG\ƙm(o tR|MD&)f4<YG$a(X()ꊁ 1q"ܥxPX{–TƲ,^FgI R΃ө^\8Db 'W_,+/M.72Gu~w} 9qnκb2W2niުfͽ=Z[;{\gx{5j 8 VdG 9&6*xjOޑjL_ˇ+ۖImqvXE2r:8RJYz@`+ ̬,0HLI @Plҙl陠 !mFu4$8}efahLmlHa[gjE BpV@i kEfЗpDydپ{R¦~-c=غY.nm捽=^ruZfXѲ̫Lq&tJO52c A=!bSAcLqlFP B@I@471 |Xud!6LQm5P6Ğ֧hbi?ǥVu.  xbIh.&=>?mZi6u[l{!ômgY}VrBqrkxTPL%TC0Op9LvEЈlIdA"o(pЋD䤗s|g~oo6qW.nm=Գ@~ɛnF5 ?e6]d305X]')SVDV0Գ ,!u"1wʣi\4\UkVS0779oçًGV :Ōp,ϱ aY#@A gY Thep$Ӕ Ph@^cb94\$.d:&! 0!C220qI F@1136 U!5ApBP'9/U ,%$5`綷YW2nm٪Iə,ŋ[m[~nK?]U{wxak]}q5^Rwkjkؽn:x+3K#.5ξkN MYALe1CYL)PX_7Q6C2d5(ƍG&5?)! .RF@+fFG-8=c9B01 93 11`VHWd) J@A{  $  ~f|StA8$TFBW ILÓ`ˑLXA0<04 %HS8?CEW`1ym ` X Sd.*ß瀁2񤙁 VӖM @bM_ JpS` (Ǡ36*Yހ*ϵ"Q:ߺSDykLI/%*b/KTn;!XVi+![e ³P3"L0Zѧ4d / 5-tCMTFJ2E4 uJ'< 9fGM͸2tt`K'KsuB K)&&1L[c NUg ;H[]ivvFR)nv:.MNJaiL˟ .(]OtI0D9]( "_aKlJlxp)@*!2ƒFYhvR^B tZH़V"]B2a bi VOR"Wd=a*]1 ҠlS<.sM:}ّ؝Y )m]z)$i#%q 4P"S&>, A%S!"̶ǟ7ߞƤ:6yٖŞʠ=z1]E"o&=҆ESk((lIIohP_k?[M.?uٙȭDbR蜭`i#k(("P]W^l፲J]G*vZdq's IlgxFGy4RUƂRjmTp)ge  |w3l%4<1gU\{?7e+h]B2@|ݟISXY0],< s2Nq_pa3 F RǞt$( xR*2liQDEb{ #7&@c*C:MRFTג^i7W.V$9YnH4TōIgo;t3iIoUrIJa8 P v& s͠R!)WZKqLG"L!٫5e/*' ,E+̩܃5UJmiͬ1GʚGgPxC?w2䆊(H0Y֖LgT5 W e]PWZ>[s[%@X (@ۀ88XeRs:ˆ&Y4FA Gfɚ }Oc)OmIUMO=dAV/?>v# 7$sC<]D|gf7mo4cslSSTl፺* 1r&6kH:&?T uEr՘Oò[YX   I+cxBC( l0؄̕Q`"4vt~EqH XqD~\:<  *B5փ#J8DBŜd!&e̪t\xn$M q0B 'P;TlcgV +n{ߧ#kbՅK.1j@!35+r6`Q6$S3:`! K@j&մ.*aZ$ $B(T/ӎ P6`ύum{[Ej.J]aG !:z;'d4$YN7 ?8fʀ/_(lنXiU@ni*ͽV]S1캮'N >0Z (N'(k`t+M *b'Mnba#MQɋIƑ,/v:mpQ'::ީ\?YjܐdWL hɫ\8ٳ;3~Zڝ&`4IAi1 )>6Ӎb.Okn3.o+cZ%@Lf3Wba C+ d*NZJ LhlL LˀTNp,E,0I|P ;ʟHfJ0 " iܔ\'vqK>c?[H\n~?uvBn$ف:7WbiW@mVͽMX+LŞ/'b8[SMU;}Z4(uB`gVgzBGDU7eY? P)<> M0*a1hZp'*z@5^uN. ] 907=DnX*1Kx{?R RemY!+Gm_ĮŵolF{զF[Q!9|os;dS#ږ*:Q`#<:"ϨRFa2+ˌCeզI0 / 2@3D3#iPZ`X R,0WR t1s{,21ugSĪGsMl8`Ed6fq84i @$dR(PDbP@.*FP&9X(;r 4H%W)'htX0hMΥmUF)k5yN#'Y("ҩI~q2r+QN a@2kren"ʽYLM5lW{~suĐ8btQsF(tWt3mcK0 10QT aDHd`#` 88xFLP(HaKq(q~(,2dL UIA^AEi4,TΤH,jI[J,/vCXY]eWBni7*ͽ$eas53nFk9^ YM,o[츝Dƾ㦈ZkjcB^̏H1BGB m3dߎu04`#CDY(pf s2Nb9S#  Di8_Lٜp{Ds y%duFul2LT)9 yJ}r3:gJX4"r݅1'YH'_8M$7+)z-NM;P"R<7%  G&ByaoY BsOC "J@?IC;S{!&@_|ܑ[ nW([ ~QE])T̰2df]F75W@m鍢ê鍬Y?J3rȓ[G=seՕ S0IMz8HclƏT> ٺ04(JĈ? G!aE#G\ʖIpUW-J\ ,?+^a bIi|)T0-1$O^1!_<Ëʸp-]R$(]|P`Օg&/5q UmAx8qu@o\ 6RD*1Ș$ÎĮmr覠W{c{ '8 M ܋HI%pe1th'3[(a>.J/~ǖfLޅ[G/|}f^ٹyY8nm* 1rf 6 t&<CX 2T̀4a  o1 8).CA *W.pPb  (Q*FEJ&fX}jT>3ZI4AQ:P$2F n)ua|{X{cujx~LҒCpB%&5_XfKkD24$ՊL2 C^ F4RL0hgrdĉTY&A"Z`@kdpaѡADhAHT0T G̨IM]`rvx>1hrZy3I ^M}s;gVvڧ >\yq Y6xu1yaW:nm8M=bI%qv[%"Gdljuk~g92­nĀChMg2DQ 51C@`i 0H4@BpD<0.XY 9q㊊C-2C*&zFҟN6zXDA |(Om$T$ 'lEk2pP0H͊JTHBAbhkul1卲rT`#MAUIG/jm鍣*獽1 kXomAyEX6ΒO  g TH]/JiYi}ö Ha;j?fo( 4 EV {I&+ 9DFc#w"0>ITb),x)aD`E*: iQV_'f:&~ }=K>P>O ;)T-:?~PaUIf#q{T*Z|ιBT2UiiQz^&ڈ$S{6A- {Y[;{@t\pb4mayEFW:nen*=_ˁ!SوXm@G=W+c/}ӷ"S۴uvw,uj_SVz"23fͭ,X\FxLX,˪D@&pWL+KM`7.JB9l 4.MsTfb K]їʢ)<)#vQo#}e c޼čAR,D(4֡ZP&5gAoU .:il^2Rೠ5r^cZ;S7׀$X2E51gZ&Qd>$7r"ROD,9u#|2GV$ϕzBFUnmozg3,bj,$$T^F h,Zí]ea# VaEbTEWHma٪ͬ=nvÈ{Z)' ˆ͆a0}[1xR1 4=r2PR0[8|0L001'4#703V!7/󄸆lvi+nKbQY6eQW0nM̱cj^c wBiȍGA ]`[0*zQ<¦#pLg2c@ӑ̌mq g\o[irtuM9a&`1uj_Q"n3ʡ:m跊*+g:Vbq{SP#!$i!f~bd"!=hp%c UBe^NH(> -"aE!(*hAf@.:ITmxF]:0~"f˥G+ea GlG8Y2niN=VɹLNE>l pb!Ctk3Hs&67 æ2sjU&VUr6ɗymFj~lI3 4ܖT/ 6bfTff\`E \1a 5R BB!MAapl$pX1iq\Fj)$ňMWLmap+&=h𺎣9Ф~څr"Җl_yuaZ5Ya[, W8&gZCgx\UWi<&V\7+NK!-ۊIfZ N\@AFMNHȑ *"F5$%eQG{[aTd*ʙ[aMxp~'ws$@[ C.7]BvЯ7=$uB oqY:rsbgveXfn`Pc=3!RV{f&04v0#AqA"2n=HhaBaG / ,H^W4ni* 1~06vQDYeetgcMJ,`epǵFXgB{JW]z%2cĨ܅/rТn:xTC壢N -)xR+nmhfZa $44({&` i(vp a %(BSKBu:!p  i1|^e.+ I9z$JQÏlTE7JؽP1َʌ34 ,=0 rP $ȱ`% \7S@}0Js6%BLxQ&[ԓ c.  #G E<;er{qnqa;y.5b%ۨN wОoIZ O"tֽPp:YӷCt@p70zŲ7!@\1UTL)XF3Ph$YA (]r-y Y2ni*͜%,uΧUC=B`8T[gI-(z3goW0htRBFN9Ԕz4tayQ8Z3#3D[0H푢6Hddqs6]53ғLW  -i' (`rpPgPQfIhsZKn7Âb[bah@0 @R!DE8Ah;B_ltȫZX&(j*~|jf+1цWM:j~7q]@wjhj& $jfLMT[K679y-igXW0wn4,!y2SM)(1$ú9*86 I"HfΝSJD]Ē$PXTp5W4ni 1^Ӓ<C|Foy&O:@sYމT,XUt2܉9=FzlΨXC G8brbi FPOVPH-C_$M>pIv |2H$D,X -,i"%Q$b13ZU20 %8x΁Z0<1=@xǍzҚ8+`HBls;t.*.Xy[a֝l+cK8q,gNnբ{2*Z~ۤĐE[+lg@JM= *`e|9C 'ր. 2XrBi@@ !sB)S34&9MW4mͽ12.`t BDhZ\frnҾq-qLMh{[ؾ5+o=P4뙣eګFGR|qU)q]-3fSQSF)=( @Q ̜ Wc1]3!JWB; 㾈iRI*)9ѫUYzZ Zx[S+/fY햦I%_DElumun1)" Qx r hTD[T\-9($4u|&knHtUnG© f=:&M$qHxq)F1t-a:, EW"r S flB :qW@ma-̱F"ab}(,| BjD~"!>- Mai^4 ŭtr~3-Pm:cfLCuAԲl$x['U*7Lt76*h^6㼆Rdhw(1 c0Av( 6&VƥuVR5+N*eA)Pg\fŒ .շl`qF~|^`y@A RrD0}0ĀpR&rjCcZ| (D8`flXPb׍8L4fh/ ҫ(j.^'^mo5Kr͝eu%DeFke`t' BIn6XWa|ht\[ƣ^D%9!iшMGI&*,)5JC /~a@4wvcj~lJN*I H2__%R2uE}L׉0NC߸z..&xe רRt^49\J5i,]QjWBma)荬1d FW- oB ,@JDm0n2#( P,ƪ@45E# .dIg>D$,˙h0șbӥ~x. Qqf(>ϽFNm#*dj^?+[mV,V@\F4 {k3-GĶe;IRDL00"# X ,0hhT*pr#ԑ!8y6tD$\@*{D"]&hVRQM9JJ Nћ<#-7O2c!Q@SVQ!^6NlDxWlX~ʮRS(0'Ȁ!W0ni*ͼtSv?0hdbu(`qW2 c|k0M2L 4a@ `6l((,F$ݝ0сAFJ*`xLu WU:WbP TK=hh<.YTCگj.2;$ߓ fg Np3pA|לVY\@̥۵]!'3 j.*͵uF ^p"iwƕS8 L'1h 3 p1Z 4\.0ܢ 6U8H 32F, 2$yS*cd2T`bnPehpevkH[AuKUD5!,]BZƧt;XiT3 GC.m ZZsrTˀW.niFM=6e4~Imn鍮 RPaƁ,rHT<ı4\׀x̠Mˌ8X :*2Qm@C !y(4 P1iԄPtx4Q' ƹ^إu,Ci`wIJ^M̈MK3)3Z䉖CR=Â歾\&nX4РGLUe*wqq<[Jkkb(hv ]Nj`JRhJMB T] n[Mڒq>P>lfq򚟇j]g#53t;}5jz㪞"6Yc5,۩XW(n 1l푪i/ ܖ_.tb'FjX D&bO$іZCóf 2(IÜ LLr 0*Ջub#iG h\y@d Dg|c@CH AB&Z,C p@#s]Q,L%QԔ-hL:# F.Xft3WЈV6j벼qo~wG>Twۭ7V;ōJE\$j"t!*Ymu/ XlGkmm7;)@PxiBy%FQieI&.@f/, a F-khb `-$ps10hE,u<Q"Ǡ`@Z>I?8t`@^  5dKDJ'etK@]Y,ni+%ͽqjnMdHQ. ᯤ W$0XZv u֙6c5/լ po+HnvOsR+~{%X9DhgSJΚs|Ʀ[XRTf_4R%%``ƛv(9>*qGՕav rĶ]3iTSy'gicPcj ";KFSHo3~VӨfyUBTKmʨCyph^!e&Ŀ 34N)zu/ NP&\Іj5 4m3qV:ri5Q,kÎ$9psh8[S+AQ*9L~re=5򨊿֋z}H'cgW>ma荬1 1ōHxʅVl34o#`MBxP¤EF n oEVz;].xB L aF3B#N1 1t t XGЦ)yR *# @b! "j Ef rڢ^l;T[kYq .lNUu gG/j!qS͡RPi]!\_H_$/Psr{3ZEp(U!&b)lt oE2_ uf4"z,y`WOQ()NgJx&h6ha|V%vն隂_]36N*4JPj}jjd8]UWBma-Ԫ獬111Sf8Rƒ09 f;6OfؐJNt' MQH[f[6j@p4.E97O5\z3" Q\BvtVұDHC/HA20}bh_N<#=?fB|* Qzp^DhpF|8C?Nna8`LP`aH㝙ykVU F&^ +40!3UWf&M+@t.9VyX88(|8u2Ɖ۸[eNv7ع'd HɆ$gHWRX\U/m)d\ g-ɫ.>% 9:&hu,싊V8v3tuԷKD.fe aFf"bIL_S@ma7*1 g\aCg% 蜟āI :4@hb238W 7g ~"SR+l.F2tб{Ȭj .nh b=I4i&Ce?2`a% DH(b,p@q@`JTyâIW2m卣AͽbPGEV 9p(81 Eq1d`*^q%$n 1hYP@0$ JTHD{HcvLKQ4^!c:$7er+.Q%|^8) VQ!Cxތ5CYaURRy֯BCqz#x Abcb+DyՀԹyZ0 FifzԒ>cw")V:j[c5;>l klj\QIGl^|\8vOjj80A. ML$3\ʠy't'5H;1D+C\+EF"@rfԒ4 `B@ 6 9"h@0T\.R2Lr-FZ䌅\Q\$E < .E3I h]餛TReĭQmfv5\>oqi,h-ysn]NI>YW)t0: nv)jyDW笟쥀yW.mƪ捼U9ʤpzů+BBdy8`t8A_g(9j`U(20hƓS S08b@ x 0YpQ3h`<1Uƣ! Ku,ƌ$GN 1j } aUor@-9nQΔ vRW /ml|pѺZjJ³d\6ft '4iFFt|5^ 30f,RKгib7nzLjx,p |4 DŝC&8a0 e2 /x,'(alzP):P+ׂ]OؔV44QR?E6@52p؈BNSZ=Y,ni*f%5Sm& fJSR2P&`@:MRҲt©h)P]$l;g$på *Ud=S6ܛe$22̛D$i! 5BdAɁ14La`)val>D&+nRyt*;룍d6n#uuBFkrm#@bHnt;GW@ )\^4[MT4ǎB ™ mEL8ʀبbxdla&&r.UJ`E*M80Jp0Z@`cDkB(Ldr 3/pgdJ @GFlqmA܏mlZ/v^˼+ mV:*W,m鍢* f:7~zZ  χ)eeWBa><9[D %p@,$U(rJ 4CWÍog`eBWD4 ĭ:@Y+y%@P8XՖVRZc*>hIF6eS4}t\8nEAZ#Z=e6CAz,X_RO sOBFW06]+6)ۤm0k@@W.m卣zMͽ*ӹ!@[֓Z۞Z&ҭftfܠg=!ZxR1aV 80hsL1M62ɀS# 540ɋtjf h A2=`(!XO @P\L`Fb!5DjcDd=&RR+ Ǟ,o8JT hXoX&Z;I7Ie{վ{7]b[.Hmyn"83.qwa#+upwG8Wn1|!n*@` 4@4 ) @4wm5Vn.KXQ%v3\sԦ٭2Hz@D-8S L'YPayUaW(nm*ͬ1<,[fyv e!hY H<')4=MR4CJ|M!KT-*L @C&2aC,Dg(*A0Oc0Q%Lbj>BSi#5JEHDVoH]9n]}l#1B!ii+Ig)/x8q<79ڇC܇m)[p(R;(/k"uwV>\HL7 lL̸L^0࠲i(d3 FEg+44iT ^ᖙ…BX& ;Rj0і{:GS ndDH5vQԱ@^ϸCc\mv$]W.m鍣*ͽ1Jeyks IgG%;`hayYmrl^j!)AvJ}ld'NYNu19⭥Ӊi yB"lUtl>:aD+fC)'tV,@#kL3cxbS0̶s10vЀ N48̡04 EFGNiX)ds\&L) f  qu#lrPA"`hrM.u*kʓ! bx@v H="82~j[$*kO^99“1,8//ڱ;;<&:9W>l፳% =vgmKU([aTE H>ƝIGoHp H՝DD`#f*?y]*1E z*k*AR0X >႑\2&"^H("{*֢/J'OM'f⨿7'l$5Y yP.<ԃ ө-Hkwk+y{,~];~ۺ4RxPèy^#BR q1,d Z 6!&$]$MRVa<&CCtd/jo0BM}Jg+K3ylsR|Ԓl6ɢ$hVEELͣf^OV4W*mͬ10 ʪMm:#$^x!Xա!PPdB&vFVl&#AbeaE# 1a,pUT DC@0D/$PqEN3Z` 5Jf*;aQ+s0u2FXFXm :rwN fLa a۽HyH6wk6=_NnJi!-'a]ڕf^\ 6Dɺ h( 0Tx (20ƒP-h5Z%ZR0=Abƫ,QMu!F_T%\SRqW,m pyM3BX1qzS݈e802ITB7pD(E`tF-tReƪF"s@ H00vTDS@4ȡ`(|& @/4~K<[hMrZ۔![фq.1lS:5PL,̻7Zff0N\4x$&wp LH䲒=fy[\4ʻƓI,cs! ƥ@(isFLU`@C>3!+t|$U2:Xh=KWRi Tji\>]$sCȯDӶRy>o!U&nqͪMZٱ%Զe)wCƔe6<^nϭQ| 30˷S t9dsĈ0 ‚34-*h!) T (J"hF<B*A4T  q^?dd Va%ĄDtIH lDUMxi"(U#[, ՝U\>IsbU% 1j3L l JƪuH%QM_fmƒxw<Ǣ׋/`0 eA'd2edf]LE J@(p19LeHw9 O܍Kr^$EQ|`HھLfm1Aީ`uD]F6n$9>x%QkЕ Hyfz,E H ~$ %fZwyQU+$00"3M)/ 1HQ! L <T4X'x5'0È7]  h*ep@"s$3Mٗ5vtI}aY1;Q2q=j;+Wtط'!HKTW@a 1z7!CB͏ZDԨ߂CV*[]:Fܶ0Gt!HdS"|KBȎR^ l88ALD*6%Q~*feR`^f)lv^3։ֵ\ 1: Zĭdzi$L氁.%^ e4y"dItst,+ e2V銝ŀ%hɦs>+PK%aB*~"Q_5L(A0G^I4HqTyP1zk~IwӂtZ=Yff_Fw 6iXOY"ƶ;`&3[رOx,{fz(Z]QE*HߨI$KݪS2me-*獜."ϊ=n`ṀdfI`22 C  |@pz=As0 *: `a)rki 4+.ElF%SwI7aRZ;!lp<"ܿE]2*FDC>vN{Q$||yQ)FL2m4ՋG*6f+3&pQ!ĦUҎN:eA4v9iᇒa"!AP4H Spea| 4G -A D\3.,0IeJ,5"&f<+ՋKFjI0S*4kQ.t=&oWDׯ:zxWSG`z:Xyvٸ҈L\xj:ٙzH dp8 YU2m-卽1kiDR xۃQز DhN b[vHEַb-Cci&}1qJxHN2E.J̓qL33f`yj~G(NHoC}l+umI,^ku,fưg`vMD@r9iGY:\p;g&Yp%T(8EPp?48}@߈Qg|&pV> rXKAKDy=Vb d&[Ou琠ynJg;%X6#Ǝ Np^צVM\bF`FdfT8lD> `@ e9`lPYCU2m-ͽ%0 X: JHa%1P%c.Dum՝gYQɚԖ\+Y*#]aU;aY$ߴ)#eEvQK|&dXIyuGv*UkM8$S^vaSF*v`&BFi4`b6!=0@țppbg5#a ieD-fSm%eZ[b=%<KI>4~C8PmUOi]˥npՈ 6Zu}Q9v4|}NL"UػeUr[.0L:iOggΣ8Ҫ` l^I‚HhH9Δ0 "93asdBLQ8pX!JXC2dDV WXId>*]|nI:1. G.m-)卽%/tMF@F,CE]zlu{qRi[\JTU*k^ HiqϮ.b릆JgEjG3<ߏz*T]NS3 82\߁GL)+L< 1yVo2oBZ vF`JT@$HJ 'd%n@n1dt.. e$\)|P1[F矯uP9OmˡUִ“j!=Epr˚b~`f*2q # TRi9 >`@Paug6HcbB#"8&"B$1X8 : Nt\,Ž&J;C\qkerߙAO.m鍫!1Vixe\V ĭHaQ2͡OulD䫛n8Qr_}cu1E7)41/,rz^Șu2W0g~!"^K9U 3P`( M =P5-dq!bA&#lcȈdˆa F`酁f4 `Đ8#@ (8b@H c,"ʍ,@@G(nm)M1*NִekInxx v c^Ogr?܎fgfϸig_6C{a˾o\-JxjD=c#x[WypōoX  O=HCgBE59P :LB0*å~c tT3\C? 0hʁo 0+xS10,=%  c`Xd@./ D#`ӄ@4//@H2 /1e2P+'V|})yc(?!3&.nA\&zW;uקՉg^ŪI*[o wo1xdǶ@ CɊI-UU"nq#a\,ɚ1_! C% `ApuԴ..r4$]KIB.LT3 (Mr9.}JrHd4O mU] v< PQD{i\>[z&yDO#PVBNCMt'젢XwOb[veٍ{P0JCB38$3QӛM0&W1PbAT 08 04h FA`]1008@*LEF^A/@Ik MH;+~'!*ϡC"ɭX ZkW{^ HtxmhMžܔLa7V*i%RfpE<8lW,m鍣Q*ͽBRJ:iFsd0Ff bX g3Fb.Xj3_2 x N̑U2[3=q}Οl{WB1XQS& 5pz`!0 i2iġ3L9`xDLhf'`C(AA Յ@L tTH`Q=R EAH1K1@]4T%nfVA O1~:(5>+(}fG7Tu3^us6.cc@x?@ᅙPF'4SqQ@A 9H4( 'kQqG$eܠ&<( RiiT\/ $t}KrWb~iCUbh޶V3rMrWke:8ޤ> q[0QCk(cF`F]Øj$Є&N Vf)H0s,&:?* L^;T# 40D03x66Gt1LA 0E0p IA43-Zt.#TWd2 ")Vs8CF7=8ղ,`W0m鍣ʪI=Anq,pnZ=\B6aΔ7sr}3O\jZ4QQL,sL {^wT)9ؿW8oW:h\"0c ;xfNѢ&=Ybߘ2b!DB0:I"a"KR}MMQsYaE\c+1> Q\0iӭ@?a3xfbh| U|Ѹ}]Z)Jj/=hND4{Er( U5ٍ ~C4t/0bpB !@a`F:* !&DE(0EWI$@AYXLu Z "ޘDVvkNuUqZDdH^FW*m鍢* %rҨ̏Md$]$"(K2B0iqa'BzPoriR+)sT!"Pe^q 1HUR!Z^6U'aęZ3g#jMEZj`3CbvzU(S&xj$pY O$Sb /a(xz#iiluyZDG!l ׭5gᙳۖJqu K2c0nˊ>TAS%g8+u >4bQ+~)jAay!pleҽ6Ϋ6I  ɞT,P%_uapu&xeF[ t4TjfEy9W:፲)M1.rؠky0B)TFK`&*| &La g@tLa-dp`FUy,N$p8 Qfpku>3I]P pf^:nkdt5oeW*m퍢ͪeͽ%#P1$S*1I0ZtIT(D40c$,GP ,j)@FlPit,V _ Ŕ:ά]̴f\E!zeHL@ЬwaUu ȮbEoa֒CwXb_F?sף9oK߹#,Vb CsI!0: 2`0O\htxq4T a`PDVVh a먽`4&XƽÐ*K%c;"fL *ݚ%$Kyk<:QɬEs&c R3z&f^? CzKg7s,].1/aO(m퍫K)ͽ\Я#Lr4`l0$$XN:J4$!Ztp"*2 hL -08nCpQY8Ɍ8p5EniAZ.$0L&CbP03/ZMDl6Z_r=BmzN/CIV3V^-زf.n= f 68C3"V ՀERg Z'16T08`…8BX"l#@1<蘰&*mo SIMOӨЭ p?7l!NĹl_Ӏ{"顕&9M3Ȥ UgE28$aK|bGUܫW"Lq%&c(/4ɀS&nmƩͭ%4ra!P&TŮjdpCf\m"Щ= 5OdU2hmK ShtHNXݫ&8H}Hq&'G 0( 8@aCI1sb3 U\nj Bd%bjRTdR$TDIR lmIMLNGRI~Ŏ &-SQ(7Y83?93;*]JMv DWN-֫]_f@ f9V%fL(!4/$ c %&" 2S  gu7,m-©卽%088d` $!+@bŮr_O]aVSJȃDtIRx͊pS:&7V 3+!N'fG#+1aZ3AAM&2|tTC)\}€'0 c1s&0C'5 Ls *@PV`dF[3A q"3լh$Ps҂BU.eḻͳ93k1*ulF"M>4^R>>.tIqzݙOOBSE7^ O{/@wK'~?)Pa:9[IHtƐG TLn !`d[Q q`# JDl)*u !7*m-) 1%Ynh-ݭ7,hWm 0'H7=u/ۯE~( RaK=ȹ{/]E6;>❔rupu~=ڮ` x`J61{٭S 0` q҇xLpPр ʡń1A8 4, ,*#0$ bA>$n| XioĜ63-y(%6JyhRΐ^_P37SklJm/;%M׬Bv)|u)3ԛ,ݥ~/1`eb h1Ú H.;00qPTc =ɇCFPC n0"$8X3^aRU:(]:z:+ 0p5(m鍫 P[*FdBe-D.R{Tq/Ѯ}~ 8y8% b%29~};*P(c6֢ڷC.Q!}!ū5/:Y_1vͱQ*Ҹ\`PL4{Р>2#?5qa`3 #? b 3P@/3qQh:$hXPR+QقUGznURw((l)c=(Q]U&m& ]Hsbv0+ejEa]Jj+use{.&j4}H+&Vpq<<٣i ӭŵy3y|gq<یi5=,$# 3$ɡϐLT(0)IX푤iLL(ƋFf` l,Lh4j Ƞ k%y0` I(C>B̌IZP-,@ p# 4nWѧhllW6ƿ%{6meQܟHδ,5!Q52FY$b %qa_'qeV?"YJϙeW֣]ͼnL mҴV3q#0|(M_2P`,D@5tؗ<" hA(FK@aS( fc͐Bg ,! q[Ȳɜ1.!H#(] eZ tE!}'oUv_4R=f^5Z3hT.w2r4汗UͤqL4OThR0@55NS2L6rt R*qyQNmͽ1L\Ox p <Ɉ lDLC4Ёw ("E@&Q1 0tJ- 媭& H ` A003-E)\2f %mwkVcN$:RL$,ܟRvk5j7^ے1QlYY[4:?\Z1ic1P<:dSɡ z4 .P9$HPH'lM1V67)Xt0dc)p煇. =.Be^&d*Cx6Ӑ^9غH-Y*p_Yl;p# i8-U1;|s`45L$Aےg7j0XƖZiïf %܀WNm*ͽqjpX8ݤ{]]49Lgb`P0>:4(%17sb.dF88vBM!JJBD!PQ!O< YB{aTLJQrْ0/(N?4+]cxZeg&sGv M籪R2/K.hḾ~iL$uS;yՙ< .)Pm'y$,DhDDH* ^T!0C\Tf`$}%5c bdI7'CyAMT=!lWy8 ONd gُ=֌o[jz7_yibPP6{_;mS&m퍪ۦͽ18ėq0  |L04+LaDc%IԀXV "3*0AHtEe0Nj;vzvQK,^aq|~lPؿE| MAky *6swo,eRwur0 B )+wh:S&ENjL.a0&$%8-<*Bpq& [>3*1p&x1a @7ȈM.ZB$Ѵ,J^5XhƘ|faib4$+c"KSzutMLKyh-vɉC㰤ƫiHFPs'lx}ϝ{8T цPFU#lMS*m卪ͽ7 y]NB} @ dB5bѐ#Jn2%cYZ I4;jO r&JdzcCN7sZKY~ߢ{t&L.B>Uq=R%^y %B!B8xKPL)pfk} H]fzyUk ؔ, uoPpm%ZBl[s,208=*! t" 6C1ѓ) j? 0CLl(EE [Sb62PƠ A l.^4DeӏHܭT:٘SYy'3P'_f!GCP+ye&2lOtH5@]` b]< HR30Ibd \iQEfL1 ZA"Dhs zO057(m鍫䍽pX ؈";+ơ QH4b6*[39ߌc[e&Pd? g!>ŢjĹT֋ݳO" w%IJCvS C#Їrb^z^eC C5@!YQ8"&#mT 1P 8YUxS|8 lӎN%# fŅ@&݈~BB@ Gl7a"荳jꎪ)9㊍֔/=T tmx1 ʓho,ۦg]`TEGŵ ;&.Qs(É7`i6aP A@QF\bL!D4#qs"y(D(X:'M7$m鍪&䍽1 &%2% \2 ul9:y-JaG߫;<ݨy*5-/j&lo].6ZziLݟKX.SGHBeӧzLdLfaAtEWHBphl;2 pXс@d!c$#da0cQ XKooo,˚}VH ØBd ̸LnP1DOv ^n_)-'פ(o2qԞl KcYq^Tw[&qv]`P#\̊|ADLH'pб$@N 8"v=ÖFR\ž -MPgu¡=T"AokBDWUrLe7$m鍫 'M1$y p!{Q-d>tqr{͎.ѻxawsqWvNg}Y)a:=0^p$u,"ƒp!#SS (G2#!i )d:Ll a0PrT%HJh88%s)Бm4X%'r#.3Sn(Q=5柭^g|̿G( /H;yηROXf۰`TL7\E $l9T0ia,e2RQD !  4" gGI%CPLDBcoKᦖnQ@݈X@<a7$m鍪*dͽ!!켾Pɥo>W)R j_Hh7D, kQ鋐+"!'Pl@E%5,"CCf9^! 8yT@.x 1I P3Hk1!DG!@j2ʤ C"&8S yF^XK.`8nO9*VЫ~P]l<ܻ G+{{ih[nѩq G(Hq~2nl3\`D^s}Of\fa`En 䀃P9T<ō P۰3b8@d⑁1I&jA-2"GBh,"_~%KR;hI<"&2_)7&m鍢誤ͽ1`OG|aaү?l 5WG >^H$um"DU\*"?6riP$H2p*TF yHnD 0eCt+1c8q #$&:@eJ7A;,}o@-$pef?ƱNw_ Y՗*۝i\Ӹ,~= a?[<~ s;}n7JYvܕbn:yPba3ւ 3!BFu{AR"aEaG^rBB@2 LEG Ɔ,#1C5)*` &A"|텤4ˣP 8X} ]j7$m鍫F$d ͽ*@ٶԺ}`&lnT\v1Z9;hF_کtf:Q:G\uȔ7v]W`P&J7(1$ɤ0)E3GC0`Z*aFlaÈV:P#h A2s-&2ʄP4M=(KcqDV2iq_W v}AuJ"U]$2U°flSZ_e4YfERQcV{Msj^WlH7ó'L<0)@ʇ1㨊p& =7 ǪA&#. 1H&:13CAS"!4F `a@"NHA7&m퍫H*d ͽ(pU:I2Δ@):X po,*`ד ref։MkyK)oڤɻ0woTi`9C H/%?uS:U^qt ƒ 0v݂ˢleLSϓh1T4e<KA.5Ti# 0lCcC!L9L̰ph(m MJR0Qh!*)1 8 Le! H@A} D #k=--^X]uYf+nԦ٨̲r,1KG![;V(jHqJuIn$yHpݽvcMR9'%-ջwS};w )yY+:-F?ۯONqP)a^am8Qc8u"7f FN% ȊBPiVK‚JG N _GEQ8ѤHF B[6+KlI"xc . #T# [Q}FhRC?LETkV6-CKO2eĵ4^ˋPQ7`'T'֐#Q aéAb2F$OGS񀑅L$$ PX*r0QS881r4A (rBÆ F>S9\%auV,i1T5,Ĕit39|h pcZijl*6a_fIZ$"Iw5&yWH2w~9]5EjkrխZő f' 1—> vm&+ n""i + +sc4@@!F&Z(pmnJ.feF39t7.?2_7R3 7bPVOT4OT;AX $gYUX l**ln$v9hOŀ5 m$dU`ÃNLOŒLa*`\Tg(7sJ L0Obe H]0B0 0hX8גZL)[El4NToyXMs;s9@Wcfm,oҶ lnmM?=c6U %r_WsZ$վmLn; 7z1s.12 sc2(D%0s20SX7`4PqÎ@Ԛ`V` I (TBpPzF C%did?)䇫8&CHIloH]RI߉[ W S{]iJc׶a-$/WRE8;m'034T̜HB -aq R-0`b)A6l80B( p&|( @-vu9WcKY&7lо IoVt;fsJ&=ˌ9#AU2sI3ܻ]A.T),Ί˦RT4U1) S1rbSs9W`ܙ\KL DX9#"m鍣>#=tTbXXDFcM- )*8`Xb+ %Pf\&@sZy~+R-%O1i!z$uRt8)l c44i9Fd@ fa4 6 8 !D4!#NL |Uţ\ !3.ceZk-ok{bF=&ߦFXW>!vz*`LѮi6iā z` 3&a81y$0V&$) 6tɌxfgDTU%=Oӆ *bu.HB&!ii]/*Re}ZɕJFb]lK5s.kɎ%Y_n v+|i8|x٠+6t$']9Fgt 8\49Agq]`e"FB <"10% P I0ҘꊜA0pì'>M#nmB#ͽ@4*-_q ,3HH!J卂aNZ ĪPF=e"m`nLk*=q)r(7QQmPݴvΞn(Ty,u2eFC yDtBh4$F9L1! E:dQLf,a`c 8dIn3vT]i\Jj: aBe|@K̸^èMEʮD;Zs7k; `Ê;Qdo9C:2sJ\1Y$D#04NDH|bWmm \viRgWIF'<>,02„E oH`/FX}f`X`=m xli!aaa- qҪ9< TjZ;z)Q%0c|21B<,؏`72pHJX4,K DTr!V@pp^H*K 5Q*OwIu+ Tί ygk#K<=:d{?kΝBj32VY䐦cmGֺ ,鵰' -zĎ D PcR.#Nq$$unj: 1(l.|5f NeV6(q1cH JhRcA܈4 b6`<  1!TF⒂ +YUHI ?[,ho IngJ4cU LqA5.0VMt٦y`kQ$J&elx;Qڪ81'x2.}kUu= +=} :(20D#3Ip6A\"4; 1Ys6BU(V(L20H#3 R4t1 ) "dʡc=L!! fH4Tj霃*\8 Hd4^#:W4k^2FOv:akL"tPu6gC75(I՜Ò5nm$ba-ܫ"%Kw*:ohqT4gqP,<ygEXjfAa Ȩ̖8H£^TA%37 $LD BF>:0  MV@m ת=@ LqPGar攩ȔbF}̎ɁPfN/@ xXм1^k^eD. g(?sZ!Kː)J^,kq5٫ݵjZAqBa<:CE 0£b)[+;GF'ApBF ]e8*G83>qyb1dy,:ػuF{PU ^&LJk[b'V}RUno‡c̥ho!#"m퍪$dM1gvRXZklEG؏5&$]!U@G. g410_P?1`(Rb(gNf4UE2d,CcH"50Q`b.` 1 S`X[I1SUvl$g.ɲIT2&\.Yjh6)nׯ9&ډtv9|IaaP=L-;JBC2 DG` ֘!ZXQրdABhFb9LÊ%f$y3X /3ّ&̂ƪ48kʂJvDeâG cHG]5kw՝:tyt\7Z;fZ=!ꌟ6W%cQGQ]!nm몝d 1d74 M&4c3 0=zTdžF܀/t  60z},pҐ83 ATç %=a[TqQ(6^6q{c31Ak$/U>o6txCe 5iU:.dk f̒k&\aDm4QR@'6Q!Xi 1iF+ `EN&#! Gf&,7b E!lWZ\DQOmby5j^}mfg-YVY9լi=5gR  N+gI^q &TNQ2tC+&4T鋍ƬB>pjdƀem뢷!1pTbHds%u|h U G7Ns O;jC>}}Y4(-X}1=ųHkbo)AGE7*W(((TVƅؠb a?aBFu d21qs] .vd!HZ3Gn -=\%DeT֯IGC1("qḴ[ՖZYA t{,˛ 0 ( a#,aC pCek*:fO;C=G a󒗕.˸`GQ !@{ۜ;z܇ԩc3v^}=[< sakgWxWeZyYkgg7c#DV.RѦG9غZaX9ds F0&<: ^-NPRA1FHK!u02"câ(ۛT+|̎~Ik\h~lHo/9bҜ܄=m2[UvZMD{ޮwslצʶjg>avJ{ RRMSXژݛhH$i 5h7UWB}#b*( ad$@M+mṙ9=pPD Y-sXao 2T%c acai%ݾEe (@<(y 4(e֏ a|_1Y@qUdv#%@?\~nw[_ݜwv{;Sx_yX\* LNi0#puł 2pbod4܇/cR@E $P FL؀&Ƅdk'9Z~2HumZo("nd4}#?cg)'\S|15w'k8yN[wxޜzVD2Č>kSBnk ? =3:ɓ̌1.6@rDD"]1GKnNPI)`QI<9\S8p,I0D=g$:#=Z/Y'IS4'~#MB M^!h]!5Ylʚw,[+m׷4g=,{Սk7Xp?}v))kibb S^u9]w *aSBm*M=ӺPe\*3<4GAV) 6G3 MRPXv f8p4t820-|00ft5dkR_3{IvQ=fqjbgiv-'2 F${侀5fcgVkT[buohHe܎H:~݌dS.1vmb/m4XF2DcCLB10Ѥd DY\ pYQti9PDHD`nI&fAF[&FyRBJU *JګtTveN,rF\9MXd r\,o0lQrí2MKGl|J'bVr*ד&9/.VOabYBni%'=Cԛ;h5Q @ivlIJm%D g xdCj'HtY0( g4MU;.A @DCG9K;bTVo;K%3WR=RiQw]#[&)Rn_S>ni*=D8L3P"@Se "b@I,ƀt*"Ɛ6cN)\1 ɂbpZ ũ WL0ضlU:,/,OQ4 -ICPi舭N7Z_L 0x[ǙB6A>"Moh+z|b䋊7P2#5 420 TC!T$9ڟ<\ AvJ"SeQ0N 4J66En@Ty0PnxL!8jeZF%I&3l&TMu28^ru7W,5X^Ĥor\+Ln]mPC_WWzض;~9j}ik/>c= tp0,5sGfi,X@-3ФӧA>:&hq,["#8$Y!=c59@*{\YCgQv?ne^hpr̊xr&PG4\?-%?ü.nJ/M~fkbbKӾ5>[^O:niM=6భ 1SsL44E2&+HnY@&0@%b 0U4h[Z`gdplY3A@3$XФT&'HԵnlg֫(zHfIj%2Yv:7dVw{2Cvraڦ|jޜ|,|Ӓ$^? 1Y_R@ 7AlvP@>Rˁ2$S5|d`" I@1y}>)|@I D28/̔zUO1Ҟ E Nz*',V/вCKefu&G{o+]öψ^ܗ-aw{eSq\aS:ni*M=r*w#¬%!G0f(86)lSɖbg!&5,@̨xcJDsC$DDi .YkF+-)sԥ#U*hTQ%1"z5AB!YiɹjϪ.q|v(]|nGk.#TJ[կ X!V`T T< 19'6@#e-DXh+Ei acAPG b$t!-"K-"ޤO<o:xaP預@G'$i 6M.J:[|eԷM{IL$c9ݟu}m:w^s7 ߮M~^4^U8nm ͽ}en{RH3RT7`NL60PX,0*qy@A019XjnB4l8‡Gh!ki"LuboZP֝ڪavfupq%qEӉN8tм0VƝ%L3<A Im=Hl?aԕf[vIJ9f3A{HUƉBϔޖ'-?Ƌ mӼ6"u,ۦNoKG֜nw2O2/ 0/TUnXu:hey 0bƬ)1;o}I?[}y$]dl-wrE4]}^U6nm)=lԀ3CQ&cPpfLa  BsB P،nC8 &>HY+2HT\fU'$DWx*L)uFfH)TR²yK]FwtV-^|oq|u٦Z7mop*(iһoX~2fLdF^u@jpy1f# (HD$`Lтq!B*0`ƅ‚Rq0uʢ0^;1}_uq4cBUTB$&k%w{nm$ޙ^XO0]g' 6s]=w:Zkw}Du"ceQ6nm+&ͽ(jnےy2"Ӹx|׬^fҵ"BDliB,Bn -2.iԬn `4G@BS;]#څe0E-sDRqs0V@GQkq%KNڳ&L)Zn5I k`F-gW8ni=\f B#.' :ъ!4 6b ,Dhʰ!4 T|/ ,,؛NYSH.WlKx6uH7PZ2&bu[lk ,>Zhaf*j]mco\n(?̞i 鄃?{m;$_5$B8G@!lrs@^b#tPY` 4p@C "$v 0>=VNm&ўL:"4 ] _vG]3dL/qx.T:Xڒo|g~%e~ԞeRm$H@OI~fїƦ0 ~Rr-Y2nm+&=?3pc\GLG=N aR .d2D!`Fk4Aad&pV0 '6R9ecgk5 (F^V ;ѧ=s[7pM1ə m3Xӽ|Fӕq4 N=3˨C_>?zp2p &^0k3jh+!@7)BEJ81` ^BqR@(Yetvc?#JI{R ftlw׭2՜{vsߏa]%7RV-Uk֜|9kQ6IHG͙eA'/cQY";tQ2niMͽ圝i(0* $PT1e B3hL +)grKE(ۂ3Ɵ?21WsmOT1c].9鸹QnTxRy>[u/˾uKμ-wzSv6h?i 0 !hQ0GfA0BӍ CKҜDP0`̸lĆFGGAUL,x aHeVWG;@# &\G{3Z;S3 \S;{7SԳ)/Y4J븽A v`<:z5]@ ( #L~=#D/ VA1ǃpx6vS0nm*= tSkF[ VTKkPX5җ *AB۔gCemN&ٯQjrMv".Mlmjguv&XGfTp@ܵW9LǺV<7uywFg(Ssģ?jà SL }qpbm>uAqD,ҎLU*7:]uǑ牷 S{ͫ+[H.Ae7y%MeJv%}x20O* g: l;5őxU,n7ͽʦiA8n"'~t , ca0PƇg 0(Faa vGHHzC6E@jL/{wh⺄,;yԞ.25ӿzD_9-.aͷMjd}*w*ӭ̈́ C ޟڀUSS1A @19 d4"ۧLhGl$28A P0ViL"j C+ my}j濚僦>̭:.˄둫eV['bUz?+i|~݉~_.ܼѪ]yónIٽ,{.(zhm}گA;Ug8`ђ'| 2!2kS2ni)=D#0 ꉘѱ^;EVCɑ`TȔ H I~"BҊIa)׍2?ʷs!&)}Ƕ^8eo6Sw&gq×.u.|o1wjO  i5jb( X fpL" L!TeꌡՠE dz1RQb!A@VB@!d#q]aC\\cd[`iHXTκ)>vf U~q$wFjU&[b{{Lym~H8t b= -?2SۄJ]7;.@pg1e!єF8fp1(}uiU.n ͽ` U}5ATYfŁ ^JI@ MaH Bh\jjI҉Mu8R- 5Q] ]`*%ki]zb_;.&Κnr/:]mʰ.617]őƒJăfn8 /$iEɋ}Sf{6R͔U0ZаX ХH.(2 Jǭda@f }M4iH@&!"DI+dǵܑW:CJi:Jϔ*,{e|q_tWnթׅƏ5bw-7M Sj{OƠ0\5>50ƓL>` ǂtW0ni*ͽ 9"`Q zU. ,„I'џ0(s'uk%2paUvV,hWixKzSn}; 7k~"Ѫk#S[F}] U;y>~-I"B3C'OjD)@c9B૨ y;e${!Qؘ1BJI$$`I#6KC2ˤ%@9Yr8mB{0vf  SGJx]yU:j\ꡛ-dx02Tf fTB`/bI qUA$" PʂLFsG 1XfKUS0*WKvĪEf>F xEO2nim*%ͽ,(%aa 2UNw`,LQaU]tb.L%'^EZ p|cE؋XmFErʡôIK+r7fI֗u7u/Mj٭][as]z4?ME6` =Zs!L(1h[N01"5:[ @8| @F@!rY::EyZ3]6e=I,Pw 9-$[gڕ!9.Il2HEV.j~,M+pՓ_`BVwmy|*:nѯpݩ=xld3sdA@`هL0 vLOyh[(hpi$`{2 lbW0nmުMͱ ik(X.ZMqJ8,j*14pdsU-=@1@b@&PE  S%j$vOф#27 oU;:_l e;~5NI;*C]Uʗ991y~*Jxe=MԞ4+羭{M}= cqd0|lepriqcfzpkKBqq2(1X W*u݀%3; |;L W2I$0"C)͠J1t粰)B.aY3.(4iS!`DecJH`${ J@Aek,}(+@4Ut29~ز62Y6̝@kLY͉ lk/3˛QM<,H{?}eBK|[6??wCLWo!SdK'6PI"1T9za0FB)Ń1HQ`lq_Y\r10г6.>w" UZ` (P(VӵW9q[@Y*DLP-08@xX|1K/6rnZn^>̹sʛuj?.s5[Ư,beE@AM5(e$)-͆KTp5Vgt 44~ p+993T"IC*i~b`8p+I֍#%B8Ii hgK ))ܯVsmWSe񭼼o[ƺN#_Mh`%X_mԺe{+.)6 %[ĀrQP0I ƌk[(-q>S\d^fWޞ!˸紛WZbjɝ5iWLY.vt=Z6r4IH2=SaL=m*k]TljB|4Şnuk>4֪ͫ*Oio9 #\fS2 3@7 ίH8 h el cqZyBx`ZLȭLk>w +`$ cq! :f &Ʊ 8N޷8>`ׯI{.4"UV¶s]c% dN0-^3P4Od%2D W*44v ʭ&N$p6CQ Gɓ}ӵ6\ @1O" 6T#9Y>.֡e \:EZ[L+rsOPǑaQ+ʹ(f*z9+ܻfHNa>]iSJm卪jݜ=5Ʉ"c-ma)"eHMrހ]X_fUZm k@wsT+\%@S'S+8VeL!zAjU*96٫blyPg[E n7m4Z~?uk+[inrnY60Lwu y0Pi2ipcR!CKL,44iJ<9-3>!Pa%*vhac"< F"A Gq6?u>ʖDK;LNF4LUNVj-Bu Q֋H:mNԟ1}e}3Ke0yAX'.Rݷr:ԾX|,/Fʢ]1]MKx* +)5yp`.Lpe"tBwPG"zEUBne*荼Y %M .f "I{/. )]Tbު\LdTa("zbϔ˝F\8ٞR*M3<ϯiXU`OY$~}U8Mo/5=?H’\rԆWfnj 3q*)E 4"oMF^^2hLZ]k;H1Y$x#iwujyu#`S0%1g>#DRobA )p[)$酐C ͈+ xYZ.QFL,1K[+GT|J~sxCvB[1#zӨ:?SDm쪧ͽ=t![VOuglV}]Y\su|N:{4Zm.o]ĪP1{ĒUpΐ c3|XcU2g1Y 1` ߃  Jb =%FҀFl0!esY2‹K,ઑ*eOkB;tc0Q3 cazĈ "lM ԵdbĦ-kMx1; -^Si8nf .~\o<_ѹ1n4Ch#@)ž6|u2x2p` 0P`Д dCœH؏5[ێ3BDa: ru : @Xҫ +v. 8s52g!1ڐ\sG#E\!,81O:nmM=inQ8JMiuJ6/W0)f=/z+fyZ=訛T{ջR7##FpJ*`>b*axT%R,z  ` bf[pc)Y/JVRN.J S/2%ۖ)b~Vf[ 72Tu[ý.xNM[˿ټӭ1T.uv VQwXG:/ ș$%YQ#$&& V!’)%Nl^B4XA&5ZV"H;-6緦n[㠇[kvBNʒ/ÞW.Żk=X>7l#Dqn8on[K=O6n*ͼ^ Xo0Dc>=) &i!chộ~ b$$YPW%qsV"ȇv6g[) @ĒSM 2ղ\}WS}ז&ڳR}+ԋ=9'o9tf FF-0̄f ZHp!xߌMDD&cATK"D( b!`|uӜwq/ Zgu"mZ˙VQl`&:0yMu;;">󿏍a.aa|7k.g'YS:ni2ͽea 5ox<13:bL}\o\,D-fSM谣OOn~Z:zy}s}:ijuA5V7sJ STeqܱ7Ǵՠ x,rxG^` J?aX;) y٣H㠰!80N>1H`p#kUWD $^dMJ(y26\28i|зc(K2MHz!k#=\gσi3jooG?.ό|63DW4n2)Mݽ|v |@Z|o&p<9V8 ^jAi!fGvbHk⁚ *Rc`sWM6axmiq*/~LFH @M1rVԩ%Ӻ(kvL_QR}x.Hc ųQC f~EOZ O5>3'ƥyk|Aߦ>dJ]]͕TvYo}i)iv|hXs>hơ\P0&8Ĝa B J$AȒű5]C). K/0&畐 T2\Jj߬EdzlGΤ9dmwծas7s-cXoֳcu]uS~&%O6ni =w>$wuК5gKgweͦ Lc xTN^KL\ X&$̻! I [1`oie0p`p؀r3$gxY,_lUcM\`Xvn+AmXP5+A 9 HC-IO2oG45ӣrW8q5y&W !MojnTAPZjʽQWsjԫPk L> &L\_3a2D[b..P2vQ/ 4$dg̘ !% ^:ڎdaAoB~T("&T"Rew*۽uҺƨW0nf=9erW\=ey=gj+Tm}{i%i4ELUS3ɨ96"tFǃ:?Ɓ2@)Ya`D$ňL %aE M1s7A&ȐHf#!hL*5~b54X@J 1r#62bT:`'.)~D%uFe(FDLRX]sh(KϹLj%y[Y/8}ɪEr8$,5 JoOO j2w&``yņ[wpeCXʀ@3;ɹkHtƶ*Dn^B[w 07$=p[y4MqG.(7{TFUb# !TL[u(ܸLF;.N-=1+-Xiܳjr#9/UCRMAF_jbƆmeLdˀ!pGxCHZu7s$X(.AGŐZv:!b'cOnhյ%S̸m3s# HxL `Ƒ@ŀxCذ!PaITXR*c$0X4HRe@K&(/~sFdKb'Y}$QӠV0, cB$ j'q]B5_@L))d)l'$#Bp0aĆci&@Eo_0u\ݖ8)Y$@gml/j@>]&h='#>L&F /VJ ڶm,GE<@BBf6 ($(. mh8}aAp~Ã", =QI<3r& jTKXlk tfԃoϷ|<Ӧs|}]MynٴpOMoBVU\df6d B&07@S! 3TY5E QG&;j ÅU!+5PpMe orlܟVO,n* 1:pWiLSMn//JAgw|faGᬺ`/go$]:.ȅR~GUNߛxV^Cjk2 &10_&R.0nX5 8 o(x]1@Ď"0 U~\w]_ದr/bӔ7=^ms;5je'Wyf4yfm+[Vkw#߹'V3ܗ=U?}-P[3wƇڳowV*_U V8 3OX1,;P:7c"S4_lLbbf<aE !`Z SYAI@FD瀆ZAxŸ !C&coLk.&#)b,4X~64WvY3 ϵ4ݟ2g_t?'wwjߗgrr5Ŋ4^Mekm{}vD hrVv%s>3!#>2A0!5@Cיg( c!2D0d>c02a3Wdf.!辎U.nmp*eM=Z+  O X `2#BB̶U/Ke lJa'ZrL uwѠcojy +@sg,[Ď'z qlU2ni۪M1٠{ P6]3X (!4 YTZ\DryOW&%r[#é-IjVB]v3Ӭ)ãqayQAD+akb)LY4@ /!0b & L00xÀ[SP!!) Th][u*hˢNmtܓX#&ъ 3a.Nꂤт /2fkyl7{Y\obY44Kiy\)Xx~4h|gZڟDt`sqƄeCFY%46f*6؈9  \`"1 1S(rۉ U*n:*ͽ|=&aC #l \h5@D\G;Tօȡ5Pa9XFL>؝vޮV;$y;Rgn8n|a*C&ԟ ؅j9ϙ} eNf=9;Fsƣ&t+f77! uL*bfF6a"!vL08*2a,@*b `Tx%4iY.iPȔXhydmk ;Q26Q2<=VprZ֨vwŤ{t67uol7;S3Z{hnD<:OrԎL$ Q^Ԁ ` 3|ϯ2"ј f2  +-JC$]EW*n =7xǼpEH؀Vm $x6aSx AcA(K$pH X <-`p*3)ʁ'uZ~H5ߧ,?76]cm׫aӴ/MWwpvkB3]?g4|̤ 4LFcoߝcD *[d)!Tb9Th#T`b KQxK"ΠY2 4F\mTۼ78I ҨJsg|SZziyV O  Oow]H=tM-ɫxlu][FLHAMedʇ@JJynVW~kVوfŒisi UIv˛ݯ{X| ڂ˷B)zϕ:g&;sӷ1ݩoֱnX L?̷72 D%葶%1,IB #`ዉ bP]1h1h Υ0508 J+@ep4T`$b Qj`, ` b$@0XpD4l s@ ! 'ɂ@̅n,3I<@HiA"E$CEMC"(  dZo'Y%Iv&(9ڀgK9>!A@ U.\aR@8Ő9@sAŐA?epؘ'9Lp pB $,hc&^2kҦy4`FGDP8&0b6ucy QFqyaH )5L" L)lKQY,#Fh+ZXsn5G5{˲dK0))ZW1 |p.6yw0ַ*mAT~Ҡ2d&rZvbs qph*#3mNKY\_C.~0nNgyu&):nG|y? (}We]2݌1udzet->smC}y5[ڒ^a__,|>k@{ٽܳwgZf~_ctXZ7JPTאF8y4/'1J!1!a!{sqZe}EY4]Xf3'SҢ{x. cevMŸCɪv=_y?K ]|"(.@p jXeTT]TË,+1gi0"4PsbSJU4KB6!lPqXvfOR{Hvo *mD2)jpO;HCޱLېU&ΠZ*b̞F]WRl፲*͌=2$"{waYV-*0NELPִ dFВ Y̢ _d @|(Sr+dZCǔ+*sE!QhvxN2-)mS'珽xvދ$T0^7-K,^k 2f]yG+ RG,WGvV*SvPR 5ʕ s:ݯ$3^dT p!TEUPEҀBC|RqN&+(v6ru)xLWDm卢*鍬1O,bUrHE HkJNrO3|Ԛٙ͝UTv"2=ŶLA m9\:th+qv-鉑N 8I2 '5KJɐuF|Ӕp"pD$0V/=ΉdK>JВh"ɉz6 w};HŐ,PBfW 2~.1# =s6F\F3:<%lvt'd Wvd )I41H#WyPj&^bF%f< A' BC 6mSE8X[_Y2x; i!Tc[P5\BCWBmM,XԬ Eޥrڈ~~~eֳhn&k}VǝtNiS龭.RJ`ib*4`Ȯ% GBSBT pdȩ}NI5^H1`x6M,k'5A7|I ?]@-Gv2=x TޝQ_Jҏ{+СRt'Q5Maܾ(gHy Mr dЮhtaCl8Nb29(>sÔ#4" $"4I!fœ7mR44o;D|ی1zy.b̂xlRi{)rECLf5ger}o+uWCUWJme* p`C2;g3pcHV`ٛKF(IDdr2) O1*L!ifQ L h$P:qB5tj,[cD5A%B攦0#U@&OK$4I -"R`^SHztk"UڇS)Hf =/m͎_?]lv>@̛wKk`04#'N^r2vӜ@,A u9 1a"'`>': X1sCFᾲ(I`  "٘tTfoHȅ[`y(1CЅgE(T BhZDqD}˚XTx"9L9xK~D+Pz V}WkwWX+VS$4);))k]Bhx <(hކrF3Sj:)00BqI ;9P2CF( vX{ lqe_74 3&;,L'C0 沕2'`lYT䤲 IyuާSfVjZz֛wm? ͽ?Cm=_ 5>KSnhSs'zK:<쓸ApЛ#KVا}u!DsBb Nm $*k,؃Ná2FE*`2PS1G2hPR錕}ėHl5k5$w-ŷНmGehHۖ0:5ej` R[MR\EU w7w:]k?oa.Eږy#jԪ?R@.\ɋauɉ1QJH% 1bcĐNYq4vLQ.aL‐4\$]pTsf0fvfNrP9sO *i彤 Y4no *hͭ12G#U'AIS܌ڗTl}y̶C&gš!AubQKHMjaSFZa^kt\z ]3$P0&̢Y9>,XdHf20yM(|8f#.(y 0PFPiba;bp|/ڢ+|! )G7T"ShNݝR9MnNUpܖVwq'7&/y;%/5MvIw4/HKF5d&h p 6\ᙴHcP>nՇQ!X"fK  a((iiRZ 0d$ )kA.C4D8"c|߅3۲9f1x0a[͜7lG6]HPU6Ld.0J/aBF4E\*I &@RW ~1-,3n/XLzW}]fObНɏuT cq7K괺Uf6)*EWDmaΪ 1~K$DH¢f v 106BBLh.c݅,$6p(@B^Ն)Ӳ5zn3TJԫ|#1V[v׏1F}̐꛺7>ǔ?պ1~;z#g1 1!o%s|AxUI#$+K[(t׽F `B9Bf/4gqAƊC  “ Fh<QP 4RbE0bnӕ(Dܞ3UicO߻|Y{wUW֤2Q+C^]jKcIXuwpQ8aU-yUž:"%Gq:2u1f!;ÀWBm*M=Siٛygf0y(0`9JJ M$xd$QFX hUB(#P6gNT)wex;xUSV.Ph!S'Hs'>캻̆G^w>[](gelO|nK]V)xRNڞNW=COs*q V085D! G&xrb1cep` a"4'`)I2"Pe䡩fB<O#] u^TXB$R !B(x*Nvd:*XF1,f| AryM󦗩u) vd2H,frVfPMs(W,n g 5fr̈& LNk;. H] t26C9 LT Nb\WIQK!45exYdggN=X#ﻪX sFCߕ%;=k۬G_̓m:rX }jvsA%aσku](E1(OnI&blv> @ X!V 0B#"XǂPP<* FA|i`!` <$ Z-*G^+R͇Hi@I jB ~1d`]QIuJe2F,ZU[ؘɀiW,ng%=+>%1i-_g,<s{s;tS`Fb& %81(!.&xX& %VY;ncJsȘHpnjIX+Tn,BIxMNBAEX-) {f3kлP)A~Yn!/Pjɻ},=]FV;;,B]z3Kjn̈<#*,FrNJeda)tb8aɆLGG\P(`bYF!2<`p h10=(.0 YABR#t~o !.yxm,XQi@H+Y¥*]n>t }6X!W@m፳) =lZΥԏLyi5jZ eucD}MIћ7]l2 =ܽ}Sʃ A4X  1 kaaw/bechvX.mܩ@s4zۅ%jK&YJ95Xh`{ߴm^MfHäs{7xpe]HQaJϥ,]xxinP8%!s3@1p"a#L6 8XF[4*2c$#gۤe@ԅHn4xDp0 "LokYC܀=W4mm*ͭ=JUhxzV*7ldqFLdh)L:ID9޵~>ԁ\0[,ݻ-Yj߯ 0&0 ,"Sk6+0LɡS7Жa I0@Խ/YĂ0B "@2C.#&/V5Gsr;wmڡ j;G5mKH8Kllso:eԿVFϦoccvםMǟ۳۶5bEZy~ZA s%$L$mFdfeF0?W` (P!Ua@2rKVat )n?1:[B { 6cOaW2nif=F3{fPCee5VQ+b.fiw'f[׃ >!#ڟMt <(ij~d2P`419X$& .K`Lv '4TH0;b0RB X"Ja#`áRPq^(I$PfH%ѨCs>q.MŁ[B~zUHX ;}(,|PJ1)&bK˛b,ϋ|uFLXښYy0K(xbA#0)DI$0}j`Y\fxB kt &"J<5GInF܀pp%[J7+&bƦb7innW4mB*ݽs(L\lZvkCt^.ugVΙ[:7\/cr:ޣŞ%/}&E$'`ݏ5%5yw/=@uL $7eL LJ" S AE e y؅ HL0*j3D&k F 0AaT.L2 DFοjE =q l+,?oq/ip?͋.K ڭ Pwl7(Ls52˓M ٤bjb ɖ*" 7bڱϒeRzcΫ`sB0xK BdLnJ LQ`ӌd@$|<@h#:&&U2aeA$;G ՞56{˘"u@55Qdnײ90)\I9׳ͶUZ]ޥen]foώ׉32V[T-.j>aζ_6u&'ssQ< ;c̾ MK0ƉSPJfADdfpa8bc(b![&s`S٘3 Y&no *fM=F/xe( 1\3L7x-F N6ØBx@q/h 'ʀ iP`BiD(뺾щnd$fInJq}YQmߔ/v ljܳX[R{weWYޙk o%1Yi&]$Ytp|xdۑEY_0`TS\e@A!B `bPA *V T1&ԅ20a)`j X 5 `"58mc<,BdNXRYfX(u t , \O3YjRQUȱDm{{fZ M"-W"U#B9@8`\D.OsCwffRL:u2`6 X+0@KΆ?t`r'HQz@F8k@FXae"d&nhm1D#"!<4"u f04we9l-cwuֻ+RGxASbPʼnt:K+XQO=V1úqݞ6rǘճ7/!u#l#;K MD4;NSޗLn54ƆqA3D[44;4VI:M `y VP LD,&DRF/9XwJy'Ȳ >Ỳ *c6T2U@<ނ DEdz>A.tO^ .ųon z[cwS w\ܢy?SDۜ5Sa;{!9B*Z@ &Ze7 3kU4&312S&+0M " VB(!4 s괠R`D*"P:hHjDvévJ3h. bLԉ?s봋&O]˔>Z}Z]v^Ն/w^Gc8f}_vN)zjA& @m@ua/2,j2mh\D R(Y'l+AgM㦊QUBmiM VišZx'$vྌd- q˓k3Fmyz>|v\oq:Mxrk7ϧL=/_Lj%`P¬ 5C??nC#1$0AgL-m$]S/`%)#9P ݁˟b]pJ2ʡ sXK*!{F7ήj,¹X<zP<@η_X5iSr,(Ts]p.ˌfTl.aw-r4 #kD鞐Oi) -Ę`q0L9UJdg&POBcB'5)/)FQVBwZ$)RqV9SFmg)ͽaK4̾%•BQlDx ]t ׊յakX}<o hˎ4ǝVL멟=]|Pa*} ذ \M~кGGD 0N@jpϙ18 DpedB p ug/u؍D A}$[`ɡdD,g*:FCUL|PF3NB<`¹A$˧uMUԍIXf}\sZßaXI~_uWscv짬w,yn/N)Fd$l.@2- c~ Eı* 8AD8&\JTԓzL21 02UB0:Kf RAOю=SBm*M= ޫ.Ǖ6Yp²MзTz .4V5u\o]cщa, g,d,gR)Y #dLnys'g.0bWb3VlRkp]frWq8UOF2] ]_3 d銟"S,@ Rih &qЊt"/504E#L6 2D4ꐀU>ni) =LcVI[[L83#[)cd)ϙj9_D"h)d_u'p gvEbɘsbkܮSC~HXVw:mٟZVh᭟Ff&̞bb1PT$ +Ƒ)a"@9HFq'FFDJa@a`-KD! \O[U9,%t aI-czh6lgsl0;nao_^fX):aXfEp]#cNKڡOw -{jڽ@t57h$ȃ_Mt=&}!"bɆLavc#G i`YH# xc(} q[nKMU:nmN*Mͽ/T$ L$;Z lI9< YȪP-))eHV!M"\>]\vګpl(:awlgxnwԑ˖)Ҹ^kTf'Tt>rOgqgeJ|ӄ%/PT*0AލB :`@R(q;L@B&hiI:m@@PmgcH2yw+>ܼ+\ 6/ ޳Bz'8i1+6Qrg9r̩]-p߬ {N1ZR)WB6'u9%qQ1KtuH c ($(87hZY.i@\q+"'!%jՑ,ɦeWHmh =YHA ˁF#.?Me[gϲKՄmZ'Xn+et1z]=WLOD%p跶uקؕE[WEepjCu<\hJ‘#,3ԏÕC:AĒhL:@}&D@mqs F@v`ya@H3aXH^ gk& "=HdHNJjNd\:L8f=ӾY_7~ݯ<ܼ]u.ך,+zJ$f91&vn1YݗDKXNbEyEӽXuV}uL Y) O'׃7Gٖ~YHd žM1-;SQ@qFZY<& wOavFI|IN-eKK'7iQ8niH&ͽWțyew='fdU־{\Wٕ5nY兖]l-<㑩\6cRƉ.E^}@KX)y{0¡AWHvD8/QLm@P y|gV ũ` r n1_پ~ćȑ>\Wuv"rɸ)W;%2gۢa1&W5Hxtmu>v򀬑,ýh28HqY@JC-QP3!s$sIB@@6Fb(psg]G^`“-=89y :595)AgQcO6МbXRaY FZS+ͩkf/L58@V9u{ki'۴tjZvٷSHma==e[×Xlrýʚ7"ϽaAӹkυ鴣'N:O^lPnufEyj08F50|Fy4D6p!@35O]K!A RT088yX%OJA<=3NtӣԇN}ڱl$LwЦwuE85O?_\;eO>ڢmǦrZO|kNm(CH4N 0(PL,5)5(+a@hI8!  FjB "31S <<,D+lݵSƗ/$֫\НHby2VF@=֜Zn2m_v2cmvaO6nm)ͽ<)OH9]S/*kTjѤھjܵz4^ 3B` \#}e8Z`Y`PE& A* P{G3@PV 00q0"*M+@QATXCp*)M MjF ,5,;I,yQ1~nņ+#c֟O{03nSP1ٴNaaܷ|Ks &* fN7TC C `c ,W0 8qC,Yd+i&b$Zʖ8(b@kzO +'!>j+sO`SȚ|Uwp_`H>  ,AS/+N*64 &5tHdP#26Sɜ0o%,ܒePR<>u  %c5Q(WU?,{35Y]ɲXEUJm~?b_O_jru3Gz 2v=-{=w65;QZ&֥}sh LTL6pSUަ4P(jRd -mLBan!@2 daAh0hMlT/4r&rUԥ*ɢZ_u'b̴ L(1R\ kI)\4| ìS:-9W8niNf ͽxW;Jzޮ0t-]bh}U5 v/g aKdufAʝpl!yPJ8q1\VLGр<)0C#& !21㴵IA)&*+*&۠YTtx}ۺCX"Ŷ EA&[%a-` l`B2DX#}!Y %,3Y>XR&>ia:TH)fg%܉LQLIU@ T``0@AaZW/a/py /B@rA֕*IhH" Y|dA{y[zm9ȍ'>`i[E\\-ΰ=L*`@Zfe*.iQ2nn 荼=SmG tw\{ZvG}³\o`>pfÈa}R0=y i(,t,D hFsdG qsc&0AD)t94@AFDcEBvHU_VQn U4ZJQ9dv_R@h1JtEUz[5YV$7p6x wµh,/Wdg/s.V.gSQ|Kh|cq=T7i](6@;  p.e/K76H@ې[ A2"dR%$ MP0R&4P&0$r|a<(^@G*@-jB4~\67h9C6|枦poMB`.: .(lxj Čr2?X4$@%)}= ^E  X@* *oDgLDa%@hvf`s^ q"Ң^ 2  jf@ oWDmed*ݽ847z'O8ld[a_YwF\6ys9-iiյ8Ų8kwhL|ޞgS\b@ɣ.Ii①qB@ABJK「%0@eƤfEȒa1)#21` 0,l)7L(a^ *:hMqf_s_W U9nB6鮽t-16{}gǪZ/swE{M1椼]}+zRRo3o_XL\;*/TrlAz cq:J!;0@iT`f+U\IB\U9ć& !CE%*&p`eQ,n f ͽ4%̀ :v$T>Vcs Jf3is!PEQQ՝gYrVfW "{uw[nJG.'gw{šg~@MAӛHIo 1Ks:M L+݃ PoaĐ02+Z`! `Dc"):*oh^TwrE 8  @P`-e1‚ш"@h|Qx 0@Xc.W2nia!GSiD: ?\4S˜Bz Q"@UJB3DX0]3ͨ0|UH8U!B@NSd#0`!+0 BQQm:@{aڢlۄzRRSWg+?ԇ*J^ptNϬo]Zt4El,K+GsԑkKKzuuYa ]@xD]M3pʃM3x%c2g)7s_ I0a"U2nm$*eͽxɀ"BIDP#'N%XɊﺉURP+uJK={ˮ}g.~Ro6z`UJ04]x̌ c1g"TM DpA I$L4"X!:A*@CEHqϼɂb~`(Um$ K$|Hj Lg ѣQ7]_]t//*k9;:JTVa2ƅRVv`P] @i(وpci$`@.5de:ea31g#wO2nmc*%Mݽ9 fFAL$m*0 *ef^#0q Д'U]`t1HZ u3h[x椇iDiQ{n gݪw+jI7+׌ϩ3uz꛳Few]צe5lأh 5Z]d3Ph`r@99=],8tJICLj_-b s3i 8Ǹ .a?`;97 Չ> ;DiaK+Tkջ>xrzI޾]OBܮm6j;{m;d7'#֙U,xwhF"Hgh`Xϋ/1PɀLyeyyS4niͽ=HE]&" 1-8u4 'T{Tv̎C`(W&T[ۏaYþr]nSU\zMy#a+W8hH4?.`rM:4iw?j%khD8qCcI 12HA'Hq{۶rݟ]srl*=E~Mɾs/׭2¯]J ykKÛ~^b}v d[!@v >c"჆- ɱ%qL &"ʊ YbٔW&n 'ͽUVdbRaC 6P, Gl#!kF}$af5fE[513.hwd)p%[wd%[îy-+^z_WXr[R0nfvP|;똱uGa0װူ1ÑL%.@H-ǔVvF~ RacVff8t;ko =+rzP_& !P]6Ǽ 4gJɩcF蠰}tzõ1pLRq?5p$4`4$4"Eh"Je@he-=V>#6:Qf-ڧ^d=1ցS@m-ͽ1NGD]]8_/e疛62N 99z,S2?PPqdpNaۢlkf*cPah`Xxaf+E<ƈH" "HEǘ@J-$```邜A"H|N3a3@gm͂1!w}aC BU5SvķOB_˒+mn1'~CO)W>maC ݽi˽k'^`eJ7+ApǾ]xn ]_| ?"S}.2!Q2Pp|Bfb A?hJ GMreK&V+a pd*%*fRιG HN@j.w7bVKݩugOoge1嗟Uܰ3_پw]N? "1Bbaq>XBh #Z .xȓ8ŀAЈ yA,Hx]i00a/:%K{j!FjDnE:V*ϭ.X{*93x>-AWT;3԰fj@F(xg@FS$J0@J-i&T 0"d ;tO&^XHs1Z@YE'"-3rJI6 e'bFVCw-ؾM~ћXzp lbɐL4k, 31`@ D AaQ"!jB5 z4aTpcz*,0(IU"dӔ}+ɒs?2f'!\xOfAlל+e|òؓ%SDFԥ VqͮWMvOԀ *MF崴QO4nimfM-e .),Y5%*uz4Zsijj]y&۝m wձ+d 6e&d `c'?mOLġ~;ȭj[{l:ӽY)/7Cۤ{0;~bԻ`móA1Lx6Z ՀS N *%=Xq o6!)eVf7fヰj`(V SQ&XqPPq p `(Q'09 Pb(ӼJ"́X镱2DA i*.΍O͵F"s'=[\J@uunO$~I'ۍ5_]8*|;m5Իs=5?.6 P .b! L#.tc,A "t- @f`#,0HABT<+X!!2!OJ߬!(A٘* 2g&a 2X(:zMA$R>\MPI~bBgb'r˲,ѓDmqZ6S+\V4_V卋Q +1€eS(n*f ͭM,L4m2VMA" ǁr@8£VaH  e42x*0$*puT<* az%(U)P('؈}?lņX@\'h)gFqjFP]!nywaZojA'#z|>;?O'w k&ٖ3Mo4J鸽2 aÌLOBFsEH3c vn`la$'+9G0B3׀C  bB4mC% AK71O>Uޡ¦fJ2bc₩fvl7.ar~/.ni(=p]=71t&20  2 5&$]8`]$Ni !*.)p*_2BTl`:0@'e/+@F,ڷ(B]$D5; Z]k(v"+h'5cuW=yffhxNkkC`ͧ?M_@ *`Hw+E*GJ4*8΍d(pVE0A1IācX#OQxP#2` l#A E!v]#h`a'^H1q>$b ̀]aF(LQAN0Dօ3b @Cl\i>f(+m$)*D(!AxeTċYCIuV_$ ÇjH]Hsr)da+$tuxn' `V* o2.7S!K  0`UI"2-,nm(- QX3  (dx  -:ݙHs1`8$8A҂eBO6q~kRqHv6ӆB.AQ6fJGeΨ(-]EPQOѱSiJo}!i&X$|w1Bf Fa٘ pP褸\0,TH#&8~)P q9҆$&."6&xF;lTjڇJ̡? )V/G}q-'nb oVJ|nݮˬ3<.`ew5%[?s8k]4 rG"L">J@4c㰱,P8mz_$L@&> `JS: Y3A0ظe6`1J];,nm(ͽ"NA׊(b2F5eC<'N&1a3iS25(sOuhSGS;[;y1 =7nɝA0P0 wCt^_+. Cg,P` -$2FE)&X8z1$"}Ui \9=_p\4B=)Ƀm/]kEE,(qyE+O7x[ꕦYuܓw P\>~s] LKzmks|cu/6^<at !W84{*CSN0ؔF#/IT yaRfe!,HѐhQ;B849*$2!c",Y2A8a}('D:D8ƠJc42ϨKq!j/8~fC!a NRdSkcy'n&Tru|ƃ4!#_X .MJf?9|_n׷l.\|y01g5}{/ /\paOm!2HJAL22Y ,0P߀Ua!YTG!`i@$=Um^\څCX  .4a)+rɈMk4f- rJޫ 鲁O5=+&nm㦥 =` Rd.iѼ)Uwҵs`G.xe}gz #9MGol8ϺBSr?oC - G ԉ )$8U-I5&nmܨ ͽUdh =FZIu7n׉[o3NIlI8l9;ٻyѠX(a,L OPtcۉ@P"e?1 +s˧c>Χ2=ͩR(ۭES[8ˋ9sگhf[;ړܭ8 aaƐf77pj@ɁLG`F RN03C3# !*f\cMdFRІf ExaB(!%a"2Sg]>+(nm ݽMc%ԟܨs{[뿽{gq,}7_1:n)x;˔m !b~?DƝB`scֹRG l3s ø3X|@`7>2YS82B 05p)` 1DLX٢ S!("BJ2*Ɨ>=5D22 z5Dj(LAlf%^gvMCT3S_wԎ:.ce~/ycŵ4Q`Sǖ"6_js a-iو`2q2<0,* (X^086n`)NZeBNR:4fÂU 0enaɦBiI&aa$BJ-&nm$EݽL9~_)_Z|z!N99cŽY|Z.%w߯<5;_bj5%P>56mk]aUٮzѲ!$ ER[+LP9lOU A Co`a]3>p%0hXrҊvSFT~eK_yY*~?P:bT_SNzjַsqILq⒝ 5Mԙ7ϧe̛7,ŮwYj{Hm^x`i.3>ZCLP10ܑ2| ! km4ʑȌ FH 01@vLa0n^@pL$a#"KR6f}n?Ǜ))t4ڎbE唤gqVcUڮaH8z2ɤ{mk-_/b!;Dm Ff `an%A(F E"В(Dx9H`c2׳Y3d~IrFLX+/TʑX~mjI%"n3&ݽy T,dޗHtH=V'[(A@CVQpj<0(FL f@jU"wY26.6"S( \G3cs*Z-ap#Ue)]2]t}תgo}ؒB"#[m|]5Obn6޹̷xR8w.mz_KfmĮ}W aR} hn@ \k<¢r`X%CAzI ! T%S(P44A@Yc 5W xuSG!N+'' ݽuR谏 $R~!Jq`/-BRgw9 eK$UF:z',Lbxa 6@!UbD1 &)!<"ց3 L8@kPw3(>*0<@" Mn:cĤ. YTU%i{#v/#f6f0#Dahv04( s0@YA!G[` P>1p$a'h&k8NL ! hDLy}_HqoQ5&|qPs]o\j6җ<.]ۈSn'`L]UkXr1˕;S:yüYJD!;ɵɉ@p4v  13 ȀRjeX&no1=N( aH$HBD_V@ae) *a$p `@Ŕ )R4jnN"`hmT[* (kBլ%ZYe~iϮgT8MLEӌ8LAD6L <1V p A g#nݱ,mxO af O2Iɚ  AA8vuDx`"  ),0 L= #) V`2r_w$N)D2q8֫]{AujۣB}V^#Ԑjs{ԖIGnưݩ 9_|FXUff8Njaz A5ѣdшNс я@| cсxȐȅ] p'`0L/Ș\  BLnx3 Ds$A9ƃS :CC b&chLPK HH5"!L%Kb< D R0"O5&=@ Re ip  CŐ*/y;/o@lD K5ZLrW'q酀ˌy,-1KI= :5@sy?H0`y 9P  400RQ8?ys2_8q @ ;T Y:dž30lc0 L4+ 2M2ZOU FL Œ -\`4tkd2.2p6b":uS+/3qc@0TPVqJ8Fа_DUHí}MO%89̀ꫳd '0q]ʀ.5FIȝO Z&,%jevwYwZ iCS72üf#!p5{1uFf3I.ڙc T&h(@TT!o]A4&ꅗ٭zG @as ج5DC= GO O>.EKB7Ik*d`ȫ3GsU;ڳ ݙw׿}v+"I䞳EpdEy2'=A䣂FWX %̘ԥLZc턛Dܱ(Y"\IWT卲꩜1)gvJjE [gB ~QHM82rGC]Ƽzٮ,sPm='zf)]'r;G6z2P#vҥJq3rEy㫔K6p0oLUdR л6PzRB<ҝ&DhfirдaÍM}*7,))D*(>BT` _8\edu%v>jrשr ؿ?:^)Bҙ8x,VIncHJ*S^&F'XdÕU < C1rU >Q4\9' fť(0Qj(. ՛CI/.]A̗h0幵altUNv贈@L W47@@ DDWȪLf0~[@``/4Jƃ]#) YWOB" #M<G=-C@QuesC0 !^ceKK'/-#9u⻚m!c\[5!2CC(8PP & ; eSdR@(L.#pUN[^Iй(}u  k:1GZQNWFm鍢 3KVC إ4T4VJxiJZVheU7D,Q)nzdR |DbIh b}it'MJ(UQ@FDpKf} jkh݋;k̚Vy,2.f>%~v4HՒ cqhгvˇQ! j(l(8'bkf66 ` 1$ @S`P;cPPI 1%@eIG=f4"_-U"9[)UůQbS94unR5vzWǒǦ hO1\]Q+ |q[/^C`VK4lmȑӔ(`?u!P1倎M FhP2htSNOGjg. DleW8'"ʃ%NdݭokHfnaSb~7.znq0$ys.1i2 xVG&&ϙ1 71TLnY>m* 7ؕi ǸHHa$@!YQni* =8# Ә=CpdJhU0$x_\uQ̊;ܖk _\fZJz,'j w !KǺk&UD;k͏?s' @v(eg[e8sў Ҏg@-b !ȀJpJahA,MP8ʬ#AİUD@;)0s"4G3{Pfԫ8pw*zL\/Xxw.rn__RMT?+>sPIK剣 p{ܳNy4n]-*J mXVۨumk'-f/$n c~q0ӆED LI>yYIPxWLa٪gͽ1@dB xZ*0*ƪ[ط-@`2(p;txTV=+*7HG3 ZS4G2U,(Pb=SɥOسUɟGWK#y[DUie2i9;lӍʊ`2 %$}*ѧ:l+ X99u/` 2Í͒uKmLǙ~ZFfzXnROXLn{;u͑X&lp5a-k̑rin(\-JܮaFtFE,a5`pԀ8Kcq!OZܳf*,T2R#<ϋ#!4.60 #nC rh=YUW>m*ͽ,Eu`];3xɰd[oz& Urqj|h}7zo }j{_OUywx*F{Cov˝g i̙U5;SCGɆmyl㉠K¥QBX,8D fT#v  YI38 Fh r2 1ybJ LsJ]p̙O)O$Zy7}-mPI9=<,$i>1oy%Ly<*ien4On yo)茂4J;jɏU& 1(a  B* Q5~q゘𡁇Z0 lJf`66a#ܓW4nmB&ͽF:ˁKp0C`*^ +GkcHB3:PiRĕ"?[ZliI? ab>nX=ʢ[$U֡_ '1Q<&(Tn(x`Vw.tR Ghs."2 E'lvkݠl`ʸ7H*v9:L5eˋi${QG`)_/ObR6=w5bMYSr$ٟk3%&V6gZh6PLR2Ƴ M㬠2׳y;c85x$S,7БQ5FLʀ7U\cǤ<( &aDӘN7? 5g&EWDme*M=遳Mnueϕn+]p]k^vq4Xx>XQX|cVo嚻{xg8o,~ ~L6U<[<-UΟ7RJd6\ z8l6)&Mͽ!-z_5=R:Z̴=;jdF6* 2pZD 8(e{XqA!7%/ u0 @aI0r pæ hJ6cCJbJ˙^^2 mшE Ntzٙ4#d8n$J0L/ 󱛯H)W/U%~[A62;u$Q0/hP,7QXB/(7 +t͊Q1aQ%#sW.nm,&Mͽڡ H s!EAP^ɀ   ;ka!c;2 һQ o'i(3R g17DJ"֟\}ڞm6|W~\Գ.5ZIlR͞DTѫR4[7~h%ji"1YFG,Vg蹎N&rZb7dCl9" F QČ8-( ?)AI@M-?@k!n`R9#[3f4S.msu.?o^x6^ty5nx]cY0 ̯: mP/d͆ vy ;D3tAW2nq*獼k ڹXRKPJ<^P0UFVZVC؟ *Ljv /{c;νvaA08=%8$"r29ltQ ŷZ%_3?CcT) @ ˯Qy깞6 a!  jP2 X _G@ 0Y&I2@%RCgPP|L( ȊcP(-ģhY]g?o~t+8Qju /C֨6AE&8wS)J`Ɏ`Q.ST%AxP`Bi*I3$鱰y*9`bfThwhP20c}W4nm'*f ͽ T3doV 2@gKIZVE=-}hr"T,iW]9E ې4ȵHy3H2ofLW}c8P:E?笎8єz3d[AmPֽmi Of1U$ÑS*J4) N%184 f@òLx·$ B( > Vh$d*L"0TQb.: pJĿ\ zP^)]PyIYIg Qp2Q/]`gFQZ*Zt֎O~5[/}3.ן4|(xgnk^DFU(duw J, 22 sH 3DS"2pps*QW,nm@%=ԙPrAl2j\``I ^ek ёA0(phb^:gl@ YR%82$ ͌x#Fĉ6J\ڝ;D]N[^(x[wß]{^3W[l˾ة+ؽF^6n׫"Sr*#-7S 003.$@f d"4PD:-_H|L&][j"c'zR"W d(bS x lp;ߡn1ФF^{!qu٫9 xH@[﫥3/+DI ݧ VlκarISM,@WF 9\,c;9`ң$X.3!LQqWg$!( gd 1q;LԨ&XkGs5bued25Kbr- sE ڑ( U g[%|i'ڗTuw<ǣ}ÿY|$xyH0MFFQ" bFIF`cBZqJ !K f:]*t/Yj ~`MZ>3FÈKZK\F ܢ֯)3K$tt,1:W@ma]CxJqp~7^iչk׏'߻/wY=7LufxjY ,2̩3s-0¢ N-0CN&t-ncH:}0ċ ea8ZsŭL]s9dJl:u{oVuAPxieD°·p"gqckKo)7ڃo n~<{gyqGlՋu^!:7eLzntZaV ƈkeACEP)AܐgXAB!^)&XhDh$!LOD?)>c84>~rNe\r8^3=NM '!)C6iq^#W0ni+& 1̵9/"7[Q%驤P cUG6oo)_iV-\iPz}e|3P j6Qd\o!f(x#S`z-Q0]U!eA±v)cfJjl_:Ɠxx.T9jD"BKQH*F!א.B.Umy$]~nA7ӭ+F&{$M6YLL`F@ a !FA)IA)D!Ap aRav`@ؠ00< I5Q\a69h ńsBj``8 %0 U@bܨ ,B@000C  ,>RMW*sqîeQ Rvѩ2~ٚ+zY"3S4_]PF$A5< / fPXKz IZDu9^sPiՃzC6kQ0TGSԅVRdvHhwnB7`6G% = d,H{kLXfgĔqEo_Ў$}qt=m6ባY10&}mm2Yg[T^Ya7&boVd{+ %y9V:H((CĬ;I/$7|lFI^QO]L=d멇+Y۰bVpO=n&xb6\s\81rbxjM |DIsMO4' k7.vܛ.7I.fu[[jh{=ni5( ng4+PX &Y_*da7d8.pj›:褀JJ;ϭ1 (5wݔ7*&v$YjG)9p~l*0dz$E"!/S߉|0]ƳxR?{Y~>gpT_UͳxiZayu+@ۮhY5 7c&@c p@cw` i"[j{BnFRHN*6zP-f6Ɣ$cܲN vSAE& x[MwWJma =ۨ+'rOآ&R1<= Brn;Lw=`A5"*ŵp{16:[<_TᔁC L70h 522 M\b9d&slL,5z!dHݕC"OZm{u/Qps-Cˆdݓҧ(e̞3yN|u9ި{1Mӣz50/6KŸ[^$NҾ2A39hǣgxhl$ e`,: K4|"@H Q1tr eB!$KtDpD w#f@F칝X:,ϵ,PŕNL5*;X !S8n!+'MͽvbT95+O1fpJmWzkowKPv< 3pbmy/R˩:o 6 J  H 2@ Pa0(.Z""c9!)&gB* H.T] I*IK&V4Lo]. I(sŢ)nsı 2@GN9akg*؏Z75߃!㧞!ߙ"[읒|;۞mm[G}JW0F Ϥ%13\N&@0 Fg: t f e2`f ;"K%8A@!3`$bVB~.iY6n8' ͽbr#>Hظ7Lh1*a>'Hqyx Mk/oO [û&/mqF[;~.bXzֳ'dUjܟh 8sci LN! 0?7FYZ~W-P) pGa- I(ĮQr3  ՠ5ƕ+04'=m4 s&צ{w gx _>N :i+mX!iMudvMR F& ᏆA!` -=# E̝ [Ca`0f(WM ^? xˆqQy 7 8I+Ux錄3QV[a: = Yڶ`eHwmrmU :Sd`՞,1׮D]4O\8y8m]pmz$?y/V8ݯjMbQLT}Ǘm3$Sd)#C7FP.P6?lf^mBjm3bEŽ 9bԑ,t1Y6n' =9;$[#oJipy[ZZd<xLε]ѾLY^vCDږlsX/EbyiKi?jzLꐮ׬9mWOH| xo9 `4jቋ3 F$@u#M+ _Y{2g|2tAZ2Ȇ1J3bw[w!`j=`M'c<+m فMe7_~17ݱ4m›3}g,^l̳f0%09BĠCC2&@֌&8B@d$dNcp\ ۭ3ج(!&}e:ꂫh  e1F`zR(z }WMA"0#Z2[#&c`*hHddq(j/od@B MѽT.S4\NpqIU@m' ͽ% bU.\ψ_,,??2Oܪr|jmOzSޱ?_Gۭ6 ʦhM6rw/H຦7}&d Ec@Y&epzT_#R/>Q#n-N$0xY()̴hXrfRPպad WLq֒XM>Y !>Wh?H8:Βllܿ~;\iXgmZګ,.gˆo>,oVz[N}WEƶձ[;o@.T|L fpQPX XIZhdS o$$KW2#Hz{00\ Y?j;GezDZz"|+çWiôN3 yY6nm* ]c85RZ-/ ,zڧH^r2L S!FpA!@BCEΪBZzBe%uGJrܚ#؂ȫ(er5oӧH~\PX$llWxnz_M}gm w=bvoG=[Vڍ|9yinc̕5ˆ|Qy{,HzNࡕ8^J6 6BQ pB$Oi>sD'l?\\dSL^[0 nڣ'1ՐdyN~LX;ɾTkQz0뎧`uKbl^mmsm}_WFm*hͼ=-kJeU9گܣl Hi_ A\D.:`CEMdQ!$=!0iu|`JY11zYgl󯞠fU[@E^Ѯo(+]Ո䎋)c3j6Yrg ?[nwvLF9zM"-lrWhy m)*p|Z*ظ J`*.-63`($bDS_7"#? ECMG@ 3uQLi^ዄDy" yJqIY5 3 {W' n:GOVD#LJeGr_p[fWybI CԫNF#?17Y>m\+& ݽj;CwVk>! ,#UL h\ ,.\hr)q , #, MNJa'A ܂j[nT; B"GTN{#&iFa*ooHw6գoE'<3;˔o;V=! p}jK7u(]P` *`hzePvPxc8bRex2`hj<` \]STxʸ(gAu z0F 0QdU`RdAEJ9MA 'i[ Hd-v[%^Q S2 4JưaD*-jʯtݤK ѱysmmP{l\<ՉTWBm%ݽHL5eꆥEꧭkU{BV0rl}qGL|$ɘry@2H \(D63$;B# @ÑP$PH*f `X:1:7+;=!o ,|ph$6"kIy#C KޗwUo I 3Svj&܍NsM{'>΢p&Xa@FZC@00iMHdPXe,/};݀h uƥ,L4}~Spg9 #M57GdSeFz⮛740_^XS>5{&;g9b'׼f9)U0nq*  GeHA2U\K0 9y[1w700V1&*3X(0M>12}+̝4HDՆ2*  !^Dq5 <NKs$a‚ zJOIIutG6*AW3jL jIPá+yTYgyqniN\oOy鞵7"梅T1mv;v-*P|A5Y˳9AԎy^%) 1`<@+F'q't B1% "*$EP!àj%IP p *81\xUQ,84X4.E~jtV˹aY(n i=Vсk (=Ex'\τަOi[mU^|ys+i4q/x@T#vjh1;U y6{cz|@Ӿ»|Ϥnts Csl 'F)`A*Ls@iěItH 1Iz`Xb`e0hТAI^{0#UXp@a@Jo"UU` Qprh$Ʉ^h|mWFmeV+%ݽC`W]4›Mu-p)/4|]m.2ÄLC’wb?w#WT 3գ*  -LM3+!A0à00 peçc!&@ !s?@  nŞU8~I7}}∾xA]d?Q%Sbe:?i77$0fY3LYɈԯwML;\v>թwxm4QWr6U]o[5yu[M'GH ã3 a=\AR %MZ-4) /JTD(fF!4 4 1Xt->jbFp nRՠ G>[5G! FUY.nm ͽvs]mLN|닉nfP}r '$sbSݙ -CeA%1Z[XКBU^[ƝK#-y4"#5>ͱr{$W,ݯ=ߟ--?;T~"ݤì?anW܀J!R`DJ&RD[xtc7yJCm'R/dN4tVx$?=z;\sS͗;Bqc9Kj_׹~^o^6Y͖k znW4ni*M=jvpЫU#5}5Vݹx]$(Lj܀"SH!0K ECy9E5a m+XAB*e,C !܂\|lI/h$ 13gB> e|?ğ~뾲 2Q/q6ڕ˾]voXR/.R^7N8aw{(7({d0 jC/ szBePh c+1 PH;H'Q\DR ` tUa#LSz6JܒN뼢d*YSzH, [ -<0dvu nxܥhzJ}+3ͻ 'kxb9h9G{'PU%R"ED2wRxUᓠ:Fbq,40dF#@C_8KgA A PDpd U !m>p߅P 5Uy)*wry(& w*'b zhtL棏%wWޛo?eW.g 4t(8aA ALb 0Ag<ǀW:m卲ͱHC(i#dSx$VYmc '.`PI FxE ֙vY\s96–dNəmA;\~5w,\f`˨k^j|EywZBN'Ԗ- RND+yB)f09Xa!%?̪0A(! t@zt1 )Yv&D$ nغ kͳ@Ԫ=25Kz6wi*F:  1rO =#iQɆV`42Xx;`a-f^8ρ-` DTp,UPH" Q&AjMyɤ#رR&c<˜/5Kzvu(vvH˪yfV?LOV>msoQuJ6 VT5≾ - 2<0̄ `pG#0" ! :^{  l"#Vt` HBOqS0nm'*%MͽQ%)[ sSz|%h3Oݨk&,WnYevQ,˗p &McoĿ-^Ojbo[_6۴=_MSc[7߁HsUk40`"0(Ƒ !2HFa(fXׂ=HcŏXp7IdaedBBp%H&Wq!I~$L>bGRnʰv11ݖ33?Obkc~v;q$AXP,sռŵ<(UuׯP DCApc$  Cx  LZ  Aa`@9cO)9UG1L fBXh<!h!aS,nm*ͽ'ae31ʱmҰƯF-VrViXP6|mOd͘M鷻{>'6֧`%iB`mل])&HyIFBw2IJr`u:_CXEAb7P5L meJ@ yȖ8VL,_:Zf7'1C,J.%]оB8HIr[j\tJeG0B*<3xxLW54$g5 , ( q s!:pғ D#݆A)>[Ұ <#8HΞ0lhMQ*n)-H:JnBW(ByFu 6GY }+Br`pQú-smF`)t|Ge `dja 8d@مP*Nhr&qF@+lH!eQeįybs0M=W*nmmŨ%ͭ9*5GRezkmS^o P&hz|9›u}3f7w~M 0R玓 '1XPPi"Û  $0gBQUbk KPe?XA5w KDLuqd[8P&jminfm;ԯ]{Eh׋{ORH;ӹ_f/c3  &%#dB z6bkiƆ4a=#5DnbE(q"J\.8CYNZή3V,$ aI Ii#l3֟[aQ*nm)ͽ)Xxkq6D,Ϳdl\v=emWolLl<-ıbNպ&R`@s9 11\#"b@Jt9FLy\fr, xaT,p81P 60[(\@:+KV*)jin&Vȅm> v}%7?wVcO6R|^ڷKY|f1=3%6#OX\^ǚ}F̗t 3dqc6-k$1a(i%8]a`!SL,@āTH"ohR7*j2eF'<#j̷!.eIܴv0 AF4y~h]]՞$z|ϛzܑ}M|R4חKo˅~ jN*V8N02X:`5sc xH/L1dH (S%\\D|Iə/05$]VԠ 4=TCS'M!=@P2 *6Th@Yd VbD¨ČD0@W C5 2"3!މS$}RRQi;e*tn.{n=5K*n*ͽ,/ΆC??cؿfg;m٧x;~=1/ /5 _`bFzY N (4 a=9Ur'QJBq (mi~ePRBIQ::FBiņ-I&_p@GQM[n;:Nko'e‹Kq'6bM%A7 e4mVt `t0,5eP250Jxz>!D1@(90`q"2ce~Ϋͤ!b $+3o5{88չc ~W*nmݤ ݽY,'mC߯c^3DXkm4ץkzı77)`YRPafspd0lf`bdf$Y'`tQSiXK@iAc(t& CRrS"ԕYj f`BA%jf/uzcqdJG)ShzztM v=FIky#v˼%jqѯ2P>']zEz7zZ `A,#pfdC318á*LshaI y$<#1R;YP H6bu X+7B]5N 9=&n*e ݽjx&-J546ӛb=1ԾW2v?#K?5z,f4Zv,kUco3Gā DsFC.GUbʵ`րT<!/!#FF LFUb& $BSh@)ēPTLsȍe&`6۔fewRLeUaw.*NF4txa "M!Cy J"v:R7 &$I=I']s8i (n8]h`Kז}-/C~qyw-ƫ|Z}m_L>Ut10Ȕ91\7% "' y1(XE8sbFjk-z`A.P,h:. (nE)v1}ejЈBeh}J|dy3Qk7]mԻx:uISm|j&k|Ğu?vB ``<3`FpdDŽϰd˰|ŀV0^k43g rPI FaPTh*DC W\X ,9UQ'sIwbI;6JYK&nm'ݽ(+czK C֑|:~fije޼?og -Ehl5sf4$'$4H qLуc gx`1``H2% Ii`k$Izd!.$ dC h,@LL( hYhB']Ec[.Ț͛~bgr7b[ |+ho'y4qmb9>f14ъGb"_һ_c[ `PÁ8 )@W0"dAI T Ӄ#c$pCȀc@:IBL0D2.PH"7+8H?d{)C&n+$ݽJ޺SipÁ-> |dO+8^6q\^#~f|[p){nͳ6qLycDSS>C UCJc uZ` # ! U$JoIP"4.B`pȁ!|, IcPlF(Vo缷$ycנON t݀ HKy"N(Sn6[VoY=૱~q$ٛf@#u[ܓֶ:ܖat-̳@H`bbJu{aXvS c\flaЎքaicb*(C?#g9Q\rFLI4؀ƀ A$f - (РҐ0exNCQ#nm<AqQa).2Ƀc.paP=sPa$a >2ZAaU/-CyjghdҠTY0H\Dq\YiB}5?@;jQ- 6>; $Sρ@H৬d#uDq3ӍFaZrd5rH!- C Ng)"݌0 _/tԙSv\KM)@j%i0mC>Eacʑj$L%^kR2ɇ%H9 vZ RZ ?q<0<1;Y ƃK*P0 z<NYl’ X1\VakT!{3G RēPFk40ԣŏ## G#J J>0b#}UGǍ <.J` m{wVOwoUɯɦ?ohM[[-MM]-@Ҏ!TDpۅ1T00@"1C&FhF AB0JOpp ;8-! 0@PDq S1;(ni(dIݽ兂AHDY ڼ%::Ƕ}0^tђ{]H!m!^Y03&ڵ6OI-I|@v>cDo6/>uL|?η=G0L?LL2˘T  EZ Ӵ55 ѐEMϒ `ǀY~N<6yT[KF✡xӯRk\GrU|N֞VlcW?y~EnPv1/rc=t&}΀CXDAHmqThtqaV\f,kD"c@M| BFB`Th6%Cj`e="N#duPX ! hD  <>rdTQ(r}ɟ@I|)nv<(y,'4`?Nn_/n{%3NQ|Klfirsܔvݭro W]{Htks!j@0#E4dsg^9 a2NF-T``^4%P@_bm&\iSl``]"!2f2Ȉ$jax``2Uw0¢uFp$ć!=ʂX/4@C/K4,ĎI^xdT۸NjCu#2o/TӀ?N $c =pu4>]D&pJ݅ҵOX۩a0.N\&s\H0x7@DT$)3yHESK茀5!os+c=f  BD Cc@PxX$TmLy KVBuYZP emH7%SQ51sC3G;EUFlfzg>pnw+ $x{>X؊6+<> @C\@"à@H9 cJbH3;afd|ykPr0q&&"E)`줾Ɋa2 f|f;OSm1z g?߇0|tv~7^8U7zʃ ٲo]͵`Aƍؙ]0}렐|3CJ 0)U95g_ r)5#8 Ab.[0@g~*nk #$$ t"01d)S< *@R 0rD]'r3n)\V)̧b< pA sǷoj{nZIS޿v+%O[8\|@7Iu D?4o0;+0(%)`rd8 `$hhC1*S&*URФ <•}`2<%Xs}zO :mCiXp=`?V&^T.Ԛw.}}]< /Qt|FYތ0gqIwMZufw>tU<=E 'CD!@o L1xx0Hfs"GHbL*:gCTƖP2NZPHBi0ͮɟj=(rVHXގ#,niޤdMͱhZC*+ ^ suq%PSUice:l2_<)CiIypT7=jVκnns@b!yrfp[abdX2`pglc8Fa*94lU+ 9ukO(*-AKѨi^PS^<ȫzF# @cs`k9{U^׾Q5Wo pu;^r~{{c!ԅ.5hʞTvCAf*D& 'p(04dI1TOg؊e': 4dҘ!⾊`D+-p2b=|9'Jl<"!NK'M-F"X9K/zx̏Dӵ]ʷ X`)DL:_,۾%9s#@*vB(!bH U1HB ^<<(8pৈX-ɕNN (uD`ACa8TDL9J#dAC^U¢MnĿ8mS#KmjK'ϳ2%9o{Esݱ{wwys9vW-3]^e$kYo@уp0( OB)h-6xC<+FL,D,L\40)kB$0f-AC&dj$+ 22tc!J3xK^~Jf]ȋ`--{ب!"n $# %Т%י^y#_(aNΥOzO,;_&{b8U2r嬷xL{5  P />  ͂L,m 0#L;8N.[.s$LBLL *`0Ȥ<ω"B`C&,M2čDC@0V*=,H*HLjKOCȎأ(j..Oֳ:3NO#ے6ѮݩyYY[_ް?&}J08""JabQ?TH ] B<ԴLu8@̜CŴ5wHLAKPtX+9݀C=s0x\RT 0eg |Gm F&. AP$ QTpdfP 0d0` -( 1`0e ࠰ 0 [00 Mx,lH5C 0P2a`x\m 7dRV JhQF|0(f)T_((8H@ ""+%Yz:[?%vb6@PQ *;2X9~3j(ܪ}K=ed|`K1AJkŜ)E677Iک0SW٩bŪn]y7]Ё%ǀ5Jms U.Bd r]dBAaor5g]:v*k1#^#=kJ֯qv,8(v~T>fFbbf u=3Wu(I%JbLY(ŮOlū)_>͛u4Ơ^:Ie۳1¶;wV֫~WB{&  F0Pd(.w{]QѢ L$)z=k (x U@tÒ5Yjb//~̭ҷúV`hrqN5֣ |\:e$-bDr߉67k>VQtRRMum[dr 99 5X搵e͕IbR/ΣfX v3 ,s`t!rޔxe&$: I0,ayZg /SaL=y*k]6.򺴾jb{3=-, -8kZz{QmLm{y|EɸV)z& HLM0H4@x @h٤POw{XVN{ +ԆX~f&[ӎ<.M%0o׫?bŭϹ'[ĺܟ=Ju6`wڻ^5->L'om'u=lM UHT . D-P29q̨ R0Tx`T0_Xu,(;lg™pJUd%<rUYTyF%`¢L ̡b4٠e#2RAV'BGS5pTmwsTLQ=aQ{z"UqLywaL1=k[SŌ r^qԻ6qϩbEHy9G:{yK~^zbYFV-+(|cYmQSDm182MZbf@5H 4tLEm4yS?r)fI*nSYxE#0[%СdJ^G(yyk=/הjf9Ȧ $ݔpL-a묔> (s*[5Ob pv3  1Y,V1U %6qcśg![P(*^_)PPAaAL`eJ *Mj5~3,QrƬ2gVn/Dz}nMՈX&>_o[/ Z{}a-j̻]UwiuZˇSAIoZQŀ@сDɁas,3t "MyYSBni)M1cCAH(<05u#Lg*Tk/7 IpPdYģ@B:͒͠6~./39Y/SJh*lGZ =yI_ TV!2s a '(6q6Wxr$}~g>Lb4VI*KSP8ˀz x:PYaK:S8ή["R=t:bSqh5j w$Q.q}g,)øIb[/<6oM<,?uÏ%Z 젊lLLǐ4Rc0$*S ZRBk4#҇j˚?!DS_Q  aS@m CcE}r~"r=eޠl+ڊ[W;9>Xsrmɖ%NٯFJA[=\.kfVvz](T<0)#A2<4@5H9 PQ8` Zi4֤v̠EEb`uK½J`yY!]9?_VkurOrjsҿ 7ݺ~YE{ nx>ZiMNxKw*Yn%^ZmdZv ž0S/3BsS v3 0  X!yc uJNdЅwSDR(ɇ  4p A+M,bݡU,VpmW@ni)=9dfX. "THoʥݎ*K]|H7ouU_c]8ڛzvS297rsG,,R@"EA;P$QRׂsV8E|މkBlAB aAPwaxdM2y `E+PRXT_KUp-%XJ9)赇+\*4u˘ۼ^>|;aMnvPw- P̤m]/'>*iԓ5JL(;Toi}PD Ð9t6OtP: <0Y9FAp A{a@ȆX8$^ b03QX8 _$ *"\f>`ԭ܀܆/#" ~#$s -o:T[J_o91W>nixfu-OZ뛠Om_jZޫzISg'o~-^ ,MK5B@Ѵ?>53eSCýbc!rglm2sBŒ!=>ÿFVZiK!__ŚGDR3>0ʬ )*%ANIbyئfTY`4ruW7m0Ke e]u"7G-J0~^'eM`t )GYO:ק$(J#b#A%rs3mY0)$ܶ { wu3teZE0NW )f&8_r>&˼i]{IT-_k}Q8ni)=^J͡Gtكז{TC"Je4hX0U mVFF0$-49FC͸MC Sp2r)hF"s!H4i՝<,$$0tٓ)TkE**.ӋkNZl/0a,\=^unQ:l>Xkߚ5c{v}姓 L̈́^cu.hXCz@fs"k!!/2Al i@ ,@4!R\PkBp8)K[7CJ/DXLBI..^cPƪOSkH7JD>rKc _4JR+m$2_7mɯO8niͽ߅]baCy;":SpVo%|5l@ $lb酱F|`U i8YYo(MԆD` ##AIPK̠N|.84 0%w6RF ,؋%D8.aKF48.rd̐Lf CeQhliKf%gK[-(쳟KuKFGPlYf%*1؟P LAz̄`MY1fL 1̘6 r{.̒ "-RD ׌4Ȉ`CVaU5r@K!*1QS7^XB`;5$ djZDEV43VKN0@EuV+޳UO4nn-*%ݽ#O<I.@a-STeAP-ς.6 b|Y t6Op$Cm~Y֡OŏU·V{)_MI=Y=V`~$T!G_^Xy3LfS`FClETU W@i0S@2ƛOB(0aF>0bE"[ërW\xF 0=vZ8z_Yn7d}|%SHm*f=) \; Z{9 _%+Mq6՚w,H@Cj U5h@pL2x%Dp@P "ԛ0`  0q`PhÆ \tUJ@" Fo!nSJJ>ˤMfrev ;(vo1=mV= WԳkMԯ]]ܓWԖOR?>{SVK=[[)n5#dĬdR|RL1x@~d5_t!1caQ.BAe@1,Y>8+;B{J$9,Weܖq"nǂ l5/$}f᱀U0no <*MݽBZȹ>lYRO~>1.7d妏}x]SW~2.\~_*6Sn ɭاؐ Vu4D0 Ef)AfQ @ 0 #٘t( ׵շ˭0k=Lj@ 3-pcM+3`icSC8 Yp f ˍ4 B0$#oj^/|(T`4ά7&_-fZEU9x`Pq/uo~)f'eH` >>2>#yOa0TƆXF<0(A(`ԶL E`pbbm1_:l_ qȚ 1SMBr SF8LPYJ 񄱑I ]E@Z>}:4م"er6՘7*-6lqҋֵo#xJ~:4ȿh˝B=f=">X#V?B0@xӀ6/$ 8LJ PR遀 hv`ӏU*na<J SX>S?R Y%:tDX1R 2[Q埠nqB=I$1ֻ#n/~豎eMG(OGG~+K!KE5 .C?w,s~,7=@M7U~b)N{ qcqB,d!.df(H8`DJ:D,@ ,O c &$s&r[4O:=Pk|p:P+\*PZ 6q ]35d>L03)tNt2q!anArZ=bO3^mSG@&)Ve`HbnkqTFN(01Q!%HsUYS4nm*fM=AJ;aoKSm89 rӂrD+?33d~=Jۏ@Vȝk~lYd7"ϷM:ߟR kO'\ڼe1>k F^fc'œ2it+2c3@JBfD ËNT^!R8QI覬ĆaC#5[lfJ$+Ŭ3TD p.y<]NaVxβř79ÿO-2n?.ڵ𵙭.zϗѧMڷՑ{W,nYX pq> rpV|!UhLHm9@s&q$D7Aw`  4.~2$>PVC`(t)D.t@r  5+l@زNnq4(xEzDd?J/WW?R-n~jr[ڞCGS9ݜ\,~*%KdI?@jc9Ch\d !,^ tU,no ) ͽLH$q@ZBaC Kq~ C`2(,,; iuF1> sZg(+ř_? xHۖ _O|\;C4=F_O2:@`t  <̄ aB":)02PTc`(K) ) HD P$@cU6RXFr̝e^pY*WЌNi^Τlufs)t->JIF{~{ cѭ|ܾ)9Zf;$<;W\|ψ 2g)C: 捻fp&D@f&yF.1ƌ*3!}U.nYݽ]@*-s RCB28A 3E8GXh+j(se v3suI,4Gd1gwfkk+Žۙ ]dRpr^6@"yf3'fiՍtତA"cJq%MHD7zu İ?1RF@ )/ 0Py)"uS]l TC\{ʖVgZ٦CcIu%md%x' #7ӣ A HAS B Y>&nj(̉FII‚FInQ2!@\0 8b^ÌZDJw|ODem ͱ<%Qz^}TpSx"J? EDQW[pOrs3tru> ]\Mhf uuR:KBg0e/ QFu+f3ɂp 14,qQQmH̨|a-Ŋ\1aa HZ T5B*xcr-}F@Z9G8HԼ"[ \3Jv k)*c 7.0y.#<͘I9j,F( Lw\5ÃIx&ddH@10-.c$ FQi(2 =6.0, ȅae0ቀCRْ)U,nm*eͽJ*k*tZ>Ȼv{ICӋm6XI+',F&w/Xzޮ3k{ir[VSWrkS h0@00-2|8 4P0e1!0؃1z0HN0Ia V (0*k$0\Uȅ@2Cg0Ё! }C;o#"D2@Yv _g,Z7[#h"v;ܭʋs^&b'n}K~~{<,_#]b9]l;Y=9Cs9Ng+{wa~vY!AoQΡÍ$yٗ`I&b (6W,u݀#Ȝ;f*XКmrQɞMO0b9Ć!c񂎆$*L 55   fL IR PnL}x"TE Xiyu[0ՠ~өbcg.w]_Zr 6*  $RH3]S/Wi*88ƴŢPtq{lΣ@uƒtH864B00,9cd?%./2`#v39Ϥ`QI3@DHdFK TP yi!@0!R" pm ƂE\//ȋ7[n,} $QÂch.**Y 6변%" >;i8ӕnw&𜽪 Sk^W\\ *r废x>kx3$[oHkYn1V7)2wN~PR]UWe9nJY< pyLh (7GKDEYS\(F$ 0@H ÔduI}MdiR$^m]] qJK"XB)D.O{ n;βrɜ[JGiP0̡/Oͤm?VTR|9GCOu܊V,nQ6“?W*gU|wF Rp4Q6|%4 Zk)W  W`=mH X'=>ZAVrQƇ" Z'̜YOmK3?=wU t!ܻ_8]GգSum'.h$RqT֪+J] C^6% /LIc|ll<>Weݵvayl4lᲮ$Gɛ !, 9z< 4qdz ^-W693 kicmAnVsU>w8ac?pS,VӼ( iZ!MY04  h RŁ@CsO@Ve_B!=QL31R*I=j,O-},R~A&QQ%i䶒>tz`S)PZ Ώlb鞙_~U6?_mX4kIMQw V(lό0M, 0`*UL$BO=RMIW$~8F2!iA ,a0g`deDQܹ GغY7>a42{QZ liթ2sW7x\BW1RK4)0# ڑk׈T2͂1M@kZ  `%0-lWNmaM1C /!CzUϗvbҥC̃!:asX+h1<;$` *Z}DS@ޭςl|GNJ_Bjrԝآ] mΕE˒ Y 40HMjb$d4 Yȃ@ Y0JMA`W"2{DI:x5B»dcrB+JnRmzVY-w>}P;=K]GYijٷ`1ԴwQo6b^""h,;KnJΰCْK[,|h*8y TydY* \0*'/xaCoAA0-+4Mـ%/蒈}WLmaMnPKd $HDSPHlj}\e kT˓m!V&ihl{ń3.Qi df?jh8*EV *FLIeFIpTc'c('8y3:3Pj\ˆ"Jh @ЁBcɚJƤKd}Y4IT ܵcF7+JAmmCgފg#!űbo5r;;32Zݔͼs]{z}"wɻ O>}ib+6.P5ą#4y9iUaFRmRPi9IR$ ..JanzL$@)1)QƓRrj텕(_'+75$f tύR,=1 /x1 wx 5 x#yB9qQ`(tb"⡦Pa;]jbUh!Z#3I vaA(yx!PܶPm!1[:pBBzO]wƛE(&׽ik2qg1Wtښ#Fhur촟TwM{q9n[UaBcp4TOsŠcM q<>8bw&OgX"s 0eTS871Ԭ, G Xx<B7rD%x*(5 (`!"4XBߛu+9O#``aHk; %mC eltmiֿypξqͨF5}<[gqWFme-g ͽ&XMn02eJU?`) bƒc7L+5$h!th``8E , P,#0 0F2WLp2 9LmՊ$:~қi$bWddjYS-'0Gpmc޺/mݡ:Ȣ}1ĴL.DiF).H:|h81鶇)>8%.Z=_HI`/pכ150ZeXu`ՠ @(y"k5qܦzhиD 5 `!+3"!t 1DtHL \LjIU1x8Y-WJ[u$hu\u^\|"Kdh#J^| UeXjEǜ2*'ֽum7;i_!W6nij+&Mͽvߖޑ7w\BlkVp`-PbBn۵ )'o( 96Zb!q }grLb!z2Q< 91 0GA5 (K$]&4+~$3$TyQSVTD>ZbM%:D HgX4ĥMa-&sCg̶'+Vxy.cB+9՗))n.+-+.',S*0X 15C8 3"@Q(YCNʢF&*r,!b1P OG ,"#Yg$F {&NEӻR% lncWؽ%Ԕ|x_Po})ޭ+l5סk~Κ~*n_#=3gY&"]\=~7xJ֑#j#׻+SMNlF*( v97 2FsAA PbZ\I$&FD ]B4q7G!_1]K bu@8_A%fK>qţs º؁;iG˨ U2nmhZ}'si]m>>DBR~lhJ$|֊H&bf"kQac 2$HH"eeU`94dD#̿`XQGA92|Y`y%jM+3 7h2m} &S<~EϺb[JJj{Mxq;2.w8k.Ԫ#Zes4*ƕϗ&m`4#F14 ̒0KCL :xBX7bܦfă-+N` 'iĨ VtZJ% X D;V0Kt}1#|'r=2]M k1u5mQj'<\(vZ泀QW>mM=o+3O6U>g/ PZ(Jc8IE$bq!` S?: j.-4ĵB|%QCA=}f co|ig-DX wigSU[2qFݛ}|'껓:w5jjANZv[ST -@ qV\L<ʆ-=<Rã%y4ZkB,Z)XDqZq xNm$лѶ[)l&l#R0W`/Ԙպ__T/fÄS\r8f=&jZiە5 a$N*8 Œ ' +BUBma =j@t RTqq4&Nd<(= 4Q@|@$鯬8Mܘ[EJ8#M~6 jƇ@=e(6M,)Gx'P6{ u-(0z~Y>14kdw1?O[uk69[{G1يwlg*pӌ,Y6c" 48 dn",Q@j{7`TрHɐLX( L$V{i |d$KJ Q-4M2xqnhXT.țR zbPQ w2 UsWLZ65ǵk, MXQ,1[ԀW,nMͽ& 7#H 4_̩4L6C h exb@Jn*&eWí  t@>a!"=/C!H>jx/@Rnerk%-tZY#eM.pgBg k@ 8}i}"X34^ |2IR;ɯ?H 3YtFS1LՓ0LE2ATM1TD@3LlyB:iɖy(3 3 8N%}h1뫯35иadžr^FuKP\ Ĝ+}:l׮`q{v!yb='$mwnŕY:RQێLjoPf ;E1ri2fZ:We0W*,1 6>0+L2X1$84b31 pʹbb%&+bL$dž8G0)pSL''W &cxƁA"#}OIhhNjD6#.qq\Y=[~ӏ{/K\["ⵛ7C64ٓ:SE(`5#+dD,QfWF.f Ib!g\9W4ni*-IPD4T 11+TW L u " 4m P c2) r:sP, &DVm4`fBE u]=6LwD۰ѷ۞m]iJtl_$& 24TCtϩAS҉G?CAIG(QJ8e1]h@iL`'H`Px%cNdxW>E c,\"5 0e먊zB(CٛOGYRkJ{/~ηz)i ɀDf'WYaP/M@S+p ʅ4eB @ʄSBS4nm* 17O:ކ2X%/lQR'$>wK/,H7p@1-Iپ|=9_c,龪= ޲WY|U#pvLte(iF~ aIB@豩4~>`BƘS.d(` 0-(X(40Y19 Pf!P ?7kΗۈ)%QU3+_qq!i 7ܝ[X>vݨw{8OYMOOup$oP#cmi@*@%$Lhs3zyL 0S L@ >ЕP0* CB3wCLtTHy 1,dQ202(ID&`i_{iO4ni*fM= _ GV\^~ʆh;wC~cOl\%KvA}M%b>?ܳ37q7)f1@vZ@N¼gRZF>cqx0x` A$:{ 6)1JXY"`"U$:w2#Eu",FNfRZ)Y1ںGb}MILiPp=1o|kVsw:tmkm4s[Wqf(6`JF@n`E3 Cdc@   f́_* c",! $9Qi# 1j[n0c4pL`!JW.nif= [v{ۭUOmR.>&kMZo7}ϓ2u{y:Juoyg[)  F?Ӽh!dcC°qm>a!6&ÒC3.)urR 8$)*%ef+!gL:| AnP1T:E us %t64za -2wH+gSM!+aER(2M0pNi̪HaOFE;t"U|ݮ׏ YW2ni * = ;/Wb80l4.}|}Ɍn[J}jq޼`.djϬ5 CZ002Զ)5f"O[5fEe0M!:3A­7cf@q d3& !bKX?(F2DWIF1Mvٞya9PӦZ8aS̫s:?aRɩi1䓍URۡ=1ܽUsW뺽szG~G}wf6~ٓOyյw@  'ISYs. F'J0}y y}@FUDѬh(L@$2!SI01ZʑK Gy`0fB DƟ0MPlQSL@]LRO(jfՍI!E<2f{{nPZm^}f>uo4W6߫81*]Y~ D$ G6gepaFNfppb hġk\ŀb +j 0| ZtgHrIY,nmW%ݽvaqԢ ʡ&=6FR9GfO'Zu T_q|grNp'ϬyIGnf|56n LANC$L|5]#B q1#I@x9 )ۓP)^Ŀ,輠0b 9Tn#Æ,`v7A] Tip{eY[p{c#?%⸤]3.60|ƭƯX9c~ٓs4b}[MbZ.u[ސ& ~e)p`e0fh4ƒfAb ZȀCD0I20 i0Ba ]Bp+4KeA1.60NycQW4m*M̽@HSt F"p\h!90!"6IA ^3fǺ (no\"oN 7c^o?[km̛kWww[H`R F1v|"S H00(.0HmLfJ #(T3̸h >` Jd@/j顥X8r2$S*j=hL<&yj¡w~ݸw.ϔ^SV|;lyukՌOaM $V6$"5vk%|@Q֋0h Cd &za@ƀLb>=s?k~I/04/xTm*WmƦ>F^jAo๛UE$`!Cq=7f3,A]Y(n =ؠ0ⱋ& BcA#A((`>d{6-!懡'zAˇ[P;3ʳ.Iu5ma0ԥûcQf-[~wk=7̹Oɝ۸Z/3y?C?R1}&9Ff6t惌% ff@,(u0dKl!Ɏ`))R|팀1XԼώL{D~Ʉh0Ь&v:YuDj @Bc&`X01TI?l }`%CbR(dOΣφT2i(-*(i>Պ-YT_ʙc>^\uٝ[ "\k;}ϹzлZiY*ns *$#,L[20_# 0`1DfHi G @88df&b,\oA&nfe"e&`*,FFpؐy;Qj@I JD5B]F>:n0Q= T6,TiCL[<5cڛ&;9aM;߇p%ik\RI_(,[U`0|\XΡ P@Ҵx bbX l$b…,.`&!&>re11Ps,W, N$U> Yg@]wAb&Px$,J jRn[ 鮬3N/90,C4Kױ(zݙXWiƀqU(nm$/8^TǵWÚƲ:Wy[X^e^H@[hbQQ_q JH0ą0 YF@J4bF,T0҃Q0p 1J0&{]Rx0̄$X8߅Ϯ;2l+CTw64"J(gXb^(B%gjM/v7=6{Ʊ Z˚b_nYccVIxų5@`(dq(`|cXjTnehVb@apdHr,U`hxaFhŠ lQ`YLo_F\! ]u38\vxUi`q`h!UF J 9=FqZ*PY\}0, vpL`P$,v>!S,nm-)M=| ڦL@wc{j$Ğ͊V[sYIJ.wڀK <⮍a;) @ iD(0P""e3ƣ*!~X:\~782 L۹UaA}dѩ`Do&e$pPM=/oj <-w,]m6U׺=vHj./w/g1wP@S L@4\9X($:(F&# ,@(a$&jvFP&`KFRp`_XjkMwJ?T~{Q&=&ؾ@tC2}4P&z֔p=s$؉|2?72w1U̾=oXZ pS4m鍪*fM1ZgZ@'` ")fG'd 1*¶L i b-teE!ƀ…exc R*7a?卽[+cLƃ\z\j^ɍT"oO)/oOO7&k_m;V.e\ܓ ]8 Nbt KBdpyF Cx^Fʈ2]cH `5P0 HD`P7O$@MS]gb^>ƳsY_u3F™y7}YO6?ߝ>u~ĕXqMƳq1bߞg V u22#';AD%W2mfM̽@4xE,@³p D#DE C=4i8SMlhQwdM(-VWi)%X>i3[a[=־#Xcx6vq=={kHkrEͽ/Gi-Lj__;PƒDC#F|0e<0AT<,;AGQC (P!zc>}HI_.@kUZFObOVȣrYFjtrǍcf$4ݽ}5yk]:;jSn6kJҘ׭u>ǐDԨbX&i}9f?&2eP(`>apdbEcL02s2S0RmgFX c(US0m*fM̽g &7gY.YLdO4yzJ!kX8'^\f/!7R,q !v분F. +Yw8bWsb#V%ξλkP+Oć Ni7.#P50`9F]A !s0L,0% Lx*S2qCI} L vLT``a flBAA"-W}M%Aɔ 'kLhDkt.+`X%ơXS $i"&no?dM2[( 5ܳM}`}UXaƉW)"ϋS?w<ꖁ]E9499xdc `)cs#O(nmVݽ' AfO(N`H^*b F#*) Rl kĈa+QU>{7Rrd YPdXsn3r 8Pg634eo_MW:}e75WŬڛ[aZZ6H084`0(ԹC5 :( L`PbH ٖ *+Qizu$Z (#q'1ȑ%?AAZΣ'XS^02WR ̐ÖZg3RG  5*x;{b~Lm IHf޺.b,J~ )J[,DLhXԐDÄ= &He V" 1bo;p.ac@d@1e= LWSq:!&%#HƕBoyeTр[s[~XgI&N] ["M՘þ)F@ aDZƗ( 6"@C B#6£Xѽ4 hÓ0OtA0?,nimΥͭL8@LaK'1x B&Lo3k߉/Lko̽Th0&Ӆ`L0P5IFȠ4+r #H,$ "hi b0@k!a/0eH{*$ lɅK{;Fǧgrk4qw<A61Ojuˤ"ӗ@X Zcyѫ40@`& ä!fxjY 8bjjdT)89S@( &uD2fD,`i58$˗ZIV6BCWX6OLXoKG3< ɜտ36I(VϿ AR\?dAd&$><1e6t1B 4QxڕyfyU^r՞q̢)R 6]SJo{EޢBuX0 FSf3taᇧ&S ɛl`[bjjGf B9!2!X pl(D$0jF4G$jRGCnE l?͗ 'G1mu6gݵi^di=>l.M|U\A.&pu5;玂@a)&)2HC}G. E1¢ 0.33@'ə@`HdġFc`s # 1Ŭ$0P0!Ⱙ]rP[ %#$nmԤ$ͽuGk lP4r +ݪ'=q^;%4gt?m&mкGѪ58fZ915ͳ"`CF=(fJ  "g8hŠr x تiBFs6BЈcb ' @חqLDC/NF|jI  !"x Hwe$A, .4%ƋLkizn>G[AuOrE)v9 B^`@OY&IX B4aqeƀNpF"atLo"C<Lx*"cB pAB. WG95+j"q#$nmdͽԋmh,Z^aW3?r7p}kkfX#IW9b׏&,ް ܺX43و] dI bcC  T4d bS/@ jT`:Fb@#:@>;]LP]Fj-P.:QF-(W>{"ST GOʇRĽcef.:ݯu*oS?vFykKè1"=ķ3s@ AoHbAba" Ec  Bl;q 5P9THMf>DMd ZڛV/1Ha aI(&lHTD 0ɟXHLxhKd 1Fbf^"X,Ѐ(2TDy Í3r( j;БN d[I,UqK0Y4.{`'NITƾ&nLgǯ+[=Lfs>'/Ŧt~ A8q!  D3 "#RbQę c*@oeAeT!,8 ʄ  %f9yPЌ'Z!JfJTD$ s# V'v8]o"no $$ͽupeUevf47H.DEn> <#ֵ-&ti~>s?ߞN[L1=ktj4YTdi4| 42(S+ݡ3|T2d Q3a֜!=<0Q1W!d8 t #fP X37U{00ty&| 븨<jdoG(:'>q;,:]Tί5Z?Wu-W~z[[zSo;6q7R#,946RH!鋦i1`ad _EʆL&g /`,% 1hhxcb@G f0 ƌ a@ TH¨ 1"nm9#tHGRuCX k$!~lI4a)M%ԱEC{!(n7wQO-/^of z/q5oXq&t >Þ)_޸0hՅ L%o9-B p*e4g ]HfFS ,vNUn &Z6VB0 N*H$HS&@I''E72v#H?ktU ,gc_`#w WfڹkզNW.5KRR/cSVM"y:2A<**a&$ e$Ki&d9*鯭ř  @H\ hŌX@##4LHRFE!Nm$dMͽ?P t2'Pb~K":S4/H5!lc_tNŒu$(7ۼOܺ`aP#{? &e&c4F*%$`Y "Np |O0gstF U`FJ `f{a 8J2<>TՀ@Oh}M=qo)vҠ(qý>cyH+ i޻b'rYw3:Z{w(6ftjЯb"03'L?0y0*1 R2( Ƈ$cBCY]3 ,tcن`̌LH,hTp,F%$m2 ͽ((:$h:VrؒRIT꘧Ҙ)cW0cKk͍5c>aRc6j@9XͰhvLEӤ="` (:6`A 6 EP:ňLǔШh^vrH0wA&.w-&n/`o# nm t0@#&c Y *+(\8ڌk@cX @)UF=*u7'&R-L9fyU5\Xb:w#߼|:4'qkyh6K__EƷO)CJ Ap0|z1121 )@c baڀf"5$ai-¨@l$R2cp1",팀:j) 5TUNSC儴B,\ИQ@92KųmLjȍk\y)^sn߽a{]ϙʦW1-o:~Z `D۞UUt.^UHađˁ|qr- mcIabe33I(B mvr>~%zhmTBe4c1#!MhXd(񝍣ؑ( 0{U}H6D-6&NQF$9Heڕ&a k8_fMn6& Fީ>_p7}C0bCu$1ªLlaBwT:cBafMh: Mx PX` PTDPH@&bQ/Fps[` u&1ғz1'v0x)<T-[Gp}n1DEŅIq-o}cyؕѥ_8(!fo X"  S2N3π!Nmǣu!DP"tv0 i̓0)(cX AH2 *JQ)S(4!+ T,0a pR8ShQucaM! ҇B1 KNkZd<9M~mͳOZ حCpթEI͹8%{B6mB$L ̨u4b%%1fÜ4 DEdMe:6Qcs1./RGlc 0}+I0d>T&$HLYs( TbF as1/zOZS?YDg) 3}ilܱ涌ӎy@;ݨ A2QɠJ4 LLҐ5#N#MtFAqIa Qۊh(a!D@DFBfbD"ą1@hV2Oa  \̥T:kUA}j,swfj;3קߋk˹umC/iH޳Fq MP6Fq1çU2/y`t4="(7>a``'b-fPzBca$[6s5ha(8 #QJd]KhX^\g),Hty+U9Փ ٓO65'œ91/aVohJP ! CL~B0\x@'uTT2(Rc]1IXy!"m$dMͽB9NJ1<]@͂fNUfS88%:@ ECCJ؉#(l;vq&cHJZpm=& d[KWgYjZģTߚSX V8Ğ5|gW98._T& &VPdh&:vIc&.b?446r `IRa[X!4H@KÌ0 ݴyeC:G6Z"  7Mplhӊg<׵ii5RX6UFrWUw]AZ<Id* +PAץJ \ ئ`l+L$h~NFԥ.o&9^zg,M|@;ŃHflґCR`i0 XѥC"}7<,@'@ÐlsO:W0$C ~g2Y Ad#-کgU4`1F!@!"#@g<9\!4)" Up A:K*y+.$3/F-ڋUiޚ@ŗglfT'3\z)3q1cEk}ZrPg GhSƃ5"Od36C! 00bQM BcQ}͘ʣ#W.j^:IsgwlaIr&4XPb<. 9)j 0H$LA}7K!#;L:$DfgbY33*0J(fS2HO$d'DM̐: J4 :UHX$AKO{L.%,1\UL#)giy9k7۵֕/.f;nGN EcM=#RjZTw$x=Zu @!f# cK"Lp4XX,eК5dbgYOMpF~G&!* @ *LI""+$X"d$QM]%y Eu]vt6Zr]a<䯘kTZD83}}9,o;=|z59nm*CI800 2:90@Т5AAS$3c# n9G3<@ki"I`ć= IU\Lxl# x1HZR i| PEhͽ bT%Z/pJHX E Pi+i>S{8Ovw띑ueV? ɸ/x=#nmcͱk^]$T E,~!MDbaG3`YfB~]BƁs<%Jr/ Q2P>bPP&:lb *^ x`7Dy!0h|LnMe;H2u\z6qng5̽}ܺTǷ7r6GJ=3{_ZSpi_ؠ`ptf3Ln:C4d%[Ŵ4 f`Fa8њ&X@w:(P*x L /2 A )1%aAḢ$U IOSOAį,'Z&9F6ZzzOUKiY2ck,wxsT7u#nq4Matnôr9{7LUbЀBb錫 0C i4].@o5&$Zw5 f'T Ѓ '1+F-bH0UP)S,Ey+#My`Oew+վjCmN(1X^`0m9/@Q 5Ռ$4R O1/30H1%9B$yJ`+LY4Í `rP9"f#D1'DlԹĘd$-Tڐc͙R2a;lG3BW{Zo3sq}Aqo6+z04mH0Xw,`(cDf5`c3T9PLÝN(ŁL}Z($}]}.9nkw竔[z{YW-nUut]Q0 @f8HjzkuaFonh(>ep٘(\kP'D}K\ 5EX`i IBH%`H EìNi!XzHrh"d(2`nx<*ms+ZzlX؆&i^f ݑ@nǀn *#MAt"|Si<`HdV.U H?~RAZvQf%q04,A&fPQ"y@8bQPcp*bܸEQ@ ‰>Q#Sw o,MOSQ]PњeW-*Sl 5&[ag?b-;^7,3̾?2U`NʻtA%Ln!dF>ZN2L pH`hPI <` 4Q8bc%NA@/0@G0q̈4cC;]Nk#gFQg.FJu"4+lf& ZoޫC5dI5"/S:`+\YkgYuz5}K 8׍5)Fj7T(HSɣT5cFkܾc*bb`9ʀ}nmߣ=t #8`0uQ3e@& 8&0 JaRP$Q-!Dx)`zR6EW| 6<*ƴ|c$? ") ^]xIfXC󿯍 .51%Ӆ`:Ulz@XAQ&O1K A*7'8`:0 3 8F`@$t,p1P:(l1 B9JcS @d 7ELG +Q;]+7esur_) 7וsHq gRYh$/zFƟ]ƎP-0%c0S"M1O 20C 1VJ  #dT5NWB H4cs@QkW\eVaA E"bac /a4 `aBB謥ËzY N( !ڍd7 #ƚdf}u! έZKcKUɻO}bxHw$@o?bn~k^=@LL̨9 XY][`T!nm룊$a=ɰ S쌔=1rg]h`f JEEzi@Bȓ@&(VUH`p()A a`;TVJVDa焙&l4Z$[VzPTggZqpR9XP~Xx\=bW/XZYÕow}Df 0 䉐ƁXd@ʐd`0$R"erܐb xbp`TGQzV6Nf<*kCB5& 9Zs܏N1vʞR^e͝4-1جhojO9aI{gRSB-&s-6do @#F1e2588{F%In $#=t-cAy #10 4&mf2˸1)&& qF;@J<_nD Fl`⦢e EP 2..LfvDqtm2b#akK=523=}l"cus7ub.۵]_7H6uz@z- J9l'5<4,e05Zjw.e̵S_[Xks&Ynˤ! ]ﷵY%GqH2871V2&$d#1  LZTM*MaM4O9͎u rG P5hKSOF,3dv\j C@pe9D d OsCR(0aa00D T<@` Z`NPgTx#i5H'e^K3_[/[=cxa}}CF]"WzdR漧`&`cn=6glWFGr`&)eE&S$b/ObRld!ro rZo|bd@a(`aSlpoy`{ђ,&8+ +.U  iO0' V9 A0T0)@O=x!Ib@26 AK<] # 0 .1qaR&:f ѹ (sk Dp> JU-~%2N5/v=CS%*UY.h-Eq64&$h,BZ[KUzөbXՍEvj)| Z0 c/\[3sXS_S׽=/e W/BqZV M"yM?:B))6Q_ aթk_wO"y祏d1]νHq㮿#tePT ԙ;%cEHԓ=_`wEr-H 7|uwBڌqZh^755q:t*lh=ki܀i4r3S[*[mNWYPv yuMY!6$Z@o%)x Ɉp_,drzp%s]wbƩl3m7+&p=P 39N7l4KloO_릷 bVL}t;Puo6KxJpn|  H$CZh\Y| )&Im!߬F-!H1s}ɰ+^ >&{Vy'qoJRy x7]vj>_Y\Ggw]mM +r IJ5#s.wB^3iG& 4_6UiSXk= EL^PƐg` @E\KGq?˱tFigS-79ĔgvU$\ D Iمrgjjo{Uܯ0exYͯ4}Z5YlOp+p^.sO) Lh`3Zr8DB:zAp@d䯚`H`X&cȻQr' x5naɣp^(iŗA*W:nJ"m?EY#7YpwTx|6ͤÎ< }{m{/o)MUtkEF˩\vP JUkRΰ 4 cATcw&6&r KTs+f!L=l@8s_xSHmh=]DCts L pJ HRtyVMN5Q -Y_zS;B0!DAT)V+%s7 Tݮٗ)<멭YOeΐ2@.dmz"Y@X²Z颻(ic@I. rL'zG,ɆHh[Q22f\PR'30(EjX$tI.[lnQ)&ĭʵ=dU4's|9 N1r+¬lno[IVwYۇӪZzvm58ѿRO4O鸧U1i7@"&j KvX`Me I}Eˀ#b0d̞TaSDm)ͼ'H]Z.g.Nꆝ4cqJg9qp\ -RX*U}3=H$6U]c= T>5/6[nel[dLn.=$:~u6UmOf=.]̵Hs"TcrwgY"쾀(5gayi$OM@XK4b­! *9eA FXS^^f IL'q+J^,̑QU>ni) =&IfSqćcL$9PTzqmVUxii/ف||#eîcв7+ uy>l<< 1]f0HߪOԴD#A1M\.Ԝ0 j+lZ*N%zeEg!p0 <.(1ZGF[ S7rjpQꬍ*Z;&`kR;Qi5~6O+ "TןuYՍZP75Eiiu_QS5haYS QL&fF >S\Q@f&&8TRpNjR#DbӗʑNK [7)%cSBm*=XL.eXݞLd {X3o|Wsa*j\}u?pÖ^zJ왣F>X9r'v?5Ļq;U!e)Qxt 4FH2&dE%bå͎hf$$&2vldHck5JSz JBFuCs t]Ub%l+FaKXUƴg7_8a%^V ƃӶrY3w<ڒsĬ '&:c O~P215aQ0QyVhI.6@cL( ,j*ELhFeb(O_e'MyZB˛dXC\lPԋ)cDSBm)=KJx޹=#bj)_Wxaǚ-6. US>ni*=ݓ2F0u+|q hfSDF`GalRȌ2H"ZE4 0hlk8<%G}s6fȥ)3˯VJy Ò6ƵV qW>niΪg1I2ԫ一njFmousdkĆL_pM("kZ8b&K&V& SpQX1 7.* xieN)~+9w)5dt @p ʯ8ɲ>:|p|]pswγˏbu]z1*k\4ۈ+n[HyX/ j$?BH+69d$@؄*wT7)Jv؆2!",L/#1„RL0h<32l"JqX *vZC'>W%C8imiXԱ*q-?g:Ïη%yZ;p-Bw,ZYQ6nm*' =3t^La{zK@M;qE g9f/!L18"2AA@Y+1XYHx*O,+u|0?._3k jߟRwms`ykz]I6߫G ̠*W8g9!ƅh8`đPP@ȉ] M=`*bD_l+ +tDdAhHUAXˡ#RhtwR1%lV %B b&FRu3ȒsJ4JO&sר]> AS4n+*)ThHI:@e7I|$f瞢',Ĩ !Ri, Lc8Xi`H8VGb `&/8gsFW0BBBxdFR fIͯti%Y}8Ͷ[N*͂)BBuщ0))Ym-ɾL|:rBqTK?ק-*ޫZ(tn[Tw|s5?`HA# #0LeДKCE`Hba 436Z @`XR 22[B"y% H`VAzSkoCt ?q(Iہ\ Mav8iSp>dÞک{˽2S6nm=)ݽ_-;M-e>v@!tׯ@^ދga94yVeYh1dRA i`^/@ 7rӑ aи Kv!2((LL2!/!D86$V)*<59+lFSpX#;LBkU,AWp]yX|Wc5Q8ni*ͽ/:ZQ6P/ 9Y_mmyvPGӭ4~tD2d{s18$,e@`,q'} 5PB#בep60KIUpBR{E2q?C}((Uo`e`h#+bYhD=p궕ViZ/$}q9zEԮI^fBLVuxqmu? Y64G?Q#+Ō"5I &0Ve09ᐎa` yrX˲ā Sdd :4LR'DFVQW}ok49!=2]s]cK %Q2niͽjhlFԩOZY̿c5͵5ƴnw]iQF\"%e1Z|‚"`ѠKt Dpbʖwb<ҥU]/v([R* oDC%4bnufaیoOj;x9٨ѣ[)"v"g~;Yu8iy^u<^'q-v]-yf77 ]@ 7EHtǬ_6䃨XZc bȱOa!6f dmO4G&5043. :2T2|C`GlZhTz]%W͆tb#ޤ^/>S]s}g=anE]Y㏷ P d b>;ÙPE$W2.I2fpkaB4M!6pdP %aRhI,Ʒ<&%gKyuKعO0nmY*eݽݷ˯|:<}h^pq~"wU.wR,kMz#ƀgƭfE c@bY00 tք `xDj5e0J `B,0L$Aa \R%%F < ސ |V.aL:;9ɲ?Ql9N݋AN]]>L fJAϛ7sM} ܻvpa^ry|ڑWků8ʧ+ s3OV(V3NLc{`d8f@J"PT*Lqa艐 ƧȅBQ;̛pij2UVh$4F3!U,n K)ݽ_}RTK KrV&KaCV$?󡨦65yG;H|IXͤM唏_z;{h_.ZC)M$ AL_jUݩfqOM&g\ ( ˱o#l~STq1&tz =4a2& lgѳZ eXADI LB 5S<(Hк$f [IS.nm*f=2P8BxRULwضmx3i$fɨrܨsSs"ݕ[e%X՘&kqIҺܘG[PY©]|M|ƫ@`JL1P1OD0ASe #I*@U@E$ pHHŌ4t ?.@'Cx뚇 0FN3q`y$Wʷrvberon3lo;nMe9[qn'+Gۇsz!j 9ӏ#z@苃cc_ Vs&;ճ#.;3R \ Q9n c   ;f/Q(vC幥iz"C )U2nmZ*ݽJ!;b8]:.]yZdIT H+-g!ѴryA9u?-v5ưϗˮown$3I}vNNHnlb֚|]u[j āiOq9!fi` b#NɝZЩ 1 ŋ X8 @TTD(f~A)fD t6S4R*-:jb5ܖAƎe#%jfzW1A9[w}|+Dv'.aRc1/g{OgxZ{V ːZ{k*q>02ɭ9p(jDFS[,+J^MzJouߧӨMnMuo@p( @G7fi6F/-i'4QQ ṔtBELfB "0 t@$@P8 ,<@OQڎU.nmjMͽU0 : !HJU |'˟klNo;6%Zwut<KzLh~ͨ2ϬMӎ-?]2GA1!ꔳD L?|c["84 ܃p@ IlhcC"":ÇD ™2>ApQ7O2niͽÑ`R\Yv !kQhIayN9u5BMi|ȾjDM!>-uf~XzUAEf=5&@W9QUO7oL^e%`Ќ RLE#&"GN=Z$)e3D1 P;T/P(;tzy RbACIuɗm S)PBѥHl$B.Gj;'G*li20/e@x}9uLKFvaz8v Sd@0nD#I ўAɇ"YTC3|&KELQt 0F!uLtx9X!B:H:(p(#GR"IIS4m鍫#*ݽϿQцSC:+bv.ă*SX5T:kRe[˟j1vGλJuuj-==I\ոs}ߴÝ`oU* ML #=K821)<˃b @5l ЎPr0ŧS)-ޱuĊOq 8ele qxg(氨W%;UsiϴjZ+Z'Eo c_^w /MѼiw>Q(e6m)痾XjV; O~7u%侶rU0~4f:X 0ĊSc H3_3%CD;\  @ pa@09oݗܙa NdufڶXrM]eOD{@ p_XPZ%bA\ -2~/ O:ri!Zj%SXan*k1XQP3!qX!eŨAѻ]zDvnd!{ L+k(H` y?'?yh)z65N_X};N&$ )8܃zHڰIqv/v#Gu\f YA3HP#$KߘWosU.ٙz^)!UL`E-;*0Eoʉfe֖FنZW)(n7b-oЩ9tL~דhR ΅2Ђԥ˖ь@JtW{Yo+jv )65Abܫ͈}r$ZخUK{$&QX+1J(t = U[Layi/pG.m͟BJ^[/|~*~Z0nV$ K!#-s}DCH$Xmlrٔ 1"Z1`k?$}֒l]J͔{v}3BNגn/Wh/5nwٯ%b߮[Ķ\b:s$@O%3ˈ-rȠei Ncb= L4d"U x:;,O1T@01~3pq BHAσn8 $ۚ2 Uj@je\@c b Ymn”8f&#cs?戸JbЧ}IU^͜~|i,rH)2(i%h+34_%4Ii0+3A~ CcUFmmꝜ= gt𖪑)bdNvs3kΎERB_ylTRg[>E3[ou-vZ[kbͧ{GΥp+Na0[v@d ;Dͧk+`kۖ`}%s9rKs~0%2,!`j2+r& ᐒ?ӒیW LHfj tx$M; }ǶAt{"]G$ W XA{RSǨL=c껵cTUwcѸg &k0h\=0QңTGQ~+q( :c+9]H/K50<!@jdixX5Én(bU#4b #uA&MEzWNme =_jx  U%+U(ʮM9JEK&k(~1ܛ`{DJ3=%2nY/ 29Hkrʂ 3rjTP=lf˴8HJǾ] 7=iY3@X 0L1b"10#08cNj$(RKQ+(5Yb%(\rTK_;u"ltFҭp$bBh风ƅyP2JSiB?c8J3ʨ"8m%#q!b/7qp*kAf&&Q91@[,Z0D2PaFJ`P -)4QaCHBxU0F49y^~WCW@m鍢ΪM1˖y_òɓ$h#.)&0iJU|\^5 S9Rv.^3L>9P{sN%S}7Za|UJ7s^:[c63 Hx+x2T o BH(Ázp B#7IY&4G,ޥ]2Ce:vغ=jx3saDnhָ[O,<\t͖5D+X-t\]]BFNkP#Vrc&7V]%4ڢ4NLlz 7: f B 9>RGB!&i+.JDd6u2Lv/) bһQB*W>mM1 ƈFdj]Iܬ`R*jJ Ic!s&iQPOT哎]"!]X[GSZ `,a\#EaQ*~ 19T@~l4 6 G2uDym{ޫ]Up>c&m!rg&!k@jb}|'NfR!y!'7N!zՑblRCY1>@f!8J˸@>JZÎS_U7򃂍2ဋYo@**9GCDHCkF_J` "p%'FԔt'..xҐZ4.vK( OhR$!Hj-ŕC\m$j w!D\WJme-תͭ1J.2_pׯVVp ɣּJ>r5XU 9a=EO532/&)0Qfvb(&BaaɋEB`J 0dA4ބrnjJo''H<*;^:H "!/Hhǖ?ݑdWDoeB=?Mt\޳? x_=drɞS 9U:m鍢hMDA& #h̜ޙfJ9t@$ \qA&R( $! mɫF,b/lТ0AXu0ʲI.;$tU$"QYKicv/ZIJ-<"#uI hyk@mprJ~Cc,Ӎ. 6?&S~f;S0P%)PM yRb`) (o&>#Pq0CV`N&oT5R:2,.qyZ #Ĥ(Gp~v^BhڮR~nT6`;}+ҧ-3ㅍelx|7X<&^UPgE0:܁MUFmeM1aʓM= Ҵ& S; \`MBjQ BP05,bD 4#h|,qӋı[l%I]7q)- eb{Dh s->I̵P6rGM N)edh<.:Ҝ+>:2FA#UyB4\ L3+#$Lp28`c*&m̱{er9Q"i"^jP :CZ-'Gw:[hdžh?"aqCAmxBcS~:RAƒWF `! Pр ' f.<.ؾE,v2 z{{Mdhh9ZUmǜDžŭ5ܥ|qu ?Y?>V2fıӖ]aܓKǑR|ug<ջL. F 'Z5?&t\o%(Ɏ9U@miͽ @Tp5@ .&lFP dzK K#(1B13.i>@&h$,Á䠄G/ki]WY{'p3&yfѴN:ڹ_`eKvY^xx؟r9{XYॼ9qVy׭ ?W˞n\BQϭW A\Mx2 DPR' Ky (MFůDMDTtTÂ#-Xe҄v$Vv^7o)֦U._R<"Nrf"ƗJ,;SoOnky{gj^ˏT)/PA&9MUɖL  0䊣؀ U.nͽM,a6i#^ ȁR4LpݘDf%c4k@@+Mc4,"c0F3E *i@3ȄV2ʊQVn`o(E>K!AU_ebc;Ǘx̖^;T׏Q%OeGbվ*+Nj 2}I54eOXWP J02vqX A 2Hp # Lh! &eӈұϜ"Hu!T*EgB,/T aA."l#K5`Ȇi}Eg ?IH8 .6+P&{|SSbY ٦UO4_&{]#LߩcFwU΀uU0nm%MͽG筞qa-F&4m"E 1TcQ@\IABK ^30YA p$8T$Dž*< NP$B ChW,! d Rb/ƕ/9,Jr[:JǕ`|1cVL?7Uw*Ԓsڎ|{ko~?3~c/(bɯx/Ֆv '.Rʫj@pPP 's9; P0c3?%LH90;t!Pr!;ԚhxL8 lEQB@,CՂ\\?%RrUp+/B}>JK),~Er#K=h)QDwTŀ U,ns *ͱ1E&zXUq'9U[ cCU]3$3FPt@k@A4~}{v)Bh9^JQP\dҚLX:j<ȉPZ%{)-RoӮcΰ٠zR? ,俬wKn:O棻ܟ|Xϯ5jwarq5r|y [;BKAgRd[^chc,bcDaXbh<%cI@x/aC e>:%A#,66*04 l@@^(+J:6ҽ YǕ=bo+ EU.n aI ;p5i0~nR1 6y*jݡԯ_[leԣΚw8'ݐޔ)s Sqlgo 62?{N&LGV k.sXz4%jf]`25+&'k,BsA;ܣi٥a ʡYr +Aƭrj9vo L8R3)mY:;(4u٥az#uhٔU_U^BY, U%pz@LHT>dA&6$u0Cc.A&"Op <DYV$]լ(DUz([A68wqzYv?\2iH]"[ 1b]5U>meܪ1KYn;bۮ4' Fi 6ǾO܏rUBev)13M.Y ƦƱH'`k>;fx΍y<$͇<64&/S 3SEeMW gZCi-ZF!#-& @hn9Yd.B5<CAA&D`M2N8,zT 9e֚'|*"rm^UD_V-IFP}Rc)fcPfTf<ИLa&.8Hf/" 2V"t(2 8`fW% *:hl/93lNTfWFma* ͱJcJRG&q5Jnڮl~]HZt.v JLO3'z6m5CRL7˭wPtut] ; r6N1 ࡓc"^)d(uUX%YhT? Eɓ8|[>頛arS 8YACZ__b;`UA.ce6ZWtqaB[H>6fcɹ{#z@]HPg&()1 &FJN(Ac7ؘu'R~*j\&?:"69ѾBeGR—G9^ײqױ K}fpJdJU@me*獽1l:0ϰ^tЮϖ BO≋d0Uaي&(`#]0X*n+Ql  R)MCV|R҄H곿U7E*n:r qbѧQ҄Γ+|d&cIrrxs#_0EhA- \mٓ޷ruϿ=O0Js+Z4D ȳS6 F4!c I"`bSXCB1H&)$(`@H($@0HYL2P0XX660U*U"iKy%Bɑy&)'8 W>FA qS3zqi^/н1뮗-@^otU6na=e18jXk-]fC);?/@C[QW/ >2x8ϲ!j4,002@a \a  @G0!hqȩ[ p^00UUb1m!i lFEE66$ܢ/M~y/. ZmyTCw؂1m,L[on~3[Lwj+K@7PeM; f59"a&K` p$e SKJ(H.`,֒}s%D bK5{ q_TM`ɶ8j=7qn[?ޯ9Yih},ٔr&g(ՑkOBЊS.nmM1I,ӱ+Y)5șf QD[A&`Z SfdP"5 %5H@q3m_``рT8`hdŁJPaH7yy"UGI'U3:5idVCC ia b #GK /L'ېE/2[ML.NkJ),ԈLȏ!l*D߃CxŒU&"]rd(D*ݖ fD Gr=5RܼI1l +$W7A S4#k6C[ 94j߃O2`~ TbcjJ^%A 0Te4p\/ @\aˆµʥhi%S4m퍪H210l7%:s03@C#A@br!VʁG$S(O<ܘ[0uP7Dd{I*VZe}Bۻxar&;(;xݱu93?gMr[bNTYk)D}G{+8>U Aٔp?H]1ؘSpA: yъԊPb_(1 U?9&7:3&%9 eQq y1p~`P.~ *fTNAfT;,T  #sH..C A- c)i!`%cW*u&eC=  ` &  Al"d?%8J"h@4CK + *uYZxrfؗt+P?K a驙JY ISUe;z ]TD5H\w)Kts:H?pW)Q5YMF9O~S0HDbmmRG^ݚ 캰&<+M-H>V*&̩(( um/Z!I*:JȕUZf_ԝY=BfVhD vMH_cֱK]wK<fKN aJ[ L؂;(>jK9UWu2<*)pmPݚ&ʭlie> VFF~ ZC->ߕ*_6mHBA+YĴMX𜫣މ0]|{l*SM)Y H^M87陣SxJ嘦ݿ,}'|Z7fخP㓆DZt_N #! 6[ :{l`~pț5bX, ^._nOnc|ZxΐR:+ET@bxiS;Ul|X0T0Jh|Н>Y~[E[X8Myfz \^sU =b/e= (MX&V 0Sj }blDLqW_L፲u]|C: x\{|߱1>?yo[_/PN좖?JzBA$Wae e*9*1 TIcC>#" pRĄE9mԖyBRU"' =0*bםQ8Y${ۏUۿuԒI#c6a=VYǤ͆.LH7~\*EQag hj9dX;d]ϩ% }mS Ou%6T`rN=CliO:_@x(F 89A!u=B d|n%䄏B]GpOD8٦¶>А82@"Y-^;w#/ M 7L=Γ +\V>sr ^SVNg -H}WXͼG+&^@P+LŋeY)# n&\ EEN *TsT+E~d5̪c[$n Nsݭ1̓5M_=!a>y飮w;-&Y/$Ny֝-jE/BdJSHĐL7\XL* NgcB J.$kfqJ(L8iV0p61 P[R PRFJp:ʉ!b4XS'*AɐLuo7$W u-ğ2'>4y+F%O^d{+Ƌf? ç5 M$zw\ca&Y&ƀWFm*=\8<#:ѕbd:c`3Q E$RRi@6%LU\Dj;/Hj$Ң-Ym#ky14o1h1:[{ZO7uϦg=Shؓ~yjp=]!:jSbZx;֯ T8`AsWFniM=B01T4,IIV I`0A(m@!EQmL:8BP1oQO z}G`%hx+hIKDLrZË<^X[6I7>gݟGz8 ȚmvrjXNsM(afh!s%3qƘiה8"BP$CH̸W@ni ͽv,PfSZ"jla̝(抢D  Q`hbO"Q`nXgfB vL*i{{&mIUJi9r4S\; {̊X:"{Hz}疚[s#܋xav?J@ږhDHb ٔ chyfpL… >w ZLN0s]!0po=_0R>'M1ljȌa]B&mt~DVoh{W}iXix.I&wGW}jim]kM_-y6J}@"H3 UZa桔`aQ$pBE \@&~\iUBniͽ`ɰL, @x.*BJ23 T$<  -}h]_5{f>"6^~f0@N$Ůt<k#wi?:ʗksOMv0wWM=gxig»I.C gb9d+3-GLb0`~dj)Ra @,T0413 ,3N,PF\2ZBAf 1*z`)UtOTɦ"Vq3&?u򸯼 ez_vlO;#y1&}my˥zRn Fw/ls1XL:U a!l!9XlH`=W@nm;*MͽHD>D"呔A$9$0YCX",P3` E&8?n5uȥޚj:|Y4gX挖|z_G[R3~]L{nL0M&哵g+TLcbUXJIn=JX``,s:= B ;"]L&B&2&$@d>P:<1T2nB@L &9@pB FڢF!˘"tgr;tP 5*$mi_Z]ڶx!OJ,F[}I7ؾ'ӎ*+NH}2F۟{QsP Sc&^1dѣc҂ $`-)S>ni:MͽqҠHM n̗@[2_:%@fz->(\ e3c2waE :Fc Jpx"54؍evX&#uv>>g{Gqܛmc=kN%HujwY#!$feiAc. U هR@ _DbɅ! >DA!|1p6|B0J U>o-iMwyf{\s7~PDs;̊3R9-@@ hAU>niMͽT ، LR*႕4@S!0TcT3<~`В@d0!$L)a Llp![ۺwW{A>69!{8\f=M|K' zۖ'\Z_poqoo.U'kr2,ݭޔ\+@ , xu^A0_!t0o a kycx$AC2'e fbȀ Yh3D: XQPAX!w}\WM WR1 ]HٝR&_m@}֔| Î>T]&9**}5SfTsc{鹹60?7']fYbnzW{PLրW8nmxa %rL2p׃Q28nD߃;XXfX bw`&"\%_&" Iݔp1DAAaV &P iZ̪%'{dfg K4tuMq?›0oWkQbM_./]3+ێv姵L3jV@D|p008182])  L ~"͘0Gi )0s$tFDQaD@_ Ch4aـhא'$:5 S{z`roMseF ?>p7eR@]vȷc]7~/_Mߗw7b8rW.JwР;ŀ}U/z}~Z]#l ;#uj/A Plcq`8HcysKWkp?aObWTǀW8nmz=,?fS H-hhzNs.3DhC V)0hX@i b f\n"XqRZ>;EBpٵ& F- " " ʂI3=p45OA@1$ "_dt]K3i;NP?/g2Z,KJm*)2qYAj&Q:r1ΒE$+R52jT1`Ɋf5Tcbf 'ǀE(>g0< fGWLS cל0Պ-(=rT$!]1`-09qBcFx$Š#i1~!&Ào,v2R"`P=7c2 U6nr-.fAOKS;Y(KF䴪GVTd:Э0}0x 9`B 1S  MT&)`GYQp4i!@ b(iFLBQJOB3.y~8tx e,.k뚦8h{z=paO&E;o#w,ɿo7HOXFGԏzjGg Y0zB3<1[VD548!p)"ņ ·&r&+lݔ `ˠfH-&*u`0z[]Jtsah@reHԖFڒ15 Z`]_ UV*ɕZS:nm4ͽ'}maѥ"W;߬{6+sU 7&ѭ(fXbP `(iR<4 '}}ߓ&aQglJ5»M;`ow{ ]"r 8`*1@5 !R1 XB&h$(ue >eVHX R?P;;JRFʎqSmr*@\$7!G_k)J3u^7*c|~'^1GrY1U3j)| '^Ldi Bk1z2?Uavq$ H*E`K.qzLH,L$J` fǬB]p8 `+?9+\ b@=2R$=C LW8nmQ}1([@c8-%@=,E\Ta:Zq匶ȹQ>UɇQ"EMh}Gu~h<8.f F)vd4BKD@"X@s`PQ<22m nD:w̴")#˖|b@@U%x~[.}TOۮ{BlY i 5Eloo8Z[4\^>GO%-6j~Wmc5"l7*Z?vPYGw'b{oV%ks j* G?hA&LAQv9M@H3-"<\N"DP)(aa,[AU.n 3M=*jd G`D lTp DJe3[fnRn:6. .ˮ,`iK7TթY'{?kͪ N1\ ˈi|`& d c9GD1gQ!5208C)DBҐ|`4J$)y%Dg~b^_f9"{J3:_-=M.7?es]FOv֞ROY]eUVfc1Sիg6O8 o  I@ PlА؄ 30=p$":bX"8F<@1YW4nmݽ/%V:eL;h!:ՅSx^UQ9xŭrZN: 4uw*L876&p|ש%Ù"RIP/h؍t /"&H<,0% }fL}TTop2A@'ڇ|mPv|sƶwIg<"QU7Yλɾ䏸˯l 7Mm:F?eo]ypuu&_bpmNkZCd^흮{~ &0FD<  IVᡚP*(5,%x$bטbKedu`#RԳk_/@"TF%+:}.u5] 1c:/0q p4= 8S$`.*c̑`L4|(`4GU.n*N`Z<-KwZ7srYbHP->b?nԱ[>|+\<_jY)r;)uv$y}E߹K9vqnQ1){rrTf:@s|] F7 Bra L' h'@^LfFLę̙l͓\ͱ~MQ Y!%qɗIAHEsC9I@qa`f c"ahi,q,10!00`217" /l)=$ `*9 ABySQ eh䏘@ixY *ITygR$o9P< bEA-s>oai3*9ހ|*뫳<[P Zr9%)h [ɧ90Tu ޵?zCIZ R(b@z_eLciLj%.}fa3Eд jtb6]5OiGmJ݌-czm p9x9o44Da ^[%YzR6 Xv7Z_T _>дZ7.mTWIby s_ܙq@KBv.PƩY XziYxv6M&!Xc/b b\ F,m @@& nbT5>߻ej]{*Amg?94՟g@`J%ޱ!1؋cAi#2!  i.NAxnj♒TZ^ 8ql,&{`<ș_MƦP0 K Sq*YTx~VLVu&ԘW9"5kWJUb=S]=)ؠ0D^DAf t V ɒO2ZSTKգmsXqX&jAbW"vknTyYgu-P_pʑ7fćlR&r$͗<=F9>&ݽ).M;v}揶ǮJ]L37 JpL HK,x4A5 A,"ϬЌ0XqPy K!řN^>z~j?3 02 ܚڨ[Sƒe5HƚsaR{F|3i9„ܮ 7I=i𶭉gKkސmrP-"c`V z(l$YawZ 8V Efxq֘HN ~UP꟯vr |+yqWZa*M=QJf5մ2[3qbMaݼul\ٷoPeݼ M7y`B(];DU#Gm[aUU<&(р@d0d`P@AGi% { Q8-s>dU$ y/yÅ cMZ\~"aɂmIYNB+_?mwagw̸L;r/qLe]|MG]ur+]5(OQB$\ADpMQрr9 Ss; 3[;wkdvk*u;+[eP:HP cX[έ&A3Bb ,Y+aj. J1 I( ׆#j$xv2jYUΩM Yi,ҤmXb~aAnh)"Mn`Y ҥYP\fj3UW#n-,Enȕֶu{ H =S@mܪ鍬ݥp#Hl2˶e犳PUTE*/ΓT45c1CF:t!0 IC̍HXYzZdv0Z[RPh,jÆI.l5t\$R/Ar!SLy/#cj`0SPce8&דZKK<\o1EfnZq'Le`_R {7j')-n:Nh9>t ?y S`A(_a >, LY(0SϢ@Z$36%ZWf* (U1аQsWE*g fH ӣeE0Ue-Sib?8˿ K0:1⌗R\Ԛc WBm鍣'ͽ19Dfq?yk^8 Z%qE\Tp DB$h@ 1Q 1 u˪S+rR Rr\~u T_P~;Cְ|S#ʎAB=a+ ē[VJe R l\ydH8LX8`ZA88;bl 2hQD&<)54Ot*K.ѫD-;Ze2Km퍣*ͼ&5clg>536 3Jtނ# .8X+0(!Q?b`SP` p1qDh`Q-e[0#J" &UVR1 "rXym-'Eˋtw^HePPGQ2{iK1;C9SnaU CuE\^&Ju|IU9w?#yq~p7pܚۖK5Gt€W6ni*獽=@RB܂0&04ơ0iĂϜ0F'NKP% "J@DZq\RĵA M.b% }#4q-ҠZlcEcoHtiʶ349lń𴕽Z$bH^55uG-NQW fR"es$φb%Fٟ-tYfj/#69H>dSI"fctk#B#1!aPp@ad&"LDqh4& . M P$Sv&bnA:UroJ#o`[:z3orn֑6T^_f,{znilO>[P [;̛Ʊyq^uv nsyW8nmM=q{{uL: sᦿ 8p$`KC @p7q\jq40kbӕ h!4KًyM"Mx*6rͳA(3%qiE__T\XƦs+}J*me8ТK[%;wN1Z>t:TKLUΒY6@ n#9`x \'(Ty"xHu@0ZZ~9Ydi̩7 t8).ǡu x*]= CS/oC @wQ!^/B?e<3F]\7U9Ku݆ab؎Mm6qD@aO~x1&2<\ϏC#EV"IL`@WBmM @amm0㈟K{1@DHQE2EJb'~#ˌ;4d,FZ[&ojF Bvg(궶boHw~3Ͱw_m;.k_:ul=}Ǯ>(<"0әL3"pj#`EG&2C(QǕ00&B풘Q M\ȀD 'c(?MYRaw=lӧ'uܟB:42²E2Mf[#{KϫoNvDw~ gm> ]kg'Ke٬6} F0pL)~s?`B0tՀS8ni;ͽ.? Ȃ#r7$ 2Yb< @ỳPy&<(Xa@J@KTB-b*GaW֏f$[E)syGH ˒%;NBRsXn/tq+ٛQ9${6oJ޿jI}Yjj͝@x(oV9JHXo.xAb/` ta0F >L`Bg5`!JuOdJ: ::V  fƒ@GZC4L/Ӻ5B 8Ά 6cM>Ml|:)Lyuo{nLwIzˬ:oy6gΩ?<US9;sx˶Wcf%w~ `73GW4nml ͽo6P1|5vA4@ffB @! /DSh1A l=P6;rL K \d!Bf&:)+&#ie!%)BA%JR"CFD69VE{۶aNȮUWa}u>^+g+,l_l6ܩӵeY.k3We`J{*a(jul̓rO >)t3K#0 *$p ɚf釉' ##L0Le(@8~a@L,aб"0.0HxS-`1(='(,6טwhSF<.-؁bRտx[ɀS,n % aj1b3M `ϙKj#IԿK ;~v3Z.g&b[r[ֲ3_e7!嫗bIխ8ͻ?=R}+ δ `2$:00.  TdU ! ȠʹTTК%b3pJG` 5 j*fL )&-h\ƈF*4 %.g]P-,A:>.yuÓ\ BܷUs`>+?0wn]k1kN[c~^nM}!gZ#ݲͰ[,"|a]8Wy0\ǧsXK0@+IBs%-Bj =,HM vǗWBm፲*荬1 ~ B`]Wz>2(+˺ЀSr8ĒLQd ɀPdxH 0>#R5)-MgX ΝhBLazS7S*03MtW~R72B؜D<ܭ1Y/I"J8VG?hx'".$מE<1%ƠPT> |F{A/ sL0BP''*$ JJLR8R>)ƄP2DaZ4#؊>.xo5MI񺼌H_dCᵀW@m፲*獽1{p` "BG0`haX>i0n`Xcv!& Ō\|| tB8T @HP.R$`h AH&6ANL. iτLሀFC1`؀8d%S.rD)jEV%nR-G۩3ji\WkKcԑV+h6:zs;דr@a8Tl(bVcQedTuaNT 'L#MA  CP dE/4R! Ap_116/`m0yc(1((8/Ɔ@@@[ba ΐ$窕^1*+ɬ7 Zk<yj;W.nҫ% =l˕Km.0'IךlcW9;ص_IZpJ*Z!&(+2 M]M1V#TH:Xoomw4%cJכR8U~ٸ<vg6īZ,c]LA~oyhk@xO1TFv2`0t!"i:(ČPP-0-HP WAM`[D`  H4Qi̹kUY Ʉ6!"Fh"|*.t+סҪImIk W@m M1/lgyaDfu(AW(ז/ťSj:J\l0ʅ)VbP ԒPH"b )xt60A/@rALl 7\0$Ȫ:< ƒƆLL$C`2b2u!ACcdlD f ѦZ&gC ErAh䛘f؛1xrGO>+%X})칝&\ybL:yc^tudsg%R7իG*1q)40q4\2 ,^Oa" ёacL6*(;70X6.ӎ#V5*޻-H 1fb<=Z#;(w]QQ kTU.n*gM<2쪑NJQ@WCkvj2NKF(V<&hL6BSM0e Y@BC 8hJ@@'fea4XZPQ$UEXcqՙ˸6u&QmL3 %搷O(13٢+8VTEU^Qתei$oofUWe.4Rh %8ɂtM%Yr QE}Uʩc@:t*%JwqH=Ҟμ5!8i?0m@>enEz9}&RJ?%MhVkI2]ό^u ]qi˸[}1<ǤW>mM=ϫnY%>fS9XҜ,K0@\ħc7@ kx$ZdĘ$( @̌‚a@_!قL, P~#j88I +eAmua=b n#UJ;]ݽ.q})w t.U5rְ9W4lSbB3C1iD-W>m 11`(2,ba x~HyX 8Hq4F` QV51E &ÊCM1vGZLethJ~~YHq~0ۥDEfvTlR}phkض#vUmc\!BR<Y$ W{m\#ֱK-ؖ-x/Y`qp kpI` VD !e{u$4 ~Z5JcBcI%B((ecWt`됷6IycK/4tfxiF)'igG<;I0w_Y凞\ڭv'Ş}b{m].PPTpN.!̀W.ni *f =Q!`(3T&  "h'0 $\|rj@@4PȁL X[5>hjE\ѳ[|a#bޟNJA_d߄z\Q9d2f2̌K^6kzjӏavjno;mq1+\=űs {}ӵMz#]@p0P$hs,@ Td %P;${(S5 ji~@GhسiqqIE0dӸ2& ]62UO/Sq sb>zZ>\x8}=5er=Úu"q/&VU (ei9F"au΀Y,n*f ͱS9L8JL`d4# TB"-:G"6<E8~G8lKNHi)4`/@ [||- "3Q N7C2"\%ś-ם37RlK)_l޼191Xx۵VN) 5d&/T$b&  ap/xEdN KšN4*p!M5O͘+dduf0[B!?},1F[ ȟCD=mG t*؉yR%ܵEw`9a/gQKW}l;󶲍[.)ZF),Sh䎥!pPRP rX0dgJGS4ni*fM1IX+Ҳv/KV[;X"}zg+. Sq=e|^14@nvvcyFdUJM) ]pqenM)'~>rxT15ꮥ\°Ues {@\7SVILf&0ₒA}!3aL,x ŵHu Yh;4D֒4=TJJAkQ7Ƴibs˖'iRm3jVd7HlGY)::Drݨ.)-#.'b3QǛkHf5] \4KD;,pS( BY8 dD4H *(*؀W:mM=-GR , ZBDkj$1VI("(&-큲)0]jS{1IejW1)+qgųb! 7 dp1)e":f@0(Vt (W!$fzFX 8ph  j$ x!@Lx (e+K)R;P5mMC(Z<ެsc dZdlkOl, j8O-(eeNmyuf-zݴ|M]heHQ@XPA U!#at 0KftϤģR4?QP#J5aRJ 4I+-Cɖӣ/M]^i foEyzz)qOֲƶf 3%N0 0Â0TH.%*8*U 2D If600tOcJˊHFS30 I|!j[PˌD^ *W.nie1 Z(9v;Ox}W<ı}yVeeR/Tz~Bmk=3[BN_ Hou: utLX) " 11O'0=3B3L0dP ,k( ` b@KPrrз@Vq^èNX>4b"_EI!C6IV:7|ⷱg`?1NYF5QO6D j^zs& M14'V6E 2X% J 2"!` OfDL4,Y`#ʐȬE3O52X-ԁ}߇F` E4ĭ"'jǯAS0ni*1׌Ͼdε@1?|q>.x-r|kr[T a!yuf< zD9<Q3Q(0U: 0{M9JPrd!@bV `H@8Hs ;,A,& ;Ax|۪)[B_IU,?2q.MNa.ZwEKw Yw"j3t:L}LM?ffcaTTF (0hrї@R yw %&p@a2EJ06e0PnT4,gѺpO1K*n&MͱP1U'SlI>$+qYc1*Y:P:L_{.k1tefLV1QhqP0^--q : DlS 49"^~Ai$ AE-RJcSF3bheyNN#." ȐƿxLDfVbQLN=*-ùe0rę |׵pWt~֐X$?hlL»MD Pʄ6sf@a)TvBYLɢ`  3!cOI2I !7$Pxb**b5h":5Rht0GY(W.ni*-OX+IF<4)ej{n]ㆨ6Յ.[zho,=)v69Nf,!1VBq#q&9`!Y0p&?RVb!@1H&2 !b`t0} Jr'D+ \ya!^],CT"KD+-J 'rm%d#jSV#i{>Lh@jU]UEZdz`^<֮1`hPyL (%* @6 x {,Ȇe6LYohȄ*ʼnaR m}^FZtN>s= QU (C'aaP0Pa`R BKU3$1A#s'`Pp @E  ""`U&n.)dݱ.+4d@}c]cv+N(3-E,BfsyP5 i͒g]I?r=5xG8OtC˿^M]%l @`9Y֘a3F\apT`9 lsgf60 ! &20 00S ŃAXg!^ & !ĆnD@hkR'CvtTt҂9 \mIu.ڟ6cP#+^[$$,.[m^Z5]pBfð*΢ H\!ApH @0jD<G\rؘCeY00qFAc "O(n% ͽO& BQj ƥe *Vco$n$eP )1NDVߓ*^B[5\z}cU4˳~#9.`*Ǎ N8B0X=8k[ zT`$&f!DġPDArf YTp?c$>1D8(<(" j3a&g]8p /X+3eՒZ q_uꏏ}igX͹r-Sݯ; {Ƭ,y N?um ]^`H<`j@D0:e$ 0/@> U2OہP GJ;fh!$]P#%4LA&vdB "{IƧV$8 8M.',ni=[jJײn(v~K\MyQrM%XȊ=ô5ލ\]F?"v^pkaQπ!0Pa ±q  TEl2ܓ4LB ^%ef)I0a`yL) }]c{_㚝`,!;R*$q-Q ]x(T5&c}]~&qQ1+x¤7!5PZ%ȌVqD^8gȆH5`tX < C@ K ` !M@ dsт 'Ѕ>c8옑Һ,2gkCqu";II(n鍪ѤeM1! :9^0e)6R<6/ +*hKkV}ֲT#]2ϛaF!H  Gm  3 <)"* IIiP1KG 0HN0eLAN4,!cـ8SQu~b`!'TE3Yy±҈y?D,Gv= p1]ҪPTvm?1nub^* 6L8AiL? @@3B˄(L2F &Dy٬,/8q@P7`tz8jL)ܛڃ=\IɸDAū*#*ni) 1rIp9c,҉ ]s1-Ǩnhsj%[~S5 V$E\bm2#q4b >` `礞TҨHf(H!d(QȷU@3!QhH1lpz$tzpMnEh^"+hvjE dts润L8⩳Os1_Hj9B˽uzK'Z9P^8H$%}l@`  $B `@P=&pD̘83xA ]vaEDQqI2V`DQeI˃UZ]prorLi'7O*ni$1J0eoU笊ƹEE}k۬ «˩[LG~=]k­|[·M]s?1r7'U!шABdh|,ѡPT dF"Hs@R  ``x0-3d@p`(DH(ާ9FQw/1vAFGC!҇V={m[mښ0]U2#\OH:u}@e|GV [aE3i*@T@f3f (9s1 6cA`t61;!  Ъi( Q&FLdA ke&C)PfCgDg!(nm$$ݽu/w(NLݽIwz[8" 0MD,CXkU ;*j/zQ7?1"y_1:iu001̏9G@85@P2=80190413ء0|k131`#Dp`k$PlR&J:ml^`F8gf 4aoe`;%0@u〠"-.Gݕ, (\tLc?2N('߃NHDޭ.v)eV_%[ߕ%=pʨk@]uy^;Xܥ+j@/{*@6:۪Ā C0)q(y>BX&Ƌ`9qɈഘ e!"n # 4iPBbi&=piӈdt1@T2FCZ7`F!,LR*w0 ¡s ̘01 @1.fo `݂f8" #B{o>@Ʈ f hVHP,00};@2@-%gb՚`q@ J (`@2LZ-J7 F9*ױ :tNw[9),XoZLeC r =KNg@<ȡn:t61@K g1bNf`3 Ț"&8pؤSRlêM=8Ojk5_iݞcGY)&.R~l}ڕ˽i ]'6Tqausr2t' E0lVt#e*f`0G/~jg7췭lm1Me}\~%:D. \鹣  \Ӈȫ43tVt B4Ύ: g¦8=) lʒU6Nx8BATPavbj!jL(6!@,㧃q0blcd6yT.=(WFmm +(M=ԑeǃ6/Z]fL;gKVm֔H2Oo'0)s)3:EU349R#Sh`XLBXK(v]P@A(0bqىáʋnpO2$t&6*U! T`iՕ覚+rtf&w \tU5xՇ|9LJDž\M&OYhٕ\cj(q4r:A`JɧKb7&G(,HhmCibRCR! ~ Á!QV&B ,0OFD`, 8+#SK/5AhE<3*7Kǵ:1?_e90n-W@m*M1[XIC+L956b%vѩ~_']\>B\YT ႸY˨B`I(u @ F' &`T4fŌȀ4Eo D0 z042P'8q4Vj:Ϝ2ЃPC397ZG=e2!%A !=23m߽sYߝ&̭~56 ~)Z}֕r&`/ ń1ٔ K|ެh~,0c`5TǕ0a 0RQNƛs \a&M[ YF%H_a (-Z}jqNUx!Pw<y7XϷm^z* iz3hgdgl쵻nĸ>m=5WBm鍢* =yln-;.|4ᖲb0]40V$Ix 6 "5!a05D?FXa.@ X QPk2,@$V05nHAڹ1PeJ7{NVeMSX)U1n],6S#;.n%MRevƘͧW@m"ͽl<}4cӺl74f#Z%jD pL%Rh&T`fBB1$ҋzVI㡨!xqQ0LAP̖V33Y-$"0ѫD` J 8Mhe}b.VO%)'ݭ͹ujܕ_w˞ٯ+E`B Rj` yb#̘40]tX4 ! Ce@P(J}DŽuP@>вGiІqy! pA# eܞά 9y=1'MoXwwKyft)Wv:V(F./mc6'Z\CT(-)Y6nm *M=f3wq(o1o=r惙2o#s%0aImd~lE0J7a7۳*6g{_ckeԉLp1M̲j08a PXa< "2BOE08 Ga)6M]F }IE70TvP?ƕ]re ^>gnoV3xmx_S G<4Vyn``DŽָsv,ݸ$0xBڔhw:( H@)"b0)Hkb79A*f0>c3#=]Bd Pea@;VY YZ-}k CMhE L'%b " %՜m򓩀S:m)ͽݯ;K_zݯrW7vjгZ6׽Mxk{UW'ѩ#F0ns: @eEfǦ~U DS@I3aƙ͠\`%Ba!!0Q`(rB2Ҩ-qP TI0 wvӂ%QK錨kMb/dM6%0VmzNӋBz{n?'mrl9cL@V|f\ʃ-PѕK|E|<3]v  pU*;yDk(;%7z$ˉZ "<0X@DX` `@26% u-ZR% ]e":e|OTG fG-H]g!hs%ῼH Y);jZHi*wmW8nm*M=)týƵe$CXIޫ0sU)6갿(NyWDma* 1rM/j)K 7k'$SH ┡ LVz4tƪB#Fgēbpp`DD4y4@$&+ QMS,L(<cPAx=0єx(/@q( `9)q`@)%8  [Y~pҭaN̮.e@ܜ)w<7ԔDuZbG?ŸiK>]bkBk S<¦3ks`CCbpb!2`q4a%1xcC0*S+0TcN!0s,WST,DP X G+Ȉ]_Db.": K,i EBy.(ej.;貀W0nq&*MͱLl'jL,+3)r`fXE'3w_4!&:ӵ+o)/R劥3I# 9Y A x/!.`),ig 6p0A* ĆҀ`\āCH(hQf\eR`)QaLn.jCШ~;Y=4l7*}5Eσ fOiמi\=[sٴ{*燖 ݦͽvm E ᬁ]'YL@5d dtH`0a+10cC8h3d B: fe๞QB L.A"@·0x] u,3VJ78RJ#a8A|F%n%s.'~U4nm*1 mą2G(}w=aBmg}%$N`UӨl)9Hgd缷sO 6]9pp间@)LX)"Ȃ($ 9{Ms ?$$YL b4|\9jIwԲǞq)Kq9F?<;(ؤ.IfG'f3leC-#F=(_#K]3%#>ÊбVª4L^J=Q՛j$1)TC@RªagZ;cDŚRaOjKKRȘZ^  64*%]K;nչ>]c6cz,W?Pjvc4w+5ke1%3,Uպk0ս|GUoKf.#R[˪[C@W>m卲荼=WY;;&u/YQ1B DX05`尠05 F0ĠCJQ8 @%2aq@kȈ<#Q UI\ 7e:PDT$ѵOHs]܀D(P)Bۧ*P'^5dNg ÚH'xKo3C{x8^GkX,5ڎ3ej 0b`x &6>Xj6!L>G:̲z3=\0AQ*%K#ɀ,$߃Y:;XJʧ7)?e4VƁ.s(AI8OdYiqueJY,n_*ͽ3i]ZxM{G}ţndsghVy,Ab#Xԣ:bH,j1!;K)@ 4#ǁ$G¤q$@Ñ g3X#z'cji|}'Xm$;5:bFs O[k\*ã[uwIaR5kqvU ?YI[4DA9.)EKxőyLAG*vZSk1=e<bN4 LKZAURoXY2ni)M6^G 0tO i2QKb)[HM3Qd1]v `Br6b*Pae@Z)12C{J"ȉ| ,->xҺaeRl#܈$bQ]PʶW]0$XQXbd(mpCt臉aLILb[K>OZW`NJ[iYcThV*T& J8`D=0@(AyGe? s(fc a~R=q&i[LGkd`~Miz. XWLͳDIs*p굍׵ 5?Y×Zez;z[-PWUY/<1vW>m卲*ͼrn tq&zȶ ( 23Cu 逊գ&.R`Ŗ1(Q &Т"BwC`p ,1XH^jWz7ߖeJX (Kd"wYYj+96w,TmA}Y%wÓG\2e)B?YHWVBjWRBEW0ni*ͭ1"> D.n75 YdhHt8pQ ,SUUE!#t0m<g,)@yq~a|֞]r=“ &N׺[e6*L,ܓGjԳ>Sx>+IjiLwQJ=}pt-pJJgRFD+b)`J^8نD1} 9$_;a@Z_QkT`>")5Q|OǺl5_`= 3=wB|IiOcnCLQU$';UͪznEg4c` *ɩT>p0$3l2F4c>\F6\L\ $SrpĀW@meŪͼ1@c< ,ʀYHR+AQ ;^ &*JƠS{ԅrg&Uu+riL}؄຅H +zdϗ2&lj5=9rr,i^?ۍmهixv۫Bq\Ʉl64CǏ&) 3 PBG(ƺ* dfLd !(00BC&1`pd %ڐtp1 bC &}ؼ 92$3gP `j ]b7LLӞ@[k$uC5}_$s$k|8vxf,0Ziw{ڣK tl{F Vkrئk'Ɋh2x8:gJW6m`%ͽ$D,ӓL0XE#q,@s8*VQH4 F*g,+roH#+,fZp Q8^Ȁ3@Kgha v5{G̰}ll}=}1 X}ە* %?Y_g{Λ ίΟ]pc,=6D-5E $[Z*7C8y44 H&fL"% -@\XN 3T!R) [,IW( KarXUb!Sӻl>9sx%v#W\tO7?uMSqJe 6?=q/ 0%U*ù#7Ye?p:Nf[T HH;.t፠p2hSL82{ #1@K2a@RAo0@Yqrj0zK$2Pd4#4ɇ}_ya,d롹ibѺ2Ys} p2}#*hͽ=8rj3FLe"K_tue3>X5jq i 5'Nu=+zZf]6E =3>@ PFEREE %s9 "*l1cx]"fP˾AaԖQ'{i=׉eX`qzvhsmK#~fWh'Һ{,T.ljͿ?u,~zEfoarGuZ7lm^Yq/lg^]KomK޻u*U%ow( kF=Ba3G4S nH`,DhhjHhLE)6_TH(:&XOՋӓe-zVnNf4vg:1Vunf;K_bkUyO%pͣ3y+,MKhu[Į? NpSFmǨ b#FF(.j0ˆ$$j |Ae F@8\qjH.ə Kl } Vcp^!Ln+!W*z1NỀy'(B-Y̧J]V+m^"wo#O{ &dgZ\Gpmvu>wm)N TIFd IԠJ1ġ XykDn EqEIQ ;(sm2B|fӂ8UP)<{V&lgqIUFUAޕf~a]ͪYH 0v9˼۬p&~7 KKY-!*< `'Ny.ca1=:g,̐s{6ӹi4!xk,SU3Z8q>2fÉP Bѳ()(@PnpAJK W4`ӗs2(ixy2L[:| @r&9\NXxZUQU:<ٓf_屽q\>eٺlz[NiJ1e^cc]2ၓېIL4$(J@er>gm^cU݇,=рSDni٪ 1F<MR S1~uUoAuuWt$q sU$3Y/]TMkwevkn}RzǕD7LFbZܬݳaߵW v|͝NVP* 冾(JJehIƙa`y1Ԕh EoiC.2# LNv4W`B79~V^~񘘎zœr[,ziғ6ϥ.JEQFvDv}|,QLJ5qb̫.ֱٰ λ!LH<$g1jH'#! ZY Dv4lI`/(QUjZYDZY'i o9SBmͼpngטZՌMSd~VM,oQ)-@PGu{=5K/|f~\_,l<<|ԨgCF`Q@kmj% D+h48#FyM75Ne,i@sL9!?J RHvMuSX8iS>ni M=a6R v-g23 ʰ8Mafp߾u5S~YwSm2/$]Bܽ/d Gv!MOENOv=(}I@ u^e!k,1HarTcҒ+c0&޽UIӼGg}yw<>%er;"$ۑrųd J.@ Ry̐4 FpXɟFx?`S0O qԆ aRtAĄJ 8[ufl+!.=y j8~*)G c* D0-YO:ni:ͽd&LM3U&%kre$r`LY/RH)fͥpsػlVk≡`~ vyNvyd.iٗġ"! L xG zcp,PX Ş@3# LnZ^!d\$8ݣF'7#3Kkp*VG:(s}&'p~~lfMcɽgsm+ض׍ALReϛ$jZV!m횱 •lBxd}xw,s5#Z/5"ٸ|s 0K@5%T&1A%G J6ݢC ιD!/:E+Iɶ"yGaS8ni*gM=r}r|Yll{c1sO; 5R2W fZIӨzN,]_|knZ {$rL!m "o_ƞ1 PX! PM$XiNBL.$H HMi>$$g9v|jD@,= O.VY6(Z΢`:<&Ul89܍w y47/Uny>]{;,e'Tmgip`u{Ϧ Ʊq$+$0f؎b+aذ`L*08 (.|<p@%*(̳P/ >lbC,~(u}*02ruÉK_Q8ni@d 7GC8if.X{B1b< +1V!r03F*3!J7b`eQ6ni)a"C `%(դ_cLII) ʞKI3#M౦ :'N+Em_,/Y٬jϦo/3gԎ^=zkY7ML+oTob} 0)P553A1 :M`3{J4q0 X "49| 8 @(2f `APS Y")R਱|TdÓATZ 4F ڪ+܈*.2^7i>V.`q'r]B~x KD{}ҧ|-;ݩ#{ =3?t{սn7%Qok?]—0 ^SHRGx}wQyP;lp @cm O2n)T E(1 x(4!! k^Q2sL aBL0a>bPdXB\&~: $KQ/?h<\5[#K* b=viI;)6lV)f;>l{v͆𭤱:wrĞ+X%pc%MqW<8sV1L^6<ܣH,a:*  u$$ m@sJGǭv%'#jd,$%AB@&!D6c.uN$0\(-b@ u7ݣclq1vm/hͬǚu#Q\vjzeJus8ۯωu= O I @ l6laE&(TMd t'pӝ|h Se)KciMXeW\+ѷJõMG^vV8ip6.:ޓ ؼM5:=g?j%ɹbjrќܫ4e\1kH˻Aԛ)Ҡ޳ '̚=CġcQx`1Pׁah)(, =0q,2 Ш @ 'j@fF,B0rT2EF#mT 6LSn׾`X+N]e!rő3 #7OJw U׮1PoάoUy:gwW^d{٩g NRRTj,-B<4VoJ@9 yᚲaΙ~̀W4ni*ͽAQ #D!ᑐ> f/^u> \ |TPCD( U !LEhG,BE`ebBw6 ԆcK'a@ha¦hNZďԧWYm˔Z΋t#m}բ{r M{urWuҽ'DD6~f(| c fMAAAEp," U9I!Kb%F0 @dE"ˆLMr6 =`SCb(gGz+|qMڵWɊ7VVmWYbJ7})πU,n D)ݽGS Vv񷺺DԚ?;J$/dfFT{&n^bf :eC2ct@,P5JL)j\t{$Xhm_Vi~V9[;>M-2EZte DGŽ#Y+-߃8tFeZ=(֣es>}RG b/ځjs.v]}KY.mm;)ݽ8եr1܀٫W&fT |w@lIð|вP˒T‘,@YV#)1B,X$ [D,``H2H`!@5q2g];VtɴLNyT>|DXivSX_xi75;jp4pW\l?w|yHfCLW<5?p-_\Rv |bspJnP `pPfid<~n3a`i>e`xL1,U(F@K ?٥)H14߀ |* LFBhcbǮwB."mPP7|&14@֣9˖ݵ)U@wٴ 2a Y`G_p[U*na*Mݽ_Ӟ eޗ.=[[j/7*דLEwMO&M# [fΞiz֥wO/Ï.xQjݕ~Xrɇ;Uߨ]e 2ңj@b]l3p#ST4F Ǘh)[a6QkltR[W6F3 1];V{#ˁ1=V%biՐK:|@[jmgwkEB4w,?Y&w;-9GzPۏ٥ ħe0BT!0 ҚdJ 7þ%t\Ev䮭Xn^޸4 2BۆN} :U!=;S@cQD# BdD0K!i)JLh֓1ó#Ѥxl%1P{i଻yrV!8AY!CS#7*}kg+-;zL:K`GT埂;Kbd2f\!, &Ԧ;&\v0L( ` ]s$pckB̨'W=76qG8옆dž}pl5+^t !dadg!6&XgAʠQ@PˡP 0sBo9"* P)DH< ~c[nKdn,jy)T@INlX$Gj#:|uĵ\mٷ)΋Z˸Ъqf/N2ȷ}fc8b`2 fxaJEpBF(tm퐲k.@p4|&Kѐ⋀W0ni٪M1D57(gV7Ei?`+%GEs3; I tr|=Tws.ۛUU8WY.nqW0g{  &O} k1 & F <ޤ:b`Pr*x>Z2!yHDP<N#@ ѧi)]ZSN |M˦UI6`'`λ[u%?bpGdK=%ѓέmtx,^AYQz9Yazifexd@YGh=:bg`88=!0`&(& 5$ AJlPz7*0GYBa |V=,G.yݵ/l+@I*+S.nm*1#be65=rLcQ-A73ՙԕWՍ!"!$ڛ 1r/9VTK :@C&I#74%Ab48al !Yda)˃d@fxt +0@kV`AR3:&/8S 4qPh>rSixZ!JYDI`"!iɾ*#{y>}F^ʑkN}ܱ|8H{{:]P"SoAfjO 34AM(ePF؜a@e ycwzOt.jcSPO>$hS͕Ԝ)*[PSUW{5U(n*=JVXu;W1]S}bI# h Kjig5Y]"xUz?lN] LySQĦ.LRa1`Pa7`StV Usj,$PFJ0%D&& ӦQP3M̙Arpn%)pvhP0H'Z\P|BhE~wfWyt9x.5v]:a-j+n8q  f* QM ?;LQ J hVhnSP3]3A)C+} 86`@+ BHVC6we| w2zi2# #5ͥ >81\ [dsph:*+6Pu)8dK2,yast&Ozhͻ\jXhZ@ nI B>`Ǔ핖IY7oC_(eo2Õoxb: ]Raaْ(f9@WpPbfPCaqɛ$ 7 xi ;w#p4  /?Ď\Ffb~\H&IuaԍȝW.M]uK]azP+ S4nim*eͽ[˹~l-u >oizp` a Hbc0Eȷ;sfخG yu{A2KOw%ipȀ8ޠ$W2nim= .  ҃ 6Xʁ\ @ dia~"dW$aS qDAjcvbaZ!]EQ$mIXwAPCSm Ǽ+ٔ+b% "/kD=u'NQqXjuwG^u_wa2n_.\v,i>P(wn J 5D|c ' ciAΘ-N! N,0 !yH N_D\-Rq'|ܧ*[f6ۮ2qHq06hBz \CsRJ$̳."U"tE)ܺr,,\ovJ'5ˎν0GxRUJ@2NjƀI(n*f 1e!IS1F :0-7=2@'fl PJ$: P~\c *U 0D^\#ՌT=Jre:o5%ƫMC@\6(A*͌W<+orKl>Ǩf`E&O&(/f> g"fPPz5є`Ʉ#`a`Y]E] AA$DDGJ "d*[ $`/FH_{O]\)h8um6TTB ?E;Ya3U:zSSO+崣c챯A[,.g[s ĩ ƴJFktXː@ǐP±ѡ0AAW.nmӪͭi tfd& X# 60S4A00T4ZƠ4ޙHU -"iA.%U'Y ֓nOWyNC1x0V3 AA(0i1k cnHw Bt* .[| K`2shubdk jD;r='IY1PFE&$+K-gbW0[~SH䥖ՌQ깆7nYG(^MgdxMW+d+|!*'TrYU&NϪe13iEgdqAI`YD()Q"{00|@$-c  (ɋH[eA AcĹ9uH@ܠ'R/:%nW%+6@*(S>`{*U6k{eZhG۟ݷ{ Sגws۩neOIrQgb|ݞߴLm\yM@\2v FBk)VG$(<J IBBANdA" Ux<>eFMhLj]NASe@,)*65&[NikyK{uC@ƤRTʟ_}HッeZ99/_Wݿw>KjjJ7 Wpױ1ڀ5Q"N dd*^_R-wmr\_'cѫ׼LFaL$owjf/ۏq}J`Vz7;q`mPĎa81Sb/ X0<@b7(v@dh(L0>9rh @HT aT/LĝRbL9+D=tc.A`H#z! CI0AnSs9Q+؟R#B'ĆUsE s^bXX ?zl0ܺS*nmΨͱ*٧DO?4B #V E%X S WRHА{ <F0*H4EI%ΐ jO+ܲ18l< jC18F_@rK65b>nYn*֭<] <DM+z+={>]sBcWC # Ga PI#@!D¡y \*x84x:$cGCS1a 1[y/첵yR^WMǝ3_AD5z=g>ƽFbffI~M+ dB8x 6T̂ðr؎Hh BB`9a f8D`f/[D[^xTmbb"Ը A4BmH%Qz H/vEvYQn&j-3 ,%[d%yA:'&dTHM4OL4L-0PӂFPŇg@2f^De"W"BD40ˀS.ni- HUC{Zlt&,9HAZ(0nMb u\P۔ߺҚRmX_]7ҸGSxtE.X5wڇǍ>XN 4L1͡gp$?1ABk^ Ze9(<2|:0P7+%2k=-@FF"$0v_A-*=ȼ֝ AcE@kMd8B"F.u8!;Rq\^d)}m'mAfJ6}Ѻ|^Umu|"baXapXFBTa`" D4% :~8?b@'JSr"2y3*nmĩͭb_dq㸘=da ) ]8(b6S֒'ض xJ鼗e'<ɦ13W18 qZ13TV. 9, ;h7D&Z(t` 03`bL_f8/Ц+ 4 `&!i2kd.Ibձf`ؤ#P&^gK(_(/&ide8_XQj(j*^L>V-uJ8 5ߨʌBm T,(0xa00. : (X9ag.ZJ)(0]ǚ#0@H4!,P'o'ܠZڵ @0!}Н$Y5*nmmM-fP%]5֕<|/a۷zM$ˏn8+>xu/7uZg{kK0!5`i܇SYt d< E3(%FC ?I@;c v*.N@;_1g88% jv988MBI{ȍ.mǯ=2]fo@ @G+(f) mLtq#hjɃD@A)0-6C WcK1) *2:S/ɂ9UIcnnOKyV|dhIS;*niɦͱs\@n (\pV߶)ٮ?[;v+ۣM=I96ɿY9\T=@ @ɚ ņI4# TV L[K0C..Fjq%b6fO(A (E *;Le%?$LזVЏ*ȶM)~v*jsgd^޴g-ƛ@΢Ϳ1(4U 3Cw=w%mUOl b3#D h QM$@$$dC@`(`Ps"Og2)d0WIfTPn a˴J2Ma쭻vCFk0J<-;(nm& =iNkseX»יe5:X|ѾfogBuoizkh8v? K)b&oD0XHgL<ʢh L ,@Y2!82@S[02!҉ Y Pu,lf(^1L0%T= ql z7AC By$m q!u33y [Aeuy#x[6극l6xJ>o͓.=\U 3,301`?08uƉO~8QiQ#ژhxl\,YMt(lw!=A"S,V>V0  `4Ծj N+(nm%ͽ;!&V;6zVz">.M򊿍3gKͺoyjUa 0 ᦃCZ !3]Hn ӄ1 A2R=`4hb 3`uD`<%Z-LvE¿26B`ݜ.Z瞨1uzݞL`kyᅴ'<SuqXY(a[r #bѠ)C|)#0(  --, `f4*KG(niԥe ͽsWRE!@GkHnE;z]nL_? ݫ?.]&3k?Xi?{BC~ xTP#0F L =QK>ϘΆ" C q7"{s @̀+h( !zUY|8 )sj>2¬Zѩz5R5*e1ⴹR8C'J[r;g\1]K䏭h\9HfzBYգ˿|x% YKswPXaw#&Oñ 0D @`gVb+FjHG-Q(!yhAg8XeWY@)VsE B *pV0qcJa0^x uh)*O873}0R?Ej-zғNEv}(Y8Tσeu+S-Zsn'M;]S2+9jXׁhkYj}x+xV}1pÉ3%Ld 1@ d`2Bahd`Gp i` $=4KQu8`șZw%ӕLS`T+c[5"n(=np"ү9.:,WN֎|il|Iq4U-k[MVXV}F һ0>5a>mh?`87EcF9c`pH`j D¯@Z"LP=ȌPi3Y!/h`e# ,8ϙPaU"PVS Hڢ&:Do,HC#c["#:g#e?}_Zy GqpƋTmJ~[9oJiVLA 40Ff%PHqq<0:^ n%,5TL@(#͈$b 0|eIcghĕ$`X46)ƷTE ;&ni.% =?z41Mc]\lϵּ?X^[y>z_,mכP-%䰂p>VX+3j1`W0-3L?"L<Z04 &a˰vMM (ˊȸ,f4T,15g1aP_"u Lhc8q TmawR~4ŎΊ6=5XڻN#uoY#>pDe!0f33 # 0 0` `S^) W CQ@BT 0bg( C%2ȱ3#K!d8&yEFVbvq%"n'Mݽ$Aew'R z;^T+9 "1~Qm3xP4$w7l;37쵒zxsn'o9j;J xo,M2fI`6*]QWn.H3ϣ 3 ÓP(|@`t ĆC <*V4T`P@B0v (\)(:iY&kUӶ3SwjV?Caۈd5[ܵr)g*I'WTg9YW(,ei&3t!ļ;i ʷXUaLA!#plL0 n#0L(/0\#*Д94y0EI' WĪXL ) h;\PxIy/Om3 ݽ1çSSeFeZ%3K3 JPP'GEnƁ{xsLwV|:Ըˇ^u+Crڿ}Tnͼ|nϛXw}wYxjYx*gɃ3+7rY0 ZZ+P6у !BڏH(&K*E G2M5KaiHhI߇W0̊GF"aL͔+ 5bzlA%">R\kSH.ʿ01yj jv)aNئaL=1@1846F&aj̖P5|(8Fd$J,^7T'$nm&ͽT&sn+V^RO!\O徰Ԯ^L){[>兕8&xjbAjy* U,D &(2iF a`` C 'I!$fQ"Ռh#8 A-M0ITE]~6aҌ+H# T1;VHS)eձe#?pV?ˮ.#x.zu-3^M,L0 CtML J@C"Gc &L:XŌ4L#CvPti@i-A)XZ'0HLzzlD(2" Z# nd=nKX{JڔD.ɠp áh&Q*aц'h q4' 8I\2fK;tHl<75$c+nfQ !UD![QbaQݣ91$%134@Q#HHs0 K4Q$P@X0@CV `Hȡ  LAG x{IoJ4("O2YhQV(G;=<.tm.V|bAf.guʴz=Vrl+O\U Pدe5rDң A! L/ L[K AXG 7 f8(0 0@ShR̸(?$ &NN915g 6j&\c#NA$#tG0elitP)\N݁yyMCvn>ܶvGǛ]h >q|+w{3-hՌwh< jL 0L*1&N2x|<eǒk!#dOUQ'"! y?_ ,Q ٩X'Y 7I~XZ 6rZ0A%_]zC%*b7 va, 7|+h,gS{;?ovܖSjSQwhm_9՛В^ljb;9}Bk0`ΣhE!"n W#Itgaɂ(4bVh5 3v0q+ݓ \ F*ҩ_c {C1B :rQL[̯4掴S-~v(`C뗾/no_o^ V.a+9k#Z տh0; ɦv.lAU# +epAv@0TLcqC Q@x-2U@brf *1 ?eBWDGHVluqd {g}z :uط" >O9đp_IXSnuz_;칗jÖ۵WqkfhyytsVa$ bP",?o&uLb yBCXH"dҀ!"no ̦=_~ U6QL5kqA1 -P)Fx\yVI"Y~d*gn)kEӁ2nmPޡ|5CcU)g}Xv!O\e97 _vo-=܏7X5j~z›ϧf9%qaJit2axabd1aHkAHFW4+(4L1h$PX9``CAP9(&!@H/(a CIbpO4J}}8@۶ :onG֓ 9$^yv7'(C?o~O˶;>ԛV?^|Ի=ˀ!N+$# etvripohHӰ|wѱa?<}M<(wBۭM28<TNf  `}[ظqB4E Qk|:(+}hlgr GNLIVul1t$&,䯆+c*GRvXH׸˭.xx!n)]!(ni뢏%M̽tobښ!/ 1``@$ D隂Fؒ.H LgJs ZF~c2` ;-,3T (Ww l]}`u*N׮<AMfʿm}-~fZߴai/|24xsq3ā4R,ۺ+w`(DqE `8`voh@WL  ^L̅ c0Da,ZIF4]06ps.01K2e( haKFnZRʸUd͉&υj Wpz /S!*?k6ic+Vf4֏I+84Z# n4$cݽ\?^ĬB@)`"Ɍ&ff%Ee"@00## R4\$0zuLK^0# H%fs "o[2],CrAdϜ-=T2~j?-7(ywܹ_S'>ݜ!5WP)kR5tG4CQƲ&T1`(+$ L ̄`- A:ՋB"Ex8\5L*<&>``#.6WʄnhR 7g[CUmt@5~B#5%x\LrfZO+glf},+[N˹b 61h`!"nk TcIݽ!ǐ1 -=mK@|`@dp<=`g1(10d3`+4F09F2ن@LЉpB³EfFM0&"q D܉a  LPASE".U` h*"<[yIi>(s*\J(R>J(f42lyccۏ^ ܩC7Ou#vf]|[?M~Q7J֍[ؽU.:8`A،!ƅ~j! HB wW,䞂d 5U!`+ywbâ(vLxPa>ޔAy@0g"ĢCQP`E Sa橘hš0D% ͼg/ș `A!q"&?#\̶PZԂ,=A#m$s! $a&<4TXNt|Uy->NP>/(s5 ~Ϯ}~4U!`J(8$00̆}a9#$niè-BJu l 5aJ :ȗ%n.̡ܼ8Z)kĘSUq?asyRXϴ9sn ^s1z~m9㻳w~,ne\|7x}!b]RKE07N00=a8<+  "ҀdT51P̀jF#;HR醌9( 1  La%}! eT!7u]NX[!JY4Q#=ɸad]2u-ȳe^M.iة3Yßm=z!< ʿuHڴO',HoWM@ʘ jKD*fRXSc>'`f# n%ݽމ.AA鄴Ɛpȕ1a"B1aփMz(hiH oA zj=N)|> Sgٺ0E"ҜC2䵙ee ˸^Usy,4G*ہYV}xRB{2 BWx>ޯ '; b 5 Y*'lAŁˉ !: 4eߛQ9]p!9hJuEDD&GG4`7(qP SN^Nk{G{貹L*i/e泫8xz\:p(kꏵm7Ԁ`XvBdpa x/`4  L+EH0.5k`#N$$ =tbA"/ <X+P4P ZqTBEC4vJaF1TbeN',5gj` iyAyB[_3$ʸ>0\KiuW<6_ΞωsmA6{ĪW!=_ +rU#LI *LI cXPLAR8b`':njC_C#"CThK`ߓf(* QhgӤTBWx(ʡJPr7׬ QKV/l%*ki~z_f]anF7lx.]Vm7jˮCF8ݩJsf@KL dòaR4DیąGA0S2m߀#NcI=qÇ !KDBlXdXL +BI..\]ưK)]ڙgF)1)u]rC";Eo1݊>En]snZ9Ux?2ž|+jᆢ6};_@#'vP;LLG€B ŒŎx <LH $>!^cL4ppi 0pB #Fp ēCϑߠP1ō zpP:78@+@ fAAQ1T`Vv CŰQR#W:bύ:˘۹Yg\ SMQ0}2v#0xGX3JוXLl9̕߀!N l$9W&L:  x &BA PBsa9A@XCGL<W"\CJ,TBR!`^f$4, adեSb8Hҝoi;!?Z5z+ 5ЅJݍjk,e;5Eeqlk&2bW/07K$9mG>PQSkUFRLka,dYs8(b`8"`lcDOE DS, (@;37C ϡБɞˌ9zYR}pA xKs&GqZt{L4n ޓ8?KY+s>>ڒҸJsuw9jӬyd^b  $#N$c=Y4LD8L?¬SPID@^b0|@f礶tƞh$1QS1X2X7.^!GL}"x R]X 8~Jj$tk5v'a& f+i"'n!3.z |gťڧw&v6 CiL{E@GS{ 쫨 Z`{pUD~C 1 <- CL K1p$N0T&f`̿YR0A(lf8c.p1YKd:h=Y#1@0tX1eIFI< jН%E4z=l$$c8x׃ƫ.pM^{]͗xjp|y#omPbݽy<ճr5}+qvU Cjzj'" ` p1N :L5J99ⱀ9 bb<(پ9D"  Ir [0Q8BM鈝DžxUBʠ$ =v(^nN͔yUS\扄N82ֱ tOc7}6ʻ-s+$e*$u_0s9b0 !4(a &0п1 .0@`H9 DlXFP4CDJԎZ\zPQa`5P8iT(! &#N`)$:XOJwj (s7WK峭ļ'MF=rO/pe_CYege#n&o=vYB;W.O|j|&֧滫@,DBgJϫ.mo * &!9L \a c&# RI+-: %0Ꮻ70îZdז/qE$ZiyG?iyn*bL0Ggq }Ø;}5VosR=5[vRg.TQe_}DH4 "cEH36@hkhaHT bāBi9`lf,,mr!50"韮V(Apj$LxN@mN2J=1(q\/FTZ\h(J!N L% ݽYtb=GgϖJYʺ/Knי%[PwW Jm[Fm/8<8QX !# ÊF-@c"#A#4E,ĠcX.B1 8?cd1:a$eC` jk(k,0"HHCo@ꋲw~V&$5΅X ch-4Mn3g_qԛWVMZa}@?Ae8:v({byc`fQa S}{0S5l8`X 03م1ل2hL24Sa@X9gH9r{uD_o`8׶zܾ})| #n@$#Mt-.j1̚7C-q_S Bs,伫EWPdw9?:*O­X8)\9BbVLY JdML#K1E2F7RY976rc =0`0xQ ( g1HP 0J.( 7I&Q[z!w(-T] X-(zݚpmmsK[n`wUed\fmī=]L^֗t|wׁ[cKZ]X=n-zv<"2xcA! po)`JG61YDڰ!yÔJ J C HeBV!#1cL S3)`)U6ܚe^c@l#n$$ =t1E̚ixk_?]15_kcmjpҘoߎ!i!`\Vfc8c`&5dFmQA@@Z $o 8a1a,IXa;ck@qt+@%1!*fLudR ( -R)Ktn9"*;Eu13Φw&>ME^Oϻ۲\ʬWB؏}` R  a~D400O0183~n&j@@0ks*Q'ل1) LML l8((u Js[. T3P@HL).Rg"jL;q#:WWxsmN.PRQ[F?;ZkhMp9Iv+7LcKˬUo ;^p8ZM,X}mW,@icid` ry<‰"'26"@s V5r FT24C1p@(H(K 18e*sGN-@'P$%Y#NcIݽsֹTX'DuqYX|җ)NZ,o3ͣ|5hWMVMGq)>ӞuKk:P紞!UsPP\A (a$TR6JplBc5b1d 8bjI陈 L03coM0 pԺ(fm6F?2Kz κUhgt϶ڳ6w :LXd]I ՚%Tqu8u}]@!`Lr@P,PRAAx`j0qbxLڀ#gneJ.`f"`' 64FEda&$2`J'dsFIK0=R5xm!n$# ݽt !(%<.Z65cfvpwu.hwMj]`8䑝q"!ј4bɂc P4@ـ1@aW-Iw *H D.Օ Nā$,xJA{ MBe yQOi#J;z}i.˿V[C~fP1Z&XV&^6E&B&pƕCifiDb`Jf*,N baLThI{*2GE a(@iX`" ){zB]PƢpS~'Kgg rE|g{! I! niFbᴃ8ϗns)~wqS6v';3g+oV,+) a3;؛UB41=qi4S6 FF+!@Y(`~o">l!U2Je`v &<46ArѠ<Kf=(쪹Ń'< 2M!ѕ4gc͸Z~^RfK+$E3Փ{TRdOZovm]" p$lɔhc‘pÌija ,de'$mn I0@!y%32 @0TJ0@] i(sQtpF"I4H С!h\}TcU}!nmJ$bݽΊAr7m ZU:g\.5`RᲦ8}3X%7w5 ,((thizt7C (4+`#XS$Ńǁe`h*v Ld(~'ScmO 2X׉ZjįxyPttEK^ joN6s~ͩ~3 ld!mth}O(b`WV@ P@J&*q f`pG=\R9@- PW *|V76#^M6 ($LJS{g?.fXtJT q2]5eGlu/ӻe>/:|ǧi!N뢝$M=t:ߍk|k3 sD0LmH"]!$ d F- aYa1*^¨&\0 Q5 coK1a [@R X@0`VG`iL282E@ڊ;rY%"G{skYzSuY̎fN67˸y"Zan -;33y2;l24H11@2h]1t0_2R"sw $x ?FyF KX]Cn `4A$XuZN ]kQLERkT6!DNEmN3;VS3u_Ԯřz&گoz}@3@$sL&3s fv4:k E@Dldd d\< Bڨb*J4 0hY{iQ߶{8PĶ !mO.6L8u'eY'7{v/^{-'ʒr TT!n cͽsӾ Q049 0n2 3q24?2$0`04DKPlf'* JV\b,TIKBAţ"VI!/sC:v!)Wcзڀ )9@6Ɔhw L@ZDhH)OƟ1aNaZ A1|8d"+ Phhp @@)xP,[yI-츴EibJ|tkәBΞyqﻞ3.oOn|Y1!N룰!apn](ܷObfkwXk9˩]ķVѹH""@]s2Lu0H0pѡHA'Q@wp+$g`A"'CJP@6WU1H<VzšOjSԩq+FjYz-ajխgjxMԛɝפ3hV+[,DF]ˍ;c]c-٭Znox€ѴC)ƹ婈118a4Hʎ'6p! `.8_-I$,!p0Ԓ a\Y4H)Ðv9b:d0-Y{Aw!~קc+Ǩ;_kd~X`?_9Jo! ni# t\*[RĪ~mnU #IBi) Yaaye0M&;Y)ﮋ[N ¿]֙zRy] q_Vf[MUÏ5zjGAU8N1 ԕhR9 C ͱ@`23KYb;u%7#E0(@cƣp pAnэ)B[jDH(0sަ~G#w4;),1YW|􊾵wo6uy9pw9}I#n"bݽS/JA~&/$!T8g+3 <#3p,.0*oE\VL4LK"*ĀAi#Ut$p@_ύAm:@ŧ&Ve{i-feRkedt8H.@ iQ >S3 , nePSKWb:c(+JݕE^%c݈ 0elYroU 3f&˦w7t۝mrS ƷԻqӝ7wZTuEҼ#N8bݽv,,\Ī@ @QdU4e2@T0PC7@$HB*6&&E|vg QP $Tcq p=t$$tH# IX;APB<\!dԄɨШ4I"l\K$tXCnt?q>zV$)]X練V0f ψ/#.Vʨ@^yشZVātfA&g"FFF0chg@f`e0vS.ZF:Cc!BQ%61T0(Da⨖< X4]:exZx])Dy+1FBǩ Ng!8f4S:vZYv}]-mZ˅8ۆE!Nc ݽh\nk4y>\dk?J$.c\@5D+ &3c4@CL0@ cI'Ls@`.4*ND?rSuDkrfd8Ǡ`Ԁ +(`E&"LUn_43*2飫q+'6f|]H0 >L84 7%] ,ل ` di($I @`# 9#\Oh1P;b pDA!C0xȣ3V1( > ZKGPTDX'-akOu+K/jȽdIhZ;Zϖ߫5^ۯ+z!n냞!ap~[__|y_ZWcv*JkPXN VײRAƑ8E<S;`D$1b XA \5ڷ&z7=WaYSj{L~.c[g?*WUJ?cޛzlo>3fedn Pϫ%.뾦rHu ԗ[ڜrlB!W2 K)BY!B`46d! A mKGJ&=$Z0llpņőA@Q66:CediqeJ&=MS̨g;YttIJ:}QU_Zh3)Ì9?p.)j8t ՝MYO@ : > @ ت8 [AI0q*mtՉ0#`R~AA(+ %0Tn~U ALn kIXJ{h١*O5#n$b =բ;Km/j?Wz;6d7 ^ܤٶw[}Y1+_T 2SLL OScKA򌠠0liL@<h)F ⁡+ *#s0P\@$ xҲ歋:ˢL,0 u_$u%]4%NO^a%E]Q׫vvf[Z6R- gӅ٩G 6ő5wkvdH20ijf2"!d< 5d(r#%8S&u[|CǪ(J H__h%@6[#NߌJ<5*h9/r2&YΥ%\;=/~_7{U#n킯#ͽtmaaN f\wW#Ou8i;Y^ P0 3U2D2:4p0vY1 p;?LL i̐ + L3P M EB#$Q`DM2 BLH @$ [0$ nuWN ",(o pI5'R-Xyz~̃hdI};4 D{UIg@ZwQn1= l0δvmb$UTR|V}j/&(XB4` }(8EL%L]5 @%5X(F1Ίs X(@FF  1P" tB}+W鬳! Ow a$a=I$ W,])7JCn7R,AVܢ%tug||SwsP7o5>rծ]gy`a1gs۪nV5 6=UcR@ $ FgnȦF#?g5G L&F7 &Ơj4 M 4R uT `\$.=lǙe1S'^%y NUx 断ie+h.\KjT-ی(Lڟ0'xt7#sc}*,ZU{ I0]#y]8wV^I?l]t40 E(b91F*Srٽ!h8<=oƾ *N{#n킍#ͽtb2T$^,؄xo/gdzց=&kÖ}0ϧOmWp anΤ0)tdxi%033C|Y7 1p8{"[ b habAsc@JsUjD# :kgwjtҶ)#KN LFi<)#n킢c={yǥzKɻ=V!Īe\֋=bzngYinm l L#o+I`Xhc`~   x#ѡ㌊ <&-`ATa 1zf Ap=\A'3wK,A}ﻐ`J.6L*2nN uW ?Iӳ_X|cuW[+sS( 1MxOyܟĘ˾ -8zٹnJtEnsûA(ȁXQdـ`qlh@xA  > 6I 37 <!8pjD.pL* "a9 1t04m'J)89$~oB@*G]+^l] M)#NS$!ap-Mܻ+ԧRƽݚoTht#W4Rղ;\| CC xv B\ h:\ X 40ptm5NɚaEeBdpɥA0B-0 RfF BNvKY85܊7R&yS 4f/p ^pzj=?7k=<Gx!Ml0;ON  )06o?iE p X`iHn $cJBN$IJO\U($ƱHh Z  F~#𡼾wJ4^Xӂo)nԳF\Ɗ"٦OUN}iڪmoq$# ͽt6>$a̱ F·L(!&[B`@(h0V.(׸SI)46/Ur%2Ŧ2:˄Vžfjn!n $#MͽtmuH4Umכ o<7혬x1q\^}2W^<,aV j``@hE &S  ,A#Մ˄ $pG;x; Ӻ.1*"Uۍ Z)}tIWXrٛMǛMuɮnGn.K8iĐs/}{@T3#s͍CwRbS0`dph3E[ā1s/(@#R `810F7V a xb0;H0PMhrR!(q^4ک}B 㺅aaϩ1"Tk/:X iwDFz !nmb =oLf9{}X\ᣚf[HRFC#a8Sð6f[?F$AHt@FH] @ci@iCLJCC  0"Nxx_e(DMɦWd-佧=O\'GzgJ@Զ]^ zԖsG2ϵwcs}yǰQvukywKwzsw@!aP_tp(Qd ̱<k$h:B3[@00`N1ȝ&e,%'51X$`) /銀NԸJ4o qdx)cţQYz/JfBaXHZ=w elcCGFc8!n i#!apSs(czQǜwn} ؕm9 zhV*Wap  ɃB͘*ɀqW9859(2X"D́P\F3Xe[O1 9`D!!`p"vbف >&P*+`U'(|uJۂ49 &G]MS9]0d "9M!UnXn<[8G_0gAWC~{[ 9wXG(UPMַԎPp $I H°h`p2a6a jbPM(T1N7 2Hp9 P0^] D@XDQ!Ui 0 ff 2JTHIdϮ Os !p8Uo.Y},?&yh+W;w џA统3S5Z䳴ܷ6wWp<+GWF\#ՐqouJ`e!͝3NG-M CA#сb~F$k:R@c5 yʉ Wi>& &(plÖOL@1#l B ,,RNC9 `h$: $zj"HJbPı ǡB( jY:PK0TazgqdY؟L_fZo\RΡ̘l>\eV1(_j"&BPvzZ̪ *R4E.T^xC1 C_LA5@cTTd-DA%01) !# n=!apbgK IV(v[N\J-1$ƫL nG`P(Dyk~73n{7c3z s;ֵvW@"Cw\A0af{L@@+04  v[!$di1IJ4чKEjt",ұ |$ `6 b;Aѥ BCMH]zCC:/}Q=/\w0y,MbuK3L2d@6BkvfZ2^z&3HB dZ tlMԄA&ƂHHn@b`I2m 5 C'P L2'nbݽ=kcmK=w5GKuFiq},R]9p sԔks3ڏ;714[LAN قxm1 8OX1Tg&"f'N0;%@ڤ0DXɌ @` a!I.d 0qK)9Y$FW1@m(/},V{ϵ3JUEjwtvziƑg=ys_Zۼv_Sx(|R&842#AzHxD tЎr!!U2@%Ci4/LW2!8V A#25G[ (8H Y̝_}7+rOC05#N7!=pd Rʯ_J_9u)oKA,|5F;xM|g/]ў%f9)kޟBԀerBa2HwYfm8D``иg(8P f7Jf asŨ)Պ̐d8B9bc,&&^óP DnoD7.&G"LѡGrOl}'? EE@~KK9oՋ_\2hԴ԰ıè²@!(HSCcCJsO%wI!a`I1X@᪹ 9Òa"ˡmF Z#3#Z*b.[轂NxHo;#n퍃a={I638npo%ٳTOHV| [D]E S15$IS80Ip 89RpY 0̋4$ Pǧ5B#hP#2w -vЋu4ŸO J5mQ4,[ŸpڝGzO9O\/wUlmBZOZlM$?Ǭj9q%Pt<@tsg aA#!BQ> %?dys*<|RW V4k.(;N3Q@cN#OUeE4`]8_Gy)YaS'UeuýW:ǦkOZ?_5Aۮ4X}dl+vUUgnWkGH|ĪO83>ZZEf;[lͽZ)^Hq0*com_9>E7ݾ2cnl.كn`L>0+g4eQC7[f'`g/?f".9 a7O!L2%2@8!zhed8b'u;$RKlw}WۭzRl=_okXYZ{Yy֒nG}_OPˤԒ6À#n$"Mݽpi(( HCA0Ÿ24FUTT h'1) J` 0P H`80PƠVradO 9΃z#)n:!ͩ(&2;'ʛ 똙wsYv- wpLB,&4/ RRK [Y37ަ0-ߘVFi#RRj00n޲7s֪s/=y38?!Ee@̀=n냶#! pV\-n}}oEd Me))L_] LNa 1`@}F(8JkHcg2,Xqbs2f(H9=!pA@"Z]Lv gA P"Nj}ogυSmI.WvX7\Wr.9F3e'K?ps/bP`" pGdZfi2N^ ` 1T0 0#b4aJ)Q"dPqAcCPP\)!а10x 0%0@C dXCt D5*oQF${%] vJKWM3`r!ЋZprkwEjïvyyzse[e]!n냲a _n3TҵǏh#bP_T^j詔Zdk(/>&>'%!qҀʐdа{("?R=5`Ɇ2!Σ ȉ"(XBL&7]-A:[@i$)C+'Pi[/fi7f5ܯ,_:~ {x;A ؒy~eRԧXI`Av5IWYZO|}_V]ބE-3 F+&2應 *#TYG*%s( @!@ af6 K bc1cP ]^)N]mf2<-Yɷ1?WEk 7!n -a=^Ͷ^żEHmn1^5{e/kҙjҫ]OrА$V[iEGcs/Eb@RbLg#Ret.1T8X$84$K`>Qe'GNu}($2 bHQU4m=n}eSGmK4`Z0nNrc(FuYJ)s32V[yKU/`돼8͈H\3[8nzp^@iT1@| 0|ǃsz5D@ b Adaa m08d*\(qaji$&IңEɯSHIh%Ffѳ\gtL,zblDfqq!n;a=6UǞ^Wi~7T`eT6FD&°efACIAVF#!F!#ə,IBE09J@II}`+P]/'a,:ŘI\]?վ۳Yߩ76Gypb#>WNmTÑPL]t @`|,`aj!b #!Դ05p3G &&FF0S1qA@y) 0HP D$˚O wx́Ҵ;*!M-tU:kh&p#nraIW0#ia|D\0۹-﷉#: lUmtQcxqdl*a)`$ x#PYv`1$1DSOKDS؁ CmX }WDq+vJH=Xi,gף;~ܓOumq˃Vh[?r*^׋ѳx;S2V9%@X0@ 19@4-:8A4[24[B)1qL ͞#!%qAȩq`bjX@ax`(-;Àh0P`0VX x+a@N$4 vIXn)Ŷc)r6Bw3 T#)jۘK#In냊 ޽q_[bz$taAӴ||s;NZc^w['3I_ٔl_x⃀3 s 6qbh-b|dpdF ̊Ą iBChمW0t@@ d i.*MX(PCl它@%Yh|ȁ+{okd{eB30+G%$jpRr 43aa,> /,:yWk|ٽMOwYoڻ.H3{"R؇;e==罎m45R< ^ 45$ p(fTg1s?0CO@MtJ0tFb`D/322a!W)S#nlj"!yp\r޻Nmh$|)|ҹO)'etXW^Q3T8R׫>r)J}j(!rX(M5U92 K-\W id(u2Ih9 h]AceJ*B("}Kqd-7)Mtfb5jlʚ?ZUjΤ cU̡@UzڪdzW7š̪T(Р+4fMUTT*@y hm% ,% ,% ,% ,% ,% ,% ,% ,% ,% ,%0T3u2scs0?3po>l0h=5`4mtD d p5  c #x6,s2G٩F a Oa5b+,%3p|߅`;ŐP*1(bP|F@00PA  b$OBx\|/R @0`bh``ƙf6 B `( T B8 p..jAy}lD ( ``H @X 0 ?rLԉ6LlN  @(@$@:S6g:Dz7F:+86U1<5@2P]p! L<= n \P<5P̀̐8 Z351*dBU9H 'G4 bI!d2Rå;G vc FAtia a98&3јH !!. I@dprM0,@b%^"PD XJ^Cp``ʑhE O3RM?`\^ $9)UT D yQHu;+]ŀgJ԰t4I1ӧnE0Ip~rSEu7b?1¯ݿoZt}%_c!(KKgtY/ԢN|7zBT4qSb%fdbt0@R[ nF) vU޷ih.̱7"I55!.oJF%CTZOZTݍu\@ү˿=6=ESN}*٪hͭIv(o8:߿;v@T[joxrMMǑތ"38o zbň%0ń:aD h)'KcŐP HC[Jg3DT TDk*x,t'< &j23c*)n?0&ŠyNU1:G!L-{1K_5]t eEsOggnm@&2Rj@c#̹<0pF8 .a $%3dPJP%4IH y1\`0@\Hd&@`sL<֌Kf bPм4BNUDmjM*MM^Zd| 6Ri!:>V۞GRsj& l~[0(A111 yМLJ0 3i088!9Y3A\F8!4U1@;(h4P&N >x[[-JhJ*qE/9@OЫ)mK"^Hy:XA;l=ݨ ~ZP?[&Y3Jդ>߯&, aHT$˅ 7& *^ 8|r"0@EW/-39ZP2d~UeG>Јƍd(SM iʄpHV/6a4[F\E+VbZEYUUBm-નMI!HfX&`Ke)< `\;h88t;ƀF1V!@> 2@Gw$Lz)T` V Gp҈mB$b O(+%?[qٓbH ]18:D#tQH4b&&$ .F IzbNMkfefm- ɴPJ(=<`2cM5 (1/hp@10cbd"`ZA 'lEIά88P%J:V:_6&emK::O(†4+RCQB$!>RE SE-Cj=.q"YE 6e;>`gSp67Q} TJ$d?v7Vp,BiAGpbgiH'͙2Ƈb9X2JF RqE+b,9[* ǹ*D!xb= N(2 2 Y_KIWbY%B:bhݔn^к#i;?ҵ֓n,kI77[Ӆ-%7d#aLl4RR;^)U(.9jI-09>L1Z l.ۀ&E*^8F~jl~Wx񳭵o6^1q2}#`U8nm *ͽNjɨbx2Rf $ ИLz0҄@fd|jA@È0qW/p8Tׁ :} @T VB$f'f- %ZTIp}qJ,k=KC^9Hxʛw\9yoy_bڼeE.rꙣ\L xD "b`XA.DӒr9$Xp -G`b1M7bT824P2Ƒ,D4F 9=+6n!Jյ1L23H?DR6+nk&)MDSꍾVI'Ңhmǭ`_Ųw$$mf bqS6nm*ͽA Qd 6h{0$ʃS  iF MOiT`"fXY"wfz,Q&)BPL;liHzL wO;JϫQ!8s+SHGJY4ne4j"qMѯjѡ{$,D))q؂!*O6t85q$&s Z(0Q !2ŀJZX5 4bcЖc.piD\Y z h( eS Fڝ_˶"b~ f\HTUǪ)?$ws}ݱd[2;E-j]_=S4nm*ͽvjg/S'?+t8(~R(@5XXd818t`3":0ӤOCР9 -$3]9,ʵb $H D*,Ro!wRGh6nW& {x ogICmhoc}>-_y Q1=[ߏi<<]#c&\{DAR3|wXk> 챟W?ј4kxhBA\yC,Z)(P\q,J˶BaCj-pPd ߿XTvJe&'<R#cy FRb©P Q"|@>fB h1$)Tf}uxYF[ d P|\7zQ[9Zƅ7{ѳ5ZfhkIwlR7y>GӾbIK0L5dngAG 0!ѻ [^&X-Q&(*8% :J*ں*e@Pj4*ݥ$+(Uq%}XF, ) ʬsF'q}MFc5$K4ǕeVT`6k] g$ʡU JGxk&eWBK6 aaEWdAὮsc69f-j4@`&I$TL` 2L(fTA\aAF 1@ #2A0JL|+{hc`&O猈(7eL_e$䇞M׀RV0Bhp**tV[ :XBL3Z14-7/]bgQ1[RHQcmǯJS} QdW2nmf=R O daРT@L 3BB!qȔ%}%!"Vm ttyO:bP{^b 堎g<8׋HѓQ8h E..ְs7|kYh0h\Udϣ |I- !>Q-ڂ=aȇv֒>ZT>vхv%fgضSvwqŨmǂFx,3 r=ԌQZ,pfJN+5&Ktq[z ad9Qrąq&0_P@"ޜ@ ^taFHP( _>wLOH׏dÌ h>@` 5:F BP`bH 5 / JՂ]ŷncΏ M86HǣA! BBcCfM $>Ai@E52%_ |W2ni*f 1%bYH 3.Rv+4HRօcfF>Fc0 MTxO1I Me!.]+{w=}F>Cynݘ#gr-[W@f; DILaY*J 0@18z@/"aux Dz^bER%LߕY ԡbOɐi"8ֵRmOfv霥:1¢Ln-s-uU*ۉ#ZھR;'67ovle@ Ol# cjˀ!" ʹY(be1Fa`,}A膌"BDB0Rm{PMW2ni*M1ò癊*W3=MVRa{_H ٍ4aa{';G%( 3އUP!/KuLëS*l+nC?K6o[=G`>@kM˟> STh0AS$B8LGC!\RVpu:!KU0 ˒*&^X 1-K&#hqt=df5lP: ,}iRck)QVu sQ,^&(-CY2 n N˝k*oa9k Cg4XH v:x<#S,L1i  O+(RA!@E$ IVё#o)0U%Ch [26W V0*"&߿9T[.$@BTW.ni*1C(H@}WUY[R3#W:-L|+#]<;tD,Auv{2)3ٵYQ<< hterȑD5M0 \t 42( ZtZ@(aZb_¤\2i 袪a|{>J4\ZJ}SAG2kD$()l2[!'\ MP(4jz!ŝH'뙱ugxR:+x6z&W͙͙N3CO:#S0zْ'_5@aBF.~afPFD1KB5q6h`T(5ʐƕGuBq!htx# spSi 0/ (k_VkR7AW0ni*=Lon9߻/+j ^Œ{<<=>5ՠSq?v#s@c KS C-c !c `E `(6X^CH wYP"&rI]&h. UH(!,˴TLB^=pI#wu.!j;B`af1TP&И@` s\NЊq` GyrTLA$bcz r]F_'axmneF2 }a4W.ni*=aL5Y0e-2,o^34vƬͶiXN|X|M-f=4 :K0r)*# B96xtwI19HZ`c"eq"i$BATIn0":YʪSyykb0]>ØF$-fr=]ZPތ+[d@WuTo97]wjڝ;::7Sz_qs6q3kXyg])̸LMBL>4 +y9!(800@9 % :{qDQִ0a'7]a *iL.**ˡdmiUJҚrS,niܽI rhsbq2 8}vcI˴30S"0[O`7>cp1b S 94 s42S0 o19(ʘq1?w<:{Kg bQW&u݀&=!jcX43Sym y@mIF| a٠>$X( *`р@@118׮}%0d&B D^€( RZ& f 4Z +. ;Tݔ:S 100dAqoM~{K;E9TE1$:b0(ơr@qݞvsdzjW*RxB ဂ!AeH L2L.\euOgrf !FA:  L"g%۟v HF<_ ` U̎d\23h4-Dag@#S,Z kAJy éϵb8$p͌)c !mB 2 "VY3pUj%9?MG4,K,x֤vٗ砩lK#1d?w]+Z}&bܲs {˺g}klJVk?\IPѹex %N*#0MW%=:̓!+q4T !":Isf0A>@ +uQ) FDWv_0:5 i)#kn9M6'PWd-=)SژgϹAh7* cV]v/8ƒܔgPCwNqFLdJfbU3aLr f|1z Wk"۠d",0WT)M=~!j_FJʟNup]6oA`_RΘ k^ mzýyaTaU$i\=wzl~g‡GIiVYBD'2!0T"f"h$TfPPVɍ9 |B !l($u+\‰?vHD'(ɯ&K\ 9ApD)V nts&sr6^񯟏| 9c:\[C Ws"F{l;ν S s0Q `*NC>,1a–,,Wx9w"yf v$UGjoiU2*g().CCc pjl,Dp?bq79MMMe*MN(Q^a2VbF F}~\+5-zuBK/*Zu\ixij vW.Z<1flɍ$`gW@ni*'=fR# ce=LXE*Lx) 4 Ri x7U"g t(b܇, d`*$NbX)$hJwB0Xd'HkR#6KSgn6={7n]2FV 8'ڂ٦f_YYC-Qpwu o? `k!W0 02j)QRי(8$ۭTl$,dT``iHQHFi p'u$ł}_˜Pkj/Stl3bryc]ϹY2ڕ{Quӱ|3lA̓7Xul2gjLb ϖ3mM5ܳfNrfjQU:nm)ͽ1.gA@XAF@er!,32#k0$i`BX*PizKpDq Թ88݆ZSq|CɘH%_0hJXj'o7qNv1ڃ6>ql9͝R&_&oS?YX#}R_+] /^Vگָ$#`4LL@ imF;ҥ.# '0hX 8y5f TT<ED -d0S &L8D2Qʹm#>(imtC^y賅0}[>]j|k^wIyzv5*qy7#.XQ E۫7NK\3+uvS"7BiUo'1ij&v݅?[M8# iuIk9mv>5|9C(;rכGw{n=`.vQZٖrM.pdgYdijWDm +' ͽeokPȀel10ARJ-]At59[Na y!@r"yycL{0^eNfJ*b1*G[uHMtɉag|FTfʃ("+knX}X ]:O&ּ e,E6|l-1&LSY>{_0"$2c&YcGSQcpJLR86k bƝ#Auge@3W\(hD&@v:"&#)ZgNp! Mck %cu6먇F^üj8nIQJ6f6wIֳ6?Y"_ M%C}x`B31Fs3pl3 $Rf@)8mW bJ^hiT'gɦᒎ0S)ސILu$] '= [kmEl敛l˯L9]mXPs׸k]ޡM/E` ]+8@&f:*< CH\@I@U'?qU Pd )ҏnI=&~X@" J+Kp J/4]<$cw~jyYךP>?͗/έJ5TUm5r!ǣvﲳax& :f<=4liSJ3D^($ @|ՈEC ImȲrMSFm*fͽmf 0)P9VJX?skXr|N$qM2o O"%F4 Y3;:Ƴ=|oӵaropeqfm];H ͺTcFYK I'~P" lKVe򱲨 +1 ,4Ꙕ"%\m@a*-@TPjC^SW)8Y"}ћuLŒk߷y'}O.7WTvdܩ}y}׻O[.aI9UJ  pZc[ #s0"S C"ʀ oB$86+U ) ɉ?iLF 35D\ʃefO:nm6*ݽQS G` м MUicA$sjy֌-? F9Ν0eǟ\g d=ILο“V)/'|NX1j/ ^n 6 r)x5U?P0l FM,91[#h`P]L.  j L~*8V`AI+ ]Rն\7JRA$a!HF<"LG 5tPzȻ"KVeP>JSdKS^:n J-Œ3 a0Oy&QTAH3*;0 ($ ;i%5`1o(4aDht #DDQ8nnM+&ͽ45So:" @WQ@'M=J5E>;(Oữ}uƛOּ.ڑM[mJxm?7Iu.ӯGfv.d Eq`#- o0酄! <{$H)3|I\Q'*.?՛>Ċ dzh'QٜTyɭC`5ZrNj%b# Otww3>/TC1ʶZ[[uL۬v/,u[֞,;=m 4xy2c Y4p =L+W0^J!pvAT)f$k(P dcnr4:I6[Bs)KQW>m*ͽ얛^aOFT`27l]$ͽrTL滃>goïj|c:1X_͈pY֦mfxEi2=Þڮ DXϓp˶eNv1D`|.5,1C5q1 @ЁFTT3(Q Sn`x 4 PQpfx (U ,8R=W r 6iO^y&L:W^_C>M7f_'?}(-,l}E҂BɳYc$#)W4ddpIP=Bxya lˆ$,N*L 0lǥaJ4ViY.n+%M= 4Imi J,>ceҪ@Ae6t*<u^.0~:Otf("DRA dISQW]&g+.jaZ_˪ǁ|ҹ+%5ܲ%No B]ϦWs(O F;J$by6:$\a#qhᅂBf!%9{RED \DML1FuQDFnY ʡ̩}b@Y[LdP dRfv ':9eLB5.*6vP!@ % lV:lٞ4>& t-+`bmM9OV"h8iq' $/z^h>OKWMwn{{D{l-]]hB/ؚտ@ V&=F>IFL4"C`fXfB].2QpHXB6-ea@AFRѶ  A0<(E 2*–P$9he͔<9ƮXYÿ ,=Y<55/&Ƕw/[cpfՖm^˜LAtɢˁ[{ 4QL ~$uU.nMͽ39/   ҁ0s LJ!0|8h7#4"GV(Vr1Ug!<k 2c5, Z®gdz6S[yV]I6lfןR'ۜeMUT\~mH<=!20q"&&fF&2J`p pI _MX!<$Vyz0΄E \,U34"^KMWіqvtNu'ퟻ讹wr̾-''-A4u/٧ŻO3ɵmĶfZ&F5C1F6/Q %0Xlkf furIS2nmO*ݽ(z5 :`(`hz>ńeQ$fF F'8q1,Aʺ]$Dh%" Kʏ`?LR7 c5Rj `ۍ|1}5}]y5M\nki4> 6sGNㅛ)3%\;? 3 5e-J9 imDAch[cFd` +$leYZ$:,PF =@8&4`X-^6/ F8re,3[)hN *>o;^gpcMg{|2>3Ϳ6ol&y7vF=+"u4lk!L$Q.0 ΓLmqY,n * ͽY1p?0axIdžAT#.Jw 0rA"$M(0+(4 <r jX6P5N)@pI6kOmjF-Io קǮΉ,ӭtv52 SeRO}H`w>YΝI^ߨtk6y(rid @K`( Wb"b{8n@aKn~ץ۬:[&Xzcnk[.<כx~b|o˩/FXKYq흯-`rȌAMF 5ҍ>"^0K}mMW4ni蝬= 8jd^~^!r~bU츁MZxoX?sm,Fy;MoTl3˅%"Ol4UbmWMDm6\&4i/[i&Y<:6g0 0C+0"AI. < OPU|ot*L~̩X2ν+Z*0&1RXƔT,Ữw?_xޛ1&mJct_"'ͽ]YNܮ]{vPu`c g.gݩfT2 dѠ+HH. +@hB摥QH9vO$bYp8yUm  SBm*&M='g}eP`Yˊ"Vl.lIb;FʧD+׷vmYnx8~)S8w=: U@ %]a17`$d fP"00 z 82`HԀ! O+F%LL=Q1i7Kn՞C]q]m/iۆj\~V>t3pͣ.mueÄOh4W2nim*4 E'  ~$m¬<`n ¡c>%AJeT Dzj@Z`H<$ɥOݨbQQ_W^ăem,Mz?jcn ][AiW}y-VWn?6+ =ad`8D_8 jI}h]p6K۫xc߇kJD(h$Q R˃95#eoE&ztfux; {uѴ] F) pf!&gfX,0H0iW4m*ͭ C182`h 7BcEijf04BFh,=my757&"Rڨ*fݵiҝa? mSmN]ݾL>n?~'ZFm{f]hӺ.$k>bٿ#ǃp*bD~Zdroich,|T" 3 L2YK"݃x4eW0nmͽ ""0E) a@!cD=J̷sJ04xwH՝[J PU#AIJV MGu)M*mp-fOY덯Mm;l<3oiH9ǚ7gz["siս@'h f\ql x+!O4"|X\2*aFxHQ00E LQVD` m "=EB]r.Np,[BL:CTW=+z=}ÛkomM1 Ψ E𦀍\[3e-ڇ.k8ί.׿4#T fxX ]20πqiTݏhŒ0FLa`@@Ea,/.K$N%ͽ•()2l c_B>]@Q7YdX\ a ҳFbOSZj0~~JGR h8[L,ឮZԬaJ80z%Z. SO'D#זSEkS< 2de`NO/E@6CɃ|$I͠(-aC!*C _pLd8/\nB ab6͖}Ux-62(OvSdR)ybi)^地\b اWQϗ6rI~k4 c>\sIqoju95(( ][ 2w>@;E@C fn!c/!O.nmp+$I=^_p@ 3!Q!*@aIBLw(}ױ/v2B \zMړ{ly>M;~bW9Ll-.r4O.͈Z5x֞jYpq'X 1bE A2&!AcCZ1I8TG@8``L$B~J_WoZNx.eQqU,B^jG|m1\ GM;<7H7ֱuv&}3{݀O,nm)MͽB^խj``z[5LA (ۻS8g g#a rmX8,0<00[1y 5` b܀f$Kd( ?F yAAe $aP0~IG4གBa+*#5=̊)n+;4g]Ϗh7MhDž&-ҷyt>[ZG{\Jϛ[~@>˺ƫ/Ps`n`X&kcbaȀ$/ +<,HIPLlfy()\= DDҕכ duX!"aM䋍:-Ѐ;w'\w>|ξ1z%Jb+fk2IlfgPUvl[خy&򆋓M sԃDT,CJR}yqc^$(^` p $pK*(b %+Ir5Q$n)Mͽ1R3$9})23 J"%9!~Qa9{ր(n3ݽ`P0 6B20Ph*\*DfF.c ’%a@(x:C'64rc"!WWj }*VLB $/+RmySI/z^iVܶ|o\gKudƊ8Vύ>uW]~V E͢} )Cy/(a i*Z``L5"L$A <; =b2*FBfp.H$>Z <-%Ssv m`#HZHL܇(@lmkkd(Ӹ 6 _2+ Ujn_cc^>s)@ @ nDGh8K]ـA"n'(dݽZdzA~,'3kqr+Ҁq!"n+#a?P G #|sQOi"f0ka|*PdD{, `T@Y1 m3Q-xe܂ ^jI +10aCh (#q>aJV [MQaɈգ{E${d~[+F^TrjIJ,L# @LLE¡A3Xȃ/@h  | %ٖ 3y0}6fB >LK(nm=dM=-M% -hh . "!<ŀ) Aba(HBGJ) 3ҨK\2逈3T;zm`h2_i 9;&뷿|Ap?nO-T^s l6gzi:5/$Q=8j%ծ=˹FwZVk~6j!PYBSj3 D@`0ip:<Ȋ$a%}0c:%O?/QF #bR%xXҜ]vmVB&v2?q#e˥MDi%vPH׬LS?Τ=[愔É,&[cgY6_姷: 0P)Aˡ9dEʜpd2rO*nmЩMͽڠ0 V7< 4 @x9T ˌPU y}8N8}X#bIY$ = nN+0) wiç34泦(4,uڑKwIP_I^i_~3y7 @ށ% .>{@zq;A&%ف S(07Y^$:hB1Ru{$&Q $rmIT8I( nM]=JPC(O_f(=Wm?RTF-.u#Y= >M6f  {O=f_{x}yq@]`P(laƠtY1VNHȰt҆m(dX PA`AC(nm) ͽ}7&]r6}Pi"1+zۛC*KEr4xK8ތ=`?Өfavf?߮n@l>|4vmGbfo{Eo!<KS (QH40`3! `Ca0:kDLlhπ i)AEb-ڹ$:۬ Aʜb8įnӐ¸;# );LrJ vJzی=ղ *%!ecKSI⏰Ĩ 06912 CLJ@$$` DEyT`$* 9Me3`"}HH תv- ^}9)|u[I5&n$e ͱi'MB 3X=O77f!jW]sEc1Qك?i WӔY{ϽKhZ?ko.]˘2 a:'X9f s#$# 1YMHL̂# fNZ«"p0*P DAs> ;n yUr3ŕp%X? qe]w˪ĝ)jƻ`Ov-˄#H1$>8-:eؒ0U^<2S\a8 nQK \$p$،uz@wEB| F x6P0(35SaU+XR97N ]iQ&n$$ͽtV5ts|9Ʒe)J$:WM_LjkX_7uIlomN`@Ʌ=rTȘ``P^J1-"3 8"YB@p 0FDU-u[D%&:8y_}*Cn"#"n'ͽ JdADmV1>$}Dz+v*B\3ڷH/XYkQ*BE<9aݩ9i#ZH"8 HP#!lfj(<F7" n2K b ,`IBO"HXF\v7*J\M t(c ,RH:l E[=YMn/]no#\Vxzku(٫vXeړ [ڋu ] . BjS? B> V`D>h()g"a``3T[`C.2,J/C@x#9T0 $a[6D56mGWsaocGf# ndMݽL}_JO+8~l}Ց+yum_|/jodݟ~ϗ:Ga.4b6|P ͕X ES7vR48@P-pc0(.a@Afiojw1Q~]U>A`5 ?U@aHO3PΓ& L&EˀL.D[6T=Hhd̂ IFq[CĊ*8 &M 2-;veUL>L# n$$ tw@PSZ[&74}5o]69|,Li#vckX}MY<5D\tK 0  5N&h39~0S!0 #:"0 i`hiىf;"ȑ,1(pP3Xãq60Y$1`)Aat1@"vʗRcY# al݌LP;zD_<' $s>QccRøjAW3 f׽V߯fyPN8E&HBRŮ>T dVL,ʤʲ, P(h!gU>MXD|"$ W. A)QQ! nm$"et? Ƅ!NXe6*s71?9/A-CdVaWaygXnho\Ǚ}l.&?s\޹g*+vG#F4X TA#Qs!H$d1 xK0D23HD9q(b 0X rCACN} -&Z& A= #1ʪD* S,"2|iKeY*KXinlK@6T(-tL8a.4ߛ9uu>vosBNzO%o&ڗ ԰L P8! :! B0hV4/Bd L<DIF土0 *"gy˯6q>bwjV>4L5o0J%w McLS `MF ≔@k 0MJ+ A81RcjLy@T ,U0dfqTuKQ%bҩ_/lǟm`>+|.4jHf?~nrMkգHu;5;_[wnJL^aen3w1`Lmw¬Cf@`L)| F #4`Z~1! x1w1W1>pLpá|t'f]#n$ t(F X\I3A> V@4{z !PXd>.aBć^ׁkJSrEغD3f3Q^W>߭s^{|?՝jע[9?+1Cʱ wsÜ1QCoyT-zeJ.[gY@;۔vk ɁR (3)0ɒO@U 1ppN! nҟb#p*=B(x0Â2IAJpdSTsÂUlHPp$tWS)3ES3#@"(AST!Q icy! y3vQOSTXR*a!!u=,\`0$`<Ǘl`قك`!tHs=o,3t`2`.  ``"`#w1ϻ@|0#.ւO\&\`( #K,0 FeѦy?YV+P4 ; g"xi# R.%LjAe`|C6׃^# S=[! dNI!8ϽgbiZ#) b*~[ hr؜ڪɓ^o^"kReDi$M.1n쫔a߯J^wvmYT޻.c{r%C8sg=]Djjx]H[44սQHulU0>LQWT WRl* Չ`.cPf +HCc #9<'e9Q#ͤ P@LB*"Wsϟ*b,1lA1y2hOS"W-CLA=V%T(ÖE =>ZjU41|o?>=ir[;=ϧUeY&~靕̭ԓ,)ٞ5ƍ(f$yvLAsC69@iT $0,R`͸1qk(hP%~AA ,Щ b(RI@ag+V-3jnB+I$SaME k]Tiy7U6)xSxkb[߸f7l>>t4*Dݧ͚4fF $0rA!5h[RB@JiaWHmm荽=wf8 x >G&+Q*%[ab  ˒QUU뼔(#,3sYՉt Q0&JSqZ|4\RCp° 2jOL}ͫƳ\?mvڹeߒxTN #\/$bx%a 1(H,8x.lXX4cv*2%vw8@N왘T1" ,CQS (ILE. Y:^(KCC#K+z on )S~6]h2!AԩʻGg=L==oOm5_T\vjZp[8FJvf7,blpR a$v=SrAWDm퍣*M=0Lʼn > !*^d,6P@% JF. X&zTi}b˰vaaL$4HOOxڥkW2ܟ[1vMkڃљ ™)4 T@P`&b ?\X_0rh)hBpHGFȌ< VX`Q(Ы[mVu+e=[ZCaͩ'Cț N6$P:.癕^˟_ |c:0l]v*^odfH& UacGWԦ2T32ԛX h2X2!kpʧJ'Hu:b,KAtی(PBSz4֞1 9mͼ%k=,E|ʟQgkɸ2hrI/wI4XjYBu\tțLd/*؜SHmii&ͽa#pRMJ 6 ߬4m{Owb^_&~%Ǽv>85f;콆?Y!H,wla5xez/rD0hă1jQ \tA"D)SS2ÅD# $M( 8aHh':펂 ֢#Ā%_&鱁 Tv f2J) . ~'rP60khs}6$'Ohp 7?i}4s&JZ !c 03S0f@WULLJPIJ 8[CtuH6f9=~CQpòbgvܹR>$ye~ˉ32{,ZQgt` љɳ0g_3 R:!Xꁘx@I…a0P20b HH:HTSi1 c)d>C t@'>+uNE )KfftBrp{uM'iq_˚bMb o6uMiqG+ۻ3+6L7Ď`&*:c(s24* [( ]F(l ,(  `Ԋ/PXBL rB/i#=W:m,*f=i{s7p_]ٓ(A]tYI\>kMĄ u׉lmXD@df٬ǁmwjR۳ǒ$j~4LHZgԒBaS&>bj*ňTAԡSJcZ@aÁ&xRAFN@ 0 ! ";=%/V(+ڭ!%Cem=F[mETIj5Ўnj8c*QmBÒGΈ׶*&`[1q_YHR޶Qw_xu NVb7[=o'mvloif:qaB _ӬL8MELMH a`D̮CA[nL,diaW4nqh&Mͽf i$2@:n*! N s5b=hJ]#)kiCδlE;ٜQպm/]_.b$x_Vk=-\›u-4Nx̻V5t RI4, 8s`'@%,$HaDQ=ˌtKj2AI7x :TcKP+׵PfHP}Љ'PE*g|֤X!N\@W-ox^ǩj\G^-k|xyd/I57/f|f]A+*yS0kmN+h%d %^ny f'vf  aCpP@&HlAD!FB>(g31!a!W@m2*ͽTP$& T`D*m"*\QA@Kx:$yi#!ZT5RHшtW-MO0ZX=b{_KΚnpa*w8~-grdbt{mxʹ=[fUπB sPeĘ@'\W G! gFRJN"@pD {Xyx) #ݧX5Y 8 Ae,ə)85$ho,MٖftIG1oDәIRŽU(X7U2+c0d2Oq91] 7=g-b,3 q҅UہU,QW>mi%*=,-Թ 3.MN0-y?&yAʳё%Q"yR G14LZz28aMZ{Re՛P'lLUl[1cZ<͏6`ÑS[cL5AQɕ|`@X PP8FH <1!ن&]:df6L8 ^4<}P"8X`s59Á bgSg}*7kč]7<|G85˓Ԯ;e^i3ـ 'C,t=XU Pr1蓓 L20lÅPрX PAdtI༘x *LLc$Pb@f݃ o0 BCCC7)PRH\i+:eR!,X^1fTl({|$ySVun&cU]}QM-{>snۗRd:ָh-xݗ@ pLUF\G $ :$hTNaCa" ^2H-2{~DO|:/w&91kpDBQz#Y.nmͪͼs"JR^Vz}* W:.w'3@[f[j^r{wZRTye)66;2pՎҾc& b#  bY$a.(qi VTLd2EKL a%4,Vk4epMai,()CVXP(V}9 ?tvCEzI̱>,f^o'4tZkZ%'+k1gF!%2X>FPK-Z- L_e9 劧Jk-9w`ҙ}O}n7<KyU"Bu ZR! NyK蘱]\=e5=W6m鍢M1c:2z}~.Ҹ).6hSF `ɂ1L{`#+ݗU%0sZWCveV&@ pDFi,4 $;H:\xDr- Ik"`K NjQt_)[`De,ċ5wPlq+r?1 (ǡN,IJuk Y~dy>muշl.Cwߺ0 9 B #=3,"'봀W@ma*ͬ1tLcUP OCBÑYM YHBP71-CT0J#PAs7ڃaԉh|<{Ŗ5#Ūlkx$$־پTL,t̻?-{'nSrI-};G+- RQѫHu˸;E]I&-65k@|Kk3ɹ+N`L&1*i9vĄLf~4xPѨbdV ɇB!]@XQbU4:"@S*J d*!>],)j\>_FtqcB1fsՃ-5Eѩ>#Ggw'as_Vk57>+czVߟ؏/3%aS2nm =2DMUD#nqJ'u2TM}Iab'k/f7It!x})}9`-7xzk놻ɹaE_Zz#QO,D`fl[ 6#:!BJPcQ#ihQb*vո3&|s-*&D)CZ`}蒟OG'4pPW4ni*M5Lņ폖6"m/|->5͋r:{c7Bnl8v]Ιh^[y8RFB8Fe'i^!,  &_nc!{ؔ6u'Hc3`8⽴^ &dP,Qδ3*&3OP1ge\f]z5h)#83N)`nZs|~{~ ͺ;*֤).ՌGw;8" B`zh&mig* YF;bak`A⩕L݁px1FD0z|fB@ $E~p^@1nIr<(uL; #:907pvW4m)f11 Y *Qȋ77s;PY]Z=kcTO^޷$8,KR]TEJ o9./ V7ļi n5b{@( @EȒ ÂL(@NfCH<FD{E+.@Jވ'z\P+d]K|0,9,,DbH!.-5Y>Os[E3\c;ojըTbjGm<ަm4vaL&LL =mS Fc# P(&AlA&*uP&0:$:b`O%AYbBhA@z)c1!l8Y-U2mB%ͽ+{#c|n{5!*A͔-3gX=HBj\)Ycflj4Ǵ <5<I/h׮gЦmx-+eb>MW,n5*ͽIFR ArՖ Q)jj^uKT)ֻ_gTI|J>l˘5,֫JNv3+v8ht*[սooG/ޯ{3Ϝzgw38]sn(.d♖N.eIR sL04ǰǠ$1=ȃr@EAY1c@ƀɘQf$P_3A\`BA`IEʰHuBQ` hs 3ȈmoTyT LGUz؜/'ILbFBSi$` sKv#3[񯥧/D'U{jz_{|1aL󥤳[e;'w~jZ\05S*no @dJ0`C&(b \DsAL)SɑTL5-  !!@D JP0( c4 8@3i ( @h\x Ġa,0( F!@ aX*,g #AGj`*qC$AIa8p"=\ PPc)QlAH<h1D\ F 1y023T ]-9Aq 2<@qqoѦ .0|* q<@; 0 ,\OaS>Qɍ`܄1`#0;3#Cw! 1+ 3A=I3.8sH bR<"q#MTBoŀ&*YڀU*hK7)J)CuyrMysO;RlFY ;MCv0kU3vyM9cSß9U4?DǤ4!DLxcR 3*C Lf2СbB$"_F}@ġ-#L렃 " f6 mF0 Țb31@Ā͔a&*$J( -L)Zn3Lٜ ~KlH2Nev_bFR؟˻~3Ϝ>AOvIgSsui.jǿtWfmAB&&l2HhUH*ak@`yy*bjXEQz.*HYB}"Ϊ  }h*Z,HT DIcI*.n:|+͛ t C5l=fuỮgf%|WL=6{ݫ/TxNy+޷$7MK4D@EsV =9CDT:46 FRtILf^0c4hCZ$PfPc1 %P"2CD,&Cthu*+D$b!JQg 垐SRma8*gͽL+LcJ^dG¼]Hhbӕ-gm^ +#7?q^qcek޲hi_ö0MLW~n< N FDtQ$F^kbҜ@h l wj 3VQY ʠm$ii8[l!% Ci Hڭ%"pD{%jlĪ@#/G1[l99dB;!yQ>=n[o&wZxr{}aW:ϛT8ZZ T_8Ţ4f' jS3 wNj$O1fޑ*<)0MH%iZ.8 XN8$ Vz`{@ & U:nm%+'=rņ$ܠA]UNiC6oU}Jma 7!ŮXSDh!z-fU"i9{ct\18bTzV6)wYjeg|mHVqΗݣ:NHE/aOЌC*fĮ͍I&>\4,BP.t@ѣ:bt8TT@o)0X&h1IbQK9,W 4AEF@`$J"RhTgi-ݕ͡rʀ頲If44Q=WPmaG'M=JTeH(f [(Rp$+g 6[]ms/: Mk]SE7Ƕ8,)ep4|a`  @ɲye/q󒂀M(! ] LN4FL57*aɮ$3aQgfvT, ZGI (GuN4ʙ kii <ā{5#Ml9٨+6qVOL5oי/y+ YmTV%Wv.qFQJ;~e)RЅL#M z]QAH5$ &e HPXiyׂ,&W )`P a?֜Y4n&=0x40g0◘*"FBFYP%/f@#sZ"bQ HGl> Z2P5OC̕t,S<wA\h/ Kgg! a2ˇy [_t%WK_C'/x^cib.kC%3@. xFtIg5 I2|#dpsfPO:D{ԣ2nj#^ SSt5=6#(=!S J6mYyʡUD=pi>יZ7nmo.$=w;9xkXʼc27w;Um{@a) adhC>{2ghy Y8nmO+&ͽ>#Q9M0w`3`g?=XPQB0&/DQi=Ck.vL]ԧ4yGQme=4ݬV%Yz]ys<=km/ϒsf]fj+aF`7Quүj) LT8yąSlL"P0b|M@nl%qɄ (jFn8*첂56B ] Ԃ@SJeYrfn5 fnGbE9 x*U\ge]'"6Sb;nM\5a%ˬ_J1'_֟z%~,HyQ);T^XzD͆p3; k#mY8nmMͽ( Rh2̥V,f1Ѡ^(y3`.,~,ا,ؠF8,P(HD}A;夻wnqC9 6#b_l(I.jtRΗQfl:[moy6_6]xx?5m`:諽-ͻUwBoQ%hTSHHk"-Cx:x J1j$0#fNAxO<}žx^ɥ8Hzz>=BMPǺRY35*.ӹ6l;5g>/}̍svn$@4~j ( d,<_  o)S$#%\f%5[UmS }ٝ7ƊWvoɉ"}0\?gP=ͿVʸZ65%(]ab}H)G ̔ 1h.1p(s ?1hF^ ĺgbE]{=W:ni *g ͽ`p4`H j/1&4CJ6iI3^1cƙ8KUR+>ﮨ;pѣ斋}&xߦMk:q^kOf|6Vd}S S<0D YapX~s>2ߦ}l깚͈ey^|]wޮ繺g8DC^-` =pU9g܊l"a #DeCIas`@d,8<Ђq^&** GnK*@EOHmaK+&=f D/֘aPG!Ve\ws@D|ɤAR>Qleq,P)hڪ>W3*|lx+F=&~}cL̻Zlܻ,96 $ut 02\Co +3A!GL:o֍ƍ,mXkBX%*&~ A  ]Ѳ'VL[*&2xA TrY Z F2 SHq!tcj]iu۔Wq0ռ$l/ub\14"yW'WBW S pTpy!Qxyjhv8 t$F5G{,FˏY4nmԪ荼O9ާrg~ \3|1ՁC%.\AnճѧTۙgcY+}8텍v+XK?i\5_pJї-d}8[]/,40'. 4K *epAH\ 4I#Dׄya`pDW[3z"eAMAqk1Nn-ͯ.Wּ_5iu6:}>Q%dvM:)ڕ}r\ιSaf`ja ( q.Y$hf3I/M~6̩"FJxinQy%]t"yv͌'}]۵$}Ϯ<%kJ]7Pֶ4xoEٻf ]SpM 0:p912 5ڡ`(r,-Ǜr(@"m X"kP]aIPH,{‡4@+M4kF:˕zhj˜; 0lOvGmvܲ5g D^=`F"{Z$.y1 {0|wA -#f#մ#sp" cz7ehp9!\U]"E}EZ1R~2Iҭbt]MSBme*=}0h:N1e)ڙmcߓVc343?^ncm[;{$rY<7od p `@ѸƮD!RX:!L*@Ø"vFs؈ a A#AEf'!P@3C hK!T:DZE2EUT@:Q4@0?+L}ڈyzZ;u>WKGgk\ݥS 3w\}SSo댶z\ e^W}5QI!1S%he7M`g$$|@o`w_1JITv>٠(Een1s\Y*n*荼=_pͰS9:腓WPҝrWbr:&V-8gJ 7~5T׉K_2܍SjN ~6be3N#Wm@"SGpȩ`18T$ T$b+^ !K'2. !=P/¼xA96|Ai}tFU K՘8\#[k1[ċ4֡$ʛ{viq\lG>E$2ëw69i|}86v 0qS<^W LH3iDFs*$@0DǸL C8 QLI4zֳt,0I|=,/s1 bs$R.VbhrAW@mI+%ͽ9ano͊aj}ԖޞY*ݶY3~;^VHhp*AlԫXq e zJN592` T Yj d08,Ё@G̬Q3Q@H `d,t4p*Ptwc$U P(iJ|0,"oRa'mzkf+&)/xϥW}LveO ibj`%S]gHvwzoHVH 8 GmLc1"le -3ĬP8viFvzs,#DLPp-Y ̉pB>Z*#P 2iU.n:*%ͽuu*jzOU{bU^*m6.[,rpnvwp _UYNsK={sݣ4p< lvĸl{V[(nm5q{jfQ@C"1\]apDJ"3:=?d&!JBRTL(I أ{Ħ|}ڤFhhB rͿg8;ES0nm*=w-W3E}6w V['xZ-8v^/aq3 @NQHCӊS7Lj ) .J ɂD4 HkcAW3 P.tۥE]fҘk3zG-]&]Q/_aQy%Q }4;$XT\`%0Z$rQd;1/=^ S q 5=:THa ^r2>= 68.YMX,.!j60J1vt{ nnnVc} S =i'H3/WA}@ϕ᝙m$YYa5-YSWO5JJZ3Y hj5E!O6nimͼR`"^$c*LDV6"8 GRa"AhMQX'Eùʼn?HBM(RD̀ʰa@dDC$[<_f*݇E'HSɢ1t95nw֍[6i_3n0Mk!kd +'2e"8G5q{S3}kphb@-|?,k]Z몵|Hi  0#1߷9VMo[l8g;jNjߏf4w}ׇh6C@&>F+:dxbjIC&4HdP<4,!.Œ_׀Y,nm*fMͽVm^$o~קl_I_/-vFܓ&i|{m0;tٛN.` s9`CkߕDv<| ^) g F!)$ Q&C gs%J`$sTX|3L|?mhīԮd({( Yrs?p;z mt8%|K|vn=r8k7iOu&MS˩q׉XnyZE 1`󹘽#SP 2 9K#2C3+&) ,|EQC % $!2 M݀S0nmܪf ͽ 1I@"'hd6ѥ_"Fto3ɳ}V3{c03'k][޻/en]ScnK Ab;B&vC# "0($<t V*` ڛBVQAd fFYiL `\x)+vXkAb n٫ ʆ֞!w,kwW6nFK |/ &?i+LF?oL 2٠ 0< 9Nd8 H$טdȃ` ɜ%bL ;N(J 8z"t0'H]uKt|"mS.nm%ͽ9ɤS-& B|yQ7/!j63F< i*WV@9m-bV׮mnJJS{ۑ^ail@wD1"#L61|@s a-c C(>eCf1F8RdlPDF݊ _1в`+/#Nkx).Kb}6Ɣ-^$g%e\_WS3Iح풙wzߦ&M˽\,Y5x$HqH}4(3 L s1\g4HlCaEHX 9Sp.0%dX(i!bcNPty(YB; W%j+_7_&@ 9O.nimͽ!R."]BZZy!VRuU~;~"ύn_Zn?y}ɉ'Ļm#Pa :u>z`ÅɌ.2uנcb"20|M`PhTЀp8$6YaFLHUnMp@3g ?% ݟ4Xc̅Cyj،ܓUW.nmm*Mͽ^cY(>؇+kߒB7!lļs^Y Nv*1Ջh2y:yѸvP8Ul2H?ĉwD <:1x`rhe#s:Ci RLv嫭v4Omb_p7~zêk^6x=|^x\  b܇RJ[ >Ɔ`b9C3lJ2S%h0Q*@0%w 8DKdHLEE[7|Ҙr^lCXp?SRLW,nmmާeMͽr3.]+ WRgUCu]O316۶ x:}o0~"f]C7 e5崝&" $ˠ,P  p0 gMjT3y4``@H8-,4 L aCTyxu Jޙ|Q;v|թTKm/:N߮m&S'ݪP--}#_l&F k4EB7gXlai6@#(@Y )1)f<4 8:" ^L'af!0Ą]ji+BfO1s4V*j21r U*n)ݽ4;xsEـw ޱԿ/gj~?LyIRMY13/f,?j@B!``5lD|` +ÊH>1GH 4)5ACFĠ)u o[|a+٢H.UȋΕJG%v_۠p@z~bPcMK?4k0<ͧ-|uS 0K3S:O9o0сh@*sNM@̔iƅLdH$@CX2b!`@]E@.=:&C E-dHEm~kciQ*nmeMݽAiijH@ZmV.BcuR %k&u&]fL*ʑ:̒L dApe@ ޤurMڱ[rıqovw7ZX}slT#[}č}rO᫵5~X, k:X֭  0#/0ˬ@``1l5r1=3b21Bg hK&U%.(*j.RPQo7Y==WuƑz%$ehqĎl QrU(nm֪eͽ_]N!\hl^|g庚,IguIrwͿj'ߛq*1O*1 twFR2\0eH,n R0 (3@ 2 )t+x4֑yOEjo$Չ@^UKv2g GzuI]1unpǬ1ܦؼ7M5gYk+R=<%6gϔ 3 d@)Q(`dPШ{_GE|3ˍYu7EXHBS0!J@)kaܒߵXew(]Wڦi c6L.'l狤Z*/*nm ͽ+%Q{9Zڒ,T:qyJ)GĐ>ƇҢJكЩwRut2 SlԘɰ(F5&}!@ǒX[:`7@dE0{A4Q@ (]% 0 Xe!́%{r<3~F:$EAḊc1L.b޹->ЬG`1&nW׏\jG^Ƥi_&񹵭@_LSlC9A H<PJm@s*3SH)NpK80MTz``a1+m4NkkͨZ-o0NdLW,ni ݽ7oFںwԷ,_լf6{e%r8{j3^wM'?3L2ߤ`DnYYFgR03 4`Dd@he;}710$0Bpj0 Z 'tQE%ʒ<,"RDuu9`/d隐|,!墉@jP nӖȵS?\qOko :D'CY*hmmneSWX֫@(L;  BJѣCcLSCF Ba柘bl0rIȂSJL@(*U1S4, ("1Qt e+ vѣI8)?(nԪe ͭH7]f r=ꒈl҂γ 7+[՗?bԴwѫn7zRf]F`9DpEh(^eSeA9aͨp&Y$ !csдFf]ɍ>NM#G$p$Y49`McnՓmuZf{& b|ļs~[j&ieva5_c!פ*8&A@ ZHH˜; &0A`$ %(Rr PF@ڍJH,~ ٺ YnOXzm8C&n%dIݽ&s&j u;E'Ƽlk,S2>Oo+t.)hTo̿2_Sc}@`apqad*0# pJ C[`cv4QD@ & `Tf \ PB + WBdRx>A+c1>򀒑5T:;&zQpѥWyjMLToL=U&ӡR*nboI92 G \LZLޒ!A D`F gb&B %$ Lx K(`H& DNv ȃJ&Лh$9(nm ݵmXJ,t5Eb")FKܽlEz|Dp}{xޖc?o/mz,)>/3y)}Ko[ci #3.6'0+2%-O&&Fq#d(XjR D ŷ0PĦA0 Qh $bP]_0 ᇃd[;,(&D%*1jVhzsu6NI2$3hk\6F0gcգuq&b6mzu[ƛ__0o?YvjC#I>paHB DE莤ĭ!0Š'c˔CC' *; $ Af RCtdę$}W$NDI= #%u KԪ?Ӎńϥ2JK$;-#z`N9IXLƣvnr}^mZugzқv(m:`4$syEb*,ZO_9ڊn)c0QYOώr7+$oԻM^r>\[C Μ$B:s@C}@ HneF @p# H{50d$`L !|fEV~VC$ c`"^NK($ݽ(G4HPUv)D!u48fA8''ʞیw2I= Gs1 -]Fq9Ǿ?[~/kR''~52ktb+2AvC潈׸VH-b29`2ba<&V z#|Қ%%+*rX)A "́@~ʀ[dre_QQ+789̒aPtҁUP{5c+"҉16UƢw}kݒگHnԘÌh1?>@ S!PH\P1>3(+ B" -LU|5yA " " +N Ӫ = !v20BR@Fl*JhY?oXGzHm0}'>'w5BּorR-+mkgµ>f7 L$_D|Ýc*Q\O#GC C+0$hF y f7d|;H*$*&HuLfv5yvֵtl\~};hJ +XV)fG9扂 L0'´'Dr-fRa"V7,(1"W3YqâUi܀B9"R8*l]ZҍX˩]]JN*9IGa1&m&p:|"øu|'|y7oMt|Ki|}O1RKG20M_0 s-0hs`1}AA%0FC0Hi*:ĒK 8!|pqq#Zli)&n/#ݽ;EWB6$ )ڐ&AD}[Uifpu`ݕ;NR wN=VAev=@۔Qko7/?7*otxr2^AJֹ?}_  JWt̗AER9T6Jkl40ZIOo $!p ɝ.L0J#@0@2 ;3u*q4| Hc zG ¡S6H`005Dv6  d0Kx|eAa 9S%M01# õYKt?E巺ZH٧s[ë)6vX3{7v%+5(bP yM l 4'1C@\ 8 `$,I3Ck3LRy6^A`a@@0g5sU8!#9Q24Bƀ ߐD/9)skBc7'H47Lyьcq*u7SYbˀ#Oqc =:Ey1~XM$=Ӹn^1!qB2sκE;֤OwP10bcD1z#,0l 0Ad0e#p 01D[OT3x <$ cf<*`@9F]£AD6 ,,舃 +0P8] (;T55++D@f3d$e.Iv}wRM=Cg%G>}?{M齼ʷmUXg[גZ.bp0* 85P0H.0&G0BiƊ /1 @SG(æQP@ 58tYOLD0 `0qAOq$# it̀C ?yMn-}X.否RGXN#anE)E^cbw –OzʷCQI5b;c|39mP_ $SqY5f,콴 @F7~(:(j8abd& H1 3(@P7'~p1,1…`AF $ ! Eg #xbPJ9)V@dT& 6,OIӬ-=r$@p @}k6riΝMڝ{όϧs l=v{[_ߧ11E >€,X¡͕\nZBq2$2Xi8Zr62i- )(񝘁"< KnӨ% = H0,  R&*W5׫|3rsdtp(LnT6 f͗f֍1q;7N.jw6>JI ʷRưP5dA\=1$6b"Rp "2# t`P@0XZ!$z0P ғHX 0n.Rr ☧Hs=KԶןL?D{?^{V;TkWƛzCۖ+L:Y%)׳JXRH Nj&#ITw200H0rh(pfyTwʞ3@` b݋I!nK$dݽzd˪V w @=(JQ)qI1$=_J#SZaOE]pSѣݚO.|kډ״k~\?.ӈ]jۭfu|C-t@?YJ2dJ0VNd>nP0`HeCCPxdh`D fwQ܅ti {ads:Z]k~ VrY"H֦01n34# 5<&6B2D1 5(:0dL@:b (Pą4X\ ge<" 1AQ b aVo bg4"eaP/2=SƂa)P%ب4v!6ծ3OȣzR(k2QI #(nmm# 쿗_5v~s'nkbS{V5#@ AE,*ңc,UJ0BC1 #AB 0s;3r 1f 1o ?1 0}qp0BRPGc$t:@c0Xvp( cp8v[1`(CI( 0t7 ' @ٰ -p D ; 9P&.!C> d<,.2,` 9DUG0 i XOR}4ѭ`  , x_ۮV x0@b9@Aa2 hg5a,L0e` LAb%*~6%=0bOHa kfaH^F]AZc&2@f].d`Va'7b4`eB>& !2oifXfTu)`c0(BN~? ݩ  JTMDoժCl)9=ؾYDŨڵjË|ӌ%+XwjfzdW  `P BPb2RFH9j,.{DTeJn, >nق,XyilJڍwY.+xzQL²qF蹮.=qWRl >\ټOw,Ɵa"*WkV*Oj<ˀ2>Y'L0 `ݣ`f,4E\*@9FWu/͛.VqqP$̪`,,x7Z]Fgs6mhMVVTtlkJ}fvmCd֊y7,&jNܹMⒿ^Uo!]4֭ Wi{5֟7lTMg:71Yӛ0X(gdmPi ςIEeFk1_jg?ys~vK%4 i,fW@m2*MͽP>$s3ĥ:k*1@> @BD9q2TY $qhH`!!*D%#d-%r6D.-VbF@4!&E)20 [rĄA>5gʱ21.4CHֶXͫ7ߚ9zĦ%]b,L](Ee '1X$> 02u*zT,bst',nz{7h//{L[՞]9AhK>ʵ75arԖ?}bubWO~z8)4]KlkfYs-&mV@F0 J˜"}NgWLmi*荭=@39^vQi$5A*?F<8%=ָww 60bXXh!$pQQN?"LV~NSv` ֏g{P#x%lV$q&+e=WL8dC/9V 5<# u!S6nq2*ͽsGBj 1 f)y.1!r,>IcBb,o`q`N=h6Z˛uP;P<ᵮU֔Kf}?muƁ7oomNj3RR{[rOx.f2&q榘0eK 5"YcJ%^D"a&\0!+:r@tu+~_/iLl%U2;& KZ!)i`ik$Zʖ VwwY%\jeR-zY '/{;6^vEokUsħw:(<5Y%}[+Ȉj U,<`|j8D3+Ί3_̤}'laUBm?+&ͽ20aCC64Q`qIњ17 Kjp"Kfn( jVJ8` PxCՆ$M p=8k*?KB +I)9wrwy?}8Lo} $.[oH!Zamm&S魱ݜ6KSO 1'J8m { "pqlo$2#IDLmn7`7h8bըd[mGl/ &Qm314h6gL6"+%ejv 8eu%=Ѻg#Gf{,Xn~ ω-O _G9W쒫Ve9j@*-0Qo"Dɡ#ԂQ 8B %(l WBmiͽb#$'_; m ݸ=|R5J1{df[ \`x@"D",4z@`F\tUXBQMS: # (@n~E Zo>7!*AUYZi̖ͦHS\ ]'H%oF;ox\a~{~-kneח;hu HZj7QCԫvGTٱvO.uJ `acH \CArI Q!guW>m* iFn0T1OVSAw 2R $ZFe"l\ID.,cr FxTW$&oYmmVQwMj=X .ӎ[ ֋ܲţ|87Xr;^U^3Jvr 6B)`i0dAAHF&]~8P.9SiPŇ4pp34=#B^d5, ~*qONWlu,ħjL=5^%bn~Kq-عrw{AvQ5w)_䗛Ŀ)$w sέ9O9qZL_n]&v v#F)) .e+L2(2r`&€axp]u'BXEfYGi*i}yYW8nm=f ͽ<0rh8Y{(X\,"ItTuaj]6)g!@v4ز|XH_rx)\%ŵ>WU=$kcY緆07ѡֳ@P `Dc(_f("C7fr6P̊0(!X\fg'. $0zÙ9#A00pTc"($Zx%T"EEZTTXL @pTP5wʥ Ƃ4H⩕lM6_zi`LU+?bS#;b;sh3\7ϖnYzYgg%zu3տ mIpDO>@hte@805\YR:WAFRW.no * =$8<-1d)狏*!:Qmԗ}^};FC9iPp6Aܩ~ذil_r]+7VIuluˬ~Mc#{Re{],W 1\!V}M00V0(1h0  a  Bͱ$:&>g$AzT-f DP J Ągyxo+7-3Y%PGcv<&*kwmp.6u|gg:|Xp=ZMo{:p) kJ>` Ɏ HExΈI YQ!c皃1S0nmʪg =$d P`T VU(MS! gOXe5*b"/ I/FuĸezΚƼٚ KiJ4ξ]1;\Ϫru;+Aó[q}һ#(ɐlm(H\4$ %QKK 2*W8Bb/-miLk[~b[$[MzQnXF+V鉰Ւ3 ˨j;]U21-CGR.MٚJcZchI{GH9p5>Eff&t̐|J E-9@SuK8XǟAE  hH" }# YRJ t%Dyes9U=ag>?Oq>Xҳ ,XW@ma*ͼ)SA(0ڒں`X pɞs6t_QvฆÜ[pY-PriV}ZN.cNE,j?$㗗V$FZzB6Fqe9.[ɺPXhpκPkQVMs< Ċղv#yXn]c-n}3M;7Y!vFea,Y%ihwx{BaF< mn4UT]if]lR]D_nK޶IL%/},gI;.Rh0'ҕlVrg˔ᕩqY6{wGC{>3|k$<뺺xճwP#WBm= =]eɾx;YL9$ 6ȌE1ōq] ae6 E9Q7f\ꅧ;cSJJ:-3H4忕2HlȈ ݘWOj0ԉ]$2>WqC: KF]^•zkǧw,B{_f*uO)̭+ĵW p&Y88^'>uF1M:c2}#rVƲZj'Z͓E;L! DfoSJc9`h`Xaq kl4:2рW.nm-ͪM%L .Bn1hpDN DT6g!QC>SkLOu_H8MtȜ7J\c"%5s.U'A}72Ol.~ 뷻qtyg&Os*ЇcbHƳܢ@C`Pt^ @aHoXsڋ0 [Y`)@d T :0Ki]/%]YH@a*آB g5oD=B)J&D,+BDJ:u+6B jb(bk,[XDs+{=ZR~u?i Y. Y@BPt< \`)v( ,7 h} !$\B"x3]fKG@)}f,ECPQr;pT& *n&%.! O%\ͤ8鬢)sH62X^zg6@̟={30G; J*JJ?y < @`@ =F -F.CB@A4bPTp4bS& )0cs. FGB:l BW0nm 1 h1f)Fʔ/ 518JAPCX$ '۷dTK2`B)}س!p1 . g ^[_5EIAR{UO܉{*Y[ (p쎶ܞf,iy:ΦxB]@ FPPd<s"883ƂÐAw &!O OS&:gFfvbEE&TbdH>ȆКT"O2Zˆ$ɀU4௶f%HDAE^IisFtbZ7i9qVK%#yi'. [_œw+1C!AdHHXK"L c-!51l:!&Rlj1ь!g!˂ B 1xc`(Q x "i(5oC% m$#Z+@I)=5.SĒ; ijWdַWےnOM[KԽzpZ{m{Zz:Q3 `mѼ[! fA:P &)"HECàj}8G`sM Aa ڀ 428dp@d9 \ :??#+L TTs>`jswEhZ_W U#]CO9@ U-j|404*&sANhwS2K0VI31U3`!'RS4.r1b3D1 3qS2%3D(2B4AG7|625<$34h0@34:41842>1 =40T! jM<‚hќA`QFlHD8 L0lh0 04A `,`P2@ o zA"4X,0 āb@0 x0kP-]$T m Q$ji`@@q  $CGܶ3I*A N),&͐`#EQI3A@ u%bxVe ƨ0Fm]QPM 7Z& 'f"luB@T9 k $)Uk_r61E%Du|N;KRKW(f3ݮh P!OMD;xـSN&@20s| $ĈeYK!L-ڑژY2{񐡘P*JDMTq =| XՒ\K2tJZGiҍK*1n f$ bO,.֞fV tQu\SXlaw*j͜1P13T:-V?O~v()xӋ{^5#CG%J5՛¾<[eZiM6 |*Ru ؓܘ{$Kg2Zډ̝E#4T| ,q6jZ4 HmvQ5T|i>]HJ]np'Zp)v~szrR@(J]sr{#Dfn5l|{JQ@<l$nLhd8Val؋Pm^dԡ"hmE++l8: jF MzpЏ\!aEtο&n8Y_%buSL]wBWXa͜=Nkzˇp;#J| 4 ma:`S*#l*W`S$ ,ؒDD|viX9͖tD\As ` C+< ,#畼/}1ctQ<*_n:SQdۖ46{ݦ_2C?^Cker'G6zɪF9]~q#iS*^]# T.VC23-٦mLaL]jq)Ԫ `뒹|m˜,+_ ;xZg55Cï1+3fTTMAq !sC(yeQ5Vq %b{1-ˈtT&/l[-.8SiOo=z %潷O[(`(q;;g88~2zUz hVwCF@ON̝$4m  & "9\,%k&KoI#;O~%P\[K7fb<{.pN5X}WFm*ͬ.w_Ĵq :\0 Uݨɚb-&; Ԋ+K~{ QGSyBiӨR`lnx *4;+Bu+o1@#H)xպ 3x3:'=qᗽ$ E˦GfLշ9jGQcrÍq6ZV ;01zktr}.@"aWWţiHdNe\Len#\ Z$n<(ī+#JT%g̬H 4$>n0ÁE`M)2pu:H"lW)9n%e~v!Pv.M_TGLnjmrt|FC<q!YQUW@m* ͽ {q&i(<xM[o\5qx\iɮ]A RXs  ]m/;]™;3OcW E^O;\Q,ϝ6 p,6p4zl&1e6hG&9eR89<(bH>s !-^F 4d23 +֤(* Q$ b4-10Iң^EҲTUy,VVo3U؈rBrȮ@˅V/.Y俳daYtn4W2nm;*=*.7kgޭw%;RhYWRmĄ.*1£mO<)_2idx'b3NLi0].Y aYɂ! iPHEn x4 Uj}5 FDќZN`H!+} @ڃw ;K k65-YHp]Rs<G Qc=gpok^yPSGeJ XBIcP/ BьTf&@e* dN DgOS7^ jthRDb@j´ӏG? 6Q+r:5Ӎv~w gN2])-1K(=W2nm˪hM>_pZ8&XӨvb;DX *I\Ε@ !ULs &"*4pK t* #fq@HI`D#Qc۸UzE5Uz4RC^fkrMEsU3ac~<n#/q]t[8Z3%⻚^ņfD;4r0˃YpsZ&{[0\ cFjaa+1 )`0X<-+R3̗iH :S#M >gԉ0DoMqf覸&"⢚#` ɝ [rm'|R2EʖWI2vK!pX7{E^4,r~Ǥ>iXoFT@k`vնWfHĄAV]{4ק*ls@Xͣ vDtk7exsΤԔΒ+{Sy mR;]o˓f0I.LC9 eA kFujjm 1Qu 7.0iLX5:(p*) >ыTdzS'A"ʨ"iݒGQ&b](e>"D{8vw3v5H0Mf-Ɋc7Yo~Ijȳ@!#'ЌP"3tOi,F L"(0( a(8pU`o\Aq a 0Ik`+IyԲ3hy`?G/L}n_Az.>T1DZ.8wl(ƤLCJBJ,,_]cU_rӗ/"Eeol{+A3JL"yN0p"iX,,Kt .(P!P,A  `Si6ڀQ6ni˪f1f )̢XBY z9k5k") =I9G>Y%m~oZ k3cvt]˘T͞4[qi\GU \ Jijt (A`(˄&  ȴԜ)C6LHC( @=*u+^,&>0{kZ?S,ބd;15mU tѽBA' O ٱ#_Xtߦ3Cۗ}0t܋d!o>=\aF=3;>n,)wo?ϭE~ꙋ.޹ޯ$aU(@_b#@, 4a:1j!+A0!C= q, Ά)PEf@L;+1 vF [l ;[=9$eSnNf]iѪ[] ;o3r֏y }_}3]D#1f!T<:(“ ;X@iɓЄ5 (dhL+ql R+G &< i,# Fx` p,VxԊۋZ+S,n*ͱ,cSACp31暳{E]Kkn8HhHS}~wЧLͩ16MeΥ(Ơn_O, Ct"b)`>3'6]j=F``4"t >sBYBDlXdSp  <Fa,4ptP{L"*. K]l8 ";iDU. r> !hY |C÷Ѳv"v3:>-Ը}$^#ٷsZ?Mtdu;Jf"a㱤(J-ǃ  Q{)Scb ϸo(84B "< a1QRAW2nid=5;k 5. }g*ժv!'գ.ak̫tQ1|}ϤǴڮ>oό+Z㾊*ŘNgF(6AfzejF##(aÁABقIRy0"3})ZN\D# 7 ,SR X+'1@J@P̤Fi^8 xp1w$ѩ07._Zdgb vsvW,lRc/tua|1\ۨ@GJgOW/[_ɻ4lfVB&\ ̚|4 0 $р``hJa932OZ܊Vlc Vƃp&̴H<&W:mͱ=Pv}_*7ܺTyB,3kR+>IΚi0@CJQis%u5FOM3SZ jPޢkQJ%JAځ@x 08XӣeCc5f:dpAqQ(P/1N`ٟBA69wx1@e 1`̒b x+[=Y_*r5‰Q3{cz̒Z4'`Aǁāٷ%@I"( @Hnb%)ltL`%C8+1T&@Sh:sA8sQW4m*f =v"D)t,nNAAŽyQvZ -@Ze{&0F+~F{!53Cy1:w1xqzn(5l ΁2E 2 B H$c&肷I>GׄJ;F$@HR&gt-\9sf.T$R4yEjv6kv9˕N"86;u3܏I S JywZ |q{Di]ɩ1<2NLA8L<7 D3h$ ffnQ|JE ^2` 6HaF]@ķ1J); @8@q5fV"ʉW,nmfM=:BV -'=~u)`?vȳMOw j?rGh4>kDgSag =:dyt# <* B%6 :(PSp:`q cjh/@Rgxei8# -ĉmY(n *M-@UST:A40BUUDL0Gv ID*fS}v[n_,vuJ+oźv[qqIox oyӌIX8ou..S>6>3>Bj "cPr 2cA`X08H| R 1E/u5LRQaд8h2' _apd"s52զLS 'Dq SECU~HOniy9(mY㬻/WC&[s\q#tїbw;ﳀ7h`N&kc!` 1 (5!0*<dE biFŅcj$XB|xŠAW,niժe̱RG k']Xքz.$Clޜ5$:4ܐ'==mw*~LF>)YԾ4B;v1*55-lj?P=+@ 0E0v08A307#033P0<F ˜i bFC 2B`!-ɎrrS@3<BMN4(ʴ!ȿFiCg޷eW1s[5HG[.L ee{f߃lP+7 j/fdzou x9$`#{F3؆02b2d-5&bp(vi\g,pYnFɚZZ aC0"(.^VHzETS.nm*eM=^~KjO8fiu^Mɔ#;oWr3@5}Ip"cm[9wghϰdAqCfKx ~c5x;D @400ĺ楀CX|0m5Am8H  M$9&M$+(Uj j4O<[Pϖh9vSrv2OkoWg~>s?ƥ_]ϔL53 )n%H0x A( ,'1Y0t`C&!pЈ  q@TÁ O] fPJm S.nm*=\uvpMjr+ (,Pmyl3ܫ}w/sgP#֚uѽoE?_W<'{AfΣE\_3t a0X`JFhqHq.2 FU܂k@a! Pw9Jna7؅۹ڙ6 M2 !5DkV< =x?7ƠxX 0w3)kd |5142b@(#1I )A 48Cƈ54Bf":fP2  ܎98ys5e@sJ;pM7(Ne=c2h,.-`3g2E*5gqהZm\oƩt㿭9Q.ID؟(+ " A%v!Le4QvӄIπPi`la@0@(C b,? ꆅ2@qNB#"*NՒSBT1V Ќ6JرEQnh2j7BqVgXau R@˘sy6?)7c&0'YF å|Կ|}P (a6^%2FT(< p`Ht4K44c`r6!!@!}sxL |̜#+Q n4Dm Jv5i)N[S-S.nim2= FGdD\´hd]q0m6Yw.T]M3l{-kbx *9R $0;|ʳgPD$: Q@E=lR,̓k4e4#lt[b F (*UViTKaG],LÊlDGH%jBӃ6u6 QBe)כ4$sIoÒH3sPƏUD&YQe9+C} u&Xuch]|#S590/6|mq_zC3j&/i/|c pȰ8`D"/020uHL^ 0ISL$z: XvF$!(cBhZvR-[}8PJrr?F98\s1'MY83Sv'}(f>-1{ͳZp73}C3VE pSRId Fa$dQ1q0A3*X$~ kދ/ya\V~GA—ȑ! EX^i:x)Zli5LڿqRmk,>}cgZsg:ZkP=~36\ x~2ň 5yA41$ J(8g$lnH#LBFF$t@%"42$ɌXn`*AYjV7 ZNvs&thIb7,ni*=C#\frnIؼpX]iuEOM_{k0+ٹ㺎g^x?tǬ{Ưcz `x f B "@ 'Ud#0h >@e:*M@ 01s:}L, 0р@9o J8<lf1Qi3Y%0Iۢ1F? UD>i81 ;'wO75 3~N%e>=b]E.q˫[U4ă\4  7S&7NCE3Q#Ex.  arx Ð?D!M%FK  s4@d2NՁ(fC|pU\%K(ni%% =4Լ8!JQު>ϤHV$H+Z6Qn DOj{ooOmMpqҴwjCfI9Imm@FF m0bW a`h\ b8p XstT, {/6 & &ïi@@1B@A A[b% ޹ft)0X 'sDXz[>oj)zߙ<_6S=޼ ݮ|^=ί {ύd, # 2CPf48!`f T,b]v#$|")IBDV N3 d8p#ƒ&e`$՛@0㘈 Ȧg֝0pe S*ne*%M=;Gbu X(T?=1%6qqX5.wJwRAY"@ 3'1M3d1CEP@.@@0 o ăq(-8. y(AdALLT<҃dP̈Y$&P28{i'lUj ahA]GM/K'q ?Ej[ H`LvIZ=kN8+Tcb \cx8$2LE&RDH7Q J#mQm(* `!Q3U0Vvj`MheegSjj]wqdKh[&!yqn6m-ѕleޯ I~m|Eyl#/nY|:oU[DNl\;   M +դdx1Č(;ّZzL0 4EV, @\t|9Cqh`TɆ PȐ$I%i%@Ac !pK*niئM=R @2JX}O)cΜi]A DPi{6(,ol Zn!^rY)˛̱W $zn `!ӑxM 1qTy`cL` W `&P:,d#aHmM T!W,VDrVVC"N%e =nXiYHe] :]uݟt=?tATe.Msqa~|~ƶtrYCDC`AcB#4S9CbPà @FQ@FIƂĔHH ^U'0a)zƗd 7-Qu*0,( Զר-M5 q9z!sC;0J_9\!&˾{diXݩ6:{0/x{?|!6UDg`!J42!z1%Q13 ѭ\Fh= j)8fbd&_!esP~jXCC$)$nQݽȃ C7!,C3kU tPb(>!E0͍v_ PCV!g CI}aQWPC0#UEe>LS[4Sߋ޳Zw}ܮcwY?U嫖r3=Rre8kk+n!9_R5%F ' q#=1*10?2 |`8Fn**- "3Rb Lh*`QDb ǀ(DР985+ `PӆE#-,ڋC~n? OHZ9-۱Q}֎7R4ړnmqav泂.~}MxNVT%ν @"^ !Oskg"euaSxN5Ǥy 5@4ΥP B# 2 O:$HbhЅ2bD`I 5R` *`C:DaaAcd&I0r҅7B$02) AB\..jv}s{Ti.iՈSjΧaoOuGorr5_}}{ՌvrzۃuPp ~d0+ E0ic>0ypQ0s s=0@&0ZS@+7`(&GqY٨nc V`@dC@1qq)^F*5@&`dQ.1Ԩ(4 GIXh?@7.\0];#RK-#/d :O´ 1 no "tso,i,e`ʕ>{b:Lԓ$=O!I ғ?@Sa3sC8A( 23([90S01Yi (M̓ 8.6heP̐GF A  c:) ڂ Uq't<2xeuaO"Ÿ 'v+PJ):cWUԾ8~rkve{uhŐq{:6 hsA3GC" L T;[h<!F`D46CGh!NKe =$ƝKK2n06ٸͱl.Zli{V\G;m].1m&55nz~c`q]61`bk@ApU0@`Ʃ [ e 8ABS˅,1T@C23 %n4I\+z. qJYڑIm+w@7h8u39lW@_'϶Vsr>r|d}[k-VTA JH 0@u ,%S)x{1YI*HdUv4LdCGbPY~uLg;^e8Oaf["xB* 8m nm3&{v^B76d}(nk fMusC8?)ΦW u?mjJ4Bs3L#17Lp N,/MIt,Jz?-I#Nσlrm~2) bh^`/ n*ni뢮"eM=tP g "L AbCA2B J [ DtDTGtKaG%S,(Ti E=1-T9B\u'rG([9mg7s,/ܷI\Z*zٺ.}]+aշ\ ǡP.qyRhs 3ʢ!!o,-0yi`ETy(T&+PA+ )HV'`X#s*c[_k螗(4ʖ_nP}5Mn5o:<(RK&gl.nфM /XiF fHja`~gd,c0,e*a8Rdf4$@m(n բatqA @î]" MD LB@KrA D6bL%P01}t0ﱺԢٶ#^ҭNh 2$OVΫviml|K5/][E_c_y~KI̱8o6 j4b=Ć@^0rEcʁ3E(OQeSGC>0={v*5H h4&bRCW0L9v֢5;kw1 j;put'9_awz.3-UǑʷ*˾ky)LS#LC@ɦ8 !ЌW@ @h%[= N Ң auU$.Je&C#s'q}ԐR MA@e(GJbV..TƖ*A0NͤjHLޚCߪW=0&a!5?9aZ}/ۘ_˝ 84Ę@tj$;|PRD9T ߜHqTH8&nr"(f TGo$b*ЮhJ t2 6 r$Kp9A0h@c$;/qȔ8 hx`?^1rNƄ2鼎"ZNAwpvř}6xx˥[JZJck\lrQo1&#-d1ycU݀#8;S%0p(5f 2.5Є1 : 0# 2CS13(83Y?)*3:Pe054$2S4U?:(1M#;wL_@ L̴$ #\>ɳESZ33΃ c@H+LLLB$!yT2I1o0`L1 %HwXww U5!Oǔ%L0 \mbF?W뢬 (40|iLqaCB!+r>0 HW6eiF9p oVYMHBG*M:^S,Q9V!.vs/Cjm{IX`k9kH}]kz̯MvX0ģ3^ Wb@czio[)STmaM=ً lxPx3qdMp̈́,80 mo1VnL75fA$u`m?UQ֡ū\vbFwI9ۮeR367ḽbAPi◶PC^Ŭ|9x0$Mه)J@r޸qNw -۬k2(  ,VLUT*Ŝ)Ps 3m7B w?àFо}/=Uˇ !'jnX{qEJ3cṇ"aV&Pz3]N/uHޫH̡$gSpf@`J$n Vdfc 8NЮ 4`Ty1:!D-} uOFmͼ&9-ң6X,P5߆:X 4GC%Ew?ẑW̳nc7NQ GÇI$`0 rX̘TP"*ZA?(r&Y ,P) e+1@R,@vWxE$C1/kGqnOꄻucPZ=%lH$Yܓ0q[M!>i^{l#O}8_/;妯Y.+o&|0t8"|1"#Q-l7]  48d09,i\e:[`sp 2L8Sv2'5~OFm:h = @JɐAȨQ QSBAK!)RyFT벢!3q gWA2QBUVjS&|TEp1[;Tuy6wӷjXnFeȺiuKuDLkP " ޢ8W|@ 4*Dc!9g@Hb #Ɲh@D Tl +q153"Xt%0B FzN'9 !wbol-8:3l.ѫhܘACx'xvr gbMHon/ɘ;F"~-A0i]dQȓ9:)PPIM rSe@ 0rsh'wODm hM=B, @H) 2ֈ _I ZQryk/:K=/kҝUV6.sָ!S __3vݜfmě凊O~vhv,]</2@ eQDEٍ'.TEH= 9`@ 21k"2Ŋ Xи>"Z2ES T rD+c1T!9#*0$UؤSr{昨3evvX47!v:$3OXw-1YΩ/ˆ!+ n `F[1A .2A@ hV@S Y m@> pli@pςYEx rG+A{WDne)M̱b ե`VUԂ ޗi8 B#Hk8`B$*⫸eٽiO-TFimQ)g{|צU!W2޴_p"Yo!ޒty0QfL)A^!9SccABEϱd^" gL/Q x0Vս! U;Y`Zk7sH}c쒣Pndw٭I.x+Oml;ˬC۫#"oS1m`ě| ZL{f8}DRec9y0rf‹$b:MyY`( u!1ADȔ.KI-PJqd칐S@m*hM=WgNg J뛯pE-;qvjjyn[߶7/mw[W^m}:H;aYQ2Ob±Pb&F1"d3iqf"ӡR""f w͏KxfVd+qA@`Li Л )8wٜ55Dg*xǼ#Ƀ[ &iXڨtsFͱzymv yq]Mb|g˖'׏kEv[et|b`t2dȬ gÝ̌R48H,"*& daF9 842c‰8#Ly ARы H@(X8U9Hdvd9bh O>ni)=䥡ɣY*_ *mڑBwnwsb~wKGWU:Xw|$ً99$ ┪t  .U%fA1b]³TPz84tN0vtN@U=*`Vcr)4z˭QnP /&jslqurnwpzlwD#l;z+]gCݾىy2z臁3ALl1\ރ|2L (( Ѐ 1T<Zta0fl$tw ApF961ɐ%ڊkVd+F%(1Zy#Rf* ۨ0ˉ3A$hLȜiW@m=g =(urdD6*o6#k)"yuzM~JmHe/7uj&-p;X ZXA^fW';f`Ӵ0($Q2 (Ƭ,3h"C6P,3ⅎn ,0O#Lsg=I->/Ͱ#]q4,2e 1$@0@0֠\f`t6R#Xdc .}h@pQ+p*飊NkLUӐ\8іSs3}S8ni*'M==eNa>FyA4ꁴ|#Qgl7+\魝k6YTe֦jZ|.ښZ%ַ41zf|t1|¾1{gH -hQٝ4AeXHgx@F :dB(isf 2`!(2?P\0! L Aȡ h@h@RA\G gblU$6!:FIPUQ(רnI՞8!->LqF3/~5=ʽEs[ΥJ=GggcU A04тLmX p!8WJ0``PIA^H 2^ G@\aY6nm ͽ%2&ͬEǶ1kPRƴ`uIBAX8`a@ጊ!&x sn!Bo1  s `RLHрA i*,f|jZ#F6SK,9:CAK}qثu!ΦK{=?n#5pw͗2 :h.3=rk^h WᩔsR5Ay "$Hp8,'"B4Bˆ "`+qsX Pȃf,Tb›_Y6ni)1ϙT"}^VX=IϡCiSdxomt$fhٴ-L܄&\j[  3r~լ:ˬ.{#bkL6WۑzM^vS#7};w_>t3u$zfRiJbY2[FI L^Ty*ШG(NL SBņTn9'zf@<Q}C'BX)Q6ni;)ͽUU(Dn;PU8RŴ붠oI{B2S Ԃj%ze)qŞ^$m#L$88P|ϴds~|}D⸡P1dg+*"H5Da)d2t 0-َ&/& 鶪 Mۃ(kNɲW|[ hTN@sf;=.rjUs7 vo.[4'Œ J,oscy_KFRG>Adi`12(,̢JAA$c~(h4KMˆ$ϟ1#LuaC 1i;''l -x ;k*(LvcߍmGD~YW]ɿ1#YQ_>sN4sNԛ?߁Y.a҃ycDÇؿebc2LeȀ&8]%@(0*t@\CFC"i,>\9f,TLlER#8T4@ +\޼C=5͍kMǀ+޲>ໄ~Gs؊ڥց1?ƺv M7V<*y{C?\_h,h酃^8jf1X4"dZu# Fi&{E+p9v$PFZ`b d@UNL#EM}xWAS4nm&=}EMCt9GV|. 䚗8V׻nq|.V}Z6?ښesx Nve}wqe$W\c󑅛G7Cf- % &G" `#PQ5LqfŀfScˀ81J2*DSPaD)CYX("UyTYesEhk'R.etBwxƫ}QpUʠhv[X usږ;[@rqwzoyc@Y򻞀CEB˶4!X jjv@S F `d F6R 3[3A^/1S :, ](PP`@EMAO'\W6niK*Mݽk`trIȪv}OzĽNQDDh|]њ\sQXv(d$1BҋrϜ)Yf7Y.nO* ͽ8P `$2e3Ђ X$wL"* `H!WlMW:keTGZЊ+MB@_bSW캛s*PtAf-q¿oeƻN;;\SX{Sxsּ񫙻mPKtpM!MldB="bBɼS b'SdеmO^$ĢnCVlgh>+t>T43"sm"Pk?q4ۼ\L>Gmop uײ:}"a`|/(g%%dّ^~X8CT(LpdtvlI51HT@T0q)R$E M*;SB ClPm;J"TsQ 4}/xvŵDWFma*=7~u5q//[w8KI<<]j\r{,9ˇ۵ ~*d\*zb)l Z%oL20I"B #,Mi EqNԳ _60I>v۽~77\ kIfĬG ɥ5xK'Q; R\a4H0 dSں!%rŊ }ͱeT0PFT6!-k`~PaVPPP hئm(ӆMjyW;BpwvK&I~fg3:iVYW6ni 5_$T9ն+-'DK:Q.R6v 8P\\JNe˕F@E2C`LVT)O()S$39|WD󈹙E\Ȍj\|mtĄd 4k<6!BUm N^YyOXeG;399|M EG;:'rFHQ2d>D%7%Adt0TL1m |Y!DH gC[l7XF^?hlOA5d BiTQPKoKxZÛSEHֱXMFivxиT,1z &tVcBfyeŷ͇_yMˌ~,I"n4(;yC+{S@m፺M=Gt7y׆re4E0L3 0s72P5"6Bq`x 14Ѡ4 HHrC }AA41p2`%FMtvԌa[: T|=&q*<\j8d54 e4LpήT Dz6&D!Ʊ\,@!0@%@I4%iJ`&'$SLA.ok"AlVC Q20> )byňah'CF w` ~1kstAE{alZ/.Zܨ2n L´ [ǀ}W0nm*ͽ-U}#*荼&gI0V5)[CW{tX h'bL9fe\DMRAG15FjK.@6 X􃯸Nx߃Lx!B'j gay*4ՙ4$&] M6Iw4wDr3b.9ܔ,#֐tF S*Vʃ0I !8 t6eڼ-(EcUzJ/kLcFlv}mj>m314*Yymcxŵ:aď21Hn ᶭ2n0@0vFs oO/`)6F!+FA<  jAa!CɂU\:dEM(*8٥:?WRl*ͬ‘m\a}PJ #s-ydNuٜ+hU֓nO3->jvLJ+gWa/ >5juhs>Y +3 d\X1 9GAPWsAcv Txxb ҽTf_0@XyL5 K /2y'I<)AK(A$б$*lB6H|I2_i̵λ]3.0od=Ogwym+<7#ej Ȫf-lL] g1Ii`x UpBn!`ILL6iV;!X8 s7 &" !pA-xvFmIAC)eAIVY0)6QUlk񪗀WNmi*ͼ񶑐Hu:_8S^|1i) &J<}yyX}oo6F9UZx76nN>ѝẩrD1xr⸌hѩmnsVLWlEYʵ%E%Y4̅UYxT1I$iARɈ,H10 C [IF1% #445zCבW&[rF#юD ugV"E+(`g2Lyd@BsU U7;}ըv\kVI{Ew_R|_ͼm8="mz& sWJme *gM=P ]O5WLCE 0do3/LvPG8̠8'+0Q%L8(#:03>'af2*&QH9 D CD 6$KhÒ ݄Kt#8na!Q%<؞8D`U ވۘ[1搜[nX;I[rΤo햍w;>/K[Xg $lË6JT܌ɎPmy! <\8,4ht)UTd IӈBv4| pWj+3sWޤ7  ܆JSKWwQX!4KX 'tHڷŧ˿]_IF7ޚp36q[kPٖ۬FJtY4nm*獽= hI䝮x;k&E@e91\f[-Jg4YC!xdG s0271J0@(e$ P a40"@`(!?J؃̔aڃ FZpsqx8*!֩-H*E6ݢ6 >NGh}}fqyq4q57ji#qXcj/>mgsO f@%i~1t)JZb@IofXo(Lt:0(< ,1Q6 OC0ꆰDuR"P(LN;hh3 R[z!Pw%t̖]Ծ!\(BRAk`۫lO ½ښ#UB0uW8nmcͽNw}ٚ<7WqtƱh!]6?Ox$lY j؆0" (hU嶇YK)$Gu\bnQ F@"ͷhb]*VKJ qxz)iUֻ^ךq4zF>k[DzLƏ(u)ܒ,\VXrqƆDlҙn в8d™> 1(Q -L ɭ9AC-3AB#443OLٌ CzSX%dU!3qẬg$0!"+R]rk-I=:I^+bL%jLjtzo?5WBmi Ӵ?^ۗYcOtrݷW֧ދMZ^g*l#s|X +l0jT\ˠ03F b1GdL@Is 5%`ǘʜ8yc Q$-ej MU4 Y,Q=vRAL7Jhcuf.$n}o^r懽 }Km=x.)u*`CƴY,Y,{},7RWwG^ŵ}n;ܷgkPF $O]H IJ`lqDɗ 2B@"Ԙ4b, b*m|Ғ6t0 $†{Vc:KbGGƛ]BYJ~5Z i#uNMpp@F<qӎ1= Ӭ1؆Y iK4lŋai&|hP@p[Fh.ŦʫnvO_2a#bcdPRH/h$A!Ǝ&F:Ӂ"nFnB Q1*4&H0`c: I*:A 4HpL X&;oQ74`f0Σ~aMz>i3no3}C/A7OW+5?/[}n~JߢNsbs+-1QoA*el 4āNyтǦ°Y-Ap"3tuI=GsT2.2XB]贍@ bBY׶馽]zc[ݩKEv7U(Ol"R*Tbu6)wMײU,n * G>?{Dpfuyۖ0{[D;!zkPS:A$WB/&| Ng htњ Q#OY]XK}2 gLlvv(/TVcզ>BzkeQ&΁~%5v0+}I6-~)c_ gMI'3+#UV鼸}LԢ+ Ia=մɀ*9ɹeA!R`Q8ԬdvaFc>L V 01tԉ882ht,FD>*6<Ɂft)76(XD;$)dD9X-# s5b8yGΦ{HK#~m+QWBmac=߁.ŏ7kO pH .iMCY`F#&؃F`"K^gF7#AQ|< ",23<MtXL2 c% G# L0YRŬ02I/)+[\i) 2][+B 1h~u׺#(RC/c"XګH.sSRyJoj|_=emY1-^}ô6rGPTpF vX$RCSL9ha)$;7WT1rcШDj[:0#(J70Un©ΡwwMiJi5ư[eQ+swZH3W(n *M x3 ol]3Nq' S;3N:Q7ʭM@ST"821Ò^/Fh/Jr{ͦK \01s- HR!(>LP>KR\2!ecFun&)v7iqH),oO,V!rGp}͌hm_@2e-Oiɟ@5f dU.c8zTBZsAS@m፺*ͼ8GG߫e)V ʒcc 2"CA&d2H 1 Ẋ&Jp n :!U"{@#E ˱ŧraY̝Z![N(T.D >v"G pCP'gY͝DWDە.5QPc {箘h  !|iɁ+ T"}4^FMlw֗ KTSŞx*AfJ J;RyԋMLZL/Dn?[Hc,io}.ooTNˈyj}c0:kd߄;^ۨt%O QJi08@e]M4ne*ͼH؈yZb$鐂S'"Iu G"Q!PXg7=bE $FTT\3MYj8bV@ DMtg,v'}&v44 tpy߼w&uUsfؔ%Ng1OeDLB(ŶZz8`9 AWyaQ)F ],_  ;Ab6nkF!PN" @E`wmxI !QU[k$]{[q4zl -L*42pV 5Xʆp@n04 Tc&M2.a L٠B0ŝF3U K(9GN{hxtVZҲBOA#Щ ÆԐ`bZhs$&ӯ|sٜ!>|o<in|_i.<_ŖpD`BH cAXH1hB`&9W9CtłMb$Ô#g"pqxW2nifM=0b64 M1@c`';#t8ۍIɂj9-/>4> tåqL|giMdgnyKD+?kng j,< qF?4,a &eG h0X8XlhaFveV_ AMt7Hhɳv*WBeZjEyn=_YXn~u/q];F qK4Yl#_0XШBQY&2DNeFj@Al0+JBOyDE!JaÃ'Ma&/ɛHu@9K2niB+%ͽWHa! 1()ߧMn93SSn4tc76o+v#ԗ;`0ȷaEc}aѲo/&:Zm9*HWmĺ{{Wrݶ@ TeCYBQF*pDfV2x =2 p!G&pJIP'Ed'e0c3 '$( Lzf3AC*HA,(t\$Ftd2)%iGL%4ՂxI CPe +^kXtY9Z"߭g7q+%qluYthJyqkĝ@8`2Q$#'N)4Y*nnMݽ< ҃ t.D@ /+) Kȯj$厪((dNcE @ /=wlBH9gNC`|$Ʌ h(  xIxj(4!x4`lIY$ /+02Q0 9 6Daꀬl-Tj %HUV>tr,H,= nV`{P7; \KSzj>kqz`OŔAKLl4Lje!$ $1/3 NAW0ni*ͽ=UB3PCD52B 43 Bc `cYvB!U$TN1dB,8.=00ݦ9YbWt\?n]bd;ψˌI=~7oL̚+V9A*3#f#Pk(9v`a1H3Ei3ф%+Tk3CAB,u fXQ1 @hjOD?l{ ) 樓'55DRc㨰"Y_OK@?nhP.-p)kږ݇.4nWR $$ @UcjٚC B(-jD$Ma!`P 6DoA@N(aS4ne =" 2B97s_:P5&X  hV"t-: !F{+Buoz<3ω~3_HzutͫHZé@08o21p0 AMfUP# `C$!AKj `S2ni:=FjX:>h ), kcDB3@FsEVGw?"]@?H+*9T>W |{{o>7]vukfoYyr\<&ϖ%(g@,3,Ӏ u.AhQAhsЈ1`h(aAŠ 3+ GE>Ѱ0hFoԛ| ;aմkK ewiކ_?ya,չ4{R__M 6Ͳ͙5 3\<ؗo15wY)8uvR*Ú60~VE4&:V q͘!y11))UY6t$12HzjW,n ͽQ"PEgEA_F`[(H˓MXSaePr$ԓf >t;̣DEyOylTv$iSx_K^[Sw†k:|V=_O}w1wʶK.}m8U"LM2Qp]#s00ȑ@e9 J-4d&&drkFA11rPaq 5en. @UGF ,Q}b\ d4O;T`[@mC66_>;5fb ,h8YrkœQ 3cKitW$N CMͽ6c@bY>P9L< =Md8A@0+E;8%H_p &bР30% 2-lm*Ur?4R QȡȐ*<$[t ߀|pG֨Jq@\;`hDҪa5lo>|< }-o3fw52B論;MΧV q6Հc40mv301ln13N6(g01m3EP C&D`.RCFh2TTTW ťmѦ dHEdcdƂt26,| 8Ƃ Si!!C&J/k'VUAcBa *HUE"Ć{t%2SyD72r'4ŵvoZ&‹[EW(n+$Iᴣ˕>gg.wois\eyOww3u~F9lTD $eс?rgP FDRHAÁaH Y bǓhJjf ?hf u9N;rE8\uZBzY(T'e4HD,33,ߩ{&>0Q=V,o6u>q[uwn6iG c=?MJIi&Rs +HG;RHB٧QDJVakD.N$$-Јn7n”]u#ʼj}Ikaiɨygt5/pt6\a<5\O1wVǃ?|oH!j'f_VS0neƩM=-Gs6YMy02#0%1@462$"DCA 1Lp`&8TU3sб)AB88*X pLcɏ}B8'm'ƄEɕLl AR9Hanz|hwfuyjfBjo?Ԙǃ LBm|go2B2GuyC$]e;lY [RԵ`I88-n-Hۻɥ94oRoL}g_a=-`f-kf){abҚ{fb,-6"c1c9΀1 ,lЊ`@BC@ACȄ !GM0FJ[+߸Jϰ`Ǎxd~QXf%N."RÕ0#')9eS0IhMF+t4Ӫks,^PncA0eS2nifM5 f`10A`r`@y0<* H:$Y1H! C=qHXp8SY {ayD2 ;c^<$~,r`=K}MzQ_]S_J5ٯqϛX$ &".fڹ+et T4D11E .0#Tv4! E.bƓ $`EafSU*Mqy9)tf^7"kg毓_]F{^4 r7li,y}MzԚ4&L 0sD30ta(̢dˀAW2neeͽ@P HЬ.A 9}F.ǖ,5+$TDT‹"iYEMSDFm_iCW;y7xhγwo3,oqd߭?UԶk42b^?wh;O  LLN.1 2!4Yqbp`(b"aa).F@ \xP@YV2trE(0|h`kYDd%R wH\SS%,x:pJǸkx`y=nyuI=N6a:s7w{難Ԑ*' 15>΁cAdR@710f(Q+ @M38,؀W.ni*eͭBHQ{1ī{.F4L›f67!_.@p >DP82$&1 @GY&`$X=۟W$ex~1۪l# iwtM>V.}gxvdhF.+ 1|SQ.ɁNA2 0  ]3I`\ *U!)8 ( Xd/kL(Q+1)fGL"r/xyxկ_j:sy]( )iܺ-{^eku=Cj5X`R3\ Mi3THbY#: 2LAL!@v`dxc4 <MFdG {KqhC%J0Q{*WI?,nimΪͭRЖ̲I>Pոa !85Z>2m_6]Ro{y6V񙯽M747\jk2 jdj' lT  %D BbBM48M(ZT/1`cSU1 wZTlMyeĊZ3AYS5裫ؗvd]i] 6qrȗs͂Xi5n[|j Ұ+޳< ǀ>+b%H50t3R21I]53<0w Lu% t°x04;ÆMPm҆W,"q xLA M tʁLpQM.H9U00RSQ@K,ni6*ͽ&2֚nt0= 8‚E>IQTu34Z\Uz'sړ;ͫjXo M޺{Y#_NR`c޳IaqblhX("Uy$a8@L"zDpDH&lpf!¨&(lEv.c+r#i9L}>R?8#@t$6 bx"Q7XXc)z%hLvk̶&{x~/6x ǚ_hyV6x;Խc?/WլN`4FaʡZ$70& @sv<b"LP0A*E))!bT_&+-rW&niT%dI!q9?,SjFĹsXi63N-:-6~>[־s=q"@`3lƒ̣@@b _C:xDZgMT%$.jt Ǿ KMLPϡů&6ڄ2ܛƍ2w,nT z.FZp=y)|SƽfL]gf;W.l^JcXųpgMWJM_~>k\V9ٿF20P3D`j\0|ƁٓBs+0a0œ2cہ͝<eġf,~bdaEqc*TA84"P$@`"dC(h #*niզM=l]>ЖIFcaC%' 7.x*ʜlߩ_zvb>zgbֻr/phQkgNU«gtdeAxFV ;DH\`aB <`A NRfa84b`Z`a"1c # $ VT,?  $ofA.*.>LҸ1"1Zq< $iE$cK2Gdɗ~c:0c02BĒHD`bHa1 sIS8L.ӹ%c#@tiO!p44*ŠX TM[x'Pst~uro9efnc}e-4ܛ;mMjkx {dPb$eAC?BgكiD`8K> "Ϩ1LegHS8,`0H"Q-Piż`bS83KHC&e#&niܣ ͽtU `ol/cr;y"\3(hNئ;ӟe5)된ji_S4~Mq>vV&4 W1#H `B3ϊBM^hkY`) iڙI $ρ'NJR8eυ7[ni20ƻ$NjXoXXP/M&6 K?qj[D}w{Z9iJ0h bte3=̐0@F ʉBa;4^7KsĀ,a]3St`2!ic NDX0ѠPDm3ĀaGbQa$׻Bbi;KDrx'+&ni̤$=tͅTu:!c+^^,7<5<9(yqHͥK?ԟ; BIH3aPfL6>'.hY3Q"3!xc,3G:§DbF0H`@䂣V"^)ITYRM2GCͥ`,Jst|02[\F B M'NkMuΤ7c]jAGӗSZcP ZqQ}@ AL8y1IVL03a(1kf!I&*kAUs22'(ٵha |l݌/)< gX'/.7>it y?M&!ϙ>i)4X`Yt!r12Y" Jf 2>(0¡@A2 2")--T'N kZR;V5 ]B$^H%MV?'ɷpkɼF7N4 3>uy8ɀiA01@QE=1 ҩŢF 4űPSI0a4&" &22c0W  6afh,&0rC"0b5znTy'$nm$$Mͽtاㆷ2 ZB-$p_ d;^i~d9yj/"1bfif|9YNxr֠DPf!,P8gQ!@V0i`f ރhI p!pX݁@'$\dCL@b"@*`"FPy2ćBH-2P`JMGXàO$dƳM74<=FƈNׂ"O}0MgI<{iuMKK=54JY,,rE"9 7LD& Fr)Hd9P&4F:d>:30@ Cb A1F"B1h'ᢡ$C0H1#"nm$dMͽ}P"~vPD1'1*Wcs/PP7hdIHV*Y(Q%ڥOlMԏ}3~ڡ@.&#xq‚,㻵 0agj+˭I t`&8mee(0``ȲFH L`\؁`afV $(VZIfZ<:rrOT2Qrm$9ECf7]kY1?Lb~7&GLk/ksPGTF`ufEPzyDS.e85hą󏏀s2 ȹ 8# d1 %1$ 10D!3ZaTD 4O0HLH'(N$dFE-qۅ#@Yu4 ˙6-r:Q\]G`zN1U-'ƉNCEs(~v:=fb]wXc9}'V1A\+ٻD , 2dX;dʖu0fqIgd1 OD4L4d"cxiiL•H 󠋰&.` gJJ6y#fԃinsWAJ2v4@f5^@5P?[W6Tz]/LRW8JC?\ A07;A! ),HB 0laFd GLf"Ebl"Xq@Ɉz+V Ns  ͽ: =)!y{VHܱEBtDV4vU%"S)>rN[nާOijhP'.Z&$u.0&OXe FTqՀKcގL yɔ P8:`=0cqi\ϒ萪3("LBaEan#zz`^#^F9Mw2B.meF5͵&LM訖>s[ (|.SVufyjH=fSEU`Pb%ቻl>`BFEE' 77A@U1hbCG& 0!E1iTY8oX,RA"t" C@"bM- "nm䍽iuI.iq;6մgCm$SsՕSA\_T=-0LĂRڔ@ˌ5&FCE^ǖp2\H`*"32S| N^;{!) |BQC"ACL2`HZb2dGD# `XJ xB 1J2 (eF$+a)Ж^`i, V6@2tמ4IZԬd5ezIFؗ z;TKb嚹+V ]X~nron'u_]_5߹!l|xۻP:@"j3=x3MC]!9APO5°}[ɬ(A \ X.R]#b`shQL\Ãht|4LH [~E}*n%in8;HdYsf{{~lEm=m|֩_`zg, b`Mx4!q /No cɽ &K dD T0B1ITpHd4=,Yb0S  p(eM+f/c5 eggRPq8pSΎ9k6myEk.5/όKcQ'-YE11ڴ׽1|W}H]bQ̆Vh IZNC }Hi!qX&0`&Æ\/a!) "Xs Fb`ē$  5 _z~S=qI( !2=MѲ*@O 4fb a d[Ky[gHl_Ú-LTܱMG}oL`'"SD%b$sЀ7$nm|I=!!hł@fxF\A` ',$ *! I \LPC51{b\U#(zyv H`x@|)pkAe B?p:5HyFٽҔy TŻb>8̹oHd h)^b F_  PW4Hzf`)ņ F@4(F$2%! (`q ,w"rG@q  BC &lHYt<#C $mp4/?szG4z;j3[lG#up%e$yN9=7O>mKkM&*٬ueC墂$52RB$\ Lx`defst-#&mm =tƘN ՔύLesU$2C<HG%hT RU#@E{%l;'F09`!Yxӛ-=jdU4FmGj^&4}|fz呾5LH g/TbS`C!Ts8E⒉:阥9B8B41gQX0S*xq h  P؈lL0\yE`-?Úypmw (ͱT]VtYp,"jI'EK,yܺ{ԛυ/Pa@?0UKNBX1 ч>d`*N(L)р`8D!"m#䍽tRi ݇(d&0<@" oHpsEw[ 2y0sN xo1*G0($f0Y%cE@cP<(4U|Q1`$mQ0Qe0U#"nm ͽt[[F3PAa%ZD>܉&Zx8/P "-Jn%J KQ+Î>賋lgP:xcRY>fzzTҍ<!-&ƘLZdƃOH4_|Bo:J:y%{ ,2q@j(0A>\1"s(A2I A<4G0X1(a.3S,InпcEZI Lx!POzW{Z띞,kCu_-j P7-OF)a+Ya&4rfZaѦpq 7icV> "Nfe?5S^ vF9dbmٝzۃ/_l|k6p׽xxXXu_.c?[ h`F0vHM`zc88HŁ .81<"b0CUb&A&[ `ldP L^Eo\aF4O"? [MGK:F]zb2xC$>X[f1ŽgVUUh?|UAjqLS__:dkjT1UОD/ GL24 O@Qp1@@H .m(`BL FNE&2=Nq_#Iat5Pb05*d)`锁T!s0@XlLi JXua\R$0=k>ER[.0~70CZB(zc5v%<];9FWyzYT:T{Ϲ뗣nA (#"  &GspsreRazAIDq󑌡&w T!SHE7]`v4@̤ F $3 X  &!q2*лhLqEĢ(KGN0(r7QKDyl܇?=-MijՌoc{w5[w 3z9յJ IrI?lw~WEfۓ=\k3sƧL~% _˩=HY$..3"nm$#ͽt"|(ffc5g832Q̤Ġ"aHL~D;o4&\L8easLYwMtObu7瓲>w?60qMb7=.aW`@gs&b ^Ā! m$#IݽtfPƦI"L2`gE2 hͼ"1i ̄cѕC U OBAhrB%F0x  Yw8L-]Pw*xdU`掮|ڜT?_6}f[ʼn{LGuCJ0Y3621zh7]3D=26'nq닞pߤ$(r0(ia\FBTb@ #xL.7'A0^ 5Qa,-<,4L8GD` <,fP [w{y1HjY zj n=Ϲf =oBT&{g;gγ暎ي2b{Aleޫ}JsK c< e( k3~Sm^ӻ{lAcy?>;mH%r+ NOSHnC=Āe#nmF"at x\1!~Dh1-mP1"CL.8@rprd6`Ps! x 0H:L<`Tlie@Vid%~];P~M-#isx*e1Z?N?7ڒm;x7:ϱc·x&d0"EqᎀbxU:?6R!ؙp рM/ffcF*\`B4hZn:0 iE7x$bLwTP-y}l(<do*CP\rxHiu.M6?MG-E$dMH<.n}U9 W羠 @P S"*}ǀns It9'6 88GD;2D 9S sfF 2(TH4;\!Bي 0`5+ERmĕ'HDTКз'qh#^M,ԙ-M[VHSs:}|zVk8%OY.{IYajP^@za*Ysћ M8@E"fm[ 0$Ixf2l~r.5Ttr,7rU`m6Ðemn~k%֩[|sC?=U'ˀ=NqE# atL`51*@fcs(bdFWL0bLӇ c@CEp L r&8 , cǑ!!I J0 "5ri| ٵ7L-H$",ux8TzMnN6ܝoXI-gpb %KtLxc'{9 :ii #J2$.IA ĉLx8 @ $ Axr@9)"hT1+4Xݭ-yeM0&BݻiMu7^Nœ7WTי9fĀf-L2|5S3F&p78d0`!nqТ㍽t bmkgNAM00#0@C䠠Z'1bbIF9Mp /pqSP;txXJyE)N+4 # ii~ɿdΤҢEnR!f8;a d6)liL0,`! $ a0p*10ONt"j|xR)Ox%li31YV: Ю~EFj>8[_I_[3O|cwx ^2KJGz@.<>4wΑ.&_F;!@ddĤF$"mFX&jYր!nq좣=tD&^#xT:2>1t 00,2<&f& FвҠ)ЁtP @ B' ?MQ M'INq-(5lОzO^6щbkڒl_ǬhTؼ8b߿ 4 eAPԪ fr,0$@9Lm 81 3' "ǣ@BAc z .B&* ⤖aJHP!Fr`1!]Hےj}1. VèHWkeҋ?hs;gnI$vJťunS cܣ bb@1ٸ‚iBc bL#n#=t0\3 )džf( b19b &ct :JIL"vC,ED.tōR]2Ub4JI6mxTm]7_?oiog1a﷫ŋfoy#P(HB& `D/Ü`P`h3fIaD&"`^v` lagH8^D09yB! i)QC*VP!ZaK؇!,c=($} Q_AVgȋQE;`O:>=UHumڷ ;=x~Zߡqƾ|oenwg6T?cZ@^&f8ހ!n룑 pŠ T2(8X2t 1023P0@ǃ ~;I L"BC H c@ &70tb"xăOi03$7I*Gh?tu29yh^߾3Ux98mƥDD}&$TFUΟo1=kJG{zvA$ D*kͨD,#ʪc&vv 0 |* 7{bѱw<a$?@(p2qPr 8NJ@E A3D"^"ҏzT9>W.εM.!;DEԹFS6YQi1bXlguS4H^i{IH$Ko[[b5恽: 8.2v qI"cѝ֦}( QF3|#n$cͽa-0s3ccE-1>DRFBCqc1 8X!z@HPPjTk ۑœwM-85(uڶRk̾x}5AՋzρ8 HX([0d2j1]7* 0d26; !10 DZ&lxD9 dJfHh8!8L #Lb4B!CB#?L5&, $XD1!<5/; eP\e R`_FYtBՕMY ˊgl{yɲrOS1MgWr޵l㝼1XUٷVU2zWڀrf;:b)0%"0B؛:* nqp,DF490悄0Լ1 90280 22!~O * !_ ~L}L  &(J`X hHA1 "C(h8MnݥL.񿃠iB4Ys'zCT,.+s4Avww,2/oT|_0՚oBTNp:3 B @k{_S@1X@PC1")[(iӯ 5+*2IzNvn]y&eڵVcD; zz% H]ߵ9Z1ySt[2076"YҪlkZ%E)m[(nEnܽbqHYSʡZdZٚIZ見]A(BrmqdN?'mv7iWP`FBfX9h!C@ fT8 B  1gAC ` kIf 1eo_xc@(((r0vcGH*P* - @AψaM!=Vz&C…9 r\]OsD:lH)ag*I2bcI/BU׷*C82w.P/1ゥfO7kworZj9惇Gz?nKvp ŖNY" 9|hzUpoL ЬIF˓z<%e1=Wnb"pT+Yv^rE#!= Z %@E5\B@x=޿ʼn{'d'^>s8OS(k9wuIAO]Liɔ 璥 ]Q-9yP ^FX*.J^X, 3B(D9~H,>:dA)\iYk(f栢bòvQVfL =5<@y3VgEGLM"*Y7^Ui4^KD؇YHCNdd&-MpwijQ0:> 2H :Èe4hb( Oxv灂=9D%g(\-(LYERi\&zg#ٴ%GHKĤVjUl}۫3foORzq>ݽT֘S?(,Z{trk֩+ AjhW&{a&6,aI/s }Lh)yCnUSHm*荽1y,8Z4*fXJIH_`fz!JnNa%\"i7! XR4 w37rw\?]f~L})OYt(yoyZPoYϛBn^4"pd 1ѝfX &IxlT dHBkvZ ]B!Kݝz8|  쥢^;R hbP7h%Sa\N3_*qV]0 ĿfXJD7x**f,TTM0 ^d`ET|sG6&Ib0Y2زPiq^ZkqĮ2s}SDnehM=BAL s\ P[m60ȕZI߽ٙ DXR+w?#dƷ˭k7=& ˚?gA\?赻{;Xh at'Y !ᯏƄY(@;vP`&ّ,:p\8R&_>bh4Unt\HD (?7ĔԟPx>"™Tyyғkt!ROz|1tJX~}elNjrr1J8uL()(DB#-^fs"M,C)\ǁA(BA .M }`u=Q0"F̀`iHO@m鍪 =AGȯ ucz1GEs;.jr댵50NUbO1Z#d!jle\f:Ki5ػd}c.XS0tc-kEvǿƣ>RAJ1rYꄍN.CũDPpKk"4f £힄 O!QD>;U[DZ @ufR^~xi sG+KK.ysA.E>i-ni9a-$ ED4(eS>ni*荼X^n8 íd%L=5)8;Zf#M&L`0ZBGAfq:HK{AyIN tQ`(x рiQl { /T!L^&EG5ceǖSOp[+y`|}qkCޝ©.Vk̉|RwJj=hsZ=6.R 51NDL1 󏅌'0%EDGY0m ,ȕ+G\2@ahFJYvnjս䄳6$hfS |FD4- cHFJo -Vx3}Dl'&bıO 6 xmZm-WU:ni )=:r MG }A ) L.>8 ¨ل9#xhˎd-'HÄg =+Z>}7Sx ~sx[U*ObUg9FAf]zJb1DtL ƴ'h"5eU+<9:.u1&S;|/cXH_o;ɵogz7 XP411|9,D")v4  \ Nyj LFM,׈BĠ`a@2'apщ 5S(ea(D:h6"E'J=buיRtBUYJK&qsmO>wV?.?q3\B}q׹_5S6n=*ݽSτ.GX/V{*znhQ40/Fod@1<0@ jʆͽpELȊBm3dB&>#D$8TS}K,8 JB3(Bk9pCW:"*b"d)apʑ~}Tֳ\OW+iׅux[VNq_ X g.tfG n1} j` &8Yj BMLB\U-" "$ :AP $10qVV4qL!JY|&5.ZP' & #`B7I,:+UIVqLpɅO*WQ/!ǖ)ӹ9O4nmG*ŴN,ˬ? pSI$QQ68[5!2%cQuZ %J4fVɒ$F,o02HٴL9A T.r@%3v$NPb gSГi1}H^?k%~{/B%NJzPg9ȓq#5L;|]?xy]\A}7 l^kJ}ƹ^Ā a.\g1LrQ<)L!$ (/30Tր gġH#I(&x ; r5DWJk/;GMb)rrܨTfW =>61:?w'_#賋knV>Q6ni©M=yf tb٭YE7̋5FcšLfs8 l537A/"!iD BLDPNP $@ KDB28HlvQ +F(Bh!$Xe%zn |G) 5_MM#]]n{_mݱ >6nZ|,ywgl(vO/4Խn/M7A8ͧ0x(#HX΀g D6blͅ(Aa#ވ*<+ TvDP@B9*Ȍ<1u%5a`${÷Vzi 3ɼy( R&#Ұak}NϓV!3-u~7?&A({'̦wW~QU4nmC*f ͽm_:žnL9:ǒ3%];_B U6. >B#1Œ5eH Pf4&5P !ʀEihƇ" C.ʎFT9 b. rvm0؂(k! P2ҷC.cZX,2o泼[0}~/>-6ZK4w[H «7ixL 1 bAA!02Ya0#|D$ ]X ( 0Dנpۤ 'xX",;ٵ}w|ҹ/r>sZ1rm7wo#FٷW~ l=>'rn2m3rWO<S4nmͽW§s|IW-Xf<&&m4GBHtdLcq$f1>Č@HɌZď i 1Rdr 3S1YA"Ǧ4P@)Ɛ]R ]ebEPP;?{bjlb j}ēx!2Gۏ ߬3|ݟgso*?-agUr CR4|o{MC?c[ۖ9 p8{]W@fanm>8aґ5c25hDb 1<2A`A"hs8pHNxP,qf45I?->ư.`JrR~d̷Ý(R5ũ`UcQAc2&=3zzjvindYnbVjd`,b0&D#񫉠pS0hdӇPd|9CL 1p8dLafh IAD(%p0 t &"3 ¾}U裰W0nn*ݽ2L/FVϤaymXrq~zގ9Lg=HSYy \㮭%woVtЛH "T`Y9*6 (S3 8!Дa#y.pQٖ MC#!a֩+,ɂW1l !% f\Dd5]mymUng\Kq^-χLÌM_.=y`wG+ Vext@6eF/FfF0x  f$F**et$(mh ivOP>wgzwkB8Rê Zl1T},1Ąs6 #]e;~™ sJIahc,a0[ kIU*nm * =7q-g ( N܈ 7oTڧKABcAW9ȇZTBy֒ku.]0Zˎ\2լ^^mǭst"Ոrx̯k o`Ңv 0\EL1"X9(hv@mP,Q17E889@˙;~sMCzKzٰ;(B%2M{F1PF)1)ʄbD@ur(B |,yE(NT X 1ԯL0%DS.nm ͱBC5X N@b$ޫ#B,-71lV3] y>5ՖvV~L=;z8/}YQKLf^0i@*lS \p,db<ʲDY}3c2X1L8C _3@#AQu8nEeh1Ep\XBE %>S/(à@"ȗs#$2#J5l*~YT^ֲ[-+kuhش};znM(hR0h,zr7K:=tV{/gJRf{QtooX"b(L \a!Pp(Ng㑤GJ@ C2) :8W*u݀$'O9P R@ƅ`3a Fm2`p1P< @x0A 1`b@ b.QD O d7|;#xXՌ;J\Mĉ,t_S`@lN HM A-DtER]e1˥#3 ffffTMdLW>Z+ƧdȢX23_ԤA3F LQ7a%Pʣ <Nj>Дv`B<ˢ'0h)@7ޕ7FjrH? Һگ[v77bYA{sM`ISX:*݇Uϙח \S H҉p%3ss(>CShJvtK \vP&u$\QQ~_8npMO u MW~a7>o__}>|OI/qHMqO?pPh'{Œ͈9j`KDPEs0qbFe 2&' Q6$)$4@L ȴ;R 5A.aԺoOGDufq;a #2+voXC0ۥ21q?'R#䪫͚9>X="Kf葻ZV9 aQIQ4К /YGz/2œ!fskth`l$n=WVl*ꍜ-K&z\)[sWb#*޸tn) *Ȓms$֖oy9톿 οp|GLT[~zđo9ݶrCmUi,vfK ho(J<1@TdIeE'8 &8Ӈj*IM2eLD#U I +HkT]1m':$&PLvR iJuN>ߛ?quxy]"$sqѭ nKTfDQL Q!yA(U?Q8 ڒ.l9W͑u%"-cA |,(&~3CDOdT~:?f\_gf`8>]WPl*M] 9 ُԳVΑS3"u+?dR9zZytLbd7K}'t S Ld|:<^ʼnL2 50G 9b̅GTxm+bdDA=G%\%@T;TnDTCH۔{Vl)՛ƿWkw%sqyY|bKicYn<Ĭ>/q-xApgB1۩N0d# *qbLL0f0^f.qc1C1( vz0LB!9;Cqވ:SP΅@PTK*'S t]]=߼.%utTJx?q/s_ȾS<:Cft/3U?qQ+0VֻB|}F_)O!֍g5kMY]K2{ ڤh@|3,&3(L& =mTdX (*H:KA 4(8z&$ %$" ,QH%/ #4nDŽ# *fH_Wjc fK!n< gY"@7G!Z;Lb4L>N:΢{ƭ!6EQBX%47؉>`E+FEzmW@m=ͽf>I֕iB"d?&!q?*)À,H Adrąe7rg^@R~j9#/zK7n!AR Рw9L*xțzV|:Hb.cy2ijϙ卹Bʙ^xݶ7x< 9\fb6沂Y"4Z_V ]wGK߉vϚu 2Qb 2Pj` TG-WHma%M=.DmhA %&Tʘ/phLIڑ)WMae Ol?9Xξ-x*C37\['}Q͜fkZ+hs(-6\k M5!pjҦaafPl3*1iF %5$10jxc!x J ` NX`P(lߖʺL8 - MZG , VdJd 0@IuBD=Ehv^̓zމni8fBkLMҮ|;>|6y{7E%K6fC"U#%W3uk\UCQ^%,j"ًF_w&0 2B9\W1yhɀD\FH E^a!e( EAE!BY _#0m6S˩EfN=ZLEge;BZC,ѽ+K9HepJ]aQsXRDڻW6m5*fͽ튴˅RǴպ]FhylÃ5b羛 0x$G w4q&31 1ȕ30XyQ!I$ÃX$fEv Ò"*ba\1jqpgH6`J4Q^P3 y\’]Ii #p^ީ5kdd֠9G]ZƩ%ZrEq-KnP,nj*Pҷ54rܱ`ɂfliiź0Ȁ; 1pbV m!y((qhDTLp!aIeTD n`P2ZkdAx.aXf7<9)!G#$ck>cnz4;^{Y9Lbˍ~1;GLqW6ni* =zK_}c% ʂg̲^#$L&b-e@hC s_5p0:$(.r pG| a@y|HIIȃɂHGA0۾' e Uh׃[Vվ^yd"Zu3a°4e;utj9Ls!t~ke # *顊 !L`ˋV1Zo)daa@3k :0Nʮ(V}[TSecXWe`0ьo03<$<6vIlX__,-}ɝk֭3{V+YU8nm(ͽT r8}nץ<55٥aGs9ɾxrq]+{EW2nif=0 aTOAg5gkDR$18ͧ 2FICvc$2" )ff";5$nh BRR3MX$!76UјT 6JvRx-Z|'p[[;$Sۓ->{;3ḻj[ggyp% ( Fڃ !C2P0`DFh M@afđ  F$dŒMn_GxdqQL@Mk]ѥ/+E.J4dաWa;$f_UiDm߻@UA]עisX W@me*M= 0hb!GFuTiLФ\@3@m2Xq@94jFK@& .08"hXRR.\A^4**ԤFrטl)BNE:znNk㠯Ms+;tfKwfcLF\"3k޻sBh}2Cͮk@+/q,0:Gc 3<3)lQ20Pm8aFś?* Jg db dp0q ]ӎ*HiF^`BQZ.%I5,J-}n-ie}r\zK5wlS.oMnⷶm6d]}an3RޠK^W0nm*=u!q MA  @4NQᇀ$GP_x sxuH$jMwJG]=aEs849d,0g8ꑳsҵ~֭[pvehjHjTW9#?Z_(A Ò`sIh=фs fv6Q& +;V2AD#E",CѾħ/SclU蛾A<ԥzzkCW+r4CYCEj.&"sr"jY~_>6b+(v\ʯprVfRe!ka F ˆ`1[f`ɅE4yǀW>mϪ1;L"#AဨbF 4:61d^KM/$G🨿[ܶ-H=br!& %k Ah$\F1YJ"^w6kk̇U3sיØO>rӇ4Z-,2Ǔ L?0^Ă$: 1iF+cQSL"q<`rDH 8)Ewnj1 H.2x-2✗_"P|z!Q5XȡÜRnb)Ŕ0yt٘iHYUuP=u AuG$U;A :q 5L:31(4 :A@ FX\tHĆHFR`0tZW4nimҪ̱p8!U=Ǐ1UeiAra(r=Ӳ7rRa7'76tyV&!i[bw]/?7fqNiBn&w;~z֋~R?iPW\8= 0y )̕ L;c2ލ Gn ' C31_0L=aҊwgա"å Sx*71%c 137AB%nra t*4AW_e0%[W2nm =4))sbK7GJ@ӟc0b0 Q-KmڹGKI7kvԘ֧~o~wz=ܟY.5/<&h΋SdLx10* %. P@ HYq pȩF"BHXZ(tMZ8lx1ź9c3Sm1zl?w/XMͱqI6gˆx]wxi7Lv6 YKq<͡S@jTLLCph891B8A$4ДB5P0U-xǗ%Vh pV׊xJS0ni*fM=,9CnӥYBlik40H8cߟOD>6+6wR;{2f&bRij_r`ȅF!0jb:A>+ /,@ `ɈQ(*2D<$Ao%8ZG7ira@nN7lAsKOنEs-}Z\tQ;W?PL'X_>>'_Z6'6qxVL~ۚOj@􌰜2h ~M)0Hi1J`2p *(DDI@,JU !Y64`,yyd6aj3eyL6W2mfM=V2PF`&jU &mgǓPB/s[$lbxQ%M| "~ M?l& bL`(`T l7hR TaAFCB`E+%8 6o|(H&04 _Hf݅HEmN#ib0Xܚ!P'\!i{ܓOVjo|MKr5wgu$71}!VԗYk?`0p s !8C$|dUђ { IQa0@  64ÂB ڍhcJĀFaBbDF8H`f DHʀI=)W0m & =p ZSM@)w<`O rڧH:Cwyq>)Jy'"u3byKAQo0L?3\`3&̳0Hg ƿ˫xb#R|L[Rm5>ť&d sK9HS=Y*3S? 0` eVh ˁE̘t12bvf` |ha>aR`LXF2hdR!3F]Y,nm*̽0tE`B@%MMEY|-AjIP U(]C.YH*JackIh>eo] 8;KYM{a?f5H& ,S#yTyPK2IrsK:`a-`/l{ڪ8DĈ*͎$RDT]xkU) l.\gyr{R;1 \mmR'+wgxݮ w BZ 0SBDk0lIX`P"(u./2P<ǃ0 H IW$N * ="/JIB@\"XoZA14C"Q9k!d?92~2f %pդL赪Kfyr3~_-}l?|x9v|ό-SO^5Xn|j|Yx$h03.1.15P2ld21d30?14FE& GFDEA̛l00]!0߀g$ XW$@M䃆*eO "kp>&+q'po.ħ:k8wg>ev]Ґ0 hR3/ @Ł W4m*@&@(bN ( *,nW1J<`x#x Nl0b3 2$8vP.ʏHiD\CAQITY8|_GDT}%PĪole2mRz?kY'SmηWgӁ r:z@$p@dD !7Jaf'a_Qp $D@%L W*Jt<%6T9.B %bnY>B) rȖl8B wF*`|#ZE\EW)v] zs[kY)#-.̵9;Lk @ 9QA04a0BFC0ld4h,$˘"jMc liBA5IZ3h%K e)ƒ-1Sy!Z,y/Zgr|JS23ao|9b6cݱ9OHm卫P+( =Ca&}@+Vnbi_S4p3Dr^&p(aF~% ;2uѺ# /9r>(%f&qitGBG$Pv,3sːZ,.3Ϛ<ȯC &4%R&# xD˄,R ^5lwdN׫,KV fzⲸEGN=j`<&p;Ht~ 9DE 2bXZD;+温Y~.dktDP D2@ᝎ Lq@PeR) *2Y|-~xX `ĖQxAD͉˜Z0£ P"ZIj"U1V; Ck#e}4Ǜ|Bt tyqo~_4Z//wn2)/n;|M2N'YDfRD0Q>&t*4iAkC а,"(|,(vnȮ5T~]R)ԭQ2ȤFtT2pC/\^I"# Z:} kDufTGZܹbdBtODniͽ-i,Y| l?gC:#2/ W1F66b84$k 'xgf<X8U6%14-()`5T̀H5܃) b! mfyb*g)Ar"%LFLW!]VD,pqN.\2;-#ޫgw7K߸fg[upշm+=IVN VyH#0 2:\5`rdC F~|rzx+UW·+:&GEXf!d (F`YR&l 4bJ0sPJ* H"03X0b$RhAb3hAP&$a+usJi3"܄+S3Lq[zŏgWJVUh=uhuSw?~MEciVqVSBniCgͽuj-4`ݦxr渦U DAjb \!h (DpB,8p̬Fxܘ1EӔ&C"fP2k$!0PK9Wq.U V R(Om=7F`WiTռ:yLb.oY]g>"ՠO[j6ݡnX\ԏ?&aw3:J3ƃO4Ձ1d2 @CL2!C !E eFLŠYI8X͐A]g#X0ѐGVTUdayU'ptOslDKa?eco>}`ĵ~fח;jOO>mF+'Mͽ7W%$mBhjRm#p/TU= aAVGgz"f`,1[ Adiis348<  T 2a%rR^ف,晽[Q JdOZD[hA#d1Ԉ^gЍ㫙XqTx-_y =cR7 өN»b+ƽ0]MT2T28ѓ BΔ 0<^֛7vÅ H"Y秫U4ca @<20 >0dj c*i`FJ,91T> )0$]@"f@&B$kš:Pm%ތvJ%d!6%Cn* e0L|<>$}6 ctG;Gdձ}GNI0Fʧ楱@;!U#03RCM1'Rɶ @ "co5 )je $oY0᳄/XD`'H5}LIs!@ͤ[O^i'ʩM;iyeU kF엲95H,mO6nm獽=Qc1/cmv ]Hƿ%g׭4f-]=ORsh)`bq+2‰7t LZ08c%4@@ȇ̬t!Dƅ٠ 2" HQvdEe` %q&p#FY1V&rn=ԊvLh*]炆lFڄ~+E%\:vxX]>7+NW{^ nP tʷoHs5"z@ 7>g@&F||A|0 AXv0m%G$0 3FuIB& As 0&7d R53 $ YbqX* J2jÁi+T7Q6nmx+&ݽ=$eDs/Ja<Oe07IQ|k>y39%Zl|K먒ª>۝&&mpyҺw]G{_p}zd  O2<?0bXU``q#LpJh`d5eBa#@>/d3ɋU˿JqU.Kw^pzKګۆN7ϟ 1"0A|c)'m[*bXDPb0eIDgaigi1eI B aA'TM.ҭ0 $RCGEWnѨj 2^>50 <`TC d/Lq#̻$pV$O\x^#ayf~DME.6XHS8ni(獽-yfq4ƛU|ARd76kӍk0!̥rȋg4HJ,2=-0d U*!q$w9$x8DU 2 mM(t` ,DXRP0wTH(X52UZ6 \;笵w=TYt9+w\g(3&w"mYӎF6mznr2ygn^}rea.хt%hpƣ..(TCHt`KEL1؟e@ DL~y.FvҎZSDlRߩVipZ&IļP,]9[?RUO:m =au ;<]k/ yp˟F~6o|FI ГWc,c(c#$AC1 pl:W&*`F``"V4QPJP4A53:(.  z%\(TLQ>/Bǥ VM$ bT ݜk")-]@xs:ԂUɬw-د`tu[\ݴ{N{jVuu>uЈEqbw rMDCץPFj2x]33:PgCҗ.(a E8y u  ¡ ^QzKo@@c)һbiiB#Ơl^ }%a !Q0nfͽvEdSY9~)  (9pIg![mf0gcjo>Mtq6$Y^m'Mq0գ 9{ [MS^jLZ0X+s 0)HӒ ;P E8$eLfd (l+eBl%F.0ʢmk$Ck%gv%qhu)"ո6 =y>1:'lմzlg/S$]ueDlhQ{ZHRf!+>PN@r!ǁ "(d?24B6$~[HX4ĄҤʌ#p8p 𹈃S /)Y2nmw*eݽqpR-T Hҟm@)E/"Ր2ʳ!V 8ZSqU9~;Z5΢g]kg>oæ1m{Tyzl*^O*cW;jo,Ya9B YC4pX8^f@rI /IR1dxRC@IX켾N$EPDiJ,:1NvQ9pA"F$󫔋Z:r}Zwsi6w )ڿ-U1|hzO:$N/LyG`쒓N2@p $G0pd& `m,@  1b aƘ6DBC(f)Q4ni$+&= jcAF>rZ &ZSźk(ɛ2x1IUL#NYMcnne̼Ya^?-x8;jAڃx~ԮmK>in-xG4)t9gyG 'uÀ`؄`a%,arC@aR# e0&UQmM74A^0G bM'HW ؙ{][gb$JDsq8ppVzO||_9c^ϋ3;kr\rk6֠j8[E{cMgeσLI|_?(,LAeL-f\-5qf&e(1Jl[وy9ҳہj9@2#$ p1س5 $)HYNˏ%c&l\zQ6hw+fF1 \uHI,#s:Ιf3 |!9ƫ}7^\o:1vesiix^wn2F"):BfKJ0$lhL_4€ m;-\!r` o[/CPPHzzˉi hN!m5Aknӓ؛5{@LDV|k9i|%]R@u;L9^W`f&X@Z3z 71R0S)L!"4 XELPe&%F4ăGC&v*5B@ vOq"X4bPU#'"UaROŵ٘Rl6´XnMͻcNu=co%;1mO>5$uf7"ƛ db~=-BRBXm W2ni=`(SS7"%-J*L1!4UJ"U CsR aԵL E0~Ek&JZziVM#["C1\0)Y٥M+Cg~}_lZ7lԘ.Vܰq;Q;eET*ZhtYb:3-33<3"0#% `:a΅h5:D "H`$`@m6e1e Gv[ 7{ e+Pۂ;N.6SDq0\DXc8ݷg8b?1rωmXα_k{'OvհX4hˁS\S " N 6c W@mתͽ=J,\JS\"q&ZHӺEbÙ!, ]ge툈 !HvU yq=quQ2452 C}8Xy=vAIRUIHMnݬ_UrMzZ|cQ+;٤lӌhrۗ#QyAቘrbP$2@ eQ„.XF*e)ƊSQb JЖE+`'YPo]5BN鴵kSU8赓dǾwV؉9>忶Yi?y@D0 \ʰ'p" Q2|Pcђ\x1/AA.`LW0ni*ͽ=X a({ ëaqH52qs-1% C0#D-!!)@A:+6\CT92Eȭ-zW fm &;͝EIPx"HFT鶙;tm_*#$^Gj1!>t_3X\>wko:M-¿~խ 03C2S.1d4c#T2q22-c2UM'00 sQE0>4c1l16Nu9D:9d}0dr2ZMAF <@x? LRlL< C:I3A@!H_&H)Pd00TI4.11pL..h*b'YrC0< 7.ހ!W*u݀&=à800p%/]CF ` 1;+G m Hܜ˷>0 0$Px (:fPN\,ḨI6d0("BZ[{rlJF4oec  %t\)p}БI(atd*ted%o;zcyEE)vvi骰@<1sXʷ!XJAf,/^OJzVzBi]y{T$z]*-qA Y5u^צ>r=eYгw!P 0q ,b(=ppz.VzWw>3GCB24)1m͍QH $j:LWZ}2u*덇S,3IUrwn5,uju7%yͅXtԁz=M-j@ .]q%zA@ LŭAS6O{gI#RFhl2g;3Ț5_"ˤ1=> odڳgd|Fu9xۺ9hݙm]Hq& JdEP >8h,ccC:fAgݫ1:=8 FU:I1+"-Utx pskJ=GK۶yq-$AWO/kn] ε-g;.bsK.k$Xٟ :"@eC 4J;BBm H4B) cQSXla*ꍜ=܋';JݤSqȈ#9YHń1WfҀT)o"fx ? -]~xY}ώ((5;d?}}_zbUt{N-ʭy[nv %ʹu7Kyԝfz]6,L?QHϊrkKP/,SKr~nV J_o(|3;O̽?p}յWoR>ۻĚ4DCXדK wJtT ܨ)116-34Ӭ7`ӴȪ"X2P DUbtBV])s)EH f8@ VjpBrsH|}WTl*M=GWҶ5'3^5L_i2WtZH}j7%[~oPe:1XO_!c?N٬O9#}ar FkFkiP d;͓wK Bi42].#?iHL2j˜53%M'^ 11+>!}Q#b5LԈI-5[gdun2JR+F7 4eVcPoomgXx3x׽6]qeߟ1g[!KwaQ ӀpEY 5#3 RPB00*a P@4PNC$A27e,00sA@p+H5ń &5*K݂fPjFBy%RxR*TU2{#cBXs +p*PUZڳWHmi*荼NWk~.jYׅKzi\R=ߟ9&b|ożu+*<ȇ(jJLf#=X^ .f'Fa r"15.$1T,L܋t_6$T6bAN\i2 $h2@IqƓYI\YKhn*II WjK4N0Ea楀U>m =ܝa>aj5AΩUU~׃5&4k11r˻Ƕ7<|i3Ly@TFUdPѣ Q1IuVmሁe%b,z/0a"ipOTHЍj bDQ=g "?2goHNH>mFFDk{f@K++c$=,Ϲ*[4φO.1ݩi֣}sf$9\xmRagަ\]|OH3z ` Eïx@$$(dTG s5V9f xd6Y0pR\T *M3i ƉOH4 jecpJA $>;k\H ]GިGh+WBm =tKnMjJWǧ *oo]G=k[vP,MFmOIfT` {?dRԇF.r/XG` @0hGtbKƞe* fm]s+Y!BJVa)+V(BK`"F W/>LAÅK) ȯJh45W\it/|S ylRPԪȹr+N#Q i2$0#sJ2R‘0A7 j=s3!3fЉ'2UxV!5q 0+p $m퍣w* ͽl"es1,U;t:lgFg:VM7,qU~Y<|i@\F̚IO+G89u׶wt_ MRdbQR\7D+$Ł#4 @z2 ʈ#dCYQD3pu&D&@)~$PÝL_2" FNq1Vŷ*HlY|ۅ%ݩ_;tǬ#ۜRݨUz5Vah-X|]}&:cj긌Yk2 f Fal]SPQTł&K4ۘpQBV9I "J0ɘ!i ĂEZ%G¼EQpp- <;Ļl<:l$-SFkiu1}Vq|Bvb~bajjT?zV-"]nvj\ͺ/YgWIg.`A)B1`ĥ#Å*|€Lm+ DMPD0R^,zߓ) \.]>RQuMZ*zbJW#q莪W6nmIͽHE+,SHX -_J,K նk˔_%Yo՜3mF&7$ Z2^E)yt  1(MA9Xdf4ID $x8I6|Ƃ eզ U3aF0 e&&. xhK Hh d` #Fb BY$iX^J#@0lu-'QlG7YY\XL%3F :Wu۞W|<*?&[lMqs=s\I&cxvqtyͻ:.&³ OP^5hD`ɿ&f* <2x,44P6`yI AFlN0 ``b .),0q  &F^"W4nm7fͽ"^TkR@ī)F wGV2lz; bHd5s4tf5*/c7|^,'o4<^9o#b5yӖ63>k7>2g"[Ynuխpb(`!ѯg@ TH`P\2$0@ 2S6E <,L2"LB}j&3p&Fמ%$XwTDB,2ڀ9]J?7u*cW5j\8315-|\mߢޚqHbV_jLm԰ש$vF@H]k%hI*{HcQhO+Jolj7Ǫu6=Wh3 p|I~W:niM=[M"9xTY3,3}Q }E^JGIc/t:T*j$v7~?H"}1W5S32? JrXDUa[)I\Ϝu4|+1Z+ *CpM^YZbI׹263ys^>*ؙ<B|Uӟ5^K>;,(dx V+1탥 LKX(F)kXPfTr3^|#L" F[h"UKP l P5([\¶T *oAyܔV/~@_ƫD(zr3g$|HmC-6_+VF0܌MWJl፲* ~K].DõO̟YGҀ lc^P|h\\eH"!`TJ@50Ddf00B#!FhQ2 |F1đDF,B B.* D TDU%<ba9m#se|& 1jo8&VY -Uﭰu,̃j ݫ5~6䓸ꌮ:-ELIÄE5w34`+8hQbeȺp$`xT82!BlBpGV 2;6^`Bb)܂ x4#KfN>bKhɌ1EB=fMY#3V چз6kW> ZW4nm'ݽ;gޘ9Цo{o;lbٯ0zr5[ u蘍HSZw2X|s F 3D`3*L*aёT}*h4):v |jd& 08S{ &h #2X85^$HX#T&GLR񬰷;OD%NeU Ze5AH}C:Wvmoocgw |xDu1<-oϚRKj9UzZ'VXϝ.W3`C37A(50هf!ɨ1  ΢0 LFLpH@> & @8LċE`ͅ!98tQl Y.nm+%Mݽp4*%C #Q*RROLPo>Cn?~OHr5W~aڋ+CmtJ'Xi7KrǬ0)xgNJi K6Y퍷gg?EA[ˆsl!0+QQfTX1?SQ@. i j,\N3G ,00Aq4C (DB6D Ft߰?jʪP9q[ RJ `Ԑٖ"09Lij8XQ-sWN~UshWxoeIC%'б21iׁ<ĝc*|sUdY/ g ^8|qfrQ ao!C{ 0a cgŀ\ɒ>W0n-=n :fH A eMiXa ۛ#%&Fkwŝ\7SH7pSY>Kֆk5kGU-0\bmZNr>eϟ1Cv[y ~?T@xpHajP@K6)~J!jK/A!gDijuY .ܪFS,lhj'^4>ȁP-牷]U~?KvWSm+J 3#~Vּ;a~\ʴYpn٪{ipL  6eeyok3GYE$`X˩L JF bH` y5uUFmaIMͽCIaʈ'*4:Yd I@ ~hдP`F\\V CA}a'b'SDmb̋.U./X1ޜI;SռZ6ٶե,\.m SkᶭJ'Nԥx0au9RMi6kAhTw=[ZqL1A3VnJn]B\WJy.BbPJ-.AqoyMG~js]C3th\F8EQzRL}Wgì[0ׅjɈmwͬ1Nag-=y V\r ɶSӘ|PՄJ~-I.Bע4BDwz;i79BT5G(_pDdhhyI?!FR4XJ3(`.0 Q*:H*`Iih,&=C[踄{z Q9`XgД\ݘWZҕD.ʈQ~"'n,(c?U?~j㸖ʧ%uޢ&*G =je|pmTLzRTzaN:ۧtNH5'D*d\F$%sWU/j[ 1ҲEV(DRw4m,b(00L0H*0t34)0 P1D5H$Dm dn.Q0# ` !P` @ǃ*F2c!#* RO7"`vjD T%#`lU@|6" z!l/-٧j 8ɹ1[xmE7U0W@m即g ݽǙ/-Q߯qu=̒x+vtUq6>u7J FЌ0C&<1hW(Ht0 0}2'X(16&$@KBPdF CZh)MO"VjnL[kIqOieDcUTlrJIhLu"ܐYlȥ*_o̱tMmR_>*ౢsHҽ0.e̻XG7b1{hTt3c*n D4<`TGA2 IXD ..HD*(' J8FB3]SFcw La9s+JV /еzSZӏ vk5g32ŞCTHĭUW:m *Mɹ4QbĽ%U.0άFJ~a#'FJ|"S&SPI"ʣ>PH }X=E+Si,р&3_duH@ p "J9 ԥ12"i Rh5VO]i8@ #Vc!ڪ`sh|L&nT ^,t a(t0TPqCc6La`xP& 2WrNdJ b``@!0R`iGaA 4 Pf UyDYq9|dQ뵖3)\kS qW:m即^*ݽvXa7 jƄ$82.>2u{ƺ].<F 1@ : /CI=F}U`GCb2xL$Hx>"`VjDA2/`x$9lA%ݮViYD8`4H+',b&-Bk6ĐݛC\;ZO&DB5kje^Z;Խ$ã/?_0(M\, T:]; T(<018)%A܆I!%ȥ6s{*<)zUU*ل) eiE2# Z,hp'p%ZB; 6\ժ;genu^4X-PܡRq-1V p+q%zK] *[ F֘ʉ.JS'BCKZOB1RZaj{&c> ٺyKQq[V e}ط|PCU_z]d,Bx bSi.Fw= cZ"~^]ءy?ƜeĴW.nm* 1 S@ 5=hŷfw9'5>Z" x F4$9\VP0V)CC[NY2tioNZ>\e#ElV,4te"kn(zʪ'ǁ6S@{vV]7Mڸvh>4}ŋ/SDk\5,B3A1DA @`ȠRyGsrX fplS3.!1T(Z-5Ovx1hI|ˤ]+.aB%TbndEHy vU96%ev,34nx+g('kOפ\cq-+rGsAW0ni=wg qV9~Q2`YF!B=Wd2cN Q 8AJƂ&4 tȏcf-)j0b.$JJ6,F% j^'U{mo=s!\aJOcM EMnբu ^#|O:Qr=H2g=€W,nmʪ1SZ΄Ɋs&c=A!L &`@04 %yMŋC0 2qCyETPjI4S 3'ffJ.63Cֶ,54m*ÈRy\o6,}ES:[\;51&+s634}F(6m+˼HJnf;lY၀C(2ZgOVrU`ߔkŔ-d:v2(8-l΄U^r5ZNO]>5(n:!k0C$Ek7n[웓)ح6H8G_&Jx:ҏ")Lj۔fy:gFQ?srw(kvmG@a$}Z~2bnP0XBS8?ƀW2ni* 1\(@ l \[qjd 6f2tT:v@Qn$sb"l6EJ8l}`Br1ei4ĭV#O,k,+ırҾk9_miY+\͍jY=mC#GX fba oC!)np&r$=P,H0a!`!+lU 2" B2Dto2% 䍻ut)#,G(HL{?8#f/Vpf7 )Daw:Q'LKkbOLH8]ňרsVPf1m @9,PB`PBE =J׀MW4m鍣8e=bc!0`0  >LA@ip X R6犢bEw$_kv|IаO&<57tϛ?cX6yn3F#;k#|>zW6YFwwoܔ'6\Q MʠV & [T!o;RQ-Ә;+ dȖ3wMz`{4M=^ĽѢz!]hc9rnWPI#a'D۾jXXGL MnPnma9?ty32X)Dg )IqB"1(t0[@Q(s)3` B 08Ŕ?=e`э&4HQ.ʄWo܀W2ni*M@YFtb Dp$m#>!S5㉼Y*K0- % E*',)#?b)t+q#5#eunւk)n}vՉL_&τ%40O( 2>%  "0Q$1sj.*_!@\(Q&eh!=JD*L r-~Ei㧈꾱д裛l&*r*aWfѨӪDUPgm~3?ڟwR @] 5q01d+@pqa!pQcdT(a LƀB|xi GCCJ6* y.ҷW0nie1lJxd2V܅W<_ I\?>C=23FtS-)>[SE)>fW)E{#'{X}튻_ 3ۇV1x HC*,AJbG-mZJcwk um΁H.J`R P&2[Wlg t5 8dC"u):굻JM;Nų晢Cɕ%絗.aݳ|Meo{ѽ;gvsH qQKH6ZvPpuPP~hက`@D &/$-pd@ (b (36 " 4# pV: w)7wm "54HK.ni* 1jba FsEz'8y7q4y)PKXѢmq~" %6lnеc+rك\6d ‚Qu@-p (3DP( (pAlc F+XpA b"%Ҷ.V*6$܂YCA37S /#9*;v8ttyYҡ xc j8d $dNR]2NµmXel)<A á PaP0422ؔT8"(%7rc Hh SaZx2BlBK,$i@0%Q7'iCHH_%sUUW*nmЪ %$WJ\|ҭLN&L8!"Wgu ߉:sz5F5m#r^dI؃jZ(xCYUL*O=?0H иL8!4 h `qp"ѐm-Pp:\[cr a!X )y7* x5cv*,vЩ|ہ響mFWyjsaSf.bEfr//Rf'ۇ{ j}^s]M!0XD88M`ȃVxoC 2>$<Tj %] YC +R@j^L$RDD)&fжj"u!W.nm%=z=F1",'AQ_W#3r!jfOQ9#^@=-i5~3q8NMh́ 7̈́PhF×@@*J(`q`oդц> L1z9P0214`a؉pV}\}o˳! URY3IE9eȚ(Uj=5?yh2zDV v\= y5.#rze܎)6^ &2ܕ q:Xs0B61@ C`Ix#=Z!( I$] *]A-(a3, ! F_e)/W)&qC1y1Q,ni-*1@D-jht:׶AЇR۱pDT4cV,L497˽ :0eɂ3 `)E~0:L0 gp.I$1{.JڥB-:(;\ *=;eThYl!?¦'<YƘOPpfe 1Xnƙ/VpKu`gİ~c利%NL[i[GK421(0D27AL,-&A3(4>C/9E `& $" BD54ȘFAf!4Q!k eh)( ,1W(ni1) ^tX0%Mͨ.%v&ͦ<^%<DVVZO%^xron+Vܚ> (ieXyeɁAA"a `08I/ш X"k0gfZR8nۂFFliN$b$@ƒȑ,*x)[bL]F~^RUn- B}#F?  3SrQ͒){'_g;di:aMZ5弰 [yV۴ % 3`S)dsrA B3 A1AP-00? B Ё  ;QXŒ\H”`9ABW(ne$ݽ Flha3"&Xn4k@$vҠ 7+c,c`2N &+kKr}Hs򙓾dWrszGrnԑb7Dx<%&r_Nx4vΏH8W0240)0P1P0,3\0 &dH806_Çcf$c;A`F &=:qV-u$✎ԒCFYahe92[А.VUploXSL9Lvc;ЊYkcay%j{>Wrp]"Cec/10@3@tNbA#@8U@lsUI$N; ݽvMcAЈ¢;>/Бj4QI1F)EM!/)y1Rw`j2=}웃=Dcᗴ)"rPϢKi⺒p#~cj_؝~  nf Hp@A&/5L 5  1x`dv˰.4$:! Bix(fE"ft )bo39Ϫ 5.nġOD_P r'&27\9n .u'zSuXocśu~MNUC$0X邁HF<hl*AC@ -F L! eAIϰP^s Lh9G*ni'eM104 v &3< ɅZidӷg{>n 'uXWlnZGC٩-ų"ij@T8c^F ) %'̆0^Bp(|Ï@Dt0Q!™Hr0l%T`#JgduC3QK*ni ͽ7o0ݪRudrD4>9޲#"bP2M-t"Q2#wu6H =멦eO$܇s<( b'RD͖^Ϙ&Jc @. qGy4 ` D1F3\7C[<2PPٿfL 4Q !,N "D5C0s~1w0Da^4*c[?,ni쥥M1|8x[4%,!GWc&'vgUZfCF:®IJuMY,JYֶY^3o.6C?&µćMfoo_Ʊkpq[\"aH4cf0aXc da`9g L\AzB!3G Lp  FdHB 1b!"n e =G%\<i3t/HƚHtGqdnP7 9X!r`N6)4 qțS)jo8 __*_3ۖGiyZw9y?|`۵WO@ N $w9p(4&^Cp! l$>:D  4(N(,~STE d He P5!=N %M1 0hel Lc– dA@X (KUO8e\݈+n~j`eҔintl8RT./y3&P'=w;3I:'\1&T8g]l05༄*U * *37#F`x@i@ QABX!:X0Ix74jȎ JXyhGk7Q-hMT@tZJXЌEhI)ޜXZg= f>ruWOx+UIF-D'J.b[2{A(Ed)!wa9`(}]LE=mW kz :HUdgi%X,fOCBdѳH0dH"IP 00 & ^r LyP UT4 .&I3dX`QB]&SnI4n; O.p[5SLۋM%SąC  O@^Q.b=~8̱z]#C.~ ˋXK(2 1@@Bq(ǁ" 0T<%$D ` u,r)3) ĖEKITf^($ p&5^I7(nid1C'dBU3/uTY8?&p <`0 >kޜw=wi/ ]8HTn0T`F NSegƈ"-=f _XP*`I ) &\%VWwmW8ұ>PX)0ѣN֝N.N=`4.8O!j0)26B̚I jTVc&ON/`)1 5LAL!QNcLfŀa+0SR'y O4U[5LD31@hB`"OSf32LF`x;Vj<AK(ni-ޤe ͥ#BҔ__ i5.PU7Z,M6iu)wYRyP&t oE|Xt`KS CP, n-Á!BU̲ 0P<8=PDA" Oj̇]C|ʳs]V06'蛴Z xNñTy3,R֚;rE-/ݚeW޷W t[Awcm=s@(¬@; \@ ˜% &|ptDi Ŵ\R¬^stφc1Z?#`@ÀCTʹ40'(0ႂ8Rd1II|gfs8k첳 L6+1\,0,G .0 f3 80d`4aqْ3 xw sЌ!0TD5,Cq ny\@6쌲VM{5U݀&s=$A@,y:Av\JHzյv+ `KϿ%b#K[q#ug4ŮǠbx!$"8_>r}d *#DA[)n @Lm25ćjk=_`+`ʛRCU " XG!DT 9r03$ F\wiz9r#Pyv %xDdk$8uP$mɲLH*6gl qǢc|i"UM7rJhaKTIˮS۵Rͬn<[-\i;ovrhAWЁnj U`f)/9!C%QNq!s :IKUi]2ͪi=@ehV0AP RtjѥY IYvN;1ğ:FF3dёL+&Pc[>"E/$,.qw 6s {jhRrUBm[E 52!aYKB 5De Q45cADȡY祮j)$V4uIPe2 )*Um+2FXک0/VK?i\߬%'+Ïm}qO>ֵ*vz͹CrӍY PTXlEVcL"8d i\PMB'DoRFiDyD,m a%A,TJsSJmiͬ=nR_ {^ILմ<%Rq8F⯝T]2b{xZ_ߝN❎nչ/mQo&r8.Z4(L(qu/@ *:b!U0Hq0sSZP˅IʌP᥂0 d, \)*ƏDJ(AG2R9NLJ 8LY;%7󞈇b߳%i[za#ܲ.H\]!V ąLo$c)a˦]!3(( U(;I JWBD (`( ( 2# c.t[~?uu1/r\Ƀ]6Tf= 3{)WFm鍢ͽ=[+]ɖ.l}Í-sa5xսs#(AC,16 FD8g#\%Oh 8@S@ 5&6-9z41JXc6+\ a2_L.a6Ï4wuYZeZotuf{ZgPl.1uc%FB`Hy, `  p N,Y<,:csfȱ3 p T2aF$#h#\ =( D E)DIc.g$[a)VͶ*̩ڢvp,.*Fm$FuQȪD-qޘgM+8);SDrOWJme*荽1f?{VkYg}^'.H jlq d,pf6mƋZLLc24 51C"'0R@"5ǵ Nb"ȄؒF3e.}V J黗fS lu%/ځ1|Xحҥvq֌H𨥩9 Ӗ#˪uDU#zw>w 8~&gs)>8ZSqa:al\xet1@xt F hPDH, ` hDCl|BP *,6[(h00  50)XT"neiA\DmɈ@h]Q։Šjr˜=Slm^K &e4T[kk,W67W hͶk"ݲjniW@m =H-VH9YWlpW[۫3ry7az XiCJm Y Ml JIL$`p`v#C| td8HX`dJA#i2a`C PI30&xC 2j|6|.1SͽI0vIQ0 -SU֫42ai^i4>]b$$WK<\;;qa1k{p_d k mת 1N4'! ]unJW·l.1Pa٘RbBfqِ!p&?yHflJ%LT#>V0i"@Ə!ƈ0Q 2dx {f]{Z6>bϷWR /;a-o62H-,EXqLaz ENLARrFj؉)f A'@HȈآ UWPJ`P64SiGGnb%uNt>]((F{Gw[^Z3Z=f~'~7㯸Q:ni)*MD=v4eXƥ^-jjR4XB`kQX77 C1X@ Xp )pG9(\ C-x `BeA)ˊ!ZJlQdu2z'@k|R} i/)GktKxݙid^/;D 5I:] T鵟`Y&K%< h.<HzbAFNtGXHX5 P$D p@D@Y&fdža2:iG+3g3s<vȼ?:K"[UfJĮڶ|9U!ZmoY)W+D x,u~ם3l7G^NtΚl< -ڭwɪ+XxWW̠8(<'%Q"Î`g^Poxgxm`Z:Lzh |hd&ɈJ:*\*DǍ.txQI%b @J"2nz7l-).SOۏϽcifNؗߗ0y4>6ozGHý ٓீWBmM=~X_fb^s<W ܱYU&3sM !NM 20 g!`8tj~c dZbE8%U0Pi>*TɌ(0<(.<Oa\Mz"2'ʴ3zeuQwuK,%.wU+ CZ$XOA0U튭{][oFNז@zdŰfyJ&~Y0=PcVb lFks(X p0"0R4Ë! !(zN@L<5AS "^p5ўT4Jc zד^i\cɵɸqOxW8nm0*g ͽMW3T\̟ɭo=|"FTY5ڬQb/^0vYeUG\M033ĈeY{'!4LZL2S <#(86bFNI(`FDs`TCrB&Jk~'aL(}~?Yq<ڪθa@NJ&y+y>rL[t_hmyϓ'Z·fsm}YUEnFY}v8lH.wB5!&bpՁY HІUcͦq2b0ğφ 4=!tmGHg#=Fq+gj^48-ťu1GS5?7_~H9b=gV[cqpr~|LJ,4pXĈ^S GF@800t`xf E, 4aHи@éB@B$dLPb@%>yTAJZd9 )1Eq[H  RGsںzNwj u)ܳH4\lJh1WBmg=m}6u* hXbԋyVA 4@pZنFvn4!37<8a0rLer񋜘0 D8 ȐU8m QC60&$B Ë$(L7UFvSږw:Kz*F(;x? KP>ɞ=v:Vo3bHS[M Iw&. oL3mnL@N0p洀)LGV̚ f Lj2Al3+DIĘP90 V$zy^5P2Hʫ/\/)PU,XJz/3\F fL `&\;(-*e񼨔kUU0nmB* =zՆlիlj z1p|%1zR ^ Qb cE aӺi'#Ld$a qeJ4Ma$Qda 9@ U&Uh}8.venu3QG|Ndj]zwټ3v$lG~we۳ܲcmQ]ig`H Ht|͍kM?; ۉ~MW 9_q\O<WBmi 8GՒ@ 4TLhd.`!fp$ce|,Xg%F"gf&H3.0`1 6 Lp2$6:FA@g'/s_C0z<0(ӗҀ4Xn'uR!(18sz-n/q;SQK皵 cw_y1 nu5A}Nybxb&nxgJjVk$MN48 W9bBU)ja`""p2(P|ܳX\8tP"R2Ql4id?8wC "[(Wq c kiΧ='Oi?ZNu }>k1hdbwM1 U0nm捽%WMz `Rٲ" )eAf-$ xVh-8PcᘐDAC0 !XA `JcH )ًFC:^/lGfv&bBmKXּp|$nHoXݻN&Y[v<=sEm}3SL:uT>` ѓlCfKf *L’ ,qaibIHX  A&e`4` VȖQ@ ($R̒*oKLu$ &s`( ƾ:[BU"@qƥwhvǿv>uI @.uW2nmg%ͽ!ֳ\FG}U\UTdf7ꋬ' VY2,hoH@ɣ0*Tw|tq-*B(GU(-C;@Th011Cof+C^ 0MQ *XB Mx* V1R`bua&QnfH"9brcə<(,rb b p@T|y8pĈ.D K5bl4t H3PGQ *cG bɸz'O"7 dh;\'k?jSJ_<{o篥wDwotͩ:)ndnf] aW>me0&Mͽس.YK5m dBqTTK 'نCV4wDA蔖Pe" 3XK4e0LiKBە!v%Ie2|𡘿Mm2)h/A% 0NjQ_4Κelae74[K\1jI'>7jcvQa(6*jahx.MI 7ɐ#3'J'qp2p * *9P I8/Us [d 918$թk9GCP 0{4QexO||\pde_3r Ow,; UQ$H T``0F/A6zA{!v!`0(0 Ec@ ݗm1Լ!j^ɀV23wfi-n#/ԼaSryh&L> q9r b¬4*Yހ˪O\;<-uLZR/LTiI.`( ELvݮC.,V乺NRe p̜dL'}m+)zJt ,B E vDPqC\5%;dS̒GWIXt9'no./u G:Qjl'%Wd罍8͇[_8g=33:Vso6ݜ̘=+<6^J5z M. )JM"XxdL``!PPqq*><] JB&^Iۛ,Ļ k!'z:صJVv.$nGS^3e|ibOiNZZoz )ivn&c&&jndJt4d@hDf \@ KDDטU:8v'eL>3'R.܇[~{Fgod5Cs5OV;*Hz]M1Z]< $|ZW^6Zf϶i^j)fDici-|&<8ײz^X h{Qw 8Y \ ^9iՕk-ꈑ_177~M"AHU/_.`:~uLhƃt[wN&_‰Κb5Cdy$Yl-+[Y)[lxD̠Hv @\MX}՗2zl#\1vXT&@G Mno :ݩkbv)6^'5X 胀WVl*M1䜔 !d0SE/F.٢# Ŷ)dj3f bnN/Ʊly"М;4\|a KUٙh 5McٶLV;Vڷ@q{61v$3Pd8cz5J4u'^)(;Q?BQ׹j܃Ѫc#,Y8ԯI}GyiTRdH!ЪC)D|}~m!*TPfTQ0i#{i C̘`9HJUf4:rȒ9!Si)ԋF8i6 "k?kSQ6Em;t`JhƖB\)|hq(}ihz"K}# 2BIJ]D(l TfӨȏO6Dj ڊuCi p Ȑe娊 `A1T/ٿB"txD $*a gQ2Z`'C3&} 6L ȉd-u${ &k&.7BzD$d|%>LhnV]ZB#]c{zŶ˄vp՞Ϝ>k q{$5ja`'dVI$|VO@ ]SFm鍫 = ̇:4oӧoꂗɌ@&OP- A\5Bl̕h1iB  C#Ap`̰1 ZКM$04&\bi G]?f'2dqE.f?5ᄷxXOți[GvXΪɺaFa,-&&d|Y2]GV//FE\c3g4o-I $iܦTyՃ1,b@:l x14 ,3!6^bC*fdF0,4rQ̵l@ 0U0pbP<@ϺF?EvH y+x& aHgiweެZ3BLoy~ƀMS8nmOͽm}j֘SW=:M@46ae MF+4L 7*@3LB`JeMaAN0`qR`Ƃdxm @S (0P.w UHD#pKP9j+iMLX ֋M7s{ÍQyF[CĴG(Emn< MUT/4jwۍEۻ=ڙכDҴ;̤mB;afF$J.p p,eSPH.cٖC Ʉ!<6 єhPxBPi+.p8*-QRYE1-CCTJƨ1dҮvBQ KLgMlҎ}3]V:GZeW>ni* ͱlE:jb~rA(Qjsf F8ɬI4an.>`$t4La\ hX " JI*C,ˆH(.Yӊ֯ۢw¥2nZ.1.۳+rkҗj{H[n}z*m>$2K#*ҶSz.2RƧQ24 ,j{6x_Xh'< 25 HD'kL"NA|V-7tp.qPyhK0BP=D^Ɖ9NNT@< ['gZLTa,&?W̱ mF6`ŀ3TɬU.fD)6YM34Cm'Ȍd:`LÊ A!IU U/m-8Z1О2lD D̢}\8:75N((qu\v vL ?4X/]Gg5nZg} *MO &}m$p E5$(% `PxcR\ p@OLQЭ sPBA.|E!;L\~?lM Y+:Ud.Pp=PYHZDW6ԷQ7V5N%)W:nm)gM= TWwjr5.\Xc#1$Z5 yHŻ2䓼^&cx4ex!f͢y2tT:A#Y*Mz&t0|1$!)aSHy$M(8B.P1.^[ Q4ۗWÏXfD"p/ !)t) c,]\S(o-\x }'\򟠗זBr E&ؗkVݗ 0 WS-L H3$N 9S ,K¢DCPUPIeKMrĴ@pP`ua8x:,2)/H@[daH&S'+B4"O}5YW:ne*獼vIShov=+⇾5+Mb܀bq3TV3e'^)]4e}2@H!ͳ"5CDw M Ȇ!3q6ca M](B Ibft `:h0yQH`!PBᩅ@ʽ&ٻc ٲ6}Gj&bHj^kMEkl/Esa֙`#tكHWLma$M=C}/ 73Y i? !Hp-XP%p].v#Ưpf '56gt2 y)JHȈA BفhDF\ńD!#Ao1+6h)FdBi㬽Pq$i.c;SD+?mYrk k.* @F?1(ђaqv8Nl;>^yFsMP1$3=#N 0$1r,ކ ..1D#.1lY8dSF$ 5eaӃ 2цlj2־-/&UUGوznaH]Μ`5]~kiq}.ᅊאָYW5PLa&KIsQ$(@0:Rτp, D`^t*^U*^8H1e"H+%-KxNՔz*3.~uwV%En Q/R!;/BY:niM̱K v8ND꜍VXxҸv%R;}(DEn8כiZ?X#8XQDhc&w]M\hN@2'^%I/U hu=gomr8K5ie ; BXWLm=M1!%u0Z"R6#?`DD&WMV.rR! 5͊J C@I;#~5>ھ{C+w,"vUsw*_.'[ ]R/ \M+C|^G#ȴqKNZ~BG櫂ŦmQ qpADH'I= L@5k)DG&xg3e/T DB )nc *5^ƩS) "":nQtlsyۼ8ijWG3+2:唨fKlۭ gtK|-rEV<_P:XFT8ç ǢgU|.- Ƙ9WHma*g1J CBqbA!i&Q)\) ?>֠(1cPS$!6b 8C")132ƅOSjbT" LBudfPhw* :aPm#F7 @غ2lȊ UE(_#49OԟSu|K*p=I 9>LH+cUUz j:|}F 8u+l;Ln4Vxo Qf[GlݫS9Vq/y[t *[80C;1DHCɌN0(:61¸LpA$0 3|  j$۸bKɀV *r*U;M|vю$㶠;'P@(1pxoR.Iwf5, Y4ni& =v`jR02+t M0V/bcF;K\ۃmN[NRa&4Z25ŘܴӰd;"~܋ó 2Jc Li ]' u0x4$2T DL1bWa*CBbB : :tEg]p YlB"|-ITG1:bKj+k:Hƺ1be~F Iݮ"5hDoG(HID"yUJVE"Ʋ};p~O鷦/'G۱ed+7- ͏c7i בݦommc'DAyϦ5piig5Oq*/s&¤m|Pi\,G .!2b%)N^c(T `Qh/ c0@QR` q:B~! XCc^.J;(A RKw!WJma9=MzޣYv P`qNZ 5@ M3 0 $iCG0@"g "Lt!Dg` ߏW2nmJ=aE#aomHV~]^Iejo=jj *iuSƤb$usrh$ŚVقj}9b]tTx7-)y[+\Ӱ!Fu| Glg8;$q\S7bH-0( cZ5 {1LJDF[+!D o@BMX<^He[>cs!"ŭ(q]yHv˯B4NAй橑c-:kVIY$~=Pv: JF]KDbpkZw-9cG3D>* +v4cy@ 1Q@{h!R` L04"F-|WDma3*ͽ=L&"1\MIP-Iџ[=PM+B$xOTτMNR5/q}\clY{ËH./,o-Fϸ_Axa9NܾZ.fUa(㮀,24a ̀3|Te0y28@ X(r t9&89 x| P$Z PiX/"VтNK}j*'hdfLUJGfuIw[N.Wq\ 8hh>ʙ klqbE6GlHNS9옙lj0e֕MI fT,˜a fJ(KES4ni*荬=Ąf3Ҿl1VBR' ^ϔ. ܂Mke-f…gP!7\hKb/$:tKڨl08m|0̚*Q0[jS5#Մw G]Ţ]y:^48p 60:A0 l04&  3N & S%PL HBbd˒H@!3XJ^2[$M\k:,# 30ĽaB~d((e7Mnc>)葤F\je6C?hzH^A-#aQ]@fXjDyt)T |L`+Ka<(p$Il6E y(%G]Յ vG=W8m鍢ͧq>/W33ɵy$ǻ}ލ3֑5AX*!,9>OVQk-@ir8﬎VFJ-BS7(F\ii<P CFfBlc*EFdzFpb@eQl=p-3SE D 0,;"63#B10-~"&Ѝ@r;a f0kS*#ٶhX.C*i9BlL ʢYȲ 3+(FZ_qLMk>ZRnzsf&]`iL[-CRғ}S>3/c9TOp1-=1b9FpQ2%S,{)Jm;an<򿤕u$soOl lBY /mW6m鍢*M1˽^Zȥ6۫nkQT.Dɖе.9\5Q- EZEqDBMp ^D3? eW1\<ȓJ4HbYG.< BDx8/ LQ`% hUtaF2a4@T88tiX2)CalK"zhlzgJ#Gv&G"tz];^Yb* gk^';D`xkԞ)Fo]tvZ{JVEVgUf`՜b<>h 53ETs Xl.V*1T0\sK!2Ca>pr0٩dh10!S`aIqFDPeTo W2ni+& ͽFDdv>i!#ÜBr]JY;IJ|H#-R˧/z)'ɒԏ+uOEEbLjxzn[J<&,9kks|hb$XvH7eJtMl,NCGBcrPb%&@ (b,Fuo^hJ^L#$aEi)lO%/RPGqS2ni* =0,Rծtоf~=<NPkPݩI˷̑aOϵGҸ̂~?-5oO%;pXT_ajxm'GQ@SR ήȘ5 d.H\W'I$jKD*b3*JPT$nJ0{0ppXt!9 f.mĄ2 y %C#dP4ic9J6{r{aji<_iՃ)Mb5%eΙ$WFl-*獼~npʯ9{WuMưW HLkNT ED2( =`a^70L4&278dvkB`3z1`@)MP*J,.nc;B Ё! 03a~A|:_T: GDCH};Anwk}Wn {Kw;;$+aGQY8NԘqG! jGsIi6[TXڀ gFi)@b)) )%Le,B  PxkIG9vw'/Q.(fFlW0nmȪM1j#]B^W&茽LnB§u QK̸Q^S.QJӗS^(zN&LZrU܆frGU[Hi+ &2Xj jRYJ{N]@:4!{TL-cqΒbKgHvki ͖Nl r_h#8&z=Qdn=QJZ>&)UCQEqzRPqܥdJʑ_/n $e ,]ze/Is;w8.:Ntx6A>rR4#441BAd8F`d)SG7Fn #3 :ЁJ%k3{|mZX{wq nmE]-)-GY_n鹲.m&W>me*ͽx")2}PX4]8*_@wM fxphUhi*23!S.1q:(FcHV`!eؚ߽~)xY6]yxt+Fq~PM*S 0G`,P 5P4B.Z (A! aМ1Tg&2SkREB%y tqNjCVQOa#=!ºBl$ ѐ8eDumS޿ƏTjDCo+5>WSY꼹*\ 1yHb>W2m鍢*獼1QDRX(VU t~31t2mod' twl ]T;6 a&.Q*3sS aB\;I0! :{RE:|ꞇTL>홏%e-U#(7T BR@w/0tsX*q7s+[ um꡶,=>A4Y{ȧdP >m/)84$#4£ 0@g 0zp4!P1a @6 FDI ̰4AfB2aJj da5TbΛ@2Y)ň/ʧSqGbYl۬1B+n]O wgLuAW4m卣*ͽۚ'lZ炾T&8̰љ_řSn|Ae}{ ogjdY&~i4@F`b4D/cYN a EV z#GdICHV d( ]e"@0EA_#z9UDɆ1&G墁3AGmk#]n7ChP<:.%CZ0I]cN}#huTp%gː$mݻ>@ "@xD5bàPPD",:(*t^L2!=\ d9&L_uĢ ݽb5|NGSu D,ow_&R a [EȣC99,C ,4 Dq䫀W4m卢*h 1MlܠU.ڨ+B˦ ԰ᦏvKHhP9(fdvŬ(nb*CaB@ $f:25&0а]A" *1$ٌ(UC2(mᔉn:|Xq3ص+ZJ8IqߧśY,s ϲ.\Tń+Dr|FoXV)'p .U6Bð!2 8fs@(2X`ShD8@چ5ч6qYD= /11u0Jٜo` U3xvO*鍼Md2yFK6,VyfMh,_87Y6}]ӕ-6)zoĦ Ty;';8E,n}zFː"IW6m-* 1]/T{bbBlt,\c b1aNRO @,Iԩ4(qVkHw 5;;c?$,f!PFs /s~ΏmԈ[W#3ma 1Hca#%ƒsc`#k2b5<`J28(12P` Bujd6cYD6nS?F~aTPl[?P66y;uݔHk6jGʋϢkilJR'cV>춅Eig]bRG1$CҭEZw6Sʌ8 KhSwRiB`ك.yW,nm 1C~99JYcɉPVCwqr3bH0pe,.#YLQPDܪ$`F/>E.{O,D mFJUKKպܚB^S IrtxYP|yNk񖒴X9G#+"#V,.c+;1PÊ;'>uL;"V9Lc4  9%\50ir(%¡P`4qfiCD~X'qj-ɼxݘzUJtݖ$q2i5T]WMmنYc+ MF-[m퉩Pହ.<-;ܢ3sg7ZN54 6Yw"/T_n1b Q;۔> >#iB˒FPVb'0ḭ  PXpFGx2'ݸ} XʉN()1N (A!PLfa1aQ1i6p!@X9W:m፲*M]W"r>:m!8] ~gxґTɅd`:]Kog[.1WVUĖտF E:}"^n*/&X#CM2n 11$ÀW1(˱#-M ˉZy@$A188i֡ !@S64@Q $Q9Mܦ䒣 Y<݂^ 9 %JEQ1Bgbx:6uq5+0ܜGs-GbqSY@޸ĞRY˧lUӦp#>\E;^2Xncـ, NԋB@ecAW0ni% ͽ&8re#OS4( 4!al1 0ElE ж-]w]'}&xe蠴;Ej3"D5ϊO+tZ/w"BjSmanuJ`,OdԾB.;{SZFcb] :A"*0`Q`Ŧ#)4./6G !XHЌIVFLdJ`(4ifH &+0@$\P`hc QsO}@?lŽ# >XC-!) "yRHuM[z,7$OVs[uw\VKnigV7EaGf9[vKD@^,mF>a a&X`qW2ni% ͽ JB^?q`0J Ӏ YށdЃu&xEAzY+z##ԍiRF?"PƄϾԖhdNb1WF;"fe;ៗ[ T[\CYj Y $t,#}ȑC`:lƺ̻ s B'vMrpGG`jM0X< sJdGTf&)2 b@qX$\%`ˡt 2` d, 4N$ R1t`/$&j@uшJmJ }OmŹ5gKl>ի_@mK-B;qKrdH>ܥť)j2eY1Qs-Lf$Y jlπAW2m卣+$ͽ޴=AaJ1FO(H8hRĴ`FӸp `ѩ.( 0 GZTϜeatxӁA7RzͦՆo6r WҖFgh`i~\!tΚ> ]jnۍlgbY6`̀)9E衇)X9  $EviZك6 ] W&nm% =g\ijN#@9~ 0Dߩ'%rд|5XU#^ڳ 7guZNfd 7p XlN@2HL0Dz|F"EA(%EfN'C`Q#!!hݤC *mơzf{3S7n8Za\9R.l/:}oYE ZG2#elڦ\;yCtհus0r3v"2xS-A N؀jS)E2G8HDT$Cr$K$T9Ot@ƶu C> 7A9)wa2HcD,I KzC|TvZ;C*ƳS蕷Uj<S0m卪ߪM1nDzjIJTz4S6CHcӨ;$d^&h((3ޕc!M 4 "08' EuP`luW,mXM=F8O1C#D L idelx<͸ bX-h7yڑ%1$jqp]9W\-W6<oˋCÈ-ͪ0T`хz.XJl\Lz>+lwlO4S1!Tz\aVoՎ[DnOIfKqp9z;zt\bi1mE@ԷA Iqm^aaw'O:ڥQU$YG4"u, .!<%x針>)j@+i`&Ex0q@K1  %Q3@pJ G@b ]Ί;$.V S/Qt}%v !ÿ#C;I%դIlUuڵVdiۺ׾FᑀiW>l卲ͼ%ښ$/H'0DQRǏޤLlVA#b dHӶa],1XL_`c DSD 0Xc 1qKAQp[G"X\tERrj< rJɻym L5[ K)LjĞmˌf֨ڠCe·u_vsYcǝUL:i* N0 5[-NnH`*޲ըVXUu/wds f`$LX1hHbaaɄ AITGїBт=ǖ #\(v |P D#T5˷ e*0`&yR=M(F)v B*^Sv aƍ_w=W.neA*=֗H6z>jwmE ɲXYӫSqp"ԾcͿSnhǘmMQ]jffK&rB#G  b6Uo0-D#F.O+Oa*@Á Kљr~uSFw&0ԜdX|'R7:aj"u7F\~'vyHOqwYBq_XԥF&؉nbMC @%Qc\@ʪC5],=sL@Jr(j,yz!$eJItyUK")Ѹ=3Խ4Lms>LsSÀILXժꎦ$k† xʩw7W.m鍢ǪgZI*g1$UJ@axP\f%o>w^heɇUJevZgtk%sij(bIsMx2ɫ5햝w6\ |Gi+rϸm~G=r[yʲh Z%f 86b A̒mV-WmW&niͽ=1"{ETr5%[ӊlaLחnX e K* `XcΚFa6nY@F2Umaq5)x@jj($x tÇ H VY#a"a#QRNa1CO@h XHAumKjxC}!.%#!f Q8A4gҷ\e#jfiVB_Iaۼ[PoIS;$VP]i"kHAY^-]S4SFB.:=7zW&nm 1iAarJ`hAu[JRrd4CXM.@ wl%LBPtLϬpM04r `1 .)9 #1XK`7% Fu r1˨L8"ʗvԭ8 nt;?V+Ɩ-&;gkK$(y˦h<gϛ!EN1i/XJJv\۬FO+e.)jvQuuh@n&r(HPhe(>QxbTfNMr@@."M&!~FDCA K72ߘ@9fLéoaJCn2@<Ke*]p*8O9W*m5e=22 Sx+PW0aYOgƻ^m\3#_໅Ycr_~AmJ}*}98mI` C"'5B`Yhɒ5)PތغV̈Ab NpTa0r?Df/ 'ҥZ"?mFA,F w 9g6*eQ^ (EeA uu}Y2M2JQ"D4T]ˡ<SԈLhT'bZ CRxn?95w2c<0Hia•`ȁ8l "|y@uG B쿂"dD= KV}7q ƨ{mEQ4TzaEH,Dؕ2h._垀W0m鍢* 1cAmEC2ҔM|iM2.0P5x1sQs- Iթ`/ֈ D΀F~r%:dm&8i%RRs6#0#\B"f q ⊮ hƊ D8B FP8 G0ĉw ݌0eGf 찦׹B5(i #wTjҼj&n4Ky*¸$8 N2Z?X/JW:Le⾼[`R62'i&k`P7 u Ya@1-{@3#܊IE6^$D벹TQ(ߢS f!rPel;q y X_{ZY K ׍bbWW.m鍢*͜1)j\AdFa *K̽SmQܦo^&>c.61}73#4>"b)4$18RCT$z+bdA0`А\88 <ËdMC􎃙~U;*j1tN!E%0&P1EfS9%whu#t Ɓdx4m,mf**fY-`3Du -LʼnWV @ԒlD @`ilP0a ;T<8TY @SR饩ʢZyK>{YF,F磷E/icʜR͝ ?q4o%Q5 LQW*m*M1 1L@%!MN}˹Dؼq}rbTtSV$qC1"#67)"p`,*;"a.TDJJHT,k;ȝ<`*AOR e69e/j 5sSi;/>-c6ᢿa>lŖd&%p\ * Ҧ#Fy)`j<D1Bd(({DU(DO/(Q'ȧHFi-v^HajiHi]cihQtx\S[8c/,W\k tNL0؞Fj 1D\  hFF MЀ-S.m鍪* %UQ@ 3`uB 2߅C%4jSs]?}Ab"*6 .!Z+HnKF'Rޥy{w4G;؆l6+Xׯ+$:RFƑ,VaeeJq3pMQ{"l29*FA$ddǢ:JҶ:aAO5mldc0st O0m-eͽ11jN;c v ..|ηD<,xM(fg<QrXiv },fJ'Dr ϧK#rB9\'C( 'vQ$K$ukS>c91#6#6E= f,d/0vQ1Ae!pg ai l5 R ?iZ$ ߅b !y ov>S4Bˢ-*(f2zA$Np0Sr0b&o?FUPOvrNj|]qbr.e@0`pNSL(0=`"0( 0`E0*BE&9Xi*4D4*D4L!0! DѠ6iDA -nMǻG,m鍪ܪ卽197#{|8D؉ܭ] #l9, ;c^-ZsV@q|,⇾ WDhVQQ{YbyG6')թE{0#A Dc# HfSEPc  jbT6@d0 d% q@XaAfr#4zao#L [@P8LiKPiAUP5!Aʮ䀎*kJTU3H`o^KOsCע/եNP5V嫅,hî_9@7Yr"VEEWiu[D /[[9'1&u@S0m鍫*ͽ9A[3BFD( 0Ǘ41[B0JR\ 40DŽB&9^&ݕMOy/Wftʕc!4g9V)ou=*zef[Z yĶ瀽 C)lY63@!ee2.(fosTCU5%s,@ bA54 C$X("2fV 0 fc@3 ;MU("=s< 0P 9R x (t81Cr`< MM(,X#'/!d5ˡ1Aw:cK5$Q,yXr4ћ|Gnޚg#\̑Ĭ.zrKi~Z ش<ȀS*m*ͽ-:Y,G ,*CTytdqnA@s[*$ LYF{c *aR0GD6 .Q\TCwڎ"Oq:wA08 oRh%qߍ?I c,3Ɛ-zvWsjAzH/Uӓ|]+;R\/4"Lrh4JƛlNM[t0a4 1@"J#T~ pLA"s"0< @9a, 03ғ<z6g[)B̡̙U#%P+΄\jf:0Ñ;Lq7nP]W(niN*e ͽ&z ӦeoX],L-"e Y-;Y`nYjٮc51˔bOSfʺ#EB~ $@ڱQ5mcj58=T!uThh љײ+.kW[Qw3ޝRNQqO#%.۹ЩtM[8UO&8FƢ^ߊF.4AwK.nW:l M15 ilB4LV~e\a1fxwlVPC d )Uy:ˌO4ԈՒ=LnW(yeϑH.kOCRPȯ-n!M _"u yj@j)fAVQ謅0^/i,n@4 ҚQ2]~%ﻍC1%(%ڀ z&<)C6@eACP~Hm&yq0Noc$VDWUHȚsn35I&ԗ]5þUEܙ]h:}0f/LBN_ɜ VLeUJmR,;KGppO8JW8l፲* 1G eЁb%'9a2p0*1D\rP MmDFltK} h.txjdv.fȲYŊ4ZjMؿGQU6wSE4q@f[rQOe+tƧ 620330{ LC3 h`@Dʪ!-0 D 5GZe Z'e5>ՠڍcDUgjWnwѦ<`? +(ڄE#匰ef,m72bD<+8uhkV͏2X^A]jaf|~&0`EHˌ áP!C=%<d2"DW.m鍢۪eͽ`m&2'&@`iPMGIN ?HSZjPKJa-)* 8.W`>ϱvYEtf߱cjVР,.4r e'nJm^.[쭨 u -|.Mf,aeu<% (2Ə@JF-+]P@y""uA$Ph>RêDUKJJjMJB}-O_a{Q ('J8!K[:]{`j{Yv;z*ᔤ Jjx& e+Q6cW%ES1=&@`ӆ}#7! ʅ@#BH2 p ?,m鍪Ш1dxI՞SիHMg7>%-مĖxRqj" ..?K:cr;e]CkKh^L[Lqf|q(76nBxQ? ը&fi a.Tb C4aXlk=zF@D:eJ`B*ѭS*_VCo>]_HCS奓ꩃ6c-\ <UU$w6e+}Vz X$mCGrŤHj&=]Nw`&X8Sb0I9PZ`xəSPy`FBv 09tUL@ 0@fPq{νt/eԴ>W*m鍢*%^m*W4 S!r[|ܥVE B}C+ؕ!!o.5 䞩f6L KVb]\_sA` m9>tĵUxHXHnj'@c%&Vd%BAI& $!"HY ZAkE_v7uEe6B QBw4d7;`Y7D{78~(LuD{t%/Jߓm~;V 93(daa@  GPt?< * > @L dG9c!ܱ]AA9mW,m퍢妥 7jj$IRoW5UW/4HVuڴARКCͳ[͓!R  lID h06`G(,ز1aK!f PÍ4|!DR@@c2WFZ h[Rpt*y30b#]~y(ëuF^>?^H JZSMQ‡KIb rLc@<n4˹  B&B|(:&T"~ I(Cdi17!!E C03H" BjEXcuam|襱9iLy@jf0 7(m퍪&M1x}lFӌ\ꩿ)y|n=R{rzG˖VIتDt $9ڴDќ{-Lo 6b+a"K:ŝ,۹jnӍ5mpqWp梼dΰ,/$(w@`$a=tl92҃Af'Tn`A2S^"Px y4"1!c31C 7 nmi& ͽ %!V EroJΆD@iPG߇TֵAy#bpd*#GUn _f旑m ľnl{]źxS/Ďtm.:ݫfsYtr@)]j"(b9 2xᢁ`P I؏#0DU08LTPfLX "PR&E1S; ETfp.U%lЙr6.zŐcRWAÊ: k^BjX mo3+ mѠ᭾#=Vj6ykk;}?,BOMt. S5 S q0QP az2IYiؕZs+UˈY*[Ȭ -p*3OMceX] Z,_F]e.MI]9nVTFO#rjX˒"s2=O"niM1)AQѠpƙ`XHa ߝk5a!ԚUVlM6 QU,he~Ρ73W{Y H} dU&"eǡa`#rÁ|P5eHJ,u>ĄtS}bi5(+)i,F*!W?f]HYx4*Ѭjf}dyH.Q^i.☣Y n9ktʼn+a%7@so[FŌԀ Biɇ)VJ0# t0h2)fc0q h\T !XA!rH(PH b12Q4>*d"Ʀv$o3XZԂ5Eq+~bdyħ 8s_5 +s)s$.lٽ4iJÒ]Z0s #]0Xo4Ֆnʸ'i^71:/rQO~g)L4 e/Qs&20R{RWnрe=(m퍫@ ͽ!4aF y6: 'ON0ቮ" F08p y&:+dj"eNleROc{|d8BL/r3m"ݐ'bv,L[|@0*R<9C/UA\'H  uA\DHO^W%F,0 _,x`jr nYT֯ E:n+-eRl2>+@y{<)UNO݌H| Ϙű֭#_H?knMJ0e0ۘH 'XN# # ?ƒUfd<'BpaBNLAXo)5(m鍪&ͼ 0i+E`3{_]ioqj[|B67/y,H&Tu'Yc :ؚa.zXNlL躓nWhl9Yc:Q 2c8#&P@k&$ 9Yxp= JFC`qQj| xBcQvztɩ ˨'gAYjI& Ѹ Pre% r.!3&K`^Υ͂8T D0@H LP0Y^dӱ  6: A+~ L92D«@c,L*K2BqA:<ߎG&m鍢ͽ\6 hn4-оR_ 6u6Ԃ j mOx6[9G83걜WQ[$7=Hfc_8&'m恬2@1reVA鏛aF)``'DɃƣFDE 1182deS#LV=[r3ǰң]$nX8lz0%3:kmSB=V|]=])bТV'!ټq|Y]hT *2w n!;S/ Cజ#HBD }sM4XTP,ZhLLc8#0+H`̍8L%7 ni&ͽ£p߈e)ƥ3J˞ur<'Ep>jNXqB$DZnϻ_ gՈVCVB}3l*Mud[^kz~ɇ`fӷ]PP3/5.Df<62@](GGD`RFt&Eaq)@Y Tƒ`rLA"ZŃ 4^q퀜&4 b ~Hn+oSbh\d\暘NG!,}d(nwRQm~UVߎW/k؆e6Kɥ7/|a`E>D`d2hB&ְ&0w$Ġ j`fcE/e=ۗPi(L_@  6( Ng@<0,0tW !Хd[蒳%VPÏ:ʬ] l ]Jfbѡ0w^X޶k@5{wq]ۄ_umZBj/GRvjN֯`A" dRQAy( S`#>3!2DTŖTC ! 8eRbٛ-7$m&Mͽ[,0̀ KYG# =_D%Y&t@n/h8)n,Fd(2wBwz~x17*PJLV֭ 1e/{3wDb0Ѿf7Dr1J&=7tV4¢PҤ'0S <2Y*aŠVa$s |(4_"+%X^ R f~aga v12|$K o^[dG6)l;hwյUi[>0MU=/Ux.;khKnFh8lBs,:81H bL9Tą$`٨#L*"3ZxP()%XB '5 nmI& ͽHD錀`1Q8paIF800` :U2`z!KLihLpkr=b>h0[+Qb孍=-U3d,myu|5KX)igP_֝ݶ3osc$a@ sKjmiHVA!EL2rdU096`>@OMJ#<ِd0v'L@5`Y)lr(1\aCAC)`.0)(D4$(LR&@+WBhJh*$ݖ,Eټ2-{aD.fV*ݨ[pnnNkf+VtbI,rUKhD]5Nq-"aឳϖ3 moeeu9Z7?^o+/va tJ4c#!ٳ|s`PV, Ɇ8`P1"! @!PmA&T mVYÖ[Vn񗋢prh݌TQr Cwc+yz{*Ti32<>)6+:/j*ݦs{8Q/0"Ȇo 24A0Q-1P4ZG*e 9jtcFID4R 8(VjpC0B*[o!u| -F:RKsͽZ)Ĝ-hyeI]gks6KyNp[d`4ɋfx(CjeB'{e7(m鍪&=aG'1bfaFJ, B9,N&0@GbdL'YAd+%®]k]/R?K d823h 0| C UJ9'S&.󹣤W rFhd``a AEF x @R cI+JtKI}CZ5W6Xxm6DNt`,ѴQA:#]./֠[&'}p.7WgJ-#*m-A&ͽK\c]?(֤qZ:b֠ayPapӀ{ ZM(1 9 )Ij V0@P@taF>D^U& UAF,j9iňFZ=h(ͳT iV?c.(`7!rΨBqb{T.Y%,#S%[n[rh(hZrbw<`c#I"001P!K%8rRA| ,0O]Έ2f(\axt-&&i$`v:r2 ǩSIjMt\<H\:TSr4Ξ/?OSt(.LOZeI,UL(n"yy'm֘@ P a7#&m퍪$ %&FF42<&8d+8pa &@ IJah .h2h$BH h-9 5)PDDV2` +n<9]G8CPBs j a.ĵ&[w[=#x^abNGK/[ūM#duERrڨ\ب-JtXc bAʦ6$,a@A& :2>oc #$1x t*281(LȰNȐw" 5)\c4% AYsO^,,Ȥ!%6M֡(83Ƞv$O0MhE(Zj#[x=hi5 ʱ6ƏAx<3`0# 0@h( EH6pŝ B$X`(B/Հ# nmϤdM11L1!reRUa0tL2`g\Y, DvvuRXth&`@kBYx74ʫzx,aP]yy mr4يy"7-q^Ŝ}T06p@H\Ģ@ "@ha<85< r ShOBB%NdfƁ"P D(Nn֞vXH+la/fKe~ljMLmu7jN@y K.y;+ͯ\[[T'WLzKNN:5u}ar;x3}<82`!2iĊRt8ܔKK :M &"66X$Sd9ZbSq=#"m鍪$Mͽu0'Aƞ=lx9 Y(Q8wVd:DU/Co2]:I1ML/)&cg\dVijHn {7=PT yUqç6sHk\Bj׉4h9wQ7H ) b'ʹ -@T!R0 t03 &0z HLv0! B$'gEjMc1,a&1" `8(9#"m퍫.$cͽ*LӁKg* 哯HKW0Blgp֊3[Q硭OTl`ʺV@ُgq"B pװi8KOxmjfy=?n`I_@.1t  v:dC āB )Ϭl!8T"@!!Pђ!L$x8[021Q:De)B*6Bٴ#B#V_GbrzOmPKI N* B_&uOԉU}(Ry#xpYۊgYq0H0c B%@]"?:6/QS1Fhʃ|Š"B pis2At`ͳ1_@| 'Vl;U챙(8  +78o GlԋQ/86(GgzLDlŬC;GFj5 Yud}VwWP>! j^yѡfo*&Axb(1d%!QA @#MLI0*N  /"mʤdM1@38!@p0$&1 Sd`M@}ǤhsVe"CJ Ob%F.yfHm9!%I{RKEZTujC2Uξ5稥j<w5EZUCW+D*O?po$9R}499FPJjtdA&3*̲c\P`Ɉ` [k:0V(R0Jak"pAF*&˓\Fa"' ʒ~P_pnCZNdaJP_{f(F4;pV֠[}Lj 30\!A㍞V<:jXI4kcZLTkcڅh`ae6`rbZi`c0bBD 5m!ns mMͽ&K"Exas2J@N2O1O[齶I.ӛ60K3.XٙpړpFɂ~/R@ "AbF,"aR5DBB2@ຉPQF`#@/h֕`<ˁ3`yml]C8\qNW9j2J8p"M˽J@^]QZ/lۻDXy!YLwxVƣ %"m)cͽե TQ7%Ĕ!^gth{Q&-+d8f O1`a:!̼f1\diasQ T ']bֿk?c8^X=#nm te7.5wV#n{ \-$]>ÌEqŃ&fmB$j:xfF :8aA氌a"4"]1-B30bdD}"AApEX5 w,N$ ArѺ'! VٗKd" Ֆz&z]ntzq2e_n!Dz.en eQ,&gi<@,qhp@ attack durSum) (mult (const 1 dur) (pwl 0 start (- attack durSum) highF (+ (- attack dur-prev) decay) sust1 dur sust1))) ((> (+ attack decay) durSum) (mult (const 1 dur) (pwl 0 start (- (+ attack decay) durSum) sust1 dur sust1))) (t (const sust1 dur)))) (t (setf durSum 0) (mult (const 1 dur) (pwl 0 0 attack highF (+ decay attack) sust1 dur sust1)))))) ; Create amplitude envelope for Control Voltages (defun score-to-env-trig (s start dur-prev art-prev attack decay sust release) (let (env1 finish) (cond ((cdr s) (setf env1 (make-env-trig start (car s) dur-prev art-prev attack decay sust release)) (setf finish (last-value env1 (car s))) (seq (mult env1 (const 1 (cadar s))) (score-to-env-trig (cdr s) finish (cadar s) (caddr (car s)) attack decay sust release))) (t (make-env-trig start (car s) dur-prev art-prev attack decay sust release))))) ; Make individual amplitude envelopes. Case checking needed if attack/decay are longer than notes. (defun make-env-trig (start info dur-prev art-prev attack decay sust release) (let ((dur (cadr info)) (art (caddr info))) (cond ((eq art-prev 1) (cond ((> (+ attack decay) dur-prev) (cond ((> (- (+ attack decay) dur-prev) (* dur art)) (setf art-cutoff (seq (const 1 (* dur art)) (const 0 (- dur (* dur art))))) (setf env1 (mult (const 1 dur) (pwl 0 start (- (+ attack decay) dur-prev) sust (* dur art) sust (+ (* dur art) release) 0 dur 0))) (setf env2 (mult art-cutoff env1)) (mult (const 1 dur) (sum env2 (pwl 0 0 (* dur art) 0 (+ (* dur art) .00001) (last-value-2 env2 (* dur art)) (+ (* dur art) release) 0 dur 0)))) (t (mult (const 1 dur) (pwl 0 start (- (+ attack decay) dur-prev) sust (* dur art) sust (+ (* dur art) release) 0 dur 0))))) (t (mult (const 1 dur) (pwl 0 start (* dur art) sust (+(* dur art) release) 0 dur 0))))) (t (cond ((> (+ attack decay) (* dur art)) (setf art-cutoff (seq (const 1 (* dur art)) (const 0 (- dur (* dur art))))) (setf env1 (pwl 0 start attack 1 (+ attack decay) sust (* dur art) sust (+(* dur art) release) 0 dur 0)) (setf env2 (mult art-cutoff env1)) (mult (const 1 dur) (sum env2 (pwl 0 0 (* dur art) 0 (+ (* dur art) .00001) (last-value-2 env2 (* dur art)) (+ (* dur art) release) 0 dur 0)))) (t (mult (const 1 dur) (pwl 0 start attack 1 (+ attack decay) sust (* dur art) sust (+(* dur art) release) 0 dur 0))))))))nyquist-3.05/lib/reverse.lsp0000644000175000000620000001131011466723256015134 0ustar stevestaff;; reverse.lsp -- reverse sounds and files ;; (setf *max-reverse-samples* 25000000) ;; about 100MB of memory (setf *reverse-blocksize* 10000) ;; how many to reverse at a time (defun s-reverse (snd) (multichan-expand #'nyq:s-reverse snd)) (defun nyq:s-reverse (snd) (let ((now (local-to-global 0))) (setf len (snd-length snd *max-reverse-samples*)) (cond ((= len *max-reverse-samples*) (error "s-reverse cannot reverse a sound longer than *max-reverse-samples*"))) (abs-env (at-abs now (nyq:s-reverse-from snd len))))) (defun nyq:s-reverse-from (snd len) (cond ((> len *reverse-blocksize*) (seq (nyq:reverse-some-samples snd (- len *reverse-blocksize*) *reverse-blocksize*) (nyq:s-reverse-from snd (- len *reverse-blocksize*)))) (t (nyq:reverse-some-samples snd 0 len)))) (defun nyq:reverse-some-samples (snd offset len) (display "reverse-some-samples" (snd-length snd 20000) offset len) (let ((samps (snd-samples (nyq:extract-samples snd offset len) len)) (i2 (1- len))) (display "reverse-some-samples" (length samps)) (dotimes (i1 (/ len 2)) (let ((s1 (aref samps i1)) (s2 (aref samps i2))) (setf (aref samps i1) s2) (setf (aref samps i2) s1) (setf i2 (1- i2)))) (snd-from-array (local-to-global 0) (snd-srate snd) samps))) (defun nyq:extract-samples (snd offset len) (let (start stop) (setf start (/ offset (snd-srate snd))) (setf stop (+ start (/ len (snd-srate snd)))) (display "nyq:extract-samples" start stop (snd-t0 snd)) (extract-abs start stop snd))) ;(play (s-reverse (s-read "sample.wav"))) (defun s-read-reverse (filename &key (time-offset 0) (srate *sound-srate*) (dur 10000) (nchans 1) (format *default-sf-format*) (mode *default-sf-mode*) (bits *default-sf-bits*) (endian nil)) (let (fsrate fdur channels rslt) ;; first, read the sound just to get the duration and rate of the file (setf rslt (s-read filename :time-offset time-offset :srate srate :dur dur :nchans nchans :format format :mode mode :bits bits :endian endian)) (if (null rslt) (error "s-read-reverse could not open file" filename)) (setf channels (cadr *rslt*)) (setf *rslt* (cddddr *rslt*)) (setf fsrate (cadr *rslt*)) (display "s-read-reverse" filename srate channels) (setf fdur (caddr *rslt*)) (setf time-offset (max 0 (min fdur time-offset))) (setf dur (max 0 (min (- fdur time-offset) dur))) (cond ((> channels 1) (setf rslt (make-array channels)) (dotimes (i channels) (setf (aref rslt i) (nyq:s-reverse-file filename time-offset fsrate dur channels format mode bits endian i))) rslt) (t (nyq:s-reverse-file filename time-offset fsrate dur channels format mode bits endian nil))))) ;; nyq:s-reverse-file -- do the work of reversing one channel of a file ;; ;; if nchans > 1, chan is the channel number to read ;; (defun nyq:s-reverse-file (filename time-offset srate dur nchans format mode bits endian chan) (let ((blockdur (/ *reverse-blocksize* srate))) (if (> dur blockdur) (seq (nyq:reverse-some-samples (nyq:s-read-chan filename (+ time-offset dur (- blockdur)) srate (/ *reverse-blocksize* srate) nchans format mode bits endian chan) 0 *reverse-blocksize*) (nyq:s-reverse-file filename time-offset srate (- dur blockdur) nchans format mode bits endian chan)) (nyq:s-read-chan filename time-offset srate dur nchans format mode bits endian chan)))) ;; nyq:s-read-chan -- grab some samples from one channel of a file ;; (defun nyq:s-read-chan (filename time-offset srate dur nchans format mode bits endian chan) (let (rslt) (setf rslt (if (= nchans 1) (s-read filename :time-offset time-offset :srate srate :dur dur :nchans nchans :format format :mode mode :bits bits :endian endian) (aref (s-read filename :time-offset time-offset :srate srate :dur dur :nchans nchans :format format :mode mode :bits bits :endian endian) chan))) (if (not rslt) (error "nyq:s-read-chan could not read part of file" filename)) rslt)) ;(play (s-read-reverse "sample.wav")) ;(play (s-read-reverse "test.wav")) nyquist-3.05/lib/pianosyn.lsp0000644000175000000620000005631511466723256015337 0ustar stevestaff;; ================================================ ;; Show Program Information ;; ================================================ (princ "\n\nPiano Synthesizer V1.2 (Feb 2004)\n") (princ " Original algorithm and program by Zheng (Geoffrey) Hua\n") (princ " and Jim Beauchamp, University of Illinois. Any publication\n") (princ " or notes on any composition that utilizes this software\n") (princ " should credit the original creators. Any software based on\n") (princ " this algorithm should carry a similar notice and restriction.\n") (princ " Ported to Nyquist from source code in M4C program by\n") (princ " Ning Hu and Roger Dannenberg, Carnegie Mellon University\n") (princ " School of Computer Science\n\n") (princ " Program Initializing...\n") (setf *pianosyn-path* (current-path)) ;; ================================================ ;; Function definition ;; ================================================ (defun readdat (filename dim data) (setf filename (strcat *pianosyn-path* "piano" (string *file-separator*) filename)) (setq fp (open-binary filename :direction :input)) (dotimes (count 4) (setf (aref dim count) (read-int fp))) (dotimes (count (aref dim 3)) (setf (aref data count) (read-float fp))) (close fp)) (defun build-harmonic-phase (n phase size) (sound-srate-abs size (osc (hz-to-step n) 1 *sine-table* phase))) ;; ****************************************** ;; * Build envelope * ;; ****************************************** ; after the initial envelope, which is stored in a table, ; envelopes are extended by splicing together final segments ; of the real envelope. The final segment is approximately ; exponential, and so each copy of the segments that is ; spliced is scaled by the amount of decay during the segment. ; The long term shape will therefore be exactly exponential, but ; we thought that a bit of variation rather than a perfectly ; smooth exponential decay might be better. ; ; This function takes a segment, the amount of decay in the ; segment (the scale factor for the next segment) and a count ; and builds an envelope ; (defun decay-env (segment decay count) (cond ((<= count 1) (cue segment)) (t (seq (cue segment) (scale decay (decay-env segment decay (1- count))))))) ; PIANO-ENVELOPE builds the amplitude envelope for a group of partials. ; igroup is the index of the group ; sc-duration is the score duration ; attack is the sampled portion of the envelope with a duration of ; gmagendtime ; seg-array is the repeating portion of the envelope tacked onto ; attack to make the envelope longer. The duration of a segment ; in seg-array is gmagendtimemini ; the amount by which seg-array[igroup] decays is scalemag1[igroup] ; ; Algorithm: ; figure out how many repetitions of the seq-array[igroup] to ; add onto the attack to make the envelope long enough. Multiply ; by an exponential decay starting at the duration -- effectively ; the damper hits the string at sc-duration. ; (defun piano-envelope (igroup sc-duration gmagendtime gmagendtimemini attack seg-array scalegmag1) (let ((decaycount (1+ (truncate (/ (- (+ sc-duration endingtime) gmagendtime) gmagendtimemini)))) pianoenv ) (setf pianoenv (sim (at 0 (cue attack)) (at gmagendtime (decay-env (aref seg-array igroup) (aref scalegmag1 igroup) decaycount)))) ;; For ending time (mult (scale (aref scale1 igroup) pianoenv) (pwlv 1 sc-duration ; decay to 1/1000: about 60dB 1 (+ sc-duration endingtime) 0.001)))) ;; ****************************************** ;; * Build wavetable * ;; ****************************************** (defun piano-group (jgroup sc-duration freq table) (sound-srate-abs *piano-srate* (osc (hz-to-step freq) sc-duration (aref table jgroup)))) ;; ****************************************** ;; * Produce single piano note * ;; ****************************************** (defun piano-note (duration pitch dynamic) (let ((ioi (get-duration duration)) (full-pitch (+ (get-transpose) pitch)) (full-dynamic (+ (get-loud) dynamic)) ;; note: the "loud" is nominally in dB, but ;; piano-note-abs uses something akin to midi velocity ;; we should probably work out a better conversion (start-time (local-to-global 0)) on-dur) (setf on-dur (* ioi (get-sustain))) (set-logical-stop (abs-env (at start-time (piano-note-abs on-dur full-pitch full-dynamic))) ioi))) ;; PIANO-NOTE-ABS -- private function to do the work; assumes ;; stretch factor of 1, etc. (defun piano-note-abs (sc-duration sc-pitch sc-dynamic) (let (attnamp freq key whichone whichone1 ngroup1 ngroup2 dyna smax dur gmagendtime gmagendtimemini k j envpoint) ;; ****************************************** ;; * Initilization for each note * ;; ****************************************** (setq attnamp 0.03) ; key is midi pitch number (setq key (truncate (+ sc-pitch 0.000001))) (cond ((< key 21) ;; 21 is A0, lowest pitch on this piano (break "piano-note-abs pitch is too low" sc-pitch) ;; continued -- transpose up to lowest octave (while (< key 21) (setf sc-pitch (+ sc-pitch 12)) (setf key (truncate (+ sc-pitch 0.000001))))) ((> key 108) ;; 108 is c9, highest pitch on this piano (break "piano-note-abs pitch is too high" sc-pitch) ;; continued -- transpose down to highest octave (while (> key 108) (setf sc-pitch (- sc-pitch 12)) (setf key (truncate (+ sc-pitch 0.000001)))))) (setq freq (step-to-hz sc-pitch)) (setq whichone -2) (dotimes (i GROUPCON) (if (and (= whichone -2) (< freq (- (aref fa i) 0.001))) (setq whichone (- i 1)))) ;; Have to use (- (aref fa i) 0.001) because of the calculation precision of Nyquist (setq whichone1 (1+ whichone)) (setq ngroup2 (aref ngroup whichone1)) (setq dyna (truncate sc-dynamic)) (setq smax 0.25) ; (setq attnpretime (/ (+ (* 0.018 dyna dyna) (* -3.9588 dyna) 244.8139) 1000.0)) (setq dur (aref durtab (+ (* key 128) dyna))) (setq ngroup1 (aref ngroup whichone)) (setq gmagendtime (* (nth whichone hkframe) (aref dt whichone))) (setq gmagendtimemini (* (aref nptsmini whichone) (aref dtmini whichone))) (setq k (* (aref gmaxtabdim 1) (aref gmaxtabdim 2))) (setq j (+ (* whichone k) (* dyna (aref gmaxtabdim 2)))) (dotimes (i (aref gmaxtabdim 2)) (setf (aref gmax1 i) (aref gmaxtab j)) (incf j)) (dotimes (i ngroup1) (setq envpoint (sref (aref (aref gmagmini whichone) i) 0)) (if (/= envpoint 0) (setf (aref scalegmag1 i) (/ (sref (aref (aref gmagmini whichone) i) (- gmagendtimemini (aref dtmini whichone))) envpoint)) (setf (aref scalegmag1 i) 0.0)) (setf (aref scale1 i) (* smax (aref gmax1 i)))) (if (> ngroup2 ngroup1) (setf ngroup2 ngroup1)) (if (< dur sc-duration) (setq sc-duration dur)) ;; ********************** ;; * now sum the groups * ;; ********************** (scale 0.5 (sim (at 0 (set-logical-stop (cue (scale attnamp attsound)) sc-duration)) (at 0 (cue (simrep (i ngroup2) (mult (piano-envelope i sc-duration gmagendtime gmagendtimemini (aref (aref gmag whichone) i) (aref gmagmini whichone) scalegmag1) (piano-group i (+ sc-duration endingtime) freq (aref wavetab whichone1)))))))) )) ;;;;; This is for debugging -- replace synthesis with a sine tone to study envelope ; (at 0 (cue (mult (piano-envelope 0 sc-duration gmagendtime ; gmagendtimemini (aref (aref gmag whichone) 0) ; (aref gmagmini whichone) scalegmag1) ; (osc c4 2.0)))))))) (defun piano-note-2 (sc-pitch sc-dynamic) (let ((dur (get-duration 1))) (stretch-abs 1 (piano-note dur sc-pitch sc-dynamic)))) (defun piano-midi (midiin) (let (midi-seq midifile) (setf midi-seq (seq-create)) (setf midifile (open-binary midiin)) (seq-read-smf midi-seq midifile) (close midifile) (seq-midi midi-seq (note (channel pitch velocity) (piano-note-2 pitch velocity))))) ;; ****************************************** ;; *Produce wave file according to MIDI file* ;; ****************************************** (defun piano-midi2file (midiin out-name) (princ "\nBegin sound production\n") (princ "=============================================\n") (s-save (piano-midi midiin) ny:all (string out-name) :play T) (princ "=============================================\n") (princ "End sound production\n")) ;; ==================================== ;; Main Program ;; ==================================== (if (not (boundp '*piano-srate*)) ;; if pianosyn.lsp wasn't loaded already (expand 70)) ;; we'll allocate a lot of nodes for data, so expand now (setf *pianosyn-save-gc-flag* *gc-flag*) (setf *gc-flag* nil) ;; we'll do a lot of gc, so turn off messages ;; Definite some constant (setq NPITCH 22 GROUPCON 23) (setq MAXAMP 32767.0) (setq TWOPI (+ pi pi)) (setq *piano-srate* *default-sound-srate*) (setq bits 32) ;; 512 gives pretty good SNR for interpolated sines ;; some tables will be larger: 512 is just the minimum (setq tabsize 512) ;; For ending time, use 30 msec. (This was originally 0.1 msec, ;; about 4 samples, but that's too short to avoid clicks.) ;; This not only must avoid clicks but it simulates the damper. ;; This is the time to decay to 0.001 of the original, so it's ;; actually quite a rapid decay. (setq endingtime 0.03) (setf hkframe (list 66 73 82 90 99 108 116 123 130 135 138 140 138 133 126 117 107 102 105 127 153 187 200)) (setf attsratelist (list 8000 11025 16000 22050 32000 44100 48000)) (setf gmax1 (make-array GROUPCON)) (setf scalegmag1 (make-array GROUPCON)) (setf scale1 (make-array GROUPCON)) (setf wavetab (make-array GROUPCON)) (setf ti (make-array GROUPCON)) (setf tstep (make-array GROUPCON)) (setf gmaxtabdim (make-array 4)) (setf gmaxtab (make-array 64768)) (setf durtabdim (make-array 4)) (setf durtab (make-array 16384)) (setf rlsratetabdim (make-array 4)) (setf rlsratetab (make-array 11392)) (setf fa (make-array GROUPCON)) (setf dt (make-array GROUPCON)) (setf ngroup (make-array GROUPCON)) (setf npts (make-array GROUPCON)) (setf gmag (make-array GROUPCON)) (setf nhar (make-array GROUPCON)) (setf gmagmini (make-array GROUPCON)) (setf dtmini (make-array GROUPCON)) (setf nptsmini (make-array GROUPCON)) (setf cw (make-array GROUPCON)) (setf phase (make-array GROUPCON)) (setf hfrom (make-array GROUPCON)) (setf hto (make-array GROUPCON)) (setf *zero-table* (scale 0 (build-harmonic 1 tabsize))) ;; ================================================= ;; run-once initilization: pianoActor construction ;; ================================================= (princ "\nBegin Instrument-wise initialization...\n") (princ "=======================================\n") (princ "Reading source files:\n") ;; Read gmax.tab (readdat "gmax.tab" gmaxtabdim gmaxtab) ;; Read dur.tab (readdat "dur.tab" durtabdim durtab) ;; Read rlsrate.tab (readdat "rlsrate.tab" rlsratetabdim rlsratetab) ;; Read cwxx.cwd (dotimes (pncount GROUPCON) (format t "~A " pncount) (setq filename (strcat "pn" (string (int-char (+ (truncate (/ pncount 10)) 48))) (string (int-char (+ (rem pncount 10) 48))) ".cod")) (setq filename (strcat *pianosyn-path* "piano" (string *file-separator*) filename)) (setq fp (open-binary filename)) ;; Read cwdHdr in cwxx.cwd (setq cwdHdr-ckID (read-int fp) cwdHdr-type (read-int fp)) ;; "CNDN" == 1129202766 ;; That is for "FORM"==cwdHdr-ckID ;;(if (and (= cwdHdr-ckID 1179603533) (= cwdHdr-type 1129202766)) ;; () ;; (error "Error in reading chunk header.")) ;;That is for "SYNC"==cwdHdr-ckID (if (and (= cwdHdr-ckID 1398361667) (= cwdHdr-type 1129202766)) () (error "Error in reading chunk header.")) ;; Read COMMCK in cwxx.cwd (setq COMMCK-ckID (read-int fp)) (if (= COMMCK-ckID 1129270605) () (error "COMMCK chunk not found.")) (setq COMMCK-fa (read-float fp) COMMCK-dt (read-float fp)) (setf (aref fa pncount) COMMCK-fa) (setf (aref dt pncount) COMMCK-dt) (setf (aref dtmini pncount) (* 10 COMMCK-dt)) (setq COMMCK-npts (read-int fp) COMMCK-ngroup (read-int fp)) (setf (aref npts pncount) COMMCK-npts) (setf (aref nptsmini pncount) (truncate (/ (+ 9 (- COMMCK-npts (nth pncount hkframe))) 10))) (setf (aref ngroup pncount) COMMCK-ngroup) ;; Read DATACK in cwxx.cwd (setq DATACK-ckID (read-int fp)) (if (= DATACK-ckID 1346458196) () (error "DATACK chunk not found.")) (setf (aref nhar pncount) (read-int fp)) (setf (aref cw pncount) (make-array (aref nhar pncount))) (setf (aref phase pncount) (make-array (aref nhar pncount))) (dotimes (count (aref nhar pncount)) (setf (aref (aref cw pncount) count) (read-float fp))) (dotimes (count (aref nhar pncount)) (setf (aref (aref phase pncount) count) (read-float fp))) ;; Read GRUPCK in cwxx.cwd (setq GRUPCK-ckID (read-int fp)) (if (= GRUPCK-ckID 1196578128) () (error "GRUPCK chunk not found.")) (setf (aref hfrom pncount) (make-array (aref ngroup pncount))) (setf (aref hto pncount) (make-array (aref ngroup pncount))) ;(display "reading grupck" (aref ngroup pncount) (aref nhar pncount) pncount) (dotimes (count (aref ngroup pncount)) (setf (aref (aref hfrom pncount) count) (read-float fp))) (dotimes (count (aref ngroup pncount)) (setf (aref (aref hto pncount) count) (read-float fp))) ;; Read GMAGCK in cwxx.cwd (setq GMAGCK-ckID (read-int fp)) (if (= GMAGCK-ckID 1196245319) () (error "GMAGCK chunk not found.")) (setq gmaghead (read-int fp)) (close fp) (setf (aref gmag pncount) (make-array (aref ngroup pncount))) (setq gmagrate (/ 1 (aref dt pncount))) (setq gmagdur (/ (nth pncount hkframe) gmagrate)) ; (display "gmagmini" pncount (aref ngroup pncount)) (setf (aref gmagmini pncount) (make-array (aref ngroup pncount))) (setq gmagratemini (/ 1 (aref dtmini pncount))) (setq gmagdurmini (/ (aref nptsmini pncount) gmagratemini)) (dotimes (i (aref ngroup pncount)) (let (gmaghead1 samps gmaghead1mini) (setf gmaghead1 (/ (float gmaghead) (* gmagrate (/ bits 8)))) ;(display "gmag read" i gmaghead1 gmagrate filename) (setf samps (s-read filename :time-offset gmaghead1 :srate gmagrate :dur gmagdur :mode snd-mode-float :format snd-head-raw :bits bits :endian :big)) (if samps (snd-length samps ny:all)) ; force read into memory (setf (aref (aref gmag pncount) i) samps) (setq gmaghead (+ gmaghead (* 4 (nth pncount hkframe)))) (setq gmaghead1mini (/ (float gmaghead) (* gmagratemini (/ bits 8)))) ;(display "gmag read mini" i gmaghead1mini gmagratemini filename) (setf samps (s-read filename :time-offset gmaghead1mini :srate gmagratemini :dur gmagdurmini :mode snd-mode-float :format snd-head-raw :bits bits :endian :big)) (if samps (snd-length samps ny:all)) ; force read into memory ;(display "read gmagmini" filename pncount i ; (if samps (snd-length samps ny:all))) (setf (aref (aref gmagmini pncount) i) samps) (setq gmaghead (+ gmaghead (* 4 (aref nptsmini pncount)))) )) ) (setq maxfreq (aref fa (1- GROUPCON))) (dotimes (i GROUPCON) (setq ngrouptemp -1) (dotimes (j (aref ngroup i)) (if (and (= ngrouptemp -1) (>= (* (aref (aref hto i) j) (aref fa i)) (/ *piano-srate* 2))) (setq ngrouptemp j))) (if (>= ngrouptemp 0) (setf (aref ngroup i) ngrouptemp))) (princ "\nGenerating wavetables...\n") (setq tempi (/ (* 360 tabsize) (* TWOPI TWOPI))) (dotimes (h GROUPCON) (setf (aref wavetab h) (make-array (aref ngroup h))) (dotimes (i (aref ngroup h)) ;(FORMAT T "WAVE ~A OF GROUP ~A~%" i h) (let ((low (aref (aref hfrom h) i)) (high (aref (aref hto h) i)) tempphase tempcw (len tabsize)) ; table size must be more than twice greatest harmonic number ; use a factor of three so we have a wider margin of oversampling (setf len (max len (* 3 high))) (setf sumwave *zero-table*) (do ((k (truncate low) (incf k))) ((> k high)) (cond ((< k (aref nhar h)) (setq tempphase (aref (aref phase h) k)) (setq tempcw (aref (aref cw h) k))) (t (setq tempphase 0) (setq tempcw 0))) (setf sumwave (sum sumwave (scale tempcw (build-harmonic-phase k (+ (* tempphase tempi) 90.0) len)))))) ;(PRINT "FORCE SUMMATION OF WAVE") (snd-length sumwave ny:all) ; force summation ;( "END SUMMATION OF WAVE") (setf (aref (aref wavetab h) i) (list sumwave (hz-to-step 1) T)))) ;; Read in attack sound (princ "\nRead in attack sound...\n") (setq attndur 0.5) (setq attnth -1) (dotimes (count (length attsratelist)) (if (and (= attnth -1) (<= *piano-srate* (nth count attsratelist))) (setq attnth count))) (if (or (= attnth -1) (/= (nth attnth attsratelist) *piano-srate*)) (princ "No attack sound rate corresponds to current sound rate, use the nearest one\n")) (if (> attnth 0) (if (<= (- (nth attnth attsratelist) *piano-srate*) (- *piano-srate* (nth (1- attnth) attsratelist))) (setq attsrate (nth attnth attsratelist)) (setq attsrate (nth (1- attnth) attsratelist))) (case attnth (-1 (setq attsrate (last attsratelist))) (0 (setq attsrate (nth 0 attsratelist))))) (setq filename (format nil "att~A.pcm" (truncate attsrate))) (setf filename (strcat *pianosyn-path* "piano" (string *file-separator*) filename)) (setf attsound (s-read filename :srate attsrate :dur attndur :format snd-head-raw :mode snd-mode-pcm :bits 16 :endian :big)) (princ "=============================================\n") (princ "End instrument-wise initialization\n") (princ "\n\n=============================================\n") (princ "Piano Synthesizer function definition:\n") (princ "(piano-note-2 step dynamic)\n") (princ "(piano-note duration step dynamic)\n") (princ "(piano-midi midi-file-name)\n") (princ "(piano-midi2file midi-file-name sound-file-name)\n\n") (princ "=============================================\n") (setf *gc-flag* *pianosyn-save-gc-flag*) ;; restore original value #| ;;================= DEBUGGING CODE ========================= ;; ;; run (show-cn-file n) to dump some data from pn??.cod ;; ;;========================================================== ;; INT-HEX -- convert integer to hex string ;; (defun int-hex (int) (let ((result "") ch) (while (/= int 0) (setf ch (char "0123456789ABCDEF" (logand int 15))) (setf result (strcat (string ch) result)) (setf int (/ int 16))) (if (equal result "") "0" result))) (defun int-4char (int) (strcat (string (int-char (logand 255 (/ int (* 256 256 256))))) (string (int-char (logand 255 (/ int (* 256 256))))) (string (int-char (logand 255 (/ int 256)))) (string (int-char (logand 255 int))))) (defun show-cn-file (pncount) (let (filename fp cwdhdr-ckid cwdhdr-type) (setq filename (strcat "pn" (string (int-char (+ (truncate (/ pncount 10)) 48))) (string (int-char (+ (rem pncount 10) 48))) ".cod")) (setf filename (strcat *pianosyn-path* "piano" (string *file-separator*) filename)) (format t "SHOW-CN-FILE ~A (~A)~%" pncount filename) (setf fp (open-binary filename)) ;; Read cwdHdr in cwxx.cwd (setq cwdHdr-ckID (read-int fp) cwdHdr-type (read-int fp)) (format t "header ckID: ~A (~A)~%" (int-hex cwdhdr-ckid) (int-4char cwdhdr-ckid)) (format t "header type: ~A (~A)~%" (int-hex cwdhdr-type) (int-4char cwdhdr-type)) (setq COMMCK-ckID (read-int fp)) (format t "header ckID: ~A (~A)~%" (int-hex commck-ckid) (int-4char commck-ckid)) (setq COMMCK-fa (read-float fp) COMMCK-dt (read-float fp)) (format t "commck-fa ~A commck-dt ~A~%" commck-fa commck-dt) (setq COMMCK-npts (read-int fp) COMMCK-ngroup (read-int fp)) (format t "commck-npts ~A commck-ngroup ~A~%" commck-npts commck-ngroup) (setq DATACK-ckID (read-int fp)) (format t "header ckID: ~A (~A)~%" (int-hex datack-ckid) (int-4char datack-ckid)) (setf datack-nhar (read-int fp)) (format t "datack-nhar ~A~%cw data:" datack-nhar) (dotimes (i datack-nhar) (if (and (zerop (rem i 10)) (or (< i 10) (> i (- datack-nhar 10)))) (format t "~% ~A:" i)) (setf data-cw (read-float fp)) (if (or (< i 10) (>= i (* (/ datack-nhar 10) 10))) (format t " ~A" data-cw))) (format t "~%phase data:") (dotimes (i datack-nhar) (if (and (zerop (rem i 10)) (or (< i 10) (> i (- datack-nhar 10)))) (format t "~% ~A:" i)) (setf data-phase (read-float fp)) (if (or (< i 10) (> i (- datack-nhar 10))) (format t " ~A" data-cw))) (format t "~%") (setf grupck-ckid (read-int fp)) (format t "header ckID: ~A (~A)~%hfrom data:" (int-hex grupck-ckid) (int-4char grupck-ckid)) (dotimes (count commck-ngroup) (setf data-hfrom (read-float fp)) (if (zerop (rem count 10)) (format t "~% ~A:" count)) (format t " ~A" data-hfrom)) (format t "~%hto data:") (dotimes (count commck-ngroup) (setf data-hto (read-float fp)) (if (zerop (rem count 10)) (format t "~% ~A:" count)) (format t " ~A" data-hto)) (setf gmagck-ckid (read-int fp)) (format t "~%header ckID: ~A (~A)~%" (int-hex gmagck-ckid) (int-4char gmagck-ckid)) (setf gmaghead (read-int fp)) (format t "gmaghead ~A" gmaghead) (format t "~%") ;; compute range of data to be read (setf offset gmaghead) (dotimes (i commck-ngroup) (format t "gmag: group ~A offset ~A length ~A end ~A~%" i offset (* 4 (nth pncount hkframe)) (+ offset (* 4 (nth pncount hkframe)))) (setf offset (+ offset (* 4 (nth pncount hkframe)))) (format t "gmagmini: group ~A offset ~A length ~A end ~A~%" i offset (* 4 (aref nptsmini pncount)) (+ offset (* 4 (aref nptsmini pncount)))) (setf offset (+ offset (* 4 (aref nptsmini pncount))))) (close fp) (setf gmag-and-gmagmini (s-read filename :time-offset (* (float gmaghead) 0.25 commck-dt) :srate (/ 1.0 commck-dt) :mode snd-mode-float :format snd-head-raw :bits 32 :endian :big)))) |# nyquist-3.05/lib/sdl.lsp0000755000175000000620000003255511466723256014264 0ustar stevestaff;;; Score Description Library. v 1.0 ;;; pmorales. Junio, 2007 ; NOTAS: ; - es obligatorio definir un instrumento al menos y asignarlo desde el principio ; - en su lugar hay que utilizar TF (time factor) que tiene un efecto similar al de Cakewalk ; - los atributos ATTR solo tienen efecto sobre el instrumento que estan definidos. ; los atributos estan asociados a un instrumento en particular ; a helper function ------------------------------------------ (defun floor (x) (round (- x 0.5))) ; this code is imported from pmorales lambda music (defun sdl:pitch-lex (pitch) "ARGS: pitch DEVUELVE: Cadena con el valor del argumento convertido a pitch-midi" (case (type-of pitch) (fixnum pitch) (flonum pitch (round pitch)) (symbol (sdl:pitch-name->step (let ((str (symbol-name pitch))) (if (equal (char str 0) #\:) (subseq str 1) str)))) (string (sdl:pitch-name->step pitch)) (t (error "PITCH-LEX: Error lexico en especificacion de pitch")))) (defun sdl:digit-char-p (chr) (char>= #\9 chr #\0)) (defun sdl:code-pitch-p-1 (chr) (or (char>= #\g chr #\a) (char>= #\G chr #\A))) (defun sdl:code-pitch-p-2 (chr) (or (eq chr #\#) (eq chr #\b)(eq chr #\B)(eq chr #\s)(eq chr #\f) (sdl:digit-char-p chr))) (defun sdl:pitch-p (str) "Detecta si el argumento es un simbolo que representa un pitch" (case (length str) (1 (sdl:code-pitch-p-1 (aref str 0))) (2 (and (sdl:code-pitch-p-1 (char str 0)) (sdl:code-pitch-p-2 (char str 1)))) (3 (and (sdl:code-pitch-p-1 (char str 0)) (sdl:code-pitch-p-2 (char str 1)) (sdl:digit-char-p (char str 2)))) (4 (and (sdl:code-pitch-p-1 (char str 0)) (sdl:code-pitch-p-2 (char str 1)) (sdl:digit-char-p (char str 2)) (sdl:digit-char-p (char str 3)))))) (defun sdl:b-or-# (pname) (let ((chrom (char pname 1))) (case chrom ((#\b #\B #\f) -1) ((#\# #\s) 1) (t 0)))) (defun sdl:pitch-name-category (pname) (let ((first-char (char pname 0))) (case first-char ((#\C #\c) 0) ((#\D #\d) 2) ((#\E #\e) 4) ((#\F #\f) 5) ((#\G #\g) 7) ((#\A #\a) 9) ((#\B #\b) 11) (t (error (strcat "Improper pitch name " pname)))))) (defun sdl:char-to-val (char) (- (char-code char) 48)) (defun sdl:string-to-val (string) (let ((len (1- (length string)))) (do* ((i -1 (1+ i)) (suma 0 (+ suma (* (sdl:char-to-val (char string i)) (expt 10 (float (- len i))))))) ((= i len) suma)))) (defun sdl:pitch-name->step (pname) (when (symbolp pname) (setf pname (string-trim ":" (symbol-name pname)))) (let ((chrom (sdl:b-or-# pname)) (category (sdl:pitch-name-category pname)) (octave (sdl:string-to-val (string-left-trim "AaBbCcDdEeFfGg#s" pname)))) (+ chrom category (* 12 (- octave 4)) 60))) (defun sdl:one-of-twelve-to-string (number) (case number (0 "C") (1 "C#") (2 "D") (3 "D#") (4 "E") (5 "F") (6 "F#") (7 "G") (8 "G#") (9 "A") (10 "A#") (11 "B"))) (defun step->pitch-name (midi-number) (let ((one-of-twelve (rem midi-number 12)) (octave (1- (floor (/ midi-number 12))))) (format nil "~A~A" (sdl:one-of-twelve-to-string one-of-twelve) octave))) (defun step->hz (midi) (* 440.0 (expt 2.0 (/ (- midi 69.0) 12.0)))) (defun pitch-name->hz (name) (step->hz (pitch-name->step name))) (defun pitch-name->step (pn) (if (numberp pn) pn (sdl:pitch-name->step pn))) ;;; functions for SYMBOL PROPERTY LIST processing (defun sdl:iterate-on-symbol-plist (fun plist &optional result) (if plist (sdl:iterate-on-symbol-plist fun (cddr plist) (cons (funcall fun (car plist) (second plist)) result)) result)) (defun sdl:sort-pwl (plist) (sdl:iterate-on-symbol-plist #'(lambda (sym pwl-list) (list sym (sort pwl-list #'(lambda (x y) (< (car x)(car y)))))) plist)) ; ATENCION: los calculos se hacen sobre pulsos, no sobre segundos (defun sdl:calcule-pwl-val (tm plist) (apply #'append (sdl:iterate-on-symbol-plist #'(lambda (prop-sym prop-val) (list prop-sym (sdl:pwl-val tm prop-val))) plist))) ; this function compute variable attributes (defun sdl:pwl-val (x points) (labels ((pwl-interpolate (x x1 y1 x2 y2) (let* ((a (/ (- y1 y2) (- x1 (float x2)))) (b (- y1 (* a x1)))) (+ b (* a x)))) (search-points (x points &optional (result 0)) (if (or (null points) (< x (caar points))) result (search-points x (cdr points) (+ 1 result)))) (points-xval (n points) (car (nth n points))) (points-yval (n points) (cadr (nth n points)))) (let ((len (length points)) (index (search-points x points))) (cond ((= 0 index) (points-yval 0 points)) ((= len index) (points-yval (- len 1) points)) (t (pwl-interpolate x (points-xval (- index 1) points) (points-yval (- index 1) points) (points-xval index points) (points-yval index points))))))) ; macros in SDL-------------------------------------------------------------- (defun sdl:is-event-macro? (ev) (and (listp ev) (equal (car ev) 'MAC))) (defun sdl:score-has-macros? (sdl-sco) (do ((i 0 (+ 1 i)) result) ((cond ((sdl:is-event-macro? (nth i sdl-sco)) (setf result T) T) ((= i (length sdl-sco)) T)) result))) (defun sdl:expand-macros (sdl-sco) (apply #'append (mapcar #'(lambda (ev) (cond ((not (listp ev)) (list ev)) ((and (listp ev) (not (equal (car ev) 'MAC))) (list ev)) (t (apply (second ev) (cddr ev))))) sdl-sco))) ; main functions for SDL ------------------------------------------------------- ; this is a BIG function (defun sdl:sdl->score-aux (score-data &optional time-marks) (let ((tf 1.0) ; global time factor sc-instr chords (sc-time 0) (sc-dur 1)) (unless time-marks (setf time-marks (gensym))) (labels ((filter-name (ky l &optional xresult) (if l (if (not (member (car l) ky :test #'equal)) (let () (push (car l) xresult) (push (cadr l) xresult) (filter-name ky (cddr l) xresult)) (filter-name ky (cddr l) xresult)) (reverse xresult))) (attrs-vals () (symbol-plist sc-instr)) (scale-score-time (event scale) (list (* scale (car event)) (* scale (cadr event)) (caddr event))) (make-sc-note (p) (list sc-time sc-dur (append (list (get sc-instr :name) :pitch (sdl:pitch-lex p)) (sdl:calcule-pwl-val sc-time (get sc-instr :pwl)) (filter-name (list :name :pwl) (attrs-vals))))) (calcula-dur (datum) (if (listp datum) (eval datum) datum)) (setdur (dur) (setf sc-dur (calcula-dur (car dur)))) (setinstr (instr) (setf sc-instr (intern (car instr)))) (init-instr (instr instr-name) (setf sc-instr (intern instr)) (setf (symbol-plist sc-instr) NIL) (putprop sc-instr (gensym) :pwl) (putprop sc-instr instr-name :name)) (set-attr (prop val) (putprop sc-instr val prop)) (set-pwl-point (prop val) (push (list sc-time val) (get (get sc-instr :pwl) prop))) (set-mrk (mrk-symbol) (if (get time-marks mrk-symbol) (error "sdl->score: time mark ~A already set" mrk-symbol) (putprop time-marks sc-time mrk-symbol))) (set-time-mrk (mrk-symbol) (let ((mrk-time (get time-marks mrk-symbol))) (if mrk-time (setf sc-time mrk-time) (error (format nil "sdl->score: time mark ~A does not exists" mrk-symbol))))) (proc-elt-for-pwl (elt) (if (not (listp elt)) (cond ((numberp elt) (setf sc-time (+ sc-time elt)) NIL) (t (setf sc-time (+ sc-time sc-dur)) NIL)) (case (car elt) ((KEY TS CHN PATCH LM TN MRK NTR) NIL) ; filter out all these ; for compatibility with lambda music ((TF) (setf tf (calcula-dur (cadr elt))) NIL) ((LABEL SET-MRK) NIL) ((AT-LABEL AT-MRK) NIL) ((TIME-IN-SECONDS) (setf tf 0.25) NIL) ; with mm = 60 ((DUR) (setdur (cdr elt)) NIL) ((INSTRUMENT) (setinstr (cdr elt)) NIL) ((INIT-INSTR) (init-instr (second elt)(third elt)) NIL) ((ATTR) NIL) ((PWL-POINT) (set-pwl-point (second elt) (calcula-dur (third elt))) NIL) ((FUN) (apply (eval (cadr elt)) (cddr elt))) ((DELTA PAU) (setf sc-time (+ sc-time (calcula-dur (second elt)))) NIL) ; pause positive or negative ((CH) (setf sc-time (+ sc-time sc-dur)) NIL) ((CH1) (setf sc-dur (calcula-dur (third elt))) ; pitch dur (setf sc-time (+ sc-time sc-dur)) NIL) (t (setf sc-dur (calcula-dur (cadr elt))) (setf sc-time (+ sc-time sc-dur)) NIL)))) (proc-elt (elt) (if (not (listp elt)) (cond ((numberp elt) (setf sc-time (+ sc-time elt)) NIL) (t (let ((ret-note (make-sc-note elt))) (setf sc-time (+ sc-time sc-dur)) ret-note))) (case (car elt) ((KEY TS CHN PATCH LM TN MRK NTR) NIL) ; filter out all these ; for compatibility with lambda music ((TF) (setf tf (calcula-dur (cadr elt))) NIL) ((LABEL SET-MRK) (set-mrk (second elt)) NIL) ((AT-LABEL AT-MRK) (set-time-mrk (second elt)) NIL) ((TIME-IN-SECONDS) (setf tf 0.25) NIL) ((DUR) (setdur (cdr elt)) NIL) ((INSTRUMENT) (setinstr (cdr elt)) NIL) ((INIT-INSTR) NIL) ;(init-instr (second elt)(third elt)) NIL) ((ATTR) (set-attr (second elt) (calcula-dur (third elt))) NIL) ((PWL-POINT) NIL) ((FUN) (apply (eval (cadr elt)) (cddr elt))) ((DELTA PAU) (setf sc-time (+ sc-time (calcula-dur (second elt)))) NIL) ; pause positive or negative ((CH) (dolist (n (cdr elt)) (push (make-sc-note n) chords)) NIL) ((CH1) (setf sc-dur (calcula-dur (third elt))) ; pitch dur (make-sc-note (second elt))) (t (setf sc-dur (calcula-dur (cadr elt))) (let ((ret-note (make-sc-note (car elt)))) (setf sc-time (+ sc-time sc-dur)) ret-note)))))) ; first sets pwl data (dolist (ev score-data NIL) (proc-elt-for-pwl ev)) ; sort pwl data (dolist (elt score-data NIL) (when (and (listp elt) (equal (car elt) 'INIT-INSTR)) (putprop (intern (second elt)) (apply #'append (sdl:sort-pwl (symbol-plist (get (intern (second elt)) :pwl)))) :pwl))) ; then process score (setf sc-time 0.0) (do ((data score-data (cdr data)) (result '())) ((null data) (list (sort (mapcar #'(lambda (ev) (scale-score-time ev tf)) result) #'(lambda (x y) (< (car x) (car y)))) time-marks)) (let ((proced-elt (proc-elt (car data)))) (when proced-elt (push proced-elt result))) (setf result (append result chords)))))) (defun sdl:get-key (l k) (when l (if (equal (car l) k) (second l) (sdl:get-key (cdr l) k)))) (defun sdl:apply-mm-to-score (sco) (let (current-time current-dur end-last-note gap current-mm result) (setf current-mm (sdl:get-key (caddar sco) :mm)) (setf current-time (* (/ 15.0 current-mm) (caar sco))) (setf end-last-note (caar sco)) (dolist (ev sco) (setf gap (- (car ev) end-last-note)) (setf end-last-note (+ (car ev) (second ev))) (setf current-mm (sdl:get-key (caddr ev) :mm)) (setf current-dur (* (/ 15.0 current-mm) (cadr ev))) (push (list (+ current-time (* (/ 15.0 current-mm) gap)) current-dur (caddr ev)) result) (setf current-time (+ current-time (* (/ 15.0 current-mm) gap) current-dur))) (reverse result))) (defun sdl:normalize-score-duration (sco) (mapcar #'(lambda (ev) (list (car ev) 1 (third ev))) sco)) ; main functions interface ------- ;(defun sdl->score (score-data &optional time-marks) ; (when (sdl:score-has-macros? score-data) ; (setf score-data (sdl:expand-macros score-data))) ; (car (sdl:sdl->score-aux score-data time-marks))) (defun sdl->score (score-data &optional time-marks) (when (sdl:score-has-macros? score-data) (setf score-data (sdl:expand-macros score-data))) (sdl:apply-mm-to-score (car (sdl:sdl->score-aux score-data time-marks)))) (defun sdl->timelabels (score-data &optional time-marks) (when (sdl:score-has-macros? score-data) (setf score-data (sdl:expand-macros score-data))) (second (sdl:sdl->score-aux score-data time-marks))) #| ; PRUEBAS (defun sdl-repeat (n quoted-event) (let (result) (dotimes (i n (apply #'append result)) (push quoted-event result)))) (setf *score* '((TF 1.0) (INIT-INSTR "i1" xx)(INIT-INSTR "i2" yy) (INSTRUMENT "i1")(ATTR :at1 2)(ATTR :mm 60) 4 (:e4 2) 2 (:d4 4) 10 (LABEL :t1) (INSTRUMENT "i2") (ATTR :mm 60)(:f4 8) (LABEL :vuelta) (AT-LABEL :t1) (:f5 4) (AT-LABEL :vuelta) (:f6 8) )) (setf *score2* '((TF 1.0) (INIT-INSTR "i1" xx2)(INSTRUMENT "i1")(ATTR :mm 60) (AT-LABEL :t1) (:e4 4) (MAC sdl-repeat 4 (:f4 :g4)) )) ;(print (sdl:apply-mm-to-score (car (sdl:sdl->score-aux *score*)))) ;(print (car (sdl:sdl->score-aux *score*))) (setf *tlabels* (sdl->timelabels *score*)) (print (sdl->score *score*)) (print (sdl->score *score2* *tlabels*)) |# nyquist-3.05/lib/xm-test.lsp0000644000175000000620000004775711466723256015112 0ustar stevestaff;; xm-test.lsp ;; ;; ============== some test code for xm.lsp =============== ;; ;(load "xm") '(setf pat (make-heap '(a b c d e))) '(dotimes (i 10) (print (next pat))) '(print "heap test done: ") '(read) (defun about-equal (x y) (cond ((null x) (null y)) ((consp x) (and (consp y) (about-equal (car x) (car y)) (about-equal (cdr x) (cdr y)))) ((numberp x) (and (numberp y) (< (abs (- x y)) 0.000001))) (t (equal x y)))) (defun test (name &rest pairs) (format t "TEST ~A : " name) (loop (cond ((or (null pairs) (null (cdr pairs))) (format t " --PASSED--~%") (return)) ((not (about-equal (car pairs) (cadr pairs))) (format t " --FAILED-- ~A returned instead of ~A~%" (car pairs) (cadr pairs)) (break "a test failed") (return))) (setf pairs (cddr pairs)))) (setf xx (make-cycle '(x y z) :name "xx" :trace nil)) (test "test" (next xx) 'x (next xx) 'y (next xx t) '(z) (next xx t) '(x y z)) (setf aa (make-cycle '(a b) :name "aa" :trace nil)) (setf zz (make-cycle (list xx aa))) (test "test2" (next zz) 'x (next zz) 'y (next zz t) '(z) (next zz t) '(a b)) (setf zz1 (make-cycle (list xx aa) :for 1 :name "zz1")) (setf zz10 (make-cycle (list xx aa) :for 10 :name "zz10" :trace nil)) (test "test3" (next zz1 t) '(x y z) (next zz1 t) '(a b) (next zz10 t) '(x y z) (next zz10 t) '(a b)) (setf aa1 (make-cycle '(a b) :for 1 :name "aa1")) (setf zza1 (make-cycle (list xx aa1) :name "zza1")) (test "test4" (next zza1 t) '(x y z) (next zza1 t) '(a) (next zza1 t) '(x y z) (next zza1 t) '(b)) (setf zz2 (make-cycle (list xx aa) :for 1 :name "zz2")) (setf zzz (make-cycle (list zz2 'q) :name "zzz")) (test "test5" (next zzz t) '(x y z) (next zzz t) '(q) (next zzz t) '(a b) (next zzz t) '(q) (next zzz t) '(x y z) (next zzz t) '(q)) ; test using cpat as items list (setf cpat (make-cycle '(a b) :name "cpat" :trace nil)) (setf recycpat (make-cycle cpat :for 3 :name "recycpat" :trace nil)) (test "test6" (next recycpat t) '(a b a) (next recycpat t) '(a b a)) ; test length-class (setf lpat (make-length (make-cycle '(a b c)) 2)) (test "length test 1" (next lpat t) '(a b) (next lpat t) '(c a)) (setf lpat2 (make-length (make-cycle '(a b c)) (make-cycle '(2 1 0)))) (test "length test 2" (next lpat2 t) '(a b) (next lpat2 t) '(c) (next lpat2 t) '() (next lpat2 t) '(a b)) (setf pp1 (make-palindrome '(a b c) :elide (make-cycle '(:first :last t nil) :name "pp1-elide-pattern") :name "pp1")) (test "palindrome test" (next pp1 t) '(a b c c b) (next pp1 t) '(a b c b a) (next pp1 t) '(a b c b) (next pp1 t) '(a b c c b a) (next pp1 1) '(a b c c b)) (setf pp2 (make-palindrome '(a b c) :elide (make-cycle '(:first :last t)) :for 3)) (test "palindrome test 2" (next pp2 t) '(a b c) (next pp2 t) '(c b a) (next pp2 t) '(a b c) (next pp2 t) '(b a b)) (setf pp3 (make-palindrome '(a) :elide (make-cycle '(:first :last t nil)))) (test "palindrome test 3" (next pp3 t) '(a) (next pp3 t) '(a) (next pp3 t) nil (next pp3 t) '(a a)) (setf pp4 (make-palindrome '(a b c) :elide (make-cycle '(:first :last)) :for 6)) (test "palindrome test 4" (next pp4 t) '(a b c c b a) (next pp4 t) '(b c b a a b)) (setf ll1 (make-line '(a b c d))) (test "line test" (next ll1 t) '(a b c d) (next ll1 t) '(d d d d)) (setf nn1 (make-cycle (list (make-cycle (list (make-cycle '(a b) :name "ab") (make-cycle '(c) :name "c")) :name "ab-c") (make-cycle (list (make-cycle '(x y) :name "xy") (make-cycle '(u v) :name "uv")) :name "xy-uv")) :name "ab-c-xy-uv")) (test "nested test" (next nn1 t) '(a b) (next nn1 t) '(c) (next nn1 t) '(x y) (next nn1 t) '(u v) (next nn1 t) '(a b) (next nn1 t) '(c)) (setf win1 (make-window (make-cycle '(a b c)) 3 1)) (test "window test 1" (next win1 t) '(a b c) (next win1 t) '(b c a) (next win1 t) '(c a b)) (setf win2 (make-window (make-cycle '(a b c)) ; source (make-cycle '(3 1)) ; length (make-cycle '(1 1 3)))) ; skip (test "window test 2" (next win2 t) '(a b c) (next win2 t) '(b) ; skip 1 length 1 (next win2 t) '(a b c) ; skip 1 length 3 (next win2 t) '(a) ; skip 3 length 1 (next win2 t) '(b c a) ; skip 1 length 3 (next win2 t) '(c) ; skip 1 length 1 (next win2 t) '(a b c) ; skip 3 length 3 (next win2 t) '(b) ; skip 1 length 1 (next win2 t) '(a b c)) ; skip 1 length 3 (defun only-abc-n (lis n) (and (= (length lis) n) (dolist (item lis t) (cond ((not (member item '(a b c))) (return nil)))))) (defun abc2 (lis) (only-abc-n lis 2)) (defun abc3 (lis) (only-abc-n lis 3)) (setf rr1 (make-random '(a b c) :name "rr1")) (display "rr1" (next rr1 t)) (test "random 1" (abc3 (next rr1 t)) t (abc3 (next rr1 t)) t) (setf rr2 (make-random '(a b c) :for 2 :name "rr2" :trace nil)) (test "random 2" (abc2 (next rr2 t)) t (abc2 (next rr2 t)) t) ; random using weights (setf rr3 (make-random '((a :weight 1) (b :weight 10)))) (setf a-count 0 b-count 0) (setf *num-trials* 10000) ;; NORMALLY, SET THIS TO 10000 (setf rr3-all nil) (dotimes (i *num-trials*) ;(display "weight test" i) (if (eq (setf rr3-out (next rr3)) 'a) (incf a-count) (incf b-count)) (push rr3-out rr3-all)) ;(print (reverse rr3-all)) (setf rr-ratio (/ (float a-count) b-count)) (format t "test rr3 a/b should be 0.091, actual ratio is ~A~%" rr-ratio) (test "weight test" (and (< rr-ratio 0.12) (> rr-ratio 0.08)) t) ; random using :min (setf rr4 (make-random '((a :weight 1 :min 2) (b :weight 10 :min 1)))) (setf sum 0) (setf a-count 0 b-count 0) (dotimes (i *num-trials*) ;(display "min test" (next rr4)) (if (eq (next rr4) 'a) (incf a-count) (incf b-count)) ) (setf rr-ratio (/ (float a-count) b-count)) (format t "test rr4 a/b should be about 0.191, actual ratio is ~A~%" rr-ratio) (test "min test" (and (< rr-ratio 0.22) (> rr-ratio 0.16)) t) ; random using :max (setf rr5 (make-random '((a :weight 1 :min 2) (b :weight 10 :max 5)))) (setf sum 0) (setf rr5-all nil) (setf a-count 0 b-count 0) (dotimes (i *num-trials*) ;(display "max test" (next rr5)) (if (eq (setf rr5-out (next rr5)) 'a) (incf a-count) (incf b-count)) (push rr5-out rr5-all)) (setf rr5-all (reverse rr5-all)) (setf rr5-state 'a2) (setf rr5-count 0) (dolist (s rr5-all) (incf rr5-count) (cond ((and (eq rr5-state 'a1) (eq s 'a)) (setf rr5-state 'a2)) ((and (eq rr5-state 'a2) (eq s 'a))) ((and (eq rr5-state 'a2) (eq s 'b)) (setf rr5-state 'b1)) ((and (eq rr5-state 'b1) (eq s 'b)) (setf rr5-state 'b2)) ((and (eq rr5-state 'b2) (eq s 'b)) (setf rr5-state 'b3)) ((and (eq rr5-state 'b3) (eq s 'b)) (setf rr5-state 'b4)) ((and (eq rr5-state 'b4) (eq s 'b)) (setf rr5-state 'b5)) ((and (eq rr5-state 'b1) (eq s 'a)) (setf rr5-state 'a1)) ((and (eq rr5-state 'b2) (eq s 'a)) (setf rr5-state 'a1)) ((and (eq rr5-state 'b3) (eq s 'a)) (setf rr5-state 'a1)) ((and (eq rr5-state 'b4) (eq s 'a)) (setf rr5-state 'a1)) ((and (eq rr5-state 'b5) (eq s 'a)) (setf rr5-state 'a1)) (t (error "bad state")))) (setf rr-ratio (/ (float a-count) b-count)) (format t "test rr5 a/b should be 0.503613, actual ratio is ~A~%" rr-ratio) (test "max test" (and (> rr-ratio 0.4) (< rr-ratio 0.6)) t) (setf hh1 (make-heap '(a b c))) (test "heap 1" (abc3 (next hh1 t)) t (abc3 (next hh1 t)) t) (setf hh2 (make-heap '(a b c) :for 2 :name "hh2" :trace nil)) (test "heap 2" (abc2 (next hh2 t)) t (abc2 (next hh2 t)) t) (setf xx (make-markov `((a -> a (b ,(make-cycle '(1 2)))) (b -> a)) :past '(b) :produces `(a ,(make-cycle '(0)) b ,(make-cycle '(1 2 3 4) :trace nil :name "b-produces")) :is-nested t :trace nil :name "markov")) (setf xx-out nil) (dotimes (i 12) (push (next xx) xx-out)) (setf xx-out (reverse xx-out)) (print xx-out) ;; this is a special test to see if the output is plausible (defun markov-test-xx (lis) (let (a b) (setf a (car lis)) (setf lis (cdr lis)) (cond ((null lis) t) ((and (setf b (car lis)) (eq a 0) (member b '(0 1))) (markov-test-xx lis)) ((and (eq a 1) (eq b 2)) (markov-test-xx lis)) ((and (eq a 2) (eq b 3)) (markov-test-xx lis)) ((and (eq a 3) (eq b 4)) (markov-test-xx lis)) ((and (= a 4) (= b 0)) (markov-test-xx lis)) (t nil)))) (format t "TEST markov test : ~A~%" (if (markov-test-xx xx-out) "--PASSED--" (break "markov test failed"))) (setf cc (make-copier (make-cycle '(a b) :name "ab" :trace nil) :repeat 3 :name "copier" :trace nil :merge t)) (test "copier test 1" (next cc t) '(a b a b a b) (next cc t) '(a b a b a b)) (setf cc2 (make-copier (make-cycle '(a b) :name "ab" :trace nil) :repeat 3 :name "copier" :trace nil)) (test "copier test 2" (next cc2 t) '(a b) (next cc2 t) '(a b) (next cc2 t) '(a b)) (setf cc3 (make-copier (make-cycle (list (make-cycle '(a)) (make-cycle '(b)))) :repeat 3 :merge t)) (test "copier test 3" (next cc3 t) '(a a a) (next cc3 t) '(b b b) (next cc3 t) '(a a a)) (setf cc4 (make-copier (make-cycle '(a b c d) :for 1) :repeat (make-cycle '(2 -2 3 -3)) :merge t)) (test "copier test 4" (next cc4 t) '(a a) (next cc4 t) '(d d d) (next cc4 t) '(d d) (next cc4 t) '(c c c)) (setf cc5 (make-copier (make-cycle '(a b c d) :for 1) :repeat 3)) (test "compier test 5" (next cc5 t) '(a) (next cc5 t) '(a) (next cc5 t) '(a) (next cc5 t) '(b) (next cc5 t) '(b) (next cc5 t) '(b) (next cc5 t) '(c) (next cc5 t) '(c) (next cc5 t) '(c) (next cc5 t) '(d) (next cc5 t) '(d) (next cc5 t) '(d) (next cc5 t) '(a) (next cc5 t) '(a)) (setf acc1 (make-accumulate (make-cycle '(1 2 -3)))) (test "accumulate test 1" (next acc1 t) '(1 3 0) (next acc1 t) '(1 3 0)) (setf acc2 (make-accumulate (make-cycle '(1 2 -3) :for 2))) (test "accumulate test 2" (next acc2 t) '(1 3) (next acc2 t) '(0 1) (next acc2 t) '(3 0)) (setf sum1 (make-sum (make-cycle '(1 2)) (make-cycle '(3 4 5)))) (test "sum test 1" (next sum1 t) '(4 6) (next sum1 t) '(6 5) (next sum1 t) '(5 7)) (setf sum2 (make-sum (make-cycle '(1 2)) (make-cycle '(3 4 5)) :for 4)) (test "sum test 2" (next sum2 t) '(4 6 6 5) (next sum2 t) '(5 7 4 6)) (setf prod1 (make-product (make-cycle '(1 2)) (make-cycle '(3 4 5)))) (test "prod test 1" (next prod1 t) '(3 8) (next prod1 t) '(5 6) (next prod1 t) '(4 10)) (setf prod2 (make-product (make-cycle '(1 2)) (make-cycle '(3 4 5)) :for 4)) (test "prod test 2" (next prod2 t) '(3 8 5 6) (next prod2 t) '(4 10 3 8)) (setf eval1 (make-eval '(+ 1 2) :for 3)) (test "eval test 1" (next eval1 t) '(3 3 3)) #| (setf testscore '((0 0 (score-begin-end 0 10)) (0.1 1 (note :pitch 60 :vel 100)) (1 1 (note :pitch 61 :vel 91)) (1 0.5 (note :pitch 68 :vel 92)) (1.5 0.5 (note :pitch 67 :vel 93)) (2 1 (note :pitch 62 :vel 94)))) (test "basic1" (score-get-begin testscore) 0) (test "basic2" (score-get-end testscore) 10) (test "basic3" (score-set-begin testscore 1) (cons '(0 0 (score-begin-end 1 10)) (cdr testscore))) (test "basic4" (score-set-end testscore 4) (cons '(0 0 (score-begin-end 0 4)) (cdr testscore))) (test "basic5" (score-get-begin (cdr testscore)) 0.1) (test "basic6" (score-get-end (cdr testscore)) 3) (test "score-shift" (score-shift testscore 5) '((0 0 (SCORE-BEGIN-END 0 15)) (5.1 1 (NOTE :PITCH 60 :VEL 100)) (6 0.5 (NOTE :PITCH 68 :VEL 92)) (6 1 (NOTE :PITCH 61 :VEL 91)) (6.5 0.5 (NOTE :PITCH 67 :VEL 93)) (7 1 (NOTE :PITCH 62 :VEL 94)) )) (test "score-stretch1" (setf xx (score-stretch testscore 2)) (setf yy '((0 0 (SCORE-BEGIN-END 0 20)) (0.2 2 (NOTE :PITCH 60 :VEL 100)) (2 2 (NOTE :PITCH 61 :VEL 91)) (2 1 (NOTE :PITCH 68 :VEL 92)) (3 1 (NOTE :PITCH 67 :VEL 93)) (4 2 (NOTE :PITCH 62 :VEL 94)) ))) (test "score-stretch2" (score-stretch testscore 2 :dur nil) '((0 0 (SCORE-BEGIN-END 0 20)) (0.2 1 (NOTE :PITCH 60 :VEL 100)) (2 1 (NOTE :PITCH 61 :VEL 91)) (2 0.5 (NOTE :PITCH 68 :VEL 92)) (3 0.5 (NOTE :PITCH 67 :VEL 93)) (4 1 (NOTE :PITCH 62 :VEL 94)) )) (test "score-stretch3" (score-stretch testscore 2 :from-index 2 :to-index 3) '((0 0 (SCORE-BEGIN-END 0 10.5)) (0.1 1.1 (NOTE :PITCH 60 :VEL 100)) (1 1.5 (NOTE :PITCH 61 :VEL 91)) (1 1 (NOTE :PITCH 68 :VEL 92)) (2 0.5 (NOTE :PITCH 67 :VEL 93)) (2.5 1 (NOTE :PITCH 62 :VEL 94)) )) (test "score-stretch4" (score-stretch testscore 2 :from-time 1.5 :to-time 2.5) '((0 0 (SCORE-BEGIN-END 0 11)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 1.5 (NOTE :PITCH 61 :VEL 91)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1.5 1 (NOTE :PITCH 67 :VEL 93)) (2.5 1.5 (NOTE :PITCH 62 :VEL 94)) )) (test "score-transpose1" (score-transpose testscore :pitch 5) '((0 0 (score-begin-end 0 10)) (0.1 1 (note :pitch 65 :vel 100)) (1 1 (note :pitch 66 :vel 91)) (1 0.5 (note :pitch 73 :vel 92)) (1.5 0.5 (note :pitch 72 :vel 93)) (2 1 (note :pitch 67 :vel 94)))) (test "score-transpose1" (score-transpose testscore :pitch 5 :from-index 2 :to-index 3) '((0 0 (score-begin-end 0 10)) (0.1 1 (note :pitch 60 :vel 100)) (1 1 (note :pitch 66 :vel 91)) (1 0.5 (note :pitch 73 :vel 92)) (1.5 0.5 (note :pitch 67 :vel 93)) (2 1 (note :pitch 62 :vel 94)))) (test "score-scale1" (score-scale testscore :vel 0.5) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (NOTE :PITCH 60 :VEL 50)) (1 1 (NOTE :PITCH 61 :VEL 45.5)) (1 0.5 (NOTE :PITCH 68 :VEL 46)) (1.5 0.5 (NOTE :PITCH 67 :VEL 46.5)) (2 1 (NOTE :PITCH 62 :VEL 47)) )) (test "score-scale2" (score-scale testscore :vel 0.5 :from-time 1 :to-time 1.5) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 1 (NOTE :PITCH 61 :VEL 45.5)) (1 0.5 (NOTE :PITCH 68 :VEL 46)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)) )) (test "score-sustain1" (score-sustain testscore 2) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 2 (NOTE :PITCH 60 :VEL 100)) (1 2 (NOTE :PITCH 61 :VEL 91)) (1 1 (NOTE :PITCH 68 :VEL 92)) (1.5 1 (NOTE :PITCH 67 :VEL 93)) (2 2 (NOTE :PITCH 62 :VEL 94)))) (test "score-sustain2" (score-sustain testscore 2 :from-index 0 :to-index 1) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 2 (NOTE :PITCH 60 :VEL 100)) (1 1 (NOTE :PITCH 61 :VEL 91)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-voice1" (score-voice testscore '((note violin))) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (VIOLIN :PITCH 60 :VEL 100)) (1 1 (VIOLIN :PITCH 61 :VEL 91)) (1 0.5 (VIOLIN :PITCH 68 :VEL 92)) (1.5 0.5 (VIOLIN :PITCH 67 :VEL 93)) (2 1 (VIOLIN :PITCH 62 :VEL 94)))) (test "score-voice2" (score-voice testscore '((flute horn) (note violin)) :from-index 0 :to-index 10) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (VIOLIN :PITCH 60 :VEL 100)) (1 1 (VIOLIN :PITCH 61 :VEL 91)) (1 0.5 (VIOLIN :PITCH 68 :VEL 92)) (1.5 0.5 (VIOLIN :PITCH 67 :VEL 93)) (2 1 (VIOLIN :PITCH 62 :VEL 94)))) '(score-print (score-merge testscore (score-shift (score-voice testscore '((note violin))) 0.1))) (test "score-merge1" (score-merge testscore (score-shift (score-voice testscore '((note violin))) 0.1)) '((0 0 (SCORE-BEGIN-END 0 10.1)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (0.2 1 (VIOLIN :PITCH 60 :VEL 100)) (1 1 (NOTE :PITCH 61 :VEL 91)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1.1 0.5 (VIOLIN :PITCH 68 :VEL 92)) (1.1 1 (VIOLIN :PITCH 61 :VEL 91)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (1.6 0.5 (VIOLIN :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)) (2.1 1 (VIOLIN :PITCH 62 :VEL 94)) )) (test "score-merge2" (score-merge '((0 0 (SCORE-BEGIN-END 0 10)) (0 1 (NOTE :PITCH 60 :VEL 100))) '((0 0 (SCORE-BEGIN-END 0 10)) (1 1 (NOTE :PITCH 61 :VEL 91))) '((0 0 (SCORE-BEGIN-END 0 10)) (2 1 (NOTE :PITCH 62 :VEL 94)))) '((0 0 (SCORE-BEGIN-END 0 10)) (0 1 (NOTE :PITCH 60 :VEL 100)) (1 1 (NOTE :PITCH 61 :VEL 91)) (2 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-append1" (score-append testscore testscore) '((0 0 (SCORE-BEGIN-END 0 20)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 1 (NOTE :PITCH 61 :VEL 91)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)) (10.1 1 (NOTE :PITCH 60 :VEL 100)) (11 1 (NOTE :PITCH 61 :VEL 91)) (11 0.5 (NOTE :PITCH 68 :VEL 92)) (11.5 0.5 (NOTE :PITCH 67 :VEL 93)) (12 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-select1" (score-select testscore t :from-time 1 :to-time 1.5) '((0 0 (SCORE-BEGIN-END 0 10)) (1 1 (NOTE :PITCH 61 :VEL 91)) (1 0.5 (NOTE :PITCH 68 :VEL 92)))) (test "score-select2" (score-select testscore '(lambda (time dur expr) (eql (expr-get-attr expr :pitch) 61)) :from-time 1 :to-time 1.5) '((0 0 (SCORE-BEGIN-END 0 10)) (1 1 (NOTE :PITCH 61 :VEL 91)))) (test "score-select3" (score-select testscore '(lambda (time dur expr) (eql (expr-get-attr expr :pitch) 61)) :reject t) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-filter-length" (score-filter-length testscore 1.5) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 0.5 (NOTE :PITCH 68 :VEL 92)))) (test "score-repeat" (score-repeat testscore 3) '((0 0 (SCORE-BEGIN-END 0 30)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1 1 (NOTE :PITCH 61 :VEL 91)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)) (10.1 1 (NOTE :PITCH 60 :VEL 100)) (11 1 (NOTE :PITCH 61 :VEL 91)) (11 0.5 (NOTE :PITCH 68 :VEL 92)) (11.5 0.5 (NOTE :PITCH 67 :VEL 93)) (12 1 (NOTE :PITCH 62 :VEL 94)) (20.1 1 (NOTE :PITCH 60 :VEL 100)) (21 1 (NOTE :PITCH 61 :VEL 91)) (21 0.5 (NOTE :PITCH 68 :VEL 92)) (21.5 0.5 (NOTE :PITCH 67 :VEL 93)) (22 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-stretch-to-length" (score-stretch-to-length testscore 20) '((0 0 (SCORE-BEGIN-END 0 20)) (0.2 2 (NOTE :PITCH 60 :VEL 100)) (2 2 (NOTE :PITCH 61 :VEL 91)) (2 1 (NOTE :PITCH 68 :VEL 92)) (3 1 (NOTE :PITCH 67 :VEL 93)) (4 2 (NOTE :PITCH 62 :VEL 94)) )) (test "score-filter-overlap" (score-filter-overlap testscore) '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-adjacent-events1" (score-adjacent-events testscore #'(lambda (a b c) b)) testscore) (test "score-adjacent-events2" (score-adjacent-events testscore #'(lambda (a b c) (if (eql (event-get-attr b :pitch) 61) nil b))) ; remove pitches with 61 '((0 0 (SCORE-BEGIN-END 0 10)) (0.1 1 (NOTE :PITCH 60 :VEL 100)) (1 0.5 (NOTE :PITCH 68 :VEL 92)) (1.5 0.5 (NOTE :PITCH 67 :VEL 93)) (2 1 (NOTE :PITCH 62 :VEL 94)))) (test "score-indexof" (score-indexof testscore #'(lambda (time dur expr) (eql (expr-get-attr expr :pitch) 61))) 2) (test "score-last-indexof" (score-last-indexof testscore #'(lambda (time dur expr) (> (expr-get-attr expr :pitch) 65))) 4) |# nyquist-3.05/lib/midishow.lsp0000644000175000000620000000355311466723256015316 0ustar stevestaff(defun midi-show-file (score-name &optional (out-file t)) (let ((infile (open-binary score-name :direction :input))) (setf my-seq (seq-create)) (seq-read-smf my-seq infile) (close infile) (midi-show my-seq out-file))) ;iterate over midi sequence and prints events ; (defun midi-show (the-seq &optional (out-file t)) (prog (event) (seq-reset the-seq) loop (setf event (seq-get the-seq)) (if (eq (car event) seq-done-tag) (go exit)) (midi-show-event event out-file) (seq-next the-seq) (go loop) exit )) ; midi-show-event -- ascii format an event ; (defun midi-show-event (ev file) (let ((tag (seq-tag ev))) (cond ((= tag seq-note-tag) (format file "Note@~A ch:~A pitch:~A vel:~A line:~A dur:~A~%" (seq-time ev) (seq-channel ev) (seq-pitch ev) (seq-velocity ev) (seq-line ev) (seq-duration ev))) ((= tag seq-ctrl-tag) (format file "Ctrl@~A ch:~A num:~A val:~A line:~A~%" (seq-time ev) (seq-channel ev) (seq-control ev) (seq-value ev) (seq-line ev))) ((= tag seq-touch-tag) (format file "Aftr@~A ch:~A val:~A line:~A~%" (seq-time ev) (seq-channel ev) (seq-touch ev) (seq-line ev))) ((= tag seq-bend-tag) (format file "Bend@~A ch:~A val:~A line:~A~%" (seq-time ev) (seq-channel ev) (seq-bend ev) (seq-line ev))) ((= tag seq-prgm-tag) (format file "Prgm@~A ch:~A num:~A line:~A~%" (seq-time ev) (seq-channel ev) (seq-program ev) (seq-line ev))) ((= tag seq-other-tag) (format file "Othr~%")) (t (format file "????: ~A~%" ev))))) nyquist-3.05/lib/grapheq.lsp0000644000175000000620000000525611466723256015124 0ustar stevestaff; basic 4 band equalizer with cuts at 4k, 2k, 1k, and 630 hertz. ; designed as a test ;(defun 4band (s f630 f1k f2k f4k) ; (eq-band ; (eq-band ; (eq-band ; (eq-band s ; 630 f630 0.33) ; 1000 f1k 0.33) ; 2000 f2k 0.33) ; 4000 f4k 0.33)) (setf *grapheq-loaded* t) ;; inf-const -- stretch a number into an "infinite" signal ;; Nyquist does not have infinite signals, so just make it very long ;; ny:all is a large number of samples, so use it as the length in samples ;; (defun inf-const (x) (stretch-abs (/ ny:all *default-sound-srate*) (const x))) ; n-band graphic eq with variable range. ; sig - input signal ; gains - vector of gain changes in dB ; lowf - lower eq band limit ; highf - upper eq band limit (defun nband-range (sig gains lowf highf) (let ((bandsep ;; bandwidth of each channel in steps (/ (- (hz-to-step highf) (hz-to-step lowf)) (length gains))) lowstep ;; low frequency in steps (newsnd sig) (chans (length gains))) (setf lowstep (+ (hz-to-step lowf) (* 0.5 bandsep))) (cond ((< bandsep 0) (error "band width must be greater than 0")) (t (dotimes (i chans newsnd) ;; gains[i] can be either a number or a signal (cond ((numberp (aref gains i)) (cond ((not (zerop (aref gains i))) (setf newsnd ;; note: gain in dB (eq-band newsnd (step-to-hz (+ (* i bandsep) lowstep)) (aref gains i) (/ bandsep 12)))))) (t (setf newsnd (eq-band newsnd (inf-const (step-to-hz (+ (* i bandsep) lowstep))) (aref gains i) (inf-const (/ bandsep 12))))))))))) ; nband eq without variable range ; wraps around nband-vl with standard limits (defun nband (sig gains) (nband-range sig gains 20 20000) ) ; simple test demo ;(play (nband-vl (noise 1) '(-6 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0) 20 20000)) ; variable gain demo ;(play (nband-vl (noise 1) '(0 0 0 0 0 0 (pwl 0 0 .9 10 1) 0 0 0 0 0 0 0 0 0 0 (pwl 0 -10 .9 10 1) (pwl 0 -10 .9 10 1) (pwl 0 -10 .9 10 1) (pwl 0 -10 .9 10 1) 0 0 0 0) 20 20000)) ; test of adjacent band cuts ;(play (nband-vl (noise 1) '(0 0 0 0 0 0 0 0 0 0 6 6 6 0 0 0 -6 -6 0 0 0 0) 20 20000)) nyquist-3.05/lib/distributions.lsp0000644000175000000620000001211511466723256016367 0ustar stevestaff;; Andreas Pfenning, 26 Apr 05 ;; modified by Roger B. Dannenberg, 25 Jun 05 ;; Probability distribution functions and demo #| This is a library of various probability distribution generators. The functions output values based on the probability distributions and the input parameters that scale the distributions. Plots of the various distributions are shown in the documentation. The user has option of adding bounds to the output values, especially in the cases where high or low outliers are expected. When a distribution returns a value outside of the given bounds, the value is rejected and another value is generated. Both discrete (whole number) and continuous distributions are available. For continous distributions, the probability of outputing a value between any two points on the x axis is equal to the area under the curve between those two points. Essentially, the higher the curve is for a an area of the x axis, the more likely it is that the generator will output a value in that area. Discrete generators output values based on how high the "bar" is at that location. The documentation shows the behavior generated by 100 trials of discrete probability distributioin generators. |# ;;Library of Continuous Probability Distribution Generators (defun linear-dist (g) (* g (- 1.0 (sqrt (rrandom))))) (defun exponential-dist (delta &optional high) (cond ((and high (<= high 0)) (error "exponential-dist: high value must be positive"))) (loop (let ((expv (* (/ -1.0 delta) (log (rrandom))))) (cond ((or (null high) (<= expv high)) (return expv)))))) (defun gamma-dist (nu &optional high) (cond ((and high (<= high 0) (error "gamma-dist: high value must be positive")))) (loop (let* ((summ 1) (summ2 (dotimes (count nu summ) (setf summ (* summ (rrandom))))) (gamv (* -1.0 (log summ2)))) (cond ((or (null high) (<= gamv high)) (return gamv)))))) (defun bilateral-exponential-dist (xmu tau &optional low high) (cond ((and high low (<= high low)) (error "bilateral-exponential-dist: high must be greater than low"))) (loop (let* ((u (* (rrandom) 2.0)) (bev (if (> u 1.0) (+ (* -1.0 tau (log (- u 1.0))) xmu) (+ (* tau (log u)) xmu)))) (cond ((and (or (null high) (< bev high)) (or (null low) (> bev low))) (return bev)))))) (defun cauchy-dist (tau &optional low high) (cond ((and high low (<= high low)) (error "cauchy-dist: high must be greater than low"))) (loop (let* ((u (* PI (rrandom))) (cauv (* tau (/ (sin u) (cos u))))) (cond ((and (or (null high) (< cauv high)) (or (null low) (> cauv low))) (return cauv)))))) (defun hyperbolic-cosine-dist (&optional low high) (cond ((and high low (<= high low)) (error "hyperbolic-cosine-dist: high must be greater than low"))) (loop (let* ((hcv (log (tan (/ (* PI (rrandom)) 2.0))))) (cond ((and (or (null high) (< hcv high)) (or (null low) (> hcv low))) (return hcv)))))) (defun logistic-dist (alpha beta &optional low high) (cond ((and high low (<= high low)) (error "logistic-dist: high must be greater than low"))) (loop (let (rand lgv) (setf rand (rrandom)) (cond ((zerop rand)) ; try again -- do not use zero (t (setf rand (- (/ rand) 1.0)) (cond ((zerop rand)) ; try again -- do not use zero (t (setf lgv (/ (- (+ beta (log rand))) alpha)) (cond ((and (or (null high) (< lgv high)) (or (null low) (> lgv low))) (return lgv)))))))))) (defun gaussian-dist (xmu sigma &optional low high) (cond ((and high low (<= high low)) (error "gauss-dist: high must be greater than low"))) (loop (let* ((s 0.0) (s2 (dotimes (i 12 s) (setq s (+ s (rrandom))))) (gsv (+ (* sigma (- s2 6.0)) xmu))) (cond ((and (or (null high) (< gsv high)) (or (null low) (> gsv low))) (return gsv)))))) (defun beta-help (ea eb) (loop (let ((y1 (power (rrandom) ea)) (y2 (power (rrandom) eb))) (if (<= (+ y1 y2) 1.0) (return (/ y1 (+ y1 y2))))))) (defun beta-dist (a b) (let ((ea (/ 1.0 a)) (eb (/ 1.0 b))) (beta-help ea eb))) ;;Library of Discrete Probability Distribution Generators (defun bernoulli-dist (px1 &optional (x1 1) (x2 0)) (let ((u (rrandom))) (if (< u px1) x1 x2))) (defun binomial-dist (n p) (let ((suc 0)) (dotimes (count n suc) (setf suc (+ suc (bernoulli-dist p)))))) (defun geometric-dist (p &optional (count 0)) (loop (cond ((= (bernoulli-dist p) 1) (return count))) (setf count (1+ count)))) (defun poisson-dist (delta) (let ((x 0) (t 0.0)) (loop (setf t (- t (/ (log (rrandom)) delta))) (cond ((> t 1) (return x))) (setf x (1+ x))))) nyquist-3.05/lib/plugin-test.lsp0000644000175000000620000001361111466723256015742 0ustar stevestaff;; plugin-test -- simulate Audacity interface to Nyquist plugins ;; ;; Roger B. Dannenberg, Dec 2005 ;; ;; This program runs an Audacity plugin from within Nyquist, where ;; more debugging tools are available. ;; There are two functions: ;; ;; (PLUGIN-TEST "plugin-file-name") -- full emulation of Audacity, ;; prompts for parameters and audio file. The ".ny" extension ;; is optional. ;; ;; (PLUGIN-AUTO-TEST "plugin-file-name" bindings ["audio-file-name"]) -- load ;; and run the plugin. Bindings is a list of bindings, e.g. ;; ((amp 1.0) (n 3)), setting the controls of the plugin. ;; This version does not prompt for values. ;; ;; ADD-EXTENSION -- if filename does not end in ext, append ext to ;; filename ext should include the ".", e.g. ".ny" ;; (defun add-extension (filename ext) (cond ((equal (subseq filename (- (length filename) (length ext))) ext) filename) (t (strcat filename ext)))) (defun string-to-number (str) (read (make-string-input-stream str))) (defun parse-control-spec (line) (let ((stream (make-string-input-stream (subseq line 8)))) (list (read stream) (read stream) (read stream) (read stream) (read stream) (read stream) (read stream)))) (defun describe-sound (snd) (let ((typ (type-of snd)) sr) (cond ((eq typ 'sound) (setf typ "single-channel sound") (setf sr (snd-srate snd))) ((and (eq typ 'VECTOR) (eq (type-of (aref snd 0)) 'SOUND)) (setf typ "multi-channel sound") (setf sr (snd-srate (aref snd 0))))) (cond ((stringp typ) (format t "=== Plugin result is a ~A at sample rate ~A ===~%" typ sr) snd) (t (format t "=== Plugin result is of type ~A ===~%" typ) (pprint snd) ;; print result of plugin if it's not a sound (s-rest 0.1))))) ;; return silence to make play happy (defun read-file-expressions (filename) (let (file expr exprs) (setf file (open filename)) (while (setf expr (read file)) (push expr exprs)) (reverse exprs))) ;; AUDIO-FILE-TO-BINDINGS -- convert audio filename to pair of bindings: ;; ((s (s-read )) (len )) ;; return nil if filename is invalid ;; (defun audio-file-to-bindings (audio-file) (let (source) (if (> (length audio-file) 0) (setf source (s-read audio-file))) (cond (source (setf len (* (nth 5 *rslt*) (nth 6 *rslt*))) (list `(len ,len) `(s (s-read ,audio-file)))) (t nil)))) (defun plugin-test (filename) (let (file controls bindings description plug-type value audio-file source exprs len) ;; first, check for filename extension (setf filename (add-extension filename ".ny")) ;; see if we can open the file (setf file (open filename)) (if (null file) (error (strcat "Could not open " filename))) ;; parse the file ;sym init step (do ((line (read-line file) (read-line file))) ((null line)) ;(display "pass 1" line) (cond ((eql 0 (string-search ";control" line)) (push (parse-control-spec line) controls)) ((or (eql 0 (string-search ";nyquist" line)) (eql 0 (string-search ";version" line)) (eql 0 (string-search ";name" line)) (eql 0 (string-search ";action" line)) (eql 0 (string-search ";info" line))) (push line description)) ((eql 0 (string-search ";type" line)) (cond ((string-search "process" line) (setf plug-type 'process)) ((string-search "generate") (setf plug-type 'generate)) ((string-search "analyze") (setf plug-type 'analyze)) (t (error (strcat "unexpected specification: " line))))))) (close file) ;; print description (dolist (line description) (format t "~A~%" line)) ;; get control values and set them as global variables (setf controls (reverse controls)) (read-line) ;; read the newline after the expression that called this fn ;; (otherwise, we'll read in unintended new-line for first control) (dolist (control controls) ;; control is (symbol description type units default minimum maximum) (let ((sym (car control)) (desc (cadr control)) (ctrl-type (caddr control)) (units (cadddr control)) (default (nth 4 control)) (minimum (nth 5 control)) (maximum (nth 6 control))) (loop (format t "~A (~A) [~A]: " desc units default) (setf value (read-line)) (if (equal value "") (setf value default) (setf value (string-to-number value))) (if (equal ctrl-type 'int) (setf value (round value)) (setf value (float value))) (if (and (<= minimum value) (<= value maximum)) (return)) ; break from loop (format t "Try again, value must be between ~A and ~A.~%" minimum maximum)) (push (list sym value) bindings))) (setf bindings (reverse bindings)) ;; determine the sound file name to process, if any, and open it (cond ((member plug-type '(process analyze)) (loop (format t "Audio input file: ") (setf audio-file (read-line)) (setf source (audio-file-to-bindings audio-file)) (if source (return)) (format t "Could not open ~A. Try again.~%" audio-file)) (setf bindings (append source bindings)))) ;; now we're ready to read the plug-in as expressions (setf exprs (read-file-expressions filename)) ;; turn expression list into a let and evaluate (run-plugin exprs bindings))) (defun plugin-auto-test (filename bindings &optional audio-file) (setf filename (add-extension filename ".ny")) (let ((exprs (read-file-expressions filename)) source) (cond (audio-file (setf source (audio-file-to-bindings audio-file)))) (cond (source (setf bindings (append source bindings))) (t (error (strcat "audio file not valid: " audio-file)))) (run-plugin exprs bindings))) (defun run-plugin (exprs bindings) (setf exprs `(let (,@bindings) ,@exprs)) (pprint exprs) (play (describe-sound (eval exprs)))) nyquist-3.05/lib/spectrum.lsp0000644000175000000620000001000711466723256015325 0ustar stevestaff;; spectrum.lsp -- operations on spectral frames (defun raised-cosine () (scale 0.5 (sum (const 1) (lfo (/ 1.0 (get-duration 1)) 1 *sine-table* 270)))) (defun fft-window (frame-size) (control-srate-abs frame-size (raised-cosine))) ;; fft-class -- an iterator converting sound to sequence of frames ;; (setf fft-class (send class :new '(sound length skip window))) (send fft-class :answer :next '() '( (snd-fft sound length skip window))) (send fft-class :answer :isnew '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp) (setf window (fft-window len)) )) (defun make-fft-iterator (sound length skip) (send fft-class :new (snd-copy sound) length skip)) ;; conversions -- assumes frame length is even (defun spectrum-to-amplitude (frame) (let* ((n (length frame)) (half-n (/ n 2)) (amps (make-array (1+ half-n)))) (setf (aref amps 0) (abs (aref frame 0))) (dotimes (i (1- half-n)) (let* ((i2 (+ i i)) (c (aref frame (1+ i2))) (s (aref frame (+ 2 i2)))) (setf (aref amps (1+ i)) (sqrt (+ (* c c) (* s s)))))) (setf (aref amps half-n) (abs (aref frame (1- n)))) amps)) (defun spectrum-by-amplitude (frame amps) (let* ((n (length frame)) (half-n (/ n 2))) (setf (aref frame 0) (* (aref frame 0) (aref amps 0))) (dotimes (i (1- half-n)) (let* ((ip1 (1+ i)) (i2 (+ i i)) (i2p1 (1+ i2)) (i2p2 (1+ i2p1))) (setf (aref frame i2p1) (* (aref frame i2p1) (aref amps ip1))) (setf (aref frame i2p2) (* (aref frame i2p2) (aref amps ip1))))) (setf (aref frame (1- n)) (* (aref frame (1- n)) (aref amps half-n))))) (defun spectrum-rms (frame) (let* ((n (length frame)) (half-n (/ n 2)) (sum (* (aref frame 0) (aref frame 0)))) (dotimes (i (1- half-n)) (let* ((i2 (+ i i)) (c (aref frame (1+ i2))) (s (aref frame (+ 2 i2)))) (setf sum (+ sum (* c c) (* s s))))) (setf sum (+ sum (* (aref frame (1- n)) (aref frame (1- n))))) (sqrt sum))) (defun amplitude-rms (frame) (let* ((n (length frame)) (sum 0)) (dotimes (i n) (setf sum (+ sum (* (aref frame i) (aref frame i))))) (sqrt sum))) ;; SMOOTH-AMPLITUDE -- simple local averaging to smooth out ;; an amplitude spectrum. This might be useful to broaden ;; spectral peaks from partials to better represent vocal ;; formants. It would be nice to have a "width" parameter, ;; but instead, the filter is fixed at (0.25, .5, 0.25) ;; (defun smooth-amplitude (frame) (let* ((len (length frame)) (lenm1 (1- len)) (lenm2 (1- lenm1)) (rslt (make-array (length frame)))) (setf (aref rslt 0) (+ (* 0.75 (aref frame 0)) (* 0.25 (aref frame 1)))) (dotimes (i lenm2) (let* ((ip1 (1+ i)) (ip2 (1+ ip1))) (setf (aref rslt ip1) (+ (* 0.25 (aref frame i)) (* 0.5 (aref frame ip1)) (* 0.25 (aref frame ip2)))))) (setf (aref rslt lenm1) (+ (* 0.25 (aref frame lenm2)) (* 0.75 (aref frame lenm1)))) rslt)) ;; ARRAY-SCALE -- multiply a spectral frame or amplitude frame ;; by a scale factor ;; (defun array-scale (frame x) (dotimes (i (length frame)) (setf (aref frame i) (* (aref frame i) x)))) (defun array-copy (frame) (let* ((len (length frame)) (copy (make-array len))) (dotimes (i len) (setf (aref copy i) (aref frame i))) copy)) (defun amplitude-plot (frame) (s-plot (snd-from-array 0 (/ (float (1- (length frame))) *default-sound-srate*) frame))) (defun spectrum-plot (frame) (amplitude-plot (spectrum-to-amplitude frame))) (defun spectrum-ifft (iterator len skip) (snd-ifft (local-to-global 0.0) *sound-srate* iterator skip (fft-window len))) nyquist-3.05/lib/lpc.lsp0000644000175000000620000001315510144436365014242 0ustar stevestaff;--------------------------------------------------------------------- ; LPANAL. Performs LPC analysis ; ; snd sound for analysis ; an-dur duration of analysis (= duration of sound) ; skiptime step frame to frame ; npoles number of poles ; ; RESULT: analysis data in list format. ; Every element of the list is a list of the form ; ; (RMS1 RMS2 ERR FILTER-COEFS) ; ; RMS1 Energy (not rms value) of input signal ; RMS2 Energy (not rms value) of residual signal ; ERR = sqrt(RMS2/RMS1) If it is small then VOICED sound, ; else UNVOICED ; FILTER-COEFS Array of filter coefs. ; ; ; The z transform of filter is H(z) = 1/A(z) ; ; where A(z) is a polynome of the form: ; ; ; A(z) = 1 + a1 z + a2 z^2 + a3 z^3 + ... + aP z^P ; ; FILTER-COEFS is the array ; ; #(-aP -aP-1 -aP-2 ... a3 a2 a1) ; ; (this format is suited for the filter ALLPOLES) ; (setfn lpc-frame-rms1 car) (setfn lpc-frame-rms2 cadr) (setfn lpc-frame-err caddr) (setfn lpc-frame-filter-coefs cadddr) ;; LPANAL-CLASS -- does lpc analysis. Frames are returned ;; from an iterator object (setf lpanal-class (send class :new '(sound framesize skipsize npoles))) (send lpanal-class :answer :isnew '(snd framedur skiptime np) '( (let ((sr (snd-srate snd))) (setf sound snd) (setf framesize (round (* sr framedur))) (setf skipsize (round (* sr skiptime))) (setf npoles np)))) (send lpanal-class :answer :next '() '( (let ((samps (snd-fetch-array sound framesize skipsize))) (cond ((null samps) nil) (t (snd-lpanal samps npoles)))))) (defun make-lpanal-iterator (sound framedur skiptime npoles) (send lpanal-class :new (snd-copy sound) framedur skiptime npoles)) ;; LPC-FILE-CLASS -- iterator returns frames from file ;; (setf lpc-file-class (send class :new '(file))) (send lpc-file-class :answer :isnew '(filename) '( (setf file (open filename)))) (send lpc-file-class :answer :next '() '( (read file))) (defun make-lpc-file-iterator (filename) (send lpc-file-class :new filename)) ;; SAVE-LPC-FILE -- create a file from an iterator. This file can ;; be turned back into an iterator using make-lpc-file-iterator. ;; (defun save-lpc-file (lpc-iterator filename) (let ((fp (open filename :direction :output)) (frame t)) (while frame (setf frame (send lpc-iterator :next)) (if frame (format fp "~A~%" frame))) (close fp))) ;; SHOW-LPC-DATA. Show values of LPC analysis frames from interator. ;; (defun show-lpc-data (lpc-iterator iniframe endframe &optional (poles? NIL)) (dotimes (i iniframe) (send lpc-iterator :next)) (dotimes (i (- endframe iniframe)) (let ((frame (send lpc-iterator :next))) (cond ((null frame) (return)) (poles? (format t "FRM ~A : ~A\n" (+ i iniframe) frame)) (t (format t "FRM ~A : ~A\n" (+ i iniframe) (reverse (cdr (reverse frame))))))))) ;---------------------------------------------------------------------- ; LPC-FREQ. Show frequency response of ALLPOLES filter. ; NEEDS MATLAB or OCTAVE ; ; ; HELPER FUNS : GET-FILTER-COEFS from a LPC analysis data ; lpc-data: data generated by LPCANAL ; numframe: index of frame data ; ; LPC-COEFS-TO-MATLAB : transforms LPC coefs format to Matlab format ; ; LPC-FREQ. ; ; varname : the name of variable that holds coef array in MATLAB ; lpc-data : as above ; numframe : as above ; ; THIS CODE TO GET FREQUENCY ASSUMES AN ARRAY OF LPC FRAMES AND REQUIRES ; MATLAB OR OCTAVE. I HAVE NOT ADAPTED THIS TO USE THE STREAM OF FRAMES ; APPROACH. -RBD ; ;(defun get-filter-coefs (lpc-data numframe) ; (nth 3 (aref lpc-data numframe))) ; ; ;(defun lpc-coefs-to-matlab (lpc-data numframe) ; (let* ((lpc-coefs (get-filter-coefs lpc-data numframe)) ; (lencoefs (length lpc-coefs)) ; (result (make-array (1+ lencoefs)))) ; (setf (aref result 0) 1.0) ; (dotimes (i lencoefs) ; (setf (aref result (1+ i)) ; (- (aref lpc-coefs (- lencoefs i 1))))) ; result)) ; ; ;(defun lpc-freq (varname lpc-data numframe) ; (octave (list (list (lpc-coefs-to-matlab lpc-data numframe) varname 'ARR)))) ;---------------------------------------------------------------------------- ; ALLPOLES ; ; THIS VERSION IS FOR ARRAY OF FRAMES ; ;(defun get-allpoles-gain (lpc-data numframe) ; (nth 2 (aref lpc-data numframe))) ; se toma ERR para que la amplitud de ; ; la salida se aproxime a 1 ; ;(defun allpoles-from-lpc (snd lpc-data numframe) ; (snd-allpoles snd (get-filter-coefs lpc-data numframe) (get-allpoles-gain lpc-data numframe))) ; ALLPOLES USES A SINGLE FRAME TO CREATE A FILTER ; ; We introduce two functions: ; NTH-FRAME runs the interator to get the nth frame; ; ALLPOLES-FROM-LPC filters a sound given a frame from an iterator ;; NTH-FRAME - get the nth frame from lpc iterator, ;; first frame is numbered zero (defun nth-frame (lpc-iterator numframe) (dotimes (i numframe) (send lpc-iterator :next)) (send lpc-iterator :next)) ;; ALLPOLES-FROM-LPC -- filter a sound using an LPC frame ;; (defun allpoles-from-lpc (snd lpc-frame) (snd-allpoles snd (lpc-frame-filter-coefs lpc-frame) (lpc-frame-err lpc-frame))) ;; use ERR for gain ;------------------------------------------------------------------------------- ; LPRESON (setfn lpreson snd-lpreson) nyquist-3.05/lib/gran.lsp0000644000175000000620000001266711466723256014430 0ustar stevestaff;; GRAN.LSP -- granular synthesis example by Roger B. Dannenberg ;; ;; This is not the ultimate granular synthesis package, so do not ;; consider this to be a stable, permanent addition to the Nyquist ;; library. You can use it as is, or use it as the basis for your ;; own custom variations. ;; ================================================================== ;; Grains are windowed with "raised cosine pulse functions." These ;; are smooth envelopes based on the function (1-cos(2*pi*t))/2. ;; To speed up computation, I save three functions with 20, 200, and ;; 2205 samples. The function one-minus-cosine selects an appropriate ;; envelope based on the duration (stretch) currently in effect. (defun cos-pulse () (scale 0.5 (sum 1 (lfo 1 1 *sine-table* 270.0)))) ;; this will be a 2205 point smooth 1-cos(x) curve: ;; (setf *cos-pulse-2205* (cos-pulse)) ;; this will be a 200 point smooth 1-cos(x) curve: ;; (setf *cos-pulse-200* (control-srate-abs 200 (cos-pulse))) (setf *cos-pulse-20* (control-srate-abs 20 (cos-pulse))) ;; one-minus-cosine -- an envelope based on (1-cos(2pi*t))/2 ;; (defun one-minus-cosine () (let ((max-samps (* *sound-srate* (get-duration 1)))) (cond ((> max-samps 2205) (sound *cos-pulse-2205*)) ((> max-samps 200) (sound *cos-pulse-200*)) (t (sound *cos-pulse-20*))))) ' (let ((duration (get-duration 1))) (scale 0.5 (sum 1 (lfo (/ duration) 1 *sine-table* 270.0)))) ;; ================================================================== ;; The granulation is applied to a sound file rather than a sound. ;; This gives us the ability to access the sound file at any point ;; in time, although is is a bit less efficient because we have to ;; reopen the file hundreds or thousands of times. (On the other hand ;; the file data is likely to be cached by the OS, so it goes pretty ;; fast.) ;; Here, we define some functions for getting file information. (defun sf-srate (filename) (s-read filename) ; s-read returns list of info in *rslt* (s-read-srate *rslt*)) (defun sf-dur (filename) (s-read filename) (s-read-dur *rslt*)) ;; ============================================================ ;; Define some other handy support functions ;; real-random -- pick a random real from a range ;; (defun real-random (from to) (cond ((= from to) from) (t (+ from (* (random 10000) 0.0001 (- to from)))))) ;; sound2 -- like SOUND but operates on stereo signal ;; (defun sound2 (a) (cond ((eq (type-of a) 'array) (vector (sound (aref a 0)) (sound (aref a 1)))) (t (sound a)))) (defun monoize (v) (cond ((eq (type-of v) 'array) (aref v 0)) (t v))) ;; ================================================================== ;; sf-granulate -- granular synthesis applied to file ;; ;; filename -- name of the file ;; grain-dur -- the duration of a grain ;; grain-dev -- grain dur is actually grain-dur + random(0, grain-dev) ;; ioi -- the basic inter-onset-interval for grains ;; ioi-dev -- ioi is actually: ioi + random(0, ioi-dev) ;; pitch-dev -- grains are resampled at rate between 1 and pitch-dev ;; file-start -- when to start reading the file (an offset from start) ;; file-end -- when to stop reading the file (an offset from end) ;; ;; NOTES: the number of grains is based on an average grain spacing ;; of (ioi + ioi-dev/2). The step through the file is computed ;; by dividing the duration (file-start - file-end) by number of ;; grains. ;; (defun sf-granulate (filename grain-dur grain-dev ioi ioi-dev pitch-dev &optional (file-start 0) (file-end 0)) (let (orig n step-size (avg-ioi (+ ioi (/ ioi-dev 2.0))) (file-dur (sf-dur filename)) (dur (get-duration 1))) (setf n (truncate (/ dur avg-ioi))) (cond ((< file-dur file-start) (error "sf-granulate: file-start is after end of file!")) ((< file-dur file-end) (error "sf-granulate: file-end (offset) exceeds file duration!")) ((< file-dur (+ file-start file-end)) (error "sf-granulate: file-start + file-end > file duration!"))) (setf file-dur (- file-dur file-start file-end)) (setf step-size (/ file-dur n)) ;(display "sf-granulate" step-size file-dur n) (stretch-abs 1.0 (set-logical-stop (seqrep (i n) (let* ((actual-grain-dur (real-random grain-dur (+ grain-dur grain-dev))) (env (stretch actual-grain-dur (one-minus-cosine))) (pitch-ratio (real-random 1.0 pitch-dev))) ;(display "gran" (local-to-global 0) i pitch-ratio) (set-logical-stop (force-srate *sound-srate* (stretch pitch-ratio (sound2 (mult (cue env) (s-read filename :time-offset (+ file-start (* step-size i)) :dur actual-grain-dur))))) (real-random ioi (+ ioi ioi-dev))))) dur)))) ;;============================================================================ ;; Here is a sample application of sf-granulate. ;; Notice that I am using simrep to mix four copies of sf-granulate output. ;; Since there are random timings involved, the layers are not identical. ;; (setf *granfile* "../demos/demo-snd.aiff") (defun gran-test () (play (stretch 4 (simrep (i 4) (sf-granulate *granfile* 0.04 0.0 0.02 0.001 2.0 0 0))))) (print "Set *granfile* and then call gran-test for an example") nyquist-3.05/lib/dist-test.lsp0000644000175000000620000001650511466723256015414 0ustar stevestaff;; Examples of how to use distributions.lsp ;;1. Altered granulate methods based on distribution (load "gran") ;;The deviatons in pitch and grainlength of the standard granular synthesis ;;functions in are based on the uniform random distribution. With simple ;;modifications, these can be made to take in a distribution generator ;;function as a variable. ;; filename -- name of the file ;; grain-dur -- the duration of a grain ;; grain-dev -- grain dur is actually grain-dur + random(0, grain-dev) ;; ioi -- the basic inter-onset-interval for grains ;; ioi-dev -- ioi is actually: ioi + random(0, ioi-dev) ;; pitch-dist -- the distribution of the alteration in pitch to the grains ;; the distribution values should be > 1. ;; file-start -- when to start reading the file (an offset from start) ;; file-end -- when to stop reading the file (an offset from end) (defun pitch-dist-granulate (filename grain-dur grain-dev ioi ioi-dev pitch-dist &optional (file-start 0) (file-end 0)) (let (orig n env actual-grain-dur step-size (avg-ioi (+ ioi (/ ioi-dev 2.0))) (file-dur (sf-dur filename)) (dur (get-duration 1))) (setf n (truncate (/ dur avg-ioi))) (cond ((< file-dur file-start) (error "sf-granulate: file-start is after end of file!")) ((< file-dur file-end) (error "sf-granulate: file-end (offset) exceeds file duration!")) ((< file-dur (+ file-start file-end)) (error "sf-granulate: file-start + file-end > file duration!"))) (setf file-dur (- file-dur file-start file-end)) (setf step-size (/ file-dur n)) (stretch-abs 1.0 (let () (seqrep (i n) (let () (setf actual-grain-dur (real-random grain-dur (+ grain-dur grain-dev))) (setf env (stretch actual-grain-dur (one-minus-cosine))) (force-srate *sound-srate* (stretch (funcall pitch-dist) (sound2 (set-logical-stop (mult (cue env) (s-read filename :time-offset (+ file-start (* step-size i)) :dur actual-grain-dur)) (real-random ioi (+ ioi ioi-dev)))))))))))) ;; filename -- name of the file ;; dist -- the distribution function that the grain sizes should follow ;; ioi -- the basic inter-onset-interval for grains ;; ioi-dev -- ioi is actually: ioi + random(0, ioi-dev) ;; pitch-dev -- grains are resampled at rate between 1 and pitch-dev ;; file-start -- when to start reading the file (an offset from start) ;; file-end -- when to stop reading the file (an offset from end) (defun len-dist-granulate (filename dist ioi ioi-dev pitch-dev &optional (file-start 0) (file-end 0)) (let (orig n env actual-grain-dur step-size (avg-ioi (+ ioi (/ ioi-dev 2.0))) (file-dur (sf-dur filename)) (dur (get-duration 1))) (setf n (truncate (/ dur avg-ioi))) (cond ((< file-dur file-start) (error "sf-granulate: file-start is after end of file!")) ((< file-dur file-end) (error "sf-granulate: file-end (offset) exceeds file duration!")) ((< file-dur (+ file-start file-end)) (error "sf-granulate: file-start + file-end > file duration!"))) (setf file-dur (- file-dur file-start file-end)) (setf step-size (/ file-dur n)) (stretch-abs 1.0 (let () (seqrep (i n) (let () (setf actual-grain-dur (funcall dist)) (setf env (stretch actual-grain-dur (one-minus-cosine))) (force-srate *sound-srate* (stretch (real-random 1.0 pitch-dev) (sound2 (set-logical-stop (mult (cue env) (s-read filename :time-offset (+ file-start (* step-size i)) :dur actual-grain-dur)) (real-random ioi (+ ioi ioi-dev)))))))))))) ;; How to use these granular-synthesis functions ;; First, make a continuation out of the distribution functions (defun make-gauss (xmu sigma low high) (lambda () (gauss-dist xmu sigma low high))) ;; Second, Plug in that continuation as a variable to the granular-synthesis function (defun try-len-dist () (play (stretch 4 (simrep (i 2) (len-dist-granulate "samples.wav" (make-gauss 0.0 1.0 0.1 .5) 0.02 0.001 2.0 0 0))))) ;; Here's an example of changing the pitch distribution (defun make-gamma (nu high) (lambda () (gamma-dist nu high))) (defun try-pitch-dist () (play (stretch 4 (simrep (i 4) (pitch-dist-granulate "samples.wav" 0.04 0.0 0.02 0.001 (make-gamma 2.0 5.0) 0 0))))) ;; 2. Simple methods of usuing probability distribution generators ;; In general, a probability distribution generator can substitue for a ;; uniform ranom generator which is (real-random min max) ;; Use a continuous distribution generator to alter the time between sounds (defun try-exponential () (play (seqrep (i 20) (pluck c4 (* 0.5 (exponential-dist .25 2.0)))))) ;; Use a discrete generator to alter the pitch by a whole number. (defun try-binomial () (play (seqrep (i 20) (pluck (+ (binomial-dist 6 .5) c4) 0.1)))) (defun dist-hist (fn n nbins low high &rest params) (let ((bins (make-array nbins)) (step (/ (- high low) (float (- nbins 2))))) (dotimes (i nbins) (setf (aref bins i) 0.0)) (dotimes (i n) (let ((x (apply fn params)) i) (cond ((< x low) (incf (aref bins 0))) ((>= x high) (incf (aref bins (1- nbins)))) (t (setf i (truncate (1+ (/ (- x low) step)))) (if (or (< i 1) (>= i (1- nbins))) (error "unexpected bin number")) (incf (aref bins i)))))) bins)) ; test LINEAR-DIST ;(setf hist (dist-hist #'linear-dist 10000 100 0 4 4)) ;(s-plot (scale 0.001 (snd-from-array 0.0 100 hist))) ; test EXPONENTIAL-DIST ; (setf hist (dist-hist #'exponential-dist 10000 100 0 3 1 3)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test GAMMA-DIST ;(setf hist (dist-hist #'gamma-dist 10000 100 0 10 3 4)) ;(s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test BILATERAL-EXPONENTIAL-DIST ; (setf hist (dist-hist #'bilateral-exponential-dist 10000 100 0 10 4.0 1.1 0 10)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test CAUCHY-DIST ; (setf hist (dist-hist #'cauchy-dist 100000 100 -10 10 1.0 -9 6)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test HYPERBOLIC-COSINE-DIST ; (setf hist (dist-hist #'hyperbolic-cosine-dist 1000000 500 -10 10)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test LOGISTIC-DIST ; (setf hist (dist-hist #'logistic-dist 10000 100 -10 10 0.5 2 -5 1)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test GAUSSIAN-DIST ; (setf hist (dist-hist #'gaussian-dist 100000 100 0 10 5 1 2 8)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test BETA-DIST ; (setf hist (dist-hist #'beta-dist 100000 100 -0.1 1.1 0.5 0.25)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test BERNOULLI-DIST ; (setf hist (dist-hist #'bernoulli-dist 10000 100 -0.1 1.1 0.75 0.1 0.9)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test GEOMETRIC-DIST ; (setf hist (dist-hist #'geometric-dist 100000 100 0 10 0.7)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) ; test POISSON-DIST ; (setf hist (dist-hist #'poisson-dist 10000 100 0 20 4)) ; (s-plot (scale 1.0 (snd-from-array 0.0 100 hist))) nyquist-3.05/lib/spatial.lsp0000644000175000000620000003425511466723256015133 0ustar stevestaff; SPATIAL.LSP ; created by Adam Hartman and Roger B. Dannenberg ; 2005 ; stereo manipulation and spatialization functions ; EMPHIGH -- use four equalizer bands to emphasize ; the higher frequencies in an input sound ; (defun emphigh (base) (eq-band (eq-band (eq-band (eq-band base 31 -3 1) 62 -3 1) 8000 3 1) 16000 3 1)) ; EMPLOW -- use four equalizer bands to emphasize ; the lower frequencies in an input sound ; (defun emplow (base) (eq-band (eq-band (eq-band (eq-band base 31 3 1) 62 3 1) 8000 -3 1) 16000 -3 1)) ; LEFTIN -- apply low frequency emphasis to a sound (defun leftin (inl) (emplow inl)) ; RIGHTIN - apply high frequency emphasis and ; a very slight delay to a sound ; (defun rightin (inr) (seq (s-rest 0.02) (emphigh inr))) ; STEREOIZE -- create a stereo sound from a monaural source ; (defun stereoize (monoin) (vector (leftin monoin) (rightin monoin))) ; EXTRACTLEFT -- extract the left channel of a stereo sound (defun extractleft (inl) (aref inl 0)) ; EXTRACTRIGHT -- extract the right channel of a stereo sound (defun extractright (inr) (aref inr 1)) ; WSUM -- weighted sum of two monaural sounds ; ; inl: first monaural sound ; inr: second monaural sound ; amtl: multiplier for the first monaural sound ; amtr: multiplier for the second monaural sound ; (defun wsum (inl inr amtl amtr) (sum (mult inl amtl) (mult inr amtr))) ; SMIXER -- remix a stereo signal ; ; in: original stereo sound ; lamtl: amount in new left channel from the original left channel ; lamtr: amount in new left channel from the original right channel ; ramtl: amount in new right channel from the original left channel ; ramtr: amount in new right channel from the original right channel ; Note: lamtl, lamtr, ramtl, ramtr should have values in the ; range of -1 to 1 and may be static numbers or sounds ; (defun smixer (in lamtl lamtr ramtl ramtr) (let ((eleft (extractleft in)) (eright (extractright in))) (vector (wsum eleft eright lamtl lamtr) (wsum eleft eright ramtl ramtr)))) ; WIDEN -- widen the field of a stereo sound ; ; in: original stereo sound ; amt: a value between 0 and 1 which represents a widening factor ; 0 will leave the sound unchanged while 1 indicates the widest ; possible stereo field ; Note: amt may be a static number or a sound ; (defun widen (in amt) (let ((widenamt (mult -1 amt))) (smixer in 1 widenamt widenamt 1))) ; SPAN -- pan the virtual center channel of a stereo sound ; ; in: original stereo sound ; amt: a value between 0 and 1 which represents the panning location ; 0 pans the center channel all the way to the left while 1 pans ; it all the way to the right ; Note: amt may be a static number or a sound ; (defun span (in amt) (let ((leftc (sum 0.5 (mult -1 amt))) (rightc (sum -0.5 amt))) (smixer in 0.5 leftc rightc 0.5))) ; SWAPCHANNELS -- swap the two channels in a stereo sound (defun swapchannels (in) (vector (aref in 1) (aref in 0))) #| NOTE: there's nothing wrong with the code that is commented out here. These functions were in the original library, but I have commented them out because they are very simple and not very general. Perhaps they can be incorporated in an expanded form in a future version of Nyquist. For example, some general 3-D positioning with Doppler effects, etc., and some more elaborate HRTF code would be very interesting. Feel free to give these a try. -RBD ; IID -- position a monaural sound source by attenuating the volume ; of the sound at each ear point based on the distance between the ; two ear points and the distance of the sound source from the listener ; ; in: monaural source sound ; dist: lateral distance of the sound source from the listener in meters ; headwidth: width of the listener's head (i.e. the distance between ; the two ears) in meters ; rorl: a value of either 0 or 1 which represents whether the sound ; source is to the left or to the right of the listener ; (defun iid (in dist headWidth RorL) (let ((nearmult (/ 1.0 (mult dist dist))) (farmult (/ 1.0 (mult (sum dist headWidth) (sum dist headWidth))))) (if (eq rorl 0) ; sound source is to the left of listener (vector (mult in nearmult) (mult in farmult)) ; sound source is to the right of listener (vector (mult in farmult) (mult in nearmult))))) ; ITD -- position a monaural sound source by delaying the arrival ; of the sound at each ear point based on the distance ; between the two ear points and the distance of the sound ; source from the listener ; in: monaural source sound ; dist: lateral distance of the sound source from the listener in meters ; headwidth: width of the listener's head (i.e. the distance ; between the two ears) in meters ; rorl: a value of either 0 or 1 which represents whether the sound ; source is to the left or to the right of the listener ; (defun itd (in dist headWidth RorL) (let ((neardel (mult 0.0029387 dist)) (fardel (mult 0.0029387 (sum dist headWidth)))) (if (eq rorl 0) ; sound source is to the left of listener (vector (seq (s-rest neardel) in ) (seq (s-rest fardel) in)) ; sound source is to the right of listener (vector (seq (s-rest fardel) in) (seq (s-rest neardel) in))))) ; CFSPATIALIZATION -- a spatialization effect based on a cross-feed network ; (defun cfspatialization (in) (let ((shadowLeft (lp (seq (s-rest 0.0004) (aref in 0)) 265)) (shadowRight (lp (seq (s-rest 0.0004) (aref in 1)) 265))) (vector (sum (aref in 0) shadowRight) (sum (aref in 1) shadowLeft)))) ; CUSTBP -- a helper function that creates a custom bandpass filter ; for use in the hrtfapprox function (defun custbp (in) (lp (sum (hp in 4980) (mult in 0.75)) 7900)) ; HRTFAPPROX -- a spatialization effect based on an approximated HRTF ; (defun hrtfapprox (in) (let ((filteredLeft (seq (s-rest 0.00025) (custbp (aref in 0)))) (filteredRight (seq (s-rest 0.00025) (custbp (aref in 1))))) (vector (sum (aref in 0) (lp filteredRight 10200)) (sum (aref in 0) (lp filteredLeft 1020))))) |# ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Dolby Pro-Logic encoding and a ;; 2D Sound Positioning Scheme ;; ;; Dave Borel (dborel) with minor changes by ;; Roger B. Dannenberg ;; ;; Features: ;; -Dolby Pro-Logic panning ;; -Doppler for moving sounds ;; -Distance attenuation ;; -Atmospheric damping of high frequencies ;; -Progagation delay ;; -Test programs (setf config 1) ;Distance between listener and speakers ;--------------------------------------------------- ; Math Helpers ;--------------------------------------------------- ; ; Distance between two points ; (defun dist (x0 y0 x1 y1) (let* ( (rx (sum x1 (mult -1.0 x0))) (ry (sum y1 (mult -1.0 y0))) ) (s-sqrt (sum (mult rx rx) (mult ry ry))))) ; ; Raise x to each sample of snd ; (defun s-expt (x snd) (s-exp (mult (s-log x) snd))) ;; ;; SPATIALIZATION HELPERS: ;; ; ; Doppler effect ; (defun pl-doppler (snd r) (let* ( (v (mult -1 (slope r))) (ratio (recip (sum 1 (mult v (recip 344.31))))) (map (integrate ratio)) ) (sound-warp map snd) )) ; ; Distance-based low-pass filter ; (see report) ; (defun absorb (snd r-m) (lp snd (mult 14763.67 (s-expt 0.97895 r-m)))) ; ; Distance-based attenuation ; (see report) ; (defun atten (snd r) ; (let* ( (log2-r (mult (s-log r) (recip (log 10.0)))) ; (db-ratio (mult 20 log2-r)) ; (ratio (db-to-linear db-ratio)) ) ; ; (mult (clip ratio 1.0) snd))) (mult snd (clip (recip (mult r r)) 1))) ; ; Top-level spatializer ; sound source at (x,y) ; speaker at (xs, ys) ; assumes listener at (0,0) ; ; You could use this with ; configurations other than ; pro-logic (e.g. 6.1, 7.1, etc) ; (defun stage (snd x y xs ys) (let* ( (r (dist x y 0 0)) (rs (dist xs ys 0 0)) (x-hat (mult x (recip r))) (y-hat (mult y (recip r))) (xs-hat (mult xs (recip rs))) (ys-hat (mult ys (recip rs))) (dot (sum (mult x-hat xs-hat) (mult y-hat ys-hat))) (overlap (mult 0.5 (sum dot (s-abs dot)))) ) (mult overlap snd))) ;--------------------------------------------------- ; Speaker Mixing ;--------------------------------------------------- ; ; Dolby Pro-Logic Encoder ; (defun prologic (left center right surround) (let* ( (c (scale 0.5 center)) (s (highpass2 (lowpass2 (scale 0.5 surround) 7000) 100) ) (slfe (scale 0.25 (lp surround 100))) (l (sim left center (mult -1.0 s) slfe)) (r (sim right center s slfe)) ) (vector l r))) ; ; Direct-to-speaker playback ; (defun pl-left (snd) (let ((s (mult 0 snd))) (prologic snd s s s))) (defun pl-center (snd) (let ((s (mult 0 snd))) (prologic s snd s s))) (defun pl-right (snd) (let ((s (mult 0 snd))) (prologic s s snd s))) (defun pl-rear (snd) (let ((s (mult 0 snd))) (prologic s s s snd))) ; ; Pans a sound across the surround speakers ; (no realistic imaging or attenuation) ; Works like pan but y specifies depth (defun pl-pan2d (s-in x y) (let ((snd (scale 0.5 s-in))) (prologic (mult snd (sum 1.0 (mult -1.0 x) (sum 1 (mult -1.0 y))) );left (mult snd 0.0) ;center(null) (mult snd x (sum 1.0 (mult -1.0 y) )) ;right (mult snd y 0.5)))) ;rear ; ; Position a sound in the 2D soundstage ; Includes spatialization effects ; ; (x,y) may be (flonum, flonum) or (behavior, behavior) ; (defun pl-position (s-in x y config) (let* ( (r-m (dist x y 0 0)) (r (mult r-m (recip config))) (spd-snd (/ 344.31 config)) (offset (if (soundp r-m) (/ (aref (snd-samples r 1) 0) spd-snd) (/ r spd-snd))) (snd (seq (s-rest offset) (if (soundp r-m) (atten (absorb (pl-doppler s-in r-m) r-m) r) (atten (absorb s-in r-m) r)))) ) ; Two Notes: ; 1.) The center channel is automatically imaged correctly ; because sounds placed between the left-and-right channels ; distribute linearly between the two channels. ; ; 2.) Although the below settings assume that all speakers are ; equidistant from the listener, you can easily assume a ; different layout by modifying the xs and ys values in ; each channel's call to the stage function. ; (prologic (stage snd x y -.1913 -.4619) ;left (scale 0.0 snd) ;center (null) (stage snd x y .1913 -.4619) ;right (stage snd x y 0.0 .5 )))) ;rear ;--------------------------------------------------- ; Diagnostics ;--------------------------------------------------- ; ; Pro-Logic Channel Test Tones ; (defun pl-test () (play (prologic ( osc-note a3 ) (seq (s-rest 1.25) (osc-note b3)) (seq (s-rest 2.5 ) (osc-note c4)) (seq (s-rest 3.75) (osc-note d4)) ))) ; ; Pan Test ; (defun pan-test () (play (pl-pan2d (seq (s-rest .25) (osc a3 .75) (s-rest .25) (osc b3 .75) (s-rest .25) (osc c4 .75) (s-rest .25) (osc d4 .75)) (pwl 0 0 0.99 0 1 1 2.99 1 3 0 4 0 4 ) (pwl 0 0 1.99 0 2 1 4 1 4 )))) ; ; Doppler test ; (defun dop () (play (pl-doppler (osc c4 10) (pwl .25 0 .5 100 .75 100 1.0)))) ; ; Attenuation test ; (defun att () (play (atten (osc-note c4 4) (pwl 0 2 1 2 2 100 3 100 4 2 4 )))) ; ; Doppler positioning test (ambulance) ; (defun ambulance () (play (scale 0.2 (pl-position (stretch 16 (fmosc c4 (mult 1000 (lfo 2)))) (pwl 0 -20 8 20 8 ) (pwl 0 0 8 ) config)))) ; ; Position test ; ; Make a sound orbit the listener (defun orbit-x (r t times) (let (k) (seqrep (k times) (pwl 0.0 0.0 (/ t 4) r (/ t 2) 0.0 (/ (* t 3) 4) (* -1 r) t 0.0 t ) ))) (defun orbit-y (r t times) (let (k) (seqrep (k times) (pwl 0.0 (* -1 r) (/ t 4.0) 0.0 (/ t 2.0) r (/ (* t 3.0)4.0) 0.0 t (* -1 r) t ) ))) (defun orbit (snd r t times) (pl-position snd (orbit-x r t times) (orbit-y r t times) config)) ; Play some tones (defun pos-1 () (play (pl-position (seq (s-rest .125) (osc a3 1.75) (s-rest .25) (osc b3 1.75) (s-rest .25) (osc c4 1.75) (s-rest .25) (osc d4 1.75) (s-rest .125)) (pwl 0 -5 1 5 2 5 3 -5 4 -5 5 5 6 5 7 -5 8 -5 8 ) (pwl 0 -5 1 -5 2 5 3 5 4 -5 5 -5 6 5 7 5 8 -5 8 ) config))) (defun pos-2 () (play (seq (orbit (seq (s-rest .125) (osc a3 1.75) (s-rest .25) (osc b3 1.75) (s-rest .25) (osc c4 1.75) (s-rest .25) (osc d4 1.75) (s-rest .125)) 5 8 1) (orbit (seq (s-rest .125) (osc a3 1.75) (s-rest .25) (osc b3 1.75) (s-rest .25) (osc c4 1.75) (s-rest .25) (osc d4 1.75) (s-rest .125)) 5 8 1)))) nyquist-3.05/lib/instruments.txt0000644000175000000620000001265411466723256016111 0ustar stevestaffTones:shiver(float dur = 1.0 (0.1:9.9), int pitch = 72 (48:96), int noise-percent = 50 (0:100), float noise-freq = 100 (20:480)) REQUIRE "../demos/pmorales/a4.lsp" END-SOUND Tones:cheap(float frq-randi = 100 (0.0:1000.0), int pitch = 69 (48:96), float dur = 2.0 (0.1:9.9), float rate = 3.0 (0.1:9.9), float amount = 1000.0 (100.0:9900.0)) REQUIRE "../demos/pmorales/a6.lsp" END-SOUND Percussion:gong-1() REQUIRE "../demos/pmorales/b1.lsp" END-SOUND Percussion:gong-2() REQUIRE "../demos/pmorales/b1.lsp" END-SOUND Percussion:gong-3(int freq = 440 (200:800), float dur = 5.0 (2.0:10.0)) REQUIRE "../demos/pmorales/b1.lsp" END-SOUND Percussion:gong-3-melody() REQUIRE "../demos/pmorales/b1.lsp" END-SOUND Percussion:plight-drum-example() LISP-SOURCE (if (not (boundp ' *plight-drum-path*)) (cond ((not (load "../demos/plight/drum.lsp")) (princ "COULD NOT FIND DRUM.LSP -- THE PLIGHT-DRUM PACKAGE IS NOT PART OF THE BASIC NYQUIST DISTRIBUTION, BUT YOU CAN DOWNLOAD IT") nil))) SAL-SOURCE if ! boundp(quote(*plight-drum-path*)) then if ! #load("../demos/plight/drum.lsp") then exec princ("COULD NOT FIND DRUM.LSP -- THE PLIGHT-DRUM PACKAGE IS NOT PART OF THE BASIC NYQUIST DISTRIBUTION, BUT YOU CAN DOWNLOAD IT") END-SOUND Tones:st-sac(int pitch = 67 (48:96), float dur = 4.0 (0.1:9.9), float offset-entry = 1.25 (0.1:3.9), int num-harmonics = 8 (1:16)) REQUIRE "../demos/pmorales/b2.lsp" END-SOUND Tones:st-sac-sequence() REQUIRE "../demos/pmorales/b2.lsp" END-SOUND Percussion:risset-bell(float amp = 1.0 (0.0:1.0), float dur = 4.0 (0.1:9.9), float frq = 440.0 (50.0:1950.0)) REQUIRE "../demos/pmorales/b3.lsp" END-SOUND Percussion:risset-bell-sequence() REQUIRE "../demos/pmorales/b3.lsp" END-SOUND Tones:starship(float freq = 200.0 (100.0:900.0), float scale = 1000.0 (0.0:4000.0)) REQUIRE "../demos/pmorales/b5.lsp" END-SOUND Tones:tibetan(float freq = 110 (25.0:575.0), float offset = 0.03 (0.0:0.1), float dur = 10.0 (1.0:29.0), float rise = 1.0 (0.02:4.98), float dec = 4.0 (0.01:19.99)) REQUIRE "../demos/pmorales/b7.lsp" END-SOUND Tones:tibetan-sequence() REQUIRE "../demos/pmorales/b7.lsp" END-SOUND Percussion:risset-drum(float amp = 1.0 (0.0:1.0), float dur = 1.0 (0.1:9.9), float freq = 100 (25.0:775.0)) REQUIRE "../demos/pmorales/b8.lsp" END-SOUND Percussion:risset-drum-sequence() REQUIRE "../demos/pmorales/b8.lsp" END-SOUND Tones:risset-endless() REQUIRE "../demos/pmorales/b9.lsp" END-SOUND Vocal:buzz-ah[ah](int pitch = 36 (24:72), float dur = 1 (0.1:9.9)) REQUIRE "../demos/pmorales/buzz.lsp" END-SOUND Vocal:buzz-ah[ah](int pitch = 36 (24:72), float dur = 1 (0.1:9.9)) REQUIRE "../demos/pmorales/buzz.lsp" END-SOUND Vocal:buzz-eh[eh](int pitch = 36 (24:72), float dur = 1 (0.1:9.9)) REQUIRE "../demos/pmorales/buzz.lsp" END-SOUND Vocal:buzz-eeh[eeh](int pitch = 36 (24:72), float dur = 1 (0.1:9.9)) REQUIRE "../demos/pmorales/buzz.lsp" END-SOUND Vocal:buzz-ooh[ooh](int pitch = 36 (24:72), float dur = 1 (0.1:9.9)) REQUIRE "../demos/pmorales/buzz.lsp" END-SOUND Vocal:buzz-demo[buzz-demo]() REQUIRE "../demos/pmorales/buzz.lsp" END-SOUND Tones:tenney(float frandi = 400 (100.0:1900.0), float freq = 440 (100.0:1900.0), float dur = 1 (0.1:9.9)) REQUIRE "../demos/pmorales/c1.lsp" END-SOUND Tones:tenney-demo() REQUIRE "../demos/pmorales/c1.lsp" END-SOUND Tones:pluck(int pitch = 36 (24:72), float dur = 1 (0.1:9.9)) END-SOUND FM:fm-bell(float freq = 150.0 (50.0:350.0), float cm-ratio = 0.714286 (0.1:1.9), float imax = 10.0 (3.0:37.0), float dur = 5.0 (0.1:9.9), float amp = 1.0 (0.0:1.0)) REQUIRE "../demos/pmorales/e2.lsp" END-SOUND FM:fm-wood-drum[fm-w-d](int pitch = 62 (48:72)) REQUIRE "../demos/pmorales/e2.lsp" END-SOUND FM:fm-brass[fm-br](int pitch = 62 (48:84)) REQUIRE "../demos/pmorales/e2.lsp" END-SOUND FM:fm-clarinet[fm-c](int pitch = 67 (48:84)) REQUIRE "../demos/pmorales/e2.lsp" END-SOUND FM:double-carrier(float dur = 1.0 (0.1:9.9), float freq = 440.0 (60.0:1940.0), float cm-ratio = 1.0 (0.1:3.9), float amp = 1.0 (0.0:10.0), float amp-ratio = 0.5 (0.0:10.0), float imax = 3.0 (0.1:3.9), float imin = 1.0 (0.1:3.9), float modulator = 2.0 (0.0:10.0)) REQUIRE "../demos/pmorales/e2.lsp" END-SOUND FM:v-fm(int pitch = 67 (48:84), float break = 0.3 (0.0:1.0), float dur = 3.0 (1.0:10.0), float rev = 0.5 (0.0:1.0)) REQUIRE "../demos/pmorales/e2.lsp" END-SOUND Tones:bell-sequence() REQUIRE "../demos/pmorales/partial.lsp" END-SOUND Keyboard:dmhm-organ(int pitch = 70 (48:96)) REQUIRE "../demos/mateos/organ.lsp" END-SOUND Keyboard:dmhm-organ-test() REQUIRE "../demos/mateos/organ.lsp" END-SOUND Percussion:dmhm-gong[dmhm-gong](int pitch = 57 (40:80)) REQUIRE "../demos/mateos/gong.lsp" END-SOUND Brass:dmhm-tuba(float freq = 70 (30:170)) REQUIRE "../demos/mateos/tuba.lsp" END-SOUND Percussion:dmhm-bell(int bell = 31 (24:60)) REQUIRE "../demos/mateos/bell.lsp" END-SOUND Keyboard:piano[piano-note](float duration = 2 (0.1:9.9), int pitch = 70 (60:100), int dynamic = 50 (0:100)) REQUIRE "pianosyn.lsp" END-SOUND Music:cellular-automation-demo[cell-aut-demo]() REQUIRE "../demos/allewis/cell_aut.lsp" END-SOUND nyquist-3.05/Readme.txt0000644000175000000620000002142011537432671014131 0ustar stevestaffREADME file for Nyquist Version 3.05 13 Mar 2011 Roger B. Dannenberg LICENSE: see license.txt WEB SITE: http://www.cs.cmu.edu/~music/nyquist INSTALLING NYQUIST ==================== You can download pre-compiled versions for Windows and OS X. You can compile Nyquist from sources for Windows, OS X, linux, and other versions of Unix. For details, see one of these files: - sys/win/README.txt - sys/mac/README.txt - sys/unix/README.txt IMPLEMENTATION STATUS ===================== Version 3.05 provides: New "UPIC Editor" window in NyquistIDE Fix to escape backslashes in default windows directory Fix to other problems with Preferences Arpeggiator example in nyquist/demos Version 3.04 provides: Updates to libraries, including liblo and PortAudio Documentation uses both syntax SAL and Lisp syntax Some STK instruments have been added Build files modified to make 32-bit code even on 64-bit architectures (Nyquist only runs in 32-bit mode) Version 3.03 provides: Bug fix to Markov pattern generator (see make-markov). Update to current (24-feb-09) liblo library. Slight change to license.txt to comply wiht two LGPL library licenses: libsndfile and liblo. score-sort can sort very big scores now using iterative merge sort Version 3.02 provides: Uses libsndfile and recent version of portaudio. Many bug fixes. Support & compatibility for Algorithmic Composition (to appear) Version 3.01 provides: Feedback FM: see fmfb, snd-fmfb and snd-fmfbv fixed help functions and internal browser window Documentation mostly using SAL syntax now Version 3.00 provides: First release supporting SAL syntax Major revision to documentation (but more to come) Bug fixes for sustain transformation Many new STK instruments ported by Pedro Morales Pedro's sdl music input language Version 2.38 provides: improved PWL editor improved preferences dialog bug fixes in Equalizer editor additional documentation for demos/plight/drums.lsp option click or right click on completion list to get help manual can be displayed in an internal window in jNyqIDE Version 2.37 provides: fix for byte order on Mac PPC that prevented pianosyn.lsp from loading Version 2.36 provides: cross-platform browser launching in jNyqIDE fix search path set by jNyqIDE (OS X-related bug introduced in 2.35) fix bug in slider update code on OS X Version 2.35 provides: fix for Open Sound Control under Windows/jNyqIDE other minor jNyqIDE fixes Version 2.34 provides: fix to ^U (send selection to Nyquist) in jNyqIDE default sound file path for Mac OS X is /tmp Nyquist exits when EOF detected -- try to make orphans abort Version 2.33 provides: additional documentation for Open Sound Control interface and utility programs Version 2.32 provides: envelope editor in jNyqIDE EQ editor in jNyqIDE score editor in jNyqIDE slider support in Nyquist OSC (Open Sound Control) interface OSC test program and serial-to-OSC program drum machine (as separate download) jNyqIDE has pop-up menus and per-file menu bars Version 2.31 provides: new compositional algorithm support in xm.lsp many bug fixes MiniMoog emulator spatialization libraries sound reversal functions Dolby Surround encode/decode Version 2.30 provides: many many changes, bug fixes, enhancements new Java-based IDE: jnyqide LPC analysis/synthesis uses PortAudio for audio I/O changes for Debian Linux compatibility new examples in demos new documentation and html files Version 2.29 provides: new functions: snd-alpassvc, sndalpassvv, snd-eqbandvvv corresponding high-level functions in Nyquist new licenses for both Nyquist and XLISP new NyqIDE implementation fixed BUZZ function various bug and documentation fixes Version 2.28 provides: include indx.html in doc folder (in files.txt) fixed compute-default-sound-file in nyquist.lsp to compute appropriate extension (.wav, .aif) more code to automate win32 releases Version 2.27 provides: makefile.lsp now generates sndfn.wcl & sndfn.cl fix to include snd-pluck and some others omittted from 2.26 Version 2.26 provides: bug fix in sampler, negative frequency handling guard against out-of-order events in TIMED-SEQ added FMLFO, an lfo with frequency modulation added SND-SQRT, S-SQRT, SND-ABS, S-ABS functions new NyqIDE version with S-PLOT function (!) NyqIDE has better parsing for paren balancing NyqIDE upgrade to WindowsXP and Delphi 6 NyqIDE increases input string length maximum NyqIDE prompts on save conflict added voice-synthesis demo from Eduardo Miranda corrected absolute path in demos/pmorales/e2.lsp minor documentation and indexing improvements pointer to demo docs goes on start menu now Version 2.25 provides: new way to provide search path: set *SEARCH-PATH* to a string, e.g. (SETF *SEARCH-PATH* "C:/program files/nyquist/runtime,c:/program files/nyquist/lib") allowing Nyquist to be run without setting registry. Version 2.24 provides: text editing for command lines in Linux version Version 2.23 provides: bug fix in (current-path) for Mac fixes to some Mac sources corrupted in 2.22 Version 2.22 provides: documentation (HTML) included in release now bug fix for Mac console output exceeding 32K limit protection from playing very high sample rates in Win32 (crashes in Windows MME library!) change s-save to take :endian rather than :swap parameter pianosyn.lsp runs on the Mac now demos/examples.lsp generates audio with "normal" sample rates Version 2.21 provides: s-plot uses gnu-plot in Linux separation from CVS -- I just couldn't keep beating my head against the wall Version 2.20 provides: improved Macintosh support Version 2.19 provides: integration of Macintosh code (from v2.12) addition of PLUCK and BUZZ synthesis functions Version 2.18 provides: bug fix in midifile read routine under Linux Version 2.17 provides: bug fix for long line input under linux and windows biquad filters hzosc osc-tri osc-saw osc-pulse -- new oscillator variants bug fix for reading in non-AIFF files with 'FORM' headings extension to s-read to support explicit byte-swap parameter Version 2.16 provides: bug fix in tables (lookup oscillators and other functions) Windows GUI version of Nyquist Version 2.15 provides: port to Linux Version 2.5 provides: more signal processing functions Version 2.2 provides: ports to more systems including Win32 (Win95 and NT) bug fixes more signal processing functions improved sound I/O subsystem Version 2.1 provides: bug fixes documentation and code for user extensions Version 2.0 provides: continuous time warps many more functions bug fixes The distribution may contain sources for Nyquist. If not, you got the runtime distribution, and there is a source version available. A number of "source" files are machine generated, including: - many .c and .h files that implement signal processing functions. These are generated by translation system that converts .alg files to .c and .h files. .alg files give high-level descriptions of DSP algorithms. - Makefile.* is generated by "makefile.lsp". The status is: System Status RS6K = RS6000, AIX untested, but used to work NEXT = NeXT 3.0 (Cube) untested, but worked fine on a previous version SGI = ??? untested, but used to work PMAX = Mach 2.5 on Dec workstation untested, but worked in previous version SPARC = Sun Sparc ??? untested - previous version of Nyquist DID work LINUX = Linux tested Win32 tested Mac tested If you have problems running Nyquist on a Unix machine, I'd be happy to help. I can give you advice or if you give me an account, I can log in remotely and install Nyquist for you. If you make corrections yourself, please let me have them so I can put them in the next release. DIRECTORY STRUCTURE =================== cmt - CMU MIDI Toolkit files, used by Nyquist for MIDI File I/O demos - Nyquist demos go here fft - some fft functions lib - .lsp files offering extensions to Nyquist misc - various files and programs used to implement Nyquist nyqsrc - general Nyquist source code (mostly in C) runtime - the Nyquist and XLisp runtime code (mostly in XLisp) sys - system specific files snd - the sound file, sound input, and sound output package test - test code (this is not maintained and may not be in the release) todo - list of things to do (this may not be in the release) tran - descriptor (.alg) files for machine-translated Nyquist code xlisp - sources for Xlisp (these are linked into Nyquist) nyquist-3.05/releasenyqide.bat0000644000175000000620000000277711466723256015536 0ustar stevestaffrmdir /s /q nyqrelide mkdir nyqrelide xcopy runtime nyqrelide\runtime /s /i del nyqrelide\runtime\CVS /q rmdir nyqrelide\runtime\CVS /q copy sys\win\msvc\system.lsp nyqrelide\runtime xcopy doc nyqrelide\doc /s /i del nyqrelide\doc\CVS /q rmdir nyqrelide\doc\CVS /q xcopy lib nyqrelide\lib /s /i del nyqrelide\lib\CVS /q rmdir nyqrelide\lib\CVS /q xcopy demos nyqrelide\demos /s /i del nyqrelide\demos\jones\docs /q rmdir nyqrelide\demos\jones\docs /q del nyqrelide\demos\jones\nydoc /q rmdir nyqrelide\demos\jones\nydoc /q del nyqrelide\demos\jones\sjlib /q rmdir nyqrelide\demos\jones\sjlib /q del nyqrelide\demos\jones /q rmdir nyqrelide\demos\jones /q del nyqrelide\demos\plight\kit /q rmdir nyqrelide\demos\plight\kit /q del nyqrelide\demos\plight /q rmdir nyqrelide\demos\plight /q del nyqrelide\demos\CVS /q rmdir nyqrelide\demos\CVS /q del nyqrelide\demos\pmorales\CVS /q rmdir nyqrelide\demos\pmorales\CVS /q copy WinRel\nyquist.exe nyqrelide copy liblo\test-client\Release\osc-test-client.exe nyqrelide copy liblo\ser-to-osc\Release\ser-to-osc.exe nyqrelide copy NyqIDE\NyqIDE.exe nyqrelide copy NyqIDE\doc\Tips.htm nyqrelide\doc copy NyqIDE\doc\NyquistIDE.gif nyqrelide\doc copy NyqIDE\doc\nyqide_plot.gif nyqrelide\doc copy advantages.txt nyqrelide copy readme.txt nyqrelide copy todo.txt nyqrelide copy license.txt nyqrelide mkdir nyqrelide\jnyqide copy jnyqide\NyquistWords.txt nyqrelide\jnyqide copy jnyqide\keywords.txt nyqrelide\jnyqide copy jnyqide\jNyqIDE.jar nyqrelide\jnyqide copy jnyqide.bat nyqrelide\jnyqide.bat nyquist-3.05/nylsf/0002755000175000000620000000000011537433127013326 5ustar stevestaffnyquist-3.05/nylsf/sndfile.c0000644000175000000620000023076511514664101015122 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #define SNDFILE_MAGICK 0x1234C0DE typedef struct { int error ; const char *str ; } ErrorStruct ; static ErrorStruct SndfileErrors [] = { /* Public error values and their associated strings. */ { SF_ERR_NO_ERROR , "No Error." }, { SF_ERR_UNRECOGNISED_FORMAT , "File opened for read. Format not recognised." }, { SF_ERR_SYSTEM , "System error." /* Often replaced. */ }, { SF_ERR_MALFORMED_FILE , "Supported file format but file is malformed." }, { SF_ERR_UNSUPPORTED_ENCODING , "Supported file format but unsupported encoding." }, /* Private error values and their associated strings. */ { SFE_BAD_FILE , "File does not exist or is not a regular file (possibly a pipe?)." }, { SFE_BAD_FILE_READ , "File exists but no data could be read." }, { SFE_OPEN_FAILED , "Could not open file." }, { SFE_BAD_SNDFILE_PTR , "Not a valid SNDFILE* pointer." }, { SFE_BAD_SF_INFO_PTR , "NULL SF_INFO pointer passed to libsndfile." }, { SFE_BAD_SF_INCOMPLETE , "SF_PRIVATE struct incomplete and end of header parsing." }, { SFE_BAD_FILE_PTR , "Bad FILE pointer." }, { SFE_BAD_INT_PTR , "Internal error, Bad pointer." }, { SFE_BAD_STAT_SIZE , "Error : software was misconfigured at compile time (sizeof statbuf.st_size)." }, { SFE_MALLOC_FAILED , "Internal malloc () failed." }, { SFE_UNIMPLEMENTED , "File contains data in an unimplemented format." }, { SFE_BAD_READ_ALIGN , "Attempt to read a non-integer number of channels." }, { SFE_BAD_WRITE_ALIGN , "Attempt to write a non-integer number of channels." }, { SFE_UNKNOWN_FORMAT , "File contains data in an unknown format." }, { SFE_NOT_READMODE , "Read attempted on file currently open for write." }, { SFE_NOT_WRITEMODE , "Write attempted on file currently open for read." }, { SFE_BAD_MODE_RW , "This file format does not support read/write mode." }, { SFE_BAD_SF_INFO , "Internal error : SF_INFO struct incomplete." }, { SFE_BAD_OFFSET , "Error : supplied offset beyond end of file." }, { SFE_NO_EMBED_SUPPORT , "Error : embedding not supported for this file format." }, { SFE_NO_EMBEDDED_RDWR , "Error : cannot open embedded file read/write." }, { SFE_NO_PIPE_WRITE , "Error : this file format does not support pipe write." }, { SFE_BAD_RDWR_FORMAT , "Attempted to open read only format for RDWR." }, { SFE_BAD_VIRTUAL_IO , "Error : bad pointer on SF_VIRTUAL_IO struct." }, { SFE_INTERLEAVE_MODE , "Attempt to write to file with non-interleaved data." }, { SFE_INTERLEAVE_SEEK , "Bad karma in seek during interleave read operation." }, { SFE_INTERLEAVE_READ , "Bad karma in read during interleave read operation." }, { SFE_INTERNAL , "Unspecified internal error." }, { SFE_BAD_CONTROL_CMD , "Bad command passed to function sf_command()." }, { SFE_BAD_ENDIAN , "Bad endian-ness. Try default endian-ness" }, { SFE_CHANNEL_COUNT , "Too many channels specified." }, { SFE_BAD_SEEK , "Internal psf_fseek() failed." }, { SFE_NOT_SEEKABLE , "Seek attempted on unseekable file type." }, { SFE_AMBIGUOUS_SEEK , "Error : combination of file open mode and seek command is ambiguous." }, { SFE_WRONG_SEEK , "Error : invalid seek parameters." }, { SFE_SEEK_FAILED , "Error : parameters OK, but psf_seek() failed." }, { SFE_BAD_OPEN_MODE , "Error : bad mode parameter for file open." }, { SFE_OPEN_PIPE_RDWR , "Error : attempt toopen a pipe in read/write mode." }, { SFE_RDWR_POSITION , "Error on RDWR position (cryptic)." }, { SFE_RDWR_BAD_HEADER , "Error : Cannot open file in read/write mode due to string data in header." }, { SFE_STR_NO_SUPPORT , "Error : File type does not support string data." }, { SFE_STR_NOT_WRITE , "Error : Trying to set a string when file is not in write mode." }, { SFE_STR_MAX_DATA , "Error : Maximum string data storage reached." }, { SFE_STR_MAX_COUNT , "Error : Maximum string data count reached." }, { SFE_STR_BAD_TYPE , "Error : Bad string data type." }, { SFE_STR_NO_ADD_END , "Error : file type does not support strings added at end of file." }, { SFE_STR_BAD_STRING , "Error : bad string." }, { SFE_STR_WEIRD , "Error : Weird string error." }, { SFE_WAV_NO_RIFF , "Error in WAV file. No 'RIFF' chunk marker." }, { SFE_WAV_NO_WAVE , "Error in WAV file. No 'WAVE' chunk marker." }, { SFE_WAV_NO_FMT , "Error in WAV file. No 'fmt ' chunk marker." }, { SFE_WAV_FMT_SHORT , "Error in WAV file. Short 'fmt ' chunk." }, { SFE_WAV_BAD_FACT , "Error in WAV file. 'fact' chunk out of place." }, { SFE_WAV_BAD_PEAK , "Error in WAV file. Bad 'PEAK' chunk." }, { SFE_WAV_PEAK_B4_FMT , "Error in WAV file. 'PEAK' chunk found before 'fmt ' chunk." }, { SFE_WAV_BAD_FORMAT , "Error in WAV file. Errors in 'fmt ' chunk." }, { SFE_WAV_BAD_BLOCKALIGN , "Error in WAV file. Block alignment in 'fmt ' chunk is incorrect." }, { SFE_WAV_NO_DATA , "Error in WAV file. No 'data' chunk marker." }, { SFE_WAV_BAD_LIST , "Error in WAV file. Malformed LIST chunk." }, { SFE_WAV_UNKNOWN_CHUNK , "Error in WAV file. File contains an unknown chunk marker." }, { SFE_WAV_WVPK_DATA , "Error in WAV file. Data is in WAVPACK format." }, { SFE_WAV_ADPCM_NOT4BIT , "Error in ADPCM WAV file. Invalid bit width." }, { SFE_WAV_ADPCM_CHANNELS , "Error in ADPCM WAV file. Invalid number of channels." }, { SFE_WAV_GSM610_FORMAT , "Error in GSM610 WAV file. Invalid format chunk." }, { SFE_AIFF_NO_FORM , "Error in AIFF file, bad 'FORM' marker." }, { SFE_AIFF_AIFF_NO_FORM , "Error in AIFF file, 'AIFF' marker without 'FORM'." }, { SFE_AIFF_COMM_NO_FORM , "Error in AIFF file, 'COMM' marker without 'FORM'." }, { SFE_AIFF_SSND_NO_COMM , "Error in AIFF file, 'SSND' marker without 'COMM'." }, { SFE_AIFF_UNKNOWN_CHUNK , "Error in AIFF file, unknown chunk." }, { SFE_AIFF_COMM_CHUNK_SIZE, "Error in AIFF file, bad 'COMM' chunk size." }, { SFE_AIFF_BAD_COMM_CHUNK , "Error in AIFF file, bad 'COMM' chunk." }, { SFE_AIFF_PEAK_B4_COMM , "Error in AIFF file. 'PEAK' chunk found before 'COMM' chunk." }, { SFE_AIFF_BAD_PEAK , "Error in AIFF file. Bad 'PEAK' chunk." }, { SFE_AIFF_NO_SSND , "Error in AIFF file, bad 'SSND' chunk." }, { SFE_AIFF_NO_DATA , "Error in AIFF file, no sound data." }, { SFE_AIFF_RW_SSND_NOT_LAST, "Error in AIFF file, RDWR only possible if SSND chunk at end of file." }, { SFE_AU_UNKNOWN_FORMAT , "Error in AU file, unknown format." }, { SFE_AU_NO_DOTSND , "Error in AU file, missing '.snd' or 'dns.' marker." }, { SFE_AU_EMBED_BAD_LEN , "Embedded AU file with unknown length." }, { SFE_RAW_READ_BAD_SPEC , "Error while opening RAW file for read. Must specify format and channels.\n" "Possibly trying to open unsupported format." }, { SFE_RAW_BAD_BITWIDTH , "Error. RAW file bitwidth must be a multiple of 8." }, { SFE_RAW_BAD_FORMAT , "Error. Bad format field in SF_INFO struct when openning a RAW file for read." }, { SFE_PAF_NO_MARKER , "Error in PAF file, no marker." }, { SFE_PAF_VERSION , "Error in PAF file, bad version." }, { SFE_PAF_UNKNOWN_FORMAT , "Error in PAF file, unknown format." }, { SFE_PAF_SHORT_HEADER , "Error in PAF file. File shorter than minimal header." }, { SFE_SVX_NO_FORM , "Error in 8SVX / 16SV file, no 'FORM' marker." }, { SFE_SVX_NO_BODY , "Error in 8SVX / 16SV file, no 'BODY' marker." }, { SFE_SVX_NO_DATA , "Error in 8SVX / 16SV file, no sound data." }, { SFE_SVX_BAD_COMP , "Error in 8SVX / 16SV file, unsupported compression format." }, { SFE_SVX_BAD_NAME_LENGTH , "Error in 8SVX / 16SV file, NAME chunk too long." }, { SFE_NIST_BAD_HEADER , "Error in NIST file, bad header." }, { SFE_NIST_CRLF_CONVERISON, "Error : NIST file damaged by Windows CR -> CRLF conversion process." }, { SFE_NIST_BAD_ENCODING , "Error in NIST file, unsupported compression format." }, { SFE_VOC_NO_CREATIVE , "Error in VOC file, no 'Creative Voice File' marker." }, { SFE_VOC_BAD_FORMAT , "Error in VOC file, bad format." }, { SFE_VOC_BAD_VERSION , "Error in VOC file, bad version number." }, { SFE_VOC_BAD_MARKER , "Error in VOC file, bad marker in file." }, { SFE_VOC_BAD_SECTIONS , "Error in VOC file, incompatible VOC sections." }, { SFE_VOC_MULTI_SAMPLERATE, "Error in VOC file, more than one sample rate defined." }, { SFE_VOC_MULTI_SECTION , "Unimplemented VOC file feature, file contains multiple sound sections." }, { SFE_VOC_MULTI_PARAM , "Error in VOC file, file contains multiple bit or channel widths." }, { SFE_VOC_SECTION_COUNT , "Error in VOC file, too many sections." }, { SFE_VOC_NO_PIPE , "Error : not able to operate on VOC files over a pipe." }, { SFE_IRCAM_NO_MARKER , "Error in IRCAM file, bad IRCAM marker." }, { SFE_IRCAM_BAD_CHANNELS , "Error in IRCAM file, bad channel count." }, { SFE_IRCAM_UNKNOWN_FORMAT, "Error in IRCAM file, unknown encoding format." }, { SFE_W64_64_BIT , "Error in W64 file, file contains 64 bit offset." }, { SFE_W64_NO_RIFF , "Error in W64 file. No 'riff' chunk marker." }, { SFE_W64_NO_WAVE , "Error in W64 file. No 'wave' chunk marker." }, { SFE_W64_NO_FMT , "Error in W64 file. No 'fmt ' chunk marker." }, { SFE_W64_NO_DATA , "Error in W64 file. No 'data' chunk marker." }, { SFE_W64_FMT_SHORT , "Error in W64 file. Short 'fmt ' chunk." }, { SFE_W64_FMT_TOO_BIG , "Error in W64 file. 'fmt ' chunk too large." }, { SFE_W64_ADPCM_NOT4BIT , "Error in ADPCM W64 file. Invalid bit width." }, { SFE_W64_ADPCM_CHANNELS , "Error in ADPCM W64 file. Invalid number of channels." }, { SFE_W64_GSM610_FORMAT , "Error in GSM610 W64 file. Invalid format chunk." }, { SFE_MAT4_BAD_NAME , "Error in MAT4 file. No variable name." }, { SFE_MAT4_NO_SAMPLERATE , "Error in MAT4 file. No sample rate." }, { SFE_MAT4_ZERO_CHANNELS , "Error in MAT4 file. Channel count is zero." }, { SFE_MAT5_BAD_ENDIAN , "Error in MAT5 file. Not able to determine endian-ness." }, { SFE_MAT5_NO_BLOCK , "Error in MAT5 file. Bad block structure." }, { SFE_MAT5_SAMPLE_RATE , "Error in MAT5 file. Not able to determine sample rate." }, { SFE_MAT5_ZERO_CHANNELS , "Error in MAT5 file. Channel count is zero." }, { SFE_PVF_NO_PVF1 , "Error in PVF file. No PVF1 marker." }, { SFE_PVF_BAD_HEADER , "Error in PVF file. Bad header." }, { SFE_PVF_BAD_BITWIDTH , "Error in PVF file. Bad bit width." }, { SFE_XI_BAD_HEADER , "Error in XI file. Bad header." }, { SFE_XI_EXCESS_SAMPLES , "Error in XI file. Excess samples in file." }, { SFE_XI_NO_PIPE , "Error : not able to operate on XI files over a pipe." }, { SFE_HTK_NO_PIPE , "Error : not able to operate on HTK files over a pipe." }, { SFE_SDS_NOT_SDS , "Error : not an SDS file." }, { SFE_SDS_BAD_BIT_WIDTH , "Error : bad bit width for SDS file." }, { SFE_SD2_FD_DISALLOWED , "Error : cannot open SD2 file without a file name." }, { SFE_SD2_BAD_DATA_OFFSET , "Error : bad data offset." }, { SFE_SD2_BAD_MAP_OFFSET , "Error : bad map offset." }, { SFE_SD2_BAD_DATA_LENGTH , "Error : bad data length." }, { SFE_SD2_BAD_MAP_LENGTH , "Error : bad map length." }, { SFE_SD2_BAD_RSRC , "Error : bad resource fork." }, { SFE_SD2_BAD_SAMPLE_SIZE , "Error : bad sample size." }, { SFE_FLAC_BAD_HEADER , "Error : bad flac header." }, { SFE_FLAC_NEW_DECODER , "Error : problem while creating flac decoder." }, { SFE_FLAC_INIT_DECODER , "Error : problem while initialization of the flac decoder." }, { SFE_FLAC_LOST_SYNC , "Error : flac decoder lost sync." }, { SFE_FLAC_BAD_SAMPLE_RATE, "Error : flac does not support this sample rate." }, { SFE_FLAC_UNKNOWN_ERROR , "Error : unknown error in flac decoder." }, { SFE_DWVW_BAD_BITWIDTH , "Error : Bad bit width for DWVW encoding. Must be 12, 16 or 24." }, { SFE_G72X_NOT_MONO , "Error : G72x encoding does not support more than 1 channel." }, { SFE_MAX_ERROR , "Maximum error number." }, { SFE_MAX_ERROR + 1 , NULL } } ; /*------------------------------------------------------------------------------ */ static int format_from_extension (SF_PRIVATE *psf) ; static int guess_file_type (SF_PRIVATE *psf) ; static int validate_sfinfo (SF_INFO *sfinfo) ; static int validate_psf (SF_PRIVATE *psf) ; static void save_header_info (SF_PRIVATE *psf) ; static void copy_filename (SF_PRIVATE *psf, const char *path) ; static int psf_close (SF_PRIVATE *psf) ; static int psf_open_file (SF_PRIVATE *psf, int mode, SF_INFO *sfinfo) ; static int try_resource_fork (SF_PRIVATE * psf, int mode) ; /*------------------------------------------------------------------------------ ** Private (static) variables. */ static int sf_errno = 0 ; static char sf_logbuffer [SF_BUFFER_LEN] = { 0 } ; static char sf_syserr [SF_SYSERR_LEN] = { 0 } ; /*------------------------------------------------------------------------------ */ #define VALIDATE_SNDFILE_AND_ASSIGN_PSF(a,b,c) \ { if ((a) == NULL) \ { sf_errno = SFE_BAD_SNDFILE_PTR ; \ return 0 ; \ } ; \ (b) = (SF_PRIVATE*) (a) ; \ if ((b)->virtual_io == SF_FALSE && \ psf_file_valid (b) == 0) \ { (b)->error = SFE_BAD_FILE_PTR ; \ return 0 ; \ } ; \ if ((b)->Magick != SNDFILE_MAGICK) \ { (b)->error = SFE_BAD_SNDFILE_PTR ; \ return 0 ; \ } ; \ if (c) (b)->error = 0 ; \ } /*------------------------------------------------------------------------------ ** Public functions. */ SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) { SF_PRIVATE *psf ; int error = 0 ; if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL) { sf_errno = SFE_MALLOC_FAILED ; return NULL ; } ; memset (psf, 0, sizeof (SF_PRIVATE)) ; psf_init_files (psf) ; psf_log_printf (psf, "File : %s\n", path) ; copy_filename (psf, path) ; if (strcmp (path, "-") == 0) error = psf_set_stdio (psf, mode) ; else error = psf_fopen (psf, path, mode) ; if (error == 0) error = psf_open_file (psf, mode, sfinfo) ; if (error) { sf_errno = error ; if (error == SFE_SYSTEM) LSF_SNPRINTF (sf_syserr, sizeof (sf_syserr), "%s", psf->syserr) ; LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "%s", psf->logbuffer) ; psf_close (psf) ; return NULL ; } ; memcpy (sfinfo, &(psf->sf), sizeof (SF_INFO)) ; return (SNDFILE*) psf ; } /* sf_open */ SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) { SF_PRIVATE *psf ; int error ; if ((sfinfo->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_SD2) { sf_errno = SFE_SD2_FD_DISALLOWED ; return NULL ; } ; if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL) { sf_errno = SFE_MALLOC_FAILED ; return NULL ; } ; psf_init_files (psf) ; psf_set_file (psf, fd) ; psf->is_pipe = psf_is_pipe (psf) ; psf->fileoffset = psf_ftell (psf) ; if (! close_desc) psf->do_not_close_descriptor = SF_TRUE ; error = psf_open_file (psf, mode, sfinfo) ; if (error) { sf_errno = error ; if (error == SFE_SYSTEM) LSF_SNPRINTF (sf_syserr, sizeof (sf_syserr), "%s", psf->syserr) ; LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "%s", psf->logbuffer) ; psf_close (psf) ; return NULL ; } ; memcpy (sfinfo, &(psf->sf), sizeof (SF_INFO)) ; return (SNDFILE*) psf ; } /* sf_open_fd */ SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) { SF_PRIVATE *psf ; int error = 0 ; /* Make sure we have a valid set ot virtual pointers. */ if (sfvirtual->get_filelen == NULL || sfvirtual->seek == NULL || sfvirtual->tell == NULL) { sf_errno = SFE_BAD_VIRTUAL_IO ; LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "Bad vio_get_filelen / vio_seek / vio_tell in SF_VIRTUAL_IO struct.\n") ; return NULL ; } ; if ((mode == SFM_READ || mode == SFM_RDWR) && sfvirtual->read == NULL) { sf_errno = SFE_BAD_VIRTUAL_IO ; LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "Bad vio_read in SF_VIRTUAL_IO struct.\n") ; return NULL ; } ; if ((mode == SFM_WRITE || mode == SFM_RDWR) && sfvirtual->write == NULL) { sf_errno = SFE_BAD_VIRTUAL_IO ; LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "Bad vio_write in SF_VIRTUAL_IO struct.\n") ; return NULL ; } ; if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL) { sf_errno = SFE_MALLOC_FAILED ; return NULL ; } ; psf_init_files (psf) ; psf->virtual_io = SF_TRUE ; psf->vio = *sfvirtual ; psf->vio_user_data = user_data ; psf->mode = mode ; error = psf_open_file (psf, mode, sfinfo) ; if (error) { sf_errno = error ; if (error == SFE_SYSTEM) LSF_SNPRINTF (sf_syserr, sizeof (sf_syserr), "%s", psf->syserr) ; LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "%s", psf->logbuffer) ; psf_close (psf) ; return NULL ; } ; memcpy (sfinfo, &(psf->sf), sizeof (SF_INFO)) ; return (SNDFILE*) psf ; } /* sf_open_virtual */ int sf_close (SNDFILE *sndfile) { SF_PRIVATE *psf ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; return psf_close (psf) ; } /* sf_close */ void sf_write_sync (SNDFILE *sndfile) { SF_PRIVATE *psf ; if ((psf = (SF_PRIVATE *) sndfile) == NULL) return ; psf_fsync (psf) ; return ; } /* sf_write_sync */ /*============================================================================== */ const char* sf_error_number (int errnum) { static const char *bad_errnum = "No error defined for this error number. This is a bug in libsndfile." ; int k ; if (errnum == SFE_MAX_ERROR) return SndfileErrors [0].str ; if (errnum < 0 || errnum > SFE_MAX_ERROR) { /* This really shouldn't happen in release versions. */ printf ("Not a valid error number (%d).\n", errnum) ; return bad_errnum ; } ; for (k = 0 ; SndfileErrors [k].str ; k++) if (errnum == SndfileErrors [k].error) return SndfileErrors [k].str ; return bad_errnum ; } /* sf_error_number */ const char* sf_strerror (SNDFILE *sndfile) { SF_PRIVATE *psf = NULL ; int errnum ; if (sndfile == NULL) { errnum = sf_errno ; if (errnum == SFE_SYSTEM && sf_syserr [0]) return sf_syserr ; } else { psf = (SF_PRIVATE *) sndfile ; if (psf->Magick != SNDFILE_MAGICK) return "sf_strerror : Bad magic number." ; errnum = psf->error ; if (errnum == SFE_SYSTEM && psf->syserr [0]) return psf->syserr ; } ; return sf_error_number (errnum) ; } /* sf_strerror */ /*------------------------------------------------------------------------------ */ int sf_error (SNDFILE *sndfile) { SF_PRIVATE *psf ; if (sndfile == NULL) { if (sf_error != 0) return sf_errno ; return 0 ; } ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 0) ; if (psf->error) return psf->error ; return 0 ; } /* sf_error */ /*------------------------------------------------------------------------------ */ int sf_perror (SNDFILE *sndfile) { SF_PRIVATE *psf ; int errnum ; if (sndfile == NULL) { errnum = sf_errno ; } else { VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 0) ; errnum = psf->error ; } ; fprintf (stderr, "%s\n", sf_error_number (errnum)) ; return SFE_NO_ERROR ; } /* sf_perror */ /*------------------------------------------------------------------------------ */ int sf_error_str (SNDFILE *sndfile, char *str, size_t maxlen) { SF_PRIVATE *psf ; int errnum ; if (str == NULL) return SFE_INTERNAL ; if (sndfile == NULL) errnum = sf_errno ; else { VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 0) ; errnum = psf->error ; } ; LSF_SNPRINTF (str, maxlen, "%s", sf_error_number (errnum)) ; return SFE_NO_ERROR ; } /* sf_error_str */ /*============================================================================== */ int sf_format_check (const SF_INFO *info) { int subformat, endian ; subformat = info->format & SF_FORMAT_SUBMASK ; endian = info->format & SF_FORMAT_ENDMASK ; /* This is the place where each file format can check if the suppiled ** SF_INFO struct is valid. ** Return 0 on failure, 1 ons success. */ if (info->channels < 1 || info->channels > 256) return 0 ; if (info->samplerate < 0) return 0 ; switch (info->format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : case SF_FORMAT_WAVEX : /* WAV now allows both endian, RIFF or RIFX (little or big respectively) */ if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if ((subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) && info->channels <= 2) return 1 ; if (subformat == SF_FORMAT_GSM610 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_G721_32 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; break ; case SF_FORMAT_AIFF : /* AIFF does allow both endian-nesses for PCM data.*/ if (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; /* Other encodings. Check for endian-ness. */ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) return 0 ; if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_S8) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; if ((subformat == SF_FORMAT_DWVW_12 || subformat == SF_FORMAT_DWVW_16 || subformat == SF_FORMAT_DWVW_24) && info-> channels == 1) return 1 ; if (subformat == SF_FORMAT_GSM610 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_IMA_ADPCM && (info->channels == 1 || info->channels == 2)) return 1 ; break ; case SF_FORMAT_AU : if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; if (subformat == SF_FORMAT_G721_32 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_G723_24 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_G723_40 && info->channels == 1) return 1 ; break ; case SF_FORMAT_CAF : if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; break ; case SF_FORMAT_RAW : if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; if (subformat == SF_FORMAT_ALAW || subformat == SF_FORMAT_ULAW) return 1 ; if ((subformat == SF_FORMAT_DWVW_12 || subformat == SF_FORMAT_DWVW_16 || subformat == SF_FORMAT_DWVW_24) && info-> channels == 1) return 1 ; if (subformat == SF_FORMAT_GSM610 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_VOX_ADPCM && info->channels == 1) return 1 ; break ; case SF_FORMAT_PAF : if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; break ; case SF_FORMAT_SVX : /* SVX currently does not support more than one channel for write. ** Read will allow more than one channel but only allow one here. */ if (info->channels != 1) return 0 ; /* Always big endian. */ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) return 0 ; if ((subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) && info->channels == 1) return 1 ; break ; case SF_FORMAT_NIST : if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; break ; case SF_FORMAT_IRCAM : if (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW || subformat == SF_FORMAT_FLOAT) return 1 ; break ; case SF_FORMAT_VOC : /* VOC is strictly little endian. */ if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) return 0 ; if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; break ; case SF_FORMAT_W64 : /* W64 is strictly little endian. */ if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) return 0 ; if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) return 1 ; if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) return 1 ; if ((subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) && info->channels <= 2) return 1 ; if (subformat == SF_FORMAT_GSM610 && info->channels == 1) return 1 ; if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; break ; case SF_FORMAT_MAT4 : if (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; break ; case SF_FORMAT_MAT5 : if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) return 1 ; if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) return 1 ; break ; case SF_FORMAT_PVF : if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) return 1 ; break ; case SF_FORMAT_XI : if (info->channels != 1) return 0 ; if (subformat == SF_FORMAT_DPCM_8 || subformat == SF_FORMAT_DPCM_16) return 1 ; break ; case SF_FORMAT_HTK : /* HTK is strictly big endian. */ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) return 0 ; if (info->channels != 1) return 0 ; if (subformat == SF_FORMAT_PCM_16) return 1 ; break ; case SF_FORMAT_SDS : /* SDS is strictly big endian. */ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) return 0 ; if (info->channels != 1) return 0 ; if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24) return 1 ; break ; case SF_FORMAT_AVR : /* SDS is strictly big endian. */ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) return 0 ; if (info->channels > 2) return 0 ; if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) return 1 ; break ; case SF_FORMAT_FLAC : /* FLAC can't do more than 8 channels. */ if (info->channels > 8) return 0 ; if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24) return 1 ; break ; case SF_FORMAT_SD2 : /* SD2 is strictly big endian. */ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) return 0 ; if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24) return 1 ; break ; default : break ; } ; return 0 ; } /* sf_format_check */ /*------------------------------------------------------------------------------ */ int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) { SF_PRIVATE *psf = NULL ; int old_value ; /* This set of commands do not need the sndfile parameter. */ switch (command) { case SFC_GET_LIB_VERSION : if (data == NULL) return (psf->error = SFE_BAD_CONTROL_CMD) ; if (ENABLE_EXPERIMENTAL_CODE) LSF_SNPRINTF (data, datasize, "%s-%s-exp", PACKAGE_NAME, PACKAGE_VERSION) ; else LSF_SNPRINTF (data, datasize, "%s-%s", PACKAGE_NAME, PACKAGE_VERSION) ; return strlen (data) ; case SFC_GET_SIMPLE_FORMAT_COUNT : if (data == NULL || datasize != SIGNED_SIZEOF (int)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; *((int*) data) = psf_get_format_simple_count () ; return 0 ; case SFC_GET_SIMPLE_FORMAT : if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; return psf_get_format_simple (data) ; case SFC_GET_FORMAT_MAJOR_COUNT : if (data == NULL || datasize != SIGNED_SIZEOF (int)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; *((int*) data) = psf_get_format_major_count () ; return 0 ; case SFC_GET_FORMAT_MAJOR : if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; return psf_get_format_major (data) ; case SFC_GET_FORMAT_SUBTYPE_COUNT : if (data == NULL || datasize != SIGNED_SIZEOF (int)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; *((int*) data) = psf_get_format_subtype_count () ; return 0 ; case SFC_GET_FORMAT_SUBTYPE : if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; return psf_get_format_subtype (data) ; case SFC_GET_FORMAT_INFO : if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) return (sf_errno = SFE_BAD_CONTROL_CMD) ; return psf_get_format_info (data) ; } ; if (sndfile == NULL && command == SFC_GET_LOG_INFO) { if (data == NULL) return (psf->error = SFE_BAD_CONTROL_CMD) ; LSF_SNPRINTF (data, datasize, "%s", sf_logbuffer) ; return strlen (data) ; } ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; switch (command) { case SFC_SET_NORM_FLOAT : old_value = psf->norm_float ; psf->norm_float = (datasize) ? SF_TRUE : SF_FALSE ; return old_value ; case SFC_SET_NORM_DOUBLE : old_value = psf->norm_double ; psf->norm_double = (datasize) ? SF_TRUE : SF_FALSE ; return old_value ; case SFC_GET_NORM_FLOAT : return psf->norm_float ; case SFC_GET_NORM_DOUBLE : return psf->norm_double ; case SFC_SET_SCALE_FLOAT_INT_READ : old_value = psf->float_int_mult ; psf->float_int_mult = (datasize != 0) ? SF_TRUE : SF_FALSE ; if (psf->float_int_mult && psf->float_max < 0.0) psf->float_max = psf_calc_signal_max (psf, SF_FALSE) ; return old_value ; case SFC_SET_ADD_PEAK_CHUNK : { int format = psf->sf.format & SF_FORMAT_TYPEMASK ; /* Only WAV and AIFF support the PEAK chunk. */ if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX && format != SF_FORMAT_AIFF) return SF_FALSE ; format = psf->sf.format & SF_FORMAT_SUBMASK ; /* Only files containg the following data types support the PEAK chunk. */ if (format != SF_FORMAT_FLOAT && format != SF_FORMAT_DOUBLE) return SF_FALSE ; } ; /* Can only do this is in SFM_WRITE mode. */ if (psf->mode != SFM_WRITE) return SF_FALSE ; /* If data has already been written this must fail. */ if (psf->have_written) return SF_FALSE ; /* Everything seems OK, so set psf->has_peak and re-write header. */ if (datasize == SF_FALSE && psf->peak_info != NULL) { free (psf->peak_info) ; psf->peak_info = NULL ; } else if (psf->peak_info == NULL) { psf->peak_info = peak_info_calloc (psf->sf.channels) ; psf->peak_info->peak_loc = SF_PEAK_START ; } ; if (psf->write_header) psf->write_header (psf, SF_TRUE) ; return datasize ; case SFC_GET_LOG_INFO : if (data == NULL) return (psf->error = SFE_BAD_CONTROL_CMD) ; LSF_SNPRINTF (data, datasize, "%s", psf->logbuffer) ; break ; case SFC_CALC_SIGNAL_MAX : if (data == NULL || datasize != sizeof (double)) return (psf->error = SFE_BAD_CONTROL_CMD) ; *((double*) data) = psf_calc_signal_max (psf, SF_FALSE) ; break ; case SFC_CALC_NORM_SIGNAL_MAX : if (data == NULL || datasize != sizeof (double)) return (psf->error = SFE_BAD_CONTROL_CMD) ; *((double*) data) = psf_calc_signal_max (psf, SF_TRUE) ; break ; case SFC_CALC_MAX_ALL_CHANNELS : if (data == NULL || datasize != SIGNED_SIZEOF (double) * psf->sf.channels) return (psf->error = SFE_BAD_CONTROL_CMD) ; return psf_calc_max_all_channels (psf, (double*) data, SF_FALSE) ; case SFC_CALC_NORM_MAX_ALL_CHANNELS : if (data == NULL || datasize != SIGNED_SIZEOF (double) * psf->sf.channels) return (psf->error = SFE_BAD_CONTROL_CMD) ; return psf_calc_max_all_channels (psf, (double*) data, SF_TRUE) ; case SFC_GET_SIGNAL_MAX : if (data == NULL || datasize != sizeof (double)) { psf->error = SFE_BAD_CONTROL_CMD ; return SF_FALSE ; } ; return psf_get_signal_max (psf, (double *) data) ; case SFC_GET_MAX_ALL_CHANNELS : if (data == NULL || datasize != SIGNED_SIZEOF (double) * psf->sf.channels) { psf->error = SFE_BAD_CONTROL_CMD ; return SF_FALSE ; } ; return psf_get_max_all_channels (psf, (double*) data) ; case SFC_UPDATE_HEADER_NOW : if (psf->write_header) psf->write_header (psf, SF_TRUE) ; break ; case SFC_SET_UPDATE_HEADER_AUTO : psf->auto_header = datasize ? SF_TRUE : SF_FALSE ; return psf->auto_header ; break ; case SFC_SET_ADD_DITHER_ON_WRITE : case SFC_SET_ADD_DITHER_ON_READ : /* ** FIXME ! ** These are obsolete. Just return. ** Remove some time after version 1.0.8. */ break ; case SFC_SET_DITHER_ON_WRITE : if (data == NULL || datasize != SIGNED_SIZEOF (SF_DITHER_INFO)) return (psf->error = SFE_BAD_CONTROL_CMD) ; memcpy (&psf->write_dither, data, sizeof (psf->write_dither)) ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) dither_init (psf, SFM_WRITE) ; break ; case SFC_SET_DITHER_ON_READ : if (data == NULL || datasize != SIGNED_SIZEOF (SF_DITHER_INFO)) return (psf->error = SFE_BAD_CONTROL_CMD) ; memcpy (&psf->read_dither, data, sizeof (psf->read_dither)) ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) dither_init (psf, SFM_READ) ; break ; case SFC_FILE_TRUNCATE : if (psf->mode != SFM_WRITE && psf->mode != SFM_RDWR) return SF_TRUE ; if (datasize != sizeof (sf_count_t)) return SF_TRUE ; { sf_count_t position ; position = *((sf_count_t*) data) ; if (sf_seek (sndfile, position, SEEK_SET) != position) return SF_TRUE ; psf->sf.frames = position ; position = psf_fseek (psf, 0, SEEK_CUR) ; return psf_ftruncate (psf, position) ; } ; break ; case SFC_SET_RAW_START_OFFSET : if (data == NULL || datasize != sizeof (sf_count_t)) return (psf->error = SFE_BAD_CONTROL_CMD) ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) return (psf->error = SFE_BAD_CONTROL_CMD) ; psf->dataoffset = *((sf_count_t*) data) ; sf_seek (sndfile, 0, SEEK_CUR) ; break ; case SFC_GET_EMBED_FILE_INFO : if (data == NULL || datasize != sizeof (SF_EMBED_FILE_INFO)) return (psf->error = SFE_BAD_CONTROL_CMD) ; ((SF_EMBED_FILE_INFO*) data)->offset = psf->fileoffset ; ((SF_EMBED_FILE_INFO*) data)->length = psf->filelength ; break ; /* Lite remove start */ case SFC_TEST_IEEE_FLOAT_REPLACE : psf->ieee_replace = (datasize) ? SF_TRUE : SF_FALSE ; if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) float32_init (psf) ; else if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE) double64_init (psf) ; else return (psf->error = SFE_BAD_CONTROL_CMD) ; break ; /* Lite remove end */ case SFC_SET_CLIPPING : psf->add_clipping = (datasize) ? SF_TRUE : SF_FALSE ; return psf->add_clipping ; case SFC_GET_CLIPPING : return psf->add_clipping ; case SFC_GET_LOOP_INFO : if (datasize != sizeof (SF_LOOP_INFO) || data == NULL) return SF_FALSE ; if (psf->loop_info == NULL) return SF_FALSE ; memcpy (data, psf->loop_info, sizeof (SF_LOOP_INFO)) ; return SF_TRUE ; case SFC_SET_BROADCAST_INFO : { int format = psf->sf.format & SF_FORMAT_TYPEMASK ; /* Only WAV supports the BEXT (Broadcast) chunk. */ if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX) return SF_FALSE ; } ; /* Can only do this is in SFM_WRITE mode. */ if (psf->mode != SFM_WRITE) return SF_FALSE ; /* If data has already been written this must fail. */ if (psf->have_written) return SF_FALSE ; if (psf->broadcast_info == NULL) psf->broadcast_info = broadcast_info_alloc () ; broadcast_info_copy (psf->broadcast_info, data) ; broadcast_add_coding_history (psf->broadcast_info, psf->sf.channels, psf->sf.samplerate) ; if (psf->write_header) psf->write_header (psf, SF_TRUE) ; return SF_TRUE ; case SFC_GET_BROADCAST_INFO : if (datasize != sizeof (SF_BROADCAST_INFO) || data == NULL) return SF_FALSE ; if (psf->broadcast_info == NULL) return SF_FALSE ; return broadcast_info_copy (data, psf->broadcast_info) ; case SFC_GET_INSTRUMENT : if (datasize != sizeof (SF_INSTRUMENT) || data == NULL) return SF_FALSE ; if (psf->instrument == NULL) return SF_FALSE ; memcpy (data, psf->instrument, sizeof (SF_INSTRUMENT)) ; return SF_TRUE ; case SFC_SET_INSTRUMENT : /* If data has already been written this must fail. */ if (psf->have_written) return SF_FALSE ; if (datasize != sizeof (SF_INSTRUMENT) || data == NULL) return SF_FALSE ; if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) { psf->error = SFE_MALLOC_FAILED ; return SF_FALSE ; } ; memcpy (psf->instrument, data, sizeof (SF_INSTRUMENT)) ; return SF_TRUE ; default : /* Must be a file specific command. Pass it on. */ if (psf->command) return psf->command (psf, command, data, datasize) ; psf_log_printf (psf, "*** sf_command : cmd = 0x%X\n", command) ; return (psf->error = SFE_BAD_CONTROL_CMD) ; } ; return 0 ; } /* sf_command */ /*------------------------------------------------------------------------------ */ sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t offset, int whence) { SF_PRIVATE *psf ; sf_count_t seek_from_start = 0, retval ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (! psf->sf.seekable) { psf->error = SFE_NOT_SEEKABLE ; return PSF_SEEK_ERROR ; } ; /* If the whence parameter has a mode ORed in, check to see that ** it makes sense. */ if (((whence & SFM_MASK) == SFM_WRITE && psf->mode == SFM_READ) || ((whence & SFM_MASK) == SFM_READ && psf->mode == SFM_WRITE)) { psf->error = SFE_WRONG_SEEK ; return PSF_SEEK_ERROR ; } ; /* Convert all SEEK_CUR and SEEK_END into seek_from_start to be ** used with SEEK_SET. */ switch (whence) { /* The SEEK_SET behaviour is independant of mode. */ case SEEK_SET : case SEEK_SET | SFM_READ : case SEEK_SET | SFM_WRITE : case SEEK_SET | SFM_RDWR : seek_from_start = offset ; break ; /* The SEEK_CUR is a little more tricky. */ case SEEK_CUR : if (offset == 0) { if (psf->mode == SFM_READ) return psf->read_current ; if (psf->mode == SFM_WRITE) return psf->write_current ; } ; if (psf->mode == SFM_READ) seek_from_start = psf->read_current + offset ; else if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) seek_from_start = psf->write_current + offset ; else psf->error = SFE_AMBIGUOUS_SEEK ; break ; case SEEK_CUR | SFM_READ : if (offset == 0) return psf->read_current ; seek_from_start = psf->read_current + offset ; break ; case SEEK_CUR | SFM_WRITE : if (offset == 0) return psf->write_current ; seek_from_start = psf->write_current + offset ; break ; /* The SEEK_END */ case SEEK_END : case SEEK_END | SFM_READ : case SEEK_END | SFM_WRITE : seek_from_start = psf->sf.frames + offset ; break ; default : psf->error = SFE_BAD_SEEK ; break ; } ; if (psf->error) return PSF_SEEK_ERROR ; if (seek_from_start < 0 || seek_from_start > psf->sf.frames) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (psf->seek) { int new_mode = (whence & SFM_MASK) ? (whence & SFM_MASK) : psf->mode ; retval = psf->seek (psf, new_mode, seek_from_start) ; switch (new_mode) { case SFM_READ : psf->read_current = retval ; break ; case SFM_WRITE : psf->write_current = retval ; break ; case SFM_RDWR : psf->read_current = retval ; psf->write_current = retval ; new_mode = SFM_READ ; break ; } ; psf->last_op = new_mode ; return retval ; } ; psf->error = SFE_AMBIGUOUS_SEEK ; return PSF_SEEK_ERROR ; } /* sf_seek */ /*------------------------------------------------------------------------------ */ const char* sf_get_string (SNDFILE *sndfile, int str_type) { SF_PRIVATE *psf ; if ((psf = (SF_PRIVATE*) sndfile) == NULL) return NULL ; if (psf->Magick != SNDFILE_MAGICK) return NULL ; return psf_get_string (psf, str_type) ; } /* sf_get_string */ int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) { SF_PRIVATE *psf ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; return psf_set_string (psf, str_type, str) ; } /* sf_get_string */ /*============================================================================== */ sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) { SF_PRIVATE *psf ; sf_count_t count ; int bytewidth, blockwidth ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; bytewidth = (psf->bytewidth > 0) ? psf->bytewidth : 1 ; blockwidth = (psf->blockwidth > 0) ? psf->blockwidth : 1 ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (bytes < 0 || psf->read_current >= psf->datalength) { psf_memset (ptr, 0, bytes) ; return 0 ; } ; if (bytes % (psf->sf.channels * bytewidth)) { psf->error = SFE_BAD_READ_ALIGN ; return 0 ; } ; count = psf_fread (ptr, 1, bytes, psf) ; if (count < bytes) psf_memset (((char*) ptr) + count, 0, bytes - count) ; psf->read_current += count / blockwidth ; psf->last_op = SFM_READ ; return count ; } /* sf_read_raw */ /*------------------------------------------------------------------------------ */ sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_READ_ALIGN ; return 0 ; } ; if (len <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, len * sizeof (short)) ; return 0 ; /* End of file. */ } ; if (psf->read_short == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_short (psf, ptr, len) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = len - count ; psf_memset (ptr + count, 0, extra * sizeof (short)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count ; } /* sf_read_short */ sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (frames <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (short)) ; return 0 ; /* End of file. */ } ; if (psf->read_short == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_short (psf, ptr, frames * psf->sf.channels) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = frames * psf->sf.channels - count ; psf_memset (ptr + count, 0, extra * sizeof (short)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count / psf->sf.channels ; } /* sf_readf_short */ /*------------------------------------------------------------------------------ */ sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_READ_ALIGN ; return 0 ; } ; if (len <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, len * sizeof (int)) ; return 0 ; } ; if (psf->read_int == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_int (psf, ptr, len) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = len - count ; psf_memset (ptr + count, 0, extra * sizeof (int)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count ; } /* sf_read_int */ sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (frames <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (int)) ; return 0 ; } ; if (psf->read_int == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_int (psf, ptr, frames * psf->sf.channels) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = frames * psf->sf.channels - count ; psf_memset (ptr + count, 0, extra * sizeof (int)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count / psf->sf.channels ; } /* sf_readf_int */ /*------------------------------------------------------------------------------ */ sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_READ_ALIGN ; return 0 ; } ; if (len <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, len * sizeof (float)) ; return 0 ; } ; if (psf->read_float == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_float (psf, ptr, len) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = len - count ; psf_memset (ptr + count, 0, extra * sizeof (float)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count ; } /* sf_read_float */ sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (frames <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (float)) ; return 0 ; } ; if (psf->read_float == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_float (psf, ptr, frames * psf->sf.channels) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = frames * psf->sf.channels - count ; psf_memset (ptr + count, 0, extra * sizeof (float)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count / psf->sf.channels ; } /* sf_readf_float */ /*------------------------------------------------------------------------------ */ sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_READ_ALIGN ; return 0 ; } ; if (len <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, len * sizeof (double)) ; return 0 ; } ; if (psf->read_double == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_double (psf, ptr, len) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = len - count ; psf_memset (ptr + count, 0, extra * sizeof (double)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count ; } /* sf_read_double */ sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count, extra ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_WRITE) { psf->error = SFE_NOT_READMODE ; return 0 ; } ; if (frames <= 0 || psf->read_current >= psf->sf.frames) { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (double)) ; return 0 ; } ; if (psf->read_double == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_READ) if (psf->seek (psf, SFM_READ, psf->read_current) < 0) return 0 ; count = psf->read_double (psf, ptr, frames * psf->sf.channels) ; if (psf->read_current + count / psf->sf.channels > psf->sf.frames) { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; extra = frames * psf->sf.channels - count ; psf_memset (ptr + count, 0, extra * sizeof (double)) ; psf->read_current = psf->sf.frames ; } ; psf->read_current += count / psf->sf.channels ; psf->last_op = SFM_READ ; if (psf->read_current > psf->sf.frames) { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ; psf->read_current = psf->sf.frames ; } ; return count / psf->sf.channels ; } /* sf_readf_double */ /*------------------------------------------------------------------------------ */ sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count ; int bytewidth, blockwidth ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; bytewidth = (psf->bytewidth > 0) ? psf->bytewidth : 1 ; blockwidth = (psf->blockwidth > 0) ? psf->blockwidth : 1 ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (len % (psf->sf.channels * bytewidth)) { psf->error = SFE_BAD_WRITE_ALIGN ; return 0 ; } ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf_fwrite (ptr, 1, len, psf) ; psf->write_current += count / blockwidth ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; psf->last_op = SFM_WRITE ; return count ; } /* sf_write_raw */ /*------------------------------------------------------------------------------ */ sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_WRITE_ALIGN ; return 0 ; } ; if (psf->write_short == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_short (psf, ptr, len) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count ; } /* sf_write_short */ sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (psf->write_short == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_short (psf, ptr, frames * psf->sf.channels) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count / psf->sf.channels ; } /* sf_writef_short */ /*------------------------------------------------------------------------------ */ sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_WRITE_ALIGN ; return 0 ; } ; if (psf->write_int == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_int (psf, ptr, len) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count ; } /* sf_write_int */ sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (psf->write_int == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_int (psf, ptr, frames * psf->sf.channels) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count / psf->sf.channels ; } /* sf_writef_int */ /*------------------------------------------------------------------------------ */ sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_WRITE_ALIGN ; return 0 ; } ; if (psf->write_float == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_float (psf, ptr, len) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count ; } /* sf_write_float */ sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (psf->write_float == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_float (psf, ptr, frames * psf->sf.channels) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count / psf->sf.channels ; } /* sf_writef_float */ /*------------------------------------------------------------------------------ */ sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t len) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (len % psf->sf.channels) { psf->error = SFE_BAD_WRITE_ALIGN ; return 0 ; } ; if (psf->write_double == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_double (psf, ptr, len) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count ; } /* sf_write_double */ sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) { SF_PRIVATE *psf ; sf_count_t count ; VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; if (psf->mode == SFM_READ) { psf->error = SFE_NOT_WRITEMODE ; return 0 ; } ; if (psf->write_double == NULL || psf->seek == NULL) { psf->error = SFE_UNIMPLEMENTED ; return 0 ; } ; if (psf->last_op != SFM_WRITE) if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) return 0 ; if (psf->have_written == SF_FALSE && psf->write_header != NULL) psf->write_header (psf, SF_FALSE) ; psf->have_written = SF_TRUE ; count = psf->write_double (psf, ptr, frames * psf->sf.channels) ; psf->write_current += count / psf->sf.channels ; psf->last_op = SFM_WRITE ; if (psf->auto_header && psf->write_header != NULL) psf->write_header (psf, SF_TRUE) ; if (psf->write_current > psf->sf.frames) psf->sf.frames = psf->write_current ; return count / psf->sf.channels ; } /* sf_writef_double */ /*========================================================================= ** Private functions. */ static int try_resource_fork (SF_PRIVATE * psf, int mode) { if (psf_open_rsrc (psf, mode) != 0) return 0 ; /* More checking here. */ psf_log_printf (psf, "Resource fork : %s\n", psf->rsrcpath) ; return SF_FORMAT_SD2 ; } /* try_resource_fork */ static int format_from_extension (SF_PRIVATE *psf) { char *cptr ; char buffer [16] ; int format = 0 ; if (psf->filename == NULL) return 0 ; if ((cptr = strrchr (psf->filename, '.')) == NULL) return 0 ; cptr ++ ; if (strlen (cptr) > sizeof (buffer) - 1) return 0 ; strncpy (buffer, cptr, sizeof (buffer)) ; buffer [sizeof (buffer) - 1] = 0 ; /* Convert everything in the buffer to lower case. */ cptr = buffer ; while (*cptr) { *cptr = tolower (*cptr) ; cptr ++ ; } ; cptr = buffer ; if (strcmp (cptr, "au") == 0) { psf->sf.channels = 1 ; psf->sf.samplerate = 8000 ; format = SF_FORMAT_RAW | SF_FORMAT_ULAW ; } else if (strcmp (cptr, "snd") == 0) { psf->sf.channels = 1 ; psf->sf.samplerate = 8000 ; format = SF_FORMAT_RAW | SF_FORMAT_ULAW ; } else if (strcmp (cptr, "vox") == 0) { psf->sf.channels = 1 ; psf->sf.samplerate = 8000 ; format = SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM ; } else if (strcmp (cptr, "gsm") == 0) { psf->sf.channels = 1 ; psf->sf.samplerate = 8000 ; format = SF_FORMAT_RAW | SF_FORMAT_GSM610 ; } /* For RAW files, make sure the dataoffset if set correctly. */ if ((format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW) psf->dataoffset = 0 ; return format ; } /* format_from_extension */ static int guess_file_type (SF_PRIVATE *psf) { int buffer [3], format ; if (psf_binheader_readf (psf, "b", &buffer, SIGNED_SIZEOF (buffer)) != SIGNED_SIZEOF (buffer)) { psf->error = SFE_BAD_FILE_READ ; return 0 ; } ; if ((buffer [0] == MAKE_MARKER ('R', 'I', 'F', 'F') || buffer [0] == MAKE_MARKER ('R', 'I', 'F', 'X')) && buffer [2] == MAKE_MARKER ('W', 'A', 'V', 'E')) return SF_FORMAT_WAV ; if (buffer [0] == MAKE_MARKER ('F', 'O', 'R', 'M')) { if (buffer [2] == MAKE_MARKER ('A', 'I', 'F', 'F') || buffer [2] == MAKE_MARKER ('A', 'I', 'F', 'C')) return SF_FORMAT_AIFF ; if (buffer [2] == MAKE_MARKER ('8', 'S', 'V', 'X') || buffer [2] == MAKE_MARKER ('1', '6', 'S', 'V')) return SF_FORMAT_SVX ; return 0 ; } ; if (buffer [0] == MAKE_MARKER ('.', 's', 'n', 'd') || buffer [0] == MAKE_MARKER ('d', 'n', 's', '.')) return SF_FORMAT_AU ; if ((buffer [0] == MAKE_MARKER ('f', 'a', 'p', ' ') || buffer [0] == MAKE_MARKER (' ', 'p', 'a', 'f'))) return SF_FORMAT_PAF ; if (buffer [0] == MAKE_MARKER ('N', 'I', 'S', 'T')) return SF_FORMAT_NIST ; if (buffer [0] == MAKE_MARKER ('C', 'r', 'e', 'a') && buffer [1] == MAKE_MARKER ('t', 'i', 'v', 'e')) return SF_FORMAT_VOC ; if ((buffer [0] & MAKE_MARKER (0xFF, 0xFF, 0xF8, 0xFF)) == MAKE_MARKER (0x64, 0xA3, 0x00, 0x00) || (buffer [0] & MAKE_MARKER (0xFF, 0xF8, 0xFF, 0xFF)) == MAKE_MARKER (0x00, 0x00, 0xA3, 0x64)) return SF_FORMAT_IRCAM ; if (buffer [0] == MAKE_MARKER ('r', 'i', 'f', 'f')) return SF_FORMAT_W64 ; if (buffer [0] == MAKE_MARKER (0, 0, 0x03, 0xE8) && buffer [1] == MAKE_MARKER (0, 0, 0, 1) && buffer [2] == MAKE_MARKER (0, 0, 0, 1)) return SF_FORMAT_MAT4 ; if (buffer [0] == MAKE_MARKER (0, 0, 0, 0) && buffer [1] == MAKE_MARKER (1, 0, 0, 0) && buffer [2] == MAKE_MARKER (1, 0, 0, 0)) return SF_FORMAT_MAT4 ; if (buffer [0] == MAKE_MARKER ('M', 'A', 'T', 'L') && buffer [1] == MAKE_MARKER ('A', 'B', ' ', '5')) return SF_FORMAT_MAT5 ; if (buffer [0] == MAKE_MARKER ('P', 'V', 'F', '1')) return SF_FORMAT_PVF ; if (buffer [0] == MAKE_MARKER ('E', 'x', 't', 'e') && buffer [1] == MAKE_MARKER ('n', 'd', 'e', 'd') && buffer [2] == MAKE_MARKER (' ', 'I', 'n', 's')) return SF_FORMAT_XI ; if (buffer [0] == MAKE_MARKER ('c', 'a', 'f', 'f') && buffer [2] == MAKE_MARKER ('d', 'e', 's', 'c')) return SF_FORMAT_CAF ; if (ENABLE_EXPERIMENTAL_CODE && buffer [0] == MAKE_MARKER ('O', 'g', 'g', 'S')) return SF_FORMAT_OGG ; if (buffer [0] == MAKE_MARKER ('A', 'L', 'a', 'w') && buffer [1] == MAKE_MARKER ('S', 'o', 'u', 'n') && buffer [2] == MAKE_MARKER ('d', 'F', 'i', 'l')) return SF_FORMAT_WVE ; if (buffer [0] == MAKE_MARKER ('D', 'i', 'a', 'm') && buffer [1] == MAKE_MARKER ('o', 'n', 'd', 'W') && buffer [2] == MAKE_MARKER ('a', 'r', 'e', ' ')) return SF_FORMAT_DWD ; if (buffer [0] == MAKE_MARKER ('L', 'M', '8', '9') || buffer [0] == MAKE_MARKER ('5', '3', 0, 0)) return SF_FORMAT_TXW ; if ((buffer [0] & MAKE_MARKER (0xFF, 0xFF, 0x80, 0xFF)) == MAKE_MARKER (0xF0, 0x7E, 0, 0x01)) return SF_FORMAT_SDS ; if (buffer [0] == MAKE_MARKER ('C', 'A', 'T', ' ') && buffer [2] == MAKE_MARKER ('R', 'E', 'X', '2')) return SF_FORMAT_REX2 ; if (buffer [0] == MAKE_MARKER (0x30, 0x26, 0xB2, 0x75) && buffer [1] == MAKE_MARKER (0x8E, 0x66, 0xCF, 0x11)) return 0 /*-SF_FORMAT_WMA-*/ ; /* HMM (Hidden Markov Model) Tool Kit. */ if (2 * BEI2H_INT (buffer [0]) + 12 == psf->filelength && buffer [2] == MAKE_MARKER (0, 2, 0, 0)) return SF_FORMAT_HTK ; if (buffer [0] == MAKE_MARKER ('f', 'L', 'a', 'C')) return SF_FORMAT_FLAC ; /* Turtle Beach SMP 16-bit */ if (buffer [0] == MAKE_MARKER ('S', 'O', 'U', 'N') && buffer [1] == MAKE_MARKER ('D', ' ', 'S', 'A')) return 0 ; if (buffer [0] == MAKE_MARKER ('S', 'Y', '8', '0') || buffer [0] == MAKE_MARKER ('S', 'Y', '8', '5')) return 0 ; if (buffer [0] == MAKE_MARKER ('a', 'j', 'k', 'g')) return 0 /*-SF_FORMAT_SHN-*/ ; if (buffer [0] == MAKE_MARKER ('2', 'B', 'I', 'T')) return SF_FORMAT_AVR ; /* This must be the second last one. */ if (psf->filelength > 0 && (format = try_resource_fork (psf, SFM_READ)) != 0) return format ; return 0 ; } /* guess_file_type */ static int validate_sfinfo (SF_INFO *sfinfo) { if (sfinfo->samplerate < 1) return 0 ; if (sfinfo->frames < 0) return 0 ; if (sfinfo->channels < 1) return 0 ; if ((sfinfo->format & SF_FORMAT_TYPEMASK) == 0) return 0 ; if ((sfinfo->format & SF_FORMAT_SUBMASK) == 0) return 0 ; if (sfinfo->sections < 1) return 0 ; return 1 ; } /* validate_sfinfo */ static int validate_psf (SF_PRIVATE *psf) { if (psf->datalength < 0) { psf_log_printf (psf, "Invalid SF_PRIVATE field : datalength == %D.\n", psf->datalength) ; return 0 ; } ; if (psf->dataoffset < 0) { psf_log_printf (psf, "Invalid SF_PRIVATE field : dataoffset == %D.\n", psf->dataoffset) ; return 0 ; } ; if (psf->blockwidth && psf->blockwidth != psf->sf.channels * psf->bytewidth) { psf_log_printf (psf, "Invalid SF_PRIVATE field : channels * bytewidth == %d.\n", psf->sf.channels * psf->bytewidth) ; return 0 ; } ; return 1 ; } /* validate_psf */ static void save_header_info (SF_PRIVATE *psf) { LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "%s", psf->logbuffer) ; } /* save_header_info */ static void copy_filename (SF_PRIVATE *psf, const char *path) { const char *ccptr ; char *cptr ; LSF_SNPRINTF (psf->filepath, sizeof (psf->filepath), "%s", path) ; if ((ccptr = strrchr (path, '/')) || (ccptr = strrchr (path, '\\'))) ccptr ++ ; else ccptr = path ; LSF_SNPRINTF (psf->filename, sizeof (psf->filename), "%s", ccptr) ; /* Now grab the directory. */ LSF_SNPRINTF (psf->directory, sizeof (psf->directory), "%s", path) ; if ((cptr = strrchr (psf->directory, '/')) || (cptr = strrchr (psf->directory, '\\'))) cptr [1] = 0 ; else psf->directory [0] = 0 ; return ; } /* copy_filename */ /*============================================================================== */ static int psf_close (SF_PRIVATE *psf) { int error ; if (psf->codec_close) error = psf->codec_close (psf) ; if (psf->container_close) error = psf->container_close (psf) ; psf_fclose (psf) ; psf_close_rsrc (psf) ; if (psf->container_data) free (psf->container_data) ; if (psf->codec_data) free (psf->codec_data) ; if (psf->interleave) free (psf->interleave) ; if (psf->dither) free (psf->dither) ; if (psf->peak_info) free (psf->peak_info) ; if (psf->broadcast_info) free (psf->broadcast_info) ; if (psf->loop_info) free (psf->loop_info) ; if (psf->instrument) free (psf->instrument) ; if (psf->channel_map) free (psf->channel_map) ; if (psf->format_desc) { memset (psf->format_desc, 0, strlen (psf->format_desc)) ; free (psf->format_desc) ; } ; memset (psf, 0, sizeof (SF_PRIVATE)) ; free (psf) ; return 0 ; } /* psf_close */ static int psf_open_file (SF_PRIVATE *psf, int mode, SF_INFO *sfinfo) { int error, format ; if (mode != SFM_READ && mode != SFM_WRITE && mode != SFM_RDWR) return SFE_BAD_OPEN_MODE ; if (sfinfo == NULL) return SFE_BAD_SF_INFO_PTR ; /* Zero out these fields. */ sfinfo->frames = 0 ; sfinfo->sections = 0 ; sfinfo->seekable = 0 ; if (mode == SFM_READ) { if ((sfinfo->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW) { if (sf_format_check (sfinfo) == 0) return SFE_RAW_BAD_FORMAT ; } else memset (sfinfo, 0, sizeof (SF_INFO)) ; } ; sf_errno = error = 0 ; sf_logbuffer [0] = 0 ; memcpy (&(psf->sf), sfinfo, sizeof (SF_INFO)) ; psf->Magick = SNDFILE_MAGICK ; psf->norm_float = SF_TRUE ; psf->norm_double = SF_TRUE ; psf->mode = mode ; psf->dataoffset = -1 ; psf->datalength = -1 ; psf->read_current = -1 ; psf->write_current = -1 ; psf->auto_header = SF_FALSE ; psf->rwf_endian = SF_ENDIAN_LITTLE ; psf->seek = psf_default_seek ; psf->float_int_mult = 0 ; psf->float_max = -1.0 ; psf->sf.sections = 1 ; psf->is_pipe = psf_is_pipe (psf) ; if (psf->is_pipe) { psf->sf.seekable = SF_FALSE ; psf->filelength = SF_COUNT_MAX ; } else { psf->sf.seekable = SF_TRUE ; /* File is open, so get the length. */ psf->filelength = psf_get_filelen (psf) ; } ; if (psf->fileoffset > 0) { switch (psf->mode) { case SFM_READ : if (psf->filelength < 44) { psf_log_printf (psf, "Short filelength: %D (fileoffset: %D)\n", psf->filelength, psf->fileoffset) ; return SFE_BAD_OFFSET ; } ; break ; case SFM_WRITE : psf->fileoffset = 0 ; psf_fseek (psf, 0, SEEK_END) ; psf->fileoffset = psf_ftell (psf) ; break ; case SFM_RDWR : return SFE_NO_EMBEDDED_RDWR ; } ; psf_log_printf (psf, "Embedded file offset : %D\n", psf->fileoffset) ; } ; if (psf->filelength == SF_COUNT_MAX) psf_log_printf (psf, "Length : unknown\n") ; else psf_log_printf (psf, "Length : %D\n", psf->filelength) ; if (mode == SFM_WRITE || (mode == SFM_RDWR && psf->filelength == 0)) { /* If the file is being opened for write or RDWR and the file is currently ** empty, then the SF_INFO struct must contain valid data. */ if (sf_format_check (&(psf->sf)) == 0) return SFE_BAD_OPEN_FORMAT ; } else if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) { /* If type RAW has not been specified then need to figure out file type. */ psf->sf.format = guess_file_type (psf) ; if (psf->sf.format == 0) psf->sf.format = format_from_extension (psf) ; } ; /* Prevent unnecessary seeks */ psf->last_op = psf->mode ; /* Set bytewidth if known. */ switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : case SF_FORMAT_ULAW : case SF_FORMAT_ALAW : case SF_FORMAT_DPCM_8 : psf->bytewidth = 1 ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_DPCM_16 : psf->bytewidth = 2 ; break ; case SF_FORMAT_PCM_24 : psf->bytewidth = 3 ; break ; case SF_FORMAT_PCM_32 : case SF_FORMAT_FLOAT : psf->bytewidth = 4 ; break ; case SF_FORMAT_DOUBLE : psf->bytewidth = 8 ; break ; } ; /* Call the initialisation function for the relevant file type. */ switch (psf->sf.format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : case SF_FORMAT_WAVEX : error = wav_open (psf) ; break ; case SF_FORMAT_AIFF : error = aiff_open (psf) ; break ; case SF_FORMAT_AU : error = au_open (psf) ; break ; case SF_FORMAT_RAW : error = raw_open (psf) ; break ; case SF_FORMAT_W64 : error = w64_open (psf) ; break ; /* Lite remove start */ case SF_FORMAT_PAF : error = paf_open (psf) ; break ; case SF_FORMAT_SVX : error = svx_open (psf) ; break ; case SF_FORMAT_NIST : error = nist_open (psf) ; break ; case SF_FORMAT_IRCAM : error = ircam_open (psf) ; break ; case SF_FORMAT_VOC : error = voc_open (psf) ; break ; case SF_FORMAT_SDS : error = sds_open (psf) ; break ; case SF_FORMAT_OGG : error = ogg_open (psf) ; break ; case SF_FORMAT_TXW : error = txw_open (psf) ; break ; case SF_FORMAT_WVE : error = wve_open (psf) ; break ; case SF_FORMAT_DWD : error = dwd_open (psf) ; break ; case SF_FORMAT_MAT4 : error = mat4_open (psf) ; break ; case SF_FORMAT_MAT5 : error = mat5_open (psf) ; break ; case SF_FORMAT_PVF : error = pvf_open (psf) ; break ; case SF_FORMAT_XI : error = xi_open (psf) ; break ; case SF_FORMAT_HTK : error = htk_open (psf) ; break ; case SF_FORMAT_SD2 : error = sd2_open (psf) ; break ; case SF_FORMAT_REX2 : error = rx2_open (psf) ; break ; case SF_FORMAT_AVR : error = avr_open (psf) ; break ; case SF_FORMAT_FLAC : error = flac_open (psf) ; break ; case SF_FORMAT_CAF : error = caf_open (psf) ; break ; /* Lite remove end */ default : error = SFE_UNKNOWN_FORMAT ; } ; if (error) { switch (error) { case SF_ERR_SYSTEM : case SF_ERR_UNSUPPORTED_ENCODING : case SFE_UNIMPLEMENTED : break ; default : psf_log_printf (psf, "Parse error : %s\n", sf_error_number (error)) ; error = SF_ERR_MALFORMED_FILE ; } ; return error ; } ; /* For now, check whether embedding is supported. */ format = psf->sf.format & SF_FORMAT_TYPEMASK ; if (psf->fileoffset > 0 && (format != SF_FORMAT_WAV) && (format != SF_FORMAT_WAVEX) && (format != SF_FORMAT_AIFF) && (format != SF_FORMAT_AU) ) return SFE_NO_EMBED_SUPPORT ; if (psf->fileoffset > 0) psf_log_printf (psf, "Embedded file length : %D\n", psf->filelength) ; if (mode == SFM_RDWR && sf_format_check (&(psf->sf)) == 0) return SFE_BAD_RDWR_FORMAT ; if (validate_sfinfo (&(psf->sf)) == 0) { psf_log_SF_INFO (psf) ; save_header_info (psf) ; return SFE_BAD_SF_INFO ; } ; if (validate_psf (psf) == 0) { save_header_info (psf) ; return SFE_INTERNAL ; } ; psf->read_current = 0 ; psf->write_current = (psf->mode == SFM_RDWR) ? psf->sf.frames : 0 ; memcpy (sfinfo, &(psf->sf), sizeof (SF_INFO)) ; return 0 ; } /* psf_open_file */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: cd4f9e91-a8ec-4154-9bf6-fe4b8c69a615 */ nyquist-3.05/nylsf/pcm.c0000644000175000000620000023232211466723256014261 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" /* Need to be able to handle 3 byte (24 bit) integers. So defined a ** type and use SIZEOF_TRIBYTE instead of (tribyte). */ typedef void tribyte ; #define SIZEOF_TRIBYTE 3 static sf_count_t pcm_read_sc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_uc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_bes2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_les2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_bet2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_let2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_bei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_lei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t pcm_read_sc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_uc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_bes2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_les2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_bet2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_let2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_bei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_lei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t pcm_read_sc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_uc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_bes2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_les2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_bet2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_let2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_bei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_lei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t pcm_read_sc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_uc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_bes2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_les2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_bet2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_let2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_bei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_read_lei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2sc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2uc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2bes (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2les (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2bet (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2let (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2bei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_s2lei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2sc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2uc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2bes (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2les (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2bet (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2let (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2bei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_i2lei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2sc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2uc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2bes (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2les (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2bet (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2let (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2bei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_f2lei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2sc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2uc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2bes (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2les (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2bet (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2let (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2bei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t pcm_write_d2lei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; /*----------------------------------------------------------------------------------------------- */ enum { /* Char type for 8 bit files. */ SF_CHARS_SIGNED = 200, SF_CHARS_UNSIGNED = 201 } ; /*----------------------------------------------------------------------------------------------- */ int pcm_init (SF_PRIVATE *psf) { int chars = 0 ; if (psf->bytewidth == 0 || psf->sf.channels == 0) return SFE_INTERNAL ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_S8) chars = SF_CHARS_SIGNED ; else if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_U8) chars = SF_CHARS_UNSIGNED ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { switch (psf->bytewidth * 0x10000 + psf->endian + chars) { case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_SIGNED) : case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_SIGNED) : psf->read_short = pcm_read_sc2s ; psf->read_int = pcm_read_sc2i ; psf->read_float = pcm_read_sc2f ; psf->read_double = pcm_read_sc2d ; break ; case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_UNSIGNED) : case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_UNSIGNED) : psf->read_short = pcm_read_uc2s ; psf->read_int = pcm_read_uc2i ; psf->read_float = pcm_read_uc2f ; psf->read_double = pcm_read_uc2d ; break ; case (2 * 0x10000 + SF_ENDIAN_BIG) : psf->read_short = pcm_read_bes2s ; psf->read_int = pcm_read_bes2i ; psf->read_float = pcm_read_bes2f ; psf->read_double = pcm_read_bes2d ; break ; case (3 * 0x10000 + SF_ENDIAN_BIG) : psf->read_short = pcm_read_bet2s ; psf->read_int = pcm_read_bet2i ; psf->read_float = pcm_read_bet2f ; psf->read_double = pcm_read_bet2d ; break ; case (4 * 0x10000 + SF_ENDIAN_BIG) : psf->read_short = pcm_read_bei2s ; psf->read_int = pcm_read_bei2i ; psf->read_float = pcm_read_bei2f ; psf->read_double = pcm_read_bei2d ; break ; case (2 * 0x10000 + SF_ENDIAN_LITTLE) : psf->read_short = pcm_read_les2s ; psf->read_int = pcm_read_les2i ; psf->read_float = pcm_read_les2f ; psf->read_double = pcm_read_les2d ; break ; case (3 * 0x10000 + SF_ENDIAN_LITTLE) : psf->read_short = pcm_read_let2s ; psf->read_int = pcm_read_let2i ; psf->read_float = pcm_read_let2f ; psf->read_double = pcm_read_let2d ; break ; case (4 * 0x10000 + SF_ENDIAN_LITTLE) : psf->read_short = pcm_read_lei2s ; psf->read_int = pcm_read_lei2i ; psf->read_float = pcm_read_lei2f ; psf->read_double = pcm_read_lei2d ; break ; default : psf_log_printf (psf, "pcm.c returning SFE_UNIMPLEMENTED\n") ; return SFE_UNIMPLEMENTED ; } ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { switch (psf->bytewidth * 0x10000 + psf->endian + chars) { case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_SIGNED) : case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_SIGNED) : psf->write_short = pcm_write_s2sc ; psf->write_int = pcm_write_i2sc ; psf->write_float = pcm_write_f2sc ; psf->write_double = pcm_write_d2sc ; break ; case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_UNSIGNED) : case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_UNSIGNED) : psf->write_short = pcm_write_s2uc ; psf->write_int = pcm_write_i2uc ; psf->write_float = pcm_write_f2uc ; psf->write_double = pcm_write_d2uc ; break ; case (2 * 0x10000 + SF_ENDIAN_BIG) : psf->write_short = pcm_write_s2bes ; psf->write_int = pcm_write_i2bes ; psf->write_float = pcm_write_f2bes ; psf->write_double = pcm_write_d2bes ; break ; case (3 * 0x10000 + SF_ENDIAN_BIG) : psf->write_short = pcm_write_s2bet ; psf->write_int = pcm_write_i2bet ; psf->write_float = pcm_write_f2bet ; psf->write_double = pcm_write_d2bet ; break ; case (4 * 0x10000 + SF_ENDIAN_BIG) : psf->write_short = pcm_write_s2bei ; psf->write_int = pcm_write_i2bei ; psf->write_float = pcm_write_f2bei ; psf->write_double = pcm_write_d2bei ; break ; case (2 * 0x10000 + SF_ENDIAN_LITTLE) : psf->write_short = pcm_write_s2les ; psf->write_int = pcm_write_i2les ; psf->write_float = pcm_write_f2les ; psf->write_double = pcm_write_d2les ; break ; case (3 * 0x10000 + SF_ENDIAN_LITTLE) : psf->write_short = pcm_write_s2let ; psf->write_int = pcm_write_i2let ; psf->write_float = pcm_write_f2let ; psf->write_double = pcm_write_d2let ; break ; case (4 * 0x10000 + SF_ENDIAN_LITTLE) : psf->write_short = pcm_write_s2lei ; psf->write_int = pcm_write_i2lei ; psf->write_float = pcm_write_f2lei ; psf->write_double = pcm_write_d2lei ; break ; default : psf_log_printf (psf, "pcm.c returning SFE_UNIMPLEMENTED\n") ; return SFE_UNIMPLEMENTED ; } ; } ; if (psf->filelength > psf->dataoffset) { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; } else psf->datalength = 0 ; psf->sf.frames = psf->datalength / psf->blockwidth ; return 0 ; } /* pcm_init */ /*============================================================================== */ static inline void sc2s_array (signed char *src, int count, short *dest) { while (--count >= 0) { dest [count] = src [count] << 8 ; } ; } /* sc2s_array */ static inline void uc2s_array (unsigned char *src, int count, short *dest) { while (--count >= 0) { dest [count] = (((short) src [count]) - 0x80) << 8 ; } ; } /* uc2s_array */ static inline void let2s_array (tribyte *src, int count, short *dest) { unsigned char *ucptr ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; dest [count] = LET2H_SHORT_PTR (ucptr) ; } ; } /* let2s_array */ static inline void bet2s_array (tribyte *src, int count, short *dest) { unsigned char *ucptr ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; dest [count] = BET2H_SHORT_PTR (ucptr) ; } ; } /* bet2s_array */ static inline void lei2s_array (int *src, int count, short *dest) { int value ; while (--count >= 0) { value = LEI2H_INT (src [count]) ; dest [count] = value >> 16 ; } ; } /* lei2s_array */ static inline void bei2s_array (int *src, int count, short *dest) { int value ; while (--count >= 0) { value = BEI2H_INT (src [count]) ; dest [count] = value >> 16 ; } ; } /* bei2s_array */ /*-------------------------------------------------------------------------- */ static inline void sc2i_array (signed char *src, int count, int *dest) { while (--count >= 0) { dest [count] = ((int) src [count]) << 24 ; } ; } /* sc2i_array */ static inline void uc2i_array (unsigned char *src, int count, int *dest) { while (--count >= 0) { dest [count] = (((int) src [count]) - 128) << 24 ; } ; } /* uc2i_array */ static inline void bes2i_array (short *src, int count, int *dest) { short value ; while (--count >= 0) { value = BES2H_SHORT (src [count]) ; dest [count] = value << 16 ; } ; } /* bes2i_array */ static inline void les2i_array (short *src, int count, int *dest) { short value ; while (--count >= 0) { value = LES2H_SHORT (src [count]) ; dest [count] = value << 16 ; } ; } /* les2i_array */ static inline void bet2i_array (tribyte *src, int count, int *dest) { unsigned char *ucptr ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; dest [count] = BET2H_INT_PTR (ucptr) ; } ; } /* bet2i_array */ static inline void let2i_array (tribyte *src, int count, int *dest) { unsigned char *ucptr ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; dest [count] = LET2H_INT_PTR (ucptr) ; } ; } /* let2i_array */ /*-------------------------------------------------------------------------- */ static inline void sc2f_array (signed char *src, int count, float *dest, float normfact) { while (--count >= 0) dest [count] = ((float) src [count]) * normfact ; } /* sc2f_array */ static inline void uc2f_array (unsigned char *src, int count, float *dest, float normfact) { while (--count >= 0) dest [count] = (((int) src [count]) - 128) * normfact ; } /* uc2f_array */ static inline void les2f_array (short *src, int count, float *dest, float normfact) { short value ; while (--count >= 0) { value = src [count] ; value = LES2H_SHORT (value) ; dest [count] = ((float) value) * normfact ; } ; } /* les2f_array */ static inline void bes2f_array (short *src, int count, float *dest, float normfact) { short value ; while (--count >= 0) { value = src [count] ; value = BES2H_SHORT (value) ; dest [count] = ((float) value) * normfact ; } ; } /* bes2f_array */ static inline void let2f_array (tribyte *src, int count, float *dest, float normfact) { unsigned char *ucptr ; int value ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = LET2H_INT_PTR (ucptr) ; dest [count] = ((float) value) * normfact ; } ; } /* let2f_array */ static inline void bet2f_array (tribyte *src, int count, float *dest, float normfact) { unsigned char *ucptr ; int value ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = BET2H_INT_PTR (ucptr) ; dest [count] = ((float) value) * normfact ; } ; } /* bet2f_array */ static inline void lei2f_array (int *src, int count, float *dest, float normfact) { int value ; while (--count >= 0) { value = src [count] ; value = LEI2H_INT (value) ; dest [count] = ((float) value) * normfact ; } ; } /* lei2f_array */ static inline void bei2f_array (int *src, int count, float *dest, float normfact) { int value ; while (--count >= 0) { value = src [count] ; value = BEI2H_INT (value) ; dest [count] = ((float) value) * normfact ; } ; } /* bei2f_array */ /*-------------------------------------------------------------------------- */ static inline void sc2d_array (signed char *src, int count, double *dest, double normfact) { while (--count >= 0) dest [count] = ((double) src [count]) * normfact ; } /* sc2d_array */ static inline void uc2d_array (unsigned char *src, int count, double *dest, double normfact) { while (--count >= 0) dest [count] = (((int) src [count]) - 128) * normfact ; } /* uc2d_array */ static inline void les2d_array (short *src, int count, double *dest, double normfact) { short value ; while (--count >= 0) { value = src [count] ; value = LES2H_SHORT (value) ; dest [count] = ((double) value) * normfact ; } ; } /* les2d_array */ static inline void bes2d_array (short *src, int count, double *dest, double normfact) { short value ; while (--count >= 0) { value = src [count] ; value = BES2H_SHORT (value) ; dest [count] = ((double) value) * normfact ; } ; } /* bes2d_array */ static inline void let2d_array (tribyte *src, int count, double *dest, double normfact) { unsigned char *ucptr ; int value ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = LET2H_INT_PTR (ucptr) ; dest [count] = ((double) value) * normfact ; } ; } /* let2d_array */ static inline void bet2d_array (tribyte *src, int count, double *dest, double normfact) { unsigned char *ucptr ; int value ; ucptr = ((unsigned char*) src) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = (ucptr [0] << 24) | (ucptr [1] << 16) | (ucptr [2] << 8) ; dest [count] = ((double) value) * normfact ; } ; } /* bet2d_array */ static inline void lei2d_array (int *src, int count, double *dest, double normfact) { int value ; while (--count >= 0) { value = src [count] ; value = LEI2H_INT (value) ; dest [count] = ((double) value) * normfact ; } ; } /* lei2d_array */ static inline void bei2d_array (int *src, int count, double *dest, double normfact) { int value ; while (--count >= 0) { value = src [count] ; value = BEI2H_INT (value) ; dest [count] = ((double) value) * normfact ; } ; } /* bei2d_array */ /*-------------------------------------------------------------------------- */ static inline void s2sc_array (const short *src, signed char *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 8 ; } /* s2sc_array */ static inline void s2uc_array (const short *src, unsigned char *dest, int count) { while (--count >= 0) dest [count] = (src [count] >> 8) + 0x80 ; } /* s2uc_array */ static inline void s2let_array (const short *src, tribyte *dest, int count) { unsigned char *ucptr ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; ucptr [0] = 0 ; ucptr [1] = src [count] ; ucptr [2] = src [count] >> 8 ; } ; } /* s2let_array */ static inline void s2bet_array (const short *src, tribyte *dest, int count) { unsigned char *ucptr ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; ucptr [2] = 0 ; ucptr [1] = src [count] ; ucptr [0] = src [count] >> 8 ; } ; } /* s2bet_array */ static inline void s2lei_array (const short *src, int *dest, int count) { unsigned char *ucptr ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; ucptr [0] = 0 ; ucptr [1] = 0 ; ucptr [2] = src [count] ; ucptr [3] = src [count] >> 8 ; } ; } /* s2lei_array */ static inline void s2bei_array (const short *src, int *dest, int count) { unsigned char *ucptr ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; ucptr [0] = src [count] >> 8 ; ucptr [1] = src [count] ; ucptr [2] = 0 ; ucptr [3] = 0 ; } ; } /* s2bei_array */ /*-------------------------------------------------------------------------- */ static inline void i2sc_array (const int *src, signed char *dest, int count) { while (--count >= 0) dest [count] = (src [count] >> 24) ; } /* i2sc_array */ static inline void i2uc_array (const int *src, unsigned char *dest, int count) { while (--count >= 0) dest [count] = ((src [count] >> 24) + 128) ; } /* i2uc_array */ static inline void i2bes_array (const int *src, short *dest, int count) { unsigned char *ucptr ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; ucptr [0] = src [count] >> 24 ; ucptr [1] = src [count] >> 16 ; } ; } /* i2bes_array */ static inline void i2les_array (const int *src, short *dest, int count) { unsigned char *ucptr ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; ucptr [0] = src [count] >> 16 ; ucptr [1] = src [count] >> 24 ; } ; } /* i2les_array */ static inline void i2let_array (const int *src, tribyte *dest, int count) { unsigned char *ucptr ; int value ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = src [count] >> 8 ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; } ; } /* i2let_array */ static inline void i2bet_array (const int *src, tribyte *dest, int count) { unsigned char *ucptr ; int value ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = src [count] >> 8 ; ucptr [2] = value ; ucptr [1] = value >> 8 ; ucptr [0] = value >> 16 ; } ; } /* i2bet_array */ /*=============================================================================================== */ static sf_count_t pcm_read_sc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; sc2s_array (psf->u.scbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_sc2s */ static sf_count_t pcm_read_uc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; uc2s_array (psf->u.ucbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_uc2s */ static sf_count_t pcm_read_bes2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int total ; total = psf_fread (ptr, sizeof (short), len, psf) ; if (CPU_IS_LITTLE_ENDIAN) endswap_short_array (ptr, len) ; return total ; } /* pcm_read_bes2s */ static sf_count_t pcm_read_les2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int total ; total = psf_fread (ptr, sizeof (short), len, psf) ; if (CPU_IS_BIG_ENDIAN) endswap_short_array (ptr, len) ; return total ; } /* pcm_read_les2s */ static sf_count_t pcm_read_bet2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; bet2s_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bet2s */ static sf_count_t pcm_read_let2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; let2s_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_let2s */ static sf_count_t pcm_read_bei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ; bei2s_array (psf->u.ibuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bei2s */ static sf_count_t pcm_read_lei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ; lei2s_array (psf->u.ibuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_lei2s */ /*----------------------------------------------------------------------------------------------- */ static sf_count_t pcm_read_sc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; sc2i_array (psf->u.scbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_sc2i */ static sf_count_t pcm_read_uc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; uc2i_array (psf->u.ucbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_uc2i */ static sf_count_t pcm_read_bes2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; bes2i_array (psf->u.sbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bes2i */ static sf_count_t pcm_read_les2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; les2i_array (psf->u.sbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_les2i */ static sf_count_t pcm_read_bet2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; bet2i_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bet2i */ static sf_count_t pcm_read_let2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; let2i_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_let2i */ static sf_count_t pcm_read_bei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int total ; total = psf_fread (ptr, sizeof (int), len, psf) ; if (CPU_IS_LITTLE_ENDIAN) endswap_int_array (ptr, len) ; return total ; } /* pcm_read_bei2i */ static sf_count_t pcm_read_lei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int total ; total = psf_fread (ptr, sizeof (int), len, psf) ; if (CPU_IS_BIG_ENDIAN) endswap_int_array (ptr, len) ; return total ; } /* pcm_read_lei2i */ /*----------------------------------------------------------------------------------------------- */ static sf_count_t pcm_read_sc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; sc2f_array (psf->u.scbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_sc2f */ static sf_count_t pcm_read_uc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; uc2f_array (psf->u.ucbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_uc2f */ static sf_count_t pcm_read_bes2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; bes2f_array (psf->u.sbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bes2f */ static sf_count_t pcm_read_les2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; les2f_array (psf->u.sbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_les2f */ static sf_count_t pcm_read_bet2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; /* Special normfactor because tribyte value is read into an int. */ normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 / 256.0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; bet2f_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bet2f */ static sf_count_t pcm_read_let2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; /* Special normfactor because tribyte value is read into an int. */ normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 / 256.0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; let2f_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_let2f */ static sf_count_t pcm_read_bei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ; bei2f_array (psf->u.ibuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bei2f */ static sf_count_t pcm_read_lei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ; lei2f_array (psf->u.ibuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_lei2f */ /*----------------------------------------------------------------------------------------------- */ static sf_count_t pcm_read_sc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; sc2d_array (psf->u.scbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_sc2d */ static sf_count_t pcm_read_uc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; uc2d_array (psf->u.ucbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_uc2d */ static sf_count_t pcm_read_bes2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; bes2d_array (psf->u.sbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bes2d */ static sf_count_t pcm_read_les2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; les2d_array (psf->u.sbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_les2d */ static sf_count_t pcm_read_bet2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 / 256.0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; bet2d_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bet2d */ static sf_count_t pcm_read_let2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; /* Special normfactor because tribyte value is read into an int. */ normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 / 256.0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; let2d_array ((tribyte*) (psf->u.ucbuf), readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_let2d */ static sf_count_t pcm_read_bei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ; bei2d_array (psf->u.ibuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_bei2d */ static sf_count_t pcm_read_lei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ; lei2d_array (psf->u.ibuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* pcm_read_lei2d */ /*=============================================================================================== **----------------------------------------------------------------------------------------------- **=============================================================================================== */ static sf_count_t pcm_write_s2sc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2sc_array (ptr + total, psf->u.scbuf, bufferlen) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2sc */ static sf_count_t pcm_write_s2uc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2uc_array (ptr + total, psf->u.ucbuf, bufferlen) ; writecount = psf_fwrite (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2uc */ static sf_count_t pcm_write_s2bes (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; if (CPU_IS_BIG_ENDIAN) return psf_fwrite (ptr, sizeof (short), len, psf) ; else bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_short_copy (psf->u.sbuf, ptr + total, bufferlen) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2bes */ static sf_count_t pcm_write_s2les (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; if (CPU_IS_LITTLE_ENDIAN) return psf_fwrite (ptr, sizeof (short), len, psf) ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_short_copy (psf->u.sbuf, ptr + total, bufferlen) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2les */ static sf_count_t pcm_write_s2bet (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2bet_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2bet */ static sf_count_t pcm_write_s2let (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2let_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2let */ static sf_count_t pcm_write_s2bei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2bei_array (ptr + total, psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2bei */ static sf_count_t pcm_write_s2lei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2lei_array (ptr + total, psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_s2lei */ /*----------------------------------------------------------------------------------------------- */ static sf_count_t pcm_write_i2sc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2sc_array (ptr + total, psf->u.scbuf, bufferlen) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2sc */ static sf_count_t pcm_write_i2uc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2uc_array (ptr + total, psf->u.ucbuf, bufferlen) ; writecount = psf_fwrite (psf->u.ucbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2uc */ static sf_count_t pcm_write_i2bes (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2bes_array (ptr + total, psf->u.sbuf, bufferlen) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2bes */ static sf_count_t pcm_write_i2les (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2les_array (ptr + total, psf->u.sbuf, bufferlen) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2les */ static sf_count_t pcm_write_i2bet (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2bet_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2bet */ static sf_count_t pcm_write_i2let (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2let_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2les */ static sf_count_t pcm_write_i2bei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; if (CPU_IS_BIG_ENDIAN) return psf_fwrite (ptr, sizeof (int), len, psf) ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_int_copy (psf->u.ibuf, ptr + total, bufferlen) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2bei */ static sf_count_t pcm_write_i2lei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; if (CPU_IS_LITTLE_ENDIAN) return psf_fwrite (ptr, sizeof (int), len, psf) ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_int_copy (psf->u.ibuf, ptr + total, bufferlen) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_i2lei */ /*------------------------------------------------------------------------------ **============================================================================== **------------------------------------------------------------------------------ */ static void f2sc_array (const float *src, signed char *dest, int count, int normalize) { float normfact ; normfact = normalize ? (1.0 * 0x7F) : 1.0 ; while (--count >= 0) { dest [count] = lrintf (src [count] * normfact) ; } ; } /* f2sc_array */ static void f2sc_clip_array (const float *src, signed char *dest, int count, int normalize) { float normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { dest [count] = 127 ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { dest [count] = -128 ; continue ; } ; dest [count] = lrintf (scaled_value) >> 24 ; } ; } /* f2sc_clip_array */ static sf_count_t pcm_write_f2sc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, signed char *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2sc_clip_array : f2sc_array ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.scbuf, bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2sc */ /*============================================================================== */ static void f2uc_array (const float *src, unsigned char *dest, int count, int normalize) { float normfact ; normfact = normalize ? (1.0 * 0x7F) : 1.0 ; while (--count >= 0) { dest [count] = lrintf (src [count] * normfact) + 128 ; } ; } /* f2uc_array */ static void f2uc_clip_array (const float *src, unsigned char *dest, int count, int normalize) { float normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { dest [count] = 0xFF ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { dest [count] = 0 ; continue ; } ; dest [count] = (lrintf (scaled_value) >> 24) + 128 ; } ; } /* f2uc_clip_array */ static sf_count_t pcm_write_f2uc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, unsigned char *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2uc_clip_array : f2uc_array ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.ucbuf, bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2uc */ /*============================================================================== */ static void f2bes_array (const float *src, short *dest, int count, int normalize) { unsigned char *ucptr ; float normfact ; short value ; normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; value = lrintf (src [count] * normfact) ; ucptr [1] = value ; ucptr [0] = value >> 8 ; } ; } /* f2bes_array */ static void f2bes_clip_array (const float *src, short *dest, int count, int normalize) { unsigned char *ucptr ; float normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [1] = 0xFF ; ucptr [0] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [1] = 0x00 ; ucptr [0] = 0x80 ; continue ; } ; value = lrintf (scaled_value) ; ucptr [1] = value >> 16 ; ucptr [0] = value >> 24 ; } ; } /* f2bes_clip_array */ static sf_count_t pcm_write_f2bes (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, short *t, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2bes_clip_array : f2bes_array ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2bes */ /*============================================================================== */ static void f2les_array (const float *src, short *dest, int count, int normalize) { unsigned char *ucptr ; float normfact ; int value ; normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; value = lrintf (src [count] * normfact) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; } ; } /* f2les_array */ static void f2les_clip_array (const float *src, short *dest, int count, int normalize) { unsigned char *ucptr ; float normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0xFF ; ucptr [1] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x00 ; ucptr [1] = 0x80 ; continue ; } ; value = lrintf (scaled_value) ; ucptr [0] = value >> 16 ; ucptr [1] = value >> 24 ; } ; } /* f2les_clip_array */ static sf_count_t pcm_write_f2les (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, short *t, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2les_clip_array : f2les_array ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2les */ /*============================================================================== */ static void f2let_array (const float *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; float normfact ; int value ; normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = lrintf (src [count] * normfact) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; } ; } /* f2let_array */ static void f2let_clip_array (const float *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; float normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0xFF ; ucptr [1] = 0xFF ; ucptr [2] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x00 ; ucptr [1] = 0x00 ; ucptr [2] = 0x80 ; continue ; } ; value = lrintf (scaled_value) ; ucptr [0] = value >> 8 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 24 ; } ; } /* f2let_clip_array */ static sf_count_t pcm_write_f2let (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, tribyte *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2let_clip_array : f2let_array ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2let */ /*============================================================================== */ static void f2bet_array (const float *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; float normfact ; int value ; normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = lrintf (src [count] * normfact) ; ucptr [0] = value >> 16 ; ucptr [1] = value >> 8 ; ucptr [2] = value ; } ; } /* f2bet_array */ static void f2bet_clip_array (const float *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; float normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0x7F ; ucptr [1] = 0xFF ; ucptr [2] = 0xFF ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x80 ; ucptr [1] = 0x00 ; ucptr [2] = 0x00 ; continue ; } ; value = lrint (scaled_value) ; ucptr [0] = value >> 24 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 8 ; } ; } /* f2bet_clip_array */ static sf_count_t pcm_write_f2bet (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, tribyte *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2bet_clip_array : f2bet_array ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2bet */ /*============================================================================== */ static void f2bei_array (const float *src, int *dest, int count, int normalize) { unsigned char *ucptr ; float normfact ; int value ; normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; value = lrintf (src [count] * normfact) ; ucptr [0] = value >> 24 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 8 ; ucptr [3] = value ; } ; } /* f2bei_array */ static void f2bei_clip_array (const float *src, int *dest, int count, int normalize) { unsigned char *ucptr ; float normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= 1.0 * 0x7FFFFFFF) { ucptr [0] = 0x7F ; ucptr [1] = 0xFF ; ucptr [2] = 0xFF ; ucptr [3] = 0xFF ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x80 ; ucptr [1] = 0x00 ; ucptr [2] = 0x00 ; ucptr [3] = 0x00 ; continue ; } ; value = lrintf (scaled_value) ; ucptr [0] = value >> 24 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 8 ; ucptr [3] = value ; } ; } /* f2bei_clip_array */ static sf_count_t pcm_write_f2bei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, int *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2bei_clip_array : f2bei_array ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2bei */ /*============================================================================== */ static void f2lei_array (const float *src, int *dest, int count, int normalize) { unsigned char *ucptr ; float normfact ; int value ; normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; value = lrintf (src [count] * normfact) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; ucptr [3] = value >> 24 ; } ; } /* f2lei_array */ static void f2lei_clip_array (const float *src, int *dest, int count, int normalize) { unsigned char *ucptr ; float normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0xFF ; ucptr [1] = 0xFF ; ucptr [2] = 0xFF ; ucptr [3] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x00 ; ucptr [1] = 0x00 ; ucptr [2] = 0x00 ; ucptr [3] = 0x80 ; continue ; } ; value = lrintf (scaled_value) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; ucptr [3] = value >> 24 ; } ; } /* f2lei_clip_array */ static sf_count_t pcm_write_f2lei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { void (*convert) (const float *, int *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? f2lei_clip_array : f2lei_array ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_float) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_f2lei */ /*============================================================================== */ static void d2sc_array (const double *src, signed char *dest, int count, int normalize) { double normfact ; normfact = normalize ? (1.0 * 0x7F) : 1.0 ; while (--count >= 0) { dest [count] = lrint (src [count] * normfact) ; } ; } /* d2sc_array */ static void d2sc_clip_array (const double *src, signed char *dest, int count, int normalize) { double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { dest [count] = 127 ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { dest [count] = -128 ; continue ; } ; dest [count] = lrintf (scaled_value) >> 24 ; } ; } /* d2sc_clip_array */ static sf_count_t pcm_write_d2sc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, signed char *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2sc_clip_array : d2sc_array ; bufferlen = ARRAY_LEN (psf->u.scbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.scbuf, bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2sc */ /*============================================================================== */ static void d2uc_array (const double *src, unsigned char *dest, int count, int normalize) { double normfact ; normfact = normalize ? (1.0 * 0x7F) : 1.0 ; while (--count >= 0) { dest [count] = lrint (src [count] * normfact) + 128 ; } ; } /* d2uc_array */ static void d2uc_clip_array (const double *src, unsigned char *dest, int count, int normalize) { double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { dest [count] = 255 ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { dest [count] = 0 ; continue ; } ; dest [count] = (lrint (src [count] * normfact) >> 24) + 128 ; } ; } /* d2uc_clip_array */ static sf_count_t pcm_write_d2uc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, unsigned char *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2uc_clip_array : d2uc_array ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.ucbuf, bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2uc */ /*============================================================================== */ static void d2bes_array (const double *src, short *dest, int count, int normalize) { unsigned char *ucptr ; short value ; double normfact ; normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; value = lrint (src [count] * normfact) ; ucptr [1] = value ; ucptr [0] = value >> 8 ; } ; } /* d2bes_array */ static void d2bes_clip_array (const double *src, short *dest, int count, int normalize) { unsigned char *ucptr ; double normfact, scaled_value ; int value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [1] = 0xFF ; ucptr [0] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [1] = 0x00 ; ucptr [0] = 0x80 ; continue ; } ; value = lrint (scaled_value) ; ucptr [1] = value >> 16 ; ucptr [0] = value >> 24 ; } ; } /* d2bes_clip_array */ static sf_count_t pcm_write_d2bes (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, short *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2bes_clip_array : d2bes_array ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2bes */ /*============================================================================== */ static void d2les_array (const double *src, short *dest, int count, int normalize) { unsigned char *ucptr ; short value ; double normfact ; normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; value = lrint (src [count] * normfact) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; } ; } /* d2les_array */ static void d2les_clip_array (const double *src, short *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; ucptr = ((unsigned char*) dest) + 2 * count ; while (--count >= 0) { ucptr -= 2 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0xFF ; ucptr [1] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x00 ; ucptr [1] = 0x80 ; continue ; } ; value = lrint (scaled_value) ; ucptr [0] = value >> 16 ; ucptr [1] = value >> 24 ; } ; } /* d2les_clip_array */ static sf_count_t pcm_write_d2les (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, short *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2les_clip_array : d2les_array ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2les */ /*============================================================================== */ static void d2let_array (const double *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact ; normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = lrint (src [count] * normfact) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; } ; } /* d2let_array */ static void d2let_clip_array (const double *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0xFF ; ucptr [1] = 0xFF ; ucptr [2] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x00 ; ucptr [1] = 0x00 ; ucptr [2] = 0x80 ; continue ; } ; value = lrint (scaled_value) ; ucptr [0] = value >> 8 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 24 ; } ; } /* d2let_clip_array */ static sf_count_t pcm_write_d2let (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, tribyte *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2let_clip_array : d2let_array ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2let */ /*============================================================================== */ static void d2bet_array (const double *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact ; normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; value = lrint (src [count] * normfact) ; ucptr [2] = value ; ucptr [1] = value >> 8 ; ucptr [0] = value >> 16 ; } ; } /* d2bet_array */ static void d2bet_clip_array (const double *src, tribyte *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; ucptr = ((unsigned char*) dest) + 3 * count ; while (--count >= 0) { ucptr -= 3 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [2] = 0xFF ; ucptr [1] = 0xFF ; ucptr [0] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [2] = 0x00 ; ucptr [1] = 0x00 ; ucptr [0] = 0x80 ; continue ; } ; value = lrint (scaled_value) ; ucptr [2] = value >> 8 ; ucptr [1] = value >> 16 ; ucptr [0] = value >> 24 ; } ; } /* d2bet_clip_array */ static sf_count_t pcm_write_d2bet (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, tribyte *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2bet_clip_array : d2bet_array ; bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2bet */ /*============================================================================== */ static void d2bei_array (const double *src, int *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact ; normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; value = lrint (src [count] * normfact) ; ucptr [0] = value >> 24 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 8 ; ucptr [3] = value ; } ; } /* d2bei_array */ static void d2bei_clip_array (const double *src, int *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [3] = 0xFF ; ucptr [2] = 0xFF ; ucptr [1] = 0xFF ; ucptr [0] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [3] = 0x00 ; ucptr [2] = 0x00 ; ucptr [1] = 0x00 ; ucptr [0] = 0x80 ; continue ; } ; value = lrint (scaled_value) ; ucptr [0] = value >> 24 ; ucptr [1] = value >> 16 ; ucptr [2] = value >> 8 ; ucptr [3] = value ; } ; } /* d2bei_clip_array */ static sf_count_t pcm_write_d2bei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, int *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2bei_clip_array : d2bei_array ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2bei */ /*============================================================================== */ static void d2lei_array (const double *src, int *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact ; normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; value = lrint (src [count] * normfact) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; ucptr [3] = value >> 24 ; } ; } /* d2lei_array */ static void d2lei_clip_array (const double *src, int *dest, int count, int normalize) { unsigned char *ucptr ; int value ; double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; ucptr = ((unsigned char*) dest) + 4 * count ; while (--count >= 0) { ucptr -= 4 ; scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF)) { ucptr [0] = 0xFF ; ucptr [1] = 0xFF ; ucptr [2] = 0xFF ; ucptr [3] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000)) { ucptr [0] = 0x00 ; ucptr [1] = 0x00 ; ucptr [2] = 0x00 ; ucptr [3] = 0x80 ; continue ; } ; value = lrint (scaled_value) ; ucptr [0] = value ; ucptr [1] = value >> 8 ; ucptr [2] = value >> 16 ; ucptr [3] = value >> 24 ; } ; } /* d2lei_clip_array */ static sf_count_t pcm_write_d2lei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { void (*convert) (const double *, int *, int, int) ; int bufferlen, writecount ; sf_count_t total = 0 ; convert = (psf->add_clipping) ? d2lei_clip_array : d2lei_array ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_double) ; writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* pcm_write_d2lei */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: d8bc7c0e-1e2f-4ff3-a28f-10ce1fbade3b */ nyquist-3.05/nylsf/voc.c0000644000175000000620000006361711466723256014302 0ustar stevestaff/* ** Copyright (C) 2001-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* RANT: ** The VOC file format is the most brain damaged format I have yet had to deal ** with. No one programmer could have bee stupid enough to put this together. ** Instead it looks like a series of manic, dyslexic assembly language programmers ** hacked it to fit their needs. ** Utterly woeful. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ * Typedefs for file chunks. */ #define VOC_MAX_SECTIONS 200 enum { VOC_TERMINATOR = 0, VOC_SOUND_DATA = 1, VOC_SOUND_CONTINUE = 2, VOC_SILENCE = 3, VOC_MARKER = 4, VOC_ASCII = 5, VOC_REPEAT = 6, VOC_END_REPEAT = 7, VOC_EXTENDED = 8, VOC_EXTENDED_II = 9 } ; typedef struct { int samples ; int offset ; /* Offset of zero => silence. */ } SND_DATA_BLOCKS ; typedef struct { unsigned int sections, section_types ; int samplerate, channels, bitwidth ; SND_DATA_BLOCKS blocks [VOC_MAX_SECTIONS] ; } VOC_DATA ; /*------------------------------------------------------------------------------ * Private static functions. */ static int voc_close (SF_PRIVATE *psf) ; static int voc_write_header (SF_PRIVATE *psf, int calc_length) ; static int voc_read_header (SF_PRIVATE *psf) ; static const char* voc_encoding2str (int encoding) ; #if 0 /* These functions would be required for files with more than one VOC_SOUND_DATA ** segment. Not sure whether to bother implementing this. */ static int voc_multi_init (SF_PRIVATE *psf, VOC_DATA *pvoc) ; static int voc_multi_read_uc2s (SF_PRIVATE *psf, short *ptr, int len) ; static int voc_multi_read_les2s (SF_PRIVATE *psf, short *ptr, int len) ; static int voc_multi_read_uc2i (SF_PRIVATE *psf, int *ptr, int len) ; static int voc_multi_read_les2i (SF_PRIVATE *psf, int *ptr, int len) ; static int voc_multi_read_uc2f (SF_PRIVATE *psf, float *ptr, int len) ; static int voc_multi_read_les2f (SF_PRIVATE *psf, float *ptr, int len) ; static int voc_multi_read_uc2d (SF_PRIVATE *psf, double *ptr, int len) ; static int voc_multi_read_les2d (SF_PRIVATE *psf, double *ptr, int len) ; #endif /*------------------------------------------------------------------------------ ** Public function. */ int voc_open (SF_PRIVATE *psf) { int subformat, error = 0 ; if (psf->is_pipe) return SFE_VOC_NO_PIPE ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = voc_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_VOC) return SFE_BAD_OPEN_FORMAT ; psf->endian = SF_ENDIAN_LITTLE ; if ((error = voc_write_header (psf, SF_FALSE))) return error ; psf->write_header = voc_write_header ; } ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; psf->container_close = voc_close ; switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : error = pcm_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; default : return SFE_UNIMPLEMENTED ; } ; return error ; } /* voc_open */ /*------------------------------------------------------------------------------ */ static int voc_read_header (SF_PRIVATE *psf) { VOC_DATA *pvoc ; char creative [20] ; unsigned char block_type, rate_byte ; short version, checksum, encoding, dataoffset ; int offset ; /* Set position to start of file to begin reading header. */ offset = psf_binheader_readf (psf, "pb", 0, creative, SIGNED_SIZEOF (creative)) ; if (creative [sizeof (creative) - 1] != 0x1A) return SFE_VOC_NO_CREATIVE ; /* Terminate the string. */ creative [sizeof (creative) - 1] = 0 ; if (strcmp ("Creative Voice File", creative)) return SFE_VOC_NO_CREATIVE ; psf_log_printf (psf, "%s\n", creative) ; offset += psf_binheader_readf (psf, "e222", &dataoffset, &version, &checksum) ; psf->dataoffset = dataoffset ; psf_log_printf (psf, "dataoffset : %d\n" "version : 0x%X\n" "checksum : 0x%X\n", psf->dataoffset, version, checksum) ; if (version != 0x010A && version != 0x0114) return SFE_VOC_BAD_VERSION ; if (! (psf->codec_data = malloc (sizeof (VOC_DATA)))) return SFE_MALLOC_FAILED ; pvoc = (VOC_DATA*) psf->codec_data ; memset (pvoc, 0, sizeof (VOC_DATA)) ; /* Set the default encoding now. */ psf->sf.format = SF_FORMAT_VOC ; /* Major format */ encoding = SF_FORMAT_PCM_U8 ; /* Minor format */ psf->endian = SF_ENDIAN_LITTLE ; while (1) { offset += psf_binheader_readf (psf, "1", &block_type) ; switch (block_type) { case VOC_ASCII : { int size ; offset += psf_binheader_readf (psf, "e3", &size) ; psf_log_printf (psf, " ASCII : %d\n", size) ; offset += psf_binheader_readf (psf, "b", psf->header, size) ; psf->header [size] = 0 ; psf_log_printf (psf, " text : %s\n", psf->header) ; } ; continue ; case VOC_SOUND_DATA : case VOC_EXTENDED : case VOC_EXTENDED_II : break ; default : psf_log_printf (psf, "*** Weird block marker (%d)\n", block_type) ; } ; break ; } ; if (block_type == VOC_SOUND_DATA) { unsigned char compression ; int size ; offset += psf_binheader_readf (psf, "e311", &size, &rate_byte, &compression) ; psf->sf.samplerate = 1000000 / (256 - (rate_byte & 0xFF)) ; psf_log_printf (psf, " Sound Data : %d\n sr : %d => %dHz\n comp : %d\n", size, rate_byte, psf->sf.samplerate, compression) ; if (offset + size - 1 > psf->filelength) { psf_log_printf (psf, "Seems to be a truncated file.\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } else if (offset + size - 1 < psf->filelength) { psf_log_printf (psf, "Seems to be a multi-segment file (#1).\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } ; psf->dataoffset = offset ; psf->dataend = psf->filelength - 1 ; psf->sf.channels = 1 ; psf->bytewidth = 1 ; psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; return 0 ; } ; if (block_type == VOC_EXTENDED) { unsigned char pack, stereo, compression ; unsigned short rate_short ; int size ; offset += psf_binheader_readf (psf, "e3211", &size, &rate_short, &pack, &stereo) ; psf_log_printf (psf, " Extended : %d\n", size) ; if (size == 4) psf_log_printf (psf, " size : 4\n") ; else psf_log_printf (psf, " size : %d (should be 4)\n", size) ; psf_log_printf (psf, " pack : %d\n" " stereo : %s\n", pack, (stereo ? "yes" : "no")) ; if (stereo) { psf->sf.channels = 2 ; psf->sf.samplerate = 128000000 / (65536 - rate_short) ; } else { psf->sf.channels = 1 ; psf->sf.samplerate = 256000000 / (65536 - rate_short) ; } ; psf_log_printf (psf, " sr : %d => %dHz\n", (rate_short & 0xFFFF), psf->sf.samplerate) ; offset += psf_binheader_readf (psf, "1", &block_type) ; if (block_type != VOC_SOUND_DATA) { psf_log_printf (psf, "*** Expecting VOC_SOUND_DATA section.\n") ; return SFE_VOC_BAD_FORMAT ; } ; offset += psf_binheader_readf (psf, "e311", &size, &rate_byte, &compression) ; psf_log_printf (psf, " Sound Data : %d\n" " sr : %d\n" " comp : %d\n", size, rate_byte, compression) ; if (offset + size - 1 > psf->filelength) { psf_log_printf (psf, "Seems to be a truncated file.\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } else if (offset + size - 1 < psf->filelength) { psf_log_printf (psf, "Seems to be a multi-segment file (#2).\n") ; psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; return SFE_VOC_BAD_SECTIONS ; } ; psf->dataoffset = offset ; psf->dataend = psf->filelength - 1 ; psf->bytewidth = 1 ; psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; return 0 ; } if (block_type == VOC_EXTENDED_II) { unsigned char bitwidth, channels ; int size, fourbytes ; offset += psf_binheader_readf (psf, "e341124", &size, &psf->sf.samplerate, &bitwidth, &channels, &encoding, &fourbytes) ; if (size * 2 == psf->filelength - 39) { int temp_size = psf->filelength - 31 ; psf_log_printf (psf, " Extended II : %d (SoX bug: should be %d)\n", size, temp_size) ; size = temp_size ; } else psf_log_printf (psf, " Extended II : %d\n", size) ; psf_log_printf (psf, " sample rate : %d\n" " bit width : %d\n" " channels : %d\n", psf->sf.samplerate, bitwidth, channels) ; if (bitwidth == 16 && encoding == 0) { encoding = 4 ; psf_log_printf (psf, " encoding : 0 (SoX bug: should be 4 for 16 bit signed PCM)\n") ; } else psf_log_printf (psf, " encoding : %d => %s\n", encoding, voc_encoding2str (encoding)) ; psf_log_printf (psf, " fourbytes : %X\n", fourbytes) ; psf->sf.channels = channels ; psf->dataoffset = offset ; psf->dataend = psf->filelength - 1 ; if (size + 31 == psf->filelength + 1) { /* Hack for reading files produced using ** sf_command (SFC_UPDATE_HEADER_NOW). */ psf_log_printf (psf, "Missing zero byte at end of file.\n") ; size = psf->filelength - 30 ; psf->dataend = 0 ; } else if (size + 31 > psf->filelength) { psf_log_printf (psf, "Seems to be a truncated file.\n") ; size = psf->filelength - 31 ; } else if (size + 31 < psf->filelength) psf_log_printf (psf, "Seems to be a multi-segment file (#3).\n") ; switch (encoding) { case 0 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; psf->bytewidth = 1 ; break ; case 4 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; case 6 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_ALAW ; psf->bytewidth = 1 ; break ; case 7 : psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_ULAW ; psf->bytewidth = 1 ; break ; default : /* Unknown */ return SFE_UNKNOWN_FORMAT ; break ; } ; } ; return 0 ; } /* voc_read_header */ /*==================================================================================== */ static int voc_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int rate_const, subformat ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* VOC marker and 0x1A byte. */ psf_binheader_writef (psf, "eb1", "Creative Voice File", make_size_t (19), 0x1A) ; /* Data offset, version and other. */ psf_binheader_writef (psf, "e222", 26, 0x0114, 0x111F) ; /* Use same logic as SOX. ** If the file is mono 8 bit data, use VOC_SOUND_DATA. ** If the file is mono 16 bit data, use VOC_EXTENED. ** Otherwise use VOC_EXTENED_2. */ if (subformat == SF_FORMAT_PCM_U8 && psf->sf.channels == 1) { /* samplerate = 1000000 / (256 - rate_const) ; */ rate_const = 256 - 1000000 / psf->sf.samplerate ; /* First type marker, length, rate_const and compression */ psf_binheader_writef (psf, "e1311", VOC_SOUND_DATA, (int) (psf->datalength + 1), rate_const, 0) ; } else if (subformat == SF_FORMAT_PCM_U8 && psf->sf.channels == 2) { /* sample_rate = 128000000 / (65536 - rate_short) ; */ rate_const = 65536 - 128000000 / psf->sf.samplerate ; /* First write the VOC_EXTENDED section ** marker, length, rate_const and compression */ psf_binheader_writef (psf, "e13211", VOC_EXTENDED, 4, rate_const, 0, 1) ; /* samplerate = 1000000 / (256 - rate_const) ; */ rate_const = 256 - 1000000 / psf->sf.samplerate ; /* Now write the VOC_SOUND_DATA section ** marker, length, rate_const and compression */ psf_binheader_writef (psf, "e1311", VOC_SOUND_DATA, (int) (psf->datalength + 1), rate_const, 0) ; } else { int length ; if (psf->sf.channels < 1 || psf->sf.channels > 2) return SFE_CHANNEL_COUNT ; switch (subformat) { case SF_FORMAT_PCM_U8 : psf->bytewidth = 1 ; length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; /* Marker, length, sample rate, bitwidth, stereo flag, encoding and fourt zero bytes. */ psf_binheader_writef (psf, "e1341124", VOC_EXTENDED_II, length, psf->sf.samplerate, 16, psf->sf.channels, 4, 0) ; break ; case SF_FORMAT_PCM_16 : psf->bytewidth = 2 ; length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; /* Marker, length, sample rate, bitwidth, stereo flag, encoding and fourt zero bytes. */ psf_binheader_writef (psf, "e1341124", VOC_EXTENDED_II, length, psf->sf.samplerate, 16, psf->sf.channels, 4, 0) ; break ; case SF_FORMAT_ALAW : psf->bytewidth = 1 ; length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; psf_binheader_writef (psf, "e1341124", VOC_EXTENDED_II, length, psf->sf.samplerate, 8, psf->sf.channels, 6, 0) ; break ; case SF_FORMAT_ULAW : psf->bytewidth = 1 ; length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; psf_binheader_writef (psf, "e1341124", VOC_EXTENDED_II, length, psf->sf.samplerate, 8, psf->sf.channels, 7, 0) ; break ; default : return SFE_UNIMPLEMENTED ; } ; } ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* voc_write_header */ static int voc_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { /* Now we know for certain the length of the file we can re-write ** correct values for the FORM, 8SVX and BODY chunks. */ unsigned byte = VOC_TERMINATOR ; psf_fseek (psf, 0, SEEK_END) ; /* Write terminator */ psf_fwrite (&byte, 1, 1, psf) ; voc_write_header (psf, SF_TRUE) ; } ; return 0 ; } /* voc_close */ static const char* voc_encoding2str (int encoding) { switch (encoding) { case 0 : return "8 bit unsigned PCM" ; case 4 : return "16 bit signed PCM" ; case 6 : return "A-law" ; case 7 : return "u-law" ; default : break ; } return "*** Unknown ***" ; } /* voc_encoding2str */ /*==================================================================================== */ #if 0 static int voc_multi_init (SF_PRIVATE *psf, VOC_DATA *pvoc) { psf->sf.frames = 0 ; if (pvoc->bitwidth == 8) { psf->read_short = voc_multi_read_uc2s ; psf->read_int = voc_multi_read_uc2i ; psf->read_float = voc_multi_read_uc2f ; psf->read_double = voc_multi_read_uc2d ; return 0 ; } ; if (pvoc->bitwidth == 16) { psf->read_short = voc_multi_read_les2s ; psf->read_int = voc_multi_read_les2i ; psf->read_float = voc_multi_read_les2f ; psf->read_double = voc_multi_read_les2d ; return 0 ; } ; psf_log_printf (psf, "Error : bitwith != 8 && bitwidth != 16.\n") ; return SFE_UNIMPLEMENTED ; } /* voc_multi_read_int */ /*------------------------------------------------------------------------------------ */ static int voc_multi_read_uc2s (SF_PRIVATE *psf, short *ptr, int len) { return 0 ; } /* voc_multi_read_uc2s */ static int voc_multi_read_les2s (SF_PRIVATE *psf, short *ptr, int len) { return 0 ; } /* voc_multi_read_les2s */ static int voc_multi_read_uc2i (SF_PRIVATE *psf, int *ptr, int len) { return 0 ; } /* voc_multi_read_uc2i */ static int voc_multi_read_les2i (SF_PRIVATE *psf, int *ptr, int len) { return 0 ; } /* voc_multi_read_les2i */ static int voc_multi_read_uc2f (SF_PRIVATE *psf, float *ptr, int len) { return 0 ; } /* voc_multi_read_uc2f */ static int voc_multi_read_les2f (SF_PRIVATE *psf, float *ptr, int len) { return 0 ; } /* voc_multi_read_les2f */ static int voc_multi_read_uc2d (SF_PRIVATE *psf, double *ptr, int len) { return 0 ; } /* voc_multi_read_uc2d */ static int voc_multi_read_les2d (SF_PRIVATE *psf, double *ptr, int len) { return 0 ; } /* voc_multi_read_les2d */ #endif /*------------------------------------------------------------------------------------ Creative Voice (VOC) file format -------------------------------- ~From: galt@dsd.es.com (byte numbers are hex!) HEADER (bytes 00-19) Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block] - --------------------------------------------------------------- HEADER: ======= byte # Description ------ ------------------------------------------ 00-12 "Creative Voice File" 13 1A (eof to abort printing of file) 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation) 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) 18-19 1's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) - --------------------------------------------------------------- DATA BLOCK: =========== Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes) NOTE: Terminator Block is an exception -- it has only the TYPE byte. TYPE Description Size (3-byte int) Info ---- ----------- ----------------- ----------------------- 00 Terminator (NONE) (NONE) 01 Sound data 2+length of data * 02 Sound continue length of data Voice Data 03 Silence 3 ** 04 Marker 2 Marker# (2 bytes) 05 ASCII length of string null terminated string 06 Repeat 2 Count# (2 bytes) 07 End repeat 0 (NONE) 08 Extended 4 *** *Sound Info Format: --------------------- 00 Sample Rate 01 Compression Type 02+ Voice Data **Silence Info Format: ---------------------------- 00-01 Length of silence - 1 02 Sample Rate ***Extended Info Format: --------------------- 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate) Stereo: 65536 - (25600000/(2*sample_rate)) 02 Pack 03 Mode: 0 = mono 1 = stereo Marker# -- Driver keeps the most recent marker in a status byte Count# -- Number of repetitions + 1 Count# may be 1 to FFFE for 0 - FFFD repetitions or FFFF for endless repetitions Sample Rate -- SR byte = 256-(1000000/sample_rate) Length of silence -- in units of sampling cycle Compression Type -- of voice data 8-bits = 0 4-bits = 1 2.6-bits = 2 2-bits = 3 Multi DAC = 3+(# of channels) [interesting-- this isn't in the developer's manual] --------------------------------------------------------------------------------- Addendum submitted by Votis Kokavessis: After some experimenting with .VOC files I found out that there is a Data Block Type 9, which is not covered in the VOC.TXT file. Here is what I was able to discover about this block type: TYPE: 09 SIZE: 12 + length of data INFO: 12 (twelve) bytes INFO STRUCTURE: Bytes 0-1: (Word) Sample Rate (e.g. 44100) Bytes 2-3: zero (could be that bytes 0-3 are a DWord for Sample Rate) Byte 4: Sample Size in bits (e.g. 16) Byte 5: Number of channels (e.g. 1 for mono, 2 for stereo) Byte 6: Unknown (equal to 4 in all files I examined) Bytes 7-11: zero -------------------------------------------------------------------------------------*/ /*===================================================================================== **===================================================================================== **===================================================================================== **===================================================================================== */ /*------------------------------------------------------------------------ The following is taken from the Audio File Formats FAQ dated 2-Jan-1995 and submitted by Guido van Rossum . -------------------------------------------------------------------------- Creative Voice (VOC) file format -------------------------------- From: galt@dsd.es.com (byte numbers are hex!) HEADER (bytes 00-19) Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block] - --------------------------------------------------------------- HEADER: ------- byte # Description ------ ------------------------------------------ 00-12 "Creative Voice File" 13 1A (eof to abort printing of file) 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation) 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) - --------------------------------------------------------------- DATA BLOCK: ----------- Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes) NOTE: Terminator Block is an exception -- it has only the TYPE byte. TYPE Description Size (3-byte int) Info ---- ----------- ----------------- ----------------------- 00 Terminator (NONE) (NONE) 01 Sound data 2+length of data * 02 Sound continue length of data Voice Data 03 Silence 3 ** 04 Marker 2 Marker# (2 bytes) 05 ASCII length of string null terminated string 06 Repeat 2 Count# (2 bytes) 07 End repeat 0 (NONE) 08 Extended 4 *** *Sound Info Format: **Silence Info Format: --------------------- ---------------------------- 00 Sample Rate 00-01 Length of silence - 1 01 Compression Type 02 Sample Rate 02+ Voice Data ***Extended Info Format: --------------------- 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate) Stereo: 65536 - (25600000/(2*sample_rate)) 02 Pack 03 Mode: 0 = mono 1 = stereo Marker# -- Driver keeps the most recent marker in a status byte Count# -- Number of repetitions + 1 Count# may be 1 to FFFE for 0 - FFFD repetitions or FFFF for endless repetitions Sample Rate -- SR byte = 256-(1000000/sample_rate) Length of silence -- in units of sampling cycle Compression Type -- of voice data 8-bits = 0 4-bits = 1 2.6-bits = 2 2-bits = 3 Multi DAC = 3+(# of channels) [interesting-- this isn't in the developer's manual] Detailed description of new data blocks (VOC files version 1.20 and above): (Source is fax from Barry Boone at Creative Labs, 405/742-6622) BLOCK 8 - digitized sound attribute extension, must preceed block 1. Used to define stereo, 8 bit audio BYTE bBlockID; // = 8 BYTE nBlockLen[3]; // 3 byte length WORD wTimeConstant; // time constant = same as block 1 BYTE bPackMethod; // same as in block 1 BYTE bVoiceMode; // 0-mono, 1-stereo Data is stored left, right BLOCK 9 - data block that supersedes blocks 1 and 8. Used for stereo, 16 bit. BYTE bBlockID; // = 9 BYTE nBlockLen[3]; // length 12 plus length of sound DWORD dwSamplesPerSec; // samples per second, not time const. BYTE bBitsPerSample; // e.g., 8 or 16 BYTE bChannels; // 1 for mono, 2 for stereo WORD wFormat; // see below BYTE reserved[4]; // pad to make block w/o data // have a size of 16 bytes Valid values of wFormat are: 0x0000 8-bit unsigned PCM 0x0001 Creative 8-bit to 4-bit ADPCM 0x0002 Creative 8-bit to 3-bit ADPCM 0x0003 Creative 8-bit to 2-bit ADPCM 0x0004 16-bit signed PCM 0x0006 CCITT a-Law 0x0007 CCITT u-Law 0x02000 Creative 16-bit to 4-bit ADPCM Data is stored left, right ------------------------------------------------------------------------*/ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 40a50167-a81c-463a-9e1d-3282ff84e09d */ nyquist-3.05/nylsf/sf_unistd.h0000644000175000000620000000405711466723256015507 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* Some defines that microsoft 'forgot' to implement. */ #ifndef S_IRWXU #define S_IRWXU 0000700 /* rwx, owner */ #endif #ifndef S_IRUSR #define S_IRUSR 0000400 /* read permission, owner */ #endif #ifndef S_IWUSR #define S_IWUSR 0000200 /* write permission, owner */ #endif #ifndef S_IXUSR #define S_IXUSR 0000100 /* execute/search permission, owner */ #endif #define S_IRWXG 0000070 /* rwx, group */ #define S_IRGRP 0000040 /* read permission, group */ #define S_IWGRP 0000020 /* write permission, grougroup */ #define S_IXGRP 0000010 /* execute/search permission, group */ #define S_IRWXO 0000007 /* rwx, other */ #define S_IROTH 0000004 /* read permission, other */ #define S_IWOTH 0000002 /* write permission, other */ #define S_IXOTH 0000001 /* execute/search permission, other */ #ifndef S_ISFIFO #define S_ISFIFO(mode) (((mode) & _S_IFMT) == _S_IFIFO) #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode) & _S_IFREG) == _S_IFREG) #endif /* ** Don't know if these are still needed. ** ** #define _IFMT _S_IFMT ** #define _IFREG _S_IFREG */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 253aea6d-6299-46fd-8d06-bc5f6224c8fe */ nyquist-3.05/nylsf/wav_w64.c0000644000175000000620000004630211466723256015000 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** Copyright (C) 2004-2005 David Viens ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "wav_w64.h" /* Known WAVEFORMATEXTENSIBLE GUIDS. */ static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM = { 0x00000002, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW = { 0x00000006, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW = { 0x00000007, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; /* ** the next two are from ** http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html */ static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM = { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = { 0x00000003, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } } ; #if 0 /* maybe interesting one day to read the following through sf_read_raw */ /* http://www.bath.ac.uk/~masrwd/pvocex/pvocex.html */ static const EXT_SUBFORMAT MSGUID_SUBTYPE_PVOCEX = { 0x8312B9C2, 0x2E6E, 0x11d4, { 0xA8, 0x24, 0xDE, 0x5B, 0x96, 0xC3, 0xAB, 0x21 } } ; #endif /*------------------------------------------------------------------------------ * Private static functions. */ static int wavex_write_guid_equal (const EXT_SUBFORMAT * first, const EXT_SUBFORMAT * second) { return !memcmp (first, second, sizeof (EXT_SUBFORMAT)) ; } /* wavex_write_guid_equal */ int wav_w64_read_fmt_chunk (SF_PRIVATE *psf, WAV_FMT *wav_fmt, int structsize) { int bytesread, k, bytespersec = 0 ; memset (wav_fmt, 0, sizeof (WAV_FMT)) ; if (structsize < 16) return SFE_WAV_FMT_SHORT ; /* assume psf->rwf_endian is already properly set */ /* Read the minimal WAV file header here. */ bytesread = psf_binheader_readf (psf, "224422", &(wav_fmt->format), &(wav_fmt->min.channels), &(wav_fmt->min.samplerate), &(wav_fmt->min.bytespersec), &(wav_fmt->min.blockalign), &(wav_fmt->min.bitwidth)) ; psf_log_printf (psf, " Format : 0x%X => %s\n", wav_fmt->format, wav_w64_format_str (wav_fmt->format)) ; psf_log_printf (psf, " Channels : %d\n", wav_fmt->min.channels) ; psf_log_printf (psf, " Sample Rate : %d\n", wav_fmt->min.samplerate) ; psf_log_printf (psf, " Block Align : %d\n", wav_fmt->min.blockalign) ; if (wav_fmt->format == WAVE_FORMAT_PCM && wav_fmt->min.bitwidth == 24 && wav_fmt->min.blockalign == 4 * wav_fmt->min.channels) { psf_log_printf (psf, "\nInvalid file generated by Syntrillium's Cooledit!\n" "Treating as WAVE_FORMAT_IEEE_FLOAT 32 bit floating point file.\n\n") ; psf_log_printf (psf, " Bit Width : 24 (should be 32)\n") ; wav_fmt->min.bitwidth = 32 ; wav_fmt->format = WAVE_FORMAT_IEEE_FLOAT ; } else if (wav_fmt->min.bitwidth == 0) { switch (wav_fmt->format) { case WAVE_FORMAT_GSM610 : case WAVE_FORMAT_IPP_ITU_G_723_1 : psf_log_printf (psf, " Bit Width : %d\n", wav_fmt->min.bitwidth) ; break ; default : psf_log_printf (psf, " Bit Width : %d (should not be 0)\n", wav_fmt->min.bitwidth) ; } } else { switch (wav_fmt->format) { case WAVE_FORMAT_GSM610 : case WAVE_FORMAT_IPP_ITU_G_723_1 : psf_log_printf (psf, " Bit Width : %d (should be 0)\n", wav_fmt->min.bitwidth) ; break ; default : psf_log_printf (psf, " Bit Width : %d\n", wav_fmt->min.bitwidth) ; } } ; psf->sf.samplerate = wav_fmt->min.samplerate ; psf->sf.frames = 0 ; /* Correct this when reading data chunk. */ psf->sf.channels = wav_fmt->min.channels ; switch (wav_fmt->format) { case WAVE_FORMAT_PCM : case WAVE_FORMAT_IEEE_FLOAT : bytespersec = wav_fmt->min.samplerate * wav_fmt->min.blockalign ; if (wav_fmt->min.bytespersec != (unsigned) bytespersec) psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ; else psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; psf->bytewidth = BITWIDTH2BYTES (wav_fmt->min.bitwidth) ; break ; case WAVE_FORMAT_ALAW : case WAVE_FORMAT_MULAW : if (wav_fmt->min.bytespersec / wav_fmt->min.blockalign != wav_fmt->min.samplerate) psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, wav_fmt->min.samplerate * wav_fmt->min.blockalign) ; else psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; psf->bytewidth = 1 ; if (structsize >= 18) { bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->size20.extrabytes)) ; psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->size20.extrabytes) ; } ; break ; case WAVE_FORMAT_IMA_ADPCM : if (wav_fmt->min.bitwidth != 4) return SFE_WAV_ADPCM_NOT4BIT ; if (wav_fmt->min.channels < 1 || wav_fmt->min.channels > 2) return SFE_WAV_ADPCM_CHANNELS ; bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->ima.extrabytes), &(wav_fmt->ima.samplesperblock)) ; bytespersec = (wav_fmt->ima.samplerate * wav_fmt->ima.blockalign) / wav_fmt->ima.samplesperblock ; if (wav_fmt->ima.bytespersec != (unsigned) bytespersec) psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->ima.bytespersec, bytespersec) ; else psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->ima.bytespersec) ; psf->bytewidth = 2 ; psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->ima.extrabytes) ; psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->ima.samplesperblock) ; break ; case WAVE_FORMAT_MS_ADPCM : if (wav_fmt->msadpcm.bitwidth != 4) return SFE_WAV_ADPCM_NOT4BIT ; if (wav_fmt->msadpcm.channels < 1 || wav_fmt->msadpcm.channels > 2) return SFE_WAV_ADPCM_CHANNELS ; bytesread += psf_binheader_readf (psf, "222", &(wav_fmt->msadpcm.extrabytes), &(wav_fmt->msadpcm.samplesperblock), &(wav_fmt->msadpcm.numcoeffs)) ; bytespersec = (wav_fmt->min.samplerate * wav_fmt->min.blockalign) / wav_fmt->msadpcm.samplesperblock ; if (wav_fmt->min.bytespersec == (unsigned) bytespersec) psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; else if (wav_fmt->min.bytespersec == (wav_fmt->min.samplerate / wav_fmt->msadpcm.samplesperblock) * wav_fmt->min.blockalign) psf_log_printf (psf, " Bytes/sec : %d (should be %d (MS BUG!))\n", wav_fmt->min.bytespersec, bytespersec) ; else psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ; psf->bytewidth = 2 ; psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->msadpcm.extrabytes) ; psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->msadpcm.samplesperblock) ; if (wav_fmt->msadpcm.numcoeffs > SIGNED_SIZEOF (MS_ADPCM_WAV_FMT) / SIGNED_SIZEOF (int)) { psf_log_printf (psf, " No. of Coeffs : %d ****\n", wav_fmt->msadpcm.numcoeffs) ; wav_fmt->msadpcm.numcoeffs = SIGNED_SIZEOF (MS_ADPCM_WAV_FMT) / SIGNED_SIZEOF (int) ; } else psf_log_printf (psf, " No. of Coeffs : %d\n", wav_fmt->msadpcm.numcoeffs) ; psf_log_printf (psf, " Index Coeffs1 Coeffs2\n") ; for (k = 0 ; k < wav_fmt->msadpcm.numcoeffs ; k++) { bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->msadpcm.coeffs [k].coeff1), &(wav_fmt->msadpcm.coeffs [k].coeff2)) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), " %2d %7d %7d\n", k, wav_fmt->msadpcm.coeffs [k].coeff1, wav_fmt->msadpcm.coeffs [k].coeff2) ; psf_log_printf (psf, psf->u.cbuf) ; } ; break ; case WAVE_FORMAT_GSM610 : if (wav_fmt->gsm610.channels != 1 || wav_fmt->gsm610.blockalign != 65) return SFE_WAV_GSM610_FORMAT ; bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->gsm610.extrabytes), &(wav_fmt->gsm610.samplesperblock)) ; if (wav_fmt->gsm610.samplesperblock != 320) return SFE_WAV_GSM610_FORMAT ; bytespersec = (wav_fmt->gsm610.samplerate * wav_fmt->gsm610.blockalign) / wav_fmt->gsm610.samplesperblock ; if (wav_fmt->gsm610.bytespersec != (unsigned) bytespersec) psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->gsm610.bytespersec, bytespersec) ; else psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->gsm610.bytespersec) ; psf->bytewidth = 2 ; psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->gsm610.extrabytes) ; psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->gsm610.samplesperblock) ; break ; case WAVE_FORMAT_EXTENSIBLE : if (wav_fmt->ext.bytespersec / wav_fmt->ext.blockalign != wav_fmt->ext.samplerate) psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->ext.bytespersec, wav_fmt->ext.samplerate * wav_fmt->ext.blockalign) ; else psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->ext.bytespersec) ; bytesread += psf_binheader_readf (psf, "224", &(wav_fmt->ext.extrabytes), &(wav_fmt->ext.validbits), &(wav_fmt->ext.channelmask)) ; psf_log_printf (psf, " Valid Bits : %d\n", wav_fmt->ext.validbits) ; psf_log_printf (psf, " Channel Mask : 0x%X\n", wav_fmt->ext.channelmask) ; bytesread += psf_binheader_readf (psf, "422", &(wav_fmt->ext.esf.esf_field1), &(wav_fmt->ext.esf.esf_field2), &(wav_fmt->ext.esf.esf_field3)) ; /* compare the esf_fields with each known GUID? and print? */ psf_log_printf (psf, " Subformat\n") ; psf_log_printf (psf, " esf_field1 : 0x%X\n", wav_fmt->ext.esf.esf_field1) ; psf_log_printf (psf, " esf_field2 : 0x%X\n", wav_fmt->ext.esf.esf_field2) ; psf_log_printf (psf, " esf_field3 : 0x%X\n", wav_fmt->ext.esf.esf_field3) ; psf_log_printf (psf, " esf_field4 : ") ; for (k = 0 ; k < 8 ; k++) { bytesread += psf_binheader_readf (psf, "1", &(wav_fmt->ext.esf.esf_field4 [k])) ; psf_log_printf (psf, "0x%X ", wav_fmt->ext.esf.esf_field4 [k] & 0xFF) ; } ; psf_log_printf (psf, "\n") ; psf->bytewidth = BITWIDTH2BYTES (wav_fmt->ext.bitwidth) ; /* Compare GUIDs for known ones. */ if (wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_PCM) || wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM)) { psf->sf.format = SF_FORMAT_WAVEX | u_bitwidth_to_subformat (psf->bytewidth * 8) ; psf_log_printf (psf, " format : pcm\n") ; } else if (wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_MS_ADPCM)) { psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM) ; psf_log_printf (psf, " format : ms adpcm\n") ; } else if (wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_IEEE_FLOAT) || wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM)) { psf->sf.format = SF_FORMAT_WAVEX | ((psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT) ; psf_log_printf (psf, " format : IEEE float\n") ; } else if (wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_ALAW)) { psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_ALAW) ; psf_log_printf (psf, " format : A-law\n") ; } else if (wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_MULAW)) { psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_ULAW) ; psf_log_printf (psf, " format : u-law\n") ; } else return SFE_UNIMPLEMENTED ; break ; case WAVE_FORMAT_G721_ADPCM : psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->g72x.bytespersec) ; if (structsize >= 20) { bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->g72x.extrabytes), &(wav_fmt->g72x.auxblocksize)) ; if (wav_fmt->g72x.extrabytes == 0) psf_log_printf (psf, " Extra Bytes : %d (should be 2)\n", wav_fmt->g72x.extrabytes) ; else psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->g72x.extrabytes) ; psf_log_printf (psf, " Aux Blk Size : %d\n", wav_fmt->g72x.auxblocksize) ; } else if (structsize == 18) { bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->g72x.extrabytes)) ; psf_log_printf (psf, " Extra Bytes : %d%s\n", wav_fmt->g72x.extrabytes, wav_fmt->g72x.extrabytes != 0 ? " (should be 0)" : "") ; } else psf_log_printf (psf, "*** 'fmt ' chunk should be bigger than this!\n") ; break ; default : psf_log_printf (psf, "*** No 'fmt ' chunk dumper for this format!\n") ; break ; } ; if (bytesread > structsize) { psf_log_printf (psf, "*** wav_w64_read_fmt_chunk (bytesread > structsize)\n") ; return SFE_W64_FMT_SHORT ; } else psf_binheader_readf (psf, "j", structsize - bytesread) ; psf->blockwidth = wav_fmt->min.channels * psf->bytewidth ; return 0 ; } /* wav_w64_read_fmt_chunk */ void wavex_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat) { psf_binheader_writef (psf, "422b", subformat->esf_field1, subformat->esf_field2, subformat->esf_field3, subformat->esf_field4, make_size_t (8)) ; } /* wavex_write_guid */ /*============================================================================== */ typedef struct { int ID ; const char *name ; } WAV_FORMAT_DESC ; #define STR(x) #x #define FORMAT_TYPE(x) { x, STR (x) } static WAV_FORMAT_DESC wave_descs [] = { FORMAT_TYPE (WAVE_FORMAT_PCM), FORMAT_TYPE (WAVE_FORMAT_MS_ADPCM), FORMAT_TYPE (WAVE_FORMAT_IEEE_FLOAT), FORMAT_TYPE (WAVE_FORMAT_VSELP), FORMAT_TYPE (WAVE_FORMAT_IBM_CVSD), FORMAT_TYPE (WAVE_FORMAT_ALAW), FORMAT_TYPE (WAVE_FORMAT_MULAW), FORMAT_TYPE (WAVE_FORMAT_OKI_ADPCM), FORMAT_TYPE (WAVE_FORMAT_IMA_ADPCM), FORMAT_TYPE (WAVE_FORMAT_MEDIASPACE_ADPCM), FORMAT_TYPE (WAVE_FORMAT_SIERRA_ADPCM), FORMAT_TYPE (WAVE_FORMAT_G723_ADPCM), FORMAT_TYPE (WAVE_FORMAT_DIGISTD), FORMAT_TYPE (WAVE_FORMAT_DIGIFIX), FORMAT_TYPE (WAVE_FORMAT_DIALOGIC_OKI_ADPCM), FORMAT_TYPE (WAVE_FORMAT_MEDIAVISION_ADPCM), FORMAT_TYPE (WAVE_FORMAT_CU_CODEC), FORMAT_TYPE (WAVE_FORMAT_YAMAHA_ADPCM), FORMAT_TYPE (WAVE_FORMAT_SONARC), FORMAT_TYPE (WAVE_FORMAT_DSPGROUP_TRUESPEECH), FORMAT_TYPE (WAVE_FORMAT_ECHOSC1), FORMAT_TYPE (WAVE_FORMAT_AUDIOFILE_AF36), FORMAT_TYPE (WAVE_FORMAT_APTX), FORMAT_TYPE (WAVE_FORMAT_AUDIOFILE_AF10), FORMAT_TYPE (WAVE_FORMAT_PROSODY_1612), FORMAT_TYPE (WAVE_FORMAT_LRC), FORMAT_TYPE (WAVE_FORMAT_DOLBY_AC2), FORMAT_TYPE (WAVE_FORMAT_GSM610), FORMAT_TYPE (WAVE_FORMAT_MSNAUDIO), FORMAT_TYPE (WAVE_FORMAT_ANTEX_ADPCME), FORMAT_TYPE (WAVE_FORMAT_CONTROL_RES_VQLPC), FORMAT_TYPE (WAVE_FORMAT_DIGIREAL), FORMAT_TYPE (WAVE_FORMAT_DIGIADPCM), FORMAT_TYPE (WAVE_FORMAT_CONTROL_RES_CR10), FORMAT_TYPE (WAVE_FORMAT_NMS_VBXADPCM), FORMAT_TYPE (WAVE_FORMAT_ROLAND_RDAC), FORMAT_TYPE (WAVE_FORMAT_ECHOSC3), FORMAT_TYPE (WAVE_FORMAT_ROCKWELL_ADPCM), FORMAT_TYPE (WAVE_FORMAT_ROCKWELL_DIGITALK), FORMAT_TYPE (WAVE_FORMAT_XEBEC), FORMAT_TYPE (WAVE_FORMAT_G721_ADPCM), FORMAT_TYPE (WAVE_FORMAT_G728_CELP), FORMAT_TYPE (WAVE_FORMAT_MSG723), FORMAT_TYPE (WAVE_FORMAT_MPEG), FORMAT_TYPE (WAVE_FORMAT_RT24), FORMAT_TYPE (WAVE_FORMAT_PAC), FORMAT_TYPE (WAVE_FORMAT_MPEGLAYER3), FORMAT_TYPE (WAVE_FORMAT_LUCENT_G723), FORMAT_TYPE (WAVE_FORMAT_CIRRUS), FORMAT_TYPE (WAVE_FORMAT_ESPCM), FORMAT_TYPE (WAVE_FORMAT_VOXWARE), FORMAT_TYPE (WAVE_FORMAT_CANOPUS_ATRAC), FORMAT_TYPE (WAVE_FORMAT_G726_ADPCM), FORMAT_TYPE (WAVE_FORMAT_G722_ADPCM), FORMAT_TYPE (WAVE_FORMAT_DSAT), FORMAT_TYPE (WAVE_FORMAT_DSAT_DISPLAY), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_BYTE_ALIGNED), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC8), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC10), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC16), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC20), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_RT24), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_RT29), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_RT29HW), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_VR12), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_VR18), FORMAT_TYPE (WAVE_FORMAT_VOXWARE_TQ40), FORMAT_TYPE (WAVE_FORMAT_SOFTSOUND), FORMAT_TYPE (WAVE_FORMAT_VOXARE_TQ60), FORMAT_TYPE (WAVE_FORMAT_MSRT24), FORMAT_TYPE (WAVE_FORMAT_G729A), FORMAT_TYPE (WAVE_FORMAT_MVI_MV12), FORMAT_TYPE (WAVE_FORMAT_DF_G726), FORMAT_TYPE (WAVE_FORMAT_DF_GSM610), FORMAT_TYPE (WAVE_FORMAT_ONLIVE), FORMAT_TYPE (WAVE_FORMAT_SBC24), FORMAT_TYPE (WAVE_FORMAT_DOLBY_AC3_SPDIF), FORMAT_TYPE (WAVE_FORMAT_ZYXEL_ADPCM), FORMAT_TYPE (WAVE_FORMAT_PHILIPS_LPCBB), FORMAT_TYPE (WAVE_FORMAT_PACKED), FORMAT_TYPE (WAVE_FORMAT_RHETOREX_ADPCM), FORMAT_TYPE (IBM_FORMAT_MULAW), FORMAT_TYPE (IBM_FORMAT_ALAW), FORMAT_TYPE (IBM_FORMAT_ADPCM), FORMAT_TYPE (WAVE_FORMAT_VIVO_G723), FORMAT_TYPE (WAVE_FORMAT_VIVO_SIREN), FORMAT_TYPE (WAVE_FORMAT_DIGITAL_G723), FORMAT_TYPE (WAVE_FORMAT_CREATIVE_ADPCM), FORMAT_TYPE (WAVE_FORMAT_CREATIVE_FASTSPEECH8), FORMAT_TYPE (WAVE_FORMAT_CREATIVE_FASTSPEECH10), FORMAT_TYPE (WAVE_FORMAT_QUARTERDECK), FORMAT_TYPE (WAVE_FORMAT_FM_TOWNS_SND), FORMAT_TYPE (WAVE_FORMAT_BZV_DIGITAL), FORMAT_TYPE (WAVE_FORMAT_VME_VMPCM), FORMAT_TYPE (WAVE_FORMAT_OLIGSM), FORMAT_TYPE (WAVE_FORMAT_OLIADPCM), FORMAT_TYPE (WAVE_FORMAT_OLICELP), FORMAT_TYPE (WAVE_FORMAT_OLISBC), FORMAT_TYPE (WAVE_FORMAT_OLIOPR), FORMAT_TYPE (WAVE_FORMAT_LH_CODEC), FORMAT_TYPE (WAVE_FORMAT_NORRIS), FORMAT_TYPE (WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS), FORMAT_TYPE (WAVE_FORMAT_DVM), FORMAT_TYPE (WAVE_FORMAT_INTERWAV_VSC112), FORMAT_TYPE (WAVE_FORMAT_IPP_ITU_G_723_1), FORMAT_TYPE (WAVE_FORMAT_EXTENSIBLE), } ; char const* wav_w64_format_str (int k) { int lower, upper, mid ; lower = -1 ; upper = sizeof (wave_descs) / sizeof (WAV_FORMAT_DESC) ; /* binary search */ if ((wave_descs [0].ID <= k) && (k <= wave_descs [upper - 1].ID)) { while (lower + 1 < upper) { mid = (upper + lower) / 2 ; if (k == wave_descs [mid].ID) return wave_descs [mid].name ; if (k < wave_descs [mid].ID) upper = mid ; else lower = mid ; } ; } ; return "Unknown format" ; } /* wav_w64_format_str */ int wav_w64_srate2blocksize (int srate_chan_product) { if (srate_chan_product < 12000) return 256 ; if (srate_chan_product < 23000) return 512 ; if (srate_chan_product < 44000) return 1024 ; return 2048 ; } /* srate2blocksize */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 43c1b1dd-8abd-43da-a8cd-44da914b64a5 */ nyquist-3.05/nylsf/README.txt0000644000175000000620000000156111466723256015033 0ustar stevestaffThis is libsndfile-1.0.17. I could not find an easy way to build a universal binary for libsndfile, so I performed the following steps: 1) configure and build libsndfile-1.0.17 for the Mac on an intel (i386) machine (I don't know if this modifies the src directory at all) 2) cd to this directory 2) cp ~/libsndfile-1.0.17/src/*.[ch] . 3) mkdir nylsf/G72x/ 4) cp ~/libsndfile-1.0.17/src/G72x/*.[ch] G72x 5) cp ~/libsndfile-1.0.17/src/G72x/README.original G72x 6) mkdir nylsf/GSM610/ 7) cp ~/libsndfile-1.0.17/src/GSM610/*.[ch] GSM610 8) cp ~/libsndfile-1.0.17/src/GSM610/README GSM610 9) add libsndfile target to xcode project and add files to project except G72x/g72x_test.c, interleave.c, macbinary3.c, macos.c, test_endswap.c, test_file_io.c, test_log_printf.c 10) modify config.h, replacing CPU_IS_LITTLE_ENDIAN and CPU_IS_BIG_ENDIAN code to use defines nyquist-3.05/nylsf/rx2.c0000644000175000000620000002164111466723256014215 0ustar stevestaff/* ** Copyright (C) 2001-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #if (ENABLE_EXPERIMENTAL_CODE == 0) int rx2_open (SF_PRIVATE *psf) { if (psf) return SFE_UNIMPLEMENTED ; return (psf && 0) ; } /* rx2_open */ #else /*------------------------------------------------------------------------------ * Macros to handle big/little endian issues. */ #define CAT_MARKER (MAKE_MARKER ('C', 'A', 'T', ' ')) #define GLOB_MARKER (MAKE_MARKER ('G', 'L', 'O', 'B')) #define RECY_MARKER (MAKE_MARKER ('R', 'E', 'C', 'Y')) #define SLCL_MARKER (MAKE_MARKER ('S', 'L', 'C', 'L')) #define SLCE_MARKER (MAKE_MARKER ('S', 'L', 'C', 'E')) #define DEVL_MARKER (MAKE_MARKER ('D', 'E', 'V', 'L')) #define TRSH_MARKER (MAKE_MARKER ('T', 'R', 'S', 'H')) #define EQ_MARKER (MAKE_MARKER ('E', 'Q', ' ', ' ')) #define COMP_MARKER (MAKE_MARKER ('C', 'O', 'M', 'P')) #define SINF_MARKER (MAKE_MARKER ('S', 'I', 'N', 'F')) #define SDAT_MARKER (MAKE_MARKER ('S', 'D', 'A', 'T')) /*------------------------------------------------------------------------------ * Typedefs for file chunks. */ /*------------------------------------------------------------------------------ * Private static functions. */ static int rx2_close (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public functions. */ int rx2_open (SF_PRIVATE *psf) { static const char *marker_type [4] = { "Original Enabled", "Enabled Hidden", "Additional/PencilTool", "Disabled" } ; int error, marker, length, glob_offset, slce_count, frames ; int sdat_length = 0, slce_total = 0 ; int n_channels ; /* So far only doing read. */ psf_binheader_readf (psf, "Epm4", 0, &marker, &length) ; if (marker != CAT_MARKER) { psf_log_printf (psf, "length : %d\n", length) ; return -1000 ; } ; if (length != psf->filelength - 8) psf_log_printf (psf, "%M : %d (should be %d)\n", marker, length, psf->filelength - 8) ; else psf_log_printf (psf, "%M : %d\n", marker, length) ; /* 'REX2' marker */ psf_binheader_readf (psf, "m", &marker) ; psf_log_printf (psf, "%M", marker) ; /* 'HEAD' marker */ psf_binheader_readf (psf, "m", &marker) ; psf_log_printf (psf, "%M\n", marker) ; /* Grab 'GLOB' offset. */ psf_binheader_readf (psf, "E4", &glob_offset) ; glob_offset += 0x14 ; /* Add the current file offset. */ /* Jump to offset 0x30 */ psf_binheader_readf (psf, "p", 0x30) ; /* Get name length */ length = 0 ; psf_binheader_readf (psf, "1", &length) ; if (length >= SIGNED_SIZEOF (psf->u.cbuf)) { psf_log_printf (psf, " Text : %d *** Error : Too sf_count_t!\n") ; return -1001 ; } memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ; psf_binheader_readf (psf, "b", psf->u.cbuf, length) ; psf_log_printf (psf, " Text : \"%s\"\n", psf->u.cbuf) ; /* Jump to GLOB offset position. */ if (glob_offset & 1) glob_offset ++ ; psf_binheader_readf (psf, "p", glob_offset) ; slce_count = 0 ; /* GLOB */ while (1) { psf_binheader_readf (psf, "m", &marker) ; if (marker != SLCE_MARKER && slce_count > 0) { psf_log_printf (psf, " SLCE count : %d\n", slce_count) ; slce_count = 0 ; } switch (marker) { case GLOB_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; psf_binheader_readf (psf, "j", length) ; break ; case RECY_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; psf_binheader_readf (psf, "j", (length+1) & 0xFFFFFFFE) ; /* ?????? */ break ; case CAT_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; /*-psf_binheader_readf (psf, "j", length) ;-*/ break ; case DEVL_MARKER: psf_binheader_readf (psf, "mE4", &marker, &length) ; psf_log_printf (psf, " DEVL%M : %d\n", marker, length) ; if (length & 1) length ++ ; psf_binheader_readf (psf, "j", length) ; break ; case EQ_MARKER: case COMP_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; /* This is weird!!!! why make this (length - 1) */ if (length & 1) length ++ ; psf_binheader_readf (psf, "j", length) ; break ; case SLCL_MARKER: psf_log_printf (psf, " %M\n (Offset, Next Offset, Type)\n", marker) ; slce_count = 0 ; break ; case SLCE_MARKER: { int len [4], indx ; psf_binheader_readf (psf, "E4444", &len [0], &len [1], &len [2], &len [3]) ; indx = ((len [3] & 0x0000FFFF) >> 8) & 3 ; if (len [2] == 1) { if (indx != 1) indx = 3 ; /* 2 cases, where next slice offset = 1 -> disabled & enabled/hidden */ psf_log_printf (psf, " %M : (%6d, ?: 0x%X, %s)\n", marker, len [1], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ; } else { slce_total += len [2] ; psf_log_printf (psf, " %M : (%6d, SLCE_next_ofs:%d, ?: 0x%X, %s)\n", marker, len [1], len [2], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ; } ; slce_count ++ ; } ; break ; case SINF_MARKER: psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " %M : %d\n", marker, length) ; psf_binheader_readf (psf, "E2", &n_channels) ; n_channels = (n_channels & 0x0000FF00) >> 8 ; psf_log_printf (psf, " Channels : %d\n", n_channels) ; psf_binheader_readf (psf, "E44", &psf->sf.samplerate, &frames) ; psf->sf.frames = frames ; psf_log_printf (psf, " Sample Rate : %d\n", psf->sf.samplerate) ; psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " ??????????? : %d\n", length) ; psf_binheader_readf (psf, "E4", &length) ; psf_log_printf (psf, " ??????????? : %d\n", length) ; break ; case SDAT_MARKER: psf_binheader_readf (psf, "E4", &length) ; sdat_length = length ; /* Get the current offset. */ psf->dataoffset = psf_binheader_readf (psf, NULL) ; if (psf->dataoffset + length != psf->filelength) psf_log_printf (psf, " %M : %d (should be %d)\n", marker, length, psf->dataoffset + psf->filelength) ; else psf_log_printf (psf, " %M : %d\n", marker, length) ; break ; default : psf_log_printf (psf, "Unknown marker : 0x%X %M", marker, marker) ; return -1003 ; break ; } ; /* SDAT always last marker in file. */ if (marker == SDAT_MARKER) break ; } ; puts (psf->logbuffer) ; puts ("-----------------------------------") ; printf ("SDAT length : %d\n", sdat_length) ; printf ("SLCE count : %d\n", slce_count) ; /* Hack for zero slice count. */ if (slce_count == 0 && slce_total == 1) slce_total = frames ; printf ("SLCE samples : %d\n", slce_total) ; /* Two bytes per sample. */ printf ("Comp Ratio : %f:1\n", (2.0 * slce_total * n_channels) / sdat_length) ; puts (" ") ; psf->logbuffer [0] = 0 ; /* OK, have the header although not too sure what it all means. */ psf->endian = SF_ENDIAN_BIG ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf_fseek (psf, psf->dataoffset, SEEK_SET)) return SFE_BAD_SEEK ; psf->sf.format = (SF_FORMAT_REX2 | SF_FORMAT_DWVW_12) ; psf->sf.channels = 1 ; psf->bytewidth = 2 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; if ((error = dwvw_init (psf, 16))) return error ; psf->container_close = rx2_close ; if (! psf->sf.frames && psf->blockwidth) psf->sf.frames = psf->datalength / psf->blockwidth ; /* All done. */ return 0 ; } /* rx2_open */ /*------------------------------------------------------------------------------ */ static int rx2_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE) { /* Now we know for certain the length of the file we can re-write ** correct values for the FORM, 8SVX and BODY chunks. */ } ; return 0 ; } /* rx2_close */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 7366e813-9fee-4d1f-881e-e4a691469370 */ nyquist-3.05/nylsf/wve.c0000644000175000000620000000641111466723256014301 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #if (ENABLE_EXPERIMENTAL_CODE == 0) int wve_open (SF_PRIVATE *psf) { if (psf) return SFE_UNIMPLEMENTED ; return (psf && 0) ; } /* wve_open */ #else #define SFE_WVE_NOT_WVE 666 /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define ALAW_MARKER MAKE_MARKER ('A', 'L', 'a', 'w') #define SOUN_MARKER MAKE_MARKER ('S', 'o', 'u', 'n') #define DFIL_MARKER MAKE_MARKER ('d', 'F', 'i', 'l') /*------------------------------------------------------------------------------ ** Private static functions. */ static int wve_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int wve_open (SF_PRIVATE *psf) { int subformat, error = 0 ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) return SFE_UNIMPLEMENTED ; if ((error = wve_read_header (psf))) return error ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WVE) return SFE_BAD_OPEN_FORMAT ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; return error ; } /* wve_open */ /*------------------------------------------------------------------------------ */ static int wve_read_header (SF_PRIVATE *psf) { int marker ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "pm", 0, &marker) ; if (marker != ALAW_MARKER) return SFE_WVE_NOT_WVE ; psf_binheader_readf (psf, "m", &marker) ; if (marker != SOUN_MARKER) return SFE_WVE_NOT_WVE ; psf_binheader_readf (psf, "m", &marker) ; if (marker != DFIL_MARKER) return SFE_WVE_NOT_WVE ; psf_log_printf (psf, "Read only : Psion Palmtop Alaw (.wve)\n" " Sample Rate : 8000\n" " Channels : 1\n" " Encoding : A-law\n") ; psf->dataoffset = 0x20 ; psf->datalength = psf->filelength - psf->dataoffset ; psf->sf.format = SF_FORMAT_WVE | SF_FORMAT_ALAW ; psf->sf.samplerate = 8000 ; psf->sf.frames = psf->datalength ; psf->sf.channels = 1 ; return alaw_init (psf) ; } /* wve_read_header */ /*------------------------------------------------------------------------------ */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: ba368cb5-523f-45e4-98c1-5b99a102f73f */ nyquist-3.05/nylsf/strings.c0000644000175000000620000001275311466723256015177 0ustar stevestaff/* ** Copyright (C) 2001-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "common.h" #define STRINGS_DEBUG 0 #if STRINGS_DEBUG static void hexdump (void *data, int len) ; #endif int psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) { static char lsf_name [] = PACKAGE "-" VERSION ; static char bracket_name [] = " (" PACKAGE "-" VERSION ")" ; int k, str_len, len_remaining, str_flags ; if (str == NULL) return SFE_STR_BAD_STRING ; str_len = strlen (str) ; /* A few extra checks for write mode. */ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->str_flags & SF_STR_ALLOW_START) == 0) return SFE_STR_NO_SUPPORT ; if ((psf->str_flags & SF_STR_ALLOW_END) == 0) return SFE_STR_NO_SUPPORT ; /* Only allow zero length strings for software. */ if (str_type != SF_STR_SOFTWARE && str_len == 0) return SFE_STR_BAD_STRING ; } ; /* Determine flags */ str_flags = SF_STR_LOCATE_START ; if (psf->have_written) { if ((psf->str_flags & SF_STR_ALLOW_END) == 0) return SFE_STR_NO_ADD_END ; str_flags = SF_STR_LOCATE_END ; } ; /* Find next free slot in table. */ for (k = 0 ; k < SF_MAX_STRINGS ; k++) if (psf->strings [k].type == 0) break ; /* More sanity checking. */ if (k >= SF_MAX_STRINGS) return SFE_STR_MAX_COUNT ; if (k == 0 && psf->str_end != NULL) { psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->str_end != NULL\n") ; return SFE_STR_WEIRD ; } ; if (k != 0 && psf->str_end == NULL) { psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->str_end == NULL\n") ; return SFE_STR_WEIRD ; } ; /* Special case for the first string. */ if (k == 0) psf->str_end = psf->str_storage ; #if STRINGS_DEBUG psf_log_printf (psf, "str_storage : %X\n", (int) psf->str_storage) ; psf_log_printf (psf, "str_end : %X\n", (int) psf->str_end) ; psf_log_printf (psf, "sizeof (str_storage) : %d\n", SIGNED_SIZEOF (psf->str_storage)) ; #endif len_remaining = SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage) ; if (len_remaining < str_len + 2) return SFE_STR_MAX_DATA ; switch (str_type) { case SF_STR_SOFTWARE : /* In write mode, want to append libsndfile-version to string. */ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->strings [k].type = str_type ; psf->strings [k].str = psf->str_end ; psf->strings [k].flags = str_flags ; memcpy (psf->str_end, str, str_len + 1) ; psf->str_end += str_len ; /* ** If the supplied string does not already contain a ** libsndfile-X.Y.Z component, then add it. */ if (strstr (str, PACKAGE) == NULL && len_remaining > (int) (strlen (bracket_name) + str_len + 2)) { if (strlen (str) == 0) strncat (psf->str_end, lsf_name, len_remaining) ; else strncat (psf->str_end, bracket_name, len_remaining) ; psf->str_end += strlen (psf->str_end) ; } ; /* Plus one to catch string terminator. */ psf->str_end += 1 ; break ; } ; /* Fall though if not write mode. */ case SF_STR_TITLE : case SF_STR_COPYRIGHT : case SF_STR_ARTIST : case SF_STR_COMMENT : case SF_STR_DATE : psf->strings [k].type = str_type ; psf->strings [k].str = psf->str_end ; psf->strings [k].flags = str_flags ; /* Plus one to catch string terminator. */ memcpy (psf->str_end, str, str_len + 1) ; psf->str_end += str_len + 1 ; break ; default : return SFE_STR_BAD_TYPE ; } ; psf->str_flags |= (psf->have_written) ? SF_STR_LOCATE_END : SF_STR_LOCATE_START ; #if STRINGS_DEBUG hexdump (psf->str_storage, 300) ; #endif return 0 ; } /* psf_store_string */ int psf_set_string (SF_PRIVATE *psf, int str_type, const char *str) { if (psf->mode == SFM_READ) return SFE_STR_NOT_WRITE ; return psf_store_string (psf, str_type, str) ; } /* psf_set_string */ const char* psf_get_string (SF_PRIVATE *psf, int str_type) { int k ; for (k = 0 ; k < SF_MAX_STRINGS ; k++) if (str_type == psf->strings [k].type) return psf->strings [k].str ; return NULL ; } /* psf_get_string */ #if STRINGS_DEBUG #include static void hexdump (void *data, int len) { unsigned char *ptr ; int k ; ptr = data ; puts ("---------------------------------------------------------") ; while (len >= 16) { for (k = 0 ; k < 16 ; k++) printf ("%02X ", ptr [k] & 0xFF) ; printf (" ") ; for (k = 0 ; k < 16 ; k++) printf ("%c", isprint (ptr [k]) ? ptr [k] : '.') ; puts ("") ; ptr += 16 ; len -= 16 ; } ; } /* hexdump */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 04393aa1-9389-46fe-baf2-58a7bd544fd6 */ nyquist-3.05/nylsf/ulaw.c0000644000175000000620000016672011466723256014462 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sndfile.h" #include "float_cast.h" #include "common.h" static sf_count_t ulaw_read_ulaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t ulaw_read_ulaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t ulaw_read_ulaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t ulaw_read_ulaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t ulaw_write_s2ulaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t ulaw_write_i2ulaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t ulaw_write_f2ulaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t ulaw_write_d2ulaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; int ulaw_init (SF_PRIVATE *psf) { if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { psf->read_short = ulaw_read_ulaw2s ; psf->read_int = ulaw_read_ulaw2i ; psf->read_float = ulaw_read_ulaw2f ; psf->read_double = ulaw_read_ulaw2d ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->write_short = ulaw_write_s2ulaw ; psf->write_int = ulaw_write_i2ulaw ; psf->write_float = ulaw_write_f2ulaw ; psf->write_double = ulaw_write_d2ulaw ; } ; psf->bytewidth = 1 ; psf->blockwidth = psf->sf.channels ; if (psf->filelength > psf->dataoffset) psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; else psf->datalength = 0 ; psf->sf.frames = psf->datalength / psf->blockwidth ; return 0 ; } /* ulaw_init */ /*============================================================================== */ static short ulaw_decode [256] = { -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, -876, -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524, -492, -460, -428, -396, -372, -356, -340, -324, -308, -292, -276, -260, -244, -228, -212, -196, -180, -164, -148, -132, -120, -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 876, 844, 812, 780, 748, 716, 684, 652, 620, 588, 556, 524, 492, 460, 428, 396, 372, 356, 340, 324, 308, 292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120, 112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0 } ; static unsigned char ulaw_encode [8193] = { 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00 } ; static inline void ulaw2s_array (unsigned char *buffer, int count, short *ptr) { while (--count >= 0) ptr [count] = ulaw_decode [(int) buffer [count]] ; } /* ulaw2s_array */ static inline void ulaw2i_array (unsigned char *buffer, int count, int *ptr) { while (--count >= 0) ptr [count] = ulaw_decode [buffer [count]] << 16 ; } /* ulaw2i_array */ static inline void ulaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) { while (--count >= 0) ptr [count] = normfact * ulaw_decode [(int) buffer [count]] ; } /* ulaw2f_array */ static inline void ulaw2d_array (const unsigned char *buffer, int count, double *ptr, double normfact) { while (--count >= 0) ptr [count] = normfact * ulaw_decode [(int) buffer [count]] ; } /* ulaw2d_array */ static inline void s2ulaw_array (const short *ptr, int count, unsigned char *buffer) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = ulaw_encode [ptr [count] / 4] ; else buffer [count] = 0x7F & ulaw_encode [ptr [count] / -4] ; } ; } /* s2ulaw_array */ static inline void i2ulaw_array (const int *ptr, int count, unsigned char *buffer) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = ulaw_encode [ptr [count] >> (16 + 2)] ; else buffer [count] = 0x7F & ulaw_encode [-ptr [count] >> (16 + 2)] ; } ; } /* i2ulaw_array */ static inline void f2ulaw_array (const float *ptr, int count, unsigned char *buffer, float normfact) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = ulaw_encode [lrintf (normfact * ptr [count])] ; else buffer [count] = 0x7F & ulaw_encode [- lrintf (normfact * ptr [count])] ; } ; } /* f2ulaw_array */ static inline void d2ulaw_array (const double *ptr, int count, unsigned char *buffer, double normfact) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = ulaw_encode [lrint (normfact * ptr [count])] ; else buffer [count] = 0x7F & ulaw_encode [- lrint (normfact * ptr [count])] ; } ; } /* d2ulaw_array */ /*============================================================================== */ static sf_count_t ulaw_read_ulaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; ulaw2s_array (psf->u.ucbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* ulaw_read_ulaw2s */ static sf_count_t ulaw_read_ulaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; ulaw2i_array (psf->u.ucbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* ulaw_read_ulaw2i */ static sf_count_t ulaw_read_ulaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; ulaw2f_array (psf->u.ucbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* ulaw_read_ulaw2f */ static sf_count_t ulaw_read_ulaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; ulaw2d_array (psf->u.ucbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* ulaw_read_ulaw2d */ /*============================================================================================= */ static sf_count_t ulaw_write_s2ulaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* ulaw_write_s2ulaw */ static sf_count_t ulaw_write_i2ulaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* ulaw_write_i2ulaw */ static sf_count_t ulaw_write_f2ulaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; float normfact ; /* Factor in a divide by 4. */ normfact = (psf->norm_float == SF_TRUE) ? (0.25 * 0x7FFF) : 0.25 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; f2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* ulaw_write_f2ulaw */ static sf_count_t ulaw_write_d2ulaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; double normfact ; /* Factor in a divide by 4. */ normfact = (psf->norm_double) ? (0.25 * 0x7FFF) : 0.25 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; d2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* ulaw_write_d2ulaw */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 655cc790-f058-45e8-89c9-86967cccc37e */ nyquist-3.05/nylsf/sndfile.h0000644000175000000620000004360211466723256015134 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** sndfile.h -- system-wide definitions ** ** API documentation is in the doc/ directory of the source code tarball ** and at http://www.mega-nerd.com/libsndfile/api.html. */ #ifndef SNDFILE_H #define SNDFILE_H /* This is the version 1.0.X header file. */ #define SNDFILE_1 #include /* For the Metrowerks CodeWarrior Pro Compiler (mainly MacOS) */ #if (defined (__MWERKS__)) #include #else #include #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* The following file types can be read and written. ** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise ** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and ** SF_FORMAT_SUBMASK can be used to separate the major and minor file ** types. */ enum { /* Major formats. */ SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */ SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */ SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */ SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */ SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */ SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */ SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */ SF_FORMAT_VOC = 0x080000, /* VOC files. */ SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */ SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */ SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */ SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */ SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */ SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */ SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */ SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */ SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */ SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */ SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */ SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */ SF_FORMAT_CAF = 0x180000, /* Core Audio File format */ /* Subtypes from here on. */ SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */ SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */ SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */ SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */ SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */ SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */ SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */ SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */ SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */ SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */ SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */ SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */ SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */ SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */ SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */ SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */ SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */ SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */ SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */ SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */ SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */ SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */ /* Endian-ness options. */ SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */ SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */ SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */ SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */ SF_FORMAT_SUBMASK = 0x0000FFFF, SF_FORMAT_TYPEMASK = 0x0FFF0000, SF_FORMAT_ENDMASK = 0x30000000 } ; /* ** The following are the valid command numbers for the sf_command() ** interface. The use of these commands is documented in the file ** command.html in the doc directory of the source code distribution. */ enum { SFC_GET_LIB_VERSION = 0x1000, SFC_GET_LOG_INFO = 0x1001, SFC_GET_NORM_DOUBLE = 0x1010, SFC_GET_NORM_FLOAT = 0x1011, SFC_SET_NORM_DOUBLE = 0x1012, SFC_SET_NORM_FLOAT = 0x1013, SFC_SET_SCALE_FLOAT_INT_READ = 0x1014, SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020, SFC_GET_SIMPLE_FORMAT = 0x1021, SFC_GET_FORMAT_INFO = 0x1028, SFC_GET_FORMAT_MAJOR_COUNT = 0x1030, SFC_GET_FORMAT_MAJOR = 0x1031, SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032, SFC_GET_FORMAT_SUBTYPE = 0x1033, SFC_CALC_SIGNAL_MAX = 0x1040, SFC_CALC_NORM_SIGNAL_MAX = 0x1041, SFC_CALC_MAX_ALL_CHANNELS = 0x1042, SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043, SFC_GET_SIGNAL_MAX = 0x1044, SFC_GET_MAX_ALL_CHANNELS = 0x1045, SFC_SET_ADD_PEAK_CHUNK = 0x1050, SFC_UPDATE_HEADER_NOW = 0x1060, SFC_SET_UPDATE_HEADER_AUTO = 0x1061, SFC_FILE_TRUNCATE = 0x1080, SFC_SET_RAW_START_OFFSET = 0x1090, SFC_SET_DITHER_ON_WRITE = 0x10A0, SFC_SET_DITHER_ON_READ = 0x10A1, SFC_GET_DITHER_INFO_COUNT = 0x10A2, SFC_GET_DITHER_INFO = 0x10A3, SFC_GET_EMBED_FILE_INFO = 0x10B0, SFC_SET_CLIPPING = 0x10C0, SFC_GET_CLIPPING = 0x10C1, SFC_GET_INSTRUMENT = 0x10D0, SFC_SET_INSTRUMENT = 0x10D1, SFC_GET_LOOP_INFO = 0x10E0, SFC_GET_BROADCAST_INFO = 0x10F0, SFC_SET_BROADCAST_INFO = 0x10F1, /* Following commands for testing only. */ SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001, /* ** SFC_SET_ADD_* values are deprecated and will disappear at some ** time in the future. They are guaranteed to be here up to and ** including version 1.0.8 to avoid breakage of existng software. ** They currently do nothing and will continue to do nothing. */ SFC_SET_ADD_DITHER_ON_WRITE = 0x1070, SFC_SET_ADD_DITHER_ON_READ = 0x1071 } ; /* ** String types that can be set and read from files. Not all file types ** support this and even the file types which support one, may not support ** all string types. */ enum { SF_STR_TITLE = 0x01, SF_STR_COPYRIGHT = 0x02, SF_STR_SOFTWARE = 0x03, SF_STR_ARTIST = 0x04, SF_STR_COMMENT = 0x05, SF_STR_DATE = 0x06 } ; /* ** Use the following as the start and end index when doing metadata ** transcoding. */ #define SF_STR_FIRST SF_STR_TITLE #define SF_STR_LAST SF_STR_DATE enum { /* True and false */ SF_FALSE = 0, SF_TRUE = 1, /* Modes for opening files. */ SFM_READ = 0x10, SFM_WRITE = 0x20, SFM_RDWR = 0x30 } ; /* Public error values. These are guaranteed to remain unchanged for the duration ** of the library major version number. ** There are also a large number of private error numbers which are internal to ** the library which can change at any time. */ enum { SF_ERR_NO_ERROR = 0, SF_ERR_UNRECOGNISED_FORMAT = 1, SF_ERR_SYSTEM = 2, SF_ERR_MALFORMED_FILE = 3, SF_ERR_UNSUPPORTED_ENCODING = 4 } ; /* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */ typedef struct SNDFILE_tag SNDFILE ; /* The following typedef is system specific and is defined when libsndfile is. ** compiled. sf_count_t can be one of loff_t (Linux), off_t (*BSD), ** off64_t (Solaris), __int64_t (Win32) etc. */ /* NOTE: changed off_t to SF_COUNT_T to support compilation with Visual C++ */ #ifdef _MSC_VER /* microsoft compiler */ #define SF_COUNT_T __int64 #else #ifndef SF_COUNT_T #define SF_COUNT_T off_t #endif #endif typedef SF_COUNT_T sf_count_t ; #define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL /* A pointer to a SF_INFO structure is passed to sf_open_read () and filled in. ** On write, the SF_INFO structure is filled in by the user and passed into ** sf_open_write (). */ struct SF_INFO { sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */ int samplerate ; int channels ; int format ; int sections ; int seekable ; } ; typedef struct SF_INFO SF_INFO ; /* The SF_FORMAT_INFO struct is used to retrieve information about the sound ** file formats libsndfile supports using the sf_command () interface. ** ** Using this interface will allow applications to support new file formats ** and encoding types when libsndfile is upgraded, without requiring ** re-compilation of the application. ** ** Please consult the libsndfile documentation (particularly the information ** on the sf_command () interface) for examples of its use. */ typedef struct { int format ; const char *name ; const char *extension ; } SF_FORMAT_INFO ; /* ** Enums and typedefs for adding dither on read and write. ** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE ** and SFC_SET_DITHER_ON_READ. */ enum { SFD_DEFAULT_LEVEL = 0, SFD_CUSTOM_LEVEL = 0x40000000, SFD_NO_DITHER = 500, SFD_WHITE = 501, SFD_TRIANGULAR_PDF = 502 } ; typedef struct { int type ; double level ; const char *name ; } SF_DITHER_INFO ; /* Struct used to retrieve information about a file embedded within a ** larger file. See SFC_GET_EMBED_FILE_INFO. */ typedef struct { sf_count_t offset ; sf_count_t length ; } SF_EMBED_FILE_INFO ; /* ** Structs used to retrieve music sample information from a file. */ enum { /* ** The loop mode field in SF_INSTRUMENT will be one of the following. */ SF_LOOP_NONE = 800, SF_LOOP_FORWARD, SF_LOOP_BACKWARD, SF_LOOP_ALTERNATING } ; typedef struct { int gain ; char basenote, detune ; char velocity_lo, velocity_hi ; char key_lo, key_hi ; int loop_count ; struct { int mode ; unsigned int start ; unsigned int end ; unsigned int count ; } loops [16] ; /* make variable in a sensible way */ } SF_INSTRUMENT ; /* Struct used to retrieve loop information from a file.*/ typedef struct { short time_sig_num ; /* any positive integer > 0 */ short time_sig_den ; /* any positive power of 2 > 0 */ int loop_mode ; /* see SF_LOOP enum */ int num_beats ; /* this is NOT the amount of quarter notes !!!*/ /* a full bar of 4/4 is 4 beats */ /* a full bar of 7/8 is 7 beats */ float bpm ; /* suggestion, as it can be calculated using other fields:*/ /* file's lenght, file's sampleRate and our time_sig_den*/ /* -> bpms are always the amount of _quarter notes_ per minute */ int root_key ; /* MIDI note, or -1 for None */ int future [6] ; } SF_LOOP_INFO ; /* Struct used to retrieve broadcast (EBU) information from a file. ** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE. */ typedef struct { char description [256] ; char originator [32] ; char originator_reference [32] ; char origination_date [10] ; char origination_time [8] ; int time_reference_low ; int time_reference_high ; short version ; char umid [64] ; char reserved [190] ; unsigned int coding_history_size ; char coding_history [256] ; } SF_BROADCAST_INFO ; typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ; typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ; typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ; typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ; typedef sf_count_t (*sf_vio_tell) (void *user_data) ; struct SF_VIRTUAL_IO { sf_vio_get_filelen get_filelen ; sf_vio_seek seek ; sf_vio_read read ; sf_vio_write write ; sf_vio_tell tell ; } ; typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ; /* Open the specified file for read, write or both. On error, this will ** return a NULL pointer. To find the error number, pass a NULL SNDFILE ** to sf_perror () or sf_error_str (). ** All calls to sf_open() should be matched with a call to sf_close(). */ SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ; /* Use the existing file descriptor to create a SNDFILE object. If close_desc ** is TRUE, the file descriptor will be closed when sf_close() is called. If ** it is FALSE, the descritor will not be closed. ** When passed a descriptor like this, the library will assume that the start ** of file header is at the current file offset. This allows sound files within ** larger container files to be read and/or written. ** On error, this will return a NULL pointer. To find the error number, pass a ** NULL SNDFILE to sf_perror () or sf_error_str (). ** All calls to sf_open_fd() should be matched with a call to sf_close(). */ SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ; SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ; /* sf_error () returns a error number which can be translated to a text ** string using sf_error_number(). */ int sf_error (SNDFILE *sndfile) ; /* sf_strerror () returns to the caller a pointer to the current error message for ** the given SNDFILE. */ const char* sf_strerror (SNDFILE *sndfile) ; /* sf_error_number () allows the retrieval of the error string for each internal ** error number. ** */ const char* sf_error_number (int errnum) ; /* The following three error functions are deprecated but they will remain in the ** library for the forseeable future. The function sf_strerror() should be used ** in their place. */ int sf_perror (SNDFILE *sndfile) ; int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ; /* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */ int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ; /* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */ int sf_format_check (const SF_INFO *info) ; /* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses ** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as ** stdio.h function fseek (). ** An offset of zero with whence set to SEEK_SET will position the ** read / write pointer to the first data sample. ** On success sf_seek returns the current position in (multi-channel) ** samples from the start of the file. ** Please see the libsndfile documentation for moving the read pointer ** separately from the write pointer on files open in mode SFM_RDWR. ** On error all of these functions return -1. */ sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ; /* Functions for retrieving and setting string data within sound files. ** Not all file types support this features; AIFF and WAV do. For both ** functions, the str_type parameter must be one of the SF_STR_* values ** defined above. ** On error, sf_set_string() returns non-zero while sf_get_string() ** returns NULL. */ int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ; const char* sf_get_string (SNDFILE *sndfile, int str_type) ; /* Functions for reading/writing the waveform data of a sound file. */ sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ; sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ; /* Functions for reading and writing the data chunk in terms of frames. ** The number of items actually read/written = frames * number of channels. ** sf_xxxx_raw read/writes the raw data bytes from/to the file ** sf_xxxx_short passes data in the native short format ** sf_xxxx_int passes data in the native int format ** sf_xxxx_float passes data in the native float format ** sf_xxxx_double passes data in the native double format ** All of these read/write function return number of frames read/written. */ sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ; sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ; sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ; sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ; sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ; sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ; sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ; sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ; /* Functions for reading and writing the data chunk in terms of items. ** Otherwise similar to above. ** All of these read/write function return number of items read/written. */ sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ; sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ; sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ; sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ; sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ; sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ; sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ; sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ; /* Close the SNDFILE and clean up all memory allocations associated with this ** file. ** Returns 0 on success, or an error number. */ int sf_close (SNDFILE *sndfile) ; /* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file ** to force the writing of data to disk. If the file is opened SFM_READ ** no action is taken. */ void sf_write_sync (SNDFILE *sndfile) ; #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* SNDFILE_H */ nyquist-3.05/nylsf/avr.c0000644000175000000620000001654111466723256014275 0ustar stevestaff/* ** Copyright (C) 2004-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #define TWOBIT_MARKER (MAKE_MARKER ('2', 'B', 'I', 'T')) #define AVR_HDR_SIZE 128 #define SFE_AVR_X 666 /* ** From: hyc@hanauma.Jpl.Nasa.Gov (Howard Chu) ** ** A lot of PD software exists to play Mac .snd files on the ST. One other ** format that seems pretty popular (used by a number of commercial packages) ** is the AVR format (from Audio Visual Research). This format has a 128 byte ** header that looks like this (its actually packed, but thats not portable): */ typedef struct { int marker ; /* 2BIT */ char name [8] ; /* null-padded sample name */ short mono ; /* 0 = mono, 0xffff = stereo */ short rez ; /* 8 = 8 bit, 16 = 16 bit */ short sign ; /* 0 = unsigned, 0xffff = signed */ short loop ; /* 0 = no loop, 0xffff = looping sample */ short midi ; /* 0xffff = no MIDI note assigned, */ /* 0xffXX = single key note assignment */ /* 0xLLHH = key split, low/hi note */ int srate ; /* sample frequency in hertz */ int frames ; /* sample length in bytes or words (see rez) */ int lbeg ; /* offset to start of loop in bytes or words. */ /* set to zero if unused */ int lend ; /* offset to end of loop in bytes or words. */ /* set to sample length if unused */ short res1 ; /* Reserved, MIDI keyboard split */ short res2 ; /* Reserved, sample compression */ short res3 ; /* Reserved */ char ext [20] ; /* Additional filename space, used if (name[7] != 0) */ char user [64] ; /* User defined. Typically ASCII message */ } AVR_HEADER ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int avr_close (SF_PRIVATE *psf) ; static int avr_read_header (SF_PRIVATE *psf) ; static int avr_write_header (SF_PRIVATE *psf, int calc_length) ; /*------------------------------------------------------------------------------ ** Public function. */ int avr_open (SF_PRIVATE *psf) { int error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = avr_read_header (psf))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AVR) return SFE_BAD_OPEN_FORMAT ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; psf->endian = SF_ENDIAN_BIG ; if (avr_write_header (psf, SF_FALSE)) return psf->error ; psf->write_header = avr_write_header ; } ; psf->container_close = avr_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; error = pcm_init (psf) ; return error ; } /* avr_open */ static int avr_read_header (SF_PRIVATE *psf) { AVR_HEADER hdr ; memset (&hdr, 0, sizeof (hdr)) ; psf_binheader_readf (psf, "pmb", 0, &hdr.marker, &hdr.name, sizeof (hdr.name)) ; psf_log_printf (psf, "%M\n", hdr.marker) ; if (hdr.marker != TWOBIT_MARKER) return SFE_AVR_X ; psf_log_printf (psf, " Name : %s\n", hdr.name) ; psf_binheader_readf (psf, "E22222", &hdr.mono, &hdr.rez, &hdr.sign, &hdr.loop, &hdr.midi) ; psf->sf.channels = (hdr.mono & 1) + 1 ; psf_log_printf (psf, " Channels : %d\n Bit width : %d\n Signed : %s\n", (hdr.mono & 1) + 1, hdr.rez, hdr.sign ? "yes" : "no") ; switch ((hdr.rez << 16) + (hdr.sign & 1)) { case ((8 << 16) + 0) : psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_U8 ; psf->bytewidth = 1 ; break ; case ((8 << 16) + 1) : psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_S8 ; psf->bytewidth = 1 ; break ; case ((16 << 16) + 1) : psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; default : psf_log_printf (psf, "Error : bad rez/sign combination.\n") ; return SFE_AVR_X ; } ; psf_binheader_readf (psf, "E4444", &hdr.srate, &hdr.frames, &hdr.lbeg, &hdr.lend) ; psf->sf.frames = hdr.frames ; psf->sf.samplerate = hdr.srate ; psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; psf_log_printf (psf, " Sample rate : %d\n", psf->sf.samplerate) ; psf_binheader_readf (psf, "E222", &hdr.res1, &hdr.res2, &hdr.res3) ; psf_binheader_readf (psf, "bb", hdr.ext, sizeof (hdr.ext), hdr.user, sizeof (hdr.user)) ; psf_log_printf (psf, " Ext : %s\n User : %s\n", hdr.ext, hdr.user) ; psf->endian = SF_ENDIAN_BIG ; psf->dataoffset = AVR_HDR_SIZE ; psf->datalength = hdr.frames * (hdr.rez / 8) ; if (psf->fileoffset > 0) psf->filelength = AVR_HDR_SIZE + psf->datalength ; if (psf_ftell (psf) != psf->dataoffset) psf_binheader_readf (psf, "j", psf->dataoffset - psf_ftell (psf)) ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; if (psf->sf.frames == 0 && psf->blockwidth) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; return 0 ; } /* avr_read_header */ static int avr_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int sign ; if (psf->pipeoffset > 0) return 0 ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; /* ** Only attempt to seek if we are not writng to a pipe. If we are ** writing to a pipe we shouldn't be here anyway. */ if (psf->is_pipe == SF_FALSE) psf_fseek (psf, 0, SEEK_SET) ; psf_binheader_writef (psf, "Emz22", TWOBIT_MARKER, make_size_t (8), psf->sf.channels == 2 ? 0xFFFF : 0, psf->bytewidth * 8) ; sign = ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_U8) ? 0 : 0xFFFF ; psf_binheader_writef (psf, "E222", sign, 0, 0xFFFF) ; psf_binheader_writef (psf, "E4444", psf->sf.samplerate, psf->sf.frames, 0, 0) ; psf_binheader_writef (psf, "E222zz", 0, 0, 0, make_size_t (20), make_size_t (64)) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* avr_write_header */ static int avr_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) avr_write_header (psf, SF_TRUE) ; return 0 ; } /* avr_close */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 0823d454-f39a-4a28-a776-607f1ef33b52 */ nyquist-3.05/nylsf/float_cast.h0000644000175000000620000001315611466723256015630 0ustar stevestaff/* ** Copyright (C) 2001-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* Version 1.4 */ #ifndef FLOAT_CAST_HEADER #define FLOAT_CAST_HEADER /*============================================================================ ** On Intel Pentium processors (especially PIII and probably P4), converting ** from float to int is very slow. To meet the C specs, the code produced by ** most C compilers targeting Pentium needs to change the FPU rounding mode ** before the float to int conversion is performed. ** ** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It ** is this flushing of the pipeline which is so slow. ** ** Fortunately the ISO C99 specifications define the functions lrint, lrintf, ** llrint and llrintf which fix this problem as a side effect. ** ** On Unix-like systems, the configure process should have detected the ** presence of these functions. If they weren't found we have to replace them ** here with a standard C cast. */ /* ** The C99 prototypes for lrint and lrintf are as follows: ** ** long int lrintf (float x) ; ** long int lrint (double x) ; */ #include "sfconfig.h" /* ** The presence of the required functions are detected during the configure ** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in ** the sfconfig.h file. */ #define HAVE_LRINT_REPLACEMENT 0 #if (HAVE_LRINT && HAVE_LRINTF) /* ** These defines enable functionality introduced with the 1999 ISO C ** standard. They must be defined before the inclusion of math.h to ** engage them. If optimisation is enabled, these functions will be ** inlined. With optimisation switched off, you have to link in the ** maths library using -lm. */ #define _ISOC9X_SOURCE 1 #define _ISOC99_SOURCE 1 #define __USE_ISOC9X 1 #define __USE_ISOC99 1 #include #elif (defined (__CYGWIN__)) #include #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int /* ** The native CYGWIN lrint and lrintf functions are buggy: ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html ** and slow. ** These functions (pulled from the Public Domain MinGW math.h header) ** replace the native versions. */ static inline long double2int (double in) { long retval ; __asm__ __volatile__ ( "fistpl %0" : "=m" (retval) : "t" (in) : "st" ) ; return retval ; } /* double2int */ static inline long float2int (float in) { long retval ; __asm__ __volatile__ ( "fistpl %0" : "=m" (retval) : "t" (in) : "st" ) ; return retval ; } /* float2int */ #elif (defined (WIN32) || defined (_WIN32)) #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #include /* ** Win32 doesn't seem to have these functions. ** Therefore implement inline versions of these functions here. */ __inline long int lrint (double flt) { int intgr ; _asm { fld flt fistp intgr } ; return intgr ; } __inline long int lrintf (float flt) { int intgr ; _asm { fld flt fistp intgr } ; return intgr ; } #elif (defined (__MWERKS__) && defined (macintosh)) /* This MacOS 9 solution was provided by Stephane Letz */ #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #include #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int inline int float2int (register float in) { long res [2] ; asm { fctiw in, in stfd in, res } return res [1] ; } /* float2int */ inline int double2int (register double in) { long res [2] ; asm { fctiw in, in stfd in, res } return res [1] ; } /* double2int */ #elif (defined (__MACH__) && defined (__APPLE__)) /* For Apple MacOSX. */ #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #include #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int inline static long float2int (register float in) { int res [2] ; __asm__ __volatile__ ( "fctiw %1, %1\n\t" "stfd %1, %0" : "=m" (res) /* Output */ : "f" (in) /* Input */ : "memory" ) ; return res [1] ; } /* lrintf */ inline static long double2int (register double in) { int res [2] ; __asm__ __volatile__ ( "fctiw %1, %1\n\t" "stfd %1, %0" : "=m" (res) /* Output */ : "f" (in) /* Input */ : "memory" ) ; return res [1] ; } /* lrint */ #else #ifndef __sgi #warning "Don't have the functions lrint() and lrintf()." #warning "Replacing these functions with a standard C cast." #endif #include #define lrint(dbl) ((long) (dbl)) #define lrintf(flt) ((long) (flt)) #endif #endif /* FLOAT_CAST_HEADER */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 42db1693-ff61-4051-bac1-e4d24c4e30b7 */ nyquist-3.05/nylsf/sd2.c0000644000175000000620000004402011466723256014166 0ustar stevestaff/* ** Copyright (C) 2001-2006 Erik de Castro Lopo ** Copyright (C) 2004 Paavo Jumppanen ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** The sd2 support implemented in this file was partially sponsored ** (financially) by Paavo Jumppanen. */ /* ** Documentation on the Mac resource fork was obtained here : ** http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ * Markers. */ #define Sd2f_MARKER MAKE_MARKER ('S', 'd', '2', 'f') #define Sd2a_MARKER MAKE_MARKER ('S', 'd', '2', 'a') #define ALCH_MARKER MAKE_MARKER ('A', 'L', 'C', 'H') #define lsf1_MARKER MAKE_MARKER ('l', 's', 'f', '1') #define STR_MARKER MAKE_MARKER ('S', 'T', 'R', ' ') #define sdML_MARKER MAKE_MARKER ('s', 'd', 'M', 'L') enum { RSRC_STR = 111, RSRC_BIN } ; typedef struct { unsigned char * rsrc_data ; int rsrc_len ; int data_offset, data_length ; int map_offset, map_length ; int type_count, type_offset ; int item_offset ; int str_index, str_count ; int string_offset ; /* All the above just to get these three. */ int sample_size, sample_rate, channels ; } SD2_RSRC ; typedef struct { int type ; int id ; char name [32] ; char value [32] ; int value_len ; } STR_RSRC ; /*------------------------------------------------------------------------------ * Private static functions. */ static int sd2_close (SF_PRIVATE *psf) ; static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) ; static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) ; static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int calc_length) ; /*------------------------------------------------------------------------------ ** Public functions. */ int sd2_open (SF_PRIVATE *psf) { int subformat, error = 0, valid ; /* SD2 is always big endian. */ psf->endian = SF_ENDIAN_BIG ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->rsrclength > 0)) { psf_use_rsrc (psf, SF_TRUE) ; valid = psf_file_valid (psf) ; psf_use_rsrc (psf, SF_FALSE) ; if (! valid) { psf_log_printf (psf, "sd2_open : psf->rsrcdes < 0\n") ; return SFE_SD2_BAD_RSRC ; } ; error = sd2_parse_rsrc_fork (psf) ; if (error) goto error_cleanup ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SD2) { error = SFE_BAD_OPEN_FORMAT ; goto error_cleanup ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; psf->dataoffset = 0 ; /* Only open and write the resource in RDWR mode is its current length is zero. */ if (psf->mode == SFM_WRITE || (psf->mode == SFM_RDWR && psf->rsrclength == 0)) { psf_open_rsrc (psf, psf->mode) ; error = sd2_write_rsrc_fork (psf, SF_FALSE) ; if (error) goto error_cleanup ; /* Not needed. */ psf->write_header = NULL ; } ; psf->container_close = sd2_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */ error = pcm_init (psf) ; break ; default : error = SFE_UNIMPLEMENTED ; break ; } ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; error_cleanup: /* Close the resource fork regardless. We won't need it again. */ psf_close_rsrc (psf) ; return error ; } /* sd2_open */ /*------------------------------------------------------------------------------ */ static int sd2_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE) { /* Now we know for certain the audio_length of the file we can re-write ** correct values for the FORM, 8SVX and BODY chunks. */ } ; return 0 ; } /* sd2_close */ /*------------------------------------------------------------------------------ */ static inline void write_char (unsigned char * data, int offset, char value) { data [offset] = value ; } /* write_char */ static inline void write_short (unsigned char * data, int offset, short value) { data [offset] = value >> 8 ; data [offset + 1] = value ; } /* write_char */ static inline void write_int (unsigned char * data, int offset, int value) { data [offset] = value >> 24 ; data [offset + 1] = value >> 16 ; data [offset + 2] = value >> 8 ; data [offset + 3] = value ; } /* write_int */ static inline void write_marker (unsigned char * data, int offset, int value) { if (CPU_IS_BIG_ENDIAN) { data [offset] = value >> 24 ; data [offset + 1] = value >> 16 ; data [offset + 2] = value >> 8 ; data [offset + 3] = value ; } else { data [offset] = value ; data [offset + 1] = value >> 8 ; data [offset + 2] = value >> 16 ; data [offset + 3] = value >> 24 ; } ; } /* write_marker */ static void write_str (unsigned char * data, int offset, char * buffer, int buffer_len) { memcpy (data + offset, buffer, buffer_len) ; } /* write_str */ static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int UNUSED (calc_length)) { SD2_RSRC rsrc ; STR_RSRC str_rsrc [] = { { RSRC_STR, 1000, "_sample-size", "", 0 }, { RSRC_STR, 1001, "_sample-rate", "", 0 }, { RSRC_STR, 1002, "_channels", "", 0 }, { RSRC_BIN, 1000, "_Markers", "", 8 } } ; int k, str_offset, data_offset, next_str ; psf_use_rsrc (psf, SF_TRUE) ; memset (&rsrc, 0, sizeof (rsrc)) ; rsrc.sample_rate = psf->sf.samplerate ; rsrc.sample_size = psf->bytewidth ; rsrc.channels = psf->sf.channels ; rsrc.rsrc_data = psf->header ; rsrc.rsrc_len = sizeof (psf->header) ; memset (rsrc.rsrc_data, 0xea, rsrc.rsrc_len) ; LSF_SNPRINTF (str_rsrc [0].value, sizeof (str_rsrc [0].value), "_%d", rsrc.sample_size) ; LSF_SNPRINTF (str_rsrc [1].value, sizeof (str_rsrc [1].value), "_%d.000000", rsrc.sample_rate) ; LSF_SNPRINTF (str_rsrc [2].value, sizeof (str_rsrc [2].value), "_%d", rsrc.channels) ; for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++) { if (str_rsrc [k].value_len == 0) { str_rsrc [k].value_len = strlen (str_rsrc [k].value) ; str_rsrc [k].value [0] = str_rsrc [k].value_len - 1 ; } ; /* Turn name string into a pascal string. */ str_rsrc [k].name [0] = strlen (str_rsrc [k].name) - 1 ; } ; rsrc.data_offset = 0x100 ; /* ** Calculate data length : ** length of strings, plus the length of the sdML chunk. */ rsrc.data_length = 0 ; for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++) rsrc.data_length += str_rsrc [k].value_len + 4 ; rsrc.map_offset = rsrc.data_offset + rsrc.data_length ; /* Very start of resource fork. */ write_int (rsrc.rsrc_data, 0, rsrc.data_offset) ; write_int (rsrc.rsrc_data, 4, rsrc.map_offset) ; write_int (rsrc.rsrc_data, 8, rsrc.data_length) ; write_char (rsrc.rsrc_data, 0x30, strlen (psf->filename)) ; write_str (rsrc.rsrc_data, 0x31, psf->filename, strlen (psf->filename)) ; write_short (rsrc.rsrc_data, 0x50, 0) ; write_marker (rsrc.rsrc_data, 0x52, Sd2f_MARKER) ; write_marker (rsrc.rsrc_data, 0x56, lsf1_MARKER) ; /* Very start of resource map. */ write_int (rsrc.rsrc_data, rsrc.map_offset + 0, rsrc.data_offset) ; write_int (rsrc.rsrc_data, rsrc.map_offset + 4, rsrc.map_offset) ; write_int (rsrc.rsrc_data, rsrc.map_offset + 8, rsrc.data_length) ; /* These I don't currently understand. */ if (1) { write_char (rsrc.rsrc_data, rsrc.map_offset+ 16, 1) ; /* Next resource map. */ write_int (rsrc.rsrc_data, rsrc.map_offset + 17, 0x12345678) ; /* File ref number. */ write_short (rsrc.rsrc_data, rsrc.map_offset + 21, 0xabcd) ; /* Fork attributes. */ write_short (rsrc.rsrc_data, rsrc.map_offset + 23, 0) ; } ; /* Resource type offset. */ rsrc.type_offset = rsrc.map_offset + 30 ; write_short (rsrc.rsrc_data, rsrc.map_offset + 24, rsrc.type_offset - rsrc.map_offset - 2) ; /* Type index max. */ rsrc.type_count = 2 ; write_short (rsrc.rsrc_data, rsrc.map_offset + 28, rsrc.type_count - 1) ; rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ; rsrc.str_count = ARRAY_LEN (str_rsrc) ; rsrc.string_offset = rsrc.item_offset + (rsrc.str_count + 1) * 12 - rsrc.map_offset ; write_short (rsrc.rsrc_data, rsrc.map_offset + 26, rsrc.string_offset) ; /* Write 'STR ' resource type. */ rsrc.str_count = 3 ; write_marker (rsrc.rsrc_data, rsrc.type_offset, STR_MARKER) ; write_short (rsrc.rsrc_data, rsrc.type_offset + 4, rsrc.str_count - 1) ; write_short (rsrc.rsrc_data, rsrc.type_offset + 6, 0x12) ; /* Write 'sdML' resource type. */ write_marker (rsrc.rsrc_data, rsrc.type_offset + 8, sdML_MARKER) ; write_short (rsrc.rsrc_data, rsrc.type_offset + 12, 0) ; write_short (rsrc.rsrc_data, rsrc.type_offset + 14, 0x36) ; str_offset = rsrc.map_offset + rsrc.string_offset ; next_str = 0 ; data_offset = rsrc.data_offset ; for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++) { write_str (rsrc.rsrc_data, str_offset, str_rsrc [k].name, strlen (str_rsrc [k].name)) ; write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12, str_rsrc [k].id) ; write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 2, next_str) ; str_offset += strlen (str_rsrc [k].name) ; next_str += strlen (str_rsrc [k].name) ; write_int (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 4, data_offset - rsrc.data_offset) ; write_int (rsrc.rsrc_data, data_offset, str_rsrc [k].value_len) ; write_str (rsrc.rsrc_data, data_offset + 4, str_rsrc [k].value, str_rsrc [k].value_len) ; data_offset += 4 + str_rsrc [k].value_len ; } ; /* Finally, calculate and set map length. */ rsrc.map_length = str_offset - rsrc.map_offset ; write_int (rsrc.rsrc_data, 12, rsrc.map_length) ; write_int (rsrc.rsrc_data, rsrc.map_offset + 12, rsrc.map_length) ; rsrc.rsrc_len = rsrc.map_offset + rsrc.map_length ; psf_fwrite (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ; psf_use_rsrc (psf, SF_FALSE) ; if (psf->error) return psf->error ; return 0 ; } /* sd2_write_rsrc_fork */ /*------------------------------------------------------------------------------ */ static inline int read_char (const unsigned char * data, int offset) { return data [offset] ; } /* read_char */ static inline int read_short (const unsigned char * data, int offset) { return (data [offset] << 8) + data [offset + 1] ; } /* read_short */ static inline int read_int (const unsigned char * data, int offset) { return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; } /* read_int */ static inline int read_marker (const unsigned char * data, int offset) { if (CPU_IS_BIG_ENDIAN) return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; else if (CPU_IS_LITTLE_ENDIAN) return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (data [offset + 3] << 24) ; else return 0x666 ; } /* read_marker */ static void read_str (const unsigned char * data, int offset, char * buffer, int buffer_len) { int k ; memset (buffer, 0, buffer_len) ; for (k = 0 ; k < buffer_len - 1 ; k++) { if (isprint (data [offset + k]) == 0) return ; buffer [k] = data [offset + k] ; } ; return ; } /* read_str */ static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) { SD2_RSRC rsrc ; int k, marker, error = 0 ; psf_use_rsrc (psf, SF_TRUE) ; memset (&rsrc, 0, sizeof (rsrc)) ; rsrc.rsrc_len = psf_get_filelen (psf) ; psf_log_printf (psf, "Resource length : %d (0x%04X)\n", rsrc.rsrc_len, rsrc.rsrc_len) ; if (rsrc.rsrc_len > SIGNED_SIZEOF (psf->header)) rsrc.rsrc_data = calloc (1, rsrc.rsrc_len) ; else rsrc.rsrc_data = psf->header ; /* Read in the whole lot. */ psf_fread (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ; /* Reset the header storage because we have changed to the rsrcdes. */ psf->headindex = psf->headend = rsrc.rsrc_len ; rsrc.data_offset = read_int (rsrc.rsrc_data, 0) ; rsrc.map_offset = read_int (rsrc.rsrc_data, 4) ; rsrc.data_length = read_int (rsrc.rsrc_data, 8) ; rsrc.map_length = read_int (rsrc.rsrc_data, 12) ; if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000) { psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ; rsrc.data_offset = read_int (rsrc.rsrc_data, 0x52 + 0) + 0x52 ; rsrc.map_offset = read_int (rsrc.rsrc_data, 0x52 + 4) + 0x52 ; rsrc.data_length = read_int (rsrc.rsrc_data, 0x52 + 8) ; rsrc.map_length = read_int (rsrc.rsrc_data, 0x52 + 12) ; } ; psf_log_printf (psf, " data offset : 0x%04X\n map offset : 0x%04X\n" " data length : 0x%04X\n map length : 0x%04X\n", rsrc.data_offset, rsrc.map_offset, rsrc.data_length, rsrc.map_length) ; if (rsrc.data_offset > rsrc.rsrc_len) { psf_log_printf (psf, "Error : rsrc.data_offset (%d, 0x%x) > len\n", rsrc.data_offset, rsrc.data_offset) ; error = SFE_SD2_BAD_DATA_OFFSET ; goto parse_rsrc_fork_cleanup ; } ; if (rsrc.map_offset > rsrc.rsrc_len) { psf_log_printf (psf, "Error : rsrc.map_offset > len\n") ; error = SFE_SD2_BAD_MAP_OFFSET ; goto parse_rsrc_fork_cleanup ; } ; if (rsrc.data_length > rsrc.rsrc_len) { psf_log_printf (psf, "Error : rsrc.data_length > len\n") ; error = SFE_SD2_BAD_DATA_LENGTH ; goto parse_rsrc_fork_cleanup ; } ; if (rsrc.map_length > rsrc.rsrc_len) { psf_log_printf (psf, "Error : rsrc.map_length > len\n") ; error = SFE_SD2_BAD_MAP_LENGTH ; goto parse_rsrc_fork_cleanup ; } ; if (rsrc.data_offset + rsrc.data_length != rsrc.map_offset || rsrc.map_offset + rsrc.map_length != rsrc.rsrc_len) { psf_log_printf (psf, "Error : This does not look like a MacOSX resource fork.\n") ; error = SFE_SD2_BAD_RSRC ; goto parse_rsrc_fork_cleanup ; } ; rsrc.string_offset = rsrc.map_offset + read_short (rsrc.rsrc_data, rsrc.map_offset + 26) ; if (rsrc.string_offset > rsrc.rsrc_len) { psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ; error = SFE_SD2_BAD_RSRC ; goto parse_rsrc_fork_cleanup ; } ; rsrc.type_offset = rsrc.map_offset + 30 ; rsrc.type_count = read_short (rsrc.rsrc_data, rsrc.map_offset + 28) + 1 ; if (rsrc.type_count < 1) { psf_log_printf (psf, "Bad type count.\n") ; error = SFE_SD2_BAD_RSRC ; goto parse_rsrc_fork_cleanup ; } ; rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ; if (rsrc.item_offset < 0 || rsrc.item_offset > rsrc.rsrc_len) { psf_log_printf (psf, "Bad item offset (%d).\n", rsrc.item_offset) ; error = SFE_SD2_BAD_RSRC ; goto parse_rsrc_fork_cleanup ; } ; rsrc.str_index = -1 ; for (k = 0 ; k < rsrc.type_count ; k ++) { marker = read_marker (rsrc.rsrc_data, rsrc.type_offset + k * 8) ; if (marker == STR_MARKER) { rsrc.str_index = k ; rsrc.str_count = read_short (rsrc.rsrc_data, rsrc.type_offset + k * 8 + 4) + 1 ; error = parse_str_rsrc (psf, &rsrc) ; goto parse_rsrc_fork_cleanup ; } ; } ; psf_log_printf (psf, "No 'STR ' resource.\n") ; error = SFE_SD2_BAD_RSRC ; parse_rsrc_fork_cleanup : psf_use_rsrc (psf, SF_FALSE) ; if ((void *) rsrc.rsrc_data < (void *) psf || (void *) rsrc.rsrc_data > (void *) (psf + 1)) free (rsrc.rsrc_data) ; return error ; } /* sd2_parse_rsrc_fork */ static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) { char name [32], value [32] ; int k, str_offset, data_offset, data_len, rsrc_id ; psf_log_printf (psf, "Finding parameters :\n") ; str_offset = rsrc->string_offset ; for (k = 0 ; k < rsrc->str_count ; k++) { int slen ; slen = read_char (rsrc->rsrc_data, str_offset) ; read_str (rsrc->rsrc_data, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ; str_offset += slen + 1 ; rsrc_id = read_short (rsrc->rsrc_data, rsrc->item_offset + k * 12) ; data_offset = rsrc->data_offset + read_int (rsrc->rsrc_data, rsrc->item_offset + k * 12 + 4) ; if (data_offset < 0 || data_offset > rsrc->rsrc_len) { psf_log_printf (psf, "Bad data offset (%d)\n", data_offset) ; return SFE_SD2_BAD_DATA_OFFSET ; } ; data_len = read_int (rsrc->rsrc_data, data_offset) ; if (data_len < 0 || data_len > rsrc->rsrc_len) { psf_log_printf (psf, "Bad data length (%d).\n", data_len) ; return SFE_SD2_BAD_RSRC ; } ; slen = read_char (rsrc->rsrc_data, data_offset + 4) ; read_str (rsrc->rsrc_data, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ; psf_log_printf (psf, " %-12s 0x%04x %4d %2d %2d '%s'\n", name, data_offset, rsrc_id, data_len, slen, value) ; if (strcmp (name, "sample-size") == 0 && rsrc->sample_size == 0) rsrc->sample_size = strtol (value, NULL, 10) ; else if (strcmp (name, "sample-rate") == 0 && rsrc->sample_rate == 0) rsrc->sample_rate = strtol (value, NULL, 10) ; else if (strcmp (name, "channels") == 0 && rsrc->channels == 0) rsrc->channels = strtol (value, NULL, 10) ; } ; if (rsrc->sample_rate < 0) { psf_log_printf (psf, "Bad sample rate (%d)\n", rsrc->sample_rate) ; return SFE_SD2_BAD_RSRC ; } ; if (rsrc->channels < 0) { psf_log_printf (psf, "Bad channel count (%d)\n", rsrc->channels) ; return SFE_SD2_BAD_RSRC ; } ; psf->sf.samplerate = rsrc->sample_rate ; psf->sf.channels = rsrc->channels ; psf->bytewidth = rsrc->sample_size ; switch (rsrc->sample_size) { case 1 : psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_S8 ; break ; case 2 : psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_16 ; break ; case 3 : psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_24 ; break ; default : psf_log_printf (psf, "Bad sample size (%d)\n", rsrc->sample_size) ; return SFE_SD2_BAD_SAMPLE_SIZE ; } ; psf_log_printf (psf, "ok\n") ; return 0 ; } /* parse_str_rsrc */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 1ee183e5-6b9f-4c2c-bd0a-24f35595cefc */ nyquist-3.05/nylsf/common.h0000644000175000000620000005342511515317366015000 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #ifndef SNDFILE_COMMON_H #define SNDFILE_COMMON_H #include "sfconfig.h" #include #if HAVE_STDINT_H #include #endif #ifndef SNDFILE_H #include "sndfile.h" #elif HAVE_INTTYPES_H #include #endif #ifdef __cplusplus #error "This code is not designed to be compiled with a C++ compiler." #endif #ifdef UNUSED #elif defined (__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__ ((unused)) #elif defined (__LCLINT__) # define UNUSED(x) /*@unused@*/ x #else # define UNUSED(x) x #endif #ifdef __GNUC__ # define WARN_UNUSED __attribute__ ((warn_unused_result)) #else # define WARN_UNUSED #endif #define SF_BUFFER_LEN (8192*2) #define SF_FILENAME_LEN (512) #define SF_SYSERR_LEN (256) #define SF_MAX_STRINGS (16) #define SF_STR_BUFFER_LEN (8192) #define SF_HEADER_LEN (4100 + SF_STR_BUFFER_LEN) #define PSF_SEEK_ERROR ((sf_count_t) -1) #define BITWIDTH2BYTES(x) (((x) + 7) / 8) /* For some reason sizeof returns an unsigned value which causes ** a warning when that value is added or subtracted from a signed ** value. Use SIGNED_SIZEOF instead. */ #define SIGNED_SIZEOF(x) ((int) sizeof (x)) #define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0]))) #define SF_MAX(a,b) ((a) > (b) ? (a) : (b)) #define SF_MIN(a,b) ((a) < (b) ? (a) : (b)) enum { /* PEAK chunk location. */ SF_PEAK_START = 42, SF_PEAK_END = 43, /* PEAK chunk location. */ SF_SCALE_MAX = 52, SF_SCALE_MIN = 53, /* str_flags values. */ SF_STR_ALLOW_START = 0x0100, SF_STR_ALLOW_END = 0x0200, /* Location of strings. */ SF_STR_LOCATE_START = 0x0400, SF_STR_LOCATE_END = 0x0800, SFD_TYPEMASK = 0x0FFFFFFF } ; #define SFM_MASK (SFM_READ | SFM_WRITE | SFM_RDWR) #define SFM_UNMASK (~SFM_MASK) /*--------------------------------------------------------------------------------------- ** Formats that may be supported at some time in the future. ** When support is finalised, these values move to src/sndfile.h. */ enum { /* Work in progress. */ /* Formats supported read only. */ SF_FORMAT_WVE = 0x4020000, /* Psion ALaw Sound File */ SF_FORMAT_TXW = 0x4030000, /* Yamaha TX16 sampler file */ SF_FORMAT_DWD = 0x4040000, /* DiamondWare Digirized */ /* Following are detected but not supported. */ SF_FORMAT_OGG = 0x4090000, SF_FORMAT_REX = 0x40A0000, /* Propellorheads Rex/Rcy */ SF_FORMAT_REX2 = 0x40D0000, /* Propellorheads Rex2 */ SF_FORMAT_KRZ = 0x40E0000, /* Kurzweil sampler file */ SF_FORMAT_WMA = 0x4100000, /* Windows Media Audio. */ SF_FORMAT_SHN = 0x4110000, /* Shorten. */ /* Unsupported encodings. */ SF_FORMAT_VORBIS = 0x1001, SF_FORMAT_SVX_FIB = 0x1020, /* SVX Fibonacci Delta encoding. */ SF_FORMAT_SVX_EXP = 0x1021, /* SVX Exponential Delta encoding. */ SF_FORMAT_PCM_N = 0x1030 } ; /*--------------------------------------------------------------------------------------- ** PEAK_CHUNK - This chunk type is common to both AIFF and WAVE files although their ** endian encodings are different. */ typedef struct { double value ; /* signed value of peak */ sf_count_t position ; /* the sample frame for the peak */ } PEAK_POS ; typedef struct { /* libsndfile internal : write a PEAK chunk at the start or end of the file? */ int peak_loc ; /* WAV/AIFF */ unsigned int version ; /* version of the PEAK chunk */ unsigned int timestamp ; /* secs since 1/1/1970 */ /* CAF */ unsigned int edit_number ; #if HAVE_FLEXIBLE_ARRAY /* the per channel peak info */ PEAK_POS peaks [] ; #else /* ** This is not ISO compliant C. It works on some compilers which ** don't support the ISO standard flexible struct array which is ** used above. If your compiler doesn't like this I suggest you find ** youself a 1999 ISO C standards compilant compiler. GCC-3.X is ** highly recommended. */ PEAK_POS peaks [0] ; #endif } PEAK_INFO ; static inline PEAK_INFO * peak_info_calloc (int channels) { return calloc (1, sizeof (PEAK_INFO) + channels * sizeof (PEAK_POS)) ; } /* peak_info_calloc */ typedef struct { int type ; int flags ; char *str ; } STR_DATA ; static inline size_t make_size_t (int x) { return (size_t) x ; } /* size_t_of_int */ /*======================================================================================= ** SF_PRIVATE stuct - a pointer to this struct is passed back to the caller of the ** sf_open_XXXX functions. The caller however has no knowledge of the struct's ** contents. */ typedef struct sf_private_tag { /* Force the compiler to double align the start of buffer. */ union { double dbuf [SF_BUFFER_LEN / sizeof (double)] ; #if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8)) int64_t lbuf [SF_BUFFER_LEN / sizeof (int64_t)] ; #else long lbuf [SF_BUFFER_LEN / sizeof (double)] ; #endif float fbuf [SF_BUFFER_LEN / sizeof (float)] ; int ibuf [SF_BUFFER_LEN / sizeof (int)] ; short sbuf [SF_BUFFER_LEN / sizeof (short)] ; char cbuf [SF_BUFFER_LEN / sizeof (char)] ; signed char scbuf [SF_BUFFER_LEN / sizeof (signed char)] ; unsigned char ucbuf [SF_BUFFER_LEN / sizeof (signed char)] ; } u ; char filepath [SF_FILENAME_LEN] ; char rsrcpath [SF_FILENAME_LEN] ; char directory [SF_FILENAME_LEN] ; char filename [SF_FILENAME_LEN / 4] ; char syserr [SF_SYSERR_LEN] ; /* logbuffer and logindex should only be changed within the logging functions ** of common.c */ char logbuffer [SF_BUFFER_LEN] ; unsigned char header [SF_HEADER_LEN] ; /* Must be unsigned */ int rwf_endian ; /* Header endian-ness flag. */ /* Storage and housekeeping data for adding/reading strings from ** sound files. */ STR_DATA strings [SF_MAX_STRINGS] ; char str_storage [SF_STR_BUFFER_LEN] ; char *str_end ; int str_flags ; /* Guard value. If this changes the buffers above have overflowed. */ int Magick ; /* Index variables for maintaining logbuffer and header above. */ int logindex ; int headindex, headend ; int has_text ; int do_not_close_descriptor ; #if USE_WINDOWS_API /* ** These fields can only be used in src/file_io.c. ** They are basically the same as a windows file HANDLE. */ void *hfile, *hrsrc, *hsaved ; #else /* These fields can only be used in src/file_io.c. */ int filedes, rsrcdes, savedes ; #endif int error ; int mode ; /* Open mode : SFM_READ, SFM_WRITE or SFM_RDWR. */ int endian ; /* File endianness : SF_ENDIAN_LITTLE or SF_ENDIAN_BIG. */ int float_endswap ; /* Need to endswap float32s? */ /* ** Maximum float value for calculating the multiplier for ** float/double to short/int conversions. */ int float_int_mult ; float float_max ; /* Vairables for handling pipes. */ int is_pipe ; /* True if file is a pipe. */ sf_count_t pipeoffset ; /* Number of bytes read from a pipe. */ /* True if clipping must be performed on float->int conversions. */ int add_clipping ; SF_INFO sf ; int have_written ; /* Has a single write been done to the file? */ PEAK_INFO *peak_info ; /* Loop Info */ SF_LOOP_INFO *loop_info ; SF_INSTRUMENT *instrument ; /* Broadcast (EBU) Info */ SF_BROADCAST_INFO *broadcast_info ; /* Channel map data (if present) : an array of ints. */ int *channel_map ; sf_count_t filelength ; /* Overall length of (embedded) file. */ sf_count_t fileoffset ; /* Offset in number of bytes from beginning of file. */ sf_count_t rsrclength ; /* Length of the resource fork (if it exists). */ sf_count_t dataoffset ; /* Offset in number of bytes from beginning of file. */ sf_count_t datalength ; /* Length in bytes of the audio data. */ sf_count_t dataend ; /* Offset to file tailer. */ int blockwidth ; /* Size in bytes of one set of interleaved samples. */ int bytewidth ; /* Size in bytes of one sample (one channel). */ void *dither ; void *interleave ; int last_op ; /* Last operation; either SFM_READ or SFM_WRITE */ sf_count_t read_current ; sf_count_t write_current ; void *container_data ; /* This is a pointer to dynamically allocated file ** container format specific data. */ void *codec_data ; /* This is a pointer to dynamically allocated file ** codec format specific data. */ SF_DITHER_INFO write_dither ; SF_DITHER_INFO read_dither ; int norm_double ; int norm_float ; int auto_header ; int ieee_replace ; /* A set of file specific function pointers */ sf_count_t (*read_short) (struct sf_private_tag*, short *ptr, sf_count_t len) ; sf_count_t (*read_int) (struct sf_private_tag*, int *ptr, sf_count_t len) ; sf_count_t (*read_float) (struct sf_private_tag*, float *ptr, sf_count_t len) ; sf_count_t (*read_double) (struct sf_private_tag*, double *ptr, sf_count_t len) ; sf_count_t (*write_short) (struct sf_private_tag*, const short *ptr, sf_count_t len) ; sf_count_t (*write_int) (struct sf_private_tag*, const int *ptr, sf_count_t len) ; sf_count_t (*write_float) (struct sf_private_tag*, const float *ptr, sf_count_t len) ; sf_count_t (*write_double) (struct sf_private_tag*, const double *ptr, sf_count_t len) ; sf_count_t (*seek) (struct sf_private_tag*, int mode, sf_count_t samples_from_start) ; int (*write_header) (struct sf_private_tag*, int calc_length) ; int (*command) (struct sf_private_tag*, int command, void *data, int datasize) ; /* ** Separate close functions for the codec and the container. ** The codec close function is always called first. */ int (*codec_close) (struct sf_private_tag*) ; int (*container_close) (struct sf_private_tag*) ; char *format_desc ; /* Virtual I/O functions. */ int virtual_io ; SF_VIRTUAL_IO vio ; void *vio_user_data ; } SF_PRIVATE ; enum { SFE_NO_ERROR = SF_ERR_NO_ERROR, SFE_BAD_OPEN_FORMAT = SF_ERR_UNRECOGNISED_FORMAT, SFE_SYSTEM = SF_ERR_SYSTEM, SFE_MALFORMED_FILE = SF_ERR_MALFORMED_FILE, SFE_UNSUPPORTED_ENCODING = SF_ERR_UNSUPPORTED_ENCODING, SFE_BAD_FILE, SFE_BAD_FILE_READ, SFE_OPEN_FAILED, SFE_BAD_SNDFILE_PTR, SFE_BAD_SF_INFO_PTR, SFE_BAD_SF_INCOMPLETE, SFE_BAD_FILE_PTR, SFE_BAD_INT_PTR, SFE_BAD_STAT_SIZE, SFE_MALLOC_FAILED, SFE_UNIMPLEMENTED, SFE_BAD_READ_ALIGN, SFE_BAD_WRITE_ALIGN, SFE_UNKNOWN_FORMAT, SFE_NOT_READMODE, SFE_NOT_WRITEMODE, SFE_BAD_MODE_RW, SFE_BAD_SF_INFO, SFE_BAD_OFFSET, SFE_NO_EMBED_SUPPORT, SFE_NO_EMBEDDED_RDWR, SFE_NO_PIPE_WRITE, SFE_INTERNAL, SFE_BAD_CONTROL_CMD, SFE_BAD_ENDIAN, SFE_CHANNEL_COUNT, SFE_BAD_RDWR_FORMAT, SFE_BAD_VIRTUAL_IO, SFE_INTERLEAVE_MODE, SFE_INTERLEAVE_SEEK, SFE_INTERLEAVE_READ, SFE_BAD_SEEK, SFE_NOT_SEEKABLE, SFE_AMBIGUOUS_SEEK, SFE_WRONG_SEEK, SFE_SEEK_FAILED, SFE_BAD_OPEN_MODE, SFE_OPEN_PIPE_RDWR, SFE_RDWR_POSITION, SFE_RDWR_BAD_HEADER, SFE_STR_NO_SUPPORT, SFE_STR_NOT_WRITE, SFE_STR_MAX_DATA, SFE_STR_MAX_COUNT, SFE_STR_BAD_TYPE, SFE_STR_NO_ADD_END, SFE_STR_BAD_STRING, SFE_STR_WEIRD, SFE_WAV_NO_RIFF, SFE_WAV_NO_WAVE, SFE_WAV_NO_FMT, SFE_WAV_FMT_SHORT, SFE_WAV_BAD_FACT, SFE_WAV_BAD_PEAK, SFE_WAV_PEAK_B4_FMT, SFE_WAV_BAD_FORMAT, SFE_WAV_BAD_BLOCKALIGN, SFE_WAV_NO_DATA, SFE_WAV_BAD_LIST, SFE_WAV_ADPCM_NOT4BIT, SFE_WAV_ADPCM_CHANNELS, SFE_WAV_GSM610_FORMAT, SFE_WAV_UNKNOWN_CHUNK, SFE_WAV_WVPK_DATA, SFE_AIFF_NO_FORM, SFE_AIFF_AIFF_NO_FORM, SFE_AIFF_COMM_NO_FORM, SFE_AIFF_SSND_NO_COMM, SFE_AIFF_UNKNOWN_CHUNK, SFE_AIFF_COMM_CHUNK_SIZE, SFE_AIFF_BAD_COMM_CHUNK, SFE_AIFF_PEAK_B4_COMM, SFE_AIFF_BAD_PEAK, SFE_AIFF_NO_SSND, SFE_AIFF_NO_DATA, SFE_AIFF_RW_SSND_NOT_LAST, SFE_AU_UNKNOWN_FORMAT, SFE_AU_NO_DOTSND, SFE_AU_EMBED_BAD_LEN, SFE_RAW_READ_BAD_SPEC, SFE_RAW_BAD_BITWIDTH, SFE_RAW_BAD_FORMAT, SFE_PAF_NO_MARKER, SFE_PAF_VERSION, SFE_PAF_UNKNOWN_FORMAT, SFE_PAF_SHORT_HEADER, SFE_SVX_NO_FORM, SFE_SVX_NO_BODY, SFE_SVX_NO_DATA, SFE_SVX_BAD_COMP, SFE_SVX_BAD_NAME_LENGTH, SFE_NIST_BAD_HEADER, SFE_NIST_CRLF_CONVERISON, SFE_NIST_BAD_ENCODING, SFE_VOC_NO_CREATIVE, SFE_VOC_BAD_FORMAT, SFE_VOC_BAD_VERSION, SFE_VOC_BAD_MARKER, SFE_VOC_BAD_SECTIONS, SFE_VOC_MULTI_SAMPLERATE, SFE_VOC_MULTI_SECTION, SFE_VOC_MULTI_PARAM, SFE_VOC_SECTION_COUNT, SFE_VOC_NO_PIPE, SFE_IRCAM_NO_MARKER, SFE_IRCAM_BAD_CHANNELS, SFE_IRCAM_UNKNOWN_FORMAT, SFE_W64_64_BIT, SFE_W64_NO_RIFF, SFE_W64_NO_WAVE, SFE_W64_NO_FMT, SFE_W64_NO_DATA, SFE_W64_FMT_SHORT, SFE_W64_FMT_TOO_BIG, SFE_W64_ADPCM_NOT4BIT, SFE_W64_ADPCM_CHANNELS, SFE_W64_GSM610_FORMAT, SFE_MAT4_BAD_NAME, SFE_MAT4_NO_SAMPLERATE, SFE_MAT4_ZERO_CHANNELS, SFE_MAT5_BAD_ENDIAN, SFE_MAT5_NO_BLOCK, SFE_MAT5_SAMPLE_RATE, SFE_MAT5_ZERO_CHANNELS, SFE_PVF_NO_PVF1, SFE_PVF_BAD_HEADER, SFE_PVF_BAD_BITWIDTH, SFE_DWVW_BAD_BITWIDTH, SFE_G72X_NOT_MONO, SFE_XI_BAD_HEADER, SFE_XI_EXCESS_SAMPLES, SFE_XI_NO_PIPE, SFE_HTK_NO_PIPE, SFE_SDS_NOT_SDS, SFE_SDS_BAD_BIT_WIDTH, SFE_SD2_FD_DISALLOWED, SFE_SD2_BAD_DATA_OFFSET, SFE_SD2_BAD_MAP_OFFSET, SFE_SD2_BAD_DATA_LENGTH, SFE_SD2_BAD_MAP_LENGTH, SFE_SD2_BAD_RSRC, SFE_SD2_BAD_SAMPLE_SIZE, SFE_FLAC_BAD_HEADER, SFE_FLAC_NEW_DECODER, SFE_FLAC_INIT_DECODER, SFE_FLAC_LOST_SYNC, SFE_FLAC_BAD_SAMPLE_RATE, SFE_FLAC_UNKNOWN_ERROR, SFE_MAX_ERROR /* This must be last in list. */ } ; int subformat_to_bytewidth (int format) ; int s_bitwidth_to_subformat (int bits) ; int u_bitwidth_to_subformat (int bits) ; /* Functions for reading and writing floats and doubles on processors ** with non-IEEE floats/doubles. */ float float32_be_read (unsigned char *cptr) ; float float32_le_read (unsigned char *cptr) ; void float32_be_write (float in, unsigned char *out) ; void float32_le_write (float in, unsigned char *out) ; double double64_be_read (unsigned char *cptr) ; double double64_le_read (unsigned char *cptr) ; void double64_be_write (double in, unsigned char *out) ; void double64_le_write (double in, unsigned char *out) ; /* Functions for writing to the internal logging buffer. */ void psf_log_printf (SF_PRIVATE *psf, const char *format, ...) ; void psf_log_SF_INFO (SF_PRIVATE *psf) ; void psf_hexdump (void *ptr, int len) ; /* Functions used when writing file headers. */ int psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) ; void psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...) ; /* Functions used when reading file headers. */ int psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) ; /* Functions used in the write function for updating the peak chunk. */ void peak_update_short (SF_PRIVATE *psf, short *ptr, size_t items) ; void peak_update_int (SF_PRIVATE *psf, int *ptr, size_t items) ; void peak_update_double (SF_PRIVATE *psf, double *ptr, size_t items) ; /* Functions defined in command.c. */ int psf_get_format_simple_count (void) ; int psf_get_format_simple (SF_FORMAT_INFO *data) ; int psf_get_format_info (SF_FORMAT_INFO *data) ; int psf_get_format_major_count (void) ; int psf_get_format_major (SF_FORMAT_INFO *data) ; int psf_get_format_subtype_count (void) ; int psf_get_format_subtype (SF_FORMAT_INFO *data) ; void psf_generate_format_desc (SF_PRIVATE *psf) ; double psf_calc_signal_max (SF_PRIVATE *psf, int normalize) ; int psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize) ; int psf_get_signal_max (SF_PRIVATE *psf, double *peak) ; int psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks) ; /* Functions in strings.c. */ const char* psf_get_string (SF_PRIVATE *psf, int str_type) ; int psf_set_string (SF_PRIVATE *psf, int str_type, const char *str) ; int psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) ; /* Default seek function. Use for PCM and float encoded data. */ sf_count_t psf_default_seek (SF_PRIVATE *psf, int mode, sf_count_t samples_from_start) ; /* Generate the currebt date as a string. */ void psf_get_date_str (char *str, int maxlen) ; int macos_guess_file_type (SF_PRIVATE *psf, const char *filename) ; /*------------------------------------------------------------------------------------ ** File I/O functions which will allow access to large files (> 2 Gig) on ** some 32 bit OSes. Implementation in file_io.c. */ int psf_fopen (SF_PRIVATE *psf, const char *pathname, int flags) ; int psf_set_stdio (SF_PRIVATE *psf, int mode) ; int psf_file_valid (SF_PRIVATE *psf) ; void psf_set_file (SF_PRIVATE *psf, int fd) ; void psf_init_files (SF_PRIVATE *psf) ; void psf_use_rsrc (SF_PRIVATE *psf, int on_off) ; sf_count_t psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) ; sf_count_t psf_fread (void *ptr, sf_count_t bytes, sf_count_t count, SF_PRIVATE *psf) ; sf_count_t psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t count, SF_PRIVATE *psf) ; sf_count_t psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) ; sf_count_t psf_ftell (SF_PRIVATE *psf) ; sf_count_t psf_get_filelen (SF_PRIVATE *psf) ; void psf_fsync (SF_PRIVATE *psf) ; int psf_is_pipe (SF_PRIVATE *psf) ; int psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) ; int psf_fclose (SF_PRIVATE *psf) ; /* Open and close the resource fork of a file. */ int psf_open_rsrc (SF_PRIVATE *psf, int mode) ; int psf_close_rsrc (SF_PRIVATE *psf) ; /* void psf_fclearerr (SF_PRIVATE *psf) ; int psf_ferror (SF_PRIVATE *psf) ; */ /*------------------------------------------------------------------------------------ ** Functions for reading and writing different file formats. */ int aiff_open (SF_PRIVATE *psf) ; int au_open (SF_PRIVATE *psf) ; int avr_open (SF_PRIVATE *psf) ; int htk_open (SF_PRIVATE *psf) ; int ircam_open (SF_PRIVATE *psf) ; int mat4_open (SF_PRIVATE *psf) ; int mat5_open (SF_PRIVATE *psf) ; int nist_open (SF_PRIVATE *psf) ; int paf_open (SF_PRIVATE *psf) ; int pvf_open (SF_PRIVATE *psf) ; int raw_open (SF_PRIVATE *psf) ; int sd2_open (SF_PRIVATE *psf) ; int sds_open (SF_PRIVATE *psf) ; int svx_open (SF_PRIVATE *psf) ; int voc_open (SF_PRIVATE *psf) ; int w64_open (SF_PRIVATE *psf) ; int wav_open (SF_PRIVATE *psf) ; int xi_open (SF_PRIVATE *psf) ; int flac_open (SF_PRIVATE *psf) ; int caf_open (SF_PRIVATE *psf) ; /* In progress. Do not currently work. */ int mpeg_open (SF_PRIVATE *psf) ; int ogg_open (SF_PRIVATE *psf) ; int rx2_open (SF_PRIVATE *psf) ; int txw_open (SF_PRIVATE *psf) ; int wve_open (SF_PRIVATE *psf) ; int dwd_open (SF_PRIVATE *psf) ; int macbinary3_open (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------------ ** Init functions for a number of common data encodings. */ int pcm_init (SF_PRIVATE *psf) ; int ulaw_init (SF_PRIVATE *psf) ; int alaw_init (SF_PRIVATE *psf) ; int float32_init (SF_PRIVATE *psf) ; int double64_init (SF_PRIVATE *psf) ; int dwvw_init (SF_PRIVATE *psf, int bitwidth) ; int gsm610_init (SF_PRIVATE *psf) ; int vox_adpcm_init (SF_PRIVATE *psf) ; int flac_init (SF_PRIVATE *psf) ; int g72x_init (SF_PRIVATE * psf) ; int dither_init (SF_PRIVATE *psf, int mode) ; int wav_w64_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; int wav_w64_msadpcm_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; int aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; int interleave_init (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------------ ** Other helper functions. */ void *psf_memset (void *s, int c, sf_count_t n) ; SF_INSTRUMENT * psf_instrument_alloc (void) ; SF_BROADCAST_INFO* broadcast_info_alloc (void) ; int broadcast_info_copy (SF_BROADCAST_INFO* dst, SF_BROADCAST_INFO* src) ; int broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, unsigned int samplerate) ; /*------------------------------------------------------------------------------------ ** Here's how we fix systems which don't snprintf / vsnprintf. ** Systems without these functions should use the */ #if USE_WINDOWS_API #define LSF_SNPRINTF _snprintf #elif (HAVE_SNPRINTF && ! FORCE_MISSING_SNPRINTF) #define LSF_SNPRINTF snprintf #else int missing_snprintf (char *str, size_t n, char const *fmt, ...) ; #define LSF_SNPRINTF missing_snprintf #endif #if USE_WINDOWS_API #define LSF_VSNPRINTF _vsnprintf #elif (HAVE_VSNPRINTF && ! FORCE_MISSING_SNPRINTF) #define LSF_VSNPRINTF vsnprintf #else int missing_vsnprintf (char *str, size_t n, const char *fmt, ...) ; #define LSF_VSNPRINTF missing_vsnprintf #endif /*------------------------------------------------------------------------------------ ** Extra commands for sf_command(). Not for public use yet. */ enum { SFC_TEST_AIFF_ADD_INST_CHUNK = 0x2000, SFC_TEST_WAV_ADD_INFO_CHUNK = 0x2010 } ; /* ** Maybe, one day, make these functions or something like them, public. ** ** Buffer to buffer dithering. Pointer in and out are allowed to point ** to the same buffer for in-place dithering. */ #if 0 int sf_dither_short (const SF_DITHER_INFO *dither, const short *in, short *out, int count) ; int sf_dither_int (const SF_DITHER_INFO *dither, const int *in, int *out, int count) ; int sf_dither_float (const SF_DITHER_INFO *dither, const float *in, float *out, int count) ; int sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int count) ; #endif #endif /* SNDFILE_COMMON_H */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 7b45c0ee-5835-4a18-a4ef-994e4cd95b67 */ nyquist-3.05/nylsf/broadcast.c0000644000175000000620000000462311466723256015445 0ustar stevestaff/* ** Copyright (C) 2006 Paul Davis ** Copyright (C) 2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include #include #include "common.h" /* ** Allocate and initialize a broadcast info structure. */ SF_BROADCAST_INFO* broadcast_info_alloc (void) { SF_BROADCAST_INFO* bext ; if ((bext = calloc (1, sizeof (SF_BROADCAST_INFO))) == NULL) return NULL ; return bext ; } /* broadcast_info_alloc */ int broadcast_info_copy (SF_BROADCAST_INFO* dst, SF_BROADCAST_INFO* src) { memcpy (dst, src, sizeof (SF_BROADCAST_INFO)) ; /* Currently writing this version. */ dst->version = 1 ; return SF_TRUE ; } /* broadcast_info_copy */ int broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, unsigned int samplerate) { char chnstr [16] ; int count ; switch (channels) { case 0 : return SF_FALSE ; case 1 : strncpy (chnstr, "mono", sizeof (chnstr)) ; break ; case 2 : strncpy (chnstr, "stereo", sizeof (chnstr)) ; break ; default : LSF_SNPRINTF (chnstr, sizeof (chnstr), "%uchn", channels) ; break ; } count = LSF_SNPRINTF (bext->coding_history, sizeof (bext->coding_history), "F=%u,A=PCM,M=%s,W=24,T=%s-%s", samplerate, chnstr, PACKAGE, VERSION) ; if (count >= SIGNED_SIZEOF (bext->coding_history)) bext->coding_history_size = sizeof (bext->coding_history) ; else { count += count & 1 ; bext->coding_history_size = count ; } ; return SF_TRUE ; } /* broadcast_add_coding_history */ /* ** Do not edit or modify anything in this comment block. ** The following line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 4b3b69c7-d710-4424-9da0-5048534a0beb */ nyquist-3.05/nylsf/txw.c0000644000175000000620000002333511466723256014326 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /*=========================================================================== ** Yamaha TX16 Sampler Files. ** ** This header parser was written using information from the SoX source code ** and trial and error experimentation. The code here however is all original. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #if (ENABLE_EXPERIMENTAL_CODE == 0) int txw_open (SF_PRIVATE *psf) { if (psf) return SFE_UNIMPLEMENTED ; return (psf && 0) ; } /* txw_open */ #else /*------------------------------------------------------------------------------ ** Markers. */ #define TXW_DATA_OFFSET 32 #define TXW_LOOPED 0x49 #define TXW_NO_LOOP 0xC9 /*------------------------------------------------------------------------------ ** Private static functions. */ static int txw_read_header (SF_PRIVATE *psf) ; static sf_count_t txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; /*------------------------------------------------------------------------------ ** Public functions. */ /* * ftp://ftp.t0.or.at/pub/sound/tx16w/samples.yamaha * ftp://ftp.t0.or.at/pub/sound/tx16w/faq/tx16w.tec * http://www.t0.or.at/~mpakesch/tx16w/ * * from tx16w.c sox 12.15: (7-Oct-98) (Mark Lakata and Leigh Smith) * char filetype[6] "LM8953" * nulls[10], * dummy_aeg[6] * format 0x49 = looped, 0xC9 = non-looped * sample_rate 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz * atc_length[3] if sample rate 0, [2]&0xfe = 6: 33kHz, 0x10:50, 0xf6: 16, * depending on [5] but to heck with it * rpt_length[3] (these are for looped samples, attack and loop lengths) * unused[2] */ typedef struct { unsigned char format, srate, sr2, sr3 ; unsigned short srhash ; unsigned int attacklen, repeatlen ; } TXW_HEADER ; #define ERROR_666 666 int txw_open (SF_PRIVATE *psf) { int error ; if (psf->mode != SFM_READ) return SFE_UNIMPLEMENTED ; if ((error = txw_read_header (psf))) return error ; if (psf_fseek (psf, psf->dataoffset, SEEK_SET) != psf->dataoffset) return SFE_BAD_SEEK ; psf->read_short = txw_read_s ; psf->read_int = txw_read_i ; psf->read_float = txw_read_f ; psf->read_double = txw_read_d ; psf->seek = txw_seek ; return 0 ; } /* txw_open */ /*------------------------------------------------------------------------------ */ static int txw_read_header (SF_PRIVATE *psf) { TXW_HEADER txwh ; char *strptr ; memset (&txwh, 0, sizeof (txwh)) ; memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ; psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, 16) ; if (memcmp (psf->u.cbuf, "LM8953\0\0\0\0\0\0\0\0\0\0", 16) != 0) return ERROR_666 ; psf_log_printf (psf, "Read only : Yamaha TX-16 Sampler (.txw)\nLM8953\n") ; /* Jump 6 bytes (dummp_aeg), read format, read sample rate. */ psf_binheader_readf (psf, "j11", 6, &txwh.format, &txwh.srate) ; /* 8 bytes (atc_length[3], rpt_length[3], unused[2]). */ psf_binheader_readf (psf, "e33j", &txwh.attacklen, &txwh.repeatlen, 2) ; txwh.sr2 = (txwh.attacklen >> 16) & 0xFE ; txwh.sr3 = (txwh.repeatlen >> 16) & 0xFE ; txwh.attacklen &= 0x1FFFF ; txwh.repeatlen &= 0x1FFFF ; switch (txwh.format) { case TXW_LOOPED : strptr = "looped" ; break ; case TXW_NO_LOOP : strptr = "non-looped" ; break ; default : psf_log_printf (psf, " Format : 0x%02x => ?????\n", txwh.format) ; return ERROR_666 ; } ; psf_log_printf (psf, " Format : 0x%02X => %s\n", txwh.format, strptr) ; strptr = NULL ; switch (txwh.srate) { case 1 : psf->sf.samplerate = 33333 ; break ; case 2 : psf->sf.samplerate = 50000 ; break ; case 3 : psf->sf.samplerate = 16667 ; break ; default : /* This is ugly and braindead. */ txwh.srhash = ((txwh.sr2 & 0xFE) << 8) | (txwh.sr3 & 0xFE) ; switch (txwh.srhash) { case ((0x6 << 8) | 0x52) : psf->sf.samplerate = 33333 ; break ; case ((0x10 << 8) | 0x52) : psf->sf.samplerate = 50000 ; break ; case ((0xF6 << 8) | 0x52) : psf->sf.samplerate = 166667 ; break ; default : strptr = " Sample Rate : Unknown : forcing to 33333\n" ; psf->sf.samplerate = 33333 ; break ; } ; } ; if (strptr) psf_log_printf (psf, strptr) ; else if (txwh.srhash) psf_log_printf (psf, " Sample Rate : %d (0x%X) => %d\n", txwh.srate, txwh.srhash, psf->sf.samplerate) ; else psf_log_printf (psf, " Sample Rate : %d => %d\n", txwh.srate, psf->sf.samplerate) ; if (txwh.format == TXW_LOOPED) { psf_log_printf (psf, " Attack Len : %d\n", txwh.attacklen) ; psf_log_printf (psf, " Repeat Len : %d\n", txwh.repeatlen) ; } ; psf->dataoffset = TXW_DATA_OFFSET ; psf->datalength = psf->filelength - TXW_DATA_OFFSET ; psf->sf.frames = 2 * psf->datalength / 3 ; if (psf->datalength % 3 == 1) psf_log_printf (psf, "*** File seems to be truncated, %d extra bytes.\n", (int) (psf->datalength % 3)) ; if (txwh.attacklen + txwh.repeatlen > psf->sf.frames) psf_log_printf (psf, "*** File has been truncated.\n") ; psf->sf.format = SF_FORMAT_TXW | SF_FORMAT_PCM_16 ; psf->sf.channels = 1 ; psf->sf.sections = 1 ; psf->sf.seekable = SF_TRUE ; return 0 ; } /* txw_read_header */ static sf_count_t txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.cbuf) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (psf->u.cbuf, 3, readcount, psf) ; ucptr = psf->u.ucbuf ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = sample ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = sample ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_s */ static sf_count_t txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; bufferlen = sizeof (psf->u.cbuf) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (psf->u.cbuf, 3, readcount, psf) ; ucptr = psf->u.ucbuf ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = sample << 16 ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = sample << 16 ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_i */ static sf_count_t txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; float normfact ; if (psf->norm_float == SF_TRUE) normfact = 1.0 / 0x8000 ; else normfact = 1.0 / 0x10 ; bufferlen = sizeof (psf->u.cbuf) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (psf->u.cbuf, 3, readcount, psf) ; ucptr = psf->u.ucbuf ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = normfact * sample ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = normfact * sample ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_f */ static sf_count_t txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { unsigned char *ucptr ; short sample ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; double normfact ; if (psf->norm_double == SF_TRUE) normfact = 1.0 / 0x8000 ; else normfact = 1.0 / 0x10 ; bufferlen = sizeof (psf->u.cbuf) / 3 ; bufferlen -= (bufferlen & 1) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = psf_fread (psf->u.cbuf, 3, readcount, psf) ; ucptr = psf->u.ucbuf ; for (k = 0 ; k < readcount ; k += 2) { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; ptr [total + k] = normfact * sample ; sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; ptr [total + k + 1] = normfact * sample ; ucptr += 3 ; } ; total += count ; len -= readcount ; } ; return total ; } /* txw_read_d */ static sf_count_t txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { if (psf && mode) return offset ; return 0 ; } /* txw_seek */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 4d0ba7af-b1c5-46b4-a900-7c6f59fd9a89 */ nyquist-3.05/nylsf/common.c0000644000175000000620000010330511466723256014770 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*----------------------------------------------------------------------------------------------- ** psf_log_printf allows libsndfile internal functions to print to an internal logbuffer which ** can later be displayed. ** The format specifiers are as for printf but without the field width and other modifiers. ** Printing is performed to the logbuffer char array of the SF_PRIVATE struct. ** Printing is done in such a way as to guarantee that the log never overflows the end of the ** logbuffer array. */ static inline void log_putchar (SF_PRIVATE *psf, char ch) { if (psf->logindex < SIGNED_SIZEOF (psf->logbuffer) - 1) { psf->logbuffer [psf->logindex++] = ch ; psf->logbuffer [psf->logindex] = 0 ; } ; return ; } /* log_putchar */ void psf_log_printf (SF_PRIVATE *psf, const char *format, ...) { va_list ap ; unsigned int u ; int d, tens, shift, width, width_specifier, left_align ; char c, *strptr, istr [5], lead_char, sign_char ; va_start (ap, format) ; while ((c = *format++)) { if (c != '%') { log_putchar (psf, c) ; continue ; } ; if (format [0] == '%') /* Handle %% */ { log_putchar (psf, '%') ; format ++ ; continue ; } ; sign_char = 0 ; left_align = SF_FALSE ; while (1) { switch (format [0]) { case ' ' : case '+' : sign_char = format [0] ; format ++ ; continue ; case '-' : left_align = SF_TRUE ; format ++ ; continue ; default : break ; } ; break ; } ; if (format [0] == 0) break ; lead_char = ' ' ; if (format [0] == '0') lead_char = '0' ; width_specifier = 0 ; while ((c = *format++) && isdigit (c)) width_specifier = width_specifier * 10 + (c - '0') ; switch (c) { case 0 : /* NULL character. */ va_end (ap) ; return ; case 's': /* string */ strptr = va_arg (ap, char *) ; if (strptr == NULL) break ; width_specifier -= strlen (strptr) ; if (left_align == SF_FALSE) while (width_specifier -- > 0) log_putchar (psf, ' ') ; while (*strptr) log_putchar (psf, *strptr++) ; while (width_specifier -- > 0) log_putchar (psf, ' ') ; break ; case 'd': /* int */ d = va_arg (ap, int) ; if (d < 0) { d = -d ; sign_char = '-' ; if (lead_char != '0' && left_align == SF_FALSE) width_specifier -- ; } ; tens = 1 ; width = 1 ; while (d / tens >= 10) { tens *= 10 ; width ++ ; } ; width_specifier -= width ; if (sign_char == ' ') { log_putchar (psf, ' ') ; width_specifier -- ; } ; if (left_align == SF_FALSE && lead_char != '0') { if (sign_char == '+') width_specifier -- ; while (width_specifier -- > 0) log_putchar (psf, lead_char) ; } ; if (sign_char == '+' || sign_char == '-') { log_putchar (psf, sign_char) ; width_specifier -- ; } ; if (left_align == SF_FALSE) while (width_specifier -- > 0) log_putchar (psf, lead_char) ; while (tens > 0) { log_putchar (psf, '0' + d / tens) ; d %= tens ; tens /= 10 ; } ; while (width_specifier -- > 0) log_putchar (psf, lead_char) ; break ; case 'D': /* sf_count_t */ { sf_count_t D, Tens ; D = va_arg (ap, sf_count_t) ; if (D == 0) { while (-- width_specifier > 0) log_putchar (psf, lead_char) ; log_putchar (psf, '0') ; break ; } if (D < 0) { log_putchar (psf, '-') ; D = -D ; } ; Tens = 1 ; width = 1 ; while (D / Tens >= 10) { Tens *= 10 ; width ++ ; } ; while (width_specifier > width) { log_putchar (psf, lead_char) ; width_specifier-- ; } ; while (Tens > 0) { log_putchar (psf, '0' + D / Tens) ; D %= Tens ; Tens /= 10 ; } ; } ; break ; case 'u': /* unsigned int */ u = va_arg (ap, unsigned int) ; tens = 1 ; width = 1 ; while (u / tens >= 10) { tens *= 10 ; width ++ ; } ; width_specifier -= width ; if (sign_char == ' ') { log_putchar (psf, ' ') ; width_specifier -- ; } ; if (left_align == SF_FALSE && lead_char != '0') { if (sign_char == '+') width_specifier -- ; while (width_specifier -- > 0) log_putchar (psf, lead_char) ; } ; if (sign_char == '+' || sign_char == '-') { log_putchar (psf, sign_char) ; width_specifier -- ; } ; if (left_align == SF_FALSE) while (width_specifier -- > 0) log_putchar (psf, lead_char) ; while (tens > 0) { log_putchar (psf, '0' + u / tens) ; u %= tens ; tens /= 10 ; } ; while (width_specifier -- > 0) log_putchar (psf, lead_char) ; break ; case 'c': /* char */ c = va_arg (ap, int) & 0xFF ; log_putchar (psf, c) ; break ; case 'x': /* hex */ case 'X': /* hex */ d = va_arg (ap, int) ; if (d == 0) { while (--width_specifier > 0) log_putchar (psf, lead_char) ; log_putchar (psf, '0') ; break ; } ; shift = 28 ; width = (width_specifier < 8) ? 8 : width_specifier ; while (! ((0xF << shift) & d)) { shift -= 4 ; width -- ; } ; while (width > 0 && width_specifier > width) { log_putchar (psf, lead_char) ; width_specifier-- ; } ; while (shift >= 0) { c = (d >> shift) & 0xF ; log_putchar (psf, (c > 9) ? c + 'A' - 10 : c + '0') ; shift -= 4 ; } ; break ; case 'M': /* int2str */ d = va_arg (ap, int) ; if (CPU_IS_LITTLE_ENDIAN) { istr [0] = d & 0xFF ; istr [1] = (d >> 8) & 0xFF ; istr [2] = (d >> 16) & 0xFF ; istr [3] = (d >> 24) & 0xFF ; } else { istr [3] = d & 0xFF ; istr [2] = (d >> 8) & 0xFF ; istr [1] = (d >> 16) & 0xFF ; istr [0] = (d >> 24) & 0xFF ; } ; istr [4] = 0 ; strptr = istr ; while (*strptr) { c = *strptr++ ; log_putchar (psf, c) ; } ; break ; default : log_putchar (psf, '*') ; log_putchar (psf, c) ; log_putchar (psf, '*') ; break ; } /* switch */ } /* while */ va_end (ap) ; return ; } /* psf_log_printf */ #ifndef PSF_LOG_PRINTF_ONLY /*----------------------------------------------------------------------------------------------- ** ASCII header printf functions. ** Some formats (ie NIST) use ascii text in their headers. ** Format specifiers are the same as the standard printf specifiers (uses vsnprintf). ** If this generates a compile error on any system, the author should be notified ** so an alternative vsnprintf can be provided. */ void psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...) { va_list argptr ; int maxlen ; char *start ; maxlen = strlen ((char*) psf->header) ; start = ((char*) psf->header) + maxlen ; maxlen = sizeof (psf->header) - maxlen ; va_start (argptr, format) ; LSF_VSNPRINTF (start, maxlen, format, argptr) ; va_end (argptr) ; /* Make sure the string is properly terminated. */ start [maxlen - 1] = 0 ; psf->headindex = strlen ((char*) psf->header) ; return ; } /* psf_asciiheader_printf */ /*----------------------------------------------------------------------------------------------- ** Binary header writing functions. Returns number of bytes written. ** ** Format specifiers for psf_binheader_writef are as follows ** m - marker - four bytes - no endian manipulation ** ** e - all following numerical values will be little endian ** E - all following numerical values will be big endian ** ** t - all following O types will be truncated to 4 bytes ** T - switch off truncation of all following O types ** ** 1 - single byte value ** 2 - two byte value ** 3 - three byte value ** 4 - four byte value ** 8 - eight byte value (sometimes written as 4 bytes) ** ** s - string preceded by a four byte length ** S - string including null terminator ** f - floating point data ** d - double precision floating point data ** h - 16 binary bytes value ** ** b - binary data (see below) ** z - zero bytes (ses below) ** j - jump forwards or backwards ** ** To write a word followed by an int (both little endian) use: ** psf_binheader_writef ("e24", wordval, longval) ; ** ** To write binary data use: ** psf_binheader_writef ("b", &bindata, sizeof (bindata)) ; ** ** To write N zero bytes use: ** NOTE: due to platform issues (ie x86-64) you should cast the ** argument to size_t or ensure the variable type is size_t. ** psf_binheader_writef ("z", N) ; */ /* These macros may seem a bit messy but do prevent problems with processors which ** seg. fault when asked to write an int or short to a non-int/short aligned address. */ static inline void header_put_byte (SF_PRIVATE *psf, char x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 1) psf->header [psf->headindex++] = x ; } /* header_put_byte */ #if (CPU_IS_BIG_ENDIAN == 1) static inline void header_put_marker (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) { psf->header [psf->headindex++] = (x >> 24) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = x ; } ; } /* header_put_marker */ #elif (CPU_IS_LITTLE_ENDIAN == 1) static inline void header_put_marker (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) { psf->header [psf->headindex++] = x ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 24) ; } ; } /* header_put_marker */ #else # error "Cannot determine endian-ness of processor." #endif static inline void header_put_be_short (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2) { psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = x ; } ; } /* header_put_be_short */ static inline void header_put_le_short (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2) { psf->header [psf->headindex++] = x ; psf->header [psf->headindex++] = (x >> 8) ; } ; } /* header_put_le_short */ static inline void header_put_be_3byte (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3) { psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = x ; } ; } /* header_put_be_3byte */ static inline void header_put_le_3byte (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3) { psf->header [psf->headindex++] = x ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = (x >> 16) ; } ; } /* header_put_le_3byte */ static inline void header_put_be_int (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) { psf->header [psf->headindex++] = (x >> 24) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = x ; } ; } /* header_put_be_int */ static inline void header_put_le_int (SF_PRIVATE *psf, int x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4) { psf->header [psf->headindex++] = x ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 24) ; } ; } /* header_put_le_int */ #if (SIZEOF_SF_COUNT_T == 4) static inline void header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) { psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = (x >> 24) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = x ; } ; } /* header_put_be_8byte */ static inline void header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) { psf->header [psf->headindex++] = x ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 24) ; psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = 0 ; psf->header [psf->headindex++] = 0 ; } ; } /* header_put_le_8byte */ #elif (SIZEOF_SF_COUNT_T == 8) static inline void header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) { psf->header [psf->headindex++] = (x >> 56) ; psf->header [psf->headindex++] = (x >> 48) ; psf->header [psf->headindex++] = (x >> 40) ; psf->header [psf->headindex++] = (x >> 32) ; psf->header [psf->headindex++] = (x >> 24) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = x ; } ; } /* header_put_be_8byte */ static inline void header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x) { if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8) { psf->header [psf->headindex++] = x ; psf->header [psf->headindex++] = (x >> 8) ; psf->header [psf->headindex++] = (x >> 16) ; psf->header [psf->headindex++] = (x >> 24) ; psf->header [psf->headindex++] = (x >> 32) ; psf->header [psf->headindex++] = (x >> 40) ; psf->header [psf->headindex++] = (x >> 48) ; psf->header [psf->headindex++] = (x >> 56) ; } ; } /* header_put_le_8byte */ #else #error "SIZEOF_SF_COUNT_T is not defined." #endif int psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) { va_list argptr ; sf_count_t countdata ; unsigned long longdata ; unsigned int data ; float floatdata ; double doubledata ; void *bindata ; size_t size ; char c, *strptr ; int count = 0, trunc_8to4 ; trunc_8to4 = SF_FALSE ; va_start (argptr, format) ; while ((c = *format++)) { switch (c) { case ' ' : /* Do nothing. Just used to space out format string. */ break ; case 'e' : /* All conversions are now from LE to host. */ psf->rwf_endian = SF_ENDIAN_LITTLE ; break ; case 'E' : /* All conversions are now from BE to host. */ psf->rwf_endian = SF_ENDIAN_BIG ; break ; case 't' : /* All 8 byte values now get written as 4 bytes. */ trunc_8to4 = SF_TRUE ; break ; case 'T' : /* All 8 byte values now get written as 8 bytes. */ trunc_8to4 = SF_FALSE ; break ; case 'm' : data = va_arg (argptr, unsigned int) ; header_put_marker (psf, data) ; count += 4 ; break ; case '1' : data = va_arg (argptr, unsigned int) ; header_put_byte (psf, data) ; count += 1 ; break ; case '2' : data = va_arg (argptr, unsigned int) ; if (psf->rwf_endian == SF_ENDIAN_BIG) { header_put_be_short (psf, data) ; } else { header_put_le_short (psf, data) ; } ; count += 2 ; break ; case '3' : /* tribyte */ data = va_arg (argptr, unsigned int) ; if (psf->rwf_endian == SF_ENDIAN_BIG) { header_put_be_3byte (psf, data) ; } else { header_put_le_3byte (psf, data) ; } ; count += 3 ; break ; case '4' : data = va_arg (argptr, unsigned int) ; if (psf->rwf_endian == SF_ENDIAN_BIG) { header_put_be_int (psf, data) ; } else { header_put_le_int (psf, data) ; } ; count += 4 ; break ; case '8' : countdata = va_arg (argptr, sf_count_t) ; if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_FALSE) { header_put_be_8byte (psf, countdata) ; count += 8 ; } else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_FALSE) { header_put_le_8byte (psf, countdata) ; count += 8 ; } else if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_TRUE) { longdata = countdata & 0xFFFFFFFF ; header_put_be_int (psf, longdata) ; count += 4 ; } else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_TRUE) { longdata = countdata & 0xFFFFFFFF ; header_put_le_int (psf, longdata) ; count += 4 ; } break ; case 'f' : /* Floats are passed as doubles. Is this always true? */ floatdata = (float) va_arg (argptr, double) ; if (psf->rwf_endian == SF_ENDIAN_BIG) float32_be_write (floatdata, psf->header + psf->headindex) ; else float32_le_write (floatdata, psf->header + psf->headindex) ; psf->headindex += 4 ; count += 4 ; break ; case 'd' : doubledata = va_arg (argptr, double) ; if (psf->rwf_endian == SF_ENDIAN_BIG) double64_be_write (doubledata, psf->header + psf->headindex) ; else double64_le_write (doubledata, psf->header + psf->headindex) ; psf->headindex += 8 ; count += 8 ; break ; case 's' : /* Write a C string (guaranteed to have a zero terminator). */ strptr = va_arg (argptr, char *) ; size = strlen (strptr) + 1 ; size += (size & 1) ; if (psf->rwf_endian == SF_ENDIAN_BIG) header_put_be_int (psf, size) ; else header_put_le_int (psf, size) ; memcpy (&(psf->header [psf->headindex]), strptr, size) ; psf->headindex += size ; psf->header [psf->headindex - 1] = 0 ; count += 4 + size ; break ; case 'S' : /* ** Write an AIFF style string (no zero terminator but possibly ** an extra pad byte if the string length is odd). */ strptr = va_arg (argptr, char *) ; size = strlen (strptr) ; if (psf->rwf_endian == SF_ENDIAN_BIG) header_put_be_int (psf, size) ; else header_put_le_int (psf, size) ; memcpy (&(psf->header [psf->headindex]), strptr, size + 1) ; size += (size & 1) ; psf->headindex += size ; psf->header [psf->headindex] = 0 ; count += 4 + size ; break ; case 'b' : bindata = va_arg (argptr, void *) ; size = va_arg (argptr, size_t) ; memcpy (&(psf->header [psf->headindex]), bindata, size) ; psf->headindex += size ; count += size ; break ; case 'z' : size = va_arg (argptr, size_t) ; count += size ; while (size) { psf->header [psf->headindex] = 0 ; psf->headindex ++ ; size -- ; } ; break ; case 'h' : bindata = va_arg (argptr, void *) ; memcpy (&(psf->header [psf->headindex]), bindata, 16) ; psf->headindex += 16 ; count += 16 ; break ; case 'j' : size = va_arg (argptr, size_t) ; psf->headindex += size ; count = size ; break ; default : psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ; psf->error = SFE_INTERNAL ; break ; } ; } ; va_end (argptr) ; return count ; } /* psf_binheader_writef */ /*----------------------------------------------------------------------------------------------- ** Binary header reading functions. Returns number of bytes read. ** ** Format specifiers are the same as for header write function above with the following ** additions: ** ** p - jump a given number of position from start of file. ** ** If format is NULL, psf_binheader_readf returns the current offset. */ #if (CPU_IS_BIG_ENDIAN == 1) #define GET_MARKER(ptr) ( ((ptr) [0] << 24) | ((ptr) [1] << 16) | \ ((ptr) [2] << 8) | ((ptr) [3]) ) #elif (CPU_IS_LITTLE_ENDIAN == 1) #define GET_MARKER(ptr) ( ((ptr) [0]) | ((ptr) [1] << 8) | \ ((ptr) [2] << 16) | ((ptr) [3] << 24) ) #else # error "Cannot determine endian-ness of processor." #endif #define GET_LE_SHORT(ptr) ( ((ptr) [1] << 8) | ((ptr) [0]) ) #define GET_BE_SHORT(ptr) ( ((ptr) [0] << 8) | ((ptr) [1]) ) #define GET_LE_3BYTE(ptr) ( ((ptr) [2] << 16) | ((ptr) [1] << 8) | ((ptr) [0]) ) #define GET_BE_3BYTE(ptr) ( ((ptr) [0] << 16) | ((ptr) [1] << 8) | ((ptr) [2]) ) #define GET_LE_INT(ptr) ( ((ptr) [3] << 24) | ((ptr) [2] << 16) | \ ((ptr) [1] << 8) | ((ptr) [0]) ) #define GET_BE_INT(ptr) ( ((ptr) [0] << 24) | ((ptr) [1] << 16) | \ ((ptr) [2] << 8) | ((ptr) [3]) ) #if (SIZEOF_LONG == 4) #define GET_LE_8BYTE(ptr) ( ((ptr) [3] << 24) | ((ptr) [2] << 16) | \ ((ptr) [1] << 8) | ((ptr) [0]) ) #define GET_BE_8BYTE(ptr) ( ((ptr) [4] << 24) | ((ptr) [5] << 16) | \ ((ptr) [6] << 8) | ((ptr) [7]) ) #else #define GET_LE_8BYTE(ptr) ( (((ptr) [7] * 1L) << 56) | (((ptr) [6] * 1L) << 48) | \ (((ptr) [5] * 1L) << 40) | (((ptr) [4] * 1L) << 32) | \ (((ptr) [3] * 1L) << 24) | (((ptr) [2] * 1L) << 16) | \ (((ptr) [1] * 1L) << 8 ) | ((ptr) [0])) #define GET_BE_8BYTE(ptr) ( (((ptr) [0] * 1L) << 56) | (((ptr) [1] * 1L) << 48) | \ (((ptr) [2] * 1L) << 40) | (((ptr) [3] * 1L) << 32) | \ (((ptr) [4] * 1L) << 24) | (((ptr) [5] * 1L) << 16) | \ (((ptr) [6] * 1L) << 8 ) | ((ptr) [7])) #endif static int header_read (SF_PRIVATE *psf, void *ptr, int bytes) { int count = 0 ; if (psf->headindex >= SIGNED_SIZEOF (psf->header)) { memset (ptr, 0, SIGNED_SIZEOF (psf->header) - psf->headindex) ; /* This is the best that we can do. */ psf_fseek (psf, bytes, SEEK_CUR) ; return bytes ; } ; if (psf->headindex + bytes > SIGNED_SIZEOF (psf->header)) { int most ; most = SIGNED_SIZEOF (psf->header) - psf->headindex ; psf_fread (psf->header + psf->headend, 1, most, psf) ; memset ((char *) ptr + most, 0, bytes - most) ; psf_fseek (psf, bytes - most, SEEK_CUR) ; return bytes ; } ; if (psf->headindex + bytes > psf->headend) { count = psf_fread (psf->header + psf->headend, 1, bytes - (psf->headend - psf->headindex), psf) ; if (count != bytes - (int) (psf->headend - psf->headindex)) { psf_log_printf (psf, "Error : psf_fread returned short count.\n") ; return 0 ; } ; psf->headend += count ; } ; memcpy (ptr, psf->header + psf->headindex, bytes) ; psf->headindex += bytes ; return bytes ; } /* header_read */ static void header_seek (SF_PRIVATE *psf, sf_count_t position, int whence) { switch (whence) { case SEEK_SET : if (position > SIGNED_SIZEOF (psf->header)) { /* Too much header to cache so just seek instead. */ psf_fseek (psf, position, whence) ; return ; } ; if (position > psf->headend) psf->headend += psf_fread (psf->header + psf->headend, 1, position - psf->headend, psf) ; psf->headindex = position ; break ; case SEEK_CUR : if (psf->headindex + position < 0) break ; if (psf->headindex >= SIGNED_SIZEOF (psf->header)) { psf_fseek (psf, position, whence) ; return ; } ; if (psf->headindex + position <= psf->headend) { psf->headindex += position ; break ; } ; if (psf->headindex + position > SIGNED_SIZEOF (psf->header)) { /* Need to jump this without caching it. */ psf->headindex = psf->headend ; psf_fseek (psf, position, SEEK_CUR) ; break ; } ; psf->headend += psf_fread (psf->header + psf->headend, 1, position - (psf->headend - psf->headindex), psf) ; psf->headindex = psf->headend ; break ; case SEEK_END : default : psf_log_printf (psf, "Bad whence param in header_seek().\n") ; break ; } ; return ; } /* header_seek */ static int header_gets (SF_PRIVATE *psf, char *ptr, int bufsize) { int k ; for (k = 0 ; k < bufsize - 1 ; k++) { if (psf->headindex < psf->headend) { ptr [k] = psf->header [psf->headindex] ; psf->headindex ++ ; } else { psf->headend += psf_fread (psf->header + psf->headend, 1, 1, psf) ; ptr [k] = psf->header [psf->headindex] ; psf->headindex = psf->headend ; } ; if (ptr [k] == '\n') break ; } ; ptr [k] = 0 ; return k ; } /* header_gets */ int psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) { va_list argptr ; sf_count_t *countptr, countdata ; unsigned char *ucptr, sixteen_bytes [16] ; unsigned int *intptr, intdata ; unsigned short *shortptr ; char *charptr ; float *floatptr ; double *doubleptr ; char c ; int byte_count = 0, count ; if (! format) return psf_ftell (psf) ; va_start (argptr, format) ; while ((c = *format++)) { switch (c) { case 'e' : /* All conversions are now from LE to host. */ psf->rwf_endian = SF_ENDIAN_LITTLE ; break ; case 'E' : /* All conversions are now from BE to host. */ psf->rwf_endian = SF_ENDIAN_BIG ; break ; case 'm' : intptr = va_arg (argptr, unsigned int*) ; ucptr = (unsigned char*) intptr ; byte_count += header_read (psf, ucptr, sizeof (int)) ; *intptr = GET_MARKER (ucptr) ; break ; case 'h' : intptr = va_arg (argptr, unsigned int*) ; ucptr = (unsigned char*) intptr ; byte_count += header_read (psf, sixteen_bytes, sizeof (sixteen_bytes)) ; { int k ; intdata = 0 ; for (k = 0 ; k < 16 ; k++) intdata ^= sixteen_bytes [k] << k ; } *intptr = intdata ; break ; case '1' : charptr = va_arg (argptr, char*) ; *charptr = 0 ; byte_count += header_read (psf, charptr, sizeof (char)) ; break ; case '2' : shortptr = va_arg (argptr, unsigned short*) ; *shortptr = 0 ; ucptr = (unsigned char*) shortptr ; byte_count += header_read (psf, ucptr, sizeof (short)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *shortptr = GET_BE_SHORT (ucptr) ; else *shortptr = GET_LE_SHORT (ucptr) ; break ; case '3' : intptr = va_arg (argptr, unsigned int*) ; *intptr = 0 ; byte_count += header_read (psf, sixteen_bytes, 3) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *intptr = GET_BE_3BYTE (sixteen_bytes) ; else *intptr = GET_LE_3BYTE (sixteen_bytes) ; break ; case '4' : intptr = va_arg (argptr, unsigned int*) ; *intptr = 0 ; ucptr = (unsigned char*) intptr ; byte_count += header_read (psf, ucptr, sizeof (int)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *intptr = GET_BE_INT (ucptr) ; else *intptr = GET_LE_INT (ucptr) ; break ; case '8' : countptr = va_arg (argptr, sf_count_t *) ; *countptr = 0 ; byte_count += header_read (psf, sixteen_bytes, 8) ; if (psf->rwf_endian == SF_ENDIAN_BIG) countdata = GET_BE_8BYTE (sixteen_bytes) ; else countdata = GET_LE_8BYTE (sixteen_bytes) ; *countptr = countdata ; break ; case 'f' : /* Float conversion */ floatptr = va_arg (argptr, float *) ; *floatptr = 0.0 ; byte_count += header_read (psf, floatptr, sizeof (float)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *floatptr = float32_be_read ((unsigned char*) floatptr) ; else *floatptr = float32_le_read ((unsigned char*) floatptr) ; break ; case 'd' : /* double conversion */ doubleptr = va_arg (argptr, double *) ; *doubleptr = 0.0 ; byte_count += header_read (psf, doubleptr, sizeof (double)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *doubleptr = double64_be_read ((unsigned char*) doubleptr) ; else *doubleptr = double64_le_read ((unsigned char*) doubleptr) ; break ; case 's' : psf_log_printf (psf, "Format conversion 's' not implemented yet.\n") ; /* strptr = va_arg (argptr, char *) ; size = strlen (strptr) + 1 ; size += (size & 1) ; longdata = H2LE_INT (size) ; get_int (psf, longdata) ; memcpy (&(psf->header [psf->headindex]), strptr, size) ; psf->headindex += size ; */ break ; case 'b' : charptr = va_arg (argptr, char*) ; count = va_arg (argptr, int) ; if (count > 0) byte_count += header_read (psf, charptr, count) ; break ; case 'G' : charptr = va_arg (argptr, char*) ; count = va_arg (argptr, int) ; if (count > 0) byte_count += header_gets (psf, charptr, count) ; break ; case 'z' : psf_log_printf (psf, "Format conversion 'z' not implemented yet.\n") ; /* size = va_arg (argptr, size_t) ; while (size) { psf->header [psf->headindex] = 0 ; psf->headindex ++ ; size -- ; } ; */ break ; case 'p' : /* Get the seek position first. */ count = va_arg (argptr, int) ; header_seek (psf, count, SEEK_SET) ; byte_count = count ; break ; case 'j' : /* Get the seek position first. */ count = va_arg (argptr, int) ; header_seek (psf, count, SEEK_CUR) ; byte_count += count ; break ; default : psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ; psf->error = SFE_INTERNAL ; break ; } ; } ; va_end (argptr) ; return byte_count ; } /* psf_binheader_readf */ /*----------------------------------------------------------------------------------------------- */ sf_count_t psf_default_seek (SF_PRIVATE *psf, int mode, sf_count_t samples_from_start) { sf_count_t position, retval ; if (! (psf->blockwidth && psf->dataoffset >= 0)) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (! psf->sf.seekable) { psf->error = SFE_NOT_SEEKABLE ; return PSF_SEEK_ERROR ; } ; position = psf->dataoffset + psf->blockwidth * samples_from_start ; if ((retval = psf_fseek (psf, position, SEEK_SET)) != position) { psf->error = SFE_SEEK_FAILED ; return PSF_SEEK_ERROR ; } ; mode = mode ; return samples_from_start ; } /* psf_default_seek */ /*----------------------------------------------------------------------------------------------- */ void psf_hexdump (void *ptr, int len) { char ascii [17], *data ; int k, m ; if ((data = ptr) == NULL) return ; if (len <= 0) return ; puts ("") ; for (k = 0 ; k < len ; k += 16) { memset (ascii, ' ', sizeof (ascii)) ; printf ("%08X: ", k) ; for (m = 0 ; m < 16 && k + m < len ; m++) { printf (m == 8 ? " %02X " : "%02X ", data [k + m] & 0xFF) ; ascii [m] = isprint (data [k + m]) ? data [k + m] : '.' ; } ; if (m <= 8) printf (" ") ; for ( ; m < 16 ; m++) printf (" ") ; ascii [16] = 0 ; printf (" %s\n", ascii) ; } ; puts ("") ; } /* psf_hexdump */ void psf_log_SF_INFO (SF_PRIVATE *psf) { psf_log_printf (psf, "---------------------------------\n") ; psf_log_printf (psf, " Sample rate : %d\n", psf->sf.samplerate) ; psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; psf_log_printf (psf, " Channels : %d\n", psf->sf.channels) ; psf_log_printf (psf, " Format : 0x%X\n", psf->sf.format) ; psf_log_printf (psf, " Sections : %d\n", psf->sf.sections) ; psf_log_printf (psf, " Seekable : %s\n", psf->sf.seekable ? "TRUE" : "FALSE") ; psf_log_printf (psf, "---------------------------------\n") ; } /* psf_dump_SFINFO */ /*======================================================================================== */ SF_INSTRUMENT * psf_instrument_alloc (void) { SF_INSTRUMENT *instr ; instr = calloc (1, sizeof (SF_INSTRUMENT)) ; if (instr == NULL) return NULL ; /* Set non-zero default values. */ instr->basenote = -1 ; instr->velocity_lo = -1 ; instr->velocity_hi = -1 ; instr->key_lo = -1 ; instr->key_hi = -1 ; return instr ; } /* psf_instrument_alloc */ void* psf_memset (void *s, int c, sf_count_t len) { char *ptr ; int setcount ; ptr = (char *) s ; while (len > 0) { setcount = (len > 0x10000000) ? 0x10000000 : (int) len ; memset (ptr, c, setcount) ; ptr += setcount ; len -= setcount ; } ; return s ; } /* psf_memset */ void psf_get_date_str (char *str, int maxlen) { time_t current ; struct tm timedata, *tmptr ; time (¤t) ; #if defined (HAVE_GMTIME_R) /* If the re-entrant version is available, use it. */ tmptr = gmtime_r (¤t, &timedata) ; #elif defined (HAVE_GMTIME) /* Otherwise use the standard one and copy the data to local storage. */ tmptr = gmtime (¤t) ; memcpy (&timedata, tmptr, sizeof (timedata)) ; #else tmptr = NULL ; #endif if (tmptr) LSF_SNPRINTF (str, maxlen, "%4d-%02d-%02d %02d:%02d:%02d UTC", 1900 + timedata.tm_year, timedata.tm_mon, timedata.tm_mday, timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ; else LSF_SNPRINTF (str, maxlen, "Unknown date") ; return ; } /* psf_get_date_str */ int subformat_to_bytewidth (int format) { switch (format) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_S8 : return 1 ; case SF_FORMAT_PCM_16 : return 2 ; case SF_FORMAT_PCM_24 : return 3 ; case SF_FORMAT_PCM_32 : case SF_FORMAT_FLOAT : return 4 ; case SF_FORMAT_DOUBLE : return 8 ; } ; return 0 ; } /* subformat_to_bytewidth */ int s_bitwidth_to_subformat (int bits) { static int array [] = { SF_FORMAT_PCM_S8, SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 } ; if (bits < 8 || bits > 32) return 0 ; return array [((bits + 7) / 8) - 1] ; } /* bitwidth_to_subformat */ int u_bitwidth_to_subformat (int bits) { static int array [] = { SF_FORMAT_PCM_U8, SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 } ; if (bits < 8 || bits > 32) return 0 ; return array [((bits + 7) / 8) - 1] ; } /* bitwidth_to_subformat */ #endif /* PSF_LOG_PRINTF_ONLY */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 33e9795e-f717-461a-9feb-65d083a56395 */ nyquist-3.05/nylsf/w64.c0000644000175000000620000004347111466723256014127 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "wav_w64.h" /*------------------------------------------------------------------------------ ** W64 files use 16 byte markers as opposed to the four byte marker of ** WAV files. ** For comparison purposes, an integer is required, so make an integer ** hash for the 16 bytes using MAKE_HASH16 macro, but also create a 16 ** byte array containing the complete 16 bytes required when writing the ** header. */ #define MAKE_HASH16(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) \ ( (x0) ^ ((x1) << 1) ^ ((x2) << 2) ^ ((x3) << 3) ^ \ ((x4) << 4) ^ ((x5) << 5) ^ ((x6) << 6) ^ ((x7) << 7) ^ \ ((x8) << 8) ^ ((x9) << 9) ^ ((xa) << 10) ^ ((xb) << 11) ^ \ ((xc) << 12) ^ ((xd) << 13) ^ ((xe) << 14) ^ ((xf) << 15) ) #define MAKE_MARKER16(name,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) \ static unsigned char name [16] = { (x0), (x1), (x2), (x3), (x4), (x5), \ (x6), (x7), (x8), (x9), (xa), (xb), (xc), (xd), (xe), (xf) } #define riff_HASH16 MAKE_HASH16 ('r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, 0xA5, \ 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) #define wave_HASH16 MAKE_HASH16 ('w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, \ 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) #define fmt_HASH16 MAKE_HASH16 ('f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, \ 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) #define fact_HASH16 MAKE_HASH16 ('f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, \ 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) #define data_HASH16 MAKE_HASH16 ('d', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, \ 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) #define ACID_HASH16 MAKE_HASH16 (0x6D, 0x07, 0x1C, 0xEA, 0xA3, 0xEF, 0x78, 0x4C, \ 0x90, 0x57, 0x7F, 0x79, 0xEE, 0x25, 0x2A, 0xAE) MAKE_MARKER16 (riff_MARKER16, 'r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) ; MAKE_MARKER16 (wave_MARKER16, 'w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; MAKE_MARKER16 (fmt_MARKER16, 'f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; MAKE_MARKER16 (fact_MARKER16, 'f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; MAKE_MARKER16 (data_MARKER16, 'd', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; enum { HAVE_riff = 0x01, HAVE_wave = 0x02, HAVE_fmt = 0x04, HAVE_fact = 0x08, HAVE_data = 0x20 } ; /*------------------------------------------------------------------------------ * Private static functions. */ static int w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ; static int w64_write_header (SF_PRIVATE *psf, int calc_length) ; static int w64_close (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int w64_open (SF_PRIVATE *psf) { int subformat, error, blockalign = 0, framesperblock = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR &&psf->filelength > 0)) { if ((error = w64_read_header (psf, &blockalign, &framesperblock))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_W64) return SFE_BAD_OPEN_FORMAT ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; psf->endian = SF_ENDIAN_LITTLE ; /* All W64 files are little endian. */ psf->blockwidth = psf->bytewidth * psf->sf.channels ; if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) { blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; framesperblock = -1 ; /* FIXME : This block must go */ psf->filelength = SF_COUNT_MAX ; psf->datalength = psf->filelength ; if (psf->sf.frames <= 0) psf->sf.frames = (psf->blockwidth) ? psf->filelength / psf->blockwidth : psf->filelength ; /* EMXIF : This block must go */ } ; if ((error = w64_write_header (psf, SF_FALSE))) return error ; psf->write_header = w64_write_header ; } ; psf->container_close = w64_close ; switch (subformat) { case SF_FORMAT_PCM_U8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; case SF_FORMAT_IMA_ADPCM : error = wav_w64_ima_init (psf, blockalign, framesperblock) ; break ; case SF_FORMAT_MS_ADPCM : error = wav_w64_msadpcm_init (psf, blockalign, framesperblock) ; break ; /* Lite remove end */ case SF_FORMAT_GSM610 : error = gsm610_init (psf) ; break ; default : return SFE_UNIMPLEMENTED ; } ; return error ; } /* w64_open */ /*========================================================================= ** Private functions. */ static int w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) { WAV_FMT wav_fmt ; int dword = 0, marker, format = 0 ; sf_count_t chunk_size, bytesread = 0 ; int parsestage = 0, error, done = 0 ; /* Set position to start of file to begin reading header. */ memset (&wav_fmt, 0, sizeof (wav_fmt)) ; psf_binheader_readf (psf, "p", 0) ; while (! done) { /* Read the 4 byte marker and jump 12 bytes. */ bytesread += psf_binheader_readf (psf, "h", &marker) ; chunk_size = 0 ; switch (marker) { case riff_HASH16 : if (parsestage) return SFE_W64_NO_RIFF ; bytesread += psf_binheader_readf (psf, "e8", &chunk_size) ; if (psf->filelength < chunk_size) psf_log_printf (psf, "riff : %D (should be %D)\n", chunk_size, psf->filelength) ; else psf_log_printf (psf, "riff : %D\n", chunk_size) ; parsestage |= HAVE_riff ; break ; case ACID_HASH16: psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ; return SFE_UNIMPLEMENTED ; case wave_HASH16 : if ((parsestage & HAVE_riff) != HAVE_riff) return SFE_W64_NO_WAVE ; psf_log_printf (psf, "wave\n") ; parsestage |= HAVE_wave ; break ; case fmt_HASH16 : if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave)) return SFE_W64_NO_FMT ; bytesread += psf_binheader_readf (psf, "e8", &chunk_size) ; psf_log_printf (psf, " fmt : %D\n", chunk_size) ; /* size of 16 byte marker and 8 byte chunk_size value. */ chunk_size -= 24 ; if ((error = wav_w64_read_fmt_chunk (psf, &wav_fmt, (int) chunk_size))) return error ; if (chunk_size % 8) psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ; format = wav_fmt.format ; parsestage |= HAVE_fmt ; break ; case fact_HASH16: { sf_count_t frames ; psf_binheader_readf (psf, "e88", &chunk_size, &frames) ; psf_log_printf (psf, " fact : %D\n frames : %D\n", chunk_size, frames) ; } ; break ; case data_HASH16 : if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt)) return SFE_W64_NO_DATA ; psf_binheader_readf (psf, "e8", &chunk_size) ; psf->dataoffset = psf_ftell (psf) ; psf->datalength = chunk_size - 24 ; if (chunk_size % 8) chunk_size += 8 - (chunk_size % 8) ; psf_log_printf (psf, "data : %D\n", chunk_size) ; parsestage |= HAVE_data ; if (! psf->sf.seekable) break ; /* Seek past data and continue reading header. */ psf_fseek (psf, chunk_size, SEEK_CUR) ; break ; default : if (psf_ftell (psf) & 0x0F) { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ; psf_binheader_readf (psf, "j", -3) ; break ; } ; psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ; done = SF_TRUE ; break ; } ; /* switch (dword) */ if (psf->sf.seekable == 0 && (parsestage & HAVE_data)) break ; if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword)))) break ; } ; /* while (1) */ if (! psf->dataoffset) return SFE_W64_NO_DATA ; psf->endian = SF_ENDIAN_LITTLE ; /* All WAV files are little endian. */ if (psf_ftell (psf) != psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if (psf->blockwidth) { if (psf->filelength - psf->dataoffset < psf->datalength) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; else psf->sf.frames = psf->datalength / psf->blockwidth ; } ; switch (format) { case WAVE_FORMAT_PCM : case WAVE_FORMAT_EXTENSIBLE : /* extensible might be FLOAT, MULAW, etc as well! */ psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ; break ; case WAVE_FORMAT_MULAW : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ; break ; case WAVE_FORMAT_ALAW : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ; break ; case WAVE_FORMAT_MS_ADPCM : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ; *blockalign = wav_fmt.msadpcm.blockalign ; *framesperblock = wav_fmt.msadpcm.samplesperblock ; break ; case WAVE_FORMAT_IMA_ADPCM : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ; *blockalign = wav_fmt.ima.blockalign ; *framesperblock = wav_fmt.ima.samplesperblock ; break ; case WAVE_FORMAT_GSM610 : psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ; break ; case WAVE_FORMAT_IEEE_FLOAT : psf->sf.format = SF_FORMAT_W64 ; psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ; break ; default : return SFE_UNIMPLEMENTED ; } ; return 0 ; } /* w64_read_header */ static int w64_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t fmt_size, current ; size_t fmt_pad = 0 ; int subformat, add_fact_chunk = SF_FALSE ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; if (psf->bytewidth) psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* riff marker, length, wave and 'fmt ' markers. */ psf_binheader_writef (psf, "eh8hh", riff_MARKER16, psf->filelength - 8, wave_MARKER16, fmt_MARKER16) ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_PCM, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ; break ; case SF_FORMAT_FLOAT : case SF_FORMAT_DOUBLE : fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_IEEE_FLOAT, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_ULAW : fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_MULAW, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 8) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_ALAW : fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_ALAW, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 8) ; add_fact_chunk = SF_TRUE ; break ; /* Lite remove start */ case SF_FORMAT_IMA_ADPCM : { int blockalign, framesperblock, bytespersec ; blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; framesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ; bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; /* fmt chunk. */ fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : size, WAV format type, channels. */ psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_IMA_ADPCM, psf->sf.channels) ; /* fmt : samplerate, bytespersec. */ psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ; /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ psf_binheader_writef (psf, "e2222", blockalign, 4, 2, framesperblock) ; } ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_MS_ADPCM : { int blockalign, framesperblock, bytespersec, extrabytes ; blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; framesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ; bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; /* fmt chunk. */ extrabytes = 2 + 2 + MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ; fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : size, W64 format type, channels. */ psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_MS_ADPCM, psf->sf.channels) ; /* fmt : samplerate, bytespersec. */ psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ; /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ psf_binheader_writef (psf, "e22222", blockalign, 4, extrabytes, framesperblock, 7) ; msadpcm_write_adapt_coeffs (psf) ; } ; add_fact_chunk = SF_TRUE ; break ; /* Lite remove end */ case SF_FORMAT_GSM610 : { int bytespersec ; bytespersec = (psf->sf.samplerate * WAV_W64_GSM610_BLOCKSIZE) / WAV_W64_GSM610_SAMPLES ; /* fmt chunk. */ fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ; fmt_size += fmt_pad ; /* fmt : size, WAV format type, channels. */ psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_GSM610, psf->sf.channels) ; /* fmt : samplerate, bytespersec. */ psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ; /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ psf_binheader_writef (psf, "e2222", WAV_W64_GSM610_BLOCKSIZE, 0, 2, WAV_W64_GSM610_SAMPLES) ; } ; add_fact_chunk = SF_TRUE ; break ; default : return SFE_UNIMPLEMENTED ; } ; /* Pad to 8 bytes with zeros. */ if (fmt_pad > 0) psf_binheader_writef (psf, "z", fmt_pad) ; if (add_fact_chunk) psf_binheader_writef (psf, "eh88", fact_MARKER16, (sf_count_t) (16 + 8 + 8), psf->sf.frames) ; psf_binheader_writef (psf, "eh8", data_MARKER16, psf->datalength + 24) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* w64_write_header */ static int w64_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) w64_write_header (psf, SF_TRUE) ; return 0 ; } /* w64_close */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 9aa4e141-538a-4dd9-99c9-b3f0f2dd4f4a */ nyquist-3.05/nylsf/sfconfig.h0000644000175000000620000000424011466723256015301 0ustar stevestaff/* ** Copyright (C) 2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** Autoconf leaves many config parameters undefined. ** Here we change then from being undefined to defining them to 0. ** This allows things like: ** ** #if HAVE_CONFIG_PARAM ** ** and ** ** if (HAVE_CONFIG_PARAM) ** do_something () ; */ #ifndef SFCONFIG_H #define SFCONFIG_H /* Include the Autoconf generated file. */ #include "config.h" /* Now fiddle the values. */ #ifndef HAVE_ALSA_ASOUNDLIB_H #define HAVE_ALSA_ASOUNDLIB_H 0 #endif #ifndef HAVE_BYTESWAP_H #define HAVE_BYTESWAP_H 0 #endif #ifndef HAVE_DECL_S_IRGRP #define HAVE_DECL_S_IRGRP 0 #endif #ifndef HAVE_ENDIAN_H #define HAVE_ENDIAN_H 0 #endif #ifndef HAVE_FSYNC #define HAVE_FSYNC 0 #endif #ifndef HAVE_LOCALE_H #define HAVE_LOCALE_H 0 #endif #ifndef HAVE_LRINT #define HAVE_LRINT 0 #endif #ifndef HAVE_LRINTF #define HAVE_LRINTF 0 #endif #ifndef HAVE_MMAP #define HAVE_MMAP 0 #endif #ifndef HAVE_PREAD #define HAVE_PREAD 0 #endif #ifndef HAVE_PWRITE #define HAVE_PWRITE 0 #endif #ifndef HAVE_SETLOCALE #define HAVE_SETLOCALE 0 #endif #ifndef HAVE_SQLITE3 #define HAVE_SQLITE3 0 #endif #ifndef HAVE_STDINT_H #define HAVE_STDINT_H 0 #endif #ifndef HAVE_UNISTD_H #define HAVE_UNISTD_H 0 #endif #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 2df2316e-8f9d-4860-bba7-f3c16c63eed3 */ nyquist-3.05/nylsf/ogg.c0000644000175000000620000000242511466723256014255 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" int ogg_open (SF_PRIVATE *psf) { if (psf) return SFE_UNIMPLEMENTED ; return (psf && 0) ; } /* ogg_open */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 9ff1fe9c-629e-4e9c-9ef5-3d0eb1e427a0 */ nyquist-3.05/nylsf/test_endswap.c0000644000175000000620000001567111466723256016210 0ustar stevestaff/* ** Copyright (C) 2002-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #if HAVE_UNISTD_H #include #endif #include #include #include "common.h" #include "sfendian.h" #define FMT_SHORT "0x%04x\n" #define FMT_INT "0x%08x\n" #if SIZEOF_INT64_T == SIZEOF_LONG #define FMT_INT64 "0x%016lx\n" #else #define FMT_INT64 "0x%016llx\n" #endif static void test_endswap_short (void) ; static void test_endswap_int (void) ; static void test_endswap_int64_t (void) ; int main (void) { test_endswap_short () ; test_endswap_int () ; test_endswap_int64_t () ; return 0 ; } /* main */ /*============================================================================== ** Actual test functions. */ static void dump_short_array (const char * name, short * data, int datalen) { int k ; printf ("%-6s : ", name) ; for (k = 0 ; k < datalen ; k++) printf (FMT_SHORT, data [k]) ; putchar ('\n') ; } /* dump_short_array */ static void test_endswap_short (void) { short orig [4], first [4], second [4] ; int k ; printf (" %-24s : ", "test_endswap_short") ; fflush (stdout) ; for (k = 0 ; k < ARRAY_LEN (orig) ; k++) orig [k] = 0x3210 + k ; endswap_short_copy (first, orig, ARRAY_LEN (first)) ; endswap_short_copy (second, first, ARRAY_LEN (second)) ; if (memcmp (orig, first, sizeof (orig)) == 0) { printf ("\n\nLine %d : test 1 : these two array should not be the same:\n\n", __LINE__) ; dump_short_array ("orig", orig, ARRAY_LEN (orig)) ; dump_short_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; if (memcmp (orig, second, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 2 : these two array should be the same:\n\n", __LINE__) ; dump_short_array ("orig", orig, ARRAY_LEN (orig)) ; dump_short_array ("second", second, ARRAY_LEN (second)) ; exit (1) ; } ; endswap_short_array (first, ARRAY_LEN (first)) ; if (memcmp (orig, first, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 3 : these two array should be the same:\n\n", __LINE__) ; dump_short_array ("orig", orig, ARRAY_LEN (orig)) ; dump_short_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; endswap_short_copy (first, orig, ARRAY_LEN (first)) ; endswap_short_copy (first, first, ARRAY_LEN (first)) ; if (memcmp (orig, first, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 4 : these two array should be the same:\n\n", __LINE__) ; dump_short_array ("orig", orig, ARRAY_LEN (orig)) ; dump_short_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; puts ("ok") ; } /* test_endswap_short */ static void dump_int_array (const char * name, int * data, int datalen) { int k ; printf ("%-6s : ", name) ; for (k = 0 ; k < datalen ; k++) printf (FMT_INT, data [k]) ; putchar ('\n') ; } /* dump_int_array */ static void test_endswap_int (void) { int orig [4], first [4], second [4] ; int k ; printf (" %-24s : ", "test_endswap_int") ; fflush (stdout) ; for (k = 0 ; k < ARRAY_LEN (orig) ; k++) orig [k] = 0x76543210 + k ; endswap_int_copy (first, orig, ARRAY_LEN (first)) ; endswap_int_copy (second, first, ARRAY_LEN (second)) ; if (memcmp (orig, first, sizeof (orig)) == 0) { printf ("\n\nLine %d : test 1 : these two array should not be the same:\n\n", __LINE__) ; dump_int_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; if (memcmp (orig, second, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 2 : these two array should be the same:\n\n", __LINE__) ; dump_int_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int_array ("second", second, ARRAY_LEN (second)) ; exit (1) ; } ; endswap_int_array (first, ARRAY_LEN (first)) ; if (memcmp (orig, first, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 3 : these two array should be the same:\n\n", __LINE__) ; dump_int_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; endswap_int_copy (first, orig, ARRAY_LEN (first)) ; endswap_int_copy (first, first, ARRAY_LEN (first)) ; if (memcmp (orig, first, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 4 : these two array should be the same:\n\n", __LINE__) ; dump_int_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; puts ("ok") ; } /* test_endswap_int */ static void dump_int64_t_array (const char * name, int64_t * data, int datalen) { int k ; printf ("%-6s : ", name) ; for (k = 0 ; k < datalen ; k++) printf (FMT_INT64, data [k]) ; putchar ('\n') ; } /* dump_int64_t_array */ static void test_endswap_int64_t (void) { int64_t orig [4], first [4], second [4] ; int k ; printf (" %-24s : ", "test_endswap_int64_t") ; fflush (stdout) ; for (k = 0 ; k < ARRAY_LEN (orig) ; k++) orig [k] = 0x0807050540302010LL + k ; endswap_int64_t_copy (first, orig, ARRAY_LEN (first)) ; endswap_int64_t_copy (second, first, ARRAY_LEN (second)) ; if (memcmp (orig, first, sizeof (orig)) == 0) { printf ("\n\nLine %d : test 1 : these two array should not be the same:\n\n", __LINE__) ; dump_int64_t_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int64_t_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; if (memcmp (orig, second, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 2 : these two array should be the same:\n\n", __LINE__) ; dump_int64_t_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int64_t_array ("second", second, ARRAY_LEN (second)) ; exit (1) ; } ; endswap_int64_t_array (first, ARRAY_LEN (first)) ; if (memcmp (orig, first, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 3 : these two array should be the same:\n\n", __LINE__) ; dump_int64_t_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int64_t_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; endswap_int64_t_copy (first, orig, ARRAY_LEN (first)) ; endswap_int64_t_copy (first, first, ARRAY_LEN (first)) ; if (memcmp (orig, first, sizeof (orig)) != 0) { printf ("\n\nLine %d : test 4 : these two array should be the same:\n\n", __LINE__) ; dump_int64_t_array ("orig", orig, ARRAY_LEN (orig)) ; dump_int64_t_array ("first", first, ARRAY_LEN (first)) ; exit (1) ; } ; puts ("ok") ; } /* test_endswap_int64_t */ nyquist-3.05/nylsf/dither.c0000644000175000000620000003446011466723256014764 0ustar stevestaff/* ** Copyright (C) 2003,2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*============================================================================ ** Rule number 1 is to only apply dither when going from a larger bitwidth ** to a smaller bitwidth. This can happen on both read and write. ** ** Need to apply dither on all conversions marked X below. ** ** Dither on write: ** ** Input ** | short int float double ** --------+----------------------------------------------- ** O 8 bit | X X X X ** u 16 bit | none X X X ** t 24 bit | none X X X ** p 32 bit | none none X X ** u float | none none none none ** t double | none none none none ** ** Dither on read: ** ** Input ** O | 8 bit 16 bit 24 bit 32 bit float double ** u --------+------------------------------------------------- ** t short | none none X X X X ** p int | none none none X X X ** u float | none none none none none none ** t double | none none none none none none */ #define SFE_DITHER_BAD_PTR 666 #define SFE_DITHER_BAD_TYPE 667 typedef struct { int read_short_dither_bits, read_int_dither_bits ; int write_short_dither_bits, write_int_dither_bits ; double read_float_dither_scale, read_double_dither_bits ; double write_float_dither_scale, write_double_dither_bits ; sf_count_t (*read_short) (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; sf_count_t (*read_int) (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; sf_count_t (*read_float) (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; sf_count_t (*read_double) (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; sf_count_t (*write_short) (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; sf_count_t (*write_int) (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; sf_count_t (*write_float) (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; sf_count_t (*write_double) (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; double buffer [SF_BUFFER_LEN / sizeof (double)] ; } DITHER_DATA ; static sf_count_t dither_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t dither_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t dither_write_short (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t dither_write_int (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t dither_write_float (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t dither_write_double (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; int dither_init (SF_PRIVATE *psf, int mode) { DITHER_DATA *pdither ; pdither = psf->dither ; /* This may be NULL. */ /* Turn off dither on read. */ if (mode == SFM_READ && psf->read_dither.type == SFD_NO_DITHER) { if (pdither == NULL) return 0 ; /* Dither is already off, so just return. */ if (pdither->read_short) psf->read_short = pdither->read_short ; if (pdither->read_int) psf->read_int = pdither->read_int ; if (pdither->read_float) psf->read_float = pdither->read_float ; if (pdither->read_double) psf->read_double = pdither->read_double ; return 0 ; } ; /* Turn off dither on write. */ if (mode == SFM_WRITE && psf->write_dither.type == SFD_NO_DITHER) { if (pdither == NULL) return 0 ; /* Dither is already off, so just return. */ if (pdither->write_short) psf->write_short = pdither->write_short ; if (pdither->write_int) psf->write_int = pdither->write_int ; if (pdither->write_float) psf->write_float = pdither->write_float ; if (pdither->write_double) psf->write_double = pdither->write_double ; return 0 ; } ; /* Turn on dither on read if asked. */ if (mode == SFM_READ && psf->read_dither.type != 0) { if (pdither == NULL) pdither = psf->dither = calloc (1, sizeof (DITHER_DATA)) ; if (pdither == NULL) return SFE_MALLOC_FAILED ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_DOUBLE : case SF_FORMAT_FLOAT : pdither->read_int = psf->read_int ; psf->read_int = dither_read_int ; case SF_FORMAT_PCM_32 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : pdither->read_short = psf->read_short ; psf->read_short = dither_read_short ; default : break ; } ; } ; /* Turn on dither on write if asked. */ if (mode == SFM_WRITE && psf->write_dither.type != 0) { if (pdither == NULL) pdither = psf->dither = calloc (1, sizeof (DITHER_DATA)) ; if (pdither == NULL) return SFE_MALLOC_FAILED ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_DOUBLE : case SF_FORMAT_FLOAT : pdither->write_int = psf->write_int ; psf->write_int = dither_write_int ; case SF_FORMAT_PCM_32 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : default : break ; } ; pdither->write_short = psf->write_short ; psf->write_short = dither_write_short ; pdither->write_int = psf->write_int ; psf->write_int = dither_write_int ; pdither->write_float = psf->write_float ; psf->write_float = dither_write_float ; pdither->write_double = psf->write_double ; psf->write_double = dither_write_double ; } ; return 0 ; } /* dither_init */ /*============================================================================== */ static void dither_short (const short *in, short *out, int frames, int channels) ; static void dither_int (const int *in, int *out, int frames, int channels) ; static void dither_float (const float *in, float *out, int frames, int channels) ; static void dither_double (const double *in, double *out, int frames, int channels) ; static sf_count_t dither_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) { psf = psf ; ptr = ptr ; return len ; } /* dither_read_short */ static sf_count_t dither_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) { psf = psf ; ptr = ptr ; return len ; } /* dither_read_int */ /*------------------------------------------------------------------------------ */ static sf_count_t dither_write_short (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { DITHER_DATA *pdither ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; if ((pdither = psf->dither) == NULL) { psf->error = SFE_DITHER_BAD_PTR ; return 0 ; } ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : case SF_FORMAT_DPCM_8 : break ; default : return pdither->write_short (psf, ptr, len) ; } ; bufferlen = sizeof (pdither->buffer) / sizeof (short) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; writecount /= psf->sf.channels ; writecount *= psf->sf.channels ; dither_short (ptr, (short*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; thiswrite = pdither->write_short (psf, (short*) pdither->buffer, writecount) ; total += thiswrite ; len -= thiswrite ; if (thiswrite < writecount) break ; } ; return total ; } /* dither_write_short */ static sf_count_t dither_write_int (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { DITHER_DATA *pdither ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; if ((pdither = psf->dither) == NULL) { psf->error = SFE_DITHER_BAD_PTR ; return 0 ; } ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_DPCM_8 : case SF_FORMAT_DPCM_16 : break ; default : return pdither->write_int (psf, ptr, len) ; } ; bufferlen = sizeof (pdither->buffer) / sizeof (int) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; writecount /= psf->sf.channels ; writecount *= psf->sf.channels ; dither_int (ptr, (int*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; thiswrite = pdither->write_int (psf, (int*) pdither->buffer, writecount) ; total += thiswrite ; len -= thiswrite ; if (thiswrite < writecount) break ; } ; return total ; } /* dither_write_int */ static sf_count_t dither_write_float (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { DITHER_DATA *pdither ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; if ((pdither = psf->dither) == NULL) { psf->error = SFE_DITHER_BAD_PTR ; return 0 ; } ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_DPCM_8 : case SF_FORMAT_DPCM_16 : break ; default : return pdither->write_float (psf, ptr, len) ; } ; bufferlen = sizeof (pdither->buffer) / sizeof (float) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (float) len ; writecount /= psf->sf.channels ; writecount *= psf->sf.channels ; dither_float (ptr, (float*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; thiswrite = pdither->write_float (psf, (float*) pdither->buffer, writecount) ; total += thiswrite ; len -= thiswrite ; if (thiswrite < writecount) break ; } ; return total ; } /* dither_write_float */ static sf_count_t dither_write_double (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { DITHER_DATA *pdither ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; if ((pdither = psf->dither) == NULL) { psf->error = SFE_DITHER_BAD_PTR ; return 0 ; } ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_DPCM_8 : case SF_FORMAT_DPCM_16 : break ; default : return pdither->write_double (psf, ptr, len) ; } ; bufferlen = sizeof (pdither->buffer) / sizeof (double) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (double) len ; writecount /= psf->sf.channels ; writecount *= psf->sf.channels ; dither_double (ptr, (double*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; thiswrite = pdither->write_double (psf, (double*) pdither->buffer, writecount) ; total += thiswrite ; len -= thiswrite ; if (thiswrite < writecount) break ; } ; return total ; } /* dither_write_double */ /*============================================================================== */ static void dither_short (const short *in, short *out, int frames, int channels) { int ch, k ; for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; } /* dither_short */ static void dither_int (const int *in, int *out, int frames, int channels) { int ch, k ; for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; } /* dither_int */ static void dither_float (const float *in, float *out, int frames, int channels) { int ch, k ; for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; } /* dither_float */ static void dither_double (const double *in, double *out, int frames, int channels) { int ch, k ; for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; } /* dither_double */ /*============================================================================== */ #if 0 /* ** Not made public because this (maybe) requires storage of state information. ** ** Also maybe need separate state info for each channel!!!! */ int DO_NOT_USE_sf_dither_short (const SF_DITHER_INFO *dither, const short *in, short *out, int frames, int channels) { int ch, k ; if (! dither) return SFE_DITHER_BAD_PTR ; switch (dither->type & SFD_TYPEMASK) { case SFD_WHITE : case SFD_TRIANGULAR_PDF : for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; break ; default : return SFE_DITHER_BAD_TYPE ; } ; return 0 ; } /* DO_NOT_USE_sf_dither_short */ int DO_NOT_USE_sf_dither_int (const SF_DITHER_INFO *dither, const int *in, int *out, int frames, int channels) { int ch, k ; if (! dither) return SFE_DITHER_BAD_PTR ; switch (dither->type & SFD_TYPEMASK) { case SFD_WHITE : case SFD_TRIANGULAR_PDF : for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; break ; default : return SFE_DITHER_BAD_TYPE ; } ; return 0 ; } /* DO_NOT_USE_sf_dither_int */ int DO_NOT_USE_sf_dither_float (const SF_DITHER_INFO *dither, const float *in, float *out, int frames, int channels) { int ch, k ; if (! dither) return SFE_DITHER_BAD_PTR ; switch (dither->type & SFD_TYPEMASK) { case SFD_WHITE : case SFD_TRIANGULAR_PDF : for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; break ; default : return SFE_DITHER_BAD_TYPE ; } ; return 0 ; } /* DO_NOT_USE_sf_dither_float */ int DO_NOT_USE_sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int frames, int channels) { int ch, k ; if (! dither) return SFE_DITHER_BAD_PTR ; switch (dither->type & SFD_TYPEMASK) { case SFD_WHITE : case SFD_TRIANGULAR_PDF : for (ch = 0 ; ch < channels ; ch++) for (k = ch ; k < channels * frames ; k += channels) out [k] = in [k] ; break ; default : return SFE_DITHER_BAD_TYPE ; } ; return 0 ; } /* DO_NOT_USE_sf_dither_double */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 673fad58-5314-421c-9144-9d54bfdf104c */ nyquist-3.05/nylsf/gsm610.c0000644000175000000620000004313611466723256014522 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" #include "wav_w64.h" #include "GSM610/gsm.h" #define GSM610_BLOCKSIZE 33 #define GSM610_SAMPLES 160 typedef struct gsm610_tag { int blocks ; int blockcount, samplecount ; int samplesperblock, blocksize ; int (*decode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ; int (*encode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ; short samples [WAV_W64_GSM610_SAMPLES] ; unsigned char block [WAV_W64_GSM610_BLOCKSIZE] ; /* Damn I hate typedef-ed pointers; yes, gsm is a pointer type. */ gsm gsm_data ; } GSM610_PRIVATE ; static sf_count_t gsm610_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t gsm610_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t gsm610_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t gsm610_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t gsm610_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t gsm610_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t gsm610_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t gsm610_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static int gsm610_read_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len) ; static int gsm610_write_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len) ; static int gsm610_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; static int gsm610_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; static int gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; static int gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; static sf_count_t gsm610_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int gsm610_close (SF_PRIVATE *psf) ; /*============================================================================================ ** WAV GSM610 initialisation function. */ int gsm610_init (SF_PRIVATE *psf) { GSM610_PRIVATE *pgsm610 ; int true_flag = 1 ; if (psf->codec_data != NULL) { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; return SFE_INTERNAL ; } ; if (psf->mode == SFM_RDWR) return SFE_BAD_MODE_RW ; psf->sf.seekable = SF_FALSE ; if ((pgsm610 = calloc (1, sizeof (GSM610_PRIVATE))) == NULL) return SFE_MALLOC_FAILED ; psf->codec_data = pgsm610 ; memset (pgsm610, 0, sizeof (GSM610_PRIVATE)) ; /*============================================================ Need separate gsm_data structs for encode and decode. ============================================================*/ if ((pgsm610->gsm_data = gsm_create ()) == NULL) return SFE_MALLOC_FAILED ; switch (psf->sf.format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : case SF_FORMAT_WAVEX : case SF_FORMAT_W64 : gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ; pgsm610->encode_block = gsm610_wav_encode_block ; pgsm610->decode_block = gsm610_wav_decode_block ; pgsm610->samplesperblock = WAV_W64_GSM610_SAMPLES ; pgsm610->blocksize = WAV_W64_GSM610_BLOCKSIZE ; break ; case SF_FORMAT_AIFF : case SF_FORMAT_RAW : pgsm610->encode_block = gsm610_encode_block ; pgsm610->decode_block = gsm610_decode_block ; pgsm610->samplesperblock = GSM610_SAMPLES ; pgsm610->blocksize = GSM610_BLOCKSIZE ; break ; default : return SFE_INTERNAL ; break ; } ; if (psf->mode == SFM_READ) { if (psf->datalength % pgsm610->blocksize == 0) pgsm610->blocks = psf->datalength / pgsm610->blocksize ; else if (psf->datalength % pgsm610->blocksize == 1 && pgsm610->blocksize == GSM610_BLOCKSIZE) { /* ** Weird AIFF specific case. ** AIFF chunks must be at an even offset from the start of file and ** GSM610_BLOCKSIZE is odd which can result in an odd length SSND ** chunk. The SSND chunk then gets padded on write which means that ** when it is read the datalength is too big by 1. */ pgsm610->blocks = psf->datalength / pgsm610->blocksize ; } else { psf_log_printf (psf, "*** Warning : data chunk seems to be truncated.\n") ; pgsm610->blocks = psf->datalength / pgsm610->blocksize + 1 ; } ; psf->sf.frames = pgsm610->samplesperblock * pgsm610->blocks ; pgsm610->decode_block (psf, pgsm610) ; /* Read first block. */ psf->read_short = gsm610_read_s ; psf->read_int = gsm610_read_i ; psf->read_float = gsm610_read_f ; psf->read_double = gsm610_read_d ; } ; if (psf->mode == SFM_WRITE) { pgsm610->blockcount = 0 ; pgsm610->samplecount = 0 ; psf->write_short = gsm610_write_s ; psf->write_int = gsm610_write_i ; psf->write_float = gsm610_write_f ; psf->write_double = gsm610_write_d ; } ; psf->codec_close = gsm610_close ; psf->seek = gsm610_seek ; psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; return 0 ; } /* gsm610_init */ /*============================================================================================ ** GSM 6.10 Read Functions. */ static int gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) { int k ; pgsm610->blockcount ++ ; pgsm610->samplecount = 0 ; if (pgsm610->blockcount > pgsm610->blocks) { memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ; return 1 ; } ; if ((k = psf_fread (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ; if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0) { psf_log_printf (psf, "Error from gsm_decode() on frame : %d\n", pgsm610->blockcount) ; return 0 ; } ; if (gsm_decode (pgsm610->gsm_data, pgsm610->block + (WAV_W64_GSM610_BLOCKSIZE + 1) / 2, pgsm610->samples + WAV_W64_GSM610_SAMPLES / 2) < 0) { psf_log_printf (psf, "Error from gsm_decode() on frame : %d.5\n", pgsm610->blockcount) ; return 0 ; } ; return 1 ; } /* gsm610_wav_decode_block */ static int gsm610_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) { int k ; pgsm610->blockcount ++ ; pgsm610->samplecount = 0 ; if (pgsm610->blockcount > pgsm610->blocks) { memset (pgsm610->samples, 0, GSM610_SAMPLES * sizeof (short)) ; return 1 ; } ; if ((k = psf_fread (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, GSM610_BLOCKSIZE) ; if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0) { psf_log_printf (psf, "Error from gsm_decode() on frame : %d\n", pgsm610->blockcount) ; return 0 ; } ; return 1 ; } /* gsm610_decode_block */ static int gsm610_read_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { if (pgsm610->blockcount >= pgsm610->blocks && pgsm610->samplecount >= pgsm610->samplesperblock) { memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ; return total ; } ; if (pgsm610->samplecount >= pgsm610->samplesperblock) pgsm610->decode_block (psf, pgsm610) ; count = pgsm610->samplesperblock - pgsm610->samplecount ; count = (len - indx > count) ? count : len - indx ; memcpy (&(ptr [indx]), &(pgsm610->samples [pgsm610->samplecount]), count * sizeof (short)) ; indx += count ; pgsm610->samplecount += count ; total = indx ; } ; return total ; } /* gsm610_read_block */ static sf_count_t gsm610_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; int readcount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; while (len > 0) { readcount = (len > 0x10000000) ? 0x1000000 : (int) len ; count = gsm610_read_block (psf, pgsm610, ptr, readcount) ; total += count ; len -= count ; if (count != readcount) break ; } ; return total ; } /* gsm610_read_s */ static sf_count_t gsm610_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = gsm610_read_block (psf, pgsm610, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = sptr [k] << 16 ; total += count ; len -= readcount ; } ; return total ; } /* gsm610_read_i */ static sf_count_t gsm610_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = gsm610_read_block (psf, pgsm610, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * sptr [k] ; total += count ; len -= readcount ; } ; return total ; } /* gsm610_read_f */ static sf_count_t gsm610_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = gsm610_read_block (psf, pgsm610, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * sptr [k] ; total += count ; len -= readcount ; } ; return total ; } /* gsm610_read_d */ static sf_count_t gsm610_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { GSM610_PRIVATE *pgsm610 ; int newblock, newsample ; mode = mode ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; if (psf->dataoffset < 0) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (offset == 0) { int true_flag = 1 ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; pgsm610->blockcount = 0 ; gsm_init (pgsm610->gsm_data) ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV || (psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_W64) gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ; pgsm610->decode_block (psf, pgsm610) ; pgsm610->samplecount = 0 ; return 0 ; } ; if (offset < 0 || offset > pgsm610->blocks * pgsm610->samplesperblock) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; newblock = offset / pgsm610->samplesperblock ; newsample = offset % pgsm610->samplesperblock ; if (psf->mode == SFM_READ) { if (psf->read_current != newblock * pgsm610->samplesperblock + newsample) { psf_fseek (psf, psf->dataoffset + newblock * pgsm610->samplesperblock, SEEK_SET) ; pgsm610->blockcount = newblock ; pgsm610->decode_block (psf, pgsm610) ; pgsm610->samplecount = newsample ; } ; return newblock * pgsm610->samplesperblock + newsample ; } ; /* What to do about write??? */ psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } /* gsm610_seek */ /*========================================================================================== ** GSM 6.10 Write Functions. */ static int gsm610_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) { int k ; /* Encode the samples. */ gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ; /* Write the block to disk. */ if ((k = psf_fwrite (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, GSM610_BLOCKSIZE) ; pgsm610->samplecount = 0 ; pgsm610->blockcount ++ ; /* Set samples to zero for next block. */ memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ; return 1 ; } /* gsm610_encode_block */ static int gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) { int k ; /* Encode the samples. */ gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ; gsm_encode (pgsm610->gsm_data, pgsm610->samples+WAV_W64_GSM610_SAMPLES/2, pgsm610->block+WAV_W64_GSM610_BLOCKSIZE/2) ; /* Write the block to disk. */ if ((k = psf_fwrite (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ; pgsm610->samplecount = 0 ; pgsm610->blockcount ++ ; /* Set samples to zero for next block. */ memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ; return 1 ; } /* gsm610_wav_encode_block */ static int gsm610_write_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { count = pgsm610->samplesperblock - pgsm610->samplecount ; if (count > len - indx) count = len - indx ; memcpy (&(pgsm610->samples [pgsm610->samplecount]), &(ptr [indx]), count * sizeof (short)) ; indx += count ; pgsm610->samplecount += count ; total = indx ; if (pgsm610->samplecount >= pgsm610->samplesperblock) pgsm610->encode_block (psf, pgsm610) ; } ; return total ; } /* gsm610_write_block */ static sf_count_t gsm610_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; int writecount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; while (len > 0) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = gsm610_write_block (psf, pgsm610, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* gsm610_write_s */ static sf_count_t gsm610_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; short *sptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = ptr [total + k] >> 16 ; count = gsm610_write_block (psf, pgsm610, sptr, writecount) ; total += count ; len -= writecount ; } ; return total ; } /* gsm610_write_i */ static sf_count_t gsm610_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; short *sptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrintf (normfact * ptr [total + k]) ; count = gsm610_write_block (psf, pgsm610, sptr, writecount) ; total += count ; len -= writecount ; } ; return total ; } /* gsm610_write_f */ static sf_count_t gsm610_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { GSM610_PRIVATE *pgsm610 ; short *sptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrint (normfact * ptr [total + k]) ; count = gsm610_write_block (psf, pgsm610, sptr, writecount) ; total += count ; len -= writecount ; } ; return total ; } /* gsm610_write_d */ static int gsm610_close (SF_PRIVATE *psf) { GSM610_PRIVATE *pgsm610 ; if (psf->codec_data == NULL) return 0 ; pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; if (psf->mode == SFM_WRITE) { /* If a block has been partially assembled, write it out ** as the final block. */ if (pgsm610->samplecount && pgsm610->samplecount < pgsm610->samplesperblock) pgsm610->encode_block (psf, pgsm610) ; } ; if (pgsm610->gsm_data) gsm_destroy (pgsm610->gsm_data) ; return 0 ; } /* gsm610_close */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 8575187d-af4f-4acf-b9dd-6ff705628345 */ nyquist-3.05/nylsf/svx.c0000644000175000000620000002671411466723256014330 0ustar stevestaff/* ** Copyright (C) 1999-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ * Macros to handle big/little endian issues. */ #define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M')) #define SVX8_MARKER (MAKE_MARKER ('8', 'S', 'V', 'X')) #define SV16_MARKER (MAKE_MARKER ('1', '6', 'S', 'V')) #define VHDR_MARKER (MAKE_MARKER ('V', 'H', 'D', 'R')) #define BODY_MARKER (MAKE_MARKER ('B', 'O', 'D', 'Y')) #define ATAK_MARKER (MAKE_MARKER ('A', 'T', 'A', 'K')) #define RLSE_MARKER (MAKE_MARKER ('R', 'L', 'S', 'E')) #define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' ')) #define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E')) #define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H')) #define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O')) #define CHAN_MARKER (MAKE_MARKER ('C', 'H', 'A', 'N')) /*------------------------------------------------------------------------------ * Typedefs for file chunks. */ typedef struct { unsigned int oneShotHiSamples, repeatHiSamples, samplesPerHiCycle ; unsigned short samplesPerSec ; unsigned char octave, compression ; unsigned int volume ; } VHDR_CHUNK ; enum { HAVE_FORM = 0x01, HAVE_SVX = 0x02, HAVE_VHDR = 0x04, HAVE_BODY = 0x08 } ; /*------------------------------------------------------------------------------ * Private static functions. */ static int svx_close (SF_PRIVATE *psf) ; static int svx_write_header (SF_PRIVATE *psf, int calc_length) ; static int svx_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int svx_open (SF_PRIVATE *psf) { int error ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = svx_read_header (psf))) return error ; psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */ psf->blockwidth = psf->sf.channels * psf->bytewidth ; if (psf->blockwidth) psf->sf.frames = psf->datalength / psf->blockwidth ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SVX) return SFE_BAD_OPEN_FORMAT ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (psf->endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU)) return SFE_BAD_ENDIAN ; psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */ error = svx_write_header (psf, SF_FALSE) ; if (error) return error ; psf->write_header = svx_write_header ; } ; psf->container_close = svx_close ; if ((error = pcm_init (psf))) return error ; return 0 ; } /* svx_open */ /*------------------------------------------------------------------------------ */ static int svx_read_header (SF_PRIVATE *psf) { VHDR_CHUNK vhdr ; unsigned int FORMsize, vhdrsize, dword, marker ; int filetype = 0, parsestage = 0, done = 0 ; int bytecount = 0, channels ; memset (&vhdr, 0, sizeof (vhdr)) ; psf_binheader_readf (psf, "p", 0) ; /* Set default number of channels. Currently can't handle stereo SVX files. */ psf->sf.channels = 1 ; psf->sf.format = SF_FORMAT_SVX ; while (! done) { psf_binheader_readf (psf, "m", &marker) ; switch (marker) { case FORM_MARKER : if (parsestage) return SFE_SVX_NO_FORM ; psf_binheader_readf (psf, "E4", &FORMsize) ; if (FORMsize != psf->filelength - 2 * sizeof (dword)) { dword = psf->filelength - 2 * sizeof (dword) ; psf_log_printf (psf, "FORM : %d (should be %d)\n", FORMsize, dword) ; FORMsize = dword ; } else psf_log_printf (psf, "FORM : %d\n", FORMsize) ; parsestage |= HAVE_FORM ; break ; case SVX8_MARKER : case SV16_MARKER : if (! (parsestage & HAVE_FORM)) return SFE_SVX_NO_FORM ; filetype = marker ; psf_log_printf (psf, " %M\n", marker) ; parsestage |= HAVE_SVX ; break ; case VHDR_MARKER : if (! (parsestage & (HAVE_FORM | HAVE_SVX))) return SFE_SVX_NO_FORM ; psf_binheader_readf (psf, "E4", &vhdrsize) ; psf_log_printf (psf, " VHDR : %d\n", vhdrsize) ; psf_binheader_readf (psf, "E4442114", &(vhdr.oneShotHiSamples), &(vhdr.repeatHiSamples), &(vhdr.samplesPerHiCycle), &(vhdr.samplesPerSec), &(vhdr.octave), &(vhdr.compression), &(vhdr.volume)) ; psf_log_printf (psf, " OneShotHiSamples : %d\n", vhdr.oneShotHiSamples) ; psf_log_printf (psf, " RepeatHiSamples : %d\n", vhdr.repeatHiSamples) ; psf_log_printf (psf, " samplesPerHiCycle : %d\n", vhdr.samplesPerHiCycle) ; psf_log_printf (psf, " Sample Rate : %d\n", vhdr.samplesPerSec) ; psf_log_printf (psf, " Octave : %d\n", vhdr.octave) ; psf_log_printf (psf, " Compression : %d => ", vhdr.compression) ; switch (vhdr.compression) { case 0 : psf_log_printf (psf, "None.\n") ; break ; case 1 : psf_log_printf (psf, "Fibonacci delta\n") ; break ; case 2 : psf_log_printf (psf, "Exponential delta\n") ; break ; } ; psf_log_printf (psf, " Volume : %d\n", vhdr.volume) ; psf->sf.samplerate = vhdr.samplesPerSec ; if (filetype == SVX8_MARKER) { psf->sf.format |= SF_FORMAT_PCM_S8 ; psf->bytewidth = 1 ; } else if (filetype == SV16_MARKER) { psf->sf.format |= SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; } ; parsestage |= HAVE_VHDR ; break ; case BODY_MARKER : if (! (parsestage & HAVE_VHDR)) return SFE_SVX_NO_BODY ; psf_binheader_readf (psf, "E4", &dword) ; psf->datalength = dword ; psf->dataoffset = psf_ftell (psf) ; if (psf->datalength > psf->filelength - psf->dataoffset) { psf_log_printf (psf, " BODY : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ; psf->datalength = psf->filelength - psf->dataoffset ; } else psf_log_printf (psf, " BODY : %D\n", psf->datalength) ; parsestage |= HAVE_BODY ; if (! psf->sf.seekable) break ; psf_fseek (psf, psf->datalength, SEEK_CUR) ; break ; case NAME_MARKER : if (! (parsestage & HAVE_SVX)) return SFE_SVX_NO_FORM ; psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; if (strlen (psf->filename) != dword) { if (dword > sizeof (psf->filename) - 1) return SFE_SVX_BAD_NAME_LENGTH ; psf_binheader_readf (psf, "b", psf->filename, dword) ; psf->filename [dword] = 0 ; } else psf_binheader_readf (psf, "j", dword) ; break ; case ANNO_MARKER : if (! (parsestage & HAVE_SVX)) return SFE_SVX_NO_FORM ; psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; case CHAN_MARKER : if (! (parsestage & HAVE_SVX)) return SFE_SVX_NO_FORM ; psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; bytecount += psf_binheader_readf (psf, "E4", &channels) ; psf->sf.channels = channels ; psf_log_printf (psf, " Channels : %d\n", channels) ; psf_binheader_readf (psf, "j", dword - bytecount) ; break ; case AUTH_MARKER : case c_MARKER : if (! (parsestage & HAVE_SVX)) return SFE_SVX_NO_FORM ; psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; default : if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF) && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF)) { psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, "%M : %d (unknown marker)\n", marker, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; } ; if ((dword = psf_ftell (psf)) & 0x03) { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ; psf_binheader_readf (psf, "j", -3) ; break ; } ; psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ; done = 1 ; } ; /* switch (marker) */ if (! psf->sf.seekable && (parsestage & HAVE_BODY)) break ; if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (dword)) break ; } ; /* while (1) */ if (vhdr.compression) return SFE_SVX_BAD_COMP ; if (psf->dataoffset <= 0) return SFE_SVX_NO_DATA ; return 0 ; } /* svx_read_header */ static int svx_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) svx_write_header (psf, SF_TRUE) ; return 0 ; } /* svx_close */ static int svx_write_header (SF_PRIVATE *psf, int calc_length) { static char annotation [] = "libsndfile by Erik de Castro Lopo\0\0\0" ; sf_count_t current ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* FORM marker and FORM size. */ psf_binheader_writef (psf, "Etm8", FORM_MARKER, (psf->filelength < 8) ? psf->filelength * 0 : psf->filelength - 8) ; psf_binheader_writef (psf, "m", (psf->bytewidth == 1) ? SVX8_MARKER : SV16_MARKER) ; /* VHDR chunk. */ psf_binheader_writef (psf, "Em4", VHDR_MARKER, sizeof (VHDR_CHUNK)) ; /* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */ psf_binheader_writef (psf, "E444", psf->sf.frames, 0, 0) ; /* VHDR : samplesPerSec, octave, compression */ psf_binheader_writef (psf, "E211", psf->sf.samplerate, 1, 0) ; /* VHDR : volume */ psf_binheader_writef (psf, "E4", (psf->bytewidth == 1) ? 0xFF : 0xFFFF) ; /* Filename and annotation strings. */ psf_binheader_writef (psf, "Emsms", NAME_MARKER, psf->filename, ANNO_MARKER, annotation) ; /* BODY marker and size. */ psf_binheader_writef (psf, "Etm8", BODY_MARKER, (psf->datalength < 0) ? psf->datalength * 0 : psf->datalength) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* svx_write_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: a80ab6fb-7d75-4d32-a6b0-0061a3f05d95 */ nyquist-3.05/nylsf/COPYING0000644000175000000620000006362611466723256014402 0ustar stevestaff GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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 Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] 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 Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these 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 other code 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. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. 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, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) 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. d) 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. e) 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 materials to be 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 with 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 Lesser 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.1 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! nyquist-3.05/nylsf/flac.c0000644000175000000620000010527411515317366014410 0ustar stevestaff/* ** Copyright (C) 2004, 2005 Erik de Castro Lopo ** Copyright (C) 2004 Tobias Gehrig ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include #include "sndfile.h" #include "common.h" #ifndef HAVE_FLAC_ALL_H int flac_open (SF_PRIVATE *psf) { if (psf) return SFE_UNIMPLEMENTED ; return (psf && 0) ; } /* flac_open */ #else #include #include "sfendian.h" #include "float_cast.h" /*------------------------------------------------------------------------------ ** Private static functions. */ #define ENC_BUFFER_SIZE 4096 typedef enum { PFLAC_PCM_SHORT = 0, PFLAC_PCM_INT = 1, PFLAC_PCM_FLOAT = 2, PFLAC_PCM_DOUBLE = 3 } PFLAC_PCM ; typedef struct { FLAC__SeekableStreamDecoder *fsd ; FLAC__SeekableStreamEncoder *fse ; PFLAC_PCM pcmtype ; void* ptr ; unsigned pos, len, remain ; const FLAC__int32 * const * wbuffer ; FLAC__int32 * rbuffer [FLAC__MAX_CHANNELS] ; FLAC__int32* encbuffer ; unsigned bufferpos ; const FLAC__Frame *frame ; FLAC__bool bufferbackup ; } FLAC_PRIVATE ; static sf_count_t flac_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int flac_close (SF_PRIVATE *psf) ; static int flac_enc_init (SF_PRIVATE *psf) ; static int flac_read_header (SF_PRIVATE *psf) ; static sf_count_t flac_read_flac2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t flac_read_flac2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t flac_read_flac2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t flac_read_flac2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t flac_write_s2flac (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t flac_write_i2flac (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t flac_write_f2flac (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t flac_write_d2flac (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static void f2flac8_array (const float *src, FLAC__int32 *dest, int count, int normalize) ; static void f2flac16_array (const float *src, FLAC__int32 *dest, int count, int normalize) ; static void f2flac24_array (const float *src, FLAC__int32 *dest, int count, int normalize) ; static void f2flac8_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) ; static void f2flac16_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) ; static void f2flac24_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) ; static void d2flac8_array (const double *src, FLAC__int32 *dest, int count, int normalize) ; static void d2flac16_array (const double *src, FLAC__int32 *dest, int count, int normalize) ; static void d2flac24_array (const double *src, FLAC__int32 *dest, int count, int normalize) ; static void d2flac8_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) ; static void d2flac16_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) ; static void d2flac24_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) ; static int flac_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; /* Decoder Callbacks */ static FLAC__SeekableStreamDecoderReadStatus sf_flac_read_callback (const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer [], unsigned *bytes, void *client_data) ; static FLAC__SeekableStreamDecoderSeekStatus sf_flac_seek_callback (const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) ; static FLAC__SeekableStreamDecoderTellStatus sf_flac_tell_callback (const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) ; static FLAC__SeekableStreamDecoderLengthStatus sf_flac_length_callback (const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) ; static FLAC__bool sf_flac_eof_callback (const FLAC__SeekableStreamDecoder *decoder, void *client_data) ; static FLAC__StreamDecoderWriteStatus sf_flac_write_callback (const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer [], void *client_data) ; static void sf_flac_meta_callback (const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) ; static void sf_flac_error_callback (const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) ; /* Encoder Callbacks */ static FLAC__SeekableStreamEncoderSeekStatus sf_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) ; #ifdef HAVE_FLAC_1_1_1 static FLAC__SeekableStreamEncoderTellStatus sf_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) ; #endif static FLAC__StreamEncoderWriteStatus sf_flac_enc_write_callback (const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer [], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) ; static const int legal_sample_rates [] = { 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000 } ; static void s2flac8_array (const short *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 8 ; } /* s2flac8_array */ static void s2flac16_array (const short *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] ; } /* s2flac16_array */ static void s2flac24_array (const short *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] << 8 ; } /* s2flac24_array */ static void i2flac8_array (const int *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 24 ; } /* i2flac8_array */ static void i2flac16_array (const int *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 16 ; } /* i2flac16_array */ static void i2flac24_array (const int *src, FLAC__int32 *dest, int count) { while (--count >= 0) dest [count] = src [count] >> 8 ; } /* i2flac24_array */ static sf_count_t flac_buffer_copy (SF_PRIVATE *psf) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; const FLAC__Frame *frame = pflac->frame ; const FLAC__int32* const *buffer = pflac->wbuffer ; unsigned i = 0, j, offset ; if (pflac->ptr == NULL) { /* ** Not sure why this code is here and not elsewhere. ** Removing it causes valgrind errors. */ pflac->bufferbackup = SF_TRUE ; for (i = 0 ; i < frame->header.channels ; i++) { if (pflac->rbuffer [i] == NULL) pflac->rbuffer [i] = calloc (frame->header.blocksize, sizeof (FLAC__int32)) ; memcpy (pflac->rbuffer [i], buffer [i], frame->header.blocksize * sizeof (FLAC__int32)) ; } ; pflac->wbuffer = (const FLAC__int32* const*) pflac->rbuffer ; return 0 ; } ; switch (pflac->pcmtype) { case PFLAC_PCM_SHORT : { short *retpcm = ((short*) pflac->ptr) ; int shift = 16 - frame->header.bits_per_sample ; if (shift < 0) { shift = abs (shift) ; for (i = 0 ; i < frame->header.blocksize && pflac->remain > 0 ; i++) { offset = pflac->pos + i * frame->header.channels ; for (j = 0 ; j < frame->header.channels ; j++) retpcm [offset + j] = buffer [j][pflac->bufferpos] >> shift ; pflac->remain -= frame->header.channels ; pflac->bufferpos++ ; } } else { for (i = 0 ; i < frame->header.blocksize && pflac->remain > 0 ; i++) { offset = pflac->pos + i * frame->header.channels ; if (pflac->bufferpos >= frame->header.blocksize) break ; for (j = 0 ; j < frame->header.channels ; j++) retpcm [offset + j] = (buffer [j][pflac->bufferpos]) << shift ; pflac->remain -= frame->header.channels ; pflac->bufferpos++ ; } ; } ; } ; break ; case PFLAC_PCM_INT : { int *retpcm = ((int*) pflac->ptr) ; int shift = 32 - frame->header.bits_per_sample ; for (i = 0 ; i < frame->header.blocksize && pflac->remain > 0 ; i++) { offset = pflac->pos + i * frame->header.channels ; if (pflac->bufferpos >= frame->header.blocksize) break ; for (j = 0 ; j < frame->header.channels ; j++) retpcm [offset + j] = buffer [j][pflac->bufferpos] << shift ; pflac->remain -= frame->header.channels ; pflac->bufferpos++ ; } ; } ; break ; case PFLAC_PCM_FLOAT : { float *retpcm = ((float*) pflac->ptr) ; float norm = (psf->norm_float == SF_TRUE) ? 1.0 / (1 << (frame->header.bits_per_sample - 1)) : 1.0 ; for (i = 0 ; i < frame->header.blocksize && pflac->remain > 0 ; i++) { offset = pflac->pos + i * frame->header.channels ; if (pflac->bufferpos >= frame->header.blocksize) break ; for (j = 0 ; j < frame->header.channels ; j++) retpcm [offset + j] = buffer [j][pflac->bufferpos] * norm ; pflac->remain -= frame->header.channels ; pflac->bufferpos++ ; } ; } ; break ; case PFLAC_PCM_DOUBLE : { double *retpcm = ((double*) pflac->ptr) ; double norm = (psf->norm_double == SF_TRUE) ? 1.0 / (1 << (frame->header.bits_per_sample - 1)) : 1.0 ; for (i = 0 ; i < frame->header.blocksize && pflac->remain > 0 ; i++) { offset = pflac->pos + i * frame->header.channels ; if (pflac->bufferpos >= frame->header.blocksize) break ; for (j = 0 ; j < frame->header.channels ; j++) retpcm [offset + j] = buffer [j][pflac->bufferpos] * norm ; pflac->remain -= frame->header.channels ; pflac->bufferpos++ ; } ; } ; break ; default : return 0 ; } ; offset = i * frame->header.channels ; pflac->pos += i * frame->header.channels ; return offset ; } /* flac_buffer_copy */ static FLAC__SeekableStreamDecoderReadStatus sf_flac_read_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), FLAC__byte buffer [], unsigned *bytes, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; *bytes = psf_fread (buffer, 1, *bytes, psf) ; if (*bytes > 0 && psf->error == 0) return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK ; return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR ; } /* sf_flac_read_callback */ static FLAC__SeekableStreamDecoderSeekStatus sf_flac_seek_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), FLAC__uint64 absolute_byte_offset, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; psf_fseek (psf, absolute_byte_offset, SEEK_SET) ; if (psf->error) return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR ; return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK ; } /* sf_flac_seek_callback */ static FLAC__SeekableStreamDecoderTellStatus sf_flac_tell_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), FLAC__uint64 *absolute_byte_offset, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; *absolute_byte_offset = psf_ftell (psf) ; if (psf->error) return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR ; return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK ; } /* sf_flac_tell_callback */ static FLAC__SeekableStreamDecoderLengthStatus sf_flac_length_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), FLAC__uint64 *stream_length, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; if ((*stream_length = psf->filelength) == 0) return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR ; return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK ; } /* sf_flac_length_callback */ static FLAC__bool sf_flac_eof_callback (const FLAC__SeekableStreamDecoder *UNUSED (decoder), void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; if (psf_ftell (psf) == psf->filelength) return SF_TRUE ; return SF_FALSE ; } /* sf_flac_eof_callback */ static FLAC__StreamDecoderWriteStatus sf_flac_write_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), const FLAC__Frame *frame, const FLAC__int32 * const buffer [], void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; pflac->frame = frame ; pflac->bufferpos = 0 ; pflac->bufferbackup = SF_FALSE ; pflac->wbuffer = buffer ; flac_buffer_copy (psf) ; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE ; } /* sf_flac_write_callback */ static void sf_flac_meta_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), const FLAC__StreamMetadata *metadata, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; switch (metadata->type) { case FLAC__METADATA_TYPE_STREAMINFO : psf->sf.channels = metadata->data.stream_info.channels ; psf->sf.samplerate = metadata->data.stream_info.sample_rate ; psf->sf.frames = metadata->data.stream_info.total_samples ; switch (metadata->data.stream_info.bits_per_sample) { case 8 : psf->sf.format |= SF_FORMAT_PCM_S8 ; break ; case 16 : psf->sf.format |= SF_FORMAT_PCM_16 ; break ; case 24 : psf->sf.format |= SF_FORMAT_PCM_24 ; break ; default : psf_log_printf (psf, "sf_flac_meta_callback : bits_per_sample %d not yet implemented.\n", metadata->data.stream_info.bits_per_sample) ; break ; } ; break ; default : psf_log_printf (psf, "sf_flac_meta_callback : metadata-type %d not yet implemented.\n", metadata->type) ; break ; } ; return ; } /* sf_flac_meta_callback */ static void sf_flac_error_callback (const FLAC__SeekableStreamDecoder * UNUSED (decoder), FLAC__StreamDecoderErrorStatus status, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; psf_log_printf (psf, "ERROR : %s\n", FLAC__StreamDecoderErrorStatusString [status]) ; switch (status) { case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC : psf->error = SFE_FLAC_LOST_SYNC ; break ; case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER : psf->error = SFE_FLAC_BAD_HEADER ; break ; default : psf->error = SFE_FLAC_UNKNOWN_ERROR ; break ; } ; return ; } /* sf_flac_error_callback */ static FLAC__SeekableStreamEncoderSeekStatus sf_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * UNUSED (encoder), FLAC__uint64 absolute_byte_offset, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; psf_fseek (psf, absolute_byte_offset, SEEK_SET) ; if (psf->error) return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR ; return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK ; } /* sf_flac_enc_seek_callback */ #ifdef HAVE_FLAC_1_1_1 static FLAC__SeekableStreamEncoderTellStatus sf_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder *UNUSED (encoder), FLAC__uint64 *absolute_byte_offset, void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; *absolute_byte_offset = psf_ftell (psf) ; if (psf->error) return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR ; return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK ; } /* sf_flac_enc_tell_callback */ #endif static FLAC__StreamEncoderWriteStatus sf_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * UNUSED (encoder), const FLAC__byte buffer [], unsigned bytes, unsigned UNUSED (samples), unsigned UNUSED (current_frame), void *client_data) { SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; if (psf_fwrite (buffer, 1, bytes, psf) == bytes && psf->error == 0) return FLAC__STREAM_ENCODER_WRITE_STATUS_OK ; return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR ; } /* sf_flac_enc_write_callback */ /*------------------------------------------------------------------------------ ** Public function. */ int flac_open (SF_PRIVATE *psf) { int subformat ; int error = 0 ; FLAC_PRIVATE* pflac = calloc (1, sizeof (FLAC_PRIVATE)) ; psf->codec_data = pflac ; if (psf->mode == SFM_RDWR) return SFE_UNIMPLEMENTED ; if (psf->mode == SFM_READ) { if ((error = flac_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_FLAC) return SFE_BAD_OPEN_FORMAT ; psf->endian = SF_ENDIAN_BIG ; if ((error = flac_enc_init (psf))) return error ; } ; psf->datalength = psf->filelength ; psf->dataoffset = 0 ; psf->blockwidth = 0 ; psf->bytewidth = 1 ; psf->container_close = flac_close ; psf->seek = flac_seek ; psf->command = flac_command ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_PCM_S8 : /* 8-bit FLAC. */ case SF_FORMAT_PCM_16 : /* 16-bit FLAC. */ case SF_FORMAT_PCM_24 : /* 24-bit FLAC. */ error = flac_init (psf) ; break ; default : return SFE_UNIMPLEMENTED ; } ; return error ; } /* flac_open */ /*------------------------------------------------------------------------------ */ static int flac_close (SF_PRIVATE *psf) { FLAC_PRIVATE* pflac ; int k ; if ((pflac = (FLAC_PRIVATE*) psf->codec_data) == NULL) return 0 ; if (psf->mode == SFM_WRITE) { FLAC__seekable_stream_encoder_finish (pflac->fse) ; FLAC__seekable_stream_encoder_delete (pflac->fse) ; if (pflac->encbuffer) free (pflac->encbuffer) ; } ; if (psf->mode == SFM_READ) { FLAC__seekable_stream_decoder_finish (pflac->fsd) ; FLAC__seekable_stream_decoder_delete (pflac->fsd) ; } ; for (k = 0 ; k < ARRAY_LEN (pflac->rbuffer) ; k++) free (pflac->rbuffer [k]) ; free (pflac) ; psf->codec_data = NULL ; return 0 ; } /* flac_close */ static int flac_enc_init (SF_PRIVATE *psf) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; unsigned bps ; int k, found ; found = 0 ; for (k = 0 ; k < ARRAY_LEN (legal_sample_rates) ; k++) if (psf->sf.samplerate == legal_sample_rates [k]) { found = 1 ; break ; } ; if (found == 0) return SFE_FLAC_BAD_SAMPLE_RATE ; psf_fseek (psf, 0, SEEK_SET) ; if ((pflac->fse = FLAC__seekable_stream_encoder_new ()) == NULL) return SFE_FLAC_NEW_DECODER ; FLAC__seekable_stream_encoder_set_write_callback (pflac->fse, sf_flac_enc_write_callback) ; FLAC__seekable_stream_encoder_set_seek_callback (pflac->fse, sf_flac_enc_seek_callback) ; #ifdef HAVE_FLAC_1_1_1 FLAC__seekable_stream_encoder_set_tell_callback (pflac->fse, sf_flac_enc_tell_callback) ; #endif FLAC__seekable_stream_encoder_set_client_data (pflac->fse, psf) ; FLAC__seekable_stream_encoder_set_channels (pflac->fse, psf->sf.channels) ; FLAC__seekable_stream_encoder_set_sample_rate (pflac->fse, psf->sf.samplerate) ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : bps = 8 ; break ; case SF_FORMAT_PCM_16 : bps = 16 ; break ; case SF_FORMAT_PCM_24 : bps = 24 ; break ; default : bps = 0 ; break ; } ; FLAC__seekable_stream_encoder_set_bits_per_sample (pflac->fse, bps) ; if ((bps = FLAC__seekable_stream_encoder_init (pflac->fse)) != FLAC__SEEKABLE_STREAM_DECODER_OK) { psf_log_printf (psf, "Error : FLAC encoder init returned error : %s\n", FLAC__seekable_stream_encoder_get_resolved_state_string (pflac->fse)) ; return SFE_FLAC_INIT_DECODER ; } ; if (psf->error == 0) psf->dataoffset = psf_ftell (psf) ; pflac->encbuffer = calloc (ENC_BUFFER_SIZE, sizeof (FLAC__int32)) ; return psf->error ; } /* flac_enc_init */ static int flac_read_header (SF_PRIVATE *psf) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; psf_fseek (psf, 0, SEEK_SET) ; if ((pflac->fsd = FLAC__seekable_stream_decoder_new ()) == NULL) return SFE_FLAC_NEW_DECODER ; FLAC__seekable_stream_decoder_set_read_callback (pflac->fsd, sf_flac_read_callback) ; FLAC__seekable_stream_decoder_set_seek_callback (pflac->fsd, sf_flac_seek_callback) ; FLAC__seekable_stream_decoder_set_tell_callback (pflac->fsd, sf_flac_tell_callback) ; FLAC__seekable_stream_decoder_set_length_callback (pflac->fsd, sf_flac_length_callback) ; FLAC__seekable_stream_decoder_set_eof_callback (pflac->fsd, sf_flac_eof_callback) ; FLAC__seekable_stream_decoder_set_write_callback (pflac->fsd, sf_flac_write_callback) ; FLAC__seekable_stream_decoder_set_metadata_callback (pflac->fsd, sf_flac_meta_callback) ; FLAC__seekable_stream_decoder_set_error_callback (pflac->fsd, sf_flac_error_callback) ; FLAC__seekable_stream_decoder_set_client_data (pflac->fsd, psf) ; if (FLAC__seekable_stream_decoder_init (pflac->fsd) != FLAC__SEEKABLE_STREAM_DECODER_OK) return SFE_FLAC_INIT_DECODER ; FLAC__seekable_stream_decoder_process_until_end_of_metadata (pflac->fsd) ; if (psf->error == 0) { FLAC__uint64 position ; FLAC__seekable_stream_decoder_get_decode_position (pflac->fsd, &position) ; psf->dataoffset = position ; } ; return psf->error ; } /* flac_read_header */ static int flac_command (SF_PRIVATE *psf, int command, void *data, int datasize) { /* Avoid compiler warnings. */ psf = psf ; data = data ; datasize = datasize ; switch (command) { default : break ; } ; return 0 ; } /* flac_command */ int flac_init (SF_PRIVATE *psf) { if (psf->mode == SFM_RDWR) return SFE_BAD_MODE_RW ; if (psf->mode == SFM_READ) { psf->read_short = flac_read_flac2s ; psf->read_int = flac_read_flac2i ; psf->read_float = flac_read_flac2f ; psf->read_double = flac_read_flac2d ; } ; if (psf->mode == SFM_WRITE) { psf->write_short = flac_write_s2flac ; psf->write_int = flac_write_i2flac ; psf->write_float = flac_write_f2flac ; psf->write_double = flac_write_d2flac ; } ; psf->bytewidth = 1 ; psf->blockwidth = psf->sf.channels ; if (psf->filelength > psf->dataoffset) psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; else psf->datalength = 0 ; return 0 ; } /* flac_init */ static unsigned flac_read_loop (SF_PRIVATE *psf, unsigned len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; pflac->pos = 0 ; pflac->len = len ; pflac->remain = len ; if (pflac->frame != NULL && pflac->bufferpos < pflac->frame->header.blocksize) flac_buffer_copy (psf) ; while (pflac->pos < pflac->len) { if (FLAC__seekable_stream_decoder_process_single (pflac->fsd) == 0) break ; if (FLAC__seekable_stream_decoder_get_state (pflac->fsd) != FLAC__SEEKABLE_STREAM_DECODER_OK) break ; } ; pflac->ptr = NULL ; return pflac->pos ; } /* flac_read_loop */ static sf_count_t flac_read_flac2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; sf_count_t total = 0, current ; unsigned readlen ; pflac->pcmtype = PFLAC_PCM_SHORT ; while (total < len) { pflac->ptr = ptr + total ; readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ; current = flac_read_loop (psf, readlen) ; if (current == 0) break ; total += current ; } ; return total ; } /* flac_read_flac2s */ static sf_count_t flac_read_flac2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; sf_count_t total = 0, current ; unsigned readlen ; pflac->pcmtype = PFLAC_PCM_INT ; while (total < len) { pflac->ptr = ptr + total ; readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ; current = flac_read_loop (psf, readlen) ; if (current == 0) break ; total += current ; } ; return total ; } /* flac_read_flac2i */ static sf_count_t flac_read_flac2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; sf_count_t total = 0, current ; unsigned readlen ; pflac->pcmtype = PFLAC_PCM_FLOAT ; while (total < len) { pflac->ptr = ptr + total ; readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ; current = flac_read_loop (psf, readlen) ; if (current == 0) break ; total += current ; } ; return total ; } /* flac_read_flac2f */ static sf_count_t flac_read_flac2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; sf_count_t total = 0, current ; unsigned readlen ; pflac->pcmtype = PFLAC_PCM_DOUBLE ; while (total < len) { pflac->ptr = ptr + total ; readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ; current = flac_read_loop (psf, readlen) ; if (current == 0) break ; total += current ; } ; return total ; } /* flac_read_flac2d */ static sf_count_t flac_write_s2flac (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; void (*convert) (const short *, FLAC__int32 *, int) ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; FLAC__int32* buffer = pflac->encbuffer ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : convert = s2flac8_array ; break ; case SF_FORMAT_PCM_16 : convert = s2flac16_array ; break ; case SF_FORMAT_PCM_24 : convert = s2flac24_array ; break ; default : return -1 ; } ; bufferlen = ENC_BUFFER_SIZE / (sizeof (FLAC__int32) * psf->sf.channels) ; bufferlen *= psf->sf.channels ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; convert (ptr + total, buffer, writecount) ; if (FLAC__seekable_stream_encoder_process_interleaved (pflac->fse, buffer, writecount/psf->sf.channels)) thiswrite = writecount ; else break ; total += thiswrite ; if (thiswrite < writecount) break ; len -= thiswrite ; } ; return total ; } /* flac_write_s2flac */ static sf_count_t flac_write_i2flac (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; void (*convert) (const int *, FLAC__int32 *, int) ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; FLAC__int32* buffer = pflac->encbuffer ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : convert = i2flac8_array ; break ; case SF_FORMAT_PCM_16 : convert = i2flac16_array ; break ; case SF_FORMAT_PCM_24 : convert = i2flac24_array ; break ; default : return -1 ; } ; bufferlen = ENC_BUFFER_SIZE / (sizeof (FLAC__int32) * psf->sf.channels) ; bufferlen *= psf->sf.channels ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; convert (ptr + total, buffer, writecount) ; if (FLAC__seekable_stream_encoder_process_interleaved (pflac->fse, buffer, writecount/psf->sf.channels)) thiswrite = writecount ; else break ; total += thiswrite ; if (thiswrite < writecount) break ; len -= thiswrite ; } ; return total ; } /* flac_write_i2flac */ static sf_count_t flac_write_f2flac (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; void (*convert) (const float *, FLAC__int32 *, int, int) ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; FLAC__int32* buffer = pflac->encbuffer ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : convert = (psf->add_clipping) ? f2flac8_clip_array : f2flac8_array ; break ; case SF_FORMAT_PCM_16 : convert = (psf->add_clipping) ? f2flac16_clip_array : f2flac16_array ; break ; case SF_FORMAT_PCM_24 : convert = (psf->add_clipping) ? f2flac24_clip_array : f2flac24_array ; break ; default : return -1 ; } ; bufferlen = ENC_BUFFER_SIZE / (sizeof (FLAC__int32) * psf->sf.channels) ; bufferlen *= psf->sf.channels ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; convert (ptr + total, buffer, writecount, psf->norm_float) ; if (FLAC__seekable_stream_encoder_process_interleaved (pflac->fse, buffer, writecount/psf->sf.channels)) thiswrite = writecount ; else break ; total += thiswrite ; if (thiswrite < writecount) break ; len -= thiswrite ; } ; return total ; } /* flac_write_f2flac */ static void f2flac8_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) { float normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10) : 1.0 ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7F)) { dest [count] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10)) { dest [count] = 0x80 ; continue ; } ; dest [count] = lrintf (scaled_value) ; } ; return ; } /* f2flac8_clip_array */ static void f2flac16_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) { float normfact, scaled_value ; normfact = normalize ? (8.0 * 0x1000) : 1.0 ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFF)) { dest [count] = 0x7FFF ; continue ; } if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x1000)) { dest [count] = 0x8000 ; continue ; } dest [count] = lrintf (scaled_value) ; } } /* f2flac16_clip_array */ static void f2flac24_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) { float normfact, scaled_value ; normfact = normalize ? (8.0 * 0x100000) : 1.0 ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFF)) { dest [count] = 0x7FFFFF ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x100000)) { dest [count] = 0x800000 ; continue ; } dest [count] = lrintf (scaled_value) ; } ; return ; } /* f2flac24_clip_array */ static void f2flac8_array (const float *src, FLAC__int32 *dest, int count, int normalize) { float normfact = normalize ? (1.0 * 0x7F) : 1.0 ; while (--count >= 0) dest [count] = lrintf (src [count] * normfact) ; } /* f2flac8_array */ static void f2flac16_array (const float *src, FLAC__int32 *dest, int count, int normalize) { float normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; while (--count >= 0) dest [count] = lrintf (src [count] * normfact) ; } /* f2flac16_array */ static void f2flac24_array (const float *src, FLAC__int32 *dest, int count, int normalize) { float normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; while (--count >= 0) dest [count] = lrintf (src [count] * normfact) ; } /* f2flac24_array */ static sf_count_t flac_write_d2flac (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; void (*convert) (const double *, FLAC__int32 *, int, int) ; int bufferlen, writecount, thiswrite ; sf_count_t total = 0 ; FLAC__int32* buffer = pflac->encbuffer ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : convert = (psf->add_clipping) ? d2flac8_clip_array : d2flac8_array ; break ; case SF_FORMAT_PCM_16 : convert = (psf->add_clipping) ? d2flac16_clip_array : d2flac16_array ; break ; case SF_FORMAT_PCM_24 : convert = (psf->add_clipping) ? d2flac24_clip_array : d2flac24_array ; break ; default : return -1 ; } ; bufferlen = ENC_BUFFER_SIZE / (sizeof (FLAC__int32) * psf->sf.channels) ; bufferlen *= psf->sf.channels ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; convert (ptr + total, buffer, writecount, psf->norm_double) ; if (FLAC__seekable_stream_encoder_process_interleaved (pflac->fse, buffer, writecount/psf->sf.channels)) thiswrite = writecount ; else break ; total += thiswrite ; if (thiswrite < writecount) break ; len -= thiswrite ; } ; return total ; } /* flac_write_d2flac */ static void d2flac8_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) { double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x10) : 1.0 ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7F)) { dest [count] = 0x7F ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10)) { dest [count] = 0x80 ; continue ; } ; dest [count] = lrint (scaled_value) ; } ; return ; } /* d2flac8_clip_array */ static void d2flac16_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) { double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x1000) : 1.0 ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFF)) { dest [count] = 0x7FFF ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x1000)) { dest [count] = 0x8000 ; continue ; } ; dest [count] = lrint (scaled_value) ; } ; return ; } /* d2flac16_clip_array */ static void d2flac24_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) { double normfact, scaled_value ; normfact = normalize ? (8.0 * 0x100000) : 1.0 ; while (--count >= 0) { scaled_value = src [count] * normfact ; if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFF)) { dest [count] = 0x7FFFFF ; continue ; } ; if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x100000)) { dest [count] = 0x800000 ; continue ; } ; dest [count] = lrint (scaled_value) ; } ; return ; } /* d2flac24_clip_array */ static void d2flac8_array (const double *src, FLAC__int32 *dest, int count, int normalize) { double normfact = normalize ? (1.0 * 0x7F) : 1.0 ; while (--count >= 0) dest [count] = lrint (src [count] * normfact) ; } /* d2flac8_array */ static void d2flac16_array (const double *src, FLAC__int32 *dest, int count, int normalize) { double normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; while (--count >= 0) dest [count] = lrint (src [count] * normfact) ; } /* d2flac16_array */ static void d2flac24_array (const double *src, FLAC__int32 *dest, int count, int normalize) { double normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; while (--count >= 0) dest [count] = lrint (src [count] * normfact) ; } /* d2flac24_array */ static sf_count_t flac_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset) { FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; if (pflac == NULL) return 0 ; if (psf->dataoffset < 0) { psf->error = SFE_BAD_SEEK ; return ((sf_count_t) -1) ; } ; pflac->frame = NULL ; if (psf->mode == SFM_READ) { FLAC__uint64 position ; if (FLAC__seekable_stream_decoder_seek_absolute (pflac->fsd, offset)) { FLAC__seekable_stream_decoder_get_decode_position (pflac->fsd, &position) ; return offset ; } ; return ((sf_count_t) -1) ; } ; /* Seeking in write mode not yet supported. */ psf->error = SFE_BAD_SEEK ; return ((sf_count_t) -1) ; } /* flac_seek */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 46d49617-ebff-42b4-8f66-a0e428147360 */ nyquist-3.05/nylsf/ircam.c0000644000175000000620000002100611466723256014570 0ustar stevestaff/* ** Copyright (C) 2001-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ /* The IRCAM magic number is weird in that one byte in the number can have ** values of 0x1, 0x2, 0x03 or 0x04. Hence the need for a marker and a mask. */ #define IRCAM_BE_MASK (MAKE_MARKER (0xFF, 0xFF, 0x00, 0xFF)) #define IRCAM_BE_MARKER (MAKE_MARKER (0x64, 0xA3, 0x00, 0x00)) #define IRCAM_LE_MASK (MAKE_MARKER (0xFF, 0x00, 0xFF, 0xFF)) #define IRCAM_LE_MARKER (MAKE_MARKER (0x00, 0x00, 0xA3, 0x64)) #define IRCAM_02B_MARKER (MAKE_MARKER (0x64, 0xA3, 0x02, 0x00)) #define IRCAM_03L_MARKER (MAKE_MARKER (0x64, 0xA3, 0x03, 0x00)) #define IRCAM_DATA_OFFSET (1024) /*------------------------------------------------------------------------------ ** Typedefs. */ enum { IRCAM_PCM_16 = 0x00002, IRCAM_FLOAT = 0x00004, IRCAM_ALAW = 0x10001, IRCAM_ULAW = 0x20001, IRCAM_PCM_32 = 0x40004 } ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int ircam_close (SF_PRIVATE *psf) ; static int ircam_write_header (SF_PRIVATE *psf, int calc_length) ; static int ircam_read_header (SF_PRIVATE *psf) ; static int get_encoding (int subformat) ; static const char* get_encoding_str (int encoding) ; /*------------------------------------------------------------------------------ ** Public function. */ int ircam_open (SF_PRIVATE *psf) { int subformat ; int error = SFE_NO_ERROR ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = ircam_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_IRCAM) return SFE_BAD_OPEN_FORMAT ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU) psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ; psf->dataoffset = IRCAM_DATA_OFFSET ; if ((error = ircam_write_header (psf, SF_FALSE))) return error ; psf->write_header = ircam_write_header ; } ; psf->container_close = ircam_close ; switch (subformat) { case SF_FORMAT_ULAW : /* 8-bit Ulaw encoding. */ error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : /* 8-bit Alaw encoding. */ error = alaw_init (psf) ; break ; case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ error = pcm_init (psf) ; break ; case SF_FORMAT_FLOAT : /* 32-bit linear PCM. */ error = float32_init (psf) ; break ; default : break ; } ; return error ; } /* ircam_open */ /*------------------------------------------------------------------------------ */ static int ircam_read_header (SF_PRIVATE *psf) { unsigned int marker, encoding ; float samplerate ; int error = SFE_NO_ERROR ; psf_binheader_readf (psf, "epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ; if (((marker & IRCAM_BE_MASK) != IRCAM_BE_MARKER) && ((marker & IRCAM_LE_MASK) != IRCAM_LE_MARKER)) { psf_log_printf (psf, "marker: 0x%X\n", marker) ; return SFE_IRCAM_NO_MARKER ; } ; psf->endian = SF_ENDIAN_LITTLE ; if (psf->sf.channels > 256) { psf_binheader_readf (psf, "Epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ; /* Sanity checking for endian-ness detection. */ if (psf->sf.channels > 256) { psf_log_printf (psf, "marker: 0x%X\n", marker) ; return SFE_IRCAM_BAD_CHANNELS ; } ; psf->endian = SF_ENDIAN_BIG ; } ; psf_log_printf (psf, "marker: 0x%X\n", marker) ; psf->sf.samplerate = (int) samplerate ; psf_log_printf (psf, " Sample Rate : %d\n" " Channels : %d\n" " Encoding : %X => %s\n", psf->sf.samplerate, psf->sf.channels, encoding, get_encoding_str (encoding)) ; switch (encoding) { case IRCAM_PCM_16 : psf->bytewidth = 2 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_16 ; break ; case IRCAM_PCM_32 : psf->bytewidth = 4 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_32 ; break ; case IRCAM_FLOAT : psf->bytewidth = 4 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_FLOAT ; break ; case IRCAM_ALAW : psf->bytewidth = 1 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ALAW ; break ; case IRCAM_ULAW : psf->bytewidth = 1 ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ULAW ; break ; default : error = SFE_IRCAM_UNKNOWN_FORMAT ; break ; } ; if (psf->endian == SF_ENDIAN_BIG) psf->sf.format |= SF_ENDIAN_BIG ; else psf->sf.format |= SF_ENDIAN_LITTLE ; if (error) return error ; psf->dataoffset = IRCAM_DATA_OFFSET ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->sf.frames == 0 && psf->blockwidth) psf->sf.frames = psf->datalength / psf->blockwidth ; psf_log_printf (psf, " Samples : %d\n", psf->sf.frames) ; psf_binheader_readf (psf, "p", IRCAM_DATA_OFFSET) ; return 0 ; } /* ircam_read_header */ static int ircam_close (SF_PRIVATE *psf) { psf_log_printf (psf, "close\n") ; return 0 ; } /* ircam_close */ static int ircam_write_header (SF_PRIVATE *psf, int calc_length) { int encoding ; float samplerate ; sf_count_t current ; if (psf->pipeoffset > 0) return 0 ; current = psf_ftell (psf) ; calc_length = calc_length ; /* This also sets psf->endian. */ encoding = get_encoding (psf->sf.format & SF_FORMAT_SUBMASK) ; if (encoding == 0) return SFE_BAD_OPEN_FORMAT ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; if (psf->is_pipe == SF_FALSE) psf_fseek (psf, 0, SEEK_SET) ; samplerate = psf->sf.samplerate ; switch (psf->endian) { case SF_ENDIAN_BIG : psf_binheader_writef (psf, "Emf", IRCAM_02B_MARKER, samplerate) ; psf_binheader_writef (psf, "E44", psf->sf.channels, encoding) ; break ; case SF_ENDIAN_LITTLE : psf_binheader_writef (psf, "emf", IRCAM_03L_MARKER, samplerate) ; psf_binheader_writef (psf, "e44", psf->sf.channels, encoding) ; break ; default : return SFE_BAD_OPEN_FORMAT ; } ; psf_binheader_writef (psf, "z", (size_t) (IRCAM_DATA_OFFSET - psf->headindex)) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* ircam_write_header */ static int get_encoding (int subformat) { switch (subformat) { case SF_FORMAT_PCM_16 : return IRCAM_PCM_16 ; case SF_FORMAT_PCM_32 : return IRCAM_PCM_32 ; case SF_FORMAT_FLOAT : return IRCAM_FLOAT ; case SF_FORMAT_ULAW : return IRCAM_ULAW ; case SF_FORMAT_ALAW : return IRCAM_ALAW ; default : break ; } ; return 0 ; } /* get_encoding */ static const char* get_encoding_str (int encoding) { switch (encoding) { case IRCAM_PCM_16 : return "16 bit PCM" ; case IRCAM_FLOAT : return "32 bit float" ; case IRCAM_ALAW : return "A law" ; case IRCAM_ULAW : return "u law" ; case IRCAM_PCM_32 : return "32 bit PCM" ; } ; return "Unknown encoding" ; } /* get_encoding_str */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: f2714ab8-f286-4c94-9740-edaf673a1c71 */ nyquist-3.05/nylsf/interleave.c0000644000175000000620000001737111466723256015645 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfendian.h" #include #include "sndfile.h" #include "common.h" #define INTERLEAVE_CHANNELS 6 typedef struct { double buffer [SF_BUFFER_LEN / sizeof (double)] ; sf_count_t channel_len ; sf_count_t (*read_short) (SF_PRIVATE*, short *ptr, sf_count_t len) ; sf_count_t (*read_int) (SF_PRIVATE*, int *ptr, sf_count_t len) ; sf_count_t (*read_float) (SF_PRIVATE*, float *ptr, sf_count_t len) ; sf_count_t (*read_double) (SF_PRIVATE*, double *ptr, sf_count_t len) ; } INTERLEAVE_DATA ; static sf_count_t interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t interleave_seek (SF_PRIVATE*, int mode, sf_count_t samples_from_start) ; int interleave_init (SF_PRIVATE *psf) { INTERLEAVE_DATA *pdata ; if (psf->mode != SFM_READ) return SFE_INTERLEAVE_MODE ; if (psf->interleave) { psf_log_printf (psf, "*** Weird, already have interleave.\n") ; return 666 ; } ; /* Free this in sf_close() function. */ if (! (pdata = malloc (sizeof (INTERLEAVE_DATA)))) return SFE_MALLOC_FAILED ; puts ("interleave_init") ; psf->interleave = pdata ; /* Save the existing methods. */ pdata->read_short = psf->read_short ; pdata->read_int = psf->read_int ; pdata->read_float = psf->read_float ; pdata->read_double = psf->read_double ; pdata->channel_len = psf->sf.frames * psf->bytewidth ; /* Insert our new methods. */ psf->read_short = interleave_read_short ; psf->read_int = interleave_read_int ; psf->read_float = interleave_read_float ; psf->read_double = interleave_read_double ; psf->seek = interleave_seek ; return 0 ; } /* pcm_interleave_init */ /*------------------------------------------------------------------------------ */ static sf_count_t interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) { INTERLEAVE_DATA *pdata ; sf_count_t offset, templen ; int chan, count, k ; short *inptr, *outptr ; if (! (pdata = psf->interleave)) return 0 ; inptr = (short*) pdata->buffer ; for (chan = 0 ; chan < psf->sf.channels ; chan++) { outptr = ptr + chan ; offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; if (psf_fseek (psf, offset, SEEK_SET) != offset) { psf->error = SFE_INTERLEAVE_SEEK ; return 0 ; } ; templen = len / psf->sf.channels ; while (templen > 0) { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short)) count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short) ; else count = (int) templen ; if (pdata->read_short (psf, inptr, count) != count) { psf->error = SFE_INTERLEAVE_READ ; return 0 ; } ; for (k = 0 ; k < count ; k++) { *outptr = inptr [k] ; outptr += psf->sf.channels ; } ; templen -= count ; } ; } ; return len ; } /* interleave_read_short */ static sf_count_t interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) { INTERLEAVE_DATA *pdata ; sf_count_t offset, templen ; int chan, count, k ; int *inptr, *outptr ; if (! (pdata = psf->interleave)) return 0 ; inptr = (int*) pdata->buffer ; for (chan = 0 ; chan < psf->sf.channels ; chan++) { outptr = ptr + chan ; offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; if (psf_fseek (psf, offset, SEEK_SET) != offset) { psf->error = SFE_INTERLEAVE_SEEK ; return 0 ; } ; templen = len / psf->sf.channels ; while (templen > 0) { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int)) count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int) ; else count = (int) templen ; if (pdata->read_int (psf, inptr, count) != count) { psf->error = SFE_INTERLEAVE_READ ; return 0 ; } ; for (k = 0 ; k < count ; k++) { *outptr = inptr [k] ; outptr += psf->sf.channels ; } ; templen -= count ; } ; } ; return len ; } /* interleave_read_int */ static sf_count_t interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) { INTERLEAVE_DATA *pdata ; sf_count_t offset, templen ; int chan, count, k ; float *inptr, *outptr ; if (! (pdata = psf->interleave)) return 0 ; inptr = (float*) pdata->buffer ; for (chan = 0 ; chan < psf->sf.channels ; chan++) { outptr = ptr + chan ; offset = psf->dataoffset + pdata->channel_len * chan + psf->read_current * psf->bytewidth ; /*-printf ("chan : %d read_current : %6lld offset : %6lld\n", chan, psf->read_current, offset) ;-*/ if (psf_fseek (psf, offset, SEEK_SET) != offset) { psf->error = SFE_INTERLEAVE_SEEK ; /*-puts ("interleave_seek error") ; exit (1) ;-*/ return 0 ; } ; templen = len / psf->sf.channels ; while (templen > 0) { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float)) count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float) ; else count = (int) templen ; if (pdata->read_float (psf, inptr, count) != count) { psf->error = SFE_INTERLEAVE_READ ; /*-puts ("interleave_read error") ; exit (1) ;-*/ return 0 ; } ; for (k = 0 ; k < count ; k++) { *outptr = inptr [k] ; outptr += psf->sf.channels ; } ; templen -= count ; } ; } ; return len ; } /* interleave_read_float */ static sf_count_t interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) { INTERLEAVE_DATA *pdata ; sf_count_t offset, templen ; int chan, count, k ; double *inptr, *outptr ; if (! (pdata = psf->interleave)) return 0 ; inptr = (double*) pdata->buffer ; for (chan = 0 ; chan < psf->sf.channels ; chan++) { outptr = ptr + chan ; offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; if (psf_fseek (psf, offset, SEEK_SET) != offset) { psf->error = SFE_INTERLEAVE_SEEK ; return 0 ; } ; templen = len / psf->sf.channels ; while (templen > 0) { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double)) count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double) ; else count = (int) templen ; if (pdata->read_double (psf, inptr, count) != count) { psf->error = SFE_INTERLEAVE_READ ; return 0 ; } ; for (k = 0 ; k < count ; k++) { *outptr = inptr [k] ; outptr += psf->sf.channels ; } ; templen -= count ; } ; } ; return len ; } /* interleave_read_double */ /*------------------------------------------------------------------------------ */ static sf_count_t interleave_seek (SF_PRIVATE *psf, int mode, sf_count_t samples_from_start) { psf = psf ; mode = mode ; /* ** Do nothing here. This is a place holder to prevent the default ** seek function from being called. */ return samples_from_start ; } /* interleave_seek */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 82314e13-0225-4408-a2f2-e6dab3f38904 */ nyquist-3.05/nylsf/htk.c0000644000175000000620000001513711466723256014273 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define SFE_HTK_BAD_FILE_LEN 1666 #define SFE_HTK_NOT_WAVEFORM 1667 /*------------------------------------------------------------------------------ ** Private static functions. */ static int htk_close (SF_PRIVATE *psf) ; static int htk_write_header (SF_PRIVATE *psf, int calc_length) ; static int htk_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int htk_open (SF_PRIVATE *psf) { int subformat ; int error = 0 ; if (psf->is_pipe) return SFE_HTK_NO_PIPE ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = htk_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_HTK) return SFE_BAD_OPEN_FORMAT ; psf->endian = SF_ENDIAN_BIG ; if (htk_write_header (psf, SF_FALSE)) return psf->error ; psf->write_header = htk_write_header ; } ; psf->container_close = htk_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ error = pcm_init (psf) ; break ; default : break ; } ; return error ; } /* htk_open */ /*------------------------------------------------------------------------------ */ static int htk_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) htk_write_header (psf, SF_TRUE) ; return 0 ; } /* htk_close */ static int htk_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int sample_count, sample_period ; current = psf_ftell (psf) ; if (calc_length) psf->filelength = psf_get_filelen (psf) ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; if (psf->filelength > 12) sample_count = (psf->filelength - 12) / 2 ; else sample_count = 0 ; sample_period = 10000000 / psf->sf.samplerate ; psf_binheader_writef (psf, "E444", sample_count, sample_period, 0x20000) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* htk_write_header */ /* ** Found the following info in a comment block within Bill Schottstaedt's ** sndlib library. ** ** HTK format files consist of a contiguous sequence of samples preceded by a ** header. Each sample is a vector of either 2-byte integers or 4-byte floats. ** 2-byte integers are used for compressed forms as described below and for ** vector quantised data as described later in section 5.11. HTK format data ** files can also be used to store speech waveforms as described in section 5.8. ** ** The HTK file format header is 12 bytes long and contains the following data ** nSamples -- number of samples in file (4-byte integer) ** sampPeriod -- sample period in 100ns units (4-byte integer) ** sampSize -- number of bytes per sample (2-byte integer) ** parmKind -- a code indicating the sample kind (2-byte integer) ** ** The parameter kind consists of a 6 bit code representing the basic ** parameter kind plus additional bits for each of the possible qualifiers. ** The basic parameter kind codes are ** ** 0 WAVEFORM sampled waveform ** 1 LPC linear prediction filter coefficients ** 2 LPREFC linear prediction reflection coefficients ** 3 LPCEPSTRA LPC cepstral coefficients ** 4 LPDELCEP LPC cepstra plus delta coefficients ** 5 IREFC LPC reflection coef in 16 bit integer format ** 6 MFCC mel-frequency cepstral coefficients ** 7 FBANK log mel-filter bank channel outputs ** 8 MELSPEC linear mel-filter bank channel outputs ** 9 USER user defined sample kind ** 10 DISCRETE vector quantised data ** ** and the bit-encoding for the qualifiers (in octal) is ** _E 000100 has energy ** _N 000200 absolute energy suppressed ** _D 000400 has delta coefficients ** _A 001000 has acceleration coefficients ** _C 002000 is compressed ** _Z 004000 has zero mean static coef. ** _K 010000 has CRC checksum ** _O 020000 has 0'th cepstral coef. */ static int htk_read_header (SF_PRIVATE *psf) { int sample_count, sample_period, marker ; psf_binheader_readf (psf, "pE444", 0, &sample_count, &sample_period, &marker) ; if (2 * sample_count + 12 != psf->filelength) return SFE_HTK_BAD_FILE_LEN ; if (marker != 0x20000) return SFE_HTK_NOT_WAVEFORM ; psf->sf.channels = 1 ; psf->sf.samplerate = 10000000 / sample_period ; psf_log_printf (psf, "HTK Waveform file\n Sample Count : %d\n Sample Period : %d => %d Hz\n", sample_count, sample_period, psf->sf.samplerate) ; psf->sf.format = SF_FORMAT_HTK | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; /* HTK always has a 12 byte header. */ psf->dataoffset = 12 ; psf->endian = SF_ENDIAN_BIG ; psf->datalength = psf->filelength - psf->dataoffset ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; if (! psf->sf.frames && psf->blockwidth) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; return 0 ; } /* htk_read_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: c350e972-082e-4c20-8934-03391a723560 */ nyquist-3.05/nylsf/aiff.c0000644000175000000620000013116411466723256014411 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** Copyright (C) 2005 David Viens ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ * Macros to handle big/little endian issues. */ #define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M')) #define AIFF_MARKER (MAKE_MARKER ('A', 'I', 'F', 'F')) #define AIFC_MARKER (MAKE_MARKER ('A', 'I', 'F', 'C')) #define COMM_MARKER (MAKE_MARKER ('C', 'O', 'M', 'M')) #define SSND_MARKER (MAKE_MARKER ('S', 'S', 'N', 'D')) #define MARK_MARKER (MAKE_MARKER ('M', 'A', 'R', 'K')) #define INST_MARKER (MAKE_MARKER ('I', 'N', 'S', 'T')) #define APPL_MARKER (MAKE_MARKER ('A', 'P', 'P', 'L')) #define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' ')) #define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E')) #define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H')) #define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O')) #define COMT_MARKER (MAKE_MARKER ('C', 'O', 'M', 'T')) #define FVER_MARKER (MAKE_MARKER ('F', 'V', 'E', 'R')) #define SFX_MARKER (MAKE_MARKER ('S', 'F', 'X', '!')) #define PEAK_MARKER (MAKE_MARKER ('P', 'E', 'A', 'K')) #define basc_MARKER (MAKE_MARKER ('b', 'a', 's', 'c')) /* Supported AIFC encodings.*/ #define NONE_MARKER (MAKE_MARKER ('N', 'O', 'N', 'E')) #define sowt_MARKER (MAKE_MARKER ('s', 'o', 'w', 't')) #define twos_MARKER (MAKE_MARKER ('t', 'w', 'o', 's')) #define raw_MARKER (MAKE_MARKER ('r', 'a', 'w', ' ')) #define in32_MARKER (MAKE_MARKER ('i', 'n', '3', '2')) #define ni32_MARKER (MAKE_MARKER ('2', '3', 'n', 'i')) #define fl32_MARKER (MAKE_MARKER ('f', 'l', '3', '2')) #define FL32_MARKER (MAKE_MARKER ('F', 'L', '3', '2')) #define fl64_MARKER (MAKE_MARKER ('f', 'l', '6', '4')) #define FL64_MARKER (MAKE_MARKER ('F', 'L', '6', '4')) #define ulaw_MARKER (MAKE_MARKER ('u', 'l', 'a', 'w')) #define ULAW_MARKER (MAKE_MARKER ('U', 'L', 'A', 'W')) #define alaw_MARKER (MAKE_MARKER ('a', 'l', 'a', 'w')) #define ALAW_MARKER (MAKE_MARKER ('A', 'L', 'A', 'W')) #define DWVW_MARKER (MAKE_MARKER ('D', 'W', 'V', 'W')) #define GSM_MARKER (MAKE_MARKER ('G', 'S', 'M', ' ')) #define ima4_MARKER (MAKE_MARKER ('i', 'm', 'a', '4')) /* Unsupported AIFC encodings.*/ #define MAC3_MARKER (MAKE_MARKER ('M', 'A', 'C', '3')) #define MAC6_MARKER (MAKE_MARKER ('M', 'A', 'C', '6')) #define ADP4_MARKER (MAKE_MARKER ('A', 'D', 'P', '4')) /* Predfined chunk sizes. */ #define SIZEOF_AIFF_COMM 18 #define SIZEOF_AIFC_COMM_MIN 22 #define SIZEOF_AIFC_COMM 24 #define SIZEOF_SSND_CHUNK 8 #define SIZEOF_INST_CHUNK 20 /* Is it constant? */ /* AIFC/IMA4 defines. */ #define AIFC_IMA4_BLOCK_LEN 34 #define AIFC_IMA4_SAMPLES_PER_BLOCK 64 #define AIFF_PEAK_CHUNK_SIZE(ch) (2 * sizeof (int) + ch * (sizeof (float) + sizeof (int))) /*------------------------------------------------------------------------------ * Typedefs for file chunks. */ enum { HAVE_FORM = 0x01, HAVE_AIFF = 0x02, HAVE_AIFC = 0x04, HAVE_FVER = 0x08, HAVE_COMM = 0x10, HAVE_SSND = 0x20 } ; typedef struct { unsigned int size ; short numChannels ; unsigned int numSampleFrames ; short sampleSize ; unsigned char sampleRate [10] ; unsigned int encoding ; char zero_bytes [2] ; } COMM_CHUNK ; typedef struct { unsigned int offset ; unsigned int blocksize ; } SSND_CHUNK ; typedef struct { short playMode ; unsigned short beginLoop ; unsigned short endLoop ; } INST_LOOP ; typedef struct { char baseNote ; /* all notes are MIDI note numbers */ char detune ; /* cents off, only -50 to +50 are significant */ char lowNote ; char highNote ; char lowVelocity ; /* 1 to 127 */ char highVelocity ; /* 1 to 127 */ short gain ; /* in dB, 0 is normal */ INST_LOOP sustain_loop ; INST_LOOP release_loop ; } INST_CHUNK ; enum { basc_SCALE_MINOR = 1, basc_SCALE_MAJOR, basc_SCALE_NEITHER, basc_SCALE_BOTH } ; enum { basc_TYPE_LOOP = 0, basc_TYPE_ONE_SHOT } ; typedef struct { unsigned int version ; unsigned int numBeats ; unsigned short rootNote ; unsigned short scaleType ; unsigned short sigNumerator ; unsigned short sigDenominator ; unsigned short loopType ; } basc_CHUNK ; typedef struct { unsigned short markerID ; unsigned int position ; } MARK_ID_POS ; typedef struct { sf_count_t comm_offset ; sf_count_t ssnd_offset ; } AIFF_PRIVATE ; /*------------------------------------------------------------------------------ * Private static functions. */ static int aiff_close (SF_PRIVATE *psf) ; static int tenbytefloat2int (unsigned char *bytes) ; static void uint2tenbytefloat (unsigned int num, unsigned char *bytes) ; static int aiff_read_comm_chunk (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) ; static int aiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) ; static int aiff_write_header (SF_PRIVATE *psf, int calc_length) ; static int aiff_write_tailer (SF_PRIVATE *psf) ; static void aiff_write_strings (SF_PRIVATE *psf, int location) ; static int aiff_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; static const char *get_loop_mode_str (short mode) ; static short get_loop_mode (short mode) ; static int aiff_read_basc_chunk (SF_PRIVATE * psf, int) ; static unsigned int marker_to_position (const MARK_ID_POS *m, unsigned short n, int marksize) ; /*------------------------------------------------------------------------------ ** Public function. */ int aiff_open (SF_PRIVATE *psf) { COMM_CHUNK comm_fmt ; int error, subformat ; memset (&comm_fmt, 0, sizeof (comm_fmt)) ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if ((psf->container_data = calloc (1, sizeof (AIFF_PRIVATE))) == NULL) return SFE_MALLOC_FAILED ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = aiff_read_header (psf, &comm_fmt))) return error ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AIFF) return SFE_BAD_OPEN_FORMAT ; if (psf->mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) { if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; psf->peak_info->peak_loc = SF_PEAK_START ; } ; if (psf->mode != SFM_RDWR || psf->filelength < 40) { psf->filelength = 0 ; psf->datalength = 0 ; psf->dataoffset = 0 ; psf->sf.frames = 0 ; } ; psf->str_flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; if ((error = aiff_write_header (psf, SF_FALSE))) return error ; psf->write_header = aiff_write_header ; } ; psf->container_close = aiff_close ; psf->command = aiff_command ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_U8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_S8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; case SF_FORMAT_DWVW_12 : error = dwvw_init (psf, 12) ; break ; case SF_FORMAT_DWVW_16 : error = dwvw_init (psf, 16) ; break ; case SF_FORMAT_DWVW_24 : error = dwvw_init (psf, 24) ; break ; case SF_FORMAT_DWVW_N : if (psf->mode != SFM_READ) { error = SFE_DWVW_BAD_BITWIDTH ; break ; } ; if (comm_fmt.sampleSize >= 8 && comm_fmt.sampleSize < 24) { error = dwvw_init (psf, comm_fmt.sampleSize) ; psf->sf.frames = comm_fmt.numSampleFrames ; break ; } ; psf_log_printf (psf, "AIFC/DWVW : Bad bitwidth %d\n", comm_fmt.sampleSize) ; error = SFE_DWVW_BAD_BITWIDTH ; break ; case SF_FORMAT_IMA_ADPCM : /* ** IMA ADPCM encoded AIFF files always have a block length ** of 34 which decodes to 64 samples. */ error = aiff_ima_init (psf, AIFC_IMA4_BLOCK_LEN, AIFC_IMA4_SAMPLES_PER_BLOCK) ; break ; /* Lite remove end */ case SF_FORMAT_GSM610 : error = gsm610_init (psf) ; break ; default : return SFE_UNIMPLEMENTED ; } ; return error ; } /* aiff_open */ /*========================================================================================== ** Private functions. */ /* This function ought to check size */ static unsigned int marker_to_position (const MARK_ID_POS *m, unsigned short n, int marksize) { int i ; for (i = 0 ; i < marksize ; i++) if (m [i].markerID == n) return m [i].position ; return 0 ; } /* marker_to_position */ static int aiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) { SSND_CHUNK ssnd_fmt ; MARK_ID_POS *markstr = NULL ; AIFF_PRIVATE *paiff ; unsigned marker, dword, FORMsize, SSNDsize, bytesread ; int k, found_chunk = 0, done = 0, error = 0 ; char *cptr, byte ; int instr_found = 0, mark_found = 0, mark_count = 0 ; if ((paiff = psf->container_data) == NULL) return SFE_INTERNAL ; paiff->comm_offset = 0 ; paiff->ssnd_offset = 0 ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "p", 0) ; memset (comm_fmt, 0, sizeof (COMM_CHUNK)) ; /* Until recently AIF* file were all BIG endian. */ psf->endian = SF_ENDIAN_BIG ; /* AIFF files can apparently have their chunks in any order. However, they ** must have a FORM chunk. Approach here is to read all the chunks one by ** one and then check for the mandatory chunks at the end. */ while (! done) { psf_binheader_readf (psf, "m", &marker) ; if (psf->mode == SFM_RDWR && (found_chunk & HAVE_SSND)) return SFE_AIFF_RW_SSND_NOT_LAST ; switch (marker) { case FORM_MARKER : if (found_chunk) return SFE_AIFF_NO_FORM ; psf_binheader_readf (psf, "E4", &FORMsize) ; if (psf->fileoffset > 0 && psf->filelength > FORMsize + 8) { /* Set file length. */ psf->filelength = FORMsize + 8 ; psf_log_printf (psf, "FORM : %u\n", FORMsize) ; } else if (FORMsize != psf->filelength - 2 * SIGNED_SIZEOF (dword)) { dword = psf->filelength - 2 * sizeof (dword) ; psf_log_printf (psf, "FORM : %u (should be %u)\n", FORMsize, dword) ; FORMsize = dword ; } else psf_log_printf (psf, "FORM : %u\n", FORMsize) ; found_chunk |= HAVE_FORM ; break ; case AIFC_MARKER : case AIFF_MARKER : if ((found_chunk & HAVE_FORM) == 0) return SFE_AIFF_AIFF_NO_FORM ; psf_log_printf (psf, " %M\n", marker) ; found_chunk |= (marker == AIFC_MARKER) ? (HAVE_AIFC | HAVE_AIFF) : HAVE_AIFF ; break ; case COMM_MARKER : paiff->comm_offset = psf_ftell (psf) - 4 ; error = aiff_read_comm_chunk (psf, comm_fmt) ; psf->sf.samplerate = tenbytefloat2int (comm_fmt->sampleRate) ; psf->sf.frames = comm_fmt->numSampleFrames ; psf->sf.channels = comm_fmt->numChannels ; psf->bytewidth = BITWIDTH2BYTES (comm_fmt->sampleSize) ; if (error) return error ; found_chunk |= HAVE_COMM ; break ; case PEAK_MARKER : /* Must have COMM chunk before PEAK chunk. */ if ((found_chunk & (HAVE_FORM | HAVE_AIFF | HAVE_COMM)) != (HAVE_FORM | HAVE_AIFF | HAVE_COMM)) return SFE_AIFF_PEAK_B4_COMM ; psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, "%M : %d\n", marker, dword) ; if (dword != AIFF_PEAK_CHUNK_SIZE (psf->sf.channels)) { psf_binheader_readf (psf, "j", dword) ; psf_log_printf (psf, "*** File PEAK chunk too big.\n") ; return SFE_WAV_BAD_PEAK ; } ; if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; /* read in rest of PEAK chunk. */ psf_binheader_readf (psf, "E44", &(psf->peak_info->version), &(psf->peak_info->timestamp)) ; if (psf->peak_info->version != 1) psf_log_printf (psf, " version : %d *** (should be version 1)\n", psf->peak_info->version) ; else psf_log_printf (psf, " version : %d\n", psf->peak_info->version) ; psf_log_printf (psf, " time stamp : %d\n", psf->peak_info->timestamp) ; psf_log_printf (psf, " Ch Position Value\n") ; cptr = psf->u.cbuf ; for (dword = 0 ; dword < (unsigned) psf->sf.channels ; dword++) { float value ; unsigned int position ; psf_binheader_readf (psf, "Ef4", &value, &position) ; psf->peak_info->peaks [dword].value = value ; psf->peak_info->peaks [dword].position = position ; LSF_SNPRINTF (cptr, sizeof (psf->u.scbuf), " %2d %-12ld %g\n", dword, (long) psf->peak_info->peaks [dword].position, psf->peak_info->peaks [dword].value) ; cptr [sizeof (psf->u.scbuf) - 1] = 0 ; psf_log_printf (psf, cptr) ; } ; break ; case SSND_MARKER : if ((found_chunk & HAVE_AIFC) && (found_chunk & HAVE_FVER) == 0) psf_log_printf (psf, "*** Valid AIFC files should have an FVER chunk.\n") ; paiff->ssnd_offset = psf_ftell (psf) - 4 ; psf_binheader_readf (psf, "E444", &SSNDsize, &(ssnd_fmt.offset), &(ssnd_fmt.blocksize)) ; psf->datalength = SSNDsize - sizeof (ssnd_fmt) ; psf->dataoffset = psf_ftell (psf) ; if (psf->datalength > psf->filelength - psf->dataoffset || psf->datalength < 0) { psf_log_printf (psf, " SSND : %u (should be %D)\n", SSNDsize, psf->filelength - psf->dataoffset + sizeof (SSND_CHUNK)) ; psf->datalength = psf->filelength - psf->dataoffset ; } else psf_log_printf (psf, " SSND : %u\n", SSNDsize) ; /* Only set dataend if there really is data at the end. */ if (psf->datalength + psf->dataoffset < psf->filelength) psf->dataend = psf->datalength + psf->dataoffset ; psf_log_printf (psf, " Offset : %u\n", ssnd_fmt.offset) ; psf_log_printf (psf, " Block Size : %u\n", ssnd_fmt.blocksize) ; found_chunk |= HAVE_SSND ; if (! psf->sf.seekable) break ; /* Seek to end of SSND chunk. */ psf_fseek (psf, psf->dataoffset + psf->datalength + (SSNDsize & 1), SEEK_SET) ; break ; case c_MARKER : psf_binheader_readf (psf, "E4", &dword) ; if (dword == 0) break ; if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 1) { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ; cptr [dword] = 0 ; psf_log_printf (psf, " %M : %s\n", marker, cptr) ; psf_store_string (psf, SF_STR_COPYRIGHT, cptr) ; break ; case AUTH_MARKER : psf_binheader_readf (psf, "E4", &dword) ; if (dword == 0) break ; if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 1) { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ; cptr [dword] = 0 ; psf_log_printf (psf, " %M : %s\n", marker, cptr) ; psf_store_string (psf, SF_STR_ARTIST, cptr) ; break ; case COMT_MARKER : { unsigned short count, id, len ; unsigned int timestamp ; psf_binheader_readf (psf, "E42", &dword, &count) ; psf_log_printf (psf, " %M : %d\n count : %d\n", marker, dword, count) ; dword += (dword & 1) ; if (dword == 0) break ; dword -= 2 ; for (k = 0 ; k < count ; k++) { dword -= psf_binheader_readf (psf, "E422", ×tamp, &id, &len) ; psf_log_printf (psf, " time : 0x%x\n marker : %x\n length : %d\n", timestamp, id, len) ; if (len + 1 > SIGNED_SIZEOF (psf->u.scbuf)) { psf_log_printf (psf, "\nError : string length (%d) too big.\n", len) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; dword -= psf_binheader_readf (psf, "b", cptr, len) ; cptr [len] = 0 ; psf_log_printf (psf, " string : %s\n", cptr) ; } ; if (dword > 0) psf_binheader_readf (psf, "j", dword) ; } ; break ; case APPL_MARKER : psf_binheader_readf (psf, "E4", &dword) ; if (dword == 0) break ; if (dword >= SIGNED_SIZEOF (psf->u.scbuf) - 1) { psf_log_printf (psf, " %M : %d (too big, skipping)\n", marker, dword) ; psf_binheader_readf (psf, "j", dword + (dword & 1)) ; break ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ; cptr [dword] = 0 ; for (k = 0 ; k < (int) dword ; k++) if (! isprint (cptr [k])) { cptr [k] = 0 ; break ; } ; psf_log_printf (psf, " %M : %s\n", marker, cptr) ; psf_store_string (psf, SF_STR_SOFTWARE, cptr) ; break ; case NAME_MARKER : psf_binheader_readf (psf, "E4", &dword) ; if (dword == 0) break ; if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 2) { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ; cptr [dword] = 0 ; psf_log_printf (psf, " %M : %s\n", marker, cptr) ; psf_store_string (psf, SF_STR_TITLE, cptr) ; break ; case ANNO_MARKER : psf_binheader_readf (psf, "E4", &dword) ; if (dword == 0) break ; if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 2) { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ; return SFE_INTERNAL ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ; cptr [dword] = 0 ; psf_log_printf (psf, " %M : %s\n", marker, cptr) ; psf_store_string (psf, SF_STR_COMMENT, cptr) ; break ; case INST_MARKER : psf_binheader_readf (psf, "E4", &dword) ; if (dword != SIZEOF_INST_CHUNK) { psf_log_printf (psf, " %M : %d (should be %d)\n", marker, dword, SIZEOF_INST_CHUNK) ; psf_binheader_readf (psf, "j", dword) ; break ; } ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; { unsigned char bytes [6] ; short gain ; if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) return SFE_MALLOC_FAILED ; psf_binheader_readf (psf, "b", bytes, 6) ; psf_log_printf (psf, " Base Note : %u\n Detune : %u\n" " Low Note : %u\n High Note : %u\n" " Low Vel. : %u\n High Vel. : %u\n", bytes [0], bytes [1], bytes [2], bytes [3], bytes [4], bytes [5]) ; psf->instrument->basenote = bytes [0] ; psf->instrument->detune = bytes [1] ; psf->instrument->key_lo = bytes [2] ; psf->instrument->key_hi = bytes [3] ; psf->instrument->velocity_lo = bytes [4] ; psf->instrument->velocity_hi = bytes [5] ; psf_binheader_readf (psf, "E2", &gain) ; psf->instrument->gain = gain ; psf_log_printf (psf, " Gain (dB) : %d\n", gain) ; } ; { short mode ; /* 0 - no loop, 1 - forward looping, 2 - backward looping */ const char *loop_mode ; unsigned short begin, end ; psf_binheader_readf (psf, "E222", &mode, &begin, &end) ; loop_mode = get_loop_mode_str (mode) ; mode = get_loop_mode (mode) ; if (mode == SF_LOOP_NONE) { psf->instrument->loop_count = 0 ; psf->instrument->loops [0].mode = SF_LOOP_NONE ; } else { psf->instrument->loop_count = 1 ; psf->instrument->loops [0].mode = SF_LOOP_FORWARD ; psf->instrument->loops [0].start = begin ; psf->instrument->loops [0].end = end ; psf->instrument->loops [0].count = 0 ; } ; psf_log_printf (psf, " Sustain\n mode : %d => %s\n begin : %u\n end : %u\n", mode, loop_mode, begin, end) ; psf_binheader_readf (psf, "E222", &mode, &begin, &end) ; loop_mode = get_loop_mode_str (mode) ; mode = get_loop_mode (mode) ; if (mode == SF_LOOP_NONE) psf->instrument->loops [0].mode = SF_LOOP_NONE ; else { psf->instrument->loop_count += 1 ; psf->instrument->loops [1].mode = SF_LOOP_FORWARD ; psf->instrument->loops [1].start = begin ; psf->instrument->loops [1].end = end ; psf->instrument->loops [1].count = 0 ; } ; psf_log_printf (psf, " Release\n mode : %d => %s\n begin : %u\n end : %u\n", mode, loop_mode, begin, end) ; } ; instr_found++ ; break ; case basc_MARKER : psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " basc : %u\n", dword) ; if ((error = aiff_read_basc_chunk (psf, dword))) return error ; break ; case MARK_MARKER : psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; { unsigned short mark_id, n = 0 ; unsigned char pstr_len ; unsigned int position ; bytesread = psf_binheader_readf (psf, "E2", &n) ; mark_count = n ; markstr = calloc (mark_count, sizeof (MARK_ID_POS)) ; psf_log_printf (psf, " Count : %d\n", mark_count) ; for (n = 0 ; n < mark_count && bytesread < dword ; n++) { bytesread += psf_binheader_readf (psf, "E241", &mark_id, &position, &pstr_len) ; psf_log_printf (psf, " Mark ID : %u\n Position : %u\n", mark_id, position) ; pstr_len += (pstr_len & 1) + 1 ; /* fudgy, fudgy, hack, hack */ bytesread += psf_binheader_readf (psf, "b", psf->u.scbuf, pstr_len) ; psf_log_printf (psf, " Name : %s\n", psf->u.scbuf) ; markstr [n].markerID = mark_id ; markstr [n].position = position ; /* ** TODO if psf->u.scbuf is equal to ** either Beg_loop, Beg loop or beg loop and spam ** if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) ** return SFE_MALLOC_FAILED ; */ } ; } ; mark_found++ ; psf_binheader_readf (psf, "j", dword - bytesread) ; break ; case FVER_MARKER : found_chunk |= HAVE_FVER ; /* Fall through to next case. */ case SFX_MARKER : psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d\n", marker, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; case NONE_MARKER : /* Fix for broken AIFC files with incorrect COMM chunk length. */ psf_binheader_readf (psf, "1", &byte) ; dword = byte ; psf_binheader_readf (psf, "j", dword) ; break ; default : if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF) && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF)) { psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, " %M : %d (unknown marker)\n", marker, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; } ; if ((dword = psf_ftell (psf)) & 0x03) { psf_log_printf (psf, " Unknown chunk marker %X at position %d. Resyncing.\n", marker, dword - 4) ; psf_binheader_readf (psf, "j", -3) ; break ; } ; psf_log_printf (psf, "*** Unknown chunk marker %X at position %D. Exiting parser.\n", marker, psf_ftell (psf)) ; done = 1 ; break ; } ; /* switch (marker) */ if ((! psf->sf.seekable) && (found_chunk & HAVE_SSND)) break ; if (psf_ftell (psf) >= psf->filelength - (2 * SIGNED_SIZEOF (dword))) break ; } ; /* while (1) */ if (instr_found && mark_found) { int j ; for (j = 0 ; jinstrument->loop_count ; j ++) { if (j < ARRAY_LEN (psf->instrument->loops)) { psf->instrument->loops [j].start = marker_to_position (markstr, psf->instrument->loops [j].start, mark_count) ; psf->instrument->loops [j].end = marker_to_position (markstr, psf->instrument->loops [j].end, mark_count) ; psf->instrument->loops [j].mode = SF_LOOP_FORWARD ; } ; } ; } ; if (markstr) free (markstr) ; if (! (found_chunk & HAVE_FORM)) return SFE_AIFF_NO_FORM ; if (! (found_chunk & HAVE_AIFF)) return SFE_AIFF_COMM_NO_FORM ; if (! (found_chunk & HAVE_COMM)) return SFE_AIFF_SSND_NO_COMM ; if (! psf->dataoffset) return SFE_AIFF_NO_DATA ; return 0 ; } /* aiff_read_header */ static int aiff_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { aiff_write_tailer (psf) ; aiff_write_header (psf, SF_TRUE) ; } ; return 0 ; } /* aiff_close */ static int aiff_read_comm_chunk (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) { int error = 0, bytesread, subformat ; psf->u.scbuf [0] = 0 ; bytesread = psf_binheader_readf (psf, "E4", &(comm_fmt->size)) ; /* The COMM chunk has an int aligned to an odd word boundary. Some ** procesors are not able to deal with this (ie bus fault) so we have ** to take special care. */ comm_fmt->size += comm_fmt->size & 1 ; bytesread += psf_binheader_readf (psf, "E242b", &(comm_fmt->numChannels), &(comm_fmt->numSampleFrames), &(comm_fmt->sampleSize), &(comm_fmt->sampleRate), SIGNED_SIZEOF (comm_fmt->sampleRate)) ; if (comm_fmt->size == SIZEOF_AIFF_COMM) comm_fmt->encoding = NONE_MARKER ; else if (comm_fmt->size == SIZEOF_AIFC_COMM_MIN) bytesread += psf_binheader_readf (psf, "Em", &(comm_fmt->encoding)) ; else if (comm_fmt->size >= SIZEOF_AIFC_COMM) { unsigned char encoding_len ; bytesread += psf_binheader_readf (psf, "Em1", &(comm_fmt->encoding), &encoding_len) ; memset (psf->u.scbuf, 0, comm_fmt->size) ; bytesread += psf_binheader_readf (psf, "b", psf->u.scbuf, comm_fmt->size - SIZEOF_AIFC_COMM + 1) ; psf->u.scbuf [encoding_len] = 0 ; } ; psf_log_printf (psf, " COMM : %d\n", comm_fmt->size) ; psf_log_printf (psf, " Sample Rate : %d\n", tenbytefloat2int (comm_fmt->sampleRate)) ; psf_log_printf (psf, " Frames : %u%s\n", comm_fmt->numSampleFrames, (comm_fmt->numSampleFrames == 0 && psf->filelength > 104) ? " (Should not be 0)" : "") ; psf_log_printf (psf, " Channels : %d\n", comm_fmt->numChannels) ; /* Found some broken 'fl32' files with comm.samplesize == 16. Fix it here. */ if ((comm_fmt->encoding == fl32_MARKER || comm_fmt->encoding == FL32_MARKER) && comm_fmt->sampleSize != 32) { psf_log_printf (psf, " Sample Size : %d (should be 32)\n", comm_fmt->sampleSize) ; comm_fmt->sampleSize = 32 ; } else if ((comm_fmt->encoding == fl64_MARKER || comm_fmt->encoding == FL64_MARKER) && comm_fmt->sampleSize != 64) { psf_log_printf (psf, " Sample Size : %d (should be 64)\n", comm_fmt->sampleSize) ; comm_fmt->sampleSize = 64 ; } else psf_log_printf (psf, " Sample Size : %d\n", comm_fmt->sampleSize) ; subformat = s_bitwidth_to_subformat (comm_fmt->sampleSize) ; psf->endian = SF_ENDIAN_BIG ; switch (comm_fmt->encoding) { case NONE_MARKER : psf->sf.format = (SF_FORMAT_AIFF | subformat) ; break ; case twos_MARKER : case in32_MARKER : psf->sf.format = (SF_ENDIAN_BIG | SF_FORMAT_AIFF | subformat) ; break ; case sowt_MARKER : case ni32_MARKER : psf->endian = SF_ENDIAN_LITTLE ; psf->sf.format = (SF_ENDIAN_LITTLE | SF_FORMAT_AIFF | subformat) ; break ; case fl32_MARKER : case FL32_MARKER : psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_FLOAT) ; break ; case ulaw_MARKER : case ULAW_MARKER : psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_ULAW) ; break ; case alaw_MARKER : case ALAW_MARKER : psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_ALAW) ; break ; case fl64_MARKER : case FL64_MARKER : psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_DOUBLE) ; break ; case raw_MARKER : psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_PCM_U8) ; break ; case DWVW_MARKER : psf->sf.format = SF_FORMAT_AIFF ; switch (comm_fmt->sampleSize) { case 12 : psf->sf.format |= SF_FORMAT_DWVW_12 ; break ; case 16 : psf->sf.format |= SF_FORMAT_DWVW_16 ; break ; case 24 : psf->sf.format |= SF_FORMAT_DWVW_24 ; break ; default : psf->sf.format |= SF_FORMAT_DWVW_N ; break ; } ; break ; case GSM_MARKER : psf->sf.format = SF_FORMAT_AIFF ; psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_GSM610) ; break ; case ima4_MARKER : psf->endian = SF_ENDIAN_BIG ; psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_IMA_ADPCM) ; break ; default : psf_log_printf (psf, "AIFC : Unimplemented format : %M\n", comm_fmt->encoding) ; error = SFE_UNIMPLEMENTED ; } ; if (! psf->u.scbuf [0]) psf_log_printf (psf, " Encoding : %M\n", comm_fmt->encoding) ; else psf_log_printf (psf, " Encoding : %M => %s\n", comm_fmt->encoding, psf->u.scbuf) ; return error ; } /* aiff_read_comm_chunk */ static int aiff_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; AIFF_PRIVATE *paiff ; unsigned char comm_sample_rate [10], comm_zero_bytes [2] = { 0, 0 } ; unsigned int comm_type, comm_size, comm_encoding, comm_frames ; int k, endian ; short bit_width ; if ((paiff = psf->container_data) == NULL) return SFE_INTERNAL ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; if (psf->mode == SFM_RDWR && psf->dataoffset > 0) { /* Assuming here that the header has already been written and just ** needs to be corrected for new data length. That means that we ** only change the length fields of the FORM and SSND chunks ; ** everything else can be skipped over. */ /* First write new FORM chunk. */ psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; psf_binheader_writef (psf, "Etm8", FORM_MARKER, psf->filelength - 8) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; /* Now write frame count field of COMM chunk header. */ psf->headindex = 0 ; psf_fseek (psf, paiff->comm_offset + 10, SEEK_SET) ; psf_binheader_writef (psf, "Et8", psf->sf.frames) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; /* Now write new SSND chunk header. */ psf->headindex = 0 ; psf_fseek (psf, paiff->ssnd_offset, SEEK_SET) ; psf_binheader_writef (psf, "Etm8", SSND_MARKER, psf->datalength + SIZEOF_SSND_CHUNK) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (current < psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; else if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return 0 ; } ; endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_LITTLE_ENDIAN && endian == SF_ENDIAN_CPU) endian = SF_ENDIAN_LITTLE ; /* Standard value here. */ bit_width = psf->bytewidth * 8 ; comm_frames = (psf->sf.frames > 0xFFFFFFFF) ? 0xFFFFFFFF : psf->sf.frames ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : switch (endian) { case SF_ENDIAN_BIG : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = twos_MARKER ; break ; case SF_ENDIAN_LITTLE : psf->endian = SF_ENDIAN_LITTLE ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = sowt_MARKER ; break ; default : /* SF_ENDIAN_FILE */ psf->endian = SF_ENDIAN_BIG ; comm_type = AIFF_MARKER ; comm_size = SIZEOF_AIFF_COMM ; comm_encoding = 0 ; break ; } ; break ; case SF_FORMAT_FLOAT : /* Big endian floating point. */ psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = FL32_MARKER ; /* Use 'FL32' because its easier to read. */ break ; case SF_FORMAT_DOUBLE : /* Big endian double precision floating point. */ psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = FL64_MARKER ; /* Use 'FL64' because its easier to read. */ break ; case SF_FORMAT_ULAW : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = ulaw_MARKER ; break ; case SF_FORMAT_ALAW : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = alaw_MARKER ; break ; case SF_FORMAT_PCM_U8 : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = raw_MARKER ; break ; case SF_FORMAT_DWVW_12 : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = DWVW_MARKER ; /* Override standard value here.*/ bit_width = 12 ; break ; case SF_FORMAT_DWVW_16 : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = DWVW_MARKER ; /* Override standard value here.*/ bit_width = 16 ; break ; case SF_FORMAT_DWVW_24 : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = DWVW_MARKER ; /* Override standard value here.*/ bit_width = 24 ; break ; case SF_FORMAT_GSM610 : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = GSM_MARKER ; /* Override standard value here.*/ bit_width = 16 ; break ; case SF_FORMAT_IMA_ADPCM : psf->endian = SF_ENDIAN_BIG ; comm_type = AIFC_MARKER ; comm_size = SIZEOF_AIFC_COMM ; comm_encoding = ima4_MARKER ; /* Override standard value here.*/ bit_width = 16 ; comm_frames = psf->sf.frames / AIFC_IMA4_SAMPLES_PER_BLOCK ; break ; default : return SFE_BAD_OPEN_FORMAT ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; psf_binheader_writef (psf, "Etm8", FORM_MARKER, psf->filelength - 8) ; /* Write AIFF/AIFC marker and COM chunk. */ if (comm_type == AIFC_MARKER) /* AIFC must have an FVER chunk. */ psf_binheader_writef (psf, "Emm44m4", comm_type, FVER_MARKER, 4, 0xA2805140, COMM_MARKER, comm_size) ; else psf_binheader_writef (psf, "Emm4", comm_type, COMM_MARKER, comm_size) ; paiff->comm_offset = psf->headindex - 8 ; memset (comm_sample_rate, 0, sizeof (comm_sample_rate)) ; uint2tenbytefloat (psf->sf.samplerate, comm_sample_rate) ; psf_binheader_writef (psf, "Et242", psf->sf.channels, comm_frames, bit_width) ; psf_binheader_writef (psf, "b", comm_sample_rate, sizeof (comm_sample_rate)) ; /* AIFC chunks have some extra data. */ if (comm_type == AIFC_MARKER) psf_binheader_writef (psf, "mb", comm_encoding, comm_zero_bytes, sizeof (comm_zero_bytes)) ; if (psf->instrument != NULL) { MARK_ID_POS m [4] ; INST_CHUNK ch ; unsigned short ct = 0 ; memset (m, 0, sizeof (m)) ; memset (&ch, 0, sizeof (ch)) ; ch.baseNote = psf->instrument->basenote ; ch.detune = psf->instrument->detune ; ch.lowNote = psf->instrument->key_lo ; ch.highNote = psf->instrument->key_hi ; ch.lowVelocity = psf->instrument->velocity_lo ; ch.highVelocity = psf->instrument->velocity_hi ; ch.gain = psf->instrument->gain ; if (psf->instrument->loops [0].mode != SF_LOOP_NONE) { ch.sustain_loop.playMode = 1 ; ch.sustain_loop.beginLoop = ct ; m [0].markerID = ct++ ; m [0].position = psf->instrument->loops [0].start ; ch.sustain_loop.endLoop = ct ; m [1].markerID = ct++ ; m [1].position = psf->instrument->loops [0].end ; } ; if (psf->instrument->loops [1].mode != SF_LOOP_NONE) { ch.release_loop.playMode = 1 ; ch.release_loop.beginLoop = ct ; m [2].markerID = ct++ ; m [2].position = psf->instrument->loops [1].start ; ch.release_loop.endLoop = ct ; m [3].markerID = ct++ ; m [3].position = psf->instrument->loops [1].end ; } else { ch.release_loop.playMode = 0 ; ch.release_loop.beginLoop = 0 ; ch.release_loop.endLoop = 0 ; } ; psf_binheader_writef (psf, "Em4111111", INST_MARKER, SIZEOF_INST_CHUNK, ch.baseNote, ch.detune, ch.lowNote, ch.highNote, ch.lowVelocity, ch.highVelocity) ; psf_binheader_writef (psf, "2222222", ch.gain, ch.sustain_loop.playMode, ch.sustain_loop.beginLoop, ch.sustain_loop.endLoop, ch.release_loop.playMode, ch.release_loop.beginLoop, ch.release_loop.endLoop) ; if (ct == 2) psf_binheader_writef (psf, "Em42241b241b", MARK_MARKER, 2 + 2 * (2 + 4 + 1 + 9), 2, m [0].markerID, m [0].position, 8, "beg loop", make_size_t (9), m [1].markerID, m [1].position, 8, "end loop", make_size_t (9)) ; else if (ct == 4) psf_binheader_writef (psf, "Em42 241b 241b 241b 241b", MARK_MARKER, 2 + 4 * (2 + 4 + 1 + 9), 4, m [0].markerID, m [0].position, 8, "beg loop", make_size_t (9), m [1].markerID, m [1].position, 8, "end loop", make_size_t (9), m [2].markerID, m [2].position, 8, "beg loop", make_size_t (9), m [3].markerID, m [3].position, 8, "end loop", make_size_t (9)) ; } ; if (psf->str_flags & SF_STR_LOCATE_START) aiff_write_strings (psf, SF_STR_LOCATE_START) ; if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START) { psf_binheader_writef (psf, "Em4", PEAK_MARKER, AIFF_PEAK_CHUNK_SIZE (psf->sf.channels)) ; psf_binheader_writef (psf, "E44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "Eft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ; } ; /* Write SSND chunk. */ paiff->ssnd_offset = psf->headindex ; psf_binheader_writef (psf, "Etm844", SSND_MARKER, psf->datalength + SIZEOF_SSND_CHUNK, 0, 0) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current < psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; else if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* aiff_write_header */ static int aiff_write_tailer (SF_PRIVATE *psf) { int k ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf->dataend = psf_fseek (psf, 0, SEEK_END) ; /* Make sure tailer data starts at even byte offset. Pad if necessary. */ if (psf->dataend % 2 == 1) { psf_fwrite (psf->header, 1, 1, psf) ; psf->dataend ++ ; } ; if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_END) { psf_binheader_writef (psf, "Em4", PEAK_MARKER, AIFF_PEAK_CHUNK_SIZE (psf->sf.channels)) ; psf_binheader_writef (psf, "E44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "Eft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ; } ; if (psf->str_flags & SF_STR_LOCATE_END) aiff_write_strings (psf, SF_STR_LOCATE_END) ; /* Write the tailer. */ if (psf->headindex > 0) psf_fwrite (psf->header, psf->headindex, 1, psf) ; return 0 ; } /* aiff_write_tailer */ static void aiff_write_strings (SF_PRIVATE *psf, int location) { int k ; for (k = 0 ; k < SF_MAX_STRINGS ; k++) { if (psf->strings [k].type == 0) break ; if (psf->strings [k].flags != location) continue ; switch (psf->strings [k].type) { case SF_STR_SOFTWARE : psf_binheader_writef (psf, "EmS", APPL_MARKER, psf->strings [k].str) ; break ; case SF_STR_TITLE : psf_binheader_writef (psf, "EmS", NAME_MARKER, psf->strings [k].str) ; break ; case SF_STR_COPYRIGHT : psf_binheader_writef (psf, "EmS", c_MARKER, psf->strings [k].str) ; break ; case SF_STR_ARTIST : psf_binheader_writef (psf, "EmS", AUTH_MARKER, psf->strings [k].str) ; break ; case SF_STR_COMMENT : psf_binheader_writef (psf, "EmS", ANNO_MARKER, psf->strings [k].str) ; break ; /* case SF_STR_DATE : psf_binheader_writef (psf, "Ems", ICRD_MARKER, psf->strings [k].str) ; break ; */ } ; } ; return ; } /* aiff_write_strings */ static int aiff_command (SF_PRIVATE *psf, int command, void *data, int datasize) { /* Avoid compiler warnings. */ psf = psf ; data = data ; datasize = datasize ; switch (command) { default : break ; } ; return 0 ; } /* aiff_command */ static const char* get_loop_mode_str (short mode) { switch (mode) { case 0 : return "none" ; case 1 : return "forward" ; case 2 : return "backward" ; } ; return "*** unknown" ; } /* get_loop_mode_str */ static short get_loop_mode (short mode) { switch (mode) { case 0 : return SF_LOOP_NONE ; case 1 : return SF_LOOP_FORWARD ; case 2 : return SF_LOOP_BACKWARD ; } ; return SF_LOOP_NONE ; } /* get_loop_mode */ /*========================================================================================== ** Rough hack at converting from 80 bit IEEE float in AIFF header to an int and ** back again. It assumes that all sample rates are between 1 and 800MHz, which ** should be OK as other sound file formats use a 32 bit integer to store sample ** rate. ** There is another (probably better) version in the source code to the SoX but it ** has a copyright which probably prevents it from being allowable as GPL/LGPL. */ static int tenbytefloat2int (unsigned char *bytes) { int val = 3 ; if (bytes [0] & 0x80) /* Negative number. */ return 0 ; if (bytes [0] <= 0x3F) /* Less than 1. */ return 1 ; if (bytes [0] > 0x40) /* Way too big. */ return 0x4000000 ; if (bytes [0] == 0x40 && bytes [1] > 0x1C) /* Too big. */ return 800000000 ; /* Ok, can handle it. */ val = (bytes [2] << 23) | (bytes [3] << 15) | (bytes [4] << 7) | (bytes [5] >> 1) ; val >>= (29 - bytes [1]) ; return val ; } /* tenbytefloat2int */ static void uint2tenbytefloat (unsigned int num, unsigned char *bytes) { unsigned int mask = 0x40000000 ; int count ; if (num <= 1) { bytes [0] = 0x3F ; bytes [1] = 0xFF ; bytes [2] = 0x80 ; return ; } ; bytes [0] = 0x40 ; if (num >= mask) { bytes [1] = 0x1D ; return ; } ; for (count = 0 ; count <= 32 ; count ++) { if (num & mask) break ; mask >>= 1 ; } ; num <<= count + 1 ; bytes [1] = 29 - count ; bytes [2] = (num >> 24) & 0xFF ; bytes [3] = (num >> 16) & 0xFF ; bytes [4] = (num >> 8) & 0xFF ; bytes [5] = num & 0xFF ; } /* uint2tenbytefloat */ static int aiff_read_basc_chunk (SF_PRIVATE * psf, int datasize) { const char * type_str ; basc_CHUNK bc ; psf_binheader_readf (psf, "E442", &bc.version, &bc.numBeats, &bc.rootNote) ; psf_binheader_readf (psf, "E222", &bc.scaleType, &bc.sigNumerator, &bc.sigDenominator) ; psf_binheader_readf (psf, "E2j", &bc.loopType, datasize - sizeof (bc)) ; psf_log_printf (psf, " Version ? : %u\n Num Beats : %u\n Root Note : 0x%x\n", bc.version, bc.numBeats, bc.rootNote) ; switch (bc.scaleType) { case basc_SCALE_MINOR : type_str = "MINOR" ; break ; case basc_SCALE_MAJOR : type_str = "MAJOR" ; break ; case basc_SCALE_NEITHER : type_str = "NEITHER" ; break ; case basc_SCALE_BOTH : type_str = "BOTH" ; break ; default : type_str = "!!WRONG!!" ; break ; } ; psf_log_printf (psf, " ScaleType : 0x%x (%s)\n", bc.scaleType, type_str) ; psf_log_printf (psf, " Time Sig : %d/%d\n", bc.sigNumerator, bc.sigDenominator) ; switch (bc.loopType) { case basc_TYPE_ONE_SHOT : type_str = "One Shot" ; break ; case basc_TYPE_LOOP : type_str = "Loop" ; break ; default: type_str = "!!WRONG!!" ; break ; } ; psf_log_printf (psf, " Loop Type : 0x%x (%s)\n", bc.loopType, type_str) ; if ((psf->loop_info = calloc (1, sizeof (SF_LOOP_INFO))) == NULL) return SFE_MALLOC_FAILED ; psf->loop_info->time_sig_num = bc.sigNumerator ; psf->loop_info->time_sig_den = bc.sigDenominator ; psf->loop_info->loop_mode = (bc.loopType == basc_TYPE_ONE_SHOT) ? SF_LOOP_NONE : SF_LOOP_FORWARD ; psf->loop_info->num_beats = bc.numBeats ; /* Can always be recalculated from other known fields. */ psf->loop_info->bpm = (1.0 / psf->sf.frames) * psf->sf.samplerate * ((bc.numBeats * 4.0) / bc.sigDenominator) * 60.0 ; psf->loop_info->root_key = bc.rootNote ; return 0 ; } /* aiff_read_basc_chunk */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 7dec56ca-d6f2-48cf-863b-a72e7e17a5d9 */ nyquist-3.05/nylsf/nist.c0000644000175000000620000002351611466723256014462 0ustar stevestaff/* ** Copyright (C) 1999-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** Some of the information used to read NIST files was gleaned from ** reading the code of Bill Schottstaedt's sndlib library ** ftp://ccrma-ftp.stanford.edu/pub/Lisp/sndlib.tar.gz ** However, no code from that package was used. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ */ #define NIST_HEADER_LENGTH 1024 /*------------------------------------------------------------------------------ ** Private static functions. */ static int nist_close (SF_PRIVATE *psf) ; static int nist_write_header (SF_PRIVATE *psf, int calc_length) ; static int nist_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ */ int nist_open (SF_PRIVATE *psf) { int error ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = nist_read_header (psf))) return error ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_NIST) return SFE_BAD_OPEN_FORMAT ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU) psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; psf->sf.frames = 0 ; if ((error = nist_write_header (psf, SF_FALSE))) return error ; psf->write_header = nist_write_header ; } ; psf->container_close = nist_close ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; default : error = SFE_UNIMPLEMENTED ; break ; } ; return error ; } /* nist_open */ /*------------------------------------------------------------------------------ */ static char bad_header [] = { 'N', 'I', 'S', 'T', '_', '1', 'A', 0x0d, 0x0a, ' ', ' ', ' ', '1', '0', '2', '4', 0x0d, 0x0a, 0 } ; static int nist_read_header (SF_PRIVATE *psf) { char *psf_header ; int bitwidth = 0, bytes = 0, count, encoding ; char str [64], *cptr ; long samples ; psf->sf.format = SF_FORMAT_NIST ; psf_header = psf->u.cbuf ; if (sizeof (psf->header) <= NIST_HEADER_LENGTH) return SFE_INTERNAL ; /* Go to start of file and read in the whole header. */ psf_binheader_readf (psf, "pb", 0, psf_header, NIST_HEADER_LENGTH) ; /* Header is a string, so make sure it is null terminated. */ psf_header [NIST_HEADER_LENGTH] = 0 ; /* Now trim the header after the end marker. */ if ((cptr = strstr (psf_header, "end_head"))) { cptr += strlen ("end_head") + 1 ; cptr [0] = 0 ; } ; if (strstr (psf_header, bad_header) == psf_header) return SFE_NIST_CRLF_CONVERISON ; /* Make sure its a NIST file. */ if (strstr (psf_header, "NIST_1A\n") != psf_header) { psf_log_printf (psf, "Not a NIST file.\n") ; return SFE_NIST_BAD_HEADER ; } ; if (sscanf (psf_header, "NIST_1A\n%d\n", &count) == 1) psf->dataoffset = count ; else { psf_log_printf (psf, "*** Suspicious header length.\n") ; psf->dataoffset = NIST_HEADER_LENGTH ; } ; /* Determine sample encoding, start by assuming PCM. */ encoding = SF_FORMAT_PCM_U8 ; if ((cptr = strstr (psf_header, "sample_coding -s"))) { sscanf (cptr, "sample_coding -s%d %63s", &count, str) ; if (strcmp (str, "pcm") == 0) encoding = SF_FORMAT_PCM_U8 ; else if (strcmp (str, "alaw") == 0) encoding = SF_FORMAT_ALAW ; else if ((strcmp (str, "ulaw") == 0) || (strcmp (str, "mu-law") == 0)) encoding = SF_FORMAT_ULAW ; else { psf_log_printf (psf, "*** Unknown encoding : %s\n", str) ; encoding = 0 ; } ; } ; if ((cptr = strstr (psf_header, "channel_count -i "))) sscanf (cptr, "channel_count -i %d", &(psf->sf.channels)) ; if ((cptr = strstr (psf_header, "sample_rate -i "))) sscanf (cptr, "sample_rate -i %d", &(psf->sf.samplerate)) ; if ((cptr = strstr (psf_header, "sample_count -i "))) { sscanf (psf_header, "sample_count -i %ld", &samples) ; psf->sf.frames = samples ; } ; if ((cptr = strstr (psf_header, "sample_n_bytes -i "))) sscanf (cptr, "sample_n_bytes -i %d", &(psf->bytewidth)) ; /* Default endian-ness (for 8 bit, u-law, A-law. */ psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ; /* This is where we figure out endian-ness. */ if ((cptr = strstr (psf_header, "sample_byte_format -s"))) { sscanf (cptr, "sample_byte_format -s%d %8s", &bytes, str) ; if (bytes > 1) { if (psf->bytewidth == 0) psf->bytewidth = bytes ; else if (psf->bytewidth != bytes) { psf_log_printf (psf, "psf->bytewidth (%d) != bytes (%d)\n", psf->bytewidth, bytes) ; return SFE_NIST_BAD_ENCODING ; } ; if (strstr (str, "01") == str) psf->endian = SF_ENDIAN_LITTLE ; else if (strstr (str, "10")) psf->endian = SF_ENDIAN_BIG ; else { psf_log_printf (psf, "Weird endian-ness : %s\n", str) ; return SFE_NIST_BAD_ENCODING ; } ; } ; psf->sf.format |= psf->endian ; } ; if ((cptr = strstr (psf_header, "sample_sig_bits -i "))) sscanf (cptr, "sample_sig_bits -i %d", &bitwidth) ; if (strstr (psf_header, "channels_interleaved -s5 FALSE")) { psf_log_printf (psf, "Non-interleaved data unsupported.\n", str) ; return SFE_NIST_BAD_ENCODING ; } ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; psf->datalength = psf->filelength - psf->dataoffset ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if (encoding == SF_FORMAT_PCM_U8) { switch (psf->bytewidth) { case 1 : psf->sf.format |= SF_FORMAT_PCM_S8 ; break ; case 2 : psf->sf.format |= SF_FORMAT_PCM_16 ; break ; case 3 : psf->sf.format |= SF_FORMAT_PCM_24 ; break ; case 4 : psf->sf.format |= SF_FORMAT_PCM_32 ; break ; default : break ; } ; } else if (encoding != 0) psf->sf.format |= encoding ; else return SFE_UNIMPLEMENTED ; return 0 ; } /* nist_read_header */ static int nist_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) nist_write_header (psf, SF_TRUE) ; return 0 ; } /* nist_close */ /*========================================================================= */ static int nist_write_header (SF_PRIVATE *psf, int calc_length) { const char *end_str ; long samples ; sf_count_t current ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; if (psf->endian == SF_ENDIAN_BIG) end_str = "10" ; else if (psf->endian == SF_ENDIAN_LITTLE) end_str = "01" ; else end_str = "error" ; /* Clear the whole header. */ memset (psf->header, 0, sizeof (psf->header)) ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; psf_asciiheader_printf (psf, "NIST_1A\n 1024\n") ; psf_asciiheader_printf (psf, "channel_count -i %d\n", psf->sf.channels) ; psf_asciiheader_printf (psf, "sample_rate -i %d\n", psf->sf.samplerate) ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : psf_asciiheader_printf (psf, "sample_coding -s3 pcm\n") ; psf_asciiheader_printf (psf, "sample_n_bytes -i 1\n" "sample_sig_bits -i 8\n") ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : psf_asciiheader_printf (psf, "sample_n_bytes -i %d\n", psf->bytewidth) ; psf_asciiheader_printf (psf, "sample_sig_bits -i %d\n", psf->bytewidth * 8) ; psf_asciiheader_printf (psf, "sample_coding -s3 pcm\n" "sample_byte_format -s%d %s\n", psf->bytewidth, end_str) ; break ; case SF_FORMAT_ALAW : psf_asciiheader_printf (psf, "sample_coding -s4 alaw\n") ; psf_asciiheader_printf (psf, "sample_n_bytes -s1 1\n") ; break ; case SF_FORMAT_ULAW : psf_asciiheader_printf (psf, "sample_coding -s4 ulaw\n") ; psf_asciiheader_printf (psf, "sample_n_bytes -s1 1\n") ; break ; default : return SFE_UNIMPLEMENTED ; } ; psf->dataoffset = NIST_HEADER_LENGTH ; /* Fix this */ samples = psf->sf.frames ; psf_asciiheader_printf (psf, "sample_count -i %ld\n", samples) ; psf_asciiheader_printf (psf, "end_head\n") ; /* Zero fill to dataoffset. */ psf_binheader_writef (psf, "z", (size_t) (NIST_HEADER_LENGTH - psf->headindex)) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* nist_write_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: b45ed85d-9e22-4ad9-b78c-4b58b67152a8 */ nyquist-3.05/nylsf/wav.c0000644000175000000620000014736111466723256014307 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** Copyright (C) 2004-2005 David Viens ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "wav_w64.h" /*------------------------------------------------------------------------------ * Macros to handle big/little endian issues. */ #define RIFF_MARKER (MAKE_MARKER ('R', 'I', 'F', 'F')) #define RIFX_MARKER (MAKE_MARKER ('R', 'I', 'F', 'X')) #define WAVE_MARKER (MAKE_MARKER ('W', 'A', 'V', 'E')) #define fmt_MARKER (MAKE_MARKER ('f', 'm', 't', ' ')) #define data_MARKER (MAKE_MARKER ('d', 'a', 't', 'a')) #define fact_MARKER (MAKE_MARKER ('f', 'a', 'c', 't')) #define PEAK_MARKER (MAKE_MARKER ('P', 'E', 'A', 'K')) #define cue_MARKER (MAKE_MARKER ('c', 'u', 'e', ' ')) #define LIST_MARKER (MAKE_MARKER ('L', 'I', 'S', 'T')) #define slnt_MARKER (MAKE_MARKER ('s', 'l', 'n', 't')) #define wavl_MARKER (MAKE_MARKER ('w', 'a', 'v', 'l')) #define INFO_MARKER (MAKE_MARKER ('I', 'N', 'F', 'O')) #define plst_MARKER (MAKE_MARKER ('p', 'l', 's', 't')) #define adtl_MARKER (MAKE_MARKER ('a', 'd', 't', 'l')) #define labl_MARKER (MAKE_MARKER ('l', 'a', 'b', 'l')) #define ltxt_MARKER (MAKE_MARKER ('l', 't', 'x', 't')) #define note_MARKER (MAKE_MARKER ('n', 'o', 't', 'e')) #define smpl_MARKER (MAKE_MARKER ('s', 'm', 'p', 'l')) #define bext_MARKER (MAKE_MARKER ('b', 'e', 'x', 't')) #define levl_MARKER (MAKE_MARKER ('l', 'e', 'v', 'l')) #define MEXT_MARKER (MAKE_MARKER ('M', 'E', 'X', 'T')) #define DISP_MARKER (MAKE_MARKER ('D', 'I', 'S', 'P')) #define acid_MARKER (MAKE_MARKER ('a', 'c', 'i', 'd')) #define strc_MARKER (MAKE_MARKER ('s', 't', 'r', 'c')) #define PAD_MARKER (MAKE_MARKER ('P', 'A', 'D', ' ')) #define afsp_MARKER (MAKE_MARKER ('a', 'f', 's', 'p')) #define clm_MARKER (MAKE_MARKER ('c', 'l', 'm', ' ')) #define elmo_MARKER (MAKE_MARKER ('e', 'l', 'm', 'o')) #define ISFT_MARKER (MAKE_MARKER ('I', 'S', 'F', 'T')) #define ICRD_MARKER (MAKE_MARKER ('I', 'C', 'R', 'D')) #define ICOP_MARKER (MAKE_MARKER ('I', 'C', 'O', 'P')) #define IARL_MARKER (MAKE_MARKER ('I', 'A', 'R', 'L')) #define IART_MARKER (MAKE_MARKER ('I', 'A', 'R', 'T')) #define INAM_MARKER (MAKE_MARKER ('I', 'N', 'A', 'M')) #define IENG_MARKER (MAKE_MARKER ('I', 'E', 'N', 'G')) #define IART_MARKER (MAKE_MARKER ('I', 'A', 'R', 'T')) #define ICOP_MARKER (MAKE_MARKER ('I', 'C', 'O', 'P')) #define IPRD_MARKER (MAKE_MARKER ('I', 'P', 'R', 'D')) #define ISRC_MARKER (MAKE_MARKER ('I', 'S', 'R', 'C')) #define ISBJ_MARKER (MAKE_MARKER ('I', 'S', 'B', 'J')) #define ICMT_MARKER (MAKE_MARKER ('I', 'C', 'M', 'T')) /* Weird WAVPACK marker which can show up at the start of the DATA section. */ #define wvpk_MARKER (MAKE_MARKER ('w', 'v', 'p', 'k')) #define OggS_MARKER (MAKE_MARKER ('O', 'g', 'g', 'S')) #define WAV_PEAK_CHUNK_SIZE(ch) (2 * sizeof (int) + ch * (sizeof (float) + sizeof (int))) #define WAV_BEXT_CHUNK_SIZE 602 enum { HAVE_RIFF = 0x01, HAVE_WAVE = 0x02, HAVE_fmt = 0x04, HAVE_fact = 0x08, HAVE_PEAK = 0x10, HAVE_data = 0x20, HAVE_other = 0x80000000 } ; /* known WAVEFORMATEXTENSIBLE GUIDS */ static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM = { 0x00000002, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW = { 0x00000006, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW = { 0x00000007, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } } ; /* ** the next two are from ** http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html */ static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM = { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } } ; static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = { 0x00000003, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } } ; #if 0 /* maybe interesting one day to read the following through sf_read_raw */ /* http://www.bath.ac.uk/~masrwd/pvocex/pvocex.html */ static const EXT_SUBFORMAT MSGUID_SUBTYPE_PVOCEX = { 0x8312B9C2, 0x2E6E, 0x11d4, { 0xA8, 0x24, 0xDE, 0x5B, 0x96, 0xC3, 0xAB, 0x21 } } ; #endif /*------------------------------------------------------------------------------ ** Private static functions. */ static int wav_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ; static int wav_write_header (SF_PRIVATE *psf, int calc_length) ; static int wavex_write_header (SF_PRIVATE *psf, int calc_length) ; static int wav_write_tailer (SF_PRIVATE *psf) ; static void wav_write_strings (SF_PRIVATE *psf, int location) ; static int wav_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; static int wav_close (SF_PRIVATE *psf) ; static int wav_subchunk_parse (SF_PRIVATE *psf, int chunk) ; static int wav_read_smpl_chunk (SF_PRIVATE *psf, unsigned int chunklen) ; static int wav_read_acid_chunk (SF_PRIVATE *psf, unsigned int chunklen) ; static int wav_read_bext_chunk (SF_PRIVATE *psf, unsigned int chunklen) ; static int wav_write_bext_chunk (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int wav_open (SF_PRIVATE *psf) { int format, subformat, error, blockalign = 0, framesperblock = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = wav_read_header (psf, &blockalign, &framesperblock))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; format = psf->sf.format & SF_FORMAT_TYPEMASK ; if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX) return SFE_BAD_OPEN_FORMAT ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; /* RIFF WAVs are little-endian, RIFX WAVs are big-endian, default to little */ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_BIG_ENDIAN && psf->endian == SF_ENDIAN_CPU) psf->endian = SF_ENDIAN_BIG ; else if (psf->endian != SF_ENDIAN_BIG) psf->endian = SF_ENDIAN_LITTLE ; if (psf->mode != SFM_RDWR || psf->filelength < 44) { psf->filelength = 0 ; psf->datalength = 0 ; psf->dataoffset = 0 ; psf->sf.frames = 0 ; } ; if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) { blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; framesperblock = -1 ; /* Corrected later. */ } ; psf->str_flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; /* By default, add the peak chunk to floating point files. Default behaviour ** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE). */ if (psf->mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) { if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; psf->peak_info->peak_loc = SF_PEAK_START ; } ; psf->write_header = (format == SF_FORMAT_WAV) ? wav_write_header : wavex_write_header ; } ; psf->container_close = wav_close ; psf->command = wav_command ; switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; case SF_FORMAT_IMA_ADPCM : error = wav_w64_ima_init (psf, blockalign, framesperblock) ; break ; case SF_FORMAT_MS_ADPCM : error = wav_w64_msadpcm_init (psf, blockalign, framesperblock) ; break ; case SF_FORMAT_G721_32 : error = g72x_init (psf) ; break ; /* Lite remove end */ case SF_FORMAT_GSM610 : error = gsm610_init (psf) ; break ; default : return SFE_UNIMPLEMENTED ; } ; if (psf->mode == SFM_WRITE || (psf->mode == SFM_RDWR && psf->filelength == 0)) return psf->write_header (psf, SF_FALSE) ; return error ; } /* wav_open */ /*========================================================================= ** Private functions. */ static int wav_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) { WAV_FMT wav_fmt ; FACT_CHUNK fact_chunk ; unsigned dword = 0, marker, RIFFsize, done = 0 ; int parsestage = 0, error, format = 0 ; char *cptr ; memset (&wav_fmt, 0, sizeof (wav_fmt)) ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "p", 0) ; while (! done) { psf_binheader_readf (psf, "m", &marker) ; switch (marker) { case RIFF_MARKER : case RIFX_MARKER : if (parsestage) return SFE_WAV_NO_RIFF ; parsestage |= HAVE_RIFF ; /* RIFX signifies big-endian format for all header and data ** to prevent lots of code copying here, we'll set the psf->rwf_endian ** flag once here, and never specify endian-ness for all other header ops */ if (marker == RIFF_MARKER) psf->rwf_endian = SF_ENDIAN_LITTLE ; else psf->rwf_endian = SF_ENDIAN_BIG ; psf_binheader_readf (psf, "4", &RIFFsize) ; if (psf->fileoffset > 0 && psf->filelength > RIFFsize + 8) { /* Set file length. */ psf->filelength = RIFFsize + 8 ; if (marker == RIFF_MARKER) psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ; else psf_log_printf (psf, "RIFX : %u\n", RIFFsize) ; } else if (psf->filelength < RIFFsize + 2 * SIGNED_SIZEOF (dword)) { if (marker == RIFF_MARKER) psf_log_printf (psf, "RIFF : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (dword)) ; else psf_log_printf (psf, "RIFX : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (dword)) ; RIFFsize = dword ; } else { if (marker == RIFF_MARKER) psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ; else psf_log_printf (psf, "RIFX : %u\n", RIFFsize) ; } ; break ; case WAVE_MARKER : if ((parsestage & HAVE_RIFF) != HAVE_RIFF) return SFE_WAV_NO_WAVE ; parsestage |= HAVE_WAVE ; psf_log_printf (psf, "WAVE\n") ; break ; case fmt_MARKER : if ((parsestage & (HAVE_RIFF | HAVE_WAVE)) != (HAVE_RIFF | HAVE_WAVE)) return SFE_WAV_NO_FMT ; /* If this file has a SECOND fmt chunk, I don't want to know about it. */ if (parsestage & HAVE_fmt) break ; parsestage |= HAVE_fmt ; psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, "fmt : %d\n", dword) ; if ((error = wav_w64_read_fmt_chunk (psf, &wav_fmt, dword))) return error ; format = wav_fmt.format ; break ; case data_MARKER : if ((parsestage & (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) != (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) return SFE_WAV_NO_DATA ; if (psf->mode == SFM_RDWR && (parsestage & HAVE_other) != 0) return SFE_RDWR_BAD_HEADER ; parsestage |= HAVE_data ; psf_binheader_readf (psf, "4", &dword) ; psf->datalength = dword ; psf->dataoffset = psf_ftell (psf) ; if (dword == 0 && RIFFsize == 8 && psf->filelength > 44) { psf_log_printf (psf, "*** Looks like a WAV file which wasn't closed properly. Fixing it.\n") ; psf->datalength = dword = psf->filelength - psf->dataoffset ; } ; if (psf->datalength > psf->filelength - psf->dataoffset) { psf_log_printf (psf, "data : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ; psf->datalength = psf->filelength - psf->dataoffset ; } else psf_log_printf (psf, "data : %D\n", psf->datalength) ; /* Only set dataend if there really is data at the end. */ if (psf->datalength + psf->dataoffset < psf->filelength) psf->dataend = psf->datalength + psf->dataoffset ; if (format == WAVE_FORMAT_MS_ADPCM && psf->datalength % 2) { psf->datalength ++ ; psf_log_printf (psf, "*** Data length odd. Increasing it by 1.\n") ; } ; if (! psf->sf.seekable) break ; /* Seek past data and continue reading header. */ psf_fseek (psf, psf->datalength, SEEK_CUR) ; dword = psf_ftell (psf) ; if (dword != (sf_count_t) (psf->dataoffset + psf->datalength)) psf_log_printf (psf, "*** psf_fseek past end error ***\n", dword, psf->dataoffset + psf->datalength) ; break ; case fact_MARKER : if ((parsestage & (HAVE_RIFF | HAVE_WAVE)) != (HAVE_RIFF | HAVE_WAVE)) return SFE_WAV_BAD_FACT ; parsestage |= HAVE_fact ; if ((parsestage & HAVE_fmt) != HAVE_fmt) psf_log_printf (psf, "*** Should have 'fmt ' chunk before 'fact'\n") ; psf_binheader_readf (psf, "44", &dword, & (fact_chunk.frames)) ; if (dword > SIGNED_SIZEOF (fact_chunk)) psf_binheader_readf (psf, "j", (int) (dword - SIGNED_SIZEOF (fact_chunk))) ; if (dword) psf_log_printf (psf, "%M : %d\n", marker, dword) ; else psf_log_printf (psf, "%M : %d (should not be zero)\n", marker, dword) ; psf_log_printf (psf, " frames : %d\n", fact_chunk.frames) ; break ; case PEAK_MARKER : if ((parsestage & (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) != (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) return SFE_WAV_PEAK_B4_FMT ; parsestage |= HAVE_PEAK ; psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, "%M : %d\n", marker, dword) ; if (dword != WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) { psf_binheader_readf (psf, "j", dword) ; psf_log_printf (psf, "*** File PEAK chunk size doesn't fit with number of channels (%d).\n", psf->sf.channels) ; return SFE_WAV_BAD_PEAK ; } ; if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; /* read in rest of PEAK chunk. */ psf_binheader_readf (psf, "44", & (psf->peak_info->version), & (psf->peak_info->timestamp)) ; if (psf->peak_info->version != 1) psf_log_printf (psf, " version : %d *** (should be version 1)\n", psf->peak_info->version) ; else psf_log_printf (psf, " version : %d\n", psf->peak_info->version) ; psf_log_printf (psf, " time stamp : %d\n", psf->peak_info->timestamp) ; psf_log_printf (psf, " Ch Position Value\n") ; cptr = psf->u.cbuf ; for (dword = 0 ; dword < (unsigned) psf->sf.channels ; dword++) { float value ; unsigned int position ; psf_binheader_readf (psf, "f4", &value, &position) ; psf->peak_info->peaks [dword].value = value ; psf->peak_info->peaks [dword].position = position ; LSF_SNPRINTF (cptr, sizeof (psf->u.cbuf), " %2d %-12ld %g\n", dword, (long) psf->peak_info->peaks [dword].position, psf->peak_info->peaks [dword].value) ; cptr [sizeof (psf->u.cbuf) - 1] = 0 ; psf_log_printf (psf, cptr) ; } ; psf->peak_info->peak_loc = ((parsestage & HAVE_data) == 0) ? SF_PEAK_START : SF_PEAK_END ; break ; case cue_MARKER : parsestage |= HAVE_other ; { unsigned bytesread, cue_count ; int id, position, chunk_id, chunk_start, block_start, offset ; bytesread = psf_binheader_readf (psf, "44", &dword, &cue_count) ; bytesread -= 4 ; /* Remove bytes for first dword. */ psf_log_printf (psf, "%M : %u\n", marker, dword) ; if (cue_count > 10) { psf_log_printf (psf, " Count : %d (skipping)\n", cue_count) ; psf_binheader_readf (psf, "j", cue_count * 24) ; break ; } ; psf_log_printf (psf, " Count : %d\n", cue_count) ; while (cue_count) { bytesread += psf_binheader_readf (psf, "444444", &id, &position, &chunk_id, &chunk_start, &block_start, &offset) ; psf_log_printf (psf, " Cue ID : %2d" " Pos : %5u Chunk : %M" " Chk Start : %d Blk Start : %d" " Offset : %5d\n", id, position, chunk_id, chunk_start, block_start, offset) ; cue_count -- ; } ; if (bytesread != dword) { psf_log_printf (psf, "**** Chunk size weirdness (%d != %d)\n", dword, bytesread) ; psf_binheader_readf (psf, "j", dword - bytesread) ; } ; } ; break ; case smpl_MARKER : parsestage |= HAVE_other ; psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, "smpl : %u\n", dword) ; if ((error = wav_read_smpl_chunk (psf, dword))) return error ; break ; case acid_MARKER : parsestage |= HAVE_other ; psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, "acid : %u\n", dword) ; if ((error = wav_read_acid_chunk (psf, dword))) return error ; break ; case INFO_MARKER : case LIST_MARKER : parsestage |= HAVE_other ; if ((error = wav_subchunk_parse (psf, marker)) != 0) return error ; break ; case bext_MARKER : parsestage |= HAVE_other ; psf_binheader_readf (psf, "4", &dword) ; if (dword < WAV_BEXT_CHUNK_SIZE) psf_log_printf (psf, "bext : %u (should be >= %d)\n", dword, WAV_BEXT_CHUNK_SIZE) ; else psf_log_printf (psf, "bext : %u\n", dword) ; if ((error = wav_read_bext_chunk (psf, dword))) return error ; break ; case strc_MARKER : /* Multiple of 32 bytes. */ case afsp_MARKER : case clm_MARKER : case elmo_MARKER : case levl_MARKER : case plst_MARKER : case DISP_MARKER : case MEXT_MARKER : case PAD_MARKER : parsestage |= HAVE_other ; psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, "%M : %u\n", marker, dword) ; dword += (dword & 1) ; psf_binheader_readf (psf, "j", dword) ; break ; default : parsestage |= HAVE_other ; if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF) && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF)) { psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, "*** %M : %d (unknown marker)\n", marker, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; } ; if (psf_ftell (psf) & 0x03) { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ; psf_binheader_readf (psf, "j", -3) ; break ; } ; psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D. Exiting parser.\n", marker, psf_ftell (psf) - 4) ; done = SF_TRUE ; break ; } ; /* switch (dword) */ if (! psf->sf.seekable && (parsestage & HAVE_data)) break ; if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (dword)) { psf_log_printf (psf, "End\n") ; break ; } ; } ; /* while (1) */ if (! psf->dataoffset) return SFE_WAV_NO_DATA ; /* WAVs can be little or big endian */ psf->endian = psf->rwf_endian ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if (psf->is_pipe == 0) { /* ** Check for 'wvpk' at the start of the DATA section. Not able to ** handle this. */ psf_binheader_readf (psf, "4", &marker) ; if (marker == wvpk_MARKER || marker == OggS_MARKER) return SFE_WAV_WVPK_DATA ; } ; /* Seek to start of DATA section. */ psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if (psf->blockwidth) { if (psf->filelength - psf->dataoffset < psf->datalength) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; else psf->sf.frames = psf->datalength / psf->blockwidth ; } ; switch (format) { case WAVE_FORMAT_EXTENSIBLE : if (psf->sf.format == (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM)) { *blockalign = wav_fmt.msadpcm.blockalign ; *framesperblock = wav_fmt.msadpcm.samplesperblock ; } ; break ; case WAVE_FORMAT_PCM : psf->sf.format = SF_FORMAT_WAV | u_bitwidth_to_subformat (psf->bytewidth * 8) ; break ; case WAVE_FORMAT_MULAW : case IBM_FORMAT_MULAW : psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_ULAW) ; break ; case WAVE_FORMAT_ALAW : case IBM_FORMAT_ALAW : psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_ALAW) ; break ; case WAVE_FORMAT_MS_ADPCM : psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM) ; *blockalign = wav_fmt.msadpcm.blockalign ; *framesperblock = wav_fmt.msadpcm.samplesperblock ; break ; case WAVE_FORMAT_IMA_ADPCM : psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM) ; *blockalign = wav_fmt.ima.blockalign ; *framesperblock = wav_fmt.ima.samplesperblock ; break ; case WAVE_FORMAT_GSM610 : psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_GSM610) ; break ; case WAVE_FORMAT_IEEE_FLOAT : psf->sf.format = SF_FORMAT_WAV ; psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ; break ; case WAVE_FORMAT_G721_ADPCM : psf->sf.format = SF_FORMAT_WAV | SF_FORMAT_G721_32 ; break ; default : return SFE_UNIMPLEMENTED ; } ; /* Only set the format endian-ness if its non-standard big-endian. */ if (psf->endian == SF_ENDIAN_BIG) psf->sf.format |= SF_ENDIAN_BIG ; return 0 ; } /* wav_read_header */ static int wav_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int fmt_size, k, subformat, add_fact_chunk = SF_FALSE ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* ** RIFX signifies big-endian format for all header and data. ** To prevent lots of code copying here, we'll set the psf->rwf_endian flag ** once here, and never specify endian-ness for all other header operations. */ /* RIFF/RIFX marker, length, WAVE and 'fmt ' markers. */ if (psf->endian == SF_ENDIAN_LITTLE) psf_binheader_writef (psf, "etm8", RIFF_MARKER, (psf->filelength < 8) ? 8 : psf->filelength - 8) ; else psf_binheader_writef (psf, "Etm8", RIFX_MARKER, (psf->filelength < 8) ? 8 : psf->filelength - 8) ; /* WAVE and 'fmt ' markers. */ psf_binheader_writef (psf, "mm", WAVE_MARKER, fmt_MARKER) ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_PCM, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ; break ; case SF_FORMAT_FLOAT : case SF_FORMAT_DOUBLE : fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_IEEE_FLOAT, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_ULAW : fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_MULAW, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, 8) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_ALAW : fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_ALAW, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, 8) ; add_fact_chunk = SF_TRUE ; break ; /* Lite remove start */ case SF_FORMAT_IMA_ADPCM : { int blockalign, framesperblock, bytespersec ; blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; framesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ; bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; /* fmt chunk. */ fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; /* fmt : size, WAV format type, channels, samplerate, bytespersec */ psf_binheader_writef (psf, "42244", fmt_size, WAVE_FORMAT_IMA_ADPCM, psf->sf.channels, psf->sf.samplerate, bytespersec) ; /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ psf_binheader_writef (psf, "2222", blockalign, 4, 2, framesperblock) ; } ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_MS_ADPCM : { int blockalign, framesperblock, bytespersec, extrabytes ; blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; framesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ; bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; /* fmt chunk. */ extrabytes = 2 + 2 + MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ; fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ; /* fmt : size, WAV format type, channels. */ psf_binheader_writef (psf, "422", fmt_size, WAVE_FORMAT_MS_ADPCM, psf->sf.channels) ; /* fmt : samplerate, bytespersec. */ psf_binheader_writef (psf, "44", psf->sf.samplerate, bytespersec) ; /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ psf_binheader_writef (psf, "22222", blockalign, 4, extrabytes, framesperblock, 7) ; msadpcm_write_adapt_coeffs (psf) ; } ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_G721_32 : /* fmt chunk. */ fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; /* fmt : size, WAV format type, channels, samplerate, bytespersec */ psf_binheader_writef (psf, "42244", fmt_size, WAVE_FORMAT_G721_ADPCM, psf->sf.channels, psf->sf.samplerate, psf->sf.samplerate * psf->sf.channels / 2) ; /* fmt : blockalign, bitwidth, extrabytes, auxblocksize. */ psf_binheader_writef (psf, "2222", 64, 4, 2, 0) ; add_fact_chunk = SF_TRUE ; break ; /* Lite remove end */ case SF_FORMAT_GSM610 : { int blockalign, framesperblock, bytespersec ; blockalign = WAV_W64_GSM610_BLOCKSIZE ; framesperblock = WAV_W64_GSM610_SAMPLES ; bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; /* fmt chunk. */ fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; /* fmt : size, WAV format type, channels. */ psf_binheader_writef (psf, "422", fmt_size, WAVE_FORMAT_GSM610, psf->sf.channels) ; /* fmt : samplerate, bytespersec. */ psf_binheader_writef (psf, "44", psf->sf.samplerate, bytespersec) ; /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ psf_binheader_writef (psf, "2222", blockalign, 0, 2, framesperblock) ; } ; add_fact_chunk = SF_TRUE ; break ; default : return SFE_UNIMPLEMENTED ; } ; if (add_fact_chunk) psf_binheader_writef (psf, "tm48", fact_MARKER, 4, psf->sf.frames) ; if (psf->str_flags & SF_STR_LOCATE_START) wav_write_strings (psf, SF_STR_LOCATE_START) ; if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START) { psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ; psf_binheader_writef (psf, "44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "ft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ; } ; if (psf->broadcast_info != NULL) wav_write_bext_chunk (psf) ; if (psf->instrument != NULL) { int tmp ; double dtune = (double) (0x40000000) / 25.0 ; psf_binheader_writef (psf, "m4", smpl_MARKER, 9 * 4 + psf->instrument->loop_count * 6 * 4) ; psf_binheader_writef (psf, "44", 0, 0) ; /* Manufacturer zero is everyone */ tmp = (int) (1.0e9 / psf->sf.samplerate) ; /* Sample period in nano seconds */ psf_binheader_writef (psf, "44", tmp, psf->instrument->basenote) ; tmp = (unsigned int) (psf->instrument->detune * dtune + 0.5) ; psf_binheader_writef (psf, "4", tmp) ; psf_binheader_writef (psf, "44", 0, 0) ; /* SMTPE format */ psf_binheader_writef (psf, "44", psf->instrument->loop_count, 0) ; for (tmp = 0 ; tmp < psf->instrument->loop_count ; tmp++) { int type ; type = psf->instrument->loops [tmp].mode ; type = (type == SF_LOOP_FORWARD ? 0 : type==SF_LOOP_BACKWARD ? 2 : type == SF_LOOP_ALTERNATING ? 1 : 32) ; psf_binheader_writef (psf, "44", tmp, type) ; psf_binheader_writef (psf, "44", psf->instrument->loops [tmp].start, psf->instrument->loops [tmp].end) ; psf_binheader_writef (psf, "44", 0, psf->instrument->loops [tmp].count) ; } ; } ; psf_binheader_writef (psf, "tm8", data_MARKER, psf->datalength) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current < psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; else if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* wav_write_header */ static int wavex_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int fmt_size, k, subformat, add_fact_chunk = SF_FALSE ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* RIFX signifies big-endian format for all header and data ** to prevent lots of code copying here, we'll set the psf->rwf_endian ** flag once here, and never specify endian-ness for all other header ops */ /* RIFF marker, length, WAVE and 'fmt ' markers. */ if (psf->endian == SF_ENDIAN_LITTLE) { if (psf->filelength < 8) psf_binheader_writef (psf, "tm8", RIFF_MARKER, 8) ; else psf_binheader_writef (psf, "tm8", RIFF_MARKER, psf->filelength - 8) ; } else { if (psf->filelength < 8) psf_binheader_writef (psf, "Etm8", RIFX_MARKER, 8) ; else psf_binheader_writef (psf, "Etm8", RIFX_MARKER, psf->filelength - 8) ; } ; /* WAVE and 'fmt ' markers. */ psf_binheader_writef (psf, "mm", WAVE_MARKER, fmt_MARKER) ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; /* initial section (same for all, it appears) */ switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : case SF_FORMAT_FLOAT : case SF_FORMAT_DOUBLE : case SF_FORMAT_ULAW : case SF_FORMAT_ALAW : fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 + 2 + 8 ; /* fmt : format, channels, samplerate */ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_EXTENSIBLE, psf->sf.channels, psf->sf.samplerate) ; /* fmt : bytespersec */ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ; /* fmt : blockalign, bitwidth */ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ; /* cbSize 22 is sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX) */ psf_binheader_writef (psf, "2", 22) ; /* wValidBitsPerSample, for our use same as bitwidth as we use it fully */ psf_binheader_writef (psf, "2", psf->bytewidth * 8) ; /* ** Ok some liberty is taken here to use the most commonly used channel masks ** instead of "no mapping". If you really want to use "no mapping" for 8 channels and less ** please don't use wavex. (otherwise we'll have to create a new SF_COMMAND) */ switch (psf->sf.channels) { case 1 : /* center channel mono */ psf_binheader_writef (psf, "4", 0x4) ; break ; case 2 : /* front left and right */ psf_binheader_writef (psf, "4", 0x1 | 0x2) ; break ; case 4 : /* Quad */ psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x10 | 0x20) ; break ; case 6 : /* 5.1 */ psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20) ; break ; case 8 : /* 7.1 */ psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80) ; break ; default : /* 0 when in doubt , use direct out, ie NO mapping*/ psf_binheader_writef (psf, "4", 0x0) ; break ; } break ; case SF_FORMAT_MS_ADPCM : /* Todo, GUID exists might have different header as per wav_write_header */ default : return SFE_UNIMPLEMENTED ; } ; /* GUID section, different for each */ switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : wavex_write_guid (psf, &MSGUID_SUBTYPE_PCM) ; break ; case SF_FORMAT_FLOAT : case SF_FORMAT_DOUBLE : wavex_write_guid (psf, &MSGUID_SUBTYPE_IEEE_FLOAT) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_ULAW : wavex_write_guid (psf, &MSGUID_SUBTYPE_MULAW) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_ALAW : wavex_write_guid (psf, &MSGUID_SUBTYPE_ALAW) ; add_fact_chunk = SF_TRUE ; break ; case SF_FORMAT_MS_ADPCM : /* todo, GUID exists */ default : return SFE_UNIMPLEMENTED ; } ; if (add_fact_chunk) psf_binheader_writef (psf, "tm48", fact_MARKER, 4, psf->sf.frames) ; if (psf->str_flags & SF_STR_LOCATE_START) wav_write_strings (psf, SF_STR_LOCATE_START) ; if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START) { psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ; psf_binheader_writef (psf, "44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "ft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ; } ; psf_binheader_writef (psf, "tm8", data_MARKER, psf->datalength) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current < psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; else if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* wavex_write_header */ static int wav_write_tailer (SF_PRIVATE *psf) { int k ; /* Reset the current header buffer length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf->dataend = psf_fseek (psf, 0, SEEK_END) ; /* Add a PEAK chunk if requested. */ if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_END) { psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ; psf_binheader_writef (psf, "44", 1, time (NULL)) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "f4", psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ; } ; if (psf->str_flags & SF_STR_LOCATE_END) wav_write_strings (psf, SF_STR_LOCATE_END) ; /* Write the tailer. */ if (psf->headindex > 0) psf_fwrite (psf->header, psf->headindex, 1, psf) ; return 0 ; } /* wav_write_tailer */ static void wav_write_strings (SF_PRIVATE *psf, int location) { int k, prev_head_index, saved_head_index ; prev_head_index = psf->headindex + 4 ; psf_binheader_writef (psf, "m4m", LIST_MARKER, 0xBADBAD, INFO_MARKER) ; for (k = 0 ; k < SF_MAX_STRINGS ; k++) { if (psf->strings [k].type == 0) break ; if (psf->strings [k].flags != location) continue ; switch (psf->strings [k].type) { case SF_STR_SOFTWARE : psf_binheader_writef (psf, "ms", ISFT_MARKER, psf->strings [k].str) ; break ; case SF_STR_TITLE : psf_binheader_writef (psf, "ms", INAM_MARKER, psf->strings [k].str) ; break ; case SF_STR_COPYRIGHT : psf_binheader_writef (psf, "ms", ICOP_MARKER, psf->strings [k].str) ; break ; case SF_STR_ARTIST : psf_binheader_writef (psf, "ms", IART_MARKER, psf->strings [k].str) ; break ; case SF_STR_COMMENT : psf_binheader_writef (psf, "ms", ICMT_MARKER, psf->strings [k].str) ; break ; case SF_STR_DATE : psf_binheader_writef (psf, "ms", ICRD_MARKER, psf->strings [k].str) ; break ; } ; } ; saved_head_index = psf->headindex ; psf->headindex = prev_head_index ; psf_binheader_writef (psf, "4", saved_head_index - prev_head_index - 4) ; psf->headindex = saved_head_index ; } /* wav_write_strings */ static int wav_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { wav_write_tailer (psf) ; psf->write_header (psf, SF_TRUE) ; } ; return 0 ; } /* wav_close */ static int wav_command (SF_PRIVATE *psf, int command, void *data, int datasize) { /* Avoid compiler warnings. */ psf = psf ; data = data ; datasize = datasize ; switch (command) { default : break ; } ; return 0 ; } /* wav_command */ static int wav_subchunk_parse (SF_PRIVATE *psf, int chunk) { sf_count_t current_pos ; char *cptr ; int dword, bytesread, length ; current_pos = psf_fseek (psf, 0, SEEK_CUR) ; bytesread = psf_binheader_readf (psf, "4", &length) ; if (length <= 8) { /* This case is for broken files generated by PEAK. */ psf_log_printf (psf, "%M : %d (weird length)\n", chunk, length) ; psf_binheader_readf (psf, "mj", &chunk, length - 4) ; psf_log_printf (psf, " %M\n", chunk) ; return 0 ; } ; if (psf->headindex + length > SIGNED_SIZEOF (psf->header)) { psf_log_printf (psf, "%M : %d (too long)\n", chunk, length) ; psf_binheader_readf (psf, "j", length) ; return 0 ; } ; if (current_pos + length > psf->filelength) { psf_log_printf (psf, "%M : %d (should be %d)\n", chunk, length, (int) (psf->filelength - current_pos)) ; length = psf->filelength - current_pos ; } else psf_log_printf (psf, "%M : %d\n", chunk, length) ; while (bytesread < length) { bytesread += psf_binheader_readf (psf, "m", &chunk) ; switch (chunk) { case adtl_MARKER : case INFO_MARKER : /* These markers don't contain anything. */ psf_log_printf (psf, " %M\n", chunk) ; break ; case data_MARKER: psf_log_printf (psf, " %M inside a LIST block??? Backing out.\n", chunk) ; /* Jump back four bytes and return to caller. */ psf_binheader_readf (psf, "j", -4) ; return 0 ; case ISFT_MARKER : case ICOP_MARKER : case IARL_MARKER : case IART_MARKER : case ICMT_MARKER : case ICRD_MARKER : case IENG_MARKER : case INAM_MARKER : case IPRD_MARKER : case ISBJ_MARKER : case ISRC_MARKER : bytesread += psf_binheader_readf (psf, "4", &dword) ; dword += (dword & 1) ; if (dword < 0 || dword > SIGNED_SIZEOF (psf->u.cbuf)) { psf_log_printf (psf, " *** %M : %d (too big)\n", chunk, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword) ; bytesread += dword ; cptr [dword - 1] = 0 ; psf_log_printf (psf, " %M : %s\n", chunk, cptr) ; break ; case labl_MARKER : { int mark_id ; bytesread += psf_binheader_readf (psf, "44", &dword, &mark_id) ; dword -= 4 ; dword += (dword & 1) ; if (dword < 1 || dword > SIGNED_SIZEOF (psf->u.cbuf)) { psf_log_printf (psf, " *** %M : %d (too big)\n", chunk, dword) ; psf_binheader_readf (psf, "j", dword) ; break ; } ; cptr = psf->u.cbuf ; psf_binheader_readf (psf, "b", cptr, dword) ; bytesread += dword ; cptr [dword - 1] = 0 ; psf_log_printf (psf, " %M : %d : %s\n", chunk, mark_id, cptr) ; } ; break ; case DISP_MARKER : case ltxt_MARKER : case note_MARKER : bytesread += psf_binheader_readf (psf, "4", &dword) ; dword += (dword & 1) ; psf_binheader_readf (psf, "j", dword) ; bytesread += dword ; psf_log_printf (psf, " %M : %d\n", chunk, dword) ; break ; default : psf_binheader_readf (psf, "4", &dword) ; bytesread += sizeof (dword) ; dword += (dword & 1) ; psf_binheader_readf (psf, "j", dword) ; bytesread += dword ; psf_log_printf (psf, " *** %M : %d\n", chunk, dword) ; if (dword > length) return 0 ; break ; } ; switch (chunk) { case ISFT_MARKER : psf_store_string (psf, SF_STR_SOFTWARE, psf->u.cbuf) ; break ; case ICOP_MARKER : psf_store_string (psf, SF_STR_COPYRIGHT, psf->u.cbuf) ; break ; case INAM_MARKER : psf_store_string (psf, SF_STR_TITLE, psf->u.cbuf) ; break ; case IART_MARKER : psf_store_string (psf, SF_STR_ARTIST, psf->u.cbuf) ; break ; case ICMT_MARKER : psf_store_string (psf, SF_STR_COMMENT, psf->u.cbuf) ; break ; case ICRD_MARKER : psf_store_string (psf, SF_STR_DATE, psf->u.cbuf) ; break ; } ; } ; current_pos = psf_fseek (psf, 0, SEEK_CUR) - current_pos ; if (current_pos - 4 != length) psf_log_printf (psf, "**** Bad chunk length %d sbould be %D\n", length, current_pos - 4) ; return 0 ; } /* wav_subchunk_parse */ static int wav_read_smpl_chunk (SF_PRIVATE *psf, unsigned int chunklen) { unsigned int bytesread = 0, dword, sampler_data, loop_count ; unsigned int note, start, end, type = -1, count ; int j, k ; chunklen += (chunklen & 1) ; bytesread += psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, " Manufacturer : %X\n", dword) ; bytesread += psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, " Product : %u\n", dword) ; bytesread += psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, " Period : %u nsec\n", dword) ; bytesread += psf_binheader_readf (psf, "4", ¬e) ; psf_log_printf (psf, " Midi Note : %u\n", note) ; bytesread += psf_binheader_readf (psf, "4", &dword) ; if (dword != 0) { LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", (1.0 * 0x80000000) / ((unsigned int) dword)) ; psf_log_printf (psf, " Pitch Fract. : %s\n", psf->u.cbuf) ; } else psf_log_printf (psf, " Pitch Fract. : 0\n") ; bytesread += psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, " SMPTE Format : %u\n", dword) ; bytesread += psf_binheader_readf (psf, "4", &dword) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%02d:%02d:%02d %02d", (dword >> 24) & 0x7F, (dword >> 16) & 0x7F, (dword >> 8) & 0x7F, dword & 0x7F) ; psf_log_printf (psf, " SMPTE Offset : %s\n", psf->u.cbuf) ; bytesread += psf_binheader_readf (psf, "4", &loop_count) ; psf_log_printf (psf, " Loop Count : %u\n", loop_count) ; /* Sampler Data holds the number of data bytes after the CUE chunks which ** is not actually CUE data. Display value after CUE data. */ bytesread += psf_binheader_readf (psf, "4", &sampler_data) ; if ((psf->instrument = psf_instrument_alloc ()) == NULL) return SFE_MALLOC_FAILED ; psf->instrument->loop_count = loop_count ; for (j = 0 ; loop_count > 0 && chunklen - bytesread >= 24 ; j ++) { bytesread += psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, " Cue ID : %2u", dword) ; bytesread += psf_binheader_readf (psf, "4", &type) ; psf_log_printf (psf, " Type : %2u", type) ; bytesread += psf_binheader_readf (psf, "4", &start) ; psf_log_printf (psf, " Start : %5u", start) ; bytesread += psf_binheader_readf (psf, "4", &end) ; psf_log_printf (psf, " End : %5u", end) ; bytesread += psf_binheader_readf (psf, "4", &dword) ; psf_log_printf (psf, " Fraction : %5u", dword) ; bytesread += psf_binheader_readf (psf, "4", &count) ; psf_log_printf (psf, " Count : %5u\n", count) ; if (j < ARRAY_LEN (psf->instrument->loops)) { psf->instrument->loops [j].start = start ; psf->instrument->loops [j].end = end ; psf->instrument->loops [j].count = count ; switch (type) { case 0 : psf->instrument->loops [j].mode = SF_LOOP_FORWARD ; break ; case 1 : psf->instrument->loops [j].mode = SF_LOOP_ALTERNATING ; break ; case 2 : psf->instrument->loops [j].mode = SF_LOOP_BACKWARD ; break ; default: psf->instrument->loops [j].mode = SF_LOOP_NONE ; break ; } ; } ; loop_count -- ; } ; if (chunklen - bytesread == 0) { if (sampler_data != 0) psf_log_printf (psf, " Sampler Data : %u (should be 0)\n", sampler_data) ; else psf_log_printf (psf, " Sampler Data : %u\n", sampler_data) ; } else { if (sampler_data != chunklen - bytesread) { psf_log_printf (psf, " Sampler Data : %u (should have been %u)\n", sampler_data, chunklen - bytesread) ; sampler_data = chunklen - bytesread ; } else psf_log_printf (psf, " Sampler Data : %u\n", sampler_data) ; psf_log_printf (psf, " ") ; for (k = 0 ; k < (int) sampler_data ; k++) { char ch ; if (k > 0 && (k % 20) == 0) psf_log_printf (psf, "\n ") ; bytesread += psf_binheader_readf (psf, "1", &ch) ; psf_log_printf (psf, "%02X ", ch & 0xFF) ; } ; psf_log_printf (psf, "\n") ; } ; psf->instrument->basenote = note ; psf->instrument->gain = 1 ; psf->instrument->velocity_lo = psf->instrument->key_lo = 0 ; psf->instrument->velocity_hi = psf->instrument->key_hi = 127 ; return 0 ; } /* wav_read_smpl_chunk */ /* ** The acid chunk goes a little something like this: ** ** 4 bytes 'acid' ** 4 bytes (int) length of chunk starting at next byte ** ** 4 bytes (int) type of file: ** this appears to be a bit mask,however some combinations ** are probably impossible and/or qualified as "errors" ** ** 0x01 On: One Shot Off: Loop ** 0x02 On: Root note is Set Off: No root ** 0x04 On: Stretch is On, Off: Strech is OFF ** 0x08 On: Disk Based Off: Ram based ** 0x10 On: ?????????? Off: ????????? (Acidizer puts that ON) ** ** 2 bytes (short) root note ** if type 0x10 is OFF : [C,C#,(...),B] -> [0x30 to 0x3B] ** if type 0x10 is ON : [C,C#,(...),B] -> [0x3C to 0x47] ** (both types fit on same MIDI pitch albeit different octaves, so who cares) ** ** 2 bytes (short) ??? always set to 0x8000 ** 4 bytes (float) ??? seems to be always 0 ** 4 bytes (int) number of beats ** 2 bytes (short) meter denominator //always 4 in SF/ACID ** 2 bytes (short) meter numerator //always 4 in SF/ACID ** //are we sure about the order?? usually its num/denom ** 4 bytes (float) tempo ** */ static int wav_read_acid_chunk (SF_PRIVATE *psf, unsigned int chunklen) { unsigned int bytesread = 0 ; int beats, flags ; short rootnote, q1, meter_denom, meter_numer ; float q2, tempo ; chunklen += (chunklen & 1) ; bytesread += psf_binheader_readf (psf, "422f", &flags, &rootnote, &q1, &q2) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", q2) ; psf_log_printf (psf, " Flags : 0x%04x (%s,%s,%s,%s,%s)\n", flags, (flags & 0x01) ? "OneShot" : "Loop", (flags & 0x02) ? "RootNoteValid" : "RootNoteInvalid", (flags & 0x04) ? "StretchOn" : "StretchOff", (flags & 0x08) ? "DiskBased" : "RAMBased", (flags & 0x10) ? "??On" : "??Off") ; psf_log_printf (psf, " Root note : 0x%x\n ???? : 0x%04x\n ???? : %s\n", rootnote, q1, psf->u.cbuf) ; bytesread += psf_binheader_readf (psf, "422f", &beats, &meter_denom, &meter_numer, &tempo) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", tempo) ; psf_log_printf (psf, " Beats : %d\n Meter : %d/%d\n Tempo : %s\n", beats, meter_numer, meter_denom, psf->u.cbuf) ; psf_binheader_readf (psf, "j", chunklen - bytesread) ; if ((psf->loop_info = calloc (1, sizeof (SF_LOOP_INFO))) == NULL) return SFE_MALLOC_FAILED ; psf->loop_info->time_sig_num = meter_numer ; psf->loop_info->time_sig_den = meter_denom ; psf->loop_info->loop_mode = (flags & 0x01) ? SF_LOOP_NONE : SF_LOOP_FORWARD ; psf->loop_info->num_beats = beats ; psf->loop_info->bpm = tempo ; psf->loop_info->root_key = (flags & 0x02) ? rootnote : -1 ; return 0 ; } /* wav_read_acid_chunk */ int wav_read_bext_chunk (SF_PRIVATE *psf, unsigned int chunksize) { SF_BROADCAST_INFO* b ; if ((psf->broadcast_info = calloc (1, sizeof (SF_BROADCAST_INFO))) == NULL) { psf->error = SFE_MALLOC_FAILED ; return -1 ; } ; b = psf->broadcast_info ; psf_binheader_readf (psf, "b", b->description, sizeof (b->description)) ; psf_binheader_readf (psf, "b", b->originator, sizeof (b->originator)) ; psf_binheader_readf (psf, "b", b->originator_reference, sizeof (b->originator_reference)) ; psf_binheader_readf (psf, "b", b->origination_date, sizeof (b->origination_date)) ; psf_binheader_readf (psf, "b", b->origination_time, sizeof (b->origination_time)) ; psf_binheader_readf (psf, "442", &b->time_reference_low, &b->time_reference_high, &b->version) ; psf_binheader_readf (psf, "bj", &b->umid, sizeof (b->umid), 190) ; if (chunksize > WAV_BEXT_CHUNK_SIZE) { /* File has coding history data. */ b->coding_history_size = chunksize - WAV_BEXT_CHUNK_SIZE ; if (b->coding_history_size > SIGNED_SIZEOF (b->coding_history)) { free (psf->broadcast_info) ; psf->broadcast_info = NULL ; psf->error = SFE_MALLOC_FAILED ; return -1 ; } ; /* We do not parse the coding history */ psf_binheader_readf (psf, "b", b->coding_history, b->coding_history_size) ; b->coding_history [sizeof (b->coding_history) - 1] = 0 ; } ; return 0 ; } /* wav_read_bext_chunk */ static int wav_write_bext_chunk (SF_PRIVATE *psf) { SF_BROADCAST_INFO *b ; if ((b = psf->broadcast_info) == NULL) return -1 ; psf_binheader_writef (psf, "m4", bext_MARKER, WAV_BEXT_CHUNK_SIZE + b->coding_history_size) ; /* ** Note that it is very important the the field widths of the SF_BROADCAST_INFO ** struct match those for the bext chunk fields. */ psf_binheader_writef (psf, "b", b->description, sizeof (b->description)) ; psf_binheader_writef (psf, "b", b->originator, sizeof (b->originator)) ; psf_binheader_writef (psf, "b", b->originator_reference, sizeof (b->originator_reference)) ; psf_binheader_writef (psf, "b", b->origination_date, sizeof (b->origination_date)) ; psf_binheader_writef (psf, "b", b->origination_time, sizeof (b->origination_time)) ; psf_binheader_writef (psf, "442", b->time_reference_low, b->time_reference_high, b->version) ; psf_binheader_writef (psf, "b", b->umid, sizeof (b->umid)) ; psf_binheader_writef (psf, "z", make_size_t (190)) ; if (b->coding_history_size > 0) psf_binheader_writef (psf, "b", b->coding_history, make_size_t (b->coding_history_size)) ; return 0 ; } /* wav_write_bext_chunk */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 9c551689-a1d8-4905-9f56-26a204374f18 */ nyquist-3.05/nylsf/config.h0000644000175000000620000000250411466723256014751 0ustar stevestaff/* src/config.h. Generated from config.h.in by configure. */ /* src/config.h.in. Generated from configure.ac by autoheader. */ /* modified by RBD for Nyquist. Since Nyquist has a "config" file * called switches.h, we'll put the stuff that matters in there. * * Some switches seem to be global or trivial to define in a system * independent fashion -- those definitions are in this file. */ #ifndef SWITCHES #include "switches.h" #endif /* Set to 1 to enable experimental code. */ #define ENABLE_EXPERIMENTAL_CODE 0 /* Define to 1 if you have the header file. */ #undef HAVE_FLAC_ALL_H /* Name of package */ #define PACKAGE "libsndfile" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsndfile" /* Define to the version of this package. */ #define PACKAGE_VERSION "1.0.17" /* Set to maximum allowed value of sf_count_t type. */ #define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL /* The size of `void*', as computed by sizeof. */ #define SIZEOF_VOIDP sizeof(void *) /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "1.0.17" /* inline is only defined for C++ in Visual C++ compiler */ #ifdef WIN32 #define inline __inline #endif /* libsndfile uses HAVE_STDLIB_H instead of HAS_STDLIB_H */ #define HAVE_STDLIB_H HAS_STDLIB_H nyquist-3.05/nylsf/sfendian.h0000644000175000000620000001521211466723256015273 0ustar stevestaff/* ** Copyright (C) 1999-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #if HAVE_STDINT_H #include #elif HAVE_INTTYPES_H #include #endif #if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8)) /* Good, we have int64_t. */ #elif (defined (SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8)) typedef long long int64_t ; #elif (defined (SIZEOF_LONG) && (SIZEOF_LONG == 8)) typedef long int64_t ; #elif (defined (WIN32) || defined (_WIN32)) typedef __int64 int64_t ; #else #error "No 64 bit integer type." #endif #if HAVE_BYTESWAP_H #include #define ENDSWAP_SHORT(x) ((short) bswap_16 (x)) #define ENDSWAP_INT(x) ((int) bswap_32 (x)) #else #define ENDSWAP_SHORT(x) ((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8)) #define ENDSWAP_INT(x) ((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24)) #endif /* ** Many file types (ie WAV, AIFF) use sets of four consecutive bytes as a ** marker indicating different sections of the file. ** The following MAKE_MARKER macro allows th creation of integer constants ** for these markers. */ #if (CPU_IS_LITTLE_ENDIAN == 1) #define MAKE_MARKER(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) #elif (CPU_IS_BIG_ENDIAN == 1) #define MAKE_MARKER(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) #else #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h" #endif /* ** Macros to handle reading of data of a specific endian-ness into host endian ** shorts and ints. The single input is an unsigned char* pointer to the start ** of the object. There are two versions of each macro as we need to deal with ** both big and little endian CPUs. */ #if (CPU_IS_LITTLE_ENDIAN == 1) #define LES2H_SHORT(x) (x) #define LEI2H_INT(x) (x) #define BES2H_SHORT(x) ENDSWAP_SHORT (x) #define BEI2H_INT(x) ENDSWAP_INT (x) #define H2BE_SHORT(x) ENDSWAP_SHORT (x) #define H2BE_INT(x) ENDSWAP_INT (x) #elif (CPU_IS_BIG_ENDIAN == 1) #define LES2H_SHORT(x) ENDSWAP_SHORT (x) #define LEI2H_INT(x) ENDSWAP_INT (x) #define BES2H_SHORT(x) (x) #define BEI2H_INT(x) (x) #define H2LE_SHORT(x) ENDSWAP_SHORT (x) #define H2LE_INT(x) ENDSWAP_INT (x) #else #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h" #endif #define LET2H_SHORT_PTR(x) ((x) [1] + ((x) [2] << 8)) #define LET2H_INT_PTR(x) (((x) [0] << 8) + ((x) [1] << 16) + ((x) [2] << 24)) #define BET2H_SHORT_PTR(x) (((x) [0] << 8) + (x) [1]) #define BET2H_INT_PTR(x) (((x) [0] << 24) + ((x) [1] << 16) + ((x) [2] << 8)) /*----------------------------------------------------------------------------------------------- ** Generic functions for performing endian swapping on integer arrays. */ static inline void endswap_short_array (short *ptr, int len) { short temp ; while (--len >= 0) { temp = ptr [len] ; ptr [len] = ENDSWAP_SHORT (temp) ; } ; } /* endswap_short_array */ static inline void endswap_short_copy (short *dest, const short *src, int len) { while (--len >= 0) { dest [len] = ENDSWAP_SHORT (src [len]) ; } ; } /* endswap_short_copy */ static inline void endswap_int_array (int *ptr, int len) { int temp ; while (--len >= 0) { temp = ptr [len] ; ptr [len] = ENDSWAP_INT (temp) ; } ; } /* endswap_int_array */ static inline void endswap_int_copy (int *dest, const int *src, int len) { while (--len >= 0) { dest [len] = ENDSWAP_INT (src [len]) ; } ; } /* endswap_int_copy */ /*======================================================================================== */ #if (HAVE_BYTESWAP_H && defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8)) static inline void endswap_int64_t_array (int64_t *ptr, int len) { int64_t value ; while (--len >= 0) { value = ptr [len] ; ptr [len] = bswap_64 (value) ; } ; } /* endswap_int64_t_array */ static inline void endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len) { int64_t value ; while (--len >= 0) { value = src [len] ; dest [len] = bswap_64 (value) ; } ; } /* endswap_int64_t_copy */ #else static inline void endswap_int64_t_array (int64_t *ptr, int len) { unsigned char *ucptr, temp ; ucptr = (unsigned char *) ptr ; ucptr += 8 * len ; while (--len >= 0) { ucptr -= 8 ; temp = ucptr [0] ; ucptr [0] = ucptr [7] ; ucptr [7] = temp ; temp = ucptr [1] ; ucptr [1] = ucptr [6] ; ucptr [6] = temp ; temp = ucptr [2] ; ucptr [2] = ucptr [5] ; ucptr [5] = temp ; temp = ucptr [3] ; ucptr [3] = ucptr [4] ; ucptr [4] = temp ; } ; } /* endswap_int64_t_array */ static inline void endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len) { const unsigned char *psrc ; unsigned char *pdest ; if (dest == src) { endswap_int64_t_array (dest, len) ; return ; } ; psrc = ((const unsigned char *) src) + 8 * len ; pdest = ((unsigned char *) dest) + 8 * len ; while (--len >= 0) { psrc -= 8 ; pdest -= 8 ; pdest [0] = psrc [7] ; pdest [2] = psrc [5] ; pdest [4] = psrc [3] ; pdest [6] = psrc [1] ; pdest [7] = psrc [0] ; pdest [1] = psrc [6] ; pdest [3] = psrc [4] ; pdest [5] = psrc [2] ; } ; } /* endswap_int64_t_copy */ #endif /* A couple of wrapper functions. */ static inline void endswap_float_array (float *ptr, int len) { endswap_int_array ((void *) ptr, len) ; } /* endswap_float_array */ static inline void endswap_double_array (double *ptr, int len) { endswap_int64_t_array ((void *) ptr, len) ; } /* endswap_double_array */ static inline void endswap_float_copy (float *dest, const float *src, int len) { endswap_int_copy ((int *) dest, (const int *) src, len) ; } /* endswap_float_copy */ static inline void endswap_double_copy (double *dest, const double *src, int len) { endswap_int64_t_copy ((int64_t *) dest, (const int64_t *) src, len) ; } /* endswap_double_copy */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: f0c5cd54-42d3-4237-90ec-11fe24995de7 */ nyquist-3.05/nylsf/ppc-config.h0000644000175000000620000001516511466723256015540 0ustar stevestaff/* src/config.h. Generated from config.h.in by configure. */ /* src/config.h.in. Generated from configure.ac by autoheader. */ /* Set to 1 if the compile is GNU GCC. */ #define COMPILER_IS_GCC 1 /* Target processor clips on negative float to int conversion. */ #define CPU_CLIPS_NEGATIVE 1 /* Target processor clips on positive float to int conversion. */ #define CPU_CLIPS_POSITIVE 1 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 1 /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 0 /* Set to 1 to enable experimental code. */ #define ENABLE_EXPERIMENTAL_CODE 0 /* Major version of GCC or 3 otherwise. */ #define GCC_MAJOR_VERSION 4 /* Define to 1 if you have the header file. */ /* #undef HAVE_ALSA_ASOUNDLIB_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_BYTESWAP_H */ /* Define to 1 if you have the `calloc' function. */ #define HAVE_CALLOC 1 /* Define to 1 if you have the `ceil' function. */ #define HAVE_CEIL 1 /* Set to 1 if S_IRGRP is defined. */ #define HAVE_DECL_S_IRGRP 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ENDIAN_H */ /* Define to 1 if you have libflac 1.1.1 */ /* #undef HAVE_FLAC_1_1_1 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_FLAC_ALL_H */ /* Set to 1 if the compile supports the struct hack. */ #define HAVE_FLEXIBLE_ARRAY 1 /* Define to 1 if you have the `floor' function. */ #define HAVE_FLOOR 1 /* Define to 1 if you have the `fmod' function. */ #define HAVE_FMOD 1 /* Define to 1 if you have the `free' function. */ #define HAVE_FREE 1 /* Define to 1 if you have the `fstat' function. */ #define HAVE_FSTAT 1 /* Define to 1 if you have the `fsync' function. */ #define HAVE_FSYNC 1 /* Define to 1 if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE 1 /* Define to 1 if you have the `getpagesize' function. */ #define HAVE_GETPAGESIZE 1 /* Define to 1 if you have the `gmtime' function. */ #define HAVE_GMTIME 1 /* Define to 1 if you have the `gmtime_r' function. */ #define HAVE_GMTIME_R 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 /* Define to 1 if you have the header file. */ #define HAVE_LOCALE_H 1 /* Define if you have C99's lrint function. */ #define HAVE_LRINT 1 /* Define if you have C99's lrintf function. */ #define HAVE_LRINTF 1 /* Define to 1 if you have the `lseek' function. */ #define HAVE_LSEEK 1 /* Define to 1 if you have the `malloc' function. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `mmap' function. */ #define HAVE_MMAP 1 /* Define to 1 if you have the `open' function. */ #define HAVE_OPEN 1 /* Define to 1 if you have the `pread' function. */ #define HAVE_PREAD 1 /* Define to 1 if you have the `pwrite' function. */ #define HAVE_PWRITE 1 /* Define to 1 if you have the `read' function. */ #define HAVE_READ 1 /* Define to 1 if you have the `realloc' function. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the `setlocale' function. */ #define HAVE_SETLOCALE 1 /* Define to 1 if you have the `snprintf' function. */ #define HAVE_SNPRINTF 1 /* Set to 1 if you have libsqlite3. */ #define HAVE_SQLITE3 0 /* Define to 1 if the system has the type `ssize_t'. */ #define HAVE_SSIZE_T 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 /* Define to 1 if you have the `write' function. */ #define HAVE_WRITE 1 /* Set to 1 if compiling for MacOSX */ #define OS_IS_MACOSX 1 /* Set to 1 if compiling for Win32 */ #define OS_IS_WIN32 0 /* Name of package */ #define PACKAGE "libsndfile" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "erikd@mega-nerd.com" /* Define to the full name of this package. */ #define PACKAGE_NAME "libsndfile" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "libsndfile 1.0.17" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libsndfile" /* Define to the version of this package. */ #define PACKAGE_VERSION "1.0.17" /* Set to maximum allowed value of sf_count_t type. */ #define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL /* The size of `double', as computed by sizeof. */ #define SIZEOF_DOUBLE 8 /* The size of `float', as computed by sizeof. */ #define SIZEOF_FLOAT 4 /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `int64_t', as computed by sizeof. */ #define SIZEOF_INT64_T 8 /* The size of `loff_t', as computed by sizeof. */ /* #undef SIZEOF_LOFF_T */ /* The size of `long', as computed by sizeof. */ #define SIZEOF_LONG 4 /* The size of `long long', as computed by sizeof. */ #define SIZEOF_LONG_LONG 8 /* The size of `off64_t', as computed by sizeof. */ /* #undef SIZEOF_OFF64_T */ /* The size of `off_t', as computed by sizeof. */ #define SIZEOF_OFF_T 8 /* Set to sizeof (long) if unknown. */ #define SIZEOF_SF_COUNT_T 8 /* The size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ #define SIZEOF_SIZE_T 4 /* The size of `ssize_t', as computed by sizeof. */ #define SIZEOF_SSIZE_T 4 /* The size of `void*', as computed by sizeof. */ #define SIZEOF_VOIDP 4 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Set to long if unknown. */ #define TYPEOF_SF_COUNT_T off_t /* Set to 1 to use the native windows API */ #define USE_WINDOWS_API 0 /* Version number of package */ #define VERSION "1.0.17" /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ /* Define to make fseeko etc. visible, on some hosts. */ /* #undef _LARGEFILE_SOURCE */ /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ nyquist-3.05/nylsf/macbinary3.c0000644000175000000620000000262311466723256015531 0ustar stevestaff/* ** Copyright (C) 2003-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #if (OS_IS_MACOSX == 1) #include int macbinary3_open (SF_PRIVATE *psf) { if (psf) return 0 ; return 0 ; } /* macbinary3_open */ #else int macbinary3_open (SF_PRIVATE *psf) { psf = psf ; return 0 ; } /* macbinary3_open */ #endif /* OS_IS_MACOSX */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: c397a7d7-1a31-4349-9684-bd29ef06211e */ nyquist-3.05/nylsf/float32.c0000644000175000000620000006164711466723256014766 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "float_cast.h" #if CPU_IS_LITTLE_ENDIAN #define FLOAT32_READ float32_le_read #define FLOAT32_WRITE float32_le_write #elif CPU_IS_BIG_ENDIAN #define FLOAT32_READ float32_be_read #define FLOAT32_WRITE float32_be_write #endif /*-------------------------------------------------------------------------------------------- ** Processor floating point capabilities. float32_get_capability () returns one of the ** latter four values. */ enum { FLOAT_UNKNOWN = 0x00, FLOAT_CAN_RW_LE = 0x12, FLOAT_CAN_RW_BE = 0x23, FLOAT_BROKEN_LE = 0x34, FLOAT_BROKEN_BE = 0x45 } ; /*-------------------------------------------------------------------------------------------- ** Prototypes for private functions. */ static sf_count_t host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t host_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t host_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t host_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t host_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static void float32_peak_update (SF_PRIVATE *psf, const float *buffer, int count, sf_count_t indx) ; static sf_count_t replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t replace_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t replace_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t replace_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t replace_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static void bf2f_array (float *buffer, int count) ; static void f2bf_array (float *buffer, int count) ; static int float32_get_capability (SF_PRIVATE *psf) ; /*-------------------------------------------------------------------------------------------- ** Exported functions. */ int float32_init (SF_PRIVATE *psf) { static int float_caps ; float_caps = float32_get_capability (psf) ; psf->blockwidth = sizeof (float) * psf->sf.channels ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { switch (psf->endian + float_caps) { case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_FALSE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_FALSE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_TRUE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_TRUE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; /* When the CPU is not IEEE compatible. */ case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) : psf->float_endswap = SF_TRUE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) : psf->float_endswap = SF_FALSE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) : psf->float_endswap = SF_FALSE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) : psf->float_endswap = SF_TRUE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; default : break ; } ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { switch (psf->endian + float_caps) { case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_FALSE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_FALSE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_TRUE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_TRUE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; /* When the CPU is not IEEE compatible. */ case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) : psf->float_endswap = SF_TRUE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) : psf->float_endswap = SF_FALSE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) : psf->float_endswap = SF_FALSE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) : psf->float_endswap = SF_TRUE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; default : break ; } ; } ; if (psf->filelength > psf->dataoffset) { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; } else psf->datalength = 0 ; psf->sf.frames = psf->datalength / psf->blockwidth ; return 0 ; } /* float32_init */ float float32_be_read (unsigned char *cptr) { int exponent, mantissa, negative ; float fvalue ; negative = cptr [0] & 0x80 ; exponent = ((cptr [0] & 0x7F) << 1) | ((cptr [1] & 0x80) ? 1 : 0) ; mantissa = ((cptr [1] & 0x7F) << 16) | (cptr [2] << 8) | (cptr [3]) ; if (! (exponent || mantissa)) return 0.0 ; mantissa |= 0x800000 ; exponent = exponent ? exponent - 127 : 0 ; fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ; if (negative) fvalue *= -1 ; if (exponent > 0) fvalue *= (1 << exponent) ; else if (exponent < 0) fvalue /= (1 << abs (exponent)) ; return fvalue ; } /* float32_be_read */ float float32_le_read (unsigned char *cptr) { int exponent, mantissa, negative ; float fvalue ; negative = cptr [3] & 0x80 ; exponent = ((cptr [3] & 0x7F) << 1) | ((cptr [2] & 0x80) ? 1 : 0) ; mantissa = ((cptr [2] & 0x7F) << 16) | (cptr [1] << 8) | (cptr [0]) ; if (! (exponent || mantissa)) return 0.0 ; mantissa |= 0x800000 ; exponent = exponent ? exponent - 127 : 0 ; fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ; if (negative) fvalue *= -1 ; if (exponent > 0) fvalue *= (1 << exponent) ; else if (exponent < 0) fvalue /= (1 << abs (exponent)) ; return fvalue ; } /* float32_le_read */ void float32_le_write (float in, unsigned char *out) { int exponent, mantissa, negative = 0 ; memset (out, 0, sizeof (int)) ; if (fabs (in) < 1e-30) return ; if (in < 0.0) { in *= -1.0 ; negative = 1 ; } ; in = frexp (in, &exponent) ; exponent += 126 ; in *= (float) 0x1000000 ; mantissa = (((int) in) & 0x7FFFFF) ; if (negative) out [3] |= 0x80 ; if (exponent & 0x01) out [2] |= 0x80 ; out [0] = mantissa & 0xFF ; out [1] = (mantissa >> 8) & 0xFF ; out [2] |= (mantissa >> 16) & 0x7F ; out [3] |= (exponent >> 1) & 0x7F ; return ; } /* float32_le_write */ void float32_be_write (float in, unsigned char *out) { int exponent, mantissa, negative = 0 ; memset (out, 0, sizeof (int)) ; if (fabs (in) < 1e-30) return ; if (in < 0.0) { in *= -1.0 ; negative = 1 ; } ; in = frexp (in, &exponent) ; exponent += 126 ; in *= (float) 0x1000000 ; mantissa = (((int) in) & 0x7FFFFF) ; if (negative) out [0] |= 0x80 ; if (exponent & 0x01) out [1] |= 0x80 ; out [3] = mantissa & 0xFF ; out [2] = (mantissa >> 8) & 0xFF ; out [1] |= (mantissa >> 16) & 0x7F ; out [0] |= (exponent >> 1) & 0x7F ; return ; } /* float32_be_write */ /*============================================================================================== ** Private functions. */ static void float32_peak_update (SF_PRIVATE *psf, const float *buffer, int count, sf_count_t indx) { int chan ; int k, position ; float fmaxval ; for (chan = 0 ; chan < psf->sf.channels ; chan++) { fmaxval = fabs (buffer [chan]) ; position = 0 ; for (k = chan ; k < count ; k += psf->sf.channels) if (fmaxval < fabs (buffer [k])) { fmaxval = fabs (buffer [k]) ; position = k ; } ; if (fmaxval > psf->peak_info->peaks [chan].value) { psf->peak_info->peaks [chan].value = fmaxval ; psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ; } ; } ; return ; } /* float32_peak_update */ static int float32_get_capability (SF_PRIVATE *psf) { union { float f ; int i ; unsigned char c [4] ; } data ; data.f = (float) 1.23456789 ; /* Some abitrary value. */ if (! psf->ieee_replace) { /* If this test is true ints and floats are compatible and little endian. */ if (data.c [0] == 0x52 && data.c [1] == 0x06 && data.c [2] == 0x9e && data.c [3] == 0x3f) return FLOAT_CAN_RW_LE ; /* If this test is true ints and floats are compatible and big endian. */ if (data.c [3] == 0x52 && data.c [2] == 0x06 && data.c [1] == 0x9e && data.c [0] == 0x3f) return FLOAT_CAN_RW_BE ; } ; /* Floats are broken. Don't expect reading or writing to be fast. */ psf_log_printf (psf, "Using IEEE replacement code for float.\n") ; return (CPU_IS_LITTLE_ENDIAN) ? FLOAT_BROKEN_LE : FLOAT_BROKEN_BE ; } /* float32_get_capability */ /*======================================================================================= */ static inline void f2s_array (const float *src, int count, short *dest, float scale) { while (--count >= 0) { dest [count] = lrintf (scale * src [count]) ; } ; } /* f2s_array */ static inline void f2i_array (const float *src, int count, int *dest, float scale) { while (--count >= 0) { dest [count] = lrintf (scale * src [count]) ; } ; } /* f2i_array */ static inline void f2d_array (const float *src, int count, double *dest) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* f2d_array */ static inline void s2f_array (const short *src, float *dest, int count) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* s2f_array */ static inline void i2f_array (const int *src, float *dest, int count) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* i2f_array */ static inline void d2f_array (const double *src, float *dest, int count) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* d2f_array */ /*---------------------------------------------------------------------------------------------- */ static sf_count_t host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float scale ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; /* Fix me : Need lef2s_array */ if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; f2s_array (psf->u.fbuf, readcount, ptr + total, scale) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* host_read_f2s */ static sf_count_t host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float scale ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; f2i_array (psf->u.fbuf, readcount, ptr + total, scale) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* host_read_f2i */ static sf_count_t host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; if (psf->float_endswap != SF_TRUE) return psf_fread (ptr, sizeof (float), len, psf) ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; endswap_int_copy ((int*) (ptr + total), psf->u.ibuf, readcount) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* host_read_f */ static sf_count_t host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; /* Fix me : Need lef2d_array */ f2d_array (psf->u.fbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* host_read_f2d */ static sf_count_t host_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2f_array (ptr + total, psf->u.fbuf, bufferlen) ; if (psf->peak_info) float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_s2f */ static sf_count_t host_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2f_array (ptr + total, psf->u.fbuf, bufferlen) ; if (psf->peak_info) float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float) , bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_i2f */ static sf_count_t host_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; if (psf->peak_info) float32_peak_update (psf, ptr, len, 0) ; if (psf->float_endswap != SF_TRUE) return psf_fwrite (ptr, sizeof (float), len, psf) ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_int_copy (psf->u.ibuf, (const int*) (ptr + total), bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_f */ static sf_count_t host_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; d2f_array (ptr + total, psf->u.fbuf, bufferlen) ; if (psf->peak_info) float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_d2f */ /*======================================================================================= */ static sf_count_t replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float scale ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; bf2f_array (psf->u.fbuf, bufferlen) ; f2s_array (psf->u.fbuf, readcount, ptr + total, scale) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_f2s */ static sf_count_t replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float scale ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; bf2f_array (psf->u.fbuf, bufferlen) ; f2i_array (psf->u.fbuf, readcount, ptr + total, scale) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_f2i */ static sf_count_t replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; /* FIX THIS */ bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; bf2f_array (psf->u.fbuf, bufferlen) ; memcpy (ptr + total, psf->u.fbuf, bufferlen * sizeof (float)) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_f */ static sf_count_t replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; bf2f_array (psf->u.fbuf, bufferlen) ; f2d_array (psf->u.fbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_f2d */ static sf_count_t replace_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2f_array (ptr + total, psf->u.fbuf, bufferlen) ; if (psf->peak_info) float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ; f2bf_array (psf->u.fbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_s2f */ static sf_count_t replace_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2f_array (ptr + total, psf->u.fbuf, bufferlen) ; if (psf->peak_info) float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ; f2bf_array (psf->u.fbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_i2f */ static sf_count_t replace_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; /* FIX THIS */ if (psf->peak_info) float32_peak_update (psf, ptr, len, 0) ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; memcpy (psf->u.fbuf, ptr + total, bufferlen * sizeof (float)) ; f2bf_array (psf->u.fbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float) , bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_f */ static sf_count_t replace_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.fbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; d2f_array (ptr + total, psf->u.fbuf, bufferlen) ; if (psf->peak_info) float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ; f2bf_array (psf->u.fbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_int_array (psf->u.ibuf, bufferlen) ; writecount = psf_fwrite (psf->u.fbuf, sizeof (float), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_d2f */ /*---------------------------------------------------------------------------------------------- */ static void bf2f_array (float *buffer, int count) { while (--count >= 0) { buffer [count] = FLOAT32_READ ((unsigned char *) (buffer + count)) ; } ; } /* bf2f_array */ static void f2bf_array (float *buffer, int count) { while (--count >= 0) { FLOAT32_WRITE (buffer [count], (unsigned char*) (buffer + count)) ; } ; } /* f2bf_array */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: b6c34917-488c-4145-9648-f4371fc4c889 */ nyquist-3.05/nylsf/vox_adpcm.c0000644000175000000620000003312011466723256015455 0ustar stevestaff/* ** Copyright (C) 2002-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** This is the OKI / Dialogic ADPCM encoder/decoder. It converts from ** 12 bit linear sample data to a 4 bit ADPCM. ** ** Implemented from the description found here: ** ** http://www.comptek.ru:8100/telephony/tnotes/tt1-13.html ** ** and compared against the encoder/decoder found here: ** ** http://ibiblio.org/pub/linux/apps/sound/convert/vox.tar.gz */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" #define VOX_DATA_LEN 2048 #define PCM_DATA_LEN (VOX_DATA_LEN *2) typedef struct { short last ; short step_index ; int vox_bytes, pcm_samples ; unsigned char vox_data [VOX_DATA_LEN] ; short pcm_data [PCM_DATA_LEN] ; } VOX_ADPCM_PRIVATE ; static int vox_adpcm_encode_block (VOX_ADPCM_PRIVATE *pvox) ; static int vox_adpcm_decode_block (VOX_ADPCM_PRIVATE *pvox) ; static short vox_adpcm_decode (char code, VOX_ADPCM_PRIVATE *pvox) ; static char vox_adpcm_encode (short samp, VOX_ADPCM_PRIVATE *pvox) ; static sf_count_t vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t vox_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t vox_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t vox_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t vox_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t vox_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t vox_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static int vox_read_block (SF_PRIVATE *psf, VOX_ADPCM_PRIVATE *pvox, short *ptr, int len) ; /*============================================================================================ ** Predefined OKI ADPCM encoder/decoder tables. */ static short step_size_table [49] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1408, 1552 } ; /* step_size_table */ static short step_adjust_table [8] = { -1, -1, -1, -1, 2, 4, 6, 8 } ; /* step_adjust_table */ /*------------------------------------------------------------------------------ */ int vox_adpcm_init (SF_PRIVATE *psf) { VOX_ADPCM_PRIVATE *pvox = NULL ; if (psf->mode == SFM_RDWR) return SFE_BAD_MODE_RW ; if (psf->mode == SFM_WRITE && psf->sf.channels != 1) return SFE_CHANNEL_COUNT ; if ((pvox = malloc (sizeof (VOX_ADPCM_PRIVATE))) == NULL) return SFE_MALLOC_FAILED ; psf->codec_data = (void*) pvox ; memset (pvox, 0, sizeof (VOX_ADPCM_PRIVATE)) ; if (psf->mode == SFM_WRITE) { psf->write_short = vox_write_s ; psf->write_int = vox_write_i ; psf->write_float = vox_write_f ; psf->write_double = vox_write_d ; } else { psf_log_printf (psf, "Header-less OKI Dialogic ADPCM encoded file.\n") ; psf_log_printf (psf, "Setting up for 8kHz, mono, Vox ADPCM.\n") ; psf->read_short = vox_read_s ; psf->read_int = vox_read_i ; psf->read_float = vox_read_f ; psf->read_double = vox_read_d ; } ; /* Standard sample rate chennels etc. */ if (psf->sf.samplerate < 1) psf->sf.samplerate = 8000 ; psf->sf.channels = 1 ; psf->sf.frames = psf->filelength * 2 ; psf->sf.seekable = SF_FALSE ; /* Seek back to start of data. */ if (psf_fseek (psf, 0 , SEEK_SET) == -1) return SFE_BAD_SEEK ; return 0 ; } /* vox_adpcm_init */ /*------------------------------------------------------------------------------ */ static char vox_adpcm_encode (short samp, VOX_ADPCM_PRIVATE *pvox) { short code ; short diff, error, stepsize ; stepsize = step_size_table [pvox->step_index] ; code = 0 ; diff = samp - pvox->last ; if (diff < 0) { code = 0x08 ; error = -diff ; } else error = diff ; if (error >= stepsize) { code = code | 0x04 ; error -= stepsize ; } ; if (error >= stepsize / 2) { code = code | 0x02 ; error -= stepsize / 2 ; } ; if (error >= stepsize / 4) code = code | 0x01 ; /* ** To close the feedback loop, the deocder is used to set the ** estimate of last sample and in doing so, also set the step_index. */ pvox->last = vox_adpcm_decode (code, pvox) ; return code ; } /* vox_adpcm_encode */ static short vox_adpcm_decode (char code, VOX_ADPCM_PRIVATE *pvox) { short diff, error, stepsize, samp ; stepsize = step_size_table [pvox->step_index] ; error = stepsize / 8 ; if (code & 0x01) error += stepsize / 4 ; if (code & 0x02) error += stepsize / 2 ; if (code & 0x04) error += stepsize ; diff = (code & 0x08) ? -error : error ; samp = pvox->last + diff ; /* ** Apply clipping. */ if (samp > 2048) samp = 2048 ; if (samp < -2048) samp = -2048 ; pvox->last = samp ; pvox->step_index += step_adjust_table [code & 0x7] ; if (pvox->step_index < 0) pvox->step_index = 0 ; if (pvox->step_index > 48) pvox->step_index = 48 ; return samp ; } /* vox_adpcm_decode */ static int vox_adpcm_encode_block (VOX_ADPCM_PRIVATE *pvox) { unsigned char code ; int j, k ; /* If data_count is odd, add an extra zero valued sample. */ if (pvox->pcm_samples & 1) pvox->pcm_data [pvox->pcm_samples++] = 0 ; for (j = k = 0 ; k < pvox->pcm_samples ; j++) { code = vox_adpcm_encode (pvox->pcm_data [k++] / 16, pvox) << 4 ; code |= vox_adpcm_encode (pvox->pcm_data [k++] / 16, pvox) ; pvox->vox_data [j] = code ; } ; pvox->vox_bytes = j ; return 0 ; } /* vox_adpcm_encode_block */ static int vox_adpcm_decode_block (VOX_ADPCM_PRIVATE *pvox) { unsigned char code ; int j, k ; for (j = k = 0 ; j < pvox->vox_bytes ; j++) { code = pvox->vox_data [j] ; pvox->pcm_data [k++] = 16 * vox_adpcm_decode ((code >> 4) & 0x0f, pvox) ; pvox->pcm_data [k++] = 16 * vox_adpcm_decode (code & 0x0f, pvox) ; } ; pvox->pcm_samples = k ; return 0 ; } /* vox_adpcm_decode_block */ /*============================================================================== */ static int vox_read_block (SF_PRIVATE *psf, VOX_ADPCM_PRIVATE *pvox, short *ptr, int len) { int indx = 0, k ; while (indx < len) { pvox->vox_bytes = (len - indx > PCM_DATA_LEN) ? VOX_DATA_LEN : (len - indx + 1) / 2 ; if ((k = psf_fread (pvox->vox_data, 1, pvox->vox_bytes, psf)) != pvox->vox_bytes) { if (psf_ftell (psf) + k != psf->filelength) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pvox->vox_bytes) ; if (k == 0) break ; } ; pvox->vox_bytes = k ; vox_adpcm_decode_block (pvox) ; memcpy (&(ptr [indx]), pvox->pcm_data, pvox->pcm_samples * sizeof (short)) ; indx += pvox->pcm_samples ; } ; return indx ; } /* vox_read_block */ static sf_count_t vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; int readcount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; while (len > 0) { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = vox_read_block (psf, pvox, ptr, readcount) ; total += count ; len -= count ; if (count != readcount) break ; } ; return total ; } /* vox_read_s */ static sf_count_t vox_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; short *sptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : (int) len ; count = vox_read_block (psf, pvox, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = ((int) sptr [k]) << 16 ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* vox_read_i */ static sf_count_t vox_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; short *sptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : (int) len ; count = vox_read_block (psf, pvox, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (float) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* vox_read_f */ static sf_count_t vox_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; short *sptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; double normfact ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : (int) len ; count = vox_read_block (psf, pvox, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (double) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* vox_read_d */ /*------------------------------------------------------------------------------ */ static int vox_write_block (SF_PRIVATE *psf, VOX_ADPCM_PRIVATE *pvox, const short *ptr, int len) { int indx = 0, k ; while (indx < len) { pvox->pcm_samples = (len - indx > PCM_DATA_LEN) ? PCM_DATA_LEN : len - indx ; memcpy (pvox->pcm_data, &(ptr [indx]), pvox->pcm_samples * sizeof (short)) ; vox_adpcm_encode_block (pvox) ; if ((k = psf_fwrite (pvox->vox_data, 1, pvox->vox_bytes, psf)) != pvox->vox_bytes) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pvox->vox_bytes) ; indx += pvox->pcm_samples ; } ; return indx ; } /* vox_write_block */ static sf_count_t vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; int writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; while (len) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = vox_write_block (psf, pvox, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* vox_write_s */ static sf_count_t vox_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; for (k = 0 ; k < writecount ; k++) sptr [k] = ptr [total + k] >> 16 ; count = vox_write_block (psf, pvox, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* vox_write_i */ static sf_count_t vox_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrintf (normfact * ptr [total + k]) ; count = vox_write_block (psf, pvox, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* vox_write_f */ static sf_count_t vox_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { VOX_ADPCM_PRIVATE *pvox ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; double normfact ; if (! psf->codec_data) return 0 ; pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrint (normfact * ptr [total + k]) ; count = vox_write_block (psf, pvox, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* vox_write_d */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: e15e97fe-ff9d-4b46-a489-7059fb2d0b1e */ nyquist-3.05/nylsf/caf.c0000644000175000000620000004046611466723256014241 0ustar stevestaff/* ** Copyright (C) 2005, 2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define aac_MARKER MAKE_MARKER ('a', 'a', 'c', ' ') #define alac_MARKER MAKE_MARKER ('a', 'l', 'a', 'c') #define alaw_MARKER MAKE_MARKER ('a', 'l', 'a', 'w') #define caff_MARKER MAKE_MARKER ('c', 'a', 'f', 'f') #define chan_MARKER MAKE_MARKER ('c', 'h', 'a', 'n') #define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a') #define desc_MARKER MAKE_MARKER ('d', 'e', 's', 'c') #define edct_MARKER MAKE_MARKER ('e', 'd', 'c', 't') #define free_MARKER MAKE_MARKER ('f', 'r', 'e', 'e') #define ima4_MARKER MAKE_MARKER ('i', 'm', 'a', '4') #define info_MARKER MAKE_MARKER ('i', 'n', 'f', 'o') #define inst_MARKER MAKE_MARKER ('i', 'n', 's', 't') #define kuki_MARKER MAKE_MARKER ('k', 'u', 'k', 'i') #define lpcm_MARKER MAKE_MARKER ('l', 'p', 'c', 'm') #define mark_MARKER MAKE_MARKER ('m', 'a', 'r', 'k') #define midi_MARKER MAKE_MARKER ('m', 'i', 'd', 'i') #define mp1_MARKER MAKE_MARKER ('.', 'm', 'p', '1') #define mp2_MARKER MAKE_MARKER ('.', 'm', 'p', '2') #define mp3_MARKER MAKE_MARKER ('.', 'm', 'p', '3') #define ovvw_MARKER MAKE_MARKER ('o', 'v', 'v', 'w') #define pakt_MARKER MAKE_MARKER ('p', 'a', 'k', 't') #define peak_MARKER MAKE_MARKER ('p', 'e', 'a', 'k') #define regn_MARKER MAKE_MARKER ('r', 'e', 'g', 'n') #define strg_MARKER MAKE_MARKER ('s', 't', 'r', 'g') #define umid_MARKER MAKE_MARKER ('u', 'm', 'i', 'd') #define uuid_MARKER MAKE_MARKER ('u', 'u', 'i', 'd') #define ulaw_MARKER MAKE_MARKER ('u', 'l', 'a', 'w') #define MAC3_MARKER MAKE_MARKER ('M', 'A', 'C', '3') #define MAC6_MARKER MAKE_MARKER ('M', 'A', 'C', '6') #define CAF_PEAK_CHUNK_SIZE(ch) ((int) (sizeof (int) + ch * (sizeof (float) + 8))) #define SFE_CAF_NOT_CAF 666 #define SFE_CAF_NO_DESC 667 #define SFE_CAF_BAD_PEAK 668 /*------------------------------------------------------------------------------ ** Typedefs. */ typedef struct { unsigned char srate [8] ; unsigned int fmt_id ; unsigned int fmt_flags ; unsigned int pkt_bytes ; unsigned int pkt_frames ; unsigned int channels_per_frame ; unsigned int bits_per_chan ; } DESC_CHUNK ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int caf_close (SF_PRIVATE *psf) ; static int caf_read_header (SF_PRIVATE *psf) ; static int caf_write_header (SF_PRIVATE *psf, int calc_length) ; /*------------------------------------------------------------------------------ ** Public function. */ int caf_open (SF_PRIVATE *psf) { int subformat, format, error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = caf_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; format = psf->sf.format & SF_FORMAT_TYPEMASK ; if (format != SF_FORMAT_CAF) return SFE_BAD_OPEN_FORMAT ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; if (psf->mode != SFM_RDWR || psf->filelength < 44) { psf->filelength = 0 ; psf->datalength = 0 ; psf->dataoffset = 0 ; psf->sf.frames = 0 ; } ; psf->str_flags = SF_STR_ALLOW_START ; /* ** By default, add the peak chunk to floating point files. Default behaviour ** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE). */ if (psf->mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) { if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; psf->peak_info->peak_loc = SF_PEAK_START ; } ; if ((error = caf_write_header (psf, SF_FALSE)) != 0) return error ; psf->write_header = caf_write_header ; } ; psf->container_close = caf_close ; /*psf->command = caf_command ;*/ switch (subformat) { case SF_FORMAT_PCM_S8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; /* Lite remove end */ default : return SFE_UNSUPPORTED_ENCODING ; } ; return error ; } /* caf_open */ static int caf_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) caf_write_header (psf, SF_TRUE) ; return 0 ; } /* caf_close */ /*------------------------------------------------------------------------------ */ static int decode_desc_chunk (SF_PRIVATE *psf, const DESC_CHUNK *desc) { int format ; psf->sf.channels = desc->channels_per_frame ; format = SF_FORMAT_CAF | (psf->endian == SF_ENDIAN_LITTLE ? SF_ENDIAN_LITTLE : 0) ; if (desc->fmt_id == lpcm_MARKER && desc->fmt_flags & 1) { /* Floating point data. */ if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame) { psf->bytewidth = 4 ; return format | SF_FORMAT_FLOAT ; } ; if (desc->bits_per_chan == 64 && desc->pkt_bytes == 8 * desc->channels_per_frame) { psf->bytewidth = 8 ; return format | SF_FORMAT_DOUBLE ; } ; } ; if ((desc->fmt_flags & 1) != 0) { psf_log_printf (psf, "**** Ooops, 'desc' chunk suggests float data, but other info invalid.\n") ; return 0 ; } ; if (desc->fmt_id == lpcm_MARKER) { /* Integer data. */ if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame) { psf->bytewidth = 4 ; return format | SF_FORMAT_PCM_32 ; } ; if (desc->bits_per_chan == 24 && desc->pkt_bytes == 3 * desc->channels_per_frame) { psf->bytewidth = 3 ; return format | SF_FORMAT_PCM_24 ; } ; if (desc->bits_per_chan == 16 && desc->pkt_bytes == 2 * desc->channels_per_frame) { psf->bytewidth = 2 ; return format | SF_FORMAT_PCM_16 ; } ; if (desc->bits_per_chan == 8 && desc->pkt_bytes == 1 * desc->channels_per_frame) { psf->bytewidth = 1 ; return format | SF_FORMAT_PCM_S8 ; } ; } ; if (desc->fmt_id == alaw_MARKER && desc->bits_per_chan == 8) { psf->bytewidth = 1 ; return format | SF_FORMAT_ALAW ; } ; if (desc->fmt_id == ulaw_MARKER && desc->bits_per_chan == 8) { psf->bytewidth = 1 ; return format | SF_FORMAT_ULAW ; } ; return 0 ; } /* decode_desc_chunk */ static int caf_read_header (SF_PRIVATE *psf) { DESC_CHUNK desc ; sf_count_t chunk_size ; double srate ; short version, flags ; int marker, k, have_data = 0 ; memset (&desc, 0, sizeof (desc)) ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ; psf_log_printf (psf, "%M\n Version : %d\n Flags : %x\n", marker, version, flags) ; if (marker != caff_MARKER) return SFE_CAF_NOT_CAF ; psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, psf->u.ucbuf, 8) ; srate = double64_be_read (psf->u.ucbuf) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%5.3f", srate) ; psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, psf->u.cbuf) ; if (marker != desc_MARKER) return SFE_CAF_NO_DESC ; if (chunk_size < SIGNED_SIZEOF (DESC_CHUNK)) { psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ; return SFE_MALFORMED_FILE ; } ; psf->sf.samplerate = lrint (srate) ; psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.pkt_frames, &desc.channels_per_frame, &desc.bits_per_chan) ; psf_log_printf (psf, " Format id : %M\n Format flags : %x\n Bytes / packet : %u\n" " Frames / packet : %u\n Channels / frame : %u\n Bits / channel : %u\n", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ; if (chunk_size > SIGNED_SIZEOF (DESC_CHUNK)) psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ; psf->sf.channels = desc.channels_per_frame ; while (have_data == 0 && psf_ftell (psf) < psf->filelength - SIGNED_SIZEOF (marker)) { psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ; switch (marker) { case peak_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) { psf_binheader_readf (psf, "j", (int) chunk_size) ; psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ; return SFE_CAF_BAD_PEAK ; } ; if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) return SFE_MALLOC_FAILED ; /* read in rest of PEAK chunk. */ psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ; psf_log_printf (psf, " edit count : %d\n", psf->peak_info->edit_number) ; psf_log_printf (psf, " Ch Position Value\n") ; for (k = 0 ; k < psf->sf.channels ; k++) { sf_count_t position ; float value ; psf_binheader_readf (psf, "Ef8", &value, &position) ; psf->peak_info->peaks [k].value = value ; psf->peak_info->peaks [k].position = position ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), " %2d %-12ld %g\n", k, (long) position, value) ; psf_log_printf (psf, psf->u.cbuf) ; } ; psf->peak_info->peak_loc = SF_PEAK_START ; break ; case free_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", (int) chunk_size) ; break ; case data_MARKER : psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; psf_binheader_readf (psf, "E4", &k) ; psf_log_printf (psf, " edit : %u\n", k) ; have_data = 1 ; break ; default : psf_log_printf (psf, " %M : %D (skipped)\n", marker, chunk_size) ; psf_binheader_readf (psf, "j", (int) chunk_size) ; break ; } ; } ; if (have_data == 0) { psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ; return SFE_MALFORMED_FILE ; } ; psf_log_printf (psf, "End\n") ; psf->dataoffset = psf_ftell (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0) return SFE_UNSUPPORTED_ENCODING ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / psf->bytewidth ; return 0 ; } /* caf_read_header */ /*------------------------------------------------------------------------------ */ static int caf_write_header (SF_PRIVATE *psf, int calc_length) { DESC_CHUNK desc ; sf_count_t current, free_len ; int subformat ; memset (&desc, 0, sizeof (desc)) ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; if (psf->bytewidth > 0) psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* 'caff' marker, version and flags. */ psf_binheader_writef (psf, "Em22", caff_MARKER, 1, 0) ; /* 'desc' marker and chunk size. */ psf_binheader_writef (psf, "Em8", desc_MARKER, (sf_count_t) (sizeof (DESC_CHUNK))) ; double64_be_write (1.0 * psf->sf.samplerate, psf->u.ucbuf) ; psf_binheader_writef (psf, "b", psf->u.ucbuf, make_size_t (8)) ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)) psf->endian = SF_ENDIAN_BIG ; else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_LITTLE || psf->endian == SF_ENDIAN_CPU)) psf->endian = SF_ENDIAN_LITTLE ; if (psf->endian == SF_ENDIAN_LITTLE) desc.fmt_flags = 2 ; else psf->endian = SF_ENDIAN_BIG ; /* initial section (same for all, it appears) */ switch (subformat) { case SF_FORMAT_PCM_S8 : desc.fmt_id = lpcm_MARKER ; psf->bytewidth = 1 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 8 ; break ; case SF_FORMAT_PCM_16 : desc.fmt_id = lpcm_MARKER ; psf->bytewidth = 2 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 16 ; break ; case SF_FORMAT_PCM_24 : psf->bytewidth = 3 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 24 ; desc.fmt_id = lpcm_MARKER ; break ; case SF_FORMAT_PCM_32 : desc.fmt_id = lpcm_MARKER ; psf->bytewidth = 4 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 32 ; break ; case SF_FORMAT_FLOAT : desc.fmt_id = lpcm_MARKER ; desc.fmt_flags |= 1 ; psf->bytewidth = 4 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 32 ; break ; case SF_FORMAT_DOUBLE : desc.fmt_id = lpcm_MARKER ; desc.fmt_flags |= 1 ; psf->bytewidth = 8 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 64 ; break ; case SF_FORMAT_ALAW : desc.fmt_id = alaw_MARKER ; psf->bytewidth = 1 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 8 ; break ; case SF_FORMAT_ULAW : desc.fmt_id = ulaw_MARKER ; psf->bytewidth = 1 ; desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; desc.pkt_frames = 1 ; desc.channels_per_frame = psf->sf.channels ; desc.bits_per_chan = 8 ; break ; default : return SFE_UNIMPLEMENTED ; } ; psf_binheader_writef (psf, "mE44444", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ; #if 0 if (psf->str_flags & SF_STR_LOCATE_START) caf_write_strings (psf, SF_STR_LOCATE_START) ; #endif if (psf->peak_info != NULL) { int k ; psf_binheader_writef (psf, "Em84", peak_MARKER, (sf_count_t) CAF_PEAK_CHUNK_SIZE (psf->sf.channels), psf->peak_info->edit_number) ; for (k = 0 ; k < psf->sf.channels ; k++) psf_binheader_writef (psf, "Ef8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ; } ; /* Add free chunk so that the actual audio data starts at a multiple 0x1000. */ free_len = 0x1000 - psf->headindex - 16 - 12 ; while (free_len < 0) free_len += 0x1000 ; psf_binheader_writef (psf, "Em8z", free_MARKER, free_len, (int) free_len) ; psf_binheader_writef (psf, "Em84", data_MARKER, psf->datalength, 0) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current < psf->dataoffset) psf_fseek (psf, psf->dataoffset, SEEK_SET) ; else if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* caf_write_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 65883e65-bd3c-4618-9241-d3c02fd630bd */ nyquist-3.05/nylsf/test_file_io.c0000644000175000000620000003436111466723256016152 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #if HAVE_UNISTD_H #include #endif #include #include #include "common.h" static void make_data (int *data, int len, int seed) ; static void file_open_test (const char *filename) ; static void file_read_write_test (const char *filename) ; static void file_truncate_test (const char *filename) ; static void test_open_or_die (SF_PRIVATE *psf, int linenum) ; static void test_close_or_die (SF_PRIVATE *psf, int linenum) ; static void test_write_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) ; static void test_read_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) ; static void test_equal_or_die (int *array1, int *array2, int len, int linenum) ; static void test_seek_or_die (SF_PRIVATE *psf, sf_count_t offset, int whence, sf_count_t new_position, int linenum) ; int main (void) { const char *filename = "file_io.dat" ; file_open_test (filename) ; file_read_write_test (filename) ; file_truncate_test (filename) ; unlink (filename) ; return 0 ; } /* main */ /*============================================================================== ** Actual test functions. */ static void file_open_test (const char *filename) { SF_PRIVATE sf_data, *psf ; int error ; printf (" %-24s : ", "file_open_test") ; fflush (stdout) ; memset (&sf_data, 0, sizeof (sf_data)) ; psf = &sf_data ; /* Ensure that the file doesn't already exist. */ if (unlink (filename) != 0 && errno != ENOENT) { printf ("\n\nLine %d: unlink failed (%d) : %s\n\n", __LINE__, errno, strerror (errno)) ; exit (1) ; } ; strncpy (psf->filename, filename, sizeof (psf->filename)) ; /* Test that open for read fails if the file doesn't exist. */ error = psf_fopen (psf, psf->filename, SFM_READ) ; if (error == 0) { printf ("\n\nLine %d: psf_fopen() should have failed.\n\n", __LINE__) ; exit (1) ; } ; /* Reset error to zero. */ psf->error = SFE_NO_ERROR ; /* Test file open in write mode. */ psf->mode = SFM_WRITE ; test_open_or_die (psf, __LINE__) ; test_close_or_die (psf, __LINE__) ; unlink (psf->filename) ; /* Test file open in read/write mode for a non-existant file. */ psf->mode = SFM_RDWR ; test_open_or_die (psf, __LINE__) ; test_close_or_die (psf, __LINE__) ; /* Test file open in read/write mode for an existing file. */ psf->mode = SFM_RDWR ; test_open_or_die (psf, __LINE__) ; test_close_or_die (psf, __LINE__) ; unlink (psf->filename) ; puts ("ok") ; } /* file_open_test */ static void file_read_write_test (const char *filename) { static int data_out [512] ; static int data_in [512] ; SF_PRIVATE sf_data, *psf ; sf_count_t retval ; /* ** Open a new file and write two blocks of data to the file. After each ** write, test that psf_get_filelen() returns the new length. */ printf (" %-24s : ", "file_write_test") ; fflush (stdout) ; memset (&sf_data, 0, sizeof (sf_data)) ; psf = &sf_data ; strncpy (psf->filename, filename, sizeof (psf->filename)) ; /* Test file open in write mode. */ psf->mode = SFM_WRITE ; test_open_or_die (psf, __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), sizeof (data_out), __LINE__) ; if ((retval = psf_get_filelen (psf)) != sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct (%ld should be %d).\n\n", __LINE__, (long) retval, (int) sizeof (data_out)) ; if (retval == 0) printf ("An fsync() may be necessary before fstat() in psf_get_filelen().\n\n") ; exit (1) ; } ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_write_or_die (psf, data_out, ARRAY_LEN (data_out), sizeof (data_out [0]), 2 * sizeof (data_out), __LINE__) ; if ((retval = psf_get_filelen (psf)) != 2 * sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %d)\n\n", __LINE__, (long) retval, 2 * ((int) sizeof (data_out))) ; exit (1) ; } ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; /* ** Now open the file in read mode, check the file length and check ** that the data is correct. */ printf (" %-24s : ", "file_read_test") ; fflush (stdout) ; /* Test file open in write mode. */ psf->mode = SFM_READ ; test_open_or_die (psf, __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_read_or_die (psf, data_in, sizeof (data_in [0]), ARRAY_LEN (data_in), 2 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; /* ** Open the file in read/write mode, seek around a bit and then seek to ** the end of the file and write another block of data (3rd block). Then ** go back and check that all three blocks are correct. */ printf (" %-24s : ", "file_seek_test") ; fflush (stdout) ; /* Test file open in read/write mode. */ psf->mode = SFM_RDWR ; test_open_or_die (psf, __LINE__) ; test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; test_seek_or_die (psf, 0, SEEK_END, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; test_seek_or_die (psf, -1 * SIGNED_SIZEOF (data_out), SEEK_CUR, (sf_count_t) sizeof (data_out), __LINE__) ; test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_CUR, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 3) ; test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), 3 * sizeof (data_out), __LINE__) ; test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_seek_or_die (psf, 2 * SIGNED_SIZEOF (data_out), SEEK_SET, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 3) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 3 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_SET, SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 2 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; /* ** Now test operations with a non-zero psf->fileoffset field. This field ** sets an artificial file start positions so that a seek to the start of ** the file will actually be a seek to the value given by psf->fileoffset. */ printf (" %-24s : ", "file_offset_test") ; fflush (stdout) ; /* Test file open in read/write mode. */ psf->mode = SFM_RDWR ; psf->fileoffset = sizeof (data_out [0]) * ARRAY_LEN (data_out) ; test_open_or_die (psf, __LINE__) ; if ((retval = psf_get_filelen (psf)) != 3 * sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %d)\n\n", __LINE__, (long) retval, 3 * ((int) sizeof (data_out))) ; exit (1) ; } ; test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_SET, SIGNED_SIZEOF (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 5) ; test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), 2 * sizeof (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; /* final test with psf->fileoffset == 0. */ psf->mode = SFM_RDWR ; psf->fileoffset = 0 ; test_open_or_die (psf, __LINE__) ; if ((retval = psf_get_filelen (psf)) != 3 * sizeof (data_out)) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %d)\n\n", __LINE__, (long) retval, 3 * ((int) sizeof (data_out))) ; exit (1) ; } ; make_data (data_out, ARRAY_LEN (data_out), 1) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 2) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 2 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; make_data (data_out, ARRAY_LEN (data_out), 5) ; test_read_or_die (psf, data_in, 1, sizeof (data_in), 3 * sizeof (data_in), __LINE__) ; test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; } /* file_read_write_test */ static void file_truncate_test (const char *filename) { SF_PRIVATE sf_data, *psf ; unsigned char buffer [256] ; int k ; /* ** Open a new file and write two blocks of data to the file. After each ** write, test that psf_get_filelen() returns the new length. */ printf (" %-24s : ", "file_truncate_test") ; fflush (stdout) ; memset (&sf_data, 0, sizeof (sf_data)) ; memset (buffer, 0xEE, sizeof (buffer)) ; psf = &sf_data ; strncpy (psf->filename, filename, sizeof (psf->filename)) ; /* ** Open the file write mode, write 0xEE data and then extend the file ** using truncate (the extended data should be 0x00). */ psf->mode = SFM_WRITE ; test_open_or_die (psf, __LINE__) ; test_write_or_die (psf, buffer, sizeof (buffer) / 2, 1, sizeof (buffer) / 2, __LINE__) ; psf_ftruncate (psf, sizeof (buffer)) ; test_close_or_die (psf, __LINE__) ; /* Open the file in read mode and check the data. */ psf->mode = SFM_READ ; test_open_or_die (psf, __LINE__) ; test_read_or_die (psf, buffer, sizeof (buffer), 1, sizeof (buffer), __LINE__) ; test_close_or_die (psf, __LINE__) ; for (k = 0 ; k < SIGNED_SIZEOF (buffer) / 2 ; k++) if (buffer [k] != 0xEE) { printf ("\n\nLine %d : buffer [%d] = %d (should be 0xEE)\n\n", __LINE__, k, buffer [k]) ; exit (1) ; } ; for (k = SIGNED_SIZEOF (buffer) / 2 ; k < SIGNED_SIZEOF (buffer) ; k++) if (buffer [k] != 0) { printf ("\n\nLine %d : buffer [%d] = %d (should be 0)\n\n", __LINE__, k, buffer [k]) ; exit (1) ; } ; /* Open the file in read/write and shorten the file using truncate. */ psf->mode = SFM_RDWR ; test_open_or_die (psf, __LINE__) ; psf_ftruncate (psf, sizeof (buffer) / 4) ; test_close_or_die (psf, __LINE__) ; /* Check the file length. */ psf->mode = SFM_READ ; test_open_or_die (psf, __LINE__) ; test_seek_or_die (psf, 0, SEEK_END, SIGNED_SIZEOF (buffer) / 4, __LINE__) ; test_close_or_die (psf, __LINE__) ; puts ("ok") ; } /* file_truncate_test */ /*============================================================================== ** Testing helper functions. */ static void test_open_or_die (SF_PRIVATE *psf, int linenum) { int error ; /* Test that open for read fails if the file doesn't exist. */ error = psf_fopen (psf, psf->filename, psf->mode) ; if (error) { printf ("\n\nLine %d: psf_fopen() failed : %s\n\n", linenum, strerror (errno)) ; exit (1) ; } ; } /* test_open_or_die */ static void test_close_or_die (SF_PRIVATE *psf, int linenum) { psf_fclose (psf) ; if (psf_file_valid (psf)) { printf ("\n\nLine %d: psf->filedes should not be valid.\n\n", linenum) ; exit (1) ; } ; } /* test_close_or_die */ static void test_write_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) { sf_count_t retval ; retval = psf_fwrite (data, bytes, items, psf) ; if (retval != items) { printf ("\n\nLine %d: psf_write() returned %ld (should be %ld)\n\n", linenum, (long) retval, (long) items) ; exit (1) ; } ; if ((retval = psf_ftell (psf)) != new_position) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %ld)\n\n", linenum, (long) retval, (long) new_position) ; exit (1) ; } ; return ; } /* test_write_or_die */ static void test_read_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) { sf_count_t retval ; retval = psf_fread (data, bytes, items, psf) ; if (retval != items) { printf ("\n\nLine %d: psf_write() returned %ld (should be %ld)\n\n", linenum, (long) retval, (long) items) ; exit (1) ; } ; if ((retval = psf_ftell (psf)) != new_position) { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %ld)\n\n", linenum, (long) retval, (long) new_position) ; exit (1) ; } ; return ; } /* test_write_or_die */ static void test_seek_or_die (SF_PRIVATE *psf, sf_count_t offset, int whence, sf_count_t new_position, int linenum) { sf_count_t retval ; retval = psf_fseek (psf, offset, whence) ; if (retval != new_position) { printf ("\n\nLine %d: psf_fseek() failed. New position is %ld (should be %ld).\n\n", linenum, (long) retval, (long) new_position) ; exit (1) ; } ; } /* test_seek_or_die */ static void test_equal_or_die (int *array1, int *array2, int len, int linenum) { int k ; for (k = 0 ; k < len ; k++) if (array1 [k] != array2 [k]) printf ("\n\nLine %d: error at index %d (%d != %d).\n\n", linenum, k, array1 [k], array2 [k]) ; return ; } /* test_equal_or_die */ static void make_data (int *data, int len, int seed) { int k ; srand (seed * 3333333 + 14756123) ; for (k = 0 ; k < len ; k++) data [k] = rand () ; } /* make_data */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 0a21fb93-78dd-4f72-8338-4bca9e77b8c8 */ nyquist-3.05/nylsf/GSM610/0002755000175000000620000000000011537433127014203 5ustar stevestaffnyquist-3.05/nylsf/GSM610/gsm610_priv.h0000644000175000000620000001717011512143043016421 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #ifndef PRIVATE_H #define PRIVATE_H /* Added by Erik de Castro Lopo */ #define USE_FLOAT_MUL #define FAST #define WAV49 #ifdef __cplusplus #error "This code is not designed to be compiled with a C++ compiler." #endif /* Added by Erik de Castro Lopo */ #if defined(_MSC_VER) && _MSC_VER >= 1500 // Visual C++ 2008 or beyond #define inline __inline #endif typedef short word; /* 16 bit signed int */ typedef int longword; /* 32 bit signed int */ typedef unsigned short uword; /* unsigned word */ typedef unsigned int ulongword; /* unsigned longword */ struct gsm_state { word dp0[ 280 ] ; word z1; /* preprocessing.c, Offset_com. */ longword L_z2; /* Offset_com. */ int mp; /* Preemphasis */ word u[8] ; /* short_term_aly_filter.c */ word LARpp[2][8] ; /* */ word j; /* */ word ltp_cut; /* long_term.c, LTP crosscorr. */ word nrp; /* 40 */ /* long_term.c, synthesis */ word v[9] ; /* short_term.c, synthesis */ word msr; /* decoder.c, Postprocessing */ char verbose; /* only used if !NDEBUG */ char fast; /* only used if FAST */ char wav_fmt; /* only used if WAV49 defined */ unsigned char frame_index; /* odd/even chaining */ unsigned char frame_chain; /* half-byte to carry forward */ /* Moved here from code.c where it was defined as static */ word e[50] ; } ; typedef struct gsm_state GSM_STATE ; #define MIN_WORD (-32767 - 1) #define MAX_WORD 32767 #define MIN_LONGWORD (-2147483647 - 1) #define MAX_LONGWORD 2147483647 /* Signed arithmetic shift right. */ static inline word SASR_W (word x, word by) { return (x >> by) ; } /* SASR */ static inline longword SASR_L (longword x, word by) { return (x >> by) ; } /* SASR */ /* * Prototypes from add.c */ word gsm_mult (word a, word b) ; longword gsm_L_mult (word a, word b) ; word gsm_mult_r (word a, word b) ; word gsm_div (word num, word denum) ; word gsm_add (word a, word b ) ; longword gsm_L_add (longword a, longword b ) ; word gsm_sub (word a, word b) ; longword gsm_L_sub (longword a, longword b) ; word gsm_abs (word a) ; word gsm_norm (longword a ) ; longword gsm_L_asl (longword a, int n) ; word gsm_asl (word a, int n) ; longword gsm_L_asr (longword a, int n) ; word gsm_asr (word a, int n) ; /* * Inlined functions from add.h */ static inline longword GSM_MULT_R (word a, word b) { return (((longword) (a)) * ((longword) (b)) + 16384) >> 15 ; } /* GSM_MULT_R */ static inline longword GSM_MULT (word a, word b) { return (((longword) (a)) * ((longword) (b))) >> 15 ; } /* GSM_MULT */ static inline longword GSM_L_MULT (word a, word b) { return ((longword) (a)) * ((longword) (b)) << 1 ; } /* GSM_L_MULT */ static inline longword GSM_L_ADD (longword a, longword b) { ulongword utmp ; if (a < 0 && b < 0) { utmp = (ulongword)-((a) + 1) + (ulongword)-((b) + 1) ; return (utmp >= (ulongword) MAX_LONGWORD) ? MIN_LONGWORD : -(longword)utmp-2 ; } ; if (a > 0 && b > 0) { utmp = (ulongword) a + (ulongword) b ; return (utmp >= (ulongword) MAX_LONGWORD) ? MAX_LONGWORD : utmp ; } ; return a + b ; } /* GSM_L_ADD */ static inline longword GSM_ADD (word a, word b) { longword ltmp ; ltmp = ((longword) a) + ((longword) b) ; if (ltmp >= MAX_WORD) return MAX_WORD ; if (ltmp <= MIN_WORD) return MIN_WORD ; return ltmp ; } /* GSM_ADD */ static inline longword GSM_SUB (word a, word b) { longword ltmp ; ltmp = ((longword) a) - ((longword) b) ; if (ltmp >= MAX_WORD) ltmp = MAX_WORD ; else if (ltmp <= MIN_WORD) ltmp = MIN_WORD ; return ltmp ; } /* GSM_SUB */ static inline word GSM_ABS (word a) { if (a > 0) return a ; if (a == MIN_WORD) return MAX_WORD ; return -a ; } /* GSM_ADD */ /* * More prototypes from implementations.. */ void Gsm_Coder ( struct gsm_state * S, word * s, /* [0..159] samples IN */ word * LARc, /* [0..7] LAR coefficients OUT */ word * Nc, /* [0..3] LTP lag OUT */ word * bc, /* [0..3] coded LTP gain OUT */ word * Mc, /* [0..3] RPE grid selection OUT */ word * xmaxc,/* [0..3] Coded maximum amplitude OUT */ word * xMc) ;/* [13*4] normalized RPE samples OUT */ void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */ struct gsm_state * S, word * d, /* [0..39] residual signal IN */ word * dp, /* [-120..-1] d' IN */ word * e, /* [0..40] OUT */ word * dpp, /* [0..40] OUT */ word * Nc, /* correlation lag OUT */ word * bc) ; /* gain factor OUT */ void Gsm_LPC_Analysis ( struct gsm_state * S, word * s, /* 0..159 signals IN/OUT */ word * LARc) ; /* 0..7 LARc's OUT */ void Gsm_Preprocess ( struct gsm_state * S, word * s, word * so) ; void Gsm_Encoding ( struct gsm_state * S, word * e, word * ep, word * xmaxc, word * Mc, word * xMc) ; void Gsm_Short_Term_Analysis_Filter ( struct gsm_state * S, word * LARc, /* coded log area ratio [0..7] IN */ word * d) ; /* st res. signal [0..159] IN/OUT */ void Gsm_Decoder ( struct gsm_state * S, word * LARcr, /* [0..7] IN */ word * Ncr, /* [0..3] IN */ word * bcr, /* [0..3] IN */ word * Mcr, /* [0..3] IN */ word * xmaxcr, /* [0..3] IN */ word * xMcr, /* [0..13*4] IN */ word * s) ; /* [0..159] OUT */ void Gsm_Decoding ( struct gsm_state * S, word xmaxcr, word Mcr, word * xMcr, /* [0..12] IN */ word * erp) ; /* [0..39] OUT */ void Gsm_Long_Term_Synthesis_Filtering ( struct gsm_state* S, word Ncr, word bcr, word * erp, /* [0..39] IN */ word * drp) ; /* [-120..-1] IN, [0..40] OUT */ void Gsm_RPE_Decoding ( /*-struct gsm_state *S,-*/ word xmaxcr, word Mcr, word * xMcr, /* [0..12], 3 bits IN */ word * erp) ; /* [0..39] OUT */ void Gsm_RPE_Encoding ( /*-struct gsm_state * S,-*/ word * e, /* -5..-1][0..39][40..44 IN/OUT */ word * xmaxc, /* OUT */ word * Mc, /* OUT */ word * xMc) ; /* [0..12] OUT */ void Gsm_Short_Term_Synthesis_Filter ( struct gsm_state * S, word * LARcr, /* log area ratios [0..7] IN */ word * drp, /* received d [0...39] IN */ word * s) ; /* signal s [0..159] OUT */ void Gsm_Update_of_reconstructed_short_time_residual_signal ( word * dpp, /* [0...39] IN */ word * ep, /* [0...39] IN */ word * dp) ; /* [-120...-1] IN/OUT */ /* * Tables from table.c */ #ifndef GSM_TABLE_C extern word gsm_A [8], gsm_B [8], gsm_MIC [8], gsm_MAC [8] ; extern word gsm_INVA [8] ; extern word gsm_DLB [4], gsm_QLB [4] ; extern word gsm_H [11] ; extern word gsm_NRFAC [8] ; extern word gsm_FAC [8] ; #endif /* GSM_TABLE_C */ /* * Debugging */ #ifdef NDEBUG # define gsm_debug_words(a, b, c, d) /* nil */ # define gsm_debug_longwords(a, b, c, d) /* nil */ # define gsm_debug_word(a, b) /* nil */ # define gsm_debug_longword(a, b) /* nil */ #else /* !NDEBUG => DEBUG */ void gsm_debug_words (char * name, int, int, word *) ; void gsm_debug_longwords (char * name, int, int, longword *) ; void gsm_debug_longword (char * name, longword) ; void gsm_debug_word (char * name, word) ; #endif /* !NDEBUG */ #endif /* PRIVATE_H */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 8bc5fdf2-e8c8-4686-9bd7-a30b512bef0c */ nyquist-3.05/nylsf/GSM610/add.c0000644000175000000620000001304311466723256015104 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ /* * See private.h for the more commonly used macro versions. */ #include #include #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" #define saturate(x) \ ((x) < MIN_WORD ? MIN_WORD : (x) > MAX_WORD ? MAX_WORD: (x)) word gsm_add ( word a, word b) { longword sum = (longword)a + (longword)b; return saturate(sum); } word gsm_sub ( word a, word b) { longword diff = (longword)a - (longword)b; return saturate(diff); } word gsm_mult ( word a, word b) { if (a == MIN_WORD && b == MIN_WORD) return MAX_WORD; return SASR_L( (longword)a * (longword)b, 15 ); } word gsm_mult_r ( word a, word b) { if (b == MIN_WORD && a == MIN_WORD) return MAX_WORD; else { longword prod = (longword)a * (longword)b + 16384; prod >>= 15; return prod & 0xFFFF; } } word gsm_abs (word a) { return a < 0 ? (a == MIN_WORD ? MAX_WORD : -a) : a; } longword gsm_L_mult (word a, word b) { assert( a != MIN_WORD || b != MIN_WORD ); return ((longword)a * (longword)b) << 1; } longword gsm_L_add ( longword a, longword b) { if (a < 0) { if (b >= 0) return a + b; else { ulongword A = (ulongword)-(a + 1) + (ulongword)-(b + 1); return A >= MAX_LONGWORD ? MIN_LONGWORD :-(longword)A-2; } } else if (b <= 0) return a + b; else { ulongword A = (ulongword)a + (ulongword)b; return A > MAX_LONGWORD ? MAX_LONGWORD : A; } } longword gsm_L_sub ( longword a, longword b) { if (a >= 0) { if (b >= 0) return a - b; else { /* a>=0, b<0 */ ulongword A = (ulongword)a + -(b + 1); return A >= MAX_LONGWORD ? MAX_LONGWORD : (A + 1); } } else if (b <= 0) return a - b; else { /* a<0, b>0 */ ulongword A = (ulongword)-(a + 1) + b; return A >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)A - 1; } } static unsigned char const bitoff[ 256 ] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; word gsm_norm (longword a ) /* * the number of left shifts needed to normalize the 32 bit * variable L_var1 for positive values on the interval * * with minimum of * minimum of 1073741824 (01000000000000000000000000000000) and * maximum of 2147483647 (01111111111111111111111111111111) * * * and for negative values on the interval with * minimum of -2147483648 (-10000000000000000000000000000000) and * maximum of -1073741824 ( -1000000000000000000000000000000). * * in order to normalize the result, the following * operation must be done: L_norm_var1 = L_var1 << norm( L_var1 ); * * (That's 'ffs', only from the left, not the right..) */ { assert(a != 0); if (a < 0) { if (a <= -1073741824) return 0; a = ~a; } return a & 0xffff0000 ? ( a & 0xff000000 ? -1 + bitoff[ 0xFF & (a >> 24) ] : 7 + bitoff[ 0xFF & (a >> 16) ] ) : ( a & 0xff00 ? 15 + bitoff[ 0xFF & (a >> 8) ] : 23 + bitoff[ 0xFF & a ] ); } longword gsm_L_asl (longword a, int n) { if (n >= 32) return 0; if (n <= -32) return -(a < 0); if (n < 0) return gsm_L_asr(a, -n); return a << n; } word gsm_asr (word a, int n) { if (n >= 16) return -(a < 0); if (n <= -16) return 0; if (n < 0) return a << -n; return SASR_W (a, (word) n); } word gsm_asl (word a, int n) { if (n >= 16) return 0; if (n <= -16) return -(a < 0); if (n < 0) return gsm_asr(a, -n); return a << n; } longword gsm_L_asr (longword a, int n) { if (n >= 32) return -(a < 0); if (n <= -32) return 0; if (n < 0) return a << -n; return SASR_L (a, (word) n); } /* ** word gsm_asr (word a, int n) ** { ** if (n >= 16) return -(a < 0); ** if (n <= -16) return 0; ** if (n < 0) return a << -n; ** ** # ifdef SASR_W ** return a >> n; ** # else ** if (a >= 0) return a >> n; ** else return -(word)( -(uword)a >> n ); ** # endif ** } ** */ /* * (From p. 46, end of section 4.2.5) * * NOTE: The following lines gives [sic] one correct implementation * of the div(num, denum) arithmetic operation. Compute div * which is the integer division of num by denum: with denum * >= num > 0 */ word gsm_div (word num, word denum) { longword L_num = num; longword L_denum = denum; word div = 0; int k = 15; /* The parameter num sometimes becomes zero. * Although this is explicitly guarded against in 4.2.5, * we assume that the result should then be zero as well. */ /* assert(num != 0); */ assert(num >= 0 && denum >= num); if (num == 0) return 0; while (k--) { div <<= 1; L_num <<= 1; if (L_num >= L_denum) { L_num -= L_denum; div++; } } return div; } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: a7398579-e2e1-4733-aa2d-4c6efc0c58ff */ nyquist-3.05/nylsf/GSM610/rpe.c0000644000175000000620000002551611466723256015152 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include #include #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" /* 4.2.13 .. 4.2.17 RPE ENCODING SECTION */ /* 4.2.13 */ static void Weighting_filter ( register word * e, /* signal [-5..0.39.44] IN */ word * x /* signal [0..39] OUT */ ) /* * The coefficients of the weighting filter are stored in a table * (see table 4.4). The following scaling is used: * * H[0..10] = integer( real_H[ 0..10] * 8192 ); */ { /* word wt[ 50 ]; */ register longword L_result; register int k /* , i */ ; /* Initialization of a temporary working array wt[0...49] */ /* for (k = 0; k <= 4; k++) wt[k] = 0; * for (k = 5; k <= 44; k++) wt[k] = *e++; * for (k = 45; k <= 49; k++) wt[k] = 0; * * (e[-5..-1] and e[40..44] are allocated by the caller, * are initially zero and are not written anywhere.) */ e -= 5; /* Compute the signal x[0..39] */ for (k = 0; k <= 39; k++) { L_result = 8192 >> 1; /* for (i = 0; i <= 10; i++) { * L_temp = GSM_L_MULT( wt[k+i], gsm_H[i] ); * L_result = GSM_L_ADD( L_result, L_temp ); * } */ #undef STEP #define STEP( i, H ) (e[ k + i ] * (longword)H) /* Every one of these multiplications is done twice -- * but I don't see an elegant way to optimize this. * Do you? */ #ifdef STUPID_COMPILER L_result += STEP( 0, -134 ) ; L_result += STEP( 1, -374 ) ; /* + STEP( 2, 0 ) */ L_result += STEP( 3, 2054 ) ; L_result += STEP( 4, 5741 ) ; L_result += STEP( 5, 8192 ) ; L_result += STEP( 6, 5741 ) ; L_result += STEP( 7, 2054 ) ; /* + STEP( 8, 0 ) */ L_result += STEP( 9, -374 ) ; L_result += STEP( 10, -134 ) ; #else L_result += STEP( 0, -134 ) + STEP( 1, -374 ) /* + STEP( 2, 0 ) */ + STEP( 3, 2054 ) + STEP( 4, 5741 ) + STEP( 5, 8192 ) + STEP( 6, 5741 ) + STEP( 7, 2054 ) /* + STEP( 8, 0 ) */ + STEP( 9, -374 ) + STEP(10, -134 ) ; #endif /* L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x2) *) * L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x4) *) * * x[k] = SASR( L_result, 16 ); */ /* 2 adds vs. >>16 => 14, minus one shift to compensate for * those we lost when replacing L_MULT by '*'. */ L_result = SASR_L( L_result, 13 ); x[k] = ( L_result < MIN_WORD ? MIN_WORD : (L_result > MAX_WORD ? MAX_WORD : L_result )); } } /* 4.2.14 */ static void RPE_grid_selection ( word * x, /* [0..39] IN */ word * xM, /* [0..12] OUT */ word * Mc_out /* OUT */ ) /* * The signal x[0..39] is used to select the RPE grid which is * represented by Mc. */ { /* register word temp1; */ register int /* m, */ i; register longword L_result, L_temp; longword EM; /* xxx should be L_EM? */ word Mc; longword L_common_0_3; EM = 0; Mc = 0; /* for (m = 0; m <= 3; m++) { * L_result = 0; * * * for (i = 0; i <= 12; i++) { * * temp1 = SASR_W( x[m + 3*i], 2 ); * * assert(temp1 != MIN_WORD); * * L_temp = GSM_L_MULT( temp1, temp1 ); * L_result = GSM_L_ADD( L_temp, L_result ); * } * * if (L_result > EM) { * Mc = m; * EM = L_result; * } * } */ #undef STEP #define STEP( m, i ) L_temp = SASR_W( x[m + 3 * i], 2 ); \ L_result += L_temp * L_temp; /* common part of 0 and 3 */ L_result = 0; STEP( 0, 1 ); STEP( 0, 2 ); STEP( 0, 3 ); STEP( 0, 4 ); STEP( 0, 5 ); STEP( 0, 6 ); STEP( 0, 7 ); STEP( 0, 8 ); STEP( 0, 9 ); STEP( 0, 10); STEP( 0, 11); STEP( 0, 12); L_common_0_3 = L_result; /* i = 0 */ STEP( 0, 0 ); L_result <<= 1; /* implicit in L_MULT */ EM = L_result; /* i = 1 */ L_result = 0; STEP( 1, 0 ); STEP( 1, 1 ); STEP( 1, 2 ); STEP( 1, 3 ); STEP( 1, 4 ); STEP( 1, 5 ); STEP( 1, 6 ); STEP( 1, 7 ); STEP( 1, 8 ); STEP( 1, 9 ); STEP( 1, 10); STEP( 1, 11); STEP( 1, 12); L_result <<= 1; if (L_result > EM) { Mc = 1; EM = L_result; } /* i = 2 */ L_result = 0; STEP( 2, 0 ); STEP( 2, 1 ); STEP( 2, 2 ); STEP( 2, 3 ); STEP( 2, 4 ); STEP( 2, 5 ); STEP( 2, 6 ); STEP( 2, 7 ); STEP( 2, 8 ); STEP( 2, 9 ); STEP( 2, 10); STEP( 2, 11); STEP( 2, 12); L_result <<= 1; if (L_result > EM) { Mc = 2; EM = L_result; } /* i = 3 */ L_result = L_common_0_3; STEP( 3, 12 ); L_result <<= 1; if (L_result > EM) { Mc = 3; EM = L_result; } /**/ /* Down-sampling by a factor 3 to get the selected xM[0..12] * RPE sequence. */ for (i = 0; i <= 12; i ++) xM[i] = x[Mc + 3*i]; *Mc_out = Mc; } /* 4.12.15 */ static void APCM_quantization_xmaxc_to_exp_mant ( word xmaxc, /* IN */ word * expon_out, /* OUT */ word * mant_out ) /* OUT */ { word expon, mant; /* Compute expononent and mantissa of the decoded version of xmaxc */ expon = 0; if (xmaxc > 15) expon = SASR_W(xmaxc, 3) - 1; mant = xmaxc - (expon << 3); if (mant == 0) { expon = -4; mant = 7; } else { while (mant <= 7) { mant = mant << 1 | 1; expon--; } mant -= 8; } assert( expon >= -4 && expon <= 6 ); assert( mant >= 0 && mant <= 7 ); *expon_out = expon; *mant_out = mant; } static void APCM_quantization ( word * xM, /* [0..12] IN */ word * xMc, /* [0..12] OUT */ word * mant_out, /* OUT */ word * expon_out, /* OUT */ word * xmaxc_out /* OUT */ ) { int i, itest; word xmax, xmaxc, temp, temp1, temp2; word expon, mant; /* Find the maximum absolute value xmax of xM[0..12]. */ xmax = 0; for (i = 0; i <= 12; i++) { temp = xM[i]; temp = GSM_ABS(temp); if (temp > xmax) xmax = temp; } /* Qantizing and coding of xmax to get xmaxc. */ expon = 0; temp = SASR_W( xmax, 9 ); itest = 0; for (i = 0; i <= 5; i++) { itest |= (temp <= 0); temp = SASR_W( temp, 1 ); assert(expon <= 5); if (itest == 0) expon++; /* expon = add (expon, 1) */ } assert(expon <= 6 && expon >= 0); temp = expon + 5; assert(temp <= 11 && temp >= 0); xmaxc = gsm_add( SASR_W(xmax, temp), (word) (expon << 3) ); /* Quantizing and coding of the xM[0..12] RPE sequence * to get the xMc[0..12] */ APCM_quantization_xmaxc_to_exp_mant( xmaxc, &expon, &mant ); /* This computation uses the fact that the decoded version of xmaxc * can be calculated by using the expononent and the mantissa part of * xmaxc (logarithmic table). * So, this method avoids any division and uses only a scaling * of the RPE samples by a function of the expononent. A direct * multiplication by the inverse of the mantissa (NRFAC[0..7] * found in table 4.5) gives the 3 bit coded version xMc[0..12] * of the RPE samples. */ /* Direct computation of xMc[0..12] using table 4.5 */ assert( expon <= 4096 && expon >= -4096); assert( mant >= 0 && mant <= 7 ); temp1 = 6 - expon; /* normalization by the expononent */ temp2 = gsm_NRFAC[ mant ]; /* inverse mantissa */ for (i = 0; i <= 12; i++) { assert(temp1 >= 0 && temp1 < 16); temp = xM[i] << temp1; temp = GSM_MULT( temp, temp2 ); temp = SASR_W(temp, 12); xMc[i] = temp + 4; /* see note below */ } /* NOTE: This equation is used to make all the xMc[i] positive. */ *mant_out = mant; *expon_out = expon; *xmaxc_out = xmaxc; } /* 4.2.16 */ static void APCM_inverse_quantization ( register word * xMc, /* [0..12] IN */ word mant, word expon, register word * xMp) /* [0..12] OUT */ /* * This part is for decoding the RPE sequence of coded xMc[0..12] * samples to obtain the xMp[0..12] array. Table 4.6 is used to get * the mantissa of xmaxc (FAC[0..7]). */ { int i; word temp, temp1, temp2, temp3; assert( mant >= 0 && mant <= 7 ); temp1 = gsm_FAC[ mant ]; /* see 4.2-15 for mant */ temp2 = gsm_sub( 6, expon ); /* see 4.2-15 for exp */ temp3 = gsm_asl( 1, gsm_sub( temp2, 1 )); for (i = 13; i--;) { assert( *xMc <= 7 && *xMc >= 0 ); /* 3 bit unsigned */ /* temp = gsm_sub( *xMc++ << 1, 7 ); */ temp = (*xMc++ << 1) - 7; /* restore sign */ assert( temp <= 7 && temp >= -7 ); /* 4 bit signed */ temp <<= 12; /* 16 bit signed */ temp = GSM_MULT_R( temp1, temp ); temp = GSM_ADD( temp, temp3 ); *xMp++ = gsm_asr( temp, temp2 ); } } /* 4.2.17 */ static void RPE_grid_positioning ( word Mc, /* grid position IN */ register word * xMp, /* [0..12] IN */ register word * ep /* [0..39] OUT */ ) /* * This procedure computes the reconstructed long term residual signal * ep[0..39] for the LTP analysis filter. The inputs are the Mc * which is the grid position selection and the xMp[0..12] decoded * RPE samples which are upsampled by a factor of 3 by inserting zero * values. */ { int i = 13; assert(0 <= Mc && Mc <= 3); switch (Mc) { case 3: *ep++ = 0; case 2: do { *ep++ = 0; case 1: *ep++ = 0; case 0: *ep++ = *xMp++; } while (--i); } while (++Mc < 4) *ep++ = 0; /* int i, k; for (k = 0; k <= 39; k++) ep[k] = 0; for (i = 0; i <= 12; i++) { ep[ Mc + (3*i) ] = xMp[i]; } */ } /* 4.2.18 */ /* This procedure adds the reconstructed long term residual signal * ep[0..39] to the estimated signal dpp[0..39] from the long term * analysis filter to compute the reconstructed short term residual * signal dp[-40..-1]; also the reconstructed short term residual * array dp[-120..-41] is updated. */ #if 0 /* Has been inlined in code.c */ void Gsm_Update_of_reconstructed_short_time_residual_signal ( word * dpp, /* [0...39] IN */ word * ep, /* [0...39] IN */ word * dp) /* [-120...-1] IN/OUT */ { int k; for (k = 0; k <= 79; k++) dp[ -120 + k ] = dp[ -80 + k ]; for (k = 0; k <= 39; k++) dp[ -40 + k ] = gsm_add( ep[k], dpp[k] ); } #endif /* Has been inlined in code.c */ void Gsm_RPE_Encoding ( /*-struct gsm_state * S,-*/ word * e, /* -5..-1][0..39][40..44 IN/OUT */ word * xmaxc, /* OUT */ word * Mc, /* OUT */ word * xMc) /* [0..12] OUT */ { word x[40]; word xM[13], xMp[13]; word mant, expon; Weighting_filter(e, x); RPE_grid_selection(x, xM, Mc); APCM_quantization( xM, xMc, &mant, &expon, xmaxc); APCM_inverse_quantization( xMc, mant, expon, xMp); RPE_grid_positioning( *Mc, xMp, e ); } void Gsm_RPE_Decoding ( /*-struct gsm_state * S,-*/ word xmaxcr, word Mcr, word * xMcr, /* [0..12], 3 bits IN */ word * erp /* [0..39] OUT */ ) { word expon, mant; word xMp[ 13 ]; APCM_quantization_xmaxc_to_exp_mant( xmaxcr, &expon, &mant ); APCM_inverse_quantization( xMcr, mant, expon, xMp ); RPE_grid_positioning( Mcr, xMp, erp ); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 82005b9e-1560-4e94-9ddb-00cb14867295 */ nyquist-3.05/nylsf/GSM610/lpc.c0000644000175000000620000001566411466723256015145 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include #include #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" /* * 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION */ /* 4.2.4 */ static void Autocorrelation ( word * s, /* [0..159] IN/OUT */ longword * L_ACF) /* [0..8] OUT */ /* * The goal is to compute the array L_ACF[k]. The signal s[i] must * be scaled in order to avoid an overflow situation. */ { register int k, i; word temp, smax, scalauto; #ifdef USE_FLOAT_MUL float float_s[160]; #endif /* Dynamic scaling of the array s[0..159] */ /* Search for the maximum. */ smax = 0; for (k = 0; k <= 159; k++) { temp = GSM_ABS( s[k] ); if (temp > smax) smax = temp; } /* Computation of the scaling factor. */ if (smax == 0) scalauto = 0; else { assert(smax > 0); scalauto = 4 - gsm_norm( (longword)smax << 16 );/* sub(4,..) */ } /* Scaling of the array s[0...159] */ if (scalauto > 0) { # ifdef USE_FLOAT_MUL # define SCALE(n) \ case n: for (k = 0; k <= 159; k++) \ float_s[k] = (float) \ (s[k] = GSM_MULT_R(s[k], 16384 >> (n-1)));\ break; # else # define SCALE(n) \ case n: for (k = 0; k <= 159; k++) \ s[k] = GSM_MULT_R( s[k], 16384 >> (n-1) );\ break; # endif /* USE_FLOAT_MUL */ switch (scalauto) { SCALE(1) SCALE(2) SCALE(3) SCALE(4) } # undef SCALE } # ifdef USE_FLOAT_MUL else for (k = 0; k <= 159; k++) float_s[k] = (float) s[k]; # endif /* Compute the L_ACF[..]. */ { # ifdef USE_FLOAT_MUL register float * sp = float_s; register float sl = *sp; # define STEP(k) L_ACF[k] += (longword)(sl * sp[ -(k) ]); # else word * sp = s; word sl = *sp; # define STEP(k) L_ACF[k] += ((longword)sl * sp[ -(k) ]); # endif # define NEXTI sl = *++sp for (k = 9; k--; L_ACF[k] = 0) ; STEP (0); NEXTI; STEP(0); STEP(1); NEXTI; STEP(0); STEP(1); STEP(2); NEXTI; STEP(0); STEP(1); STEP(2); STEP(3); NEXTI; STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); NEXTI; STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); NEXTI; STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); NEXTI; STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); STEP(7); for (i = 8; i <= 159; i++) { NEXTI; STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); STEP(7); STEP(8); } for (k = 9; k--; L_ACF[k] <<= 1) ; } /* Rescaling of the array s[0..159] */ if (scalauto > 0) { assert(scalauto <= 4); for (k = 160; k--; *s++ <<= scalauto) ; } } #if defined(USE_FLOAT_MUL) && defined(FAST) static void Fast_Autocorrelation ( word * s, /* [0..159] IN/OUT */ longword * L_ACF) /* [0..8] OUT */ { register int k, i; float f_L_ACF[9]; float scale; float s_f[160]; register float *sf = s_f; for (i = 0; i < 160; ++i) sf[i] = s[i]; for (k = 0; k <= 8; k++) { register float L_temp2 = 0; register float *sfl = sf - k; for (i = k; i < 160; ++i) L_temp2 += sf[i] * sfl[i]; f_L_ACF[k] = L_temp2; } scale = MAX_LONGWORD / f_L_ACF[0]; for (k = 0; k <= 8; k++) { L_ACF[k] = f_L_ACF[k] * scale; } } #endif /* defined (USE_FLOAT_MUL) && defined (FAST) */ /* 4.2.5 */ static void Reflection_coefficients ( longword * L_ACF, /* 0...8 IN */ register word * r /* 0...7 OUT */ ) { register int i, m, n; register word temp; word ACF[9]; /* 0..8 */ word P[ 9]; /* 0..8 */ word K[ 9]; /* 2..8 */ /* Schur recursion with 16 bits arithmetic. */ if (L_ACF[0] == 0) { for (i = 8; i--; *r++ = 0) ; return; } assert( L_ACF[0] != 0 ); temp = gsm_norm( L_ACF[0] ); assert(temp >= 0 && temp < 32); /* ? overflow ? */ for (i = 0; i <= 8; i++) ACF[i] = SASR_L( L_ACF[i] << temp, 16 ); /* Initialize array P[..] and K[..] for the recursion. */ for (i = 1; i <= 7; i++) K[ i ] = ACF[ i ]; for (i = 0; i <= 8; i++) P[ i ] = ACF[ i ]; /* Compute reflection coefficients */ for (n = 1; n <= 8; n++, r++) { temp = P[1]; temp = GSM_ABS(temp); if (P[0] < temp) { for (i = n; i <= 8; i++) *r++ = 0; return; } *r = gsm_div( temp, P[0] ); assert(*r >= 0); if (P[1] > 0) *r = -*r; /* r[n] = sub(0, r[n]) */ assert (*r != MIN_WORD); if (n == 8) return; /* Schur recursion */ temp = GSM_MULT_R( P[1], *r ); P[0] = GSM_ADD( P[0], temp ); for (m = 1; m <= 8 - n; m++) { temp = GSM_MULT_R( K[ m ], *r ); P[m] = GSM_ADD( P[ m+1 ], temp ); temp = GSM_MULT_R( P[ m+1 ], *r ); K[m] = GSM_ADD( K[ m ], temp ); } } } /* 4.2.6 */ static void Transformation_to_Log_Area_Ratios ( register word * r /* 0..7 IN/OUT */ ) /* * The following scaling for r[..] and LAR[..] has been used: * * r[..] = integer( real_r[..]*32768. ); -1 <= real_r < 1. * LAR[..] = integer( real_LAR[..] * 16384 ); * with -1.625 <= real_LAR <= 1.625 */ { register word temp; register int i; /* Computation of the LAR[0..7] from the r[0..7] */ for (i = 1; i <= 8; i++, r++) { temp = *r; temp = GSM_ABS(temp); assert(temp >= 0); if (temp < 22118) { temp >>= 1; } else if (temp < 31130) { assert( temp >= 11059 ); temp -= 11059; } else { assert( temp >= 26112 ); temp -= 26112; temp <<= 2; } *r = *r < 0 ? -temp : temp; assert( *r != MIN_WORD ); } } /* 4.2.7 */ static void Quantization_and_coding ( register word * LAR /* [0..7] IN/OUT */ ) { register word temp; /* This procedure needs four tables; the following equations * give the optimum scaling for the constants: * * A[0..7] = integer( real_A[0..7] * 1024 ) * B[0..7] = integer( real_B[0..7] * 512 ) * MAC[0..7] = maximum of the LARc[0..7] * MIC[0..7] = minimum of the LARc[0..7] */ # undef STEP # define STEP( A, B, MAC, MIC ) \ temp = GSM_MULT( A, *LAR ); \ temp = GSM_ADD( temp, B ); \ temp = GSM_ADD( temp, 256 ); \ temp = SASR_W( temp, 9 ); \ *LAR = temp>MAC ? MAC - MIC : (tempfast) Fast_Autocorrelation (s, L_ACF ); else #endif Autocorrelation (s, L_ACF ); Reflection_coefficients (L_ACF, LARc ); Transformation_to_Log_Area_Ratios (LARc); Quantization_and_coding (LARc); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 63146664-a002-4e1e-8b7b-f0cc8a6a53da */ nyquist-3.05/nylsf/GSM610/gsm_encode.c0000644000175000000620000002640011466723256016460 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" void gsm_encode (gsm s, gsm_signal * source, gsm_byte * c) { word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4]; Gsm_Coder(s, source, LARc, Nc, bc, Mc, xmaxc, xmc); /* variable size GSM_MAGIC 4 LARc[0] 6 LARc[1] 6 LARc[2] 5 LARc[3] 5 LARc[4] 4 LARc[5] 4 LARc[6] 3 LARc[7] 3 Nc[0] 7 bc[0] 2 Mc[0] 2 xmaxc[0] 6 xmc[0] 3 xmc[1] 3 xmc[2] 3 xmc[3] 3 xmc[4] 3 xmc[5] 3 xmc[6] 3 xmc[7] 3 xmc[8] 3 xmc[9] 3 xmc[10] 3 xmc[11] 3 xmc[12] 3 Nc[1] 7 bc[1] 2 Mc[1] 2 xmaxc[1] 6 xmc[13] 3 xmc[14] 3 xmc[15] 3 xmc[16] 3 xmc[17] 3 xmc[18] 3 xmc[19] 3 xmc[20] 3 xmc[21] 3 xmc[22] 3 xmc[23] 3 xmc[24] 3 xmc[25] 3 Nc[2] 7 bc[2] 2 Mc[2] 2 xmaxc[2] 6 xmc[26] 3 xmc[27] 3 xmc[28] 3 xmc[29] 3 xmc[30] 3 xmc[31] 3 xmc[32] 3 xmc[33] 3 xmc[34] 3 xmc[35] 3 xmc[36] 3 xmc[37] 3 xmc[38] 3 Nc[3] 7 bc[3] 2 Mc[3] 2 xmaxc[3] 6 xmc[39] 3 xmc[40] 3 xmc[41] 3 xmc[42] 3 xmc[43] 3 xmc[44] 3 xmc[45] 3 xmc[46] 3 xmc[47] 3 xmc[48] 3 xmc[49] 3 xmc[50] 3 xmc[51] 3 */ #ifdef WAV49 if (s->wav_fmt) { s->frame_index = !s->frame_index; if (s->frame_index) { uword sr; sr = 0; sr = sr >> 6 | LARc[0] << 10; sr = sr >> 6 | LARc[1] << 10; *c++ = sr >> 4; sr = sr >> 5 | LARc[2] << 11; *c++ = sr >> 7; sr = sr >> 5 | LARc[3] << 11; sr = sr >> 4 | LARc[4] << 12; *c++ = sr >> 6; sr = sr >> 4 | LARc[5] << 12; sr = sr >> 3 | LARc[6] << 13; *c++ = sr >> 7; sr = sr >> 3 | LARc[7] << 13; sr = sr >> 7 | Nc[0] << 9; *c++ = sr >> 5; sr = sr >> 2 | bc[0] << 14; sr = sr >> 2 | Mc[0] << 14; sr = sr >> 6 | xmaxc[0] << 10; *c++ = sr >> 3; sr = sr >> 3 | xmc[0] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[1] << 13; sr = sr >> 3 | xmc[2] << 13; sr = sr >> 3 | xmc[3] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[4] << 13; sr = sr >> 3 | xmc[5] << 13; sr = sr >> 3 | xmc[6] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[7] << 13; sr = sr >> 3 | xmc[8] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[9] << 13; sr = sr >> 3 | xmc[10] << 13; sr = sr >> 3 | xmc[11] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[12] << 13; sr = sr >> 7 | Nc[1] << 9; *c++ = sr >> 5; sr = sr >> 2 | bc[1] << 14; sr = sr >> 2 | Mc[1] << 14; sr = sr >> 6 | xmaxc[1] << 10; *c++ = sr >> 3; sr = sr >> 3 | xmc[13] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[14] << 13; sr = sr >> 3 | xmc[15] << 13; sr = sr >> 3 | xmc[16] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[17] << 13; sr = sr >> 3 | xmc[18] << 13; sr = sr >> 3 | xmc[19] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[20] << 13; sr = sr >> 3 | xmc[21] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[22] << 13; sr = sr >> 3 | xmc[23] << 13; sr = sr >> 3 | xmc[24] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[25] << 13; sr = sr >> 7 | Nc[2] << 9; *c++ = sr >> 5; sr = sr >> 2 | bc[2] << 14; sr = sr >> 2 | Mc[2] << 14; sr = sr >> 6 | xmaxc[2] << 10; *c++ = sr >> 3; sr = sr >> 3 | xmc[26] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[27] << 13; sr = sr >> 3 | xmc[28] << 13; sr = sr >> 3 | xmc[29] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[30] << 13; sr = sr >> 3 | xmc[31] << 13; sr = sr >> 3 | xmc[32] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[33] << 13; sr = sr >> 3 | xmc[34] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[35] << 13; sr = sr >> 3 | xmc[36] << 13; sr = sr >> 3 | xmc[37] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[38] << 13; sr = sr >> 7 | Nc[3] << 9; *c++ = sr >> 5; sr = sr >> 2 | bc[3] << 14; sr = sr >> 2 | Mc[3] << 14; sr = sr >> 6 | xmaxc[3] << 10; *c++ = sr >> 3; sr = sr >> 3 | xmc[39] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[40] << 13; sr = sr >> 3 | xmc[41] << 13; sr = sr >> 3 | xmc[42] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[43] << 13; sr = sr >> 3 | xmc[44] << 13; sr = sr >> 3 | xmc[45] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[46] << 13; sr = sr >> 3 | xmc[47] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[48] << 13; sr = sr >> 3 | xmc[49] << 13; sr = sr >> 3 | xmc[50] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[51] << 13; sr = sr >> 4; *c = sr >> 8; s->frame_chain = *c; } else { uword sr; sr = 0; sr = sr >> 4 | s->frame_chain << 12; sr = sr >> 6 | LARc[0] << 10; *c++ = sr >> 6; sr = sr >> 6 | LARc[1] << 10; *c++ = sr >> 8; sr = sr >> 5 | LARc[2] << 11; sr = sr >> 5 | LARc[3] << 11; *c++ = sr >> 6; sr = sr >> 4 | LARc[4] << 12; sr = sr >> 4 | LARc[5] << 12; *c++ = sr >> 6; sr = sr >> 3 | LARc[6] << 13; sr = sr >> 3 | LARc[7] << 13; *c++ = sr >> 8; sr = sr >> 7 | Nc[0] << 9; sr = sr >> 2 | bc[0] << 14; *c++ = sr >> 7; sr = sr >> 2 | Mc[0] << 14; sr = sr >> 6 | xmaxc[0] << 10; *c++ = sr >> 7; sr = sr >> 3 | xmc[0] << 13; sr = sr >> 3 | xmc[1] << 13; sr = sr >> 3 | xmc[2] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[3] << 13; sr = sr >> 3 | xmc[4] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[5] << 13; sr = sr >> 3 | xmc[6] << 13; sr = sr >> 3 | xmc[7] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[8] << 13; sr = sr >> 3 | xmc[9] << 13; sr = sr >> 3 | xmc[10] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[11] << 13; sr = sr >> 3 | xmc[12] << 13; *c++ = sr >> 8; sr = sr >> 7 | Nc[1] << 9; sr = sr >> 2 | bc[1] << 14; *c++ = sr >> 7; sr = sr >> 2 | Mc[1] << 14; sr = sr >> 6 | xmaxc[1] << 10; *c++ = sr >> 7; sr = sr >> 3 | xmc[13] << 13; sr = sr >> 3 | xmc[14] << 13; sr = sr >> 3 | xmc[15] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[16] << 13; sr = sr >> 3 | xmc[17] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[18] << 13; sr = sr >> 3 | xmc[19] << 13; sr = sr >> 3 | xmc[20] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[21] << 13; sr = sr >> 3 | xmc[22] << 13; sr = sr >> 3 | xmc[23] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[24] << 13; sr = sr >> 3 | xmc[25] << 13; *c++ = sr >> 8; sr = sr >> 7 | Nc[2] << 9; sr = sr >> 2 | bc[2] << 14; *c++ = sr >> 7; sr = sr >> 2 | Mc[2] << 14; sr = sr >> 6 | xmaxc[2] << 10; *c++ = sr >> 7; sr = sr >> 3 | xmc[26] << 13; sr = sr >> 3 | xmc[27] << 13; sr = sr >> 3 | xmc[28] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[29] << 13; sr = sr >> 3 | xmc[30] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[31] << 13; sr = sr >> 3 | xmc[32] << 13; sr = sr >> 3 | xmc[33] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[34] << 13; sr = sr >> 3 | xmc[35] << 13; sr = sr >> 3 | xmc[36] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[37] << 13; sr = sr >> 3 | xmc[38] << 13; *c++ = sr >> 8; sr = sr >> 7 | Nc[3] << 9; sr = sr >> 2 | bc[3] << 14; *c++ = sr >> 7; sr = sr >> 2 | Mc[3] << 14; sr = sr >> 6 | xmaxc[3] << 10; *c++ = sr >> 7; sr = sr >> 3 | xmc[39] << 13; sr = sr >> 3 | xmc[40] << 13; sr = sr >> 3 | xmc[41] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[42] << 13; sr = sr >> 3 | xmc[43] << 13; *c++ = sr >> 8; sr = sr >> 3 | xmc[44] << 13; sr = sr >> 3 | xmc[45] << 13; sr = sr >> 3 | xmc[46] << 13; *c++ = sr >> 7; sr = sr >> 3 | xmc[47] << 13; sr = sr >> 3 | xmc[48] << 13; sr = sr >> 3 | xmc[49] << 13; *c++ = sr >> 6; sr = sr >> 3 | xmc[50] << 13; sr = sr >> 3 | xmc[51] << 13; *c++ = sr >> 8; } } else #endif /* WAV49 */ { *c++ = ((GSM_MAGIC & 0xF) << 4) /* 1 */ | ((LARc[0] >> 2) & 0xF); *c++ = ((LARc[0] & 0x3) << 6) | (LARc[1] & 0x3F); *c++ = ((LARc[2] & 0x1F) << 3) | ((LARc[3] >> 2) & 0x7); *c++ = ((LARc[3] & 0x3) << 6) | ((LARc[4] & 0xF) << 2) | ((LARc[5] >> 2) & 0x3); *c++ = ((LARc[5] & 0x3) << 6) | ((LARc[6] & 0x7) << 3) | (LARc[7] & 0x7); *c++ = ((Nc[0] & 0x7F) << 1) | ((bc[0] >> 1) & 0x1); *c++ = ((bc[0] & 0x1) << 7) | ((Mc[0] & 0x3) << 5) | ((xmaxc[0] >> 1) & 0x1F); *c++ = ((xmaxc[0] & 0x1) << 7) | ((xmc[0] & 0x7) << 4) | ((xmc[1] & 0x7) << 1) | ((xmc[2] >> 2) & 0x1); *c++ = ((xmc[2] & 0x3) << 6) | ((xmc[3] & 0x7) << 3) | (xmc[4] & 0x7); *c++ = ((xmc[5] & 0x7) << 5) /* 10 */ | ((xmc[6] & 0x7) << 2) | ((xmc[7] >> 1) & 0x3); *c++ = ((xmc[7] & 0x1) << 7) | ((xmc[8] & 0x7) << 4) | ((xmc[9] & 0x7) << 1) | ((xmc[10] >> 2) & 0x1); *c++ = ((xmc[10] & 0x3) << 6) | ((xmc[11] & 0x7) << 3) | (xmc[12] & 0x7); *c++ = ((Nc[1] & 0x7F) << 1) | ((bc[1] >> 1) & 0x1); *c++ = ((bc[1] & 0x1) << 7) | ((Mc[1] & 0x3) << 5) | ((xmaxc[1] >> 1) & 0x1F); *c++ = ((xmaxc[1] & 0x1) << 7) | ((xmc[13] & 0x7) << 4) | ((xmc[14] & 0x7) << 1) | ((xmc[15] >> 2) & 0x1); *c++ = ((xmc[15] & 0x3) << 6) | ((xmc[16] & 0x7) << 3) | (xmc[17] & 0x7); *c++ = ((xmc[18] & 0x7) << 5) | ((xmc[19] & 0x7) << 2) | ((xmc[20] >> 1) & 0x3); *c++ = ((xmc[20] & 0x1) << 7) | ((xmc[21] & 0x7) << 4) | ((xmc[22] & 0x7) << 1) | ((xmc[23] >> 2) & 0x1); *c++ = ((xmc[23] & 0x3) << 6) | ((xmc[24] & 0x7) << 3) | (xmc[25] & 0x7); *c++ = ((Nc[2] & 0x7F) << 1) /* 20 */ | ((bc[2] >> 1) & 0x1); *c++ = ((bc[2] & 0x1) << 7) | ((Mc[2] & 0x3) << 5) | ((xmaxc[2] >> 1) & 0x1F); *c++ = ((xmaxc[2] & 0x1) << 7) | ((xmc[26] & 0x7) << 4) | ((xmc[27] & 0x7) << 1) | ((xmc[28] >> 2) & 0x1); *c++ = ((xmc[28] & 0x3) << 6) | ((xmc[29] & 0x7) << 3) | (xmc[30] & 0x7); *c++ = ((xmc[31] & 0x7) << 5) | ((xmc[32] & 0x7) << 2) | ((xmc[33] >> 1) & 0x3); *c++ = ((xmc[33] & 0x1) << 7) | ((xmc[34] & 0x7) << 4) | ((xmc[35] & 0x7) << 1) | ((xmc[36] >> 2) & 0x1); *c++ = ((xmc[36] & 0x3) << 6) | ((xmc[37] & 0x7) << 3) | (xmc[38] & 0x7); *c++ = ((Nc[3] & 0x7F) << 1) | ((bc[3] >> 1) & 0x1); *c++ = ((bc[3] & 0x1) << 7) | ((Mc[3] & 0x3) << 5) | ((xmaxc[3] >> 1) & 0x1F); *c++ = ((xmaxc[3] & 0x1) << 7) | ((xmc[39] & 0x7) << 4) | ((xmc[40] & 0x7) << 1) | ((xmc[41] >> 2) & 0x1); *c++ = ((xmc[41] & 0x3) << 6) /* 30 */ | ((xmc[42] & 0x7) << 3) | (xmc[43] & 0x7); *c++ = ((xmc[44] & 0x7) << 5) | ((xmc[45] & 0x7) << 2) | ((xmc[46] >> 1) & 0x3); *c++ = ((xmc[46] & 0x1) << 7) | ((xmc[47] & 0x7) << 4) | ((xmc[48] & 0x7) << 1) | ((xmc[49] >> 2) & 0x1); *c++ = ((xmc[49] & 0x3) << 6) | ((xmc[50] & 0x7) << 3) | (xmc[51] & 0x7); } } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: cfe9c43d-d97c-4216-b5e5-ccd6a25b582b */ nyquist-3.05/nylsf/GSM610/code.c0000644000175000000620000000475311466723256015276 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include #include #include "config.h" #include "gsm610_priv.h" #include "gsm.h" /* * 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER */ void Gsm_Coder ( struct gsm_state * State, word * s, /* [0..159] samples IN */ /* * The RPE-LTD coder works on a frame by frame basis. The length of * the frame is equal to 160 samples. Some computations are done * once per frame to produce at the output of the coder the * LARc[1..8] parameters which are the coded LAR coefficients and * also to realize the inverse filtering operation for the entire * frame (160 samples of signal d[0..159]). These parts produce at * the output of the coder: */ word * LARc, /* [0..7] LAR coefficients OUT */ /* * Procedure 4.2.11 to 4.2.18 are to be executed four times per * frame. That means once for each sub-segment RPE-LTP analysis of * 40 samples. These parts produce at the output of the coder: */ word * Nc, /* [0..3] LTP lag OUT */ word * bc, /* [0..3] coded LTP gain OUT */ word * Mc, /* [0..3] RPE grid selection OUT */ word * xmaxc,/* [0..3] Coded maximum amplitude OUT */ word * xMc /* [13*4] normalized RPE samples OUT */ ) { int k; word * dp = State->dp0 + 120; /* [ -120...-1 ] */ word * dpp = dp; /* [ 0...39 ] */ word so[160]; Gsm_Preprocess (State, s, so); Gsm_LPC_Analysis (State, so, LARc); Gsm_Short_Term_Analysis_Filter (State, LARc, so); for (k = 0; k <= 3; k++, xMc += 13) { Gsm_Long_Term_Predictor ( State, so+k*40, /* d [0..39] IN */ dp, /* dp [-120..-1] IN */ State->e + 5, /* e [0..39] OUT */ dpp, /* dpp [0..39] OUT */ Nc++, bc++); Gsm_RPE_Encoding ( /*-S,-*/ State->e + 5, /* e ][0..39][ IN/OUT */ xmaxc++, Mc++, xMc ); /* * Gsm_Update_of_reconstructed_short_time_residual_signal * ( dpp, e + 5, dp ); */ { register int i; for (i = 0; i <= 39; i++) dp[ i ] = GSM_ADD( State->e[5 + i], dpp[i] ); } dp += 40; dpp += 40; } (void)memcpy( (char *)State->dp0, (char *)(State->dp0 + 160), 120 * sizeof(*State->dp0) ); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: ae8ef1b2-5a1e-4263-94cd-42b15dca81a3 */ nyquist-3.05/nylsf/GSM610/long_term.c0000644000175000000620000005564311466723256016356 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include "config.h" // RBD #include #include #include "gsm610_priv.h" #include "gsm.h" /* * 4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION */ /* * This module computes the LTP gain (bc) and the LTP lag (Nc) * for the long term analysis filter. This is done by calculating a * maximum of the cross-correlation function between the current * sub-segment short term residual signal d[0..39] (output of * the short term analysis filter; for simplification the index * of this array begins at 0 and ends at 39 for each sub-segment of the * RPE-LTP analysis) and the previous reconstructed short term * residual signal dp[ -120 .. -1 ]. A dynamic scaling must be * performed to avoid overflow. */ /* The next procedure exists in six versions. First two integer * version (if USE_FLOAT_MUL is not defined); then four floating * point versions, twice with proper scaling (USE_FLOAT_MUL defined), * once without (USE_FLOAT_MUL and FAST defined, and fast run-time * option used). Every pair has first a Cut version (see the -C * option to toast or the LTP_CUT option to gsm_option()), then the * uncut one. (For a detailed explanation of why this is altogether * a bad idea, see Henry Spencer and Geoff Collyer, ``#ifdef Considered * Harmful''.) */ #ifndef USE_FLOAT_MUL #ifdef LTP_CUT static void Cut_Calculation_of_the_LTP_parameters ( struct gsm_state * st, register word * d, /* [0..39] IN */ register word * dp, /* [-120..-1] IN */ word * bc_out, /* OUT */ word * Nc_out /* OUT */ ) { register int k, lambda; word Nc, bc; word wt[40]; longword L_result; longword L_max, L_power; word R, S, dmax, scal, best_k; word ltp_cut; register word temp, wt_k; /* Search of the optimum scaling of d[0..39]. */ dmax = 0; for (k = 0; k <= 39; k++) { temp = d[k]; temp = GSM_ABS( temp ); if (temp > dmax) { dmax = temp; best_k = k; } } temp = 0; if (dmax == 0) scal = 0; else { assert(dmax > 0); temp = gsm_norm( (longword)dmax << 16 ); } if (temp > 6) scal = 0; else scal = 6 - temp; assert(scal >= 0); /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ wt_k = SASR_W(d[best_k], scal); for (lambda = 40; lambda <= 120; lambda++) { L_result = (longword)wt_k * dp[best_k - lambda]; if (L_result > L_max) { Nc = lambda; L_max = L_result; } } *Nc_out = Nc; L_max <<= 1; /* Rescaling of L_max */ assert(scal <= 100 && scal >= -100); L_max = L_max >> (6 - scal); /* sub(6, scal) */ assert( Nc <= 120 && Nc >= 40); /* Compute the power of the reconstructed short term residual * signal dp[..] */ L_power = 0; for (k = 0; k <= 39; k++) { register longword L_temp; L_temp = SASR_W( dp[k - Nc], 3 ); L_power += L_temp * L_temp; } L_power <<= 1; /* from L_MULT */ /* Normalization of L_max and L_power */ if (L_max <= 0) { *bc_out = 0; return; } if (L_max >= L_power) { *bc_out = 3; return; } temp = gsm_norm( L_power ); R = SASR( L_max << temp, 16 ); S = SASR( L_power << temp, 16 ); /* Coding of the LTP gain */ /* Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; *bc_out = bc; } #endif /* LTP_CUT */ static void Calculation_of_the_LTP_parameters ( register word * d, /* [0..39] IN */ register word * dp, /* [-120..-1] IN */ word * bc_out, /* OUT */ word * Nc_out /* OUT */ ) { register int k, lambda; word Nc, bc; word wt[40]; longword L_max, L_power; word R, S, dmax, scal; register word temp; /* Search of the optimum scaling of d[0..39]. */ dmax = 0; for (k = 0; k <= 39; k++) { temp = d[k]; temp = GSM_ABS( temp ); if (temp > dmax) dmax = temp; } temp = 0; if (dmax == 0) scal = 0; else { assert(dmax > 0); temp = gsm_norm( (longword)dmax << 16 ); } if (temp > 6) scal = 0; else scal = 6 - temp; assert(scal >= 0); /* Initialization of a working array wt */ for (k = 0; k <= 39; k++) wt[k] = SASR_W( d[k], scal ); /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ for (lambda = 40; lambda <= 120; lambda++) { # undef STEP # define STEP(k) (longword)wt[k] * dp[k - lambda] register longword L_result; L_result = STEP(0) ; L_result += STEP(1) ; L_result += STEP(2) ; L_result += STEP(3) ; L_result += STEP(4) ; L_result += STEP(5) ; L_result += STEP(6) ; L_result += STEP(7) ; L_result += STEP(8) ; L_result += STEP(9) ; L_result += STEP(10) ; L_result += STEP(11) ; L_result += STEP(12) ; L_result += STEP(13) ; L_result += STEP(14) ; L_result += STEP(15) ; L_result += STEP(16) ; L_result += STEP(17) ; L_result += STEP(18) ; L_result += STEP(19) ; L_result += STEP(20) ; L_result += STEP(21) ; L_result += STEP(22) ; L_result += STEP(23) ; L_result += STEP(24) ; L_result += STEP(25) ; L_result += STEP(26) ; L_result += STEP(27) ; L_result += STEP(28) ; L_result += STEP(29) ; L_result += STEP(30) ; L_result += STEP(31) ; L_result += STEP(32) ; L_result += STEP(33) ; L_result += STEP(34) ; L_result += STEP(35) ; L_result += STEP(36) ; L_result += STEP(37) ; L_result += STEP(38) ; L_result += STEP(39) ; if (L_result > L_max) { Nc = lambda; L_max = L_result; } } *Nc_out = Nc; L_max <<= 1; /* Rescaling of L_max */ assert(scal <= 100 && scal >= -100); L_max = L_max >> (6 - scal); /* sub(6, scal) */ assert( Nc <= 120 && Nc >= 40); /* Compute the power of the reconstructed short term residual * signal dp[..] */ L_power = 0; for (k = 0; k <= 39; k++) { register longword L_temp; L_temp = SASR_W( dp[k - Nc], 3 ); L_power += L_temp * L_temp; } L_power <<= 1; /* from L_MULT */ /* Normalization of L_max and L_power */ if (L_max <= 0) { *bc_out = 0; return; } if (L_max >= L_power) { *bc_out = 3; return; } temp = gsm_norm( L_power ); R = SASR_L( L_max << temp, 16 ); S = SASR_L( L_power << temp, 16 ); /* Coding of the LTP gain */ /* Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; *bc_out = bc; } #else /* USE_FLOAT_MUL */ #ifdef LTP_CUT static void Cut_Calculation_of_the_LTP_parameters ( struct gsm_state * st, /* IN */ register word * d, /* [0..39] IN */ register word * dp, /* [-120..-1] IN */ word * bc_out, /* OUT */ word * Nc_out /* OUT */ ) { register int k, lambda; word Nc, bc; word ltp_cut; float wt_float[40]; float dp_float_base[120], * dp_float = dp_float_base + 120; longword L_max, L_power; word R, S, dmax, scal; register word temp; /* Search of the optimum scaling of d[0..39]. */ dmax = 0; for (k = 0; k <= 39; k++) { temp = d[k]; temp = GSM_ABS( temp ); if (temp > dmax) dmax = temp; } temp = 0; if (dmax == 0) scal = 0; else { assert(dmax > 0); temp = gsm_norm( (longword)dmax << 16 ); } if (temp > 6) scal = 0; else scal = 6 - temp; assert(scal >= 0); ltp_cut = (longword)SASR_W(dmax, scal) * st->ltp_cut / 100; /* Initialization of a working array wt */ for (k = 0; k < 40; k++) { register word w = SASR_W( d[k], scal ); if (w < 0 ? w > -ltp_cut : w < ltp_cut) { wt_float[k] = 0.0; } else { wt_float[k] = w; } } for (k = -120; k < 0; k++) dp_float[k] = dp[k]; /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ for (lambda = 40; lambda <= 120; lambda += 9) { /* Calculate L_result for l = lambda .. lambda + 9. */ register float *lp = dp_float - lambda; register float W; register float a = lp[-8], b = lp[-7], c = lp[-6], d = lp[-5], e = lp[-4], f = lp[-3], g = lp[-2], h = lp[-1]; register float E; register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, S5 = 0, S6 = 0, S7 = 0, S8 = 0; # undef STEP # define STEP(K, a, b, c, d, e, f, g, h) \ if ((W = wt_float[K]) != 0.0) { \ E = W * a; S8 += E; \ E = W * b; S7 += E; \ E = W * c; S6 += E; \ E = W * d; S5 += E; \ E = W * e; S4 += E; \ E = W * f; S3 += E; \ E = W * g; S2 += E; \ E = W * h; S1 += E; \ a = lp[K]; \ E = W * a; S0 += E; } else (a = lp[K]) # define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h) # define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a) # define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b) # define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c) # define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d) # define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e) # define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f) # define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g) STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3); STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7); STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11); STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15); STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19); STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23); STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27); STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31); STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35); STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39); if (S0 > L_max) { L_max = S0; Nc = lambda; } if (S1 > L_max) { L_max = S1; Nc = lambda + 1; } if (S2 > L_max) { L_max = S2; Nc = lambda + 2; } if (S3 > L_max) { L_max = S3; Nc = lambda + 3; } if (S4 > L_max) { L_max = S4; Nc = lambda + 4; } if (S5 > L_max) { L_max = S5; Nc = lambda + 5; } if (S6 > L_max) { L_max = S6; Nc = lambda + 6; } if (S7 > L_max) { L_max = S7; Nc = lambda + 7; } if (S8 > L_max) { L_max = S8; Nc = lambda + 8; } } *Nc_out = Nc; L_max <<= 1; /* Rescaling of L_max */ assert(scal <= 100 && scal >= -100); L_max = L_max >> (6 - scal); /* sub(6, scal) */ assert( Nc <= 120 && Nc >= 40); /* Compute the power of the reconstructed short term residual * signal dp[..] */ L_power = 0; for (k = 0; k <= 39; k++) { register longword L_temp; L_temp = SASR_W( dp[k - Nc], 3 ); L_power += L_temp * L_temp; } L_power <<= 1; /* from L_MULT */ /* Normalization of L_max and L_power */ if (L_max <= 0) { *bc_out = 0; return; } if (L_max >= L_power) { *bc_out = 3; return; } temp = gsm_norm( L_power ); R = SASR( L_max << temp, 16 ); S = SASR( L_power << temp, 16 ); /* Coding of the LTP gain */ /* Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; *bc_out = bc; } #endif /* LTP_CUT */ static void Calculation_of_the_LTP_parameters ( register word * din, /* [0..39] IN */ register word * dp, /* [-120..-1] IN */ word * bc_out, /* OUT */ word * Nc_out /* OUT */ ) { register int k, lambda; word Nc, bc; float wt_float[40]; float dp_float_base[120], * dp_float = dp_float_base + 120; longword L_max, L_power; word R, S, dmax, scal; register word temp; /* Search of the optimum scaling of d[0..39]. */ dmax = 0; for (k = 0; k <= 39; k++) { temp = din [k] ; temp = GSM_ABS (temp) ; if (temp > dmax) dmax = temp; } temp = 0; if (dmax == 0) scal = 0; else { assert(dmax > 0); temp = gsm_norm( (longword)dmax << 16 ); } if (temp > 6) scal = 0; else scal = 6 - temp; assert(scal >= 0); /* Initialization of a working array wt */ for (k = 0; k < 40; k++) wt_float[k] = SASR_W (din [k], scal) ; for (k = -120; k < 0; k++) dp_float[k] = dp[k]; /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ for (lambda = 40; lambda <= 120; lambda += 9) { /* Calculate L_result for l = lambda .. lambda + 9. */ register float *lp = dp_float - lambda; register float W; register float a = lp[-8], b = lp[-7], c = lp[-6], d = lp[-5], e = lp[-4], f = lp[-3], g = lp[-2], h = lp[-1]; register float E; register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, S5 = 0, S6 = 0, S7 = 0, S8 = 0; # undef STEP # define STEP(K, a, b, c, d, e, f, g, h) \ W = wt_float[K]; \ E = W * a; S8 += E; \ E = W * b; S7 += E; \ E = W * c; S6 += E; \ E = W * d; S5 += E; \ E = W * e; S4 += E; \ E = W * f; S3 += E; \ E = W * g; S2 += E; \ E = W * h; S1 += E; \ a = lp[K]; \ E = W * a; S0 += E # define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h) # define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a) # define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b) # define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c) # define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d) # define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e) # define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f) # define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g) STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3); STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7); STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11); STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15); STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19); STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23); STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27); STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31); STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35); STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39); if (S0 > L_max) { L_max = S0; Nc = lambda; } if (S1 > L_max) { L_max = S1; Nc = lambda + 1; } if (S2 > L_max) { L_max = S2; Nc = lambda + 2; } if (S3 > L_max) { L_max = S3; Nc = lambda + 3; } if (S4 > L_max) { L_max = S4; Nc = lambda + 4; } if (S5 > L_max) { L_max = S5; Nc = lambda + 5; } if (S6 > L_max) { L_max = S6; Nc = lambda + 6; } if (S7 > L_max) { L_max = S7; Nc = lambda + 7; } if (S8 > L_max) { L_max = S8; Nc = lambda + 8; } } *Nc_out = Nc; L_max <<= 1; /* Rescaling of L_max */ assert(scal <= 100 && scal >= -100); L_max = L_max >> (6 - scal); /* sub(6, scal) */ assert( Nc <= 120 && Nc >= 40); /* Compute the power of the reconstructed short term residual * signal dp[..] */ L_power = 0; for (k = 0; k <= 39; k++) { register longword L_temp; L_temp = SASR_W( dp[k - Nc], 3 ); L_power += L_temp * L_temp; } L_power <<= 1; /* from L_MULT */ /* Normalization of L_max and L_power */ if (L_max <= 0) { *bc_out = 0; return; } if (L_max >= L_power) { *bc_out = 3; return; } temp = gsm_norm( L_power ); R = SASR_L ( L_max << temp, 16 ); S = SASR_L ( L_power << temp, 16 ); /* Coding of the LTP gain */ /* Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break; *bc_out = bc; } #ifdef FAST #ifdef LTP_CUT static void Cut_Fast_Calculation_of_the_LTP_parameters ( struct gsm_state * st, /* IN */ register word * d, /* [0..39] IN */ register word * dp, /* [-120..-1] IN */ word * bc_out, /* OUT */ word * Nc_out /* OUT */ ) { register int k, lambda; register float wt_float; word Nc, bc; word wt_max, best_k, ltp_cut; float dp_float_base[120], * dp_float = dp_float_base + 120; register float L_result, L_max, L_power; wt_max = 0; for (k = 0; k < 40; ++k) { if ( d[k] > wt_max) wt_max = d[best_k = k]; else if (-d[k] > wt_max) wt_max = -d[best_k = k]; } assert(wt_max >= 0); wt_float = (float)wt_max; for (k = -120; k < 0; ++k) dp_float[k] = (float)dp[k]; /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ for (lambda = 40; lambda <= 120; lambda++) { L_result = wt_float * dp_float[best_k - lambda]; if (L_result > L_max) { Nc = lambda; L_max = L_result; } } *Nc_out = Nc; if (L_max <= 0.) { *bc_out = 0; return; } /* Compute the power of the reconstructed short term residual * signal dp[..] */ dp_float -= Nc; L_power = 0; for (k = 0; k < 40; ++k) { register float f = dp_float[k]; L_power += f * f; } if (L_max >= L_power) { *bc_out = 3; return; } /* Coding of the LTP gain * Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ lambda = L_max / L_power * 32768.; for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break; *bc_out = bc; } #endif /* LTP_CUT */ static void Fast_Calculation_of_the_LTP_parameters ( register word * din, /* [0..39] IN */ register word * dp, /* [-120..-1] IN */ word * bc_out, /* OUT */ word * Nc_out /* OUT */ ) { register int k, lambda; word Nc, bc; float wt_float[40]; float dp_float_base[120], * dp_float = dp_float_base + 120; register float L_max, L_power; for (k = 0; k < 40; ++k) wt_float[k] = (float) din [k] ; for (k = -120; k < 0; ++k) dp_float[k] = (float) dp [k] ; /* Search for the maximum cross-correlation and coding of the LTP lag */ L_max = 0; Nc = 40; /* index for the maximum cross-correlation */ for (lambda = 40; lambda <= 120; lambda += 9) { /* Calculate L_result for l = lambda .. lambda + 9. */ register float *lp = dp_float - lambda; register float W; register float a = lp[-8], b = lp[-7], c = lp[-6], d = lp[-5], e = lp[-4], f = lp[-3], g = lp[-2], h = lp[-1]; register float E; register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, S5 = 0, S6 = 0, S7 = 0, S8 = 0; # undef STEP # define STEP(K, a, b, c, d, e, f, g, h) \ W = wt_float[K]; \ E = W * a; S8 += E; \ E = W * b; S7 += E; \ E = W * c; S6 += E; \ E = W * d; S5 += E; \ E = W * e; S4 += E; \ E = W * f; S3 += E; \ E = W * g; S2 += E; \ E = W * h; S1 += E; \ a = lp[K]; \ E = W * a; S0 += E # define STEP_A(K) STEP(K, a, b, c, d, e, f, g, h) # define STEP_B(K) STEP(K, b, c, d, e, f, g, h, a) # define STEP_C(K) STEP(K, c, d, e, f, g, h, a, b) # define STEP_D(K) STEP(K, d, e, f, g, h, a, b, c) # define STEP_E(K) STEP(K, e, f, g, h, a, b, c, d) # define STEP_F(K) STEP(K, f, g, h, a, b, c, d, e) # define STEP_G(K) STEP(K, g, h, a, b, c, d, e, f) # define STEP_H(K) STEP(K, h, a, b, c, d, e, f, g) STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3); STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7); STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11); STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15); STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19); STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23); STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27); STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31); STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35); STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39); if (S0 > L_max) { L_max = S0; Nc = lambda; } if (S1 > L_max) { L_max = S1; Nc = lambda + 1; } if (S2 > L_max) { L_max = S2; Nc = lambda + 2; } if (S3 > L_max) { L_max = S3; Nc = lambda + 3; } if (S4 > L_max) { L_max = S4; Nc = lambda + 4; } if (S5 > L_max) { L_max = S5; Nc = lambda + 5; } if (S6 > L_max) { L_max = S6; Nc = lambda + 6; } if (S7 > L_max) { L_max = S7; Nc = lambda + 7; } if (S8 > L_max) { L_max = S8; Nc = lambda + 8; } } *Nc_out = Nc; if (L_max <= 0.) { *bc_out = 0; return; } /* Compute the power of the reconstructed short term residual * signal dp[..] */ dp_float -= Nc; L_power = 0; for (k = 0; k < 40; ++k) { register float f = dp_float[k]; L_power += f * f; } if (L_max >= L_power) { *bc_out = 3; return; } /* Coding of the LTP gain * Table 4.3a must be used to obtain the level DLB[i] for the * quantization of the LTP gain b to get the coded version bc. */ lambda = L_max / L_power * 32768.; for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break; *bc_out = bc; } #endif /* FAST */ #endif /* USE_FLOAT_MUL */ /* 4.2.12 */ static void Long_term_analysis_filtering ( word bc, /* IN */ word Nc, /* IN */ register word * dp, /* previous d [-120..-1] IN */ register word * d, /* d [0..39] IN */ register word * dpp, /* estimate [0..39] OUT */ register word * e /* long term res. signal [0..39] OUT */ ) /* * In this part, we have to decode the bc parameter to compute * the samples of the estimate dpp[0..39]. The decoding of bc needs the * use of table 4.3b. The long term residual signal e[0..39] * is then calculated to be fed to the RPE encoding section. */ { register int k; # undef STEP # define STEP(BP) \ for (k = 0; k <= 39; k++) { \ dpp[k] = GSM_MULT_R( BP, dp[k - Nc]); \ e[k] = GSM_SUB( d[k], dpp[k] ); \ } switch (bc) { case 0: STEP( 3277 ); break; case 1: STEP( 11469 ); break; case 2: STEP( 21299 ); break; case 3: STEP( 32767 ); break; } } void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */ struct gsm_state * S, word * d, /* [0..39] residual signal IN */ word * dp, /* [-120..-1] d' IN */ word * e, /* [0..39] OUT */ word * dpp, /* [0..39] OUT */ word * Nc, /* correlation lag OUT */ word * bc /* gain factor OUT */ ) { assert( d ); assert( dp ); assert( e ); assert( dpp); assert( Nc ); assert( bc ); #if defined(FAST) && defined(USE_FLOAT_MUL) if (S->fast) #if defined (LTP_CUT) if (S->ltp_cut) Cut_Fast_Calculation_of_the_LTP_parameters(S, d, dp, bc, Nc); else #endif /* LTP_CUT */ Fast_Calculation_of_the_LTP_parameters(d, dp, bc, Nc ); else #endif /* FAST & USE_FLOAT_MUL */ #ifdef LTP_CUT if (S->ltp_cut) Cut_Calculation_of_the_LTP_parameters(S, d, dp, bc, Nc); else #endif Calculation_of_the_LTP_parameters(d, dp, bc, Nc); Long_term_analysis_filtering( *bc, *Nc, dp, d, dpp, e ); } /* 4.3.2 */ void Gsm_Long_Term_Synthesis_Filtering ( struct gsm_state * S, word Ncr, word bcr, register word * erp, /* [0..39] IN */ register word * drp /* [-120..-1] IN, [-120..40] OUT */ ) /* * This procedure uses the bcr and Ncr parameter to realize the * long term synthesis filtering. The decoding of bcr needs * table 4.3b. */ { register int k; word brp, drpp, Nr; /* Check the limits of Nr. */ Nr = Ncr < 40 || Ncr > 120 ? S->nrp : Ncr; S->nrp = Nr; assert(Nr >= 40 && Nr <= 120); /* Decoding of the LTP gain bcr */ brp = gsm_QLB[ bcr ]; /* Computation of the reconstructed short term residual * signal drp[0..39] */ assert(brp != MIN_WORD); for (k = 0; k <= 39; k++) { drpp = GSM_MULT_R( brp, drp[ k - Nr ] ); drp[k] = GSM_ADD( erp[k], drpp ); } /* * Update of the reconstructed short term residual signal * drp[ -1..-120 ] */ for (k = 0; k <= 119; k++) drp[ -120 + k ] = drp[ -80 + k ]; } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: b369b90d-0284-42a0-87b0-99a25bbd93ac */ nyquist-3.05/nylsf/GSM610/decode.c0000644000175000000620000000310211466723256015572 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" /* * 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER */ static void Postprocessing ( struct gsm_state * S, register word * s) { register int k; register word msr = S->msr; register word tmp; for (k = 160; k--; s++) { tmp = GSM_MULT_R( msr, 28180 ); msr = GSM_ADD(*s, tmp); /* Deemphasis */ *s = GSM_ADD(msr, msr) & 0xFFF8; /* Truncation & Upscaling */ } S->msr = msr; } void Gsm_Decoder ( struct gsm_state * S, word * LARcr, /* [0..7] IN */ word * Ncr, /* [0..3] IN */ word * bcr, /* [0..3] IN */ word * Mcr, /* [0..3] IN */ word * xmaxcr, /* [0..3] IN */ word * xMcr, /* [0..13*4] IN */ word * s) /* [0..159] OUT */ { int j, k; word erp[40], wt[160]; word * drp = S->dp0 + 120; for (j=0; j <= 3; j++, xmaxcr++, bcr++, Ncr++, Mcr++, xMcr += 13) { Gsm_RPE_Decoding( /*-S,-*/ *xmaxcr, *Mcr, xMcr, erp ); Gsm_Long_Term_Synthesis_Filtering( S, *Ncr, *bcr, erp, drp ); for (k = 0; k <= 39; k++) wt[ j * 40 + k ] = drp[ k ]; } Gsm_Short_Term_Synthesis_Filter( S, LARcr, wt, s ); Postprocessing(S, s); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 11ae5b90-2e8b-400b-ac64-a69a1fc6cc41 */ nyquist-3.05/nylsf/GSM610/gsm_option.c0000644000175000000620000000242411466723256016533 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" int gsm_option (gsm r, int opt, int * val) { int result = -1; switch (opt) { case GSM_OPT_LTP_CUT: #ifdef LTP_CUT result = r->ltp_cut; if (val) r->ltp_cut = *val; #endif break; case GSM_OPT_VERBOSE: #ifndef NDEBUG result = r->verbose; if (val) r->verbose = *val; #endif break; case GSM_OPT_FAST: #if defined(FAST) && defined(USE_FLOAT_MUL) result = r->fast; if (val) r->fast = !!*val; #endif break; case GSM_OPT_FRAME_CHAIN: #ifdef WAV49 result = r->frame_chain; if (val) r->frame_chain = *val; #endif break; case GSM_OPT_FRAME_INDEX: #ifdef WAV49 result = r->frame_index; if (val) r->frame_index = *val; #endif break; case GSM_OPT_WAV49: #ifdef WAV49 result = r->wav_fmt; if (val) r->wav_fmt = !!*val; #endif break; default: break; } return result; } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 963ff156-506f-4359-9145-371e9060b030 */ nyquist-3.05/nylsf/GSM610/table.c0000644000175000000620000000435411466723256015450 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ /* Most of these tables are inlined at their point of use. */ /* 4.4 TABLES USED IN THE FIXED POINT IMPLEMENTATION OF THE RPE-LTP * CODER AND DECODER * * (Most of them inlined, so watch out.) */ #define GSM_TABLE_C #include "sfconfig.h" // RBD #include "gsm610_priv.h" #include "gsm.h" /* Table 4.1 Quantization of the Log.-Area Ratios */ /* i 1 2 3 4 5 6 7 8 */ word gsm_A[8] = {20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036}; word gsm_B[8] = { 0, 0, 2048, -2560, 94, -1792, -341, -1144}; word gsm_MIC[8] = { -32, -32, -16, -16, -8, -8, -4, -4 }; word gsm_MAC[8] = { 31, 31, 15, 15, 7, 7, 3, 3 }; /* Table 4.2 Tabulation of 1/A[1..8] */ word gsm_INVA[8]={ 13107, 13107, 13107, 13107, 19223, 17476, 31454, 29708 }; /* Table 4.3a Decision level of the LTP gain quantizer */ /* bc 0 1 2 3 */ word gsm_DLB[4] = { 6554, 16384, 26214, 32767 }; /* Table 4.3b Quantization levels of the LTP gain quantizer */ /* bc 0 1 2 3 */ word gsm_QLB[4] = { 3277, 11469, 21299, 32767 }; /* Table 4.4 Coefficients of the weighting filter */ /* i 0 1 2 3 4 5 6 7 8 9 10 */ word gsm_H[11] = {-134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 }; /* Table 4.5 Normalized inverse mantissa used to compute xM/xmax */ /* i 0 1 2 3 4 5 6 7 */ word gsm_NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 }; /* Table 4.6 Normalized direct mantissa used to compute xM/xmax */ /* i 0 1 2 3 4 5 6 7 */ word gsm_FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 }; /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 8957c531-e6b0-4097-9202-da7ca42729ca */ nyquist-3.05/nylsf/GSM610/gsm_create.c0000644000175000000620000000155311466723256016470 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include "config.h" #include #include #include #include "gsm.h" #include "gsm610_priv.h" gsm gsm_create (void) { gsm r; r = malloc (sizeof(struct gsm_state)); if (!r) return r; memset((char *)r, 0, sizeof (struct gsm_state)); r->nrp = 40; return r; } /* Added for libsndfile : May 6, 2002. Not sure if it works. */ void gsm_init (gsm state) { memset (state, 0, sizeof (struct gsm_state)) ; state->nrp = 40 ; } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 9fedb6b3-ed99-40c2-aac1-484c536261fe */ nyquist-3.05/nylsf/GSM610/preprocess.c0000644000175000000620000000476511466723256016554 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include #include #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" /* 4.2.0 .. 4.2.3 PREPROCESSING SECTION * * After A-law to linear conversion (or directly from the * Ato D converter) the following scaling is assumed for * input to the RPE-LTP algorithm: * * in: 0.1.....................12 * S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.* * * Where S is the sign bit, v a valid bit, and * a "don't care" bit. * The original signal is called sop[..] * * out: 0.1................... 12 * S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0 */ void Gsm_Preprocess ( struct gsm_state * S, word * s, word * so ) /* [0..159] IN/OUT */ { word z1 = S->z1; longword L_z2 = S->L_z2; word mp = S->mp; word s1; longword L_s2; longword L_temp; word msp, lsp; word SO; register int k = 160; while (k--) { /* 4.2.1 Downscaling of the input signal */ SO = SASR_W( *s, 3 ) << 2; s++; assert (SO >= -0x4000); /* downscaled by */ assert (SO <= 0x3FFC); /* previous routine. */ /* 4.2.2 Offset compensation * * This part implements a high-pass filter and requires extended * arithmetic precision for the recursive part of this filter. * The input of this procedure is the array so[0...159] and the * output the array sof[ 0...159 ]. */ /* Compute the non-recursive part */ s1 = SO - z1; /* s1 = gsm_sub( *so, z1 ); */ z1 = SO; assert(s1 != MIN_WORD); /* Compute the recursive part */ L_s2 = s1; L_s2 <<= 15; /* Execution of a 31 bv 16 bits multiplication */ msp = SASR_L( L_z2, 15 ); lsp = L_z2-((longword)msp<<15); /* gsm_L_sub(L_z2,(msp<<15)); */ L_s2 += GSM_MULT_R( lsp, 32735 ); L_temp = (longword)msp * 32735; /* GSM_L_MULT(msp,32735) >> 1;*/ L_z2 = GSM_L_ADD( L_temp, L_s2 ); /* Compute sof[k] with rounding */ L_temp = GSM_L_ADD( L_z2, 16384 ); /* 4.2.3 Preemphasis */ msp = GSM_MULT_R( mp, -28180 ); mp = SASR_L( L_temp, 15 ); *so++ = GSM_ADD( mp, msp ); } S->z1 = z1; S->L_z2 = L_z2; S->mp = mp; } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: b760b0d9-3a05-4da3-9dc9-441ffb905d87 */ nyquist-3.05/nylsf/GSM610/gsm_decode.c0000644000175000000620000002501011466723256016442 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" int gsm_decode (gsm s, gsm_byte * c, gsm_signal * target) { word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4]; #ifdef WAV49 if (s->wav_fmt) { uword sr = 0; s->frame_index = !s->frame_index; if (s->frame_index) { sr = *c++; LARc[0] = sr & 0x3f; sr >>= 6; sr |= (uword)*c++ << 2; LARc[1] = sr & 0x3f; sr >>= 6; sr |= (uword)*c++ << 4; LARc[2] = sr & 0x1f; sr >>= 5; LARc[3] = sr & 0x1f; sr >>= 5; sr |= (uword)*c++ << 2; LARc[4] = sr & 0xf; sr >>= 4; LARc[5] = sr & 0xf; sr >>= 4; sr |= (uword)*c++ << 2; /* 5 */ LARc[6] = sr & 0x7; sr >>= 3; LARc[7] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 4; Nc[0] = sr & 0x7f; sr >>= 7; bc[0] = sr & 0x3; sr >>= 2; Mc[0] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 1; xmaxc[0] = sr & 0x3f; sr >>= 6; xmc[0] = sr & 0x7; sr >>= 3; sr = *c++; xmc[1] = sr & 0x7; sr >>= 3; xmc[2] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[3] = sr & 0x7; sr >>= 3; xmc[4] = sr & 0x7; sr >>= 3; xmc[5] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; /* 10 */ xmc[6] = sr & 0x7; sr >>= 3; xmc[7] = sr & 0x7; sr >>= 3; xmc[8] = sr & 0x7; sr >>= 3; sr = *c++; xmc[9] = sr & 0x7; sr >>= 3; xmc[10] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[11] = sr & 0x7; sr >>= 3; xmc[12] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 4; Nc[1] = sr & 0x7f; sr >>= 7; bc[1] = sr & 0x3; sr >>= 2; Mc[1] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 1; xmaxc[1] = sr & 0x3f; sr >>= 6; xmc[13] = sr & 0x7; sr >>= 3; sr = *c++; /* 15 */ xmc[14] = sr & 0x7; sr >>= 3; xmc[15] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[16] = sr & 0x7; sr >>= 3; xmc[17] = sr & 0x7; sr >>= 3; xmc[18] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[19] = sr & 0x7; sr >>= 3; xmc[20] = sr & 0x7; sr >>= 3; xmc[21] = sr & 0x7; sr >>= 3; sr = *c++; xmc[22] = sr & 0x7; sr >>= 3; xmc[23] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[24] = sr & 0x7; sr >>= 3; xmc[25] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 4; /* 20 */ Nc[2] = sr & 0x7f; sr >>= 7; bc[2] = sr & 0x3; sr >>= 2; Mc[2] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 1; xmaxc[2] = sr & 0x3f; sr >>= 6; xmc[26] = sr & 0x7; sr >>= 3; sr = *c++; xmc[27] = sr & 0x7; sr >>= 3; xmc[28] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[29] = sr & 0x7; sr >>= 3; xmc[30] = sr & 0x7; sr >>= 3; xmc[31] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[32] = sr & 0x7; sr >>= 3; xmc[33] = sr & 0x7; sr >>= 3; xmc[34] = sr & 0x7; sr >>= 3; sr = *c++; /* 25 */ xmc[35] = sr & 0x7; sr >>= 3; xmc[36] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[37] = sr & 0x7; sr >>= 3; xmc[38] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 4; Nc[3] = sr & 0x7f; sr >>= 7; bc[3] = sr & 0x3; sr >>= 2; Mc[3] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 1; xmaxc[3] = sr & 0x3f; sr >>= 6; xmc[39] = sr & 0x7; sr >>= 3; sr = *c++; xmc[40] = sr & 0x7; sr >>= 3; xmc[41] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; /* 30 */ xmc[42] = sr & 0x7; sr >>= 3; xmc[43] = sr & 0x7; sr >>= 3; xmc[44] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[45] = sr & 0x7; sr >>= 3; xmc[46] = sr & 0x7; sr >>= 3; xmc[47] = sr & 0x7; sr >>= 3; sr = *c++; xmc[48] = sr & 0x7; sr >>= 3; xmc[49] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[50] = sr & 0x7; sr >>= 3; xmc[51] = sr & 0x7; sr >>= 3; s->frame_chain = sr & 0xf; } else { sr = s->frame_chain; sr |= (uword)*c++ << 4; /* 1 */ LARc[0] = sr & 0x3f; sr >>= 6; LARc[1] = sr & 0x3f; sr >>= 6; sr = *c++; LARc[2] = sr & 0x1f; sr >>= 5; sr |= (uword)*c++ << 3; LARc[3] = sr & 0x1f; sr >>= 5; LARc[4] = sr & 0xf; sr >>= 4; sr |= (uword)*c++ << 2; LARc[5] = sr & 0xf; sr >>= 4; LARc[6] = sr & 0x7; sr >>= 3; LARc[7] = sr & 0x7; sr >>= 3; sr = *c++; /* 5 */ Nc[0] = sr & 0x7f; sr >>= 7; sr |= (uword)*c++ << 1; bc[0] = sr & 0x3; sr >>= 2; Mc[0] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 5; xmaxc[0] = sr & 0x3f; sr >>= 6; xmc[0] = sr & 0x7; sr >>= 3; xmc[1] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[2] = sr & 0x7; sr >>= 3; xmc[3] = sr & 0x7; sr >>= 3; xmc[4] = sr & 0x7; sr >>= 3; sr = *c++; xmc[5] = sr & 0x7; sr >>= 3; xmc[6] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; /* 10 */ xmc[7] = sr & 0x7; sr >>= 3; xmc[8] = sr & 0x7; sr >>= 3; xmc[9] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[10] = sr & 0x7; sr >>= 3; xmc[11] = sr & 0x7; sr >>= 3; xmc[12] = sr & 0x7; sr >>= 3; sr = *c++; Nc[1] = sr & 0x7f; sr >>= 7; sr |= (uword)*c++ << 1; bc[1] = sr & 0x3; sr >>= 2; Mc[1] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 5; xmaxc[1] = sr & 0x3f; sr >>= 6; xmc[13] = sr & 0x7; sr >>= 3; xmc[14] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; /* 15 */ xmc[15] = sr & 0x7; sr >>= 3; xmc[16] = sr & 0x7; sr >>= 3; xmc[17] = sr & 0x7; sr >>= 3; sr = *c++; xmc[18] = sr & 0x7; sr >>= 3; xmc[19] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[20] = sr & 0x7; sr >>= 3; xmc[21] = sr & 0x7; sr >>= 3; xmc[22] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[23] = sr & 0x7; sr >>= 3; xmc[24] = sr & 0x7; sr >>= 3; xmc[25] = sr & 0x7; sr >>= 3; sr = *c++; Nc[2] = sr & 0x7f; sr >>= 7; sr |= (uword)*c++ << 1; /* 20 */ bc[2] = sr & 0x3; sr >>= 2; Mc[2] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 5; xmaxc[2] = sr & 0x3f; sr >>= 6; xmc[26] = sr & 0x7; sr >>= 3; xmc[27] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[28] = sr & 0x7; sr >>= 3; xmc[29] = sr & 0x7; sr >>= 3; xmc[30] = sr & 0x7; sr >>= 3; sr = *c++; xmc[31] = sr & 0x7; sr >>= 3; xmc[32] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[33] = sr & 0x7; sr >>= 3; xmc[34] = sr & 0x7; sr >>= 3; xmc[35] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; /* 25 */ xmc[36] = sr & 0x7; sr >>= 3; xmc[37] = sr & 0x7; sr >>= 3; xmc[38] = sr & 0x7; sr >>= 3; sr = *c++; Nc[3] = sr & 0x7f; sr >>= 7; sr |= (uword)*c++ << 1; bc[3] = sr & 0x3; sr >>= 2; Mc[3] = sr & 0x3; sr >>= 2; sr |= (uword)*c++ << 5; xmaxc[3] = sr & 0x3f; sr >>= 6; xmc[39] = sr & 0x7; sr >>= 3; xmc[40] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[41] = sr & 0x7; sr >>= 3; xmc[42] = sr & 0x7; sr >>= 3; xmc[43] = sr & 0x7; sr >>= 3; sr = *c++; /* 30 */ xmc[44] = sr & 0x7; sr >>= 3; xmc[45] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 2; xmc[46] = sr & 0x7; sr >>= 3; xmc[47] = sr & 0x7; sr >>= 3; xmc[48] = sr & 0x7; sr >>= 3; sr |= (uword)*c++ << 1; xmc[49] = sr & 0x7; sr >>= 3; xmc[50] = sr & 0x7; sr >>= 3; xmc[51] = sr & 0x7; sr >>= 3; } } else #endif { /* GSM_MAGIC = (*c >> 4) & 0xF; */ if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1; LARc[0] = (*c++ & 0xF) << 2; /* 1 */ LARc[0] |= (*c >> 6) & 0x3; LARc[1] = *c++ & 0x3F; LARc[2] = (*c >> 3) & 0x1F; LARc[3] = (*c++ & 0x7) << 2; LARc[3] |= (*c >> 6) & 0x3; LARc[4] = (*c >> 2) & 0xF; LARc[5] = (*c++ & 0x3) << 2; LARc[5] |= (*c >> 6) & 0x3; LARc[6] = (*c >> 3) & 0x7; LARc[7] = *c++ & 0x7; Nc[0] = (*c >> 1) & 0x7F; bc[0] = (*c++ & 0x1) << 1; bc[0] |= (*c >> 7) & 0x1; Mc[0] = (*c >> 5) & 0x3; xmaxc[0] = (*c++ & 0x1F) << 1; xmaxc[0] |= (*c >> 7) & 0x1; xmc[0] = (*c >> 4) & 0x7; xmc[1] = (*c >> 1) & 0x7; xmc[2] = (*c++ & 0x1) << 2; xmc[2] |= (*c >> 6) & 0x3; xmc[3] = (*c >> 3) & 0x7; xmc[4] = *c++ & 0x7; xmc[5] = (*c >> 5) & 0x7; xmc[6] = (*c >> 2) & 0x7; xmc[7] = (*c++ & 0x3) << 1; /* 10 */ xmc[7] |= (*c >> 7) & 0x1; xmc[8] = (*c >> 4) & 0x7; xmc[9] = (*c >> 1) & 0x7; xmc[10] = (*c++ & 0x1) << 2; xmc[10] |= (*c >> 6) & 0x3; xmc[11] = (*c >> 3) & 0x7; xmc[12] = *c++ & 0x7; Nc[1] = (*c >> 1) & 0x7F; bc[1] = (*c++ & 0x1) << 1; bc[1] |= (*c >> 7) & 0x1; Mc[1] = (*c >> 5) & 0x3; xmaxc[1] = (*c++ & 0x1F) << 1; xmaxc[1] |= (*c >> 7) & 0x1; xmc[13] = (*c >> 4) & 0x7; xmc[14] = (*c >> 1) & 0x7; xmc[15] = (*c++ & 0x1) << 2; xmc[15] |= (*c >> 6) & 0x3; xmc[16] = (*c >> 3) & 0x7; xmc[17] = *c++ & 0x7; xmc[18] = (*c >> 5) & 0x7; xmc[19] = (*c >> 2) & 0x7; xmc[20] = (*c++ & 0x3) << 1; xmc[20] |= (*c >> 7) & 0x1; xmc[21] = (*c >> 4) & 0x7; xmc[22] = (*c >> 1) & 0x7; xmc[23] = (*c++ & 0x1) << 2; xmc[23] |= (*c >> 6) & 0x3; xmc[24] = (*c >> 3) & 0x7; xmc[25] = *c++ & 0x7; Nc[2] = (*c >> 1) & 0x7F; bc[2] = (*c++ & 0x1) << 1; /* 20 */ bc[2] |= (*c >> 7) & 0x1; Mc[2] = (*c >> 5) & 0x3; xmaxc[2] = (*c++ & 0x1F) << 1; xmaxc[2] |= (*c >> 7) & 0x1; xmc[26] = (*c >> 4) & 0x7; xmc[27] = (*c >> 1) & 0x7; xmc[28] = (*c++ & 0x1) << 2; xmc[28] |= (*c >> 6) & 0x3; xmc[29] = (*c >> 3) & 0x7; xmc[30] = *c++ & 0x7; xmc[31] = (*c >> 5) & 0x7; xmc[32] = (*c >> 2) & 0x7; xmc[33] = (*c++ & 0x3) << 1; xmc[33] |= (*c >> 7) & 0x1; xmc[34] = (*c >> 4) & 0x7; xmc[35] = (*c >> 1) & 0x7; xmc[36] = (*c++ & 0x1) << 2; xmc[36] |= (*c >> 6) & 0x3; xmc[37] = (*c >> 3) & 0x7; xmc[38] = *c++ & 0x7; Nc[3] = (*c >> 1) & 0x7F; bc[3] = (*c++ & 0x1) << 1; bc[3] |= (*c >> 7) & 0x1; Mc[3] = (*c >> 5) & 0x3; xmaxc[3] = (*c++ & 0x1F) << 1; xmaxc[3] |= (*c >> 7) & 0x1; xmc[39] = (*c >> 4) & 0x7; xmc[40] = (*c >> 1) & 0x7; xmc[41] = (*c++ & 0x1) << 2; xmc[41] |= (*c >> 6) & 0x3; xmc[42] = (*c >> 3) & 0x7; xmc[43] = *c++ & 0x7; /* 30 */ xmc[44] = (*c >> 5) & 0x7; xmc[45] = (*c >> 2) & 0x7; xmc[46] = (*c++ & 0x3) << 1; xmc[46] |= (*c >> 7) & 0x1; xmc[47] = (*c >> 4) & 0x7; xmc[48] = (*c >> 1) & 0x7; xmc[49] = (*c++ & 0x1) << 2; xmc[49] |= (*c >> 6) & 0x3; xmc[50] = (*c >> 3) & 0x7; xmc[51] = *c & 0x7; /* 33 */ } Gsm_Decoder(s, LARc, Nc, bc, Mc, xmaxc, xmc, target); return 0; } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 6a9b6628-821c-4a96-84c1-485ebd35f170 */ nyquist-3.05/nylsf/GSM610/gsm.h0000644000175000000620000000255711466723256015157 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #ifndef GSM_H #define GSM_H #include /* for FILE * */ /* * Interface */ typedef struct gsm_state * gsm; typedef short gsm_signal; /* signed 16 bit */ typedef unsigned char gsm_byte; typedef gsm_byte gsm_frame[33]; /* 33 * 8 bits */ #define GSM_MAGIC 0xD /* 13 kbit/s RPE-LTP */ #define GSM_PATCHLEVEL 10 #define GSM_MINOR 0 #define GSM_MAJOR 1 #define GSM_OPT_VERBOSE 1 #define GSM_OPT_FAST 2 #define GSM_OPT_LTP_CUT 3 #define GSM_OPT_WAV49 4 #define GSM_OPT_FRAME_INDEX 5 #define GSM_OPT_FRAME_CHAIN 6 gsm gsm_create (void); /* Added for libsndfile : May 6, 2002 */ void gsm_init (gsm); void gsm_destroy (gsm); int gsm_print (FILE *, gsm, gsm_byte *); int gsm_option (gsm, int, int *); void gsm_encode (gsm, gsm_signal *, gsm_byte *); int gsm_decode (gsm, gsm_byte *, gsm_signal *); int gsm_explode (gsm, gsm_byte *, gsm_signal *); void gsm_implode (gsm, gsm_signal *, gsm_byte *); #endif /* GSM_H */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 8cfc7698-5433-4b6f-aeca-967c6fda4dec */ nyquist-3.05/nylsf/GSM610/short_term.c0000644000175000000620000002360311466723256016545 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include #include #include "config.h" // RBD #include "gsm610_priv.h" #include "gsm.h" /* * SHORT TERM ANALYSIS FILTERING SECTION */ /* 4.2.8 */ static void Decoding_of_the_coded_Log_Area_Ratios ( word * LARc, /* coded log area ratio [0..7] IN */ word * LARpp) /* out: decoded .. */ { register word temp1 /* , temp2 */; /* This procedure requires for efficient implementation * two tables. * * INVA[1..8] = integer( (32768 * 8) / real_A[1..8]) * MIC[1..8] = minimum value of the LARc[1..8] */ /* Compute the LARpp[1..8] */ /* for (i = 1; i <= 8; i++, B++, MIC++, INVA++, LARc++, LARpp++) { * * temp1 = GSM_ADD( *LARc, *MIC ) << 10; * temp2 = *B << 1; * temp1 = GSM_SUB( temp1, temp2 ); * * assert(*INVA != MIN_WORD); * * temp1 = GSM_MULT_R( *INVA, temp1 ); * *LARpp = GSM_ADD( temp1, temp1 ); * } */ #undef STEP #define STEP( B, MIC, INVA ) \ temp1 = GSM_ADD( *LARc++, MIC ) << 10; \ temp1 = GSM_SUB( temp1, B << 1 ); \ temp1 = GSM_MULT_R( INVA, temp1 ); \ *LARpp++ = GSM_ADD( temp1, temp1 ); STEP( 0, -32, 13107 ); STEP( 0, -32, 13107 ); STEP( 2048, -16, 13107 ); STEP( -2560, -16, 13107 ); STEP( 94, -8, 19223 ); STEP( -1792, -8, 17476 ); STEP( -341, -4, 31454 ); STEP( -1144, -4, 29708 ); /* NOTE: the addition of *MIC is used to restore * the sign of *LARc. */ } /* 4.2.9 */ /* Computation of the quantized reflection coefficients */ /* 4.2.9.1 Interpolation of the LARpp[1..8] to get the LARp[1..8] */ /* * Within each frame of 160 analyzed speech samples the short term * analysis and synthesis filters operate with four different sets of * coefficients, derived from the previous set of decoded LARs(LARpp(j-1)) * and the actual set of decoded LARs (LARpp(j)) * * (Initial value: LARpp(j-1)[1..8] = 0.) */ static void Coefficients_0_12 ( register word * LARpp_j_1, register word * LARpp_j, register word * LARp) { register int i; for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++) { *LARp = GSM_ADD( SASR_W( *LARpp_j_1, 2 ), SASR_W( *LARpp_j, 2 )); *LARp = GSM_ADD( *LARp, SASR_W( *LARpp_j_1, 1)); } } static void Coefficients_13_26 ( register word * LARpp_j_1, register word * LARpp_j, register word * LARp) { register int i; for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) { *LARp = GSM_ADD( SASR_W( *LARpp_j_1, 1), SASR_W( *LARpp_j, 1 )); } } static void Coefficients_27_39 ( register word * LARpp_j_1, register word * LARpp_j, register word * LARp) { register int i; for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) { *LARp = GSM_ADD( SASR_W( *LARpp_j_1, 2 ), SASR_W( *LARpp_j, 2 )); *LARp = GSM_ADD( *LARp, SASR_W( *LARpp_j, 1 )); } } static void Coefficients_40_159 ( register word * LARpp_j, register word * LARp) { register int i; for (i = 1; i <= 8; i++, LARp++, LARpp_j++) *LARp = *LARpp_j; } /* 4.2.9.2 */ static void LARp_to_rp ( register word * LARp) /* [0..7] IN/OUT */ /* * The input of this procedure is the interpolated LARp[0..7] array. * The reflection coefficients, rp[i], are used in the analysis * filter and in the synthesis filter. */ { register int i; register word temp; for (i = 1; i <= 8; i++, LARp++) { /* temp = GSM_ABS( *LARp ); * * if (temp < 11059) temp <<= 1; * else if (temp < 20070) temp += 11059; * else temp = GSM_ADD( temp >> 2, 26112 ); * * *LARp = *LARp < 0 ? -temp : temp; */ if (*LARp < 0) { temp = *LARp == MIN_WORD ? MAX_WORD : -(*LARp); *LARp = - ((temp < 11059) ? temp << 1 : ((temp < 20070) ? temp + 11059 : GSM_ADD( (word) (temp >> 2), (word) 26112 ))); } else { temp = *LARp; *LARp = (temp < 11059) ? temp << 1 : ((temp < 20070) ? temp + 11059 : GSM_ADD( (word) (temp >> 2), (word) 26112 )); } } } /* 4.2.10 */ static void Short_term_analysis_filtering ( struct gsm_state * S, register word * rp, /* [0..7] IN */ register int k_n, /* k_end - k_start */ register word * s /* [0..n-1] IN/OUT */ ) /* * This procedure computes the short term residual signal d[..] to be fed * to the RPE-LTP loop from the s[..] signal and from the local rp[..] * array (quantized reflection coefficients). As the call of this * procedure can be done in many ways (see the interpolation of the LAR * coefficient), it is assumed that the computation begins with index * k_start (for arrays d[..] and s[..]) and stops with index k_end * (k_start and k_end are defined in 4.2.9.1). This procedure also * needs to keep the array u[0..7] in memory for each call. */ { register word * u = S->u; register int i; register word di, zzz, ui, sav, rpi; for (; k_n--; s++) { di = sav = *s; for (i = 0; i < 8; i++) { /* YYY */ ui = u[i]; rpi = rp[i]; u[i] = sav; zzz = GSM_MULT_R(rpi, di); sav = GSM_ADD( ui, zzz); zzz = GSM_MULT_R(rpi, ui); di = GSM_ADD( di, zzz ); } *s = di; } } #if defined(USE_FLOAT_MUL) && defined(FAST) static void Fast_Short_term_analysis_filtering ( struct gsm_state * S, register word * rp, /* [0..7] IN */ register int k_n, /* k_end - k_start */ register word * s /* [0..n-1] IN/OUT */ ) { register word * u = S->u; register int i; float uf[8], rpf[8]; register float scalef = 3.0517578125e-5; register float sav, di, temp; for (i = 0; i < 8; ++i) { uf[i] = u[i]; rpf[i] = rp[i] * scalef; } for (; k_n--; s++) { sav = di = *s; for (i = 0; i < 8; ++i) { register float rpfi = rpf[i]; register float ufi = uf[i]; uf[i] = sav; temp = rpfi * di + ufi; di += rpfi * ufi; sav = temp; } *s = di; } for (i = 0; i < 8; ++i) u[i] = uf[i]; } #endif /* ! (defined (USE_FLOAT_MUL) && defined (FAST)) */ static void Short_term_synthesis_filtering ( struct gsm_state * S, register word * rrp, /* [0..7] IN */ register int k, /* k_end - k_start */ register word * wt, /* [0..k-1] IN */ register word * sr /* [0..k-1] OUT */ ) { register word * v = S->v; register int i; register word sri, tmp1, tmp2; while (k--) { sri = *wt++; for (i = 8; i--;) { /* sri = GSM_SUB( sri, gsm_mult_r( rrp[i], v[i] ) ); */ tmp1 = rrp[i]; tmp2 = v[i]; tmp2 = ( tmp1 == MIN_WORD && tmp2 == MIN_WORD ? MAX_WORD : 0x0FFFF & (( (longword)tmp1 * (longword)tmp2 + 16384) >> 15)) ; sri = GSM_SUB( sri, tmp2 ); /* v[i+1] = GSM_ADD( v[i], gsm_mult_r( rrp[i], sri ) ); */ tmp1 = ( tmp1 == MIN_WORD && sri == MIN_WORD ? MAX_WORD : 0x0FFFF & (( (longword)tmp1 * (longword)sri + 16384) >> 15)) ; v[i+1] = GSM_ADD( v[i], tmp1); } *sr++ = v[0] = sri; } } #if defined(FAST) && defined(USE_FLOAT_MUL) static void Fast_Short_term_synthesis_filtering ( struct gsm_state * S, register word * rrp, /* [0..7] IN */ register int k, /* k_end - k_start */ register word * wt, /* [0..k-1] IN */ register word * sr /* [0..k-1] OUT */ ) { register word * v = S->v; register int i; float va[9], rrpa[8]; register float scalef = 3.0517578125e-5, temp; for (i = 0; i < 8; ++i) { va[i] = v[i]; rrpa[i] = (float)rrp[i] * scalef; } while (k--) { register float sri = *wt++; for (i = 8; i--;) { sri -= rrpa[i] * va[i]; if (sri < -32768.) sri = -32768.; else if (sri > 32767.) sri = 32767.; temp = va[i] + rrpa[i] * sri; if (temp < -32768.) temp = -32768.; else if (temp > 32767.) temp = 32767.; va[i+1] = temp; } *sr++ = va[0] = sri; } for (i = 0; i < 9; ++i) v[i] = va[i]; } #endif /* defined(FAST) && defined(USE_FLOAT_MUL) */ void Gsm_Short_Term_Analysis_Filter ( struct gsm_state * S, word * LARc, /* coded log area ratio [0..7] IN */ word * s /* signal [0..159] IN/OUT */ ) { word * LARpp_j = S->LARpp[ S->j ]; word * LARpp_j_1 = S->LARpp[ S->j ^= 1 ]; word LARp[8]; #undef FILTER #if defined(FAST) && defined(USE_FLOAT_MUL) # define FILTER (* (S->fast \ ? Fast_Short_term_analysis_filtering \ : Short_term_analysis_filtering )) #else # define FILTER Short_term_analysis_filtering #endif Decoding_of_the_coded_Log_Area_Ratios( LARc, LARpp_j ); Coefficients_0_12( LARpp_j_1, LARpp_j, LARp ); LARp_to_rp( LARp ); FILTER( S, LARp, 13, s); Coefficients_13_26( LARpp_j_1, LARpp_j, LARp); LARp_to_rp( LARp ); FILTER( S, LARp, 14, s + 13); Coefficients_27_39( LARpp_j_1, LARpp_j, LARp); LARp_to_rp( LARp ); FILTER( S, LARp, 13, s + 27); Coefficients_40_159( LARpp_j, LARp); LARp_to_rp( LARp ); FILTER( S, LARp, 120, s + 40); } void Gsm_Short_Term_Synthesis_Filter ( struct gsm_state * S, word * LARcr, /* received log area ratios [0..7] IN */ word * wt, /* received d [0..159] IN */ word * s /* signal s [0..159] OUT */ ) { word * LARpp_j = S->LARpp[ S->j ]; word * LARpp_j_1 = S->LARpp[ S->j ^=1 ]; word LARp[8]; #undef FILTER #if defined(FAST) && defined(USE_FLOAT_MUL) # define FILTER (* (S->fast \ ? Fast_Short_term_synthesis_filtering \ : Short_term_synthesis_filtering )) #else # define FILTER Short_term_synthesis_filtering #endif Decoding_of_the_coded_Log_Area_Ratios( LARcr, LARpp_j ); Coefficients_0_12( LARpp_j_1, LARpp_j, LARp ); LARp_to_rp( LARp ); FILTER( S, LARp, 13, wt, s ); Coefficients_13_26( LARpp_j_1, LARpp_j, LARp); LARp_to_rp( LARp ); FILTER( S, LARp, 14, wt + 13, s + 13 ); Coefficients_27_39( LARpp_j_1, LARpp_j, LARp); LARp_to_rp( LARp ); FILTER( S, LARp, 13, wt + 27, s + 27 ); Coefficients_40_159( LARpp_j, LARp ); LARp_to_rp( LARp ); FILTER(S, LARp, 120, wt + 40, s + 40); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 019ac7ba-c6dd-4540-abf0-8644b6c4a633 */ nyquist-3.05/nylsf/GSM610/gsm_destroy.c0000644000175000000620000000120111466723256016704 0ustar stevestaff/* * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische * Universitaet Berlin. See the accompanying file "COPYRIGHT" for * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. */ #include "gsm.h" #include "config.h" #ifdef HAS_STDLIB_H # include #else # ifdef HAS_MALLOC_H # include # else extern void free(); # endif #endif void gsm_destroy (gsm S) { if (S) free((char *)S); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: f423d09b-6ccc-47e0-9b18-ee1cf7a8e473 */ nyquist-3.05/nylsf/GSM610/README0000644000175000000620000000262011466723256015067 0ustar stevestaffGSM 06.10 13 kbit/s RPE/LTP speech codec ---------------------------------------- All the file in this directory were written by Jutta Degener and Carsten Borman for The Communications and Operating Systems Research Group (KBS) at the Technische Universitaet Berlin. Their work was released under the following license which is assumed to be compatible with The GNU Lesser General Public License. ---------------------------------------------------------------------------- Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, Technische Universitaet Berlin Any use of this software is permitted provided that this notice is not removed and that neither the authors nor the Technische Universitaet Berlin are deemed to have made any representations as to the suitability of this software for any purpose nor are held responsible for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. As a matter of courtesy, the authors request to be informed about uses this software has found, about bugs in this software, and about any improvements that may be of general interest. Berlin, 28.11.1994 Jutta Degener (jutta@cs.tu-berlin.de) Carsten Bormann (cabo@cs.tu-berlin.de) ---------------------------------------------------------------------------- Jutta Degener and Carsten Bormann's work can be found on their homepage at: http://kbs.cs.tu-berlin.de/~jutta/toast.html nyquist-3.05/nylsf/ms_adpcm.c0000644000175000000620000005773211466723256015277 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" #include "wav_w64.h" /* These required here because we write the header in this file. */ #define RIFF_MARKER (MAKE_MARKER ('R', 'I', 'F', 'F')) #define WAVE_MARKER (MAKE_MARKER ('W', 'A', 'V', 'E')) #define fmt_MARKER (MAKE_MARKER ('f', 'm', 't', ' ')) #define fact_MARKER (MAKE_MARKER ('f', 'a', 'c', 't')) #define data_MARKER (MAKE_MARKER ('d', 'a', 't', 'a')) #define WAVE_FORMAT_MS_ADPCM 0x0002 typedef struct { int channels, blocksize, samplesperblock, blocks, dataremaining ; int blockcount ; sf_count_t samplecount ; short *samples ; unsigned char *block ; #if HAVE_FLEXIBLE_ARRAY short dummydata [] ; /* ISO C99 struct flexible array. */ #else short dummydata [0] ; /* This is a hack an might not work. */ #endif } MSADPCM_PRIVATE ; /*============================================================================================ ** MS ADPCM static data and functions. */ static int AdaptationTable [] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 } ; /* TODO : The first 7 coef's are are always hardcode and must appear in the actual WAVE file. They should be read in in case a sound program added extras to the list. */ static int AdaptCoeff1 [MSADPCM_ADAPT_COEFF_COUNT] = { 256, 512, 0, 192, 240, 460, 392 } ; static int AdaptCoeff2 [MSADPCM_ADAPT_COEFF_COUNT] = { 0, -256, 0, 64, 0, -208, -232 } ; /*============================================================================================ ** MS ADPCM Block Layout. ** ====================== ** Block is usually 256, 512 or 1024 bytes depending on sample rate. ** For a mono file, the block is laid out as follows: ** byte purpose ** 0 block predictor [0..6] ** 1,2 initial idelta (positive) ** 3,4 sample 1 ** 5,6 sample 0 ** 7..n packed bytecodes ** ** For a stereo file, the block is laid out as follows: ** byte purpose ** 0 block predictor [0..6] for left channel ** 1 block predictor [0..6] for right channel ** 2,3 initial idelta (positive) for left channel ** 4,5 initial idelta (positive) for right channel ** 6,7 sample 1 for left channel ** 8,9 sample 1 for right channel ** 10,11 sample 0 for left channel ** 12,13 sample 0 for right channel ** 14..n packed bytecodes */ /*============================================================================================ ** Static functions. */ static int msadpcm_decode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) ; static sf_count_t msadpcm_read_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, short *ptr, int len) ; static int msadpcm_encode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) ; static sf_count_t msadpcm_write_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, const short *ptr, int len) ; static sf_count_t msadpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t msadpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t msadpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t msadpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t msadpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t msadpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t msadpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t msadpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int msadpcm_close (SF_PRIVATE *psf) ; static void choose_predictor (unsigned int channels, short *data, int *bpred, int *idelta) ; /*============================================================================================ ** MS ADPCM Read Functions. */ int wav_w64_msadpcm_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) { MSADPCM_PRIVATE *pms ; unsigned int pmssize ; int count ; if (psf->codec_data != NULL) { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; return SFE_INTERNAL ; } ; if (psf->mode == SFM_WRITE) samplesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ; pmssize = sizeof (MSADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ; if (! (psf->codec_data = malloc (pmssize))) return SFE_MALLOC_FAILED ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; memset (pms, 0, pmssize) ; pms->samples = pms->dummydata ; pms->block = (unsigned char*) (pms->dummydata + psf->sf.channels * samplesperblock) ; pms->channels = psf->sf.channels ; pms->blocksize = blockalign ; pms->samplesperblock = samplesperblock ; if (psf->mode == SFM_READ) { pms->dataremaining = psf->datalength ; if (psf->datalength % pms->blocksize) pms->blocks = psf->datalength / pms->blocksize + 1 ; else pms->blocks = psf->datalength / pms->blocksize ; count = 2 * (pms->blocksize - 6 * pms->channels) / pms->channels ; if (pms->samplesperblock != count) psf_log_printf (psf, "*** Warning : samplesperblock shoud be %d.\n", count) ; psf->sf.frames = (psf->datalength / pms->blocksize) * pms->samplesperblock ; psf_log_printf (psf, " bpred idelta\n") ; msadpcm_decode_block (psf, pms) ; psf->read_short = msadpcm_read_s ; psf->read_int = msadpcm_read_i ; psf->read_float = msadpcm_read_f ; psf->read_double = msadpcm_read_d ; } ; if (psf->mode == SFM_WRITE) { pms->samples = pms->dummydata ; pms->samplecount = 0 ; psf->write_short = msadpcm_write_s ; psf->write_int = msadpcm_write_i ; psf->write_float = msadpcm_write_f ; psf->write_double = msadpcm_write_d ; } ; psf->codec_close = msadpcm_close ; psf->seek = msadpcm_seek ; return 0 ; } /* wav_w64_msadpcm_init */ static int msadpcm_decode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) { int chan, k, blockindx, sampleindx ; short bytecode, bpred [2], chan_idelta [2] ; int predict ; int current ; int idelta ; pms->blockcount ++ ; pms->samplecount = 0 ; if (pms->blockcount > pms->blocks) { memset (pms->samples, 0, pms->samplesperblock * pms->channels) ; return 1 ; } ; if ((k = psf_fread (pms->block, 1, pms->blocksize, psf)) != pms->blocksize) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pms->blocksize) ; /* Read and check the block header. */ if (pms->channels == 1) { bpred [0] = pms->block [0] ; if (bpred [0] >= 7) psf_log_printf (psf, "MS ADPCM synchronisation error (%d).\n", bpred [0]) ; chan_idelta [0] = pms->block [1] | (pms->block [2] << 8) ; chan_idelta [1] = 0 ; psf_log_printf (psf, "(%d) (%d)\n", bpred [0], chan_idelta [0]) ; pms->samples [1] = pms->block [3] | (pms->block [4] << 8) ; pms->samples [0] = pms->block [5] | (pms->block [6] << 8) ; blockindx = 7 ; } else { bpred [0] = pms->block [0] ; bpred [1] = pms->block [1] ; if (bpred [0] >= 7 || bpred [1] >= 7) psf_log_printf (psf, "MS ADPCM synchronisation error (%d %d).\n", bpred [0], bpred [1]) ; chan_idelta [0] = pms->block [2] | (pms->block [3] << 8) ; chan_idelta [1] = pms->block [4] | (pms->block [5] << 8) ; psf_log_printf (psf, "(%d, %d) (%d, %d)\n", bpred [0], bpred [1], chan_idelta [0], chan_idelta [1]) ; pms->samples [2] = pms->block [6] | (pms->block [7] << 8) ; pms->samples [3] = pms->block [8] | (pms->block [9] << 8) ; pms->samples [0] = pms->block [10] | (pms->block [11] << 8) ; pms->samples [1] = pms->block [12] | (pms->block [13] << 8) ; blockindx = 14 ; } ; /*-------------------------------------------------------- This was left over from a time when calculations were done as ints rather than shorts. Keep this around as a reminder in case I ever find a file which decodes incorrectly. if (chan_idelta [0] & 0x8000) chan_idelta [0] -= 0x10000 ; if (chan_idelta [1] & 0x8000) chan_idelta [1] -= 0x10000 ; --------------------------------------------------------*/ /* Pull apart the packed 4 bit samples and store them in their ** correct sample positions. */ sampleindx = 2 * pms->channels ; while (blockindx < pms->blocksize) { bytecode = pms->block [blockindx++] ; pms->samples [sampleindx++] = (bytecode >> 4) & 0x0F ; pms->samples [sampleindx++] = bytecode & 0x0F ; } ; /* Decode the encoded 4 bit samples. */ for (k = 2 * pms->channels ; k < (pms->samplesperblock * pms->channels) ; k ++) { chan = (pms->channels > 1) ? (k % 2) : 0 ; bytecode = pms->samples [k] & 0xF ; /* Compute next Adaptive Scale Factor (ASF) */ idelta = chan_idelta [chan] ; chan_idelta [chan] = (AdaptationTable [bytecode] * idelta) >> 8 ; /* => / 256 => FIXED_POINT_ADAPTATION_BASE == 256 */ if (chan_idelta [chan] < 16) chan_idelta [chan] = 16 ; if (bytecode & 0x8) bytecode -= 0x10 ; predict = ((pms->samples [k - pms->channels] * AdaptCoeff1 [bpred [chan]]) + (pms->samples [k - 2 * pms->channels] * AdaptCoeff2 [bpred [chan]])) >> 8 ; /* => / 256 => FIXED_POINT_COEFF_BASE == 256 */ current = (bytecode * idelta) + predict ; if (current > 32767) current = 32767 ; else if (current < -32768) current = -32768 ; pms->samples [k] = current ; } ; return 1 ; } /* msadpcm_decode_block */ static sf_count_t msadpcm_read_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { if (pms->blockcount >= pms->blocks && pms->samplecount >= pms->samplesperblock) { memset (&(ptr [indx]), 0, (size_t) ((len - indx) * sizeof (short))) ; return total ; } ; if (pms->samplecount >= pms->samplesperblock) msadpcm_decode_block (psf, pms) ; count = (pms->samplesperblock - pms->samplecount) * pms->channels ; count = (len - indx > count) ? count : len - indx ; memcpy (&(ptr [indx]), &(pms->samples [pms->samplecount * pms->channels]), count * sizeof (short)) ; indx += count ; pms->samplecount += count / pms->channels ; total = indx ; } ; return total ; } /* msadpcm_read_block */ static sf_count_t msadpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; int readcount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; while (len > 0) { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = msadpcm_read_block (psf, pms, ptr, readcount) ; total += count ; len -= count ; if (count != readcount) break ; } ; return total ; } /* msadpcm_read_s */ static sf_count_t msadpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = msadpcm_read_block (psf, pms, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = sptr [k] << 16 ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* msadpcm_read_i */ static sf_count_t msadpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = msadpcm_read_block (psf, pms, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (float) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* msadpcm_read_f */ static sf_count_t msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = msadpcm_read_block (psf, pms, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (double) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* msadpcm_read_d */ static sf_count_t msadpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { MSADPCM_PRIVATE *pms ; int newblock, newsample ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; if (psf->datalength < 0 || psf->dataoffset < 0) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (offset == 0) { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; pms->blockcount = 0 ; msadpcm_decode_block (psf, pms) ; pms->samplecount = 0 ; return 0 ; } ; if (offset < 0 || offset > pms->blocks * pms->samplesperblock) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; newblock = offset / pms->samplesperblock ; newsample = offset % pms->samplesperblock ; if (mode == SFM_READ) { psf_fseek (psf, psf->dataoffset + newblock * pms->blocksize, SEEK_SET) ; pms->blockcount = newblock ; msadpcm_decode_block (psf, pms) ; pms->samplecount = newsample ; } else { /* What to do about write??? */ psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; return newblock * pms->samplesperblock + newsample ; } /* msadpcm_seek */ /*========================================================================================== ** MS ADPCM Write Functions. */ void msadpcm_write_adapt_coeffs (SF_PRIVATE *psf) { int k ; for (k = 0 ; k < MSADPCM_ADAPT_COEFF_COUNT ; k++) psf_binheader_writef (psf, "22", AdaptCoeff1 [k], AdaptCoeff2 [k]) ; } /* msadpcm_write_adapt_coeffs */ /*========================================================================================== */ static int msadpcm_encode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) { unsigned int blockindx ; unsigned char byte ; int chan, k, predict, bpred [2], idelta [2], errordelta, newsamp ; choose_predictor (pms->channels, pms->samples, bpred, idelta) ; /* Write the block header. */ if (pms->channels == 1) { pms->block [0] = bpred [0] ; pms->block [1] = idelta [0] & 0xFF ; pms->block [2] = idelta [0] >> 8 ; pms->block [3] = pms->samples [1] & 0xFF ; pms->block [4] = pms->samples [1] >> 8 ; pms->block [5] = pms->samples [0] & 0xFF ; pms->block [6] = pms->samples [0] >> 8 ; blockindx = 7 ; byte = 0 ; /* Encode the samples as 4 bit. */ for (k = 2 ; k < pms->samplesperblock ; k++) { predict = (pms->samples [k-1] * AdaptCoeff1 [bpred [0]] + pms->samples [k-2] * AdaptCoeff2 [bpred [0]]) >> 8 ; errordelta = (pms->samples [k] - predict) / idelta [0] ; if (errordelta < -8) errordelta = -8 ; else if (errordelta > 7) errordelta = 7 ; newsamp = predict + (idelta [0] * errordelta) ; if (newsamp > 32767) newsamp = 32767 ; else if (newsamp < -32768) newsamp = -32768 ; if (errordelta < 0) errordelta += 0x10 ; byte = (byte << 4) | (errordelta & 0xF) ; if (k % 2) { pms->block [blockindx++] = byte ; byte = 0 ; } ; idelta [0] = (idelta [0] * AdaptationTable [errordelta]) >> 8 ; if (idelta [0] < 16) idelta [0] = 16 ; pms->samples [k] = newsamp ; } ; } else { /* Stereo file. */ pms->block [0] = bpred [0] ; pms->block [1] = bpred [1] ; pms->block [2] = idelta [0] & 0xFF ; pms->block [3] = idelta [0] >> 8 ; pms->block [4] = idelta [1] & 0xFF ; pms->block [5] = idelta [1] >> 8 ; pms->block [6] = pms->samples [2] & 0xFF ; pms->block [7] = pms->samples [2] >> 8 ; pms->block [8] = pms->samples [3] & 0xFF ; pms->block [9] = pms->samples [3] >> 8 ; pms->block [10] = pms->samples [0] & 0xFF ; pms->block [11] = pms->samples [0] >> 8 ; pms->block [12] = pms->samples [1] & 0xFF ; pms->block [13] = pms->samples [1] >> 8 ; blockindx = 14 ; byte = 0 ; chan = 1 ; for (k = 4 ; k < 2 * pms->samplesperblock ; k++) { chan = k & 1 ; predict = (pms->samples [k-2] * AdaptCoeff1 [bpred [chan]] + pms->samples [k-4] * AdaptCoeff2 [bpred [chan]]) >> 8 ; errordelta = (pms->samples [k] - predict) / idelta [chan] ; if (errordelta < -8) errordelta = -8 ; else if (errordelta > 7) errordelta = 7 ; newsamp = predict + (idelta [chan] * errordelta) ; if (newsamp > 32767) newsamp = 32767 ; else if (newsamp < -32768) newsamp = -32768 ; if (errordelta < 0) errordelta += 0x10 ; byte = (byte << 4) | (errordelta & 0xF) ; if (chan) { pms->block [blockindx++] = byte ; byte = 0 ; } ; idelta [chan] = (idelta [chan] * AdaptationTable [errordelta]) >> 8 ; if (idelta [chan] < 16) idelta [chan] = 16 ; pms->samples [k] = newsamp ; } ; } ; /* Write the block to disk. */ if ((k = psf_fwrite (pms->block, 1, pms->blocksize, psf)) != pms->blocksize) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pms->blocksize) ; memset (pms->samples, 0, pms->samplesperblock * sizeof (short)) ; pms->blockcount ++ ; pms->samplecount = 0 ; return 1 ; } /* msadpcm_encode_block */ static sf_count_t msadpcm_write_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, const short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { count = (pms->samplesperblock - pms->samplecount) * pms->channels ; if (count > len - indx) count = len - indx ; memcpy (&(pms->samples [pms->samplecount * pms->channels]), &(ptr [total]), count * sizeof (short)) ; indx += count ; pms->samplecount += count / pms->channels ; total = indx ; if (pms->samplecount >= pms->samplesperblock) msadpcm_encode_block (psf, pms) ; } ; return total ; } /* msadpcm_write_block */ static sf_count_t msadpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; int writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; while (len > 0) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = msadpcm_write_block (psf, pms, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* msadpcm_write_s */ static sf_count_t msadpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = ptr [total + k] >> 16 ; count = msadpcm_write_block (psf, pms, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* msadpcm_write_i */ static sf_count_t msadpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrintf (normfact * ptr [total + k]) ; count = msadpcm_write_block (psf, pms, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* msadpcm_write_f */ static sf_count_t msadpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { MSADPCM_PRIVATE *pms ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; if (! psf->codec_data) return 0 ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrint (normfact * ptr [total + k]) ; count = msadpcm_write_block (psf, pms, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* msadpcm_write_d */ /*======================================================================================== */ static int msadpcm_close (SF_PRIVATE *psf) { MSADPCM_PRIVATE *pms ; pms = (MSADPCM_PRIVATE*) psf->codec_data ; if (psf->mode == SFM_WRITE) { /* Now we know static int for certain the length of the file we can ** re-write the header. */ if (pms->samplecount && pms->samplecount < pms->samplesperblock) msadpcm_encode_block (psf, pms) ; } ; return 0 ; } /* msadpcm_close */ /*======================================================================================== ** Static functions. */ /*---------------------------------------------------------------------------------------- ** Choosing the block predictor. ** Each block requires a predictor and an idelta for each channel. ** The predictor is in the range [0..6] which is an indx into the two AdaptCoeff tables. ** The predictor is chosen by trying all of the possible predictors on a small set of ** samples at the beginning of the block. The predictor with the smallest average ** abs (idelta) is chosen as the best predictor for this block. ** The value of idelta is chosen to to give a 4 bit code value of +/- 4 (approx. half the ** max. code value). If the average abs (idelta) is zero, the sixth predictor is chosen. ** If the value of idelta is less then 16 it is set to 16. ** ** Microsoft uses an IDELTA_COUNT (number of sample pairs used to choose best predictor) ** value of 3. The best possible results would be obtained by using all the samples to ** choose the predictor. */ #define IDELTA_COUNT 3 static void choose_predictor (unsigned int channels, short *data, int *block_pred, int *idelta) { unsigned int chan, k, bpred, idelta_sum, best_bpred, best_idelta ; for (chan = 0 ; chan < channels ; chan++) { best_bpred = best_idelta = 0 ; for (bpred = 0 ; bpred < 7 ; bpred++) { idelta_sum = 0 ; for (k = 2 ; k < 2 + IDELTA_COUNT ; k++) idelta_sum += abs (data [k * channels] - ((data [(k - 1) * channels] * AdaptCoeff1 [bpred] + data [(k - 2) * channels] * AdaptCoeff2 [bpred]) >> 8)) ; idelta_sum /= (4 * IDELTA_COUNT) ; if (bpred == 0 || idelta_sum < best_idelta) { best_bpred = bpred ; best_idelta = idelta_sum ; } ; if (! idelta_sum) { best_bpred = bpred ; best_idelta = 16 ; break ; } ; } ; /* for bpred ... */ if (best_idelta < 16) best_idelta = 16 ; block_pred [chan] = best_bpred ; idelta [chan] = best_idelta ; } ; return ; } /* choose_predictor */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: a98908a3-5305-4935-872b-77d6a86c330f */ nyquist-3.05/nylsf/raw.c0000644000175000000620000000535011466723256014272 0ustar stevestaff/* ** Copyright (C) 1999-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include "sndfile.h" #include "common.h" /*------------------------------------------------------------------------------ ** Public function. */ int raw_open (SF_PRIVATE *psf) { int subformat, error = SFE_NO_ERROR ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)) psf->endian = SF_ENDIAN_BIG ; else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)) psf->endian = SF_ENDIAN_LITTLE ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; psf->dataoffset = 0 ; psf->datalength = psf->filelength ; switch (subformat) { case SF_FORMAT_PCM_S8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_U8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; case SF_FORMAT_GSM610 : error = gsm610_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; case SF_FORMAT_DWVW_12 : error = dwvw_init (psf, 12) ; break ; case SF_FORMAT_DWVW_16 : error = dwvw_init (psf, 16) ; break ; case SF_FORMAT_DWVW_24 : error = dwvw_init (psf, 24) ; break ; case SF_FORMAT_VOX_ADPCM : error = vox_adpcm_init (psf) ; break ; /* Lite remove end */ default : return SFE_BAD_OPEN_FORMAT ; } ; return error ; } /* raw_open */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: f0066de7-d6ce-4f36-a1e0-e475c07d4e1a */ nyquist-3.05/nylsf/ima_adpcm.c0000644000175000000620000006473211466723256015424 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" typedef struct IMA_ADPCM_PRIVATE_tag { int (*decode_block) (SF_PRIVATE *psf, struct IMA_ADPCM_PRIVATE_tag *pima) ; int (*encode_block) (SF_PRIVATE *psf, struct IMA_ADPCM_PRIVATE_tag *pima) ; int channels, blocksize, samplesperblock, blocks ; int blockcount, samplecount ; int previous [2] ; int stepindx [2] ; unsigned char *block ; short *samples ; #if HAVE_FLEXIBLE_ARRAY short data [] ; /* ISO C99 struct flexible array. */ #else short data [0] ; /* This is a hack and might not work. */ #endif } IMA_ADPCM_PRIVATE ; /*============================================================================================ ** Predefined IMA ADPCM data. */ static int ima_indx_adjust [16] = { -1, -1, -1, -1, /* +0 - +3, decrease the step size */ 2, 4, 6, 8, /* +4 - +7, increase the step size */ -1, -1, -1, -1, /* -0 - -3, decrease the step size */ 2, 4, 6, 8, /* -4 - -7, increase the step size */ } ; static int ima_step_size [89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 } ; static int ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; static int ima_writer_init (SF_PRIVATE *psf, int blockalign) ; static int ima_read_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, short *ptr, int len) ; static int ima_write_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, const short *ptr, int len) ; static sf_count_t ima_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t ima_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t ima_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t ima_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t ima_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t ima_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t ima_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t ima_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int ima_close (SF_PRIVATE *psf) ; static int wav_w64_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; static int wav_w64_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; /*-static int aiff_ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;-*/ static int aiff_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; static int aiff_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; /*============================================================================================ ** IMA ADPCM Reader initialisation function. */ int wav_w64_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) { int error ; if (psf->codec_data != NULL) { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; return SFE_INTERNAL ; } ; if (psf->mode == SFM_RDWR) return SFE_BAD_MODE_RW ; if (psf->mode == SFM_READ) if ((error = ima_reader_init (psf, blockalign, samplesperblock))) return error ; if (psf->mode == SFM_WRITE) if ((error = ima_writer_init (psf, blockalign))) return error ; psf->codec_close = ima_close ; psf->seek = ima_seek ; return 0 ; } /* wav_w64_ima_init */ int aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) { int error ; if (psf->mode == SFM_RDWR) return SFE_BAD_MODE_RW ; if (psf->mode == SFM_READ) if ((error = ima_reader_init (psf, blockalign, samplesperblock))) return error ; if (psf->mode == SFM_WRITE) if ((error = ima_writer_init (psf, blockalign))) return error ; psf->codec_close = ima_close ; return 0 ; } /* aiff_ima_init */ static int ima_close (SF_PRIVATE *psf) { IMA_ADPCM_PRIVATE *pima ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; if (psf->mode == SFM_WRITE) { /* If a block has been partially assembled, write it out ** as the final block. */ if (pima->samplecount && pima->samplecount < pima->samplesperblock) pima->encode_block (psf, pima) ; psf->sf.frames = pima->samplesperblock * pima->blockcount / psf->sf.channels ; } ; return 0 ; } /* ima_close */ /*============================================================================================ ** IMA ADPCM Read Functions. */ static int ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) { IMA_ADPCM_PRIVATE *pima ; int pimasize, count ; if (psf->mode != SFM_READ) return SFE_BAD_MODE_RW ; pimasize = sizeof (IMA_ADPCM_PRIVATE) + blockalign * psf->sf.channels + 3 * psf->sf.channels * samplesperblock ; if (! (pima = malloc (pimasize))) return SFE_MALLOC_FAILED ; psf->codec_data = (void*) pima ; memset (pima, 0, pimasize) ; pima->samples = pima->data ; pima->block = (unsigned char*) (pima->data + samplesperblock * psf->sf.channels) ; pima->channels = psf->sf.channels ; pima->blocksize = blockalign ; pima->samplesperblock = samplesperblock ; psf->filelength = psf_get_filelen (psf) ; psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; if (psf->datalength % pima->blocksize) pima->blocks = psf->datalength / pima->blocksize + 1 ; else pima->blocks = psf->datalength / pima->blocksize ; switch (psf->sf.format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : case SF_FORMAT_W64 : count = 2 * (pima->blocksize - 4 * pima->channels) / pima->channels + 1 ; if (pima->samplesperblock != count) psf_log_printf (psf, "*** Warning : samplesperblock should be %d.\n", count) ; pima->decode_block = wav_w64_ima_decode_block ; psf->sf.frames = pima->samplesperblock * pima->blocks ; break ; case SF_FORMAT_AIFF : psf_log_printf (psf, "still need to check block count\n") ; pima->decode_block = aiff_ima_decode_block ; psf->sf.frames = pima->samplesperblock * pima->blocks / pima->channels ; break ; default : psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ; return SFE_INTERNAL ; break ; } ; pima->decode_block (psf, pima) ; /* Read first block. */ psf->read_short = ima_read_s ; psf->read_int = ima_read_i ; psf->read_float = ima_read_f ; psf->read_double = ima_read_d ; return 0 ; } /* ima_reader_init */ static int aiff_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) { unsigned char *blockdata ; int chan, k, diff, bytecode ; short step, stepindx, predictor, *sampledata ; static int count = 0 ; count ++ ; pima->blockcount += pima->channels ; pima->samplecount = 0 ; if (pima->blockcount > pima->blocks) { memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ; return 1 ; } ; if ((k = psf_fread (pima->block, 1, pima->blocksize * pima->channels, psf)) != pima->blocksize * pima->channels) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pima->blocksize) ; /* Read and check the block header. */ for (chan = 0 ; chan < pima->channels ; chan++) { blockdata = pima->block + chan * 34 ; sampledata = pima->samples + chan ; predictor = (blockdata [0] << 8) | (blockdata [1] & 0x80) ; stepindx = blockdata [1] & 0x7F ; { if (count < 5) printf ("\nchan: %d predictor: %d stepindx: %d (%d)\n", chan, predictor, stepindx, ima_step_size [stepindx]) ; } /* FIXME : Do this a better way. */ if (stepindx < 0) stepindx = 0 ; else if (stepindx > 88) stepindx = 88 ; /* ** Pull apart the packed 4 bit samples and store them in their ** correct sample positions. */ for (k = 0 ; k < pima->blocksize - 2 ; k++) { bytecode = blockdata [k + 2] ; sampledata [pima->channels * (2 * k + 0)] = bytecode & 0xF ; sampledata [pima->channels * (2 * k + 1)] = (bytecode >> 4) & 0xF ; } ; /* Decode the encoded 4 bit samples. */ for (k = 0 ; k < pima->samplesperblock ; k ++) { step = ima_step_size [stepindx] ; bytecode = pima->samples [pima->channels * k + chan] ; stepindx += ima_indx_adjust [bytecode] ; if (stepindx < 0) stepindx = 0 ; else if (stepindx > 88) stepindx = 88 ; diff = step >> 3 ; if (bytecode & 1) diff += step >> 2 ; if (bytecode & 2) diff += step >> 1 ; if (bytecode & 4) diff += step ; if (bytecode & 8) diff = -diff ; predictor += diff ; pima->samples [pima->channels * k + chan] = predictor ; } ; } ; if (count < 5) { for (k = 0 ; k < 10 ; k++) printf ("% 7d,", pima->samples [k]) ; puts ("") ; } return 1 ; } /* aiff_ima_decode_block */ static int aiff_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) { int chan, k, step, diff, vpdiff, blockindx, indx ; short bytecode, mask ; static int count = 0 ; if (0 && count == 0) { pima->samples [0] = 0 ; printf ("blocksize : %d\n", pima->blocksize) ; printf ("pima->stepindx [0] : %d\n", pima->stepindx [0]) ; } count ++ ; /* Encode the block header. */ for (chan = 0 ; chan < pima->channels ; chan ++) { blockindx = chan * pima->blocksize ; pima->block [blockindx] = (pima->samples [chan] >> 8) & 0xFF ; pima->block [blockindx + 1] = (pima->samples [chan] & 0x80) + (pima->stepindx [chan] & 0x7F) ; pima->previous [chan] = pima->samples [chan] ; } ; /* Encode second and later samples for every block as a 4 bit value. */ for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++) { chan = (pima->channels > 1) ? (k % 2) : 0 ; diff = pima->samples [k] - pima->previous [chan] ; bytecode = 0 ; step = ima_step_size [pima->stepindx [chan]] ; vpdiff = step >> 3 ; if (diff < 0) { bytecode = 8 ; diff = -diff ; } ; mask = 4 ; while (mask) { if (diff >= step) { bytecode |= mask ; diff -= step ; vpdiff += step ; } ; step >>= 1 ; mask >>= 1 ; } ; if (bytecode & 8) pima->previous [chan] -= vpdiff ; else pima->previous [chan] += vpdiff ; if (pima->previous [chan] > 32767) pima->previous [chan] = 32767 ; else if (pima->previous [chan] < -32768) pima->previous [chan] = -32768 ; pima->stepindx [chan] += ima_indx_adjust [bytecode] ; if (pima->stepindx [chan] < 0) pima->stepindx [chan] = 0 ; else if (pima->stepindx [chan] > 88) pima->stepindx [chan] = 88 ; pima->samples [k] = bytecode ; } ; /* Pack the 4 bit encoded samples. */ for (chan = 0 ; chan < pima->channels ; chan ++) { for (indx = pima->channels ; indx < pima->channels * pima->samplesperblock ; indx += 2 * pima->channels) { blockindx = chan * pima->blocksize + 2 + indx / 2 ; if (0 && count ++ < 5) printf ("chan: %d blockindx: %3d indx: %3d\n", chan, blockindx, indx) ; pima->block [blockindx] = pima->samples [indx] & 0x0F ; pima->block [blockindx] |= (pima->samples [indx + pima->channels] << 4) & 0xF0 ; } ; } ; /* Write the block to disk. */ if ((k = psf_fwrite (pima->block, 1, pima->channels * pima->blocksize, psf)) != pima->channels * pima->blocksize) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pima->channels * pima->blocksize) ; memset (pima->samples, 0, pima->channels * pima->samplesperblock * sizeof (short)) ; pima->samplecount = 0 ; pima->blockcount ++ ; return 1 ; } /* aiff_ima_encode_block */ static int wav_w64_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) { int chan, k, current, blockindx, indx, indxstart, diff ; short step, bytecode, stepindx [2] ; pima->blockcount ++ ; pima->samplecount = 0 ; if (pima->blockcount > pima->blocks) { memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ; return 1 ; } ; if ((k = psf_fread (pima->block, 1, pima->blocksize, psf)) != pima->blocksize) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pima->blocksize) ; /* Read and check the block header. */ for (chan = 0 ; chan < pima->channels ; chan++) { current = pima->block [chan*4] | (pima->block [chan*4+1] << 8) ; if (current & 0x8000) current -= 0x10000 ; stepindx [chan] = pima->block [chan*4+2] ; if (stepindx [chan] < 0) stepindx [chan] = 0 ; else if (stepindx [chan] > 88) stepindx [chan] = 88 ; if (pima->block [chan*4+3] != 0) psf_log_printf (psf, "IMA ADPCM synchronisation error.\n") ; pima->samples [chan] = current ; } ; /* ** Pull apart the packed 4 bit samples and store them in their ** correct sample positions. */ blockindx = 4 * pima->channels ; indxstart = pima->channels ; while (blockindx < pima->blocksize) { for (chan = 0 ; chan < pima->channels ; chan++) { indx = indxstart + chan ; for (k = 0 ; k < 4 ; k++) { bytecode = pima->block [blockindx++] ; pima->samples [indx] = bytecode & 0x0F ; indx += pima->channels ; pima->samples [indx] = (bytecode >> 4) & 0x0F ; indx += pima->channels ; } ; } ; indxstart += 8 * pima->channels ; } ; /* Decode the encoded 4 bit samples. */ for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++) { chan = (pima->channels > 1) ? (k % 2) : 0 ; bytecode = pima->samples [k] & 0xF ; step = ima_step_size [stepindx [chan]] ; current = pima->samples [k - pima->channels] ; diff = step >> 3 ; if (bytecode & 1) diff += step >> 2 ; if (bytecode & 2) diff += step >> 1 ; if (bytecode & 4) diff += step ; if (bytecode & 8) diff = -diff ; current += diff ; if (current > 32767) current = 32767 ; else if (current < -32768) current = -32768 ; stepindx [chan] += ima_indx_adjust [bytecode] ; if (stepindx [chan] < 0) stepindx [chan] = 0 ; else if (stepindx [chan] > 88) stepindx [chan] = 88 ; pima->samples [k] = current ; } ; return 1 ; } /* wav_w64_ima_decode_block */ static int wav_w64_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) { int chan, k, step, diff, vpdiff, blockindx, indx, indxstart ; short bytecode, mask ; /* Encode the block header. */ for (chan = 0 ; chan < pima->channels ; chan++) { pima->block [chan*4] = pima->samples [chan] & 0xFF ; pima->block [chan*4+1] = (pima->samples [chan] >> 8) & 0xFF ; pima->block [chan*4+2] = pima->stepindx [chan] ; pima->block [chan*4+3] = 0 ; pima->previous [chan] = pima->samples [chan] ; } ; /* Encode the samples as 4 bit. */ for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++) { chan = (pima->channels > 1) ? (k % 2) : 0 ; diff = pima->samples [k] - pima->previous [chan] ; bytecode = 0 ; step = ima_step_size [pima->stepindx [chan]] ; vpdiff = step >> 3 ; if (diff < 0) { bytecode = 8 ; diff = -diff ; } ; mask = 4 ; while (mask) { if (diff >= step) { bytecode |= mask ; diff -= step ; vpdiff += step ; } ; step >>= 1 ; mask >>= 1 ; } ; if (bytecode & 8) pima->previous [chan] -= vpdiff ; else pima->previous [chan] += vpdiff ; if (pima->previous [chan] > 32767) pima->previous [chan] = 32767 ; else if (pima->previous [chan] < -32768) pima->previous [chan] = -32768 ; pima->stepindx [chan] += ima_indx_adjust [bytecode] ; if (pima->stepindx [chan] < 0) pima->stepindx [chan] = 0 ; else if (pima->stepindx [chan] > 88) pima->stepindx [chan] = 88 ; pima->samples [k] = bytecode ; } ; /* Pack the 4 bit encoded samples. */ blockindx = 4 * pima->channels ; indxstart = pima->channels ; while (blockindx < pima->blocksize) { for (chan = 0 ; chan < pima->channels ; chan++) { indx = indxstart + chan ; for (k = 0 ; k < 4 ; k++) { pima->block [blockindx] = pima->samples [indx] & 0x0F ; indx += pima->channels ; pima->block [blockindx] |= (pima->samples [indx] << 4) & 0xF0 ; indx += pima->channels ; blockindx ++ ; } ; } ; indxstart += 8 * pima->channels ; } ; /* Write the block to disk. */ if ((k = psf_fwrite (pima->block, 1, pima->blocksize, psf)) != pima->blocksize) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pima->blocksize) ; memset (pima->samples, 0, pima->samplesperblock * sizeof (short)) ; pima->samplecount = 0 ; pima->blockcount ++ ; return 1 ; } /* wav_w64_ima_encode_block */ static int ima_read_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { if (pima->blockcount >= pima->blocks && pima->samplecount >= pima->samplesperblock) { memset (&(ptr [indx]), 0, (size_t) ((len - indx) * sizeof (short))) ; return total ; } ; if (pima->samplecount >= pima->samplesperblock) pima->decode_block (psf, pima) ; count = (pima->samplesperblock - pima->samplecount) * pima->channels ; count = (len - indx > count) ? count : len - indx ; memcpy (&(ptr [indx]), &(pima->samples [pima->samplecount * pima->channels]), count * sizeof (short)) ; indx += count ; pima->samplecount += count / pima->channels ; total = indx ; } ; return total ; } /* ima_read_block */ static sf_count_t ima_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; int readcount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; while (len > 0) { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = ima_read_block (psf, pima, ptr, readcount) ; total += count ; len -= count ; if (count != readcount) break ; } ; return total ; } /* ima_read_s */ static sf_count_t ima_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; short *sptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : (int) len ; count = ima_read_block (psf, pima, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = ((int) sptr [k]) << 16 ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* ima_read_i */ static sf_count_t ima_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; short *sptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : (int) len ; count = ima_read_block (psf, pima, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (float) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* ima_read_f */ static sf_count_t ima_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; short *sptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; double normfact ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : (int) len ; count = ima_read_block (psf, pima, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (double) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* ima_read_d */ static sf_count_t ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { IMA_ADPCM_PRIVATE *pima ; int newblock, newsample ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; if (psf->datalength < 0 || psf->dataoffset < 0) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (offset == 0) { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; pima->blockcount = 0 ; pima->decode_block (psf, pima) ; pima->samplecount = 0 ; return 0 ; } ; if (offset < 0 || offset > pima->blocks * pima->samplesperblock) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; newblock = offset / pima->samplesperblock ; newsample = offset % pima->samplesperblock ; if (mode == SFM_READ) { psf_fseek (psf, psf->dataoffset + newblock * pima->blocksize, SEEK_SET) ; pima->blockcount = newblock ; pima->decode_block (psf, pima) ; pima->samplecount = newsample ; } else { /* What to do about write??? */ psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; return newblock * pima->samplesperblock + newsample ; } /* ima_seek */ /*========================================================================================== ** IMA ADPCM Write Functions. */ static int ima_writer_init (SF_PRIVATE *psf, int blockalign) { IMA_ADPCM_PRIVATE *pima ; int samplesperblock ; unsigned int pimasize ; if (psf->mode != SFM_WRITE) return SFE_BAD_MODE_RW ; samplesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ; pimasize = sizeof (IMA_ADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ; if ((pima = calloc (1, pimasize)) == NULL) return SFE_MALLOC_FAILED ; psf->codec_data = (void*) pima ; pima->channels = psf->sf.channels ; pima->blocksize = blockalign ; pima->samplesperblock = samplesperblock ; pima->block = (unsigned char*) pima->data ; pima->samples = (short*) (pima->data + blockalign) ; pima->samplecount = 0 ; switch (psf->sf.format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : case SF_FORMAT_W64 : pima->encode_block = wav_w64_ima_encode_block ; break ; case SF_FORMAT_AIFF : pima->encode_block = aiff_ima_encode_block ; break ; default : psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ; return SFE_INTERNAL ; break ; } ; psf->write_short = ima_write_s ; psf->write_int = ima_write_i ; psf->write_float = ima_write_f ; psf->write_double = ima_write_d ; return 0 ; } /* ima_writer_init */ /*========================================================================================== */ static int ima_write_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, const short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { count = (pima->samplesperblock - pima->samplecount) * pima->channels ; if (count > len - indx) count = len - indx ; memcpy (&(pima->samples [pima->samplecount * pima->channels]), &(ptr [total]), count * sizeof (short)) ; indx += count ; pima->samplecount += count / pima->channels ; total = indx ; if (pima->samplecount >= pima->samplesperblock) pima->encode_block (psf, pima) ; } ; return total ; } /* ima_write_block */ static sf_count_t ima_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; int writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; while (len) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = ima_write_block (psf, pima, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* ima_write_s */ static sf_count_t ima_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; for (k = 0 ; k < writecount ; k++) sptr [k] = ptr [total + k] >> 16 ; count = ima_write_block (psf, pima, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* ima_write_i */ static sf_count_t ima_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrintf (normfact * ptr [total + k]) ; count = ima_write_block (psf, pima, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* ima_write_f */ static sf_count_t ima_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { IMA_ADPCM_PRIVATE *pima ; short *sptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; double normfact ; if (! psf->codec_data) return 0 ; pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : (int) len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrint (normfact * ptr [total + k]) ; count = ima_write_block (psf, pima, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* ima_write_d */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 75a54b82-ad18-4758-9933-64e00a7f24e0 */ nyquist-3.05/nylsf/pvf.c0000644000175000000620000001207711466723256014300 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define PVF1_MARKER (MAKE_MARKER ('P', 'V', 'F', '1')) /*------------------------------------------------------------------------------ ** Private static functions. */ static int pvf_close (SF_PRIVATE *psf) ; static int pvf_write_header (SF_PRIVATE *psf, int calc_length) ; static int pvf_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int pvf_open (SF_PRIVATE *psf) { int subformat ; int error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = pvf_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_PVF) return SFE_BAD_OPEN_FORMAT ; psf->endian = SF_ENDIAN_BIG ; if (pvf_write_header (psf, SF_FALSE)) return psf->error ; psf->write_header = pvf_write_header ; } ; psf->container_close = pvf_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ error = pcm_init (psf) ; break ; default : break ; } ; return error ; } /* pvf_open */ /*------------------------------------------------------------------------------ */ static int pvf_close (SF_PRIVATE *psf) { psf = psf ; return 0 ; } /* pvf_close */ static int pvf_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; if (psf->pipeoffset > 0) return 0 ; calc_length = calc_length ; /* Avoid a compiler warning. */ current = psf_ftell (psf) ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; if (psf->is_pipe == SF_FALSE) psf_fseek (psf, 0, SEEK_SET) ; LSF_SNPRINTF ((char*) psf->header, sizeof (psf->header), "PVF1\n%d %d %d\n", psf->sf.channels, psf->sf.samplerate, psf->bytewidth * 8) ; psf->headindex = strlen ((char*) psf->header) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* pvf_write_header */ static int pvf_read_header (SF_PRIVATE *psf) { char buffer [32] ; int marker, channels, samplerate, bitwidth ; psf_binheader_readf (psf, "pmj", 0, &marker, 1) ; psf_log_printf (psf, "%M\n", marker) ; if (marker != PVF1_MARKER) return SFE_PVF_NO_PVF1 ; /* Grab characters up until a newline which is replaced by an EOS. */ psf_binheader_readf (psf, "G", buffer, sizeof (buffer)) ; if (sscanf (buffer, "%d %d %d", &channels, &samplerate, &bitwidth) != 3) return SFE_PVF_BAD_HEADER ; psf_log_printf (psf, " Channels : %d\n Sample rate : %d\n Bit width : %d\n", channels, samplerate, bitwidth) ; psf->sf.channels = channels ; psf->sf.samplerate = samplerate ; switch (bitwidth) { case 8 : psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_S8 ; psf->bytewidth = 1 ; break ; case 16 : psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; case 32 : psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_32 ; psf->bytewidth = 4 ; break ; default : return SFE_PVF_BAD_BITWIDTH ; } ; psf->dataoffset = psf_ftell (psf) ; psf_log_printf (psf, " Data Offset : %D\n", psf->dataoffset) ; psf->endian = SF_ENDIAN_BIG ; psf->datalength = psf->filelength - psf->dataoffset ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; if (! psf->sf.frames && psf->blockwidth) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; return 0 ; } /* pvf_read_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 20a26761-8bc1-41d7-b1f3-9793bf3d9864 */ nyquist-3.05/nylsf/au.c0000644000175000000620000003235511466723256014113 0ustar stevestaff/* ** Copyright (C) 1999-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define DOTSND_MARKER (MAKE_MARKER ('.', 's', 'n', 'd')) #define DNSDOT_MARKER (MAKE_MARKER ('d', 'n', 's', '.')) #define AU_DATA_OFFSET 24 /*------------------------------------------------------------------------------ ** Known AU file encoding types. */ enum { AU_ENCODING_ULAW_8 = 1, /* 8-bit u-law samples */ AU_ENCODING_PCM_8 = 2, /* 8-bit linear samples */ AU_ENCODING_PCM_16 = 3, /* 16-bit linear samples */ AU_ENCODING_PCM_24 = 4, /* 24-bit linear samples */ AU_ENCODING_PCM_32 = 5, /* 32-bit linear samples */ AU_ENCODING_FLOAT = 6, /* floating-point samples */ AU_ENCODING_DOUBLE = 7, /* double-precision float samples */ AU_ENCODING_INDIRECT = 8, /* fragmented sampled data */ AU_ENCODING_NESTED = 9, /* ? */ AU_ENCODING_DSP_CORE = 10, /* DSP program */ AU_ENCODING_DSP_DATA_8 = 11, /* 8-bit fixed-point samples */ AU_ENCODING_DSP_DATA_16 = 12, /* 16-bit fixed-point samples */ AU_ENCODING_DSP_DATA_24 = 13, /* 24-bit fixed-point samples */ AU_ENCODING_DSP_DATA_32 = 14, /* 32-bit fixed-point samples */ AU_ENCODING_DISPLAY = 16, /* non-audio display data */ AU_ENCODING_MULAW_SQUELCH = 17, /* ? */ AU_ENCODING_EMPHASIZED = 18, /* 16-bit linear with emphasis */ AU_ENCODING_NEXT = 19, /* 16-bit linear with compression (NEXT) */ AU_ENCODING_COMPRESSED_EMPHASIZED = 20, /* A combination of the two above */ AU_ENCODING_DSP_COMMANDS = 21, /* Music Kit DSP commands */ AU_ENCODING_DSP_COMMANDS_SAMPLES = 22, /* ? */ AU_ENCODING_ADPCM_G721_32 = 23, /* G721 32 kbs ADPCM - 4 bits per sample. */ AU_ENCODING_ADPCM_G722 = 24, /* G722 64 kbs ADPCM */ AU_ENCODING_ADPCM_G723_24 = 25, /* G723 24 kbs ADPCM - 3 bits per sample. */ AU_ENCODING_ADPCM_G723_40 = 26, /* G723 40 kbs ADPCM - 5 bits per sample. */ AU_ENCODING_ALAW_8 = 27 } ; /*------------------------------------------------------------------------------ ** Typedefs. */ typedef struct { int dataoffset ; int datasize ; int encoding ; int samplerate ; int channels ; } AU_FMT ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int au_close (SF_PRIVATE *psf) ; static int au_format_to_encoding (int format) ; static int au_write_header (SF_PRIVATE *psf, int calc_length) ; static int au_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int au_open (SF_PRIVATE *psf) { int subformat ; int error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = au_read_header (psf))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AU) return SFE_BAD_OPEN_FORMAT ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU) psf->endian = SF_ENDIAN_LITTLE ; else if (psf->endian != SF_ENDIAN_LITTLE) psf->endian = SF_ENDIAN_BIG ; if (au_write_header (psf, SF_FALSE)) return psf->error ; psf->write_header = au_write_header ; } ; psf->container_close = au_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_ULAW : /* 8-bit Ulaw encoding. */ ulaw_init (psf) ; break ; case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */ case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ error = pcm_init (psf) ; break ; case SF_FORMAT_ALAW : /* 8-bit Alaw encoding. */ alaw_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : /* 32-bit floats. */ error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : /* 64-bit double precision floats. */ error = double64_init (psf) ; break ; case SF_FORMAT_G721_32 : error = g72x_init (psf) ; psf->sf.seekable = SF_FALSE ; break ; case SF_FORMAT_G723_24 : error = g72x_init (psf) ; psf->sf.seekable = SF_FALSE ; break ; case SF_FORMAT_G723_40 : error = g72x_init (psf) ; psf->sf.seekable = SF_FALSE ; break ; /* Lite remove end */ default : break ; } ; return error ; } /* au_open */ /*------------------------------------------------------------------------------ */ static int au_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) au_write_header (psf, SF_TRUE) ; return 0 ; } /* au_close */ static int au_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int encoding, datalength ; if (psf->pipeoffset > 0) return 0 ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; encoding = au_format_to_encoding (psf->sf.format & SF_FORMAT_SUBMASK) ; if (! encoding) return (psf->error = SFE_BAD_OPEN_FORMAT) ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; /* ** Only attempt to seek if we are not writng to a pipe. If we are ** writing to a pipe we shouldn't be here anyway. */ if (psf->is_pipe == SF_FALSE) psf_fseek (psf, 0, SEEK_SET) ; /* ** AU format files allow a datalength value of -1 if the datalength ** is not know at the time the header is written. ** Also use this value of -1 if the datalength > 2 gigabytes. */ if (psf->datalength < 0 || psf->datalength > 0x7FFFFFFF) datalength = -1 ; else datalength = (int) (psf->datalength & 0x7FFFFFFF) ; if (psf->endian == SF_ENDIAN_BIG) { psf_binheader_writef (psf, "Em4", DOTSND_MARKER, AU_DATA_OFFSET) ; psf_binheader_writef (psf, "E4444", datalength, encoding, psf->sf.samplerate, psf->sf.channels) ; } else if (psf->endian == SF_ENDIAN_LITTLE) { psf_binheader_writef (psf, "em4", DNSDOT_MARKER, AU_DATA_OFFSET) ; psf_binheader_writef (psf, "e4444", datalength, encoding, psf->sf.samplerate, psf->sf.channels) ; } else return (psf->error = SFE_BAD_OPEN_FORMAT) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* au_write_header */ static int au_format_to_encoding (int format) { switch (format) { case SF_FORMAT_PCM_S8 : return AU_ENCODING_PCM_8 ; case SF_FORMAT_PCM_16 : return AU_ENCODING_PCM_16 ; case SF_FORMAT_PCM_24 : return AU_ENCODING_PCM_24 ; case SF_FORMAT_PCM_32 : return AU_ENCODING_PCM_32 ; case SF_FORMAT_FLOAT : return AU_ENCODING_FLOAT ; case SF_FORMAT_DOUBLE : return AU_ENCODING_DOUBLE ; case SF_FORMAT_ULAW : return AU_ENCODING_ULAW_8 ; case SF_FORMAT_ALAW : return AU_ENCODING_ALAW_8 ; case SF_FORMAT_G721_32 : return AU_ENCODING_ADPCM_G721_32 ; case SF_FORMAT_G723_24 : return AU_ENCODING_ADPCM_G723_24 ; case SF_FORMAT_G723_40 : return AU_ENCODING_ADPCM_G723_40 ; default : break ; } ; return 0 ; } /* au_format_to_encoding */ static int au_read_header (SF_PRIVATE *psf) { AU_FMT au_fmt ; int marker, dword ; memset (&au_fmt, 0, sizeof (au_fmt)) ; psf_binheader_readf (psf, "pm", 0, &marker) ; psf_log_printf (psf, "%M\n", marker) ; if (marker == DOTSND_MARKER) { psf->endian = SF_ENDIAN_BIG ; psf_binheader_readf (psf, "E44444", &(au_fmt.dataoffset), &(au_fmt.datasize), &(au_fmt.encoding), &(au_fmt.samplerate), &(au_fmt.channels)) ; } else if (marker == DNSDOT_MARKER) { psf->endian = SF_ENDIAN_LITTLE ; psf_binheader_readf (psf, "e44444", &(au_fmt.dataoffset), &(au_fmt.datasize), &(au_fmt.encoding), &(au_fmt.samplerate), &(au_fmt.channels)) ; } else return SFE_AU_NO_DOTSND ; psf_log_printf (psf, " Data Offset : %d\n", au_fmt.dataoffset) ; if (psf->fileoffset > 0 && au_fmt.datasize == -1) { psf_log_printf (psf, " Data Size : -1\n") ; return SFE_AU_EMBED_BAD_LEN ; } ; if (psf->fileoffset > 0) { psf->filelength = au_fmt.dataoffset + au_fmt.datasize ; psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; } else if (au_fmt.datasize == -1 || au_fmt.dataoffset + au_fmt.datasize == psf->filelength) psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; else if (au_fmt.dataoffset + au_fmt.datasize < psf->filelength) { psf->filelength = au_fmt.dataoffset + au_fmt.datasize ; psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; } else { dword = psf->filelength - au_fmt.dataoffset ; psf_log_printf (psf, " Data Size : %d (should be %d)\n", au_fmt.datasize, dword) ; au_fmt.datasize = dword ; } ; psf->dataoffset = au_fmt.dataoffset ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf_ftell (psf) < psf->dataoffset) psf_binheader_readf (psf, "j", psf->dataoffset - psf_ftell (psf)) ; psf->sf.samplerate = au_fmt.samplerate ; psf->sf.channels = au_fmt.channels ; /* Only fill in type major. */ if (psf->endian == SF_ENDIAN_BIG) psf->sf.format = SF_FORMAT_AU ; else if (psf->endian == SF_ENDIAN_LITTLE) psf->sf.format = SF_ENDIAN_LITTLE | SF_FORMAT_AU ; psf_log_printf (psf, " Encoding : %d => ", au_fmt.encoding) ; psf->sf.format = psf->sf.format & SF_FORMAT_ENDMASK ; switch (au_fmt.encoding) { case AU_ENCODING_ULAW_8 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_ULAW ; psf->bytewidth = 1 ; /* Before decoding */ psf_log_printf (psf, "8-bit ISDN u-law\n") ; break ; case AU_ENCODING_PCM_8 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_S8 ; psf->bytewidth = 1 ; psf_log_printf (psf, "8-bit linear PCM\n") ; break ; case AU_ENCODING_PCM_16 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; psf_log_printf (psf, "16-bit linear PCM\n") ; break ; case AU_ENCODING_PCM_24 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_24 ; psf->bytewidth = 3 ; psf_log_printf (psf, "24-bit linear PCM\n") ; break ; case AU_ENCODING_PCM_32 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_32 ; psf->bytewidth = 4 ; psf_log_printf (psf, "32-bit linear PCM\n") ; break ; case AU_ENCODING_FLOAT : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_FLOAT ; psf->bytewidth = 4 ; psf_log_printf (psf, "32-bit float\n") ; break ; case AU_ENCODING_DOUBLE : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_DOUBLE ; psf->bytewidth = 8 ; psf_log_printf (psf, "64-bit double precision float\n") ; break ; case AU_ENCODING_ALAW_8 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_ALAW ; psf->bytewidth = 1 ; /* Before decoding */ psf_log_printf (psf, "8-bit ISDN A-law\n") ; break ; case AU_ENCODING_ADPCM_G721_32 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G721_32 ; psf->bytewidth = 0 ; psf_log_printf (psf, "G721 32kbs ADPCM\n") ; break ; case AU_ENCODING_ADPCM_G723_24 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G723_24 ; psf->bytewidth = 0 ; psf_log_printf (psf, "G723 24kbs ADPCM\n") ; break ; case AU_ENCODING_ADPCM_G723_40 : psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G723_40 ; psf->bytewidth = 0 ; psf_log_printf (psf, "G723 40kbs ADPCM\n") ; break ; case AU_ENCODING_ADPCM_G722 : psf_log_printf (psf, "G722 64 kbs ADPCM (unsupported)\n") ; break ; case AU_ENCODING_NEXT : psf_log_printf (psf, "Weird NeXT encoding format (unsupported)\n") ; break ; default : psf_log_printf (psf, "Unknown!!\n") ; break ; } ; psf_log_printf (psf, " Sample Rate : %d\n", au_fmt.samplerate) ; psf_log_printf (psf, " Channels : %d\n", au_fmt.channels) ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; if (! psf->sf.frames && psf->blockwidth) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; return 0 ; } /* au_read_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 31f691b1-cde9-4ed2-9469-6bca60fb9cd0 */ nyquist-3.05/nylsf/g72x.c0000644000175000000620000004065211466723256014274 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" #include "G72x/g72x.h" /* This struct is private to the G72x code. */ struct g72x_state ; typedef struct g72x_state G72x_STATE ; typedef struct { /* Private data. Don't mess with it. */ struct g72x_state * private ; /* Public data. Read only. */ int blocksize, samplesperblock, bytesperblock ; /* Public data. Read and write. */ int blocks_total, block_curr, sample_curr ; unsigned char block [G72x_BLOCK_SIZE] ; short samples [G72x_BLOCK_SIZE] ; } G72x_PRIVATE ; static int psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ; static int psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ; static sf_count_t g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t g72x_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int g72x_close (SF_PRIVATE *psf) ; /*============================================================================================ ** WAV G721 Reader initialisation function. */ int g72x_init (SF_PRIVATE * psf) { G72x_PRIVATE *pg72x ; int bitspersample, bytesperblock, codec ; if (psf->codec_data != NULL) { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; return SFE_INTERNAL ; } ; psf->sf.seekable = SF_FALSE ; if (psf->sf.channels != 1) return SFE_G72X_NOT_MONO ; if ((pg72x = calloc (1, sizeof (G72x_PRIVATE))) == NULL) return SFE_MALLOC_FAILED ; psf->codec_data = (void*) pg72x ; pg72x->block_curr = 0 ; pg72x->sample_curr = 0 ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_G721_32 : codec = G721_32_BITS_PER_SAMPLE ; bytesperblock = G721_32_BYTES_PER_BLOCK ; bitspersample = G721_32_BITS_PER_SAMPLE ; break ; case SF_FORMAT_G723_24: codec = G723_24_BITS_PER_SAMPLE ; bytesperblock = G723_24_BYTES_PER_BLOCK ; bitspersample = G723_24_BITS_PER_SAMPLE ; break ; case SF_FORMAT_G723_40: codec = G723_40_BITS_PER_SAMPLE ; bytesperblock = G723_40_BYTES_PER_BLOCK ; bitspersample = G723_40_BITS_PER_SAMPLE ; break ; default : return SFE_UNIMPLEMENTED ; } ; psf->blockwidth = psf->bytewidth = 1 ; psf->filelength = psf_get_filelen (psf) ; if (psf->filelength < psf->dataoffset) psf->filelength = psf->dataoffset ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend > 0) psf->datalength -= psf->filelength - psf->dataend ; if (psf->mode == SFM_READ) { pg72x->private = g72x_reader_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ; if (pg72x->private == NULL) return SFE_MALLOC_FAILED ; pg72x->bytesperblock = bytesperblock ; psf->read_short = g72x_read_s ; psf->read_int = g72x_read_i ; psf->read_float = g72x_read_f ; psf->read_double = g72x_read_d ; psf->seek = g72x_seek ; if (psf->datalength % pg72x->blocksize) { psf_log_printf (psf, "*** Odd psf->datalength (%D) should be a multiple of %d\n", psf->datalength, pg72x->blocksize) ; pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ; } else pg72x->blocks_total = psf->datalength / pg72x->blocksize ; psf->sf.frames = pg72x->blocks_total * pg72x->samplesperblock ; psf_g72x_decode_block (psf, pg72x) ; } else if (psf->mode == SFM_WRITE) { pg72x->private = g72x_writer_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ; if (pg72x->private == NULL) return SFE_MALLOC_FAILED ; pg72x->bytesperblock = bytesperblock ; psf->write_short = g72x_write_s ; psf->write_int = g72x_write_i ; psf->write_float = g72x_write_f ; psf->write_double = g72x_write_d ; if (psf->datalength % pg72x->blocksize) pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ; else pg72x->blocks_total = psf->datalength / pg72x->blocksize ; if (psf->datalength > 0) psf->sf.frames = (8 * psf->datalength) / bitspersample ; if ((psf->sf.frames * bitspersample) / 8 != psf->datalength) psf_log_printf (psf, "*** Warning : weird psf->datalength.\n") ; } ; psf->codec_close = g72x_close ; return 0 ; } /* g72x_init */ /*============================================================================================ ** G721 Read Functions. */ static int psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) { int k ; pg72x->block_curr ++ ; pg72x->sample_curr = 0 ; if (pg72x->block_curr > pg72x->blocks_total) { memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ; return 1 ; } ; if ((k = psf_fread (pg72x->block, 1, pg72x->bytesperblock, psf)) != pg72x->bytesperblock) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pg72x->bytesperblock) ; pg72x->blocksize = k ; g72x_decode_block (pg72x->private, pg72x->block, pg72x->samples) ; return 1 ; } /* psf_g72x_decode_block */ static int g72x_read_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { if (pg72x->block_curr > pg72x->blocks_total) { memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ; return total ; } ; if (pg72x->sample_curr >= pg72x->samplesperblock) psf_g72x_decode_block (psf, pg72x) ; count = pg72x->samplesperblock - pg72x->sample_curr ; count = (len - indx > count) ? count : len - indx ; memcpy (&(ptr [indx]), &(pg72x->samples [pg72x->sample_curr]), count * sizeof (short)) ; indx += count ; pg72x->sample_curr += count ; total = indx ; } ; return total ; } /* g72x_read_block */ static sf_count_t g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; int readcount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; while (len > 0) { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = g72x_read_block (psf, pg72x, ptr, readcount) ; total += count ; len -= count ; if (count != readcount) break ; } ; return total ; } /* g72x_read_s */ static sf_count_t g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = SF_BUFFER_LEN / sizeof (short) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = g72x_read_block (psf, pg72x, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = sptr [k] << 16 ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* g72x_read_i */ static sf_count_t g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = SF_BUFFER_LEN / sizeof (short) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = g72x_read_block (psf, pg72x, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * sptr [k] ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* g72x_read_f */ static sf_count_t g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; short *sptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = SF_BUFFER_LEN / sizeof (short) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = g72x_read_block (psf, pg72x, sptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (double) (sptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* g72x_read_d */ static sf_count_t g72x_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { /* Prevent compiler warnings. */ mode ++ ; offset ++ ; psf_log_printf (psf, "seek unsupported\n") ; /* No simple solution. To do properly, would need to seek ** to start of file and decode everything up to seek position. ** Maybe implement SEEK_SET to 0 only? */ return 0 ; /* ** G72x_PRIVATE *pg72x ; ** int newblock, newsample, sample_curr ; ** ** if (psf->codec_data == NULL) ** return 0 ; ** pg72x = (G72x_PRIVATE*) psf->codec_data ; ** ** if (! (psf->datalength && psf->dataoffset)) ** { psf->error = SFE_BAD_SEEK ; ** return PSF_SEEK_ERROR ; ** } ; ** ** sample_curr = (8 * psf->datalength) / G721_32_BITS_PER_SAMPLE ; ** ** switch (whence) ** { case SEEK_SET : ** if (offset < 0 || offset > sample_curr) ** { psf->error = SFE_BAD_SEEK ; ** return PSF_SEEK_ERROR ; ** } ; ** newblock = offset / pg72x->samplesperblock ; ** newsample = offset % pg72x->samplesperblock ; ** break ; ** ** case SEEK_CUR : ** if (psf->current + offset < 0 || psf->current + offset > sample_curr) ** { psf->error = SFE_BAD_SEEK ; ** return PSF_SEEK_ERROR ; ** } ; ** newblock = (8 * (psf->current + offset)) / pg72x->samplesperblock ; ** newsample = (8 * (psf->current + offset)) % pg72x->samplesperblock ; ** break ; ** ** case SEEK_END : ** if (offset > 0 || sample_curr + offset < 0) ** { psf->error = SFE_BAD_SEEK ; ** return PSF_SEEK_ERROR ; ** } ; ** newblock = (sample_curr + offset) / pg72x->samplesperblock ; ** newsample = (sample_curr + offset) % pg72x->samplesperblock ; ** break ; ** ** default : ** psf->error = SFE_BAD_SEEK ; ** return PSF_SEEK_ERROR ; ** } ; ** ** if (psf->mode == SFM_READ) ** { psf_fseek (psf, psf->dataoffset + newblock * pg72x->blocksize, SEEK_SET) ; ** pg72x->block_curr = newblock ; ** psf_g72x_decode_block (psf, pg72x) ; ** pg72x->sample_curr = newsample ; ** } ** else ** { /+* What to do about write??? *+/ ** psf->error = SFE_BAD_SEEK ; ** return PSF_SEEK_ERROR ; ** } ; ** ** psf->current = newblock * pg72x->samplesperblock + newsample ; ** return psf->current ; ** */ } /* g72x_seek */ /*========================================================================================== ** G72x Write Functions. */ static int psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) { int k ; /* Encode the samples. */ g72x_encode_block (pg72x->private, pg72x->samples, pg72x->block) ; /* Write the block to disk. */ if ((k = psf_fwrite (pg72x->block, 1, pg72x->blocksize, psf)) != pg72x->blocksize) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pg72x->blocksize) ; pg72x->sample_curr = 0 ; pg72x->block_curr ++ ; /* Set samples to zero for next block. */ memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ; return 1 ; } /* psf_g72x_encode_block */ static int g72x_write_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, const short *ptr, int len) { int count, total = 0, indx = 0 ; while (indx < len) { count = pg72x->samplesperblock - pg72x->sample_curr ; if (count > len - indx) count = len - indx ; memcpy (&(pg72x->samples [pg72x->sample_curr]), &(ptr [indx]), count * sizeof (short)) ; indx += count ; pg72x->sample_curr += count ; total = indx ; if (pg72x->sample_curr >= pg72x->samplesperblock) psf_g72x_encode_block (psf, pg72x) ; } ; return total ; } /* g72x_write_block */ static sf_count_t g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; int writecount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; while (len > 0) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = g72x_write_block (psf, pg72x, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* g72x_write_s */ static sf_count_t g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; short *sptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; sptr = psf->u.sbuf ; bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = ptr [total + k] >> 16 ; count = g72x_write_block (psf, pg72x, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* g72x_write_i */ static sf_count_t g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; short *sptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrintf (normfact * ptr [total + k]) ; count = g72x_write_block (psf, pg72x, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* g72x_write_f */ static sf_count_t g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { G72x_PRIVATE *pg72x ; short *sptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; pg72x = (G72x_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ; sptr = psf->u.sbuf ; bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) sptr [k] = lrint (normfact * ptr [total + k]) ; count = g72x_write_block (psf, pg72x, sptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* g72x_write_d */ static int g72x_close (SF_PRIVATE *psf) { G72x_PRIVATE *pg72x ; pg72x = (G72x_PRIVATE*) psf->codec_data ; if (psf->mode == SFM_WRITE) { /* If a block has been partially assembled, write it out ** as the final block. */ if (pg72x->sample_curr && pg72x->sample_curr < G72x_BLOCK_SIZE) psf_g72x_encode_block (psf, pg72x) ; if (psf->write_header) psf->write_header (psf, SF_FALSE) ; } ; /* Only free the pointer allocated by g72x_(reader|writer)_init. */ free (pg72x->private) ; return 0 ; } /* g72x_close */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 3cc5439e-7247-486b-b2e6-11a4affa5744 */ nyquist-3.05/nylsf/file_io.c0000644000175000000620000010274311466723256015113 0ustar stevestaff/* ** Copyright (C) 2002-2005 Erik de Castro Lopo ** Copyright (C) 2003 Ross Bencina ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** The file is split into three sections as follows: ** - The top section (USE_WINDOWS_API == 0) for Linux, Unix and MacOSX ** systems (including Cygwin). ** - The middle section (USE_WINDOWS_API == 1) for microsoft windows ** (including MinGW) using the native windows API. ** - A legacy windows section which attempted to work around grevious ** bugs in microsoft's POSIX implementation. */ /* ** The header file sfconfig.h MUST be included before the others to ensure ** that large file support is enabled correctly on Unix systems. */ #include "sfconfig.h" #include #include #if HAVE_UNISTD_H #include #endif #if (HAVE_DECL_S_IRGRP == 0) #include #endif #include #include #include #include #include "sndfile.h" #include "common.h" #define SENSIBLE_SIZE (0x40000000) static void psf_log_syserr (SF_PRIVATE *psf, int error) ; #if (USE_WINDOWS_API == 0) /*------------------------------------------------------------------------------ ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here. */ static int psf_close_fd (int fd) ; static int psf_open_fd (const char * path, int mode) ; static sf_count_t psf_get_filelen_fd (int fd) ; int psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode) { psf->error = 0 ; psf->filedes = psf_open_fd (pathname, open_mode) ; if (psf->filedes == - SFE_BAD_OPEN_MODE) { psf->error = SFE_BAD_OPEN_MODE ; psf->filedes = -1 ; return psf->error ; } ; if (psf->filedes == -1) psf_log_syserr (psf, errno) ; psf->mode = open_mode ; return psf->error ; } /* psf_fopen */ int psf_fclose (SF_PRIVATE *psf) { int retval ; if (psf->virtual_io) return 0 ; if (psf->do_not_close_descriptor) { psf->filedes = -1 ; return 0 ; } ; if ((retval = psf_close_fd (psf->filedes)) == -1) psf_log_syserr (psf, errno) ; psf->filedes = -1 ; return retval ; } /* psf_fclose */ int psf_open_rsrc (SF_PRIVATE *psf, int open_mode) { if (psf->rsrcdes > 0) return 0 ; /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s/rsrc", psf->filepath) ; psf->error = SFE_NO_ERROR ; if ((psf->rsrcdes = psf_open_fd (psf->rsrcpath, open_mode)) >= 0) { psf->rsrclength = psf_get_filelen_fd (psf->rsrcdes) ; if (psf->rsrclength > 0 || (open_mode & SFM_WRITE)) return SFE_NO_ERROR ; psf_close_fd (psf->rsrcdes) ; psf->rsrcdes = -1 ; } ; if (psf->rsrcdes == - SFE_BAD_OPEN_MODE) { psf->error = SFE_BAD_OPEN_MODE ; return psf->error ; } ; /* ** Now try for a resource fork stored as a separate file in the same ** directory, but preceded with a dot underscore. */ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s._%s", psf->directory, psf->filename) ; psf->error = SFE_NO_ERROR ; if ((psf->rsrcdes = psf_open_fd (psf->rsrcpath, open_mode)) >= 0) { psf->rsrclength = psf_get_filelen_fd (psf->rsrcdes) ; return SFE_NO_ERROR ; } ; /* ** Now try for a resource fork stored in a separate file in the ** .AppleDouble/ directory. */ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s.AppleDouble/%s", psf->directory, psf->filename) ; psf->error = SFE_NO_ERROR ; if ((psf->rsrcdes = psf_open_fd (psf->rsrcpath, open_mode)) >= 0) { psf->rsrclength = psf_get_filelen_fd (psf->rsrcdes) ; return SFE_NO_ERROR ; } ; /* No resource file found. */ if (psf->rsrcdes == -1) psf_log_syserr (psf, errno) ; psf->rsrcdes = -1 ; return psf->error ; } /* psf_open_rsrc */ sf_count_t psf_get_filelen (SF_PRIVATE *psf) { sf_count_t filelen ; if (psf->virtual_io) return psf->vio.get_filelen (psf->vio_user_data) ; filelen = psf_get_filelen_fd (psf->filedes) ; if (filelen == -1) { psf_log_syserr (psf, errno) ; return (sf_count_t) -1 ; } ; if (filelen == -SFE_BAD_STAT_SIZE) { psf->error = SFE_BAD_STAT_SIZE ; return (sf_count_t) -1 ; } ; switch (psf->mode) { case SFM_WRITE : filelen = filelen - psf->fileoffset ; break ; case SFM_READ : if (psf->fileoffset > 0 && psf->filelength > 0) filelen = psf->filelength ; break ; case SFM_RDWR : /* ** Cannot open embedded files SFM_RDWR so we don't need to ** subtract psf->fileoffset. We already have the answer we ** need. */ break ; default : /* Shouldn't be here, so return error. */ filelen = -1 ; } ; return filelen ; } /* psf_get_filelen */ int psf_close_rsrc (SF_PRIVATE *psf) { if (psf->rsrcdes >= 0) psf_close_fd (psf->rsrcdes) ; psf->rsrcdes = -1 ; return 0 ; } /* psf_close_rsrc */ int psf_set_stdio (SF_PRIVATE *psf, int mode) { int error = 0 ; switch (mode) { case SFM_RDWR : error = SFE_OPEN_PIPE_RDWR ; break ; case SFM_READ : psf->filedes = 0 ; break ; case SFM_WRITE : psf->filedes = 1 ; break ; default : error = SFE_BAD_OPEN_MODE ; break ; } ; psf->filelength = 0 ; return error ; } /* psf_set_stdio */ void psf_set_file (SF_PRIVATE *psf, int fd) { psf->filedes = fd ; } /* psf_set_file */ int psf_file_valid (SF_PRIVATE *psf) { return (psf->filedes >= 0) ? SF_TRUE : SF_FALSE ; } /* psf_set_file */ sf_count_t psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) { sf_count_t new_position ; if (psf->virtual_io) return psf->vio.seek (offset, whence, psf->vio_user_data) ; switch (whence) { case SEEK_SET : offset += psf->fileoffset ; break ; case SEEK_END : if (psf->mode == SFM_WRITE) { new_position = lseek (psf->filedes, offset, whence) ; if (new_position < 0) psf_log_syserr (psf, errno) ; return new_position - psf->fileoffset ; } ; /* Transform SEEK_END into a SEEK_SET, ie find the file ** length add the requested offset (should be <= 0) to ** get the offset wrt the start of file. */ whence = SEEK_SET ; offset = lseek (psf->filedes, 0, SEEK_END) + offset ; break ; default : /* No need to do anything about SEEK_CUR. */ break ; } ; new_position = lseek (psf->filedes, offset, whence) ; if (new_position < 0) psf_log_syserr (psf, errno) ; new_position -= psf->fileoffset ; return new_position ; } /* psf_fseek */ sf_count_t psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) { sf_count_t total = 0 ; ssize_t count ; if (psf->virtual_io) return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; items *= bytes ; /* Do this check after the multiplication above. */ if (items <= 0) return 0 ; while (items > 0) { /* Break the read down to a sensible size. */ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; count = read (psf->filedes, ((char*) ptr) + total, (size_t) count) ; if (count == -1) { if (errno == EINTR) continue ; psf_log_syserr (psf, errno) ; break ; } ; if (count == 0) break ; total += count ; items -= count ; } ; if (psf->is_pipe) psf->pipeoffset += total ; return total / bytes ; } /* psf_fread */ sf_count_t psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) { sf_count_t total = 0 ; ssize_t count ; if (psf->virtual_io) return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ; items *= bytes ; /* Do this check after the multiplication above. */ if (items <= 0) return 0 ; while (items > 0) { /* Break the writes down to a sensible size. */ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ; count = write (psf->filedes, ((const char*) ptr) + total, count) ; if (count == -1) { if (errno == EINTR) continue ; psf_log_syserr (psf, errno) ; break ; } ; if (count == 0) break ; total += count ; items -= count ; } ; if (psf->is_pipe) psf->pipeoffset += total ; return total / bytes ; } /* psf_fwrite */ sf_count_t psf_ftell (SF_PRIVATE *psf) { sf_count_t pos ; if (psf->virtual_io) return psf->vio.tell (psf->vio_user_data) ; if (psf->is_pipe) return psf->pipeoffset ; pos = lseek (psf->filedes, 0, SEEK_CUR) ; if (pos == ((sf_count_t) -1)) { psf_log_syserr (psf, errno) ; return -1 ; } ; return pos - psf->fileoffset ; } /* psf_ftell */ static int psf_close_fd (int fd) { int retval ; while ((retval = close (fd)) == -1 && errno == EINTR) /* Do nothing. */ ; return retval ; } /* psf_close_fd */ sf_count_t psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) { sf_count_t k = 0 ; sf_count_t count ; while (k < bufsize - 1) { count = read (psf->filedes, &(buffer [k]), 1) ; if (count == -1) { if (errno == EINTR) continue ; psf_log_syserr (psf, errno) ; break ; } ; if (count == 0 || buffer [k++] == '\n') break ; } ; buffer [k] = 0 ; return k ; } /* psf_fgets */ int psf_is_pipe (SF_PRIVATE *psf) { struct stat statbuf ; if (psf->virtual_io) return SF_FALSE ; if (fstat (psf->filedes, &statbuf) == -1) { psf_log_syserr (psf, errno) ; /* Default to maximum safety. */ return SF_TRUE ; } ; if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode)) return SF_TRUE ; return SF_FALSE ; } /* psf_is_pipe */ static sf_count_t psf_get_filelen_fd (int fd) { struct stat statbuf ; /* ** Sanity check. ** If everything is OK, this will be optimised out. */ if (sizeof (statbuf.st_size) == 4 && sizeof (sf_count_t) == 8) return (sf_count_t) -SFE_BAD_STAT_SIZE ; if (fstat (fd, &statbuf) == -1) return (sf_count_t) -1 ; return statbuf.st_size ; } /* psf_get_filelen_fd */ int psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) { int retval ; /* Returns 0 on success, non-zero on failure. */ if (len < 0) return -1 ; if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF) return -1 ; retval = ftruncate (psf->filedes, len) ; if (retval == -1) psf_log_syserr (psf, errno) ; return retval ; } /* psf_ftruncate */ void psf_init_files (SF_PRIVATE *psf) { psf->filedes = -1 ; psf->rsrcdes = -1 ; psf->savedes = -1 ; } /* psf_init_files */ void psf_use_rsrc (SF_PRIVATE *psf, int on_off) { if (on_off) { if (psf->filedes != psf->rsrcdes) { psf->savedes = psf->filedes ; psf->filedes = psf->rsrcdes ; } ; } else if (psf->filedes == psf->rsrcdes) psf->filedes = psf->savedes ; return ; } /* psf_use_rsrc */ static int psf_open_fd (const char * pathname, int open_mode) { int fd, oflag, mode ; /* ** Sanity check. If everything is OK, this test and the printfs will ** be optimised out. This is meant to catch the problems caused by ** "sfconfig.h" being included after . */ if (sizeof (off_t) != sizeof (sf_count_t)) { puts ("\n\n*** Fatal error : sizeof (off_t) != sizeof (sf_count_t)") ; puts ("*** This means that libsndfile was not configured correctly.\n") ; exit (1) ; } ; switch (open_mode) { case SFM_READ : oflag = O_RDONLY ; mode = 0 ; break ; case SFM_WRITE : oflag = O_WRONLY | O_CREAT | O_TRUNC ; mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; break ; case SFM_RDWR : oflag = O_RDWR | O_CREAT ; mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; break ; default : return - SFE_BAD_OPEN_MODE ; break ; } ; #if OS_IS_WIN32 /* For Cygwin. */ oflag |= O_BINARY ; #endif if (mode == 0) fd = open (pathname, oflag) ; else fd = open (pathname, oflag, mode) ; return fd ; } /* psf_open_fd */ static void psf_log_syserr (SF_PRIVATE *psf, int error) { /* Only log an error if no error has been set yet. */ if (psf->error == 0) { psf->error = SFE_SYSTEM ; LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ; } ; return ; } /* psf_log_syserr */ void psf_fsync (SF_PRIVATE *psf) { #if HAVE_FSYNC if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) fsync (psf->filedes) ; #else psf = NULL ; #endif } /* psf_fsync */ #elif USE_WINDOWS_API /* Win32 file i/o functions implemented using native Win32 API */ #include #include #ifndef HAVE_SSIZE_T typedef long ssize_t ; #endif static int psf_close_handle (HANDLE handle) ; static HANDLE psf_open_handle (const char * path, int mode) ; static sf_count_t psf_get_filelen_handle (HANDLE handle) ; /* USE_WINDOWS_API */ int psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode) { psf->error = 0 ; psf->hfile = psf_open_handle (pathname, open_mode) ; if (psf->hfile == NULL) psf_log_syserr (psf, GetLastError()) ; psf->mode = open_mode ; return psf->error ; } /* psf_fopen */ /* USE_WINDOWS_API */ int psf_fclose (SF_PRIVATE *psf) { int retval ; if (psf->virtual_io) return 0 ; if (psf->do_not_close_descriptor) { psf->hfile = NULL ; return 0 ; } ; if ((retval = psf_close_handle (psf->hfile)) == -1) psf_log_syserr (psf, GetLastError ()) ; psf->hfile = NULL ; return retval ; } /* psf_fclose */ /* USE_WINDOWS_API */ int psf_open_rsrc (SF_PRIVATE *psf, int open_mode) { if (psf->hrsrc != NULL) return 0 ; /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s/rsrc", psf->filepath) ; psf->error = SFE_NO_ERROR ; if ((psf->hrsrc = psf_open_handle (psf->rsrcpath, open_mode)) != NULL) { psf->rsrclength = psf_get_filelen_handle (psf->hrsrc) ; return SFE_NO_ERROR ; } ; /* ** Now try for a resource fork stored as a separate file in the same ** directory, but preceded with a dot underscore. */ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s._%s", psf->directory, psf->filename) ; psf->error = SFE_NO_ERROR ; if ((psf->hrsrc = psf_open_handle (psf->rsrcpath, open_mode)) != NULL) { psf->rsrclength = psf_get_filelen_handle (psf->hrsrc) ; return SFE_NO_ERROR ; } ; /* ** Now try for a resource fork stored in a separate file in the ** .AppleDouble/ directory. */ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s.AppleDouble/%s", psf->directory, psf->filename) ; psf->error = SFE_NO_ERROR ; if ((psf->hrsrc = psf_open_handle (psf->rsrcpath, open_mode)) != NULL) { psf->rsrclength = psf_get_filelen_handle (psf->hrsrc) ; return SFE_NO_ERROR ; } ; /* No resource file found. */ if (psf->hrsrc == NULL) psf_log_syserr (psf, GetLastError ()) ; psf->hrsrc = NULL ; return psf->error ; } /* psf_open_rsrc */ /* USE_WINDOWS_API */ sf_count_t psf_get_filelen (SF_PRIVATE *psf) { sf_count_t filelen ; if (psf->virtual_io) return psf->vio.get_filelen (psf->vio_user_data) ; filelen = psf_get_filelen_handle (psf->hfile) ; if (filelen == -1) { psf_log_syserr (psf, errno) ; return (sf_count_t) -1 ; } ; if (filelen == -SFE_BAD_STAT_SIZE) { psf->error = SFE_BAD_STAT_SIZE ; return (sf_count_t) -1 ; } ; switch (psf->mode) { case SFM_WRITE : filelen = filelen - psf->fileoffset ; break ; case SFM_READ : if (psf->fileoffset > 0 && psf->filelength > 0) filelen = psf->filelength ; break ; case SFM_RDWR : /* ** Cannot open embedded files SFM_RDWR so we don't need to ** subtract psf->fileoffset. We already have the answer we ** need. */ break ; default : /* Shouldn't be here, so return error. */ filelen = -1 ; } ; return filelen ; } /* psf_get_filelen */ /* USE_WINDOWS_API */ void psf_init_files (SF_PRIVATE *psf) { psf->hfile = NULL ; psf->hrsrc = NULL ; psf->hsaved = NULL ; } /* psf_init_files */ /* USE_WINDOWS_API */ void psf_use_rsrc (SF_PRIVATE *psf, int on_off) { if (on_off) { if (psf->hfile != psf->hrsrc) { psf->hsaved = psf->hfile ; psf->hfile = psf->hrsrc ; } ; } else if (psf->hfile == psf->hrsrc) psf->hfile = psf->hsaved ; return ; } /* psf_use_rsrc */ /* USE_WINDOWS_API */ static HANDLE psf_open_handle (const char * pathname, int open_mode) { DWORD dwDesiredAccess ; DWORD dwShareMode ; DWORD dwCreationDistribution ; HANDLE handle ; switch (open_mode) { case SFM_READ : dwDesiredAccess = GENERIC_READ ; dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; dwCreationDistribution = OPEN_EXISTING ; break ; case SFM_WRITE : dwDesiredAccess = GENERIC_WRITE ; dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; dwCreationDistribution = CREATE_ALWAYS ; break ; case SFM_RDWR : dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ; dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; dwCreationDistribution = OPEN_ALWAYS ; break ; default : return NULL ; } ; handle = CreateFile ( pathname, /* pointer to name of the file */ dwDesiredAccess, /* access (read-write) mode */ dwShareMode, /* share mode */ 0, /* pointer to security attributes */ dwCreationDistribution, /* how to create */ FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */ NULL /* handle to file with attributes to copy */ ) ; if (handle == INVALID_HANDLE_VALUE) return NULL ; return handle ; } /* psf_open_handle */ /* USE_WINDOWS_API */ static void psf_log_syserr (SF_PRIVATE *psf, int error) { LPVOID lpMsgBuf ; /* Only log an error if no error has been set yet. */ if (psf->error == 0) { psf->error = SFE_SYSTEM ; FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ) ; LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s", lpMsgBuf) ; LocalFree (lpMsgBuf) ; } ; return ; } /* psf_log_syserr */ /* USE_WINDOWS_API */ int psf_close_rsrc (SF_PRIVATE *psf) { if (psf->hrsrc != NULL) psf_close_handle (psf->hrsrc) ; psf->hrsrc = NULL ; return 0 ; } /* psf_close_rsrc */ /* USE_WINDOWS_API */ int psf_set_stdio (SF_PRIVATE *psf, int mode) { HANDLE handle = NULL ; int error = 0 ; switch (mode) { case SFM_RDWR : error = SFE_OPEN_PIPE_RDWR ; break ; case SFM_READ : handle = GetStdHandle (STD_INPUT_HANDLE) ; psf->do_not_close_descriptor = 1 ; break ; case SFM_WRITE : handle = GetStdHandle (STD_OUTPUT_HANDLE) ; psf->do_not_close_descriptor = 1 ; break ; default : error = SFE_BAD_OPEN_MODE ; break ; } ; psf->hfile = handle ; psf->filelength = 0 ; return error ; } /* psf_set_stdio */ /* USE_WINDOWS_API */ void psf_set_file (SF_PRIVATE *psf, int fd) { HANDLE handle ; long osfhandle ; osfhandle = _get_osfhandle (fd) ; handle = (HANDLE) osfhandle ; psf->hfile = handle ; } /* psf_set_file */ /* USE_WINDOWS_API */ int psf_file_valid (SF_PRIVATE *psf) { if (psf->hfile == NULL) return SF_FALSE ; if (psf->hfile == INVALID_HANDLE_VALUE) return SF_FALSE ; return SF_TRUE ; } /* psf_set_file */ /* USE_WINDOWS_API */ sf_count_t psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) { sf_count_t new_position ; LONG lDistanceToMove, lDistanceToMoveHigh ; DWORD dwMoveMethod ; DWORD dwResult, dwError ; if (psf->virtual_io) return psf->vio.seek (offset, whence, psf->vio_user_data) ; switch (whence) { case SEEK_SET : offset += psf->fileoffset ; dwMoveMethod = FILE_BEGIN ; break ; case SEEK_END : dwMoveMethod = FILE_END ; break ; default : dwMoveMethod = FILE_CURRENT ; break ; } ; lDistanceToMove = (DWORD) (offset & 0xFFFFFFFF) ; lDistanceToMoveHigh = (DWORD) ((offset >> 32) & 0xFFFFFFFF) ; dwResult = SetFilePointer (psf->hfile, lDistanceToMove, &lDistanceToMoveHigh, dwMoveMethod) ; if (dwResult == 0xFFFFFFFF) dwError = GetLastError () ; else dwError = NO_ERROR ; if (dwError != NO_ERROR) { psf_log_syserr (psf, dwError) ; return -1 ; } ; new_position = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) - psf->fileoffset ; return new_position ; } /* psf_fseek */ /* USE_WINDOWS_API */ sf_count_t psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) { sf_count_t total = 0 ; ssize_t count ; DWORD dwNumberOfBytesRead ; if (psf->virtual_io) return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; items *= bytes ; /* Do this check after the multiplication above. */ if (items <= 0) return 0 ; while (items > 0) { /* Break the writes down to a sensible size. */ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; if (ReadFile (psf->hfile, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0) { psf_log_syserr (psf, GetLastError ()) ; break ; } else count = dwNumberOfBytesRead ; if (count == 0) break ; total += count ; items -= count ; } ; if (psf->is_pipe) psf->pipeoffset += total ; return total / bytes ; } /* psf_fread */ /* USE_WINDOWS_API */ sf_count_t psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) { sf_count_t total = 0 ; ssize_t count ; DWORD dwNumberOfBytesWritten ; if (psf->virtual_io) return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ; items *= bytes ; /* Do this check after the multiplication above. */ if (items <= 0) return 0 ; while (items > 0) { /* Break the writes down to a sensible size. */ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; if (WriteFile (psf->hfile, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0) { psf_log_syserr (psf, GetLastError ()) ; break ; } else count = dwNumberOfBytesWritten ; if (count == 0) break ; total += count ; items -= count ; } ; if (psf->is_pipe) psf->pipeoffset += total ; return total / bytes ; } /* psf_fwrite */ /* USE_WINDOWS_API */ sf_count_t psf_ftell (SF_PRIVATE *psf) { sf_count_t pos ; LONG lDistanceToMoveLow, lDistanceToMoveHigh ; DWORD dwResult, dwError ; if (psf->virtual_io) return psf->vio.tell (psf->vio_user_data) ; if (psf->is_pipe) return psf->pipeoffset ; lDistanceToMoveLow = 0 ; lDistanceToMoveHigh = 0 ; dwResult = SetFilePointer (psf->hfile, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_CURRENT) ; if (dwResult == 0xFFFFFFFF) dwError = GetLastError () ; else dwError = NO_ERROR ; if (dwError != NO_ERROR) { psf_log_syserr (psf, dwError) ; return -1 ; } ; pos = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) ; return pos - psf->fileoffset ; } /* psf_ftell */ /* USE_WINDOWS_API */ static int psf_close_handle (HANDLE handle) { if (CloseHandle (handle) == 0) return -1 ; return 0 ; } /* psf_close_handle */ /* USE_WINDOWS_API */ sf_count_t psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) { sf_count_t k = 0 ; sf_count_t count ; DWORD dwNumberOfBytesRead ; while (k < bufsize - 1) { if (ReadFile (psf->hfile, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0) { psf_log_syserr (psf, GetLastError ()) ; break ; } else { count = dwNumberOfBytesRead ; /* note that we only check for '\n' not other line endings such as CRLF */ if (count == 0 || buffer [k++] == '\n') break ; } ; } ; buffer [k] = 0 ; return k ; } /* psf_fgets */ /* USE_WINDOWS_API */ int psf_is_pipe (SF_PRIVATE *psf) { if (psf->virtual_io) return SF_FALSE ; if (GetFileType (psf->hfile) == FILE_TYPE_DISK) return SF_FALSE ; /* Default to maximum safety. */ return SF_TRUE ; } /* psf_is_pipe */ /* USE_WINDOWS_API */ sf_count_t psf_get_filelen_handle (HANDLE handle) { sf_count_t filelen ; DWORD dwFileSizeLow, dwFileSizeHigh, dwError = NO_ERROR ; dwFileSizeLow = GetFileSize (handle, &dwFileSizeHigh) ; if (dwFileSizeLow == 0xFFFFFFFF) dwError = GetLastError () ; if (dwError != NO_ERROR) return (sf_count_t) -1 ; filelen = dwFileSizeLow + ((__int64) dwFileSizeHigh << 32) ; return filelen ; } /* psf_get_filelen_handle */ /* USE_WINDOWS_API */ void psf_fsync (SF_PRIVATE *psf) { FlushFileBuffers (psf->hfile) ; } /* psf_fsync */ /* USE_WINDOWS_API */ int psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) { int retval = 0 ; LONG lDistanceToMoveLow, lDistanceToMoveHigh ; DWORD dwResult, dwError = NO_ERROR ; /* This implementation trashes the current file position. ** should it save and restore it? what if the current position is past ** the new end of file? */ /* Returns 0 on success, non-zero on failure. */ if (len < 0) return 1 ; lDistanceToMoveLow = (DWORD) (len & 0xFFFFFFFF) ; lDistanceToMoveHigh = (DWORD) ((len >> 32) & 0xFFFFFFFF) ; dwResult = SetFilePointer (psf->hfile, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_BEGIN) ; if (dwResult == 0xFFFFFFFF) dwError = GetLastError () ; if (dwError != NO_ERROR) { retval = -1 ; psf_log_syserr (psf, dwError) ; } else { /* Note: when SetEndOfFile is used to extend a file, the contents of the ** new portion of the file is undefined. This is unlike chsize(), ** which guarantees that the new portion of the file will be zeroed. ** Not sure if this is important or not. */ if (SetEndOfFile (psf->hfile) == 0) { retval = -1 ; psf_log_syserr (psf, GetLastError ()) ; } ; } ; return retval ; } /* psf_ftruncate */ #else /* Win32 file i/o functions implemented using Unix-style file i/o API */ /* Win32 has a 64 file offset seek function: ** ** __int64 _lseeki64 (int handle, __int64 offset, int origin) ; ** ** It also has a 64 bit fstat function: ** ** int fstati64 (int, struct _stati64) ; ** ** but the fscking thing doesn't work!!!!! The file size parameter returned ** by this function is only valid up until more data is written at the end of ** the file. That makes this function completely 100% useless. */ #include #include #ifndef HAVE_SSIZE_T typedef long ssize_t ; #endif /* Win32 */ int psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode) { int oflag, mode ; switch (open_mode) { case SFM_READ : oflag = O_RDONLY | O_BINARY ; mode = 0 ; break ; case SFM_WRITE : oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; mode = S_IRUSR | S_IWUSR | S_IRGRP ; break ; case SFM_RDWR : oflag = O_RDWR | O_CREAT | O_BINARY ; mode = S_IRUSR | S_IWUSR | S_IRGRP ; break ; default : psf->error = SFE_BAD_OPEN_MODE ; return -1 ; break ; } ; if (mode == 0) psf->filedes = open (pathname, oflag) ; else psf->filedes = open (pathname, oflag, mode) ; if (psf->filedes == -1) psf_log_syserr (psf, errno) ; return psf->filedes ; } /* psf_fopen */ /* Win32 */ sf_count_t psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) { sf_count_t new_position ; if (psf->virtual_io) return psf->vio.seek (offset, whence, psf->vio_user_data) ; switch (whence) { case SEEK_SET : offset += psf->fileoffset ; break ; case SEEK_END : if (psf->mode == SFM_WRITE) { new_position = _lseeki64 (psf->filedes, offset, whence) ; if (new_position < 0) psf_log_syserr (psf, errno) ; return new_position - psf->fileoffset ; } ; /* Transform SEEK_END into a SEEK_SET, ie find the file ** length add the requested offset (should be <= 0) to ** get the offset wrt the start of file. */ whence = SEEK_SET ; offset = _lseeki64 (psf->filedes, 0, SEEK_END) + offset ; break ; default : /* No need to do anything about SEEK_CUR. */ break ; } ; /* ** Bypass weird Win32-ism if necessary. ** _lseeki64() returns an "invalid parameter" error if called with the ** offset == 0 and whence == SEEK_CUR. *** Use the _telli64() function instead. */ if (offset == 0 && whence == SEEK_CUR) new_position = _telli64 (psf->filedes) ; else new_position = _lseeki64 (psf->filedes, offset, whence) ; if (new_position < 0) psf_log_syserr (psf, errno) ; new_position -= psf->fileoffset ; return new_position ; } /* psf_fseek */ /* Win32 */ sf_count_t psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) { sf_count_t total = 0 ; ssize_t count ; if (psf->virtual_io) return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; items *= bytes ; /* Do this check after the multiplication above. */ if (items <= 0) return 0 ; while (items > 0) { /* Break the writes down to a sensible size. */ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; count = read (psf->filedes, ((char*) ptr) + total, (size_t) count) ; if (count == -1) { if (errno == EINTR) continue ; psf_log_syserr (psf, errno) ; break ; } ; if (count == 0) break ; total += count ; items -= count ; } ; return total / bytes ; } /* psf_fread */ /* Win32 */ sf_count_t psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) { sf_count_t total = 0 ; ssize_t count ; if (psf->virtual_io) return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ; items *= bytes ; /* Do this check after the multiplication above. */ if (items <= 0) return 0 ; while (items > 0) { /* Break the writes down to a sensible size. */ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ; count = write (psf->filedes, ((const char*) ptr) + total, count) ; if (count == -1) { if (errno == EINTR) continue ; psf_log_syserr (psf, errno) ; break ; } ; if (count == 0) break ; total += count ; items -= count ; } ; return total / bytes ; } /* psf_fwrite */ /* Win32 */ sf_count_t psf_ftell (SF_PRIVATE *psf) { sf_count_t pos ; if (psf->virtual_io) return psf->vio.tell (psf->vio_user_data) ; pos = _telli64 (psf->filedes) ; if (pos == ((sf_count_t) -1)) { psf_log_syserr (psf, errno) ; return -1 ; } ; return pos - psf->fileoffset ; } /* psf_ftell */ /* Win32 */ int psf_fclose (SF_PRIVATE *psf) { int retval ; while ((retval = close (psf->filedes)) == -1 && errno == EINTR) /* Do nothing. */ ; if (retval == -1) psf_log_syserr (psf, errno) ; psf->filedes = -1 ; return retval ; } /* psf_fclose */ /* Win32 */ sf_count_t psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) { sf_count_t k = 0 ; sf_count_t count ; while (k < bufsize - 1) { count = read (psf->filedes, &(buffer [k]), 1) ; if (count == -1) { if (errno == EINTR) continue ; psf_log_syserr (psf, errno) ; break ; } ; if (count == 0 || buffer [k++] == '\n') break ; } ; buffer [k] = 0 ; return k ; } /* psf_fgets */ /* Win32 */ int psf_is_pipe (SF_PRIVATE *psf) { struct stat statbuf ; if (psf->virtual_io) return SF_FALSE ; /* Not sure if this works. */ if (fstat (psf->filedes, &statbuf) == -1) { psf_log_syserr (psf, errno) ; /* Default to maximum safety. */ return SF_TRUE ; } ; /* These macros are defined in Win32/unistd.h. */ if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode)) return SF_TRUE ; return SF_FALSE ; } /* psf_checkpipe */ /* Win32 */ sf_count_t psf_get_filelen (SF_PRIVATE *psf) { #if 0 /* ** Windoze is SOOOOO FUCKED!!!!!!! ** This code should work but doesn't. Why? ** Code below does work. */ struct _stati64 statbuf ; if (_fstati64 (psf->filedes, &statbuf)) { psf_log_syserr (psf, errno) ; return (sf_count_t) -1 ; } ; return statbuf.st_size ; #else sf_count_t current, filelen ; if (psf->virtual_io) return psf->vio.get_filelen (psf->vio_user_data) ; if ((current = _telli64 (psf->filedes)) < 0) { psf_log_syserr (psf, errno) ; return (sf_count_t) -1 ; } ; /* ** Lets face it, windoze if FUBAR!!! ** ** For some reason, I have to call _lseeki64() TWICE to get to the ** end of the file. ** ** This might have been avoided if windows had implemented the POSIX ** standard function fsync() but NO, that would have been too easy. ** ** I am VERY close to saying that windoze will no longer be supported ** by libsndfile and changing the license to GPL at the same time. */ _lseeki64 (psf->filedes, 0, SEEK_END) ; if ((filelen = _lseeki64 (psf->filedes, 0, SEEK_END)) < 0) { psf_log_syserr (psf, errno) ; return (sf_count_t) -1 ; } ; if (filelen > current) _lseeki64 (psf->filedes, current, SEEK_SET) ; switch (psf->mode) { case SFM_WRITE : filelen = filelen - psf->fileoffset ; break ; case SFM_READ : if (psf->fileoffset > 0 && psf->filelength > 0) filelen = psf->filelength ; break ; case SFM_RDWR : /* ** Cannot open embedded files SFM_RDWR so we don't need to ** subtract psf->fileoffset. We already have the answer we ** need. */ break ; default : filelen = 0 ; } ; return filelen ; #endif } /* psf_get_filelen */ /* Win32 */ int psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) { int retval ; /* Returns 0 on success, non-zero on failure. */ if (len < 0) return 1 ; /* The global village idiots at micorsoft decided to implement ** nearly all the required 64 bit file offset functions except ** for one, truncate. The fscking morons! ** ** This is not 64 bit file offset clean. Somone needs to clean ** this up. */ if (len > 0x7FFFFFFF) return -1 ; retval = chsize (psf->filedes, len) ; if (retval == -1) psf_log_syserr (psf, errno) ; return retval ; } /* psf_ftruncate */ static void psf_log_syserr (SF_PRIVATE *psf, int error) { /* Only log an error if no error has been set yet. */ if (psf->error == 0) { psf->error = SFE_SYSTEM ; LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s", strerror (error)) ; } ; return ; } /* psf_log_syserr */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 749740d7-ecc7-47bd-8cf7-600f31d32e6d */ nyquist-3.05/nylsf/xi.c0000644000175000000620000007735711466723256014141 0ustar stevestaff/* ** Copyright (C) 2003-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "float_cast.h" #define MAX_XI_SAMPLES 16 /*------------------------------------------------------------------------------ ** Private static functions and tyepdefs. */ typedef struct { /* Warning, this filename is NOT nul terminated. */ char filename [22] ; char software [20] ; char sample_name [22] ; int loop_begin, loop_end ; int sample_flags ; /* Data for encoder and decoder. */ short last_16 ; } XI_PRIVATE ; static int xi_close (SF_PRIVATE *psf) ; static int xi_write_header (SF_PRIVATE *psf, int calc_length) ; static int xi_read_header (SF_PRIVATE *psf) ; static int dpcm_init (SF_PRIVATE *psf) ; static sf_count_t dpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; /*------------------------------------------------------------------------------ ** Public function. */ int xi_open (SF_PRIVATE *psf) { XI_PRIVATE *pxi ; int subformat, error = 0 ; if (psf->is_pipe) return SFE_XI_NO_PIPE ; if (psf->codec_data) pxi = psf->codec_data ; else if ((pxi = calloc (1, sizeof (XI_PRIVATE))) == NULL) return SFE_MALLOC_FAILED ; psf->codec_data = pxi ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = xi_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_XI) return SFE_BAD_OPEN_FORMAT ; psf->endian = SF_ENDIAN_LITTLE ; psf->sf.channels = 1 ; /* Always mono */ psf->sf.samplerate = 44100 ; /* Always */ /* Set up default instrument and software name. */ memcpy (pxi->filename, "Default Name ", sizeof (pxi->filename)) ; memcpy (pxi->software, PACKAGE "-" VERSION " ", sizeof (pxi->software)) ; memset (pxi->sample_name, 0, sizeof (pxi->sample_name)) ; LSF_SNPRINTF (pxi->sample_name, sizeof (pxi->sample_name), "%s", "Sample #1") ; pxi->sample_flags = (subformat == SF_FORMAT_DPCM_16) ? 16 : 0 ; if (xi_write_header (psf, SF_FALSE)) return psf->error ; psf->write_header = xi_write_header ; } ; psf->container_close = xi_close ; psf->seek = dpcm_seek ; psf->sf.seekable = SF_FALSE ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_DPCM_8 : /* 8-bit differential PCM. */ case SF_FORMAT_DPCM_16 : /* 16-bit differential PCM. */ error = dpcm_init (psf) ; break ; default : break ; } ; return error ; } /* xi_open */ /*------------------------------------------------------------------------------ */ static int xi_close (SF_PRIVATE *psf) { psf = psf ; return 0 ; } /* xi_close */ /*============================================================================== */ static sf_count_t dpcm_read_dsc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dsc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dsc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dsc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t dpcm_write_s2dsc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t dpcm_write_i2dsc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t dpcm_write_f2dsc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t dpcm_write_d2dsc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dles2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dles2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dles2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t dpcm_read_dles2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t dpcm_write_s2dles (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t dpcm_write_i2dles (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t dpcm_write_f2dles (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t dpcm_write_d2dles (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static int dpcm_init (SF_PRIVATE *psf) { if (psf->bytewidth == 0 || psf->sf.channels == 0) return SFE_INTERNAL ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { switch (psf->bytewidth) { case 1 : psf->read_short = dpcm_read_dsc2s ; psf->read_int = dpcm_read_dsc2i ; psf->read_float = dpcm_read_dsc2f ; psf->read_double = dpcm_read_dsc2d ; break ; case 2 : psf->read_short = dpcm_read_dles2s ; psf->read_int = dpcm_read_dles2i ; psf->read_float = dpcm_read_dles2f ; psf->read_double = dpcm_read_dles2d ; break ; default : psf_log_printf (psf, "dpcm_init() returning SFE_UNIMPLEMENTED\n") ; return SFE_UNIMPLEMENTED ; } ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { switch (psf->bytewidth) { case 1 : psf->write_short = dpcm_write_s2dsc ; psf->write_int = dpcm_write_i2dsc ; psf->write_float = dpcm_write_f2dsc ; psf->write_double = dpcm_write_d2dsc ; break ; case 2 : psf->write_short = dpcm_write_s2dles ; psf->write_int = dpcm_write_i2dles ; psf->write_float = dpcm_write_f2dles ; psf->write_double = dpcm_write_d2dles ; break ; default : psf_log_printf (psf, "dpcm_init() returning SFE_UNIMPLEMENTED\n") ; return SFE_UNIMPLEMENTED ; } ; } ; psf->filelength = psf_get_filelen (psf) ; psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; psf->sf.frames = psf->datalength / psf->blockwidth ; return 0 ; } /* dpcm_init */ /*============================================================================== */ static sf_count_t dpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { XI_PRIVATE *pxi ; int total, bufferlen, len ; if ((pxi = psf->codec_data) == NULL) return SFE_INTERNAL ; if (psf->datalength < 0 || psf->dataoffset < 0) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (offset == 0) { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; pxi->last_16 = 0 ; return 0 ; } ; if (offset < 0 || offset > psf->sf.frames) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (mode != SFM_READ) { /* What to do about write??? */ psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DPCM_16) { total = offset ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (total > 0) { len = (total > bufferlen) ? bufferlen : total ; total -= dpcm_read_dles2s (psf, psf->u.sbuf, len) ; } ; } else { total = offset ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (total > 0) { len = (total > bufferlen) ? bufferlen : total ; total -= dpcm_read_dsc2s (psf, psf->u.sbuf, len) ; } ; } ; return offset ; } /* dpcm_seek */ static int xi_write_header (SF_PRIVATE *psf, int calc_length) { XI_PRIVATE *pxi ; sf_count_t current ; const char *string ; if ((pxi = psf->codec_data) == NULL) return SFE_INTERNAL ; calc_length = calc_length ; /* Avoid a compiler warning. */ current = psf_ftell (psf) ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; string = "Extended Instrument: " ; psf_binheader_writef (psf, "b", string, strlen (string)) ; psf_binheader_writef (psf, "b1", pxi->filename, sizeof (pxi->filename), 0x1A) ; /* Write software version and two byte XI version. */ psf_binheader_writef (psf, "eb2", pxi->software, sizeof (pxi->software), (1 << 8) + 2) ; /* ** Jump note numbers (96), volume envelope (48), pan envelope (48), ** volume points (1), pan points (1) */ psf_binheader_writef (psf, "z", (size_t) (96 + 48 + 48 + 1 + 1)) ; /* Jump volume loop (3 bytes), pan loop (3), envelope flags (3), vibrato (3) ** fade out (2), 22 unknown bytes, and then write sample_count (2 bytes). */ psf_binheader_writef (psf, "ez2z2", (size_t) (4 * 3), 0x1234, make_size_t (22), 1) ; pxi->loop_begin = 0 ; pxi->loop_end = 0 ; psf_binheader_writef (psf, "et844", psf->sf.frames, pxi->loop_begin, pxi->loop_end) ; /* volume, fine tune, flags, pan, note, namelen */ psf_binheader_writef (psf, "111111", 128, 0, pxi->sample_flags, 128, 0, strlen (pxi->sample_name)) ; psf_binheader_writef (psf, "b", pxi->sample_name, sizeof (pxi->sample_name)) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* xi_write_header */ static int xi_read_header (SF_PRIVATE *psf) { char buffer [64], name [32] ; short version, fade_out, sample_count ; int k, loop_begin, loop_end ; int sample_sizes [MAX_XI_SAMPLES] ; psf_binheader_readf (psf, "pb", 0, buffer, 21) ; memset (sample_sizes, 0, sizeof (sample_sizes)) ; buffer [20] = 0 ; if (strcmp (buffer, "Extended Instrument:") != 0) return SFE_XI_BAD_HEADER ; memset (buffer, 0, sizeof (buffer)) ; psf_binheader_readf (psf, "b", buffer, 23) ; if (buffer [22] != 0x1A) return SFE_XI_BAD_HEADER ; buffer [22] = 0 ; psf_log_printf (psf, "Extended Instrument : %s\n", buffer) ; psf_binheader_readf (psf, "be2", buffer, 20, &version) ; buffer [19] = 0 ; psf_log_printf (psf, "Software : %s\nVersion : %d.%02d\n", buffer, version / 256, version % 256) ; /* Jump note numbers (96), volume envelope (48), pan envelope (48), ** volume points (1), pan points (1) */ psf_binheader_readf (psf, "j", 96 + 48 + 48 + 1 + 1) ; psf_binheader_readf (psf, "b", buffer, 12) ; psf_log_printf (psf, "Volume Loop\n sustain : %u\n begin : %u\n end : %u\n", buffer [0], buffer [1], buffer [2]) ; psf_log_printf (psf, "Pan Loop\n sustain : %u\n begin : %u\n end : %u\n", buffer [3], buffer [4], buffer [5]) ; psf_log_printf (psf, "Envelope Flags\n volume : 0x%X\n pan : 0x%X\n", buffer [6] & 0xFF, buffer [7] & 0xFF) ; psf_log_printf (psf, "Vibrato\n type : %u\n sweep : %u\n depth : %u\n rate : %u\n", buffer [8], buffer [9], buffer [10], buffer [11]) ; /* ** Read fade_out then jump reserved (2 bytes) and ???? (20 bytes) and ** sample_count. */ psf_binheader_readf (psf, "e2j2", &fade_out, 2 + 20, &sample_count) ; psf_log_printf (psf, "Fade out : %d\n", fade_out) ; /* XI file can contain up to 16 samples. */ if (sample_count > MAX_XI_SAMPLES) return SFE_XI_EXCESS_SAMPLES ; if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) return SFE_MALLOC_FAILED ; /* Log all data for each sample. */ for (k = 0 ; k < sample_count ; k++) { psf_binheader_readf (psf, "e444", &(sample_sizes [k]), &loop_begin, &loop_end) ; /* Read 5 know bytes, 1 unknown byte and 22 name bytes. */ psf_binheader_readf (psf, "bb", buffer, 6, name, 22) ; name [21] = 0 ; psf_log_printf (psf, "Sample #%d\n name : %s\n", k + 1, name) ; psf_log_printf (psf, " size : %d\n", sample_sizes [k]) ; psf_log_printf (psf, " loop\n begin : %d\n end : %d\n", loop_begin, loop_end) ; psf_log_printf (psf, " volume : %u\n f. tune : %d\n flags : 0x%02X ", buffer [0] & 0xFF, buffer [1] & 0xFF, buffer [2] & 0xFF) ; psf_log_printf (psf, " (") ; if (buffer [2] & 1) psf_log_printf (psf, " Loop") ; if (buffer [2] & 2) psf_log_printf (psf, " PingPong") ; psf_log_printf (psf, (buffer [2] & 16) ? " 16bit" : " 8bit") ; psf_log_printf (psf, " )\n") ; psf_log_printf (psf, " pan : %u\n note : %d\n namelen : %d\n", buffer [3] & 0xFF, buffer [4], buffer [5]) ; if (k != 0) continue ; if (buffer [2] & 16) { psf->sf.format = SF_FORMAT_XI | SF_FORMAT_DPCM_16 ; psf->bytewidth = 2 ; } else { psf->sf.format = SF_FORMAT_XI | SF_FORMAT_DPCM_8 ; psf->bytewidth = 1 ; } ; } ; while (sample_count > 1 && sample_sizes [sample_count - 1] == 0) sample_count -- ; /* Currently, we can only handle 1 sample per file. */ if (sample_count > 2) { psf_log_printf (psf, "*** Sample count is less than 16 but more than 1.\n") ; psf_log_printf (psf, " sample count : %d sample_sizes [%d] : %d\n", sample_count, sample_count - 1, sample_sizes [sample_count - 1]) ; return SFE_XI_EXCESS_SAMPLES ; } ; psf->dataoffset = psf_fseek (psf, 0, SEEK_CUR) ; psf_log_printf (psf, "Data Offset : %D\n", psf->dataoffset) ; psf->datalength = sample_sizes [0] ; if (psf->dataoffset + psf->datalength > psf->filelength) { psf_log_printf (psf, "*** File seems to be truncated. Should be at least %D bytes long.\n", psf->dataoffset + sample_sizes [0]) ; psf->datalength = psf->filelength - psf->dataoffset ; } ; if (psf_fseek (psf, psf->dataoffset, SEEK_SET) != psf->dataoffset) return SFE_BAD_SEEK ; psf->endian = SF_ENDIAN_LITTLE ; psf->sf.channels = 1 ; /* Always mono */ psf->sf.samplerate = 44100 ; /* Always */ psf->blockwidth = psf->sf.channels * psf->bytewidth ; if (! psf->sf.frames && psf->blockwidth) psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; psf->instrument->basenote = 0 ; psf->instrument->gain = 1 ; psf->instrument->velocity_lo = psf->instrument->key_lo = 0 ; psf->instrument->velocity_hi = psf->instrument->key_hi = 127 ; return 0 ; } /* xi_read_header */ /*============================================================================== */ static void dsc2s_array (XI_PRIVATE *pxi, signed char *src, int count, short *dest) ; static void dsc2i_array (XI_PRIVATE *pxi, signed char *src, int count, int *dest) ; static void dsc2f_array (XI_PRIVATE *pxi, signed char *src, int count, float *dest, float normfact) ; static void dsc2d_array (XI_PRIVATE *pxi, signed char *src, int count, double *dest, double normfact) ; static void dles2s_array (XI_PRIVATE *pxi, short *src, int count, short *dest) ; static void dles2i_array (XI_PRIVATE *pxi, short *src, int count, int *dest) ; static void dles2f_array (XI_PRIVATE *pxi, short *src, int count, float *dest, float normfact) ; static void dles2d_array (XI_PRIVATE *pxi, short *src, int count, double *dest, double normfact) ; static sf_count_t dpcm_read_dsc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; dsc2s_array (pxi, psf->u.scbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dsc2s */ static sf_count_t dpcm_read_dsc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; dsc2i_array (pxi, psf->u.scbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dsc2i */ static sf_count_t dpcm_read_dsc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; dsc2f_array (pxi, psf->u.scbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dsc2f */ static sf_count_t dpcm_read_dsc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; dsc2d_array (pxi, psf->u.scbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dsc2d */ /*------------------------------------------------------------------------------ */ static sf_count_t dpcm_read_dles2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; dles2s_array (pxi, psf->u.sbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dles2s */ static sf_count_t dpcm_read_dles2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; dles2i_array (pxi, psf->u.sbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dles2i */ static sf_count_t dpcm_read_dles2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; dles2f_array (pxi, psf->u.sbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dles2f */ static sf_count_t dpcm_read_dles2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ; dles2d_array (pxi, psf->u.sbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* dpcm_read_dles2d */ /*============================================================================== */ static void s2dsc_array (XI_PRIVATE *pxi, const short *src, signed char *dest, int count) ; static void i2dsc_array (XI_PRIVATE *pxi, const int *src, signed char *dest, int count) ; static void f2dsc_array (XI_PRIVATE *pxi, const float *src, signed char *dest, int count, float normfact) ; static void d2dsc_array (XI_PRIVATE *pxi, const double *src, signed char *dest, int count, double normfact) ; static void s2dles_array (XI_PRIVATE *pxi, const short *src, short *dest, int count) ; static void i2dles_array (XI_PRIVATE *pxi, const int *src, short *dest, int count) ; static void f2dles_array (XI_PRIVATE *pxi, const float *src, short *dest, int count, float normfact) ; static void d2dles_array (XI_PRIVATE *pxi, const double *src, short *dest, int count, double normfact) ; static sf_count_t dpcm_write_s2dsc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_s2dsc */ static sf_count_t dpcm_write_i2dsc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_i2dsc */ static sf_count_t dpcm_write_f2dsc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; float normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7F) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; f2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen, normfact) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_f2dsc */ static sf_count_t dpcm_write_d2dsc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; double normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7F) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; d2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen, normfact) ; writecount = psf_fwrite (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_d2dsc */ static sf_count_t dpcm_write_s2dles (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_s2dles */ static sf_count_t dpcm_write_i2dles (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; if ((pxi = psf->codec_data) == NULL) return 0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_i2dles */ static sf_count_t dpcm_write_f2dles (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; float normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; f2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen, normfact) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_f2dles */ static sf_count_t dpcm_write_d2dles (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { XI_PRIVATE *pxi ; int bufferlen, writecount ; sf_count_t total = 0 ; double normfact ; if ((pxi = psf->codec_data) == NULL) return 0 ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.sbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; d2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen, normfact) ; writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* dpcm_write_d2dles */ /*============================================================================== */ static void dsc2s_array (XI_PRIVATE *pxi, signed char *src, int count, short *dest) { signed char last_val ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { last_val += src [k] ; dest [k] = last_val << 8 ; } ; pxi->last_16 = last_val << 8 ; } /* dsc2s_array */ static void dsc2i_array (XI_PRIVATE *pxi, signed char *src, int count, int *dest) { signed char last_val ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { last_val += src [k] ; dest [k] = last_val << 24 ; } ; pxi->last_16 = last_val << 8 ; } /* dsc2i_array */ static void dsc2f_array (XI_PRIVATE *pxi, signed char *src, int count, float *dest, float normfact) { signed char last_val ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { last_val += src [k] ; dest [k] = last_val * normfact ; } ; pxi->last_16 = last_val << 8 ; } /* dsc2f_array */ static void dsc2d_array (XI_PRIVATE *pxi, signed char *src, int count, double *dest, double normfact) { signed char last_val ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { last_val += src [k] ; dest [k] = last_val * normfact ; } ; pxi->last_16 = last_val << 8 ; } /* dsc2d_array */ /*------------------------------------------------------------------------------ */ static void s2dsc_array (XI_PRIVATE *pxi, const short *src, signed char *dest, int count) { signed char last_val, current ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { current = src [k] >> 8 ; dest [k] = current - last_val ; last_val = current ; } ; pxi->last_16 = last_val << 8 ; } /* s2dsc_array */ static void i2dsc_array (XI_PRIVATE *pxi, const int *src, signed char *dest, int count) { signed char last_val, current ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { current = src [k] >> 24 ; dest [k] = current - last_val ; last_val = current ; } ; pxi->last_16 = last_val << 8 ; } /* i2dsc_array */ static void f2dsc_array (XI_PRIVATE *pxi, const float *src, signed char *dest, int count, float normfact) { signed char last_val, current ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { current = lrintf (src [k] * normfact) ; dest [k] = current - last_val ; last_val = current ; } ; pxi->last_16 = last_val << 8 ; } /* f2dsc_array */ static void d2dsc_array (XI_PRIVATE *pxi, const double *src, signed char *dest, int count, double normfact) { signed char last_val, current ; int k ; last_val = pxi->last_16 >> 8 ; for (k = 0 ; k < count ; k++) { current = lrint (src [k] * normfact) ; dest [k] = current - last_val ; last_val = current ; } ; pxi->last_16 = last_val << 8 ; } /* d2dsc_array */ /*============================================================================== */ static void dles2s_array (XI_PRIVATE *pxi, short *src, int count, short *dest) { short last_val ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { last_val += LES2H_SHORT (src [k]) ; dest [k] = last_val ; } ; pxi->last_16 = last_val ; } /* dles2s_array */ static void dles2i_array (XI_PRIVATE *pxi, short *src, int count, int *dest) { short last_val ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { last_val += LES2H_SHORT (src [k]) ; dest [k] = last_val << 16 ; } ; pxi->last_16 = last_val ; } /* dles2i_array */ static void dles2f_array (XI_PRIVATE *pxi, short *src, int count, float *dest, float normfact) { short last_val ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { last_val += LES2H_SHORT (src [k]) ; dest [k] = last_val * normfact ; } ; pxi->last_16 = last_val ; } /* dles2f_array */ static void dles2d_array (XI_PRIVATE *pxi, short *src, int count, double *dest, double normfact) { short last_val ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { last_val += LES2H_SHORT (src [k]) ; dest [k] = last_val * normfact ; } ; pxi->last_16 = last_val ; } /* dles2d_array */ /*------------------------------------------------------------------------------ */ static void s2dles_array (XI_PRIVATE *pxi, const short *src, short *dest, int count) { short diff, last_val ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { diff = src [k] - last_val ; dest [k] = LES2H_SHORT (diff) ; last_val = src [k] ; } ; pxi->last_16 = last_val ; } /* s2dles_array */ static void i2dles_array (XI_PRIVATE *pxi, const int *src, short *dest, int count) { short diff, last_val ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { diff = (src [k] >> 16) - last_val ; dest [k] = LES2H_SHORT (diff) ; last_val = src [k] >> 16 ; } ; pxi->last_16 = last_val ; } /* i2dles_array */ static void f2dles_array (XI_PRIVATE *pxi, const float *src, short *dest, int count, float normfact) { short diff, last_val, current ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { current = lrintf (src [k] * normfact) ; diff = current - last_val ; dest [k] = LES2H_SHORT (diff) ; last_val = current ; } ; pxi->last_16 = last_val ; } /* f2dles_array */ static void d2dles_array (XI_PRIVATE *pxi, const double *src, short *dest, int count, double normfact) { short diff, last_val, current ; int k ; last_val = pxi->last_16 ; for (k = 0 ; k < count ; k++) { current = lrint (src [k] * normfact) ; diff = current - last_val ; dest [k] = LES2H_SHORT (diff) ; last_val = current ; } ; pxi->last_16 = last_val ; } /* d2dles_array */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 1ab2dbe0-29af-4d80-9c6f-cb21b67521bc */ nyquist-3.05/nylsf/dwd.c0000644000175000000620000001363111466723256014260 0ustar stevestaff/* ** Copyright (C) 2002-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #if (ENABLE_EXPERIMENTAL_CODE == 0) int dwd_open (SF_PRIVATE *psf) { if (psf) return SFE_UNIMPLEMENTED ; return (psf && 0) ; } /* dwd_open */ #else /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define SFE_DWD_NO_DWD 1666 #define SFE_DWD_BAND_BIT_WIDTH 1667 #define SFE_DWD_COMPRESSION 1668 #define DWD_IDENTIFIER "DiamondWare Digitized\n\0\x1a" #define DWD_IDENTIFIER_LEN 24 #define DWD_HEADER_LEN 57 /*------------------------------------------------------------------------------ ** Typedefs. */ /*------------------------------------------------------------------------------ ** Private static functions. */ static int dwd_read_header (SF_PRIVATE *psf) ; static int dwd_close (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int dwd_open (SF_PRIVATE *psf) { int subformat, error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = dwd_read_header (psf))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_DWD) return SFE_BAD_OPEN_FORMAT ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { /*-psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU) psf->endian = SF_ENDIAN_LITTLE ; else if (psf->endian != SF_ENDIAN_LITTLE) psf->endian = SF_ENDIAN_BIG ; if (! (encoding = dwd_write_header (psf, SF_FALSE))) return psf->error ; psf->write_header = dwd_write_header ; -*/ } ; psf->container_close = dwd_close ; /*-psf->blockwidth = psf->bytewidth * psf->sf.channels ;-*/ return error ; } /* dwd_open */ /*------------------------------------------------------------------------------ */ static int dwd_close (SF_PRIVATE *psf) { psf = psf ; return 0 ; } /* dwd_close */ /* This struct contains all the fields of interest om the DWD header, but does not ** do so in the same order and layout as the actual file, header. ** No assumptions are made about the packing of this struct. */ typedef struct { unsigned char major, minor, compression, channels, bitwidth ; unsigned short srate, maxval ; unsigned int id, datalen, frames, offset ; } DWD_HEADER ; static int dwd_read_header (SF_PRIVATE *psf) { DWD_HEADER dwdh ; memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, DWD_IDENTIFIER_LEN) ; if (memcmp (psf->u.cbuf, DWD_IDENTIFIER, DWD_IDENTIFIER_LEN) != 0) return SFE_DWD_NO_DWD ; psf_log_printf (psf, "Read only : DiamondWare Digitized (.dwd)\n", psf->u.cbuf) ; psf_binheader_readf (psf, "11", &dwdh.major, &dwdh.minor) ; psf_binheader_readf (psf, "e4j1", &dwdh.id, 1, &dwdh.compression) ; psf_binheader_readf (psf, "e211", &dwdh.srate, &dwdh.channels, &dwdh.bitwidth) ; psf_binheader_readf (psf, "e24", &dwdh.maxval, &dwdh.datalen) ; psf_binheader_readf (psf, "e44", &dwdh.frames, &dwdh.offset) ; psf_log_printf (psf, " Version Major : %d\n Version Minor : %d\n Unique ID : %08X\n", dwdh.major, dwdh.minor, dwdh.id) ; psf_log_printf (psf, " Compression : %d => ", dwdh.compression) ; if (dwdh.compression != 0) { psf_log_printf (psf, "Unsupported compression\n") ; return SFE_DWD_COMPRESSION ; } else psf_log_printf (psf, "None\n") ; psf_log_printf (psf, " Sample Rate : %d\n Channels : %d\n" " Bit Width : %d\n", dwdh.srate, dwdh.channels, dwdh.bitwidth) ; switch (dwdh.bitwidth) { case 8 : psf->sf.format = SF_FORMAT_DWD | SF_FORMAT_PCM_S8 ; psf->bytewidth = 1 ; break ; case 16 : psf->sf.format = SF_FORMAT_DWD | SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; default : psf_log_printf (psf, "*** Bad bit width %d\n", dwdh.bitwidth) ; return SFE_DWD_BAND_BIT_WIDTH ; } ; if (psf->filelength != dwdh.offset + dwdh.datalen) { psf_log_printf (psf, " Data Length : %d (should be %D)\n", dwdh.datalen, psf->filelength - dwdh.offset) ; dwdh.datalen = (unsigned int) (psf->filelength - dwdh.offset) ; } else psf_log_printf (psf, " Data Length : %d\n", dwdh.datalen) ; psf_log_printf (psf, " Max Value : %d\n", dwdh.maxval) ; psf_log_printf (psf, " Frames : %d\n", dwdh.frames) ; psf_log_printf (psf, " Data Offset : %d\n", dwdh.offset) ; psf->datalength = dwdh.datalen ; psf->dataoffset = dwdh.offset ; psf->endian = SF_ENDIAN_LITTLE ; psf->sf.samplerate = dwdh.srate ; psf->sf.channels = dwdh.channels ; psf->sf.sections = 1 ; return pcm_init (psf) ; } /* dwd_read_header */ /*------------------------------------------------------------------------------ */ #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: a5e1d2a6-a840-4039-a0e7-e1a43eb05a4f */ nyquist-3.05/nylsf/macos.c0000644000175000000620000000335211466723256014603 0ustar stevestaff/* ** Copyright (C) 2003-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #define STR_MARKER MAKE_MARKER ('S', 'T', 'R', ' ') int macos_guess_file_type (SF_PRIVATE *psf, const char *filename) { static char rsrc_name [1024] ; struct stat statbuf ; int format ; psf = psf ; snprintf (rsrc_name, sizeof (rsrc_name), "%s/rsrc", filename) ; /* If there is no resource fork, just return. */ if (stat (rsrc_name, &statbuf) != 0) { psf_log_printf (psf, "No resource fork.\n") ; return 0 ; } ; if (statbuf.st_size == 0) { psf_log_printf (psf, "Have zero size resource fork.\n") ; return 0 ; } ; format = 0 ; return format ; } /* macos_guess_file_type */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 5fbf66d7-9547-442a-9c73-92fd164f3a95 */ nyquist-3.05/nylsf/dwvw.c0000644000175000000620000004303011466723256014465 0ustar stevestaff/* ** Copyright (C) 2002-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /*=========================================================================== ** Delta Word Variable Width ** ** This decoder and encoder were implemented using information found in this ** document : http://home.swbell.net/rubywand/R011SNDFMTS.TXT ** ** According to the document, the algorithm "was invented 1991 by Magnus ** Lidstrom and is copyright 1993 by NuEdge Development". */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" typedef struct { int dwm_maxsize, bit_width, max_delta, span ; int samplecount ; int bit_count, bits, last_delta_width, last_sample ; struct { int index, end ; unsigned char buffer [256] ; } b ; } DWVW_PRIVATE ; /*============================================================================================ */ static sf_count_t dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t dwvw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t dwvw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t dwvw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t dwvw_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t dwvw_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t dwvw_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t dwvw_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t dwvw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int dwvw_close (SF_PRIVATE *psf) ; static int dwvw_decode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int *ptr, int len) ; static int dwvw_decode_load_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int bit_count) ; static int dwvw_encode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, const int *ptr, int len) ; static void dwvw_encode_store_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int data, int new_bits) ; static void dwvw_read_reset (DWVW_PRIVATE *pdwvw) ; /*============================================================================================ ** DWVW initialisation function. */ int dwvw_init (SF_PRIVATE *psf, int bitwidth) { DWVW_PRIVATE *pdwvw ; if (psf->codec_data != NULL) { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; return SFE_INTERNAL ; } ; if (bitwidth > 24) return SFE_DWVW_BAD_BITWIDTH ; if (psf->mode == SFM_RDWR) return SFE_BAD_MODE_RW ; if ((pdwvw = calloc (1, sizeof (DWVW_PRIVATE))) == NULL) return SFE_MALLOC_FAILED ; psf->codec_data = (void*) pdwvw ; pdwvw->bit_width = bitwidth ; pdwvw->dwm_maxsize = bitwidth / 2 ; pdwvw->max_delta = 1 << (bitwidth - 1) ; pdwvw->span = 1 << bitwidth ; dwvw_read_reset (pdwvw) ; if (psf->mode == SFM_READ) { psf->read_short = dwvw_read_s ; psf->read_int = dwvw_read_i ; psf->read_float = dwvw_read_f ; psf->read_double = dwvw_read_d ; } ; if (psf->mode == SFM_WRITE) { psf->write_short = dwvw_write_s ; psf->write_int = dwvw_write_i ; psf->write_float = dwvw_write_f ; psf->write_double = dwvw_write_d ; } ; psf->codec_close = dwvw_close ; psf->seek = dwvw_seek ; /* FIXME : This is bogus. */ psf->sf.frames = SF_COUNT_MAX ; psf->datalength = psf->sf.frames ; /* EMXIF : This is bogus. */ return 0 ; } /* dwvw_init */ /*-------------------------------------------------------------------------------------------- */ static int dwvw_close (SF_PRIVATE *psf) { DWVW_PRIVATE *pdwvw ; if (psf->codec_data == NULL) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; if (psf->mode == SFM_WRITE) { static int last_values [12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ; /* Write 8 zero samples to fully flush output. */ dwvw_encode_data (psf, pdwvw, last_values, 12) ; /* Write the last buffer worth of data to disk. */ psf_fwrite (pdwvw->b.buffer, 1, pdwvw->b.index, psf) ; if (psf->write_header) psf->write_header (psf, SF_TRUE) ; } ; return 0 ; } /* dwvw_close */ static sf_count_t dwvw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { DWVW_PRIVATE *pdwvw ; mode = mode ; if (! psf->codec_data) { psf->error = SFE_INTERNAL ; return PSF_SEEK_ERROR ; } ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; if (offset == 0) { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; dwvw_read_reset (pdwvw) ; return 0 ; } ; psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } /* dwvw_seek */ /*============================================================================== */ static sf_count_t dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int *iptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = iptr [k] >> 16 ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* dwvw_read_s */ static sf_count_t dwvw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int readcount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; while (len > 0) { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = dwvw_decode_data (psf, pdwvw, ptr, readcount) ; total += count ; len -= count ; if (count != readcount) break ; } ; return total ; } /* dwvw_read_i */ static sf_count_t dwvw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int *iptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (float) (iptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* dwvw_read_f */ static sf_count_t dwvw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int *iptr ; int k, bufferlen, readcount = 0, count ; sf_count_t total = 0 ; double normfact ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * (double) (iptr [k]) ; total += count ; len -= readcount ; if (count != readcount) break ; } ; return total ; } /* dwvw_read_d */ static int dwvw_decode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int *ptr, int len) { int count ; int delta_width_modifier, delta_width, delta_negative, delta, sample ; /* Restore state from last decode call. */ delta_width = pdwvw->last_delta_width ; sample = pdwvw->last_sample ; for (count = 0 ; count < len ; count++) { /* If bit_count parameter is zero get the delta_width_modifier. */ delta_width_modifier = dwvw_decode_load_bits (psf, pdwvw, -1) ; /* Check for end of input bit stream. Break loop if end. */ if (delta_width_modifier < 0) break ; if (delta_width_modifier && dwvw_decode_load_bits (psf, pdwvw, 1)) delta_width_modifier = - delta_width_modifier ; /* Calculate the current word width. */ delta_width = (delta_width + delta_width_modifier + pdwvw->bit_width) % pdwvw->bit_width ; /* Load the delta. */ delta = 0 ; if (delta_width) { delta = dwvw_decode_load_bits (psf, pdwvw, delta_width - 1) | (1 << (delta_width - 1)) ; delta_negative = dwvw_decode_load_bits (psf, pdwvw, 1) ; if (delta == pdwvw->max_delta - 1) delta += dwvw_decode_load_bits (psf, pdwvw, 1) ; if (delta_negative) delta = -delta ; } ; /* Calculate the sample */ sample += delta ; if (sample >= pdwvw->max_delta) sample -= pdwvw->span ; else if (sample < - pdwvw->max_delta) sample += pdwvw->span ; /* Store the sample justifying to the most significant bit. */ ptr [count] = sample << (32 - pdwvw->bit_width) ; if (pdwvw->b.end == 0 && pdwvw->bit_count == 0) break ; } ; pdwvw->last_delta_width = delta_width ; pdwvw->last_sample = sample ; pdwvw->samplecount += count ; return count ; } /* dwvw_decode_data */ static int dwvw_decode_load_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int bit_count) { int output = 0, get_dwm = SF_FALSE ; /* ** Depending on the value of parameter bit_count, either get the ** required number of bits (ie bit_count > 0) or the ** delta_width_modifier (otherwise). */ if (bit_count < 0) { get_dwm = SF_TRUE ; /* modify bit_count to ensure we have enought bits for finding dwm. */ bit_count = pdwvw->dwm_maxsize ; } ; /* Load bits in bit reseviour. */ while (pdwvw->bit_count < bit_count) { if (pdwvw->b.index >= pdwvw->b.end) { pdwvw->b.end = psf_fread (pdwvw->b.buffer, 1, sizeof (pdwvw->b.buffer), psf) ; pdwvw->b.index = 0 ; } ; /* Check for end of input stream. */ if (bit_count < 8 && pdwvw->b.end == 0) return -1 ; pdwvw->bits = (pdwvw->bits << 8) ; if (pdwvw->b.index < pdwvw->b.end) { pdwvw->bits |= pdwvw->b.buffer [pdwvw->b.index] ; pdwvw->b.index ++ ; } ; pdwvw->bit_count += 8 ; } ; /* If asked to get bits do so. */ if (! get_dwm) { output = (pdwvw->bits >> (pdwvw->bit_count - bit_count)) & ((1 << bit_count) - 1) ; pdwvw->bit_count -= bit_count ; return output ; } ; /* Otherwise must have been asked to get delta_width_modifier. */ while (output < (pdwvw->dwm_maxsize)) { pdwvw->bit_count -= 1 ; if (pdwvw->bits & (1 << pdwvw->bit_count)) break ; output += 1 ; } ; return output ; } /* dwvw_decode_load_bits */ static void dwvw_read_reset (DWVW_PRIVATE *pdwvw) { pdwvw->samplecount = 0 ; pdwvw->b.index = 0 ; pdwvw->b.end = 0 ; pdwvw->bit_count = 0 ; pdwvw->bits = 0 ; pdwvw->last_delta_width = 0 ; pdwvw->last_sample = 0 ; } /* dwvw_read_reset */ static void dwvw_encode_store_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int data, int new_bits) { int byte ; /* Shift the bits into the resevoir. */ pdwvw->bits = (pdwvw->bits << new_bits) | (data & ((1 << new_bits) - 1)) ; pdwvw->bit_count += new_bits ; /* Transfer bit to buffer. */ while (pdwvw->bit_count >= 8) { byte = pdwvw->bits >> (pdwvw->bit_count - 8) ; pdwvw->bit_count -= 8 ; pdwvw->b.buffer [pdwvw->b.index] = byte & 0xFF ; pdwvw->b.index ++ ; } ; if (pdwvw->b.index > SIGNED_SIZEOF (pdwvw->b.buffer) - 4) { psf_fwrite (pdwvw->b.buffer, 1, pdwvw->b.index, psf) ; pdwvw->b.index = 0 ; } ; return ; } /* dwvw_encode_store_bits */ #if 0 /* Debigging routine. */ static void dump_bits (DWVW_PRIVATE *pdwvw) { int k, mask ; for (k = 0 ; k < 10 && k < pdwvw->b.index ; k++) { mask = 0x80 ; while (mask) { putchar (mask & pdwvw->b.buffer [k] ? '1' : '0') ; mask >>= 1 ; } ; putchar (' ') ; } for (k = pdwvw->bit_count - 1 ; k >= 0 ; k --) putchar (pdwvw->bits & (1 << k) ? '1' : '0') ; putchar ('\n') ; } /* dump_bits */ #endif #define HIGHEST_BIT(x,count) \ { int y = x ; \ (count) = 0 ; \ while (y) \ { (count) ++ ; \ y >>= 1 ; \ } ; \ } ; static int dwvw_encode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, const int *ptr, int len) { int count ; int delta_width_modifier, delta, delta_negative, delta_width, extra_bit ; for (count = 0 ; count < len ; count++) { delta = (ptr [count] >> (32 - pdwvw->bit_width)) - pdwvw->last_sample ; /* Calculate extra_bit if needed. */ extra_bit = -1 ; delta_negative = 0 ; if (delta < -pdwvw->max_delta) delta = pdwvw->max_delta + (delta % pdwvw->max_delta) ; else if (delta == -pdwvw->max_delta) { extra_bit = 1 ; delta_negative = 1 ; delta = pdwvw->max_delta - 1 ; } else if (delta > pdwvw->max_delta) { delta_negative = 1 ; delta = pdwvw->span - delta ; delta = abs (delta) ; } else if (delta == pdwvw->max_delta) { extra_bit = 1 ; delta = pdwvw->max_delta - 1 ; } else if (delta < 0) { delta_negative = 1 ; delta = abs (delta) ; } ; if (delta == pdwvw->max_delta - 1 && extra_bit == -1) extra_bit = 0 ; /* Find width in bits of delta */ HIGHEST_BIT (delta, delta_width) ; /* Calculate the delta_width_modifier */ delta_width_modifier = (delta_width - pdwvw->last_delta_width) % pdwvw->bit_width ; if (delta_width_modifier > pdwvw->dwm_maxsize) delta_width_modifier -= pdwvw->bit_width ; if (delta_width_modifier < -pdwvw->dwm_maxsize) delta_width_modifier += pdwvw->bit_width ; /* Write delta_width_modifier zeros, followed by terminating '1'. */ dwvw_encode_store_bits (psf, pdwvw, 0, abs (delta_width_modifier)) ; if (abs (delta_width_modifier) != pdwvw->dwm_maxsize) dwvw_encode_store_bits (psf, pdwvw, 1, 1) ; /* Write delta_width_modifier sign. */ if (delta_width_modifier < 0) dwvw_encode_store_bits (psf, pdwvw, 1, 1) ; if (delta_width_modifier > 0) dwvw_encode_store_bits (psf, pdwvw, 0, 1) ; /* Write delta and delta sign bit. */ if (delta_width) { dwvw_encode_store_bits (psf, pdwvw, delta, abs (delta_width) - 1) ; dwvw_encode_store_bits (psf, pdwvw, (delta_negative ? 1 : 0), 1) ; } ; /* Write extra bit!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ if (extra_bit >= 0) dwvw_encode_store_bits (psf, pdwvw, extra_bit, 1) ; pdwvw->last_sample = ptr [count] >> (32 - pdwvw->bit_width) ; pdwvw->last_delta_width = delta_width ; } ; pdwvw->samplecount += count ; return count ; } /* dwvw_encode_data */ static sf_count_t dwvw_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int *iptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = ptr [total + k] << 16 ; count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* dwvw_write_s */ static sf_count_t dwvw_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int writecount, count ; sf_count_t total = 0 ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; while (len > 0) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = dwvw_encode_data (psf, pdwvw, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* dwvw_write_i */ static sf_count_t dwvw_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int *iptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; float normfact ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : 1.0 ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = lrintf (normfact * ptr [total + k]) ; count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* dwvw_write_f */ static sf_count_t dwvw_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { DWVW_PRIVATE *pdwvw ; int *iptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; double normfact ; if (! psf->codec_data) return 0 ; pdwvw = (DWVW_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : 1.0 ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = lrint (normfact * ptr [total + k]) ; count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* dwvw_write_d */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 1ca09552-b01f-4d7f-9bcf-612f834fe41d */ nyquist-3.05/nylsf/paf.c0000644000175000000620000005652311466723256014257 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "float_cast.h" #include "common.h" /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define FAP_MARKER (MAKE_MARKER ('f', 'a', 'p', ' ')) #define PAF_MARKER (MAKE_MARKER (' ', 'p', 'a', 'f')) /*------------------------------------------------------------------------------ ** Other defines. */ #define PAF_HEADER_LENGTH 2048 #define PAF24_SAMPLES_PER_BLOCK 10 #define PAF24_BLOCK_SIZE 32 /*------------------------------------------------------------------------------ ** Typedefs. */ typedef struct { int version ; int endianness ; int samplerate ; int format ; int channels ; int source ; } PAF_FMT ; typedef struct { int max_blocks, channels, samplesperblock, blocksize ; int read_block, write_block, read_count, write_count ; sf_count_t sample_count ; int *samples ; unsigned char *block ; #if HAVE_FLEXIBLE_ARRAY int data [] ; /* ISO C99 struct flexible array. */ #else int data [1] ; /* This is a hack and may not work. */ #endif } PAF24_PRIVATE ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int paf24_init (SF_PRIVATE *psf) ; static int paf_read_header (SF_PRIVATE *psf) ; static int paf_write_header (SF_PRIVATE *psf, int calc_length) ; static sf_count_t paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; enum { PAF_PCM_16 = 0, PAF_PCM_24 = 1, PAF_PCM_S8 = 2 } ; /*------------------------------------------------------------------------------ ** Public function. */ int paf_open (SF_PRIVATE *psf) { int subformat, error, endian ; psf->dataoffset = PAF_HEADER_LENGTH ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = paf_read_header (psf))) return error ; } ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_PAF) return SFE_BAD_OPEN_FORMAT ; endian = psf->sf.format & SF_FORMAT_ENDMASK ; /* PAF is by default big endian. */ psf->endian = SF_ENDIAN_BIG ; if (endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && (endian == SF_ENDIAN_CPU))) psf->endian = SF_ENDIAN_LITTLE ; if ((error = paf_write_header (psf, SF_FALSE))) return error ; psf->write_header = paf_write_header ; } ; switch (subformat) { case SF_FORMAT_PCM_S8 : psf->bytewidth = 1 ; error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : psf->bytewidth = 2 ; error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_24 : /* No bytewidth because of whacky 24 bit encoding. */ error = paf24_init (psf) ; break ; default : return SFE_PAF_UNKNOWN_FORMAT ; } ; return error ; } /* paf_open */ /*------------------------------------------------------------------------------ */ static int paf_read_header (SF_PRIVATE *psf) { PAF_FMT paf_fmt ; int marker ; memset (&paf_fmt, 0, sizeof (paf_fmt)) ; psf_binheader_readf (psf, "pm", 0, &marker) ; psf_log_printf (psf, "Signature : '%M'\n", marker) ; if (marker == PAF_MARKER) { psf_binheader_readf (psf, "E444444", &(paf_fmt.version), &(paf_fmt.endianness), &(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ; } else if (marker == FAP_MARKER) { psf_binheader_readf (psf, "e444444", &(paf_fmt.version), &(paf_fmt.endianness), &(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ; } else return SFE_PAF_NO_MARKER ; psf_log_printf (psf, "Version : %d\n", paf_fmt.version) ; if (paf_fmt.version != 0) { psf_log_printf (psf, "*** Bad version number. should be zero.\n") ; return SFE_PAF_VERSION ; } ; psf_log_printf (psf, "Sample Rate : %d\n", paf_fmt.samplerate) ; psf_log_printf (psf, "Channels : %d\n", paf_fmt.channels) ; psf_log_printf (psf, "Endianness : %d => ", paf_fmt.endianness) ; if (paf_fmt.endianness) { psf_log_printf (psf, "Little\n", paf_fmt.endianness) ; psf->endian = SF_ENDIAN_LITTLE ; } else { psf_log_printf (psf, "Big\n", paf_fmt.endianness) ; psf->endian = SF_ENDIAN_BIG ; } ; if (psf->filelength < PAF_HEADER_LENGTH) return SFE_PAF_SHORT_HEADER ; psf->datalength = psf->filelength - psf->dataoffset ; psf_binheader_readf (psf, "p", (int) psf->dataoffset) ; psf->sf.samplerate = paf_fmt.samplerate ; psf->sf.channels = paf_fmt.channels ; /* Only fill in type major. */ psf->sf.format = SF_FORMAT_PAF ; psf_log_printf (psf, "Format : %d => ", paf_fmt.format) ; /* PAF is by default big endian. */ psf->sf.format |= paf_fmt.endianness ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; switch (paf_fmt.format) { case PAF_PCM_S8 : psf_log_printf (psf, "8 bit linear PCM\n") ; psf->bytewidth = 1 ; psf->sf.format |= SF_FORMAT_PCM_S8 ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; psf->sf.frames = psf->datalength / psf->blockwidth ; break ; case PAF_PCM_16 : psf_log_printf (psf, "16 bit linear PCM\n") ; psf->bytewidth = 2 ; psf->sf.format |= SF_FORMAT_PCM_16 ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; psf->sf.frames = psf->datalength / psf->blockwidth ; break ; case PAF_PCM_24 : psf_log_printf (psf, "24 bit linear PCM\n") ; psf->bytewidth = 3 ; psf->sf.format |= SF_FORMAT_PCM_24 ; psf->blockwidth = 0 ; psf->sf.frames = PAF24_SAMPLES_PER_BLOCK * psf->datalength / (PAF24_BLOCK_SIZE * psf->sf.channels) ; break ; default : psf_log_printf (psf, "Unknown\n") ; return SFE_PAF_UNKNOWN_FORMAT ; break ; } ; psf_log_printf (psf, "Source : %d => ", paf_fmt.source) ; switch (paf_fmt.source) { case 1 : psf_log_printf (psf, "Analog Recording\n") ; break ; case 2 : psf_log_printf (psf, "Digital Transfer\n") ; break ; case 3 : psf_log_printf (psf, "Multi-track Mixdown\n") ; break ; case 5 : psf_log_printf (psf, "Audio Resulting From DSP Processing\n") ; break ; default : psf_log_printf (psf, "Unknown\n") ; break ; } ; return 0 ; } /* paf_read_header */ static int paf_write_header (SF_PRIVATE *psf, int calc_length) { int paf_format ; /* PAF header already written so no need to re-write. */ if (psf_ftell (psf) >= PAF_HEADER_LENGTH) return 0 ; psf->dataoffset = PAF_HEADER_LENGTH ; psf->dataoffset = PAF_HEADER_LENGTH ; /* Prevent compiler warning. */ calc_length = calc_length ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : paf_format = PAF_PCM_S8 ; break ; case SF_FORMAT_PCM_16 : paf_format = PAF_PCM_16 ; break ; case SF_FORMAT_PCM_24 : paf_format = PAF_PCM_24 ; break ; default : return SFE_PAF_UNKNOWN_FORMAT ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; if (psf->endian == SF_ENDIAN_BIG) { /* Marker, version, endianness, samplerate */ psf_binheader_writef (psf, "Em444", PAF_MARKER, 0, 0, psf->sf.samplerate) ; /* format, channels, source */ psf_binheader_writef (psf, "E444", paf_format, psf->sf.channels, 0) ; } else if (psf->endian == SF_ENDIAN_LITTLE) { /* Marker, version, endianness, samplerate */ psf_binheader_writef (psf, "em444", FAP_MARKER, 0, 1, psf->sf.samplerate) ; /* format, channels, source */ psf_binheader_writef (psf, "e444", paf_format, psf->sf.channels, 0) ; } ; /* Zero fill to dataoffset. */ psf_binheader_writef (psf, "z", (size_t) (psf->dataoffset - psf->headindex)) ; psf_fwrite (psf->header, psf->headindex, 1, psf) ; return psf->error ; } /* paf_write_header */ /*=============================================================================== ** 24 bit PAF files have a really weird encoding. ** For a mono file, 10 samples (each being 3 bytes) are packed into a 32 byte ** block. The 8 ints in this 32 byte block are then endian swapped (as ints) ** if necessary before being written to disk. ** For a stereo file, blocks of 10 samples from the same channel are encoded ** into 32 bytes as for the mono case. The 32 byte blocks are then interleaved ** on disk. ** Reading has to reverse the above process :-). ** Weird!!! ** ** The code below attempts to gain efficiency while maintaining readability. */ static int paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ; static int paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ; static int paf24_close (SF_PRIVATE *psf) ; static int paf24_init (SF_PRIVATE *psf) { PAF24_PRIVATE *ppaf24 ; int paf24size ; paf24size = sizeof (PAF24_PRIVATE) + psf->sf.channels * (PAF24_BLOCK_SIZE + PAF24_SAMPLES_PER_BLOCK * sizeof (int)) ; /* ** Not exatly sure why this needs to be here but the tests ** fail without it. */ psf->last_op = 0 ; if (! (psf->codec_data = malloc (paf24size))) return SFE_MALLOC_FAILED ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; memset (ppaf24, 0, paf24size) ; ppaf24->channels = psf->sf.channels ; ppaf24->samples = ppaf24->data ; ppaf24->block = (unsigned char*) (ppaf24->data + PAF24_SAMPLES_PER_BLOCK * ppaf24->channels) ; ppaf24->blocksize = PAF24_BLOCK_SIZE * ppaf24->channels ; ppaf24->samplesperblock = PAF24_SAMPLES_PER_BLOCK ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { paf24_read_block (psf, ppaf24) ; /* Read first block. */ psf->read_short = paf24_read_s ; psf->read_int = paf24_read_i ; psf->read_float = paf24_read_f ; psf->read_double = paf24_read_d ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->write_short = paf24_write_s ; psf->write_int = paf24_write_i ; psf->write_float = paf24_write_f ; psf->write_double = paf24_write_d ; } ; psf->seek = paf24_seek ; psf->container_close = paf24_close ; psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->datalength % PAF24_BLOCK_SIZE) { if (psf->mode == SFM_READ) psf_log_printf (psf, "*** Warning : file seems to be truncated.\n") ; ppaf24->max_blocks = psf->datalength / ppaf24->blocksize + 1 ; } else ppaf24->max_blocks = psf->datalength / ppaf24->blocksize ; ppaf24->read_block = 0 ; if (psf->mode == SFM_RDWR) ppaf24->write_block = ppaf24->max_blocks ; else ppaf24->write_block = 0 ; psf->sf.frames = ppaf24->samplesperblock * ppaf24->max_blocks ; ppaf24->sample_count = psf->sf.frames ; return 0 ; } /* paf24_init */ static sf_count_t paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) { PAF24_PRIVATE *ppaf24 ; int newblock, newsample ; if (psf->codec_data == NULL) { psf->error = SFE_INTERNAL ; return PSF_SEEK_ERROR ; } ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; if (mode == SFM_READ && ppaf24->write_count > 0) paf24_write_block (psf, ppaf24) ; newblock = offset / ppaf24->samplesperblock ; newsample = offset % ppaf24->samplesperblock ; switch (mode) { case SFM_READ : if (psf->last_op == SFM_WRITE && ppaf24->write_count) paf24_write_block (psf, ppaf24) ; psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ; ppaf24->read_block = newblock ; paf24_read_block (psf, ppaf24) ; ppaf24->read_count = newsample ; break ; case SFM_WRITE : if (offset > ppaf24->sample_count) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (psf->last_op == SFM_WRITE && ppaf24->write_count) paf24_write_block (psf, ppaf24) ; psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ; ppaf24->write_block = newblock ; paf24_read_block (psf, ppaf24) ; ppaf24->write_count = newsample ; break ; default : psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; return newblock * ppaf24->samplesperblock + newsample ; } /* paf24_seek */ static int paf24_close (SF_PRIVATE *psf) { PAF24_PRIVATE *ppaf24 ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (ppaf24->write_count > 0) paf24_write_block (psf, ppaf24) ; } ; return 0 ; } /* paf24_close */ /*--------------------------------------------------------------------------- */ static int paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) { int k, channel ; unsigned char *cptr ; ppaf24->read_block ++ ; ppaf24->read_count = 0 ; if (ppaf24->read_block * ppaf24->samplesperblock > ppaf24->sample_count) { memset (ppaf24->samples, 0, ppaf24->samplesperblock * ppaf24->channels) ; return 1 ; } ; /* Read the block. */ if ((k = psf_fread (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, ppaf24->blocksize) ; if (CPU_IS_LITTLE_ENDIAN) { /* Do endian swapping if necessary. */ if (psf->endian == SF_ENDIAN_BIG) endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ; /* Unpack block. */ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) { channel = k % ppaf24->channels ; cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (cptr [2] << 24) ; } ; } else { /* Do endian swapping if necessary. */ if (psf->endian == SF_ENDIAN_BIG) endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ; /* Unpack block. */ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) { channel = k % ppaf24->channels ; cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (cptr [2] << 24) ; } ; } ; return 1 ; } /* paf24_read_block */ static int paf24_read (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, int *ptr, int len) { int count, total = 0 ; while (total < len) { if (ppaf24->read_block * ppaf24->samplesperblock >= ppaf24->sample_count) { memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ; return total ; } ; if (ppaf24->read_count >= ppaf24->samplesperblock) paf24_read_block (psf, ppaf24) ; count = (ppaf24->samplesperblock - ppaf24->read_count) * ppaf24->channels ; count = (len - total > count) ? count : len - total ; memcpy (&(ptr [total]), &(ppaf24->samples [ppaf24->read_count * ppaf24->channels]), count * sizeof (int)) ; total += count ; ppaf24->read_count += count / ppaf24->channels ; } ; return total ; } /* paf24_read */ static sf_count_t paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int *iptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = paf24_read (psf, ppaf24, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = iptr [k] >> 16 ; total += count ; len -= readcount ; } ; return total ; } /* paf24_read_s */ static sf_count_t paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int total ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; total = paf24_read (psf, ppaf24, ptr, len) ; return total ; } /* paf24_read_i */ static sf_count_t paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int *iptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = paf24_read (psf, ppaf24, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * iptr [k] ; total += count ; len -= readcount ; } ; return total ; } /* paf24_read_f */ static sf_count_t paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int *iptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = paf24_read (psf, ppaf24, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * iptr [k] ; total += count ; len -= readcount ; } ; return total ; } /* paf24_read_d */ /*--------------------------------------------------------------------------- */ static int paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) { int k, nextsample, channel ; unsigned char *cptr ; /* First pack block. */ if (CPU_IS_LITTLE_ENDIAN) { for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) { channel = k % ppaf24->channels ; cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; nextsample = ppaf24->samples [k] >> 8 ; cptr [0] = nextsample ; cptr [1] = nextsample >> 8 ; cptr [2] = nextsample >> 16 ; } ; /* Do endian swapping if necessary. */ if (psf->endian == SF_ENDIAN_BIG) endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ; } else if (CPU_IS_BIG_ENDIAN) { /* This is correct. */ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) { channel = k % ppaf24->channels ; cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; nextsample = ppaf24->samples [k] >> 8 ; cptr [0] = nextsample ; cptr [1] = nextsample >> 8 ; cptr [2] = nextsample >> 16 ; } ; if (psf->endian == SF_ENDIAN_BIG) endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ; } ; /* Write block to disk. */ if ((k = psf_fwrite (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize) psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, ppaf24->blocksize) ; if (ppaf24->sample_count < ppaf24->write_block * ppaf24->samplesperblock + ppaf24->write_count) ppaf24->sample_count = ppaf24->write_block * ppaf24->samplesperblock + ppaf24->write_count ; if (ppaf24->write_count == ppaf24->samplesperblock) { ppaf24->write_block ++ ; ppaf24->write_count = 0 ; } ; return 1 ; } /* paf24_write_block */ static int paf24_write (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, const int *ptr, int len) { int count, total = 0 ; while (total < len) { count = (ppaf24->samplesperblock - ppaf24->write_count) * ppaf24->channels ; if (count > len - total) count = len - total ; memcpy (&(ppaf24->samples [ppaf24->write_count * ppaf24->channels]), &(ptr [total]), count * sizeof (int)) ; total += count ; ppaf24->write_count += count / ppaf24->channels ; if (ppaf24->write_count >= ppaf24->samplesperblock) paf24_write_block (psf, ppaf24) ; } ; return total ; } /* paf24_write */ static sf_count_t paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int *iptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = ptr [total + k] << 16 ; count = paf24_write (psf, ppaf24, iptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* paf24_write_s */ static sf_count_t paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int writecount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; while (len > 0) { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; count = paf24_write (psf, ppaf24, ptr, writecount) ; total += count ; len -= count ; if (count != writecount) break ; } ; return total ; } /* paf24_write_i */ static sf_count_t paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int *iptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = lrintf (normfact * ptr [total + k]) ; count = paf24_write (psf, ppaf24, iptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* paf24_write_f */ static sf_count_t paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { PAF24_PRIVATE *ppaf24 ; int *iptr ; int k, bufferlen, writecount = 0, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = lrint (normfact * ptr [total+k]) ; count = paf24_write (psf, ppaf24, iptr, writecount) ; total += count ; len -= writecount ; if (count != writecount) break ; } ; return total ; } /* paf24_write_d */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 477a5308-451e-4bbd-bab4-fab6caa4e884 */ nyquist-3.05/nylsf/command.c0000644000175000000620000002455711466723256015131 0ustar stevestaff/* ** Copyright (C) 2001-2004 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "common.h" static SF_FORMAT_INFO const simple_formats [] = { { SF_FORMAT_AIFF | SF_FORMAT_PCM_16, "AIFF (Apple/SGI 16 bit PCM)", "aiff" }, { SF_FORMAT_AIFF | SF_FORMAT_FLOAT, "AIFF (Apple/SGI 32 bit float)", "aifc" }, { SF_FORMAT_AIFF | SF_FORMAT_PCM_S8, "AIFF (Apple/SGI 8 bit PCM)", "aiff" }, { SF_FORMAT_AU | SF_FORMAT_PCM_16, "AU (Sun/Next 16 bit PCM)", "au" }, { SF_FORMAT_AU | SF_FORMAT_ULAW, "AU (Sun/Next 8-bit u-law)", "au" }, { SF_FORMAT_CAF | SF_FORMAT_PCM_16, "CAF (Apple 16 bit PCM)", "caf" }, #ifdef HAVE_FLAC_ALL_H { SF_FORMAT_FLAC | SF_FORMAT_PCM_16, "FLAC 16 bit", "flac" }, #endif { SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, "OKI Dialogic VOX ADPCM", "vox" }, { SF_FORMAT_WAV | SF_FORMAT_PCM_16, "WAV (Microsoft 16 bit PCM)", "wav" }, { SF_FORMAT_WAV | SF_FORMAT_FLOAT, "WAV (Microsoft 32 bit float)", "wav" }, { SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, "WAV (Microsoft 4 bit IMA ADPCM)", "wav" }, { SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, "WAV (Microsoft 4 bit MS ADPCM)", "wav" }, { SF_FORMAT_WAV | SF_FORMAT_PCM_U8, "WAV (Microsoft 8 bit PCM)", "wav" }, } ; /* simple_formats */ int psf_get_format_simple_count (void) { return (sizeof (simple_formats) / sizeof (SF_FORMAT_INFO)) ; } /* psf_get_format_simple_count */ int psf_get_format_simple (SF_FORMAT_INFO *data) { int indx ; if (data->format < 0 || data->format >= (SIGNED_SIZEOF (simple_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) return SFE_BAD_CONTROL_CMD ; indx = data->format ; memcpy (data, &(simple_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; return 0 ; } /* psf_get_format_simple */ /*============================================================================ ** Major format info. */ static SF_FORMAT_INFO const major_formats [] = { { SF_FORMAT_AIFF, "AIFF (Apple/SGI)", "aiff" }, { SF_FORMAT_AU, "AU (Sun/NeXT)", "au" }, { SF_FORMAT_AVR, "AVR (Audio Visual Research)", "avr" }, { SF_FORMAT_CAF, "CAF (Apple Core Audio File)", "caf" }, #ifdef HAVE_FLAC_ALL_H { SF_FORMAT_FLAC, "FLAC (FLAC Lossless Audio Codec)", "flac" }, #endif { SF_FORMAT_HTK, "HTK (HMM Tool Kit)", "htk" }, { SF_FORMAT_SVX, "IFF (Amiga IFF/SVX8/SV16)", "iff" }, { SF_FORMAT_MAT4, "MAT4 (GNU Octave 2.0 / Matlab 4.2)", "mat" }, { SF_FORMAT_MAT5, "MAT5 (GNU Octave 2.1 / Matlab 5.0)", "mat" }, { SF_FORMAT_PAF, "PAF (Ensoniq PARIS)", "paf" }, { SF_FORMAT_PVF, "PVF (Portable Voice Format)", "pvf" }, { SF_FORMAT_RAW, "RAW (header-less)", "raw" }, { SF_FORMAT_SD2, "SD2 (Sound Designer II)", "sd2" }, { SF_FORMAT_SDS, "SDS (Midi Sample Dump Standard)", "sds" }, { SF_FORMAT_IRCAM, "SF (Berkeley/IRCAM/CARL)", "sf" }, { SF_FORMAT_VOC, "VOC (Creative Labs)", "voc" }, { SF_FORMAT_W64, "W64 (SoundFoundry WAVE 64)", "w64" }, { SF_FORMAT_WAV, "WAV (Microsoft)", "wav" }, { SF_FORMAT_NIST, "WAV (NIST Sphere)", "wav" }, { SF_FORMAT_WAVEX, "WAVEX (Microsoft)", "wav" }, { SF_FORMAT_XI, "XI (FastTracker 2)", "xi" }, } ; /* major_formats */ int psf_get_format_major_count (void) { return (sizeof (major_formats) / sizeof (SF_FORMAT_INFO)) ; } /* psf_get_format_major_count */ int psf_get_format_major (SF_FORMAT_INFO *data) { int indx ; if (data->format < 0 || data->format >= (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) return SFE_BAD_CONTROL_CMD ; indx = data->format ; memcpy (data, &(major_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; return 0 ; } /* psf_get_format_major */ /*============================================================================ ** Subtype format info. */ static SF_FORMAT_INFO subtype_formats [] = { { SF_FORMAT_PCM_S8, "Signed 8 bit PCM", NULL }, { SF_FORMAT_PCM_16, "Signed 16 bit PCM", NULL }, { SF_FORMAT_PCM_24, "Signed 24 bit PCM", NULL }, { SF_FORMAT_PCM_32, "Signed 32 bit PCM", NULL }, { SF_FORMAT_PCM_U8, "Unsigned 8 bit PCM", NULL }, { SF_FORMAT_FLOAT, "32 bit float", NULL }, { SF_FORMAT_DOUBLE, "64 bit float", NULL }, { SF_FORMAT_ULAW, "U-Law", NULL }, { SF_FORMAT_ALAW, "A-Law", NULL }, { SF_FORMAT_IMA_ADPCM, "IMA ADPCM", NULL }, { SF_FORMAT_MS_ADPCM, "Microsoft ADPCM", NULL }, { SF_FORMAT_GSM610, "GSM 6.10", NULL }, { SF_FORMAT_G721_32, "32kbs G721 ADPCM", NULL }, { SF_FORMAT_G723_24, "24kbs G723 ADPCM", NULL }, { SF_FORMAT_DWVW_12, "12 bit DWVW", NULL }, { SF_FORMAT_DWVW_16, "16 bit DWVW", NULL }, { SF_FORMAT_DWVW_24, "24 bit DWVW", NULL }, { SF_FORMAT_VOX_ADPCM, "VOX ADPCM", "vox" }, { SF_FORMAT_DPCM_16, "16 bit DPCM", NULL }, { SF_FORMAT_DPCM_8, "8 bit DPCM", NULL } } ; /* subtype_formats */ int psf_get_format_subtype_count (void) { return (sizeof (subtype_formats) / sizeof (SF_FORMAT_INFO)) ; } /* psf_get_format_subtype_count */ int psf_get_format_subtype (SF_FORMAT_INFO *data) { int indx ; if (data->format < 0 || data->format >= (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) return SFE_BAD_CONTROL_CMD ; indx = data->format ; memcpy (data, &(subtype_formats [indx]), sizeof (SF_FORMAT_INFO)) ; return 0 ; } /* psf_get_format_subtype */ /*============================================================================== */ int psf_get_format_info (SF_FORMAT_INFO *data) { int k, format ; if (data->format & SF_FORMAT_TYPEMASK) { format = data->format & SF_FORMAT_TYPEMASK ; for (k = 0 ; k < (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) { if (format == major_formats [k].format) { memcpy (data, &(major_formats [k]), sizeof (SF_FORMAT_INFO)) ; return 0 ; } ; } ; } else if (data->format & SF_FORMAT_SUBMASK) { format = data->format & SF_FORMAT_SUBMASK ; for (k = 0 ; k < (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) { if (format == subtype_formats [k].format) { memcpy (data, &(subtype_formats [k]), sizeof (SF_FORMAT_INFO)) ; return 0 ; } ; } ; } ; memset (data, 0, sizeof (SF_FORMAT_INFO)) ; return SFE_BAD_CONTROL_CMD ; } /* psf_get_format_info */ /*============================================================================== */ double psf_calc_signal_max (SF_PRIVATE *psf, int normalize) { sf_count_t position ; double max_val, temp, *data ; int k, len, readcount, save_state ; /* If the file is not seekable, there is nothing we can do. */ if (! psf->sf.seekable) { psf->error = SFE_NOT_SEEKABLE ; return 0.0 ; } ; if (! psf->read_double) { psf->error = SFE_UNIMPLEMENTED ; return 0.0 ; } ; save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ; sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ; /* Brute force. Read the whole file and find the biggest sample. */ /* Get current position in file */ position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; /* Go to start of file. */ sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; data = psf->u.dbuf ; len = ARRAY_LEN (psf->u.dbuf) ; for (readcount = 1, max_val = 0.0 ; readcount > 0 ; /* nothing */) { readcount = sf_read_double ((SNDFILE*) psf, data, len) ; for (k = 0 ; k < readcount ; k++) { temp = fabs (data [k]) ; max_val = temp > max_val ? temp : max_val ; } ; } ; /* Return to SNDFILE to original state. */ sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ; return max_val ; } /* psf_calc_signal_max */ int psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize) { sf_count_t position ; double temp, *data ; int k, len, readcount, save_state ; int chan ; /* If the file is not seekable, there is nothing we can do. */ if (! psf->sf.seekable) return (psf->error = SFE_NOT_SEEKABLE) ; if (! psf->read_double) return (psf->error = SFE_UNIMPLEMENTED) ; save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ; sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ; memset (peaks, 0, sizeof (double) * psf->sf.channels) ; /* Brute force. Read the whole file and find the biggest sample for each channel. */ position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; /* Get current position in file */ sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; /* Go to start of file. */ len = ARRAY_LEN (psf->u.dbuf) ; data = psf->u.dbuf ; chan = 0 ; readcount = len ; while (readcount > 0) { readcount = sf_read_double ((SNDFILE*) psf, data, len) ; for (k = 0 ; k < readcount ; k++) { temp = fabs (data [k]) ; peaks [chan] = temp > peaks [chan] ? temp : peaks [chan] ; chan = (chan + 1) % psf->sf.channels ; } ; } ; sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; /* Return to original position. */ sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ; return 0 ; } /* psf_calc_max_all_channels */ int psf_get_signal_max (SF_PRIVATE *psf, double *peak) { int k ; if (psf->peak_info == NULL) return SF_FALSE ; peak [0] = psf->peak_info->peaks [0].value ; for (k = 1 ; k < psf->sf.channels ; k++) peak [0] = SF_MAX (peak [0], psf->peak_info->peaks [k].value) ; return SF_TRUE ; } /* psf_get_signal_max */ int psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks) { int k ; if (psf->peak_info == NULL) return SF_FALSE ; for (k = 0 ; k < psf->sf.channels ; k++) peaks [k] = psf->peak_info->peaks [k].value ; return SF_TRUE ; } /* psf_get_max_all_channels */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 0aae0d9d-ab2b-4d70-ade3-47a534666f8e */ nyquist-3.05/nylsf/alaw.c0000644000175000000620000005725411466723256014437 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sndfile.h" #include "float_cast.h" #include "common.h" static sf_count_t alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t alaw_read_alaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t alaw_read_alaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t alaw_read_alaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t alaw_write_s2alaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t alaw_write_i2alaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t alaw_write_f2alaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t alaw_write_d2alaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static void alaw2s_array (unsigned char *buffer, int count, short *ptr) ; static void alaw2i_array (unsigned char *buffer, int count, int *ptr) ; static void alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) ; static void alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact) ; static void s2alaw_array (const short *buffer, int count, unsigned char *ptr) ; static void i2alaw_array (const int *buffer, int count, unsigned char *ptr) ; static void f2alaw_array (const float *buffer, int count, unsigned char *ptr, float normfact) ; static void d2alaw_array (const double *buffer, int count, unsigned char *ptr, double normfact) ; int alaw_init (SF_PRIVATE *psf) { if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { psf->read_short = alaw_read_alaw2s ; psf->read_int = alaw_read_alaw2i ; psf->read_float = alaw_read_alaw2f ; psf->read_double = alaw_read_alaw2d ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->write_short = alaw_write_s2alaw ; psf->write_int = alaw_write_i2alaw ; psf->write_float = alaw_write_f2alaw ; psf->write_double = alaw_write_d2alaw ; } ; psf->bytewidth = 1 ; psf->blockwidth = psf->sf.channels ; if (psf->filelength > psf->dataoffset) psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; else psf->datalength = 0 ; psf->sf.frames = psf->datalength / psf->blockwidth ; return 0 ; } /* alaw_init */ /*============================================================================== * Private static functions and data. */ static short alaw_decode [256] = { -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344, -328, -376, -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848 } ; /* alaw_decode */ static unsigned char alaw_encode [2048 + 1] = { 0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2, 0xdd, 0xdc, 0xdf, 0xde, 0xd9, 0xd8, 0xdb, 0xda, 0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2, 0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca, 0xf5, 0xf5, 0xf4, 0xf4, 0xf7, 0xf7, 0xf6, 0xf6, 0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2, 0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe, 0xf9, 0xf9, 0xf8, 0xf8, 0xfb, 0xfb, 0xfa, 0xfa, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a } ; /* alaw_encode */ static inline void alaw2s_array (unsigned char *buffer, int count, short *ptr) { while (--count >= 0) ptr [count] = alaw_decode [(int) buffer [count]] ; } /* alaw2s_array */ static inline void alaw2i_array (unsigned char *buffer, int count, int *ptr) { while (--count >= 0) ptr [count] = alaw_decode [(int) buffer [count]] << 16 ; } /* alaw2i_array */ static inline void alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) { while (--count >= 0) ptr [count] = normfact * alaw_decode [(int) buffer [count]] ; } /* alaw2f_array */ static inline void alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact) { while (--count >= 0) ptr [count] = normfact * alaw_decode [(int) buffer [count]] ; } /* alaw2d_array */ static inline void s2alaw_array (const short *ptr, int count, unsigned char *buffer) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = alaw_encode [ptr [count] / 16] ; else buffer [count] = 0x7F & alaw_encode [ptr [count] / -16] ; } ; } /* s2alaw_array */ static inline void i2alaw_array (const int *ptr, int count, unsigned char *buffer) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = alaw_encode [ptr [count] >> (16 + 4)] ; else buffer [count] = 0x7F & alaw_encode [- ptr [count] >> (16 + 4)] ; } ; } /* i2alaw_array */ static inline void f2alaw_array (const float *ptr, int count, unsigned char *buffer, float normfact) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = alaw_encode [lrintf (normfact * ptr [count])] ; else buffer [count] = 0x7F & alaw_encode [- lrintf (normfact * ptr [count])] ; } ; } /* f2alaw_array */ static inline void d2alaw_array (const double *ptr, int count, unsigned char *buffer, double normfact) { while (--count >= 0) { if (ptr [count] >= 0) buffer [count] = alaw_encode [lrint (normfact * ptr [count])] ; else buffer [count] = 0x7F & alaw_encode [- lrint (normfact * ptr [count])] ; } ; } /* d2alaw_array */ /*============================================================================== */ static sf_count_t alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; alaw2s_array (psf->u.ucbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* alaw_read_alaw2s */ static sf_count_t alaw_read_alaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; alaw2i_array (psf->u.ucbuf, readcount, ptr + total) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* alaw_read_alaw2i */ static sf_count_t alaw_read_alaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; alaw2f_array (psf->u.ucbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* alaw_read_alaw2f */ static sf_count_t alaw_read_alaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ; alaw2d_array (psf->u.ucbuf, readcount, ptr + total, normfact) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* alaw_read_alaw2d */ /*============================================================================================= */ static sf_count_t alaw_write_s2alaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2alaw_array (ptr + total, bufferlen, psf->u.ucbuf) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* alaw_write_s2alaw */ static sf_count_t alaw_write_i2alaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2alaw_array (ptr + total, bufferlen, psf->u.ucbuf) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* alaw_write_i2alaw */ static sf_count_t alaw_write_f2alaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; float normfact ; normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) / 16.0 : 1.0 / 16 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; f2alaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* alaw_write_f2alaw */ static sf_count_t alaw_write_d2alaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; double normfact ; normfact = (psf->norm_double) ? (1.0 * 0x7FFF) / 16.0 : 1.0 / 16.0 ; bufferlen = ARRAY_LEN (psf->u.ucbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; d2alaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ; writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* alaw_write_d2alaw */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 289ccfc2-42a6-4f1f-a29f-4dcc9bfa8752 */ nyquist-3.05/nylsf/sds.c0000644000175000000620000006567311466723256014310 0ustar stevestaff/* ** Copyright (C) 2002-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "float_cast.h" /*------------------------------------------------------------------------------ */ #define SDS_DATA_OFFSET 0x15 #define SDS_BLOCK_SIZE 127 #define SDS_AUDIO_BYTES_PER_BLOCK 120 #define SDS_3BYTE_TO_INT_DECODE(x) (((x) & 0x7F) | (((x) & 0x7F00) >> 1) | (((x) & 0x7F0000) >> 2)) #define SDS_INT_TO_3BYTE_ENCODE(x) (((x) & 0x7F) | (((x) << 1) & 0x7F00) | (((x) << 2) & 0x7F0000)) /*------------------------------------------------------------------------------ ** Typedefs. */ typedef struct tag_SDS_PRIVATE { int bitwidth, frames ; int samplesperblock, total_blocks ; int (*reader) (SF_PRIVATE *psf, struct tag_SDS_PRIVATE *psds) ; int (*writer) (SF_PRIVATE *psf, struct tag_SDS_PRIVATE *psds) ; int read_block, read_count ; unsigned char read_data [SDS_BLOCK_SIZE] ; int read_samples [SDS_BLOCK_SIZE / 2] ; /* Maximum samples per block */ int write_block, write_count ; unsigned char write_data [SDS_BLOCK_SIZE] ; int write_samples [SDS_BLOCK_SIZE / 2] ; /* Maximum samples per block */ } SDS_PRIVATE ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int sds_close (SF_PRIVATE *psf) ; static int sds_write_header (SF_PRIVATE *psf, int calc_length) ; static int sds_read_header (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_init (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static sf_count_t sds_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t sds_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t sds_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t sds_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t sds_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t sds_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t sds_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t sds_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static sf_count_t sds_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; static int sds_2byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_3byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_4byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_read (SF_PRIVATE *psf, SDS_PRIVATE *psds, int *iptr, int readcount) ; static int sds_2byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_3byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_4byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; static int sds_write (SF_PRIVATE *psf, SDS_PRIVATE *psds, const int *iptr, int writecount) ; /*------------------------------------------------------------------------------ ** Public function. */ int sds_open (SF_PRIVATE *psf) { SDS_PRIVATE *psds ; int error = 0 ; /* Hmmmm, need this here to pass update_header_test. */ psf->sf.frames = 0 ; if (! (psds = calloc (1, sizeof (SDS_PRIVATE)))) return SFE_MALLOC_FAILED ; psf->codec_data = psds ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = sds_read_header (psf, psds))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SDS) return SFE_BAD_OPEN_FORMAT ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (sds_write_header (psf, SF_FALSE)) return psf->error ; psf->write_header = sds_write_header ; psf_fseek (psf, SDS_DATA_OFFSET, SEEK_SET) ; } ; if ((error = sds_init (psf, psds)) != 0) return error ; psf->seek = sds_seek ; psf->container_close = sds_close ; psf->blockwidth = 0 ; return error ; } /* sds_open */ /*------------------------------------------------------------------------------ */ static int sds_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { SDS_PRIVATE *psds ; if ((psds = (SDS_PRIVATE *) psf->codec_data) == NULL) { psf_log_printf (psf, "*** Bad psf->codec_data ptr.\n") ; return SFE_INTERNAL ; } ; if (psds->write_count > 0) { memset (&(psds->write_data [psds->write_count]), 0, (psds->samplesperblock - psds->write_count) * sizeof (int)) ; psds->writer (psf, psds) ; } ; sds_write_header (psf, SF_TRUE) ; } ; return 0 ; } /* sds_close */ static int sds_init (SF_PRIVATE *psf, SDS_PRIVATE *psds) { if (psds->bitwidth < 8 || psds->bitwidth > 28) return (psf->error = SFE_SDS_BAD_BIT_WIDTH) ; if (psds->bitwidth < 14) { psds->reader = sds_2byte_read ; psds->writer = sds_2byte_write ; psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / 2 ; } else if (psds->bitwidth < 21) { psds->reader = sds_3byte_read ; psds->writer = sds_3byte_write ; psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / 3 ; } else { psds->reader = sds_4byte_read ; psds->writer = sds_4byte_write ; psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / 4 ; } ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { psf->read_short = sds_read_s ; psf->read_int = sds_read_i ; psf->read_float = sds_read_f ; psf->read_double = sds_read_d ; /* Read first block. */ psds->reader (psf, psds) ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { psf->write_short = sds_write_s ; psf->write_int = sds_write_i ; psf->write_float = sds_write_f ; psf->write_double = sds_write_d ; } ; return 0 ; } /* sds_init */ static int sds_read_header (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char channel, bitwidth, loop_type, byte ; unsigned short sample_no, marker ; unsigned int samp_period, data_length, sustain_loop_start, sustain_loop_end ; int bytesread, blockcount ; /* Set position to start of file to begin reading header. */ bytesread = psf_binheader_readf (psf, "pE211", 0, &marker, &channel, &byte) ; if (marker != 0xF07E || byte != 0x01) return SFE_SDS_NOT_SDS ; psf_log_printf (psf, "Midi Sample Dump Standard (.sds)\nF07E\n Midi Channel : %d\n", channel) ; bytesread += psf_binheader_readf (psf, "e213", &sample_no, &bitwidth, &samp_period) ; sample_no = SDS_3BYTE_TO_INT_DECODE (sample_no) ; samp_period = SDS_3BYTE_TO_INT_DECODE (samp_period) ; psds->bitwidth = bitwidth ; psf->sf.samplerate = 1000000000 / samp_period ; psf_log_printf (psf, " Sample Number : %d\n" " Bit Width : %d\n" " Sample Rate : %d\n", sample_no, psds->bitwidth, psf->sf.samplerate) ; bytesread += psf_binheader_readf (psf, "e3331", &data_length, &sustain_loop_start, &sustain_loop_end, &loop_type) ; data_length = SDS_3BYTE_TO_INT_DECODE (data_length) ; sustain_loop_start = SDS_3BYTE_TO_INT_DECODE (sustain_loop_start) ; sustain_loop_end = SDS_3BYTE_TO_INT_DECODE (sustain_loop_end) ; psf_log_printf (psf, " Sustain Loop\n" " Start : %d\n" " End : %d\n" " Loop Type : %d\n", sustain_loop_start, sustain_loop_end, loop_type) ; psf->dataoffset = SDS_DATA_OFFSET ; psf->datalength = psf->filelength - psf->dataoffset ; if (data_length != psf->filelength - psf->dataoffset) { psf_log_printf (psf, " Datalength : %d (truncated data??? %d)\n", data_length, psf->filelength - psf->dataoffset) ; data_length = psf->filelength - psf->dataoffset ; } else psf_log_printf (psf, " Datalength : %d\n", data_length) ; bytesread += psf_binheader_readf (psf, "1", &byte) ; if (byte != 0xF7) psf_log_printf (psf, "bad end : %X\n", byte & 0xFF) ; for (blockcount = 0 ; bytesread < psf->filelength ; blockcount++) { bytesread += psf_fread (&marker, 1, 2, psf) ; if (marker == 0) break ; psf_fseek (psf, SDS_BLOCK_SIZE - 2, SEEK_CUR) ; bytesread += SDS_BLOCK_SIZE - 2 ; } ; psf_log_printf (psf, "\nBlocks : %d\n", blockcount) ; psds->total_blocks = blockcount ; psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / ((psds->bitwidth + 6) / 7) ; psf_log_printf (psf, "Samples/Block : %d\n", psds->samplesperblock) ; psf_log_printf (psf, "Frames : %d\n", blockcount * psds->samplesperblock) ; psf->sf.frames = blockcount * psds->samplesperblock ; psds->frames = blockcount * psds->samplesperblock ; /* Always Mono */ psf->sf.channels = 1 ; psf->sf.sections = 1 ; /* ** Lie to the user about PCM bit width. Always round up to ** the next multiple of 8. */ switch ((psds->bitwidth + 7) / 8) { case 1 : psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_S8 ; break ; case 2 : psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_16 ; break ; case 3 : psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_24 ; break ; case 4 : psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_32 ; break ; default : psf_log_printf (psf, "*** Weird byte width (%d)\n", (psds->bitwidth + 7) / 8) ; return SFE_SDS_BAD_BIT_WIDTH ; } ; psf_fseek (psf, SDS_DATA_OFFSET, SEEK_SET) ; return 0 ; } /* sds_read_header */ static int sds_write_header (SF_PRIVATE *psf, int calc_length) { SDS_PRIVATE *psds ; sf_count_t current ; int samp_period, data_length, sustain_loop_start, sustain_loop_end ; unsigned char loop_type = 0 ; if ((psds = (SDS_PRIVATE *) psf->codec_data) == NULL) { psf_log_printf (psf, "*** Bad psf->codec_data ptr.\n") ; return SFE_INTERNAL ; } ; if (psf->pipeoffset > 0) return 0 ; current = psf_ftell (psf) ; if (calc_length) psf->sf.frames = psds->total_blocks * psds->samplesperblock + psds->write_count ; if (psds->write_count > 0) { int current_count = psds->write_count ; int current_block = psds->write_block ; psds->writer (psf, psds) ; psf_fseek (psf, -1 * SDS_BLOCK_SIZE, SEEK_CUR) ; psds->write_count = current_count ; psds->write_block = current_block ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; if (psf->is_pipe == SF_FALSE) psf_fseek (psf, 0, SEEK_SET) ; psf_binheader_writef (psf, "E211", 0xF07E, 0, 1) ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8 : psds->bitwidth = 8 ; break ; case SF_FORMAT_PCM_16 : psds->bitwidth = 16 ; break ; case SF_FORMAT_PCM_24 : psds->bitwidth = 24 ; break ; default: return SFE_SDS_BAD_BIT_WIDTH ; } ; samp_period = SDS_INT_TO_3BYTE_ENCODE (1000000000 / psf->sf.samplerate) ; psf_binheader_writef (psf, "e213", 0, psds->bitwidth, samp_period) ; data_length = SDS_INT_TO_3BYTE_ENCODE (psds->total_blocks * SDS_BLOCK_SIZE) ; sustain_loop_start = SDS_INT_TO_3BYTE_ENCODE (0) ; sustain_loop_end = SDS_INT_TO_3BYTE_ENCODE (psf->sf.frames) ; psf_binheader_writef (psf, "e33311", data_length, sustain_loop_start, sustain_loop_end, loop_type, 0xF7) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; psf->datalength = psds->write_block * SDS_BLOCK_SIZE ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* sds_write_header */ /*------------------------------------------------------------------------------ */ static int sds_2byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char *ucptr, checksum ; unsigned int sample ; int k ; psds->read_block ++ ; psds->read_count = 0 ; if (psds->read_block * psds->samplesperblock > psds->frames) { memset (psds->read_samples, 0, psds->samplesperblock * sizeof (int)) ; return 1 ; } ; if ((k = psf_fread (psds->read_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, SDS_BLOCK_SIZE) ; if (psds->read_data [0] != 0xF0) { printf ("Error A : %02X\n", psds->read_data [0] & 0xFF) ; } ; checksum = psds->read_data [1] ; if (checksum != 0x7E) { printf ("Error 1 : %02X\n", checksum & 0xFF) ; } for (k = 2 ; k < SDS_BLOCK_SIZE - 3 ; k ++) checksum ^= psds->read_data [k] ; checksum &= 0x7F ; if (checksum != psds->read_data [SDS_BLOCK_SIZE - 2]) { psf_log_printf (psf, "Block %d : checksum is %02X should be %02X\n", psds->read_data [4], checksum, psds->read_data [SDS_BLOCK_SIZE - 2]) ; } ; ucptr = psds->read_data + 5 ; for (k = 0 ; k < 120 ; k += 2) { sample = (ucptr [k] << 25) + (ucptr [k + 1] << 18) ; psds->read_samples [k / 2] = (int) (sample - 0x80000000) ; } ; return 1 ; } /* sds_2byte_read */ static int sds_3byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char *ucptr, checksum ; unsigned int sample ; int k ; psds->read_block ++ ; psds->read_count = 0 ; if (psds->read_block * psds->samplesperblock > psds->frames) { memset (psds->read_samples, 0, psds->samplesperblock * sizeof (int)) ; return 1 ; } ; if ((k = psf_fread (psds->read_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, SDS_BLOCK_SIZE) ; if (psds->read_data [0] != 0xF0) { printf ("Error A : %02X\n", psds->read_data [0] & 0xFF) ; } ; checksum = psds->read_data [1] ; if (checksum != 0x7E) { printf ("Error 1 : %02X\n", checksum & 0xFF) ; } for (k = 2 ; k < SDS_BLOCK_SIZE - 3 ; k ++) checksum ^= psds->read_data [k] ; checksum &= 0x7F ; if (checksum != psds->read_data [SDS_BLOCK_SIZE - 2]) { psf_log_printf (psf, "Block %d : checksum is %02X should be %02X\n", psds->read_data [4], checksum, psds->read_data [SDS_BLOCK_SIZE - 2]) ; } ; ucptr = psds->read_data + 5 ; for (k = 0 ; k < 120 ; k += 3) { sample = (ucptr [k] << 25) + (ucptr [k + 1] << 18) + (ucptr [k + 2] << 11) ; psds->read_samples [k / 3] = (int) (sample - 0x80000000) ; } ; return 1 ; } /* sds_3byte_read */ static int sds_4byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char *ucptr, checksum ; unsigned int sample ; int k ; psds->read_block ++ ; psds->read_count = 0 ; if (psds->read_block * psds->samplesperblock > psds->frames) { memset (psds->read_samples, 0, psds->samplesperblock * sizeof (int)) ; return 1 ; } ; if ((k = psf_fread (psds->read_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, SDS_BLOCK_SIZE) ; if (psds->read_data [0] != 0xF0) { printf ("Error A : %02X\n", psds->read_data [0] & 0xFF) ; } ; checksum = psds->read_data [1] ; if (checksum != 0x7E) { printf ("Error 1 : %02X\n", checksum & 0xFF) ; } for (k = 2 ; k < SDS_BLOCK_SIZE - 3 ; k ++) checksum ^= psds->read_data [k] ; checksum &= 0x7F ; if (checksum != psds->read_data [SDS_BLOCK_SIZE - 2]) { psf_log_printf (psf, "Block %d : checksum is %02X should be %02X\n", psds->read_data [4], checksum, psds->read_data [SDS_BLOCK_SIZE - 2]) ; } ; ucptr = psds->read_data + 5 ; for (k = 0 ; k < 120 ; k += 4) { sample = (ucptr [k] << 25) + (ucptr [k + 1] << 18) + (ucptr [k + 2] << 11) + (ucptr [k + 3] << 4) ; psds->read_samples [k / 4] = (int) (sample - 0x80000000) ; } ; return 1 ; } /* sds_4byte_read */ static sf_count_t sds_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int *iptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = sds_read (psf, psds, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = iptr [k] >> 16 ; total += count ; len -= readcount ; } ; return total ; } /* sds_read_s */ static sf_count_t sds_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int total ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; total = sds_read (psf, psds, ptr, len) ; return total ; } /* sds_read_i */ static sf_count_t sds_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int *iptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; if (psf->norm_float == SF_TRUE) normfact = 1.0 / 0x80000000 ; else normfact = 1.0 / (1 << psds->bitwidth) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = sds_read (psf, psds, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * iptr [k] ; total += count ; len -= readcount ; } ; return total ; } /* sds_read_f */ static sf_count_t sds_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int *iptr ; int k, bufferlen, readcount, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; if (psf->norm_double == SF_TRUE) normfact = 1.0 / 0x80000000 ; else normfact = 1.0 / (1 << psds->bitwidth) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { readcount = (len >= bufferlen) ? bufferlen : len ; count = sds_read (psf, psds, iptr, readcount) ; for (k = 0 ; k < readcount ; k++) ptr [total + k] = normfact * iptr [k] ; total += count ; len -= readcount ; } ; return total ; } /* sds_read_d */ static int sds_read (SF_PRIVATE *psf, SDS_PRIVATE *psds, int *ptr, int len) { int count, total = 0 ; while (total < len) { if (psds->read_block * psds->samplesperblock >= psds->frames) { memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ; return total ; } ; if (psds->read_count >= psds->samplesperblock) psds->reader (psf, psds) ; count = (psds->samplesperblock - psds->read_count) ; count = (len - total > count) ? count : len - total ; memcpy (&(ptr [total]), &(psds->read_samples [psds->read_count]), count * sizeof (int)) ; total += count ; psds->read_count += count ; } ; return total ; } /* sds_read */ /*============================================================================== */ static sf_count_t sds_seek (SF_PRIVATE *psf, int mode, sf_count_t seek_from_start) { SDS_PRIVATE *psds ; sf_count_t file_offset ; int newblock, newsample ; if ((psds = psf->codec_data) == NULL) { psf->error = SFE_INTERNAL ; return PSF_SEEK_ERROR ; } ; if (psf->datalength < 0 || psf->dataoffset < 0) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (seek_from_start < 0 || seek_from_start > psf->sf.frames) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; if (mode == SFM_READ && psds->write_count > 0) psds->writer (psf, psds) ; newblock = seek_from_start / psds->samplesperblock ; newsample = seek_from_start % psds->samplesperblock ; switch (mode) { case SFM_READ : if (newblock > psds->total_blocks) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; file_offset = psf->dataoffset + newblock * SDS_BLOCK_SIZE ; if (psf_fseek (psf, file_offset, SEEK_SET) != file_offset) { psf->error = SFE_SEEK_FAILED ; return PSF_SEEK_ERROR ; } ; psds->read_block = newblock ; psds->reader (psf, psds) ; psds->read_count = newsample ; break ; case SFM_WRITE : if (newblock > psds->total_blocks) { psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; } ; file_offset = psf->dataoffset + newblock * SDS_BLOCK_SIZE ; if (psf_fseek (psf, file_offset, SEEK_SET) != file_offset) { psf->error = SFE_SEEK_FAILED ; return PSF_SEEK_ERROR ; } ; psds->write_block = newblock ; psds->reader (psf, psds) ; psds->write_count = newsample ; break ; default : psf->error = SFE_BAD_SEEK ; return PSF_SEEK_ERROR ; break ; } ; return seek_from_start ; } /* sds_seek */ /*============================================================================== */ static int sds_2byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char *ucptr, checksum ; unsigned int sample ; int k ; psds->write_data [0] = 0xF0 ; psds->write_data [1] = 0x7E ; psds->write_data [2] = 0 ; /* Channel number */ psds->write_data [3] = psds->write_block & 0x7F ; /* Packet number */ ucptr = psds->write_data + 5 ; for (k = 0 ; k < 120 ; k += 2) { sample = psds->write_samples [k / 2] ; sample += 0x80000000 ; ucptr [k] = (sample >> 25) & 0x7F ; ucptr [k + 1] = (sample >> 18) & 0x7F ; } ; checksum = psds->write_data [1] ; for (k = 2 ; k < SDS_BLOCK_SIZE - 3 ; k ++) checksum ^= psds->write_data [k] ; checksum &= 0x7F ; psds->write_data [SDS_BLOCK_SIZE - 2] = checksum ; psds->write_data [SDS_BLOCK_SIZE - 1] = 0xF7 ; if ((k = psf_fwrite (psds->write_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) psf_log_printf (psf, "*** Warning : psf_fwrite (%d != %d).\n", k, SDS_BLOCK_SIZE) ; psds->write_block ++ ; psds->write_count = 0 ; if (psds->write_block > psds->total_blocks) psds->total_blocks = psds->write_block ; psds->frames = psds->total_blocks * psds->samplesperblock ; return 1 ; } /* sds_2byte_write */ static int sds_3byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char *ucptr, checksum ; unsigned int sample ; int k ; psds->write_data [0] = 0xF0 ; psds->write_data [1] = 0x7E ; psds->write_data [2] = 0 ; /* Channel number */ psds->write_data [3] = psds->write_block & 0x7F ; /* Packet number */ ucptr = psds->write_data + 5 ; for (k = 0 ; k < 120 ; k += 3) { sample = psds->write_samples [k / 3] ; sample += 0x80000000 ; ucptr [k] = (sample >> 25) & 0x7F ; ucptr [k + 1] = (sample >> 18) & 0x7F ; ucptr [k + 2] = (sample >> 11) & 0x7F ; } ; checksum = psds->write_data [1] ; for (k = 2 ; k < SDS_BLOCK_SIZE - 3 ; k ++) checksum ^= psds->write_data [k] ; checksum &= 0x7F ; psds->write_data [SDS_BLOCK_SIZE - 2] = checksum ; psds->write_data [SDS_BLOCK_SIZE - 1] = 0xF7 ; if ((k = psf_fwrite (psds->write_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) psf_log_printf (psf, "*** Warning : psf_fwrite (%d != %d).\n", k, SDS_BLOCK_SIZE) ; psds->write_block ++ ; psds->write_count = 0 ; if (psds->write_block > psds->total_blocks) psds->total_blocks = psds->write_block ; psds->frames = psds->total_blocks * psds->samplesperblock ; return 1 ; } /* sds_3byte_write */ static int sds_4byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) { unsigned char *ucptr, checksum ; unsigned int sample ; int k ; psds->write_data [0] = 0xF0 ; psds->write_data [1] = 0x7E ; psds->write_data [2] = 0 ; /* Channel number */ psds->write_data [3] = psds->write_block & 0x7F ; /* Packet number */ ucptr = psds->write_data + 5 ; for (k = 0 ; k < 120 ; k += 4) { sample = psds->write_samples [k / 4] ; sample += 0x80000000 ; ucptr [k] = (sample >> 25) & 0x7F ; ucptr [k + 1] = (sample >> 18) & 0x7F ; ucptr [k + 2] = (sample >> 11) & 0x7F ; ucptr [k + 3] = (sample >> 4) & 0x7F ; } ; checksum = psds->write_data [1] ; for (k = 2 ; k < SDS_BLOCK_SIZE - 3 ; k ++) checksum ^= psds->write_data [k] ; checksum &= 0x7F ; psds->write_data [SDS_BLOCK_SIZE - 2] = checksum ; psds->write_data [SDS_BLOCK_SIZE - 1] = 0xF7 ; if ((k = psf_fwrite (psds->write_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) psf_log_printf (psf, "*** Warning : psf_fwrite (%d != %d).\n", k, SDS_BLOCK_SIZE) ; psds->write_block ++ ; psds->write_count = 0 ; if (psds->write_block > psds->total_blocks) psds->total_blocks = psds->write_block ; psds->frames = psds->total_blocks * psds->samplesperblock ; return 1 ; } /* sds_4byte_write */ static sf_count_t sds_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int *iptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = ptr [total + k] << 16 ; count = sds_write (psf, psds, iptr, writecount) ; total += count ; len -= writecount ; } ; return total ; } /* sds_write_s */ static sf_count_t sds_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int total ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; total = sds_write (psf, psds, ptr, len) ; return total ; } /* sds_write_i */ static sf_count_t sds_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int *iptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; float normfact ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; if (psf->norm_float == SF_TRUE) normfact = 1.0 * 0x80000000 ; else normfact = 1.0 * (1 << psds->bitwidth) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = normfact * ptr [total + k] ; count = sds_write (psf, psds, iptr, writecount) ; total += count ; len -= writecount ; } ; return total ; } /* sds_write_f */ static sf_count_t sds_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { SDS_PRIVATE *psds ; int *iptr ; int k, bufferlen, writecount, count ; sf_count_t total = 0 ; double normfact ; if (psf->codec_data == NULL) return 0 ; psds = (SDS_PRIVATE*) psf->codec_data ; if (psf->norm_double == SF_TRUE) normfact = 1.0 * 0x80000000 ; else normfact = 1.0 * (1 << psds->bitwidth) ; iptr = psf->u.ibuf ; bufferlen = ARRAY_LEN (psf->u.ibuf) ; while (len > 0) { writecount = (len >= bufferlen) ? bufferlen : len ; for (k = 0 ; k < writecount ; k++) iptr [k] = normfact * ptr [total + k] ; count = sds_write (psf, psds, iptr, writecount) ; total += count ; len -= writecount ; } ; return total ; } /* sds_write_d */ static int sds_write (SF_PRIVATE *psf, SDS_PRIVATE *psds, const int *ptr, int len) { int count, total = 0 ; while (total < len) { count = psds->samplesperblock - psds->write_count ; if (count > len - total) count = len - total ; memcpy (&(psds->write_samples [psds->write_count]), &(ptr [total]), count * sizeof (int)) ; total += count ; psds->write_count += count ; if (psds->write_count >= psds->samplesperblock) psds->writer (psf, psds) ; } ; return total ; } /* sds_write */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: d5d26aa3-368c-4ca6-bb85-377e5a2578cc */ nyquist-3.05/nylsf/wav_w64.h0000644000175000000620000002642111466723256015005 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* This file contains definitions commong to WAV and W64 files. */ #ifndef WAV_W64_H_INCLUDED #define WAV_W64_H_INCLUDED /*------------------------------------------------------------------------------ ** List of known WAV format tags */ enum { /* keep sorted for wav_w64_format_str() */ WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Corporation */ WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM format */ WAVE_FORMAT_MS_ADPCM = 0x0002, /* Microsoft ADPCM */ WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* Micrososft 32 bit float format */ WAVE_FORMAT_VSELP = 0x0004, /* Compaq Computer Corporation */ WAVE_FORMAT_IBM_CVSD = 0x0005, /* IBM Corporation */ WAVE_FORMAT_ALAW = 0x0006, /* Microsoft Corporation */ WAVE_FORMAT_MULAW = 0x0007, /* Microsoft Corporation */ WAVE_FORMAT_OKI_ADPCM = 0x0010, /* OKI */ WAVE_FORMAT_IMA_ADPCM = 0x0011, /* Intel Corporation */ WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012, /* Videologic */ WAVE_FORMAT_SIERRA_ADPCM = 0x0013, /* Sierra Semiconductor Corp */ WAVE_FORMAT_G723_ADPCM = 0x0014, /* Antex Electronics Corporation */ WAVE_FORMAT_DIGISTD = 0x0015, /* DSP Solutions, Inc. */ WAVE_FORMAT_DIGIFIX = 0x0016, /* DSP Solutions, Inc. */ WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic Corporation */ WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018, /* Media Vision, Inc. */ WAVE_FORMAT_CU_CODEC = 0x0019, /* Hewlett-Packard Company */ WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha Corporation of America */ WAVE_FORMAT_SONARC = 0x0021, /* Speech Compression */ WAVE_FORMAT_DSPGROUP_TRUESPEECH = 0x0022, /* DSP Group, Inc */ WAVE_FORMAT_ECHOSC1 = 0x0023, /* Echo Speech Corporation */ WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024, /* Audiofile, Inc. */ WAVE_FORMAT_APTX = 0x0025, /* Audio Processing Technology */ WAVE_FORMAT_AUDIOFILE_AF10 = 0x0026, /* Audiofile, Inc. */ WAVE_FORMAT_PROSODY_1612 = 0x0027, /* Aculab plc */ WAVE_FORMAT_LRC = 0x0028, /* Merging Technologies S.A. */ WAVE_FORMAT_DOLBY_AC2 = 0x0030, /* Dolby Laboratories */ WAVE_FORMAT_GSM610 = 0x0031, /* Microsoft Corporation */ WAVE_FORMAT_MSNAUDIO = 0x0032, /* Microsoft Corporation */ WAVE_FORMAT_ANTEX_ADPCME = 0x0033, /* Antex Electronics Corporation */ WAVE_FORMAT_CONTROL_RES_VQLPC = 0x0034, /* Control Resources Limited */ WAVE_FORMAT_DIGIREAL = 0x0035, /* DSP Solutions, Inc. */ WAVE_FORMAT_DIGIADPCM = 0x0036, /* DSP Solutions, Inc. */ WAVE_FORMAT_CONTROL_RES_CR10 = 0x0037, /* Control Resources Limited */ WAVE_FORMAT_NMS_VBXADPCM = 0x0038, /* Natural MicroSystems */ WAVE_FORMAT_ROLAND_RDAC = 0x0039, /* Roland */ WAVE_FORMAT_ECHOSC3 = 0x003A, /* Echo Speech Corporation */ WAVE_FORMAT_ROCKWELL_ADPCM = 0x003B, /* Rockwell International */ WAVE_FORMAT_ROCKWELL_DIGITALK = 0x003C, /* Rockwell International */ WAVE_FORMAT_XEBEC = 0x003D, /* Xebec Multimedia Solutions Limited */ WAVE_FORMAT_G721_ADPCM = 0x0040, /* Antex Electronics Corporation */ WAVE_FORMAT_G728_CELP = 0x0041, /* Antex Electronics Corporation */ WAVE_FORMAT_MSG723 = 0x0042, /* Microsoft Corporation */ WAVE_FORMAT_MPEG = 0x0050, /* Microsoft Corporation */ WAVE_FORMAT_RT24 = 0x0052, /* InSoft Inc. */ WAVE_FORMAT_PAC = 0x0053, /* InSoft Inc. */ WAVE_FORMAT_MPEGLAYER3 = 0x0055, /* MPEG 3 Layer 1 */ WAVE_FORMAT_LUCENT_G723 = 0x0059, /* Lucent Technologies */ WAVE_FORMAT_CIRRUS = 0x0060, /* Cirrus Logic */ WAVE_FORMAT_ESPCM = 0x0061, /* ESS Technology */ WAVE_FORMAT_VOXWARE = 0x0062, /* Voxware Inc */ WAVE_FORMAT_CANOPUS_ATRAC = 0x0063, /* Canopus, Co., Ltd. */ WAVE_FORMAT_G726_ADPCM = 0x0064, /* APICOM */ WAVE_FORMAT_G722_ADPCM = 0x0065, /* APICOM */ WAVE_FORMAT_DSAT = 0x0066, /* Microsoft Corporation */ WAVE_FORMAT_DSAT_DISPLAY = 0x0067, /* Microsoft Corporation */ WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 0x0069, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_AC8 = 0x0070, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_AC10 = 0x0071, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_AC16 = 0x0072, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_AC20 = 0x0073, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_RT24 = 0x0074, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_RT29 = 0x0075, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_RT29HW = 0x0076, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_VR12 = 0x0077, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_VR18 = 0x0078, /* Voxware Inc. */ WAVE_FORMAT_VOXWARE_TQ40 = 0x0079, /* Voxware Inc. */ WAVE_FORMAT_SOFTSOUND = 0x0080, /* Softsound, Ltd. */ WAVE_FORMAT_VOXARE_TQ60 = 0x0081, /* Voxware Inc. */ WAVE_FORMAT_MSRT24 = 0x0082, /* Microsoft Corporation */ WAVE_FORMAT_G729A = 0x0083, /* AT&T Laboratories */ WAVE_FORMAT_MVI_MV12 = 0x0084, /* Motion Pixels */ WAVE_FORMAT_DF_G726 = 0x0085, /* DataFusion Systems (Pty) (Ltd) */ WAVE_FORMAT_DF_GSM610 = 0x0086, /* DataFusion Systems (Pty) (Ltd) */ /* removed because duplicate */ /* WAVE_FORMAT_ISIAUDIO = 0x0088, */ /* Iterated Systems, Inc. */ WAVE_FORMAT_ONLIVE = 0x0089, /* OnLive! Technologies, Inc. */ WAVE_FORMAT_SBC24 = 0x0091, /* Siemens Business Communications Systems */ WAVE_FORMAT_DOLBY_AC3_SPDIF = 0x0092, /* Sonic Foundry */ WAVE_FORMAT_ZYXEL_ADPCM = 0x0097, /* ZyXEL Communications, Inc. */ WAVE_FORMAT_PHILIPS_LPCBB = 0x0098, /* Philips Speech Processing */ WAVE_FORMAT_PACKED = 0x0099, /* Studer Professional Audio AG */ WAVE_FORMAT_RHETOREX_ADPCM = 0x0100, /* Rhetorex, Inc. */ /* removed because of the following */ /* WAVE_FORMAT_IRAT = 0x0101,*/ /* BeCubed Software Inc. */ /* these three are unofficial */ IBM_FORMAT_MULAW = 0x0101, /* IBM mu-law format */ IBM_FORMAT_ALAW = 0x0102, /* IBM a-law format */ IBM_FORMAT_ADPCM = 0x0103, /* IBM AVC Adaptive Differential PCM format */ WAVE_FORMAT_VIVO_G723 = 0x0111, /* Vivo Software */ WAVE_FORMAT_VIVO_SIREN = 0x0112, /* Vivo Software */ WAVE_FORMAT_DIGITAL_G723 = 0x0123, /* Digital Equipment Corporation */ WAVE_FORMAT_CREATIVE_ADPCM = 0x0200, /* Creative Labs, Inc */ WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 0x0202, /* Creative Labs, Inc */ WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 0x0203, /* Creative Labs, Inc */ WAVE_FORMAT_QUARTERDECK = 0x0220, /* Quarterdeck Corporation */ WAVE_FORMAT_FM_TOWNS_SND = 0x0300, /* Fujitsu Corporation */ WAVE_FORMAT_BZV_DIGITAL = 0x0400, /* Brooktree Corporation */ WAVE_FORMAT_VME_VMPCM = 0x0680, /* AT&T Labs, Inc. */ WAVE_FORMAT_OLIGSM = 0x1000, /* Ing C. Olivetti & C., S.p.A. */ WAVE_FORMAT_OLIADPCM = 0x1001, /* Ing C. Olivetti & C., S.p.A. */ WAVE_FORMAT_OLICELP = 0x1002, /* Ing C. Olivetti & C., S.p.A. */ WAVE_FORMAT_OLISBC = 0x1003, /* Ing C. Olivetti & C., S.p.A. */ WAVE_FORMAT_OLIOPR = 0x1004, /* Ing C. Olivetti & C., S.p.A. */ WAVE_FORMAT_LH_CODEC = 0x1100, /* Lernout & Hauspie */ WAVE_FORMAT_NORRIS = 0x1400, /* Norris Communications, Inc. */ /* removed because duplicate */ /* WAVE_FORMAT_ISIAUDIO = 0x1401, */ /* AT&T Labs, Inc. */ WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 0x1500, /* AT&T Labs, Inc. */ WAVE_FORMAT_DVM = 0x2000, /* FAST Multimedia AG */ WAVE_FORMAT_INTERWAV_VSC112 = 0x7150, /* ????? */ WAVE_FORMAT_IPP_ITU_G_723_1 = 0x7230, /* Intel Performance Primitives g723 codec. */ WAVE_FORMAT_EXTENSIBLE = 0xFFFE } ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; } MIN_WAV_FMT ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; unsigned short extrabytes ; unsigned short dummy ; } WAV_FMT_SIZE20 ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; unsigned short extrabytes ; unsigned short samplesperblock ; unsigned short numcoeffs ; struct { short coeff1 ; short coeff2 ; } coeffs [7] ; } MS_ADPCM_WAV_FMT ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; unsigned short extrabytes ; unsigned short samplesperblock ; } IMA_ADPCM_WAV_FMT ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; unsigned short extrabytes ; unsigned short auxblocksize ; } G72x_ADPCM_WAV_FMT ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; unsigned short extrabytes ; unsigned short samplesperblock ; } GSM610_WAV_FMT ; typedef struct { unsigned int esf_field1 ; unsigned short esf_field2 ; unsigned short esf_field3 ; char esf_field4 [8] ; } EXT_SUBFORMAT ; typedef struct { unsigned short format ; unsigned short channels ; unsigned int samplerate ; unsigned int bytespersec ; unsigned short blockalign ; unsigned short bitwidth ; unsigned short extrabytes ; unsigned short validbits ; unsigned int channelmask ; EXT_SUBFORMAT esf ; } EXTENSIBLE_WAV_FMT ; typedef union { unsigned short format ; MIN_WAV_FMT min ; IMA_ADPCM_WAV_FMT ima ; MS_ADPCM_WAV_FMT msadpcm ; G72x_ADPCM_WAV_FMT g72x ; EXTENSIBLE_WAV_FMT ext ; GSM610_WAV_FMT gsm610 ; WAV_FMT_SIZE20 size20 ; char padding [512] ; } WAV_FMT ; typedef struct { int frames ; } FACT_CHUNK ; #define WAV_W64_GSM610_BLOCKSIZE 65 #define WAV_W64_GSM610_SAMPLES 320 /*------------------------------------------------------------------------------------ ** Functions defined in wav_ms_adpcm.c */ #define MSADPCM_ADAPT_COEFF_COUNT 7 void msadpcm_write_adapt_coeffs (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------------ ** Functions defined in wav_w64.c */ int wav_w64_srate2blocksize (int srate_chan_product) ; char const* wav_w64_format_str (int k) ; int wav_w64_read_fmt_chunk (SF_PRIVATE *psf, WAV_FMT *wav_fmt, int structsize) ; void wavex_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat) ; #endif /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 877fde12-9be3-4a31-8a5a-fdae39958613 */ nyquist-3.05/nylsf/G72x/0002755000175000000620000000000011537433127014055 5ustar stevestaffnyquist-3.05/nylsf/G72x/g723_24.c0000644000175000000620000001037011466723256015215 0ustar stevestaff/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* * g723_24.c * * Description: * * g723_24_encoder(), g723_24_decoder() * * These routines comprise an implementation of the CCITT G.723 24 Kbps * ADPCM coding algorithm. Essentially, this implementation is identical to * the bit level description except for a few deviations which take advantage * of workstation attributes, such as hardware 2's complement arithmetic. * */ #include "g72x.h" #include "g72x_priv.h" /* * Maps G.723_24 code word to reconstructed scale factor normalized log * magnitude values. */ static short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048}; /* Maps G.723_24 code word to log of scale factor multiplier. */ static short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128}; /* * Maps G.723_24 code words to a set of values whose long and short * term averages are computed and then compared to give an indication * how stationary (steady state) the signal is. */ static short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0}; static short qtab_723_24[3] = {8, 218, 331}; /* * g723_24_encoder() * * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. * Returns -1 if invalid input coding value. */ int g723_24_encoder( int sl, G72x_STATE *state_ptr) { short sei, sezi, se, sez; /* ACCUM */ short d; /* SUBTA */ short y; /* MIX */ short sr; /* ADDB */ short dqsez; /* ADDC */ short dq, i; /* linearize input sample to 14-bit PCM */ sl >>= 2; /* sl of 14-bit dynamic range */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ d = sl - se; /* d = estimation diff. */ /* quantize prediction difference d */ y = step_size(state_ptr); /* quantizer step size */ i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */ dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */ dqsez = sr + sez - se; /* pole prediction diff. */ update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); return (i); } /* * g723_24_decoder() * * Decodes a 3-bit CCITT G.723_24 ADPCM code and returns * the resulting 16-bit linear PCM, A-law or u-law sample value. * -1 is returned if the output coding is unknown. */ int g723_24_decoder( int i, G72x_STATE *state_ptr) { short sezi, sei, sez, se; /* ACCUM */ short y; /* MIX */ short sr; /* ADDB */ short dq; short dqsez; i &= 0x07; /* mask to get proper bits */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ y = step_size(state_ptr); /* adaptive quantizer step size */ dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */ dqsez = sr - se + sez; /* pole prediction diff. */ update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); return (sr << 2); /* sr was of 14-bit dynamic range */ } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 75389236-650b-4427-98f3-0df6e8fb24bc */ nyquist-3.05/nylsf/G72x/g72x.h0000644000175000000620000000702111466723256015021 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ /* ** This file is not the same as the original file from Sun Microsystems. Nearly ** all the original definitions and function prototypes that were in the file ** of this name have been moved to g72x_priv.h. */ #ifndef G72X_HEADER_FILE #define G72X_HEADER_FILE /* ** Number of samples per block to process. ** Must be a common multiple of possible bits per sample : 2, 3, 4, 5 and 8. */ #define G72x_BLOCK_SIZE (3 * 5 * 8) /* ** Identifiers for the differing kinds of G72x ADPCM codecs. ** The identifiers also define the number of encoded bits per sample. */ enum { G723_16_BITS_PER_SAMPLE = 2, G723_24_BITS_PER_SAMPLE = 3, G723_40_BITS_PER_SAMPLE = 5, G721_32_BITS_PER_SAMPLE = 4, G721_40_BITS_PER_SAMPLE = 5, G723_16_SAMPLES_PER_BLOCK = G72x_BLOCK_SIZE, G723_24_SAMPLES_PER_BLOCK = G723_24_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G723_24_BITS_PER_SAMPLE), G723_40_SAMPLES_PER_BLOCK = G723_40_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G723_40_BITS_PER_SAMPLE), G721_32_SAMPLES_PER_BLOCK = G72x_BLOCK_SIZE, G721_40_SAMPLES_PER_BLOCK = G721_40_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G721_40_BITS_PER_SAMPLE), G723_16_BYTES_PER_BLOCK = (G723_16_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, G723_24_BYTES_PER_BLOCK = (G723_24_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, G723_40_BYTES_PER_BLOCK = (G723_40_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, G721_32_BYTES_PER_BLOCK = (G721_32_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, G721_40_BYTES_PER_BLOCK = (G721_40_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8 } ; /* Forward declaration of of g72x_state. */ struct g72x_state ; /* External function definitions. */ struct g72x_state * g72x_reader_init (int codec, int *blocksize, int *samplesperblock) ; struct g72x_state * g72x_writer_init (int codec, int *blocksize, int *samplesperblock) ; /* ** Initialize the ADPCM state table for the given codec. ** Return 0 on success, 1 on fail. */ int g72x_decode_block (struct g72x_state *pstate, const unsigned char *block, short *samples) ; /* ** The caller fills data->block with data->bytes bytes before calling the ** function. The value data->bytes must be an integer multiple of ** data->blocksize and be <= data->max_bytes. ** When it returns, the caller can read out data->samples samples. */ int g72x_encode_block (struct g72x_state *pstate, short *samples, unsigned char *block) ; /* ** The caller fills state->samples some integer multiple data->samples_per_block ** (up to G72x_BLOCK_SIZE) samples before calling the function. ** When it returns, the caller can read out bytes encoded bytes. */ #endif /* !G72X_HEADER_FILE */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 6ca84e5f-f932-4ba1-87ee-37056d921621 */ nyquist-3.05/nylsf/G72x/g721.c0000644000175000000620000001155411466723256014713 0ustar stevestaff/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* * g721.c * * Description: * * g721_encoder(), g721_decoder() * * These routines comprise an implementation of the CCITT G.721 ADPCM * coding algorithm. Essentially, this implementation is identical to * the bit level description except for a few deviations which * take advantage of work station attributes, such as hardware 2's * complement arithmetic and large memory. Specifically, certain time * consuming operations such as multiplications are replaced * with lookup tables and software 2's complement operations are * replaced with hardware 2's complement. * * The deviation from the bit level specification (lookup tables) * preserves the bit level performance specifications. * * As outlined in the G.721 Recommendation, the algorithm is broken * down into modules. Each section of code below is preceded by * the name of the module which it is implementing. * */ #include "g72x.h" #include "g72x_priv.h" static short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400}; /* * Maps G.721 code word to reconstructed scale factor normalized log * magnitude values. */ static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425, 425, 373, 323, 273, 213, 135, 4, -2048}; /* Maps G.721 code word to log of scale factor multiplier. */ static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122, 1122, 355, 198, 112, 64, 41, 18, -12}; /* * Maps G.721 code words to a set of values whose long and short * term averages are computed and then compared to give an indication * how stationary (steady state) the signal is. */ static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0}; /* * g721_encoder() * * Encodes the input vale of linear PCM, A-law or u-law data sl and returns * the resulting code. -1 is returned for unknown input coding value. */ int g721_encoder( int sl, G72x_STATE *state_ptr) { short sezi, se, sez; /* ACCUM */ short d; /* SUBTA */ short sr; /* ADDB */ short y; /* MIX */ short dqsez; /* ADDC */ short dq, i; /* linearize input sample to 14-bit PCM */ sl >>= 2; /* 14-bit dynamic range */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */ d = sl - se; /* estimation difference */ /* quantize the prediction difference */ y = step_size(state_ptr); /* quantizer step size */ i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */ dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */ dqsez = sr + sez - se; /* pole prediction diff. */ update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); return (i); } /* * g721_decoder() * * Description: * * Decodes a 4-bit code of G.721 encoded data of i and * returns the resulting linear PCM, A-law or u-law value. * return -1 for unknown out_coding value. */ int g721_decoder( int i, G72x_STATE *state_ptr) { short sezi, sei, sez, se; /* ACCUM */ short y; /* MIX */ short sr; /* ADDB */ short dq; short dqsez; i &= 0x0f; /* mask to get proper bits */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ y = step_size(state_ptr); /* dynamic quantizer step size */ dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */ dqsez = sr - se + sez; /* pole prediction diff. */ update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); /* sr was 14-bit dynamic range */ return (sr << 2); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 101b6e25-457d-490a-99ae-e2e74a26ea24 */ nyquist-3.05/nylsf/G72x/README.original0000644000175000000620000000622111466723256016545 0ustar stevestaffThe files in this directory comprise ANSI-C language reference implementations of the CCITT (International Telegraph and Telephone Consultative Committee) G.711, G.721 and G.723 voice compressions. They have been tested on Sun SPARCstations and passed 82 out of 84 test vectors published by CCITT (Dec. 20, 1988) for G.721 and G.723. [The two remaining test vectors, which the G.721 decoder implementation for u-law samples did not pass, may be in error because they are identical to two other vectors for G.723_40.] This source code is released by Sun Microsystems, Inc. to the public domain. Please give your acknowledgement in product literature if this code is used in your product implementation. Sun Microsystems supports some CCITT audio formats in Solaris 2.0 system software. However, Sun's implementations have been optimized for higher performance on SPARCstations. The source files for CCITT conversion routines in this directory are: g72x.h header file for g721.c, g723_24.c and g723_40.c g711.c CCITT G.711 u-law and A-law compression g72x.c common denominator of G.721 and G.723 ADPCM codes g721.c CCITT G.721 32Kbps ADPCM coder (with g72x.c) g723_24.c CCITT G.723 24Kbps ADPCM coder (with g72x.c) g723_40.c CCITT G.723 40Kbps ADPCM coder (with g72x.c) Simple conversions between u-law, A-law, and 16-bit linear PCM are invoked as follows: unsigned char ucode, acode; short pcm_val; ucode = linear2ulaw(pcm_val); ucode = alaw2ulaw(acode); acode = linear2alaw(pcm_val); acode = ulaw2alaw(ucode); pcm_val = ulaw2linear(ucode); pcm_val = alaw2linear(acode); The other CCITT compression routines are invoked as follows: #include "g72x.h" struct g72x_state state; int sample, code; g72x_init_state(&state); code = {g721,g723_24,g723_40}_encoder(sample, coding, &state); sample = {g721,g723_24,g723_40}_decoder(code, coding, &state); where coding = AUDIO_ENCODING_ULAW for 8-bit u-law samples AUDIO_ENCODING_ALAW for 8-bit A-law samples AUDIO_ENCODING_LINEAR for 16-bit linear PCM samples This directory also includes the following sample programs: encode.c CCITT ADPCM encoder decode.c CCITT ADPCM decoder Makefile makefile for the sample programs The sample programs contain examples of how to call the various compression routines and pack/unpack the bits. The sample programs read byte streams from stdin and write to stdout. The input/output data is raw data (no file header or other identifying information is embedded). The sample programs are invoked as follows: encode [-3|4|5] [-a|u|l] outfile decode [-3|4|5] [-a|u|l] outfile where: -3 encode to (decode from) G.723 24kbps (3-bit) data -4 encode to (decode from) G.721 32kbps (4-bit) data [the default] -5 encode to (decode from) G.723 40kbps (5-bit) data -a encode from (decode to) A-law data -u encode from (decode to) u-law data [the default] -l encode from (decode to) 16-bit linear data Examples: # Read 16-bit linear and output G.721 encode -4 -l g721file # Read 40Kbps G.723 and output A-law decode -5 -a alawfile # Compress and then decompress u-law data using 24Kbps G.723 encode -3 ulawout nyquist-3.05/nylsf/G72x/g72x_test.c0000644000175000000620000001311711466723256016056 0ustar stevestaff/* ** Copyright (C) 1999-2004 Erik de Castro Lopo ** ** 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. */ #include #include #include #include #include #include "g72x.h" #include "g72x_priv.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338 #endif #define BUFFER_SIZE (1<<14) /* Should be (1<<14) */ #define SAMPLE_RATE 11025 static void g721_test (void) ; static void g723_test (double margin) ; static void gen_signal_double (double *data, double scale, int datalen) ; static int error_function (double data, double orig, double margin) ; static int oct_save_short (short *a, short *b, int len) ; int main (int argc, char *argv []) { int bDoAll = 0 ; int nTests = 0 ; if (argc != 2) { printf ("Usage : %s \n", argv [0]) ; printf (" Where is one of the following:\n") ; printf (" g721 - test G721 encoder and decoder\n") ; printf (" g723 - test G721 encoder and decoder\n") ; printf (" all - perform all tests\n") ; exit (1) ; } ; bDoAll=!strcmp (argv [1], "all"); if (bDoAll || ! strcmp (argv [1], "g721")) { g721_test () ; nTests++ ; } ; if (bDoAll || ! strcmp (argv [1], "g723")) { g723_test (0.53) ; nTests++ ; } ; if (nTests == 0) { printf ("Mono : ************************************\n") ; printf ("Mono : * No '%s' test defined.\n", argv [1]) ; printf ("Mono : ************************************\n") ; return 1 ; } ; return 0 ; } /* main */ static void g721_test (void) { return ; } /* g721_test */ static void g723_test (double margin) { static double orig_buffer [BUFFER_SIZE] ; static short orig [BUFFER_SIZE] ; static short data [BUFFER_SIZE] ; G72x_STATE encoder_state, decoder_state ; long k ; int code, position, max_err ; private_init_state (&encoder_state) ; encoder_state.encoder = g723_24_encoder ; encoder_state.codec_bits = 3 ; private_init_state (&decoder_state) ; decoder_state.decoder = g723_24_decoder ; decoder_state.codec_bits = 3 ; memset (data, 0, BUFFER_SIZE * sizeof (short)) ; memset (orig, 0, BUFFER_SIZE * sizeof (short)) ; printf (" g723_test : ") ; fflush (stdout) ; gen_signal_double (orig_buffer, 32000.0, BUFFER_SIZE) ; for (k = 0 ; k < BUFFER_SIZE ; k++) orig [k] = (short) orig_buffer [k] ; /* Write and read data here. */ position = 0 ; max_err = 0 ; for (k = 0 ; k < BUFFER_SIZE ; k++) { code = encoder_state.encoder (orig [k], &encoder_state) ; data [k] = decoder_state.decoder (code, &decoder_state) ; if (abs (orig [k] - data [k]) > max_err) { position = k ; max_err = abs (orig [k] - data [k]) ; } ; } ; printf ("\n\nMax error of %d at postion %d.\n", max_err, position) ; for (k = 0 ; k < BUFFER_SIZE ; k++) { if (error_function (data [k], orig [k], margin)) { printf ("Line %d: Incorrect sample A (#%ld : %d should be %d).\n", __LINE__, k, data [k], orig [k]) ; oct_save_short (orig, data, BUFFER_SIZE) ; exit (1) ; } ; } ; printf ("ok\n") ; return ; } /* g723_test */ #define SIGNAL_MAXVAL 30000.0 #define DECAY_COUNT 1000 static void gen_signal_double (double *gendata, double scale, int gendatalen) { int k, ramplen ; double amp = 0.0 ; ramplen = DECAY_COUNT ; for (k = 0 ; k < gendatalen ; k++) { if (k <= ramplen) amp = scale * k / ((double) ramplen) ; else if (k > gendatalen - ramplen) amp = scale * (gendatalen - k) / ((double) ramplen) ; gendata [k] = amp * (0.4 * sin (33.3 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE)) + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE))) ; } ; return ; } /* gen_signal_double */ static int error_function (double data, double orig, double margin) { double error ; if (fabs (orig) <= 500.0) error = fabs (fabs (data) - fabs(orig)) / 2000.0 ; else if (fabs (orig) <= 1000.0) error = fabs (data - orig) / 3000.0 ; else error = fabs (data - orig) / fabs (orig) ; if (error > margin) { printf ("\n\n*******************\nError : %f\n", error) ; return 1 ; } ; return 0 ; } /* error_function */ static int oct_save_short (short *a, short *b, int len) { FILE *file ; int k ; if (! (file = fopen ("error.dat", "w"))) return 1 ; fprintf (file, "# Not created by Octave\n") ; fprintf (file, "# name: a\n") ; fprintf (file, "# type: matrix\n") ; fprintf (file, "# rows: %d\n", len) ; fprintf (file, "# columns: 1\n") ; for (k = 0 ; k < len ; k++) fprintf (file, "% d\n", a [k]) ; fprintf (file, "# name: b\n") ; fprintf (file, "# type: matrix\n") ; fprintf (file, "# rows: %d\n", len) ; fprintf (file, "# columns: 1\n") ; for (k = 0 ; k < len ; k++) fprintf (file, "% d\n", b [k]) ; fclose (file) ; return 0 ; } /* oct_save_short */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 0597b442-a5b0-4abf-92a4-92f6c24e85a6 */ nyquist-3.05/nylsf/G72x/g723_40.c0000644000175000000620000001214411466723256015214 0ustar stevestaff/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* * g723_40.c * * Description: * * g723_40_encoder(), g723_40_decoder() * * These routines comprise an implementation of the CCITT G.723 40Kbps * ADPCM coding algorithm. Essentially, this implementation is identical to * the bit level description except for a few deviations which * take advantage of workstation attributes, such as hardware 2's * complement arithmetic. * * The deviation from the bit level specification (lookup tables), * preserves the bit level performance specifications. * * As outlined in the G.723 Recommendation, the algorithm is broken * down into modules. Each section of code below is preceded by * the name of the module which it is implementing. * */ #include "g72x.h" #include "g72x_priv.h" /* * Maps G.723_40 code word to ructeconstructed scale factor normalized log * magnitude values. */ static short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318, 358, 395, 429, 459, 488, 514, 539, 566, 566, 539, 514, 488, 459, 429, 395, 358, 318, 274, 224, 169, 104, 28, -66, -2048}; /* Maps G.723_40 code word to log of scale factor multiplier. */ static short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200, 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, 3200, 1856, 1312, 1280, 1248, 768, 448, 448}; /* * Maps G.723_40 code words to a set of values whose long and short * term averages are computed and then compared to give an indication * how stationary (steady state) the signal is. */ static short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200, 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, 0x200, 0x200, 0x200, 0, 0, 0, 0, 0}; static short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339, 378, 413, 445, 475, 502, 528, 553}; /* * g723_40_encoder() * * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens * the resulting 5-bit CCITT G.723 40Kbps code. * Returns -1 if the input coding value is invalid. */ int g723_40_encoder (int sl, G72x_STATE *state_ptr) { short sei, sezi, se, sez; /* ACCUM */ short d; /* SUBTA */ short y; /* MIX */ short sr; /* ADDB */ short dqsez; /* ADDC */ short dq, i; /* linearize input sample to 14-bit PCM */ sl >>= 2; /* sl of 14-bit dynamic range */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ d = sl - se; /* d = estimation difference */ /* quantize prediction difference */ y = step_size(state_ptr); /* adaptive quantizer step size */ i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */ dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */ sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */ dqsez = sr + sez - se; /* dqsez = pole prediction diff. */ update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); return (i); } /* * g723_40_decoder() * * Decodes a 5-bit CCITT G.723 40Kbps code and returns * the resulting 16-bit linear PCM, A-law or u-law sample value. * -1 is returned if the output coding is unknown. */ int g723_40_decoder (int i, G72x_STATE *state_ptr) { short sezi, sei, sez, se; /* ACCUM */ short y ; /* MIX */ short sr; /* ADDB */ short dq; short dqsez; i &= 0x1f; /* mask to get proper bits */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ y = step_size(state_ptr); /* adaptive quantizer step size */ dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */ sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */ dqsez = sr - se + sez; /* pole prediction diff. */ update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); return (sr << 2); /* sr was of 14-bit dynamic range */ } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: eb8d9a00-32bf-4dd2-b287-01b0336d72bf */ nyquist-3.05/nylsf/G72x/g72x.c0000644000175000000620000004145711466723256015027 0ustar stevestaff/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* * g72x.c * * Common routines for G.721 and G.723 conversions. */ #include #include #include #include "g72x.h" #include "g72x_priv.h" static G72x_STATE * g72x_state_new (void) ; static int unpack_bytes (int bits, int blocksize, const unsigned char * block, short * samples) ; static int pack_bytes (int bits, const short * samples, unsigned char * block) ; static short power2 [15] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 } ; /* * quan() * * quantizes the input val against the table of size short integers. * It returns i if table[i - 1] <= val < table[i]. * * Using linear search for simple coding. */ static int quan (int val, short *table, int size) { int i; for (i = 0; i < size; i++) if (val < *table++) break; return (i); } /* * fmult() * * returns the integer product of the 14-bit integer "an" and * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". */ static int fmult (int an, int srn) { short anmag, anexp, anmant; short wanexp, wanmant; short retval; anmag = (an > 0) ? an : ((-an) & 0x1FFF); anexp = quan(anmag, power2, 15) - 6; anmant = (anmag == 0) ? 32 : (anexp >= 0) ? anmag >> anexp : anmag << -anexp; wanexp = anexp + ((srn >> 6) & 0xF) - 13; /* ** The original was : ** wanmant = (anmant * (srn & 0x37) + 0x30) >> 4 ; ** but could see no valid reason for the + 0x30. ** Removed it and it improved the SNR of the codec. */ wanmant = (anmant * (srn & 0x37)) >> 4 ; retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : (wanmant >> -wanexp); return (((an ^ srn) < 0) ? -retval : retval); } static G72x_STATE * g72x_state_new (void) { return calloc (1, sizeof (G72x_STATE)) ; } /* * private_init_state() * * This routine initializes and/or resets the G72x_PRIVATE structure * pointed to by 'state_ptr'. * All the initial state values are specified in the CCITT G.721 document. */ void private_init_state (G72x_STATE *state_ptr) { int cnta; state_ptr->yl = 34816; state_ptr->yu = 544; state_ptr->dms = 0; state_ptr->dml = 0; state_ptr->ap = 0; for (cnta = 0; cnta < 2; cnta++) { state_ptr->a[cnta] = 0; state_ptr->pk[cnta] = 0; state_ptr->sr[cnta] = 32; } for (cnta = 0; cnta < 6; cnta++) { state_ptr->b[cnta] = 0; state_ptr->dq[cnta] = 32; } state_ptr->td = 0; } /* private_init_state */ struct g72x_state * g72x_reader_init (int codec, int *blocksize, int *samplesperblock) { G72x_STATE *pstate ; if ((pstate = g72x_state_new ()) == NULL) return NULL ; private_init_state (pstate) ; pstate->encoder = NULL ; switch (codec) { case G723_16_BITS_PER_SAMPLE : /* 2 bits per sample. */ pstate->decoder = g723_16_decoder ; *blocksize = G723_16_BYTES_PER_BLOCK ; *samplesperblock = G723_16_SAMPLES_PER_BLOCK ; pstate->codec_bits = 2 ; pstate->blocksize = G723_16_BYTES_PER_BLOCK ; pstate->samplesperblock = G723_16_SAMPLES_PER_BLOCK ; break ; case G723_24_BITS_PER_SAMPLE : /* 3 bits per sample. */ pstate->decoder = g723_24_decoder ; *blocksize = G723_24_BYTES_PER_BLOCK ; *samplesperblock = G723_24_SAMPLES_PER_BLOCK ; pstate->codec_bits = 3 ; pstate->blocksize = G723_24_BYTES_PER_BLOCK ; pstate->samplesperblock = G723_24_SAMPLES_PER_BLOCK ; break ; case G721_32_BITS_PER_SAMPLE : /* 4 bits per sample. */ pstate->decoder = g721_decoder ; *blocksize = G721_32_BYTES_PER_BLOCK ; *samplesperblock = G721_32_SAMPLES_PER_BLOCK ; pstate->codec_bits = 4 ; pstate->blocksize = G721_32_BYTES_PER_BLOCK ; pstate->samplesperblock = G721_32_SAMPLES_PER_BLOCK ; break ; case G721_40_BITS_PER_SAMPLE : /* 5 bits per sample. */ pstate->decoder = g723_40_decoder ; *blocksize = G721_40_BYTES_PER_BLOCK ; *samplesperblock = G721_40_SAMPLES_PER_BLOCK ; pstate->codec_bits = 5 ; pstate->blocksize = G721_40_BYTES_PER_BLOCK ; pstate->samplesperblock = G721_40_SAMPLES_PER_BLOCK ; break ; default : free (pstate) ; return NULL ; } ; return pstate ; } /* g72x_reader_init */ struct g72x_state * g72x_writer_init (int codec, int *blocksize, int *samplesperblock) { G72x_STATE *pstate ; if ((pstate = g72x_state_new ()) == NULL) return NULL ; private_init_state (pstate) ; pstate->decoder = NULL ; switch (codec) { case G723_16_BITS_PER_SAMPLE : /* 2 bits per sample. */ pstate->encoder = g723_16_encoder ; *blocksize = G723_16_BYTES_PER_BLOCK ; *samplesperblock = G723_16_SAMPLES_PER_BLOCK ; pstate->codec_bits = 2 ; pstate->blocksize = G723_16_BYTES_PER_BLOCK ; pstate->samplesperblock = G723_16_SAMPLES_PER_BLOCK ; break ; case G723_24_BITS_PER_SAMPLE : /* 3 bits per sample. */ pstate->encoder = g723_24_encoder ; *blocksize = G723_24_BYTES_PER_BLOCK ; *samplesperblock = G723_24_SAMPLES_PER_BLOCK ; pstate->codec_bits = 3 ; pstate->blocksize = G723_24_BYTES_PER_BLOCK ; pstate->samplesperblock = G723_24_SAMPLES_PER_BLOCK ; break ; case G721_32_BITS_PER_SAMPLE : /* 4 bits per sample. */ pstate->encoder = g721_encoder ; *blocksize = G721_32_BYTES_PER_BLOCK ; *samplesperblock = G721_32_SAMPLES_PER_BLOCK ; pstate->codec_bits = 4 ; pstate->blocksize = G721_32_BYTES_PER_BLOCK ; pstate->samplesperblock = G721_32_SAMPLES_PER_BLOCK ; break ; case G721_40_BITS_PER_SAMPLE : /* 5 bits per sample. */ pstate->encoder = g723_40_encoder ; *blocksize = G721_40_BYTES_PER_BLOCK ; *samplesperblock = G721_40_SAMPLES_PER_BLOCK ; pstate->codec_bits = 5 ; pstate->blocksize = G721_40_BYTES_PER_BLOCK ; pstate->samplesperblock = G721_40_SAMPLES_PER_BLOCK ; break ; default : free (pstate) ; return NULL ; } ; return pstate ; } /* g72x_writer_init */ int g72x_decode_block (G72x_STATE *pstate, const unsigned char *block, short *samples) { int k, count ; count = unpack_bytes (pstate->codec_bits, pstate->blocksize, block, samples) ; for (k = 0 ; k < count ; k++) samples [k] = pstate->decoder (samples [k], pstate) ; return 0 ; } /* g72x_decode_block */ int g72x_encode_block (G72x_STATE *pstate, short *samples, unsigned char *block) { int k, count ; for (k = 0 ; k < pstate->samplesperblock ; k++) samples [k] = pstate->encoder (samples [k], pstate) ; count = pack_bytes (pstate->codec_bits, samples, block) ; return count ; } /* g72x_encode_block */ /* * predictor_zero() * * computes the estimated signal from 6-zero predictor. * */ int predictor_zero (G72x_STATE *state_ptr) { int i; int sezi; sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]); for (i = 1; i < 6; i++) /* ACCUM */ sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]); return (sezi); } /* * predictor_pole() * * computes the estimated signal from 2-pole predictor. * */ int predictor_pole(G72x_STATE *state_ptr) { return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) + fmult(state_ptr->a[0] >> 2, state_ptr->sr[0])); } /* * step_size() * * computes the quantization step size of the adaptive quantizer. * */ int step_size (G72x_STATE *state_ptr) { int y; int dif; int al; if (state_ptr->ap >= 256) return (state_ptr->yu); else { y = state_ptr->yl >> 6; dif = state_ptr->yu - y; al = state_ptr->ap >> 2; if (dif > 0) y += (dif * al) >> 6; else if (dif < 0) y += (dif * al + 0x3F) >> 6; return (y); } } /* * quantize() * * Given a raw sample, 'd', of the difference signal and a * quantization step size scale factor, 'y', this routine returns the * ADPCM codeword to which that sample gets quantized. The step * size scale factor division operation is done in the log base 2 domain * as a subtraction. */ int quantize( int d, /* Raw difference signal sample */ int y, /* Step size multiplier */ short *table, /* quantization table */ int size) /* table size of short integers */ { short dqm; /* Magnitude of 'd' */ short expon; /* Integer part of base 2 log of 'd' */ short mant; /* Fractional part of base 2 log */ short dl; /* Log of magnitude of 'd' */ short dln; /* Step size scale factor normalized log */ int i; /* * LOG * * Compute base 2 log of 'd', and store in 'dl'. */ dqm = abs(d); expon = quan(dqm >> 1, power2, 15); mant = ((dqm << 7) >> expon) & 0x7F; /* Fractional portion. */ dl = (expon << 7) + mant; /* * SUBTB * * "Divide" by step size multiplier. */ dln = dl - (y >> 2); /* * QUAN * * Obtain codword i for 'd'. */ i = quan(dln, table, size); if (d < 0) /* take 1's complement of i */ return ((size << 1) + 1 - i); else if (i == 0) /* take 1's complement of 0 */ return ((size << 1) + 1); /* new in 1988 */ else return (i); } /* * reconstruct() * * Returns reconstructed difference signal 'dq' obtained from * codeword 'i' and quantization step size scale factor 'y'. * Multiplication is performed in log base 2 domain as addition. */ int reconstruct( int sign, /* 0 for non-negative value */ int dqln, /* G.72x codeword */ int y) /* Step size multiplier */ { short dql; /* Log of 'dq' magnitude */ short dex; /* Integer part of log */ short dqt; short dq; /* Reconstructed difference signal sample */ dql = dqln + (y >> 2); /* ADDA */ if (dql < 0) { return ((sign) ? -0x8000 : 0); } else { /* ANTILOG */ dex = (dql >> 7) & 15; dqt = 128 + (dql & 127); dq = (dqt << 7) >> (14 - dex); return ((sign) ? (dq - 0x8000) : dq); } } /* * update() * * updates the state variables for each output code */ void update( int code_size, /* distinguish 723_40 with others */ int y, /* quantizer step size */ int wi, /* scale factor multiplier */ int fi, /* for long/short term energies */ int dq, /* quantized prediction difference */ int sr, /* reconstructed signal */ int dqsez, /* difference from 2-pole predictor */ G72x_STATE *state_ptr) /* coder state pointer */ { int cnt; short mag, expon; /* Adaptive predictor, FLOAT A */ short a2p = 0; /* LIMC */ short a1ul; /* UPA1 */ short pks1; /* UPA2 */ short fa1; char tr; /* tone/transition detector */ short ylint, thr2, dqthr; short ylfrac, thr1; short pk0; pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */ mag = dq & 0x7FFF; /* prediction difference magnitude */ /* TRANS */ ylint = state_ptr->yl >> 15; /* exponent part of yl */ ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */ thr1 = (32 + ylfrac) << ylint; /* threshold */ thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */ dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */ if (state_ptr->td == 0) /* signal supposed voice */ tr = 0; else if (mag <= dqthr) /* supposed data, but small mag */ tr = 0; /* treated as voice */ else /* signal is data (modem) */ tr = 1; /* * Quantizer scale factor adaptation. */ /* FUNCTW & FILTD & DELAY */ /* update non-steady state step size multiplier */ state_ptr->yu = y + ((wi - y) >> 5); /* LIMB */ if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */ state_ptr->yu = 544; else if (state_ptr->yu > 5120) state_ptr->yu = 5120; /* FILTE & DELAY */ /* update steady state step size multiplier */ state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6); /* * Adaptive predictor coefficients. */ if (tr == 1) { /* reset a's and b's for modem signal */ state_ptr->a[0] = 0; state_ptr->a[1] = 0; state_ptr->b[0] = 0; state_ptr->b[1] = 0; state_ptr->b[2] = 0; state_ptr->b[3] = 0; state_ptr->b[4] = 0; state_ptr->b[5] = 0; } else { /* update a's and b's */ pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */ /* update predictor pole a[1] */ a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7); if (dqsez != 0) { fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0]; if (fa1 < -8191) /* a2p = function of fa1 */ a2p -= 0x100; else if (fa1 > 8191) a2p += 0xFF; else a2p += fa1 >> 5; if (pk0 ^ state_ptr->pk[1]) { /* LIMC */ if (a2p <= -12160) a2p = -12288; else if (a2p >= 12416) a2p = 12288; else a2p -= 0x80; } else if (a2p <= -12416) a2p = -12288; else if (a2p >= 12160) a2p = 12288; else a2p += 0x80; } /* TRIGB & DELAY */ state_ptr->a[1] = a2p; /* UPA1 */ /* update predictor pole a[0] */ state_ptr->a[0] -= state_ptr->a[0] >> 8; if (dqsez != 0) { if (pks1 == 0) state_ptr->a[0] += 192; else state_ptr->a[0] -= 192; } ; /* LIMD */ a1ul = 15360 - a2p; if (state_ptr->a[0] < -a1ul) state_ptr->a[0] = -a1ul; else if (state_ptr->a[0] > a1ul) state_ptr->a[0] = a1ul; /* UPB : update predictor zeros b[6] */ for (cnt = 0; cnt < 6; cnt++) { if (code_size == 5) /* for 40Kbps G.723 */ state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9; else /* for G.721 and 24Kbps G.723 */ state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8; if (dq & 0x7FFF) { /* XOR */ if ((dq ^ state_ptr->dq[cnt]) >= 0) state_ptr->b[cnt] += 128; else state_ptr->b[cnt] -= 128; } } } for (cnt = 5; cnt > 0; cnt--) state_ptr->dq[cnt] = state_ptr->dq[cnt-1]; /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ if (mag == 0) { state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20; } else { expon = quan(mag, power2, 15); state_ptr->dq[0] = (dq >= 0) ? (expon << 6) + ((mag << 6) >> expon) : (expon << 6) + ((mag << 6) >> expon) - 0x400; } state_ptr->sr[1] = state_ptr->sr[0]; /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ if (sr == 0) { state_ptr->sr[0] = 0x20; } else if (sr > 0) { expon = quan(sr, power2, 15); state_ptr->sr[0] = (expon << 6) + ((sr << 6) >> expon); } else if (sr > -32768) { mag = -sr; expon = quan(mag, power2, 15); state_ptr->sr[0] = (expon << 6) + ((mag << 6) >> expon) - 0x400; } else state_ptr->sr[0] = (short) 0xFC20; /* DELAY A */ state_ptr->pk[1] = state_ptr->pk[0]; state_ptr->pk[0] = pk0; /* TONE */ if (tr == 1) /* this sample has been treated as data */ state_ptr->td = 0; /* next one will be treated as voice */ else if (a2p < -11776) /* small sample-to-sample correlation */ state_ptr->td = 1; /* signal may be data */ else /* signal is voice */ state_ptr->td = 0; /* * Adaptation speed control. */ state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */ state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */ if (tr == 1) state_ptr->ap = 256; else if (y < 1536) /* SUBTC */ state_ptr->ap += (0x200 - state_ptr->ap) >> 4; else if (state_ptr->td == 1) state_ptr->ap += (0x200 - state_ptr->ap) >> 4; else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= (state_ptr->dml >> 3)) state_ptr->ap += (0x200 - state_ptr->ap) >> 4; else state_ptr->ap += (-state_ptr->ap) >> 4; return ; } /* update */ /*------------------------------------------------------------------------------ */ static int unpack_bytes (int bits, int blocksize, const unsigned char * block, short * samples) { unsigned int in_buffer = 0 ; unsigned char in_byte ; int k, in_bits = 0, bindex = 0 ; for (k = 0 ; bindex <= blocksize && k < G72x_BLOCK_SIZE ; k++) { if (in_bits < bits) { in_byte = block [bindex++] ; in_buffer |= (in_byte << in_bits); in_bits += 8; } samples [k] = in_buffer & ((1 << bits) - 1); in_buffer >>= bits; in_bits -= bits; } ; return k ; } /* unpack_bytes */ static int pack_bytes (int bits, const short * samples, unsigned char * block) { unsigned int out_buffer = 0 ; int k, bindex = 0, out_bits = 0 ; unsigned char out_byte ; for (k = 0 ; k < G72x_BLOCK_SIZE ; k++) { out_buffer |= (samples [k] << out_bits) ; out_bits += bits ; if (out_bits >= 8) { out_byte = out_buffer & 0xFF ; out_bits -= 8 ; out_buffer >>= 8 ; block [bindex++] = out_byte ; } } ; return bindex ; } /* pack_bytes */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 6298dc75-fd0f-4062-9b90-f73ed69f22d4 */ nyquist-3.05/nylsf/G72x/g723_16.c0000644000175000000620000001310711466723256015217 0ustar stevestaff/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ /* 16kbps version created, used 24kbps code and changing as little as possible. * G.726 specs are available from ITU's gopher or WWW site (http://www.itu.ch) * If any errors are found, please contact me at mrand@tamu.edu * -Marc Randolph */ /* * g723_16.c * * Description: * * g723_16_encoder(), g723_16_decoder() * * These routines comprise an implementation of the CCITT G.726 16 Kbps * ADPCM coding algorithm. Essentially, this implementation is identical to * the bit level description except for a few deviations which take advantage * of workstation attributes, such as hardware 2's complement arithmetic. * */ #include "g72x.h" #include "g72x_priv.h" /* * Maps G.723_16 code word to reconstructed scale factor normalized log * magnitude values. Comes from Table 11/G.726 */ static short _dqlntab[4] = { 116, 365, 365, 116}; /* Maps G.723_16 code word to log of scale factor multiplier. * * _witab[4] is actually {-22 , 439, 439, -22}, but FILTD wants it * as WI << 5 (multiplied by 32), so we'll do that here */ static short _witab[4] = {-704, 14048, 14048, -704}; /* * Maps G.723_16 code words to a set of values whose long and short * term averages are computed and then compared to give an indication * how stationary (steady state) the signal is. */ /* Comes from FUNCTF */ static short _fitab[4] = {0, 0xE00, 0xE00, 0}; /* Comes from quantizer decision level tables (Table 7/G.726) */ static short qtab_723_16[1] = {261}; /* * g723_16_encoder() * * Encodes a linear PCM, A-law or u-law input sample and returns its 2-bit code. * Returns -1 if invalid input coding value. */ int g723_16_encoder( int sl, G72x_STATE *state_ptr) { short sei, sezi, se, sez; /* ACCUM */ short d; /* SUBTA */ short y; /* MIX */ short sr; /* ADDB */ short dqsez; /* ADDC */ short dq, i; /* linearize input sample to 14-bit PCM */ sl >>= 2; /* sl of 14-bit dynamic range */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ d = sl - se; /* d = estimation diff. */ /* quantize prediction difference d */ y = step_size(state_ptr); /* quantizer step size */ i = quantize(d, y, qtab_723_16, 1); /* i = ADPCM code */ /* Since quantize() only produces a three level output * (1, 2, or 3), we must create the fourth one on our own */ if (i == 3) /* i code for the zero region */ if ((d & 0x8000) == 0) /* If d > 0, i=3 isn't right... */ i = 0; dq = reconstruct(i & 2, _dqlntab[i], y); /* quantized diff. */ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */ dqsez = sr + sez - se; /* pole prediction diff. */ update(2, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); return (i); } /* * g723_16_decoder() * * Decodes a 2-bit CCITT G.723_16 ADPCM code and returns * the resulting 16-bit linear PCM, A-law or u-law sample value. * -1 is returned if the output coding is unknown. */ int g723_16_decoder( int i, G72x_STATE *state_ptr) { short sezi, sei, sez, se; /* ACCUM */ short y; /* MIX */ short sr; /* ADDB */ short dq; short dqsez; i &= 0x03; /* mask to get proper bits */ sezi = predictor_zero(state_ptr); sez = sezi >> 1; sei = sezi + predictor_pole(state_ptr); se = sei >> 1; /* se = estimated signal */ y = step_size(state_ptr); /* adaptive quantizer step size */ dq = reconstruct(i & 0x02, _dqlntab[i], y); /* unquantize pred diff */ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */ dqsez = sr - se + sez; /* pole prediction diff. */ update(2, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); /* sr was of 14-bit dynamic range */ return (sr << 2); } /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: ae265466-c3fc-4f83-bb32-edae488a5ca5 */ nyquist-3.05/nylsf/G72x/g72x_priv.h0000644000175000000620000001015111466723256016057 0ustar stevestaff/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #ifndef G72X_PRIVATE_H #define G72X_PRIVATE_H #ifdef __cplusplus #error "This code is not designed to be compiled with a C++ compiler." #endif /* ** The following is the definition of the state structure used by the ** G.721/G.723 encoder and decoder to preserve their internal state ** between successive calls. The meanings of the majority of the state ** structure fields are explained in detail in the CCITT Recommendation ** G.721. The field names are essentially identical to variable names ** in the bit level description of the coding algorithm included in this ** Recommendation. */ struct g72x_state { long yl; /* Locked or steady state step size multiplier. */ short yu; /* Unlocked or non-steady state step size multiplier. */ short dms; /* Short term energy estimate. */ short dml; /* Long term energy estimate. */ short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */ short a[2]; /* Coefficients of pole portion of prediction filter. */ short b[6]; /* Coefficients of zero portion of prediction filter. */ short pk[2]; /* ** Signs of previous two samples of a partially ** reconstructed signal. **/ short dq[6]; /* ** Previous 6 samples of the quantized difference ** signal represented in an internal floating point ** format. **/ short sr[2]; /* ** Previous 2 samples of the quantized difference ** signal represented in an internal floating point ** format. */ char td; /* delayed tone detect, new in 1988 version */ /* The following struct members were added for libsndfile. The original ** code worked by calling a set of functions on a sample by sample basis ** which is slow on architectures like Intel x86. For libsndfile, this ** was changed so that the encoding and decoding routines could work on ** a block of samples at a time to reduce the function call overhead. */ int (*encoder) (int, struct g72x_state* state) ; int (*decoder) (int, struct g72x_state* state) ; int codec_bits, blocksize, samplesperblock ; } ; typedef struct g72x_state G72x_STATE ; int predictor_zero (G72x_STATE *state_ptr); int predictor_pole (G72x_STATE *state_ptr); int step_size (G72x_STATE *state_ptr); int quantize (int d, int y, short *table, int size); int reconstruct (int sign, int dqln, int y); void update (int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, G72x_STATE *state_ptr); int g721_encoder (int sample, G72x_STATE *state_ptr); int g721_decoder (int code, G72x_STATE *state_ptr); int g723_16_encoder (int sample, G72x_STATE *state_ptr); int g723_16_decoder (int code, G72x_STATE *state_ptr); int g723_24_encoder (int sample, G72x_STATE *state_ptr); int g723_24_decoder (int code, G72x_STATE *state_ptr); int g723_40_encoder (int sample, G72x_STATE *state_ptr); int g723_40_decoder (int code, G72x_STATE *state_ptr); void private_init_state (G72x_STATE *state_ptr) ; #endif /* G72X_PRIVATE_H */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: d9ad4da7-0fa3-471d-8020-720b5cfb5e5b */ nyquist-3.05/nylsf/test_log_printf.c0000644000175000000620000001046311466723256016704 0ustar stevestaff/* ** Copyright (C) 2003-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include #include #include #include #include #include "sfconfig.h" /* ** This is a bit rough, but it is the nicest way to do it. */ #define PSF_LOG_PRINTF_ONLY #include "common.c" #define CMP_0_ARGS(line,err,fmt) \ { psf->logindex = 0 ; \ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt)) ; \ psf_log_printf (psf, (fmt)) ; \ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \ } #define CMP_2_ARGS(line,err,fmt,a) \ { psf->logindex = 0 ; \ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt), (a), (a)) ; \ psf_log_printf (psf, (fmt), (a), (a)) ; \ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \ } #define CMP_4_ARGS(line,err,fmt,a) \ { psf->logindex = 0 ; \ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt), (a), (a), (a), (a)) ; \ psf_log_printf (psf, (fmt), (a), (a), (a), (a)) ; \ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \ } #define CMP_5_ARGS(line,err,fmt,a) \ { psf->logindex = 0 ; \ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt), (a), (a), (a), (a), (a)) ; \ psf_log_printf (psf, (fmt), (a), (a), (a), (a), (a)) ; \ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \ } #define CMP_6_ARGS(line,err,fmt,a) \ { psf->logindex = 0 ; \ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt), (a), (a), (a), (a), (a), (a)) ; \ psf_log_printf (psf, (fmt), (a), (a), (a), (a), (a), (a)) ; \ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \ } static int compare_strings_or_die (int linenum, const char *fmt, const char* s1, const char* s3) ; int main (void) { static char buffer [2048] ; SF_PRIVATE sf_private, *psf ; int k, errors = 0 ; int int_values [] = { 0, 1, 12, 123, 1234, 123456, -1, -12, -123, -1234, -123456 } ; printf (" %-24s : ", "psf_log_printf_test") ; fflush (stdout) ; psf = &sf_private ; memset (psf, 0, sizeof (sf_private)) ; CMP_0_ARGS (__LINE__, errors, " ->%%<- ") ; /* Test printing of ints. */ for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) CMP_6_ARGS (__LINE__, errors, "int A : %d, % d, %4d, % 4d, %04d, % 04d", int_values [k]) ; for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) CMP_5_ARGS (__LINE__, errors, "int B : %+d, %+4d, %+04d, %-d, %-4d", int_values [k]) ; for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) CMP_2_ARGS (__LINE__, errors, "int C : %- d, %- 4d", int_values [k]) ; /* Test printing of unsigned ints. */ for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) CMP_4_ARGS (__LINE__, errors, "D : %u, %4u, %04u, %0u", int_values [k]) ; /* Test printing of hex ints. */ for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) CMP_4_ARGS (__LINE__, errors, "E : %X, %4X, %04X, %0X", int_values [k]) ; /* Test printing of strings. */ CMP_4_ARGS (__LINE__, errors, "B %s, %3s, %8s, %-8s", "str") ; if (errors) { puts ("\nExiting due to errors.\n") ; exit (1) ; } ; puts ("ok") ; return 0 ; } /* main */ static int compare_strings_or_die (int linenum, const char *fmt, const char* s1, const char* s2) { int errors = 0 ; /*-puts (s1) ;puts (s2) ;-*/ if (strcmp (s1, s2) != 0) { printf ("\n\nLine %d: string compare mismatch:\n\t", linenum) ; printf ("\"%s\"\n", fmt) ; printf ("\t\"%s\"\n\t\"%s\"\n", s1, s2) ; errors ++ ; } ; return errors ; } /* compare_strings_or_die */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 45147310-868b-400a-97e8-cc0a572a6270 */ nyquist-3.05/nylsf/mat5.c0000644000175000000620000003365611466723256014361 0ustar stevestaff/* ** Copyright (C) 2002-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "float_cast.h" /*------------------------------------------------------------------------------ ** Information on how to decode and encode this file was obtained in a PDF ** file which I found on http://www.wotsit.org/. ** Also did a lot of testing with GNU Octave but do not have access to ** Matlab (tm) and so could not test it there. */ /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define MATL_MARKER (MAKE_MARKER ('M', 'A', 'T', 'L')) #define IM_MARKER (('I' << 8) + 'M') #define MI_MARKER (('M' << 8) + 'I') /*------------------------------------------------------------------------------ ** Enums and typedefs. */ enum { MAT5_TYPE_SCHAR = 0x1, MAT5_TYPE_UCHAR = 0x2, MAT5_TYPE_INT16 = 0x3, MAT5_TYPE_UINT16 = 0x4, MAT5_TYPE_INT32 = 0x5, MAT5_TYPE_UINT32 = 0x6, MAT5_TYPE_FLOAT = 0x7, MAT5_TYPE_DOUBLE = 0x9, MAT5_TYPE_ARRAY = 0xE, MAT5_TYPE_COMP_USHORT = 0x00020004, MAT5_TYPE_COMP_UINT = 0x00040006 } ; typedef struct { sf_count_t size ; int rows, cols ; char name [32] ; } MAT5_MATRIX ; /*------------------------------------------------------------------------------ ** Private static functions. */ static int mat5_close (SF_PRIVATE *psf) ; static int mat5_write_header (SF_PRIVATE *psf, int calc_length) ; static int mat5_read_header (SF_PRIVATE *psf) ; /*------------------------------------------------------------------------------ ** Public function. */ int mat5_open (SF_PRIVATE *psf) { int subformat, error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = mat5_read_header (psf))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_MAT5) return SFE_BAD_OPEN_FORMAT ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) psf->endian = SF_ENDIAN_LITTLE ; else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) psf->endian = SF_ENDIAN_BIG ; if ((error = mat5_write_header (psf, SF_FALSE))) return error ; psf->write_header = mat5_write_header ; } ; psf->container_close = mat5_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_PCM_U8 : case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; default : break ; } ; return error ; } /* mat5_open */ /*------------------------------------------------------------------------------ */ static int mat5_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) mat5_write_header (psf, SF_TRUE) ; return 0 ; } /* mat5_close */ /*------------------------------------------------------------------------------ */ static int mat5_write_header (SF_PRIVATE *psf, int calc_length) { static const char *filename = "MATLAB 5.0 MAT-file, written by " PACKAGE "-" VERSION ", " ; static const char *sr_name = "samplerate\0\0\0\0\0\0\0\0\0\0\0" ; static const char *wd_name = "wavedata\0" ; sf_count_t current, datasize ; int encoding ; current = psf_ftell (psf) ; if (calc_length) { psf_fseek (psf, 0, SEEK_END) ; psf->filelength = psf_ftell (psf) ; psf_fseek (psf, 0, SEEK_SET) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_U8 : encoding = MAT5_TYPE_UCHAR ; break ; case SF_FORMAT_PCM_16 : encoding = MAT5_TYPE_INT16 ; break ; case SF_FORMAT_PCM_32 : encoding = MAT5_TYPE_INT32 ; break ; case SF_FORMAT_FLOAT : encoding = MAT5_TYPE_FLOAT ; break ; case SF_FORMAT_DOUBLE : encoding = MAT5_TYPE_DOUBLE ; break ; default : return SFE_BAD_OPEN_FORMAT ; } ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; psf_get_date_str (psf->u.cbuf, sizeof (psf->u.scbuf)) ; psf_binheader_writef (psf, "bb", filename, strlen (filename), psf->u.cbuf, strlen (psf->u.cbuf) + 1) ; memset (psf->u.scbuf, ' ', 124 - psf->headindex) ; psf_binheader_writef (psf, "b", psf->u.scbuf, make_size_t (124 - psf->headindex)) ; psf->rwf_endian = psf->endian ; if (psf->rwf_endian == SF_ENDIAN_BIG) psf_binheader_writef (psf, "2b", 0x0100, "MI", make_size_t (2)) ; else psf_binheader_writef (psf, "2b", 0x0100, "IM", make_size_t (2)) ; psf_binheader_writef (psf, "444444", MAT5_TYPE_ARRAY, 64, MAT5_TYPE_UINT32, 8, 6, 0) ; psf_binheader_writef (psf, "4444", MAT5_TYPE_INT32, 8, 1, 1) ; psf_binheader_writef (psf, "44b", MAT5_TYPE_SCHAR, strlen (sr_name), sr_name, make_size_t (16)) ; if (psf->sf.samplerate > 0xFFFF) psf_binheader_writef (psf, "44", MAT5_TYPE_COMP_UINT, psf->sf.samplerate) ; else { unsigned short samplerate = psf->sf.samplerate ; psf_binheader_writef (psf, "422", MAT5_TYPE_COMP_USHORT, samplerate, 0) ; } ; datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ; psf_binheader_writef (psf, "t484444", MAT5_TYPE_ARRAY, datasize + 64, MAT5_TYPE_UINT32, 8, 6, 0) ; psf_binheader_writef (psf, "t4448", MAT5_TYPE_INT32, 8, psf->sf.channels, psf->sf.frames) ; psf_binheader_writef (psf, "44b", MAT5_TYPE_SCHAR, strlen (wd_name), wd_name, strlen (wd_name)) ; datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ; if (datasize > 0x7FFFFFFF) datasize = 0x7FFFFFFF ; psf_binheader_writef (psf, "t48", encoding, datasize) ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* mat5_write_header */ static int mat5_read_header (SF_PRIVATE *psf) { char name [32] ; short version, endian ; int type, size, flags1, flags2, rows, cols ; psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, 124) ; psf->u.scbuf [125] = 0 ; if (strlen (psf->u.cbuf) >= 124) return SFE_UNIMPLEMENTED ; if (strstr (psf->u.cbuf, "MATLAB 5.0 MAT-file") == psf->u.cbuf) psf_log_printf (psf, "%s\n", psf->u.scbuf) ; psf_binheader_readf (psf, "E22", &version, &endian) ; if (endian == MI_MARKER) { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; if (CPU_IS_LITTLE_ENDIAN) version = ENDSWAP_SHORT (version) ; } else if (endian == IM_MARKER) { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; if (CPU_IS_BIG_ENDIAN) version = ENDSWAP_SHORT (version) ; } else return SFE_MAT5_BAD_ENDIAN ; if ((CPU_IS_LITTLE_ENDIAN && endian == IM_MARKER) || (CPU_IS_BIG_ENDIAN && endian == MI_MARKER)) version = ENDSWAP_SHORT (version) ; psf_log_printf (psf, "Version : 0x%04X\n", version) ; psf_log_printf (psf, "Endian : 0x%04X => %s\n", endian, (psf->endian == SF_ENDIAN_LITTLE) ? "Little" : "Big") ; /*========================================================*/ psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, "Block\n Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_ARRAY) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_UINT32) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &flags1, &flags2) ; psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_INT32) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &rows, &cols) ; psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ; if (rows != 1 || cols != 1) return SFE_MAT5_SAMPLE_RATE ; psf_binheader_readf (psf, "4", &type) ; if (type == MAT5_TYPE_SCHAR) { psf_binheader_readf (psf, "4", &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (size > SIGNED_SIZEOF (name) - 1) { psf_log_printf (psf, "Error : Bad name length.\n") ; return SFE_MAT5_NO_BLOCK ; } ; psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ; name [size] = 0 ; } else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR) { size = type >> 16 ; if (size > 4) { psf_log_printf (psf, "Error : Bad name length.\n") ; return SFE_MAT5_NO_BLOCK ; } ; psf_log_printf (psf, " Type : %X\n", type) ; psf_binheader_readf (psf, "4", &name) ; name [size] = 0 ; } else return SFE_MAT5_NO_BLOCK ; psf_log_printf (psf, " Name : %s\n", name) ; /*-----------------------------------------*/ psf_binheader_readf (psf, "44", &type, &size) ; switch (type) { case MAT5_TYPE_DOUBLE : { double samplerate ; psf_binheader_readf (psf, "d", &samplerate) ; LSF_SNPRINTF (name, sizeof (name), "%f\n", samplerate) ; psf_log_printf (psf, " Val : %s\n", name) ; psf->sf.samplerate = lrint (samplerate) ; } ; break ; case MAT5_TYPE_COMP_USHORT : { unsigned short samplerate ; psf_binheader_readf (psf, "j2j", -4, &samplerate, 2) ; psf_log_printf (psf, " Val : %u\n", samplerate) ; psf->sf.samplerate = samplerate ; } break ; case MAT5_TYPE_COMP_UINT : psf_log_printf (psf, " Val : %u\n", size) ; psf->sf.samplerate = size ; break ; default : psf_log_printf (psf, " Type : %X Size : %d ***\n", type, size) ; return SFE_MAT5_SAMPLE_RATE ; } ; /*-----------------------------------------*/ psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_ARRAY) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_UINT32) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &flags1, &flags2) ; psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (type != MAT5_TYPE_INT32) return SFE_MAT5_NO_BLOCK ; psf_binheader_readf (psf, "44", &rows, &cols) ; psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ; psf_binheader_readf (psf, "4", &type) ; if (type == MAT5_TYPE_SCHAR) { psf_binheader_readf (psf, "4", &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; if (size > SIGNED_SIZEOF (name) - 1) { psf_log_printf (psf, "Error : Bad name length.\n") ; return SFE_MAT5_NO_BLOCK ; } ; psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ; name [size] = 0 ; } else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR) { size = type >> 16 ; if (size > 4) { psf_log_printf (psf, "Error : Bad name length.\n") ; return SFE_MAT5_NO_BLOCK ; } ; psf_log_printf (psf, " Type : %X\n", type) ; psf_binheader_readf (psf, "4", &name) ; name [size] = 0 ; } else return SFE_MAT5_NO_BLOCK ; psf_log_printf (psf, " Name : %s\n", name) ; psf_binheader_readf (psf, "44", &type, &size) ; psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; /*++++++++++++++++++++++++++++++++++++++++++++++++++*/ if (rows == 0 && cols == 0) { psf_log_printf (psf, "*** Error : zero channel count.\n") ; return SFE_MAT5_ZERO_CHANNELS ; } ; psf->sf.channels = rows ; psf->sf.frames = cols ; psf->sf.format = psf->endian | SF_FORMAT_MAT5 ; switch (type) { case MAT5_TYPE_DOUBLE : psf_log_printf (psf, "Data type : double\n") ; psf->sf.format |= SF_FORMAT_DOUBLE ; psf->bytewidth = 8 ; break ; case MAT5_TYPE_FLOAT : psf_log_printf (psf, "Data type : float\n") ; psf->sf.format |= SF_FORMAT_FLOAT ; psf->bytewidth = 4 ; break ; case MAT5_TYPE_INT32 : psf_log_printf (psf, "Data type : 32 bit PCM\n") ; psf->sf.format |= SF_FORMAT_PCM_32 ; psf->bytewidth = 4 ; break ; case MAT5_TYPE_INT16 : psf_log_printf (psf, "Data type : 16 bit PCM\n") ; psf->sf.format |= SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; case MAT5_TYPE_UCHAR : psf_log_printf (psf, "Data type : unsigned 8 bit PCM\n") ; psf->sf.format |= SF_FORMAT_PCM_U8 ; psf->bytewidth = 1 ; break ; default : psf_log_printf (psf, "*** Error : Bad marker %08X\n", type) ; return SFE_UNIMPLEMENTED ; } ; psf->dataoffset = psf_ftell (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; return 0 ; } /* mat5_read_header */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: dfdb6742-b2be-4be8-b390-d0c674e8bc8e */ nyquist-3.05/nylsf/mat4.c0000644000175000000620000002552411466723256014353 0ustar stevestaff/* ** Copyright (C) 2002-2006 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "float_cast.h" /*------------------------------------------------------------------------------ ** Information on how to decode and encode this file was obtained in a PDF ** file which I found on http://www.wotsit.org/. ** Also did a lot of testing with GNU Octave but do not have access to ** Matlab (tm) and so could not test it there. */ /*------------------------------------------------------------------------------ ** Macros to handle big/little endian issues. */ #define MAT4_BE_DOUBLE (MAKE_MARKER (0, 0, 0x03, 0xE8)) #define MAT4_LE_DOUBLE (MAKE_MARKER (0, 0, 0, 0)) #define MAT4_BE_FLOAT (MAKE_MARKER (0, 0, 0x03, 0xF2)) #define MAT4_LE_FLOAT (MAKE_MARKER (0x0A, 0, 0, 0)) #define MAT4_BE_PCM_32 (MAKE_MARKER (0, 0, 0x03, 0xFC)) #define MAT4_LE_PCM_32 (MAKE_MARKER (0x14, 0, 0, 0)) #define MAT4_BE_PCM_16 (MAKE_MARKER (0, 0, 0x04, 0x06)) #define MAT4_LE_PCM_16 (MAKE_MARKER (0x1E, 0, 0, 0)) /* Can't see any reason to ever implement this. */ #define MAT4_BE_PCM_U8 (MAKE_MARKER (0, 0, 0x04, 0x1A)) #define MAT4_LE_PCM_U8 (MAKE_MARKER (0x32, 0, 0, 0)) /*------------------------------------------------------------------------------ ** Private static functions. */ static int mat4_close (SF_PRIVATE *psf) ; static int mat4_format_to_encoding (int format, int endian) ; static int mat4_write_header (SF_PRIVATE *psf, int calc_length) ; static int mat4_read_header (SF_PRIVATE *psf) ; static const char * mat4_marker_to_str (int marker) ; /*------------------------------------------------------------------------------ ** Public function. */ int mat4_open (SF_PRIVATE *psf) { int subformat, error = 0 ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = mat4_read_header (psf))) return error ; } ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_MAT4) return SFE_BAD_OPEN_FORMAT ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ; if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) psf->endian = SF_ENDIAN_LITTLE ; else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) psf->endian = SF_ENDIAN_BIG ; if ((error = mat4_write_header (psf, SF_FALSE))) return error ; psf->write_header = mat4_write_header ; } ; psf->container_close = mat4_close ; psf->blockwidth = psf->bytewidth * psf->sf.channels ; switch (subformat) { case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; default : break ; } ; if (error) return error ; return error ; } /* mat4_open */ /*------------------------------------------------------------------------------ */ static int mat4_close (SF_PRIVATE *psf) { if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) mat4_write_header (psf, SF_TRUE) ; return 0 ; } /* mat4_close */ /*------------------------------------------------------------------------------ */ static int mat4_write_header (SF_PRIVATE *psf, int calc_length) { sf_count_t current ; int encoding ; double samplerate ; current = psf_ftell (psf) ; if (calc_length) { psf->filelength = psf_get_filelen (psf) ; psf->datalength = psf->filelength - psf->dataoffset ; if (psf->dataend) psf->datalength -= psf->filelength - psf->dataend ; psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; } ; encoding = mat4_format_to_encoding (psf->sf.format & SF_FORMAT_SUBMASK, psf->endian) ; if (encoding == -1) return SFE_BAD_OPEN_FORMAT ; /* Reset the current header length to zero. */ psf->header [0] = 0 ; psf->headindex = 0 ; psf_fseek (psf, 0, SEEK_SET) ; /* Need sample rate as a double for writing to the header. */ samplerate = psf->sf.samplerate ; if (psf->endian == SF_ENDIAN_BIG) { psf_binheader_writef (psf, "Em444", MAT4_BE_DOUBLE, 1, 1, 0) ; psf_binheader_writef (psf, "E4bd", 11, "samplerate", make_size_t (11), samplerate) ; psf_binheader_writef (psf, "tEm484", encoding, psf->sf.channels, psf->sf.frames, 0) ; psf_binheader_writef (psf, "E4b", 9, "wavedata", make_size_t (9)) ; } else if (psf->endian == SF_ENDIAN_LITTLE) { psf_binheader_writef (psf, "em444", MAT4_LE_DOUBLE, 1, 1, 0) ; psf_binheader_writef (psf, "e4bd", 11, "samplerate", make_size_t (11), samplerate) ; psf_binheader_writef (psf, "tem484", encoding, psf->sf.channels, psf->sf.frames, 0) ; psf_binheader_writef (psf, "e4b", 9, "wavedata", make_size_t (9)) ; } else return SFE_BAD_OPEN_FORMAT ; /* Header construction complete so write it out. */ psf_fwrite (psf->header, psf->headindex, 1, psf) ; if (psf->error) return psf->error ; psf->dataoffset = psf->headindex ; if (current > 0) psf_fseek (psf, current, SEEK_SET) ; return psf->error ; } /* mat4_write_header */ static int mat4_read_header (SF_PRIVATE *psf) { int marker, namesize, rows, cols, imag ; double value ; const char *marker_str ; char name [64] ; psf_binheader_readf (psf, "pm", 0, &marker) ; /* MAT4 file must start with a double for the samplerate. */ if (marker == MAT4_BE_DOUBLE) { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; marker_str = "big endian double" ; } else if (marker == MAT4_LE_DOUBLE) { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; marker_str = "little endian double" ; } else return SFE_UNIMPLEMENTED ; psf_log_printf (psf, "GNU Octave 2.0 / MATLAB v4.2 format\nMarker : %s\n", marker_str) ; psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; psf_binheader_readf (psf, "4", &namesize) ; if (namesize >= SIGNED_SIZEOF (name)) return SFE_MAT4_BAD_NAME ; psf_binheader_readf (psf, "b", name, namesize) ; name [namesize] = 0 ; psf_log_printf (psf, " Name : %s\n", name) ; psf_binheader_readf (psf, "d", &value) ; LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), " Value : %f\n", value) ; psf_log_printf (psf, psf->u.cbuf) ; if ((rows != 1) || (cols != 1)) return SFE_MAT4_NO_SAMPLERATE ; psf->sf.samplerate = lrint (value) ; /* Now write out the audio data. */ psf_binheader_readf (psf, "m", &marker) ; psf_log_printf (psf, "Marker : %s\n", mat4_marker_to_str (marker)) ; psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; psf_binheader_readf (psf, "4", &namesize) ; if (namesize >= SIGNED_SIZEOF (name)) return SFE_MAT4_BAD_NAME ; psf_binheader_readf (psf, "b", name, namesize) ; name [namesize] = 0 ; psf_log_printf (psf, " Name : %s\n", name) ; psf->dataoffset = psf_ftell (psf) ; if (rows == 0 && cols == 0) { psf_log_printf (psf, "*** Error : zero channel count.\n") ; return SFE_MAT4_ZERO_CHANNELS ; } ; psf->sf.channels = rows ; psf->sf.frames = cols ; psf->sf.format = psf->endian | SF_FORMAT_MAT4 ; switch (marker) { case MAT4_BE_DOUBLE : case MAT4_LE_DOUBLE : psf->sf.format |= SF_FORMAT_DOUBLE ; psf->bytewidth = 8 ; break ; case MAT4_BE_FLOAT : case MAT4_LE_FLOAT : psf->sf.format |= SF_FORMAT_FLOAT ; psf->bytewidth = 4 ; break ; case MAT4_BE_PCM_32 : case MAT4_LE_PCM_32 : psf->sf.format |= SF_FORMAT_PCM_32 ; psf->bytewidth = 4 ; break ; case MAT4_BE_PCM_16 : case MAT4_LE_PCM_16 : psf->sf.format |= SF_FORMAT_PCM_16 ; psf->bytewidth = 2 ; break ; default : psf_log_printf (psf, "*** Error : Bad marker %08X\n", marker) ; return SFE_UNIMPLEMENTED ; } ; if ((psf->filelength - psf->dataoffset) < psf->sf.channels * psf->sf.frames * psf->bytewidth) { psf_log_printf (psf, "*** File seems to be truncated. %D <--> %D\n", psf->filelength - psf->dataoffset, psf->sf.channels * psf->sf.frames * psf->bytewidth) ; } else if ((psf->filelength - psf->dataoffset) > psf->sf.channels * psf->sf.frames * psf->bytewidth) psf->dataend = psf->dataoffset + rows * cols * psf->bytewidth ; psf->datalength = psf->filelength - psf->dataoffset - psf->dataend ; psf->sf.sections = 1 ; return 0 ; } /* mat4_read_header */ static int mat4_format_to_encoding (int format, int endian) { switch (format | endian) { case (SF_FORMAT_PCM_16 | SF_ENDIAN_BIG) : return MAT4_BE_PCM_16 ; case (SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE) : return MAT4_LE_PCM_16 ; case (SF_FORMAT_PCM_32 | SF_ENDIAN_BIG) : return MAT4_BE_PCM_32 ; case (SF_FORMAT_PCM_32 | SF_ENDIAN_LITTLE) : return MAT4_LE_PCM_32 ; case (SF_FORMAT_FLOAT | SF_ENDIAN_BIG) : return MAT4_BE_FLOAT ; case (SF_FORMAT_FLOAT | SF_ENDIAN_LITTLE) : return MAT4_LE_FLOAT ; case (SF_FORMAT_DOUBLE | SF_ENDIAN_BIG) : return MAT4_BE_DOUBLE ; case (SF_FORMAT_DOUBLE | SF_ENDIAN_LITTLE) : return MAT4_LE_DOUBLE ; default : break ; } ; return -1 ; } /* mat4_format_to_encoding */ static const char * mat4_marker_to_str (int marker) { static char str [32] ; switch (marker) { case MAT4_BE_PCM_16 : return "big endian 16 bit PCM" ; case MAT4_LE_PCM_16 : return "little endian 16 bit PCM" ; case MAT4_BE_PCM_32 : return "big endian 32 bit PCM" ; case MAT4_LE_PCM_32 : return "little endian 32 bit PCM" ; case MAT4_BE_FLOAT : return "big endian float" ; case MAT4_LE_FLOAT : return "big endian float" ; case MAT4_BE_DOUBLE : return "big endian double" ; case MAT4_LE_DOUBLE : return "little endian double" ; } ; /* This is a little unsafe but is really only for debugging. */ str [sizeof (str) - 1] = 0 ; LSF_SNPRINTF (str, sizeof (str) - 1, "%08X", marker) ; return str ; } /* mat4_marker_to_str */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: f7e5f5d6-fc39-452e-bc4a-59627116ff59 */ nyquist-3.05/nylsf/double64.c0000644000175000000620000006550111466723256015131 0ustar stevestaff/* ** Copyright (C) 1999-2005 Erik de Castro Lopo ** ** This program 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.1 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 Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser 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. */ #include "sfconfig.h" #include #include #include #include "sndfile.h" #include "sfendian.h" #include "common.h" #include "float_cast.h" #if CPU_IS_LITTLE_ENDIAN #define DOUBLE64_READ double64_le_read #define DOUBLE64_WRITE double64_le_write #elif CPU_IS_BIG_ENDIAN #define DOUBLE64_READ double64_be_read #define DOUBLE64_WRITE double64_be_write #endif /* A 32 number which will not overflow when multiplied by sizeof (double). */ #define SENSIBLE_LEN (0x8000000) /*-------------------------------------------------------------------------------------------- ** Processor floating point capabilities. double64_get_capability () returns one of the ** latter three values. */ enum { DOUBLE_UNKNOWN = 0x00, DOUBLE_CAN_RW_LE = 0x23, DOUBLE_CAN_RW_BE = 0x34, DOUBLE_BROKEN_LE = 0x45, DOUBLE_BROKEN_BE = 0x56 } ; /*-------------------------------------------------------------------------------------------- ** Prototypes for private functions. */ static sf_count_t host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t host_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t host_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t host_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t host_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t host_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t host_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t host_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static void double64_peak_update (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) ; static int double64_get_capability (SF_PRIVATE *psf) ; static sf_count_t replace_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; static sf_count_t replace_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; static sf_count_t replace_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; static sf_count_t replace_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; static sf_count_t replace_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; static sf_count_t replace_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; static sf_count_t replace_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; static sf_count_t replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; static void d2bd_read (double *buffer, int count) ; static void bd2d_write (double *buffer, int count) ; /*-------------------------------------------------------------------------------------------- ** Exported functions. */ int double64_init (SF_PRIVATE *psf) { static int double64_caps ; double64_caps = double64_get_capability (psf) ; psf->blockwidth = sizeof (double) * psf->sf.channels ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { switch (psf->endian + double64_caps) { case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) : psf->float_endswap = SF_FALSE ; psf->read_short = host_read_d2s ; psf->read_int = host_read_d2i ; psf->read_float = host_read_d2f ; psf->read_double = host_read_d ; break ; case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) : psf->float_endswap = SF_FALSE ; psf->read_short = host_read_d2s ; psf->read_int = host_read_d2i ; psf->read_float = host_read_d2f ; psf->read_double = host_read_d ; break ; case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) : psf->float_endswap = SF_TRUE ; psf->read_short = host_read_d2s ; psf->read_int = host_read_d2i ; psf->read_float = host_read_d2f ; psf->read_double = host_read_d ; break ; case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) : psf->float_endswap = SF_TRUE ; psf->read_short = host_read_d2s ; psf->read_int = host_read_d2i ; psf->read_float = host_read_d2f ; psf->read_double = host_read_d ; break ; /* When the CPU is not IEEE compatible. */ case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) : psf->float_endswap = SF_FALSE ; psf->read_short = replace_read_d2s ; psf->read_int = replace_read_d2i ; psf->read_float = replace_read_d2f ; psf->read_double = replace_read_d ; break ; case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) : psf->float_endswap = SF_FALSE ; psf->read_short = replace_read_d2s ; psf->read_int = replace_read_d2i ; psf->read_float = replace_read_d2f ; psf->read_double = replace_read_d ; break ; case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) : psf->float_endswap = SF_TRUE ; psf->read_short = replace_read_d2s ; psf->read_int = replace_read_d2i ; psf->read_float = replace_read_d2f ; psf->read_double = replace_read_d ; break ; case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) : psf->float_endswap = SF_TRUE ; psf->read_short = replace_read_d2s ; psf->read_int = replace_read_d2i ; psf->read_float = replace_read_d2f ; psf->read_double = replace_read_d ; break ; default : break ; } ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { switch (psf->endian + double64_caps) { case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) : psf->float_endswap = SF_FALSE ; psf->write_short = host_write_s2d ; psf->write_int = host_write_i2d ; psf->write_float = host_write_f2d ; psf->write_double = host_write_d ; break ; case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) : psf->float_endswap = SF_FALSE ; psf->write_short = host_write_s2d ; psf->write_int = host_write_i2d ; psf->write_float = host_write_f2d ; psf->write_double = host_write_d ; break ; case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) : psf->float_endswap = SF_TRUE ; psf->write_short = host_write_s2d ; psf->write_int = host_write_i2d ; psf->write_float = host_write_f2d ; psf->write_double = host_write_d ; break ; case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) : psf->float_endswap = SF_TRUE ; psf->write_short = host_write_s2d ; psf->write_int = host_write_i2d ; psf->write_float = host_write_f2d ; psf->write_double = host_write_d ; break ; /* When the CPU is not IEEE compatible. */ case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) : psf->float_endswap = SF_FALSE ; psf->write_short = replace_write_s2d ; psf->write_int = replace_write_i2d ; psf->write_float = replace_write_f2d ; psf->write_double = replace_write_d ; break ; case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) : psf->float_endswap = SF_FALSE ; psf->write_short = replace_write_s2d ; psf->write_int = replace_write_i2d ; psf->write_float = replace_write_f2d ; psf->write_double = replace_write_d ; break ; case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) : psf->float_endswap = SF_TRUE ; psf->write_short = replace_write_s2d ; psf->write_int = replace_write_i2d ; psf->write_float = replace_write_f2d ; psf->write_double = replace_write_d ; break ; case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) : psf->float_endswap = SF_TRUE ; psf->write_short = replace_write_s2d ; psf->write_int = replace_write_i2d ; psf->write_float = replace_write_f2d ; psf->write_double = replace_write_d ; break ; default : break ; } ; } ; if (psf->filelength > psf->dataoffset) { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; } else psf->datalength = 0 ; psf->sf.frames = psf->datalength / psf->blockwidth ; return 0 ; } /* double64_init */ /*---------------------------------------------------------------------------- ** From : http://www.hpcf.cam.ac.uk/fp_formats.html ** ** 64 bit double precision layout (big endian) ** Sign bit 0 ** Exponent bits 1-11 ** Mantissa bits 12-63 ** Exponent Offset 1023 ** ** double single ** ** +INF 7FF0000000000000 7F800000 ** -INF FFF0000000000000 FF800000 ** NaN 7FF0000000000001 7F800001 ** to to ** 7FFFFFFFFFFFFFFF 7FFFFFFF ** and and ** FFF0000000000001 FF800001 ** to to ** FFFFFFFFFFFFFFFF FFFFFFFF ** +OVER 7FEFFFFFFFFFFFFF 7F7FFFFF ** -OVER FFEFFFFFFFFFFFFF FF7FFFFF ** +UNDER 0010000000000000 00800000 ** -UNDER 8010000000000000 80800000 */ double double64_be_read (unsigned char *cptr) { int exponent, negative, upper, lower ; double dvalue ; negative = (cptr [0] & 0x80) ? 1 : 0 ; exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ; /* Might not have a 64 bit long, so load the mantissa into a double. */ upper = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8) | cptr [4]) ; lower = (cptr [5] << 16) | (cptr [6] << 8) | cptr [7] ; if (exponent == 0 && upper == 0 && lower == 0) return 0.0 ; dvalue = upper + lower / ((double) 0x1000000) ; dvalue += 0x10000000 ; exponent = exponent - 0x3FF ; dvalue = dvalue / ((double) 0x10000000) ; if (negative) dvalue *= -1 ; if (exponent > 0) dvalue *= (1 << exponent) ; else if (exponent < 0) dvalue /= (1 << abs (exponent)) ; return dvalue ; } /* double64_be_read */ double double64_le_read (unsigned char *cptr) { int exponent, negative, upper, lower ; double dvalue ; negative = (cptr [7] & 0x80) ? 1 : 0 ; exponent = ((cptr [7] & 0x7F) << 4) | ((cptr [6] >> 4) & 0xF) ; /* Might not have a 64 bit long, so load the mantissa into a double. */ upper = ((cptr [6] & 0xF) << 24) | (cptr [5] << 16) | (cptr [4] << 8) | cptr [3] ; lower = (cptr [2] << 16) | (cptr [1] << 8) | cptr [0] ; if (exponent == 0 && upper == 0 && lower == 0) return 0.0 ; dvalue = upper + lower / ((double) 0x1000000) ; dvalue += 0x10000000 ; exponent = exponent - 0x3FF ; dvalue = dvalue / ((double) 0x10000000) ; if (negative) dvalue *= -1 ; if (exponent > 0) dvalue *= (1 << exponent) ; else if (exponent < 0) dvalue /= (1 << abs (exponent)) ; return dvalue ; } /* double64_le_read */ void double64_be_write (double in, unsigned char *out) { int exponent, mantissa ; memset (out, 0, sizeof (double)) ; if (fabs (in) < 1e-30) return ; if (in < 0.0) { in *= -1.0 ; out [0] |= 0x80 ; } ; in = frexp (in, &exponent) ; exponent += 1022 ; out [0] |= (exponent >> 4) & 0x7F ; out [1] |= (exponent << 4) & 0xF0 ; in *= 0x20000000 ; mantissa = lrint (floor (in)) ; out [1] |= (mantissa >> 24) & 0xF ; out [2] = (mantissa >> 16) & 0xFF ; out [3] = (mantissa >> 8) & 0xFF ; out [4] = mantissa & 0xFF ; in = fmod (in, 1.0) ; in *= 0x1000000 ; mantissa = lrint (floor (in)) ; out [5] = (mantissa >> 16) & 0xFF ; out [6] = (mantissa >> 8) & 0xFF ; out [7] = mantissa & 0xFF ; return ; } /* double64_be_write */ void double64_le_write (double in, unsigned char *out) { int exponent, mantissa ; memset (out, 0, sizeof (double)) ; if (fabs (in) < 1e-30) return ; if (in < 0.0) { in *= -1.0 ; out [7] |= 0x80 ; } ; in = frexp (in, &exponent) ; exponent += 1022 ; out [7] |= (exponent >> 4) & 0x7F ; out [6] |= (exponent << 4) & 0xF0 ; in *= 0x20000000 ; mantissa = lrint (floor (in)) ; out [6] |= (mantissa >> 24) & 0xF ; out [5] = (mantissa >> 16) & 0xFF ; out [4] = (mantissa >> 8) & 0xFF ; out [3] = mantissa & 0xFF ; in = fmod (in, 1.0) ; in *= 0x1000000 ; mantissa = lrint (floor (in)) ; out [2] = (mantissa >> 16) & 0xFF ; out [1] = (mantissa >> 8) & 0xFF ; out [0] = mantissa & 0xFF ; return ; } /* double64_le_write */ /*============================================================================================== ** Private functions. */ static void double64_peak_update (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) { int chan ; int k, position ; float fmaxval ; for (chan = 0 ; chan < psf->sf.channels ; chan++) { fmaxval = fabs (buffer [chan]) ; position = 0 ; for (k = chan ; k < count ; k += psf->sf.channels) if (fmaxval < fabs (buffer [k])) { fmaxval = fabs (buffer [k]) ; position = k ; } ; if (fmaxval > psf->peak_info->peaks [chan].value) { psf->peak_info->peaks [chan].value = fmaxval ; psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ; } ; } ; return ; } /* double64_peak_update */ static int double64_get_capability (SF_PRIVATE *psf) { union { double d ; unsigned char c [8] ; } data ; data.d = 1.234567890123456789 ; /* Some abitrary value. */ if (! psf->ieee_replace) { /* If this test is true ints and floats are compatible and little endian. */ if (data.c [0] == 0xfb && data.c [1] == 0x59 && data.c [2] == 0x8c && data.c [3] == 0x42 && data.c [4] == 0xca && data.c [5] == 0xc0 && data.c [6] == 0xf3 && data.c [7] == 0x3f) return DOUBLE_CAN_RW_LE ; /* If this test is true ints and floats are compatible and big endian. */ if (data.c [0] == 0x3f && data.c [1] == 0xf3 && data.c [2] == 0xc0 && data.c [3] == 0xca && data.c [4] == 0x42 && data.c [5] == 0x8c && data.c [6] == 0x59 && data.c [7] == 0xfb) return DOUBLE_CAN_RW_BE ; } ; /* Doubles are broken. Don't expect reading or writing to be fast. */ psf_log_printf (psf, "Using IEEE replacement code for double.\n") ; return (CPU_IS_LITTLE_ENDIAN) ? DOUBLE_BROKEN_LE : DOUBLE_BROKEN_BE ; } /* double64_get_capability */ /*======================================================================================= */ static inline void d2s_array (const double *src, int count, short *dest, double scale) { while (--count >= 0) { dest [count] = lrint (scale * src [count]) ; } ; } /* d2s_array */ static inline void d2i_array (const double *src, int count, int *dest, double scale) { while (--count >= 0) { dest [count] = lrint (scale * src [count]) ; } ; } /* d2i_array */ static inline void d2f_array (const double *src, int count, float *dest) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* d2f_array */ static inline void s2d_array (const short *src, double *dest, int count) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* s2d_array */ static inline void i2d_array (const int *src, double *dest, int count) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* i2d_array */ static inline void f2d_array (const float *src, double *dest, int count) { while (--count >= 0) { dest [count] = src [count] ; } ; } /* f2d_array */ /*---------------------------------------------------------------------------------------------- */ static sf_count_t host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double scale ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, readcount) ; d2s_array (psf->u.dbuf, readcount, ptr + total, scale) ; total += readcount ; len -= readcount ; if (readcount < bufferlen) break ; } ; return total ; } /* host_read_d2s */ static sf_count_t host_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double scale ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; d2i_array (psf->u.dbuf, readcount, ptr + total, scale) ; total += readcount ; len -= readcount ; if (readcount < bufferlen) break ; } ; return total ; } /* host_read_d2i */ static sf_count_t host_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; d2f_array (psf->u.dbuf, readcount, ptr + total) ; total += readcount ; len -= readcount ; if (readcount < bufferlen) break ; } ; return total ; } /* host_read_d2f */ static sf_count_t host_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen ; sf_count_t readcount, total = 0 ; readcount = psf_fread (ptr, sizeof (double), len, psf) ; if (psf->float_endswap != SF_TRUE) return readcount ; /* If the read length was sensible, endswap output in one go. */ if (readcount < SENSIBLE_LEN) { endswap_double_array (ptr, readcount) ; return readcount ; } ; bufferlen = SENSIBLE_LEN ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_double_array (ptr + total, bufferlen) ; total += bufferlen ; len -= bufferlen ; } ; return total ; } /* host_read_d */ static sf_count_t host_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2d_array (ptr + total, psf->u.dbuf, bufferlen) ; if (psf->peak_info) double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_s2d */ static sf_count_t host_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2d_array (ptr + total, psf->u.dbuf, bufferlen) ; if (psf->peak_info) double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_i2d */ static sf_count_t host_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; f2d_array (ptr + total, psf->u.dbuf, bufferlen) ; if (psf->peak_info) double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_f2d */ static sf_count_t host_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; if (psf->peak_info) double64_peak_update (psf, ptr, len, 0) ; if (psf->float_endswap != SF_TRUE) return psf_fwrite (ptr, sizeof (double), len, psf) ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; endswap_double_copy (psf->u.dbuf, ptr + total, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* host_write_d */ /*======================================================================================= */ static sf_count_t replace_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double scale ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; d2bd_read (psf->u.dbuf, bufferlen) ; d2s_array (psf->u.dbuf, readcount, ptr + total, scale) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_d2s */ static sf_count_t replace_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; double scale ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; d2bd_read (psf->u.dbuf, bufferlen) ; d2i_array (psf->u.dbuf, readcount, ptr + total, scale) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_d2i */ static sf_count_t replace_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; d2bd_read (psf->u.dbuf, bufferlen) ; memcpy (ptr + total, psf->u.dbuf, bufferlen * sizeof (double)) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_d2f */ static sf_count_t replace_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) { int bufferlen, readcount ; sf_count_t total = 0 ; /* FIXME : This is probably nowhere near optimal. */ bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, readcount) ; d2bd_read (psf->u.dbuf, readcount) ; memcpy (ptr + total, psf->u.dbuf, readcount * sizeof (double)) ; total += readcount ; if (readcount < bufferlen) break ; len -= readcount ; } ; return total ; } /* replace_read_d */ static sf_count_t replace_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; s2d_array (ptr + total, psf->u.dbuf, bufferlen) ; if (psf->peak_info) double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; bd2d_write (psf->u.dbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_s2d */ static sf_count_t replace_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; i2d_array (ptr + total, psf->u.dbuf, bufferlen) ; if (psf->peak_info) double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; bd2d_write (psf->u.dbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_i2d */ static sf_count_t replace_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; f2d_array (ptr + total, psf->u.dbuf, bufferlen) ; bd2d_write (psf->u.dbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_f2d */ static sf_count_t replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) { int bufferlen, writecount ; sf_count_t total = 0 ; /* FIXME : This is probably nowhere near optimal. */ if (psf->peak_info) double64_peak_update (psf, ptr, len, 0) ; bufferlen = ARRAY_LEN (psf->u.dbuf) ; while (len > 0) { if (len < bufferlen) bufferlen = (int) len ; memcpy (psf->u.dbuf, ptr + total, bufferlen * sizeof (double)) ; bd2d_write (psf->u.dbuf, bufferlen) ; if (psf->float_endswap == SF_TRUE) endswap_double_array (psf->u.dbuf, bufferlen) ; writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; total += writecount ; if (writecount < bufferlen) break ; len -= writecount ; } ; return total ; } /* replace_write_d */ /*---------------------------------------------------------------------------------------------- */ static void d2bd_read (double *buffer, int count) { while (--count >= 0) { buffer [count] = DOUBLE64_READ ((unsigned char *) (buffer + count)) ; } ; } /* d2bd_read */ static void bd2d_write (double *buffer, int count) { while (--count >= 0) { DOUBLE64_WRITE (buffer [count], (unsigned char*) (buffer + count)) ; } ; } /* bd2d_write */ /* ** Do not edit or modify anything in this comment block. ** The arch-tag line is a file identity tag for the GNU Arch ** revision control system. ** ** arch-tag: 4ee243b7-8c7a-469b-869c-e9aa0ee3b77f */ nyquist-3.05/nyquist.dsw0000644000175000000620000000313610144436365014427 0ustar stevestaffMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "filelist"=.\misc\filelist.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "intgen"=.\misc\intgen_win32\intgen.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "nyquist"=.\nyquist.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "nyqwin"=.\nyqwin.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "packer"=.\misc\packer.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "portaudio_test"=.\portaudio_test\portaudio_test.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "unpacker"=.\misc\unpacker.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### nyquist-3.05/liblo/0002755000175000000620000000000011537433130013266 5ustar stevestaffnyquist-3.05/liblo/src/0002755000175000000620000000000011537433127014063 5ustar stevestaffnyquist-3.05/liblo/src/message.c0000644000175000000620000005517111467003724015660 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include #include #ifdef WIN32 #include #include #else #include #endif #include "lo_types_internal.h" #include "lo_internal.h" #include "lo/lo.h" #define LO_DEF_TYPE_SIZE 8 #define LO_DEF_DATA_SIZE 8 static char lo_numerical_types[] = { LO_INT32, LO_FLOAT, LO_INT64, LO_DOUBLE, '\0' }; static char lo_string_types[] = { LO_STRING, LO_SYMBOL, '\0' }; static int lo_message_add_typechar(lo_message m, char t); static void *lo_message_add_data(lo_message m, size_t s); void lo_arg_pp_internal(lo_type type, void *data, int bigendian); // Used for calculating new sizes when expanding message data buffers. // Note that log(x)/0.69315 = log2(x): this simply finds the next // highest power of 2. #if 1 #define lo_pow2_over(a,b) \ a = ((b > a) ? (a << ((int)((log(((double)b/(double)a))/0.69315)+1))) : a); #else #define lo_pow2_over(a,b) \ while (b > a) {a *= 2;} #endif lo_message lo_message_new() { lo_message m = malloc(sizeof(struct _lo_message)); if (!m) { return m; } m->types = calloc(LO_DEF_TYPE_SIZE, sizeof(char)); m->types[0] = ','; m->types[1] = '\0'; m->typelen = 1; m->typesize = LO_DEF_TYPE_SIZE; m->data = NULL; m->datalen = 0; m->datasize = 0; m->source = NULL; m->argv = NULL; m->ts = LO_TT_IMMEDIATE; return m; } void lo_message_free(lo_message m) { if (m) { free(m->types); free(m->data); free(m->argv); } free(m); } /* Don't call lo_message_add_varargs_internal directly, use * lo_message_add_varargs, a macro wrapping this function with * appropriate values for file and line */ int lo_message_add_varargs_internal(lo_message msg, const char *types, va_list ap, const char *file, int line) { int count = 0; int i; int64_t i64; float f; char *s; lo_blob b; uint8_t *m; lo_timetag tt; double d; int ret = 0; while (types && *types) { count++; i=0; i64=0; f=0; s=0; b=0; m=0; d=0; switch (*types++) { case LO_INT32: i = va_arg(ap, int32_t); lo_message_add_int32(msg, i); break; case LO_FLOAT: f = (float)va_arg(ap, double); lo_message_add_float(msg, f); break; case LO_STRING: s = va_arg(ap, char *); #ifdef __GNUC__ if (s == (char *)LO_MARKER_A) { fprintf(stderr, "liblo error: lo_send or lo_message_add called with " "invalid string pointer for arg %d, probably arg mismatch\n" "at %s:%d, exiting.\n", count, file, line); } #endif lo_message_add_string(msg, s); break; case LO_BLOB: b = va_arg(ap, lo_blob); lo_message_add_blob(msg, b); break; case LO_INT64: i64 = va_arg(ap, int64_t); lo_message_add_int64(msg, i64); break; case LO_TIMETAG: tt = va_arg(ap, lo_timetag); lo_message_add_timetag(msg, tt); break; case LO_DOUBLE: d = va_arg(ap, double); lo_message_add_double(msg, d); break; case LO_SYMBOL: s = va_arg(ap, char *); #ifdef __GNUC__ if (s == (char *)LO_MARKER_A) { fprintf(stderr, "liblo error: lo_send or lo_message_add called with " "invalid symbol pointer for arg %d, probably arg mismatch\n" "at %s:%d, exiting.\n", count, file, line); va_end(ap); return -2; } #endif lo_message_add_symbol(msg, s); break; case LO_CHAR: i = va_arg(ap, int); lo_message_add_char(msg, i); break; case LO_MIDI: m = va_arg(ap, uint8_t *); lo_message_add_midi(msg, m); break; case LO_TRUE: lo_message_add_true(msg); break; case LO_FALSE: lo_message_add_false(msg); break; case LO_NIL: lo_message_add_nil(msg); break; case LO_INFINITUM: lo_message_add_infinitum(msg); break; default: ret = -1; // unknown type fprintf(stderr, "liblo warning: unknown type '%c' at %s:%d\n", *(types-1), file, line); break; } } #ifdef __GNUC__ i = va_arg(ap, uint32_t); if (i != LO_MARKER_A) { ret = -2; // bad format/args fprintf(stderr, "liblo error: lo_send, lo_message_add, or lo_message_add_varargs called with " "mismatching types and data at\n%s:%d, exiting.\n", file, line); va_end(ap); return ret; } i = va_arg(ap, uint32_t); if (i != LO_MARKER_B) { ret = -2; // bad format/args fprintf(stderr, "liblo error: lo_send, lo_message_add, or lo_message_add_varargs called with " "mismatching types and data at\n%s:%d, exiting.\n", file, line); } #endif va_end(ap); return ret; } /* Don't call lo_message_add_internal directly, use lo_message_add, * a macro wrapping this function with appropriate values for file and line */ #ifdef __GNUC__ int lo_message_add_internal(lo_message msg, const char *file, const int line, const char *types, ...) #else int lo_message_add(lo_message msg, const char *types, ...) #endif { va_list ap; int ret = 0; #ifndef __GNUC__ const char *file = ""; const int line = 0; #endif va_start(ap, types); ret = lo_message_add_varargs_internal(msg, types, ap, file, line); return ret; } int lo_message_add_int32(lo_message m, int32_t a) { lo_pcast32 b; int32_t *nptr = lo_message_add_data(m, sizeof(a)); if (!nptr) return -1; b.i = a; if (lo_message_add_typechar(m, LO_INT32)) return -1; *nptr = b.nl; return 0; } int lo_message_add_float(lo_message m, float a) { lo_pcast32 b; int32_t *nptr = lo_message_add_data(m, sizeof(a)); if (!nptr) return -1; b.f = a; if (lo_message_add_typechar(m, LO_FLOAT)) return -1; *nptr = b.nl; return 0; } int lo_message_add_string(lo_message m, const char *a) { const int size = lo_strsize(a); char *nptr = lo_message_add_data(m, size); if (!nptr) return -1; if (lo_message_add_typechar(m, LO_STRING)) return -1; strncpy(nptr, a, size); return 0; } int lo_message_add_blob(lo_message m, lo_blob a) { const uint32_t size = lo_blobsize(a); const uint32_t dsize = lo_blob_datasize(a); char *nptr = lo_message_add_data(m, size); if (!nptr) return -1; if (lo_message_add_typechar(m, LO_BLOB)) return -1; memset(nptr + size - 4, 0, 4); memcpy(nptr, &dsize, sizeof(dsize)); memcpy(nptr + sizeof(int32_t), lo_blob_dataptr(a), lo_blob_datasize(a)); return 0; } int lo_message_add_int64(lo_message m, int64_t a) { lo_pcast64 b; uint64_t *nptr = lo_message_add_data(m, sizeof(a)); if (!nptr) return -1; b.i = a; if (lo_message_add_typechar(m, LO_INT64)) return -1; *nptr = b.nl; return 0; } int lo_message_add_timetag(lo_message m, lo_timetag a) { lo_pcast64 b; uint64_t *nptr = lo_message_add_data(m, sizeof(a)); if (!nptr) return -1; b.tt = a; if (lo_message_add_typechar(m, LO_TIMETAG)) return -1; *nptr = b.nl; return 0; } int lo_message_add_double(lo_message m, double a) { lo_pcast64 b; uint64_t *nptr = lo_message_add_data(m, sizeof(a)); if (!nptr) return -1; b.f = a; if (lo_message_add_typechar(m, LO_DOUBLE)) return -1; *nptr = b.nl; return 0; } int lo_message_add_symbol(lo_message m, const char *a) { const int size = lo_strsize(a); char *nptr = lo_message_add_data(m, size); if (!nptr) return -1; if (lo_message_add_typechar(m, LO_SYMBOL)) return -1; strncpy(nptr, a, size); return 0; } int lo_message_add_char(lo_message m, char a) { lo_pcast32 b; int32_t *nptr = lo_message_add_data(m, sizeof(int32_t)); if (!nptr) return -1; b.c = a; if (lo_message_add_typechar(m, LO_CHAR)) return -1; *nptr = b.nl; return 0; } int lo_message_add_midi(lo_message m, uint8_t a[4]) { char *nptr = lo_message_add_data(m, 4); if (!nptr) return -1; if (lo_message_add_typechar(m, LO_MIDI)) return -1; memcpy(nptr, a, sizeof(a)); return 0; } int lo_message_add_true(lo_message m) { return lo_message_add_typechar(m, LO_TRUE); } int lo_message_add_false(lo_message m) { return lo_message_add_typechar(m, LO_FALSE); } int lo_message_add_nil(lo_message m) { return lo_message_add_typechar(m, LO_NIL); } int lo_message_add_infinitum(lo_message m) { return lo_message_add_typechar(m, LO_INFINITUM); } static int lo_message_add_typechar(lo_message m, char t) { if (m->typelen + 1 >= m->typesize) { int new_typesize = m->typesize * 2; char *new_types = 0; if (!new_typesize) new_typesize = LO_DEF_TYPE_SIZE; new_types = realloc(m->types, new_typesize); if (!new_types) return -1; m->types = new_types; m->typesize = new_typesize; } m->types[m->typelen] = t; m->typelen++; m->types[m->typelen] = '\0'; if (m->argv) { free(m->argv); m->argv = NULL; } return 0; } static void *lo_message_add_data(lo_message m, size_t s) { uint32_t old_dlen = m->datalen; int new_datasize = m->datasize; int new_datalen = m->datalen + s; void *new_data = 0; if (!new_datasize) new_datasize = LO_DEF_DATA_SIZE; lo_pow2_over(new_datasize, new_datalen); new_data = realloc(m->data, new_datasize); if (!new_data) return 0; m->datalen = new_datalen; m->datasize = new_datasize; m->data = new_data; if (m->argv) { free(m->argv); m->argv = NULL; } return (void*)((char*)m->data + old_dlen); } int lo_strsize(const char *s) { return 4 * (strlen(s) / 4 + 1); } size_t lo_arg_size(lo_type type, void *data) { switch (type) { case LO_TRUE: case LO_FALSE: case LO_NIL: case LO_INFINITUM: return 0; case LO_INT32: case LO_FLOAT: case LO_MIDI: case LO_CHAR: return 4; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: return 8; case LO_STRING: case LO_SYMBOL: return lo_strsize((char *)data); case LO_BLOB: return lo_blobsize((lo_blob)data); default: fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); return 0; } return 0; } char *lo_get_path(void *data, ssize_t size) { ssize_t result = lo_validate_string(data, size); return (result >= 4) ? (char *)data : NULL; } ssize_t lo_validate_string(void *data, ssize_t size) { ssize_t i = 0, len = 0; char *pos = data; if (size < 0) { return -LO_ESIZE; // invalid size } for (i = 0; i < size; ++i) { if (pos[i] == '\0') { len = 4 * (i / 4 + 1); break; } } if (0 == len) { return -LO_ETERM; // string not terminated } if (len > size) { return -LO_ESIZE; // would overflow buffer } for (; i < len; ++i) { if (pos[i] != '\0') { return -LO_EPAD; // non-zero char found in pad area } } return len; } ssize_t lo_validate_blob(void *data, ssize_t size) { ssize_t i, end, len; uint32_t dsize; char *pos = (char *)data; if (size < 0) { return -LO_ESIZE; // invalid size } dsize = lo_otoh32(*(uint32_t*)data); if (dsize > LO_MAX_MSG_SIZE) { // avoid int overflow in next step return -LO_ESIZE; } end = sizeof(uint32_t) + dsize; // end of data len = 4 * (end / 4 + 1); // full padded size if (len > size) { return -LO_ESIZE; // would overflow buffer } for (i = end; i < len; ++i) { if (pos[i] != '\0') { return -LO_EPAD; // non-zero char found in pad area } } return len; } ssize_t lo_validate_bundle(void *data, ssize_t size) { ssize_t len = 0, remain = size; char *pos = data; uint32_t elem_len; len = lo_validate_string(data, size); if (len < 0) { return -LO_ESIZE; // invalid size } if (0 != strcmp(data, "#bundle")) { return -LO_EINVALIDBUND; // not a bundle } pos += len; remain -= len; // time tag if (remain < 8) { return -LO_ESIZE; } pos += 8; remain -= 8; while (remain >= 4) { elem_len = lo_otoh32(*((uint32_t *)pos)); pos += 4; remain -= 4; if (elem_len > remain) { return -LO_ESIZE; } pos += elem_len; remain -= elem_len; } if (0 != remain) { return -LO_ESIZE; } return size; } ssize_t lo_validate_arg(lo_type type, void *data, ssize_t size) { if (size < 0) { return -1; } switch (type) { case LO_TRUE: case LO_FALSE: case LO_NIL: case LO_INFINITUM: return 0; case LO_INT32: case LO_FLOAT: case LO_MIDI: case LO_CHAR: return size >= 4 ? 4 : -LO_ESIZE; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: return size >= 8 ? 8 : -LO_ESIZE; case LO_STRING: case LO_SYMBOL: return lo_validate_string((char *)data, size); case LO_BLOB: return lo_validate_blob((lo_blob)data, size); default: return -LO_EINVALIDTYPE; } return -LO_INT_ERR; } /* convert endianness of arg pointed to by data from network to host */ void lo_arg_host_endian(lo_type type, void *data) { switch (type) { case LO_INT32: case LO_FLOAT: case LO_BLOB: case LO_CHAR: *(int32_t *)data = lo_otoh32(*(int32_t *)data); break; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: *(int64_t *)data = lo_otoh64(*(int64_t *)data); break; case LO_STRING: case LO_SYMBOL: case LO_MIDI: case LO_TRUE: case LO_FALSE: case LO_NIL: case LO_INFINITUM: /* these are fine */ break; default: fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); break; } } /* convert endianness of arg pointed to by data from host to network */ void lo_arg_network_endian(lo_type type, void *data) { switch (type) { case LO_INT32: case LO_FLOAT: case LO_BLOB: case LO_CHAR: *(int32_t *)data = lo_htoo32(*(int32_t *)data); break; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: *(int64_t *)data = lo_htoo64(*(int64_t *)data); break; case LO_STRING: case LO_SYMBOL: case LO_MIDI: case LO_TRUE: case LO_FALSE: case LO_NIL: case LO_INFINITUM: /* these are fine */ break; default: fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); break; } } lo_address lo_message_get_source(lo_message m) { return m->source; } lo_timetag lo_message_get_timestamp(lo_message m) { return m->ts; } size_t lo_message_length(lo_message m, const char *path) { return lo_strsize(path) + lo_strsize(m->types) + m->datalen; } int lo_message_get_argc(lo_message m) { return m->typelen - 1; } lo_arg **lo_message_get_argv(lo_message m) { int i, argc; char *types, *ptr; lo_arg **argv; if (NULL != m->argv) { return m->argv; } i = 0; argc = m->typelen - 1; types = m->types + 1; ptr = m->data; argv = calloc(argc, sizeof(lo_arg *)); for (i = 0; i < argc; ++i) { size_t len = lo_arg_size(types[i], ptr); argv[i] = len ? (lo_arg*)ptr : NULL; ptr += len; } m->argv = argv; return argv; } char *lo_message_get_types(lo_message m) { return m->types + 1; } void *lo_message_serialise(lo_message m, const char *path, void *to, size_t *size) { int i, argc; char *types, *ptr; size_t s = lo_message_length(m, path); if (size) { *size = s; } if (!to) { to = calloc(1, s); } memset((char*)to + lo_strsize(path) - 4, 0, 4); // ensure zero-padding strcpy(to, path); memset((char*)to + lo_strsize(path) + lo_strsize(m->types) - 4, 0, 4); strcpy((char*)to + lo_strsize(path), m->types); types = m->types + 1; ptr = (char*)to + lo_strsize(path) + lo_strsize(m->types); memcpy(ptr, m->data, m->datalen); i = 0; argc = m->typelen - 1; for (i = 0; i < argc; ++i) { size_t len = lo_arg_size(types[i], ptr); lo_arg_network_endian(types[i], ptr); ptr += len; } return to; } lo_message lo_message_deserialise(void *data, size_t size, int *result) { lo_message msg = NULL; char *types = NULL, *ptr = NULL; int i = 0, argc = 0, remain = size, res = 0, len; if (remain <= 0) { res = LO_ESIZE; goto fail; } msg = malloc(sizeof(struct _lo_message)); if (!msg) { res = LO_EALLOC; goto fail; } msg->types = NULL; msg->typelen = 0; msg->typesize = 0; msg->data = NULL; msg->datalen = 0; msg->datasize = 0; msg->source = NULL; msg->argv = NULL; msg->ts = LO_TT_IMMEDIATE; // path len = lo_validate_string(data, remain); if (len < 0) { res = LO_EINVALIDPATH; // invalid path string goto fail; } remain -= len; // types if (remain <= 0) { res = LO_ENOTYPE; // no type tag string goto fail; } types = (char*)data + len; len = lo_validate_string(types, remain); if (len < 0) { res = LO_EINVALIDTYPE; // invalid type tag string goto fail; } if (types[0] != ',') { res = LO_EBADTYPE; // type tag string missing initial comma goto fail; } remain -= len; msg->typelen = strlen(types); msg->typesize = len; msg->types = malloc(msg->typesize); if (NULL == msg->types) { res = LO_EALLOC; goto fail; } memcpy(msg->types, types, msg->typesize); // args msg->data = malloc(remain); if (NULL == msg->data) { res = LO_EALLOC; goto fail; } memcpy(msg->data, types + len, remain); msg->datalen = msg->datasize = remain; ptr = msg->data; ++types; argc = msg->typelen - 1; if (argc) { msg->argv = calloc(argc, sizeof(lo_arg *)); if (NULL == msg->argv) { res = LO_EALLOC; goto fail; } } for (i = 0; remain >= 0 && i < argc; ++i) { len = lo_validate_arg((lo_type)types[i], ptr, remain); if (len < 0) { res = LO_EINVALIDARG; // invalid argument goto fail; } lo_arg_host_endian((lo_type)types[i], ptr); msg->argv[i] = len ? (lo_arg*)ptr : NULL; remain -= len; ptr += len; } if (0 != remain || i != argc) { res = LO_ESIZE; // size/argument mismatch goto fail; } if (result) { *result = res; } return msg; fail: if (msg) { lo_message_free(msg); } if (result) { *result = res; } return NULL; } void lo_message_pp(lo_message m) { void *d = m->data; void *end = (char*)m->data + m->datalen; int i; printf("%s ", m->types); for (i = 1; m->types[i]; i++) { if (i > 1) { printf(" "); } lo_arg_pp_internal(m->types[i], d, 1); d = (char*)d + lo_arg_size(m->types[i], d); } putchar('\n'); if (d != end) { fprintf(stderr, "liblo warning: type and data do not match (off by %d) in message %p\n", abs((char*)d - (char*)end), m); } } void lo_arg_pp(lo_type type, void *data) { lo_arg_pp_internal(type, data, 0); } void lo_arg_pp_internal(lo_type type, void *data, int bigendian) { lo_pcast32 val32; lo_pcast64 val64; int size; int i; size = lo_arg_size(type, data); if (size == 4 || type == LO_BLOB) { if (bigendian) { val32.nl = lo_otoh32(*(int32_t *)data); } else { val32.nl = *(int32_t *)data; } } else if (size == 8) { if (bigendian) { val64.nl = lo_otoh64(*(int64_t *)data); } else { val64.nl = *(int64_t *)data; } } switch (type) { case LO_INT32: printf("%d", val32.i); break; case LO_FLOAT: printf("%f", val32.f); break; case LO_STRING: printf("\"%s\"", (char *)data); break; case LO_BLOB: printf("["); if (val32.i > 12) { printf("%d byte blob", val32.i); } else { printf("%db ", val32.i); for (i=0; ii = (uint32_t)lo_hires_val(type_from, from); break; case LO_INT64: to->i64 = (uint64_t)lo_hires_val(type_from, from); break; case LO_FLOAT: to->f = (float)lo_hires_val(type_from, from); break; case LO_DOUBLE: to->d = (double)lo_hires_val(type_from, from); break; default: fprintf(stderr, "liblo: bad coercion: %c -> %c\n", type_from, type_to); return 0; } return 1; } return 0; } lo_hires lo_hires_val(lo_type type, lo_arg *p) { switch (type) { case LO_INT32: return p->i; case LO_INT64: return p->h; case LO_FLOAT: return p->f; case LO_DOUBLE: return p->d; default: fprintf(stderr, "liblo: hires val requested of non numerical type '%c' at %s:%d\n", type, __FILE__, __LINE__); break; } return 0.0l; } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/Makefile.in0000644000175000000620000011161011515462141016120 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = testlo$(EXEEXT) subtest$(EXEEXT) subdir = src DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) liblo_la_DEPENDENCIES = am__objects_1 = liblo_la-address.lo liblo_la-send.lo \ liblo_la-message.lo liblo_la-server.lo liblo_la-method.lo \ liblo_la-server_thread.lo liblo_la-blob.lo liblo_la-bundle.lo \ liblo_la-timetag.lo liblo_la-pattern_match.lo am_liblo_la_OBJECTS = $(am__objects_1) liblo_la_OBJECTS = $(am_liblo_la_OBJECTS) liblo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(liblo_la_CFLAGS) $(CFLAGS) \ $(liblo_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(noinst_PROGRAMS) am_subtest_OBJECTS = subtest-subtest.$(OBJEXT) subtest_OBJECTS = $(am_subtest_OBJECTS) subtest_DEPENDENCIES = liblo.la subtest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(subtest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_testlo_OBJECTS = testlo-testlo.$(OBJEXT) testlo_OBJECTS = $(am_testlo_OBJECTS) testlo_DEPENDENCIES = liblo.la testlo_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(testlo_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(liblo_la_SOURCES) $(subtest_SOURCES) $(testlo_SOURCES) DIST_SOURCES = $(liblo_la_SOURCES) $(subtest_SOURCES) \ $(testlo_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = . tools MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = liblo.def noinst_HEADERS = lo_types_internal.h lo_internal.h SOURCE_FILES = address.c send.c message.c server.c method.c \ server_thread.c blob.c bundle.c timetag.c pattern_match.c lib_LTLIBRARIES = liblo.la liblo_la_CFLAGS = -Wall -I$(top_srcdir) liblo_la_SOURCES = $(SOURCE_FILES) liblo_la_LIBADD = -lpthread liblo_la_LDFLAGS = -export-dynamic -version-info @LO_SO_VERSION@ testlo_CFLAGS = -Wall -I$(top_srcdir) testlo_SOURCES = testlo.c testlo_LDADD = liblo.la subtest_CFLAGS = -Wall -I$(top_srcdir) subtest_SOURCES = subtest.c subtest_LDADD = liblo.la all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done liblo.la: $(liblo_la_OBJECTS) $(liblo_la_DEPENDENCIES) $(liblo_la_LINK) -rpath $(libdir) $(liblo_la_OBJECTS) $(liblo_la_LIBADD) $(LIBS) clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list subtest$(EXEEXT): $(subtest_OBJECTS) $(subtest_DEPENDENCIES) @rm -f subtest$(EXEEXT) $(subtest_LINK) $(subtest_OBJECTS) $(subtest_LDADD) $(LIBS) testlo$(EXEEXT): $(testlo_OBJECTS) $(testlo_DEPENDENCIES) @rm -f testlo$(EXEEXT) $(testlo_LINK) $(testlo_OBJECTS) $(testlo_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-address.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-blob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-bundle.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-method.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-pattern_match.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-send.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-server_thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblo_la-timetag.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subtest-subtest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testlo-testlo.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< liblo_la-address.lo: address.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-address.lo -MD -MP -MF $(DEPDIR)/liblo_la-address.Tpo -c -o liblo_la-address.lo `test -f 'address.c' || echo '$(srcdir)/'`address.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-address.Tpo $(DEPDIR)/liblo_la-address.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='address.c' object='liblo_la-address.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-address.lo `test -f 'address.c' || echo '$(srcdir)/'`address.c liblo_la-send.lo: send.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-send.lo -MD -MP -MF $(DEPDIR)/liblo_la-send.Tpo -c -o liblo_la-send.lo `test -f 'send.c' || echo '$(srcdir)/'`send.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-send.Tpo $(DEPDIR)/liblo_la-send.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='send.c' object='liblo_la-send.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-send.lo `test -f 'send.c' || echo '$(srcdir)/'`send.c liblo_la-message.lo: message.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-message.lo -MD -MP -MF $(DEPDIR)/liblo_la-message.Tpo -c -o liblo_la-message.lo `test -f 'message.c' || echo '$(srcdir)/'`message.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-message.Tpo $(DEPDIR)/liblo_la-message.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='message.c' object='liblo_la-message.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-message.lo `test -f 'message.c' || echo '$(srcdir)/'`message.c liblo_la-server.lo: server.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-server.lo -MD -MP -MF $(DEPDIR)/liblo_la-server.Tpo -c -o liblo_la-server.lo `test -f 'server.c' || echo '$(srcdir)/'`server.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-server.Tpo $(DEPDIR)/liblo_la-server.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='server.c' object='liblo_la-server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-server.lo `test -f 'server.c' || echo '$(srcdir)/'`server.c liblo_la-method.lo: method.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-method.lo -MD -MP -MF $(DEPDIR)/liblo_la-method.Tpo -c -o liblo_la-method.lo `test -f 'method.c' || echo '$(srcdir)/'`method.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-method.Tpo $(DEPDIR)/liblo_la-method.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='method.c' object='liblo_la-method.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-method.lo `test -f 'method.c' || echo '$(srcdir)/'`method.c liblo_la-server_thread.lo: server_thread.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-server_thread.lo -MD -MP -MF $(DEPDIR)/liblo_la-server_thread.Tpo -c -o liblo_la-server_thread.lo `test -f 'server_thread.c' || echo '$(srcdir)/'`server_thread.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-server_thread.Tpo $(DEPDIR)/liblo_la-server_thread.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='server_thread.c' object='liblo_la-server_thread.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-server_thread.lo `test -f 'server_thread.c' || echo '$(srcdir)/'`server_thread.c liblo_la-blob.lo: blob.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-blob.lo -MD -MP -MF $(DEPDIR)/liblo_la-blob.Tpo -c -o liblo_la-blob.lo `test -f 'blob.c' || echo '$(srcdir)/'`blob.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-blob.Tpo $(DEPDIR)/liblo_la-blob.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='blob.c' object='liblo_la-blob.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-blob.lo `test -f 'blob.c' || echo '$(srcdir)/'`blob.c liblo_la-bundle.lo: bundle.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-bundle.lo -MD -MP -MF $(DEPDIR)/liblo_la-bundle.Tpo -c -o liblo_la-bundle.lo `test -f 'bundle.c' || echo '$(srcdir)/'`bundle.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-bundle.Tpo $(DEPDIR)/liblo_la-bundle.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bundle.c' object='liblo_la-bundle.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-bundle.lo `test -f 'bundle.c' || echo '$(srcdir)/'`bundle.c liblo_la-timetag.lo: timetag.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-timetag.lo -MD -MP -MF $(DEPDIR)/liblo_la-timetag.Tpo -c -o liblo_la-timetag.lo `test -f 'timetag.c' || echo '$(srcdir)/'`timetag.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-timetag.Tpo $(DEPDIR)/liblo_la-timetag.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='timetag.c' object='liblo_la-timetag.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-timetag.lo `test -f 'timetag.c' || echo '$(srcdir)/'`timetag.c liblo_la-pattern_match.lo: pattern_match.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -MT liblo_la-pattern_match.lo -MD -MP -MF $(DEPDIR)/liblo_la-pattern_match.Tpo -c -o liblo_la-pattern_match.lo `test -f 'pattern_match.c' || echo '$(srcdir)/'`pattern_match.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblo_la-pattern_match.Tpo $(DEPDIR)/liblo_la-pattern_match.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pattern_match.c' object='liblo_la-pattern_match.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblo_la_CFLAGS) $(CFLAGS) -c -o liblo_la-pattern_match.lo `test -f 'pattern_match.c' || echo '$(srcdir)/'`pattern_match.c subtest-subtest.o: subtest.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(subtest_CFLAGS) $(CFLAGS) -MT subtest-subtest.o -MD -MP -MF $(DEPDIR)/subtest-subtest.Tpo -c -o subtest-subtest.o `test -f 'subtest.c' || echo '$(srcdir)/'`subtest.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/subtest-subtest.Tpo $(DEPDIR)/subtest-subtest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='subtest.c' object='subtest-subtest.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(subtest_CFLAGS) $(CFLAGS) -c -o subtest-subtest.o `test -f 'subtest.c' || echo '$(srcdir)/'`subtest.c subtest-subtest.obj: subtest.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(subtest_CFLAGS) $(CFLAGS) -MT subtest-subtest.obj -MD -MP -MF $(DEPDIR)/subtest-subtest.Tpo -c -o subtest-subtest.obj `if test -f 'subtest.c'; then $(CYGPATH_W) 'subtest.c'; else $(CYGPATH_W) '$(srcdir)/subtest.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/subtest-subtest.Tpo $(DEPDIR)/subtest-subtest.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='subtest.c' object='subtest-subtest.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(subtest_CFLAGS) $(CFLAGS) -c -o subtest-subtest.obj `if test -f 'subtest.c'; then $(CYGPATH_W) 'subtest.c'; else $(CYGPATH_W) '$(srcdir)/subtest.c'; fi` testlo-testlo.o: testlo.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testlo_CFLAGS) $(CFLAGS) -MT testlo-testlo.o -MD -MP -MF $(DEPDIR)/testlo-testlo.Tpo -c -o testlo-testlo.o `test -f 'testlo.c' || echo '$(srcdir)/'`testlo.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/testlo-testlo.Tpo $(DEPDIR)/testlo-testlo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='testlo.c' object='testlo-testlo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testlo_CFLAGS) $(CFLAGS) -c -o testlo-testlo.o `test -f 'testlo.c' || echo '$(srcdir)/'`testlo.c testlo-testlo.obj: testlo.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testlo_CFLAGS) $(CFLAGS) -MT testlo-testlo.obj -MD -MP -MF $(DEPDIR)/testlo-testlo.Tpo -c -o testlo-testlo.obj `if test -f 'testlo.c'; then $(CYGPATH_W) 'testlo.c'; else $(CYGPATH_W) '$(srcdir)/testlo.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/testlo-testlo.Tpo $(DEPDIR)/testlo-testlo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='testlo.c' object='testlo-testlo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(testlo_CFLAGS) $(CFLAGS) -c -o testlo-testlo.obj `if test -f 'testlo.c'; then $(CYGPATH_W) 'testlo.c'; else $(CYGPATH_W) '$(srcdir)/testlo.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \ ctags-recursive distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ uninstall-libLTLIBRARIES test: all ./testlo memtest: all LD_LIBRARY_PATH=.libs valgrind --tool=memcheck .libs/testlo # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/src/testlo.c0000644000175000000620000010727511467003724015551 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ /* * This is some testcase code - it exercises the internals of liblo, so its not * a good example to learn from, see examples/ for example code */ #include #include #include #include #include #ifdef _MSC_VER #define snprintf _snprintf #else #include #endif #include "lo_types_internal.h" #include "lo_internal.h" #include "lo/lo.h" #include "config.h" #ifdef WIN32 #define PATHDELIM "\\" #else #define PATHDELIM "/" #endif #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif #define TEST(cond) if (!(cond)) { fprintf(stderr, "FAILED " #cond \ " at %s:%d\n", __FILE__, __LINE__); \ exit(1); } \ else { printf("passed " #cond "\n"); } union end_test32 { uint32_t i; char c[4]; }; union end_test64 { uint64_t i; char c[8]; }; static int done = 0; static int bundle_count = 0; static int pattern_count = 0; static int reply_count = 0; static int subtest_count = 0; static int subtest_reply_count = 0; static int error_okay = 0; char testdata[5] = "ABCDE"; static int jitter_count = 0; static float jitter_total = 0.0f; static float jitter_max = 0.0f; static float jitter_min = 1000.0f; void exitcheck(void); void test_deserialise(void); void test_validation(lo_address a); void test_multicast(lo_server_thread st); void error(int num, const char *m, const char *path); void rep_error(int num, const char *m, const char *path); int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int foo_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int reply_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int lots_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int coerce_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int bundle_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int timestamp_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int jitter_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int pattern_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int subtest_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int subtest_reply_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int test_varargs(lo_address a, const char *path, const char *types, ...); int main() { lo_blob btest = lo_blob_new(sizeof(testdata), testdata); lo_server_thread st, sta, stb; lo_server s = lo_server_new(NULL, error); lo_bundle b; lo_message m1, m2; char *server_url, *path, *protocol, *host, *port; const char *host2, *port2; lo_address a; uint8_t midi_data[4] = {0xff, 0xf7, 0xAA, 0x00}; union end_test32 et32; union end_test64 et64; lo_timetag tt = {0x1, 0x80000000}, sched; int count; int proto; char cmd[256]; test_deserialise(); sta = lo_server_thread_new("7591", error); stb = lo_server_thread_new("7591", rep_error); if (stb) { fprintf(stderr, "FAILED: create bad server thread object!\n"); exit(1); } lo_server_thread_free(sta); /* leak check */ st = lo_server_thread_new(NULL, error); lo_server_thread_start(st); #ifdef WIN32 Sleep(4); #else usleep(4000); #endif lo_server_thread_stop(st); lo_server_thread_free(st); st = lo_server_thread_new(NULL, error); lo_server_thread_start(st); lo_server_thread_stop(st); lo_server_thread_free(st); st = lo_server_thread_new(NULL, error); lo_server_thread_free(st); st = lo_server_thread_new(NULL, error); lo_server_thread_free(st); st = lo_server_thread_new(NULL, error); a = lo_address_new_from_url("osc://localhost/"); TEST(a != NULL); lo_address_free(a); a = lo_address_new_from_url("osc.://localhost/"); TEST(a == NULL); atexit(exitcheck); printf("type tests\n"); TEST(sizeof(float) == sizeof(int32_t)); TEST(sizeof(double) == sizeof(int64_t)); et32.i = 0x23242526U; et32.i = lo_htoo32(et32.i); if (et32.c[0] != 0x23 || et32.c[1] != 0x24 || et32.c[2] != 0x25 || et32.c[3] != 0x26) { fprintf(stderr, "failed 32bit endian conversion test\n"); fprintf(stderr, "0x23242526 -> %X\n", et32.i); exit(1); } else { printf("passed 32bit endian conversion test\n"); } et64.i = 0x232425262728292AULL; et64.i = lo_htoo64(et64.i); if (et64.c[0] != 0x23 || et64.c[1] != 0x24 || et64.c[2] != 0x25 || et64.c[3] != 0x26 || et64.c[4] != 0x27 || et64.c[5] != 0x28 || et64.c[6] != 0x29 || et64.c[7] != 0x2A) { fprintf(stderr, "failed 64bit endian conversion\n"); fprintf(stderr, "0x232425262728292A -> %llX\n", (long long unsigned int)et64.i); exit(1); } else { printf("passed 64bit endian conversion\n"); } printf("\n"); /* OSC URL tests */ path = lo_url_get_path("osc.udp://localhost:9999/a/path/is/here"); if (strcmp(path, "/a/path/is/here")) { printf("failed lo_url_get_path() test1\n"); printf("'%s' != '/a/path/is/here'\n", path); exit(1); } else { printf("passed lo_url_get_path() test1\n"); } free(path); protocol = lo_url_get_protocol("osc.udp://localhost:9999/a/path/is/here"); if (strcmp(protocol, "udp")) { printf("failed lo_url_get_protocol() test1\n"); printf("'%s' != 'udp'\n", protocol); exit(1); } else { printf("passed lo_url_get_protocol() test1\n"); } free(protocol); protocol = lo_url_get_protocol("osc.tcp://localhost:9999/a/path/is/here"); if (strcmp(protocol, "tcp")) { printf("failed lo_url_get_protocol() test2\n"); printf("'%s' != 'tcp'\n", protocol); exit(1); } else { printf("passed lo_url_get_protocol() test2\n"); } free(protocol); protocol = lo_url_get_protocol("osc.udp://[::ffff:localhost]:9999/a/path/is/here"); if (strcmp(protocol, "udp")) { printf("failed lo_url_get_protocol() test1 (IPv6)\n"); printf("'%s' != 'udp'\n", protocol); exit(1); } else { printf("passed lo_url_get_protocol() test1 (IPv6)\n"); } free(protocol); proto = lo_url_get_protocol_id("osc.udp://localhost:9999/a/path/is/here"); if (proto != LO_UDP) { printf("failed lo_url_get_protocol_id() test1\n"); printf("'%d' != LO_UDP\n", proto); exit(1); } else { printf("passed lo_url_get_protocol_id() test1\n"); } proto = lo_url_get_protocol_id("osc.tcp://localhost:9999/a/path/is/here"); if (proto != LO_TCP) { printf("failed lo_url_get_protocol_id() test2\n"); printf("'%d' != LO_TCP\n", proto); exit(1); } else { printf("passed lo_url_get_protocol_id() test2\n"); } proto = lo_url_get_protocol_id("osc.invalid://localhost:9999/a/path/is/here"); if (proto != -1) { printf("failed lo_url_get_protocol_id() test3\n"); printf("'%d' != -1\n", proto); exit(1); } else { printf("passed lo_url_get_protocol_id() test3\n"); } proto = lo_url_get_protocol_id("osc.udp://[::ffff:localhost]:9999/a/path/is/here"); if (proto != LO_UDP) { printf("failed lo_url_get_protocol_id() test1 (IPv6)\n"); printf("'%d' != LO_UDP\n", proto); exit(1); } else { printf("passed lo_url_get_protocol_id() test1 (IPv6)\n"); } host = lo_url_get_hostname("osc.udp://foo.example.com:9999/a/path/is/here"); if (strcmp(host, "foo.example.com")) { printf("failed lo_url_get_hostname() test1\n"); printf("'%s' != 'foo.example.com'\n", host); exit(1); } else { printf("passed lo_url_get_hostname() test1\n"); } free(host); host = lo_url_get_hostname("osc.udp://[0000::::0001]:9999/a/path/is/here"); if (strcmp(host, "0000::::0001")) { printf("failed lo_url_get_hostname() test2 (IPv6)\n"); printf("'%s' != '0000::::0001'\n", host); exit(1); } else { printf("passed lo_url_get_hostname() test2 (IPv6)\n"); } free(host); port = lo_url_get_port("osc.udp://localhost:9999/a/path/is/here"); if (strcmp(port, "9999")) { printf("failed lo_url_get_port() test1\n"); printf("'%s' != '9999'\n", port); exit(1); } else { printf("passed lo_url_get_port() test1\n"); } free(port); port = lo_url_get_port("osc.udp://[::ffff:127.0.0.1]:9999/a/path/is/here"); if (strcmp(port, "9999")) { printf("failed lo_url_get_port() test1 (IPv6)\n"); printf("'%s' != '9999'\n", port); exit(1); } else { printf("passed lo_url_get_port() test1 (IPv6)\n"); } free(port); printf("\n"); a = lo_address_new_from_url("osc.tcp://foo.example.com:9999/"); host2 = lo_address_get_hostname(a); if (strcmp(host2, "foo.example.com")) { printf("failed lo_address_get_hostname() test\n"); printf("'%s' != 'foo.example.com'\n", host2); exit(1); } else { printf("passed lo_address_get_hostname() test\n"); } port2 = lo_address_get_port(a); if (strcmp(port2, "9999")) { printf("failed lo_address_get_port() test\n"); printf("'%s' != '9999'\n", port2); exit(1); } else { printf("passed lo_address_get_port() test\n"); } proto = lo_address_get_protocol(a); if (proto != LO_TCP) { printf("failed lo_address_get_protocol() test\n"); printf("'%d' != '%d'\n", proto, LO_TCP); exit(1); } else { printf("passed lo_address_get_protocol() test\n"); } server_url = lo_address_get_url(a); if (strcmp(server_url, "osc.tcp://foo.example.com:9999/")) { printf("failed lo_address_get_url() test\n"); printf("'%s' != '%s'\n", server_url, "osc.tcp://foo.example.com:9999/"); exit(1); } else { printf("passed lo_address_get_url() test\n"); } free(server_url); lo_address_free( a ); printf("\n"); /* Test blod sizes */ if (lo_blob_datasize(btest) != 5 || lo_blobsize(btest) != 12) { printf("blob is %d (%d) bytes long, should be 5 (12)\n", lo_blob_datasize(btest), lo_blobsize(btest)); lo_arg_pp(LO_BLOB, btest); printf(" <- blob\n"); exit(1); } /* Server method handler tests */ server_url = lo_server_thread_get_url(st); a = lo_address_new_from_url(server_url); printf("Server URL: %s\n", server_url); free(server_url); /* add method that will match the path /foo/bar, with two numbers, coerced * to float and int */ lo_server_thread_add_method(st, "/foo/bar", "fi", foo_handler, lo_server_thread_get_server(st)); lo_server_thread_add_method(st, "/reply", "s", reply_handler, NULL); lo_server_thread_add_method(st, "/lotsofformats", "fisbmhtdSccTFNI", lots_handler, NULL); lo_server_thread_add_method(st, "/coerce", "dfhiSs", coerce_handler, NULL); lo_server_thread_add_method(st, "/bundle", NULL, bundle_handler, NULL); lo_server_thread_add_method(st, "/timestamp", NULL, timestamp_handler, NULL); lo_server_thread_add_method(st, "/jitter", "ti", jitter_handler, NULL); lo_server_thread_add_method(st, "/pattern/foo", NULL, pattern_handler, "foo"); lo_server_thread_add_method(st, "/pattern/bar", NULL, pattern_handler, "bar"); lo_server_thread_add_method(st, "/pattern/baz", NULL, pattern_handler, "baz"); lo_server_thread_add_method(st, "/subtest", "i", subtest_handler, st); lo_server_thread_add_method(st, "/subtest-reply", "i", subtest_reply_handler, NULL); /* add method that will match any path and args */ lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL); /* add method that will match the path /quit with no args */ lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL); /* check that the thread restarts */ lo_server_thread_start(st); lo_server_thread_stop(st); lo_server_thread_start(st); if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) { printf("OSC error A %d: %s\n", lo_address_errno(a), lo_address_errstr(a)); exit(1); } if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) { printf("OSC error B %d: %s\n", lo_address_errno(a), lo_address_errstr(a)); exit(1); } test_validation(a); test_multicast(st); lo_send(a, "/", "i", 242); lo_send(a, "/pattern/", "i", 243); #ifndef _MSC_VER /* MS compiler refuses to compile this case */ lo_send(a, "/bar", "ff", 0.12345678f, 1.0/0.0); #endif lo_send(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym", 'X', 'Y'); lo_send(a, "/coerce", "fdihsS", 0.1f, 0.2, 123, 124LL, "aaa", "bbb"); lo_send(a, "/coerce", "ffffss", 0.1f, 0.2f, 123.0, 124.0, "aaa", "bbb"); lo_send(a, "/coerce", "ddddSS", 0.1, 0.2, 123.0, 124.0, "aaa", "bbb"); lo_send(a, "/a/b/c/d", "sfsff", "one", 0.12345678f, "three", -0.00000023001f, 1.0); lo_send(a, "/a/b/c/d", "b", btest); TEST(test_varargs(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym", 'X', 'Y', LO_ARGS_END) == 0); #ifdef __GNUC__ // Note: Lack of support for variable-argument macros in non-GCC compilers // does not allow us to test for these conditions. // too many args TEST(test_varargs(a, "/lotsofformats", "f", 0.12345678f, 123, "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym", 'X', 'Y', LO_ARGS_END) != 0); // too many types TEST(test_varargs(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.5, LO_ARGS_END) != 0); #endif // test lo_message_add m1 = lo_message_new(); TEST(lo_message_add(m1, "fisbmhtdSccTFNI", 0.12345678f, 123, "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym", 'X', 'Y') == 0); lo_send_message(a, "/lotsofformats", m1); lo_message_free(m1); lo_blob_free(btest); lo_send(a, "/pattern/*", "s", "a"); lo_send(a, "/pattern/ba[rz]", "s", "b"); server_url = lo_server_thread_get_url(st); sprintf(cmd, "." PATHDELIM "subtest %s &", server_url); if (system(cmd) != 0) { fprintf(stderr, "Cannot execute subtest command\n"); exit(1); } system(cmd); free(server_url); #ifdef WIN32 Sleep(2000); #else sleep(2); #endif TEST(reply_count == 3); TEST(pattern_count == 5); TEST(subtest_count == 2); TEST(subtest_reply_count == 22); printf("\n"); { lo_timetag t = {10,0xFFFFFFFC}; b = lo_bundle_new(t); } m1 = lo_message_new(); lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz"); lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); lo_bundle_add_message(b, "/bundle", m1); lo_send_bundle(a, b); /* This should be safe for multiple copies of the same message. */ lo_bundle_free_messages(b); { lo_timetag t = {1,2}; b = lo_bundle_new(t); } m1 = lo_message_new(); lo_message_add_int32(m1, 23); lo_message_add_string(m1, "23"); lo_bundle_add_message(b, "/bundle", m1); m2 = lo_message_new(); lo_message_add_string(m2, "24"); lo_message_add_int32(m2, 24); lo_bundle_add_message(b, "/bundle", m2); lo_bundle_add_message(b, "/bundle", m1); /* lo_send_bundle(a, b); if (a->errnum) { printf("error %d: %s\n", a->errnum, a->errstr); exit(1); } */ TEST(lo_send_bundle(a, b) == 88); /* Test freeing out-of-order copies of messages in a bundle. */ lo_bundle_free_messages(b); { lo_timetag t = {10,0xFFFFFFFE}; b = lo_bundle_new(t); } m1 = lo_message_new(); lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz"); lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); lo_bundle_add_message(b, "/bundle", m1); lo_send_bundle(a, b); lo_message_free(m1); lo_bundle_free(b); lo_timetag_now(&sched); sched.sec += 5; b = lo_bundle_new(sched); m1 = lo_message_new(); lo_message_add_string(m1, "future"); lo_message_add_string(m1, "time"); lo_message_add_string(m1, "test"); lo_bundle_add_message(b, "/bundle", m1); lo_send_bundle(a, b); lo_message_free(m1); lo_bundle_free(b); lo_send_timestamped(a, sched, "/bundle", "s", "lo_send_timestamped() test"); /* test bundle timestamp ends up in message struct (and doesn't end up in unbundled messages) */ lo_timetag_now(&sched); lo_send_timestamped(a, sched, "/timestamp", "it", 1, sched); lo_send(a, "/timestamp", "it", 0, sched); #define JITTER_ITS 25 /* jitter tests */ { lo_timetag stamps[JITTER_ITS]; lo_timetag now; int i; for (i=0; i= 1000) { printf("lo_server_recv_noblock() test failed\n"); exit(1); } /* Delete methods */ lo_server_thread_del_method(st, "/coerce", "dfhiSs"); lo_server_del_method(s, NULL, NULL); lo_address_free(a); lo_server_free(s); free(server_url); #ifndef WIN32 { /* UNIX domain tests */ lo_address ua; lo_server us; char *addr; unlink("/tmp/testlo.osc"); us = lo_server_new_with_proto("/tmp/testlo.osc", LO_UNIX, error); ua = lo_address_new_from_url("osc.unix:///tmp/testlo.osc"); TEST(lo_server_get_protocol(us) == LO_UNIX); TEST(lo_send(ua, "/unix", "f", 23.0) == 16); TEST(lo_server_recv(us) == 16); addr = lo_server_get_url(us); TEST(!strcmp("osc.unix:////tmp/testlo.osc", addr)); free(addr); lo_address_free(ua); ua = lo_address_new_with_proto(LO_UNIX, NULL, "/tmp/testlo.osc"); TEST(lo_send(ua, "/unix", "f", 23.0) == 16); TEST(lo_server_recv(us) == 16); lo_server_free(us); lo_address_free(ua); } #endif { /* TCP tests */ lo_address ta; lo_server ts; char *addr; ts = lo_server_new_with_proto(NULL, LO_TCP, error); addr = lo_server_get_url(ts); ta = lo_address_new_from_url(addr); if (lo_address_errno(ta)) { printf("err: %s\n", lo_address_errstr(ta)); exit(1); } TEST(lo_server_get_protocol(ts) == LO_TCP); TEST(lo_send(ta, "/tcp", "f", 23.0) == 16); TEST(lo_send(ta, "/tcp", "f", 23.0) == 16); TEST(lo_server_recv(ts) == 16); TEST(lo_server_recv(ts) == 16); free(addr); lo_server_free(ts); lo_address_free(ta); } server_url = lo_server_thread_get_url(st); a = lo_address_new_from_url(server_url); /* exit */ lo_send(a, "/quit", NULL); lo_address_free(a); while (!done) { #ifdef WIN32 Sleep(1); #else usleep(1000); #endif } lo_server_thread_free(st); free(server_url); return 0; } void exitcheck(void) { if (!done) { fprintf(stderr, "\ntest run not completed\n" PACKAGE_NAME " test FAILED\n"); } else { printf(PACKAGE_NAME " test PASSED\n"); } } void error(int num, const char *msg, const char *path) { printf("liblo server error %d in %s: %s", num, path, msg); if (!error_okay) exit(1); else printf(" (expected)\n"); } void rep_error(int num, const char *msg, const char *path) { if (num != 9904) { error(num, msg, path); } } int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { int i; printf("path: <%s>\n", path); for (i=0; if, argv[1]->i); if (lo_send_from(src, serv, LO_TT_IMMEDIATE, "/reply", "s", "a reply") == -1) { printf("OSC reply error %d: %s\nSending to %s\n", lo_address_errno(src), lo_address_errstr(src), url); exit(1); } else { printf("Reply sent to %s\n\n", url); } free(server_url); free(url); return 0; } int reply_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { lo_address src = lo_message_get_source(data); char *url = lo_address_get_url(src); printf("Reply received from %s\n", url); free(url); reply_count++; return 0; } int lots_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { lo_blob b; unsigned char *d; if (strcmp(path, "/lotsofformats")) { fprintf(stderr, "path != /lotsofformats\n"); exit(1); } printf("path = %s\n", path); TEST(types[0] == 'f' && argv[0]->f == 0.12345678f); TEST(types[1] == 'i' && argv[1]->i == 123); TEST(types[2] == 's' && !strcmp(&argv[2]->s, "123")); b = (lo_blob)argv[3]; d = lo_blob_dataptr(b); TEST(types[3] == 'b' && lo_blob_datasize(b) == 5); TEST(d[0] == 'A' && d[1] == 'B' && d[2] == 'C' && d[3] == 'D' && d[4] == 'E'); d = argv[4]->m; TEST(d[0] == 0xff && d[1] == 0xf7 && d[2] == 0xaa && d[3] == 0x00); TEST(types[5] == 'h' && argv[5]->h == 0x0123456789ABCDEFULL); TEST(types[6] == 't' && argv[6]->t.sec == 1 && \ argv[6]->t.frac == 0x80000000); TEST(types[7] == 'd' && argv[7]->d == 0.9999); TEST(types[8] == 'S' && !strcmp(&argv[8]->S, "sym")); printf("char: %d\n", argv[9]->c); TEST(types[9] == 'c' && argv[9]->c == 'X'); TEST(types[10] == 'c' && argv[10]->c == 'Y'); TEST(types[11] == 'T'); TEST(types[12] == 'F'); TEST(types[13] == 'N'); TEST(types[14] == 'I'); printf("\n"); return 0; } int coerce_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { printf("path = %s\n", path); TEST(types[0] == 'd' && fabs(argv[0]->d - 0.1) < FLT_EPSILON); TEST(types[1] == 'f' && fabs(argv[1]->f - 0.2) < FLT_EPSILON); TEST(types[2] == 'h' && argv[2]->h == 123); TEST(types[3] == 'i' && argv[3]->i == 124); TEST(types[4] == 'S' && !strcmp(&argv[4]->S, "aaa")); TEST(types[5] == 's' && !strcmp(&argv[5]->s, "bbb")); printf("\n"); return 0; } int bundle_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { bundle_count++; printf("received bundle\n"); return 0; } int timestamp_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { int bundled = argv[0]->i; lo_timetag ts, arg_ts; ts = lo_message_get_timestamp(data); arg_ts = argv[1]->t; if (bundled) { TEST((ts.sec == arg_ts.sec) && (ts.frac == arg_ts.frac)); } else { TEST(ts.sec == LO_TT_IMMEDIATE.sec && ts.frac == LO_TT_IMMEDIATE.frac); } return 0; } int jitter_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { lo_timetag now; float jitter; lo_timetag_now(&now); jitter = fabs(lo_timetag_diff(now, argv[0]->t)); jitter_count++; //printf("jitter: %f\n", jitter); printf("%d expected: %x:%x received %x:%x\n", argv[1]->i, argv[0]->t.sec, argv[0]->t.frac, now.sec, now.frac); jitter_total += jitter; if (jitter > jitter_max) jitter_max = jitter; if (jitter < jitter_min) jitter_min = jitter; return 0; } int pattern_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { pattern_count++; printf("pattern matched %s\n", (char *)user_data); return 0; } int subtest_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { lo_address a = lo_message_get_source(data); subtest_count++; printf("got subtest message %d\n", subtest_count); lo_send_from(a, lo_server_thread_get_server(user_data), LO_TT_IMMEDIATE, "/subtest", "i", subtest_count); return 0; } int subtest_reply_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { subtest_reply_count++; //printf("got subtest reply message %d\n", subtest_reply_count); return 0; } int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { done = 1; return 0; } int test_varargs(lo_address a, const char *path, const char *types, ...) { va_list ap; lo_message m = lo_message_new(); int error; va_start(ap, types); if ((error=lo_message_add_varargs(m, types, ap))==0) lo_send_message(a, path, m); else printf("lo_message_add_varargs returned %d\n", error); lo_message_free(m); return error<0; } void replace_char(char *str, size_t size, const char find, const char replace) { char *p = str; while(size--) { if (find == *p) { *p = replace; } ++p; } } void test_deserialise() { char *buf, *buf2, *tmp; const char *types = NULL, *path; lo_arg **argv = NULL; size_t len, size; char data[256]; int result = 0; lo_blob btest = lo_blob_new(sizeof(testdata), testdata); uint8_t midi_data[4] = {0xff, 0xf7, 0xAA, 0x00}; lo_timetag tt = {0x1, 0x80000000}; lo_blob b = NULL; // build a message lo_message msg = lo_message_new(); TEST(0 == lo_message_get_argc(msg)); lo_message_add_float(msg, 0.12345678f); // 0 f lo_message_add_int32(msg, 123); // 1 i lo_message_add_string(msg, "123"); // 2 s lo_message_add_blob(msg, btest); // 3 b lo_message_add_midi(msg, midi_data); // 4 m lo_message_add_int64(msg, 0x0123456789abcdefULL); // 5 h lo_message_add_timetag(msg, tt); // 6 t lo_message_add_double(msg, 0.9999); // 7 d lo_message_add_symbol(msg, "sym"); // 8 S lo_message_add_char(msg, 'X'); // 9 c lo_message_add_char(msg, 'Y'); // 10 c lo_message_add_true(msg); // 11 T lo_message_add_false(msg); // 12 F lo_message_add_nil(msg); // 13 N lo_message_add_infinitum(msg); // 14 I // test types, args TEST(15 == lo_message_get_argc(msg)); types = lo_message_get_types(msg); TEST(NULL != types); argv = lo_message_get_argv(msg); TEST(NULL != argv); TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON); TEST('i' == types[1] && 123 == argv[1]->i); TEST('s' == types[2] && !strcmp(&argv[2]->s, "123")); TEST('b' == types[3]); b = (lo_blob)argv[3]; TEST(lo_blob_datasize(b) == sizeof(testdata)); TEST(12 == lo_blobsize(b)); TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata))); TEST('m' == types[4] && !memcmp(&argv[4]->m, midi_data, 4)); TEST('h' == types[5] && 0x0123456789abcdefULL == argv[5]->h); TEST('t' == types[6] && 1 == argv[6]->t.sec && 0x80000000 == argv[6]->t.frac); TEST('d' == types[7] && fabs(argv[7]->d - 0.9999) < FLT_EPSILON); TEST('S' == types[8] && !strcmp(&argv[8]->s, "sym")); TEST('c' == types[9] && 'X' == argv[9]->c); TEST('c' == types[10] && 'Y' == argv[10]->c); TEST('T' == types[11] && NULL == argv[11]); TEST('F' == types[12] && NULL == argv[12]); TEST('N' == types[13] && NULL == argv[13]); TEST('I' == types[14] && NULL == argv[14]); // serialise it len = lo_message_length(msg, "/foo"); printf("serialise message_length=%d\n", (int)len); buf = calloc(len, sizeof(char)); size = 0; tmp = lo_message_serialise(msg, "/foo", buf, &size); TEST(tmp == buf && size == len && 92 == len); lo_message_free(msg); // deserialise it printf("deserialise\n"); path = lo_get_path(buf, len); TEST(NULL != path && !strcmp(path, "/foo")); msg = lo_message_deserialise(buf, size, NULL); TEST(NULL != msg); // repeat same test as above TEST(15 == lo_message_get_argc(msg)); types = lo_message_get_types(msg); TEST(NULL != types); argv = lo_message_get_argv(msg); TEST(NULL != argv); TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON); TEST('i' == types[1] && 123 == argv[1]->i); TEST('s' == types[2] && !strcmp(&argv[2]->s, "123")); TEST('b' == types[3]); b = (lo_blob)argv[3]; TEST(lo_blob_datasize(b) == sizeof(testdata)); TEST(12 == lo_blobsize(b)); TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata))); TEST('m' == types[4] && !memcmp(&argv[4]->m, midi_data, 4)); TEST('h' == types[5] && 0x0123456789abcdefULL == argv[5]->h); TEST('t' == types[6] && 1 == argv[6]->t.sec && 0x80000000 == argv[6]->t.frac); TEST('d' == types[7] && fabs(argv[7]->d - 0.9999) < FLT_EPSILON); TEST('S' == types[8] && !strcmp(&argv[8]->s, "sym")); TEST('c' == types[9] && 'X' == argv[9]->c); TEST('c' == types[10] && 'Y' == argv[10]->c); TEST('T' == types[11] && NULL == argv[11]); TEST('F' == types[12] && NULL == argv[12]); TEST('N' == types[13] && NULL == argv[13]); TEST('I' == types[14] && NULL == argv[14]); // serialise it again, compare len = lo_message_length(msg, "/foo"); printf("serialise message_length=%d\n", (int)len); buf2 = calloc(len, sizeof(char)); size = 0; tmp = lo_message_serialise(msg, "/foo", buf2, &size); TEST(tmp == buf2 && size == len && 92 == len); TEST(!memcmp(buf, buf2, len)); lo_message_free(msg); lo_blob_free(btest); free(buf); free(buf2); // deserialise failure tests with invalid message data msg = lo_message_deserialise(data, 0, &result); // 0 size TEST(NULL == msg && LO_ESIZE == result); snprintf(data, 256, "%s", "/foo"); // unterminated path string msg = lo_message_deserialise(data, 4, &result); TEST(NULL == msg && LO_EINVALIDPATH == result); snprintf(data, 256, "%s", "/f_o"); // non-0 in pad area msg = lo_message_deserialise(data, 4, &result); TEST(NULL == msg && LO_EINVALIDPATH == result); snprintf(data, 256, "%s", "/t__"); // types missing replace_char(data, 4, '_', '\0'); msg = lo_message_deserialise(data, 4, &result); TEST(NULL == msg && LO_ENOTYPE == result); snprintf(data, 256, "%s%s", "/t__", "____"); // types empty replace_char(data, 8, '_', '\0'); msg = lo_message_deserialise(data, 8, &result); TEST(NULL == msg && LO_EBADTYPE == result); snprintf(data, 256, "%s%s", "/t__", ",f_"); // short message replace_char(data, 7, '_', '\0'); msg = lo_message_deserialise(data, 7, &result); TEST(NULL == msg && LO_EINVALIDTYPE == result); snprintf(data, 256, "%s%s", "/t__", "ifi_"); // types missing comma replace_char(data, 8, '_', '\0'); msg = lo_message_deserialise(data, 8, &result); TEST(NULL == msg && LO_EBADTYPE == result); snprintf(data, 256, "%s%s", "/t__", ",ifi"); // types unterminated replace_char(data, 8, '_', '\0'); msg = lo_message_deserialise(data, 8, &result); TEST(NULL == msg && LO_EINVALIDTYPE == result); snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data replace_char(data, 8, '_', '\0'); msg = lo_message_deserialise(data, 12, &result); TEST(NULL == msg && LO_EINVALIDARG == result); snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data again replace_char(data, 8, '_', '\0'); msg = lo_message_deserialise(data, 15, &result); TEST(NULL == msg && LO_EINVALIDARG == result); snprintf(data, 256, "%s%s", "/t__", ",f__"); // too much arg data replace_char(data, 8, '_', '\0'); msg = lo_message_deserialise(data, 16, &result); TEST(NULL == msg && LO_ESIZE == result); snprintf(data, 256, "%s%s", "/t__", ",bs_"); // blob longer than msg length replace_char(data, 8, '_', '\0'); *(uint32_t *)(data + 8) = lo_htoo32((uint32_t)99999); msg = lo_message_deserialise(data, 256, &result); TEST(NULL == msg && LO_EINVALIDARG == result); } void test_validation(lo_address a) { /* packet crafted to crash a lo_server when no input validation is performed */ char mem[] = {"/\0\0\0,bs\0,\x00\x0F\x42\x3F"}; // OSC: "/" ",bs" 999999 int eok = error_okay; int sock = a->socket; /* This code won't work with MSVC because the lo_client_sockets data structure * is not explicitly made available to external programs. We could expose it * in debug mode, perhaps, but let's just skip this test for now. (Can be tested * on Windows using MingW.) */ #ifdef _MSC_VER return; #else printf("validation\n"); if (sock == -1) sock = lo_client_sockets.udp; if (sock == -1) { fprintf(stderr, "Couldn't get socket in test_validation(), %s:%d\n", __FILE__, __LINE__); exit(1); } error_okay = 1; if (sendto(sock, &mem, sizeof(mem), MSG_NOSIGNAL, a->ai->ai_addr, a->ai->ai_addrlen)==-1) { fprintf(stderr, "Error sending packet in test_validation(), %s:%d\n", __FILE__, __LINE__); } #ifndef WIN32 usleep(10000); #else Sleep(10); #endif error_okay = eok; #endif } void test_multicast(lo_server_thread st) { /* test multicast server and sender */ /* message is sent from st otherwise reply doesn't work */ lo_server ms = lo_server_new_multicast("224.0.1.1", "15432", error); lo_address ma = lo_address_new("224.0.1.1", "15432"); lo_address_set_ttl(ma, 1); lo_server_add_method(ms, "/foo/bar", "fi", foo_handler, ms); lo_server_add_method(ms, "/reply", "s", reply_handler, NULL); if (lo_send_from(ma, lo_server_thread_get_server(st), LO_TT_IMMEDIATE, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) { printf("multicast send error %d: %s\n", lo_address_errno(ma), lo_address_errstr(ma)); exit(1); } TEST(lo_server_recv(ms)==24); lo_server_free(ms); lo_address_free(ma); } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/blob.c0000644000175000000620000000237211467003724015145 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include "lo_types_internal.h" #include "lo/lo.h" lo_blob lo_blob_new(int32_t size, const void *data) { lo_blob b; if (size < 1) { return NULL; } b = malloc(sizeof(size) + size); b->size = size; if (data) { memcpy((char*)b + sizeof(uint32_t), data, size); } return b; } void lo_blob_free(lo_blob b) { free(b); } uint32_t lo_blob_datasize(lo_blob b) { return b->size; } void *lo_blob_dataptr(lo_blob b) { return (char*)b + sizeof(uint32_t); } uint32_t lo_blobsize(lo_blob b) { const uint32_t len = sizeof(uint32_t) + b->size; return 4 * (len / 4 + 1); } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/server_thread.c0000644000175000000620000000750511467003724017067 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include #include #ifdef WIN32 #include #include #else #include #include #include #endif #include "lo_types_internal.h" #include "lo/lo.h" #include "lo/lo_throw.h" static void thread_func(void *data); lo_server_thread lo_server_thread_new(const char *port, lo_err_handler err_h) { return lo_server_thread_new_with_proto(port, LO_DEFAULT, err_h); } lo_server_thread lo_server_thread_new_multicast(const char *group, const char *port, lo_err_handler err_h) { lo_server_thread st = malloc(sizeof(struct _lo_server_thread)); st->s = lo_server_new_multicast(group, port, err_h); st->active = 0; st->done = 0; if (!st->s) { free(st); return NULL; } return st; } lo_server_thread lo_server_thread_new_with_proto(const char *port, int proto, lo_err_handler err_h) { lo_server_thread st = malloc(sizeof(struct _lo_server_thread)); st->s = lo_server_new_with_proto(port, proto, err_h); st->active = 0; st->done = 0; if (!st->s) { free(st); return NULL; } return st; } void lo_server_thread_free(lo_server_thread st) { if (st) { if (st->active) { lo_server_thread_stop(st); } lo_server_free(st->s); } free(st); } lo_method lo_server_thread_add_method(lo_server_thread st, const char *path, const char *typespec, lo_method_handler h, void *user_data) { return lo_server_add_method(st->s, path, typespec, h, user_data); } void lo_server_thread_del_method(lo_server_thread st, const char *path, const char *typespec) { lo_server_del_method(st->s, path, typespec); } int lo_server_thread_start(lo_server_thread st) { int result; if (!st->active) { st->active = 1; st->done = 0; // Create the server thread result = pthread_create(&(st->thread), NULL, (void *)&thread_func, st); if (result) { fprintf(stderr, "Failed to create thread: pthread_create(), %s", strerror(result)); return -result; } } return 0; } int lo_server_thread_stop(lo_server_thread st) { int result; if (st->active) { // Signal thread to stop st->active = 0; // pthread_join waits for thread to terminate // and then releases the thread's resources result = pthread_join( st->thread, NULL ); if (result) { fprintf(stderr, "Failed to stop thread: pthread_join(), %s", strerror(result)); return -result; } } return 0; } int lo_server_thread_get_port(lo_server_thread st) { return lo_server_get_port(st->s); } char *lo_server_thread_get_url(lo_server_thread st) { return lo_server_get_url(st->s); } lo_server lo_server_thread_get_server(lo_server_thread st) { return st->s; } int lo_server_thread_events_pending(lo_server_thread st) { return lo_server_events_pending(st->s); } static void thread_func(void *data) { lo_server_thread st = (lo_server_thread)data; while (st->active) { lo_server_recv_noblock(st->s, 10); } st->done = 1; pthread_exit(NULL); } void lo_server_thread_pp(lo_server_thread st) { lo_server_pp(st->s); } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/lo_types_internal.h0000644000175000000620000000522611467003724017767 0ustar stevestaff#ifndef LO_TYPES_H #define LO_TYPES_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_POLL #include #endif #ifdef WIN32 #include #include #else #include #endif #ifdef _MSC_VER typedef SSIZE_T ssize_t; typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef __int32 int32_t; #endif #include #include "lo/lo_osc_types.h" typedef void (*lo_err_handler)(int num, const char *msg, const char *path); struct _lo_method; typedef struct _lo_address { char *host; int socket; char *port; int protocol; struct addrinfo *ai; int errnum; const char *errstr; int ttl; } *lo_address; typedef struct _lo_blob { uint32_t size; char *data; } *lo_blob; typedef struct _lo_message { char *types; size_t typelen; size_t typesize; void *data; size_t datalen; size_t datasize; lo_address source; lo_arg **argv; /* timestamp from bundle (LO_TT_IMMEDIATE for unbundled messages) */ lo_timetag ts; } *lo_message; typedef int (*lo_method_handler)(const char *path, const char *types, lo_arg **argv, int argc, struct _lo_message *msg, void *user_data); typedef struct _lo_method { const char *path; const char *typespec; lo_method_handler handler; char *user_data; struct _lo_method *next; } *lo_method; typedef struct _lo_server { struct addrinfo *ai; lo_method first; lo_err_handler err_h; int port; char *hostname; char *path; int protocol; void *queued; struct sockaddr_storage addr; socklen_t addr_len; int sockets_len; int sockets_alloc; #ifdef HAVE_POLL struct pollfd *sockets; #else struct { int fd; } *sockets; #endif } *lo_server; typedef struct _lo_server_thread { lo_server s; pthread_t thread; volatile int active; volatile int done; } *lo_server_thread; typedef struct _lo_bundle { size_t size; size_t len; lo_timetag ts; lo_message *msgs; char **paths; } *lo_bundle; typedef struct _lo_strlist { char *str; struct _lo_strlist *next; } lo_strlist; typedef union { int32_t i; float f; char c; uint32_t nl; } lo_pcast32; typedef union { int64_t i; double f; uint64_t nl; lo_timetag tt; } lo_pcast64; extern struct lo_cs { int udp; int tcp; } lo_client_sockets; #endif nyquist-3.05/liblo/src/timetag.c0000644000175000000620000000307211467003724015657 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include "lo_types_internal.h" #include "lo/lo.h" #ifdef _MSC_VER lo_timetag lo_get_tt_immediate() { lo_timetag tt = {0U,1U}; return tt; } #else #include #endif #include #define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */ double lo_timetag_diff(lo_timetag a, lo_timetag b) { return (double)a.sec - (double)b.sec + ((double)a.frac - (double)b.frac) * 0.00000000023283064365; } void lo_timetag_now(lo_timetag *t) { #ifdef WIN32 /* FILETIME is the time in units of 100 nsecs from 1601-Jan-01 1601 and 1900 are 9435484800 seconds apart. */ FILETIME ftime; double dtime; GetSystemTimeAsFileTime(&ftime); dtime = ((ftime.dwHighDateTime*4294967296.e-7)-9435484800.)+ (ftime.dwLowDateTime*1.e-7); t->sec = (uint32_t)dtime; t->frac = (uint32_t)((dtime-t->sec)*4294967296.); #else struct timeval tv; gettimeofday(&tv, NULL); t->sec = tv.tv_sec + JAN_1970; t->frac = tv.tv_usec * 4294.967295; #endif } nyquist-3.05/liblo/src/liblo.def0000644000175000000620000001215211467004266015643 0ustar stevestaff DESCRIPTION 'Lightweight OSC implementation' EXPORTS lo_address_errno @1 lo_address_errstr @2 lo_address_free @3 lo_address_get_hostname @4 lo_address_get_port @5 lo_address_get_protocol @6 lo_address_get_ttl @7 lo_address_get_url @8 lo_address_new @9 lo_address_new_from_url @10 lo_address_new_with_proto @11 lo_address_set_ttl @12 lo_arg_host_endian @13 lo_arg_network_endian @14 lo_arg_pp @15 lo_arg_size @16 lo_blob_dataptr @17 lo_blob_datasize @18 lo_blob_free @19 lo_blob_new @20 lo_blobsize @21 lo_bundle_add_message @22 lo_bundle_free @23 lo_bundle_free_messages @24 lo_bundle_length @25 lo_bundle_new @26 lo_bundle_pp @27 lo_bundle_serialise @28 lo_coerce @29 lo_get_path @30 lo_get_tt_immediate @31 lo_hires_val @32 lo_is_numerical_type @33 lo_is_string_type @34 lo_message_add @35 lo_message_add_blob @36 lo_message_add_char @37 lo_message_add_double @38 lo_message_add_false @39 lo_message_add_float @40 lo_message_add_infinitum @41 lo_message_add_int32 @42 lo_message_add_int64 @43 lo_message_add_midi @44 lo_message_add_nil @45 lo_message_add_string @46 lo_message_add_symbol @47 lo_message_add_timetag @48 lo_message_add_true @49 lo_message_add_varargs_internal @50 lo_message_deserialise @51 lo_message_free @52 lo_message_get_argc @53 lo_message_get_argv @54 lo_message_get_source @55 lo_message_get_timestamp @56 lo_message_get_types @57 lo_message_length @58 lo_message_new @59 lo_message_pp @60 lo_message_serialise @61 lo_method_pp @62 lo_method_pp_prefix @63 lo_pattern_match @64 lo_send @65 lo_send_bundle @66 lo_send_bundle_from @67 lo_send_from @68 lo_send_message @69 lo_send_message_from @70 lo_send_timestamped @71 lo_server_add_method @72 lo_server_del_method @73 lo_server_dispatch_data @74 lo_server_events_pending @75 lo_server_free @76 lo_server_get_port @77 lo_server_get_protocol @78 lo_server_get_socket_fd @79 lo_server_get_url @80 lo_server_new @81 lo_server_new_multicast @82 lo_server_new_with_proto @83 lo_server_next_event_delay @84 lo_server_pp @85 lo_server_recv @86 lo_server_recv_noblock @87 lo_server_thread_add_method @88 lo_server_thread_del_method @89 lo_server_thread_events_pending @90 lo_server_thread_free @91 lo_server_thread_get_port @92 lo_server_thread_get_server @93 lo_server_thread_get_url @94 lo_server_thread_new @95 lo_server_thread_new_multicast @96 lo_server_thread_new_with_proto @97 lo_server_thread_pp @98 lo_server_thread_start @99 lo_server_thread_stop @100 lo_server_wait @101 lo_strsize @102 lo_throw @103 lo_timetag_diff @104 lo_timetag_now @105 lo_url_get_hostname @106 lo_url_get_path @107 lo_url_get_port @108 lo_url_get_protocol @109 lo_url_get_protocol_id @110 nyquist-3.05/liblo/src/method.c0000644000175000000620000000175311467003724015511 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include "lo_types_internal.h" #include "lo/lo.h" void lo_method_pp(lo_method m) { lo_method_pp_prefix(m, ""); } void lo_method_pp_prefix(lo_method m, const char *p) { printf("%spath: %s\n", p, m->path); printf("%stypespec: %s\n", p, m->typespec); printf("%shandler: %p\n", p, m->handler); printf("%suser-data: %p\n", p, m->user_data); } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/send.c0000644000175000000620000002601211512356031015146 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h"xxx #endif #include #include #include #include #include #include #ifdef _MSC_VER #include #else #include #endif #ifdef WIN32 #include #include #else #include #include #include #endif #include "lo_types_internal.h" #include "lo/lo.h" #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif #ifdef WIN32 int initWSock(); #endif #ifdef WIN32 #define geterror() WSAGetLastError() #else #define geterror() errno #endif static int resolve_address(lo_address a); static int create_socket(lo_address a); static int send_data(lo_address a, lo_server from, char *data, const size_t data_len); // message.c int lo_message_add_varargs_internal(lo_message m, const char *types, va_list ap, const char *file, int line); /* Don't call lo_send_internal directly, use lo_send, a macro wrapping this * function with appropriate values for file and line */ #ifdef __GNUC__ int lo_send_internal(lo_address t, const char *file, const int line, const char *path, const char *types, ...) #else int lo_send(lo_address t, const char *path, const char *types, ...) #endif { va_list ap; int ret; #ifndef __GNUC__ const char *file = ""; int line = 0; #endif lo_message msg = lo_message_new(); t->errnum = 0; t->errstr = NULL; va_start(ap, types); ret = lo_message_add_varargs_internal(msg, types, ap, file, line); if (ret) { lo_message_free(msg); t->errnum = ret; if (ret == -1) t->errstr = "unknown type"; else t->errstr = "bad format/args"; return ret; } ret = lo_send_message(t, path, msg); lo_message_free(msg); return ret; } /* Don't call lo_send_timestamped_internal directly, use lo_send_timestamped, a * macro wrapping this function with appropriate values for file and line */ #ifdef __GNUC__ int lo_send_timestamped_internal(lo_address t, const char *file, const int line, lo_timetag ts, const char *path, const char *types, ...) #else int lo_send_timestamped(lo_address t, lo_timetag ts, const char *path, const char *types, ...) #endif { va_list ap; int ret; lo_message msg = lo_message_new(); lo_bundle b = lo_bundle_new(ts); #ifndef __GNUC__ const char *file = ""; int line = 0; #endif t->errnum = 0; t->errstr = NULL; va_start(ap, types); ret = lo_message_add_varargs_internal(msg, types, ap, file, line); if (t->errnum) { lo_message_free(msg); return t->errnum; } lo_bundle_add_message(b, path, msg); ret = lo_send_bundle(t, b); lo_message_free(msg); lo_bundle_free(b); return ret; } /* Don't call lo_send_from_internal directly, use macros wrapping this * function with appropriate values for file and line */ #ifdef __GNUC__ int lo_send_from_internal(lo_address to, lo_server from, const char *file, const int line, lo_timetag ts, const char *path, const char *types, ...) #else int lo_send_from(lo_address to, lo_server from, lo_timetag ts, const char *path, const char *types, ...) #endif { lo_bundle b = NULL; va_list ap; int ret; #ifndef __GNUC__ const char *file = ""; int line = 0; #endif lo_message msg = lo_message_new(); if (ts.sec!=LO_TT_IMMEDIATE.sec || ts.frac!=LO_TT_IMMEDIATE.frac) b = lo_bundle_new(ts); // Clear any previous errors to->errnum = 0; to->errstr = NULL; va_start(ap, types); ret = lo_message_add_varargs_internal(msg, types, ap, file, line); if (to->errnum) { if (b) lo_bundle_free(b); lo_message_free(msg); return to->errnum; } if (b) { lo_bundle_add_message(b, path, msg); ret = lo_send_bundle_from(to, from, b); } else { ret = lo_send_message_from(to, from, path, msg); } // Free-up memory lo_message_free(msg); if (b) lo_bundle_free(b); return ret; } #if 0 This (incomplete) function converts from printf-style formats to OSC typetags, but I think its dangerous and mislieading so its not available at the moment. static char *format_to_types(const char *format); static char *format_to_types(const char *format) { const char *ptr; char *types = malloc(sizeof(format) + 1); char *out = types; int inspec = 0; int width = 0; int number = 0; if (!format) { return NULL; } for (ptr = format; *ptr; ptr++) { if (inspec) { if (*ptr == 'l') { width++; } else if (*ptr >= '0' && *ptr <= '9') { number *= 10; number += *ptr - '0'; } else if (*ptr == 'd') { if (width < 2 && number < 64) { *out++ = LO_INT32; } else { *out++ = LO_INT64; } } else if (*ptr == 'f') { if (width < 2 && number < 64) { *out++ = LO_FLOAT; } else { *out++ = LO_DOUBLE; } } else if (*ptr == '%') { fprintf(stderr, "liblo warning, unexpected '%%' in format\n"); inspec = 1; width = 0; number = 0; } else { fprintf(stderr, "liblo warning, unrecognised character '%c' " "in format\n", *ptr); } } else { if (*ptr == '%') { inspec = 1; width = 0; number = 0; } else if (*ptr == LO_TRUE || *ptr == LO_FALSE || *ptr == LO_NIL || *ptr == LO_INFINITUM) { *out++ = *ptr; } else { fprintf(stderr, "liblo warning, unrecognised character '%c' " "in format\n", *ptr); } } } *out++ = '\0'; return types; } #endif static int resolve_address(lo_address a) { int ret; if (a->protocol == LO_UDP || a->protocol == LO_TCP) { struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); #ifdef ENABLE_IPV6 hints.ai_family = PF_UNSPEC; #else hints.ai_family = PF_INET; #endif hints.ai_socktype = a->protocol == LO_UDP ? SOCK_DGRAM : SOCK_STREAM; if ((ret = getaddrinfo(a->host, a->port, &hints, &ai))) { a->errnum = ret; a->errstr = gai_strerror(ret); a->ai = NULL; return -1; } a->ai = ai; } return 0; } static int create_socket(lo_address a) { if (a->protocol == LO_UDP || a->protocol == LO_TCP) { a->socket = socket(a->ai->ai_family, a->ai->ai_socktype, 0); if (a->socket == -1) { a->errnum = geterror(); a->errstr = NULL; return -1; } if (a->protocol == LO_TCP) { // Only call connect() for TCP sockets - we use sendto() for UDP if ((connect(a->socket, a->ai->ai_addr, a->ai->ai_addrlen))) { a->errnum = geterror(); a->errstr = NULL; close(a->socket); a->socket = -1; return -1; } } // if UDP and destination address is broadcast allow broadcast on the // socket else if (a->protocol == LO_UDP && a->ai->ai_family == AF_INET) { // If UDP, and destination address is broadcast, // then allow broadcast on the socket. struct sockaddr_in* si = (struct sockaddr_in*)a->ai->ai_addr; unsigned char* ip = (unsigned char*)&(si->sin_addr); if (ip[0]==255 && ip[1]==255 && ip[2]==255 && ip[3]==255) { int opt = 1; setsockopt(a->socket, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(int)); } } } #ifndef WIN32 else if (a->protocol == LO_UNIX) { struct sockaddr_un sa; a->socket = socket(PF_UNIX, SOCK_DGRAM, 0); if (a->socket == -1) { a->errnum = geterror(); a->errstr = NULL; return -1; } sa.sun_family = AF_UNIX; strncpy(sa.sun_path, a->port, sizeof(sa.sun_path)-1); if ((connect(a->socket, (struct sockaddr *)&sa, sizeof(sa))) < 0) { a->errnum = geterror(); a->errstr = NULL; close(a->socket); a->socket = -1; return -1; } } #endif else { /* unknown protocol */ return -2; } return 0; } static int send_data(lo_address a, lo_server from, char *data, const size_t data_len) { int ret=0; int sock=-1; #ifdef WIN32 if(!initWSock()) return -1; #endif if (data_len > LO_MAX_MSG_SIZE) { a->errnum = 99; a->errstr = "Attempted to send message in excess of maximum " "message size"; return -1; } // Resolve the destination address, if not done already if (!a->ai) { ret = resolve_address( a ); if (ret) return ret; } // Re-use existing socket? if (from) { sock = from->sockets[0].fd; } else if (a->protocol == LO_UDP && lo_client_sockets.udp!=-1) { sock = lo_client_sockets.udp; } else { if (a->socket==-1) { ret = create_socket( a ); if (ret) return ret; } sock = a->socket; } // Send Length of the following data if (a->protocol == LO_TCP) { int32_t size = htonl(data_len); ret = send(sock, &size, sizeof(size), MSG_NOSIGNAL); } // Send the data if (a->protocol == LO_UDP) { if (a->ttl >= 0) { unsigned char ttl = (unsigned char)a->ttl; setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&ttl,sizeof(ttl)); } ret = sendto(sock, data, data_len, MSG_NOSIGNAL, a->ai->ai_addr, a->ai->ai_addrlen); } else { ret = send(sock, data, data_len, MSG_NOSIGNAL); } if (a->protocol == LO_TCP && ret == -1) { close(a->socket); a->socket=-1; } if (ret == -1) { a->errnum = geterror(); a->errstr = NULL; } else { a->errnum = 0; a->errstr = NULL; } return ret; } int lo_send_message(lo_address a, const char *path, lo_message msg) { return lo_send_message_from( a, NULL, path, msg ); } int lo_send_message_from(lo_address a, lo_server from, const char *path, lo_message msg) { const size_t data_len = lo_message_length(msg, path); char *data = lo_message_serialise(msg, path, NULL, NULL); // Send the message int ret = send_data( a, from, data, data_len ); // For TCP, retry once if it failed. The first try will return // error if the connection was closed, so the second try will // attempt to re-open the connection. if (ret == -1 && a->protocol == LO_TCP) ret = send_data( a, from, data, data_len ); // Free the memory allocated by lo_message_serialise if (data) free( data ); return ret; } int lo_send_bundle(lo_address a, lo_bundle b) { return lo_send_bundle_from( a, NULL, b ); } int lo_send_bundle_from(lo_address a, lo_server from, lo_bundle b) { const size_t data_len = lo_bundle_length(b); char *data = lo_bundle_serialise(b, NULL, NULL); // Send the bundle int ret = send_data( a, from, data, data_len ); // Free the memory allocated by lo_bundle_serialise if (data) free( data ); return ret; } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/pattern_match.c0000644000175000000620000002065711467003724017066 0ustar stevestaff/* Open SoundControl kit in C++ */ /* Copyright (C) 2002-2004 libOSC++ contributors. See AUTHORS */ /* */ /* 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.1 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 */ /* */ /* For questions regarding this program contact */ /* Daniel Holth or visit */ /* http://wiretap.stetson.edu/ */ /* In the sprit of the public domain, my modifications to this file are also */ /* dedicated to the public domain. Daniel Holth, Oct. 2004 */ /* ChangeLog: * * 2004-10-29 Import, convert to C++, begin OSC syntax changes. -dwh * OSC syntax changes are now working, needs more testing. * */ // Original header and syntax: /* * robust glob pattern matcher * ozan s. yigit/dec 1994 * public domain * * glob patterns: * * matches zero or more characters * ? matches any single character * [set] matches any character in the set * [^set] matches any character NOT in the set * where a set is a group of characters or ranges. a range * is written as two characters seperated with a hyphen: a-z denotes * all characters between a to z inclusive. * [-set] set matches a literal hypen and any character in the set * []set] matches a literal close bracket and any character in the set * * char matches itself except where char is '*' or '?' or '[' * \char matches char, including any pattern character * * examples: * a*c ac abc abbc ... * a?c acc abc aXc ... * a[a-z]c aac abc acc ... * a[-a-z]c a-c aac abc ... * * $Log$ * Revision 1.1 2004/11/19 23:00:57 theno23 * Added lo_send_timestamped * * Revision 1.3 1995/09/14 23:24:23 oz * removed boring test/main code. * * Revision 1.2 94/12/11 10:38:15 oz * cset code fixed. it is now robust and interprets all * variations of cset [i think] correctly, including [z-a] etc. * * Revision 1.1 94/12/08 12:45:23 oz * Initial revision */ #include "lo/lo.h" #ifndef NEGATE #define NEGATE '!' #endif #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif int lo_pattern_match(const char *str, const char *p) { int negate; int match; char c; while (*p) { if (!*str && *p != '*') return false; switch (c = *p++) { case '*': while (*p == '*' && *p != '/') p++; if (!*p) return true; // if (*p != '?' && *p != '[' && *p != '\\') if (*p != '?' && *p != '[' && *p != '{') while (*str && *p != *str) str++; while (*str) { if (lo_pattern_match(str, p)) return true; str++; } return false; case '?': if (*str) break; return false; /* * set specification is inclusive, that is [a-z] is a, z and * everything in between. this means [z-a] may be interpreted * as a set that contains z, a and nothing in between. */ case '[': if (*p != NEGATE) negate = false; else { negate = true; p++; } match = false; while (!match && (c = *p++)) { if (!*p) return false; if (*p == '-') { /* c-c */ if (!*++p) return false; if (*p != ']') { if (*str == c || *str == *p || (*str > c && *str < *p)) match = true; } else { /* c-] */ if (*str >= c) match = true; break; } } else { /* cc or c] */ if (c == *str) match = true; if (*p != ']') { if (*p == *str) match = true; } else break; } } if (negate == match) return false; /* * if there is a match, skip past the cset and continue on */ while (*p && *p != ']') p++; if (!*p++) /* oops! */ return false; break; /* * {astring,bstring,cstring} */ case '{': { // *p is now first character in the {brace list} const char *place = str; // to backtrack const char *remainder = p; // to forwardtrack // find the end of the brace list while (*remainder && *remainder != '}') remainder++; if (!*remainder++) /* oops! */ return false; c = *p++; while (c) { if (c == ',') { if(lo_pattern_match(str, remainder)) { return true; } else { // backtrack on test string str = place; // continue testing, // skip comma if (!*p++) // oops return false; } } else if (c == '}') { // continue normal pattern matching if (!*p && !*str) return true; str--; // str is incremented again below break; } else if (c == *str) { str++; if (!*str && *remainder) return false; } else { // skip to next comma str = place; while (*p != ',' && *p != '}' && *p) p++; if (*p == ',') p++; else if (*p == '}') { return false; } } c = *p++; } } break; /* Not part of OSC pattern matching case '\\': if (*p) c = *p++; */ default: if (c != *str) return false; break; } str++; } return !*str; } nyquist-3.05/liblo/src/bundle.c0000644000175000000620000000702011467003724015473 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include "lo_types_internal.h" #include "lo/lo.h" lo_bundle lo_bundle_new(lo_timetag tt) { lo_bundle b = calloc(1, sizeof(struct _lo_bundle)); b->size = 4; b->len = 0; b->ts = tt; b->msgs = calloc(b->size, sizeof(lo_message)); b->paths = calloc(b->size, sizeof(char *)); return b; } int lo_bundle_add_message(lo_bundle b, const char *path, lo_message m) { if (!m) return 0; if (b->len >= b->size) { b->size *= 2; b->msgs = realloc(b->msgs, b->size * sizeof(lo_message)); b->paths = realloc(b->paths, b->size * sizeof(char *)); if (!b->msgs || !b->paths) return -1; } b->msgs[b->len] = m; b->paths[b->len] = (char *)path; (b->len)++; return 0; } size_t lo_bundle_length(lo_bundle b) { size_t size = 16; /* "#bundle" and the timetag */ int i; if (!b) { return 0; } size += b->len * 4; /* sizes */ for (i = 0; i < b->len; i++) { size += lo_message_length(b->msgs[i], b->paths[i]); } return size; } void *lo_bundle_serialise(lo_bundle b, void *to, size_t *size) { size_t s, skip; int32_t *bes; int i; char *pos; lo_pcast32 be; if (!b) { return NULL; } s = lo_bundle_length(b); if (size) { *size = s; } if (!to) { to = calloc(1, s); } pos = to; strcpy(pos, "#bundle"); pos += 8; be.nl = lo_htoo32(b->ts.sec); memcpy(pos, &be, 4); pos += 4; be.nl = lo_htoo32(b->ts.frac); memcpy(pos, &be, 4); pos += 4; for (i = 0; i < b->len; i++) { lo_message_serialise(b->msgs[i], b->paths[i], pos + 4, &skip); bes = (int32_t *)pos; *bes = lo_htoo32(skip); pos += skip + 4; if (pos > (char *)to + s) { fprintf(stderr, "liblo: data integrity error at message %d\n", i); return NULL; } } if (pos != (char*)to + s) { fprintf(stderr, "liblo: data integrity error\n"); return NULL; } return to; } void lo_bundle_free(lo_bundle b) { if (!b) { return; } free(b->msgs); free(b->paths); free(b); } static int _lo_internal_compare_ptrs( const void* a, const void* b ) { if (*(void**)a < *(void**)b) return -1; if (*(void**)a == *(void**)b) return 0; return 1; } void lo_bundle_free_messages(lo_bundle b) { int i; lo_message tmp = 0; if (!b) return; /* avoid freeing the same message twice */ if (b->len > 2) qsort(b->msgs, b->len, sizeof(lo_message*), _lo_internal_compare_ptrs); for(i = 0; i < b->len; i++) { if (b->msgs[i] != tmp) { tmp = b->msgs[i]; lo_message_free(b->msgs[i]); } } free(b->msgs); free(b->paths); free(b); } void lo_bundle_pp(lo_bundle b) { int i; if (!b) return; printf("bundle(%f):\n", (double)b->ts.sec + b->ts.frac / 4294967296.0); for (i = 0; i < b->len; i++) { lo_message_pp(b->msgs[i]); } printf("\n"); } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/Makefile.am0000644000175000000620000000137211467003724016116 0ustar stevestaffSUBDIRS = . tools MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = liblo.def noinst_HEADERS = lo_types_internal.h lo_internal.h SOURCE_FILES = address.c send.c message.c server.c method.c \ server_thread.c blob.c bundle.c timetag.c pattern_match.c lib_LTLIBRARIES = liblo.la liblo_la_CFLAGS = -Wall -I$(top_srcdir) liblo_la_SOURCES = $(SOURCE_FILES) liblo_la_LIBADD = -lpthread liblo_la_LDFLAGS = -export-dynamic -version-info @LO_SO_VERSION@ noinst_PROGRAMS = testlo subtest testlo_CFLAGS = -Wall -I$(top_srcdir) testlo_SOURCES = testlo.c testlo_LDADD = liblo.la subtest_CFLAGS = -Wall -I$(top_srcdir) subtest_SOURCES = subtest.c subtest_LDADD = liblo.la test: all ./testlo memtest: all LD_LIBRARY_PATH=.libs valgrind --tool=memcheck .libs/testlo nyquist-3.05/liblo/src/server.c0000644000175000000620000010041511467003724015532 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #ifdef _MSC_VER #define _WINSOCKAPI_ #define snprintf _snprintf #else #include #endif #ifdef WIN32 #include #include #define EADDRINUSE WSAEADDRINUSE #else #include #include #ifdef HAVE_POLL #include #endif #include #include #endif #ifdef WIN32 #define geterror() WSAGetLastError() #else #define geterror() errno #endif #include "lo_types_internal.h" #include "lo_internal.h" #include "lo/lo.h" #include "lo/lo_throw.h" #define LO_HOST_SIZE 1024 typedef struct { lo_timetag ts; char *path; lo_message msg; void *next; } queued_msg_list; struct lo_cs lo_client_sockets = {-1, -1}; static int lo_can_coerce_spec(const char *a, const char *b); static int lo_can_coerce(char a, char b); static void dispatch_method(lo_server s, const char *path, lo_message msg); static int dispatch_queued(lo_server s); static void queue_data(lo_server s, lo_timetag ts, const char *path, lo_message msg); static lo_server lo_server_new_with_proto_internal(const char *group, const char *port, int proto, lo_err_handler err_h); static int lo_server_add_socket(lo_server s, int socket); static void lo_server_del_socket(lo_server s, int index, int socket); static int lo_server_join_multicast_group(lo_server s, const char *group); #ifdef WIN32 #ifndef gai_strerror // Copied from the Win32 SDK // WARNING: The gai_strerror inline functions below use static buffers, // and hence are not thread-safe. We'll use buffers long enough to hold // 1k characters. Any system error messages longer than this will be // returned as empty strings. However 1k should work for the error codes // used by getaddrinfo(). #define GAI_STRERROR_BUFFER_SIZE 1024 char *WSAAPI gai_strerrorA(int ecode) { DWORD dwMsgLen; static char buff[GAI_STRERROR_BUFFER_SIZE + 1]; dwMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS |FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ecode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)buff, GAI_STRERROR_BUFFER_SIZE, NULL); return buff; } #endif static int stateWSock = -1; int initWSock() { WORD reqversion; WSADATA wsaData; if(stateWSock >= 0) return stateWSock; /* TODO - which version of Winsock do we actually need? */ reqversion = MAKEWORD( 2, 2 ); if(WSAStartup(reqversion,&wsaData) != 0) { /* Couldn't initialize Winsock */ stateWSock = 0; } else if ( LOBYTE( wsaData.wVersion ) != LOBYTE(reqversion) || HIBYTE( wsaData.wVersion ) != HIBYTE(reqversion) ) { /* wrong version */ WSACleanup(); stateWSock = 0; } else stateWSock = 1; return stateWSock; } #endif lo_server lo_server_new(const char *port, lo_err_handler err_h) { return lo_server_new_with_proto(port, LO_DEFAULT, err_h); } lo_server lo_server_new_multicast(const char *group, const char *port, lo_err_handler err_h) { return lo_server_new_with_proto_internal(group, port, LO_UDP, err_h); } lo_server lo_server_new_with_proto(const char *port, int proto, lo_err_handler err_h) { return lo_server_new_with_proto_internal(NULL, port, proto, err_h); } lo_server lo_server_new_with_proto_internal(const char *group, const char *port, int proto, lo_err_handler err_h) { lo_server s; struct addrinfo *ai = NULL, *it, *used; struct addrinfo hints; int ret = -1; int tries = 0; char pnum[16]; const char *service; char hostname[LO_HOST_SIZE]; // Set real protocol, if Default is requested if (proto==LO_DEFAULT) { #ifndef WIN32 if (port && *port == '/') proto = LO_UNIX; else #endif proto = LO_UDP; } #ifdef WIN32 if(!initWSock()) return NULL; #endif s = calloc(1, sizeof(struct _lo_server)); if (!s) return 0; s->err_h = err_h; s->first = NULL; s->ai = NULL; s->hostname = NULL; s->protocol = proto; s->port = 0; s->path = NULL; s->queued = NULL; s->sockets_len = 1; s->sockets_alloc = 2; s->sockets = calloc(2, sizeof(*(s->sockets))); if (!s->sockets) { free(s); return 0; } s->sockets[0].fd = -1; memset(&hints, 0, sizeof(hints)); if (proto == LO_UDP) { hints.ai_socktype = SOCK_DGRAM; } else if (proto == LO_TCP) { hints.ai_socktype = SOCK_STREAM; } #ifndef WIN32 else if (proto == LO_UNIX) { struct sockaddr_un sa; s->sockets[0].fd = socket(PF_UNIX, SOCK_DGRAM, 0); if (s->sockets[0].fd == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } sa.sun_family = AF_UNIX; strncpy(sa.sun_path, port, sizeof(sa.sun_path)-1); if ((ret = bind(s->sockets[0].fd, (struct sockaddr *)&sa, sizeof(sa))) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "bind()"); lo_server_free(s); return NULL; } s->path = strdup(port); return s; } #endif else { lo_throw(s, LO_UNKNOWNPROTO, "Unknown protocol", NULL); lo_server_free(s); return NULL; } #ifdef ENABLE_IPV6 hints.ai_family = PF_UNSPEC; #else hints.ai_family = PF_INET; #endif hints.ai_flags = AI_PASSIVE; if (!port) { service = pnum; } else { service = port; } do { if (!port) { /* not a good way to get random numbers, but its not critical */ snprintf(pnum, 15, "%ld", 10000 + ((unsigned int)rand() + time(NULL)) % 10000); } if ((ret = getaddrinfo(NULL, service, &hints, &ai))) { lo_throw(s, ret, gai_strerror(ret), NULL); freeaddrinfo(ai); return NULL; } used = NULL; s->ai = ai; s->sockets[0].fd = -1; s->port = 0; for (it = ai; it && s->sockets[0].fd == -1; it = it->ai_next) { used = it; s->sockets[0].fd = socket(it->ai_family, hints.ai_socktype, 0); } if (s->sockets[0].fd == -1) { int err = geterror(); used = NULL; lo_throw(s, err, strerror(err), "socket()"); lo_server_free(s); return NULL; } /* Join multicast group if specified. */ /* This must be done before bind() on POSIX, but after bind() Windows. */ #ifndef WIN32 if (group != NULL) if (lo_server_join_multicast_group(s, group)) return NULL; #endif if ((ret = bind(s->sockets[0].fd, used->ai_addr, used->ai_addrlen)) < 0) { int err = geterror(); if (err == EINVAL || err == EADDRINUSE) { used = NULL; continue; } lo_throw(s, err, strerror(err), "bind()"); lo_server_free(s); return NULL; } } while (!used && tries++ < 16); /* Join multicast group if specified (see above). */ #ifdef WIN32 if (group != NULL) if (lo_server_join_multicast_group(s, group)) return NULL; #endif if (proto == LO_TCP) { listen(s->sockets[0].fd, 8); } if (!used) { lo_throw(s, LO_NOPORT, "cannot find free port", NULL); lo_server_free(s); return NULL; } if (proto == LO_UDP) { lo_client_sockets.udp = s->sockets[0].fd; } else if (proto == LO_TCP) { lo_client_sockets.tcp = s->sockets[0].fd; } /* Set hostname to empty string */ hostname[0] = '\0'; #ifdef ENABLE_IPV6 /* Try it the IPV6 friendly way first */ for (it = ai; it; it = it->ai_next) { if (getnameinfo(it->ai_addr, it->ai_addrlen, hostname, sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) { break; } } /* check to make sure getnameinfo() didn't just set the hostname to "::". Needed on Darwin. */ if (hostname[0] == ':') { hostname[0] = '\0'; } #endif /* Fallback to the oldschool (i.e. more reliable) way */ if (!hostname[0]) { struct hostent *he; gethostname(hostname, sizeof(hostname)); he = gethostbyname(hostname); if (he) { strncpy(hostname, he->h_name, sizeof(hostname)); } } /* soethings gone really wrong, just hope its local only */ if (!hostname[0]) { strcpy(hostname, "localhost"); } s->hostname = strdup(hostname); if (used->ai_family == PF_INET6) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)used->ai_addr; s->port = htons(addr->sin6_port); } else if (used->ai_family == PF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)used->ai_addr; s->port = htons(addr->sin_port); } else { lo_throw(s, LO_UNKNOWNPROTO, "unknown protocol family", NULL); s->port = atoi(port); } return s; } int lo_server_join_multicast_group(lo_server s, const char *group) { struct ip_mreq mreq; unsigned int yes = 1; memset(&mreq, 0, sizeof(mreq)); #ifdef HAVE_INET_ATON if (inet_aton(group, &mreq.imr_multiaddr)==0) { int err = geterror(); lo_throw(s, err, strerror(err), "inet_aton()"); lo_server_free(s); return err; } #else mreq.imr_multiaddr.s_addr = inet_addr(group); if (mreq.imr_multiaddr.s_addr == INADDR_ANY || mreq.imr_multiaddr.s_addr == INADDR_NONE) { int err = geterror(); lo_throw(s, err, strerror(err), "inet_addr()"); lo_server_free(s); return err; } #endif mreq.imr_interface.s_addr=htonl(INADDR_ANY); if (setsockopt(s->sockets[0].fd,IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(IP_ADD_MEMBERSHIP)"); lo_server_free(s); return err; } if (setsockopt(s->sockets[0].fd,SOL_SOCKET,SO_REUSEADDR, &yes,sizeof(yes)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEADDR)"); lo_server_free(s); return err; } #ifdef SO_REUSEPORT if (setsockopt(s->sockets[0].fd,SOL_SOCKET,SO_REUSEPORT, &yes,sizeof(yes)) < 0) { int err = geterror(); lo_throw(s, err, strerror(err), "setsockopt(SO_REUSEPORT)"); lo_server_free(s); return err; } #endif return 0; } void lo_server_free(lo_server s) { if (s) { lo_method it; lo_method next; int i; for (i=s->sockets_len-1; i >= 0; i--) { if (s->sockets[i].fd != -1) { if (s->protocol == LO_UDP && s->sockets[i].fd == lo_client_sockets.udp) { lo_client_sockets.udp = -1; } else if (s->protocol == LO_TCP && s->sockets[0].fd == lo_client_sockets.tcp) { lo_client_sockets.tcp = -1; } close(s->sockets[i].fd); s->sockets[i].fd = -1; } } if (s->ai) { freeaddrinfo(s->ai); s->ai=NULL; } if (s->hostname) { free(s->hostname); s->hostname = NULL; } if (s->path) { if (s->protocol == LO_UNIX) unlink( s->path ); free(s->path); s->path = NULL; } for (it = s->first; it; it = next) { next = it->next; free((char *)it->path); free((char *)it->typespec); free(it); } free(s->sockets); free(s); } } void *lo_server_recv_raw(lo_server s, size_t *size) { char buffer[LO_MAX_MSG_SIZE]; int ret; void *data = NULL; #ifdef WIN32 if(!initWSock()) return NULL; #endif s->addr_len = sizeof(s->addr); ret = recvfrom(s->sockets[0].fd, buffer, LO_MAX_MSG_SIZE, 0, (struct sockaddr *)&s->addr, &s->addr_len); if (ret <= 0) { return NULL; } data = malloc(ret); memcpy(data, buffer, ret); if (size) *size = ret; return data; } void *lo_server_recv_raw_stream(lo_server s, size_t *size) { struct sockaddr_storage addr; socklen_t addr_len = sizeof(addr); char buffer[LO_MAX_MSG_SIZE]; int32_t read_size; int ret=0, i; void *data = NULL; int sock = -1; int repeat = 1; #ifdef HAVE_SELECT #ifndef HAVE_POLL fd_set ps; int nfds=0; #endif #endif /* check sockets in reverse order so that already-open sockets * have priority. this allows checking for closed sockets even * when new connections are being requested. it also allows to * continue looping through the list of sockets after closing and * deleting a socket, since deleting sockets doesn't affect the * order of the array to the left of the index. */ #ifdef HAVE_POLL for (i=0; i < s->sockets_len; i++) { s->sockets[i].events = POLLIN | POLLPRI; s->sockets[i].revents = 0; } poll(s->sockets, s->sockets_len, -1); for (i=(s->sockets_len-1); i >= 0; --i) { if (s->sockets[i].revents == POLLERR || s->sockets[i].revents == POLLHUP) { if (i>0) { close(s->sockets[i].fd); lo_server_del_socket(s, i, s->sockets[i].fd); continue; } else return NULL; } if (s->sockets[i].revents) { sock = s->sockets[i].fd; #else #ifdef HAVE_SELECT if(!initWSock()) return NULL; FD_ZERO(&ps); for (i=(s->sockets_len-1); i >= 0; --i) { FD_SET(s->sockets[i].fd, &ps); if (s->sockets[i].fd > nfds) nfds = s->sockets[i].fd; } if (select(nfds+1,&ps,NULL,NULL,NULL) == SOCKET_ERROR) return NULL; for (i=0; i < s->sockets_len; i++) { if (FD_ISSET(s->sockets[i].fd, &ps)) { sock = s->sockets[i].fd; #endif #endif if (sock == -1 || !repeat) return NULL; /* zeroeth socket is listening for new connections */ if (sock == s->sockets[0].fd) { sock = accept(sock, (struct sockaddr *)&addr, &addr_len); i = lo_server_add_socket(s, sock); /* only repeat this loop for sockets other than the listening * socket, (otherwise i will be wrong next time around) */ repeat = 0; } if (i<0) { close(sock); return NULL; } ret = recv(sock, &read_size, sizeof(read_size), 0); read_size = ntohl(read_size); if (read_size > LO_MAX_MSG_SIZE || ret <= 0) { close(sock); lo_server_del_socket(s, i, sock); if (ret > 0) lo_throw(s, LO_TOOBIG, "Message too large", "recv()"); continue; } ret = recv(sock, buffer, read_size, 0); if (ret <= 0) { close(sock); lo_server_del_socket(s, i, sock); continue; } /* end of loop over sockets: successfully read data */ break; } } data = malloc(ret); memcpy(data, buffer, ret); if (size) *size = ret; return data; } int lo_server_wait(lo_server s, int timeout) { int sched_timeout = lo_server_next_event_delay(s) * 1000; int i; #ifdef HAVE_SELECT #ifndef HAVE_POLL fd_set ps; struct timeval stimeout; #endif #endif #ifdef HAVE_POLL for (i=0; i < s->sockets_len; i++) { s->sockets[i].events = POLLIN | POLLPRI | POLLERR | POLLHUP; s->sockets[i].revents = 0; } poll(s->sockets, s->sockets_len, timeout > sched_timeout ? sched_timeout : timeout); if (lo_server_next_event_delay(s) < 0.01) return 1; for (i=0; i < s->sockets_len; i++) { if (s->sockets[i].revents == POLLERR || s->sockets[i].revents == POLLHUP) return 0; if (s->sockets[i].revents) return 1; } #else #ifdef HAVE_SELECT int res,to,nfds=0; if(!initWSock()) return 0; to = timeout > sched_timeout ? sched_timeout : timeout; stimeout.tv_sec = to/1000; stimeout.tv_usec = (to%1000)*1000; FD_ZERO(&ps); for (i=0; i < s->sockets_len; i++) { FD_SET(s->sockets[i].fd,&ps); if (s->sockets[i].fd > nfds) nfds = s->sockets[i].fd; } res = select(nfds+1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) return 0; if (res || lo_server_next_event_delay(s) < 0.01) return 1; #endif #endif return 0; } int lo_server_recv_noblock(lo_server s, int timeout) { int result = lo_server_wait(s,timeout); if (result>0) { return lo_server_recv(s); } else { return 0; } } int lo_server_recv(lo_server s) { void *data; size_t size; double sched_time = lo_server_next_event_delay(s); int i; #ifdef HAVE_SELECT #ifndef HAVE_POLL fd_set ps; struct timeval stimeout; int res,nfds=0; #endif #endif again: if (sched_time > 0.01) { if (sched_time > 10.0) { sched_time = 10.0; } #ifdef HAVE_POLL for (i=0; i < s->sockets_len; i++) { s->sockets[i].events = POLLIN | POLLPRI | POLLERR | POLLHUP; s->sockets[i].revents = 0; } poll(s->sockets, s->sockets_len, (int)(sched_time * 1000.0)); for (i=0; i < s->sockets_len; i++) { if ( s->sockets[i].revents == POLLERR || s->sockets[i].revents == POLLHUP) return 0; if (s->sockets[i].revents) break; } if (i >= s->sockets_len) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) goto again; return dispatch_queued(s); } #else #ifdef HAVE_SELECT if(!initWSock()) return 0; FD_ZERO(&ps); for (i=0; i < s->sockets_len; i++) { FD_SET(s->sockets[i].fd,&ps); if (s->sockets[i].fd > nfds) nfds = s->sockets[i].fd; } stimeout.tv_sec = sched_time; stimeout.tv_usec = (sched_time-stimeout.tv_sec)*1.e6; res = select(nfds+1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) { return 0; } if(!res) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) goto again; return dispatch_queued(s); } #endif #endif } else { return dispatch_queued(s); } if (s->protocol == LO_TCP) { data = lo_server_recv_raw_stream(s, &size); } else { data = lo_server_recv_raw(s, &size); } if (!data) { return 0; } if (lo_server_dispatch_data(s, data, size) < 0) { free(data); return -1; } free(data); return size; } /** \internal \brief Add a socket to this server's list of sockets. * \param s The lo_server * \param socket The socket number to add. * \return The index number of the added socket, or -1 on failure. */ int lo_server_add_socket(lo_server s, int socket) { if ((s->sockets_len+1) > s->sockets_alloc) { void *sp = realloc(s->sockets, sizeof(*(s->sockets))*(s->sockets_alloc*2)); if (!sp) return -1; s->sockets = sp; s->sockets_alloc *= 2; } s->sockets[s->sockets_len].fd = socket; s->sockets_len ++; return s->sockets_len-1; } /** \internal \brief Delete a socket from this server's list of sockets. * \param s The lo_server * \param index The index of the socket to delete, -1 if socket is provided. * \param socket The socket number to delete, -1 if index is provided. * \return The index number of the added socket. */ void lo_server_del_socket(lo_server s, int index, int socket) { int i; if (index < 0 && socket != -1) { for (index=0; index < s->sockets_len; index++) if (s->sockets[index].fd == socket) break; } if (index < 0 || index >= s->sockets_len) return; for (i=index+1; i < s->sockets_len; i++) s->sockets[i-1] = s->sockets[i]; s->sockets_len --; } int lo_server_dispatch_data(lo_server s, void *data, size_t size) { int result = 0; char *path = data; ssize_t len = lo_validate_string(data, size); if (len < 0) { lo_throw(s, -len, "Invalid message path", NULL); return len; } if (!strcmp(data, "#bundle")) { char *pos; int remain; uint32_t elem_len; lo_timetag ts, now; ssize_t bundle_result = lo_validate_bundle(data, size); if (bundle_result < 0) { lo_throw(s, -bundle_result, "Invalid bundle", NULL); return bundle_result; } pos = (char *)data + len; remain = size - len; lo_timetag_now(&now); ts.sec = lo_otoh32(*((uint32_t *)pos)); pos += 4; ts.frac = lo_otoh32(*((uint32_t *)pos)); pos += 4; remain -= 8; while (remain >= 4) { lo_message msg; elem_len = lo_otoh32(*((uint32_t *)pos)); pos += 4; remain -= 4; msg = lo_message_deserialise(pos, elem_len, &result); if (!msg) { lo_throw(s, result, "Invalid bundle element received", path); return -result; } // set timetag from bundle msg->ts = ts; // test for immediate dispatch if ((ts.sec == LO_TT_IMMEDIATE.sec && ts.frac == LO_TT_IMMEDIATE.frac) || lo_timetag_diff(ts, now) <= 0.0) { dispatch_method(s, pos, msg); lo_message_free(msg); } else { queue_data(s, ts, pos, msg); } pos += elem_len; remain -= elem_len; } } else { lo_message msg = lo_message_deserialise(data, size, &result); if (NULL == msg) { lo_throw(s, result, "Invalid message received", path); return -result; } dispatch_method(s, data, msg); lo_message_free(msg); } return size; } /* returns the time in seconds until the next scheduled event */ double lo_server_next_event_delay(lo_server s) { if (s->queued) { lo_timetag now; double delay; lo_timetag_now(&now); delay = lo_timetag_diff(((queued_msg_list *)s->queued)->ts, now); delay = delay > 100.0 ? 100.0 : delay; delay = delay < 0.0 ? 0.0 : delay; return delay; } return 100.0; } static void dispatch_method(lo_server s, const char *path, lo_message msg) { char *types = msg->types + 1; int argc = strlen(types); lo_arg **argv = msg->argv; lo_method it; int ret = 1; int err; int pattern = strpbrk(path, " #*,?[]{}") != NULL; lo_address src = lo_address_new(NULL, NULL); char hostname[LO_HOST_SIZE]; char portname[32]; const char *pptr; msg->source = src; //inet_ntop(s->addr.ss_family, &s->addr.padding, hostname, sizeof(hostname)); if (s->protocol == LO_UDP && s->addr_len>0) { err = getnameinfo((struct sockaddr *)&s->addr, sizeof(s->addr), hostname, sizeof(hostname), portname, sizeof(portname), NI_NUMERICHOST | NI_NUMERICSERV); if (err) { switch (err) { case EAI_AGAIN: lo_throw(s, err, "Try again", path); break; case EAI_BADFLAGS: lo_throw(s, err, "Bad flags", path); break; case EAI_FAIL: lo_throw(s, err, "Failed", path); break; case EAI_FAMILY: lo_throw(s, err, "Cannot resolve address family", path); break; case EAI_MEMORY: lo_throw(s, err, "Out of memory", path); break; case EAI_NONAME: lo_throw(s, err, "Cannot resolve", path); break; #ifndef WIN32 case EAI_SYSTEM: lo_throw(s, err, strerror(err), path); break; #endif default: lo_throw(s, err, "Unknown error", path); break; } return; } } else { hostname[0] = '\0'; portname[0] = '\0'; } // Store the source information in the lo_address if (src->host) free(src->host); if (src->host) free(src->port); src->host = strdup(hostname); src->port = strdup(portname); src->protocol = s->protocol; for (it = s->first; it; it = it->next) { /* If paths match or handler is wildcard */ if (!it->path || !strcmp(path, it->path) || (pattern && lo_pattern_match(it->path, path))) { /* If types match or handler is wildcard */ if (!it->typespec || !strcmp(types, it->typespec)) { /* Send wildcard path to generic handler, expanded path to others. */ pptr = path; if (it->path) pptr = it->path; ret = it->handler(pptr, types, argv, argc, msg, it->user_data); } else if (lo_can_coerce_spec(types, it->typespec)) { int i; int opsize = 0; char *ptr = msg->data; char *data_co, *data_co_ptr; argv = calloc(argc, sizeof(lo_arg *)); for (i=0; itypespec[i], ptr); ptr += lo_arg_size(types[i], ptr); } data_co = malloc(opsize); data_co_ptr = data_co; ptr = msg->data; for (i=0; itypespec[i], (lo_arg *)data_co_ptr, types[i], (lo_arg *)ptr); data_co_ptr += lo_arg_size(it->typespec[i], data_co_ptr); ptr += lo_arg_size(types[i], ptr); } /* Send wildcard path to generic handler, expanded path to others. */ pptr = path; if (it->path) pptr = it->path; ret = it->handler(pptr, it->typespec, argv, argc, msg, it->user_data); free(argv); free(data_co); argv = NULL; } if (ret == 0 && !pattern) { break; } } } /* If we find no matching methods, check for protocol level stuff */ if (ret == 1 && s->protocol == LO_UDP) { char *pos = strrchr(path, '/'); /* if its a method enumeration call */ if (pos && *(pos+1) == '\0') { lo_message reply = lo_message_new(); int len = strlen(path); lo_strlist *sl = NULL, *slit, *slnew, *slend; if (!strcmp(types, "i")) { lo_message_add_int32(reply, argv[0]->i); } lo_message_add_string(reply, path); for (it = s->first; it; it = it->next) { /* If paths match */ if (it->path && !strncmp(path, it->path, len)) { char *tmp; char *sec; tmp = malloc(strlen(it->path + len) + 1); strcpy(tmp, it->path + len); #ifdef WIN32 sec = strchr(tmp,'/'); #else sec = index(tmp, '/'); #endif if (sec) *sec = '\0'; slend = sl; for (slit = sl; slit; slend = slit, slit = slit->next) { if (!strcmp(slit->str, tmp)) { free(tmp); tmp = NULL; break; } } if (tmp) { slnew = calloc(1, sizeof(lo_strlist)); slnew->str = tmp; slnew->next = NULL; if (!slend) { sl = slnew; } else { slend->next = slnew; } } } } slit = sl; while(slit) { lo_message_add_string(reply, slit->str); slnew = slit; slit = slit->next; free(slnew->str); free(slnew); } lo_send_message(src, "#reply", reply); lo_message_free(reply); } } lo_address_free(src); msg->source = NULL; } int lo_server_events_pending(lo_server s) { return s->queued != 0; } static void queue_data(lo_server s, lo_timetag ts, const char *path, lo_message msg) { /* insert blob into future dispatch queue */ queued_msg_list *it = s->queued; queued_msg_list *prev = NULL; queued_msg_list *ins = calloc(1, sizeof(queued_msg_list)); ins->ts = ts; ins->path = strdup(path); ins->msg = msg; while (it) { if (lo_timetag_diff(it->ts, ts) > 0.0) { if (prev) { prev->next = ins; } else { s->queued = ins; ins->next = NULL; } ins->next = it; return; } prev = it; it = it->next; } /* fell through, so this event is last */ if (prev) { prev->next = ins; } else { s->queued = ins; } ins->next = NULL; } static int dispatch_queued(lo_server s) { queued_msg_list *head = s->queued; queued_msg_list *tailhead; lo_timetag disp_time; if (!head) { lo_throw(s, LO_INT_ERR, "attempted to dispatch with empty queue", "timeout"); return 1; } disp_time = head->ts; do { char *path; lo_message msg; tailhead = head->next; path = ((queued_msg_list *)s->queued)->path; msg = ((queued_msg_list *)s->queued)->msg; dispatch_method(s, path, msg); free(path); lo_message_free(msg); free((queued_msg_list *)s->queued); s->queued = tailhead; head = tailhead; } while (head && lo_timetag_diff(head->ts, disp_time) < FLT_EPSILON); return 0; } lo_method lo_server_add_method(lo_server s, const char *path, const char *typespec, lo_method_handler h, void *user_data) { lo_method m = calloc(1, sizeof(struct _lo_method)); lo_method it; if (path && strpbrk(path, " #*,?[]{}")) { return NULL; } if (path) { m->path = strdup(path); } else { m->path = NULL; } if (typespec) { m->typespec = strdup(typespec); } else { m->typespec = NULL; } m->handler = h; m->user_data = user_data; m->next = NULL; /* append the new method to the list */ if (!s->first) { s->first = m; } else { /* get to the last member of the list */ for (it=s->first; it->next; it=it->next); it->next = m; } return m; } void lo_server_del_method(lo_server s, const char *path, const char *typespec) { lo_method it, prev, next; int pattern = 0; if (!s->first) return; if (path) pattern = strpbrk(path, " #*,?[]{}") != NULL; it = s->first; prev = it; while (it) { /* incase we free it */ next = it->next; /* If paths match or handler is wildcard */ if ((it->path == path) || (path && it->path && !strcmp(path, it->path)) || (pattern && it->path && lo_pattern_match(it->path, path))) { /* If types match or handler is wildcard */ if ((it->typespec == typespec) || (typespec && it->typespec && !strcmp(typespec, it->typespec)) ) { /* Take care when removing the head. */ if (it == s->first) { s->first = it->next; } else { prev->next = it->next; } next = it->next; free((void *)it->path); free((void *)it->typespec); free(it); it = prev; } } prev = it; if (it) it = next; } } int lo_server_get_socket_fd(lo_server s) { if (s->protocol != LO_UDP && s->protocol != LO_TCP #ifndef WIN32 && s->protocol != LO_UNIX #endif ) { return -1; /* assume it is not supported */ } return s->sockets[0].fd; } int lo_server_get_port(lo_server s) { if (!s) { return 0; } return s->port; } int lo_server_get_protocol(lo_server s) { if (!s) { return -1; } return s->protocol; } char *lo_server_get_url(lo_server s) { int ret=0; char *buf; if (!s) { return NULL; } if (s->protocol == LO_UDP || s->protocol == LO_TCP) { char *proto = s->protocol == LO_UDP ? "udp" : "tcp"; #ifndef _MSC_VER ret = snprintf(NULL, 0, "osc.%s://%s:%d/", proto, s->hostname, s->port); #endif if (ret <= 0) { /* this libc is not C99 compliant, guess a size */ ret = 1023; } buf = malloc((ret + 2) * sizeof(char)); snprintf(buf, ret+1, "osc.%s://%s:%d/", proto, s->hostname, s->port); return buf; } #ifndef WIN32 else if (s->protocol == LO_UNIX) { ret = snprintf(NULL, 0, "osc.unix:///%s", s->path); if (ret <= 0) { /* this libc is not C99 compliant, guess a size */ ret = 1023; } buf = malloc((ret + 2) * sizeof(char)); snprintf(buf, ret+1, "osc.unix:///%s", s->path); return buf; } #endif return NULL; } void lo_server_pp(lo_server s) { lo_method it; printf("socket: %d\n\n", s->sockets[0].fd); printf("Methods\n"); for (it = s->first; it; it = it->next) { printf("\n"); lo_method_pp_prefix(it, " "); } } static int lo_can_coerce_spec(const char *a, const char *b) { unsigned int i; if (strlen(a) != strlen(b)) { return 0; } for (i=0; a[i]; i++) { if (!lo_can_coerce(a[i], b[i])) { return 0; } } return 1; } static int lo_can_coerce(char a, char b) { return ((a == b) || (lo_is_numerical_type(a) && lo_is_numerical_type(b)) || (lo_is_string_type(a) && lo_is_string_type (b))); } void lo_throw(lo_server s, int errnum, const char *message, const char *path) { if (s->err_h) { (*s->err_h)(errnum, message, path); } } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/subtest.c0000644000175000000620000000427511467003724015724 0ustar stevestaff/* * Copyright (C) 2005 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #ifndef _MSC_VER #include #endif #include "lo/lo.h" int subtest_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data); int main(int argc, char *argv[]) { lo_server st = lo_server_thread_new(NULL, NULL); lo_address t; if (argc != 2) { fprintf(stderr, "Usage: subtest \n"); return 1; } lo_server_thread_add_method(st, NULL, "i", subtest_handler, NULL); lo_server_thread_start(st); t = lo_address_new_from_url(argv[1]); lo_send(t, "/subtest", "i", 0xf00); #ifdef WIN32 Sleep(4000); #else sleep(4); #endif return 0; } int subtest_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message data, void *user_data) { int i; lo_address a = lo_message_get_source(data); static char *uri = NULL; printf("subtest: got reply (%s)\n", path); if (!uri) { uri = lo_address_get_url(a); } else { char *new_uri = lo_address_get_url(a); if (strcmp(uri, new_uri)) { printf("ERROR: %s != %s\n", uri, new_uri); exit(1); } free(new_uri); } lo_send(a, "/subtest-reply", "i", 0xbaa); if (lo_address_errno(a)) { fprintf(stderr, "subtest error %d: %s\n", lo_address_errno(a), lo_address_errstr(a)); exit(1); } for (i=0; i<10; i++) { #ifdef WIN32 /* TODO: Wait time of 2.233 not easily doable in Windows */ Sleep(2); #else usleep(2233); #endif lo_send(a, "/subtest-reply", "i", 0xbaa+i); } return 0; } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/address.c0000644000175000000620000001514611467003724015657 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include #ifdef _MSC_VER #include #define snprintf _snprintf #else #include #endif #ifdef WIN32 #include #include #else #include #include #endif #include "lo_types_internal.h" #include "lo/lo.h" #include "config.h" lo_address lo_address_new_with_proto(int proto, const char *host, const char *port) { lo_address a; if(proto != LO_UDP && proto != LO_TCP && proto != LO_UNIX) return NULL; a = calloc(1, sizeof(struct _lo_address)); if(a == NULL) return NULL; a->ai = NULL; a->socket = -1; a->protocol = proto; switch(proto) { default: case LO_UDP: case LO_TCP: if (host) { a->host = strdup(host); } else { a->host = strdup("localhost"); } break; case LO_UNIX: a->host = strdup("localhost"); break; } if (port) { a->port = strdup(port); } else { a->port = NULL; } a->ttl = -1; return a; } lo_address lo_address_new(const char *host, const char *port) { return lo_address_new_with_proto(LO_UDP, host ,port); } lo_address lo_address_new_from_url(const char *url) { lo_address a; int protocol; char *host, *port, *proto; if (!url || !*url) { return NULL; } protocol = lo_url_get_protocol_id(url); if (protocol == LO_UDP || protocol == LO_TCP) { host = lo_url_get_hostname(url); port = lo_url_get_port(url); a = lo_address_new_with_proto(protocol, host, port); if(host) free(host); if(port) free(port); #ifndef WIN32 } else if (protocol == LO_UNIX) { port = lo_url_get_path(url); a = lo_address_new_with_proto(LO_UNIX, NULL, port); if(port) free(port); #endif } else { proto = lo_url_get_protocol(url); fprintf(stderr, PACKAGE_NAME ": protocol '%s' not supported by this " "version\n", proto); if(proto) free(proto); return NULL; } return a; } const char *lo_address_get_hostname(lo_address a) { if (!a) { return NULL; } return a->host; } int lo_address_get_protocol(lo_address a) { if (!a) { return -1; } return a->protocol; } const char *lo_address_get_port(lo_address a) { if (!a) { return NULL; } return a->port; } static const char* get_protocol_name(int proto) { switch(proto) { case LO_UDP: return "udp"; case LO_TCP: return "tcp"; #ifndef WIN32 case LO_UNIX: return "unix"; #endif } return NULL; } char *lo_address_get_url(lo_address a) { char *buf; int ret=0; int needquote = strchr(a->host, ':') ? 1 : 0; char *fmt; if (needquote) { fmt = "osc.%s://[%s]:%s/"; } else { fmt = "osc.%s://%s:%s/"; } #ifndef _MSC_VER ret = snprintf(NULL, 0, fmt, get_protocol_name(a->protocol), a->host, a->port); #endif if (ret <= 0) { /* this libc is not C99 compliant, guess a size */ ret = 1023; } buf = malloc((ret + 2) * sizeof(char)); snprintf(buf, ret+1, fmt, get_protocol_name(a->protocol), a->host, a->port); return buf; } void lo_address_free(lo_address a) { if (a) { if (a->socket != -1) { close(a->socket); } if (a->host) free(a->host); if (a->port) free(a->port); if (a->ai) freeaddrinfo(a->ai); free(a); } } int lo_address_errno(lo_address a) { return a->errnum; } const char *lo_address_errstr(lo_address a) { char *msg; if (a->errstr) { return a->errstr; } msg = strerror(a->errnum); if (msg) { return msg; } else { return "unknown error"; } return "unknown error"; } char *lo_url_get_protocol(const char *url) { char *protocol,*ret; if (!url) { return NULL; } protocol = malloc(strlen(url)); if (sscanf(url, "osc://%s", protocol)) { fprintf(stderr, PACKAGE_NAME " warning: no protocol specified in URL, " "assuming UDP.\n"); ret = strdup("udp"); } else if (sscanf(url, "osc.%[^:/[]", protocol)) { ret = strdup(protocol); } else { ret = NULL; } free(protocol); return ret; } int lo_url_get_protocol_id(const char *url) { if(!url) { return -1; } if(!strncmp(url, "osc:", 4)) { fprintf(stderr, PACKAGE_NAME " warning: no protocol specified in URL, " "assuming UDP.\n"); return LO_UDP; // should be LO_DEFAULT? } else if(!strncmp(url, "osc.udp:", 8)) { return LO_UDP; } else if(!strncmp(url, "osc.tcp:", 8)) { return LO_TCP; } else if(!strncmp(url, "osc.unix:", 9)) { return LO_UNIX; } return -1; } char *lo_url_get_hostname(const char *url) { char *hostname = malloc(strlen(url)); if (sscanf(url, "osc://%[^[:/]", hostname)) { return hostname; } if (sscanf(url, "osc.%*[^:/]://[%[^]/]]", hostname)) { return hostname; } if (sscanf(url, "osc.%*[^:/]://%[^[:/]", hostname)) { return hostname; } /* doesnt look like an OSC URL */ free(hostname); return NULL; } char *lo_url_get_port(const char *url) { char *port = malloc(strlen(url)); if (sscanf(url, "osc://%*[^:]:%[0-9]", port)) { return port; } if (sscanf(url, "osc.%*[^:]://%*[^:]:%[0-9]", port)) { return port; } if (sscanf(url, "osc://[%*[^]]]:%[0-9]", port)) { return port; } if (sscanf(url, "osc.%*[^:]://[%*[^]]]:%[0-9]", port)) { return port; } /* doesnt look like an OSC URL with port number */ free(port); return NULL; } char *lo_url_get_path(const char *url) { char *path = malloc(strlen(url)); if (sscanf(url, "osc://%*[^:]:%*[0-9]%s", path)) { return path; } if (sscanf(url, "osc.%*[^:]://%*[^:]:%*[0-9]%s", path) == 1) { return path; } if (sscanf(url, "osc.unix://%*[^/]%s", path) == 1) { return path; } if (sscanf(url, "osc.%*[^:]://%s", path)) { return path; } /* doesnt look like an OSC URL with port number and path*/ free(path); return NULL; } void lo_address_set_ttl(lo_address t, int ttl) { if (t->protocol == LO_UDP) t->ttl = ttl; } int lo_address_get_ttl(lo_address t) { return t->ttl; } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/src/tools/0002755000175000000620000000000011537433127015223 5ustar stevestaffnyquist-3.05/liblo/src/tools/Makefile.in0000644000175000000620000006172411515462141017272 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = oscsend$(EXEEXT) oscdump$(EXEEXT) subdir = src/tools DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_oscdump_OBJECTS = oscdump-oscdump.$(OBJEXT) oscdump_OBJECTS = $(am_oscdump_OBJECTS) oscdump_DEPENDENCIES = ../liblo.la oscdump_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(oscdump_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ am_oscsend_OBJECTS = oscsend-oscsend.$(OBJEXT) oscsend_OBJECTS = $(am_oscsend_OBJECTS) oscsend_DEPENDENCIES = ../liblo.la oscsend_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(oscsend_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(oscdump_SOURCES) $(oscsend_SOURCES) DIST_SOURCES = $(oscdump_SOURCES) $(oscsend_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = foreign SUBDIRS = . oscsend_SOURCES = oscsend.c oscsend_CFLAGS = $(LIBLO_CFLAGS) oscsend_LDADD = ../liblo.la oscdump_SOURCES = oscdump.c oscdump_CFLAGS = $(LIBLO_CFLAGS) oscdump_LDADD = ../liblo.la all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/tools/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/tools/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list oscdump$(EXEEXT): $(oscdump_OBJECTS) $(oscdump_DEPENDENCIES) @rm -f oscdump$(EXEEXT) $(oscdump_LINK) $(oscdump_OBJECTS) $(oscdump_LDADD) $(LIBS) oscsend$(EXEEXT): $(oscsend_OBJECTS) $(oscsend_DEPENDENCIES) @rm -f oscsend$(EXEEXT) $(oscsend_LINK) $(oscsend_OBJECTS) $(oscsend_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oscdump-oscdump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oscsend-oscsend.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< oscdump-oscdump.o: oscdump.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscdump_CFLAGS) $(CFLAGS) -MT oscdump-oscdump.o -MD -MP -MF $(DEPDIR)/oscdump-oscdump.Tpo -c -o oscdump-oscdump.o `test -f 'oscdump.c' || echo '$(srcdir)/'`oscdump.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/oscdump-oscdump.Tpo $(DEPDIR)/oscdump-oscdump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='oscdump.c' object='oscdump-oscdump.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscdump_CFLAGS) $(CFLAGS) -c -o oscdump-oscdump.o `test -f 'oscdump.c' || echo '$(srcdir)/'`oscdump.c oscdump-oscdump.obj: oscdump.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscdump_CFLAGS) $(CFLAGS) -MT oscdump-oscdump.obj -MD -MP -MF $(DEPDIR)/oscdump-oscdump.Tpo -c -o oscdump-oscdump.obj `if test -f 'oscdump.c'; then $(CYGPATH_W) 'oscdump.c'; else $(CYGPATH_W) '$(srcdir)/oscdump.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/oscdump-oscdump.Tpo $(DEPDIR)/oscdump-oscdump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='oscdump.c' object='oscdump-oscdump.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscdump_CFLAGS) $(CFLAGS) -c -o oscdump-oscdump.obj `if test -f 'oscdump.c'; then $(CYGPATH_W) 'oscdump.c'; else $(CYGPATH_W) '$(srcdir)/oscdump.c'; fi` oscsend-oscsend.o: oscsend.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscsend_CFLAGS) $(CFLAGS) -MT oscsend-oscsend.o -MD -MP -MF $(DEPDIR)/oscsend-oscsend.Tpo -c -o oscsend-oscsend.o `test -f 'oscsend.c' || echo '$(srcdir)/'`oscsend.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/oscsend-oscsend.Tpo $(DEPDIR)/oscsend-oscsend.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='oscsend.c' object='oscsend-oscsend.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscsend_CFLAGS) $(CFLAGS) -c -o oscsend-oscsend.o `test -f 'oscsend.c' || echo '$(srcdir)/'`oscsend.c oscsend-oscsend.obj: oscsend.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscsend_CFLAGS) $(CFLAGS) -MT oscsend-oscsend.obj -MD -MP -MF $(DEPDIR)/oscsend-oscsend.Tpo -c -o oscsend-oscsend.obj `if test -f 'oscsend.c'; then $(CYGPATH_W) 'oscsend.c'; else $(CYGPATH_W) '$(srcdir)/oscsend.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/oscsend-oscsend.Tpo $(DEPDIR)/oscsend-oscsend.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='oscsend.c' object='oscsend-oscsend.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(oscsend_CFLAGS) $(CFLAGS) -c -o oscsend-oscsend.obj `if test -f 'oscsend.c'; then $(CYGPATH_W) 'oscsend.c'; else $(CYGPATH_W) '$(srcdir)/oscsend.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(PROGRAMS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-recursive uninstall uninstall-am \ uninstall-binPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/src/tools/oscdump.c0000644000175000000620000000405411466705460017045 0ustar stevestaff/* * oscdump - Receive and dump OpenSound Control messages. * * Copyright (C) 2008 Kentaro Fukuchi * * This program 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.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * */ #include #include #include #include #include #include #include void usage(void) { printf("oscdump version %s\n" "Copyright (C) 2008 Kentaro Fukuchi\n\n" "Usage: oscdump port\n" "Receive OpenSound Control messages via UDP and dump to standard output.\n\n" "Description\n" "port : specifies the listening port number.\n\n", VERSION); } void errorHandler(int num, const char *msg, const char *where) { printf("liblo server error %d in path %s: %s\n", num, where, msg); } int messageHandler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { int i; printf("%s %s", path, types); for(i=0; i * * This program 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.1 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * TODO: * - support binary blob. * - support TimeTag. * - receive replies. */ #include #include #include #include #include #include #include #include void usage(void) { printf("oscsend version %s\n" "Copyright (C) 2008 Kentaro Fukuchi\n\n" "Usage: oscsend hostname port address types values...\n" "Send OpenSound Control message via UDP.\n\n" "Description\n" "hostname: specifies the remote host's name.\n" "port : specifies the port number to connect to the remote host.\n" "address : the OSC address where the message to be sent.\n" "types : specifies the types of the following values.\n", VERSION); printf(" %c - 32bit integer\n", LO_INT32); printf(" %c - 64bit integer\n", LO_INT64); printf(" %c - 32bit floating point number\n", LO_FLOAT); printf(" %c - 64bit (double) floating point number\n", LO_DOUBLE); printf(" %c - string\n", LO_STRING); printf(" %c - symbol\n", LO_SYMBOL); printf(" %c - char\n", LO_CHAR); printf(" %c - 4 byte midi packet (8 digits hexadecimal)\n", LO_MIDI); printf(" %c - TRUE (no value required)\n", LO_TRUE); printf(" %c - FALSE (no value required)\n", LO_FALSE); printf(" %c - NIL (no value required)\n", LO_NIL); printf(" %c - INFINITUM (no value required)\n", LO_INFINITUM); printf("values : space separated values.\n\n" "Example\n" "$ oscsend localhost 7777 /sample/address %c%c%c%c 1 3.14 hello\n", LO_INT32, LO_TRUE, LO_FLOAT, LO_STRING); } lo_message create_message(char **argv) { /* Note: * argv[1] <- hostname * argv[2] <- port * argv[3] <- OSC address * argv[4] <- types * argv[5..] <- values */ int i, argi; lo_message message; const char *types, *arg; int values; message = lo_message_new(); if(argv[4] == NULL) { /* empty message is allowed. */ values = 0; } else { types = argv[4]; values = strlen(types); } argi = 5; for(i=0; i INT_MAX || v < INT_MIN) { fprintf(stderr, "Value out of range: '%s'\n", arg); goto EXIT; } lo_message_add_int32(message, (int32_t)v); argi++; break; } case LO_INT64: { char *endp; int64_t v; v = strtoll(arg, &endp, 10); if(*endp != '\0') { fprintf(stderr, "An invalid value was given: '%s'\n", arg); goto EXIT; } if((v == LONG_MAX || v == LONG_MIN) && errno == ERANGE) { fprintf(stderr, "Value out of range: '%s'\n", arg); goto EXIT; } lo_message_add_int64(message, v); argi++; break; } case LO_FLOAT: { char *endp; float v; #ifdef __USE_ISOC99 v = strtof(arg, &endp); #else v = (float)strtod(arg, &endp); #endif /* __USE_ISOC99 */ if(*endp != '\0') { fprintf(stderr, "An invalid value was given: '%s'\n", arg); goto EXIT; } lo_message_add_float(message, v); argi++; break; } case LO_DOUBLE: { char *endp; double v; v = strtod(arg, &endp); if(*endp != '\0') { perror(NULL); fprintf(stderr, "An invalid value was given: '%s'\n", arg); goto EXIT; } lo_message_add_double(message, v); argi++; break; } case LO_STRING: lo_message_add_string(message, arg); argi++; break; case LO_SYMBOL: lo_message_add_symbol(message, arg); argi++; break; case LO_CHAR: lo_message_add_char(message, arg[0]); argi++; break; case LO_MIDI: { unsigned int midi; uint8_t packet[4]; int ret; ret = sscanf(arg, "%08x", &midi); if(ret != 1) { fprintf(stderr, "An invalid hexadecimal value was given: '%s'\n", arg); goto EXIT; } packet[0] = (midi>>24) & 0xff; packet[1] = (midi>>16) & 0xff; packet[2] = (midi>> 8) & 0xff; packet[3] = midi & 0xff; lo_message_add_midi(message, packet); argi++; break; } case LO_TRUE: lo_message_add_true(message); break; case LO_FALSE: lo_message_add_false(message); break; case LO_NIL: lo_message_add_nil(message); break; case LO_INFINITUM: lo_message_add_infinitum(message); break; default: fprintf(stderr, "Type '%c' is not supported or invalid.\n", types[i]); goto EXIT; break; } } return message; EXIT: lo_message_free(message); return NULL; } int main(int argc, char **argv) { lo_address target; lo_message message; int ret; if(argc < 4) { usage(); exit(1); } if(argv[1] == NULL) { fprintf(stderr, "No hostname is given.\n"); exit(1); } if(argv[2] == NULL) { fprintf(stderr, "No port number is given.\n"); exit(1); } target = lo_address_new(argv[1], argv[2]); if(target == NULL) { fprintf(stderr, "Failed to open %s:%s\n", argv[1], argv[2]); exit(1); } if(argv[3] == NULL) { fprintf(stderr, "No path is given.\n"); exit(1); } message = create_message(argv); if(message == NULL) { fprintf(stderr, "Failed to create OSC message.\n"); exit(1); } ret = lo_send_message(target, argv[3], message); if(ret == -1) { fprintf(stderr, "An error occured: %s\n", lo_address_errstr(target)); exit(1); } return 0; } nyquist-3.05/liblo/src/tools/Makefile.am0000644000175000000620000000037211466705460017262 0ustar stevestaffAUTOMAKE_OPTIONS = foreign SUBDIRS = . bin_PROGRAMS = oscsend oscdump oscsend_SOURCES = oscsend.c oscsend_CFLAGS = $(LIBLO_CFLAGS) oscsend_LDADD = ../liblo.la oscdump_SOURCES = oscdump.c oscdump_CFLAGS = $(LIBLO_CFLAGS) oscdump_LDADD = ../liblo.la nyquist-3.05/liblo/src/tools/README0000644000175000000620000000374111466705460016111 0ustar stevestaffoscsend and oscdump 1.0.0 - Send/receive OpenSound Control messages. GENERAL INFORMATION =================== oscsend and oscdump are OpenSound Control (OSC) tools using liblo. oscsend sends an OSC message specified by command line arguments, while oscdump receives OSC messages and prints to standard output. Both tools uses UDP for networking. INSTALL ======= Requirements ------------ Liblo is required to compile oscsend and oscdump. See http://liblo.sourceforge.net/ Compile & install ----------------- Just try ./configure make make install This compiles and installs oscsend and oscdump to the appropriate directories. By default, /usr/local/bin. You can change the destination directory by passing some options to the configure script. Run "./configure --help" to see the list of options. USAGE ===== Please invoke the command without any arguments to show usage. Oscsend and oscdump are incompatible with Matt Wright's well known tools, sendOSC and dumpOSC. LICENSING INFORMATION ===================== Copyright (C) 2008 Kentaro Fukuchi This program 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.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public Licensealong with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. CONTACTS ======== Visit the homepage at: http://megaui.net/fukuchi/works/oscsend/index.en.html Please mail any bug reports, suggestions, comments and questions to Kentaro Fukuchi . Questions of license compliance are also welcome. nyquist-3.05/liblo/src/lo_internal.h0000644000175000000620000000350311466705460016544 0ustar stevestaff#ifndef LO_INTERNAL_H #define LO_INTERNAL_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /** * \brief Validate raw OSC string data. Where applicable, data should be * in network byte order. * * This function is used internally to parse and validate raw OSC data. * * Returns length of string or < 0 if data is invalid. * * \param data A pointer to the data. * \param size The size of data in bytes (total bytes remaining). */ ssize_t lo_validate_string(void *data, ssize_t size); /** * \brief Validate raw OSC blob data. Where applicable, data should be * in network byte order. * * This function is used internally to parse and validate raw OSC data. * * Returns length of blob or < 0 if data is invalid. * * \param data A pointer to the data. * \param size The size of data in bytes (total bytes remaining). */ ssize_t lo_validate_blob(void *data, ssize_t size); /** * \brief Validate raw OSC bundle data. Where applicable, data should be * in network byte order. * * This function is used internally to parse and validate raw OSC data. * * Returns length of bundle or < 0 if data is invalid. * * \param data A pointer to the data. * \param size The size of data in bytes (total bytes remaining). */ ssize_t lo_validate_bundle(void *data, ssize_t size); /** * \brief Validate raw OSC argument data. Where applicable, data should be * in network byte order. * * This function is used internally to parse and validate raw OSC data. * * Returns length of argument data or < 0 if data is invalid. * * \param type The OSC type of the data item (eg. LO_FLOAT). * \param data A pointer to the data. * \param size The size of data in bytes (total bytes remaining). */ ssize_t lo_validate_arg(lo_type type, void *data, ssize_t size); #endif nyquist-3.05/liblo/test-client/0002755000175000000620000000000011537433127015527 5ustar stevestaffnyquist-3.05/liblo/test-client/osc-test-client.vcproj0000644000175000000620000001077111512143043021761 0ustar stevestaff nyquist-3.05/liblo/test-client/README.txt0000644000175000000620000000056611466705460017235 0ustar stevestafftest-client sends OSC messages to Nyquist. The default behavior is to generate a low frequency triangle that simulates ramping slider 0 up and down. On the Mac, you build this with the osc-test-client target in Xcode. You can find the executable in: nyquist/macosxproject/build/Development/osc-test-client and you can run this from a terminal window (or with Xcode) nyquist-3.05/liblo/test-client/test-client.c0000644000175000000620000000347111466705460020134 0ustar stevestaff/* * test-client.c -- Roger Dannenberg, 2006 * * based on example_client.c by Steve Harris, Uwe Koloska * * Usage: test-client [mode], where mode is: * h -- help * ? -- help * t -- triangle (up/down ramp), default behavior * i -- interactive, type returns to advance */ #include #include #ifdef WIN32 #define usleep(x) Sleep((x)/1000) #else #include #endif #include "lo/lo.h" int main(int argc, char *argv[]) { /* an address to send messages to. sometimes it is better to let the server * pick a port number for you by passing NULL as the last argument */ lo_address t = lo_address_new(NULL, "7770"); char mode = 't'; float x = 0.0; float delta = 0.1; int n = 0; /* slider number */ if (argc == 2) { mode = argv[1][0]; if (mode == '?' || mode == 'h' || (mode != 'i' && mode != 't')) { printf("usage: test-client [?hti]\n"); printf(" default (t) is triangle, (i)nteractive sends msg after each return\n"); exit(1); } } printf("lo_address_new done\n"); /* send messages to /slider with two arguments, report any * errors */ while (1) { if (lo_send(t, "/slider", "if", n, x) == -1) { printf("OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t)); break; } else { printf("/slider %d %g\n", n, x); } x = x + delta; if (x > 1.0 - delta * 0.5) { x = 1.0; delta = -delta; } else if (x < -delta * 0.5) { x = 0.0; delta = -delta; } if (mode == 'i') { while (getchar() != '\n') ; } else { usleep(100000); } } printf("done calling lo_send\n"); return 0; } nyquist-3.05/liblo/aclocal.m40000644000175000000620000010711511515462141015131 0ustar stevestaff# generated automatically by aclocal 1.11.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, [m4_warning([this file was generated for autoconf 2.68. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 10 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 8 # AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) nyquist-3.05/liblo/m4/0002755000175000000620000000000011537433127013614 5ustar stevestaffnyquist-3.05/liblo/m4/ltoptions.m40000644000175000000620000002724211515462141016110 0ustar stevestaff# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [0], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) nyquist-3.05/liblo/m4/lt~obsolete.m40000644000175000000620000001311311515462141016417 0ustar stevestaff# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 4 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) nyquist-3.05/liblo/m4/libtool.m40000644000175000000620000077341111515462141015527 0ustar stevestaff# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 56 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl _LT_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\[$]0 --fallback-echo"')dnl " lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` ;; esac _LT_OUTPUT_LIBTOOL_INIT ]) # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) cat >"$CONFIG_LT" <<_LTEOF #! $SHELL # Generated by $as_me. # Run this file to recreate a libtool stub with the current configuration. lt_cl_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2008 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. if test "$no_create" != yes; then lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) fi ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_XSI_SHELLFNS sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES # -------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(whole_archive_flag_spec, $1)='' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX # ----------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl AC_LINK_IFELSE(AC_LANG_PROGRAM,[ lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. m4_defun([_LT_PROG_ECHO_BACKSLASH], [_LT_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac ECHO=${lt_ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF [$]* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(lt_ECHO) ]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that does not interpret backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [AC_CHECK_TOOL(AR, ar, false) test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1]) AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line __oline__ "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[[3-9]]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method == "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC*) # IBM XL 8.0 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE(int foo(void) {}, _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' ) LDFLAGS="$save_LDFLAGS" else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then _LT_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], [[If ld is used when linking, flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [fix_srcfile_path], [1], [Fix the shell variable $srcfile for the compiler]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_PROG_CXX # ------------ # Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ # compiler, we have our own version here. m4_defun([_LT_PROG_CXX], [ pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) AC_PROG_CXX if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_CXX dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_CXX], []) # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [AC_REQUIRE([_LT_PROG_CXX])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 will use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; xl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=echo else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ]) dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_PROG_F77 # ------------ # Since AC_PROG_F77 is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_F77], [ pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) AC_PROG_F77 if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_F77 dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_F77], []) # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_REQUIRE([_LT_PROG_F77])dnl AC_LANG_PUSH(Fortran 77) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${F77-"f77"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_PROG_FC # ----------- # Since AC_PROG_FC is broken, in that it returns the empty string # if there is no fortran compiler, we have our own version here. m4_defun([_LT_PROG_FC], [ pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) AC_PROG_FC if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi popdef([AC_MSG_ERROR]) ])# _LT_PROG_FC dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([_LT_PROG_FC], []) # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_REQUIRE([_LT_PROG_FC])dnl AC_LANG_PUSH(Fortran) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC CC=${FC-"f95"} compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC="$lt_save_CC" ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC GCC= CC=${RC-"windres"} compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC="$lt_save_CC" ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_XSI_SHELLFNS # --------------------- # Bourne and XSI compatible variants of some useful shell functions. m4_defun([_LT_PROG_XSI_SHELLFNS], [case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $[*] )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } dnl func_dirname_and_basename dnl A portable version of this function is already defined in general.m4sh dnl so there is no need for it here. # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[[^=]]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$[@]"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]+=\$[2]" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$[1]=\$$[1]\$[2]" } _LT_EOF ;; esac ]) nyquist-3.05/liblo/m4/ltsugar.m40000644000175000000620000001042411515462141015530 0ustar stevestaff# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) nyquist-3.05/liblo/m4/ltversion.m40000644000175000000620000000127711515462141016102 0ustar stevestaff# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # Generated from ltversion.in. # serial 3017 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.2.6b]) m4_define([LT_PACKAGE_REVISION], [1.3017]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.2.6b' macro_revision='1.3017' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) nyquist-3.05/liblo/TODO0000644000175000000620000000061211467003724013757 0ustar stevestaff* Full bundle support [needs NTP, argh], find budle timestamp delivery artimetic bug * More/better regression tests * More/better example code * Normalise URI handling [needs discussion] * GTK/Qt/etc. linking code [belongs in another library] * Rendevous/OpenWhatever (eg. howl) service discovery [low priority] * Think about a JACK transport layer [maybe^W probably not, low priority] nyquist-3.05/liblo/README.txt0000644000175000000620000000436211466705460015000 0ustar stevestaffREADME.txt -- notes on installing liblo into Nyquist Roger B. Dannenberg Feb, 2009 To help manage version skew problems, the Nyquist sources include a copy of Liblo sources. This additional file contains notes on how to integrate Liblo into Nyquist. Note that Liblo has an LGPL license. To distribute Nyquist binaries without sources, you may have to deal with Liblo licensing restrictions. How to install and build Liblo. On OS X (all of these steps should be unnecessary if you simply obtain Nyquist sources from CVS and build with Xcode) 1. Download liblo source tree to a scratch directory. 2. Copy the entire source tree from scratch to nyquist/liblo 3. Don't forget to keep the following files and directories in nyquist/liblo: README.txt (this file) ser-to-osc (a directory) test-client (a directory) 4. In the scratch directory, run "sh autogen.sh" 5. Make nyquist/liblo/osx 6. Copy scratch/config.h to nyquist/liblo/osx/config.h 7. Make sure the following are on search paths in Xcode: liblo, liblo/src, liblo/osx 8. NOTE: Xcode will include any .h file that is in the project sources, so remove all config.h files from the source tree, including those in nylsf, if any. 9. The liblo sources include , but unless you have installed sources to a system include path, this will not be found. Solution: check the Always Search User Path option in the target preferences for all configuration. 10. Add HAVE_CONFIG_H to Preprocessor Macros in All Configurations 11. Some files in liblo that do NOT belong in the liblo library: subtest.c 12. Note that Serial.cpp is windows only. Don't put it in the ser-to-osc target. 13. It should now build under Xcode. On Linux: (all of these steps should be unnecessary if you simply obtan Nyquist sources from CVS and build with Xcode) 1. Download liblo source tree to a scratch directory 2. Copy the entire source tree from scratch to nyquist/liblo 3. Don't forget to keep the following files and directories in nyquist/liblo: README.txt (this file) ser-to-osc (a directory) test-client (a directory) 4. In nyquist/liblo, run "sh autogen.sh --enable-static --disable-shared" 5. Run make nyquist-3.05/liblo/Makefile.in0000644000175000000620000006035311515462141015340 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(srcdir)/liblo.pc.in $(top_srcdir)/configure AUTHORS COPYING \ ChangeLog INSTALL NEWS TODO compile config.guess config.sub \ depcomp install-sh ltmain.sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = liblo.pc CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(pkgconfigdir)" DATA = $(pkgconfig_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir dist dist-all distcheck ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d "$(distdir)" \ || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr "$(distdir)"; }; } am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src examples lo build @DOXYGEN@ EXTRA_DIST = libtool ltmain.sh autogen.sh ACLOCAL_AMFLAGS = -I m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = liblo.pc all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then \ rm -f stamp-h1; \ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 liblo.pc: $(top_builddir)/config.status $(srcdir)/liblo.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @$(am__cd) '$(distuninstallcheck_dir)' \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-pkgconfigDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-pkgconfigDATA .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-pkgconfigDATA install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-pkgconfigDATA test: all (cd src && make test) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/liblo.pc.in0000644000175000000620000000035011466705460015325 0ustar stevestaffprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: liblo Version: @PACKAGE_VERSION@ Description: A lightweight OSC server/client library Libs: -L${libdir} -llo -lpthread Cflags: -I${includedir} nyquist-3.05/liblo/INSTALL0000644000175000000620000002203011466705460014323 0ustar stevestaffCopyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. 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, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) 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 you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' 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 awhile. 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. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. 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 support 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/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' 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. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. 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' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS 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 machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. 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. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. nyquist-3.05/liblo/config.sub0000755000175000000620000010224011515462141015246 0ustar stevestaff#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2009-04-17' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nyquist-3.05/liblo/doc/0002755000175000000620000000000011537433127014041 5ustar stevestaffnyquist-3.05/liblo/doc/reference.doxygen0000644000175000000620000012515711467004266017407 0ustar stevestaff# Doxyfile 1.3.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = liblo # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.26 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper # language. The default language is English, other supported languages # are: Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, # Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Norwegian, Polish, Portuguese, Romanian, Russian, Serbian, # Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = NO # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = NO # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = NO #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../lo/lo.h ../lo/lo_types.h ../lo/lo_osc_types.h ../lo/lo_lowlevel.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are # excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = . # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output dir. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = YES # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = A4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are # alone on a line, have an all uppercase name, and do not end with a # semicolon. Such function macros are typically used for boiler-plate # code, and will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes # with base or super classes. Setting the tag to NO turns the diagrams # off. Note that this option is superceded by the HAVE_DOT option # below. This is only a fallback. It is recommended to install and use # dot, since it yields more powerful graphs. CLASS_DIAGRAMS = NO # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similiar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of # the graphs generated by dot. A depth value of 3 means that only # nodes reachable from the root by following a path via at most 3 # edges will be shown. Nodes that lay further from the root node will # be omitted. Note that setting this option to 1 or 2 may greatly # reduce the computation time needed for large code bases. Also note # that a graph may be further truncated if the graph's image # dimensions are not sufficient to fit the graph (see # MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the # depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO nyquist-3.05/liblo/doc/Makefile.in0000644000175000000620000002441111515462141016100 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/reference.doxygen.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = reference.doxygen CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in CLEANFILES = doxygen-build.stamp DOX = reference.doxygen EXTRA_DIST = INSTIMAGES = html/doxygen.png DOC_STAMPS = html-build.stamp DOC_DIR = $(HTML_DIR) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): reference.doxygen: $(top_builddir)/config.status $(srcdir)/reference.doxygen.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile all-local installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am all-local check check-am clean clean-generic \ clean-libtool clean-local distclean distclean-generic \ distclean-libtool distclean-local distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am all-local: doxygen-build.stamp doxygen-build.stamp: $(DOX) ../lo/lo.h ../lo/lo_types.h ../lo/lo_lowlevel.h \ ../lo/lo_osc_types.h @echo '*** Running doxygen ***' doxygen $(DOX) touch doxygen-build.stamp clean-local: rm -f *~ *.bak $(DOC_STAMPS) || true if test -d html; then rm -fr html; fi if test -d latex; then rm -fr latex; fi if test -d man; then rm -fr man; fi distclean-local: clean rm -f *.stamp || true if test -d html; then rm -rf html; fi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/doc/reference.doxygen.in0000644000175000000620000012524411466705460020014 0ustar stevestaff# Doxyfile 1.3.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = liblo # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @PACKAGE_VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper # language. The default language is English, other supported languages # are: Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, # Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Norwegian, Polish, Portuguese, Romanian, Russian, Serbian, # Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = NO # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = NO # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = NO # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = NO #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @top_srcdir@/lo/lo.h @top_srcdir@/lo/lo_types.h @top_srcdir@/lo/lo_osc_types.h @top_srcdir@/lo/lo_lowlevel.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are # excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = . # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output dir. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = YES # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = A4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are # alone on a line, have an all uppercase name, and do not end with a # semicolon. Such function macros are typically used for boiler-plate # code, and will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes # with base or super classes. Setting the tag to NO turns the diagrams # off. Note that this option is superceded by the HAVE_DOT option # below. This is only a fallback. It is recommended to install and use # dot, since it yields more powerful graphs. CLASS_DIAGRAMS = NO # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similiar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of # the graphs generated by dot. A depth value of 3 means that only # nodes reachable from the root by following a path via at most 3 # edges will be shown. Nodes that lay further from the root node will # be omitted. Note that setting this option to 1 or 2 may greatly # reduce the computation time needed for large code bases. Also note # that a graph may be further truncated if the graph's image # dimensions are not sufficient to fit the graph (see # MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the # depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO nyquist-3.05/liblo/doc/Makefile.am0000644000175000000620000000127711466705460016105 0ustar stevestaff## Process this file with automake to produce Makefile.in MAINTAINERCLEANFILES=Makefile.in CLEANFILES=doxygen-build.stamp DOX=reference.doxygen EXTRA_DIST= INSTIMAGES=html/doxygen.png DOC_STAMPS=html-build.stamp DOC_DIR=$(HTML_DIR) all-local: doxygen-build.stamp doxygen-build.stamp: $(DOX) ../lo/lo.h ../lo/lo_types.h ../lo/lo_lowlevel.h \ ../lo/lo_osc_types.h @echo '*** Running doxygen ***' doxygen $(DOX) touch doxygen-build.stamp clean-local: rm -f *~ *.bak $(DOC_STAMPS) || true if test -d html; then rm -fr html; fi if test -d latex; then rm -fr latex; fi if test -d man; then rm -fr man; fi distclean-local: clean rm -f *.stamp || true if test -d html; then rm -rf html; fi nyquist-3.05/liblo/build/0002755000175000000620000000000011537433130014365 5ustar stevestaffnyquist-3.05/liblo/build/Makefile.in0000644000175000000620000002265211515462141016437 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = build DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = config-msvc.h lo_endian-msvc.h premake4.exe premake4.lua all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu build/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/build/vs2008/0002755000175000000620000000000011537433130015327 5ustar stevestaffnyquist-3.05/liblo/build/vs2008/testlo.vcproj0000644000175000000620000002067011515366753020105 0ustar stevestaff nyquist-3.05/liblo/build/vs2008/config-msvc.h0000644000175000000620000000507211515366753017731 0ustar stevestaff/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define this to enable ipv6. */ /* #undef ENABLE_IPV6 */ /* Define to 1 if you have the header file. */ /* #undef HAVE_DLFCN_H */ /* Define to 1 if inet_aton() is available. */ /* #undef HAVE_INET_ATON */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `pthread' library (-lpthread). */ /* #undef HAVE_LIBPTHREAD */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_NETDB_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_NETINET_IN_H */ /* Define to 1 if poll() is available. */ /* #undef HAVE_POLL */ /* Define to 1 if select() is available. */ #define HAVE_SELECT 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_SOCKET_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* If machine is bigendian */ #define LO_BIGENDIAN "0" /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "liblo" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "liblo-devel@lists.sourceforge.net" /* Define to the full name of this package. */ #define PACKAGE_NAME "liblo" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "liblo " /*VERSION*/ /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "liblo" /* Define to the version of this package. */ #define PACKAGE_VERSION /*VERSION*/ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION /*VERSION*/ /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ nyquist-3.05/liblo/build/vs2008/subtest.vcproj0000644000175000000620000002070311515366753020261 0ustar stevestaff nyquist-3.05/liblo/build/vs2008/config.h0000644000175000000620000000014211515366753016754 0ustar stevestaff// for windows compilation, here is a special config file and location #include "config-msvc.h" nyquist-3.05/liblo/build/vs2008/liblo.suo0000644000175000000620000003200011515366753017165 0ustar stevestaffࡱ>  Root Entry`̞ProjInfoExTaskListUserTasks$VsToolboxService" yjkD+}ϫC BC:\Users\rbd\liblo\build\vs2008\C:\Program Files\MicrosoDebuggerWatches DebuggerBreakpoints(NDebuggerExceptions& DebuggerFindSource&&ft Visual Studio 9.0\Common7\IDE\vc7\atlmfcC:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\vc7\crtDebuggerFindSymbol&DebuggerMemoryWindows, TExternalFilesProjectContents:DocumentWindowPositions0 DocumentWindowUserData. SolutionConfiguration,`ObjMgrContentsV8"ClassViewContents$MultiStartupProj=;4{FEA9DQ ZC:\Users\rbd\liblo\build\vs2008\liblo.vcproj^C:\Users\rbd\liblo\build\vs2008\subtest.vcproj\C:\Users\rbd\liblo\build\vs2008\testlo.vcprojeleaseLWin32.BatchBldCtx=Release$Bookmarks V001.013-46BD-594F-ProjExplorerState$2UnloadedProjects"HiddenSlnFolders"OutliningStateDir$BookmarkState(TaskListShortcuts$OutliningState8 X fBatchBld=;4{2E13DBE4-57 `ABF0-B99D9FBC74C2}.dwStartupOpt=;D{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseLib|Win32.BatchBldCtx=ReleaseLib|Win32;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseLib|Win32.fBatchBld=;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugLib|Win32.BatchBldCtx=DebugLib|Win32;@{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugLib|Win32.fBatchBld=;D{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseDLL|Win32.BatchBldCtx=ReleaseDLL|Win32;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseDLL|Win32.fBatchBld=;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugDLL|Win32.BatchBldCtx=DebugDLL|Win32;@{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugDLL|Win32.fBatchBld=;4{5B596F11-654F-314A-9453-75C9759AB591}.dwStartupOpt=;D{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseLib|Win32.BatchBldCtx=ReleaseLib|Win32;B{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseLib|Win32.fBatchBld=;B{5B596F11-654F-314A-9453-75C9759AB591}.DebugLib|Win32.BatchBldCtx=DebugLib|Win32;@{5B596F11-654F-314A-9453-75C9759AB591}.DebugLib|Win32.fBatchBld=;D{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseDLL|Win32.BatchBldCtx=ReleaseDLL|Win32;B{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseDLL|Win32.fBatchBld=;BMultiStartupProj=;4{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.dwStartupOpt=;StartupProject=&{FEA9D5D3-46BD-594F-85C6-F1380FD994A6};D{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseLib|Win32.BatchBldCtx=ReleaseLib|Win32;B{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseLib|Win32.fBatchBld=;B{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugLib|Win32.BatchBldCtx=DebugLib|Win32;@{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugLib|Win32.fBatchBld=;D{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseDLL|Win32.BatchBldCtx=ReleaseDLL|Win32;B{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseDLL|Win32.fBatchBld=;B{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugDLL|Win32.BatchBldCtx=DebugDLL|Win32;@{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugDLL|Win32.fBatchBld=;4{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.dwStartupOpt=;D{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseLib|Win32.BatchBldCtx=ReleaseLib|Win32;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseLib|Win32.fBatchBld=;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugLib|Win32.BatchBldCtx=DebugLib|Win32;@{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugLib|Win32.fBatchBld=;D{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseDLL|Win32.BatchBldCtx=ReleaseDLL|Win32;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.ReleaseDLL|Win32.fBatchBld=;B{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugDLL|Win32.BatchBldCtx=DebugDLL|Win32;@{2E13DBE4-5FCA-9946-ABF0-B99D9FBC74C2}.DebugDLL|Win32.fBatchBld=;4{5B596F11-654F-314A-9453-75C9759AB591}.dwStartupOpt=;D{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseLib|Win32.BatchBldCtx=ReleaseLib|Win32;B{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseLib|Win32.fBatchBld=;B{5B596F11-654F-314A-9453-75C9759AB591}.DebugLib|Win32.BatchBldCtx=DebugLib|Win32;@{5B596F11-654F-314A-9453-75C9759AB591}.DebugLib|Win32.fBatchBld=;D{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseDLL|Win32.BatchBldCtx=ReleaseDLL|Win32;B{5B596F11-654F-314A-9453-75C9759AB591}.ReleaseDLL|Win32.fBatchBld=;B{5B596F11-654F-314A-9453-75C9759AB591}.DebugDLL|Win32.BatchBldCtx=DebugDLL|Win32;@{5B596F11-654F-314A-9453-75C9759AB591}.DebugDLL|Win32.fBatchBld=; ActiveCfg=DebugDLL|Win32;nyquist-3.05/liblo/build/vs2008/liblo.vcproj0000644000175000000620000001213211515366753017666 0ustar stevestaff nyquist-3.05/liblo/build/premake4.exe0000644000175000000620000062100011467004266016603 0ustar stevestaffMZ@ !L!This program cannot be run in DOS mode. $PELOI 8F`@`o" P .textDF``.data`J@.rdatapL@@.bss@.idata P @U]U1ۉu1=wC=r[$1҉T$T=tzt$л؋u]]=twJ=t؋u]]=t[=u$1t$<tjt$=$L$<v7l$ 1ɉL$<t0R$ ?$D$l<%$ \$R< 'US$]$@Ab6]7E@CU\$ `AD$T$L$ $@C<0@Ctc`ARCt 0@CD$RCK0 $;RCt&0@C\$ RCQP$;t&';`A~5V;L$@CT$@C$";$@D$RCB$E;RCJv'U$RC&U$RC&U RC]t&U RC]ᐐU]7UVuSjjVPV@ uVaShpAVO jVe[^]ÐUW}VSjjW]jjWQjPS@uWVh0pAW jWe[^_]ÐU@S"9Sh@?1҅t-t8\u/@8Pu]ÐUS0]jjS 8ujEPR$9YZu E%@PjSX]ZÐUEЃ0Pu8Z1҅Yu UɉUS]jjSP$S]ÐUW}VSjjWhH9Í@PV>SWCle[^_]USju ZËYtPy>S8]1US]jS 4PS ]US]jS @PS]UVuSjVd X1;Zt913jV${uCP3=t؀{4.Cu܍e[^]ÐUVuSjjVjP= uVo ShPpAV]  jV"e[^]UWVSV}EuWVY[juWLà j;S7^Zt)PSWC S1Wr Y[jWhppAW] jWjW jjW2 PZtjW ,jWY[t CrEW9EZ<1e[^_]ÐUVuSjjV~P< uV1 ShpAV  jV e[^]ÐUS@=@CuhpAV<hpAP[<@CE]P@CEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPhpAS5HSu ]ÐUWVSj=R5Y[t/)~SVwP5Ƅ+ VqAP5XZVj Sj hqASn5u >t5 @Ce1[^_]UW}VS0w#P袀hqAhrAShrAS h-rAhS $h8rAS h)@VYGuVF;BrBe[^_]UVu S]PjSw^PSFBSJKBCAPSjPSWWe[^]UPPE jUEEEB+B PEPh)@ROYUWVS u}uCu]u SWiVSWgZe[^_]UMQzu"Bxujuu BpQ?]UE]@UU W}EV1S_w$CC@rCDC@jW5mXasD YsDNSD 9w)K@4C@9S@w(Wl{XtCD9C@sPCP sTCTe[^_]UuK1UU S]USR0S ‹CtC]UVuS] ~4VB@9BDrVkXF+F HPSVF)؃F!u ^jhCVDFC e[^]UU MtA@]A@ UEPEBE B ]US]SB@9BDrSNkXPu SSCB]U1ɉVuSxuGyt~$A9DC#ҋY~;S$~1D@CL[^]UWVSR}U URUƅXt]OSCQAOe[^_]UWVSSSU EUǍEP3EYtDE]pNVHFSACy~VBt@t RPuj Ee[^_]ÐUVuSp]Vu S= t(VhCSEE ~PEPhCS] jhCSe[^]UVuS]jSVu SjShSe[^]UWVuSp}V] jW = u uShC.VhCWEhCu}uKuuuhCWm}uE9CuuSh;CWLe[^_]UWVS} ]uWSZYPSZYPVhYCS]E} ]e[^_]0UVSuPZYPVSe[^]UVu S]VhSdjS61҅u+jSejjS jSVhSe[^]UWVu S]VS8DžXZt8VSZYt+uhSjjSt jS uVS1e[^_]UVS]uu SYZuuE mC]e[^]e[^]UWVSu }]VWCY9Zt]e[^_]e[^_]UVuS] SVY@ZuhCSV e[^]UW}Vu SuVW/ u jSYe[^_]UWVSSE} u]EWPZYt/1t эA]E} Ee[^_]ue[^_]UWVSSSE}EE EEtjPuutjuu- 1?tS4ZYt3F<ShCuEE E EEe[^_]e[^_]UVSQQ] uSVnX]EZuzSVZYu j^Ee[^]UVSSS] uE]SVfZY~] ue[^]Ee[^]UWVuS] SV DžXZuSVZYu j^e[^_]UWVS] u}SVYZ~] ue[^_]뗍e[^_]US]u SYZ1҅t9uSjS&jSu jS1 jS]UW}Vu S'='w WY\0uSWx 1҅tSWjjWe[^_]UE U@PP ]UWVuS]u VXZj.S6Y_u߃1э|)PSVjV9jVuBjV?.EuPjV)PSV jVLjVTjVfYZt jVj_V?.XZJ1e[^_]UWVSPP] Euۋ}EE8tEjhChVSjV jV$tAjV uShVtShCV1 jVqSjVjVPVKU:tC~PV6YKXuWEpVKUG2PVOEE8뻉u׉} e[^_]_Ujuu uU1҉VS) tP^ Sv Fe[^]US]ssC]UWVS x~jExjWMYXE@EPW9ZFZE+E@ 9 ШtEˉEE9E|uWWF+E@FXZe[^_]US]tdC []UW}Vu S]Kt 9rWXFݍe[^_]U1WU IQRu}UW1VS}u 򮍅IPu^[_!)PVWauW4uVZYuVWhWajju}e[^_]UEWVSQ]sPjV\ lj؋U ) 9wRWQEjV t jVXZC e[^_]UW}VS] '='w W^tjWY[u jWNjVWjWMjWtSVWjVW VWCXZSVW؍e[^_]UWVSQE}] ExR'='w W ZtjVWuVWuWE u }e[^_]e[^_]UM VuS9tC+Q1B u RYhjSu1҉Ѝe[^]UWVSS0\juSV@PWhCS$uSe[^_]UWVSuV&Dž@} XujhCVRC 8u hCVhCu uClBHBx @ R_#ucDžBHBx @ R[t u u$BHBx @ R\Y1҃} …thhCu  uCBHBx @ RZtuDžQbjjV PPh8@VNjX } tPXt ViCVe[^_]U1M QtEA]UPPE uEEEEPh;@u`UWU 1RIQRu}UEU t E UGR1Ujju PRChC@P1USjh<@蝹YÅXt h3<@S XZ؋]ÐUWVSQ]S/huChSE;}mjSWSjjS)jjS(u hxCS4F~RC Pj XZRCG PVjS뎡RC Pj 1e[^_]UWVSVuj jV@ u*jVjVjVY[jjVǍC "vhCjV SEPW_ ;}tT@EERC8uRCP jRG_ZEuˀ8u1RS,$$VsVSe[^_]UVS]jjSWjSjSt~VShjSjS@]e[^]US]jSjS0uS hCjS]UVuSjVjjVjƒ ШuhCjVZ hCjV t hCVXZjVjVe[^]UWVSpjPMZYu jS_XtjjS" jSY^yhCjS }WVS+ uhCjS Wh$CS3jSuVh&CSD e[^_]US]>jSZYt hSXjS[]XUS]jjS1҉jS jSt1jSXZuzSjSjS1.jS?ZYujSZYu hXCSn[X]US]jSjSjjS PSR]US]jjS=jSljSjS]US]jjS jS9jS1jS$jS]US]jjSF PS!]UW}VShChCjWjjWP4CWƋC(tt#*jjWV$$$ CVW=V$$Wue[^_]US]jSLjSfYZPS|YZPS]US]jjSjSqjSu S]US]jjShSjSS]UVuSjVjCjVaSVSjV\(jVYЃ[e[^]US]jjS"hSAjS9jSf]U҉SøtSjS]UEVSV]PjS%jPjSMPuVS"ƒe[^]US]jjjSPSZ‰Y]mUVS]uhCjSjStjjS jSYZu=jSYZt"jSXZuE ]e[^]h*CS[^e1[^]UVS]jhOCjScjjSjSO$VjhC@Se‰[^]UWVuSjjjVVSVtVYjjV Ve)[^_]US]jSmjSt ]]jhWCjSPhiCS]UWVSjjujju)ju$ZY ju ju^1_9@)؍x~WuZYuhlCu]Sju|؃ C9|e[^_]UW}VSWjW u#jjW 8#uFPW2jW"ÅXZy9~hCjW )؍e[^_]US]jSjjSNH$SPS jSYX]]US]jSjSjSjjjSp(PSQjS]]US]jShhCjSjSjZYt.tK[ttOjjS P#jSjSUZCYuCRSt[X?jhCS& -jSZYPjSZYPSZYPhCS]UVuSjVjVgjVjV[HZu*jjVujVPjVhV$LjVZYt$hVjVnjV|uhCjV jVH[XjV[e[^]USӃp19tDSZt Ht1*EPjS" SY҃B]UVuSjVYÅXuhCjV@ ډu4CVe[^]UWVSMuWdZYu hCVYXt4ChCV]uWVWVuW!9w2W$Í@PV u h CV]XZSVWN jVWAe[^_]UVuSjV!ÅXZuhCjVH VHډ$ÅXyjV jV-jCVPV؍e[^]UVuShVVS$ډ y0jVZYtjV$jVjVVYe[^]UVS]SjS ujSZYth;CjSS jSajVSe[^]US]SjhfJ@SY]US]Sy$S7]US]S ZtS[]UVSju PjuSVjSe[^]US]hSYXhQChS hChQCS jhTCS h\ChS غeChB@hC@^XZlCh[B@hB@FYXjjSA jSXZjSYXjhrCSP huCjS, jhG@S h|ChS hpChCS]ÐU1҉8uxuxu]UVS]@ )Ӎ4C1)=~hCq \XZ? ‰e[^]UUBB]U@ -tL]UWVSu}E t-u0 Éډuuډ[^_]@[^_]Uҋ@ ~A?*CyA]UVSӃt'ډ?tډ?1[^]UV1S]Ѓ?u@t9t?? ډ Ѓ[^]UVSӃthډYډߍe[^]UWVSӃt2ډu ډljFZtuuډ [ɍe[^_]US]S=u C PSa]UEMU ;Hu]͉ME M]qUVuS^$] @K9~~hCv YYXXKe[^]UVu S]VSs$e[^]Uu @29|I$]U: u]R]UWVS @RvEP? x{(u!}E fEm]mEF(@F(@;C(~!hCC(hjPsumC;{(}SDG;{(|F(}COWHP~@tCt PSuH V(BF(Ѝe[^_]UEM UREMUE EEUR]UWVSPEu }E u$^H E@?% ‰RuM^H E@ ‰^G$%?? ‰E }X[^_]X[^_]UES]  u S@ %C#u KP % []UR?u@]UEHE RD]UWVS0ËP php}C C @;F,~!hCF,hjPv s~kF CV [uvFPW V;VEEuVt=> t WYjUjkjUjEZSWEWuËVuPxuVuSgFEF Fe[^_]UVSu ]VS$jSC$HEe[^]UVuS] SV; XZu#CS9CuF29| RSVCe[^]UU MB9Bt]량U M]zUVS0u ]VSXZt}w uz{(quECUEEEP-uv vSI EUREȉYF F=VSe[^]UWVS ÉUEu FE@E wt$tCqmڞztoZڞzt\U]$EXEZ$Ƀ\$$ u z UZv؃}1҃}1t VSVY_uSIY9EZ~U UWujuSUB e[^_]UVS E Eu]EE]t YXuIV@ ?u6؉t ^H G ‰FGVSXZu }Lu }?u }2u }%u }u } u }e[^_]u} E u} EDu} Eu} E!u} Eu} Ee[^_]e[^_]UVSE u]$C] ue[^]SVXZtwHtt tV-C jډYPCPV sVXZC-] ue[^]xu] ue[^]e[^]US] uuC  ]UWVuS]u S\U U{$jSVSYZPE pWj S؃$%E x e[^_]UWVSu ]}t4wtmt7 tJaFEe[^_]WSjvPj(WSvPjSWSPv vj Se؉[^_]uU2WEV} uSHXEu1SPWj"VjPWj"VF pGF$e[^_]ÐUhuƾɸUS]jSjSuSX]US]jS谾Zƒ YuhYCjSH jSżjSZYPS]UjuɸUS]jjSjS}jSu hoCS[X]UVSuPcSjV e[^]UVSuPSjVe[^]UVSjP½ZYujS)؍e[^]U9ЉSujP[jS jPR ujSs]UUWVSt]xjNjEhCPSuƋE@PS脽Ut)EPBPSZYPW u[SBPSZYu4VhCSjjSƋE@PS蒼 jWS6 hCE@EPVW uhCEPS9jjS`jSVtOuC=ECP-uC@uC1uCjlVWZYtuغ CXjuV9ZYtuCYjnVYZt uCuCXZjLVZYth(CYjfV^Zth4C؉[e[^_]UUWVSt]uwSNjE@PVZYPW Euh9C@PVGPVZYPSW tjVWuSVKjV趺 V諾e[^_]UUW}VSt]WƋE@PS\ZYPVz Euh9C@PSCJtt ECNuC Ut _t݋M؍T1E9}EE9EC UEEe[^_]UEP,h;ZUtЋQ|uC]UWVS uEE UEUBxxXEPǍFPSU t CVYƒ? $CCUCo9}`g؁UC?CCt EC؁UC1e[^_]UWVSE E}E8>uE UMBP@QEG`tUkR(ЉE@E}EE EuWGCG$GCG CGGG GCjCHd1CPC@[^]USE] UHyu []\CQ$ЈC[]UU EHbA(BQ(]UEM @PH@$AEA]UVuS] NAYS¨uAu=yu)CSx~(@t tPSV= A$ˆSe[^]ÐU=$CVuS Ct)jsV3VGjjV< {Սe[^]ÐUWVSۋ8tjVILVn}XtW詴$uhCVJW荴$hCV1 WV`e[^_]UVSJ0S$uhCSjjSm PVSʓe[^]UVS]jSٕjSEhChStjSYZtjjS蚄 u S與Z>u j hCjhCS踇 e[^]UVShCjP{ 8u hCVY^e[^]UVSjPhChSSjSme[^]US]Sjh CS#]UVSuhCjV0u1Ee[^]UVSuhCjV觓0r1Ee[^]USjP݉h) CjS~jS}ZYSЋ]US]jS7Z@YujhS׈ ؋]US]hCjS 8t}]1US]hCjSܒ uj h1 CS Ph? CS~ ]UWVSS}jjW蛓EjhI CjW输É!Su赱$uE1҉Ee[^_]e[^_]UWVSV}jjW5EjhI CjWXÉSu菲$uE1҉Ee[^_] e[^_]UVSuu=uE1[^][^]UWVSRhPyhVzy1e[^]UWVS]PUxZE@SWzZYu5Et%SWN|$h CuA~Eu9EPSWsE tuujP藫;EuEuMC}qj]e[^_]US]gE‰[]US]_E‰[]UWVSu=h Ch CjVQjjV蛍4 CPWҪ(tEe[1^_]W螪$Vp}e[^_]UWVS]h!CjjS܋hjS#P4 CjW8E,1҅e[^_]9US]KPY1҅E؋]US]5P©Z1҅E؋]UW}VS7~jVNxWhVKjV7xjV8u jV`e[^_]UVSjjP&jVS'}h) CjS/e[^]US]hCS贈XZjSwYXh!CjS hCjS غ@hSvhCh!CS藎غ@_h!CRCjh!!CRCj RC$h(!Cj@jSuhCjSv}@jS$jSqu]ÐUWVS1Pu!CE}1IQuVPH Cƒ P~ʍe[^_]UVuS] @RC8uRCX j SAZYtSh`"CShi"Cv4$Ce[^]UWVSP]jPu} F@PS$WvShl"Cv4$ }t:E-w16F< uV;[ZPWhv"Cv4s$jv4e[^_]UWVSSX~+OmS8H@t B@B RY -t -S8H@t B@B RZ [u1‹C<@xR1/C<@_ 1҃ …AS8H@t B@B Rm^ 뿉]xPU@[hh#CS S8H@t B@B RY ==S8H@t B@B RߕZ S8H@t B@B R賕_ =<pS8H@t B@B R胕^ DS8H@t B@B RWY =>S8H@t B@B R'Z S8H@t B@B R_ =~S8H@t B@B R˔^ S8H@t B@B R薔Y 9 t @t t\t$hhh:#CS K8H@t A@A Q-Z‰btJ t Bu tlat!}rtB ft'nt,jtt9vt>^  غ RC8uRCP jR1Y^E1k S8pЋH@t B@B R)ZE }(RC8uRCH jQɛZYu~hhL#CS /S8H@t B@B R裒^ 9;S8H@t B@B RqY SWYUe[^_]ÐUWtVSĀ芕jhWjPjh聕t WVidXZSh&CVd e[^_]USh)&CjupË tPG1]UWVSRh2&Ch<&CPqdhSeY_jS__ZtjSbZYdjS]_XjSmZYh)&ChSre jShYXVh2&Ch<&CScjS^XZhSfYX?uVDu7t&uR1u jPSc1e[^_]UVuSjjVpjjVpPډÃ۸t'VXbjVG]KA&CtF&CPVbe[^]UWVSQQ]hK&ChM&CRPUEvShuEPdjjun`(uShO&Cum jhm&Cub ;;uC1;t3j;S$^_u߃1эt)PSua tuuhn&Cjju_ Puuju\hp&CS蹍ZYu*Shr&Cu'bju[juYjLPX1e[^_]UVSjjPf_ PVjjSW_ Ph&CS~le[^]UVuSjjVnh&C‰ttPVwZYt ډe[^]UVSj-RZYtXh&ChM&CSVtPh&CV`e[^_]UVS]jjS[mh&ChSdajS6[ t h&CSjYXVjS>ajS[uVh'CS_ e[^]UWVS]jjSljSYh0'ChS` VjS`jS\t)jS]Z=&CYJVh8'CS j 6hc'ChS`jSeZt hk'CSiY_jhm&CS_^ WjS`jS*ZujjSi\ PVh'CSiVS]^jjSRdjSYt%jSsZYZt jSfjSXXGZh&CSw_VjSaVS^jjSc(jSYZYt VjSa VjS_jS\=&CujS^jS$YVjSWae[^_]UWVSp]jjS/kSKWh0'CxhS/_VWS'_(jSXZYtAjS'WjVhSmtVh'CSLh@jSXVWS`h'CjS^jSXt jSVY^mjSVXZjSEXYXh'CjSr` VS\XZh'CjSY` j.V\ZYu@)PVSM\ h'CjS)` jSW^uXVjS t!Vh'CS tjSXZYt h'CSVgY^jOSWXZjSaY^jSUXZ9#VFSoWYXjSeWXZjjSa 1e[^_]US]jjSijS^ujjS=^jSWjS`hSWh(CjS1_]1UWVSuu Zu VST[)h(Ch (CPS/oVh(CPS"o jSWU^XhVjA= Шuj\V趉ZYu h(CSf(Vh.(CjjSX PSnjST^XWjSb^e[^_]UVuS1h)&CVfjh@V#[h0(CjV+^ h%Ch5(CVljVUhVUjjV\(=%Ct&j4%CCVZSjV^<%Chc'CjV]h=(C&Chw(C|h(C&Ch(Cfj h(CVY(h(CjVs]jh0'ChVJjh(CjVT](jjV(\h&CjV:]hVT h%CjVkjVJSe[^]ÐU1ɉEv@Av  ]UUSЉt HZ[]UE=v(C]U1S]M S;Qu6t'Ұt)tu 9[]UWVuSS]V} S{EZ19YttTW耀$uh,CV!UWVSTe[^_]US]jjjSmbP?$S!T]UVSujjV b PZ1҅]e[^]GUVS]jjSajjSaPV诃YZ1҅ue[^]UVS]SurYu h,CV^ SVSe[^]US]jjS\a PS$SS]UP$5,C$uSɸUVSuPSSjVWe[^]UWVSRjPTjV-OtjVP_X]yWh,CV/^ jVL؍e[^_]UWVS]jh,CjS`jSjN_Z j(Y9jSaٽXZ f٭۝٭>!u PFāP謁Xu SQ`h,CV_}ZYj jST7,Cw,Cw,Cw ,CG,C@PvG ,ClP^G,C@PMG,C@Ptg>%u~u+E9rRdX.FWEEPhSJPSPdF딍PcXe[^_]UVS0]jSnL^Z j,jjS]jSJj,CMEȺ,CjXtZSPw0| w0WoBW1X _0j‰X4s$$S|lY^wjX4ZVPSl{C2 CJSk T S‰Y,C=uݺ=-t Dž1ҍPRkXZ6Ww0X_ u;uDž1! wMjSVl 1҃…tP F2Dž!u SV8sY[ SVrXF2ZPVo W[|R_0 uP %?@jDž Y1;ÉW0B2B$u_wW4B4HfB4e[^_]UWVS]UEu׉E1IQRV Pu SVdd@JSغVde[^_]UWVSLQU P<(}t(jh/CV? ‰jXN01ۋ9GJ~)tvF=t=uBS‰XC:V$h/CV ‰SCZYGJ h!/CVXZJu,눉ډ WJA2(ЈGIA2PQhY)[VP@u h XF0Z@,{4@9~!h:/CC4hjPsv4CS49}CG9|􋍨A,K@B,@tCt PSv4 1ۋA,HPjj$Qj P_xHt;]1Ҁ]jPjCRk@H9|ōe[^_]UWVS(EЉUbUЋB-t#tC=t 51ujŰEűESp0q7= +={= =tp =tU=t =t&jE̺XUЋEBXUЋErU]jLjCj:EЋX0xJuhR/Cu^_`Jjjjj%SiPE [:ŰE6uYUЋErUjXZŰE uXEЋP^E-*%m1+f< tl/S >ItL#t@ $ t| t Q?`-C;EvIuЍ]űUWr0r?a-CPElSƋEuWp0p$uEЋP4B4HfB4e[^_]Uj-UVu؉S }uEVs0jEe[^]UVSPVs0l e[]^]xUWVSL@0UP$EUu+Ex~h}/CE[Uԉ UԉrU]B= EPu>lƉډSu*lZUYPVBpj ugUEP$e[^_]UVS{ ~F0h}/C'^C C$e[^]UWVS8Ӌx0@jjjj WEfP EEEE]jE1Sv0j${~}}Et1PWj}2XEZuj2EupWBrEF[t=UuV~ =UXuUĉ2,lq;X]u}j{~}YM[tRUčBw%jQW^c EjupWqM"t QWiXZuEupWnqp Eu ËEp Eu?% ËEe[^_]UWVSVGs0,i؉YX,Vuۍe[^_]UWVS(x0UЋ@E̋F{tk (t=tdyE;Ft h/CV舺XZV~)Xu E]ԉPjSWb u̺)j(UԉQ$vUԉVCY[ h/CVZEЃMԋXAvt EPW+hXZW$jBPSjWc PEuWbCG$e[^_]UWVSD@0EF(t =t18V^Y0S)j(%XZWv0c h/CVLY[F:tW(t}.t{tn[t|=t^sW]uwgډSWumV]ډgSWumtWuf[e[^_]UWVSHBUv h/CV{Y[,E}E}ue^01ɋUC$҉EtSz u&G9Bu EBG9Bu EBu΅tjws$jSajS.^XZF4@4)9U~h0CF0XEU@PXI=}H;EtWUPs;]_X~+]F0)X$ Wv0_WF0]Ժ @$HPSEPv0le[^_]UWVuԉS V}s0Tee[^_]UUVSËp0jCe[^]UVSPƺde[^]UWVSX0U(-}thuj S_S`_jǍUU u S\/WS[}thujS_u juj!S_uS^}GPuS_^PS[e[^_]ÐUVShjjR hjC(CjVC0C$CpSSC C,-BC@CC C@Be[^]UVSjkB0Pr(VjC,Ps Vze[^]UWVSP]CڍsHE3jjS"CHFsjj~`S"F`Gj S= S2Sjh 0CSH UBDB@e[^_]U]P@ @,@p@D@8@<@9@@@h@0f@6f@4@@@(@@t@PUVSpp P蹔S轞jSBP2SEjvFPxWXP$:e[^_]U卅WV1S]PjS4ǍPS7;s7E9rRn:XC>FPVXP9e[^_]U卅WVS]PjSR4jS5ƍPS 7N~WP: ፅP(9e[^_]UEWVSVVPju3jjuE5U %Pju5] 9v19O)x>9h!1Cu0Y[h!1CWu2 ~EtFPuM%XKZue[^_]UWVS}WMPW5 ;JVW4Z9Yth71CVW0 E9rR8XF뮍P7e[^_]Uuu u{81UVS]jjS2jSVS75Vh@S,,(t hE1CS/[XV]7e[^]UVSC%t[tN;uDhc1Cv/Y^31;^À;uh1Cvd/XZC<%u<;]u׍C؍e[^]UVSRTYaV$1CRC8uRCX%"hRC8uRCX j RC8uRCXjRC8uRCXjRC8uRCXjRC8uRCXnjbRC8uRCXPjDRC8uRCX%0h!RC8uRCX% hSN[Z 193RC8uRCp jVNZYu1҅‰Ѝe[^]UWVSӀz^uf1CC;]sD<%uCt({-uS;UsB999u1[^_]UVSuȃ.t%t,[t%)R[^]FE[^]G9[^]UWVSuE%*$(<(t )t'-~)ujFjFPEUFB Hx M|th2CEp6,[ZUÉ+DDEVXYMD~Vƒbt ft~~^t{uh(2CEp+XZ1:u=WEE[]X9s;EuIuB;EB1҅҉>[th;2CUrZ+Y[EEM1;9tG]KSZS[uYRC҃8uRCP jRKZYF1xU;B } Mƒ|uh^2CEp*Y[MA\)9rSWt4O t1҅҉~uU;zE1EM;ysuZtU+t=*t.~-tF?uttEW@PE2YuluF5uV 1tUuWVEDE@PEZu.M;Ysu_tCυu1 uGe[^_]UWVSp Ã~ht2Cp\)XZ|E DFuC {YuK e[^_]UWVS1C;GsUu ZuxE @P.YuK1e[^_]UWVSËU;{ E |#u)PRYE ^2CCEe[^_](tuh2Cs(YX!uD+@E CEe[^_]Vts e[^_]UWVSQH Uɉƒ} Шuht2C1Sw* 9}uFu&XZe[^_]UWVS4PjO*Pj5*jj , gǃOy19v߃j[^uh2CKZY)to9v ^O)'WC@PSK t܉+)ƅFVPK u+CPSDž8^uMDž@:+CP+Vj1҉DžƅXtgVډW$C;s te[^_]UE]uU1҉E]gU卅WVSPhujhuEhua ;wZڍDžƅXt31)9Pu4hu8VڍFC1e[^_]US]jjS&jjS&jS! jSjhAS]Uh2Cu5$U卅WVS@Pju&jju&jurË @PjuQ( Dž8^uDž@DžCƒ Шuth2Cju# Pu(_UX9WDž][jSpZY" 7'1Pj ;]<%u3CRC8uRCP jRCZYu# 9rW*Y D<0u)PVW* !Ѓ1V*XZWU+XCHjS<YX$PS 1ҍVXZjS&YXjSCYZujSMXZ)PVS-jSZYu"jSZYPSZYPh2CSR! W*X19…t5;s:9rRO)XF)PVS8)Sk(u;e[^_]U1҉WVSƈэQ\fDl\D[^_]U卅WVS`PjuDž"ƋPu%;>%uF>%u,E9rRN([FGtPh3C?ZYu)vh3CuY[RC8uRCP jR@[ZRC8uRCP jRh@ZY?.u[RCG8uRCP jR5@Y[RC8uRCP jR@[ZRC8uRCP jR?ZYth83CuY[)C%APVFQ> Dg>eWXECG:ctJdqE itqous7xu!ٽXZ f٭۝٭P1uO!_ٽX f٭۝٭Lu!ٽZ f٭߽٭YPSu $PP<PuWE 9rS%X"H@ tH tK "t\uN 9;rS$X\@9rS$X7jhe3Cjhh3CS$ 9rS]$XP 9rS2$X"PuKj.ÍP{;u%cvu P$NSPPK; FPhm3Cu_:1эIQRP# P"e[^_]US]h0Ch3CS_"ha0CjSh[0CjSq$jjSE jh 1CSh jS XZjSzYXjSh XZjS YXh3CjS jSD X]ZÐUSSSEuzS'KE EJE1҉ESZY[]UVSQQBtIt5@tt4r2^ZCKH#J(KH# K21HKe[^]URRxu"3C]EP$ztɉUWVSSu} ~~R;GMHP$FO U AQAVFQFAVFVCPZYu{ u~~9Cu +GG[uh3Cu*bY1[_P9}G |BF9؉|_+W9}-EGM|% BM9|1e[^_]USH1=wPD]UVuSӍF=wPBPr Q>QZC S9}DB9|se[^]UWVSQ]uB3CE|CPWZ@E~ h3CV`[XMC=wPjjV袦V胦YG~$1ɉڋGȃ @J@@uE_G_e[^_]UVuSj jjV?jPV要CډCCC CC3Cu ue[^]UVuS] S3Ctj KPRVjCPs V謥jj SV补e[^]UPPU MB;AsQ B?;R$$]ZYzuBEzt͋Ru(CUSU] JH#CBxu9Xt @u(C[]UVSSSu MVt Ҹ(Cte<u76QT3C]UR$uz RQ+'VCP,ZYu[u(Ce[^]UWVS]u }SV^F=(CYZu>Cuh3Cuzt h4CWG^XZ]e[^_]Se[^_]UWVS}EBUM9ljEIRMU~ WUEk^u UE;}[EU܉xMU܋A |t#FPQu KSHPEF;u|ÍG=weMWuq uL u+YUB MNx9U{t"CPuu KSHP Nyҁ}3CtM jPuu͢e[^_]UWVSU|xu =3C]WOBG9vWztBG҉1D@~DžpDžxDžtt1G9~9ÉG;tG @C9~pxѥtt@x~DžlpDžhOUKt0GxtUhlK uՋEUhMplEDž\F9\EDž`DžXDžd}vdD~2`ȉә9`P~X`\U9`Pt%d әP9ЉT+\X|VQM|XZuW|zS9t)9Xt@pj SV1C C CFsMQCSACy~@tGtW|W{_X؍e[^_]UVSu] VSEY=(CZuVE$$EE]e[^]U1VSU u]z3CtJE ][^]sUVSu] VS0Y=(CZuuEPEEe[^]UEWVSHt:p |u+1ۃv  |uӉ)؃މzUȉ΍yz3Cu-eSuxYZu݉ىe[^_]ÐUWVS]jjS$jS2jjS 9GjS+VSYVjSjjS (jS5YZtjFS_XZ1e[^_]US]jjSjjSSDjSjSjSjjS& $jSZYtjSYXjSt YZu]USQQ]jjS]#SI7jSjSaujS EXZv]jS ZYuuuS ]US]jjS jSZYPS]US]jjS}h4CSQ jS]UWVSjjuNjuZXuZttL>EEULD>MD9xreEUECjBCBC KMI Mgt ]DCExht uPG^XMċUJWRw:M Y[]C@CG GʞvٞGUG8U_0O UĉME_PtWWTYZuh7C@{tGPS7ÅXZuh7C!Myt"G PQYE[uh8CuP4XZG]/EčEG O0W$]ĉGPG(WTWGXGWDWG@GW4UGHZG0GAG`B%PQR=E U@ E̋M̋BY8@ۉBt!Y(A0Q4A Q$MċMăEju]C)pC@Cu UċUĉƒ(k2MD0;AE~ PQuK 8uMuu KSHP{~@tE@t PuS_XNWuDY[UB@KHr MQuqCX1ۃ ;]}@EċЃ?uMDDEPuCDXZEC뻉7]EGSCB@9BDrS/RYUR UM]IHES+AMRI)H}EuKEUċ]P@+A9 uQ5XZEU@ MUE̍A1;uk1;u}$UE )ًQ;AT;D;D;F;u|*e[^_]USP]EPs sS tEuKHACЋ]US];uSZ@t KC]UU EBEBBEB ]UW}VuSt3WY@u'9vSwu ) _] )1e[^_]UMVu S]V9v-w CwSR6QvQuZ^e[^]ÐU9CQ@9Cr]ÐUSX5 PX1Щ 1Ӂft @@Ct @@Ct @@Ct @@Ct @@C t @@C@ t @@C=v+@@C@t @@Ct&[]à @@CM[ @@C]ÐU]ÐU`A8t `AQA`AuÍ&USTAt)t'TAKu$HAzY[]1=TA @TAu뾍'USP@Cu5TA P@Ct$tt&TAKu$HA X[]1=TA @TAuÐU@C]HUBSdT$U1ۉT$$pRC uFJx|*Au Jy; 1 then i = i - 1 end return p:sub(1, i) else return "." end end function path.getdrive(p) local ch1 = p:sub(1,1) local ch2 = p:sub(2,2) if ch2 == ":" then return ch1 end end function path.getextension(p) local i = p:findlast(".", true) if (i) then return p:sub(i) else return "" end end function path.getname(p) local i = p:findlast("[/\\]") if (i) then return p:sub(i + 1) else return p end end function path.getrelative(src, dst) -- normalize the two paths src = path.getabsolute(src) dst = path.getabsolute(dst) -- same directory? if (src == dst) then return "." end -- different drives? Must use absolute path if path.getdrive(src) ~= path.getdrive(dst) then return dst end src = src .. "/" dst = dst .. "/" -- trim off the common directories from the front local i = src:find("/") while (i) do if (src:sub(1,i) == dst:sub(1,i)) then src = src:sub(i + 1) dst = dst:sub(i + 1) else break end i = src:find("/") end -- back up from dst to get to this common parent local result = "" i = src:find("/") while (i) do result = result .. "../" i = src:find("/", i + 1) end -- tack on the path down to the dst from here result = result .. dst -- remove the trailing slash return result:sub(1, -2) end function path.isabsolute(p) local ch1 = p:sub(1,1) local ch2 = p:sub(2,2) return (ch1 == "/" or ch1 == "\\" or ch2 == ":") end function path.iscfile(fname) local extensions = { ".c", ".s" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.iscppfile(fname) local extensions = { ".cc", ".cpp", ".cxx", ".c", ".s" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.isresourcefile(fname) local extensions = { ".rc" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.join(leading, trailing) if (not leading) then leading = "" end if (not trailing) then return leading end if (path.isabsolute(trailing)) then return trailing end if (leading == ".") then leading = "" end if (leading:len() > 0 and not leading:endswith("/")) then leading = leading .. "/" end return leading .. trailing end function path.rebase(p, oldbase, newbase) p = path.getabsolute(path.join(oldbase, p)) p = path.getrelative(newbase, p) return p end function path.translate(p, sep) if (type(p) == "table") then local result = { } for _, value in ipairs(p) do table.insert(result, path.translate(value)) end return result else if (not sep) then if (os.is("windows")) then sep = "\\" else sep = "/" end end local result = p:gsub("[/\\]", sep) return result end end -- function string.endswith(haystack, needle) if (haystack and needle) then local hlen = haystack:len() local nlen = needle:len() if (hlen >= nlen) then return (haystack:sub(-nlen) == needle) end end return false end function string.explode(s, pattern, plain) if (pattern == '') then return false end local pos = 0 local arr = { } for st,sp in function() return s:find(pattern, pos, plain) end do table.insert(arr, s:sub(pos, st-1)) pos = sp + 1 end table.insert(arr, s:sub(pos)) return arr end function string.findlast(s, pattern, plain) local curr = 0 repeat local next = s:find(pattern, curr + 1, plain) if (next) then curr = next end until (not next) if (curr > 0) then return curr end end function string.startswith(haystack, needle) return (haystack:find(needle, 1, true) == 1) end-- function table.contains(t, value) for _,v in pairs(t) do if (v == value) then return true end end return false end function table.extract(arr, fname) local result = { } for _,v in ipairs(arr) do table.insert(result, v[fname]) end return result end function table.implode(arr, before, after, between) local result = "" for _,v in ipairs(arr) do if (result ~= "" and between) then result = result .. between end result = result .. before .. v .. after end return result end function table.join(...) local result = { } for _,t in ipairs(arg) do if type(t) == "table" then for _,v in ipairs(t) do table.insert(result, v) end else table.insert(result, t) end end return result end function table.translate(arr, translation) local result = { } for _, value in ipairs(arr) do local tvalue if type(translation) == "function" then tvalue = translation(value) else tvalue = translation[value] end if (tvalue) then table.insert(result, tvalue) end end return result end -- _SOLUTIONS = { } _TEMPLATES = { } premake = { } premake.actions = { } premake.options = { } local builtin_dofile = dofile function dofile(fname) -- remember the current working directory; I'll restore it shortly local oldcwd = os.getcwd() -- if the file doesn't exist, check the search path if (not os.isfile(fname)) then local path = os.pathsearch(fname, _OPTIONS["scripts"], os.getenv("PREMAKE_PATH")) if (path) then fname = path.."/"..fname end end -- use the absolute path to the script file, to avoid any file name -- ambiguity if an error should arise fname = path.getabsolute(fname) -- switch the working directory to the new script location local newcwd = path.getdirectory(fname) os.chdir(newcwd) -- run the chunk. How can I catch variable return values? local a, b, c, d, e, f = builtin_dofile(fname) -- restore the previous working directory when done os.chdir(oldcwd) return a, b, c, d, e, f end function iif(expr, trueval, falseval) if (expr) then return trueval else return falseval end end function include(fname) return dofile(fname .. "/premake4.lua") end local builtin_open = io.open function io.open(fname, mode) if (mode) then if (mode:find("w")) then local dir = path.getdirectory(fname) ok, err = os.mkdir(dir) if (not ok) then error(err, 0) end end end return builtin_open(fname, mode) end function printf(msg, ...) print(string.format(msg, unpack(arg))) end local builtin_type = type function type(t) local mt = getmetatable(t) if (mt) then if (mt.__type) then return mt.__type end end return builtin_type(t) end -- local function literal(str) local code = "" for line in str:gmatch("[^\n]*") do if (line:len() > 0) then code = code .. "io.write[=[" .. line .. "]=]" else code = code .. "io.write(eol)\n" end end return code:sub(1, -15) end function premake.encodetemplate(tmpl) code = "" -- normalize line endings tmpl = tmpl:gsub("\r\n", "\n") while (true) do -- find an escaped block start, finish = tmpl:find("<%%.-%%>") if (not start) then break end local before = tmpl:sub(1, start - 1) local after = tmpl:sub(finish + 1) -- get the block type and contents local block local isexpr = (tmpl:sub(start + 2, start + 2) == "=") if (isexpr) then block = tmpl:sub(start + 3, finish - 2) else block = tmpl:sub(start + 2, finish - 2) end -- if a statement block, strip out everything else on that line if (not isexpr) then finish = before:findlast("\n", true) if (finish) then before = before:sub(1, finish) else before = nil end start = after:find("\n", 1, true) if (start) then after = after:sub(start + 1) end end -- output everything before the block if (before) then code = code .. literal(before) end -- output the block itself if (isexpr) then code = code .. "io.write(" .. block .. ")" else code = code .. block .. "\n" end -- do it again, with everything after the block tmpl = after end -- tack on everything after the last block code = code .. literal(tmpl) return code end function premake.loadtemplatestring(name, str) local code = premake.encodetemplate(str) local fn, msg = loadstring("return function (this) eol='\\n';" .. code .. " end", name) if (not fn) then error(msg, 0) end return fn() end function premake.getoutputname(this, namespec) local fname if (type(namespec) == "function") then fname = namespec(this) else fname = this.name .. namespec end return path.join(this.location, fname) end function premake.loadtemplatefile(fname) local f = io.open(fname, "rb") local tmpl = f:read("*a") f:close() return premake.loadtemplatestring(path.getname(fname), tmpl) end -- function premake.eachconfig(prj) -- I probably have the project root config, rather than the actual project if prj.project then prj = prj.project end local i = 0 local t = prj.solution.configurations return function () i = i + 1 if (i <= #t) then return prj.__configs[t[i]] end end end function premake.eachfile(prj) -- project root config contains the file config list if not prj.project then prj = premake.getconfig(prj) end local i = 0 local t = prj.files return function () i = i + 1 if (i <= #t) then return prj.__fileconfigs[t[i]] end end end function premake.eachproject(sln) local i = 0 return function () i = i + 1 if (i <= #sln.projects) then local prj = sln.projects[i] local cfg = premake.getconfig(prj) cfg.name = prj.name cfg.blocks = prj.blocks return cfg end end end function premake.esc(value) if (type(value) == "table") then local result = { } for _,v in ipairs(value) do table.insert(result, premake.esc(v)) end return result else value = value:gsub('&', "&") value = value:gsub('"', """) value = value:gsub("'", "'") value = value:gsub('<', "<") value = value:gsub('>', ">") value = value:gsub('\r', " ") value = value:gsub('\n', " ") return value end end function premake.findproject(name) name = name:lower() for _, sln in ipairs(_SOLUTIONS) do for _, prj in ipairs(sln.projects) do if (prj.name:lower() == name) then return prj end end end end function premake.findfile(prj, extension) for _, fname in ipairs(prj.files) do if fname:endswith(extension) then return fname end end end function premake.getconfig(prj, cfgname) -- might have the root configuration, rather than the actual project if prj.project then prj = prj.project end return prj.__configs[cfgname or ""] end function premake.getdependencies(cfg) local results = { } for _, link in ipairs(cfg.links) do local prj = premake.findproject(link) if (prj) then table.insert(results, prj) end end return results end function premake.getlinks(cfg, kind, part) -- if I'm building a list of link directories, include libdirs local result = iif (part == "directory" and kind == "all", cfg.libdirs, {}) -- am I getting links for a configuration or a project? local cfgname = iif(cfg.name == cfg.project.name, "", cfg.name) local function canlink(source, target) if (target.kind ~= "SharedLib" and target.kind ~= "StaticLib") then return false end if (source.language == "C" or source.language == "C++") then if (target.language ~= "C" and target.language ~= "C++") then return false end return true elseif (source.language == "C#") then if (target.language ~= "C#") then return false end return true end end for _, link in ipairs(cfg.links) do local item -- is this a sibling project? local prj = premake.findproject(link) if prj and kind ~= "system" then local prjcfg = premake.getconfig(prj, cfgname) if kind == "dependencies" or canlink(cfg, prjcfg) then if (part == "directory") then item = path.rebase(prjcfg.linktarget.directory, prjcfg.location, cfg.location) elseif (part == "basename") then item = prjcfg.linktarget.basename elseif (part == "fullpath") then item = path.rebase(prjcfg.linktarget.fullpath, prjcfg.location, cfg.location) elseif (part == "object") then item = prjcfg end end elseif not prj and (kind == "system" or kind == "all") then if (part == "directory") then local dir = path.getdirectory(link) if (dir ~= ".") then item = dir end elseif (part == "fullpath") then item = link if premake.actions[_ACTION].targetstyle == "windows" then item = item .. iif(cfg.language == "C" or cfg.language == "C++", ".lib", ".dll") end if item:find("/", nil, true) then item = path.getrelative(cfg.basedir, item) end else item = link end end if item then if premake.actions[_ACTION].targetstyle == "windows" and part ~= "object" then item = path.translate(item, "\\") end if not table.contains(result, item) then table.insert(result, item) end end end return result end function premake.gettarget(cfg, direction, style, os) -- normalize the arguments if not os then os = _G["os"].get() end if (os == "bsd") then os = "linux" end local kind = cfg.kind if (cfg.language == "C" or cfg.language == "C++") then -- On Windows, shared libraries link against a static import library if (style == "windows" or os == "windows") and kind == "SharedLib" and direction == "link" then kind = "StaticLib" end -- Linux name conventions only apply to static libs on windows (by user request) if (style == "linux" and os == "windows" and kind ~= "StaticLib") then style = "windows" end elseif (cfg.language == "C#") then -- .NET always uses Windows naming conventions style = "windows" end -- Initialize the target components local field = iif(direction == "build", "target", "implib") local name = cfg[field.."name"] or cfg.targetname or cfg.project.name local dir = cfg[field.."dir"] or cfg.targetdir or path.getrelative(cfg.location, cfg.basedir) local prefix = "" local suffix = "" -- If using an import library and "NoImportLib" flag is set, library will be in objdir if cfg.kind == "SharedLib" and kind == "StaticLib" and cfg.flags.NoImportLib then dir = cfg.objectsdir end if style == "windows" then if kind == "ConsoleApp" or kind == "WindowedApp" then suffix = ".exe" elseif kind == "SharedLib" then suffix = ".dll" elseif kind == "StaticLib" then suffix = ".lib" end elseif style == "linux" then if (kind == "WindowedApp" and os == "macosx") then dir = path.join(dir, name .. ".app/Contents/MacOS") elseif kind == "SharedLib" then prefix = "lib" suffix = ".so" elseif kind == "StaticLib" then prefix = "lib" suffix = ".a" end end prefix = cfg[field.."prefix"] or cfg.targetprefix or prefix suffix = cfg[field.."extension"] or cfg.targetextension or suffix local result = { } result.basename = name result.name = prefix .. name .. suffix result.directory = dir result.fullpath = path.join(result.directory, result.name) return result end local function walksources(prj, files, fn, group, nestlevel, finished) local grouplen = group:len() local gname = iif(group:endswith("/"), group:sub(1, -2), group) -- open this new group if (nestlevel >= 0) then fn(prj, gname, "GroupStart", nestlevel) end -- scan the list of files for items which belong in this group for _,fname in ipairs(files) do if (fname:startswith(group)) then -- is there a subgroup within this item? local _,split = fname:find("[^\.]/", grouplen + 1) if (split) then local subgroup = fname:sub(1, split) if (not finished[subgroup]) then finished[subgroup] = true walksources(prj, files, fn, subgroup, nestlevel + 1, finished) end end end end -- process all files that belong in this group for _,fname in ipairs(files) do if (fname:startswith(group) and not fname:find("[^\.]/", grouplen + 1)) then fn(prj, fname, "GroupItem", nestlevel + 1) end end -- close the group if (nestlevel >= 0) then fn(prj, gname, "GroupEnd", nestlevel) end end function premake.walksources(prj, files, fn) walksources(prj, files, fn, "", -1, {}) end -- -- do not copy these fields into the configurations local nocopy = { blocks = true, keywords = true, projects = true, } -- leave these paths as absolute, rather than converting to project relative local nofixup = { basedir = true, location = true, } function premake.getactiveterms() local terms = { _ACTION:lower(), os.get() } -- add option keys or values for key, value in pairs(_OPTIONS) do if value ~= "" then table.insert(terms, value:lower()) else table.insert(terms, key:lower()) end end return terms end function premake.escapekeyword(keyword) keyword = keyword:gsub("([%.%-%^%$%(%)%%])", "%%%1") if keyword:find("**", nil, true) then keyword = keyword:gsub("%*%*", ".*") else keyword = keyword:gsub("%*", "[^/]*") end return keyword:lower() end function premake.iskeywordmatch(keyword, terms) -- is it negated? if keyword:startswith("not ") then return not premake.iskeywordmatch(keyword:sub(5), terms) end for _, word in ipairs(keyword:explode(" or ")) do local pattern = "^" .. word .. "$" for termkey, term in pairs(terms) do if term:match(pattern) then return termkey end end end end function premake.iskeywordsmatch(keywords, terms) local hasrequired = false for _, keyword in ipairs(keywords) do local matched = premake.iskeywordmatch(keyword, terms) if not matched then return false end if matched == "required" then hasrequired = true end end if terms.required and not hasrequired then return false else return true end end local function copyfields(cfg, this) for field,value in pairs(this) do if (not nocopy[field]) then if (type(value) == "table") then if (not cfg[field]) then cfg[field] = { } end cfg[field] = table.join(cfg[field], value) else cfg[field] = value end end end end local function buildconfig(prj, terms) -- fields are copied first from the solution, then the solution's configs, -- then from the project, then the project's configs. Each can overwrite -- or add to the values set previously. The objdir field gets special -- treatment, in order to provide a project-level default and still enable -- solution-level overrides local cfg = { } copyfields(cfg, prj.solution) for _,blk in ipairs(prj.solution.blocks) do if (premake.iskeywordsmatch(blk.keywords, terms)) then copyfields(cfg, blk) end end copyfields(cfg, prj) for _,blk in ipairs(prj.blocks) do if (premake.iskeywordsmatch(blk.keywords, terms)) then copyfields(cfg, blk) end end return cfg end local function buildprojectconfig(prj, cfgname) -- create the base configuration, flattening the list of objects and -- filtering out settings which do not match the current environment local terms = premake.getactiveterms() terms.config = (cfgname or ""):lower() local cfg = buildconfig(prj, terms) cfg.name = cfgname cfg.project = prj -- set the project location, if not already set cfg.location = cfg.location or cfg.basedir -- remove excluded files from the file list local files = { } for _, fname in ipairs(cfg.files) do local excluded = false for _, exclude in ipairs(cfg.excludes) do excluded = (fname == exclude) if (excluded) then break end end if (not excluded) then table.insert(files, fname) end end cfg.files = files -- fixup the data for name, field in pairs(premake.fields) do -- convert absolute paths to project relative if (field.kind == "path" or field.kind == "dirlist" or field.kind == "filelist") and (not nofixup[name]) then if type(cfg[name]) == "table" then for i,p in ipairs(cfg[name]) do cfg[name][i] = path.getrelative(prj.location, p) end else if cfg[name] then cfg[name] = path.getrelative(prj.location, cfg[name]) end end end -- re-key flag fields for faster lookups if field.isflags then local values = cfg[name] for _, flag in ipairs(values) do values[flag] = true end end end -- build configuration objects for all files cfg.__fileconfigs = { } for _, fname in ipairs(cfg.files) do terms.required = fname:lower() local fcfg = buildconfig(prj, terms) fcfg.name = fname -- add indexed by name and integer cfg.__fileconfigs[fname] = fcfg table.insert(cfg.__fileconfigs, fcfg) end return cfg end local function buildtargets(cfg) -- deduce and store the applicable tool for this configuration if cfg.language == "C" or cfg.language == "C++" then if _OPTIONS.cc then cfg.tool = premake[_OPTIONS.cc] end elseif cfg.language == "C#" then if _OPTIONS.dotnet then cfg.tool = premake[_OPTIONS.dotnet] end end -- deduce the target and path style from the current action/tool pairing local action = premake.actions[_ACTION] local targetstyle = action.targetstyle or "linux" if (cfg.tool) then targetstyle = cfg.tool.targetstyle or targetstyle end -- build a unique objects directory local function getbasedir(cfg) return path.join(cfg.location, cfg.objdir or cfg.project.objdir or "obj") end local function getuniquedir(cfg) local thisbase = getbasedir(cfg) local thislocal = path.join(thisbase, cfg.name) local isbasematched = false for _, sln in ipairs(_SOLUTIONS) do for _, prj in ipairs(sln.projects) do for _, thatcfg in pairs(prj.__configs) do if thatcfg ~= cfg then local thatbase = getbasedir(thatcfg) if thisbase == thatbase then isbasematched = true if thislocal == path.join(thatbase, thatcfg.name) then return path.join(thislocal, cfg.project.name) end end end end end end return iif(isbasematched, thislocal, thisbase) end cfg.objectsdir = path.getrelative(cfg.location, getuniquedir(cfg)) -- precompute the target names and paths cfg.buildtarget = premake.gettarget(cfg, "build", targetstyle) cfg.linktarget = premake.gettarget(cfg, "link", targetstyle) -- translate the paths as appropriate local pathstyle = action.pathstyle or targetstyle if (pathstyle == "windows") then cfg.buildtarget.directory = path.translate(cfg.buildtarget.directory, "\\") cfg.buildtarget.fullpath = path.translate(cfg.buildtarget.fullpath, "\\") cfg.linktarget.directory = path.translate(cfg.linktarget.directory, "\\") cfg.linktarget.fullpath = path.translate(cfg.linktarget.fullpath, "\\") cfg.objectsdir = path.translate(cfg.objectsdir, "\\") end end function premake.buildconfigs() -- walk the object tree once and flatten the configurations for _, sln in ipairs(_SOLUTIONS) do for _, prj in ipairs(sln.projects) do prj.__configs = { } prj.__configs[""] = buildprojectconfig(prj) for _, name in ipairs(sln.configurations) do prj.__configs[name] = buildprojectconfig(prj, name) end end end -- walk it again and build the targets and unique directories for _, sln in ipairs(_SOLUTIONS) do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do buildtargets(cfg) end end end end -- premake.fields = { basedir = { kind = "path", scope = "container", }, buildaction = { kind = "string", scope = "config", allowed = { "Compile", "Copy", "Embed", "None" } }, buildoptions = { kind = "list", scope = "config", }, configurations = { kind = "list", scope = "solution", }, defines = { kind = "list", scope = "config", }, excludes = { kind = "filelist", scope = "config", }, files = { kind = "filelist", scope = "config", }, flags = { kind = "list", scope = "config", isflags = true, allowed = { "ExtraWarnings", "FatalWarnings", "Managed", "NativeWChar", "No64BitChecks", "NoEditAndContinue", "NoExceptions", "NoFramePointer", "NoImportLib", "NoManifest", "NoNativeWChar", "NoPCH", "NoRTTI", "Optimize", "OptimizeSize", "OptimizeSpeed", "SEH", "StaticRuntime", "Symbols", "Unicode", "Unsafe", "WinMain" } }, implibdir = { kind = "path", scope = "config", }, implibextension = { kind = "string", scope = "config", }, implibname = { kind = "string", scope = "config", }, implibprefix = { kind = "string", scope = "config", }, includedirs = { kind = "dirlist", scope = "config", }, kind = { kind = "string", scope = "config", allowed = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" } }, language = { kind = "string", scope = "container", allowed = { "C", "C++", "C#" } }, libdirs = { kind = "dirlist", scope = "config", }, linkoptions = { kind = "list", scope = "config", }, links = { kind = "list", scope = "config", allowed = function(value) -- if library name contains a '/' then treat it as a path to a local file if value:find('/', nil, true) then value = path.getabsolute(value) end return value end }, location = { kind = "path", scope = "container", }, objdir = { kind = "path", scope = "config", }, pchheader = { kind = "path", scope = "config", }, pchsource = { kind = "path", scope = "config", }, postbuildcommands = { kind = "list", scope = "config", }, prebuildcommands = { kind = "list", scope = "config", }, prelinkcommands = { kind = "list", scope = "config", }, resdefines = { kind = "list", scope = "config", }, resincludedirs = { kind = "dirlist", scope = "config", }, resoptions = { kind = "list", scope = "config", }, targetdir = { kind = "path", scope = "config", }, targetextension = { kind = "string", scope = "config", }, targetname = { kind = "string", scope = "config", }, targetprefix = { kind = "string", scope = "config", }, uuid = { kind = "string", scope = "container", allowed = function(value) local ok = true if (#value ~= 36) then ok = false end for i=1,36 do local ch = value:sub(i,i) if (not ch:find("[ABCDEFabcdef0123456789-]")) then ok = false end end if (value:sub(9,9) ~= "-") then ok = false end if (value:sub(14,14) ~= "-") then ok = false end if (value:sub(19,19) ~= "-") then ok = false end if (value:sub(24,24) ~= "-") then ok = false end if (not ok) then return nil, "invalid UUID" end return value:upper() end }, } local function checkvalue(value, allowed) if (allowed) then if (type(allowed) == "function") then return allowed(value) else for _,v in ipairs(allowed) do if (value:lower() == v:lower()) then return v end end return nil, "invalid value '" .. value .. "'" end else return value end end function premake.getobject(t) local container if (t == "container" or t == "solution") then container = premake.CurrentContainer else container = premake.CurrentConfiguration end if t == "solution" then if type(container) == "project" then container = container.solution end if type(container) ~= "solution" then container = nil end end local msg if (not container) then if (t == "container") then msg = "no active solution or project" elseif (t == "solution") then msg = "no active solution" else msg = "no active solution, project, or configuration" end end return container, msg end function premake.setarray(ctype, fieldname, value, allowed) local container, err = premake.getobject(ctype) if (not container) then error(err, 4) end if (not container[fieldname]) then container[fieldname] = { } end local function doinsert(value, depth) if (type(value) == "table") then for _,v in ipairs(value) do doinsert(v, depth + 1) end else value, err = checkvalue(value, allowed) if (not value) then error(err, depth) end table.insert(container[fieldname], value) end end if (value) then doinsert(value, 5) end return container[fieldname] end local function domatchedarray(ctype, fieldname, value, matchfunc) local result = { } function makeabsolute(value) if (type(value) == "table") then for _,item in ipairs(value) do makeabsolute(item) end else if value:find("*") then makeabsolute(matchfunc(value)) else table.insert(result, path.getabsolute(value)) end end end makeabsolute(value) return premake.setarray(ctype, fieldname, result) end function premake.setdirarray(ctype, fieldname, value) return domatchedarray(ctype, fieldname, value, os.matchdirs) end function premake.setfilearray(ctype, fieldname, value) return domatchedarray(ctype, fieldname, value, os.matchfiles) end function premake.setstring(ctype, fieldname, value, allowed) -- find the container for this value local container, err = premake.getobject(ctype) if (not container) then error(err, 4) end -- if a value was provided, set it if (value) then value, err = checkvalue(value, allowed) if (not value) then error(err, 4) end container[fieldname] = value end return container[fieldname] end local function accessor(name, value) local kind = premake.fields[name].kind local scope = premake.fields[name].scope local allowed = premake.fields[name].allowed if (kind == "string") then return premake.setstring(scope, name, value, allowed) elseif (kind == "path") then if value then value = path.getabsolute(value) end return premake.setstring(scope, name, value) elseif (kind == "list") then return premake.setarray(scope, name, value, allowed) elseif (kind == "dirlist") then return premake.setdirarray(scope, name, value) elseif (kind == "filelist") then return premake.setfilearray(scope, name, value) end end for name,_ in pairs(premake.fields) do _G[name] = function(value) return accessor(name, value) end end function configuration(keywords) if not keywords then return premake.CurrentConfiguration end local container, err = premake.getobject("container") if (not container) then error(err, 2) end local cfg = { } table.insert(container.blocks, cfg) premake.CurrentConfiguration = cfg -- create a keyword list using just the indexed keyword items cfg.keywords = { } for _, word in ipairs(table.join({}, keywords)) do table.insert(cfg.keywords, premake.escapekeyword(word)) end -- if file patterns are specified, convert them to Lua patterns and add them too if keywords.files then for _, pattern in ipairs(table.join({}, keywords.files)) do pattern = pattern:gsub("%.", "%%.") if pattern:find("**", nil, true) then pattern = pattern:gsub("%*%*", ".*") else pattern = pattern:gsub("%*", "[^/]*") end table.insert(cfg.keywords, "^" .. pattern .. "$") end end -- initialize list-type fields to empty tables for name, field in pairs(premake.fields) do if (field.kind ~= "string" and field.kind ~= "path") then cfg[name] = { } end end return cfg end function project(name) if not name then return iif(type(premake.CurrentContainer) == "project", premake.CurrentContainer, nil) end -- identify the parent solution local sln if (type(premake.CurrentContainer) == "project") then sln = premake.CurrentContainer.solution else sln = premake.CurrentContainer end if (type(sln) ~= "solution") then error("no active solution", 2) end -- if this is a new project, create it premake.CurrentContainer = sln.projects[name] if (not premake.CurrentContainer) then local prj = { } premake.CurrentContainer = prj -- add to master list keyed by both name and index table.insert(sln.projects, prj) sln.projects[name] = prj -- attach a type setmetatable(prj, { __type = "project", }) prj.solution = sln prj.name = name prj.basedir = os.getcwd() prj.location = prj.basedir prj.uuid = os.uuid() prj.blocks = { } end -- add an empty, global configuration to the project configuration { } return premake.CurrentContainer end function solution(name) if not name then if type(premake.CurrentContainer) == "project" then return premake.CurrentContainer.solution else return premake.CurrentContainer end end premake.CurrentContainer = _SOLUTIONS[name] if (not premake.CurrentContainer) then local sln = { } premake.CurrentContainer = sln -- add to master list keyed by both name and index table.insert(_SOLUTIONS, sln) _SOLUTIONS[name] = sln -- attach a type setmetatable(sln, { __type="solution" }) sln.name = name sln.location = os.getcwd() sln.projects = { } sln.blocks = { } sln.configurations = { } end -- add an empty, global configuration configuration { } return premake.CurrentContainer end -- local requiredactionfields = { "description", "trigger", } local requiredoptionfields = { "description", "trigger" } function newaction(a) -- some sanity checking local missing for _, field in ipairs(requiredactionfields) do if (not a[field]) then missing = field end end if (missing) then error("action needs a " .. missing, 2) end -- add it to the master list premake.actions[a.trigger] = a end function newoption(opt) -- some sanity checking local missing for _, field in ipairs(requiredoptionfields) do if (not opt[field]) then missing = field end end if (missing) then error("action needs a " .. missing, 2) end -- add it to the master list premake.options[opt.trigger] = opt end newoption { trigger = "cc", value = "compiler", description = "Choose a C/C++ compiler set", allowed = { { "gcc", "GNU GCC compiler (gcc/g++)" }, { "ow", "OpenWatcom compiler" }, } } newoption { trigger = "dotnet", value = "value", description = "Choose a .NET compiler set", allowed = { { "ms", "Microsoft .NET (csc)" }, { "mono", "Novell Mono (mcs)" }, { "pnet", "Portable.NET (cscc)" }, } } newoption { trigger = "file", value = "filename", description = "Process the specified Premake script file" } newoption { trigger = "help", description = "Display this information" } newoption { trigger = "os", value = "value", description = "Generate files for a different operating system", allowed = { { "bsd", "OpenBSD, NetBSD, or FreeBSD" }, { "linux", "Linux" }, { "macosx", "Apple Mac OS X" }, { "windows", "Microsoft Windows" }, } } newoption { trigger = "scripts", value = "path", description = "Search for additional scripts on the given path" } newoption { trigger = "version", description = "Display version information" } -- premake.csc = { } local flags = { FatalWarning = "/warnaserror", Optimize = "/optimize", OptimizeSize = "/optimize", OptimizeSpeed = "/optimize", Symbols = "/debug", Unsafe = "/unsafe" } function premake.csc.getbuildaction(fcfg) local ext = path.getextension(fcfg.name):lower() if fcfg.buildaction == "Compile" or ext == ".cs" then return "Compile" elseif fcfg.buildaction == "Embed" or ext == ".resx" then return "EmbeddedResource" elseif fcfg.buildaction == "Copy" or ext == ".asax" or ext == ".aspx" then return "Content" else return "None" end end function premake.csc.getcompilervar(cfg) if (_OPTIONS.dotnet == "ms") then return "csc" elseif (_OPTIONS.dotnet == "mono") then return "gmcs" else return "cscc" end end function premake.csc.getflags(cfg) local result = table.translate(cfg.flags, flags) return result end function premake.csc.getkind(cfg) if (cfg.kind == "ConsoleApp") then return "Exe" elseif (cfg.kind == "WindowedApp") then return "WinExe" elseif (cfg.kind == "SharedLib") then return "Library" end end-- premake.gcc = { } premake.targetstyle = "linux" local cflags = { ExtraWarnings = "-Wall", FatalWarning = "-Werror", NoFramePointer = "-fomit-frame-pointer", Optimize = "-O2", OptimizeSize = "-Os", OptimizeSpeed = "-O3", Symbols = "-g", } local cxxflags = { NoExceptions = "--no-exceptions", NoRTTI = "--no-rtti", } function premake.gcc.getcppflags(cfg) -- if $(ARCH) contains multiple targets, then disable the incompatible automatic -- dependency generation. This allows building universal binaries on MacOSX, sorta. return "$(if $(word 2, $(ARCH)), , -MMD)" end function premake.gcc.getcflags(cfg) local result = table.translate(cfg.flags, cflags) if (cfg.kind == "SharedLib" and not os.is("windows")) then table.insert(result, "-fPIC") end return result end function premake.gcc.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.gcc.getldflags(cfg) local result = { } if (cfg.kind == "SharedLib") then if os.is("macosx") then result = table.join(result, { "-dynamiclib", "-flat_namespace" }) else table.insert(result, "-shared") end -- create import library for DLLs under Windows if (os.is("windows") and not cfg.flags.NoImportLib) then table.insert(result, '-Wl,--out-implib="'..premake.gettarget(cfg, "link", "linux").fullpath..'"') end end if (os.is("windows") and cfg.kind == "WindowedApp") then table.insert(result, "-mwindows") end -- OS X has a bug, see http://lists.apple.com/archives/Darwin-dev/2006/Sep/msg00084.html if (not cfg.flags.Symbols) then if (os.is("macosx")) then table.insert(result, "-Wl,-x") else table.insert(result, "-s") end end return result end function premake.gcc.getlinkflags(cfg) local result = { } for _, value in ipairs(premake.getlinks(cfg, "all", "directory")) do table.insert(result, '-L' .. _MAKE.esc(value)) end for _, value in ipairs(premake.getlinks(cfg, "all", "basename")) do table.insert(result, '-l' .. _MAKE.esc(value)) end return result end function premake.gcc.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.gcc.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-I" .. _MAKE.esc(dir)) end return result end -- premake.ow = { } premake.ow.targetstyle = "windows" local cflags = { ExtraWarnings = "-wx", FatalWarning = "-we", Optimize = "-ox", OptimizeSize = "-os", OptimizeSpeed = "-ot", Symbols = "-d2", } local cxxflags = { NoExceptions = "-xd", NoRTTI = "-xr", } function premake.ow.getcppflags(cfg) return "" end function premake.ow.getcflags(cfg) local result = table.translate(cfg.flags, cflags) if (cfg.flags.Symbols) then table.insert(result, "-hw") -- Watcom debug format for Watcom debugger end return result end function premake.ow.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.ow.getldflags(cfg) local result = { } if (cfg.flags.Symbols) then table.insert(result, "op symf") end return result end function premake.ow.getlinkflags(cfg) local result = { } return result end function premake.ow.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.ow.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, '-I "' .. dir .. '"') end return result end -- function premake.checkoptions() for key, value in pairs(_OPTIONS) do -- is this a valid option? local opt = premake.options[key] if (not opt) then return false, "invalid option '" .. key .. "'" end -- does it need a value? if (opt.value and value == "") then return false, "no value specified for option '" .. key .. "'" end -- is the value allowed? if (opt.allowed) then for _, match in ipairs(opt.allowed) do if (match[1] == value) then return true end end return false, "invalid value '" .. value .. "' for option '" .. key .. "'" end end return true end function premake.checkprojects() local action = premake.actions[_ACTION] for _, sln in ipairs(_SOLUTIONS) do -- every solution must have at least one project if (#sln.projects == 0) then return nil, "solution '" .. sln.name .. "' needs at least one project" end -- every solution must provide a list of configurations if (#sln.configurations == 0) then return nil, "solution '" .. sln.name .. "' needs configurations" end for prj in premake.eachproject(sln) do -- every project must have a language if (not prj.language) then return nil, "project '" ..prj.name .. "' needs a language" end -- and the action must support it if (action.valid_languages) then if (not table.contains(action.valid_languages, prj.language)) then return nil, "the " .. action.shortname .. " action does not support " .. prj.language .. " projects" end end for cfg in premake.eachconfig(prj) do -- every config must have a kind if (not cfg.kind) then return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfgname .. "'" end -- and the action must support it if (action.valid_kinds) then if (not table.contains(action.valid_kinds, cfg.kind)) then return nil, "the " .. action.shortname .. " action does not support " .. cfg.kind .. " projects" end end end end end return true end function premake.checktools() local action = premake.actions[_ACTION] if (not action.valid_tools) then return true end for tool, values in pairs(action.valid_tools) do if (_OPTIONS[tool]) then if (not table.contains(values, _OPTIONS[tool])) then return nil, "the " .. action.shortname .. " action does not support /" .. tool .. "=" .. _OPTIONS[tool] .. " (yet)" end else _OPTIONS[tool] = values[1] end end return true end -- function premake.showhelp() -- sort the lists of actions and options into alphabetical order actions = { } for name,_ in pairs(premake.actions) do table.insert(actions, name) end table.sort(actions) options = { } for name,_ in pairs(premake.options) do table.insert(options, name) end table.sort(options) -- display the basic usage printf("Premake %s, a build script generator", _PREMAKE_VERSION) printf(_PREMAKE_COPYRIGHT) printf("%s %s", _VERSION, _COPYRIGHT) printf("") printf("Usage: premake4 [options] action [arguments]") printf("") -- display all options printf("OPTIONS") printf("") for _,name in ipairs(options) do local opt = premake.options[name] local trigger = opt.trigger local description = opt.description if (opt.value) then trigger = trigger .. "=" .. opt.value end if (opt.allowed) then description = description .. "; one of:" end printf(" --%-15s %s", trigger, description) if (opt.allowed) then table.sort(opt.allowed, function(a,b) return a[1] < b[1] end) for _, value in ipairs(opt.allowed) do printf(" %-14s %s", value[1], value[2]) end end printf("") end -- display all actions printf("ACTIONS") printf("") for _,name in ipairs(actions) do printf(" %-17s %s", name, premake.actions[name].description) end printf("") -- see more printf("For additional information, see http://industriousone.com/premake") end -- local scriptfile = "premake4.lua" local shorthelp = "Type 'premake4 --help' for help" local versionhelp = "premake4 (Premake Build Script Generator) %s" local function doaction(name) local action = premake.actions[name] -- walk the session objects and generate files from the templates local function generatefiles(this, templates) if (not templates) then return end for _,tmpl in ipairs(templates) do local output = true if (tmpl[3]) then output = tmpl[3](this) end if (output) then local fname = path.getrelative(os.getcwd(), premake.getoutputname(this, tmpl[1])) printf("Generating %s...", fname) local f, err = io.open(fname, "wb") if (not f) then error(err, 0) end io.output(f) -- call the template function to generate the output tmpl[2](this) io.output():close() end end end for _,sln in ipairs(_SOLUTIONS) do generatefiles(sln, action.solutiontemplates) for prj in premake.eachproject(sln) do generatefiles(prj, action.projecttemplates) end end if (action.execute) then action.execute() end end function _premake_main(scriptpath) -- if running off the disk (in debug mode), load everything -- listed in _manifest.lua; the list divisions make sure -- everything gets initialized in the proper order. if (scriptpath) then local scripts, templates, actions = dofile(scriptpath .. "/_manifest.lua") -- core code first for _,v in ipairs(scripts) do dofile(scriptpath .. "/" .. v) end -- then the templates for _,v in ipairs(templates) do local name = path.getbasename(v) _TEMPLATES[name] = premake.loadtemplatefile(scriptpath .. "/" .. v) end -- finally the actions for _,v in ipairs(actions) do dofile(scriptpath .. "/" .. v) end end -- If there is a project script available, run it to get the -- project information, available options and actions, etc. local fname = _OPTIONS["file"] or scriptfile if (os.isfile(fname)) then dofile(fname) end -- Process special options if (_OPTIONS["version"]) then printf(versionhelp, _PREMAKE_VERSION) return 1 end if (_OPTIONS["help"]) then premake.showhelp() return 1 end -- If no action was specified, show a short help message if (not _ACTION) then print(shorthelp) return 1 end -- If there wasn't a project script I've got to bail now if (not os.isfile(fname)) then error("No Premake script ("..scriptfile..") found!", 2) end -- Validate the command-line arguments. This has to happen after the -- script has run to allow for project-specific options if (not premake.actions[_ACTION]) then error("Error: no such action '".._ACTION.."'", 0) end ok, err = premake.checkoptions() if (not ok) then error("Error: " .. err, 0) end -- Sanity check the current project setup ok, err = premake.checktools() if (not ok) then error("Error: " .. err, 0) end -- work-in-progress: build the configurations print("Building configurations...") premake.buildconfigs() ok, err = premake.checkprojects() if (not ok) then error("Error: " .. err, 0) end -- Hand over control to the action printf("Running action '%s'...", _ACTION) doaction(_ACTION) print("Done.") return 0 end _TEMPLATES.codeblocks_workspace=premake.loadtemplatestring('codeblocks_workspace',[[ <% for prj in premake.eachproject(this) do %> > <% for _,dep in ipairs(premake.getdependencies(prj)) do %> <% end %> <% end %> ]])_TEMPLATES.codeblocks_cbp=premake.loadtemplatestring('codeblocks_cbp',[[<% local cc = premake[_OPTIONS.cc] %> ]])_TEMPLATES.codelite_workspace=premake.loadtemplatestring('codelite_workspace',[[ <% for i,prj in ipairs(this.projects) do %> " /> <% end %> <% for _, cfgname in ipairs(this.configurations) do %> <% for _,prj in ipairs(this.projects) do %> <% end %> <% end %> ]])_TEMPLATES.codelite_project=premake.loadtemplatestring('codelite_project',[[ <% premake.walksources(this, this.files, _CODELITE.files) %> <% for cfg in premake.eachconfig(this) do %> " DebuggerType="GNU gdb debugger" Type="<%= _CODELITE.kind(cfg.kind) %>"> "/> "> <% for _,v in ipairs(cfg.includedirs) do %> <% end %> <% for _,v in ipairs(cfg.defines) do %> <% end %> "> <% for _,v in ipairs(premake.getlinks(cfg, "all", "directory")) do %> <% end %> <% for _,v in ipairs(premake.getlinks(cfg, "all", "basename")) do %> <% end %> <% if premake.findfile(cfg, ".rc") then %> <%= table.concat(cfg.resoptions, ";") %>"> <% for _,v in ipairs(table.join(cfg.includedirs, cfg.resincludedirs)) do %> <% end %> <% else %> <% end %> <% if #cfg.prebuildcommands > 0 then %> <% for _,v in ipairs(cfg.prebuildcommands) do %> <%= premake.esc(v) %> <% end %> <% end %> <% if #cfg.postbuildcommands > 0 then %> <% for _,v in ipairs(cfg.postbuildcommands) do %> <%= premake.esc(v) %> <% end %> <% end %> None <%end %> <% for _,cfgname in ipairs(this.configurations) do %> <% for _,dep in ipairs(premake.getdependencies(this)) do %> <% end %> <% end %> ]])_TEMPLATES.make_solution=premake.loadtemplatestring('make_solution',[[# <%= premake.actions[_ACTION].shortname %> solution makefile autogenerated by Premake # Usage: make [ config=config_name ] # Where {config_name} is one of: <%= table.implode(this.configurations, '"', '"', ', '):lower() %>. ifndef config config=<%= _MAKE.esc(this.configurations[1]:lower()) %> endif export config PROJECTS := <%= table.concat(_MAKE.esc(table.extract(this.projects, "name")), " ") %> .PHONY: all clean $(PROJECTS) all: $(PROJECTS) <% for _,prj in ipairs(this.projects) do %> <% for cfg in premake.eachconfig(prj) do %> ifeq ($(config),<%= _MAKE.esc(cfg.name:lower())%>) DEPENDENCIES := <%= table.concat(_MAKE.esc(table.extract(premake.getdependencies(cfg), "name")), " ") %> endif <% end %> <%= _MAKE.esc(prj.name) %>: ${DEPENDENCIES} @echo ==== Building <%= prj.name %> ==== @${MAKE} --no-print-directory -C <%=_MAKE.esc(path.getrelative(this.location, prj.location))%> -f <%=_MAKE.esc(_MAKE.getmakefilename(prj, true))%> <% end %> clean: <% for _,prj in ipairs(this.projects) do %> @${MAKE} --no-print-directory -C <%=_MAKE.esc(path.getrelative(this.location, prj.location))%> -f <%=_MAKE.esc(_MAKE.getmakefilename(prj, true))%> clean <% end %> ]])_TEMPLATES.make_cpp=premake.loadtemplatestring('make_cpp',[[<% local cc = premake[_OPTIONS.cc] %> # <%= premake.actions[_ACTION].shortname %> project makefile autogenerated by Premake ifndef config config=<%= _MAKE.esc(this.configurations[1]:lower()) %> endif ifndef verbose SILENT = @ endif <% for cfg in premake.eachconfig(this) do %> ifeq ($(config),<%= _MAKE.esc(cfg.name:lower())%>) TARGETDIR = <%= _MAKE.esc(cfg.buildtarget.directory) %> TARGET = $(TARGETDIR)/<%= _MAKE.esc(cfg.buildtarget.name) %> OBJDIR = <%= _MAKE.esc(cfg.objectsdir) %> DEFINES += <%= table.concat(cc.getdefines(cfg.defines), " ") %> INCLUDES += <%= table.concat(cc.getincludedirs(cfg.includedirs), " ") %> CPPFLAGS += <%= cc.getcppflags(cfg) %> $(DEFINES) $(INCLUDES) CFLAGS += $(CPPFLAGS) $(ARCH) <%= table.concat(table.join(cc.getcflags(cfg), cfg.buildoptions), " ") %> CXXFLAGS += $(CFLAGS) <%= table.concat(cc.getcxxflags(cfg), " ") %> LDFLAGS += <%= table.concat(table.join(cc.getldflags(cfg), cc.getlinkflags(cfg), cfg.linkoptions), " ") %> RESFLAGS += $(DEFINES) $(INCLUDES) <%= table.concat(table.join(cc.getdefines(cfg.resdefines), cc.getincludedirs(cfg.resincludedirs), cfg.resoptions), " ") %> LDDEPS += <%= table.concat(_MAKE.esc(premake.getlinks(cfg, "siblings", "fullpath")), " ") %> <% if cfg.kind == "StaticLib" then %> LINKCMD = ar -rcs $(TARGET) $(OBJECTS) <% else %> LINKCMD = $(<%= iif(cfg.language == "C", "CC", "CXX") %>) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(ARCH) <% end %> define PREBUILDCMDS <% if #cfg.prebuildcommands > 0 then %> @echo Running pre-build commands <%= table.implode(cfg.prebuildcommands, "", "", "\n\t") %> <% end %> endef define PRELINKCMDS <% if #cfg.prelinkcommands > 0 then %> @echo Running pre-link commands <%= table.implode(cfg.prelinkcommands, "", "", "\n\t") %> <% end %> endef define POSTBUILDCMDS <% if #cfg.postbuildcommands > 0 then %> @echo Running post-build commands <%= table.implode(cfg.postbuildcommands, "", "", "\n\t") %> <% end %> endef endif <% end %> OBJECTS := \ <% for _, file in ipairs(this.files) do %> <% if path.iscppfile(file) then %> $(OBJDIR)/<%= _MAKE.esc(path.getbasename(file)) %>.o \ <% end %> <% end %> RESOURCES := \ <% for _, file in ipairs(this.files) do %> <% if path.isresourcefile(file) then %> $(OBJDIR)/<%= _MAKE.esc(path.getbasename(file)) %>.res \ <% end %> <% end %> SHELLTYPE := msdos ifeq (,$(ComSpec)$(COMSPEC)) SHELLTYPE := posix endif ifeq (/bin,$(findstring /bin,$(SHELL))) SHELLTYPE := posix endif ifeq (posix,$(SHELLTYPE)) define MKDIR_RULE @echo Creating $@ $(SILENT) mkdir -p $@ endef else define MKDIR_RULE @echo Creating $@ $(SILENT) mkdir $(subst /,\\,$@) endef endif .PHONY: clean prebuild prelink <% if os.is("MacOSX") and this.kind == "WindowedApp" then %> all: $(TARGETDIR) $(OBJDIR) prebuild $(OBJECTS) $(RESOURCES) prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist <% else %> all: $(TARGETDIR) $(OBJDIR) prebuild $(OBJECTS) $(RESOURCES) prelink $(TARGET) <% end %> $(TARGET): $(OBJECTS) $(LDDEPS) $(RESOURCES) @echo Linking <%= this.name %> @$(LINKCMD) $(POSTBUILDCMDS) $(TARGETDIR): $(MKDIR_RULE) $(OBJDIR): $(MKDIR_RULE) <% if os.is("MacOSX") and this.kind == "WindowedApp" then %> $(dir $(TARGETDIR))PkgInfo: $(dir $(TARGETDIR))Info.plist: <% end %> clean: @echo Cleaning <%= this.name %> ifeq (posix,$(SHELLTYPE)) $(SILENT) rm -f $(TARGET) $(SILENT) rm -rf $(OBJDIR) else $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) endif prebuild: $(PREBUILDCMDS) prelink: $(PRELINKCMDS) <% for _, file in ipairs(this.files) do %> <% if path.iscppfile(file) then %> $(OBJDIR)/<%= _MAKE.esc(path.getbasename(file)) %>.o: <%= _MAKE.esc(file) %> @echo $(notdir $<) <% if (path.iscfile(file)) then %> $(SILENT) $(CC) $(CFLAGS) -o $@ -c $< <% else %> $(SILENT) $(CXX) $(CXXFLAGS) -o $@ -c $< <% end %> <% elseif (path.getextension(file) == ".rc") then %> $(OBJDIR)/<%= _MAKE.esc(path.getbasename(file)) %>.res: <%= _MAKE.esc(file) %> @echo $(notdir $<) $(SILENT) windres $< -O coff -o $@ $(RESFLAGS) <% end %> <% end %> -include $(OBJECTS:%.o=%.d) ]])_TEMPLATES.make_csharp=premake.loadtemplatestring('make_csharp',[[<% local csc = premake.csc -- -- Given a .resx resource file, builds the path to corresponding .resource -- file, matching the behavior and naming of Visual Studio. -- function getresourcefilename(cfg, fname) if path.getextension(fname) == ".resx" then local name = cfg.buildtarget.basename .. "." local dir = path.getdirectory(fname) if dir ~= "." then name = name .. path.translate(dir, ".") .. "." end return "$(OBJDIR)/" .. name .. path.getbasename(fname) .. ".resources" else return fname end end -- Do some processing up front: build a list of configuration-dependent libraries. -- Libraries that are built to a location other than $(TARGETDIR) will need to -- be copied so they can be found at runtime. local cfglibs = { } local cfgpairs = { } local anycfg for cfg in premake.eachconfig(this) do anycfg = cfg cfglibs[cfg] = premake.getlinks(cfg, "siblings", "fullpath") cfgpairs[cfg] = { } for _, fname in ipairs(cfglibs[cfg]) do if path.getdirectory(fname) ~= cfg.buildtarget.directory then cfgpairs[cfg]["$(TARGETDIR)/"..path.getname(fname)] = fname end end end -- sort the files into categories, based on their build action local sources = {} local embedded = { } local copypairs = { } for fcfg in premake.eachfile(this) do local action = csc.getbuildaction(fcfg) if action == "Compile" then table.insert(sources, fcfg.name) elseif action == "EmbeddedResource" then table.insert(embedded, fcfg.name) elseif action == "Content" then copypairs["$(TARGETDIR)/"..path.getname(fcfg.name)] = fcfg.name elseif path.getname(fcfg.name):lower() == "app.config" then copypairs["$(TARGET).config"] = fcfg.name end end -- Any assemblies that are on the library search paths should be copied -- to $(TARGETDIR) so they can be found at runtime local paths = table.translate(this.libdirs, function(v) return path.join(this.basedir, v) end) paths = table.join({this.basedir}, paths) for _, libname in ipairs(premake.getlinks(this, "system", "fullpath")) do local libdir = os.pathsearch(libname..".dll", unpack(paths)) if (libdir) then local target = "$(TARGETDIR)/"..path.getname(libname) local source = path.getrelative(this.basedir, path.join(libdir, libname))..".dll" copypairs[target] = source end end -- end of preprocessing -- %> # <%= premake.actions[_ACTION].shortname %> project makefile autogenerated by Premake ifndef config config=<%= _MAKE.esc(this.configurations[1]:lower()) %> endif ifndef verbose SILENT = @ endif ifndef CSC CSC=<%= csc.getcompilervar(this) %> endif ifndef RESGEN RESGEN=resgen endif <% for cfg in premake.eachconfig(this) do %> ifeq ($(config),<%= _MAKE.esc(cfg.name:lower())%>) TARGETDIR := <%= _MAKE.esc(cfg.buildtarget.directory) %> OBJDIR := <%= _MAKE.esc(cfg.objectsdir) %> DEPENDS := <%= table.concat(_MAKE.esc(premake.getlinks(cfg, "dependencies", "fullpath")), " ") %> REFERENCES := <%= table.implode(_MAKE.esc(cfglibs[cfg]), "/r:", "", " ") %> FLAGS += <%= table.concat(csc.getflags(cfg), " ") %> <%= table.implode(cfg.defines, "/d:", "", " ") %> define PREBUILDCMDS <% if #cfg.prebuildcommands > 0 then %> @echo Running pre-build commands <%= table.implode(cfg.prebuildcommands, "", "", "\n\t") %> <% end %> endef define PRELINKCMDS <% if #cfg.prelinkcommands > 0 then %> @echo Running pre-link commands <%= table.implode(cfg.prelinkcommands, "", "", "\n\t") %> <% end %> endef define POSTBUILDCMDS <% if #cfg.postbuildcommands > 0 then %> @echo Running post-build commands <%= table.implode(cfg.postbuildcommands, "", "", "\n\t") %> <% end %> endef endif <% end %> # To maintain compatibility with VS.NET, these values must be set at the project level TARGET = $(TARGETDIR)/<%= _MAKE.esc(this.buildtarget.name) %> FLAGS += /t:<%= csc.getkind(this):lower() %> <%= table.implode(_MAKE.esc(this.libdirs), "/lib:", "", " ") %> REFERENCES += <%= table.implode(_MAKE.esc(premake.getlinks(this, "system", "basename")), "/r:", ".dll", " ") %> SOURCES := \ <% for _, fname in ipairs(sources) do %> <%= _MAKE.esc(path.translate(fname)) %> \ <% end %> EMBEDFILES := \ <% for _, fname in ipairs(embedded) do %> <%= _MAKE.esc(getresourcefilename(this, fname)) %> \ <% end %> COPYFILES += \ <% for target, source in pairs(cfgpairs[anycfg]) do %> <%= _MAKE.esc(target) %> \ <% end %> <% for target, source in pairs(copypairs) do %> <%= _MAKE.esc(target) %> \ <% end %> SHELLTYPE := msdos ifeq (,$(ComSpec)$(COMSPEC)) SHELLTYPE := posix endif ifeq (/bin,$(findstring /bin,$(SHELL))) SHELLTYPE := posix endif ifeq (posix,$(SHELLTYPE)) define MKDIR_RULE @echo Creating $@ $(SILENT) mkdir -p $@ endef define COPY_RULE @echo Copying $(notdir $@) $(SILENT) cp -fR $^ $@ endef else define MKDIR_RULE @echo Creating $@ $(SILENT) mkdir $(subst /,\\,$@) endef define COPY_RULE @echo Copying $(notdir $@) $(SILENT) copy /Y $(subst /,\\,$^) $(subst /,\\,$@) endef endif .PHONY: clean prebuild prelink all: $(TARGETDIR) $(OBJDIR) prebuild $(EMBEDFILES) $(COPYFILES) prelink $(TARGET) $(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS) $(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) $(SOURCES) $(patsubst %,/resource:%,$(EMBEDFILES)) $(POSTBUILDCMDS) $(TARGETDIR): $(MKDIR_RULE) $(OBJDIR): $(MKDIR_RULE) clean: @echo Cleaning <%= this.name %> ifeq (posix,$(SHELLTYPE)) $(SILENT) rm -f $(TARGETDIR)/<%= this.buildtarget.basename %>.* $(COPYFILES) $(SILENT) rm -rf $(OBJDIR) else $(SILENT) if exist $(subst /,\\,$(TARGETDIR)/<%= this.buildtarget.basename %>.*) del $(subst /,\\,$(TARGETDIR)/<%= this.buildtarget.basename %>.*) <% for target, source in pairs(cfgpairs[anycfg]) do %> $(SILENT) if exist $(subst /,\\,<%= target %>) del $(subst /,\\,<%= target %>) <% end %> <% for target, source in pairs(copypairs) do %> $(SILENT) if exist $(subst /,\\,<%= target %>) del $(subst /,\\,<%= target %>) <% end %> $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) endif prebuild: $(PREBUILDCMDS) prelink: $(PRELINKCMDS) # Per-configuration copied file rules <% for cfg in premake.eachconfig(this) do %> ifeq ($(config),<%= _MAKE.esc(cfg.name:lower())%>) <% for target, source in pairs(cfgpairs[cfg]) do %> <%= _MAKE.esc(target) %>: <%= _MAKE.esc(source) %> $(COPY_RULE) <% end %> endif <% end %> # Copied file rules <% for target, source in pairs(copypairs) do %> <%= _MAKE.esc(target) %>: <%= _MAKE.esc(source) %> $(COPY_RULE) <% end %> # Embedded file rules <% for _, fname in ipairs(embedded) do if path.getextension(fname) == ".resx" then %> <%= _MAKE.esc(getresourcefilename(this, fname)) %>: <%= _MAKE.esc(fname) %> $(SILENT) $(RESGEN) $^ $@ <% end end %> ]])_TEMPLATES.vs2002_solution=premake.loadtemplatestring('vs2002_solution',[[<% eol = "\r\n" %> Microsoft Visual Studio Solution File, Format Version 7.00 <% for prj in premake.eachproject(this) do %> Project("{<%=_VS.tool(prj)%>}") = "<%=prj.name%>", "<%=path.translate(path.getrelative(this.location, _VS.projectfile(prj)))%>", "{<%=prj.uuid%>}" EndProject <% end %> Global GlobalSection(SolutionConfiguration) = preSolution <% for i,cfgname in ipairs(this.configurations) do %> ConfigName.<%= i-1 %> = <%= cfgname %> <% end %> EndGlobalSection GlobalSection(ProjectDependencies) = postSolution <% for prj in premake.eachproject(this) do %> <% for i,dep in ipairs(premake.getdependencies(prj)) do %> {<%= prj.uuid %>}.<%= i - 1 %> = {<%= dep.uuid %>} <% end %> <% end %> EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution <% for prj in premake.eachproject(this) do %> <% for i,cfgname in ipairs(this.configurations) do %> {<%=prj.uuid%>}.<%=cfgname%>.ActiveCfg = <%=cfgname%>|<%=_VS.arch(prj)%> {<%=prj.uuid%>}.<%=cfgname%>.Build.0 = <%=cfgname%>|<%=_VS.arch(prj)%> <% end %> <% end %> EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal ]])_TEMPLATES.vs2002_csproj=premake.loadtemplatestring('vs2002_csproj',[[<% eol = "\r\n" local csc = premake.csc -- -- Figure out what elements a particular file need in its item block, -- based on its build action and any related files in the project. -- function getelements(prj, action, fname) if action == "Compile" and fname:endswith(".cs") then return "SubTypeCode" end if action == "EmbeddedResource" and fname:endswith(".resx") then -- is there a matching *.cs file? local basename = fname:sub(1, -6) local testname = path.getname(basename .. ".cs") if premake.findfile(prj, testname) then return "Dependency", testname end end return "None" end -- end of preprocessing; template starts here -- %> " SchemaVersion = "<%= iif(_ACTION == "vs2002", "1.0", "2.0") %>" ProjectGuid = "{<%= this.uuid %>}" > NoStandardLibraries = "false" <% end %> OutputType = "<%= csc.getkind(this) %>" <% if _ACTION == "vs2003" then %> PreBuildEvent = "" PostBuildEvent = "" <% end %> RootNamespace = "<%= this.buildtarget.basename %>" <% if _ACTION == "vs2003" then %> RunPostBuildEvent = "OnBuildSuccess" <% end %> StartupObject = "" > <% for cfg in premake.eachconfig(this) do %> " BaseAddress = "285212672" CheckForOverflowUnderflow = "false" ConfigurationOverrideFile = "" DefineConstants = "<%= premake.esc(table.concat(cfg.defines, ";")) %>" DocumentationFile = "" DebugSymbols = "<%= iif(cfg.flags.Symbols, "true", "false") %>" FileAlignment = "4096" IncrementalBuild = "false" <% if _ACTION == "vs2003" then %> NoStdLib = "false" NoWarn = "" <% end %> Optimize = "<%= iif(cfg.flags.Optimize or cfg.flags.OptimizeSize or cfg.flags.OptimizeSpeed, "true", "false") %>" OutputPath = "<%= premake.esc(cfg.buildtarget.directory) %>" RegisterForComInterop = "false" RemoveIntegerChecks = "false" TreatWarningsAsErrors = "<%= iif(cfg.flags.FatalWarnings, "true", "false") %>" WarningLevel = "4" /> <% end %> <% for _, prj in ipairs(premake.getlinks(this, "siblings", "object")) do %> <% end %> <% for _, linkname in ipairs(premake.getlinks(this, "system", "fullpath")) do %> HintPath = "<%= path.translate(linkname, "\\") %>" <% end %> /> <% end %> <% for fcfg in premake.eachfile(this) do local action = csc.getbuildaction(fcfg) local fname = path.translate(premake.esc(fcfg.name), "\\") local elements, dependency = getelements(this, action, fcfg.name) %> DependentUpon = "<%= premake.esc(path.translate(dependency, "\\")) %>" <% end %> <% if elements == "SubTypeCode" then %> SubType = "Code" <% end %> /> <% end %> ]])_TEMPLATES.vs2002_csproj_user=premake.loadtemplatestring('vs2002_csproj_user',[[<% eol = "\r\n" local csc = premake.csc %> "> <% for cfg in premake.eachconfig(this) do %> <% end %> ]])_TEMPLATES.vs2003_solution=premake.loadtemplatestring('vs2003_solution',[[<% eol = "\r\n" %> Microsoft Visual Studio Solution File, Format Version 8.00 <% for prj in premake.eachproject(this) do %> Project("{<%=_VS.tool(prj)%>}") = "<%=prj.name%>", "<%=path.translate(path.getrelative(this.location, _VS.projectfile(prj)))%>", "{<%=prj.uuid%>}" <% local deps = premake.getdependencies(prj); if #deps > 0 then %> ProjectSection(ProjectDependencies) = postProject <% for _,dep in ipairs(deps) do %> {<%= dep.uuid %>} = {<%= dep.uuid %>} <% end %> EndProjectSection <% end %> EndProject <% end %> Global GlobalSection(SolutionConfiguration) = preSolution <% for i,cfgname in ipairs(this.configurations) do %> <%= cfgname %> = <%= cfgname %> <% end %> EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution <% for prj in premake.eachproject(this) do %> <% for i,cfgname in ipairs(this.configurations) do %> {<%=prj.uuid%>}.<%=cfgname%>.ActiveCfg = <%=cfgname%>|<%=_VS.arch(prj)%> {<%=prj.uuid%>}.<%=cfgname%>.Build.0 = <%=cfgname%>|<%=_VS.arch(prj)%> <% end %> <% end %> EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal ]])_TEMPLATES.vs2005_solution=premake.loadtemplatestring('vs2005_solution',[[<% eol = "\r\n" %> <%= "\239\187\191" %> <% local hascpp, hasdotnet %> <% if _ACTION == "vs2005" then %> Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 <% elseif _ACTION == "vs2008" then %> Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 <% end %> <% for prj in premake.eachproject(this) do %> <% if (prj.language == "C" or prj.language == "C++") then hascpp = true end %> <% if (prj.language == "C#") then hasdotnet = true end %> Project("{<%=_VS.tool(prj)%>}") = "<%=prj.name%>", "<%=path.translate(path.getrelative(this.location, _VS.projectfile(prj)),"\\")%>", "{<%=prj.uuid%>}" <% local deps = premake.getdependencies(prj); if #deps > 0 then %> ProjectSection(ProjectDependencies) = postProject <% for _,dep in ipairs(deps) do %> {<%= dep.uuid %>} = {<%= dep.uuid %>} <% end %> EndProjectSection <% end %> EndProject <% end %> Global GlobalSection(SolutionConfigurationPlatforms) = preSolution <% for _, cfgname in ipairs(this.configurations) do %> <% if hasdotnet then %> <%= cfgname %>|Any CPU = <%= cfgname %>|Any CPU <% end; if hasdotnet and hascpp then %> <%= cfgname %>|Mixed Platforms = <%= cfgname %>|Mixed Platforms <% end; if hascpp then %> <%= cfgname %>|Win32 = <%= cfgname %>|Win32 <% end %> <% end %> EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution <% for prj in premake.eachproject(this) do %> <% for _, cfgname in ipairs(this.configurations) do %> <% if hasdotnet then %> {<%= prj.uuid %>}.<%= cfgname %>|Any CPU.ActiveCfg = <%= cfgname %>|<%= _VS.arch(prj) %> <% if (prj.language ~= "C" and prj.language ~= "C++") then %> {<%= prj.uuid %>}.<%= cfgname %>|Any CPU.Build.0 = <%= cfgname %>|<%= _VS.arch(prj) %> <% end %> <% end; if (hasdotnet and hascpp) then %> {<%= prj.uuid %>}.<%= cfgname %>|Mixed Platforms.ActiveCfg = <%= cfgname %>|<%= _VS.arch(prj) %> {<%= prj.uuid %>}.<%= cfgname %>|Mixed Platforms.Build.0 = <%= cfgname %>|<%= _VS.arch(prj) %> <% end; if (hascpp) then %> {<%= prj.uuid %>}.<%= cfgname %>|Win32.ActiveCfg = <%= cfgname %>|<%= _VS.arch(prj) %> <% if (prj.language == "C" or prj.language == "C++") then %> {<%= prj.uuid %>}.<%= cfgname %>|Win32.Build.0 = <%= cfgname %>|<%= _VS.arch(prj) %> <% end %> <% end %> <% end %> <% end %> EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ]])_TEMPLATES.vs2005_csproj=premake.loadtemplatestring('vs2005_csproj',[[<% eol = "\r\n" local csc = premake.csc -- translate the action to format and tool versions local vsversion, toolversion if _ACTION == "vs2005" then vsversion = "8.0.50727" toolversion = nil elseif _ACTION == "vs2008" then vsversion = "9.0.50727" toolversion = "3.5" end -- -- Figure out what elements a particular source code file need in its item -- block, based on its build action and any related files in the project. -- function getelements(prj, action, fname) if action == "Compile" and fname:endswith(".cs") then if fname:endswith(".Designer.cs") then -- is there a matching *.cs file? local basename = fname:sub(1, -13) local testname = basename .. ".cs" if premake.findfile(prj, testname) then return "Dependency", testname end -- is there a matching *.resx file? testname = basename .. ".resx" if premake.findfile(prj, testname) then return "AutoGen", testname end else -- is there a *.Designer.cs file? local basename = fname:sub(1, -4) local testname = basename .. ".Designer.cs" if premake.findfile(prj, testname) then return "SubTypeForm" end end end if action == "EmbeddedResource" and fname:endswith(".resx") then -- is there a matching *.cs file? local basename = fname:sub(1, -6) local testname = path.getname(basename .. ".cs") if premake.findfile(prj, testname) then if premake.findfile(prj, basename .. ".Designer.cs") then return "DesignerType", testname else return "Dependency", testname end else -- is there a matching *.Designer.cs? testname = path.getname(basename .. ".Designer.cs") if premake.findfile(prj, testname) then return "AutoGenerated" end end end if action == "Content" then return "CopyNewest" end return "None" end -- end of preprocessing; template starts here -- %> <% if toolversion then %> <% else %> <% end %> <%= premake.esc(this.solution.configurations[1]) %> AnyCPU <%= vsversion %> 2.0 {<%= this.uuid %>} <%= csc.getkind(this) %> Properties <%= this.buildtarget.basename %> <%= this.buildtarget.basename %> <% for cfg in premake.eachconfig(this) do %> <% if cfg.flags.Symbols then %> true full <% else %> pdbonly <% end %> <%= iif(cfg.flags.Optimize or cfg.flags.OptimizeSize or cfg.flags.OptimizeSpeed, "true", "false") %> <%= cfg.buildtarget.directory %> <%= table.concat(premake.esc(cfg.defines), ";") %> prompt 4 <% if cfg.flags.Unsafe then %> true <% end %> <% if cfg.flags.FatalWarnings then %> true <% end %> <% end %> <% for _, prj in ipairs(premake.getlinks(this, "siblings", "object")) do %> "> {<%= prj.uuid %>} <%= premake.esc(prj.name) %> <% end %> <% for _, linkname in ipairs(premake.getlinks(this, "system", "basename")) do %> <% end %> <% for fcfg in premake.eachfile(this) do local action = csc.getbuildaction(fcfg) local fname = path.translate(premake.esc(fcfg.name), "\\") local elements, dependency = getelements(this, action, fcfg.name) if elements == "None" then %> <<%= action %> Include="<%= fname %>" /> <% else %> <<%= action %> Include="<%= fname %>"> <% if elements == "AutoGen" then %> True <% elseif elements == "AutoGenerated" then %> Designer ResXFileCodeGenerator <%= premake.esc(path.getbasename(fcfg.name)) %>.Designer.cs <% elseif elements == "SubTypeDesigner" then %> Designer <% elseif elements == "SubTypeForm" then %> Form <% elseif elements == "PreserveNewest" then %> PreserveNewest <% end %> <% if dependency then %> <%= path.translate(premake.esc(dependency), "\\") %> <% end %> > <% end end %> ]])_TEMPLATES.vs2005_csproj_user=premake.loadtemplatestring('vs2005_csproj_user',[[<% eol = "\r\n" %> <%= table.concat(table.translate(this.libdirs, function(v) return path.translate(path.getabsolute(this.location.."/"..v),"\\") end), ";") %> ]])_TEMPLATES.vs200x_vcproj=premake.loadtemplatestring('vs200x_vcproj',[[<% eol = "\r\n" %> Version="7.00" <% elseif _ACTION == "vs2003" then %> Version="7.10" <% elseif _ACTION == "vs2005" then %> Version="8.00" <% elseif _ACTION == "vs2008" then %> Version="9.00" <% end %> Name="<%= premake.esc(this.name) %>" ProjectGUID="{<%= this.uuid %>}" <% if _ACTION > "vs2003" then %> RootNamespace="<%= this.name %>" <% end %> Keyword="<%= iif(this.flags.Managed, "ManagedCProj", "Win32Proj") %>" > <% if _ACTION > "vs2003" then %> <% end %> <% for cfg in premake.eachconfig(this) do %> ManagedExtensions="true" <% end %> > <% for _,block in ipairs(_VS[_ACTION]) do %> <% if (block == "VCALinkTool") then %> <% elseif (block == "VCAppVerifierTool") then %> <% elseif (block == "VCAuxiliaryManagedWrapperGeneratorTool") then %> <% elseif (block == "VCBscMakeTool") then %> <% elseif (block == "VCCLCompilerTool") then %> 0 then %> AdditionalOptions="<%= table.concat(premake.esc(cfg.buildoptions), " ") %>" <% end %> Optimization="<%= _VS.optimization(cfg) %>" <% if cfg.flags.NoFramePointer then %> OmitFramePointers="<%= _VS.bool(true) %>" <% end %> <% if #cfg.includedirs > 0 then %> AdditionalIncludeDirectories="<%= table.concat(premake.esc(cfg.includedirs), ";") %>" <% end %> <% if #cfg.defines > 0 then %> PreprocessorDefinitions="<%= table.concat(premake.esc(cfg.defines), ";") %>" <% end %> <% if cfg.flags.Symbols and not cfg.flags.Managed then %> MinimalRebuild="<%= _VS.bool(true) %>" <% end %> <% if cfg.flags.NoExceptions then %> ExceptionHandling="<%= iif(_ACTION < "vs2005", "FALSE", 0) %>" <% elseif cfg.flags.SEH and _ACTION > "vs2003" then %> ExceptionHandling="2" <% end %> <% if _VS.optimization(cfg) == 0 and not cfg.flags.Managed then %> BasicRuntimeChecks="3" <% end %> <% if _VS.optimization(cfg) ~= 0 then %> StringPooling="<%= _VS.bool(true) %>" <% end %> RuntimeLibrary="<%= _VS.runtime(cfg) %>" EnableFunctionLevelLinking="<%= _VS.bool(true) %>" <% if _ACTION < "vs2005" and not cfg.flags.NoRTTI then %> RuntimeTypeInfo="<%= _VS.bool(true) %>" <% elseif _ACTION > "vs2003" and cfg.flags.NoRTTI then %> RuntimeTypeInfo="<%= _VS.bool(false) %>" <% end %> <% if cfg.flags.NativeWChar then %> TreatWChar_tAsBuiltInType="<%= _VS.bool(true) %>" <% elseif cfg.flags.NoNativeWChar then %> TreatWChar_tAsBuiltInType="<%= _VS.bool(false) %>" <% end %> <% if not cfg.flags.NoPCH and cfg.pchheader then %> UsePrecompiledHeader="<%= iif(_ACTION < "vs2005", 3, 2) %>" PrecompiledHeaderThrough="<%= cfg.pchheader %>" <% else %> UsePrecompiledHeader="<%= iif(_ACTION > "vs2003" or cfg.flags.NoPCH, 0, 2) %>" <% end %> WarningLevel="<%= iif(cfg.flags.ExtraWarnings, 4, 3) %>" <% if cfg.flags.FatalWarnings then %> WarnAsError="<%= _VS.bool(true) %>" <% end %> <% if _ACTION < "vs2008" and not cfg.flags.Managed then %> Detect64BitPortabilityProblems="<%= _VS.bool(not cfg.flags.No64BitChecks) %>" <% end %> ProgramDataBaseFileName="$(OutDir)\$(ProjectName).pdb" DebugInformationFormat="<%= _VS.symbols(cfg) %>" /> <% elseif (block == "VCCustomBuildTool") then %> <% elseif (block == "VCFxCopTool") then %> <% elseif (block == "VCLinkerTool") then %> Name="VCLinkerTool" <% if cfg.flags.NoImportLib then %> IgnoreImportLibrary="<%= _VS.bool(true) %>" <% end %> <% if #cfg.linkoptions > 0 then %> AdditionalOptions="<%= table.concat(premake.esc(cfg.linkoptions), " ") %>" <% end %> <% if #cfg.links > 0 then %> AdditionalDependencies="<%= table.concat(premake.getlinks(cfg, "all", "fullpath"), " ") %>" <% end %> OutputFile="$(OutDir)\<%= cfg.buildtarget.name %>" LinkIncremental="<%= iif(_VS.optimization(cfg) == 0, 2, 1) %>" AdditionalLibraryDirectories="<%= table.concat(premake.esc(path.translate(cfg.libdirs)) , ";") %>" <% local deffile = premake.findfile(cfg, ".def"); if deffile then %> ModuleDefinitionFile="<%= deffile %>" <% end %> <% if cfg.flags.NoManifest then %> GenerateManifest="<%= _VS.bool(false) %>" <% end %> GenerateDebugInformation="<%= _VS.bool(_VS.symbols(cfg) ~= 0) %>" <% if _VS.symbols(cfg) ~= 0 then %> ProgramDatabaseFile="$(OutDir)\$(ProjectName).pdb" <% end %> SubSystem="<%= iif(cfg.kind == "ConsoleApp", 1, 2) %>" <% if _VS.optimization(cfg) ~= 0 then %> OptimizeReferences="2" EnableCOMDATFolding="2" <% end %> <% if (cfg.kind == "ConsoleApp" or cfg.kind == "WindowedApp") and not cfg.flags.WinMain then %> EntryPointSymbol="mainCRTStartup" <% end %> <% if cfg.kind == "SharedLib" then %> <% local implibname = path.translate(premake.gettarget(cfg, "link", "windows").fullpath, "\\") %> ImportLibrary="<%= iif(cfg.flags.NoImportLib, cfg.objectsdir.."\\"..path.getname(implibname), implibname) %>" <% end %> TargetMachine="1" <% else %> Name="VCLibrarianTool" OutputFile="$(OutDir)\<%= cfg.buildtarget.name %>" <% end %> /> <% elseif (block == "VCManagedResourceCompilerTool") then %> <% elseif (block == "VCManagedWrapperGeneratorTool") then %> <% elseif (block == "VCManifestTool") then %> <% elseif (block == "VCMIDLTool") then %> <% elseif (block == "VCPreBuildEventTool") then %> 0 then %> CommandLine="<%= premake.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n")) %>" <% end %> /> <% elseif (block == "VCPreLinkEventTool") then %> 0 then %> CommandLine="<%= premake.esc(table.implode(cfg.prelinkcommands, "", "", "\r\n")) %>" <% end %> /> <% elseif (block == "VCPostBuildEventTool") then %> 0 then %> CommandLine="<%= premake.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n")) %>" <% end %> /> <% elseif (block == "VCResourceCompilerTool") then %> 0 then %> AdditionalOptions="<%= table.concat(premake.esc(cfg.resoptions), " ") %>" <% end %> <% if #cfg.defines > 0 or #cfg.resdefines > 0 then %> PreprocessorDefinitions="<%= table.concat(premake.esc(table.join(cfg.defines, cfg.resdefines)), ";") %>" <% end %> <% if #cfg.includedirs > 0 or #cfg.resincludedirs > 0 then %> AdditionalIncludeDirectories="<%= table.concat(premake.esc(table.join(cfg.includedirs, cfg.resincludedirs)), ";") %>" <% end %> /> <% elseif (block == "VCWebDeploymentTool") then %> <% elseif (block == "VCWebServiceProxyGeneratorTool") then %> <% elseif (block == "VCXDCMakeTool") then %> <% elseif (block == "VCXMLDataGeneratorTool") then %> <% end %> <% end %> <% end %> <% premake.walksources(this, this.files, _VS.files) %> ]])-- local function cleantemplatefiles(this, templates) if (templates) then for _,tmpl in ipairs(templates) do local fname = premake.getoutputname(this, tmpl[1]) os.remove(fname) end end end newaction { trigger = "clean", description = "Remove all binaries and generated files", targetstyle = "windows", execute = function() local solutions = { } local projects = { } local targets = { } local cwd = os.getcwd() local function rebase(parent, dir) return path.rebase(dir, parent.location, cwd) end -- Walk the tree. Build a list of object names to pass to the cleaners, -- and delete any toolset agnostic files along the way. for _,sln in ipairs(_SOLUTIONS) do table.insert(solutions, path.join(sln.location, sln.name)) for prj in premake.eachproject(sln) do table.insert(projects, path.join(prj.location, prj.name)) if (prj.objectsdir) then os.rmdir(rebase(prj, prj.objectsdir)) end for cfg in premake.eachconfig(prj) do table.insert(targets, path.join(rebase(cfg, cfg.buildtarget.directory), cfg.buildtarget.basename)) -- remove all possible permutations of the target binary os.remove(rebase(cfg, premake.gettarget(cfg, "build", "windows").fullpath)) os.remove(rebase(cfg, premake.gettarget(cfg, "build", "linux", "linux").fullpath)) os.remove(rebase(cfg, premake.gettarget(cfg, "build", "linux", "macosx").fullpath)) if (cfg.kind == "WindowedApp") then os.rmdir(rebase(cfg, premake.gettarget(cfg, "build", "linux", "linux").fullpath .. ".app")) end -- if there is an import library, remove that too os.remove(rebase(cfg, premake.gettarget(cfg, "link", "windows").fullpath)) os.remove(rebase(cfg, premake.gettarget(cfg, "link", "linux").fullpath)) os.rmdir(rebase(cfg, cfg.objectsdir)) end end end -- Walk the tree again. Delete templated and toolset-specific files for _,action in pairs(premake.actions) do for _,sln in ipairs(_SOLUTIONS) do cleantemplatefiles(sln, action.solutiontemplates) for prj in premake.eachproject(sln) do cleantemplatefiles(prj, action.projecttemplates) end end if (type(action.onclean) == "function") then action.onclean(solutions, projects, targets) end end end, } -- newaction { trigger = "codeblocks", shortname = "Code::Blocks", description = "Code::Blocks Studio", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc", "ow" }, }, solutiontemplates = { { ".workspace", _TEMPLATES.codeblocks_workspace }, }, projecttemplates = { { ".cbp", _TEMPLATES.codeblocks_cbp }, }, onclean = function(solutions, projects, targets) for _,name in ipairs(projects) do os.remove(name .. ".depend") os.remove(name .. ".layout") end end } -- _CODELITE = { } function _CODELITE.kind(value) if (value == "ConsoleApp" or value == "WindowedApp") then return "Executable" elseif (value == "StaticLib") then return "Static Library" elseif (value == "SharedLib") then return "Dynamic Library" end end function _CODELITE.files(prj, fname, state, nestlevel) local indent = string.rep(" ", nestlevel + 1) if (state == "GroupStart") then io.write(indent .. '\n') elseif (state == "GroupEnd") then io.write(indent .. '\n') else io.write(indent .. '\n') end end newaction { trigger = "codelite", shortname = "CodeLite", description = "CodeLite (experimental)", targetstyle = "linux", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, solutiontemplates = { { ".workspace", _TEMPLATES.codelite_workspace }, }, projecttemplates = { { ".project", _TEMPLATES.codelite_project }, }, onclean = function(solutions, projects, targets) for _,name in ipairs(solutions) do os.remove(name .. "_wsp.mk") os.remove(name .. ".tags") end for _,name in ipairs(projects) do os.remove(name .. ".mk") os.remove(name .. ".list") os.remove(name .. ".out") end end } -- _MAKE = { } function _MAKE.esc(value) if (type(value) == "table") then local result = { } for _,v in ipairs(value) do table.insert(result, _MAKE.esc(v)) end return result else local result result = value:gsub(" ", "\\ ") result = result:gsub("\\", "\\\\") return result end end function _MAKE.getmakefilename(this, searchprjs) -- how many projects/solutions use this location? local count = 0 for _,sln in ipairs(_SOLUTIONS) do if (sln.location == this.location) then count = count + 1 end if (searchprjs) then for _,prj in ipairs(sln.projects) do if (prj.location == this.location) then count = count + 1 end end end end if (count == 1) then return "Makefile" else return this.name .. ".make" end end function _MAKE.getnames(tbl) local result = table.extract(tbl, "name") for k,v in pairs(result) do result[k] = _MAKE.esc(v) end return result end newaction { trigger = "gmake", shortname = "GNU Make", description = "GNU makefiles for POSIX, MinGW, and Cygwin", targetstyle = "linux", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "gcc" }, dotnet = { "mono", "ms", "pnet" }, }, solutiontemplates = { { function(this) return _MAKE.getmakefilename(this, false) end, _TEMPLATES.make_solution }, }, projecttemplates = { { function(this) return _MAKE.getmakefilename(this, true) end, _TEMPLATES.make_cpp, function(this) return this.language == "C" or this.language == "C++" end }, { function(this) return _MAKE.getmakefilename(this, true) end, _TEMPLATES.make_csharp, function(this) return this.language == "C#" end }, }, } -- _VS = { } _VS.vs2002 = { "VCCLCompilerTool", "VCCustomBuildTool", "VCLinkerTool", "VCMIDLTool", "VCPostBuildEventTool", "VCPreBuildEventTool", "VCPreLinkEventTool", "VCResourceCompilerTool", "VCWebServiceProxyGeneratorTool", "VCWebDeploymentTool" } _VS.vs2003 = { "VCCLCompilerTool", "VCCustomBuildTool", "VCLinkerTool", "VCMIDLTool", "VCPostBuildEventTool", "VCPreBuildEventTool", "VCPreLinkEventTool", "VCResourceCompilerTool", "VCWebServiceProxyGeneratorTool", "VCXMLDataGeneratorTool", "VCWebDeploymentTool", "VCManagedWrapperGeneratorTool", "VCAuxiliaryManagedWrapperGeneratorTool" } _VS.vs2005 = { "VCPreBuildEventTool", "VCCustomBuildTool", "VCXMLDataGeneratorTool", "VCWebServiceProxyGeneratorTool", "VCMIDLTool", "VCCLCompilerTool", "VCManagedResourceCompilerTool", "VCResourceCompilerTool", "VCPreLinkEventTool", "VCLinkerTool", "VCALinkTool", "VCManifestTool", "VCXDCMakeTool", "VCBscMakeTool", "VCFxCopTool", "VCAppVerifierTool", "VCWebDeploymentTool", "VCPostBuildEventTool" } _VS.vs2008 = _VS.vs2005 function _VS.onclean(solutions, projects, targets) for _,name in ipairs(solutions) do os.remove(name .. ".suo") os.remove(name .. ".ncb") end for _,name in ipairs(projects) do os.remove(name .. ".csproj.user") os.remove(name .. ".csproj.webinfo") local files = os.matchfiles(name .. ".vcproj.*.user", name .. ".csproj.*.user") for _, fname in ipairs(files) do os.remove(fname) end end for _,name in ipairs(targets) do os.remove(name .. ".pdb") os.remove(name .. ".idb") os.remove(name .. ".ilk") os.remove(name .. ".vshost.exe") os.remove(name .. ".exe.manifest") end end function _VS.arch(prj) if (prj.language == "C#") then if (_ACTION < "vs2005") then return ".NET" else return "Any CPU" end else return "Win32" end end function _VS.bool(value) if (_ACTION < "vs2005") then return iif(value, "TRUE", "FALSE") else return iif(value, "true", "false") end end function _VS.cfgtype(cfg) if (cfg.kind == "SharedLib") then return 2 elseif (cfg.kind == "StaticLib") then return 4 else return 1 end end local function output(indent, value) io.write(indent .. value .. "\r\n") end local function attrib(indent, name, value) io.write(indent .. "\t" .. name .. '="' .. value .. '"\r\n') end function _VS.files(prj, fname, state, nestlevel) local indent = string.rep("\t", nestlevel + 2) if (state == "GroupStart") then output(indent, "") elseif (state == "GroupEnd") then output(indent, "") else output(indent, "") if (not prj.flags.NoPCH and prj.pchsource == fname) then for _, cfgname in ipairs(prj.configurations) do output(indent, "\t") output(indent, "\t\t") output(indent, "\t") end end output(indent, "") end end function _VS.optimization(cfg) local result = 0 for _, value in ipairs(cfg.flags) do if (value == "Optimize") then result = 3 elseif (value == "OptimizeSize") then result = 1 elseif (value == "OptimizeSpeed") then result = 2 end end return result end function _VS.projectfile(prj) local extension if (prj.language == "C#") then extension = ".csproj" else extension = ".vcproj" end local fname = path.join(prj.location, prj.name) return fname..extension end function _VS.runtime(cfg) local debugbuild = (_VS.optimization(cfg) == 0) if (cfg.flags.StaticRuntime) then return iif(debugbuild, 1, 0) else return iif(debugbuild, 3, 2) end end function _VS.symbols(cfg) if (not cfg.flags.Symbols) then return 0 else -- Edit-and-continue does't work if optimizing or managed C++ if (cfg.flags.NoEditAndContinue or _VS.optimization(cfg) ~= 0 or cfg.flags.Managed) then return 3 else return 4 end end end function _VS.tool(prj) if (prj.language == "C#") then return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC" else return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" end end newaction { trigger = "vs2002", shortname = "Visual Studio 2002", description = "Microsoft Visual Studio 2002", targetstyle = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, solutiontemplates = { { ".sln", _TEMPLATES.vs2002_solution }, }, projecttemplates = { { ".vcproj", _TEMPLATES.vs200x_vcproj, function(this) return this.language ~= "C#" end }, { ".csproj", _TEMPLATES.vs2002_csproj, function(this) return this.language == "C#" end }, { ".csproj.user", _TEMPLATES.vs2002_csproj_user, function(this) return this.language == "C#" end }, }, onclean = _VS.onclean, } newaction { trigger = "vs2003", shortname = "Visual Studio 2003", description = "Microsoft Visual Studio 2003", targetstyle = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, solutiontemplates = { { ".sln", _TEMPLATES.vs2003_solution }, }, projecttemplates = { { ".vcproj", _TEMPLATES.vs200x_vcproj, function(this) return this.language ~= "C#" end }, { ".csproj", _TEMPLATES.vs2002_csproj, function(this) return this.language == "C#" end }, { ".csproj.user", _TEMPLATES.vs2002_csproj_user, function(this) return this.language == "C#" end }, }, onclean = _VS.onclean, } newaction { trigger = "vs2005", shortname = "Visual Studio 2005", description = "Microsoft Visual Studio 2005 (SharpDevelop, MonoDevelop)", targetstyle = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, solutiontemplates = { { ".sln", _TEMPLATES.vs2005_solution }, }, projecttemplates = { { ".vcproj", _TEMPLATES.vs200x_vcproj, function(this) return this.language ~= "C#" end }, { ".csproj", _TEMPLATES.vs2005_csproj, function(this) return this.language == "C#" end }, { ".csproj.user", _TEMPLATES.vs2005_csproj_user, function(this) return this.language == "C#" end }, }, onclean = _VS.onclean, } newaction { trigger = "vs2008", shortname = "Visual Studio 2008", description = "Microsoft Visual Studio 2008", targetstyle = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, solutiontemplates = { { ".sln", _TEMPLATES.vs2005_solution }, }, projecttemplates = { { ".vcproj", _TEMPLATES.vs200x_vcproj, function(this) return this.language ~= "C#" end }, { ".csproj", _TEMPLATES.vs2005_csproj, function(this) return this.language == "C#" end }, { ".csproj.user", _TEMPLATES.vs2005_csproj_user, function(this) return this.language == "C#" end }, }, onclean = _VS.onclean, } $Lua: Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio $ $Authors: R. Ierusalimschy, L. H. de Figueiredo & W. Celes $ $URL: www.lua.org $ no calling environmentno valueYg"@r"@r"@c"@c"@g"@c"@?*@*@*@+@+@+@N+@V+@Sl%s:%d: bad argument #%d (%s)nmethodcalling '%s' on bad self (%s)?bad argument #%d to '%s' (%s)%s expected, got %sstack overflow (%s)value expectedinvalid option '%s'_LOADEDname conflict for module '%s' cannot %s %s: %s=stdin@%sropenrbreopenreadPANIC: unprotected error in call to Lua API (%s) createresumerunningstatuswrapyield0CJ@7CI@>CiK@FCH@MC*K@RCNK@suspendednormaldead>CCCCassertcollectgarbagedofileerrorgcinfogetfenvgetmetatableloadfileloadloadstringnextpcallprintrawequalrawgetrawsetselectsetfenvsetmetatabletonumbertostringtypeunpackxpcallCE@CA@CD@C2>@CoA@C?@C>@CC@CkD@CvC@(C[B@-CmF@3C<@9C@@BC@@IC1A@PCE@WC4@@_C>@lCG=@uC G@~C(B@CTE@CF@'tostring' must return a string to 'print'base out of range__metatablenil or table expectedcannot change a protected metatablelevel must be non-negativeinvalid levelfno function environment for tail call at level %d'setfenv' cannot change environment of given objectstoprestartcollectcountstepsetpausesetstepmulCCCCCCC:too many nested functionsreader function must return a string=(load)assertion failed!%stoo many results to unpackindex out of range__tostringtruefalsenil%s: %pboolean or proxy expectedcoroutine expectedtoo many arguments to resumecannot resume %s coroutinetoo many results to resumeLua function expected_GLua 5.1_VERSIONipairspairskv__modenewproxycoroutinecontrol structure too longfunction or expression too complexconstant table overflowcode size overflowS@S@S@S@T@T@T@T@T@T@T@T@U@ U@jU@jU@jU@jU@jU@(U@KU@3V@8V@3V@3V@NV@NV@NV@NV@@V@Y@^Y@Y@Y@,Y@bY@xY@~Y@Y@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@Z@s\@\@\@\@\@\@\@\@\@\@\@]@"]@[@[@]@]@]@]@]@]@]@]@]@]@]@]@]@h]@y]@debuggetfenvgethookgetinfogetlocalgetregistrygetmetatablegetupvaluesetfenvsethooksetlocalsetmetatablesetupvaluetraceback@Cg@FC;`@NCf@VCDa@^CBc@gC_@sC_@Cd@CO`@Ce@Cc@C_@Cd@Ch@hnil or table expected'setfenv' cannot change environment of given objectflnSu>%sfunction or level expectedinvalid optionsourceshort_srclinedefinedlastlinedefinedwhatcurrentlinenupsnamenamewhatactivelinesfunclevel out of rangecallreturnlinecounttail returnLCQCXC]CcCexternal hooklua_debug> cont =(debug command) stack traceback: ... Snl%s:%d: in function '%s' in main chunk ? in function <%s:%d>(*temporary)o@o@p@p@r@p@p@r@r@4p@r@r@r@r@r@r@r@r@r@Rp@p@r@r@r@r@r@p@p@Cq@p@p@Zp@Xq@r@q@q@?localglobalfieldupvaluemethods@s@s@s@Os@s@3s@s@s@s@s@ps@tail=(tail call)=[C]CmainLua%s:%d: %sattempt to compare two %s valuesattempt to compare %s with %sattempt to %s %s '%s' (a %s value)attempt to %s a %s valueperform arithmetic onconcatenatenot enough memoryerror in error handlingstack overflowcallnC stack overflowcannot resume non-suspended coroutineattempt to yield across metamethod/C-call boundary@@@B@@@e@@@@@@@@@@@@@packagetableioosstringmathdebugCK@CX@CV&AC@C@CAC@Cj@closeflushinputlinesopenoutputpopenreadtmpfiletypewriteC_@C@Cޞ@CW@C@C@Cg@C@C͝@C@C@CCseeksetvbuf__gc__tostringC_@Cڥ@C6@C@HCФ@MCH@C@UC@ZC@%s: %s%sFILE*closed filefileattempt to use a closed filecannot close standard file__closefile (closed)file (%p)rstandard %s file is closedwtoo many argumentsinvalid option%lfinvalid formatfile is already closed%.14gsetcurend C C C@nofullline C C C__indexiostdinstdoutstderrandbreakdoelseelseifendfalseforfunctionifinlocalnilnotorrepeatreturnthentrueuntilwhile.....==>=<=~=@!CD!CJ!CM!CR!CY!C]!Cc!Cg!Cp!Cs!Cv!C|!C!C!C!C!C!C!C!C!C!C!C!C!C!C!C!C!C!C!Cchar(%d)%c%s:%d: %s%s near '%s'lexical element too longchunk has too many linesEe+-malformed numberunfinished long stringunfinished long commentnesting of [[...]] is deprecatedinvalid long string delimiterunfinished stringescape sequence too large.absacosasinatan2atanceilcoshcosdegexpfloorfmodfrexpldexplog10logmaxminmodfpowradrandomrandomseedsinhsinsqrttanhtan#C@#C@#Cз@#CN@#C$@#C@#CR@#C(@#CN@#C$@#C@#Cٸ@#C@#C׺@#C@#Cй@#Cm@#C @#C@#C@#Cv@#Cѻ@#Cۼ@#C@#CԶ@$CS@$C@ $C|@9RFߑ?9RFߑ?interval is emptywrong number of argumentsF?mathpihugemodmemory allocation error: block too bigmodulerequire%Ck@%C@C@@I@@loadlibseeall%C@%C,@system error %d _LOADLIBLOADLIB: %s%sopeninit\.'package.%s' must be a string?r no file '%s'error loading module '%s' from file '%s': %spath_luaopen_%scpath no module '%s' in file '%s'preload'package.preload' must be a table no field package.preload['%s']_LOADEDloop or previous error loading module '%s'loaders'package.loaders' must be a tablemodule '%s' not found:%sname conflict for module '%s'_NAME_M_PACKAGEf'module' not called from a Lua function__index;;;;unable to get ModuleFileName!__gcpackage.\?.lua;!\lua\?.lua;!\lua\?\init.lua;!\?.lua;!\?\init.luaLUA_PATH.\?.dll;!\?.dll;!\loadall.dllLUA_CPATH\ ; ? ! -configloaded%(null)%p... "]`qT`Pql1@+Ce@+C@+CC@+C@+C@+C@,C$@,C @%s: %sunable to generate a unique filenamezDfield '%s' missing in date table%c*tsecminhourdaymonthyearwdayydayisdstallcollatectypemonetarynumeric-C -C(-C.-C7-C,Cos '%s' expectedmain function has more than %d %sfunction at line %d has more than %d %s'%s' expected (to close '%s' at line %d)local variablestoo many local variablesupvalueschunk has too many syntax levelsno loop to break(for index)(for limit)(for step)(for generator)(for state)(for control)'=' or 'in' expected@@@@@@@'@@@@@@@o@@@@@d@selfarg or '...' expectedconstant table overflowcannot use '...' outside a vararg functionitems in a constructorambiguous syntax (function call x new statement)function arguments expectedunexpected symbolsyntax errorvariables in assignmentnot enough memorybytechardumpfindformatgfindgmatchgsublenlowermatchrepreversesubupper@0C@E0Cm@J0C@O0CAT0C A[0C Aa0C Ah0C Am0C@q0C,@w0CA}0C@@0C@0C@0C@string slice too longinvalid valueunable to dump given functionmalformed pattern (ends with '%%')malformed pattern (missing ']')@^A8@\@^A^A^A^A^A^A^A@^A^A^A@^A^A@^A@^AA'A^ATAinvalid pattern captureunbalanced patternmissing '[' after '%%f' in patterninvalid capture indextoo many capturesunfinished capture^$*+?.([%-'string.gfind' was renamed to 'string.gmatch'string/function/table expectedinvalid replacement value (a %s)-+ #0invalid format (repeated flags)invalid format (width or precision too long)\r\000invalid option '%%%c' to 'format'string__indexYinvalid key to 'next'table overflowYtable index is niltable index is NaNconcatforeachforeachigetnmaxninsertremovesetnsort 4Cn"A'4CA/4CA84C A=4C AB4C AI4C!AP4C AU4C%A'setn' is obsoletewrong number of arguments to 'insert'invalid value (%s) at index %d in table for 'concat'invalid order function for sortingtablenilbooleanuserdatanumberstringtablefunctionthreadprotoupval`5Cd5Cl5Cu5C|5C5C5Cl5C5C5C5C__index__newindex__gc__mode__eq__add__sub__mul__div__mod__pow__unm__len__lt__le__concat__call5C5C5C6C 6C6C6C6C"6C(6C.6C46C:6C@6CE6CJ6CS6C%s: %s in precompiled chunkunexpected endbad integercode too deepbad constantbad codebinary stringbad header=?%.14gindexloop in gettableloop in settablem3A3A3At3A3A3A3A3Astring length overflow5A5A5A5A5A5A6Aget length of'for' initial value must be a number'for' limit must be a number'for' step must be a number7A7A7A7A7A8A[8A8A8A(9A9A9AJ:A:A;A;A;AAy>A>AX?AC@A@A@A?AA+BABABAxCA(DADADAEA-LIBGCCW32-EH-2-SJLJ-GTHR-MINGW32w32_sharedptr->size == sizeof(W32_EH_SHARED)%s:%u: failed assertion `%s' ../../gcc/gcc/config/i386/w32-shared-ptr.cGetAtomNameA (atom, s, sizeof(s)) != 0TPZHRP(ZRP[R8TDTPTdTtTTTTTTTTT U$U8UHU\UtUUUUUUUUUVVV(V4V@VLVXVdVpVxVVVVVVVVVVVVVVVW WWW$W0W8W@WHWPW\WdWpWxWWWWWWWWWWWWWXX X(X0X8X@XLXXXdXpX|XXXXXXXXXXXXXYY Y,Y8YDYPY\YhYtY|YYYYYYY8TDTPTdTtTTTTTTTTT U$U8UHU\UtUUUUUUUUUVVV(V4V@VLVXVdVpVxVVVVVVVVVVVVVVVW WWW$W0W8W@WHWPW\WdWpWxWWWWWWWWWWWWWXX X(X0X8X@XLXXXdXpX|XXXXXXXXXXXXXYY Y,Y8YDYPY\YhYtY|YYYYYYYAddAtomA5CopyFileA<CreateDirectoryAExitProcessFindAtomAFindCloseFindFirstFileAFindNextFileAFormatMessageAFreeLibraryGetAtomNameAGetCurrentDirectoryACGetLastErrorMGetModuleFileNameAjGetProcAddress LoadLibraryAtRemoveDirectoryASetCurrentDirectoryASetUnhandledExceptionFilterO_stat'__getmainargs0__mb_cur_max<__p__environ>__p__fmodeP__set_app_typey_cexit_errno_filbuf_iob_isctype^_onexitf_pcloseg_pctypej_popen_setjmp_setmodeabortacosasinatanatan2atexit"ceil#clearerr$clock%cos&cosh(difftime*exit+exp-fclose0fflush3fgets6floor7fmod8fopen9fprintf:fputc;fputs>fread?free@freopenAfrexpBfscanfCfseekEftellGfwriteKgetenvOgmtimekldexpmlocaleconvnlocaltimeologplog10qlongjmprmallocvmemchrwmemcmpxmemcpy{mktime|modf~powputsrandreallocremoverenamesetlocalesetvbufsignalsinsinhsprintfsqrtsrandstrcatstrchrstrcmpstrcollstrcpystrcspnstrerrorstrftimestrncatstrncpystrpbrkstrrchrstrstrstrtodstrtoulsystemtantanhtimetmpfiletmpnamtolowertoupperungetcPPPPPPPPPPPPPPPPPPPKERNEL32.dllPmsvcrt.dll(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(P(Pmsvcrt.dllnyquist-3.05/liblo/build/premake4.lua0000644000175000000620000001231611467004266016607 0ustar stevestaff---------------------------------------------------------------------- -- Premake4 configuration script for LibLo -- Adapted from ODE's build script by Jason Perkins. -- For more information on Premake: http://industriousone.com/premake ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- Configuration options ---------------------------------------------------------------------- -- always clean all of the optional components and toolsets if _ACTION == "clean" then for action in pairs(premake.actions) do os.rmdir(action) end end ---------------------------------------------------------------------- -- The solution, and solution-wide settings ---------------------------------------------------------------------- solution "liblo" language "C" location ( _OPTIONS["to"] or _ACTION ) includedirs { "../lo", "../src" } -- define all the possible build configurations configurations { "DebugDLL", "ReleaseDLL", "DebugLib", "ReleaseLib", } configuration { "Debug*" } defines { "_DEBUG" } flags { "Symbols" } configuration { "Release*" } flags { "OptimizeSpeed", "NoFramePointer" } configuration { "Windows" } defines { "WIN32" } -- give each configuration a unique output directory for _, name in ipairs(configurations()) do configuration { name } targetdir ( "../lib/" .. name ) end -- disable Visual Studio security warnings configuration { "vs*" } defines { "_CRT_SECURE_NO_DEPRECATE" } -- tell source to use config.h configuration { "vs*" } defines { "HAVE_CONFIG_H" } -- don't remember why we had to do this (from ODE) configuration { "vs2002 or vs2003", "*Lib" } flags { "StaticRuntime" } ---------------------------------------------------------------------- -- Write a custom to .., based on the supplied flags ---------------------------------------------------------------------- -- First get the version number from "configure.ac" -- io.input("../configure.ac") text = io.read("*all") io.close() text = string.sub(text,string.find(text, "AC_INIT.+")) version = string.sub(text,string.find(text, "%d+%.%d+")) -- Replace it in "config.h" -- io.input("config-msvc.h") local text = io.read("*all") text = string.gsub(text, '/%*VERSION%*/', '"'..version..'"') io.output("../config.h") io.write(text) io.close() ---------------------------------------------------------------------- -- Copy to ../lo ---------------------------------------------------------------------- io.input("lo_endian-msvc.h") io.output("../lo/lo_endian.h") local text = io.read("*all") io.write(text) io.close() ---------------------------------------------------------------------- -- The LibLo library project ---------------------------------------------------------------------- project "liblo" kind "StaticLib" location ( _OPTIONS["to"] or _ACTION ) includedirs { "..", } files { "../src/*.c", "../src/*.h", "../lo/*.h", "../src/liblo.def", } excludes { "../src/testlo.c", "../src/subtest.c", "../src/tools", } configuration { "windows" } links { "user32", "wsock32", "ws2_32", "pthreadVC2", } configuration { "*Lib" } kind "StaticLib" defines "LIBLO_LIB" configuration { "*DLL" } kind "SharedLib" defines "LIBLO_DLL" configuration { "Debug*" } targetname "liblo_d" configuration { "Release*" } targetname "liblo" ---------------------------------------------------------------------- -- The automated test application ---------------------------------------------------------------------- project "testlo" kind "ConsoleApp" location ( _OPTIONS["to"] or _ACTION ) links { "user32", "wsock32", "ws2_32", "pthreadVC2", } includedirs { "..", } files { "../src/testlo.c", } configuration { "DebugDLL" } links { "liblo_d" } libdirs { "../lib/debugdll" } configuration { "DebugLib" } links { "liblo_d" } libdirs { "../lib/debuglib" } configuration { "Release*" } links { "liblo" } project "subtest" kind "ConsoleApp" location ( _OPTIONS["to"] or _ACTION ) links { "user32", "wsock32", "ws2_32", "pthreadVC2", } includedirs { "..", } files { "../src/subtest.c", } configuration { "DebugDLL" } links { "liblo_d" } libdirs { "../lib/debugdll" } configuration { "DebugLib" } links { "liblo_d" } libdirs { "../lib/debuglib" } configuration { "Release*" } links { "liblo" } nyquist-3.05/liblo/build/Makefile.am0000644000175000000620000000015311467004266016424 0ustar stevestaff MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = config-msvc.h lo_endian-msvc.h premake4.exe premake4.lua nyquist-3.05/liblo/build/lo_endian-msvc.h0000644000175000000620000000611411467004266017442 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_ENDIAN_H #define LO_ENDIAN_H #include #ifdef _MSC_VER #define inline __inline #define uint64_t unsigned __int64 #define uint32_t unsigned __int32 #else #include #endif #ifdef WIN32 #include #include #else #include #endif #ifdef __cplusplus extern "C" { #endif #define lo_swap16(x) htons(x) #define lo_swap32(x) htonl(x) /* These macros come from the Linux kernel */ #ifndef lo_swap16 #define lo_swap16(x) \ ({ \ uint16_t __x = (x); \ ((uint16_t)( \ (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ }) #warning USING UNOPTIMISED ENDIAN STUFF #endif #ifndef lo_swap32 #define lo_swap32(x) \ ({ \ uint32_t __x = (x); \ ((uint32_t)( \ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ }) #endif #if 0 #ifndef lo_swap64 #define lo_swap64(x) \ ({ \ uint64_t __x = (x); \ ((uint64_t)( \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ }) #endif #else typedef union { uint64_t all; struct { uint32_t a; uint32_t b; } part; } lo_split64; static inline uint64_t lo_swap64(uint64_t x) { lo_split64 in, out; in.all = x; out.part.a = lo_swap32(in.part.b); out.part.b = lo_swap32(in.part.a); return out.all; } #endif /* Host to OSC and OSC to Host conversion macros */ #if 0 #define lo_htoo16(x) (x) #define lo_htoo32(x) (x) #define lo_htoo64(x) (x) #define lo_otoh16(x) (x) #define lo_otoh32(x) (x) #define lo_otoh64(x) (x) #else #define lo_htoo16 lo_swap16 #define lo_htoo32 lo_swap32 #define lo_htoo64 lo_swap64 #define lo_otoh16 lo_swap16 #define lo_otoh32 lo_swap32 #define lo_otoh64 lo_swap64 #endif #ifdef __cplusplus } #endif #ifdef _MSC_VER #undef inline #undef uint64_t #undef uint32_t #endif #endif /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/osx/0002755000175000000620000000000011537433130014077 5ustar stevestaffnyquist-3.05/liblo/osx/config.h0000644000175000000620000000477611466705460015542 0ustar stevestaff/* config.h. Generated by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define this to enable ipv6. */ /* #undef ENABLE_IPV6 */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if inet_aton() is available. */ #define HAVE_INET_ATON 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `pthread' library (-lpthread). */ #define HAVE_LIBPTHREAD 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETDB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_NETINET_IN_H 1 /* Define to 1 if poll() is available. */ #define HAVE_POLL 1 /* Define to 1 if select() is available. */ #define HAVE_SELECT 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_SOCKET_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* If machine is bigendian */ #define LO_BIGENDIAN "0" /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "liblo" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "liblo-devel@lists.sourceforge.net" /* Define to the full name of this package. */ #define PACKAGE_NAME "liblo" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "liblo 0.26" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "liblo" /* Define to the version of this package. */ #define PACKAGE_VERSION "0.26" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "0.26" /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */ /* Define to `unsigned' if does not define. */ /* #undef size_t */ nyquist-3.05/liblo/ser-to-osc/0002755000175000000620000000000011537433130015261 5ustar stevestaffnyquist-3.05/liblo/ser-to-osc/README.txt0000644000175000000620000000125311466705460016767 0ustar stevestaffser-to-osc reads a serial port and sends OSC messages to Nyquist. usage: ser-to-osc [-q] [input-device] The default input is stdin, but another device can be specified on the command line. The optional -q switch means "quiet": do not echo input. The input format is Channel where is an ascii decimal integer, and is an ascii decimal integer between 0 and 255. The input values are translated to the range 0-1. On the Mac, you build this with the ser-to-osc target in Xcode. You can find the executable in: nyquist/macosxproject/build/Development/ser-to-osc and you can run this from a terminal window (or with Xcode) nyquist-3.05/liblo/ser-to-osc/Serial.cpp0000644000175000000620000010266611466705460017226 0ustar stevestaff// Serial.cpp - Implementation of the CSerial class // // Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) // // 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.1 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 ////////////////////////////////////////////////////////////////////// // Include the standard header files #define STRICT #include #include #include ////////////////////////////////////////////////////////////////////// // Include module headerfile #include "Serial.h" ////////////////////////////////////////////////////////////////////// // Disable warning C4127: conditional expression is constant, which // is generated when using the _RPTF and _ASSERTE macros. #pragma warning(disable: 4127) ////////////////////////////////////////////////////////////////////// // Enable debug memory manager #ifdef _DEBUG #ifdef THIS_FILE #undef THIS_FILE #endif static const char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Helper methods inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const { #ifdef SERIAL_NO_OVERLAPPED // Check if an overlapped structure has been specified if (lpOverlapped || (dwTimeout != INFINITE)) { // Quit application ::MessageBox(0,_T("Overlapped I/O and time-outs are not supported, when overlapped I/O is disabled."),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL); ::DebugBreak(); ::ExitProcess(0xFFFFFFF); } #endif #ifdef SERIAL_NO_CANCELIO // Check if 0 or INFINITE time-out has been specified, because // the communication I/O cannot be cancelled. if ((dwTimeout != 0) && (dwTimeout != INFINITE)) { // Quit application ::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL); ::DebugBreak(); ::ExitProcess(0xFFFFFFF); } #endif // SERIAL_NO_CANCELIO // Avoid warnings (void) dwTimeout; (void) lpOverlapped; } inline BOOL CSerial::CancelCommIo (void) { #ifdef SERIAL_NO_CANCELIO // CancelIo shouldn't have been called at this point ::DebugBreak(); return FALSE; #else // Cancel the I/O request return ::CancelIo(m_hFile); #endif // SERIAL_NO_CANCELIO } ////////////////////////////////////////////////////////////////////// // Code CSerial::CSerial () : m_lLastError(ERROR_SUCCESS) , m_hFile(0) , m_eEvent(EEventNone) , m_dwEventMask(0) #ifndef SERIAL_NO_OVERLAPPED , m_hevtOverlapped(0) #endif { } CSerial::~CSerial () { // If the device is already closed, // then we don't need to do anything. if (m_hFile) { // Display a warning _RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n"); // Close implicitly Close(); } } CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice) { // Try to open the device HANDLE hFile = ::CreateFile(lpszDevice, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); // Check if we could open the device if (hFile == INVALID_HANDLE_VALUE) { // Display error switch (::GetLastError()) { case ERROR_FILE_NOT_FOUND: // The specified COM-port does not exist return EPortNotAvailable; case ERROR_ACCESS_DENIED: // The specified COM-port is in use return EPortInUse; default: // Something else is wrong return EPortUnknownError; } } // Close handle ::CloseHandle(hFile); // Port is available return EPortAvailable; } LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the port isn't already opened if (m_hFile) { m_lLastError = ERROR_ALREADY_INITIALIZED; _RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n"); return m_lLastError; } // Open the device m_hFile = ::CreateFile(lpszDevice, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, fOverlapped?FILE_FLAG_OVERLAPPED:0, 0); if (m_hFile == INVALID_HANDLE_VALUE) { // Reset file handle m_hFile = 0; // Display error m_lLastError = ::GetLastError(); _RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n"); return m_lLastError; } #ifndef SERIAL_NO_OVERLAPPED // We cannot have an event handle yet _ASSERTE(m_hevtOverlapped == 0); // Create the event handle for internal overlapped operations (manual reset) if (fOverlapped) { m_hevtOverlapped = ::CreateEvent(0,true,false,0); if (m_hevtOverlapped == 0) { // Obtain the error information m_lLastError = ::GetLastError(); _RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n"); // Close the port ::CloseHandle(m_hFile); m_hFile = 0; // Return the error return m_lLastError; } } #else // Overlapped flag shouldn't be specified _ASSERTE(!fOverlapped); #endif // Setup the COM-port if (dwInQueue || dwOutQueue) { // Make sure the queue-sizes are reasonable sized. Win9X systems crash // if the input queue-size is zero. Both queues need to be at least // 16 bytes large. _ASSERTE(dwInQueue >= 16); _ASSERTE(dwOutQueue >= 16); if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue)) { // Display a warning long lLastError = ::GetLastError(); _RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n"); // Close the port Close(); // Save last error from SetupComm m_lLastError = lLastError; return m_lLastError; } } // Setup the default communication mask SetMask(); // Non-blocking reads is default SetupReadTimeouts(EReadTimeoutNonblocking); // Setup the device for default settings COMMCONFIG commConfig = {0}; DWORD dwSize = sizeof(commConfig); commConfig.dwSize = dwSize; if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize)) { // Set the default communication configuration if (!::SetCommConfig(m_hFile,&commConfig,dwSize)) { // Display a warning _RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n"); } } else { // Display a warning _RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n"); } // Return successful return m_lLastError; } LONG CSerial::Close (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // If the device is already closed, // then we don't need to do anything. if (m_hFile == 0) { // Display a warning _RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n"); return m_lLastError; } #ifndef SERIAL_NO_OVERLAPPED // Free event handle if (m_hevtOverlapped) { ::CloseHandle(m_hevtOverlapped); m_hevtOverlapped = 0; } #endif // Close COM port ::CloseHandle(m_hFile); m_hFile = 0; // Return successful return m_lLastError; } LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n"); return m_lLastError; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = :: GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n"); return m_lLastError; } // Set the new data dcb.BaudRate = DWORD(eBaudrate); dcb.ByteSize = BYTE(eDataBits); dcb.Parity = BYTE(eParity); dcb.StopBits = BYTE(eStopBits); // Determine if parity is used dcb.fParity = (eParity != EParNone); // Set the new DCB structure if (!::SetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n"); return m_lLastError; } // Return successful return m_lLastError; } LONG CSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n"); return m_lLastError; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n"); return m_lLastError; } // Set the new event character dcb.EvtChar = char(bEventChar); // Adjust the event mask, to make sure the event will be received if (fAdjustMask) { // Enable 'receive event character' event. Note that this // will generate an EEventNone if there is an asynchronous // WaitCommEvent pending. SetMask(GetEventMask() | EEventRcvEv); } // Set the new DCB structure if (!::SetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n"); return m_lLastError; } // Return successful return m_lLastError; } LONG CSerial::SetMask (DWORD dwEventMask) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n"); return m_lLastError; } // Set the new mask. Note that this will generate an EEventNone // if there is an asynchronous WaitCommEvent pending. if (!::SetCommMask(m_hFile,dwEventMask)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n"); return m_lLastError; } // Save event mask and return successful m_dwEventMask = dwEventMask; return m_lLastError; } LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) { // Check if time-outs are supported CheckRequirements(lpOverlapped,dwTimeout); // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n"); return m_lLastError; } #ifndef SERIAL_NO_OVERLAPPED // Check if an overlapped structure has been specified if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE))) { // Set the internal error code m_lLastError = ERROR_INVALID_FUNCTION; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n"); return m_lLastError; } // Wait for the event to happen OVERLAPPED ovInternal; if (!lpOverlapped && m_hevtOverlapped) { // Setup our own overlapped structure memset(&ovInternal,0,sizeof(ovInternal)); ovInternal.hEvent = m_hevtOverlapped; // Use our internal overlapped structure lpOverlapped = &ovInternal; } // Make sure the overlapped structure isn't busy _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped)); // Wait for the COM event if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped)) { // Set the internal error code long lLastError = ::GetLastError(); // Overlapped operation in progress is not an actual error if (lLastError != ERROR_IO_PENDING) { // Save the error m_lLastError = lLastError; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n"); return m_lLastError; } // We need to block if the client didn't specify an overlapped structure if (lpOverlapped == &ovInternal) { // Wait for the overlapped operation to complete switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)) { case WAIT_OBJECT_0: // The overlapped operation has completed break; case WAIT_TIMEOUT: // Cancel the I/O operation CancelCommIo(); // The operation timed out. Set the internal error code and quit m_lLastError = ERROR_TIMEOUT; return m_lLastError; default: // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait until COM event has arrived\n"); return m_lLastError; } } } else { // The operation completed immediatly. Just to be sure // we'll set the overlapped structure's event handle. if (lpOverlapped) ::SetEvent(lpOverlapped->hEvent); } #else // Wait for the COM event if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),0)) { // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n"); return m_lLastError; } #endif // Return successfully return m_lLastError; } LONG CSerial::SetupHandshaking (EHandshake eHandshake) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Device is not opened\n"); return m_lLastError; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to obtain DCB information\n"); return m_lLastError; } // Set the handshaking flags switch (eHandshake) { case EHandshakeOff: dcb.fOutxCtsFlow = false; // Disable CTS monitoring dcb.fOutxDsrFlow = false; // Disable DSR monitoring dcb.fDtrControl = DTR_CONTROL_DISABLE; // Disable DTR monitoring dcb.fOutX = false; // Disable XON/XOFF for transmission dcb.fInX = false; // Disable XON/XOFF for receiving dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send) break; case EHandshakeHardware: dcb.fOutxCtsFlow = true; // Enable CTS monitoring dcb.fOutxDsrFlow = true; // Enable DSR monitoring dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; // Enable DTR handshaking dcb.fOutX = false; // Disable XON/XOFF for transmission dcb.fInX = false; // Disable XON/XOFF for receiving dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; // Enable RTS handshaking break; case EHandshakeSoftware: dcb.fOutxCtsFlow = false; // Disable CTS (Clear To Send) dcb.fOutxDsrFlow = false; // Disable DSR (Data Set Ready) dcb.fDtrControl = DTR_CONTROL_DISABLE; // Disable DTR (Data Terminal Ready) dcb.fOutX = true; // Enable XON/XOFF for transmission dcb.fInX = true; // Enable XON/XOFF for receiving dcb.fRtsControl = RTS_CONTROL_DISABLE; // Disable RTS (Ready To Send) break; default: // This shouldn't be possible _ASSERTE(false); m_lLastError = E_INVALIDARG; return m_lLastError; } // Set the new DCB structure if (!::SetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to set DCB information\n"); return m_lLastError; } // Return successful return m_lLastError; } LONG CSerial::SetupReadTimeouts (EReadTimeout eReadTimeout) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Device is not opened\n"); return m_lLastError; } // Determine the time-outs COMMTIMEOUTS cto; if (!::GetCommTimeouts(m_hFile,&cto)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to obtain timeout information\n"); return m_lLastError; } // Set the new timeouts switch (eReadTimeout) { case EReadTimeoutBlocking: cto.ReadIntervalTimeout = 0; cto.ReadTotalTimeoutConstant = 0; cto.ReadTotalTimeoutMultiplier = 0; break; case EReadTimeoutNonblocking: cto.ReadIntervalTimeout = MAXDWORD; cto.ReadTotalTimeoutConstant = 0; cto.ReadTotalTimeoutMultiplier = 0; break; default: // This shouldn't be possible _ASSERTE(false); m_lLastError = E_INVALIDARG; return m_lLastError; } // Set the new DCB structure if (!::SetCommTimeouts(m_hFile,&cto)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n"); return m_lLastError; } // Return successful return m_lLastError; } CSerial::EBaudrate CSerial::GetBaudrate (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Device is not opened\n"); return EBaudUnknown; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Unable to obtain DCB information\n"); return EBaudUnknown; } // Return the appropriate baudrate return EBaudrate(dcb.BaudRate); } CSerial::EDataBits CSerial::GetDataBits (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetDataBits - Device is not opened\n"); return EDataUnknown; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetDataBits - Unable to obtain DCB information\n"); return EDataUnknown; } // Return the appropriate bytesize return EDataBits(dcb.ByteSize); } CSerial::EParity CSerial::GetParity (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetParity - Device is not opened\n"); return EParUnknown; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetParity - Unable to obtain DCB information\n"); return EParUnknown; } // Check if parity is used if (!dcb.fParity) { // No parity return EParNone; } // Return the appropriate parity setting return EParity(dcb.Parity); } CSerial::EStopBits CSerial::GetStopBits (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetStopBits - Device is not opened\n"); return EStopUnknown; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetStopBits - Unable to obtain DCB information\n"); return EStopUnknown; } // Return the appropriate stopbits return EStopBits(dcb.StopBits); } DWORD CSerial::GetEventMask (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetEventMask - Device is not opened\n"); return 0; } // Return the event mask return m_dwEventMask; } BYTE CSerial::GetEventChar (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetEventChar - Device is not opened\n"); return 0; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetEventChar - Unable to obtain DCB information\n"); return 0; } // Set the new event character return BYTE(dcb.EvtChar); } CSerial::EHandshake CSerial::GetHandshaking (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Device is not opened\n"); return EHandshakeUnknown; } // Obtain the DCB structure for the device CDCB dcb; if (!::GetCommState(m_hFile,&dcb)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Unable to obtain DCB information\n"); return EHandshakeUnknown; } // Check if hardware handshaking is being used if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE)) return EHandshakeHardware; // Check if software handshaking is being used if (dcb.fOutX && dcb.fInX) return EHandshakeSoftware; // No handshaking is being used return EHandshakeOff; } LONG CSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) { // Check if time-outs are supported CheckRequirements(lpOverlapped,dwTimeout); // Overlapped operation should specify the pdwWritten variable _ASSERTE(!lpOverlapped || pdwWritten); // Reset error state m_lLastError = ERROR_SUCCESS; // Use our own variable for read count DWORD dwWritten; if (pdwWritten == 0) { pdwWritten = &dwWritten; } // Reset the number of bytes written *pdwWritten = 0; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Write - Device is not opened\n"); return m_lLastError; } #ifndef SERIAL_NO_OVERLAPPED // Check if an overlapped structure has been specified if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE))) { // Set the internal error code m_lLastError = ERROR_INVALID_FUNCTION; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped I/O is disabled, specified parameters are illegal.\n"); return m_lLastError; } // Wait for the event to happen OVERLAPPED ovInternal; if (!lpOverlapped && m_hevtOverlapped) { // Setup our own overlapped structure memset(&ovInternal,0,sizeof(ovInternal)); ovInternal.hEvent = m_hevtOverlapped; // Use our internal overlapped structure lpOverlapped = &ovInternal; } // Make sure the overlapped structure isn't busy _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped)); // Write the data if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped)) { // Set the internal error code long lLastError = ::GetLastError(); // Overlapped operation in progress is not an actual error if (lLastError != ERROR_IO_PENDING) { // Save the error m_lLastError = lLastError; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n"); return m_lLastError; } // We need to block if the client didn't specify an overlapped structure if (lpOverlapped == &ovInternal) { // Wait for the overlapped operation to complete switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)) { case WAIT_OBJECT_0: // The overlapped operation has completed if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE)) { // Set the internal error code m_lLastError = ::GetLastError(); _RPTF0(_CRT_WARN,"CSerial::Write - Overlapped completed without result\n"); return m_lLastError; } break; case WAIT_TIMEOUT: // Cancel the I/O operation CancelCommIo(); // The operation timed out. Set the internal error code and quit m_lLastError = ERROR_TIMEOUT; return m_lLastError; default: // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Write - Unable to wait until data has been sent\n"); return m_lLastError; } } } else { // The operation completed immediatly. Just to be sure // we'll set the overlapped structure's event handle. if (lpOverlapped) ::SetEvent(lpOverlapped->hEvent); } #else // Write the data if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,0)) { // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n"); return m_lLastError; } #endif // Return successfully return m_lLastError; } LONG CSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) { // Check if time-outs are supported CheckRequirements(lpOverlapped,dwTimeout); // Determine the length of the string return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout); } LONG CSerial::Read (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout) { // Check if time-outs are supported CheckRequirements(lpOverlapped,dwTimeout); // Overlapped operation should specify the pdwRead variable _ASSERTE(!lpOverlapped || pdwRead); // Reset error state m_lLastError = ERROR_SUCCESS; // Use our own variable for read count DWORD dwRead; if (pdwRead == 0) { pdwRead = &dwRead; } // Reset the number of bytes read *pdwRead = 0; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Read - Device is not opened\n"); return m_lLastError; } #ifdef _DEBUG // The debug version fills the entire data structure with // 0xDC bytes, to catch buffer errors as soon as possible. memset(pData,0xDC,iLen); #endif #ifndef SERIAL_NO_OVERLAPPED // Check if an overlapped structure has been specified if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE))) { // Set the internal error code m_lLastError = ERROR_INVALID_FUNCTION; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped I/O is disabled, specified parameters are illegal.\n"); return m_lLastError; } // Wait for the event to happen OVERLAPPED ovInternal; if (lpOverlapped == 0) { // Setup our own overlapped structure memset(&ovInternal,0,sizeof(ovInternal)); ovInternal.hEvent = m_hevtOverlapped; // Use our internal overlapped structure lpOverlapped = &ovInternal; } // Make sure the overlapped structure isn't busy _ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped)); // Read the data if (!::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped)) { // Set the internal error code long lLastError = ::GetLastError(); // Overlapped operation in progress is not an actual error if (lLastError != ERROR_IO_PENDING) { // Save the error m_lLastError = lLastError; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n"); return m_lLastError; } // We need to block if the client didn't specify an overlapped structure if (lpOverlapped == &ovInternal) { // Wait for the overlapped operation to complete switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout)) { case WAIT_OBJECT_0: // The overlapped operation has completed if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE)) { // Set the internal error code m_lLastError = ::GetLastError(); _RPTF0(_CRT_WARN,"CSerial::Read - Overlapped completed without result\n"); return m_lLastError; } break; case WAIT_TIMEOUT: // Cancel the I/O operation CancelCommIo(); // The operation timed out. Set the internal error code and quit m_lLastError = ERROR_TIMEOUT; return m_lLastError; default: // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Read - Unable to wait until data has been read\n"); return m_lLastError; } } } else { // The operation completed immediatly. Just to be sure // we'll set the overlapped structure's event handle. if (lpOverlapped) ::SetEvent(lpOverlapped->hEvent); } #else // Read the data if (!::ReadFile(m_hFile,pData,iLen,pdwRead,0)) { // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n"); return m_lLastError; } #endif // Return successfully return m_lLastError; } LONG CSerial::Purge() { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Purge - Device is not opened\n"); return m_lLastError; } if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR)) { // Set the internal error code m_lLastError = ::GetLastError(); _RPTF0(_CRT_WARN,"CSerial::Purge - Overlapped completed without result\n"); } // Return successfully return m_lLastError; } LONG CSerial::Break (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::Break - Device is not opened\n"); return m_lLastError; } // Set the RS-232 port in break mode for a little while ::SetCommBreak(m_hFile); ::Sleep(100); ::ClearCommBreak(m_hFile); // Return successfully return m_lLastError; } CSerial::EEvent CSerial::GetEventType (void) { #ifdef _DEBUG // Check if the event is within the mask if ((m_eEvent & m_dwEventMask) == 0) _RPTF2(_CRT_WARN,"CSerial::GetEventType - Event %08Xh not within mask %08Xh.\n", m_eEvent, m_dwEventMask); #endif // Obtain the event (mask unwanted events out) EEvent eEvent = EEvent(m_eEvent & m_dwEventMask); // Reset internal event type m_eEvent = EEventNone; // Return the current cause return eEvent; } CSerial::EError CSerial::GetError (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Check if the device is open if (m_hFile == 0) { // Set the internal error code m_lLastError = ERROR_INVALID_HANDLE; // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetError - Device is not opened\n"); return EErrorUnknown; } // Obtain COM status DWORD dwErrors = 0; if (!::ClearCommError(m_hFile,&dwErrors,0)) { // Set the internal error code m_lLastError = ::GetLastError(); // Issue an error and quit _RPTF0(_CRT_WARN,"CSerial::GetError - Unable to obtain COM status\n"); return EErrorUnknown; } // Return the error return EError(dwErrors); } bool CSerial::GetCTS (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Obtain the modem status DWORD dwModemStat = 0; if (!::GetCommModemStatus(m_hFile,&dwModemStat)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetCTS - Unable to obtain the modem status\n"); return false; } // Determine if CTS is on return (dwModemStat & MS_CTS_ON) != 0; } bool CSerial::GetDSR (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Obtain the modem status DWORD dwModemStat = 0; if (!::GetCommModemStatus(m_hFile,&dwModemStat)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetDSR - Unable to obtain the modem status\n"); return false; } // Determine if DSR is on return (dwModemStat & MS_DSR_ON) != 0; } bool CSerial::GetRing (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Obtain the modem status DWORD dwModemStat = 0; if (!::GetCommModemStatus(m_hFile,&dwModemStat)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetRing - Unable to obtain the modem status"); return false; } // Determine if Ring is on return (dwModemStat & MS_RING_ON) != 0; } bool CSerial::GetRLSD (void) { // Reset error state m_lLastError = ERROR_SUCCESS; // Obtain the modem status DWORD dwModemStat = 0; if (!::GetCommModemStatus(m_hFile,&dwModemStat)) { // Obtain the error code m_lLastError = ::GetLastError(); // Display a warning _RPTF0(_CRT_WARN,"CSerial::GetRLSD - Unable to obtain the modem status"); return false; } // Determine if RLSD is on return (dwModemStat & MS_RLSD_ON) != 0; } nyquist-3.05/liblo/ser-to-osc/Serial.h0000644000175000000620000003127111466705460016664 0ustar stevestaff// Serial.h - Definition of the CSerial class // // Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl) // // 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.1 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 #ifndef __SERIAL_H #define __SERIAL_H ////////////////////////////////////////////////////////////////////// // The SERIAL_DEFAULT_OVERLAPPED defines if the default open mode uses // overlapped I/O. When overlapped I/O is available (normal Win32 // platforms) it uses overlapped I/O. Windows CE doesn't allow the use // of overlapped I/O, so it is disabled there by default. #ifndef SERIAL_DEFAULT_OVERLAPPED #ifndef SERIAL_NO_OVERLAPPED #define SERIAL_DEFAULT_OVERLAPPED true #else #define SERIAL_DEFAULT_OVERLAPPED false #endif #endif ////////////////////////////////////////////////////////////////////// // // CSerial - Win32 wrapper for serial communications // // Serial communication often causes a lot of problems. This class // tries to supply an easy to use interface to deal with serial // devices. // // The class is actually pretty ease to use. You only need to open // the COM-port, where you need to specify the basic serial // communication parameters. You can also choose to setup handshaking // and read timeout behaviour. // // The following serial classes are available: // // CSerial - Serial communication support. // CSerialEx - Serial communication with listener thread for events // CSerialSync - Serial communication with synchronized event handler // CSerialWnd - Asynchronous serial support, which uses the Win32 // message queue for event notification. // CSerialMFC - Preferred class to use in MFC-based GUI windows. // // // Pros: // ----- // - Easy to use (hides a lot of nasty Win32 stuff) // - Fully ANSI and Unicode aware // // Cons: // ----- // - Little less flexibility then native Win32 API, however you can // use this API at the same time for features which are missing // from this class. // - Incompatible with Windows 95 or Windows NT v3.51 (or earlier), // because CancelIo isn't support on these platforms. Define the // SERIAL_NO_CANCELIO macro for support of these platforms as // well. When this macro is defined, then only time-out values of // 0 or INFINITE are valid. // // // Copyright (C) 1999-2003 Ramon de Klein // (Ramon.de.Klein@ict.nl) class CSerial { // Class enumerations public: // Communication event typedef enum { EEventUnknown = -1, // Unknown event EEventNone = 0, // Event trigged without cause EEventBreak = EV_BREAK, // A break was detected on input EEventCTS = EV_CTS, // The CTS signal changed state EEventDSR = EV_DSR, // The DSR signal changed state EEventError = EV_ERR, // A line-status error occurred EEventRing = EV_RING, // A ring indicator was detected EEventRLSD = EV_RLSD, // The RLSD signal changed state EEventRecv = EV_RXCHAR, // Data is received on input EEventRcvEv = EV_RXFLAG, // Event character was received on input EEventSend = EV_TXEMPTY, // Last character on output was sent EEventPrinterError = EV_PERR, // Printer error occured EEventRx80Full = EV_RX80FULL, // Receive buffer is 80 percent full EEventProviderEvt1 = EV_EVENT1, // Provider specific event 1 EEventProviderEvt2 = EV_EVENT2, // Provider specific event 2 } EEvent; // Baudrate typedef enum { EBaudUnknown = -1, // Unknown EBaud110 = CBR_110, // 110 bits/sec EBaud300 = CBR_300, // 300 bits/sec EBaud600 = CBR_600, // 600 bits/sec EBaud1200 = CBR_1200, // 1200 bits/sec EBaud2400 = CBR_2400, // 2400 bits/sec EBaud4800 = CBR_4800, // 4800 bits/sec EBaud9600 = CBR_9600, // 9600 bits/sec EBaud14400 = CBR_14400, // 14400 bits/sec EBaud19200 = CBR_19200, // 19200 bits/sec (default) EBaud38400 = CBR_38400, // 38400 bits/sec EBaud56000 = CBR_56000, // 56000 bits/sec EBaud57600 = CBR_57600, // 57600 bits/sec EBaud115200 = CBR_115200, // 115200 bits/sec EBaud128000 = CBR_128000, // 128000 bits/sec EBaud256000 = CBR_256000, // 256000 bits/sec } EBaudrate; // Data bits (5-8) typedef enum { EDataUnknown = -1, // Unknown EData5 = 5, // 5 bits per byte EData6 = 6, // 6 bits per byte EData7 = 7, // 7 bits per byte EData8 = 8 // 8 bits per byte (default) } EDataBits; // Parity scheme typedef enum { EParUnknown = -1, // Unknown EParNone = NOPARITY, // No parity (default) EParOdd = ODDPARITY, // Odd parity EParEven = EVENPARITY, // Even parity EParMark = MARKPARITY, // Mark parity EParSpace = SPACEPARITY // Space parity } EParity; // Stop bits typedef enum { EStopUnknown = -1, // Unknown EStop1 = ONESTOPBIT, // 1 stopbit (default) EStop1_5 = ONE5STOPBITS,// 1.5 stopbit EStop2 = TWOSTOPBITS // 2 stopbits } EStopBits; // Handshaking typedef enum { EHandshakeUnknown = -1, // Unknown EHandshakeOff = 0, // No handshaking EHandshakeHardware = 1, // Hardware handshaking (RTS/CTS) EHandshakeSoftware = 2 // Software handshaking (XON/XOFF) } EHandshake; // Timeout settings typedef enum { EReadTimeoutUnknown = -1, // Unknown EReadTimeoutNonblocking = 0, // Always return immediately EReadTimeoutBlocking = 1 // Block until everything is retrieved } EReadTimeout; // Communication errors typedef enum { EErrorUnknown = 0, // Unknown EErrorBreak = CE_BREAK, // Break condition detected EErrorFrame = CE_FRAME, // Framing error EErrorIOE = CE_IOE, // I/O device error EErrorMode = CE_MODE, // Unsupported mode EErrorOverrun = CE_OVERRUN, // Character buffer overrun, next byte is lost EErrorRxOver = CE_RXOVER, // Input buffer overflow, byte lost EErrorParity = CE_RXPARITY,// Input parity error EErrorTxFull = CE_TXFULL // Output buffer full } EError; // Port availability typedef enum { EPortUnknownError = -1, // Unknown error occurred EPortAvailable = 0, // Port is available EPortNotAvailable = 1, // Port is not present EPortInUse = 2 // Port is in use } EPort; // Construction public: CSerial(); virtual ~CSerial(); // Operations public: // Check if particular COM-port is available (static method). static EPort CheckPort (LPCTSTR lpszDevice); // Open the serial communications for a particular COM port. You // need to use the full devicename (i.e. "COM1") to open the port. // It's possible to specify the size of the input/output queues. virtual LONG Open (LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0, bool fOverlapped = SERIAL_DEFAULT_OVERLAPPED); // Close the serial port. virtual LONG Close (void); // Setup the communication settings such as baudrate, databits, // parity and stopbits. The default settings are applied when the // device has been opened. Call this function if these settings do // not apply for your application. If you prefer to use integers // instead of the enumerated types then just cast the integer to // the required type. So the following two initializations are // equivalent: // // Setup(EBaud9600,EData8,EParNone,EStop1) // // or // // Setup(EBaudrate(9600),EDataBits(8),EParity(NOPARITY),EStopBits(ONESTOPBIT)) // // In the latter case, the types are not validated. So make sure // that you specify the appropriate values. virtual LONG Setup (EBaudrate eBaudrate = EBaud9600, EDataBits eDataBits = EData8, EParity eParity = EParNone, EStopBits eStopBits = EStop1); // Set/clear the event character. When this byte is being received // on the serial port then the EEventRcvEv event is signalled, // when the mask has been set appropriately. If the fAdjustMask flag // has been set, then the event mask is automatically adjusted. virtual LONG SetEventChar (BYTE bEventChar, bool fAdjustMask = true); // Set the event mask, which indicates what events should be // monitored. The WaitEvent method can only monitor events that // have been enabled. The default setting only monitors the // error events and data events. An application may choose to // monitor CTS. DSR, RLSD, etc as well. virtual LONG SetMask (DWORD dwMask = EEventBreak|EEventError|EEventRecv); // The WaitEvent method waits for one of the events that are // enabled (see SetMask). virtual LONG WaitEvent (LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); // Setup the handshaking protocol. There are three forms of // handshaking: // // 1) No handshaking, so data is always send even if the receiver // cannot handle the data anymore. This can lead to data loss, // when the sender is able to transmit data faster then the // receiver can handle. // 2) Hardware handshaking, where the RTS/CTS lines are used to // indicate if data can be sent. This mode requires that both // ports and the cable support hardware handshaking. Hardware // handshaking is the most reliable and efficient form of // handshaking available, but is hardware dependant. // 3) Software handshaking, where the XON/XOFF characters are used // to throttle the data. A major drawback of this method is that // these characters cannot be used for data anymore. virtual LONG SetupHandshaking (EHandshake eHandshake); // Read operations can be blocking or non-blocking. You can use // this method to setup wether to use blocking or non-blocking // reads. Non-blocking reads is the default, which is required // for most applications. // // 1) Blocking reads, which will cause the 'Read' method to block // until the requested number of bytes have been read. This is // useful if you know how many data you will receive. // 2) Non-blocking reads, which will read as many bytes into your // buffer and returns almost immediately. This is often the // preferred setting. virtual LONG SetupReadTimeouts (EReadTimeout eReadTimeout); // Obtain communication settings virtual EBaudrate GetBaudrate (void); virtual EDataBits GetDataBits (void); virtual EParity GetParity (void); virtual EStopBits GetStopBits (void); virtual EHandshake GetHandshaking (void); virtual DWORD GetEventMask (void); virtual BYTE GetEventChar (void); // Write data to the serial port. Note that we are only able to // send ANSI strings, because it probably doesn't make sense to // transmit Unicode strings to an application. virtual LONG Write (const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); virtual LONG Write (LPCSTR pString, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); // Read data from the serial port. Refer to the description of // the 'SetupReadTimeouts' for an explanation about (non) blocking // reads and how to use this. virtual LONG Read (void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE); // Send a break LONG Break (void); // Determine what caused the event to trigger EEvent GetEventType (void); // Obtain the error EError GetError (void); // Obtain the COMM and event handle HANDLE GetCommHandle (void) { return m_hFile; } // Check if com-port is opened bool IsOpen (void) const { return (m_hFile != 0); } // Obtain last error status LONG GetLastError (void) const { return m_lLastError; } // Obtain CTS/DSR/RING/RLSD settings bool GetCTS (void); bool GetDSR (void); bool GetRing (void); bool GetRLSD (void); // Purge all buffers LONG Purge (void); protected: // Internal helper class which wraps DCB structure class CDCB : public DCB { public: CDCB() { DCBlength = sizeof(DCB); } }; // Attributes protected: LONG m_lLastError; // Last serial error HANDLE m_hFile; // File handle EEvent m_eEvent; // Event type DWORD m_dwEventMask; // Event mask #ifndef SERIAL_NO_OVERLAPPED HANDLE m_hevtOverlapped; // Event handle for internal overlapped operations #endif protected: // Check the requirements void CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const; // CancelIo wrapper (for Win95 compatibility) BOOL CancelCommIo (void); }; #endif // __SERIAL_H nyquist-3.05/liblo/ser-to-osc/ser-to-osc.cpp0000644000175000000620000001564511466705460020002 0ustar stevestaff/* * ser-to-osc.cpp -- Roger Dannenberg, 2006 * * Usage: ser-to-osc inputdevice * * Note: this is C++ only because the Windows version uses the Serial class * for USB-Serial I/O. Hopefully compiling this as C++ will not cause * problems on Mac and Linux. * */ #include #include #ifdef WIN32 #else #include #include #include "string.h" #endif #define _WIN32_WINNT 0x1000 #include "lo/lo.h" #ifdef WIN32 #include "Serial.h" enum { EOF_Char = 27 }; CSerial serial; typedef CSerial *port_type; #define MAX_LINE 256 char inp_line[MAX_LINE]; int inp_len; CSerial *port_open(char *inputname) { LONG lLastError = serial.Open(inputname, 0, 0, false); if (lLastError != ERROR_SUCCESS) return NULL; // Setup the serial port (9600,8N1, which is the default setting) lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1); if (lLastError != ERROR_SUCCESS) return NULL; // Register only for the receive event lLastError = serial.SetMask(CSerial::EEventBreak | CSerial::EEventCTS | CSerial::EEventDSR | CSerial::EEventError | CSerial::EEventRing | CSerial::EEventRLSD | CSerial::EEventRecv); if (lLastError != ERROR_SUCCESS) return NULL; // Use 'non-blocking' reads, because we don't know how many bytes // will be received. This is normally the most convenient mode // (and also the default mode for reading data). lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking); if (lLastError != ERROR_SUCCESS) return NULL; inp_len = 0; return &serial; } char *port_getln(CSerial *serial, size_t *len_ptr) { // Keep reading data, until an EOF (CTRL-Z) has been received bool done = false; LONG lLastError; *len_ptr = 0; while (!done) { // Wait for an event lLastError = serial->WaitEvent(); if (lLastError != ERROR_SUCCESS) return NULL; // Save event const CSerial::EEvent eEvent = serial->GetEventType(); // Handle break event if (eEvent & CSerial::EEventBreak) { // printf("\n### BREAK received ###\n"); } // Handle CTS event if (eEvent & CSerial::EEventCTS) { // printf("\n### Clear to send %s ###\n", serial->GetCTS()?"on":"off"); } // Handle DSR event if (eEvent & CSerial::EEventDSR) { // printf("\n### Data set ready %s ###\n", serial->GetDSR()?"on":"off"); } // Handle error event if (eEvent & CSerial::EEventError) { printf("\n### ERROR: "); switch (serial->GetError()) { case CSerial::EErrorBreak: printf("Break condition"); break; case CSerial::EErrorFrame: printf("Framing error"); break; case CSerial::EErrorIOE: printf("IO device error"); break; case CSerial::EErrorMode: printf("Unsupported mode"); break; case CSerial::EErrorOverrun: printf("Buffer overrun"); break; case CSerial::EErrorRxOver: printf("Input buffer overflow"); break; case CSerial::EErrorParity: printf("Input parity error"); break; case CSerial::EErrorTxFull: printf("Output buffer full"); break; default: printf("Unknown"); break; } printf(" ###\n"); } // Handle ring event if (eEvent & CSerial::EEventRing) { // printf("\n### RING ###\n"); } // Handle RLSD/CD event if (eEvent & CSerial::EEventRLSD) { // printf("\n### RLSD/CD %s ###\n", serial->GetRLSD()?"on":"off"); } // Handle data receive event if (eEvent & CSerial::EEventRecv) { // Read data, until there is nothing left while (true) { // Read data from the COM-port DWORD dwBytesRead = 0; lLastError = serial->Read(inp_line + inp_len, 1, &dwBytesRead); if (lLastError != ERROR_SUCCESS) return NULL; if (dwBytesRead == 0) break; // printf("Read %c (%d)\n", inp_line[inp_len], inp_line[inp_len]); if (inp_line[inp_len] == '\n' || // inp_line[inp_len] == '\r' || inp_line[inp_len] == EOF_Char || inp_len >= MAX_LINE - 2) { inp_line[inp_len + 1] = '\0'; *len_ptr = inp_len + 1; inp_len = 0; done = true; break; } inp_len++; } } } return inp_line; } void port_close(CSerial *serial) { serial->Close(); } #else typedef FILE *port_type; FILE *port_open(char *inputname) { return fopen(inputname, "r"); } char *port_getln(FILE *input, size_t *len_ptr) { // linux does not have fgetln (must be bsd only) // return fgetln(input, len_ptr); static char line[256]; char *result = fgets(line, 256, input); if (result) *len_ptr = strlen(line); return result; } void port_close(FILE *input) { fclose(input); } #endif int main(int argc, char *argv[]) { /* an address to send messages to. sometimes it is better to let the server * pick a port number for you by passing NULL as the last argument */ lo_address t = lo_address_new(NULL, "7770"); char *inputname = NULL; port_type input = NULL; int verbose = 1; int argptr = 1; while (argptr < argc) { char *arg = argv[argptr]; if (*arg == '-') { if (arg[1] == 'q') { verbose = 0; } } else if (!inputname) { inputname = arg; } argptr++; } if (inputname) input = port_open(inputname); if (!input) { printf("Could not open %s\n", inputname); exit(EXIT_FAILURE); } /* send messages to /slider with two arguments, report any errors */ while (1) { /* get input data, report errors */ size_t len; char *s = port_getln(input, &len); int slider_no, value; float x; char channel[64]; /* buffer to hold "Channel" */ if (!s) exit(EXIT_SUCCESS); /* we don't need the newline, but we do want an EOS */ s[len - 1] = 0; len--; while (isspace(s[len - 1])) s[--len] = 0; /* trim white space */ if (verbose) printf("%s: ", s); if (sscanf(s, "%s %d %d", channel, &slider_no, &value) != 3) { puts("Error: expected 2 integers\n"); fflush(stdout); } x = value / 255.0F; if (x > 1) x = 1; if (x < 0) x = 0; if (verbose) printf("/slider %d %g\n", slider_no, x); if (lo_send(t, "/slider", "if", slider_no, x) == -1) { printf("OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t)); break; } } port_close(input); return 0; /* make compiler happy */ } nyquist-3.05/liblo/ser-to-osc/ser-to-osc.vcproj0000644000175000000620000001060111512143043020467 0ustar stevestaff nyquist-3.05/liblo/ChangeLog0000644000175000000620000003110711467003724015044 0ustar stevestaff2009-03-07 Stephen Sinclair * Fix some typos, grammar, and links in the documentation. * Remove TCP from TODO list. * Add recent contributors to the AUTHORS list. * Add previous release notes to the NEWS file. * Add note about MSVC in README. * Release 0.26. 2009-03-06 Stephen Sinclair * Add a return value to lo_bundle_add_message(). * Avoid pointer arithmetic on void* types for compilers that can't handle it. * Move all local variable declarations to the top of the scope. * Conditionally avoid the use of variable-argument macros if not GCC. * Fix multicast on Windows: join multicast group after bind() instead of before. * Avoid the use of C99 struct literals when giving timetag arguments. * Add premake4, used to generate MSVC project/solution files. * Add numerous typical kludges necessary to cover differences in MSVC. * Use log() instead of a while loop to calculate new data size. * Add return values for all functions that can potentially fail. * Add premake4-related files to the dist build. 2009-02-17 Stephen Sinclair * For multicast, enable SO_REUSEPORT as well as SO_REUSEADDR. (Mike Wozniewski) 2009-02-12 Stephen Sinclair * Fix the definition of LO_TT_IMMEDIATE per the OSC spec. (Dominic Sacré) 2009-02-01 Stephen Sinclair * Add function lo_message_get_timestamp(). (Alex McLean) * Fix magic constant in lo_timetag_diff. (Dominic Sacré) * Bump the LO_SO_VERSION version major number to resolve ABI incompatibilities with previous versions. In particular, the addition of 'const' to an argument of lo_blob_new() in r80 constituted an API add and removal, hence the reset of the 3rd number ('age') according to the libtool manual. (SS) 2009-01-04 Stephen Sinclair * Add checks to configure.ac for select() and poll(). * Use inet_addr if inet_aton is not available. (i.e., on Windows) * Retry a TCP connection once if it failed to connect on send. * Remove useless conditional call to freeaddrinfo(). * Only implement gai_strerrorA if gai_strerror was not already defined. * Make the TCP protocol retain session information for multiple connections. 2008-12-23 Nicholas Humfrey * Added a function called lo_server_wait() which waits for a message to be received. 2008-11-23 Stephen Sinclair * Use the \internal Doxygen command to hide internal functions. 2008-10-11 Kentaro Fukuchi * lo_url_get_protocol_id() has been added. * lo_address_new_with_proto() has been added. * Changed lo_address_new_from_url() to use lo_url_get_protocol_id(). 2008-10-09 Kentaro Fukuchi * src/tools/oscsend.c: Fixed compile-time error on OS X. (thanks to Koichiro Ozaki) 2008-10-07 Stephen Sinclair * Move lo_arg_size(), lo_get_path(), lo_arg_host/network_endian() back to lo_lowlevel.h. * Expose the lo_server_dispatch_data() function as public. * Fix zero-padding of path and type strings in lo_message_deserialise(). 2008-09-07 Kentaro Fukuchi * Memory leak in lo_address_new_from_url() has been fixed. * Memory leak in dispatch_method() has been fixed. * Fix a typo and some missing free() in testlo.c. 2008-09-04 Stephen Sinclair * Change license of LibLo to LGPL 2.1 or later. (With permission of all authors.) 2008-07-11 Kentaro Fukuchi * Some error checks have been added. * oscsend now uses strtod() instead of strtof(). strtof of glibc returned buggy results when --std=c99 is not given. (strtof is described in C99) 2008-06-18 Stephen Sinclair * Update AUTHORS * Release version 0.25 2008-06-05 Stephen Sinclair * Fix autogen.sh: Use glibtoolize if it exists, for OS X. * Fix undefined MSG_NOSIGNAL in testlo.c. * Fix warning on lo_message_deserialize(). 2008-05-05 Stephen Sinclair * Fix invalid pointer in lo_server_del_method() when doing pattern matching. (Camille Troillard) 2008-04-28 Stephen Sinclair * Add support for multicast groups to LibLo. * Add test case for sending a crafted packet that would crash a lo_server without validation. * Make validation-related functions internal to liblo. * Add server input validation along with a function to deserialise an OSC message. (Chris Hixon) * Fix bad socket number in lo_client_sockets when a server is freed. 2008-04-21 Stephen Sinclair * Added Daniel Lacroix's patch for level 2 broadcast support. * Use resolved IP address to detect broadcast address. 2008-02-25 Stephen Sinclair * Fix bug where curly brackets didn't match the last item in the comma-separated list. 2008-02-20 Stephen Sinclair * Added lo_bundle_free_messages() to free a bundle and the messages it points to. (Kentaro Fukuchi) 2008-01-27 Stephen Sinclair * Fix for lo_message_add(), wrong argument order for lo_message_add_varargs_internal(). (Dave Robillard) * Added test case for lo_message_add(). 2008-01-20 Stephen Sinclair * Added lo_message_add_varargs() to play well with C functions taking a variable number of arguments. (Dave Robillard) * Avoid unnecessary repetitive reallocation on lo_message_add_*(). (Dave Robillard) * Fixed errors related to 64-bit in packing blob and MIDI messages. (Dave Robillard) 2008-01-13 Stephen Sinclair * Fixed index increment in sendosc.c for string and symbol types 2008-01-12 Nicholas Humfrey * Added tools from Kentaro Fukuchi 2007-03-19 Nicholas Humfrey * Applied patch from Chris Hixon to check for buffer overflows 2007-03-16 Nicholas Humfrey * Fixed several compiler warnings * Changed address for package bug reports * Released version 0.24 2007-03-09 Nicholas Humfrey * Changed lo_blob_new() to take const void* (thanks to Lars Luthman) * Disable getnameinfo() method of getting hostname, when IPv6 is disabled * Unlink Unix server socket when it is close (thanks to Dominic SacrŽ) * Checks size of unix socket path properly * Now accepts unix socket format osc.unix://localhost/tmp/mysocket.sock * Released version 0.24pre1 2007-03-08 Nicholas Humfrey * Added lo_server_thread_new_with_proto(), as suggested by Dave Robillard * Applied patch from Aron Stansvik to fix bug with FreeBSD/NetBSD systems * Removed freeaddrinfo() from resolve_address() error case (thanks to Anthony Green) * Only call connect() for TCP sessions (thanks to Roger B. Dannenberg) 2006-03-29 Nicholas Humfrey * Applied lo_address_get_url() patch from Sze'kelyi Szabolcs * Added lo_server_get_protocol() and lo_address_get_protocol() * Added tests for lo_address_get_* tests to test tool 2006-01-26 Nicholas Humfrey * IPv6 is now disabled by default * Released version 0.23 2005-12-29 Nicholas Humfrey * Fixed pthread resource leak, when stopping thread 2005-12-21 Nicholas Humfrey * Fixed bug where sockets weren't closed when replying to messages * Split off resolve_address into seperate create_socket function * Only creates new sockets when needed 2005-12-05 Nicholas Humfrey * Added lo_send_from, lo_send_message_from and lo_send_bundle_from * Merged guts of lo_send_message and lo_send_bundle into new static send_data() 2005-09-04 Steve Harris * Released 0.22 2005-09-02 Steve Harris * address.c, server.c: Added patch from Martin Habets that redoes parts of previous patches... 2005-09-01 Steve Harris * address.c, server.c: Added patches from Jesse Chappell and Dave Robillard to close various sockets when there no longer used. 2005-08-19 Steve Harris * address.c, testlo.c: Added patch from Dave Robillard to fix parsing of IPV6 addresses in URLs. 2005-08-11 Martin Habets * message.c: Fix LO_CHAR sending on big endian architectures. 2005-08-09 Martin Habets * server.c: Add lo_server_del_method() * server_thread.c: Add lo_server_thread_del_method() 2005-07-26 Steve Harris * bundle.c, server.c: Endianess fixed from Topher Cyll for bundle timestamps. # Bundle delivery timing is still not right, theres an arithmetic # errorsomewhere, but I cant see it. 2005-06-05 Steve Harris * server.c: Patch from Lorenz Schori to optionally disable IPV6 support with --disable-ipv6 2005-03-31 Steve Harris * server.c: Patch from Martin Habets that expands wildcarded patch to the matching path where possible (eg. not when using the NULL wildcard path). 2005-03-04 Steve Harris * server.c: try to fix the global struct thing that keeps track of server sockets. 2005-02-03 Steve Harris * server.c: made UDP messages resolve back to thier originating server, or something close to it. 2005-02-03 Taybin Rutkin * server.c: commited resource leak fix from Jesse Chappell 2005-01-22 Steve Harris * address.c: fixed bug when determining protocol of URL with unspecified sub-protocol. Reported by Pix. 2005-01-13 Steve Harris * bundle.c: patch from Dave Robillard that fixes bundles of more than 4 messages. 2005-01-13 Steve Harris * message.c: made the arguments to _add_string and _add_symbol const char * for C++ compatibility. 2005-01-10 Steve Harris * message.c: added a source field that represents the source from which a message was received. Useful in method handlers to determine which client sent the message. 2004-12-21 Steve Harris * server.c: added patch from Walco van Loon and Pix that fixes a bug in the hostname detection fallback code 2004-11-19 Steve Harris * send.c: added lo_send_timestamped() 2004-11-17 Steve Harris * server.c: added code to handle bundle reception * bundle.c: code to build bundle objects * timetag.c: code to manipulate and test timetags 2004-10-19 Steve Harris Release 0.13 * lo.h: removed reference to obsolete header lo_backcompat.h 2004-10-17 Steve Harris * lo_server.c: added code to allow servers to poll() on the server socket, if available. From Sean Bolton. 2004-08-27 Steve Harris * lo_lowlevel.h, send.c: added OSX compatibility fixes from Taybin Rutkin. 2004-08-19 Steve Harris Release 0.9 * testlo.c: added more URL tests 2004-08-19 Steve Harris * address.c: more bugfixes to URL handling 2004-08-02 Steve Harris * server.c, address.c: fixed bugs and ommisions in URL handling 2004-07-28 Steve Harris * send.c, server.c: added code to handle UNIX domain sockets. 2004-07-12 Steve Harris * server_thread.c: added a lo_server_thread_stop() function for symmetry with lo_server_thread_start() 2004-06-07 Steve Harris * server.c: added a lo_server_recv_noblock() that will not wait for a packet to be received 2004-03-26 Steve Harris * doc/, *.h: added doxygen documentation * address.c: changed URL methods to accept/expect protocol specifiers (eg. osc.udp://...) * examples/*.c: added comments, slightly simplified 2004-03-21 Steve Harris * server.c: made binding to unspecified ports work 2004-03-21 Steve Harris * message.c: fixed coercion type bugs * server.c: fixed endian conversion bug * testlo.c: added lots of tests * send.c: added implicit guard variable to end of send arguments 2004-03-20 Steve Harris * message.c, send.c: added support for the remaining types OSC 2004-03-15 Steve Harris * message.c: changed the definition of the string argument accessor member (it was wrong before). * target.c, *.[ch]: lo_target* is now called lo_address*, this makes the api much clearer, %s/lo_target/lo_address/g, should bring all source files up to date. 2004-02-29 Steve Harris * configure.in, Makefile.am: added auto* stuff nyquist-3.05/liblo/depcomp0000755000175000000620000004271311467003724014654 0ustar stevestaff#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2007-03-29.01 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007 Free Software # Foundation, Inc. # 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add `dependent.h:' lines. sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: nyquist-3.05/liblo/compile0000755000175000000620000000717311466705460014663 0ustar stevestaff#! /bin/sh # Wrapper for compilers which do not understand `-c -o'. scriptversion=2005-05-14.22 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand `-c -o'. Remove `-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file `INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; esac ofile= cfile= eat= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as `compile cc -o foo foo.c'. # So we strip `-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no `-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # `.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` # Create the lock directory. # Note: use `[/.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: nyquist-3.05/liblo/configure.ac0000644000175000000620000000520311515462141015552 0ustar stevestaffAC_PREREQ(2.57) AC_INIT([liblo], [0.26], [liblo-devel@lists.sourceforge.net]) # libtool version: current:revision:age # # If the library source code has changed at all since the last update, then # increment revision (`c:r:a' becomes `c:r+1:a'). # # If any interfaces have been added, removed, or changed since the last update, # increment current, and set revision to 0. # # If any interfaces have been added since the last public release, then # increment age. # # If any interfaces have been removed since the last public release, then set # age to 0. LO_SO_VERSION=7:0:0 AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/address.c]) AM_CONFIG_HEADER([config.h]) AM_INIT_AUTOMAKE AC_ENABLE_STATIC(no) AC_ENABLE_SHARED(yes) AC_SUBST(LO_SO_VERSION) # disable support for ipv6. AC_ARG_ENABLE(ipv6, [ --enable-ipv6 Enable ipv6 support],want_ipv6=yes,) if test "$want_ipv6" = "yes"; then AC_DEFINE(ENABLE_IPV6, 1, Define this to enable ipv6.) fi # Checks for programs. AC_PROG_CC AM_PROG_LIBTOOL AM_PROG_CC_C_O AC_CHECK_PROG([DOXYGEN], [doxygen], [doc], []) AC_SUBST(DOXYGEN) # Checks for libraries. AC_CHECK_LIB([pthread], [pthread_create]) AC_SEARCH_LIBS([recvfrom], [socket]) AC_CHECK_FUNC([log], [], [AC_CHECK_LIB([m],[log])]) # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T # Check for features AC_CHECK_FUNC([select], [AC_DEFINE(HAVE_SELECT, [1], [Define to 1 if select() is available.])], [ AC_MSG_CHECKING([for select in ws2_32]) LIBS="$LIBS -lws2_32" # some winsock2 functions require XP, so WINNT=0x501 CFLAGS="$CFLAGS -DWIN32 -D_WIN32_WINNT=0x501" AC_TRY_LINK([#include ], [select(0,0,0,0,0)], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_SELECT, [1], [Define to 1 if select() is available.])], [AC_MSG_RESULT(no)]) ]) AC_CHECK_FUNC([poll], [AC_DEFINE(HAVE_POLL, [1], [Define to 1 if poll() is available.])]) AC_CHECK_FUNC([inet_aton], [AC_DEFINE(HAVE_INET_ATON, [1], [Define to 1 if inet_aton() is available.])]) # to make Windows compilation easier, lo/lo_endian.h uses conditional # compilation rather than configure to determine byte order #AC_C_BIGENDIAN([LO_BIGENDIAN="1"], [LO_BIGENDIAN="0"]) #AC_DEFINE_UNQUOTED(LO_BIGENDIAN, "$LO_BIGENDIAN", [If machine is bigendian]) #AC_SUBST(LO_BIGENDIAN) AC_CONFIG_FILES([ Makefile src/Makefile src/tools/Makefile examples/Makefile lo/Makefile lo/lo_endian.h liblo.pc doc/Makefile doc/reference.doxygen build/Makefile ]) AC_OUTPUT() nyquist-3.05/liblo/Makefile.osx0000644000175000000620000000032211466705460015542 0ustar stevestaffOBJECTS = message.o blob.o server.o address.o method.o pattern_match.o send.o timetag.o bundle.o nonblocking_server_example.o example_client: $(OBJECTS) g++ $(OBJECTS) $(LFLAGS) -o nonblocking_server_example nyquist-3.05/liblo/missing0000755000175000000620000002557711467003724014707 0ustar stevestaff#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2006-05-10.23 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case $1 in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $1 in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case $firstarg in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case $firstarg in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: nyquist-3.05/liblo/COPYING0000644000175000000620000006350411466705460014340 0ustar stevestaff GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] 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 Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these 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 other code 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. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. 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, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) 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. d) 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. e) 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 materials to be 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 with 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 Lesser 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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! nyquist-3.05/liblo/NEWS0000644000175000000620000002512211467003724013771 0ustar stevestaff -------------------------------------------- 2009-03-07: Release 0.26 -------------------------------------------- We are pleased to present stable release 0.26 of LibLo, the lightweight, easy to use implementation of the Open Sound Control protocol. Open Sound Control (OSC) is a protocol for communication among computers, sound synthesizers, and other multimedia devices that is designed for use over modern network transports. This release marks the first release of LibLo under the LGPL license version 2.1 or later, allowing the use of LibLo in non-GPL applications as long as it is dynamically linked such that the LibLo portion of the application can remain freely modifiable. We hope that this will allow compatibility with a wider variety of audio applications and encourage the use of open protocols even in commercial software. (This change was motivated by receiving a number of requests for special permission for the use of LibLo in non-GPL software.) This release also introduces some new features, such as the ability to use custom transports, proper TCP multi-session support, access to bundle timestamp information, and wider C compiler compatibility. Details: - Change license to LGPL 2.1 or later. - Add return codes to all functions that may fail. - Fix memory leaks in lo_address_new_from_url(), dispatch_method(), lo_url_get_path() - Move lo_arg_size(), lo_get_path(), lo_arg_host/network_endian() back to lo_lowlevel.h. - Expose the lo_server_dispatch_data() function as public, making it possible to react to messages contained in an arbitrary block of memory. (i.e., allows use with custom transport protocols) - Get protocol by ID number. - Keep TCP sessions open, and automatically track multiple open sessions in a data structure. - Allow access to bundle timestamp information. - Fix bug in lo_timetag_diff(). - Change the value of LO_TT_IMMEDIATE to correspond with the OSC specification. - Enable SO_REUSEPORT when initializing a multicast server. - Update the "soname" describing API/ABI compatibility. - Update documentation and various bug fixes. - Compiles under MSVC, avoiding the use of gcc-isms when not using gcc. Contributions by: - Mike Wozniewski - Dominic Sacré - Alex McLean - Steve Harris - Kentaro Fukuchi - Koichiro Ozaki - Stephen Sinclair Please feel free to download it at SourceForge: http://downloads.sourceforge.net/liblo/liblo-0.26.tar.gz Or read the online documentation: http://liblo.sourceforge.net Stephen Sinclair LibLo maintainer -------------------------------------------- 2008-07-18: Release 0.25 -------------------------------------------- We are pleased to present stable release 0.25 of LibLo, the lightweight, easy to use implementation of the Open Sound Control protocol. Open Sound Control (OSC) is a protocol for communication among computers, sound synthesizers, and other multimedia devices that is optimized for modern networking technology. This release brings several new features, including support for broadcast messages, multicast UDP groups, message deserialisation, and input validation. Details: - Check for buffer overflows - Added oscsend and oscdump command-line tools - Added lo_message_add_varargs() for variable-argument C functions. - Added lo_bundle_free_messages() - Bug fix for pattern matching. (curly braces) - Broadcast support - Added lo_message_deserialise() - Multicast support - Fixes for compiling on OS X - General bug fixes Contributions by: - Camille Troillard - Chris Hixon - Kentaro Fukuchi - Dave Robillard - Nicolas Humfrey - Stephen Sinclair Please feel free to download it at SourceForge: http://downloads.sourceforge.net/liblo/liblo-0.25.tar.gz Or read the online documentation: http://liblo.sourceforge.net Stephen Sinclair LibLo maintainer -------------------------------------------- 2007-03-21: Release 0.24 -------------------------------------------- About: LibLO is a lightweight library for handling the sending and receiving of messages according to the Open Sound Control (OSC) protocol on POSIX systems. Changes: lo_server_get_protocol() and lo_address_get_protocol() were added. Tests for lo_address_get_* were added to the test tool. Several compiler warnings were fixed. The address for package bug reports was changed. lo_blob_new() was changed to take const void*. The getnameinfo() method of getting hostname is disabled when IPv6 is disabled. A Unix server socket is now unlinked when it is closed. The size of a Unix socket path is checked properly. -------------------------------------------- 2006-01-27: Release 0.23 -------------------------------------------- Liblo, the Lite OSC library, is an implementation of the Open Sound Control protocol for POSIX systems*. It is written in ANSI C99 and released under the GNU General Public Licence. It is designed to make developing OSC applictions as easy as possible. http://liblo.sourceforge.net/ nick. Changes: * New Maintainer (me!) * Fixed pthread resource leak, when stopping server * IPv6 is now disabled by default * Fixed bug where sockets weren't closed when replying to messages * Split off resolve_address into seperate create_socket function * Only creates new sockets when needed * Added lo_send_from, lo_send_message_from and lo_send_bundle_from -------------------------------------------- 2005-09-09: Release 0.22 -------------------------------------------- Liblo, the Lite OSC library, is an implementation of the Open Sound Control protocol for POSIX systems*. It is written in ANSI C99 and released under the GNU General Public Licence. It is designed to make developing OSC applictions as easy as possible. http://plugin.org.uk/liblo/ - Steve Changes: Fixes for socket leaking from Martin Habets, Dave Robillard and Jesse Chappell Fix for IPV6 numerical address parsing from Dave Robillard Fix for char handling on bigendian machines from Martin Habets (and others) New lo_server(thread)_del_method() from Martin Habets Endianess and arithmetic fixes for bundle timestamps from Topher Cyll - bundle delivery is still not accurate though Patch to optioanlly disable IPV6 support from Lorenz Schori * and MS Windows, under some environment or other -------------------------------------------- 2005-03-03: Release 0.18 -------------------------------------------- http://www.plugin.org.uk/liblo/releases/liblo-0.18.tar.gz This is bugfix release and fixes a critical bug in 0.17 that bites when trying to connect multiple clients to one server. All users of 0.17 should upgrade as soon as possible. Liblo is an implementation of the Open Sound Control protocol for POSIX systems. It is released under the GNU General Public Licence. http://www.plugin.org.uk/liblo/ http://www.cnmat.berkeley.edu/OpenSoundControl/ - Steve -------------------------------------------- 2005-02-24: Release 0.17 -------------------------------------------- Liblo, the Lite OSC library, is an implementation of the Open Sound Control [1] protocol for POSIX systems. It is written in ANSI C99 and released under the GNU General Public Licence. It is designed to make developing OSC applictions as easy as possible. http://plugin.org.uk/liblo/ Changes: Patch from Jesse Chappell to fix memory leak Ability to directly reply to the sender of a UDP message Preliminary support for the OSC method enumeration scheme - Steve [1] http://www.cnmat.berkeley.edu/OpenSoundControl/ -------------------------------------------- 2005-01-26: Release 0.16 -------------------------------------------- Liblo, the Lite OSC library, is an implementation of the Open Sound Control [1] protocol for POSIX systems. It is written in ANSI C and released under the GNU General Public Licence. It is designed to make developing OSC applictions as easy as possible. http://plugin.org.uk/liblo/ Changes: Patch from Dave Robillard that fixes bundles of more than 4 messages. Some const char * for C++ compatibility. Added a source field to messages that represents the source from which a message was received. Useful in method handlers to determine which client sent the message. Added patch from Walco van Loon and Pix that fixes a bug in the hostname detection fallback code - Steve [1] http://www.cnmat.berkeley.edu/OpenSoundControl/ -------------------------------------------- 2004-10-19: Release 0.13 -------------------------------------------- liblo is an implementation of the Open Sound Control[1] protocol for POSIX systems. It is written in ANSI C and released under the GNU General Public Licence. It is designed to make developing OSC applictions as easy as possible. http://plugin.org.uk/liblo/ This release adds Mac OSX compatibility fixes from Taybin Rutkin, a memory leak fix from Jesse Chappell and methods and examples to allow server polling from exisitng threads from Sean Bolton. Some legacy compatobility code has been removed, but this should not affect anyone. Documentation has been updated to reflect the changes. [1] http://www.cnmat.berkeley.edu/OpenSoundControl/ [website is currently down] -------------------------------------------- 2004-08-19: Release 0.9 -------------------------------------------- liblo is an implementation of the Open Sound Control[1] protocol for POSIX systems. It is released under the GPL. It is written in ANSI C. http://plugin.org.uk/liblo/ This release adds: (over the last stable release, 0.5) * Nonblocking mesage dispatcher (useful for single GUI-thread applications, eg Qt, GTK+) * bugfixes to URL handling (0.6 - 0.8 broke DSSI) * UNIX domain (FIFO) socket server/client support * TCP domain socket server/client support * A method to stop server threads * Better regression tests (testlo) * Fixed memory leaks * More documentation * Dynamic library building fixes - Steve [1] http://www.cnmat.berkeley.edu/OpenSoundControl/ -------------------------------------------- 2004-03-29: Release 0.5 -------------------------------------------- liblo is a easy to use OSC (Open Sound Control) implementation written in C. http://plugin.org.uk/liblo/ See the website for docs and example code. Changes since last release: bugfixes OSC URL handling better IPV6 support real documentation better example code support for all the types listed in the specification automatic port number selection for servers lo_target type has been deprecated, use lo_address now some buffer overrun checks in lo_send() This version is not binary compatible with the previous release. - Steve nyquist-3.05/liblo/lo/0002755000175000000620000000000011537433130013700 5ustar stevestaffnyquist-3.05/liblo/lo/lo_macros.h0000644000175000000620000000505011467003724016031 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_MACROS_H #define LO_MACROS_H /* macros that have to be defined after function signatures */ #ifdef __cplusplus extern "C" { #endif /* \brief Maximum length of UDP messages in bytes */ #define LO_MAX_MSG_SIZE 32768 /* \brief A set of macros to represent different communications transports */ #define LO_DEFAULT 0x0 #define LO_UDP 0x1 #define LO_UNIX 0x2 #define LO_TCP 0x4 /* an internal value, ignored in transmission but check against LO_MARKER in the * argument list. Used to do primitive bounds checking */ #define LO_MARKER_A 0xdeadbeef #define LO_MARKER_B 0xf00baa23 #define LO_ARGS_END LO_MARKER_A, LO_MARKER_B #define lo_message_add_varargs(msg, types, list) \ lo_message_add_varargs_internal(msg, types, list, __FILE__, __LINE__) #ifdef __GNUC__ #define lo_message_add(msg, types...) \ lo_message_add_internal(msg, __FILE__, __LINE__, types, \ LO_MARKER_A, LO_MARKER_B) #define lo_send(targ, path, types...) \ lo_send_internal(targ, __FILE__, __LINE__, path, types, \ LO_MARKER_A, LO_MARKER_B) #define lo_send_timestamped(targ, ts, path, types...) \ lo_send_timestamped_internal(targ, __FILE__, __LINE__, ts, path, \ types, LO_MARKER_A, LO_MARKER_B) #define lo_send_from(targ, from, ts, path, types...) \ lo_send_from_internal(targ, from, __FILE__, __LINE__, ts, path, \ types, LO_MARKER_A, LO_MARKER_B) #else /* In non-GCC compilers, there is no support for variable-argument * macros, so provide "internal" vararg functions directly instead. */ int lo_message_add(lo_message msg, const char *types, ...); int lo_send(lo_address targ, const char *path, const char *types, ...); int lo_send_timestamped(lo_address targ, lo_timetag ts, const char *path, const char *types, ...); int lo_send_from(lo_address targ, lo_server from, lo_timetag ts, const char *path, const char *types, ...); #endif #ifdef __cplusplus } #endif #endif nyquist-3.05/liblo/lo/lo_types.h0000644000175000000620000001031711467003724015713 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_TYPES_H #define LO_TYPES_H /** * \file lo_types.h The liblo headerfile defining types used by this API. */ #ifdef __cplusplus extern "C" { #endif #ifdef WIN32 #include #include #else #include #endif #include #include "lo/lo_osc_types.h" /** * \brief A reference to an OSC service. * * Created by calls to lo_address_new() or lo_address_new_from_url(). */ typedef void *lo_address; /** * \brief A object to store an opaque binary data object. * * Can be passed over OSC using the 'b' type. Created by calls to lo_blob_new(). */ typedef void *lo_blob; /** * \brief A low-level object used to represent messages passed over OSC. * * Created by calls to lo_message_new(), arguments can be added with calls to * lo_message_add_*(). */ typedef void *lo_message; /** * \brief A low-level object used to represent bundles of messages passed over * OSC. * * Created by calls to lo_bundle_new(), messages can be added with calls to * lo_bundle_add_message(). */ typedef void *lo_bundle; /** * \brief An object representing an method on a server. * * Returned by calls to lo_server_thread_add_method() and * lo_server_add_method(). */ typedef void *lo_method; /** * \brief An object representing an instance of an OSC server. * * Created by calls to lo_server_new(). If you with the library to take care of * the threading as well you can just use server threads instead. */ typedef void *lo_server; /** * \brief An object representing a thread containing an OSC server. * * Created by calls to lo_server_thread_new(). */ typedef void *lo_server_thread; /** * \brief A callback function to receive notifcation of an error in a server or * server thread. * * On callback the paramters will be set to the following values: * * \param num An error number that can be used to identify this condition. * \param msg An error message describing the condidtion. * \param where A string describing the place the error occured - typically * either a function call or method path. */ typedef void (*lo_err_handler)(int num, const char *msg, const char *where); /** * \brief A callback function to receive notifcation of matching message * arriving in the server or server thread. * * The return value tells the method dispatcher whether this handler * has dealt with the message correctly: a return value of 0 indicates * that it has been handled, and it should not attempt to pass it on * to any other handlers, non-0 means that it has not been handled and * the dispatcher will attempt to find more handlers that match the * path and types of the incoming message. * * On callback the paramters will be set to the following values: * * \param path That path that the incoming message was sent to * \param types If you specided types in your method creation call then this * will match those and the incoming types will have been coerced to match, * otherwise it will be the types of the arguments of the incoming message. * \param argv An array of lo_arg types containing the values, e.g. if the * first argument of the incoming message is of type 'f' then the vlaue will be * found in argv[0]->f. * \param argc The number of argumets received. * \param msg A structure containing the original raw message as received. No * type coercion will have occured and the data will be in OSC byte order * (bigendian). * \param user_data This contains the user_data value passed in the call to * lo_server_thread_add_method. */ typedef int (*lo_method_handler)(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data); #ifdef __cplusplus } #endif #endif nyquist-3.05/liblo/lo/lo_endian.h.in0000644000175000000620000000745211512404520016406 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_ENDIAN_H #define LO_ENDIAN_H #include #ifdef _MSC_VER #define inline __inline #define uint64_t unsigned __int64 #define uint32_t unsigned __int32 #else #include #endif #ifdef WIN32 #include #include #else #include #endif #ifdef __cplusplus extern "C" { #endif #define lo_swap16(x) htons(x) #define lo_swap32(x) htonl(x) /* These macros come from the Linux kernel */ #ifndef lo_swap16 #define lo_swap16(x) \ ({ \ uint16_t __x = (x); \ ((uint16_t)( \ (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ }) #warning USING UNOPTIMISED ENDIAN STUFF #endif #ifndef lo_swap32 #define lo_swap32(x) \ ({ \ uint32_t __x = (x); \ ((uint32_t)( \ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ }) #endif #if 0 #ifndef lo_swap64 #define lo_swap64(x) \ ({ \ uint64_t __x = (x); \ ((uint64_t)( \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ }) #endif #else typedef union { uint64_t all; struct { uint32_t a; uint32_t b; } part; } lo_split64; static inline uint64_t lo_swap64(uint64_t x) { lo_split64 in, out; in.all = x; out.part.a = lo_swap32(in.part.b); out.part.b = lo_swap32(in.part.a); return out.all; } #endif /* Host to OSC and OSC to Host conversion macros */ #if defined(__linux__) || defined(__GLIBC__) #include // set __BYTE_ORDER #endif #ifndef __BIG_ENDIAN #define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 #endif #ifdef __APPLE__ #include #if defined(__LITTLE_ENDIAN__) #define __BYTE_ORDER __LITTLE_ENDIAN #endif #if defined(__BIG_ENDIAN__) #define __BYTE_ORDER __BIG_ENDIAN #endif #endif #ifdef WIN32 #define __BYTE_ORDER __LITTLE_ENDIAN #endif #ifndef __BYTE_ORDER #error __BYTE_ORDER not defined #endif #if __BYTE_ORDER == __BIG_ENDIAN #define lo_htoo16(x) (x) #define lo_htoo32(x) (x) #define lo_htoo64(x) (x) #define lo_otoh16(x) (x) #define lo_otoh32(x) (x) #define lo_otoh64(x) (x) #else #define lo_htoo16 lo_swap16 #define lo_htoo32 lo_swap32 #define lo_htoo64 lo_swap64 #define lo_otoh16 lo_swap16 #define lo_otoh32 lo_swap32 #define lo_otoh64 lo_swap64 #endif #ifdef __cplusplus } #endif #ifdef _MSC_VER #undef inline #undef uint64_t #undef uint32_t #endif #endif /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/lo/lo_lowlevel.h0000644000175000000620000006553111467003724016410 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_LOWLEVEL_H #define LO_LOWLEVEL_H #include "lo/lo_osc_types.h" /** * \file lo_lowlevel.h The liblo headerfile defining the low-level API * functions. */ #ifdef __cplusplus extern "C" { #endif #include #ifdef _MSC_VER #define ssize_t SSIZE_T #define uint32_t unsigned __int32 #else #include #endif #include "lo/lo_types.h" #include "lo/lo_errors.h" /** * \defgroup liblolowlevel Low-level OSC API * * Use these functions if you require more precise control over OSC message * contruction or handling that what is provided in the high-level functions * described in liblo. * @{ */ /** * \brief Type used to represent numerical values in conversions between OSC * types. */ typedef long double lo_hires; /** * \brief Send a lo_message object to target targ * * This is slightly more efficient than lo_send() if you want to send a lot of * similar messages. The messages are constructed with the lo_message_new() and * \ref lo_message_add_int32 "lo_message_add*()" functions. */ int lo_send_message(lo_address targ, const char *path, lo_message msg); /** * \brief Send a lo_message object to target targ from address of serv * * This is slightly more efficient than lo_send() if you want to send a lot of * similar messages. The messages are constructed with the lo_message_new() and * \ref lo_message_add_int32 "lo_message_add*()" functions. * * \param targ The address to send the message to * \param serv The server socket to send the message from * (can be NULL to use new socket) * \param path The path to send the message to * \param msg The bundle itself */ int lo_send_message_from(lo_address targ, lo_server serv, const char *path, lo_message msg); /** * \brief Send a lo_bundle object to address targ * * Bundles are constructed with the * lo_bundle_new() and lo_bundle_add_message() functions. */ int lo_send_bundle(lo_address targ, lo_bundle b); /** * \brief Send a lo_bundle object to address targ from address of serv * * Bundles are constructed with the * lo_bundle_new() and lo_bundle_add_message() functions. * * \param targ The address to send the bundle to * \param serv The server socket to send the bundle from * (can be NULL to use new socket) * \param b The bundle itself */ int lo_send_bundle_from(lo_address targ, lo_server serv, lo_bundle b); /** * \brief Create a new lo_message object */ lo_message lo_message_new(); /** * \brief Free memory allocated by lo_message_new() and any subsequent * \ref lo_message_add_int32 lo_message_add*() calls. */ void lo_message_free(lo_message m); /** * \brief Append a number of arguments to a message. * * The data will be added in OSC byteorder (bigendian). * * \param m The message to be extended. * \param types The types of the data items in the message, types are defined in * lo_types_common.h * \param ... The data values to be transmitted. The types of the arguments * passed here must agree with the types specified in the type parameter. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add(lo_message m, const char *types, ...); /** \internal \brief the real message_add function (don't call directly) */ int lo_message_add_internal(lo_message m, const char *file, const int line, const char *types, ...); /** * \brief Append a varargs list to a message. * * The data will be added in OSC byteorder (bigendian). * IMPORTANT: args list must be terminated with LO_ARGS_END, or this call will * fail. This is used to do simple error checking on the sizes of parameters * passed. * * \param m The message to be extended. * \param types The types of the data items in the message, types are defined in * lo_types_common.h * \param ap The va_list created by a C function declared with an * ellipsis (...) argument, and pre-initialised with * "va_start(ap)". The types of the arguments passed here must agree * with the types specified in the type parameter. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_varargs(lo_message m, const char *types, va_list ap); /** \internal \brief the real message_add_varargs function (don't call directly) */ int lo_message_add_varargs_internal(lo_message m, const char *types, va_list ap, const char *file, const int line); /** * \brief Append a data item and typechar of the specified type to a message. * * The data will be added in OSC byteorder (bigendian). * * \param m The message to be extended. * \param a The data item. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_int32(lo_message m, int32_t a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_float(lo_message m, float a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_string(lo_message m, const char *a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_blob(lo_message m, lo_blob a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_int64(lo_message m, int64_t a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_timetag(lo_message m, lo_timetag a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_double(lo_message m, double a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_symbol(lo_message m, const char *a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_char(lo_message m, char a); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_midi(lo_message m, uint8_t a[4]); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_true(lo_message m); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_false(lo_message m); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_nil(lo_message m); /** * \brief Append a data item and typechar of the specified type to a message. * See lo_message_add_int32() for details. * * \return Less than 0 on failure, 0 on success. */ int lo_message_add_infinitum(lo_message m); /** * \brief Returns the source (lo_address) of an incoming message. * * Returns NULL if the message is outgoing. Do not free the returned address. */ lo_address lo_message_get_source(lo_message m); /** * \brief Returns the timestamp (lo_timetag *) of a bundled incoming message. * * Returns LO_TT_IMMEDIATE if the message is outgoing, or did not arrive * contained in a bundle. Do not free the returned timetag. */ lo_timetag lo_message_get_timestamp(lo_message m); /** * \brief Return the message type tag string. * * The result is valid until further data is added with lo_message_add*(). */ char *lo_message_get_types(lo_message m); /** * \brief Return the message argument count. * * The result is valid until further data is added with lo_message_add*(). */ int lo_message_get_argc(lo_message m); /** * \brief Return the message arguments. Do not free the returned data. * * The result is valid until further data is added with lo_message_add*(). */ lo_arg **lo_message_get_argv(lo_message m); /** * \brief Return the length of a message in bytes. * * \param m The message to be sized * \param path The path the message will be sent to */ size_t lo_message_length(lo_message m, const char *path); /** * \brief Serialise the lo_message object to an area of memory and return a * pointer to the serialised form. Opposite of lo_message_deserialise(). * * \param m The message to be serialised * \param path The path the message will be sent to * \param to The address to serialise to, memory will be allocated if to is * NULL. * \param size If this pointer is non-NULL the size of the memory area * will be written here * * The returned form is suitable to be sent over a low level OSC transport, * having the correct endianess and bit-packed structure. */ void *lo_message_serialise(lo_message m, const char *path, void *to, size_t *size); /** * \brief Deserialise a raw OSC message and return a new lo_message object. * Opposite of lo_message_serialise(). * * \param data Pointer to the raw OSC message data in network transmission form * (network byte order where appropriate). * \param size The size of data in bytes * \param result If this pointer is non-NULL, the result or error code will * be written here. * * Returns a new lo_message, or NULL if deserialisation fails. * Use lo_message_free() to free the resulting object. */ lo_message lo_message_deserialise(void *data, size_t size, int *result); /** * \brief Dispatch a raw block of memory containing an OSC message. * * This is useful when a raw block of memory is available that is * structured as OSC, and you wish to use liblo to dispatch the * message to a handler function as if it had been received over the * network. * * \param s The lo_server to use for dispatching. * \param data Pointer to the raw OSC message data in network transmission form * (network byte order where appropriate). * \param size The size of data in bytes * * Returns the number of bytes used if successful, or less than 0 otherwise. */ int lo_server_dispatch_data(lo_server s, void *data, size_t size); /** * \brief Return the hostname of a lo_address object * * Returned value must not be modified or free'd. Value will be a dotted quad, * colon'd IPV6 address, or resolvable name. */ const char *lo_address_get_hostname(lo_address a); /** * \brief Return the port/service name of a lo_address object * * Returned value must not be modified or free'd. Value will be a service name * or ASCII representation of the port number. */ const char *lo_address_get_port(lo_address a); /** * \brief Return the protocol of a lo_address object * * Returned value will be one of LO_UDP, LO_TCP or LO_UNIX. */ int lo_address_get_protocol(lo_address a); /** * \brief Return a URL representing an OSC address * * Returned value must be free'd. */ char *lo_address_get_url(lo_address a); /** * \brief Set the Time-to-Live value for a given target address. * * This is required for sending multicast UDP messages. A value of 1 * (the usual case) keeps the message within the subnet, while 255 * means a global, unrestricted scope. * * \param t An OSC address. * \param ttl An integer specifying the scope of a multicast UDP message. */ void lo_address_set_ttl(lo_address t, int ttl); /** * \brief Get the Time-to-Live value for a given target address. * * \param t An OSC address. * \return An integer specifying the scope of a multicast UDP message. */ int lo_address_get_ttl(lo_address t); /** * \brief Create a new bundle object. * * OSC Bundles encapsulate one or more OSC messages and may include a timestamp * indicating when the bundle should be dispatched. * * \param tt The timestamp when the bundle should be handled by the receiver. * Pass LO_TT_IMMEDIATE if you want the receiving server to dispatch * the bundle as soon as it receives it. */ lo_bundle lo_bundle_new(lo_timetag tt); /** * \brief Adds an OSC message to an existing bundle. * * The message passed is appended to the list of messages in the bundle to be * dispatched to 'path'. * * \return 0 if successful, less than 0 otherwise. */ int lo_bundle_add_message(lo_bundle b, const char *path, lo_message m); /** * \brief Return the length of a bundle in bytes. * * Includes the marker and typetage length. * * \param b The bundle to be sized */ size_t lo_bundle_length(lo_bundle b); /** * \brief Serialise the bundle object to an area of memory and return a * pointer to the serialised form. * * \param b The bundle to be serialised * \param to The address to serialise to, memory will be allocated if to is * NULL. * \param size If this pointer is non-NULL the size of the memory area * will be written here * * The returned form is suitable to be sent over a low level OSC transport, * having the correct endianess and bit-packed structure. */ void *lo_bundle_serialise(lo_bundle b, void *to, size_t *size); /** * \brief Frees the memory taken by a bundle object. * * \param b The bundle to be freed. */ void lo_bundle_free(lo_bundle b); /** * \brief Frees the memory taken by a bundle object and messages in the bundle. * * \param b The bundle, which may contain messages, to be freed. */ void lo_bundle_free_messages(lo_bundle b); /** * \brief Return true if the type specified has a numerical value, such as * LO_INT32, LO_FLOAT etc. * * \param a The type to be tested. */ int lo_is_numerical_type(lo_type a); /** * \brief Return true if the type specified has a textual value, such as * LO_STRING or LO_SYMBOL. * * \param a The type to be tested. */ int lo_is_string_type(lo_type a); /** * \brief Attempt to convert one OSC type to another. * * Numerical types (eg LO_INT32, LO_FLOAT etc.) may be converted to other * numerical types and string types (LO_STRING and LO_SYMBOL) may be converted * to the other type. This is done automatically if a received message matches * the path, but not the exact types, and is coercible (ie. all numerical * types in numerical positions). * * On failure no translation occurs and false is returned. * * \param type_to The type of the destination variable. * \param to A pointer to the destination variable. * \param type_from The type of the source variable. * \param from A pointer to the source variable. */ int lo_coerce(lo_type type_to, lo_arg *to, lo_type type_from, lo_arg *from); /** * \brief Return the numerical value of the given argument with the * maximum native system precision. */ lo_hires lo_hires_val(lo_type type, lo_arg *p); /** * \brief Create a new server instance. * * Using lo_server_recv(), lo_servers block until they receive OSC * messages. If you want non-blocking behaviour see * lo_server_recv_noblock() or the \ref lo_server_thread_new * "lo_server_thread_*" functions. * * \param port If NULL is passed then an unused UDP port will be chosen by the * system, its number may be retrieved with lo_server_thread_get_port() * so it can be passed to clients. Otherwise a decimal port number, service * name or UNIX domain socket path may be passed. * \param err_h An error callback function that will be called if there is an * error in messge reception or server creation. Pass NULL if you do not want * error handling. */ lo_server lo_server_new(const char *port, lo_err_handler err_h); /** * \brief Create a new server instance, specifying protocol. * * Using lo_server_recv(), lo_servers block until they receive OSC * messages. If you want non-blocking behaviour see * lo_server_recv_noblock() or the \ref lo_server_thread_new * "lo_server_thread_*" functions. * * \param port If using UDP then NULL may be passed to find an unused port. * Otherwise a decimal port number orservice name or may be passed. * If using UNIX domain sockets then a socket path should be passed here. * \param proto The protocol to use, should be one of LO_UDP, LO_TCP or LO_UNIX. * \param err_h An error callback function that will be called if there is an * error in messge reception or server creation. Pass NULL if you do not want * error handling. */ lo_server lo_server_new_with_proto(const char *port, int proto, lo_err_handler err_h); /** * \brief Create a new server instance, and join a UDP multicast group. * * \param group The multicast group to join. See documentation on IP * multicast for the acceptable address range; e.g., http://tldp.org/HOWTO/Multicast-HOWTO-2.html * \param port If using UDP then NULL may be passed to find an unused port. * Otherwise a decimal port number or service name or may be passed. * If using UNIX domain sockets then a socket path should be passed here. * \param err_h An error callback function that will be called if there is an * error in messge reception or server creation. Pass NULL if you do not want * error handling. */ lo_server lo_server_new_multicast(const char *group, const char *port, lo_err_handler err_h); /** * \brief Free up memory used by the lo_server object */ void lo_server_free(lo_server s); /** * \brief Wait for an OSC message to be received * * \param s The server to wait for connections on. * \param timeout A timeout in milliseconds to wait for the incoming packet. * a value of 0 will return immediately. * * The return value is 1 if there is a message waiting or 0 if * there is no message. If there is a message waiting you can now * call lo_server_recv() to receive that message. */ int lo_server_wait(lo_server s, int timeout); /** * \brief Look for an OSC message waiting to be received * * \param s The server to wait for connections on. * \param timeout A timeout in milliseconds to wait for the incoming packet. * a value of 0 will return immediately. * * The return value is the number of bytes in the received message or 0 if * there is no message. The message will be dispatched to a matching method * if one is found. */ int lo_server_recv_noblock(lo_server s, int timeout); /** * \brief Block, waiting for an OSC message to be received * * The return value is the number of bytes in the received message. The message * will be dispatched to a matching method if one is found. */ int lo_server_recv(lo_server s); /** * \brief Add an OSC method to the specifed server. * * \param s The server the method is to be added to. * \param path The OSC path to register the method to. If NULL is passed the * method will match all paths. * \param typespec The typespec the method accepts. Incoming messages with * similar typespecs (e.g. ones with numerical types in the same position) will * be coerced to the typespec given here. * \param h The method handler callback function that will be called if a * matching message is received * \param user_data A value that will be passed to the callback function, h, * when its invoked matching from this method. */ lo_method lo_server_add_method(lo_server s, const char *path, const char *typespec, lo_method_handler h, void *user_data); /** * \brief Delete an OSC method from the specifed server. * * \param s The server the method is to be removed from. * \param path The OSC path of the method to delete. If NULL is passed the * method will match the generic handler. * \param typespec The typespec the method accepts. */ void lo_server_del_method(lo_server s, const char *path, const char *typespec); /** * \brief Return the file descriptor of the server socket. * * If the server protocol supports exposing the server's underlying * receive mechanism for monitoring with select() or poll(), this function * returns the file descriptor needed, otherwise, it returns -1. * * WARNING: when using this function beware that not all OSC packets that are * received are dispatched immediately. lo_server_events_pending() and * lo_server_next_event_delay() can be used to tell if there are pending * events and how long before you should attempt to receive them. */ int lo_server_get_socket_fd(lo_server s); /** * \brief Return the port number that the server has bound to. * * Useful when NULL is passed for the port number and you wish to know how to * address the server. */ int lo_server_get_port(lo_server s); /** * \brief Return the protocol that the server is using. * * Returned value will be one of LO_UDP, LO_TCP or LO_UNIX. */ int lo_server_get_protocol(lo_server s); /** * \brief Return an OSC URL that can be used to contact the server. * * The return value should be free()'d when it is no longer needed. */ char *lo_server_get_url(lo_server s); /** * \brief Return true if there are scheduled events (eg. from bundles) * waiting to be dispatched by the server */ int lo_server_events_pending(lo_server s); /** * \brief Return the time in seconds until the next scheduled event. * * If the delay is greater than 100 seconds then it will return 100.0. */ double lo_server_next_event_delay(lo_server s); /** * \brief Return the protocol portion of an OSC URL, eg. udp, tcp. * * This library uses OSC URLs of the form: osc.prot://hostname:port/path if the * prot part is missing, UDP is assumed. * * The return value should be free()'d when it is no longer needed. */ char *lo_url_get_protocol(const char *url); /** * \brief Return the protocol ID of an OSC URL. * * This library uses OSC URLs of the form: osc.prot://hostname:port/path if the * prot part is missing, UDP is assumed. * Returned value will be one of LO_UDP, LO_TCP, LO_UNIX or -1. * * \return An integer specifying the protocol. Return -1 when the protocol is * not supported by liblo. * */ int lo_url_get_protocol_id(const char *url); /** * \brief Return the hostname portion of an OSC URL. * * The return value should be free()'d when it is no longer needed. */ char *lo_url_get_hostname(const char *url); /** * \brief Return the port portion of an OSC URL. * * The return value should be free()'d when it is no longer needed. */ char *lo_url_get_port(const char *url); /** * \brief Return the path portion of an OSC URL. * * The return value should be free()'d when it is no longer needed. */ char *lo_url_get_path(const char *url); /* utility functions */ /** * \brief A function to calculate the amount of OSC message space required by a * C char *. * * Returns the storage size in bytes, which will always be a multiple of four. */ int lo_strsize(const char *s); /** * \brief A function to calculate the amount of OSC message space required by a * lo_blob object. * * Returns the storage size in bytes, which will always be a multiple of four. */ uint32_t lo_blobsize(lo_blob b); /** * \brief Test a string against an OSC pattern glob * * \param str The string to test * \param p The pattern to test against */ int lo_pattern_match(const char *str, const char *p); /** \internal \brief the real send function (don't call directly) */ int lo_send_internal(lo_address t, const char *file, const int line, const char *path, const char *types, ...); /** \internal \brief the real send_timestamped function (don't call directly) */ int lo_send_timestamped_internal(lo_address t, const char *file, const int line, lo_timetag ts, const char *path, const char *types, ...); /** \internal \brief the real lo_send_from() function (don't call directly) */ int lo_send_from_internal(lo_address targ, lo_server from, const char *file, const int line, const lo_timetag ts, const char *path, const char *types, ...); /** \brief Find the time difference between two timetags * * Returns a - b in seconds. */ double lo_timetag_diff(lo_timetag a, lo_timetag b); /** \brief Return a timetag for the current time * * On exit the timetag pointed to by t is filled with the OSC * representation of this instant in time. */ void lo_timetag_now(lo_timetag *t); /** * \brief Return the storage size, in bytes, of the given argument. */ size_t lo_arg_size(lo_type type, void *data); /** * \brief Given a raw OSC message, return the message path. * * \param data A pointer to the raw OSC message data. * \param size The size of data in bytes (total buffer bytes). * * Returns the message path or NULL if an error occurs. * Do not free() the returned pointer. */ char *lo_get_path(void *data, ssize_t size); /** * \brief Convert the specified argument to host byte order where necessary. * * \param type The OSC type of the data item (eg. LO_FLOAT). * \param data A pointer to the data item to be converted. It is changed * in-place. */ void lo_arg_host_endian(lo_type type, void *data); /** * \brief Convert the specified argument to network byte order where necessary. * * \param type The OSC type of the data item (eg. LO_FLOAT). * \param data A pointer to the data item to be converted. It is changed * in-place. */ void lo_arg_network_endian(lo_type type, void *data); /** @} */ /* prettyprinters */ /** * \defgroup pp Prettyprinting functions * * These functions all print an ASCII representation of their argument to * stdout. Useful for debugging. * @{ */ /** \brief Pretty-print a lo_bundle object. */ void lo_bundle_pp(lo_bundle b); /** \brief Pretty-print a lo_message object. */ void lo_message_pp(lo_message m); /** \brief Pretty-print a set of typed arguments. * \param type A type string in the form provided to lo_send(). * \param data An OSC data pointer, like that provided in the * lo_method_handler. */ void lo_arg_pp(lo_type type, void *data); /** \brief Pretty-print a lo_server object. */ void lo_server_pp(lo_server s); /** \brief Pretty-print a lo_method object. */ void lo_method_pp(lo_method m); /** \brief Pretty-print a lo_method object, but prepend a given prefix * to all field names. */ void lo_method_pp_prefix(lo_method m, const char *p); /** \brief Pretty-print a lo_server_thread object. */ void lo_server_thread_pp(lo_server_thread st); /** @} */ #ifdef __cplusplus } #endif #endif nyquist-3.05/liblo/lo/Makefile.in0000644000175000000620000003265111515462141015752 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = lo DIST_COMMON = $(libloinclude_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/lo_endian.h.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = lo_endian.h CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libloincludedir)" HEADERS = $(libloinclude_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ libloincludedir = $(includedir)/lo libloinclude_HEADERS = lo_errors.h lo.h lo_lowlevel.h lo_throw.h lo_types.h \ lo_osc_types.h lo_endian.h lo_macros.h all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lo/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu lo/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): lo_endian.h: $(top_builddir)/config.status $(srcdir)/lo_endian.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-libloincludeHEADERS: $(libloinclude_HEADERS) @$(NORMAL_INSTALL) test -z "$(libloincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libloincludedir)" @list='$(libloinclude_HEADERS)'; test -n "$(libloincludedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libloincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libloincludedir)" || exit $$?; \ done uninstall-libloincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(libloinclude_HEADERS)'; test -n "$(libloincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(libloincludedir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(libloincludedir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libloincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-libloincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libloincludeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool ctags distclean distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libloincludeHEADERS install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-libloincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/lo/lo_errors.h0000644000175000000620000000221611467003724016062 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_ERRORS_H #define LO_ERRORS_H #ifdef __cplusplus extern "C" { #endif #define LO_ENOPATH 9901 #define LO_ENOTYPE 9902 #define LO_UNKNOWNPROTO 9903 #define LO_NOPORT 9904 #define LO_TOOBIG 9905 #define LO_INT_ERR 9906 #define LO_EALLOC 9907 #define LO_EINVALIDPATH 9908 #define LO_EINVALIDTYPE 9909 #define LO_EBADTYPE 9910 #define LO_ESIZE 9911 #define LO_EINVALIDARG 9912 #define LO_ETERM 9913 #define LO_EPAD 9914 #define LO_EINVALIDBUND 9915 #define LO_EINVALIDTIME 9916 #ifdef __cplusplus } #endif #endif nyquist-3.05/liblo/lo/lo_osc_types.h0000644000175000000620000000727011467003724016563 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_OSC_TYPES_H #define LO_OSC_TYPES_H /** * \file lo_osc_types.h A liblo header defining OSC-related types and * constants. */ #ifdef _MSC_VER #define int32_t __int32 #define int64_t __int64 #define uint32_t unsigned __int32 #define uint64_t unsigned __int64 #define uint8_t unsigned __int8 #else #include #endif /** * \addtogroup liblo * @{ */ /** * \brief A structure to store OSC TimeTag values. */ typedef struct { /** The number of seconds since Jan 1st 1900 in the UTC timezone. */ uint32_t sec; /** The fractions of a second offset from above, expressed as 1/2^32nds * of a second */ uint32_t frac; } lo_timetag; /** * \brief An enumeration of the OSC types liblo can send and receive. * * The value of the enumeration is the typechar used to tag messages and to * specify arguments with lo_send(). */ typedef enum { /* basic OSC types */ /** 32 bit signed integer. */ LO_INT32 = 'i', /** 32 bit IEEE-754 float. */ LO_FLOAT = 'f', /** Standard C, NULL terminated string. */ LO_STRING = 's', /** OSC binary blob type. Accessed using the lo_blob_*() functions. */ LO_BLOB = 'b', /* extended OSC types */ /** 64 bit signed integer. */ LO_INT64 = 'h', /** OSC TimeTag type, represented by the lo_timetag structure. */ LO_TIMETAG = 't', /** 64 bit IEEE-754 double. */ LO_DOUBLE = 'd', /** Standard C, NULL terminated, string. Used in systems which * distinguish strings and symbols. */ LO_SYMBOL = 'S', /** Standard C, 8 bit, char variable. */ LO_CHAR = 'c', /** A 4 byte MIDI packet. */ LO_MIDI = 'm', /** Sybol representing the value True. */ LO_TRUE = 'T', /** Sybol representing the value False. */ LO_FALSE = 'F', /** Sybol representing the value Nil. */ LO_NIL = 'N', /** Sybol representing the value Infinitum. */ LO_INFINITUM = 'I' } lo_type; /** * \brief Union used to read values from incoming messages. * * Types can generally be read using argv[n]->t where n is the argument number * and t is the type character, with the exception of strings and symbols which * must be read with &argv[n]->t. */ typedef union { /** 32 bit signed integer. */ int32_t i; /** 32 bit signed integer. */ int32_t i32; /** 64 bit signed integer. */ int64_t h; /** 64 bit signed integer. */ int64_t i64; /** 32 bit IEEE-754 float. */ float f; /** 32 bit IEEE-754 float. */ float f32; /** 64 bit IEEE-754 double. */ double d; /** 64 bit IEEE-754 double. */ double f64; /** Standard C, NULL terminated string. */ char s; /** Standard C, NULL terminated, string. Used in systems which * distinguish strings and symbols. */ char S; /** Standard C, 8 bit, char. */ unsigned char c; /** A 4 byte MIDI packet. */ uint8_t m[4]; /** OSC TimeTag value. */ lo_timetag t; } lo_arg; /** \brief A timetag constant representing "now". */ /* Note: No struct literals in MSVC */ #ifdef _MSC_VER lo_timetag lo_get_tt_immediate(); #define LO_TT_IMMEDIATE lo_get_tt_immediate() #else #define LO_TT_IMMEDIATE ((lo_timetag){0U,1U}) #endif /** @} */ #endif nyquist-3.05/liblo/lo/lo_endian.h0000644000175000000620000000745211512144250016002 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_ENDIAN_H #define LO_ENDIAN_H #include #ifdef _MSC_VER #define inline __inline #define uint64_t unsigned __int64 #define uint32_t unsigned __int32 #else #include #endif #ifdef WIN32 #include #include #else #include #endif #ifdef __cplusplus extern "C" { #endif #define lo_swap16(x) htons(x) #define lo_swap32(x) htonl(x) /* These macros come from the Linux kernel */ #ifndef lo_swap16 #define lo_swap16(x) \ ({ \ uint16_t __x = (x); \ ((uint16_t)( \ (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ }) #warning USING UNOPTIMISED ENDIAN STUFF #endif #ifndef lo_swap32 #define lo_swap32(x) \ ({ \ uint32_t __x = (x); \ ((uint32_t)( \ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ }) #endif #if 0 #ifndef lo_swap64 #define lo_swap64(x) \ ({ \ uint64_t __x = (x); \ ((uint64_t)( \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ }) #endif #else typedef union { uint64_t all; struct { uint32_t a; uint32_t b; } part; } lo_split64; static inline uint64_t lo_swap64(uint64_t x) { lo_split64 in, out; in.all = x; out.part.a = lo_swap32(in.part.b); out.part.b = lo_swap32(in.part.a); return out.all; } #endif /* Host to OSC and OSC to Host conversion macros */ #if defined(__linux__) || defined(__GLIBC__) #include // set __BYTE_ORDER #endif #ifndef __BIG_ENDIAN #define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 #endif #ifdef __APPLE__ #include #if defined(__LITTLE_ENDIAN__) #define __BYTE_ORDER __LITTLE_ENDIAN #endif #if defined(__BIG_ENDIAN__) #define __BYTE_ORDER __BIG_ENDIAN #endif #endif #ifdef WIN32 #define __BYTE_ORDER __LITTLE_ENDIAN #endif #ifndef __BYTE_ORDER #error __BYTE_ORDER not defined #endif #if __BYTE_ORDER == __BIG_ENDIAN #define lo_htoo16(x) (x) #define lo_htoo32(x) (x) #define lo_htoo64(x) (x) #define lo_otoh16(x) (x) #define lo_otoh32(x) (x) #define lo_otoh64(x) (x) #else #define lo_htoo16 lo_swap16 #define lo_htoo32 lo_swap32 #define lo_htoo64 lo_swap64 #define lo_otoh16 lo_swap16 #define lo_otoh32 lo_swap32 #define lo_otoh64 lo_swap64 #endif #ifdef __cplusplus } #endif #ifdef _MSC_VER #undef inline #undef uint64_t #undef uint32_t #endif #endif /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/lo/lo_throw.h0000644000175000000620000000141311467003724015707 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_THROW_H #define LO_THROW_H #ifdef __cplusplus extern "C" { #endif void lo_throw(lo_server s, int errnum, const char *message, const char *path); #ifdef __cplusplus } #endif #endif nyquist-3.05/liblo/lo/lo.h0000644000175000000620000002777111467003724014503 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris * * This program 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.1 * 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 Lesser General Public License for more details. * * $Id$ */ #ifndef LO_H #define LO_H #ifdef __cplusplus extern "C" { #endif /** * \file lo.h The liblo main headerfile and high-level API functions. */ #include "lo/lo_endian.h" #include "lo/lo_types.h" #include "lo/lo_osc_types.h" #include "lo/lo_errors.h" #include "lo/lo_lowlevel.h" /** * \defgroup liblo High-level OSC API * * Defines the high-level API functions necessary to implement OSC support. * Should be adequate for most applications, but if you require lower level * control you can use the functions defined in lo_lowlevel.h * @{ */ /** * \brief Declare an OSC destination, given IP address and port number. * Same as lo_address_new_with_proto(), but using UDP. * * \param host An IP address or number, or NULL for the local machine. * \param port a decimal port number or service name. * * The lo_address object may be used as the target of OSC messages. * * Note: if you wish to receive replies from the target of this address, you * must first create a lo_server_thread or lo_server object which will receive * the replies. The last lo_server(_thread) object creted will be the receiver. */ lo_address lo_address_new(const char *host, const char *port); /** * \brief Declare an OSC destination, given IP address and port number, * specifying protocol. * * \param proto The protocol to use, must be one of LO_UDP, LO_TCP or LO_UNIX. * \param host An IP address or number, or NULL for the local machine. * \param port a decimal port number or service name. * * The lo_address object may be used as the target of OSC messages. * * Note: if you wish to receive replies from the target of this address, you * must first create a lo_server_thread or lo_server object which will receive * the replies. The last lo_server(_thread) object creted will be the receiver. */ lo_address lo_address_new_with_proto(int proto, const char *host, const char *port); /** * \brief Create a lo_address object from an OSC URL. * * example: \c "osc.udp://localhost:4444/my/path/" */ lo_address lo_address_new_from_url(const char *url); /** * \brief Free the memory used by the lo_address object */ void lo_address_free(lo_address t); /** * \brief Set the Time-to-Live value for a given target address. * * This is required for sending multicast UDP messages. A value of 1 * (the usual case) keeps the message within the subnet, while 255 * means a global, unrestricted scope. * * \param t An OSC address. * \param ttl An integer specifying the scope of a multicast UDP message. */ void lo_address_set_ttl(lo_address t, int ttl); /** * \brief Get the Time-to-Live value for a given target address. * * \param t An OSC address. * \return An integer specifying the scope of a multicast UDP message. */ int lo_address_get_ttl(lo_address t); /** * \brief Send a OSC formatted message to the address specified. * * \param targ The target OSC address * \param path The OSC path the message will be delivered to * \param type The types of the data items in the message, types are defined in * lo_osc_types.h * \param ... The data values to be transmitted. The types of the arguments * passed here must agree with the types specified in the type parameter. * * example: * \code * lo_send(t, "/foo/bar", "ff", 0.1f, 23.0f); * \endcode * * \return -1 on failure. */ int lo_send(lo_address targ, const char *path, const char *type, ...); /** * \brief Send a OSC formatted message to the address specified, * from the same socket as the specificied server. * * \param targ The target OSC address * \param from The server to send message from (can be NULL to use new socket) * \param ts The OSC timetag timestamp at which the message will be processed * (can be LO_TT_IMMEDIATE if you don't want to attach a timetag) * \param path The OSC path the message will be delivered to * \param type The types of the data items in the message, types are defined in * lo_osc_types.h * \param ... The data values to be transmitted. The types of the arguments * passed here must agree with the types specified in the type parameter. * * example: * \code * serv = lo_server_new(NULL, err); * lo_server_add_method(serv, "/reply", "ss", reply_handler, NULL); * lo_send_from(t, serv, LO_TT_IMMEDIATE, "/foo/bar", "ff", 0.1f, 23.0f); * \endcode * * \return on success, the number of bytes sent, or -1 on failure. */ int lo_send_from(lo_address targ, lo_server from, lo_timetag ts, const char *path, const char *type, ...); /** * \brief Send a OSC formatted message to the address specified, scheduled to * be dispatch at some time in the future. * * \param targ The target OSC address * \param ts The OSC timetag timestamp at which the message will be processed * \param path The OSC path the message will be delivered to * \param type The types of the data items in the message, types are defined in * lo_osc_types.h * \param ... The data values to be transmitted. The types of the arguments * passed here must agree with the types specified in the type parameter. * * example: * \code * lo_timetag now;
* lo_timetag_now(&now);
* lo_send_timestamped(t, now, "/foo/bar", "ff", 0.1f, 23.0f); * \endcode * * \return on success, the number of bytes sent, or -1 on failure. */ int lo_send_timestamped(lo_address targ, lo_timetag ts, const char *path, const char *type, ...); /** * \brief Return the error number from the last failed lo_send() or * lo_address_new() call */ int lo_address_errno(lo_address a); /** * \brief Return the error string from the last failed lo_send() or * lo_address_new() call */ const char *lo_address_errstr(lo_address a); /** * \brief Create a new server thread to handle incoming OSC * messages. * * Server threads take care of the message reception and dispatch by * transparently creating a system thread to handle incoming messages. * Use this if you do not want to handle the threading yourself. * * \param port If NULL is passed then an unused port will be chosen by the * system, its number may be retrieved with lo_server_thread_get_port() * so it can be passed to clients. Otherwise a decimal port number, service * name or UNIX domain socket path may be passed. * \param err_h A function that will be called in the event of an error being * raised. The function prototype is defined in lo_types.h */ lo_server_thread lo_server_thread_new(const char *port, lo_err_handler err_h); /** * \brief Create a new server thread to handle incoming OSC * messages, and join a UDP multicast group. * * Server threads take care of the message reception and dispatch by * transparently creating a system thread to handle incoming messages. * Use this if you do not want to handle the threading yourself. * * \param group The multicast group to join. See documentation on IP * multicast for the acceptable address range; e.g., http://tldp.org/HOWTO/Multicast-HOWTO-2.html * \param port If NULL is passed then an unused port will be chosen by the * system, its number may be retrieved with lo_server_thread_get_port() * so it can be passed to clients. Otherwise a decimal port number, service * name or UNIX domain socket path may be passed. * \param err_h A function that will be called in the event of an error being * raised. The function prototype is defined in lo_types.h */ lo_server_thread lo_server_thread_new_multicast(const char *group, const char *port, lo_err_handler err_h); /** * \brief Create a new server thread to handle incoming OSC * messages, specifying protocol. * * Server threads take care of the message reception and dispatch by * transparently creating a system thread to handle incoming messages. * Use this if you do not want to handle the threading yourself. * * \param port If NULL is passed then an unused port will be chosen by the * system, its number may be retrieved with lo_server_thread_get_port() * so it can be passed to clients. Otherwise a decimal port number, service * name or UNIX domain socket path may be passed. * \param proto The protocol to use, should be one of LO_UDP, LO_TCP or LO_UNIX. * \param err_h A function that will be called in the event of an error being * raised. The function prototype is defined in lo_types.h */ lo_server_thread lo_server_thread_new_with_proto(const char *port, int proto, lo_err_handler err_h); /** * \brief Free memory taken by a server thread * * Frees the memory, and, if currently running will stop the associated thread. */ void lo_server_thread_free(lo_server_thread st); /** * \brief Add an OSC method to the specifed server thread. * * \param st The server thread the method is to be added to. * \param path The OSC path to register the method to. If NULL is passed the * method will match all paths. * \param typespec The typespec the method accepts. Incoming messages with * similar typespecs (e.g. ones with numerical types in the same position) will * be coerced to the typespec given here. * \param h The method handler callback function that will be called it a * matching message is received * \param user_data A value that will be passed to the callback function, h, * when its invoked matching from this method. */ lo_method lo_server_thread_add_method(lo_server_thread st, const char *path, const char *typespec, lo_method_handler h, void *user_data); /** * \brief Delete an OSC method from the specifed server thread. * * \param st The server thread the method is to be removed from. * \param path The OSC path of the method to delete. If NULL is passed the * method will match the generic handler. * \param typespec The typespec the method accepts. */ void lo_server_thread_del_method(lo_server_thread st, const char *path, const char *typespec); /** * \brief Start the server thread * * \param st the server thread to start. * \return Less than 0 on failure, 0 on success. */ int lo_server_thread_start(lo_server_thread st); /** * \brief Stop the server thread * * \param st the server thread to start. * \return Less than 0 on failure, 0 on success. */ int lo_server_thread_stop(lo_server_thread st); /** * \brief Return the port number that the server thread has bound to. */ int lo_server_thread_get_port(lo_server_thread st); /** * \brief Return a URL describing the address of the server thread. * * Return value must be free()'d to reclaim memory. */ char *lo_server_thread_get_url(lo_server_thread st); /** * \brief Return the lo_server for a lo_server_thread * * This function is useful for passing a thread's lo_server * to lo_send_from(). */ lo_server lo_server_thread_get_server(lo_server_thread st); /** \brief Return true if there are scheduled events (eg. from bundles) waiting * to be dispatched by the thread */ int lo_server_thread_events_pending(lo_server_thread st); /** * \brief Create a new OSC blob type. * * \param size The amount of space to allocate in the blob structure. * \param data The data that will be used to initialise the blob, should be * size bytes long. */ lo_blob lo_blob_new(int32_t size, const void *data); /** * \brief Free the memory taken by a blob */ void lo_blob_free(lo_blob b); /** * \brief Return the amount of valid data in a lo_blob object. * * If you want to know the storage size, use lo_arg_size(). */ uint32_t lo_blob_datasize(lo_blob b); /** * \brief Return a pointer to the start of the blob data to allow contents to * be changed. */ void *lo_blob_dataptr(lo_blob b); /** @} */ #include "lo/lo_macros.h" #ifdef __cplusplus } #endif #endif nyquist-3.05/liblo/lo/Makefile.am0000644000175000000620000000023211466705460015740 0ustar stevestafflibloincludedir = $(includedir)/lo libloinclude_HEADERS = lo_errors.h lo.h lo_lowlevel.h lo_throw.h lo_types.h \ lo_osc_types.h lo_endian.h lo_macros.h nyquist-3.05/liblo/pthreads.2/0002755000175000000620000000000011537433130015240 5ustar stevestaffnyquist-3.05/liblo/pthreads.2/mt.dep0000644000175000000620000000010211512143043016333 0ustar stevestaffManifest resource last updated at 23:57:51.50 on Sun 10/25/2009 nyquist-3.05/liblo/pthreads.2/pthread_mutex_timedlock.c0000644000175000000620000001204311512143043022300 0ustar stevestaff/* * pthread_mutex_timedlock.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" static INLINE int ptw32_timed_eventwait (HANDLE event, const struct timespec *abstime) /* * ------------------------------------------------------ * DESCRIPTION * This function waits on an event until signaled or until * abstime passes. * If abstime has passed when this routine is called then * it returns a result to indicate this. * * If 'abstime' is a NULL pointer then this function will * block until it can successfully decrease the value or * until interrupted by a signal. * * This routine is not a cancelation point. * * RESULTS * 0 successfully signaled, * ETIMEDOUT abstime passed * EINVAL 'event' is not a valid event, * * ------------------------------------------------------ */ { DWORD milliseconds; DWORD status; if (event == NULL) { return EINVAL; } else { if (abstime == NULL) { milliseconds = INFINITE; } else { /* * Calculate timeout as milliseconds from current system time. */ milliseconds = ptw32_relmillisecs (abstime); } status = WaitForSingleObject (event, milliseconds); if (status == WAIT_OBJECT_0) { return 0; } else if (status == WAIT_TIMEOUT) { return ETIMEDOUT; } else { return EINVAL; } } return 0; } /* ptw32_timed_semwait */ int pthread_mutex_timedlock (pthread_mutex_t * mutex, const struct timespec *abstime) { int result; pthread_mutex_t mx; /* * Let the system deal with invalid pointers. */ /* * We do a quick check to see if we need to do more work * to initialise a static mutex. We check * again inside the guarded section of ptw32_mutex_check_need_init() * to avoid race conditions. */ if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { if ((result = ptw32_mutex_check_need_init (mutex)) != 0) { return (result); } } mx = *mutex; if (mx->kind == PTHREAD_MUTEX_NORMAL) { if ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) 1) != 0) { while ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) -1) != 0) { if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) { return result; } } } } else { pthread_t self = pthread_self(); if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, (PTW32_INTERLOCKED_LONG) 1, (PTW32_INTERLOCKED_LONG) 0) == 0) { mx->recursive_count = 1; mx->ownerThread = self; } else { if (pthread_equal (mx->ownerThread, self)) { if (mx->kind == PTHREAD_MUTEX_RECURSIVE) { mx->recursive_count++; } else { return EDEADLK; } } else { while ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) -1) != 0) { if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) { return result; } } mx->recursive_count = 1; mx->ownerThread = self; } } } return 0; } nyquist-3.05/liblo/pthreads.2/pthread_spin_init.c0000644000175000000620000000566011512143043021106 0ustar stevestaff/* * pthread_spin_init.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_spin_init (pthread_spinlock_t * lock, int pshared) { pthread_spinlock_t s; int cpus = 0; int result = 0; if (lock == NULL) { return EINVAL; } if (0 != ptw32_getprocessors (&cpus)) { cpus = 1; } if (cpus > 1) { if (pshared == PTHREAD_PROCESS_SHARED) { /* * Creating spinlock that can be shared between * processes. */ #if _POSIX_THREAD_PROCESS_SHARED >= 0 /* * Not implemented yet. */ #error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet. #else return ENOSYS; #endif /* _POSIX_THREAD_PROCESS_SHARED */ } } s = (pthread_spinlock_t) calloc (1, sizeof (*s)); if (s == NULL) { return ENOMEM; } if (cpus > 1) { s->u.cpus = cpus; s->interlock = PTW32_SPIN_UNLOCKED; } else { pthread_mutexattr_t ma; result = pthread_mutexattr_init (&ma); if (0 == result) { ma->pshared = pshared; result = pthread_mutex_init (&(s->u.mutex), &ma); if (0 == result) { s->interlock = PTW32_SPIN_USE_MUTEX; } } (void) pthread_mutexattr_destroy (&ma); } if (0 == result) { *lock = s; } else { (void) free (s); *lock = NULL; } return (result); } nyquist-3.05/liblo/pthreads.2/pthread_spin_trylock.c0000644000175000000620000000461711512143043021633 0ustar stevestaff/* * pthread_spin_trylock.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_spin_trylock (pthread_spinlock_t * lock) { register pthread_spinlock_t s; if (NULL == lock || NULL == *lock) { return (EINVAL); } if (*lock == PTHREAD_SPINLOCK_INITIALIZER) { int result; if ((result = ptw32_spinlock_check_need_init (lock)) != 0) { return (result); } } s = *lock; switch ((long) PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & (s->interlock), (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED, (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED)) { case PTW32_SPIN_UNLOCKED: return 0; case PTW32_SPIN_LOCKED: return EBUSY; case PTW32_SPIN_USE_MUTEX: return pthread_mutex_trylock (&(s->u.mutex)); } return EINVAL; } nyquist-3.05/liblo/pthreads.2/attr.c0000644000175000000620000000412211512143043016345 0ustar stevestaff/* * attr.c * * Description: * This translation unit agregates operations on thread attribute objects. * It is used for inline optimisation. * * The included modules are used separately when static executable sizes * must be minimised. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_attr_init.c" #include "pthread_attr_destroy.c" #include "pthread_attr_getdetachstate.c" #include "pthread_attr_setdetachstate.c" #include "pthread_attr_getstackaddr.c" #include "pthread_attr_setstackaddr.c" #include "pthread_attr_getstacksize.c" #include "pthread_attr_setstacksize.c" #include "pthread_attr_getscope.c" #include "pthread_attr_setscope.c" nyquist-3.05/liblo/pthreads.2/pthread_setconcurrency.c0000644000175000000620000000340111512143043022147 0ustar stevestaff/* * pthread_setconcurrency.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_setconcurrency (int level) { if (level < 0) { return EINVAL; } else { ptw32_concurrency = level; return 0; } } nyquist-3.05/liblo/pthreads.2/pthread_attr_getschedparam.c0000644000175000000620000000354511512143043022753 0ustar stevestaff/* * pthread_attr_getschedparam.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_attr_getschedparam (const pthread_attr_t * attr, struct sched_param *param) { if (ptw32_is_attr (attr) != 0 || param == NULL) { return EINVAL; } memcpy (param, &(*attr)->param, sizeof (*param)); return 0; } nyquist-3.05/liblo/pthreads.2/ptw32_calloc.c0000644000175000000620000000343411512143043017674 0ustar stevestaff/* * ptw32_calloc.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifdef NEED_CALLOC void * ptw32_calloc (size_t n, size_t s) { unsigned int m = n * s; void *p; p = malloc (m); if (p == NULL) return NULL; memset (p, 0, m); return p; } #endif nyquist-3.05/liblo/pthreads.2/pthread_barrierattr_getpshared.c0000644000175000000620000000651111512143043023635 0ustar stevestaff/* * pthread_barrier_attr_getpshared.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr, int *pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Determine whether barriers created with 'attr' can be * shared between processes. * * PARAMETERS * attr * pointer to an instance of pthread_barrierattr_t * * pshared * will be set to one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * * DESCRIPTION * Mutexes creatd with 'attr' can be shared between * processes if pthread_barrier_t variable is allocated * in memory shared by these processes. * NOTES: * 1) pshared barriers MUST be allocated in shared * memory. * 2) The following macro is defined if shared barriers * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully retrieved attribute, * EINVAL 'attr' is invalid, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && (pshared != NULL)) { *pshared = (*attr)->pshared; result = 0; } else { result = EINVAL; } return (result); } /* pthread_barrierattr_getpshared */ nyquist-3.05/liblo/pthreads.2/FAQ0000644000175000000620000003577711512143043015605 0ustar stevestaff ========================================= PTHREADS-WIN32 Frequently Asked Questions ========================================= INDEX ----- Q 1 What is it? Q 2 Which of the several dll versions do I use? or, What are all these pthread*.dll and pthread*.lib files? Q 3 What is the library naming convention? Q 4 Cleanup code default style or: it used to work when I built the library myself, but now it doesn't - why? Q 5 Why is the default library version now less exception-friendly? Q 6 Should I use Cygwin or Mingw32 as a development environment? Q 7 Now that pthreads-win32 builds under Mingw32, why do I get memory access violations (segfaults)? Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0) Q 9 Cancelation doesn't work for me, why? Q 10 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32? ============================================================================= Q 1 What is it? --- Pthreads-win32 is an Open Source Software implementation of the Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's Win32 environment. Some functions from POSIX 1003.1b are also supported including semaphores. Other related functions include the set of read-write lock functions. The library also supports some of the functionality of the Open Group's Single Unix specification, version 2, namely mutex types. See the file "ANNOUNCE" for more information including standards conformance details and list of supported routines. ------------------------------------------------------------------------------ Q 2 Which of the several dll versions do I use? --- or, What are all these pthread*.dll and pthread*.lib files? Simply, you only use one of them, but you need to choose carefully. The most important choice you need to make is whether to use a version that uses exceptions internally, or not (there are versions of the library that use exceptions as part of the thread cancelation and cleanup implementation, and one that uses setjmp/longjmp instead). There is some contension amongst POSIX threads experts as to how POSIX threads cancelation and exit should work with languages that include exceptions and handlers, e.g. C++ and even C (Microsoft's Structured Exceptions). The issue is: should cancelation of a thread in, say, a C++ application cause object destructors and C++ exception handlers to be invoked as the stack unwinds during thread exit, or not? There seems to be more opinion in favour of using the standard C version of the library (no EH) with C++ applications since this appears to be the assumption commercial pthreads implementations make. Therefore, if you use an EH version of pthreads-win32 then you may be under the illusion that your application will be portable, when in fact it is likely to behave very differently linked with other pthreads libraries. Now you may be asking: why have you kept the EH versions of the library? There are a couple of reasons: - there is division amongst the experts and so the code may be needed in the future. (Yes, it's in the repository and we can get it out anytime in the future, but ...) - pthreads-win32 is one of the few implementations, and possibly the only freely available one, that has EH versions. It may be useful to people who want to play with or study application behaviour under these conditions. ------------------------------------------------------------------------------ Q 3 What is the library naming convention? --- Because the library is being built using various exception handling schemes and compilers - and because the library may not work reliably if these are mixed in an application, each different version of the library has it's own name. Note 1: the incompatibility is really between EH implementations of the different compilers. It should be possible to use the standard C version from either compiler with C++ applications built with a different compiler. If you use an EH version of the library, then you must use the same compiler for the application. This is another complication and dependency that can be avoided by using only the standard C library version. Note 2: if you use a standard C pthread*.dll with a C++ application, then any functions that you define that are intended to be called via pthread_cleanup_push() must be __cdecl. Note 3: the intention is to also name either the VC or GC version (it should be arbitrary) as pthread.dll, including pthread.lib and libpthread.a as appropriate. In general: pthread[VG]{SE,CE,C}.dll pthread[VG]{SE,CE,C}.lib where: [VG] indicates the compiler V - MS VC G - GNU C {SE,CE,C} indicates the exception handling scheme SE - Structured EH CE - C++ EH C - no exceptions - uses setjmp/longjmp For example: pthreadVSE.dll (MSVC/SEH) pthreadGCE.dll (GNUC/C++ EH) pthreadGC.dll (GNUC/not dependent on exceptions) The GNU library archive file names have changed to: libpthreadGCE.a libpthreadGC.a ------------------------------------------------------------------------------ Q 4 Cleanup code default style or: it used to work when I built --- the library myself, but now it doesn't - why? Up to and including snapshot 2001-07-12, if not defined, the cleanup style was determined automatically from the compiler used, and one of the following was defined accordingly: __CLEANUP_SEH MSVC only __CLEANUP_CXX C++, including MSVC++, GNU G++ __CLEANUP_C C, including GNU GCC, not MSVC These defines determine the style of cleanup (see pthread.h) and, most importantly, the way that cancelation and thread exit (via pthread_exit) is performed (see the routine ptw32_throw() in private.c). In short, the exceptions versions of the library throw an exception when a thread is canceled or exits (via pthread_exit()), which is caught by a handler in the thread startup routine, so that the the correct stack unwinding occurs regardless of where the thread is when it's canceled or exits via pthread_exit(). After snapshot 2001-07-12, unless your build explicitly defines (e.g. via a compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then the build now ALWAYS defaults to __CLEANUP_C style cleanup. This style uses setjmp/longjmp in the cancelation and pthread_exit implementations, and therefore won't do stack unwinding even when linked to applications that have it (e.g. C++ apps). This is for consistency with most/all commercial Unix POSIX threads implementations. Although it was not clearly documented before, it is still necessary to build your application using the same __CLEANUP_* define as was used for the version of the library that you link with, so that the correct parts of pthread.h are included. That is, the possible defines require the following library versions: __CLEANUP_SEH pthreadVSE.dll __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll __CLEANUP_C pthreadVC.dll or pthreadGC.dll THE POINT OF ALL THIS IS: if you have not been defining one of these explicitly, then the defaults have been set according to the compiler and language you are using, as described at the top of this section. THIS NOW CHANGES, as has been explained above. For example: If you were building your application with MSVC++ i.e. using C++ exceptions (rather than SEH) and not explicitly defining one of __CLEANUP_*, then __CLEANUP_C++ was defined for you in pthread.h. You should have been linking with pthreadVCE.dll, which does stack unwinding. If you now build your application as you had before, pthread.h will now set __CLEANUP_C as the default style, and you will need to link with pthreadVC.dll. Stack unwinding will now NOT occur when a thread is canceled, nor when the thread calls pthread_exit(). Your application will now most likely behave differently to previous versions, and in non-obvious ways. Most likely is that local objects may not be destroyed or cleaned up after a thread is canceled. If you want the same behaviour as before, then you must now define __CLEANUP_C++ explicitly using a compiler option and link with pthreadVCE.dll as you did before. ------------------------------------------------------------------------------ Q 5 Why is the default library version now less exception-friendly? --- Because most commercial Unix POSIX threads implementations don't allow you to choose to have stack unwinding. (Compaq's TRU64 Unix is possibly an exception.) Therefore, providing it in pthread-win32 as a default could be dangerous and non-portable. We still provide the choice but you must now consciously make it. WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER? There are a few reasons: - because there are well respected POSIX threads people who believe that POSIX threads implementations should be exceptions-aware and do the expected thing in that context. (There are equally respected people who believe it should not be easily accessible, if it's there at all.) - because pthreads-win32 is one of the few implementations that has the choice, perhaps the only freely available one, and so offers a laboratory to people who may want to explore the effects; - although the code will always be around somewhere for anyone who wants it, once it's removed from the current version it will not be nearly as visible to people who may have a use for it. ------------------------------------------------------------------------------ Q 6 Should I use Cygwin or Mingw32 as a development environment? --- Important: see Q7 also. Use Mingw32 with the MSVCRT library to build applications that use the pthreads DLL. Cygwin's own internal support for POSIX threads is growing. Consult that project's documentation for more information. ------------------------------------------------------------------------------ Q 7 Now that pthreads-win32 builds under Mingw32, why do I get --- memory access violations (segfaults)? The latest Mingw32 package has thread-safe exception handling (see Q10). Also, see Q6 above. ------------------------------------------------------------------------------ Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0) --- > > I'm a "rookie" when it comes to your pthread implementation. I'm currently > desperately trying to install the prebuilt .dll file into my MSVC compiler. > Could you please provide me with explicit instructions on how to do this (or > direct me to a resource(s) where I can acquire such information)? > > Thank you, > You should have a .dll, .lib, .def, and three .h files. It is recommended that you use pthreadVC.dll, rather than pthreadVCE.dll or pthreadVSE.dll (see Q2 above). The .dll can go in any directory listed in your PATH environment variable, so putting it into C:\WINDOWS should work. The .lib file can go in any directory listed in your LIB environment variable. The .h files can go in any directory listed in your INCLUDE environment variable. Or you might prefer to put the .lib and .h files into a new directory and add its path to LIB and INCLUDE. You can probably do this easiest by editing the file:- C:\Program Files\DevStudio\vc\bin\vcvars32.bat The .def file isn't used by anything in the pre-compiled version but is included for information. Cheers. Ross ------------------------------------------------------------------------------ Q 9 Cancelation doesn't work for me, why? --- > I'm investigating a problem regarding thread cancelation. The thread I want > to cancel has PTHREAD_CANCEL_ASYNCHRONOUS, however, this piece of code > blocks on the join(): > > if ((retv = Pthread_cancel( recvThread )) == 0) > { > retv = Pthread_join( recvThread, 0 ); > } > > Pthread_* are just macro's; they call pthread_*. > > The thread recvThread seems to block on a select() call. It doesn't get > cancelled. > > Two questions: > > 1) is this normal behaviour? > > 2) if not, how does the cancel mechanism work? I'm not very familliar to > win32 programming, so I don't really understand how the *Event() family of > calls work. The answer to your first question is, normal POSIX behaviour would be to asynchronously cancel the thread. However, even that doesn't guarantee cancelation as the standard only says it should be cancelled as soon as possible. Snapshot 99-11-02 or earlier only partially supports asynchronous cancellation. Snapshots since then simulate async cancelation by poking the address of a cancelation routine into the PC of the threads context. This requires the thread to be resumed in some way for the cancelation to actually proceed. This is not true async cancelation, but it is as close as we've been able to get to it. If the thread you're trying to cancel is blocked (for instance, it could be waiting for data from the network), it will only get cancelled when it unblocks (when the data arrives). For true pre-emptive cancelation in these cases, pthreads-win32 from snapshot 2004-05-16 can automatically recognise and use the QueueUserAPCEx package by Panagiotis E. Hadjidoukas. This package is available from the pthreads-win32 ftp site and is included in the pthreads-win32 self-unpacking zip from 2004-05-16 onwards. Using deferred cancelation would normally be the way to go, however, even though the POSIX threads standard lists a number of C library functions that are defined as deferred cancelation points, there is no hookup between those which are provided by Windows and the pthreads-win32 library. Incidently, it's worth noting for code portability that the older POSIX threads standards cancelation point lists didn't include "select" because (as I read in Butenhof) it wasn't part of POSIX. However, it does appear in the SUSV3. Effectively, the only mandatory cancelation points that pthreads-win32 recognises are those the library implements itself, ie. pthread_testcancel pthread_cond_wait pthread_cond_timedwait pthread_join sem_wait sem_timedwait pthread_delay_np The following routines from the non-mandatory list in SUSV3 are cancelation points in pthreads-win32: pthread_rwlock_wrlock pthread_rwlock_timedwrlock The following routines from the non-mandatory list in SUSV3 are not cancelation points in pthreads-win32: pthread_rwlock_rdlock pthread_rwlock_timedrdlock Pthreads-win32 also provides two functions that allow you to create cancelation points within your application, but only for cases where a thread is going to block on a Win32 handle. These are: pthreadCancelableWait(HANDLE waitHandle) /* Infinite wait */ pthreadCancelableTimedWait(HANDLE waitHandle, DWORD timeout) ------------------------------------------------------------------------------ Q 10 How do I create thread-safe applications using ---- pthreadGCE.dll, libpthreadw32.a and Mingw32? This should not be a problem with recent versions of MinGW32. For early versions, see Thomas Pfaff's email at: http://sources.redhat.com/ml/pthreads-win32/2002/msg00000.html ------------------------------------------------------------------------------ nyquist-3.05/liblo/pthreads.2/version.rc0000644000175000000620000003702211512143043017247 0ustar stevestaff/* This is an implementation of the threads API of POSIX 1003.1-2001. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" /* * Note: the correct __CLEANUP_* macro must be defined corresponding to * the definition used for the object file builds. This is done in the * relevent makefiles for the command line builds, but users should ensure * that their resource compiler knows what it is too. * If using the default (no __CLEANUP_* defined), pthread.h will define it * as __CLEANUP_C. */ #ifdef PTW32_RC_MSC # if defined(__CLEANUP_C) # define PTW32_VERSIONINFO_NAME "pthreadVC\0" # define PTW32_VERSIONINFO_COMMENT "MS C build -- longjmp thread exiting\0" # elif defined(__CLEANUP_CXX) # define PTW32_VERSIONINFO_NAME "pthreadVCE\0" # define PTW32_VERSIONINFO_COMMENT "MS C++ build -- C++ exception thread exiting\0" # elif defined(__CLEANUP_SEH) # define PTW32_VERSIONINFO_NAME "pthreadVSE\0" # define PTW32_VERSIONINFO_COMMENT "MS C build -- structured exception thread exiting\0" # else # error Resource compiler doesn't know which cleanup style you're using - see version.rc # endif #elif defined(__GNUC__) # if defined(__CLEANUP_C) # define PTW32_VERSIONINFO_NAME "pthreadGC\0" # define PTW32_VERSIONINFO_COMMENT "GNU C build -- longjmp thread exiting\0" # elif defined(__CLEANUP_CXX) # define PTW32_VERSIONINFO_NAME "pthreadGCE\0" # define PTW32_VERSIONINFO_COMMENT "GNU C++ build -- C++ exception thread exiting\0" # else # error Resource compiler doesn't know which cleanup style you're using - see version.rc # endif #elif defined(__BORLANDC__) # if defined(__CLEANUP_C) # define PTW32_VERSIONINFO_NAME "pthreadBC\0" # define PTW32_VERSIONINFO_COMMENT "BORLAND C build -- longjmp thread exiting\0" # elif defined(__CLEANUP_CXX) # define PTW32_VERSIONINFO_NAME "pthreadBCE\0" # define PTW32_VERSIONINFO_COMMENT "BORLAND C++ build -- C++ exception thread exiting\0" # else # error Resource compiler doesn't know which cleanup style you're using - see version.rc # endif #elif defined(__WATCOMC__) # if defined(__CLEANUP_C) # define PTW32_VERSIONINFO_NAME "pthreadWC\0" # define PTW32_VERSIONINFO_COMMENT "WATCOM C build -- longjmp thread exiting\0" # elif defined(__CLEANUP_CXX) # define PTW32_VERSIONINFO_NAME "pthreadWCE\0" # define PTW32_VERSIONINFO_COMMENT "WATCOM C++ build -- C++ exception thread exiting\0" # else # error Resource compiler doesn't know which cleanup style you're using - see version.rc # endif #else # error Resource compiler doesn't know which compiler you're using - see version.rc #endif VS_VERSION_INFO VERSIONINFO FILEVERSION PTW32_VERSION PRODUCTVERSION PTW32_VERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "POSIX Threads for Windows32 Library\0" VALUE "ProductVersion", PTW32_VERSION_STRING VALUE "FileVersion", PTW32_VERSION_STRING VALUE "InternalName", PTW32_VERSIONINFO_NAME VALUE "OriginalFilename", PTW32_VERSIONINFO_NAME VALUE "CompanyName", "Open Source Software community project\0" VALUE "LegalCopyright", "Copyright (C) Project contributors 1998-2004\0" VALUE "Licence", "LGPL\0" VALUE "Info", "http://sources.redhat.com/pthreads-win32/\0" VALUE "Comment", PTW32_VERSIONINFO_COMMENT END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END /* VERSIONINFO Resource The VERSIONINFO resource-definition statement creates a version-information resource. The resource contains such information about the file as its version number, its intended operating system, and its original filename. The resource is intended to be used with the Version Information functions. versionID VERSIONINFO fixed-info { block-statement...} versionID Version-information resource identifier. This value must be 1. fixed-info Version information, such as the file version and the intended operating system. This parameter consists of the following statements. Statement Description -------------------------------------------------------------------------- FILEVERSION version Binary version number for the file. The version consists of two 32-bit integers, defined by four 16-bit integers. For example, "FILEVERSION 3,10,0,61" is translated into two doublewords: 0x0003000a and 0x0000003d, in that order. Therefore, if version is defined by the DWORD values dw1 and dw2, they need to appear in the FILEVERSION statement as follows: HIWORD(dw1), LOWORD(dw1), HIWORD(dw2), LOWORD(dw2). PRODUCTVERSION version Binary version number for the product with which the file is distributed. The version parameter is two 32-bit integers, defined by four 16-bit integers. For more information about version, see the FILEVERSION description. FILEFLAGSMASK fileflagsmask Bits in the FILEFLAGS statement are valid. If a bit is set, the corresponding bit in FILEFLAGS is valid. FILEFLAGSfileflags Attributes of the file. The fileflags parameter must be the combination of all the file flags that are valid at compile time. For 16-bit Windows, this value is 0x3f. FILEOSfileos Operating system for which this file was designed. The fileos parameter can be one of the operating system values given in the Remarks section. FILETYPEfiletype General type of file. The filetype parameter can be one of the file type values listed in the Remarks section. FILESUBTYPE subtype Function of the file. The subtype parameter is zero unless the type parameter in the FILETYPE statement is VFT_DRV, VFT_FONT, or VFT_VXD. For a list of file subtype values, see the Remarks section. block-statement Specifies one or more version-information blocks. A block can contain string information or variable information. For more information, see StringFileInfo Block or VarFileInfo Block. Remarks To use the constants specified with the VERSIONINFO statement, you must include the Winver.h or Windows.h header file in the resource-definition file. The following list describes the parameters used in the VERSIONINFO statement: fileflags A combination of the following values. Value Description VS_FF_DEBUG File contains debugging information or is compiled with debugging features enabled. VS_FF_PATCHED File has been modified and is not identical to the original shipping file of the same version number. VS_FF_PRERELEASE File is a development version, not a commercially released product. VS_FF_PRIVATEBUILD File was not built using standard release procedures. If this value is given, the StringFileInfo block must contain a PrivateBuild string. VS_FF_SPECIALBUILD File was built by the original company using standard release procedures but is a variation of the standard file of the same version number. If this value is given, the StringFileInfo block must contain a SpecialBuild string. fileos One of the following values. Value Description VOS_UNKNOWN The operating system for which the file was designed is unknown. VOS_DOS File was designed for MS-DOS. VOS_NT File was designed for Windows Server 2003 family, Windows XP, Windows 2000, or Windows NT. VOS__WINDOWS16 File was designed for 16-bit Windows. VOS__WINDOWS32 File was designed for 32-bit Windows. VOS_DOS_WINDOWS16 File was designed for 16-bit Windows running with MS-DOS. VOS_DOS_WINDOWS32 File was designed for 32-bit Windows running with MS-DOS. VOS_NT_WINDOWS32 File was designed for Windows Server 2003 family, Windows XP, Windows 2000, or Windows NT. The values 0x00002L, 0x00003L, 0x20000L and 0x30000L are reserved. filetype One of the following values. Value Description VFT_UNKNOWN File type is unknown. VFT_APP File contains an application. VFT_DLL File contains a dynamic-link library (DLL). VFT_DRV File contains a device driver. If filetype is VFT_DRV, subtype contains a more specific description of the driver. VFT_FONT File contains a font. If filetype is VFT_FONT, subtype contains a more specific description of the font. VFT_VXD File contains a virtual device. VFT_STATIC_LIB File contains a static-link library. All other values are reserved for use by Microsoft. subtype Additional information about the file type. If filetype specifies VFT_DRV, this parameter can be one of the following values. Value Description VFT2_UNKNOWN Driver type is unknown. VFT2_DRV_COMM File contains a communications driver. VFT2_DRV_PRINTER File contains a printer driver. VFT2_DRV_KEYBOARD File contains a keyboard driver. VFT2_DRV_LANGUAGE File contains a language driver. VFT2_DRV_DISPLAY File contains a display driver. VFT2_DRV_MOUSE File contains a mouse driver. VFT2_DRV_NETWORK File contains a network driver. VFT2_DRV_SYSTEM File contains a system driver. VFT2_DRV_INSTALLABLE File contains an installable driver. VFT2_DRV_SOUND File contains a sound driver. VFT2_DRV_VERSIONED_PRINTER File contains a versioned printer driver. If filetype specifies VFT_FONT, this parameter can be one of the following values. Value Description VFT2_UNKNOWN Font type is unknown. VFT2_FONT_RASTER File contains a raster font. VFT2_FONT_VECTOR File contains a vector font. VFT2_FONT_TRUETYPE File contains a TrueType font. If filetype specifies VFT_VXD, this parameter must be the virtual-device identifier included in the virtual-device control block. All subtype values not listed here are reserved for use by Microsoft. langID One of the following language codes. Code Language Code Language 0x0401 Arabic 0x0415 Polish 0x0402 Bulgarian 0x0416 Portuguese (Brazil) 0x0403 Catalan 0x0417 Rhaeto-Romanic 0x0404 Traditional Chinese 0x0418 Romanian 0x0405 Czech 0x0419 Russian 0x0406 Danish 0x041A Croato-Serbian (Latin) 0x0407 German 0x041B Slovak 0x0408 Greek 0x041C Albanian 0x0409 U.S. English 0x041D Swedish 0x040A Castilian Spanish 0x041E Thai 0x040B Finnish 0x041F Turkish 0x040C French 0x0420 Urdu 0x040D Hebrew 0x0421 Bahasa 0x040E Hungarian 0x0804 Simplified Chinese 0x040F Icelandic 0x0807 Swiss German 0x0410 Italian 0x0809 U.K. English 0x0411 Japanese 0x080A Mexican Spanish 0x0412 Korean 0x080C Belgian French 0x0413 Dutch 0x0C0C Canadian French 0x0414 Norwegian – Bokmal 0x100C Swiss French 0x0810 Swiss Italian 0x0816 Portuguese (Portugal) 0x0813 Belgian Dutch 0x081A Serbo-Croatian (Cyrillic) 0x0814 Norwegian – Nynorsk charsetID One of the following character-set identifiers. Identifier Character Set 0 7-bit ASCII 932 Japan (Shift %G–%@ JIS X-0208) 949 Korea (Shift %G–%@ KSC 5601) 950 Taiwan (Big5) 1200 Unicode 1250 Latin-2 (Eastern European) 1251 Cyrillic 1252 Multilingual 1253 Greek 1254 Turkish 1255 Hebrew 1256 Arabic string-name One of the following predefined names. Name Description Comments Additional information that should be displayed for diagnostic purposes. CompanyName Company that produced the file%G—%@for example, "Microsoft Corporation" or "Standard Microsystems Corporation, Inc." This string is required. FileDescription File description to be presented to users. This string may be displayed in a list box when the user is choosing files to install%G—%@for example, "Keyboard Driver for AT-Style Keyboards". This string is required. FileVersion Version number of the file%G—%@for example, "3.10" or "5.00.RC2". This string is required. InternalName Internal name of the file, if one exists — for example, a module name if the file is a dynamic-link library. If the file has no internal name, this string should be the original filename, without extension. This string is required. LegalCopyright Copyright notices that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, and so on — for example, "Copyright (C) Microsoft Corporation 1990–1999". This string is optional. LegalTrademarks Trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. This string is optional. OriginalFilename Original name of the file, not including a path. This information enables an application to determine whether a file has been renamed by a user. The format of the name depends on the file system for which the file was created. This string is required. PrivateBuild Information about a private version of the file — for example, "Built by TESTER1 on \TESTBED". This string should be present only if VS_FF_PRIVATEBUILD is specified in the fileflags parameter of the root block. ProductName Name of the product with which the file is distributed. This string is required. ProductVersion Version of the product with which the file is distributed — for example, "3.10" or "5.00.RC2". This string is required. SpecialBuild Text that indicates how this version of the file differs from the standard version — for example, "Private build for TESTER1 solving mouse problems on M250 and M250E computers". This string should be present only if VS_FF_SPECIALBUILD is specified in the fileflags parameter of the root block. */ nyquist-3.05/liblo/pthreads.2/sched_getscheduler.c0000644000175000000620000000424711512143043021227 0ustar stevestaff/* * sched_getscheduler.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int sched_getscheduler (pid_t pid) { /* * Win32 only has one policy which we call SCHED_OTHER. * However, we try to provide other valid side-effects * such as EPERM and ESRCH errors. */ if (0 != pid) { int selfPid = (int) GetCurrentProcessId (); if (pid != selfPid) { HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) pid); if (NULL == h) { errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; return -1; } } } return SCHED_OTHER; } nyquist-3.05/liblo/pthreads.2/pthread_getspecific.c0000644000175000000620000000525411512143043021376 0ustar stevestaff/* * pthread_getspecific.c * * Description: * POSIX thread functions which implement thread-specific data (TSD). * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" void * pthread_getspecific (pthread_key_t key) /* * ------------------------------------------------------ * DOCPUBLIC * This function returns the current value of key in the * calling thread. If no value has been set for 'key' in * the thread, NULL is returned. * * PARAMETERS * key * an instance of pthread_key_t * * * DESCRIPTION * This function returns the current value of key in the * calling thread. If no value has been set for 'key' in * the thread, NULL is returned. * * RESULTS * key value or NULL on failure * * ------------------------------------------------------ */ { void * ptr; if (key == NULL) { ptr = NULL; } else { int lasterror = GetLastError (); int lastWSAerror = WSAGetLastError (); ptr = TlsGetValue (key->key); SetLastError (lasterror); WSASetLastError (lastWSAerror); } return ptr; } nyquist-3.05/liblo/pthreads.2/exit.c0000644000175000000620000000323611512143043016351 0ustar stevestaff/* * exit.c * * Description: * This translation unit implements routines associated with exiting from * a thread. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifndef _UWIN # include #endif #include "pthread_exit.c" nyquist-3.05/liblo/pthreads.2/ptw32_is_attr.c0000644000175000000620000000344211512143043020103 0ustar stevestaff/* * ptw32_is_attr.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int ptw32_is_attr (const pthread_attr_t * attr) { /* Return 0 if the attr object is valid, non-zero otherwise. */ return (attr == NULL || *attr == NULL || (*attr)->valid != PTW32_ATTR_VALID); } nyquist-3.05/liblo/pthreads.2/pthread_join.c0000644000175000000620000001102711512143043020043 0ustar stevestaff/* * pthread_join.c * * Description: * This translation unit implements functions related to thread * synchronisation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * Not needed yet, but defining it should indicate clashes with build target * environment that should be fixed. */ #include int pthread_join (pthread_t thread, void **value_ptr) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL. This also detaches the thread on successful * completion. * * PARAMETERS * thread * an instance of pthread_t * * value_ptr * pointer to an instance of pointer to void * * * DESCRIPTION * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL. This also detaches the thread on successful * completion. * NOTE: detached threads cannot be joined or canceled * * RESULTS * 0 'thread' has completed * EINVAL thread is not a joinable thread, * ESRCH no thread could be found with ID 'thread', * ENOENT thread couldn't find it's own valid handle, * EDEADLK attempt to join thread with self * * ------------------------------------------------------ */ { int result; pthread_t self; ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; EnterCriticalSection (&ptw32_thread_reuse_lock); if (NULL == tp || thread.x != tp->ptHandle.x) { result = ESRCH; } else if (PTHREAD_CREATE_DETACHED == tp->detachState) { result = EINVAL; } else { result = 0; } LeaveCriticalSection (&ptw32_thread_reuse_lock); if (result == 0) { /* * The target thread is joinable and can't be reused before we join it. */ self = pthread_self(); if (NULL == self.p) { result = ENOENT; } else if (pthread_equal (self, thread)) { result = EDEADLK; } else { /* * Pthread_join is a cancelation point. * If we are canceled then our target thread must not be * detached (destroyed). This is guarranteed because * pthreadCancelableWait will not return if we * are canceled. */ result = pthreadCancelableWait (tp->threadH); if (0 == result) { if (value_ptr != NULL) { *value_ptr = tp->exitStatus; } /* * The result of making multiple simultaneous calls to * pthread_join() or pthread_detach() specifying the same * target is undefined. */ result = pthread_detach (thread); } else { result = ESRCH; } } } return (result); } /* pthread_join */ nyquist-3.05/liblo/pthreads.2/ptw32_getprocessors.c0000644000175000000620000000515711512143043021345 0ustar stevestaff/* * ptw32_getprocessors.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * ptw32_getprocessors() * * Get the number of CPUs available to the process. * * If the available number of CPUs is 1 then pthread_spin_lock() * will block rather than spin if the lock is already owned. * * pthread_spin_init() calls this routine when initialising * a spinlock. If the number of available processors changes * (after a call to SetProcessAffinityMask()) then only * newly initialised spinlocks will notice. */ int ptw32_getprocessors (int *count) { DWORD_PTR vProcessCPUs; DWORD_PTR vSystemCPUs; int result = 0; #if defined(NEED_PROCESS_AFFINITY_MASK) *count = 1; #else if (GetProcessAffinityMask (GetCurrentProcess (), &vProcessCPUs, &vSystemCPUs)) { DWORD_PTR bit; int CPUs = 0; for (bit = 1; bit != 0; bit <<= 1) { if (vProcessCPUs & bit) { CPUs++; } } *count = CPUs; } else { result = EAGAIN; } #endif return (result); } nyquist-3.05/liblo/pthreads.2/fork.c0000644000175000000620000000305211512143043016335 0ustar stevestaff/* * fork.c * * Description: * Implementation of fork() for POSIX threads. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" nyquist-3.05/liblo/pthreads.2/pthread_rwlock_wrlock.c0000644000175000000620000000714011512143043021767 0ustar stevestaff/* * pthread_rwlock_wrlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_wrlock (pthread_rwlock_t * rwlock) { int result; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static rwlock. We check * again inside the guarded section of ptw32_rwlock_check_need_init() * to avoid race conditions. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = ptw32_rwlock_check_need_init (rwlock); if (result != 0 && result != EBUSY) { return result; } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) { return result; } if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } if (rwl->nExclusiveAccessCount == 0) { if (rwl->nCompletedSharedAccessCount > 0) { rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; } if (rwl->nSharedAccessCount > 0) { rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; /* * This routine may be a cancelation point * according to POSIX 1003.1j section 18.1.2. */ #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); do { result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted), &(rwl->mtxSharedAccessCompleted)); } while (result == 0 && rwl->nCompletedSharedAccessCount < 0); pthread_cleanup_pop ((result != 0) ? 1 : 0); #ifdef _MSC_VER #pragma inline_depth() #endif if (result == 0) { rwl->nSharedAccessCount = 0; } } } if (result == 0) { rwl->nExclusiveAccessCount++; } return result; } nyquist-3.05/liblo/pthreads.2/README.Watcom0000644000175000000620000000445511512143043017351 0ustar stevestaffWatcom compiler notes ===================== Status ------ Not yet usable. Although the library builds under Watcom it substantially fails the test suite. There is a working Wmakefile for wmake for the library build. invoke as any of: wmake -f Wmakefile clean WC wmake -f Wmakefile clean WC-inlined wmake -f Wmakefile clean WCE wmake -f Wmakefile clean WCE-inlined These build pthreadWC.dll and pthreadWCE.dll. There is a working Wmakefile for wmake for the test suite. invoke as any of: wmake -f Wmakefile clean WC wmake -f Wmakefile clean WCX wmake -f Wmakefile clean WCE wmake -f Wmakefile clean WC-bench wmake -f Wmakefile clean WCX-bench wmake -f Wmakefile clean WCE-bench Current known problems ---------------------- Library build: The Watcom compiler uses a different default call convention to MS C or GNU C and so applications are not compatible with pthreadVC.dll etc using pre 2003-10-14 versions of pthread.h, sched.h, or semaphore.h. The cdecl attribute can be used on exposed function prototypes to force compatibility with MS C built DLLs. However, there appear to be other incompatibilities. Errno.h, for example, defines different values for the standard C and POSIX errors to those defined by the MS C errno.h. It may be that references to Watcom's threads compatible 'errno' do set and return translated numbers consistently, but I have not verified this. Watcom defines errno as a dereferenced pointer returned by the function _get_errno_ptr(). This is similar to both the MS and GNU C environments for multithreaded use. However, the Watcom version appears to have a number of problems: - different threads return the same pointer value. Compare with the MS and GNU C versions which correctly return different values (since each thread must maintain a thread specific errno value). - an errno value set within the DLL appears as zero in the application even though both share the same thread. Therefore applications built using the Watcom compiler may need to use a Watcom built version of the library (pthreadWC.dll). If this is the case, then the cdecl function attribute should not be required. Application builds: The test suite fails with the Watcom compiler. Test semaphore1.c fails for pthreadWC.dll because errno returns 0 instead of EAGAIN. nyquist-3.05/liblo/pthreads.2/private.c0000644000175000000620000000426611512143043017056 0ustar stevestaff/* * private.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* Must be first to define HAVE_INLINABLE_INTERLOCKED_CMPXCHG */ #include "ptw32_InterlockedCompareExchange.c" #include "ptw32_MCS_lock.c" #include "ptw32_is_attr.c" #include "ptw32_processInitialize.c" #include "ptw32_processTerminate.c" #include "ptw32_threadStart.c" #include "ptw32_threadDestroy.c" #include "ptw32_tkAssocCreate.c" #include "ptw32_tkAssocDestroy.c" #include "ptw32_callUserDestroyRoutines.c" #include "ptw32_semwait.c" #include "ptw32_timespec.c" #include "ptw32_relmillisecs.c" #include "ptw32_throw.c" #include "ptw32_getprocessors.c" nyquist-3.05/liblo/pthreads.2/TODO0000644000175000000620000000033111512143043015715 0ustar stevestaff Things that aren't done yet --------------------------- 1. Implement PTHREAD_PROCESS_SHARED for semaphores, mutexes, condition variables, read/write locks, barriers. nyquist-3.05/liblo/pthreads.2/ptw32_semwait.c0000644000175000000620000000702511512143043020110 0ustar stevestaff/* * ptw32_semwait.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef _UWIN //# include #endif #include "pthread.h" #include "implement.h" int ptw32_semwait (sem_t * sem) /* * ------------------------------------------------------ * DESCRIPTION * This function waits on a POSIX semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value. * * Unlike sem_wait(), this routine is non-cancelable. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno. * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; if (s == NULL) { result = EINVAL; } else { if ((result = pthread_mutex_lock (&s->lock)) == 0) { int v = --s->value; (void) pthread_mutex_unlock (&s->lock); if (v < 0) { /* Must wait */ if (WaitForSingleObject (s->sem, INFINITE) == WAIT_OBJECT_0) { #ifdef NEED_SEM if (pthread_mutex_lock (&s->lock) == 0) { if (s->leftToUnblock > 0) { --s->leftToUnblock; SetEvent(s->sem); } (void) pthread_mutex_unlock (&s->lock); } #endif return 0; } } else { return 0; } } } if (result != 0) { errno = result; return -1; } return 0; } /* ptw32_semwait */ nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_settype.c0000644000175000000620000001275511512143043022727 0ustar stevestaff/* * pthread_mutexattr_settype.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind) /* * ------------------------------------------------------ * * DOCPUBLIC * The pthread_mutexattr_settype() and * pthread_mutexattr_gettype() functions respectively set and * get the mutex type attribute. This attribute is set in the * type parameter to these functions. * * PARAMETERS * attr * pointer to an instance of pthread_mutexattr_t * * type * must be one of: * * PTHREAD_MUTEX_DEFAULT * * PTHREAD_MUTEX_NORMAL * * PTHREAD_MUTEX_ERRORCHECK * * PTHREAD_MUTEX_RECURSIVE * * DESCRIPTION * The pthread_mutexattr_settype() and * pthread_mutexattr_gettype() functions respectively set and * get the mutex type attribute. This attribute is set in the * type parameter to these functions. The default value of the * type attribute is PTHREAD_MUTEX_DEFAULT. * * The type of mutex is contained in the type attribute of the * mutex attributes. Valid mutex types include: * * PTHREAD_MUTEX_NORMAL * This type of mutex does not detect deadlock. A * thread attempting to relock this mutex without * first unlocking it will deadlock. Attempting to * unlock a mutex locked by a different thread * results in undefined behavior. Attempting to * unlock an unlocked mutex results in undefined * behavior. * * PTHREAD_MUTEX_ERRORCHECK * This type of mutex provides error checking. A * thread attempting to relock this mutex without * first unlocking it will return with an error. A * thread attempting to unlock a mutex which another * thread has locked will return with an error. A * thread attempting to unlock an unlocked mutex will * return with an error. * * PTHREAD_MUTEX_DEFAULT * Same as PTHREAD_MUTEX_NORMAL. * * PTHREAD_MUTEX_RECURSIVE * A thread attempting to relock this mutex without * first unlocking it will succeed in locking the * mutex. The relocking deadlock which can occur with * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur * with this type of mutex. Multiple locks of this * mutex require the same number of unlocks to * release the mutex before another thread can * acquire the mutex. A thread attempting to unlock a * mutex which another thread has locked will return * with an error. A thread attempting to unlock an * unlocked mutex will return with an error. This * type of mutex is only supported for mutexes whose * process shared attribute is * PTHREAD_PROCESS_PRIVATE. * * RESULTS * 0 successfully set attribute, * EINVAL 'attr' or 'type' is invalid, * * ------------------------------------------------------ */ { int result = 0; if ((attr != NULL && *attr != NULL)) { switch (kind) { case PTHREAD_MUTEX_FAST_NP: case PTHREAD_MUTEX_RECURSIVE_NP: case PTHREAD_MUTEX_ERRORCHECK_NP: (*attr)->kind = kind; break; default: result = EINVAL; break; } } else { result = EINVAL; } return (result); } /* pthread_mutexattr_settype */ nyquist-3.05/liblo/pthreads.2/condvar.c0000644000175000000620000000364111512143043017034 0ustar stevestaff/* * condvar.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * */ #include "pthread.h" #include "implement.h" #include "ptw32_cond_check_need_init.c" #include "pthread_condattr_init.c" #include "pthread_condattr_destroy.c" #include "pthread_condattr_getpshared.c" #include "pthread_condattr_setpshared.c" #include "pthread_cond_init.c" #include "pthread_cond_destroy.c" #include "pthread_cond_wait.c" #include "pthread_cond_signal.c" nyquist-3.05/liblo/pthreads.2/pthread_rwlock_destroy.c0000644000175000000620000001013611512143043022156 0ustar stevestaff/* * pthread_rwlock_destroy.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_destroy (pthread_rwlock_t * rwlock) { pthread_rwlock_t rwl; int result = 0, result1 = 0, result2 = 0; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) { rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) { return result; } if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } /* * Check whether any threads own/wait for the lock (wait for ex.access); * report "BUSY" if so. */ if (rwl->nExclusiveAccessCount > 0 || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) { result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); result2 = EBUSY; } else { rwl->nMagic = 0; if ((result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) { pthread_mutex_unlock (&rwl->mtxExclusiveAccess); return result; } if ((result = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) != 0) { return result; } *rwlock = NULL; /* Invalidate rwlock before anything else */ result = pthread_cond_destroy (&(rwl->cndSharedAccessCompleted)); result1 = pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); result2 = pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); (void) free (rwl); } } else { /* * See notes in ptw32_rwlock_check_need_init() above also. */ EnterCriticalSection (&ptw32_rwlock_test_init_lock); /* * Check again. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { /* * This is all we need to do to destroy a statically * initialised rwlock that has not yet been used (initialised). * If we get to here, another thread * waiting to initialise this rwlock will get an EINVAL. */ *rwlock = NULL; } else { /* * The rwlock has been initialised while we were waiting * so assume it's in use. */ result = EBUSY; } LeaveCriticalSection (&ptw32_rwlock_test_init_lock); } return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); } nyquist-3.05/liblo/pthreads.2/sched_yield.c0000644000175000000620000000505311512143043017653 0ustar stevestaff/* * sched_yield.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int sched_yield (void) /* * ------------------------------------------------------ * DOCPUBLIC * This function indicates that the calling thread is * willing to give up some time slices to other threads. * * PARAMETERS * N/A * * * DESCRIPTION * This function indicates that the calling thread is * willing to give up some time slices to other threads. * NOTE: Since this is part of POSIX 1003.1b * (realtime extensions), it is defined as returning * -1 if an error occurs and sets errno to the actual * error. * * RESULTS * 0 successfully created semaphore, * ENOSYS sched_yield not supported, * * ------------------------------------------------------ */ { Sleep (0); return 0; } nyquist-3.05/liblo/pthreads.2/pthread_attr_setinheritsched.c0000644000175000000620000000367211512143043023332 0ustar stevestaff/* * pthread_attr_setinheritsched.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_attr_setinheritsched (pthread_attr_t * attr, int inheritsched) { if (ptw32_is_attr (attr) != 0) { return EINVAL; } if (PTHREAD_INHERIT_SCHED != inheritsched && PTHREAD_EXPLICIT_SCHED != inheritsched) { return EINVAL; } (*attr)->inheritsched = inheritsched; return 0; } nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_destroy.c0000644000175000000620000000525211512143043022715 0ustar stevestaff/* * pthread_mutexattr_destroy.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_destroy (pthread_mutexattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Destroys a mutex attributes object. The object can * no longer be used. * * PARAMETERS * attr * pointer to an instance of pthread_mutexattr_t * * * DESCRIPTION * Destroys a mutex attributes object. The object can * no longer be used. * * NOTES: * 1) Does not affect mutexes created using 'attr' * * RESULTS * 0 successfully released attr, * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ { int result = 0; if (attr == NULL || *attr == NULL) { result = EINVAL; } else { pthread_mutexattr_t ma = *attr; *attr = NULL; free (ma); } return (result); } /* pthread_mutexattr_destroy */ nyquist-3.05/liblo/pthreads.2/pthread_barrier_init.c0000644000175000000620000000536511512143043021565 0ustar stevestaff/* * pthread_barrier_init.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrier_init (pthread_barrier_t * barrier, const pthread_barrierattr_t * attr, unsigned int count) { pthread_barrier_t b; if (barrier == NULL || count == 0) { return EINVAL; } if (NULL != (b = (pthread_barrier_t) calloc (1, sizeof (*b)))) { b->pshared = (attr != NULL && *attr != NULL ? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE); b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count; b->iStep = 0; /* * Two semaphores are used in the same way as two stepping * stones might be used in crossing a stream. Once all * threads are safely on one stone, the other stone can * be moved ahead, and the threads can start moving to it. * If some threads decide to eat their lunch before moving * then the other threads have to wait. */ if (0 == sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0)) { if (0 == sem_init (&(b->semBarrierBreeched[1]), b->pshared, 0)) { *barrier = b; return 0; } (void) sem_destroy (&(b->semBarrierBreeched[0])); } (void) free (b); } return ENOMEM; } nyquist-3.05/liblo/pthreads.2/pthread_attr_setschedpolicy.c0000644000175000000620000000351111512143043023157 0ustar stevestaff/* * pthread_attr_setschedpolicy.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_attr_setschedpolicy (pthread_attr_t * attr, int policy) { if (ptw32_is_attr (attr) != 0) { return EINVAL; } if (policy != SCHED_OTHER) { return ENOTSUP; } return 0; } nyquist-3.05/liblo/pthreads.2/pthread_mutex_destroy.c0000644000175000000620000001001411512143043022012 0ustar stevestaff/* * pthread_mutex_destroy.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutex_destroy (pthread_mutex_t * mutex) { int result = 0; pthread_mutex_t mx; /* * Let the system deal with invalid pointers. */ /* * Check to see if we have something to delete. */ if (*mutex < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { mx = *mutex; result = pthread_mutex_trylock (&mx); /* * If trylock succeeded and the mutex is not recursively locked it * can be destroyed. */ if (result == 0) { if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count) { /* * FIXME!!! * The mutex isn't held by another thread but we could still * be too late invalidating the mutex below since another thread * may already have entered mutex_lock and the check for a valid * *mutex != NULL. * * Note that this would be an unusual situation because it is not * common that mutexes are destroyed while they are still in * use by other threads. */ *mutex = NULL; result = pthread_mutex_unlock (&mx); if (result == 0) { if (!CloseHandle (mx->event)) { *mutex = mx; result = EINVAL; } else { free (mx); } } else { /* * Restore the mutex before we return the error. */ *mutex = mx; } } else /* mx->recursive_count > 1 */ { /* * The mutex must be recursive and already locked by us (this thread). */ mx->recursive_count--; /* Undo effect of pthread_mutex_trylock() above */ result = EBUSY; } } } else { /* * See notes in ptw32_mutex_check_need_init() above also. */ EnterCriticalSection (&ptw32_mutex_test_init_lock); /* * Check again. */ if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { /* * This is all we need to do to destroy a statically * initialised mutex that has not yet been used (initialised). * If we get to here, another thread * waiting to initialise this mutex will get an EINVAL. */ *mutex = NULL; } else { /* * The mutex has been initialised while we were waiting * so assume it's in use. */ result = EBUSY; } LeaveCriticalSection (&ptw32_mutex_test_init_lock); } return (result); } nyquist-3.05/liblo/pthreads.2/pthread_setcancelstate.c0000644000175000000620000001007611512143043022111 0ustar stevestaff/* * pthread_setcancelstate.c * * Description: * POSIX thread functions related to thread cancellation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_setcancelstate (int state, int *oldstate) /* * ------------------------------------------------------ * DOCPUBLIC * This function atomically sets the calling thread's * cancelability state to 'state' and returns the previous * cancelability state at the location referenced by * 'oldstate' * * PARAMETERS * state, * oldstate * PTHREAD_CANCEL_ENABLE * cancellation is enabled, * * PTHREAD_CANCEL_DISABLE * cancellation is disabled * * * DESCRIPTION * This function atomically sets the calling thread's * cancelability state to 'state' and returns the previous * cancelability state at the location referenced by * 'oldstate'. * * NOTES: * 1) Use to disable cancellation around 'atomic' code that * includes cancellation points * * COMPATIBILITY ADDITIONS * If 'oldstate' is NULL then the previous state is not returned * but the function still succeeds. (Solaris) * * RESULTS * 0 successfully set cancelability type, * EINVAL 'state' is invalid * * ------------------------------------------------------ */ { int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)) { return EINVAL; } /* * Lock for async-cancel safety. */ (void) pthread_mutex_lock (&sp->cancelLock); if (oldstate != NULL) { *oldstate = sp->cancelState; } sp->cancelState = state; /* * Check if there is a pending asynchronous cancel */ if (state == PTHREAD_CANCEL_ENABLE && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } (void) pthread_mutex_unlock (&sp->cancelLock); return (result); } /* pthread_setcancelstate */ nyquist-3.05/liblo/pthreads.2/ptw32_spinlock_check_need_init.c0000644000175000000620000000545511512143043023441 0ustar stevestaff/* * ptw32_spinlock_check_need_init.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" INLINE int ptw32_spinlock_check_need_init (pthread_spinlock_t * lock) { int result = 0; /* * The following guarded test is specifically for statically * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER). * * Note that by not providing this synchronisation we risk * introducing race conditions into applications which are * correctly written. */ EnterCriticalSection (&ptw32_spinlock_test_init_lock); /* * We got here possibly under race * conditions. Check again inside the critical section * and only initialise if the spinlock is valid (not been destroyed). * If a static spinlock has been destroyed, the application can * re-initialise it only by calling pthread_spin_init() * explicitly. */ if (*lock == PTHREAD_SPINLOCK_INITIALIZER) { result = pthread_spin_init (lock, PTHREAD_PROCESS_PRIVATE); } else if (*lock == NULL) { /* * The spinlock has been destroyed while we were waiting to * initialise it, so the operation that caused the * auto-initialisation should fail. */ result = EINVAL; } LeaveCriticalSection (&ptw32_spinlock_test_init_lock); return (result); } nyquist-3.05/liblo/pthreads.2/BUGS0000644000175000000620000001363111512143043015717 0ustar stevestaff---------- Known bugs ---------- 1. Not strictly a bug, more of a gotcha. Under MS VC++ (only tested with version 6.0), a term_func set via the standard C++ set_terminate() function causes the application to abort. Notes from the MSVC++ manual: 1) A term_func() should call exit(), otherwise abort() will be called on return to the caller. A call to abort() raises SIGABRT and the default signal handler for all signals terminates the calling program with exit code 3. 2) A term_func() must not throw an exception. Therefore term_func() should not call pthread_exit(), which works by throwing an exception (pthreadVCE or pthreadVSE) or by calling longjmp (pthreadVC). Workaround: avoid using pthread_exit() in C++ applications. Exit threads by dropping through the end of the thread routine. 2. Cancellation problems in optimised code - Milan Gardian This is suspected to be a compiler bug in VC6.0, and also seen in VC7.0 and VS .NET 2003. The GNU C++ compiler does not have a problem with this, and it has been reported that the Intel C++ 8.1 compiler and Visual C++ 2005 Express Edition Beta2 pass tests\semaphore4.c (which exposes the bug). Workaround [rpj - 2 Feb 2002] ----------------------------- [Please note: this workaround did not solve a similar problem in snapshot-2004-11-03 or later, even though similar symptoms were seen. tests\semaphore4.c fails in that snapshot for the VCE version of the DLL.] The problem disappears when /Ob0 is used, i.e. /O2 /Ob0 works OK, but if you want to use inlining optimisation you can be much more specific about where it's switched off and on by using a pragma. So the inlining optimisation is interfering with the way that cleanup handlers are run. It appears to relate to auto-inlining of class methods since this is the only auto inlining that is performed at /O1 optimisation (functions with the "inline" qualifier are also inlined, but the problem doesn't appear to involve any such functions in the library or testsuite). In order to confirm the inlining culprit, the following use of pragmas eliminate the problem but I don't know how to make it transparent, putting it in, say, pthread.h where pthread_cleanup_push defined as a macro. #pragma inline_depth(0) pthread_cleanup_push(handlerFunc, (void *) &arg); /* ... */ pthread_cleanup_pop(0); #pragma inline_depth() Note the empty () pragma value after the pop macro. This resets depth to the default. Or you can specify a non-zero depth here. The pragma is also needed (and now used) within the library itself wherever cleanup handlers are used (condvar.c and rwlock.c). Use of these pragmas allows compiler optimisations /O1 and /O2 to be used for either or both the library and applications. Experimenting further, I found that wrapping the actual cleanup handler function with #pragma auto_inline(off|on) does NOT work. MSVC6.0 doesn't appear to support the C99 standard's _Pragma directive, however, later versions may. This form is embeddable inside #define macros, which would be ideal because it would mean that it could be added to the push/pop macro definitions in pthread.h and hidden from the application programmer. [/rpj] Original problem description ---------------------------- The cancellation (actually, cleanup-after-cancel) tests fail when using VC (professional) optimisation switches (/O1 or /O2) in pthreads library. I have not investigated which concrete optimisation technique causes this problem (/Og, /Oi, /Ot, /Oy, /Ob1, /Gs, /Gf, /Gy, etc.), but here is a summary of builds and corresponding failures: * pthreads VSE (optimised tests): OK * pthreads VCE (optimised tests): Failed "cleanup1" test (runtime) * pthreads VSE (DLL in CRT, optimised tests): OK * pthreads VCE (DLL in CRT, optimised tests): Failed "cleanup1" test (runtime) Please note that while in VSE version of the pthreads library the optimisation does not really have any impact on the tests (they pass OK), in VCE version addition of optimisation (/O2 in this case) causes the tests to fail uniformly - either in "cleanup0" or "cleanup1" test cases. Please note that all the tests above use default pthreads DLL (no optimisations, linked with either static or DLL CRT, based on test type). Therefore the problem lies not within the pthreads DLL but within the compiled client code (the application using pthreads -> involvement of "pthread.h"). I think the message of this section is that usage of VCE version of pthreads in applications relying on cancellation/cleanup AND using optimisations for creation of production code is highly unreliable for the current version of the pthreads library. 3. The Borland Builder 5.5 version of the library produces memory read exceptions in some tests. 4. pthread_barrier_wait() can deadlock if the number of potential calling threads for a particular barrier is greater than the barrier count parameter given to pthread_barrier_init() for that barrier. This is due to the very lightweight implementation of pthread-win32 barriers. To cope with more than "count" possible waiters, barriers must effectively implement all the same safeguards as condition variables, making them much "heavier" than at present. The workaround is to ensure that no more than "count" threads attempt to wait at the barrier. 5. Canceling a thread blocked on pthread_once appears not to work in the MSVC++ version of the library "pthreadVCE.dll". The test case "once3.c" hangs. I have no clues on this at present. All other versions pass this test ok - pthreadsVC.dll, pthreadsVSE.dll, pthreadsGC.dll and pthreadsGCE.dll. nyquist-3.05/liblo/pthreads.2/pthread_attr_setscope.c0000644000175000000620000000412011512143043021757 0ustar stevestaff/* * pthread_attr_setscope.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int pthread_attr_setscope (pthread_attr_t * attr, int contentionscope) { #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING switch (contentionscope) { case PTHREAD_SCOPE_SYSTEM: (*attr)->contentionscope = contentionscope; return 0; case PTHREAD_SCOPE_PROCESS: return ENOTSUP; default: return EINVAL; } #else return ENOSYS; #endif } nyquist-3.05/liblo/pthreads.2/pthread_barrierattr_init.c0000644000175000000620000000530411512143043022451 0ustar stevestaff/* * pthread_barrier_attr_init.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrierattr_init (pthread_barrierattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Initializes a barrier attributes object with default * attributes. * * PARAMETERS * attr * pointer to an instance of pthread_barrierattr_t * * * DESCRIPTION * Initializes a barrier attributes object with default * attributes. * * NOTES: * 1) Used to define barrier types * * RESULTS * 0 successfully initialized attr, * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ { pthread_barrierattr_t ba; int result = 0; ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba)); if (ba == NULL) { result = ENOMEM; } else { ba->pshared = PTHREAD_PROCESS_PRIVATE; } *attr = ba; return (result); } /* pthread_barrierattr_init */ nyquist-3.05/liblo/pthreads.2/sem_timedwait.c0000644000175000000620000001472411512143043020237 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_timedwait.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" typedef struct { sem_t sem; int * resultPtr; } sem_timedwait_cleanup_args_t; static void PTW32_CDECL ptw32_sem_timedwait_cleanup (void * args) { sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args; sem_t s = a->sem; if (pthread_mutex_lock (&s->lock) == 0) { /* * We either timed out or were cancelled. * If someone has posted between then and now we try to take the semaphore. * Otherwise the semaphore count may be wrong after we * return. In the case of a cancellation, it is as if we * were cancelled just before we return (after taking the semaphore) * which is ok. */ if (WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0) { /* We got the semaphore on the second attempt */ *(a->resultPtr) = 0; } else { /* Indicate we're no longer waiting */ s->value++; #ifdef NEED_SEM if (s->value > 0) { s->leftToUnblock = 0; } #else /* * Don't release the W32 sema, it doesn't need adjustment * because it doesn't record the number of waiters. */ #endif } (void) pthread_mutex_unlock (&s->lock); } } int sem_timedwait (sem_t * sem, const struct timespec *abstime) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a semaphore possibly until * 'abstime' time. * * PARAMETERS * sem * pointer to an instance of sem_t * * abstime * pointer to an instance of struct timespec * * DESCRIPTION * This function waits on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value or until interrupted by * a signal. * * If 'abstime' is a NULL pointer then this function will * block until it can successfully decrease the value or * until interrupted by a signal. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * ETIMEDOUT abstime elapsed before success. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; pthread_testcancel(); if (sem == NULL) { result = EINVAL; } else { DWORD milliseconds; if (abstime == NULL) { milliseconds = INFINITE; } else { /* * Calculate timeout as milliseconds from current system time. */ milliseconds = ptw32_relmillisecs (abstime); } if ((result = pthread_mutex_lock (&s->lock)) == 0) { int v; /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } v = --s->value; (void) pthread_mutex_unlock (&s->lock); if (v < 0) { #ifdef NEED_SEM int timedout; #endif sem_timedwait_cleanup_args_t cleanup_args; cleanup_args.sem = s; cleanup_args.resultPtr = &result; #ifdef _MSC_VER #pragma inline_depth(0) #endif /* Must wait */ pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args); #ifdef NEED_SEM timedout = #endif result = pthreadCancelableTimedWait (s->sem, milliseconds); pthread_cleanup_pop(result); #ifdef _MSC_VER #pragma inline_depth() #endif #ifdef NEED_SEM if (!timedout && pthread_mutex_lock (&s->lock) == 0) { if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } if (s->leftToUnblock > 0) { --s->leftToUnblock; SetEvent(s->sem); } (void) pthread_mutex_unlock (&s->lock); } #endif /* NEED_SEM */ } } } if (result != 0) { errno = result; return -1; } return 0; } /* sem_timedwait */ nyquist-3.05/liblo/pthreads.2/ptw32_rwlock_cancelwrwait.c0000644000175000000620000000364211512143043022504 0ustar stevestaff/* * ptw32_rwlock_cancelwrwait.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" void ptw32_rwlock_cancelwrwait (void *arg) { pthread_rwlock_t rwl = (pthread_rwlock_t) arg; rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; (void) pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); } nyquist-3.05/liblo/pthreads.2/pthread_cancel.c0000644000175000000620000001402611512143043020333 0ustar stevestaff/* * pthread_cancel.c * * Description: * POSIX thread functions related to thread cancellation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #if defined(_M_IX86) || defined(_X86_) #define PTW32_PROGCTR(Context) ((Context).Eip) #endif #if defined (_M_IA64) #define PTW32_PROGCTR(Context) ((Context).StIIP) #endif #if defined(_MIPS_) #define PTW32_PROGCTR(Context) ((Context).Fir) #endif #if defined(_ALPHA_) #define PTW32_PROGCTR(Context) ((Context).Fir) #endif #if defined(_PPC_) #define PTW32_PROGCTR(Context) ((Context).Iar) #endif #if defined(_AMD64_) #define PTW32_PROGCTR(Context) ((Context).Rip) #endif #if !defined(PTW32_PROGCTR) #error Module contains CPU-specific code; modify and recompile. #endif static void ptw32_cancel_self (void) { ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } static void CALLBACK ptw32_cancel_callback (DWORD unused) { ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } /* * ptw32_RegisterCancelation() - * Must have args of same type as QueueUserAPCEx because this function * is a substitute for QueueUserAPCEx if it's not available. */ DWORD ptw32_RegisterCancelation (PAPCFUNC unused1, HANDLE threadH, DWORD unused2) { CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext (threadH, &context); PTW32_PROGCTR (context) = (DWORD_PTR) ptw32_cancel_self; SetThreadContext (threadH, &context); return 0; } int pthread_cancel (pthread_t thread) /* * ------------------------------------------------------ * DOCPUBLIC * This function requests cancellation of 'thread'. * * PARAMETERS * thread * reference to an instance of pthread_t * * * DESCRIPTION * This function requests cancellation of 'thread'. * NOTE: cancellation is asynchronous; use pthread_join to * wait for termination of 'thread' if necessary. * * RESULTS * 0 successfully requested cancellation, * ESRCH no thread found corresponding to 'thread', * ENOMEM implicit self thread create failed. * ------------------------------------------------------ */ { int result; int cancel_self; pthread_t self; ptw32_thread_t * tp; result = pthread_kill (thread, 0); if (0 != result) { return result; } if ((self = pthread_self ()).p == NULL) { return ENOMEM; }; /* * FIXME!! * * Can a thread cancel itself? * * The standard doesn't * specify an error to be returned if the target * thread is itself. * * If it may, then we need to ensure that a thread can't * deadlock itself trying to cancel itself asyncronously * (pthread_cancel is required to be an async-cancel * safe function). */ cancel_self = pthread_equal (thread, self); tp = (ptw32_thread_t *) thread.p; /* * Lock for async-cancel safety. */ (void) pthread_mutex_lock (&tp->cancelLock); if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && tp->cancelState == PTHREAD_CANCEL_ENABLE && tp->state < PThreadStateCanceling) { if (cancel_self) { tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&tp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } else { HANDLE threadH = tp->threadH; SuspendThread (threadH); if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) { tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; /* * If alertdrv and QueueUserAPCEx is available then the following * will result in a call to QueueUserAPCEx with the args given, otherwise * this will result in a call to ptw32_RegisterCancelation and only * the threadH arg will be used. */ ptw32_register_cancelation (ptw32_cancel_callback, threadH, 0); (void) pthread_mutex_unlock (&tp->cancelLock); ResumeThread (threadH); } } } else { /* * Set for deferred cancellation. */ if (tp->state < PThreadStateCancelPending) { tp->state = PThreadStateCancelPending; if (!SetEvent (tp->cancelEvent)) { result = ESRCH; } } else if (tp->state >= PThreadStateCanceling) { result = ESRCH; } (void) pthread_mutex_unlock (&tp->cancelLock); } return (result); } nyquist-3.05/liblo/pthreads.2/ptw32_processTerminate.c0000644000175000000620000000671111512143043021767 0ustar stevestaff/* * ptw32_processTerminate.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" void ptw32_processTerminate (void) /* * ------------------------------------------------------ * DOCPRIVATE * This function performs process wide termination for * the pthread library. * * PARAMETERS * N/A * * DESCRIPTION * This function performs process wide termination for * the pthread library. * This routine sets the global variable * ptw32_processInitialized to FALSE * * RESULTS * N/A * * ------------------------------------------------------ */ { if (ptw32_processInitialized) { ptw32_thread_t * tp, * tpNext; if (ptw32_selfThreadKey != NULL) { /* * Release ptw32_selfThreadKey */ pthread_key_delete (ptw32_selfThreadKey); ptw32_selfThreadKey = NULL; } if (ptw32_cleanupKey != NULL) { /* * Release ptw32_cleanupKey */ pthread_key_delete (ptw32_cleanupKey); ptw32_cleanupKey = NULL; } EnterCriticalSection (&ptw32_thread_reuse_lock); tp = ptw32_threadReuseTop; while (tp != PTW32_THREAD_REUSE_EMPTY) { tpNext = tp->prevReuse; free (tp); tp = tpNext; } LeaveCriticalSection (&ptw32_thread_reuse_lock); /* * Destroy the global locks and other objects. */ DeleteCriticalSection (&ptw32_spinlock_test_init_lock); DeleteCriticalSection (&ptw32_rwlock_test_init_lock); DeleteCriticalSection (&ptw32_cond_test_init_lock); DeleteCriticalSection (&ptw32_cond_list_lock); DeleteCriticalSection (&ptw32_mutex_test_init_lock); DeleteCriticalSection (&ptw32_thread_reuse_lock); ptw32_processInitialized = PTW32_FALSE; } } /* processTerminate */ nyquist-3.05/liblo/pthreads.2/pthread_kill.c0000644000175000000620000000671011512143043020042 0ustar stevestaff/* * pthread_kill.c * * Description: * This translation unit implements the pthread_kill routine. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * Not needed yet, but defining it should indicate clashes with build target * environment that should be fixed. */ #include int pthread_kill (pthread_t thread, int sig) /* * ------------------------------------------------------ * DOCPUBLIC * This function requests that a signal be delivered to the * specified thread. If sig is zero, error checking is * performed but no signal is actually sent such that this * function can be used to check for a valid thread ID. * * PARAMETERS * thread reference to an instances of pthread_t * sig signal. Currently only a value of 0 is supported. * * * DESCRIPTION * This function requests that a signal be delivered to the * specified thread. If sig is zero, error checking is * performed but no signal is actually sent such that this * function can be used to check for a valid thread ID. * * RESULTS * ESRCH the thread is not a valid thread ID, * EINVAL the value of the signal is invalid * or unsupported. * 0 the signal was successfully sent. * * ------------------------------------------------------ */ { int result = 0; ptw32_thread_t * tp; EnterCriticalSection (&ptw32_thread_reuse_lock); tp = (ptw32_thread_t *) thread.p; if (NULL == tp || thread.x != tp->ptHandle.x || NULL == tp->threadH) { result = ESRCH; } LeaveCriticalSection (&ptw32_thread_reuse_lock); if (0 == result && 0 != sig) { /* * Currently does not support any signals. */ result = EINVAL; } return result; } /* pthread_kill */ nyquist-3.05/liblo/pthreads.2/pthread.c0000644000175000000620000000424011512143043017023 0ustar stevestaff/* * pthread.c * * Description: * This translation unit agregates pthreads-win32 translation units. * It is used for inline optimisation of the library, * maximising for speed at the expense of size. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* The following are ordered for inlining */ #include "private.c" #include "attr.c" #include "barrier.c" #include "cancel.c" #include "cleanup.c" #include "condvar.c" #include "create.c" #include "dll.c" #include "errno.c" #include "exit.c" #include "fork.c" #include "global.c" #include "misc.c" #include "mutex.c" #include "nonportable.c" #include "rwlock.c" #include "sched.c" #include "semaphore.c" #include "signal.c" #include "spin.c" #include "sync.c" #include "tsd.c" nyquist-3.05/liblo/pthreads.2/pthread_getschedparam.c0000644000175000000620000000471311512143043021717 0ustar stevestaff/* * sched_getschedparam.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_getschedparam (pthread_t thread, int *policy, struct sched_param *param) { int result; /* Validate the thread id. */ result = pthread_kill (thread, 0); if (0 != result) { return result; } /* * Validate the policy and param args. * Check that a policy constant wasn't passed rather than &policy. */ if (policy <= (int *) SCHED_MAX || param == NULL) { return EINVAL; } /* Fill out the policy. */ *policy = SCHED_OTHER; /* * This function must return the priority value set by * the most recent pthread_setschedparam() or pthread_create() * for the target thread. It must not return the actual thread * priority as altered by any system priority adjustments etc. */ param->sched_priority = ((ptw32_thread_t *)thread.p)->sched_priority; return 0; } nyquist-3.05/liblo/pthreads.2/pthread_condattr_getpshared.c0000644000175000000620000000653311512143043023136 0ustar stevestaff/* * pthread_condattr_getpshared.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Determine whether condition variables created with 'attr' * can be shared between processes. * * PARAMETERS * attr * pointer to an instance of pthread_condattr_t * * pshared * will be set to one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * * DESCRIPTION * Condition Variables created with 'attr' can be shared * between processes if pthread_cond_t variable is allocated * in memory shared by these processes. * NOTES: * 1) pshared condition variables MUST be allocated in * shared memory. * * 2) The following macro is defined if shared mutexes * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully retrieved attribute, * EINVAL 'attr' or 'pshared' is invalid, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && (pshared != NULL)) { *pshared = (*attr)->pshared; result = 0; } else { result = EINVAL; } return result; } /* pthread_condattr_getpshared */ nyquist-3.05/liblo/pthreads.2/BuildLog.htm0000644000175000000620000000667211512143043017456 0ustar stevestaff<html> <head> <META HTTP-EQUIV="Content-Type" content="text/html; charset=utf-16"> </head> <body> <pre> <table width=100% bgcolor=#CFCFE5><tr> <td> <font face=arial size=+3> Build Log </font></table><table width=* cellspacing=0 cellpadding=0><tr><td width=0 bgcolor=#EDEDF5>&nbsp;</td><td width=0 bgcolor=#FFFFFF>&nbsp;</td><td width=*><pre> <h3>Build started: Project: pthread, Configuration: Release|Win32</h3> </pre></table><table width=100% bgcolor=#DFDFE5><tr><td><font face=arial size=+2> Command Lines </font></table><table width=* cellspacing=0 cellpadding=0><tr><td width=0 bgcolor=#EDEDF5>&nbsp;</td><td width=0 bgcolor=#FFFFFF>&nbsp;</td><td width=*><pre>Creating temporary file "c:\Users\rbd\nyquist\liblo\pthreads.2\RSP0000B590767480.rsp" with contents [ /OUT:&quot;C:\Users\rbd\nyquist\/liblo/lib/Release\pthread.lib&quot; .\pthread.obj .\version.res ] Creating command line "lib.exe @c:\Users\rbd\nyquist\liblo\pthreads.2\RSP0000B590767480.rsp /NOLOGO" </pre></table><table width=100% bgcolor=#DFDFE5><tr><td><font face=arial size=+2> Output Window </font></table><table width=* cellspacing=0 cellpadding=0><tr><td width=0 bgcolor=#EDEDF5>&nbsp;</td><td width=0 bgcolor=#FFFFFF>&nbsp;</td><td width=*><pre>Creating library... </pre></table><table width=100% bgcolor=#DFDFE5><tr><td><font face=arial size=+2> Results </font></table><table width=* cellspacing=0 cellpadding=0><tr><td width=0 bgcolor=#EDEDF5>&nbsp;</td><td width=0 bgcolor=#FFFFFF>&nbsp;</td><td width=*><pre>Build log was saved at "file://c:\Users\rbd\nyquist\liblo\pthreads.2\BuildLog.htm" pthread - 0 error(s), 0 warning(s) </pre></table><table width=100% height=20 bgcolor=#CFCFE5><tr><td><font face=arial size=+2> </font></table></body></html>nyquist-3.05/liblo/pthreads.2/pthread_rwlock_timedwrlock.c0000644000175000000620000000733011512143043023013 0ustar stevestaff/* * pthread_rwlock_timedwrlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_timedwrlock (pthread_rwlock_t * rwlock, const struct timespec *abstime) { int result; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static rwlock. We check * again inside the guarded section of ptw32_rwlock_check_need_init() * to avoid race conditions. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = ptw32_rwlock_check_need_init (rwlock); if (result != 0 && result != EBUSY) { return result; } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) { return result; } if ((result = pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), abstime)) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } if (rwl->nExclusiveAccessCount == 0) { if (rwl->nCompletedSharedAccessCount > 0) { rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; } if (rwl->nSharedAccessCount > 0) { rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; /* * This routine may be a cancelation point * according to POSIX 1003.1j section 18.1.2. */ #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); do { result = pthread_cond_timedwait (&(rwl->cndSharedAccessCompleted), &(rwl->mtxSharedAccessCompleted), abstime); } while (result == 0 && rwl->nCompletedSharedAccessCount < 0); pthread_cleanup_pop ((result != 0) ? 1 : 0); #ifdef _MSC_VER #pragma inline_depth() #endif if (result == 0) { rwl->nSharedAccessCount = 0; } } } if (result == 0) { rwl->nExclusiveAccessCount++; } return result; } nyquist-3.05/liblo/pthreads.2/create.c0000644000175000000620000002012311512143043016635 0ustar stevestaff/* * create.c * * Description: * This translation unit implements routines associated with spawning a new * thread. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifndef _UWIN #include #endif int pthread_create (pthread_t * tid, const pthread_attr_t * attr, void *(*start) (void *), void *arg) /* * ------------------------------------------------------ * DOCPUBLIC * This function creates a thread running the start function, * passing it the parameter value, 'arg'. The 'attr' * argument specifies optional creation attributes. * The identity of the new thread is returned * via 'tid', which should not be NULL. * * PARAMETERS * tid * pointer to an instance of pthread_t * * attr * optional pointer to an instance of pthread_attr_t * * start * pointer to the starting routine for the new thread * * arg * optional parameter passed to 'start' * * * DESCRIPTION * This function creates a thread running the start function, * passing it the parameter value, 'arg'. The 'attr' * argument specifies optional creation attributes. * The identity of the new thread is returned * via 'tid', which should not be the NULL pointer. * * RESULTS * 0 successfully created thread, * EINVAL attr invalid, * EAGAIN insufficient resources. * * ------------------------------------------------------ */ { pthread_t thread; ptw32_thread_t * tp; register pthread_attr_t a; HANDLE threadH = 0; int result = EAGAIN; int run = PTW32_TRUE; ThreadParms *parms = NULL; long stackSize; int priority; pthread_t self; /* * Before doing anything, check that tid can be stored through * without invoking a memory protection error (segfault). * Make sure that the assignment below can't be optimised out by the compiler. * This is assured by conditionally assigning *tid again at the end. */ tid->x = 0; if (attr != NULL) { a = *attr; } else { a = NULL; } if ((thread = ptw32_new ()).p == NULL) { goto FAIL0; } tp = (ptw32_thread_t *) thread.p; priority = tp->sched_priority; if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL) { goto FAIL0; } parms->tid = thread; parms->start = start; parms->arg = arg; #if defined(HAVE_SIGSET_T) /* * Threads inherit their initial sigmask from their creator thread. */ self = pthread_self(); tp->sigmask = ((ptw32_thread_t *)self.p)->sigmask; #endif /* HAVE_SIGSET_T */ if (a != NULL) { stackSize = a->stacksize; tp->detachState = a->detachstate; priority = a->param.sched_priority; #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) /* WinCE */ #else /* Everything else */ /* * Thread priority must be set to a valid system level * without altering the value set by pthread_attr_setschedparam(). */ /* * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads * don't inherit their creator's priority. They are started with * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying * an 'attr' arg to pthread_create() is equivalent to defaulting to * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. */ if (PTHREAD_INHERIT_SCHED == a->inheritsched) { /* * If the thread that called pthread_create() is a Win32 thread * then the inherited priority could be the result of a temporary * system adjustment. This is not the case for POSIX threads. */ #if ! defined(HAVE_SIGSET_T) self = pthread_self (); #endif priority = ((ptw32_thread_t *) self.p)->sched_priority; } #endif } else { /* * Default stackSize */ stackSize = PTHREAD_STACK_MIN; } tp->state = run ? PThreadStateInitial : PThreadStateSuspended; tp->keys = NULL; /* * Threads must be started in suspended mode and resumed if necessary * after _beginthreadex returns us the handle. Otherwise we set up a * race condition between the creating and the created threads. * Note that we also retain a local copy of the handle for use * by us in case thread.p->threadH gets NULLed later but before we've * finished with it here. */ #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) tp->threadH = threadH = (HANDLE) _beginthreadex ((void *) NULL, /* No security info */ (unsigned) stackSize, /* default stack size */ ptw32_threadStart, parms, (unsigned) CREATE_SUSPENDED, (unsigned *) &(tp->thread)); if (threadH != 0) { if (a != NULL) { (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); } if (run) { ResumeThread (threadH); } } #else /* __MINGW32__ && ! __MSVCRT__ */ /* * This lock will force pthread_threadStart() to wait until we have * the thread handle and have set the priority. */ (void) pthread_mutex_lock (&tp->cancelLock); tp->threadH = threadH = (HANDLE) _beginthread (ptw32_threadStart, (unsigned) stackSize, /* default stack size */ parms); /* * Make the return code match _beginthreadex's. */ if (threadH == (HANDLE) - 1L) { tp->threadH = threadH = 0; } else { if (!run) { /* * beginthread does not allow for create flags, so we do it now. * Note that beginthread itself creates the thread in SUSPENDED * mode, and then calls ResumeThread to start it. */ SuspendThread (threadH); } if (a != NULL) { (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); } } (void) pthread_mutex_unlock (&tp->cancelLock); #endif /* __MINGW32__ && ! __MSVCRT__ */ result = (threadH != 0) ? 0 : EAGAIN; /* * Fall Through Intentionally */ /* * ------------ * Failure Code * ------------ */ FAIL0: if (result != 0) { ptw32_threadDestroy (thread); tp = NULL; if (parms != NULL) { free (parms); } } else { *tid = thread; } #ifdef _UWIN if (result == 0) pthread_count++; #endif return (result); } /* pthread_create */ nyquist-3.05/liblo/pthreads.2/sem_post_multiple.c0000644000175000000620000001000311512143043021132 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_post_multiple.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" int sem_post_multiple (sem_t * sem, int count) /* * ------------------------------------------------------ * DOCPUBLIC * This function posts multiple wakeups to a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * count * counter, must be greater than zero. * * DESCRIPTION * This function posts multiple wakeups to a semaphore. If there * are waiting threads (or processes), n <= count are awakened; * the semaphore value is incremented by count - n. * * RESULTS * 0 successfully posted semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore * or count is less than or equal to zero. * ERANGE semaphore count is too big * * ------------------------------------------------------ */ { int result = 0; long waiters; sem_t s = *sem; if (s == NULL || count <= 0) { result = EINVAL; } else if ((result = pthread_mutex_lock (&s->lock)) == 0) { /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); result = EINVAL; return -1; } if (s->value <= (SEM_VALUE_MAX - count)) { waiters = -s->value; s->value += count; if (waiters > 0) { #ifdef NEED_SEM if (SetEvent(s->sem)) { waiters--; s->leftToUnblock += count - 1; if (s->leftToUnblock > waiters) { s->leftToUnblock = waiters; } } #else if (ReleaseSemaphore (s->sem, (waiters<=count)?waiters:count, 0)) { /* No action */ } #endif else { s->value -= count; result = EINVAL; } } } else { result = ERANGE; } (void) pthread_mutex_unlock (&s->lock); } if (result != 0) { errno = result; return -1; } return 0; } /* sem_post_multiple */ nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_getpshared.c0000644000175000000620000000650711512143043023356 0ustar stevestaff/* * pthread_mutexattr_getpshared.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Determine whether mutexes created with 'attr' can be * shared between processes. * * PARAMETERS * attr * pointer to an instance of pthread_mutexattr_t * * pshared * will be set to one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * * DESCRIPTION * Mutexes creatd with 'attr' can be shared between * processes if pthread_mutex_t variable is allocated * in memory shared by these processes. * NOTES: * 1) pshared mutexes MUST be allocated in shared * memory. * 2) The following macro is defined if shared mutexes * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully retrieved attribute, * EINVAL 'attr' is invalid, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && (pshared != NULL)) { *pshared = (*attr)->pshared; result = 0; } else { result = EINVAL; } return (result); } /* pthread_mutexattr_getpshared */ nyquist-3.05/liblo/pthreads.2/cancel.c0000644000175000000620000000330011512143043016615 0ustar stevestaff/* * cancel.c * * Description: * POSIX thread functions related to thread cancellation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_setcancelstate.c" #include "pthread_setcanceltype.c" #include "pthread_testcancel.c" #include "pthread_cancel.c" nyquist-3.05/liblo/pthreads.2/pthread_mutex_lock.c0000644000175000000620000000717711512143043021271 0ustar stevestaff/* * pthread_mutex_lock.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef _UWIN //# include #endif #include "pthread.h" #include "implement.h" int pthread_mutex_lock (pthread_mutex_t * mutex) { int result = 0; pthread_mutex_t mx; /* * Let the system deal with invalid pointers. */ if (*mutex == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static mutex. We check * again inside the guarded section of ptw32_mutex_check_need_init() * to avoid race conditions. */ if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { if ((result = ptw32_mutex_check_need_init (mutex)) != 0) { return (result); } } mx = *mutex; if (mx->kind == PTHREAD_MUTEX_NORMAL) { if ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) 1) != 0) { while ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) -1) != 0) { if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) { result = EINVAL; break; } } } } else { pthread_t self = pthread_self(); if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, (PTW32_INTERLOCKED_LONG) 1, (PTW32_INTERLOCKED_LONG) 0) == 0) { mx->recursive_count = 1; mx->ownerThread = self; } else { if (pthread_equal (mx->ownerThread, self)) { if (mx->kind == PTHREAD_MUTEX_RECURSIVE) { mx->recursive_count++; } else { result = EDEADLK; } } else { while ((LONG) PTW32_INTERLOCKED_EXCHANGE( (LPLONG) &mx->lock_idx, (LONG) -1) != 0) { if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) { result = EINVAL; break; } } if (0 == result) { mx->recursive_count = 1; mx->ownerThread = self; } } } } return (result); } nyquist-3.05/liblo/pthreads.2/pthread.suo0000644000175000000620000002300011512143043017402 0ustar stevestaffࡱ>   Root Entry1ProjInfoExTaskListUserTasks$DebuggerWatches  )478%&'(*+,-./012356>9:;=E?@DBCFGyjkD+}ϫC DC:\Users\rbd\pthreads\pthreads.2\C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDEDebuggerBreakpoints( PDebuggerExceptions&DebuggerFindSource&&DebuggerFindSymbol&\vc7\atlmfcC:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\vc7\crt 8}r |rͫ4V`ͫ4MultiStartupProj=;4{A02E8DebuggerMemoryWindows, TExternalFilesProjectContents:$DocumentWindowPositions0 DocumentWindowUserData. 4SolutionConfiguration, 0ObjMgrContentsV8"ClassViewContents$ProjExplorerState$8EC5-317C-42CD-9425-60BDDE09D833}.dwStartupOpt=;StartupProject=&{A02E8EC5-317C-42CD-9425-60BDDE09D833};?{A02E8EC5-317C-42CD-9425-60BDDE09D833}.Debug|Win32.BatchBldCtx= Debug|Win32;={A02E8EC5-317C-42CD-9425-60BDDE09D833}.Debug|Win32.fBatchBld=;A{A02E8EC5-317C-42CD-9425-6Q `C:\Users\rbd\pthreads\pthreads.2\pthread.vcproj`C:\Users\rbd\pthreads\pthreads.2\pthread.vcprojHeader FilesResourcc:\program files\microsof$Bookmarks V001.01UnloadedProjects"HiddenSlnFolders"OutliningStateDir$BookmarkState(TaskListShortcuts$ VsToolboxService" !OutliningState3 "XmlPackageOptions$#X 7 `c:\users\rbd\pthreads\pthreads.2\ptw32_relmillisecs.c<open> c:\program files\microsoft visual studio 9.0\vc\include\sys\timeb.h<open> udio 9.0\vc\include\sy>{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|<MiscFiles>|c:\program files\microsoft visual studio 9.0\vc\include\sys\timeb.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22} 8}r |r"{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|<MiscFiles>|c:\users\rbd\pthreads\pthreads.2\ptw32_relmillisecs.c||{8B382828-6202-11D1-8870-0000F87579D2}1234-6202-11D1-0BDDE09D833}.Release|Win32.BatchBldCtx= Release|Win32;?{A02E8EC5-317C-42CD-9425-60BDDE09D833e FilesSource Filest visual studio 9.0\vc\include\sys\timeb.hlc:\users\rbd\pthreads\pthreads.2\ptw32_relmillisecs.clc:\users\rbd\pthreads\pthreads.2\ptw32_relmillisecs.cX}.Release|Win32.fBatchBld=;4{A2FE74E1-B743-11D0-AE1A-00A0C9OutliningState1 <0OutliningState2 A0FFFC3}.dwStartupOpt=; Actic:\program files\microsoft visual studio 9.0\vc\include\sys\timeb.hˇ  veCfg= Release|Win32;,32# $%)*69:;?IO]^d4/xqwnyquist-3.05/liblo/pthreads.2/ptw32_tkAssocDestroy.c0000644000175000000620000000657611512143043021432 0ustar stevestaff/* * ptw32_tkAssocDestroy.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc) /* * ------------------------------------------------------------------- * This routine releases all resources for the given ThreadKeyAssoc * once it is no longer being referenced * ie) either the key or thread has stopped referencing it. * * Parameters: * assoc * an instance of ThreadKeyAssoc. * Returns: * N/A * ------------------------------------------------------------------- */ { /* * Both key->keyLock and thread->threadLock are locked on * entry to this routine. */ if (assoc != NULL) { ThreadKeyAssoc * prev, * next; /* Remove assoc from thread's keys chain */ prev = assoc->prevKey; next = assoc->nextKey; if (prev != NULL) { prev->nextKey = next; } if (next != NULL) { next->prevKey = prev; } if (assoc->thread->keys == assoc) { /* We're at the head of the thread's keys chain */ assoc->thread->keys = next; } if (assoc->thread->nextAssoc == assoc) { /* * Thread is exiting and we're deleting the assoc to be processed next. * Hand thread the assoc after this one. */ assoc->thread->nextAssoc = next; } /* Remove assoc from key's threads chain */ prev = assoc->prevThread; next = assoc->nextThread; if (prev != NULL) { prev->nextThread = next; } if (next != NULL) { next->prevThread = prev; } if (assoc->key->threads == assoc) { /* We're at the head of the key's threads chain */ assoc->key->threads = next; } free (assoc); } } /* ptw32_tkAssocDestroy */ nyquist-3.05/liblo/pthreads.2/MAINTAINERS0000644000175000000620000000014311512143043016723 0ustar stevestaffCVS Repository maintainers Ross Johnson rpj@ise.canberra.edu.au Ben Elliston bje@cygnus.com nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_getkind_np.c0000644000175000000620000000333111512143043023342 0ustar stevestaff/* * pthread_mutexattr_getkind_np.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_getkind_np (pthread_mutexattr_t * attr, int *kind) { return pthread_mutexattr_gettype (attr, kind); } nyquist-3.05/liblo/pthreads.2/pthread_setcanceltype.c0000644000175000000620000001011511512143043021744 0ustar stevestaff/* * pthread_setcanceltype.c * * Description: * POSIX thread functions related to thread cancellation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_setcanceltype (int type, int *oldtype) /* * ------------------------------------------------------ * DOCPUBLIC * This function atomically sets the calling thread's * cancelability type to 'type' and returns the previous * cancelability type at the location referenced by * 'oldtype' * * PARAMETERS * type, * oldtype * PTHREAD_CANCEL_DEFERRED * only deferred cancelation is allowed, * * PTHREAD_CANCEL_ASYNCHRONOUS * Asynchronous cancellation is allowed * * * DESCRIPTION * This function atomically sets the calling thread's * cancelability type to 'type' and returns the previous * cancelability type at the location referenced by * 'oldtype' * * NOTES: * 1) Use with caution; most code is not safe for use * with asynchronous cancelability. * * COMPATIBILITY ADDITIONS * If 'oldtype' is NULL then the previous type is not returned * but the function still succeeds. (Solaris) * * RESULTS * 0 successfully set cancelability type, * EINVAL 'type' is invalid * * ------------------------------------------------------ */ { int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL || (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)) { return EINVAL; } /* * Lock for async-cancel safety. */ (void) pthread_mutex_lock (&sp->cancelLock); if (oldtype != NULL) { *oldtype = sp->cancelType; } sp->cancelType = type; /* * Check if there is a pending asynchronous cancel */ if (sp->cancelState == PTHREAD_CANCEL_ENABLE && type == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } (void) pthread_mutex_unlock (&sp->cancelLock); return (result); } /* pthread_setcanceltype */ nyquist-3.05/liblo/pthreads.2/ptw32_InterlockedCompareExchange.c0000644000175000000620000002077011512143043023656 0ustar stevestaff/* * ptw32_InterlockedCompareExchange.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * ptw32_InterlockedCompareExchange -- * * Originally needed because W9x doesn't support InterlockedCompareExchange. * We now use this version wherever possible so we can inline it. */ PTW32_INTERLOCKED_LONG WINAPI ptw32_InterlockedCompareExchange (PTW32_INTERLOCKED_LPLONG location, PTW32_INTERLOCKED_LONG value, PTW32_INTERLOCKED_LONG comparand) { #if defined(__WATCOMC__) /* Don't report that result is not assigned a value before being referenced */ #pragma disable_message (200) #endif PTW32_INTERLOCKED_LONG result; /* * Using the LOCK prefix on uni-processor machines is significantly slower * and it is not necessary. The overhead of the conditional below is * negligible in comparison. Since an optimised DLL will inline this * routine, this will be faster than calling the system supplied * Interlocked routine, which appears to avoid the LOCK prefix on * uniprocessor systems. So one DLL works for all systems. */ if (ptw32_smp_system) /* *INDENT-OFF* */ #if defined(_M_IX86) || defined(_X86_) #if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && defined(HAVE_TASM32)) #define HAVE_INLINABLE_INTERLOCKED_CMPXCHG { _asm { PUSH ecx PUSH edx MOV ecx,dword ptr [location] MOV edx,dword ptr [value] MOV eax,dword ptr [comparand] LOCK CMPXCHG dword ptr [ecx],edx MOV dword ptr [result], eax POP edx POP ecx } } else { _asm { PUSH ecx PUSH edx MOV ecx,dword ptr [location] MOV edx,dword ptr [value] MOV eax,dword ptr [comparand] CMPXCHG dword ptr [ecx],edx MOV dword ptr [result], eax POP edx POP ecx } } #elif defined(__GNUC__) #define HAVE_INLINABLE_INTERLOCKED_CMPXCHG { __asm__ __volatile__ ( "lock\n\t" "cmpxchgl %2,%1" /* if (EAX == [location]) */ /* [location] = value */ /* else */ /* EAX = [location] */ :"=a" (result) :"m" (*location), "r" (value), "a" (comparand)); } else { __asm__ __volatile__ ( "cmpxchgl %2,%1" /* if (EAX == [location]) */ /* [location] = value */ /* else */ /* EAX = [location] */ :"=a" (result) :"m" (*location), "r" (value), "a" (comparand)); } #endif #else /* * If execution gets to here then we're running on a currently * unsupported processor or compiler. */ result = 0; #endif /* *INDENT-ON* */ return result; #if defined(__WATCOMC__) #pragma enable_message (200) #endif } /* * ptw32_InterlockedExchange -- * * We now use this version wherever possible so we can inline it. */ LONG WINAPI ptw32_InterlockedExchange (LPLONG location, LONG value) { #if defined(__WATCOMC__) /* Don't report that result is not assigned a value before being referenced */ #pragma disable_message (200) #endif LONG result; /* * The XCHG instruction always locks the bus with or without the * LOCKED prefix. This makes it significantly slower than CMPXCHG on * uni-processor machines. The Windows InterlockedExchange function * is nearly 3 times faster than the XCHG instruction, so this routine * is not yet very useful for speeding up pthreads. */ if (ptw32_smp_system) /* *INDENT-OFF* */ #if defined(_M_IX86) || defined(_X86_) #if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && defined(HAVE_TASM32)) #define HAVE_INLINABLE_INTERLOCKED_XCHG { _asm { PUSH ecx MOV ecx,dword ptr [location] MOV eax,dword ptr [value] XCHG dword ptr [ecx],eax MOV dword ptr [result], eax POP ecx } } else { /* * Faster version of XCHG for uni-processor systems because * it doesn't lock the bus. If an interrupt or context switch * occurs between the MOV and the CMPXCHG then the value in * 'location' may have changed, in which case we will loop * back to do the MOV again. * * FIXME! Need memory barriers for the MOV+CMPXCHG combo? * * Tests show that this routine has almost identical timing * to Win32's InterlockedExchange(), which is much faster than * using the inlined 'xchg' instruction above, so it's probably * doing something similar to this (on UP systems). * * Can we do without the PUSH/POP instructions? */ _asm { PUSH ecx PUSH edx MOV ecx,dword ptr [location] MOV edx,dword ptr [value] L1: MOV eax,dword ptr [ecx] CMPXCHG dword ptr [ecx],edx JNZ L1 MOV dword ptr [result], eax POP edx POP ecx } } #elif defined(__GNUC__) #define HAVE_INLINABLE_INTERLOCKED_XCHG { __asm__ __volatile__ ( "xchgl %2,%1" :"=r" (result) :"m" (*location), "0" (value)); } else { /* * Faster version of XCHG for uni-processor systems because * it doesn't lock the bus. If an interrupt or context switch * occurs between the movl and the cmpxchgl then the value in * 'location' may have changed, in which case we will loop * back to do the movl again. * * FIXME! Need memory barriers for the MOV+CMPXCHG combo? * * Tests show that this routine has almost identical timing * to Win32's InterlockedExchange(), which is much faster than * using the an inlined 'xchg' instruction, so it's probably * doing something similar to this (on UP systems). */ __asm__ __volatile__ ( "0:\n\t" "movl %1,%%eax\n\t" "cmpxchgl %2,%1\n\t" "jnz 0b" :"=&a" (result) :"m" (*location), "r" (value)); } #endif #else /* * If execution gets to here then we're running on a currently * unsupported processor or compiler. */ result = 0; #endif /* *INDENT-ON* */ return result; #if defined(__WATCOMC__) #pragma enable_message (200) #endif } #if 1 #if defined(PTW32_BUILD_INLINED) && defined(HAVE_INLINABLE_INTERLOCKED_CMPXCHG) #undef PTW32_INTERLOCKED_COMPARE_EXCHANGE #define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_InterlockedCompareExchange #endif #if defined(PTW32_BUILD_INLINED) && defined(HAVE_INLINABLE_INTERLOCKED_XCHG) #undef PTW32_INTERLOCKED_EXCHANGE #define PTW32_INTERLOCKED_EXCHANGE ptw32_InterlockedExchange #endif #endif nyquist-3.05/liblo/pthreads.2/implement.h0000644000175000000620000005221711512143043017402 0ustar stevestaff/* * implement.h * * Definitions that don't need to be public. * * Keeps all the internals out of pthread.h * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef _IMPLEMENT_H #define _IMPLEMENT_H #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT 0x400 #include /* * In case windows.h doesn't define it (e.g. WinCE perhaps) */ #ifdef WINCE typedef VOID (APIENTRY *PAPCFUNC)(DWORD dwParam); #endif /* * note: ETIMEDOUT is correctly defined in winsock.h */ #include /* * In case ETIMEDOUT hasn't been defined above somehow. */ #ifndef ETIMEDOUT # define ETIMEDOUT 10060 /* This is the value in winsock.h. */ #endif #if !defined(malloc) #include #endif #if !defined(INT_MAX) #include #endif /* use local include files during development */ #include "semaphore.h" #include "sched.h" #if defined(HAVE_C_INLINE) || defined(__cplusplus) #define INLINE inline #else #define INLINE #endif #if defined (__MINGW32__) || (_MSC_VER >= 1300) #define PTW32_INTERLOCKED_LONG long #define PTW32_INTERLOCKED_LPLONG long* #else #define PTW32_INTERLOCKED_LONG PVOID #define PTW32_INTERLOCKED_LPLONG PVOID* #endif #if defined(__MINGW32__) #include #elif defined(__BORLANDC__) #define int64_t ULONGLONG #else #define int64_t _int64 #endif typedef enum { /* * This enumeration represents the state of the thread; * The thread is still "alive" if the numeric value of the * state is greater or equal "PThreadStateRunning". */ PThreadStateInitial = 0, /* Thread not running */ PThreadStateRunning, /* Thread alive & kicking */ PThreadStateSuspended, /* Thread alive but suspended */ PThreadStateCancelPending, /* Thread alive but is */ /* has cancelation pending. */ PThreadStateCanceling, /* Thread alive but is */ /* in the process of terminating */ /* due to a cancellation request */ PThreadStateException, /* Thread alive but exiting */ /* due to an exception */ PThreadStateLast } PThreadState; typedef struct ptw32_thread_t_ ptw32_thread_t; struct ptw32_thread_t_ { #ifdef _UWIN DWORD dummy[5]; #endif DWORD thread; HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */ pthread_t ptHandle; /* This thread's permanent pthread_t handle */ ptw32_thread_t * prevReuse; /* Links threads on reuse stack */ volatile PThreadState state; void *exitStatus; void *parms; int ptErrno; int detachState; pthread_mutex_t threadLock; /* Used for serialised access to public thread state */ int sched_priority; /* As set, not as currently is */ pthread_mutex_t cancelLock; /* Used for async-cancel safety */ int cancelState; int cancelType; HANDLE cancelEvent; #ifdef __CLEANUP_C jmp_buf start_mark; #endif /* __CLEANUP_C */ #if HAVE_SIGSET_T sigset_t sigmask; #endif /* HAVE_SIGSET_T */ int implicit:1; void *keys; void *nextAssoc; }; /* * Special value to mark attribute objects as valid. */ #define PTW32_ATTR_VALID ((unsigned long) 0xC4C0FFEE) struct pthread_attr_t_ { unsigned long valid; void *stackaddr; size_t stacksize; int detachstate; struct sched_param param; int inheritsched; int contentionscope; #if HAVE_SIGSET_T sigset_t sigmask; #endif /* HAVE_SIGSET_T */ }; /* * ==================== * ==================== * Semaphores, Mutexes and Condition Variables * ==================== * ==================== */ struct sem_t_ { int value; pthread_mutex_t lock; HANDLE sem; #ifdef NEED_SEM int leftToUnblock; #endif }; #define PTW32_OBJECT_AUTO_INIT ((void *) -1) #define PTW32_OBJECT_INVALID NULL struct pthread_mutex_t_ { LONG lock_idx; /* Provides exclusive access to mutex state via the Interlocked* mechanism. 0: unlocked/free. 1: locked - no other waiters. -1: locked - with possible other waiters. */ int recursive_count; /* Number of unlocks a thread needs to perform before the lock is released (recursive mutexes only). */ int kind; /* Mutex type. */ pthread_t ownerThread; HANDLE event; /* Mutex release notification to waiting threads. */ }; struct pthread_mutexattr_t_ { int pshared; int kind; }; /* * Possible values, other than PTW32_OBJECT_INVALID, * for the "interlock" element in a spinlock. * * In this implementation, when a spinlock is initialised, * the number of cpus available to the process is checked. * If there is only one cpu then "interlock" is set equal to * PTW32_SPIN_USE_MUTEX and u.mutex is a initialised mutex. * If the number of cpus is greater than 1 then "interlock" * is set equal to PTW32_SPIN_UNLOCKED and the number is * stored in u.cpus. This arrangement allows the spinlock * routines to attempt an InterlockedCompareExchange on "interlock" * immediately and, if that fails, to try the inferior mutex. * * "u.cpus" isn't used for anything yet, but could be used at * some point to optimise spinlock behaviour. */ #define PTW32_SPIN_UNLOCKED (1) #define PTW32_SPIN_LOCKED (2) #define PTW32_SPIN_USE_MUTEX (3) struct pthread_spinlock_t_ { long interlock; /* Locking element for multi-cpus. */ union { int cpus; /* No. of cpus if multi cpus, or */ pthread_mutex_t mutex; /* mutex if single cpu. */ } u; }; struct pthread_barrier_t_ { unsigned int nCurrentBarrierHeight; unsigned int nInitialBarrierHeight; int iStep; int pshared; sem_t semBarrierBreeched[2]; }; struct pthread_barrierattr_t_ { int pshared; }; struct pthread_key_t_ { DWORD key; void (*destructor) (void *); pthread_mutex_t keyLock; void *threads; }; typedef struct ThreadParms ThreadParms; typedef struct ThreadKeyAssoc ThreadKeyAssoc; struct ThreadParms { pthread_t tid; void *(*start) (void *); void *arg; }; struct pthread_cond_t_ { long nWaitersBlocked; /* Number of threads blocked */ long nWaitersGone; /* Number of threads timed out */ long nWaitersToUnblock; /* Number of threads to unblock */ sem_t semBlockQueue; /* Queue up threads waiting for the */ /* condition to become signalled */ sem_t semBlockLock; /* Semaphore that guards access to */ /* | waiters blocked count/block queue */ /* +-> Mandatory Sync.LEVEL-1 */ pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */ /* | waiters (to)unblock(ed) counts */ /* +-> Optional* Sync.LEVEL-2 */ pthread_cond_t next; /* Doubly linked list */ pthread_cond_t prev; }; struct pthread_condattr_t_ { int pshared; }; #define PTW32_RWLOCK_MAGIC 0xfacade2 struct pthread_rwlock_t_ { pthread_mutex_t mtxExclusiveAccess; pthread_mutex_t mtxSharedAccessCompleted; pthread_cond_t cndSharedAccessCompleted; int nSharedAccessCount; int nExclusiveAccessCount; int nCompletedSharedAccessCount; int nMagic; }; struct pthread_rwlockattr_t_ { int pshared; }; /* * MCS lock queue node - see ptw32_MCS_lock.c */ struct ptw32_mcs_node_t_ { struct ptw32_mcs_node_t_ **lock; /* ptr to tail of queue */ struct ptw32_mcs_node_t_ *next; /* ptr to successor in queue */ LONG readyFlag; /* set after lock is released by predecessor */ LONG nextFlag; /* set after 'next' ptr is set by successor */ }; typedef struct ptw32_mcs_node_t_ ptw32_mcs_local_node_t; typedef struct ptw32_mcs_node_t_ *ptw32_mcs_lock_t; struct ThreadKeyAssoc { /* * Purpose: * This structure creates an association between a thread and a key. * It is used to implement the implicit invocation of a user defined * destroy routine for thread specific data registered by a user upon * exiting a thread. * * Graphically, the arrangement is as follows, where: * * K - Key with destructor * (head of chain is key->threads) * T - Thread that has called pthread_setspecific(Kn) * (head of chain is thread->keys) * A - Association. Each association is a node at the * intersection of two doubly-linked lists. * * T1 T2 T3 * | | | * | | | * K1 -----+-----A-----A-----> * | | | * | | | * K2 -----A-----A-----+-----> * | | | * | | | * K3 -----A-----+-----A-----> * | | | * | | | * V V V * * Access to the association is guarded by two locks: the key's * general lock (guarding the row) and the thread's general * lock (guarding the column). This avoids the need for a * dedicated lock for each association, which not only consumes * more handles but requires that: before the lock handle can * be released - both the key must be deleted and the thread * must have called the destructor. The two-lock arrangement * allows the resources to be freed as soon as either thread or * key is concluded. * * To avoid deadlock: whenever both locks are required, the key * and thread locks are always acquired in the order: key lock * then thread lock. An exception to this exists when a thread * calls the destructors, however this is done carefully to * avoid deadlock. * * An association is created when a thread first calls * pthread_setspecific() on a key that has a specified * destructor. * * An association is destroyed either immediately after the * thread calls the key destructor function on thread exit, or * when the key is deleted. * * Attributes: * thread * reference to the thread that owns the * association. This is actually the pointer to the * thread struct itself. Since the association is * destroyed before the thread exits, this can never * point to a different logical thread to the one that * created the assoc, i.e. after thread struct reuse. * * key * reference to the key that owns the association. * * nextKey * The pthread_t->keys attribute is the head of a * chain of associations that runs through the nextKey * link. This chain provides the 1 to many relationship * between a pthread_t and all pthread_key_t on which * it called pthread_setspecific. * * prevKey * Similarly. * * nextThread * The pthread_key_t->threads attribute is the head of * a chain of assoctiations that runs through the * nextThreads link. This chain provides the 1 to many * relationship between a pthread_key_t and all the * PThreads that have called pthread_setspecific for * this pthread_key_t. * * prevThread * Similarly. * * Notes: * 1) As soon as either the key or the thread is no longer * referencing the association, it can be destroyed. The * association will be removed from both chains. * * 2) Under WIN32, an association is only created by * pthread_setspecific if the user provided a * destroyRoutine when they created the key. * * */ ptw32_thread_t * thread; pthread_key_t key; ThreadKeyAssoc *nextKey; ThreadKeyAssoc *nextThread; ThreadKeyAssoc *prevKey; ThreadKeyAssoc *prevThread; }; #ifdef __CLEANUP_SEH /* * -------------------------------------------------------------- * MAKE_SOFTWARE_EXCEPTION * This macro constructs a software exception code following * the same format as the standard Win32 error codes as defined * in WINERROR.H * Values are 32 bit values layed out as follows: * * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +---+-+-+-----------------------+-------------------------------+ * |Sev|C|R| Facility | Code | * +---+-+-+-----------------------+-------------------------------+ * * Severity Values: */ #define SE_SUCCESS 0x00 #define SE_INFORMATION 0x01 #define SE_WARNING 0x02 #define SE_ERROR 0x03 #define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \ ( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \ ( 1 << 29 ) | /* MS=0, User=1 */ \ ( 0 << 28 ) | /* Reserved */ \ ( (_facility) << 16 ) | /* Facility Code */ \ ( (_exception) << 0 ) /* Exception Code */ \ ) ) /* * We choose one specific Facility/Error code combination to * identify our software exceptions vs. WIN32 exceptions. * We store our actual component and error code within * the optional information array. */ #define EXCEPTION_PTW32_SERVICES \ MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \ PTW32_SERVICES_FACILITY, \ PTW32_SERVICES_ERROR ) #define PTW32_SERVICES_FACILITY 0xBAD #define PTW32_SERVICES_ERROR 0xDEED #endif /* __CLEANUP_SEH */ /* * Services available through EXCEPTION_PTW32_SERVICES * and also used [as parameters to ptw32_throw()] as * generic exception selectors. */ #define PTW32_EPS_EXIT (1) #define PTW32_EPS_CANCEL (2) /* Useful macros */ #define PTW32_MAX(a,b) ((a)<(b)?(b):(a)) #define PTW32_MIN(a,b) ((a)>(b)?(b):(a)) /* Declared in global.c */ extern PTW32_INTERLOCKED_LONG (WINAPI * ptw32_interlocked_compare_exchange) (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG); /* Declared in pthread_cancel.c */ extern DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD); /* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */ #define PTW32_THREAD_REUSE_EMPTY ((ptw32_thread_t *) 1) extern int ptw32_processInitialized; extern ptw32_thread_t * ptw32_threadReuseTop; extern ptw32_thread_t * ptw32_threadReuseBottom; extern pthread_key_t ptw32_selfThreadKey; extern pthread_key_t ptw32_cleanupKey; extern pthread_cond_t ptw32_cond_list_head; extern pthread_cond_t ptw32_cond_list_tail; extern int ptw32_mutex_default_kind; extern int ptw32_concurrency; extern int ptw32_features; extern BOOL ptw32_smp_system; /* True: SMP system, False: Uni-processor system */ extern CRITICAL_SECTION ptw32_thread_reuse_lock; extern CRITICAL_SECTION ptw32_mutex_test_init_lock; extern CRITICAL_SECTION ptw32_cond_list_lock; extern CRITICAL_SECTION ptw32_cond_test_init_lock; extern CRITICAL_SECTION ptw32_rwlock_test_init_lock; extern CRITICAL_SECTION ptw32_spinlock_test_init_lock; #ifdef _UWIN extern int pthread_count; #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * ===================== * ===================== * Forward Declarations * ===================== * ===================== */ int ptw32_is_attr (const pthread_attr_t * attr); int ptw32_cond_check_need_init (pthread_cond_t * cond); int ptw32_mutex_check_need_init (pthread_mutex_t * mutex); int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock); PTW32_INTERLOCKED_LONG WINAPI ptw32_InterlockedCompareExchange (PTW32_INTERLOCKED_LPLONG location, PTW32_INTERLOCKED_LONG value, PTW32_INTERLOCKED_LONG comparand); LONG WINAPI ptw32_InterlockedExchange (LPLONG location, LONG value); DWORD ptw32_RegisterCancelation (PAPCFUNC callback, HANDLE threadH, DWORD callback_arg); int ptw32_processInitialize (void); void ptw32_processTerminate (void); void ptw32_threadDestroy (pthread_t tid); void ptw32_pop_cleanup_all (int execute); pthread_t ptw32_new (void); pthread_t ptw32_threadReusePop (void); void ptw32_threadReusePush (pthread_t thread); int ptw32_getprocessors (int *count); int ptw32_setthreadpriority (pthread_t thread, int policy, int priority); void ptw32_rwlock_cancelwrwait (void *arg); #if ! defined (__MINGW32__) || defined (__MSVCRT__) unsigned __stdcall #else void #endif ptw32_threadStart (void *vthreadParms); void ptw32_callUserDestroyRoutines (pthread_t thread); int ptw32_tkAssocCreate (ptw32_thread_t * thread, pthread_key_t key); void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc); int ptw32_semwait (sem_t * sem); DWORD ptw32_relmillisecs (const struct timespec * abstime); void ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); void ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node); #ifdef NEED_FTIME void ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft); void ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts); #endif /* Declared in misc.c */ #ifdef NEED_CALLOC #define calloc(n, s) ptw32_calloc(n, s) void *ptw32_calloc (size_t n, size_t s); #endif /* Declared in private.c */ void ptw32_throw (DWORD exception); #ifdef __cplusplus } #endif /* __cplusplus */ #ifdef _UWIN_ # ifdef _MT # ifdef __cplusplus extern "C" { # endif _CRTIMP unsigned long __cdecl _beginthread (void (__cdecl *) (void *), unsigned, void *); _CRTIMP void __cdecl _endthread (void); _CRTIMP unsigned long __cdecl _beginthreadex (void *, unsigned, unsigned (__stdcall *) (void *), void *, unsigned, unsigned *); _CRTIMP void __cdecl _endthreadex (unsigned); # ifdef __cplusplus } # endif # endif #else # include #endif /* * Defaults. Could be overridden when building the inlined version of the dll. * See ptw32_InterlockedCompareExchange.c */ #ifndef PTW32_INTERLOCKED_COMPARE_EXCHANGE #define PTW32_INTERLOCKED_COMPARE_EXCHANGE ptw32_interlocked_compare_exchange #endif #ifndef PTW32_INTERLOCKED_EXCHANGE #define PTW32_INTERLOCKED_EXCHANGE InterlockedExchange #endif /* * Check for old and new versions of cygwin. See the FAQ file: * * Question 1 - How do I get pthreads-win32 to link under Cygwin or Mingw32? * * Patch by Anders Norlander */ #if defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(NEED_CREATETHREAD) /* * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE * in order to avoid warnings because of return type */ #define _beginthreadex(security, \ stack_size, \ start_proc, \ arg, \ flags, \ pid) \ CreateThread(security, \ stack_size, \ (LPTHREAD_START_ROUTINE) start_proc, \ arg, \ flags, \ pid) #define _endthreadex ExitThread #endif /* __CYGWIN32__ || __CYGWIN__ || NEED_CREATETHREAD */ #endif /* _IMPLEMENT_H */ nyquist-3.05/liblo/pthreads.2/pthread_rwlock_init.c0000644000175000000620000000553411512143043021436 0ustar stevestaff/* * pthread_rwlock_init.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_init (pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attr) { int result; pthread_rwlock_t rwl = 0; if (rwlock == NULL) { return EINVAL; } if (attr != NULL && *attr != NULL) { result = EINVAL; /* Not supported */ goto DONE; } rwl = (pthread_rwlock_t) calloc (1, sizeof (*rwl)); if (rwl == NULL) { result = ENOMEM; goto DONE; } rwl->nSharedAccessCount = 0; rwl->nExclusiveAccessCount = 0; rwl->nCompletedSharedAccessCount = 0; result = pthread_mutex_init (&rwl->mtxExclusiveAccess, NULL); if (result != 0) { goto FAIL0; } result = pthread_mutex_init (&rwl->mtxSharedAccessCompleted, NULL); if (result != 0) { goto FAIL1; } result = pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL); if (result != 0) { goto FAIL2; } rwl->nMagic = PTW32_RWLOCK_MAGIC; result = 0; goto DONE; FAIL2: (void) pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); FAIL1: (void) pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); FAIL0: (void) free (rwl); rwl = NULL; DONE: *rwlock = rwl; return result; } nyquist-3.05/liblo/pthreads.2/ChangeLog0000644000175000000620000055106511512143043017016 0ustar stevestaff2006-12-20 Ross Johnson * sem_destroy.c: Fix the race involving invalidation of the sema; fix incorrect return of EBUSY resulting from the mutex trylock on the private mutex guard. * sem_wait.c: Add check for invalid sem_t after acquiring the sem_t state guard mutex and before affecting changes to sema state. * sem_trywait.c: Likewise. * sem_timedwait.c: Likewise. * sem_getvalue.c: Likewise. * sem_post.c: Similar. * sem_post_multiple.c: Likewise. * sem_init.c: Set max Win32 semaphore count to SEM_VALUE_MAX (was _POSIX_SEM_VALUE_MAX, which is a lower value - the minimum). * pthread_win32_attach_detach_np.c (pthread_win32_process_attach_np): Load COREDLL.DLL under WINCE to check existence of InterlockedCompareExchange() routine. This used to be done to test for TryEnterCriticalSection() but was removed when this was no longer needed. 2006-01-25 Prashant Thakre * pthread_cancel.c: Added _M_IA64 register context support. 2005-05-13 Ross Johnson * pthread_kill.c (pthread_kill): Remove check for Win32 thread priority (to confirm HANDLE validity). Useless since thread HANDLEs a not recycle-unique. 2005-05-30 Vladimir Kliatchko * pthread_once.c: Re-implement using an MCS queue-based lock. The form of pthread_once is as proposed by Alexander Terekhov (see entry of 2005-03-13). The MCS lock implementation does not require a unique 'name' to identify the lock between threads. Attempts to get the Event or Semaphore based versions of pthread_once to a satisfactory level of robustness have thus far failed. The last problem (avoiding races involving non recycle-unique Win32 HANDLEs) was giving everyone grey hair trying to solve it. * ptw32_MCS_lock.c: New MCS queue-based lock implementation. These locks are efficient: they have very low overhead in the uncontended case; are efficient in contention and minimise cache-coherence updates in managing the user level FIFO queue; do not require an ABI change in the library. 2005-05-27 Alexander Gottwald * pthread.h: Some things, like HANDLE, were only defined if PTW32_LEVEL was >= 3. They should always be defined. 2005-05-25 Vladimir Kliatchko * pthread_once.c: Eliminate all priority operations and other complexity by replacing the event with a semaphore. The advantage of the change is the ability to release just one waiter if the init_routine thread is cancelled yet still release all waiters when done. Simplify once_control state checks to improve efficiency further. 2005-05-24 Mikael Magnusson * GNUmakefile: Patched to allow cross-compile with mingw32 on Linux. It uses macros instead of referencing dlltool, gcc and g++ directly; added a call to ranlib. For example the GC static library can be built with: make CC=i586-mingw32msvc-gcc RC=i586-mingw32msvc-windres \ RANLIB=i586-mingw32msvc-ranlib clean GC-static 2005-05-13 Ross Johnson * pthread_win32_attach_detach_np.c (pthread_win32_thread_detach_np): Move on-exit-only stuff from ptw32_threadDestroy() to here. * ptw32_threadDestroy.c: It's purpose is now only to reclaim thread resources for detached threads, or via pthread_join() or pthread_detach() on joinable threads. * ptw32_threadStart.c: Calling user destruct routines has moved to pthread_win32_thread_detach_np(); call pthread_win32_thread_detach_np() directly if statically linking, otherwise do so via dllMain; store thread return value in thread struct for all cases, including cancellation and exception exits; thread abnormal exits go via pthread_win32_thread_detach_np. * pthread_join.c (pthread_join): Don't try to get return code from Win32 thread - always get it from he thread struct. * pthread_detach.c (pthread_detach): reduce extent of the thread existence check since we now don't care if the Win32 thread HANDLE has been closed; reclaim thread resources if the thread has exited already. * ptw32_throw.c (ptw32_throw): For Win32 threads that are not implicit, only Call thread cleanup if statically linking, otherwise leave it to dllMain. * sem_post.c (_POSIX_SEM_VALUE_MAX): Change to SEM_VALUE_MAX. * sem_post_multiple.c: Likewise. * sem_init.c: Likewise. 2005-05-10 Ross Johnson * pthread_join.c (pthread_join): Add missing check for thread ID reference count in thread existence test; reduce extent of the existence test since we don't care if the Win32 thread HANDLE has been closed. 2005-05-09 Ross Johnson * ptw32_callUserDestroyRoutines.c: Run destructor process (i.e. loop over all keys calling destructors) up to PTHREAD_DESTRUCTOR_ITERATIONS times if TSD value isn't NULL yet; modify assoc management. * pthread_key_delete.c: Modify assoc management. * ptw32_tkAssocDestroy.c: Fix error in assoc removal from chains. * pthread.h (_POSIX_THREAD_DESTRUCTOR_ITERATIONS): Define to value specified by POSIX. (_POSIX_THREAD_KEYS_MAX): Define to value specified by POSIX. (PTHREAD_KEYS_MAX): Redefine [upward] to minimum required by POSIX. (SEM_NSEMS_MAX): Define to implementation value. (SEM_VALUE_MAX): Define to implementation value. (_POSIX_SEM_NSEMS_MAX): Redefine to value specified by POSIX. (_POSIX_SEM_VALUE_MAX): Redefine to value specified by POSIX. 2005-05-06 Ross Johnson * signal.c (sigwait): Add a cancellation point to this otherwise no-op. * sem_init.c (sem_init): Check for and return ERANGE error. * sem_post.c (sem_post): Likewise. * sem_post_multiple.c (sem_post_multiple): Likewise. * manual (directory): Added; see ChangeLog inside. 2005-05-02 Ross Johnson * implement.h (struct pthread_key_t_): Change threadsLock to keyLock so as not to be confused with the per thread lock 'threadlock'; change all references to it. * implement.h (struct ThreadKeyAssoc): Remove lock; add prevKey and prevThread pointers; re-implemented all routines that use this struct. The effect of this is to save one handle per association, which could potentially equal the number of keys multiplied by the number of threads, accumulating over time - and to free the association memory as soon as it is no longer referenced by either the key or the thread. Previously, the handle and memory were released only after BOTH key and thread no longer referenced the association. That is, often no association resources were released until the process itself exited. In addition, at least one race condition has been removed - where two threads could attempt to release the association resources simultaneously - one via ptw32_callUserDestroyRoutines and the other via pthread_key_delete. - thanks to Richard Hughes at Aculab for discovering the problem. * pthread_key_create.c: See above. * pthread_key_delete.c: See above. * pthread_setspecific.c: See above. * ptw32_callUserDestroyRoutines.c: See above. * ptw32_tkAssocCreate.c: See above. * ptw32_tkAssocDestroy.c: See above. 2005-04-27 Ross Johnson * sem_wait.c (ptw32_sem_wait_cleanup): after cancellation re-attempt to acquire the semaphore to avoid a race with a late sem_post. * sem_timedwait.c: Modify comments. 2005-04-25 Ross Johnson * ptw32_relmillisecs.c: New module; converts future abstime to milliseconds relative to 'now'. * pthread_mutex_timedlock.c: Use new ptw32_relmillisecs routine in place of internal code; remove the NEED_SEM code - this routine is now implemented for builds that define NEED_SEM (WinCE etc) * sem_timedwait.c: Likewise; after timeout or cancellation, re-attempt to acquire the semaphore in case one has been posted since the timeout/cancel occurred. Thanks to Stefan Mueller. * Makefile: Add ptw32_relmillisecs.c module; remove ptw32_{in,de}crease_semaphore.c modules. * GNUmakefile: Likewise. * Bmakefile: Likewise. * sem_init.c: Re-write the NEED_SEM code to be consistent with the non-NEED_SEM code, but retaining use of an event in place of the w32 sema for w32 systems that don't include semaphores (WinCE); the NEED_SEM versions of semaphores has been broken for a long time but is now fixed and supports all of the same routines as the non-NEED_SEM case. * sem_destroy.c: Likewise. * sem_wait.c: Likewise. * sem_post.c: Likewise. * sem_post_multple.c: Likewise. * implement.h: Likewise. * sem_timedwait.c: Likewise; this routine is now implemented for builds that define NEED_SEM (WinCE etc). * sem_trywait.c: Likewise. * sem_getvalue.c: Likewise. * pthread_once.c: Yet more changes, reverting closer to Gottlob Frege's first design, but retaining cancellation, priority boosting, and adding preservation of W32 error codes to make pthread_once transparent to GetLastError. 2005-04-11 Ross Johnson * pthread_once.c (pthread_once): Added priority boosting to solve starvation problem after once_routine cancellation. See notes in file. 2005-04-06 Kevin Lussier * Makefile: Added debug targets for all versions of the library. 2005-04-01 Ross Johnson * GNUmakefile: Add target to build libpthreadGC1.a as a static link library. * Makefile: Likewise for pthreadGC1.lib. 2005-04-01 Kevin Lussier * sem_timedwait.c (sem_timedwait): Increase size of temp variables to avoid int overflows for large timeout values. * implement.h (int64_t): Include or define. 2005-03-31 Dimitar Panayotov ^M * pthread.h: Fix conditional defines for static linking. * sched.h: Liekwise. * semaphore.h: Likewise. * dll.c (PTW32_STATIC_LIB): Module is conditionally included in the build. 2005-03-16 Ross Johnson ^M * pthread_setcancelstate.c: Undo the last change. 2005-03-16 Ross Johnson ^M * pthread_setcancelstate.c: Don't check for an async cancel event if the library is using alertable async cancel.. 2005-03-14 Ross Johnson * pthread_once.c (pthread_once): Downgrade interlocked operations to simple memory operations where these are protected by the critical section; edit comments. 2005-03-13 Ross Johnson * pthread_once.c (pthread_once): Completely redesigned; a change was required to the ABI (pthread_once_t_), and resulting in a version compatibility index increment. NOTES: The design (based on pseudo code contributed by Gottlob Frege) avoids creating a kernel object if there is no contention. See URL for details:- http://sources.redhat.com/ml/pthreads-win32/2005/msg00029.html This uses late initialisation similar to the technique already used for pthreads-win32 mutexes and semaphores (from Alexander Terekhov). The subsequent cancelation cleanup additions (by rpj) could not be implemented without sacrificing some of the efficiency in Gottlob's design. In particular, although each once_control uses it's own event to block on, a global CS is required to manage it - since the event must be either re-usable or re-creatable under cancelation. This is not needed in the non-cancelable design because it is able to mark the event as closed (forever). When uncontested, a CS operation is equivalent to an Interlocked operation in speed. So, in the final design with cancelability, an uncontested once_control operation involves a minimum of five interlocked operations (including the LeaveCS operation). ALTERNATIVES: An alternative design from Alexander Terekhov proposed using a named mutex, as sketched below:- if (!once_control) { // May be in TLS named_mutex::guard guard(&once_control2); if (!once_control2) { once_control2 = true; } once_control = true; } A more detailed description of this can be found here:- http://groups.yahoo.com/group/boost/message/15442 [Although the definition of a suitable PTHREAD_ONCE_INIT precludes use of the TLS located flag, this is not critical.] There are three primary concerns though:- 1) The [named] mutex is 'created' even in the uncontended case. 2) A system wide unique name must be generated. 3) Win32 mutexes are VERY slow even in the uncontended case. An uncontested Win32 mutex lock operation can be 50 (or more) times slower than an uncontested EnterCS operation. Ultimately, the named mutex trick is making use of the global locks maintained by the kernel. * pthread.h (pthread_once_t_): One flag and an event HANDLE added. (PTHREAD_ONCE_INIT): Additional values included. 2005-03-08 Ross Johnson * pthread_once.c (pthread_once): Redesigned to elliminate potential starvation problem. - reported by Gottlob Frege * ptw32_threadDestroy.c (ptw32_threadDestroy): Implicit threads were not closing their Win32 thread duplicate handle. - reported by Dmitrii Semii 2005-01-25 Ralf Kubis * Attempted acquisition of recursive mutex was causing waiting threads to not be woken when the mutex is released. * GNUmakefile (GCE): Generate correct version resource comments. 2005-01-01 Konstantin Voronkov * pthread_mutex_lock.c (pthread_mutex_lock): The new atomic exchange mutex algorithm is known to allow a thread to steal the lock off FIFO waiting threads. The next waiting FIFO thread gets a spurious wake-up and must attempt to re-acquire the lock. The woken thread was setting itself as the mutex's owner before the re-acquisition. 2004-11-22 Ross Johnson * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Undo change from 2004-11-02. * Makefile (DLL_VER): Added for DLL naming suffix - see README. * GNUmakefile (DLL_VER): Likewise. * Wmakefile (DLL_VER): Likewise. * Bmakefile (DLL_VER): Likewise. * pthread.dsw (version.rc): Added to MSVS workspace. 2004-11-20 Boudewijn Dekker * pthread_getspecific.c (pthread_getspecific): Check for invalid (NULL) key argument. 2004-11-19 Ross Johnson * config.h (PTW32_THREAD_ID_REUSE_INCREMENT): Added to allow building the library for either unique thread IDs like Solaris or non-unique thread IDs like Linux; allows application developers to override the library's default insensitivity to some apps that may not be strictly POSIX compliant. * version.rc: New resource module to encode version information within the DLL. * pthread.h: Added PTW32_VERSION* defines and grouped sections required by resource compiler together; bulk of file is skipped if RC_INVOKED. Defined some error numbers and other names for Borland compiler. 2004-11-02 Ross Johnson * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Lock CV mutex at start of cleanup handler rather than at the end. * implement.h (PTW32_THREAD_REUSE_EMPTY): Renamed from *_BOTTOM. (ptw32_threadReuseBottom): New global variable. * global.c (ptw32_threadReuseBottom): Declare new variable. * ptw32_reuse.c (ptw32_reuse): Change reuse LIFO stack to LILO queue to more evenly distribute use of reusable thread IDs; use renamed PTW32_THREAD_REUSE_EMPTY. * ptw32_processTerminate.c (ptw2_processTerminate): Use renamed PTW32_THREAD_REUSE_EMPTY. 2004-10-31 Ross Johnson * implement.h (PThreadState): Add new state value 'PThreadStateCancelPending'. * pthread_testcancel.c (pthread_testcancel): Use new thread 'PThreadStateCancelPending' state as short cut to avoid entering kernel space via WaitForSingleObject() call. This was obviated by user space sema acquisition in sem_wait() and sem_timedwait(), which are also cancelation points. A call to pthread_testcancel() was required, which introduced a kernel call, effectively nullifying any gains made by the user space sem acquisition checks. * pthread_cancel.c (pthread_cancel): Set new thread 'PThreadStateCancelPending' state. 2004-10-29 Ross Johnson * implement.h (pthread_t): Renamed to ptw32_thread_t; struct contains all thread state. * pthread.h (ptw32_handle_t): New general purpose struct to serve as a handle for various reusable object IDs - currently only used by pthread_t; contains a pointer to ptw32_thread_t (thread state) and a general purpose uint for use as a reuse counter or flags etc. (pthread_t): typedef'ed to ptw32_handle_t; the uint is the reuse counter that allows the library to maintain unique POSIX thread IDs. When the pthread struct reuse stack was introduced, threads would often acquire an identical ID to a previously destroyed thread. The same was true for the pre-reuse stack library, by virtue of pthread_t being the address of the thread struct. The new pthread_t retains the reuse stack but provides virtually unique thread IDs. * sem_wait.c (ptw32_sem_wait_cleanup): New routine used for cancelation cleanup. * sem_timedwait.c (ptw32_sem_timedwait_cleanup): Likewise. 2004-10-22 Ross Johnson * sem_init.c (sem_init): Introduce a 'lock' element in order to replace the interlocked operations with conventional serialisation. This is needed in order to be able to atomically modify the sema value and perform Win32 sema release operations. Win32 semaphores are used instead of events in order to support efficient multiple posting. If the whole modify/release isn't atomic, a race between sem_timedwait() and sem_post() could result in a release when there is no waiting semaphore, which would cause too many threads to proceed. * sem_wait.c (sem_wait): Use new 'lock'element. * sem_timedwait.c (sem_timedwait): Likewise. * sem_trywait.c (sem_trywait): Likewise. * sem_post.c (sem_post): Likewise. * sem_post_multiple.c (sem_post_multiple): Likewise. * sem_getvalue.c (sem_getvalue): Likewise. * ptw32_semwait.c (ptw32_semwait): Likewise. * sem_destroy.c (sem_destroy): Likewise; also tightened the conditions for semaphore destruction; in particular, a semaphore will not be destroyed if it has waiters. * sem_timedwait.c (sem_timedwait): Added cancel cleanup handler to restore sema value when cancelled. * sem_wait.c (sem_wait): Likewise. 2004-10-21 Ross Johnson * pthread_mutex_unlock.c (pthread_mutex_unlock): Must use PulseEvent() rather than SetEvent() to reset the event if there are no waiters. 2004-10-19 Ross Johnson * sem_init.c (sem_init): New semaphore model based on the same idea as mutexes, i.e. user space interlocked check to avoid unnecessarily entering kernel space. Wraps the Win32 semaphore and keeps it's own counter. Although the motivation to do this has existed for a long time, credit goes to Alexander Terekhov for providing the logic. I have deviated slightly from AT's logic to add the waiters count, which has made the code more complicated by adding cancelation cleanup. This also appears to have broken the VCE (C++ EH) version of the library (the same problem as previously reported - see BUGS #2), only apparently not fixable using the usual workaround, nor by turning all optimisation off. The GCE version works fine, so it is presumed to be a bug in MSVC++ 6.0. The cancelation exception is thrown and caught correctly, but the cleanup class destructor is never called. The failing test is tests\semaphore4.c. * sem_wait.c (sem_wait): Implemented user space check model. * sem_post.c (sem_post): Likewise. * sem_trywait.c (sem_trywait): Likewise. * sem_timedwait.c (sem_timedwait): Likewise. * sem_post_multiple.c (sem_post_multiple): Likewise. * sem_getvalue.c (sem_getvalue): Likewise. * ptw32_semwait.c (ptw32_semwait): Likewise. * implement.h (sem_t_): Add counter element. 2004-10-15 Ross Johnson * implement.h (pthread_mutex_t_): Use an event in place of the POSIX semaphore. * pthread_mutex_init.c: Create the event; remove semaphore init. * pthread_mutex_destroy.c: Delete the event. * pthread_mutex_lock.c: Replace the semaphore wait with the event wait. * pthread_mutex_trylock.c: Likewise. * pthread_mutex_timedlock.c: Likewise. * pthread_mutex_unlock.c: Set the event. 2004-10-14 Ross Johnson * pthread_mutex_lock.c (pthread_mutex_lock): New algorithm using Terekhov's xchg based variation of Drepper's cmpxchg model. Theoretically, xchg uses fewer clock cycles than cmpxchg (using IA-32 as a reference), however, in my opinion bus locking dominates the equation on smp systems, so the model with the least number of bus lock operations in the execution path should win, which is Terekhov's variant. On IA-32 uni-processor systems, it's faster to use the CMPXCHG instruction without locking the bus than to use the XCHG instruction, which always locks the bus. This makes the two variants equal for the non-contended lock (fast lane) execution path on up IA-32. Testing shows that the xchg variant is faster on up IA-32 as well if the test forces higher lock contention frequency, even though kernel calls should be dominating the times (on up IA-32, both variants used CMPXCHG instructions and neither locked the bus). * pthread_mutex_timedlock.c pthread_mutex_timedlock(): Similarly. * pthread_mutex_trylock.c (pthread_mutex_trylock): Similarly. * pthread_mutex_unlock.c (pthread_mutex_unlock): Similarly. * ptw32_InterlockedCompareExchange.c (ptw32_InterlockExchange): New function. (PTW32_INTERLOCKED_EXCHANGE): Sets up macro to use inlined ptw32_InterlockedExchange. * implement.h (PTW32_INTERLOCKED_EXCHANGE): Set default to InterlockedExchange(). * Makefile: Building using /Ob2 so that asm sections within inline functions are inlined. 2004-10-08 Ross Johnson * pthread_mutex_destroy.c (pthread_mutex_destroy): Critical Section element is no longer required. * pthread_mutex_init.c (pthread_mutex_init): Likewise. * pthread_mutex_lock.c (pthread_mutex_lock): New algorithm following Drepper's paper at http://people.redhat.com/drepper/futex.pdf, but using the existing semaphore in place of the futex described in the paper. Idea suggested by Alexander Terekhov - see: http://sources.redhat.com/ml/pthreads-win32/2003/msg00108.html * pthread_mutex_timedlock.c pthread_mutex_timedlock(): Similarly. * pthread_mutex_trylock.c (pthread_mutex_trylock): Similarly. * pthread_mutex_unlock.c (pthread_mutex_unlock): Similarly. * pthread_barrier_wait.c (pthread_barrier_wait): Use inlined version of InterlockedCompareExchange() if possible - determined at build-time. * pthread_spin_destroy.c pthread_spin_destroy(): Likewise. * pthread_spin_lock.c pthread_spin_lock():Likewise. * pthread_spin_trylock.c (pthread_spin_trylock):Likewise. * pthread_spin_unlock.c (pthread_spin_unlock):Likewise. * ptw32_InterlockedCompareExchange.c: Sets up macro for inlined use. * implement.h (pthread_mutex_t_): Remove Critical Section element. (PTW32_INTERLOCKED_COMPARE_EXCHANGE): Set to default non-inlined version of InterlockedCompareExchange(). * private.c: Include ptw32_InterlockedCompareExchange.c first for inlining. * GNUmakefile: Add commandline option to use inlined InterlockedCompareExchange(). * Makefile: Likewise. 2004-09-27 Ross Johnson * pthread_mutex_lock.c (pthread_mutex_lock): Separate PTHREAD_MUTEX_NORMAL logic since we do not need to keep or check some state required by other mutex types; do not check mutex pointer arg for validity - leave this to the system since we are only checking for NULL pointers. This should improve speed of NORMAL mutexes and marginally improve speed of other type. * pthread_mutex_trylock.c (pthread_mutex_trylock): Likewise. * pthread_mutex_unlock.c (pthread_mutex_unlock): Likewise; also avoid entering the critical section for the no-waiters case, with approx. 30% reduction in lock/unlock overhead for this case. * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise; also no longer keeps mutex if post-timeout second attempt succeeds - this will assist applications that wish to impose strict lock deadlines, rather than simply to escape from frozen locks. 2004-09-09 Tristan Savatier * pthread.h (struct pthread_once_t_): Qualify the 'done' element as 'volatile'. * pthread_once.c: Concerned about possible race condition, specifically on MPU systems re concurrent access to multibyte types. [Maintainer's note: the race condition is harmless on SPU systems and only a problem on MPU systems if concurrent access results in an exception (presumably generated by a hardware interrupt). There are other instances of similar harmless race conditions that have not been identified as issues.] 2004-09-09 Ross Johnson * pthread.h: Declare additional types as volatile. 2004-08-27 Ross Johnson * pthread_barrier_wait.c (pthread_barrier_wait): Remove excessive code by substituting the internal non-cancelable version of sem_wait (ptw32_semwait). 2004-08-25 Ross Johnson * pthread_join.c (pthread_join): Rewrite and re-order the conditional tests in an attempt to improve efficiency and remove a race condition. 2004-08-23 Ross Johnson * create.c (pthread_create): Don't create a thread if the thread id pointer location (first arg) is inaccessible. A memory protection fault will result if the thread id arg isn't an accessible location. This is consistent with GNU/Linux but different to Solaris or MKS (and possibly others), which accept NULL as meaning 'don't return the created thread's ID'. Applications that run using pthreads-win32 will run on all other POSIX threads implementations, at least w.r.t. this feature. It was decided not to copy the Solaris et al behaviour because, although it would have simplified some application porting (but only from Solaris to Windows), the feature is not technically necessary, and the alternative segfault behaviour helps avoid buggy application code. 2004-07-01 Anuj Goyal * builddmc.bat: New; Windows bat file to build the library. * config.h (__DMC__): Support for Digital Mars compiler. * create.c (__DMC__): Likewise. * pthread_exit.c (__DMC__): Likewise. * pthread_join.c (__DMC__): Likewise. * ptw32_threadDestroy.c (__DMC__): Likewise. * ptw32_threadStart.c (__DMC__): Likewise. * ptw32_throw.c (__DMC__): Likewise. 2004-06-29 Anuj Goyal * pthread.h (__DMC__): Initial support for Digital Mars compiler. 2004-06-29 Will Bryant * README.Borland: New; description of Borland changes. * Bmakefile: New makefile for the Borland make utility. * ptw32_InterlockedCompareExchange.c: Add Borland compatible asm code. 2004-06-26 Jason Bard * pthread.h (HAVE_STRUCT_TIMESPEC): If undefined, define it to avoid timespec struct redefined errors elsewhere in an application. 2004-06-21 Ross Johnson * pthread.h (PTHREAD_RECURSIVE_MUTEX_INITIALIZER): Mutex initialiser added for compatibility with Linux threads and others; currently not included in SUSV3. * pthread.h (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER): Likewise. * pthread.h (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise. * pthread.h (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. * ptw32_mutex_check_need_init.c (ptw32_mutex_check_need_init): Add new initialisers. * pthread_mutex_lock.c (pthread_mutex_lock): Check for new initialisers. * pthread_mutex_trylock.c (pthread_mutex_trylock): Likewise. * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise. * pthread_mutex_unlock.c (pthread_mutex_unlock): Likewise. * pthread_mutex_destroy.c (pthread_mutex_destroy): Likewise. 2004-05-20 Ross Johnson * README.NONPORTABLE: Document pthread_win32_test_features_np(). * FAQ: Update various answers. 2004-05-19 Ross Johnson * Makefile: Don't define _WIN32_WINNT on compiler command line. * GNUmakefile: Likewise. 2004-05-16 Ross Johnson * pthread_cancel.c (pthread_cancel): Adapted to use auto-detected QueueUserAPCEx features at run-time. (ptw32_RegisterCancelation): Drop in replacement for QueueUserAPCEx() if it can't be used. Provides older style non-preemptive async cancelation. * pthread_win32_attach_detach_np.c (pthread_win32_attach_np): Auto-detect quserex.dll and the availability of alertdrv.sys; initialise and close on process attach/detach. * global.c (ptw32_register_cancelation): Pointer to either QueueUserAPCEx() or ptw32_RegisterCancelation() depending on availability. QueueUserAPCEx makes pre-emptive async cancelation possible. * implement.h: Add definitions and prototypes related to QueueUserAPC. 2004-05-16 Panagiotis E. Hadjidoukas * QueueUserAPCEx (separate contributed package): Provides preemptive APC feature. * pthread_cancel.c (pthread_cancel): Initial integration of QueueUserAPCEx into pthreads-win32 to provide true pre-emptive async cancelation of threads, including blocked threads. 2004-05-06 Makoto Kato * pthread.h (DWORD_PTR): Define typedef for older MSVC. * pthread_cancel.c (AMD64): Add architecture specific Context register. * ptw32_getprocessors.c: Use correct types (DWORD_PTR) for mask variables. 2004-04-06 P. van Bruggen * ptw32_threadDestroy.c: Destroy threadLock mutex to close a memory leak. 2004-02-13 Gustav Hallberg * pthread_equal.c: Remove redundant equality logic. 2003-12-10 Philippe Di Cristo * sem_timedwait.c (sem_timedwait): Fix timeout calculations. 2003-10-20 Alexander Terekhov * pthread_mutex_timedlock.c (ptw32_semwait): Move to individual module. * ptw32_semwait.c: New module. * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Replace cancelable sem_wait() call with non-cancelable ptw32_semwait() call. * pthread.c (private.c): Re-order for inlining. GNU C warned that function ptw32_semwait() was defined 'inline' after it was called. * pthread_cond_signal.c (ptw32_cond_unblock): Likewise. * pthread_delay_np.c: Disable Watcom warning with comment. * *.c (process.h): Remove include from .c files. This is conditionally included by the common project include files. 2003-10-20 James Ewing * ptw32_getprocessors.c: Some Win32 environments don't have GetProcessAffinityMask(), so always return CPU count = 1 for them. * config.h (NEED_PROCESSOR_AFFINITY_MASK): Define for WinCE. 2003-10-15 Ross Johnson * Re-indented all .c files using default GNU style to remove assorted editor ugliness (used GNU indent utility in default style). 2003-10-15 Alex Blanco * sem_init.c (sem_init): Would call CreateSemaphore even if the sema struct calloc failed; was not freeing calloced memory if either CreateSemaphore or CreateEvent failed. 2003-10-14 Ross Johnson * pthread.h: Add Watcom compiler compatibility. Esssentially just add the cdecl attribute to all exposed function prototypes so that Watcom generates function call code compatible with non-Watcom built libraries. By default, Watcom uses registers to pass function args if possible rather than pushing to stack. * semaphore.h: Likewise. * sched.h: Likewise. * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Define with cdecl attribute for Watcom compatibility. This routine is called via pthread_cleanup_push so it had to match function arg definition. * Wmakefile: New makefile for Watcom builds. 2003-09-14 Ross Johnson * pthread_setschedparam.c (pthread_setschedparam): Attempt to map all priority levels between max and min (as returned by sched_get_priority_min/max) to reasonable Win32 priority levels - i.e. levels between THREAD_PRIORITY_LOWEST/IDLE to THREAD_PRIORITY_LOWEST and between THREAD_PRIORITY_HIGHEST/TIME_CRITICAL to THREAD_PRIORITY_HIGHEST while others remain unchanged; record specified thread priority level for return by pthread_getschedparam. Note that, previously, specified levels not matching Win32 priority levels would silently leave the current thread priority unaltered. * pthread_getschedparam.c (pthread_getschedparam): Return the priority level specified by the latest pthread_setschedparam or pthread_create rather than the actual running thread priority as returned by GetThreadPriority - as required by POSIX. I.e. temporary or adjusted actual priority levels are not returned by this routine. * pthread_create.c (pthread_create): For priority levels specified via pthread attributes, attempt to map all priority levels between max and min (as returned by sched_get_priority_min/max) to reasonable Win32 priority levels; record priority level given via attributes, or inherited from parent thread, for later return by pthread_getschedparam. * ptw32_new.c (ptw32_new): Initialise pthread_t_ sched_priority element. * pthread_self.c (pthread_self): Set newly created implicit POSIX thread sched_priority to Win32 thread's current actual priority. Temporarily altered priorities can't be avoided in this case. * implement.h (struct pthread_t_): Add new sched_priority element. 2003-09-12 Ross Johnson * sched_get_priority_min.c (sched_get_priority_min): On error should return -1 with errno set. * sched_get_priority_max.c (sched_get_priority_max): Likewise. 2003-09-03 Ross Johnson * w32_cancelableWait.c (ptw32_cancelable_wait): Allow cancelation of implicit POSIX threads as well. 2003-09-02 Ross Johnson * pthread_win32_attach_detach_np.c (pthread_win32_thread_detach_np): Add comment. * pthread_exit.c (pthread_exit): Fix to recycle the POSIX thread handle in addition to calling user TSD destructors. Move the implicit POSIX thread exit handling to ptw32_throw to centralise the logic. * ptw32_throw.c (ptw32_throw): Implicit POSIX threads have no point to jump or throw to, so cleanup and exit the thread here in this case. For processes using the C runtime, the exit code will be set to the POSIX reason for the throw (i.e. PTHREAD_CANCEL or the value given to pthread_exit). Note that pthread_exit() already had similar logic, which has been moved to here. * ptw32_threadDestroy.c (ptw32_threadDestroy): Don't close the Win32 handle of implicit POSIX threads - expect this to be done by Win32? 2003-09-01 Ross Johnson * pthread_self.c (pthread_self): The newly aquired pthread_t must be assigned to the reuse stack, not freed, if the routine fails somehow. 2003-08-13 Ross Johnson * pthread_getschedparam.c (pthread_getschedparam): An invalid thread ID parameter was returning an incorrect error value; now uses a more exhaustive check for validity. * pthread_setschedparam.c (pthread_setschedparam): Likewise. * pthread_join.c (pthread_join): Now uses a more exhaustive check for validity. * pthread_detach.c (pthread_detach): Likewise. * pthread_cancel.c (pthread_cancel): Likewise. * ptw32_threadDestroy.c (ptw32_threadDestroy): pthread_t structs are never freed - push them onto a stack for reuse. * ptw32_new.c (ptw32_new): Check for reusable pthread_t before dynamically allocating new memory for the struct. * pthread_kill.c (pthread_kill): New file; new routine; takes only a zero signal arg so that applications can check the thread arg for validity; checks that the underlying Win32 thread HANDLE is valid. * pthread.h (pthread_kill): Add prototype. * ptw32_reuse.c (ptw32_threadReusePop): New file; new routine; pop a pthread_t off the reuse stack. pthread_t_ structs that have been destroyed, i.e. have exited detached or have been joined, are cleaned up and put onto a reuse stack. Consequently, thread IDs are no longer freed once calloced. The library will attempt to get a struct off this stack before asking the system to alloc new memory when creating threads. The stack is guarded by a global mutex. (ptw32_threadReusePush): New routine; push a pthread_t onto the reuse stack. * implement.h (ptw32_threadReusePush): Add new prototype. (ptw32_threadReusePop): Likewise. (pthread_t): Add new element. * ptw32_processTerminate.c (ptw32_processTerminate): Delete the thread reuse lock; free all thread ID structs on the thread reuse stack. * ptw32_processInitialize.c (ptw32_processInitialize): Initialise the thread reuse lock. 2003-07-19 Ross Johnson * GNUmakefile: modified to work under MsysDTK environment. * pthread_spin_lock.c (pthread_spin_lock): Check for NULL arg. * pthread_spin_unlock.c (pthread_spin_unlock): Likewise. * pthread_spin_trylock.c (pthread_spin_trylock): Likewise; fix incorrect pointer value if lock is dynamically initialised by this function. * sem_init.c (sem_init): Initialise sem_t value to quell compiler warning. * sem_destroy.c (sem_destroy): Likewise. * ptw32_threadStart.c (non-MSVC code sections): Include rather than old-style ; fix all std:: namespace entities such as std::terminate_handler instances and associated methods. * ptw32_callUserDestroyRoutines.c (non-MSVC code sections): Likewise. 2003-06-24 Piet van Bruggen * pthread_spin_destroy.c (pthread_spin_destroy): Was not freeing the spinlock struct. 2003-06-22 Nicolas Barry * pthread_mutex_destroy.c (pthread_mutex_destroy): When called with a recursive mutex that was locked by the current thread, the function was failing with a success return code. 2003-05-15 Steven Reddie * pthread_win32_attach_detach_np.c (pthread_win32_process_detach_np): NULLify ptw32_selfThreadKey after the thread is destroyed, otherwise destructors calling pthreads routines might resurrect it again, creating memory leaks. Call the underlying Win32 Tls routine directly rather than pthread_setspecific(). (pthread_win32_thread_detach_np): Likewise. 2003-05-14 Viv * pthread.dsp: Change /MT compile flag to /MD. 2003-03-04 Alexander Terekhov * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Fix failure to set ownership of mutex on second grab after abstime timeout. - bug reported by Robert Strycek 2002-12-17 Thomas Pfaff * pthread_mutex_lock.c (ptw32_semwait): New static routine to provide a non-cancelable sem_wait() function. This is consistent with the way that pthread_mutex_timedlock.c does it. (pthread_mutex_lock): Use ptw32_semwait() instead of sem_wait(). 2002-12-11 Thomas Pfaff * pthread_mutex_trylock.c: Should return EBUSY rather than EDEADLK. * pthread_mutex_destroy.c: Remove redundant ownership test (the trylock call does this for us); do not destroy a recursively locked mutex. 2002-09-20 Michael Johnson * pthread_cond_destroy.c (pthread_cond_destroy): When two different threads exist, and one is attempting to destroy a condition variable while the other is attempting to initialize a condition variable that was created with PTHREAD_COND_INITIALIZER, a deadlock can occur. Shrink the ptw32_cond_list_lock critical section to fix it. 2002-07-31 Ross Johnson * ptw32_threadStart.c (ptw32_threadStart): Thread cancelLock destruction moved to ptw32_threadDestroy(). * ptw32_threadDestroy.c (ptw32_threadDestroy): Destroy the thread's cancelLock. Moved here from ptw32_threadStart.c to cleanup implicit threads as well. 2002-07-30 Alexander Terekhov * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Remove code designed to avoid/prevent spurious wakeup problems. It is believed that the sem_timedwait() call is consuming a CV signal that it shouldn't and this is breaking the avoidance logic. 2002-07-30 Ross Johnson * sem_timedwait.c (sem_timedwait): Tighten checks for unreasonable abstime values - that would result in unexpected timeout values. * w32_CancelableWait.c (ptw32_cancelable_wait): Tighten up return value checking and add comments. 2002-06-08 Ross Johnson * sem_getvalue.c (sem_getvalue): Now returns a value for the NEED_SEM version (i.e. earlier versions of WinCE). 2002-06-04 Rob Fanner * sem_getvalue.c (sem_getvalue): The Johnson M. Hart approach didn't work - we are forced to take an intrusive approach. We try to decrement the sema and then immediately release it again to get the value. There is a small probability that this may block other threads, but only momentarily. 2002-06-03 Ross Johnson * sem_init.c (sem_init): Initialise Win32 semaphores to _POSIX_SEM_VALUE_MAX (which this implementation defines in pthread.h) so that sem_getvalue() can use the trick described in the comments in sem_getvalue(). * pthread.h (_POSIX_SEM_VALUE_MAX): Defined. (_POSIX_SEM_NSEMS_MAX): Defined - not used but may be useful for source code portability. 2002-06-03 Rob Fanner * sem_getvalue.c (sem_getvalue): Did not work on NT. Use approach suggested by Johnson M. Hart in his book "Win32 System Programming". 2002-02-28 Ross Johnson * errno.c: Compiler directive was incorrectly including code. * pthread.h: Conditionally added some #defines from config.h needed when not building the library. e.g. NEED_ERRNO, NEED_SEM. (PTW32_DLLPORT): Now only defined if _DLL defined. (_errno): Compiler directive was incorrectly including prototype. * sched.h: Conditionally added some #defines from config.h needed when not building the library. * semaphore.h: Replace an instance of NEED_SEM that should have been NEED_ERRNO. This change currently has nil effect. * GNUmakefile: Correct some recent changes. * Makefile: Add rule to generate pre-processor output. 2002-02-23 Ross Johnson * pthread_rwlock_timedrdlock.c: New - untested. * pthread_rwlock_timedwrlock.c: New - untested. * Testsuite passed (except known MSVC++ problems) * pthread_cond_destroy.c: Expand the time change critical section to solve deadlock problem. * pthread.c: Add all remaining C modules. * pthread.h: Use dllexport/dllimport attributes on functions to avoid using pthread.def. * sched.h: Likewise. * semaphore.h: Likewise. * GNUmakefile: Add new targets for single translation unit build to maximise inlining potential; generate pthread.def automatically. * Makefile: Likewise, but no longer uses pthread.def. 2002-02-20 Ross Johnson * pthread_cond_destroy.c (pthread_cond_destroy): Enter the time change critical section earlier. 2002-02-17 Ross Johnson * nonportable.c (pthread_delay_np): Make a true cancelation point. Deferred cancels will interrupt the wait. 2002-02-07 Ross Johnson Reduced name space pollution. ----------------------------- When the appropriate symbols are defined, the headers will restrict the definitions of new names. In particular, it must be possible to NOT include the header and related definitions with some combination of symbol definitions. Secondly, it should be possible that additional definitions should be limited to POSIX compliant symbols by the definition of appropriate symbols. * pthread.h: POSIX conditionals. * sched.h: POSIX conditionals. * semaphore.h: POSIX conditionals. * semaphore.c: Included . (sem_init): Changed magic 0x7FFFFFFFL to INT_MAX. (sem_getvalue): Trial version. Reduce executable size. ----------------------- When linking with the static library, only those routines actually called, either directly or indirectly should be included. [Gcc has the -ffunction-segments option to do this but MSVC doesn't have this feature as far as I can determine. Other compilers are undetermined as well. - rpj] * semaphore.c: All routines are now in separate compilation units; This file is used to congregate the separate modules for potential inline optimisation and backward build compatibility. * sem_close.c: Separated routine from semaphore.c. * ptw32_decrease_semaphore.c: Likewise. * sem_destroy.c: Likewise. * sem_getvalue.c: Likewise. * ptw32_increase_semaphore.c: Likewise. * sem_init.c: Likewise. * sem_open.c: Likewise. * sem_post.c: Likewise. * sem_post_multiple.c: Likewise. * sem_timedwait.c: Likewise. * sem_trywait.c: Likewise. * sem_unlink.c: Likewise. * sem_wait.c: Likewise. 2002-02-04 Ross Johnson The following extends the idea above to the rest of pthreads-win32 - rpj * attr.c: All routines are now in separate compilation units; This file is used to congregate the separate modules for potential inline optimisation and backward build compatibility. * pthread_attr_destroy.c: Separated routine from attr.c. * pthread_attr_getdetachstate.c: Likewise. * pthread_attr_getscope.c: Likewise. * pthread_attr_getstackaddr.c: Likewise. * pthread_attr_getstacksize.c: Likewise. * pthread_attr_init.c: Likewise. * pthread_attr_is_attr.c: Likewise. * pthread_attr_setdetachstate.c: Likewise. * pthread_attr_setscope.c: Likewise. * pthread_attr_setstackaddr.c: Likewise. * pthread_attr_setstacksize.c: Likewise. * pthread.c: Agregation of agregate modules for super-inlineability. 2002-02-02 Ross Johnson * cancel.c: Rearranged some code and introduced checks to disable cancelation at the start of a thread's cancelation run to prevent double cancelation. The main problem arises if a thread is canceling and then receives a subsequent async cancel request. * private.c: Likewise. * condvar.c: Place pragmas around cleanup_push/pop to turn off inline optimisation (/Obn where n>0 - MSVC only). Various optimisation switches in MSVC turn this on, which interferes with the way that cleanup handlers are run in C++ EH and SEH code. Application code compiled with inline optimisation must also wrap cleanup_push/pop blocks with the pragmas, e.g. #pragma inline_depth(0) pthread_cleanup_push(...) ... pthread_cleanup_pop(...) #pragma inline_depth(8) * rwlock.c: Likewise. * mutex.c: Remove attempts to inline some functions. * signal.c: Modify misleading comment. 2002-02-01 Ross Johnson * semaphore.c (sem_trywait): Fix missing errno return for systems that define NEED_SEM (e.g. early WinCE). * mutex.c (pthread_mutex_timedlock): Return ENOTSUP for systems that define NEED_SEM since they don't have sem_trywait(). 2002-01-27 Ross Johnson * mutex.c (pthread_mutex_timedlock): New function suggested by Alexander Terekhov. The logic required to implement this properly came from Alexander, with some collaboration with Thomas Pfaff. (pthread_mutex_unlock): Wrap the waiters check and sema post in a critical section to prevent a race with pthread_mutex_timedlock. (ptw32_timed_semwait): New function; returns a special result if the absolute timeout parameter represents a time already passed when called; used by pthread_mutex_timedwait(). Have deliberately not reused the name "ptw32_sem_timedwait" because they are not the same routine. * condvar.c (ptw32_cond_timedwait): Use the new sem_timedwait() instead of ptw32_sem_timedwait(), which now has a different function. See previous. * implement.h: Remove prototype for ptw32_sem_timedwait. See next. (pthread_mutex_t_): Add critical section element for access to lock_idx during mutex post-timeout processing. * semaphore.h (sem_timedwait): See next. * semaphore.c (sem_timedwait): See next. * private.c (ptw32_sem_timedwait): Move to semaphore.c and rename as sem_timedwait(). 2002-01-18 Ross Johnson * sync.c (pthread_join): Was getting the exit code from the calling thread rather than the joined thread if defined(__MINGW32__) && !defined(__MSVCRT__). 2002-01-15 Ross Johnson * pthread.h: Unless the build explicitly defines __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then the build defaults to __CLEANUP_C style cleanup. This style uses setjmp/longjmp in the cancelation and thread exit implementations and therefore won't do stack unwinding if linked to applications that have it (e.g. C++ apps). This is currently consistent with most/all commercial Unix POSIX threads implementations. * spin.c (pthread_spin_init): Edit renamed function call. * nonportable.c (pthread_num_processors_np): New. (pthread_getprocessors_np): Renamed to ptw32_getprocessors and moved to private.c. * private.c (pthread_getprocessors): Moved here from nonportable.c. * pthread.def (pthread_getprocessors_np): Removed from export list. * rwlock.c (pthread_rwlockattr_init): New. (pthread_rwlockattr_destroy): New. (pthread_rwlockattr_getpshared): New. (pthread_rwlockattr_setpshared): New. 2002-01-14 Ross Johnson * attr.c (pthread_attr_setscope): Fix struct pointer indirection error introduced 2002-01-04. (pthread_attr_getscope): Likewise. 2002-01-12 Ross Johnson * pthread.dsp (SOURCE): Add missing source files. 2002-01-08 Ross Johnson * mutex.c (pthread_mutex_trylock): use ptw32_interlocked_compare_exchange function pointer rather than ptw32_InterlockedCompareExchange() directly to retain portability to non-iX86 processors, e.g. WinCE etc. The pointer will point to the native OS version of InterlockedCompareExchange() if the OS supports it (see ChangeLog entry of 2001-10-17). 2002-01-07 Thomas Pfaff , Alexander Terekhov * mutex.c (pthread_mutex_init): Remove critical section calls. (pthread_mutex_destroy): Likewise. (pthread_mutex_unlock): Likewise. (pthread_mutex_trylock): Likewise; uses ptw32_InterlockedCompareExchange() to avoid need for critical section; library is no longer i386 compatible; recursive mutexes now increment the lock count rather than return EBUSY; errorcheck mutexes return EDEADLCK rather than EBUSY. This behaviour is consistent with the Solaris pthreads implementation. * implement.h (pthread_mutex_t_): Remove critical section element - no longer needed. 2002-01-04 Ross Johnson * attr.c (pthread_attr_setscope): Add more error checking and actually store the scope value even though it's not really necessary. (pthread_attr_getscope): Return stored value. * implement.h (pthread_attr_t_): Add new scope element. * ANNOUNCE: Fix out of date comment next to pthread_attr_setscope in conformance section. 2001-12-21 Alexander Terekhov * mutex.c (pthread_mutex_lock): Decrementing lock_idx was not thread-safe. (pthread_mutex_trylock): Likewise. 2001-10-26 prionx@juno.com * semaphore.c (sem_init): Fix typo and missing bracket in conditionally compiled code. Only older versions of WinCE require this code, hence it doesn't normally get tested; somehow when sem_t reverted to an opaque struct the calloc NULL check was left in the conditionally included section. (sem_destroy): Likewise, the calloced sem_t wasn't being freed. 2001-10-25 Ross Johnson * GNUmakefile (libwsock32): Add to linker flags for WSAGetLastError() and WSASetLastError(). * Makefile (wsock32.lib): Likewise. * create.c: Minor mostly inert changes. * implement.h (PTW32_MAX): Move into here and renamed from sched.h. (PTW32_MIN): Likewise. * GNUmakefile (TEST_ICE): Define if testing internal implementation of InterlockedCompareExchange. * Makefile (TEST_ICE): Likewise. * private.c (TEST_ICE): Likewise. 2001-10-24 Ross Johnson * attr.c (pthread_attr_setstacksize): Quell warning from LCC by conditionally compiling the stacksize validity check. LCC correctly warns that the condition (stacksize < PTHREAD_STACK_MIN) is suspicious because STACK_MIN is 0 and stacksize is of type size_t (or unsigned int). 2001-10-17 Ross Johnson * barrier.c: Move _LONG and _LPLONG defines into implement.h; rename to PTW32_INTERLOCKED_LONG and PTW32_INTERLOCKED_LPLONG respectively. * spin.c: Likewise; ptw32_interlocked_compare_exchange used in place of InterlockedCompareExchange directly. * global.c (ptw32_interlocked_compare_exchange): Add prototype for this new routine pointer to be used when InterlockedCompareExchange isn't supported by Windows. * nonportable.c (pthread_win32_process_attach_np): Check for support of InterlockedCompareExchange in kernel32 and assign its address to ptw32_interlocked_compare_exchange if it exists, or our own ix86 specific implementation ptw32_InterlockedCompareExchange. *private.c (ptw32_InterlockedCompareExchange): An implementation of InterlockedCompareExchange() which is specific to ix86; written directly in assembler for either MSVC or GNU C; needed because Windows 95 doesn't support InterlockedCompareExchange(). * sched.c (sched_get_priority_min): Extend to return THREAD_PRIORITY_IDLE. (sched_get_priority_max): Extend to return THREAD_PRIORITY_CRITICAL. 2001-10-15 Ross Johnson * spin.c (pthread_spin_lock): PTHREAD_SPINLOCK_INITIALIZER was causing a program fault. (pthread_spin_init): Could have alloced memory without freeing under some error conditions. * mutex.c (pthread_mutex_init): Move memory allocation of mutex struct after checking for PROCESS_SHARED. 2001-10-12 Ross Johnson * spin.c (pthread_spin_unlock): Was not returning EPERM if the spinlock was not locked, for multi CPU machines. 2001-10-08 Ross Johnson * spin.c (pthread_spin_trylock): Was not returning EBUSY for multi CPU machines. 2001-08-24 Ross Johnson * condvar.c (pthread_cond_destroy): Remove cv element that is no longer used. * implement.h: Likewise. 2001-08-23 Alexander Terekhov * condvar.c (pthread_cond_destroy): fix bug with respect to deadlock in the case of concurrent _destroy/_unblock; a condition variable can be destroyed immediately after all the threads that are blocked on it are awakened. 2001-08-23 Phil Frisbie, Jr. * tsd.c (pthread_getspecific): Preserve the last winsock error [from WSAGetLastError()]. 2001-07-18 Scott McCaskill * mutex.c (pthread_mutexattr_init): Return ENOMEM immediately and don't dereference the NULL pointer if calloc fails. (pthread_mutexattr_getpshared): Don't dereference a pointer that is possibly NULL. * barrier.c (pthread_barrierattr_init): Likewise (pthread_barrierattr_getpshared): Don't dereference a pointer that is possibly NULL. * condvar.c (pthread_condattr_getpshared): Don't dereference a pointer that is possibly NULL. 2001-07-15 Ross Johnson * rwlock.c (pthread_rwlock_wrlock): Is allowed to be a cancelation point; re-enable deferred cancelability around the CV call. 2001-07-10 Ross Johnson * barrier.c: Still more revamping. The exclusive access mutex isn't really needed so it has been removed and replaced by an InterlockedDecrement(). nSerial has been removed. iStep is now dual-purpose. The process shared attribute is now stored in the barrier struct. * implement.h (pthread_barrier_t_): Lost some/gained one elements. * private.c (ptw32_threadStart): Removed some comments. 2001-07-10 Ross Johnson * barrier.c: Revamped to fix the race condition. Two alternating semaphores are used instead of the PulseEvent. Also improved overall throughput by returning PTHREAD_BARRIER_SERIAL_THREAD to the first waking thread. * implement.h (pthread_barrier_t_): Revamped. 2001-07-09 Ross Johnson * barrier.c: Fix several bugs in all routines. Now passes tests/barrier5.c which is fairly rigorous. There is still a non-optimal work-around for a race condition between the barrier breeched event signal and event wait. Basically the last (signalling) thread to hit the barrier yields to allow any other threads, which may have lost the race, to complete. 2001-07-07 Ross Johnson * barrier.c: Changed synchronisation mechanism to a Win32 manual reset Event and use PulseEvent to signal waiting threads. If the implementation continued to use a semaphore it would require a second semaphore and some management to use them alternately as barriers. A single semaphore allows threads to cascade from one barrier through the next, leaving some threads blocked at the first. * implement.h (pthread_barrier_t_): As per above. * general: Made a number of other routines inlinable. 2001-07-07 Ross Johnson * spin.c: Revamped and working; included static initialiser. Now beta level. * barrier.c: Likewise. * condvar.c: Macro constant change; inline auto init routine. * mutex.c: Likewise. * rwlock.c: Likewise. * private.c: Add support for spinlock initialiser. * global.c: Likewise. * implement.h: Likewise. * pthread.h (PTHREAD_SPINLOCK_INITIALIZER): Fix typo. 2001-07-05 Ross Johnson * barrier.c: Remove static initialisation - irrelevent for this object. * pthread.h (PTHREAD_BARRIER_INITIALIZER): Removed. * rwlock.c (pthread_rwlock_wrlock): This routine is not a cancelation point - disable deferred cancelation around call to pthread_cond_wait(). 2001-07-05 Ross Johnson * spin.c: New module implementing spin locks. * barrier.c: New module implementing barriers. * pthread.h (_POSIX_SPIN_LOCKS): defined. (_POSIX_BARRIERS): Defined. (pthread_spin_*): Defined. (pthread_barrier*): Defined. (PTHREAD_BARRIER_SERIAL_THREAD): Defined. * implement.h (pthread_spinlock_t_): Defined. (pthread_barrier_t_): Defined. (pthread_barrierattr_t_): Defined. * mutex.c (pthread_mutex_lock): Return with the error if an auto-initialiser initialisation fails. * nonportable.c (pthread_getprocessors_np): New; gets the number of available processors for the current process. 2001-07-03 Ross Johnson * pthread.h (_POSIX_READER_WRITER_LOCKS): Define it if not already defined. 2001-07-01 Alexander Terekhov * condvar.c: Fixed lost signal bug reported by Timur Aydin (taydin@snet.net). [RPJ (me) didn't translate the original algorithm correctly.] * semaphore.c: Added sem_post_multiple; this is a useful routine, but it doesn't appear to be standard. For now it's not an exported function. 2001-06-25 Ross Johnson * create.c (pthread_create): Add priority inheritance attributes. * mutex.c (pthread_mutex_lock): Remove some overhead for PTHREAD_MUTEX_NORMAL mutex types. Specifically, avoid calling pthread_self() and pthread_equal() to check/set the mutex owner. Introduce a new pseudo owner for this type. Test results suggest increases in speed of up to 90% for non-blocking locks. This is the default type of mutex used internally by other synchronising objects, ie. condition variables and read-write locks. The test rwlock7.c shows about a 30-35% speed increase over snapshot 2001-06-06. The price of this is that the application developer must ensure correct behaviour, or explicitly set the mutex to a safer type such as PTHREAD_MUTEX_ERRORCHECK. For example, PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_DEFAULT) type mutexes will not return an error if a thread which is not the owner calls pthread_mutex_unlock. The call will succeed in unlocking the mutex if it is currently locked, but a subsequent unlock by the true owner will then fail with EPERM. This is however consistent with some other implementations. (pthread_mutex_unlock): Likewise. (pthread_mutex_trylock): Likewise. (pthread_mutex_destroy): Likewise. * attr.c (pthread_attr_init): PTHREAD_EXPLICIT_SCHED is the default inheritance attribute; THREAD_PRIORITY_NORMAL is the default priority for new threads. * sched.c (pthread_attr_setschedpolicy): Added routine. (pthread_attr_getschedpolicy): Added routine. (pthread_attr_setinheritsched): Added routine. (pthread_attr_getinheritsched): Added routine. * pthread.h (sched_rr_set_interval): Added as a macro; returns -1 with errno set to ENOSYS. 2001-06-23 Ross Johnson *sched.c (pthread_attr_setschedparam): Add priority range check. (sched_setscheduler): New function; checks for a valid pid and policy; checks for permission to set information in the target process; expects pid to be a Win32 process ID, not a process handle; the only scheduler policy allowed is SCHED_OTHER. (sched_getscheduler): Likewise, but checks for permission to query. * pthread.h (SCHED_*): Moved to sched.h as defined in the POSIX standard. * sched.h (SCHED_*): Moved from pthread.h. (pid_t): Defined if necessary. (sched_setscheduler): Defined. (sched_getscheduler): Defined. * pthread.def (sched_setscheduler): Exported. (sched_getscheduler): Likewise. 2001-06-23 Ralf Brese * create.c (pthread_create): Set thread priority from thread attributes. 2001-06-18 Ross Johnson * Made organisational-only changes to UWIN additions. * dll.c (dllMain): Moved UWIN process attach code to pthread_win32_process_attach_np(); moved instance of pthread_count to global.c. * global.c (pthread_count): Moved from dll.c. * nonportable.c (pthread_win32_process_attach_np): Moved _UWIN code to here from dll.c. * implement.h (pthread_count): Define extern int. * create.c (pthread_count): Remove extern int. * private.c (pthread_count): Likewise. * exit.c (pthread_count): Likewise. 2001-06-18 David Korn * dll.c: Added changes necessary to work with UWIN. * create.c: Likewise. * pthread.h: Likewise. * misc.c: Likewise. * exit.c: Likewise. * private.c: Likewise. * implement.h: Likewise. There is some room at the start of struct pthread_t_ to implement the signal semantics in UWIN's posix.dll although this is not yet complete. * Nmakefile: Compatible with UWIN's Nmake utility. * Nmakefile.tests: Likewise - for running the tests. 2001-06-08 Ross Johnson * semaphore.h (sem_t): Fixed for compile and test. * implement.h (sem_t_): Likewise. * semaphore.c: Likewise. * private.c (ptw32_sem_timedwait): Updated to use new opaque sem_t. 2001-06-06 Ross Johnson * semaphore.h (sem_t): Is now an opaque pointer; moved actual definition to implement.h. * implement.h (sem_t_): Move here from semaphore.h; was the definition of sem_t. * semaphore.c: Wherever necessary, changed use of sem from that of a pointer to a pointer-pointer; added extra checks for a valid sem_t; NULL sem_t when it is destroyed; added extra checks when creating and destroying sem_t elements in the NEED_SEM code branches; changed from using a pthread_mutex_t ((*sem)->mutex) to CRITICAL_SECTION ((*sem)->sem_lock_cs) in NEED_SEM branches for access serialisation. 2001-06-06 Ross Johnson * mutex.c (pthread_mutexattr_init): Remove ptw32_mutex_default_kind. 2001-06-05 Ross Johnson * nonportable.c (pthread_mutex_setdefaultkind_np): Remove - should not have been included in the first place. (pthread_mutex_getdefaultkind_np): Likewise. * global.c (ptw32_mutex_default_kind): Likewise. * mutex.c (pthread_mutex_init): Remove use of ptw32_mutex_default_kind. * pthread.h (pthread_mutex_setdefaultkind_np): Likewise. (pthread_mutex_getdefaultkind_np): Likewise. * pthread.def (pthread_mutexattr_setkind_np): Added. (pthread_mutexattr_getkind_np): Likewise. * README: Many changes that should have gone in before the last snapshot. * README.NONPORTABLE: New - referred to by ANNOUNCE but never created; documents the non-portable routines included in the library - moved from README with new routines added. * ANNOUNCE (pthread_mutexattr_setkind_np): Added to compliance list. (pthread_mutexattr_getkind_np): Likewise. 2001-06-04 Ross Johnson * condvar.c: Add original description of the algorithm as developed by Terekhov and Thomas, plus reference to README.CV. 2001-06-03 Alexander Terekhov , Louis Thomas * condvar.c (pthread_cond_init): Completely revamped. (pthread_cond_destroy): Likewise. (ptw32_cond_wait_cleanup): Likewise. (ptw32_cond_timedwait): Likewise. (ptw32_cond_unblock): New general signaling routine. (pthread_cond_signal): Now calls ptw32_cond_unblock. (pthread_cond_broadcast): Likewise. * implement.h (pthread_cond_t_): Revamped. * README.CV: New; explanation of the above changes. 2001-05-30 Ross Johnson * pthread.h (rand_r): Fake using _seed argument to quell compiler warning (compiler should optimise this away later). * GNUmakefile (OPT): Leave symbolic information out of the library and increase optimisation level - for smaller faster prebuilt dlls. 2001-05-29 Milan Gardian * Makefile: fix typo. * pthreads.h: Fix problems with stdcall/cdecl conventions, in particular remove the need for PT_STDCALL everywhere; remove warning supression. * (errno): Fix the longstanding "inconsistent dll linkage" problem with errno; now also works with /MD debugging libs - warnings emerged when compiling pthreads library with /MD (or /MDd) compiler switch, instead of /MT (or /MTd) (i.e. when compiling pthreads using Multithreaded DLL CRT instead of Multithreaded statically linked CRT). * create.c (pthread_create): Likewise; fix typo. * private.c (ptw32_threadStart): Eliminate use of terminate() which doesn't throw exceptions. * Remove unnecessary #includes from a number of modules - [I had to #include malloc.h in implement.h for gcc - rpj]. 2001-05-29 Thomas Pfaff * pthread.h (PTHREAD_MUTEX_DEFAULT): New; equivalent to PTHREAD_MUTEX_DEFAULT_NP. * (PTHREAD_MUTEX_NORMAL): Similarly. * (PTHREAD_MUTEX_ERRORCHECK): Similarly. * (PTHREAD_MUTEX_RECURSIVE): Similarly. * (pthread_mutex_setdefaultkind_np): New; Linux compatibility stub for pthread_mutexattr_settype. * (pthread_mutexattr_getkind_np): New; Linux compatibility stub for pthread_mutexattr_gettype. * mutex.c (pthread_mutexattr_settype): New; allow the following types of mutex: PTHREAD_MUTEX_DEFAULT_NP PTHREAD_MUTEX_NORMAL_NP PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_RECURSIVE_NP * Note that PTHREAD_MUTEX_DEFAULT is equivalent to PTHREAD_MUTEX_NORMAL - ie. mutexes should no longer be recursive by default, and a thread will deadlock if it tries to relock a mutex it already owns. This is inline with other pthreads implementations. * (pthread_mutex_lock): Process the lock request according to the mutex type. * (pthread_mutex_init): Eliminate use of Win32 mutexes as the basis of POSIX mutexes - instead, a combination of one critical section and one semaphore are used in conjunction with Win32 Interlocked* routines. * (pthread_mutex_destroy): Likewise. * (pthread_mutex_lock): Likewise. * (pthread_mutex_trylock): Likewise. * (pthread_mutex_unlock): Likewise. * Use longjmp/setjmp to implement cancelation when building the library using a C compiler which doesn't support exceptions, e.g. gcc -x c (note that gcc -x c++ uses exceptions). * Also fixed some of the same typos and eliminated PT_STDCALL as Milan Gardian's patches above. 2001-02-07 Alexander Terekhov * rwlock.c: Revamped. * implement.h (pthread_rwlock_t_): Redefined. This implementation does not have reader/writer starvation problem. Rwlock attempts to behave more like a normal mutex with races and scheduling policy determining who is more important; It also supports recursive locking, has less synchronization overhead (no broadcasts at all, readers are not blocked on any condition variable) and seem to be faster than the current implementation [W98 appears to be approximately 15 percent faster at least - on top of speed increase from Thomas Pfaff's changes to mutex.c - rpj]. 2000-12-29 Ross Johnson * Makefile: Back-out "for" loops which don't work. * GNUmakefile: Remove the fake.a target; add the "realclean" target; don't remove built libs under the "clean" target. * config.h: Add a guard against multiple inclusion. * semaphore.h: Add some defines from config.h to make semaphore.h independent of config.h when building apps. * pthread.h (_errno): Back-out previous fix until we know how to fix it properly. * implement.h (lockCount): Add missing element to pthread_mutex_t_. * sync.c (pthread_join): Spelling fix in comment. * private.c (ptw32_threadStart): Reset original termination function (C++). (ptw32_threadStart): Cleanup detached threads early in case the library is statically linked. (ptw32_callUserDestroyRoutines): Remove [SEH] __try block from destructor call so that unhandled exceptions will be passed through to the system; call terminate() from [C++] try block for the same reason. * tsd.c (pthread_getspecific): Add comment. * mutex.c (pthread_mutex_init): Initialise new elements in pthread_mutex_t. (pthread_mutex_unlock): Invert "pthread_equal()" test. 2000-12-28 Ross Johnson * semaphore.c (mode_t): Use ifndef HAVE_MODE_T to include definition. * config.h.in (HAVE_MODE_T): Added. (_UWIN): Start adding defines for the UWIN package. * private.c (ptw32_threadStart): Unhandled exceptions are now passed through to the system to deal with. This is consistent with normal Windows behaviour. C++ applications may use set_terminate() to override the default behaviour which is to call ptw32_terminate(). Ptw32_terminate() cleans up some POSIX thread stuff before calling the system default function which calls abort(). The users termination function should conform to standard C++ semantics which is to not return. It should exit the thread (call pthread_exit()) or exit the application. * private.c (ptw32_terminate): Added as the default set_terminate() function. It calls the system default function after cleaning up some POSIX thread stuff. * implement.h (ptw32_try_enter_critical_section): Move declaration. * global.c (ptw32_try_enter_critical_section): Moved from dll.c. * dll.c: Move process and thread attach/detach code into functions in nonportable.c. * nonportable.c (pthread_win32_process_attach_np): Process attach code from dll.c is now available to static linked applications. * nonportable.c (pthread_win32_process_detach_np): Likewise. * nonportable.c (pthread_win32_thread_attach_np): Likewise. * nonportable.c (pthread_win32_thread_detach_np): Likewise. * pthread.h: Add new non-portable prototypes for static linked applications. * GNUmakefile (OPT): Increase optimisation flag and remove debug info flag. * pthread.def: Add new non-portable exports for static linked applications. 2000-12-11 Ross Johnson * FAQ: Update Answer 6 re getting a fully working Mingw32 built library. 2000-10-10 Steven Reddie * misc.c (pthread_self): Restore Win32 "last error" cleared by TlsGetValue() call in pthread_getspecific() 2000-09-20 Arthur Kantor * mutex.c (pthread_mutex_lock): Record the owner of the mutex. This requires also keeping count of recursive locks ourselves rather than leaving it to Win32 since we need to know when to NULL the thread owner when the mutex is unlocked. (pthread_mutex_trylock): Likewise. (pthread_mutex_unlock): Check that the calling thread owns the mutex, decrement the recursive lock count, and NULL the owner if zero. Return EPERM if the mutex is owned by another thread. * implement.h (pthread_mutex_t_): Add ownerThread and lockCount members. 2000-09-13 Jef Gearhart * mutex.c (pthread_mutex_init): Call TryEnterCriticalSection through the pointer rather than directly so that the dll can load on Windows versions that can't resolve the function, eg. Windows 95 2000-09-09 Ross Johnson * pthread.h (ctime_r): Fix arg. 2000-09-08 Ross Johnson * GNUmakefile(_WIN32_WINNT=0x400): Define in CFLAGS; doesn't seem to be needed though. * cancel.c (pthread_cancel): Must get "self" through calling pthread_self() which will ensure a POSIX thread struct is built for non-POSIX threads; return an error if this fails - Ollie Leahy (pthread_setcancelstate): Likewise. (pthread_setcanceltype): Likewise. * misc.c (ptw32_cancelable_wait): Likewise. * private.c (ptw32_tkAssocCreate): Remove unused #if 0 wrapped code. * pthread.h (ptw32_get_exception_services_code): Needed to be forward declared unconditionally. 2000-09-06 Ross Johnson * cancel.c (pthread_cancel): If called from the main thread "self" would be NULL; get "self" via pthread_self() instead of directly from TLS so that an implicit pthread object is created. * misc.c (pthread_equal): Strengthen test for NULLs. 2000-09-02 Ross Johnson * condvar.c (ptw32_cond_wait_cleanup): Ensure that all waking threads check if they are the last, and notify the broadcaster if so - even if an error occurs in the waiter. * semaphore.c (_decrease_semaphore): Should be a call to ptw32_decrease_semaphore. (_increase_semaphore): Should be a call to ptw32_increase_semaphore. * misc.c (ptw32_cancelable_wait): Renamed from CancelableWait. * rwlock.c (_rwlock_check*): Renamed to ptw32_rwlock_check*. * mutex.c (_mutex_check*): Renamed to ptw32_mutex_check*. * condvar.c (cond_timed*): Renamed to ptw32_cond_timed*. (_cond_check*): Renamed to ptw32_cond_check*. (cond_wait_cleanup*): Rename to ptw32_cond_wait_cleanup*. (ptw32_cond_timedwait): Add comments. 2000-08-22 Ross Johnson * private.c (ptw32_throw): Fix exception test; move exceptionInformation declaration. * tsd.c (pthread_key_create): newkey wrongly declared. * pthread.h: Fix comment block. 2000-08-18 Ross Johnson * mutex.c (pthread_mutex_destroy): Check that the mutex isn't held; invalidate the mutex as early as possible to avoid contention; not perfect - FIXME! * rwlock.c (pthread_rwlock_init): Remove redundant assignment to "rw". (pthread_rwlock_destroy): Invalidate the rwlock before freeing up any of it's resources - to avoid contention. * private.c (ptw32_tkAssocCreate): Change assoc->lock to use a dynamically initialised mutex - only consumes a W32 mutex or critical section when first used, not before. * mutex.c (pthread_mutex_init): Remove redundant assignment to "mx". (pthread_mutexattr_destroy): Set attribute to NULL before freeing it's memory - to avoid contention. * implement.h (PTW32_EPS_CANCEL/PTW32_EPS_EXIT): Must be defined for all compilers - used as generic exception selectors by ptw32_throw(). * Several: Fix typos from scripted edit session yesterday. * nonportable.c (pthread_mutexattr_setforcecs_np): Moved this function from mutex.c. (pthread_getw32threadhandle_np): New function to return the win32 thread handle that the POSIX thread is using. * mutex.c (pthread_mutexattr_setforcecs_np): Moved to new file "nonportable.c". * pthread.h (PTW32_BUILD): Only redefine __except and catch compiler keywords if we aren't building the library (ie. PTW32_BUILD is not defined) - this is safer than defining and then undefining if not building the library. * implement.h: Remove __except and catch undefines. * Makefile (CFLAGS): Define PTW32_BUILD. * GNUmakefile (CFLAGS): Define PTW32_BUILD. * All appropriate: Change Pthread_exception* to ptw32_exception* to be consistent with internal identifier naming. * private.c (ptw32_throw): New function to provide a generic exception throw for all internal exceptions and EH schemes. (ptw32_threadStart): pthread_exit() value is now returned via the thread structure exitStatus element. * exit.c (pthread_exit): pthread_exit() value is now returned via the thread structure exitStatus element. * cancel.c (ptw32_cancel_self): Now uses ptw32_throw. (pthread_setcancelstate): Ditto. (pthread_setcanceltype): Ditto. (pthread_testcancel): Ditto. (pthread_cancel): Ditto. * misc.c (CancelableWait): Ditto. * exit.c (pthread_exit): Ditto. * All applicable: Change PTW32_ prefix to PTW32_ prefix to remove leading underscores from private library identifiers. 2000-08-17 Ross Johnson * All applicable: Change _pthread_ prefix to ptw32_ prefix to remove leading underscores from private library identifiers (single and double leading underscores are reserved in the ANSI C standard for compiler implementations). * tsd.c (pthread_create_key): Initialise temporary key before returning it's address to avoid race conditions. 2000-08-13 Ross Johnson * errno.c: Add _MD precompile condition; thus far had no effect when using /MD compile option but I thnk it should be there. * exit.c: Add __cplusplus to various #if lines; was compiling SEH code even when VC++ had C++ compile options. * private.c: ditto. * create.c (pthread_create): Add PT_STDCALL macro to function pointer arg in _beginthread(). * pthread.h: PT_STDCALL really does need to be defined in both this and impliment.h; don't set it to __cdecl - this macro is only used to extend function pointer casting for functions that will be passed as parameters. (~PThreadCleanup): add cast and group expression. (_errno): Add _MD compile conditional. (PtW32NoCatchWarn): Change pragma message. * implement.h: Move and change PT_STDCALL define. * need_errno.h: Add _MD to compilation conditional. * GNUmakefile: Substantial rewrite for new naming convention; set for nil optimisation (turn it up when we have a working library build; add target "fake.a" to build a libpthreadw32.a from the VC++ built DLL pthreadVCE.dll. * pthread.def (LIBRARY): Don't specify in the .def file - it is specified on the linker command line since we now use the same .def file for variously named .dlls. * Makefile: Substantial rewrite for new naming convention; default nmake target only issues a help message; run nmake with specific target corresponding to the EH scheme being used. * README: Update information; add naming convention explanation. * ANNOUNCE: Update information. 2000-08-12 Ross Johnson * pthread.h: Add compile-time message when using MSC_VER compiler and C++ EH to warn application programmers to use PtW32Catch instead of catch(...) if they want cancelation and pthread_exit to work. * implement.h: Remove #include ; we use our own local semaphore.h. 2000-08-10 Ross Johnson * cleanup.c (pthread_pop_cleanup): Remove _pthread prefix from __except and catch keywords; implement.h now simply undefines ptw32__except and ptw32_catch if defined; VC++ was not textually substituting ptw32_catch etc back to catch as it was redefined; the reason for using the prefixed version was to make it clear that it was not using the pthread.h redefined catch keyword. * private.c (ptw32_threadStart): Ditto. (ptw32_callUserDestroyRoutines): Ditto. * implement.h (ptw32__except): Remove #define. (ptw32_catch): Remove #define. * GNUmakefile (pthread.a): New target to build libpthread32.a from pthread.dll using dlltool. * buildlib.bat: Duplicate cl commands with args to build C++ EH version of pthread.dll; use of .bat files is redundant now that nmake compatible Makefile is included; used as a kludge only now. * Makefile: Localise some macros and fix up the clean: target to extend it and work properly. * CONTRIBUTORS: Add contributors. * ANNOUNCE: Updated. * README: Updated. 2000-08-06 Ross Johnson * pthread.h: Remove #warning - VC++ doesn't accept it. 2000-08-05 Ross Johnson * pthread.h (PtW32CatchAll): Add macro. When compiling applications using VC++ with C++ EH rather than SEH 'PtW32CatchAll' must be used in place of any 'catch( ... )' if the application wants pthread cancelation or pthread_exit() to work. 2000-08-03 Ross Johnson * pthread.h: Add a base class ptw32_exception for library internal exceptions and change the "catch" re-define macro to use it. 2000-08-02 Ross Johnson * GNUmakefile (CFLAGS): Add -mthreads. Add new targets to generate cpp and asm output. * sync.c (pthread_join): Remove dead code. 2000-07-25 Tristan Savatier * sched.c (sched_get_priority_max): Handle different WinCE and Win32 priority values together. (sched_get_priority_min): Ditto. 2000-07-25 Ross Johnson * create.c (pthread_create): Force new threads to wait until pthread_create has the new thread's handle; we also retain a local copy of the handle for internal use until pthread_create returns. * private.c (ptw32_threadStart): Initialise ei[]. (ptw32_threadStart): When beginthread is used to start the thread, force waiting until the creator thread had the thread handle. * cancel.c (ptw32_cancel_thread): Include context switch code for defined(_X86_) environments in addition to _M_IX86. * rwlock.c (pthread_rwlock_destroy): Assignment changed to avoid compiler warning. * private.c (ptw32_get_exception_services_code): Cast NULL return value to avoid compiler warning. * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable to avoid compiler warnings. * misc.c (ptw32_new): Change "new" variable to "t" to avoid confusion with the C++ keyword of the same name. * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable. (cond_timedwait): Remove unused local variables. to avoid compiler warnings. * dll.c (dllMain): Remove 2000-07-21 change - problem appears to be in pthread_create(). 2000-07-22 Ross Johnson * tsd.c (pthread_key_create): If a destructor was given and the pthread_mutex_init failed, then would try to reference a NULL pointer (*key); eliminate this section of code by using a dynamically initialised mutex (PTHREAD_MUTEX_INITIALIZER). * tsd.c (pthread_setspecific): Return an error if unable to set the value; simplify cryptic conditional. * tsd.c (pthread_key_delete): Locking threadsLock relied on mutex_lock returning an error if the key has no destructor. ThreadsLock is only initialised if the key has a destructor. Making this mutex a static could reduce the number of mutexes used by an application since it is actually created only at first use and it's often destroyed soon after. 2000-07-22 Ross Johnson * FAQ: Added Q5 and Q6. 2000-07-21 David Baggett * dll.c: Include resource leakage work-around. This is a partial FIXME which doesn't stop all leakage. The real problem needs to be found and fixed. 2000-07-21 Ross Johnson * create.c (pthread_create): Set threadH to 0 (zero) everywhere. Some assignments were using NULL. Maybe it should be NULL everywhere - need to check. (I know they are nearly always the same thing - but not by definition.) * misc.c (pthread_self): Try to catch NULL thread handles at the point where they might be generated, even though they should always be valid at this point. * tsd.c (pthread_setspecific): return an error value if pthread_self() returns NULL. * sync.c (pthread_join): return an error value if pthread_self() returns NULL. * signal.c (pthread_sigmask): return an error value if pthread_self() returns NULL. 2000-03-02 Ross Johnson * attr.c (pthread_attr_init): Set default stacksize to zero (0) rather than PTHREAD_STACK_MIN even though these are now the same. * pthread.h (PTHREAD_STACK_MIN): Lowered to 0. 2000-01-28 Ross Johnson * mutex.c (pthread_mutex_init): Free mutex if it has been alloced; if critical sections can be used instead of Win32 mutexes, test that the critical section works and return an error if not. 2000-01-07 Ross Johnson * cleanup.c (pthread_pop_cleanup): Include SEH code only if MSC is not compiling as C++. (pthread_push_cleanup): Include SEH code only if MSC is not compiling as C++. * pthread.h: Include SEH code only if MSC is not compiling as C++. * implement.h: Include SEH code only if MSC is not compiling as C++. * cancel.c (ptw32_cancel_thread): Add _M_IX86 check. (pthread_testcancel): Include SEH code only if MSC is not compiling as C++. (ptw32_cancel_self): Include SEH code only if MSC is not compiling as C++. 2000-01-06 Erik Hensema * Makefile: Remove inconsistencies in 'cl' args 2000-01-04 Ross Johnson * private.c (ptw32_get_exception_services_code): New; returns value of EXCEPTION_PTW32_SERVICES. (ptw32_processInitialize): Remove initialisation of ptw32_exception_services which is no longer needed. * pthread.h (ptw32_exception_services): Remove extern. (ptw32_get_exception_services_code): Add function prototype; use this to return EXCEPTION_PTW32_SERVICES value instead of using the ptw32_exception_services variable which I had trouble exporting through pthread.def. * global.c (ptw32_exception_services): Remove declaration. 1999-11-22 Ross Johnson * implement.h: Forward declare ptw32_new(); * misc.c (ptw32_new): New; alloc and initialise a new pthread_t. (pthread_self): New thread struct is generated by new routine ptw32_new(). * create.c (pthread_create): New thread struct is generated by new routine ptw32_new(). 1999-11-21 Ross Johnson * global.c (ptw32_exception_services): Declare new variable. * private.c (ptw32_threadStart): Destroy thread's cancelLock mutex; make 'catch' and '__except' usageimmune to redfinitions in pthread.h. (ptw32_processInitialize): Init new constant ptw32_exception_services. * create.c (pthread_create): Initialise thread's cancelLock mutex. * cleanup.c (pthread_pop_cleanup): Make 'catch' and '__except' usage immune to redfinition s in pthread.h. * private.c: Ditto. * pthread.h (catch): Redefine 'catch' so that C++ applications won't catch our internal exceptions. (__except): ditto for __except. * implement.h (ptw32_catch): Define internal version of 'catch' because 'catch' is redefined by pthread.h. (__except): ditto for __except. (struct pthread_t_): Add cancelLock mutex for async cancel safety. 1999-11-21 Jason Nye , Erik Hensema * cancel.c (ptw32_cancel_self): New; part of the async cancellation implementation. (ptw32_cancel_thread): Ditto; this function is X86 processor specific. (pthread_setcancelstate): Add check for pending async cancel request and cancel the calling thread if required; add async-cancel safety lock. (pthread_setcanceltype): Ditto. 1999-11-13 Erik Hensema * configure.in (AC_OUTPUT): Put generated output into GNUmakefile rather than Makefile. Makefile will become the MSC nmake compatible version 1999-11-13 John Bossom (John.Bossom@cognos.com> * misc.c (pthread_self): Add a note about GetCurrentThread returning a pseudo-handle 1999-11-10 Todd Owen * dll.c (dllMain): Free kernel32 ASAP. If TryEnterCriticalSection is not being used, then free the kernel32.dll handle now, rather than leaving it until DLL_PROCESS_DETACH. Note: this is not a pedantic exercise in freeing unused resources! It is a work-around for a bug in Windows 95 (see microsoft knowledge base article, Q187684) which does Bad Things when FreeLibrary is called within the DLL_PROCESS_DETACH code, in certain situations. Since w95 just happens to be a platform which does not provide TryEnterCriticalSection, the bug will be effortlessly avoided. 1999-11-10 Ross Johnson * sync.c (pthread_join): Make it a deferred cancelation point. * misc.c (pthread_self): Explicitly initialise implicitly created thread state to default values. 1999-11-05 Tristan Savatier * pthread.h (winsock.h): Include unconditionally. (ETIMEDOUT): Change fallback value to that defined by winsock.h. * general: Patched for portability to WinCE. The details are described in the file WinCE-PORT. Follow the instructions in README.WinCE to make the appropriate changes in config.h. 1999-10-30 Erik Hensema * create.c (pthread_create): Explicitly initialise thread state to default values. * cancel.c (pthread_setcancelstate): Check for NULL 'oldstate' for compatibility with Solaris pthreads; (pthread_setcanceltype): ditto: 1999-10-23 Erik Hensema * pthread.h (ctime_r): Fix incorrect argument "_tm" 1999-10-21 Aurelio Medina * pthread.h (_POSIX_THREADS): Only define it if it isn't already defined. Projects may need to define this on the CC command line under Win32 as it doesn't have unistd.h 1999-10-17 Ross Johnson * rwlock.c (pthread_rwlock_destroy): Add cast to remove compile warning. * condvar.c (pthread_cond_broadcast): Only release semaphores if there are waiting threads. 1999-10-15 Lorin Hochstein , Peter Slacik * condvar.c (cond_wait_cleanup): New static cleanup handler for cond_timedwait; (cond_timedwait): pthread_cleanup_push args changed; canceling a thread while it's in pthread_cond_wait will now decrement the waiters count and cleanup if it's the last waiter. 1999-10-15 Graham Dumpleton * condvar.c (cond_wait_cleanup): the last waiter will now reset the CV's wasBroadcast flag Thu Sep 16 1999 Ross Johnson * rwlock.c (pthread_rwlock_destroy): Add serialisation. (_rwlock_check_need_init): Check for detroyed rwlock. * rwlock.c: Check return codes from _rwlock_check_need_init(); modify comments; serialise access to rwlock objects during operations; rename rw_mutex to rw_lock. * implement.h: Rename rw_mutex to rw_lock. * mutex.c (pthread_mutex_destroy): Add serialisation. (_mutex_check_need_init): Check for detroyed mutex. * condvar.c (pthread_cond_destroy): Add serialisation. (_cond_check_need_init): Check for detroyed condvar. * mutex.c: Modify comments. * condvar.c: Modify comments. 1999-08-10 Aurelio Medina * implement.h (pthread_rwlock_t_): Add. * pthread.h (pthread_rwlock_t): Add. (PTHREAD_RWLOCK_INITIALIZER): Add. Add rwlock function prototypes. * rwlock.c: New module. * pthread.def: Add new rwlock functions. * private.c (ptw32_processInitialize): initialise ptw32_rwlock_test_init_lock critical section. * global.c (ptw32_rwlock_test_init_lock): Add. * mutex.c (pthread_mutex_destroy): Don't free mutex memory if mutex is PTHREAD_MUTEX_INITIALIZER and has not been initialised yet. 1999-08-08 Milan Gardian * mutex.c (pthread_mutex_destroy): Free mutex memory. 1999-08-22 Ross Johnson * exit.c (pthread_exit): Fix reference to potentially uninitialised pointer. 1999-08-21 Ross Johnson * private.c (ptw32_threadStart): Apply fix of 1999-08-19 this time to C++ and non-trapped C versions. Ommitted to do this the first time through. 1999-08-19 Ross Johnson * private.c (ptw32_threadStart): Return exit status from the application thread startup routine. - Milan Gardian 1999-08-18 John Bossom * exit.c (pthread_exit): Put status into pthread_t->exitStatus * private.c (ptw32_threadStart): Set pthread->exitStatus on exit of try{} block. * sync.c (pthread_join): use pthread_exitStatus value if the thread exit doesn't return a value (for Mingw32 CRTDLL which uses endthread instead of _endthreadex). Tue Aug 17 20:17:58 CDT 1999 Mumit Khan * create.c (pthread_create): Add CRTDLL suppport. * exit.c (pthread_exit): Likewise. * private.c (ptw32_threadStart): Likewise. (ptw32_threadDestroy): Likewise. * sync.c (pthread_join): Likewise. * tests/join1.c (main): Warn about partial support for CRTDLL. Tue Aug 17 20:00:08 1999 Mumit Khan * Makefile.in (LD): Delete entry point. * acconfig.h (STDCALL): Delete unused macro. * configure.in: Remove test for STDCALL. * config.h.in: Regenerate. * errno.c (_errno): Fix self type. * pthread.h (PT_STDCALL): Move from here to * implement.h (PT_STDCALL): here. (ptw32_threadStart): Fix prototype. * private.c (ptw32_threadStart): Likewise. 1999-08-14 Ross Johnson * exit.c (pthread_exit): Don't call pthread_self() but get thread handle directly from TSD for efficiency. 1999-08-12 Ross Johnson * private.c (ptw32_threadStart): ei[] only declared if _MSC_VER. * exit.c (pthread_exit): Check for implicitly created threads to avoid raising an unhandled exception. 1999-07-12 Peter Slacik * condvar.c (pthread_cond_destroy): Add critical section. (cond_timedwait): Add critical section; check for timeout waiting on semaphore. (pthread_cond_broadcast): Add critical section. 1999-07-09 Lorin Hochstein , John Bossom The problem was that cleanup handlers were not executed when pthread_exit() was called. * implement.h (pthread_t_): Add exceptionInformation element for C++ per-thread exception information. (general): Define and rename exceptions. 1999-07-09 Ross Johnson * misc.c (CancelableWait): PTW32_EPS_CANCEL (SEH) and ptw32_exception_cancel (C++) used to identify the exception. * cancel.c (pthread_testcancel): PTW32_EPS_CANCEL (SEH) and ptw32_exception_cancel (C++) used to identify the exception. * exit.c (pthread_exit): throw/raise an exception to return to ptw32_threadStart() to exit the thread. PTW32_EPS_EXIT (SEH) and ptw32_exception_exit (C++) used to identify the exception. * private.c (ptw32_threadStart): Add pthread_exit exception trap; clean up and exit the thread directly rather than via pthread_exit(). Sun May 30 00:25:02 1999 Ross Johnson * semaphore.h (mode_t): Conditionally typedef it. Fri May 28 13:33:05 1999 Mark E. Armstrong * condvar.c (pthread_cond_broadcast): Fix possible memory fault Thu May 27 13:08:46 1999 Peter Slacik * condvar.c (pthread_cond_broadcast): Fix logic bug Thu May 27 13:08:46 1999 Bossom, John * condvar.c (pthread_cond_broadcast): optimise sem_post loop Fri May 14 12:13:18 1999 Mike Russo * attr.c (pthread_attr_setdetachstate): Fix logic bug Sat May 8 09:42:30 1999 Ross Johnson * pthread.def (sem_open): Add. (sem_close): Add. (sem_unlink): Add. (sem_getvalue): Add. * FAQ (Question 3): Add. Thu Apr 8 01:16:23 1999 Ross Johnson * semaphore.c (sem_open): New function; returns an error (ENOSYS). (sem_close): ditto. (sem_unlink): ditto. (sem_getvalue): ditto. * semaphore.h (_POSIX_SEMAPHORES): define. Wed Apr 7 14:09:52 1999 Ross Johnson * errno.c (_REENTRANT || _MT): Invert condition. * pthread.h (_errno): Conditionally include prototype. Wed Apr 7 09:37:00 1999 Ross Johnson * *.c (comments): Remove individual attributions - these are documented sufficiently elsewhere. * implement.h (pthread.h): Remove extraneous include. Sun Apr 4 11:05:57 1999 Ross Johnson * sched.c (sched.h): Include. * sched.h: New file for POSIX 1b scheduling. * pthread.h: Move opaque structures to implement.h; move sched_* prototypes out and into sched.h. * implement.h: Add opaque structures from pthread.h. * sched.c (sched_yield): New function. * condvar.c (ptw32_sem_*): Rename to sem_*; except for ptw32_sem_timedwait which is an private function. Sat Apr 3 23:28:00 1999 Ross Johnson * Makefile.in (OBJS): Add errno.o. Fri Apr 2 11:08:50 1999 Ross Johnson * implement.h (ptw32_sem_*): Remove prototypes now defined in semaphore.h. * pthread.h (sempahore.h): Include. * semaphore.h: New file for POSIX 1b semaphores. * semaphore.c (ptw32_sem_timedwait): Moved to private.c. * pthread.h (ptw32_sem_t): Change to sem_t. * private.c (ptw32_sem_timedwait): Moved from semaphore.c; set errno on error. * pthread.h (pthread_t_): Add per-thread errno element. Fri Apr 2 11:08:50 1999 John Bossom * semaphore.c (ptw32_sem_*): Change to sem_*; these functions will be exported from the library; set errno on error. * errno.c (_errno): New file. New function. Fri Mar 26 14:11:45 1999 Tor Lillqvist * semaphore.c (ptw32_sem_timedwait): Check for negative milliseconds. Wed Mar 24 11:32:07 1999 John Bossom * misc.c (CancelableWait): Initialise exceptionInformation[2]. (pthread_self): Get a real Win32 thread handle for implicit threads. * cancel.c (pthread_testcancel): Initialise exceptionInformation[2]. * implement.h (SE_INFORMATION): Fix values. * private.c (ptw32_threadDestroy): Close the thread handle. Fri Mar 19 12:57:27 1999 Ross Johnson * cancel.c (comments): Update and cleanup. Fri Mar 19 09:12:59 1999 Ross Johnson * private.c (ptw32_threadStart): status returns PTHREAD_CANCELED. * pthread.h (PTHREAD_CANCELED): defined. Tue Mar 16 1999 Ross Johnson * all: Add GNU LGPL and Copyright and Warranty. Mon Mar 15 00:20:13 1999 Ross Johnson * condvar.c (pthread_cond_init): fix possible uninitialised use of cv. Sun Mar 14 21:01:59 1999 Ross Johnson * condvar.c (pthread_cond_destroy): don't do full cleanup if static initialised cv has never been used. (cond_timedwait): check result of auto-initialisation. Thu Mar 11 09:01:48 1999 Ross Johnson * pthread.h (pthread_mutex_t): revert to (pthread_mutex_t *); define a value to serve as PTHREAD_MUTEX_INITIALIZER. (pthread_mutex_t_): remove staticinit and valid elements. (pthread_cond_t): revert to (pthread_cond_t_ *); define a value to serve as PTHREAD_COND_INITIALIZER. (pthread_cond_t_): remove staticinit and valid elements. * mutex.c (pthread_mutex_t args): adjust indirection of references. (all functions): check for PTHREAD_MUTEX_INITIALIZER value; check for NULL (invalid). * condvar.c (pthread_cond_t args): adjust indirection of references. (all functions): check for PTHREAD_COND_INITIALIZER value; check for NULL (invalid). Wed Mar 10 17:18:12 1999 Ross Johnson * misc.c (CancelableWait): Undo changes from Mar 8 and 7. Mon Mar 8 11:18:59 1999 Ross Johnson * misc.c (CancelableWait): Ensure cancelEvent handle is the lowest indexed element in the handles array. Enhance test for abandoned objects. * pthread.h (PTHREAD_MUTEX_INITIALIZER): Trailing elements not initialised are set to zero by the compiler. This avoids the problem of initialising the opaque critical section element in it. (PTHREAD_COND_INITIALIZER): Ditto. * semaphore.c (ptw32_sem_timedwait): Check sem == NULL earlier. Sun Mar 7 12:31:14 1999 Ross Johnson * condvar.c (pthread_cond_init): set semaphore initial value to 0, not 1. cond_timedwait was returning signaled immediately. * misc.c (CancelableWait): Place the cancel event handle first in the handle table for WaitForMultipleObjects. This ensures that the cancel event is recognised and acted apon if both objects happen to be signaled together. * private.c (ptw32_cond_test_init_lock): Initialise and destroy. * implement.h (ptw32_cond_test_init_lock): Add extern. * global.c (ptw32_cond_test_init_lock): Add declaration. * condvar.c (pthread_cond_destroy): check for valid initialised CV; flag destroyed CVs as invalid. (pthread_cond_init): pthread_cond_t is no longer just a pointer. This is because PTHREAD_COND_INITIALIZER needs state info to reside in pthread_cond_t so that it can initialise on first use. Will work on making pthread_cond_t (and other objects like it) opaque again, if possible, later. (cond_timedwait): add check for statically initialisation of CV; initialise on first use. (pthread_cond_signal): check for valid CV. (pthread_cond_broadcast): check for valid CV. (_cond_check_need_init): Add. * pthread.h (PTHREAD_COND_INITIALIZER): Fix. (pthread_cond_t): no longer a pointer to pthread_cond_t_. (pthread_cond_t_): add 'staticinit' and 'valid' elements. Sat Mar 6 1999 Ross Johnson * implement.h: Undate comments. Sun Feb 21 1999 Ross Johnson * pthread.h (PTHREAD_MUTEX_INITIALIZER): missing braces around cs element initialiser. 1999-02-21 Ben Elliston * pthread.h (pthread_exit): The return type of this function is void, not int. * exit.c (pthread_exit): Do not return 0. Sat Feb 20 16:03:30 1999 Ross Johnson * dll.c (DLLMain): Expand TryEnterCriticalSection support test. * mutex.c (pthread_mutex_trylock): The check for ptw32_try_enter_critical_section == NULL should have been removed long ago. Fri Feb 19 16:03:30 1999 Ross Johnson * sync.c (pthread_join): Fix pthread_equal() test. * mutex.c (pthread_mutex_trylock): Check mutex != NULL before using it. Thu Feb 18 16:17:30 1999 Ross Johnson * misc.c (pthread_equal): Fix inverted result. * Makefile.in: Use libpthread32.a as the name of the DLL export library instead of pthread.lib. * condvar.c (pthread_cond_init): cv could have been used unitialised; initialise. * create.c (pthread_create): parms could have been used unitialised; initialise. * pthread.h (struct pthread_once_t_): Remove redefinition. Sat Feb 13 03:03:30 1999 Ross Johnson * pthread.h (struct pthread_once_t_): Replaced. * misc.c (pthread_once): Replace with John Bossom's version; has lighter weight serialisation; fixes problem of not holding competing threads until after the init_routine completes. Thu Feb 11 13:34:14 1999 Ross Johnson * misc.c (CancelableWait): Change C++ exception throw. * sync.c (pthread_join): Change FIXME comment - issue resolved. Wed Feb 10 12:49:11 1999 Ross Johnson * configure: Various temporary changes. - Kevin Ruland * README: Update. * pthread.def (pthread_attr_getstackaddr): uncomment (pthread_attr_setstackaddr): uncomment Fri Feb 5 13:42:30 1999 Ross Johnson * semaphore.c: Comment format changes. Thu Feb 4 10:07:28 1999 Ross Johnson * global.c: Remove ptw32_exception instantiation. * cancel.c (pthread_testcancel): Change C++ exception throw. * implement.h: Remove extern declaration. Wed Feb 3 13:04:44 1999 Ross Johnson * cleanup.c: Rename ptw32_*_cleanup() to pthread_*_cleanup(). * pthread.def: Ditto. * pthread.h: Ditto. * pthread.def (pthread_cleanup_push): Remove from export list; the function is defined as a macro under all compilers. (pthread_cleanup_pop): Ditto. * pthread.h: Remove #if defined(). Wed Feb 3 10:13:48 1999 Ross Johnson * sync.c (pthread_join): Check for NULL value_ptr arg; check for detached threads. Tue Feb 2 18:07:43 1999 Ross Johnson * implement.h: Add #include . Change sem_t to ptw32_sem_t. Tue Feb 2 18:07:43 1999 Kevin Ruland * signal.c (pthread_sigmask): Add and modify casts. Reverse LHS/RHS bitwise assignments. * pthread.h: Remove #include . (PTW32_ATTR_VALID): Add cast. (struct pthread_t_): Add sigmask element. * dll.c: Add "extern C" for DLLMain. (DllMain): Add cast. * create.c (pthread_create): Set sigmask in thread. * condvar.c: Remove #include. Change sem_* to ptw32_sem_*. * attr.c: Changed #include. * Makefile.in: Additional targets and changes to build the library as a DLL. Fri Jan 29 11:56:28 1999 Ross Johnson * Makefile.in (OBJS): Add semaphore.o to list. * semaphore.c (ptw32_sem_timedwait): Move from private.c. Rename sem_* to ptw32_sem_*. * pthread.h (pthread_cond_t): Change type of sem_t. _POSIX_SEMAPHORES no longer defined. * semaphore.h: Contents moved to implement.h. Removed from source tree. * implement.h: Add semaphore function prototypes and rename all functions to prepend 'ptw32_'. They are now private to the pthreads-win32 implementation. * private.c: Change #warning. Move ptw32_sem_timedwait() to semaphore.c. * cleanup.c: Change #warning. * misc.c: Remove #include * pthread.def: Cleanup CVS merge conflicts. * global.c: Ditto. * ChangeLog: Ditto. * cleanup.c: Ditto. Sun Jan 24 01:34:52 1999 Ross Johnson * semaphore.c (sem_wait): Remove second arg to pthreadCancelableWait() call. Sat Jan 23 17:36:40 1999 Ross Johnson * pthread.def: Add new functions to export list. * pthread.h (PTHREAD_MUTEX_AUTO_CS_NP): New. (PTHREAD_MUTEX_FORCE_CS_NP): New. * README: Updated. Fri Jan 22 14:31:59 1999 Ross Johnson * Makefile.in (CFLAGS): Remove -fhandle-exceptions. Not needed with egcs. Add -g for debugging. * create.c (pthread_create): Replace __stdcall with PT_STDCALL macro. This is a hack and must be fixed. * misc.c (CancelableWait): Remove redundant statement. * mutex.c (pthread_mutexattr_init): Cast calloc return value. * misc.c (CancelableWait): Add cast. (pthread_self): Add cast. * exit.c (pthread_exit): Add cast. * condvar.c (pthread_condattr_init): Cast calloc return value. * cleanup.c: Reorganise conditional compilation. * attr.c (pthread_attr_init): Remove unused 'result'. Cast malloc return value. * private.c (ptw32_callUserDestroyRoutines): Redo conditional compilation. * misc.c (CancelableWait): C++ version uses 'throw'. * cancel.c (pthread_testcancel): Ditto. * implement.h (class ptw32_exception): Define for C++. * pthread.h: Fix C, C++, and Win32 SEH condition compilation mayhem around pthread_cleanup_* defines. C++ version now uses John Bossom's cleanup handlers. (pthread_attr_t): Make 'valid' unsigned. Define '_timeb' as 'timeb' for Ming32. Define PT_STDCALL as nothing for Mingw32. May be temporary. * cancel.c (pthread_testcancel): Cast return value. Wed Jan 20 09:31:28 1999 Ross Johnson * pthread.h (pthread_mutexattr_t): Changed to a pointer. * mutex.c (pthread_mutex_init): Conditionally create Win32 mutex - from John Bossom's implementation. (pthread_mutex_destroy): Conditionally close Win32 mutex - from John Bossom's implementation. (pthread_mutexattr_init): Replaced by John Bossom's version. (pthread_mutexattr_destroy): Ditto. (pthread_mutexattr_getpshared): New function from John Bossom's implementation. (pthread_mutexattr_setpshared): New function from John Bossom's implementation. Tue Jan 19 18:27:42 1999 Ross Johnson * pthread.h (pthreadCancelableTimedWait): New prototype. (pthreadCancelableWait): Remove second argument. * misc.c (CancelableWait): New static function is pthreadCancelableWait() renamed. (pthreadCancelableWait): Now just calls CancelableWait() with INFINITE timeout. (pthreadCancelableTimedWait): Just calls CancelableWait() with passed in timeout. Tue Jan 19 18:27:42 1999 Scott Lightner * private.c (ptw32_sem_timedwait): 'abstime' arg really is absolute time. Calculate relative time to wait from current time before passing timeout to new routine pthreadCancelableTimedWait(). Tue Jan 19 10:27:39 1999 Ross Johnson * pthread.h (pthread_mutexattr_setforcecs_np): New prototype. * mutex.c (pthread_mutexattr_init): Init 'pshared' and 'forcecs' attributes to 0. (pthread_mutexattr_setforcecs_np): New function (not portable). * pthread.h (pthread_mutex_t): Add 'mutex' element. Set to NULL in PTHREAD_MUTEX_INITIALIZER. The pthread_mutex_*() routines will try to optimise performance by choosing either mutexes or critical sections as the basis for pthread mutexes for each indevidual mutex. (pthread_mutexattr_t_): Add 'forcecs' element. Some applications may choose to force use of critical sections if they know that:- the mutex is PROCESS_PRIVATE and, either the OS supports TryEnterCriticalSection() or pthread_mutex_trylock() will never be called on the mutex. This attribute will be setable via a non-portable routine. Note: We don't yet support PROCESS_SHARED mutexes, so the implementation as it stands will default to Win32 mutexes only if the OS doesn't support TryEnterCriticalSection. On Win9x, and early versions of NT 'forcecs' will need to be set in order to get critical section based mutexes. Sun Jan 17 12:01:26 1999 Ross Johnson * pthread.h (PTHREAD_MUTEX_INITIALIZER): Init new 'staticinit' value to '1' and existing 'valid' value to '1'. * global.c (ptw32_mutex_test_init_lock): Add. * implement.h (ptw32_mutex_test_init_lock.): Add extern. * private.c (ptw32_processInitialize): Init critical section for global lock used by _mutex_check_need_init(). (ptw32_processTerminate): Ditto (:s/Init/Destroy/). * dll.c (dllMain): Move call to FreeLibrary() so that it is only called once when the process detaches. * mutex.c (_mutex_check_need_init): New static function to test and init PTHREAD_MUTEX_INITIALIZER mutexes. Provides serialised access to the internal state of the uninitialised static mutex. Called from pthread_mutex_trylock() and pthread_mutex_lock() which do a quick unguarded test to check if _mutex_check_need_init() needs to be called. This is safe as the test is conservative and is repeated inside the guarded section of _mutex_check_need_init(). Thus in all calls except the first calls to lock static mutexes, the additional overhead to lock any mutex is a single memory fetch and test for zero. * pthread.h (pthread_mutex_t_): Add 'staticinit' member. Mutexes initialised by PTHREAD_MUTEX_INITIALIZER aren't really initialised until the first attempt to lock it. Using the 'valid' flag (which flags the mutex as destroyed or not) to record this information would be messy. It is possible for a statically initialised mutex such as this to be destroyed before ever being used. * mutex.c (pthread_mutex_trylock): Call _mutex_check_need_init() to test/init PTHREAD_MUTEX_INITIALIZER mutexes. (pthread_mutex_lock): Ditto. (pthread_mutex_unlock): Add check to ensure we don't try to unlock an unitialised static mutex. (pthread_mutex_destroy): Add check to ensure we don't try to delete a critical section that we never created. Allows us to destroy a static mutex that has never been locked (and hence initialised). (pthread_mutex_init): Set 'staticinit' flag to 0 for the new mutex. Sun Jan 17 12:01:26 1999 Ross Johnson * private.c (ptw32_sem_timedwait): Move from semaphore.c. * semaphore.c : Remove redundant #includes. (ptw32_sem_timedwait): Move to private.c. (sem_wait): Add missing abstime arg to pthreadCancelableWait() call. Fri Jan 15 23:38:05 1999 Ross Johnson * condvar.c (cond_timedwait): Remove comment. Fri Jan 15 15:41:28 1999 Ross Johnson * pthread.h: Add new 'abstime' arg to pthreadCancelableWait() prototype. * condvar.c (cond_timedwait): New generalised function called by both pthread_cond_wait() and pthread_cond_timedwait(). This is essentially pthread_cond_wait() renamed and modified to add the 'abstime' arg and call the new ptw32_sem_timedwait() instead of sem_wait(). (pthread_cond_wait): Now just calls the internal static function cond_timedwait() with an INFINITE wait. (pthread_cond_timedwait): Now implemented. Calls the internal static function cond_timedwait(). * implement.h (ptw32_sem_timedwait): New internal function prototype. * misc.c (pthreadCancelableWait): Added new 'abstime' argument to allow shorter than INFINITE wait. * semaphore.c (ptw32_sem_timedwait): New function for internal use. This is essentially sem_wait() modified to add the 'abstime' arg and call the modified (see above) pthreadCancelableWait(). Thu Jan 14 14:27:13 1999 Ross Johnson * cleanup.c: Correct _cplusplus to __cplusplus wherever used. * Makefile.in: Add CC=g++ and add -fhandle-exceptions to CFLAGS. The derived Makefile will compile all units of the package as C++ so that those which include try/catch exception handling should work properly. The package should compile ok if CC=gcc, however, exception handling will not be included and thus thread cancellation, for example, will not work. * cleanup.c (ptw32_pop_cleanup): Add #warning to compile this file as C++ if using a cygwin32 environment. Perhaps the whole package should be compiled using g++ under cygwin. * private.c (ptw32_threadStart): Change #error directive into #warning and bracket for __CYGWIN__ and derivative compilers. Wed Jan 13 09:34:52 1999 Ross Johnson * build.bat: Delete old binaries before compiling/linking. Tue Jan 12 09:58:38 1999 Tor Lillqvist * dll.c: The Microsoft compiler pragmas probably are more appropriately protected by _MSC_VER than by _WIN32. * pthread.h: Define ETIMEDOUT. This should be returned by pthread_cond_timedwait which is not implemented yet as of snapshot-1999-01-04-1305. It was implemented in the older version. The Microsoft compiler pragmas probably are more appropriately protected by _MSC_VER than by _WIN32. * pthread.def: pthread_mutex_destroy was missing from the def file * condvar.c (pthread_cond_broadcast): Ensure we only wait on threads if there were any waiting on the condition. I think pthread_cond_broadcast should do the WaitForSingleObject only if cv->waiters > 0? Otherwise it seems to hang, at least in the testg thread program from glib. Tue Jan 12 09:58:38 1999 Ross Johnson * condvar.c (pthread_cond_timedwait): Fix function description comments. * semaphore.c (sem_post): Correct typo in comment. Mon Jan 11 20:33:19 1999 Ross Johnson * pthread.h: Re-arrange conditional compile of pthread_cleanup-* macros. * cleanup.c (ptw32_push_cleanup): Provide conditional compile of cleanup->prev. 1999-01-11 Tor Lillqvist * condvar.c (pthread_cond_init): Invert logic when testing the return value from calloc(). Sat Jan 9 14:32:08 1999 Ross Johnson * implement.h: Compile-time switch for CYGWIN derived environments to use CreateThread instead of _beginthreadex. Ditto for ExitThread. Patch provided by Anders Norlander . Tue Jan 5 16:33:04 1999 Ross Johnson * cleanup.c (ptw32_pop_cleanup): Add C++ version of __try/__except block. Move trailing "}" out of #ifdef _WIN32 block left there by (rpj's) mistake. * private.c: Remove #include which is included by pthread.h. 1998-12-11 Ben Elliston * README: Update info about subscribing to the mailing list. Mon Jan 4 11:23:40 1999 Ross Johnson * all: No code changes, just cleanup. - remove #if 0 /* Pre Bossom */ enclosed code. - Remove some redundant #includes. * pthread.h: Update implemented/unimplemented routines list. * Tag the bossom merge branch getting ready to merge back to main trunk. Tue Dec 29 13:11:16 1998 Ross Johnson * implement.h: Move the following struct definitions to pthread.h: pthread_t_, pthread_attr_t_, pthread_mutex_t_, pthread_mutex_t_, pthread_mutexattr_t_, pthread_key_t_, pthread_cond_t_, pthread_condattr_t_, pthread_once_t_. * pthread.h: Add "_" prefix to pthread_push_cleanup and pthread_pop_cleanup internal routines, and associated struct and typedefs. * buildlib.bat: Add compile command for semaphore.c * pthread.def: Comment out pthread_atfork routine name. Now unimplemented. * tsd.c (pthread_setspecific): Rename tkAssocCreate to ptw32_tkAssocCreate. (pthread_key_delete): Rename tkAssocDestroy to ptw32_tkAssocDestroy. * sync.c (pthread_join): Rename threadDestroy to ptw32_threadDestroy * sched.c (is_attr): attr is now **attr (was *attr), so add extra NULL pointer test. (pthread_attr_setschedparam): Increase redirection for attr which is now a **. (pthread_attr_getschedparam): Ditto. (pthread_setschedparam): Change thread validation and rename "thread" Win32 thread Handle element name to match John Bossom's version. (pthread_getschedparam): Ditto. * private.c (ptw32_threadDestroy): Rename call to callUserDestroyRoutines() as ptw32_callUserDestroyRoutines() * misc.c: Add #include "implement.h". * dll.c: Remove defined(KLUDGE) wrapped code. * fork.c: Remove redefinition of ENOMEM. Remove pthread_atfork() and fork() with #if 0/#endif. * create.c (pthread_create): Rename threadStart and threadDestroy calls to ptw32_threadStart and ptw32_threadDestroy. * implement.h: Rename "detachedstate" to "detachstate". * attr.c: Rename "detachedstate" to "detachstate". Mon Dec 28 09:54:39 1998 John Bossom * semaphore.c: Initial version. * semaphore.h: Initial version. Mon Dec 28 09:54:39 1998 Ross Johnson * pthread.h (pthread_attr_t_): Change to *pthread_attr_t. Mon Dec 28 09:54:39 1998 John Bossom, Ben Elliston * attr.c (pthread_attr_setstacksize): Merge with John's version. (pthread_attr_getstacksize): Merge with John's version. (pthread_attr_setstackaddr): Merge with John's version. (pthread_attr_getstackaddr): Merge with John's version. (pthread_attr_init): Merge with John's version. (pthread_attr_destroy): Merge with John's version. (pthread_attr_getdetachstate): Merge with John's version. (pthread_attr_setdetachstate): Merge with John's version. (is_attr): attr is now **attr (was *attr), so add extra NULL pointer test. Mon Dec 28 09:54:39 1998 Ross Johnson * implement.h (pthread_attr_t_): Add and rename elements in JEB's version to correspond to original, so that it can be used with original attr routines. * pthread.h: Add #endif at end which was truncated in merging. Sun Dec 20 14:51:58 1998 Ross Johnson * misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard but provides a hook that can be used to implement cancellation points in applications that use this library. * pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses try/catch to emulate John Bossom's WIN32 __try/__finally behaviour. In the WIN32 version __finally block, add a test for AbnormalTermination otherwise cleanup is only run if the cleanup_pop execute arg is non-zero. Cancellation should cause the cleanup to run irrespective of the execute arg. * condvar.c (pthread_condattr_init): Replaced by John Bossom's version. (pthread_condattr_destroy): Replaced by John Bossom's version. (pthread_condattr_getpshared): Replaced by John Bossom's version. (pthread_condattr_setpshared): Replaced by John Bossom's version. (pthread_cond_init): Replaced by John Bossom's version. Fix comment (refered to mutex rather than condition variable). (pthread_cond_destroy): Replaced by John Bossom's version. (pthread_cond_wait): Replaced by John Bossom's version. (pthread_cond_timedwait): Replaced by John Bossom's version. (pthread_cond_signal): Replaced by John Bossom's version. (pthread_cond_broadcast): Replaced by John Bossom's version. Thu Dec 17 19:10:46 1998 Ross Johnson * tsd.c (pthread_key_create): Replaced by John Bossom's version. (pthread_key_delete): Replaced by John Bossom's version. (pthread_setspecific): Replaced by John Bossom's version. (pthread_getspecific): Replaced by John Bossom's version. Mon Dec 7 09:44:40 1998 John Bossom * cancel.c (pthread_setcancelstate): Replaced. (pthread_setcanceltype): Replaced. (pthread_testcancel): Replaced. (pthread_cancel): Replaced. * exit.c (pthread_exit): Replaced. * misc.c (pthread_self): Replaced. (pthread_equal): Replaced. * sync.c (pthread_detach): Replaced. (pthread_join): Replaced. * create.c (pthread_create): Replaced. * private.c (ptw32_processInitialize): New. (ptw32_processTerminate): New. (ptw32_threadStart): New. (ptw32_threadDestroy): New. (ptw32_cleanupStack): New. (ptw32_tkAssocCreate): New. (ptw32_tkAssocDestroy): New. (ptw32_callUserDestroyRoutines): New. * implement.h: Added non-API structures and declarations. * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress to resolve compile warning from MSVC. * dll.c (DLLmain): Replaced. * dll.c (PthreadsEntryPoint): Re-applied Anders Norlander's patch:- Initialize ptw32_try_enter_critical_section at startup and release kernel32 handle when DLL is being unloaded. Sun Dec 6 21:54:35 1998 Ross Johnson * buildlib.bat: Fix args to CL when building the .DLL * cleanup.c (ptw32_destructor_run_all): Fix TSD key management. This is a tidy-up before TSD and Thread management is completely replaced by John Bossom's code. * tsd.c (pthread_key_create): Fix TSD key management. * global.c (ptw32_key_virgin_next): Initialise. * build.bat: New DOS script to compile and link a pthreads app using Microsoft's CL compiler linker. * buildlib.bat: New DOS script to compile all the object files and create pthread.lib and pthread.dll using Microsoft's CL compiler linker. 1998-12-05 Anders Norlander * implement.h (ptw32_try_enter_critical_section): New extern * dll.c (ptw32_try_enter_critical_section): New pointer to TryEnterCriticalSection if it exists; otherwise NULL. * dll.c (PthreadsEntryPoint): Initialize ptw32_try_enter_critical_section at startup and release kernel32 handle when DLL is being unloaded. * mutex.c (pthread_mutex_trylock): Replaced check for NT with a check if ptw32_try_enter_critical_section is valid pointer to a function. Call ptw32_try_enter_critical_section instead of TryEnterCriticalSection to avoid errors on Win95. Thu Dec 3 13:32:00 1998 Ross Johnson * README: Correct cygwin32 compatibility statement. Sun Nov 15 21:24:06 1998 Ross Johnson * cleanup.c (ptw32_destructor_run_all): Declare missing void * arg. Fixup CVS merge conflicts. 1998-10-30 Ben Elliston * condvar.c (cond_wait): Fix semantic error. Test for equality instead of making an assignment. Fri Oct 30 15:15:50 1998 Ross Johnson * cleanup.c (ptw32_handler_push): Fixed bug appending new handler to list reported by Peter Slacik . (new_thread): Rename poorly named local variable to "new_handler". Sat Oct 24 18:34:59 1998 Ross Johnson * global.c: Add TSD key management array and index declarations. * implement.h: Ditto for externs. Fri Oct 23 00:08:09 1998 Ross Johnson * implement.h (PTW32_TSD_KEY_REUSE): Add enum. * private.c (ptw32_delete_thread): Add call to ptw32_destructor_run_all() to clean up the threads keys. * cleanup.c (ptw32_destructor_run_all): Check for no more dirty keys to run destructors on. Assume that the destructor call always succeeds and set the key value to NULL. Thu Oct 22 21:44:44 1998 Ross Johnson * tsd.c (pthread_setspecific): Add key management code. (pthread_key_create): Ditto. (pthread_key_delete): Ditto. * implement.h (struct ptw32_tsd_key): Add status member. * tsd.c: Add description of pthread_key_delete() from the standard as a comment. Fri Oct 16 17:38:47 1998 Ross Johnson * cleanup.c (ptw32_destructor_run_all): Fix and improve stepping through the key table. Thu Oct 15 14:05:01 1998 Ross Johnson * private.c (ptw32_new_thread): Remove init of destructorstack. No longer an element of pthread_t. * tsd.c (pthread_setspecific): Fix type declaration and cast. (pthread_getspecific): Ditto. (pthread_getspecific): Change error return value to NULL if key is not in use. Thu Oct 15 11:53:21 1998 Ross Johnson * global.c (ptw32_tsd_key_table): Fix declaration. * implement.h(ptw32_TSD_keys_TlsIndex): Add missing extern. (ptw32_tsd_mutex): Ditto. * create.c (ptw32_start_call): Fix "keys" array declaration. Add comment. * tsd.c (pthread_setspecific): Fix type declaration and cast. (pthread_getspecific): Ditto. * cleanup.c (ptw32_destructor_run_all): Declare missing loop counter. Wed Oct 14 21:09:24 1998 Ross Johnson * private.c (ptw32_new_thread): Increment ptw32_threads_count. (ptw32_delete_thread): Decrement ptw32_threads_count. Remove some comments. * exit.c (ptw32_exit): : Fix two pthread_mutex_lock() calls that should have been pthread_mutex_unlock() calls. (ptw32_vacuum): Remove call to ptw32_destructor_pop_all(). * create.c (pthread_create): Fix two pthread_mutex_lock() calls that should have been pthread_mutex_unlock() calls. * global.c (ptw32_tsd_mutex): Add mutex for TSD operations. * tsd.c (pthread_key_create): Add critical section. (pthread_setspecific): Ditto. (pthread_getspecific): Ditto. (pthread_key_delete): Ditto. * sync.c (pthread_join): Fix two pthread_mutex_lock() calls that should have been pthread_mutex_unlock() calls. Mon Oct 12 00:00:44 1998 Ross Johnson * implement.h (ptw32_tsd_key_table): New. * create.c (ptw32_start_call): Initialise per-thread TSD keys to NULL. * misc.c (pthread_once): Correct typo in comment. * implement.h (ptw32_destructor_push): Remove. (ptw32_destructor_pop): Remove. (ptw32_destructor_run_all): Rename from ptw32_destructor_pop_all. (PTW32_TSD_KEY_DELETED): Add enum. (PTW32_TSD_KEY_INUSE): Add enum. * cleanup.c (ptw32_destructor_push): Remove. (ptw32_destructor_pop): Remove. (ptw32_destructor_run_all): Totally revamped TSD. * dll.c (ptw32_TSD_keys_TlsIndex): Initialise. * tsd.c (pthread_setspecific): Totally revamped TSD. (pthread_getspecific): Ditto. (pthread_create): Ditto. (pthread_delete): Ditto. Sun Oct 11 22:44:55 1998 Ross Johnson * global.c (ptw32_tsd_key_table): Add new global. * implement.h (ptw32_tsd_key_t and struct ptw32_tsd_key): Add. (struct _pthread): Remove destructorstack. * cleanup.c (ptw32_destructor_run_all): Rename from ptw32_destructor_pop_all. The key destructor stack was made global rather than per-thread. No longer removes destructor nodes from the stack. Comments updated. 1998-10-06 Ben Elliston * condvar.c (cond_wait): Use POSIX, not Win32 mutex calls. (pthread_cond_broadcast): Likewise. (pthread_cond_signal): Likewise. 1998-10-05 Ben Elliston * pthread.def: Update. Some functions aren't available yet, others are macros in . * tests/join.c: Remove; useless. Mon Oct 5 14:25:08 1998 Ross Johnson * pthread.def: New file for building the DLL. 1998-10-05 Ben Elliston * misc.c (pthread_equal): Correct inverted logic bug. (pthread_once): Use the POSIX mutex primitives, not Win32. Remove irrelevant FIXME comment. * global.c (PTHREAD_MUTEX_INITIALIZER): Move to pthread.h. * pthread.h (PTHREAD_MUTEX_INITIALIZER): Define. (pthread_mutex_t): Reimplement as a struct containing a valid flag. If the flag is ever down upon entry to a mutex operation, we call pthread_mutex_create() to initialise the object. This fixes the problem of how to handle statically initialised objects that can't call InitializeCriticalSection() due to their context. (PTHREAD_ONCE_INIT): Define. * mutex.c (pthread_mutex_init): Set valid flag. (pthread_mutex_destroy): Clear valid flag. (pthread_mutex_lock): Check and handle the valid flag. (pthread_mutex_unlock): Likewise. (pthread_mutex_trylock): Likewise. * tests/mutex3.c: New file; test for the static initialisation macro. Passes. * tests/create1.c: New file; test pthread_create(). Passes. * tests/equal.c: Poor test; remove. * tests/equal1.c New file; test pthread_equal(). Passes. * tests/once1.c: New file; test for pthread_once(). Passes. * tests/self.c: Remove; rename to self1.c. * tests/self1.c: This is the old self.c. * tests/self2.c: New file. Test pthread_self() with a single thread. Passes. * tests/self3.c: New file. Test pthread_self() with a couple of threads to ensure their thread IDs differ. Passes. 1998-10-04 Ben Elliston * tests/mutex2.c: Test pthread_mutex_trylock(). Passes. * tests/mutex1.c: New basic test for mutex functions (it passes). (main): Eliminate warning. * configure.in: Test for __stdcall, not _stdcall. Typo. * configure: Regenerate. * attr.c (pthread_attr_setstackaddr): Remove FIXME comment. Win32 does know about ENOSYS after all. (pthread_attr_setstackaddr): Likewise. 1998-10-03 Ben Elliston * configure.in: Test for the `_stdcall' keyword. Define `STDCALL' to `_stdcall' if we have it, null otherwise. * configure: Regenerate. * acconfig.h (STDCALL): New define. * config.h.in: Regenerate. * create.c (ptw32_start_call): Add STDCALL prefix. * mutex.c (pthread_mutex_init): Correct function signature. * attr.c (pthread_attr_init): Only zero out the `sigmask' member if we have the sigset_t type. * pthread.h: No need to include . It doesn't even exist on Win32! Again, an artifact of cross-compilation. (pthread_sigmask): Only provide if we have the sigset_t type. * process.h: Remove. This was a stand-in before we started doing native compilation under Win32. * pthread.h (pthread_mutex_init): Make `attr' argument const. 1998-10-02 Ben Elliston * COPYING: Remove. * COPYING.LIB: Add. This library is under the LGPL. 1998-09-13 Ben Elliston * configure.in: Test for required system features. * configure: Generate. * acconfig.h: New file. * config.h.in: Generate. * Makefile.in: Renamed from Makefile. * COPYING: Import from a recent GNU package. * config.guess: Likewise. * config.sub: Likewise. * install-sh: Likewise. * config.h: Remove. * Makefile: Likewise. 1998-09-12 Ben Elliston * windows.h: No longer needed; remove. * windows.c: Likewise. Sat Sep 12 20:09:24 1998 Ross Johnson * windows.h: Remove error number definitions. These are in * tsd.c: Add comment explaining rationale for not building POSIX TSD on top of Win32 TLS. 1998-09-12 Ben Elliston * {most}.c: Include to get POSIX error values. * signal.c (pthread_sigmask): Only provide if HAVE_SIGSET_T is defined. * config.h: #undef features, don't #define them. This will be generated by autoconf very soon. 1998-08-11 Ben Elliston * Makefile (LIB): Define. (clean): Define target. (all): Build a library not just the object files. * pthread.h: Provide a definition for struct timespec if we don't already have one. * windows.c (TlsGetValue): Bug fix. Thu Aug 6 15:19:22 1998 Ross Johnson * misc.c (pthread_once): Fix arg 1 of EnterCriticalSection() and LeaveCriticalSection() calls to pass address-of lock. * fork.c (pthread_atfork): Typecast (void (*)(void *)) funcptr in each ptw32_handler_push() call. * exit.c (ptw32_exit): Fix attr arg in pthread_attr_getdetachstate() call. * private.c (ptw32_new_thread): Typecast (HANDLE) NULL. (ptw32_delete_thread): Ditto. * implement.h: (PTW32_MAX_THREADS): Add define. This keeps changing in an attempt to make thread administration data types opaque and cleanup DLL startup. * dll.c (PthreadsEntryPoint): (ptw32_virgins): Remove malloc() and free() calls. (ptw32_reuse): Ditto. (ptw32_win32handle_map): Ditto. (ptw32_threads_mutex_table): Ditto. * global.c (_POSIX_THREAD_THREADS_MAX): Initialise with PTW32_MAX_THREADS. (ptw32_virgins): Ditto. (ptw32_reuse): Ditto. (ptw32_win32handle_map): Ditto. (ptw32_threads_mutex_table): Ditto. * create.c (pthread_create): Typecast (HANDLE) NULL. Typecast (unsigned (*)(void *)) start_routine. * condvar.c (pthread_cond_init): Add address-of operator & to arg 1 of pthread_mutex_init() call. (pthread_cond_destroy): Add address-of operator & to arg 1 of pthread_mutex_destroy() call. * cleanup.c (ptw32_destructor_pop_all): Add (int) cast to pthread_getspecific() arg. (ptw32_destructor_pop): Add (void *) cast to "if" conditional. (ptw32_destructor_push): Add (void *) cast to ptw32_handler_push() "key" arg. (malloc.h): Add include. * implement.h (ptw32_destructor_pop): Add prototype. * tsd.c (implement.h): Add include. * sync.c (pthread_join): Remove target_thread_mutex and it's initialisation. Rename getdetachedstate to getdetachstate. Remove unused variable "exitcode". (pthread_detach): Remove target_thread_mutex and it's initialisation. Rename getdetachedstate to getdetachstate. Rename setdetachedstate to setdetachstate. * signal.c (pthread_sigmask): Rename SIG_SET to SIG_SETMASK. Cast "set" to (long *) in assignment to passify compiler warning. Add address-of operator & to thread->attr.sigmask in memcpy() call and assignment. (pthread_sigmask): Add address-of operator & to thread->attr.sigmask in memcpy() call and assignment. * windows.h (THREAD_PRIORITY_ERROR_RETURN): Add. (THREAD_PRIORITY_LOWEST): Add. (THREAD_PRIORITY_HIGHEST): Add. * sched.c (is_attr): Add function. (implement.h): Add include. (pthread_setschedparam): Rename all instances of "sched_policy" to "sched_priority". (pthread_getschedparam): Ditto. Tue Aug 4 16:57:58 1998 Ross Johnson * private.c (ptw32_delete_thread): Fix typo. Add missing ';'. * global.c (ptw32_virgins): Change types from pointer to array pointer. (ptw32_reuse): Ditto. (ptw32_win32handle_map): Ditto. (ptw32_threads_mutex_table): Ditto. * implement.h(ptw32_virgins): Change types from pointer to array pointer. (ptw32_reuse): Ditto. (ptw32_win32handle_map): Ditto. (ptw32_threads_mutex_table): Ditto. * private.c (ptw32_delete_thread): Fix "entry" should be "thread". * misc.c (pthread_self): Add extern for ptw32_threadID_TlsIndex. * global.c: Add comment. * misc.c (pthread_once): Fix member -> dereferences. Change ptw32_once_flag to once_control->flag in "if" test. Tue Aug 4 00:09:30 1998 Ross Johnson * implement.h(ptw32_virgins): Add extern. (ptw32_virgin_next): Ditto. (ptw32_reuse): Ditto. (ptw32_reuse_top): Ditto. (ptw32_win32handle_map): Ditto. (ptw32_threads_mutex_table): Ditto. * global.c (ptw32_virgins): Changed from array to pointer. Storage allocation for the array moved into dll.c. (ptw32_reuse): Ditto. (ptw32_win32handle_map): Ditto. (ptw32_threads_mutex_table): Ditto. * dll.c (PthreadsEntryPoint): Set up thread admin storage when DLL is loaded. * fork.c (pthread_atfork): Fix function pointer arg to all ptw32_handler_push() calls. Change "arg" arg to NULL in child push. * exit.c: Add windows.h and process.h includes. (ptw32_exit): Add local detachstate declaration. (ptw32_exit): Fix incorrect name for pthread_attr_getdetachstate(). * pthread.h (_POSIX_THREAD_ATTR_STACKSIZE): Move from global.c (_POSIX_THREAD_ATTR_STACKADDR): Ditto. * create.c (pthread_create): Fix #if should be #ifdef. (ptw32_start_call): Remove usused variables. * process.h: Create. * windows.h: Move _beginthreadex and _endthreadex into process.h Mon Aug 3 21:19:57 1998 Ross Johnson * condvar.c (pthread_cond_init): Add NULL attr to pthread_mutex_init() call - default attributes will be used. (cond_wait): Fix typo. (cond_wait): Fix typo - cv was ev. (pthread_cond_broadcast): Fix two identical typos. * cleanup.c (ptw32_destructor_pop_all): Remove _ prefix from PTHREAD_DESTRUCTOR_ITERATIONS. * pthread.h: Move _POSIX_* values into posix.h * pthread.h: Fix typo in pthread_mutex_init() prototype. * attr.c (pthread_attr_init): Fix error in priority member init. * windows.h (THREAD_PRIORITY_NORMAL): Add. * pthread.h (sched_param): Add missing ';' to struct definition. * attr.c (pthread_attr_init): Remove obsolete pthread_attr_t member initialisation - cancelstate, canceltype, cancel_pending. (is_attr): Make arg "attr" a const. * implement.h (PTW32_HANDLER_POP_LIFO): Remove definition. (PTW32_HANDLER_POP_FIFO): Ditto. (PTW32_VALID): Add missing newline escape (\). (ptw32_handler_node): Make element "next" a pointer. 1998-08-02 Ben Elliston * windows.h: Remove duplicate TlsSetValue() prototype. Add TlsGetValue() prototype. (FALSE): Define. (TRUE): Likewise. Add forgotten errno values. Guard against multiple #includes. * windows.c: New file. Implement stubs for Win32 functions. * Makefile (SRCS): Remove. Not explicitly needed. (CFLAGS): Add -Wall for all warnings with GCC. Sun Aug 2 19:03:42 1998 Ross Johnson * config.h: Create. This is a temporary stand-in for autoconf yet to be done. (HAVE_SIGNAL_H): Add. * pthread.h: Minor rearrangement for temporary config.h. Fri Jul 31 14:00:29 1998 Ross Johnson * cleanup.c (ptw32_destructor_pop): Implement. Removes destructors associated with a key without executing them. (ptw32_destructor_pop_all): Add FIXME comment. * tsd.c (pthread_key_delete): Add call to ptw32_destructor_pop(). Fri Jul 31 00:05:45 1998 Ross Johnson * tsd.c (pthread_key_create): Update to properly associate the destructor routine with the key. (pthread_key_delete): Add FIXME comment. * exit.c (ptw32_vacuum): Add call to ptw32_destructor_pop_all(). * implement.h (ptw32_handler_pop_all): Add prototype. (ptw32_destructor_pop_all): Ditto. * cleanup.c (ptw32_destructor_push): Implement. This is just a call to ptw32_handler_push(). (ptw32_destructor_pop_all): Implement. This is significantly different to ptw32_handler_pop_all(). * Makefile (SRCS): Create. Preliminary. * windows.h: Create. Contains Win32 definitions for compile testing. This is just a standin for the real one. * pthread.h (SIG_UNBLOCK): Fix typo. Was SIG_BLOCK. (windows.h): Add include. Required for CRITICAL_SECTION. (pthread_cond_t): Move enum declaration outside of struct definition. (unistd.h): Add include - may be temporary. * condvar.c (windows.h): Add include. * implement.h (PTW32_THIS): Remove - no longer required. (PTW32_STACK): Use pthread_self() instead of PTW32_THIS. Thu Jul 30 23:12:45 1998 Ross Johnson * implement.h: Remove ptw32_find_entry() prototype. * private.c: Extend comments. Remove ptw32_find_entry() - no longer needed. * create.c (ptw32_start_call): Add call to TlsSetValue() to store the thread ID. * dll.c (PthreadsEntryPoint): Implement. This is called whenever a process loads the DLL. Used to initialise thread local storage. * implement.h: Add ptw32_threadID_TlsIndex. Add ()s around PTW32_VALID expression. * misc.c (pthread_self): Re-implement using Win32 TLS to store the threads own ID. Wed Jul 29 11:39:03 1998 Ross Johnson * private.c: Corrections in comments. (ptw32_new_thread): Alter "if" flow to be more natural. * cleanup.c (ptw32_handler_push): Same as below. * create.c (pthread_create): Same as below. * private.c (ptw32_new_thread): Rename "new" to "new_thread". Since when has a C programmer been required to know C++? Tue Jul 28 14:04:29 1998 Ross Johnson * implement.h: Add PTW32_VALID macro. * sync.c (pthread_join): Modify to use the new thread type and ptw32_delete_thread(). Rename "target" to "thread". Remove extra local variable "target". (pthread_detach): Ditto. * signal.c (pthread_sigmask): Move init of "us" out of inner block. Fix instance of "this" should have been "us". Rename "us" to "thread". * sched.c (pthread_setschedparam): Modify to use the new thread type. (pthread_getschedparam): Ditto. * private.c (ptw32_find_thread): Fix return type and arg. * implement.h: Remove PTW32_YES and PTW32_NO. (ptw32_new_thread): Add prototype. (ptw32_find_thread): Ditto. (ptw32_delete_thread): Ditto. (ptw32_new_thread_entry): Remove prototype. (ptw32_find_thread_entry): Ditto. (ptw32_delete_thread_entry): Ditto. ( PTW32_NEW, PTW32_INUSE, PTW32_EXITED, PTW32_REUSE): Add. * create.c (pthread_create): Minor rename "us" to "new" (I need these cues but it doesn't stop me coming out with some major bugs at times). Load start_routine and arg into the thread so the wrapper can call it. * exit.c (pthread_exit): Fix pthread_this should be pthread_self. * cancel.c (pthread_setcancelstate): Change ptw32_threads_thread_t * to pthread_t and init with pthread_this(). (pthread_setcanceltype): Ditto. * exit.c (ptw32_exit): Add new pthread_t arg. Rename ptw32_delete_thread_entry to ptw32_delete_thread. Rename "us" to "thread". (pthread_exit): Call ptw32_exit with added thread arg. * create.c (ptw32_start_call): Insert missing ")". Add "us" arg to ptw32_exit() call. (pthread_create): Modify to use new thread allocation scheme. * private.c: Added detailed explanation of the new thread allocation scheme. (ptw32_new_thread): Totally rewritten to use new thread allocation scheme. (ptw32_delete_thread): Ditto. (ptw32_find_thread): Obsolete. Mon Jul 27 17:46:37 1998 Ross Johnson * create.c (pthread_create): Start of rewrite. Not completed yet. * private.c (ptw32_new_thread_entry): Start of rewrite. Not complete. * implement.h (ptw32_threads_thread): Rename, remove thread member, add win32handle and ptstatus members. (ptw32_t): Add. * pthread.h: pthread_t is no longer mapped directly to a Win32 HANDLE type. This is so we can let the Win32 thread terminate and reuse the HANDLE while pthreads holds it's own thread ID until the last waiting join exits. Mon Jul 27 00:20:37 1998 Ross Johnson * private.c (ptw32_delete_thread_entry): Destroy the thread entry attribute object before deleting the thread entry itself. * attr.c (pthread_attr_init): Initialise cancel_pending = FALSE. (pthread_attr_setdetachstate): Rename "detached" to "detachedstate". (pthread_attr_getdetachstate): Ditto. * exit.c (ptw32_exit): Fix incorrect check for detachedstate. * implement.h (ptw32_call_t): Remove env member. Sun Jul 26 13:06:12 1998 Ross Johnson * implement.h (ptw32_new_thread_entry): Fix prototype. (ptw32_find_thread_entry): Ditto. (ptw32_delete_thread_entry): Ditto. (ptw32_exit): Add prototype. * exit.c (ptw32_exit): New function. Called from pthread_exit() and ptw32_start_call() to exit the thread. It allows an extra argument which is the return code passed to _endthreadex(). (ptw32_exit): Move thread entry delete call from ptw32_vacuum() into here. Add more explanation of thread entry deletion. (ptw32_exit): Clarify comment. * create.c (ptw32_start_call): Change pthread_exit() call to ptw32_exit() call. * exit.c (ptw32_vacuum): Add thread entry deletion code moved from ptw32_start_call(). See next item. (pthread_exit): Remove longjmp(). Add mutex lock around thread table manipulation code. This routine now calls _enthreadex(). * create.c (ptw32_start_call): Remove setjmp() call and move cleanup code out. Call pthread_exit(NULL) to terminate the thread. 1998-07-26 Ben Elliston * tsd.c (pthread_getspecific): Update comments. * mutex.c (pthread_mutexattr_setpshared): Not supported; remove. (pthread_mutexattr_getpshared): Likewise. * pthread.h (pthread_mutexattr_setpshared): Remove prototype. (pthread_mutexattr_getpshared): Likewise. Sun Jul 26 00:09:59 1998 Ross Johnson * sync.c: Rename all instances of ptw32_count_mutex to ptw32_table_mutex. * implement.h: Rename ptw32_count_mutex to ptw32_table_mutex. * global.c: Rename ptw32_count_mutex to ptw32_table_mutex. * create.c (pthread_create): Add critical sections. (ptw32_start_call): Rename ptw32_count_mutex to ptw32_table_mutex. * cancel.c (pthread_setcancelstate): Fix indirection bug and rename "this" to "us". * signal.c (pthread_sigmask): Rename "this" to "us" and fix some minor syntax errors. Declare "us" and initialise it. * sync.c (pthread_detach): Rename "this" to "target". * pthread.h: Converting PTHREAD_* defines to alias the (const int) values in global.c. * global.c: Started converting PTHREAD_* defines to (const int) as a part of making the eventual pthreads DLL binary compatible through version changes. * condvar.c (cond_wait): Add cancelation point. This applies the point to both pthread_cond_wait() and pthread_cond_timedwait(). * exit.c (pthread_exit): Rename "this" to "us". * implement.h: Add comment. * sync.c (pthread_join): I've satisfied myself that pthread_detach() does set the detached attribute in the thread entry attributes to PTHREAD_CREATE_DETACHED. "if" conditions were changed to test that attribute instead of a separate flag. * create.c (pthread_create): Rename "this" to "us". (pthread_create): cancelstate and canceltype are not attributes so the copy to thread entry attribute storage was removed. Only the thread itself can change it's cancelstate or canceltype, ie. the thread must exist already. * private.c (ptw32_delete_thread_entry): Mutex locks removed. Mutexes must be applied at the caller level. (ptw32_new_thread_entry): Ditto. (ptw32_new_thread_entry): Init cancelstate, canceltype, and cancel_pending to default values. (ptw32_new_thread_entry): Rename "this" to "new". (ptw32_find_thread_entry): Rename "this" to "entry". (ptw32_delete_thread_entry): Rename "thread_entry" to "entry". * create.c (ptw32_start_call): Mutexes changed to ptw32_count_mutex. All access to the threads table entries is under the one mutex. Otherwise chaos reigns. Sat Jul 25 23:16:51 1998 Ross Johnson * implement.h (ptw32_threads_thread): Move cancelstate and canceltype members out of pthread_attr_t into here. * fork.c (fork): Add comment. 1998-07-25 Ben Elliston * fork.c (fork): Autoconfiscate. Sat Jul 25 00:00:13 1998 Ross Johnson * create.c (ptw32_start_call): Set thread priority. Ensure our thread entry is removed from the thread table but only if pthread_detach() was called and there are no waiting joins. (pthread_create): Set detach flag in thread entry if the thread is created PTHREAD_CREATE_DETACHED. * pthread.h (pthread_attr_t): Rename member "detachedstate". * attr.c (pthread_attr_init): Rename attr members. * exit.c (pthread_exit): Fix indirection mistake. * implement.h (PTW32_THREADS_TABLE_INDEX): Add. * exit.c (ptw32_vacuum): Fix incorrect args to ptw32_handler_pop_all() calls. Make thread entry removal conditional. * sync.c (pthread_join): Add multiple join and async detach handling. * implement.h (PTW32_THREADS_TABLE_INDEX): Add. * global.c (ptw32_threads_mutex_table): Add. * implement.h (ptw32_once_flag): Remove. (ptw32_once_lock): Ditto. (ptw32_threads_mutex_table): Add. * global.c (ptw32_once_flag): Remove. (ptw32_once_lock): Ditto. * sync.c (pthread_join): Fix tests involving new return value from ptw32_find_thread_entry(). (pthread_detach): Ditto. * private.c (ptw32_find_thread_entry): Failure return code changed from -1 to NULL. Fri Jul 24 23:09:33 1998 Ross Johnson * create.c (pthread_create): Change . to -> in sigmask memcpy() args. * pthread.h: (pthread_cancel): Add function prototype. (pthread_testcancel): Ditto. 1998-07-24 Ben Elliston * pthread.h (pthread_condattr_t): Rename dummy structure member. (pthread_mutexattr_t): Likewise. Fri Jul 24 21:13:55 1998 Ross Johnson * cancel.c (pthread_cancel): Implement. (pthread_testcancel): Implement. * exit.c (pthread_exit): Add comment explaining the longjmp(). * implement.h (ptw32_threads_thread_t): New member cancelthread. (PTW32_YES): Define. (PTW32_NO): Define. (RND_SIZEOF): Remove. * create.c (pthread_create): Rename cancelability to cancelstate. * pthread.h (pthread_attr_t): Rename cancelability to cancelstate. (PTHREAD_CANCELED): Define. 1998-07-24 Ben Elliston * pthread.h (SIG_BLOCK): Define if not already defined. (SIG_UNBLOCK): Likewise. (SIG_SETMASK): Likewise. (pthread_attr_t): Add signal mask member. (pthread_sigmask): Add function prototype. * signal.c (pthread_sigmask): Implement. * create.c: #include to get a prototype for memcpy(). (pthread_create): New threads inherit their creator's signal mask. Copy the signal mask to the new thread structure if we know about signals. Fri Jul 24 16:33:17 1998 Ross Johnson * fork.c (pthread_atfork): Add all the necessary push calls. Local implementation semantics: If we get an ENOMEM at any time then ALL handlers (including those from previous pthread_atfork() calls) will be popped off each of the three atfork stacks before we return. (fork): Add all the necessary pop calls. Add the thread cancellation and join calls to the child fork. Add #includes. * implement.h: (ptw32_handler_push): Fix return type and stack arg type in prototype. (ptw32_handler_pop): Fix stack arg type in prototype. (ptw32_handler_pop_all): Fix stack arg type in prototype. * cleanup.c (ptw32_handler_push): Change return type to int and return ENOMEM if malloc() fails. * sync.c (pthread_detach): Use equality test, not assignment. * create.c (ptw32_start_call): Add call to Win32 CloseHandle() if thread is detached. 1998-07-24 Ben Elliston * sync.c (pthread_detach): Close the Win32 thread handle to emulate detached (or daemon) threads. Fri Jul 24 03:00:25 1998 Ross Johnson * sync.c (pthread_join): Save valueptr arg in joinvalueptr for pthread_exit() to use. * private.c (ptw32_new_thread_entry): Initialise joinvalueptr to NULL. * create.c (ptw32_start_call): Rewrite to facilitate joins. pthread_exit() will do a longjmp() back to here. Does appropriate cleanup and exit/return from the thread. (pthread_create): _beginthreadex() now passes a pointer to our thread table entry instead of just the call member of that entry. * implement.h (ptw32_threads_thread): New member void ** joinvalueptr. (ptw32_call_t): New member jmpbuf env. * exit.c (pthread_exit): Major rewrite to handle joins and handing value pointer to joining thread. Uses longjmp() back to ptw32_start_call(). * create.c (pthread_create): Ensure values of new attribute members are copied to the thread attribute object. * attr.c (pthread_attr_destroy): Fix merge conflicts. (pthread_attr_getdetachstate): Fix merge conflicts. (pthread_attr_setdetachstate): Fix merge conflicts. * pthread.h: Fix merge conflicts. * sync.c (pthread_join): Fix merge conflicts. Fri Jul 24 00:21:21 1998 Ross Johnson * sync.c (pthread_join): Add check for valid and joinable thread. (pthread_detach): Implement. After checking for a valid and joinable thread, it's still a no-op. * private.c (ptw32_find_thread_entry): Bug prevented returning an error value in some cases. * attr.c (pthread_attr_setdetachedstate): Implement. (pthread_attr_getdetachedstate): Implement. * implement.h: Move more hidden definitions into here from pthread.h. 1998-07-24 Ben Elliston * pthread.h (PTHREAD_CREATE_JOINABLE): Define. (PTHREAD_CREATE_DETACHED): Likewise. (pthread_attr_t): Add new structure member `detached'. (pthread_attr_getdetachstate): Add function prototype. (pthread_attr_setdetachstate): Likewise. * sync.c (pthread_join): Return if the target thread is detached. * attr.c (pthread_attr_init): Initialise cancelability and canceltype structure members. (pthread_attr_getdetachstate): Implement. (pthread_attr_setdetachstate): Likewise. * implement.h (PTW32_CANCEL_DEFAULTS): Remove. Bit fields proved to be too cumbersome. Set the defaults in attr.c using the public PTHREAD_CANCEL_* constants. * cancel.c: New file. * pthread.h (sched_param): Define this type. (pthread_attr_getschedparam): Add function prototype. (pthread_attr_setschedparam): Likewise. (pthread_setcancelstate): Likewise. (pthread_setcanceltype): Likewise. (sched_get_priority_min): Likewise. (sched_get_priority_max): Likewise. (pthread_mutexattr_setprotocol): Remove; not supported. (pthread_mutexattr_getprotocol): Likewise. (pthread_mutexattr_setprioceiling): Likewise. (pthread_mutexattr_getprioceiling): Likewise. (pthread_attr_t): Add canceltype member. Update comments. (SCHED_OTHER): Define this scheduling policy constant. (SCHED_FIFO): Likewise. (SCHED_RR): Likewise. (SCHED_MIN): Define the lowest possible value for this constant. (SCHED_MAX): Likewise, the maximum possible value. (PTHREAD_CANCEL_ASYNCHRONOUS): Redefine. (PTHREAD_CANCEL_DEFERRED): Likewise. * sched.c: New file. (pthread_setschedparam): Implement. (pthread_getschedparam): Implement. (sched_get_priority_max): Validate policy argument. (sched_get_priority_min): Likewise. * mutex.c (pthread_mutexattr_setprotocol): Remove; not supported. (pthread_mutexattr_getprotocol): Likewise. (pthread_mutexattr_setprioceiling): Likewise. (pthread_mutexattr_getprioceiling): Likewise. Fri Jul 24 00:21:21 1998 Ross Johnson * create.c (pthread_create): Arg to ptw32_new_thread_entry() changed. See next entry. Move mutex locks out. Changes made yesterday and today allow us to start the new thread running rather than temporarily suspended. * private.c (ptw32_new_thread_entry): ptw32_thread_table was changed back to a table of thread structures rather than pointers. As such we're trading storage for increaded speed. This routine was modified to work with the new table. Mutex lock put in around global data accesses. (ptw32_find_thread_entry): Ditto (ptw32_delete_thread_entry): Ditto Thu Jul 23 23:25:30 1998 Ross Johnson * global.c: New. Global data objects declared here. These moved from pthread.h. * pthread.h: Move implementation hidden definitions into implement.h. * implement.h: Move implementation hidden definitions from pthread.h. Add constants to index into the different handler stacks. * cleanup.c (ptw32_handler_push): Simplify args. Restructure. (ptw32_handler_pop): Simplify args. Restructure. (ptw32_handler_pop_all): Simplify args. Restructure. Wed Jul 22 00:16:22 1998 Ross Johnson * attr.c, implement.h, pthread.h, ChangeLog: Resolve CVS merge conflicts. * private.c (ptw32_find_thread_entry): Changes to return type to support leaner ptw32_threads_table[] which now only stores ptw32_thread_thread_t *. (ptw32_new_thread_entry): Internal changes. (ptw32_delete_thread_entry): Internal changes to avoid contention. Calling routines changed accordingly. * pthread.h: Modified cleanup macros to use new generic push and pop. Added destructor and atfork stacks to ptw32_threads_thread_t. * cleanup.c (ptw32_handler_push, ptw32_handler_pop, ptw32_handler_pop_all): Renamed cleanup push and pop routines and made generic to handle destructors and atfork handlers as well. * create.c (ptw32_start_call): New function is a wrapper for all new threads. It allows us to do some cleanup when the thread returns, ie. that is otherwise only done if the thread is cancelled. * exit.c (ptw32_vacuum): New function contains code from pthread_exit() that we need in the new ptw32_start_call() as well. * implement.h: Various additions and minor changes. * pthread.h: Various additions and minor changes. Change cleanup handler macros to use generic handler push and pop functions. * attr.c: Minor mods to all functions. (is_attr): Implemented missing function. * create.c (pthread_create): More clean up. * private.c (ptw32_find_thread_entry): Implement. (ptw32_delete_thread_entry): Implement. (ptw32_new_thread_entry): Implement. These functions manipulate the implementations internal thread table and are part of general code cleanup and modularisation. They replace ptw32_getthreadindex() which was removed. * exit.c (pthread_exit): Changed to use the new code above. * pthread.h: Add cancelability constants. Update comments. 1998-07-22 Ben Elliston * attr.c (pthread_setstacksize): Update test of attr argument. (pthread_getstacksize): Likewise. (pthread_setstackaddr): Likewise. (pthread_getstackaddr): Likewise. (pthread_attr_init): No need to allocate any storage. (pthread_attr_destroy): No need to free any storage. * mutex.c (is_attr): Not likely to be needed; remove. (remove_attr): Likewise. (insert_attr): Likewise. * implement.h (ptw32_mutexattr_t): Moved to a public definition in pthread.h. There was little gain in hiding these details. (ptw32_condattr_t): Likewise. (ptw32_attr_t): Likewise. * pthread.h (pthread_atfork): Add function prototype. (pthread_attr_t): Moved here from implement.h. * fork.c (pthread_atfork): Preliminary implementation. (ptw32_fork): Likewise. Wed Jul 22 00:16:22 1998 Ross Johnson * cleanup.c (ptw32_cleanup_push): Implement. (ptw32_cleanup_pop): Implement. (ptw32_do_cancellation): Implement. These are private to the implementation. The real cleanup functions are macros. See below. * pthread.h (pthread_cleanup_push): Implement as a macro. (pthread_cleanup_pop): Implement as a macro. Because these are macros which start and end a block, the POSIX scoping requirement is observed. See the comment in the file. * exit.c (pthread_exit): Refine the code. * create.c (pthread_create): Code cleanup. * implement.h (RND_SIZEOF): Add RND_SIZEOF(T) to round sizeof(T) up to multiple of DWORD. Add function prototypes. * private.c (ptw32_getthreadindex): "*thread" should have been "thread". Detect empty slot fail condition. 1998-07-20 Ben Elliston * misc.c (pthread_once): Implement. Don't use a per-application flag and mutex--make `pthread_once_t' contain these elements in their structure. The earlier version had incorrect semantics. * pthread.h (ptw32_once_flag): Add new variable. Remove. (ptw32_once_lock): Add new mutex lock to ensure integrity of access to ptw32_once_flag. Remove. (pthread_once): Add function prototype. (pthread_once_t): Define this type. Mon Jul 20 02:31:05 1998 Ross Johnson * private.c (ptw32_getthreadindex): Implement. * pthread.h: Add application static data dependent on _PTHREADS_BUILD_DLL define. This is needed to avoid allocating non-sharable static data within the pthread DLL. * implement.h: Add ptw32_cleanup_stack_t, ptw32_cleanup_node_t and PTW32_HASH_INDEX. * exit.c (pthread_exit): Begin work on cleanup and de-allocate thread-private storage. * create.c (pthread_create): Add thread to thread table. Keep a thread-private copy of the attributes with default values filled in when necessary. Same for the cleanup stack. Make pthread_create C run-time library friendly by using _beginthreadex() instead of CreateThread(). Fix error returns. Sun Jul 19 16:26:23 1998 Ross Johnson * implement.h: Rename pthreads_thread_count to ptw32_threads_count. Create ptw32_threads_thread_t struct to keep thread specific data. * create.c: Rename pthreads_thread_count to ptw32_threads_count. (pthread_create): Handle errors from CreateThread(). 1998-07-19 Ben Elliston * condvar.c (pthread_cond_wait): Generalise. Moved from here .. (cond_wait): To here. (pthread_cond_timedwait): Implement; use generalised cond_wait(). * pthread.h (pthread_key_t): Define this type. (pthread_key_create): Add function prototype. (pthread_setspecific): Likewise. (pthread_getspecific): Likwise. (pthread_key_delete): Likewise. * tsd.c (pthread_key_create): Implement. (pthread_setspecific): Likewise. (pthread_getspecific): Likewise. (pthread_key_delete): Likewise. * mutex.c (pthread_mutex_trylock): Return ENOSYS if this function is called on a Win32 platform which is not Windows NT. 1998-07-18 Ben Elliston * condvar.c (pthread_condattr_init): Do not attempt to malloc any storage; none is needed now that condattr_t is an empty struct. (pthread_condattr_destory): Likewise; do not free storage. (pthread_condattr_setpshared): No longer supported; return ENOSYS. (pthread_condattr_getpshared): Likewise. (pthread_cond_init): Implement with help from Douglas Schmidt. Remember to initialise the cv's internal mutex. (pthread_cond_wait): Likewise. (pthread_cond_signal): Likewise. (pthread_cond_broadcast): Likewise. (pthread_cond_timedwait): Preliminary implementation, but I need to see some API documentation for `WaitForMultipleObject'. (pthread_destory): Implement. * pthread.h (pthread_cond_init): Add function protoype. (pthread_cond_broadcast): Likewise. (pthread_cond_signal): Likewise. (pthread_cond_timedwait): Likewise. (pthread_cond_wait): Likewise. (pthread_cond_destroy): Likewise. (pthread_cond_t): Define this type. Fix for u_int. Do not assume that the mutex contained withing the pthread_cond_t structure will be a critical section. Use our new POSIX type! * implement.h (ptw32_condattr_t): Remove shared attribute. 1998-07-17 Ben Elliston * pthread.h (PTHREADS_PROCESS_PRIVATE): Remove. (PTHREAD_PROCESS_SHARED): Likewise. No support for mutexes shared across processes for now. (pthread_mutex_t): Use a Win32 CRITICAL_SECTION type for better performance. * implement.h (ptw32_mutexattr_t): Remove shared attribute. * mutex.c (pthread_mutexattr_setpshared): This optional function is no longer supported, since we want to implement POSIX mutex variables using the much more efficient Win32 critical section primitives. Critical section objects in Win32 cannot be shared between processes. (pthread_mutexattr_getpshared): Likewise. (pthread_mutexattr_init): No need to malloc any storage; the attributes structure is now empty. (pthread_mutexattr_destroy): This is now a nop. (pthread_mutex_init): Use InitializeCriticalSection(). (pthread_mutex_destroy): Use DeleteCriticalSection(). (pthread_mutex_lock): Use EnterCriticalSection(). (pthread_mutex_trylock): Use TryEnterCriticalSection(). This is not supported by Windows 9x, but trylock is a hack anyway, IMHO. (pthread_mutex_unlock): Use LeaveCriticalSection(). 1998-07-14 Ben Elliston * attr.c (pthread_attr_setstacksize): Implement. (pthread_attr_getstacksize): Likewise. (pthread_attr_setstackaddr): Likewise. (pthread_attr_getstackaddr): Likewise. (pthread_attr_init): Likewise. (pthread_attr_destroy): Likewise. * condvar.c (pthread_condattr_init): Add `_cond' to function name. * mutex.c (pthread_mutex_lock): Add `_mutex' to function name. (pthread_mutex_trylock): Likewise. (pthread_mutex_unlock): Likewise. * pthread.h (pthread_condattr_setpshared): Fix typo. (pthread_attr_init): Add function prototype. (pthread_attr_destroy): Likewise. (pthread_attr_setstacksize): Likewise. (pthread_attr_getstacksize): Likewise. (pthread_attr_setstackaddr): Likewise. (pthread_attr_getstackaddr): Likewise. Mon Jul 13 01:09:55 1998 Ross Johnson * implement.h: Wrap in #ifndef _IMPLEMENT_H * create.c (pthread_create): Map stacksize attr to Win32. * mutex.c: Include implement.h 1998-07-13 Ben Elliston * condvar.c (pthread_condattr_init): Implement. (pthread_condattr_destroy): Likewise. (pthread_condattr_setpshared): Likewise. (pthread_condattr_getpshared): Likewise. * implement.h (PTHREAD_THREADS_MAX): Remove trailing semicolon. (PTHREAD_STACK_MIN): Specify; needs confirming. (ptw32_attr_t): Define this type. (ptw32_condattr_t): Likewise. * pthread.h (pthread_mutex_t): Define this type. (pthread_condattr_t): Likewise. (pthread_mutex_destroy): Add function prototype. (pthread_lock): Likewise. (pthread_trylock): Likewise. (pthread_unlock): Likewise. (pthread_condattr_init): Likewise. (pthread_condattr_destroy): Likewise. (pthread_condattr_setpshared): Likewise. (pthread_condattr_getpshared): Likewise. * mutex.c (pthread_mutex_init): Implement. (pthread_mutex_destroy): Likewise. (pthread_lock): Likewise. (pthread_trylock): Likewise. (pthread_unlock): Likewise. 1998-07-12 Ben Elliston * implement.h (ptw32_mutexattr_t): Define this implementation internal type. Application programmers only see a mutex attribute object as a void pointer. * pthread.h (pthread_mutexattr_t): Define this type. (pthread_mutexattr_init): Add function prototype. (pthread_mutexattr_destroy): Likewise. (pthread_mutexattr_setpshared): Likewise. (pthread_mutexattr_getpshared): Likewise. (pthread_mutexattr_setprotocol): Likewise. (pthread_mutexattr_getprotocol): Likewise. (pthread_mutexattr_setprioceiling): Likewise. (pthread_mutexattr_getprioceiling): Likewise. (PTHREAD_PROCESS_PRIVATE): Define. (PTHREAD_PROCESS_SHARED): Define. * mutex.c (pthread_mutexattr_init): Implement. (pthread_mutexattr_destroy): Implement. (pthread_mutexattr_setprotocol): Implement. (pthread_mutexattr_getprotocol): Likewise. (pthread_mutexattr_setprioceiling): Likewise. (pthread_mutexattr_getprioceiling): Likewise. (pthread_mutexattr_setpshared): Likewise. (pthread_mutexattr_getpshared): Likewise. (insert_attr): New function; very preliminary implementation! (is_attr): Likewise. (remove_attr): Likewise. Sat Jul 11 14:48:54 1998 Ross Johnson * implement.h: Preliminary implementation specific defines. * create.c (pthread_create): Preliminary implementation. 1998-07-11 Ben Elliston * sync.c (pthread_join): Implement. * misc.c (pthread_equal): Likewise. * pthread.h (pthread_join): Add function prototype. (pthread_equal): Likewise. 1998-07-10 Ben Elliston * misc.c (pthread_self): Implement. * exit.c (pthread_exit): Implement. * pthread.h (pthread_exit): Add function prototype. (pthread_self): Likewise. (pthread_t): Define this type. 1998-07-09 Ben Elliston * create.c (pthread_create): A dummy stub right now. * pthread.h (pthread_create): Add function prototype. nyquist-3.05/liblo/pthreads.2/pthread_mutex_unlock.c0000644000175000000620000000604211512143043021622 0ustar stevestaff/* * pthread_mutex_unlock.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutex_unlock (pthread_mutex_t * mutex) { int result = 0; pthread_mutex_t mx; /* * Let the system deal with invalid pointers. */ mx = *mutex; /* * If the thread calling us holds the mutex then there is no * race condition. If another thread holds the * lock then we shouldn't be in here. */ if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { if (mx->kind == PTHREAD_MUTEX_NORMAL) { LONG idx; idx = (LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, (LONG) 0); if (idx != 0) { if (idx < 0) { /* * Someone may be waiting on that mutex. */ if (SetEvent (mx->event) == 0) { result = EINVAL; } } } else { /* * Was not locked (so can't be owned by us). */ result = EPERM; } } else { if (pthread_equal (mx->ownerThread, pthread_self ())) { if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 0 == --mx->recursive_count) { mx->ownerThread.p = NULL; if ((LONG) PTW32_INTERLOCKED_EXCHANGE ((LPLONG) &mx->lock_idx, (LONG) 0) < 0) { /* Someone may be waiting on that mutex */ if (SetEvent (mx->event) == 0) { result = EINVAL; } } } } else { result = EPERM; } } } else { result = EINVAL; } return (result); } nyquist-3.05/liblo/pthreads.2/pthread_setschedparam.c0000644000175000000620000000651011512143043021730 0ustar stevestaff/* * sched_setschedparam.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_setschedparam (pthread_t thread, int policy, const struct sched_param *param) { int result; /* Validate the thread id. */ result = pthread_kill (thread, 0); if (0 != result) { return result; } /* Validate the scheduling policy. */ if (policy < SCHED_MIN || policy > SCHED_MAX) { return EINVAL; } /* Ensure the policy is SCHED_OTHER. */ if (policy != SCHED_OTHER) { return ENOTSUP; } return (ptw32_setthreadpriority (thread, policy, param->sched_priority)); } int ptw32_setthreadpriority (pthread_t thread, int policy, int priority) { int prio; int result; ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; prio = priority; /* Validate priority level. */ if (prio < sched_get_priority_min (policy) || prio > sched_get_priority_max (policy)) { return EINVAL; } #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) /* WinCE */ #else /* Everything else */ if (THREAD_PRIORITY_IDLE < prio && THREAD_PRIORITY_LOWEST > prio) { prio = THREAD_PRIORITY_LOWEST; } else if (THREAD_PRIORITY_TIME_CRITICAL > prio && THREAD_PRIORITY_HIGHEST < prio) { prio = THREAD_PRIORITY_HIGHEST; } #endif result = pthread_mutex_lock (&tp->threadLock); if (0 == result) { /* If this fails, the current priority is unchanged. */ if (0 == SetThreadPriority (tp->threadH, prio)) { result = EINVAL; } else { /* * Must record the thread's sched_priority as given, * not as finally adjusted. */ tp->sched_priority = priority; } (void) pthread_mutex_unlock (&tp->threadLock); } return result; } nyquist-3.05/liblo/pthreads.2/sem_unlink.c0000644000175000000620000000401411512143043017537 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_unlink.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int sem_unlink (const char *name) { errno = ENOSYS; return -1; } /* sem_unlink */ nyquist-3.05/liblo/pthreads.2/pthread_condattr_destroy.c0000644000175000000620000000532411512143043022476 0ustar stevestaff/* * condvar_attr_destroy.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_condattr_destroy (pthread_condattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Destroys a condition variable attributes object. * The object can no longer be used. * * PARAMETERS * attr * pointer to an instance of pthread_condattr_t * * * DESCRIPTION * Destroys a condition variable attributes object. * The object can no longer be used. * * NOTES: * 1) Does not affect condition variables created * using 'attr' * * RESULTS * 0 successfully released attr, * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ { int result = 0; if (attr == NULL || *attr == NULL) { result = EINVAL; } else { (void) free (*attr); *attr = NULL; result = 0; } return result; } /* pthread_condattr_destroy */ nyquist-3.05/liblo/pthreads.2/pthread_cond_init.c0000644000175000000620000001032611512143043021053 0ustar stevestaff/* * pthread_cond_init.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * This function initializes a condition variable. * * PARAMETERS * cond * pointer to an instance of pthread_cond_t * * attr * specifies optional creation attributes. * * * DESCRIPTION * This function initializes a condition variable. * * RESULTS * 0 successfully created condition variable, * EINVAL 'attr' is invalid, * EAGAIN insufficient resources (other than * memory, * ENOMEM insufficient memory, * EBUSY 'cond' is already initialized, * * ------------------------------------------------------ */ { int result; pthread_cond_t cv = NULL; if (cond == NULL) { return EINVAL; } if ((attr != NULL && *attr != NULL) && ((*attr)->pshared == PTHREAD_PROCESS_SHARED)) { /* * Creating condition variable that can be shared between * processes. */ result = ENOSYS; goto DONE; } cv = (pthread_cond_t) calloc (1, sizeof (*cv)); if (cv == NULL) { result = ENOMEM; goto DONE; } cv->nWaitersBlocked = 0; cv->nWaitersToUnblock = 0; cv->nWaitersGone = 0; if (sem_init (&(cv->semBlockLock), 0, 1) != 0) { result = errno; goto FAIL0; } if (sem_init (&(cv->semBlockQueue), 0, 0) != 0) { result = errno; goto FAIL1; } if ((result = pthread_mutex_init (&(cv->mtxUnblockLock), 0)) != 0) { goto FAIL2; } result = 0; goto DONE; /* * ------------- * Failed... * ------------- */ FAIL2: (void) sem_destroy (&(cv->semBlockQueue)); FAIL1: (void) sem_destroy (&(cv->semBlockLock)); FAIL0: (void) free (cv); cv = NULL; DONE: if (0 == result) { EnterCriticalSection (&ptw32_cond_list_lock); cv->next = NULL; cv->prev = ptw32_cond_list_tail; if (ptw32_cond_list_tail != NULL) { ptw32_cond_list_tail->next = cv; } ptw32_cond_list_tail = cv; if (ptw32_cond_list_head == NULL) { ptw32_cond_list_head = cv; } LeaveCriticalSection (&ptw32_cond_list_lock); } *cond = cv; return result; } /* pthread_cond_init */ nyquist-3.05/liblo/pthreads.2/pthread_getconcurrency.c0000644000175000000620000000323211512143043022135 0ustar stevestaff/* * pthread_getconcurrency.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_getconcurrency (void) { return ptw32_concurrency; } nyquist-3.05/liblo/pthreads.2/pthread_attr_getschedpolicy.c0000644000175000000620000000375711512143043023157 0ustar stevestaff/* * pthread_attr_getschedpolicy.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_attr_getschedpolicy (pthread_attr_t * attr, int *policy) { if (ptw32_is_attr (attr) != 0 || policy == NULL) { return EINVAL; } /* * Validate the policy arg. * Check that a policy constant wasn't passed rather than &policy. */ if (policy <= (int *) SCHED_MAX) { return EINVAL; } *policy = SCHED_OTHER; return 0; } nyquist-3.05/liblo/pthreads.2/pthread_detach.c0000644000175000000620000001033711512143043020337 0ustar stevestaff/* * pthread_detach.c * * Description: * This translation unit implements functions related to thread * synchronisation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * Not needed yet, but defining it should indicate clashes with build target * environment that should be fixed. */ #include int pthread_detach (pthread_t thread) /* * ------------------------------------------------------ * DOCPUBLIC * This function detaches the given thread. * * PARAMETERS * thread * an instance of a pthread_t * * * DESCRIPTION * This function detaches the given thread. You may use it to * detach the main thread or to detach a joinable thread. * NOTE: detached threads cannot be joined; * storage is freed immediately on termination. * * RESULTS * 0 successfully detached the thread, * EINVAL thread is not a joinable thread, * ENOSPC a required resource has been exhausted, * ESRCH no thread could be found for 'thread', * * ------------------------------------------------------ */ { int result; BOOL destroyIt = PTW32_FALSE; ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; EnterCriticalSection (&ptw32_thread_reuse_lock); if (NULL == tp || thread.x != tp->ptHandle.x) { result = ESRCH; } else if (PTHREAD_CREATE_DETACHED == tp->detachState) { result = EINVAL; } else { /* * Joinable ptw32_thread_t structs are not scavenged until * a join or detach is done. The thread may have exited already, * but all of the state and locks etc are still there. */ result = 0; if (pthread_mutex_lock (&tp->cancelLock) == 0) { if (tp->state != PThreadStateLast) { tp->detachState = PTHREAD_CREATE_DETACHED; } else if (tp->detachState != PTHREAD_CREATE_DETACHED) { /* * Thread is joinable and has exited or is exiting. */ destroyIt = PTW32_TRUE; } (void) pthread_mutex_unlock (&tp->cancelLock); } else { /* cancelLock shouldn't fail, but if it does ... */ result = ESRCH; } } LeaveCriticalSection (&ptw32_thread_reuse_lock); if (result == 0) { /* Thread is joinable */ if (destroyIt) { /* The thread has exited or is exiting but has not been joined or * detached. Need to wait in case it's still exiting. */ (void) WaitForSingleObject(tp->threadH, INFINITE); ptw32_threadDestroy (thread); } } return (result); } /* pthread_detach */ nyquist-3.05/liblo/pthreads.2/sync.c0000644000175000000620000000321211512143043016346 0ustar stevestaff/* * sync.c * * Description: * This translation unit implements functions related to thread * synchronisation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_detach.c" #include "pthread_join.c" nyquist-3.05/liblo/pthreads.2/pthread_rwlockattr_setpshared.c0000644000175000000620000000751611512143043023532 0ustar stevestaff/* * pthread_rwlockattr_setpshared.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Rwlocks created with 'attr' can be shared between * processes if pthread_rwlock_t variable is allocated * in memory shared by these processes. * * PARAMETERS * attr * pointer to an instance of pthread_rwlockattr_t * * pshared * must be one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * DESCRIPTION * Rwlocks creatd with 'attr' can be shared between * processes if pthread_rwlock_t variable is allocated * in memory shared by these processes. * * NOTES: * 1) pshared rwlocks MUST be allocated in shared * memory. * * 2) The following macro is defined if shared rwlocks * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully set attribute, * EINVAL 'attr' or pshared is invalid, * ENOSYS PTHREAD_PROCESS_SHARED not supported, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && ((pshared == PTHREAD_PROCESS_SHARED) || (pshared == PTHREAD_PROCESS_PRIVATE))) { if (pshared == PTHREAD_PROCESS_SHARED) { #if !defined( _POSIX_THREAD_PROCESS_SHARED ) result = ENOSYS; pshared = PTHREAD_PROCESS_PRIVATE; #else result = 0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ } else { result = 0; } (*attr)->pshared = pshared; } else { result = EINVAL; } return (result); } /* pthread_rwlockattr_setpshared */ nyquist-3.05/liblo/pthreads.2/misc.c0000644000175000000620000000354611512143043016337 0ustar stevestaff/* * misc.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_kill.c" #include "pthread_once.c" #include "pthread_self.c" #include "pthread_equal.c" #include "pthread_setconcurrency.c" #include "pthread_getconcurrency.c" #include "ptw32_new.c" #include "ptw32_calloc.c" #include "ptw32_reuse.c" #include "w32_CancelableWait.c" nyquist-3.05/liblo/pthreads.2/pthread_num_processors_np.c0000644000175000000620000000352111512143043022662 0ustar stevestaff/* * pthread_num_processors_np.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * pthread_num_processors_np() * * Get the number of CPUs available to the process. */ int pthread_num_processors_np (void) { int count; if (ptw32_getprocessors (&count) != 0) { count = 1; } return (count); } nyquist-3.05/liblo/pthreads.2/barrier.c0000644000175000000620000000351711512143043017030 0ustar stevestaff/* * barrier.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_barrier_init.c" #include "pthread_barrier_destroy.c" #include "pthread_barrier_wait.c" #include "pthread_barrierattr_init.c" #include "pthread_barrierattr_destroy.c" #include "pthread_barrierattr_getpshared.c" #include "pthread_barrierattr_setpshared.c" nyquist-3.05/liblo/pthreads.2/Nmakefile.tests0000644000175000000620000001376511512143043020223 0ustar stevestaff/* for running tests */ CCFLAGS = -g _MT == 1 _timeb == timeb _ftime == ftime .SOURCE: tests /* :PACKAGE: pthread */ set keepgoing ":test:" : .MAKE .OPERATOR local I $(<:D:B:S=.pass) : .IMPLICIT $(>:D:B:S=.pass) for I $(<) $(>) $(I:D:B:S=.pass) : .VIRTUAL .FORCE $(I) $(>) end sizes:: sizes.c loadfree:: loadfree.c mutex1:: mutex1.c mutex1e:: mutex1e.c mutex1n:: mutex1n.c mutex1r:: mutex1r.c mutex2:: mutex2.c mutex2r:: mutex2r.c mutex2e:: mutex2e.c exit1:: exit1.c condvar1:: condvar1.c condvar1_1:: condvar1_1.c condvar1_2:: condvar1_2.c self1:: self1.c condvar2:: condvar2.c condvar2_1:: condvar2_1.c condvar3_1:: condvar3_1.c condvar3_2:: condvar3_2.c condvar3_3:: condvar3_3.c create1.:: create1.c create2.:: create2.c cancel1:: cancel1.c cancel2:: cancel2.c mutex3:: mutex3.c mutex3r:: mutex3r.c mutex3e:: mutex3e.c mutex4:: mutex4.c mutex5:: mutex5.c mutex6:: mutex6.c mutex6e:: mutex6e.c mutex6n:: mutex6n.c mutex6r:: mutex6r.c mutex7:: mutex7.c mutex6s:: mutex6s.c mutex6rs:: mutex6rs.c mutex6es:: mutex6es.c mutex7e:: mutex7e.c mutex7n:: mutex7n.c mutex7r:: mutex7r.c mutex8:: mutex8.c mutex8e:: mutex8e.c mutex8n:: mutex8n.c mutex8r:: mutex8r.c equal1:: equal1.c exit2:: exit2.c exit3:: exit3.c exit4:: exit4.c exit5:: exit5.c join0:: join0.c join1:: join1.c join2:: join2.c join3:: join3.c kill1:: kill1.c count1:: count1.c once1:: once1.c tsd1:: tsd1.c self2:: self2.c eyal1:: eyal1.c condvar3:: condvar3.c condvar4:: condvar4.c condvar5:: condvar5.c condvar6:: condvar6.c condvar7:: condvar7.c condvar8:: condvar8.c condvar9:: condvar9.c errno1:: errno1.c reuse1.:: reuse1.c reuse2.:: reuse2.c rwlock1:: rwlock1.c rwlock2:: rwlock2.c rwlock3:: rwlock3.c rwlock4:: rwlock4.c rwlock5:: rwlock5.c rwlock6:: rwlock6.c rwlock7:: rwlock7.c rwlock8:: rwlock8.c rwlock2_t:: rwlock2_t.c rwlock3_t:: rwlock3_t.c rwlock4_t:: rwlock4_t.c rwlock5_t:: rwlock5_t.c rwlock6_t:: rwlock6_t.c rwlock6_t2:: rwlock6_t2.c semaphore1:: semaphore1.c semaphore2:: semaphore2.c semaphore3:: semaphore3.c context1:: context1.c cancel3:: cancel3.c cancel4:: cancel4.c cancel5:: cancel5.c cancel6a:: cancel6a.c cancel6d:: cancel6d.c cancel7:: cancel7.c cleanup0:: cleanup0.c cleanup1:: cleanup1.c cleanup2:: cleanup2.c cleanup3:: cleanup3.c priority1:: priority1.c priority2:: priority2.c inherit1:: inherit1.c spin1:: spin1.c spin2:: spin2.c spin3:: spin3.c spin4:: spin4.c barrier1:: barrier1.c barrier2:: barrier2.c barrier3:: barrier3.c barrier4:: barrier4.c barrier5:: barrier5.c exception1:: exception1.c exception2:: exception2.c exception3:: exception3.c benchtest1:: benchtest1.c benchtest2:: benchtest2.c benchtest3:: benchtest3.c benchtest4:: benchtest4.c benchtest5:: benchtest5.c valid1:: valid1.c valid2:: valid2.c cancel9:: cancel9.c sizes: :test: sizes loadfree: :test: mutex5 :test: loadfree mutex1 :test: loadfree mutex1n :test: loadfree mutex1r :test: loadfree mutex1e :test: loadfree semaphore1 :test: loadfree semaphore2 :test: loadfree semaphore3 :test: loadfree mutex2 :test: loadfree mutex2r :test: loadfree mutex2e :test: loadfree exit1 :test: loadfree condvar1 :test: loadfree kill1 :test: loadfree condvar1_1 :test: condvar1 condvar1_2 :test: join2 self1 :test: loadfree condvar2 :test: condvar1 condvar2_1 :test: condvar2 create1 :test: mutex2 create2 :test: create1 reuse1 :test: create2 reuse2 :test: reuse1 cancel1 :test: create1 cancel2 :test: cancel1 mutex3 :test: create1 mutex3r :test: create1 mutex3e :test: create1 mutex4 :test: mutex3 mutex6 :test: mutex4 mutex6n :test: mutex4 mutex6e :test: mutex4 mutex6r :test: mutex4 mutex6s :test: mutex6 mutex6rs :test: mutex6r mutex6es :test: mutex6e mutex7 :test: mutex6 mutex7n :test: mutex6n mutex7e :test: mutex6e mutex7r :test: mutex6r mutex8 :test: mutex7 mutex8n :test: mutex7n mutex8e :test: mutex7e mutex8r :test: mutex7r equal1 :test: create1 exit2 :test: create1 exit3 :test: create1 exit4 :test: kill1 exit5 :test: exit4 join0 :test: create1 join1 :test: create1 join2 :test: create1 join3 :test: join2 count1 :test: join1 once1 :test: create1 tsd1 :test: join1 self2 :test: create1 eyal1 :test: tsd1 condvar3 :test: create1 condvar3_1 :test: condvar3 condvar3_2 :test: condvar3_1 condvar3_3 :test: condvar3_2 condvar4 :test: create1 condvar5 :test: condvar4 condvar6 :test: condvar5 condvar7 :test: condvar6 cleanup1 condvar8 :test: condvar7 condvar9 :test: condvar8 errno1 :test: mutex3 rwlock1 :test: condvar6 rwlock2 :test: rwlock1 rwlock3 :test: rwlock2 rwlock4 :test: rwlock3 rwlock5 :test: rwlock4 rwlock6 :test: rwlock5 rwlock7 :test: rwlock6 rwlock8 :test: rwlock7 rwlock2_t :test: rwlock2 rwlock3_t :test: rwlock2_t rwlock4_t :test: rwlock3_t rwlock5_t :test: rwlock4_t rwlock6_t :test: rwlock5_t rwlock6_t2 :test: rwlock6_t context1 :test: cancel2 cancel3 :test: context1 cancel4 :test: cancel3 cancel5 :test: cancel3 cancel6a :test: cancel3 cancel6d :test: cancel3 cancel7 :test: kill1 cleanup0 :test: cancel5 cleanup1 :test: cleanup0 cleanup2 :test: cleanup1 cleanup3 :test: cleanup2 priority1 :test: join1 priority2 :test: priority1 inherit1 :test: join1 spin1 :test: spin2 :test: spin1.c spin3 :test: spin2.c spin4 :test: spin3.c barrier1 :test: barrier2 :test: barrier1.c barrier3 :test: barrier2.c barrier4 :test: barrier3.c barrier5 :test: barrier4.c benchtest1 :test: mutex3 benchtest2 :test: benchtest1 benchtest3 :test: benchtest2 benchtest4 :test: benchtest3 benchtest5 :test: benchtest4 exception1 :test: cancel4 exception2 :test: exception1 exception3 :test: exception2 exit4 :test: exit3 valid1 :test: join1 valid2 :test: valid1 cancel9 :test: cancel8 nyquist-3.05/liblo/pthreads.2/pthread_key_create.c0000644000175000000620000000753111512143043021224 0ustar stevestaff/* * pthread_key_create.c * * Description: * POSIX thread functions which implement thread-specific data (TSD). * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* TLS_OUT_OF_INDEXES not defined on WinCE */ #ifndef TLS_OUT_OF_INDEXES #define TLS_OUT_OF_INDEXES 0xffffffff #endif int pthread_key_create (pthread_key_t * key, void (*destructor) (void *)) /* * ------------------------------------------------------ * DOCPUBLIC * This function creates a thread-specific data key visible * to all threads. All existing and new threads have a value * NULL for key until set using pthread_setspecific. When any * thread with a non-NULL value for key terminates, 'destructor' * is called with key's current value for that thread. * * PARAMETERS * key * pointer to an instance of pthread_key_t * * * DESCRIPTION * This function creates a thread-specific data key visible * to all threads. All existing and new threads have a value * NULL for key until set using pthread_setspecific. When any * thread with a non-NULL value for key terminates, 'destructor' * is called with key's current value for that thread. * * RESULTS * 0 successfully created semaphore, * EAGAIN insufficient resources or PTHREAD_KEYS_MAX * exceeded, * ENOMEM insufficient memory to create the key, * * ------------------------------------------------------ */ { int result = 0; pthread_key_t newkey; if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL) { result = ENOMEM; } else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) { result = EAGAIN; free (newkey); newkey = NULL; } else if (destructor != NULL) { /* * Have to manage associations between thread and key; * Therefore, need a lock that allows multiple threads * to gain exclusive access to the key->threads list. * * The mutex will only be created when it is first locked. */ newkey->keyLock = PTHREAD_MUTEX_INITIALIZER; newkey->destructor = destructor; } *key = newkey; return (result); } nyquist-3.05/liblo/pthreads.2/pthread_attr_getstacksize.c0000644000175000000620000000646611512143043022651 0ustar stevestaff/* * pthread_attr_getstacksize.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize) /* * ------------------------------------------------------ * DOCPUBLIC * This function determines the size of the stack on * which threads created with 'attr' will run. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * stacksize * pointer to size_t into which is returned the * stack size, in bytes. * * * DESCRIPTION * This function determines the size of the stack on * which threads created with 'attr' will run. * * NOTES: * 1) Function supported only if this macro is * defined: * * _POSIX_THREAD_ATTR_STACKSIZE * * 2) Use on newly created attributes object to * find the default stack size. * * RESULTS * 0 successfully retrieved stack size, * EINVAL 'attr' is invalid * ENOSYS function not supported * * ------------------------------------------------------ */ { #ifdef _POSIX_THREAD_ATTR_STACKSIZE if (ptw32_is_attr (attr) != 0) { return EINVAL; } /* Everything is okay. */ *stacksize = (*attr)->stacksize; return 0; #else return ENOSYS; #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ } nyquist-3.05/liblo/pthreads.2/pthread_attr_getinheritsched.c0000644000175000000620000000351711512143043023314 0ustar stevestaff/* * pthread_attr_getinheritsched.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_attr_getinheritsched (pthread_attr_t * attr, int *inheritsched) { if (ptw32_is_attr (attr) != 0 || inheritsched == NULL) { return EINVAL; } *inheritsched = (*attr)->inheritsched; return 0; } nyquist-3.05/liblo/pthreads.2/global.c0000644000175000000620000000736011512143043016642 0ustar stevestaff/* * global.c * * Description: * This translation unit instantiates data associated with the implementation * as a whole. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int ptw32_processInitialized = PTW32_FALSE; ptw32_thread_t * ptw32_threadReuseTop = PTW32_THREAD_REUSE_EMPTY; ptw32_thread_t * ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; pthread_key_t ptw32_selfThreadKey = NULL; pthread_key_t ptw32_cleanupKey = NULL; pthread_cond_t ptw32_cond_list_head = NULL; pthread_cond_t ptw32_cond_list_tail = NULL; int ptw32_concurrency = 0; /* What features have been auto-detaected */ int ptw32_features = 0; BOOL ptw32_smp_system = PTW32_TRUE; /* Safer if assumed true initially. */ /* * Function pointer to InterlockedCompareExchange if it exists, otherwise * it will be set at runtime to a substitute local version with the same * functionality but may be architecture specific. */ PTW32_INTERLOCKED_LONG (WINAPI * ptw32_interlocked_compare_exchange) (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG) = NULL; /* * Function pointer to QueueUserAPCEx if it exists, otherwise * it will be set at runtime to a substitute routine which cannot unblock * blocked threads. */ DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD) = NULL; /* * Global lock for managing pthread_t struct reuse. */ CRITICAL_SECTION ptw32_thread_reuse_lock; /* * Global lock for testing internal state of statically declared mutexes. */ CRITICAL_SECTION ptw32_mutex_test_init_lock; /* * Global lock for testing internal state of PTHREAD_COND_INITIALIZER * created condition variables. */ CRITICAL_SECTION ptw32_cond_test_init_lock; /* * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER * created read/write locks. */ CRITICAL_SECTION ptw32_rwlock_test_init_lock; /* * Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER * created spin locks. */ CRITICAL_SECTION ptw32_spinlock_test_init_lock; /* * Global lock for condition variable linked list. The list exists * to wake up CVs when a WM_TIMECHANGE message arrives. See * w32_TimeChangeHandler.c. */ CRITICAL_SECTION ptw32_cond_list_lock; #ifdef _UWIN /* * Keep a count of the number of threads. */ int pthread_count = 0; #endif nyquist-3.05/liblo/pthreads.2/pthreadVC2.dll.embed.manifest.res0000644000175000000620000000133011512143043023334 0ustar stevestaff  0  nyquist-3.05/liblo/pthreads.2/errno.c0000644000175000000620000000542611512143043016530 0ustar stevestaff/* * errno.c * * Description: * This translation unit implements routines associated with spawning a new * thread. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if defined(NEED_ERRNO) #include "pthread.h" #include "implement.h" static int reallyBad = ENOMEM; /* * Re-entrant errno. * * Each thread has it's own errno variable in pthread_t. * * The benefit of using the pthread_t structure * instead of another TSD key is TSD keys are limited * on Win32 to 64 per process. Secondly, to implement * it properly without using pthread_t you'd need * to dynamically allocate an int on starting the thread * and store it manually into TLS and then ensure that you free * it on thread termination. We get all that for free * by simply storing the errno on the pthread_t structure. * * MSVC and Mingw32 already have their own thread-safe errno. * * #if defined( _REENTRANT ) || defined( _MT ) * #define errno *_errno() * * int *_errno( void ); * #else * extern int errno; * #endif * */ int * _errno (void) { pthread_t self; int *result; if ((self = pthread_self ()) == NULL) { /* * Yikes! unable to allocate a thread! * Throw an exception? return an error? */ result = &reallyBad; } else { result = &(self->ptErrno); } return (result); } /* _errno */ #endif /* (NEED_ERRNO) */ nyquist-3.05/liblo/pthreads.2/sem_init.c0000644000175000000620000001113311512143043017202 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_init.c * * Purpose: * Semaphores aren't actually part of PThreads. * They are defined by the POSIX Standard: * * POSIX 1003.1-2001 * * ------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" int sem_init (sem_t * sem, int pshared, unsigned int value) /* * ------------------------------------------------------ * DOCPUBLIC * This function initializes a semaphore. The * initial value of the semaphore is 'value' * * PARAMETERS * sem * pointer to an instance of sem_t * * pshared * if zero, this semaphore may only be shared between * threads in the same process. * if nonzero, the semaphore can be shared between * processes * * value * initial value of the semaphore counter * * DESCRIPTION * This function initializes a semaphore. The * initial value of the semaphore is set to 'value'. * * RESULTS * 0 successfully created semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, or * 'value' >= SEM_VALUE_MAX * ENOMEM out of memory, * ENOSPC a required resource has been exhausted, * ENOSYS semaphores are not supported, * EPERM the process lacks appropriate privilege * * ------------------------------------------------------ */ { int result = 0; sem_t s = NULL; if (pshared != 0) { /* * Creating a semaphore that can be shared between * processes */ result = EPERM; } else if (value > (unsigned int)SEM_VALUE_MAX) { result = EINVAL; } else { s = (sem_t) calloc (1, sizeof (*s)); if (NULL == s) { result = ENOMEM; } else { s->value = value; if (pthread_mutex_init(&s->lock, NULL) == 0) { #ifdef NEED_SEM s->sem = CreateEvent (NULL, PTW32_FALSE, /* auto (not manual) reset */ PTW32_FALSE, /* initial state is unset */ NULL); if (0 == s->sem) { free (s); (void) pthread_mutex_destroy(&s->lock); result = ENOSPC; } else { s->leftToUnblock = 0; } #else /* NEED_SEM */ if ((s->sem = CreateSemaphore (NULL, /* Always NULL */ (long) 0, /* Force threads to wait */ (long) SEM_VALUE_MAX, /* Maximum value */ NULL)) == 0) /* Name */ { (void) pthread_mutex_destroy(&s->lock); result = ENOSPC; } #endif /* NEED_SEM */ } else { result = ENOSPC; } if (result != 0) { free(s); } } } if (result != 0) { errno = result; return -1; } *sem = s; return 0; } /* sem_init */ nyquist-3.05/liblo/pthreads.2/COPYING0000644000175000000620000001346311512143043016272 0ustar stevestaff pthreads-win32 - a POSIX threads library for Microsoft Windows This file is Copyrighted ------------------------ This file is covered under the following Copyright: Copyright (C) 2001,2006 Ross P. Johnson All rights reserved. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Pthreads-win32 is covered by the GNU Lesser General Public License ------------------------------------------------------------------ Pthreads-win32 is open 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 version 2.1 of the License. Pthreads-win32 is several binary link libraries, several modules, associated interface definition files and scripts used to control its compilation and installation. Pthreads-win32 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. A copy of the GNU Lesser General Public License is distributed with pthreads-win32 under the filename: COPYING.LIB You should have received a copy of the version 2.1 GNU Lesser General Public License with pthreads-win32; if not, write to: Free Software Foundation, Inc. 59 Temple Place Suite 330 Boston, MA 02111-1307 USA The contact addresses for pthreads-win32 is as follows: Web: http://sources.redhat.com/pthreads-win32 Email: Ross Johnson Please use: Firstname.Lastname@homemail.com.au Pthreads-win32 copyrights and exception files --------------------------------------------- With the exception of the files listed below, Pthreads-win32 is covered under the following GNU Lesser General Public License Copyrights: Pthreads-win32 - POSIX Threads Library for Win32 Copyright(C) 1998 John E. Bossom Copyright(C) 1999,2006 Pthreads-win32 contributors The current list of contributors is contained in the file CONTRIBUTORS included with the source code distribution. The current list of CONTRIBUTORS can also be seen at the following WWW location: http://sources.redhat.com/pthreads-win32/contributors.html Contact Email: Ross Johnson Please use: Firstname.Lastname@homemail.com.au These files are not covered under one of the Copyrights listed above: COPYING COPYING.LIB tests/rwlock7.c This file, COPYING, is distributed under the Copyright found at the top of this file. It is important to note that you may distribute verbatim copies of this file but you may not modify this file. The file COPYING.LIB, which contains a copy of the version 2.1 GNU Lesser General Public License, is itself copyrighted by the Free Software Foundation, Inc. Please note that the Free Software Foundation, Inc. does NOT have a copyright over Pthreads-win32, only the COPYING.LIB that is supplied with pthreads-win32. The file tests/rwlock7.c is derived from code written by Dave Butenhof for his book 'Programming With POSIX(R) Threads'. The original code was obtained by free download from his website http://home.earthlink.net/~anneart/family/Threads/source.html and did not contain a copyright or author notice. It is assumed to be freely distributable. In all cases one may use and distribute these exception files freely. And because one may freely distribute the LGPL covered files, the entire pthreads-win32 source may be freely used and distributed. General Copyleft and License info --------------------------------- For general information on Copylefts, see: http://www.gnu.org/copyleft/ For information on GNU Lesser General Public Licenses, see: http://www.gnu.org/copyleft/lesser.html http://www.gnu.org/copyleft/lesser.txt Why pthreads-win32 did not use the GNU General Public License ------------------------------------------------------------- The goal of the pthreads-win32 project has been to provide a quality and complete implementation of the POSIX threads API for Microsoft Windows within the limits imposed by virtue of it being a stand-alone library and not linked directly to other POSIX compliant libraries. For example, some functions and features, such as those based on POSIX signals, are missing. Pthreads-win32 is a library, available in several different versions depending on supported compilers, and may be used as a dynamically linked module or a statically linked set of binary modules. It is not an application on it's own. It was fully intended that pthreads-win32 be usable with commercial software not covered by either the GPL or the LGPL licenses. Pthreads-win32 has many contributors to it's code base, many of whom have done so because they have used the library in commercial or proprietry software projects. Releasing pthreads-win32 under the LGPL ensures that the library can be used widely, while at the same time ensures that bug fixes and improvements to the pthreads-win32 code itself is returned to benefit all current and future users of the library. Although pthreads-win32 makes it possible for applications that use POSIX threads to be ported to Win32 platforms, the broader goal of the project is to encourage the use of open standards, and in particular, to make it just a little easier for developers writing Win32 applications to consider widening the potential market for their products. nyquist-3.05/liblo/pthreads.2/sched.c0000644000175000000620000000406711512143043016471 0ustar stevestaff/* * sched.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" #include "pthread_attr_setschedpolicy.c" #include "pthread_attr_getschedpolicy.c" #include "pthread_attr_setschedparam.c" #include "pthread_attr_getschedparam.c" #include "pthread_attr_setinheritsched.c" #include "pthread_attr_getinheritsched.c" #include "pthread_setschedparam.c" #include "pthread_getschedparam.c" #include "sched_get_priority_max.c" #include "sched_get_priority_min.c" #include "sched_setscheduler.c" #include "sched_getscheduler.c" #include "sched_yield.c" nyquist-3.05/liblo/pthreads.2/ptw32_cond_check_need_init.c0000644000175000000620000000636411512143043022542 0ustar stevestaff/* * ptw32_cond_check_need_init.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" INLINE int ptw32_cond_check_need_init (pthread_cond_t * cond) { int result = 0; /* * The following guarded test is specifically for statically * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER). * * Note that by not providing this synchronisation we risk * introducing race conditions into applications which are * correctly written. * * Approach * -------- * We know that static condition variables will not be PROCESS_SHARED * so we can serialise access to internal state using * Win32 Critical Sections rather than Win32 Mutexes. * * If using a single global lock slows applications down too much, * multiple global locks could be created and hashed on some random * value associated with each mutex, the pointer perhaps. At a guess, * a good value for the optimal number of global locks might be * the number of processors + 1. * */ EnterCriticalSection (&ptw32_cond_test_init_lock); /* * We got here possibly under race * conditions. Check again inside the critical section. * If a static cv has been destroyed, the application can * re-initialise it only by calling pthread_cond_init() * explicitly. */ if (*cond == PTHREAD_COND_INITIALIZER) { result = pthread_cond_init (cond, NULL); } else if (*cond == NULL) { /* * The cv has been destroyed while we were waiting to * initialise it, so the operation that caused the * auto-initialisation should fail. */ result = EINVAL; } LeaveCriticalSection (&ptw32_cond_test_init_lock); return result; } nyquist-3.05/liblo/pthreads.2/NEWS0000644000175000000620000011331311512143043015731 0ustar stevestaffRELEASE 2.8.0 ------------- (2006-12-22) General ------- New bug fixes in this release since 2.7.0 have not been applied to the version 1.x.x series. It is probably time to drop version 1. Testing and verification ------------------------ This release has not yet been tested on SMP architechtures. All tests pass on a uni-processor system. Bug fixes --------- Sem_destroy could return EBUSY even though no threads were waiting on the semaphore. Other races around invalidating semaphore structs (internally) have been removed as well. New tests --------- semaphore5.c - tests the bug fix referred to above. RELEASE 2.7.0 ------------- (2005-06-04) General ------- All new features in this release have been back-ported in release 1.11.0, including the incorporation of MCS locks in pthread_once, however, versions 1 and 2 remain incompatible even though they are now identical in performance and functionality. Testing and verification ------------------------ This release has been tested (passed the test suite) on both uni-processor and multi-processor systems. - Tim Theisen Bug fixes --------- Pthread_once has been re-implemented to remove priority boosting and other complexity to improve robustness. Races for Win32 handles that are not recycle-unique have been removed. The general form of pthread_once is now the same as that suggested earlier by Alexander Terekhov, but instead of the 'named mutex', a queue-based lock has been implemented which has the required properties of dynamic self initialisation and destruction. This lock is also efficient. The ABI is unaffected in as much as the size of pthread_once_t has not changed and PTHREAD_ONCE_INIT has not changed, however, applications that peek inside pthread_once_t, which is supposed to be opaque, will break. - Vladimir Kliatchko New features ------------ * Support for Mingw cross development tools added to GNUmakefile. Mingw cross tools allow building the libraries on Linux. - Mikael Magnusson RELEASE 2.6.0 ------------- (2005-05-19) General ------- All of the bug fixes and new features in this release have been back-ported in release 1.10.0. Testing and verification ------------------------ This release has been tested (passed the test suite) on both uni-processor and multi-processor systems. Thanks to Tim Theisen at TomoTherapy for exhaustively running the MP tests and for providing crutial observations and data when faults are detected. Bugs fixed ---------- * pthread_detach() now reclaims remaining thread resources if called after the target thread has terminated. Previously, this routine did nothing in this case. New tests --------- * detach1.c - tests that pthread_detach properly invalidates the target thread, which indicates that the thread resources have been reclaimed. RELEASE 2.5.0 ------------- (2005-05-09) General ------- The package now includes a reference documentation set consisting of HTML formatted Unix-style manual pages that have been edited for consistency with Pthreads-w32. The set can also be read online at: http://sources.redhat.com/pthreads-win32/manual/index.html Thanks again to Tim Theisen for running the test suite pre-release on an MP system. All of the bug fixes and new features in this release have been back-ported in release 1.9.0. Bugs fixed ---------- * Thread Specific Data (TSD) key management has been ammended to eliminate a source of (what was effectively) resource leakage (a HANDLE plus memory for each key destruct routine/thread association). This was not a true leak because these resources were eventually reclaimed when pthread_key_delete was run AND each thread referencing the key had exited. The problem was that these two conditions are often not met until very late, and often not until the process is about to exit. The ammended implementation avoids the need for the problematic HANDLE and reclaims the memory as soon as either the key is deleted OR the thread exits, whichever is first. Thanks to Richard Hughes at Aculab for identifying and locating the leak. * TSD key destructors are now processed up to PTHREAD_DESTRUCTOR_ITERATIONS times instead of just once. PTHREAD_DESTRUCTOR_ITERATIONS has been defined in pthread.h for some time but not used. * Fix a semaphore accounting race between sem_post/sem_post_multiple and sem_wait cancellation. This is the same issue as with sem_timedwait that was fixed in the last release. * sem_init, sem_post, and sem_post_multiple now check that the semaphore count never exceeds _POSIX_SEM_VALUE_MAX. * Although sigwait() is nothing more than a no-op, it should at least be a cancellation point to be consistent with the standard. New tests --------- * stress1.c - attempts to expose problems in condition variable and semaphore timed wait logic. This test was inspired by Stephan Mueller's sample test code used to identify the sem_timedwait bug from the last release. It's not a part of the regular test suite because it can take awhile to run. To run it: nmake clean VC-stress * tsd2.c - tests that key destructors are re-run if the tsd key value is not NULL after the destructor routine has run. Also tests that pthread_setspecific() and pthread_getspecific() are callable from destructors. RELEASE 2.4.0 ------------- (2005-04-26) General ------- There is now no plan to release a version 3.0.0 to fix problems in pthread_once(). Other possible implementations of pthread_once will still be investigated for a possible future release in an attempt to reduce the current implementation's complexity. All of the bug fixes and new features in this release have been back-ported for release 1.8.0. Bugs fixed ---------- * Fixed pthread_once race (failures on an MP system). Thanks to Tim Theisen for running exhaustive pre-release testing on his MP system using a range of compilers: VC++ 6 VC++ 7.1 Intel C++ version 8.0 All tests passed. Some minor speed improvements were also done. * Fix integer overrun error in pthread_mutex_timedlock() - missed when sem_timedwait() was fixed in release 2.2.0. This routine no longer returns ENOTSUP when NEED_SEM is defined - it is supported (NEED_SEM is only required for WinCE versions prior to 3.0). * Fix timeout bug in sem_timedwait(). - Thanks to Stephan Mueller for reporting, providing diagnostic output and test code. * Fix several problems in the NEED_SEM conditionally included code. NEED_SEM included code is provided for systems that don't implement W32 semaphores, such as WinCE prior to version 3.0. An alternate implementation of POSIX semaphores is built using W32 events for these systems when NEED_SEM is defined. This code has been completely rewritten in this release to reuse most of the default POSIX semaphore code, and particularly, to implement all of the sem_* routines supported by pthreads-win32. Tim Theisen also run the test suite over the NEED_SEM code on his MP system. All tests passed. * The library now builds without errors for the Borland Builder 5.5 compiler. New features ------------ * pthread_mutex_timedlock() and all sem_* routines provided by pthreads-win32 are now implemented for WinCE versions prior to 3.0. Those versions did not implement W32 semaphores. Define NEED_SEM in config.h when building the library for these systems. Known issues in this release ---------------------------- * pthread_once is too complicated - but it works as far as testing can determine.. * The Borland version of the dll fails some of the tests with a memory read exception. The cause is not yet known but a compiler bug has not been ruled out. RELEASE 2.3.0 ------------- (2005-04-12) General ------- Release 1.7.0 is a backport of features and bug fixes new in this release. See earlier notes under Release 2.0.0/General. Bugs fixed ---------- * Fixed pthread_once potential for post once_routine cancellation hanging due to starvation. See comments in pthread_once.c. Momentary priority boosting is used to ensure that, after a once_routine is cancelled, the thread that will run the once_routine is not starved by higher priority waiting threads at critical times. Priority boosting occurs only AFTER a once_routine cancellation, and is applied only to that once_control. The once_routine is run at the thread's normal base priority. New tests --------- * once4.c: Aggressively tests pthread_once() under realtime conditions using threads with varying priorities. Windows' random priority boosting does not occur for threads with realtime priority levels. RELEASE 2.2.0 ------------- (2005-04-04) General ------- * Added makefile targets to build static link versions of the library. Both MinGW and MSVC. Please note that this does not imply any change to the LGPL licensing, which still imposes psecific conditions on distributing software that has been statically linked with this library. * There is a known bug in pthread_once(). Cancellation of the init_routine exposes a potential starvation (i.e. deadlock) problem if a waiting thread has a higher priority than the initting thread. This problem will be fixed in version 3.0.0 of the library. Bugs fixed ---------- * Fix integer overrun error in sem_timedwait(). Kevin Lussier * Fix preprocessor directives for static linking. Dimitar Panayotov RELEASE 2.1.0 ------------- (2005-03-16) Bugs fixed ---------- * Reverse change to pthread_setcancelstate() in 2.0.0. RELEASE 2.0.0 ------------- (2005-03-16) General ------- This release represents an ABI change and the DLL version naming has incremented from 1 to 2, e.g. pthreadVC2.dll. Version 1.4.0 back-ports the new functionality included in this release. Please distribute DLLs built from that version with updates to applications built on pthreads-win32 version 1.x.x. The package naming has changed, replacing the snapshot date with the version number + descriptive information. E.g. this release is "pthreads-w32-2-0-0-release". Bugs fixed ---------- * pthread_setcancelstate() no longer checks for a pending async cancel event if the library is using alertable async cancel. See the README file (Prerequisites section) for info on adding alertable async cancelation. New features ------------ * pthread_once() now supports init_routine cancellability. New tests --------- * Agressively test pthread_once() init_routine cancellability. SNAPSHOT 2005-03-08 ------------------- Version 1.3.0 Bug reports (fixed) ------------------- * Implicitly created threads leave Win32 handles behind after exiting. - Dmitrii Semii * pthread_once() starvation problem. - Gottlob Frege New tests --------- * More intense testing of pthread_once(). SNAPSHOT 2005-01-25 ------------------- Version 1.2.0 Bug fixes --------- * Attempted acquisition of a recursive mutex could cause waiting threads to not be woken when the mutex was released. - Ralf Kubis * Various package omissions have been fixed. SNAPSHOT 2005-01-03 ------------------- Version 1.1.0 Bug fixes --------- * Unlocking recursive or errorcheck mutexes would sometimes unexpectedly return an EPERM error (bug introduced in snapshot-2004-11-03). - Konstantin Voronkov SNAPSHOT 2004-11-22 ------------------- Version 1.0.0 This snapshot primarily fixes the condvar bug introduced in snapshot-2004-11-03. DLL versioning has also been included to allow applications to runtime check the Microsoft compatible DLL version information, and to extend the DLL naming system for ABI and major (non-backward compatible) API changes. See the README file for details. Bug fixes --------- * Condition variables no longer deadlock (bug introduced in snapshot-2004-11-03). - Alexander Kotliarov and Nicolas at saintmac * DLL naming extended to avoid 'DLL hell' in the future, and to accommodate the ABI change introduced in snapshot-2004-11-03. Snapshot 2004-11-03 will be removed from FTP sites. New features ------------ * A Microsoft-style version resource has been added to the DLL for applications that wish to check DLL compatibility at runtime. * Pthreads-win32 DLL naming has been extended to allow incompatible DLL versions to co-exist in the same filesystem. See the README file for details, but briefly: while the version information inside the DLL will change with each release from now on, the DLL version names will only change if the new DLL is not backward compatible with older applications. The versioning scheme has been borrowed from GNU Libtool, and the DLL naming scheme is from Cygwin. Provided the Libtool-style numbering rules are honoured, the Cygwin DLL naming scheme automatcally ensures that DLL name changes are minimal and that applications will not load an incompatible pthreads-win32 DLL. Those who use the pre-built DLLs will find that the DLL/LIB names have a new suffix (1) in this snapshot. E.g. pthreadVC1.dll etc. * The POSIX thread ID reuse uniqueness feature introduced in the last snapshot has been kept as default, but the behaviour can now be controlled when the DLL is built to effectively switch it off. This makes the library much more sensitive to applications that assume that POSIX thread IDs are unique, i.e. are not strictly compliant with POSIX. See the PTW32_THREAD_ID_REUSE_INCREMENT macro comments in config.h for details. Other changes ------------- Certain POSIX macros have changed. These changes are intended to conform to the Single Unix Specification version 3, which states that, if set to 0 (zero) or not defined, then applications may use sysconf() to determine their values at runtime. Pthreads-win32 does not implement sysconf(). The following macros are no longer undefined, but defined and set to -1 (not implemented): _POSIX_THREAD_ATTR_STACKADDR _POSIX_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_PROTECT _POSIX_THREAD_PROCESS_SHARED The following macros are defined and set to 200112L (implemented): _POSIX_THREADS _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_THREAD_ATTR_STACKSIZE _POSIX_THREAD_PRIORITY_SCHEDULING _POSIX_SEMAPHORES _POSIX_READER_WRITER_LOCKS _POSIX_SPIN_LOCKS _POSIX_BARRIERS The following macros are defined and set to appropriate values: _POSIX_THREAD_THREADS_MAX _POSIX_SEM_VALUE_MAX _POSIX_SEM_NSEMS_MAX PTHREAD_DESTRUCTOR_ITERATIONS PTHREAD_KEYS_MAX PTHREAD_STACK_MIN PTHREAD_THREADS_MAX SNAPSHOT 2004-11-03 ------------------- DLLs produced from this snapshot cannot be used with older applications without recompiling the application, due to a change to pthread_t to provide unique POSIX thread IDs. Although this snapshot passes the extended test suite, many of the changes are fairly major, and some applications may show different behaviour than previously, so adopt with care. Hopefully, any changed behaviour will be due to the library being better at it's job, not worse. Bug fixes --------- * pthread_create() no longer accepts NULL as the thread reference arg. A segfault (memory access fault) will result, and no thread will be created. * pthread_barrier_wait() no longer acts as a cancelation point. * Fix potential race condition in pthread_once() - Tristan Savatier * Changes to pthread_cond_destroy() exposed some coding weaknesses in several test suite mini-apps because pthread_cond_destroy() now returns EBUSY if the CV is still in use. New features ------------ * Added for compatibility: PTHREAD_RECURSIVE_MUTEX_INITIALIZER, PTHREAD_ERRORCHECK_MUTEX_INITIALIZER, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP * Initial support for Digital Mars compiler - Anuj Goyal * Faster Mutexes. These have been been rewritten following a model provided by Alexander Terekhov that reduces kernel space checks, and eliminates some additional critical sections used to manage a race between timedlock expiration and unlock. Please be aware that the new mutexes do not enforce strict absolute FIFO scheduling of mutexes, however any out-of-order lock acquisition should be very rare. * Faster semaphores. Following a similar model to mutexes above, these have been rewritten to use preliminary users space checks. * sem_getvalue() now returns the number of waiters. * The POSIX thread ID now has much stronger uniqueness characteristics. The library garrantees not to reuse the same thread ID for at least 2^(wordsize) thread destruction/creation cycles. New tests --------- * semaphore4.c: Tests cancelation of the new sem_wait(). * semaphore4t.c: Likewise for sem_timedwait(). * rwlock8.c: Tests and times the slow execution paths of r/w locks, and the CVs, mutexes, and semaphores that they're built on. SNAPSHOT 2004-05-16 ------------------- Attempt to add Watcom to the list of compilers that can build the library. This failed in the end due to it's non-thread-aware errno. The library builds but the test suite fails. See README.Watcom for more details. Bug fixes --------- * Bug and memory leak in sem_init() - Alex Blanco * ptw32_getprocessors() now returns CPU count of 1 for WinCE. - James Ewing * pthread_cond_wait() could be canceled at a point where it should not be cancelable. Fixed. - Alexander Terekhov * sem_timedwait() had an incorrect timeout calculation. - Philippe Di Cristo * Fix a memory leak left behind after threads are destroyed. - P. van Bruggen New features ------------ * Ported to AMD64. - Makoto Kato * True pre-emptive asynchronous cancelation of threads. This is optional and requires that Panagiotis E. Hadjidoukas's QueueUserAPCEx package be installed. This package is included in the pthreads-win32 self-unpacking Zip archive starting from this snapshot. See the README.txt file inside the package for installation details. Note: If you don't use async cancelation in your application, or don't need to cancel threads that are blocked on system resources such as network I/O, then the default non-preemptive async cancelation is probably good enough. However, pthreads-win32 auto-detects the availability of these components at run-time, so you don't need to rebuild the library from source if you change your mind later. All of the advice available in books and elsewhere on the undesirability of using async cancelation in any application still stands, but this feature is a welcome addition with respect to the library's conformance to the POSIX standard. SNAPSHOT 2003-09-18 ------------------- Cleanup of thread priority management. In particular, setting of thread priority now attempts to map invalid Win32 values within the range returned by sched_get_priority_min/max() to useful values. See README.NONPORTABLE under "Thread priority". Bug fixes --------- * pthread_getschedparam() now returns the priority given by the most recent call to pthread_setschedparam() or established by pthread_create(), as required by the standard. Previously, pthread_getschedparam() incorrectly returned the running thread priority at the time of the call, which may have been adjusted or temporarily promoted/demoted. * sched_get_priority_min() and sched_get_priority_max() now return -1 on error and set errno. Previously, they incorrectly returned the error value directly. SNAPSHOT 2003-09-04 ------------------- Bug fixes --------- * ptw32_cancelableWait() now allows cancelation of waiting implicit POSIX threads. New test -------- * cancel8.c tests cancelation of Win32 threads waiting at a POSIX cancelation point. SNAPSHOT 2003-09-03 ------------------- Bug fixes --------- * pthread_self() would free the newly created implicit POSIX thread handle if DuplicateHandle failed instead of recycle it (very unlikely). * pthread_exit() was neither freeing nor recycling the POSIX thread struct for implicit POSIX threads. New feature - Cancelation of/by Win32 (non-POSIX) threads --------------------------------------------------------- Since John Bossom's original implementation, the library has allowed non-POSIX initialised threads (Win32 threads) to call pthreads-win32 routines and therefore interact with POSIX threads. This is done by creating an on-the-fly POSIX thread ID for the Win32 thread that, once created, allows fully reciprical interaction. This did not extend to thread cancelation (async or deferred). Now it does. Any thread can be canceled by any other thread (Win32 or POSIX) if the former thread's POSIX pthread_t value is known. It's TSD destructors and POSIX cleanup handlers will be run before the thread exits with an exit code of PTHREAD_CANCELED (retrieved with GetExitCodeThread()). This allows a Win32 thread to, for example, call POSIX CV routines in the same way that POSIX threads would/should, with pthread_cond_wait() cancelability and cleanup handlers (pthread_cond_wait() is a POSIX cancelation point). By adding cancelation, Win32 threads should now be able to call all POSIX threads routines that make sense including semaphores, mutexes, condition variables, read/write locks, barriers, spinlocks, tsd, cleanup push/pop, cancelation, pthread_exit, scheduling, etc. Note that these on-the-fly 'implicit' POSIX thread IDs are initialised as detached (not joinable) with deferred cancelation type. The POSIX thread ID will be created automatically by any POSIX routines that need a POSIX handle (unless the routine needs a pthread_t as a parameter of course). A Win32 thread can discover it's own POSIX thread ID by calling pthread_self(), which will create the handle if necessary and return the pthread_t value. New tests --------- Test the above new feature. SNAPSHOT 2003-08-19 ------------------- This snapshot fixes some accidental corruption to new test case sources. There are no changes to the library source code. SNAPSHOT 2003-08-15 ------------------- Bug fixes --------- * pthread.dsp now uses correct compile flags (/MD). - Viv * pthread_win32_process_detach_np() fixed memory leak. - Steven Reddie * pthread_mutex_destroy() fixed incorrect return code. - Nicolas Barry * pthread_spin_destroy() fixed memory leak. - Piet van Bruggen * Various changes to tighten arg checking, and to work with later versions of MinGW32 and MsysDTK. * pthread_getschedparam() etc, fixed dangerous thread validity checking. - Nicolas Barry * POSIX thread handles are now reused and their memory is not freed on thread exit. This allows for stronger thread validity checking. New standard routine -------------------- * pthread_kill() added to provide thread validity checking to applications. It does not accept any non zero values for the signal arg. New test cases -------------- * New test cases to confirm validity checking, pthread_kill(), and thread reuse. SNAPSHOT 2003-05-10 ------------------- Bug fixes --------- * pthread_mutex_trylock() now returns correct error values. pthread_mutex_destroy() will no longer destroy a recursively locked mutex. pthread_mutex_lock() is no longer inadvertantly behaving as a cancelation point. - Thomas Pfaff * pthread_mutex_timedlock() no longer occasionally sets incorrect mutex ownership, causing deadlocks in some applications. - Robert Strycek and Alexander Terekhov SNAPSHOT 2002-11-04 ------------------- Bug fixes --------- * sem_getvalue() now returns the correct value under Win NT and WinCE. - Rob Fanner * sem_timedwait() now uses tighter checks for unreasonable abstime values - that would result in unexpected timeout values. * ptw32_cond_wait_cleanup() no longer mysteriously consumes CV signals but may produce more spurious wakeups. It is believed that the sem_timedwait() call is consuming a CV signal that it shouldn't. - Alexander Terekhov * Fixed a memory leak in ptw32_threadDestroy() for implicit threads. * Fixed potential for deadlock in pthread_cond_destroy(). A deadlock could occur for statically declared CVs (PTHREAD_COND_INITIALIZER), when one thread is attempting to destroy the condition variable while another is attempting to dynamically initialize it. - Michael Johnson SNAPSHOT 2002-03-02 ------------------- Cleanup code default style. (IMPORTANT) ---------------------------------------------------------------------- Previously, if not defined, the cleanup style was determined automatically from the compiler/language, and one of the following was defined accordingly: __CLEANUP_SEH MSVC only __CLEANUP_CXX C++, including MSVC++, GNU G++ __CLEANUP_C C, including GNU GCC, not MSVC These defines determine the style of cleanup (see pthread.h) and, most importantly, the way that cancelation and thread exit (via pthread_exit) is performed (see the routine ptw32_throw() in private.c). In short, the exceptions versions of the library throw an exception when a thread is canceled or exits (via pthread_exit()), which is caught by a handler in the thread startup routine, so that the the correct stack unwinding occurs regardless of where the thread is when it's canceled or exits via pthread_exit(). In this and future snapshots, unless the build explicitly defines (e.g. via a compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then the build NOW always defaults to __CLEANUP_C style cleanup. This style uses setjmp/longjmp in the cancelation and pthread_exit implementations, and therefore won't do stack unwinding even when linked to applications that have it (e.g. C++ apps). This is for consistency with most current commercial Unix POSIX threads implementations. Compaq's TRU64 may be an exception (no pun intended) and possible future trend. Although it was not clearly documented before, it is still necessary to build your application using the same __CLEANUP_* define as was used for the version of the library that you link with, so that the correct parts of pthread.h are included. That is, the possible defines require the following library versions: __CLEANUP_SEH pthreadVSE.dll __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll __CLEANUP_C pthreadVC.dll or pthreadGC.dll E.g. regardless of whether your app is C or C++, if you link with pthreadVC.lib or libpthreadGC.a, then you must define __CLEANUP_C. THE POINT OF ALL THIS IS: if you have not been defining one of these explicitly, then the defaults as described at the top of this section were being used. THIS NOW CHANGES, as has been explained above, but to try to make this clearer here's an example: If you were building your application with MSVC++ i.e. using C++ exceptions and not explicitly defining one of __CLEANUP_*, then __CLEANUP_C++ was automatically defined for you in pthread.h. You should have been linking with pthreadVCE.dll, which does stack unwinding. If you now build your application as you had before, pthread.h will now automatically set __CLEANUP_C as the default style, and you will need to link with pthreadVC.dll. Stack unwinding will now NOT occur when a thread is canceled, or the thread calls pthread_exit(). Your application will now most likely behave differently to previous versions, and in non-obvious ways. Most likely is that locally instantiated objects may not be destroyed or cleaned up after a thread is canceled. If you want the same behaviour as before, then you must now define __CLEANUP_C++ explicitly using a compiler option and link with pthreadVCE.dll as you did before. WHY ARE WE MAKING THE DEFAULT STYLE LESS EXCEPTION-FRIENDLY? Because no commercial Unix POSIX threads implementation allows you to choose to have stack unwinding. Therefore, providing it in pthread-win32 as a default is dangerous. We still provide the choice but unless you consciously choose to do otherwise, your pthreads applications will now run or crash in similar ways irrespective of the threads platform you use. Or at least this is the hope. WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER? There are a few reasons: - because there are well respected POSIX threads people who believe that POSIX threads implementations should be exceptions aware and do the expected thing in that context. (There are equally respected people who believe it should not be easily accessible, if it's there at all, for unconditional conformity to other implementations.) - because pthreads-win32 is one of the few implementations that has the choice, perhaps the only freely available one, and so offers a laboratory to people who may want to explore the effects; - although the code will always be around somewhere for anyone who wants it, once it's removed from the current version it will not be nearly as visible to people who may have a use for it. Source module splitting ----------------------- In order to enable smaller image sizes to be generated for applications that link statically with the library, most routines have been separated out into individual source code files. This is being done in such a way as to be backward compatible. The old source files are reused to congregate the individual routine files into larger translation units (via a bunch of # includes) so that the compiler can still optimise wherever possible, e.g. through inlining, which can only be done within the same translation unit. It is also possible to build the entire library by compiling the single file named "pthread.c", which just #includes all the secondary congregation source files. The compiler may be able to use this to do more inlining of routines. Although the GNU compiler is able to produce libraries with the necessary separation (the -ffunction-segments switch), AFAIK, the MSVC and other compilers don't have this feature. Finally, since I use makefiles and command-line compilation, I don't know what havoc this reorganisation may wreak amongst IDE project file users. You should be able to continue using your existing project files without modification. New non-portable functions -------------------------- pthread_num_processors_np(): Returns the number of processors in the system that are available to the process, as determined from the processor affinity mask. pthread_timechange_handler_np(): To improve tolerance against operator or time service initiated system clock changes. This routine can be called by an application when it receives a WM_TIMECHANGE message from the system. At present it broadcasts all condition variables so that waiting threads can wake up and re-evaluate their conditions and restart their timed waits if required. - Suggested by Alexander Terekhov Platform dependence ------------------- As Win95 doesn't provide one, the library now contains it's own InterlockedCompareExchange() routine, which is used whenever Windows doesn't provide it. InterlockedCompareExchange() is used to implement spinlocks and barriers, and also in mutexes. This routine relies on the CMPXCHG machine instruction which is not available on i386 CPUs. This library (from snapshot 20010712 onwards) is therefore no longer supported on i386 processor platforms. New standard routines --------------------- For source code portability only - rwlocks cannot be process shared yet. pthread_rwlockattr_init() pthread_rwlockattr_destroy() pthread_rwlockattr_setpshared() pthread_rwlockattr_getpshared() As defined in the new POSIX standard, and the Single Unix Spec version 3: sem_timedwait() pthread_mutex_timedlock() - Alexander Terekhov and Thomas Pfaff pthread_rwlock_timedrdlock() - adapted from pthread_rwlock_rdlock() pthread_rwlock_timedwrlock() - adapted from pthread_rwlock_wrlock() pthread.h no longer includes windows.h -------------------------------------- [Not yet for G++] This was done to prevent conflicts. HANDLE, DWORD, and NULL are temporarily defined within pthread.h if they are not already. pthread.h, sched.h and semaphore.h now use dllexport/dllimport -------------------------------------------------------------- Not only to avoid the need for the pthread.def file, but to improve performance. Apparently, declaring functions with dllimport generates a direct call to the function and avoids the overhead of a stub function call. Bug fixes --------- * Fixed potential NULL pointer dereferences in pthread_mutexattr_init, pthread_mutexattr_getpshared, pthread_barrierattr_init, pthread_barrierattr_getpshared, and pthread_condattr_getpshared. - Scott McCaskill * Removed potential race condition in pthread_mutex_trylock and pthread_mutex_lock; - Alexander Terekhov * The behaviour of pthread_mutex_trylock in relation to recursive mutexes was inconsistent with commercial implementations. Trylock would return EBUSY if the lock was owned already by the calling thread regardless of mutex type. Trylock now increments the recursion count and returns 0 for RECURSIVE mutexes, and will return EDEADLK rather than EBUSY for ERRORCHECK mutexes. This is consistent with Solaris. - Thomas Pfaff * Found a fix for the library and workaround for applications for the known bug #2, i.e. where __CLEANUP_CXX or __CLEANUP_SEH is defined. See the "Known Bugs in this snapshot" section below. This could be made transparent to applications by replacing the macros that define the current C++ and SEH versions of pthread_cleanup_push/pop with the C version, but AFAIK cleanup handlers would not then run in the correct sequence with destructors and exception cleanup handlers when an exception occurs. * Cancelation once started in a thread cannot now be inadvertantly double canceled. That is, once a thread begins it's cancelation run, cancelation is disabled and a subsequent cancel request will return an error (ESRCH). * errno: An incorrect compiler directive caused a local version of errno to be used instead of the Win32 errno. Both instances are thread-safe but applications checking errno after a pthreads-win32 call would be wrong. Fixing this also fixed a bad compiler option in the testsuite (/MT should have been /MD) which is needed to link with the correct library MSVCRT.LIB. SNAPSHOT 2001-07-12 ------------------- To be added SNAPSHOT 2001-07-03 ------------------- To be added SNAPSHOT 2000-08-13 ------------------- New: - Renamed DLL and LIB files: pthreadVSE.dll (MS VC++/Structured EH) pthreadVSE.lib pthreadVCE.dll (MS VC++/C++ EH) pthreadVCE.lib pthreadGCE.dll (GNU G++/C++ EH) libpthreadw32.a Both your application and the pthread dll should use the same exception handling scheme. Bugs fixed: - MSVC++ C++ exception handling. Some new tests have been added. SNAPSHOT 2000-08-10 ------------------- New: - asynchronous cancelation on X86 (Jason Nye) - Makefile compatible with MS nmake to replace buildlib.bat - GNUmakefile for Mingw32 - tests/Makefile for MS nmake replaces runall.bat - tests/GNUmakefile for Mingw32 Bugs fixed: - kernel32 load/free problem - attempt to hide internel exceptions from application exception handlers (__try/__except and try/catch blocks) - Win32 thread handle leakage bug (David Baggett/Paul Redondo/Eyal Lebedinsky) Some new tests have been added. SNAPSHOT 1999-11-02 ------------------- Bugs fixed: - ctime_r macro had an incorrect argument (Erik Hensema), - threads were not being created PTHREAD_CANCEL_DEFERRED. This should have had little effect as deferred is the only supported type. (Ross Johnson). Some compatibility improvements added, eg. - pthread_setcancelstate accepts NULL pointer for the previous value argument. Ditto for pthread_setcanceltype. This is compatible with Solaris but should not affect standard applications (Erik Hensema) Some new tests have been added. SNAPSHOT 1999-10-17 ------------------- Bug fix - Cancelation of threads waiting on condition variables now works properly (Lorin Hochstein and Peter Slacik) SNAPSHOT 1999-08-12 ------------------- Fixed exception stack cleanup if calling pthread_exit() - (Lorin Hochstein and John Bossom). Fixed bugs in condition variables - (Peter Slacik): - additional contention checks - properly adjust number of waiting threads after timed condvar timeout. SNAPSHOT 1999-05-30 ------------------- Some minor bugs have been fixed. See the ChangeLog file for details. Some more POSIX 1b functions are now included but ony return an error (ENOSYS) if called. They are: sem_open sem_close sem_unlink sem_getvalue SNAPSHOT 1999-04-07 ------------------- Some POSIX 1b functions which were internally supported are now available as exported functions: sem_init sem_destroy sem_wait sem_trywait sem_post sched_yield sched_get_priority_min sched_get_priority_max Some minor bugs have been fixed. See the ChangeLog file for details. SNAPSHOT 1999-03-16 ------------------- Initial release. nyquist-3.05/liblo/pthreads.2/sched.h0000644000175000000620000001135411512143043016473 0ustar stevestaff/* * Module: sched.h * * Purpose: * Provides an implementation of POSIX realtime extensions * as defined in * * POSIX 1003.1b-1993 (POSIX.1b) * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef _SCHED_H #define _SCHED_H #undef PTW32_LEVEL #if defined(_POSIX_SOURCE) #define PTW32_LEVEL 0 /* Early POSIX */ #endif #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 #undef PTW32_LEVEL #define PTW32_LEVEL 1 /* Include 1b, 1c and 1d */ #endif #if defined(INCLUDE_NP) #undef PTW32_LEVEL #define PTW32_LEVEL 2 /* Include Non-Portable extensions */ #endif #define PTW32_LEVEL_MAX 3 #if !defined(PTW32_LEVEL) #define PTW32_LEVEL PTW32_LEVEL_MAX /* Include everything */ #endif #if __GNUC__ && ! defined (__declspec) # error Please upgrade your GNU compiler to one that supports __declspec. #endif /* * When building the DLL code, you should define PTW32_BUILD so that * the variables/functions are exported correctly. When using the DLL, * do NOT define PTW32_BUILD, and then the variables/functions will * be imported correctly. */ #ifndef PTW32_STATIC_LIB # ifdef PTW32_BUILD # define PTW32_DLLPORT __declspec (dllexport) # else # define PTW32_DLLPORT __declspec (dllimport) # endif #else # define PTW32_DLLPORT #endif /* * This is a duplicate of what is in the autoconf config.h, * which is only used when building the pthread-win32 libraries. */ #ifndef PTW32_CONFIG_H # if defined(WINCE) # define NEED_ERRNO # define NEED_SEM # endif # if defined(_UWIN) || defined(__MINGW32__) # define HAVE_MODE_T # endif #endif /* * */ #if PTW32_LEVEL >= PTW32_LEVEL_MAX #ifdef NEED_ERRNO #include "need_errno.h" #else #include #endif #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ #if defined(__MINGW32__) || defined(_UWIN) #if PTW32_LEVEL >= PTW32_LEVEL_MAX /* For pid_t */ # include /* Required by Unix 98 */ # include #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ #else typedef int pid_t; #endif /* Thread scheduling policies */ enum { SCHED_OTHER = 0, SCHED_FIFO, SCHED_RR, SCHED_MIN = SCHED_OTHER, SCHED_MAX = SCHED_RR }; struct sched_param { int sched_priority; }; #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PTW32_DLLPORT int __cdecl sched_yield (void); PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); /* * Note that this macro returns ENOTSUP rather than * ENOSYS as might be expected. However, returning ENOSYS * should mean that sched_get_priority_{min,max} are * not implemented as well as sched_rr_get_interval. * This is not the case, since we just don't support * round-robin scheduling. Therefore I have chosen to * return the same value as sched_setscheduler when * SCHED_RR is passed to it. */ #define sched_rr_get_interval(_pid, _interval) \ ( errno = ENOTSUP, (int) -1 ) #ifdef __cplusplus } /* End of extern "C" */ #endif /* __cplusplus */ #undef PTW32_LEVEL #undef PTW32_LEVEL_MAX #endif /* !_SCHED_H */ nyquist-3.05/liblo/pthreads.2/PROGRESS0000644000175000000620000000021611512143043016416 0ustar stevestaffPlease see the ANNOUNCE file "Level of Standards Conformance" or the web page: http://sources.redhat.com/pthreads-win32/conformance.html nyquist-3.05/liblo/pthreads.2/pthread_delay_np.c0000644000175000000620000001165211512143043020703 0ustar stevestaff/* * pthreads_delay_np.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * pthread_delay_np * * DESCRIPTION * * This routine causes a thread to delay execution for a specific period of time. * This period ends at the current time plus the specified interval. The routine * will not return before the end of the period is reached, but may return an * arbitrary amount of time after the period has gone by. This can be due to * system load, thread priorities, and system timer granularity. * * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is * allowed and can be used to force the thread to give up the processor or to * deliver a pending cancelation request. * * The timespec structure contains the following two fields: * * tv_sec is an integer number of seconds. * tv_nsec is an integer number of nanoseconds. * * Return Values * * If an error condition occurs, this routine returns an integer value indicating * the type of error. Possible return values are as follows: * * 0 * Successful completion. * [EINVAL] * The value specified by interval is invalid. * * Example * * The following code segment would wait for 5 and 1/2 seconds * * struct timespec tsWait; * int intRC; * * tsWait.tv_sec = 5; * tsWait.tv_nsec = 500000000L; * intRC = pthread_delay_np(&tsWait); */ int pthread_delay_np (struct timespec *interval) { DWORD wait_time; DWORD secs_in_millisecs; DWORD millisecs; DWORD status; pthread_t self; ptw32_thread_t * sp; if (interval == NULL) { return EINVAL; } if (interval->tv_sec == 0L && interval->tv_nsec == 0L) { pthread_testcancel (); Sleep (0); pthread_testcancel (); return (0); } /* convert secs to millisecs */ secs_in_millisecs = interval->tv_sec * 1000L; /* convert nanosecs to millisecs (rounding up) */ millisecs = (interval->tv_nsec + 999999L) / 1000000L; #if defined(__WATCOMC__) #pragma disable_message (124) #endif /* * Most compilers will issue a warning 'comparison always 0' * because the variable type is unsigned, but we need to keep this * for some reason I can't recall now. */ if (0 > (wait_time = secs_in_millisecs + millisecs)) { return EINVAL; } #if defined(__WATCOMC__) #pragma enable_message (124) #endif if (NULL == (self = pthread_self ()).p) { return ENOMEM; } sp = (ptw32_thread_t *) self.p; if (sp->cancelState == PTHREAD_CANCEL_ENABLE) { /* * Async cancelation won't catch us until wait_time is up. * Deferred cancelation will cancel us immediately. */ if (WAIT_OBJECT_0 == (status = WaitForSingleObject (sp->cancelEvent, wait_time))) { /* * Canceling! */ (void) pthread_mutex_lock (&sp->cancelLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); } (void) pthread_mutex_unlock (&sp->cancelLock); return ESRCH; } else if (status != WAIT_TIMEOUT) { return EINVAL; } } else { Sleep (wait_time); } return (0); } nyquist-3.05/liblo/pthreads.2/pthread_win32_attach_detach_np.c0000644000175000000620000001737211512143043023410 0ustar stevestaff/* * pthread_win32_attach_detach_np.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * Handle to kernel32.dll */ static HINSTANCE ptw32_h_kernel32; /* * Handle to quserex.dll */ static HINSTANCE ptw32_h_quserex; BOOL pthread_win32_process_attach_np () { BOOL result = TRUE; DWORD_PTR vProcessCPUs; DWORD_PTR vSystemCPUs; result = ptw32_processInitialize (); #ifdef _UWIN pthread_count++; #endif ptw32_features = 0; #if defined(NEED_PROCESS_AFFINITY_MASK) ptw32_smp_system = PTW32_FALSE; #else if (GetProcessAffinityMask (GetCurrentProcess (), &vProcessCPUs, &vSystemCPUs)) { int CPUs = 0; DWORD_PTR bit; for (bit = 1; bit != 0; bit <<= 1) { if (vSystemCPUs & bit) { CPUs++; } } ptw32_smp_system = (CPUs > 1); } else { ptw32_smp_system = PTW32_FALSE; } #endif #ifdef WINCE /* * Load COREDLL and try to get address of InterlockedCompareExchange */ ptw32_h_kernel32 = LoadLibrary (TEXT ("COREDLL.DLL")); #else /* * Load KERNEL32 and try to get address of InterlockedCompareExchange */ ptw32_h_kernel32 = LoadLibrary (TEXT ("KERNEL32.DLL")); #endif ptw32_interlocked_compare_exchange = (PTW32_INTERLOCKED_LONG (WINAPI *) (PTW32_INTERLOCKED_LPLONG, PTW32_INTERLOCKED_LONG, PTW32_INTERLOCKED_LONG)) #if defined(NEED_UNICODE_CONSTS) GetProcAddress (ptw32_h_kernel32, (const TCHAR *) TEXT ("InterlockedCompareExchange")); #else GetProcAddress (ptw32_h_kernel32, (LPCSTR) "InterlockedCompareExchange"); #endif if (ptw32_interlocked_compare_exchange == NULL) { ptw32_interlocked_compare_exchange = ptw32_InterlockedCompareExchange; /* * If InterlockedCompareExchange is not being used, then free * the kernel32.dll handle now, rather than leaving it until * DLL_PROCESS_DETACH. * * Note: this is not a pedantic exercise in freeing unused * resources! It is a work-around for a bug in Windows 95 * (see microsoft knowledge base article, Q187684) which * does Bad Things when FreeLibrary is called within * the DLL_PROCESS_DETACH code, in certain situations. * Since w95 just happens to be a platform which does not * provide InterlockedCompareExchange, the bug will be * effortlessly avoided. */ (void) FreeLibrary (ptw32_h_kernel32); ptw32_h_kernel32 = 0; } else { ptw32_features |= PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE; } /* * Load QUSEREX.DLL and try to get address of QueueUserAPCEx */ ptw32_h_quserex = LoadLibrary (TEXT ("QUSEREX.DLL")); if (ptw32_h_quserex != NULL) { ptw32_register_cancelation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD)) #if defined(NEED_UNICODE_CONSTS) GetProcAddress (ptw32_h_quserex, (const TCHAR *) TEXT ("QueueUserAPCEx")); #else GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx"); #endif } if (NULL == ptw32_register_cancelation) { ptw32_register_cancelation = ptw32_RegisterCancelation; if (ptw32_h_quserex != NULL) { (void) FreeLibrary (ptw32_h_quserex); } ptw32_h_quserex = 0; } else { /* Initialise QueueUserAPCEx */ BOOL (*queue_user_apc_ex_init) (VOID); queue_user_apc_ex_init = (BOOL (*)(VOID)) #if defined(NEED_UNICODE_CONSTS) GetProcAddress (ptw32_h_quserex, (const TCHAR *) TEXT ("QueueUserAPCEx_Init")); #else GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init"); #endif if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ()) { ptw32_register_cancelation = ptw32_RegisterCancelation; (void) FreeLibrary (ptw32_h_quserex); ptw32_h_quserex = 0; } } if (ptw32_h_quserex) { ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL; } return result; } BOOL pthread_win32_process_detach_np () { if (ptw32_processInitialized) { ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); if (sp != NULL) { /* * Detached threads have their resources automatically * cleaned up upon exit (others must be 'joined'). */ if (sp->detachState == PTHREAD_CREATE_DETACHED) { ptw32_threadDestroy (sp->ptHandle); TlsSetValue (ptw32_selfThreadKey->key, NULL); } } /* * The DLL is being unmapped from the process's address space */ ptw32_processTerminate (); if (ptw32_h_quserex) { /* Close QueueUserAPCEx */ BOOL (*queue_user_apc_ex_fini) (VOID); queue_user_apc_ex_fini = (BOOL (*)(VOID)) #if defined(NEED_UNICODE_CONSTS) GetProcAddress (ptw32_h_quserex, (const TCHAR *) TEXT ("QueueUserAPCEx_Fini")); #else GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Fini"); #endif if (queue_user_apc_ex_fini != NULL) { (void) queue_user_apc_ex_fini (); } (void) FreeLibrary (ptw32_h_quserex); } if (ptw32_h_kernel32) { (void) FreeLibrary (ptw32_h_kernel32); } } return TRUE; } BOOL pthread_win32_thread_attach_np () { return TRUE; } BOOL pthread_win32_thread_detach_np () { if (ptw32_processInitialized) { /* * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle * unnecessarily. */ ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle. { ptw32_callUserDestroyRoutines (sp->ptHandle); (void) pthread_mutex_lock (&sp->cancelLock); sp->state = PThreadStateLast; /* * If the thread is joinable at this point then it MUST be joined * or detached explicitly by the application. */ (void) pthread_mutex_unlock (&sp->cancelLock); if (sp->detachState == PTHREAD_CREATE_DETACHED) { ptw32_threadDestroy (sp->ptHandle); TlsSetValue (ptw32_selfThreadKey->key, NULL); } } } return TRUE; } BOOL pthread_win32_test_features_np (int feature_mask) { return ((ptw32_features & feature_mask) == feature_mask); } nyquist-3.05/liblo/pthreads.2/sem_destroy.c0000644000175000000620000001135211512143043017733 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_destroy.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" int sem_destroy (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function destroys an unnamed semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function destroys an unnamed semaphore. * * RESULTS * 0 successfully destroyed semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EBUSY threads (or processes) are currently * blocked on 'sem' * * ------------------------------------------------------ */ { int result = 0; sem_t s = NULL; if (sem == NULL || *sem == NULL) { result = EINVAL; } else { s = *sem; if ((result = pthread_mutex_lock (&s->lock)) == 0) { if (s->value < 0) { (void) pthread_mutex_unlock (&s->lock); result = EBUSY; } else { /* There are no threads currently blocked on this semaphore. */ if (!CloseHandle (s->sem)) { (void) pthread_mutex_unlock (&s->lock); result = EINVAL; } else { /* * Invalidate the semaphore handle when we have the lock. * Other sema operations should test this after acquiring the lock * to check that the sema is still valid, i.e. before performing any * operations. This may only be necessary before the sema op routine * returns so that the routine can return EINVAL - e.g. if setting * s->value to SEM_VALUE_MAX below does force a fall-through. */ *sem = NULL; /* Prevent anyone else actually waiting on or posting this sema. */ s->value = SEM_VALUE_MAX; (void) pthread_mutex_unlock (&s->lock); do { /* Give other threads a chance to run and exit any sema op * routines. Due to the SEM_VALUE_MAX value, if sem_post or * sem_wait were blocked by us they should fall through. */ Sleep(0); } while (pthread_mutex_destroy (&s->lock) == EBUSY); } } } } if (result != 0) { errno = result; return -1; } free (s); return 0; } /* sem_destroy */ nyquist-3.05/liblo/pthreads.2/pthread_condattr_setpshared.c0000644000175000000620000000744011512143043023150 0ustar stevestaff/* * pthread_condattr_setpshared.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Mutexes created with 'attr' can be shared between * processes if pthread_mutex_t variable is allocated * in memory shared by these processes. * * PARAMETERS * attr * pointer to an instance of pthread_mutexattr_t * * pshared * must be one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * DESCRIPTION * Mutexes creatd with 'attr' can be shared between * processes if pthread_mutex_t variable is allocated * in memory shared by these processes. * * NOTES: * 1) pshared mutexes MUST be allocated in shared * memory. * * 2) The following macro is defined if shared mutexes * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully set attribute, * EINVAL 'attr' or pshared is invalid, * ENOSYS PTHREAD_PROCESS_SHARED not supported, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && ((pshared == PTHREAD_PROCESS_SHARED) || (pshared == PTHREAD_PROCESS_PRIVATE))) { if (pshared == PTHREAD_PROCESS_SHARED) { #if !defined( _POSIX_THREAD_PROCESS_SHARED ) result = ENOSYS; pshared = PTHREAD_PROCESS_PRIVATE; #else result = 0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ } else { result = 0; } (*attr)->pshared = pshared; } else { result = EINVAL; } return result; } /* pthread_condattr_setpshared */ nyquist-3.05/liblo/pthreads.2/pthread_barrier_wait.c0000644000175000000620000000651011512143043021557 0ustar stevestaff/* * pthread_barrier_wait.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrier_wait (pthread_barrier_t * barrier) { int result; int step; pthread_barrier_t b; if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } b = *barrier; step = b->iStep; if (0 == InterlockedDecrement ((long *) &(b->nCurrentBarrierHeight))) { /* Must be done before posting the semaphore. */ b->nCurrentBarrierHeight = b->nInitialBarrierHeight; /* * There is no race condition between the semaphore wait and post * because we are using two alternating semas and all threads have * entered barrier_wait and checked nCurrentBarrierHeight before this * barrier's sema can be posted. Any threads that have not quite * entered sem_wait below when the multiple_post has completed * will nevertheless continue through the semaphore (barrier) * and will not be left stranded. */ result = (b->nInitialBarrierHeight > 1 ? sem_post_multiple (&(b->semBarrierBreeched[step]), b->nInitialBarrierHeight - 1) : 0); } else { /* * Use the non-cancelable version of sem_wait(). */ result = ptw32_semwait (&(b->semBarrierBreeched[step])); } /* * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. * This also sets up the alternate semaphore as the next barrier. */ if (0 == result) { result = ((PTW32_INTERLOCKED_LONG) step == PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & (b->iStep), (PTW32_INTERLOCKED_LONG) (1L - step), (PTW32_INTERLOCKED_LONG) step) ? PTHREAD_BARRIER_SERIAL_THREAD : 0); } return (result); } nyquist-3.05/liblo/pthreads.2/tests/0002755000175000000620000000000011537433130016402 5ustar stevestaffnyquist-3.05/liblo/pthreads.2/tests/equal1.c0000644000175000000620000000405011512143043017725 0ustar stevestaff/* * Test for pthread_equal. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on functions: pthread_create(). */ #include "test.h" void * func(void * arg) { Sleep(2000); return 0; } int main() { pthread_t t1, t2; assert(pthread_create(&t1, NULL, func, (void *) 1) == 0); assert(pthread_create(&t2, NULL, func, (void *) 2) == 0); assert(pthread_equal(t1, t2) == 0); assert(pthread_equal(t1,t1) != 0); /* This is a hack. We don't want to rely on pthread_join yet if we can help it. */ Sleep(4000); /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex6s.c0000644000175000000620000000521311512143043020152 0ustar stevestaff/* * mutex6s.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test the default (type not set) static mutex type. * Should be the same as PTHREAD_MUTEX_NORMAL. * Thread locks mutex twice (recursive lock). * Locking thread should deadlock on second attempt. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; /* Should wait here (deadlocked) */ assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); return 0; } int main() { pthread_t t; assert(mutex == PTHREAD_MUTEX_INITIALIZER); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(1000); assert(lockCount == 1); /* * Should succeed even though we don't own the lock * because FAST mutexes don't check ownership. */ assert(pthread_mutex_unlock(&mutex) == 0); Sleep (1000); assert(lockCount == 2); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/exit2.c0000644000175000000620000000360711512143043017577 0ustar stevestaff/* * Test for pthread_exit(). * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: * pthread_create() * pthread_exit() */ #include "test.h" void * func(void * arg) { pthread_exit(arg); /* Never reached. */ assert(0); return NULL; } int main(int argc, char * argv[]) { pthread_t t; assert(pthread_create(&t, NULL, func, (void *) NULL) == 0); Sleep(1000); return 0; } nyquist-3.05/liblo/pthreads.2/tests/reuse2.c0000644000175000000620000001016011512143043017741 0ustar stevestaff/* * File: reuse2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test that thread reuse works for detached threads. * - Analyse thread struct reuse. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - This test is implementation specific * because it uses knowledge of internals that should be * opaque to an application. * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* */ enum { NUMTHREADS = 10000 }; static long done = 0; void * func(void * arg) { sched_yield(); InterlockedIncrement(&done); return (void *) 0; } int main() { pthread_t t[NUMTHREADS]; pthread_attr_t attr; int i; unsigned int notUnique = 0, totalHandles = 0, reuseMax = 0, reuseMin = NUMTHREADS; assert(pthread_attr_init(&attr) == 0); assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_create(&t[i], &attr, func, NULL) == 0); } while (NUMTHREADS > InterlockedExchangeAdd((LPLONG)&done, 0L)) Sleep(100); Sleep(100); /* * Analyse reuse by computing min and max number of times pthread_create() * returned the same pthread_t value. */ for (i = 0; i < NUMTHREADS; i++) { if (t[i].p != NULL) { unsigned int j, thisMax; thisMax = t[i].x; for (j = i+1; j < NUMTHREADS; j++) if (t[i].p == t[j].p) { if (t[i].x == t[j].x) notUnique++; if (thisMax < t[j].x) thisMax = t[j].x; t[j].p = NULL; } if (reuseMin > thisMax) reuseMin = thisMax; if (reuseMax < thisMax) reuseMax = thisMax; } } for (i = 0; i < NUMTHREADS; i++) if (t[i].p != NULL) totalHandles++; /* * pthread_t reuse counts start at 0, so we need to add 1 * to the max and min values derived above. */ printf("For %d total threads:\n", NUMTHREADS); printf("Non-unique IDs = %d\n", notUnique); printf("Reuse maximum = %d\n", reuseMax + 1); printf("Reuse minimum = %d\n", reuseMin + 1); printf("Total handles = %d\n", totalHandles); return 0; } nyquist-3.05/liblo/pthreads.2/tests/valid1.c0000644000175000000620000000500511512143043017716 0ustar stevestaff/* * File: valid1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test that thread validation works. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" enum { NUMTHREADS = 1 }; static int washere = 0; void * func(void * arg) { washere = 1; return (void *) 0; } int main() { pthread_t t; void * result = NULL; washere = 0; assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_join(t, &result) == 0); assert(result == 0); assert(washere == 1); sched_yield(); assert(pthread_kill(t, 0) == ESRCH); return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchlib.c0000644000175000000620000001636111512143043020313 0ustar stevestaff/* * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * */ #include "../config.h" #include "pthread.h" #include "sched.h" #include "semaphore.h" #include #include #ifdef __GNUC__ #include #endif #include "benchtest.h" int old_mutex_use = OLD_WIN32CS; BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; HINSTANCE ptw32_h_kernel32; void dummy_call(int * a) { } void interlocked_inc_with_conditionals(int * a) { if (a != NULL) if (InterlockedIncrement((long *) a) == -1) { *a = 0; } } void interlocked_dec_with_conditionals(int * a) { if (a != NULL) if (InterlockedDecrement((long *) a) == -1) { *a = 0; } } int old_mutex_init(old_mutex_t *mutex, const old_mutexattr_t *attr) { int result = 0; old_mutex_t mx; if (mutex == NULL) { return EINVAL; } mx = (old_mutex_t) calloc(1, sizeof(*mx)); if (mx == NULL) { result = ENOMEM; goto FAIL0; } mx->mutex = 0; if (attr != NULL && *attr != NULL && (*attr)->pshared == PTHREAD_PROCESS_SHARED ) { result = ENOSYS; } else { CRITICAL_SECTION cs; /* * Load KERNEL32 and try to get address of TryEnterCriticalSection */ ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); ptw32_try_enter_critical_section = (BOOL (WINAPI *)(LPCRITICAL_SECTION)) #if defined(NEED_UNICODE_CONSTS) GetProcAddress(ptw32_h_kernel32, (const TCHAR *)TEXT("TryEnterCriticalSection")); #else GetProcAddress(ptw32_h_kernel32, (LPCSTR) "TryEnterCriticalSection"); #endif if (ptw32_try_enter_critical_section != NULL) { InitializeCriticalSection(&cs); if ((*ptw32_try_enter_critical_section)(&cs)) { LeaveCriticalSection(&cs); } else { /* * Not really supported (Win98?). */ ptw32_try_enter_critical_section = NULL; } DeleteCriticalSection(&cs); } if (ptw32_try_enter_critical_section == NULL) { (void) FreeLibrary(ptw32_h_kernel32); ptw32_h_kernel32 = 0; } if (old_mutex_use == OLD_WIN32CS) { InitializeCriticalSection(&mx->cs); } else if (old_mutex_use == OLD_WIN32MUTEX) { mx->mutex = CreateMutex (NULL, FALSE, NULL); if (mx->mutex == 0) { result = EAGAIN; } } else { result = EINVAL; } } if (result != 0 && mx != NULL) { free(mx); mx = NULL; } FAIL0: *mutex = mx; return(result); } int old_mutex_lock(old_mutex_t *mutex) { int result = 0; old_mutex_t mx; if (mutex == NULL || *mutex == NULL) { return EINVAL; } if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) { /* * Don't use initialisers when benchtesting. */ result = EINVAL; } mx = *mutex; if (result == 0) { if (mx->mutex == 0) { EnterCriticalSection(&mx->cs); } else { result = (WaitForSingleObject(mx->mutex, INFINITE) == WAIT_OBJECT_0) ? 0 : EINVAL; } } return(result); } int old_mutex_unlock(old_mutex_t *mutex) { int result = 0; old_mutex_t mx; if (mutex == NULL || *mutex == NULL) { return EINVAL; } mx = *mutex; if (mx != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) { if (mx->mutex == 0) { LeaveCriticalSection(&mx->cs); } else { result = (ReleaseMutex (mx->mutex) ? 0 : EINVAL); } } else { result = EINVAL; } return(result); } int old_mutex_trylock(old_mutex_t *mutex) { int result = 0; old_mutex_t mx; if (mutex == NULL || *mutex == NULL) { return EINVAL; } if (*mutex == (old_mutex_t) PTW32_OBJECT_AUTO_INIT) { /* * Don't use initialisers when benchtesting. */ result = EINVAL; } mx = *mutex; if (result == 0) { if (mx->mutex == 0) { if (ptw32_try_enter_critical_section == NULL) { result = 0; } else if ((*ptw32_try_enter_critical_section)(&mx->cs) != TRUE) { result = EBUSY; } } else { DWORD status; status = WaitForSingleObject (mx->mutex, 0); if (status != WAIT_OBJECT_0) { result = ((status == WAIT_TIMEOUT) ? EBUSY : EINVAL); } } } return(result); } int old_mutex_destroy(old_mutex_t *mutex) { int result = 0; old_mutex_t mx; if (mutex == NULL || *mutex == NULL) { return EINVAL; } if (*mutex != (old_mutex_t) PTW32_OBJECT_AUTO_INIT) { mx = *mutex; if ((result = old_mutex_trylock(&mx)) == 0) { *mutex = NULL; (void) old_mutex_unlock(&mx); if (mx->mutex == 0) { DeleteCriticalSection(&mx->cs); } else { result = (CloseHandle (mx->mutex) ? 0 : EINVAL); } if (result == 0) { mx->mutex = 0; free(mx); } else { *mutex = mx; } } } else { result = EINVAL; } if (ptw32_try_enter_critical_section != NULL) { (void) FreeLibrary(ptw32_h_kernel32); ptw32_h_kernel32 = 0; } return(result); } /****************************************************************************************/ nyquist-3.05/liblo/pthreads.2/tests/rwlock4.c0000644000175000000620000000431611512143043020127 0ustar stevestaff/* * rwlock4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, rdlock it, trywrlock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_rdlock() * pthread_rwlock_trywrlock() * pthread_rwlock_unlock() */ #include "test.h" pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_rwlock_rdlock(&rwlock1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); Sleep(2000); assert(pthread_rwlock_unlock(&rwlock1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/SIZES.VCE0000644000175000000620000000137511512143043017634 0ustar stevestaffSizes of pthreads-win32 structs ------------------------------- pthread_t 8 ptw32_thread_t 76 pthread_attr_t_ 28 sem_t_ 12 pthread_mutex_t_ 24 pthread_mutexattr_t_ 8 pthread_spinlock_t_ 8 pthread_barrier_t_ 24 pthread_barrierattr_t_ 4 pthread_key_t_ 16 pthread_cond_t_ 32 pthread_condattr_t_ 4 pthread_rwlock_t_ 28 pthread_rwlockattr_t_ 4 pthread_once_t_ 16 ptw32_cleanup_t 12 ptw32_mcs_node_t_ 16 sched_param 4 ------------------------------- nyquist-3.05/liblo/pthreads.2/tests/spin1.c0000644000175000000620000000377011512143043017577 0ustar stevestaff/* * spin1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create a simple spinlock object, lock it, and then unlock it again. * This is the simplest test of the pthread mutex family that we can do. * */ #include "test.h" pthread_spinlock_t lock; int main() { assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_spin_lock(&lock) == 0); assert(pthread_spin_unlock(&lock) == 0); assert(pthread_spin_destroy(&lock) == 0); assert(pthread_spin_lock(&lock) == EINVAL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel3.c0000644000175000000620000001161211512143043020047 0ustar stevestaff/* * File: cancel3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test asynchronous cancelation (alertable or non-alertable). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - Async cancel if thread is not blocked (i.e. voluntarily resumes if blocked). * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join. * - quserex.dll and alertdrv.sys are not available. * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; void * mythread (void *arg) { int result = ((int) PTHREAD_CANCELED + 1); bag_t *bag = (bag_t *) arg; assert (bag == &threadbag[bag->threadnum]); assert (bag->started == 0); bag->started = 1; /* Set to known state and type */ assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) == 0); assert (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); /* * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (bag->count = 0; bag->count < 100; bag->count++) Sleep (100); return (void *) result; } int main () { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; assert ((t[0] = pthread_self ()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert (pthread_create (&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep (500); for (i = 1; i <= NUMTHREADS; i++) { assert (pthread_cancel (t[i]) == 0); } /* * Give threads time to run. */ Sleep (NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf (stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert (!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; /* * The thread does not contain any cancelation points, so * a return value of PTHREAD_CANCELED confirms that async * cancelation succeeded. */ assert (pthread_join (t[i], (void **) &result) == 0); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf (stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert (!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock3_t.c0000644000175000000620000000502311512143043020445 0ustar stevestaff/* * rwlock3_t.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, timed-wrlock it, trywrlock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_timedwrlock() * pthread_rwlock_trywrlock() * pthread_rwlock_unlock() */ #include "test.h" #include pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_rwlock_timedwrlock(&rwlock1, &abstime) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); Sleep(2000); assert(pthread_rwlock_unlock(&rwlock1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock6_t.c0000644000175000000620000000712511512143043020455 0ustar stevestaff/* * rwlock6_t.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Check writer and reader locking with reader timeouts * * Depends on API functions: * pthread_rwlock_timedrdlock() * pthread_rwlock_wrlock() * pthread_rwlock_unlock() */ #include "test.h" #include static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int bankAccount = 0; void * wrfunc(void * arg) { assert(pthread_rwlock_wrlock(&rwlock1) == 0); Sleep(2000); bankAccount += 10; assert(pthread_rwlock_unlock(&rwlock1) == 0); return ((void *) bankAccount); } void * rdfunc(void * arg) { int ba = -1; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; if ((int) arg == 1) { abstime.tv_sec += 1; assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == ETIMEDOUT); ba = 0; } else if ((int) arg == 2) { abstime.tv_sec += 3; assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == 0); ba = bankAccount; assert(pthread_rwlock_unlock(&rwlock1) == 0); } return ((void *) ba); } int main() { pthread_t wrt1; pthread_t wrt2; pthread_t rdt1; pthread_t rdt2; int wr1Result = 0; int wr2Result = 0; int rd1Result = 0; int rd2Result = 0; bankAccount = 0; assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0); Sleep(500); assert(pthread_create(&rdt1, NULL, rdfunc, (void *) 1) == 0); Sleep(500); assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0); Sleep(500); assert(pthread_create(&rdt2, NULL, rdfunc, (void *) 2) == 0); assert(pthread_join(wrt1, (void **) &wr1Result) == 0); assert(pthread_join(rdt1, (void **) &rd1Result) == 0); assert(pthread_join(wrt2, (void **) &wr2Result) == 0); assert(pthread_join(rdt2, (void **) &rd2Result) == 0); assert(wr1Result == 10); assert(rd1Result == 0); assert(wr2Result == 20); assert(rd2Result == 20); return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock7.c0000644000175000000620000001153211512143043020130 0ustar stevestaff/* * rwlock7.c * * Hammer on a bunch of rwlocks to test robustness and fairness. * Printed stats should be roughly even for each thread. */ #include "test.h" #include #ifdef __GNUC__ #include #endif #define THREADS 5 #define DATASIZE 7 #define ITERATIONS 1000000 /* * Keep statistics for each thread. */ typedef struct thread_tag { int thread_num; pthread_t thread_id; int updates; int reads; int changed; int seed; } thread_t; /* * Read-write lock and shared data */ typedef struct data_tag { pthread_rwlock_t lock; int data; int updates; } data_t; static thread_t threads[THREADS]; static data_t data[DATASIZE]; /* * Thread start routine that uses read-write locks */ void *thread_routine (void *arg) { thread_t *self = (thread_t*)arg; int iteration; int element = 0; int seed = self->seed; int interval = 1 + rand_r (&seed) % 71; self->changed = 0; for (iteration = 0; iteration < ITERATIONS; iteration++) { if (iteration % (ITERATIONS / 10) == 0) { putchar('.'); fflush(stdout); } /* * Each "self->interval" iterations, perform an * update operation (write lock instead of read * lock). */ if ((iteration % interval) == 0) { assert(pthread_rwlock_wrlock (&data[element].lock) == 0); data[element].data = self->thread_num; data[element].updates++; self->updates++; interval = 1 + rand_r (&seed) % 71; assert(pthread_rwlock_unlock (&data[element].lock) == 0); } else { /* * Look at the current data element to see whether * the current thread last updated it. Count the * times, to report later. */ assert(pthread_rwlock_rdlock (&data[element].lock) == 0); self->reads++; if (data[element].data != self->thread_num) { self->changed++; interval = 1 + self->changed % 71; } assert(pthread_rwlock_unlock (&data[element].lock) == 0); } element = (element + 1) % DATASIZE; } return NULL; } int main (int argc, char *argv[]) { int count; int data_count; int thread_updates = 0; int data_updates = 0; int seed = 1; struct _timeb currSysTime1; struct _timeb currSysTime2; /* * Initialize the shared data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { data[data_count].data = 0; data[data_count].updates = 0; assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); } _ftime(&currSysTime1); /* * Create THREADS threads to access shared data. */ for (count = 0; count < THREADS; count++) { threads[count].thread_num = count; threads[count].updates = 0; threads[count].reads = 0; threads[count].seed = 1 + rand_r (&seed) % 71; assert(pthread_create (&threads[count].thread_id, NULL, thread_routine, (void*)&threads[count]) == 0); } /* * Wait for all threads to complete, and collect * statistics. */ for (count = 0; count < THREADS; count++) { assert(pthread_join (threads[count].thread_id, NULL) == 0); } putchar('\n'); fflush(stdout); for (count = 0; count < THREADS; count++) { if (threads[count].changed > 0) { printf ("Thread %d found changed elements %d times\n", count, threads[count].changed); } } putchar('\n'); fflush(stdout); for (count = 0; count < THREADS; count++) { thread_updates += threads[count].updates; printf ("%02d: seed %d, updates %d, reads %d\n", count, threads[count].seed, threads[count].updates, threads[count].reads); } putchar('\n'); fflush(stdout); /* * Collect statistics for the data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { data_updates += data[data_count].updates; printf ("data %02d: value %d, %d updates\n", data_count, data[data_count].data, data[data_count].updates); assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); } printf ("%d thread updates, %d data updates\n", thread_updates, data_updates); _ftime(&currSysTime2); printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", currSysTime1.time,currSysTime1.millitm, currSysTime2.time,currSysTime2.millitm, (currSysTime2.time*1000+currSysTime2.millitm) - (currSysTime1.time*1000+currSysTime1.millitm)); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex7r.c0000644000175000000620000000610111512143043020147 0ustar stevestaff/* * mutex7r.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_RECURSIVE mutex type. * Thread locks mutex then trylocks mutex (recursive lock twice). * Both locks and unlocks should succeed. * * Depends on API functions: * pthread_create() * pthread_join() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_trylock(&mutex) == 0); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); return (void *) 555; } int main() { pthread_t t; int result = 0; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_RECURSIVE); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == 555); assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock5_t.c0000644000175000000620000000510211512143043020445 0ustar stevestaff/* * rwlock5_t.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, timed-rdlock it, tryrdlock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_timedrdlock() * pthread_rwlock_tryrdlock() * pthread_rwlock_unlock() */ #include "test.h" #include pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_rwlock_tryrdlock(&rwlock1) == 0); assert(pthread_rwlock_unlock(&rwlock1) == 0); washere = 1; return 0; } int main() { pthread_t t; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); Sleep(2000); assert(pthread_rwlock_unlock(&rwlock1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar7.c0000644000175000000620000001342411512143043020265 0ustar stevestaff/* * File: condvar7.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test pthread_cond_broadcast with thread cancelation. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Test broadcast with NUMTHREADS (=5) waiting CVs, one is canceled while waiting. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #include /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 5 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct cvthing_t_ cvthing_t; struct cvthing_t_ { pthread_cond_t notbusy; pthread_mutex_t lock; int shared; }; static cvthing_t cvthing = { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }; static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; static struct timespec abstime = { 0, 0 }; static int awoken; void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Wait for the start gun */ assert(pthread_mutex_lock(&start_flag) == 0); assert(pthread_mutex_unlock(&start_flag) == 0); assert(pthread_mutex_lock(&cvthing.lock) == 0); #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif assert(cvthing.shared > 0); awoken++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); return (void *) 0; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; cvthing.shared = 0; assert((t[0] = pthread_self()).p != NULL); assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&start_flag) == 0); _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 10; assert((t[0] = pthread_self()).p != NULL); awoken = 0; for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ assert(pthread_mutex_unlock(&start_flag) == 0); /* * Give threads time to start. */ Sleep(1000); /* * Cancel one of the threads. */ assert(pthread_cancel(t[1]) == 0); assert(pthread_join(t[1], NULL) == 0); assert(pthread_mutex_lock(&cvthing.lock) == 0); cvthing.shared++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); /* * Signal all remaining waiting threads. */ assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); /* * Wait for all threads to complete. */ for (i = 2; i <= NUMTHREADS; i++) assert(pthread_join(t[i], NULL) == 0); /* * Cleanup the CV. */ assert(pthread_mutex_destroy(&cvthing.lock) == 0); assert(cvthing.lock == NULL); assert(pthread_cond_destroy(&cvthing.notbusy) == 0); assert(cvthing.notbusy == NULL); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { failed = !threadbag[i].started; if (failed) { fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. */ assert(awoken == (NUMTHREADS - 1)); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar3_3.c0000644000175000000620000000721011512143043020477 0ustar stevestaff/* * File: condvar3_3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test timeouts and lost signals on a CV. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait does not return ETIMEDOUT. * - Process returns non-zero exit status. */ /* Timur Aydin (taydin@snet.net) */ #include "test.h" #include pthread_cond_t cnd; pthread_mutex_t mtx; int main() { int rc; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert(pthread_cond_init(&cnd, 0) == 0); assert(pthread_mutex_init(&mtx, 0) == 0); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; /* Here pthread_cond_timedwait should time out after one second. */ assert(pthread_mutex_lock(&mtx) == 0); assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT); assert(pthread_mutex_unlock(&mtx) == 0); /* Here, the condition variable is signaled, but there are no threads waiting on it. The signal should be lost and the next pthread_cond_timedwait should time out too. */ // assert(pthread_mutex_lock(&mtx) == 0); assert((rc = pthread_cond_signal(&cnd)) == 0); // assert(pthread_mutex_unlock(&mtx) == 0); assert(pthread_mutex_lock(&mtx) == 0); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT); assert(pthread_mutex_unlock(&mtx) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/cleanup0.c0000644000175000000620000001210711512143043020246 0ustar stevestaff/* * File: cleanup1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test cleanup handler executes (when thread is not canceled). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 10 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t pop_count = {0, {0}}; static void increment_pop_count(void * arg) { sharedInt_t * sI = (sharedInt_t *) arg; EnterCriticalSection(&sI->cs); sI->i++; LeaveCriticalSection(&sI->cs); } void * mythread(void * arg) { int result = 0; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Set to known state and type */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); Sleep(100); pthread_cleanup_pop(1); #ifdef _MSC_VER #pragma inline_depth() #endif return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; InitializeCriticalSection(&pop_count.cs); assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; assert(pthread_join(t[i], (void **) &result) == 0); fail = (result == (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: result %d\n", i, threadbag[i].started, result); fflush(stderr); } failed = (failed || fail); } assert(!failed); assert(pop_count.i == NUMTHREADS); DeleteCriticalSection(&pop_count.cs); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ int main() { return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/condvar1_2.c0000644000175000000620000000633111512143043020477 0ustar stevestaff/* * File: condvar1_2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test CV linked list management and serialisation. * * Test Method (Validation or Falsification): * - Validation: * Initiate and destroy several CVs in random order. * Asynchronously traverse the CV list and broadcast. * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Creates and then imediately destroys a CV. Does not * test the CV. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - All initialised CVs destroyed without segfault. * - Successfully broadcasts all remaining CVs after * each CV is removed. * * Fail Criteria: */ #include #include "test.h" enum { NUM_CV = 5, NUM_LOOPS = 5 }; static pthread_cond_t cv[NUM_CV]; int main() { int i, j, k; int result = -1; pthread_t t; for (k = 0; k < NUM_LOOPS; k++) { for (i = 0; i < NUM_CV; i++) { assert(pthread_cond_init(&cv[i], NULL) == 0); } j = NUM_CV; (void) srand((unsigned)time(NULL)); /* Traverse the list asynchronously. */ assert(pthread_create(&t, NULL, pthread_timechange_handler_np, NULL) == 0); do { i = (NUM_CV - 1) * rand() / RAND_MAX; if (cv[i] != NULL) { j--; assert(pthread_cond_destroy(&cv[i]) == 0); } } while (j > 0); assert(pthread_join(t, (void **) &result) == 0); assert (result == 0); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/loadfree.c0000644000175000000620000000531111512143043020317 0ustar stevestaff/* * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * From: Todd Owen * To: pthreads-win32@sourceware.cygnus.com * Subject: invalid page fault when using LoadLibrary/FreeLibrary * * hi, * for me, pthread.dll consistently causes an "invalid page fault in * kernel32.dll" when I load it "explicitly"...to be precise, loading (with * LoadLibrary) isn't a problem, it gives the error when I call FreeLibrary. * I guess that the dll's cleanup must be causing the error. * * Implicit linkage of the dll has never given me this problem. Here's a * program (console application) that gives me the error. * * I compile with: mingw32 (gcc-2.95 release), with the MSVCRT add-on (not * that the compiler should make much difference in this case). * PTHREAD.DLL: is the precompiled 1999-11-02 one (I tried an older one as * well, with the same result). * * Fascinatingly, if you have your own dll (mycode.dll) which implicitly * loads pthread.dll, and then do LoadLibrary/FreeLibrary on _this_ dll, the * same thing happens. * */ #include "test.h" int main() { HINSTANCE hinst; assert((hinst = LoadLibrary("pthread")) != (HINSTANCE) 0); Sleep(100); FreeLibrary(hinst); return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel7.c0000644000175000000620000001221111512143043020047 0ustar stevestaff/* * File: cancel7.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test canceling a Win32 thread having created an * implicit POSIX handle for it. * * Test Method (Validation or Falsification): * - Validate return value and that POSIX handle is created and destroyed. * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #ifndef _UWIN #include #endif /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; pthread_t self; }; static bag_t threadbag[NUMTHREADS + 1]; #if ! defined (__MINGW32__) || defined (__MSVCRT__) unsigned __stdcall #else void #endif Win32thread(void * arg) { int i; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; assert((bag->self = pthread_self()).p != NULL); assert(pthread_kill(bag->self, 0) == 0); for (i = 0; i < 100; i++) { Sleep(100); pthread_testcancel(); } return 0; } int main() { int failed = 0; int i; HANDLE h[NUMTHREADS + 1]; unsigned thrAddr; /* Dummy variable to pass a valid location to _beginthreadex (Win98). */ for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; #if ! defined (__MINGW32__) || defined (__MSVCRT__) h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, &thrAddr); #else h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]); #endif } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); /* * Cancel all threads. */ for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_kill(threadbag[i].self, 0) == 0); assert(pthread_cancel(threadbag[i].self) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; #if ! defined (__MINGW32__) || defined (__MSVCRT__) assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE); #else /* * Can't get a result code. */ result = (int) PTHREAD_CANCELED; #endif assert(threadbag[i].self.p != NULL); assert(pthread_kill(threadbag[i].self, 0) == ESRCH); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/barrier4.c0000644000175000000620000000564211512143043020257 0ustar stevestaff/* * barrier4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a single barrier object, multiple wait on it, * and then destroy it. * */ #include "test.h" enum { NUMTHREADS = 16 }; pthread_barrier_t barrier = NULL; pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; static int serialThreadCount = 0; static int otherThreadCount = 0; void * func(void * arg) { int result = pthread_barrier_wait(&barrier); assert(pthread_mutex_lock(&mx) == 0); if (result == PTHREAD_BARRIER_SERIAL_THREAD) { serialThreadCount++; } else if (0 == result) { otherThreadCount++; } else { printf("Barrier wait failed: error = %s\n", error_string[result]); fflush(stdout); return NULL; } assert(pthread_mutex_unlock(&mx) == 0); return NULL; } int main() { int i, j; pthread_t t[NUMTHREADS + 1]; for (j = 1; j <= NUMTHREADS; j++) { printf("Barrier height = %d\n", j); serialThreadCount = 0; assert(pthread_barrier_init(&barrier, NULL, j) == 0); for (i = 1; i <= j; i++) { assert(pthread_create(&t[i], NULL, func, NULL) == 0); } for (i = 1; i <= j; i++) { assert(pthread_join(t[i], NULL) == 0); } assert(serialThreadCount == 1); assert(pthread_barrier_destroy(&barrier) == 0); } assert(pthread_mutex_destroy(&mx) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel2.c0000644000175000000620000001315311512143043020050 0ustar stevestaff/* * File: cancel2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test SEH or C++ cancel exception handling within * application exception blocks. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 1 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER; void * mythread(void * arg) { int result = 0; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Set to known state and type */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); switch (bag->threadnum % 2) { case 0: assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); result = 0; break; case 1: assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); result = 1; break; } #if defined(_MSC_VER) && !defined(__cplusplus) __try #else try #endif { /* Wait for go from main */ assert(pthread_mutex_lock(&waitLock) == 0); assert(pthread_mutex_unlock(&waitLock) == 0); sched_yield(); for (;;) { pthread_testcancel(); } } #if defined(_MSC_VER) && !defined(__cplusplus) __except(EXCEPTION_EXECUTE_HANDLER) #else #if defined(PtW32CatchAll) PtW32CatchAll #else catch(...) #endif #endif { /* * Should not get into here. */ result += 100; } /* * Should not get to here either. */ result += 1000; return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; assert((t[0] = pthread_self()).p != NULL); assert(pthread_mutex_lock(&waitLock) == 0); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); assert(pthread_mutex_unlock(&waitLock) == 0); Sleep(500); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_cancel(t[i]) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; assert(pthread_join(t[i], (void **) &result) == 0); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: location %d: cancel type %s\n", i, threadbag[i].started, result, ((result % 2) == 0) ? "ASYNCHRONOUS" : "DEFERRED"); } failed |= fail; } assert(!failed); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ int main() { return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/mutex7e.c0000644000175000000620000000622111512143043020135 0ustar stevestaff/* * mutex7e.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_ERRORCHECK mutex type. * Thread locks and then trylocks mutex (attempted recursive lock). * Trylock should fail with an EBUSY error. * The second unlock attempt should fail with an EPERM error. * * Depends on API functions: * pthread_create() * pthread_join() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == EPERM); return (void *) 555; } int main() { pthread_t t; int result = 0; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_ERRORCHECK); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == 555); assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex4.c0000644000175000000620000000715511512143043017774 0ustar stevestaff/* * mutex4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Thread A locks mutex - thread B tries to unlock. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" static int wasHere = 0; static pthread_mutex_t mutex1; void * unlocker(void * arg) { int expectedResult = (int) arg; wasHere++; assert(pthread_mutex_unlock(&mutex1) == expectedResult); wasHere++; return NULL; } int main() { pthread_t t; pthread_mutexattr_t ma; assert(pthread_mutexattr_init(&ma) == 0); wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_DEFAULT) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); /* * NORMAL (fast) mutexes don't check ownership. */ assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == EPERM); assert(wasHere == 2); wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); /* * NORMAL (fast) mutexes don't check ownership. */ assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == EPERM); assert(wasHere == 2); wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); wasHere = 0; assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutex_init(&mutex1, &ma) == 0); assert(pthread_mutex_lock(&mutex1) == 0); assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(wasHere == 2); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex2r.c0000644000175000000620000000415111512143043020145 0ustar stevestaff/* * mutex2r.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static mutex object, lock it, * and then unlock it again. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; int main() { assert(mutex == PTHREAD_RECURSIVE_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&mutex) == 0); assert(mutex != PTHREAD_RECURSIVE_MUTEX_INITIALIZER); assert(mutex != NULL); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/Debug.dsw0000644000175000000620000000102511512143043020135 0ustar stevestaffMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "Debug"=.\Debug.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### nyquist-3.05/liblo/pthreads.2/tests/mutex2e.c0000644000175000000620000000415411512143043020133 0ustar stevestaff/* * mutex2e.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static mutex object, lock it, * and then unlock it again. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER; int main() { assert(mutex == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&mutex) == 0); assert(mutex != PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); assert(mutex != NULL); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchtest4.c0000644000175000000620000001273211512143043020606 0ustar stevestaff/* * benchtest4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Measure time taken to complete an elementary operation. * * - Mutex * Single thread iteration over trylock/unlock for each mutex type. */ #include "test.h" #include #ifdef __GNUC__ #include #endif #include "benchtest.h" #define PTW32_MUTEX_TYPES #define ITERATIONS 10000000L pthread_mutex_t mx; old_mutex_t ox; pthread_mutexattr_t ma; struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; long durationMilliSecs; long overHeadMilliSecs = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) /* * Dummy use of j, otherwise the loop may be removed by the optimiser * when doing the overhead timing with an empty loop. */ #define TESTSTART \ { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; #define TESTSTOP \ }; _ftime(&currSysTimeStop); if (j + k == i) j++; } void oldRunTest (char * testNameString, int mType) { } void runTest (char * testNameString, int mType) { #ifdef PTW32_MUTEX_TYPES pthread_mutexattr_settype(&ma, mType); #endif pthread_mutex_init(&mx, &ma); TESTSTART (void) pthread_mutex_trylock(&mx); (void) pthread_mutex_unlock(&mx); TESTSTOP pthread_mutex_destroy(&mx); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); } int main (int argc, char *argv[]) { pthread_mutexattr_init(&ma); printf( "=============================================================================\n"); printf( "Trylock plus unlock on an unlocked mutex.\n"); printf( "%ld iterations.\n\n", ITERATIONS); printf( "%-45s %15s %15s\n", "Test", "Total(msec)", "average(usec)"); printf( "-----------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ TESTSTART TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; overHeadMilliSecs = durationMilliSecs; old_mutex_use = OLD_WIN32CS; assert(old_mutex_init(&ox, NULL) == 0); TESTSTART (void) old_mutex_trylock(&ox); (void) old_mutex_unlock(&ox); TESTSTOP assert(old_mutex_destroy(&ox) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Critical Section (WNT)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); old_mutex_use = OLD_WIN32MUTEX; assert(old_mutex_init(&ox, NULL) == 0); TESTSTART (void) old_mutex_trylock(&ox); (void) old_mutex_unlock(&ox); TESTSTOP assert(old_mutex_destroy(&ox) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Win32 Mutex (W9x)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); printf( ".............................................................................\n"); /* * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif printf( "=============================================================================\n"); /* * End of tests. */ pthread_mutexattr_destroy(&ma); return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock6_t2.c0000644000175000000620000000652111512143043020536 0ustar stevestaff/* * rwlock6_t2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Check writer and reader timeouts. * * Depends on API functions: * pthread_rwlock_timedrdlock() * pthread_rwlock_timedwrlock() * pthread_rwlock_unlock() */ #include "test.h" #include static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int bankAccount = 0; struct timespec abstime = { 0, 0 }; void * wrfunc(void * arg) { int result; result = pthread_rwlock_timedwrlock(&rwlock1, &abstime); if ((int) arg == 1) { assert(result == 0); Sleep(2000); bankAccount += 10; assert(pthread_rwlock_unlock(&rwlock1) == 0); return ((void *) bankAccount); } else if ((int) arg == 2) { assert(result == ETIMEDOUT); return ((void *) 100); } return ((void *) -1); } void * rdfunc(void * arg) { int ba = 0; assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == ETIMEDOUT); return ((void *) ba); } int main() { pthread_t wrt1; pthread_t wrt2; pthread_t rdt; int wr1Result = 0; int wr2Result = 0; int rdResult = 0; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; bankAccount = 0; assert(pthread_create(&wrt1, NULL, wrfunc, (void *) 1) == 0); Sleep(100); assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0); Sleep(100); assert(pthread_create(&wrt2, NULL, wrfunc, (void *) 2) == 0); assert(pthread_join(wrt1, (void **) &wr1Result) == 0); assert(pthread_join(rdt, (void **) &rdResult) == 0); assert(pthread_join(wrt2, (void **) &wr2Result) == 0); assert(wr1Result == 10); assert(rdResult == 0); assert(wr2Result == 100); return 0; } nyquist-3.05/liblo/pthreads.2/tests/semaphore1.c0000644000175000000620000000713411512143043020607 0ustar stevestaff/* * File: semaphore1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Verify trywait() returns -1 and sets EAGAIN. * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" void * thr(void * arg) { sem_t s; int result; assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); assert((result = sem_trywait(&s)) == -1); if ( result == -1 ) { int err = errno; printf("thread: sem_trywait 1: expecting error %s: got %s\n", error_string[EAGAIN], error_string[err]); fflush(stdout); assert(err == EAGAIN); } else { printf("thread: ok 1\n"); } assert((result = sem_post(&s)) == 0); assert((result = sem_trywait(&s)) == 0); if ( result == -1 ) { perror("thread: sem_trywait 2"); } else { printf("thread: ok 2\n"); } assert(sem_post(&s) == 0); return 0; } int main() { pthread_t t; sem_t s; int result; assert(pthread_create(&t, NULL, thr, NULL) == 0); assert(pthread_join(t, (void **)&result) == 0); assert(result == 0); assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); assert((result = sem_trywait(&s)) == -1); if ( result == -1 ) { int err = errno; printf("main: sem_trywait 1: expecting error %s: got %s\n", error_string[EAGAIN], error_string[err]); fflush(stdout); assert(err == EAGAIN); } else { printf("main: ok 1\n"); } assert((result = sem_post(&s)) == 0); assert((result = sem_trywait(&s)) == 0); if ( result == -1 ) { perror("main: sem_trywait 2"); } else { printf("main: ok 2\n"); } assert(sem_post(&s) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex6r.c0000644000175000000620000000605211512143043020153 0ustar stevestaff/* * mutex6r.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_RECURSIVE mutex type. * Thread locks mutex twice (recursive lock). * Both locks and unlocks should succeed. * * Depends on API functions: * pthread_create() * pthread_join() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); return (void *) 555; } int main() { pthread_t t; int result = 0; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_RECURSIVE); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == 555); assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/context1.c0000644000175000000620000000623411512143043020310 0ustar stevestaff/* * File: context1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test context switching method. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - pthread_create * pthread_exit * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #define _WIN32_WINNT 0x400 #include "test.h" #include "../implement.h" static int washere = 0; static void * func(void * arg) { washere = 1; Sleep(1000); return 0; } static void anotherEnding () { /* * Switched context */ washere++; pthread_exit(0); } int main() { pthread_t t; HANDLE hThread; assert(pthread_create(&t, NULL, func, NULL) == 0); hThread = ((ptw32_thread_t *)t.p)->threadH; Sleep(500); SuspendThread(hThread); if (WaitForSingleObject(hThread, 0) == WAIT_TIMEOUT) { /* * Ok, thread did not exit before we got to it. */ CONTEXT context; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext(hThread, &context); /* *_x86 only!!! */ context.Eip = (DWORD) anotherEnding; SetThreadContext(hThread, &context); ResumeThread(hThread); } else { printf("Exited early\n"); fflush(stdout); } Sleep(1000); assert(washere == 2); return 0; } nyquist-3.05/liblo/pthreads.2/tests/eyal1.c0000644000175000000620000002161411512143043017555 0ustar stevestaff/* Simple POSIX threads program. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Author: Eyal Lebedinsky eyal@eyal.emu.id.au * Written: Sep 1998. * Version Date: 12 Sep 1998 * * Do we need to lock stdout or is it thread safe? * * Used: * pthread_t * pthread_attr_t * pthread_create() * pthread_join() * pthread_mutex_t * PTHREAD_MUTEX_INITIALIZER * pthread_mutex_init() [not used now] * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() * * What this program does is establish a work queue (implemented using * four mutexes for each thread). It then schedules work (by storing * a number in 'todo') and releases the threads. When the work is done * the threads will block. The program then repeats the same thing once * more (just to test the logic) and when the work is done it destroyes * the threads. * * The 'work' we do is simply burning CPU cycles in a loop. * The 'todo' work queue is trivial - each threads pops one element * off it by incrementing it, the poped number is the 'work' to do. * When 'todo' reaches the limit (nwork) the queue is considered * empty. * * The number displayed at the end is the amount of work each thread * did, so we can see if the load was properly distributed. * * The program was written to test a threading setup (not seen here) * rather than to demonstrate correct usage of the pthread facilities. * * Note how each thread is given access to a thread control structure * (TC) which is used for communicating to/from the main program (e.g. * the threads knows its 'id' and also filles in the 'work' done). */ #include "test.h" #include #include struct thread_control { int id; pthread_t thread; /* thread id */ pthread_mutex_t mutex_start; pthread_mutex_t mutex_started; pthread_mutex_t mutex_end; pthread_mutex_t mutex_ended; long work; /* work done */ int stat; /* pthread_init status */ }; typedef struct thread_control TC; static TC *tcs = NULL; static int nthreads = 10; static int nwork = 100; static int quiet = 0; static int todo = -1; static pthread_mutex_t mutex_todo = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t mutex_stdout = PTHREAD_MUTEX_INITIALIZER; static void die (int ret) { if (NULL != tcs) { free (tcs); tcs = NULL; } if (ret) exit (ret); } static double waste_time (int n) { int i; double f, g, h, s; s = 0.0; /* * Useless work. */ for (i = n*100; i > 0; --i) { f = rand (); g = rand (); h = rand (); s += 2.0 * f * g / (h != 0.0 ? (h * h) : 1.0); } return s; } static int do_work_unit (int who, int n) { int i; static int nchars = 0; double f = 0.0; if (quiet) i = 0; else { /* * get lock on stdout */ assert(pthread_mutex_lock (&mutex_stdout) == 0); /* * do our job */ i = printf ("%c", "0123456789abcdefghijklmnopqrstuvwxyz"[who]); if (!(++nchars % 50)) printf ("\n"); fflush (stdout); /* * release lock on stdout */ assert(pthread_mutex_unlock (&mutex_stdout) == 0); } n = rand () % 10000; /* ignore incoming 'n' */ f = waste_time (n); /* This prevents the statement above from being optimised out */ if (f > 0.0) return(n); return (n); } static int print_server (void *ptr) { int mywork; int n; TC *tc = (TC *)ptr; assert(pthread_mutex_lock (&tc->mutex_started) == 0); for (;;) { assert(pthread_mutex_lock (&tc->mutex_start) == 0); assert(pthread_mutex_unlock (&tc->mutex_start) == 0); assert(pthread_mutex_lock (&tc->mutex_ended) == 0); assert(pthread_mutex_unlock (&tc->mutex_started) == 0); for (;;) { /* * get lock on todo list */ assert(pthread_mutex_lock (&mutex_todo) == 0); mywork = todo; if (todo >= 0) { ++todo; if (todo >= nwork) todo = -1; } assert(pthread_mutex_unlock (&mutex_todo) == 0); if (mywork < 0) break; assert((n = do_work_unit (tc->id, mywork)) >= 0); tc->work += n; } assert(pthread_mutex_lock (&tc->mutex_end) == 0); assert(pthread_mutex_unlock (&tc->mutex_end) == 0); assert(pthread_mutex_lock (&tc->mutex_started) == 0); assert(pthread_mutex_unlock (&tc->mutex_ended) == 0); if (-2 == mywork) break; } assert(pthread_mutex_unlock (&tc->mutex_started) == 0); return (0); } static void dosync (void) { int i; for (i = 0; i < nthreads; ++i) { assert(pthread_mutex_lock (&tcs[i].mutex_end) == 0); assert(pthread_mutex_unlock (&tcs[i].mutex_start) == 0); assert(pthread_mutex_lock (&tcs[i].mutex_started) == 0); assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0); } /* * Now threads do their work */ for (i = 0; i < nthreads; ++i) { assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0); assert(pthread_mutex_unlock (&tcs[i].mutex_end) == 0); assert(pthread_mutex_lock (&tcs[i].mutex_ended) == 0); assert(pthread_mutex_unlock (&tcs[i].mutex_ended) == 0); } } static void dowork (void) { todo = 0; dosync(); todo = 0; dosync(); } int main (int argc, char *argv[]) { int i; assert(NULL != (tcs = (TC *) calloc (nthreads, sizeof (*tcs)))); /* * Launch threads */ for (i = 0; i < nthreads; ++i) { tcs[i].id = i; assert(pthread_mutex_init (&tcs[i].mutex_start, NULL) == 0); assert(pthread_mutex_init (&tcs[i].mutex_started, NULL) == 0); assert(pthread_mutex_init (&tcs[i].mutex_end, NULL) == 0); assert(pthread_mutex_init (&tcs[i].mutex_ended, NULL) == 0); tcs[i].work = 0; assert(pthread_mutex_lock (&tcs[i].mutex_start) == 0); assert((tcs[i].stat = pthread_create (&tcs[i].thread, NULL, (void *(*)(void *))print_server, (void *) &tcs[i]) ) == 0); /* * Wait for thread initialisation */ { int trylock = 0; while (trylock == 0) { trylock = pthread_mutex_trylock(&tcs[i].mutex_started); assert(trylock == 0 || trylock == EBUSY); if (trylock == 0) { assert(pthread_mutex_unlock (&tcs[i].mutex_started) == 0); } } } } dowork (); /* * Terminate threads */ todo = -2; /* please terminate */ dosync(); for (i = 0; i < nthreads; ++i) { if (0 == tcs[i].stat) assert(pthread_join (tcs[i].thread, NULL) == 0); } /* * destroy locks */ assert(pthread_mutex_destroy (&mutex_stdout) == 0); assert(pthread_mutex_destroy (&mutex_todo) == 0); /* * Cleanup */ printf ("\n"); /* * Show results */ for (i = 0; i < nthreads; ++i) { printf ("%2d ", i); if (0 == tcs[i].stat) printf ("%10ld\n", tcs[i].work); else printf ("failed %d\n", tcs[i].stat); assert(pthread_mutex_unlock(&tcs[i].mutex_start) == 0); assert(pthread_mutex_destroy (&tcs[i].mutex_start) == 0); assert(pthread_mutex_destroy (&tcs[i].mutex_started) == 0); assert(pthread_mutex_destroy (&tcs[i].mutex_end) == 0); assert(pthread_mutex_destroy (&tcs[i].mutex_ended) == 0); } die (0); return (0); } nyquist-3.05/liblo/pthreads.2/tests/cancel6a.c0000644000175000000620000001051011512143043020207 0ustar stevestaff/* * File: cancel6a.c * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 Ben Elliston and Ross Johnson * Copyright (C) 1999,2000,2001 Ross Johnson * * Contact Email: rpj@ise.canberra.edu.au * * 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.1 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 * * -------------------------------------------------------------------------- * * Test Synopsis: Test double cancelation - asynchronous. * Second attempt should fail (ESRCH). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; void * mythread(void * arg) { int result = ((int)PTHREAD_CANCELED + 1); bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Set to known state and type */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); /* * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (bag->count = 0; bag->count < 100; bag->count++) Sleep(100); return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_cancel(t[i]) == 0); assert(pthread_cancel(t[i]) == ESRCH); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; /* * The thread does not contain any cancelation points, so * a return value of PTHREAD_CANCELED confirms that async * cancelation succeeded. */ assert(pthread_join(t[i], (void **) &result) == 0); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/tsd2.c0000644000175000000620000001246511512143043017422 0ustar stevestaff/* * tsd2.c * * Test Thread Specific Data (TSD) key creation and destruction. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * * -------------------------------------------------------------------------- * * Description: * - * * Test Method (validation or falsification): * - validation * * Requirements Tested: * - keys are created for each existing thread including the main thread * - keys are created for newly created threads * - keys are thread specific * - destroy routine is called on each thread exit including the main thread * * Features Tested: * - * * Cases Tested: * - * * Environment: * - * * Input: * - none * * Output: * - text to stdout * * Assumptions: * - already validated: pthread_create() * pthread_once() * - main thread also has a POSIX thread identity * * Pass Criteria: * - stdout matches file reference/tsd1.out * * Fail Criteria: * - fails to match file reference/tsd1.out * - output identifies failed component */ #include #include "test.h" enum { NUM_THREADS = 100 }; static pthread_key_t key = NULL; static int accesscount[NUM_THREADS]; static int thread_set[NUM_THREADS]; static int thread_destroyed[NUM_THREADS]; static pthread_barrier_t startBarrier; static void destroy_key(void * arg) { int * j = (int *) arg; (*j)++; /* Set TSD key from the destructor to test destructor iteration */ if (*j == 2) assert(pthread_setspecific(key, arg) == 0); else assert(*j == 3); thread_destroyed[j - accesscount] = 1; } static void setkey(void * arg) { int * j = (int *) arg; thread_set[j - accesscount] = 1; assert(*j == 0); assert(pthread_getspecific(key) == NULL); assert(pthread_setspecific(key, arg) == 0); assert(pthread_setspecific(key, arg) == 0); assert(pthread_setspecific(key, arg) == 0); assert(pthread_getspecific(key) == arg); (*j)++; assert(*j == 1); } static void * mythread(void * arg) { (void) pthread_barrier_wait(&startBarrier); setkey(arg); return 0; /* Exiting the thread will call the key destructor. */ } int main() { int i; int fail = 0; pthread_t thread[NUM_THREADS]; assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0); for (i = 1; i < NUM_THREADS/2; i++) { accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); } /* * Here we test that existing threads will get a key created * for them. */ assert(pthread_key_create(&key, destroy_key) == 0); (void) pthread_barrier_wait(&startBarrier); /* * Test main thread key. */ accesscount[0] = 0; setkey((void *) &accesscount[0]); /* * Here we test that new threads will get a key created * for them. */ for (i = NUM_THREADS/2; i < NUM_THREADS; i++) { accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); } /* * Wait for all threads to complete. */ for (i = 1; i < NUM_THREADS; i++) { int result = 0; assert(pthread_join(thread[i], (void **) &result) == 0); } assert(pthread_key_delete(key) == 0); assert(pthread_barrier_destroy(&startBarrier) == 0); for (i = 1; i < NUM_THREADS; i++) { /* * The counter is incremented once when the key is set to * a value, and again when the key is destroyed. If the key * doesn't get set for some reason then it will still be * NULL and the destroy function will not be called, and * hence accesscount will not equal 2. */ if (accesscount[i] != 3) { fail++; fprintf(stderr, "Thread %d key, set = %d, destroyed = %d\n", i, thread_set[i], thread_destroyed[i]); } } fflush(stderr); return (fail); } nyquist-3.05/liblo/pthreads.2/tests/exit5.c0000644000175000000620000001162711512143043017603 0ustar stevestaff/* * File: exit5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test calling pthread_exit from a Win32 thread * having created an implicit POSIX handle for it. * * Test Method (Validation or Falsification): * - Validate return value and that POSIX handle is created and destroyed. * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #ifndef _UWIN #include #endif /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; pthread_t self; }; static bag_t threadbag[NUMTHREADS + 1]; #if ! defined (__MINGW32__) || defined (__MSVCRT__) unsigned __stdcall #else void #endif Win32thread(void * arg) { int result = 1; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; assert((bag->self = pthread_self()).p != NULL); assert(pthread_kill(bag->self, 0) == 0); /* * Doesn't return. */ pthread_exit((void *) result); return 0; } int main() { int failed = 0; int i; HANDLE h[NUMTHREADS + 1]; unsigned thrAddr; /* Dummy variable to pass a valid location to _beginthreadex (Win98). */ for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; #if ! defined (__MINGW32__) || defined (__MSVCRT__) h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, &thrAddr); #else h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]); #endif } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; #if ! defined (__MINGW32__) || defined (__MSVCRT__) assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE); #else /* * Can't get a result code. */ result = 1; #endif assert(threadbag[i].self.p != NULL && pthread_kill(threadbag[i].self, 0) == ESRCH); fail = (result != 1); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/Debug.dsp0000644000175000000620000000673011512143043020136 0ustar stevestaff# Microsoft Developer Studio Project File - Name="Debug" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=Debug - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "Debug.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "Debug.mak" CFG="Debug - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "Debug - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "Debug - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "Debug - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0xc09 /d "NDEBUG" # ADD RSC /l 0xc09 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "Debug - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /MDd /W3 /WX /Gm /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "CLEANUP_C" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0xc09 /d "_DEBUG" # ADD RSC /l 0xc09 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib pthreadVC2d.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:".." !ENDIF # Begin Target # Name "Debug - Win32 Release" # Name "Debug - Win32 Debug" # Begin Source File SOURCE=.\Debug.txt # End Source File # Begin Source File SOURCE=.\semaphore1.c # End Source File # End Target # End Project nyquist-3.05/liblo/pthreads.2/tests/once3.c0000644000175000000620000000777611512143043017566 0ustar stevestaff/* * once3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create several pthread_once objects and channel several threads * through each. Make the init_routine cancelable and cancel them with * waiters waiting. * * Depends on API functions: * pthread_once() * pthread_create() * pthread_testcancel() * pthread_cancel() * pthread_once() */ #define ASSERT_TRACE #include "test.h" #define NUM_THREADS 100 /* Targeting each once control */ #define NUM_ONCE 10 pthread_once_t o = PTHREAD_ONCE_INIT; pthread_once_t once[NUM_ONCE]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t numOnce = {0, {0}}; static sharedInt_t numThreads = {0, {0}}; void myfunc(void) { EnterCriticalSection(&numOnce.cs); numOnce.i++; assert(numOnce.i > 0); LeaveCriticalSection(&numOnce.cs); /* Simulate slow once routine so that following threads pile up behind it */ Sleep(10); /* test for cancelation late so we're sure to have waiters. */ pthread_testcancel(); } void * mythread(void * arg) { /* * Cancel every thread. These threads are deferred cancelable only, so * only the thread performing the once routine (my_func) will see it (there are * no other cancelation points here). The result will be that every thread * eventually cancels only when it becomes the new once thread. */ assert(pthread_cancel(pthread_self()) == 0); assert(pthread_once(&once[(int) arg], myfunc) == 0); EnterCriticalSection(&numThreads.cs); numThreads.i++; LeaveCriticalSection(&numThreads.cs); return 0; } int main() { pthread_t t[NUM_THREADS][NUM_ONCE]; int i, j; InitializeCriticalSection(&numThreads.cs); InitializeCriticalSection(&numOnce.cs); for (j = 0; j < NUM_ONCE; j++) { once[j] = o; for (i = 0; i < NUM_THREADS; i++) { assert(pthread_create(&t[i][j], NULL, mythread, (void *) j) == 0); } } for (j = 0; j < NUM_ONCE; j++) for (i = 0; i < NUM_THREADS; i++) if (pthread_join(t[i][j], NULL) != 0) printf("Join failed for [thread,once] = [%d,%d]\n", i, j); /* * All threads will cancel, none will return normally from * pthread_once and so numThreads should never be incremented. However, * numOnce should be incremented by every thread (NUM_THREADS*NUM_ONCE). */ assert(numOnce.i == NUM_ONCE * NUM_THREADS); assert(numThreads.i == 0); DeleteCriticalSection(&numOnce.cs); DeleteCriticalSection(&numThreads.cs); return 0; } nyquist-3.05/liblo/pthreads.2/tests/tryentercs.c0000644000175000000620000000612411512143043020743 0ustar stevestaff/* * tryentercs.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * See if we have the TryEnterCriticalSection function. * Does not use any part of pthreads. */ #include #include #include /* * Function pointer to TryEnterCriticalSection if it exists * - otherwise NULL */ BOOL (WINAPI *_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; /* * Handle to kernel32.dll */ static HINSTANCE _h_kernel32; int main() { CRITICAL_SECTION cs; SetLastError(0); printf("Last Error [main enter] %ld\n", (long) GetLastError()); /* * Load KERNEL32 and try to get address of TryEnterCriticalSection */ _h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); _try_enter_critical_section = (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION)) GetProcAddress(_h_kernel32, (LPCSTR) "TryEnterCriticalSection"); if (_try_enter_critical_section != NULL) { InitializeCriticalSection(&cs); SetLastError(0); if ((*_try_enter_critical_section)(&cs) != 0) { LeaveCriticalSection(&cs); } else { printf("Last Error [try enter] %ld\n", (long) GetLastError()); _try_enter_critical_section = NULL; } DeleteCriticalSection(&cs); } (void) FreeLibrary(_h_kernel32); printf("This system %s TryEnterCriticalSection.\n", (_try_enter_critical_section == NULL) ? "DOES NOT SUPPORT" : "SUPPORTS"); printf("POSIX Mutexes will be based on Win32 %s.\n", (_try_enter_critical_section == NULL) ? "Mutexes" : "Critical Sections"); return(0); } nyquist-3.05/liblo/pthreads.2/tests/cancel1.c0000644000175000000620000001104011512143043020040 0ustar stevestaff/* * File: cancel1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test setting cancel state and cancel type. * - * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - pthread_setcancelstate function * - pthread_setcanceltype function * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - pthread_create, pthread_self work. * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 2 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* ... */ { int oldstate; int oldtype; assert(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) == 0); assert(oldstate == PTHREAD_CANCEL_ENABLE); /* Check default */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) == 0); assert(pthread_setcancelstate(oldstate, &oldstate) == 0); assert(oldstate == PTHREAD_CANCEL_DISABLE); /* Check setting */ assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype) == 0); assert(oldtype == PTHREAD_CANCEL_DEFERRED); /* Check default */ assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); assert(pthread_setcanceltype(oldtype, &oldtype) == 0); assert(oldtype == PTHREAD_CANCEL_ASYNCHRONOUS); /* Check setting */ } return 0; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ /* * Give threads time to run. */ Sleep(NUMTHREADS * 1000); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { failed = !threadbag[i].started; if (failed) { fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print ouput on failure. */ for (i = 1; i <= NUMTHREADS; i++) { /* ... */ } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/join2.c0000644000175000000620000000412211512143043017556 0ustar stevestaff/* * Test for pthread_join() returning return value from threads. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: pthread_create(). */ #include "test.h" void * func(void * arg) { Sleep(1000); return arg; } int main(int argc, char * argv[]) { pthread_t id[4]; int i; int result; /* Create a few threads and then exit. */ for (i = 0; i < 4; i++) { assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); } for (i = 0; i < 4; i++) { assert(pthread_join(id[i], (void **) &result) == 0); assert(result == i); } /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock1.c0000644000175000000620000000367511512143043020133 0ustar stevestaff/* * rwlock1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create a simple rwlock object and then destroy it. * * Depends on API functions: * pthread_rwlock_init() * pthread_rwlock_destroy() */ #include "test.h" pthread_rwlock_t rwlock = NULL; int main() { assert(rwlock == NULL); assert(pthread_rwlock_init(&rwlock, NULL) == 0); assert(rwlock != NULL); assert(pthread_rwlock_destroy(&rwlock) == 0); assert(rwlock == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex1r.c0000644000175000000620000000456211512143043020152 0ustar stevestaff/* * mutex1r.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * As for mutex1.c but with type set to PTHREAD_MUTEX_RECURSIVE. * * Create a simple mutex object, lock it, unlock it, then destroy it. * This is the simplest test of the pthread mutex family that we can do. * * Depends on API functions: * pthread_mutexattr_settype() * pthread_mutex_init() * pthread_mutex_destroy() */ #include "test.h" pthread_mutex_t mutex = NULL; pthread_mutexattr_t mxAttr; int main() { assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(mutex == NULL); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(mutex != NULL); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock2_t.c0000644000175000000620000000464711512143043020457 0ustar stevestaff/* * rwlock2_t.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, timed-lock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_timedrdlock() * pthread_rwlock_unlock() */ #include "test.h" #include pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; int main() { struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(rwlock == PTHREAD_RWLOCK_INITIALIZER); assert(pthread_rwlock_timedrdlock(&rwlock, &abstime) == 0); assert(rwlock != PTHREAD_RWLOCK_INITIALIZER); assert(rwlock != NULL); assert(pthread_rwlock_unlock(&rwlock) == 0); assert(pthread_rwlock_destroy(&rwlock) == 0); assert(rwlock == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/semaphore4.c0000644000175000000620000000704011512143043020606 0ustar stevestaff/* * File: semaphore4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Verify sem_getvalue returns the correct number of waiters * after threads are cancelled. * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #define MAX_COUNT 100 sem_t s; void * thr (void * arg) { assert(sem_wait(&s) == 0); return NULL; } int main() { int value = 0; int i; pthread_t t[MAX_COUNT+1]; assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %d\n", value); fflush(stdout); assert(value == 0); for (i = 1; i <= MAX_COUNT; i++) { assert(pthread_create(&t[i], NULL, thr, NULL) == 0); do { sched_yield(); assert(sem_getvalue(&s, &value) == 0); } while (value != -i); // printf("Value = %d\n", value); fflush(stdout); assert(-value == i); } assert(sem_getvalue(&s, &value) == 0); assert(-value == MAX_COUNT); //printf("value = %d\n", -value); fflush(stdout); assert(pthread_cancel(t[50]) == 0); { int result; assert(pthread_join(t[50], (void **) &result) == 0); // printf("result = %d\n", result); fflush(stdout); } assert(sem_getvalue(&s, &value) == 0); //printf("value = %d\n", -value); fflush(stdout); assert(-value == (MAX_COUNT - 1)); for (i = MAX_COUNT - 2; i >= 0; i--) { assert(sem_post(&s) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %d\n", value); fflush(stdout); assert(-value == i); } for (i = 1; i <= MAX_COUNT; i++) if (i != 50) assert(pthread_join(t[i], NULL) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/Debug.txt0000644000175000000620000000034011512143043020156 0ustar stevestaffThis project is used to debug individual test case programs. To build and debug a test case: - add the .c file to this project; - remove any .c files from other test cases from this project. - build and debug as usual.nyquist-3.05/liblo/pthreads.2/tests/once1.c0000644000175000000620000000415211512143043017545 0ustar stevestaff/* * once1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create a static pthread_once and test that it calls myfunc once. * * Depends on API functions: * pthread_once() * pthread_create() */ #include "test.h" pthread_once_t once = PTHREAD_ONCE_INIT; static int washere = 0; void myfunc(void) { washere++; } void * mythread(void * arg) { assert(pthread_once(&once, myfunc) == 0); return 0; } int main() { pthread_t t1, t2; assert(pthread_create(&t1, NULL, mythread, NULL) == 0); assert(pthread_create(&t2, NULL, mythread, NULL) == 0); Sleep(2000); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/barrier1.c0000644000175000000620000000355611512143043020256 0ustar stevestaff/* * barrier1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create a barrier object and then destroy it. * */ #include "test.h" pthread_barrier_t barrier = NULL; int main() { assert(barrier == NULL); assert(pthread_barrier_init(&barrier, NULL, 1) == 0); assert(barrier != NULL); assert(pthread_barrier_destroy(&barrier) == 0); assert(barrier == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar3_1.c0000644000175000000620000001243011512143043020475 0ustar stevestaff/* * File: condvar3_1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test timeout of multiple waits on a CV with some signaled. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Because some CVs are never signaled, we expect their waits to time out. * Some are signaled, the rest time out. Pthread_cond_destroy() will fail * unless all are accounted for, either signaled or timedout. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait does not return ETIMEDOUT. * - Process returns non-zero exit status. */ #define _WIN32_WINNT 0x400 #include "test.h" #include static pthread_cond_t cv; static pthread_cond_t cv1; static pthread_mutex_t mutex; static pthread_mutex_t mutex1; static struct timespec abstime = { 0, 0 }; static int timedout = 0; static int signaled = 0; static int awoken = 0; static int waiting = 0; enum { NUMTHREADS = 30 }; void * mythread(void * arg) { int result; assert(pthread_mutex_lock(&mutex1) == 0); ++waiting; assert(pthread_mutex_unlock(&mutex1) == 0); assert(pthread_cond_signal(&cv1) == 0); assert(pthread_mutex_lock(&mutex) == 0); result = pthread_cond_timedwait(&cv, &mutex, &abstime); if (result == ETIMEDOUT) { timedout++; } else { awoken++; } assert(pthread_mutex_unlock(&mutex) == 0); return arg; } #include "../implement.h" int main() { int i; pthread_t t[NUMTHREADS + 1]; int result = 0; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert(pthread_cond_init(&cv, NULL) == 0); assert(pthread_cond_init(&cv1, NULL) == 0); assert(pthread_mutex_init(&mutex, NULL) == 0); assert(pthread_mutex_init(&mutex1, NULL) == 0); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; assert(pthread_mutex_lock(&mutex1) == 0); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); } do { assert(pthread_cond_wait(&cv1,&mutex1) == 0); } while ( NUMTHREADS > waiting ); assert(pthread_mutex_unlock(&mutex1) == 0); for (i = NUMTHREADS/3; i <= 2*NUMTHREADS/3; i++) { // assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_cond_signal(&cv) == 0); // assert(pthread_mutex_unlock(&mutex) == 0); signaled++; } for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_join(t[i], (void **) &result) == 0); assert(result == i); } fprintf(stderr, "awk = %d\n", awoken); fprintf(stderr, "sig = %d\n", signaled); fprintf(stderr, "tot = %d\n", timedout); assert(signaled == awoken); assert(timedout == NUMTHREADS - signaled); assert(pthread_cond_destroy(&cv1) == 0); { int result = pthread_cond_destroy(&cv); if (result != 0) { fprintf(stderr, "Result = %s\n", error_string[result]); fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); fflush(stderr); } assert(result == 0); } assert(pthread_mutex_destroy(&mutex1) == 0); assert(pthread_mutex_destroy(&mutex) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar3_2.c0000644000175000000620000001212511512143043020477 0ustar stevestaff/* * File: condvar3_2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test timeout of multiple waits on a CV with remainder broadcast awoken. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Because some CVs are never signaled, we expect their waits to time out. * Some time out, the rest are broadcast signaled. Pthread_cond_destroy() will fail * unless all are accounted for, either signaled or timedout. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait does not return ETIMEDOUT. * - Process returns non-zero exit status. */ #define _WIN32_WINNT 0x400 #include "test.h" #include static pthread_cond_t cv; static pthread_mutex_t mutex; static struct timespec abstime = { 0, 0 }; static struct timespec abstime2 = { 0, 0 }; static int timedout = 0; static int awoken = 0; enum { NUMTHREADS = 30 }; void * mythread(void * arg) { int result; assert(pthread_mutex_lock(&mutex) == 0); abstime2.tv_sec = abstime.tv_sec; if ((int) arg % 3 == 0) { abstime2.tv_sec += 2; } result = pthread_cond_timedwait(&cv, &mutex, &abstime2); assert(pthread_mutex_unlock(&mutex) == 0); if (result == ETIMEDOUT) { InterlockedIncrement((LPLONG)&timedout); } else { InterlockedIncrement((LPLONG)&awoken); } return arg; } #include "../implement.h" int main() { int i; pthread_t t[NUMTHREADS + 1]; int result = 0; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert(pthread_cond_init(&cv, NULL) == 0); assert(pthread_mutex_init(&mutex, NULL) == 0); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = abstime.tv_sec = currSysTime.time + 5; abstime.tv_nsec = abstime2.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; assert(pthread_mutex_lock(&mutex) == 0); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); } assert(pthread_mutex_unlock(&mutex) == 0); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_join(t[i], (void **) &result) == 0); assert(result == i); /* * Approximately 2/3rds of the threads are expected to time out. * Signal the remainder after some threads have woken up and exited * and while some are still waking up after timeout. * Also tests that redundant broadcasts don't return errors. */ // assert(pthread_mutex_lock(&mutex) == 0); if (InterlockedExchangeAdd((LPLONG)&awoken, 0L) > NUMTHREADS/3) { assert(pthread_cond_broadcast(&cv) == 0); } // assert(pthread_mutex_unlock(&mutex) == 0); } assert(awoken == NUMTHREADS - timedout); { int result = pthread_cond_destroy(&cv); if (result != 0) { fprintf(stderr, "Result = %s\n", error_string[result]); fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); fflush(stderr); } assert(result == 0); } assert(pthread_mutex_destroy(&mutex) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/README.BENCHTESTS0000644000175000000620000000412311512143043020713 0ustar stevestaff ------------ Benchmarking ------------ There is a set a benchmarking programs in the "tests" directory. These should be runnable using the following command-lines corresponding to each of the possible library builds: MSVC: nmake clean VC-bench nmake clean VCE-bench nmake clean VSE-bench Mingw32: make clean GC-bench make clean GCE-bench UWIN: The benchtests are run as part of the testsuite. Mutex benchtests ---------------- benchtest1 - Lock plus unlock on an unlocked mutex. benchtest2 - Lock plus unlock on a locked mutex. benchtest3 - Trylock on a locked mutex. benchtest4 - Trylock plus unlock on an unlocked mutex. Each test times up to three alternate synchronisation implementations as a reference, and then times each of the four mutex types provided by the library. Each is described below: Simple Critical Section - uses a simple Win32 critical section. There is no additional overhead for this case as there is in the remaining cases. POSIX mutex implemented using a Critical Section - The old implementation which uses runtime adaptation depending on the Windows variant being run on. When the pthreads DLL was run on WinNT or higher then POSIX mutexes would use Win32 Critical Sections. POSIX mutex implemented using a Win32 Mutex - The old implementation which uses runtime adaptation depending on the Windows variant being run on. When the pthreads DLL was run on Win9x then POSIX mutexes would use Win32 Mutexes (because TryEnterCriticalSection is not implemented on Win9x). PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_RECURSIVE - The current implementation supports these mutex types. The underlying basis of POSIX mutexes is now the same irrespective of the Windows variant, and should therefore have consistent performance. Semaphore benchtests -------------------- benchtest5 - Timing for various uncontended cases. In all benchtests, the operation is repeated a large number of times and an average is calculated. Loop overhead is measured and subtracted from all test times. nyquist-3.05/liblo/pthreads.2/tests/count1.c0000644000175000000620000000505211512143043017751 0ustar stevestaff/* * count1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Description: * Test some basic assertions about the number of threads at runtime. */ #include "test.h" #define NUMTHREADS (30) static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_t threads[NUMTHREADS]; static unsigned numThreads = 0; void * myfunc(void *arg) { pthread_mutex_lock(&lock); numThreads++; pthread_mutex_unlock(&lock); Sleep(1000); return 0; } int main() { int i; int maxThreads = sizeof(threads) / sizeof(pthread_t); /* * Spawn NUMTHREADS threads. Each thread should increment the * numThreads variable, sleep for one second. */ for (i = 0; i < maxThreads; i++) { assert(pthread_create(&threads[i], NULL, myfunc, 0) == 0); } /* * Wait for all the threads to exit. */ for (i = 0; i < maxThreads; i++) { assert(pthread_join(threads[i], NULL) == 0); } /* * Check the number of threads created. */ assert((int) numThreads == maxThreads); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/kill1.c0000644000175000000620000000430311512143043017552 0ustar stevestaff/* * File: kill1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - pthread_kill() does not support non zero signals.. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" int main() { assert(pthread_kill(pthread_self(), 1) == EINVAL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex6es.c0000644000175000000620000000552411512143043020324 0ustar stevestaff/* * mutex6es.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_ERRORCHECK static mutex type. * Thread locks mutex twice (recursive lock). * This should fail with an EDEADLK error. * The second unlock attempt should fail with an EPERM error. * * Depends on API functions: * pthread_create() * pthread_join() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_lock(&mutex) == EDEADLK); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == EPERM); return (void *) 555; } int main() { pthread_t t; int result = 0; assert(mutex == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); assert(pthread_create(&t, NULL, locker, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == 555); assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/join3.c0000644000175000000620000000433011512143043017560 0ustar stevestaff/* * Test for pthread_join() returning return value from threads. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: pthread_create(). */ #include "test.h" void * func(void * arg) { sched_yield(); return arg; } int main(int argc, char * argv[]) { pthread_t id[4]; int i; int result; /* Create a few threads and then exit. */ for (i = 0; i < 4; i++) { assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); } /* * Let threads exit before we join them. * We should still retrieve the exit code for the threads. */ Sleep(1000); for (i = 0; i < 4; i++) { assert(pthread_join(id[i], (void **) &result) == 0); assert(result == i); } /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/priority2.c0000644000175000000620000001165611512143043020512 0ustar stevestaff/* * File: priority2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test thread priority setting after creation. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" enum { PTW32TEST_THREAD_INIT_PRIO = 0, PTW32TEST_MAXPRIORITIES = 512 }; int minPrio; int maxPrio; int validPriorities[PTW32TEST_MAXPRIORITIES]; pthread_barrier_t startBarrier, endBarrier; void * func(void * arg) { int policy; int result; struct sched_param param; result = pthread_barrier_wait(&startBarrier); assert(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD); assert(pthread_getschedparam(pthread_self(), &policy, ¶m) == 0); assert(policy == SCHED_OTHER); result = pthread_barrier_wait(&endBarrier); assert(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD); return (void *) param.sched_priority; } void * getValidPriorities(void * arg) { int prioSet; pthread_t thread = pthread_self(); HANDLE threadH = pthread_getw32threadhandle_np(thread); struct sched_param param; for (prioSet = minPrio; prioSet <= maxPrio; prioSet++) { /* * If prioSet is invalid then the threads priority is unchanged * from the previous value. Make the previous value a known * one so that we can check later. */ param.sched_priority = prioSet; assert(pthread_setschedparam(thread, SCHED_OTHER, ¶m) == 0); validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); } return (void *) 0; } int main() { pthread_t t; void * result = NULL; int result2; struct sched_param param; assert((maxPrio = sched_get_priority_max(SCHED_OTHER)) != -1); assert((minPrio = sched_get_priority_min(SCHED_OTHER)) != -1); assert(pthread_create(&t, NULL, getValidPriorities, NULL) == 0); assert(pthread_join(t, &result) == 0); assert(pthread_barrier_init(&startBarrier, NULL, 2) == 0); assert(pthread_barrier_init(&endBarrier, NULL, 2) == 0); /* Set the thread's priority to a known initial value. * If the new priority is invalid then the threads priority * is unchanged from the previous value. */ SetThreadPriority(pthread_getw32threadhandle_np(pthread_self()), PTW32TEST_THREAD_INIT_PRIO); for (param.sched_priority = minPrio; param.sched_priority <= maxPrio; param.sched_priority++) { assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_setschedparam(t, SCHED_OTHER, ¶m) == 0); result2 = pthread_barrier_wait(&startBarrier); assert(result2 == 0 || result2 == PTHREAD_BARRIER_SERIAL_THREAD); result2 = pthread_barrier_wait(&endBarrier); assert(result2 == 0 || result2 == PTHREAD_BARRIER_SERIAL_THREAD); assert(GetThreadPriority(pthread_getw32threadhandle_np(t)) == validPriorities[param.sched_priority+(PTW32TEST_MAXPRIORITIES/2)]); pthread_join(t, &result); assert(param.sched_priority == (int)result); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/cleanup1.c0000644000175000000620000001273511512143043020256 0ustar stevestaff/* * File: cleanup1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test cleanup handler executes (when thread is canceled). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 10 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t pop_count = {0, {0}}; static void #ifdef __CLEANUP_C __cdecl #endif increment_pop_count(void * arg) { sharedInt_t * sI = (sharedInt_t *) arg; EnterCriticalSection(&sI->cs); sI->i++; LeaveCriticalSection(&sI->cs); } void * mythread(void * arg) { int result = 0; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Set to known state and type */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); /* * We don't have true async cancelation - it relies on the thread * at least re-entering the run state at some point. * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (bag->count = 0; bag->count < 100; bag->count++) Sleep(100); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; InitializeCriticalSection(&pop_count.cs); assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_cancel(t[i]) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; assert(pthread_join(t[i], (void **) &result) == 0); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: result %d\n", i, threadbag[i].started, result); } failed = (failed || fail); } assert(!failed); assert(pop_count.i == NUMTHREADS); DeleteCriticalSection(&pop_count.cs); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ int main() { return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/cleanup2.c0000644000175000000620000001144011512143043020247 0ustar stevestaff/* * File: cleanup2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test cleanup handler executes (when thread is not canceled). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 10 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t pop_count = {0, {0}}; static void increment_pop_count(void * arg) { sharedInt_t * sI = (sharedInt_t *) arg; EnterCriticalSection(&sI->cs); sI->i++; LeaveCriticalSection(&sI->cs); } void * mythread(void * arg) { int result = 0; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); sched_yield(); pthread_cleanup_pop(1); #ifdef _MSC_VER #pragma inline_depth() #endif return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; InitializeCriticalSection(&pop_count.cs); assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(1000); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; assert(pthread_join(t[i], (void **) &result) == 0); fail = (result != 0); if (fail) { fprintf(stderr, "Thread %d: started %d: result: %d\n", i, threadbag[i].started, result); } failed = (failed || fail); } assert(!failed); assert(pop_count.i == NUMTHREADS); DeleteCriticalSection(&pop_count.cs); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ int main() { return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/exception3.c0000644000175000000620000001163511512143043020625 0ustar stevestaff/* * File: exception3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test running of user supplied terminate() function. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #if defined(__cplusplus) #if defined(_MSC_VER) # include #else # if defined(__GNUC__) && __GNUC__ < 3 # include # else # include using std::set_terminate; # endif #endif /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 1 }; int caught = 0; pthread_mutex_t caughtLock; void terminateFunction () { assert(pthread_mutex_lock(&caughtLock) == 0); caught++; #if 1 { FILE * fp = fopen("pthread.log", "a"); fprintf(fp, "Caught = %d\n", caught); fclose(fp); } #endif assert(pthread_mutex_unlock(&caughtLock) == 0); #if defined(__MINGW32__) /* * Seems to work. That is, threads exit and the process * continues. Note: need to check correct POSIX behaviour. * My guess is: this is because of the * eh incompatibility between g++ and MSVC++. That is, * an exception thrown in g++ code doesn't propogate * through or to MSVC++ code, and vice versa. * Applications should probably not depend on this. */ pthread_exit((void *) 0); #else /* * Notes from the MSVC++ manual: * 1) A term_func() should call exit(), otherwise * abort() will be called on return to the caller. * abort() raises SIGABRT. The default signal handler * for all signals terminates the calling program with * exit code 3. * 2) A term_func() must not throw an exception. Therefore * term_func() should not call pthread_exit() if an * an exception-using version of pthreads-win32 library * is being used (i.e. either pthreadVCE or pthreadVSE). */ exit(0); #endif } void * exceptionedThread(void * arg) { int dummy = 0x1; (void) set_terminate(&terminateFunction); throw dummy; return (void *) 0; } int main() { int i; pthread_t mt; pthread_t et[NUMTHREADS]; pthread_mutexattr_t ma; assert((mt = pthread_self()).p != NULL); printf("See the notes inside of exception3.c re term_funcs.\n"); assert(pthread_mutexattr_init(&ma) == 0); assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutex_init(&caughtLock, &ma) == 0); assert(pthread_mutexattr_destroy(&ma) == 0); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0); } Sleep(5000); assert(caught == NUMTHREADS); /* * Success. */ return 0; } #else /* defined(__cplusplus) */ #include int main() { fprintf(stderr, "Test N/A for this compiler environment.\n"); return 0; } #endif /* defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/mutex2.c0000644000175000000620000000411211512143043017760 0ustar stevestaff/* * mutex2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static mutex object, lock it, * and then unlock it again. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int main() { assert(mutex == PTHREAD_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&mutex) == 0); assert(mutex != PTHREAD_MUTEX_INITIALIZER); assert(mutex != NULL); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex1.c0000644000175000000620000000423311512143043017763 0ustar stevestaff/* * mutex1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create a simple mutex object, lock it, and then unlock it again. * This is the simplest test of the pthread mutex family that we can do. * * Depends on API functions: * pthread_mutex_init() * pthread_mutex_lock() * pthread_mutex_unlock() * pthread_mutex_destroy() */ #include "test.h" pthread_mutex_t mutex = NULL; int main() { assert(mutex == NULL); assert(pthread_mutex_init(&mutex, NULL) == 0); assert(mutex != NULL); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar5.c0000644000175000000620000001031011512143043020252 0ustar stevestaff/* * File: condvar5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test pthread_cond_broadcast. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Test broadcast with one waiting CV. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns 0. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns non-zero exit status. */ #include "test.h" #include typedef struct cvthing_t_ cvthing_t; struct cvthing_t_ { pthread_cond_t notbusy; pthread_mutex_t lock; int shared; }; static cvthing_t cvthing = { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }; enum { NUMTHREADS = 2 }; void * mythread(void * arg) { assert(pthread_mutex_lock(&cvthing.lock) == 0); cvthing.shared++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); return (void *) 0; } int main() { pthread_t t[NUMTHREADS]; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; cvthing.shared = 0; assert((t[0] = pthread_self()).p != NULL); assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&cvthing.lock) == 0); assert(cvthing.lock != PTHREAD_MUTEX_INITIALIZER); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT); assert(cvthing.notbusy != PTHREAD_COND_INITIALIZER); assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); assert(cvthing.shared > 0); assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_join(t[1], NULL) == 0); assert(pthread_mutex_destroy(&cvthing.lock) == 0); assert(cvthing.lock == NULL); assert(pthread_cond_destroy(&cvthing.notbusy) == 0); assert(cvthing.notbusy == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/ChangeLog0000644000175000000620000006526711512143043020164 0ustar stevestaff2005-06-12 Ross Johnson * stress1.c (millisecondsFromNow): Remove limit 0 <= millisecs < 1000; now works for -INT_MAX <= millisecs <= INT_MAX; not needed for stress1.c but should be general anyway. 2005-05-18 Ross Johnson * reuse2.c (main): Must use a read with memory barrier semantics when polling 'done' to force the cache into coherence on MP systems. 2005-05-15 Ross Johnson * detach1.c: New test. * join1.c: Reduce sleep times. * join0.c: Remove MSVCRT conditional compile - join should always return the thread exit code. * join1.c: Likewise. * join2.c: Likewise. * join3.c: Likewise. 2005-04-18 Ross Johnson * condvar3.c: Remove locks from around signalling calls - should not be required for normal operation and only serve to mask deficiencies; ensure that CV destruction is not premature after removing guards. * condvar3_1.c: Likewise. * condvar3_2.c: Likewise. * condvar3_3.c: Likewise. * condvar4.c: Likewise. * condvar5.c: Likewise. * condvar6.c: Likewise. * condvar7.c: Likewise. * condvar8.c: Likewise. * condvar9.c: Likewise. 2005-04-11 Ross Johnson * once4.c: New test; tries to test priority adjustments in pthread_once(); set priority class to realtime so that any failures can be seen. 2005-04-06 Ross Johnson * cleanup0.c: Fix unguarded global variable accesses. * cleanup1.c: Likewise. * cleanup2.c: Likewise. * cleanup3.c: Likewise. * once2.c: Likewise. * once3.c: Likewise. 2005-04-01 Ross Johnson * GNUmakefile: Add target to test linking static link library. * Makefile: Likewise. * self1.c: Run process attach/detach routines when static linked. 2005-03-16 Ross Johnson * mutex5.c: Prevent optimiser from removing asserts. 2005-03-12 Ross Johnson * once3.c: New test. 2005-03-08 Ross Johnson * once2.c: New test. 2004-11-19 Ross Johnson * Bmakefile: New makefile for Borland. * Makefile (DLL_VER): Added. * GNUmakefile (DLL_VER): Added. * Wmakefile (DLL_VER): Added. 2004-10-29 Ross Johnson * semaphore4.c: New test. * semaphore4t.c: New test. * Debug.dsp (et al): Created MSVC Workspace project to aid debugging. * All: Many tests have been modified to work with the new pthread ID type; some other corrections were made after some library functions were semantically strengthened. For example, pthread_cond_destroy() no longer destroys a busy CV, which required minor redesigns of some tests, including some where the mutex associated with the CV was not locked during signaling and broadcasting. 2004-10-23 Ross Johnson * condvar3.c: Fixed mutex operations that were incorrectly placed in relation to their condition variable operations. The error became evident after sem_destroy() was rewritten and conditions for destroing the semaphore were tightened. As a result, pthread_cond_destroy() was not able to destroy the cv queueing sempahore. * condvar3_1.c: Likewise. * condvar3_2.c: Likewise. * condvar4.c: Likewise. * condvar5.c: Likewise. * condvar6.c: Likewise. * condvar7.c: Likewise. * condvar8.c: Likewise. * condvar9.c: Likewise. 2004-10-19 Ross Johnson * semaphore3.c: New test. 2004-10-14 Ross Johnson * rwlock7.c (main): Tidy up statistics reporting; randomise update accesses. * rwlock8.c: New test. 2004-09-08 Alexandre Girao * cancel7.c (main): Win98 wants a valid (non-NULL) location for the last arg of _beginthreadex(). * cancel8.c (main): Likewise. * exit4.c (main): Likewise. * exit5.c (main): Likewise. 2004-08-26 Ross Johnson * create3.c: New test. 2004-06-21 Ross Johnson * mutex2r.c: New test. * mutex2e.c: New test. * mutex3r.c: New test. * mutex3e.c: New test. * mutex6s.c: New test. * mutex6rs.c: New test. * mutex6es.c: New test. 2004-05-21 Ross Johnson * join3.c: New test. 2004-05-16 Ross Johnson * condvar2.c (WIN32_WINNT): Define to avoid redefinition warning from inclusion of implement.h. * convar2_1.c: Likewise. * condvar3_1.c: Likewise. * condvar3_2.c: Likewise. * context1.c: Likewise. * sizes.c: Likewise. * Makefile: Don't define _WIN32_WINNT on compiler command line. * GNUmakefile: Likewise. * priority1.c (main): Add column to output for actual win32 priority. 2004-05-16 Ross Johnson * cancel9.c: New test. * cancel3.c: Remove inappropriate conditional compilation; GNU C version of test suite no longer quietly skips this test. * cancel5.c: Likewise. * GNUmakefile: Can now build individual test app using default C version of library using 'make clean testname.c'. * Makefile: Likewise for VC using 'nmake clean test testname.c'. 2003-10-14 Ross Johnson * Wmakefile: New makefile for Watcom testing. 2003-09-18 Ross Johnson * benchtest.h: Move old mutex code into benchlib.c. * benchlib.c: New statically linked module to ensure that bench apps don't inline the code and therefore have an unfair advantage over the pthreads lib routines. Made little or no difference. * benchtest1.c: Minor change to avoid compiler warnings. * benchtest5.c: Likewise. * benchtest2.c: Fix misinformation in output report. * README.BENCH: Add comments on results. 2003-09-14 Ross Johnson * priority1.c: Reworked to comply with modified priority management and provide additional output. * priority2.c: Likewise. * inherit1.c: Likewise. 2003-09-03 Ross Johnson * exit4.c: New test. * exit5.c: New test. * cancel7.c: New test. * cancel8.c: New test. 2003-08-13 Ross Johnson * reuse1.c: New test. * reuse1.c: New test. * valid1.c: New test. * valid2.c: New test. * kill1.c: New test. * create2.c: Now included in test regime. 2003-07-19 Ross Johnson * eyal1.c (waste_time): Make threads do more work to ensure that all threads get to do some work. * semaphore1.c: Make it clear that certain errors are expected. * exception2.c (non_MSVC code sections): Change to include C++ standard include file, i.e. change to . * exception3.c (non_MSVC code sections): Likewise; qualify std:: namespace entities where necessary. * GNUmakefile: modified to work in the MsysDTK (newer MinGW) environment; define CC as gcc or g++ as appropriate because using gcc -x c++ doesn't link with required c++ libs by default, but g++ does. 2002-12-11 Ross Johnson * mutex7e.c: Assert EBUSY return instead of EDEADLK. 2002-06-03 Ross Johnson * semaphore2.c: New test. 2002-03-02 Ross Johnson * Makefile (CFLAGS): Changed /MT to /MD to link with the correct library MSVCRT.LIB. Otherwise errno doesn't work. 2002-02-28 Ross Johnson * exception3.c: Correct recent change. * semaphore1.c: New test. * Makefile: Add rule to generate pre-processor output. 2002-02-28 Ross Johnson * exception3.c (terminateFunction): For MSVC++, call exit() rather than pthread_exit(). Add comments to explain why. * Notes from the MSVC++ manual: * 1) A term_func() should call exit(), otherwise * abort() will be called on return to the caller. * abort() raises SIGABRT. The default signal handler * for all signals terminates the calling program with * exit code 3. * 2) A term_func() must not throw an exception. Therefore * term_func() should not call pthread_exit() if an * an exception-using version of pthreads-win32 library * is being used (i.e. either pthreadVCE or pthreadVSE). 2002-02-23 Ross Johnson * rwlock2_t.c: New test. * rwlock3_t.c: New test. * rwlock4_t.c: New test. * rwlock5_t.c: New test. * rwlock6_t.c: New test. * rwlock6_t2.c: New test. * rwlock6.c (main): Swap thread and result variables to correspond to actual thread functions. * rwlock1.c: Change test description comment to correspond to the actual test. * condvar1_2.c: Loop over the test many times in the hope of detecting any intermittent deadlocks. This is to test a fixed problem in pthread_cond_destroy.c. * spin4.c: Remove unused variable. 2002-02-17 Ross Johnson * condvar1_1.c: New test. * condvar1_2.c: New test. 2002-02-07 Ross Johnson * delay1.c: New test. * delay2.c: New test. * exit4.c: New test. 2002-02-02 Ross Johnson * mutex8: New test. * mutex8n: New test. * mutex8e: New test. * mutex8r: New test. * cancel6a: New test. * cancel6d: New test. * cleanup0.c: Add pragmas for inline optimisation control. * cleanup1.c: Add pragmas for inline optimisation control. * cleanup2.c: Add pragmas for inline optimisation control. * cleanup3.c: Add pragmas for inline optimisation control. * condvar7.c: Add pragmas for inline optimisation control. * condvar8.c: Add pragmas for inline optimisation control. * condvar9.c: Add pragmas for inline optimisation control. 2002-01-30 Ross Johnson * cleanup1.c (): Must be declared __cdecl when compiled as C++ AND testing the standard C library version. 2002-01-16 Ross Johnson * spin4.c (main): Fix renamed function call. 2002-01-14 Ross Johnson * exception3.c (main): Shorten wait time. 2002-01-09 Ross Johnson * mutex7.c: New test. * mutex7n.c: New test. * mutex7e.c: New test. * mutex7r.c: New test. * mutex6.c: Modified to avoid leaving the locked mutex around on exit. 2001-10-25 Ross Johnson * condvar2.c: Remove reference to cv->nWaitersUnblocked. * condvar2_1.c: Likewise; lower NUMTHREADS from 60 to 30. * condvar3_1.c: Likewise. * condvar3_2.c: Likewise. * count1.c: lower NUMTHREADS from 60 to 30. * inherit1.c: Determine valid priority values and then assert values returned by POSIX routines are the same. * priority1.c: Likewise. * priority2.c: Likewise. 2001-07-12 Ross Johnson * barrier5.c: Assert that precisely one thread receives PTHREAD_BARRIER_SERIAL_THREAD at each barrier. 2001-07-09 Ross Johnson * barrier3.c: Fixed. * barrier4.c: Fixed. * barrier5.c: New; proves that all threads in the group reaching the barrier wait and then resume together. Repeats the test using groups of 1 to 16 threads. Each group of threads must negotiate a large number of barriers (10000). * spin4.c: Fixed. * test.h (error_string): Modified the success (0) value. 2001-07-07 Ross Johnson * spin3.c: Changed test and fixed. * spin4.c: Fixed. * barrier3.c: Fixed. * barrier4.c: Fixed. 2001-07-05 Ross Johnson * spin1.c: New; testing spinlocks. * spin2.c: New; testing spinlocks. * spin3.c: New; testing spinlocks. * spin4.c: New; testing spinlocks. * barrier1.c: New; testing barriers. * barrier2.c: New; testing barriers. * barrier3.c: New; testing barriers. * barrier4.c: New; testing barriers. * GNUmakefile: Add new tests. * Makefile: Add new tests. 2001-07-01 Ross Johnson * benchtest3.c: New; timing mutexes. * benchtest4.c: New; time mutexes. * condvar3_1.c: Fixed bug - Alexander Terekhov * condvar3_3.c: New test. 2001-06-25 Ross Johnson * priority1.c: New test. * priority2.c: New test. * inherit1.c: New test. * benchtest1.c: New; timing mutexes. * benchtest2.c: New; timing mutexes. * mutex4.c: Modified to test all mutex types. 2001-06-8 Ross Johnson * mutex5.c: Insert inert change to quell compiler warnings. * condvar3_2.c: Remove unused variable. 2001-06-3 Ross Johnson * condvar2_1.c: New test. * condvar3_1.c: New test. * condvar3_2.c: New test. 2001-05-30 Ross Johnson * mutex1n.c: New test. * mutex1e.c: New test. * mutex1r.c: New test. * mutex4.c: Now locks and unlocks a mutex. * mutex5.c: New test. * mutex6.c: New test. * mutex6n.c: New test. * mutex6e.c: New test. * mutex6r.c: New test. * Makefile: Added new tests; reorganised. * GNUmakefile: Likewise. * rwlock6.c: Fix to properly prove read-while-write locking and single writer locking. 2001-05-29 Ross Johnson * Makefile: Reorganisation. * GNUmakefile: Likewise. - Thomas Pfaff * exception1.c: Add stdio.h include to define fprintf and stderr in non-exception C version of main(). * exception2.c: Likewise. * exception3.c: Likewise. * Makefile (rwlock7): Add new test. * GNUmakefile (rwlock7): Add new test. * rwlock7.c: New test. * rwlock6.c: Changed to test that writer has priority. * eyal1.c (main): Unlock each mutex_start lock before destroying it. 2000-12-29 Ross Johnson * GNUmakefile: Add mutex4 test; ensure libpthreadw32.a is removed for "clean" target. * Makefile: Add mutex4 test. * exception3.c: Remove SEH code; automatically pass the test under SEH (which is an N/A environment). * mutex4.c: New test. * eyal1.c (do_work_unit): Add a dummy "if" to force the optimiser to retain code; reduce thread work loads. * condvar8.c (main): Add an additional "assert" for debugging; increase pthread_cond_signal timeout. 2000-12-28 Ross Johnson * eyal1.c: Increase thread work loads. * exception2.c: New test. * exception3.c: New test. * Makefile: Add new tests exception2.c and exception3.c. * GNUmakefile: Likewise. 2000-12-11 Ross Johnson * cleanup3.c: Remove unused variable. * cleanup2.c: Likewise. * exception1.c: Throw an exception rather than use a deliberate zero divide so that catch(...) will handle it under Mingw32. Mingw32 now builds the library correctly to pass all tests - see Thomas Pfaff's detailed instructions re needed changes to Mingw32 in the Pthreads-Win32 FAQ. 2000-09-08 Ross Johnson * cancel5.c: New; tests calling pthread_cancel() from the main thread without first creating a POSIX thread struct for the non-POSIX main thread - this forces pthread_cancel() to create one via pthread_self(). * Makefile (cancel5): Add new test. * GNUmakefile (cancel5): Likewise. 2000-08-17 Ross Johnson * create2.c: New; Test that pthread_t contains the W32 HANDLE before it calls the thread routine proper. 2000-08-13 Ross Johnson * condvar3.c: Minor change to eliminate compiler warning. * condvar4.c: ditto. * condvar5.c: ditto. * condvar6.c: ditto. * condvar7.c: ditto. * condvar8.c: ditto. * condvar9.c: ditto. * exit1.c: Function needed return statement. * cleanup1.c: Remove unnecessary printf arg. * cleanup2.c: Fix cast. * rwlock6.c: Fix casts. * exception1.c (PtW32CatchAll): Had the wrong name; fix casts. * cancel3.c: Remove unused waitLock variable. * GNUmakefile: Change library/dll naming; add new tests; general minor changes. * Makefile: Change library/dll naming; add targets for testing each of the two VC++ EH scheme versions; default target now issues help message; compile warnings now interpreted as errors to stop the make; add new tests; restructure to remove prerequisites needed otherwise. * README: Updated. 2000-08-10 Ross Johnson * eyal1.c (main): Change implicit cast to explicit cast when passing "print_server" function pointer; G++ no longer allows implicit func parameter casts. * cleanup1.c: Remove unused "waitLock". (main): Fix implicit parameter cast. * cancel2.c (main): Fix implicit parameter cast. * cancel4.c (main): Fix implicit parameter cast. * cancel3.c (main): Fix implicit parameter cast. * GNUmakefile: Renamed from Makefile; Add missing cancel1 and cancel2 test targets. * Makefile: Converted for use with MS nmake. 2000-08-06 Ross Johnson * ccl.bat: Add /nologo to remove extraneous output. * exception1.c (exceptionedThread): Init 'dummy'; put expression into if condition to prevent optimising away; remove unused variable. * cancel4.c (mythread): Cast return value to avoid warnings. * cancel2.c (mythread): Missing #endif. * condvar9.c (mythread): Cast return value to avoid warnings. * condvar8.c (mythread): Cast return value to avoid warnings. * condvar7.c (mythread): Cast return value to avoid warnings. * cleanup3.c (mythread): Cast return value to avoid warnings. * cleanup2.c (mythread): Cast return value to avoid warnings. * cleanup1.c (mythread): Cast return value to avoid warnings. * condvar5.c (mythread): Cast return value to avoid warnings. * condvar3.c (mythread): Cast return value to avoid warnings. * condvar6.c (mythread): Cast return value to avoid warnings. * condvar4.c (mythread): Cast return value to avoid warnings. 2000-08-05 Ross Johnson * cancel2.c: Use PtW32CatchAll macro if defined. * exception1.c: Use PtW32CatchAll macro if defined. 2000-08-02 Ross Johnson * tsd1.c: Fix typecasts of &result [g++ is now very fussy]. * test.h (assert): Return 0's explicitly to allay g++ errors. * join2.c: Add explicit typecasts. * join1.c: Add explicit typecasts. * join0.c: Add explicit typecasts. * eyal1.c: Add explicit typecasts. * count1.c (main): Add type cast to remove g++ parse warning [gcc-2.95.2 seems to have tightened up on this]. * Makefile (GLANG): Use c++ explicitly. Remove MSVC sections (was commented out). Add target to generate cpp output. 2000-07-25 Ross Johnson * runtest.bat: modified to work under W98. * runall.bat: Add new tests; modified to work under W98. It was ok under NT. * Makefile: Add new tests. * exception1.c: New; Test passing exceptions back to the application and retaining library internal exceptions. * join0.c: New; Test a single join. 2000-01-06 Ross Johnson * cleanup1.c: New; Test cleanup handler executes (when thread is canceled). * cleanup2.c: New; Test cleanup handler executes (when thread is not canceled). * cleanup3.c: New; Test cleanup handler does not execute (when thread is not canceled). 2000-01-04 Ross Johnson * cancel4.c: New; Test cancelation does not occur in deferred cancelation threads with no cancelation points. * cancel3.c: New; Test asynchronous cancelation. * context1.c: New; Test context switching method for async cancelation. 1999-11-23 Ross Johnson * test.h: Add header includes; include local header versions rather than system versions; rearrange the assert macro defines. 1999-11-07 Ross Johnson * loadfree.c: New. Test loading and freeing the library (DLL). 1999-10-30 Ross Johnson * cancel1.c: New. Test pthread_setcancelstate and pthread_setcanceltype functions. * eyal1.c (waste_time): Change calculation to avoid FP exception on Aplhas - Rich Peters Oct 14 1999 Ross Johnson * condvar7.c: New. Test broadcast after waiting thread is canceled. * condvar8.c: New. Test multiple broadcasts. * condvar9.c: New. Test multiple broadcasts with thread cancelation. Sep 16 1999 Ross Johnson * rwlock6.c: New test. Sep 15 1999 Ross Johnson * rwlock1.c: New test. * rwlock2.c: New test. * rwlock3.c: New test. * rwlock4.c: New test. * rwlock5.c: New test. Aug 22 1999 Ross Johnson * runall.bat (join2): Add test. Aug 19 1999 Ross Johnson * join2.c: New test. Wed Aug 12 1999 Ross Johnson * Makefile (LIBS): Add -L. Mon May 31 10:25:01 1999 Ross Johnson * Makefile (GLANG): Add GCC language option. Sat May 29 23:29:04 1999 Ross Johnson * runall.bat (condvar5): Add new test. * runall.bat (condvar6): Add new test. * Makefile (condvar5) : Add new test. * Makefile (condvar6) : Add new test. * condvar5.c: New test for pthread_cond_broadcast(). * condvar6.c: New test for pthread_cond_broadcast(). Sun Apr 4 12:04:28 1999 Ross Johnson * tsd1.c (mythread): Change Sleep(0) to sched_yield(). (sched.h): Include. * condvar3.c (mythread): Remove redundant Sleep(). * runtest.bat: Re-organised to make more informative. Fri Mar 19 1999 Ross Johnson * *.bat: redirect unwanted output to nul: * runall.bat: new. * cancel1.c: new. Not part of suite yet. Mon Mar 15 00:17:55 1999 Ross Johnson * mutex1.c: only test mutex init and destroy; add assertions. * count1.c: raise number of spawned threads to 60 (appears to be the limit under Win98). Sun Mar 14 21:31:02 1999 Ross Johnson * test.h (assert): add assertion trace option. Use: "#define ASSERT_TRACE 1" to turn it on, "#define ASSERT_TRACE 0" to turn it off (default). * condvar3.c (main): add more assertions. * condvar4.c (main): add more assertions. * condvar1.c (main): add more assertions. Fri Mar 12 08:34:15 1999 Ross Johnson * condvar4.c (cvthing): switch the order of the INITIALIZERs. * eyal1.c (main): Fix trylock loop; was not waiting for thread to lock the "started" mutex. Wed Mar 10 10:41:52 1999 Ross Johnson * tryentercs.c: Apply typo patch from bje. * tryentercs2.c: Ditto. Sun Mar 7 10:41:52 1999 Ross Johnson * Makefile (condvar3, condvar4): Add tests. * condvar4.c (General): Reduce to simple test case; prerequisite is condvar3.c; add description. * condvar3.c (General): Reduce to simple test case; prerequisite is condvar2.c; add description. * condvar2.c (General): Reduce to simple test case; prerequisite is condvar1.c; add description. * condvar1.c (General): Reduce to simple test case; add description. * Template.c (Comments): Add generic test detail. 1999-02-23 Ross Johnson * Template.c: Revamp. * condvar1.c: Add. * condvar2.c: Add. * Makefile: Add condvar1 condvar2 tests. * exit1.c, exit2.c, exit3.c: Cosmetic changes. 1999-02-23 Ross Johnson * Makefile: Some refinement. * *.c: More exhaustive checking through assertions; clean up; add some more tests. * Makefile: Now actually runs the tests. * tests.h: Define our own assert macro. The Mingw32 version pops up a dialog but we want to run non-interactively. * equal1.c: use assert a little more directly so that it prints the actual call statement. * exit1.c: Modify to return 0 on success, 1 on failure. 1999-02-22 Ross Johnson * self2.c: Bring up to date. * self3.c: Ditto. 1999-02-21 Ben Elliston * README: Update. * Makefile: New file. Run all tests automatically. Primitive tests are run first; more complex tests are run last. * count1.c: New test. Validate the thread count. * exit2.c: Perform a simpler test. * exit3.c: New test. Replaces exit2.c, since exit2.c needs to perform simpler checking first. * create1.c: Update to use the new testsuite exiting convention. * equal1.c: Likewise. * mutex1.c: Likewise. * mutex2.c: Likewise. * once1.c: Likewise. * self2.c: Likewise. * self3.c: Likewise. * tsd1.c: Likewise. 1999-02-20 Ross Johnson * mutex2.c: Test static mutex initialisation. * test.h: New. Declares a table mapping error numbers to error names. 1999-01-17 Ross Johnson * runtest: New script to build and run a test in the tests directory. Wed Dec 30 11:22:44 1998 Ross Johnson * tsd1.c: Re-written. See comments at start of file. * Template.c: New. Contains skeleton code and comment template intended to fully document the test. Fri Oct 16 17:59:49 1998 Ross Johnson * tsd1.c (destroy_key): Add function. Change diagnostics. Thu Oct 15 17:42:37 1998 Ross Johnson * tsd1.c (mythread): Fix some casts and add some message output. Fix inverted conditional. Mon Oct 12 02:12:29 1998 Ross Johnson * tsd1.c: New. Test TSD using 1 key and 2 threads. 1998-09-13 Ben Elliston * eyal1.c: New file; contributed by Eyal Lebedinsky . 1998-09-12 Ben Elliston * exit2.c (func): Return a value. (main): Call the right thread entry function. 1998-07-22 Ben Elliston * exit2.c (main): Fix size of pthread_t array. 1998-07-10 Ben Elliston * exit2.c: New file; test pthread_exit() harder. * exit1.c: New file; test pthread_exit(). nyquist-3.05/liblo/pthreads.2/tests/mutex5.c0000644000175000000620000000474011512143043017772 0ustar stevestaff/* * mutex5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Confirm the equality/inequality of the various mutex types, * and the default not-set value. */ #include "test.h" static pthread_mutexattr_t mxAttr; /* Prevent optimiser from removing dead or obvious asserts. */ int _optimiseFoil; #define FOIL(x) (_optimiseFoil = x) int main() { int mxType = -1; assert(FOIL(PTHREAD_MUTEX_DEFAULT) == PTHREAD_MUTEX_NORMAL); assert(FOIL(PTHREAD_MUTEX_DEFAULT) != PTHREAD_MUTEX_ERRORCHECK); assert(FOIL(PTHREAD_MUTEX_DEFAULT) != PTHREAD_MUTEX_RECURSIVE); assert(FOIL(PTHREAD_MUTEX_RECURSIVE) != PTHREAD_MUTEX_ERRORCHECK); assert(FOIL(PTHREAD_MUTEX_NORMAL) == PTHREAD_MUTEX_FAST_NP); assert(FOIL(PTHREAD_MUTEX_RECURSIVE) == PTHREAD_MUTEX_RECURSIVE_NP); assert(FOIL(PTHREAD_MUTEX_ERRORCHECK) == PTHREAD_MUTEX_ERRORCHECK_NP); assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/spin2.c0000644000175000000620000000425411512143043017576 0ustar stevestaff/* * spin2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a spinlock object, lock it, trylock it, * and then unlock it again. * */ #include "test.h" pthread_spinlock_t lock = NULL; static int washere = 0; void * func(void * arg) { assert(pthread_spin_trylock(&lock) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_spin_lock(&lock) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_spin_unlock(&lock) == 0); assert(pthread_spin_destroy(&lock) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchtest5.c0000644000175000000620000001105211512143043020601 0ustar stevestaff/* * benchtest5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Measure time taken to complete an elementary operation. * * - Semaphore * Single thread iteration over post/wait for a semaphore. */ #include "test.h" #include #ifdef __GNUC__ #include #endif #include "benchtest.h" #define ITERATIONS 1000000L sem_t sema; HANDLE w32sema; struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; long durationMilliSecs; long overHeadMilliSecs = 0; int one = 1; int zero = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) /* * Dummy use of j, otherwise the loop may be removed by the optimiser * when doing the overhead timing with an empty loop. */ #define TESTSTART \ { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; #define TESTSTOP \ }; _ftime(&currSysTimeStop); if (j + k == i) j++; } void reportTest (char * testNameString) { durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); } int main (int argc, char *argv[]) { printf( "=============================================================================\n"); printf( "\nOperations on a semaphore.\n%ld iterations\n\n", ITERATIONS); printf( "%-45s %15s %15s\n", "Test", "Total(msec)", "average(usec)"); printf( "-----------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ TESTSTART assert(1 == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; overHeadMilliSecs = durationMilliSecs; /* * Now we can start the actual tests */ assert((w32sema = CreateSemaphore(NULL, (long) 0, (long) ITERATIONS, NULL)) != 0); TESTSTART assert(ReleaseSemaphore(w32sema, 1, NULL) != zero); TESTSTOP assert(CloseHandle(w32sema) != 0); reportTest("W32 Post with no waiters"); assert((w32sema = CreateSemaphore(NULL, (long) ITERATIONS, (long) ITERATIONS, NULL)) != 0); TESTSTART assert(WaitForSingleObject(w32sema, INFINITE) == WAIT_OBJECT_0); TESTSTOP assert(CloseHandle(w32sema) != 0); reportTest("W32 Wait without blocking"); assert(sem_init(&sema, 0, 0) == 0); TESTSTART assert(sem_post(&sema) == zero); TESTSTOP assert(sem_destroy(&sema) == 0); reportTest("POSIX Post with no waiters"); assert(sem_init(&sema, 0, ITERATIONS) == 0); TESTSTART assert(sem_wait(&sema) == zero); TESTSTOP assert(sem_destroy(&sema) == 0); reportTest("POSIX Wait without blocking"); printf( "=============================================================================\n"); /* * End of tests. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel5.c0000644000175000000620000001140411512143043020050 0ustar stevestaff/* * File: cancel5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test calling pthread_cancel from the main thread * without calling pthread_self() in main. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; void * mythread (void *arg) { int result = ((int) PTHREAD_CANCELED + 1); bag_t *bag = (bag_t *) arg; assert (bag == &threadbag[bag->threadnum]); assert (bag->started == 0); bag->started = 1; /* Set to known state and type */ assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) == 0); assert (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); /* * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (bag->count = 0; bag->count < 100; bag->count++) Sleep (100); return (void *) result; } int main () { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert (pthread_create (&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep (500); for (i = 1; i <= NUMTHREADS; i++) { assert (pthread_cancel (t[i]) == 0); } /* * Give threads time to run. */ Sleep (NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf (stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert (!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; /* * The thread does not contain any cancelation points, so * a return value of PTHREAD_CANCELED confirms that async * cancelation succeeded. */ assert (pthread_join (t[i], (void **) &result) == 0); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf (stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert (!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/sizes.vse0000644000175000000620000000137511512143043020254 0ustar stevestaffSizes of pthreads-win32 structs ------------------------------- pthread_t 8 ptw32_thread_t 76 pthread_attr_t_ 28 sem_t_ 12 pthread_mutex_t_ 24 pthread_mutexattr_t_ 8 pthread_spinlock_t_ 8 pthread_barrier_t_ 24 pthread_barrierattr_t_ 4 pthread_key_t_ 16 pthread_cond_t_ 32 pthread_condattr_t_ 4 pthread_rwlock_t_ 28 pthread_rwlockattr_t_ 4 pthread_once_t_ 16 ptw32_cleanup_t 12 ptw32_mcs_node_t_ 16 sched_param 4 ------------------------------- nyquist-3.05/liblo/pthreads.2/tests/join1.c0000644000175000000620000000440211512143043017556 0ustar stevestaff/* * Test for pthread_join(). * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: pthread_create(), pthread_join(), pthread_exit(). */ #include "test.h" void * func(void * arg) { int i = (int) arg; Sleep(i * 100); pthread_exit(arg); /* Never reached. */ exit(1); } int main(int argc, char * argv[]) { pthread_t id[4]; int i; int result; /* Create a few threads and then exit. */ for (i = 0; i < 4; i++) { assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); } /* Some threads will finish before they are joined, some after. */ Sleep(2 * 100 + 50); for (i = 0; i < 4; i++) { assert(pthread_join(id[i], (void **) &result) == 0); assert(result == i); } /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/sizes.gc0000644000175000000620000000137511512143043020050 0ustar stevestaffSizes of pthreads-win32 structs ------------------------------- pthread_t 8 ptw32_thread_t 140 pthread_attr_t_ 28 sem_t_ 12 pthread_mutex_t_ 24 pthread_mutexattr_t_ 8 pthread_spinlock_t_ 8 pthread_barrier_t_ 24 pthread_barrierattr_t_ 4 pthread_key_t_ 16 pthread_cond_t_ 32 pthread_condattr_t_ 4 pthread_rwlock_t_ 28 pthread_rwlockattr_t_ 4 pthread_once_t_ 16 ptw32_cleanup_t 12 ptw32_mcs_node_t_ 16 sched_param 4 ------------------------------- nyquist-3.05/liblo/pthreads.2/tests/condvar9.c0000644000175000000620000001444511512143043020273 0ustar stevestaff/* * File: condvar9.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test multiple pthread_cond_broadcasts with thread cancelation. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Make NUMTHREADS threads wait on CV, cancel one, broadcast signal them, * and then repeat. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #include /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 9 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; int finished; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct cvthing_t_ cvthing_t; struct cvthing_t_ { pthread_cond_t notbusy; pthread_mutex_t lock; int shared; }; static cvthing_t cvthing = { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }; static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; static struct timespec abstime = { 0, 0 }; static int awoken; static void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Wait for the start gun */ assert(pthread_mutex_lock(&start_flag) == 0); assert(pthread_mutex_unlock(&start_flag) == 0); assert(pthread_mutex_lock(&cvthing.lock) == 0); /* * pthread_cond_timedwait is a cancelation point and we're * going to cancel some threads deliberately. */ #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif assert(cvthing.shared > 0); awoken++; bag->finished = 1; assert(pthread_mutex_unlock(&cvthing.lock) == 0); return (void *) 0; } int main() { int failed = 0; int i; int first, last; int canceledThreads = 0; pthread_t t[NUMTHREADS + 1]; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert((t[0] = pthread_self()).p != NULL); assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; assert((t[0] = pthread_self()).p != NULL); awoken = 0; for (first = 1, last = NUMTHREADS / 2; first < NUMTHREADS; first = last + 1, last = NUMTHREADS) { int ct; assert(pthread_mutex_lock(&start_flag) == 0); for (i = first; i <= last; i++) { threadbag[i].started = threadbag[i].finished = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ cvthing.shared = 0; assert(pthread_mutex_unlock(&start_flag) == 0); /* * Give threads time to start. */ Sleep(1000); ct = (first + last) / 2; assert(pthread_cancel(t[ct]) == 0); canceledThreads++; assert(pthread_join(t[ct], NULL) == 0); assert(pthread_mutex_lock(&cvthing.lock) == 0); cvthing.shared++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); /* * Standard check that all threads started - and wait for them to finish. */ for (i = first; i <= last; i++) { failed = !threadbag[i].started; if (failed) { fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } else { assert(pthread_join(t[i], NULL) == 0 || threadbag[i].finished == 0); // fprintf(stderr, "Thread %d: finished %d\n", i, threadbag[i].finished); } } } /* * Cleanup the CV. */ assert(pthread_mutex_destroy(&cvthing.lock) == 0); assert(cvthing.lock == NULL); assert_e(pthread_cond_destroy(&cvthing.notbusy), ==, 0); assert(cvthing.notbusy == NULL); assert(!failed); /* * Check any results here. */ assert(awoken == NUMTHREADS - canceledThreads); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex6n.c0000644000175000000620000000572511512143043020155 0ustar stevestaff/* * mutex6n.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_NORMAL mutex type. * Thread locks mutex twice (recursive lock). * The thread should deadlock. * * Depends on API functions: * pthread_create() * pthread_mutexattr_init() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; /* Should wait here (deadlocked) */ assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); return (void *) 555; } int main() { pthread_t t; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(1000); assert(lockCount == 1); /* * Should succeed even though we don't own the lock * because FAST mutexes don't check ownership. */ assert(pthread_mutex_unlock(&mutex) == 0); Sleep (1000); assert(lockCount == 2); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel6d.c0000644000175000000620000001037711512143043020225 0ustar stevestaff/* * File: cancel6d.c * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 Ben Elliston and Ross Johnson * Copyright (C) 1999,2000,2001 Ross Johnson * * Contact Email: rpj@ise.canberra.edu.au * * 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.1 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 * * -------------------------------------------------------------------------- * * Test Synopsis: Test double cancelation - deferred. * Second attempt should succeed (unless the canceled thread has started * cancelation already - not tested here). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; void * mythread(void * arg) { int result = ((int)PTHREAD_CANCELED + 1); bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Set to known state and type */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); /* * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (bag->count = 0; bag->count < 100; bag->count++) { Sleep(100); pthread_testcancel(); } return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_cancel(t[i]) == 0); assert(pthread_cancel(t[i]) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; assert(pthread_join(t[i], (void **) &result) == 0); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/tsd1.c0000644000175000000620000001224411512143043017414 0ustar stevestaff/* * tsd1.c * * Test Thread Specific Data (TSD) key creation and destruction. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * * -------------------------------------------------------------------------- * * Description: * - * * Test Method (validation or falsification): * - validation * * Requirements Tested: * - keys are created for each existing thread including the main thread * - keys are created for newly created threads * - keys are thread specific * - destroy routine is called on each thread exit including the main thread * * Features Tested: * - * * Cases Tested: * - * * Environment: * - * * Input: * - none * * Output: * - text to stdout * * Assumptions: * - already validated: pthread_create() * pthread_once() * - main thread also has a POSIX thread identity * * Pass Criteria: * - stdout matches file reference/tsd1.out * * Fail Criteria: * - fails to match file reference/tsd1.out * - output identifies failed component */ #include #include "test.h" enum { NUM_THREADS = 100 }; static pthread_key_t key = NULL; static int accesscount[NUM_THREADS]; static int thread_set[NUM_THREADS]; static int thread_destroyed[NUM_THREADS]; static pthread_barrier_t startBarrier; static void destroy_key(void * arg) { int * j = (int *) arg; (*j)++; assert(*j == 2); thread_destroyed[j - accesscount] = 1; } static void setkey(void * arg) { int * j = (int *) arg; thread_set[j - accesscount] = 1; assert(*j == 0); assert(pthread_getspecific(key) == NULL); assert(pthread_setspecific(key, arg) == 0); assert(pthread_setspecific(key, arg) == 0); assert(pthread_setspecific(key, arg) == 0); assert(pthread_getspecific(key) == arg); (*j)++; assert(*j == 1); } static void * mythread(void * arg) { (void) pthread_barrier_wait(&startBarrier); setkey(arg); return 0; /* Exiting the thread will call the key destructor. */ } int main() { int i; int fail = 0; pthread_t thread[NUM_THREADS]; assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0); for (i = 1; i < NUM_THREADS/2; i++) { accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); } /* * Here we test that existing threads will get a key created * for them. */ assert(pthread_key_create(&key, destroy_key) == 0); (void) pthread_barrier_wait(&startBarrier); /* * Test main thread key. */ accesscount[0] = 0; setkey((void *) &accesscount[0]); /* * Here we test that new threads will get a key created * for them. */ for (i = NUM_THREADS/2; i < NUM_THREADS; i++) { accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); } /* * Wait for all threads to complete. */ for (i = 1; i < NUM_THREADS; i++) { int result = 0; assert(pthread_join(thread[i], (void **) &result) == 0); } assert(pthread_key_delete(key) == 0); assert(pthread_barrier_destroy(&startBarrier) == 0); for (i = 1; i < NUM_THREADS; i++) { /* * The counter is incremented once when the key is set to * a value, and again when the key is destroyed. If the key * doesn't get set for some reason then it will still be * NULL and the destroy function will not be called, and * hence accesscount will not equal 2. */ if (accesscount[i] != 2) { fail++; fprintf(stderr, "Thread %d key, set = %d, destroyed = %d\n", i, thread_set[i], thread_destroyed[i]); } } fflush(stderr); return (fail); } nyquist-3.05/liblo/pthreads.2/tests/mutex3e.c0000644000175000000620000000432511512143043020134 0ustar stevestaff/* * mutex3e.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static mutex object, lock it, trylock it, * and then unlock it again. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" pthread_mutex_t mutex1 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_mutex_trylock(&mutex1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_mutex_lock(&mutex1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar8.c0000644000175000000620000001347711512143043020276 0ustar stevestaff/* * File: condvar8.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test multiple pthread_cond_broadcasts. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Make NUMTHREADS threads wait on CV, broadcast signal them, and then repeat. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #include /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 5 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct cvthing_t_ cvthing_t; struct cvthing_t_ { pthread_cond_t notbusy; pthread_mutex_t lock; int shared; }; static cvthing_t cvthing = { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }; static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; static struct timespec abstime = { 0, 0 }; static int awoken; static void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Wait for the start gun */ assert(pthread_mutex_lock(&start_flag) == 0); assert(pthread_mutex_unlock(&start_flag) == 0); assert(pthread_mutex_lock(&cvthing.lock) == 0); #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif assert(cvthing.shared > 0); awoken++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); return (void *) 0; } int main() { int failed = 0; int i; int first, last; pthread_t t[NUMTHREADS + 1]; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert((t[0] = pthread_self()).p != NULL); assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 10; assert((t[0] = pthread_self()).p != NULL); awoken = 0; for (first = 1, last = NUMTHREADS / 2; first < NUMTHREADS; first = last + 1, last = NUMTHREADS) { assert(pthread_mutex_lock(&start_flag) == 0); for (i = first; i <= last; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ cvthing.shared = 0; assert(pthread_mutex_unlock(&start_flag) == 0); /* * Give threads time to start. */ Sleep(100); assert(pthread_mutex_lock(&cvthing.lock) == 0); cvthing.shared++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); /* * Give threads time to complete. */ for (i = first; i <= last; i++) { assert(pthread_join(t[i], NULL) == 0); } assert(awoken == (i - 1)); } /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { failed = !threadbag[i].started; if (failed) { fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } /* * Cleanup the CV. */ assert(pthread_mutex_destroy(&cvthing.lock) == 0); assert(cvthing.lock == NULL); assert(pthread_cond_destroy(&cvthing.notbusy) == 0); assert(cvthing.notbusy == NULL); assert(!failed); /* * Check any results here. */ assert(awoken == NUMTHREADS); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/exit4.c0000644000175000000620000001126511512143043017600 0ustar stevestaff/* * File: exit4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test calling pthread_exit from a Win32 thread * without having created an implicit POSIX handle for it. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #ifndef _UWIN #include #endif /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; #if ! defined (__MINGW32__) || defined (__MSVCRT__) unsigned __stdcall #else void #endif Win32thread(void * arg) { int result = 1; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* * Doesn't return and doesn't create an implicit POSIX handle. */ pthread_exit((void *) result); return 0; } int main() { int failed = 0; int i; HANDLE h[NUMTHREADS + 1]; unsigned thrAddr; /* Dummy variable to pass a valid location to _beginthreadex (Win98). */ for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; #if ! defined (__MINGW32__) || defined (__MSVCRT__) h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, &thrAddr); #else h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]); #endif } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; #if ! defined (__MINGW32__) || defined (__MSVCRT__) assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE); #else /* * Can't get a result code. */ result = 1; #endif fail = (result != 1); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar1_1.c0000644000175000000620000000601311512143043020473 0ustar stevestaff/* * File: condvar1_1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test CV linked list management. * * Test Method (Validation or Falsification): * - Validation: * Initiate and destroy several CVs in random order. * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Creates and then imediately destroys a CV. Does not * test the CV. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - All initialised CVs destroyed without segfault. * - Successfully broadcasts all remaining CVs after * each CV is removed. * * Fail Criteria: */ #include #include "test.h" enum { NUM_CV = 100 }; static pthread_cond_t cv[NUM_CV]; int main() { int i, j; for (i = 0; i < NUM_CV; i++) { /* Traverse the list before every init of a CV. */ assert(pthread_timechange_handler_np(NULL) == (void *) 0); assert(pthread_cond_init(&cv[i], NULL) == 0); } j = NUM_CV; (void) srand((unsigned)time(NULL)); do { i = (NUM_CV - 1) * rand() / RAND_MAX; if (cv[i] != NULL) { j--; assert(pthread_cond_destroy(&cv[i]) == 0); /* Traverse the list every time we remove a CV. */ assert(pthread_timechange_handler_np(NULL) == (void *) 0); } } while (j > 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock4_t.c0000644000175000000620000000502311512143043020446 0ustar stevestaff/* * rwlock4_t.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, timed-rdlock it, trywrlock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_timedrdlock() * pthread_rwlock_trywrlock() * pthread_rwlock_unlock() */ #include "test.h" #include pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); Sleep(2000); assert(pthread_rwlock_unlock(&rwlock1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/once4.c0000644000175000000620000001307611512143043017555 0ustar stevestaff/* * once4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create several pthread_once objects and channel several threads * through each. Make the init_routine cancelable and cancel them * waiters waiting. Vary the priorities. * * Depends on API functions: * pthread_once() * pthread_create() * pthread_testcancel() * pthread_cancel() * pthread_once() */ #include "test.h" #define NUM_THREADS 100 /* Targeting each once control */ #define NUM_ONCE 10 pthread_once_t o = PTHREAD_ONCE_INIT; pthread_once_t once[NUM_ONCE]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t numOnce = {0, {0}}; static sharedInt_t numThreads = {0, {0}}; typedef struct { int threadnum; int oncenum; int myPrio; HANDLE w32Thread; } bag_t; static bag_t threadbag[NUM_THREADS][NUM_ONCE]; CRITICAL_SECTION print_lock; void mycleanupfunc(void * arg) { bag_t * bag = (bag_t *) arg; EnterCriticalSection(&print_lock); /* once thrd prio error */ printf("%4d %4d %4d %4d\n", bag->oncenum, bag->threadnum, bag->myPrio, bag->myPrio - GetThreadPriority(bag->w32Thread)); LeaveCriticalSection(&print_lock); } void myinitfunc(void) { EnterCriticalSection(&numOnce.cs); numOnce.i++; LeaveCriticalSection(&numOnce.cs); /* Simulate slow once routine so that following threads pile up behind it */ Sleep(10); /* test for cancelation late so we're sure to have waiters. */ pthread_testcancel(); } void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; struct sched_param param; /* * Cancel every thread. These threads are deferred cancelable only, so * only the thread performing the init_routine will see it (there are * no other cancelation points here). The result will be that every thread * eventually cancels only when it becomes the new initter. */ pthread_t self = pthread_self(); bag->w32Thread = pthread_getw32threadhandle_np(self); /* * Set priority between -2 and 2 inclusive. */ bag->myPrio = (bag->threadnum % 5) - 2; param.sched_priority = bag->myPrio; pthread_setschedparam(self, SCHED_OTHER, ¶m); /* Trigger a cancellation at the next cancellation point in this thread */ pthread_cancel(self); #if 0 pthread_cleanup_push(mycleanupfunc, arg); assert(pthread_once(&once[bag->oncenum], myinitfunc) == 0); pthread_cleanup_pop(1); #else assert(pthread_once(&once[bag->oncenum], myinitfunc) == 0); #endif EnterCriticalSection(&numThreads.cs); numThreads.i++; LeaveCriticalSection(&numThreads.cs); return 0; } int main() { pthread_t t[NUM_THREADS][NUM_ONCE]; int i, j; InitializeCriticalSection(&print_lock); InitializeCriticalSection(&numThreads.cs); InitializeCriticalSection(&numOnce.cs); #if 0 /* once thrd prio change */ printf("once thrd prio error\n"); #endif /* * Set the priority class to realtime - otherwise normal * Windows random priority boosting will obscure any problems. */ SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); /* Set main thread to lower prio than threads */ SetThreadPriority(GetCurrentThread(), -2); for (j = 0; j < NUM_ONCE; j++) { once[j] = o; for (i = 0; i < NUM_THREADS; i++) { bag_t * bag = &threadbag[i][j]; bag->threadnum = i; bag->oncenum = j; assert(pthread_create(&t[i][j], NULL, mythread, (void *) bag) == 0); } } for (j = 0; j < NUM_ONCE; j++) for (i = 0; i < NUM_THREADS; i++) if (pthread_join(t[i][j], NULL) != 0) printf("Join failed for [thread,once] = [%d,%d]\n", i, j); /* * All threads will cancel, none will return normally from * pthread_once and so numThreads should never be incremented. However, * numOnce should be incremented by every thread (NUM_THREADS*NUM_ONCE). */ assert(numOnce.i == NUM_ONCE * NUM_THREADS); assert(numThreads.i == 0); DeleteCriticalSection(&numOnce.cs); DeleteCriticalSection(&numThreads.cs); DeleteCriticalSection(&print_lock); return 0; } nyquist-3.05/liblo/pthreads.2/tests/semaphore5.c0000644000175000000620000000501111512143043020603 0ustar stevestaff/* * File: semaphore5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Verify sem_destroy EBUSY race avoidance * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ // #define ASSERT_TRACE #include "test.h" void * thr(void * arg) { assert(sem_post((sem_t *)arg) == 0); return 0; } int main() { pthread_t t; sem_t s; assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); assert(pthread_create(&t, NULL, thr, (void *)&s) == 0); assert(sem_wait(&s) == 0); assert(sem_destroy(&s) == 0); assert(pthread_join(t, NULL) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar1.c0000644000175000000620000000512011512143043020251 0ustar stevestaff/* * File: condvar1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test initialisation and destruction of a CV. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Creates and then imediately destroys a CV. Does not * test the CV. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_init returns 0, and * - pthread_cond_destroy returns 0. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_init returns non-zero, or * - pthread_cond_destroy returns non-zero. * - Process returns non-zero exit status. */ #include "test.h" static pthread_cond_t cv = NULL; int main() { assert(cv == NULL); assert(pthread_cond_init(&cv, NULL) == 0); assert(cv != NULL); assert(pthread_cond_destroy(&cv) == 0); assert(cv == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex7.c0000644000175000000620000000467511512143043020003 0ustar stevestaff/* * mutex7.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test the default (type not set) mutex type. * Should be the same as PTHREAD_MUTEX_NORMAL. * Thread locks then trylocks mutex (attempted recursive lock). * The thread should lock first time and EBUSY second time. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == EPERM); return 0; } int main() { pthread_t t; assert(pthread_mutex_init(&mutex, NULL) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(1000); assert(lockCount == 2); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/errno1.c0000644000175000000620000000756511512143043017761 0ustar stevestaff/* * File: errno1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test thread-safety of errno * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 3 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; pthread_mutex_t stop_here = PTHREAD_MUTEX_INITIALIZER; void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; errno = bag->threadnum; Sleep(1000); pthread_mutex_lock(&stop_here); assert(errno == bag->threadnum); pthread_mutex_unlock(&stop_here); Sleep(1000); return 0; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; pthread_mutex_lock(&stop_here); errno = 0; assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(2000); pthread_mutex_unlock(&stop_here); /* * Give threads time to run. */ Sleep(NUMTHREADS * 1000); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { failed = !threadbag[i].started; if (failed) { fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print ouput on failure. */ for (i = 1; i <= NUMTHREADS; i++) { /* ... */ } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel4.c0000644000175000000620000001143611512143043020054 0ustar stevestaff/* * File: cancel4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test cancelation does not occur in deferred * cancelation threads with no cancelation points. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - pthread_create * pthread_self * pthread_cancel * pthread_join * pthread_setcancelstate * pthread_setcanceltype * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; void * mythread(void * arg) { int result = ((int)PTHREAD_CANCELED + 1); bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Set to known state and type */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); /* * We wait up to 2 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (bag->count = 0; bag->count < 20; bag->count++) Sleep(100); return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_cancel(t[i]) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; /* * The thread does not contain any cancelation points, so * a return value of PTHREAD_CANCELED indicates that async * cancelation occurred. */ assert(pthread_join(t[i], (void **) &result) == 0); fail = (result == (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/sizes.c0000644000175000000620000000314411512143043017675 0ustar stevestaff#define _WIN32_WINNT 0x400 #include "test.h" #include "../implement.h" int main() { printf("Sizes of pthreads-win32 structs\n"); printf("-------------------------------\n"); printf("%30s %4d\n", "pthread_t", sizeof(pthread_t)); printf("%30s %4d\n", "ptw32_thread_t", sizeof(ptw32_thread_t)); printf("%30s %4d\n", "pthread_attr_t_", sizeof(struct pthread_attr_t_)); printf("%30s %4d\n", "sem_t_", sizeof(struct sem_t_)); printf("%30s %4d\n", "pthread_mutex_t_", sizeof(struct pthread_mutex_t_)); printf("%30s %4d\n", "pthread_mutexattr_t_", sizeof(struct pthread_mutexattr_t_)); printf("%30s %4d\n", "pthread_spinlock_t_", sizeof(struct pthread_spinlock_t_)); printf("%30s %4d\n", "pthread_barrier_t_", sizeof(struct pthread_barrier_t_)); printf("%30s %4d\n", "pthread_barrierattr_t_", sizeof(struct pthread_barrierattr_t_)); printf("%30s %4d\n", "pthread_key_t_", sizeof(struct pthread_key_t_)); printf("%30s %4d\n", "pthread_cond_t_", sizeof(struct pthread_cond_t_)); printf("%30s %4d\n", "pthread_condattr_t_", sizeof(struct pthread_condattr_t_)); printf("%30s %4d\n", "pthread_rwlock_t_", sizeof(struct pthread_rwlock_t_)); printf("%30s %4d\n", "pthread_rwlockattr_t_", sizeof(struct pthread_rwlockattr_t_)); printf("%30s %4d\n", "pthread_once_t_", sizeof(struct pthread_once_t_)); printf("%30s %4d\n", "ptw32_cleanup_t", sizeof(struct ptw32_cleanup_t)); printf("%30s %4d\n", "ptw32_mcs_node_t_", sizeof(struct ptw32_mcs_node_t_)); printf("%30s %4d\n", "sched_param", sizeof(struct sched_param)); printf("-------------------------------\n"); return 0; } nyquist-3.05/liblo/pthreads.2/tests/create1.c0000644000175000000620000000372611512143043020072 0ustar stevestaff/* * create1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Description: * Create a thread and check that it ran. * * Depends on API functions: None. */ #include "test.h" static int washere = 0; void * func(void * arg) { washere = 1; return 0; } int main() { pthread_t t; assert(pthread_create(&t, NULL, func, NULL) == 0); /* A dirty hack, but we cannot rely on pthread_join in this primitive test. */ Sleep(2000); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/once2.c0000644000175000000620000000621311512143043017546 0ustar stevestaff/* * once2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Create several static pthread_once objects and channel several threads * through each. * * Depends on API functions: * pthread_once() * pthread_create() */ #include "test.h" #define NUM_THREADS 100 /* Targeting each once control */ #define NUM_ONCE 10 pthread_once_t o = PTHREAD_ONCE_INIT; pthread_once_t once[NUM_ONCE]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t numOnce = {0, {0}}; static sharedInt_t numThreads = {0, {0}}; void myfunc(void) { EnterCriticalSection(&numOnce.cs); numOnce.i++; LeaveCriticalSection(&numOnce.cs); /* Simulate slow once routine so that following threads pile up behind it */ Sleep(100); } void * mythread(void * arg) { assert(pthread_once(&once[(int) arg], myfunc) == 0); EnterCriticalSection(&numThreads.cs); numThreads.i++; LeaveCriticalSection(&numThreads.cs); return 0; } int main() { pthread_t t[NUM_THREADS][NUM_ONCE]; int i, j; InitializeCriticalSection(&numThreads.cs); InitializeCriticalSection(&numOnce.cs); for (j = 0; j < NUM_ONCE; j++) { once[j] = o; for (i = 0; i < NUM_THREADS; i++) assert(pthread_create(&t[i][j], NULL, mythread, (void *) j) == 0); } for (j = 0; j < NUM_ONCE; j++) for (i = 0; i < NUM_THREADS; i++) if (pthread_join(t[i][j], NULL) != 0) printf("Join failed for [thread,once] = [%d,%d]\n", i, j); assert(numOnce.i == NUM_ONCE); assert(numThreads.i == NUM_THREADS * NUM_ONCE); DeleteCriticalSection(&numOnce.cs); DeleteCriticalSection(&numThreads.cs); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex6e.c0000644000175000000620000000617111512143043020140 0ustar stevestaff/* * mutex6e.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_ERRORCHECK mutex type. * Thread locks mutex twice (recursive lock). * This should fail with an EDEADLK error. * The second unlock attempt should fail with an EPERM error. * * Depends on API functions: * pthread_create() * pthread_join() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_lock(&mutex) == EDEADLK); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == EPERM); return (void *) 555; } int main() { pthread_t t; int result = 0; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_ERRORCHECK); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == 555); assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); assert(pthread_mutexattr_destroy(&mxAttr) == 0); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/semaphore4t.c0000644000175000000620000000661411512143043021000 0ustar stevestaff/* * File: semaphore4t.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Verify sem_getvalue returns the correct number of waiters * after threads are cancelled. * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - sem_timedwait cancellation. * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #define MAX_COUNT 100 sem_t s; void * thr (void * arg) { assert(sem_timedwait(&s, NULL) == 0); return NULL; } int main() { int value = 0; int i; pthread_t t[MAX_COUNT+1]; assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %d\n", value); fflush(stdout); assert(value == 0); for (i = 1; i <= MAX_COUNT; i++) { assert(pthread_create(&t[i], NULL, thr, NULL) == 0); do { sched_yield(); assert(sem_getvalue(&s, &value) == 0); } while (value != -i); // printf("Value = %d\n", value); fflush(stdout); assert(-value == i); } assert(sem_getvalue(&s, &value) == 0); assert(-value == MAX_COUNT); assert(pthread_cancel(t[50]) == 0); assert(pthread_join(t[50], NULL) == 0); assert(sem_getvalue(&s, &value) == 0); assert(-value == MAX_COUNT - 1); for (i = MAX_COUNT - 2; i >= 0; i--) { assert(sem_post(&s) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %d\n", value); fflush(stdout); assert(-value == i); } for (i = 1; i <= MAX_COUNT; i++) if (i != 50) assert(pthread_join(t[i], NULL) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/detach1.c0000644000175000000620000000511311512143043020047 0ustar stevestaff/* * Test for pthread_detach(). * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: pthread_create(), pthread_detach(), pthread_exit(). */ #include "test.h" enum { NUMTHREADS = 100 }; void * func(void * arg) { int i = (int) arg; Sleep(i * 10); pthread_exit(arg); /* Never reached. */ exit(1); } int main(int argc, char * argv[]) { pthread_t id[NUMTHREADS]; int i; /* Create a few threads and then exit. */ for (i = 0; i < NUMTHREADS; i++) { assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); } /* Some threads will finish before they are detached, some after. */ Sleep(NUMTHREADS/2 * 10 + 50); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_detach(id[i]) == 0); } Sleep(NUMTHREADS * 10 + 100); /* * Check that all threads are now invalid. * This relies on unique thread IDs - e.g. works with * pthreads-w32 or Solaris, but may not work for Linux, BSD etc. */ for (i = 0; i < NUMTHREADS; i++) { assert(pthread_kill(id[i], 0) == ESRCH); } /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/semaphore2.c0000644000175000000620000000540211512143043020604 0ustar stevestaff/* * File: semaphore2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Verify sem_getvalue returns the correct value. * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #define MAX_COUNT 100 int main() { sem_t s; int value = 0; int i; assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, MAX_COUNT) == 0); assert(sem_getvalue(&s, &value) == 0); assert(value == MAX_COUNT); // printf("Value = %ld\n", value); for (i = MAX_COUNT - 1; i >= 0; i--) { assert(sem_wait(&s) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %ld\n", value); assert(value == i); } for (i = 1; i <= MAX_COUNT; i++) { assert(sem_post(&s) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %ld\n", value); assert(value == i); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar3.c0000644000175000000620000000752611512143043020267 0ustar stevestaff/* * File: condvar3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test basic function of a CV * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - The primary thread takes the lock before creating any threads. * The secondary thread blocks on the lock allowing the primary * thread to enter the cv wait state which releases the lock. * The secondary thread then takes the lock and signals the waiting * primary thread. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns 0. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns non-zero exit status. */ #include "test.h" #include static pthread_cond_t cv; static pthread_mutex_t mutex; static int shared = 0; enum { NUMTHREADS = 2 /* Including the primary thread. */ }; void * mythread(void * arg) { int result = 0; assert(pthread_mutex_lock(&mutex) == 0); shared++; assert(pthread_mutex_unlock(&mutex) == 0); if ((result = pthread_cond_signal(&cv)) != 0) { printf("Error = %s\n", error_string[result]); } assert(result == 0); return (void *) 0; } int main() { pthread_t t[NUMTHREADS]; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert((t[0] = pthread_self()).p != NULL); assert(pthread_cond_init(&cv, NULL) == 0); assert(pthread_mutex_init(&mutex, NULL) == 0); assert(pthread_mutex_lock(&mutex) == 0); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); abstime.tv_sec += 5; while (! (shared > 0)) assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == 0); assert(shared > 0); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_join(t[1], NULL) == 0); assert(pthread_cond_destroy(&cv) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/test.h0000644000175000000620000000732011512143043017524 0ustar stevestaff/* * test.h * * Useful definitions and declarations for tests. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * */ #ifndef _PTHREAD_TEST_H_ #define _PTHREAD_TEST_H_ #include "pthread.h" #include "sched.h" #include "semaphore.h" #include #include #define PTW32_THREAD_NULL_ID {NULL,0} #if defined(__MINGW32__) #include #elif defined(__BORLANDC__) #define int64_t ULONGLONG #else #define int64_t _int64 #endif char * error_string[] = { "ZERO_or_EOK", "EPERM", "ENOFILE_or_ENOENT", "ESRCH", "EINTR", "EIO", "ENXIO", "E2BIG", "ENOEXEC", "EBADF", "ECHILD", "EAGAIN", "ENOMEM", "EACCES", "EFAULT", "UNKNOWN_15", "EBUSY", "EEXIST", "EXDEV", "ENODEV", "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", "ENOTTY", "UNKNOWN_26", "EFBIG", "ENOSPC", "ESPIPE", "EROFS", "EMLINK", "EPIPE", "EDOM", "ERANGE", "UNKNOWN_35", "EDEADLOCK_or_EDEADLK", "UNKNOWN_37", "ENAMETOOLONG", "ENOLCK", "ENOSYS", "ENOTEMPTY", "EILSEQ", }; /* * The Mingw32 assert macro calls the CRTDLL _assert function * which pops up a dialog. We want to run in batch mode so * we define our own assert macro. */ #ifdef assert # undef assert #endif #ifndef ASSERT_TRACE # define ASSERT_TRACE 0 #else # undef ASSERT_TRACE # define ASSERT_TRACE 1 #endif # define assert(e) \ ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \ "Assertion succeeded: (%s), file %s, line %d\n", \ #e, __FILE__, (int) __LINE__), \ fflush(stderr) : \ 0) : \ (fprintf(stderr, "Assertion failed: (%s), file %s, line %d\n", \ #e, __FILE__, (int) __LINE__), exit(1), 0)) int assertE; # define assert_e(e, o, r) \ (((assertE = e) o (r)) ? ((ASSERT_TRACE) ? fprintf(stderr, \ "Assertion succeeded: (%s), file %s, line %d\n", \ #e, __FILE__, (int) __LINE__), \ fflush(stderr) : \ 0) : \ (fprintf(stderr, "Assertion failed: (%s %s %s), file %s, line %d, error %s\n", \ #e,#o,#r, __FILE__, (int) __LINE__, error_string[assertE]), exit(1), 0)) #endif nyquist-3.05/liblo/pthreads.2/tests/spin4.c0000644000175000000620000000566711512143043017611 0ustar stevestaff/* * spin4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static spinlock object, lock it, spin on it, * and then unlock it again. */ #include "test.h" #include pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER; struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) static int washere = 0; void * func(void * arg) { _ftime(&currSysTimeStart); washere = 1; assert(pthread_spin_lock(&lock) == 0); assert(pthread_spin_unlock(&lock) == 0); _ftime(&currSysTimeStop); return (void *) GetDurationMilliSecs(currSysTimeStart, currSysTimeStop); } int main() { long result = 0; pthread_t t; int CPUs; struct _timeb sysTime; if ((CPUs = pthread_num_processors_np()) == 1) { printf("Test not run - it requires multiple CPUs.\n"); exit(0); } assert(pthread_spin_lock(&lock) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); while (washere == 0) { sched_yield(); } do { sched_yield(); _ftime(&sysTime); } while (GetDurationMilliSecs(currSysTimeStart, sysTime) <= 1000); assert(pthread_spin_unlock(&lock) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result > 1000); assert(pthread_spin_destroy(&lock) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/exit1.c0000644000175000000620000000335511512143043017576 0ustar stevestaff/* * Test for pthread_exit(). * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: None. */ #include "test.h" int main(int argc, char * argv[]) { /* A simple test first. */ pthread_exit((void *) 0); /* Not reached */ assert(0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mkdir/0002755000175000000620000000000011537433130017510 5ustar stevestaffnyquist-3.05/liblo/pthreads.2/tests/Makefile0000644000175000000620000003147411512143043020043 0ustar stevestaff# Makefile for the pthreads test suite. # If all of the .pass files can be created, the test suite has passed. # # -------------------------------------------------------------------------- # # Pthreads-win32 - POSIX Threads Library for Win32 # Copyright(C) 1998 John E. Bossom # Copyright(C) 1999,2005 Pthreads-win32 contributors # # Contact Email: rpj@callisto.canberra.edu.au # # The current list of contributors is contained # in the file CONTRIBUTORS included with the source # code distribution. The list can also be seen at the # following World Wide Web location: # http://sources.redhat.com/pthreads-win32/contributors.html # # 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 in the file COPYING.LIB; # if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # DLL_VER = 2 CP = copy RM = erase CAT = type MKDIR = mkdir TOUCH = echo Passed > ECHO = @echo QAPC = ..\QueueUserAPCEx\User\quserex.dll CPHDR = pthread.h semaphore.h sched.h OPTIM = /O2 /Ob0 XXLIBS = ws2_32.lib # C++ Exceptions VCEFLAGS = /GX /TP /DPtW32NoCatchWarn /D__CLEANUP_CXX VCELIB = pthreadVCE$(DLL_VER).lib VCEDLL = pthreadVCE$(DLL_VER).dll # Structured Exceptions VSEFLAGS = /D__CLEANUP_SEH VSELIB = pthreadVSE$(DLL_VER).lib VSEDLL = pthreadVSE$(DLL_VER).dll # C cleanup code VCFLAGS = /D__CLEANUP_C VCLIB = pthreadVC$(DLL_VER).lib VCDLL = pthreadVC$(DLL_VER).dll # C++ Exceptions in application - using VC version of pthreads dll VCXFLAGS = /GX /TP /D__CLEANUP_C # Defaults CPLIB = $(VCLIB) CPDLL = $(VCDLL) CFLAGS= $(OPTIM) /W3 /WX /MD /nologo /Yd /Zi LFLAGS= /INCREMENTAL:NO INCLUDES=-I. BUILD_DIR=.. COPYFILES = $(CPHDR) $(CPLIB) $(CPDLL) $(QAPC) TEST = EHFLAGS = # If a test case returns a non-zero exit code to the shell, make will # stop. PASSES= sizes.pass loadfree.pass \ self1.pass mutex5.pass \ mutex1.pass mutex1n.pass mutex1e.pass mutex1r.pass \ semaphore1.pass semaphore2.pass semaphore3.pass \ mutex2.pass mutex3.pass \ mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass \ condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \ exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \ kill1.pass valid1.pass valid2.pass \ exit2.pass exit3.pass exit4.pass exit5.pass \ join0.pass join1.pass detach1.pass join2.pass join3.pass \ mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass \ mutex6s.pass mutex6es.pass mutex6rs.pass \ mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \ mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \ count1.pass \ once1.pass once2.pass once3.pass once4.pass \ self2.pass \ cancel1.pass cancel2.pass \ semaphore4.pass semaphore4t.pass semaphore5.pass \ barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \ tsd1.pass tsd2.pass delay1.pass delay2.pass eyal1.pass \ condvar3.pass condvar3_1.pass condvar3_2.pass condvar3_3.pass \ condvar4.pass condvar5.pass condvar6.pass \ condvar7.pass condvar8.pass condvar9.pass \ errno1.pass \ rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass \ rwlock5.pass rwlock6.pass rwlock7.pass rwlock8.pass \ rwlock2_t.pass rwlock3_t.pass rwlock4_t.pass rwlock5_t.pass rwlock6_t.pass rwlock6_t2.pass \ context1.pass \ cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass \ cancel7.pass cancel8.pass \ cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \ priority1.pass priority2.pass inherit1.pass \ spin1.pass spin2.pass spin3.pass spin4.pass \ exception1.pass exception2.pass exception3.pass \ cancel9.pass create3.pass stress1.pass BENCHRESULTS = \ benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench STRESSRESULTS = \ stress1.stress STATICRESULTS = \ self1.pass help: @ $(ECHO) Run one of the following command lines: @ $(ECHO) nmake clean VC (to test using VC dll with VC (no EH) apps) @ $(ECHO) nmake clean VC-bench (to benchtest using VC dll with C bench apps) @ $(ECHO) nmake clean VC-stress (to stresstest using VC dll with C stress apps) @ $(ECHO) nmake clean VC-static (to test using VC static lib with VC (no EH) apps) @ $(ECHO) nmake clean VCX (to test using VC dll with VC++ (EH) applications) @ $(ECHO) nmake clean VCX-bench (to benchtest using VC dll with C++ bench apps) @ $(ECHO) nmake clean VCX-stress (to stresstest using VC dll with C++ stress apps) @ $(ECHO) nmake clean VCE (to test using the VCE dll with VC++ EH applications) @ $(ECHO) nmake clean VCE-bench (to benchtest using VCE dll with C++ bench apps) @ $(ECHO) nmake clean VCE-stress (to stresstest using VCE dll with C++ stress apps) @ $(ECHO) nmake clean VSE (to test using VSE dll with VC (SEH) apps) @ $(ECHO) nmake clean VSE-bench (to benchtest using VSE dll with SEH bench apps) @ $(ECHO) nmake clean VSE-stress (to stresstest using VSE dll with SEH stress apps) all: @ nmake clean VC @ nmake clean VCX @ nmake clean VCE @ nmake clean VSE @ nmake clean VC-bench @ nmake clean VC-stress # This allows an individual test application to be made using the default lib. # e.g. nmake clean test cancel3.exe test: $(CPLIB) $(CPDLL) $(CPHDR) $(QAPC) tests: $(CPLIB) $(CPDLL) $(CPHDR) $(QAPC) $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(XXLIBS) $(BENCHRESULTS) @ $(ECHO) ALL BENCH TESTS DONE. stresstests: $(CPLIB) $(CPDLL) $(CPHDR) $(STRESSRESULTS) @ $(ECHO) ALL STRESS TESTS DONE. statictests: $(CPLIB) $(CPDLL) $(CPHDR) $(STATICRESULTS) @ $(ECHO) ALL STATIC TESTS DONE. @ $(ECHO) Build and test the DLL to run all tests. @ $(ECHO) The static test only confirms that the .lib links correctly. sizes.pass: sizes.exe @ $(ECHO) ... Running $(TEST)$(DLL_VER) test: $*.exe @ .\$*.exe > SIZES.$(TEST) @ $(CAT) SIZES.$(TEST) @ $(ECHO) ...... Passed @ $(TOUCH) $*.pass $(PASSES): $*.exe @ $(ECHO) ... Running $(TEST) test: $*.exe @ .\$*.exe @ $(ECHO) ...... Passed @ $(TOUCH) $*.pass $(BENCHRESULTS): $*.exe @ $(ECHO) ... Running $(TEST) benchtest: $*.exe @ .\$*.exe @ $(ECHO) ...... Done @ $(TOUCH) $*.bench $(STRESSRESULTS): $*.exe @ $(ECHO) ... Running $(TEST) stresstest: $*.exe @ .\$*.exe @ $(ECHO) ...... Done @ $(TOUCH) $*.pass VC: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" tests VCE: @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" tests VSE: @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" tests VCX: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" tests VC-bench: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" XXLIBS="benchlib.o" benchtests VCE-bench: @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" XXLIBS="benchlib.o" benchtests VSE-bench: @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" XXLIBS="benchlib.o" benchtests VCX-bench: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" XXLIBS="benchlib.o" benchtests VC-stress: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" stresstests VCE-stress: @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" stresstests VSE-stress: @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" stresstests VCX-stress: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" stresstests VC-static: @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="" EHFLAGS="$(VCFLAGS) /DPTW32_STATIC_LIB" statictests .c.exe: @ $(ECHO) $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) $(XXLIBS) @ $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< /Fe$@ /link $(LFLAGS) $(CPLIB) $(XXLIBS) .c.o: @ $(ECHO) $(CC) $(EHFLAGS) /c $(CFLAGS) $(INCLUDES) $< /Fo$@ @ $(CC) $(EHFLAGS) $(CFLAGS) /c $(INCLUDES) $< /Fo$@ .c.i: @ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< $(COPYFILES): @ $(ECHO) Copying $@ @ $(CP) $(BUILD_DIR)\$@ . pthread.dll: $(CPDLL) @ $(CP) $(CPDLL) pthread.dll @ $(CP) $(CPLIB) pthread.lib clean: - $(RM) *.dll - $(RM) *.lib - $(RM) pthread.h - $(RM) semaphore.h - $(RM) sched.h - $(RM) *.e - $(RM) *.i - $(RM) *.obj - $(RM) *.pdb - $(RM) *.o - $(RM) *.asm - $(RM) *.exe - $(RM) *.pass - $(RM) *.bench - $(RM) *.log benchtest1.bench: benchtest2.bench: benchtest3.bench: benchtest4.bench: benchtest5.bench: barrier1.pass: semaphore4.pass barrier2.pass: barrier1.pass barrier3.pass: barrier2.pass barrier4.pass: barrier3.pass barrier5.pass: barrier4.pass cancel1.pass: create1.pass cancel2.pass: cancel1.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass cancel5.pass: cancel3.pass cancel6a.pass: cancel3.pass cancel6d.pass: cancel3.pass cancel7.pass: kill1.pass cancel8.pass: cancel7.pass cancel9.pass: cancel8.pass cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass condvar1.pass: condvar1_1.pass: condvar1.pass condvar1_2.pass: join2.pass condvar2.pass: condvar1.pass condvar2_1.pass: condvar2.pass join2.pass condvar3.pass: create1.pass condvar2.pass condvar3_1.pass: condvar3.pass join2.pass condvar3_2.pass: condvar3_1.pass condvar3_3.pass: condvar3_2.pass condvar4.pass: create1.pass condvar5.pass: condvar4.pass condvar6.pass: condvar5.pass condvar7.pass: condvar6.pass cleanup1.pass condvar8.pass: condvar7.pass condvar9.pass: condvar8.pass context1.pass: cancel2.pass count1.pass: join1.pass create1.pass: mutex2.pass create2.pass: create1.pass create3.pass: delay1.pass: delay2.pass: delay1.pass detach1.pass: join0.pass equal1.pass: create1.pass errno1.pass: mutex3.pass exception1.pass: cancel4.pass exception2.pass: exception1.pass exception3.pass: exception2.pass exit1.pass: exit2.pass: create1.pass exit3.pass: create1.pass exit4.pass: exit5.pass: kill1.pass eyal1.pass: tsd1.pass inherit1.pass: join1.pass priority1.pass join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass join3.pass: join2.pass kill1.pass: loadfree.pass: pthread.dll mutex1.pass: self1.pass mutex1n.pass: mutex1.pass mutex1e.pass: mutex1.pass mutex1r.pass: mutex1.pass mutex2.pass: mutex1.pass mutex2r.pass: mutex2.pass mutex2e.pass: mutex2.pass mutex3.pass: create1.pass mutex3r.pass: mutex3.pass mutex3e.pass: mutex3.pass mutex4.pass: mutex3.pass mutex5.pass: mutex6.pass: mutex4.pass mutex6n.pass: mutex4.pass mutex6e.pass: mutex4.pass mutex6r.pass: mutex4.pass mutex6s.pass: mutex6.pass mutex6rs.pass: mutex6r.pass mutex6es.pass: mutex6e.pass mutex7.pass: mutex6.pass mutex7n.pass: mutex6n.pass mutex7e.pass: mutex6e.pass mutex7r.pass: mutex6r.pass mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass once4.pass: once3.pass priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass rwlock7.pass: rwlock6.pass rwlock8.pass: rwlock7.pass rwlock2_t.pass: rwlock2.pass rwlock3_t.pass: rwlock2_t.pass rwlock4_t.pass: rwlock3_t.pass rwlock5_t.pass: rwlock4_t.pass rwlock6_t.pass: rwlock5_t.pass rwlock6_t2.pass: rwlock6_t.pass self1.pass: self2.pass: create1.pass semaphore1.pass: semaphore2.pass: semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass sizes.pass: spin1.pass: spin2.pass: spin1.pass spin3.pass: spin2.pass spin4.pass: spin3.pass stress1.pass: condvar9.pass barrier5.pass tsd1.pass: barrier5.pass join1.pass tsd2.pass: tsd1.pass valid1.pass: join1.pass valid2.pass: valid1.pass nyquist-3.05/liblo/pthreads.2/tests/condvar2_1.c0000644000175000000620000000765211512143043020506 0ustar stevestaff/* * File: condvar2_1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test timeout of multiple waits on a CV with no signal/broadcast. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Because the CV is never signaled, we expect the waits to time out. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait does not return ETIMEDOUT. * - Process returns non-zero exit status. */ #define _WIN32_WINNT 0x400 #include "test.h" #include static pthread_cond_t cv; static pthread_mutex_t mutex; static struct timespec abstime = { 0, 0 }; enum { NUMTHREADS = 30 }; void * mythread(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT); assert(pthread_mutex_unlock(&mutex) == 0); return arg; } #include "../implement.h" int main() { int i; pthread_t t[NUMTHREADS + 1]; int result = 0; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert(pthread_cond_init(&cv, NULL) == 0); assert(pthread_mutex_init(&mutex, NULL) == 0); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; assert(pthread_mutex_lock(&mutex) == 0); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); } assert(pthread_mutex_unlock(&mutex) == 0); for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_join(t[i], (void **) &result) == 0); assert(result == i); } { int result = pthread_cond_destroy(&cv); if (result != 0) { fprintf(stderr, "Result = %s\n", error_string[result]); fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); fflush(stderr); } assert(result == 0); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/stress1.c0000644000175000000620000001650311512143043020147 0ustar stevestaff/* * stress1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Stress test condition variables, mutexes, semaphores. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - Correct accounting of semaphore and condition variable waiters. * * Features Tested: * - * * Cases Tested: * - * * Description: * Attempting to expose race conditions in cond vars, semaphores etc. * - Master attempts to signal slave close to when timeout is due. * - Master and slave do battle continuously until main tells them to stop. * - Afterwards, the CV must be successfully destroyed (will return an * error if there are waiters (including any internal semaphore waiters, * which, if there are, cannot not be real waiters). * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - CV is successfully destroyed. * * Fail Criteria: * - CV destroy fails. */ #include "test.h" #include #include const unsigned int ITERATIONS = 1000; static pthread_t master, slave; typedef struct { int value; pthread_cond_t cv; pthread_mutex_t mx; } mysig_t; static int allExit; static mysig_t control = {0, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; static pthread_barrier_t startBarrier, readyBarrier, holdBarrier; static int timeoutCount = 0; static int signalsTakenCount = 0; static int signalsSent = 0; static int bias = 0; static int timeout = 10; // Must be > 0 enum { CTL_STOP = -1 }; /* * Returns abstime 'milliseconds' from 'now'. * * Works for: -INT_MAX <= millisecs <= INT_MAX */ struct timespec * millisecondsFromNow (struct timespec * time, int millisecs) { struct _timeb currSysTime; int64_t nanosecs, secs; const int64_t NANOSEC_PER_MILLISEC = 1000000; const int64_t NANOSEC_PER_SEC = 1000000000; /* get current system time and add millisecs */ _ftime(&currSysTime); secs = (int64_t)(currSysTime.time) + (millisecs / 1000); nanosecs = ((int64_t) (millisecs%1000 + currSysTime.millitm)) * NANOSEC_PER_MILLISEC; if (nanosecs >= NANOSEC_PER_SEC) { secs++; nanosecs -= NANOSEC_PER_SEC; } else if (nanosecs < 0) { secs--; nanosecs += NANOSEC_PER_SEC; } time->tv_nsec = (long)nanosecs; time->tv_sec = (long)secs; return time; } void * masterThread (void * arg) { int dither = (int) arg; timeout = (int) arg; pthread_barrier_wait(&startBarrier); do { int sleepTime; assert(pthread_mutex_lock(&control.mx) == 0); control.value = timeout; assert(pthread_mutex_unlock(&control.mx) == 0); /* * We are attempting to send the signal close to when the slave * is due to timeout. We feel around by adding some [non-random] dither. * * dither is in the range 2*timeout peak-to-peak * sleep time is the average of timeout plus dither. * e.g. * if timeout = 10 then dither = 20 and * sleep millisecs is: 5 <= ms <= 15 * * The bias value attempts to apply some negative feedback to keep * the ratio of timeouts to signals taken close to 1:1. * bias changes more slowly than dither so as to average more. * * Finally, if abs(bias) exceeds timeout then timeout is incremented. */ if (signalsSent % timeout == 0) { if (timeoutCount > signalsTakenCount) { bias++; } else if (timeoutCount < signalsTakenCount) { bias--; } if (bias < -timeout || bias > timeout) { timeout++; } } dither = (dither + 1 ) % (timeout * 2); sleepTime = (timeout - bias + dither) / 2; Sleep(sleepTime); assert(pthread_cond_signal(&control.cv) == 0); signalsSent++; pthread_barrier_wait(&holdBarrier); pthread_barrier_wait(&readyBarrier); } while (!allExit); return NULL; } void * slaveThread (void * arg) { struct timespec time; pthread_barrier_wait(&startBarrier); do { assert(pthread_mutex_lock(&control.mx) == 0); if (pthread_cond_timedwait(&control.cv, &control.mx, millisecondsFromNow(&time, control.value)) == ETIMEDOUT) { timeoutCount++; } else { signalsTakenCount++; } assert(pthread_mutex_unlock(&control.mx) == 0); pthread_barrier_wait(&holdBarrier); pthread_barrier_wait(&readyBarrier); } while (!allExit); return NULL; } int main () { unsigned int i; assert(pthread_barrier_init(&startBarrier, NULL, 3) == 0); assert(pthread_barrier_init(&readyBarrier, NULL, 3) == 0); assert(pthread_barrier_init(&holdBarrier, NULL, 3) == 0); assert(pthread_create(&master, NULL, masterThread, (void *) timeout) == 0); assert(pthread_create(&slave, NULL, slaveThread, NULL) == 0); allExit = FALSE; pthread_barrier_wait(&startBarrier); for (i = 1; !allExit; i++) { pthread_barrier_wait(&holdBarrier); if (i >= ITERATIONS) { allExit = TRUE; } pthread_barrier_wait(&readyBarrier); } assert(pthread_join(slave, NULL) == 0); assert(pthread_join(master, NULL) == 0); printf("Signals sent = %d\nWait timeouts = %d\nSignals taken = %d\nBias = %d\nTimeout = %d\n", signalsSent, timeoutCount, signalsTakenCount, (int) bias, timeout); /* Cleanup */ assert(pthread_barrier_destroy(&holdBarrier) == 0); assert(pthread_barrier_destroy(&readyBarrier) == 0); assert(pthread_barrier_destroy(&startBarrier) == 0); assert(pthread_cond_destroy(&control.cv) == 0); assert(pthread_mutex_destroy(&control.mx) == 0); /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock2.c0000644000175000000620000000414111512143043020121 0ustar stevestaff/* * rwlock2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, lock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_rdlock() * pthread_rwlock_unlock() */ #include "test.h" pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; int main() { assert(rwlock == PTHREAD_RWLOCK_INITIALIZER); assert(pthread_rwlock_rdlock(&rwlock) == 0); assert(rwlock != PTHREAD_RWLOCK_INITIALIZER); assert(rwlock != NULL); assert(pthread_rwlock_unlock(&rwlock) == 0); assert(pthread_rwlock_destroy(&rwlock) == 0); assert(rwlock == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchtest2.c0000644000175000000620000002216011512143043020600 0ustar stevestaff/* * benchtest1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Measure time taken to complete an elementary operation. * * - Mutex * Two threads iterate over lock/unlock for each mutex type. * The two threads are forced into lock-step using two mutexes, * forcing the threads to block on each lock operation. The * time measured is therefore the worst case senario. */ #include "test.h" #include #ifdef __GNUC__ #include #endif #include "benchtest.h" #define PTW32_MUTEX_TYPES #define ITERATIONS 100000L pthread_mutex_t gate1, gate2; old_mutex_t ox1, ox2; CRITICAL_SECTION cs1, cs2; pthread_mutexattr_t ma; long durationMilliSecs; long overHeadMilliSecs = 0; struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; pthread_t worker; int running = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) /* * Dummy use of j, otherwise the loop may be removed by the optimiser * when doing the overhead timing with an empty loop. */ #define TESTSTART \ { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; #define TESTSTOP \ }; _ftime(&currSysTimeStop); if (j + k == i) j++; } void * overheadThread(void * arg) { do { sched_yield(); } while (running); return NULL; } void * oldThread(void * arg) { do { (void) old_mutex_lock(&ox1); (void) old_mutex_lock(&ox2); (void) old_mutex_unlock(&ox1); sched_yield(); (void) old_mutex_unlock(&ox2); } while (running); return NULL; } void * workerThread(void * arg) { do { (void) pthread_mutex_lock(&gate1); (void) pthread_mutex_lock(&gate2); (void) pthread_mutex_unlock(&gate1); sched_yield(); (void) pthread_mutex_unlock(&gate2); } while (running); return NULL; } void * CSThread(void * arg) { do { EnterCriticalSection(&cs1); EnterCriticalSection(&cs2); LeaveCriticalSection(&cs1); sched_yield(); LeaveCriticalSection(&cs2); } while (running); return NULL; } void runTest (char * testNameString, int mType) { #ifdef PTW32_MUTEX_TYPES assert(pthread_mutexattr_settype(&ma, mType) == 0); #endif assert(pthread_mutex_init(&gate1, &ma) == 0); assert(pthread_mutex_init(&gate2, &ma) == 0); assert(pthread_mutex_lock(&gate1) == 0); assert(pthread_mutex_lock(&gate2) == 0); running = 1; assert(pthread_create(&worker, NULL, workerThread, NULL) == 0); TESTSTART (void) pthread_mutex_unlock(&gate1); sched_yield(); (void) pthread_mutex_unlock(&gate2); (void) pthread_mutex_lock(&gate1); (void) pthread_mutex_lock(&gate2); TESTSTOP running = 0; assert(pthread_mutex_unlock(&gate2) == 0); assert(pthread_mutex_unlock(&gate1) == 0); assert(pthread_join(worker, NULL) == 0); assert(pthread_mutex_destroy(&gate2) == 0); assert(pthread_mutex_destroy(&gate1) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS / 4 /* Four locks/unlocks per iteration */); } int main (int argc, char *argv[]) { assert(pthread_mutexattr_init(&ma) == 0); printf( "=============================================================================\n"); printf( "\nLock plus unlock on a locked mutex.\n"); printf("%ld iterations, four locks/unlocks per iteration.\n\n", ITERATIONS); printf( "%-45s %15s %15s\n", "Test", "Total(msec)", "average(usec)"); printf( "-----------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ running = 1; assert(pthread_create(&worker, NULL, overheadThread, NULL) == 0); TESTSTART sched_yield(); sched_yield(); TESTSTOP running = 0; assert(pthread_join(worker, NULL) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; overHeadMilliSecs = durationMilliSecs; InitializeCriticalSection(&cs1); InitializeCriticalSection(&cs2); EnterCriticalSection(&cs1); EnterCriticalSection(&cs2); running = 1; assert(pthread_create(&worker, NULL, CSThread, NULL) == 0); TESTSTART LeaveCriticalSection(&cs1); sched_yield(); LeaveCriticalSection(&cs2); EnterCriticalSection(&cs1); EnterCriticalSection(&cs2); TESTSTOP running = 0; LeaveCriticalSection(&cs2); LeaveCriticalSection(&cs1); assert(pthread_join(worker, NULL) == 0); DeleteCriticalSection(&cs2); DeleteCriticalSection(&cs1); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Simple Critical Section", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS / 4 ); old_mutex_use = OLD_WIN32CS; assert(old_mutex_init(&ox1, NULL) == 0); assert(old_mutex_init(&ox2, NULL) == 0); assert(old_mutex_lock(&ox1) == 0); assert(old_mutex_lock(&ox2) == 0); running = 1; assert(pthread_create(&worker, NULL, oldThread, NULL) == 0); TESTSTART (void) old_mutex_unlock(&ox1); sched_yield(); (void) old_mutex_unlock(&ox2); (void) old_mutex_lock(&ox1); (void) old_mutex_lock(&ox2); TESTSTOP running = 0; assert(old_mutex_unlock(&ox1) == 0); assert(old_mutex_unlock(&ox2) == 0); assert(pthread_join(worker, NULL) == 0); assert(old_mutex_destroy(&ox2) == 0); assert(old_mutex_destroy(&ox1) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Critical Section (WNT)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS / 4); old_mutex_use = OLD_WIN32MUTEX; assert(old_mutex_init(&ox1, NULL) == 0); assert(old_mutex_init(&ox2, NULL) == 0); assert(old_mutex_lock(&ox1) == 0); assert(old_mutex_lock(&ox2) == 0); running = 1; assert(pthread_create(&worker, NULL, oldThread, NULL) == 0); TESTSTART (void) old_mutex_unlock(&ox1); sched_yield(); (void) old_mutex_unlock(&ox2); (void) old_mutex_lock(&ox1); (void) old_mutex_lock(&ox2); TESTSTOP running = 0; assert(old_mutex_unlock(&ox1) == 0); assert(old_mutex_unlock(&ox2) == 0); assert(pthread_join(worker, NULL) == 0); assert(old_mutex_destroy(&ox2) == 0); assert(old_mutex_destroy(&ox1) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Win32 Mutex (W9x)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS / 4); printf( ".............................................................................\n"); /* * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Blocking locks", 0); #endif printf( "=============================================================================\n"); /* * End of tests. */ pthread_mutexattr_destroy(&ma); return 0; } nyquist-3.05/liblo/pthreads.2/tests/readme0000644000175000000620000000205711512143043017556 0ustar stevestaffRunning test cases in this directory ------------------------------------ These make scripts expect to be able to copy the dll, library and header files from this directory's parent directory, which should be the pthreads-win32 source directory. MS VC nmake ------------- Run the target corresponding to the DLL version being tested: nmake clean VC or: nmake clean VS GNU GCC make ------------ Run "make clean" and then "make". See the "Known bugs" section in ..\README. Writing Test Cases ------------------ Tests written in this test suite should behave in the following manner: * If a test fails, leave main() with a result of 1. * If a test succeeds, leave main() with a result of 0. * No diagnostic output should appear when the test is succeeding. Diagnostic output may be emitted if something in the test fails, to help determine the cause of the test failure. Notes: ------ Many test cases use knowledge of implementation internals which are supposed to be opaque to portable applications. nyquist-3.05/liblo/pthreads.2/tests/mutex1n.c0000644000175000000620000000455411512143043020147 0ustar stevestaff/* * mutex1n.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * As for mutex1.c but with type set to PTHREAD_MUTEX_NORMAL. * * Create a simple mutex object, lock it, unlock it, then destroy it. * This is the simplest test of the pthread mutex family that we can do. * * Depends on API functions: * pthread_mutexattr_settype() * pthread_mutex_init() * pthread_mutex_destroy() */ #include "test.h" pthread_mutex_t mutex = NULL; pthread_mutexattr_t mxAttr; int main() { assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(mutex == NULL); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(mutex != NULL); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/priority1.c0000644000175000000620000001152011512143043020477 0ustar stevestaff/* * File: priority1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test thread priority explicit setting using thread attribute. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" enum { PTW32TEST_THREAD_INIT_PRIO = 0, PTW32TEST_MAXPRIORITIES = 512 }; int minPrio; int maxPrio; int validPriorities[PTW32TEST_MAXPRIORITIES]; void * func(void * arg) { int policy; struct sched_param param; pthread_t threadID = pthread_self(); assert(pthread_getschedparam(threadID, &policy, ¶m) == 0); assert(policy == SCHED_OTHER); return (void *) (param.sched_priority); } void * getValidPriorities(void * arg) { int prioSet; pthread_t threadID = pthread_self(); HANDLE threadH = pthread_getw32threadhandle_np(threadID); printf("Using GetThreadPriority\n"); printf("%10s %10s\n", "Set value", "Get value"); for (prioSet = minPrio; prioSet <= maxPrio; prioSet++) { /* * If prioSet is invalid then the threads priority is unchanged * from the previous value. Make the previous value a known * one so that we can check later. */ if (prioSet < 0) SetThreadPriority(threadH, THREAD_PRIORITY_LOWEST); else SetThreadPriority(threadH, THREAD_PRIORITY_HIGHEST); SetThreadPriority(threadH, prioSet); validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); printf("%10d %10d\n", prioSet, validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)]); } return (void *) 0; } int main() { pthread_t t; pthread_attr_t attr; void * result = NULL; struct sched_param param; assert((maxPrio = sched_get_priority_max(SCHED_OTHER)) != -1); assert((minPrio = sched_get_priority_min(SCHED_OTHER)) != -1); assert(pthread_create(&t, NULL, getValidPriorities, NULL) == 0); assert(pthread_join(t, &result) == 0); assert(pthread_attr_init(&attr) == 0); assert(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0); /* Set the thread's priority to a known initial value. */ SetThreadPriority(pthread_getw32threadhandle_np(pthread_self()), PTW32TEST_THREAD_INIT_PRIO); printf("Using pthread_getschedparam\n"); printf("%10s %10s %10s\n", "Set value", "Get value", "Win priority"); for (param.sched_priority = minPrio; param.sched_priority <= maxPrio; param.sched_priority++) { int prio; assert(pthread_attr_setschedparam(&attr, ¶m) == 0); assert(pthread_create(&t, &attr, func, (void *) &attr) == 0); assert((prio = GetThreadPriority(pthread_getw32threadhandle_np(t))) == validPriorities[param.sched_priority+(PTW32TEST_MAXPRIORITIES/2)]); assert(pthread_join(t, &result) == 0); assert(param.sched_priority == (int) result); printf("%10d %10d %10d\n", param.sched_priority, (int) result, prio); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/GNUmakefile0000644000175000000620000002525511512143043020455 0ustar stevestaff# Makefile for the pthreads test suite. # If all of the .pass files can be created, the test suite has passed. # # -------------------------------------------------------------------------- # # Pthreads-win32 - POSIX Threads Library for Win32 # Copyright(C) 1998 John E. Bossom # Copyright(C) 1999,2005 Pthreads-win32 contributors # # Contact Email: rpj@callisto.canberra.edu.au # # The current list of contributors is contained # in the file CONTRIBUTORS included with the source # code distribution. The list can also be seen at the # following World Wide Web location: # http://sources.redhat.com/pthreads-win32/contributors.html # # 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 in the file COPYING.LIB; # if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # DLL_VER = 2 CP = cp -f MV = mv -f RM = rm -f CAT = cat #CP = copy #MV = rename #RM = erase #CAT = type MKDIR = mkdir TOUCH = echo Passed > ECHO = @echo MAKE = make # # Mingw32 # XXCFLAGS = XXLIBS = -lws2_32 #CFLAGS = -O3 -UNDEBUG -Wall $(XXCFLAGS) CFLAGS = -g -UNDEBUG -Wall $(XXCFLAGS) BUILD_DIR = .. INCLUDES = -I. TEST = GC # Default lib version GCX = $(TEST)$(DLL_VER) # Files we need to run the tests # - paths are relative to pthreads build dir. HDR = pthread.h semaphore.h sched.h LIB = libpthread$(GCX).a DLL = pthread$(GCX).dll QAPC = ../QueueUserAPCEx/User/quserex.dll COPYFILES = $(HDR) $(LIB) $(DLL) $(QAPC) # If a test case returns a non-zero exit code to the shell, make will # stop. TESTS = sizes loadfree \ self1 mutex5 mutex1 mutex1e mutex1n mutex1r \ semaphore1 semaphore2 semaphore3 \ condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ create1 create2 reuse1 reuse2 equal1 \ kill1 valid1 valid2 \ exit2 exit3 exit4 exit5 \ join0 join1 detach1 join2 join3 \ mutex2 mutex2r mutex2e mutex3 mutex3r mutex3e \ mutex4 mutex6 mutex6n mutex6e mutex6r \ mutex6s mutex6es mutex6rs \ mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \ count1 \ once1 once2 once3 once4 self2 \ cancel1 cancel2 \ semaphore4 semaphore4t semaphore5 \ barrier1 barrier2 barrier3 barrier4 barrier5 \ tsd1 tsd2 delay1 delay2 eyal1 \ condvar3 condvar3_1 condvar3_2 condvar3_3 \ condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 rwlock8 \ rwlock2_t rwlock3_t rwlock4_t rwlock5_t rwlock6_t rwlock6_t2 \ context1 cancel3 cancel4 cancel5 cancel6a cancel6d \ cancel7 cancel8 \ cleanup0 cleanup1 cleanup2 cleanup3 \ priority1 priority2 inherit1 \ spin1 spin2 spin3 spin4 \ exception1 exception2 exception3 \ cancel9 create3 stress1 STRESSTESTS = \ stress1 BENCHTESTS = \ benchtest1 benchtest2 benchtest3 benchtest4 benchtest5 STATICTESTS = \ self1 PASSES = $(TESTS:%=%.pass) BENCHRESULTS = $(BENCHTESTS:%=%.bench) STRESSRESULTS = $(STRESSTESTS:%=%.pass) STATICRESULTS = $(STATICTESTS:%=%.pass) help: @ $(ECHO) "Run one of the following command lines:" @ $(ECHO) "make clean GC (to test using GC dll with C (no EH) applications)" @ $(ECHO) "make clean GCX (to test using GC dll with C++ (EH) applications)" @ $(ECHO) "make clean GCE (to test using GCE dll with C++ (EH) applications)" @ $(ECHO) "make clean GC-bench (to benchtest using GNU C dll with C cleanup code)" @ $(ECHO) "make clean GCE-bench (to benchtest using GNU C dll with C++ exception handling)" @ $(ECHO) "make clean GC-stress (to stresstest using GNU C dll with C cleanup code)" @ $(ECHO) "make clean GCE-stress (to stresstest using GNU C dll with C++ exception handling)" @ $(ECHO) "make clean GC-static (to test using GC static lib with C (no EH) applications)" all: @ $(MAKE) clean GC @ $(MAKE) clean GCX @ $(MAKE) clean GCE GC: $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" all-pass GCE: $(MAKE) TEST=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" all-pass GCX: $(MAKE) TEST=GC CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_C" all-pass GC-bench: $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" XXLIBS="benchlib.o" all-bench GCE-bench: $(MAKE) TEST=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" XXLIBS="benchlib." all-bench GC-debug: $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" DLL_VER="$(DLL_VER)d" all-pass GC-static: $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C -DPTW32_STATIC_LIB" DLL="" all-static GC-stress: $(ECHO) Stress tests can take a long time since they are trying to $(ECHO) expose weaknesses that may be intermittant or statistically rare. $(ECHO) A pass does not prove correctness, but may give greater confidence. $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" all-stress GCE-stress: $(MAKE) TEST=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" all-stress all-pass: $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! all-bench: $(BENCHRESULTS) @ $(ECHO) BENCH TESTS COMPLETED. all-stress: $(STRESSRESULTS) @ $(ECHO) STRESS TESTS COMPLETED. all-static: $(STATICRESULTS) @ $(ECHO) ALL STATIC TESTS PASSED! Congratulations! @ $(ECHO) Build and test the DLL to run all tests. @ $(ECHO) This test only confirms that the static lib links correctly. benchtest1.bench: benchtest2.bench: benchtest3.bench: benchtest4.bench: benchtest5.bench: barrier1.pass: semaphore4.pass barrier2.pass: barrier1.pass barrier3.pass: barrier2.pass barrier4.pass: barrier3.pass barrier5.pass: barrier4.pass cancel1.pass: create1.pass cancel2.pass: cancel1.pass cancel2_1.pass: cancel2.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass cancel5.pass: cancel3.pass cancel6a.pass: cancel3.pass cancel6d.pass: cancel3.pass cancel7.pass: kill1.pass cancel8.pass: cancel7.pass cancel9.pass: cancel8.pass cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass condvar1.pass: condvar1_1.pass: condvar1.pass condvar1_2.pass: join2.pass condvar2.pass: condvar1.pass condvar2_1.pass: condvar2.pass join2.pass condvar3.pass: create1.pass condvar2.pass condvar3_1.pass: condvar3.pass join2.pass condvar3_2.pass: condvar3_1.pass condvar3_3.pass: condvar3_2.pass condvar4.pass: create1.pass condvar5.pass: condvar4.pass condvar6.pass: condvar5.pass condvar7.pass: condvar6.pass cleanup1.pass condvar8.pass: condvar7.pass condvar9.pass: condvar8.pass context1.pass: cancel2.pass count1.pass: join1.pass create1.pass: mutex2.pass create2.pass: create1.pass create3.pass: delay1.pass: cancel2.pass delay2.pass: delay1.pass detach1.pass: join0.pass equal1.pass: create1.pass errno1.pass: mutex3.pass exception1.pass: cancel4.pass exception2.pass: exception1.pass exception3.pass: exception2.pass exit1.pass: exit2.pass: create1.pass exit3.pass: create1.pass exit4.pass: exit5.pass: exit4.pass kill1.pass eyal1.pass: tsd1.pass inherit1.pass: join1.pass priority1.pass join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass join3.pass: join2.pass kill1.pass: loadfree.pass: pthread.dll mutex1.pass: self1.pass mutex1n.pass: mutex1.pass mutex1e.pass: mutex1.pass mutex1r.pass: mutex1.pass mutex2.pass: mutex1.pass mutex2r.pass: mutex2.pass mutex2e.pass: mutex2.pass mutex3.pass: create1.pass mutex3r.pass: mutex3.pass mutex3e.pass: mutex3.pass mutex4.pass: mutex3.pass mutex5.pass: mutex6.pass: mutex4.pass mutex6n.pass: mutex4.pass mutex6e.pass: mutex4.pass mutex6r.pass: mutex4.pass mutex6s.pass: mutex6.pass mutex6rs.pass: mutex6r.pass mutex6es.pass: mutex6e.pass mutex7.pass: mutex6.pass mutex7n.pass: mutex6n.pass mutex7e.pass: mutex6e.pass mutex7r.pass: mutex6r.pass mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass once4.pass: once3.pass priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass rwlock7.pass: rwlock6.pass rwlock8.pass: rwlock7.pass rwlock2_t.pass: rwlock2.pass rwlock3_t.pass: rwlock2_t.pass rwlock4_t.pass: rwlock3_t.pass rwlock5_t.pass: rwlock4_t.pass rwlock6_t.pass: rwlock5_t.pass rwlock6_t2.pass: rwlock6_t.pass self1.pass: self2.pass: create1.pass semaphore1.pass: semaphore2.pass: semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass sizes.pass: spin1.pass: spin2.pass: spin1.pass spin3.pass: spin2.pass spin4.pass: spin3.pass stress1.pass: tsd1.pass: barrier5.pass join1.pass tsd2.pass: tsd1.pass valid1.pass: join1.pass valid2.pass: valid1.pass sizes.pass: sizes.exe @ $(ECHO) Running $* $< > SIZES.$(TEST) @ $(CAT) SIZES.$(TEST) @ $(ECHO) Passed @ $(TOUCH) $@ %.pass: %.exe @ $(ECHO) Running $* $* @ $(ECHO) Passed @ $(TOUCH) $@ %.bench: $(LIB) $(DLL) $(HDR) $(QAPC) $(XXLIBS) %.exe @ $(ECHO) Running $* $* @ $(ECHO) Done @ $(TOUCH) $@ %.exe: %.c $(LIB) $(DLL) $(HDR) $(QAPC) @ $(ECHO) Compiling $@ @ $(ECHO) $(CC) $(CFLAGS) -o $@ $< $(INCLUDES) -L. -lpthread$(GCX) -lsupc++ $(XXLIBS) @ $(CC) $(CFLAGS) -o $@ $< $(INCLUDES) -L. -lpthread$(GCX) -lsupc++ $(XXLIBS) %.pre: %.c $(HDR) @ $(CC) -E $(CFLAGS) -o $@ $< $(INCLUDES) %.s: %.c $(HDR) @ $(CC) -S $(CFLAGS) -o $@ $< $(INCLUDES) $(COPYFILES): @ $(ECHO) Copying $@ @ $(CP) $(BUILD_DIR)/$@ . benchlib.o: benchlib.c @ $(ECHO) Compiling $@ @ $(ECHO) $(CC) -c $(CFLAGS) $< $(INCLUDES) @ $(CC) -c $(CFLAGS) $< $(INCLUDES) pthread.dll: $(DLL) @ $(CP) $(DLL) $@ clean: - $(RM) *.dll - $(RM) *.lib - $(RM) pthread.h - $(RM) semaphore.h - $(RM) sched.h - $(RM) *.a - $(RM) *.e - $(RM) *.i - $(RM) *.o - $(RM) *.obj - $(RM) *.pdb - $(RM) *.exe - $(RM) *.pass - $(RM) *.bench - $(RM) *.static - $(RM) *.log nyquist-3.05/liblo/pthreads.2/tests/self1.c0000644000175000000620000000407411512143043017555 0ustar stevestaff/* * self1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test for pthread_self(). * * Depends on API functions: * pthread_self() * * Implicitly depends on: * pthread_getspecific() * pthread_setspecific() */ #include "test.h" int main(int argc, char * argv[]) { /* * This should always succeed unless the system has no * resources (memory) left. */ pthread_t self; #ifdef PTW32_STATIC_LIB pthread_win32_process_attach_np(); #endif self = pthread_self(); assert(self.p != NULL); #ifdef PTW32_STATIC_LIB pthread_win32_process_detach_np(); #endif return 0; } nyquist-3.05/liblo/pthreads.2/tests/sizes.gce0000644000175000000620000000137511512143043020215 0ustar stevestaffSizes of pthreads-win32 structs ------------------------------- pthread_t 8 ptw32_thread_t 76 pthread_attr_t_ 28 sem_t_ 12 pthread_mutex_t_ 24 pthread_mutexattr_t_ 8 pthread_spinlock_t_ 8 pthread_barrier_t_ 24 pthread_barrierattr_t_ 4 pthread_key_t_ 16 pthread_cond_t_ 32 pthread_condattr_t_ 4 pthread_rwlock_t_ 28 pthread_rwlockattr_t_ 4 pthread_once_t_ 16 ptw32_cleanup_t 12 ptw32_mcs_node_t_ 16 sched_param 4 ------------------------------- nyquist-3.05/liblo/pthreads.2/tests/cancel8.c0000644000175000000620000001246711512143043020065 0ustar stevestaff/* * File: cancel8.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test cancelling a blocked Win32 thread having created an * implicit POSIX handle for it. * * Test Method (Validation or Falsification): * - Validate return value and that POSIX handle is created and destroyed. * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #ifndef _UWIN #include #endif /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; pthread_t self; }; static bag_t threadbag[NUMTHREADS + 1]; pthread_cond_t CV = PTHREAD_COND_INITIALIZER; pthread_mutex_t CVLock = PTHREAD_MUTEX_INITIALIZER; #if ! defined (__MINGW32__) || defined (__MSVCRT__) unsigned __stdcall #else void #endif Win32thread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; assert((bag->self = pthread_self()).p != NULL); assert(pthread_kill(bag->self, 0) == 0); assert(pthread_mutex_lock(&CVLock) == 0); pthread_cleanup_push(pthread_mutex_unlock, &CVLock); pthread_cond_wait(&CV, &CVLock); pthread_cleanup_pop(1); return 0; } int main() { int failed = 0; int i; HANDLE h[NUMTHREADS + 1]; unsigned thrAddr; /* Dummy variable to pass a valid location to _beginthreadex (Win98). */ for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; #if ! defined (__MINGW32__) || defined (__MSVCRT__) h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, &thrAddr); #else h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]); #endif } /* * Code to control or munipulate child threads should probably go here. */ Sleep(500); /* * Cancel all threads. */ for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_kill(threadbag[i].self, 0) == 0); assert(pthread_cancel(threadbag[i].self) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 100); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; #if ! defined (__MINGW32__) || defined (__MSVCRT__) assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE); #else /* * Can't get a result code. */ result = (int) PTHREAD_CANCELED; #endif assert(threadbag[i].self.p != NULL); assert(pthread_kill(threadbag[i].self, 0) == ESRCH); fail = (result != (int) PTHREAD_CANCELED); if (fail) { fprintf(stderr, "Thread %d: started %d: count %d\n", i, threadbag[i].started, threadbag[i].count); } failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock6.c0000644000175000000620000000553711512143043020137 0ustar stevestaff/* * rwlock6.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Check writer and reader locking * * Depends on API functions: * pthread_rwlock_rdlock() * pthread_rwlock_wrlock() * pthread_rwlock_unlock() */ #include "test.h" static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int bankAccount = 0; void * wrfunc(void * arg) { int ba; assert(pthread_rwlock_wrlock(&rwlock1) == 0); Sleep(2000); bankAccount += 10; ba = bankAccount; assert(pthread_rwlock_unlock(&rwlock1) == 0); return ((void *) ba); } void * rdfunc(void * arg) { int ba; assert(pthread_rwlock_rdlock(&rwlock1) == 0); ba = bankAccount; assert(pthread_rwlock_unlock(&rwlock1) == 0); return ((void *) ba); } int main() { pthread_t wrt1; pthread_t wrt2; pthread_t rdt; int wr1Result = 0; int wr2Result = 0; int rdResult = 0; bankAccount = 0; assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0); Sleep(500); assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0); Sleep(500); assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0); assert(pthread_join(wrt1, (void **) &wr1Result) == 0); assert(pthread_join(rdt, (void **) &rdResult) == 0); assert(pthread_join(wrt2, (void **) &wr2Result) == 0); assert(wr1Result == 10); assert(rdResult == 10); assert(wr2Result == 20); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex1e.c0000644000175000000620000000456411512143043020137 0ustar stevestaff/* * mutex1e.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * As for mutex1.c but with type set to PTHREAD_MUTEX_ERRORCHECK. * * Create a simple mutex object, lock it, unlock it, then destroy it. * This is the simplest test of the pthread mutex family that we can do. * * Depends on API functions: * pthread_mutexattr_settype() * pthread_mutex_init() * pthread_mutex_destroy() */ #include "test.h" pthread_mutex_t mutex = NULL; pthread_mutexattr_t mxAttr; int main() { assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(mutex == NULL); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(mutex != NULL); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_destroy(&mutex) == 0); assert(mutex == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar6.c0000644000175000000620000001254511512143043020267 0ustar stevestaff/* * File: condvar6.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test pthread_cond_broadcast. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Test broadcast with NUMTHREADS (=5) waiting CVs. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #include /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 5 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct cvthing_t_ cvthing_t; struct cvthing_t_ { pthread_cond_t notbusy; pthread_mutex_t lock; int shared; }; static cvthing_t cvthing = { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }; static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; static struct timespec abstime = { 0, 0 }; static int awoken; void * mythread(void * arg) { bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; /* Wait for the start gun */ assert(pthread_mutex_lock(&start_flag) == 0); assert(pthread_mutex_unlock(&start_flag) == 0); assert(pthread_mutex_lock(&cvthing.lock) == 0); while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); assert(cvthing.shared > 0); awoken++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); return (void *) 0; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; cvthing.shared = 0; assert((t[0] = pthread_self()).p != NULL); assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&start_flag) == 0); _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; assert((t[0] = pthread_self()).p != NULL); awoken = 0; for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ assert(pthread_mutex_unlock(&start_flag) == 0); /* * Give threads time to start. */ Sleep(1000); assert(pthread_mutex_lock(&cvthing.lock) == 0); cvthing.shared++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); /* * Give threads time to complete. */ for (i = 1; i <= NUMTHREADS; i++) { assert(pthread_join(t[i], NULL) == 0); } /* * Cleanup the CV. */ assert(pthread_mutex_destroy(&cvthing.lock) == 0); assert(cvthing.lock == NULL); assert(pthread_cond_destroy(&cvthing.notbusy) == 0); assert(cvthing.notbusy == NULL); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { failed = !threadbag[i].started; if (failed) { fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. */ assert(awoken == NUMTHREADS); /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/barrier2.c0000644000175000000620000000357511512143043020260 0ustar stevestaff/* * barrier2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a single barrier object, wait on it, * and then destroy it. * */ #include "test.h" pthread_barrier_t barrier = NULL; int main() { assert(pthread_barrier_init(&barrier, NULL, 1) == 0); assert(pthread_barrier_wait(&barrier) == PTHREAD_BARRIER_SERIAL_THREAD); assert(pthread_barrier_destroy(&barrier) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/condvar4.c0000644000175000000620000001035311512143043020260 0ustar stevestaff/* * File: condvar4.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test PTHREAD_COND_INITIALIZER. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Test basic CV function but starting with a static initialised * CV. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns 0. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns non-zero exit status. */ #include "test.h" #include typedef struct cvthing_t_ cvthing_t; struct cvthing_t_ { pthread_cond_t notbusy; pthread_mutex_t lock; int shared; }; static cvthing_t cvthing = { PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }; enum { NUMTHREADS = 2 }; void * mythread(void * arg) { assert(pthread_mutex_lock(&cvthing.lock) == 0); cvthing.shared++; assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_cond_signal(&cvthing.notbusy) == 0); return (void *) 0; } int main() { pthread_t t[NUMTHREADS]; struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; cvthing.shared = 0; assert((t[0] = pthread_self()).p != NULL); assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); assert(pthread_mutex_lock(&cvthing.lock) == 0); assert(cvthing.lock != PTHREAD_MUTEX_INITIALIZER); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT); assert(cvthing.notbusy != PTHREAD_COND_INITIALIZER); assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 5; while (! (cvthing.shared > 0)) assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); assert(cvthing.shared > 0); assert(pthread_mutex_unlock(&cvthing.lock) == 0); assert(pthread_join(t[1], NULL) == 0); assert(pthread_mutex_destroy(&cvthing.lock) == 0); assert(cvthing.lock == NULL); assert(pthread_cond_destroy(&cvthing.notbusy) == 0); assert(cvthing.notbusy == NULL); return 0; } nyquist-3.05/liblo/pthreads.2/tests/barrier5.c0000644000175000000620000000722311512143043020255 0ustar stevestaff/* * barrier5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a single barrier object, set up a sequence of * barrier points to prove lockstepness, and then destroy it. * */ #include "test.h" enum { NUMTHREADS = 16, BARRIERS = 10000 }; pthread_barrier_t barrier = NULL; pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; int barrierReleases[BARRIERS + 1]; void * func(void * barrierHeight) { int i; int result; int serialThreads = 0; for (i = 1; i < BARRIERS; i++) { result = pthread_barrier_wait(&barrier); assert(pthread_mutex_lock(&mx) == 0); barrierReleases[i]++; assert(pthread_mutex_unlock(&mx) == 0); /* * Confirm the correct number of releases from the previous * barrier. We can't do the current barrier yet because there may * still be threads waking up. */ if (result == PTHREAD_BARRIER_SERIAL_THREAD) { serialThreads++; assert(barrierReleases[i - 1] == (int) barrierHeight); barrierReleases[i + 1] = 0; } else if (result != 0) { printf("Barrier failed: result = %s\n", error_string[result]); fflush(stdout); return NULL; } } return (void *) serialThreads; } int main() { int i, j; int result; int serialThreadsTotal; pthread_t t[NUMTHREADS + 1]; for (j = 1; j <= NUMTHREADS; j++) { printf("Barrier height = %d\n", j); barrierReleases[0] = j; barrierReleases[1] = 0; assert(pthread_barrier_init(&barrier, NULL, j) == 0); for (i = 1; i <= j; i++) { assert(pthread_create(&t[i], NULL, func, (void *) j) == 0); } serialThreadsTotal = 0; for (i = 1; i <= j; i++) { assert(pthread_join(t[i], (void **) &result) == 0); serialThreadsTotal += result; } assert(serialThreadsTotal == BARRIERS - 1); assert(barrierReleases[BARRIERS - 1] == j); assert(barrierReleases[BARRIERS] == 0); assert(pthread_barrier_destroy(&barrier) == 0); } assert(pthread_mutex_destroy(&mx) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/sizes.vc0000644000175000000620000000137511512143043020067 0ustar stevestaffSizes of pthreads-win32 structs ------------------------------- pthread_t 8 ptw32_thread_t 140 pthread_attr_t_ 28 sem_t_ 12 pthread_mutex_t_ 24 pthread_mutexattr_t_ 8 pthread_spinlock_t_ 8 pthread_barrier_t_ 24 pthread_barrierattr_t_ 4 pthread_key_t_ 16 pthread_cond_t_ 32 pthread_condattr_t_ 4 pthread_rwlock_t_ 28 pthread_rwlockattr_t_ 4 pthread_once_t_ 16 ptw32_cleanup_t 12 ptw32_mcs_node_t_ 16 sched_param 4 ------------------------------- nyquist-3.05/liblo/pthreads.2/tests/Wmakefile0000644000175000000620000002607411512143043020232 0ustar stevestaff# Watcom makefile for the pthreads test suite. # If all of the .pass files can be created, the test suite has passed. # # -------------------------------------------------------------------------- # # Pthreads-win32 - POSIX Threads Library for Win32 # Copyright(C) 1998 John E. Bossom # Copyright(C) 1999,2005 Pthreads-win32 contributors # # Contact Email: rpj@callisto.canberra.edu.au # # The current list of contributors is contained # in the file CONTRIBUTORS included with the source # code distribution. The list can also be seen at the # following World Wide Web location: # http://sources.redhat.com/pthreads-win32/contributors.html # # 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 in the file COPYING.LIB; # if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # DLL_VER = 2 .EXTENSIONS: .EXTENSIONS: .pass .exe .obj .i .c CP = copy RM = erase CAT = type MKDIR = mkdir TOUCH = echo Passed > ECHO = @echo CPHDR = pthread.h semaphore.h sched.h OPTIM = -od XXLIBS = # C++ Exceptions WCEFLAGS = -xs -dPtW32NoCatchWarn -d__CLEANUP_CXX WCELIB = pthreadWCE$(DLL_VER).lib WCEDLL = pthreadWCE$(DLL_VER).dll # C cleanup code WCFLAGS = -d__CLEANUP_C WCLIB = pthreadWC$(DLL_VER).lib WCDLL = pthreadWC$(DLL_VER).dll # C++ Exceptions in application - using WC version of pthreads dll WCXFLAGS = -xs -d__CLEANUP_C CFLAGS= -w4 -e25 -d_WIN32_WINNT=0x400 -d_REENTRANT -zq -bm $(OPTIM) -5r -bt=nt -mf -d2 LFLAGS= INCLUDES= -i=. BUILD_DIR=.. COPYFILES = $(CPHDR) $(CPLIB) $(CPDLL) TEST = EHFLAGS = # If a test case returns a non-zero exit code to the shell, make will # stop. PASSES = sizes.pass loadfree.pass & self1.pass mutex5.pass & mutex1.pass mutex1n.pass mutex1e.pass mutex1r.pass & semaphore1.pass semaphore2.pass semaphore3.pass & mutex2.pass mutex3.pass & mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass & condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass & exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass & kill1.pass valid1.pass valid2.pass & exit2.pass exit3.pass exit4 exit5 & join0.pass join1.pass detach1.pass join2.pass join3.pass & mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass & mutex6s.pass mutex6es.pass mutex6rs.pass & mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass & mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass & count1.pass & once1.pass once2.pass once3.pass once4.pass tsd1.pass & self2.pass & cancel1.pass cancel2.pass & semaphore4.pass semaphore4t.pass semaphore5.pass & delay1.pass delay2.pass eyal1.pass & condvar3.pass condvar3_1.pass condvar3_2.pass condvar3_3.pass & condvar4.pass condvar5.pass condvar6.pass & condvar7.pass condvar8.pass condvar9.pass & errno1.pass & rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass rwlock5.pass & rwlock6.pass rwlock7.pass rwlock8.pass & rwlock2_t.pass rwlock3_t.pass rwlock4_t.pass rwlock5_t.pass rwlock6_t.pass rwlock6_t2.pass & context1.pass & cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass & cancel7 cancel8 & cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass & priority1.pass priority2.pass inherit1.pass & spin1.pass spin2.pass spin3.pass spin4.pass & barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass & exception1.pass exception2.pass exception3.pass & cancel9.pass create3.pass stress1.pass BENCHRESULTS = & benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench help: .SYMBOLIC @ $(ECHO) Run one of the following command lines: @ $(ECHO) wmake /f Wmakefile clean WC (to test using WC dll with wcc386 (no EH) applications) @ $(ECHO) wmake /f Wmakefile clean WCX (to test using WC dll with wpp386 (EH) applications) @ $(ECHO) wmake /f Wmakefile clean WCE (to test using the WCE dll with wpp386 EH applications) @ $(ECHO) wmake /f Wmakefile clean WC-bench (to benchtest using WC dll with C bench app) @ $(ECHO) wmake /f Wmakefile clean WCX-bench (to benchtest using WC dll with C++ bench app) @ $(ECHO) wmake /f Wmakefile clean WCE-bench (to benchtest using WCE dll with C++ bench app) all: .SYMBOLIC @ wmake /f Wmakefile clean WC @ wmake /f Wmakefile clean WCX @ wmake /f Wmakefile clean WCE @ wmake /f Wmakefile clean WSE @ wmake /f Wmakefile clean WC-bench tests: $(CPLIB) $(CPDLL) $(CPHDR) $(PASSES) .SYMBOLIC @ $(ECHO) ALL TESTS PASSED! Congratulations! benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(XXLIBS) $(BENCHRESULTS) .SYMBOLIC @ $(ECHO) ALL BENCH TESTS DONE. $(BENCHRESULTS): ($[*).exe @ $(ECHO) ... Running $(TEST) benchtest: ($[*).exe @ .\($[*).exe @ $(ECHO) ...... Done @ $(TOUCH) ($[*).bench WCE: .SYMBOLIC @ wmake /f Wmakefile CC=wpp386 TEST="$@" CPLIB="$(WCELIB)" CPDLL="$(WCEDLL)" EHFLAGS="$(WCEFLAGS)" tests WC: .SYMBOLIC @ wmake /f Wmakefile CC=wcc386 TEST="$@" CPLIB="$(WCLIB)" CPDLL="$(WCDLL)" EHFLAGS="$(WCFLAGS)" tests WCX: .SYMBOLIC @ wmake /f Wmakefile CC=wpp386 TEST="$@" CPLIB="$(WCLIB)" CPDLL="$(WCDLL)" EHFLAGS="$(WCXFLAGS)" tests WCE-bench: .SYMBOLIC @ wmake /f Wmakefile CC=wpp386 TEST="$@" CPLIB="$(WCELIB)" CPDLL="$(WCEDLL)" EHFLAGS="$(WCEFLAGS)" XXLIBS="benchlib.o" benchtests WC-bench: .SYMBOLIC @ wmake /f Wmakefile CC=wcc386 TEST="$@" CPLIB="$(WCLIB)" CPDLL="$(WCDLL)" EHFLAGS="$(WCFLAGS)" XXLIBS="benchlib.o" benchtests WCX-bench: .SYMBOLIC @ wmake /f Wmakefile CC=wpp386 TEST="$@" CPLIB="$(WCLIB)" CPDLL="$(WCDLL)" EHFLAGS="$(WCXFLAGS)" XXLIBS="benchlib.o" benchtests sizes.pass: sizes.exe @ $(ECHO) ... Running $(TEST) test: $^* @ $[@ > SIZES.$(TEST) @ $(CAT) SIZES.$(TEST) @ $(ECHO) ...... Passed @ $(TOUCH) $^@ .exe.pass: @ $(ECHO) ... Running $(TEST) test: $^* @ $[@ @ $(ECHO) ...... Passed @ $(TOUCH) $^@ .obj.exe: @ $(ECHO) wlink NAME $^@ FILE $[@ LIBRARY $(CPLIB) OPTION quiet @ wlink NAME $^@ FILE $[@ LIBRARY $(CPLIB) OPTION quiet .c.obj: @ $(ECHO) $(CC) $^* $(EHFLAGS) $(CFLAGS) $(INCLUDES) @ $(CC) $^* $(EHFLAGS) $(CFLAGS) $(INCLUDES) .c.i: @ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< $(COPYFILES): .SYMBOLIC @ $(ECHO) Copying $@ @ $(CP) $(BUILD_DIR)\$@ . pthread.dll: @ $(CP) $(CPDLL) $*.dll @ $(CP) $(CPLIB) $*.lib clean: .SYMBOLIC @ if exist *.dll $(RM) *.dll @ if exist *.lib $(RM) *.lib @ if exist *.err $(RM) *.err @ if exist pthread.h $(RM) pthread.h @ if exist semaphore.h $(RM) semaphore.h @ if exist sched.h $(RM) sched.h @ if exist *.e $(RM) *.e @ if exist *.i $(RM) *.i @ if exist *.obj $(RM) *.obj @ if exist *.pdb $(RM) *.pdb @ if exist *.o $(RM) *.o @ if exist *.asm $(RM) *.asm @ if exist *.exe $(RM) *.exe @ if exist *.pass $(RM) *.pass @ if exist *.bench $(RM) *.bench @ if exist *.log $(RM) *.log @ $(ECHO) Clean completed. benchtest1.bench: benchtest2.bench: benchtest3.bench: benchtest4.bench: benchtest5.bench: barrier1.pass: barrier2.pass: barrier1.pass barrier3.pass: barrier2.pass barrier4.pass: barrier3.pass barrier5.pass: barrier4.pass cancel1.pass: create1.pass cancel2.pass: cancel1.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass cancel5.pass: cancel3.pass cancel6a.pass: cancel3.pass cancel6d.pass: cancel3.pass cancel7.pass: kill1.pass cancel8.pass: cancel7.pass cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass condvar1.pass: condvar1_1.pass: condvar1.pass condvar1_2.pass: join2.pass condvar2.pass: condvar1.pass condvar2_1.pass: condvar2.pass join2.pass condvar3.pass: create1.pass condvar2.pass condvar3_1.pass: condvar3.pass join2.pass condvar3_2.pass: condvar3_1.pass condvar3_3.pass: condvar3_2.pass condvar4.pass: create1.pass condvar5.pass: condvar4.pass condvar6.pass: condvar5.pass condvar7.pass: condvar6.pass cleanup1.pass condvar8.pass: condvar7.pass condvar9.pass: condvar8.pass context1.pass: cancel2.pass count1.pass: join1.pass create1.pass: mutex2.pass create2.pass: create1.pass create3.pass: delay1.pass: delay2.pass: delay1.pass detach1.pass: join0.pass equal1.pass: create1.pass errno1.pass: mutex3.pass exception1.pass: cancel4.pass exception2.pass: exception1.pass exception3.pass: exception2.pass exit1.pass: exit2.pass: create1.pass exit3.pass: create1.pass exit4.pass: exit5.pass: kill1.pass eyal1.pass: tsd1.pass inherit1.pass: join1.pass priority1.pass join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass join3.pass: join2.pass kill1.pass: loadfree.pass: pthread.dll mutex1.pass: self1.pass mutex1n.pass: mutex1.pass mutex1e.pass: mutex1.pass mutex1r.pass: mutex1.pass mutex2.pass: mutex1.pass mutex2r.pass: mutex2.pass mutex2e.pass: mutex2.pass mutex3.pass: create1.pass mutex3r.pass: mutex3.pass mutex3e.pass: mutex3.pass mutex4.pass: mutex3.pass mutex5.pass: mutex6.pass: mutex4.pass mutex6n.pass: mutex4.pass mutex6e.pass: mutex4.pass mutex6r.pass: mutex4.pass mutex6s.pass: mutex6.pass mutex6rs.pass: mutex6r.pass mutex6es.pass: mutex6e.pass mutex7.pass: mutex6.pass mutex7n.pass: mutex6n.pass mutex7e.pass: mutex6e.pass mutex7r.pass: mutex6r.pass mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass once4.pass: once3.pass priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass rwlock7.pass: rwlock6.pass rwlock2_t.pass: rwlock2.pass rwlock3_t.pass: rwlock2_t.pass rwlock4_t.pass: rwlock3_t.pass rwlock5_t.pass: rwlock4_t.pass rwlock6_t.pass: rwlock5_t.pass rwlock6_t2.pass: rwlock6_t.pass self1.pass: self2.pass: create1.pass semaphore1.pass: semaphore2.pass: semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass sizes.pass: spin1.pass: spin2.pass: spin1.pass spin3.pass: spin2.pass spin4.pass: spin3.pass stress1.pass: tsd1.pass: join1.pass valid1.pass: join1.pass valid2.pass: valid1.pass cancel9.pass: cancel8.pass nyquist-3.05/liblo/pthreads.2/tests/condvar2.c0000644000175000000620000000657211512143043020266 0ustar stevestaff/* * File: condvar2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test timed wait on a CV. * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - Because the CV is never signaled, we expect the wait to time out. * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - pthread_cond_timedwait returns ETIMEDOUT. * - Process returns zero exit status. * * Fail Criteria: * - pthread_cond_timedwait does not return ETIMEDOUT. * - Process returns non-zero exit status. */ #define _WIN32_WINNT 0x400 #include "test.h" #include pthread_cond_t cv; pthread_mutex_t mutex; #include "../implement.h" int main() { struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; assert(pthread_cond_init(&cv, NULL) == 0); assert(pthread_mutex_init(&mutex, NULL) == 0); assert(pthread_mutex_lock(&mutex) == 0); /* get current system time */ _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT); assert(pthread_mutex_unlock(&mutex) == 0); { int result = pthread_cond_destroy(&cv); if (result != 0) { fprintf(stderr, "Result = %s\n", error_string[result]); fprintf(stderr, "\tWaitersBlocked = %ld\n", cv->nWaitersBlocked); fprintf(stderr, "\tWaitersGone = %ld\n", cv->nWaitersGone); fprintf(stderr, "\tWaitersToUnblock = %ld\n", cv->nWaitersToUnblock); fflush(stderr); } assert(result == 0); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchtest1.c0000644000175000000620000001644511512143043020610 0ustar stevestaff/* * benchtest1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Measure time taken to complete an elementary operation. * * - Mutex * Single thread iteration over lock/unlock for each mutex type. */ #include "test.h" #include #ifdef __GNUC__ #include #endif #include "benchtest.h" #define PTW32_MUTEX_TYPES #define ITERATIONS 10000000L pthread_mutex_t mx; pthread_mutexattr_t ma; struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; long durationMilliSecs; long overHeadMilliSecs = 0; int one = 1; int zero = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) /* * Dummy use of j, otherwise the loop may be removed by the optimiser * when doing the overhead timing with an empty loop. */ #define TESTSTART \ { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; #define TESTSTOP \ }; _ftime(&currSysTimeStop); if (j + k == i) j++; } void runTest (char * testNameString, int mType) { #ifdef PTW32_MUTEX_TYPES assert(pthread_mutexattr_settype(&ma, mType) == 0); #endif assert(pthread_mutex_init(&mx, &ma) == 0); TESTSTART assert(pthread_mutex_lock(&mx) == zero); assert(pthread_mutex_unlock(&mx) == zero); TESTSTOP assert(pthread_mutex_destroy(&mx) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); } int main (int argc, char *argv[]) { int i = 0; CRITICAL_SECTION cs; old_mutex_t ox; pthread_mutexattr_init(&ma); printf( "=============================================================================\n"); printf( "\nLock plus unlock on an unlocked mutex.\n%ld iterations\n\n", ITERATIONS); printf( "%-45s %15s %15s\n", "Test", "Total(msec)", "average(usec)"); printf( "-----------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ TESTSTART assert(1 == one); assert(1 == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; overHeadMilliSecs = durationMilliSecs; TESTSTART assert((dummy_call(&i), 1) == one); assert((dummy_call(&i), 1) == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Dummy call x 2", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); TESTSTART assert((interlocked_inc_with_conditionals(&i), 1) == one); assert((interlocked_dec_with_conditionals(&i), 1) == one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Dummy call -> Interlocked with cond x 2", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); TESTSTART assert((InterlockedIncrement((LPLONG)&i), 1) == (LONG)one); assert((InterlockedDecrement((LPLONG)&i), 1) == (LONG)one); TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "InterlockedOp x 2", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); InitializeCriticalSection(&cs); TESTSTART assert((EnterCriticalSection(&cs), 1) == one); assert((LeaveCriticalSection(&cs), 1) == one); TESTSTOP DeleteCriticalSection(&cs); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Simple Critical Section", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); old_mutex_use = OLD_WIN32CS; assert(old_mutex_init(&ox, NULL) == 0); TESTSTART assert(old_mutex_lock(&ox) == zero); assert(old_mutex_unlock(&ox) == zero); TESTSTOP assert(old_mutex_destroy(&ox) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Critical Section (WNT)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); old_mutex_use = OLD_WIN32MUTEX; assert(old_mutex_init(&ox, NULL) == 0); TESTSTART assert(old_mutex_lock(&ox) == zero); assert(old_mutex_unlock(&ox) == zero); TESTSTOP assert(old_mutex_destroy(&ox) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Win32 Mutex (W9x)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); printf( ".............................................................................\n"); /* * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif printf( "=============================================================================\n"); /* * End of tests. */ pthread_mutexattr_destroy(&ma); one = i; /* Dummy assignment to avoid 'variable unused' warning */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/Bmakefile0000644000175000000620000002543711512143043020207 0ustar stevestaff# Makefile for the pthreads test suite. # If all of the .pass files can be created, the test suite has passed. # # -------------------------------------------------------------------------- # # Pthreads-win32 - POSIX Threads Library for Win32 # Copyright(C) 1998 John E. Bossom # Copyright(C) 1999,2005 Pthreads-win32 contributors # # Contact Email: rpj@callisto.canberra.edu.au # # The current list of contributors is contained # in the file CONTRIBUTORS included with the source # code distribution. The list can also be seen at the # following World Wide Web location: # http://sources.redhat.com/pthreads-win32/contributors.html # # 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 in the file COPYING.LIB; # if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # DLL_VER = 2 CP = copy RM = erase CAT = type MKDIR = mkdir TOUCH = echo Passed > ECHO = @echo QAPC = ..\QueueUserAPCEx\User\quserex.dll CPHDR = pthread.h semaphore.h sched.h OPTIM = -O2 XXLIBS = cw32mti.lib ws2_32.lib # C++ Exceptions BCEFLAGS = -P -DPtW32NoCatchWarn -D__CLEANUP_CXX BCELIB = pthreadBCE$(DLL_VER).lib BCEDLL = pthreadBCE$(DLL_VER).dll # C cleanup code BCFLAGS = -D__CLEANUP_C BCLIB = pthreadBC$(DLL_VER).lib BCDLL = pthreadBC$(DLL_VER).dll # C++ Exceptions in application - using VC version of pthreads dll BCXFLAGS = -D__CLEANUP_C # Defaults CPLIB = $(BCLIB) CPDLL = $(BCDLL) CFLAGS= -q $(OPTIM) /D_WIN32_WINNT=0x400 -w -tWC -tWM -4 -w-aus -w-asc -w-par LFLAGS= INCLUDES=-I. BUILD_DIR=.. COPYFILES = $(CPHDR) $(CPLIB) $(CPDLL) $(QAPC) EHFLAGS = # If a test case returns a non-zero exit code to the shell, make will # stop. PASSES= loadfree.pass \ errno1.pass \ self1.pass mutex5.pass \ mutex1.pass mutex1n.pass mutex1e.pass mutex1r.pass \ semaphore1.pass semaphore2.pass semaphore3.pass \ mutex2.pass mutex3.pass \ mutex2r.pass mutex2e.pass mutex3r.pass mutex3e.pass \ condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \ exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \ kill1.pass valid1.pass valid2.pass \ exit2.pass exit3.pass exit4.pass exit5.pass \ join0.pass join1.pass detach1.pass join2.pass join3.pass \ mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass \ mutex6s.pass mutex6es.pass mutex6rs.pass \ mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \ mutex8.pass mutex8n.pass mutex8e.pass mutex8r.pass \ count1.pass \ once1.pass once2.pass once3.pass once4.pass \ self2.pass \ cancel1.pass cancel2.pass \ semaphore4.pass semaphore4t.pass semaphore5.pass \ barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \ tsd1.pass tsd2.pass delay1.pass delay2.pass eyal1.pass \ condvar3.pass condvar3_1.pass condvar3_2.pass condvar3_3.pass \ condvar4.pass condvar5.pass condvar6.pass \ condvar7.pass condvar8.pass condvar9.pass \ rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass \ rwlock5.pass rwlock6.pass rwlock7.pass rwlock8.pass \ rwlock2_t.pass rwlock3_t.pass rwlock4_t.pass rwlock5_t.pass rwlock6_t.pass rwlock6_t2.pass \ context1.pass \ cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass \ cancel7.pass cancel8.pass \ cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \ priority1.pass priority2.pass inherit1.pass \ spin1.pass spin2.pass spin3.pass spin4.pass \ exception1.pass exception2.pass exception3.pass \ cancel9.pass create3.pass stress1.pass BENCHRESULTS = \ benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench help: @ $(ECHO) Run one of the following command lines: @ $(ECHO) make clean BC (to test using BC dll with VC (no EH) applications) @ $(ECHO) make clean BCX (to test using BC dll with VC++ (EH) applications) @ $(ECHO) make clean BCE (to test using the BCE dll with VC++ EH applications) @ $(ECHO) make clean BC-bench (to benchtest using BC dll with C bench app) @ $(ECHO) make clean BCX-bench (to benchtest using BC dll with C++ bench app) @ $(ECHO) make clean BCE-bench (to benchtest using BCE dll with C++ bench app) all: @ make clean BC @ make clean BCX @ make clean BCE @ make clean BC-bench # This allows an individual test application to be made using the default lib. # e.g. make clean test cancel3.exe test: $(CPLIB) $(CPDLL) $(CPHDR) $(QAPC) tests: $(CPLIB) $(CPDLL) $(CPHDR) $(QAPC) sizes.pass $(PASSES) @ $(ECHO) ALL TESTS PASSED! Congratulations! benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(BENCHRESULTS) @ $(ECHO) ALL BENCH TESTS DONE. sizes.pass: sizes.exe @ $(ECHO) ... Running $(TEST) test: $*.exe @ .\$*.exe > SIZES.$(TEST) @ $(CAT) SIZES.$(TEST) @ $(ECHO) ...... Passed @ $(TOUCH) $*.pass BCE: @ make -f Bmakefile TEST="$@" CPLIB="$(BCELIB)" CPDLL="$(BCEDLL)" EHFLAGS="$(BCEFLAGS)" tests BC: @ make -f Bmakefile TEST="$@" CPLIB="$(BCLIB)" CPDLL="$(BCDLL)" EHFLAGS="$(BCFLAGS)" tests BCX: @ make -f Bmakefile TEST="$@" CPLIB="$(BCLIB)" CPDLL="$(BCDLL)" EHFLAGS="$(BCXFLAGS)" tests BCE-bench: @ make -f Bmakefile TEST="$@" CPLIB="$(BCELIB)" CPDLL="$(BCEDLL)" EHFLAGS="$(BCEFLAGS)" XXLIBS="benchlib.o" benchtests BC-bench: @ make -f Bmakefile TEST="$@" CPLIB="$(BCLIB)" CPDLL="$(BCDLL)" EHFLAGS="$(BCFLAGS)" XXLIBS="benchlib.o" benchtests BCX-bench: @ make -f Bmakefile TEST="$@" CPLIB="$(BCLIB)" CPDLL="$(BCDLL)" EHFLAGS="$(BCXFLAGS)" XXLIBS="benchlib.o" benchtests .exe.pass: @ $(ECHO) ... Running $(TEST) test: $< @ .\$< @ $(ECHO) ...... Passed @ $(TOUCH) $@ .exe.bench: @ $(ECHO) ... Running $(TEST) benchtest: $< @ .\$< @ $(ECHO) ...... Done @ $(TOUCH) $@ .c.exe: @ $(ECHO) $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< -e$@ $(LFLAGS) $(CPLIB) $(XXLIBS) @ $(CC) $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< -e$@ $(LFLAGS) $(CPLIB) $(XXLIBS) .c.o: @ $(ECHO) $(CC) $(EHFLAGS) -c $(CFLAGS) $(INCLUDES) $< -o$@ @ $(CC) $(EHFLAGS) $(CFLAGS) -c $(INCLUDES) $< -o$@ .c.i: @ $(CC) /P $(EHFLAGS) $(CFLAGS) $(INCLUDES) $< $(COPYFILES): @ $(ECHO) Copying $@ @ $(CP) $(BUILD_DIR)\$@ . pthread.dll: $(CPDLL) @ $(CP) $(CPDLL) pthread.dll @ $(CP) $(CPLIB) pthread.lib clean: - $(RM) *.dll - $(RM) *.lib - $(RM) pthread.h - $(RM) semaphore.h - $(RM) sched.h - $(RM) *.e - $(RM) *.i - $(RM) *.obj - $(RM) *.tds - $(RM) *.pdb - $(RM) *.o - $(RM) *.asm - $(RM) *.exe - $(RM) *.pass - $(RM) *.bench - $(RM) *.log benchtest1.bench: benchtest2.bench: benchtest3.bench: benchtest4.bench: benchtest5.bench: barrier1.pass: semaphore4.pass barrier2.pass: barrier1.pass barrier3.pass: barrier2.pass barrier4.pass: barrier3.pass barrier5.pass: barrier4.pass cancel1.pass: create1.pass cancel2.pass: cancel1.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass cancel5.pass: cancel3.pass cancel6a.pass: cancel3.pass cancel6d.pass: cancel3.pass cancel7.pass: kill1.pass cancel8.pass: cancel7.pass cancel9.pass: cancel8.pass cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass condvar1.pass: condvar1_1.pass: condvar1.pass condvar1_2.pass: join2.pass condvar2.pass: condvar1.pass condvar2_1.pass: condvar2.pass join2.pass condvar3.pass: create1.pass condvar2.pass condvar3_1.pass: condvar3.pass join2.pass condvar3_2.pass: condvar3_1.pass condvar3_3.pass: condvar3_2.pass condvar4.pass: create1.pass condvar5.pass: condvar4.pass condvar6.pass: condvar5.pass condvar7.pass: condvar6.pass cleanup1.pass condvar8.pass: condvar7.pass condvar9.pass: condvar8.pass context1.pass: cancel2.pass count1.pass: join1.pass create1.pass: mutex2.pass create2.pass: create1.pass create3.pass: delay1.pass: delay2.pass: delay1.pass detach1.pass: join0.pass equal1.pass: create1.pass errno1.pass: mutex3.pass exception1.pass: cancel4.pass exception2.pass: exception1.pass exception3.pass: exception2.pass exit1.pass: exit2.pass: create1.pass exit3.pass: create1.pass exit4.pass: exit5.pass: kill1.pass eyal1.pass: tsd1.pass inherit1.pass: join1.pass priority1.pass join0.pass: create1.pass join1.pass: create1.pass join2.pass: create1.pass join3.pass: join2.pass kill1.pass: loadfree.pass: pthread.dll mutex1.pass: self1.pass mutex1n.pass: mutex1.pass mutex1e.pass: mutex1.pass mutex1r.pass: mutex1.pass mutex2.pass: mutex1.pass mutex2r.pass: mutex2.pass mutex2e.pass: mutex2.pass mutex3.pass: create1.pass mutex3r.pass: mutex3.pass mutex3e.pass: mutex3.pass mutex4.pass: mutex3.pass mutex5.pass: mutex6.pass: mutex4.pass mutex6n.pass: mutex4.pass mutex6e.pass: mutex4.pass mutex6r.pass: mutex4.pass mutex6s.pass: mutex6.pass mutex6rs.pass: mutex6r.pass mutex6es.pass: mutex6e.pass mutex7.pass: mutex6.pass mutex7n.pass: mutex6n.pass mutex7e.pass: mutex6e.pass mutex7r.pass: mutex6r.pass mutex8.pass: mutex7.pass mutex8n.pass: mutex7n.pass mutex8e.pass: mutex7e.pass mutex8r.pass: mutex7r.pass once1.pass: create1.pass once2.pass: once1.pass once3.pass: once2.pass once4.pass: once3.pass priority1.pass: join1.pass priority2.pass: priority1.pass barrier3.pass reuse1.pass: create2.pass reuse2.pass: reuse1.pass rwlock1.pass: condvar6.pass rwlock2.pass: rwlock1.pass rwlock3.pass: rwlock2.pass rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass rwlock7.pass: rwlock6.pass rwlock8.pass: rwlock7.pass rwlock2_t.pass: rwlock2.pass rwlock3_t.pass: rwlock2_t.pass rwlock4_t.pass: rwlock3_t.pass rwlock5_t.pass: rwlock4_t.pass rwlock6_t.pass: rwlock5_t.pass rwlock6_t2.pass: rwlock6_t.pass self1.pass: self2.pass: create1.pass semaphore1.pass: semaphore2.pass: semaphore3.pass: semaphore2.pass semaphore4.pass: semaphore3.pass cancel1.pass semaphore4t.pass: semaphore4.pass semaphore5.pass: semaphore4.pass sizes.pass: spin1.pass: spin2.pass: spin1.pass spin3.pass: spin2.pass spin4.pass: spin3.pass stress1.pass: tsd1.pass: barrier5.pass join1.pass tsd2.pass: tsd1.pass valid1.pass: join1.pass valid2.pass: valid1.pass nyquist-3.05/liblo/pthreads.2/tests/exit3.c0000644000175000000620000000374211512143043017600 0ustar stevestaff/* * Test for pthread_exit(). * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: pthread_create(). */ #include "test.h" void * func(void * arg) { pthread_exit(arg); /* Never reached. */ assert(0); return NULL; } int main(int argc, char * argv[]) { pthread_t id[4]; int i; /* Create a few threads and then exit. */ for (i = 0; i < 4; i++) { assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); } Sleep(1000); /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/create2.c0000644000175000000620000000526511512143043020073 0ustar stevestaff/* * File: create2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test that threads have a Win32 handle when started. * * Test Method (Validation or Falsification): * - Statistical, not absolute (depends on sample size). * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" enum { NUMTHREADS = 10000 }; static int washere = 0; void * func(void * arg) { washere = 1; return (void *) 0; } int main() { pthread_t t; pthread_attr_t attr; void * result = NULL; int i; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i = 0; i < NUMTHREADS; i++) { washere = 0; assert(pthread_create(&t, &attr, func, NULL) == 0); pthread_join(t, &result); assert(washere == 1); } return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock5.c0000644000175000000620000000437511512143043020135 0ustar stevestaff/* * rwlock5.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, rdlock it, tryrdlock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_rdlock() * pthread_rwlock_tryrdlock() * pthread_rwlock_unlock() */ #include "test.h" pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_rwlock_tryrdlock(&rwlock1) == 0); assert(pthread_rwlock_unlock(&rwlock1) == 0); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_rwlock_rdlock(&rwlock1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); Sleep(2000); assert(pthread_rwlock_unlock(&rwlock1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/tryentercs2.c0000644000175000000620000000562211512143043021027 0ustar stevestaff/* * tryentercs.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * See if we have the TryEnterCriticalSection function. * Does not use any part of pthreads. */ #include #include #include /* * Function pointer to TryEnterCriticalSection if it exists * - otherwise NULL */ BOOL (WINAPI *_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; /* * Handle to kernel32.dll */ static HINSTANCE _h_kernel32; int main() { LPCRITICAL_SECTION lpcs = NULL; SetLastError(0); printf("Last Error [main enter] %ld\n", (long) GetLastError()); /* * Load KERNEL32 and try to get address of TryEnterCriticalSection */ _h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); _try_enter_critical_section = (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION)) GetProcAddress(_h_kernel32, (LPCSTR) "TryEnterCriticalSection"); if (_try_enter_critical_section != NULL) { SetLastError(0); (*_try_enter_critical_section)(lpcs); printf("Last Error [try enter] %ld\n", (long) GetLastError()); } (void) FreeLibrary(_h_kernel32); printf("This system %s TryEnterCriticalSection.\n", (_try_enter_critical_section == NULL) ? "DOES NOT SUPPORT" : "SUPPORTS"); printf("POSIX Mutexes will be based on Win32 %s.\n", (_try_enter_critical_section == NULL) ? "Mutexes" : "Critical Sections"); return(0); } nyquist-3.05/liblo/pthreads.2/tests/rwlock8.c0000644000175000000620000001201711512143043020130 0ustar stevestaff/* * rwlock8.c * * Hammer on a bunch of rwlocks to test robustness and fairness. * Printed stats should be roughly even for each thread. * * Yield during each access to exercise lock contention code paths * more than rwlock7.c does (particularly on uni-processor systems). */ #include "test.h" #include #ifdef __GNUC__ #include #endif #define THREADS 5 #define DATASIZE 7 #define ITERATIONS 100000 /* * Keep statistics for each thread. */ typedef struct thread_tag { int thread_num; pthread_t thread_id; int updates; int reads; int changed; int seed; } thread_t; /* * Read-write lock and shared data */ typedef struct data_tag { pthread_rwlock_t lock; int data; int updates; } data_t; static thread_t threads[THREADS]; static data_t data[DATASIZE]; /* * Thread start routine that uses read-write locks */ void *thread_routine (void *arg) { thread_t *self = (thread_t*)arg; int iteration; int element = 0; int seed = self->seed; int interval = 1 + rand_r (&seed) % 71; self->changed = 0; for (iteration = 0; iteration < ITERATIONS; iteration++) { if (iteration % (ITERATIONS / 10) == 0) { putchar('.'); fflush(stdout); } /* * Each "self->interval" iterations, perform an * update operation (write lock instead of read * lock). */ if ((iteration % interval) == 0) { assert(pthread_rwlock_wrlock (&data[element].lock) == 0); data[element].data = self->thread_num; data[element].updates++; self->updates++; interval = 1 + rand_r (&seed) % 71; sched_yield(); assert(pthread_rwlock_unlock (&data[element].lock) == 0); } else { /* * Look at the current data element to see whether * the current thread last updated it. Count the * times, to report later. */ assert(pthread_rwlock_rdlock (&data[element].lock) == 0); self->reads++; if (data[element].data != self->thread_num) { self->changed++; interval = 1 + self->changed % 71; } sched_yield(); assert(pthread_rwlock_unlock (&data[element].lock) == 0); } element = (element + 1) % DATASIZE; } return NULL; } int main (int argc, char *argv[]) { int count; int data_count; int thread_updates = 0; int data_updates = 0; int seed = 1; struct _timeb currSysTime1; struct _timeb currSysTime2; /* * Initialize the shared data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { data[data_count].data = 0; data[data_count].updates = 0; assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); } _ftime(&currSysTime1); /* * Create THREADS threads to access shared data. */ for (count = 0; count < THREADS; count++) { threads[count].thread_num = count; threads[count].updates = 0; threads[count].reads = 0; threads[count].seed = 1 + rand_r (&seed) % 71; assert(pthread_create (&threads[count].thread_id, NULL, thread_routine, (void*)&threads[count]) == 0); } /* * Wait for all threads to complete, and collect * statistics. */ for (count = 0; count < THREADS; count++) { assert(pthread_join (threads[count].thread_id, NULL) == 0); } putchar('\n'); fflush(stdout); for (count = 0; count < THREADS; count++) { if (threads[count].changed > 0) { printf ("Thread %d found changed elements %d times\n", count, threads[count].changed); } } putchar('\n'); fflush(stdout); for (count = 0; count < THREADS; count++) { thread_updates += threads[count].updates; printf ("%02d: seed %d, updates %d, reads %d\n", count, threads[count].seed, threads[count].updates, threads[count].reads); } putchar('\n'); fflush(stdout); /* * Collect statistics for the data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { data_updates += data[data_count].updates; printf ("data %02d: value %d, %d updates\n", data_count, data[data_count].data, data[data_count].updates); assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); } printf ("%d thread updates, %d data updates\n", thread_updates, data_updates); _ftime(&currSysTime2); printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", currSysTime1.time,currSysTime1.millitm, currSysTime2.time,currSysTime2.millitm, (currSysTime2.time*1000+currSysTime2.millitm) - (currSysTime1.time*1000+currSysTime1.millitm)); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex3r.c0000644000175000000620000000432411512143043020150 0ustar stevestaff/* * mutex3r.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static mutex object, lock it, trylock it, * and then unlock it again. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" pthread_mutex_t mutex1 = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_mutex_trylock(&mutex1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_mutex_lock(&mutex1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/delay2.c0000644000175000000620000000457111512143043017725 0ustar stevestaff/* * delay1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: * pthread_delay_np */ #include "test.h" pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; void * func(void * arg) { struct timespec interval = {5, 500000000L}; assert(pthread_mutex_lock(&mx) == 0); #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(pthread_mutex_unlock, &mx); assert(pthread_delay_np(&interval) == 0); pthread_cleanup_pop(1); #ifdef _MSC_VER #pragma inline_depth() #endif return (void *) 1; } int main(int argc, char * argv[]) { pthread_t t; int result = 0; assert(pthread_mutex_lock(&mx) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_cancel(t) == 0); assert(pthread_mutex_unlock(&mx) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == (int) PTHREAD_CANCELED); return 0; } nyquist-3.05/liblo/pthreads.2/tests/delay1.c0000644000175000000620000000336711512143043017726 0ustar stevestaff/* * delay1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: * pthread_delay_np */ #include "test.h" int main(int argc, char * argv[]) { struct timespec interval = {1L, 500000000L}; assert(pthread_delay_np(&interval) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex3.c0000644000175000000620000000431111512143043017762 0ustar stevestaff/* * mutex3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static mutex object, lock it, trylock it, * and then unlock it again. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_mutex_trylock(&mutex1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_mutex_lock(&mutex1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mutex1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/exception1.c0000644000175000000620000001417111512143043020621 0ustar stevestaff/* * File: exception1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test passing of exceptions back to the application. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 4 }; void * exceptionedThread(void * arg) { int dummy = 0; int result = ((int)PTHREAD_CANCELED + 1); /* Set to async cancelable */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); Sleep(100); #if defined(_MSC_VER) && !defined(__cplusplus) __try { int zero = (int) arg; /* Passed in from arg to avoid compiler error */ int one = 1; /* * The deliberate exception condition (zero divide) is * in an "if" to avoid being optimised out. */ if (dummy == one/zero) Sleep(0); } __except (EXCEPTION_EXECUTE_HANDLER) { /* Should get into here. */ result = ((int)PTHREAD_CANCELED + 2); } #elif defined(__cplusplus) try { /* * I had a zero divide exception here but it * wasn't being caught by the catch(...) * below under Mingw32. That could be a problem. */ throw dummy; } #if defined(PtW32CatchAll) PtW32CatchAll #else catch (...) #endif { /* Should get into here. */ result = ((int)PTHREAD_CANCELED + 2); } #endif return (void *) result; } void * canceledThread(void * arg) { int result = ((int)PTHREAD_CANCELED + 1); int count; /* Set to async cancelable */ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); #if defined(_MSC_VER) && !defined(__cplusplus) __try { /* * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (count = 0; count < 100; count++) Sleep(100); } __except (EXCEPTION_EXECUTE_HANDLER) { /* Should NOT get into here. */ result = ((int)PTHREAD_CANCELED + 2); } #elif defined(__cplusplus) try { /* * We wait up to 10 seconds, waking every 0.1 seconds, * for a cancelation to be applied to us. */ for (count = 0; count < 100; count++) Sleep(100); } #if defined(PtW32CatchAll) PtW32CatchAll #else catch (...) #endif { /* Should NOT get into here. */ result = ((int)PTHREAD_CANCELED + 2); } #endif return (void *) result; } int main() { int failed = 0; int i; pthread_t mt; pthread_t et[NUMTHREADS]; pthread_t ct[NUMTHREADS]; assert((mt = pthread_self()).p != NULL); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_create(&et[i], NULL, exceptionedThread, (void *) 0) == 0); assert(pthread_create(&ct[i], NULL, canceledThread, NULL) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(1000); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_cancel(ct[i]) == 0); } /* * Give threads time to run. */ Sleep(NUMTHREADS * 1000); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 0; i < NUMTHREADS; i++) { int fail = 0; int result = 0; /* Canceled thread */ assert(pthread_join(ct[i], (void **) &result) == 0); assert(!(fail = (result != (int) PTHREAD_CANCELED))); failed = (failed || fail); /* Exceptioned thread */ assert(pthread_join(et[i], (void **) &result) == 0); assert(!(fail = (result != ((int) PTHREAD_CANCELED + 2)))); failed = (failed || fail); } assert(!failed); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ #include int main() { fprintf(stderr, "Test N/A for this compiler environment.\n"); return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/valid2.c0000644000175000000620000000437111512143043017724 0ustar stevestaff/* * File: valid2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Confirm that thread validation fails for garbage thread ID. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" int main() { pthread_t NullThread = PTW32_THREAD_NULL_ID; assert(pthread_kill(NullThread, 0) == ESRCH); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex8e.c0000644000175000000620000000515311512143043020141 0ustar stevestaff/* * mutex8e.c * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 Ben Elliston and Ross Johnson * Copyright (C) 1999,2000,2001 Ross Johnson * * Contact Email: rpj@ise.canberra.edu.au * * 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.1 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 * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_ERRORCHECK mutex type exercising timedlock. * Thread locks mutex, another thread timedlocks the mutex. * Timed thread should timeout. * * Depends on API functions: * pthread_create() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_timedlock() * pthread_mutex_unlock() */ #include "test.h" #include static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); lockCount++; return 0; } int main() { pthread_t t; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_ERRORCHECK); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(2000); assert(lockCount == 1); assert(pthread_mutex_unlock(&mutex) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/inherit1.c0000644000175000000620000001215011512143043020260 0ustar stevestaff/* * File: inherit1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Test thread priority inheritance. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" enum { PTW32TEST_THREAD_INIT_PRIO = 0, PTW32TEST_MAXPRIORITIES = 512 }; int minPrio; int maxPrio; int validPriorities[PTW32TEST_MAXPRIORITIES]; void * func(void * arg) { int policy; struct sched_param param; assert(pthread_getschedparam(pthread_self(), &policy, ¶m) == 0); return (void *) param.sched_priority; } void * getValidPriorities(void * arg) { int prioSet; pthread_t thread = pthread_self(); HANDLE threadH = pthread_getw32threadhandle_np(thread); struct sched_param param; for (prioSet = minPrio; prioSet <= maxPrio; prioSet++) { /* * If prioSet is invalid then the threads priority is unchanged * from the previous value. Make the previous value a known * one so that we can check later. */ param.sched_priority = prioSet; assert(pthread_setschedparam(thread, SCHED_OTHER, ¶m) == 0); validPriorities[prioSet+(PTW32TEST_MAXPRIORITIES/2)] = GetThreadPriority(threadH); } return (void *) 0; } int main() { pthread_t t; pthread_t mainThread = pthread_self(); pthread_attr_t attr; void * result = NULL; struct sched_param param; struct sched_param mainParam; int prio; int policy; int inheritsched = -1; pthread_t threadID = pthread_self(); HANDLE threadH = pthread_getw32threadhandle_np(threadID); assert((maxPrio = sched_get_priority_max(SCHED_OTHER)) != -1); assert((minPrio = sched_get_priority_min(SCHED_OTHER)) != -1); assert(pthread_create(&t, NULL, getValidPriorities, NULL) == 0); assert(pthread_join(t, &result) == 0); assert(pthread_attr_init(&attr) == 0); assert(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) == 0); assert(pthread_attr_getinheritsched(&attr, &inheritsched) == 0); assert(inheritsched == PTHREAD_INHERIT_SCHED); for (prio = minPrio; prio <= maxPrio; prio++) { mainParam.sched_priority = prio; /* Set the thread's priority to a known initial value. */ SetThreadPriority(threadH, PTW32TEST_THREAD_INIT_PRIO); /* Change the main thread priority */ assert(pthread_setschedparam(mainThread, SCHED_OTHER, &mainParam) == 0); assert(pthread_getschedparam(mainThread, &policy, &mainParam) == 0); assert(policy == SCHED_OTHER); /* Priority returned below should be the level set by pthread_setschedparam(). */ assert(mainParam.sched_priority == prio); assert(GetThreadPriority(threadH) == validPriorities[prio+(PTW32TEST_MAXPRIORITIES/2)]); for (param.sched_priority = prio; param.sched_priority <= maxPrio; param.sched_priority++) { /* The new thread create should ignore this new priority */ assert(pthread_attr_setschedparam(&attr, ¶m) == 0); assert(pthread_create(&t, &attr, func, NULL) == 0); pthread_join(t, &result); assert((int) result == mainParam.sched_priority); } } return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchtest3.c0000644000175000000620000001374711512143043020614 0ustar stevestaff/* * benchtest3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Measure time taken to complete an elementary operation. * * - Mutex * Single thread iteration over a trylock on a locked mutex for each mutex type. */ #include "test.h" #include #ifdef __GNUC__ #include #endif #include "benchtest.h" #define PTW32_MUTEX_TYPES #define ITERATIONS 10000000L pthread_mutex_t mx; old_mutex_t ox; pthread_mutexattr_t ma; struct _timeb currSysTimeStart; struct _timeb currSysTimeStop; long durationMilliSecs; long overHeadMilliSecs = 0; #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \ - (_TStart.time*1000+_TStart.millitm)) /* * Dummy use of j, otherwise the loop may be removed by the optimiser * when doing the overhead timing with an empty loop. */ #define TESTSTART \ { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++; #define TESTSTOP \ }; _ftime(&currSysTimeStop); if (j + k == i) j++; } void * trylockThread (void * arg) { TESTSTART (void) pthread_mutex_trylock(&mx); TESTSTOP return NULL; } void * oldTrylockThread (void * arg) { TESTSTART (void) old_mutex_trylock(&ox); TESTSTOP return NULL; } void runTest (char * testNameString, int mType) { pthread_t t; #ifdef PTW32_MUTEX_TYPES (void) pthread_mutexattr_settype(&ma, mType); #endif assert(pthread_mutex_init(&mx, &ma) == 0); assert(pthread_mutex_lock(&mx) == 0); assert(pthread_create(&t, NULL, trylockThread, 0) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_mutex_unlock(&mx) == 0); assert(pthread_mutex_destroy(&mx) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", testNameString, durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); } int main (int argc, char *argv[]) { pthread_t t; assert(pthread_mutexattr_init(&ma) == 0); printf( "=============================================================================\n"); printf( "\nTrylock on a locked mutex.\n"); printf( "%ld iterations.\n\n", ITERATIONS); printf( "%-45s %15s %15s\n", "Test", "Total(msec)", "average(usec)"); printf( "-----------------------------------------------------------------------------\n"); /* * Time the loop overhead so we can subtract it from the actual test times. */ TESTSTART TESTSTOP durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; overHeadMilliSecs = durationMilliSecs; old_mutex_use = OLD_WIN32CS; assert(old_mutex_init(&ox, NULL) == 0); assert(old_mutex_lock(&ox) == 0); assert(pthread_create(&t, NULL, oldTrylockThread, 0) == 0); assert(pthread_join(t, NULL) == 0); assert(old_mutex_unlock(&ox) == 0); assert(old_mutex_destroy(&ox) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Critical Section (WNT)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); old_mutex_use = OLD_WIN32MUTEX; assert(old_mutex_init(&ox, NULL) == 0); assert(old_mutex_lock(&ox) == 0); assert(pthread_create(&t, NULL, oldTrylockThread, 0) == 0); assert(pthread_join(t, NULL) == 0); assert(old_mutex_unlock(&ox) == 0); assert(old_mutex_destroy(&ox) == 0); durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", "Old PT Mutex using a Win32 Mutex (W9x)", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); printf( ".............................................................................\n"); /* * Now we can start the actual tests */ #ifdef PTW32_MUTEX_TYPES runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); #else runTest("Non-blocking lock", 0); #endif printf( "=============================================================================\n"); /* * End of tests. */ pthread_mutexattr_destroy(&ma); return 0; } nyquist-3.05/liblo/pthreads.2/tests/create3.c0000644000175000000620000000546311512143043020074 0ustar stevestaff/* * File: create3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2003 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test passing NULL as thread id arg to pthread_create. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #ifdef __GNUC__ #include #endif #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 1 }; void * threadFunc(void * arg) { return (void *) 0; } int main(int argc, char * argv[]) { int i; pthread_t mt; if (argc <= 1) { int result; printf("You should see an application memory write error message\n"); fflush(stdout); result = system("create3.exe die"); exit(0); } assert((mt = pthread_self()).p != NULL); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_create(NULL, NULL, threadFunc, NULL) == 0); } /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/cleanup3.c0000644000175000000620000001162311512143043020253 0ustar stevestaff/* * File: cleanup3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test cleanup handler does not execute (when thread is * not canceled). * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 10 }; typedef struct bag_t_ bag_t; struct bag_t_ { int threadnum; int started; /* Add more per-thread state variables here */ int count; }; static bag_t threadbag[NUMTHREADS + 1]; typedef struct { int i; CRITICAL_SECTION cs; } sharedInt_t; static sharedInt_t pop_count = {0, {0}}; static void increment_pop_count(void * arg) { sharedInt_t * sI = (sharedInt_t *) arg; EnterCriticalSection(&sI->cs); sI->i++; LeaveCriticalSection(&sI->cs); } void * mythread(void * arg) { int result = 0; bag_t * bag = (bag_t *) arg; assert(bag == &threadbag[bag->threadnum]); assert(bag->started == 0); bag->started = 1; #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(increment_pop_count, (void *) &pop_count); sched_yield(); EnterCriticalSection(&pop_count.cs); pop_count.i--; LeaveCriticalSection(&pop_count.cs); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif return (void *) result; } int main() { int failed = 0; int i; pthread_t t[NUMTHREADS + 1]; InitializeCriticalSection(&pop_count.cs); assert((t[0] = pthread_self()).p != NULL); for (i = 1; i <= NUMTHREADS; i++) { threadbag[i].started = 0; threadbag[i].threadnum = i; assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); } /* * Code to control or munipulate child threads should probably go here. */ Sleep(1000); /* * Standard check that all threads started. */ for (i = 1; i <= NUMTHREADS; i++) { if (!threadbag[i].started) { failed |= !threadbag[i].started; fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); } } assert(!failed); /* * Check any results here. Set "failed" and only print output on failure. */ failed = 0; for (i = 1; i <= NUMTHREADS; i++) { int fail = 0; int result = 0; assert(pthread_join(t[i], (void **) &result) == 0); fail = (result != 0); if (fail) { fprintf(stderr, "Thread %d: started %d: result: %d\n", i, threadbag[i].started, result); } failed = (failed || fail); } assert(!failed); assert(pop_count.i == -(NUMTHREADS)); DeleteCriticalSection(&pop_count.cs); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ int main() { return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/reuse1.c0000644000175000000620000000624511512143043017751 0ustar stevestaff/* * File: reuse1.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: * - Confirm that thread reuse works for joined threads. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" enum { NUMTHREADS = 100 }; static int washere = 0; void * func(void * arg) { washere = 1; return arg; } int main() { pthread_t t, last_t; pthread_attr_t attr; void * result = NULL; int i; assert(pthread_attr_init(&attr) == 0);; assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); washere = 0; assert(pthread_create(&t, &attr, func, NULL) == 0); assert(pthread_join(t, &result) == 0);; assert(result == 0); assert(washere == 1); last_t = t; for (i = 1; i < NUMTHREADS; i++) { washere = 0; assert(pthread_create(&t, &attr, func, (void *) i) == 0); pthread_join(t, &result); assert((int) result == i); assert(washere == 1); /* thread IDs should be unique */ assert(!pthread_equal(t, last_t)); /* thread struct pointers should be the same */ assert(t.p == last_t.p); /* thread handle reuse counter should be different by one */ assert(t.x == last_t.x+1); last_t = t; } return 0; } nyquist-3.05/liblo/pthreads.2/tests/barrier3.c0000644000175000000620000000446311512143043020256 0ustar stevestaff/* * barrier3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a single barrier object with barrier attribute, wait on it, * and then destroy it. * */ #include "test.h" pthread_barrier_t barrier = NULL; static int result = 1; void * func(void * arg) { return (void *) pthread_barrier_wait(&barrier); } int main() { pthread_t t; pthread_barrierattr_t ba; assert(pthread_barrierattr_init(&ba) == 0); assert(pthread_barrierattr_setpshared(&ba, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_barrier_init(&barrier, &ba, 1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == PTHREAD_BARRIER_SERIAL_THREAD); assert(pthread_barrier_destroy(&barrier) == 0); assert(pthread_barrierattr_destroy(&ba) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex6.c0000644000175000000620000000515211512143043017771 0ustar stevestaff/* * mutex6.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test the default (type not set) mutex type. * Should be the same as PTHREAD_MUTEX_NORMAL. * Thread locks mutex twice (recursive lock). * Locking thread should deadlock on second attempt. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_trylock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; /* Should wait here (deadlocked) */ assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); return 0; } int main() { pthread_t t; assert(pthread_mutex_init(&mutex, NULL) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(1000); assert(lockCount == 1); /* * Should succeed even though we don't own the lock * because FAST mutexes don't check ownership. */ assert(pthread_mutex_unlock(&mutex) == 0); Sleep (1000); assert(lockCount == 2); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/spin3.c0000644000175000000620000000442311512143043017575 0ustar stevestaff/* * spin3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Thread A locks spin - thread B tries to unlock. * This should succeed, but it's undefined behaviour. * */ #include "test.h" static int wasHere = 0; static pthread_spinlock_t spin; void * unlocker(void * arg) { int expectedResult = (int) arg; wasHere++; assert(pthread_spin_unlock(&spin) == expectedResult); wasHere++; return NULL; } int main() { pthread_t t; wasHere = 0; assert(pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE) == 0); assert(pthread_spin_lock(&spin) == 0); assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); assert(pthread_join(t, NULL) == 0); assert(pthread_spin_unlock(&spin) == EPERM); assert(pthread_spin_destroy(&spin) == 0); assert(wasHere == 2); return 0; } nyquist-3.05/liblo/pthreads.2/tests/rwlock3.c0000644000175000000620000000431611512143043020126 0ustar stevestaff/* * rwlock3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Declare a static rwlock object, wrlock it, trywrlock it, * and then unlock it again. * * Depends on API functions: * pthread_rwlock_wrlock() * pthread_rwlock_trywrlock() * pthread_rwlock_unlock() */ #include "test.h" pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; static int washere = 0; void * func(void * arg) { assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); washere = 1; return 0; } int main() { pthread_t t; assert(pthread_rwlock_wrlock(&rwlock1) == 0); assert(pthread_create(&t, NULL, func, NULL) == 0); Sleep(2000); assert(pthread_rwlock_unlock(&rwlock1) == 0); assert(washere == 1); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex8.c0000644000175000000620000000417211512143043017774 0ustar stevestaff/* * mutex8.c * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 Ben Elliston and Ross Johnson * Copyright (C) 1999,2000,2001 Ross Johnson * * Contact Email: rpj@ise.canberra.edu.au * * 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.1 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 * * -------------------------------------------------------------------------- * * Test the default (type not set) mutex type exercising timedlock. * Thread locks mutex, another thread timedlocks the mutex. * Timed thread should timeout. * * Depends on API functions: * pthread_mutex_lock() * pthread_mutex_timedlock() * pthread_mutex_unlock() */ #include "test.h" #include static int lockCount = 0; static pthread_mutex_t mutex; void * locker(void * arg) { struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); lockCount++; return 0; } int main() { pthread_t t; assert(pthread_mutex_init(&mutex, NULL) == 0); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(2000); assert(lockCount == 1); assert(pthread_mutex_unlock(&mutex) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/exception2.c0000644000175000000620000000705011512143043020620 0ustar stevestaff/* * File: exception2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test passing of exceptions out of thread scope. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #if defined(_MSC_VER) || defined(__cplusplus) #if defined(_MSC_VER) && defined(__cplusplus) #include #elif defined(__cplusplus) #include #endif #ifdef __GNUC__ #include #endif #include "test.h" /* * Create NUMTHREADS threads in addition to the Main thread. */ enum { NUMTHREADS = 1 }; void * exceptionedThread(void * arg) { int dummy = 0x1; #if defined(_MSC_VER) && !defined(__cplusplus) RaiseException(dummy, 0, 0, NULL); #elif defined(__cplusplus) throw dummy; #endif return (void *) 100; } int main(int argc, char argv[]) { int i; pthread_t mt; pthread_t et[NUMTHREADS]; if (argc <= 1) { int result; printf("You should see an \"abnormal termination\" message\n"); fflush(stdout); result = system("exception2.exe die"); exit(0); } assert((mt = pthread_self()).p != NULL); for (i = 0; i < NUMTHREADS; i++) { assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0); } Sleep(1000); /* * Success. */ return 0; } #else /* defined(_MSC_VER) || defined(__cplusplus) */ #include int main() { fprintf(stderr, "Test N/A for this compiler environment.\n"); return 0; } #endif /* defined(_MSC_VER) || defined(__cplusplus) */ nyquist-3.05/liblo/pthreads.2/tests/self2.c0000644000175000000620000000401711512143043017553 0ustar stevestaff/* * self2.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test for pthread_self(). * * Depends on API functions: * pthread_create() * pthread_self() * * Implicitly depends on: * pthread_getspecific() * pthread_setspecific() */ #include "test.h" #include static pthread_t me; void * entry(void * arg) { me = pthread_self(); return arg; } int main() { pthread_t t; assert(pthread_create(&t, NULL, entry, NULL) == 0); Sleep(100); assert(pthread_equal(t, me) != 0); /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/cancel9.c0000644000175000000620000001241611512143043020060 0ustar stevestaff/* * File: cancel9.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Test true asynchronous cancelation with Alert driver. * * Test Method (Validation or Falsification): * - * * Requirements Tested: * - Cancel threads, including those blocked on system recources * such as network I/O. * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock * pthread_testcancel, pthread_cancel, pthread_join * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #include void * test_udp (void *arg) { struct sockaddr_in serverAddress; struct sockaddr_in clientAddress; SOCKET UDPSocket; int addr_len; int nbyte, bytes; char buffer[4096]; WORD wsaVersion = MAKEWORD (2, 2); WSADATA wsaData; pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); if (WSAStartup (wsaVersion, &wsaData) != 0) { return NULL; } UDPSocket = socket (AF_INET, SOCK_DGRAM, 0); if ((int)UDPSocket == -1) { printf ("Server: socket ERROR \n"); exit (-1); } serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = INADDR_ANY; serverAddress.sin_port = htons (9003); if (bind (UDPSocket, (struct sockaddr *) &serverAddress, sizeof (struct sockaddr_in))) { printf ("Server: ERROR can't bind UDPSocket"); exit (-1); } addr_len = sizeof (struct sockaddr); nbyte = 512; bytes = recvfrom (UDPSocket, (char *) buffer, nbyte, 0, (struct sockaddr *) &clientAddress, &addr_len); closesocket (UDPSocket); WSACleanup (); return NULL; } void * test_sleep (void *arg) { pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); Sleep (1000); return NULL; } void * test_wait (void *arg) { HANDLE hEvent; DWORD dwEvent; pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); dwEvent = WaitForSingleObject (hEvent, 1000); /* WAIT_IO_COMPLETION */ return NULL; } int main () { pthread_t t; void *result; if (pthread_win32_test_features_np (PTW32_ALERTABLE_ASYNC_CANCEL)) { printf ("Cancel sleeping thread.\n"); assert (pthread_create (&t, NULL, test_sleep, NULL) == 0); /* Sleep for a while; then cancel */ Sleep (100); assert (pthread_cancel (t) == 0); assert (pthread_join (t, &result) == 0); assert (result == PTHREAD_CANCELED && "test_sleep" != NULL); printf ("Cancel waiting thread.\n"); assert (pthread_create (&t, NULL, test_wait, NULL) == 0); /* Sleep for a while; then cancel. */ Sleep (100); assert (pthread_cancel (t) == 0); assert (pthread_join (t, &result) == 0); assert (result == PTHREAD_CANCELED && "test_wait"); printf ("Cancel blocked thread (blocked on network I/O).\n"); assert (pthread_create (&t, NULL, test_udp, NULL) == 0); /* Sleep for a while; then cancel. */ Sleep (100); assert (pthread_cancel (t) == 0); assert (pthread_join (t, &result) == 0); assert (result == PTHREAD_CANCELED && "test_udp" != NULL); } else { printf ("Alertable async cancel not available.\n"); } /* * Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex7n.c0000644000175000000620000000547611512143043020161 0ustar stevestaff/* * mutex7n.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_NORMAL mutex type. * Thread locks then trylocks mutex (attempted recursive lock). * The thread should lock first time and EBUSY second time. * * Depends on API functions: * pthread_create() * pthread_mutexattr_init() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_trylock(&mutex) == EBUSY); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == EPERM); return (void *) 555; } int main() { pthread_t t; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(1000); assert(lockCount == 2); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/benchtest.h0000644000175000000620000000454211512143043020527 0ustar stevestaff/* * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * */ #include "../config.h" enum { OLD_WIN32CS, OLD_WIN32MUTEX }; extern int old_mutex_use; struct old_mutex_t_ { HANDLE mutex; CRITICAL_SECTION cs; }; typedef struct old_mutex_t_ * old_mutex_t; struct old_mutexattr_t_ { int pshared; }; typedef struct old_mutexattr_t_ * old_mutexattr_t; extern BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION); extern HINSTANCE ptw32_h_kernel32; #define PTW32_OBJECT_AUTO_INIT ((void *) -1) void dummy_call(int * a); void interlocked_inc_with_conditionals(int *a); void interlocked_dec_with_conditionals(int *a); int old_mutex_init(old_mutex_t *mutex, const old_mutexattr_t *attr); int old_mutex_lock(old_mutex_t *mutex); int old_mutex_unlock(old_mutex_t *mutex); int old_mutex_trylock(old_mutex_t *mutex); int old_mutex_destroy(old_mutex_t *mutex); /****************************************************************************************/ nyquist-3.05/liblo/pthreads.2/tests/mutex6rs.c0000644000175000000620000000540511512143043020337 0ustar stevestaff/* * mutex6rs.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_RECURSIVE static mutex type. * Thread locks mutex twice (recursive lock). * Both locks and unlocks should succeed. * * Depends on API functions: * pthread_create() * pthread_join() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_unlock() */ #include "test.h" static int lockCount = 0; static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; void * locker(void * arg) { assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_lock(&mutex) == 0); lockCount++; assert(pthread_mutex_unlock(&mutex) == 0); assert(pthread_mutex_unlock(&mutex) == 0); return (void *) 555; } int main() { pthread_t t; int result = 0; assert(mutex == PTHREAD_RECURSIVE_MUTEX_INITIALIZER); assert(pthread_create(&t, NULL, locker, NULL) == 0); assert(pthread_join(t, (void **) &result) == 0); assert(result == 555); assert(lockCount == 2); assert(pthread_mutex_destroy(&mutex) == 0); exit(0); /* Never reached */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/join0.c0000644000175000000620000000403711512143043017561 0ustar stevestaff/* * Test for pthread_join(). * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Depends on API functions: pthread_create(), pthread_exit(). */ #include "test.h" void * func(void * arg) { Sleep(2000); pthread_exit(arg); /* Never reached. */ exit(1); } int main(int argc, char * argv[]) { pthread_t id; int result; /* Create a single thread and wait for it to exit. */ assert(pthread_create(&id, NULL, func, (void *) 123) == 0); assert(pthread_join(id, (void **) &result) == 0); assert(result == 123); /* Success. */ return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex8r.c0000644000175000000620000000515011512143043020153 0ustar stevestaff/* * mutex8r.c * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 Ben Elliston and Ross Johnson * Copyright (C) 1999,2000,2001 Ross Johnson * * Contact Email: rpj@ise.canberra.edu.au * * 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.1 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 * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_RECURSIVE mutex type exercising timedlock. * Thread locks mutex, another thread timedlocks the mutex. * Timed thread should timeout. * * Depends on API functions: * pthread_create() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_timedlock() * pthread_mutex_unlock() */ #include "test.h" #include static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); lockCount++; return 0; } int main() { pthread_t t; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_RECURSIVE); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(2000); assert(lockCount == 1); assert(pthread_mutex_unlock(&mutex) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/mutex8n.c0000644000175000000620000000513611512143043020153 0ustar stevestaff/* * mutex8n.c * * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright (C) 1998 Ben Elliston and Ross Johnson * Copyright (C) 1999,2000,2001 Ross Johnson * * Contact Email: rpj@ise.canberra.edu.au * * 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.1 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 * * -------------------------------------------------------------------------- * * Tests PTHREAD_MUTEX_NORMAL mutex type exercising timedlock. * Thread locks mutex, another thread timedlocks the mutex. * Timed thread should timeout. * * Depends on API functions: * pthread_create() * pthread_mutexattr_init() * pthread_mutexattr_destroy() * pthread_mutexattr_settype() * pthread_mutexattr_gettype() * pthread_mutex_init() * pthread_mutex_destroy() * pthread_mutex_lock() * pthread_mutex_timedlock() * pthread_mutex_unlock() */ #include "test.h" #include static int lockCount = 0; static pthread_mutex_t mutex; static pthread_mutexattr_t mxAttr; void * locker(void * arg) { struct timespec abstime = { 0, 0 }; struct _timeb currSysTime; const DWORD NANOSEC_PER_MILLISEC = 1000000; _ftime(&currSysTime); abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; abstime.tv_sec += 1; assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); lockCount++; return 0; } int main() { pthread_t t; int mxType = -1; assert(pthread_mutexattr_init(&mxAttr) == 0); assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); assert(mxType == PTHREAD_MUTEX_NORMAL); assert(pthread_mutex_init(&mutex, &mxAttr) == 0); assert(pthread_mutex_lock(&mutex) == 0); assert(pthread_create(&t, NULL, locker, NULL) == 0); Sleep(2000); assert(lockCount == 1); assert(pthread_mutex_unlock(&mutex) == 0); return 0; } nyquist-3.05/liblo/pthreads.2/tests/multiPCcaBetter.c0000644000175000000620000002232111512143043021565 0ustar stevestaff/* Session 7. multiPCca.c Lab 7-1 */ /* Maintain a producer thread and several consumer threads */ /* The producer periodically creates checksummed data buffers, */ /* or "message block" which the consumers display as soon */ /* as possible. The conusmers read the NEXT complete */ /* set of data, and each consumer validates the data before */ /* before display. */ /* Consumers are created and cancelled on demand based */ /* user input. */ /* Usage: multiPCca maxconsumer */ #if defined (_MSC_VER) #include #define sleep(i) Sleep(i*1000) #endif #include //#include "errors.h" //#include "utility.h" #include #include #define DATA_SIZE 256 typedef struct msg_block_tag { /* Message block */ pthread_mutex_t mguard; /* Guard the message block */ pthread_cond_t mready; /* Message ready */ pthread_cond_t mok; /* Ok for the producer to produce */ volatile int f_ready; volatile int f_stop; /* ready state flag; producer stopped flag */ volatile int sequence; /* Message block sequence number */ time_t timestamp; int checksum; /* Message contents checksum */ int data[DATA_SIZE]; /* Message Contents */ } msg_block_t; /* The invariant and condition variable predicates are: */ /* Invariant - */ /* f_ready && data is valid */ /* && checksum and timestamp are valid */ /* Condition variable predicate */ /* mready if and only if f_ready and a new message */ /* has just been generated */ /* Single message block, ready to fill with a new message */ struct msg_block_tag mblock = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0, 0 }; void * produce (void *), * consume (void *); void message_fill (msg_block_t *); void message_display (int, msg_block_t *); static volatile int ShutDown = 0; int main (int argc, char * argv[]) { int tstatus, nthread, ithread; int * f_consumer; /* Array of flags to indicate corresponding thread exists */ void *join_result; pthread_t *consume_t; char command [10]; if (argc != 2) { printf ("Usage: multiPCca maxconsumer\n"); return 1; } nthread = atoi(argv[1]); consume_t = calloc (nthread, sizeof(pthread_t)); f_consumer = (int *)calloc (nthread, sizeof(int)); while (!ShutDown) { printf ("Enter command: nc (new consumer), cc (cancel), "); printf ("pr (produce msg), sh (shutdown):"); fflush (stdout); scanf ("%s", command); printf ("Command received: %s.\n", command); fflush (stdout); if (strcmp (command, "nc") == 0) { /* New consumer thread */ /* Look for empty thread slot */ for (ithread = 0; ithread < nthread; ithread++) { if (!f_consumer[ithread]) break; } if (ithread >= nthread) { printf ("Maximum # consumers (%d) already exist\n", nthread); fflush (stdout); continue; } tstatus = pthread_create (&consume_t[ithread], NULL, consume, (void *)ithread); // if (tstatus != 0) // err_abort (tstatus, "Cannot create consumer thread"); f_consumer[ithread] = 1; printf ("Consumer number %d created successfully.\n", ithread); fflush (stdout); } else if (strcmp (command, "cc") == 0) { /* cancel consumer thread */ printf ("Enter consumer number: 0 to %d:", nthread-1); fflush (stdout); scanf ("%d", &ithread); if (ithread < 0 || ithread >= nthread || !f_consumer[ithread]) { printf ("Thread %d does not exist.\n", ithread); fflush (stdout); fflush (stdout); } else { printf ("About to cancel thread # %d.\n", ithread); fflush (stdout); tstatus = pthread_cancel (consume_t[ithread]); printf ("Cancel status: %d. About to join thread # %d\n", tstatus, ithread); fflush (stdout); tstatus = pthread_join (consume_t[ithread], &join_result); printf ("Join status: %d after joining thread # %d. Result: %d\n", tstatus, ithread, (int) join_result); fflush (stdout); f_consumer[ithread] = 0; } continue; } else if (strcmp (command, "pr") == 0) { /* Produce a message */ printf ("About to produce a new message.\n"); fflush (stdout); produce(NULL); /* Note the race to prompt before/after message display */ } else if (strcmp (command, "sh") == 0) { /* shutdown system */ printf ("Shutdown command received\n"); for (ithread = 0; ithread < nthread; ithread++) printf ("Thread #: %d. Flag: %d.\n", ithread, f_consumer[ithread]); fflush (stdout); ShutDown = 1; /* Cancel and join all running threads */ for (ithread = 0; ithread < nthread; ithread++) { printf ("Thread #: %d. Flag: %d.\n", ithread, f_consumer[ithread]); fflush (stdout); if (f_consumer[ithread]) { printf ("About to cancel consumer thread #: %d.\n", ithread); fflush (stdout); tstatus = pthread_cancel (consume_t[ithread]); if (tstatus != 0) printf ("Cannot cancel consumer thread %d", ithread); printf ("About to join consumer thread #: %d.\n", ithread); fflush (stdout); tstatus = pthread_join (consume_t[ithread], &join_result); if (tstatus != 0 || join_result != PTHREAD_CANCELED) printf ("Error joining thread #: %d. tstatus: %d.\n", ithread, tstatus); printf ("Joined consumer thread #: %d.\n", ithread); fflush (stdout); } } fflush (stdout); printf ("All consumer threads cancelled and joined.\n"); fflush (stdout); } else { /* Illegal command */ printf ("Illegal command. %s. Try again\n", command); fflush (stdout); } } free (consume_t); printf ("Producer and consumer threads have terminated\n"); fflush (stdout); return 0; } void * produce (void *arg) /* Producer function. Create new message when called, and notify consumers */ /* The arg is there as this was derived from a thread function. */ { int tstatus = 1; /* Get the buffer, fill it,*/ /* and inform all consumers with a broadcast */ printf ("Entering producer.\n"); fflush (stdout); while (tstatus != 0) { tstatus = pthread_mutex_trylock (&mblock.mguard); printf ("Trylock status: %d\n", tstatus); fflush (stdout); if (tstatus != 0) sleep (1); } message_fill (&mblock); mblock.sequence++; mblock.f_ready = 1; pthread_cond_broadcast (&mblock.mready); printf ("Producer produced one message.\n"); fflush (stdout); pthread_mutex_unlock (&mblock.mguard); return NULL; } /* Mutex cleanup handler used by the consumers */ void free_mutex (void * arg) { int tstatus; printf ("Entering free_mutex cleanup handler.\n"); tstatus = pthread_mutex_unlock ((pthread_mutex_t *)arg); printf ("Unlocked mutex. Status: %d\n", tstatus); fflush (stdout); } /* Cleanup handler for the consumer thread */ void cancel_consumer (void * arg) { int ithread; ithread = (int) arg; printf ("Thread number %d cancellation handler. Curently, does nothing.\n", ithread); fflush (stdout); } void *consume (void *arg) { int ithread, old_state, old_type; struct timespec timeout; timeout.tv_nsec = 0; ithread = (int)arg; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_state); pthread_cleanup_push (cancel_consumer, (void *)ithread); pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old_type); pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &old_state); /* Consume the NEXT message */ do { pthread_testcancel(); pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_state); pthread_mutex_lock (&mblock.mguard); pthread_cleanup_push (free_mutex, &mblock.mguard); pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &old_state); if (!mblock.f_stop) { do { /* Wait for the NEXT message */ pthread_testcancel(); printf ("Thread #: %d about to wait for mready.\n", ithread); fflush (stdout); pthread_cond_wait (&mblock.mready, &mblock.mguard); printf ("Thread #: %d after wait for mready.\n", ithread); fflush (stdout); } while (!mblock.f_ready && !ShutDown); message_display (ithread, &mblock); pthread_testcancel(); } /* Free the mutex through the free_mutex cleanup handler (a macro) */ pthread_cleanup_pop (1); } while (!ShutDown); pthread_cleanup_pop(1); /* NOTE: Try removing this!! Compiler error! Why?? Because it's a macro */ printf ("Consumer number %d is shutting down\n", ithread); fflush (stdout); return NULL; } void message_fill (msg_block_t *mblock) { /* Fill the message buffer, and include checksum and timestamp */ /* This function is called from the producer thread while it */ /* owns the message block mutex */ int i; mblock->checksum = 0; for (i = 0; i < DATA_SIZE; i++) { mblock->data[i] = rand(); mblock->checksum ^= mblock->data[i]; } mblock->timestamp = time(NULL); return; } void message_display (int ithread, msg_block_t *mblock) { /* Display message buffer and timestamp, validate checksum */ /* This function is called from the consumer thread while it */ /* owns the message block mutex */ int i, tcheck = 0; for (i = 0; i < DATA_SIZE; i++) tcheck ^= mblock->data[i]; printf ("\nConsumer thread #: %d\n", ithread); printf ("Message number %d generated at: %s", mblock->sequence, ctime (&(mblock->timestamp))); printf ("First and last entries: %x %x\n", mblock->data[0], mblock->data[DATA_SIZE-1]); fflush (stdout); if (tcheck == mblock->checksum) printf ("GOOD ->Checksum was validated.\n"); else printf ("BAD ->Checksum failed. message was corrupted\n"); fflush (stdout); return; } nyquist-3.05/liblo/pthreads.2/tests/semaphore3.c0000644000175000000620000000602711512143043020611 0ustar stevestaff/* * File: semaphore3.c * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * -------------------------------------------------------------------------- * * Test Synopsis: Verify sem_getvalue returns the correct number of waiters. * - * * Test Method (Validation or Falsification): * - Validation * * Requirements Tested: * - * * Features Tested: * - * * Cases Tested: * - * * Description: * - * * Environment: * - * * Input: * - None. * * Output: * - File name, Line number, and failed expression on failure. * - No output on success. * * Assumptions: * - * * Pass Criteria: * - Process returns zero exit status. * * Fail Criteria: * - Process returns non-zero exit status. */ #include "test.h" #define MAX_COUNT 100 sem_t s; void * thr (void * arg) { assert(sem_wait(&s) == 0); assert(pthread_detach(pthread_self()) == 0); return NULL; } int main() { int value = 0; int i; pthread_t t[MAX_COUNT+1]; assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %d\n", value); fflush(stdout); assert(value == 0); for (i = 1; i <= MAX_COUNT; i++) { assert(pthread_create(&t[i], NULL, thr, NULL) == 0); do { sched_yield(); assert(sem_getvalue(&s, &value) == 0); } while (value != -i); // printf("Value = %d\n", value); fflush(stdout); assert(-value == i); } for (i = MAX_COUNT - 1; i >= 0; i--) { assert(sem_post(&s) == 0); assert(sem_getvalue(&s, &value) == 0); // printf("Value = %d\n", value); fflush(stdout); assert(-value == i); } return 0; } nyquist-3.05/liblo/pthreads.2/ptw32_tkAssocCreate.c0000644000175000000620000000776211512143043021202 0ustar stevestaff/* * ptw32_tkAssocCreate.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int ptw32_tkAssocCreate (ptw32_thread_t * sp, pthread_key_t key) /* * ------------------------------------------------------------------- * This routine creates an association that * is unique for the given (thread,key) combination.The association * is referenced by both the thread and the key. * This association allows us to determine what keys the * current thread references and what threads a given key * references. * See the detailed description * at the beginning of this file for further details. * * Notes: * 1) New associations are pushed to the beginning of the * chain so that the internal ptw32_selfThreadKey association * is always last, thus allowing selfThreadExit to * be implicitly called last by pthread_exit. * 2) * * Parameters: * thread * current running thread. * key * key on which to create an association. * Returns: * 0 - if successful, * ENOMEM - not enough memory to create assoc or other object * EINVAL - an internal error occurred * ENOSYS - an internal error occurred * ------------------------------------------------------------------- */ { ThreadKeyAssoc *assoc; /* * Have to create an association and add it * to both the key and the thread. * * Both key->keyLock and thread->threadLock are locked on * entry to this routine. */ assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); if (assoc == NULL) { return ENOMEM; } assoc->thread = sp; assoc->key = key; /* * Register assoc with key */ assoc->prevThread = NULL; assoc->nextThread = (ThreadKeyAssoc *) key->threads; if (assoc->nextThread != NULL) { assoc->nextThread->prevThread = assoc; } key->threads = (void *) assoc; /* * Register assoc with thread */ assoc->prevKey = NULL; assoc->nextKey = (ThreadKeyAssoc *) sp->keys; if (assoc->nextKey != NULL) { assoc->nextKey->prevKey = assoc; } sp->keys = (void *) assoc; return (0); } /* ptw32_tkAssocCreate */ nyquist-3.05/liblo/pthreads.2/ptw32_relmillisecs.c0000644000175000000620000000721611512143043021130 0ustar stevestaff/* * ptw32_relmillisecs.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef _UWIN //#include #endif #include "pthread.h" #include "implement.h" #ifndef NEED_FTIME #include #endif INLINE DWORD ptw32_relmillisecs (const struct timespec * abstime) { const int64_t NANOSEC_PER_MILLISEC = 1000000; const int64_t MILLISEC_PER_SEC = 1000; DWORD milliseconds; int64_t tmpAbsMilliseconds; int64_t tmpCurrMilliseconds; #ifdef NEED_FTIME struct timespec currSysTime; FILETIME ft; SYSTEMTIME st; #else /* ! NEED_FTIME */ struct _timeb currSysTime; #endif /* NEED_FTIME */ /* * Calculate timeout as milliseconds from current system time. */ /* * subtract current system time from abstime in a way that checks * that abstime is never in the past, or is never equivalent to the * defined INFINITE value (0xFFFFFFFF). * * Assume all integers are unsigned, i.e. cannot test if less than 0. */ tmpAbsMilliseconds = (int64_t)abstime->tv_sec * MILLISEC_PER_SEC; tmpAbsMilliseconds += ((int64_t)abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; /* get current system time */ #ifdef NEED_FTIME GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); /* * GetSystemTimeAsFileTime(&ft); would be faster, * but it does not exist on WinCE */ ptw32_filetime_to_timespec(&ft, &currSysTime); tmpCurrMilliseconds = (int64_t)currSysTime.tv_sec * MILLISEC_PER_SEC; tmpCurrMilliseconds += ((int64_t)currSysTime.tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; #else /* ! NEED_FTIME */ _ftime(&currSysTime); tmpCurrMilliseconds = (int64_t) currSysTime.time * MILLISEC_PER_SEC; tmpCurrMilliseconds += (int64_t) currSysTime.millitm; #endif /* NEED_FTIME */ if (tmpAbsMilliseconds > tmpCurrMilliseconds) { milliseconds = (DWORD) (tmpAbsMilliseconds - tmpCurrMilliseconds); if (milliseconds == INFINITE) { /* Timeouts must be finite */ milliseconds--; } } else { /* The abstime given is in the past */ milliseconds = 0; } return milliseconds; } nyquist-3.05/liblo/pthreads.2/pthread_once.x0000644000175000000620000001620711512143043020062 0ustar stevestaff/* * pthread_once.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" static void PTW32_CDECL ptw32_once_init_routine_cleanup(void * arg) { pthread_once_t * once_control = (pthread_once_t *) arg; /* * Continue to direct new threads into the wait path until the waiter that we * release can reset state to INIT. */ (void) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->state, (LONG)PTW32_ONCE_CANCELLED); if (InterlockedExchangeAdd((LPLONG)&once_control->semaphore, 0L)) /* MBR fence */ { ReleaseSemaphore(once_control->semaphore, 1, NULL); } } int pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) /* * ------------------------------------------------------ * DOCPUBLIC * If any thread in a process with a once_control parameter * makes a call to pthread_once(), the first call will summon * the init_routine(), but subsequent calls will not. The * once_control parameter determines whether the associated * initialization routine has been called. The init_routine() * is complete upon return of pthread_once(). * This function guarantees that one and only one thread * executes the initialization routine, init_routine when * access is controlled by the pthread_once_t control * key. * * pthread_once() is not a cancelation point, but the init_routine * can be. If it's cancelled then the effect on the once_control is * as if pthread_once had never been entered. * * * PARAMETERS * once_control * pointer to an instance of pthread_once_t * * init_routine * pointer to an initialization routine * * * DESCRIPTION * See above. * * RESULTS * 0 success, * EINVAL once_control or init_routine is NULL * * ------------------------------------------------------ */ { int result; int state; HANDLE sema; if (once_control == NULL || init_routine == NULL) { result = EINVAL; goto FAIL0; } else { result = 0; } while ((state = (int) PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)&once_control->state, (PTW32_INTERLOCKED_LONG)PTW32_ONCE_STARTED, (PTW32_INTERLOCKED_LONG)PTW32_ONCE_INIT)) != PTW32_ONCE_DONE) { if (PTW32_ONCE_INIT == state) { #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(ptw32_once_init_routine_cleanup, (void *) once_control); (*init_routine)(); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif (void) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->state, (LONG)PTW32_ONCE_DONE); /* * we didn't create the semaphore. * it is only there if there is someone waiting. */ if (InterlockedExchangeAdd((LPLONG)&once_control->semaphore, 0L)) /* MBR fence */ { ReleaseSemaphore(once_control->semaphore, once_control->numSemaphoreUsers, NULL); } } else { if (1 == InterlockedIncrement((LPLONG)&once_control->numSemaphoreUsers)) // if (!InterlockedExchangeAdd((LPLONG)&once_control->semaphore, 0L)) /* MBR fence */ { sema = CreateSemaphore(NULL, 0, INT_MAX, NULL); if (PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)&once_control->semaphore, (PTW32_INTERLOCKED_LONG)sema, (PTW32_INTERLOCKED_LONG)0)) { CloseHandle(sema); } } /* * If initter was cancelled then state is CANCELLED. * Until state is reset to INIT, all new threads will enter the wait path. * The woken waiter, if it exists, will also re-enter the wait path, but * either it or a new thread will reset state = INIT here, continue around the Wait, * and become the new initter. Any thread that is suspended in the wait path before * this point will hit this check. Any thread suspended between this check and * the Wait will wait on a valid semaphore, and possibly continue through it * if the cancellation handler has incremented (released) it and there were * no waiters. */ (void) PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)&once_control->state, (PTW32_INTERLOCKED_LONG)PTW32_ONCE_INIT, (PTW32_INTERLOCKED_LONG)PTW32_ONCE_CANCELLED); /* * Check 'state' again in case the initting thread has finished * and left before seeing that there was a semaphore. */ if (InterlockedExchangeAdd((LPLONG)&once_control->state, 0L) >= PTW32_ONCE_STARTED) { WaitForSingleObject(once_control->semaphore, INFINITE); } if (0 == InterlockedDecrement((LPLONG)&once_control->numSemaphoreUsers)) { /* we were last */ if ((sema = (HANDLE) PTW32_INTERLOCKED_EXCHANGE((LPLONG)&once_control->semaphore, (LONG)0))) { CloseHandle(sema); } } } } /* * ------------ * Failure Code * ------------ */ FAIL0: return (result); } /* pthread_once */ nyquist-3.05/liblo/pthreads.2/sched_get_priority_max.c0000644000175000000620000001452511512143043022136 0ustar stevestaff/* * sched_get_priority_max.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" /* * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. * * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: * highest priority use smaller numbers) and the following happens: * * sched_get_priority_min() returns 5 * sched_get_priority_max() returns 1 * * The following table shows the base priority levels for combinations * of priority class and priority value in Win32. * * Process Priority Class Thread Priority Level * ----------------------------------------------------------------- * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 17 REALTIME_PRIORITY_CLASS -7 * 18 REALTIME_PRIORITY_CLASS -6 * 19 REALTIME_PRIORITY_CLASS -5 * 20 REALTIME_PRIORITY_CLASS -4 * 21 REALTIME_PRIORITY_CLASS -3 * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 27 REALTIME_PRIORITY_CLASS 3 * 28 REALTIME_PRIORITY_CLASS 4 * 29 REALTIME_PRIORITY_CLASS 5 * 30 REALTIME_PRIORITY_CLASS 6 * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. */ int sched_get_priority_max (int policy) { if (policy < SCHED_MIN || policy > SCHED_MAX) { errno = EINVAL; return -1; } #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) /* WinCE? */ return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); #else /* This is independent of scheduling policy in Win32. */ return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); #endif } nyquist-3.05/liblo/pthreads.2/sem_post.c0000644000175000000620000000721511512143043017232 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_post.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" int sem_post (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function posts a wakeup to a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function posts a wakeup to a semaphore. If there * are waiting threads (or processes), one is awakened; * otherwise, the semaphore value is incremented by one. * * RESULTS * 0 successfully posted semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * ERANGE semaphore count is too big * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; if (s == NULL) { result = EINVAL; } else if ((result = pthread_mutex_lock (&s->lock)) == 0) { /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); result = EINVAL; return -1; } if (s->value < SEM_VALUE_MAX) { #ifdef NEED_SEM if (++s->value <= 0 && !SetEvent(s->sem)) { s->value--; result = EINVAL; } #else if (++s->value <= 0 && !ReleaseSemaphore (s->sem, 1, NULL)) { s->value--; result = EINVAL; } #endif /* NEED_SEM */ } else { result = ERANGE; } (void) pthread_mutex_unlock (&s->lock); } if (result != 0) { errno = result; return -1; } return 0; } /* sem_post */ nyquist-3.05/liblo/pthreads.2/semaphore.h0000644000175000000620000001051511512143043017366 0ustar stevestaff/* * Module: semaphore.h * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined( SEMAPHORE_H ) #define SEMAPHORE_H #undef PTW32_LEVEL #if defined(_POSIX_SOURCE) #define PTW32_LEVEL 0 /* Early POSIX */ #endif #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 #undef PTW32_LEVEL #define PTW32_LEVEL 1 /* Include 1b, 1c and 1d */ #endif #if defined(INCLUDE_NP) #undef PTW32_LEVEL #define PTW32_LEVEL 2 /* Include Non-Portable extensions */ #endif #define PTW32_LEVEL_MAX 3 #if !defined(PTW32_LEVEL) #define PTW32_LEVEL PTW32_LEVEL_MAX /* Include everything */ #endif #if __GNUC__ && ! defined (__declspec) # error Please upgrade your GNU compiler to one that supports __declspec. #endif /* * When building the DLL code, you should define PTW32_BUILD so that * the variables/functions are exported correctly. When using the DLL, * do NOT define PTW32_BUILD, and then the variables/functions will * be imported correctly. */ #ifndef PTW32_STATIC_LIB # ifdef PTW32_BUILD # define PTW32_DLLPORT __declspec (dllexport) # else # define PTW32_DLLPORT __declspec (dllimport) # endif #else # define PTW32_DLLPORT #endif /* * This is a duplicate of what is in the autoconf config.h, * which is only used when building the pthread-win32 libraries. */ #ifndef PTW32_CONFIG_H # if defined(WINCE) # define NEED_ERRNO # define NEED_SEM # endif # if defined(_UWIN) || defined(__MINGW32__) # define HAVE_MODE_T # endif #endif /* * */ #if PTW32_LEVEL >= PTW32_LEVEL_MAX #ifdef NEED_ERRNO #include "need_errno.h" #else #include #endif #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ #define _POSIX_SEMAPHORES #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef HAVE_MODE_T typedef unsigned int mode_t; #endif typedef struct sem_t_ * sem_t; PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, int pshared, unsigned int value); PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, const struct timespec * abstime); PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, int count); PTW32_DLLPORT int __cdecl sem_open (const char * name, int oflag, mode_t mode, unsigned int value); PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); PTW32_DLLPORT int __cdecl sem_unlink (const char * name); PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, int * sval); #ifdef __cplusplus } /* End of extern "C" */ #endif /* __cplusplus */ #undef PTW32_LEVEL #undef PTW32_LEVEL_MAX #endif /* !SEMAPHORE_H */ nyquist-3.05/liblo/pthreads.2/ptw32_timespec.c0000644000175000000620000000632311512143043020250 0ustar stevestaff/* * ptw32_timespec.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifdef NEED_FTIME /* * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds */ #define PTW32_TIMESPEC_TO_FILETIME_OFFSET \ ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 ) INLINE void ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft) /* * ------------------------------------------------------------------- * converts struct timespec * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is * expressed in 100 nanoseconds from Jan 1, 1601, * ------------------------------------------------------------------- */ { *(LONGLONG *) ft = ts->tv_sec * 10000000 + (ts->tv_nsec + 50) / 100 + PTW32_TIMESPEC_TO_FILETIME_OFFSET; } INLINE void ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts) /* * ------------------------------------------------------------------- * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is * expressed in 100 nanoseconds from Jan 1, 1601, * into struct timespec * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. * ------------------------------------------------------------------- */ { ts->tv_sec = (int) ((*(LONGLONG *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000); ts->tv_nsec = (int) ((*(LONGLONG *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET - ((LONGLONG) ts->tv_sec * (LONGLONG) 10000000)) * 100); } #endif /* NEED_FTIME */ nyquist-3.05/liblo/pthreads.2/README.WinCE0000644000175000000620000000033411512143043017054 0ustar stevestaffWinCE port ---------- (See the file WinCE-PORT for a detailed explanation.) Make sure you define "WINCE" amongst your compiler flags (eg. -DWINCE). The config.h file will define all the necessary defines for you. nyquist-3.05/liblo/pthreads.2/CONTRIBUTORS0000644000175000000620000001172611512143043017117 0ustar stevestaffContributors (in approximate order of appearance) [See also the ChangeLog file where individuals are attributed in log entries. Likewise in the FAQ file.] Ben Elliston bje at cygnus dot com Initiated the project; setup the project infrastructure (CVS, web page, etc.); early prototype routines. Ross Johnson rpj at callisto dot canberra dot edu dot au early prototype routines; ongoing project coordination/maintenance; implementation of spin locks and barriers; various enhancements; bug fixes; documentation; testsuite. Robert Colquhoun rjc at trump dot net dot au Early bug fixes. John E. Bossom John dot Bossom at cognos dot com Contributed substantial original working implementation; bug fixes; ongoing guidance and standards interpretation. Anders Norlander anorland at hem2 dot passagen dot se Early enhancements and runtime checking for supported Win32 routines. Tor Lillqvist tml at iki dot fi General enhancements; early bug fixes to condition variables. Scott Lightner scott at curriculum dot com Bug fix. Kevin Ruland Kevin dot Ruland at anheuser-busch dot com Various bug fixes. Mike Russo miker at eai dot com Bug fix. Mark E. Armstrong avail at pacbell dot net Bug fixes. Lorin Hochstein lmh at xiphos dot ca general bug fixes; bug fixes to condition variables. Peter Slacik Peter dot Slacik at tatramed dot sk Bug fixes. Mumit Khan khan at xraylith dot wisc dot edu Fixes to work with Mingw32. Milan Gardian mg at tatramed dot sk Bug fixes and reports/analyses of obscure problems. Aurelio Medina aureliom at crt dot com First implementation of read-write locks. Graham Dumpleton Graham dot Dumpleton at ra dot pad dot otc dot telstra dot com dot au Bug fix in condition variables. Tristan Savatier tristan at mpegtv dot com WinCE port. Erik Hensema erik at hensema dot xs4all dot nl Bug fixes. Rich Peters rpeters at micro-magic dot com Todd Owen towen at lucidcalm dot dropbear dot id dot au Bug fixes to dll loading. Jason Nye jnye at nbnet dot nb dot ca Implementation of async cancelation. Fred Forester fforest at eticomm dot net Kevin D. Clark kclark at cabletron dot com David Baggett dmb at itasoftware dot com Bug fixes. Paul Redondo paul at matchvision dot com Scott McCaskill scott at 3dfx dot com Bug fixes. Jef Gearhart jgearhart at tpssys dot com Bug fix. Arthur Kantor akantor at bexusa dot com Mutex enhancements. Steven Reddie smr at essemer dot com dot au Bug fix. Alexander Terekhov TEREKHOV at de dot ibm dot com Re-implemented and improved read-write locks; (with Louis Thomas) re-implemented and improved condition variables; enhancements to semaphores; enhancements to mutexes; new mutex implementation in 'futex' style; suggested a robust implementation of pthread_once similar to that implemented by V.Kliathcko; system clock change handling re CV timeouts; bug fixes. Thomas Pfaff tpfaff at gmx dot net Changes to make C version usable with C++ applications; re-implemented mutex routines to avoid Win32 mutexes and TryEnterCriticalSection; procedure to fix Mingw32 thread-safety issues. Franco Bez franco dot bez at gmx dot de procedure to fix Mingw32 thread-safety issues. Louis Thomas lthomas at arbitrade dot com (with Alexander Terekhov) re-implemented and improved condition variables. David Korn dgk at research dot att dot com Ported to UWIN. Phil Frisbie, Jr. phil at hawksoft dot com Bug fix. Ralf Brese Ralf dot Brese at pdb4 dot siemens dot de Bug fix. prionx at juno dot com prionx at juno dot com Bug fixes. Max Woodbury mtew at cds dot duke dot edu POSIX versioning conditionals; reduced namespace pollution; idea to separate routines to reduce statically linked image sizes. Rob Fanner rfanner at stonethree dot com Bug fix. Michael Johnson michaelj at maine dot rr dot com Bug fix. Nicolas Barry boozai at yahoo dot com Bug fixes. Piet van Bruggen pietvb at newbridges dot nl Bug fix. Makoto Kato raven at oldskool dot jp AMD64 port. Panagiotis E. Hadjidoukas peh at hpclab dot ceid dot upatras dot gr Contributed the QueueUserAPCEx package which makes preemptive async cancelation possible. Will Bryant will dot bryant at ecosm dot com Borland compiler patch and makefile. Anuj Goyal anuj dot goyal at gmail dot com Port to Digital Mars compiler. Gottlob Frege gottlobfrege at gmail dot com re-implemented pthread_once (version 2) (pthread_once cancellation added by rpj). Vladimir Kliatchko vladimir at kliatchko dot com reimplemented pthread_once with the same form as described by A.Terekhov (later version 2); implementation of MCS (Mellor-Crummey/Scott) locks. nyquist-3.05/liblo/pthreads.2/pthread_setspecific.c0000644000175000000620000001106611512143043021410 0ustar stevestaff/* * pthread_setspecific.c * * Description: * POSIX thread functions which implement thread-specific data (TSD). * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_setspecific (pthread_key_t key, const void *value) /* * ------------------------------------------------------ * DOCPUBLIC * This function sets the value of the thread specific * key in the calling thread. * * PARAMETERS * key * an instance of pthread_key_t * value * the value to set key to * * * DESCRIPTION * This function sets the value of the thread specific * key in the calling thread. * * RESULTS * 0 successfully set value * EAGAIN could not set value * ENOENT SERIOUS!! * * ------------------------------------------------------ */ { pthread_t self; int result = 0; if (key != ptw32_selfThreadKey) { /* * Using pthread_self will implicitly create * an instance of pthread_t for the current * thread if one wasn't explicitly created */ self = pthread_self (); if (self.p == NULL) { return ENOENT; } } else { /* * Resolve catch-22 of registering thread with selfThread * key */ ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); if (sp == NULL) { if (value == NULL) { return ENOENT; } self = *((pthread_t *) value); } else { self = sp->ptHandle; } } result = 0; if (key != NULL) { if (self.p != NULL && key->destructor != NULL && value != NULL) { /* * Only require associations if we have to * call user destroy routine. * Don't need to locate an existing association * when setting data to NULL for WIN32 since the * data is stored with the operating system; not * on the association; setting assoc to NULL short * circuits the search. */ ThreadKeyAssoc *assoc; if (pthread_mutex_lock(&(key->keyLock)) == 0) { ptw32_thread_t * sp = (ptw32_thread_t *) self.p; (void) pthread_mutex_lock(&(sp->threadLock)); assoc = (ThreadKeyAssoc *) sp->keys; /* * Locate existing association */ while (assoc != NULL) { if (assoc->key == key) { /* * Association already exists */ break; } assoc = assoc->nextKey; } /* * create an association if not found */ if (assoc == NULL) { result = ptw32_tkAssocCreate (sp, key); } (void) pthread_mutex_unlock(&(sp->threadLock)); } (void) pthread_mutex_unlock(&(key->keyLock)); } if (result == 0) { if (!TlsSetValue (key->key, (LPVOID) value)) { result = EAGAIN; } } } return (result); } /* pthread_setspecific */ nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_setkind_np.c0000644000175000000620000000333011512143043023355 0ustar stevestaff/* * pthread_mutexattr_setkind_np.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr, int kind) { return pthread_mutexattr_settype (attr, kind); } nyquist-3.05/liblo/pthreads.2/manual/0002755000175000000620000000000011537433130016515 5ustar stevestaffnyquist-3.05/liblo/pthreads.2/manual/sched_get_priority_max.html0000644000175000000620000001121211512143043024123 0ustar stevestaff "SCHED_GET_PRIORITY_MAX"(P) manual page

Reference Index

Table of Contents

Name

sched_get_priority_max, sched_get_priority_min - get priority limits (REALTIME)

Synopsis

#include <sched.h>

int sched_get_priority_max(int policy);
int sched_get_priority_min(int
policy);

Description

The sched_get_priority_max and sched_get_priority_min functions shall return the appropriate maximum or minimum, respectively, for the scheduling policy specified by policy.

The value of policy shall be one of the scheduling policy values defined in <sched.h>.

Return Value

If successful, the sched_get_priority_max and sched_get_priority_min functions shall return the appropriate maximum or minimum values, respectively. If unsuccessful, they shall return a value of -1 and set errno to indicate the error.

Errors

The sched_get_priority_max and sched_get_priority_min functions shall fail if:

EINVAL
The value of the policy parameter does not represent a defined scheduling policy.

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

sched_getscheduler(3) , sched_setscheduler(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <sched.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlock_timedrdlock.html0000644000175000000620000001555111512143043024773 0ustar stevestaff "PTHREAD_RWLOCK_TIMEDRDLOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlock_timedrdlock - lock a read-write lock for reading

Synopsis

#include <pthread.h>
#include <time.h>

int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);

Description

The pthread_rwlock_timedrdlock function shall apply a read lock to the read-write lock referenced by rwlock as in the pthread_rwlock_rdlock(3) function. However, if the lock cannot be acquired without waiting for other threads to unlock the lock, this wait shall be terminated when the specified timeout expires. The timeout shall expire when the absolute time specified by abs_timeout passes, as measured by the clock on which timeouts are based (that is, when the value of that clock equals or exceeds abs_timeout), or if the absolute time specified by abs_timeout has already been passed at the time of the call.

The timespec data type is defined in the <time.h> header. Under no circumstances shall the function fail with a timeout if the lock can be acquired immediately. The validity of the abs_timeout parameter need not be checked if the lock can be immediately acquired.

The calling thread may deadlock if at the time the call is made it holds a write lock on rwlock. The results are undefined if this function is called with an uninitialized read-write lock.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

The pthread_rwlock_timedrdlock function shall return zero if the lock for reading on the read-write lock object referenced by rwlock is acquired. Otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlock_timedrdlock function shall fail if:

ETIMEDOUT
The lock could not be acquired before the specified timeout expired.

The pthread_rwlock_timedrdlock function may fail if:

EAGAIN
The read lock could not be acquired because the maximum number of read locks for lock would be exceeded.
EINVAL
The value specified by rwlock does not refer to an initialized read-write lock object, or the abs_timeout nanosecond value is less than zero or greater than or equal to 1000 million.

This function shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using this function may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlock_rdlock(3) , pthread_rwlock_timedwrlock(3) , pthread_rwlock_tryrdlock(3) , pthread_rwlock_trywrlock(3) , pthread_rwlock_unlock(3) , pthread_rwlock_wrlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>, <time.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_exit.html0000644000175000000620000000416611512143043022062 0ustar stevestaff PTHREAD_EXIT(3) manual page Table of Contents

Name

pthread_exit - terminate the calling thread

Synopsis

#include <pthread.h>

void pthread_exit(void *retval);

Description

pthread_exit terminates the execution of the calling thread. All cleanup handlers that have been set for the calling thread with pthread_cleanup_push(3) are executed in reverse order (the most recently pushed handler is executed first). Finalization functions for thread-specific data are then called for all keys that have non- NULL values associated with them in the calling thread (see pthread_key_create(3) ). Finally, execution of the calling thread is stopped.

The retval argument is the return value of the thread. It can be consulted from another thread using pthread_join(3) .

Return Value

The pthread_exit function never returns.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

See Also

pthread_create(3) , pthread_join(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_cleanup_push.html0000644000175000000620000001600211512143043023567 0ustar stevestaff PTHREAD_CLEANUP(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_cleanup_push, pthread_cleanup_pop - install and remove cleanup handlers

Synopsis

#include <pthread.h>

void pthread_cleanup_push(void (*routine) (void *), void *arg);

void pthread_cleanup_pop(int execute);

Description

Cleanup handlers are functions that get called when a thread terminates, either by calling pthread_exit(3) or because of cancellation. Cleanup handlers are installed and removed following a stack-like discipline.

The purpose of cleanup handlers is to free the resources that a thread may hold at the time it terminates. In particular, if a thread exits or is cancelled while it owns a locked mutex, the mutex will remain locked forever and prevent other threads from executing normally. The best way to avoid this is, just before locking the mutex, to install a cleanup handler whose effect is to unlock the mutex. Cleanup handlers can be used similarly to free blocks allocated with malloc(3) or close file descriptors on thread termination.

pthread_cleanup_push installs the routine function with argument arg as a cleanup handler. From this point on to the matching pthread_cleanup_pop, the function routine will be called with arguments arg when the thread terminates, either through pthread_exit(3) or by cancellation. If several cleanup handlers are active at that point, they are called in LIFO order: the most recently installed handler is called first.

pthread_cleanup_pop removes the most recently installed cleanup handler. If the execute argument is not 0, it also executes the handler, by calling the routine function with arguments arg. If the execute argument is 0, the handler is only removed but not executed.

Matching pairs of pthread_cleanup_push and pthread_cleanup_pop must occur in the same function, at the same level of block nesting. Actually, pthread_cleanup_push and pthread_cleanup_pop are macros, and the expansion of pthread_cleanup_push introduces an open brace { with the matching closing brace } being introduced by the expansion of the matching pthread_cleanup_pop.

Return Value

None.

Errors

None.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>
Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_exit(3) , pthread_cancel(3) , pthread_setcanceltype(3) .

Example

Here is how to lock a mutex mut in such a way that it will be unlocked if the thread is canceled while mut is locked:
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);
Equivalently, the last two lines can be replaced by
pthread_cleanup_pop(1);
Notice that the code above is safe only in deferred cancellation mode (see pthread_setcanceltype(3) ). In asynchronous cancellation mode, a cancellation can occur between pthread_cleanup_push and pthread_mutex_lock, or between pthread_mutex_unlock and pthread_cleanup_pop, resulting in both cases in the thread trying to unlock a mutex not locked by the current thread. This is the main reason why asynchronous cancellation is difficult to use.
If the code above must also work in asynchronous cancellation mode, then it must switch to deferred mode for locking and unlocking the mutex:
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_cleanup_pop(1);
pthread_setcanceltype(oldtype, NULL);

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_barrierattr_setpshared.html0000644000175000000620000001601011512143043025643 0ustar stevestaff "PTHREAD_BARRIERATTR_GETPSHARED"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_barrierattr_getpshared, pthread_barrierattr_setpshared - get and set the process-shared attribute of the barrier attributes object (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

int pthread_barrierattr_getpshared(const pthread_barrierattr_t * restrict attr, int *restrict pshared);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *
attr, int pshared);

Description

The pthread_barrierattr_getpshared function shall obtain the value of the process-shared attribute from the attributes object referenced by attr. The pthread_barrierattr_setpshared function shall set the process-shared attribute in an initialized attributes object referenced by attr.

The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit a barrier to be operated upon by any thread that has access to the memory where the barrier is allocated. If the process-shared attribute is PTHREAD_PROCESS_PRIVATE, the barrier shall only be operated upon by threads created within the same process as the thread that initialized the barrier; if threads of different processes attempt to operate on such a barrier, the behavior is undefined. The default value of the attribute shall be PTHREAD_PROCESS_PRIVATE. Both constants PTHREAD_PROCESS_SHARED and PTHREAD_PROCESS_PRIVATE are defined in <pthread.h>.

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines are implemented but that the process shared attribute is not supported.

Additional attributes, their default values, and the names of the associated functions to get and set those attribute values are implementation-defined.

Return Value

If successful, the pthread_barrierattr_getpshared function shall return zero and store the value of the process-shared attribute of attr into the object referenced by the pshared parameter. Otherwise, an error number shall be returned to indicate the error.

If successful, the pthread_barrierattr_setpshared function shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

These functions may fail if:

EINVAL
The value specified by attr is invalid.
The pthread_barrierattr_setpshared function may fail if:
EINVAL
The new value specified for the process-shared attribute is not one of the legal values PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE.
ENOSYS
The value specified by attr was PTHREAD_PROCESS_SHARED (Pthreads-w32).

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

The pthread_barrierattr_getpshared and pthread_barrierattr_setpshared functions are part of the Barriers option and need not be provided on all implementations.

Pthreads-w32 defines _POSIX_BARRIERS and _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines are implemented and may be used, but do not support the process shared option.

Rationale

None.

Future Directions

None.

See Also

pthread_barrier_destroy(3) , pthread_barrierattr_destroy(3) , pthread_barrierattr_init(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_cancel.html0000644000175000000620000002262611512143043022337 0ustar stevestaff PTHREAD_CANCEL(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_cancel, pthread_setcancelstate, pthread_setcanceltype, pthread_testcancel - thread cancellation

Synopsis

#include <pthread.h>

int pthread_cancel(pthread_t thread);

int pthread_setcancelstate(int state, int *oldstate);

int pthread_setcanceltype(int type, int *oldtype);

void pthread_testcancel(void);

Description

Cancellation is the mechanism by which a thread can terminate the execution of another thread. More precisely, a thread can send a cancellation request to another thread. Depending on its settings, the target thread can then either ignore the request, honor it immediately, or defer it until it reaches a cancellation point.

When a thread eventually honors a cancellation request, it performs as if pthread_exit(PTHREAD_CANCELED) has been called at that point: all cleanup handlers are executed in reverse order, destructor functions for thread-specific data are called, and finally the thread stops executing with the return value PTHREAD_CANCELED. See pthread_exit(3) for more information.

pthread_cancel sends a cancellation request to the thread denoted by the thread argument.

pthread_setcancelstate changes the cancellation state for the calling thread -- that is, whether cancellation requests are ignored or not. The state argument is the new cancellation state: either PTHREAD_CANCEL_ENABLE to enable cancellation, or PTHREAD_CANCEL_DISABLE to disable cancellation (cancellation requests are ignored). If oldstate is not NULL, the previous cancellation state is stored in the location pointed to by oldstate, and can thus be restored later by another call to pthread_setcancelstate.

pthread_setcanceltype changes the type of responses to cancellation requests for the calling thread: asynchronous (immediate) or deferred. The type argument is the new cancellation type: either PTHREAD_CANCEL_ASYNCHRONOUS to cancel the calling thread as soon as the cancellation request is received, or PTHREAD_CANCEL_DEFERRED to keep the cancellation request pending until the next cancellation point. If oldtype is not NULL, the previous cancellation state is stored in the location pointed to by oldtype, and can thus be restored later by another call to pthread_setcanceltype.

Pthreads-w32 provides two levels of support for PTHREAD_CANCEL_ASYNCHRONOUS: full and partial. Full support requires an additional DLL and driver be installed on the Windows system (see the See Also section below) that allows blocked threads to be cancelled immediately. Partial support means that the target thread will not cancel until it resumes execution naturally. Partial support is provided if either the DLL or the driver are not automatically detected by the pthreads-w32 library at run-time.

Threads are always created by pthread_create(3) with cancellation enabled and deferred. That is, the initial cancellation state is PTHREAD_CANCEL_ENABLE and the initial type is PTHREAD_CANCEL_DEFERRED.

Cancellation points are those points in the program execution where a test for pending cancellation requests is performed and cancellation is executed if positive. The following POSIX threads functions are cancellation points:

pthread_join(3)
pthread_cond_wait(3)
pthread_cond_timedwait(3)
pthread_testcancel(3)
sem_wait(3)
sem_timedwait(3)
sigwait(3)

Pthreads-w32 provides two functions to enable additional cancellation points to be created in user functions that block on Win32 HANDLEs:

pthreadCancelableWait()
pthreadCancelableTimedWait()

All other POSIX threads functions are guaranteed not to be cancellation points. That is, they never perform cancellation in deferred cancellation mode.

pthread_testcancel does nothing except testing for pending cancellation and executing it. Its purpose is to introduce explicit checks for cancellation in long sequences of code that do not call cancellation point functions otherwise.

Return Value

pthread_cancel, pthread_setcancelstate and pthread_setcanceltype return 0 on success and a non-zero error code on error.

Errors

pthread_cancel returns the following error code on error:

ESRCH
no thread could be found corresponding to that specified by the thread ID.

pthread_setcancelstate returns the following error code on error:

EINVAL
the state argument is not
PTHREAD_CANCEL_ENABLE nor PTHREAD_CANCEL_DISABLE

pthread_setcanceltype returns the following error code on error:

EINVAL
the type argument is not
PTHREAD_CANCEL_DEFERRED nor PTHREAD_CANCEL_ASYNCHRONOUS

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_exit(3) , pthread_cleanup_push(3) , pthread_cleanup_pop(3) , Pthreads-w32 package README file 'Prerequisites' section.

Bugs

POSIX specifies that a number of system calls (basically, all system calls that may block, such as read(2) , write(2) , wait(2) , etc.) and library functions that may call these system calls (e.g. fprintf(3) ) are cancellation points. Pthreads-win32 is not integrated enough with the C library to implement this, and thus none of the C library functions is a cancellation point.

A workaround for these calls is to temporarily switch to asynchronous cancellation (assuming full asynchronous cancellation support is installed). So, checking for cancellation during a read system call, for instance, can be achieved as follows:



pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldCancelType);
read(fd, buffer, length);
pthread_setcanceltype(oldCancelType, NULL);

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlock_wrlock.html0000644000175000000620000001513311512143043023767 0ustar stevestaff "PTHREAD_RWLOCK_TRYWRLOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlock_trywrlock, pthread_rwlock_wrlock - lock a read-write lock object for writing

Synopsis

#include <pthread.h>

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *
rwlock);

Description

The pthread_rwlock_trywrlock function shall apply a write lock like the pthread_rwlock_wrlock function, with the exception that the function shall fail if any thread currently holds rwlock (for reading or writing).

The pthread_rwlock_wrlock function shall apply a write lock to the read-write lock referenced by rwlock. The calling thread acquires the write lock if no other thread (reader or writer) holds the read-write lock rwlock. Otherwise, the thread shall block until it can acquire the lock. The calling thread may deadlock if at the time the call is made it holds the read-write lock (whether a read or write lock).

Pthreads-win32 does not prefer either writers or readers in acquiring the lock – all threads enter a single prioritised FIFO queue. While this may not be optimally efficient for some applications, it does ensure that one type does not starve the other.

Results are undefined if any of these functions are called with an uninitialized read-write lock.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

The pthread_rwlock_trywrlock function shall return zero if the lock for writing on the read-write lock object referenced by rwlock is acquired. Otherwise, an error number shall be returned to indicate the error.

If successful, the pthread_rwlock_wrlock function shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlock_trywrlock function shall fail if:

EBUSY
The read-write lock could not be acquired for writing because it was already locked for reading or writing.

The pthread_rwlock_trywrlock and pthread_rwlock_wrlock functions may fail if:

EINVAL
The value specified by rwlock does not refer to an initialized read-write lock object.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using these functions may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlock_rdlock(3) , pthread_rwlock_timedrdlock(3) , pthread_rwlock_timedwrlock(3) , pthread_rwlock_tryrdlock(3) , pthread_rwlock_unlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlockattr_init.html0000644000175000000620000001354511512143043024331 0ustar stevestaff "PTHREAD_RWLOCKATTR_DESTROY"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlockattr_destroy, pthread_rwlockattr_init - destroy and initialize the read-write lock attributes object

Synopsis

#include <pthread.h>

int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_init(pthread_rwlockattr_t *
attr);

Description

The pthread_rwlockattr_destroy function shall destroy a read-write lock attributes object. A destroyed attr attributes object can be reinitialized using pthread_rwlockattr_init ; the results of otherwise referencing the object after it has been destroyed are undefined. An implementation may cause pthread_rwlockattr_destroy to set the object referenced by attr to an invalid value.

The pthread_rwlockattr_init function shall initialize a read-write lock attributes object attr with the default value for all of the attributes defined by the implementation.

Results are undefined if pthread_rwlockattr_init is called specifying an already initialized attr attributes object.

After a read-write lock attributes object has been used to initialize one or more read-write locks, any function affecting the attributes object (including destruction) shall not affect any previously initialized read-write locks.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

If successful, the pthread_rwlockattr_destroy and pthread_rwlockattr_init functions shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlockattr_destroy function may fail if:

EINVAL
The value specified by attr is invalid.

The pthread_rwlockattr_init function shall fail if:

ENOMEM
Insufficient memory exists to initialize the read-write lock attributes object.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlockattr_getpshared(3) , pthread_rwlockattr_setpshared(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_mutex_init.html0000644000175000000620000003103611512143043023272 0ustar stevestaff PTHREAD_MUTEX(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_mutex_init, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_timedlock, pthread_mutex_unlock, pthread_mutex_destroy - operations on mutexes

Synopsis

#include <pthread.h>

#include <time.h>

pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;

pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;

pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER;

pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

Description

A mutex is a MUTual EXclusion device, and is useful for protecting shared data structures from concurrent modifications, and implementing critical sections and monitors.

A mutex has two possible states: unlocked (not owned by any thread), and locked (owned by one thread). A mutex can never be owned by two different threads simultaneously. A thread attempting to lock a mutex that is already locked by another thread is suspended until the owning thread unlocks the mutex first.

pthread_mutex_init initializes the mutex object pointed to by mutex according to the mutex attributes specified in mutexattr. If mutexattr is NULL, default attributes are used instead.

The type of a mutex determines whether it can be locked again by a thread that already owns it. The default type is “normal”. See pthread_mutexattr_init(3) for more information on mutex attributes.

Variables of type pthread_mutex_t can also be initialized statically, using the constants PTHREAD_MUTEX_INITIALIZER (for normal “fast” mutexes), PTHREAD_RECURSIVE_MUTEX_INITIALIZER (for recursive mutexes), and PTHREAD_ERRORCHECK_MUTEX_INITIALIZER (for error checking mutexes). In the Pthreads-w32 implementation, an application should still call pthread_mutex_destroy at some point to ensure that any resources consumed by the mutex are released.

pthread_mutex_lock locks the given mutex. If the mutex is currently unlocked, it becomes locked and owned by the calling thread, and pthread_mutex_lock returns immediately. If the mutex is already locked by another thread, pthread_mutex_lock suspends the calling thread until the mutex is unlocked.

If the mutex is already locked by the calling thread, the behavior of pthread_mutex_lock depends on the type of the mutex. If the mutex is of the “normal” type, the calling thread is suspended until the mutex is unlocked, thus effectively causing the calling thread to deadlock. If the mutex is of the ‘‘error checking’’ type, pthread_mutex_lock returns immediately with the error code EDEADLK. If the mutex is of the ‘‘recursive’’ type, pthread_mutex_lock succeeds and returns immediately, recording the number of times the calling thread has locked the mutex. An equal number of pthread_mutex_unlock operations must be performed before the mutex returns to the unlocked state.

pthread_mutex_trylock behaves identically to pthread_mutex_lock, except that it does not block the calling thread if the mutex is already locked by another thread (or by the calling thread in the case of a “normal” mutex). Instead, pthread_mutex_trylock returns immediately with the error code EBUSY.

pthread_mutex_timedlock behaves identically to pthread_mutex_lock, except that if it cannot acquire the lock before the abs_timeout time, the call returns with the error code ETIMEDOUT. If the mutex can be locked immediately it is, and the abs_timeout parameter is ignored.

pthread_mutex_unlock unlocks the given mutex. The mutex is assumed to be locked and owned by the calling thread on entrance to pthread_mutex_unlock. If the mutex is of the “normal” type, pthread_mutex_unlock always returns it to the unlocked state. If it is of the ‘‘recursive’’ type, it decrements the locking count of the mutex (number of pthread_mutex_lock operations performed on it by the calling thread), and only when this count reaches zero is the mutex actually unlocked.

On ‘‘error checking’’ mutexes, pthread_mutex_unlock actually checks at run-time that the mutex is locked on entrance, and that it was locked by the same thread that is now calling pthread_mutex_unlock. If these conditions are not met, an error code is returned and the mutex remains unchanged. ‘‘Normal’’ mutexes perform no such checks, thus allowing a locked mutex to be unlocked by a thread other than its owner. This is non-portable behavior and is not meant to be used as a feature.

pthread_mutex_destroy destroys a mutex object, freeing the resources it might hold. The mutex must be unlocked on entrance.

Cancellation

None of the mutex functions is a cancellation point, not even pthread_mutex_lock, in spite of the fact that it can suspend a thread for arbitrary durations. This way, the status of mutexes at cancellation points is predictable, allowing cancellation handlers to unlock precisely those mutexes that need to be unlocked before the thread stops executing. Consequently, threads using deferred cancellation should never hold a mutex for extended periods of time.

Async-signal Safety

The mutex functions are not async-signal safe. What this means is that they should not be called from a signal handler. In particular, calling pthread_mutex_lock or pthread_mutex_unlock from a signal handler may deadlock the calling thread.

Return Value

pthread_mutex_init always returns 0. The other mutex functions return 0 on success and a non-zero error code on error.

Errors

The pthread_mutex_lock function returns the following error code on error:

EINVAL
the mutex has not been properly initialized.
EDEADLK
the mutex is already locked by the calling thread (‘‘error checking’’ mutexes only).

The pthread_mutex_trylock function returns the following error codes on error:

EBUSY
the mutex could not be acquired because it was currently locked.
EINVAL
the mutex has not been properly initialized.

The pthread_mutex_timedlock function returns the following error codes on error:

ETIMEDOUT
the mutex could not be acquired before the abs_timeout time arrived.
EINVAL
the mutex has not been properly initialized.

The pthread_mutex_unlock function returns the following error code on error:

EINVAL
the mutex has not been properly initialized.
EPERM
the calling thread does not own the mutex (‘‘error checking’’ mutexes only).

The pthread_mutex_destroy function returns the following error code on error:

EBUSY
the mutex is currently locked.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_mutexattr_init(3) , pthread_mutexattr_settype(3) , pthread_cancel(3) .

Example

A shared global variable x can be protected by a mutex as follows:

int x;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
All accesses and modifications to x should be bracketed by calls to pthread_mutex_lock and pthread_mutex_unlock as follows:
pthread_mutex_lock(&mut);
/* operate on x */
pthread_mutex_unlock(&mut);

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_spin_unlock.html0000644000175000000620000001212511512143043023427 0ustar stevestaff "PTHREAD_SPIN_UNLOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_spin_unlock - unlock a spin lock object (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

int pthread_spin_unlock(pthread_spinlock_t *lock);

Description

The pthread_spin_unlock function shall release the spin lock referenced by lock which was locked via the pthread_spin_lock(3) or pthread_spin_trylock(3) functions. If there are threads spinning on the lock when pthread_spin_unlock is called, the lock becomes available and an unspecified spinning thread shall acquire the lock.

Pthreads-w32 does not check ownership of the lock and it is therefore possible for a thread other than the locker to unlock the spin lock. This is not a feature that should be exploited.

The results are undefined if this function is called with an uninitialized thread spin lock.

Return Value

Upon successful completion, the pthread_spin_unlock function shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_spin_unlock function may fail if:

EINVAL
An invalid argument was specified.

This function shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Pthreads-w32 does not check ownership of the lock and it is therefore possible for a thread other than the locker to unlock the spin lock. This is not a feature that should be exploited.

Rationale

None.

Future Directions

None.

See Also

pthread_spin_destroy(3) , pthread_spin_lock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlock_timedwrlock.html0000644000175000000620000001530011512143043025006 0ustar stevestaff "PTHREAD_RWLOCK_TIMEDWRLOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlock_timedwrlock - lock a read-write lock for writing

Synopsis

#include <pthread.h>
#include <time.h>

int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);

Description

The pthread_rwlock_timedwrlock function shall apply a write lock to the read-write lock referenced by rwlock as in the pthread_rwlock_wrlock(3) function. However, if the lock cannot be acquired without waiting for other threads to unlock the lock, this wait shall be terminated when the specified timeout expires. The timeout shall expire when the absolute time specified by abs_timeout passes, as measured by the clock on which timeouts are based (that is, when the value of that clock equals or exceeds abs_timeout), or if the absolute time specified by abs_timeout has already been passed at the time of the call.

The timespec data type is defined in the <time.h> header. Under no circumstances shall the function fail with a timeout if the lock can be acquired immediately. The validity of the abs_timeout parameter need not be checked if the lock can be immediately acquired.

The calling thread may deadlock if at the time the call is made it holds the read-write lock. The results are undefined if this function is called with an uninitialized read-write lock.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

The pthread_rwlock_timedwrlock function shall return zero if the lock for writing on the read-write lock object referenced by rwlock is acquired. Otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlock_timedwrlock function shall fail if:

ETIMEDOUT
The lock could not be acquired before the specified timeout expired.

The pthread_rwlock_timedwrlock function may fail if:

EINVAL
The value specified by rwlock does not refer to an initialized read-write lock object, or the abs_timeout nanosecond value is less than zero or greater than or equal to 1000 million.

This function shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using this function may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlock_rdlock(3) , pthread_rwlock_timedrdlock(3) , pthread_rwlock_tryrdlock(3) , pthread_rwlock_trywrlock(3) , pthread_rwlock_unlock(3) , pthread_rwlock_wrlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>, <time.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlockattr_setpshared.html0000644000175000000620000001555211512143043025530 0ustar stevestaff "PTHREAD_RWLOCKATTR_GETPSHARED"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared - get and set the process-shared attribute of the read-write lock attributes object

Synopsis

#include <pthread.h>

int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * restrict attr, int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *
attr, int pshared);

Description

The pthread_rwlockattr_getpshared function shall obtain the value of the process-shared attribute from the initialized attributes object referenced by attr. The pthread_rwlockattr_setpshared function shall set the process-shared attribute in an initialized attributes object referenced by attr.

The process-shared attribute shall be set to PTHREAD_PROCESS_SHARED to permit a read-write lock to be operated upon by any thread that has access to the memory where the read-write lock is allocated, even if the read-write lock is allocated in memory that is shared by multiple processes. If the process-shared attribute is PTHREAD_PROCESS_PRIVATE, the read-write lock shall only be operated upon by threads created within the same process as the thread that initialized the read-write lock; if threads of differing processes attempt to operate on such a read-write lock, the behavior is undefined. The default value of the process-shared attribute shall be PTHREAD_PROCESS_PRIVATE.

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines are implemented but they do not support the process shared option.

Additional attributes, their default values, and the names of the associated functions to get and set those attribute values are implementation-defined.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

Upon successful completion, the pthread_rwlockattr_getpshared function shall return zero and store the value of the process-shared attribute of attr into the object referenced by the pshared parameter. Otherwise, an error number shall be returned to indicate the error.

If successful, the pthread_rwlockattr_setpshared function shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlockattr_getpshared and pthread_rwlockattr_setpshared functions may fail if:

EINVAL
The value specified by attr is invalid.

The pthread_rwlockattr_setpshared function may fail if:

EINVAL
The new value specified for the attribute is outside the range of legal values for that attribute.
ENOTSUP
The new value specified for the attribute is PTHREAD_PROCESS_SHARED.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlockattr_destroy(3) , pthread_rwlockattr_init(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_delay_np.html0000644000175000000620000000613311512143043022700 0ustar stevestaff PTHREAD_DELAY_NP manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_delay_np – suspend the thread for a specified period

Synopsis

#include <pthread.h>

int pthread_delay_np (const struct timespec *interval);

Description

pthread_delay_np causes a thread to delay execution for a specific period of time. This period ends at the current time plus the specified interval. The routine will not return before the end of the period is reached, but may return an arbitrary amount of time after the period has gone by. This can be due to system load, thread priorities, and system timer granularity.

Specifying an interval of zero (0) seconds and zero (0) nanoseconds is allowed and can be used to force the thread to give up the processor or to deliver a pending cancellation request.

Cancellation

pthread_delay_np is a cancellation point.

Return Value

If an error condition occurs, pthread_delay_np returns an integer value indicating the type of error.

Errors

The pthread_delay_np function returns the following error code on error:

EINVAL

The value specified by interval is invalid.

Author

Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_attr_setstacksize.html0000644000175000000620000001254111512143043024653 0ustar stevestaff "PTHREAD_ATTR_GETSTACKSIZE"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_attr_getstacksize, pthread_attr_setstacksize - get and set the stacksize attribute

Synopsis

#include <pthread.h>

int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize);
int pthread_attr_setstacksize(pthread_attr_t *
attr, size_t stacksize);

Description

The pthread_attr_getstacksize and pthread_attr_setstacksize functions, respectively, shall get and set the thread creation stacksize attribute in the attr object.

The stacksize attribute shall define the minimum stack size (in bytes) allocated for the created threads stack.

Pthreads-w32 defines _POSIX_THREAD_ATTR_STACKSIZE in pthread.h to indicate that these routines are implemented and may be used to set or get the stack size.

Default value: 0 (in Pthreads-w32 a value of 0 means the stack will grow as required)

Return Value

Upon successful completion, pthread_attr_getstacksize and pthread_attr_setstacksize shall return a value of 0; otherwise, an error number shall be returned to indicate the error.

The pthread_attr_getstacksize function stores the stacksize attribute value in stacksize if successful.

Errors

The pthread_attr_setstacksize function shall fail if:

EINVAL
The value of stacksize is less than {PTHREAD_STACK_MIN} or exceeds a system-imposed limit.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

pthread_attr_destroy(3) , pthread_attr_getstackaddr(3) , pthread_attr_getdetachstate(3) , pthread_create(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <limits.h>, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_barrier_wait.html0000644000175000000620000001624311512143043023562 0ustar stevestaff "PTHREAD_BARRIER_WAIT"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_barrier_wait - synchronize at a barrier (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

int pthread_barrier_wait(pthread_barrier_t *barrier);

Description

The pthread_barrier_wait function shall synchronize participating threads at the barrier referenced by barrier. The calling thread shall block until the required number of threads have called pthread_barrier_wait specifying the barrier.

When the required number of threads have called pthread_barrier_wait specifying the barrier, the constant PTHREAD_BARRIER_SERIAL_THREAD shall be returned to one unspecified thread and zero shall be returned to each of the remaining threads. At this point, the barrier shall be reset to the state it had as a result of the most recent pthread_barrier_init(3) function that referenced it.

The constant PTHREAD_BARRIER_SERIAL_THREAD is defined in <pthread.h> and its value shall be distinct from any other value returned by pthread_barrier_wait .

The results are undefined if this function is called with an uninitialized barrier.

If a signal is delivered to a thread blocked on a barrier, upon return from the signal handler the thread shall resume waiting at the barrier if the barrier wait has not completed (that is, if the required number of threads have not arrived at the barrier during the execution of the signal handler); otherwise, the thread shall continue as normal from the completed barrier wait. Until the thread in the signal handler returns from it, it is unspecified whether other threads may proceed past the barrier once they have all reached it.

A thread that has blocked on a barrier shall not prevent any unblocked thread that is eligible to use the same processing resources from eventually making forward progress in its execution. Eligibility for processing resources shall be determined by the scheduling policy.

Return Value

Upon successful completion, the pthread_barrier_wait function shall return PTHREAD_BARRIER_SERIAL_THREAD for a single (arbitrary) thread synchronized at the barrier and zero for each of the other threads. Otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_barrier_wait function may fail if:

EINVAL
The value specified by barrier does not refer to an initialized barrier object.

This function shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using this function may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

The pthread_barrier_wait function is part of the Barriers option and need not be provided on all implementations.

Pthreads-w32 defines _POSIX_BARRIERS to indicate that this routine is implemented and may be used.

Rationale

None.

Future Directions

None.

Known Bugs

In pthreads-win32, pthread_barrier_wait may deadlock if the number of running threads able to wait on the barrier object exceeds the value given as the count parameter in pthread_barrier_init(3).

See Also

pthread_barrier_destroy(3), pthread_barrier_init(3), the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_barrierattr_init.html0000644000175000000620000001356211512143043024455 0ustar stevestaff "PTHREAD_BARRIERATTR_DESTROY"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_barrierattr_destroy, pthread_barrierattr_init - destroy and initialize the barrier attributes object (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
int pthread_barrierattr_init(pthread_barrierattr_t *
attr);

Description

The pthread_barrierattr_destroy function shall destroy a barrier attributes object. A destroyed attr attributes object can be reinitialized using pthread_barrierattr_init ; the results of otherwise referencing the object after it has been destroyed are undefined. An implementation may cause pthread_barrierattr_destroy to set the object referenced by attr to an invalid value.

The pthread_barrierattr_init function shall initialize a barrier attributes object attr with the default value for all of the attributes defined by the implementation.

Results are undefined if pthread_barrierattr_init is called specifying an already initialized attr attributes object.

After a barrier attributes object has been used to initialize one or more barriers, any function affecting the attributes object (including destruction) shall not affect any previously initialized barrier.

Return Value

If successful, the pthread_barrierattr_destroy and pthread_barrierattr_init functions shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_barrierattr_destroy function may fail if:

EINVAL
The value specified by attr is invalid.

The pthread_barrierattr_init function shall fail if:

ENOMEM
Insufficient memory exists to initialize the barrier attributes object.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

The pthread_barrierattr_destroy and pthread_barrierattr_init functions are part of the Barriers option and need not be provided on all implementations.

Pthreads-w32 defines _POSIX_BARRIERS to indicate that these routines are implemented and may be used.

Rationale

None.

Future Directions

None.

See Also

pthread_barrierattr_getpshared(3) , pthread_barrierattr_setpshared(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>.

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_key_create.html0000644000175000000620000002200211512143043023211 0ustar stevestaff PTHREAD_SPECIFIC(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_key_create, pthread_key_delete, pthread_setspecific, pthread_getspecific - management of thread-specific data

Synopsis

#include <pthread.h>

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));

int pthread_key_delete(pthread_key_t key);

int pthread_setspecific(pthread_key_t key, const void *pointer);

void * pthread_getspecific(pthread_key_t key);

Description

Programs often need global or static variables that have different values in different threads. Since threads share one memory space, this cannot be achieved with regular variables. Thread-specific data is the POSIX threads answer to this need.

Each thread possesses a private memory block, the thread-specific data area, or TSD area for short. This area is indexed by TSD keys. The TSD area associates values of type void * to TSD keys. TSD keys are common to all threads, but the value associated with a given TSD key can be different in each thread.

For concreteness, the TSD areas can be viewed as arrays of void * pointers, TSD keys as integer indices into these arrays, and the value of a TSD key as the value of the corresponding array element in the calling thread.

When a thread is created, its TSD area initially associates NULL with all keys.

pthread_key_create allocates a new TSD key. The key is stored in the location pointed to by key. There is a limit of PTHREAD_KEYS_MAX on the number of keys allocated at a given time. The value initially associated with the returned key is NULL in all currently executing threads.

The destr_function argument, if not NULL, specifies a destructor function associated with the key. When a thread terminates via pthread_exit or by cancellation, destr_function is called with arguments the value associated with the key in that thread. The destr_function is not called if that value is NULL or the key has been deleted. The order in which destructor functions are called at thread termination time is unspecified.

Before the destructor function is called, the NULL value is associated with the key in the current thread. A destructor function might, however, re-associate non- NULL values to that key or some other key. To deal with this, if after all the destructors have been called for all non- NULL values, there are still some non- NULL values with associated destructors, then the process is repeated.

pthread_key_delete deallocates a TSD key. It does not check whether non- NULL values are associated with that key in the currently executing threads, nor call the destructor function associated with the key.

pthread_setspecific changes the value associated with key in the calling thread, storing the given pointer instead.

pthread_getspecific returns the value currently associated with key in the calling thread.

The routines pthread_setspecific, pthread_getspecific, and pthread_key_delete can be called from destr_function targeting any valid key including the key on which destr_function is currently operating. If pthread_getspecific is called on the key whose thread specific data is being destroyed, the value NULL is returned, unless pthread_setspecific was called previously on that key from within destr_function to set the value to non-NULL. For some implementations the effect of calling pthread_setspecific from within destr_function can be either memory leakage or infinite loops if destr_function has already been called at least PTHREAD_DESTRUCTOR_ITERATIONS times.

Pthreads-w32 stops running key destr_function routines after PTHREAD_DESTRUCTOR_ITERATIONS iterations, even if some non- NULL values with associated descriptors remain. If memory is allocated and associated with a key from within destr_function, that memory may not be reclaimed because that key's destr_function, may not run again.

Return Value

pthread_key_create, pthread_key_delete, and pthread_setspecific return 0 on success and a non-zero error code on failure. If successful, pthread_key_create stores the newly allocated key in the location pointed to by its key argument.

pthread_getspecific returns the value associated with key on success, and NULL on error.

Errors

pthread_key_create returns the following error code on error:

EAGAIN
PTHREAD_KEYS_MAX keys are already allocated
ENOMEM
Insufficient memory to allocate the key.

pthread_key_delete and pthread_setspecific return the following error code on error:

EINVAL
key is not a valid, allocated TSD key

pthread_getspecific returns NULL if key is not a valid, allocated TSD key.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_create(3) , pthread_exit(3) , pthread_testcancel(3) .

Example

The following code fragment allocates a thread-specific array of 100 characters, with automatic reclamation at thread exit:



/* Key for the thread-specific buffer */
static pthread_key_t buffer_key;
/* Once-only initialisation of the key */
static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT;
/* Allocate the thread-specific buffer */
void buffer_alloc(void)
{
  pthread_once(&buffer_key_once, buffer_key_alloc);
  pthread_setspecific(buffer_key, malloc(100));
}
/* Return the thread-specific buffer */
char * get_buffer(void)
{
  return (char *) pthread_getspecific(buffer_key);
}
/* Allocate the key */
static void buffer_key_alloc()
{
  pthread_key_create(&buffer_key, buffer_destroy);
}
/* Free the thread-specific buffer */
static void buffer_destroy(void * buf)
{
  free(buf);
}

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlock_rdlock.html0000644000175000000620000001634611512143043023753 0ustar stevestaff "PTHREAD_RWLOCK_RDLOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlock_rdlock, pthread_rwlock_tryrdlock - lock a read-write lock object for reading

Synopsis

#include <pthread.h>

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

Description

The pthread_rwlock_rdlock function shall apply a read lock to the read-write lock referenced by rwlock. The calling thread acquires the read lock if a writer does not hold the lock and there are no writers blocked on the lock.

Pthreads-win32 does not prefer either writers or readers in acquiring the lock – all threads enter a single prioritised FIFO queue. While this may not be optimally efficient for some applications, it does ensure that one type does not starve the other.

A thread may hold multiple concurrent read locks on rwlock (that is, successfully call the pthread_rwlock_rdlock function n times). If so, the application shall ensure that the thread performs matching unlocks (that is, it calls the pthread_rwlock_unlock(3) function n times).

The pthread_rwlock_tryrdlock function shall apply a read lock as in the pthread_rwlock_rdlock function, with the exception that the function shall fail if the equivalent pthread_rwlock_rdlock call would have blocked the calling thread. In no case shall the pthread_rwlock_tryrdlock function ever block; it always either acquires the lock or fails and returns immediately.

Results are undefined if any of these functions are called with an uninitialized read-write lock.

Pthreads-w32 does not detect deadlock if the thread already owns the lock for writing.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

If successful, the pthread_rwlock_rdlock function shall return zero; otherwise, an error number shall be returned to indicate the error.

The pthread_rwlock_tryrdlock function shall return zero if the lock for reading on the read-write lock object referenced by rwlock is acquired. Otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlock_tryrdlock function shall fail if:

EBUSY
The read-write lock could not be acquired for reading because a writer holds the lock or a writer with the appropriate priority was blocked on it.

The pthread_rwlock_rdlock and pthread_rwlock_tryrdlock functions may fail if:

EINVAL
The value specified by rwlock does not refer to an initialized read-write lock object.
EAGAIN
The read lock could not be acquired because the maximum number of read locks for rwlock has been exceeded.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using these functions may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlock_timedrdlock(3) , pthread_rwlock_timedwrlock(3) , pthread_rwlock_trywrlock(3) , pthread_rwlock_unlock(3) , pthread_rwlock_wrlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_getw32threadhandle_np.html0000644000175000000620000000475011512143043025264 0ustar stevestaff PTHREAD_GETW32THREADHANDLE_NP manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_getw32threadhandle_np – get the Win32 thread handle associated with a thread

Synopsis

#include <pthread.h>

HANDLE pthread_getw32threadhandle_np(pthread_t thread);

Description

Returns the Win32 native thread HANDLE that the POSIX thread thread is running as.

Applications can use the Win32 handle to set Win32 specific attributes of the thread.

Cancellation

None.

Return Value

pthread_getw32threadhandle_np returns the Win32 native thread HANDLE for the specified POSIX thread thread.

Errors

None.

Author

Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/sched_yield.html0000644000175000000620000000737111512143043021657 0ustar stevestaff "SCHED_YIELD"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

sched_yield - yield the processor

Synopsis

#include <sched.h>

int sched_yield(void);

Description

The sched_yield function shall force the running thread to relinquish the processor until it again becomes the head of its thread list. It takes no arguments.

Return Value

The sched_yield function shall return 0 if it completes successfully; otherwise, it shall return a value of -1 and set errno to indicate the error.

Errors

No errors are defined.

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

The Base Definitions volume of IEEE Std 1003.1-2001, <sched.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/ChangeLog0000644000175000000620000000427011512143043020262 0ustar stevestaff2005-05-06 Ross Johnson * PortabilityIssues.html: Was nonPortableIssues.html. * index.html: Updated; add table of contents at top. * *.html: Add Pthreads-win32 header info; add link back to the index page 'index.html'. 2005-05-06 Ross Johnson * index.html: New. * nonPortableIssues.html: New. * pthread_attr_init.html: New. * pthread_attr_setstackaddr.html: New. * pthread_attr_setstacksize.html: New. * pthread_barrierattr_init.html: New. * pthread_barrierattr_setpshared.html: New. * pthread_barrier_init.html: New. * pthread_barrier_wait.html: New. * pthreadCancelableWait.html: New. * pthread_cancel.html: New. * pthread_cleanup_push.html: New. * pthread_condattr_init.html: New. * pthread_condattr_setpshared.html: New. * pthread_cond_init.html: New. * pthread_create.html: New. * pthread_delay_np.html: New. * pthread_detach.html: New. * pthread_equal.html: New. * pthread_exit.html: New. * pthread_getw32threadhandle_np.html: New. * pthread_join.html: New. * pthread_key_create.html: New. * pthread_kill.html: New. * pthread_mutexattr_init.html: New. * pthread_mutexattr_setpshared.html: New. * pthread_mutex_init.html: New. * pthread_num_processors_np.html: New. * pthread_once.html: New. * pthread_rwlockattr_init.html: New. * pthread_rwlockattr_setpshared.html: New. * pthread_rwlock_init.html: New. * pthread_rwlock_rdlock.html: New. * pthread_rwlock_timedrdlock.html: New. * pthread_rwlock_timedwrlock.html: New. * pthread_rwlock_unlock.html: New. * pthread_rwlock_wrlock.html: New. * pthread_self.html: New. * pthread_setcancelstate.html: New. * pthread_setcanceltype.html: New. * pthread_setconcurrency.html: New. * pthread_setschedparam.html: New. * pthread_spin_init.html: New. * pthread_spin_lock.html: New. * pthread_spin_unlock.html: New. * pthread_timechange_handler_np.html: New. * pthread_win32_attach_detach_np.html: New. * pthread_win32_test_features_np.html: New. * sched_get_priority_max.html: New. * sched_getscheduler.html: New. * sched_setscheduler.html: New. * sched_yield.html: New. * sem_init.html: New. nyquist-3.05/liblo/pthreads.2/manual/pthread_setschedparam.html0000644000175000000620000001132611512143043023730 0ustar stevestaff PTHREAD_SETSCHEDPARAM(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_setschedparam, pthread_getschedparam - control thread scheduling

parameters

Synopsis

#include <pthread.h>

int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param);

int pthread_getschedparam(pthread_t target_thread, int *policy, struct sched_param *param);

Description

pthread_setschedparam sets the scheduling parameters for the thread target_thread as indicated by policy and param. policy can be either SCHED_OTHER (regular, non-real-time scheduling), SCHED_RR (real-time, round-robin) or SCHED_FIFO (real-time, first-in first-out). param specifies the scheduling priority for the two real-time policies.

Pthreads-w32 only supports SCHED_OTHER and does not support the real-time scheduling policies SCHED_RR and SCHED_FIFO.

pthread_getschedparam retrieves the scheduling policy and scheduling parameters for the thread target_thread and stores them in the locations pointed to by policy and param, respectively.

Return Value

pthread_setschedparam and pthread_getschedparam return 0 on success and a non-zero error code on error.

Errors

On error, pthread_setschedparam returns the following error codes:

ENOTSUP
policy is not SCHED_OTHER.
EINVAL
One of the arguments is invalid, or the priority value specified by param is not valid for the specified policy.
ESRCH
The target_thread is invalid or has already terminated

On error, pthread_getschedparam returns the following error codes:

ESRCH
the target_thread is invalid or has already terminated

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

sched_setscheduler(2) , sched_getscheduler(2) , sched_getparam(2) , pthread_attr_setschedpolicy(3) , pthread_attr_setschedparam(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/sem_init.html0000644000175000000620000002064611512143043021212 0ustar stevestaff SEMAPHORES(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

sem_init, sem_wait, sem_trywait, sem_post, sem_getvalue, sem_destroy - operations on semaphores

Synopsis

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

int sem_wait(sem_t * sem);

int sem_timedwait(sem_t * sem, const struct timespec *abstime);

int sem_trywait(sem_t * sem);

int sem_post(sem_t * sem);

int sem_post_multiple(sem_t * sem, int number);

int sem_getvalue(sem_t * sem, int * sval);

int sem_destroy(sem_t * sem);

Description

Semaphores are counters for resources shared between threads. The basic operations on semaphores are: increment the counter atomically, and wait until the counter is non-null and decrement it atomically.

sem_init initializes the semaphore object pointed to by sem. The count associated with the semaphore is set initially to value. The pshared argument indicates whether the semaphore is local to the current process ( pshared is zero) or is to be shared between several processes ( pshared is not zero).

Pthreads-w32 currently does not support process-shared semaphores, thus sem_init always returns with error EPERM if pshared is not zero.

sem_wait atomically decrements sem's count if it is greater than 0 and returns immediately or it suspends the calling thread until it can resume following a call to sem_post or sem_post_multiple.

sem_timedwait atomically decrements sem's count if it is greater than 0 and returns immediately, or it suspends the calling thread. If abstime time arrives before the thread can resume following a call to sem_post or sem_post_multiple, then sem_timedwait returns with a return code of -1 after having set errno to ETIMEDOUT. If the call can return without suspending then abstime is not checked.

sem_trywait atomically decrements sem's count if it is greater than 0 and returns immediately, or it returns immediately with a return code of -1 after having set errno to EAGAIN. sem_trywait never blocks.

sem_post either releases one thread if there are any waiting on sem, or it atomically increments sem's count.

sem_post_multiple either releases multiple threads if there are any waiting on sem and/or it atomically increases sem's count. If there are currently n waiters, where n the largest number less than or equal to number, then n waiters are released and sem's count is incremented by number minus n.

sem_getvalue stores in the location pointed to by sval the current count of the semaphore sem. In the Pthreads-w32 implementation: if the value returned in sval is greater than or equal to 0 it was the sem's count at some point during the call to sem_getvalue. If the value returned in sval is less than 0 then it's absolute value represents the number of threads waiting on sem at some point during the call to sem_getvalue. POSIX does not require an implementation of sem_getvalue to return a value in sval that is less than 0, but if it does then it's absolute value must represent the number of waiters.

sem_destroy destroys a semaphore object, freeing the resources it might hold. No threads should be waiting on the semaphore at the time sem_destroy is called.

Cancellation

sem_wait and sem_timedwait are cancellation points.

Async-signal Safety

These routines are not async-cancel safe.

Return Value

All semaphore functions return 0 on success, or -1 on error in which case they write an error code in errno.

Errors

The sem_init function sets errno to the following codes on error:

EINVAL
value exceeds the maximal counter value SEM_VALUE_MAX
ENOSYS
pshared is not zero

The sem_timedwait function sets errno to the following error code on error:

ETIMEDOUT
if abstime arrives before the waiting thread can resume following a call to sem_post or sem_post_multiple.

The sem_trywait function sets errno to the following error code on error:

EAGAIN
if the semaphore count is currently 0

The sem_post and sem_post_multiple functions set errno to the following error code on error:

ERANGE
if after incrementing, the semaphore count would exceed SEM_VALUE_MAX (the semaphore count is left unchanged in this case)

The sem_destroy function sets errno to the following error code on error:

EBUSY
if some threads are currently blocked waiting on the semaphore.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_mutex_init(3) , pthread_cond_init(3) , pthread_cancel(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_timechange_handler_np.html0000644000175000000620000000662011512143043025404 0ustar stevestaff PTHREAD_TIMECHANGE_HANDLER_NP manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_timechange_handler_np – alert timed waiting condition variables to system time changes.

Synopsis

#include <pthread.h>

void * pthread_timechange_handler_np(void * dummy);

Description

To improve tolerance against operator or time service initiated system clock changes.

pthread_timechange_handler_np can be called by an application when it receives a WM_TIMECHANGE message from the system. At present it broadcasts all condition variables so that waiting threads can wake up and re-evaluate their conditions and restart their timed waits if required.

pthread_timechange_handler_np has the same return type and argument type as a thread routine so that it may be called directly through pthread_create(), i.e. as a separate thread. If run as a thread, the return code must be retrieved through pthread_join().

Although the dummy parameter is required it is not used and any value including NULL can be given.

Cancellation

None.

Return Value

pthread_timechange_handler_np returns 0 on success, or an error code.

Errors

The pthread_timechange_handler_np function returns the following error code on error:

EAGAIN

To indicate that not all condition variables were signalled for some reason.

Author

Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_barrier_init.html0000644000175000000620000002064411512143043023561 0ustar stevestaff "PTHREAD_BARRIER_DESTROY"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_barrier_destroy, pthread_barrier_init - destroy and initialize a barrier object (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

int pthread_barrier_destroy(pthread_barrier_t *barrier);
int pthread_barrier_init(pthread_barrier_t *restrict
barrier, const pthread_barrierattr_t *restrict attr, unsigned count);

Description

The pthread_barrier_destroy function shall destroy the barrier referenced by barrier and release any resources used by the barrier. The effect of subsequent use of the barrier is undefined until the barrier is reinitialized by another call to pthread_barrier_init . An implementation may use this function to set barrier to an invalid value. The results are undefined if pthread_barrier_destroy is called when any thread is blocked on the barrier, or if this function is called with an uninitialized barrier.

The pthread_barrier_init function shall allocate any resources required to use the barrier referenced by barrier and shall initialize the barrier with attributes referenced by attr. If attr is NULL, the default barrier attributes shall be used; the effect is the same as passing the address of a default barrier attributes object. The results are undefined if pthread_barrier_init is called when any thread is blocked on the barrier (that is, has not returned from the pthread_barrier_wait(3) call). The results are undefined if a barrier is used without first being initialized. The results are undefined if pthread_barrier_init is called specifying an already initialized barrier.

The count argument specifies the number of threads that must call pthread_barrier_wait(3) before any of them successfully return from the call. The value specified by count must be greater than zero.

If the pthread_barrier_init function fails, the barrier shall not be initialized and the contents of barrier are undefined.

Only the object referenced by barrier may be used for performing synchronization. The result of referring to copies of that object in calls to pthread_barrier_destroy or pthread_barrier_wait(3) is undefined.

Return Value

Upon successful completion, these functions shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_barrier_destroy function may fail if:

EBUSY
The implementation has detected an attempt to destroy a barrier while it is in use (for example, while being used in a pthread_barrier_wait(3) call) by another thread.
EINVAL
The value specified by barrier is invalid.

The pthread_barrier_init function shall fail if:

EAGAIN
The system lacks the necessary resources to initialize another barrier.
EINVAL
The value specified by count is equal to zero.
ENOMEM
Insufficient memory exists to initialize the barrier.

The pthread_barrier_init function may fail if:

EBUSY
The implementation has detected an attempt to reinitialize a barrier while it is in use (for example, while being used in a pthread_barrier_wait(3) call) by another thread.
EINVAL
The value specified by attr is invalid.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

The pthread_barrier_destroy and pthread_barrier_init functions are part of the Barriers option and need not be provided on all implementations.

Pthreads-w32 defines _POSIX_BARRIERS to indicate that these routines are implemented and may be used.

Rationale

None.

Future Directions

None.

Known Bugs

In pthreads-win32, pthread_barrier_wait(3) may deadlock if the number of running threads able to wait on the barrier object exceeds the value given as the count parameter in pthread_barrier_init.

See Also

pthread_barrier_wait(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_setcanceltype.html0000644000175000000620000002273611512143043023757 0ustar stevestaff PTHREAD_CANCEL(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_cancel, pthread_setcancelstate, pthread_setcanceltype, pthread_testcancel - thread cancellation

Synopsis

#include <pthread.h>

int pthread_cancel(pthread_t thread);

int pthread_setcancelstate(int state, int *oldstate);

int pthread_setcanceltype(int type, int *oldtype);

void pthread_testcancel(void);

Description

Cancellation is the mechanism by which a thread can terminate the execution of another thread. More precisely, a thread can send a cancellation request to another thread. Depending on its settings, the target thread can then either ignore the request, honor it immediately, or defer it until it reaches a cancellation point.

When a thread eventually honors a cancellation request, it performs as if pthread_exit(PTHREAD_CANCELED) has been called at that point: all cleanup handlers are executed in reverse order, destructor functions for thread-specific data are called, and finally the thread stops executing with the return value PTHREAD_CANCELED. See pthread_exit(3) for more information.

pthread_cancel sends a cancellation request to the thread denoted by the thread argument.

pthread_setcancelstate changes the cancellation state for the calling thread -- that is, whether cancellation requests are ignored or not. The state argument is the new cancellation state: either PTHREAD_CANCEL_ENABLE to enable cancellation, or PTHREAD_CANCEL_DISABLE to disable cancellation (cancellation requests are ignored). If oldstate is not NULL, the previous cancellation state is stored in the location pointed to by oldstate, and can thus be restored later by another call to pthread_setcancelstate.

pthread_setcanceltype changes the type of responses to cancellation requests for the calling thread: asynchronous (immediate) or deferred. The type argument is the new cancellation type: either PTHREAD_CANCEL_ASYNCHRONOUS to cancel the calling thread as soon as the cancellation request is received, or PTHREAD_CANCEL_DEFERRED to keep the cancellation request pending until the next cancellation point. If oldtype is not NULL, the previous cancellation state is stored in the location pointed to by oldtype, and can thus be restored later by another call to pthread_setcanceltype.

Pthreads-w32 provides two levels of support for PTHREAD_CANCEL_ASYNCHRONOUS: full and partial. Full support requires an additional DLL and driver be installed on the Windows system (see the See Also section below) that allows blocked threads to be cancelled immediately. Partial support means that the target thread will not cancel until it resumes execution naturally. Partial support is provided if either the DLL or the driver are not automatically detected by the pthreads-w32 library at run-time.

Threads are always created by pthread_create(3) with cancellation enabled and deferred. That is, the initial cancellation state is PTHREAD_CANCEL_ENABLE and the initial type is PTHREAD_CANCEL_DEFERRED.

Cancellation points are those points in the program execution where a test for pending cancellation requests is performed and cancellation is executed if positive. The following POSIX threads functions are cancellation points:

pthread_join(3)
pthread_cond_wait(3)
pthread_cond_timedwait(3)
pthread_testcancel(3)
sem_wait(3)
sem_timedwait(3)
sigwait(3) (not supported under Pthreads-w32)

Pthreads-w32 provides two functions to enable additional cancellation points to be created in user functions that block on Win32 HANDLEs:

pthreadCancelableWait()
pthreadCancelableTimedWait()

All other POSIX threads functions are guaranteed not to be cancellation points. That is, they never perform cancellation in deferred cancellation mode.

pthread_testcancel does nothing except testing for pending cancellation and executing it. Its purpose is to introduce explicit checks for cancellation in long sequences of code that do not call cancellation point functions otherwise.

Return Value

pthread_cancel, pthread_setcancelstate and pthread_setcanceltype return 0 on success and a non-zero error code on error.

Errors

pthread_cancel returns the following error code on error:

ESRCH
no thread could be found corresponding to that specified by the thread ID.

pthread_setcancelstate returns the following error code on error:

EINVAL
the state argument is not
PTHREAD_CANCEL_ENABLE nor PTHREAD_CANCEL_DISABLE

pthread_setcanceltype returns the following error code on error:

EINVAL
the type argument is not
PTHREAD_CANCEL_DEFERRED nor PTHREAD_CANCEL_ASYNCHRONOUS

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_exit(3) , pthread_cleanup_push(3) , pthread_cleanup_pop(3) , Pthreads-w32 package README file 'Prerequisites' section.

Bugs

POSIX specifies that a number of system calls (basically, all system calls that may block, such as read(2) , write(2) , wait(2) , etc.) and library functions that may call these system calls (e.g. fprintf(3) ) are cancellation points. Pthreads-win32 is not integrated enough with the C library to implement this, and thus none of the C library functions is a cancellation point.

A workaround for these calls is to temporarily switch to asynchronous cancellation (assuming full asynchronous cancellation support is installed). So, checking for cancellation during a read system call, for instance, can be achieved as follows:



pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldCancelType);
read(fd, buffer, length);
pthread_setcanceltype(oldCancelType, NULL);

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_spin_init.html0000644000175000000620000001716211512143043023105 0ustar stevestaff "PTHREAD_SPIN_DESTROY"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_spin_destroy, pthread_spin_init - destroy or initialize a spin lock object (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER;

int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *
lock, int pshared);

Description

The pthread_spin_destroy function shall destroy the spin lock referenced by lock and release any resources used by the lock. The effect of subsequent use of the lock is undefined until the lock is reinitialized by another call to pthread_spin_init . The results are undefined if pthread_spin_destroy is called when a thread holds the lock, or if this function is called with an uninitialized thread spin lock.

The pthread_spin_init function shall allocate any resources required to use the spin lock referenced by lock and initialize the lock to an unlocked state.

Pthreads-w32 supports single and multiple processor systems as well as process CPU affinity masking by checking the mask when the spin lock is initialized. If the process is using only a single processor at the time pthread_spin_init is called then the spin lock is initialized as a PTHREAD_MUTEX_NORMAL mutex object. A thread that calls pthread_spin_lock(3) will block rather than spin in this case. If the process CPU affinity mask is altered after the spin lock has been initialised, the spin lock is not modified, and may no longer be optimal for the number of CPUs available.

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines do not support the PTHREAD_PROCESS_SHARED attribute. pthread_spin_init will return the error ENOTSUP if the value of pshared is not PTHREAD_PROCESS_PRIVATE.

The results are undefined if pthread_spin_init is called specifying an already initialized spin lock. The results are undefined if a spin lock is used without first being initialized.

If the pthread_spin_init function fails, the lock is not initialized and the contents of lock are undefined.

Only the object referenced by lock may be used for performing synchronization.

The result of referring to copies of that object in calls to pthread_spin_destroy , pthread_spin_lock(3) , pthread_spin_trylock(3), or pthread_spin_unlock(3) is undefined.

Pthreads-w32 supports statically initialized spin locks using PTHREAD_SPINLOCK_INITIALIZER. An application should still call pthread_spin_destroy at some point to ensure that any resources consumed by the spin lock are released.

Return Value

Upon successful completion, these functions shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

These functions may fail if:

EBUSY
The implementation has detected an attempt to initialize or destroy a spin lock while it is in use (for example, while being used in a pthread_spin_lock(3) call) by another thread.
EINVAL
The value specified by lock is invalid.

The pthread_spin_init function shall fail if:

ENOTSUP
The value of pshared is not PTHREAD_PROCESS_PRIVATE.
ENOMEM
Insufficient memory exists to initialize the lock.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

The pthread_spin_destroy and pthread_spin_init functions are part of the Spin Locks option and need not be provided on all implementations.

Rationale

None.

Future Directions

None.

See Also

pthread_spin_lock(3) , pthread_spin_unlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_condattr_setpshared.html0000644000175000000620000001525711512143043025154 0ustar stevestaff "PTHREAD_CONDATTR_GETPSHARED"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_condattr_getpshared, pthread_condattr_setpshared - get and set the process-shared condition variable attributes

Synopsis

#include <pthread.h>

int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr, int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t *
attr, int pshared);

Description

The pthread_condattr_getpshared function shall obtain the value of the process-shared attribute from the attributes object referenced by attr. The pthread_condattr_setpshared function shall set the process-shared attribute in an initialized attributes object referenced by attr.

The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit a condition variable to be operated upon by any thread that has access to the memory where the condition variable is allocated, even if the condition variable is allocated in memory that is shared by multiple processes. If the process-shared attribute is PTHREAD_PROCESS_PRIVATE, the condition variable shall only be operated upon by threads created within the same process as the thread that initialized the condition variable; if threads of differing processes attempt to operate on such a condition variable, the behavior is undefined. The default value of the attribute is PTHREAD_PROCESS_PRIVATE.

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines are implemented but that the process shared attribute is not supported.

Return Value

If successful, the pthread_condattr_setpshared function shall return zero; otherwise, an error number shall be returned to indicate the error.

If successful, the pthread_condattr_getpshared function shall return zero and store the value of the process-shared attribute of attr into the object referenced by the pshared parameter. Otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_condattr_getpshared and pthread_condattr_setpshared functions may fail if:

EINVAL
The value specified by attr is invalid.

The pthread_condattr_setpshared function may fail if:

EINVAL
The new value specified for the attribute is outside the range of legal values for that attribute.
ENOSYS
The value specified by attr was PTHREAD_PROCESS_SHARED (Pthreads-w32).

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines are implemented and may be used, but do not support the process shared option.

Rationale

None.

Future Directions

None.

See Also

pthread_create(3) , pthread_cond_destroy(3) , pthread_condattr_destroy(3) , pthread_mutex_destroy(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_condattr_init.html0000644000175000000620000000762311512143043023753 0ustar stevestaff PTHREAD_CONDATTR(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_condattr_init, pthread_condattr_destroy - condition creation

attributes

Synopsis

#include <pthread.h>

int pthread_condattr_init(pthread_condattr_t *attr);

int pthread_condattr_destroy(pthread_condattr_t *attr);

Description

Condition attributes can be specified at condition creation time, by passing a condition attribute object as second argument to pthread_cond_init(3) . Passing NULL is equivalent to passing a condition attribute object with all attributes set to their default values.

pthread_condattr_init initializes the condition attribute object attr and fills it with default values for the attributes. pthread_condattr_destroy destroys a condition attribute object, which must not be reused until it is reinitialized.

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that the attribute routines are implemented but that the process shared attribute is not supported.

Return Value

All condition variable functions return 0 on success and a non-zero error code on error.

Errors

The pthread_condattr_init function returns the following error code on error:

ENOMEM
The was insufficient memory to create the attribute.

The pthread_condattr_destroy function returns the following error code on error:

EINVAL
The attr argument is not valid.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_cond_init(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_equal.html0000644000175000000620000000276511512143043022223 0ustar stevestaff PTHREAD_EQUAL(3) manual page Table of Contents

Name

pthread_equal - compare two thread identifiers

Synopsis

#include <pthread.h>

int pthread_equal(pthread_t thread1, pthread_t thread2);

Description

pthread_equal determines if two thread identifiers refer to the same thread.

Return Value

A non-zero value is returned if thread1 and thread2 refer to the same thread. Otherwise, 0 is returned.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

See Also

pthread_self(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_join.html0000644000175000000620000001150111512143043022037 0ustar stevestaff PTHREAD_JOIN(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_join - wait for termination of another thread

Synopsis

#include <pthread.h>

int pthread_join(pthread_t th, void **thread_return);

Description

pthread_join suspends the execution of the calling thread until the thread identified by th terminates, either by calling pthread_exit(3) or by being cancelled.

If thread_return is not NULL, the return value of th is stored in the location pointed to by thread_return. The return value of th is either the argument it gave to pthread_exit(3) , or PTHREAD_CANCELED if th was cancelled.

The joined thread th must be in the joinable state: it must not have been detached using pthread_detach(3) or the PTHREAD_CREATE_DETACHED attribute to pthread_create(3) .

When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore, pthread_join must be called once for each joinable thread created to avoid memory leaks.

At most one thread can wait for the termination of a given thread. Calling pthread_join on a thread th on which another thread is already waiting for termination returns an error.

Cancellation

pthread_join is a cancellation point. If a thread is cancelled while suspended in pthread_join, the thread execution resumes immediately and the cancellation is executed without waiting for the th thread to terminate. If cancellation occurs during pthread_join, the th thread remains not joined.

Return Value

On success, the return value of th is stored in the location pointed to by thread_return, and 0 is returned. On error, a non-zero error code is returned.

Errors

ESRCH
No thread could be found corresponding to that specified by th.
EINVAL
The th thread has been detached.
EINVAL
Another thread is already waiting on termination of th.
EDEADLK
The th argument refers to the calling thread.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

See Also

pthread_exit(3) , pthread_detach(3) , pthread_create(3) , pthread_attr_setdetachstate(3) , pthread_cleanup_push(3) , pthread_key_create(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlock_init.html0000644000175000000620000002065211512143043023433 0ustar stevestaff "PTHREAD_RWLOCK_DESTROY"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlock_destroy, pthread_rwlock_init - destroy and initialize a read-write lock object

Synopsis

#include <pthread.h>

pthread_wrlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *restrict
rwlock, const pthread_rwlockattr_t *restrict attr);

Description

The pthread_rwlock_destroy function shall destroy the read-write lock object referenced by rwlock and release any resources used by the lock. The effect of subsequent use of the lock is undefined until the lock is reinitialized by another call to pthread_rwlock_init. An implementation may cause pthread_rwlock_destroy to set the object referenced by rwlock to an invalid value. Results are undefined if pthread_rwlock_destroy is called when any thread holds rwlock. Attempting to destroy an uninitialized read-write lock results in undefined behavior.

The pthread_rwlock_init function shall allocate any resources required to use the read-write lock referenced by rwlock and initializes the lock to an unlocked state with attributes referenced by attr. If attr is NULL, the default read-write lock attributes shall be used; the effect is the same as passing the address of a default read-write lock attributes object. Once initialized, the lock can be used any number of times without being reinitialized. Results are undefined if pthread_rwlock_init is called specifying an already initialized read-write lock. Results are undefined if a read-write lock is used without first being initialized.

If the pthread_rwlock_init function fails, rwlock shall not be initialized and the contents of rwlock are undefined.

Pthreads-w32 supports statically initialized rwlock objects using PTHREAD_RWLOCK_INITIALIZER. An application should still call pthread_rwlock_destroy at some point to ensure that any resources consumed by the read/write lock are released.

Only the object referenced by rwlock may be used for performing synchronization. The result of referring to copies of that object in calls to pthread_rwlock_destroy , pthread_rwlock_rdlock , pthread_rwlock_timedrdlock , pthread_rwlock_timedwrlock , pthread_rwlock_tryrdlock , pthread_rwlock_trywrlock , pthread_rwlock_unlock , or pthread_rwlock_wrlock is undefined.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

If successful, the pthread_rwlock_destroy and pthread_rwlock_init functions shall return zero; otherwise, an error number shall be returned to indicate the error.

The [EBUSY] and [EINVAL] error checks, if implemented, act as if they were performed immediately at the beginning of processing for the function and caused an error return prior to modifying the state of the read-write lock specified by rwlock.

Errors

The pthread_rwlock_destroy function may fail if:

EBUSY
The implementation has detected an attempt to destroy the object referenced by rwlock while it is locked.
EINVAL
The value specified by rwlock is invalid.

The pthread_rwlock_init function shall fail if:

EAGAIN
The system lacked the necessary resources (other than memory) to initialize another read-write lock.
ENOMEM
Insufficient memory exists to initialize the read-write lock.


The pthread_rwlock_init function may fail if:

EINVAL
The value specified by attr is invalid.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using these and related read-write lock functions may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_rdlock(3) , pthread_rwlock_timedrdlock(3) , pthread_rwlock_timedwrlock(3) , pthread_rwlock_tryrdlock(3) , pthread_rwlock_trywrlock(3) , pthread_rwlock_unlock(3) , pthread_rwlock_wrlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_attr_setstackaddr.html0000644000175000000620000001604011512143043024611 0ustar stevestaff "PTHREAD_ATTR_GETSTACKADDR"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_attr_getstackaddr, pthread_attr_setstackaddr - get and set the stackaddr attribute

Synopsis

#include <pthread.h>

int pthread_attr_getstackaddr(const pthread_attr_t *restrict attr, void **restrict stackaddr);
int pthread_attr_setstackaddr(pthread_attr_t *
attr, void *stackaddr);

Description

The pthread_attr_getstackaddr and pthread_attr_setstackaddr functions, respectively, shall get and set the thread creation stackaddr attribute in the attr object.

The stackaddr attribute specifies the location of storage to be used for the created thread’s stack. The size of the storage shall be at least {PTHREAD_STACK_MIN}.

Pthreads-w32 defines _POSIX_THREAD_ATTR_STACKADDR in pthread.h as -1 to indicate that these routines are implemented but cannot used to set or get the stack address. These routines always return the error ENOSYS when called.

Return Value

Upon successful completion, pthread_attr_getstackaddr and pthread_attr_setstackaddr shall return a value of 0; otherwise, an error number shall be returned to indicate the error.

The pthread_attr_getstackaddr function stores the stackaddr attribute value in stackaddr if successful.

Errors

The pthread_attr_setstackaddr function always returns the following error code:

ENOSYS
The function is not supported.

The pthread_attr_getstackaddr function always returns the following error code:

ENOSYS
The function is not supported.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

The specification of the stackaddr attribute presents several ambiguities that make portable use of these interfaces impossible. The description of the single address parameter as a "stack" does not specify a particular relationship between the address and the "stack" implied by that address. For example, the address may be taken as the low memory address of a buffer intended for use as a stack, or it may be taken as the address to be used as the initial stack pointer register value for the new thread. These two are not the same except for a machine on which the stack grows "up" from low memory to high, and on which a "push" operation first stores the value in memory and then increments the stack pointer register. Further, on a machine where the stack grows "down" from high memory to low, interpretation of the address as the "low memory" address requires a determination of the intended size of the stack. IEEE Std 1003.1-2001 has introduced the new interfaces pthread_attr_setstack(3) and pthread_attr_getstack(3) to resolve these ambiguities.

Rationale

None.

Future Directions

None.

See Also

pthread_attr_destroy(3) , pthread_attr_getdetachstate(3) , pthread_attr_getstack(3) , pthread_attr_getstacksize(3) , pthread_attr_setstack(3) , pthread_create(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <limits.h>, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_kill.html0000644000175000000620000001546511512143043022050 0ustar stevestaff PTHREAD_SIGNAL(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_sigmask, pthread_kill, sigwait - handling of signals in threads

Synopsis

#include <pthread.h>
#include <signal.h>

int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask);

int pthread_kill(pthread_t thread, int signo);

int sigwait(const sigset_t *set, int *sig);

Description

pthread_sigmask changes the signal mask for the calling thread as described by the how and newmask arguments. If oldmask is not NULL, the previous signal mask is stored in the location pointed to by oldmask. Pthreads-w32 implements this function but no other function uses the signal mask yet.

The meaning of the how and newmask arguments is the same as for sigprocmask(2). If how is SIG_SETMASK, the signal mask is set to newmask. If how is SIG_BLOCK, the signals specified to newmask are added to the current signal mask. If how is SIG_UNBLOCK, the signals specified to newmask are removed from the current signal mask.

Recall that signal masks are set on a per-thread basis, but signal actions and signal handlers, as set with sigaction(2), are shared between all threads.

pthread_kill send signal number signo to the thread thread. Pthreads-w32 only supports signal number 0, which does not send any signal but causes pthread_kill to return an error if thread is not valid.

sigwait suspends the calling thread until one of the signals in set is delivered to the calling thread. It then stores the number of the signal received in the location pointed to by sig and returns. The signals in set must be blocked and not ignored on entrance to sigwait. If the delivered signal has a signal handler function attached, that function is not called. Pthreads-w32 implements this function as a cancellation point only - it does not wait for any signals and does not change the location pointed to by sig.

Cancellation

sigwait is a cancellation point.

Return Value

On success, 0 is returned. On failure, a non-zero error code is returned.

Errors

The pthread_sigmask function returns the following error codes on error:

EINVAL
how is not one of SIG_SETMASK, SIG_BLOCK, or SIG_UNBLOCK

The pthread_kill function returns the following error codes on error:

EINVAL
signo is not a valid signal number or is unsupported.
ESRCH
the thread thread does not exist (e.g. it has already terminated)

The sigwait function never returns an error.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

Notes

In any implementation, for sigwait to work reliably, the signals being waited for must be blocked in all threads, not only in the calling thread, since otherwise the POSIX semantics for signal delivery do not guarantee that it’s the thread doing the sigwait that will receive the signal. The best way to achieve this is to block those signals before any threads are created, and never unblock them in the program other than by calling sigwait. This works because all threads inherit their initial sigmask from their creating thread.

Bugs

Pthreads-w32 does not implement signals yet and so these routines have almost no use except to prevent the compiler or linker from complaining. pthread_kill is useful in determining if the thread is a valid thread, but since many threads implementations reuse thread IDs, the valid thread may no longer be the thread you think it is, and so this method of determining thread validity is not portable, and very risky. Pthreads-w32 from version 1.0.0 onwards implements pseudo-unique thread IDs, so applications that use this technique (but really shouldn't) have some protection.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_win32_test_features_np.html0000644000175000000620000000623411512143043025503 0ustar stevestaff PTHREAD_WIN32_TEST_FEATURES_NP manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_win32_test_features_np – find out what features were detected at process attach time.

Synopsis

#include <pthread.h>

BOOL pthread_win32_test_features_np(int mask);

Description

pthread_win32_test_features_np allows an application to check which run-time auto-detected features are available within the library.

The possible features are:

PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE

Return TRUE if the Win32 version of InterlockedCompareExchange() is being used. On IA32 systems the library can use optimised and inlinable assembler versions of InterlockedExchange() and InterlockedCompareExchange().

PTW32_ALERTABLE_ASYNC_CANCEL

Return TRUE if the QueueUserAPCEx package QUSEREX.DLL and the AlertDrv.sys driver was detected. This package provides alertable (pre-emptive) asynchronous threads cancellation. If this feature returns FALSE then the default async cancel scheme is in use, which cannot cancel blocked threads.

Cancellation

None.

Return Value

pthread_win32_test_features_np returns TRUE (non-zero) if the specified feature is present, and FALSE (0) otherwise.

Errors

None.

Author

Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_num_processors_np.html0000644000175000000620000000502111512143043024656 0ustar stevestaff PTHREAD_NUM_PROCESSORS_NP manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_num_processors_np – get the number of processors (CPUs) in use by the process

Synopsis

#include <pthread.h>

int pthread_num_processors_np(void);

Description

pthread_num_processors_np returns the number of processors in the system. This implementation actually returns the number of processors available to the process, which can be a lower number than the system's number, depending on the process's affinity mask.

Cancellation

None.

Return Value

pthread_num_processors_np returns the number of processors currently available to the process.

Errors

None.

Author

Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_self.html0000644000175000000620000000626411512143043022043 0ustar stevestaff PTHREAD_SELF(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_self - return identifier of current thread

Synopsis

#include <pthread.h>

pthread_t pthread_self(void);

Description

pthread_self return the thread identifier for the calling thread.

Pthreads-w32 also provides support for Win32 native threads to interact with POSIX threads through the pthreads API. Whereas all threads created via a call to pthread_create have a POSIX thread ID and thread state, the library ensures that any Win32 native threads that interact through the Pthreads API also generate a POSIX thread ID and thread state when and if necessary. This provides full reciprocity between Win32 and POSIX threads. Win32 native threads that generate a POSIX thread ID and state are treated by the library as having been created with the PTHREAD_CREATE_DETACHED attribute.

Any Win32 native thread may call pthread_self directly to return it's POSIX thread identifier. The ID and state will be generated if it does not already exist. Win32 native threads do not need to call pthread_self before calling Pthreads-w32 routines unless that routine requires a pthread_t parameter.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_equal(3) , pthread_join(3) , pthread_detach(3) , pthread_setschedparam(3) , pthread_getschedparam(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/sched_getscheduler.html0000644000175000000620000001213511512143043023221 0ustar stevestaff "SCHED_GETSCHEDULER"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

sched_getscheduler - get scheduling policy (REALTIME)

Synopsis

#include <sched.h>

int sched_getscheduler(pid_t pid);

Description

The sched_getscheduler function shall return the scheduling policy of the process specified by pid. If the value of pid is negative, the behavior of the sched_getscheduler function is unspecified.

The values that can be returned by sched_getscheduler are defined in the <sched.h> header.

Pthreads-w32 only supports the SCHED_OTHER policy, which is the only value that can be returned. However, checks on pid and permissions are performed first so that the other useful side effects of this routine are retained.

If a process specified by pid exists, and if the calling process has permission, the scheduling policy shall be returned for the process whose process ID is equal to pid.

If pid is zero, the scheduling policy shall be returned for the calling process.

Return Value

Upon successful completion, the sched_getscheduler function shall return the scheduling policy of the specified process. If unsuccessful, the function shall return -1 and set errno to indicate the error.

Errors

The sched_getscheduler function shall fail if:

EPERM
The requesting process does not have permission to determine the scheduling policy of the specified process.
ESRCH
No process can be found corresponding to that specified by pid.

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

sched_setscheduler(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <sched.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_rwlock_unlock.html0000644000175000000620000001376711512143043023774 0ustar stevestaff "PTHREAD_RWLOCK_UNLOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_rwlock_unlock - unlock a read-write lock object

Synopsis

#include <pthread.h>

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

Description

The pthread_rwlock_unlock function shall release a lock held on the read-write lock object referenced by rwlock. Results are undefined if the read-write lock rwlock is not held by the calling thread.

If this function is called to release a read lock from the read-write lock object and there are other read locks currently held on this read-write lock object, the read-write lock object remains in the read locked state. If this function releases the last read lock for this read-write lock object, the read-write lock object shall be put in the unlocked state with no owners.

If this function is called to release a write lock for this read-write lock object, the read-write lock object shall be put in the unlocked state.

Pthreads-win32 does not prefer either writers or readers in acquiring the lock – all threads enter a single prioritised FIFO queue. While this may not be optimally efficient for some applications, it does ensure that one type does not starve the other.

Results are undefined if any of these functions are called with an uninitialized read-write lock.

Pthreads-w32 defines _POSIX_READER_WRITER_LOCKS in pthread.h as 200112L to indicate that the reader/writer routines are implemented and may be used.

Return Value

If successful, the pthread_rwlock_unlock function shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_rwlock_unlock function may fail if:

EINVAL
The value specified by rwlock does not refer to an initialized read-write lock object.


The pthread_rwlock_unlock function shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

pthread_rwlock_destroy(3) , pthread_rwlock_rdlock(3) , pthread_rwlock_timedrdlock(3) , pthread_rwlock_timedwrlock(3) , pthread_rwlock_tryrdlock(3) , pthread_rwlock_trywrlock(3) , pthread_rwlock_wrlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_create.html0000644000175000000620000000775611512143043022364 0ustar stevestaff PTHREAD_CREATE(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_create - create a new thread

Synopsis

#include <pthread.h>

int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);

Description

pthread_create creates a new thread of control that executes concurrently with the calling thread. The new thread applies the function start_routine passing it arg as first argument. The new thread terminates either explicitly, by calling pthread_exit(3) , or implicitly, by returning from the start_routine function. The latter case is equivalent to calling pthread_exit(3) with the result returned by start_routine as exit code.

The initial signal state of the new thread is inherited from it's creating thread and there are no pending signals. Pthreads-w32 does not yet implement signals.

The attr argument specifies thread attributes to be applied to the new thread. See pthread_attr_init(3) for a complete list of thread attributes. The attr argument can also be NULL, in which case default attributes are used: the created thread is joinable (not detached) and has default (non real-time) scheduling policy.

Return Value

On success, the identifier of the newly created thread is stored in the location pointed by the thread argument, and a 0 is returned. On error, a non-zero error code is returned.

Errors

EAGAIN
Not enough system resources to create a process for the new thread, or
more than PTHREAD_THREADS_MAX threads are already active.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_exit(3) , pthread_join(3) , pthread_detach(3) , pthread_attr_init(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_mutexattr_setpshared.html0000644000175000000620000001462311512143043025367 0ustar stevestaff "PTHREAD_MUTEXATTR_GETPSHARED"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_mutexattr_getpshared, pthread_mutexattr_setpshared - get and set the process-shared attribute

Synopsis

#include <pthread.h>

int pthread_mutexattr_getpshared(const pthread_mutexattr_t * restrict attr, int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *
attr, int pshared);

Description

The pthread_mutexattr_getpshared function shall obtain the value of the process-shared attribute from the attributes object referenced by attr. The pthread_mutexattr_setpshared function shall set the process-shared attribute in an initialized attributes object referenced by attr.

The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit a mutex to be operated upon by any thread that has access to the memory where the mutex is allocated, even if the mutex is allocated in memory that is shared by multiple processes. If the process-shared attribute is PTHREAD_PROCESS_PRIVATE, the mutex shall only be operated upon by threads created within the same process as the thread that initialized the mutex; if threads of differing processes attempt to operate on such a mutex, the behavior is undefined. The default value of the attribute shall be PTHREAD_PROCESS_PRIVATE.

Pthreads-w32 defines _POSIX_THREAD_PROCESS_SHARED in pthread.h as -1 to indicate that these routines are implemented but the process shared option is not supported.

Return Value

Upon successful completion, pthread_mutexattr_setpshared shall return zero; otherwise, an error number shall be returned to indicate the error.

Upon successful completion, pthread_mutexattr_getpshared shall return zero and store the value of the process-shared attribute of attr into the object referenced by the pshared parameter. Otherwise, an error number shall be returned to indicate the error.

Errors

The pthread_mutexattr_getpshared and pthread_mutexattr_setpshared functions may fail if:

EINVAL
The value specified by attr is invalid.

The pthread_mutexattr_setpshared function may fail if:

EINVAL
The new value specified for the attribute is outside the range of legal values for that attribute.
ENOTSUP
The new value specified for the attribute is PTHREAD_PROCESS_SHARED.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

pthread_cond_destroy(3) , pthread_create(3) , pthread_mutex_destroy(3) , pthread_mutexattr_destroy(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_detach.html0000644000175000000620000000735411512143043022343 0ustar stevestaff PTHREAD_DETACH(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_detach - put a running thread in the detached state

Synopsis

#include <pthread.h>

int pthread_detach(pthread_t th);

Description

pthread_detach puts the thread th in the detached state. This guarantees that the resources consumed by th will be freed immediately when th terminates. However, this prevents other threads from synchronizing on the termination of th using pthread_join. If, when pthread_detach is called, th has already terminated, all of th's remaining resources will be freed.

A thread can be created initially in the detached state, using the detachstate attribute to pthread_create(3) . In contrast, pthread_detach applies to threads created in the joinable state, and which need to be put in the detached state later.

After pthread_detach completes, subsequent attempts to perform pthread_join on th will fail. If another thread is already joining the thread th at the time pthread_detach is called, th will be detached and pthread_join will eventually return when th terminates but may not return with th's correct return code.

Return Value

On success, 0 is returned. On error, a non-zero error code is returned.

Errors

ESRCH
No thread could be found corresponding to that specified by th
EINVAL
the thread th is already in the detached state

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_create(3) , pthread_join(3) , pthread_attr_setdetachstate(3)


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/index.html0000644000175000000620000003150011512143043020501 0ustar stevestaff

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Table of Contents

POSIX threads API reference
Miscellaneous POSIX thread safe routines provided by Pthreads-w32
Non-portable Pthreads-w32 routines
Other

POSIX threads API reference

pthread_attr_destroy

pthread_attr_getdetachstate

pthread_attr_getinheritsched

pthread_attr_getschedparam

pthread_attr_getschedpolicy

pthread_attr_getscope

pthread_attr_getstackaddr

pthread_attr_getstacksize

pthread_attr_init

pthread_attr_setdetachstate

pthread_attr_setinheritsched

pthread_attr_setschedparam

pthread_attr_setschedpolicy

pthread_attr_setscope

pthread_attr_setstackaddr

pthread_attr_setstacksize

pthread_barrierattr_destroy

pthread_barrierattr_getpshared

pthread_barrierattr_init

pthread_barrierattr_setpshared

pthread_barrier_destroy

pthread_barrier_init

pthread_barrier_wait

pthread_cancel

pthread_cleanup_pop

pthread_cleanup_push

pthread_condattr_destroy

pthread_condattr_getpshared

pthread_condattr_init

pthread_condattr_setpshared

pthread_cond_broadcast

pthread_cond_destroy

pthread_cond_init

pthread_cond_signal

pthread_cond_timedwait

pthread_cond_wait

pthread_create

pthread_detach

pthread_equal

pthread_exit

pthread_getconcurrency

pthread_getschedparam

pthread_getspecific

pthread_join

pthread_key_create

pthread_key_delete

pthread_kill

pthread_mutexattr_destroy

pthread_mutexattr_getkind_np

pthread_mutexattr_getpshared

pthread_mutexattr_gettype

pthread_mutexattr_init

pthread_mutexattr_setkind_np

pthread_mutexattr_setpshared

pthread_mutexattr_settype

pthread_mutex_destroy

pthread_mutex_init

pthread_mutex_lock

pthread_mutex_timedlock

pthread_mutex_trylock

pthread_mutex_unlock

pthread_once

pthread_rwlockattr_destroy

pthread_rwlockattr_getpshared

pthread_rwlockattr_init

pthread_rwlockattr_setpshared

pthread_rwlock_destroy

pthread_rwlock_init

pthread_rwlock_rdlock

pthread_rwlock_timedrdlock

pthread_rwlock_timedwrlock

pthread_rwlock_tryrdlock

pthread_rwlock_trywrlock

pthread_rwlock_unlock

pthread_rwlock_wrlock

pthread_self

pthread_setcancelstate

pthread_setcanceltype

pthread_setconcurrency

pthread_setschedparam

pthread_setspecific

pthread_sigmask

pthread_spin_destroy

pthread_spin_init

pthread_spin_lock

pthread_spin_trylock

pthread_spin_unlock

pthread_testcancel

sched_get_priority_max

sched_get_priority_min

sched_getscheduler

sched_setscheduler

sched_yield

sem_close

sem_destroy

sem_getvalue

sem_init

sem_open

sem_post

sem_post_multiple

sem_timedwait

sem_trywait

sem_unlink

sem_wait

sigwait

Miscellaneous POSIX thread safe routines provided by Pthreads-w32

asctime_r

ctime_r

gmtime_r

localtime_r

rand_r

Non-portable Pthreads-w32 routines

pthreadCancelableTimedWait

pthreadCancelableWait

pthread_delay_np

pthread_getw32threadhandle_np

pthread_num_processors_np

pthread_win32_test_features_np

pthread_timechange_handler_np

pthread_win32_process_attach_np

pthread_win32_process_detach_np

pthread_win32_thread_attach_np

pthread_win32_thread_detach_np

Other

Portability issues

nyquist-3.05/liblo/pthreads.2/manual/pthread_attr_init.html0000644000175000000620000002731311512143043023105 0ustar stevestaff PTHREAD_ATTR_INIT(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_attr_init, pthread_attr_destroy, pthread_attr_setdetachstate, pthread_attr_getdetachstate, pthread_attr_setschedparam, pthread_attr_getschedparam, pthread_attr_setschedpolicy, pthread_attr_getschedpolicy, pthread_attr_setinheritsched, pthread_attr_getinheritsched, pthread_attr_setscope, pthread_attr_getscope - thread creation attributes

Synopsis

#include <pthread.h>

int pthread_attr_init(pthread_attr_t *attr);

int pthread_attr_destroy(pthread_attr_t *attr);

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);

int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);

int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);

int pthread_attr_setscope(pthread_attr_t *attr, int scope);

int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);

Description

Setting attributes for threads is achieved by filling a thread attribute object attr of type pthread_attr_t, then passing it as second argument to pthread_create(3) . Passing NULL is equivalent to passing a thread attribute object with all attributes set to their default values.

pthread_attr_init initializes the thread attribute object attr and fills it with default values for the attributes. (The default values are listed below for each attribute.)

Each attribute attrname (see below for a list of all attributes) can be individually set using the function pthread_attr_setattrname and retrieved using the function pthread_attr_getattrname.

pthread_attr_destroy destroys a thread attribute object, which must not then be reused until it is reinitialized.

Attribute objects are consulted only when creating a new thread. The same attribute object can be used for creating several threads. Modifying an attribute object after a call to pthread_create does not change the attributes of the thread previously created.

The following thread attributes are supported:

detachstate

Control whether the thread is created in the joinable state (value PTHREAD_CREATE_JOINABLE) or in the detached state ( PTHREAD_CREATE_DETACHED).

Default value: PTHREAD_CREATE_JOINABLE.

In the joinable state, another thread can synchronize on the thread termination and recover its termination code using pthread_join(3) . When a joinable thread terminates, some of the thread resources are kept allocated, and released only when another thread performs pthread_join(3) on that thread.

In the detached state, the thread's resources are released immediately when it terminates. pthread_join(3) cannot be used to synchronize on the thread termination.

A thread created in the joinable state can later be put in the detached thread using pthread_detach(3) .

schedpolicy

Select the scheduling policy for the thread: one of SCHED_OTHER (regular, non-real-time scheduling), SCHED_RR (real-time, round-robin) or SCHED_FIFO (real-time, first-in first-out).

Pthreads-w32 only supports SCHED_OTHER - attempting to set one of the other policies will return an error ENOTSUP.

Default value: SCHED_OTHER.

Pthreads-w32 only supports SCHED_OTHER - attempting to set one of the other policies will return an error ENOTSUP.

The scheduling policy of a thread can be changed after creation with pthread_setschedparam(3) .

schedparam

Contain the scheduling parameters (essentially, the scheduling priority) for the thread.

Pthreads-w32 supports the priority levels defined by the Windows system it is running on. Under Windows, thread priorities are relative to the process priority class, which must be set via the Windows W32 API.

Default value: priority is 0 (Win32 level THREAD_PRIORITY_NORMAL).

The scheduling priority of a thread can be changed after creation with pthread_setschedparam(3) .

inheritsched

Indicate whether the scheduling policy and scheduling parameters for the newly created thread are determined by the values of the schedpolicy and schedparam attributes (value PTHREAD_EXPLICIT_SCHED) or are inherited from the parent thread (value PTHREAD_INHERIT_SCHED).

Default value: PTHREAD_EXPLICIT_SCHED.

scope

Define the scheduling contention scope for the created thread. The only value supported in the Pthreads-w32 implementation is PTHREAD_SCOPE_SYSTEM, meaning that the threads contend for CPU time with all processes running on the machine. The other value specified by the standard, PTHREAD_SCOPE_PROCESS, means that scheduling contention occurs only between the threads of the running process.

Pthreads-w32 only supports PTHREAD_SCOPE_SYSTEM.

Default value: PTHREAD_SCOPE_SYSTEM.

Return Value

All functions return 0 on success and a non-zero error code on error. On success, the pthread_attr_getattrname functions also store the current value of the attribute attrname in the location pointed to by their second argument.

Errors

The pthread_attr_setdetachstate function returns the following error codes on error:

EINVAL
the specified detachstate is not one of PTHREAD_CREATE_JOINABLE or PTHREAD_CREATE_DETACHED.

The pthread_attr_setschedparam function returns the following error codes on error:

EINVAL
the priority specified in param is outside the range of allowed priorities for the scheduling policy currently in attr (1 to 99 for SCHED_FIFO and SCHED_RR; 0 for SCHED_OTHER).

The pthread_attr_setschedpolicy function returns the following error codes on error:

EINVAL
the specified policy is not one of SCHED_OTHER, SCHED_FIFO, or SCHED_RR.
ENOTSUP
policy is not SCHED_OTHER, the only value supported by Pthreads-w32.

The pthread_attr_setinheritsched function returns the following error codes on error:

EINVAL
the specified inherit is not one of PTHREAD_INHERIT_SCHED or PTHREAD_EXPLICIT_SCHED.

The pthread_attr_setscope function returns the following error codes on error:

EINVAL
the specified scope is not one of PTHREAD_SCOPE_SYSTEM or PTHREAD_SCOPE_PROCESS.
ENOTSUP
the specified scope is PTHREAD_SCOPE_PROCESS (not supported by Pthreads-w32).

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_create(3) , pthread_join(3) , pthread_detach(3) , pthread_setschedparam(3) .


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthreadCancelableWait.html0000644000175000000620000001004611512143043023602 0ustar stevestaff PTHREADCANCELLABLEWAIT manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthreadCancelableTimedWait, pthreadCancelableWait – provide cancellation hooks for user Win32 routines

Synopsis

#include <pthread.h>

int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);

int pthreadCancelableWait (HANDLE waitHandle);

Description

These two functions provide hooks into the pthread_cancel() mechanism that will allow you to wait on a Windows handle and make it a cancellation point. Both functions block until either the given Win32 HANDLE is signalled, or pthread_cancel() has been called. They are implemented using WaitForMultipleObjects on waitHandle and the manually reset Win32 event handle that is the target of pthread_cancel(). These routines may be called from Win32 native threads but pthread_cancel() will require that thread's POSIX thread ID that the thread must retrieve using pthread_self().

pthreadCancelableTimedWait is the timed version that will return with the code ETIMEDOUT if the interval timeout milliseconds elapses before waitHandle is signalled.

Cancellation

These routines allow routines that block on Win32 HANDLEs to be cancellable via pthread_cancel().

Return Value



Errors

The pthreadCancelableTimedWait function returns the following error code on error:

ETIMEDOUT

The interval timeout milliseconds elapsed before waitHandle was signalled.

Author

Ross Johnson for use with Pthreads-w32.

See also

pthread_cancel(), pthread_self()


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_win32_attach_detach_np.html0000644000175000000620000000670311512143043025403 0ustar stevestaff PTHREAD_WIN32_ATTACH_DETACH_NP manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_win32_process_attach_np, pthread_win32_process_detach_np, pthread_win32_thread_attach_np, pthread_win32_thread_detach_np – exposed versions of the pthreads-w32 DLL dllMain() switch functionality for use when statically linking the library.

Synopsis

#include <pthread.h>

BOOL pthread_win32_process_attach_np (void);

BOOL pthread_win32_process_detach_np (void);

BOOL pthread_win32_thread_attach_np (void);

BOOL pthread_win32_thread_detach_np (void);

Description

These functions contain the code normally run via dllMain when the library is used as a dll but which need to be called explicitly by an application when the library is statically linked.

You will need to call pthread_win32_process_attach_np before you can call any pthread routines when statically linking. You should call pthread_win32_process_detach_np before exiting your application to clean up.

pthread_win32_thread_attach_np is currently a no-op, but pthread_win32_thread_detach_np is needed to clean up the implicit pthread handle that is allocated to a Win32 thread if it calls certain pthreads routines. Call this routine when the Win32 thread exits.

These functions invariably return TRUE except for pthread_win32_process_attach_np which will return FALSE if pthreads-w32 initialisation fails.

Cancellation

None.

Return Value

These routines return TRUE (non-zero) on success, or FALSE (0) if they fail.

Errors

None.

Author

Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_setconcurrency.html0000644000175000000620000001522111512143043024151 0ustar stevestaff "PTHREAD_GETCONCURRENCY"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_getconcurrency, pthread_setconcurrency - get and set the level of concurrency

Synopsis

#include <pthread.h>

int pthread_getconcurrency(void);
int pthread_setconcurrency(int new_level);

Description

Unbound threads in a process may or may not be required to be simultaneously active. By default, the threads implementation ensures that a sufficient number of threads are active so that the process can continue to make progress. While this conserves system resources, it may not produce the most effective level of concurrency.

The pthread_setconcurrency function allows an application to inform the threads implementation of its desired concurrency level, new_level. The actual level of concurrency provided by the implementation as a result of this function call is unspecified.

If new_level is zero, it causes the implementation to maintain the concurrency level at its discretion as if pthread_setconcurrency had never been called.

The pthread_getconcurrency function shall return the value set by a previous call to the pthread_setconcurrency function. If the pthread_setconcurrency function was not previously called, this function shall return zero to indicate that the implementation is maintaining the concurrency level.

A call to pthread_setconcurrency shall inform the implementation of its desired concurrency level. The implementation shall use this as a hint, not a requirement.

If an implementation does not support multiplexing of user threads on top of several kernel-scheduled entities, the pthread_setconcurrency and pthread_getconcurrency functions are provided for source code compatibility but they shall have no effect when called. To maintain the function semantics, the new_level parameter is saved when pthread_setconcurrency is called so that a subsequent call to pthread_getconcurrency shall return the same value.

Pthreads-w32 provides these routines for source code compatibility only, as described in the previous paragraph.

Return Value

If successful, the pthread_setconcurrency function shall return zero; otherwise, an error number shall be returned to indicate the error.

The pthread_getconcurrency function shall always return the concurrency level set by a previous call to pthread_setconcurrency . If the pthread_setconcurrency function has never been called, pthread_getconcurrency shall return zero.

Errors

The pthread_setconcurrency function shall fail if:

EINVAL
The value specified by new_level is negative.
EAGAIN
The value specific by new_level would cause a system resource to be exceeded.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Use of these functions changes the state of the underlying concurrency upon which the application depends. Library developers are advised to not use the pthread_getconcurrency and pthread_setconcurrency functions since their use may conflict with an applications use of these functions.

Rationale

None.

Future Directions

None.

See Also

The Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/PortabilityIssues.html0000644000175000000620000005237311512143043023103 0ustar stevestaff PORTABILITYISSUES manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

Portability issues

Synopsis

Thread priority

Description

Thread priority

POSIX defines a single contiguous range of numbers that determine a thread's priority. Win32 defines priority classes - and priority levels relative to these classes. Classes are simply priority base levels that the defined priority levels are relative to such that, changing a process's priority class will change the priority of all of it's threads, while the threads retain the same relativity to each other.

A Win32 system defines a single contiguous monotonic range of values that define system priority levels, just like POSIX. However, Win32 restricts individual threads to a subset of this range on a per-process basis.

The following table shows the base priority levels for combinations of priority class and priority value in Win32.


Process Priority Class

Thread Priority Level

1

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_IDLE

1

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_IDLE

1

NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_IDLE

1

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_IDLE

1

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_IDLE

2

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

3

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

4

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

4

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

5

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

5

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

5

Background NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

6

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

6

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

6

Background NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

7

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

7

Background NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

7

Foreground NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

8

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

8

NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

8

Foreground NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

8

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

9

NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

9

Foreground NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

9

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

10

Foreground NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

10

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

11

Foreground NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

11

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

11

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

12

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

12

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

13

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

14

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

15

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

15

HIGH_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

15

IDLE_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

15

BELOW_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

15

NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

15

ABOVE_NORMAL_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

16

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_IDLE

17

REALTIME_PRIORITY_CLASS

-7

18

REALTIME_PRIORITY_CLASS

-6

19

REALTIME_PRIORITY_CLASS

-5

20

REALTIME_PRIORITY_CLASS

-4

21

REALTIME_PRIORITY_CLASS

-3

22

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_LOWEST

23

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_BELOW_NORMAL

24

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_NORMAL

25

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_ABOVE_NORMAL

26

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_HIGHEST

27

REALTIME_PRIORITY_CLASS

3

28

REALTIME_PRIORITY_CLASS

4

29

REALTIME_PRIORITY_CLASS

5

30

REALTIME_PRIORITY_CLASS

6

31

REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported.

As you can see, the real priority levels available to any individual Win32 thread are non-contiguous.

An application using Pthreads-w32 should not make assumptions about the numbers used to represent thread priority levels, except that they are monotonic between the values returned by sched_get_priority_min() and sched_get_priority_max(). E.g. Windows 95, 98, NT, 2000, XP make available a non-contiguous range of numbers between -15 and 15, while at least one version of WinCE (3.0) defines the minimum priority (THREAD_PRIORITY_LOWEST) as 5, and the maximum priority (THREAD_PRIORITY_HIGHEST) as 1.

Internally, pthreads-win32 maps any priority levels between THREAD_PRIORITY_IDLE and THREAD_PRIORITY_LOWEST to THREAD_PRIORITY_LOWEST, or between THREAD_PRIORITY_TIME_CRITICAL and THREAD_PRIORITY_HIGHEST to THREAD_PRIORITY_HIGHEST. Currently, this also applies to REALTIME_PRIORITY_CLASS even if levels -7, -6, -5, -4, -3, 3, 4, 5, and 6 are supported.

If it wishes, a Win32 application using pthreads-w32 can use the Win32 defined priority macros THREAD_PRIORITY_IDLE through THREAD_PRIORITY_TIME_CRITICAL.

Author

Ross Johnson for use with Pthreads-w32.

See also




Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_once.html0000644000175000000620000000673011512143043022034 0ustar stevestaff PTHREAD_ONCE(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_once - once-only initialization

Synopsis

#include <pthread.h>

pthread_once_t once_control = PTHREAD_ONCE_INIT;

int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));

Description

The purpose of pthread_once is to ensure that a piece of initialization code is executed at most once. The once_control argument points to a static or extern variable statically initialized to PTHREAD_ONCE_INIT.

The first time pthread_once is called with a given once_control argument, it calls init_routine with no argument and changes the value of the once_control variable to record that initialization has been performed. Subsequent calls to pthread_once with the same once_control argument do nothing.

Cancellation

While pthread_once is not a cancellation point, init_routine can be. The effect on once_control of a cancellation inside the init_routine is to leave it as if pthread_once had not been called by the cancelled thread.

Return Value

pthread_once returns 0 on success, or an error code on failure.

Errors

The pthread_once function returns the following error code on error:

EINVAL

The once_control or init_routine parameter is NULL.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_cond_init.html0000644000175000000620000003236711512143043023063 0ustar stevestaff PTHREAD_COND(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_cond_init, pthread_cond_destroy, pthread_cond_signal, pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait - operations on conditions

Synopsis

#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

int pthread_cond_destroy(pthread_cond_t *cond);

Description

A condition (short for ‘‘condition variable’’) is a synchronization device that allows threads to suspend execution and relinquish the processors until some predicate on shared data is satisfied. The basic operations on conditions are: signal the condition (when the predicate becomes true), and wait for the condition, suspending the thread execution until another thread signals the condition.

A condition variable must always be associated with a mutex, to avoid the race condition where a thread prepares to wait on a condition variable and another thread signals the condition just before the first thread actually waits on it.

pthread_cond_init initializes the condition variable cond, using the condition attributes specified in cond_attr, or default attributes if cond_attr is NULL.

Variables of type pthread_cond_t can also be initialized statically, using the constant PTHREAD_COND_INITIALIZER. In the Pthreads-w32 implementation, an application should still call pthread_cond_destroy at some point to ensure that any resources consumed by the condition variable are released.

pthread_cond_signal restarts one of the threads that are waiting on the condition variable cond. If no threads are waiting on cond, nothing happens. If several threads are waiting on cond, exactly one is restarted, but it is not specified which.

pthread_cond_broadcast restarts all the threads that are waiting on the condition variable cond. Nothing happens if no threads are waiting on cond.

pthread_cond_wait atomically unlocks the mutex (as per pthread_unlock_mutex) and waits for the condition variable cond to be signalled. The thread execution is suspended and does not consume any CPU time until the condition variable is signalled. The mutex must be locked by the calling thread on entrance to pthread_cond_wait. Before returning to the calling thread, pthread_cond_wait re-acquires mutex (as per pthread_lock_mutex).

Unlocking the mutex and suspending on the condition variable is done atomically. Thus, if all threads always acquire the mutex before signalling the condition, this guarantees that the condition cannot be signalled (and thus ignored) between the time a thread locks the mutex and the time it waits on the condition variable.

pthread_cond_timedwait atomically unlocks mutex and waits on cond, as pthread_cond_wait does, but it also bounds the duration of the wait. If cond has not been signalled within the amount of time specified by abstime, the mutex mutex is re-acquired and pthread_cond_timedwait returns the error ETIMEDOUT. The abstime parameter specifies an absolute time, with the same origin as time(2) and gettimeofday(2).

pthread_cond_destroy destroys a condition variable, freeing the resources it might hold. No threads must be waiting on the condition variable on entrance to pthread_cond_destroy.

Cancellation

pthread_cond_wait and pthread_cond_timedwait are cancellation points. If a thread is cancelled while suspended in one of these functions, the thread immediately resumes execution, then locks again the mutex argument to pthread_cond_wait and pthread_cond_timedwait, and finally executes the cancellation. Consequently, cleanup handlers are assured that mutex is locked when they are called.

Async-signal Safety

The condition functions are not async-signal safe, and should not be called from a signal handler. In particular, calling pthread_cond_signal or pthread_cond_broadcast from a signal handler may deadlock the calling thread.

Return Value

All condition variable functions return 0 on success and a non-zero error code on error.

Errors

pthread_cond_init, pthread_cond_signal, pthread_cond_broadcast, and pthread_cond_wait never return an error code.

The pthread_cond_init function returns the following error codes on error:

EINVAL
The cond argument is invalid.
ENOMEM
There was not enough memory to allocate the condition variable.

The pthread_cond_signal function returns the following error codes on error:

EINVAL
The cond argument is invalid.

The pthread_cond_broadcast function returns the following error codes on error:

EINVAL
The cond argument is invalid.

The pthread_cond_wait function returns the following error codes on error:

EINVAL
The cond argument is invalid.
ENOMEM
There was not enough memory to allocate the statically initialised condition variable. Statically initialised condition variables are dynamically allocated by the first thread to wait on them.

The pthread_cond_timedwait function returns the following error codes on error:

EINVAL

The cond argument is invalid.

ETIMEDOUT
The condition variable was not signalled before the timeout specified by abstime
ENOMEM
There was not enough memory to allocate the statically initialised condition variable. Statically initialised condition variables are dynamically allocated by the first thread to wait on them.

The pthread_cond_destroy function returns the following error code on error:

EINVAL

The cond argument is invalid.

EBUSY
Some threads are currently waiting on cond.

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_condattr_init(3) , pthread_mutex_lock(3) , pthread_mutex_unlock(3) , pthread_cancel(3).

Example

Consider two shared variables x and y, protected by the mutex mut, and a condition variable cond that is to be signaled whenever x becomes greater than y.

int x,y;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Waiting until x is greater than y is performed as follows:
pthread_mutex_lock(&mut);
while (x <= y) {
        pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
Modifications on x and y that may cause x to become greater than y should signal the condition if needed:
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
If it can be proved that at most one waiting thread needs to be waken up (for instance, if there are only two threads communicating through x and y), pthread_cond_signal can be used as a slightly more efficient alternative to pthread_cond_broadcast. If in doubt, use pthread_cond_broadcast.
To wait for x to become greater than y with a timeout of 5 seconds, do:
struct timeval now;
struct timespec timeout;
int retcode;
pthread_mutex_lock(&mut);
gettimeofday(&now);
timeout.tv_sec = now.tv_sec + 5;
timeout.tv_nsec = now.tv_usec * 1000;
retcode = 0;
while (x <= y && retcode != ETIMEDOUT) {
        retcode = pthread_cond_timedwait(&cond, &mut, &timeout);
}
if (retcode == ETIMEDOUT) {
        /* timeout occurred */
} else {
        /* operate on x and y */
}
pthread_mutex_unlock(&mut);

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_mutexattr_init.html0000644000175000000620000001622111512143043024164 0ustar stevestaff PTHREAD_MUTEXATTR(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_mutexattr_init, pthread_mutexattr_destroy, pthread_mutexattr_settype, pthread_mutexattr_gettype - mutex creation attributes

Synopsis

#include <pthread.h>

int pthread_mutexattr_init(pthread_mutexattr_t *attr);

int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);

int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);

int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int type);

int pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr, int *type);

Description

Mutex attributes can be specified at mutex creation time, by passing a mutex attribute object as second argument to pthread_mutex_init(3) . Passing NULL is equivalent to passing a mutex attribute object with all attributes set to their default values.

pthread_mutexattr_init initializes the mutex attribute object attr and fills it with default values for the attributes.

pthread_mutexattr_destroy destroys a mutex attribute object, which must not be reused until it is reinitialized.

The following mutex types are supported:

PTHREAD_MUTEX_NORMAL - for ‘‘fast’’ mutexes.

PTHREAD_MUTEX_RECURSIVE - for ‘‘recursive’’ mutexes.

PTHREAD_MUTEX_ERRORCHECK - for ‘‘error checking’’ mutexes.

The mutex type determines what happens if a thread attempts to lock a mutex it already owns with pthread_mutex_lock(3) . If the mutex is of the “normal” or “fast” type, pthread_mutex_lock(3) simply suspends the calling thread forever. If the mutex is of the ‘‘error checking’’ type, pthread_mutex_lock(3) returns immediately with the error code EDEADLK. If the mutex is of the ‘‘recursive’’ type, the call to pthread_mutex_lock(3) returns immediately with a success return code. The number of times the thread owning the mutex has locked it is recorded in the mutex. The owning thread must call pthread_mutex_unlock(3) the same number of times before the mutex returns to the unlocked state.

The default mutex type is PTHREAD_MUTEX_NORMAL

Pthreads-w32 also recognises the following equivalent types that are used by Linux:

PTHREAD_MUTEX_FAST_NP – equivalent to PTHREAD_MUTEX_NORMAL

PTHREAD_MUTEX_RECURSIVE_NP

PTHREAD_MUTEX_ERRORCHECK_NP

pthread_mutexattr_settype sets the mutex type attribute in attr to the value specified by type.

pthread_mutexattr_gettype retrieves the current value of the mutex kind attribute in attr and stores it in the location pointed to by type.

Pthreads-w32 also recognises the following equivalent functions that are used in Linux:

pthread_mutexattr_setkind_np is an alias for pthread_mutexattr_settype.

pthread_mutexattr_getkind_np is an alias for pthread_mutexattr_gettype.

Return Value

pthread_mutexattr_init, pthread_mutexattr_destroy and pthread_mutexattr_gettype always return 0.

pthread_mutexattr_settype returns 0 on success and a non-zero error code on error.

Errors

On error, pthread_mutexattr_settype returns the following error code:

EINVAL
type is none of:
PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK
, PTHREAD_MUTEX_ERRORCHECK_NP

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_mutex_init(3) , pthread_mutex_lock(3) , pthread_mutex_unlock(3) .

Notes

For speed, Pthreads-w32 never checks the thread ownership of mutexes of type PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_FAST_NP) when performing operations on the mutex. It is therefore possible for one thread to lock such a mutex and another to unlock it.

When developing code, it is a common precaution to substitute the error checking type, and drop in the normal type for release if the extra performance is required.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/sched_setscheduler.html0000644000175000000620000001720011512143043023233 0ustar stevestaff "SCHED_SETSCHEDULER"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

sched_setscheduler - set scheduling policy and parameters (REALTIME)

Synopsis

#include <sched.h>

int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param);

Description

The sched_setscheduler function shall set the scheduling policy and scheduling parameters of the process specified by pid to policy and the parameters specified in the sched_param structure pointed to by param, respectively. The value of the sched_priority member in the sched_param structure shall be any integer within the inclusive priority range for the scheduling policy specified by policy. If the value of pid is negative, the behavior of the sched_setscheduler function is unspecified.

The possible values for the policy parameter are defined in the <sched.h> header.

Pthreads-w32 only supports the SCHED_OTHER policy. Any other value for policy will return failure with errno set to ENOSYS. However, checks on pid and permissions are performed first so that the other useful side effects of this routine are retained.

If a process specified by pid exists, and if the calling process has permission, the scheduling policy and scheduling parameters shall be set for the process whose process ID is equal to pid.

If pid is zero, the scheduling policy and scheduling parameters shall be set for the calling process.

Implementations may require that the requesting process have permission to set its own scheduling parameters or those of another process. Additionally, implementation-defined restrictions may apply as to the appropriate privileges required to set a process’ own scheduling policy, or another process’ scheduling policy, to a particular value.

The sched_setscheduler function shall be considered successful if it succeeds in setting the scheduling policy and scheduling parameters of the process specified by pid to the values specified by policy and the structure pointed to by param, respectively.

The effect of this function on individual threads is dependent on the scheduling contention scope of the threads:

*
For threads with system scheduling contention scope, these functions shall have no effect on their scheduling.
*
For threads with process scheduling contention scope, the threads’ scheduling policy and associated parameters shall not be affected. However, the scheduling of these threads with respect to threads in other processes may be dependent on the scheduling parameters of their process, which are governed using these functions.

This function is not atomic with respect to other threads in the process. Threads may continue to execute while this function call is in the process of changing the scheduling policy and associated scheduling parameters for the underlying kernel-scheduled entities used by the process contention scope threads.

Return Value

Upon successful completion, the function shall return the former scheduling policy of the specified process. If the sched_setscheduler function fails to complete successfully, the policy and scheduling parameters shall remain unchanged, and the function shall return a value of -1 and set errno to indicate the error.

Errors

The sched_setscheduler function shall fail if:

EINVAL
The value of the policy parameter is invalid, or one or more of the parameters contained in param is outside the valid range for the specified scheduling policy.
EPERM
The requesting process does not have permission to set either or both of the scheduling parameters or the scheduling policy of the specified process.
ESRCH
No process can be found corresponding to that specified by pid.

The following sections are informative.

Examples

None.

Application Usage

None.

Rationale

None.

Future Directions

None.

See Also

sched_getscheduler(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <sched.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/manual/pthread_setcancelstate.html0000644000175000000620000002273611512143043024116 0ustar stevestaff PTHREAD_CANCEL(3) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_cancel, pthread_setcancelstate, pthread_setcanceltype, pthread_testcancel - thread cancellation

Synopsis

#include <pthread.h>

int pthread_cancel(pthread_t thread);

int pthread_setcancelstate(int state, int *oldstate);

int pthread_setcanceltype(int type, int *oldtype);

void pthread_testcancel(void);

Description

Cancellation is the mechanism by which a thread can terminate the execution of another thread. More precisely, a thread can send a cancellation request to another thread. Depending on its settings, the target thread can then either ignore the request, honor it immediately, or defer it until it reaches a cancellation point.

When a thread eventually honors a cancellation request, it performs as if pthread_exit(PTHREAD_CANCELED) has been called at that point: all cleanup handlers are executed in reverse order, destructor functions for thread-specific data are called, and finally the thread stops executing with the return value PTHREAD_CANCELED. See pthread_exit(3) for more information.

pthread_cancel sends a cancellation request to the thread denoted by the thread argument.

pthread_setcancelstate changes the cancellation state for the calling thread -- that is, whether cancellation requests are ignored or not. The state argument is the new cancellation state: either PTHREAD_CANCEL_ENABLE to enable cancellation, or PTHREAD_CANCEL_DISABLE to disable cancellation (cancellation requests are ignored). If oldstate is not NULL, the previous cancellation state is stored in the location pointed to by oldstate, and can thus be restored later by another call to pthread_setcancelstate.

pthread_setcanceltype changes the type of responses to cancellation requests for the calling thread: asynchronous (immediate) or deferred. The type argument is the new cancellation type: either PTHREAD_CANCEL_ASYNCHRONOUS to cancel the calling thread as soon as the cancellation request is received, or PTHREAD_CANCEL_DEFERRED to keep the cancellation request pending until the next cancellation point. If oldtype is not NULL, the previous cancellation state is stored in the location pointed to by oldtype, and can thus be restored later by another call to pthread_setcanceltype.

Pthreads-w32 provides two levels of support for PTHREAD_CANCEL_ASYNCHRONOUS: full and partial. Full support requires an additional DLL and driver be installed on the Windows system (see the See Also section below) that allows blocked threads to be cancelled immediately. Partial support means that the target thread will not cancel until it resumes execution naturally. Partial support is provided if either the DLL or the driver are not automatically detected by the pthreads-w32 library at run-time.

Threads are always created by pthread_create(3) with cancellation enabled and deferred. That is, the initial cancellation state is PTHREAD_CANCEL_ENABLE and the initial type is PTHREAD_CANCEL_DEFERRED.

Cancellation points are those points in the program execution where a test for pending cancellation requests is performed and cancellation is executed if positive. The following POSIX threads functions are cancellation points:

pthread_join(3)
pthread_cond_wait(3)
pthread_cond_timedwait(3)
pthread_testcancel(3)
sem_wait(3)
sem_timedwait(3)
sigwait(3) (not supported under Pthreads-w32)

Pthreads-w32 provides two functions to enable additional cancellation points to be created in user functions that block on Win32 HANDLEs:

pthreadCancelableWait()
pthreadCancelableTimedWait()

All other POSIX threads functions are guaranteed not to be cancellation points. That is, they never perform cancellation in deferred cancellation mode.

pthread_testcancel does nothing except testing for pending cancellation and executing it. Its purpose is to introduce explicit checks for cancellation in long sequences of code that do not call cancellation point functions otherwise.

Return Value

pthread_cancel, pthread_setcancelstate and pthread_setcanceltype return 0 on success and a non-zero error code on error.

Errors

pthread_cancel returns the following error code on error:

ESRCH
no thread could be found corresponding to that specified by the thread ID.

pthread_setcancelstate returns the following error code on error:

EINVAL
the state argument is not
PTHREAD_CANCEL_ENABLE nor PTHREAD_CANCEL_DISABLE

pthread_setcanceltype returns the following error code on error:

EINVAL
the type argument is not
PTHREAD_CANCEL_DEFERRED nor PTHREAD_CANCEL_ASYNCHRONOUS

Author

Xavier Leroy <Xavier.Leroy@inria.fr>

Modified by Ross Johnson for use with Pthreads-w32.

See Also

pthread_exit(3) , pthread_cleanup_push(3) , pthread_cleanup_pop(3) , Pthreads-w32 package README file 'Prerequisites' section.

Bugs

POSIX specifies that a number of system calls (basically, all system calls that may block, such as read(2) , write(2) , wait(2) , etc.) and library functions that may call these system calls (e.g. fprintf(3) ) are cancellation points. Pthreads-win32 is not integrated enough with the C library to implement this, and thus none of the C library functions is a cancellation point.

A workaround for these calls is to temporarily switch to asynchronous cancellation (assuming full asynchronous cancellation support is installed). So, checking for cancellation during a read system call, for instance, can be achieved as follows:



pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldCancelType);
read(fd, buffer, length);
pthread_setcanceltype(oldCancelType, NULL);

Table of Contents
nyquist-3.05/liblo/pthreads.2/manual/pthread_spin_lock.html0000644000175000000620000001364011512143043023067 0ustar stevestaff "PTHREAD_SPIN_LOCK"(P) manual page

POSIX Threads for Windows – REFERENCE - Pthreads-w32

Reference Index

Table of Contents

Name

pthread_spin_lock, pthread_spin_trylock - lock a spin lock object (ADVANCED REALTIME THREADS)

Synopsis

#include <pthread.h>

int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *
lock);

Description

The pthread_spin_lock function shall lock the spin lock referenced by lock. The calling thread shall acquire the lock if it is not held by another thread. Otherwise, the thread shall spin (that is, shall not return from the pthread_spin_lock call) until the lock becomes available. The results are undefined if the calling thread holds the lock at the time the call is made.

Pthreads-w32 supports single and multiple processor systems as well as process CPU affinity masking by checking the mask when the spin lock is initialized. If the process is using only a single processor at the time pthread_spin_init(3) is called then the spin lock is initialized as a PTHREAD_MUTEX_NORMAL mutex object. A thread that calls pthread_spin_lock will block rather than spin in this case. If the process CPU affinity mask is altered after the spin lock has been initialised, the spin lock is not modified, and may no longer be optimal for the number of CPUs available.

The pthread_spin_trylock function shall lock the spin lock referenced by lock if it is not held by any thread. Otherwise, the function shall fail.

The results are undefined if any of these functions is called with an uninitialized spin lock.

Return Value

Upon successful completion, these functions shall return zero; otherwise, an error number shall be returned to indicate the error.

Errors

These functions may fail if:

EINVAL
The value specified by lock does not refer to an initialized spin lock object.

The pthread_spin_trylock function shall fail if:

EBUSY
A thread currently holds the lock.

These functions shall not return an error code of [EINTR].

The following sections are informative.

Examples

None.

Application Usage

Applications using this function may be subject to priority inversion, as discussed in the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.285, Priority Inversion.

Rationale

None.

Future Directions

None.

See Also

pthread_spin_destroy(3) , pthread_spin_unlock(3) , the Base Definitions volume of IEEE Std 1003.1-2001, <pthread.h>

Copyright

Portions of this text are reprinted and reproduced in electronic form from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between this version and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html .

Modified by Ross Johnson for use with Pthreads-w32.


Table of Contents

nyquist-3.05/liblo/pthreads.2/pthread_attr_getstackaddr.c0000644000175000000620000000635011512143043022601 0ustar stevestaff/* * pthread_attr_getstackaddr.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr) /* * ------------------------------------------------------ * DOCPUBLIC * This function determines the address of the stack * on which threads created with 'attr' will run. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * stackaddr * pointer into which is returned the stack address. * * * DESCRIPTION * This function determines the address of the stack * on which threads created with 'attr' will run. * * NOTES: * 1) Function supported only if this macro is * defined: * * _POSIX_THREAD_ATTR_STACKADDR * * 2) Create only one thread for each stack * address.. * * RESULTS * 0 successfully retreived stack address, * EINVAL 'attr' is invalid * ENOSYS function not supported * * ------------------------------------------------------ */ { #if defined( _POSIX_THREAD_ATTR_STACKADDR ) if (ptw32_is_attr (attr) != 0) { return EINVAL; } *stackaddr = (*attr)->stackaddr; return 0; #else return ENOSYS; #endif /* _POSIX_THREAD_ATTR_STACKADDR */ } nyquist-3.05/liblo/pthreads.2/pthread_testcancel.c0000644000175000000620000000662711512143043021243 0ustar stevestaff/* * pthread_testcancel.c * * Description: * POSIX thread functions related to thread cancellation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" void pthread_testcancel (void) /* * ------------------------------------------------------ * DOCPUBLIC * This function creates a deferred cancellation point * in the calling thread. The call has no effect if the * current cancelability state is * PTHREAD_CANCEL_DISABLE * * PARAMETERS * N/A * * * DESCRIPTION * This function creates a deferred cancellation point * in the calling thread. The call has no effect if the * current cancelability state is * PTHREAD_CANCEL_DISABLE * * NOTES: * 1) Cancellation is asynchronous. Use pthread_join * to wait for termination of thread if necessary * * RESULTS * N/A * * ------------------------------------------------------ */ { pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL) { return; } /* * Pthread_cancel() will have set sp->state to PThreadStateCancelPending * and set an event, so no need to enter kernel space if * sp->state != PThreadStateCancelPending - that only slows us down. */ if (sp->state != PThreadStateCancelPending) { return; } (void) pthread_mutex_lock (&sp->cancelLock); if (sp->cancelState != PTHREAD_CANCEL_DISABLE) { ResetEvent(sp->cancelEvent); sp->state = PThreadStateCanceling; (void) pthread_mutex_unlock (&sp->cancelLock); sp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); } (void) pthread_mutex_unlock (&sp->cancelLock); } /* pthread_testcancel */ nyquist-3.05/liblo/pthreads.2/pthread_rwlock_rdlock.c0000644000175000000620000000576111512143043021753 0ustar stevestaff/* * pthread_rwlock_rdlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_rdlock (pthread_rwlock_t * rwlock) { int result; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static rwlock. We check * again inside the guarded section of ptw32_rwlock_check_need_init() * to avoid race conditions. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = ptw32_rwlock_check_need_init (rwlock); if (result != 0 && result != EBUSY) { return result; } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) { return result; } if (++rwl->nSharedAccessCount == INT_MAX) { if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; if ((result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } } return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); } nyquist-3.05/liblo/pthreads.2/version.res0000644000175000000620000000211411512143043017426 0ustar stevestaff  0  4VS_VERSION_INFO?jStringFileInfoF040904b0p$FileDescriptionPOSIX Threads for Windows32 Library: ProductVersion2, 8, 0, 06 FileVersion2, 8, 0, 04 InternalNamepthreadVC< OriginalFilenamepthreadVCn'CompanyNameOpen Source Software community project~-LegalCopyrightCopyright (C) Project contributors 1998-2004"LicenceLGPLd*Infohttp://sources.redhat.com/pthreads-win32/b%CommentMS C build -- longjmp thread exitingDVarFileInfo$Translation nyquist-3.05/liblo/pthreads.2/pthread_attr_setdetachstate.c0000644000175000000620000000616611512143043023153 0ustar stevestaff/* * pthread_attr_setdetachstate.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate) /* * ------------------------------------------------------ * DOCPUBLIC * This function specifies whether threads created with * 'attr' will run detached. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * detachstate * an integer containing one of: * * PTHREAD_CREATE_JOINABLE * Thread ID is valid, must be joined * * PTHREAD_CREATE_DETACHED * Thread ID is invalid, cannot be joined, * canceled, or modified * * * DESCRIPTION * This function specifies whether threads created with * 'attr' will run detached. * * NOTES: * 1) You cannot join or cancel detached threads. * * RESULTS * 0 successfully set detach state, * EINVAL 'attr' or 'detachstate' is invalid * * ------------------------------------------------------ */ { if (ptw32_is_attr (attr) != 0) { return EINVAL; } if (detachstate != PTHREAD_CREATE_JOINABLE && detachstate != PTHREAD_CREATE_DETACHED) { return EINVAL; } (*attr)->detachstate = detachstate; return 0; } nyquist-3.05/liblo/pthreads.2/config.h0000644000175000000620000000762311512143043016656 0ustar stevestaff/* config.h */ #ifndef PTW32_CONFIG_H #define PTW32_CONFIG_H /********************************************************************* * Defaults: see target specific redefinitions below. *********************************************************************/ /* We're building the pthreads-win32 library */ #define PTW32_BUILD /* Do we know about the C type sigset_t? */ #undef HAVE_SIGSET_T /* Define if you have the header file. */ #undef HAVE_SIGNAL_H /* Define if you have the Borland TASM32 or compatible assembler. */ #undef HAVE_TASM32 /* Define if you don't have Win32 DuplicateHandle. (eg. WinCE) */ #undef NEED_DUPLICATEHANDLE /* Define if you don't have Win32 _beginthreadex. (eg. WinCE) */ #undef NEED_CREATETHREAD /* Define if you don't have Win32 errno. (eg. WinCE) */ #undef NEED_ERRNO /* Define if you don't have Win32 calloc. (eg. WinCE) */ #undef NEED_CALLOC /* Define if you don't have Win32 ftime. (eg. WinCE) */ #undef NEED_FTIME /* Define if you don't have Win32 semaphores. (eg. WinCE 2.1 or earlier) */ #undef NEED_SEM /* Define if you need to convert string parameters to unicode. (eg. WinCE) */ #undef NEED_UNICODE_CONSTS /* Define if your C (not C++) compiler supports "inline" functions. */ #undef HAVE_C_INLINE /* Do we know about type mode_t? */ #undef HAVE_MODE_T /* Define if you have the timespec struct */ #undef HAVE_STRUCT_TIMESPEC /* Define if you don't have the GetProcessAffinityMask() */ #undef NEED_PROCESS_AFFINITY_MASK /* # ---------------------------------------------------------------------- # The library can be built with some alternative behaviour to better # facilitate development of applications on Win32 that will be ported # to other POSIX systems. # # Nothing described here will make the library non-compliant and strictly # compliant applications will not be affected in any way, but # applications that make assumptions that POSIX does not guarantee are # not strictly compliant and may fail or misbehave with some settings. # # PTW32_THREAD_ID_REUSE_INCREMENT # Purpose: # POSIX says that applications should assume that thread IDs can be # recycled. However, Solaris (and some other systems) use a [very large] # sequence number as the thread ID, which provides virtual uniqueness. # This provides a very high but finite level of safety for applications # that are not meticulous in tracking thread lifecycles e.g. applications # that call functions which target detached threads without some form of # thread exit synchronisation. # # Usage: # Set to any value in the range: 0 <= value < 2^wordsize. # Set to 0 to emulate reusable thread ID behaviour like Linux or *BSD. # Set to 1 for unique thread IDs like Solaris (this is the default). # Set to some factor of 2^wordsize to emulate smaller word size types # (i.e. will wrap sooner). This might be useful to emulate some embedded # systems. # # define PTW32_THREAD_ID_REUSE_INCREMENT 0 # # ---------------------------------------------------------------------- */ #undef PTW32_THREAD_ID_REUSE_INCREMENT /********************************************************************* * Target specific groups * * If you find that these are incorrect or incomplete please report it * to the pthreads-win32 maintainer. Thanks. *********************************************************************/ #ifdef WINCE #define NEED_DUPLICATEHANDLE #define NEED_CREATETHREAD #define NEED_ERRNO #define NEED_CALLOC #define NEED_FTIME //#define NEED_SEM #define NEED_UNICODE_CONSTS #define NEED_PROCESS_AFFINITY_MASK #endif #ifdef _UWIN #define HAVE_MODE_T #define HAVE_STRUCT_TIMESPEC #endif #ifdef __GNUC__ #define HAVE_C_INLINE #endif #ifdef __MINGW32__ #define HAVE_MODE_T #endif #ifdef __BORLANDC__ #endif #ifdef __WATCOMC__ #endif #ifdef __DMC__ #define HAVE_SIGNAL_H #define HAVE_C_INLINE #endif #endif nyquist-3.05/liblo/pthreads.2/ANNOUNCE0000644000175000000620000003355411512143043016373 0ustar stevestaff PTHREADS-WIN32 RELEASE 2.8.0 (2006-12-22) ----------------------------------------- Web Site: http://sources.redhat.com/pthreads-win32/ FTP Site: ftp://sources.redhat.com/pub/pthreads-win32 Maintainer: Ross Johnson We are pleased to announce the availability of a new release of Pthreads-win32, an Open Source Software implementation of the Threads component of the POSIX 1003.1 2001 Standard for Microsoft's Win32 environment. Some functions from other sections of POSIX 1003.1 2001 are also supported including semaphores and scheduling functions. Some common non-portable functions are also implemented for additional compatibility, as are a few functions specific to pthreads-win32 for easier integration with Win32 applications. Pthreads-win32 is free software, distributed under the GNU Lesser General Public License (LGPL). Acknowledgements ---------------- This library is based originally on a Win32 pthreads implementation contributed by John Bossom . The implementation of Condition Variables uses algorithms developed by Alexander Terekhov and Louis Thomas. The implementation of POSIX mutexes has been improved by Thomas Pfaff and later by Alexander Terekhov. The implementation of Spinlocks and Barriers was contributed by Ross Johnson. The implementation of read/write locks was contributed by Aurelio Medina and improved by Alexander Terekhov. Many others have contributed significant time and effort to solve crutial problems in order to make the library workable, robust and reliable. Thanks to Xavier Leroy for granting permission to use and modify his LinuxThreads manual pages. Thanks to The Open Group for making the Single Unix Specification publicly available - many of the manual pages included in the package were extracted from it. There is also a separate CONTRIBUTORS file. This file and others are on the web site: http://sources.redhat.com/pthreads-win32 As much as possible, the ChangeLog file acknowledges contributions to the code base in more detail. Changes since the last release ------------------------------ These are now documented in the NEWS file. See the ChangeLog file also. Known Bugs ---------- These are now documented in the BUGS file. Level of standards conformance ------------------------------ The following POSIX 1003.1 2001 options are defined and set to 200112L: _POSIX_THREADS _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_THREAD_ATTR_STACKSIZE _POSIX_THREAD_PRIORITY_SCHEDULING _POSIX_SEMAPHORES _POSIX_READER_WRITER_LOCKS _POSIX_SPIN_LOCKS _POSIX_BARRIERS The following POSIX 1003.1 2001 options are defined and set to -1: _POSIX_THREAD_ATTR_STACKADDR _POSIX_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_PROTECT _POSIX_THREAD_PROCESS_SHARED The following POSIX 1003.1 2001 limits are defined and set: _POSIX_THREAD_THREADS_MAX _POSIX_SEM_VALUE_MAX _POSIX_SEM_NSEMS_MAX _POSIX_THREAD_KEYS_MAX _POSIX_THREAD_DESTRUCTOR_ITERATIONS PTHREAD_STACK_MIN PTHREAD_THREADS_MAX SEM_VALUE_MAX SEM_NSEMS_MAX PTHREAD_KEYS_MAX PTHREAD_DESTRUCTOR_ITERATIONS The following functions are implemented: --------------------------- PThreads --------------------------- pthread_attr_init pthread_attr_destroy pthread_attr_getdetachstate pthread_attr_getstackaddr pthread_attr_getstacksize pthread_attr_setdetachstate pthread_attr_setstackaddr pthread_attr_setstacksize pthread_create pthread_detach pthread_equal pthread_exit pthread_join pthread_once pthread_self pthread_cancel pthread_cleanup_pop pthread_cleanup_push pthread_setcancelstate pthread_setcanceltype pthread_testcancel --------------------------- Thread Specific Data --------------------------- pthread_key_create pthread_key_delete pthread_setspecific pthread_getspecific --------------------------- Mutexes --------------------------- pthread_mutexattr_init pthread_mutexattr_destroy pthread_mutexattr_getpshared pthread_mutexattr_setpshared pthread_mutexattr_gettype pthread_mutexattr_settype (types: PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_RECURSIVE ) pthread_mutex_init pthread_mutex_destroy pthread_mutex_lock pthread_mutex_trylock pthread_mutex_timedlock pthread_mutex_unlock --------------------------- Condition Variables --------------------------- pthread_condattr_init pthread_condattr_destroy pthread_condattr_getpshared pthread_condattr_setpshared pthread_cond_init pthread_cond_destroy pthread_cond_wait pthread_cond_timedwait pthread_cond_signal pthread_cond_broadcast --------------------------- Read/Write Locks --------------------------- pthread_rwlock_init pthread_rwlock_destroy pthread_rwlock_tryrdlock pthread_rwlock_trywrlock pthread_rwlock_rdlock pthread_rwlock_timedrdlock pthread_rwlock_rwlock pthread_rwlock_timedwrlock pthread_rwlock_unlock pthread_rwlockattr_init pthread_rwlockattr_destroy pthread_rwlockattr_getpshared pthread_rwlockattr_setpshared --------------------------- Spin Locks --------------------------- pthread_spin_init pthread_spin_destroy pthread_spin_lock pthread_spin_unlock pthread_spin_trylock --------------------------- Barriers --------------------------- pthread_barrier_init pthread_barrier_destroy pthread_barrier_wait pthread_barrierattr_init pthread_barrierattr_destroy pthread_barrierattr_getpshared pthread_barrierattr_setpshared --------------------------- Semaphores --------------------------- sem_init sem_destroy sem_post sem_wait sem_trywait sem_timedwait sem_getvalue (# free if +ve, # of waiters if -ve) sem_open (returns an error ENOSYS) sem_close (returns an error ENOSYS) sem_unlink (returns an error ENOSYS) --------------------------- RealTime Scheduling --------------------------- pthread_attr_getschedparam pthread_attr_setschedparam pthread_attr_getinheritsched pthread_attr_setinheritsched pthread_attr_getschedpolicy (only supports SCHED_OTHER) pthread_attr_setschedpolicy (only supports SCHED_OTHER) pthread_getschedparam pthread_setschedparam pthread_getconcurrency pthread_setconcurrency pthread_attr_getscope pthread_attr_setscope (only supports PTHREAD_SCOPE_SYSTEM) sched_get_priority_max sched_get_priority_min sched_rr_get_interval (returns an error ENOTSUP) sched_setscheduler (only supports SCHED_OTHER) sched_getscheduler (only supports SCHED_OTHER) sched_yield --------------------------- Signals --------------------------- pthread_sigmask pthread_kill (only supports zero sig value, for thread validity checking) --------------------------- Non-portable routines (see the README.NONPORTABLE file for usage) --------------------------- pthread_getw32threadhandle_np pthread_timechange_handler_np pthread_delay_np pthread_mutexattr_getkind_np pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_ERRORCHECK_NP, PTHREAD_MUTEX_RECURSIVE_NP, PTHREAD_MUTEX_ADAPTIVE_NP, PTHREAD_MUTEX_TIMED_NP) pthread_num_processors_np pthread_win32_process_attach_np (Required when statically linking the library) pthread_win32_process_detach_np (Required when statically linking the library) pthread_win32_thread_attach_np (Required when statically linking the library) pthread_win32_thread_detach_np (Required when statically linking the library) --------------------------- Static Initializers --------------------------- PTHREAD_ONCE_INIT PTHREAD_MUTEX_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_COND_INITIALIZER PTHREAD_RWLOCK_INITIALIZER PTHREAD_SPINLOCK_INITIALIZER --------------------------- Thread-Safe C Runtime Library (macros) --------------------------- strtok_r asctime_r ctime_r gmtime_r localtime_r rand_r The following functions are not implemented: --------------------------- RealTime Scheduling --------------------------- pthread_mutex_getprioceiling pthread_mutex_setprioceiling pthread_mutex_attr_getprioceiling pthread_mutex_attr_getprotocol pthread_mutex_attr_setprioceiling pthread_mutex_attr_setprotocol --------------------------- Fork Handlers --------------------------- pthread_atfork --------------------------- Stdio --------------------------- flockfile ftrylockfile funlockfile getc_unlocked getchar_unlocked putc_unlocked putchar_unlocked --------------------------- Thread-Safe C Runtime Library --------------------------- readdir_r getgrgid_r getgrnam_r getpwuid_r getpwnam_r --------------------------- Signals --------------------------- sigtimedwait sigwait sigwaitinfo --------------------------- General --------------------------- sysconf The library includes two non-API functions for creating cancellation points in applications and libraries: pthreadCancelableWait pthreadCancelableTimedWait Availability ------------ The prebuilt DLL, export libs (for both MSVC and Mingw32), and the header files (pthread.h, semaphore.h, sched.h) are available along with the complete source code. The source code can be found at: ftp://sources.redhat.com/pub/pthreads-win32 and as individual source code files at ftp://sources.redhat.com/pub/pthreads-win32/source The pre-built DLL, export libraries and include files can be found at: ftp://sources.redhat.com/pub/pthreads-win32/dll-latest Mailing List ------------ There is a mailing list for discussing pthreads on Win32. To join, send email to: pthreads-win32-subscribe@sourceware.cygnus.com Application Development Environments ------------------------------------ See the README file for more information. MSVC: MSVC using SEH works. Distribute pthreadVSE.dll with your application. MSVC using C++ EH works. Distribute pthreadVCE.dll with your application. MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your application. Mingw32: See the FAQ, Questions 6 and 10. Mingw using C++ EH works. Distribute pthreadGCE.dll with your application. Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your application. Cygwin: (http://sourceware.cygnus.com/cygwin/) Developers using Cygwin will not need pthreads-win32 since it has POSIX threads support. Refer to its documentation for details and extent. UWIN: UWIN is a complete Unix-like environment for Windows from AT&T. Pthreads-win32 doesn't currently support UWIN (and vice versa), but that may change in the future. Generally: For convenience, the following pre-built files are available on the FTP site (see Availability above): pthread.h - for POSIX 1c threads semaphore.h - for POSIX 1b semaphores sched.h - for POSIX 1b scheduling pthreadVCE.dll - built with MSVC++ compiler using C++ EH pthreadVCE.lib pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp pthreadVC.lib pthreadVSE.dll - built with MSVC compiler using SEH pthreadVSE.lib pthreadGCE.dll - built with Mingw32 G++ 2.95.2-1 pthreadGC.dll - built with Mingw32 GCC 2.95.2-1 using setjmp/longjmp libpthreadGCE.a - derived from pthreadGCE.dll libpthreadGC.a - derived from pthreadGC.dll gcc.dll - needed if distributing applications that use pthreadGCE.dll (but see the FAQ Q 10 for the latest related information) These are the only files you need in order to build POSIX threads applications for Win32 using either MSVC or Mingw32. See the FAQ file in the source tree for additional information. Documentation ------------- For the authoritative reference, see the online POSIX standard reference at: http://www.OpenGroup.org For POSIX Thread API programming, several reference books are available: Programming with POSIX Threads David R. Butenhof Addison-Wesley (pub) Pthreads Programming By Bradford Nichols, Dick Buttlar & Jacqueline Proulx Farrell O'Reilly (pub) On the web: see the links at the bottom of the pthreads-win32 site: http://sources.redhat.com/pthreads-win32/ Currently, there is no documentation included in the package apart from the copious comments in the source code. Enjoy! Ross Johnson nyquist-3.05/liblo/pthreads.2/pthread_attr_destroy.c0000644000175000000620000000502511512143043021630 0ustar stevestaff/* * pthread_attr_destroy.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_attr_destroy (pthread_attr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Destroys a thread attributes object. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * * DESCRIPTION * Destroys a thread attributes object. * * NOTES: * 1) Does not affect threads created with 'attr'. * * RESULTS * 0 successfully destroyed attr, * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ { if (ptw32_is_attr (attr) != 0) { return EINVAL; } /* * Set the attribute object to a specific invalid value. */ (*attr)->valid = 0; free (*attr); *attr = NULL; return 0; } nyquist-3.05/liblo/pthreads.2/signal.c0000644000175000000620000001240111512143043016647 0ustar stevestaff/* * signal.c * * Description: * Thread-aware signal functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * Possible future strategy for implementing pthread_kill() * ======================================================== * * Win32 does not implement signals. * Signals are simply software interrupts. * pthread_kill() asks the system to deliver a specified * signal (interrupt) to a specified thread in the same * process. * Signals are always asynchronous (no deferred signals). * Pthread-win32 has an async cancelation mechanism. * A similar system can be written to deliver signals * within the same process (on ix86 processors at least). * * Each thread maintains information about which * signals it will respond to. Handler routines * are set on a per-process basis - not per-thread. * When signalled, a thread will check it's sigmask * and, if the signal is not being ignored, call the * handler routine associated with the signal. The * thread must then (except for some signals) return to * the point where it was interrupted. * * Ideally the system itself would check the target thread's * mask before possibly needlessly bothering the thread * itself. This could be done by pthread_kill(), that is, * in the signaling thread since it has access to * all pthread_t structures. It could also retrieve * the handler routine address to minimise the target * threads response overhead. This may also simplify * serialisation of the access to the per-thread signal * structures. * * pthread_kill() eventually calls a routine similar to * ptw32_cancel_thread() which manipulates the target * threads processor context to cause the thread to * run the handler launcher routine. pthread_kill() must * save the target threads current context so that the * handler launcher routine can restore the context after * the signal handler has returned. Some handlers will not * return, eg. the default SIGKILL handler may simply * call pthread_exit(). * * The current context is saved in the target threads * pthread_t structure. */ #include "pthread.h" #include "implement.h" #if HAVE_SIGSET_T static void ptw32_signal_thread () { } static void ptw32_signal_callhandler () { } int pthread_sigmask (int how, sigset_t const *set, sigset_t * oset) { pthread_t thread = pthread_self (); if (thread.p == NULL) { return ENOENT; } /* Validate the `how' argument. */ if (set != NULL) { switch (how) { case SIG_BLOCK: break; case SIG_UNBLOCK: break; case SIG_SETMASK: break; default: /* Invalid `how' argument. */ return EINVAL; } } /* Copy the old mask before modifying it. */ if (oset != NULL) { memcpy (oset, &(thread.p->sigmask), sizeof (sigset_t)); } if (set != NULL) { unsigned int i; /* FIXME: this code assumes that sigmask is an even multiple of the size of a long integer. */ unsigned long *src = (unsigned long const *) set; unsigned long *dest = (unsigned long *) &(thread.p->sigmask); switch (how) { case SIG_BLOCK: for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) { /* OR the bit field longword-wise. */ *dest++ |= *src++; } break; case SIG_UNBLOCK: for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) { /* XOR the bitfield longword-wise. */ *dest++ ^= *src++; } case SIG_SETMASK: /* Replace the whole sigmask. */ memcpy (&(thread.p->sigmask), set, sizeof (sigset_t)); break; } } return 0; } int sigwait (const sigset_t * set, int *sig) { /* This routine is a cancellation point */ pthread_test_cancel(); } int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) { } #endif /* HAVE_SIGSET_T */ nyquist-3.05/liblo/pthreads.2/cleanup.c0000644000175000000620000001210011512143043017015 0ustar stevestaff/* * cleanup.c * * Description: * This translation unit implements routines associated * with cleaning up threads. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * The functions ptw32_pop_cleanup and ptw32_push_cleanup * are implemented here for applications written in C with no * SEH or C++ destructor support. */ ptw32_cleanup_t * ptw32_pop_cleanup (int execute) /* * ------------------------------------------------------ * DOCPUBLIC * This function pops the most recently pushed cleanup * handler. If execute is nonzero, then the cleanup handler * is executed if non-null. * * PARAMETERS * execute * if nonzero, execute the cleanup handler * * * DESCRIPTION * This function pops the most recently pushed cleanup * handler. If execute is nonzero, then the cleanup handler * is executed if non-null. * NOTE: specify 'execute' as nonzero to avoid duplication * of common cleanup code. * * RESULTS * N/A * * ------------------------------------------------------ */ { ptw32_cleanup_t *cleanup; cleanup = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); if (cleanup != NULL) { if (execute && (cleanup->routine != NULL)) { (*cleanup->routine) (cleanup->arg); } pthread_setspecific (ptw32_cleanupKey, (void *) cleanup->prev); } return (cleanup); } /* ptw32_pop_cleanup */ void ptw32_push_cleanup (ptw32_cleanup_t * cleanup, ptw32_cleanup_callback_t routine, void *arg) /* * ------------------------------------------------------ * DOCPUBLIC * This function pushes a new cleanup handler onto the thread's stack * of cleanup handlers. Each cleanup handler pushed onto the stack is * popped and invoked with the argument 'arg' when * a) the thread exits by calling 'pthread_exit', * b) when the thread acts on a cancellation request, * c) or when the thread calls pthread_cleanup_pop with a nonzero * 'execute' argument * * PARAMETERS * cleanup * a pointer to an instance of pthread_cleanup_t, * * routine * pointer to a cleanup handler, * * arg * parameter to be passed to the cleanup handler * * * DESCRIPTION * This function pushes a new cleanup handler onto the thread's stack * of cleanup handlers. Each cleanup handler pushed onto the stack is * popped and invoked with the argument 'arg' when * a) the thread exits by calling 'pthread_exit', * b) when the thread acts on a cancellation request, * c) or when the thrad calls pthread_cleanup_pop with a nonzero * 'execute' argument * NOTE: pthread_push_cleanup, ptw32_pop_cleanup must be paired * in the same lexical scope. * * RESULTS * pthread_cleanup_t * * pointer to the previous cleanup * * ------------------------------------------------------ */ { cleanup->routine = routine; cleanup->arg = arg; cleanup->prev = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); pthread_setspecific (ptw32_cleanupKey, (void *) cleanup); } /* ptw32_push_cleanup */ nyquist-3.05/liblo/pthreads.2/pthread_self.c0000644000175000000620000001001711512143043020033 0ustar stevestaff/* * pthread_self.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" pthread_t pthread_self (void) /* * ------------------------------------------------------ * DOCPUBLIC * This function returns a reference to the current running * thread. * * PARAMETERS * N/A * * * DESCRIPTION * This function returns a reference to the current running * thread. * * RESULTS * pthread_t reference to the current thread * * ------------------------------------------------------ */ { pthread_t self; pthread_t nil = {NULL, 0}; ptw32_thread_t * sp; #ifdef _UWIN if (!ptw32_selfThreadKey) return nil; #endif sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); if (sp != NULL) { self = sp->ptHandle; } else { /* * Need to create an implicit 'self' for the currently * executing thread. */ self = ptw32_new (); sp = (ptw32_thread_t *) self.p; if (sp != NULL) { /* * This is a non-POSIX thread which has chosen to call * a POSIX threads function for some reason. We assume that * it isn't joinable, but we do assume that it's * (deferred) cancelable. */ sp->implicit = 1; sp->detachState = PTHREAD_CREATE_DETACHED; sp->thread = GetCurrentThreadId (); #ifdef NEED_DUPLICATEHANDLE /* * DuplicateHandle does not exist on WinCE. * * NOTE: * GetCurrentThread only returns a pseudo-handle * which is only valid in the current thread context. * Therefore, you should not pass the handle to * other threads for whatever purpose. */ sp->threadH = GetCurrentThread (); #else if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &sp->threadH, 0, FALSE, DUPLICATE_SAME_ACCESS)) { /* * Should not do this, but we have no alternative if * we can't get a Win32 thread handle. * Thread structs are never freed. */ ptw32_threadReusePush (self); return nil; } #endif /* * No need to explicitly serialise access to sched_priority * because the new handle is not yet public. */ sp->sched_priority = GetThreadPriority (sp->threadH); pthread_setspecific (ptw32_selfThreadKey, (void *) sp); } } return (self); } /* pthread_self */ nyquist-3.05/liblo/pthreads.2/semaphore.c0000644000175000000620000000447411512143043017370 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: semaphore.c * * Purpose: * Concatenated version of separate modules to allow * inlining optimisation, which it is assumed can only * be effective within a single module. * * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef NEED_FTIME # include #endif #include #include "pthread.h" #include "semaphore.h" #include "implement.h" #include "sem_init.c" #include "sem_destroy.c" #include "sem_trywait.c" #include "sem_wait.c" #include "sem_timedwait.c" #include "sem_post.c" #include "sem_post_multiple.c" #include "sem_getvalue.c" #include "sem_open.c" #include "sem_close.c" #include "sem_unlink.c" nyquist-3.05/liblo/pthreads.2/Makefile0000644000175000000620000003542111512143043016675 0ustar stevestaff# This makefile is compatible with MS nmake and can be used as a # replacement for buildlib.bat. I've changed the target from an ordinary dll # (/LD) to a debugging dll (/LDd). # # The variables $DLLDEST and $LIBDEST hold the destination directories for the # dll and the lib, respectively. Probably all that needs to change is $DEVROOT. # DLL_VER: # See pthread.h and README - This number is computed as 'current - age' DLL_VER = 2 DLL_VERD= $(DLL_VER)d DEVROOT = C:\pthreads DLLDEST = $(DEVROOT)\DLL LIBDEST = $(DEVROOT)\LIB HDRDEST = $(DEVROOT)\INCLUDE DLLS = pthreadVCE$(DLL_VER).dll pthreadVSE$(DLL_VER).dll pthreadVC$(DLL_VER).dll \ pthreadVCE$(DLL_VERD).dll pthreadVSE$(DLL_VERD).dll pthreadVC$(DLL_VERD).dll INLINED_STAMPS = pthreadVCE$(DLL_VER).stamp pthreadVSE$(DLL_VER).stamp pthreadVC$(DLL_VER).stamp \ pthreadVCE$(DLL_VERD).stamp pthreadVSE$(DLL_VERD).stamp pthreadVC$(DLL_VERD).stamp STATIC_STAMPS = pthreadVCE$(DLL_VER).static pthreadVSE$(DLL_VER).static pthreadVC$(DLL_VER).static \ pthreadVCE$(DLL_VERD).static pthreadVSE$(DLL_VERD).static pthreadVC$(DLL_VERD).static OPTIM = /O2 /Ob2 OPTIMD = CFLAGS = /W3 /MD /nologo /Yd /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H CFLAGSD = /Zi $(CFLAGS) # Default cleanup style CLEANUP = __CLEANUP_C # C++ Exceptions VCEFLAGS = /GX /TP $(CFLAGS) VCEFLAGSD = /GX /TP $(CFLAGSD) #Structured Exceptions VSEFLAGS = $(CFLAGS) VSEFLAGSD = $(CFLAGSD) #C cleanup code VCFLAGS = $(CFLAGS) VCFLAGSD= $(CFLAGSD) DLL_INLINED_OBJS = \ pthread.obj \ version.res # Aggregate modules for inlinability DLL_OBJS = \ attr.obj \ barrier.obj \ cancel.obj \ cleanup.obj \ condvar.obj \ create.obj \ dll.obj \ errno.obj \ exit.obj \ fork.obj \ global.obj \ misc.obj \ mutex.obj \ nonportable.obj \ private.obj \ rwlock.obj \ sched.obj \ semaphore.obj \ signal.obj \ spin.obj \ sync.obj \ tsd.obj \ version.res # Separate modules for minimising the size of statically linked images SMALL_STATIC_OBJS = \ pthread_attr_init.obj \ pthread_attr_destroy.obj \ pthread_attr_getdetachstate.obj \ pthread_attr_setdetachstate.obj \ pthread_attr_getstackaddr.obj \ pthread_attr_setstackaddr.obj \ pthread_attr_getstacksize.obj \ pthread_attr_setstacksize.obj \ pthread_attr_getscope.obj \ pthread_attr_setscope.obj \ pthread_attr_setschedpolicy.obj \ pthread_attr_getschedpolicy.obj \ pthread_attr_setschedparam.obj \ pthread_attr_getschedparam.obj \ pthread_attr_setinheritsched.obj \ pthread_attr_getinheritsched.obj \ pthread_barrier_init.obj \ pthread_barrier_destroy.obj \ pthread_barrier_wait.obj \ pthread_barrierattr_init.obj \ pthread_barrierattr_destroy.obj \ pthread_barrierattr_setpshared.obj \ pthread_barrierattr_getpshared.obj \ pthread_setcancelstate.obj \ pthread_setcanceltype.obj \ pthread_testcancel.obj \ pthread_cancel.obj \ cleanup.obj \ pthread_condattr_destroy.obj \ pthread_condattr_getpshared.obj \ pthread_condattr_init.obj \ pthread_condattr_setpshared.obj \ pthread_cond_destroy.obj \ pthread_cond_init.obj \ pthread_cond_signal.obj \ pthread_cond_wait.obj \ create.obj \ dll.obj \ errno.obj \ pthread_exit.obj \ fork.obj \ global.obj \ pthread_mutex_init.obj \ pthread_mutex_destroy.obj \ pthread_mutexattr_init.obj \ pthread_mutexattr_destroy.obj \ pthread_mutexattr_getpshared.obj \ pthread_mutexattr_setpshared.obj \ pthread_mutexattr_settype.obj \ pthread_mutexattr_gettype.obj \ pthread_mutex_lock.obj \ pthread_mutex_timedlock.obj \ pthread_mutex_unlock.obj \ pthread_mutex_trylock.obj \ pthread_mutexattr_setkind_np.obj \ pthread_mutexattr_getkind_np.obj \ pthread_getw32threadhandle_np.obj \ pthread_delay_np.obj \ pthread_num_processors_np.obj \ pthread_win32_attach_detach_np.obj \ pthread_equal.obj \ pthread_getconcurrency.obj \ pthread_once.obj \ pthread_self.obj \ pthread_setconcurrency.obj \ pthread_rwlock_init.obj \ pthread_rwlock_destroy.obj \ pthread_rwlockattr_init.obj \ pthread_rwlockattr_destroy.obj \ pthread_rwlockattr_getpshared.obj \ pthread_rwlockattr_setpshared.obj \ pthread_rwlock_rdlock.obj \ pthread_rwlock_wrlock.obj \ pthread_rwlock_unlock.obj \ pthread_rwlock_tryrdlock.obj \ pthread_rwlock_trywrlock.obj \ pthread_setschedparam.obj \ pthread_getschedparam.obj \ pthread_timechange_handler_np.obj \ ptw32_is_attr.obj \ ptw32_processInitialize.obj \ ptw32_processTerminate.obj \ ptw32_threadStart.obj \ ptw32_threadDestroy.obj \ ptw32_tkAssocCreate.obj \ ptw32_tkAssocDestroy.obj \ ptw32_callUserDestroyRoutines.obj \ ptw32_timespec.obj \ ptw32_throw.obj \ ptw32_InterlockedCompareExchange.obj \ ptw32_getprocessors.obj \ ptw32_calloc.obj \ ptw32_new.obj \ ptw32_reuse.obj \ ptw32_rwlock_check_need_init.obj \ ptw32_cond_check_need_init.obj \ ptw32_mutex_check_need_init.obj \ ptw32_semwait.obj \ ptw32_relmillisecs.obj \ ptw32_MCS_lock.obj \ sched_get_priority_max.obj \ sched_get_priority_min.obj \ sched_setscheduler.obj \ sched_getscheduler.obj \ sched_yield.obj \ sem_init.obj \ sem_destroy.obj \ sem_trywait.obj \ sem_timedwait.obj \ sem_wait.obj \ sem_post.obj \ sem_post_multiple.obj \ sem_getvalue.obj \ sem_open.obj \ sem_close.obj \ sem_unlink.obj \ signal.obj \ pthread_kill.obj \ ptw32_spinlock_check_need_init.obj \ pthread_spin_init.obj \ pthread_spin_destroy.obj \ pthread_spin_lock.obj \ pthread_spin_unlock.obj \ pthread_spin_trylock.obj \ pthread_detach.obj \ pthread_join.obj \ pthread_key_create.obj \ pthread_key_delete.obj \ pthread_setspecific.obj \ pthread_getspecific.obj \ w32_CancelableWait.obj \ version.res INCL = config.h implement.h semaphore.h pthread.h need_errno.h ATTR_SRCS = \ pthread_attr_init.c \ pthread_attr_destroy.c \ pthread_attr_getdetachstate.c \ pthread_attr_setdetachstate.c \ pthread_attr_getstackaddr.c \ pthread_attr_setstackaddr.c \ pthread_attr_getstacksize.c \ pthread_attr_setstacksize.c \ pthread_attr_getscope.c \ pthread_attr_setscope.c BARRIER_SRCS = \ pthread_barrier_init.c \ pthread_barrier_destroy.c \ pthread_barrier_wait.c \ pthread_barrierattr_init.c \ pthread_barrierattr_destroy.c \ pthread_barrierattr_setpshared.c \ pthread_barrierattr_getpshared.c CANCEL_SRCS = \ pthread_setcancelstate.c \ pthread_setcanceltype.c \ pthread_testcancel.c \ pthread_cancel.c CONDVAR_SRCS = \ ptw32_cond_check_need_init.c \ pthread_condattr_destroy.c \ pthread_condattr_getpshared.c \ pthread_condattr_init.c \ pthread_condattr_setpshared.c \ pthread_cond_destroy.c \ pthread_cond_init.c \ pthread_cond_signal.c \ pthread_cond_wait.c EXIT_SRCS = \ pthread_exit.c MISC_SRCS = \ pthread_equal.c \ pthread_getconcurrency.c \ pthread_kill.c \ pthread_once.c \ pthread_self.c \ pthread_setconcurrency.c \ ptw32_calloc.c \ ptw32_MCS_lock.c \ ptw32_new.c \ ptw32_reuse.c \ ptw32_relmillisecs.c \ w32_CancelableWait.c MUTEX_SRCS = \ ptw32_mutex_check_need_init.c \ pthread_mutex_init.c \ pthread_mutex_destroy.c \ pthread_mutexattr_init.c \ pthread_mutexattr_destroy.c \ pthread_mutexattr_getpshared.c \ pthread_mutexattr_setpshared.c \ pthread_mutexattr_settype.c \ pthread_mutexattr_gettype.c \ pthread_mutex_lock.c \ pthread_mutex_timedlock.c \ pthread_mutex_unlock.c \ pthread_mutex_trylock.c NONPORTABLE_SRCS = \ pthread_mutexattr_setkind_np.c \ pthread_mutexattr_getkind_np.c \ pthread_getw32threadhandle_np.c \ pthread_delay_np.c \ pthread_num_processors_np.c \ pthread_win32_attach_detach_np.c \ pthread_timechange_handler_np.c PRIVATE_SRCS = \ ptw32_is_attr.c \ ptw32_processInitialize.c \ ptw32_processTerminate.c \ ptw32_threadStart.c \ ptw32_threadDestroy.c \ ptw32_tkAssocCreate.c \ ptw32_tkAssocDestroy.c \ ptw32_callUserDestroyRoutines.c \ ptw32_semwait.c \ ptw32_timespec.c \ ptw32_throw.c \ ptw32_InterlockedCompareExchange.c \ ptw32_getprocessors.c RWLOCK_SRCS = \ ptw32_rwlock_check_need_init.c \ ptw32_rwlock_cancelwrwait.c \ pthread_rwlock_init.c \ pthread_rwlock_destroy.c \ pthread_rwlockattr_init.c \ pthread_rwlockattr_destroy.c \ pthread_rwlockattr_getpshared.c \ pthread_rwlockattr_setpshared.c \ pthread_rwlock_rdlock.c \ pthread_rwlock_timedrdlock.c \ pthread_rwlock_wrlock.c \ pthread_rwlock_timedwrlock.c \ pthread_rwlock_unlock.c \ pthread_rwlock_tryrdlock.c \ pthread_rwlock_trywrlock.c SCHED_SRCS = \ pthread_attr_setschedpolicy.c \ pthread_attr_getschedpolicy.c \ pthread_attr_setschedparam.c \ pthread_attr_getschedparam.c \ pthread_attr_setinheritsched.c \ pthread_attr_getinheritsched.c \ pthread_setschedparam.c \ pthread_getschedparam.c \ sched_get_priority_max.c \ sched_get_priority_min.c \ sched_setscheduler.c \ sched_getscheduler.c \ sched_yield.c SEMAPHORE_SRCS = \ sem_init.c \ sem_destroy.c \ sem_trywait.c \ sem_timedwait.c \ sem_wait.c \ sem_post.c \ sem_post_multiple.c \ sem_getvalue.c \ sem_open.c \ sem_close.c \ sem_unlink.c SPIN_SRCS = \ ptw32_spinlock_check_need_init.c \ pthread_spin_init.c \ pthread_spin_destroy.c \ pthread_spin_lock.c \ pthread_spin_unlock.c \ pthread_spin_trylock.c SYNC_SRCS = \ pthread_detach.c \ pthread_join.c TSD_SRCS = \ pthread_key_create.c \ pthread_key_delete.c \ pthread_setspecific.c \ pthread_getspecific.c help: @ echo Run one of the following command lines: @ echo nmake clean VCE (to build the MSVC dll with C++ exception handling) @ echo nmake clean VSE (to build the MSVC dll with structured exception handling) @ echo nmake clean VC (to build the MSVC dll with C cleanup code) @ echo nmake clean VCE-inlined (to build the MSVC inlined dll with C++ exception handling) @ echo nmake clean VSE-inlined (to build the MSVC inlined dll with structured exception handling) @ echo nmake clean VC-inlined (to build the MSVC inlined dll with C cleanup code) @ echo nmake clean VC-static (to build the MSVC static lib with C cleanup code) @ echo nmake clean VCE-debug (to build the debug MSVC dll with C++ exception handling) @ echo nmake clean VSE-debug (to build the debug MSVC dll with structured exception handling) @ echo nmake clean VC-debug (to build the debug MSVC dll with C cleanup code) @ echo nmake clean VCE-inlined-debug (to build the debug MSVC inlined dll with C++ exception handling) @ echo nmake clean VSE-inlined-debug (to build the debug MSVC inlined dll with structured exception handling) @ echo nmake clean VC-inlined-debug (to build the debug MSVC inlined dll with C cleanup code) @ echo nmake clean VC-static-debug (to build the debug MSVC static lib with C cleanup code) all: @ nmake clean VCE-inlined @ nmake clean VSE-inlined @ nmake clean VC-inlined @ nmake clean VCE-inlined-debug @ nmake clean VSE-inlined-debug @ nmake clean VC-inlined-debug VCE: @ nmake /nologo EHFLAGS="$(OPTIM) $(VCEFLAGS)" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VER).dll VCE-debug: @ nmake /nologo EHFLAGS="$(OPTIMD) $(VCEFLAGSD)" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VERD).dll VSE: @ nmake /nologo EHFLAGS="$(OPTIM) $(VSEFLAGS)" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VER).dll VSE-debug: @ nmake /nologo EHFLAGS="$(OPTIMD) $(VSEFLAGSD)" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VERD).dll VC: @ nmake /nologo EHFLAGS="$(OPTIM) $(VCFLAGS)" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VER).dll VC-debug: @ nmake /nologo EHFLAGS="$(OPTIMD) $(VCFLAGSD)" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VERD).dll # # The so-called inlined DLL is just a single translation unit with # inlining optimisation turned on. # VCE-inlined: @ nmake /nologo EHFLAGS="$(OPTIM) $(VCEFLAGS) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VER).stamp VCE-inlined-debug: @ nmake /nologo EHFLAGS="$(OPTIMD) $(VCEFLAGSD) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VERD).stamp VSE-inlined: @ nmake /nologo EHFLAGS="$(OPTIM) $(VSEFLAGS) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VER).stamp VSE-inlined-debug: @ nmake /nologo EHFLAGS="$(OPTIMD) $(VSEFLAGSD) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VERD).stamp VC-inlined: @ nmake /nologo EHFLAGS="$(OPTIM) $(VCFLAGS) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VER).stamp VC-inlined-debug: nmake /nologo EHFLAGS="$(OPTIMD) $(VCFLAGSD) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VERD).stamp VC-static: @ nmake /nologo EHFLAGS="$(OPTIM) $(VCFLAGS) /DPTW32_BUILD_INLINED /DPTW32_STATIC_LIB" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VER).static VC-static-debug: @ nmake /nologo EHFLAGS="$(OPTIMD) $(VCFLAGSD) /DPTW32_BUILD_INLINED /DPTW32_STATIC_LIB" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VERD).static realclean: clean if exist pthread*.dll del pthread*.dll if exist pthread*.lib del pthread*.lib if exist *.stamp del *.stamp clean: if exist *.obj del *.obj if exist *.ilk del *.ilk if exist *.pdb del *.pdb if exist *.exp del *.exp if exist *.map del *.map if exist *.o del *.o if exist *.i del *.i if exist *.res del *.res install: $(DLLS) copy pthread*.dll $(DLLDEST) copy pthread*.lib $(LIBDEST) copy pthread.h $(HDRDEST) copy sched.h $(HDRDEST) copy semaphore.h $(HDRDEST) $(DLLS): $(DLL_OBJS) cl /LDd /Zi /nologo $(DLL_OBJS) \ /link /nodefaultlib:libcmt /implib:$*.lib \ msvcrt.lib wsock32.lib /out:$@ $(INLINED_STAMPS): $(DLL_INLINED_OBJS) cl /LDd /Zi /nologo $(DLL_INLINED_OBJS) \ /link /nodefaultlib:libcmt /implib:$*.lib \ msvcrt.lib wsock32.lib /out:$*.dll $(STATIC_STAMPS): $(DLL_INLINED_OBJS) if exist $*.lib del $*.lib lib $(DLL_INLINED_OBJS) /out:$*.lib .c.obj: cl $(EHFLAGS) /D$(CLEANUP) -c $< .rc.res: rc /dPTW32_RC_MSC /d$(CLEANUP) $< .c.i: cl /P /O2 /Ob1 $(VCFLAGS) $< attr.obj: attr.c $(ATTR_SRCS) $(INCL) barrier.obj: barrier.c $(BARRIER_SRCS) $(INCL) cancel.obj: cancel.c $(CANCEL_SRCS) $(INCL) condvar.obj: condvar.c $(CONDVAR_SRCS) $(INCL) exit.obj: exit.c $(EXIT_SRCS) $(INCL) misc.obj: misc.c $(MISC_SRCS) $(INCL) mutex.obj: mutex.c $(MUTEX_SRCS) $(INCL) nonportable.obj: nonportable.c $(NONPORTABLE_SRCS) $(INCL) private.obj: private.c $(PRIVATE_SRCS) $(INCL) rwlock.obj: rwlock.c $(RWLOCK_SRCS) $(INCL) sched.obj: sched.c $(SCHED_SRCS) $(INCL) semaphore.obj: semaphore.c $(SEMAPHORE_SRCS) $(INCL) spin.obj: spin.c $(SPIN_SRCS) $(INCL) sync.obj: sync.c $(SYNC_SRCS) $(INCL) tsd.obj: tsd.c $(TSD_SRCS) $(INCL) version.res: version.rc $(INCL) nyquist-3.05/liblo/pthreads.2/README.Borland0000644000175000000620000000504311512143043017472 0ustar stevestaffIn ptw32_InterlockedCompareExchange.c, I've added a section for Borland's compiler; it's identical to that for the MS compiler except that it uses /* ... */ comments instead of ; comments. [RPJ: need to define HAVE_TASM32 in config.h to use the above.] The other file is a makefile suitable for use with Borland's compiler (run "make -fBmakefile" in the directory). It builds a single version of the library, pthreadBC.dll and the corresponding pthreadBC.lib import library, which is comparable to the pthreadVC version; I can't personally see any demand for the versions that include structured or C++ exception cancellation handling so I haven't attempted to build those versions of the library. (I imagine a static version might be of use to some, but we can't legally use that on my commercial projects so I can't try that out, unfortunately.) [RPJ: Added tests\Bmakefile as well.] Borland C++ doesn't define the ENOSYS constant used by pthreads-win32; rather than make more extensive patches to the pthreads-win32 source I have a mostly-arbitrary constant for it in the makefile. However this doesn't make it visible to the application using the library, so if anyone actually wants to use this constant in their apps (why?) someone might like to make a seperate NEED_BCC_something define to add this stuff. The makefile also #defines EDEADLK as EDEADLOCK, _timeb as timeb, and _ftime as ftime, to deal with the minor differences between the two RTLs' naming conventions, and sets the compiler flags as required to get a normal compile of the library. [RPJ: Moved errno values and _timeb etc to pthread.h, so apps will also use them.] (While I'm on the subject, the reason Borland users should recompile the library, rather than using the impdef/implib technique suggested previously on the mailing list, is that a) the errno constants are different, so the results returned by the pthread_* functions can be meaningless, and b) the errno variable/pseudo-variable itself is different in the MS & BCC runtimes, so you can't access the pthreadVC's errno from a Borland C++-compiled host application correctly - I imagine there are other potential problems from the RTL mismatch too.) [RPJ: Make sure you use the same RTL in both dll and application builds. The dll and tests Bmakefiles use cw32mti.lib. Having some trouble with memory read exceptions running the test suite using BCC55.] Best regards, Will -- Will Bryant Systems Architect, eCOSM Limited Cell +64 21 655 443, office +64 3 365 4176 http://www.ecosm.com/ nyquist-3.05/liblo/pthreads.2/pthread.vcproj0000644000175000000620000001322011512143043020102 0ustar stevestaff nyquist-3.05/liblo/pthreads.2/pthread_getw32threadhandle_np.c0000644000175000000620000000366111512143043023265 0ustar stevestaff/* * pthread_getw32threadhandle_np.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * pthread_getw32threadhandle_np() * * Returns the win32 thread handle that the POSIX * thread "thread" is running as. * * Applications can use the win32 handle to set * win32 specific attributes of the thread. */ HANDLE pthread_getw32threadhandle_np (pthread_t thread) { return ((ptw32_thread_t *)thread.p)->threadH; } nyquist-3.05/liblo/pthreads.2/pthread_barrierattr_destroy.c0000644000175000000620000000525411512143043023203 0ustar stevestaff/* * pthread_barrier_attr_destroy.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrierattr_destroy (pthread_barrierattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Destroys a barrier attributes object. The object can * no longer be used. * * PARAMETERS * attr * pointer to an instance of pthread_barrierattr_t * * * DESCRIPTION * Destroys a barrier attributes object. The object can * no longer be used. * * NOTES: * 1) Does not affect barrieres created using 'attr' * * RESULTS * 0 successfully released attr, * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ { int result = 0; if (attr == NULL || *attr == NULL) { result = EINVAL; } else { pthread_barrierattr_t ba = *attr; *attr = NULL; free (ba); } return (result); } /* pthread_barrierattr_destroy */ nyquist-3.05/liblo/pthreads.2/pthread_cond_wait.c0000644000175000000620000004176411512143043021066 0ustar stevestaff/* * pthread_cond_wait.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * ------------------------------------------------------------- * Algorithm: * The algorithm used in this implementation is that developed by * Alexander Terekhov in colaboration with Louis Thomas. The bulk * of the discussion is recorded in the file README.CV, which contains * several generations of both colaborators original algorithms. The final * algorithm used here is the one referred to as * * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL * * presented below in pseudo-code as it appeared: * * * given: * semBlockLock - bin.semaphore * semBlockQueue - semaphore * mtxExternal - mutex or CS * mtxUnblockLock - mutex or CS * nWaitersGone - int * nWaitersBlocked - int * nWaitersToUnblock - int * * wait( timeout ) { * * [auto: register int result ] // error checking omitted * [auto: register int nSignalsWasLeft ] * [auto: register int nWaitersWasGone ] * * sem_wait( semBlockLock ); * nWaitersBlocked++; * sem_post( semBlockLock ); * * unlock( mtxExternal ); * bTimedOut = sem_wait( semBlockQueue,timeout ); * * lock( mtxUnblockLock ); * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { * if ( bTimeout ) { // timeout (or canceled) * if ( 0 != nWaitersBlocked ) { * nWaitersBlocked--; * } * else { * nWaitersGone++; // count spurious wakeups. * } * } * if ( 0 == --nWaitersToUnblock ) { * if ( 0 != nWaitersBlocked ) { * sem_post( semBlockLock ); // open the gate. * nSignalsWasLeft = 0; // do not open the gate * // below again. * } * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { * nWaitersGone = 0; * } * } * } * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or * // spurious semaphore :-) * sem_wait( semBlockLock ); * nWaitersBlocked -= nWaitersGone; // something is going on here * // - test of timeouts? :-) * sem_post( semBlockLock ); * nWaitersGone = 0; * } * unlock( mtxUnblockLock ); * * if ( 1 == nSignalsWasLeft ) { * if ( 0 != nWaitersWasGone ) { * // sem_adjust( semBlockQueue,-nWaitersWasGone ); * while ( nWaitersWasGone-- ) { * sem_wait( semBlockQueue ); // better now than spurious later * } * } sem_post( semBlockLock ); // open the gate * } * * lock( mtxExternal ); * * return ( bTimedOut ) ? ETIMEOUT : 0; * } * * signal(bAll) { * * [auto: register int result ] * [auto: register int nSignalsToIssue] * * lock( mtxUnblockLock ); * * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! * if ( 0 == nWaitersBlocked ) { // NO-OP * return unlock( mtxUnblockLock ); * } * if (bAll) { * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; * nWaitersBlocked = 0; * } * else { * nSignalsToIssue = 1; * nWaitersToUnblock++; * nWaitersBlocked--; * } * } * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! * sem_wait( semBlockLock ); // close the gate * if ( 0 != nWaitersGone ) { * nWaitersBlocked -= nWaitersGone; * nWaitersGone = 0; * } * if (bAll) { * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; * nWaitersBlocked = 0; * } * else { * nSignalsToIssue = nWaitersToUnblock = 1; * nWaitersBlocked--; * } * } * else { // NO-OP * return unlock( mtxUnblockLock ); * } * * unlock( mtxUnblockLock ); * sem_post( semBlockQueue,nSignalsToIssue ); * return result; * } * ------------------------------------------------------------- * * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL * * presented below in pseudo-code; basically 8a... * ...BUT W/O "spurious wakes" prevention: * * * given: * semBlockLock - bin.semaphore * semBlockQueue - semaphore * mtxExternal - mutex or CS * mtxUnblockLock - mutex or CS * nWaitersGone - int * nWaitersBlocked - int * nWaitersToUnblock - int * * wait( timeout ) { * * [auto: register int result ] // error checking omitted * [auto: register int nSignalsWasLeft ] * * sem_wait( semBlockLock ); * ++nWaitersBlocked; * sem_post( semBlockLock ); * * unlock( mtxExternal ); * bTimedOut = sem_wait( semBlockQueue,timeout ); * * lock( mtxUnblockLock ); * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { * --nWaitersToUnblock; * } * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or * // spurious semaphore :-) * sem_wait( semBlockLock ); * nWaitersBlocked -= nWaitersGone; // something is going on here * // - test of timeouts? :-) * sem_post( semBlockLock ); * nWaitersGone = 0; * } * unlock( mtxUnblockLock ); * * if ( 1 == nSignalsWasLeft ) { * sem_post( semBlockLock ); // open the gate * } * * lock( mtxExternal ); * * return ( bTimedOut ) ? ETIMEOUT : 0; * } * * signal(bAll) { * * [auto: register int result ] * [auto: register int nSignalsToIssue] * * lock( mtxUnblockLock ); * * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! * if ( 0 == nWaitersBlocked ) { // NO-OP * return unlock( mtxUnblockLock ); * } * if (bAll) { * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; * nWaitersBlocked = 0; * } * else { * nSignalsToIssue = 1; * ++nWaitersToUnblock; * --nWaitersBlocked; * } * } * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! * sem_wait( semBlockLock ); // close the gate * if ( 0 != nWaitersGone ) { * nWaitersBlocked -= nWaitersGone; * nWaitersGone = 0; * } * if (bAll) { * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; * nWaitersBlocked = 0; * } * else { * nSignalsToIssue = nWaitersToUnblock = 1; * --nWaitersBlocked; * } * } * else { // NO-OP * return unlock( mtxUnblockLock ); * } * * unlock( mtxUnblockLock ); * sem_post( semBlockQueue,nSignalsToIssue ); * return result; * } * ------------------------------------------------------------- * */ #include "pthread.h" #include "implement.h" /* * Arguments for cond_wait_cleanup, since we can only pass a * single void * to it. */ typedef struct { pthread_mutex_t *mutexPtr; pthread_cond_t cv; int *resultPtr; } ptw32_cond_wait_cleanup_args_t; static void PTW32_CDECL ptw32_cond_wait_cleanup (void *args) { ptw32_cond_wait_cleanup_args_t *cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args; pthread_cond_t cv = cleanup_args->cv; int *resultPtr = cleanup_args->resultPtr; int nSignalsWasLeft; int result; /* * Whether we got here as a result of signal/broadcast or because of * timeout on wait or thread cancellation we indicate that we are no * longer waiting. The waiter is responsible for adjusting waiters * (to)unblock(ed) counts (protected by unblock lock). */ if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) { *resultPtr = result; return; } if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock)) { --(cv->nWaitersToUnblock); } else if (INT_MAX / 2 == ++(cv->nWaitersGone)) { /* Use the non-cancellable version of sem_wait() */ if (ptw32_semwait (&(cv->semBlockLock)) != 0) { *resultPtr = errno; /* * This is a fatal error for this CV, * so we deliberately don't unlock * cv->mtxUnblockLock before returning. */ return; } cv->nWaitersBlocked -= cv->nWaitersGone; if (sem_post (&(cv->semBlockLock)) != 0) { *resultPtr = errno; /* * This is a fatal error for this CV, * so we deliberately don't unlock * cv->mtxUnblockLock before returning. */ return; } cv->nWaitersGone = 0; } if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0) { *resultPtr = result; return; } if (1 == nSignalsWasLeft) { if (sem_post (&(cv->semBlockLock)) != 0) { *resultPtr = errno; return; } } /* * XSH: Upon successful return, the mutex has been locked and is owned * by the calling thread. */ if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0) { *resultPtr = result; } } /* ptw32_cond_wait_cleanup */ static INLINE int ptw32_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec *abstime) { int result = 0; pthread_cond_t cv; ptw32_cond_wait_cleanup_args_t cleanup_args; if (cond == NULL || *cond == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static condition variable. We check * again inside the guarded section of ptw32_cond_check_need_init() * to avoid race conditions. */ if (*cond == PTHREAD_COND_INITIALIZER) { result = ptw32_cond_check_need_init (cond); } if (result != 0 && result != EBUSY) { return result; } cv = *cond; /* Thread can be cancelled in sem_wait() but this is OK */ if (sem_wait (&(cv->semBlockLock)) != 0) { return errno; } ++(cv->nWaitersBlocked); if (sem_post (&(cv->semBlockLock)) != 0) { return errno; } /* * Setup this waiter cleanup handler */ cleanup_args.mutexPtr = mutex; cleanup_args.cv = cv; cleanup_args.resultPtr = &result; #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args); /* * Now we can release 'mutex' and... */ if ((result = pthread_mutex_unlock (mutex)) == 0) { /* * ...wait to be awakened by * pthread_cond_signal, or * pthread_cond_broadcast, or * timeout, or * thread cancellation * * Note: * * sem_timedwait is a cancellation point, * hence providing the mechanism for making * pthread_cond_wait a cancellation point. * We use the cleanup mechanism to ensure we * re-lock the mutex and adjust (to)unblock(ed) waiters * counts if we are cancelled, timed out or signalled. */ if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0) { result = errno; } } /* * Always cleanup */ pthread_cleanup_pop (1); #ifdef _MSC_VER #pragma inline_depth() #endif /* * "result" can be modified by the cleanup handler. */ return result; } /* ptw32_cond_timedwait */ int pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a condition variable until * awakened by a signal or broadcast. * * Caller MUST be holding the mutex lock; the * lock is released and the caller is blocked waiting * on 'cond'. When 'cond' is signaled, the mutex * is re-acquired before returning to the caller. * * PARAMETERS * cond * pointer to an instance of pthread_cond_t * * mutex * pointer to an instance of pthread_mutex_t * * * DESCRIPTION * This function waits on a condition variable until * awakened by a signal or broadcast. * * NOTES: * * 1) The function must be called with 'mutex' LOCKED * by the calling thread, or undefined behaviour * will result. * * 2) This routine atomically releases 'mutex' and causes * the calling thread to block on the condition variable. * The blocked thread may be awakened by * pthread_cond_signal or * pthread_cond_broadcast. * * Upon successful completion, the 'mutex' has been locked and * is owned by the calling thread. * * * RESULTS * 0 caught condition; mutex released, * EINVAL 'cond' or 'mutex' is invalid, * EINVAL different mutexes for concurrent waits, * EINVAL mutex is not held by the calling thread, * * ------------------------------------------------------ */ { /* * The NULL abstime arg means INFINITE waiting. */ return (ptw32_cond_timedwait (cond, mutex, NULL)); } /* pthread_cond_wait */ int pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec *abstime) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a condition variable either until * awakened by a signal or broadcast; or until the time * specified by abstime passes. * * PARAMETERS * cond * pointer to an instance of pthread_cond_t * * mutex * pointer to an instance of pthread_mutex_t * * abstime * pointer to an instance of (const struct timespec) * * * DESCRIPTION * This function waits on a condition variable either until * awakened by a signal or broadcast; or until the time * specified by abstime passes. * * NOTES: * 1) The function must be called with 'mutex' LOCKED * by the calling thread, or undefined behaviour * will result. * * 2) This routine atomically releases 'mutex' and causes * the calling thread to block on the condition variable. * The blocked thread may be awakened by * pthread_cond_signal or * pthread_cond_broadcast. * * * RESULTS * 0 caught condition; mutex released, * EINVAL 'cond', 'mutex', or abstime is invalid, * EINVAL different mutexes for concurrent waits, * EINVAL mutex is not held by the calling thread, * ETIMEDOUT abstime ellapsed before cond was signaled. * * ------------------------------------------------------ */ { if (abstime == NULL) { return EINVAL; } return (ptw32_cond_timedwait (cond, mutex, abstime)); } /* pthread_cond_timedwait */ nyquist-3.05/liblo/pthreads.2/COPYING.LIB0000644000175000000620000006446611512143043016710 0ustar stevestaff GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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 Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] 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 Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these 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 other code 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. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. 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, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) 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. d) 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. e) 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 materials to be 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 with 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 Lesser 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.1 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! nyquist-3.05/liblo/pthreads.2/pthread_attr_init.c0000644000175000000620000000710711512143043021105 0ustar stevestaff/* * pthread_attr_init.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_attr_init (pthread_attr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Initializes a thread attributes object with default * attributes. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * * DESCRIPTION * Initializes a thread attributes object with default * attributes. * * NOTES: * 1) Used to define thread attributes * * RESULTS * 0 successfully initialized attr, * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ { pthread_attr_t attr_result; if (attr == NULL) { /* This is disallowed. */ return EINVAL; } attr_result = (pthread_attr_t) malloc (sizeof (*attr_result)); if (attr_result == NULL) { return ENOMEM; } #ifdef _POSIX_THREAD_ATTR_STACKSIZE /* * Default to zero size. Unless changed explicitly this * will allow Win32 to set the size to that of the * main thread. */ attr_result->stacksize = 0; #endif #ifdef _POSIX_THREAD_ATTR_STACKADDR /* FIXME: Set this to something sensible when we support it. */ attr_result->stackaddr = NULL; #endif attr_result->detachstate = PTHREAD_CREATE_JOINABLE; #if HAVE_SIGSET_T memset (&(attr_result->sigmask), 0, sizeof (sigset_t)); #endif /* HAVE_SIGSET_T */ /* * Win32 sets new threads to THREAD_PRIORITY_NORMAL and * not to that of the parent thread. We choose to default to * this arrangement. */ attr_result->param.sched_priority = THREAD_PRIORITY_NORMAL; attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED; attr_result->contentionscope = PTHREAD_SCOPE_SYSTEM; attr_result->valid = PTW32_ATTR_VALID; *attr = attr_result; return 0; } nyquist-3.05/liblo/pthreads.2/GNUmakefile0000644000175000000620000004175011512143043017311 0ustar stevestaff# # -------------------------------------------------------------------------- # # Pthreads-win32 - POSIX Threads Library for Win32 # Copyright(C) 1998 John E. Bossom # Copyright(C) 1999,2005 Pthreads-win32 contributors # # Contact Email: rpj@callisto.canberra.edu.au # # The current list of contributors is contained # in the file CONTRIBUTORS included with the source # code distribution. The list can also be seen at the # following World Wide Web location: # http://sources.redhat.com/pthreads-win32/contributors.html # # 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 in the file COPYING.LIB; # if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # DLL_VER = 2 DLL_VERD= $(DLL_VER)d DEVROOT = C:\PTHREADS DLLDEST = $(DEVROOT)\DLL LIBDEST = $(DEVROOT)\DLL # If Running MsysDTK RM = rm -f MV = mv -f CP = cp -f # If not. #RM = erase #MV = rename #CP = copy # For cross compiling use e.g. # make CROSS=i386-mingw32msvc- clean GC-inlined CROSS = AR = $(CROSS)ar DLLTOOL = $(CROSS)dlltool CC = $(CROSS)gcc CXX = $(CROSS)g++ RANLIB = $(CROSS)ranlib RC = $(CROSS)windres OPT = $(CLEANUP) -O3 -finline-functions DOPT = $(CLEANUP) -g -O0 XOPT = RCFLAGS = --include-dir=. LFLAGS = -lwsock32 # ---------------------------------------------------------------------- # The library can be built with some alternative behaviour to # facilitate development of applications on Win32 that will be ported # to other POSIX systems. Nothing definable here will make the library # non-compliant, but applications that make assumptions that POSIX # does not garrantee may fail or misbehave under some settings. # # PTW32_THREAD_ID_REUSE_INCREMENT # Purpose: # POSIX says that applications should assume that thread IDs can be # recycled. However, Solaris and some other systems use a [very large] # sequence number as the thread ID, which provides virtual uniqueness. # Pthreads-win32 provides pseudo-unique IDs when the default increment # (1) is used, but pthread_t is not a scalar type like Solaris's. # # Usage: # Set to any value in the range: 0 <= value <= 2^wordsize # # Examples: # Set to 0 to emulate non recycle-unique behaviour like Linux or *BSD. # Set to 1 for recycle-unique thread IDs (this is the default). # Set to some other +ve value to emulate smaller word size types # (i.e. will wrap sooner). # #PTW32_FLAGS = "-DPTW32_THREAD_ID_REUSE_INCREMENT=0" # # ---------------------------------------------------------------------- GC_CFLAGS = $(PTW32_FLAGS) GCE_CFLAGS = $(PTW32_FLAGS) -mthreads ## Mingw32 MAKE ?= make CFLAGS = $(OPT) $(XOPT) -I. -DHAVE_CONFIG_H -Wall DLL_INLINED_OBJS = \ pthread.o \ version.o # Agregate modules for inlinability DLL_OBJS = \ attr.o \ barrier.o \ cancel.o \ cleanup.o \ condvar.o \ create.o \ dll.o \ errno.o \ exit.o \ fork.o \ global.o \ misc.o \ mutex.o \ nonportable.o \ private.o \ rwlock.o \ sched.o \ semaphore.o \ signal.o \ spin.o \ sync.o \ tsd.o \ version.o # Separate modules for minimum size statically linked images SMALL_STATIC_OBJS = \ pthread_attr_init.o \ pthread_attr_destroy.o \ pthread_attr_getdetachstate.o \ pthread_attr_setdetachstate.o \ pthread_attr_getstackaddr.o \ pthread_attr_setstackaddr.o \ pthread_attr_getstacksize.o \ pthread_attr_setstacksize.o \ pthread_attr_getscope.o \ pthread_attr_setscope.o \ pthread_attr_setschedpolicy.o \ pthread_attr_getschedpolicy.o \ pthread_attr_setschedparam.o \ pthread_attr_getschedparam.o \ pthread_attr_setinheritsched.o \ pthread_attr_getinheritsched.o \ pthread_barrier_init.o \ pthread_barrier_destroy.o \ pthread_barrier_wait.o \ pthread_barrierattr_init.o \ pthread_barrierattr_destroy.o \ pthread_barrierattr_setpshared.o \ pthread_barrierattr_getpshared.o \ pthread_setcancelstate.o \ pthread_setcanceltype.o \ pthread_testcancel.o \ pthread_cancel.o \ cleanup.o \ pthread_condattr_destroy.o \ pthread_condattr_getpshared.o \ pthread_condattr_init.o \ pthread_condattr_setpshared.o \ pthread_cond_destroy.o \ pthread_cond_init.o \ pthread_cond_signal.o \ pthread_cond_wait.o \ create.o \ dll.o \ errno.o \ pthread_exit.o \ fork.o \ global.o \ pthread_mutex_init.o \ pthread_mutex_destroy.o \ pthread_mutexattr_init.o \ pthread_mutexattr_destroy.o \ pthread_mutexattr_getpshared.o \ pthread_mutexattr_setpshared.o \ pthread_mutexattr_settype.o \ pthread_mutexattr_gettype.o \ pthread_mutex_lock.o \ pthread_mutex_timedlock.o \ pthread_mutex_unlock.o \ pthread_mutex_trylock.o \ pthread_mutexattr_setkind_np.o \ pthread_mutexattr_getkind_np.o \ pthread_getw32threadhandle_np.o \ pthread_delay_np.o \ pthread_num_processors_np.o \ pthread_win32_attach_detach_np.o \ pthread_equal.o \ pthread_getconcurrency.o \ pthread_once.o \ pthread_self.o \ pthread_setconcurrency.o \ pthread_rwlock_init.o \ pthread_rwlock_destroy.o \ pthread_rwlockattr_init.o \ pthread_rwlockattr_destroy.o \ pthread_rwlockattr_getpshared.o \ pthread_rwlockattr_setpshared.o \ pthread_rwlock_rdlock.o \ pthread_rwlock_wrlock.o \ pthread_rwlock_unlock.o \ pthread_rwlock_tryrdlock.o \ pthread_rwlock_trywrlock.o \ pthread_setschedparam.o \ pthread_getschedparam.o \ pthread_timechange_handler_np.o \ ptw32_is_attr.o \ ptw32_cond_check_need_init.o \ ptw32_MCS_lock.o \ ptw32_mutex_check_need_init.o \ ptw32_processInitialize.o \ ptw32_processTerminate.o \ ptw32_threadStart.o \ ptw32_threadDestroy.o \ ptw32_tkAssocCreate.o \ ptw32_tkAssocDestroy.o \ ptw32_callUserDestroyRoutines.o \ ptw32_timespec.o \ ptw32_throw.o \ ptw32_InterlockedCompareExchange.o \ ptw32_getprocessors.o \ ptw32_calloc.o \ ptw32_new.o \ ptw32_reuse.o \ ptw32_semwait.o \ ptw32_relmillisecs.o \ ptw32_rwlock_check_need_init.o \ sched_get_priority_max.o \ sched_get_priority_min.o \ sched_setscheduler.o \ sched_getscheduler.o \ sched_yield.o \ sem_init.o \ sem_destroy.o \ sem_trywait.o \ sem_timedwait.o \ sem_wait.o \ sem_post.o \ sem_post_multiple.o \ sem_getvalue.o \ sem_open.o \ sem_close.o \ sem_unlink.o \ signal.o \ pthread_kill.o \ ptw32_spinlock_check_need_init.o \ pthread_spin_init.o \ pthread_spin_destroy.o \ pthread_spin_lock.o \ pthread_spin_unlock.o \ pthread_spin_trylock.o \ pthread_detach.o \ pthread_join.o \ pthread_key_create.o \ pthread_key_delete.o \ pthread_setspecific.o \ pthread_getspecific.o \ w32_CancelableWait.o \ version.o INCL = \ config.h \ implement.h \ semaphore.h \ pthread.h \ need_errno.h ATTR_SRCS = \ pthread_attr_init.c \ pthread_attr_destroy.c \ pthread_attr_getdetachstate.c \ pthread_attr_setdetachstate.c \ pthread_attr_getstackaddr.c \ pthread_attr_setstackaddr.c \ pthread_attr_getstacksize.c \ pthread_attr_setstacksize.c \ pthread_attr_getscope.c \ pthread_attr_setscope.c BARRIER_SRCS = \ pthread_barrier_init.c \ pthread_barrier_destroy.c \ pthread_barrier_wait.c \ pthread_barrierattr_init.c \ pthread_barrierattr_destroy.c \ pthread_barrierattr_setpshared.c \ pthread_barrierattr_getpshared.c CANCEL_SRCS = \ pthread_setcancelstate.c \ pthread_setcanceltype.c \ pthread_testcancel.c \ pthread_cancel.c CONDVAR_SRCS = \ ptw32_cond_check_need_init.c \ pthread_condattr_destroy.c \ pthread_condattr_getpshared.c \ pthread_condattr_init.c \ pthread_condattr_setpshared.c \ pthread_cond_destroy.c \ pthread_cond_init.c \ pthread_cond_signal.c \ pthread_cond_wait.c EXIT_SRCS = \ pthread_exit.c MISC_SRCS = \ pthread_equal.c \ pthread_getconcurrency.c \ pthread_kill.c \ pthread_once.c \ pthread_self.c \ pthread_setconcurrency.c \ ptw32_calloc.c \ ptw32_MCS_lock.c \ ptw32_new.c \ ptw32_reuse.c \ w32_CancelableWait.c MUTEX_SRCS = \ ptw32_mutex_check_need_init.c \ pthread_mutex_init.c \ pthread_mutex_destroy.c \ pthread_mutexattr_init.c \ pthread_mutexattr_destroy.c \ pthread_mutexattr_getpshared.c \ pthread_mutexattr_setpshared.c \ pthread_mutexattr_settype.c \ pthread_mutexattr_gettype.c \ pthread_mutex_lock.c \ pthread_mutex_timedlock.c \ pthread_mutex_unlock.c \ pthread_mutex_trylock.c NONPORTABLE_SRCS = \ pthread_mutexattr_setkind_np.c \ pthread_mutexattr_getkind_np.c \ pthread_getw32threadhandle_np.c \ pthread_delay_np.c \ pthread_num_processors_np.c \ pthread_win32_attach_detach_np.c \ pthread_timechange_handler_np.c PRIVATE_SRCS = \ ptw32_is_attr.c \ ptw32_processInitialize.c \ ptw32_processTerminate.c \ ptw32_threadStart.c \ ptw32_threadDestroy.c \ ptw32_tkAssocCreate.c \ ptw32_tkAssocDestroy.c \ ptw32_callUserDestroyRoutines.c \ ptw32_semwait.c \ ptw32_relmillisecs.c \ ptw32_timespec.c \ ptw32_throw.c \ ptw32_InterlockedCompareExchange.c \ ptw32_getprocessors.c RWLOCK_SRCS = \ ptw32_rwlock_check_need_init.c \ ptw32_rwlock_cancelwrwait.c \ pthread_rwlock_init.c \ pthread_rwlock_destroy.c \ pthread_rwlockattr_init.c \ pthread_rwlockattr_destroy.c \ pthread_rwlockattr_getpshared.c \ pthread_rwlockattr_setpshared.c \ pthread_rwlock_rdlock.c \ pthread_rwlock_timedrdlock.c \ pthread_rwlock_wrlock.c \ pthread_rwlock_timedwrlock.c \ pthread_rwlock_unlock.c \ pthread_rwlock_tryrdlock.c \ pthread_rwlock_trywrlock.c SCHED_SRCS = \ pthread_attr_setschedpolicy.c \ pthread_attr_getschedpolicy.c \ pthread_attr_setschedparam.c \ pthread_attr_getschedparam.c \ pthread_attr_setinheritsched.c \ pthread_attr_getinheritsched.c \ pthread_setschedparam.c \ pthread_getschedparam.c \ sched_get_priority_max.c \ sched_get_priority_min.c \ sched_setscheduler.c \ sched_getscheduler.c \ sched_yield.c SEMAPHORE_SRCS = \ sem_init.c \ sem_destroy.c \ sem_trywait.c \ sem_timedwait.c \ sem_wait.c \ sem_post.c \ sem_post_multiple.c \ sem_getvalue.c \ sem_open.c \ sem_close.c \ sem_unlink.c SPIN_SRCS = \ ptw32_spinlock_check_need_init.c \ pthread_spin_init.c \ pthread_spin_destroy.c \ pthread_spin_lock.c \ pthread_spin_unlock.c \ pthread_spin_trylock.c SYNC_SRCS = \ pthread_detach.c \ pthread_join.c TSD_SRCS = \ pthread_key_create.c \ pthread_key_delete.c \ pthread_setspecific.c \ pthread_getspecific.c GCE_DLL = pthreadGCE$(DLL_VER).dll GCED_DLL= pthreadGCE$(DLL_VERD).dll GCE_LIB = libpthreadGCE$(DLL_VER).a GCED_LIB= libpthreadGCE$(DLL_VERD).a GCE_INLINED_STAMP = pthreadGCE$(DLL_VER).stamp GCED_INLINED_STAMP = pthreadGCE$(DLL_VERD).stamp GC_DLL = pthreadGC$(DLL_VER).dll GCD_DLL = pthreadGC$(DLL_VERD).dll GC_LIB = libpthreadGC$(DLL_VER).a GCD_LIB = libpthreadGC$(DLL_VERD).a GC_INLINED_STAMP = pthreadGC$(DLL_VER).stamp GCD_INLINED_STAMP = pthreadGC$(DLL_VERD).stamp GC_STATIC_STAMP = libpthreadGC$(DLL_VER).stamp GCD_STATIC_STAMP = libpthreadGC$(DLL_VERD).stamp PTHREAD_DEF = pthread.def help: @ echo "Run one of the following command lines:" @ echo "make clean GC (to build the GNU C dll with C cleanup code)" @ echo "make clean GCE (to build the GNU C dll with C++ exception handling)" @ echo "make clean GC-inlined (to build the GNU C inlined dll with C cleanup code)" @ echo "make clean GCE-inlined (to build the GNU C inlined dll with C++ exception handling)" @ echo "make clean GC-static (to build the GNU C inlined static lib with C cleanup code)" @ echo "make clean GC-debug (to build the GNU C debug dll with C cleanup code)" @ echo "make clean GCE-debug (to build the GNU C debug dll with C++ exception handling)" @ echo "make clean GC-inlined-debug (to build the GNU C inlined debug dll with C cleanup code)" @ echo "make clean GCE-inlined-debug (to build the GNU C inlined debug dll with C++ exception handling)" @ echo "make clean GC-static-debug (to build the GNU C inlined static debug lib with C cleanup code)" all: @ $(MAKE) clean GCE @ $(MAKE) clean GC GC: $(MAKE) CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_OBJS)" $(GC_DLL) GC-debug: $(MAKE) CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_OBJS)" DLL_VER=$(DLL_VERD) OPT="$(DOPT)" $(GCD_DLL) GCE: $(MAKE) CC=$(CXX) CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_OBJS)" $(GCE_DLL) GCE-debug: $(MAKE) CC=$(CXX) CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_OBJS)" DLL_VER=$(DLL_VERD) OPT="$(DOPT)" $(GCED_DLL) GC-inlined: $(MAKE) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" $(GC_INLINED_STAMP) GC-inlined-debug: $(MAKE) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" DLL_VER=$(DLL_VERD) OPT="$(DOPT)" $(GCD_INLINED_STAMP) GCE-inlined: $(MAKE) CC=$(CXX) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" $(GCE_INLINED_STAMP) GCE-inlined-debug: $(MAKE) CC=$(CXX) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" DLL_VER=$(DLL_VERD) OPT="$(DOPT)" $(GCED_INLINED_STAMP) GC-static: $(MAKE) XOPT="-DPTW32_BUILD_INLINED -DPTW32_STATIC_LIB" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" $(GC_STATIC_STAMP) GC-static-debug: $(MAKE) XOPT="-DPTW32_BUILD_INLINED -DPTW32_STATIC_LIB" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" DLL_VER=$(DLL_VERD) OPT="$(DOPT)" $(GCD_STATIC_STAMP) tests: @ cd tests @ $(MAKE) auto %.pre: %.c $(CC) -E -o $@ $(CFLAGS) $^ %.s: %.c $(CC) -c $(CFLAGS) -DPTW32_BUILD_INLINED -Wa,-ahl $^ > $@ %.o: %.rc $(RC) $(RCFLAGS) $(CLEANUP) -o $@ $< .SUFFIXES: .dll .rc .c .o .c.o:; $(CC) -c -o $@ $(CFLAGS) $(XC_FLAGS) $< $(GC_DLL) $(GCD_DLL): $(DLL_OBJS) $(CC) $(OPT) -shared -o $(GC_DLL) $(DLL_OBJS) $(LFLAGS) $(DLLTOOL) -z pthread.def $(DLL_OBJS) $(DLLTOOL) -k --dllname $@ --output-lib $(GC_LIB) --def $(PTHREAD_DEF) $(GCE_DLL): $(DLL_OBJS) $(CC) $(OPT) -mthreads -shared -o $(GCE_DLL) $(DLL_OBJS) $(LFLAGS) $(DLLTOOL) -z pthread.def $(DLL_OBJS) $(DLLTOOL) -k --dllname $@ --output-lib $(GCE_LIB) --def $(PTHREAD_DEF) $(GC_INLINED_STAMP) $(GCD_INLINED_STAMP): $(DLL_INLINED_OBJS) $(CC) $(OPT) $(XOPT) -shared -o $(GC_DLL) $(DLL_INLINED_OBJS) $(LFLAGS) $(DLLTOOL) -z pthread.def $(DLL_INLINED_OBJS) $(DLLTOOL) -k --dllname $(GC_DLL) --output-lib $(GC_LIB) --def $(PTHREAD_DEF) echo touched > $(GC_INLINED_STAMP) $(GCE_INLINED_STAMP) $(GCED_INLINED_STAMP): $(DLL_INLINED_OBJS) $(CC) $(OPT) $(XOPT) -mthreads -shared -o $(GCE_DLL) $(DLL_INLINED_OBJS) $(LFLAGS) $(DLLTOOL) -z pthread.def $(DLL_INLINED_OBJS) $(DLLTOOL) -k --dllname $(GCE_DLL) --output-lib $(GCE_LIB) --def $(PTHREAD_DEF) echo touched > $(GCE_INLINED_STAMP) $(GC_STATIC_STAMP) $(GCD_STATIC_STAMP): $(DLL_INLINED_OBJS) $(RM) $(GC_LIB) $(AR) -rv $(GC_LIB) $(DLL_INLINED_OBJS) $(RANLIB) $(GC_LIB) echo touched > $(GC_STATIC_STAMP) clean: -$(RM) *~ -$(RM) *.i -$(RM) *.o -$(RM) *.obj -$(RM) *.exe -$(RM) $(PTHREAD_DEF) realclean: clean -$(RM) $(GC_LIB) -$(RM) $(GCE_LIB) -$(RM) $(GC_DLL) -$(RM) $(GCE_DLL) -$(RM) $(GC_INLINED_STAMP) -$(RM) $(GCE_INLINED_STAMP) -$(RM) $(GC_STATIC_STAMP) -$(RM) $(GCD_LIB) -$(RM) $(GCED_LIB) -$(RM) $(GCD_DLL) -$(RM) $(GCED_DLL) -$(RM) $(GCD_INLINED_STAMP) -$(RM) $(GCED_INLINED_STAMP) -$(RM) $(GCD_STATIC_STAMP) attr.o: attr.c $(ATTR_SRCS) $(INCL) barrier.o: barrier.c $(BARRIER_SRCS) $(INCL) cancel.o: cancel.c $(CANCEL_SRCS) $(INCL) condvar.o: condvar.c $(CONDVAR_SRCS) $(INCL) exit.o: exit.c $(EXIT_SRCS) $(INCL) misc.o: misc.c $(MISC_SRCS) $(INCL) mutex.o: mutex.c $(MUTEX_SRCS) $(INCL) nonportable.o: nonportable.c $(NONPORTABLE_SRCS) $(INCL) private.o: private.c $(PRIVATE_SRCS) $(INCL) rwlock.o: rwlock.c $(RWLOCK_SRCS) $(INCL) sched.o: sched.c $(SCHED_SRCS) $(INCL) semaphore.o: semaphore.c $(SEMAPHORE_SRCS) $(INCL) spin.o: spin.c $(SPIN_SRCS) $(INCL) sync.o: sync.c $(SYNC_SRCS) $(INCL) tsd.o: tsd.c $(TSD_SRCS) $(INCL) version.o: version.rc $(INCL) nyquist-3.05/liblo/pthreads.2/ptw32_reuse.c0000644000175000000620000001103311512143043017554 0ustar stevestaff/* * ptw32_threadReuse.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * How it works: * A pthread_t is a struct (2x32 bit scalar types on IA-32, 2x64 bit on IA-64) * which is normally passed/returned by value to/from pthreads routines. * Applications are therefore storing a copy of the struct as it is at that * time. * * The original pthread_t struct plus all copies of it contain the address of * the thread state struct ptw32_thread_t_ (p), plus a reuse counter (x). Each * ptw32_thread_t contains the original copy of it's pthread_t. * Once malloced, a ptw32_thread_t_ struct is not freed until the process exits. * * The thread reuse stack is a simple LILO stack managed through a singly * linked list element in the ptw32_thread_t. * * Each time a thread is destroyed, the ptw32_thread_t address is pushed onto the * reuse stack after it's ptHandle's reuse counter has been incremented. * * The following can now be said from this: * - two pthread_t's are identical if their ptw32_thread_t reference pointers * are equal and their reuse counters are equal. That is, * * equal = (a.p == b.p && a.x == b.x) * * - a pthread_t copy refers to a destroyed thread if the reuse counter in * the copy is not equal to the reuse counter in the original. * * threadDestroyed = (copy.x != ((ptw32_thread_t *)copy.p)->ptHandle.x) * */ /* * Pop a clean pthread_t struct off the reuse stack. */ pthread_t ptw32_threadReusePop (void) { pthread_t t = {NULL, 0}; EnterCriticalSection (&ptw32_thread_reuse_lock); if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseTop) { ptw32_thread_t * tp; tp = ptw32_threadReuseTop; ptw32_threadReuseTop = tp->prevReuse; if (PTW32_THREAD_REUSE_EMPTY == ptw32_threadReuseTop) { ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; } tp->prevReuse = NULL; t = tp->ptHandle; } LeaveCriticalSection (&ptw32_thread_reuse_lock); return t; } /* * Push a clean pthread_t struct onto the reuse stack. * Must be re-initialised when reused. * All object elements (mutexes, events etc) must have been either * detroyed before this, or never initialised. */ void ptw32_threadReusePush (pthread_t thread) { ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; pthread_t t; EnterCriticalSection (&ptw32_thread_reuse_lock); t = tp->ptHandle; memset(tp, 0, sizeof(ptw32_thread_t)); /* Must restore the original POSIX handle that we just wiped. */ tp->ptHandle = t; /* Bump the reuse counter now */ #ifdef PTW32_THREAD_ID_REUSE_INCREMENT tp->ptHandle.x += PTW32_THREAD_ID_REUSE_INCREMENT; #else tp->ptHandle.x++; #endif tp->prevReuse = PTW32_THREAD_REUSE_EMPTY; if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseBottom) { ptw32_threadReuseBottom->prevReuse = tp; } else { ptw32_threadReuseTop = tp; } ptw32_threadReuseBottom = tp; LeaveCriticalSection (&ptw32_thread_reuse_lock); } nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_setpshared.c0000644000175000000620000000744711512143043023376 0ustar stevestaff/* * pthread_mutexattr_setpshared.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Mutexes created with 'attr' can be shared between * processes if pthread_mutex_t variable is allocated * in memory shared by these processes. * * PARAMETERS * attr * pointer to an instance of pthread_mutexattr_t * * pshared * must be one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * DESCRIPTION * Mutexes creatd with 'attr' can be shared between * processes if pthread_mutex_t variable is allocated * in memory shared by these processes. * * NOTES: * 1) pshared mutexes MUST be allocated in shared * memory. * * 2) The following macro is defined if shared mutexes * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully set attribute, * EINVAL 'attr' or pshared is invalid, * ENOSYS PTHREAD_PROCESS_SHARED not supported, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && ((pshared == PTHREAD_PROCESS_SHARED) || (pshared == PTHREAD_PROCESS_PRIVATE))) { if (pshared == PTHREAD_PROCESS_SHARED) { #if !defined( _POSIX_THREAD_PROCESS_SHARED ) result = ENOSYS; pshared = PTHREAD_PROCESS_PRIVATE; #else result = 0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ } else { result = 0; } (*attr)->pshared = pshared; } else { result = EINVAL; } return (result); } /* pthread_mutexattr_setpshared */ nyquist-3.05/liblo/pthreads.2/pthread_mutex_init.c0000644000175000000620000000567011512143043021300 0ustar stevestaff/* * pthread_mutex_init.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) { int result = 0; pthread_mutex_t mx; if (mutex == NULL) { return EINVAL; } if (attr != NULL && *attr != NULL && (*attr)->pshared == PTHREAD_PROCESS_SHARED) { /* * Creating mutex that can be shared between * processes. */ #if _POSIX_THREAD_PROCESS_SHARED >= 0 /* * Not implemented yet. */ #error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. #else return ENOSYS; #endif /* _POSIX_THREAD_PROCESS_SHARED */ } mx = (pthread_mutex_t) calloc (1, sizeof (*mx)); if (mx == NULL) { result = ENOMEM; } else { mx->lock_idx = 0; mx->recursive_count = 0; mx->kind = (attr == NULL || *attr == NULL ? PTHREAD_MUTEX_DEFAULT : (*attr)->kind); mx->ownerThread.p = NULL; mx->event = CreateEvent (NULL, PTW32_FALSE, /* manual reset = No */ PTW32_FALSE, /* initial state = not signaled */ NULL); /* event name */ if (0 == mx->event) { result = ENOSPC; free (mx); mx = NULL; } } *mutex = mx; return (result); } nyquist-3.05/liblo/pthreads.2/pthread_attr_setschedparam.c0000644000175000000620000000413111512143043022757 0ustar stevestaff/* * pthread_attr_setschedparam.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int pthread_attr_setschedparam (pthread_attr_t * attr, const struct sched_param *param) { int priority; if (ptw32_is_attr (attr) != 0 || param == NULL) { return EINVAL; } priority = param->sched_priority; /* Validate priority level. */ if (priority < sched_get_priority_min (SCHED_OTHER) || priority > sched_get_priority_max (SCHED_OTHER)) { return EINVAL; } memcpy (&(*attr)->param, param, sizeof (*param)); return 0; } nyquist-3.05/liblo/pthreads.2/pthread_rwlock_unlock.c0000644000175000000620000000525311512143043021764 0ustar stevestaff/* * pthread_rwlock_unlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_unlock (pthread_rwlock_t * rwlock) { int result, result1; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return (EINVAL); } if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { /* * Assume any race condition here is harmless. */ return 0; } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if (rwl->nExclusiveAccessCount == 0) { if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) { return result; } if (++rwl->nCompletedSharedAccessCount == 0) { result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted)); } result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); } else { rwl->nExclusiveAccessCount--; result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); } return ((result != 0) ? result : result1); } nyquist-3.05/liblo/pthreads.2/sem_trywait.c0000644000175000000620000000712611512143043017751 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_trywait.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" int sem_trywait (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function tries to wait on a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function tries to wait on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * this function returns immediately with the error EAGAIN * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EAGAIN the semaphore was already locked, * EINVAL 'sem' is not a valid semaphore, * ENOTSUP sem_trywait is not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; if (s == NULL) { result = EINVAL; } else if ((result = pthread_mutex_lock (&s->lock)) == 0) { /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } if (s->value > 0) { s->value--; } else { result = EAGAIN; } (void) pthread_mutex_unlock (&s->lock); } if (result != 0) { errno = result; return -1; } return 0; } /* sem_trywait */ nyquist-3.05/liblo/pthreads.2/ptw32_MCS_lock.c0000644000175000000620000001514311512143043020071 0ustar stevestaff/* * ptw32_MCS_lock.c * * Description: * This translation unit implements queue-based locks. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* * About MCS locks: * * MCS locks are queue-based locks, where the queue nodes are local to the * thread. The 'lock' is nothing more than a global pointer that points to * the last node in the queue, or is NULL if the queue is empty. * * Originally designed for use as spin locks requiring no kernel resources * for synchronisation or blocking, the implementation below has adapted * the MCS spin lock for use as a general mutex that will suspend threads * when there is lock contention. * * Because the queue nodes are thread-local, most of the memory read/write * operations required to add or remove nodes from the queue do not trigger * cache-coherence updates. * * Like 'named' mutexes, MCS locks consume system resources transiently - * they are able to acquire and free resources automatically - but MCS * locks do not require any unique 'name' to identify the lock to all * threads using it. * * Usage of MCS locks: * * - you need a global ptw32_mcs_lock_t instance initialised to 0 or NULL. * - you need a local thread-scope ptw32_mcs_local_node_t instance, which * may serve several different locks but you need at least one node for * every lock held concurrently by a thread. * * E.g.: * * ptw32_mcs_lock_t lock1 = 0; * ptw32_mcs_lock_t lock2 = 0; * * void *mythread(void *arg) * { * ptw32_mcs_local_node_t node; * * ptw32_mcs_acquire (&lock1, &node); * ptw32_mcs_release (&node); * * ptw32_mcs_acquire (&lock2, &node); * ptw32_mcs_release (&node); * { * ptw32_mcs_local_node_t nodex; * * ptw32_mcs_acquire (&lock1, &node); * ptw32_mcs_acquire (&lock2, &nodex); * * ptw32_mcs_release (&nodex); * ptw32_mcs_release (&node); * } * return (void *)0; * } */ #include "implement.h" #include "pthread.h" /* * ptw32_mcs_flag_set -- notify another thread about an event. * * Set event if an event handle has been stored in the flag, and * set flag to -1 otherwise. Note that -1 cannot be a valid handle value. */ INLINE void ptw32_mcs_flag_set (LONG * flag) { HANDLE e = (HANDLE)PTW32_INTERLOCKED_COMPARE_EXCHANGE( (PTW32_INTERLOCKED_LPLONG)flag, (PTW32_INTERLOCKED_LONG)-1, (PTW32_INTERLOCKED_LONG)0); if ((HANDLE)0 != e) { /* another thread has already stored an event handle in the flag */ SetEvent(e); } } /* * ptw32_mcs_flag_set -- wait for notification from another. * * Store an event handle in the flag and wait on it if the flag has not been * set, and proceed without creating an event otherwise. */ INLINE void ptw32_mcs_flag_wait (LONG * flag) { if (0 == InterlockedExchangeAdd((LPLONG)flag, 0)) /* MBR fence */ { /* the flag is not set. create event. */ HANDLE e = CreateEvent(NULL, PTW32_FALSE, PTW32_FALSE, NULL); if (0 == PTW32_INTERLOCKED_COMPARE_EXCHANGE( (PTW32_INTERLOCKED_LPLONG)flag, (PTW32_INTERLOCKED_LONG)e, (PTW32_INTERLOCKED_LONG)0)) { /* stored handle in the flag. wait on it now. */ WaitForSingleObject(e, INFINITE); } CloseHandle(e); } } /* * ptw32_mcs_lock_acquire -- acquire an MCS lock. * * See: * J. M. Mellor-Crummey and M. L. Scott. * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. */ INLINE void ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node) { ptw32_mcs_local_node_t *pred; node->lock = lock; node->nextFlag = 0; node->readyFlag = 0; node->next = 0; /* initially, no successor */ /* queue for the lock */ pred = (ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_EXCHANGE((LPLONG)lock, (LONG)node); if (0 != pred) { /* the lock was not free. link behind predecessor. */ pred->next = node; ptw32_mcs_flag_set(&pred->nextFlag); ptw32_mcs_flag_wait(&node->readyFlag); } } /* * ptw32_mcs_lock_release -- release an MCS lock. * * See: * J. M. Mellor-Crummey and M. L. Scott. * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. */ INLINE void ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node) { ptw32_mcs_lock_t *lock = node->lock; ptw32_mcs_local_node_t *next = (ptw32_mcs_local_node_t *) InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ if (0 == next) { /* no known successor */ if (node == (ptw32_mcs_local_node_t *) PTW32_INTERLOCKED_COMPARE_EXCHANGE((PTW32_INTERLOCKED_LPLONG)lock, (PTW32_INTERLOCKED_LONG)0, (PTW32_INTERLOCKED_LONG)node)) { /* no successor, lock is free now */ return; } /* wait for successor */ ptw32_mcs_flag_wait(&node->nextFlag); next = (ptw32_mcs_local_node_t *) InterlockedExchangeAdd((LPLONG)&node->next, 0); /* MBR fence */ } /* pass the lock */ ptw32_mcs_flag_set(&next->readyFlag); } nyquist-3.05/liblo/pthreads.2/pthread_spin_lock.c0000644000175000000620000000465711512143043021100 0ustar stevestaff/* * pthread_spin_lock.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_spin_lock (pthread_spinlock_t * lock) { register pthread_spinlock_t s; if (NULL == lock || NULL == *lock) { return (EINVAL); } if (*lock == PTHREAD_SPINLOCK_INITIALIZER) { int result; if ((result = ptw32_spinlock_check_need_init (lock)) != 0) { return (result); } } s = *lock; while ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED == PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & (s->interlock), (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED, (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED)) { } if (s->interlock == PTW32_SPIN_LOCKED) { return 0; } else if (s->interlock == PTW32_SPIN_USE_MUTEX) { return pthread_mutex_lock (&(s->u.mutex)); } return EINVAL; } nyquist-3.05/liblo/pthreads.2/pthread_equal.c0000644000175000000620000000507711512143043020223 0ustar stevestaff/* * pthread_equal.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_equal (pthread_t t1, pthread_t t2) /* * ------------------------------------------------------ * DOCPUBLIC * This function returns nonzero if t1 and t2 are equal, else * returns nonzero * * PARAMETERS * t1, * t2 * thread IDs * * * DESCRIPTION * This function returns nonzero if t1 and t2 are equal, else * returns zero. * * RESULTS * non-zero if t1 and t2 refer to the same thread, * 0 t1 and t2 do not refer to the same thread * * ------------------------------------------------------ */ { int result; /* * We also accept NULL == NULL - treating NULL as a thread * for this special case, because there is no error that we can return. */ result = ( t1.p == t2.p && t1.x == t2.x ); return (result); } /* pthread_equal */ nyquist-3.05/liblo/pthreads.2/pthread_barrierattr_setpshared.c0000644000175000000620000000745011512143043023654 0ustar stevestaff/* * pthread_barrier_attr_setpshared.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Barriers created with 'attr' can be shared between * processes if pthread_barrier_t variable is allocated * in memory shared by these processes. * * PARAMETERS * attr * pointer to an instance of pthread_barrierattr_t * * pshared * must be one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * DESCRIPTION * Mutexes creatd with 'attr' can be shared between * processes if pthread_barrier_t variable is allocated * in memory shared by these processes. * * NOTES: * 1) pshared barriers MUST be allocated in shared * memory. * * 2) The following macro is defined if shared barriers * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully set attribute, * EINVAL 'attr' or pshared is invalid, * ENOSYS PTHREAD_PROCESS_SHARED not supported, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && ((pshared == PTHREAD_PROCESS_SHARED) || (pshared == PTHREAD_PROCESS_PRIVATE))) { if (pshared == PTHREAD_PROCESS_SHARED) { #if !defined( _POSIX_THREAD_PROCESS_SHARED ) result = ENOSYS; pshared = PTHREAD_PROCESS_PRIVATE; #else result = 0; #endif /* _POSIX_THREAD_PROCESS_SHARED */ } else { result = 0; } (*attr)->pshared = pshared; } else { result = EINVAL; } return (result); } /* pthread_barrierattr_setpshared */ nyquist-3.05/liblo/pthreads.2/dll.c0000644000175000000620000000514611512143043016155 0ustar stevestaff/* * dll.c * * Description: * This translation unit implements DLL initialisation. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef PTW32_STATIC_LIB #include "pthread.h" #include "implement.h" #ifdef _MSC_VER /* * lpvReserved yields an unreferenced formal parameter; * ignore it */ #pragma warning( disable : 4100 ) #endif #ifdef __cplusplus /* * Dear c++: Please don't mangle this name. -thanks */ extern "C" #endif /* __cplusplus */ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { BOOL result = PTW32_TRUE; switch (fdwReason) { case DLL_PROCESS_ATTACH: result = pthread_win32_process_attach_np (); break; case DLL_THREAD_ATTACH: /* * A thread is being created */ result = pthread_win32_thread_attach_np (); break; case DLL_THREAD_DETACH: /* * A thread is exiting cleanly */ result = pthread_win32_thread_detach_np (); break; case DLL_PROCESS_DETACH: (void) pthread_win32_thread_detach_np (); result = pthread_win32_process_detach_np (); break; } return (result); } /* DllMain */ #endif /* PTW32_STATIC_LIB */ nyquist-3.05/liblo/pthreads.2/sem_wait.c0000644000175000000620000001226711512143043017214 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_wait.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" static void PTW32_CDECL ptw32_sem_wait_cleanup(void * sem) { sem_t s = (sem_t) sem; if (pthread_mutex_lock (&s->lock) == 0) { /* * If sema is destroyed do nothing, otherwise:- * If the sema is posted between us being cancelled and us locking * the sema again above then we need to consume that post but cancel * anyway. If we don't get the semaphore we indicate that we're no * longer waiting. */ if (*((sem_t *)sem) != NULL && !(WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0)) { ++s->value; #ifdef NEED_SEM if (s->value > 0) { s->leftToUnblock = 0; } #else /* * Don't release the W32 sema, it doesn't need adjustment * because it doesn't record the number of waiters. */ #endif /* NEED_SEM */ } (void) pthread_mutex_unlock (&s->lock); } } int sem_wait (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function waits on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value or until interrupted by * a signal. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; pthread_testcancel(); if (s == NULL) { result = EINVAL; } else { if ((result = pthread_mutex_lock (&s->lock)) == 0) { int v; /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } v = --s->value; (void) pthread_mutex_unlock (&s->lock); if (v < 0) { #ifdef _MSC_VER #pragma inline_depth(0) #endif /* Must wait */ pthread_cleanup_push(ptw32_sem_wait_cleanup, (void *) s); result = pthreadCancelableWait (s->sem); /* Cleanup if we're canceled or on any other error */ pthread_cleanup_pop(result); #ifdef _MSC_VER #pragma inline_depth() #endif } #ifdef NEED_SEM if (!result && pthread_mutex_lock (&s->lock) == 0) { if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } if (s->leftToUnblock > 0) { --s->leftToUnblock; SetEvent(s->sem); } (void) pthread_mutex_unlock (&s->lock); } #endif /* NEED_SEM */ } } if (result != 0) { errno = result; return -1; } return 0; } /* sem_wait */ nyquist-3.05/liblo/pthreads.2/ptw32_threadStart.c0000644000175000000620000002076511512143043020732 0ustar stevestaff/* * ptw32_threadStart.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifdef __CLEANUP_SEH static DWORD ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) { switch (ep->ExceptionRecord->ExceptionCode) { case EXCEPTION_PTW32_SERVICES: { DWORD param; DWORD numParams = ep->ExceptionRecord->NumberParameters; numParams = (numParams > 3) ? 3 : numParams; for (param = 0; param < numParams; param++) { ei[param] = ep->ExceptionRecord->ExceptionInformation[param]; } return EXCEPTION_EXECUTE_HANDLER; break; } default: { /* * A system unexpected exception has occurred running the user's * routine. We need to cleanup before letting the exception * out of thread scope. */ pthread_t self = pthread_self (); (void) pthread_mutex_destroy (&((ptw32_thread_t *)self.p)->cancelLock); ptw32_callUserDestroyRoutines (self); return EXCEPTION_CONTINUE_SEARCH; break; } } } #elif defined(__CLEANUP_CXX) #if defined(_MSC_VER) # include #elif defined(__WATCOMC__) # include # include typedef terminate_handler terminate_function; #else # if defined(__GNUC__) && __GNUC__ < 3 # include # else # include using std::terminate_handler; using std::terminate; using std::set_terminate; # endif typedef terminate_handler terminate_function; #endif static terminate_function ptw32_oldTerminate; void ptw32_terminate () { set_terminate (ptw32_oldTerminate); (void) pthread_win32_thread_detach_np (); terminate (); } #endif #if ! defined (__MINGW32__) || (defined (__MSVCRT__) && ! defined (__DMC__)) unsigned __stdcall #else void #endif ptw32_threadStart (void *vthreadParms) { ThreadParms * threadParms = (ThreadParms *) vthreadParms; pthread_t self; ptw32_thread_t * sp; void *(*start) (void *); void * arg; #ifdef __CLEANUP_SEH DWORD ei[] = { 0, 0, 0 }; #endif #ifdef __CLEANUP_C int setjmp_rc; #endif void * status = (void *) 0; self = threadParms->tid; sp = (ptw32_thread_t *) self.p; start = threadParms->start; arg = threadParms->arg; free (threadParms); #if defined (__MINGW32__) && ! defined (__MSVCRT__) /* * beginthread does not return the thread id and is running * before it returns us the thread handle, and so we do it here. */ sp->thread = GetCurrentThreadId (); /* * Here we're using cancelLock as a general-purpose lock * to make the new thread wait until the creating thread * has the new handle. */ if (pthread_mutex_lock (&sp->cancelLock) == 0) { (void) pthread_mutex_unlock (&sp->cancelLock); } #endif pthread_setspecific (ptw32_selfThreadKey, sp); sp->state = PThreadStateRunning; #ifdef __CLEANUP_SEH __try { /* * Run the caller's routine; */ status = sp->exitStatus = (*start) (arg); #ifdef _UWIN if (--pthread_count <= 0) exit (0); #endif } __except (ExceptionFilter (GetExceptionInformation (), ei)) { switch (ei[0]) { case PTW32_EPS_CANCEL: status = sp->exitStatus = PTHREAD_CANCELED; #ifdef _UWIN if (--pthread_count <= 0) exit (0); #endif break; case PTW32_EPS_EXIT: status = sp->exitStatus; break; default: status = sp->exitStatus = PTHREAD_CANCELED; break; } } #else /* __CLEANUP_SEH */ #ifdef __CLEANUP_C setjmp_rc = setjmp (sp->start_mark); if (0 == setjmp_rc) { /* * Run the caller's routine; */ status = sp->exitStatus = (*start) (arg); } else { switch (setjmp_rc) { case PTW32_EPS_CANCEL: status = sp->exitStatus = PTHREAD_CANCELED; break; case PTW32_EPS_EXIT: status = sp->exitStatus; break; default: status = sp->exitStatus = PTHREAD_CANCELED; break; } } #else /* __CLEANUP_C */ #ifdef __CLEANUP_CXX ptw32_oldTerminate = set_terminate (&ptw32_terminate); try { /* * Run the caller's routine in a nested try block so that we * can run the user's terminate function, which may call * pthread_exit() or be canceled. */ try { status = sp->exitStatus = (*start) (arg); } catch (ptw32_exception &) { /* * Pass these through to the outer block. */ throw; } catch (...) { /* * We want to run the user's terminate function if supplied. * That function may call pthread_exit() or be canceled, which will * be handled by the outer try block. * * ptw32_terminate() will be called if there is no user * supplied function. */ terminate_function term_func = set_terminate (0); set_terminate (term_func); if (term_func != 0) { term_func (); } throw; } } catch (ptw32_exception_cancel &) { /* * Thread was canceled. */ status = sp->exitStatus = PTHREAD_CANCELED; } catch (ptw32_exception_exit &) { /* * Thread was exited via pthread_exit(). */ status = sp->exitStatus; } catch (...) { /* * A system unexpected exception has occurred running the user's * terminate routine. We get control back within this block - cleanup * and release the exception out of thread scope. */ status = sp->exitStatus = PTHREAD_CANCELED; (void) pthread_mutex_lock (&sp->cancelLock); sp->state = PThreadStateException; (void) pthread_mutex_unlock (&sp->cancelLock); (void) pthread_win32_thread_detach_np (); (void) set_terminate (ptw32_oldTerminate); throw; /* * Never reached. */ } (void) set_terminate (ptw32_oldTerminate); #else #error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. #endif /* __CLEANUP_CXX */ #endif /* __CLEANUP_C */ #endif /* __CLEANUP_SEH */ #if defined(PTW32_STATIC_LIB) /* * We need to cleanup the pthread now if we have * been statically linked, in which case the cleanup * in dllMain won't get done. Joinable threads will * only be partially cleaned up and must be fully cleaned * up by pthread_join() or pthread_detach(). * * Note: if this library has been statically linked, * implicitly created pthreads (those created * for Win32 threads which have called pthreads routines) * must be cleaned up explicitly by the application * (by calling pthread_win32_thread_detach_np()). * For the dll, dllMain will do the cleanup automatically. */ (void) pthread_win32_thread_detach_np (); #endif #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) _endthreadex ((unsigned) status); #else _endthread (); #endif /* * Never reached. */ #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) return (unsigned) status; #endif } /* ptw32_threadStart */ nyquist-3.05/liblo/pthreads.2/README.NONPORTABLE0000644000175000000620000002735611512143043017707 0ustar stevestaffThis file documents non-portable functions and other issues. Non-portable functions included in pthreads-win32 ------------------------------------------------- BOOL pthread_win32_test_features_np(int mask) This routine allows an application to check which run-time auto-detected features are available within the library. The possible features are: PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE Return TRUE if the native version of InterlockedCompareExchange() is being used. PTW32_ALERTABLE_ASYNC_CANCEL Return TRUE is the QueueUserAPCEx package QUSEREX.DLL is available and the AlertDrv.sys driver is loaded into Windows, providing alertable (pre-emptive) asyncronous threads cancelation. If this feature returns FALSE then the default async cancel scheme is in use, which cannot cancel blocked threads. Features may be Or'ed into the mask parameter, in which case the routine returns TRUE if any of the Or'ed features would return TRUE. At this stage it doesn't make sense to Or features but it may some day. void * pthread_timechange_handler_np(void *) To improve tolerance against operator or time service initiated system clock changes. This routine can be called by an application when it receives a WM_TIMECHANGE message from the system. At present it broadcasts all condition variables so that waiting threads can wake up and re-evaluate their conditions and restart their timed waits if required. It has the same return type and argument type as a thread routine so that it may be called directly through pthread_create(), i.e. as a separate thread. Parameters Although a parameter must be supplied, it is ignored. The value NULL can be used. Return values It can return an error EAGAIN to indicate that not all condition variables were broadcast for some reason. Otherwise, 0 is returned. If run as a thread, the return value is returned through pthread_join(). The return value should be cast to an integer. HANDLE pthread_getw32threadhandle_np(pthread_t thread); Returns the win32 thread handle that the POSIX thread "thread" is running as. Applications can use the win32 handle to set win32 specific attributes of the thread. int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind) int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind) These two routines are included for Linux compatibility and are direct equivalents to the standard routines pthread_mutexattr_settype pthread_mutexattr_gettype pthread_mutexattr_setkind_np accepts the following mutex kinds: PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_RECURSIVE_NP These are really just equivalent to (respectively): PTHREAD_MUTEX_NORMAL PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_RECURSIVE int pthread_delay_np (const struct timespec *interval); This routine causes a thread to delay execution for a specific period of time. This period ends at the current time plus the specified interval. The routine will not return before the end of the period is reached, but may return an arbitrary amount of time after the period has gone by. This can be due to system load, thread priorities, and system timer granularity. Specifying an interval of zero (0) seconds and zero (0) nanoseconds is allowed and can be used to force the thread to give up the processor or to deliver a pending cancelation request. This routine is a cancelation point. The timespec structure contains the following two fields: tv_sec is an integer number of seconds. tv_nsec is an integer number of nanoseconds. Return Values If an error condition occurs, this routine returns an integer value indicating the type of error. Possible return values are as follows: 0 Successful completion. [EINVAL] The value specified by interval is invalid. int pthread_num_processors_np This routine (found on HPUX systems) returns the number of processors in the system. This implementation actually returns the number of processors available to the process, which can be a lower number than the system's number, depending on the process's affinity mask. BOOL pthread_win32_process_attach_np (void); BOOL pthread_win32_process_detach_np (void); BOOL pthread_win32_thread_attach_np (void); BOOL pthread_win32_thread_detach_np (void); These functions contain the code normally run via dllMain when the library is used as a dll but which need to be called explicitly by an application when the library is statically linked. You will need to call pthread_win32_process_attach_np() before you can call any pthread routines when statically linking. You should call pthread_win32_process_detach_np() before exiting your application to clean up. pthread_win32_thread_attach_np() is currently a no-op, but pthread_win32_thread_detach_np() is needed to clean up the implicit pthread handle that is allocated to a Win32 thread if it calls certain pthreads routines. Call this routine when the Win32 thread exits. These functions invariably return TRUE except for pthread_win32_process_attach_np() which will return FALSE if pthreads-win32 initialisation fails. int pthreadCancelableWait (HANDLE waitHandle); int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); These two functions provide hooks into the pthread_cancel mechanism that will allow you to wait on a Windows handle and make it a cancellation point. Both functions block until either the given w32 handle is signaled, or pthread_cancel has been called. It is implemented using WaitForMultipleObjects on 'waitHandle' and a manually reset w32 event used to implement pthread_cancel. Non-portable issues ------------------- Thread priority POSIX defines a single contiguous range of numbers that determine a thread's priority. Win32 defines priority classes and priority levels relative to these classes. Classes are simply priority base levels that the defined priority levels are relative to such that, changing a process's priority class will change the priority of all of it's threads, while the threads retain the same relativity to each other. A Win32 system defines a single contiguous monotonic range of values that define system priority levels, just like POSIX. However, Win32 restricts individual threads to a subset of this range on a per-process basis. The following table shows the base priority levels for combinations of priority class and priority value in Win32. Process Priority Class Thread Priority Level ----------------------------------------------------------------- 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE 17 REALTIME_PRIORITY_CLASS -7 18 REALTIME_PRIORITY_CLASS -6 19 REALTIME_PRIORITY_CLASS -5 20 REALTIME_PRIORITY_CLASS -4 21 REALTIME_PRIORITY_CLASS -3 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST 27 REALTIME_PRIORITY_CLASS 3 28 REALTIME_PRIORITY_CLASS 4 29 REALTIME_PRIORITY_CLASS 5 30 REALTIME_PRIORITY_CLASS 6 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. As you can see, the real priority levels available to any individual Win32 thread are non-contiguous. An application using pthreads-win32 should not make assumptions about the numbers used to represent thread priority levels, except that they are monotonic between the values returned by sched_get_priority_min() and sched_get_priority_max(). E.g. Windows 95, 98, NT, 2000, XP make available a non-contiguous range of numbers between -15 and 15, while at least one version of WinCE (3.0) defines the minimum priority (THREAD_PRIORITY_LOWEST) as 5, and the maximum priority (THREAD_PRIORITY_HIGHEST) as 1. Internally, pthreads-win32 maps any priority levels between THREAD_PRIORITY_IDLE and THREAD_PRIORITY_LOWEST to THREAD_PRIORITY_LOWEST, or between THREAD_PRIORITY_TIME_CRITICAL and THREAD_PRIORITY_HIGHEST to THREAD_PRIORITY_HIGHEST. Currently, this also applies to REALTIME_PRIORITY_CLASSi even if levels -7, -6, -5, -4, -3, 3, 4, 5, and 6 are supported. If it wishes, a Win32 application using pthreads-win32 can use the Win32 defined priority macros THREAD_PRIORITY_IDLE through THREAD_PRIORITY_TIME_CRITICAL. nyquist-3.05/liblo/pthreads.2/sem_getvalue.c0000644000175000000620000000643411512143043020063 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_getvalue.c * * Purpose: * Semaphores aren't actually part of PThreads. * They are defined by the POSIX Standard: * * POSIX 1003.1-2001 * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" int sem_getvalue (sem_t * sem, int *sval) /* * ------------------------------------------------------ * DOCPUBLIC * This function stores the current count value of the * semaphore. * RESULTS * * Return value * * 0 sval has been set. * -1 failed, error in errno * * in global errno * * EINVAL 'sem' is not a valid semaphore, * ENOSYS this function is not supported, * * * PARAMETERS * * sem pointer to an instance of sem_t * * sval pointer to int. * * DESCRIPTION * This function stores the current count value of the semaphore * pointed to by sem in the int pointed to by sval. */ { if (sem == NULL || *sem == NULL || sval == NULL) { errno = EINVAL; return -1; } else { long value; register sem_t s = *sem; int result = 0; if ((result = pthread_mutex_lock(&s->lock)) == 0) { /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } value = s->value; (void) pthread_mutex_unlock(&s->lock); *sval = value; } return result; } } /* sem_getvalue */ nyquist-3.05/liblo/pthreads.2/rwlock.c0000644000175000000620000000413211512143043016675 0ustar stevestaff/* * rwlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "ptw32_rwlock_check_need_init.c" #include "ptw32_rwlock_cancelwrwait.c" #include "pthread_rwlock_init.c" #include "pthread_rwlock_destroy.c" #include "pthread_rwlockattr_init.c" #include "pthread_rwlockattr_destroy.c" #include "pthread_rwlockattr_getpshared.c" #include "pthread_rwlockattr_setpshared.c" #include "pthread_rwlock_rdlock.c" #include "pthread_rwlock_timedrdlock.c" #include "pthread_rwlock_wrlock.c" #include "pthread_rwlock_timedwrlock.c" #include "pthread_rwlock_unlock.c" #include "pthread_rwlock_tryrdlock.c" #include "pthread_rwlock_trywrlock.c" nyquist-3.05/liblo/pthreads.2/pthread.h0000644000175000000620000012423211512143043017034 0ustar stevestaff/* This is an implementation of the threads API of POSIX 1003.1-2001. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined( PTHREAD_H ) #define PTHREAD_H /* * See the README file for an explanation of the pthreads-win32 version * numbering scheme and how the DLL is named etc. */ #define PTW32_VERSION 2,8,0,0 #define PTW32_VERSION_STRING "2, 8, 0, 0\0" /* There are three implementations of cancel cleanup. * Note that pthread.h is included in both application * compilation units and also internally for the library. * The code here and within the library aims to work * for all reasonable combinations of environments. * * The three implementations are: * * WIN32 SEH * C * C++ * * Please note that exiting a push/pop block via * "return", "exit", "break", or "continue" will * lead to different behaviour amongst applications * depending upon whether the library was built * using SEH, C++, or C. For example, a library built * with SEH will call the cleanup routine, while both * C++ and C built versions will not. */ /* * Define defaults for cleanup code. * Note: Unless the build explicitly defines one of the following, then * we default to standard C style cleanup. This style uses setjmp/longjmp * in the cancelation and thread exit implementations and therefore won't * do stack unwinding if linked to applications that have it (e.g. * C++ apps). This is currently consistent with most/all commercial Unix * POSIX threads implementations. */ #if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) # define __CLEANUP_C #endif #if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) #error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. #endif /* * Stop here if we are being included by the resource compiler. */ #ifndef RC_INVOKED #undef PTW32_LEVEL #if defined(_POSIX_SOURCE) #define PTW32_LEVEL 0 /* Early POSIX */ #endif #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 #undef PTW32_LEVEL #define PTW32_LEVEL 1 /* Include 1b, 1c and 1d */ #endif #if defined(INCLUDE_NP) #undef PTW32_LEVEL #define PTW32_LEVEL 2 /* Include Non-Portable extensions */ #endif #define PTW32_LEVEL_MAX 3 #if !defined(PTW32_LEVEL) #define PTW32_LEVEL PTW32_LEVEL_MAX /* Include everything */ #endif #ifdef _UWIN # define HAVE_STRUCT_TIMESPEC 1 # define HAVE_SIGNAL_H 1 # undef HAVE_CONFIG_H # pragma comment(lib, "pthread") #endif /* * ------------------------------------------------------------- * * * Module: pthread.h * * Purpose: * Provides an implementation of PThreads based upon the * standard: * * POSIX 1003.1-2001 * and * The Single Unix Specification version 3 * * (these two are equivalent) * * in order to enhance code portability between Windows, * various commercial Unix implementations, and Linux. * * See the ANNOUNCE file for a full list of conforming * routines and defined constants, and a list of missing * routines and constants not defined in this implementation. * * Authors: * There have been many contributors to this library. * The initial implementation was contributed by * John Bossom, and several others have provided major * sections or revisions of parts of the implementation. * Often significant effort has been contributed to * find and fix important bugs and other problems to * improve the reliability of the library, which sometimes * is not reflected in the amount of code which changed as * result. * As much as possible, the contributors are acknowledged * in the ChangeLog file in the source code distribution * where their changes are noted in detail. * * Contributors are listed in the CONTRIBUTORS file. * * As usual, all bouquets go to the contributors, and all * brickbats go to the project maintainer. * * Maintainer: * The code base for this project is coordinated and * eventually pre-tested, packaged, and made available by * * Ross Johnson * * QA Testers: * Ultimately, the library is tested in the real world by * a host of competent and demanding scientists and * engineers who report bugs and/or provide solutions * which are then fixed or incorporated into subsequent * versions of the library. Each time a bug is fixed, a * test case is written to prove the fix and ensure * that later changes to the code don't reintroduce the * same error. The number of test cases is slowly growing * and therefore so is the code reliability. * * Compliance: * See the file ANNOUNCE for the list of implemented * and not-implemented routines and defined options. * Of course, these are all defined is this file as well. * * Web site: * The source code and other information about this library * are available from * * http://sources.redhat.com/pthreads-win32/ * * ------------------------------------------------------------- */ /* Try to avoid including windows.h */ #if defined(__MINGW32__) && defined(__cplusplus) #define PTW32_INCLUDE_WINDOWS_H #endif #ifdef PTW32_INCLUDE_WINDOWS_H #include #endif #if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) /* * VC++6.0 or early compiler's header has no DWORD_PTR type. */ typedef unsigned long DWORD_PTR; #endif /* * ----------------- * autoconf switches * ----------------- */ #if HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifndef NEED_FTIME #include #else /* NEED_FTIME */ /* use native WIN32 time API */ #endif /* NEED_FTIME */ #if HAVE_SIGNAL_H #include #endif /* HAVE_SIGNAL_H */ #include #include /* * Boolean values to make us independent of system includes. */ enum { PTW32_FALSE = 0, PTW32_TRUE = (! PTW32_FALSE) }; /* * This is a duplicate of what is in the autoconf config.h, * which is only used when building the pthread-win32 libraries. */ #ifndef PTW32_CONFIG_H # if defined(WINCE) # define NEED_ERRNO # define NEED_SEM # endif # if defined(_UWIN) || defined(__MINGW32__) # define HAVE_MODE_T # endif #endif /* * */ #if PTW32_LEVEL >= PTW32_LEVEL_MAX #ifdef NEED_ERRNO #include "need_errno.h" #else #include #endif #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ /* * Several systems don't define some error numbers. */ #ifndef ENOTSUP # define ENOTSUP 48 /* This is the value in Solaris. */ #endif #ifndef ETIMEDOUT # define ETIMEDOUT 10060 /* This is the value in winsock.h. */ #endif #ifndef ENOSYS # define ENOSYS 140 /* Semi-arbitrary value */ #endif #ifndef EDEADLK # ifdef EDEADLOCK # define EDEADLK EDEADLOCK # else # define EDEADLK 36 /* This is the value in MSVC. */ # endif #endif #include /* * To avoid including windows.h we define only those things that we * actually need from it. */ #ifndef PTW32_INCLUDE_WINDOWS_H #ifndef HANDLE # define PTW32__HANDLE_DEF # define HANDLE void * #endif #ifndef DWORD # define PTW32__DWORD_DEF # define DWORD unsigned long #endif #endif #ifndef HAVE_STRUCT_TIMESPEC #define HAVE_STRUCT_TIMESPEC 1 struct timespec { long tv_sec; long tv_nsec; }; #endif /* HAVE_STRUCT_TIMESPEC */ #ifndef SIG_BLOCK #define SIG_BLOCK 0 #endif /* SIG_BLOCK */ #ifndef SIG_UNBLOCK #define SIG_UNBLOCK 1 #endif /* SIG_UNBLOCK */ #ifndef SIG_SETMASK #define SIG_SETMASK 2 #endif /* SIG_SETMASK */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * ------------------------------------------------------------- * * POSIX 1003.1-2001 Options * ========================= * * Options are normally set in , which is not provided * with pthreads-win32. * * For conformance with the Single Unix Specification (version 3), all of the * options below are defined, and have a value of either -1 (not supported) * or 200112L (supported). * * These options can neither be left undefined nor have a value of 0, because * either indicates that sysconf(), which is not implemented, may be used at * runtime to check the status of the option. * * _POSIX_THREADS (== 200112L) * If == 200112L, you can use threads * * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) * If == 200112L, you can control the size of a thread's * stack * pthread_attr_getstacksize * pthread_attr_setstacksize * * _POSIX_THREAD_ATTR_STACKADDR (== -1) * If == 200112L, you can allocate and control a thread's * stack. If not supported, the following functions * will return ENOSYS, indicating they are not * supported: * pthread_attr_getstackaddr * pthread_attr_setstackaddr * * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) * If == 200112L, you can use realtime scheduling. * This option indicates that the behaviour of some * implemented functions conforms to the additional TPS * requirements in the standard. E.g. rwlocks favour * writers over readers when threads have equal priority. * * _POSIX_THREAD_PRIO_INHERIT (== -1) * If == 200112L, you can create priority inheritance * mutexes. * pthread_mutexattr_getprotocol + * pthread_mutexattr_setprotocol + * * _POSIX_THREAD_PRIO_PROTECT (== -1) * If == 200112L, you can create priority ceiling mutexes * Indicates the availability of: * pthread_mutex_getprioceiling * pthread_mutex_setprioceiling * pthread_mutexattr_getprioceiling * pthread_mutexattr_getprotocol + * pthread_mutexattr_setprioceiling * pthread_mutexattr_setprotocol + * * _POSIX_THREAD_PROCESS_SHARED (== -1) * If set, you can create mutexes and condition * variables that can be shared with another * process.If set, indicates the availability * of: * pthread_mutexattr_getpshared * pthread_mutexattr_setpshared * pthread_condattr_getpshared * pthread_condattr_setpshared * * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) * If == 200112L you can use the special *_r library * functions that provide thread-safe behaviour * * _POSIX_READER_WRITER_LOCKS (== 200112L) * If == 200112L, you can use read/write locks * * _POSIX_SPIN_LOCKS (== 200112L) * If == 200112L, you can use spin locks * * _POSIX_BARRIERS (== 200112L) * If == 200112L, you can use barriers * * + These functions provide both 'inherit' and/or * 'protect' protocol, based upon these macro * settings. * * ------------------------------------------------------------- */ /* * POSIX Options */ #undef _POSIX_THREADS #define _POSIX_THREADS 200112L #undef _POSIX_READER_WRITER_LOCKS #define _POSIX_READER_WRITER_LOCKS 200112L #undef _POSIX_SPIN_LOCKS #define _POSIX_SPIN_LOCKS 200112L #undef _POSIX_BARRIERS #define _POSIX_BARRIERS 200112L #undef _POSIX_THREAD_SAFE_FUNCTIONS #define _POSIX_THREAD_SAFE_FUNCTIONS 200112L #undef _POSIX_THREAD_ATTR_STACKSIZE #define _POSIX_THREAD_ATTR_STACKSIZE 200112L /* * The following options are not supported */ #undef _POSIX_THREAD_ATTR_STACKADDR #define _POSIX_THREAD_ATTR_STACKADDR -1 #undef _POSIX_THREAD_PRIO_INHERIT #define _POSIX_THREAD_PRIO_INHERIT -1 #undef _POSIX_THREAD_PRIO_PROTECT #define _POSIX_THREAD_PRIO_PROTECT -1 /* TPS is not fully supported. */ #undef _POSIX_THREAD_PRIORITY_SCHEDULING #define _POSIX_THREAD_PRIORITY_SCHEDULING -1 #undef _POSIX_THREAD_PROCESS_SHARED #define _POSIX_THREAD_PROCESS_SHARED -1 /* * POSIX 1003.1-2001 Limits * =========================== * * These limits are normally set in , which is not provided with * pthreads-win32. * * PTHREAD_DESTRUCTOR_ITERATIONS * Maximum number of attempts to destroy * a thread's thread-specific data on * termination (must be at least 4) * * PTHREAD_KEYS_MAX * Maximum number of thread-specific data keys * available per process (must be at least 128) * * PTHREAD_STACK_MIN * Minimum supported stack size for a thread * * PTHREAD_THREADS_MAX * Maximum number of threads supported per * process (must be at least 64). * * SEM_NSEMS_MAX * The maximum number of semaphores a process can have. * (must be at least 256) * * SEM_VALUE_MAX * The maximum value a semaphore can have. * (must be at least 32767) * */ #undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS #define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 #undef PTHREAD_DESTRUCTOR_ITERATIONS #define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS #undef _POSIX_THREAD_KEYS_MAX #define _POSIX_THREAD_KEYS_MAX 128 #undef PTHREAD_KEYS_MAX #define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX #undef PTHREAD_STACK_MIN #define PTHREAD_STACK_MIN 0 #undef _POSIX_THREAD_THREADS_MAX #define _POSIX_THREAD_THREADS_MAX 64 /* Arbitrary value */ #undef PTHREAD_THREADS_MAX #define PTHREAD_THREADS_MAX 2019 #undef _POSIX_SEM_NSEMS_MAX #define _POSIX_SEM_NSEMS_MAX 256 /* Arbitrary value */ #undef SEM_NSEMS_MAX #define SEM_NSEMS_MAX 1024 #undef _POSIX_SEM_VALUE_MAX #define _POSIX_SEM_VALUE_MAX 32767 #undef SEM_VALUE_MAX #define SEM_VALUE_MAX INT_MAX #if __GNUC__ && ! defined (__declspec) # error Please upgrade your GNU compiler to one that supports __declspec. #endif /* * When building the DLL code, you should define PTW32_BUILD so that * the variables/functions are exported correctly. When using the DLL, * do NOT define PTW32_BUILD, and then the variables/functions will * be imported correctly. */ #ifndef PTW32_STATIC_LIB # ifdef PTW32_BUILD # define PTW32_DLLPORT __declspec (dllexport) # else # define PTW32_DLLPORT __declspec (dllimport) # endif #else # define PTW32_DLLPORT #endif /* * The Open Watcom C/C++ compiler uses a non-standard calling convention * that passes function args in registers unless __cdecl is explicitly specified * in exposed function prototypes. * * We force all calls to cdecl even though this could slow Watcom code down * slightly. If you know that the Watcom compiler will be used to build both * the DLL and application, then you can probably define this as a null string. * Remember that pthread.h (this file) is used for both the DLL and application builds. */ #define PTW32_CDECL __cdecl #if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX # include #else /* * Generic handle type - intended to extend uniqueness beyond * that available with a simple pointer. It should scale for either * IA-32 or IA-64. */ typedef struct { void * p; /* Pointer to actual object */ unsigned int x; /* Extra information - reuse count etc */ } ptw32_handle_t; typedef ptw32_handle_t pthread_t; typedef struct pthread_attr_t_ * pthread_attr_t; typedef struct pthread_once_t_ pthread_once_t; typedef struct pthread_key_t_ * pthread_key_t; typedef struct pthread_mutex_t_ * pthread_mutex_t; typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; typedef struct pthread_cond_t_ * pthread_cond_t; typedef struct pthread_condattr_t_ * pthread_condattr_t; #endif typedef struct pthread_rwlock_t_ * pthread_rwlock_t; typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; typedef struct pthread_spinlock_t_ * pthread_spinlock_t; typedef struct pthread_barrier_t_ * pthread_barrier_t; typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; /* * ==================== * ==================== * POSIX Threads * ==================== * ==================== */ enum { /* * pthread_attr_{get,set}detachstate */ PTHREAD_CREATE_JOINABLE = 0, /* Default */ PTHREAD_CREATE_DETACHED = 1, /* * pthread_attr_{get,set}inheritsched */ PTHREAD_INHERIT_SCHED = 0, PTHREAD_EXPLICIT_SCHED = 1, /* Default */ /* * pthread_{get,set}scope */ PTHREAD_SCOPE_PROCESS = 0, PTHREAD_SCOPE_SYSTEM = 1, /* Default */ /* * pthread_setcancelstate paramters */ PTHREAD_CANCEL_ENABLE = 0, /* Default */ PTHREAD_CANCEL_DISABLE = 1, /* * pthread_setcanceltype parameters */ PTHREAD_CANCEL_ASYNCHRONOUS = 0, PTHREAD_CANCEL_DEFERRED = 1, /* Default */ /* * pthread_mutexattr_{get,set}pshared * pthread_condattr_{get,set}pshared */ PTHREAD_PROCESS_PRIVATE = 0, PTHREAD_PROCESS_SHARED = 1, /* * pthread_barrier_wait */ PTHREAD_BARRIER_SERIAL_THREAD = -1 }; /* * ==================== * ==================== * Cancelation * ==================== * ==================== */ #define PTHREAD_CANCELED ((void *) -1) /* * ==================== * ==================== * Once Key * ==================== * ==================== */ #define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} struct pthread_once_t_ { int done; /* indicates if user function has been executed */ void * lock; int reserved1; int reserved2; }; /* * ==================== * ==================== * Object initialisers * ==================== * ==================== */ #define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1) #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t) -2) #define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t) -3) /* * Compatibility with LinuxThreads */ #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER #define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER #define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1) #define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1) #define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1) /* * Mutex types. */ enum { /* Compatibility with LinuxThreads */ PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE_NP, PTHREAD_MUTEX_ERRORCHECK_NP, PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, /* For compatibility with POSIX */ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL }; typedef struct ptw32_cleanup_t ptw32_cleanup_t; #if defined(_MSC_VER) /* Disable MSVC 'anachronism used' warning */ #pragma warning( disable : 4229 ) #endif typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); #if defined(_MSC_VER) #pragma warning( default : 4229 ) #endif struct ptw32_cleanup_t { ptw32_cleanup_callback_t routine; void *arg; struct ptw32_cleanup_t *prev; }; #ifdef __CLEANUP_SEH /* * WIN32 SEH version of cancel cleanup. */ #define pthread_cleanup_push( _rout, _arg ) \ { \ ptw32_cleanup_t _cleanup; \ \ _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ _cleanup.arg = (_arg); \ __try \ { \ #define pthread_cleanup_pop( _execute ) \ } \ __finally \ { \ if( _execute || AbnormalTermination()) \ { \ (*(_cleanup.routine))( _cleanup.arg ); \ } \ } \ } #else /* __CLEANUP_SEH */ #ifdef __CLEANUP_C /* * C implementation of PThreads cancel cleanup */ #define pthread_cleanup_push( _rout, _arg ) \ { \ ptw32_cleanup_t _cleanup; \ \ ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ #define pthread_cleanup_pop( _execute ) \ (void) ptw32_pop_cleanup( _execute ); \ } #else /* __CLEANUP_C */ #ifdef __CLEANUP_CXX /* * C++ version of cancel cleanup. * - John E. Bossom. */ class PThreadCleanup { /* * PThreadCleanup * * Purpose * This class is a C++ helper class that is * used to implement pthread_cleanup_push/ * pthread_cleanup_pop. * The destructor of this class automatically * pops the pushed cleanup routine regardless * of how the code exits the scope * (i.e. such as by an exception) */ ptw32_cleanup_callback_t cleanUpRout; void * obj; int executeIt; public: PThreadCleanup() : cleanUpRout( 0 ), obj( 0 ), executeIt( 0 ) /* * No cleanup performed */ { } PThreadCleanup( ptw32_cleanup_callback_t routine, void * arg ) : cleanUpRout( routine ), obj( arg ), executeIt( 1 ) /* * Registers a cleanup routine for 'arg' */ { } ~PThreadCleanup() { if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) { (void) (*cleanUpRout)( obj ); } } void execute( int exec ) { executeIt = exec; } }; /* * C++ implementation of PThreads cancel cleanup; * This implementation takes advantage of a helper * class who's destructor automatically calls the * cleanup routine if we exit our scope weirdly */ #define pthread_cleanup_push( _rout, _arg ) \ { \ PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ (void *) (_arg) ); #define pthread_cleanup_pop( _execute ) \ cleanup.execute( _execute ); \ } #else #error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. #endif /* __CLEANUP_CXX */ #endif /* __CLEANUP_C */ #endif /* __CLEANUP_SEH */ /* * =============== * =============== * Methods * =============== * =============== */ /* * PThread Attribute Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, struct sched_param *param); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, const struct sched_param *param); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, int); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (pthread_attr_t *, int *); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, int inheritsched); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(pthread_attr_t * attr, int * inheritsched); PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, int); PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, int *); /* * PThread Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, const pthread_attr_t * attr, void *(*start) (void *), void *arg); PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, pthread_t t2); PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, void **value_ptr); PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, int *oldstate); PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, int *oldtype); PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, void (*init_routine) (void)); #if PTW32_LEVEL >= PTW32_LEVEL_MAX PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, void (*routine) (void *), void *arg); #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ /* * Thread Specific Data Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, void (*destructor) (void *)); PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, const void *value); PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); /* * Mutex Attribute Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind); /* * Barrier Attribute Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr, int *pshared); PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared); /* * Mutex Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); /* * Spinlock Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); /* * Barrier Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, const pthread_barrierattr_t * attr, unsigned int count); PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); /* * Condition Variable Attribute Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared); PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared); /* * Condition Variable Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec *abstime); PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); /* * Scheduling */ PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, int policy, const struct sched_param *param); PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, int *policy, struct sched_param *param); PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); /* * Read-Write Lock Functions */ PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, const pthread_rwlockattr_t *attr); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, const struct timespec *abstime); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, const struct timespec *abstime); PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, int *pshared); PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared); #if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 /* * Signal Functions. Should be defined in but MSVC and MinGW32 * already have signal.h that don't define these. */ PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); /* * Non-portable functions */ /* * Compatibility with Linux. */ PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, int kind); PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, int *kind); /* * Possibly supported by other POSIX threads implementations */ PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); /* * Useful if an application wants to statically link * the lib rather than load the DLL at run-time. */ PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); /* * Features that are auto-detected at load/run time. */ PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); enum ptw32_features { PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ }; /* * Register a system time change with the library. * Causes the library to perform various functions * in response to the change. Should be called whenever * the application's top level window receives a * WM_TIMECHANGE message. It can be passed directly to * pthread_create() as a new thread if desired. */ PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); #endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ #if PTW32_LEVEL >= PTW32_LEVEL_MAX /* * Returns the Win32 HANDLE for the POSIX thread. */ PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); /* * Protected Methods * * This function blocks until the given WIN32 handle * is signaled or pthread_cancel had been called. * This function allows the caller to hook into the * PThreads cancel mechanism. It is implemented using * * WaitForMultipleObjects * * on 'waitHandle' and a manually reset WIN32 Event * used to implement pthread_cancel. The 'timeout' * argument to TimedWait is simply passed to * WaitForMultipleObjects. */ PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ /* * Thread-Safe C Runtime Library Mappings. */ #ifndef _UWIN # if defined(NEED_ERRNO) PTW32_DLLPORT int * PTW32_CDECL _errno( void ); # else # ifndef errno # if (defined(_MT) || defined(_DLL)) __declspec(dllimport) extern int * __cdecl _errno(void); # define errno (*_errno()) # endif # endif # endif #endif /* * WIN32 C runtime library had been made thread-safe * without affecting the user interface. Provide * mappings from the UNIX thread-safe versions to * the standard C runtime library calls. * Only provide function mappings for functions that * actually exist on WIN32. */ #if !defined(__MINGW32__) #define strtok_r( _s, _sep, _lasts ) \ ( *(_lasts) = strtok( (_s), (_sep) ) ) #endif /* !__MINGW32__ */ #define asctime_r( _tm, _buf ) \ ( strcpy( (_buf), asctime( (_tm) ) ), \ (_buf) ) #define ctime_r( _clock, _buf ) \ ( strcpy( (_buf), ctime( (_clock) ) ), \ (_buf) ) #define gmtime_r( _clock, _result ) \ ( *(_result) = *gmtime( (_clock) ), \ (_result) ) #define localtime_r( _clock, _result ) \ ( *(_result) = *localtime( (_clock) ), \ (_result) ) #define rand_r( _seed ) \ ( _seed == _seed? rand() : rand() ) /* * Some compiler environments don't define some things. */ #if defined(__BORLANDC__) # define _ftime ftime # define _timeb timeb #endif #ifdef __cplusplus /* * Internal exceptions */ class ptw32_exception {}; class ptw32_exception_cancel : public ptw32_exception {}; class ptw32_exception_exit : public ptw32_exception {}; #endif #if PTW32_LEVEL >= PTW32_LEVEL_MAX /* FIXME: This is only required if the library was built using SEH */ /* * Get internal SEH tag */ PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ #ifndef PTW32_BUILD #ifdef __CLEANUP_SEH /* * Redefine the SEH __except keyword to ensure that applications * propagate our internal exceptions up to the library's internal handlers. */ #define __except( E ) \ __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) #endif /* __CLEANUP_SEH */ #ifdef __CLEANUP_CXX /* * Redefine the C++ catch keyword to ensure that applications * propagate our internal exceptions up to the library's internal handlers. */ #ifdef _MSC_VER /* * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' * if you want Pthread-Win32 cancelation and pthread_exit to work. */ #ifndef PtW32NoCatchWarn #pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") #pragma message("------------------------------------------------------------------") #pragma message("When compiling applications with MSVC++ and C++ exception handling:") #pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") #pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") #pragma message(" cancelation and pthread_exit to work. For example:") #pragma message("") #pragma message(" #ifdef PtW32CatchAll") #pragma message(" PtW32CatchAll") #pragma message(" #else") #pragma message(" catch(...)") #pragma message(" #endif") #pragma message(" {") #pragma message(" /* Catchall block processing */") #pragma message(" }") #pragma message("------------------------------------------------------------------") #endif #define PtW32CatchAll \ catch( ptw32_exception & ) { throw; } \ catch( ... ) #else /* _MSC_VER */ #define catch( E ) \ catch( ptw32_exception & ) { throw; } \ catch( E ) #endif /* _MSC_VER */ #endif /* __CLEANUP_CXX */ #endif /* ! PTW32_BUILD */ #ifdef __cplusplus } /* End of extern "C" */ #endif /* __cplusplus */ #ifdef PTW32__HANDLE_DEF # undef HANDLE #endif #ifdef PTW32__DWORD_DEF # undef DWORD #endif #undef PTW32_LEVEL #undef PTW32_LEVEL_MAX #endif /* ! RC_INVOKED */ #endif /* PTHREAD_H */ nyquist-3.05/liblo/pthreads.2/sched_get_priority_min.c0000644000175000000620000001453111512143043022131 0ustar stevestaff/* * sched_get_priority_min.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" /* * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. * * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: * highest priority use smaller numbers) and the following happens: * * sched_get_priority_min() returns 5 * sched_get_priority_max() returns 1 * * The following table shows the base priority levels for combinations * of priority class and priority value in Win32. * * Process Priority Class Thread Priority Level * ----------------------------------------------------------------- * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE * 17 REALTIME_PRIORITY_CLASS -7 * 18 REALTIME_PRIORITY_CLASS -6 * 19 REALTIME_PRIORITY_CLASS -5 * 20 REALTIME_PRIORITY_CLASS -4 * 21 REALTIME_PRIORITY_CLASS -3 * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST * 27 REALTIME_PRIORITY_CLASS 3 * 28 REALTIME_PRIORITY_CLASS 4 * 29 REALTIME_PRIORITY_CLASS 5 * 30 REALTIME_PRIORITY_CLASS 6 * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL * * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. * */ int sched_get_priority_min (int policy) { if (policy < SCHED_MIN || policy > SCHED_MAX) { errno = EINVAL; return -1; } #if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) /* WinCE? */ return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); #else /* This is independent of scheduling policy in Win32. */ return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); #endif } nyquist-3.05/liblo/pthreads.2/w32_CancelableWait.c0000644000175000000620000001107311512143043020727 0ustar stevestaff/* * w32_CancelableWait.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" static INLINE int ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) /* * ------------------------------------------------------------------- * This provides an extra hook into the pthread_cancel * mechanism that will allow you to wait on a Windows handle and make it a * cancellation point. This function blocks until the given WIN32 handle is * signaled or pthread_cancel has been called. It is implemented using * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32 * event used to implement pthread_cancel. * * Given this hook it would be possible to implement more of the cancellation * points. * ------------------------------------------------------------------- */ { int result; pthread_t self; ptw32_thread_t * sp; HANDLE handles[2]; DWORD nHandles = 1; DWORD status; handles[0] = waitHandle; self = pthread_self(); sp = (ptw32_thread_t *) self.p; if (sp != NULL) { /* * Get cancelEvent handle */ if (sp->cancelState == PTHREAD_CANCEL_ENABLE) { if ((handles[1] = sp->cancelEvent) != NULL) { nHandles++; } } } else { handles[1] = NULL; } status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout); switch (status - WAIT_OBJECT_0) { case 0: /* * Got the handle. * In the event that both handles are signalled, the smallest index * value (us) is returned. As it has been arranged, this ensures that * we don't drop a signal that we should act on (i.e. semaphore, * mutex, or condition variable etc). */ result = 0; break; case 1: /* * Got cancel request. * In the event that both handles are signaled, the cancel will * be ignored (see case 0 comment). */ ResetEvent (handles[1]); if (sp != NULL) { /* * Should handle POSIX and implicit POSIX threads.. * Make sure we haven't been async-canceled in the meantime. */ (void) pthread_mutex_lock (&sp->cancelLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } (void) pthread_mutex_unlock (&sp->cancelLock); } /* Should never get to here. */ result = EINVAL; break; default: if (status == WAIT_TIMEOUT) { result = ETIMEDOUT; } else { result = EINVAL; } break; } return (result); } /* CancelableWait */ int pthreadCancelableWait (HANDLE waitHandle) { return (ptw32_cancelable_wait (waitHandle, INFINITE)); } int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) { return (ptw32_cancelable_wait (waitHandle, timeout)); } nyquist-3.05/liblo/pthreads.2/sem_open.c0000644000175000000620000000406211512143043017203 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_open.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int sem_open (const char *name, int oflag, mode_t mode, unsigned int value) { errno = ENOSYS; return -1; } /* sem_open */ nyquist-3.05/liblo/pthreads.2/pthread_exit.c0000644000175000000620000000635411512143043020064 0ustar stevestaff/* * pthread_exit.c * * Description: * This translation unit implements routines associated with exiting from * a thread. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifndef _UWIN //# include #endif void pthread_exit (void *value_ptr) /* * ------------------------------------------------------ * DOCPUBLIC * This function terminates the calling thread, returning * the value 'value_ptr' to any joining thread. * * PARAMETERS * value_ptr * a generic data value (i.e. not the address of a value) * * * DESCRIPTION * This function terminates the calling thread, returning * the value 'value_ptr' to any joining thread. * NOTE: thread should be joinable. * * RESULTS * N/A * * ------------------------------------------------------ */ { ptw32_thread_t * sp; /* * Don't use pthread_self() to avoid creating an implicit POSIX thread handle * unnecessarily. */ sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); #ifdef _UWIN if (--pthread_count <= 0) exit ((int) value_ptr); #endif if (NULL == sp) { /* * A POSIX thread handle was never created. I.e. this is a * Win32 thread that has never called a pthreads-win32 routine that * required a POSIX handle. * * Implicit POSIX handles are cleaned up in ptw32_throw() now. */ #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) _endthreadex ((unsigned) value_ptr); #else _endthread (); #endif /* Never reached */ } sp->exitStatus = value_ptr; ptw32_throw (PTW32_EPS_EXIT); /* Never reached. */ } nyquist-3.05/liblo/pthreads.2/sem_close.c0000644000175000000620000000400411512143043017343 0ustar stevestaff/* * ------------------------------------------------------------- * * Module: sem_close.c * * Purpose: * Semaphores aren't actually part of the PThreads standard. * They are defined by the POSIX Standard: * * POSIX 1003.1b-1993 (POSIX.1b) * * ------------------------------------------------------------- * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "semaphore.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int sem_close (sem_t * sem) { errno = ENOSYS; return -1; } /* sem_close */ nyquist-3.05/liblo/pthreads.2/ptw32_processInitialize.c0000644000175000000620000000667711512143043022153 0ustar stevestaff/* * ptw32_processInitialize.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int ptw32_processInitialize (void) /* * ------------------------------------------------------ * DOCPRIVATE * This function performs process wide initialization for * the pthread library. * * PARAMETERS * N/A * * DESCRIPTION * This function performs process wide initialization for * the pthread library. * If successful, this routine sets the global variable * ptw32_processInitialized to TRUE. * * RESULTS * TRUE if successful, * FALSE otherwise * * ------------------------------------------------------ */ { if (ptw32_processInitialized) { /* * Ignore if already initialized. this is useful for * programs that uses a non-dll pthread * library. Such programs must call ptw32_processInitialize() explicitly, * since this initialization routine is automatically called only when * the dll is loaded. */ return PTW32_TRUE; } ptw32_processInitialized = PTW32_TRUE; /* * Initialize Keys */ if ((pthread_key_create (&ptw32_selfThreadKey, NULL) != 0) || (pthread_key_create (&ptw32_cleanupKey, NULL) != 0)) { ptw32_processTerminate (); } /* * Set up the global locks. */ InitializeCriticalSection (&ptw32_thread_reuse_lock); InitializeCriticalSection (&ptw32_mutex_test_init_lock); InitializeCriticalSection (&ptw32_cond_list_lock); InitializeCriticalSection (&ptw32_cond_test_init_lock); InitializeCriticalSection (&ptw32_rwlock_test_init_lock); InitializeCriticalSection (&ptw32_spinlock_test_init_lock); return (ptw32_processInitialized); } /* processInitialize */ nyquist-3.05/liblo/pthreads.2/builddmc.bat0000644000175000000620000000065411512143043017510 0ustar stevestaff; Build the pthreads library with the Digital Mars Compiler ; set DMCDIR=c:\dm ; RELEASE %DMCDIR%\bin\dmc -D_WIN32_WINNT -D_MT -DHAVE_CONFIG_H -I.;c:\dm\include -o+all -WD pthread.c user32.lib+kernel32.lib+wsock32.lib -L/impl -L/NODEBUG -L/SU:WINDOWS ; DEBUG %DMCDIR%\bin\dmc -g -D_WIN32_WINNT -D_MT -DHAVE_CONFIG_H -I.;c:\dm\include -o+all -WD pthread.c user32.lib+kernel32.lib+wsock32.lib -L/impl -L/SU:WINDOWS nyquist-3.05/liblo/pthreads.2/Bmakefile0000644000175000000620000001443111512143043017035 0ustar stevestaff# This makefile is compatible with BCB make. Use "make -fBMakefile" to compile. # # The variables $DLLDEST and $LIBDEST hold the destination directories for the # dll and the lib, respectively. Probably all that needs to change is $DEVROOT. # # Currently only the recommended pthreadBC.dll is built by this makefile. # DLL_VER = 2 DEVROOT = . DLLDEST = $(DEVROOT)\DLL LIBDEST = $(DEVROOT)\DLL DLLS = pthreadBC$(DLL_VER).dll OPTIM = /O2 RC = brcc32 RCFLAGS = -i. CFLAGS = /q /I. /D_WIN32_WINNT=0x400 /DHAVE_CONFIG_H=1 /4 /tWD /tWM \ /w-aus /w-asc /w-par #C cleanup code BCFLAGS = $(PTW32_FLAGS) $(CFLAGS) # Agregate modules for inlinability DLL_OBJS = \ attr.obj \ barrier.obj \ cancel.obj \ cleanup.obj \ condvar.obj \ create.obj \ dll.obj \ errno.obj \ exit.obj \ fork.obj \ global.obj \ misc.obj \ mutex.obj \ nonportable.obj \ private.obj \ rwlock.obj \ sched.obj \ semaphore.obj \ signal.obj \ spin.obj \ sync.obj \ tsd.obj INCL = config.h implement.h semaphore.h pthread.h need_errno.h ATTR_SRCS = \ pthread_attr_init.c \ pthread_attr_destroy.c \ pthread_attr_getdetachstate.c \ pthread_attr_setdetachstate.c \ pthread_attr_getstackaddr.c \ pthread_attr_setstackaddr.c \ pthread_attr_getstacksize.c \ pthread_attr_setstacksize.c \ pthread_attr_getscope.c \ pthread_attr_setscope.c BARRIER_SRCS = \ pthread_barrier_init.c \ pthread_barrier_destroy.c \ pthread_barrier_wait.c \ pthread_barrierattr_init.c \ pthread_barrierattr_destroy.c \ pthread_barrierattr_setpshared.c \ pthread_barrierattr_getpshared.c CANCEL_SRCS = \ pthread_setcancelstate.c \ pthread_setcanceltype.c \ pthread_testcancel.c \ pthread_cancel.c CONDVAR_SRCS = \ ptw32_cond_check_need_init.c \ pthread_condattr_destroy.c \ pthread_condattr_getpshared.c \ pthread_condattr_init.c \ pthread_condattr_setpshared.c \ pthread_cond_destroy.c \ pthread_cond_init.c \ pthread_cond_signal.c \ pthread_cond_wait.c EXIT_SRCS = \ pthread_exit.c MISC_SRCS = \ pthread_equal.c \ pthread_getconcurrency.c \ pthread_once.c \ pthread_self.c \ pthread_setconcurrency.c \ ptw32_calloc.c \ ptw32_MCS_lock.c \ ptw32_new.c \ w32_CancelableWait.c MUTEX_SRCS = \ ptw32_mutex_check_need_init.c \ pthread_mutex_init.c \ pthread_mutex_destroy.c \ pthread_mutexattr_init.c \ pthread_mutexattr_destroy.c \ pthread_mutexattr_getpshared.c \ pthread_mutexattr_setpshared.c \ pthread_mutexattr_settype.c \ pthread_mutexattr_gettype.c \ pthread_mutex_lock.c \ pthread_mutex_timedlock.c \ pthread_mutex_unlock.c \ pthread_mutex_trylock.c NONPORTABLE_SRCS = \ pthread_mutexattr_setkind_np.c \ pthread_mutexattr_getkind_np.c \ pthread_getw32threadhandle_np.c \ pthread_delay_np.c \ pthread_num_processors_np.c \ pthread_win32_attach_detach_np.c \ pthread_timechange_handler_np.c PRIVATE_SRCS = \ ptw32_is_attr.c \ ptw32_processInitialize.c \ ptw32_processTerminate.c \ ptw32_threadStart.c \ ptw32_threadDestroy.c \ ptw32_tkAssocCreate.c \ ptw32_tkAssocDestroy.c \ ptw32_callUserDestroyRoutines.c \ ptw32_timespec.c \ ptw32_relmillisecs.c \ ptw32_throw.c \ ptw32_InterlockedCompareExchange.c \ ptw32_getprocessors.c RWLOCK_SRCS = \ ptw32_rwlock_check_need_init.c \ ptw32_rwlock_cancelwrwait.c \ pthread_rwlock_init.c \ pthread_rwlock_destroy.c \ pthread_rwlockattr_init.c \ pthread_rwlockattr_destroy.c \ pthread_rwlockattr_getpshared.c \ pthread_rwlockattr_setpshared.c \ pthread_rwlock_rdlock.c \ pthread_rwlock_timedrdlock.c \ pthread_rwlock_wrlock.c \ pthread_rwlock_timedwrlock.c \ pthread_rwlock_unlock.c \ pthread_rwlock_tryrdlock.c \ pthread_rwlock_trywrlock.c SCHED_SRCS = \ pthread_attr_setschedpolicy.c \ pthread_attr_getschedpolicy.c \ pthread_attr_setschedparam.c \ pthread_attr_getschedparam.c \ pthread_attr_setinheritsched.c \ pthread_attr_getinheritsched.c \ pthread_setschedparam.c \ pthread_getschedparam.c \ sched_get_priority_max.c \ sched_get_priority_min.c \ sched_setscheduler.c \ sched_getscheduler.c \ sched_yield.c SEMAPHORE_SRCS = \ sem_init.c \ sem_destroy.c \ sem_trywait.c \ sem_timedwait.c \ sem_wait.c \ sem_post.c \ sem_post_multiple.c \ sem_getvalue.c \ sem_open.c \ sem_close.c \ sem_unlink.c SPIN_SRCS = \ ptw32_spinlock_check_need_init.c \ pthread_spin_init.c \ pthread_spin_destroy.c \ pthread_spin_lock.c \ pthread_spin_unlock.c \ pthread_spin_trylock.c SYNC_SRCS = \ pthread_detach.c \ pthread_join.c TSD_SRCS = \ pthread_key_create.c \ pthread_key_delete.c \ pthread_setspecific.c \ pthread_getspecific.c all: clean $(DLLS) realclean: clean if exist pthread*.dll del pthread*.dll if exist pthread*.lib del pthread*.lib if exist *.stamp del *.stamp clean: if exist *.obj del *.obj if exist *.ilk del *.ilk if exist *.ilc del *.ilc if exist *.ild del *.ild if exist *.ilf del *.ilf if exist *.ils del *.ils if exist *.tds del *.tds if exist *.pdb del *.pdb if exist *.exp del *.exp if exist *.map del *.map if exist *.o del *.o if exist *.i del *.i if exist *.res del *.res install: $(DLLS) copy pthread*.dll $(DLLDEST) copy pthread*.lib $(LIBDEST) $(DLLS): $(DLL_OBJS) version.res ilink32 /Tpd /Gi c0d32x.obj $(DLL_OBJS), \ $@, ,\ cw32mti.lib import32.lib, ,\ version.res .c.obj: $(CC) $(OPTIM) $(BCFLAGS) -c $< .rc.res: $(RC) $(RCFLAGS) $< attr.obj: attr.c $(ATTR_SRCS) $(INCL) barrier.obj: barrier.c $(BARRIER_SRCS) $(INCL) cancel.obj: cancel.c $(CANCEL_SRCS) $(INCL) condvar.obj: condvar.c $(CONDVAR_SRCS) $(INCL) exit.obj: exit.c $(EXIT_SRCS) $(INCL) misc.obj: misc.c $(MISC_SRCS) $(INCL) mutex.obj: mutex.c $(MUTEX_SRCS) $(INCL) nonportable.obj: nonportable.c $(NONPORTABLE_SRCS) $(INCL) private.obj: private.c $(PRIVATE_SRCS) $(INCL) rwlock.obj: rwlock.c $(RWLOCK_SRCS) $(INCL) sched.obj: sched.c $(SCHED_SRCS) $(INCL) semaphore.obj: semaphore.c $(SEMAPHORE_SRCS) $(INCL) spin.obj: spin.c $(SPIN_SRCS) $(INCL) sync.obj: sync.c $(SYNC_SRCS) $(INCL) tsd.obj: tsd.c $(TSD_SRCS) $(INCL) version.res: version.rc $(INCL) nyquist-3.05/liblo/pthreads.2/ptw32_throw.c0000644000175000000620000001020511512143043017574 0ustar stevestaff/* * ptw32_throw.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * ptw32_throw * * All canceled and explicitly exited POSIX threads go through * here. This routine knows how to exit both POSIX initiated threads and * 'implicit' POSIX threads for each of the possible language modes (C, * C++, and SEH). */ void ptw32_throw (DWORD exception) { /* * Don't use pthread_self() to avoid creating an implicit POSIX thread handle * unnecessarily. */ ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); #ifdef __CLEANUP_SEH DWORD exceptionInformation[3]; #endif if (exception != PTW32_EPS_CANCEL && exception != PTW32_EPS_EXIT) { /* Should never enter here */ exit (1); } if (NULL == sp || sp->implicit) { /* * We're inside a non-POSIX initialised Win32 thread * so there is no point to jump or throw back to. Just do an * explicit thread exit here after cleaning up POSIX * residue (i.e. cleanup handlers, POSIX thread handle etc). */ unsigned exitCode = 0; switch (exception) { case PTW32_EPS_CANCEL: exitCode = (unsigned) PTHREAD_CANCELED; break; case PTW32_EPS_EXIT: exitCode = (unsigned) sp->exitStatus;; break; } #if defined(PTW32_STATIC_LIB) pthread_win32_thread_detach_np (); #endif #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) _endthreadex (exitCode); #else _endthread (); #endif } #ifdef __CLEANUP_SEH exceptionInformation[0] = (DWORD) (exception); exceptionInformation[1] = (DWORD) (0); exceptionInformation[2] = (DWORD) (0); RaiseException (EXCEPTION_PTW32_SERVICES, 0, 3, exceptionInformation); #else /* __CLEANUP_SEH */ #ifdef __CLEANUP_C ptw32_pop_cleanup_all (1); longjmp (sp->start_mark, exception); #else /* __CLEANUP_C */ #ifdef __CLEANUP_CXX switch (exception) { case PTW32_EPS_CANCEL: throw ptw32_exception_cancel (); break; case PTW32_EPS_EXIT: throw ptw32_exception_exit (); break; } #else #error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. #endif /* __CLEANUP_CXX */ #endif /* __CLEANUP_C */ #endif /* __CLEANUP_SEH */ /* Never reached */ } void ptw32_pop_cleanup_all (int execute) { while (NULL != ptw32_pop_cleanup (execute)) { } } DWORD ptw32_get_exception_services_code (void) { #ifdef __CLEANUP_SEH return EXCEPTION_PTW32_SERVICES; #else return (DWORD) NULL; #endif } nyquist-3.05/liblo/pthreads.2/pthread_attr_getscope.c0000644000175000000620000000365211512143043021754 0ustar stevestaff/* * pthread_attr_getscope.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* ignore warning "unreferenced formal parameter" */ #ifdef _MSC_VER #pragma warning( disable : 4100 ) #endif int pthread_attr_getscope (const pthread_attr_t * attr, int *contentionscope) { #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING *contentionscope = (*attr)->contentionscope; return 0; #else return ENOSYS; #endif } nyquist-3.05/liblo/pthreads.2/ptw32_new.c0000644000175000000620000000531511512143043017230 0ustar stevestaff/* * ptw32_new.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" pthread_t ptw32_new (void) { pthread_t t; pthread_t nil = {NULL, 0}; ptw32_thread_t * tp; /* * If there's a reusable pthread_t then use it. */ t = ptw32_threadReusePop (); if (NULL != t.p) { tp = (ptw32_thread_t *) t.p; } else { /* No reuse threads available */ tp = (ptw32_thread_t *) calloc (1, sizeof(ptw32_thread_t)); if (tp == NULL) { return nil; } /* ptHandle.p needs to point to it's parent ptw32_thread_t. */ t.p = tp->ptHandle.p = tp; t.x = tp->ptHandle.x = 0; } /* Set default state. */ tp->sched_priority = THREAD_PRIORITY_NORMAL; tp->detachState = PTHREAD_CREATE_JOINABLE; tp->cancelState = PTHREAD_CANCEL_ENABLE; tp->cancelType = PTHREAD_CANCEL_DEFERRED; tp->cancelLock = PTHREAD_MUTEX_INITIALIZER; tp->threadLock = PTHREAD_MUTEX_INITIALIZER; tp->cancelEvent = CreateEvent (0, (int) PTW32_TRUE, /* manualReset */ (int) PTW32_FALSE, /* setSignaled */ NULL); if (tp->cancelEvent == NULL) { ptw32_threadReusePush (tp->ptHandle); return nil; } return t; } nyquist-3.05/liblo/pthreads.2/pthread_rwlockattr_init.c0000644000175000000620000000523011512143043022322 0ustar stevestaff/* * pthread_rwlockattr_init.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlockattr_init (pthread_rwlockattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Initializes a rwlock attributes object with default * attributes. * * PARAMETERS * attr * pointer to an instance of pthread_rwlockattr_t * * * DESCRIPTION * Initializes a rwlock attributes object with default * attributes. * * RESULTS * 0 successfully initialized attr, * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ { int result = 0; pthread_rwlockattr_t rwa; rwa = (pthread_rwlockattr_t) calloc (1, sizeof (*rwa)); if (rwa == NULL) { result = ENOMEM; } else { rwa->pshared = PTHREAD_PROCESS_PRIVATE; } *attr = rwa; return (result); } /* pthread_rwlockattr_init */ nyquist-3.05/liblo/pthreads.2/pthread_barrier_destroy.c0000644000175000000620000000420111512143043022277 0ustar stevestaff/* * pthread_barrier_destroy.c * * Description: * This translation unit implements barrier primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_barrier_destroy (pthread_barrier_t * barrier) { int result = 0; pthread_barrier_t b; if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } b = *barrier; *barrier = NULL; if (0 == (result = sem_destroy (&(b->semBarrierBreeched[0])))) { if (0 == (result = sem_destroy (&(b->semBarrierBreeched[1])))) { (void) free (b); return 0; } (void) sem_init (&(b->semBarrierBreeched[0]), b->pshared, 0); } *barrier = b; return (result); } nyquist-3.05/liblo/pthreads.2/pthread_rwlock_tryrdlock.c0000644000175000000620000000577011512143043022512 0ustar stevestaff/* * pthread_rwlock_tryrdlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_tryrdlock (pthread_rwlock_t * rwlock) { int result; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static rwlock. We check * again inside the guarded section of ptw32_rwlock_check_need_init() * to avoid race conditions. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = ptw32_rwlock_check_need_init (rwlock); if (result != 0 && result != EBUSY) { return result; } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) { return result; } if (++rwl->nSharedAccessCount == INT_MAX) { if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; if ((result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } } return (pthread_mutex_unlock (&rwl->mtxExclusiveAccess)); } nyquist-3.05/liblo/pthreads.2/Nmakefile0000644000175000000620000000142711512143043017052 0ustar stevestaff/* * nmake file for uwin pthread library */ VERSION = - CCFLAGS = -V -g $(CC.DLL) HAVE_CONFIG_H == 1 _MT == 1 _timeb == timeb _ftime == ftime _errno == _ast_errno $(INCLUDEDIR) :INSTALLDIR: pthread.h sched.h pthread $(VERSION) :LIBRARY: attr.c barrier.c cancel.c cleanup.c condvar.c \ create.c dll.c exit.c fork.c global.c misc.c mutex.c private.c \ rwlock.c sched.c semaphore.c spin.c sync.c tsd.c nonportable.c :: ANNOUNCE CONTRIBUTORS COPYING.LIB ChangeLog FAQ GNUmakefile MAINTAINERS \ Makefile Makefile.in Makefile.vc NEWS PROGRESS README README.WinCE \ TODO WinCE-PORT install-sh errno.c tests tests.mk acconfig.h \ config.guess config.h.in config.sub configure configure.in signal.c \ README.CV README.NONPORTABLE pthread.dsp pthread.dsw nyquist-3.05/liblo/pthreads.2/WinCE-PORT0000644000175000000620000001734011512143043016707 0ustar stevestaffNOTE: The comments in this file relate to the original WinCE port done by Tristan Savatier. The semaphore routines have been completely rewritten since (2005-04-25), having been progressively broken more and more by changes to the library. All of the semaphore routines implemented for W9x/WNT/2000 and up should now also work for WinCE. Also, pthread_mutex_timedlock should now work. [RPJ] ---- Some interesting news: I have been able to port pthread-win32 to Windows-CE, which uses a subset of the WIN32 API. Since we intend to keep using pthread-win32 for our Commercial WinCE developments, I would be very interested if WinCE support could be added to the main source tree of pthread-win32. Also, I would like to be credited for this port :-) Now, here is the story... The port was performed and tested on a Casio "Cassiopeia" PalmSize PC, which runs a MIP processor. The OS in the Casio is WinCE version 2.11, but I used VC++ 6.0 with the WinCE SDK for version 2.01. I used pthread-win32 to port a heavily multithreaded commercial application (real-time MPEG video player) from Linux to WinCE. I consider the changes that I have done to be quite well tested. Overall the modifications that we had to do are minor. The WinCE port were based on pthread-win32-snap-1999-05-30, but I am certain that they can be integrated very easiely to more recent versions of the source. I have attached the modified source code: pthread-win32-snap-1999-05-30-WinCE. All the changes do not affect the code compiled on non-WinCE environment, provided that the macros used for WinCE compilation are not used, of course! Overall description of the WinCE port: ------------------------------------- Most of the changes had to be made in areas where pthread-win32 was relying on some standard-C librairies (e.g. _ftime, calloc, errno), which are not available on WinCE. We have changed the code to use native Win32 API instead (or in some cases we made wrappers). The Win32 Semaphores are not available, so we had to re-implement Semaphores using mutexes and events. Limitations / known problems of the WinCE port: ---------------------------------------------- Not all the semaphore routines have been ported (semaphores are defined by Posix but are not part pf pthread). I have just done enough to make pthread routines (that rely internally on semaphores) work, like signal conditions. I noticed that the Win32 threads work slightly differently on WinCE. This may have some impact on some tricky parts of pthread-win32, but I have not really investigated. For example, on WinCE, the process is killed if the main thread falls off the bottom (or calls pthread_exit), regardless of the existence of any other detached thread. Microsoft manual indicates that this behavior is deffirent from that of Windows Threads for other Win32 platforms. Detailed descriptions of the changes and rationals: ------------------------------------ - use a new macro NEED_ERRNO. If defined, the code in errno.c that defines a reentrant errno is compiled, regardless of _MT and _REENTRANT. Rational: On WinCE, there is no support for , or any other standard C library, i.e. even if _MT or _REENTRANT is defined, errno is not provided by any library. NEED_ERRNO must be set to compile for WinCE. ------------------------------------ - In implement.h, change #include to #include "semaphore.h". Rational: semaphore.h is provided in pthread-win32 and should not be searched in the systems standard include. would not compile. This change does not seem to create problems on "classic" win32 (e.g. win95). ------------------------------------ - use a new macro NEED_CALLOC. If defined, some code in misc.c will provide a replacement for calloc, which is not available on Win32. ------------------------------------ - use a new macro NEED_CREATETHREAD. If defined, implement.h defines the macro _beginthreadex and _endthreadex. Rational: On WinCE, the wrappers _beginthreadex and _endthreadex do not exist. The native Win32 routines must be used. ------------------------------------ - in misc.c: #ifdef NEED_DUPLICATEHANDLE /* DuplicateHandle does not exist on WinCE */ self->threadH = GetCurrentThread(); #else if( !DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &self->threadH, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) { free( self ); return (NULL); } #endif Rational: On WinCE, DuplicateHandle does not exist. I could not understand why DuplicateHandle must be used. It seems to me that getting the current thread handle with GetCurrentThread() is sufficient, and it seems to work perfectly fine, so maybe DuplicateHandle was just plain useless to begin with ? ------------------------------------ - In private.c, added some code at the beginning of ptw32_processInitialize to detect the case of multiple calls to ptw32_processInitialize. Rational: In order to debug pthread-win32, it is easier to compile it as a regular library (it is not possible to debug DLL's on winCE). In that case, the application must call ptw32_rocessInitialize() explicitely, to initialize pthread-win32. It is safer in this circumstance to handle the case where ptw32_processInitialize() is called on an already initialized library: int ptw32_processInitialize (void) { if (ptw32_processInitialized) { /* * ignore if already initialized. this is useful for * programs that uses a non-dll pthread * library. such programs must call ptw32_processInitialize() explicitely, * since this initialization routine is automatically called only when * the dll is loaded. */ return TRUE; } ptw32_processInitialized = TRUE; [...] } ------------------------------------ - in private.c, if macro NEED_FTIME is defined, add routines to convert timespec_to_filetime and filetime_to_timespec, and modified code that was using _ftime() to use Win32 API instead. Rational: _ftime is not available on WinCE. It is necessary to use the native Win32 time API instead. Note: the routine timespec_to_filetime is provided as a convenience and a mean to test that filetime_to_timespec works, but it is not used by the library. ------------------------------------ - in semaphore.c, if macro NEED_SEM is defined, add code for the routines _increase_semaphore and _decrease_semaphore, and modify significantly the implementation of the semaphores so that it does not use CreateSemaphore. Rational: CreateSemaphore is not available on WinCE. I had to re-implement semaphores using mutexes and Events. Note: Only the semaphore routines that are used by pthread are implemented (i.e. signal conditions rely on a subset of the semaphores routines, and this subset works). Some other semaphore routines (e.g. sem_trywait) are not yet supported on my WinCE port (and since I don't need them, I am not planning to do anything about them). ------------------------------------ - in tsd.c, changed the code that defines TLS_OUT_OF_INDEXES /* TLS_OUT_OF_INDEXES not defined on WinCE */ #ifndef TLS_OUT_OF_INDEXES #define TLS_OUT_OF_INDEXES 0xffffffff #endif Rational: TLS_OUT_OF_INDEXES is not defined in any standard include file on WinCE. ------------------------------------ - added file need_errno.h Rational: On WinCE, there is no errno.h file. need_errno.h is just a copy of windows version of errno.h, with minor modifications due to the fact that some of the error codes are defined by the WinCE socket library. In pthread.h, if NEED_ERRNO is defined, the file need_errno.h is included (instead of ). -- eof nyquist-3.05/liblo/pthreads.2/pthread_attr_getdetachstate.c0000644000175000000620000000614211512143043023131 0ustar stevestaff/* * pthread_attr_getdetachstate.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate) /* * ------------------------------------------------------ * DOCPUBLIC * This function determines whether threads created with * 'attr' will run detached. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * detachstate * pointer to an integer into which is returned one * of: * * PTHREAD_CREATE_JOINABLE * Thread ID is valid, must be joined * * PTHREAD_CREATE_DETACHED * Thread ID is invalid, cannot be joined, * canceled, or modified * * * DESCRIPTION * This function determines whether threads created with * 'attr' will run detached. * * NOTES: * 1) You cannot join or cancel detached threads. * * RESULTS * 0 successfully retrieved detach state, * EINVAL 'attr' is invalid * * ------------------------------------------------------ */ { if (ptw32_is_attr (attr) != 0 || detachstate == NULL) { *detachstate = PTHREAD_CREATE_DETACHED; return EINVAL; } *detachstate = (*attr)->detachstate; return 0; } nyquist-3.05/liblo/pthreads.2/ptw32_threadDestroy.c0000644000175000000620000000524311512143043021260 0ustar stevestaff/* * ptw32_threadDestroy.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" void ptw32_threadDestroy (pthread_t thread) { ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; ptw32_thread_t threadCopy; if (tp != NULL) { /* * Copy thread state so that the thread can be atomically NULLed. */ memcpy (&threadCopy, tp, sizeof (threadCopy)); /* * Thread ID structs are never freed. They're NULLed and reused. * This also sets the thread to PThreadStateInitial (invalid). */ ptw32_threadReusePush (thread); /* Now work on the copy. */ if (threadCopy.cancelEvent != NULL) { CloseHandle (threadCopy.cancelEvent); } (void) pthread_mutex_destroy(&threadCopy.cancelLock); (void) pthread_mutex_destroy(&threadCopy.threadLock); #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) /* * See documentation for endthread vs endthreadex. */ if (threadCopy.threadH != 0) { CloseHandle (threadCopy.threadH); } #endif } } /* ptw32_threadDestroy */ nyquist-3.05/liblo/pthreads.2/ptw32_mutex_check_need_init.c0000644000175000000620000001004411512143043022747 0ustar stevestaff/* * ptw32_mutex_check_need_init.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" static struct pthread_mutexattr_t_ ptw32_recursive_mutexattr_s = {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_RECURSIVE}; static struct pthread_mutexattr_t_ ptw32_errorcheck_mutexattr_s = {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_ERRORCHECK}; static pthread_mutexattr_t ptw32_recursive_mutexattr = &ptw32_recursive_mutexattr_s; static pthread_mutexattr_t ptw32_errorcheck_mutexattr = &ptw32_errorcheck_mutexattr_s; INLINE int ptw32_mutex_check_need_init (pthread_mutex_t * mutex) { register int result = 0; register pthread_mutex_t mtx; /* * The following guarded test is specifically for statically * initialised mutexes (via PTHREAD_MUTEX_INITIALIZER). * * Note that by not providing this synchronisation we risk * introducing race conditions into applications which are * correctly written. * * Approach * -------- * We know that static mutexes will not be PROCESS_SHARED * so we can serialise access to internal state using * Win32 Critical Sections rather than Win32 Mutexes. * * If using a single global lock slows applications down too much, * multiple global locks could be created and hashed on some random * value associated with each mutex, the pointer perhaps. At a guess, * a good value for the optimal number of global locks might be * the number of processors + 1. * */ EnterCriticalSection (&ptw32_mutex_test_init_lock); /* * We got here possibly under race * conditions. Check again inside the critical section * and only initialise if the mutex is valid (not been destroyed). * If a static mutex has been destroyed, the application can * re-initialise it only by calling pthread_mutex_init() * explicitly. */ mtx = *mutex; if (mtx == PTHREAD_MUTEX_INITIALIZER) { result = pthread_mutex_init (mutex, NULL); } else if (mtx == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) { result = pthread_mutex_init (mutex, &ptw32_recursive_mutexattr); } else if (mtx == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { result = pthread_mutex_init (mutex, &ptw32_errorcheck_mutexattr); } else if (mtx == NULL) { /* * The mutex has been destroyed while we were waiting to * initialise it, so the operation that caused the * auto-initialisation should fail. */ result = EINVAL; } LeaveCriticalSection (&ptw32_mutex_test_init_lock); return (result); } nyquist-3.05/liblo/pthreads.2/pthread_condattr_init.c0000644000175000000620000000572511512143043021755 0ustar stevestaff/* * pthread_condattr_init.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_condattr_init (pthread_condattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Initializes a condition variable attributes object * with default attributes. * * PARAMETERS * attr * pointer to an instance of pthread_condattr_t * * * DESCRIPTION * Initializes a condition variable attributes object * with default attributes. * * NOTES: * 1) Use to define condition variable types * 2) It is up to the application to ensure * that it doesn't re-init an attribute * without destroying it first. Otherwise * a memory leak is created. * * RESULTS * 0 successfully initialized attr, * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ { pthread_condattr_t attr_result; int result = 0; attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result)); if (attr_result == NULL) { result = ENOMEM; } *attr = attr_result; return result; } /* pthread_condattr_init */ nyquist-3.05/liblo/pthreads.2/pthread_attr_setstacksize.c0000644000175000000620000000700611512143043022654 0ustar stevestaff/* * pthread_attr_setstacksize.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize) /* * ------------------------------------------------------ * DOCPUBLIC * This function specifies the size of the stack on * which threads created with 'attr' will run. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * stacksize * stack size, in bytes. * * * DESCRIPTION * This function specifies the size of the stack on * which threads created with 'attr' will run. * * NOTES: * 1) Function supported only if this macro is * defined: * * _POSIX_THREAD_ATTR_STACKSIZE * * 2) Find the default first (using * pthread_attr_getstacksize), then increase * by multiplying. * * 3) Only use if thread needs more than the * default. * * RESULTS * 0 successfully set stack size, * EINVAL 'attr' is invalid or stacksize too * small or too big. * ENOSYS function not supported * * ------------------------------------------------------ */ { #ifdef _POSIX_THREAD_ATTR_STACKSIZE #if PTHREAD_STACK_MIN > 0 /* Verify that the stack size is within range. */ if (stacksize < PTHREAD_STACK_MIN) { return EINVAL; } #endif if (ptw32_is_attr (attr) != 0) { return EINVAL; } /* Everything is okay. */ (*attr)->stacksize = stacksize; return 0; #else return ENOSYS; #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ } nyquist-3.05/liblo/pthreads.2/pthread_once.c0000644000175000000620000000510011512143043020023 0ustar stevestaff/* * pthread_once.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" static void PTW32_CDECL ptw32_once_on_init_cancel (void * arg) { /* when the initting thread is cancelled we have to release the lock */ ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)arg; ptw32_mcs_lock_release(node); } int pthread_once (pthread_once_t * once_control, void (*init_routine) (void)) { if (once_control == NULL || init_routine == NULL) { return EINVAL; } if (!InterlockedExchangeAdd((LPLONG)&once_control->done, 0)) /* MBR fence */ { ptw32_mcs_local_node_t node; ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node); if (!once_control->done) { #ifdef _MSC_VER #pragma inline_depth(0) #endif pthread_cleanup_push(ptw32_once_on_init_cancel, (void *)&node); (*init_routine)(); pthread_cleanup_pop(0); #ifdef _MSC_VER #pragma inline_depth() #endif once_control->done = PTW32_TRUE; } ptw32_mcs_lock_release(&node); } return 0; } /* pthread_once */ nyquist-3.05/liblo/pthreads.2/ptw32_rwlock_check_need_init.c0000644000175000000620000000646011512143043023115 0ustar stevestaff/* * pthread_rwlock_check_need_init.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" INLINE int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock) { int result = 0; /* * The following guarded test is specifically for statically * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER). * * Note that by not providing this synchronisation we risk * introducing race conditions into applications which are * correctly written. * * Approach * -------- * We know that static rwlocks will not be PROCESS_SHARED * so we can serialise access to internal state using * Win32 Critical Sections rather than Win32 Mutexes. * * If using a single global lock slows applications down too much, * multiple global locks could be created and hashed on some random * value associated with each mutex, the pointer perhaps. At a guess, * a good value for the optimal number of global locks might be * the number of processors + 1. * */ EnterCriticalSection (&ptw32_rwlock_test_init_lock); /* * We got here possibly under race * conditions. Check again inside the critical section * and only initialise if the rwlock is valid (not been destroyed). * If a static rwlock has been destroyed, the application can * re-initialise it only by calling pthread_rwlock_init() * explicitly. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = pthread_rwlock_init (rwlock, NULL); } else if (*rwlock == NULL) { /* * The rwlock has been destroyed while we were waiting to * initialise it, so the operation that caused the * auto-initialisation should fail. */ result = EINVAL; } LeaveCriticalSection (&ptw32_rwlock_test_init_lock); return result; } nyquist-3.05/liblo/pthreads.2/tsd.c0000644000175000000620000000331011512143043016163 0ustar stevestaff/* * tsd.c * * Description: * POSIX thread functions which implement thread-specific data (TSD). * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_key_create.c" #include "pthread_key_delete.c" #include "pthread_setspecific.c" #include "pthread_getspecific.c" nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_gettype.c0000644000175000000620000000354411512143043022707 0ustar stevestaff/* * pthread_mutexattr_gettype.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind) { int result = 0; if (attr != NULL && *attr != NULL && kind != NULL) { *kind = (*attr)->kind; } else { result = EINVAL; } return (result); } nyquist-3.05/liblo/pthreads.2/pthread_spin_destroy.c0000644000175000000620000000634011512143043021630 0ustar stevestaff/* * pthread_spin_destroy.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_spin_destroy (pthread_spinlock_t * lock) { register pthread_spinlock_t s; int result = 0; if (lock == NULL || *lock == NULL) { return EINVAL; } if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER) { if (s->interlock == PTW32_SPIN_USE_MUTEX) { result = pthread_mutex_destroy (&(s->u.mutex)); } else if ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED != PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & (s->interlock), (PTW32_INTERLOCKED_LONG) PTW32_OBJECT_INVALID, (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED)) { result = EINVAL; } if (0 == result) { /* * We are relying on the application to ensure that all other threads * have finished with the spinlock before destroying it. */ *lock = NULL; (void) free (s); } } else { /* * See notes in ptw32_spinlock_check_need_init() above also. */ EnterCriticalSection (&ptw32_spinlock_test_init_lock); /* * Check again. */ if (*lock == PTHREAD_SPINLOCK_INITIALIZER) { /* * This is all we need to do to destroy a statically * initialised spinlock that has not yet been used (initialised). * If we get to here, another thread * waiting to initialise this mutex will get an EINVAL. */ *lock = NULL; } else { /* * The spinlock has been initialised while we were waiting * so assume it's in use. */ result = EBUSY; } LeaveCriticalSection (&ptw32_spinlock_test_init_lock); } return (result); } nyquist-3.05/liblo/pthreads.2/pthread_timechange_handler_np.c0000644000175000000620000000764511512143043023415 0ustar stevestaff/* * pthread_timechange_handler_np.c * * Description: * This translation unit implements miscellaneous thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" /* * Notes on handling system time adjustments (especially negative ones). * --------------------------------------------------------------------- * * This solution was suggested by Alexander Terekhov, but any errors * in the implementation are mine - [Ross Johnson] * * 1) The problem: threads doing a timedwait on a CV may expect to timeout * at a specific absolute time according to a system timer. If the * system clock is adjusted backwards then those threads sleep longer than * expected. Also, pthreads-win32 converts absolute times to intervals in * order to make use of the underlying Win32, and so waiting threads may * awake before their proper abstimes. * * 2) We aren't able to distinquish between threads on timed or untimed waits, * so we wake them all at the time of the adjustment so that they can * re-evaluate their conditions and re-compute their timeouts. * * 3) We rely on correctly written applications for this to work. Specifically, * they must be able to deal properly with spurious wakeups. That is, * they must re-test their condition upon wakeup and wait again if * the condition is not satisfied. */ void * pthread_timechange_handler_np (void *arg) /* * ------------------------------------------------------ * DOCPUBLIC * Broadcasts all CVs to force re-evaluation and * new timeouts if required. * * PARAMETERS * NONE * * * DESCRIPTION * Broadcasts all CVs to force re-evaluation and * new timeouts if required. * * This routine may be passed directly to pthread_create() * as a new thread in order to run asynchronously. * * * RESULTS * 0 successfully broadcast all CVs * EAGAIN Not all CVs were broadcast * * ------------------------------------------------------ */ { int result = 0; pthread_cond_t cv; EnterCriticalSection (&ptw32_cond_list_lock); cv = ptw32_cond_list_head; while (cv != NULL && 0 == result) { result = pthread_cond_broadcast (&cv); cv = cv->next; } LeaveCriticalSection (&ptw32_cond_list_lock); return (void *) (result != 0 ? EAGAIN : 0); } nyquist-3.05/liblo/pthreads.2/pthread_spin_unlock.c0000644000175000000620000000445111512143043021433 0ustar stevestaff/* * pthread_spin_unlock.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_spin_unlock (pthread_spinlock_t * lock) { register pthread_spinlock_t s; if (NULL == lock || NULL == *lock) { return (EINVAL); } s = *lock; if (s == PTHREAD_SPINLOCK_INITIALIZER) { return EPERM; } switch ((long) PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) & (s->interlock), (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED, (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED)) { case PTW32_SPIN_LOCKED: return 0; case PTW32_SPIN_UNLOCKED: return EPERM; case PTW32_SPIN_USE_MUTEX: return pthread_mutex_unlock (&(s->u.mutex)); } return EINVAL; } nyquist-3.05/liblo/pthreads.2/nonportable.c0000644000175000000620000000354711512143043017730 0ustar stevestaff/* * nonportable.c * * Description: * This translation unit implements non-portable thread functions. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "pthread_mutexattr_setkind_np.c" #include "pthread_mutexattr_getkind_np.c" #include "pthread_getw32threadhandle_np.c" #include "pthread_delay_np.c" #include "pthread_num_processors_np.c" #include "pthread_win32_attach_detach_np.c" #include "pthread_timechange_handler_np.c" nyquist-3.05/liblo/pthreads.2/ptw32_callUserDestroyRoutines.c0000644000175000000620000001541411512143043023315 0ustar stevestaff/* * ptw32_callUserDestroyRoutines.c * * Description: * This translation unit implements routines which are private to * the implementation and may be used throughout it. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #ifdef __cplusplus # if ! defined (_MSC_VER) && ! (defined(__GNUC__) && __GNUC__ < 3) && ! defined(__WATCOMC__) using std::terminate; # endif #endif void ptw32_callUserDestroyRoutines (pthread_t thread) /* * ------------------------------------------------------------------- * DOCPRIVATE * * This the routine runs through all thread keys and calls * the destroy routines on the user's data for the current thread. * It simulates the behaviour of POSIX Threads. * * PARAMETERS * thread * an instance of pthread_t * * RETURNS * N/A * ------------------------------------------------------------------- */ { ThreadKeyAssoc * assoc; if (thread.p != NULL) { int assocsRemaining; int iterations = 0; ptw32_thread_t * sp = (ptw32_thread_t *) thread.p; /* * Run through all Thread<-->Key associations * for the current thread. * * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. */ do { assocsRemaining = 0; iterations++; (void) pthread_mutex_lock(&(sp->threadLock)); /* * The pointer to the next assoc is stored in the thread struct so that * the assoc destructor in pthread_key_delete can adjust it * if it deletes this assoc. This can happen if we fail to acquire * both locks below, and are forced to release all of our locks, * leaving open the opportunity for pthread_key_delete to get in * before us. */ sp->nextAssoc = sp->keys; (void) pthread_mutex_unlock(&(sp->threadLock)); for (;;) { void * value; pthread_key_t k; void (*destructor) (void *); /* * First we need to serialise with pthread_key_delete by locking * both assoc guards, but in the reverse order to our convention, * so we must be careful to avoid deadlock. */ (void) pthread_mutex_lock(&(sp->threadLock)); if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) { /* Finished */ pthread_mutex_unlock(&(sp->threadLock)); break; } else { /* * assoc->key must be valid because assoc can't change or be * removed from our chain while we hold at least one lock. If * the assoc was on our key chain then the key has not been * deleted yet. * * Now try to acquire the second lock without deadlocking. * If we fail, we need to relinquish the first lock and the * processor and then try to acquire them all again. */ if (pthread_mutex_trylock(&(assoc->key->keyLock)) == EBUSY) { pthread_mutex_unlock(&(sp->threadLock)); Sleep(1); // Ugly but necessary to avoid priority effects. /* * Go around again. * If pthread_key_delete has removed this assoc in the meantime, * sp->nextAssoc will point to a new assoc. */ continue; } } /* We now hold both locks */ sp->nextAssoc = assoc->nextKey; /* * Key still active; pthread_key_delete * will block on these same mutexes before * it can release actual key; therefore, * key is valid and we can call the destroy * routine; */ k = assoc->key; destructor = k->destructor; value = TlsGetValue(k->key); TlsSetValue (k->key, NULL); // Every assoc->key exists and has a destructor if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) { /* * Unlock both locks before the destructor runs. * POSIX says pthread_key_delete can be run from destructors, * and that probably includes with this key as target. * pthread_setspecific can also be run from destructors and * also needs to be able to access the assocs. */ (void) pthread_mutex_unlock(&(sp->threadLock)); (void) pthread_mutex_unlock(&(k->keyLock)); assocsRemaining++; #ifdef __cplusplus try { /* * Run the caller's cleanup routine. */ destructor (value); } catch (...) { /* * A system unexpected exception has occurred * running the user's destructor. * We get control back within this block in case * the application has set up it's own terminate * handler. Since we are leaving the thread we * should not get any internal pthreads * exceptions. */ terminate (); } #else /* __cplusplus */ /* * Run the caller's cleanup routine. */ destructor (value); #endif /* __cplusplus */ } else { /* * Remove association from both the key and thread chains * and reclaim it's memory resources. */ ptw32_tkAssocDestroy (assoc); (void) pthread_mutex_unlock(&(sp->threadLock)); (void) pthread_mutex_unlock(&(k->keyLock)); } } } while (assocsRemaining); } } /* ptw32_callUserDestroyRoutines */ nyquist-3.05/liblo/pthreads.2/pthread_mutex_trylock.c0000644000175000000620000000525411512143043022022 0ustar stevestaff/* * pthread_mutex_trylock.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutex_trylock (pthread_mutex_t * mutex) { int result = 0; pthread_mutex_t mx; /* * Let the system deal with invalid pointers. */ /* * We do a quick check to see if we need to do more work * to initialise a static mutex. We check * again inside the guarded section of ptw32_mutex_check_need_init() * to avoid race conditions. */ if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) { if ((result = ptw32_mutex_check_need_init (mutex)) != 0) { return (result); } } mx = *mutex; if (0 == (LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE ( (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, (PTW32_INTERLOCKED_LONG) 1, (PTW32_INTERLOCKED_LONG) 0)) { if (mx->kind != PTHREAD_MUTEX_NORMAL) { mx->recursive_count = 1; mx->ownerThread = pthread_self (); } } else { if (mx->kind == PTHREAD_MUTEX_RECURSIVE && pthread_equal (mx->ownerThread, pthread_self ())) { mx->recursive_count++; } else { result = EBUSY; } } return (result); } nyquist-3.05/liblo/pthreads.2/need_errno.h0000644000175000000620000000547711512143043017536 0ustar stevestaff/*** * errno.h - system wide error numbers (set by system calls) * * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. * * Purpose: * This file defines the system-wide error numbers (set by * system calls). Conforms to the XENIX standard. Extended * for compatibility with Uniforum standard. * [System V] * * [Public] * ****/ #if _MSC_VER > 1000 #pragma once #endif #ifndef _INC_ERRNO #define _INC_ERRNO #if !defined(_WIN32) && !defined(_MAC) #error ERROR: Only Mac or Win32 targets supported! #endif #include #ifdef __cplusplus extern "C" { #endif /* Define _CRTIMP */ #ifndef _CRTIMP #ifdef _DLL #define _CRTIMP __declspec(dllimport) #else /* ndef _DLL */ #define _CRTIMP #endif /* _DLL */ #endif /* _CRTIMP */ /* Define __cdecl for non-Microsoft compilers */ #if ( !defined(_MSC_VER) && !defined(__cdecl) ) #define __cdecl #endif /* Define _CRTAPI1 (for compatibility with the NT SDK) */ #ifndef _CRTAPI1 #if _MSC_VER >= 800 && _M_IX86 >= 300 #define _CRTAPI1 __cdecl #else #define _CRTAPI1 #endif #endif /* declare reference to errno */ #if (defined(_MT) || defined(_MD) || defined(_DLL)) && !defined(_MAC) _CRTIMP extern int * __cdecl _errno(void); #define errno (*_errno()) #else /* ndef _MT && ndef _MD && ndef _DLL */ _CRTIMP extern int errno; #endif /* _MT || _MD || _DLL */ /* Error Codes */ #define EPERM 1 #define ENOENT 2 #define ESRCH 3 #define EINTR 4 #define EIO 5 #define ENXIO 6 #define E2BIG 7 #define ENOEXEC 8 #define EBADF 9 #define ECHILD 10 #define EAGAIN 11 #define ENOMEM 12 #define EACCES 13 #define EFAULT 14 #define EBUSY 16 #define EEXIST 17 #define EXDEV 18 #define ENODEV 19 #define ENOTDIR 20 #define EISDIR 21 #define EINVAL 22 #define ENFILE 23 #define EMFILE 24 #define ENOTTY 25 #define EFBIG 27 #define ENOSPC 28 #define ESPIPE 29 #define EROFS 30 #define EMLINK 31 #define EPIPE 32 #define EDOM 33 #define ERANGE 34 #define EDEADLK 36 /* defined differently in winsock.h on WinCE */ #ifndef ENAMETOOLONG #define ENAMETOOLONG 38 #endif #define ENOLCK 39 #define ENOSYS 40 /* defined differently in winsock.h on WinCE */ #ifndef ENOTEMPTY #define ENOTEMPTY 41 #endif #define EILSEQ 42 /* * Support EDEADLOCK for compatibiity with older MS-C versions. */ #define EDEADLOCK EDEADLK #ifdef __cplusplus } #endif #endif /* _INC_ERRNO */ nyquist-3.05/liblo/pthreads.2/sched_setscheduler.c0000644000175000000620000000476411512143043021247 0ustar stevestaff/* * sched_setscheduler.c * * Description: * POSIX thread functions that deal with thread scheduling. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "sched.h" int sched_setscheduler (pid_t pid, int policy) { /* * Win32 only has one policy which we call SCHED_OTHER. * However, we try to provide other valid side-effects * such as EPERM and ESRCH errors. Choosing to check * for a valid policy last allows us to get the most value out * of this function. */ if (0 != pid) { int selfPid = (int) GetCurrentProcessId (); if (pid != selfPid) { HANDLE h = OpenProcess (PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) pid); if (NULL == h) { errno = (GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; return -1; } } } if (SCHED_OTHER != policy) { errno = ENOSYS; return -1; } /* * Don't set anything because there is nothing to set. * Just return the current (the only possible) value. */ return SCHED_OTHER; } nyquist-3.05/liblo/pthreads.2/pthread_rwlock_trywrlock.c0000644000175000000620000000652611512143043022535 0ustar stevestaff/* * pthread_rwlock_trywrlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_trywrlock (pthread_rwlock_t * rwlock) { int result, result1; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static rwlock. We check * again inside the guarded section of ptw32_rwlock_check_need_init() * to avoid race conditions. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = ptw32_rwlock_check_need_init (rwlock); if (result != 0 && result != EBUSY) { return result; } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) { return result; } if ((result = pthread_mutex_trylock (&(rwl->mtxSharedAccessCompleted))) != 0) { result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return ((result1 != 0) ? result1 : result); } if (rwl->nExclusiveAccessCount == 0) { if (rwl->nCompletedSharedAccessCount > 0) { rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; } if (rwl->nSharedAccessCount > 0) { if ((result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } if ((result = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) == 0) { result = EBUSY; } } else { rwl->nExclusiveAccessCount = 1; } } else { result = EBUSY; } return result; } nyquist-3.05/liblo/pthreads.2/README0000644000175000000620000005377011512143043016124 0ustar stevestaffPTHREADS-WIN32 ============== Pthreads-win32 is free software, distributed under the GNU Lesser General Public License (LGPL). See the file 'COPYING.LIB' for terms and conditions. Also see the file 'COPYING' for information specific to pthreads-win32, copyrights and the LGPL. What is it? ----------- Pthreads-win32 is an Open Source Software implementation of the Threads component of the POSIX 1003.1c 1995 Standard (or later) for Microsoft's Win32 environment. Some functions from POSIX 1003.1b are also supported including semaphores. Other related functions include the set of read-write lock functions. The library also supports some of the functionality of the Open Group's Single Unix specification, version 2, namely mutex types, plus some common and pthreads-win32 specific non-portable routines (see README.NONPORTABLE). See the file "ANNOUNCE" for more information including standards conformance details and the list of supported and unsupported routines. Prerequisites ------------- MSVC or GNU C (MinGW32 MSys development kit) To build from source. QueueUserAPCEx by Panagiotis E. Hadjidoukas For true async cancelation of threads (including blocked threads). This is a DLL and Windows driver that provides pre-emptive APC by forcing threads into an alertable state when the APC is queued. Both the DLL and driver are provided with the pthreads-win32.exe self-unpacking ZIP, and on the pthreads-win32 FTP site (in source and pre-built forms). Currently this is a separate LGPL package to pthreads-win32. See the README in the QueueUserAPCEx folder for installation instructions. Pthreads-win32 will automatically detect if the QueueUserAPCEx DLL QuserEx.DLL is available and whether the driver AlertDrv.sys is loaded. If it is not available, pthreads-win32 will simulate async cancelation, which means that it can async cancel only threads that are runnable. The simulated async cancellation cannot cancel blocked threads. Library naming -------------- Because the library is being built using various exception handling schemes and compilers - and because the library may not work reliably if these are mixed in an application, each different version of the library has it's own name. Note 1: the incompatibility is really between EH implementations of the different compilers. It should be possible to use the standard C version from either compiler with C++ applications built with a different compiler. If you use an EH version of the library, then you must use the same compiler for the application. This is another complication and dependency that can be avoided by using only the standard C library version. Note 2: if you use a standard C pthread*.dll with a C++ application, then any functions that you define that are intended to be called via pthread_cleanup_push() must be __cdecl. Note 3: the intention was to also name either the VC or GC version (it should be arbitrary) as pthread.dll, including pthread.lib and libpthread.a as appropriate. This is no longer likely to happen. Note 4: the compatibility number was added so that applications can differentiate between binary incompatible versions of the libs and dlls. In general: pthread[VG]{SE,CE,C}c.dll pthread[VG]{SE,CE,C}c.lib where: [VG] indicates the compiler V - MS VC, or G - GNU C {SE,CE,C} indicates the exception handling scheme SE - Structured EH, or CE - C++ EH, or C - no exceptions - uses setjmp/longjmp c - DLL compatibility number indicating ABI and API compatibility with applications built against any snapshot with the same compatibility number. See 'Version numbering' below. The name may also be suffixed by a 'd' to indicate a debugging version of the library. E.g. pthreadVC2d.lib. Debugging versions contain additional information for debugging (symbols etc) and are often not optimised in any way (compiled with optimisation turned off). For example: pthreadVSE.dll (MSVC/SEH) pthreadGCE.dll (GNUC/C++ EH) pthreadGC.dll (GNUC/not dependent on exceptions) pthreadVC1.dll (MSVC/not dependent on exceptions - not binary compatible with pthreadVC.dll) pthreadVC2.dll (MSVC/not dependent on exceptions - not binary compatible with pthreadVC1.dll or pthreadVC.dll) The GNU library archive file names have correspondingly changed to: libpthreadGCEc.a libpthreadGCc.a Versioning numbering -------------------- Version numbering is separate from the snapshot dating system, and is the canonical version identification system embedded within the DLL using the Microsoft version resource system. The versioning system chosen follows the GNU Libtool system. See http://www.gnu.org/software/libtool/manual.html section 6.2. See the resource file 'version.rc'. Microsoft version numbers use 4 integers: 0.0.0.0 Pthreads-win32 uses the first 3 following the Libtool convention. The fourth is commonly used for the build number, but will be reserved for future use. current.revision.age.0 The numbers are changed as follows: 1. If the library source code has changed at all since the last update, then increment revision (`c:r:a' becomes `c:r+1:a'). 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0. 3. If any interfaces have been added since the last public release, then increment age. 4. If any interfaces have been removed or changed since the last public release, then set age to 0. DLL compatibility numbering is an attempt to ensure that applications always load a compatible pthreads-win32 DLL by using a DLL naming system that is consistent with the version numbering system. It also allows older and newer DLLs to coexist in the same filesystem so that older applications can continue to be used. For pre .NET Windows systems, this inevitably requires incompatible versions of the same DLLs to have different names. Pthreads-win32 has adopted the Cygwin convention of appending a single integer number to the DLL name. The number used is based on the library version number and is computed as 'current' - 'age'. (See http://home.att.net/~perlspinr/libversioning.html for a nicely detailed explanation.) Using this method, DLL name/s will only change when the DLL's backwards compatibility changes. Note that the addition of new 'interfaces' will not of itself change the DLL's compatibility for older applications. Which of the several dll versions to use? ----------------------------------------- or, --- What are all these pthread*.dll and pthread*.lib files? ------------------------------------------------------- Simple, use either pthreadGCv.* if you use GCC, or pthreadVCv.* if you use MSVC - where 'v' is the DLL versioning (compatibility) number. Otherwise, you need to choose carefully and know WHY. The most important choice you need to make is whether to use a version that uses exceptions internally, or not. There are versions of the library that use exceptions as part of the thread cancelation and exit implementation. The default version uses setjmp/longjmp. There is some contension amongst POSIX threads experts as to how POSIX threads cancelation and exit should work with languages that use exceptions, e.g. C++ and even C (Microsoft's Structured Exceptions). The issue is: should cancelation of a thread in, say, a C++ application cause object destructors and C++ exception handlers to be invoked as the stack unwinds during thread exit, or not? There seems to be more opinion in favour of using the standard C version of the library (no EH) with C++ applications for the reason that this appears to be the assumption commercial pthreads implementations make. Therefore, if you use an EH version of pthreads-win32 then you may be under the illusion that your application will be portable, when in fact it is likely to behave differently when linked with other pthreads libraries. Now you may be asking: then why have you kept the EH versions of the library? There are a couple of reasons: - there is division amongst the experts and so the code may be needed in the future. Yes, it's in the repository and we can get it out anytime in the future, but it would be difficult to find. - pthreads-win32 is one of the few implementations, and possibly the only freely available one, that has EH versions. It may be useful to people who want to play with or study application behaviour under these conditions. Notes: [If you use either pthreadVCE or pthreadGCE] 1. [See also the discussion in the FAQ file - Q2, Q4, and Q5] If your application contains catch(...) blocks in your POSIX threads then you will need to replace the "catch(...)" with the macro "PtW32Catch", eg. #ifdef PtW32Catch PtW32Catch { ... } #else catch(...) { ... } #endif Otherwise neither pthreads cancelation nor pthread_exit() will work reliably when using versions of the library that use C++ exceptions for cancelation and thread exit. This is due to what is believed to be a C++ compliance error in VC++ whereby you may not have multiple handlers for the same exception in the same try/catch block. GNU G++ doesn't have this restriction. Other name changes ------------------ All snapshots prior to and including snapshot 2000-08-13 used "_pthread_" as the prefix to library internal functions, and "_PTHREAD_" to many library internal macros. These have now been changed to "ptw32_" and "PTW32_" respectively so as to not conflict with the ANSI standard's reservation of identifiers beginning with "_" and "__" for use by compiler implementations only. If you have written any applications and you are linking statically with the pthreads-win32 library then you may have included a call to _pthread_processInitialize. You will now have to change that to ptw32_processInitialize. Cleanup code default style -------------------------- Previously, if not defined, the cleanup style was determined automatically from the compiler used, and one of the following was defined accordingly: __CLEANUP_SEH MSVC only __CLEANUP_CXX C++, including MSVC++, GNU G++ __CLEANUP_C C, including GNU GCC, not MSVC These defines determine the style of cleanup (see pthread.h) and, most importantly, the way that cancelation and thread exit (via pthread_exit) is performed (see the routine ptw32_throw()). In short, the exceptions versions of the library throw an exception when a thread is canceled, or exits via pthread_exit(). This exception is caught by a handler in the thread startup routine, so that the the correct stack unwinding occurs regardless of where the thread is when it's canceled or exits via pthread_exit(). In this snapshot, unless the build explicitly defines (e.g. via a compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then the build NOW always defaults to __CLEANUP_C style cleanup. This style uses setjmp/longjmp in the cancelation and pthread_exit implementations, and therefore won't do stack unwinding even when linked to applications that have it (e.g. C++ apps). This is for consistency with most/all commercial Unix POSIX threads implementations. Although it was not clearly documented before, it is still necessary to build your application using the same __CLEANUP_* define as was used for the version of the library that you link with, so that the correct parts of pthread.h are included. That is, the possible defines require the following library versions: __CLEANUP_SEH pthreadVSE.dll __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll __CLEANUP_C pthreadVC.dll or pthreadGC.dll It is recommended that you let pthread.h use it's default __CLEANUP_C for both library and application builds. That is, don't define any of the above, and then link with pthreadVC.lib (MSVC or MSVC++) and libpthreadGC.a (MinGW GCC or G++). The reason is explained below, but another reason is that the prebuilt pthreadVCE.dll is currently broken. Versions built with MSVC++ later than version 6 may not be broken, but I can't verify this yet. WHY ARE WE MAKING THE DEFAULT STYLE LESS EXCEPTION-FRIENDLY? Because no commercial Unix POSIX threads implementation allows you to choose to have stack unwinding. Therefore, providing it in pthread-win32 as a default is dangerous. We still provide the choice but unless you consciously choose to do otherwise, your pthreads applications will now run or crash in similar ways irrespective of the pthreads platform you use. Or at least this is the hope. Building under VC++ using C++ EH, Structured EH, or just C ---------------------------------------------------------- From the source directory run nmake without any arguments to list help information. E.g. $ nmake Microsoft (R) Program Maintenance Utility Version 6.00.8168.0 Copyright (C) Microsoft Corp 1988-1998. All rights reserved. Run one of the following command lines: nmake clean VCE (to build the MSVC dll with C++ exception handling) nmake clean VSE (to build the MSVC dll with structured exception handling) nmake clean VC (to build the MSVC dll with C cleanup code) nmake clean VCE-inlined (to build the MSVC inlined dll with C++ exception handling) nmake clean VSE-inlined (to build the MSVC inlined dll with structured exception handling) nmake clean VC-inlined (to build the MSVC inlined dll with C cleanup code) nmake clean VC-static (to build the MSVC static lib with C cleanup code) nmake clean VCE-debug (to build the debug MSVC dll with C++ exception handling) nmake clean VSE-debug (to build the debug MSVC dll with structured exception handling) nmake clean VC-debug (to build the debug MSVC dll with C cleanup code) nmake clean VCE-inlined-debug (to build the debug MSVC inlined dll with C++ exception handling) nmake clean VSE-inlined-debug (to build the debug MSVC inlined dll with structured exception handling) nmake clean VC-inlined-debug (to build the debug MSVC inlined dll with C cleanup code) nmake clean VC-static-debug (to build the debug MSVC static lib with C cleanup code) The pre-built dlls are normally built using the *-inlined targets. You can run the testsuite by changing to the "tests" directory and running nmake. E.g.: $ cd tests $ nmake Microsoft (R) Program Maintenance Utility Version 6.00.8168.0 Copyright (C) Microsoft Corp 1988-1998. All rights reserved. Run one of the following command lines: nmake clean VC (to test using VC dll with VC (no EH) applications) nmake clean VCX (to test using VC dll with VC++ (EH) applications) nmake clean VCE (to test using the VCE dll with VC++ EH applications) nmake clean VSE (to test using VSE dll with VC (SEH) applications) nmake clean VC-bench (to benchtest using VC dll with C bench app) nmake clean VCX-bench (to benchtest using VC dll with C++ bench app) nmake clean VCE-bench (to benchtest using VCE dll with C++ bench app) nmake clean VSE-bench (to benchtest using VSE dll with SEH bench app) nmake clean VC-static (to test using VC static lib with VC (no EH) applications) Building under Mingw32 ---------------------- The dll can be built easily with recent versions of Mingw32. (The distributed versions are built using Mingw32 and MsysDTK from www.mingw32.org.) From the source directory, run make for help information. E.g.: $ make Run one of the following command lines: make clean GC (to build the GNU C dll with C cleanup code) make clean GCE (to build the GNU C dll with C++ exception handling) make clean GC-inlined (to build the GNU C inlined dll with C cleanup code) make clean GCE-inlined (to build the GNU C inlined dll with C++ exception handling) make clean GC-static (to build the GNU C inlined static lib with C cleanup code) make clean GC-debug (to build the GNU C debug dll with C cleanup code) make clean GCE-debug (to build the GNU C debug dll with C++ exception handling) make clean GC-inlined-debug (to build the GNU C inlined debug dll with C cleanup code) make clean GCE-inlined-debug (to build the GNU C inlined debug dll with C++ exception handling) make clean GC-static-debug (to build the GNU C inlined static debug lib with C cleanup code) The pre-built dlls are normally built using the *-inlined targets. You can run the testsuite by changing to the "tests" directory and running make for help information. E.g.: $ cd tests $ make Run one of the following command lines: make clean GC (to test using GC dll with C (no EH) applications) make clean GCX (to test using GC dll with C++ (EH) applications) make clean GCE (to test using GCE dll with C++ (EH) applications) make clean GC-bench (to benchtest using GNU C dll with C cleanup code) make clean GCE-bench (to benchtest using GNU C dll with C++ exception handling) make clean GC-static (to test using GC static lib with C (no EH) applications) Building under Linux using the Mingw32 cross development tools -------------------------------------------------------------- You can build the library without leaving Linux by using the Mingw32 cross development toolchain. See http://www.libsdl.org/extras/win32/cross/ for tools and info. The GNUmakefile contains some support for this, for example: make CROSS=i386-mingw32msvc- clean GC-inlined will build pthreadGCn.dll and libpthreadGCn.a (n=version#), provided your cross-tools/bin directory is in your PATH (or use the cross-make.sh script at the URL above). Building the library as a statically linkable library ----------------------------------------------------- General: PTW32_STATIC_LIB must be defined for both the library build and the application build. The makefiles supplied and used by the following 'make' command lines will define this for you. MSVC (creates pthreadVCn.lib as a static link lib): nmake clean VC-static MinGW32 (creates libpthreadGCn.a as a static link lib): make clean GC-static Define PTW32_STATIC_LIB when building your application. Also, your application must call a two non-portable routines to initialise the some state on startup and cleanup before exit. One other routine needs to be called to cleanup after any Win32 threads have called POSIX API routines. See README.NONPORTABLE or the html reference manual pages for details on these routines: BOOL pthread_win32_process_attach_np (void); BOOL pthread_win32_process_detach_np (void); BOOL pthread_win32_thread_attach_np (void); // Currently a no-op BOOL pthread_win32_thread_detach_np (void); The tests makefiles have the same targets but only check that the static library is statically linkable. They don't run the full testsuite. To run the full testsuite, build the dlls and run the dll test targets. Building the library under Cygwin --------------------------------- Cygwin is implementing it's own POSIX threads routines and these will be the ones to use if you develop using Cygwin. Ready to run binaries --------------------- For convenience, the following ready-to-run files can be downloaded from the FTP site (see under "Availability" below): pthread.h semaphore.h sched.h pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp pthreadVC.lib pthreadVCE.dll - built with MSVC++ compiler using C++ EH pthreadVCE.lib pthreadVSE.dll - built with MSVC compiler using SEH pthreadVSE.lib pthreadGC.dll - built with Mingw32 GCC libpthreadGC.a - derived from pthreadGC.dll pthreadGCE.dll - built with Mingw32 G++ libpthreadGCE.a - derived from pthreadGCE.dll As of August 2003 pthreads-win32 pthreadG* versions are built and tested using the MinGW + MsysDTK environment current as of that date or later. The following file MAY be needed for older MinGW environments. gcc.dll - needed to build and run applications that use pthreadGCE.dll. Building applications with GNU compilers ---------------------------------------- If you're using pthreadGC.dll: With the three header files, pthreadGC.dll and libpthreadGC.a in the same directory as your application myapp.c, you could compile, link and run myapp.c under Mingw32 as follows: gcc -o myapp.exe myapp.c -I. -L. -lpthreadGC myapp Or put pthreadGC.dll in an appropriate directory in your PATH, put libpthreadGC.a in your system lib directory, and put the three header files in your system include directory, then use: gcc -o myapp.exe myapp.c -lpthreadGC myapp If you're using pthreadGCE.dll: With the three header files, pthreadGCE.dll, gcc.dll and libpthreadGCE.a in the same directory as your application myapp.c, you could compile, link and run myapp.c under Mingw32 as follows: gcc -x c++ -o myapp.exe myapp.c -I. -L. -lpthreadGCE myapp Or put pthreadGCE.dll and gcc.dll in an appropriate directory in your PATH, put libpthreadGCE.a in your system lib directory, and put the three header files in your system include directory, then use: gcc -x c++ -o myapp.exe myapp.c -lpthreadGCE myapp Availability ------------ The complete source code in either unbundled, self-extracting Zip file, or tar/gzipped format can be found at: ftp://sources.redhat.com/pub/pthreads-win32 The pre-built DLL, export libraries and matching pthread.h can be found at: ftp://sources.redhat.com/pub/pthreads-win32/dll-latest Home page: http://sources.redhat.com/pthreads-win32/ Mailing list ------------ There is a mailing list for discussing pthreads on Win32. To join, send email to: pthreads-win32-subscribe@sources.redhat.com Unsubscribe by sending mail to: pthreads-win32-unsubscribe@sources.redhat.com Acknowledgements ---------------- See the ANNOUNCE file for acknowledgements. See the 'CONTRIBUTORS' file for the list of contributors. As much as possible, the ChangeLog file attributes contributions and patches that have been incorporated in the library to the individuals responsible. Finally, thanks to all those who work on and contribute to the POSIX and Single Unix Specification standards. The maturity of an industry can be measured by it's open standards. ---- Ross Johnson nyquist-3.05/liblo/pthreads.2/spin.c0000644000175000000620000000341411512143043016347 0ustar stevestaff/* * spin.c * * Description: * This translation unit implements spin lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" #include "ptw32_spinlock_check_need_init.c" #include "pthread_spin_init.c" #include "pthread_spin_destroy.c" #include "pthread_spin_lock.c" #include "pthread_spin_unlock.c" #include "pthread_spin_trylock.c" nyquist-3.05/liblo/pthreads.2/pthread_cond_signal.c0000644000175000000620000001544411512143043021373 0ustar stevestaff/* * pthread_cond_signal.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * ------------------------------------------------------------- * Algorithm: * See the comments at the top of pthread_cond_wait.c. */ #include "pthread.h" #include "implement.h" static INLINE int ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) /* * Notes. * * Does not use the external mutex for synchronisation, * therefore semBlockLock is needed. * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the * state where the external mutex is not necessarily locked by * any thread, ie. between cond_wait unlocking and re-acquiring * the lock after having been signaled or a timeout or * cancellation. * * Uses the following CV elements: * nWaitersBlocked * nWaitersToUnblock * nWaitersGone * mtxUnblockLock * semBlockLock * semBlockQueue */ { int result; pthread_cond_t cv; int nSignalsToIssue; if (cond == NULL || *cond == NULL) { return EINVAL; } cv = *cond; /* * No-op if the CV is static and hasn't been initialised yet. * Assuming that any race condition is harmless. */ if (cv == PTHREAD_COND_INITIALIZER) { return 0; } if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) { return result; } if (0 != cv->nWaitersToUnblock) { if (0 == cv->nWaitersBlocked) { return pthread_mutex_unlock (&(cv->mtxUnblockLock)); } if (unblockAll) { cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked); cv->nWaitersBlocked = 0; } else { nSignalsToIssue = 1; cv->nWaitersToUnblock++; cv->nWaitersBlocked--; } } else if (cv->nWaitersBlocked > cv->nWaitersGone) { /* Use the non-cancellable version of sem_wait() */ if (ptw32_semwait (&(cv->semBlockLock)) != 0) { result = errno; (void) pthread_mutex_unlock (&(cv->mtxUnblockLock)); return result; } if (0 != cv->nWaitersGone) { cv->nWaitersBlocked -= cv->nWaitersGone; cv->nWaitersGone = 0; } if (unblockAll) { nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked; cv->nWaitersBlocked = 0; } else { nSignalsToIssue = cv->nWaitersToUnblock = 1; cv->nWaitersBlocked--; } } else { return pthread_mutex_unlock (&(cv->mtxUnblockLock)); } if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) { if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0) { result = errno; } } return result; } /* ptw32_cond_unblock */ int pthread_cond_signal (pthread_cond_t * cond) /* * ------------------------------------------------------ * DOCPUBLIC * This function signals a condition variable, waking * one waiting thread. * If SCHED_FIFO or SCHED_RR policy threads are waiting * the highest priority waiter is awakened; otherwise, * an unspecified waiter is awakened. * * PARAMETERS * cond * pointer to an instance of pthread_cond_t * * * DESCRIPTION * This function signals a condition variable, waking * one waiting thread. * If SCHED_FIFO or SCHED_RR policy threads are waiting * the highest priority waiter is awakened; otherwise, * an unspecified waiter is awakened. * * NOTES: * * 1) Use when any waiter can respond and only one need * respond (all waiters being equal). * * RESULTS * 0 successfully signaled condition, * EINVAL 'cond' is invalid, * * ------------------------------------------------------ */ { /* * The '0'(FALSE) unblockAll arg means unblock ONE waiter. */ return (ptw32_cond_unblock (cond, 0)); } /* pthread_cond_signal */ int pthread_cond_broadcast (pthread_cond_t * cond) /* * ------------------------------------------------------ * DOCPUBLIC * This function broadcasts the condition variable, * waking all current waiters. * * PARAMETERS * cond * pointer to an instance of pthread_cond_t * * * DESCRIPTION * This function signals a condition variable, waking * all waiting threads. * * NOTES: * * 1) Use when more than one waiter may respond to * predicate change or if any waiting thread may * not be able to respond * * RESULTS * 0 successfully signalled condition to all * waiting threads, * EINVAL 'cond' is invalid * ENOSPC a required resource has been exhausted, * * ------------------------------------------------------ */ { /* * The TRUE unblockAll arg means unblock ALL waiters. */ return (ptw32_cond_unblock (cond, PTW32_TRUE)); } /* pthread_cond_broadcast */ nyquist-3.05/liblo/pthreads.2/pthread_rwlockattr_destroy.c0000644000175000000620000000532511512143043023055 0ustar stevestaff/* * pthread_rwlockattr_destroy.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Destroys a rwlock attributes object. The object can * no longer be used. * * PARAMETERS * attr * pointer to an instance of pthread_rwlockattr_t * * * DESCRIPTION * Destroys a rwlock attributes object. The object can * no longer be used. * * NOTES: * 1) Does not affect rwlockss created using 'attr' * * RESULTS * 0 successfully released attr, * EINVAL 'attr' is invalid. * * ------------------------------------------------------ */ { int result = 0; if (attr == NULL || *attr == NULL) { result = EINVAL; } else { pthread_rwlockattr_t rwa = *attr; *attr = NULL; free (rwa); } return (result); } /* pthread_rwlockattr_destroy */ nyquist-3.05/liblo/pthreads.2/pthread_cond_destroy.c0000644000175000000620000001675411512143043021614 0ustar stevestaff/* * pthread_cond_destroy.c * * Description: * This translation unit implements condition variables and their primitives. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_cond_destroy (pthread_cond_t * cond) /* * ------------------------------------------------------ * DOCPUBLIC * This function destroys a condition variable * * * PARAMETERS * cond * pointer to an instance of pthread_cond_t * * * DESCRIPTION * This function destroys a condition variable. * * NOTES: * 1) A condition variable can be destroyed * immediately after all the threads that * are blocked on it are awakened. e.g. * * struct list { * pthread_mutex_t lm; * ... * } * * struct elt { * key k; * int busy; * pthread_cond_t notbusy; * ... * } * * * struct elt * * list_find(struct list *lp, key k) * { * struct elt *ep; * * pthread_mutex_lock(&lp->lm); * while ((ep = find_elt(l,k) != NULL) && ep->busy) * pthread_cond_wait(&ep->notbusy, &lp->lm); * if (ep != NULL) * ep->busy = 1; * pthread_mutex_unlock(&lp->lm); * return(ep); * } * * delete_elt(struct list *lp, struct elt *ep) * { * pthread_mutex_lock(&lp->lm); * assert(ep->busy); * ... remove ep from list ... * ep->busy = 0; * (A) pthread_cond_broadcast(&ep->notbusy); * pthread_mutex_unlock(&lp->lm); * (B) pthread_cond_destroy(&rp->notbusy); * free(ep); * } * * In this example, the condition variable * and its list element may be freed (line B) * immediately after all threads waiting for * it are awakened (line A), since the mutex * and the code ensure that no other thread * can touch the element to be deleted. * * RESULTS * 0 successfully released condition variable, * EINVAL 'cond' is invalid, * EBUSY 'cond' is in use, * * ------------------------------------------------------ */ { pthread_cond_t cv; int result = 0, result1 = 0, result2 = 0; /* * Assuming any race condition here is harmless. */ if (cond == NULL || *cond == NULL) { return EINVAL; } if (*cond != PTHREAD_COND_INITIALIZER) { EnterCriticalSection (&ptw32_cond_list_lock); cv = *cond; /* * Close the gate; this will synchronize this thread with * all already signaled waiters to let them retract their * waiter status - SEE NOTE 1 ABOVE!!! */ if (sem_wait (&(cv->semBlockLock)) != 0) { return errno; } /* * !TRY! lock mtxUnblockLock; try will detect busy condition * and will not cause a deadlock with respect to concurrent * signal/broadcast. */ if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0) { (void) sem_post (&(cv->semBlockLock)); return result; } /* * Check whether cv is still busy (still has waiters) */ if (cv->nWaitersBlocked > cv->nWaitersGone) { if (sem_post (&(cv->semBlockLock)) != 0) { result = errno; } result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock)); result2 = EBUSY; } else { /* * Now it is safe to destroy */ *cond = NULL; if (sem_destroy (&(cv->semBlockLock)) != 0) { result = errno; } if (sem_destroy (&(cv->semBlockQueue)) != 0) { result1 = errno; } if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) { result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock)); } /* Unlink the CV from the list */ if (ptw32_cond_list_head == cv) { ptw32_cond_list_head = cv->next; } else { cv->prev->next = cv->next; } if (ptw32_cond_list_tail == cv) { ptw32_cond_list_tail = cv->prev; } else { cv->next->prev = cv->prev; } (void) free (cv); } LeaveCriticalSection (&ptw32_cond_list_lock); } else { /* * See notes in ptw32_cond_check_need_init() above also. */ EnterCriticalSection (&ptw32_cond_test_init_lock); /* * Check again. */ if (*cond == PTHREAD_COND_INITIALIZER) { /* * This is all we need to do to destroy a statically * initialised cond that has not yet been used (initialised). * If we get to here, another thread waiting to initialise * this cond will get an EINVAL. That's OK. */ *cond = NULL; } else { /* * The cv has been initialised while we were waiting * so assume it's in use. */ result = EBUSY; } LeaveCriticalSection (&ptw32_cond_test_init_lock); } return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); } nyquist-3.05/liblo/pthreads.2/pthread_attr_setstackaddr.c0000644000175000000620000000634511512143043022621 0ustar stevestaff/* * pthread_attr_setstackaddr.c * * Description: * This translation unit implements operations on thread attribute objects. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr) /* * ------------------------------------------------------ * DOCPUBLIC * Threads created with 'attr' will run on the stack * starting at 'stackaddr'. * Stack must be at least PTHREAD_STACK_MIN bytes. * * PARAMETERS * attr * pointer to an instance of pthread_attr_t * * stacksize * stack size, in bytes. * * * DESCRIPTION * Threads created with 'attr' will run on the stack * starting at 'stackaddr'. * Stack must be at least PTHREAD_STACK_MIN bytes. * * NOTES: * 1) Function supported only if this macro is * defined: * * _POSIX_THREAD_ATTR_STACKADDR * * 2) Create only one thread for each stack * address.. * * 3) Ensure that stackaddr is aligned. * * RESULTS * 0 successfully set stack address, * EINVAL 'attr' is invalid * ENOSYS function not supported * * ------------------------------------------------------ */ { #if defined( _POSIX_THREAD_ATTR_STACKADDR ) if (ptw32_is_attr (attr) != 0) { return EINVAL; } (*attr)->stackaddr = stackaddr; return 0; #else return ENOSYS; #endif /* _POSIX_THREAD_ATTR_STACKADDR */ } nyquist-3.05/liblo/pthreads.2/pthread_mutexattr_init.c0000644000175000000620000000535111512143043022167 0ustar stevestaff/* * pthread_mutexattr_init.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_mutexattr_init (pthread_mutexattr_t * attr) /* * ------------------------------------------------------ * DOCPUBLIC * Initializes a mutex attributes object with default * attributes. * * PARAMETERS * attr * pointer to an instance of pthread_mutexattr_t * * * DESCRIPTION * Initializes a mutex attributes object with default * attributes. * * NOTES: * 1) Used to define mutex types * * RESULTS * 0 successfully initialized attr, * ENOMEM insufficient memory for attr. * * ------------------------------------------------------ */ { int result = 0; pthread_mutexattr_t ma; ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma)); if (ma == NULL) { result = ENOMEM; } else { ma->pshared = PTHREAD_PROCESS_PRIVATE; ma->kind = PTHREAD_MUTEX_DEFAULT; } *attr = ma; return (result); } /* pthread_mutexattr_init */ nyquist-3.05/liblo/pthreads.2/pthread_rwlock_timedrdlock.c0000644000175000000620000000625111512143043022771 0ustar stevestaff/* * pthread_rwlock_timedrdlock.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlock_timedrdlock (pthread_rwlock_t * rwlock, const struct timespec *abstime) { int result; pthread_rwlock_t rwl; if (rwlock == NULL || *rwlock == NULL) { return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static rwlock. We check * again inside the guarded section of ptw32_rwlock_check_need_init() * to avoid race conditions. */ if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) { result = ptw32_rwlock_check_need_init (rwlock); if (result != 0 && result != EBUSY) { return result; } } rwl = *rwlock; if (rwl->nMagic != PTW32_RWLOCK_MAGIC) { return EINVAL; } if ((result = pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) { return result; } if (++rwl->nSharedAccessCount == INT_MAX) { if ((result = pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), abstime)) != 0) { if (result == ETIMEDOUT) { ++rwl->nCompletedSharedAccessCount; } (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; rwl->nCompletedSharedAccessCount = 0; if ((result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) { (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); return result; } } return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); } nyquist-3.05/liblo/pthreads.2/pthread_key_delete.c0000644000175000000620000001021111512143043021210 0ustar stevestaff/* * pthread_key_delete.c * * Description: * POSIX thread functions which implement thread-specific data (TSD). * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "pthread.h" #include "implement.h" int pthread_key_delete (pthread_key_t key) /* * ------------------------------------------------------ * DOCPUBLIC * This function deletes a thread-specific data key. This * does not change the value of the thread specific data key * for any thread and does not run the key's destructor * in any thread so it should be used with caution. * * PARAMETERS * key * pointer to an instance of pthread_key_t * * * DESCRIPTION * This function deletes a thread-specific data key. This * does not change the value of the thread specific data key * for any thread and does not run the key's destructor * in any thread so it should be used with caution. * * RESULTS * 0 successfully deleted the key, * EINVAL key is invalid, * * ------------------------------------------------------ */ { int result = 0; if (key != NULL) { if (key->threads != NULL && key->destructor != NULL && pthread_mutex_lock (&(key->keyLock)) == 0) { ThreadKeyAssoc *assoc; /* * Run through all Thread<-->Key associations * for this key. * * While we hold at least one of the locks guarding * the assoc, we know that the assoc pointed to by * key->threads is valid. */ while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL) { ptw32_thread_t * thread = assoc->thread; if (assoc == NULL) { /* Finished */ break; } if (pthread_mutex_lock (&(thread->threadLock)) == 0) { /* * Since we are starting at the head of the key's threads * chain, this will also point key->threads at the next assoc. * While we hold key->keyLock, no other thread can insert * a new assoc via pthread_setspecific. */ ptw32_tkAssocDestroy (assoc); (void) pthread_mutex_unlock (&(thread->threadLock)); } else { /* Thread or lock is no longer valid? */ ptw32_tkAssocDestroy (assoc); } } pthread_mutex_unlock (&(key->keyLock)); } TlsFree (key->key); if (key->destructor != NULL) { /* A thread could be holding the keyLock */ while (EBUSY == pthread_mutex_destroy (&(key->keyLock))) { Sleep(1); // Ugly. } } #if defined( _DEBUG ) memset ((char *) key, 0, sizeof (*key)); #endif free (key); } return (result); } nyquist-3.05/liblo/pthreads.2/README.CV0000644000175000000620000025725611512143043016440 0ustar stevestaffREADME.CV -- Condition Variables -------------------------------- The original implementation of condition variables in pthreads-win32 was based on a discussion paper: "Strategies for Implementing POSIX Condition Variables on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html The changes suggested below were made on Feb 6 2001. This file is included in the package for the benefit of anyone interested in understanding the pthreads-win32 implementation of condition variables and the (sometimes subtle) issues that it attempts to resolve. Thanks go to the individuals whose names appear throughout the following text. Ross Johnson -------------------------------------------------------------------- fyi.. (more detailed problem description/demos + possible fix/patch) regards, alexander. Alexander Terekhov 31.01.2001 17:43 To: ace-bugs@cs.wustl.edu cc: From: Alexander Terekhov/Germany/IBM@IBMDE Subject: Implementation of POSIX CVs: spur.wakeups/lost signals/deadlocks/unfairness ACE VERSION: 5.1.12 (pthread-win32 snapshot 2000-12-29) HOST MACHINE and OPERATING SYSTEM: IBM IntelliStation Z Pro, 2 x XEON 1GHz, Win2K TARGET MACHINE and OPERATING SYSTEM, if different from HOST: COMPILER NAME AND VERSION (AND PATCHLEVEL): Microsoft Visual C++ 6.0 AREA/CLASS/EXAMPLE AFFECTED: Implementation of POSIX condition variables - OS.cpp/.h DOES THE PROBLEM AFFECT: EXECUTION? YES! SYNOPSIS: a) spurious wakeups (minor problem) b) lost signals c) broadcast deadlock d) unfairness (minor problem) DESCRIPTION: Please see attached copy of discussion thread from comp.programming.threads for more details on some reported problems. (i've also posted a "fyi" message to ace-users a week or two ago but unfortunately did not get any response so far). It seems that current implementation suffers from two essential problems: 1) cond.waiters_count does not accurately reflect number of waiters blocked on semaphore - w/o proper synchronisation that could result (in the time window when counter is not accurate) in spurious wakeups organised by subsequent _signals and _broadcasts. 2) Always having (with no e.g. copy_and_clear/..) the same queue in use (semaphore+counter) neither signal nor broadcast provide 'atomic' behaviour with respect to other threads/subsequent calls to signal/broadcast/wait. Each problem and combination of both could produce various nasty things: a) spurious wakeups (minor problem) it is possible that waiter(s) which was already unblocked even so is still counted as blocked waiter. signal and broadcast will release semaphore which will produce a spurious wakeup for a 'real' waiter coming later. b) lost signals signalling thread ends up consuming its own signal. please see demo/discussion below. c) broadcast deadlock last_waiter processing code does not correctly handle the case with multiple threads waiting for the end of broadcast. please see demo/discussion below. d) unfairness (minor problem) without SignalObjectAndWait some waiter(s) may end up consuming broadcasted signals multiple times (spurious wakeups) because waiter thread(s) can be preempted before they call semaphore wait (but after count++ and mtx.unlock). REPEAT BY: See below... run problem demos programs (tennis.cpp and tennisb.cpp) number of times concurrently (on multiprocessor) and in multiple sessions or just add a couple of "Sleep"s as described in the attached copy of discussion thread from comp.programming.threads SAMPLE FIX/WORKAROUND: See attached patch to pthread-win32.. well, I can not claim that it is completely bug free but at least my test and tests provided by pthreads-win32 seem to work. Perhaps that will help. regards, alexander. >> Forum: comp.programming.threads >> Thread: pthread_cond_* implementation questions . . . David Schwartz wrote: > terekhov@my-deja.com wrote: > >> BTW, could you please also share your view on other perceived >> "problems" such as nested broadcast deadlock, spurious wakeups >> and (the latest one) lost signals?? > >I'm not sure what you mean. The standard allows an implementation >to do almost whatever it likes. In fact, you could implement >pthread_cond_wait by releasing the mutex, sleeping a random >amount of time, and then reacquiring the mutex. Of course, >this would be a pretty poor implementation, but any code that >didn't work under that implementation wouldn't be strictly >compliant. The implementation you suggested is indeed correct one (yes, now I see it :). However it requires from signal/broadcast nothing more than to "{ return 0; }" That is not the case for pthread-win32 and ACE implementations. I do think that these implementations (basically the same implementation) have some serious problems with wait/signal/broadcast calls. I am looking for help to clarify whether these problems are real or not. I think that I can demonstrate what I mean using one or two small sample programs. . . . ========== tennis.cpp ========== #include "ace/Synch.h" #include "ace/Thread.h" enum GAME_STATE { START_GAME, PLAYER_A, // Player A playes the ball PLAYER_B, // Player B playes the ball GAME_OVER, ONE_PLAYER_GONE, BOTH_PLAYERS_GONE }; enum GAME_STATE eGameState; ACE_Mutex* pmtxGameStateLock; ACE_Condition< ACE_Mutex >* pcndGameStateChange; void* playerA( void* pParm ) { // For access to game state variable pmtxGameStateLock->acquire(); // Play loop while ( eGameState < GAME_OVER ) { // Play the ball cout << endl << "PLAYER-A" << endl; // Now its PLAYER-B's turn eGameState = PLAYER_B; // Signal to PLAYER-B that now it is his turn pcndGameStateChange->signal(); // Wait until PLAYER-B finishes playing the ball do { pcndGameStateChange->wait(); if ( PLAYER_B == eGameState ) cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl; } while ( PLAYER_B == eGameState ); } // PLAYER-A gone eGameState = (GAME_STATE)(eGameState+1); cout << endl << "PLAYER-A GONE" << endl; // No more access to state variable needed pmtxGameStateLock->release(); // Signal PLAYER-A gone event pcndGameStateChange->broadcast(); return 0; } void* playerB( void* pParm ) { // For access to game state variable pmtxGameStateLock->acquire(); // Play loop while ( eGameState < GAME_OVER ) { // Play the ball cout << endl << "PLAYER-B" << endl; // Now its PLAYER-A's turn eGameState = PLAYER_A; // Signal to PLAYER-A that now it is his turn pcndGameStateChange->signal(); // Wait until PLAYER-A finishes playing the ball do { pcndGameStateChange->wait(); if ( PLAYER_A == eGameState ) cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl; } while ( PLAYER_A == eGameState ); } // PLAYER-B gone eGameState = (GAME_STATE)(eGameState+1); cout << endl << "PLAYER-B GONE" << endl; // No more access to state variable needed pmtxGameStateLock->release(); // Signal PLAYER-B gone event pcndGameStateChange->broadcast(); return 0; } int main (int, ACE_TCHAR *[]) { pmtxGameStateLock = new ACE_Mutex(); pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock ); // Set initial state eGameState = START_GAME; // Create players ACE_Thread::spawn( playerA ); ACE_Thread::spawn( playerB ); // Give them 5 sec. to play Sleep( 5000 );//sleep( 5 ); // Set game over state pmtxGameStateLock->acquire(); eGameState = GAME_OVER; // Let them know pcndGameStateChange->broadcast(); // Wait for players to stop do { pcndGameStateChange->wait(); } while ( eGameState < BOTH_PLAYERS_GONE ); // Cleanup cout << endl << "GAME OVER" << endl; pmtxGameStateLock->release(); delete pcndGameStateChange; delete pmtxGameStateLock; return 0; } =========== tennisb.cpp =========== #include "ace/Synch.h" #include "ace/Thread.h" enum GAME_STATE { START_GAME, PLAYER_A, // Player A playes the ball PLAYER_B, // Player B playes the ball GAME_OVER, ONE_PLAYER_GONE, BOTH_PLAYERS_GONE }; enum GAME_STATE eGameState; ACE_Mutex* pmtxGameStateLock; ACE_Condition< ACE_Mutex >* pcndGameStateChange; void* playerA( void* pParm ) { // For access to game state variable pmtxGameStateLock->acquire(); // Play loop while ( eGameState < GAME_OVER ) { // Play the ball cout << endl << "PLAYER-A" << endl; // Now its PLAYER-B's turn eGameState = PLAYER_B; // Signal to PLAYER-B that now it is his turn pcndGameStateChange->broadcast(); // Wait until PLAYER-B finishes playing the ball do { pcndGameStateChange->wait(); if ( PLAYER_B == eGameState ) cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl; } while ( PLAYER_B == eGameState ); } // PLAYER-A gone eGameState = (GAME_STATE)(eGameState+1); cout << endl << "PLAYER-A GONE" << endl; // No more access to state variable needed pmtxGameStateLock->release(); // Signal PLAYER-A gone event pcndGameStateChange->broadcast(); return 0; } void* playerB( void* pParm ) { // For access to game state variable pmtxGameStateLock->acquire(); // Play loop while ( eGameState < GAME_OVER ) { // Play the ball cout << endl << "PLAYER-B" << endl; // Now its PLAYER-A's turn eGameState = PLAYER_A; // Signal to PLAYER-A that now it is his turn pcndGameStateChange->broadcast(); // Wait until PLAYER-A finishes playing the ball do { pcndGameStateChange->wait(); if ( PLAYER_A == eGameState ) cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl; } while ( PLAYER_A == eGameState ); } // PLAYER-B gone eGameState = (GAME_STATE)(eGameState+1); cout << endl << "PLAYER-B GONE" << endl; // No more access to state variable needed pmtxGameStateLock->release(); // Signal PLAYER-B gone event pcndGameStateChange->broadcast(); return 0; } int main (int, ACE_TCHAR *[]) { pmtxGameStateLock = new ACE_Mutex(); pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock ); // Set initial state eGameState = START_GAME; // Create players ACE_Thread::spawn( playerA ); ACE_Thread::spawn( playerB ); // Give them 5 sec. to play Sleep( 5000 );//sleep( 5 ); // Make some noise pmtxGameStateLock->acquire(); cout << endl << "---Noise ON..." << endl; pmtxGameStateLock->release(); for ( int i = 0; i < 100000; i++ ) pcndGameStateChange->broadcast(); cout << endl << "---Noise OFF" << endl; // Set game over state pmtxGameStateLock->acquire(); eGameState = GAME_OVER; cout << endl << "---Stopping the game..." << endl; // Let them know pcndGameStateChange->broadcast(); // Wait for players to stop do { pcndGameStateChange->wait(); } while ( eGameState < BOTH_PLAYERS_GONE ); // Cleanup cout << endl << "GAME OVER" << endl; pmtxGameStateLock->release(); delete pcndGameStateChange; delete pmtxGameStateLock; return 0; } . . . David Schwartz wrote: >> > It's compliant >> >> That is really good. > >> Tomorrow (I have to go urgently now) I will try to >> demonstrate the lost-signal "problem" of current >> pthread-win32 and ACE-(variant w/o SingleObjectAndWait) >> implementations: players start suddenly drop their balls :-) >> (with no change in source code). > >Signals aren't lost, they're going to the main thread, >which isn't coded correctly to handle them. Try this: > > // Wait for players to stop > do { > > pthread_cond_wait( &cndGameStateChange,&mtxGameStateLock ); >printf("Main thread stole a signal\n"); > > } while ( eGameState < BOTH_PLAYERS_GONE ); > >I bet everytime you thing a signal is lost, you'll see that printf. >The signal isn't lost, it was stolen by another thread. well, you can probably loose your bet.. it was indeed stolen by "another" thread but not the one you seem to think of. I think that what actually happens is the following: H:\SA\UXX\pt\PTHREADS\TESTS>tennis3.exe PLAYER-A PLAYER-B ----PLAYER-B: SPURIOUS WAKEUP!!! PLAYER-A GONE PLAYER-B GONE GAME OVER H:\SA\UXX\pt\PTHREADS\TESTS> here you can see that PLAYER-B after playing his first ball (which came via signal from PLAYER-A) just dropped it down. What happened is that his signal to player A was consumed as spurious wakeup by himself (player B). The implementation has a problem: ================ waiting threads: ================ { /** Critical Section inc cond.waiters_count } /* /* Atomic only if using Win32 SignalObjectAndWait /* cond.mtx.release /*** ^^-- A THREAD WHICH DID SIGNAL MAY ACQUIRE THE MUTEX, /*** GO INTO WAIT ON THE SAME CONDITION AND OVERTAKE /*** ORIGINAL WAITER(S) CONSUMING ITS OWN SIGNAL! cond.sem.wait Player-A after playing game's initial ball went into wait (called _wait) but was pre-empted before reaching wait semaphore. He was counted as waiter but was not actually waiting/blocked yet. =============== signal threads: =============== { /** Critical Section waiters_count = cond.waiters_count } if ( waiters_count != 0 ) sem.post 1 endif Player-B after he received signal/ball from Player A called _signal. The _signal did see that there was one waiter blocked on the condition (Player-A) and released the semaphore.. (but it did not unblock Player-A because he was not actually blocked). Player-B thread continued its execution, called _wait, was counted as second waiter BUT was allowed to slip through opened semaphore gate (which was opened for Player-B) and received his own signal. Player B remained blocked followed by Player A. Deadlock happened which lasted until main thread came in and said game over. It seems to me that the implementation fails to correctly implement the following statement from specification: http://www.opengroup.org/ onlinepubs/007908799/xsh/pthread_cond_wait.html "These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable". That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_signal() or pthread_cond_broadcast() in that thread behaves as if it were issued after the about-to-block thread has blocked." Question: Am I right? (I produced the program output above by simply adding ?Sleep( 1 )?: ================ waiting threads: ================ { /** Critical Section inc cond.waiters_count } /* /* Atomic only if using Win32 SignalObjectAndWait /* cond.mtx.release Sleep( 1 ); // Win32 /*** ^^-- A THREAD WHICH DID SIGNAL MAY ACQUIRE THE MUTEX, /*** GO INTO WAIT ON THE SAME CONDITION AND OVERTAKE /*** ORIGINAL WAITER(S) CONSUMING ITS OWN SIGNAL! cond.sem.wait to the source code of pthread-win32 implementation: http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/ condvar.c?rev=1.36&content-type=text/ x-cvsweb-markup&cvsroot=pthreads-win32 /* * We keep the lock held just long enough to increment the count of * waiters by one (above). * Note that we can't keep it held across the * call to sem_wait since that will deadlock other calls * to pthread_cond_signal */ cleanup_args.mutexPtr = mutex; cleanup_args.cv = cv; cleanup_args.resultPtr = &result; pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args); if ((result = pthread_mutex_unlock (mutex)) == 0) {((result Sleep( 1 ); // @AT /* * Wait to be awakened by * pthread_cond_signal, or * pthread_cond_broadcast, or * a timeout * * Note: * ptw32_sem_timedwait is a cancelation point, * hence providing the * mechanism for making pthread_cond_wait a cancelation * point. We use the cleanup mechanism to ensure we * re-lock the mutex and decrement the waiters count * if we are canceled. */ if (ptw32_sem_timedwait (&(cv->sema), abstime) == -1) { result = errno; } } pthread_cleanup_pop (1); /* Always cleanup */ BTW, on my system (2 CPUs) I can manage to get signals lost even without any source code modification if I run the tennis program many times in different shell sessions. . . . David Schwartz wrote: >terekhov@my-deja.com wrote: > >> well, it might be that the program is in fact buggy. >> but you did not show me any bug. > >You're right. I was close but not dead on. I was correct, however, >that the code is buggy because it uses 'pthread_cond_signal' even >though not any thread waiting on the condition variable can do the >job. I was wrong in which thread could be waiting on the cv but >unable to do the job. Okay, lets change 'pthread_cond_signal' to 'pthread_cond_broadcast' but also add some noise from main() right before declaring the game to be over (I need it in order to demonstrate another problem of pthread-win32/ACE implementations - broadcast deadlock)... . . . It is my understanding of POSIX conditions, that on correct implementation added noise in form of unnecessary broadcasts from main, should not break the tennis program. The only 'side effect' of added noise on correct implementation would be 'spurious wakeups' of players (in fact they are not spurious, players just see them as spurious) unblocked, not by another player but by main before another player had a chance to acquire the mutex and change the game state variable: . . . PLAYER-B PLAYER-A ---Noise ON... PLAYER-B PLAYER-A . . . PLAYER-B PLAYER-A ----PLAYER-A: SPURIOUS WAKEUP!!! PLAYER-B PLAYER-A ---Noise OFF PLAYER-B ---Stopping the game... PLAYER-A GONE PLAYER-B GONE GAME OVER H:\SA\UXX\pt\PTHREADS\TESTS> On pthread-win32/ACE implementations the program could stall: . . . PLAYER-A PLAYER-B PLAYER-A PLAYER-B PLAYER-A PLAYER-B PLAYER-A PLAYER-B ---Noise ON... PLAYER-A ---Noise OFF ^C H:\SA\UXX\pt\PTHREADS\TESTS> The implementation has problems: ================ waiting threads: ================ { /** Critical Section inc cond.waiters_count } /* /* Atomic only if using Win32 SignalObjectAndWait /* cond.mtx.release cond.sem.wait /*** ^^-- WAITER CAN BE PREEMPTED AFTER BEING UNBLOCKED... { /** Critical Section dec cond.waiters_count /*** ^^- ...AND BEFORE DECREMENTING THE COUNT (1) last_waiter = ( cond.was_broadcast && cond.waiters_count == 0 ) if ( last_waiter ) cond.was_broadcast = FALSE endif } if ( last_waiter ) /* /* Atomic only if using Win32 SignalObjectAndWait /* cond.auto_reset_event_or_sem.post /* Event for Win32 cond.mtx.acquire /*** ^^-- ...AND BEFORE CALL TO mtx.acquire (2) /*** ^^-- NESTED BROADCASTS RESULT IN A DEADLOCK else cond.mtx.acquire /*** ^^-- ...AND BEFORE CALL TO mtx.acquire (3) endif ================== broadcast threads: ================== { /** Critical Section waiters_count = cond.waiters_count if ( waiters_count != 0 ) cond.was_broadcast = TRUE endif } if ( waiters_count != 0 ) cond.sem.post waiters_count /*** ^^^^^--- SPURIOUS WAKEUPS DUE TO (1) cond.auto_reset_event_or_sem.wait /* Event for Win32 /*** ^^^^^--- DEADLOCK FOR FURTHER BROADCASTS IF THEY HAPPEN TO GO INTO WAIT WHILE PREVIOUS BROADCAST IS STILL IN PROGRESS/WAITING endif a) cond.waiters_count does not accurately reflect number of waiters blocked on semaphore - that could result (in the time window when counter is not accurate) in spurios wakeups organised by subsequent _signals and _broadcasts. From standard compliance point of view that is OK but that could be a real problem from performance/efficiency point of view. b) If subsequent broadcast happen to go into wait on cond.auto_reset_event_or_sem before previous broadcast was unblocked from cond.auto_reset_event_or_sem by its last waiter, one of two blocked threads will remain blocked because last_waiter processing code fails to unblock both threads. In the situation with tennisb.c the Player-B was put in a deadlock by noise (broadcast) coming from main thread. And since Player-B holds the game state mutex when it calls broadcast, the whole program stalled: Player-A was deadlocked on mutex and main thread after finishing with producing the noise was deadlocked on mutex too (needed to declare the game over) (I produced the program output above by simply adding ?Sleep( 1 )?: ================== broadcast threads: ================== { /** Critical Section waiters_count = cond.waiters_count if ( waiters_count != 0 ) cond.was_broadcast = TRUE endif } if ( waiters_count != 0 ) Sleep( 1 ); //Win32 cond.sem.post waiters_count /*** ^^^^^--- SPURIOUS WAKEUPS DUE TO (1) cond.auto_reset_event_or_sem.wait /* Event for Win32 /*** ^^^^^--- DEADLOCK FOR FURTHER BROADCASTS IF THEY HAPPEN TO GO INTO WAIT WHILE PREVIOUS BROADCAST IS STILL IN PROGRESS/WAITING endif to the source code of pthread-win32 implementation: http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/ condvar.c?rev=1.36&content-type=text/ x-cvsweb-markup&cvsroot=pthreads-win32 if (wereWaiters) {(wereWaiters)sroot=pthreads-win32eb.cgi/pthreads/Yem...m /* * Wake up all waiters */ Sleep( 1 ); //@AT #ifdef NEED_SEM result = (ptw32_increase_semaphore( &cv->sema, cv->waiters ) ? 0 : EINVAL); #else /* NEED_SEM */ result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL ) ? 0 : EINVAL); #endif /* NEED_SEM */ } (void) pthread_mutex_unlock(&(cv->waitersLock)); if (wereWaiters && result == 0) {(wereWaiters /* * Wait for all the awakened threads to acquire their part of * the counting semaphore */ if (WaitForSingleObject (cv->waitersDone, INFINITE) == WAIT_OBJECT_0) { result = 0; } else { result = EINVAL; } } return (result); } BTW, on my system (2 CPUs) I can manage to get the program stalled even without any source code modification if I run the tennisb program many times in different shell sessions. =================== pthread-win32 patch =================== struct pthread_cond_t_ { long nWaitersBlocked; /* Number of threads blocked */ long nWaitersUnblocked; /* Number of threads unblocked */ long nWaitersToUnblock; /* Number of threads to unblock */ sem_t semBlockQueue; /* Queue up threads waiting for the */ /* condition to become signalled */ sem_t semBlockLock; /* Semaphore that guards access to */ /* | waiters blocked count/block queue */ /* +-> Mandatory Sync.LEVEL-1 */ pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */ /* | waiters (to)unblock(ed) counts */ /* +-> Optional* Sync.LEVEL-2 */ }; /* Opt*) for _timedwait and cancellation*/ int pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) int result = EAGAIN; pthread_cond_t cv = NULL; if (cond == NULL) {(cond return EINVAL; } if ((attr != NULL && *attr != NULL) && ((*attr)->pshared == PTHREAD_PROCESS_SHARED)) { /* * Creating condition variable that can be shared between * processes. */ result = ENOSYS; goto FAIL0; } cv = (pthread_cond_t) calloc (1, sizeof (*cv)); if (cv == NULL) {(cv result = ENOMEM; goto FAIL0; } cv->nWaitersBlocked = 0; cv->nWaitersUnblocked = 0; cv->nWaitersToUnblock = 0; if (sem_init (&(cv->semBlockLock), 0, 1) != 0) {(sem_init goto FAIL0; } if (sem_init (&(cv->semBlockQueue), 0, 0) != 0) {(sem_init goto FAIL1; } if (pthread_mutex_init (&(cv->mtxUnblockLock), 0) != 0) {(pthread_mutex_init goto FAIL2; } result = 0; goto DONE; /* * ------------- * Failed... * ------------- */ FAIL2: (void) sem_destroy (&(cv->semBlockQueue)); FAIL1: (void) sem_destroy (&(cv->semBlockLock)); FAIL0: DONE: *cond = cv; return (result); } /* pthread_cond_init */ int pthread_cond_destroy (pthread_cond_t * cond) { int result = 0; pthread_cond_t cv; /* * Assuming any race condition here is harmless. */ if (cond == NULL || *cond == NULL) { return EINVAL; } if (*cond != (pthread_cond_t) PTW32_OBJECT_AUTO_INIT) {(*cond cv = *cond; /* * Synchronize access to waiters blocked count (LEVEL-1) */ if (sem_wait(&(cv->semBlockLock)) != 0) {(sem_wait(&(cv->semBlockLock)) return errno; } /* * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2) */ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0) {((result (void) sem_post(&(cv->semBlockLock)); return result; } /* * Check whether cv is still busy (still has waiters blocked) */ if (cv->nWaitersBlocked - cv->nWaitersUnblocked > 0) {(cv->nWaitersBlocked (void) sem_post(&(cv->semBlockLock)); (void) pthread_mutex_unlock(&(cv->mtxUnblockLock)); return EBUSY; } /* * Now it is safe to destroy */ (void) sem_destroy (&(cv->semBlockLock)); (void) sem_destroy (&(cv->semBlockQueue)); (void) pthread_mutex_unlock (&(cv->mtxUnblockLock)); (void) pthread_mutex_destroy (&(cv->mtxUnblockLock)); free(cv); *cond = NULL; } else { /* * See notes in ptw32_cond_check_need_init() above also. */ EnterCriticalSection(&ptw32_cond_test_init_lock); /* * Check again. */ if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT) {(*cond /* * This is all we need to do to destroy a statically * initialised cond that has not yet been used (initialised). * If we get to here, another thread * waiting to initialise this cond will get an EINVAL. */ *cond = NULL; } else { /* * The cv has been initialised while we were waiting * so assume it's in use. */ result = EBUSY; } LeaveCriticalSection(&ptw32_cond_test_init_lock); } return (result); } /* * Arguments for cond_wait_cleanup, since we can only pass a * single void * to it. */ typedef struct { pthread_mutex_t * mutexPtr; pthread_cond_t cv; int * resultPtr; } ptw32_cond_wait_cleanup_args_t; static void ptw32_cond_wait_cleanup(void * args) { ptw32_cond_wait_cleanup_args_t * cleanup_args = (ptw32_cond_wait_cleanup_args_t *) args; pthread_cond_t cv = cleanup_args->cv; int * resultPtr = cleanup_args->resultPtr; int eLastSignal; /* enum: 1=yes 0=no -1=cancelled/timedout w/o signal(s) */ int result; /* * Whether we got here as a result of signal/broadcast or because of * timeout on wait or thread cancellation we indicate that we are no * longer waiting. The waiter is responsible for adjusting waiters * (to)unblock(ed) counts (protected by unblock lock). * Unblock lock/Sync.LEVEL-2 supports _timedwait and cancellation. */ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0) {((result *resultPtr = result; return; } cv->nWaitersUnblocked++; eLastSignal = (cv->nWaitersToUnblock == 0) ? -1 : (--cv->nWaitersToUnblock == 0); /* * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed */ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0) {((result *resultPtr = result; return; } /* * If last signal... */ if (eLastSignal == 1) {(eLastSignal /* * ...it means that we have end of 'atomic' signal/broadcast */ if (sem_post(&(cv->semBlockLock)) != 0) {(sem_post(&(cv->semBlockLock)) *resultPtr = errno; return; } } /* * If not last signal and not timed out/cancelled wait w/o signal... */ else if (eLastSignal == 0) { /* * ...it means that next waiter can go through semaphore */ if (sem_post(&(cv->semBlockQueue)) != 0) {(sem_post(&(cv->semBlockQueue)) *resultPtr = errno; return; } } /* * XSH: Upon successful return, the mutex has been locked and is owned * by the calling thread */ if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0) {((result *resultPtr = result; } } /* ptw32_cond_wait_cleanup */ static int ptw32_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec *abstime) { int result = 0; pthread_cond_t cv; ptw32_cond_wait_cleanup_args_t cleanup_args; if (cond == NULL || *cond == NULL) {(cond return EINVAL; } /* * We do a quick check to see if we need to do more work * to initialise a static condition variable. We check * again inside the guarded section of ptw32_cond_check_need_init() * to avoid race conditions. */ if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT) {(*cond result = ptw32_cond_check_need_init(cond); } if (result != 0 && result != EBUSY) {(result return result; } cv = *cond; /* * Synchronize access to waiters blocked count (LEVEL-1) */ if (sem_wait(&(cv->semBlockLock)) != 0) {(sem_wait(&(cv->semBlockLock)) return errno; } cv->nWaitersBlocked++; /* * Thats it. Counted means waiting, no more access needed */ if (sem_post(&(cv->semBlockLock)) != 0) {(sem_post(&(cv->semBlockLock)) return errno; } /* * Setup this waiter cleanup handler */ cleanup_args.mutexPtr = mutex; cleanup_args.cv = cv; cleanup_args.resultPtr = &result; pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args); /* * Now we can release 'mutex' and... */ if ((result = pthread_mutex_unlock (mutex)) == 0) {((result /* * ...wait to be awakened by * pthread_cond_signal, or * pthread_cond_broadcast, or * timeout, or * thread cancellation * * Note: * * ptw32_sem_timedwait is a cancellation point, * hence providing the mechanism for making * pthread_cond_wait a cancellation point. * We use the cleanup mechanism to ensure we * re-lock the mutex and adjust (to)unblock(ed) waiters * counts if we are cancelled, timed out or signalled. */ if (ptw32_sem_timedwait (&(cv->semBlockQueue), abstime) != 0) {(ptw32_sem_timedwait result = errno; } } /* * Always cleanup */ pthread_cleanup_pop (1); /* * "result" can be modified by the cleanup handler. */ return (result); } /* ptw32_cond_timedwait */ static int ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) { int result; pthread_cond_t cv; if (cond == NULL || *cond == NULL) {(cond return EINVAL; } cv = *cond; /* * No-op if the CV is static and hasn't been initialised yet. * Assuming that any race condition is harmless. */ if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT) {(cv return 0; } /* * Synchronize access to waiters blocked count (LEVEL-1) */ if (sem_wait(&(cv->semBlockLock)) != 0) {(sem_wait(&(cv->semBlockLock)) return errno; } /* * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2) * This sync.level supports _timedwait and cancellation */ if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0) {((result return result; } /* * Adjust waiters blocked and unblocked counts (collect garbage) */ if (cv->nWaitersUnblocked != 0) {(cv->nWaitersUnblocked cv->nWaitersBlocked -= cv->nWaitersUnblocked; cv->nWaitersUnblocked = 0; } /* * If (after adjustment) there are still some waiters blocked counted... */ if ( cv->nWaitersBlocked > 0) {( /* * We will unblock first waiter and leave semBlockLock/LEVEL-1 locked * LEVEL-1 access is left disabled until last signal/unblock completes */ cv->nWaitersToUnblock = (unblockAll) ? cv->nWaitersBlocked : 1; /* * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed * This sync.level supports _timedwait and cancellation */ if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0) {((result return result; } /* * Now, with LEVEL-2 lock released let first waiter go through semaphore */ if (sem_post(&(cv->semBlockQueue)) != 0) {(sem_post(&(cv->semBlockQueue)) return errno; } } /* * No waiter blocked - no more LEVEL-1 access to blocked count needed... */ else if (sem_post(&(cv->semBlockLock)) != 0) { return errno; } /* * ...and no more LEVEL-2 access to waiters (to)unblock(ed) counts needed too * This sync.level supports _timedwait and cancellation */ else { result = pthread_mutex_unlock(&(cv->mtxUnblockLock)); } return(result); } /* ptw32_cond_unblock */ int pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) { /* The NULL abstime arg means INFINITE waiting. */ return(ptw32_cond_timedwait(cond, mutex, NULL)); } /* pthread_cond_wait */ int pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec *abstime) { if (abstime == NULL) {(abstime return EINVAL; } return(ptw32_cond_timedwait(cond, mutex, abstime)); } /* pthread_cond_timedwait */ int pthread_cond_signal (pthread_cond_t * cond) { /* The '0'(FALSE) unblockAll arg means unblock ONE waiter. */ return(ptw32_cond_unblock(cond, 0)); } /* pthread_cond_signal */ int pthread_cond_broadcast (pthread_cond_t * cond) { /* The '1'(TRUE) unblockAll arg means unblock ALL waiters. */ return(ptw32_cond_unblock(cond, 1)); } /* pthread_cond_broadcast */ TEREKHOV@de.ibm.com on 17.01.2001 01:00:57 Please respond to TEREKHOV@de.ibm.com To: pthreads-win32@sourceware.cygnus.com cc: schmidt@uci.edu Subject: win32 conditions: sem+counter+event = broadcast_deadlock + spur.wakeup/unfairness/incorrectness ?? Hi, Problem 1: broadcast_deadlock It seems that current implementation does not provide "atomic" broadcasts. That may lead to "nested" broadcasts... and it seems that nested case is not handled correctly -> producing a broadcast DEADLOCK as a result. Scenario: N (>1) waiting threads W1..N are blocked (in _wait) on condition's semaphore. Thread B1 calls pthread_cond_broadcast, which results in "releasing" N W threads via incrementing semaphore counter by N (stored in cv->waiters) BUT cv->waiters counter does not change!! The caller thread B1 remains blocked on cv->waitersDone event (auto-reset!!) BUT condition is not protected from starting another broadcast (when called on another thread) while still waiting for the "old" broadcast to complete on thread B1. M (>=0, waiters counter. L (N-M) "late" waiter W threads are a) still blocked/not returned from their semaphore wait call or b) were preempted after sem_wait but before lock( &cv->waitersLock ) or c) are blocked on cv->waitersLock. cv->waiters is still > 0 (= L). Another thread B2 (or some W thread from M group) calls pthread_cond_broadcast and gains access to counter... neither a) nor b) prevent thread B2 in pthread_cond_broadcast from gaining access to counter and starting another broadcast ( for c) - it depends on cv->waitersLock scheduling rules: FIFO=OK, PRTY=PROBLEM,... ) That call to pthread_cond_broadcast (on thread B2) will result in incrementing semaphore by cv->waiters (=L) which is INCORRECT (all W1..N were in fact already released by thread B1) and waiting on _auto-reset_ event cv->waitersDone which is DEADLY WRONG (produces a deadlock)... All late W1..L threads now have a chance to complete their _wait call. Last W_L thread sets an auto-reselt event cv->waitersDone which will release either B1 or B2 leaving one of B threads in a deadlock. Problem 2: spur.wakeup/unfairness/incorrectness It seems that: a) because of the same problem with counter which does not reflect the actual number of NOT RELEASED waiters, the signal call may increment a semaphore counter w/o having a waiter blocked on it. That will result in (best case) spurious wake ups - performance degradation due to unnecessary context switches and predicate re-checks and (in worth case) unfairness/incorrectness problem - see b) b) neither signal nor broadcast prevent other threads - "new waiters" (and in the case of signal, the caller thread as well) from going into _wait and overtaking "old" waiters (already released but still not returned from sem_wait on condition's semaphore). Win semaphore just [API DOC]: "Maintains a count between zero and some maximum value, limiting the number of threads that are simultaneously accessing a shared resource." Calling ReleaseSemaphore does not imply (at least not documented) that on return from ReleaseSemaphore all waiters will in fact become released (returned from their Wait... call) and/or that new waiters calling Wait... afterwards will become less importance. It is NOT documented to be an atomic release of waiters... And even if it would be there is still a problem with a thread being preempted after Wait on semaphore and before Wait on cv->waitersLock and scheduling rules for cv->waitersLock itself (??WaitForMultipleObjects??) That may result in unfairness/incorrectness problem as described for SetEvent impl. in "Strategies for Implementing POSIX Condition Variables on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html Unfairness -- The semantics of the POSIX pthread_cond_broadcast function is to wake up all threads currently blocked in wait calls on the condition variable. The awakened threads then compete for the external_mutex. To ensure fairness, all of these threads should be released from their pthread_cond_wait calls and allowed to recheck their condition expressions before other threads can successfully complete a wait on the condition variable. Unfortunately, the SetEvent implementation above does not guarantee that all threads sleeping on the condition variable when cond_broadcast is called will acquire the external_mutex and check their condition expressions. Although the Pthreads specification does not mandate this degree of fairness, the lack of fairness can cause starvation. To illustrate the unfairness problem, imagine there are 2 threads, C1 and C2, that are blocked in pthread_cond_wait on condition variable not_empty_ that is guarding a thread-safe message queue. Another thread, P1 then places two messages onto the queue and calls pthread_cond_broadcast. If C1 returns from pthread_cond_wait, dequeues and processes the message, and immediately waits again then it and only it may end up acquiring both messages. Thus, C2 will never get a chance to dequeue a message and run. The following illustrates the sequence of events: 1. Thread C1 attempts to dequeue and waits on CV non_empty_ 2. Thread C2 attempts to dequeue and waits on CV non_empty_ 3. Thread P1 enqueues 2 messages and broadcasts to CV not_empty_ 4. Thread P1 exits 5. Thread C1 wakes up from CV not_empty_, dequeues a message and runs 6. Thread C1 waits again on CV not_empty_, immediately dequeues the 2nd message and runs 7. Thread C1 exits 8. Thread C2 is the only thread left and blocks forever since not_empty_ will never be signaled Depending on the algorithm being implemented, this lack of fairness may yield concurrent programs that have subtle bugs. Of course, application developers should not rely on the fairness semantics of pthread_cond_broadcast. However, there are many cases where fair implementations of condition variables can simplify application code. Incorrectness -- A variation on the unfairness problem described above occurs when a third consumer thread, C3, is allowed to slip through even though it was not waiting on condition variable not_empty_ when a broadcast occurred. To illustrate this, we will use the same scenario as above: 2 threads, C1 and C2, are blocked dequeuing messages from the message queue. Another thread, P1 then places two messages onto the queue and calls pthread_cond_broadcast. C1 returns from pthread_cond_wait, dequeues and processes the message. At this time, C3 acquires the external_mutex, calls pthread_cond_wait and waits on the events in WaitForMultipleObjects. Since C2 has not had a chance to run yet, the BROADCAST event is still signaled. C3 then returns from WaitForMultipleObjects, and dequeues and processes the message in the queue. Thus, C2 will never get a chance to dequeue a message and run. The following illustrates the sequence of events: 1. Thread C1 attempts to dequeue and waits on CV non_empty_ 2. Thread C2 attempts to dequeue and waits on CV non_empty_ 3. Thread P1 enqueues 2 messages and broadcasts to CV not_empty_ 4. Thread P1 exits 5. Thread C1 wakes up from CV not_empty_, dequeues a message and runs 6. Thread C1 exits 7. Thread C3 waits on CV not_empty_, immediately dequeues the 2nd message and runs 8. Thread C3 exits 9. Thread C2 is the only thread left and blocks forever since not_empty_ will never be signaled In the above case, a thread that was not waiting on the condition variable when a broadcast occurred was allowed to proceed. This leads to incorrect semantics for a condition variable. COMMENTS??? regards, alexander. ----------------------------------------------------------------------------- Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementation questions Date: Wed, 21 Feb 2001 11:54:47 +0100 From: TEREKHOV@de.ibm.com To: lthomas@arbitrade.com CC: rpj@ise.canberra.edu.au, Thomas Pfaff , Nanbor Wang Hi Louis, generation number 8.. had some time to revisit timeouts/spurious wakeup problem.. found some bugs (in 7.b/c/d) and something to improve (7a - using IPC semaphores but it should speedup Win32 version as well). regards, alexander. ---------- Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL ------ given: semBlockLock - bin.semaphore semBlockQueue - semaphore mtxExternal - mutex or CS mtxUnblockLock - mutex or CS nWaitersGone - int nWaitersBlocked - int nWaitersToUnblock - int wait( timeout ) { [auto: register int result ] // error checking omitted [auto: register int nSignalsWasLeft ] [auto: register int nWaitersWasGone ] sem_wait( semBlockLock ); nWaitersBlocked++; sem_post( semBlockLock ); unlock( mtxExternal ); bTimedOut = sem_wait( semBlockQueue,timeout ); lock( mtxUnblockLock ); if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { if ( bTimeout ) { // timeout (or canceled) if ( 0 != nWaitersBlocked ) { nWaitersBlocked--; } else { nWaitersGone++; // count spurious wakeups } } if ( 0 == --nWaitersToUnblock ) { if ( 0 != nWaitersBlocked ) { sem_post( semBlockLock ); // open the gate nSignalsWasLeft = 0; // do not open the gate below again } else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { nWaitersGone = 0; } } } else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious semaphore :-) sem_wait( semBlockLock ); nWaitersBlocked -= nWaitersGone; // something is going on here - test of timeouts? :-) sem_post( semBlockLock ); nWaitersGone = 0; } unlock( mtxUnblockLock ); if ( 1 == nSignalsWasLeft ) { if ( 0 != nWaitersWasGone ) { // sem_adjust( -nWaitersWasGone ); while ( nWaitersWasGone-- ) { sem_wait( semBlockLock ); // better now than spurious later } } sem_post( semBlockLock ); // open the gate } lock( mtxExternal ); return ( bTimedOut ) ? ETIMEOUT : 0; } signal(bAll) { [auto: register int result ] [auto: register int nSignalsToIssue] lock( mtxUnblockLock ); if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! if ( 0 == nWaitersBlocked ) { // NO-OP return unlock( mtxUnblockLock ); } if (bAll) { nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; nWaitersBlocked = 0; } else { nSignalsToIssue = 1; nWaitersToUnblock++; nWaitersBlocked--; } } else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! sem_wait( semBlockLock ); // close the gate if ( 0 != nWaitersGone ) { nWaitersBlocked -= nWaitersGone; nWaitersGone = 0; } if (bAll) { nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; nWaitersBlocked = 0; } else { nSignalsToIssue = nWaitersToUnblock = 1; nWaitersBlocked--; } } else { // NO-OP return unlock( mtxUnblockLock ); } unlock( mtxUnblockLock ); sem_post( semBlockQueue,nSignalsToIssue ); return result; } ---------- Algorithm 8b / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ONEBYONE ------ given: semBlockLock - bin.semaphore semBlockQueue - bin.semaphore mtxExternal - mutex or CS mtxUnblockLock - mutex or CS nWaitersGone - int nWaitersBlocked - int nWaitersToUnblock - int wait( timeout ) { [auto: register int result ] // error checking omitted [auto: register int nWaitersWasGone ] [auto: register int nSignalsWasLeft ] sem_wait( semBlockLock ); nWaitersBlocked++; sem_post( semBlockLock ); unlock( mtxExternal ); bTimedOut = sem_wait( semBlockQueue,timeout ); lock( mtxUnblockLock ); if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { if ( bTimeout ) { // timeout (or canceled) if ( 0 != nWaitersBlocked ) { nWaitersBlocked--; nSignalsWasLeft = 0; // do not unblock next waiter below (already unblocked) } else { nWaitersGone = 1; // spurious wakeup pending!! } } if ( 0 == --nWaitersToUnblock && if ( 0 != nWaitersBlocked ) { sem_post( semBlockLock ); // open the gate nSignalsWasLeft = 0; // do not open the gate below again } else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { nWaitersGone = 0; } } } else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious semaphore :-) sem_wait( semBlockLock ); nWaitersBlocked -= nWaitersGone; // something is going on here - test of timeouts? :-) sem_post( semBlockLock ); nWaitersGone = 0; } unlock( mtxUnblockLock ); if ( 1 == nSignalsWasLeft ) { if ( 0 != nWaitersWasGone ) { // sem_adjust( -1 ); sem_wait( semBlockQueue ); // better now than spurious later } sem_post( semBlockLock ); // open the gate } else if ( 0 != nSignalsWasLeft ) { sem_post( semBlockQueue ); // unblock next waiter } lock( mtxExternal ); return ( bTimedOut ) ? ETIMEOUT : 0; } signal(bAll) { [auto: register int result ] lock( mtxUnblockLock ); if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! if ( 0 == nWaitersBlocked ) { // NO-OP return unlock( mtxUnblockLock ); } if (bAll) { nWaitersToUnblock += nWaitersBlocked; nWaitersBlocked = 0; } else { nWaitersToUnblock++; nWaitersBlocked--; } unlock( mtxUnblockLock ); } else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! sem_wait( semBlockLock ); // close the gate if ( 0 != nWaitersGone ) { nWaitersBlocked -= nWaitersGone; nWaitersGone = 0; } if (bAll) { nWaitersToUnblock = nWaitersBlocked; nWaitersBlocked = 0; } else { nWaitersToUnblock = 1; nWaitersBlocked--; } unlock( mtxUnblockLock ); sem_post( semBlockQueue ); } else { // NO-OP unlock( mtxUnblockLock ); } return result; } ---------- Algorithm 8c / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ONEBYONE --------- given: hevBlockLock - auto-reset event hevBlockQueue - auto-reset event mtxExternal - mutex or CS mtxUnblockLock - mutex or CS nWaitersGone - int nWaitersBlocked - int nWaitersToUnblock - int wait( timeout ) { [auto: register int result ] // error checking omitted [auto: register int nSignalsWasLeft ] [auto: register int nWaitersWasGone ] wait( hevBlockLock,INFINITE ); nWaitersBlocked++; set_event( hevBlockLock ); unlock( mtxExternal ); bTimedOut = wait( hevBlockQueue,timeout ); lock( mtxUnblockLock ); if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) { if ( bTimeout ) { // timeout (or canceled) if ( 0 != nWaitersBlocked ) { nWaitersBlocked--; nSignalsWasLeft = 0; // do not unblock next waiter below (already unblocked) } else { nWaitersGone = 1; // spurious wakeup pending!! } } if ( 0 == --nWaitersToUnblock ) if ( 0 != nWaitersBlocked ) { set_event( hevBlockLock ); // open the gate nSignalsWasLeft = 0; // do not open the gate below again } else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { nWaitersGone = 0; } } } else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious event :-) wait( hevBlockLock,INFINITE ); nWaitersBlocked -= nWaitersGone; // something is going on here - test of timeouts? :-) set_event( hevBlockLock ); nWaitersGone = 0; } unlock( mtxUnblockLock ); if ( 1 == nSignalsWasLeft ) { if ( 0 != nWaitersWasGone ) { reset_event( hevBlockQueue ); // better now than spurious later } set_event( hevBlockLock ); // open the gate } else if ( 0 != nSignalsWasLeft ) { set_event( hevBlockQueue ); // unblock next waiter } lock( mtxExternal ); return ( bTimedOut ) ? ETIMEOUT : 0; } signal(bAll) { [auto: register int result ] lock( mtxUnblockLock ); if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! if ( 0 == nWaitersBlocked ) { // NO-OP return unlock( mtxUnblockLock ); } if (bAll) { nWaitersToUnblock += nWaitersBlocked; nWaitersBlocked = 0; } else { nWaitersToUnblock++; nWaitersBlocked--; } unlock( mtxUnblockLock ); } else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! wait( hevBlockLock,INFINITE ); // close the gate if ( 0 != nWaitersGone ) { nWaitersBlocked -= nWaitersGone; nWaitersGone = 0; } if (bAll) { nWaitersToUnblock = nWaitersBlocked; nWaitersBlocked = 0; } else { nWaitersToUnblock = 1; nWaitersBlocked--; } unlock( mtxUnblockLock ); set_event( hevBlockQueue ); } else { // NO-OP unlock( mtxUnblockLock ); } return result; } ---------- Algorithm 8d / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ALL ------ given: hevBlockLock - auto-reset event hevBlockQueueS - auto-reset event // for signals hevBlockQueueB - manual-reset even // for broadcasts mtxExternal - mutex or CS mtxUnblockLock - mutex or CS eBroadcast - int // 0: no broadcast, 1: broadcast, 2: broadcast after signal(s) nWaitersGone - int nWaitersBlocked - int nWaitersToUnblock - int wait( timeout ) { [auto: register int result ] // error checking omitted [auto: register int eWasBroadcast ] [auto: register int nSignalsWasLeft ] [auto: register int nWaitersWasGone ] wait( hevBlockLock,INFINITE ); nWaitersBlocked++; set_event( hevBlockLock ); unlock( mtxExternal ); bTimedOut = waitformultiple( hevBlockQueueS,hevBlockQueueB,timeout,ONE ); lock( mtxUnblockLock ); if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) { if ( bTimeout ) { // timeout (or canceled) if ( 0 != nWaitersBlocked ) { nWaitersBlocked--; nSignalsWasLeft = 0; // do not unblock next waiter below (already unblocked) } else if ( 1 != eBroadcast ) { nWaitersGone = 1; } } if ( 0 == --nWaitersToUnblock ) { if ( 0 != nWaitersBlocked ) { set_event( hevBlockLock ); // open the gate nSignalsWasLeft = 0; // do not open the gate below again } else { if ( 0 != (eWasBroadcast = eBroadcast) ) { eBroadcast = 0; } if ( 0 != (nWaitersWasGone = nWaitersGone ) { nWaitersGone = 0; } } } else if ( 0 != eBroadcast ) { nSignalsWasLeft = 0; // do not unblock next waiter below (already unblocked) } } else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious event :-) wait( hevBlockLock,INFINITE ); nWaitersBlocked -= nWaitersGone; // something is going on here - test of timeouts? :-) set_event( hevBlockLock ); nWaitersGone = 0; } unlock( mtxUnblockLock ); if ( 1 == nSignalsWasLeft ) { if ( 0 != eWasBroadcast ) { reset_event( hevBlockQueueB ); } if ( 0 != nWaitersWasGone ) { reset_event( hevBlockQueueS ); // better now than spurious later } set_event( hevBlockLock ); // open the gate } else if ( 0 != nSignalsWasLeft ) { set_event( hevBlockQueueS ); // unblock next waiter } lock( mtxExternal ); return ( bTimedOut ) ? ETIMEOUT : 0; } signal(bAll) { [auto: register int result ] [auto: register HANDLE hevBlockQueue ] lock( mtxUnblockLock ); if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! if ( 0 == nWaitersBlocked ) { // NO-OP return unlock( mtxUnblockLock ); } if (bAll) { nWaitersToUnblock += nWaitersBlocked; nWaitersBlocked = 0; eBroadcast = 2; hevBlockQueue = hevBlockQueueB; } else { nWaitersToUnblock++; nWaitersBlocked--; return unlock( mtxUnblockLock ); } } else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! wait( hevBlockLock,INFINITE ); // close the gate if ( 0 != nWaitersGone ) { nWaitersBlocked -= nWaitersGone; nWaitersGone = 0; } if (bAll) { nWaitersToUnblock = nWaitersBlocked; nWaitersBlocked = 0; eBroadcast = 1; hevBlockQueue = hevBlockQueueB; } else { nWaitersToUnblock = 1; nWaitersBlocked--; hevBlockQueue = hevBlockQueueS; } } else { // NO-OP return unlock( mtxUnblockLock ); } unlock( mtxUnblockLock ); set_event( hevBlockQueue ); return result; } ---------------------- Forwarded by Alexander Terekhov/Germany/IBM on 02/21/2001 09:13 AM --------------------------- Alexander Terekhov 02/20/2001 04:33 PM To: Louis Thomas cc: From: Alexander Terekhov/Germany/IBM@IBMDE Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio n questions Importance: Normal >Sorry, gotta take a break and work on something else for a while. >Real work >calls, unfortunately. I'll get back to you in two or three days. ok. no problem. here is some more stuff for pauses you might have in between :) ---------- Algorithm 7d / IMPL_EVENT,UNBLOCK_STRATEGY == UNBLOCK_ALL ------ given: hevBlockLock - auto-reset event hevBlockQueueS - auto-reset event // for signals hevBlockQueueB - manual-reset even // for broadcasts mtxExternal - mutex or CS mtxUnblockLock - mutex or CS bBroadcast - int nWaitersGone - int nWaitersBlocked - int nWaitersToUnblock - int wait( timeout ) { [auto: register int result ] // error checking omitted [auto: register int bWasBroadcast ] [auto: register int nSignalsWasLeft ] wait( hevBlockLock,INFINITE ); nWaitersBlocked++; set_event( hevBlockLock ); unlock( mtxExternal ); bTimedOut = waitformultiple( hevBlockQueueS,hevBlockQueueB,timeout,ONE ); lock( mtxUnblockLock ); if ( 0 != (SignalsWasLeft = nWaitersToUnblock) ) { if ( bTimeout ) { // timeout (or canceled) if ( 0 != nWaitersBlocked ) { nWaitersBlocked--; nSignalsWasLeft = 0; // do not unblock next waiter below (already unblocked) } else if ( !bBroadcast ) { wait( hevBlockQueueS,INFINITE ); // better now than spurious later } } if ( 0 == --nWaitersToUnblock ) { if ( 0 != nWaitersBlocked ) { if ( bBroadcast ) { reset_event( hevBlockQueueB ); bBroadcast = false; } set_event( hevBlockLock ); // open the gate nSignalsWasLeft = 0; // do not open the gate below again } else if ( false != (bWasBroadcast = bBroadcast) ) { bBroadcast = false; } } else { bWasBroadcast = bBroadcast; } } else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or spurious event :-) wait( hevBlockLock,INFINITE ); nWaitersBlocked -= nWaitersGone; // something is going on here - test of timeouts? :-) set_event( hevBlockLock ); nWaitersGone = 0; } unlock( mtxUnblockLock ); if ( 1 == nSignalsWasLeft ) { if ( bWasBroadcast ) { reset_event( hevBlockQueueB ); } set_event( hevBlockLock ); // open the gate } else if ( 0 != nSignalsWasLeft && !bWasBroadcast ) { set_event( hevBlockQueueS ); // unblock next waiter } lock( mtxExternal ); return ( bTimedOut ) ? ETIMEOUT : 0; } signal(bAll) { [auto: register int result ] [auto: register HANDLE hevBlockQueue ] lock( mtxUnblockLock ); if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! if ( 0 == nWaitersBlocked ) { // NO-OP return unlock( mtxUnblockLock ); } if (bAll) { nWaitersToUnblock += nWaitersBlocked; nWaitersBlocked = 0; bBroadcast = true; hevBlockQueue = hevBlockQueueB; } else { nWaitersToUnblock++; nWaitersBlocked--; return unlock( mtxUnblockLock ); } } else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! wait( hevBlockLock,INFINITE ); // close the gate if ( 0 != nWaitersGone ) { nWaitersBlocked -= nWaitersGone; nWaitersGone = 0; } if (bAll) { nWaitersToUnblock = nWaitersBlocked; nWaitersBlocked = 0; bBroadcast = true; hevBlockQueue = hevBlockQueueB; } else { nWaitersToUnblock = 1; nWaitersBlocked--; hevBlockQueue = hevBlockQueueS; } } else { // NO-OP return unlock( mtxUnblockLock ); } unlock( mtxUnblockLock ); set_event( hevBlockQueue ); return result; } ---------------------------------------------------------------------------- Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio n questions Date: Mon, 26 Feb 2001 22:20:12 -0600 From: Louis Thomas To: "'TEREKHOV@de.ibm.com'" CC: rpj@ise.canberra.edu.au, Thomas Pfaff , Nanbor Wang Sorry all. Busy week. > this insures the fairness > which POSIX does not (e.g. two subsequent broadcasts - the gate does insure > that first wave waiters will start the race for the mutex before waiters > from the second wave - Linux pthreads process/unblock both waves > concurrently...) I'm not sure how we are any more fair about this than Linux. We certainly don't guarantee that the threads released by the first broadcast will get the external mutex before the threads of the second wave. In fact, it is possible that those threads will never get the external mutex if there is enough contention for it. > e.g. i was thinking about implementation with a pool of > N semaphores/counters [...] I considered that too. The problem is as you mentioned in a). You really need to assign threads to semaphores once you know how you want to wake them up, not when they first begin waiting which is the only time you can assign them. > well, i am not quite sure that i've fully understood your scenario, Hmm. Well, it think it's an important example, so I'll try again. First, we have thread A which we KNOW is waiting on a condition. As soon as it becomes unblocked for any reason, we will know because it will set a flag. Since the flag is not set, we are 100% confident that thread A is waiting on the condition. We have another thread, thread B, which has acquired the mutex and is about to wait on the condition. Thus it is pretty clear that at any point, either just A is waiting, or A and B are waiting. Now thread C comes along. C is about to do a broadcast on the condition. A broadcast is guaranteed to unblock all threads currently waiting on a condition, right? Again, we said that either just A is waiting, or A and B are both waiting. So, when C does its broadcast, depending upon whether B has started waiting or not, thread C will unblock A or unblock A and B. Either way, C must unblock A, right? Now, you said anything that happens is correct so long as a) "a signal is not lost between unlocking the mutex and waiting on the condition" and b) "a thread must not steal a signal it sent", correct? Requirement b) is easy to satisfy: in this scenario, thread C will never wait on the condition, so it won't steal any signals. Requirement a) is not hard either. The only way we could fail to meet requirement a) in this scenario is if thread B was started waiting but didn't wake up because a signal was lost. This will not happen. Now, here is what happens. Assume thread C beats thread B. Thread C looks to see how many threads are waiting on the condition. Thread C sees just one thread, thread A, waiting. It does a broadcast waking up just one thread because just one thread is waiting. Next, before A can become unblocked, thread B begins waiting. Now there are two threads waiting, but only one will be unblocked. Suppose B wins. B will become unblocked. A will not become unblocked, because C only unblocked one thread (sema_post cond, 1). So at the end, B finishes and A remains blocked. We have met both of your requirements, so by your rules, this is an acceptable outcome. However, I think that the spec says this is an unacceptable outcome! We know for certain that A was waiting and that C did a broadcast, but A did not become unblocked! Yet, the spec says that a broadcast wakes up all waiting threads. This did not happen. Do you agree that this shows your rules are not strict enough? > and what about N2? :) this one does allow almost everything. Don't get me started about rule #2. I'll NEVER advocate an algorithm that uses rule 2 as an excuse to suck! > but it is done (decrement)under mutex protection - this is not a subject > of a race condition. You are correct. My mistake. > i would remove "_bTimedOut=false".. after all, it was a real timeout.. I disagree. A thread that can't successfully retract its waiter status can't really have timed out. If a thread can't return without executing extra code to deal with the fact that someone tried to unblock it, I think it is a poor idea to pretend we didn't realize someone was trying to signal us. After all, a signal is more important than a time out. > when nSignaled != 0, it is possible to update nWaiters (--) and do not > touch nGone I realize this, but I was thinking that writing it the other ways saves another if statement. > adjust only if nGone != 0 and save one cache memory write - probably much slower than 'if' Hmm. You are probably right. > well, in a strange (e.g. timeout test) program you may (theoretically) > have an overflow of nWaiters/nGone counters (with waiters repeatedly timing > out and no signals at all). Also true. Not only that, but you also have the possibility that one could overflow the number of waiters as well! However, considering the limit you have chosen for nWaitersGone, I suppose it is unlikely that anyone would be able to get INT_MAX/2 threads waiting on a single condition. :) Analysis of 8a: It looks correct to me. What are IPC semaphores? In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone because nWaitersGone is never modified without holding mtxUnblockLock. You are correct that there is a harmless race on nWaitersBlocked, which can increase and make the condition become true just after we check it. If this happens, we interpret it as the wait starting after the signal. I like your optimization of this. You could improve Alg. 6 as follows: ---------- Algorithm 6b ---------- signal(bAll) { _nSig=0 lock counters // this is safe because nWaiting can only be decremented by a thread that // owns counters and nGone can only be changed by a thread that owns counters. if (nWaiting>nGone) { if (0==nSignaled) { sema_wait gate // close gate if not already closed } if (nGone>0) { nWaiting-=nGone nGone=0 } _nSig=bAll?nWaiting:1 nSignaled+=_nSig nWaiting-=_nSig } unlock counters if (0!=_nSig) { sema_post queue, _nSig } } ---------- ---------- ---------- I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings depending upon whether the gate is open or closed. In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on semBlockLock. Perhaps waiting on semBlockQueue would be a better idea. What have you gained by making the last thread to be signaled do the waits for all the timed out threads, besides added complexity? It took me a long time to figure out what your objective was with this, to realize you were using nWaitersGone to mean two different things, and to verify that you hadn't introduced any bug by doing this. Even now I'm not 100% sure. What has all this playing about with nWaitersGone really gained us besides a lot of complexity (it is much harder to verify that this solution is correct), execution overhead (we now have a lot more if statements to evaluate), and space overhead (more space for the extra code, and another integer in our data)? We did manage to save a lock/unlock pair in an uncommon case (when a time out occurs) at the above mentioned expenses in the common cases. As for 8b, c, and d, they look ok though I haven't studied them thoroughly. What would you use them for? Later, -Louis! :) ----------------------------------------------------------------------------- Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio n questions Date: Tue, 27 Feb 2001 15:51:28 +0100 From: TEREKHOV@de.ibm.com To: Louis Thomas CC: rpj@ise.canberra.edu.au, Thomas Pfaff , Nanbor Wang Hi Louis, >> that first wave waiters will start the race for the mutex before waiters >> from the second wave - Linux pthreads process/unblock both waves >> concurrently...) > >I'm not sure how we are any more fair about this than Linux. We certainly >don't guarantee that the threads released by the first broadcast will get >the external mutex before the threads of the second wave. In fact, it is >possible that those threads will never get the external mutex if there is >enough contention for it. correct. but gate is nevertheless more fair than Linux because of the barrier it establishes between two races (1st and 2nd wave waiters) for the mutex which under 'normal' circumstances (e.g. all threads of equal priorities,..) will 'probably' result in fair behaviour with respect to mutex ownership. >> well, i am not quite sure that i've fully understood your scenario, > >Hmm. Well, it think it's an important example, so I'll try again. ... ok. now i seem to understand this example. well, now it seems to me that the only meaningful rule is just: a) "a signal is not lost between unlocking the mutex and waiting on the condition" and that the rule b) "a thread must not steal a signal it sent" is not needed at all because a thread which violates b) also violates a). i'll try to explain.. i think that the most important thing is how POSIX defines waiter's visibility: "if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_signal() or pthread_cond_broadcast() in that thread behaves as if it were issued after the about-to-block thread has blocked. " my understanding is the following: 1) there is no guarantees whatsoever with respect to whether signal/broadcast will actually unblock any 'waiter' if it is done w/o acquiring the mutex first (note that a thread may release it before signal/broadcast - it does not matter). 2) it is guaranteed that waiters become 'visible' - eligible for unblock as soon as signalling thread acquires the mutex (but not before!!) so.. >So, when C does its broadcast, depending upon whether B has started waiting >or not, thread C will unblock A or unblock A and B. Either way, C must >unblock A, right? right. but only if C did acquire the mutex prior to broadcast (it may release it before broadcast as well). implementation will violate waiters visibility rule (signal will become lost) if C will not unblock A. >Now, here is what happens. Assume thread C beats thread B. Thread C looks to >see how many threads are waiting on the condition. Thread C sees just one >thread, thread A, waiting. It does a broadcast waking up just one thread >because just one thread is waiting. Next, before A can become unblocked, >thread B begins waiting. Now there are two threads waiting, but only one >will be unblocked. Suppose B wins. B will become unblocked. A will not >become unblocked, because C only unblocked one thread (sema_post cond, 1). >So at the end, B finishes and A remains blocked. thread C did acquire the mutex ("Thread C sees just one thread, thread A, waiting"). beginning from that moment it is guaranteed that subsequent broadcast will unblock A. Otherwise we will have a lost signal with respect to A. I do think that it does not matter whether the signal was physically (completely) lost or was just stolen by another thread (B) - in both cases it was simply lost with respect to A. >..Do you agree that this shows your rules are not strict enough? probably the opposite.. :-) i think that it shows that the only meaningful rule is a) "a signal is not lost between unlocking the mutex and waiting on the condition" with clarification of waiters visibility as defined by POSIX above. >> i would remove "_bTimedOut=false".. after all, it was a real timeout.. > >I disagree. A thread that can't successfully retract its waiter status can't >really have timed out. If a thread can't return without executing extra code >to deal with the fact that someone tried to unblock it, I think it is a poor >idea to pretend we >didn't realize someone was trying to signal us. After all, a signal is more >important than a time out. a) POSIX does allow timed out thread to consume a signal (cancelled is not). b) ETIMEDOUT status just says that: "The time specified by abstime to pthread_cond_timedwait() has passed." c) it seem to me that hiding timeouts would violate "The pthread_cond_timedwait() function is the same as pthread_cond_wait() except that an error is returned if the absolute time specified by abstime passes (that is, system time equals or exceeds abstime) before the condition cond is signaled or broadcasted" because the abs. time did really pass before cond was signaled (waiter was released via semaphore). however, if it really matters, i could imaging that we can save an abs. time of signal/broadcast and compare it with timeout after unblock to find out whether it was a 'real' timeout or not. absent this check i do think that hiding timeouts would result in technical violation of specification.. but i think that this check is not important and we can simply trust timeout error code provided by wait since we are not trying to make 'hard' realtime implementation. >What are IPC semaphores? int semctl(int, int, int, ...); int semget(key_t, int, int); int semop(int, struct sembuf *, size_t); they support adjustment of semaphore counter (semvalue) in one single call - imaging Win32 ReleaseSemaphore( hsem,-N ) >In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) { >// HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone >because nWaitersGone is never modified without holding mtxUnblockLock. You >are correct that there is a harmless race on nWaitersBlocked, which can >increase and make the condition become true just after we check it. If this >happens, we interpret it as the wait starting after the signal. well, the reason why i've asked on comp.programming.threads whether this race condition is harmless or not is that in order to be harmless it should not violate the waiters visibility rule (see above). Fortunately, we increment the counter under protection of external mutex.. so that any (signalling) thread which will acquire the mutex next, should see the updated counter (in signal) according to POSIX memory visibility rules and mutexes (memory barriers). But i am not so sure how it actually works on Win32/INTEL which does not explicitly define any memory visibility rules :( >I like your optimization of this. You could improve Alg. 6 as follows: >---------- Algorithm 6b ---------- >signal(bAll) { > _nSig=0 > lock counters > // this is safe because nWaiting can only be decremented by a thread that > // owns counters and nGone can only be changed by a thread that owns >counters. > if (nWaiting>nGone) { > if (0==nSignaled) { > sema_wait gate // close gate if not already closed > } > if (nGone>0) { > nWaiting-=nGone > nGone=0 > } > _nSig=bAll?nWaiting:1 > nSignaled+=_nSig > nWaiting-=_nSig > } > unlock counters > if (0!=_nSig) { > sema_post queue, _nSig > } >} >---------- ---------- ---------- >I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings >depending upon whether the gate is open or closed. agree. >In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on >semBlockLock. Perhaps waiting on semBlockQueue would be a better idea. you are correct. my mistake. >What have you gained by making the last thread to be signaled do the waits >for all the timed out threads, besides added complexity? It took me a long >time to figure out what your objective was with this, to realize you were >using nWaitersGone to mean two different things, and to verify that you >hadn't introduced any bug by doing this. Even now I'm not 100% sure. > >What has all this playing about with nWaitersGone really gained us besides a >lot of complexity (it is much harder to verify that this solution is >correct), execution overhead (we now have a lot more if statements to >evaluate), and space overhead (more space for the extra code, and another >integer in our data)? We did manage to save a lock/unlock pair in an >uncommon case (when a time out occurs) at the above mentioned expenses in >the common cases. well, please consider the following: 1) with multiple waiters unblocked (but some timed out) the trick with counter seem to ensure potentially higher level of concurrency by not delaying most of unblocked waiters for semaphore cleanup - only the last one will be delayed but all others would already contend/acquire/release the external mutex - the critical section protected by mtxUnblockLock is made smaller (increment + couple of IFs is faster than system/kernel call) which i think is good in general. however, you are right, this is done at expense of 'normal' waiters.. 2) some semaphore APIs (e.g. POSIX IPC sems) do allow to adjust the semaphore counter in one call => less system/kernel calls.. imagine: if ( 1 == nSignalsWasLeft ) { if ( 0 != nWaitersWasGone ) { ReleaseSemaphore( semBlockQueue,-nWaitersWasGone ); // better now than spurious later } sem_post( semBlockLock ); // open the gate } 3) even on win32 a single thread doing multiple cleanup calls (to wait) will probably result in faster execution (because of processor caching) than multiple threads each doing a single call to wait. >As for 8b, c, and d, they look ok though I haven't studied them thoroughly. >What would you use them for? 8b) for semaphores which do not allow to unblock multiple waiters in a single call to post/release (e.g. POSIX realtime semaphores - ) 8c/8d) for WinCE prior to 3.0 (WinCE 3.0 does have semaphores) ok. so, which one is the 'final' algorithm(s) which we should use in pthreads-win32?? regards, alexander. ---------------------------------------------------------------------------- Louis Thomas on 02/27/2001 05:20:12 AM Please respond to Louis Thomas To: Alexander Terekhov/Germany/IBM@IBMDE cc: rpj@ise.canberra.edu.au, Thomas Pfaff , Nanbor Wang Subject: RE: FYI/comp.programming.threads/Re: pthread_cond_* implementatio n questions Sorry all. Busy week. > this insures the fairness > which POSIX does not (e.g. two subsequent broadcasts - the gate does insure > that first wave waiters will start the race for the mutex before waiters > from the second wave - Linux pthreads process/unblock both waves > concurrently...) I'm not sure how we are any more fair about this than Linux. We certainly don't guarantee that the threads released by the first broadcast will get the external mutex before the threads of the second wave. In fact, it is possible that those threads will never get the external mutex if there is enough contention for it. > e.g. i was thinking about implementation with a pool of > N semaphores/counters [...] I considered that too. The problem is as you mentioned in a). You really need to assign threads to semaphores once you know how you want to wake them up, not when they first begin waiting which is the only time you can assign them. > well, i am not quite sure that i've fully understood your scenario, Hmm. Well, it think it's an important example, so I'll try again. First, we have thread A which we KNOW is waiting on a condition. As soon as it becomes unblocked for any reason, we will know because it will set a flag. Since the flag is not set, we are 100% confident that thread A is waiting on the condition. We have another thread, thread B, which has acquired the mutex and is about to wait on the condition. Thus it is pretty clear that at any point, either just A is waiting, or A and B are waiting. Now thread C comes along. C is about to do a broadcast on the condition. A broadcast is guaranteed to unblock all threads currently waiting on a condition, right? Again, we said that either just A is waiting, or A and B are both waiting. So, when C does its broadcast, depending upon whether B has started waiting or not, thread C will unblock A or unblock A and B. Either way, C must unblock A, right? Now, you said anything that happens is correct so long as a) "a signal is not lost between unlocking the mutex and waiting on the condition" and b) "a thread must not steal a signal it sent", correct? Requirement b) is easy to satisfy: in this scenario, thread C will never wait on the condition, so it won't steal any signals. Requirement a) is not hard either. The only way we could fail to meet requirement a) in this scenario is if thread B was started waiting but didn't wake up because a signal was lost. This will not happen. Now, here is what happens. Assume thread C beats thread B. Thread C looks to see how many threads are waiting on the condition. Thread C sees just one thread, thread A, waiting. It does a broadcast waking up just one thread because just one thread is waiting. Next, before A can become unblocked, thread B begins waiting. Now there are two threads waiting, but only one will be unblocked. Suppose B wins. B will become unblocked. A will not become unblocked, because C only unblocked one thread (sema_post cond, 1). So at the end, B finishes and A remains blocked. We have met both of your requirements, so by your rules, this is an acceptable outcome. However, I think that the spec says this is an unacceptable outcome! We know for certain that A was waiting and that C did a broadcast, but A did not become unblocked! Yet, the spec says that a broadcast wakes up all waiting threads. This did not happen. Do you agree that this shows your rules are not strict enough? > and what about N2? :) this one does allow almost everything. Don't get me started about rule #2. I'll NEVER advocate an algorithm that uses rule 2 as an excuse to suck! > but it is done (decrement)under mutex protection - this is not a subject > of a race condition. You are correct. My mistake. > i would remove "_bTimedOut=false".. after all, it was a real timeout.. I disagree. A thread that can't successfully retract its waiter status can't really have timed out. If a thread can't return without executing extra code to deal with the fact that someone tried to unblock it, I think it is a poor idea to pretend we didn't realize someone was trying to signal us. After all, a signal is more important than a time out. > when nSignaled != 0, it is possible to update nWaiters (--) and do not > touch nGone I realize this, but I was thinking that writing it the other ways saves another if statement. > adjust only if nGone != 0 and save one cache memory write - probably much slower than 'if' Hmm. You are probably right. > well, in a strange (e.g. timeout test) program you may (theoretically) > have an overflow of nWaiters/nGone counters (with waiters repeatedly timing > out and no signals at all). Also true. Not only that, but you also have the possibility that one could overflow the number of waiters as well! However, considering the limit you have chosen for nWaitersGone, I suppose it is unlikely that anyone would be able to get INT_MAX/2 threads waiting on a single condition. :) Analysis of 8a: It looks correct to me. What are IPC semaphores? In the line where you state, "else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!" there is no race condition for nWaitersGone because nWaitersGone is never modified without holding mtxUnblockLock. You are correct that there is a harmless race on nWaitersBlocked, which can increase and make the condition become true just after we check it. If this happens, we interpret it as the wait starting after the signal. I like your optimization of this. You could improve Alg. 6 as follows: ---------- Algorithm 6b ---------- signal(bAll) { _nSig=0 lock counters // this is safe because nWaiting can only be decremented by a thread that // owns counters and nGone can only be changed by a thread that owns counters. if (nWaiting>nGone) { if (0==nSignaled) { sema_wait gate // close gate if not already closed } if (nGone>0) { nWaiting-=nGone nGone=0 } _nSig=bAll?nWaiting:1 nSignaled+=_nSig nWaiting-=_nSig } unlock counters if (0!=_nSig) { sema_post queue, _nSig } } ---------- ---------- ---------- I guess this wouldn't apply to Alg 8a because nWaitersGone changes meanings depending upon whether the gate is open or closed. In the loop "while ( nWaitersWasGone-- ) {" you do a sema_wait on semBlockLock. Perhaps waiting on semBlockQueue would be a better idea. What have you gained by making the last thread to be signaled do the waits for all the timed out threads, besides added complexity? It took me a long time to figure out what your objective was with this, to realize you were using nWaitersGone to mean two different things, and to verify that you hadn't introduced any bug by doing this. Even now I'm not 100% sure. What has all this playing about with nWaitersGone really gained us besides a lot of complexity (it is much harder to verify that this solution is correct), execution overhead (we now have a lot more if statements to evaluate), and space overhead (more space for the extra code, and another integer in our data)? We did manage to save a lock/unlock pair in an uncommon case (when a time out occurs) at the above mentioned expenses in the common cases. As for 8b, c, and d, they look ok though I haven't studied them thoroughly. What would you use them for? Later, -Louis! :) nyquist-3.05/liblo/pthreads.2/pthread_rwlockattr_getpshared.c0000644000175000000620000000657011512143043023515 0ustar stevestaff/* * pthread_rwlockattr_getpshared.c * * Description: * This translation unit implements read/write lock primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in 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 "pthread.h" #include "implement.h" int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, int *pshared) /* * ------------------------------------------------------ * DOCPUBLIC * Determine whether rwlocks created with 'attr' can be * shared between processes. * * PARAMETERS * attr * pointer to an instance of pthread_rwlockattr_t * * pshared * will be set to one of: * * PTHREAD_PROCESS_SHARED * May be shared if in shared memory * * PTHREAD_PROCESS_PRIVATE * Cannot be shared. * * * DESCRIPTION * Rwlocks creatd with 'attr' can be shared between * processes if pthread_rwlock_t variable is allocated * in memory shared by these processes. * NOTES: * 1) pshared rwlocks MUST be allocated in shared * memory. * 2) The following macro is defined if shared rwlocks * are supported: * _POSIX_THREAD_PROCESS_SHARED * * RESULTS * 0 successfully retrieved attribute, * EINVAL 'attr' is invalid, * * ------------------------------------------------------ */ { int result; if ((attr != NULL && *attr != NULL) && (pshared != NULL)) { *pshared = (*attr)->pshared; result = 0; } else { result = EINVAL; } return (result); } /* pthread_rwlockattr_getpshared */ nyquist-3.05/liblo/pthreads.2/mutex.c0000644000175000000620000000423311512143043016540 0ustar stevestaff/* * mutex.c * * Description: * This translation unit implements mutual exclusion (mutex) primitives. * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * 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 in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef _UWIN # include #endif #ifndef NEED_FTIME #include #endif #include "pthread.h" #include "implement.h" #include "ptw32_mutex_check_need_init.c" #include "pthread_mutex_init.c" #include "pthread_mutex_destroy.c" #include "pthread_mutexattr_init.c" #include "pthread_mutexattr_destroy.c" #include "pthread_mutexattr_getpshared.c" #include "pthread_mutexattr_setpshared.c" #include "pthread_mutexattr_settype.c" #include "pthread_mutexattr_gettype.c" #include "pthread_mutex_lock.c" #include "pthread_mutex_timedlock.c" #include "pthread_mutex_unlock.c" #include "pthread_mutex_trylock.c" nyquist-3.05/liblo/AUTHORS0000644000175000000620000000150311467003724014337 0ustar stevestaffSteve Harris Nicholas J Humfrey Uwe Koloska Jesse Chappell Topher Cyll Sze'kelyi Szabolcs Camille Troillard Chris Hixon Kentaro Fukuchi Dave Robillard Nicolas Humfrey Stephen Sinclair Dominic Sacré Alex McLean Mike Wozniewski Guidelines for authors: As liblo is an implementation of a fairly widespread protocol I'd like to keep any changes in check to try to prevent it deviating too far from the agreed OSC standard and the intended niche of liblo (ie. easy to use). To help that, please try to follow the following guidelines: * Keep to the current, fairly minimal, OO-C API style where possible * Document any API changes in Doxygen style. my current docs aren't great, but the're better than nothing :) * Update the ChangeLog whenever neccesary. * Add tests for any changes or discovered bugs to the regression test file. nyquist-3.05/liblo/autogen.sh0000755000175000000620000000635611466705460015310 0ustar stevestaff#!/bin/sh # Run this to generate all the initial makefiles, etc. srcdir=`dirname $0` test -z "$srcdir" && srcdir=. DIE=0 (test -f $srcdir/configure.ac) || { echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" echo " top-level package directory" exit 1 } (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`autoconf' installed." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" DIE=1 } (grep "^AM_PROG_LIBTOOL" $srcdir/configure.ac >/dev/null) && { (libtoolize --version) < /dev/null > /dev/null 2>&1 \ && LIBTOOLIZE=libtoolize || { (glibtoolize --version) < /dev/null > /dev/null 2>&1 \ && LIBTOOLIZE=glibtoolize || { echo echo "**Error**: You must have \`libtool' installed." echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" DIE=1 } } } (automake --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: You must have \`automake' installed." echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" DIE=1 NO_AUTOMAKE=yes } # if no automake, don't bother testing for aclocal test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: Missing \`aclocal'. The version of \`automake'" echo "installed doesn't appear recent enough." echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" DIE=1 } if test "$DIE" -eq 1; then exit 1 fi if test -z "$*"; then echo "**Warning**: I am going to run \`configure' with no arguments." echo "If you wish to pass any to it, please specify them on the" echo \`$0\'" command line." echo fi case $CC in xlc ) am_opt=--include-deps;; esac for coin in `find $srcdir -name configure.ac -print` do dr=`dirname $coin` if test -f $dr/NO-AUTO-GEN; then echo skipping $dr -- flagged as no auto-gen else echo processing $dr ( cd $dr aclocalinclude="$ACLOCAL_FLAGS" if grep "^AM_GLIB_GNU_GETTEXT" configure.ac >/dev/null; then echo "Creating $dr/aclocal.m4 ..." test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 echo "Running glib-gettextize... Ignore non-fatal messages." echo "no" | glib-gettextize --force --copy echo "Making $dr/aclocal.m4 writable ..." test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 fi if grep "^AC_PROG_INTLTOOL" configure.ac >/dev/null; then echo "Running intltoolize..." intltoolize --copy --force --automake fi if grep "^AM_PROG_LIBTOOL" configure.ac >/dev/null; then if test -z "$NO_LIBTOOLIZE" ; then echo "Running libtoolize..." $LIBTOOLIZE --force --copy fi fi echo "Running aclocal $aclocalinclude ..." aclocal $aclocalinclude if grep "^AM_CONFIG_HEADER" configure.ac >/dev/null; then echo "Running autoheader..." autoheader fi echo "Running automake --gnu $am_opt ..." automake --add-missing --gnu $am_opt echo "Running autoconf ..." autoconf ) fi done conf_flags="--enable-maintainer-mode" if test x$NOCONFIGURE = x; then echo Running $srcdir/configure $conf_flags "$@" ... $srcdir/configure $conf_flags "$@" \ && echo Now type \`make\' to compile. || exit 1 else echo Skipping configure process. fi nyquist-3.05/liblo/config.guess0000755000175000000620000013226411515462141015614 0ustar stevestaff#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2009-04-27' # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd | genuineintel) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nyquist-3.05/liblo/examples/0002755000175000000620000000000011537433130015104 5ustar stevestaffnyquist-3.05/liblo/examples/Makefile.in0000644000175000000620000003652211515462141017157 0ustar stevestaff# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = example_server$(EXEEXT) example_client$(EXEEXT) \ nonblocking_server_example$(EXEEXT) subdir = examples DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) am_example_client_OBJECTS = example_client.$(OBJEXT) example_client_OBJECTS = $(am_example_client_OBJECTS) example_client_DEPENDENCIES = ../src/liblo.la am_example_server_OBJECTS = example_server.$(OBJEXT) example_server_OBJECTS = $(am_example_server_OBJECTS) example_server_DEPENDENCIES = ../src/liblo.la am_nonblocking_server_example_OBJECTS = \ nonblocking_server_example.$(OBJEXT) nonblocking_server_example_OBJECTS = \ $(am_nonblocking_server_example_OBJECTS) nonblocking_server_example_DEPENDENCIES = ../src/liblo.la DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(example_client_SOURCES) $(example_server_SOURCES) \ $(nonblocking_server_example_SOURCES) DIST_SOURCES = $(example_client_SOURCES) $(example_server_SOURCES) \ $(nonblocking_server_example_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOXYGEN = @DOXYGEN@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LO_SO_VERSION = @LO_SO_VERSION@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in AM_CFLAGS = -Wall -I@top_srcdir@ example_server_SOURCES = example_server.c example_server_LDADD = ../src/liblo.la example_client_SOURCES = example_client.c example_client_LDADD = ../src/liblo.la nonblocking_server_example_SOURCES = nonblocking_server_example.c nonblocking_server_example_LDADD = ../src/liblo.la all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu examples/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list example_client$(EXEEXT): $(example_client_OBJECTS) $(example_client_DEPENDENCIES) @rm -f example_client$(EXEEXT) $(LINK) $(example_client_OBJECTS) $(example_client_LDADD) $(LIBS) example_server$(EXEEXT): $(example_server_OBJECTS) $(example_server_DEPENDENCIES) @rm -f example_server$(EXEEXT) $(LINK) $(example_server_OBJECTS) $(example_server_LDADD) $(LIBS) nonblocking_server_example$(EXEEXT): $(nonblocking_server_example_OBJECTS) $(nonblocking_server_example_DEPENDENCIES) @rm -f nonblocking_server_example$(EXEEXT) $(LINK) $(nonblocking_server_example_OBJECTS) $(nonblocking_server_example_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/example_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/example_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonblocking_server_example.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nyquist-3.05/liblo/examples/nonblocking_server_example.c0000644000175000000620000001147611467003724022667 0ustar stevestaff/* * nonblocking_server_example.c * * This code demonstrates two methods of monitoring both an lo_server * and other I/O from a single thread. * * Copyright (C) 2004 Steve Harris, Uwe Koloska * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include #include #include #include "lo/lo.h" int done = 0; void error(int num, const char *m, const char *path); int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); int foo_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); void read_stdin(void); int main() { int lo_fd; fd_set rfds; struct timeval tv; int retval; /* start a new server on port 7770 */ lo_server s = lo_server_new("7770", error); /* add method that will match any path and args */ lo_server_add_method(s, NULL, NULL, generic_handler, NULL); /* add method that will match the path /foo/bar, with two numbers, coerced * to float and int */ lo_server_add_method(s, "/foo/bar", "fi", foo_handler, NULL); /* add method that will match the path /quit with no args */ lo_server_add_method(s, "/quit", "", quit_handler, NULL); /* get the file descriptor of the server socket, if supported */ lo_fd = lo_server_get_socket_fd(s); if (lo_fd > 0) { /* select() on lo_server fd is supported, so we'll use select() * to watch both stdin and the lo_server fd. */ do { FD_ZERO(&rfds); #ifndef WIN32 FD_SET(0, &rfds); /* stdin */ #endif FD_SET(lo_fd, &rfds); retval = select(lo_fd + 1, &rfds, NULL, NULL, NULL); /* no timeout */ if (retval == -1) { printf("select() error\n"); exit(1); } else if (retval > 0) { if (FD_ISSET(0, &rfds)) { read_stdin(); } if (FD_ISSET(lo_fd, &rfds)) { lo_server_recv_noblock(s, 0); } } } while (!done); } else { /* lo_server protocol does not support select(), so we'll watch * stdin while polling the lo_server. */ #ifdef WIN32 printf("non-blocking input from stdin not supported under Windows\n"); exit(1); #else do { FD_ZERO(&rfds); FD_SET(0, &rfds); tv.tv_sec = 0; tv.tv_usec = 10000; retval = select(1, &rfds, NULL, NULL, &tv); /* timeout every 10ms */ if (retval == -1) { printf("select() error\n"); exit(1); } else if (retval > 0 && FD_ISSET(0, &rfds)) { read_stdin(); } lo_server_recv_noblock(s, 0); } while (!done); #endif } return 0; } void error(int num, const char *msg, const char *path) { printf("liblo server error %d in path %s: %s\n", num, path, msg); } /* catch any incoming messages and display them. returning 1 means that the * message has not been fully handled and the server should try other methods */ int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { int i; printf("path: <%s>\n", path); for (i=0; if, argv[1]->i); fflush(stdout); return 0; } int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { done = 1; printf("quiting\n\n"); return 0; } void read_stdin(void) { char buf[256]; int len = read(0, buf, 256); if (len > 0) { printf("stdin: "); fwrite(buf, len, 1, stdout); printf("\n"); fflush(stdout); } } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/examples/example_server.c0000644000175000000620000000564411467003724020304 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris, Uwe Koloska * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include "lo/lo.h" int done = 0; void error(int num, const char *m, const char *path); int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); int foo_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); int main() { /* start a new server on port 7770 */ lo_server_thread st = lo_server_thread_new("7770", error); /* add method that will match any path and args */ lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL); /* add method that will match the path /foo/bar, with two numbers, coerced * to float and int */ lo_server_thread_add_method(st, "/foo/bar", "fi", foo_handler, NULL); /* add method that will match the path /quit with no args */ lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL); lo_server_thread_start(st); while (!done) { #ifdef WIN32 Sleep(1); #else usleep(1000); #endif } lo_server_thread_free(st); return 0; } void error(int num, const char *msg, const char *path) { printf("liblo server error %d in path %s: %s\n", num, path, msg); fflush(stdout); } /* catch any incoming messages and display them. returning 1 means that the * message has not been fully handled and the server should try other methods */ int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { int i; printf("path: <%s>\n", path); for (i=0; if, argv[1]->i); fflush(stdout); return 0; } int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { done = 1; printf("quiting\n\n"); fflush(stdout); return 0; } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/examples/example_client.c0000644000175000000620000000407411467003724020250 0ustar stevestaff/* * Copyright (C) 2004 Steve Harris, Uwe Koloska * * This program 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.1 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 Lesser General Public License for more details. * * $Id$ */ #include #include #include #include "lo/lo.h" const char testdata[5] = "ABCDE"; int main(int argc, char *argv[]) { /* build a blob object from some data */ lo_blob btest = lo_blob_new(sizeof(testdata), testdata); /* an address to send messages to. sometimes it is better to let the server * pick a port number for you by passing NULL as the last argument */ // lo_address t = lo_address_new_from_url( "osc.unix://localhost/tmp/mysocket" ); lo_address t = lo_address_new(NULL, "7770"); if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'q') { /* send a message with no arguments to the path /quit */ if (lo_send(t, "/quit", NULL) == -1) { printf("OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t)); } } else { /* send a message to /foo/bar with two float arguments, report any * errors */ if (lo_send(t, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) { printf("OSC error %d: %s\n", lo_address_errno(t), lo_address_errstr(t)); } /* send a message to /a/b/c/d with a mixtrure of float and string * arguments */ lo_send(t, "/a/b/c/d", "sfsff", "one", 0.12345678f, "three", -0.00000023001f, 1.0); /* send a 'blob' object to /a/b/c/d */ lo_send(t, "/a/b/c/d", "b", btest); /* send a jamin scene change instruction with a 32bit integer argument */ lo_send(t, "/jamin/scene", "i", 2); } return 0; } /* vi:set ts=8 sts=4 sw=4: */ nyquist-3.05/liblo/examples/Makefile.am0000644000175000000620000000065211466705460017152 0ustar stevestaffMAINTAINERCLEANFILES = Makefile.in noinst_PROGRAMS = example_server example_client nonblocking_server_example AM_CFLAGS = -Wall -I@top_srcdir@ example_server_SOURCES = example_server.c example_server_LDADD = ../src/liblo.la example_client_SOURCES = example_client.c example_client_LDADD = ../src/liblo.la nonblocking_server_example_SOURCES = nonblocking_server_example.c nonblocking_server_example_LDADD = ../src/liblo.la nyquist-3.05/liblo/ltmain.sh0000755000175000000620000073306011515462141015120 0ustar stevestaff# Generated from ltmain.m4sh. # ltmain.sh (GNU libtool) 2.2.6b # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print informational messages (default) # --version print version information # -h, --help print short or long help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.2.6b # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . PROGRAM=ltmain.sh PACKAGE=libtool VERSION=2.2.6b TIMESTAMP="" package_revision=1.3017 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # NLS nuisances: We save the old values to restore during execute mode. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done $lt_unset CDPATH : ${CP="cp -f"} : ${ECHO="echo"} : ${EGREP="/bin/grep -E"} : ${FGREP="/bin/grep -F"} : ${GREP="/bin/grep"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SED="/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } # Generated shell functions inserted here. # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" # The name of this program: # In the unlikely event $progname began with a '-', it would play havoc with # func_echo (imagine progname=-n), so we prepend ./ in that case: func_dirname_and_basename "$progpath" progname=$func_basename_result case $progname in -*) progname=./$progname ;; esac # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=: for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname${mode+: }$mode: $*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` done my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "X$my_tmpdir" | $Xsed } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "X$1" | $Xsed \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_version # Echo version message to standard output and exit. func_version () { $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $SED -n '/^# Usage:/,/# -h/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" $ECHO $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help # Echo long help message to standard output and exit. func_help () { $SED -n '/^# Usage:/,/# Report bugs to/ { s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ p }' < "$progpath" exit $? } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { func_error "missing argument for $1" exit_cmd=exit } exit_cmd=: # Check that we have a working $ECHO. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then # Yippee, $ECHO works! : else # Restart under the correct shell, and then maybe $ECHO will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # Parse options once, thoroughly. This comes as soon as possible in # the script to make things like `libtool --version' happen quickly. { # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Parse non-mode specific arguments: while test "$#" -gt 0; do opt="$1" shift case $opt in --config) func_config ;; --debug) preserve_args="$preserve_args $opt" func_echo "enabling shell trace mode" opt_debug='set -x' $opt_debug ;; -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break execute_dlfiles="$execute_dlfiles $1" shift ;; --dry-run | -n) opt_dry_run=: ;; --features) func_features ;; --finish) mode="finish" ;; --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break case $1 in # Valid mode arguments: clean) ;; compile) ;; execute) ;; finish) ;; install) ;; link) ;; relink) ;; uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac mode="$1" shift ;; --preserve-dup-deps) opt_duplicate_deps=: ;; --quiet|--silent) preserve_args="$preserve_args $opt" opt_silent=: ;; --verbose| -v) preserve_args="$preserve_args $opt" opt_silent=false ;; --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break preserve_args="$preserve_args $opt $1" func_enable_tag "$1" # tagname is set here shift ;; # Separate optargs to long options: -dlopen=*|--mode=*|--tag=*) func_opt_split "$opt" set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} shift ;; -\?|-h) func_usage ;; --help) opt_help=: ;; --version) func_version ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) nonopt="$opt" break ;; esac done case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_duplicate_deps ;; esac # Having warned about all mis-specified options, bail out if # anything was wrong. $exit_cmd $EXIT_FAILURE } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } ## ----------- ## ## Main. ## ## ----------- ## $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi test -z "$mode" && func_fatal_error "error: you must specify a MODE." # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$mode' for more information." } # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_ltwrapper_scriptname_result="" if func_ltwrapper_executable_p "$1"; then func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" fi } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_quote_for_eval "$arg" CC_quoted="$CC_quoted $func_quote_for_eval_result" done case "$@ " in " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T <?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi removelist="$removelist $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist removelist="$removelist $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir command="$command -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$mode'" ;; esac $ECHO $ECHO "Try \`$progname --help' for more information about other modes." exit $? } # Now that we've collected a possible --mode arg, show help if necessary $opt_help && func_mode_help # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $execute_dlfiles; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_quote_for_eval "$file" args="$args $func_quote_for_eval_result" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" $ECHO "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS $ECHO "X----------------------------------------------------------------------" | $Xsed $ECHO "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done $ECHO $ECHO "If you ever happen to want to link against installed libraries" $ECHO "in a given directory, LIBDIR, you must either use libtool, and" $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" $ECHO "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" $ECHO " during execution" fi if test -n "$runpath_var"; then $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" $ECHO " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $ECHO $ECHO "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" $ECHO "pages." ;; *) $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac $ECHO "X----------------------------------------------------------------------" | $Xsed exit $EXIT_SUCCESS } test "$mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $ECHO "X$nonopt" | $GREP shtool >/dev/null; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" install_prog="$install_prog$func_quote_for_eval_result" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) case " $install_prog " in *[\\\ /]cp\ *) ;; *) prev=$arg ;; esac ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" install_prog="$install_prog $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for progfile in $progfiles; do func_verbose "extracting global C symbols from \`$progfile'" $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" } done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" fi $ECHO >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; " case $host in *cygwin* | *mingw* | *cegcc* ) $ECHO >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */" lt_dlsym_const= ;; *osf5*) echo >> "$output_objdir/$my_dlsyms" "\ /* This system does not cope well with relocations in const data */" lt_dlsym_const= ;; *) lt_dlsym_const=const ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ extern $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; $lt_dlsym_const lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac $ECHO >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) symtab_cflags="$symtab_cflags $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper_part1 [arg=no] # # Emit the first part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part1 () { func_emit_wrapper_part1_arg1=no if test -n "$1" ; then func_emit_wrapper_part1_arg1=$1 fi $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then ECHO=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then # Yippee, \$ECHO works! : else # Restart under the correct shell, and then maybe \$ECHO will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $ECHO "\ # Find the directory that this script lives in. thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done " } # end: func_emit_wrapper_part1 # func_emit_wrapper_part2 [arg=no] # # Emit the second part of a libtool wrapper script on stdout. # For more information, see the description associated with # func_emit_wrapper(), below. func_emit_wrapper_part2 () { func_emit_wrapper_part2_arg1=no if test -n "$1" ; then func_emit_wrapper_part2_arg1=$1 fi $ECHO "\ # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # end: func_emit_wrapper_part2 # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=no if test -n "$1" ; then func_emit_wrapper_arg1=$1 fi # split this up so that func_emit_cwrapperexe_src # can call each part independently. func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" } # func_to_host_path arg # # Convert paths to host format when used with build tools. # Intended for use with "native" mingw (where libtool itself # is running under the msys shell), or in the following cross- # build environments: # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # where wine is equipped with the `winepath' executable. # In the native mingw case, the (msys) shell automatically # converts paths for any non-msys applications it launches, # but that facility isn't available from inside the cwrapper. # Similar accommodations are necessary for $host mingw and # $build cygwin. Calling this function does no harm for other # $host/$build combinations not listed above. # # ARG is the path (on $build) that should be converted to # the proper representation for $host. The result is stored # in $func_to_host_path_result. func_to_host_path () { func_to_host_path_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' case $build in *mingw* ) # actually, msys # awkward: cmd appends spaces to result lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_path_tmp1=`( cmd //c echo "$1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_path_tmp1=`cygpath -w "$1"` func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # Unfortunately, winepath does not exit with a non-zero # error code, so we are forced to check the contents of # stdout. On the other hand, if the command is not # found, the shell will set an exit code of 127 and print # *an error message* to stdout. So we must check for both # error code of zero AND non-empty stdout, which explains # the odd construction: func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ $SED -e "$lt_sed_naive_backslashify"` else # Allow warning below. func_to_host_path_result="" fi ;; esac if test -z "$func_to_host_path_result" ; then func_error "Could not determine host path corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_path_result="$1" fi ;; esac fi } # end: func_to_host_path # func_to_host_pathlist arg # # Convert pathlists to host format when used with build tools. # See func_to_host_path(), above. This function supports the # following $build/$host combinations (but does no harm for # combinations not listed here): # $build $host # mingw (msys) mingw [e.g. native] # cygwin mingw # *nix + wine mingw # # Path separators are also converted from $build format to # $host format. If ARG begins or ends with a path separator # character, it is preserved (but converted to $host format) # on output. # # ARG is a pathlist (on $build) that should be converted to # the proper representation on $host. The result is stored # in $func_to_host_pathlist_result. func_to_host_pathlist () { func_to_host_pathlist_result="$1" if test -n "$1" ; then case $host in *mingw* ) lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_to_host_pathlist_tmp2="$1" # Once set for this call, this variable should not be # reassigned. It is used in tha fallback case. func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e 's|^:*||' -e 's|:*$||'` case $build in *mingw* ) # Actually, msys. # Awkward: cmd appends spaces to result. lt_sed_strip_trailing_spaces="s/[ ]*\$//" func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; *cygwin* ) func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ $SED -e "$lt_sed_naive_backslashify"` ;; * ) # unfortunately, winepath doesn't convert pathlists func_to_host_pathlist_result="" func_to_host_pathlist_oldIFS=$IFS IFS=: for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do IFS=$func_to_host_pathlist_oldIFS if test -n "$func_to_host_pathlist_f" ; then func_to_host_path "$func_to_host_pathlist_f" if test -n "$func_to_host_path_result" ; then if test -z "$func_to_host_pathlist_result" ; then func_to_host_pathlist_result="$func_to_host_path_result" else func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" fi fi fi IFS=: done IFS=$func_to_host_pathlist_oldIFS ;; esac if test -z "$func_to_host_pathlist_result" ; then func_error "Could not determine the host path(s) corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This may break if $1 contains DOS-style drive # specifications. The fix is not to complicate the expression # below, but for the user to provide a working wine installation # with winepath so that path translation in the cross-to-mingw # case works properly. lt_replace_pathsep_nix_to_dos="s|:|;|g" func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ $SED -e "$lt_replace_pathsep_nix_to_dos"` fi # Now, add the leading and trailing path separators back case "$1" in :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" ;; esac case "$1" in *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" ;; esac ;; esac fi } # end: func_to_host_pathlist # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include # define setmode _setmode #else # include # include # ifdef __CYGWIN__ # include # define HAVE_SETENV # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif # endif #endif #include #include #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif #ifdef _MSC_VER # define S_IXUSR _S_IEXEC # define stat _stat # ifndef _INTPTR_T_DEFINED # define intptr_t int # endif #endif #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifdef __CYGWIN__ # define FOPEN_WB "wb" #endif #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #undef LTWRAPPER_DEBUGPRINTF #if defined DEBUGWRAPPER # define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args static void ltwrapper_debugprintf (const char *fmt, ...) { va_list args; va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } #else # define LTWRAPPER_DEBUGPRINTF(args) #endif const char *program_name = NULL; void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_fatal (const char *message, ...); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_opt_process_env_set (const char *arg); void lt_opt_process_env_prepend (const char *arg); void lt_opt_process_env_append (const char *arg); int lt_split_name_value (const char *arg, char** name, char** value); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); static const char *script_text_part1 = EOF func_emit_wrapper_part1 yes | $SED -e 's/\([\\"]\)/\\\1/g' \ -e 's/^/ "/' -e 's/$/\\n"/' echo ";" cat <"))); for (i = 0; i < newargc; i++) { LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); } EOF case $host_os in mingw*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); if (rval == -1) { /* failed to start process */ LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); return 127; } return rval; EOF ;; *) cat <<"EOF" execv (lt_argv_zero, newargz); return rval; /* =127, but avoids unused variable warning */ EOF ;; esac cat <<"EOF" } void * xmalloc (size_t num) { void *p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL; } const char * base_name (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha ((unsigned char) name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return base; } int check_executable (const char *path) { struct stat st; LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if ((stat (path, &st) >= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!")); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", tmp_pathspec)); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { char *errstr = strerror (errno); lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal ("Could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } void lt_setenv (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", (name ? name : ""), (value ? value : ""))); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } int lt_split_name_value (const char *arg, char** name, char** value) { const char *p; int len; if (!arg || !*arg) return 1; p = strchr (arg, (int)'='); if (!p) return 1; *value = xstrdup (++p); len = strlen (arg) - strlen (*value); *name = XMALLOC (char, len); strncpy (*name, arg, len-1); (*name)[len - 1] = '\0'; return 0; } void lt_opt_process_env_set (const char *arg) { char *name = NULL; char *value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); } lt_setenv (name, value); XFREE (name); XFREE (value); } void lt_opt_process_env_prepend (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); } new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_opt_process_env_append (const char *arg) { char *name = NULL; char *value = NULL; char *new_value = NULL; if (lt_split_name_value (arg, &name, &value) != 0) { XFREE (name); XFREE (value); lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); } new_value = lt_extend_str (getenv (name), value, 1); lt_setenv (name, new_value); XFREE (new_value); XFREE (name); XFREE (value); } void lt_update_exe_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", (name ? name : ""), (value ? value : ""))); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF } # end: func_emit_cwrapperexe_src # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) deplibs="$deplibs $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) weak_libs="$weak_libs $arg" prev= continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname '-L' '' "$arg" dir=$func_stripname_result if test -z "$dir"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) dllsearchpath="$dllsearchpath:$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" arg="$arg $wl$func_quote_for_eval_result" compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" linker_flags="$linker_flags $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # -64, -mips[0-9] enable 64-bit mode on the SGI compiler # -r[0-9][0-9]* specifies the processor on the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler # +DA*, +DD* enable 64-bit mode on the HP compiler # -q* pass through compiler args for the IBM compiler # -m*, -t[45]*, -txscale* pass through architecture-specific # compiler args for GCC # -F/path gives path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC # @file GCC response files -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" compiler_flags="$compiler_flags $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_duplicate_deps ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= case $lib in *.la) func_source "$lib" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` case " $weak_libs " in *" $deplib_base "*) ;; *) deplibs="$deplibs $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else compiler_flags="$compiler_flags $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" dir=$func_stripname_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then $ECHO $ECHO "*** Warning: Trying to link with static lib archive $deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because the file extensions .$libext of this argument makes me believe" $ECHO "*** that it is just a static archive that I should not use here." else $ECHO $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" newlib_search_path="$newlib_search_path $func_stripname_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) temp_rpath="$temp_rpath$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no ;; *) if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then $ECHO if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $ECHO $ECHO "*** And there doesn't seem to be a static archive available" $ECHO "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $ECHO $ECHO "*** Warning: This system can not link to static lib archive $lib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $ECHO "*** But as you try to build a module library, libtool will still create " $ECHO "*** a static module, that should work as long as the dlopening application" $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if $opt_duplicate_deps ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do case $deplib in -L*) path="$deplib" ;; *.la) func_dirname "$deplib" "" "." dir="$func_dirname_result" # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else $ECHO $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" libobjs="$libobjs $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $ECHO $ECHO "*** Warning: linker path does not have real file for library $a_deplib." $ECHO "*** I have the capability to make that library automatically link in when" $ECHO "*** you link to this library. But I can only do this if you have a" $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` done fi if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | $GREP . >/dev/null; then $ECHO if test "X$deplibs_check_method" = "Xnone"; then $ECHO "*** Warning: inter-library dependencies are not supported in this platform." else $ECHO "*** Warning: inter-library dependencies are not known to be supported." fi $ECHO "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $ECHO $ECHO "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" $ECHO "*** a static module, that should work as long as the dlopening" $ECHO "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $ECHO $ECHO "*** However, this would only work if libtool was able to extract symbol" $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" $ECHO "*** not find such a program. So, this module is probably useless." $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $ECHO "*** The inter-library dependencies that have been dropped here will be" $ECHO "*** automatically added whenever a program is linked with this library" $ECHO "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $ECHO $ECHO "*** Since this library must not contain undefined symbols," $ECHO "*** because either the platform does not support them or" $ECHO "*** it was explicitly requested with -no-undefined," $ECHO "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" delfiles="$delfiles $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" func_len " $cmd" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then func_show_eval "$cmd" 'exit $?' skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $convenience libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output output_la=`$ECHO "X$output" | $Xsed -e "$basename"` # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" $ECHO 'INPUT (' > $output for obj in $save_libobjs do $ECHO "$obj" >> $output done $ECHO ')' >> $output delfiles="$delfiles $output" elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do $ECHO "$obj" >> $output done delfiles="$delfiles $output" output=$firstobj\"$file_list_spec$output\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=$obj func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi delfiles="$delfiles $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles libobjs="$libobjs $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` else gentop="$output_objdir/${obj}x" generated="$generated $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done compile_deplibs="$new_libs" compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) dllsearchpath="$dllsearchpath:$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *cegcc) # Disable wrappers for cegcc, we are cross compiling anyway. wrappers_required=no ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $ECHO for shipping. if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then case $progpath in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; esac qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then oldobjs="$oldobjs $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $addlibs oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $dlprefiles oldobjs="$oldobjs $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else $ECHO "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" oldobjs="$oldobjs $gentop/$newobj" ;; *) oldobjs="$oldobjs $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlfiles="$newdlfiles $libdir/$name" ;; *) newdlfiles="$newdlfiles $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" newdlprefiles="$newdlprefiles $libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$mode" = link || test "$mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) RM="$RM $arg"; rmforce=yes ;; -*) RM="$RM $arg" ;; *) files="$files $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= origobjdir="$objdir" for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then objdir="$origobjdir" else objdir="$dir/$origobjdir" fi func_basename "$file" name="$func_basename_result" test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" case "$mode" in clean) case " $library_names " in # " " in the beginning catches empty $dlname *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result rmfiles="$rmfiles $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$mode" = uninstall || test "$mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 nyquist-3.05/liblo/Makefile.am0000644000175000000620000000031611515462141015320 0ustar stevestaffSUBDIRS = src examples lo build @DOXYGEN@ EXTRA_DIST = libtool ltmain.sh autogen.sh ACLOCAL_AMFLAGS = -I m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = liblo.pc test: all (cd src && make test) nyquist-3.05/liblo/config.h.in0000644000175000000620000000474511515462141015321 0ustar stevestaff/* config.h.in. Generated from configure.ac by autoheader. */ /* Define this to enable ipv6. */ #undef ENABLE_IPV6 /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if inet_aton() is available. */ #undef HAVE_INET_ATON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if poll() is available. */ #undef HAVE_POLL /* Define to 1 if select() is available. */ #undef HAVE_SELECT /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `unsigned int' if does not define. */ #undef size_t nyquist-3.05/liblo/README0000644000175000000620000000421511467003724014152 0ustar stevestaffliblo is a lightweight library that provides an easy to use implementation of the OSC protocol. For more information about the OSC protocol, please see: - http://www.cnmat.berkeley.edu/OpenSoundControl/ - http://www.opensoundcontrol.org/ The official liblo homepage is here: - http://liblo.sourceforge.net/ liblo is portable to most UNIX systems (including OS X) and Windows. It is released under the GNU Lesser General Public Licence (LGPL). --- To build and install liblo, read INSTALL in the main liblo directory. liblo is configured as a dynamically-linked library. To use liblo in a new application, you should install liblo with "make install" so that the liblo library can be located by your application. To build with MS Visual Studio on Windows, first run the premake4.exe application in the build directory with an argument describing which IDE you are using. This will generate project and solution files. See examples for example source code for a simple client and two servers: - example_server.c uses lo_server_thread_start() to create a liblo server in an separate thread. - nonblocking_server_example.c uses select() to wait for either console input or OSC messages, all in a single thread. - example_client.c uses liblo to send OSC messages to a server. These examples will work without installing liblo. This is accomplished by a shell script. For example, examples/client_example is a shell script that runs the "real" program examples/.libs/example_client. Because of this indirection, you cannot run example_client with a debugger. To debug applications using liblo, one option is to include all the liblo source code in the application rather than linking with the liblo library. For more information about this, please see the libtool's manual: http://www.gnu.org/software/libtool/manual.html#Debugging-executables --- IPv6 NOTICE: liblo was written to support both IPv4 and IPv6, however it has caused various problems along the way because most of the currently available OSC applications like Pd and SuperCollider doesn't listen on ipv6 sockets. IPv6 is currently disabled by default, but you can enable it using ./configure --enable-ipv6nyquist-3.05/liblo/configure0000755000175000000620000140771711515462141015214 0ustar stevestaff#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for liblo 0.26. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: liblo-devel@lists.sourceforge.net about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$lt_ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` ;; esac ECHO=${lt_ECHO-echo} if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then # Yippee, $ECHO works! : else # Restart under the correct shell. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <<_LT_EOF $* _LT_EOF exit 0 fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null then break fi done fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} else # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL ECHO="$CONFIG_SHELL $0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. ECHO=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. lt_ECHO=$ECHO if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" fi test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='liblo' PACKAGE_TARNAME='liblo' PACKAGE_VERSION='0.26' PACKAGE_STRING='liblo 0.26' PACKAGE_BUGREPORT='liblo-devel@lists.sourceforge.net' PACKAGE_URL='' ac_unique_file="src/address.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS DOXYGEN CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL lt_ECHO RANLIB AR OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC LO_SO_VERSION am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_static enable_shared enable_ipv6 enable_dependency_tracking with_pic enable_fast_install with_gnu_ld enable_libtool_lock ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures liblo 0.26 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/liblo] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of liblo 0.26:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-static[=PKGS] build static libraries [default=no] --enable-shared[=PKGS] build shared libraries [default=yes] --enable-ipv6 Enable ipv6 support --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF liblo configure 0.26 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------------------ ## ## Report this to liblo-devel@lists.sourceforge.net ## ## ------------------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by liblo $as_me 0.26, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # libtool version: current:revision:age # # If the library source code has changed at all since the last update, then # increment revision (`c:r:a' becomes `c:r+1:a'). # # If any interfaces have been added, removed, or changed since the last update, # increment current, and set revision to 0. # # If any interfaces have been added since the last public release, then # increment age. # # If any interfaces have been removed since the last public release, then set # age to 0. LO_SO_VERSION=7:0:0 ac_config_headers="$ac_config_headers config.h" am__api_version='1.11' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='liblo' VERSION='0.26' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=no fi # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # disable support for ipv6. # Check whether --enable-ipv6 was given. if test "${enable_ipv6+set}" = set; then : enableval=$enable_ipv6; want_ipv6=yes fi if test "$want_ipv6" = "yes"; then $as_echo "#define ENABLE_IPV6 1" >>confdefs.h fi # Checks for programs. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.2.6b' macro_revision='1.3017' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$ac_tool_prefix"; then for ac_prog in "dumpbin -symbols" "link -dump -symbols" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in "dumpbin -symbols" "link -dump -symbols" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:4634: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:4637: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:4640: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5846 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7315: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7319: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl*) # IBM XL C 8.0/Fortran 10.1 on PPC lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Sun\ F*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 $as_echo "$lt_prog_compiler_pic" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7654: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7658: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7759: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7763: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7814: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7818: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld='-rpath $libdir' archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/ p } }' aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes=yes ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='' link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=echo archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo(void) {} _ACEOF if ac_fn_c_try_link "$LINENO"; then : archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc=no else archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 $as_echo "$archive_cmds_need_lc" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` else lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix[3-9]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Add ABI-specific directories to the system library path. sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 10184 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 10280 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: if test "x$CC" != xcc; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 $as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 $as_echo_n "checking whether cc understands -c and -o together... " >&6; } fi set dummy $CC; ac_cc=`$as_echo "$2" | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # We do the test twice because some compilers refuse to overwrite an # existing .o file with -o, though they will create one. ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then eval ac_cv_prog_cc_${ac_cc}_c_o=yes if test "x$CC" != xcc; then # Test first that cc exists at all. if { ac_try='cc -c conftest.$ac_ext >&5' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # cc works too. : else # cc exists but doesn't like -o. eval ac_cv_prog_cc_${ac_cc}_c_o=no fi fi fi else eval ac_cv_prog_cc_${ac_cc}_c_o=no fi rm -f core conftest* fi if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h fi # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi # Extract the first word of "doxygen", so it can be a program name with args. set dummy doxygen; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DOXYGEN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DOXYGEN"; then ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DOXYGEN="doc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DOXYGEN=$ac_cv_prog_DOXYGEN if test -n "$DOXYGEN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 $as_echo "$DOXYGEN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Checks for libraries. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing recvfrom" >&5 $as_echo_n "checking for library containing recvfrom... " >&6; } if ${ac_cv_search_recvfrom+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char recvfrom (); int main () { return recvfrom (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_recvfrom=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_recvfrom+:} false; then : break fi done if ${ac_cv_search_recvfrom+:} false; then : else ac_cv_search_recvfrom=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_recvfrom" >&5 $as_echo "$ac_cv_search_recvfrom" >&6; } ac_res=$ac_cv_search_recvfrom if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi ac_fn_c_check_func "$LINENO" "log" "ac_cv_func_log" if test "x$ac_cv_func_log" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log in -lm" >&5 $as_echo_n "checking for log in -lm... " >&6; } if ${ac_cv_lib_m_log+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char log (); int main () { return log (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_log=yes else ac_cv_lib_m_log=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_log" >&5 $as_echo "$ac_cv_lib_m_log" >&6; } if test "x$ac_cv_lib_m_log" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi fi # Checks for header files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi for ac_header in netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset cs; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # Check for features ac_fn_c_check_func "$LINENO" "select" "ac_cv_func_select" if test "x$ac_cv_func_select" = xyes; then : $as_echo "#define HAVE_SELECT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for select in ws2_32" >&5 $as_echo_n "checking for select in ws2_32... " >&6; } LIBS="$LIBS -lws2_32" # some winsock2 functions require XP, so WINNT=0x501 CFLAGS="$CFLAGS -DWIN32 -D_WIN32_WINNT=0x501" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { select(0,0,0,0,0) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_SELECT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" if test "x$ac_cv_func_poll" = xyes; then : $as_echo "#define HAVE_POLL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton" if test "x$ac_cv_func_inet_aton" = xyes; then : $as_echo "#define HAVE_INET_ATON 1" >>confdefs.h fi # to make Windows compilation easier, lo/lo_endian.h uses conditional # compilation rather than configure to determine byte order #AC_C_BIGENDIAN([LO_BIGENDIAN="1"], [LO_BIGENDIAN="0"]) #AC_DEFINE_UNQUOTED(LO_BIGENDIAN, "$LO_BIGENDIAN", [If machine is bigendian]) #AC_SUBST(LO_BIGENDIAN) ac_config_files="$ac_config_files Makefile src/Makefile src/tools/Makefile examples/Makefile lo/Makefile lo/lo_endian.h liblo.pc doc/Makefile doc/reference.doxygen build/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by liblo $as_me 0.26, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ liblo config.status 0.26 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # Quote evaled strings. for var in SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ AR \ AR_FLAGS \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ SHELL \ ECHO \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_wl \ lt_prog_compiler_pic \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ fix_srcfile_path \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Fix-up fallback echo if it was mangled by the above quoting rules. case \$lt_ECHO in *'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` ;; esac ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/tools/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/Makefile" ;; "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; "lo/Makefile") CONFIG_FILES="$CONFIG_FILES lo/Makefile" ;; "lo/lo_endian.h") CONFIG_FILES="$CONFIG_FILES lo/lo_endian.h" ;; "liblo.pc") CONFIG_FILES="$CONFIG_FILES liblo.pc" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/reference.doxygen") CONFIG_FILES="$CONFIG_FILES doc/reference.doxygen" ;; "build/Makefile") CONFIG_FILES="$CONFIG_FILES build/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == "file_magic". file_magic_cmd=$lt_file_magic_cmd # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name of the directory that contains temporary libtool files. objdir=$objdir # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that does not interpret backslashes. ECHO=$lt_ECHO # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into a binary # during linking. This must work even if \$libdir does not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path=$lt_fix_srcfile_path # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) case $xsi_shell in yes) cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac } # func_basename file func_basename () { func_basename_result="${1##*/}" } # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}" } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). func_stripname () { # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"} } # func_opt_split func_opt_split () { func_opt_split_opt=${1%%=*} func_opt_split_arg=${1#*=} } # func_lo2o object func_lo2o () { case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac } # func_xform libobj-or-source func_xform () { func_xform_result=${1%.*}.lo } # func_arith arithmetic-term... func_arith () { func_arith_result=$(( $* )) } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=${#1} } _LT_EOF ;; *) # Bourne compatible functions. cat << \_LT_EOF >> "$cfgfile" # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_basename file func_basename () { func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "X${3}" \ | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; esac } # sed scripts: my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^-[^=]*=//' # func_opt_split func_opt_split () { func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` } # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` } # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` } # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "$@"` } # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } _LT_EOF esac case $lt_shell_append in yes) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$1+=\$2" } _LT_EOF ;; *) cat << \_LT_EOF >> "$cfgfile" # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "$1=\$$1\$2" } _LT_EOF ;; esac sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nyquist-3.05/liblo/install-sh0000755000175000000620000003253711515462141015302 0ustar stevestaff#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: nyquist-3.05/doc/0002755000175000000620000000000011537433123012734 5ustar stevestaffnyquist-3.05/doc/fig3.gif0000644000175000000620000000364210144436365014262 0ustar stevestaffGIF87a3,3ڋ޼H扦ʶ L ĢL*̦ JԪjܮ N (8HXhx)9IYiy *:JZjz +;K[k{ ,.}nM~ RO͏__y;TaIP|bIWcEиƈ+B ?fe Mdӛϟ I"ISfΡ &hh1EzӬ=Z JtO^O%{V,~h-5͈"v2י͢fX-A pY'o0G/l^ygՑt.cav랱ܢM󖰻sМ3wqlө$'fٹo_n9x!$9]1|{lVk]X'^7{~7^5H[iWҡuy(v a#&F֡ "m4 !a ];%b%yZyo>Δ/V)!eYqVٗZ"%spA_ vbԛb^ yxNd{w]_YVXɹI$ꨢyie((c*S \^)z)d#T5jj+$,ady %ү|rjeȅ2 -Nd]V%϶jגn jj[,{/˶nlP+kքplnj8Iy,.*%jD eŮnΓT>A(=&aY^1ْhy'!?hwWC+mvpyf}k!Z~~씿;`&_zUGoup>O0KJ+JZF8Uj"O @ gA3eUl2/T qB,p9DZ5GAL`Mh\1\₈ؽ)T1 i"x"ĉc@4Ћ4ظх"8n8ro#0OR'$}'!U9&O0 :.HL(xnjPzr,)OTrl+_ Xr-o\r/ ` s,1d*sl3 hJsԬ5ljs7 ps,9ωtsl; xs'hhB1,$)L-AЄ*t mC шJtE/ьBG? Ґt$-IOz%8-Bu"run[i7ܭ-i]6ޥj{Q+斗~;v7~K7a S_A6 Kx/ kx? x$.O;nyquist-3.05/doc/fig2.gif0000644000175000000620000000333110144436365014254 0ustar stevestaffGIF87aT.,T.ڋ޼H扦ʶ L ĢL*̦ JԪjܮ N 7Hxeh(I$9YytYs)jx:*;kR{K+kK0Y @:\,|5#)v-*e݀>i~[ &?koR_H`A^Q0D0(F4 Ycg !n+Q2QL&v7dgC;YO%iOD5:!jƯr iIسCӢϸFѝn~k>Ջ\7.0}}m-A貉y>T]S)H '޻ //կCKGQhФ໭ wq: j#O;'-/ ,j\: r̽@?kk.; 3F4ϤGWulPc7DC6ӼkjS[W=Ғh_ww.ޖ s1Hv+nBJg3x5uO.zAw#ԺhtZ{EE;99Nf啪IDռRCXEMG)[֚|+AlXYxo_w!+^Jޏ9Ɗ榾mVP'`sG='y}A܆Acdt 7Fʘ@ صPo7c_pXcWDQnw(TLB%I0[DN R" y;#0q9|RDeY"'.1ccG1^r۬hH [ %ު=µ-1#(iEr^c< Y6|(E`mJ(4k1w+b`Uqv\%+{F]~)z$RLTBbnicTime/Frequency Transformation Previous Section | Next Section | Table of Contents | Index | Title Page

Time/Frequency Transformation

Nyquist provides functions for FFT and inverse FFT operations on streams of audio data. Because sounds can be of any length, but an FFT operates on a fixed amount of data, FFT processing is typically done in short blocks or windows that move through the audio. Thus, a stream of samples is converted in to a sequence of FFT frames representing short-term spectra.

Nyquist does not have a special data type corresponding to a sequence of FFT frames. This would be nice, but it would require creating a large set of operations suitable for processing frame sequences. Another approach, and perhaps the most "pure" would be to convert a single sound into a multichannel sound, with one channel per bin of the FFT.

Instead, Nyquist violates its "pure" functional model and resorts to objects for FFT processing. A sequence of frames is represented by an XLISP object. Whenever you send the selector :next to the object, you get back either NIL, indicating the end of the sequence, or you get an array of FFT coefficients.

The Nyquist function snd-fft (mnemonic, isn't it?) returns one of the frame sequence generating objects. You can pass any frame sequence generating object to another function, snd-ifft, and turn the sequence back into audio.

With snd-fft and snd-ifft, you can create all sorts of interesting processes. The main idea is to create intermediate objects that both accept and generate sequences of frames. These objects can operate on the frames to implement the desired spectral-domain processes. Examples of this can be found in the file fft_tutorial.htm, which is part of the standard Nyquist release. The documentation for snd-fft and snd-ifft follows.

snd-fft(sound, length, skip, window) [SAL]
(snd-fft sound length skip window) [LISP]
This function performs an FFT on the first samples in sound and returns a Lisp array of FLONUMs. The function modifies the sound, violating the normal rule that sounds are immutable in Nyquist, so it is advised that you copy the sound using snd-copy if there are any other references to sound. The length of the FFT is specified by length, a FIXNUM (integer) which must be a power of 2. After each FFT, the sound is advanced by skip samples, also of type FIXNUM. Overlapping FFTs, where skip is less than length, are allowed. If window is not NIL, it must be a sound. The first length samples of window are multiplied by length samples of sound before performing the FFT. When there are no more samples in sound to transform, this function returns NIL. The coefficients in the returned array, in order, are the DC coefficient, the first real, the first imaginary, the second real, the second imaginary, etc. The last array element corresponds to the real coefficient at the Nyquist frequency.

snd-ifft(time, srate, iterator, skip, window) [SAL]
(snd-ifft time srate iterator skip window) [LISP]
This function performs an IFFT on a sequence of spectral frames obtained from iterator and returns a sound. The start time of the sound is given by time. Typically, this would be computed by calling (local-to-global 0). The sample rate is given by srate. Typically, this would be *sound-srate*, but it might also depend upon the sample rate of the sound from which the spectral frames were derived. To obtain each frame, the function sends the message :next to the iterator object, using XLISP's primitives for objects and message passing. The object should return an array in the same format as obtained from snd-fft, and the object should return NIL when the end of the sound is reached. After each frame is inverse transformed into the time domain, it is added to the resulting sound. Each successive frame is added with a sample offset specified by skip relative to the previous frame. This must be an integer greater than zero. If window is not NIL, it must be a sound. This window signal is multiplied by the inverse transformed frame before the frame is added to the output sound. The length of each frame should be the same power of 2. The length is implied by the array returned by iterator, so it does not appear as a parameter. This length is also the number of samples used from window. Extra samples are ignored, and window is padded with zeros if necessary, so be sure window is the right length. The resulting sound is computed on demand as with other Nyquist sounds, so :next messages are sent to iterator only when new frames are needed. One should be careful not to reuse or modify iterator once it is passed to snd-ifft.


Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/part5.html0000644000175000000620000003675011537432671014675 0ustar stevestaffContinuous Transformations and Time Warps Previous Section | Next Section | Table of Contents | Index | Title Page

Continuous Transformations and Time Warps

Nyquist transformations were discussed in the previous chapter, but all of the examples used scalar values. For example, we saw the loud transformation used to change loudness by a fixed amount. What if we want to specify a crescendo, where the loudness changes gradually over time?

It turns out that all transformations can accept signals as well as numbers, so transformations can be continuous over time. This raises some interesting questions about how to interpret continuous transformations. Should a loudness transformation apply to the internal details of a note or only affect the initial loudness? It might seem unnatural for a decaying piano note to perform a crescendo. On the other hand, a sustained trumpet sound should probably crescendo continuously. In the case of time warping (tempo changes), it might be best for a drum roll to maintain a steady rate, a trill may or may not change rates with tempo, and a run of sixteenth notes will surely change its rate.

These issues are complex, and Nyquist cannot hope to automatically do the right thing in all cases. However, the concept of behavioral abstraction provides an elegant solution. Since transformations merely modify the environment, behaviors are not forced to implement any particular style of transformation. Nyquist is designed so that the default transformation is usually the right one, but it is always possible to override the default transformation to achieve a particular effect.

Simple Transformations

The "simple" transformations affect some parameter, but have no effect on time itself. The simple transformations that support continuously changing parameters are: sustain, loud, and transpose.

As a first example, Let us use transpose to create a chromatic scale. First define a sequence of tones at a steady pitch. The seqrep "function" works like seq except that it creates copies of a sound by evaluating an expression multiple times. Here, i takes on 16 values from 0 to 15, and the expression for the sound could potentially use i. Technically, seqrep is not really a function but an abbreviation for a special kind of loop construct.

define function tone-seq()
  return seqrep(i, 16,
                osc-note(c4) ~ 0.25)
Now define a linearly increasing ramp to serve as a transposition function: define function pitch-rise() return sustain-abs(1.0, 16 * ramp() ~ 4) This ramp has a duration of 4 seconds, and over that interval it rises from 0 to 16 (corresponding to the 16 semitones we want to transpose). The ramp is inside a sustain-abs transformation, which prevents a sustain transformation from having any effect on the ramp. (One of the drawbacks of behavioral abstraction is that built-in behaviors sometimes do the wrong thing implicitly, requiring some explicit correction to turn off the unwanted transformation.) Now, pitch-rise is used to transpose tone-seq: define function chromatic-scale() return transpose(pitch-rise(), tone-seq())

Similar transformations can be constructed to change the sustain or "duty factor" of notes and their loudness. The following expression plays the chromatic-scale behavior with increasing note durations. The rhythm is unchanged, but the note length changes from staccato to legato: play sustain((0.2 + ramp()) ~ 4, chromatic-scale()) The resulting sustain function will ramp from 0.2 to 1.2. A sustain of 1.2 denotes a 20 percent overlap between notes. The sum has a stretch factor of 4, so it will extend over the 4 second duration of chromatic-scale.

If you try this, you will discover that the chromatic-scale no longer plays a chromatic scale. You will hear the first 4 notes going up in intervals of 5 semitones (perfect fourths) followed by repeated pitches. What is happening is that the sustain operation applies to pitch-rise in addition to tone-seq, so now the 4s ramp from 0 to 16 becomes a 0.8s ramp. To fix this problem, we need to shield pitch-rise from the effect of sustain using the sustain-abs transformation. Here is a corrected version of chromatic-scale: define function chromatic-scale() return transpose(sustain-abs(1, pitch-rise()), tone-seq())

What do these transformations mean? How did the system know to produce a pitch rise rather than a continuous glissando? This all relates to the idea of behavioral abstraction. It is possible to design sounds that do glissando under the transpose transform, and you can even make sounds that ignore transpose altogether. As explained in Chapter "Behavioral Abstraction", the transformations modify the environment, and behaviors can reference the environment to determine what signals to generate. All built-in functions, such as osc, have a default behavior.

The default behavior for sound primitives under transpose, sustain, and loud transformations is to sample the environment at the beginning of the note. Transposition is not quantized to semitones or any other scale, but in our example, we arranged for the transposition to work out to integer numbers of semitones, so we obtained a chromatic scale anyway.

Transposition only applies to the oscillator and sampling primitives osc, partial, sampler, sine, fmosc, and amosc. Sustain applies to osc, env, ramp, and pwl. (Note that partial, amosc, and fmosc get their durations from the modulation signal, so they may indirectly depend upon the sustain.) Loud applies to osc, sampler, cue, sound, fmosc, and amosc. (But not pwl or env.)

Time Warps

The most interesting transformations have to do with transforming time itself. The warp transformation provides a mapping function from logical (score) time to real time. The slope of this function tells us how many units of real time are covered by one unit of score time. This is proportional to 1/tempo. A higher slope corresponds to a slower tempo.

To demonstrate warp, we will define a time warp function using pwl:

define function warper()
  return pwl(0.25, .4, .75, .6, 1.0, 1.0, 2.0, 2.0, 2.0)
This function has an initial slope of .4/.25 = 1.6. It may be easier to think in reciprocal terms: the initial tempo is .25/.4 = .625. Between 0.25 and 0.75, the tempo is .5/.2 = 2.5, and from 0.75 to 1.0, the tempo is again .625. It is important for warp functions to completely span the interval of interest (in our case it will be 0 to 1), and it is safest to extend a bit beyond the interval, so we extend the function on to 2.0 with a tempo of 1.0. Next, we stretch and scale the warper function to cover 4 seconds of score time and 4 seconds of real time:
define function warp4()
  return 4 * warper() ~ 4




Figure 2: The result of (warp4), intended to map 4 seconds of score time into 4 seconds of real time. The function extends beyond 4 seconds (the dashed lines) to make sure the function is well-defined at location (4, 4). Nyquist sounds are ordinarily open on the right.


Figure 2 shows a plot of this warp function. Now, we can warp the tempo of the tone-seq defined above using warp4:

play warp(warp4(), tone-seq())
Figure 3 shows the result graphically. Notice that the durations of the tones are warped as well as their onsets. Envelopes are not shown in detail in the figure. Because of the way env is defined, the tones will have constant attack and decay times, and the sustain will be adjusted to fit the available time.




Figure 3: When (warp4) is applied to (tone-seq-2), the note onsets and durations are warped.


Abstract Time Warps

We have seen a number of examples where the default behavior did the "right thing," making the code straightforward. This is not always the case. Suppose we want to warp the note onsets but not the durations. We will first look at an incorrect solution and discuss the error. Then we will look at a slightly more complex (but correct) solution.

The default behavior for most Nyquist built-in functions is to sample the time warp function at the nominal starting and ending score times of the primitive. For many built-in functions, including osc, the starting logical time is 0 and the ending logical time is 1, so the time warp function is evaluated at these points to yield real starting and stopping times, say 15.23 and 16.79. The difference (e.g. 1.56) becomes the signal duration, and there is no internal time warping. The pwl function behaves a little differently. Here, each breakpoint is warped individually, but the resulting function is linear between the breakpoints.

A consequence of the default behavior is that notes stretch when the tempo slows down. Returning to our example, recall that we want to warp only the note onset times and not the duration. One would think that the following would work:

define function tone-seq-2 ()
  return seqrep(i, 16,
                osc-note(c4) ~~ 0.25)

play warp(warp4(), tone-seq-2())

Here, we have redefined tone-seq, renaming it to tone-seq-2 and changing the stretch (~) to absolute stretch (~~). The absolute stretch should override the warp function and produce a fixed duration.

If you play the example, you will hear steady sixteenths and no tempo changes. What is wrong? In a sense, the "fix" works too well. Recall that sequences (including seqrep) determine the starting time of the next note from the logical stop time of the previous sound in the sequence. When we forced the stretch to 0.25, we also forced the logical stop time to 0.25 real seconds from the beginning, so every note starts 0.25 seconds after the previous one, resulting in a constant tempo.

Now let us design a proper solution. The trick is to use absolute stretch (~~) as before to control the duration, but to restore the logical stop time to a value that results in the proper inter-onset time interval:

define function tone-seq-3()
  return seqrep(i, 16,
                set-logical-stop(osc-note(c4) ~~ 0.25, 0.25))

play warp(warp4(), tone-seq-3())

Notice the addition of set-logical-stop enclosing the absolute stretch (~~) expression to set the logical stop time. A possible point of confusion here is that the logical stop time is set to 0.25, the same number given to ~~! How does setting the logical stop time to 0.25 result in a tempo change? When used within a warp transformation, the second argument to set-logical-stop refers to score time rather than real time. Therefore, the score duration of 0.25 is warped into real time, producing tempo changes according to the enviroment. Figure 4 illustrates the result graphically.




Figure 4: When (warp4) is applied to (tone-seq-3), the note onsets are warped, but not the duration, which remains a constant 0.25 seconds. In the fast middle section, this causes notes to overlap. Nyquist will sum (mix) them.


Nested Transformations

Transformations can be nested. In particular, a simple transformation such as transpose can be nested within a time warp transformation. Suppose we want to warp our chromatic scale example with the warp4 time warp function. As in the previous section, we will show an erroneous simple solution followed by a correct one.

The simplest approach to a nested transformation is to simply combine them and hope for the best:

play warp(warp4(),
          transpose(pitch-rise(), tone-seq()))
This example will not work the way you might expect. Here is why: the warp transformation applies to the (pitch-rise) expression, which is implemented using the ramp function. The default behavior of ramp is to interpolate linearly (in real time) between two points. Thus, the "warped" ramp function will not truly reflect the internal details of the intended time warp. When the notes are moving faster, they will be closer together in pitch, and the result is not chromatic. What we need is a way to properly compose the warp and ramp functions. If we continuously warp the ramp function in the same way as the note sequence, a chromatic scale should be obtained. This will lead to a correct solution.

Here is the modified code to properly warp a transposed sequence. Note that the original sequence is used without modification. The only complication is producing a properly warped transposition function:

  play warp(warp4(),
            transpose(
              control-warp(get-warp(),
                           warp-abs(nil, pitch-rise())),
              tone-seq()))
To properly warp the pitch-rise transposition function, we use control-warp, which applies a warp function to a function of score time, yielding a function of real time. We need to pass the desired function to control-warp, so we fetch it from the environment with get-warp(). Finally, since the warping is done here, we want to shield the pitch-rise expression from further warping, so we enclose it in warp-abs(nil, ...).

An aside: This last example illustrates a difficulty in the design of Nyquist. To support behavioral abstraction universally, we must rely upon behaviors to "do the right thing." In this case, we would like the ramp function to warp continuously according to the environment. But this is inefficient and unnecessary in many other cases where ramp and especially pwl are used. (pwl warps its breakpoints, but still interpolates linearly between them.) Also, if the default behavior of primitives is to warp in a continuous manner, this makes it difficult to build custom abstract behaviors. The final vote is not in.


Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/nyquistman.pdf0000644000175000000620000235261711537432671015664 0ustar stevestaff%PDF-1.4 %쏢 5 0 obj <> stream xUn0~=RUO҄NT`!RU73+Pd@wّj ^ëȕYUvɃ( ?cD@f%# #zJ o1^xyőSA/iRʼnRh1J=曪`u su'%e) 5 KC+_ֳ3d )t*U~`64;'o3PhB?QƢ9u߷Пawi eĠ`4kq8MW[kKN>Y/oendstream endobj 6 0 obj 302 endobj 13 0 obj <> stream x-˱ 0 =_qVmWA tlUpp\0,09qk4Xqlѻ⠑ )dW5pvɨ4<endstream endobj 14 0 obj 108 endobj 18 0 obj <> stream x}X]s:}ϯܗ3V_z4IohDd{@Rtڤ 0XH׬:ݔY>oq,U lV3w-b8i:˻OV?Y\4W9NB0);2cф3<3wԈ Do,Cv%t2ӡ0LJYUK8+Z ц05u3bl8# fVrU.fZ6R+UjҿGlE-uyY{4L٩[q`mg#EMft@&۲?E#tyf&kdf]r@]Z m蝝/&.}ѩYt#vӪ2ͱ- * ?YL67Y{{wqLg5@厭Ȅ16h< Wg>kFPɺ-QnA#@W( U4qVOuj q^qZ S>\<W{$A%^r˦?sYZT)amDt!,(H\ #vm.L o錓I3\*nCg8N{S^-D %h<Gl!͚R6MnM,Qr=_6CZ?\J<]mFS[@ŸXY }#])*˭Oh`6jm-~7`gӒa+N,&t٥9RP|'ǮHx׮͒aqGga2NS]F=l5%}eFU X#gVd@ "1ݴ`tL[ְ==d'+LB[@!hyzd}q6WK>r3Vhm-A_4H㸫@׊/6`RF&tfHm5WK„#WSQ2l?0M ``BӪ|U>`g5;xX\A{7}sUA2.p*u Iϛǻk 7pmAlg!z XoHSO, :.1rI6+c z>(EpQ s(}vV[I<~x[|\x4Z¬ٿ"Aendstream endobj 19 0 obj 2354 endobj 23 0 obj <> stream x51 0~ōu虫1c "Q 7݌ULlнA.85zl% yfhKQ<{Y+M+&S.w(k?/Ǧ1GXfYjU)@ 'endstream endobj 24 0 obj 139 endobj 28 0 obj <> stream xXmsH_1Bj "RJ콘8:_UiBCb{tHJ9Ơ闧~j5w>9gy$o3<4U-NXPjMuwu=|Z_W7w.0QfIw*bSp4tiԙ+)Ruhn;7PPO)V'&jUʨˆ|/\*Z+ꕭcn,Q[o\Gԗ"WBꕩUm∢GjGF# P?Z+W;ꕲr% pE-`l- ڔ.U‚sud[I]};:p@¹.2Cum-jj0 dAIjۧl35Վ"o*61;#+ek L273C8Ҁ0V}̪)-׌*Fz BLWW;רr`H"DZB櫺lT75{YAUY4ӶRu5y@\VWܕ jUfn>1[hUzŕ a '.oQ?$5j6`2j,maH!ӏ5nCE>p;sHٗTT2}rFzm; .O_#)-'+? =>A@HΖScmXA|QOiVڤFUC 4sMPS2zET}e4԰5f}uJĢ50CxBmIۍ)6 Ů4y7 ;pДsf:x,qfE7Mj5[ȕij-ImUFl'g]Fj ĬqԪЫT+}YAQnS%8&B*!yAΟfk0/} ԿcDG! dOꎄ .li 躰;Ƀ53Tonj]e` u&#:Dl@C[ku[& 9հãWJGSf Ǿ8j c=eH<,7s_h{u"><%迅7ɚZ1Gc+)04d)$6|ަ~}Ɠ[b(+)HǓn vs߿á~[dK}sํg9TTfVj%C!姲\a1O¬ÔOdեoU [f8O.7ju 3|ŒWKo3o2N^.$b?a*V-mX!ҺmH8U^/E톌xDvV#.n*yn5ܶxCA g0G8w!gmGNVp2)OHޭ\?5DBn?kѤ1z}E )m B 2NL}Ҿskd[f5xY ǝ/f4Ԓ,WJ49Mms,96t'cH++iq2z!#Jn{DS.[, K>M`Emy6/Tެg5NmͮOx'1x=q,b ^@':]M ( dž˰u1`8}KX{lmWKlEA+$~zo-uP<&Uh!`ښS+[; a|Ø%6D*p\cbxʣK)(*.?w~`}<-P,7UlR(ݚ2 < ;3V@ktm=d&6]Jn^>XY}Լr{`(>(:m@Dw ,"gu{~0=h6+>_t `9Yi/l[߱"t`Ԏ̡\L6@ Go=}#a|,EL/Sbk6w +C (\Ho?\}BSѪ7$҅ϼ~IteX$~^Qwί4Xܼ6!LQF]oy걸z&X|w\ ;>>p)JB>M1xtn9CqڙSa?_BRp/2mV4dZ1* Uz_b endstream endobj 29 0 obj 2413 endobj 35 0 obj <> stream x}Xko_1ȗȀ4C(^۵,;F>i= EʻA<;&y5[g+f06 p_J2~fbHlי ⾚ZD7)Dn78}~wnTlN.T&aؗAܽ~ }'o? 9@,7@&?G-NmshU%jUȂ(P4Nttuٜ*]wBEbߴ_3\bpSrOC򡶯G,D ө3;jF[&uݝ!+U#œJtr8ݩDQ %Ek|Kb_.OROQ7rA&\ įn].5\* _O}'t[96G$}8\zUeFFQQh.5ZbGUYbOu)x껮K`R=B"⃨V5f8qް=E%zNHDsܦYj hUOj5{F|Ň0&PCש-GwT_1 j8uP En?!5[ԚB(N|݀=vcv}[/ؚ~9LF`@0S|sG24j[E`/7U9Hor$HZk6FH |=/J5"*7raɦ+Kv\οNȚpTfD57z\dEwҵLl l-%'n iL ҙĨg=098HJk"N\#!0:m |.'f Hg62ee)CMpg%~}[IgL* J(DuUӢҪ6v|Ɲ% c=\ T/\[p )8xcO_wlUiTl49ߦJ|='G*΍*o>e\/QJ,"XX#nj ,@ ǎp/j})-xU#o@fƓ;7~ѹ(}cqZaGHfs' Oʍ{"D5 NIT\;#ztU=0g\ '-i{pX1ٕ794=kYsс:.hQROC* 'Mo9Dww޳f:U8!VǮ;e:R;LWrWচڰһjW.:uk~Q4+M*,.U%*w> stream xXێI}7vR H+1V-,J@N5*DFf]ݬVpfdĉ'"U2r?7Ǜr77~oބp?6G JQd!a"VǛէ~AN|?yކ9\OP,7_^x:ҁ;3eAcbj#v]w܎bjlT᠍6w:]lNlڱfg =祌+}E(\3Zߵ=]0yVt'%{66Γ߻^S~Gw(E~܄+pٍ7^ltm 9se:a͠߉? ɠšC-*#UW 9p+)Ql OITH*t~̄}0>*0H5mt?^:^F1Vb@hi~Z}4Q9VS?rQD2u<",Ƶ L늵On,/OSr Mujs⃻rB楻)R!S{=8Zxb{0QMq+xD~h]KJd])W pcTe`fji+wCeR6VAL?5ZfL(߫) 4< >:?wNʘuܮ{ i #ߓ8PvoWEKL7pR]x%5X}ԮOUZH4",֙H ^pzj pkCj"BG)\F!lc۹jA M=wF3bsP`>3oeI`O^'u b׵(^ne]b)LdM LYrj=]3I(1lJl2I,YpVkkdL,Ǚ6Do ?6ݙp, -V[қF3aQ޹ĥG&N?q/3xiQ(8§RS|{<۞lA#h P WB'2I"bwν~-~Q<9Wn <,V7cHP>)hͥb.̇54/KY&xEj"|7;ȷz=1_leM47@S\&rPo3J 4/i7;ug@&"x\?Jx9a"a9=  Y\֮ElNeظDyv#cV5iԮM*rT J 2<:3gM؏Y0#zvda c+jc݂o%f_?y)sׁIU8 5rw* D@!=Asr?:م1p&qTMJ8Xۻ p>sp7OZK!]m>Ya> stream xXr}WLr\RJ_@`H$DmVsӧIxR ~k}Xlۙ'٧½{,Jff)TqJlEx;MhiF2^bK1}Eg.ʧ rRi\J%o٫;VB2V{2qv 9J-,ZC[]u~MVӇV b[iEWY a|D[U!T[#l]EMl2Mޥy]h_ e;LފP0"nࢾMc*Q7nuo8:Vl-x& R`WygJty?nj[DV|/e"PFe$`# msؓuu3$#μ ;U0lO+#$e me)c)rPY[z#x E<+V7D*¥v~1v}\h8luzc`@s`YL-WW2 /DOFs$oY2GE8,@d[1'P*p:K9\P/ 8LR\suz1 gM@Cy.{BŊs"w|##ԶxpKlO=*x,DI۱r w>8k&:7ݘC2VWq o9():dLPyzo*@>/V6Ltĩ0mIÏ-)'FMI"$s`wt2syXwP"8dU'v0$Pd{0}VJOVZ@ mLRp9vYYp_t(-ж) 7e D'Ey@|PU_fC $j ;"G[t8),c!" G1*3\Q2\uyy+$rLx`=A"ד%?¢T:TkeF AJ=F"ujT': qjH?|< 9,/fL89-Wc03``FrrB^Pɠrdvlj&vR zk Qju'Po:e+4o.] |u۝tMBm7VXxkֵwTv9~.lo2.[ hLJhQ[ #7l~RRS 7o?3֭~Π;^eY]#_MhЂp(\7?,.4쭔kHdlƔzu,˻S~ :.:`ߗ=G` (U!nrҺ* ʈ(M@Suj& Tو? ! S_w(=ɫʦLփ;MGe_Lo` *r7ٍ %m# 2|J0@$jfn"e봦-e!N#Z Fr0^[Èqy чE񀖧hBt>m#|?o_Z2)A 7%uBÐ9l]Mٱng[{өn&3%%;hPܫ.O,I+\_iѓ^D`eo\BZd4!$94 GÒmql1I ܜAFg]!>e=r$Uɸθʙw(I{WLMi#NuCSC-ԩ0^||lYEi i(9ͅ&cQdiu Yw .h'qۉ3C3 kb7)cΣ 2-qL{+$ ߏpO-[K ]xTz6Q-5DP-@NC&4آ>P}"qR׏Ion{$~]v8R#z +s,mA+vǦoCߠđ8K$j8FxM.endstream endobj 47 0 obj 2126 endobj 51 0 obj <> stream xXr}W#EN0ɱD.ֻQ*C^\(BiMmi&{zt9(#s/Sr;O f6E6]ƈTTfI˻?{ofY `F D_&uPqtX;H)K82PA'tVw!&3"fi$;IL6/OEeE^4}QkN0PI*E겮^Oc=ھ!NKM[H^ȩ/ϺK!:R$']QJMmjJ]lIxfViBؼǯ8GJ 8fpESg4eYĐYqr;dTa2(ukZݟz"b7+5IanH~]^l5Wr69Q٦"i@6s̊&Ca>&lJfdr5g<6 Ўhu}J}h2l1 d Yb]Wdwnn0$RFԨcy珥~g:)ǽq2l+R`'O dS0jgZP5Oi\Vfi㊪?uD@F3+@8R?U@/t3078m^^_['ݜj"5vz4g$ :Z#͹OCpşƒn\@b<%IʩDH+ļ G :H"(fx Հn7(泞ͣ>EvjeUPm $/*3 8m<-"_S!๳E]"ā u$J)'*Iw cc>$o+g* UüIM9H=d⦵ \D>hOVK!Lx[m_’Vwޤ%+ёJݹ2,Aȴ9׻4JQOHLFJfLGmn=o1iTOqf`&W"*Cf6;l;mftߡCb82M \~'5((x"D`_,XT@ck;t}R-dF;h{@ ,8yDkDYVdFNKHYpS߂ Kd x@k&vIKoފ]v Ҡt/~N\dص(J.Ejpx[ıg[6qjo#o<,,po=~9*ojs;@1Wv&'6J/ L=T}ln\Ir>.%!Gj=ܞK%#%9a{&2x3y4֗EDܞvZ b^d)+rO HPFO7ÌpFJ,uP<ޛдބ,tQg)"5нmO7fGA>^^8\CׄG/,endstream endobj 52 0 obj 2287 endobj 57 0 obj <> stream xWɎF+fM /IĀcر lIsvsd]yFbW^5G},Rr+qqEM(?+{O$rGdWّ֯nʹi4M`+WWyջg/]ז0i|$3sw7ۦUt}[5G^/D ٝ8))6گ#'/ dw֮J~`CݓU4Yy*Q-!"R\'R ='D \/N9r~k0MFM0Y1EjR! $/.I4ȎݷzG v;FrB'4_w;,5 f lGѾH0 Gx ϣ-(4" AH;o9Jy2&"2ZA1c!O薐du/ԞA0"UfmDW }dC)Z"űaՆ\pUm/ȣ!\my ;MP%YRS'99"H=(nd ݀F(XUro,\6^4GRcij) YRk8)ڒE/:C,ȵ 2H1U%ynnS0ZA`=zGlf@SSϡ5QR1@,Vf<ߡs%ye䉝,^HWCSJ3Rm4`gEciG5geh`ʼ0vlM@6djhDݧ(;F.pTG~7?ʹ,0rM{6:Wf4#)~ṁss3%CA>A x/VnedpzJiۢu]v6UtzfBBَ[ Cs\>΋rI2'tLUkU[WX4C~<jYH[tJ D&sbr-(%͒qP\7d%m!n ِXhQ~h)rUEaj\QϿX$掳ݵz]dأy?}M)NKtMX)A#Kn [UjRD/M01YLi.a@Β"袙GSq=ǎ>'h쵡gJ 4ZHf9TpVEje۶,o $4Cb"Z'ڍeO4zU(2Hϕqjw7x Jendstream endobj 58 0 obj 1621 endobj 62 0 obj <> stream xVr6+Vy*)R3=qLj5$hF^wdGx2۷._9lȃ?f46%- e6r8>a>[0>e1.k͗g4ٌ3/Be:ߋ 9ELg|ƢAĢpO`lj@Fj,hT!@)d"a-Gx.(HaA~] "O(>h>c G.3%FXw*졖FϘq6*7ZGWHáJ\`^9"iZvR` QD8@E$sɏF -N5[Y䭄d7K5`+u`> stream xXm8ίoe+ډV^u[ZtJא]^ NlEZ<3~-P€WeFPEQ>/Gf <aÕf8szݗ9cg3`LYNm˅|B6ΌM@l5/ɏJZ s?mY8'qQU"xWURt#-lY㳯cTeIEu8H擀׉2F~mQpcREkm:̘p>'Mm Eaw%pNyaNw!r)Jd-T"'&,SKJ<_"*ͮ:CD*.DZ nRc+a{L+gbRȉvsaj5΁1 (K!7EK?¨J}}C(/^dJ = ]ÍiwňjO3~B}Q{G)k2졗Qk$:#I#b(F;EV\KwЫ] e[Xݡ2R:1R5NypMBLuuÕeefTq&{/=ʎ*ӪOXP*i FL3^IYTZ.#JSZpM. qUy0Zҡ;vm x_ʍXB".v Aqyԑl7GtĵrCdvw |߆*IEI qTwL jQpɱ2ɻ.qOCI~F FR 8PqԌVoVV쌪ӽ$= rCȠ0=`j \]w}$q'q?m[ endstream endobj 69 0 obj 1708 endobj 73 0 obj <> stream xTn0+h6-"h^ X,H!u~ץ$' 03ry .oYiDž8vέC; SRIBoF!H2^]};/.\]/οO9% qL01%,9 HĢC~P0 K2L֢IT԰ t!̍p*J/tO!*SX \D.FR/ш CLkeQj]vG qk }5cָI{wdpS5( ܨf%atBhb$@w*֨rZ5jdb=>)]V[GykTĴZ%";1ӇJe[6?攒s;[LDzx*)df3 >4J2}ć}L65nUU i36BkU[z݊~Eq;ɳ}/|ڤ0'7ry!a|8>Z{XI.UJ3yqdiX-]MVja!v@ȟh:ӚQ"')Dћ3> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥ TVlRklignT¥Rendstream endobj 79 0 obj 122 endobj 83 0 obj <> stream xXێ8}[:@-Y@"d/f臡-V"(=U$e`E#EU眪WXDn~Ozb)V-D.E>/d<oĻ~_߈/Wy+y(UysAcb)VYZXD^w}e;>5Vc,8yV-)t7ws^/6氮mA5gqb72)Etݪ Vu׈Nw0}GVfq̰wyTfllordeEu8aGuǦΩkh|"k,BFbwoꠅ=Ni٫xT&nOumd>l۩IӐ-# ގ cLI(q5sRgXk6BCŽi*)h9vqٮ:?nH>!A){J5Iy ~LoVo~W}-lg8i'>n_5!aĶj\ʪfkڃ"@w^N ʲNmTM+ RzK'yJ^s2ZM,ysգٝWt[Gi@坜4"rpI 3}#$$ђx [{<51(]a,ݔvt;!Qް l Y]ʁTZ,ϮYj@faS˻~˫`c=AseT貧 5/V>LCDQRQx睙 {d)K-pM<W4BJr#qv%WKNmGPw2sA!dgW9\T4͇~_Ow fDp0*c~ɨGSa16D>VRK0 WcOS{حjhJҩvʋ:9zնeN2G6㡚g,AP[:Ccrm%k< Gp(Y- 5yItդ7؛oD۳e$_VDQq; Kwg+; H}hBT'jTA |mY\͓~oV|K/;뻁jpJE]a_ szVP2|AAI^[]GjtS;>#4p͈Zת^{A==֘+m3·G!%싼Bf T :Xϔw\Q бE ͆.)xP@wU]a$_9zK5 #mb8!]nv {'w]P15UL#w`Pu5 y2 T![[.Q Y1OmV^en2Q.Mz5'E~Od]Wy z{COQ/4t-!_x`.~0^BHcT(`B5P0~ZHc{4 _I0,Y2s4o+{p=mxLaZɆnFy+T``JxVoƞZOMU<(W&7wnx`~۪a" O@+CYxCs󀌎vsӃ yΜ `T\._2T' > stream xXnS]d@O";u䧩|Q\Y)BRd}H盝] G8;;7,< ~gX_F@؏|+~ZB(/+>狅/G#^M~F8!0xeq5yOoO7oY.&$ga^,)0M̉2e{UB`mݩz}{&<:6~ZTF[ RuI(By_bQnhE(QNez*ȪJľj@|_ /0ʍNBZnFC-}u+asmS0xRu'p1nu?ZVɝRN#D #PKn?~ <Xpak&DWLnN #P_.euY]ĉP.c3Gv~ة5^JGAbU{˼Q9AttV۲ ݈b&ۚ Nss3 'gIokd(ilE0H8K$ ~pȷ\s= M=Ԏ$mEBgOk(c5~U_KA[$(u 6HcJLWn0BF + Я'd}T&0;k*\ sm3bd 2|ELwY1?#f7s}ChQ @Ye%XR GZuܜKܲ|. ʭB5(dԢPv.l,&ͶP]VV}M%5@ Hj&ҏ PeJ1npfr{!{2ZlT5 LMJsP7܊m K8V^tǝCnZ)]5Cɸ׌RmU;Qκ|C$H4.X O2Wp|8왡a}.Y)#xGV "sR4d,PYQm0V[܉?bB4E7UÇ1QX&)6 u,ⰰk& m {F<'C!UɈ:.ߣwLL(# `*DC8*vUm=c1Qs;%!ү늦{KG*^On0aQA *JwZ׺Ec#=NKOWjbTl]>̝SbInu+V4o'Ϻ8>]ەp UScփd?U)3{eC-}´@@Ž .Z;.uF&+j@bwMKQ'K.R'~B:ŗyѥ[c:|C)=O`¾^yC.ϱC뱺qΙYi:Ԍ"K@Z_dNn6$sqfwQ ۔ uH.PTYyDn { !w#y E ܩ׽m%M;k̍Mei> stream xXnH}W Ո;~J2L8AO~p,Ɍ)&_?w( CY]=\ދg_["vb#>nqh^EHv<2II/__|~˷?>|{{'m`orbvZxH]u2ZHAWMyQȨX{Lb>`ԭmԴQj=D^fNekiDrW UthK쵨Z=MkS i5ά^ ۫6 'F4# t=JF8LA^8'F/=/%3ݑS3=trjiw1T]!8F]-ćlBLpCۃ?unYl;bmJ\"]WEAwj' ~[ʔpӊb{$1 X\p>!_w؀;d9[$%( \ yGSț+J!:01f߲ŵ險 "{ iŶUMPuٌ{НG[EP|^/)&Pv~myk-F 4k7]F@FeYi[ 4n|~lQJ?LyK(7>GA=H0hC>`&7)> ҸU=Kx;9R /@~T+Qn)<{@dOx/a8Jfzz&iar좌Qs0S($ڮ c1ңm<$Ғ[Wo)L#i3 r<3N3`YSdĖe5(ڲ\oUeշxBGזcڛJ$?/>2Bklxz~/ [(N/ф 2՛ ˤ̎MC-6..smM$X҃DRQ51T5 d Z"gio}<r57;|Rs33RB1ke;_{hf|D!>j@S~'һZpPdF2tM yIFC5Y[@!II`۠ m P!-Mt5X{`ݺXvկE;j6Gm" 0#mF|ѻrx> )㒱=W7Cc@d@0,Djxh9'n\lEb 1VB4Fքk_ևb"~خslZzp%]3sV' Q2؍21 :>@y}I uRI T8=:KvF)JΩpC&Gcr` ϵ7-K.)пGsff2܌@mНaHG_f`zݚP:bK~w2yؕaIp :4wnI_@иP3#/YjN9_$v/;ǝ̩ՉQ0f(hOǢ }Dz=웞F]@a=O鏡ǣxlCNI6DwqlA4_8?8nRB=YBU%xiEY$x FlՒM_cQ,ZJR9e?di4M1³bP+xsDi <]_h ,ً@C vOxllA(aVO6(T蚟I ͜v0QɩH!?$D'@8r=-IUЃb5p<}K!UV }~PU t^Dc1eґ<()c W̷^qUϡo݃ꤶȲuɧgu[adQ2-n,.dq[M nbkMx~{}&B>w n|g`&F]0Sq*ߵy֬Gkf7P^yvg\HzD'hM _>^NdV"pl[vG^)|T5?Vw%1.zY.΋1]X vڈ:*A B] vn۩r$HgeN ,My \i]_I zmoC+7tq| .F723e}hU+t_ط7MľAxX8+|D4f=*:7#nx,4͠5Ar~ &^endstream endobj 94 0 obj 2539 endobj 98 0 obj <> stream xuX[s9}ϯI-gw"r '-ě;,w e$cZldw"Z\-^&%e;oןº(Sr:_z 3wNjƖ6-r|(nVW$k)ShZ[eTnt!uyecJZd:׍ITfoinҟ܉K[zo͔ Oi4͆@g)ha)mDKSf&Ul NDs:йGm%I |=y=|MV z j/eՅ q9%7&9C7h*۶A\$e /5lh> .o|[qN;™8mׅ>~n|wH:Ȧfe+FceNÂ1C;TvW#iKZO[-SrU 𠪺'VGJKU^[Z[aA`qDNg~rp$2' -TQn|I3FXԹPQQ#3*μܝ&rݠLgV+.'Fӆ#M1q9Co3Y ]>ӯ{|mz´o}w6.:FqipFJnf\ܲ}̇'ikS]3ғO. ;Umt0yd.Sr͍Vf/)%V|Io{*5h<.|0cx=pĸ"U&?Vu9<ˏُ#ihIZiGK+.YPwWR|s0 O8Ɂz@5U6*0N#oQ=xGz@फWn(Gum&Wz 3ƓgΛDZ\ooċg?Hsm>CʘNfsgqޒxL:yc$F_o*uпAC$pH_=xCwnX_|)hh1E P㺄yT\5G:|1qrz^ws)잊ATk@SncvsEE5Ι@(Kk xY'˵\EdQV,ݞ”h^gӎM4i2_i[^D0og֗h/8,; 0.vԪbMAW[YiAk3M$(1q "Zph/LGg[k]7In׳8=hݏ+yߜ8u|ohq0z Lieqɐdx/]aa}%a V'6f0L=CDw^)-d4IM\c\.a4MP?-Qb};@?/ 65ҕq{LQ^aQ]e+x4L.J]ŕ7[* U4# ?,+1U g9CTt3#>tl|~H%cGV\Vx4!hZ0Y: `j3 m3M) PX@C$a[O8gL:l ztbwc6%=vCe|='x2nc&>"*~ۨ7sjG2'|UUN  -!ZDiՍ7hYe~' ~'.1Zbפb"> ~%$ZP탓ne/cch Auפp 'z@ Z,d?nhTVVV~;]!r}{=#DSj4$$ym%SA7wiendstream endobj 99 0 obj 2560 endobj 103 0 obj <> stream xTMs0+!>{K4 r@w%c{z޾_! e}yHa;x\sz|+[V`Q`dF9*~cq} w~^,{!6b [4>TPS%>ޒ,L%%q njxW#ZT}jV=LM?M4j/K kAóa"Q9%Ev_*|H)A涰M#<1:!Iξǽ,OM9a +T5/wK:U7Kv@g004/̜!#1'a婱]6G!QXq@Idf.;#oک L0f$ZRL A]0e[K++3 Mmen0INբ 2FB6A l8^zA ^Qlbxe}Yq -I%jI Gu %h3|<ݎ4W g)0&aΊB0@7 f߶㡗p:_|tNYN˜.׌Z``Pbx Z9 FV);%Mq>ΑWT]\k^`RBYl^drwiB> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hVlRklignT¥R1endstream endobj 109 0 obj 123 endobj 113 0 obj <> stream xYr}WͲr3Y'qجTJ9 9=|ɷ4ns8]LFӧl?t5?| fN l XeqmN7_~|ݽ|͇_?,썣Slߔ7dAfV,Hi.YEϓ"+#ɣVVnjlVAij(hۚG<~hاסL51J gb8= kؿvaj`j\+ˊ!jrg֑"gъeۑ)M jʅ_VJZ9tq{4fg"WLAV587vϭF*%'X!~heI?EOr/[ ""8(qL^fdjUsMk(q0Y;TO1o5eP:54AQ"0fT}uo4c9I0CY}r8⠋{G]6#&1lZ(/ wq:ג)Eo֯TgK3jKvnU9$;)PY*;;J'y1dUeC*r4,jhovqB8p4(4ױrhkDFGNΩn^6` Y%u)W"x<_hR5Z?#UQ,SgdVL%N@dϧe^P]hКR||*t8YWLrw7hr>vP&FRX$Y!1E"^Qv.: !ecDyMQ-pI[ ][m<DV&hnHӨт2iXbmr-(xejآGG&(9W)EKdhZSC2EW!->JMe Xv!CyGq^lVe-dt9\A{Ӷjf( Κ$b\8R{qB]%Tmf9l"/΀n@P u?/LahCH(xooE{^}6(hݯJB# jR<#zxSfPCg~I9 ^FTz& hRf(>$=<J*9[uBG9{eijZagEuHN=PtxlpA()ܬfDmRwa\ \K!ڿ"kKLT (?J)$E4ϙ ͪW+se'Btk!rW=ank3Cu(7³u-,ct}V\MBfLꨱqQ"Ԟ)R!xAsW/Էa&qsS:[f]CԒ: ~VO+*\>C'J&T~OuXrЙ#MGW$9̉[$T?d?/~k!xK[(ҥ Cԝ$(WnX.Q+IV$r]/= SH<CP ۋ}˼FA3b_0M̑0Sb6g: \B;MXNIn'(ZXzLO77ğD2endstream endobj 114 0 obj 2909 endobj 118 0 obj <> stream xYr8}W. C{ޒ鮩-*$q".V<_? Y˕8@.{.y\0~t?bvh˱({Q++!jv.ע:Sq8vY1ܨU;v)#˖ liɛƄ=a' J.BsMΪSȉjFkn͂y2F s;#S+}NFtq˚n` MgZdX^3Qܞ(!ֱ|S|m 髲[d_o* YkXB&s4h.ي }_]”h!%ںG[b#:JN)j|g%}&\,px,4 d?|ˊلDZT [֗m^TiUN>ayV8G Mr8Tkq"- f$x` 5%`39V5Y]nUY[?\;m(0q2`cFE#\VAX%u5}{x?$d!Xe%j߷YUwQkCx\ss֚^4A%ME}V>Gr4=,0²~G:4 Sg W&|MjsnW^h>;اWW=xdp>M ODxcMoM&2AQLѡڍe\s_6$ڔ{3\E4@KqP_OԧsݒytE'Vi1LH͉Fr?Z.u=kq7 :UY3U}bwݣY0ƋgJ/Aӄc%=,wx⩴IEɄj2͠mIѦĒ,()ћG;/5FTi-idpƻH)alW! 3BX.-18dtDh)  ߣ" Xa8Q/;l0̀vy(C+PlWHnlξRG R~Y,%$!or(i4xtcݭ&ޫHAv_fx!EӼ=x@7Jj>i!I gVJY%&d)8"&.M[{L)H"B\YrHs1uѻ‹ԙp}r7<1vkHIB*o z{C>/=2R 1 ,ρc>$*: ~sWiErĩ1NN㸏9U_f@<3l gT Q Dz.>)^pb8{JJ֊S8Oj5a XpE#ej[ߖ<^<{ڜ^tMɃOvx_ރle%LhkG5QQ60::3tu=.]U$fh;yLNU,!TE{Tuˮʕ8,'WҳůUŹ/k(IGX,[II5hl~ IHn. օr.9 \Z3j2LL)+a Ij; MytSJLɠ,|,~BQx1I(Ntbb)+qR{Ȣƚeb0Z[ӹf;Jm*ĂRc tj9e-n;VrSL`sQ]Tj7 ǩh/Kr1'ѾnQgPb=?Ru. z)&lv0^u`ggDӋZoNH];2i$|H ׄ?+8wI3 fЛd֙h2hO/$2A]ӛ. xP,ejg8kޣq#p B)X}װ XӧKGuCgH ߈u=`L?]gOlgF wPt yNެ\8wF^8o t D#SSeG9! nz3"~}$^䖨L@oGZ (aCBgm)fւ!p3Z<,+$Fy{)}Y56@|ٍ{^^@DRbGI|WL2L$,3!Zpare `njljA 7ti/H.mPNELM솉{0H-Phr]\.ܙ.I'rxF3.(4s/y?LI-ng9&X7ԋЎtVoxT 3El/5'ǛSU?endstream endobj 119 0 obj 2804 endobj 123 0 obj <> stream xXnH}WK4A@8BE]JR%)s9Rl0lŪ{\c.~C¶ew;yxj3={l;ٴL؋孬ZVux-XU'WC׊5;ञBok2!tS'|mNLՉF^4=jNg^Ej-6v*W= +'^t,V< X6F^{DQyq7.a L)oAY{99oV: ͘*ڱh$&(o>Y;YdU0L*n%nlVŁs?twm,c/u-Z.wÓr궻ku# yfN6`FExE^K2~6qEpx:Y2J&E kWpu+}/(&<dɸV"ط%v?X{h;4"5u&KY^T ޜ2ed);[Iі.8"]RT]ދU}<1e;N y[&fNVh+֞-@K\_qq6:zyDF`c?MD-54foF.o7#2GمjST+m ^B8`~+WY^`& #@*Ċ 2 4 7ϥh/P-3빋 X[F!Cט,+Ћ]mȳbsHy#A+xDȉ3/jg(s)u{% B?teȍzF<qB${<{=2Nr#  9`tNٖ(#N!!3n<0H/+EUS.V~J> stream xXrF+:وJ=hlbWLJ$Hh4`|vld?}ι `_$MxvF*62`zc  $̸rs3-Yē×_yd' \bYJfkZ|p/Ͷj%WD(ZqЖss0&vbXRswP}Sзm0L#i깯UI C[ hHȽH5.ldOEGnr2 6m(E/O#'3c.">C8gΚvw" e(kjLs[Iu~$lV+0g_uEc<뉇մXAZ?M Ws# ZW UW,d5CrH?_K5 AzS,f?2Un,'~ <<0`Ew0]& έn@6M}&5 x08Gm\ Otp|74*SJ4:\u~C3|02Bۭĝe$O:)M], Z?'e̕_X u)؉<=6w|(n&"B}nw$`/Y+z{26׍*p ຯQ Y5g傁&ͮ.=-yWZ~32 7Ng/ 9_.# JJKlxD%2n=ѝع3׼Kaf2Uoʍ4MYf}x};L~l,6fm`*X5]c~fW]<@ .L7@kXOn7i4Cf0 &ɉP\ ^DİnDb>ĸE#ݮc2ϖǾ̇q6~D}ռ'$5gkzIE3lID_L8{㖨DǣX_ͽWRmƽC'k'NNOސ_=lbr绩p,pKrFJfyNq]OwJ܃$߇ <>g\Nſ7}endstream endobj 129 0 obj 2338 endobj 133 0 obj <> stream xXv+zgp)8̆ 7&@x|{n$@irNloݪo>,?~J١{x(jƢel0| [ l_\ӊU%+L<>S>?,~9^I#(JϷV+5&C~eRڳOՅC՗P6e?x؍b5s)֩Z{}qd=u$ۋWٿs=O|*xC";.xC&p +<%_l7{vΑ_(pEhD WE&w\WvrԝҲyyR4xdGٚw,\**q014Y/! rmK#byl"gJt=Mr\MAhGO)7a*>{}f?+X粪tPD7E^DB63Ki y;aez%T \;HE7>Gl_`P0څ@;*%rExK#cD++=R8yrU\ĄIO`[Y$,i z{T:r[?KM0yuE[n$FC*{jr"3 'Spr>$MbGɸ4* 7G9wXF wXuPKeW?]}+O¤ȡ ZYaؙO ކsH!m#Vo %(QB_HӌZB&94thp .̘Cnz!`Vd+e;bp|߽Ӫڡf*]h 1峛jʭ*^TL4 !QyjKBLGWqה4pus04!BEk'h XlN,Z&D3%˻rk:Fp+);+ ^4qّ S/NǙ۾@< 4|I h?@Bwi$JQZcF#[}>́j' NOݕJԤ)0GkpcnnAqYPYح&wHP<=/ |ɰ1LI JI`u0Z9ӗ^#gJeIαe|WXlZ)(-\M&%vvASXʕ`hQMzG# Y#⫝̸0D- SU+a.m^ٖRM E[UvY#_MMS ^0澱q4XM0#^3<;}(::QXP>:%"B?ٲ,`y87eEtY?~GuM؇ @jʴVq\or]\pffԯ^_ 㪴eJH]riZ U;Kllƚ>kD>w mk{gfiVk/RD:c(43T:d2F^v8n!g)NTBUBwIRll_'lF4Y60{{^krq (7HJDQ(tMDUC?_5֗*{endstream endobj 134 0 obj 2419 endobj 138 0 obj <> stream x}Xێ}Wh E$7$8Fv=Z#[fS# )Rg,5.ԩ*~a,?gyהY//3a0<=PNc{&ku\u{<-k+-YWbU]tjM'}S}9In pcXHx BU <=5eWug< -0%YY?Dc)M|#_fU6nO- {db=2͇ټݩm\_\0 ֏w&x0[޺ F&ϊGYa& tV5 <)hdQUYhbSÃ=} ɍ9LcY/UNXIPha<XZGو+s$jl0ė"1Q͎= gp~-dj7< \vwq<;mYDzjz'Pvc}dxϖ! #gD3,WkuݞjWQ)j&D&(y A Twt?Wy'-T{0kVԼ2~R'mKU\C.5#mjAU9$ITKrv(.EEІNZ k"ӞQj/1[Zm^,l%B;JV5<ړ9Y\wc!OE[Tڮ&}QVzǡnA>LԪ ,A@#?j̎QdћXp 98JFIm=F:|zJ+65ڟ-Q>c"aC-h$MꣾdGgRSTbB-$MyYs%[HDWDAWծ/ 㔢ke]C%]Zݱ b|T 2:2j}ki#+϶K*vE(7-؀GIc>ٚx'RMMi+87*w'>s1m0 C˽B?NS]S7]6%9 RuDžYc_ޣhg8۫D`$RP-j5_Iikcu Hl{=f:~lP,*Ƿӌ,CfHDǟ+~K^8ƋWk.2.#~[-b?2'Ʈ"%+!/2T2/!ZQ*ڕ5lk+3G/p y&-lA3k5^jJ躑t&8/1ȿ #`ߨC9LS$3jALeZHY}針U-G ׇ(]=1fBmuuǁ3"y D;fB37qn!dAQkJ˒w ej:VTMZ'3q2t]UT_6}s[{峞v. F։oHE@o )-ȴg&UvqD;/%MаUnxrt9cO;.+${Ƴz;hǹ0o;Bw rjG~׾) ÛC*KҽqFs+p0 74AvPˈ0浔$UE]}A]ϳ_T(endstream endobj 139 0 obj 2306 endobj 143 0 obj <> stream xXrF+ԌX\{iTbM$wLBdp+{v(_k|x33^GspCq3 -DD&-ڶ Z0b`ϙ把sTv%w^^Nyj-s(L!rjdmXnI -㙈moz8lT@N FNxC\-:Hbv,LuYr42$Gs>!IcEB&')fepMt֟Qr sG>8d} ǖ%PMUJ}}c؋YUo,䫡n? e*DRHYܙ] :$: W4!j\:g0avKjf , 񕼮i ۡS;t2siYW*lIAA%>~o3?XB; Yk;gиA#1FxNi"!KaK͆vN^Xxg"X-f*ׯ `i0䇑|At nv]=d@KDxB8Xv5l<. mWD8FKb2yf0=EƧ"5BgF!:dz9qqkJlv'PUy8YI}s#ĚjcSjᵟe=R|,XBu=.H,7y@7 Z=qeO-VMT &5& XK˔VVk&DRYU/;coӡ[Kq[,'ot_':g%׆m Uk^;̣+LlFN:cgܥi#l(gW*FRzδE!tAc-Z?JY[\aW0[#",V$/f,mFN'*k+8%Ku۽.kBO'Q??뻙endstream endobj 144 0 obj 2802 endobj 148 0 obj <> stream xYێ}߯G*X~1`Rl!iI6ɉRC=2.W!iWۗSN~fY@s'>?fs6G~E%}c{B tӛG1o![uŹajɦa(EW~PgCeΓ' io Ew>lRmc)#K#Xiq{uL\DjzՃ`JklYQr q+k1T[)s +Պ[xƢ}0jmÚD\nE[4%ڨUl-Z'Oc~m,")/!!1&m?axP>ˆ'qȳ-I\=c4AԝKN3R j=;Dڰ }]LmŲT\9ʦ3pL12Na܁D nv &;RJ Y^6T$⌊8@ڼlꇧu_Nɮq"I^m#S}E ./]Yx7%XFu7;df5]7mPEXSs Qik'lJFǹihPpm@ IS~;Aeb}huE(B<xtEj-UCB(v2D|s/@m5`TLV &f0eh? oRVxlvW,ED 4^aj?aF]us|9F\>,Uor\_n ;1N5JZ,kM)#od9 .XDUI{-o}u7, %2R;޼<N F_P3b2fz"K5{E"T *2[veId}GO2p\߻wzZ|W\1 QC|+2~=P/>U$3z1'A@%PVV-cޡAk"l8?@\5ۊ4->h^̝a]Xg C[q:/)6v:wH.ܼŎPH( nhl:難{Jendstream endobj 149 0 obj 2749 endobj 153 0 obj <> stream xZKsGW-ޛl%U)TeD,&#RR@ (gkH\fL?Li\oiy!KPe˻E&Yx4l绷l߾{Ûw~`o-?Zv\8@\W?vzlf \Q‚a,=,L+pHC0*#.[Ϝ\ecNg  dZqwe8NewK&c.Tm ?aa΂鄩WA|ڙHsǞ}_W6Kh)FůO e>Hlͬ맅j06ց8'$cʷ7޴ڈy-e A0'QmMʟA't5h3 Xaa`N iчJdsu.Q2:O57  &ݶI*%4wSw!`itѭitdmItA0s΢[ȆFW74UR*`{]?G-%a!dQ?T/&Z+dII0=#,"c"uϵ̹=rZ͹V[Np\oiٯ@d0pn| ssPl%O_ gˤR<0F(~tùdM-TqlW8.M2os47m~ccЄsM4 n,cj6}رk8V9ʰk)w)+&}7ɜ]6- ?nBUr#tGsm?.hrleInzfۏ7?m碷o2rZIiTxB~XYذ[uq͕y q3ظ;כm '{ѭlahЂCͧڱkj jFξ>'ϡdO3ܲu6CWqC;Sɥoey!T尽6y{ h]K͛0+*Q#, \F"AKAŧ q!XdJLE tl`+)A@Q 0GW9HLD* AWh *)/$0ʵQ:a 0$Y-LRsY2r˒a"ёa2 %DgHnY/H8`o 6*L`"$rJւ]$zA26omER J&o?۟6m4H RdݞU\K.Rb[E_.sp/p7~TM}фgUn\wGV?b.]U~%EO%U:Z/Re Z˭T")ZUR9RMsDw#Ĩ9R2g1H# J0Ga$H#L19"TR ^2xI!#OU "F%C&}Ȳ!+$(CF xbÛiۧz^B rVB -LǕ AJJ% T9#(*%hdT*TyE*%`Uq!XdJLE l[BPy9PjT5 bTUj{ La$H^2SJ0!HlDJq m ,A8$q%F xR%yۧQ J5 u= Ja$t=L1RxB3DPZz+`(e|)p!Q a!X%`H&H]._L`CL-=]bDJ0ǤL$Ǥb *)/.Tޓ.1Q WTn%l|dn.1JZB/_L?&)2A|4$ iG`ATpq#4/Xv#%z|}jN{x.—z@Iҙ#6}t&6`X PA5uгA؈J }c/ք._db BIk܎}:eƹwY Om9Է2ul{|{x=hu붇)ݞ7b|l?w:6\h ]Mw}5gťU Q5Ә,tchp||܍!фexZ+.L]SfD\;7s[6r$r1;K6sُ6vN.4v} W1ve،hnѶ@*,mC,(lB8SnYܪ慞-څ$n ,,txU{~Zsendstream endobj 154 0 obj 2954 endobj 159 0 obj <> stream xXَ}ﯨ>b}!V{zqJk,Ia_~or넠 +7A4KiQƶXvrzlZϱzx<F1w ZlMAa,N{Z) xy ~2ȡ>bѕ{BP1vm)f:!- q`.`Wm"L5zU\D ]pdU#p_]qKX H#=#)t(d%2\",GըσN>!8suۮoU{Y'PI՜;C |EJќkꇶրk, 0YlWMRkxj)gA͢tqb j$y[j! C㳅,V"'ScYYbV9f6ӟ0cNDL"V5wMgjl|[d):VǐaYNOr:]ci`mU|Aw#sFW|n Oq{Z!XE7' jt+O@~V3Cl=V ?agԗQ>wM5N̗Ņı[-&;n.͋j۲0E,4wjbsH+_Mf79Qf}z.Q"W1*NPɿSmMnM\\CmG]ℏX.eb)ʨIB1Rmd?7o4+P?9|x%5G5C$10FMX(#qmNm]tvPWCl6GS.$LseB$.fn~!gj,.~Dm8@ h[yf&@|IHVPWCI4 {^ꢻY.@@2Ԛ h j#*NۦN6rםF6֫ y־ nxǦ/ssY-䍌5c/̠\[6ؓBzE}u̥UQ!K+dY]'Q< E{$^fG6*[[mc1bB Ht\1Hh^|}(,7J+pH+WJGD겳~$B" 9 Qu7);os-qbO4AM34`d:c`3D6BkơɳP6;Nhŝ}z yh׶=~] %!6KP'_rg;t/FvRsWIЮ8OS޽iKTwat_zendstream endobj 160 0 obj 2380 endobj 164 0 obj <> stream x[KWMTj`ɉU^]>dS%wǮ߻{fz_JI.-z{~&;`*eW_V00ȾS4VgZ$Lbjw۷۾sw|}{sw}w7z# ă8%$AvZTLv3E%^HRr]IZfn0"Ӊ.qJ')"KD3J}q]+˖$2@i(B+ڳSD9% .UHBAᙜˤ 42+OA8*g1pX8HsPSgb(Z`O+~n+`:, q@"HH8Af|@0) E=e%K$ S@zIC1j|Ɓ*/ PHyP2)WB#(ց׌8cZy q@ s) =FPqb%&gNj q@ZZ Pv/ B9@RB#(ց׌8{)i#<,Q Gx qP=+!xЁ21@."TœPzqs) =^5>@I9 $"S@=@ +U3):(2B#8 MT&B9@RB#(ց׌8Pc2BU@b.qŘMPc6Ԡ"=(`^ ֈƇT"J`Pq*[@=S@=@^5>,~դrǯ<WMJ[ U@j Pů]xvq|@y.)j%|v\ğ{J$%?׌ |C7+,_$}ׇ1ROpRw#)d9$inFVNmSHhNB7ce#c~RmnPjdQ\(e}7hhhA Ip69iP*J7u{V~ƞct@TuK03qbfokb"EƨԨO ]5Y4#Ix#-롭N܀m8v 9&Fέ@yadnQk[ulc=k`aU7j P1*Yj0:;cIJ~\\a169 > ų-ǿ42vI-N#w@àNM7ُΙ0h I5O6N<o闹v Va6*,~Oޛbo0`x};5񞲍/Qpe {ۮ7kqV FLa`|D[لR^Jas ]zo0I(d)_mxj&ٽl=‚mFw~aTWKh ZcɓD ;.Zق9|j++k-yn ݭ?Y-0Xa:''OgSTƻu״7_c65jc'-DYfv>8".TE {` M=ƾ2dfhBj.J[W sՏ6gI6uw̫M]aMmPNJG`Ϥ`5c3ؚ 4ůcwC*\E?y{c8;@Q2c3&cG$h8楪Ŋo͡ KAlW B̮ׄ%UǗ.uZt(0 H%whQ&pЅb\ _v Fgfe5DP2bcE/4R_~*C$܉@XLжfpZHx;6:޺ 8WӕZLH.r]5 9Tr bߛqVx|:C,mZmJse_p#&5d&G0*|_X3M~m7l2}[Z36^S* VQew|v1N_%?hAy2%k1T;(SXLҨS ;v,XsF%gM]W xXufV+asI P\ 'nعk/9$>aNOm$G&3NgbT T5)R賬mvp|azL4m~p;jL5+ϸ~[ ʰհ7߰ka}6nH _֦a6,3ʚBbOsɰRHYrp3>\βly;$#endstream endobj 165 0 obj 3267 endobj 169 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`dVlRklignT¥Rendstream endobj 170 0 obj 123 endobj 174 0 obj <> stream xXMW|Y@M9$0k;an- ְɑߞ&EQ/`Ũ>^z=/3>/)ʇep2W,`Qx/| 4W0a~Y$=Oل9<3'c_U'wq<5ROFÇ Y9`{^y۪PTˎn1K}XxS ?5h\Ïo/C{N DY}Zl+ (\ zNMR?$WϊzZW)k8WuQF/^v-$hYP4PJ]tnS5i62axBrO}'O&Ж /:(nAm9(-J)5mb:1+MV(GTO*&!sZOέ9šq5B!:i1Mc&t f>w'JP..mTט"95`\ȝ Y4𗲀)*NE1˂thpt!xZ4< sKꝬk:ɈvrD%;E< ,gOl4~|>͙!mEQ: ˳KSBMR26ȃERIb,ڋGg:};ecudpјsU̲;ȇNot ;9}]؟oKe 1#ax#sCubU3yVRۈʱ"GBȵ DEQq^d'4%hfq_46:84=aw0pT4~UQ4>;FF]c&TGA"+ؑ} uiOΖuҦ)zZBގ.Arj !x * h3 gRzf)5 ]i"tէ~oNN}ח[C'mH $^DoӸAӊ>O9t3={x_ 6& ۇ5B|1ܚz7A "C0lņ@W{ynY`.89ք/b~I|ys0}L8ЬZ?i8Hڍ!noX]WG_75ӹ{3@:̶1S!XCm=9/( bifsuY-IIsl5F8 t^:K')oMbSwT.wPSe~g4 ώ0C mXȷnT2PN Q1yA%C2ćF :XFѷГCڃi&:ߪ.1'*'Q`p,+> stream xXێ6}W'/-m AQ`HVQ^g_=Ël˛-Ů79<3sp?G,/Y+V/BO,`޳XTуfaE,x̊Q, _2KZT/r,_7?~ݻ߽뢈ne;*y{+f;y@O8{" )O#h_!ғ=rw׆{+y\sA^ijhE+5^1HU|EVE7}l#83 gr5Ce9?L^Zt?/^kDk< 68A}Vu[Odu*Lx֩69qG&Gl6HJVDVqed7yVS*b{AQ{&[zbAz CïKRY׏l/PxװƁUZHF)$:6YNBUE(8Mm^xd30eWKְ0H}lޜLaų苑M.KYpuHW؍ĥxu ͼ"^ĥ?j '"ٔޟ5ӊP+ t33H '{3Sl[ݍz9ĒMrnvIZC#V&T,7u@d~)6-K+1-bM"'6)d 7׏`*I*8 +G/E&PљM'HN9=,k$6o%!/ yt2̚ǜ&I?VpVš-=zx"ԦyiF|yh /6:'h)l"XNK?N#$> /?KVLȨ (tۖd}=@(j4^QGy`0ye@<)_Qzpk=xo5/j ?NIp`Ԕ#O B |Fʯg3& 'ߘKB=܎9뷋ҫ7!/]< [D'0QЩ @ABnQ;6ʶu 'b`RmAtkD``>0= hMq)_AHK UL'or(& (/1,es][Ks3c{mGz+5Yendstream endobj 180 0 obj 1873 endobj 184 0 obj <> stream xX]o}"抒i 4ۙya$F"dKɶ(dKޯsνWUka_aϏhTBPĬ<-Ol~׿v;W4XzU$$[@.쒂yY:=K<vkhտUF~ -OX "f͌xpݩX"a>^ckh|M85+>xY~Ytro6^ºx*~aRg,1q5ȦQ´ {'>r%|jQDS+.Ҕ^čAtO kVd'Kn冻Ë2ܝGrݚ Dd@X݂KD~R0&z֌&TK0E*FB<+;xP 2+)InIpGbskDZe]4|1Γ)ȓ lON{}+z >_@@҆gL{əSC^&a|ڎ)x6UQZc^)+{\$V8I€`Urq 7,e#" эǕFU:0?5k Us*{0=9N9, =4uqN8ݙx'!U:E ISqE&3#HuJ2CXDh5q :j:]јZتڗMgTgi-x8!_jD.wViXf#ܳcGU Jdl zL8 CzetKSGkBSw$&!'Ht5nB]e7ζ0 AX_ jj^5R?H1.TkRNR[29:-ghH8(Ϣz~w*vzqGX%=G)Mx3vbx89^ D.g'y(8E:.C Ct^)3@ir^/8+?Kp@F4Jp\RͶQIl{9+b^N#-TԿh$Qڕ4 -NiL Bɤ _]\xfgQZٱӒLA$(tyhc%lNW¢]c, {焻QC+;!Ư)*0]uk#H 91QZ 71MG\~eKt6K+&w=͐Eg39ﵸ8׸Kڂ?VTg?m.d.',M ^3K}tY92{x65fBCs$rkNk HQ9]3ʹW,g|F8T7vAJh sFfhݠ{Iㅶנ;Y_dܙNT9ǰyrrRX(<g0?A^ _6+]Ϗ> stream xX]۶} o`l%i6/Ep%fW{d[EP88s(>OXy=|{?i~PBY󀭣ۖob/Yl7t6LV|6>?ӻݺsQ|N.8aU7޲J7(WTJY.0F+$32j&ؓh/}l{KTˎ(ؽdld >-+OQnMf_Wݍ7&`=TuJT)+QIW7z{K#ʺfN;ea B6Xܞ;'pXOL=68(*[oy܂}~&2ϔ D{@Fp(; s%F}L=.&(J.V78׀ 94UzbtKEtGE+e,CnhMJ7zVܚ=ֿdDH,82 K1Z}oƿc[}' k|[&>_'=gd7 0὞|Y+>#'^|Dѳ{>QV9ɹVd]IZU]yaȗ-O6bXVvK#L;sZ,+򽓐1p۫"vP5\&_DcE}@ޠZѳ$#VRY/Fy)7{тǂ&~?8Ʋ\nk\s(+`|kܫYV蝙j%ܘUM8] _yrlFfs㣛 {$Ӟ64{?⚾Md3Ԝ7%S[Aohz9dǁLD*+*AUcX)DejB~`5Tdb{D.M6g9co±U􋗃~2QU]X=ɂ>as> stream xWKs6W-rJ$ٸi;nMSzС Yh(B!Hί.Rd2[},~g}a fo{?4~^rXmgN,IVݟ޽{?+*P$3f(f^B'":GEN'#puͻN%Q詑gV. <, g8-QAb/;WhT.(fˬ(Hu;ډVѠBŵ0 c=KyS1wI#%Jv>48"pSP>a~(SƗc %x$fqe2V(%j&kt$fCtoaaIxgYdRR8mC N Iny~PəVv}ېOe}E_dt/^jLQF`^7;Jܚ"EẙD,F9ܿD\RI8ʜ9ߓ0lfr=CDX_#hӁp#)wQœxeg٠ ~-G'C{<Mee+M_wTmߔ Nm;YO"&G LuELTPF $RL2R <uCTc#f/;} `'[In׏Z$| (,œD+؋2m^6ҁrԲ{P2G6&,EmIaZ%=_c^a3Q[6+ 3Rܼ -GUP~S;l2>sE0hk ʾGr["zHM'5F4 G=Hڲ1'-[z3}><0:/'w؋x:aM/Nnr<JۮIn<_DlXyu"4wYݾk}өF6Ϭ97\/cn1VdmeӟzU~ı=l!az#qߑ,d#]_vŌ~/Iɿ *rX&L˕!n)9^pfxY;[B(ip$ *,?-0qv %ᘳJ j0뭾ZMagU.%w>=8;3| duXO^բ%|a/EW'p% 7XCGH9 {˫3y%^-O!Ud~ I'zO1"*qU7ɔ:uR< rQ /gja>endstream endobj 195 0 obj 1757 endobj 199 0 obj <> stream xXkb~0א&|?Z]ĉhbA E I$bVs{Fӏ}ڇaxُx̾T-{>f_Ҁ, l>x*EzqNk"Y߿~x~~yëݺ (+QӼiCmrdegfmMejjl<ʁ; vj?5d@Y, Zu[ŧItՅӅSP4IƳ O#x}1O#C,ԌHg ۨssazQ^1nM9hB䑣jj DofٛR^ _!]w]єD: g,gnOJVƒo+B -xb$1L#pާIbGti%{FP*4٧u|k7 3k0@:l=++VMNN lA5n8qtY"quTT"5j@mnly`!Էӳi֘qCЋU9 lV"\BE |f8OW# (c٭iDObHN"G(M"mQP6DžlΙcd7:. V$BOs#s?pl W8_6A!sd=;I鄧bP}jmr 4v } q$iF7nfP0e4%QC筒2-1ޝJ\q&4ǂ&v .u}p\W.iD]Ja'O&SV<ކK: i- !ja^- , &'&@Rt]ς1'9ێmIpsby.1 *y:F'}Mw)Xs]% *:hGM\5)Dh__t.1-#MЗ0ѐ0B;1,<^UP|%2  ИחÐ Jv ppBůX#Õ-hE4(i ,^̓)tˋ|_+Z7EPwWw/E7 C-|Z{GN?w 9~۟6Hendstream endobj 200 0 obj 2251 endobj 204 0 obj <> stream xXr}WKtŕ$'mbǮ:kUe 7cQ$$'RY7zN>}"ͫ~݈ p&tW{VoPl#$a"ONO}~{=x$2XfIDH'VI䎬prͶiaPlNVY+u'IV컦 ooDwqkUhD.j[(ۇEo=@K 'xxh.m] c!&߅8Rxo "ܣDn<ܮfqbbFj5?R0M6=AY(2:?VuxX qDR)eOq^lGdZ9] l2Ǔ# ,ءQ'Ӗ*nܼ:|r.  SV]Gt{7푻C7[|Œ!.|#8taTqOaTn77L8vlI2+6>ej|v6gD,°=$67L5^w u&к :'Y0> stream xX]s|ׯ) !fr՞s*?%Ao)RGPߧmo*ZT"{{\x4@?.X(@_ۣ `_sJJ" b>.n.wFE"׻~ry-~p'N)Zr+WQ*ӼX&X?/nO]ؕc<ʇwbҳy"$y@]*FKqix68OZضSUnI4y\ +~?h?׵0j<m'/+/E솽iU2 2R/ 0 k]v(7[REt}8oN2Q0Ƕ6Z @Rl8df>49_5P(+dIwj[馗#,m- Ce!>uZ BQ"e/J$Ҵ諣^uh;h#̂ saJHteʜ* E <#=@s]h7m/ȥƗ6B ȞX %o6U#L>@hG[v)*luڠoD=,,NT Ʀe% t-{$KcY5;DN6HjX=ᩲyw@^~xPU =#5bҭiv+bwI"UDCLpߚ(O:[$\"сU#E-w8P6SKNYQ&j EYҦ|Let(d ?_> xLҘ38hwPY6)xcn[B: vl {(>RׂaN5}ٱtiM(8-%4QKqˌR/^$wwI/NRS`FvSZsq[%4Ɗk޽i0D#A+Pyr*&+ Bx2Hquԓj9zupm%q[5=#^BRgK*OepT.^ed׊9J%Kj(x߂]LI1rC0FE:fgH=i>zs0#v$d}n!潘@@KTP$/DGBK5R*+d ~Њ|n3bg3ܘ'"3׃nH,1/愌G~fƈ~$(@j-Am8U6!7L^5h>o՟1Fof;Q>ɣ=QLSM;5^}ÀGxgF ;+7b' , Wl q4VED&|"1cU*_ +p-pew%b;\<eSDu/4~rD 4Pw|, w`es^O.XZlj"~\P:&JlpMn|W"dž Y&Z[-7Ӷ6U;K}8Lln*ߧt@|kQa#ߪnp$L=Rlk:;:ܶn6\YG ݝҜ7[y>YʬqX8SŎ'%5&fcWJCL9;:3 F'^L8rT iϝttK3ݜbw'}kȷed;隷pi> stream xWMs6W-ҩL⤉= AZQ}wP)IGLb}-C8y5s 3 O̾ϸ]+%.`̙qX4`Yn>||Wk.$ $h,f7FAWpZ1K,]k;֠tU-hB ) bWatt-;U`.`uVu}[z3͓E޾Uߌ"P"bpVM|$u~tcgu"|T6HcJ _vY̒I ^od]LZdm@[.1h3t T}]Ua荮M'R>!Kp9Y;[D>3 [5<UE ևUd,>O !/1 . S;);yGAhI`d>N+Z2`A0rAëǛx2>0J<[ဿb7;,<ڄg23&69bYJ~Ni JwSZ J*3;1A4ű. MEpW5^k/%'zy,V)(F-OyY.ߎHBYv.?;<ϓy K'u)s.Pk fy,r$prR,{eږ Aۖ'5@^G`*LO2Ċ;-XUƱz7(̥ ϯUjMnηX%xD%di JqPrݕ"Az8|5~Q`dyL#5H-V۫5UV/;rmӣ\ʢ|ojR}],IjO(/_ Jĭ莨cnEm."PzN eH"ufO8I(htxFkj!P1Yʦ/Z;meHerHcdq#p%%}Bz $u.$[Ms8Fz-ŮUO?QBid-N~9?;endstream endobj 215 0 obj 1726 endobj 219 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`lVlRklignT¥Rendstream endobj 220 0 obj 123 endobj 224 0 obj <> stream xXmo#_A}ӾI(pI\Q+JjZV};- ÂL3D'7obkof|I-e*Kȗ2osy69>o~U[-?QdN'4[ʲX|r.Źu4b\ҙTfp: ;t`Du;]HI2ShL r,GܷšVVO. kvk1Ms/mZ2,gYQD'ۉun[xVT;9݋U_%m߉97MNH_V2OfɼdGay,{պb iRy*#Gi˧9ȹ,ҧdIhRf,0'»wKB&C0/wN pGv@,VI dII2 7hM0dmר^KSBVe]E(93p"(s f(8}b#IiO`v0=HĈ^K<ˏlSG]}*s{njmW2HaVkp lJp\Tg#?/C ^b E^۷խUÕ HڡUCs\4-dQu{߹'&!o: ʒrtyث<)eԞA#MKeN ?ڟY~?YռR3Q;~%YrsS1RdLq8288T8qL^bu :njop{ۈȂTh9l=?&~nѷ܊ϟ=VlB&8?~gғ+GEӑуk+`م$9 ۩J -GYz=gŃ5r-cELkv}Ո=u/b^ZђPl>powցr,xP맚(-ˉm?af~s'*GmӼ%`rУwPj!3 c4e# =x$X."dI KA;ƃS 3Cp%A+٥ 2ʙwpMy!I}z3 |Hxu,Ys,ue E{^ QF+4CG*7K%=`N|kt^D)tS/:n'q3ys{ww]O7Mcooє$}n7kZGCN+ R*˫q*RlPPmաN+Et|1"5QLcGyPy,ڊۆgOMmwzjDǏ~{%; ^)Haw|/?_ɧB/eob/s!i7T^$(3C.;=czF؁PTj)"3Ȫ,6BV"+EykŁ>lߪ؜OPqg `؀aAL۸m/z o%,%A]'|Mҏ7Iendstream endobj 225 0 obj 2450 endobj 229 0 obj <> stream xXmo6_ؚn6+J[H$m- %aGz[vGJ؊v6ysϝrM,ʈ?(,DR7SƜhH'y`:jO=zC.nxRRh#sFCB7ʜRdbMZR0A 2뼼'd)Y%FG<.'Q*3^J 2[aV APcҧL sC;U\O/],&Rݼvja_"x/.u>xlC֜j T@4`HHD*R} M̨cXl5,d5i-iDD_dVDiXShh)_23=ܦFV3C2sh j`PGGr)7JXSui4E ΪTZPFkۖYH-N-֩ĆҶd-Y;Vab{sz >oϦnІZ!z`R&$Y+`7s~ED}7삃%"h)ډ0`dҙmƨcm E / TU=ts45[] +mJ5Bh‰rk@AV؅^?p{OYtj)RވdE/k*Ag΀*d^),(ʕnWڞadG s(U0Oގv t+fVpMf0\ij`,R]NwhWˆ@w16G} Z{yL~I\W<<A 1\a1+M9y::JN"4U6UƋ.LǼ1K*Ϩzꚡ>sY&l{N/IUøf؂txQcUʂG_ỳsJJLdПDA`'V?E 02j FVc4 I/Iy\%"Y.;mD<H:}gF@/Q:]]3 aT6Hmݯa{|ȍxo4/'dQaӟÂz uCMfPka.K? D#1$LrԼmo܆A =2S }'GصPL_No?Rendstream endobj 230 0 obj 1687 endobj 234 0 obj <> stream xWnF}WLqÛxqN^@aZٛ\zo:K}(dK9;sfE\j?b] j>xFڏ J!fby$8L¢Lߟ=X|0rx "nd =gzV"qB/"A N4H#O+B1I<FÔ5/ vx%Ȓ7'>SP +%fضou.7oowqY-V h:$_vq=S^@+&5I=x~ hT G>G bf9/xְ@Kk\+h/AU4c JVb^7@:]iF-N$ؚ`E6Z[f ~8ʀ ͉t8c #IgKx?^#?#} ~ ^KChgl):EM=xC\hD# lSҁwJZtج',?|lz,3A&:w )0=n0JnV,as3r ^xstypJQ' ^/k&h>A^#FD|߀z/t}5Rlʐ -S`åU o4ym 6!t֟ۂuLM-6kό2 ۭhZc)|PbZ#^;ZOȒ :8i "t:6ua9Rכt0"t`{7ɒJq^# Zw TOGQ`[`kJ~1m}ǒ>YqBl 拃רFk'ap$fõ㒤mxGIsNE1eѮDg̑G}! %d!]4طq Vz)4im)x)NGSK\е(k\JܩRݽajuaִnw8%2W32L٢l<ܭkU",Bӊ(b`-Vݣux2܍{{dp(oq*qEP@|dk!jv⒘xN{kL Rlqo7}Cxws.D6I Х:vvi?Dp2z6ln KM0-GfzC.Q卂Oٿ_ ݐ$AC3_{mh]"i&YuH=uj@<=1wi)JGc0GtD6ˆck1pwIΉC&ao_/#Zendstream endobj 235 0 obj 1649 endobj 239 0 obj <> stream xX[}_AK׭D9~Xij1ZnQx0P$s3V榕X,lȏC~"eS?]uo19|ͧϮ"7X?l7f#AJY@6_ Y/NZ? ia&{?y!?ܿp֬Kjڮ\1eq %[q(j9un60Ț4=_okfӡu*;E?(YdwsQ!*[ԇRE%۾#'O>tðY|N_ó4 N%"ۖB*;cܑ]BpLN^yD2 }M{@p9*T-! ïWܤϦdܧ0g&">gթ,Yȧ~"ŝTe Tt$ߒWT"8vwY"k"߮fm>>ۇ S[ vEnפVH5h=Jo+bhaoOJk_Y_? @ </[cS;EUD0Y3 gD,,!)^4L !RSΖ8 d~Q #BLu2FSk`RCѤY%9c[45)mQݙG4 X:!F~qڑoWz ` eHyZkEVb<\MlhF#ywԃ;bQ Ā+=.w,'J`.ك /V*Fu\]1+{(kUcX9l8pyJPٍ*6+EiƐ#3l;@t#HS׆IR=B @B:~r|n]u:y9p:~QfSZL'ᓧa;04U8AfGSRqPȢW:m31Z'>z͔Mx^hC{ߗ8p9Z-A[Kܣ=FfDstcQgh*mb@VfZH1HA񬁮"grw hӅyysa ֳoPu|2 AEA"A&+J岋9/TQީ{w8LQ쭾`J}x}VbVAӔ"Ǧ]:oI)xgЯ\kސBց@)i|-NZshh5[zCYNH#r15Ŵ:W\/͓x &WVE2#y̨c&uJIF emh8 V7irrbmLS0{llNˑZ^8T(IoP֫^ù963ȋIf5J" "Ae^Hg:}X'|R=TfL7}w,-ʬxҧqLeR |E0מZ~6jZ\~Z=ЩOƌ!;Q'GL 112\`7ZE9fLJM!d5 A.-ȷͣxx !#9' @Hc؉}poP<{̕n` zȟ&zꀸX hx!&/. m6ZSf6 ?Q#@vRBڂ<]A:p!ux} q;xC@SAe{җb[H[F 7m5"mJfv.yRi区p€~ G.〦pCFP}:6y6h~~ENF]LWeLZTF+lq5բzsCUW6:j۔GCS,Jaid Ήmkb>&qQzja^Nݓ2,DЁ>dx+]l'%e\IJPJPQ+SjS#oԷF󶐧մ*ŧLJ6}EdCPGH'+W)i67??բCendstream endobj 240 0 obj 2363 endobj 244 0 obj <> stream xXn}Wźas 2`ŃIjP.k+A=$aKk=u<8[>?H-@#;ӯ PLOsLR슘"?ҧOw-P8!dߧ'E7HHY>8Y7zz}بQe-U%/Ҭ҂EzU_T"oچ@i]W|UKYuaKMEy٪%-OTdk|7~(<їSU,evQ$ZT]e}/PEFqDc"JwvǧB_Tqұ0YICJ{E?kU&O?Oߵ\W$6 j ҖP[cfW}P>\z#@>ˣȴZVhKU9c-ljvPܺמH/Nx^7DsQ!Kl?0]A p&}%$7kqEdY%u xA2ȅvP gMbd0Ĉ:. v1.x L5K@߻4y&Y1 0fX_hKf@eִ#4L:7'Ѝ{U_3$q$N  fq22 لG5/UW!e"BdK`s  s.O? ,ǎ 4 Pai2k"QI FoOVlYeh.j@*^VGSnAPDntGMڄ.`pbꉓ"!H= 7mwqkNg?Nw/ l.\/7lrw6}5P6v{dWC]Ü[xC[ 'tL;پmG:Tzݛst5jcVk%0s)+A&x !YFߦ@c(t'\E)~?|wFhú/' kٙ3QKO)-qTh}U0 \ArT=f]!&Ed@5TXjٺa{]8w _.{"NDC8hO*G")6Dٷl)C \FS多Q]o0HhN/ۣEcA>x DT-MbHvǡY(}$<34L[wj״5>#.Ֆa1_}I jf:&N|ZV) 4]UW`ɂa 5u(vv9T zZsݬdx0nhpM`V,hlFZa:0WGۡs{uO Hm} Ca@榫a>D:goP> stream xXm_Aܗ\׌(Qoh.(6AsM>6U*K>QZ[!7Sonp^yfƟGO#~yiw+na11ꓘq:,{I8jNl4 .O<~Z?ǧN1-l%AD$MUZdQ ,은☦[@ԇma{ZVeh!{,s%_>VQd>O,ij$y%@v!+DV$ïX%yy#'[Kߧ~oIss8Bg2+˒Qb=ҧŽo||t_rp6yyZfƵNυk qn`<v7k7ibj ȗu"Uo!2zkLE M.CidKM,<bXۗ%R8MZn?3䌓q@vF.ei[rNH6}05kuBCִEM$ٔM5J)/a;85ȱT*[s<NSV?syPdH: ? =Ini'vJ,97G3$j0#TRXɗlHk1ӡ-*)g,^bM4nkyhd< =%E^0o'.rhPE4ƊwRO]Ei)Yƛ֙&ZV0cҊ< fG3p*6/KfN;#*+ 07n)y='`LXM+թaPlx`- ᛲ"#2i7H5Sz yO~.+Jc@6+FP䳙tDֲ5LI> Jg+t9tl/o|Tvj%@_KU\zE;dAO`өj0~?Ցd,:O$)w4$ Pvԓ1!n$.+՝ M̿ ^kd#t^f $N7q P _/iXWc:˳qY*QO AK7ibO T'_gS:/`?ظ*ې]S\ifWk򑁾[ɣ5IWϚd%۽nܼ< loŝ~E ]r%= aU|'2ZKͷJ9yU&֚E5p+1R{*2Ha~n  r'htIöny `GCƭ⇹U&ڿmCvtWXȐ:=یb 8Κrlrՙȳ6I7krc4Փ%6Yۆ˙8H_zvsI{C5 Yp~QɉIqk*~UeN wtC\vu릂6ƃ?%Sendstream endobj 250 0 obj 1911 endobj 254 0 obj <> stream xZn}W[kO9XFכ۪)/ȱ|Q0v Ru뱮x*1RV"e/(ߵDՑԣKDBYBd\U.Rȗ x 퐢`V۲WRP(~ہ8nq]#P=%e /(#fXr${p^۸lk5rQ=l>M.'eUaOQ-|Jh(p$4s 0s*yډg4NxMl)V< #8ͩ@@FH([B^a%v) vpEuطӓIw ` 0O"2KW4MݎYNHq,-&Uق@  Rg.4hOgU }zկp),|9 R/0wr'e |8Pqߎ}Tyi˓ihCK-Lp`@Z6opI=B6i낅o:y V4 lMYx0u< ] _QMTAdxxÉ\ +22e?bN&p'XDy1OkHBS%89NY?ˡӭb_ 7R1H0 +bZwI:Kfx D0D:^D(rٚ87&u.vP",S ;-][9 &w "̞o4aJhc+`DX;=%P40*Vk$2{hr[suFӂ$ȘI0'a1q.&ю[MTڵ8IGDT&nB}V˳ߍR@4-hF.a,:Q,}" nEbJW{xZrs߽S|^ S8$qTdSsTA{Kv@nV0Q$~, kP>>i'Ӑ9_<,-yaPxjcZH(Ŝc.7>ޯlFyb#GUz{y(/i$F2+< ^b ;BPk~voc(cDŽb2m ]߉ڬ Z2J ؒ&[2)8m1XEP< Ò~V`I{`<#=k717s5$V0 6o| t  ;Ejd 7 d1mb,[jMrGװ7" 2wlZlNn0y-31oHx3Ӷuy[єCmjnJqh\ɽʉ AlĆ^` }F!˨3NOBES89Z2 e.PFB8+jݯ&:gf|G9&TG c jC]XyyJ w\[i"[F, ޾v)4NcQϧ5|le Whs/ 0Xb;$&@i>w}wyeܞ·_3̠«ɧJtՌf1PΫM$wtƯQƒA#[IBgO0r. q>\D, ܃݋Z^49ϋW[$SL$Fgo[neZh^Rw"Fξ%د=alY5LgI>}6 ._U+sS@(r_BKI`"'+/$pn'&"\CpfȬka)"@A6v ir`87hOGinsD m%w!Mf,OU2̺ _=+XLˀJ z9^0}aɹwRn54" y"ɒYfpExmMI\f# t^E~b!RPjc}pYPvOj5>kkYlN}Vbh~6*Y}Vlض靚6Me߼~T -(梆JH{%VIc}4a8fDQFSMendstream endobj 255 0 obj 2722 endobj 259 0 obj <> stream xVnF}W ȅ]RpQ($CQp)AbrT C693{3 ~vCؘ w346ڏ~I0(I6iI dGQW?68X/^0d= ~{%As/~`G6tVttw4Yhӹn2rj"<5^[R{XJ5Ti.wSf͟l=LS(%aӮ)UaT*wj k(Jl"AZ3x[czۆuY0-Tgq(D&/)AOTk]Q= lM3{h YyVrmjL"Iu\ }3"_MF?XtтEVqІP17G\qW[Yjp|4clbi<3k\t^S]5snA4?c9`M0Œ^DM[ gVieԴS4Bkʌ-C_fcw_fSia"Ks.\Վu8-Ô^J1"o CS):1ׅb}Ѻh/VHnN)+!ۻYk]fðRF<ӍmH3Gw&B\07|tZ?!<51v}3}yC)cp{7A"UUq% ЊRuaZгCE W$ sp3m,.!a1[nq:$-Y45dZfԱ/ܝ]?CpmٙEG9 %^n>=lL0bRp9sA;-g`vA_3~"\Km*ȓg Pժֺܬc]Y5imR%=ޫ[]reW뇌VA2Y] D;G 9X4ѦydB)@sM1hS}K` sYn>Lo8endstream endobj 260 0 obj 1247 endobj 264 0 obj <> stream xXko6_qgjsE=( )E`1;c-.ȴíIN-۱'If}{>89}_߇/.>^pGXSD)rYD3:X|js֮7wN'Uf,mo,N}$[w5Afτpg6أ,̚7:c'B;XC֨}#5#Ð#XwH1UQ˪IkCМKYR7$3ˢBVVHM3?<$Sr w$Q_1@5.?7՛F%9wYqgg(ڮB>dETTWɄa+rcуCYȮR ՁSxCt I 0,x}s=ϧ%2$Uu>X3#[d%gb $@Qԏhqʗb=Bt8IͶY@.NiB0` "1Uq218E=/g cJ~%yQ'X$X$"}KgJ)*T~;Z633&+vURlus:ܫs}N{޹6KsNs+ܰ=IGb9QE/J`;@IoA&>3{Jp+/k6N+o!ڭEVKK_xP%K,)Ń/i,I-+|ӫ1mY[ (-)m c%7o>7KK3zli|)X6X ]拍M@Dmo" ̍E H}4I MbX 3Oo&/ E$x'xc}Ǿ0ni⠧!(P7Ico5f "~`F%/>gedOE?\ᝮ@;bNfޘ6z{^;#>,YIvst,7Wi(9ʼnGg6,%sOM@y^=mnBw}UV,3("pu@voUpkԙճT<;s{&5/'MR㖕dUV&@oh1j3Djvu6oXlTk$xNrMӮ6f]ؘLNzvztINk}zdq#?u ڻTa'J`T" U7 h,J&z žc4/9hAV-\=Zz/See%D[.Z)#;m%6%A7]fU4Iat &o$&HYhmOgR+q1W\ u0S9t`9ſ?<.endstream endobj 265 0 obj 2099 endobj 269 0 obj <> stream xXnF}Wf"R/w؇IlN&kziS-1ְI$RI0lI}:ԩ>C8?Vo}f?e-qQAo,7wv`@hir5JY;V!cjm~MIj4!jxǃUP-UjrBOD%:(0`e>X^Xl^Ѻ0c1//$0PX1,GANgvQUq'ʅƢwRk^"G K0Phiߡz9m,.X0.Vo㦪%o氮:i~5j5GVܳ,ŀJ0jyE)w`yto b r':Q"&h L(ڄYU 6 ujԹptcC -7V' a v2M-Wyc s'(=ם0vO %70+{EN^_ H4  2^|ÈSs#=?EKTSb jGNWduor;رtF"O@\!Щe6'Da%♚#oȉ9z짰y v8bNksw_f.j4:bGeW/~n tU*:jS N s_ ެزVMfe8bm=~x[4<3=ږU;ȫ=ݡ=2w%|/[־QjF24δ vVrG0P+Nʞ ]8~ҭgA(;Kp|bJon0`N*V5kgZ5ѵurUW#4M_&3 pêZCy:JhwSƵH \vn5aLx# 49i cGC]0P,Owv^E=́dB8DgdriJ,]Sc8HT=^ kQG4>0o`ϹYZ4MtBGߙQHY%)ܨq˻_ [endstream endobj 270 0 obj 2000 endobj 274 0 obj <> stream xXێ}߯hKd{B` q#YI}I5fKQ Oʩ!gv-9%^NI_x,7=͇G-q(Xnn/@f"rGb//{oZ&KpsZD9ȄЉ=syfNR;8]/?E_6u7=XL< fܕ(vV\N(Qz{$VׅuZ?t"ZM ^ȶC/ mӖZbcSUٟ" -c\_p9涪BU撨$]szq2d͚G'XfI HL-JuäWu*עi+;Vt2](YJSٴ6.N؉VZSh.ASp΂$Qjbt_Y} k*D&kVZPCU q(HTf6˝(D_a2+.+gS&MPͱP<~U>?tA:?TulHlXթ-^H,Ɋq6>RWL3#*_5K-e_>u¦lG9n.VGf\D/`oIM+-9맲mjEIZU ,HYucx2YwD%noRyM'e.PPұؓYP](j۰w!lks=̃|Am۪J5ʴJIVzjJO}+1a2L?̔ޔZϩ՛-8E#0q9X1ťVͱ'yHY[:N>Q ]$.vɵAV12ѨY7T@ךAxB2!-475xԀ틄+5B vt)(/I"ل?w4W&Bon?wՕ"pNm4RMie3ecڱ{վ.F~B"7!+XkՊM?1FE CiE`0m}ܯ(@@rsF)t_'d,Bf`檪NYY/R 躩Bt(Gq.xFN y>=#v쁳_u lZ cYC7GFmӢO쑺BtI{5hS5H}hJӚa(dGM&x#Vוo"9x^fܕoۯ Bۯġ:veX=uy2MS7(}2xF`msEj׌5VkX.0wݗRH`>2Ԏ=4ʣпz2 )X,cDpqyEEdo3 /C~genؔER ͸]pk4<8L I$[ߝd.eUosǚq9sF$O<9pN^b`8p<} PdَOlg#m@{"v[ .NU\Mq,ue blu.B۪vch-ESUɰBx#ƂX}Ǐ d^c<3w(&B96?Ld{\Dg6f=EzҖ YnL!GiL HCh_qّ2)3qFuZ9яޑqBM'* dBLc LNcĔK-saxXmO~pyS(6Y~e&e3v 9ϰT͖v& l ejFX=qsZn%ڀ$D d 1}Qv8k)hVTuXMw lyLWP4 "&qAI=ìqw;f Į]y~c]i=\Kz]; -Ct[CO3fMvt*&0L8]ߓ*&3] EE YfMs~GcM]'-4#OA5HO) ns{L\Bw۲ײ=Z[!He p=Pk%#[棜{h<մ@I2kaqȱvsifĘ$i(|8g 0wfcBR@8P`#0ϛL\>gaT({G#b@E? uATh-wy|\=誉thmf{HXNV/Xis uHpli3TiӦjoC Ά9 *?{j԰P}а'S/դK\g'Rgۜ>u/3m} P΍v- Mendstream endobj 275 0 obj 2615 endobj 279 0 obj <> stream xYk_1߬MVcߌNЦn]-•F+&)Ԫ_s4nPK-|pn:Q7X>H2IxiZ`^+x+~[ݻ+"̈bڕ^.~1`AhE2Vo;*:șq벥8 e*P̲ 2rFىϟU81Эf%xcKzuM(]/AEP3mXtSP:qMUط֘he ;\S29' $Ym_-7e]뭸M^ \n<}4KTPqh!xޖRF,[]GmAnͻ۟&Pof+rGZAx1ToS3Qg5?3'Bb.ǖF2H]O8n*2T2F[t-DsBGtxģĔDS}/]ef꫻h 1o_E{1XɎp!a怒JlHpz,2ǴKF 5 J٨a+<.P8#$9vk~ѿnÁ*ELGEH?nhYڼEM"qk T{q?3[=n@E/:tI(AWX~8a>K(}0nV(]S\4^º~"B!( 'AϢzHVb>drEbCl e%{`ѫ1 Ş+nSm%bbfQ c30 aYĒ1tvȐxnHɃ JҔa9|z͑N`(Т\ Tv4&8?Xk&LDVf '@WBTB8Զ͓3C[G;r:$3X|V"dWZy^/KĉV1e[8p| %x/2B4=T3Z ϋS#4+Zؤ/XiHkzBCEIТfyGO PdV=#K)"[jHvP%$>rBe$ʘRN4U_d]$/4LqL0) ƸE^TDB3:XjRvq)HQYǦb`z!Xތ!o"Bܵ2S)z>CN6wjhF|Su}G*Zű+si^8 ^uzE-grenꍁDu1cX{kB!\{5LLz"B1HvM1_ȃ1b3L\1%$[q$ESu[&,ꅂdp>hR/3+.sQ`zqxD$3B6hY Թ4©%W.-ťdڿ-׆[0Ht!aOz%^V3 űDzmta]DP1b_Ub7JC}%8KQ~T:J vvwl*#B! wB!|lsɘwN햿7yݡFH0,Gl+-QRE&#ohoFv#_6z+K1hojf9rdenJI)hu/ =^&}>vvrendstream endobj 280 0 obj 2657 endobj 284 0 obj <> stream xZko_1,Ҕ3OnP\96E .&7΋!w-brws#(#c~.!#ED/>^01?[;x 9[]e$em/.ow͇onݾyZ24JaQ7q-_7Ӽ՛rYUS"áɖtvlf,^.1UGVzkHߐE+)I%;Igcf7YJD}׫ٖm[o/ss> vid93& )xlv,6_0oܿ-YAcFy:3Fh—.sSژgt Z2keQ~w?RH7c`3 t"jZk+Y4[I <{s^n-Iחm_Տ`Ӫ ,bZ) r֋_,p~퇿w o)%> bj" ~юZfQ6 oķLAX,1dĂ-fV'pBd.q .k#&I Y(%y/u] ;.RH'W5w[_OG_H) (K7T m-e-q?ȜMR.;uWࠀQֲ@zme h?4*W82]:MXg&wYNC*&p)=Sє`PRsyTFA9g4Jĩ$#E:(7cfVCw?t-s\6>&=,fR gmDR,˝"0%)MQ|, b'L |> ┋ ZcXsygo,K?8Iٙ9vsπ\%4uye/PjlHLat Y*TBpnυĄ t0 3Z&qksPE}? +)ofܡ2l_Rx?GS[']g-#DX8M8:)~L 1R^|0X#Mg3 61)k'81ϓizqU%<'rRqfq>Pe@\*M5mV~WKRdre$n+Vx[ ހOo c'6ͶA,M}]aTEۦ=jOA:Izhn65=I}ӀK4SVuKc XA7ɭ#!-4?ӺD>1HUHgWV8SVI۪׽pbg>`Ozܭ3k"uKd"q˫|!EӶʛ.kC^p哩7k\N8-q:K}plD+T(+tRBin`I$z>#N/`RN%јa-lp A}=TP/V-lS5( ʃ1 sZEz\c5IO7Wt~NO ]?ZD90q~{%u0k^ # _T^&c)p GR!NoEXCgPb@l5/!L40`~ ZHC?!ZxsD>: 9t#S-q ^QPsA G fQZͳw-<fw*F[ B]3g({F j!t) y)wuqJfjȉ3pfl6v]( ub^r!tLظĝMqԝ ~jݒ ͋3fua[zMo"z#6h:("=O ae: )uv||}!--r|ހLqz&j)g"f(WU =6st`X]:w  6oSl8.Ȍ™ڡig U}Ge2:0q w>I-QB/{5Q, ,$Q~SA9kNGqKl3a?=8NØʍbrzp]B]x0-@ߴݦfq;c#8L@*) I }5gJBVǞ~X0T.B“r!QНVp4;sl޾S/^C{ *`)GdV[_Bcb?X(_qčQg/ +P#"Rz|f-qEΓ-76p}[]s"?mitH72W117H$)@*|g:XJ*+n O'z|s>ɪ!zJa) ,|}߱ŸK?Fq̾NL+{N+x5 vjZ7m)r7ʎ)xPFE*tVk7 2D q^ }èbZ8ؔ}/]W1G_z5f{.h:"yBXP^tMmK\r{_endstream endobj 285 0 obj 3156 endobj 289 0 obj <> stream xY[s6}:3$x[LЩI5E($EÅ/vi2v&XCЏ{o۶7lo>܄fs?XT\ҐG, as^nKW7sZ+g)?onoϯ_p!V.DӼ遀 {8>ʖm+ur\Ɋu#BQ^/*UoNXٱU*y$]Ss>tmtRCZ`i_DiNE" "M$6+?;feMQXȞW{ݜ9{=d[Qs-۩F]+&FRv1-Ƹ8Yfvx^k0a>kRw^G%@Z}Qf=3*lU5$w(\.te:v!2(2DWd%ɲNeU1".=}C2 %Oxă<c[UFvqe62%aά',͒ziJ4vvGYʅwS? r.• Ʀ4$04L7/M֣ߢ]zfWTEtB@wl5H<?,,QLdXd~F {w]jhQck{k5ZP J; !,;tjS(+SȻbt"lO!=qqd&2De=pHi&-x@Qvp[i|X LLve ett"$/:2C4_ fdvDMCF,BwQ!1ĿtR[+j-@X"yƮYH=5U&*Bطnq{`DDYr"cBOMA/i$8y.42(3׷>h^(\T%(ǽlu/ gh8u7$7T_cwuΓbbE:>4U\D7`QTHG2Ŋ7%< N>m+"( ӠH2jl 01ZvԱ }@d##b6ڨڊ26Nfr+Ix d윴WvGYVĻ>~#C6, t6e㊉8POxA90(v|InA[9]!cJL'z-sPiR uJ1Y؁ht"RyNӡQm"r6R.(BL~ĜY"e"Oni Hh'""NR8BDʦio @CwnLX34 XKSn#y #)xtAS,oeG.!: $кl0GUI .cXiץ\=aLu*Hb[VeC.KyZd (+*aPd}ڕlK [#$Zke5c!8yhzoJ;MpaNT{F@nsh5AQ&)#F5ZlE-!.łT098̓^WN A'}Ad}Z7 QN?_)T0+OpgELȢJbzHGk&wj .$dɎFj_l-;$k+"jbwHWSZ--=XK1 g#U/3A7_>qNs|mv>o\\Dq=n`DqRıӃ!C>DܩoSw(N>htWw}"{[Mҡ4љ0M=^h$'36Nو(4J0 6eC:NVtŎ*Fn7``􁨠KcԳ̩ͯendstream endobj 290 0 obj 2655 endobj 294 0 obj <> stream xYYF~_o#.ټ: d 0H[&%;XH꺿0$gqLJ컫1?n rJ?FIƂ<('|?ׯ߽}]=b1%A{$JʜY$3uc[ݵ>Ι9Xiʮ+ Inx(yd׷u!1 VAWD/;O=BzVdhq\jK $1w$SGH 4-5m+Iv75QNp$})0bib*v݉ñ2$$PV &]JPbo{/(MhSbRv+e%Z [*xLڒ8%,k˧@f *[X 2Nm JeRlѭE ++i,".zL8-ܒe+7~_{8y+vR}ش[-gdy2Z*UBToQfZEߓʒمf!5uݗ=N3Ї%X,L(]*i2_3+o Z4 keźNC_C]AC[C"{/{RN qȗ@S!=UBOfJR]E1p<勑3ɖp )M/N,ru |RDQ@퓒 V E0 Xfu l, ? C_ˉ̦9ڴ3d(4}+<R,fIƺ㱀[mf)ĞSsƜ!_Hs$ϧ;1Cߥj!5dJq_5DHͳ:LA Hʢܕ@Uy`e3W z`JtF5rs= !3}zt8v9o!BVԋ٨ǢJIT|5ă<4&C$ R4^|tH< _5CF"g+A_9l/` M[z&0 .}Hpl@QbSI`l'm(J x੺ɃRDY4M ֲ:1֧~!({AZuLChCrZL)Ȯ7YUe ꬃd+']d'}Q%} 0TwtY 36Oh٪+qOC{C,l3ٵ D EnÔ>gE+q#LjX(Pk-D C 9y=YWnP>KS30K _hw3ր :a0wy ½kYiAqY 71, #wjvbb7MZ|sP-@6TnvpbGB@M">ŷiͲxfwz;udJ,ʞ)F7O2 t+ pTn侬q>- x,1NA<ũ }`өoT/>Ԅ%Sj>ffXwMU5o]w0 -ѾnN.'tcOv1K" qE%""o׀*,#_:rwz;`bD4CrubbWh| *^DBMWi%Z!q+z"?"*nl`/8j7d9Pnn-!A]Y 3L7-XM ׸-NXG)>uWJRg:P݀ n~ك4ȶ 8n4Ws3[ lxE@ <A۷MFu4/6Ii`cs\~xs RtC+:`m~<yp)mKұ^`8j[0 jh&гp@K.N$u\ \]8^yhI@zGlT`|4XvT fIЀӸbDv֐.g"rg3<Ӟ^w%Zhh?X<"N!;l[E c\p1hŽr~^ptJjߴ@[B ÞE/4<Z`2`EaҼ½K3!u/ˊjJz4#Qj/X/)u#{oL tȒ$MoƅU L.K;װtr%uH %]6bL3}{g P4X(`S# إ16tR=@.Ԥ ʼn۲0IudA9UGXP7h. bV{yt:dsWGd5~{27endstream endobj 295 0 obj 2840 endobj 299 0 obj <> stream xZYsF~ׯS,fk'*G9$VX_ @8"p_]qb~eJc$f$( |'IxZZE4a ?{].\(Õ+8ROW]~8V集Ty7KW-ّu^'eM:[UBv]ޞa;)DIYp~-;ٽ(B3I@/\BhMYhPȍF`@$XSEJ4k@ҬOC^$%Eʪ"M]SӾW*?ģW 催PȚ1jsxbB-B47S9È+η'B4 ,3RCKqBc(@YLiBdy:UPa hg<^{$U919,x[0\rt˜7{tDÐ?{D,p SCAeyžEFQb (>̨I?gdS}4tYF"b MҚ\=c|YvY{{{Q8ŤH.qa֕j#sℹR74LVpҩΗE04Gu#zM`N;WL޴xt1 Nx#ZǘEk 8wJ@S؝Qjꝡ Gr X8 }@]+Ow~NYֺqIr ԛ%rWW(S ǃ_9)˩|W3V$ݍk7$;3@ih^ 1kpvkbPa `|:#qB*>bǗ<:`Ӿ,@)9m`g2G`1 H *jA#@=%oJ z989p t.X*[c67܎TKgG||T ~aHo=NkkA?C.B/:!えF#%4-M- "4[Y..X{Lr//jUj%`ݜ5R+]1ǟHk-Z ջҼo\CBZQKj 8ظ`,Kg1u!k9}KS'⥏!vgfcF'rR|3jPw*6jju,+,<.ZyJȈ?fqqN]?|Lh] s0Mm]Xe@)턐?(6,1$ 7!OmrtXi?` rGlg|ځL|nթ AsO^A;U=ٛ)k 8BG5TCvwBN:ffYJ'Ki9#O9tjZ-YϢ4va`QEdυ(#t,'K/r!@c3i Pt`v$7Y.?N/6;VTNYஎˆ1 YN8 mI'n'|޾yK#8G,@`|z&:";-F 1ݘ<ؼ" ; ,".0NXUAd\& D]NY2}F'[9$hs&ursI/˜d>LhZVcYN# _mٍšx@lN586zxGw3N_JhpLGQ6ig&~35ʢ' Lm_:,eVHmKMl ,CYcVA4ξǦ\MIh. > "8`-3(w%nv3t7A%tLj8fwiV1.3 W8~֓aIkV<L&*~04z0VnL7ˮ`Y+oszytZq\Sf@j޾mU.WK]UoݨqO#Lp&[ (r4nPiߍbv/۵HTc9T :Ljn=1oCu"f Z!,=ś5 &X'V75wӛXeᰕ%4PPOv!eԚ{׍ZՌX]c; ";ώ{) $ ' u}7b f RK#]pN@ 5`#YҦLƿ WӦl.g _ѫac$ՂiLNJg{ ˿4M+l}'~AgF (DPlbC"AV, iti'&;_,L$KcU mlG$3]Xϝ !;kRLn&TRu47moꣷ@{>SqE\m׮g$.ҟ|YY][KCurH^S@7""pv=o~?NJendstream endobj 300 0 obj 3219 endobj 304 0 obj <> stream xYrF}W#2cɱJCyB}v Đ/[NJ. >}t (#1?Wٛ/ʳ|gΘz*HNn6g5F$ brӜ-. G) Rxf}\n9I'q#Kx2͋ h_=vȁ$-hN})nČaV4,eSRB~F*[ڕV YL"`(V&alvKM3\ s3G?pzvQDSXҀe_ ݲ-.RWÈƱcbT,Um5Te]=reEB.UB wч dvη] [.( h69Nμ2ZȺy2nY\(ך151]͎ \ L;mGƪuҋUגM'0 5>$$ N0p~Y7=vxM]7nwd\HQ ڷIP@70~힬F\7c0j c?PXˡ[o8H -yPh~PeU뷟GXa(h^|GWYLd:_0VBa:$!w ;%R8m@ -} KuW_/ύF}p7Դ9q EQj woc)S@ [ U]]~ub q6^ 8M#s:a{Xw)D<৸8Ew\sfb Pֲ8uwX'i\fJ`QuQ3F:z%2Q Ig x˞~ͩv揟?śS<3D9yG>Hnqѭk8A89Bp? >(v:c㯏CR4Fz8?*8 >öuwgo`w:FdI0qKYU Wb-j *5WhsCS% O,MRd3'*J2_GQxˎX|31k{I?B8&Ը4 i8 '1DAsrfP&4P2',`/yR&< B* La#sg HѠ˸Q#w%D]@G )ȉA#9dߛ X ,0錭*: K3q_XB so1#'ៀ={-#\5,fSP}zdv0QnC6}NpNzwҟ jl@%vvJAYݨ98?ҙfC\ |\e&St>@G C4e/L+B@JTyLmTC{ baM9l5wUkg8]ֵ[~Ō;?. ^Hm)xXAFI2e5yH1P5VĬ˸ R F֕Rm:f-6AjڀzIa 4btf慷84hW޾: \04`XL"XSl ȋzo.|xcdہ Ì 1 f>nJ\ ն0܁[w'QjbV?{!L SxBAhB Sϧwo?J@YG#< ׷T?\Zm sحFN \;u)suw -jx,dx9Wn']]0 F14ZTrCZ j[leϭY7uy(c铁de ir'w޶3'5+HseQ^t]I׫59s84_ o1=Z$GYL R;pn_>Lĥ5='DZuJu 4PˊƁeY@; z^:p)-z&x?i׌yrW!TB*rIKܗ-1&rYWk-#ӝ*+ _1+2~?\a`ht_|8d^ \*~CWH@06iP7fs{t"a2MoMzk lbgDɩJA=_U(JiUR؍Dr K._x JmEِ]کV垬ˡTޔ @N1wKdȿWrXJ:~%o謹HlJh ZeӇ^3~\]Dbf Iq[W$8UV9{<`n}>*6Ul0j٫Fm Ă}e* SSn;GFΪJrsFendstream endobj 305 0 obj 2721 endobj 309 0 obj <> stream xYr}W̛)8yޔ7+I\ 8$Hk>s0dűR*%}P8{Lv!/xyR`\#qR7 Cc$.W/'4b_}|{"^x}s]|q)#%i duX0ؒI u6h MhE$6|)G'2ۍyC#(ǫ]c^i?7jjl-IzEt-6 ,YuΙv>MCg|CJyҒvu^ȵŁzo<+KJV{xUy[򞰯o9f~Gp,pszI# BALdv:iaL0vX5)U=8,[jj]R]MSSȚ i8f!40r6k$Z܍iP/gX{uj,Ẻ @KT؊$l ٺ(?b7oo? !KIR Ls89q%bܐahPcy XyY5N/uC, Pq)駣7 3 mPY"EtoSC 99dUqGAaZJ"-&TRM#>P.ݥP*մ2'Ydk`1|# 0It {2or Wz2K٨ *K *Uw~"ۡr`XJ^}9iYF4 7=2?3ܐ[|10)TNH"Hޓg&:ح l<:a Ld8$#y^7EΘ6V]4 gە]AQQFhUCF?d'V`Ԑ<}zrE>y|/9(.x3 {'@SLCr| "ۖMt$}B H5;VG,"2bE}PR ]#In54$/˺ۼ|Yx5RTOdOM/Ys|Ĥ6_}г  j{C- \cAfL:|hp6_nAO;iNM Q nxw`g( cQۑ& ora h:ל8#㒅C<)8XꇂwG5kr2Aw ᭘ȺAZy=sPR£%o,,& 5[ߚsb sP< e$cdPo g᷇K|h?fjX??@n*yPs`ޱ1g.7Ɨ;;́ ks#XG'o&;Fȩx JNhNzFenXhq5 ّܖ`.03bLx-uf(Hk 1,{^#kBE q}khe߈Q ĝ:F$M̎CgQHbpU6|J[P]?rD\it*X3qCtUђD ̿xWjZ+lpm r_ٌ7M׈4>Yy=t+D<5kND=u,?AO]<[?[87?:"endstream endobj 310 0 obj 2526 endobj 314 0 obj <> stream xZQsܶ~ׯ@ģiZwRljt"OX3ɓH3X$~QF"^(]{/W@6kI\2F2N3"cEYLWwɷ?{_\Ǭm`Y,Rz{iH;q-k3TwF4Vow%9}j{]GM.1a"=^4JԄJqAt{M&")eb&@b l"zc12cW$rP.xQ޳d9vE88ʢŌT]Qpu|t0VLc:1Ma[Fa58Bo$4cDT8=ӧ1%C(;a^y()?73SnȨL:{BH,C #h| =XoB븠ҡmO\ "A̺A2dC*<6G0hz|g+;lFw ?] e!(T^ˋ^&\ (13cjf~BeM?>,/{|C%b_>bȤ1~P+,.tuPpcqb#- mݩ2;k!5d£Zp8|uKO늃&Ɩs̀юi=:,*^ؘ}?X(SPow?/is\sFe uj*\[lʰjcLX+C4NM]uM][=*BB!Y}:LVNSʀ@xn P7J7P"C-J ٝ-{KW7慡=w;mB!oEuGC bWۍKW][o8ezQe T?F&u6h s&)fn7MqNyypE)Uqz\of7u-d2HQ/P#Ϟ{nV䣶%)ǟfֈ\j&΍(|nr,/̱GA :X 8bdP@-Φ 'lC%.^ ,RG ȩ2j-7aѴ';X.@By)cƍEj!eO]!+F \Րٶ@,!PlЄe٢|7fJ[K/9n-)s,\]à/ \K4-񗏯þAլ&O KզA:vOr=#럠R0#S#gt**: xJ:Wұ^ BE.LSތ%*x>4%㒘f5nYjJ1tOѷAx# %O5K:w EY,J ] X>gJق &ϪXITȏ%m mCxMp$/z95x2l'NImw :A̰ǑR实[~]61(gMj:A Յh3rOUOeX݂m 8LdBƁH>q|9|& yƪnNʧf-0T$u^ggNX$Y;j褿HGj)sRB>񥭆ꃟL0>]X2ๅ4SZa;FMdƅXPOKPғ6Q_|϶Od; gE!égѵٸOx$x(K(j~6u\u@giY0^L a|;B-TG>[d#VWHB9Inad:yB1%#E;w߿| ҟ.;2& ~Ԟ&s8(*3!j@bg$|Ň60er"?3 3N[,lυq˸ъmPߘko8@4wN_Q*[6ZRWV-"&poan%`1(9l:Zqݞ K"8;vHhP#@[yskX a?kÑ^@{{j{Rcٔ4N=iY 3 {Eq2tp{',Vzm+o͸ps qjh63A'x\I`JD-fMy|E7lm諵E.<4փMZbx$n ;egn™= ʲ P[QE"ց5"X'=!yA?,JfL`{1_9gH0;%>qʒJQ⥤$J#7[5z.3JL?Ԗx> g306B9jHP+}=`a:G/kD8tEP:]f(c93l CuWJFqr~,IO[^(uͪ yh4Y d/Ѕ31zMQԅgdĚ> stream xZn8}Wm큛+1 , di8F-u$8-)J0Kb7/SEH5GE=\| rTG[/njA1In?rp!R<᷻w巛-wyk"nh pVBL fW>v@っS(f 'E08QGPQwIep>vб|Be3t0=kTPWTGC}<5\l1;l,bQLFs3֧ʱZT}٣R "EilmcekНeѱw9h('ڏCU6|>˘^rn+cy;4v84ɅiRc&V?IgB-ajΠݢOz>ߴh(cQ_\X1{N/|Lj8 3RK5&v~ĤS\L N:XP.0qxǩ̓[2L'o~ EH.P5[*Ø_4[fc3y9<? prm5 'Ffn\![@N| %E@-`~Q$Ϻ'"(W%<8HHXHra%8_,9|cS:|kyqH.K2PYU]xw~L\>Nꭟ9`ݶꨓـQwC`@sQf|p r a-CNm;  :/e$YI$u!MuR0 ѐ4L&'g$"jRӀN.,M"ddx"^ˋ FdНѾCZ 8HEzƩR=UH#/4|?^K@yX0 }p1<[#z9`(/+4+ˈlUmy#ҹ;-/I9L=Hcu,XޕFN:> 00WP=ҫ@ύdJp zON R` t8?F\r}1EdOg(ڽ̊rm}yUia)oM=>)B=uM_Kax,U70Krzϫ^WNSa뇶lP9?Fo04,9Բoq@fϷn>@a[e}I%XaUO2 $Ir!$PZ(JXc_E_APc D_ ~_*lj鵑9i52B-%lvmuHF-Ai\Gk%zxeiI1Mrˀ/@yՈ'@If)Fs}A~(=a*S3bY-F a<^$yl̚[}b8*sդgwL8qld5B C-4˙~(UWZ n? M,a*e!$˕*~'vc0 -p(87UdE^HEgZɤlr_s gU;q#N00;.aZ,Ͳd5S6Sr> stream xYMFW-ňoCHYN XsHDG$Wݔ(azZ d?suX|K)BvaHf)Q y󯷿xw/~ݫ| bp_H.ЉoIeY"/ W5O;Uɷ;oPU*ISNlQJY>s3_lMS% EYcP[/Q|K - 0LJv| vV9$E‹D|maBk#O]`1.`$*|)V -MB{O iQTtH҉NBf)7U?*![7*X\ )w+^{n7Ln -$A;ULDwKplo!]F*f*c$J( "8 +S+ NYh]FZ(Z2-EyZIl7!fq*FF2F=y8k;bi8kxu,WŤD9:9;L0[W\Qrg~k8vEoyLoΪ+xqz9S]9$Log;AfPT#\K>D%W g8 kgӜ\O''ZI)ss*s1Q6ɤ{ZYIk+9M'PCpssOk˜"̜Vi#[ UV;o8t{>sZ(ӜW|bdLK(9tިH y5Q2Q&N3G'*!6醧uŜZE<Y}N?! ӌY04Uڳ]V.0  o9M4>9Jw$NH2KReŔe q KLj|A3H (0ҨHUdB"(NZ כKfK2I'"h`TJt.<)*U<Ҡd :JJ:4e" Cߐd4t8XHZ;HBzp}+sEQOB^/v򭼳9G)g_ڹ Y祝5k&[Sd睳|ŝIe~(Ad/GzRD Ncp\OcJ#QwcW|bԖv"xnFRM% p/@XhĻxx9FWES ^%, T v{M9Qwh!gwM\JI#4<-n6jlc4cj-j%i4 Kx'0,Ch!÷Q6UP-)KD3dthcAg}z!`YٰNxhih֢<6v6wI}x7GdG^{C#ͫ.1b^!>rs((WH! r0]txhz)C>颡|NbU !5 hNW=BKeϲXxJFTbnwzߎϨ v&AN2> |\V1B{ה PC8;zW'uFjqL۴"=) ǎbtǺo{Oyyˤҹ7K <Ե-eu9dbXf9P:]c<}3vtʢgP'e)na׷?b[`,RD.\wM] p@-^v^UC1}ݶzY-t"9BZGξD-'wH? C7X\]Z _\̊϶)qb䙊[aZcCeEcدسX- T`#r((Rytܝ'Y2<kGol+JR (PQp%@u_%6Q]#Өf[DKYا*v=&=7> stream xZko6_oHJ~niŢ YÙQzu~^>%Qd, #H8 EHؿLѾп+@q  ݕy N0Ei,0|/^ԳL$8[w?z#D=aPOn<~4CA+̫1BpF&]j88O`t u}/uTI=GFy+Q5ڵ1؏I\w֘8 /J՜ulWsY!ԇ$2_&8Sf,xD"Ɣ5)C޾y ~l IL#, veh+!fGLS^H؛AN Myl/Ȧ '< 'Uիpj>Pf}K1w]QVU7mgu%X)pyvMbPe`SDWQޣDz"ilpKhg1$f~GWxw]tV2"rX~-wP!xK_+6}ڌ92{1XM{Vb_Ayy9g>)&L+#<)q~G/ Nl)'i 9ꡒ;J]Re=tM+s}׷@!E7ѽZycޞB>mP|4 : 'ZˍVk0Fcn:hr$h XUKlQdCjlq ()a1 A ydUT v46oPӆƀvZ.C}rrdө56+t#HRVI1(=4CxNX\ٳ0fc{yV^v' W(_;T2SY,BV/G}XȻN|`Z1-D Dn(RBP&0RWKe'h1 *U$TiA)HddTL"j4`K<20 MY#lZs3p u?JRCj ߀D_Dw 4lWVL h&lR2qpl;%+#I99}hM@.L8 baNi tjqI*yA :c>]bwx#L5vzP4Rhs ;dts>Øx~Nye/ۻ*N氐@\КH^g=c Nz(Ofԙ7Cȸ$D&]i(k̢!Y /QXЩt^MG{,ŪGtKln_ba 7skE  vГ!JRκ> U1t;j? fh? #["wZW@LP72dA|AJ)FR-U`JQi>o̲g̉^;kiύu8jy{Y5m#Jm9j̩(_5]9R1  Fw q3>oۓ,qBdd8\̢cJ  Xf=ἴJZ6$Ц<)BP빨<U_O:ڱo:fUSC2аW,СDzI1} `jB⦎붥Jìmn:fpzyYhz"oX,K Is 93x;`G! K\ ut)7ybFf%!)6Nf^h}ӻyopOUFbTI;xzQ-Q#-ԓ^?pyendstream endobj 330 0 obj 3129 endobj 334 0 obj <> stream xZےܶ}߯KVMG;cUd*#^vWHC*uYntsu(qůlO6W.^}7wx(!1\(Oꓻۿ޽~ݯ-,|/toޭHT=QBxd?oaѪVm_}?jgkĉ8_iKC/4o~툨x.%+?.ShSlC3 y_L0'0s]]6$%)-'7Iڒvj4&M$/y|M652{"yIu|!w;Nt5$ycI/= MՕU#bN#sr+,@Tpi CZ{'ܚ >u|jINf$A]7=TX^8h,Keqc9̥ڞ<|h+#T|%Z%_عJa4rh}xXVE9q s`Liy4IvP*oKGCs4nDU|.9<QM[e|U(җ|Cc@doljסrlhi4U]Fe)Ǎc%=r^ǜ$tW*0eNI/Qh6-Nal❕G]'L&:@/qZӧ?qH~3 _] G Gv* :a\[Cy] 'p_\!)b@$4>`i,}ߦF{2%BJ'pl+QOFQvy:Es1Fdѯ](6H l&ͪ5wO<]}_^:hEc+oz" `!N\y>#3Gk>:m?WHEZ/8G󭠜K{%gǁHԳ ejK$A$'C"m B _ޢ2< -˕=rxp0;;#H}UdyQHifCC\FX94oZLHյPcEmlGD"oT8QlӓuW˵Dy/Nv~ȱW`U jMN18e !B ;p;tJRpM-Q5kO/Jo=q9ogO^AUR3@q l/*g7O/B LU"ͩOc}*3'g|*̧%P&h[^h25zBZl2S de1R  Weɉ54WQ)R7DMSrE(oᑧPVRp]p\*y+Pd# Q:]h7OU|k&ʨ@7 $(\K3v) n )V$#XT#~DGwRnw[ s0_ ={q:3ZP|"N𰸼]=t%}(oJ ڑ Бg3'ZgmÂ:w?`˫S7k|#nBbEk!9"\ zO Fߔ۪앲j(3~\0Z9/ ,>lm.gQbIvԆ)5i8ڭbH#5zLq1sHQ}l"p[N^E) s=lAI"~!J}unN'f/*]m{9puHȌ2WM9_}DL.׭avMQ # h=y)?ng5:T~įgXendstream endobj 335 0 obj 3192 endobj 339 0 obj <> stream xXKs8W(,,97얫Ds@K I()owHNjq9~~u7 mn{&bͷAm8T6wOTpɲ"ff`֥N=Lcuy P |H1ghPew Pò$H܃KvROE9OӜFJ=/PB9PBA8h͕ǎe[e3$FUcvS\!B#a$ČKHhru5u^'O7-w0,s䁐5DLt6b;^(EDCƠؑHM{xل'pvyiTS/+ţw*>rAf'?="G/GUf_t43Ο7;VIW?, ;,tfT;b-Vg䡣l_4 5aP3]2GryHre:zB aZDDk9xfįr;m;f]f+ DžP:ЖYA[NUqX<_Ͱ)P7g6çgmUnMwR}};4ZP |b?.8v8gO=u [}OݟNj( <>/ml Jf}L:Ese:|FULOH"t}ʖeC(ĝcwK=iBmXabtSڎk ,w`+ dxдE򫞶ɒ CC ZR;BH X/U KqO&6#=n%,fӴOL iYYAA.;ﰴjUH ꟎^sհ9_Upr\. bHgwp OOO3mc{ - h9/n_ $W0 ( ȍ96o$ZR~ [wN]sVzu44bDK;Ӡ0P2qhzlaNĪ us|Fendstream endobj 340 0 obj 2265 endobj 344 0 obj <> stream xXs6~_ %H$rOmx&㦵pSw&0H$ERR.dv[|ḅt?טmO3at~X!5',%![gW݊ۻGs 0zvNmEABЉE(B:Q"{26+@iS[MV+'hB.#77^}&{09 ˊTΪ2+v͙w=g*o>x >]r:yk~ȳ~1t?$.y93cc bLxYėBJ$av}rÚ 6bLi`پa5N uӮ5W5DGSƂb4ƇMX" 05{]xbCVVUB5#ɠuk8:XaOerPraU,r>Bt,e~bM ldt'M)x46hxVz z V#.+`k+xb%g f"=5<4`hN5آPJc !/^ɥ[ ;@/ր)5g֦ջDU鿮1V`kF)E(SMphX.;C<9 y|+gt_;䁓o\Ake} G)̤~fݿ%Moo>L)צKbȭrxf俻;$8$83H>}ayq܈ s)$8ɧ|FE]X$"ɻ`O >%ş,sxr[k $È`JJiϏͥ99G+#(Ue[O=^8Q瞉!zX }IkR*xOʢU+K9ComJiP.md)T!6UYH\biu]Rl Cv S*Uo浵+ÇAٷm}jn>Bj6t-mFK[rJ:Oh,8n'xXZ]IKږfXEmAQYU/u}5-(Ų[mvX9&v1,SF"'$С>P *n:bЮ﷧|7#no&8s#9sES{QpI[ZޛnɎNs&. 2Ya)6>#y &k+=I,IQx0N{>,ϮvoV_?@mendstream endobj 345 0 obj 2056 endobj 349 0 obj <> stream xo6W]<~Hzm M;ʒۿ7%ٲa lj4$3`7v A7 @՟}~{S>G!ϑ:~sSSH8o3}=K{onnϿpy/wqKJ=r v! <[Up03(JxPěTm20&) d]}DF4J}N w9ک(˃'~zI)RKFZuPd ? Yf ث8/baV\]*,b^QT.!29~ڇh.:Yª%2ǾWѭV|.;[g[ l# m9a+E i>DM =;w K(`| ֕׊e=bOi˯%QclobZ_cb?<+1N>ܽ6RFHi|gi;) >r5?<.{3?Qc:e>s*FV``j#iJ;Cjf3*HUz 󇮛DA!,PSy.]c 4_h5p'xSk4ǤjUƋ2ce*x#YR9>q٬iHP)i^:Lb`mTB*W!x ER;-󄨍}'d*Aec Y"-y.D~՚ O5BF=*efGI[HuU;þ`옅I<ݔǾ`Z[n{\CBB-l;bIiiPX֐BiB: s4̅/sbOi{5F<=S)G5#zx^Q<l3煶juW2 ̇lէAp l`2hsa /KS|tj@{tAل65@̴sإ'eOb<:2@C*m6В&/ gzDpm0M&NbMC2FR0ױ򪐤=%&د9V($ڠ0FJ>a8 [h#uGeD+\Ɲ]\UPgExUz +;Ahn:'S?#f9y6u 3GN&<:|B|US^XE<土QE|$*hs#foʈ3M2B8~^A\Y(fSa`J}{5Ha֞E7__XaVgSa<^G s2=gor u18Abԙpblr$&N¹Eo2]9%v*sО̳\rg1}^Wj!%>7L^HxdvuR`g "p5WQc8N /G8闲)>Y5p[lmgC:| 2׸'r5SfwIB)mF!bVU.VR!v(f=R[/McwSl&O!ńAtHl"AVIJ22iT±` =9LwA1Q~z*wcqFh[z3;Cf2*C{Y.MLa Pe?Z6M( yR,N,մ9CYat[W*}ܗ_(j+Twu M-;A`A}·iKvz*X?\C=dFc ,ڠN@WhP|lox]B;$t.]u/]_^}Kk}#ԑ۹5iѬNI;znjˍ3:5Vu#v7?lbendstream endobj 350 0 obj 2627 endobj 354 0 obj <> stream xZ[s۸~*3JM7̤nL-7%)ί9I[N6q2z w$g>W?#!, ?gL@jG~2˛3Ӕ$aFYH.wgKū7.޿]m`Y(bİr}%HG cҼ8RN.ˢcu#O1b4 97]&e0"L&o Y2'ޥ73(yMz/]IYBbl2A H%M[osS x=pQ=ޘg40ϻmޑ.$[6$,<`8:UGÉd5[RG9dQBK0s6Zf;6eڼm,IzǬƻRJ#CF'R=p渫<}7~=dO)Hk'fN^k'?n(`(+NԾ++ZIuS%խ,$wE=\-s®^*jm ( ӄaОS+c@Dٌ{(f 4lll9YlrQM Dw[H،q6c~&TTXRѪvn:9OqG=Fxnԇև02"`'PkApL-نͺ=WGb-@4rUrM 8P6GN6քm)2x(Wm^8p`1YvC dVsç0o A&QlqcR {jA)~R)Wuk=g"e4Ɏ(‬;!JHNdp)0!i;u[pPqD 'Hw}n6t7?j/%ݷgY g#OfgݏY+J8a* e*!æ8 NkTNOO 'ܗ)EƗigT( ft_%R)<~YOK1~H'h`g[QuG1;Cdqc7,P: ah3LYtsrLD:k#*$-DzɺKT2TkOFV\bMYGpLT.h! OF@ϭ?C8 GsZ<B|W|2*aAHzPH)v _f"OBfϗ0z7K":.}tȜI ^-S &uWOP( ȏ -Ua?N_{6SiZ{}D/gib7~FPnN6Zn9>W u,l et}) $&VÖ ٖ28?|S=&xy5,DH"yY.Or뫫GKGMQ0W'bLOǮ])onS>ЃekBKU+yӪ]UOZpC ̔&w8IeV4`D7DmPFD I]|m 4p_&e>iw갻 ] CtoT ,Mn 4sJ3!`ipjciN:Y_IC`" 4HB&|XP䐫B%f][zWr@xŇ{@b m#h[F(YKe}p}BlF/UkPI5G!|L%L ,h_wc9a 뢑)XW_>M~t$Hw|*^-!$4vrg,]8uӱ/N (Аk=v\H)M}[-$?%qLs3.1Z4=aL&UU1#=TC1! T9&(4ɸFK ϓ6oϊ'kAdUeRM1 f|-Q(ލʗ)uUz lD j@z^:”<˳_?endstream endobj 355 0 obj 3053 endobj 359 0 obj <> stream xZn}WԣPWX,؉;#?nlM>UH#0YTusνY t󇿧p e{b_cQNq1 4ʹX^Z~ݏ3paJ+5(ON(~Kl_T$7SSY5-ZdH.JpWϷ5*Ѳ$DD`}ۜyi4q饀BT#kȭtZ1B]` Mj ͑X`@IVϗ@r>6>pinc_<)eMFuݝ~lX:Tz<S,[{NP'L s[Hm1ON1÷b•wyVFɩ W6%],j3Fqa"Mt"']s)XAb(}m0,B̑s> Ɣ )9g/ͅmAnro침)ru#.w!i*g~.nR]?Qo"п/Gi}":qZfƺ4C ;Hpw`˜@rZ`gSg##SQ ZV` =H[nRd9n zW2H<p2.ܚ.a$ 7t־K"#C6w *SS}ֿa,yITF D> dQ7A5:,;:ݩwpG)' , 2}X-#C^Х1iMb?Yb0t0$LfSS=EGnߵi\i )-z ⚎ޑD9}EI2HLi)tef٠E׻45_[:]y@ܬ"ۗ-R@~ׇhC ?EDK&Z{sӮ^h֝-AT@ (P97-I ֘\׆-(QW踩u#3t:YZ{t4Gծt4{+$9cLIӷHкqQ}cO8}JӐCV –vYaU~4R,_Md:i&MxB+VQq>+r9mmR؂a zl衴#i;nWԥ Wu^głDWK pW U'UɥyۙMuc`VS0X:a* r|6\O+,>_hb 0lӴ;K}9 | ܡ_\U&t3%۔kUZҍQ@Ed:/ ~z*Ziz83Sg8N]fi: 6j/?mPi.TvhP> stream xZYs6~ׯʱ!;<8x+UsH~؊\[F5 I)_n\$Aj|lr%5@_7Rr^S Qw7('^mdf$r"r|_x}C^}͏?~v/ (LhΛ/N$+BF%+f?8K5K#nF ZVH<^\M_oHwv S)3>aNØ?^ΩJSeϊ1'Ǖƹ:MCG۲oc!YFO˺\ $eG'"6^첕ݶ&`if%sP%`-%Adt 95M/n=r86wGBK`ZumS^z~ sg/Ofŕlf~YȺG_{ZsEy,7][s p@ka.=^ɓg4σp%̔ʷjd'݇gWqW;'pmՈRP%~k)]-* ݥwXŜSlIn>N27֦y+m=rrRW,iB>*E#۲(-#;Ӿ.gD%hʇ<0$Z#iPIlZ7 Rkё2 ͸2!f]'^;c|+N&FC,4eAL_yGНlYp OS 'Ԑa4R_$V<6} w;!$948yTN~ NU w!m.`+"W M2Wı#]ˮ*;^&= 1IiWpHmxR:ӱ B KCprc2UU\ael3CCEF>[qD8o>oگlO5k˖iOmG bҦ)=ƌzqu^b| /5^@K+ƦþbF)4ed GH[x 9M M + inWqP8fO%(O3(H%k@v1* c-i՛va!-h h{ DkIFWMB&t݉<()l9ub]͜luq숃\`'Du!^nu\y^ljA^cIŃDMUKb+ vFŒ:|r #)y*O֛aT+BȰg@-ߘҨanBF>ДTJ Bsp+[ę+g|4R #vv`@#s4>u;tZM4j{<LK!e@5԰!Wdw8Sh@(}0 !^J&g9Mĉ7LP-^M[p=5d%q==8MF}q氘er߼+18|nA  BhK5r-76Dra2p|9vjZg5lOϜ QC;GvPؾX Ъ]1pYX /s#D :u$p5n2NBz!Y.`,] W)I~ݶEfX]K4-}[^+除 [&ï.d 0 73HpW:\H] 9MɘDnh\!L N/ŅWz8BE#Q8L:eeKBo4KE{T y2؛L .nj;=FmNQ[fmfHdi0A6>ɁBL5\&WS4o8V3z뉈5rhh`};*eS?QΆ<nmA ,`"YP,zS amv`jN7P =hg&`4vŏ&llLɼ :串_@d7t:lEh<}v(#{;_.'FqBH\p8Ӝ 2i¯mʶV@ωiUQ٪zp`4]AVB-L*L\ B`^ќ M 3|'bP}5QVБ``{q9àQJfYtG jh#Ixie;7ʞ0jVZ$"ֱA7MׁOwύ&%l_ē} P?ڕ0Ț5'" r!>΍˳)iB7/ [!7+7!Zy3FWa^ȽEhK@X3Z~ q9|axB`)Uxm=zl?ggʻݒFO0yf' qnϻxv`Nh%9c}SfZ݌}f{ 3r@fd3[YTVt`k@ZּЄv S3T-Y) 乢P<:,k:(n!~ R Y;oRm>/9r1vԟ+9WRըbPF< \}#\)KJf}40ęo*} sƴϛL)REδ{ :gJS@+=،3 Wp¥OZuz~^;FdMc.\~ֺ-K=*e WQ>ӹ`1o? S('N8oblFh` b8KFo&vSlybcRhASB ]X~6/9 /8~lb]!iͪ9n umrYf;7ƙu?lfg"=} aC7H컜27Ÿ?> stream xZMs6WX(ILNfY;N%Q[EJ RII3Y3".{Xy U߳_2;Yܜbf% I9 I0E>טpty}r.XHg˴7>G8aB&TZ.Li5{X3R^P,GWAy{+0WPuIht H=]-q^\a*ڦjώچL܇cQF^* o&qzx/Ҳƾ494ػ// dCtayJpM >`:(1Q{^%8D`%Kts`N_/nkj#z6 hA)>۴o I!u..K! XN ~ ^whFI1I頜6=EŞ+w@Wxe= @xkFPiC@gLNy)V2]X.uC}zE{EҸCW4In h.m6aN,DS@uX*ez?096 |YnSa9m\ Ovq)tM $W%&a-҅ p-K&pS|4EG#T?5i_KJdp/p/޲w@DZ[С[^A>D[{aXK[lfVg"+e?@)E_tp6->]EWٷ<_u|RVWmIӘ c 4HK0ըBJ Z(E14ŗ]( *u4mX"-R+G5YFBȅ7ff; Hnޢ:v*uo%_};">2L.s 9)a=(|kx LСf?XlC~I'P' ,vaѹaA؅q'D )1eo= M{DR78k+_C0uKCf4qxͯNXfgh @|>8.#Cɀ? 3%.V6fhf4.F~[H[Pm |EgQXvZ_\l>SVIz j#5Pv3Y)Ϸ9p6*r%}+7da*?|ɢO_ >0}o \AMl}yj=k=OP-WW6ɐa7=KJ,tUB7}FEQ4ǜ'2Uh݋~E̞^\o2eendstream endobj 370 0 obj 1891 endobj 374 0 obj <> stream xZ[s۸~[!.1i'Vfک@KōD*q~\IIxl|w EH}ٟRt\D}{XO+X$PV AJbq_߿Z__\z{yt~ 8Kp]~+Q" F!jҮY$^zc4YΩ]Rlc8beG/Μa̞~ԙ&ԇ8߯_]m7eS$$jeO|X%k[YWuCf-GV;][mh[O,hhؙpVceubNm4_^|f.bF8` "2qpg Y,LD1 \ EHuBcȔA%J$H ` "1M8jB9U]".Yg!Ģm.7r?[ 3[!<$`X,)d*!U0P)UP rv8q6fI0hD:W X5E[T%0B6l5ܼ$3 GSn} *EfFWRE۪ۼ7zbk?@B r)|q~nmp \EYK'? M<@nCyhedy$ǣ< U#45,#8"4'3Pl3+MrN(2ɏC`/A̱Lhԟ*3 kMKLCR#Π%‚ 2"P]M @@bř3lM/.{>C16oVJp8ܠDWCuWEySW4TPtt dWLp#NtzYPtM~Ҡ3t+;nZ~;XV}uv< NfI(JT+n0Rn E@Y`wdSj 9DBEchWHE͈04qiX-ծD/wսN 0]i xhCK u ?{0):Tt*yz)3k$6n,ZȄIo jڦ,71qȤVkXˮ^VGc׆)M9;sTD"G(smƒ 6d]?E>>iFiT±1O7UUzWWh[@Yn1&FL#ka8UHJڕ9tc,6\jg3acU&us  C pݾ-]^pN2N?,S|i[YUhDS V@fP!WM P h 5-OM7Y 7H=PKty=r`2L(iA)8y(Ur.-٨nڏ]Uw͙Iͣ%ձM#朞T"uWPTRrβ0ԴaVL^Gj@@g@>K ΙhhҝD|Üɪ;H> stream xZKo8W9")1} 6Y;xr7mkW8~HQ[݉مRU_}(eg_=vW;{pEhoEÕ=GPI0En6c]uC3FO m;-9 }@=̨1iv m5m"i22][7P v\cSh_աC+c^Y BH;Ew&gXhs!pN|wdpt,/I"CIܺa׭:\ٮoW%hءOu*k«fp_P7ϨS=[IJؠgEJ\7pdU4w+jC4uIze^HI "b^@c>vgT.Y$汪wbI6vb˪ݵu er4琵͛ƑI_MB%RKBoT,LA#w}(:MR1Fp포.]~+ɉ3 ϱ@{? 럪}7Cvڦ3c<<towռL.VswkZR{p`kZ0ۗnZ{'DA!|KI`OVlHwMC!IБz{t+{N{g\iR h 9gI(Oqv2v*m7= JULl5hИBpW!.bѶݨf|fc%:==-1@#dc3@"=C}d8/g111x=uʀe6tWƮb+ioc!(L>CzSѧ'uPmu+]2]vII֧J6d*ow)*?S{4%(D7A PU!Ӫ:nm q<^*RHyZθ UN;hLlK{V!Ak اWC @k1E%pUAIElfr%]xBX Fhw"KdAup[5t*gZP$-ࡐb BbbK r\wifXBxA}^渤|!;&7v*57׶Q?b@5$^i a*/:!sf5WhXܐoՍ\6RԝeC51ePɔ`"R:Hd@ 0O`KS#aK?d%$hܜ;hv@C WK2<3Xc5G| 7Km eY\B"ߨcd#ё@6ⷓ|P£!t2祥Em1$YLMXЬLp)&7SwSp9lQ'oEF8& 0M}%u!ؤN%%LJ*}{Khä#8 hX@+N*759&/u>i߀V*c^x(4C^f(“'ʮPW6hT.0-<@|_HP.\a@LrHH.Wi}H*C|6o뺟Pm(`Ҡ2Cc:&䶍.+|fU5K}T %bfC%("oah$ʓa`AL,uC8{;O҉uV[2wV\/馽.' ǭ( =rqEÆ~r"ၕ=1'cL *2R;!l$tiYH2LA]<&_h B䫯`/C/OGF8+V#vP~j9>_I#2PG CtO~4G2yM솏2w=ai0;I> stream xZoܸ~_`DJԏ5hjEq.m뢕6acwHDqy( "g3|h??LCwŧ "x r AJ/.ˇ77}) {|,Qsd ˲WC[Gf vT ǢGePvTݷmoJmq89:s =?G/y'8( yR("6pY} n~@]3;?FcaHN>/r?9NziSqiy?.efPId~>`3uَC{C6\} d;%A(lnnoCeZ7p}Ee/h7euG> ]y ܤK]]nxRR+- 3}7S&q:- YyS0/.§r1j לI#gm>8d8xs>^Ň9j~y77'b@+ch јǐ#4qG! (SbKu׷on4#{A6V3mܼ}s0T4ajAXRb k1NNTiZ{qY&2#+7365bYta3:{j@ L3s{phP=_;4X_pZ(h ,N5{Bƒb}cZUHܐSo9J -ݠgNoo gM 't2HY^GRhPl(N7$$yL'g``r5{ Y8R,9P:rĞujTߑ{?ThɄ,QoIqF-'p.5Zt2_2L_6žͮ 3kw\ud--6E=dCS{ᯃ`4h) WA8Q,Fu!W-p^Z+G);,꨸*;6hu쥶yіb7!zI E2]T~5hB|T-C8HՠK[l_j@`lX %VB{([pL*EHp\' Ts uje5j!9J _$̼3wOlAgBfF*vv֪r'4wj9azs1Vb >Ҍru$mw #a7be@cخ;eC]{Mqu8mӶ|ۋ1"0bz.:9q ECPFM7X"BCrߴ`S 7r^(_;ku;JQ~;o3f.;>18(:6&! 8h|_|ӌ|17rk4 :_wu&k~[—ډyQe5Q%Cêtz-#wH.ЏbP8z2d:[ ,B1@4')VY瓶P y?eQ`8[R%A pRD_|GJGs]IOF'l^}%Ʒb&;C[۾b’јR`nW :_Y)>k.|$"y8t$T;3ݚ&Itw)oH Xm^蝞%yyYWb_.էxBܽ:n|`"U<1 /d&&} dt1&޽z 9UvU5Լ$aDhF)U &rgaD;7 7p} Moz{ endstream endobj 385 0 obj 2887 endobj 389 0 obj <> stream xZYsF~篘7SU,xQǢl# hYWs` ΦU9|D&(P{}YZmћ% JG 'p"zUX80|ͯÇ%$*SB2[ZnPmVU7c} 4 pq j`;kLsqMqH\X < ۉ&ξ1"T8 XVp]{SVt !./f&_u`ZjEmNӁD<*N)0QtJ4 $xA.Uӆ;ߧ5d۬y`eiZ*BC!$s&6*&CF4v!NmJMU Q)Xi˵p(TIv;GA@k1K\4dC lPIKN|SmF4`n\:@ YtAAQ0EG c JDr5m_U7$MÕ ɰ y >>JSK΂Abԯ| NFOY{-<;6\m2u) a)BѺPpEgƝ̐,CTx'˔Uf=D31iwf0~Vt_3w7TaTuook<֐EkJ $McG~ڎ0L6 oH]6}uyǮ!hLPӨk3،׭@ja9qHF!k)I.%4q֩K4^neaz{ԼÉ,LS/o!mWn ,cRPJ`[qqttYH&[h5liGmrJ0k=u֜$R7'h!(Gkq Hac$H69%GUw:Vb#S#0X q7TbH]-U 4¿9I j[<"u>-2Q^Li!/QNڴԽUa,E!}'h.[SZbVDؾ@u2GV6=,Ylo!u62]R=ZAb#M?*+ <4@Ѽֽ0$hPHV=fHYMy.NL11XufV5SWC'pY6b.S/mnhj%wUi)4^]v(1LnV7nen7NTTdB ;S_@ bNZĝUʓW3H\ElN)(fSn8u ]r} YEQVΨL^P_#4`l|W2pK6zvril u;wendstream endobj 390 0 obj 2712 endobj 394 0 obj <> stream xZrH}W>1݅J7Y"3`cr[j|fMRI-e&VrɬB<ʈɋ 5'N0lKx\ޜe>MIrBr?9=χOo/.ɛO.߾?xv\0N$PO>a YϬ8|r^ I1YVnXJsh\=Q?"'WXV⦪&h%wY 7䛨+"nġ%y{O%ޱܛ\ ncg몽OÐ<|2/]K̬ ,XyuiON[fcɊ"Ӻ!eu۬t P=GR:) mWƦUfmFڇ@#iڬZBz\Z`=QJg_GZi䣈pǝa?Su囬"UдAv}hyk QM9Mr7Cm"2 T~r`̽98%B9h0} * UYp czWvslH k摁Q9YqI/f7!.n4vfu]=`t@(q #|wR G;c!|p0MXqd "!MN!,~8ȢZe([D1MBMI "QG1 u^?PJ>e470q}8$91j=kpj7dhX p(& J/lSϭ&9=bbGH.y/=]<6;j,irXx,z?'Y+,MCbLfȺgF-))$&F6H ]n]}NoE{!( `?Guɜ=hݧ sAKVA`Leȇט~23wqi=N@G}tA F Hu2tXIі]<,\nMA^TJ"ÿJaO# hB6Pόdq>Ok8ʇ 'yRY@ʶY1bbшk|!ԑ PM)10]M蟭h\U&p0n1#LB 洰aztevs#6d <\xuZGrPN)'-9J3,X9XɟiDRH#ZzTXeA@;0TL0_7\E"P"ͧS˞g'd |fE!WhgKs M Z3؎>/Js(wzXLtG<:3q=~Ψ3|#,rKk55t.Q?GR\=Tke4]gc/yn|P6c3:Eb^m0勼UM)ìVCWsJ^M?- RV-&p@4!&`=p7D]?@FA`w Gy0 2^B(oVɶs{ '?4`u m|=~Q|nk-X5"P ZR ⱳ539^o$@תuXn8ö1u@䛆= &R_zt;%֣n> stream x~Z\rIj#; zeV,ۄmɕʬ3'S֔?ߋNj[c/.l`o`SD3M 76Ǫhj~|7~|o..b4ujER !r*C.nut@bmh6N.i[[xBˢʐBL:R ev1Ӯ-ˢAH] 60dvjBO yL }aİ&1̐Dx 0(6+!:0n9!nv[,46/ "̒_I!uWS k?:{+V,:=✼7E1,泼h؞QixalƶS)[4N Ku $. b̵j߃%%@7Q2-|=y˻Uk벝Z0LO%UNmUSH69u m;Եvjj Q۞u 2@oz=2d!u, wZ[d]ay!T~zbV!TNm; Sl[!jzjdۀ}&!bso۶~3 CV}[U_5pkWAouD]:s{}ZC1S9:yhY/@H><ɉ q|D""o ۹rFRsT}NJc@&[E<$D]XqhGM`u@3Nh9d*xRf|Ε)CMQ/D i(@qkE),=8جd%z *) L`*Ô)ϖ$9JByqo{O^EѼd%/;Aו4C[Oh%(Cd 3>Ζ$ ʷJG! kOLURǂר3VА QHCbhVJBvaGFŽq'WWp%=.Wդ3ƛ+*H!b5݁'j`BC !T )ds[\kh/#ҤdMeߴ۴N)M;۴A֑S]`5ic&ޡmZBvaGFkH\}*yۊKS;\=䵌-2 >2TR0L ɝ+oIr1T<K zJD"G%6xG@ vQ4:T*tP)|$ɝ-o(PZ~:݇ɳ}[:;j;経{}CJCJ0%wZz^fHHT&!+`=yaO車-ɓˎ2I)CgN *!TR0LH;[ޒ䜭x ı CɃ+=Ζ7څ߄(iƏ;!Tlи3|$d-]Sp_U1pUάR;J0c4;_Q**0C!}v!FDm#qכ3Nj$}# _˿u۽;Ko1ұ rf|z9; ⴥ x+"^z_~;ml~lާE<\Zsm+??݇S[CofX҇+PY$n7 C23fwI[_tR:Zy-w$U$D8q6};hÿ0,E A9`=g߽٬{G!fYߣ1̦#yuw~7#fmaG`q4C;dЁTKGb-W[-kČbAdlݰY3]wSp(؇a}{9XmRs K+T=`Ov95˂(aUsJ}uoi}Nݫ7?<{[;q s 2hɽfϼ@%n_?ed*|*rmgxr`_ۑ}0TK~r;f >QgT߁]DoVpxx@{5O9<&ʡaq8A+:O(|<g!'Mxշos,gHSZO){, x_lj&Xɬ[`dli3UESa\!$ s1@um~Ia$ca%VXyL剕|sQO9 HgЏ\F(pwC(E)ZƦH. 7WJߐo?BK&rR2Բ\'2wݰa1Uü6!8*U;Sɒ_mhoasH:jth; ǸZoה M7A*,0#Cu 0I9Ln'#)WBb.ojO Os2ɪ/>'8@q\W+׳X[6*^Oml?3޼Zu@ʲ7&ߣwO=tx:+ [PT Oʀw7< h&lin/ab98^-6T*wГUzg]tWv7cP` +,nJ]Z +6# c?͇- *u9Hed+B6`fyb!UO K0~csJ3+0Nk)wH9dL<>AOuq:LHsryYFQY?r@qnvX9BlG >-хkq-G 8]^#]SJpmcOHu:7ٹ?>e~xPhڠ # z:G.!^}J*d3͊pqasdravjVDuX8Tmd;BJٶӽ$qpށAW$ pVsRb߲3$t:En!8 ȽR#%@_=ݹTU"ڗ%nwfw`fto/([>4 5KS9x"a-VA6? 9OϺAxωAVKD~(2z@Y} brxnі p8t?Z]VX|26'DWB]ӉǯV;@`@`T^˜|0Lm+saF=@]#v#g5z?בSyMAbD@g%U~ޣf-@읈(.o!!yS@(-w85RoZz-*fAȑjH)$'M _"/=/VW! wKϤ0&\v o/~z%2X,כQyiI?ƤD6FuM>9\&YXniQ`HXÉf$x.#d\Yendstream endobj 400 0 obj 5281 endobj 404 0 obj <> stream xYms۸_o3J|}殓4݇N}3GSŖ"]I^tĊ ,n/FYw#eKZ)kr8NYbabLb-ΨӒԞggf"st#+#SӠ򣋀pcUVUN^]Gٴ jGd^쵂~! >`#^5 #$@c8TjtR& J+-p"?SDN${) SS{unH蠴ͧ?6dc &&Ћ/q$yRjKS2X|u-8ȳCB8/VN3xg`0MP-k0̨p膽2U)eh :O0i^a׈Eb#z3M>g2|9.&Li~9կ8 h{776`Ep/w}m2(b&pxV' ve+?uU3 ʤ?_:;m֢qŘ 31 ֏H%]q "۲-#iVcŎR5. z82s +UպSJA ARztoWv{GWKiI?9@]Yo S4RWS6KRєSz?7𤋮* [HF׸7ʵC'~[5!o'Iĥ %d챂I,nqe#]r3gGc5eNJ|tw~$~3yg G`_w2F<ǽԐ~[eA M[7Bqa^6 !kEֆS ֧x^iBTg!* dtFp8+T ,}RvUys,B'@jpx M=V}MWfd KF( "o| =I-VC9p ĺHJ&F}[o %<6U8uQ+ ߽?Z\݅6%ZG@N9̪L_8ah#[SVψӭ< ٔޡhd-ϠiByrtlWve)^Zz 4Z_.eJ_'bEh8 DVF0'8[,Q$I/է5RjA ڥJ5叀<_ƗTqNM컕38Ųs 6ʒhMollt)YUʾ_p(pڊ R0 ~Y&/0^6]@gN-)=|BO>!|39t/D$Av@AĽ403_tiHi_{]X^؆Q5 @&IAE잤 Q h1&}T7xE6 '!Nd ᥇QD+7bUtDaD uػ&ƗR2Ƌv%]4.*LٰԮEїjl.8T3ѥ~-{vXv1fP0kk-Xyd m] Sw`c-fm̏ZC-_b.`tʪ)\> stream xZߓ۶~o=J$AONf$Љ2cIl%R&;O S$d< o~B&(R/so"OtGdmNo+$vw=R)$F|/O_gj, ) _m__pΌcF.%KqL^֌32%htxD̚Ę&Ԯ~lL؇??֦c-KBH#G~/y+7MF#>|*R9( 'aDXY妖'Yrx=f32;M~D6˨TtmA0cQ s5|H!0, zce/7`~QzeƊ }u|,Mڴl71BXsv0 LeBU|2UG`\Z&| 0Pq.N\dĐ u6fX1Kiꛧ>ɕ{af݀ ATA/4m^`YCڔ\yn2LQ U:FmvkeRLKRN߉ 2T9;Wϯ/HĽm/줳';@>iŔ Yѽ?)`Dґ> Ǣymb|7dw) ͊j_3ToObրh4@(()uDZ3*5Ǧ@9~kL!Ao&/+9c ]FF,)Sicym:S)7#ViORwyPg )yHP]g`A=0G=$su'ˈ36K̢Ϝn\1;GW h6 . n*ɹPP}0F:wJㆾg6熭q3Pn\NErO+2$<#3Qm[ gbUz?ڕ)b;z|1%n:(3Wx}LgKjb$ܓ.> stream xZ˒W.MvЍRQ)U[U%$FϹ©5ht߾sϹGpe,OW}}P <]cQ2vү I4ʹj~}5/_Ϯ6x- $xz{W,MH2!h& Z$3:*$ ٩Y82e8Tlwnʡnt5;n7 UFl}0?4!DqY4r`LG3+ Bp!nWZ?ɯIڅWjLBZ$~nۯU箫t4R폺Mۡf˚Vm D ɣp5lv'unJ>q 2ceH)s.SPEJƚGhOuS(8^קs935CTCWŧz(Yijɳ{*3LESro뎖ۂ7C)T)Tׯ)?2K+6<b!b^<ꭥuʳ^D6c݌K[<™y$v*b`.p;嗛+vU~iw%b<֜$u|c,VY adzEY,V{&@@Odn *%?h Êǝ̉q9,~h^a wa讫`(N1T:@gEW %o1 @r,{، O6L26XL2e'/^@j6Ǹy^ D)*#^C0 vFS26îBiخǏkj ';~eW)@wg0֊DABWoUV Ss3G㳏§5w+ AL¾MEncuOM$r= ߗBC&NFk.&ْ_LXkyD\KwGMY6!D`(yqZiDww,J.iȃ^J1ݖ }u)(8qTqk8W8ݶGŏ:5Ewv*_6Vn7ms|h+jf̌cKGx {yeP8ac0j5'ZNd *5E8v5G ]lT`4㿲+l$2 /A%Ui !g9Zl`O+Q0ayVee0Hrƞ]KˈN|!obyfRo "Q wX!3 Gxgs CS4DXnY0tE|~]"e CQVav;Jg%G( ee8q86}hۢt*jCEє'aYq5 FSHK_kt3b۵nc)F-pa#90_[waIּُјm??N7R9$4Swj6$FY}PP{h3~B{b1JjMp~#0NӽiIb^$ZQ6T=78c{oͳ zf?0l%O:+-%kg ,gtVN S'gn73ؤUu˔(son'x! blc< f)f3qS.fLfs/5VUbTtb QxwJ!GjAvf n1^m> stream xZ[oF~>XJ:}K"@ik.ZYHBRq_ߙ ɡM}( 4sw.O,! Op3v^{" X^`nf_Ґ Œ19\,/7ыsZɄg)l.W᧷7_/~zή CZI+WQ\!in.?T-+X[ {ؕ+[kOVoYY]QUKԮ\֍'E"<{f*F]"꿄{A ?)l#6% vCp15p.a\dI {+- )L0|c NmHEl&8.uUwuUo_x(cJ&xop]j]iAfȶjqc<16O}+ ܎EӕӾhlBQ0G0RQ|?bAY18 DHGԖս$az9B)V y;W $PCM#xjlsTܨf8z #e`n _#i/DP#p|>X=cc/j2"M<φYq^?> bڲ S¨>[u}}Ozڮ>.>?X[/i pœX-%Q\|LTdLB%݈ LvF3E_޽W/0O|+'&2q.BEI~ڌ D` NEʭS g[2stۖd9*/n΅g~ O&ς#dH2W(A⚪){2琔 "D #ܚTGSܶ'QmcPsic٘.HݕjC $i1 G":xQѪtS xFU1*h̊=>Ncܔ^fUr5|d$ږ_؇dQvyG`j_?ye#aTsjw~ YzsZwgFNހKx,cG(L6RoggEBI;m+17v#> yB~$>NI'qꃂR3bW81l5=IE͝fOlޣԘ3${Tےob4,/i&y' ƴԡ#Z~MOX-ʪz,>h9Zk +TK7p[]v1o7\fKh.CCֻi_Ŏ 5|Jo<ܩzqO^MMBriԔ\XXۻV`ʕvA~HZ ~31"\$GVl#x ?jQyIQ&VοؘK"w3IYOY&11hw4jɃu4;DZ;;gό[#b҃̓>/glYsҎ\Y5 vC).(Y~ꘀ2؍ҰPW0v,(A̾VX4Au(m g,JE8[SE@՟@fAN͎ .ࢳYE9 (E?ǡUwPuVE*Vz6 ?=?H+B쳃:ͣaF#cFG.aZHpY<TjԗcBoS6j!g3Qn]#]]᧞U,hg|zoVoq8v,6KJ)hc&$$KkSĪa:]m==\;3+ v4yGp0wGC!B5zP3;\zJ3\;ٞ>hYӴֱ~8{VD6hcjDK㓙xCd)q>iNUm^p0t+U %Ŗ$Uw265#tv^Z뙡J3rFUQhxb:i aЗ69?B2NJ826Jk=GWmUG_VDbo'߽|M̽)(P CIXYfUQu}8h јL.Y41mR-XQ+D,գPG#&e?{O:gPЋeTvy#"Dnz32q ͬvMPkG:4}hN?8o)[: ЁϨxڨ(f؛f<R] PT:&vJaQG$3Ғͩi4ElU{?{i{"}{,o{vFҶ}fTrt4W,i߭ E7u`sWUgLMr*Me"@$<{"sp I ߞ16(ƒzrg<g0\KfWQce4Q Ɋ{տJտ5Q@ݬ'5e$ě b4=k/}~(Qw n7eH81S\Y3Z+ѯ@ ;%>N4y^bG;_VJZ?N|NK5r~\PGF]8lСF&8Eꔋ|+jida7]*#}=5 珺40t;>_| endstream endobj 420 0 obj 3280 endobj 424 0 obj <> stream xYnF}Wdž;ON,8cUȦ1/c6oU_xf!SNU|&e/3>"O!匿WL- GZaQBbr_m.I'侺Ǐw|jmR'$J Wl}%[XI+py؈+Z[\4ݑ "mj-M_g IiבGA&#ENMOx+ȡi?9ݎ KmȎiy-5'mI@ulۮ%, k#o) n 汄Ndx:H8.{%)Ѐf3c5m*8Yk³PC(y/բi:'yQ pȦixY6 o{=!֚rQ_P%d8}tkCfunFQ8g b8 2%{:|4ھGJ;Aݏ< ͐"ߞ)oK lZ%x׹o7?uCD^lnbF *Yִ #\&O?,i N.ݮAݾĹ;~ .vØlU(C^ut8f(^ DBݩߺs9fvg dkJĝ"+uֶ'Ws,]bBw"T.ZĦBCX6'Zg&4Y;rO#$IwʚCfbt6mvt tf) 5 UU!1eW Sy e,P[(cص Lw*OktV"a :A/b,dhfUE^__4Bgyg?TPA]^/X`?`l w蔢:i(?6ora_a+XSޟ&lE7q[p^wA`άB ,,e6|ܛ᷅Wioj'?zh;e(E_Jam/mC/M]nq qХuW9AJqd!&UСlpoz,:f,,b<և׈,&|?-M¶rȪT%' pIe}y02$1O}I3b|d(D#g¼p̠)f'\N}f<;<l܌!_ۿBwlo07|3xs3t9%Y66晗=(c;#Jɺ&`am/o=xl2Ė??qx0H3f|* >0)y} 6.?ODiKUq@ \4=RQk1͖%>~W?%тw%~\}fv\8aes/m,V/3s3]t|.:uvC2۵M>rȣD2[vēRQy yv&8@aπ4j5%+ByN1Fs)( ?C"5.3n8ѝyEcYZ l~F?o~ԫfendstream endobj 425 0 obj 2376 endobj 429 0 obj <> stream xYn}W%Ҁ]}ћ$c.RYˍz=_؜7ʞ/H*Yt:y0ȗ-Mv[嶐Jgm&k;(WLT6h#|X b6U>g`Vg[?xN#/w%vK֐ՙi6:W|рFK"k/!srŸA<层j?z%C `h:Q5VnNHT.@ d"uyo5VLeݤRzA2qU7^ϋB5$, Iȃ8p wlO6lB񲄠{] 1sHM^ϼ]; c}FMS0SH =vg#(۽n|5K GVXϬkUݱ;P'9Z؉%mfT )2jWՏ3{݀c$iN(2H.s\g@QQB72PyHr<17F>M4m*ih1!$L.Q+Q^P `JLe?g/31vS@dz2URqf_ߗ Z݋ $>l )8P$"Nj4bNTC6AѨ?qs7y+~x{sN?d>R: n# |!o?>LQMSu|ԥFfzMBʤ#jCJ 1ٕdA~ *ϊtAGީ&C vt$D+Ѳ֨hi;B4u˨vtx6>xQ4Z@?nC9+ht% ߗ- (W:Ո4)VKoYSץL@IyW/ü!G,j`m3R6RHZP[cmT[Br[xGSjS4, wyib:"[&ˮxC3(4K9GkГ 61{>:'Y96גc2h랧nI,1 v5b3H1 {'ظ>MWe!ϓZ|wʰW8uONf5ExEl2P0,Z^5u9S,qx ˙ _(!mϺ_h4Q(IhToҼv> stream xYێ}Wuݼm z $[%)oR7MIؘUn2=.E@?L HCIzI9MIfd}\,5۟}[n1\|/I 'V"4 Ni'eTД f>rsc! QY?/%A.?*cFE1{()$nt#e~ݕoTgiD42J2vݪC>kYP:]w>mD^E 9˴"JV8l+>*}0z IHh8[Σ~Ɛ͜UzOC'-tZ/VMI"hL`(Cy6͏PFT綕uIQ!?te&% 4\T tje '",c]5eϿpW5Wܒe4bq/!z}'4K.Uo.^$:k_:5Y,@!b~.#^7P)l#߈kT͇k\:΋BtW{Mc Y1>ܑ9?Bc7UpAQ9RW,Rݑ %AEyP?k"۶iZ*hVʵ E'LSf#:9U'{Xf\zl}?ճ,,i2D71MG*@4tN*-k jz5Dtоے$A<pkH? ց!`EF')C9$E_*ʵեH3>xsg9(#%z<TUܽE)2dRMR('o4p2a͊1/wIg/!3bDlop 5q2.z0̸&f 2_,Fl7яiBp a 1` НΗ܏Uo?6c!ˢ8 #>ns%T5t)* "Ϋ3N;M뉄fLJq@•{4_[t]B8Aovz@ FoDUp;H}ڀ&pqH!ʺK i`xU>@8Y#`hgN:`E)|(br Ǎ5q3xƎ$SJExYգ@˙ED[TK%hu)3/V^d\,pIPyCnWdD l5O"tlbi0t 6PIfx1.MO'3(fe$qͲ=ah6/@4/eeݠ˶9J" 5"Me 1r;m+ubG`jRN %L!(fYi^D#c^g0Ƶ]KL5uRt H'kfDܹi9i9]dl`ݪ,CfΦY [픖sŮm,qmXy7F!F k<v!fó -No]n^@\3FXdӐ[iY-ӛO xg:AJO4خR]`Ƈ\1x`g"a6yx|+0ZLL_'@w_B]鈋A/U(Cfz͹* ;ErKdi+&czbTjpψ3<"[T}نx1u6@ x ږG'}<啟6]Ze/SUʎaCWOFk{A,1 ѫkso8%: {-尗Bgܨ 6wp؃_7B -|:qDn ,̼if)67 & ge*b`EP7*+cv0^_DyW-pUoc#31(2O*Л8gA$z+?D'tjZ4?`xa: eު+ciWfV~ʏ,0[z& yeqEU=>nSrDdYCn$L۪Q[> stream xZێ}߯hE+cbyS) ˲zę0#6so]%ِj6rԩ>3̧_ů)+>_qu6G[ݕ~{K#e E no~e?|[{s: cA'Wa%gX^UYs[vegݡ`e+vێqE~߇8kv,g_U lZ627l+WǑ`b2XzO?hɚ <M["y} )*7Cf\Q7#_oX/ mLȭ5~E6]rW]sip>7g/Hz-,60Ft.h=L$B2Wc/;IӀn١ȷE gϣCS0ޕ]G5[]Or zj= ar]f.lXת>rJ4uQEC^~!lCCijͺ,@o32/J/y}7Ġ,ͱ)I]}#Awѷo~{Ǥa%P՗AҖخT?$$ܛ{o- Cw5+r_D?ç*Gͫ2<2Mpǰ|~*X2/MEju= tk'L ۑnYYˢ4 5GLG]O&Zh= И`R [ b, eơB\w@)RzVa kAdnjf+hy@ x1}L_Lhs/n, I_+.mYwԚwM ~&CC`[WFC)hAc ؏/5 J<I8-tuǚ(M{8"Aue ۲‡1kt'2K3C uǏ޳gd툀Vbt;ųg'7}A8JMiEl^jn+^+boQ ,n$Zf$Bo Dz.#*qZfe+W) UB,H3rԐ P?z-s:tq&MdōOi!mw.SW$Qd)Gw^ NA4if+fzb S]9!$ӑv?h&ԘgfĤ@:xSݔH-P[B7f^'OU3Q#pa5Znrz805N!/bB_m Ba5IBx/w`_Z'^fkY坑-I-{=S*3QFMmmNrEP໑v=x|2 lIT}-W!`SGCqAXfU v%=|vơȹYiq>璡o{bF֒YЉY>ݧJDlytR1I?l='#M>W?$m1 euO s& Lls}w/e.MKkxvKCv+a]^M4{FA@S;ҢU 8eO.7eSwhc`pjHz&ʕZ.+c#ݵpGZژ 2y<~"[Q &Ԗpܢ/-1վAxǃ zWלLv6'l,U$rM%d'VN'|8q; # mk@ձi ) /9־?t}0k(R> c^32vpt9lq>YŎs.F>|Je$RׄF]EL4IpA(kVtT+[ˬ Ѹ>y]8Y(lKPQhܴPj c$>Wk1)~^mݻRQ׭ wԦ|UٻDZs2FG#I;G¦Q%aXA^{E1 H |"5oS/pӒ*¤FݼAOILl^^_mMuendstream endobj 440 0 obj 2962 endobj 444 0 obj <> stream xZ]s}ׯG9#"F&NXt2Q rI&%(+qڎؽ{?=.>1w}6gŧ `,g `y,@vqy/ܲ?\WToaGiSyHGXGQԓY"`eU4zպ,zv+}VK5u˺mٱ%-#YaQl^VeYy.ؚ֫uw84l$u(44O\yvQDy$Y.ο028dg?NOޫD^ąy{A?A$<7?vBm!DP<ԫN8Jq&8Scg" xBXϿg!k`E2J80 u5\f:% uz0dFbpFnV!ZAX$1h%s!X8T&kʕCh>6{֘Wb4 \Wk1S2ԏxX%VCsge۞`]C"eT>[DAݮy* ՇAApHuS`vଜ F)` sCVV3E'Ze պjӁ˜ĕ_(J>QZ`ފ]GYw'Vm(5*b>lFR±i:M"Ut#_8r;yrY`ۺڜ8yS)[wUZ ]w:":QP^q%JcHFTM `)H}61P񻝩۲eucuXByBYf;ЦOj w(NߚdߢY/,P޽bO͉R@!HX&m]z۷YgAҳ9$^:A3S:OY5S'"KXG<˒ ӠY7TXK"4[xpkWmwp{"&֊UDꎎu|{ ' nh~'^}黚?pVb# q Vj 0sa18SɊ*=+$4@T_W.5mmvq7-tw\Yk$/6XO\@uP3[ZjE%ȥQ9r6Z$ ryrQKtXoj<EUm, T<4IQJb)ISMA4_c\$!o7i9 "v L?7ie& QY\6Eȉ|cgjH>& FDPZ/ TfU;0IG:̘U]'¸@(,Q5!UVeW\I{q9G>4Q@zRƕ#ױ:(hj8 ,ܡ7&=`*#=ڒMVd!*2w,t0'f ў|U5t gvt)Jd"n:E':u86=8cYG[_@:؊0L#"_D$H^mF4kmPf(aI! (ZZl=C^8wJ"#Hv2@҂7@kM~Fzјy>3Vk_;9hin\C/ ;Ng@qf2( (4s`neZk40I)V8ODHxWۙzNcGG( (uN41n-`(Q MXξE]Du31[>wA9!\j9X I=dZ9ݥ:" Yl#ԭCa]@ԗNCVԳږ#f( KύaD nIf Bg?Rڟf* Mmض;Xbwc!kRKqy\@t2I;v f0heԃNDW(u-zP\g^Ě9@@^S6֜pFo:q\B߃~73- 2NVMt:Bct<%|]6E9('4ځTs3qlRB_? WԧOVUC)Do"L([TA"-&3c}"s,ڥ0lSGA7àj9ZUD}7>/ .yܕ2^+MTJbhw42@ pN>PWPz F +Q/Zw-߬? <&9ݑ%ЦX: u;+?};"R+%n'FA]<'s),bw4Y% B68׌^M"? _}gG4Պc8r2w5 .rӢ/s%>+&!YP w|Y9jL<{EH*%Rߔ/oxkfsJRڡ=AO+Ū7!~;w3!0)HgJr DT3 fЗ&|p'sp{R9"ӉHV5F(?5#81/#3ayTКQ_Yhٹ++5EU^>FȊeno7wRL"3B(l]Y g"=# A3qouԄ0CHܽ-髼C̍!F$AvˀKO/\Fsɛ8-m.р ]i'@>B$g a?vCI;ɀ6! (ܻWj) nSlϫ݉M@mW,հ:9v1]R*X6X@_HK1CW#C`xp9ۋHtc> stream xZ[o~ k3kni+X,27G!(9seHn È! ܿ|&e$pګW ́e `xec$e,.(pu)7ϊ"Y ۫wݚsH <)M"Y;M$9ȯt >sh.h$JӛEB*v[uz$L,rsuY;1jd4! &j j*%KpzDʺZ!&|IC  ̢jFw9_%qꋬea@x8_O2Ayĸ?7_1_{{׹1$9'%u'6iSʒ,Z+.b7w?`M) ڜ}oJen_ˮ&F;ܝl''ڹLX$ .-Hc|{)%b$J1iqGkPWֶ'p,5C+<Q/4~>#kΊJaw1%*S϶Hp_Z|lM6;Ս-!x LKK (t'mRmhT{'ey8煿ՠgjwEՅeݡw8H/s/ 1<(7Fm Vfso[HdA8Ƒi;QyKɃP 䤠ZAw'ʬ=i40f]_ADBLLQQ&CJ!=ޥ,"fr^v𸧧|WA tk>$déCu6@7)ٖ3[,;VmUx>j}XyoP""{8TiGLװڛWs1`[opd| iƱQL܇5MD0H<6 [N]t 5OD2cBN4hl9 z) -THϡSN@րg-m^} JL;>#ĨGI7Eld .ͧD"O!@'pdMF)ZY0agytߦ|T ) %$'H۪Dz6C)On F-\jZǠ#c6BzI>c*dKpYtr Y2!¤+Ŀ[Lp`L[3Ԭz颙 ώ@\ '<&wG*BONEmHBXJgac*p(,zj n2Z-c3 n>`%i,A&8S!pqo]T.8~A/d`H0ž7IPF̀^+ -װd۱.NxRm8 ͊-))[a翳j`LRo-%3WFdpאNt 蠺)K;/!aK=LOK [`f2,2Y]cF1u飝 Q><~Pj[N0P`j%L,^e2-Vr.Pcp*tٳP[ ;4lFJWf7=K_>eU_ڂ|3 PR;J-c -ԡI)P ZDz+$S@ IDn0^(ժA 4Lxs^=Tm#:K.L⛿~oPI۰$/aXB#/ek708_}ywƎJUHכ R> stream xZێ6}fDa56;NHR[qjpxD$dNSE"e$_x͇컫|>]11G[(#)]e!MI"2=^]O?%㷷ox7 e4amyu>KFؚO<,eBcRrS@ޝdUSwnsl Ȗq$Wn'I#.:%隡.;~8ʺ6QKԤ 뒴ښz rfݪ3*]]nZ(BawWyp$w2aFyXb~?ꛑT-fqm5-`_doo:|[4y>%OD "@0H #mѴNM]Vެ@!3 $Sn5),!PQK3%9}~LNzd,`c2He]-#m㯘tqDcg* IV,4X'tӱ4䰤mR.}/͘ɺ;?ΖZ> Yh $.uPr/mcSAU˫-fSS=m۴*q- M9Uc(a`L{[? `qF򋅗y;qxo5pJ;}= 1ΩX/eyΜY,4e! %`X4RK1LJ 8ʦ۞Qe\P /cUWh16?^:-~sG%f_99 PQh+AdL5"P@Q.jǏ3^) ¹b^cܴ>!2pq""bx4MQiPn'ynC՝ķڲ%q!A/ 4bxlE45Tu/֛|_7Z!Yƫ:u4!ƾL(L]A_RS4G:?g"8T?7,3LC3o# L`vrf|ɖ")H Bm x|~.&zewm.M`*G3$n5QSU8#@7bZX룕kDaрo󪖥8I!4Zi&O!2n Һiry%c)G^Gߝ - GCзpk՘E#vDwO ɵ3-/_/< $ТAh=/Wzid=a bɎLv>KOِJJYH$6flhACWv:}~y]Ww6zmlT, 83,d$2r;U~d \\ G]fD/L_NmuAp# bySޞ@mLA9/H{WzR@' T'~f%݀f BuH)Ԡ)ZNQ;5Ǔk|]4x^xÝk 8vgs˯)u-P 0#77<=pnNl V<_#XԻ*o Y rZS*=56Z]KSNb7&1' / z?Jvط?P]F |ǝ=f E*`#ɺGFVÇޖ6 oVcM'qhWQΠ߾GCρkp7maQ%!†%>;cQn#1 W+Q&eFpg૷;Z$? 2ۍy"жjLJ"!h뙑Ǫ:lY78( ꅀ/:ϡNS?u%oB KRMmpnj!?-:kRH#Lg`Ng^͡lzc ({Ycfgb3ÀМRٝ?ӡYJIͿ0PhZS#=>T^}UC;p3Yc}x뽤zIה}~z ֕MG,/iv}? IZjn>pqg8]iХ/k㛽"9c) O;`endstream endobj 455 0 obj 3064 endobj 459 0 obj <> stream xZYoF~ׯGtlM;tDrQ~.N2q{@E_F]R>~Q!e3wІpI8sOkiIW6%in pQ]S ]T(eQ˾,+>TT4Bs,e}菸@ά(%ȾxMW8[OO)ÒJ/N}n`u(+Z Wp-$ݲ cF.!|q8@m@gm-2Ac„ifZ Wp>!Rv0]`wX3G|=4 3ܾ.BkMrd9:z$,V8Rf%8ĪH^8}Y0Ͽ{rEAZB^.s@k=#`F.O[yiZQ]7M2C{L$A ?k߄R!CXdhJf聕ԕ@>S_l|TDc7j6{,#J/J8 MKvE7N L,u@&ȗ:aE Ls f@& *m5p_|ގ' ItUϯ4ηq1cB8@DB|}(k,E'h}2G3ɵb{*Ф亨* 9<]5$[PGT%tز |^ zAdh/Z$ZQaLy1Iʪ;6C#5%w; +{E{"y7W`oۦT?Bhn婕4.eZw+ Cf ŌЪ^g%E R jnEoy8YʃgLI;C^΢Z͢t]q9H_4:m^N mхN{_"A*ظ5. rzlvx37I3oXϺ7r>b!P%gZssHhb | +hȏl`{fu#0tk iQ菕<ΐ0?Аt|,@;y(Ty ` #m0g!f?Ac2;;aɶ-2lRWU᱉C9e C^!{ ΐԝӅ^.R ׏)q;-l>KO CeZљ ҹ>Բse”CԘI;f,`qW?*vd4AYꞍiB@*0S|5eHq2m)O3ziuwgBZ{#'s.yRś\7 )!/I=IQrhw^ɉd؀Ye[hzyr㓣{mLW5 UeoS]t8j:(p K%eoL8xAY&qxK(jjpcޛ-* o4ڣhw)wkԚ nSc^]-f8kk7VzQd[`qIt1 B"rtznF7 tjV9Gu- -΄bʢ)$ G6&qa23wb ГKiXY蘔,j 5=d5XݡKYf@U 껕ݤXVZ1aɣYMOZ!H?)ql_U= C9z~8c sj5 376Q ?*++Qfb0A] %J&{F9*8 {c2]A;zB| V弖~ǟ iP)f+]b[ǡ}<[XŌ,?21n=zz*cm5QTRc@ fse9 !LK d#z+K}n1i3bx;>vn>:%Ewdq2] 1R. !> stream xZ[o~Ȁ4}ئI@C%dv)Rˡ֫~s%9m- k-53GPFcN7{F&  S;cPArrC,.(f?˻߾ww{O5 `Z4H1~=aNt2EbB |Mؓj(5^*oӄGk '^%ㅠA-rkXjF+KԽ<ڞ+AqɕqB0^ @)( Ahb7m?k{ڦ<jt@°,M<"D-s:F8krm/q~I'zd%k1BvĜZ5"ӹBj"z$0Ćq`!!n<0`II$RINC5𤗈C/{2@_Rz!rob7KKzX چ hpKua@Gkj>N٬N ”El}/aX%)D/wa&:a* Yz|-hrk?PD_|W/GyE_0?a24' .9A)xLo,`pȘS #ATH&H]5wl%m]ʝךM\%Y_^#WDZZO#A!A v/ci+^8*',Vx4$O9KH+,']Bؑ'Q;Z}g*(b}( TAkKi$_?H;a0J,g)+>P uVmaybZw?9Ie)hdYIX>p`>Q"M_:XvU)%X\"@McZ\;xRFsXo UF=i@s9By)>U^A`siqȊEÃ:ڇ3E_c?/1}܉X\{Wˉ[U+ 2VZ: " P%IvлVΟ8jXec=~m>Jr`l|?(6°;3!Oi]sV'e'8r 6 FHN Ȱc;1IRvmqݛDADEKzKA i.myS㥕92Z Д]>YF)`sC@jmXL<]ybpkKqr|~̀9W:0Q}*|hꒈ:?q~k7auwTj׭fIz}=Yn"M-Z'|EUUܛ(hV^ynn%[6`w\*^G둲\187TM(lcvW[ BN,ob[6 B%4X v{cy q<*#ALN` hAR.-5O#ș\NcP^$*t{k$>(~jYD^bI V8ƙUТ)-Oibcن5y ˂ȃg1 4fM;H|(BαP7 ~piK"[:MO2c!i\ Ƈ[bJL੔u:@OZiRG 8FVK !Hݎ{jX7Fמ̯4,(In[kwu&֗ӿ>T d|Y8ʝ#~nvlh e%U A$z2ٳx?+@Yzs@d!4قg3exf{ݘZx[JM2`jb褣02M=IWGzaST=wY8ߍyY8M8 !M hEM{/xh'0c ΏW1 Prk([IX5ffƓ gcJ`^xj-oc`SȮy—Oj$jA]'o1}{Z5 zy]+sҵ)s`xMQDitJ(akP^ bu'+@<S6ߢɐنd>n bzWbؓ~HU&Ǹ-9142Vdp-‡&[+/U > stream xZr6}Wq\K\xX*p1/(_ݸ9cU-ӧL<凌<7>|z?# ')d<&wǛwœ"yg=8DZLhOo߻q}HR2Maͮ=ڮ's1E)񨚡7eQ+X."ql9#='%EY<܎OϤLҴ)s{7Ǟs*S&p*A\OըR}ѽ06ciQ,xl#)XvzN >"}q<-l#@6J`z{6Yn%mVb8 >M9TmCɝg;Ofq=ңY,*gk,iIaON:՛C}VS=5E}KƁ^-Q{Lx þmuߙC3 X6(vf)YnOtw#*wQsĜ&I_M6CuT X!o\H|(i,Bg.h-;%(O56rH1'7H6Qɋv&g>~S@<j"=AF Si:K ̿%R=Sc`(^@NSF |ӵG*?qN|t$^^pմ|*e6:0X٤L^5 lԱ<=S2mMTKhnb׽r$vUCzU͡C Г"ƁYqA /(`̡ /·n*]{* "ʙEIB7c2dSV49n2Lqg׃o$0p% Ot8ٴ z ˄mZ`[f#I(_B rS>i~S8@\4~}6=Rn?ah"q nIҰƀNEgNyT"ұ:G$[;IU)cV%Ǫѓ.AԈ\@vƲZRi8!U bCQ"7JrGۂȳׁ̈́U@JJ[eOʅcnecF>^` sLR@b".5tҊ!<֙隑KZkd$}%H~D8 D|98/Mx@{bR%U7ueG e\ sy>ڂtJ*sUV94G }M-a^S<0j{Ƭ ucSRgfdXDdX4ŔS`3Ϡ(B&Kb= Gwx4EΪ QP=+ |g6ػy݇@ؔv7:$a <PVyt*pۡ JM)ۡ\e~MhӔf'= g\P_a4U>K ̯78t ^ipU_,2㍯ Iy&efFdjN鯀LE |i44A7]QZ֟X i+rLTh`Lǹjrjv]qw=kendstream endobj 470 0 obj 3126 endobj 474 0 obj <> stream xZێ6}[l`+1ofa'; =[Rtq%5 " HR,9u߉G?t䱹ȿ7L DA$ac14!q ( ݏ?{}@}ww/~ճ <^ߧ$Œ0l1BM4_jMXGg1?D?֙8(bu/QP^7?N`qLÐl"|ǚا8MBlAȢIBE"&F7T&Ĩ_I*S"k󲠄< IU秼͟$骲 χ<;n|nox<51g۴;qO0k`YdoqpZ}<O%4X9DHcYLV--c/Ļ]4WJ FS&/F_LyꚖl%ArҢ/ISvŮюf f8kfi0zhZR{i|SD_R:\]SDhѮG n3N߇ x,VrAqzudWsZB{ 1ukH*b{ $/ZYW1H%0sNg6p #J]1Fnˆ|~1KF^eV];='eKb0,j0kL{`e}hee$#ՊXvmyog6r$\\=&$,~;= y4l\z=1+Pl6#1q+ ~PYIDbg#ݤ'lm'4"Xc6pkӦuZȎmZ<->< _.5,6ISZ=D9ɒ,!6QXE}/,2*7Ju&޵<~-$i )(Hz 6jhL|f,Sfނ*5|Vکw 1]Mw/EBN@L9bCXgz!MXtR s+zO}3[nxy|T#422nkf,*ײ-,$l[ =z`f6 ?`>Ar(yq- UC< 2_*ùkxv̫ u9g 9'z˟SpxwD21됹bݘس7&4h<lj!6(Bέ>&xJh b |:j*8U2TDH6/X|+m˺+CWMɧ@[4f5uJ3kcLviwjt;빻2Np”M%f S1̑K$o|yggm?*ӓTT!e%<1g4C~`gJ_Q0UӯUd̜k_]t>IcנM#H7c6 /Nӳ;jGIM\>uFX#n"l!}-So46,.E Td Lu7hf7bn+ }d`~ݻP%@cY,(RED%@ݚc$ML13old%:2M@=zn]Zl5VJӞJ? 0ّc~&we+vo 2:ai0(-}-O)̭l,j-=j}ww^QJ >#M7wJbAO`NX`{oュ&',BX0~/Q_x\`tu1Kl_ =|t& c0yԟP' [?=.&OI Ģjrlɚ pdEXsV?&S 8ɾo跌`h{,@9|5u͜z\"´Tc# 'O,xN^M9|=endstream endobj 475 0 obj 2986 endobj 479 0 obj <> stream xZ[۶~_lGѧ @6eyYr$yͯ %{E.p8!?_g k"osw銘70HnWvA`.1fuˑ^bz,1N \]~A߼~w~!zR\1E*S=`յPYey ;%cS3[+'$8ӡ6&oj`AlPE!HeoPWw9j**US "$F+BNRtP }e%Nk-IbDzkC^|T7]Z`]n_:0f /Zn4`ZqMqʒϞ[/g|p׷/UIw? $o'& 4{9éucX'tIUMu?޽ $'OqČ7h{ AtLP}K>@& EDd0΃,1"IprqAz^js*6倧Zk1ׯh´OXEv[d0oc}bAFu:3xnf1wJ ̇\D:ћw.U8%8< 1?eYfYy1DSG-u |8=^\TC/O| vHLsXK'}>r>(YDcίZ4xBUHToQ^M08op.eS(.p,~V,A}0ӥ gqWW Z\B Y$$z'a>=`#"I7!Mm7uq^]q[T a<\NMX7Bzѷ:zB148޼={MiٯUѡ![C]TTkK/&(uNr89B.]p.42q mtHb ̴+9k|hKR= NSVJ. *!={4?:f<'I|frH b#PŌ_$ҷlА;T|~rl;T }v*&}祀_f}bTŃ&ٱہ2)(?Grě,aIw(Yĕ9+xochq4=gSMfQm̀\G܅y~y$I9+QCKrcvʷE& (Ou)R)fѢ"YO/i߽.#K@n̳ WzNPK*Qr'X 9r5 7 2 eZF(g~h1 EB`rڬ-uimh7+e9E6! Tzr-1 LOCɸZBy߼ Ig+ǜk.kq I4&d)~4_.OK_],4TvZco3cZ]^nFQ ڎK"zZ1!X8{P9tcOuP{|n}?ҜW# :^NH"sZˤyk.8_F<} ۬) *݀N w5hmm((f= -ir*@WU5{J]_,iʁx?o'vjՄ҃6 vO޲Xk4Ew~%ƜSz^[% đdpd6yjR3/4b9.SxQ['[ݔ|cQ} AV/+#=؀Y?e,/ݖp\aP;N#Ti@"(yE*e8 .깉!l v5Dj;KMLx0-~2_!ĞKf]9h[X@OEYBT3cSj6T@֗-7ImSa{7Zw |ԾCH YN0=3W5D @\SVx]7ҡ\z;rPy{ # 5yi1c'r{r> stream xZkoF_1,`?eEl.PIl$R!)9ί'!){i( #bν{P ԏ].}E .bvL#(8C)ptwonw7|ssg= i%8J`|- f#5ڎ_I,2=E]euisjǧy'H HSmS+w,%2*nV`8!%B}'0 ܾ!D$0]EQ%C28+ID)#_GUkapj-!p/Q[[~ Cf]|Z\Byo5jn#lZFcQ;[(Ŝ ҲE9jCT8D2\0iQ;TAe8'plvrߢUS=jDf˛+8 Qn=|\u-5xĨ벪j$uv&6};`AjFn%xq Jm~¨,C2/6Uh :A:f e,?JV]y BF\`#n$ jE) H/{kw8R_M`oW;Pa2Mb8#OE:!9AzQ[ٶhYOclÝb-qLb{" 9 crjM腬9W[Z;4fCLR,ؕ(}{BLp.Ae><{Y~ԇڐR@;e`HnY e$/V]YW&9qr)pHL|XorT#{2,i&+-y\'sA֨)>FQPUx:Rhh}I$V(z\`^YBgD=P}6,Cspg )OBS*77#z{uݔf'J"ɸY{=\@$ qzs[g8Zw+ԩCjF/ 0x/ENȡ%HV#C^|8 =8WCh G=5D{8ʍOtp@&Yw0$o}ݨ϶Z<%(?SanB]p9n8q 21OIm:H/IKG$_|`̑JʥSc:3 ~@I:<т\yg0(@%3ni,0:+*b [z-84m l 8"W/ӁG-%3) &34 i)5vy(&LK0 1hW|m=2Hb 徑砳ڿ֓7Ү^U=ԫf,FMp>n$ƾ{L &Iub˅jNO dcdDf2R1lo:ĸˢ\RhB,y `{ҕ#: ΈWgͤ@ n]y6WƷ>˔Y5lD*jzX5y z[#2qFt};xЃu߿~1!϶6u+Z>|ؔú4Ks; jA6:XK.wuVWT7^(lk_i^:T&ysTb/Fz _@y2/"T.Q_O3Lآ1ԃEE ]w l\u!<(a}cXqfX3 >Uoa ߃,>^Lc=DZ8_zB("<;5['`$:@Bضbh@Ep}1C,Iu'R=gxw (";G90NRc?%0i_d?U 1(bsDB;/1 ZݨSD%yQr}#};*_$^ypݥH}m)ΪGWdӰǏ '[d^ ݣ2{M?Zh#ȵ1s =Aˆ ?`{_lЎ0a pل2`FO)9C5opLNm̀z*Y?ɸl>a$řG ڷE%ŧgoLR-T Sc.үw%neޓp!!I:NK"> stream xZَ}W[z^yq2x qMZPLRnX~/U X{?1 _qoخԌɌڈnvUw"idH?.K}ď[x1`^,d,fMa$u_M\K9߿~–>%ܞs(̡O#E: juT0 ƾ߾y3IĽ`HskI^58Co1"! =i8 4#}/ x䅨 7f<=F z@p 0ISj쳼vP:tsUm (< qkib9!s!P_Cz{cd_ETWY 5@ѿSQu3=ز HOE_f%O N|ĥ&TYk&L KF>o_EviM[<)VϛSֶ\!#D%1^>&CN=EfDL20MBNiQYYtt:%pI"]ʨz"Dw-JZBC?C6oľl,5Vn㤝 O+ O$]peISx}5Tw^^fڼ)n/N)qEf\9{R9o* MojK{X2A]&Ne\ҼxS0Y*DK >]ύs-580!blEB )N7;`}Ӧ4ΪgYF=@kT^jFMzLfϊU|*(Q `TnMOd";aO|*'RKx=2gͨw֦7%ut'|6xpwЗ͟Lb"S.]T{:_l!6{8:~貢  !Nؘ7d :lݡ(̸A@t2AO PjOV3E'ƪ4t ه;Ǝr٫ )91qtFogxQԭDea8'6EAA1ŢueL_DoD,&{R[[֏g̀G^=Ib9eŔ>@׍^u1/6բڭYCU\DeΞFws3 I"y^Mz ̙Х NM ^AD=r?bN'_W{^+9.#WzHtoUpU8zu"R :)h0EcRT|EHZq&!`fS4577:#8:cdH'5Th9GľҠ4;_wWnendstream endobj 490 0 obj 2908 endobj 494 0 obj <> stream xZr}W̛*q5o&N\݈~Zm!bH" 4J~,>dS-|&ebsEd\xS c!âd9I'dooǛo?^v1!B9..LW$Bp%3TDd&"$VKD4f3xdxq9_KŚTK_ %d5eFDss. #^ܣKmZʚeF2i+<&a*LZ˼ą3-czC֣hsz9jWf!Ql4j yLs+lպ%i+-y]6(R~bΫ -djSj4K0qu5)k;!6/Wd6RkKek2RI7Z$EUmDx$>Ճz;S6ͷUQi]~7edY;Y.)YRh^%KV*%٤{jhCzuSm`$* 0@7a"oKr˛It/ ?QygMuw iǣ.}¸xJY}!mz_`zka4ԧ4,eF!l7> ` pdvpDqvo@?r!TܝbRDޠ  ƭOa[5T^FI ΃t4%qmhJcU竼ܱ '1@up;ٍфFeVkGӁzcHqO/F`׮f}k(f]@^r/)!`iA9bQ*@>t3vm5){r/vL8LrëWwWhei3|SL:bȃ=chnj!\:)̲kp@`] +/?-Pr=VbԔG(1{L N2*c|ڬgv%n+)|"/"}:$i-%Q5 l%*.fiCebuQ'*mZ+y:ukoFni# hņi3<rw,^| ܨ&gwϱTVj_PU;j%RIY əqJM8yl!D@\"dr \`> w3Q̧Xlbb]:6 ';\x.(2cǷ$T6;;u7N-6;dj;yU7WgA}߶:wy9ɇsywe#]F޼b8Ջ|;AjH%Oѡt#s +k5/衏G0c=Dيn2|藼xPmaUv@V G$ao1E уIh1TQV fa#}7>||T$KM:jZćmiLq!9&`ƾ b 3?,qFQc}$%~qcݸZI[CȜu_8>Mha7$n)߀=ON/a $I;|2fȟy ڐIɠ c]Cd [5\|;|˻Wso翯endstream endobj 495 0 obj 2884 endobj 499 0 obj <> stream xZMsܸW(Wy "7oo\eo$W큚p!ViH,֔~^LP~OhW_gzAd~$n7F80#n_ȋ8,䔛/so~)%8$hEq@Ul vk1D܏TP]7h$D@>%'( ]0F5kIK-xp%j;?//YMY٣mܠm%X?bnm*m@Y_C1pIBdΎZbSck٪qa Ɔzek Nx2v};6\P1Bu_zA]˵> ~+'W$:Ӫ|z.\:BO#LR" Dx8; =sF?SbO,vd g5>JQ}kNΕ&yld!\R Ȝv7`mlUD!+]%eaኲ*@ÐLjv?u!5fER"ZP'SreúeOF*Ɛ;g>D-GmG\DKs&ťV"&OA 6~Q&L( Tr'hU2Ah 4t5 `ckRFG2:$xcTyՍB^] Jp("  @1<:I^Z ,^mCg4VNKicn":4f_WVBbMDW{-+$`8HbF˔(.ѱ{- !^T"e]jFlWe.5/ɡfUjj= 4q h6†~wa8L.]>@~[BeyZB 1:[PAVZ֪Ά~p"EO';4R(/!詄kI in NvW@ƪ"0Q{+(-oo&<0kal@ҥ\oޕTCHMH*.*q n+e8t]LMyDMvTs<ĨtJ&"ȓT= sŮVTlx0P7>ӟ;ZY Vwj4=oL M;%V7P*f*P70?mp. W1%I%(˃D9hWwʠB5c!zF&.@A (J ݕJ =>MQ)LRh,'%Y^P^@WxB,I[Efл~պk}SY4H_O0rT]'/l2p*W? A8ՌzlP0$$?_C!\8*-vPsUAdUCS -%.3&N8 Xݿ'"fpZwiSSFiX8V,F'*rbY!R/mUA叚7m˶2u *Zp T(5 tS^5c}Z,D՟HȱU0&MZ kr?T35r }}ZJG(c8gϊE jB3@w~4 NWh|R[}ۉ},pgW=6RX[ޙ~7QRQ@󇀶2bfd.,_(!s"yu;_"Ygi0]5G"R?g_?28xM Z.R,7L婺v~T׺.&+ڲ^ϴljFU@]6BNO!kPte3U/FV%f? PQgPg3syj{N7A8L=^= 5ԀWN.I`]@ҜkT/|?ttgF}as/E2+vsnlMb58'Ãk$=GLM$&20=$$d}Y1`8۝ˣx?df 4?P!> stream xZn8}W\^%q`̺`=[;閜z2OQI8@` 2@Sb]N*3""bo =\|sE]"Z_QV(Sۋ˫_z|WˏW ><$/˟iVPb!1K2QZ5+w}^}EweQ F{T= i'JnE^/fJa)e뢪ln.y}9`5/Z6ۂkSJf=,^[1Y(hAro}U."`9k߬?|4{%B2ImPke]?lZ 6)eۼw/wꍵX %1!/rXh(+Vfy E?7и.徲(wΈ<: ]ؽ79fUi:Uq Q~&X:d(Oxj xJNI>{I<0Ŕ=!׮RǓsL,X{h}ۼ!\hjOdrL#X&i`lAͻW3!Nm +B*WaaeIPp6M'J>EJZ?f5eC^8NFu-[+Q]_[l[^}VXkg2P~*;qPTCT6xss9:"Cp`p3|'hϩ 43Rah6J CP+c ?DnjTdp LF(txHa@5̝E tU0 m`"(Nԣ M =fyPD)Cz5DMD&bp?["1r/"&Qn)OфIaqrFHs$HP̑]E.;M 6F[ aF^/aLc덜M[>=F#ΌsQ1OVX j|  (Zҧlo JJ8a6$گ4|V:ߐoѶP :{Db6CLky1a g-7bsJb 5MHf1r:VQäjruQKȠ}1S9Ƣg,Akc,֙AIM@`^䌄ڳF(A/5݋ BPSPt }^*|Qн? i:4kfvGڥ㸍2rtPĦk=:<PW9(WUWA;I̵o،Ж :A/9j$9q[9H,E"6]dk鷬&n)}qz=/^Ąe8^>s\l'\}XjJ՘F: =Dk|Uv?*v?*M ~6fZuۚ1:C/h`h8@6Ơ O< }G0}p+rlFS*DKC:7nbf&ĨNyk^/m&#e%17ZJ*{t)r^yȆD}0쪣!1q޾eA S(IN)YEoRGpGu1t&?o1Ԑc!~LͫKˀy0c#t zT*{:Nsłjf  Gh,s ҃.To7u@bnT[mAiֆPYP+tХ4tR#&=:[ pa}a}!#KIch/+k<[N;d9UDݣS BM^tkS>VMoh(f '"RL.F/A:ɂn.z~ˮحANM. }UFyo,or^Eȁ~=x*CUy!wiLuffaNN-ȋa 5 J+g&|X A|sݰL}Y#kGYr"Of_āXW?t0*X{-zEwseV j`Ks܃׃k(n][s}D=iylZ`dP-gk&at"TG&endstream endobj 505 0 obj 2453 endobj 509 0 obj <> stream xXr}W[*3=kޘ"vU20D 9(}n/3@ɕ(%O/w9{E\~ئ?BZߗXTX>\}K1[/.,7֪"Y?}xwd_|~o) tR&EnvtzU}]tShr_ZlϤ8]y6ܝpŹ˅t_pwo|$ Xp"q~kA&A*P/*I7dk>%^ǢJfbږuv֪ z\"SĐǶK[(&#BCe&ƮOh{ܽ},lw4u0xحfVcG7ZC QK+=)nN4ЛUP uVNˁ;1)q- =:ٶhUO`q3 )2r^]qXؾ\퇽U .䱘Nb´.KR>NRwNrք?BB`d:۾6=RȀmpVltŸ٢\ĩyL+T!lQih񧩵GuS˗f{gS )F^lE{-?U LIu j@jd́Dؿ]'u8>5䖃٘D?|yp6hQGM2ѷeq6{6+QmC7ahلSvE:(Uz2yEsq\2iexl$"v.gW!fiFwewDx[ ln7 \l`bl$RukO ;ϺGY 7DpKGg6O<`B^=]NH1ʥdg%h9_{FL aM`P~ރb̆ӣF`vpeO27ͱ@1܁@j^=; U3b׍C÷U.C?5+mJgHx6aL[j銫~*O2WئS_5k\R@Qr={z%]G","4cqΗX51CӮ +Tbu'JG֡]|\xzl56k{8N $n0dWՏCyiz.])aVtD_o2=3ܮ\iS|,/~ (Qendstream endobj 510 0 obj 2295 endobj 514 0 obj <> stream xYrH+&aTc_|S/8Bqvw]$Z I쯟WHdf"&lY|%#eNF,\_ׅ ȏKe$%BHӔ$aF,wˏۇ%yo^-Rg nsp%"%^,-cM,U)%_Bt}Y߱R n=u8^@8ˤi\ny ׎U{QGk vWrAʺu+| qB3DjnB4ISo q/Wx`W+8I]2q0T!n,LhqoRч1Sj]W垰C8"uq$2iwYߑ-)y5tx~F`؎kQۊ(-wK^VrENH"WcLr?5ˎ(#~EoYL#7'jS4̇2Y:0+ʒuu+es|MfU IZUU(qRAd_dꨒf8 *h$6K;)|ܾ=,-]w(k|˪MQm]!p QǏsv7ˈ.@!+j5Q1پw@_ӔS4}j2Y8ݾBhb- .E'eԢBA eD4PM4[^Dl%̣գ~4;*BҖspNq2֔K֜u=Zȅ)4 ۗ`2yH OQgf tQnrCj̧2x|Mo_[C{B FvN['\%HfVڴ+߁?ؓ#خ6`c@lMb]L[и``H#l\5#8Ua!k-# g*q}*u=eu1Ƈ:㉮w}.(m9[͑ڨ(hM~Y\'X]׹2GfnvCqJNNpcopX77!cKzGBFmFz$HqDp]i#@X? iG߂(hT=`avk7ke嵩ˢW|Hh^VYJ:ФQ686y=YhlNKxQO9tˮ GNܴ3JB ܘb<ƀ=rDܑ*B;Y.' ð{]%+DDe:bՙHA!cj~9gD"E!m8b)N:ݝ| %@ FIP}kΰnPu%5MU[[3t>6SD+ޱ/הk΍]]ƣ#DߚYm]`UM!=6&u؋J۽z5*j ž7Q[Ϧx@u@TI \K,"ya9.Q4-6[^)V+:V8xBW}e :P$"(&MAVB!Q~^zۢQ?+q(ZOw^tf BRaKVoX91;3="W꤃}jƹKI%mq ]:*qq2=ӵûw id"]-:x"b/: |R]TvzSrYRTS_$LgB64Y+0J5Y{zI"u!P]:ALA :tz6MhEc+F]*X~#ɠTB($jcXՋӵSG̼3K a'qr4]A}[u94|,8yϣޣMHacutPQLHH5;W<+'#+;3\,5\R8ܠ+`jO"a|a;ߪwɎy_܀$a~O~}OsE# 臹 ..,B GI__?y~endstream endobj 515 0 obj 2229 endobj 519 0 obj <> stream xU]o6}oquE1Htq CiJKRNwIʎc+Cy9~$B*ae' DŽ_M1̗GAՄf0'{PWCpc:'ev2ϧϷsw8J}G҂U]obPJǨKL9Ik?MWW>j 5/J2 T*Ӕ4\4HVdEp}hU('|Pf{qmkuh'|Kkendstream endobj 520 0 obj 968 endobj 524 0 obj <> stream xYnG}Wԛ,X8 `L"I/twSsnmR80KqW]=ܪ>{W߼C_}_}G9f, x(~6>m>y݇߼x7Qp/.[q,bm>Y9T)\NةNkez] PjƜFM;B-EF, g ?MA`) 9\@Nٔ;RzB#XDSvV ?PrJRiL1t*tk{ڹ: v'l#v3N:S0RﯿΝ|8i )#ltX`P aTj(wG42ћ\F[Ñ*mvDLDOjF.e[B-vH8IMX*Q|0vJego4JRml$IUO0?[sg?e#eE&#gu3˞3K)DL돡8Qh(cur/@p{)y2TsMĕ2nw&KVB^S'FIq]E׉'|DgGQs[>eݵr/w%_J%61CmXHg mȺyEdO_ ùSJZUU]tFdS :NEP]?]TI:^?#NU dS2E l0VhqB@Q^$@ 2  X9qKFAKke-byRXD3KR8fnHMz Nu#j-@KBV!|Po`NVղ(_J$lo&v;yT *&me$*0Jm!pZY}ٞH09y-L78n!XsAJ*`%iŮV@MVPTUaF֨B,ۛ0ibv_Vr0t Bg/4 ?R<#$e$〔A0)ݙsסa%sּ^ZY@~?S1O?'!ya9nQp/J0,S 2 X ϷN)_Xm<-LZ?ϬZ/5B!>}aØӿѼfv|/ ^J`fiC &p;a=(8YPEbfՔ_-&o_ k][΃)9,5V'F;\JvJ6vOUC>TF3#4nvXX_)޽;mi(LlI\ y<ӝ]EtדiMoɬS|rP/SϕeR_`_-O2aI}me{a\ZKԕaTBAtjdʮw?~Jendstream endobj 525 0 obj 3162 endobj 529 0 obj <> stream x}Tˎ8+ zqoY`HfrȑcQ!u&)9aGuU5_4|Ø(1{X 0_ ptYcP2¡%a94cCͿ1B*1iӗ~jϯߥc!r/ B$e-qMk/k($5e&'RBsvc)I} =}w_IR/wO0~ge܊x;@sn hx0ԟ^|餡7ic=+()x{ƈ,)u)u#vNQ_l'O<;EВJ:Om lZNKAFlkZV$)y~N(l9&S#9ؘ851|b{Oח˂0m%'4_}_guF4;&NXT1O^ uKkMпwvlf vI˛7Z66%xC؄ @#Bѯ`"Vhiޤ&Fy 5")po}u ~{IylXendstream endobj 530 0 obj 809 endobj 534 0 obj <> stream xXn}Wt,d\HΌ G h`(Ȏ8Ms|}NUu/R S tq䧿%jMI(g]Wx(SZm&r,TiS3ժznn~+~~?|W086V|ky(*\#3,tR~4 rN|kBݛצefaeX/":Ln>땭PNm-mo@:|HjM^Ck{Á-a!%ku{NG?{;Snݴl#1΁%A,>}fߚ}ۦVe^o'|k{dQ4QS(#M_=trTylbTQmwUͽ1klTNjXi5zd`RzX)|~g(R/*@RR:(j 8bkB:$$N tx+Lt?U]_]gjWV"@O!0FsIKNV>lڝV). \.{y B:'=p)Uj갳띇;,}lۼL}epݰm5N2> ЇLUpFqcF{7Cu=ϴ`N r f1-TChZ v羻a& _ X8;n H _9&b guo9 UhdFU0V{nA}Ae4ӕt{)gR%s㋘a]o0W =Y[eNyt'(q{^>Wpȱ<# :mXoOOS)ǁE3ٴ!<-V_"/\הxFTjI:F*2D, O ĎPk90i8"7pDIJ͸̈~ͻ]1 a Fҏ%HgLV]Ӂe4 }nz|̛8q~(w >>~7Cۣ# gO( "msxyW2)ɾ`T7z=4Otʐ0yw ؙxwm\Ir&"  s$2& <ᶼ/GzPb6GD qR'qY8t+<ԆW3!{ϒI()U 9'o4x|/0A7|נ١}]lbz<]E;v#H3%MCo͓3Ň?5‚2,^Rae%T-6Ca[.qߛ?v5vi,d]A75n+|P,Qa"neo/y(UqJحkCb& ;G:yOTI[z[a$_寧lMSc"SEBq{y 0'wÙz^)o]TͦxF+ J`k4Vqr mlizb "fOm D%g^ܖ;P,V3i$XZmrWɆ94NA]%5Z{'hM"@92ewӔ⨙eui<^NpX,Q>^|Bs(Eu!=}jʁ!x܌tLJ40;7|bJ}':)y>0 e>lծ' R )[|T>`/;'d%$Ak^4J5T=z+S< .N3MI^peMN=/9\]_^ϘfzC8;e^Fk\Jr0x+48&@ "ȨR̐^v%S?7o.u3ԁ4[ @f~%R٪2E5F6B3kՃ4EN:#X:[*t2ΩgС1ʽQWiL}nʉ =ɧd^~{"rm_lݑPd3 Ma26.^>$|EI!n !> stream xXn}W,ܗI 3< ;\㿟S]E;. Ö]]˩SCxؿE}?S؟y#~~fZ[cQN_g/F#7QcIpY0e`zs>ݮŗ]}v|40IgfC(i@X?-Pطe3ݥ(QաnDh|vk)ՠf2p` u.am.iXxoSl6e#zX(UŖ @Q|Z*s>;Mڭ[^ [?BTeBHZ8o 7f}&NPu ]TP^ f:Uk$G$(^ˡ؉u9TKnVxc]ӡ:}wi\|駱CKIZ2vrr.#5P=;= ݁ǡ|R`0%/.~;- !NG(.ϏTz0 v$ڙ Fwf<_KnuN0tU(zz/#K&W JOlM ihil:j<\s<մ5lB;U,8!:o0σ.}55%ԡnqj)B0x3x$ m:T84`諬M0 P-:y<)7fRQۓbEa2 GL*N|9uB뎩J3kʈ SA,OHS?CӃ\v4fZ| xt扲-'haƳƦ-v,y$0JdffglL@'k;PƱM(&3`N' Lzb{8 ߯1'P?f[E|kdZ]|͡cxpY&v>d<f 7lVuc{P8 @ <~45QiKU Qӱn0}?N癯@u)]uݨ1wߑo/#P ?)^(Vab@BT}mM?K.k¶O8̐y/4vZ,?J3ΤbϢ³->Ɩ`X) zq5>` G5*$>Y qז1{neszs="b^Y$gꮿ cc?+L?8^8\eSZ|57 Di~D3#D:s ت( NWBu~,^lqKΌ펢>I5/Iݲ0#M<`V ɶa'Cz+z:7ƀ8lв]tb1Mwwk2#wb=mŅ"C7le9KfC*"V] =ĝ޵&6{XBAn14gLF-ᕕ%s M_t\ [j0t"gB0xǽ*#hiU6q$S;"kUӌ3oL'Yb4 3HO"{Wvw'o{jG.9N2%c]Ӯ}*%еH7MڗN)hƉUza(襰O+n 2+)w*vmk.W 6O߯Ͼ_Z?endstream endobj 540 0 obj 2399 endobj 544 0 obj <> stream xXr}WKj59)Etŕ0$ 4J\nT*@Oߦn|gG?o~X|OvcwBKf0| $̸a|տ3ryy(0CǦX,-w σA'Y1,%Q<,^졬*v(:\B 姶UuώeX^5b}[u_6n|}lg6$-TAxgYmsj}ǚ塬n -x"bCGkUܕ =jT˚d,( =ǵϧVeS,Hc'ʎuG=2*[ECY}:ܩ|Ḁ=Lڑ;%{m*[jjE)Խj%)L`"ԚfsdWp^M 5y|GQ:-oˇ}S >fZz<)8+ڮxTmi_HỼzE*w~u (B3h+:}ʛ Sd]oh4UmjP&Ju]7=x3L%T%ZzKYd]@NH(Iϋ< e$͋{Gh 3P[yz֫ñ=/;[^R 9"HRVk >22L#th CHY&̙ǝd\nbyb<h&5$$>l\Il M{g$y܋":orq3wNj[W9w[uѱ|]]^vjq(x}si\odbҰy@voӌAM'@m[P*H¦yqjL0f%Y;S;\sOy+=ؒb8AI<_㡖rl`1l<=oZ\Z2Lfj|J^<1L/ =Cec غO|.A%jr_1=q ż \nu+\2za8&[g(t3ysv,qy&~9nqŇ:STJ-Q8ҀHޞ3ㄘ0 ̧*,~Jcz[c(j@{|Pp2~x#/HL`?N[Bk ZXt 8|Awy=lnBήAlIgFAs{ETE)fȌ(i4c ;dŌuÈ}Yf8PbV=|zOyk|j[Qt> xg#t>rvKǔSi_upR6/{0=3{a:q>LMDkןlA ӮY'hgNv8ӯN_j'kAq< sK޴;Ec9xڦ6 +HPgggmX8mlocQ\_q5@kJ$? %yxao(<:a ]I7O4' C?iTtHMՀ@!hYl2?U_9~u^K)5SGBܩĔlpKqrCĴ#C.q:`(es"Qaв6g> stream xXn}WT0L JK^HlsÔEgza>d;Z@=V}aG_wQSՉ~ɗ_`WQk,y(~FKN׿ ί7'5>ٕ91?+{rOT ǜ}wj}_;᱕4B:8gǓTLtw(aw{V6E5lqʳ80~y<Ѳl[jc섾5$<29ca5m/Yֵh6drE-Lz< Y;JuٻVa<0iH#YE{?=[uBZbPuR yG dB ɦx('];N᱇9z l׵T mP=MŒgYjZD+W:j)e"}ߕwC/SC@nNe,YƖУKrf xikB4N2D96ZS:~"zL=cDAG7=oG?פj01Xv5;1X:s>OV]7by+ަx19I/h"gM dpvvte&<ѕ {s72j~Ah]QmlQߞ %>"ah(U$UHՒ}b5#w)D][Tt]iVyM8h}](ЊB \oUGv ^K~RO3'cDq F=X p45-v冰ŞN'*0IkjiO70h+׌ѠZcOtRlDo S/ ZR brzlۂ,>DU ~e'u}Y n7ό!ǿiJFܗ-RV]JIє'\Mr-M($_T6 pGb4W+!69޴IgCDBRE[8$;dvse|'ڡ7^ȱJ^* O2sW qA.bSL(w9q&}r[tfyځvt6R?=$bb+EmoOuw(t'EBŐ#eo[՞n$=9kgLg593 F%<g{ϤA}%r%\nvA]6ýAY-;eAwXNָjS9Q˷CoY@Aj[ZvR4j3d8KZ^x ! GS?;@cmkY TTH;.CIi(!oNg UWbYBɥ]IVv+R.1ҍfL 3Og08De"R$.5p0Zw|0^iTo6tagHh Tg!vF4Brve-cF̓D;Y\ͷ0˳qXYl;loD]J; }ғ=t̮5nvJ˳Q~)e=cx C1~f;e;˼pbkTj2 t`V6v鈩{|qz`ͱ!7o)[^feiawqznjewE\l9M?O>%Z{endstream endobj 550 0 obj 2312 endobj 554 0 obj <> stream xYks_)bJ?kk&qv:MgRD_{>f}|}x㫷/^}x/`@F!)Vԝ摌YgQ4OBgdH1lFoQs.)vq@'P/e<#eBM(l>Syd]uɶLjG}{sKSz} wr*xut5X]5Ո=kT@[z0H5TUKٻnmunWj>}Z'>趤~" o0:#4<v%+mlBC=T뇋f$<ܣ~u9A=(GW[k6t{۱+/Y_+HQ6bU_,E d fr6U};]gPy\ds3slLՐ'"cе.Fq;H$l>~pG|b{A 3x,sa>S+&HM̧B+;w8g"#lƪZf[}᪈"V.)B@b۾Aeن@2rT]8Q4n& u Cu1ZR@ R)pw[?+,M3%ҙ m6smƪ h4~`F(G/$#Yp`Pa:vo;?Z`TsVjngO-$,Dwoe-x_dĚAFY)Yn iMݟKAu<SηKz![I6`{&K"5\fSA!@(c96^S hw_S$>zԱ* = @ [UeE1v E|Aծ^(~bVKD/f:biPMrOt!$L !'.op@RI#"uV-I5GruiPv"(vE9OХ,,a/6bH.2Gэ<臊grX*at䂽GM5k[,G'Abwc X4|ł5>\=pUec.S;.I]W"k7U:qba"˞6{<$#UNd Op$Hlx5&:@'Af#屧)3p!S^$}H૭ {,a.smaTI:niǮVy;_虘0An ?_cܱ7cz3#8QRn/mYn7ɖ𚼹,B3. yd8XFBKeN-;K,=5]fxyܮSy u8̤7~ϼHxyVw-0bhOL#\grF2f줴}{'-qQp N vz|Gunf 2k]`` paFO^[L&tly"H ]foI^@fjoSXKPԭؘ[+$ߓ]E^mßua-endstream endobj 555 0 obj 2543 endobj 559 0 obj <> stream xXko6_a6'}vȐv}xy@RK,n pcs=ġ8c>b!?n |q bu uI'd]oNvf/ hu6owo{1ܸ4;^H8YE-y#m#j»3c4o/_ԼR/0iÜT-3h=&ѰĞA(8"y#NCẹQxzz/&M<߯/OMhOv<B礑Kifܑf_)1Y["[ E%CƵȚ"Ֆ(Ve(!+ZAHS& tjqH!xHYt˝X9TȖfA0AS%]x`Ny WUMg^rT&9H.Bc$Bm'wڔjI9Yd[yuF/<,K\*j"CۀLXuz\j@#b9)_f<DUȡZQ;MCa~o=ȹ$/}I]ȁFth!ͪ!eU<`QUǪnӴX Kơct;n[;``+`4dPk]̞C mX+D>൬` s3-FZ-f^gtJil "" AMSHª_e;1*cx_顿̟`lE kZlF,Y}haw[\` M]*ow/E1\䝄:udaZi[pz2r=\lͩpi,r}MJ7ГJw - My-x4 U:PW@TluThFDqرT QWx)V6s%ԈKS݂ [\J^-3deYD#VʁzB6 r.^ޡ6Ћzw`fϩ8ͰL;_y/j65678!JB6qAVx(VIU <6C.`Fқr={?Wendstream endobj 560 0 obj 1916 endobj 564 0 obj <> stream xVMs8WBRɤjL9l0XDa~%Hv{آ~g>^߿񻌞# 5\LѨoP&"`7W7C8:+x9vnN[KTկڕp>KջZmWa@9Jy*^7:zN-aoa&q5mvkiE)G u0~m')L,CH9Kq~*-?;Em%<.a-~hxJ8g<+o$\gpӇ@ o^t#aU9,j-AXklkݮ2>;Xј28cUړ4~K1 9sB!3$nwa;%;4w `sj+h6m֎{$Jƞ"EzsTǞbfIǁbEճ2FPxAZ(9gԡn > m,f+8La Y<0"X"W&ÊhAu/SSG~NEvԪeQ餃[dֺÆ~Ӎ Q o}c)PḁޞdH!Dc-ip 6L.U ^[6ǍVB8:;"Sd!\PW]J?IXez"SOF;l5U`E- bJF#ңůbrCHSⷲy< \8v;4n% <]h&GS8[ 9{6M P╚ 3D"u|4M=T'JZ ֵ/8Goa- &ʹipQH=q"MG'=i1Iq.iLOc&U48YuNL0.>_r|x|V E;BN@Ei >%VRd2B4NC|6,'GYgn&o<:Žt/u\'{%4s *4 idkšzaʐ'l_ ƓȨ =(t26F06endstream endobj 565 0 obj 1234 endobj 569 0 obj <> stream xVnF}WL_bٰ{ovb'v-ZlyQȵe;{!MFA"Μ=~% yk^M~`M(|fclK^eA!]Os BF8D2!LBZM_4F&X$BOW͟>~Mŧ>1830Nb~P.J0"/IA[f&Ӽ^ycJE Ӻ-Z;gek~#*uZZBbfE-*3]< x3I fL`sIb6ܖhֶ\u0&'}r"(,DYX@xH >?gնT dZE :뢩;1 mKOO0}Sp?pvR垙o0K5ǕsNxL-7\m{JG%2.F}%եmy`aZCBt@z#u\Qv ÝJ}o0J4BƌKyQY6mr][hjӜ@,!4c;LzbfVEiؖپ UҙaeS+XA8֬ED#j Xp#T Z=+Y R^f?F.`XŨ;Tӈ']SOe1FxcC-FL\"tZi4 *4dewfq.PbC` H"W&,w*lZU~jblLD6f}8xVEϱ ǴMvFLGV%%t1Z3[ J<"z%rƃZmۜ2&aBLx^Bcv0NXlæm:yK: (?P! P}bCde8-!thڇfOWĈ:3c!γyV#[w b'i-B%lb$H1*Vٮ:z'* vޔQ[OUǮ?}'ڃxUyrmw71.0$ җYuj> stream xWrF}+zDR\yjYlR~u1ϙd@ t>}y"qr^|ȡOxGO#$9]̱(櫑)rYDS?fܧy>9O7z{Eoa8sBؘ/Gob-q?6KrWGVTU !˺ZQ 1M h Di kȂ4RCКJP;n)W=gƱ-Qb#.Dω\X(t^8 \dy2\-ǓSBTC酀?¼mY"EhBibb+WCg}GWQ?k̦v_1phD2IW)8xP]!.fS5a2j B|WS8u~*'>EZ-Lnl~A Tc=Ug1(} s /ۉ VL].(Tiϭ+ }P fO'h4H; yY pc' We^9AWQhjuIR9=$>7Fjsc})FS-k?|-C=Jӎ9{6#J4})"uݧAendstream endobj 575 0 obj 1653 endobj 579 0 obj <> stream xW]s6}ׯ>YXX>9v&Nٴޙ$$C*?huN&#\{ιW23]+-~Y0؏&7ؔ/6ۅ9H('qRMXv06?݉!#~x z[g8v(~D7?{5 y rKrYYN2F⎷_6>HVG%1W+Woy`xq&41=@^譀K @߸nܦ?0 O hO_=}맏<}706!k4qb OɵlVVz5ŵbmStN(M52 g ;ܖfِzcV`aH=v>J| -L)Of5v5N CCM?{puӹKE|p!NemSW4C}%2kFYU}uVuCh?o `̾UnHVe_\ٮdo V9jmʕo+[=Mͳ'+T1E=ߟb6IVC-ƕ,cճk2 L`bJT R]k]Y"2\R԰ף77e#/BaL,HjQ I@^Hf03ч:hk*;ZBE)Y*$߭~3 zTYz4HΞb]AffL$Nz1bJs7ެF8MJ+N?T0u~aa .Ql[$(Uv쨹> ܋12P$85^jD9|wNDnˢp:Ӵ!#&po`MXTeG*{jɜfk8QߴxAIssTa:Ə*IJB |K۬ۃWm3,棹Eݐ/MD%?LqLA}Ϻ|ɉwJEu吵ja^ʡǩƽ9{̴mUT,8!JiSORsu>nAF>(yypWO9 k>Of:d!xa^u]rNݧD?4R%$NݠyLJfݑm¼~'`}J[33f0S%(#61DLQb p\u٫?t3b}}endstream endobj 580 0 obj 1921 endobj 584 0 obj <> stream xWMsHW`OS6o'R;H3[aheqB ?hݤ$Ɠ-mv7rE.w9o1='.ɷ% ~eE)%XmI(RG؜n߿yNWo޽74lA|l,'O٣&Y+< (IY є,R'5\'i|2{.ʒMsM=jI-d.wTWZ):~Uˉ^ط^~qUFsiƗs_ _%Ӆ-M@n*hIy6zJ|S/E( ?l05λI;m<+9m._E+\n)ω[ݶ&agQ` OYk:@볒~U-om \xg.yru]uM]Rȵ˚NNU!l[+ܮ+j\tɩ_)'Hƴz 견6R0)Rzfq^=kvzkwk tƙ%rul.5=?:q sq :*8nl7k'|;3֩ڎBHZ85uF,7("q_O++ /TxՍ +Œk(KЇ۷tߕҝrNv)x[4<Ľ?h.x\k\rxr ,LFa!]yp 3K.Bwom_vGg7bBDtK'ƊεfӱjPvE*<^Ү^8OoQA9.`nQ-cCeK-x^9T'ʰ%5DA0}h49-n_سȩiNS] V. uS- +uT=KԱ+e3C z5 ?okqs#ł?]n.%K_-\x9^* e\4c/\껹Xl2N#&\xNl9<.ih2cƌѭfi($_<=m*ݲ SJVTfwם`qb5qfa.Űz:~MXUܙ٦K "3ᦍn/Y%N!mJ:&et&Z1٬d u؜3 9eC㙜챆S~!6KqX2y5C,V+zrIF;=}#ߙ A?TqR(tUzmDL&XМsQYXL4rLƲ6MlUWʃF#qz*营pDƆRWB9Fz;ԉCA WVAB7;nAƣ g3FVJ0*4ȝ>e%_-"h`Rf!@vu ]|ܚtulV*Yilܿ0ѷXR]US.=(y|UkGFK}Ǎ_?+2X1l/Yc$X3%*3(jLQi滊{xU-uS=j=5MQopt4vҡm6xnn8dKd2}47"simң?9Vӓg|q?@endstream endobj 585 0 obj 2124 endobj 589 0 obj <> stream xXے}WTZU- ptY%[j(U[.c..˥CLP&8sxNJ|;fvDҭʊӨղ]&ifDzbЉ> w>uߨsOgf2G\YsѨV =Ug/(1 |fa| q &JǦdfWX %c!.GWl3:_m[ʠ~=CkN +؉챭ޒVQ.<2 Ͽ_aV2EL0hQנ$?y,FFK/Ma&#%(-j,yYk^EBC(L'*)n$-Z/wC۳OuOSl7k$[AroPmB(F}N7twÆ68fy ԋܡ"l[3tuc[qVTj3-g&ufNw zƤ<8d N#['#}Y.06垧]+}'?FxXO{2]{?>ɜ}G%]WR+'=wMsVP&p}p+OvczKC~G&rɏa9NݠEC18Ay*y\!j0CG ؉@|!r)DcRpP%.=v⒞H#&zFuJ^4E@f|D|Pmzˌf nɏWG6E,m=zy{Ƕ>UW=왜v*JyK6{$^+> stream xWko_1iQD1dGג󰃤qQZZYlp}o%-). Crg̙x\Vz0:ُeEťR]OG樂t[M;|^fbqOB(qc]ME+gstrj]Ԋ|6nZz,UeSUyoX9^ꯓ\Y.}f*+ $D|G~Bˁ,bސ 0E;*|9 ^xj~/wST꾺!(]]L$|D tqMڃltV!mCMSJx)Dv5jV?8 lA090鐿T)1]C)ZT8ւVOHAN5M^a0ugh deN',xAz 3׾#MMGhlM?%"r{ldqt/3cgڙRriAѐYeIA3tPw蠹TYB,A؇yU l(}ޖ%P+*:3(QE`KWqi[1|XuKOlX+R*(Sp2Jg ꆊʹ:ΌVc fcMm0gd8mDW`>WE8 9 mrR&K/2Qީ6xy4`s:|pp9=1xG< 6Obמ`{հiHr|r2q%,8S7ud8X.\Z<-fekz~h,/- 6?x]` $Žq{p?Ըfac>7Ѓu“IZ5sg83ǧKdI0DiGY[N>o5endstream endobj 595 0 obj 1788 endobj 599 0 obj <> stream x}WnH}W<^67105vƚ,Elnx٤ -N$r꺜:u.X@?lW-czy%se~ʞ,ߗKya`Fzf9,8tN6"qݱ&RL?S/ bjeBG S%$#۟?@ǘ4btlzZrudmq`k4O'2CQ' HO3JMH4֭2;|_lN}4y)|Vr߿(jI=)Ŵ;<Q)} Pd}v9-fyBؑζm3onnoYJJ;8Y?%VAQq%.avπj-:!_8R.DȖs_U)1A PV6vpl0h_Q1% Q+ p%Q ~`p0C`'Cb@YV#WKH0,9q]ƐεiCT$ }&X O4,6l90a[z0푻ʬ󥓔'`(ZĎ -L`PGEDrWgOU6O \!$We޵c+2LAI[@)uë:Y, y#[?u 8(7"@s_ T߻>X _}T|J8XhR15V~CM;UK8*Eಪj3$n*5XM(;# #mӡoSGj *Hf؎pj4d,ubybg=3=#)NX`' yż*Q\Rx(TBbV䋥BQ0"9ztvg=wQl{D^&><{`K.^&P?[5% }D<2 NKАB6糈xxT#Oa3zP0,@Y -2R4x3Gr𢕼ݹ E}`#c-(|B%u]D:W{'Q+Gڎ{@0S \=Pˡ[pRe_ g7> stream xYko_1HQTX n 8v AAK#DjIʎyю4޹s}# `ߋ3vwwHZl?q`9^C,.hvq~yz{.WW5SG% !-R^ޕw #9)3yR]T,[jWMNrU+%z{܍BxI y®fOwU׳mܗ[TS.Lc瑶ڞ}gJFs~c_mlR(-x I! o;.lpܓuNchJM{XDyu !;^N7(!EjNSvjUٰAQ'i$]6Z@V_V;LhjU-*eHMGY:T a̳"ޑPj\Rztqn 9\ZۣPNR!RnѼQ.̤l]M +}9&,J+ '| edZe7vD0y=TkbȉaOp僲]O"apSV",zG7U["b*~zLBlXfCHhn$:-EZ܏P|@D؏NL"^ wpMֈZyII*ٺ2a )"13ʑΙK\{%ڇ>J(wO̠@p'\x:KC]m%rG5}OBTe9}޻mDC#4cYuBShhAPDE:}= $Y.^ٱE@@4 ffgקo;= 08 jm GMD[4X{`\.%4)dhp090兎#rpYޢd%ZRne5J@Sp A)(T7nthɹ6ԌpG"\s*$5*!Em;'*af2aɋB`^뜢絔(fMk0j4csۗ rR5]Urcͮ-AOOFQb\T/k}Mg>Z~a]t3;H4 bZ-}n[JWֈGꡫ'8eEY'c) G+ڲ#?z]Ж?͆%,wIO/!){y,Ww%WYqK/AvzRqs^;U0۹TR]΃c53u]_ 7Ԍ{[_|p >ÐVV"7~pu\&J-ہΞD<Nju|Ʋy[bnAmy3Ck<4hnНck}6P(w?U[} TC^"" 3nFˌQ{(vه~43D35ͤFR[s{Qc6IE4HݖMSuNo#RGm!7}6nE?ݢn|24T[//<{*ѿ(6Unҧ?h*kC`k!겧}dnL/Z2فozv$/I0m4sjk IsfI/SÈ{;$eJUەc%VHy}>_k=1;wͣhY3NferrÁ•QC9M; ᗗԭ3m5&~~c]œ^ ?-endstream endobj 605 0 obj 3098 endobj 609 0 obj <> stream xZ[o6~xXQԅܗm`uV#M$sH(Elgx;3 (#~uW۳nRМ{8|}[mKX$?3ѐ,"Aƒ7ji?].?]^u%\&B L%OYW 6dSg[mSW[<ŜqhnBo$Y筪IuZ,U3$ ;(L0t[-18iXJWo%w8`n a5%pKєGn&z nޅzF/Z(dV7?ݲ10V osBybͨf0"xsmhv CnZ ծ+^L]O{[7ʅgT0c4&p!Jm dU6|5=ƚw0!#2!:B#^` . }2.oX!H$U0g964P[% ޽xޢX CZøj{55^AݱMpo5mGn"WGouAӁ5Ž']Hhگ~^X_4վֽPicȎ:l:crN=NHb ~q8RWL;[04L7+Hm4I9 4 v?ynM|5x䮜 f f. kH< )zR6d@j`[1BM{}ϛl~3;%FfLlx_RH歐Jz-J~PIM\xW.҄ƉA%lv45nFѤe&jqt]P-` F[a'7z: ״c{Luɶ5's;h*sX s,R}qV|̂KpJp}BFS8d}83 M|$K.{W CN˛_&hjYGAꞭtSwQ!L :(j &|r0ZlTz\du|j}cY8<%%ڗ5c{bP2pA՞4վX6t8ΌCbOnd t~dզ&Jl…~Ӈ9!q @m{xYܘ i_jbG _IL3L;&j HHԀE@up-/uLXhf}k |HfU=X)Frk?o AYcScp)A(3و!87쫓y7,tYHG1 fXA4l3LՐίr9h(n]v\ uؔB=Q'\g/v1endstream endobj 610 0 obj 2650 endobj 614 0 obj <> stream xn0EYT;%-(%ޠ‚@B#m E*+#0$`Ũ%.'휓C%XHu2Qt5 &t&xp:, yۿ,ŬUs!8z"T }U߳x te-G>j.f?K.{y}::!JwR5c4HγsGc(9mJ5&cDqi7N&]lj| U7N}jJLǔv$Px}Ialj: ٪gϵU3+ 4ʓ,N6q'zy5Jښs\U<$~Lcbendstream endobj 615 0 obj 386 endobj 619 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hhVmRllignT¥R endstream endobj 620 0 obj 124 endobj 624 0 obj <> stream xXr}W. !.e-;.U7&*=, IA ,3_3ޔK%ќK_N>=*Պ/^;.>_@_AtEB*\eI?\\y{޼w흺_o?޿8(`C* Y0%nu\yi[sl*7nGNݝ>Bz8ҢCVANj*Gua{ej0WtBA&jhLgAWQ: $k-{+>;2ZjPs4XpDZHQFN(ܕ\\忟5do9v;C( U872m@'a A(""rG"բWK" k%Z$Qe;#@5p‰r=wnz0nbD&HF#N hyiGp;]%J#EN QEN;I7 !=s93T*U|޾u3ES`V(9!Fp:\mZ. asNrd &'MiG=b$ @*ӱiH:RY& P>ղ\q*wXMyE' 1Ta"~X!&1I.gAj.t% ܙNpn:F3Icrj["WF<{4! у{< H'-!0|iũdU `/(:Q Oy$ǣBAsiyċ8uDb1e,Ks6$xAJE{Q/lxK3~Hq;_Bʋ WBCђ) /. SI܅XXx7dެ#}o߼%0#yE#'zX\)zt~LjXgF)[[퍱Lkm9q_)P)[Luoxq|?$@?h<}|I#b$T O $BZD4_>=2h]AdEiKly8RϠM@n;TPZD8djd juٻ_4 c"dٝ|0J#4E(dT{.yt@}U :he,;=F#?1;5!G:rc23;Iw#T&y1ۥ cRޯEcY*,9#I8v53By cKڳKV@s_8\/7ڵZ˄ ?2)D PNۄ$ϥMFXВJ3pwAC "5?GVRsSl:/H5*DqpɬF *2Q&lTY^ ΜlanC%FVѧJOݿ *AҳQ |Nr fN4;1QpbzwTU_7PODV=YC.mC;!Nc]x`v+‹E8ɒiV I:4Oo/~"endstream endobj 625 0 obj 2613 endobj 629 0 obj <> stream xXێ8} 抢ynf m"˴..)2ݝyFidN:/y3Ϋ3fcǿ͗W^(ݍ'X$ "`f!+&|w:2 yaz{x_?=?޾ެ A+W2J~ŝW]3Ufz\{|MB8ެʛorݭG<`+4=`b[ˆg]VK蜎 .-ӡ 횖eöhl3ln(3)#'.ڊ^eUQffUDzzKVvJH*MfU8[P}Nwf뢣t :ql^p۬X: ,wVL&]<(~8O SQ ZD`;Ɠ{{Ƹ=祣m;ڦrN$=Q6gE Dd,kDi, d);lʦ̲c$E[gE5=r~]pfrFXy5 15Gr'r%ywlNOU5;f2dv?T*1 | o.΄hjvM}+fغa:Fmӊ%OGB1z[0Bz蛣6B7V#7p_0+TcF" CQfmm@_RN?(\gծmTURX?mZ}V5ӥIS9)Tdf`J'< ej$cL_*i/LQVǞ0F>Ÿ0%yV]MgZ-؜ȡ(O˲ɶZGRG5h #*0鰇;}4HƋqQa<=MۛȔcC=ߣXyH8_#ڃr87Eޠ*9,bDQ|Ǧ)rH E@v=%/z*hh5JydW@rѤ{LfdH )n?W,i+UEVotW\ZbXǯ'NJ~8 $?\/Ȥ)-a#S2Y $({rMR@;>ki=802g?'xñMmd]ˍXFX: CF/kLXk"gɵYL;)8Uݿq$lt<gYa.Cݖ]՛MQI0~)dб*[-M*UmLz'YLh\BL,HJY1]]mZǮ) Q! 7n ê2:?G RX s4梽N U>h:U?}U5]]V+^RLp=Y#hvcä@*8{T .`ίZ1ݩ4E \ݱeb y2,=yg|u].q&I*"L':Bkj52fi>D$  }q灗q?% *S01>OqՄ3[qΦS(Ew59)5 =4@{Z@!Kc) bRpWpًk}"LuGz9ݬw݊RC!$0HՎU's2nIb֭;C^(mBީ?It3ECOhU\ybϼ짂l|UG8ϓyC+ I>Z 5.臡|)}hI\%^ā˰kH,._?endstream endobj 630 0 obj 2393 endobj 634 0 obj <> stream xYo6l/+>) 4p Tƺj!EJd'h '̛7o=\|>a O/ZoqEKf,yʒ0"dy}'?yC]ݰjl@p/^]I2 DВuEfA1DPC 2%p#پhZocgYb4)B  ?`l#کw'nv{τ!lV]3x4=3ԝ49J.jdwj*dUОHyd΂̈́vwޫy @2 P-RDe9geAWq]}4];8Las "Ku&e\ X*ϗkgHf7N`c‹P~&/+Gl(견)F @u#q8? L5vi۵sov?qN HԸMb5c#tA gY0zdzӆp9wr?z랣Z\̊4[}ȋLdN#Ev>@D- Y^`e]9r)L@sXXϧHk+xz(@L"9N9Ȇ/l w"ɾ :O/b'grpC^tGw:Q&Xy!¦G=.-U-UkvJ|lXRG Y]4{1 q F Lpt`hף1>=?NkŐDTڱ>˦B7}cU⭄{՜ m7?IIYʃ#|]+JZ4y 'ZI9QfYQˬS׈Z"4Nx&Fs1Oa6Fq8y8)Y {0(|4E߱gfꤎDy=Ac+gNȸ;6;DЊp,u؀%X Հx!25- MxGGSjMisAGkUuTNV[]ޜ /G1+" gz 1Ԛm^6Pg?=E~Qh`kf? 8'7\1<.}۳uH|19yhkdH$~l (YI S>kU`Rq?Ec}*w8,T;rhP;8 BKvDrEC g;קqTX]m 5 vRU З)JHtERXԩNNj#-J0Awr_TR9PTd;͈lT+S))v2',bN=wW\ظ8Tf:ls.BL_n3?^OF5K::1FEE9,I<`mm3*^;[Fn5|ŪtMC9}1>1~_]]jM!?U~p1 1}14]Ǽ_BsJ 28$k2oVNq|3%=q̳Gխ}[l*R=?lP[=I,ZOB-G4ł'YlbtI ហ>~Ez4 C/csW7oyn7rM7>e-22/˳csJ )Л}r䃏>`3-^CuE{{ZFғg(;ǖUO:CD̄KlSSFG 'BԌr%C Ĥn34@Sqbfjx!O~T7z,6b60tЁxIۗJhhۮX'nc;N- esN8sq5>>JwEPJn\iB%Ճ*f4D< R;H{e:2M QrlP|s,[rZD9dgj#ssB0׵LMA$\ِhtߋG9ǽH"b;b=9A_4l򤘧h:)MI11ZAu5]s< G .vR2`=sA=[븐dl@ooEI]+gtK:@O/syI{Z<=N+D& nRaNZi:6pڢm碢Ҥ TjJey \aJ,fLCR%gT9@=S£y*p7pdϏv7sGø Aܩdw {eșa~2e4 ns66rpJ4|㿝RгNvr6h zx:LQZ4l42S{VeD}7_, Ddߌ`i(zl^p|_WL`SgyFu˚P_wemx@J F,>;ch[,IN3ߘ|a=ڇgo17(9H8tИ ԧf܉87y*7a?F{F|Fendstream endobj 635 0 obj 2883 endobj 639 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hdVmRllignT¥R endstream endobj 640 0 obj 124 endobj 644 0 obj <> stream xXnH}W426 ~`2Ym~iS-Ǽ(l&EJv(fu]N:ů>YT7دos?el, x(~6op3{O_7}ǻ NK`j,AhdOڝY9<3Gߪ^zޖUݡhթ[4s>nnlE>JwTOhԬdt<6mvMrL8g=}.@qm=\G=i\LQ:^<`d[{l+:}]Vn#d2)XލnMM܄AM+o$AP%a* #6CL: r$l6gm2.j$]TA|hꩧh^~tD?\V(f U电Y橭"`Hע '9i51f<@o4aG-ݑ1_0v.#:wRt=%n`2{&‒YS±F 14"qRcL] ifiQ8'dȪF0RTؗk O#Ź((ObdtX B*F=::GW"R,`!9b}-g;0dh@i:z8QjwfGqlX{8chXZj 1hE%ᇞ0/Y w}]5E}T.Ra]:dM: 4ؼlc'cg6 FK+X٩VwB !: +&/E)k1ƒ ZkB##ƃohŶH|v`nowphܢPm& M" > stream xXi_QXn6`1gF ,E$)bSERr $=CuzUݟc--;J9!L@$%<˷^-, Q!_,߼wnρs\anUL~T9+fYmYfr9~)ͫ+9~SSTT3JխC&.5XhE | A9 $mPBWVnO";+'uN[1:E1œ/{ a]lUoFB 'OOiש+,B? otgi|ăFhUp긥/Hkah,mxǴ4JMU!نSGW,ՅR+ڜlۺF,bA՟t} #cpF-O&ʊ]@VmNhלIֵμ+ v'eX?)r~J,iw"Ss`D.hf_ݜY}Կ"0qȊ" ?0BӐP8hh^sP; !m^}ކ\rrœaL@3]|vMaEMy7 j%D>bB?Mk'g7h {"OMM3-k)KÐx*Щo `S2,jm^ll 8Gh 72Єe|RBYN>3Y̿icjtgA>v,VhS<ӭſnBꧣ_1gqrSQ^÷.@wsO^\`qSf}[}g+B 䈕7U R`tWWt4 ޷ SjOR=4.rb؟=12zYEAHjɢ e6͚bK|}VOUkkoOC)m#M"Xvdw'Lv8 Gj`|<z&HG.јϝ,#*BxvӳۤMU0J7̒]ڗc{*dž6* Lik^RAlgD ,b8>MhZ[5s ĥ+HA> Xuj?ZaVY H$ xZS ZBb>CHţyK҉BjuMbRL`#qZn{Z\rȰ51jO%_m&f>)66^2UlG?qR΋Vv} f4L1]fsMkƍ5-kZ vj]e": 6Hu߹DL'5"™¶ʌ1iout9]SǻrBȺ}Qv뢚s&3}tG]]B,<- &s1]3c Za/tjqܚrwXcR6:iq]h̡F֗#Gwܽ--Ü! y'2_Ty< a[z LrJ2_\FiBuvȀY=B/~Jt |t4a2u>qv p¹%~Bsi.3 I:sbDge<ɐĥŠdg- ^hOs5퀐9)"'?|AL)|3J<*&,> |U,朲d아)GGVryQaNsIxSaBuJԃsfx2U,-HG8B<97r{Q,WJ%6wʮ2nħQNG*RKfǠ+k-3`{O*w^=U\sȵ,J\FHcܪ>3Q:h TJ zF/>7a=7zendstream endobj 650 0 obj 2165 endobj 654 0 obj <> stream xY[o~*5!쓓dn\@cjd!E{"ɛlZe!$s|gPF?Sr_ _|`ZEM^@('^BqrS_o_H޾y_>x}s7jzxh@bAK؈dxDVfyEYDCHU6kdڳmYYZTJ\IPnDMbrsX=˺DG Fk ZOE%{I9dCʁtR;٫ljl6U}9Oҽf)y$yl42 B R6^-UX0Kqm<˙Q$á%+M'`28U->ɵv wEx&?jCZ0\;u"vRs]7kPpՈЊ&.u8Ƀ kuImr0Z㯰t_s~yba=F|u;7+r^v*1ĥDIlNQwYu&,Ϛa_tP$*}(P.%AtW*?#5@d%h6m1@J0:NHШmF  'kxƸZ/+YhfT(NYSCS٢cRe3IlQ;#,m)7D?$A;sp]nځCA"jIY:&'v{; z(ʹ*$&쓝K)[;y@:0cF_g4μq#xgx yhwKSI| Y<u*Ty}Rv(Fs2%P@m։qUƮk6î,vG,i)y gq絳0+xm1;ڜ-#4s t3ʖ4^YѨ̰&QXyޫBvmz wE=GboX?{˳iׄj<;D]J=cp Q\\|6uʶ3 .R$> stream xZK6ϯ-ml7#Asu`M6b'ݭZHjwS4c/``8dF"H8Dx S :7wHwhLTP( .NDFs7?ߑvcpdWNy! ˳eצY攱(6beS\Z,^QfS-9%O|.mC\p"flΨr/y~0P) uM` ؑkǾkH/Xuגl"%;Nu>e' os•."]Ș`vq`p^PV us@2N#UBبvZ2b5e2gkze;h72dSD 6u =.M$*Io߮$"r}R:0q%ﺞK -q!a$Sܡ!7)ɃN[}QqjHܡ7Kiܡ-yMܿ"7P9&ʕ`J>vl`ޠফKAؒB|m5RLN`S(ABU"MLuX׷fHU'\2J[ogwQbmPBS|B4u4 GQL5kEɋyID6[jK أCu1ND<5ʬ c  z bpgY@'`@f>B<3 r 9FMys@wKn*-( 3>0ژ9Ƕش3D$Q_~eM)BvY$+4Bw=C?f|_4jgi-D%HL^/H'Tڊ;6B<7MMj<~ET4'c3FSͺeqVJ8\7eL_t_Vx1-C=K0uiI"5>%vSAUٿ !Wo_EJ[`eWTl\f@7\vTxIf{t+ nU@8iMK;.&BiQq! W')y՚͙ezMU:ؐ$5. ,(+K">N0Z%R՗ !h~CFCK)Viu4:S1@UcPn'R:)kѐ:N߁|Z14ok wJҨJEly|5cP Ydp4TWsv3 2BClPH> stream xY[s~[ %.$m6toͪ3@S̮H*$ۓ$L!E}P W&E*B_ÿwW7@[^H"ֻ+ A@)p.yO_7޼7߿O݀_Q۫l3!ddmV,7]+cũ5sQGusGN-j{0T^yID C뇫ZTfONcuZgjTwj*!S!hSAe=/'@+B1/iT{TyW|O`8ߔmTo3l! kR:S[TTEWdÓe;A*Y^*C492*8f)xǶY\zb3b i")jl?f ;nR6#<,b_NApd} ry fI$;nJ3]t޸Qu*2"~VO訚޶6o[$0w{[h曋9dH,t5j?GA7=licQM>[B~i|e'N7IQ ܫJ5߱Y z0- M= FYVT \DPU~&p cPP{*@jhc=(5$u_C@VC=fnW<"dH77 ZE}Vq)??D!?n7,2n}3Y.K< >q,@lj>xTf<=*Lo`RG7߆4~f-84a[X)8y'8a1! X .n)*-%Q U~VLRH [NM5Y~Ifiћ4{CFCX͹7oH t0u[A1#$W@fG@ko:l/ . r(XP^83n&]%B~{㷞M)31[JQA&sSUi0(i ۽2&Z7ȦplE@c`iZ# I +wM]z iV}ax!1cQ(TZVŮP IĪy $$@S+s0K!R x5>BKVu$W =D_K)u(. WgZ Zed0##L PiNφd礂/;wA2.9u "3o@JөI<;(}01@u=4bT:묙-"p\!^],>|@.տN{{@{${K'Τ~g8)E8Jeg,3ٞI~Ⱥ/9xA<PZki83G1JzT/y: F)gN.*דζL4rkG{J"b1Ts+TCjTV-Ǐ g}iƩ֢`.D嵾LYN?rL9?`P{xKz~m$bkHH`_Rgs߸ wa# LSH޳y )j&ݙ3R L: ǩwf P/P)ax/Bh.3`/Hxgt"(`%bj;Nw81)JAT_RNq>g7jz{ʽ[W,H$D |`#ڥ?hXt161ij@[L6s{Un;.WTryC\H,\!w !%[c7˗lhlk %]n]Y re${xSi$.'k3;J;f:򥀝%aboR|ek)rh0>=/7ʆ| מEBK0^{no{k-s:Qm; qGXa_R,b>^w4$ :Hݭ|c> gp(e|Ȗ.endstream endobj 665 0 obj 2336 endobj 669 0 obj <> stream xYKsFWLr9 ^>luv]%5sHE9HD 4V\!\r٢AOׯH@ sr^?{we #1!IDF $,L~ӧSugMb_m/.O߭ț?]]sɥ=1,O\r)=ԉDXS!xq[79,B{rp e7S"N^{D̞yԗBd__Ww"Ɯ,Y KWwg<`gHf*ajr'+@f&8VKRtrO)t M0}>癢%99]'jB ~ؒuEuG$)K`bS"nzG<iUW5S$v MTX0NCBJJYu|vgQ:*#c)KJCs\ kA6EmI} |ۃ454$j8)Y }K0C어ž(t_lb4ck5PDC /Ɩ!{p킬IϫobdN%y ՑuCDbL! ] f!}JFM0F~R.Hqk.ˢ3ҙHv9'yRVN}:;Y:BXθďCt)"`ـJ INEY$z8,yUmMi#yŒ&}:ߜݡ)F,B&'0Z0ؗQ1βFNl umja\+TsͥҲFN<}Oן@ M_Vnx )Lm͕( z` `7Zq v8bkMhWcN'7DFJ7*LTXvZ7vɣabqUF roϳiҨRdKfb'7Ư]QU.{lV FxHgXJPѨN: KT$u,A:pܓ!3 Ӌ8f$V!iB4{:Bq'wW׿Q(R4"X7C'hlF< (`y6a\=S): 3"k8%wM}<&h#:ؖ=bӒD\k" 5l@J414'6PT>DHmq~  n5a,,}_p! _te: ԇ|h}eQ9΢rޗ!4TG:\27,qL(F89Ek9:nOF#ۮ71/sWz9V?Ij"ʇt6[LM/ԋT#h|Oe7)kϪ-+;K~жυ |Tk$A9[ge.,Ĭ(:MF}T8Nk fiٿIV \)o ',\~Țl>Ok|4Pm&INli'&/.?:DU^> stream xZko_q_,[^ 8MqċXXJ$n(Y"y%gQby93q?}~n.ԁZd;TE!׳KwKGJ,zB '9"A mê\AiO #,xǣflӴ(L^T:}#psqI.B?!BŞ/?|u$>mG ^Ldaƃ0_>^~r!DE0xB8 ec\ v"Q…Glta“ )O&l J9@/HqxSE_& /|uŗWk6}6mg9{+Mw\| JQ `-<-web1P;í?(SœPŰ|Ywr ܵ%i<\T?|{8Lc3ۺONkWyAcz}; ׋u("PƬm0c0Qա]Q%0H>):M׳X5^Gt ԣ 1eSlO01}cUR(OE{؞l Jm`aNʦPNV:) \7_kXӮ[t7⌀6eK%x}:dk4X:oPΫbKEl07V7J}yBR~qqws@)@2"4v` UyʫR]pDi 'Na_[cp5]W.QҤ^JU BBP u*.K5隠kd@/WSTYϠJ| ZmSVG;jNaS}PNt3Vma5׬W< 'eBȨQxw9ԡS Ҵr'SL-1bQXSQ :C=xQ<:=G$_3Tc^\qK9nj-3,sf.N1B#:eq0+.v{Bk pKMr':*`qLTHuGᮅ=IH9;^pjdQJ#ۦlfK݄jFJUb{l굄uYӬd;6y鵝O*. R36{;kV$jP,u(cN= #ZҲ*꛺F×{[5˼B&evPjaβ1w%:dG975TШVjY.b9K;..cٖnSSư@ɏa]$]lmǝq#7)W忎T4üW~F=G֥fШ1g'M㣱Ϯ?XQ<D:J̰&CI$֪yP(fqyd3hmtJhxN /g9 b&;GJsUfeLgp Am[)WkY銄ͦ/"H ynpȃmnZV6z$g+%G3 EQS4I #&[y~:]UG;BbY隭uos&REuHEK30mʺ$IĽF,nnI <5ZN`jZ W: l]jObֿN4dϪiXĮ΁:LqW;.S( OA>ߜkPVY)#30>\|ohJ{OP8cl&ó^++)`r%NFP^o S@Cn!)eJEzMLIf>H:ԂJu\<)5 ߛnנxm(u;^uOjCDzۃq+ޞmr*5ЮPtKSi8<-Ѫ' QZ/eY͍asЫ%VZR)? 'QmA2xSVurFC];D7RQ#gV Sq@P̾ tEuz;euHXi/e[k@y/}Ezd m%q).4h.^߾-u~TBC+zBE&#çJ9#lD^@7vbdd *IR&W.$琮0NW-0M5zLfl5Nmj5loY^zeښN^SjS_Z бe]%jPKLs-Q$ BW"bB oV;0rί;l!zqۡÙ6iyľ}jbCzZ ؗSzDb}|OT?Eendstream endobj 675 0 obj 3499 endobj 679 0 obj <> stream xXێ}W[4f@ll]e A-aT_8bH $0ƲSUN Bc??2v!{˂kf?5Fb_8Ky,.uX.q^s2Ed)׻>fqN+k˕H4/rz! 2֧}Xgýblvm͚ިT:9]Oya Nۮܨۨ=]N18m#+vՠ -+]l YI[Y5C\?F*Ql}zŶlՎFq B&1Qء},%+Q`µ&cYgvԡW&DUI6D(>kW jmu:" 4vR(ChH/(&{Ji}0PE>Fxo P/kӎN8c8Qp%Sf@{rf3uT64ujTXU3X'PVMxq&lYmQ lT^՗"ETgfevg:o;]iӀ{Wڢf ۭ:rS)T僪p8Z = 8#衬s_sρ̀p !{Lli$a !nIMӛdݝMY|ʲt @!&-3"sBfDV w˫?,YVy^<I`_]9+A|[q#h02.c0S`GBy-qʠ+3aG"ۛn?:w -]4G b"̴I8αk7rSVpnۢz՛"!Js4A/aH[al3aV 6nK I=bmg\Iv{[FwW4EbZagA86 $nOy_l1dvד ܪ,_5rqT0*"9%D&*Ԉ( B+^8 @%a\}hEh#6X*{h$"'ޗ$3 /OPHF!Hia{g$| {xӓ96o_#~x,5(OV'9jNB GP۩Y%"1 ^$w%t9G.kUn2w;7*8сSb`dzaLƓfq赖r_n a g=} 060p 09Nͱ 4` 21_~(y'5^k>S;piJLt#CS֏|r!Tphr "BLYT8 BH^>'`7Z敳ן׶zO6f{T˯h]=LQ$V]7Rs!2UyC[Q%*}Iy]CrJ)qa99S4A!0De$. 4-d7~6Q d倭٫m ޛk[БZNLnH ߣ}k'E{;@q6{ pM8С 'A!F7Is[>(@q:ޥ)OeC!sɒ&eOqɺo,vZ3-mvHd=c~WsHa>"~m1_gww3#O;$FP+ɲ]3:s&.0BQ-8)߾ Edœ`ANa{|h;[DWCs;vOlZHA~_g4&'st߅,ߟ 0HuktOOBnAF_>, > stream xVn6}ẈĬ(BCr Hͮ%9ICfɹEEq49sf!O7!,gA[0|"Mqw~v{}?da 3J:qFU 13[z~ub,g/ڔ- G K|jJ]u4`j8] sZeUzVZPuHڻ=cҝυZ{qN~?cn8`=t w|{>ٹc>Kw2跶uJ3 ǖ9ݐa7wY k耍?P nHhۦQn  %F t{CJQ&KxؑNeu޲ :4:#ڽ;4'S`۫tocx,endstream endobj 687 0 obj 1239 endobj 694 0 obj <> stream xVMo6W"VH Ѓ$EǍ!@klGwϕVR̛ٟ3J_+~ߝ&(w+ RiQ(arE(U}ѻW6J09v}f/n/.m܇s<+> } Kg1Pm $Pz OOxzo{m 13B'!2{SVy+gUL*JĀ=YHI&u}/B9SzDRuǿ%O1jW>a?!OLFyi`ݼwi "9A1~MT{0UiWmI LL=&! gcȉ˙6)S >$GH-"]h).Jؙ1.*56%`v~LZp)CN7dN&.C]A qy k%'ZQHv;4ra䰟 栠E zb}EW#p?|jf0aͼ=K` ,46^ !"hcb>Z .l}XTk V8g.7A9FUvb-hjӅqz0J|x@L5 ¤03UVZlhw5VE$Cl.D;Lت֊N*dw kvj߬u(KLQC!pXsHL90,GMEXJxww%b1{.8> stream xVN8}W##ў؎x}``i dLڤI\a~΅Ni !N])?K({ƙ&r\8yr#K$=:1 !#!$ԃ(sq;?38Y_̣o<_]~f.8%st s< F!$ 8SlafCt3!nHjAMD= <&e.ZiCNc8-4pVu>4uZC,?Y@/GE@.cPJ@A捑t[c3Έ.62 ̖h],-c3_ 3J24\D[FMW&@> stream xW[O8~ϯc۱x%@v+Cںū48sqڲUUE͹}}ESḐy._!A^=Z)ܢ(Ibj; Ĕ֛7 Q#Kg+or }1zϼ;(jB1>|H0"e[f}x2xD8+)sk}1 l Ξȗ^ }.׋r Eb\R\)qYӛ% 'oA_j?a9z{ߺ?GPc37O^l/tw>[zU/+7! qr 2!!sIY˳?+ѨG oia$j2ҙRe@XeWF3.PUbEVB&_?MHl7b7fqE]\ |H,1t~ M& Y$zj'NvP^ީ㎱K-<0FAהG }Le/;e4?J(d<_ {>֝aIxԮ) ;BEfv]J2١8)q{z / Hpbř r-6d3BI&C9OuzYqOVPBh)F]G`4P[ҕx\2JA"-mÊjW*@@񽩴:PrU0BLNcaDU1@V{BqъrTEtv&c \: #VꐚN# ۄHgy`v9+/NR]*?B-ECÖN9D"lb";8aGW>z γmuTgsL棹&öuϻ#_ׇ}Zn͑~iXば+Dz z4#NBLCeu/q[S%e#o33-XVT` Kt:mujPvn8:!Z\Ue;_!V mU\]ry( ukF#SW C![lTV>`yPQendstream endobj 711 0 obj 1173 endobj 718 0 obj <> stream xUNJ}W 5ӹ{H}' T'$sKiWbCiգ}Y{@ ZaW>.Xc}Y0m6@(-aC0|fN/zs[^\-obyyהXG FR&];L:(7jRʒP6p?lč!!k@*\$bCue g(sJ )8<$Z8'awntF1+r6s"E{ą2yOʘ~DYiV%7}c]s>c sT0Iing;\7ɪw7NnOz(>D'/n΍$R1b5 1!DڕUOzIC$~Ÿ9*qR9Jw6ޯGE@@\4r9d:e.EhZN>r uCQ׮(!w_O`hHJdQ wWnNj' 2n6grM0َ\Ǹݞ> stream xMO@E+y JL hYiŘޙ3g "'ҊP7%[eЇk~%9ht$iL3֦mN!_Io<>yLf&wɔlsnPvcY6(@p䑓[MF }et&0JѰ&K@i/;C^IڹW ̳FYUﲗ}p1#Uoi8u/ETxIN 1i,N kw$ȝ4N< f' 4lg":)`NUV[׫2%Oendstream endobj 727 0 obj 326 endobj 734 0 obj <> stream x}Vn8}W[⊺+@I %V#RIܯCRrbarΜ9s'E3kJ[5#>Ì~_"() XFi3ѲͿu޾>}^y|^^^.cp.ΉBG-JajBXξ(ئ xF,(N80q3@GaRnAC/)8<-w>wR]K+j=knSLix`TZSBV22^,ȋ9cC1/:`([ D[ҍhPNS -fTtMѶpBp9 ֲoi2wJHeQmE#hvZ*F&놺-4eS?4;w{U-2]峦FVc zI=Uz勒FGT$j ,C-7޴zʢ FE ;TF,l~ʒ xw7;m5j5TwO^4kߵ&Ѓء?E9:E^-T62}}Xce4_ODw H<ת9"Tb|d[HPb_c>ȱbuI1'㐏:8K3b{ؓ266CTDm*ʪݞ%ai\Va&BXוBu'2ܸju(;†q hkhPq<Ŝ3Α997:+$oLFqSxj+TJU@b6%,Z{)Jy=VID- eQ 1gk.T~9]5xI{tCȜжhp[c Fr\ }nޠ(vvc,Hgaa#I aפF3=iHSח돢eN6p\ކp8 'a'8dHE@iӼm`ѥ?WbЍ ?K3 aA0m2=Df M\&F e>'J_Δ||[ww#f+]|C +E-WVy)lҎ+gi\5uu|2tendstream endobj 735 0 obj 1272 endobj 741 0 obj <> stream xXr}W-r6l\ήT/Y)CROwHڔk˳V};}@?X .7=eM~o~2`Wq`_`ֻ{NDQEևw?dc&`,a~| +\& ~OuwI<> #Bp!̝"8_w쿑=X_9҉XUtš\VɟHVWoE^=[]};EEv0 ycݡ9[nfN3c/dmǪE-Dγú1Zut7UQc:f]aZݱVTz˴dӚBw;{5(we0yCBx+"k_jsR8gK6Ml=;E_c$+k;M:4^2SkVce!dַ5lt";Ds;8Egs_!yhTm+Pz-g,,ܩѕ0$G\!=t;$訶0mH+{g//Ma!luzq 4M ,pKtXM{jBQ>@Zej^tg"̂_\&#jç c+PmxZgɶ&7>FGXH. ֻ7%;! RZp|tDC5`y+cvPG͆. ,B| Ed.*Oy@B> stream xY[oF}% rw,4H 䶍]`]4YS‹+ɡX7PFc~o%%" g킩=PN2r}wHiF(,"ׇ>[O͇#/^]_}u 9QhK~$d1< dyM+6{Q߬7'渐f1~X=K"w<2 rs;e93>pSJ/gÛ$_|͏K9 "aIc440'S3Àz5>D m%SncoP89_QfYM$DmswTGGv5*x hk5}KT9:OY*[-d!(yJBj1hY!TdJN=S1HKs(dskiy&t,>],i5F;% "mGx[ j uQnӉos?chG+g@zEx1 ӹW7^!Ї{=+}.튬hJ[ǢC6GCW'bFc>2QR6:iQiyӷAF\ԏeQ2O%;a//_E_T}bX)R y}7TbugH%gla:VA;EO&z5g&i-`<9TxPȹQ;q>{#U67#:)Lqp"Q!w :b<ݭY6fEE'YϖeM7rsK5'ʆq1GDyU`1VьA~@iɄ nf /6?{iOޑLe$`6)kj59ZYPQFڟura*C5tOTk?v2Wcr)cPV<6oX[)*H&ۚZ3B|.rŹ8q b+}< }*yfDq;O=/#oJPlm߉M^C=Bfq>YɕGSe9gzd;*Fv*an@~N4fL5.HMz}cHm+R3&SX;N;O`4qXf5x<0#`ܱmIT> stream xYnF}7^6ټedYX a̋$~VuMk'0+T:T#q(#Nއl-w|0%a10꒐ǔqr[n?$GAw.nP#\> Xm׿-w:p_Dqi~i"iR~HU\= f\&yDaLκrb@z %b>媻SEEAXU~{u"1@ۑ0N\*kկ5^FCeB.v*KUPKՇI\uH;V6؉*|ON6b7Gjfȯ+K8W~+e+Of@CN"͡ !AeQye;1V|`վǼu͢ʬn`.y+ٻY'_|+r.uoY^k"kLkb}K'x? /'akݴgR.ˢЖ=3nyӫnۨa: ('PU{7B:"+Ҋi] U+}nR<}3"\2Ѽl0uJn&令BYś J gk~ء߁$ר[@Ӫ0k&0F]ƒo#zC0c'dy-k@~6B1@6z,V!T<7؍:ܹLHX`MO`2 Ui|t%}.9)8ttnoPM3 Yɒ6-R0y3,FXST0Dp?Cۓ*|&Tpҡ` YjȢ1=5wN9>,D<( "KpBbvXƬוB')wRe6]h C|]~Mqh+^ՂS$(5Β n1~vJ3~L̀gKMxH#pO0\qL|K>_9ЬW熹Nޓ.DBJ70Ãn~?_endstream endobj 752 0 obj 2287 endobj 756 0 obj <> stream xZێܸ}[4#ԅ~s3o;@?hڨߧxDQm;8@]Ί*N:E+0Ac~n}w7Q 9aG9Z.k1Q8& zׯѫE޾zw>~|eF R0^\~,FJ!r,Z Zq/~%ͥ^b<VLqLجya!ǔ򜙇~ q!`F|-a/P_jvc$8JgW;m:u- 8\աVE߷lCʅge8b)pj=S/<49g|1IN8ďlFqqx-y NdZ$KH]`Ѣu| G8" @g9n%k1̓!F R:EX! "11T˂ׂ B9Pv+)`n4,3\RL "ɏJ!o1"q r@J(KqFՃga R^@_,9[4 uBr։;#*\Thh:3%9'; Ֆ@A@Shi*Y (Ut*ꍼ;P]C,ʝ:+ZqfL|׺hޫ N0T`,P{I5zՓ$zF/-؂mvdY*)011Cn]Gы6 #!Xݩ{=E@k&a}[ڢOB~h M[+ee$#mmY vIKZu7U魨ϔAAmE_ :')X35wrPUKW+r3qSR 5C)_gԶ X[ >@ef*x|9xX {p 9@nes)Wp!E~jV&Z=D^\ɗiiF;;6n)x^! ,׆2Gaȡt8I*~'иnO"fZq[2;8G\G2ʪI*v;Q"0&>8rD %>jQؾh+7hzR-ВbӢFd>x$J4M/KTr+3lhlyf$Yy4c Uq d"xSn9U؏6.#)8= wr(}Ruo ~[taK5e.x^QM_ G`[?cDP=fJLA޼(KO΂eW_OzE4VH+Мu)TۗZݪy2K݁?(t[)y$ 8.^ W*hkq{r 4n+o.,.HZ1{~ T҂6Q  CD*'UQ0SÄo0LAfJi?\:7&T`$[tU '@WLwHXI|5Fy#nʦ3x;_j0@3b[hllYYq]4:?sgPM؈lZ,~ +[^x9繻1) )fs{Yꮤ, ,{y74iBf8%c6YcaU\Pe/F7~N<5n٠tBҡQO3Z/l<< o> Tendstream endobj 757 0 obj 2626 endobj 761 0 obj <> stream xZnF}W4qe7oM9fa$hs ɱ,+\b. ]]]S; (#_cJ {Do#¢ qRI$2"rZ|?Eora4wooɿ_}ӫ7fcp\ MD&p_>^-^$'ƈiDp}FtE? c! 7dj!˳`KHEG;_43mѭQoȺ䇪&yUiڶ C0FR].7e&^^ikr_ܕ}&eOM&wE_%⡬GFSc4+N9JH9dSZZ )@;8勡xUO8 ,ڔ)e<^j 9l7riKC^k$3nuJwi(plcy1WmںXSul좻0 enKi4+k,fѐBu$"3QT\EFI.`rS< N͑;R 6`Ŭ$pgJڴnY//hsfˑ *g\?4*Yܵ&&4H3 B]N@P۸|S`o a JqyalRU^ipJEnGHf<Fwrk8µ;>?NPin }k/9jTW&y_UWW(O4U<s`KPG V)i914B}"]"!s16f3##:e)|R15cb$*_VPUQ+*E Px{0PQq[3d\Q5i4lY: (AS*키f1nL2=!}I-6ԡkJy"N 0niNq:d=qVwV&qJ R8.B cZv8JͰ:͓uX_YHr1u6c;<9̆xNdO1V 6̒2-9nIF K鱜Vqh:M*Tz"k] .TOZY| Y+ N!`FaBNS@5*- Bs L(Mw/v )"RE4:8EqR_pf%Sj `LLjC=[b?A*ɚZsCe3@rqOi:n"AK K .pI4+G&ADCao{ 8ROѹOLc'w wJ٘ E.Eָ݁,exla眘+ElqXϗݡ}%  C3fD2+c:ÀLO"P)0p kn.y/hPޞm04}@И@@.a[dTğ$=0'O I粎O; I{8 v7iG3lW#ȱ ِ]CCf+tT?3%wf:r K#hb1ٷyK[mLkN^['|| x U&ዌY{Zb. Th>p=z>3L቗DPs|;hVwƶi뉃#kC[e$?Zd08U3~$v9'xdv.&;J e .T4ӆAϔ>qal_usd"0gnQ5L DEl2f YxWoW `xN+L f_X% 05oѥ%|/ױ# o5(T-sendstream endobj 762 0 obj 2975 endobj 766 0 obj <> stream xYmo8_oM'R%>uE/@peUlQזRI˿$ZJM8EgyP rwm}oGD/@Eeh>2(P& -vGٯݧ}ߟr~y8=?;Y|b@.a1Q|#a_BԒy,fs3NZD9*=jU-Ѳ*ۼ(r7U+T`1 r6leMA9S2-HWNڜ,xDPjZ*u E RBBJ.6Ev uUiOz#WrZT4Zyk1Zę-2Fm)H8Ԫl5kCue_*tIswhͽm#_hWu!W3T. 8 D8EN緷ձY˨]-8:ȢǔSd&1&"NK70MǫU/ }O& Y`j`*bf831c rg^/\@x CLakn58&@ǐ!57jME=r]Mۡt@έ`WmȷPjYJ F#.`8$$tp[˻7=`/~KzKSOnl䷽,kgERk#[l0.O6Kc,*@#8a3*5(u]EoL$M E /Qf 0.%8ԭBP(&8c4UڙrκIA5>kAܡE U2XZZ+ul@15f]u׳5"QjLU=]U:+T>׸Au_;ט;(GzMYG]ɰ`NHfOfi*9B {ӱ ( ͳit3_8WZUDtQV< F ™ |xz6pkAD=*NQ3upE7p٥ emvt:iPCj'(9|>Mوovw0t?3WǓ\1߁vir5NW'u:V4!ĘIA1 */Y{<&Qq餺W`-Fk{vez%y7 tBuCbmٝ E.T8r<~9N}[סDZO4fOGzWT\9wT$M κ 2K=b)` 8kLVi* T(jψsʏIQL9QvFϜ};}\VDx(Z 5ZM[uϸ*G?< endstream endobj 767 0 obj 2398 endobj 771 0 obj <> stream xZ[o:~ϯq˛D2oiك6<-WfII& jQ\f/`Ζg }{F?ٗ3jl"m>;sQS̐Sng}7jesa?~ϫ_(5 DmW4 )^ݞ_ywT uQB@KrgrauVF:K=VC͢j;P4X)&ClR"*cQ+ gR1f:d޷H:}HL^C2&'`Ra<H3"mosp-yݻn+Kȷ3"j:{F qrE:v,gL@Bۆ`>v)]#Xw #޶P(m]jn3~uhjV@⣦XݗYmCcۃeUES,/ H;J}*fɹiӻV-Wp2Ǔ{R<'ձП1)H(@>jSȣ\[CW/@ԳV'<ȩ.=0@R,,4W W9v-"b;F.*;jd4Pz7#{)6"I3naSneǫM!X6+PYPR`0h9If )ǎ M#,˓18P}EvZ_W`2Ys ˡ Wl/e[0 $3ONo;E8-AX3B''YB άǏ&{@ڿfS&JdbL2"s,!Iؾ<+1<(Aq`V t+ މ+x Qt5_ ;GWU?uQKEpz4rfLֆÚ`AaLs` ?dE~WrKXvrZ[)g_H“endstream endobj 772 0 obj 2542 endobj 776 0 obj <> stream xYY~_o;^:lu6 XԒh_dK6 Œu~U+ `Ms۫ 7_o=Ǧa]Czw ~Erܫzy8s-Vr "jdn: tpR7,2 8r9vE *g\ 4w0 T좻A$S> 3L6n7 k_>q+ 4Ñ,/1(OJt*N[ QR]9փ.34f>ĥSYm$tZpd++ />GжxZV%.TR j:a8C3q@4d$&Yf!<ǺwlTfrtgbNGkqTím3ˈ}dRlnZ

Va~YdP> 鵌;Mh֦:&v2{vE0MWt CDx%h<b|۲~Vu/;Ey$> stream xXێ6}Wy;z&zɌ`-me$MoOYFmXSLP>o.1C/re zs ~a,.0Ѧ],/ 8}WjqT$8KaZ,?_>m?l刄jڮ\G&Y $1N0/HK&qB+ZÚ, ">z^,;aSݽs,`r.ZzAPݣQIIP`-;uPd83=ϴq0v?3{ `hs눘(ب%xhj)O?ue풞储`Xi.UuzA!ӊU4A::,xC%zAe2n-S73ɚ@cGECR0|=*ӕvԁR缧_*U(

  • \^OQA[)p1r:ɺ=6 <Ю-84*]L 4t L Ƒ<S.U ΉQZtm33һyvf` ,pg@1.e_4,wziH(,^uht1ax&l &lzjv'-C< Lu`ɏ5g9 NTC61?kH;&L).R2 *Լ N_t K !H+yYuTfo:ia8AQϾivr @`hn-\7 ?+n9~.TT>",4Z-֕!:mÏ'.e0^O@All B#TчQ)H[ziJQyhb1eOqR nZ6+ !=:o &uO)`\n5;Wԉ|؅R:u쁟l ZͰ6h#>Z8Kݺkv=CN;̌EҝUBX(Bׅz|<68SC +̮Wڿӧ?OIaMHaH{ |*1e{U ka@p^pE O􁟚J!B_Ox0*PbOGݚ3z+Ym&^yd>D8ZlwdC {(XC]ڳʓQU VU\Vަ0̡eT8 VCP@x*ک% xcռ7 #ـ{+y%\GGsc]83o/2ߋ? cyHPEqUE. %;<4#z5+ր [ ~~\iI֓_3RG[= A!3u )Ii]or՘[A+3W@e |n͵LrU< Hr +u04JG,yGN=)p_3"ʎ{N4ńK]< 0H7q GTOYwG~ô5ow˵BO]sh4T\ 75Kpv+{Bh ;Aiw- Z=Ɗu F3]mCD Z& >.rw5}>Uu Ph؍}77duKsFZkN8Ӻf|{6( !&r W: N"ʞ)Ԉ]dz}S{> stream xXr6}W=c! m'Nce&3uh PK,}E$HIN4#vvϞ]38_{xC1s=>ϨY[HjVo Pهo^囟ͻo˛oonW7o3hGSmADezɼY3 RʉK|8'J2Ң3O L4n-q:ܖ*(KZr KUqR@/agUUc}ZUCeM* Imn=ۻz˚.jNv\q\_6#J$e#0#D@HaI8Wo?S2>B!*JWL<+}6X)|TEAsq~O͕~<2bj+Jiԋ-7^;yzz3 wSZ&q:c`%1(4X9,x@s:v"LjA!XF\ShǺ(PfK]ꋪQ1LS(d >pcBNEqC+1Д$FgsfMx\\h &BDq^YR- )z;7gO ̲>,#LQ+*ԝ?\.(ZL[LMý0HtqB]="{ei6:6DjiR]F8}IYP[d{>ZHJLC9s<9Y H*2хFiaLILgkCX\U%4?ƅR{R ;YWQ473SG.iY?im'Dyi>cNq8xA-^_(LƲ,V7\ U6AHN S%nV o`EQ 23jZ|5ğ_G܎~H;\@&OBPWy672oIՃބJN<>Tq_~Wmv-&$6GOlQ =Rt٭9FK~;k9Sp0yU>w q=.| I|gϨD.߆jGpp@uzmݱމJyLq( v(a1<8pZڮT9s-LxOS;;%%A=qv(Ja =l< .9YA]-[M/yfR晾øk1ol0xLCxt'm.tUfvఌҫAN"|w2S) l{z?+7fT)5O7l8 46Թ{vJ#MI7Žof֑ 1nxc~s 9PS粋ΏM~un w5f9^wL~Th1@_mĠ|VxeLЉ.yΈ7J c?~HCt0I@%jt+a !NK۩<Ɇ4~%$nEu'H O8tQۘwϙwƏGc}*Sy5<}Q3...@Ѻ%؞~*!OQȆ fY~_~4endstream endobj 787 0 obj 1690 endobj 791 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hbVmRllignT¥R!2 #endstream endobj 792 0 obj 124 endobj 796 0 obj <> stream xYr6}Wbj!{ޜu.rǒkoJU fk Rٯn\8CJÖ˖ӧZIDZ5W_\E|T  w+ӂIIYBǛ;o>|wvmIhλ{%[Rᒵ_KZeaGeN=WL("k<+K#M"8A;rPÞ@c[ J÷d؋^FnXlQܠ /h GFJ $.ֻ^Ga #qӭV=%(kjesЛ=ľ0ij*AO>þ%vKDnBL|UVHZ{|~cj;:/nFK JoeGpZiz5Dp,@N6t?4sL ˠm[+]9~q&hm)y٪<Gc.,!\Bd]]Czsy36 ;sQ&Wi?8£ԣ [W=:ըKx[iMㄳ?n߼m#< AޟEdѩP!0GvE'y/h{osЬYZ{!v >Q43&`BbvpNr`ӜPH@8t-h6ZkjE2hOzB^tj5:Js;Aj 0U1CZًz r) 0N-NMAeSgIf]/ HE \䧛7B3繵`%h&dNЊ ̔|jlRzzc9 ?4z;qc+:E##Q`?g4Wʬ|S槊~3MQ; {UBl,[Kȋfb㌘&Y5N8S(<ҽ0v8b$fX-eZ,;m'ͳ^xG05dd6j%5LQYH'-=_Z_;{kAOae +l4#{e T:P뤓t efih(I!A8[)j'`nije aTolRN`qY K'Z\MW+p}K[ܛMhCEJnF up? z' ؞WJkd!?Y,9o`詖'9z`1Ya?YTXQiY[>&8^ďҜ][8ŶL%SY-K>Y8/{8RfկߍSendstream endobj 797 0 obj 2640 endobj 801 0 obj <> stream xZiF>EzlXza1JlIy<k&^pHdիWE&eēCuyo{|8T.J;}#>ES#uӓ{_kҟE'H/ڪےX( lJ]whp.4X_ȷd?Ҟcrp ;|^ST=#;?qzFꖇ 84uNћV>g!cABMv:L#R$Ţ'Eu)E%j7UrMbߚgp]mSQQ7 \H=pT,"|(^t̤;7m7@0 P^VHfU*鳒:6Ob #+H=CIԢl(y< i2[M4x.>iƳlqFyVEnBR6iN'<'"J ~Jiop][R <;0PEHFh:+,Ixqny$Οd˷5'~ .8?_2@fTBW3;.qIa44nԥ3>* aT繳ܮCϧo-Rec{1\{n~J$˓LB&x=TiW@:pY୅$9y53w,Р?>|qXkhhͲo   ܆Xp̱Xz =ɛDCsmj%k,[ku凚Vq< J{ПTmH'5idh 4M^RmmkL!e՞Scʒii=`@p'ɛ)k-ǎhm0:]QZ֊&㾖Z Jov7qBKd@0]dNE?BZ)s47BjNo@h:TE{A+95A:Ow˯ni.{G!'TTW; ٌYKG"˃lP=n2đbV t{Kl7~FӲ48eMJ#K(P}Pg'~߮Eo\iPHoQ!Sz$I4Mep+q.]Jm+ L=M{:LLcX-bFmn\ i!Ϛc ^5P*\‚J@Hҥկ1XEv~.$5],6lJjUPFUD&ߗEU \G8OSMh7HKVTocƳx}@ޖT"͔6l>G:CyeS?{")ą:!YʱS^*•;_/ЭIʢF9f4[C JR$Pb/'!Xnnһ^JK6?5'|J1*4Lhh2n>b'1Γ]NBvE0STJ? S+p\)Ռ绹^Z5M`(IsP;Ќȕ>Qm^P/0t"ʼn1!c:ӂ;;b" \(dxpQ g}U.|Y9 #V-mq. cr?(䧟:ٕo18t:j4ɛ|8xfn*_a9@^d'XYL̷nV"M?;C[8A"cD/L҄򏐂k6 =DžNlOz-~m QʽPf(.CQd<]PS\seA 7:ƗeW}8=(h* ^CA߮s42אwy:' ?}N5ng嗶g{BsbZބ%SQ_ x!~[|ٷZN emw&t&V|D}BԎRSro]S.ڇ)cG;kJ[soIՒ@ࢺUϓċzfxUx$eN)*^N!,+w|;{ɴNYS<̱({pt Әmfs2%{e2^#"R\b_( ׇ_ endstream endobj 802 0 obj 2993 endobj 806 0 obj <> stream xYn8}W-#.9s V֥-Jv*^$$7,,VO:E?25//M^]x'x`z_|EIlc$iJ0,$xwOn>~]`^ ;^~ %kf4Nz4Ŋv"oŖl^IK«-im0P6xvKFhI+z)Fc!UK -E? yGܻRSr_<`Zz#[p--| xDKښ0? yd퇐}}=몼K<*LJw-C&ĪnJ:h:M$Χ3ɢ߬W>k?ik 0Th#$n's)VQs72&YBo.V޵ZVwK:j;5Q?ImK7|i޵n71Gԋ{ ?h,5Sb:bsOiLSOSM#=,:4 ~8o>礶XO6X⤨-s; r@|T#|Pe0i/*p&J,; nҞECzO=PByY$41Eˁ.!T}-8 z p1.B&0qzq~UHj}]AH=S6He)- IDmɤi1@~L)K1& iHO ?d9*SϑCƥJChk#x_{g;75$4BBnD u<#*~xI6.Մ3C~,  RhJ̍MPƂ|֗ p9;%IվSӘxOÉT]г1T:ť \O$l5bdqYVX$& OY9W`q+6[婎<E]+^/{ =.$ ws]NYWخ;=uB_R xO!s|G"sڵ%<,1މm-+U-چ֣FBN_)ris F߆B`TUE,Oi uAHvu)4GMsje5C"4Oe3d(HAuA4 ;6' `IWi۲{]zC4Z7 !6XhRu>eaC7~ď4) 4i"k5ui5 Wf25ь[X@hI/T7 }g\bv}>'pz-5Sz~y4)9q;2'%ze9zllN5 #b؍3lR1G"^yt4y21"11 }G|۾]zG~:U~02ZFYGʾQXVx}h G~;}Tu*\L'tl!18k.;ֹzi,f9hf0Η'G-fAڈf$Oо}EȬ6cVv@6ԡnLΫ6껒q\+QMPs@@0dSn@{D dݼkp>#+u:<#xfeRl%틊@˪s$f&%~wfx3opKLuB,A8s%8_}w5FEa=o6ģYby s=[R\O6մ{Z!Vӓ*3 ;TXY6uDZ 2A*odzr4 wrn(!&QfMS,Ԡk?8`jWkRtl%V)I5ΕÉj@>7 W2;Y.ؒRu]vJW3)rUm֜'8\-5 $llfj!F Xp}& }Wt`{_gɊ#Qfj 4NVYog‘soS+\q?{##IރVSjz K.0 _)_O=aYpә?  MJz.p3|}lVzBfD> stream xY[~_1o] w(PkE75ZEͯwFdH°w-ws3`1?&챿?0ٗ8}OXp%aEGD俸: xxͻ{˷_RF7sr<Y.ǜݗd_*fǦʶCP*yl#\7R=42j ّ;y|#{*]=>Vгvcǎ˛Wy~/狧oD$x3P[}40Wf"~fVx /j$O<#Ϣ,b* E""oyބpS$|:qKYMU) Ã3 N]h.bX*Mѳ6ifm_ g7 ;rmZv̻q`{)+滑nw :77"xSNveFn* "N?1L,VʟTHҴt&kx\L} X@4YR@u'ISqd561le@fKhk!NZaM/#8601Ė<~44|*E8sҺ- m66ea`pHsLy8{YU #|9rLAv,aS6u\ҩ5=CORcQY䪗~S.doe]w8"$N/Kߞ< }}{w_)O.-r=_~F-al NQ]xd= .j+ .ѵZYB TR4OaS&υ<2ѵ?+qKM˟Q0=1T.ew]43aʽeB0>o{ۅ{§S? OejXT#Q x|!CYKdLϔ[qX_ƳjD!,bB '"R(S#ȩ̷?E ٯ au > طucPa8[Asw6~ [K%? 㱍Qé ",9Rw'q82 (l^kQ1>Q/s  Z}Q?%b85O%Wd$QtgUZO}1S ][6کxxFikj v2F%'jq`za2^ptK\ #-[W\ F$+ap9AWb%h'ff'p1`h/N7o{4h @N8v(їӯ[7 @x!U#w3˄^~rl/M/~hwښQ6jʝMB8#91#|"9H^R {fX>NunUx;K ^a2G!QzkҏSz&>iTZZO(,&{x<HٗpRոwۧFk]DU\S|ϗAE6'uL|5xdžy33DYWش134;!i Tp8AW͎4(q*q:{n,GT;ŝVK?"a.;%{$}2wV/z~<"PcR{ھ ݗ_"~Я73Ϝ92g #:&@LGHn-b9 6ѤyS?*LOXe-ûU+ PRHjR=H)rNڧ~_(igLlplGleE=rhFļD4?sާ@6ljÓ %7= n_t5rWsl?.W nO"+p[ǀ%Wv'cX++WDɀUf3VZ$y}dhriΦVrC Tx}SlsE}yv ta|] [^qO~<ٮv1ouJcwBs-BMH⣻:ዜ`놨ݪ5'(zhLu;ߴMB?)3gM.O~1革uӈn5tDnxh6O,?ʂYH+.X Zxukޣ=^⯱;{hԬkМоfXg;JkBƴcR]"4(2D uא.eHE31ظլ5;3k2z eožT#WdU:C8[2՗T>jƶrx1\C88{E|KGtGbr _2tCdgtbc@Ю&ZKƟPs[/2hW_frA-7A֐,&ǫmW{{=bڝϼ?uˊ,T'fͶmaJDYA.Z7}oFud9H]OSpWk83U\&PQ2d"Po~_)endstream endobj 812 0 obj 2962 endobj 816 0 obj <> stream xZێ}7a;X3}ԉDʼ̬{ʫd0rT_Os})57>y7L@̏|r>HЌQNYD7G|)(dOpqssqн+^/Lh|$&/7oN )Ȫ9T/d[/xD?uF O}!&Qb(O] E~nt{(/̼ьhAh&F O ?'DW譊r3(i9- ^'4Qƹw[WGl3Kil i. U~J3k|y*2 n>ݶ{pR|(};?>L|8ц%͉\iYvQSsGʪ%Y IڗF%Q9)ϜNO,R>ąԦk"NV*EGgWr,4SMHh8j^RQ+J܀/!|V$Mwb_w\S.1`Z.GNtC{cpm.j0zJ4QѮA1&M͝c|=.Dx̲nȀT@ctPXIqPຍ$AGQj]L6yx7E4q_D,Ҁ|1}E8З3YYf虭W&4mZh- 1ӭ\xX7rZ)g,:Bmde^[d ЊBKBPGʸg;6v)e@̀N)QWchL.!@%ʧQiJmoBKל5pSm^˧$dY'Zؽnvw|){ =ovBHCY>x+̰"L#+`%IWhx}ٖQO52SP"i[iSdYSV@/!v9݊lԌ$66HOZv8}[X} s|nJ<VGT="TQB))8yT>Ьl}Tv"u}2AU8pV˦1堥Z& aC]L`} ~Uendstream endobj 817 0 obj 3020 endobj 821 0 obj <> stream xXkoF_1֔3|G6)8S#THʪ̃8] , Jt9s{.27^9%OE@~ f oߖ0? # ,"|R忌uC4ruq_?-O7cpB[.„&MQu(U%U_ʕ=$T`01 xoREETnq4:=+ yS"wP𦞡FG,nC$h'8I9l5zLP(q=yW[sNvmS >RT24D9Ocο|$W{ȾE_e hTvط>XTpi~Q/Mb~7,Kit,Clw2$ Hc'Ui):Je}d1I@ԯ)؀ڝlVuش2} q(P6 iTtRzѧ1#wtq|omwciӆ0eg!fƉ1l].G]-?=G%x7d,4.MN7P!y| 9nBӣzIʎϓ0I"Lsu]4GGG8)s4Og#bL4O 2 ;'Z-VX]pmev~Ih6p`qd 3*Ĉt3ZpAhGխʼn\]桿4h97h%-)󄣸s cȁKQv`m}-DC7ţZY@( }B>J׽,82xDn#+馳:(TBګr'xaͲ>5G" ܷq E}WiFuřɰYaZC#0VK,u^qoҫ燷WE&w;$ ginVy΋Bz̩d`(qpE3$Nvޙ5NA6}(+ƸTn,~I&.;qi,WZDk1e$yV Mvv`hJ;AxZ9AxjUh% P~ikÚG!LovfN7ĝ}ߕor׸4L"=( w'e1Hp"N r]110k/99&-CI9?N9c ny ~ O-endstream endobj 822 0 obj 2319 endobj 826 0 obj <> stream xYrF}WJ3jlr8$ָ(gn 1 iNjS)>}N3(#1yuCLV݅GL@G^Wx)% ]^e$&$Rr[]\ϯܒ뷯>*leϨa}~g1ܼ4#iݴM٬RpvW: ㄙ3g!)oڀ&Oeid-칌ٵwW}|R?d]1C2g.S" _.}INZڄ8 \ymmM"HNTΛ fےmcbkrw?UiŦ^~- &Xlb9-Vk<6Th~0G#aZ wŃ(w۵m[ Rt$# mu~7+ y1ߣv',iM٢l{}ZG]14H#c4ŤP!4=6At%$ԛXm\"w:wW+VuVǢ_;r/{ 9ψ5+$24t 1( N lŸ"bű$"F څ_Uu?Ipx# (c0@忯?_2)}X-L>&}6DB[im&; m?IEz6YS=γ姯gһk` /mOuZ DD\ :߀gL tL}MoȻmx§0,5lS8$Yjc8==LhjKJ^Ӛd8lt?·P#rρy4תly,;|۹u_@dus>S˦e.hVvwEk(J NRZuݶPk`Z1EC܌! +H- 괍JFB/YW _iB%P`u>?/<6X;ͼ3Z]/Dtĭ2֋'@{JRT!b*xm( #EY6J`x,M]C]Н]&uβ`J2Km"jfE>w ҴEMCVafwߜ@"c`J&ތ0G>JeL:hJiDf yr7j!LniB, KnSJ3l8R%~Ps8e&j-IJ:$"iqvNgq`pj)٢b%BSeNWeVEݺ-9_EO+&%<p?Y1G|fD%m3O5Ц5r2K7wSDCspd$Zd~0r~1Ys9|-p}>6= &Q.[D fECOp,BC`9RTEq8J.@NˆO`|K)$ Y/4PHRl@44aC 9o82zw|8,E3qdM۠NN_v()i.P[:-Ǒ,Is> stream xYn8}Wyig`1"E]>dv3]EmMے[o/Nz] 6Y,:ub?-%vfeb{#,zf10I*$eܩ"~~7cWO*Zm\-º+XzV˹3Yu̗F740C x'm}V-ɫq6/36iwr]pN%M.;%HR5K 9m:@*+Rɦ|N1AB( '^t'"*c}5%؈u%ܾ;դ{9(0CȯikCRln@`hd" }cɄfqlp^A6?';L\p a]7{?4mMU4X*y!$Wj_g(bZ}cQ;qLɟ&h`0U4*6h BJ% ]PnPVAfb])1Tn1=߂7mZfa]dI gG^*v9&{#kȿG@mWQGt@*<\h02"bf3ԇ). wC5ξISaR}v n8pbJIF&E/R[?P#9[k%矵$6>Ug3@ J.P{su?WH#&zO؂T=}FIW,T fhMf:$JΙ 9| %` 1T:K)@H zTmj8+scD6%? t#ȡ x99V嗣ߢs@ x,rӖJ &(LKۭm?OP%V"wc*hU}I˞Vu̢qM$%dt~ U$j5)د;hjp!/ ն_" `Vl1mA=6;ƨCk˹%EP/bR 3pAbCן~>`i&(|9[7"Fnhqez}(d|Xf2Wԅ`㮭4=5@Q$ W+K #,s^ꙇ m}B|!㊒kp(do-tb֣ӧ42r8~8-(~7x`]8t{ˆ'G 7C/uwm^e 2CtRc9I?3ˁB z0w ?44ˈCnyeɏmw?ǵ- Ne5w=CE4hoBa&'}#4fG1%)#՘C9"/Q:Nu_@,\H@4H\mZ6Ag49@ۗձI:_&31MWZ 7N bP՝jĊNC琷]nDGn{@"bcgAʵw2q&z=HE}O;PƪqhY^Cئ hʸ3W-(J6/6@]&KƧMEN|2`WHSX{j@^$oc_hF@l3)4^wʽj)K|"%YfE3*s)ge^$ 3WyY_BNZ:`>$8v \uG%n?F8+Mo] p$ n=XIgnG:7LʈK9ӨMެvۗ!P$М9COoy0!M aWju> stream xuV]} X-m.G7q -l;y%ͺ/)J{{/k"9<d"qn~#5-Zm!Zh+?߿_~naVVxs/^& 򺙏tdYk:,Wbծ[:y*9h6#lo+POVƃBQDm ؆dw 켲pIz[=A; Ly.֫!C4vQdG+X^>~p @ !ߴ@"4y]uд"oM8WzGcK=/KqH2/EZAHDAEqT tf^` @~o="vjhu.Jks/C>Y{ :9k^4x8NĪAPH "5zk0Gd/jbx=q%۷lnGQ1R܏ސUwl˰iPCPq -ʣB6DN=lla=&,GK}jcFQJ-zKNpeayrlj%ҠG)T)B iUx2XH”.vs/gИciHۋH=߿9R QQCf8fb/t/{qXfn/RUޠ>U~c 㩛DO3?)+c^[h=vr<2U [Ҵǒ/D:hUjY|aI!W2 JVZn4pv8A'$ k9`B+<sx+Y}KyDASU">x5[/TGNjd8I轏9՚AX\K+6?B1HFendstream endobj 837 0 obj 1727 endobj 843 0 obj <> stream xV]o6}ےD1V MyFmHt ^-ˑS`C/ι_ħ>lg>3}k2|0_9FbF9IŒ׳/b) &: hC]s9tspskR8z. ʒ,1XHm^VЪ!_D#R˦#^>X@FK6g#4+x}%&`Y6SXlO`SX:ͮ+J(b"3IrUFUD$Q/ R+zi)!/ښinT]De]в0 +͵O{s7[MjS%I8Xl^֢^R;TIbÓ I%LFBm}bZipڣ~"7SpOyf zB z@/F:[L#j9oh%!lAAZ[uU C{܋w36K6+\' cfwys#k@cYQC{6 LY }֚6l4۶{æ`haЄ'}q|\m JAхj֘+~oQt^1M v[NBӹ}ӿJjav,r:kcs;0a7 VtM~}0 T(5.7˾0^jRMS?<,,)|Iko1q?(oojv\ٸD,G.2a ,􊒏OdU`:ZZ|-C֙c.w `Xr6b{ݑq\N:Q>r:;ʣ㑝{ 8GwC#8'ofRQL:I]K&;N Oجpd)[4^Vy|oQ hcOC7vX-] Mhp%ب[Ms3 [h-SMث@,s+o{C?'%ʃxJ&ҘSB#̄Bg&cD40_+{b@Nȏ[؟u~]vendstream endobj 844 0 obj 1339 endobj 848 0 obj <> stream xXnF}W,o P/kr%& ~}gBRE6L̙9C#e$/h|Nɶ_-|o WѐWk87 {ӌQNYDo|YۛW_~yzfZ2$ps].>$,·# ܙU$3< B~Z\j-;RBIZݩ'z'#]5y1g 4",rc_럤ܓMVVO8h٠7b!MǼ@sVs?_%觡3ÜK k.kz>A<&#kGU??[b1g9' !<@fNJ*0eILQ 愛=})p:n x,mܙsOd g-Z^w`4Jo(ut:Es&ZzzkRvw4C[6srzGK4X W^~bJ>@XzI7֞m]x,;nQ<}mhct{ÝC<ؖ&č*3i"%GkڪQj k+gfE\ GQ0E鹓N<O&#e{AWEƴ=p>ˣ&x{Uq/^Nۓ4 l(=fC^^xG' 9 2`|px2>;1r徟4:4-`'%jvVpᰯU@8cp'+wZb0q> 0`uh^n*A)6EBjߥO.h)=qi #ʇ3Bc(BZBkqҦE׭YÄ= R;xDŽyIg{y#χU iv][mptƇOwf,Ie>lc dM8B:%liR=ǹ[@dXPti*ܨVwGK~ -)VyrNp}T~).tɠ LD\rLq$Y\'0Y(٬5z Cendstream endobj 849 0 obj 1684 endobj 853 0 obj <> stream xVMo6W̭ޅ%)QzmQ`h@.Dʒ#JII'Ex7C?% _lo]<-@/O%fc/QfX) XHm؀D(D&[,?} 󗏟. 둞%5`:'{? ~3LDc>"[CeWpܫV5lh-HZGx~$I3'xXW"!z`$ )yrc컅z/Ra_ۇ%61bɦ-ҮmQW+8!m)hTVNULم'ɰkʧ9IYkĄĶex1C $v֧/UVo +p)nӒ$@Χ^k2IܷzïE`m+ӯ [RQ6 ]s*PQNVPխj ,WZﶛ$Al@=uFjo׊ҊEṋnmoɃj5okcO^ 5FNs=wϝ=~aXڵuti]uנLb^I"x#G\)$ )fWhP-ʲm#yiLD :9@7mk㴨%T\!R<"URHB.fZbƸFPFjT,Mh/$([ PTG  6;txvvg3wSQ>len |1cɻ*?{Niy|F]SصTm|8e·τXALPP]˪.p(*@ΕJRT#aSRæ1ܸQwLg^o雙mvn?xdg>ļlCs;1Ijcߺ:' ￈\&_ /Hתrqe_TrwS ?4| $^pM9ɪ?endstream endobj 854 0 obj 1056 endobj 858 0 obj <> stream xUAk@+Qf$f*H Ru{(xIӘ&{wWEeXfޛaw!pqyc- h_v> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hfVmRllignT¥R d endstream endobj 864 0 obj 124 endobj 868 0 obj <> stream xYr6}W`q%xgeInTCbfĄ -i~Op8dkF9,~V?^__y%~T ݕ&XeqEͻݿ/w??yl#;˽d"%7a$d7QQuh1(G7"AHk=sjh1iaWDJVԕ={(xݿ d'Z+%s- x3ʁT~lge-Ɍ!切eV_8 i+[ {7S3Sٶ/KCf9Hܨd"!xe,X(l8nQ {Q~Fe R4z4d;38LJ~-pWTURcnvMg,SG{Dwdt?n2k9@|37&D9YW;.8{pw'X '.N J$"PK6iYi`o0@.b!O uSK͚h?X;ר[$Z07N F\68 4K9C~+S:T+?o$iϗfO:Ϧ')xՋDkTV7ƝNAM,Ym)H#Iy*|?0H` w\MlFI.NF-|L@L$@C%Ml!<}8n(Ɋ̪EL7 Nzz|c9fq/> Ge$huHcE Mٯ#rF{Mtl$Dw8Ҳ4(BOӉeT3T.<N^os:𥂾`,QW@Т̧,l}mr_s”X@`Sz_y ;q :amA^$F2WV> 3E*5EzRW:ڼW^gzh' UA΂ lי#MB2 lgfg_]t' {Bq`ĐGW\ˑfbrI-K}~ro1/:0|Y5S.OD_vEXrҢy*CV?@񐳟vj1jݡZnkv7BG1^*`Ev>kUN^U$ 6`ZsՄ^x S:pn;d _z̙c@OH(OVŒE?|(?J"U;aD4W샪˺>\'Bڭ_[k͡~p~`uIN9C3sI'BRf^!={/< >Ou#SBCzqL bׇzjCӣ!L%s6Mݚ4QTQA̽h5hz&D\F5 V EL;bz ]Ca ,/O=t5m9,mY׺i)_r%Jh(7>*kxbN-'CzYSXpӻq44Xم}!ͯY$9mjUM乡 k}xX&LELlūlB4,|RT[[K{}OʜAJu}絍G5,_quX+LmM@>J!ѐ:N_7_B ]i^ujBSr*/0$(x uLo-HS4\mTl7"ջX*endstream endobj 869 0 obj 2606 endobj 873 0 obj <> stream xXnH}W42RBuqYEI;﩮&%*,aSU"2cYq1[{1r %rs2iQ5rl 03َ#.rvRO1q E2 4})Q h*[mXB.bg-sm,r2E^5$zNu_$  Ynx5M_(LYe^U{)6y[[TnDwXM>So:nK_.ddcUjQQZ+D5)N'yC(c G(bdhYzcC:|oU)ЫZg1Bt @Db%ڦ*p=ڃǺ\4&Neue`ȡ1 #@gAg&޲g^wdfOPC*0lY3鯃PEiwp{W.8Le$=n<uF{-U+^jç_?Fo)|KWRaC}t6&'Z`>@ ׃Bsv() wIr-1ar<,Pi6Br V8(18U{l\, n y~OҞGȳfuhv5F $f;Un\y‰cCrtN熳3Φp&'eb 'c4R*{͹$Al `JRt_{hyb~K[?tX~D&.x[s?6x A?eTG _} ],nGw%. '.n揝\~y]&H\۷%$bpԇsw1`pxMybɲlrCOXvDv+8Q zy?9 }EBw1B}Fi ௪URJ9rtowU~͐F :Y d90 ֲlz_ ٱf8!s^AoQw&|Uy*09Rvhgy∻Kk".Qq8QHd}טKD^}}&Ln}WѰ!; 9OH8hi^ }gSΆ@Q'h%gkjSzנ3R_Ȏ"nQ I(~:Bڨ[&!9_#0.~C1PJIYpJ;Ck-b)p/*Aq"-MfM[> stream xZr}WLIH*ʮq-ͦHb1eszn˶$3=ݧO'₭{/);ȋ.zG5Y `Y3F9[/n~[Gv?[Z[eZ JzwqSq(HbGe$3zTpUu6'G4#Xݶ']yXةu%>-rwʅ̮<5mW+UQü}kڞV V)`Bm*e# V_Ki}U;HVv]I?25)iv*{)b-% @< _T$4gjo))Aڡ? =dxO\7OZj7<ښ'gq!0(qgl=Y1G6ӕUH>/67qȾR nWv BdEc Wnإ~C*[F@"v,AуG ʮûUpkH| BEgPahBhHtYݕr|Tu\eC_"8H]7TiYٜdƃ]xC6XlZo@A8˲~-j7;nWSU3cX<XsB# ʬ:KWGW9x/쩓='wa4o~gU,ݭ7_SJp3% $XR'UvUfj}碫 A굨z5eIZw*;;9B9ɮ <Wq(p¶KuY+2z)Ưʶ{+̙6<syJh]>Vت)/;Llg:E[9kj?7~s558 ǚf~f_sԕ.g!*bDd öPR4*)d6Wi.XIob G}aɛiLc* b ,By4;[Y6Yonoo~Y}'3ҘqI3_S^b-HZqgK@:J8<89#KQCe. FvzFX pOJ ,V*#%jc5P@E lX]5*֭´ZW,7e1@0(sSVʖA-nlݟHq:uSUTla5M-0ё[ؕ[x&Tl졩WQ F1Y>3a}?_2 ReA#ݿW4YWLj~+p3H~9 #^jPŗa<7PC/PeG>nO`r=n>]=*' GBQ14= VEVVS?VZOivb{7 WĤ,YIY;hL~&HwnE-*CJzeǗީ- Wm~9<m/TI], 6z@}}ɶfcv.kn.* 5 2=2VM336" E* 4Dj}thaMCgMfRϤ7h2{y}.ӸHPlVԜZnReq!_҈tB Ҷux%oEģ {?u2XA!gN1%O9u ']gsH-ET_hM3U$DL &aJ\>hy.n"|FFrNck= 8!aI*'ISI"u>RL |vq(@hޢzI@DCwwRL?}=05Pߡs3jr-Ɖ5lDZK.,TM_vvK,u.ZL4Hfq0.eϠLe$t 2kJm`X p#TdtEBX+5u-6-Q%@FW7M9<J];$m s.7͍V4wAŦ:f83̦͝:0Bk虩o]!V{( WF2"[/[#EOhZ  ֕c"#gMQf}3endstream endobj 879 0 obj 3408 endobj 883 0 obj <> stream xYr}WL틥* UIVjvA9s!%몤T(r0:G6'Ⱥ9q'[|9rѿ |u$#8']愆w:$p˓_f:{^uύʉ:ax䴩rIinx놼-.P:9A]0-M$L0p]9i06ƒN˦H۪&|ܒ[4mv-'+o͇$/A.#Jq:^`+ةj_*-Ҍ7NqfӒT%wZ᯼!ۺZ|C,쪎EAbS5-xݦyYȚLs@IJ.EciQ":ʠlv4M_ 몆-g\-S/rP; m+5T^W_:Ga% iny[I̎.:o+8ƪfOW]LO95˒EUm'Ya0ꚥ?=Y)La #ǝΟu;l!\x" K^Wud!!#jE*Kޭ ix+]Tf|i&'VBlDD~:Qd6C;U{zI׼UeՕ`IrYU^oDݏE:tT>>.WO%˰d`(>^ͦW0x#Aݽ A0< ܮTs &xkOD(NF;z:hy!5aEVAQe(pJ$\m?. h9n.hC< O+ i/^p\Vb!|Ɫw{bDIPHpU^i2BĶҥD5V5J5]}(cņעmB~ʻ4oW;MJKюZP/9Ľm IX@BSQ0/̅Ruy|H#bxWAľȴi:i.kZ)q@C)1Gw\ Rycgc-f02g\_(/^ՒڈR?~3O4ttLFOoW~n{!0=h7TþühXհ˚Y+dGV~ o^Wh?Ez ǨLѼjH%^~?Ɋhy*/.zg{}/ۦ8 8vnبߛu t(J%sQN&5q醧e3GzT$g6"!u,)\^IlGeK| 2ht|HGrϭ'^8@mTA;,1$@^{_Fb1ZwCk⃤84rd$V(x.NK70;UE蔣*o}PAf>/5ZJ0J: V(D9A؏\`sQI 0#E F"7TLaXMEߍ@wRG/@OzEND(x;+PuYWMcv'ӊ4Ԏ|eŎs?2)nURDh8YvJf1%rL9ӏ#ӈŎfk69Ku(8vD2@6 m?0.WUb6) K043#hShxV< djnࡹRaz=b@?[A{its   !uo?զʾ<3ьWIa{cPr7 a~{Khۗ(<{-ZQdiۅeCE>.4Ahwhߊ@K,FbWc׶hA&dmaM }%++;qIdnƱN2m:_ lu_TѼJǢRe/lmoK_&vC7y"vl +JT0/! 9d(melL3/x\.{- fQC69] TWAlQc_Ʃ9(=i'2:]jR1kuҡUWR_TA@{XD-ˆ jLjuBSjZAkdrn[MȋjZ \ݓc'_m && Օxn@&Y&"vUrSw/'?]_Vendstream endobj 884 0 obj 2763 endobj 888 0 obj <> stream xYYs~ׯr,W n$OZRLi-:٭8U;"@!鞋@ʖ._OK-g' SOXlgj#Y@3F9e/\Z'~tuyC1- ع)o ,IK0 q&4 4 A4 E[ ܗ<ʕDXev7|ю ^W̓|ohI/jQ d =tJ@!C h@G-J`I_=4&Us~U=`lRflլkbCh$õC/p*iy5뫶I+5wlZ۪*yAhV汶TKZA|=- Z(I2}8cjß_\;\ U|~]' aj\j}}֛ˏ75|~ \^?V=jAfݡ#=.QhG4-L9^m%G(Cjwnۃ13*#%m,NV' j^y:`N4Y?5`u}xw$G1 $3h~2:p5|ЫN!sPmb%QNnsy~+)GI,1Il`ܔ,̵ ).A{X"9M3>`$^Gƽh}^r%-j0# Kε)ZIphƮqv #9)IhŖyb r%@|Z C(=νYa{iHYtU @*bJ v@.%`J+s2oy1')P;4LƂC,.~AZ ` `kIo`-}ĵG8$`ͺ*$f{}߀ŐRt1 "zE)ؤ@Ti2 !+)h7FLs%|;6*780niB  'Y3 hhö3եʲ0VJ\G~?PLEF0lf3QMAE1ZW' kuS:I:5p1N!\ļ v2tUX"V؎Qԯ51/- ڦ>J)sdԮ2ah9`}S"NCRS<*MdzKڢ;$/25&:Fs,W3rD@fSe".Rc,I+}'+@ -ӡ#$ YΩQ[OY#;9_.Bg]3{Ɖ1 Ͱ;+p,2~U7ݖtNl A 4ͽ4a09+uhs@M|aY]#gKE,^9gNSaZAO/]h7\>mQ$>3ꯥ爤8H;,zY@Fs5hz(JQ@ I}qF`HEI6; n0 Vc ;kG z@btQE&u|^4C9 جǐt[0U}0>wIyW^&ghnɝ)YA\zVhU :ͻ0+E [3R)i`A346Μ3hqaZ\%G;$5GJ|;$M|$XQU3c6;Tw>%X\7ʙ㬈-鋜Lt_駨XFD-N 97љDb Q13 3y1hu9 Jendstream endobj 889 0 obj 2890 endobj 893 0 obj <> stream xYms_q͗ȶx&ށtգnl9z2u'>G5^h>{{tx/>,K?vK/Jdp1cyzvSzjDEXxQ@@22~|- }CȔ%Gy]Ln4-dVnh^M;ۀv{tw@&zd ;U+3@FO^"cϹ@@ 0"9084C"'Mz_DOUS[L,;1 YBam.Z sC&6qCZ嶩8+LF̱)1I0Cp&sg))Y%sݭb#WB7ENi!)66 ؀P6CQ@r4{O~TfiO"f2cԦЕkhfE6,]/mϊoAfP Q/Vpl"J9j#T~@~둵 s 4[PZz*@b϶-i3}' :&Gڪ\nDb]5=YxfwĎK| (FCt74 :(-v|Baݣ4}g>}|&҆ E2"P ٠(:pXXǏ{e6)pwXnP:(%mDfCd6wjLUK`.$;EL{P nWEQjPʣz7Bf|e/pei&&فÔy[P;#f2Ήwt2;XC8:&/ $7߮0 htN}u֎C3'dn2`?NvG§f^ @7wE֏uL ?K\mM }%H τv=2+ජ?k[ޛ#(Dsg3G xSZgr5,r-畗7-lF m 8ŧ-p{шf@n}C OAִhQaAhqS.;bcʂx7_^ e {gI [^g[&`MC@1Kz바Lsp9-h o /m7}ZAS>9ay/epbytA TeHۇ3TBXu^48Sf҉`5tfm'UxaMVf 3 JLQ/haih[582qyU졒XlykEl7n=ae,9-,Dф، Gޚ+} V>~CP܁Xͱ);x7ؿo=թT=(UyxsT Vq'rf2>Y|dohq,:u8]ԭQݬ.~׿tendstream endobj 894 0 obj 2781 endobj 898 0 obj <> stream xYnG|W>8}~)J QIym@jki7>f(BDjʌ<3߿lןy5ξj3 rLoYQ6gW^]|s]77W1>ݞ(vId6f&xZAluшޝ+ ։~u[BIrc /W~T{[ѳ%O(ӟDڱ;trFOVb9'~x#R6q(Zk-e#{P܋?Vocg}[~ܐj3uȃld(GnlD;v[z:cEˌث'l걉n[EtiEѭN~b}:izr~oN}'[C~0D/!r+N.8+wy[7ȍAe4({zp:XB׳^ Ub@h-+I,HKcE+a|73$䔰Sƻ[ 2ei0W}PMAk_ȁ u#6ĮA0O3d /<"j=k~`w5ma1 ':HQ`̕*:I@EHqSξ~n/bMX ;<8¥/ 2PcPc)9[:KC@AO_}0Ed՗ g}Q {Q+ɵt0HP SPv:MUS svqXzu@`_yܩ?Ohqy'  54Ug#ױ%B LgU] |7A`#dg'*A ՃWQ ?nQ'֜V/ *D@+~{YӮDQm6OL`aJZ;9 QBG,OQ< "Xur?Y2&Z!vh {~{[M: XlM;j6EwJgT9^ˡ.5mdxVzi˟T7K;>VW"^wՓ٣xc4_pvc)tI$5O+xu>C$9u>3n%o 7vDjȃ&uESңm?)9^@.AJjZ *=WF<"mx0鏗F&:V# tb ϊY6g/-HG)l۸gػG?5!ԩ  I L,:;T5;Q"c0@Äs\ >ԍ =j3;Dh$_O`/H*}(f>e&IK\W 3;n~Ɵ9endstream endobj 899 0 obj 3070 endobj 903 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hnVmRllignT¥R 1 endstream endobj 904 0 obj 124 endobj 908 0 obj <> stream xY]s۶}uX0K&Mo3mN'3~)bC ?gwJIbb{Y Q}T=?<]|0@ʭ=*S fTLqMQwp^7?lF,a~uqKdI,ɔYҒEezE,3^fͪ޽ՋhubkfokkU gct@e@ǩ߿hWUjuЖmMC kNvԺTncSP5Oj;U芭l׫G;mnaN} &loþ*vͶMO& u%?k^58>ZǶ-T |ܲ+[+Q&1ȮAq ~{>]< y#[yRܭmo:6&vҜ[yD${!dCj]Ы=ZaP{:['N}3cSrJRylAujhU5Wz[N39J3b37_482 mS<֖-q(P7Kj$Ѐ}\x懟묘Mht/٧[=u댢,`vfjI˕Ґ@)ʃP%o2[ʻj-:PR/jkԡ$T;#(EY"[@DQ@K]Qp2Gt@ SSWpDIavW|FG,:9 q^zN;+q>-uLf|#WjeβM6Wj(>^h͜=s #%<GɌ l-8ʓd(ʍOCaJYweqva ~9v~t9mxxg]P#w*5Rm U3@i'೉^qr :i7=LϠp 6G8I[-\I{) LFdzpf$DTnɪC7Rˋ8Lu4 ֮bG߁ ;o67o]eǞ 1lŘ)u+ם4ol@8BiuEԀe8թ =]k2B c k(޻}Zہ R"'/P> u媁5u}5ly2 5sЩ:Ŝu9?Ä\nO=U1M{?wy Bʪp r&3^F5؝4I{0L!V!C\u2WX~cldط5~/ڻ&#X'eNp$4eB= \g>AL RڗF: ΓDT=ՃȻk~i3V" 7'~ӎHH9WU+d4NbhB$'<ylaB;EQ"~ϮjH= r6u2^ֱ|qye_[zڈn rӹlnPi05Eؑ fSN ~-1{KR=\-ͣSzD/'Hv;b"ws)YJQ{M[3[ZuO4r7z boc <4;z:ZJU4OZb6|H󋴇xYoA\۷DhB6I(* /od別Rwnע7*wa2cW"cOGd?$qHF5mlْg1pcG941Tg}by_hb|jf5I'Awե;_W]~lRxϳ/ϴvp|Eo{IQ1V;y C9 `2xd^\;y_8Yj?CK8)Kgp㟏D`9DyZG. , i<=?5Mŗ"b]WMڊ c9.-'Sh,3xBA:μ\I{+C.x{Y?\}PKHLN1~F,;@U sESf%:)$f(w$V X,uOMͅ3$v"Hɿ[CW 4TVf?msBr)B/ݍvN, y3I617/C0`k:rծf *㫠WWd| ~r@l^1_dendstream endobj 909 0 obj 2708 endobj 913 0 obj <> stream xXr8}WqR&̫H>l%n|X٩C`8(گӸPmof㊝X }>1̧/XIٲ;?wyt(r|qb ,!K1ONoR ԫ3Z OgX?/ONݜ]}p-LeyF;oON?4_ɖYغZzMzJŶUbUV}]B5}jVuE۳N% M|%M( MoRVxA,NЩXWu%Z )<5!*A?N3If u?FO:D ܺ+axШv-z̧eLr>lZz-k(SqAx?#Vv gf<yN@н8Djt ,=rs|<؄8xJBP^0jD)HDaׂ #I6u>茞'UHGPV>H1$q827LM/PJÑ^jQMHvUA')ݦ"4us\=M&OW Q݄棌L,~ Ch-}4sG(1;߾tP2,A* hue+񭭠@`4:};N?Š@lk,DXhXTDVjwLh> #'vV!4U߫FMiۜu S0F$vQ \ 0Fm EÇDP - @E Aj%6qQBUhȰ7x77IDdAہ$ 2kUJ"jwz[*6j.KKCz$P@З__2ɥ֓y6:n C*H` ޶PV  ,,=#9@Mqg`24g{0nKJƵ$&Yޣ['70[WE}e < HQa]8a<Δ=O8Xx1qR(V0\ˏn~HiȦjTF7jx#_\}C맺wABVtTOB8E~L>!K"^gf /Ag'엩@@L&7OoOz=^^^>f^]u5HLBf}:U>)t..=:oZТ(Ţf #5Mp5 c GCLSjw+׳=has6ưi{n簸?Oa_u0P@B`>4y޾R+uAC#Sg G_WpO x6R+Q`nMl?hȁ- '_e瀵{pXiFV 7e`n\S{bN֙._"iNRPa G@vwFnxW]khQЩu}_՞#00\^A0w\E+J ؠ(ÎjxRjaVja{cBjIOKoY|/ ],hmHnx͐$gk .]mCŨFb֫8_-t,(^7dFڕh] {jJ}84q]Pٌ[\:+73Lǖ79 W8*5dSK P6 -z] h'5a&-`Л!=U$ q3 yO48qwɵCͽld Ȣh)Ko/lC2endstream endobj 914 0 obj 2361 endobj 918 0 obj <> stream xmTn:+f+RݥiQ(Qa$b! I]A!ys !%R-vܼQnRi!G;j9nb ʼ&4fl>?'?4?_~}y4C 5򌒴2M~'^BIrb EUW>4%yymzGmF|b(raHB0 #RMi?WPZ%^:a' h{nx9lp5O¼?>U;':)(a4 yJaj߀n!n l: 8d}ì`;EX3nI ]HlAmP}#lO( ª^TQW +70ъNS/9Ii#ZӀnЕi'":yRA'Z9!(W4#@5nGzVgSX5Gj|{".i5LCjJB}4**d5[|)8,b]p$nArRW_4T #֎;eI莑ZmD;]oeS=Cpj2Ѵ^YV+a.2~8K~**ήdȍY?[s 0{ܖ '++RU]ͯ(F> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥`hnVmRllignT¥R! "endstream endobj 924 0 obj 124 endobj 928 0 obj <> stream xYێF}hd"V/w&/o0@d- "[cTؔ5C~koO_yGꮪSNN<ʈ'gq|ŃG~ĿL- 8,HJ6#OSe!Vo7?ybZw6 b,ߔ_=',X.Y!IHAF(KWo<>>~HÈYHcjcycږ$B|Y&zԋ*Aʶ8y}6-D[{Irr}ɮ6{_!}K~ Un\PBc8]Y]ɥ> %k\"o} q&D|SCfݍvU g.U ċ*[ILc?qKu8He$!3d{RџTSj_ׂ*X3AO]}ʺz E^׼DYow_^|%ɛr!+-_An !Lѵg$#E SqgLhP jȣQ6 8E|]67GOҩ[G[sR;Kh%)f@c` ۝Bv09RsڞI^}] vyFWA\I]} ߡz4&) ,ZTuM# epz]UkRg4E4Apy,a4 M~-o*CO-e44+>nu bfD怒董ى;Wr4TdW] 4N|hxU /uhc~Ռ#]P{E[lB4)́7 k'(C{K3%(c{%_}KpS.Ym+ߋ57d`t nWk8*sS_I/jЏqd7`g KX `={=Cf6D%R=G!=lGA#oM-PQv'8;g7DlC p/h Wd 8I%33Ʃ(OiN dGIpd3;Q*dÔ-uguV勛k 1kQ+ n8E))y'wTűv@bTY ϷxvWރyO*~ 2ȠuVmFI$=Hh칤K:?6̽Ϋbf@s{0/!wW}8 xR׆Gh]%i)J>^TCW虆?^ў*Ir-T/ sKmF4`À![_%T`tts.]D(D jV)@C(W){y9pIyw3>!I8 *0t'RBȷA_mGqO&UVp7;76mS[DEY^'IX;TᲽ M6>Wz>DˠN(pʼgY7kjatS@1^ jz6|lZI{ FH77Jl b*룺h`KDyWgtv T(7 `9T#8WruE#-z?4Smz |.t<ӭToK'׫oNe=.6,Kg1R/~ )۫Džo(Fu︠hܥAfx8N0c6$6%6F$ЫfF\Ʊ`1xbʂ_@ܗ RX%"bwޟ:m]VS)lڳZ^mU%8n&4fz0"9CQm(ԵNlFkendstream endobj 929 0 obj 2493 endobj 933 0 obj <> stream xXr7}W\&<ܲOrKQu*JAxs1X~oOsPdKe$}9}tC_ @\@Ӟ=ȫi"CXb̆ze-+=6Acޥ: Ofy|1"TNSK刹`K]o8NyzXGAeI1KsR}.`OxW mc`^6`*uG/K>Cd׻V0$g4S1YAQc'i hv %I ^ϵT?LK콷gOaogމM9ϧ"LM4#>Pj},ˀs=zrZyy7v)[hˊJ"hKNC͖ TVcO)" H7Sh%p5TM zm+ؒDz.͵[])ecÔ$ Cpre.֦,*öv,ߠ&N CBR]1*tϦ4{f:-x]=at VFĝft?ErV n{,6ϲD^%J!xwV[_R0Fva@?ߡv@\Yڞࣿ^½X)d;{Kv0Fe?Aendstream endobj 934 0 obj 1972 endobj 938 0 obj <> stream xYkoF_1`ǐ&iKT;E0vK#[!~%,E`(fǹF,ʈgR\'^v?m"Bmc$iH7%jqt{nZaa*o9aA/adrF\q/jJ;,"mzh6/./IiyC]ܐ-Ysjk MյYe\ 6,Og펔J8ꙗY%NqvjG>i`7`=k5Y\H!8 nF!sQYqCCDGA5OZgtlv̙O#O\Ol6uKАS5$ȥl7-e<5۪x;&bf 7^z26Csމ?0wBpHvRDއ~ 7!T}%!:)A 21D<mZsߺAnhW+nƘ2̀S -e9]+T7(g$,[b@ ^GG-ZP5MV8+^d?tj*v;4b*0 (dVL! oFj$C`n J,t6Ҋ! Mp"c`0=I^\ꃟ8[(TNYRIȘXRU!H?܀T*CH!-NH|눞$W,[eWp Pxw( $bk4F^ M&eD\Bϣ卦bm4m h{n@@j *L1tn6! w+7Y:weD`%U ZKZ\ǰQxLL| <ϞRQn ġXWcT`\=Xgן7hr(7YlǸ, X]ho0 ]̻*J\T:zR5dtefU)^\Ӏ iՕBtu]5i*/I}P*4]D@X$q'd0m3̼4lFs'POcy]d*k>2q:kiy3#`[QL# 8͢)xŐ ƨ L  rnWeM;ƤQxSyi7I]3'[]k_ͨ[`d'K/ym?;KCs["wԇ=v+"0Àbߠ,)duF#2 ¬<E Zť0C{y RګnsVuBxc3ςKΝ%&|З!QDkm#6<=|ӊ]iz*l!OWテ_[(sGbuO?,>N]C;j ZZVBn> stream xVQoF ~ 8}$Yʞ N8] lk%Wf~Iۊ ,HǏ?7o#os4|380"=ozwr_:$cl6V[3EO>ݻc?Bo''P]Z>) 2V[1U#(Aٱg7`8@wu2 q8Nf̼J@"ځ6Ʉ Ӵ$]:Tuk;+Etaq{dIGX*D-\A\U-z-%gЅ]^^㗥 (b'x\E%xհ_m4CG)jJV*iu*o!+dBŗP@VjYjbQy7iET!8 0û/`ї9m*-)w|efW,ޢSTǪ m/i X}KvXG*ZI^n1Xq3"{a6w/8a쟹C9sBMRE]U"8 M+]4U2*@aI4!2$>Rh$w.F᜷ )=lMeᇌ2;˼Ȱ`4v&lokLX;x9 yǐ-t xUUZ%V0+c{)E0s_,tNxǜȀ3rK7}ѭ.r79AQ՘-7$BC5tսHu.s1ءkGQ\dt1ѣcNƏ(^ea@bȒHPYٰt tN9U.N1R7T,J&V0'Ŕ(p=.2猨b,i(mϾVgIx&YFʻG%#d4C6W]V 4R<_T9]Q-C]P(3Ya/vY@XW(k qPG fz'goz 37]Wh ڂY2Aߌw oc2{Η!!:"``Z;0Ɛ Wa?~@@ὺ ^>8_J2~ip7.]~[l}Zkl'3OeQ4LMӂCΓ&9MVX8H8#دF,f. NNwJݮ?0;~iF`N m.W2UjF*IUsvws?AXv[hzu%WiWMpE[n^ÄwL̑JQO_n 1@|\!\际{?g#HDmY W6D4HO|CЯDɊ4$i&I|j]z]R'6[]% 'U>CV{e@endstream endobj 944 0 obj 1528 endobj 948 0 obj <> stream xmKo0{te7;qDC.z02=JtV@AofgGo@ .:]@{> stream x}XrH}W`TYR7vb8V&;5Ւz‹‹5گIӗl\et88@;^@>sߓlO1 -Fs`蹀l2 -]5Dbx>f!}Y<,͗koCg9G4w/heny{yH(> 1}MiyzpGX짡7Es 6goJSڗŶ[J|p2IlUEfP31qݔϋ,+r՞= C;DDoâpmֈ6yr g8q^G)ʦ>zDqE6ۧ&;4-.ΣD:x8c+ W36eI~4fsܱhclrіudMy”>Vɐ][~dрW bNzmbm667Z ijbĚPUt+9q-E'$љ?vsF@= FӉ"oOZytJϨN:~kC^PՀj1egr@뎔EQbG/n.]|_KX*LIהoʸ{ 3gWHsg[驍WruTs/y4us)+wI!GS:T'ӧ#0^V/S>4)lp58^r{@?Ԧe맾|t1quk+qv F<)#W]ɪf/ ,"* FQwA)PױP[:75 ݺ'Q 7ْm:'@Wѯ9o?endstream endobj 954 0 obj 2165 endobj 958 0 obj <> stream xXn8}Wn_@E$ۺ>EYRE*NloglnAΜ9a~0;L~٭8d|N`-9 [l&_߱bv|~`or>G܉b5^gkLn7sFYdՊ]u3xw fȜrxv2k-*{X*tj:q'N ȞI *t+bfe^ ;d0} ]C)U÷wj 0x5*zC>mEJ"u;/Cx\S3Y ^i&'6e'˕bYd%&6~\4n1UFXx<:tZ0ԢULx[f|dYӈj%ۃ,=o39C._&p/[Bn^@2qKdcᗲJuX̀˲S~w%J9\Ƚ\1Y[!}_$g@i͠ xhZDjL?6b5 (up|6%0ܥ}/ 7xP?Rm>+;lR"WĬg/UJ -:gs.|5ԕ\Z+tV?l'0p1v]Yk8Ƙ ހ/1J< ܵamU>6%aF7!ngnDѨӱR_L@!?:niN >" {YwjeY5;Y8lAqgn6/f_ SP0b:oIΠ Dijqu=_ 4uv19zPJ CASCOAJ zִ5K21ٰh pVdwB`Ì\֐U'̚fS;M{/vL@L{Jy0F7 @ 6BQ$gѰ؍zˏW6Z/!Y7bl)Uslr(gEם+\m 7]$=Aq4ϜS^GTAh>vb=;*=YhC~OP*[͘$Nm݂0RkIr{f =xᄰ_l^lϘGQp$yHr`O1>zO!( mp!P.8/@[zɠϤ9f;wbG;[ F#{n >ӱ Evb} t) ha)7RdHR>'_w0W@ IB.P(@4 ?VviPC<5$mJݓvUd [lVbͰLjN!T QDA (sǧ؜9ӳă΃qn'f J&5ͪ݀:+Ž('K@bH =؀4 >uP>4)qWjޔ[l_ط,SC`=Xh ?.endstream endobj 959 0 obj 1687 endobj 963 0 obj <> stream xWnF}ẈH[.ISd\4( AR+yYK1/ҶיH.,mqv̙31e79$|pkW/ 4*E=q8d0O SXtOb%7kqRyjr_./Ws2yY,/r{4CLmSFb@1puʎ@ q:g)|ɜf:i-m5~DZC ,vl[$A%g,M*[ͯ =A-NIQ)};6uzN6X-v}o`WJ+ĸ'PW^VcށaԈXɡ_ݫ(G;,#piͷmb[ˮ}g  +DDKkƮn4 PѢLXL>\xendstream endobj 964 0 obj 1362 endobj 968 0 obj <> stream xXv6+pF(7ݕz\; -Ėe>?'u)$'ɱesĢXe'ۀlE~|K 2C I m(sI\L^-^]kr<.G㿔 6\Q3q:[AX#pFdxsP7O]DzB2cF6&d j%zvg:C6u^f'x>y.R֙ܪ'(x&S (l0.fnj߲Ui+;꜎2<OE="e> <['ON TP\_quKWyJ€ӅE:<JA$H&> FYV6<ׯpigC=XRZLE\B|iB(941r#[5@G´wj ,3:'g-yA!? 5މL0{Q% .,tbdGjB IJGhRB.I{uNh 1XCF3csCMd`g*Ar>yR)62ޝ~7:!Hkոx lh]@QZaqZܪPӉ=&!AVWb_Z 5&ϊ e(|۱plz^j˒i,pZ bUęY t%#kk~K#2*q0[n'R8JGJ9{w2miHgP ؍8("i$+@4i#^8!?Z , h &B}8Dh =zQ' N]]AdQ!s=,Cve b<4BApf+a9i Ԣ5=Ea-_!e#}b4yiLڞ5bw$u[Ue΍ܷe\9b^}=x0v޾PYjji9;;m,SA'`C RCc")"B,{jfVţ BfMZssQ?-l^<>$>1vpC6gÕי3jڙkVSΚG}jV)GhJ~_S6eUWPQɎS{ؕ$ ȁZosz#u5qY(l$wh=qm3H gjԊ6K?,e \,=5VX~T]_/a$!;0m54He/x1{u9_|r$ǿ7<IJ^Ŀ]ooE`sʑ;3r>^}"LL5?,?e>oendstream endobj 969 0 obj 1873 endobj 973 0 obj <> stream xXnE}($O{GaFr$?SI/v_ĭo(A$k9sL#i1m~W3" #-+X_GPH"?Gb6C":$QWY^Ы_N:"b‹BD~Kb/ECygN_}Zf͢+';AC6{*- ^ҖWftSдE ?/N߼ 3g5)1niMS.Ǘ|":yWx-Ʊ<`-\Gb>f6_>0Te<i<+1Й -7S&؉bZ )Np\NcN!v 4]UEAUZm7)-pG ; .\.N<$x=U5b}լiM_l.ߠgT0R#K<:BX^&Niahfn}rC(yZԴ`@M K+:b vK[kZ*\.[2l#A()Y5kz/E8egcUI4Йil hiXڠ-͎ 4qX!gJC)ycXyz8 @1 *MšL9}Rq&# bǞqbĢ,4M^g(a'(iaBTYM% p\KBKק*0[;[^A5kVQ Ѭ $&8#DP@{<wt?\6!Ӌ˥JZ6 O1BMI<8 $b$!tpDJ=XWF`W+!՞=&Oݗ*7k?Tr@OB!PSOb5U穩18O1&B!L3giI:$^Qf7"8ik.hjd7[ukKѻwzkm  >O6oY#0)ۉy};M4hó ~Ce{&Y6Ԍ6-Z17zKTtqHRӪ$p„ nashU洞Դ9udFOpZ;j~Q u ~U0UB0 `Gb7 ]#8X4]k5yQ0eRᮮ )/ ytQUdbt HJO5-}&Mpvy+zrN<=Ġ;ڡx cU =Fk R߱r{==?_2qwo&PsԷȼ`I>њp嫧pH yW`:gC_їݓ+dצr0zYS2sMkN}P)H@=Y2>R2F9J<2qpZMt̏}^)q{C P`g9Yn8UWJVΓ@Zϼlf$X D_HoгK"E V2 xW_(ꝉR*WvP)$Nʫ!]ѾMHz#-8+6IdxXrѤH38,1{NwCl[s VJ֞ X0}endstream endobj 974 0 obj 1989 endobj 978 0 obj <> stream xXێF}W=Fl6~$F s$jٔ 7Tw%XY,:U]UY ^mg9ezo~q&~,c^, y("b?bo-|ëFdBF$Yg7?,GG93 O<3G=%;<Dh z5횝SZàae͈ͅiVF`el+vlYaT/4,@:]Zʚ\>Jqƀ3۔XyL5g 5+HꊣND]61WXIh-tձeq_֚=|3!JaAr2_{řL #>‘Ū$П2qs[S™[8΀qB8IӭQ`U5r >gHPLKĕ CֲكT eWC!i>yH3~b=*"e";T˪@5Sui\\h czWʍIS',؞ u,t4A˪"V78kg<##CeV2?GFEh zK$о&i%#D20.`:dn etNcU2}z|G"ދM  =}A<=SQރB?O{̥U}-pDi³ ɶˏ)f)}X6ڂ/8l#co/W)q\al$_vZ#6MK&SU?7 /B6"q}-\GaY]@\Q_5]UIӇSDVrMƤ#qhݍ# $ $⸏ 疫p/Jc:&@'"D[i5B G_l]]}yD4(ᕦkwt;y  I$&|cCy4!F Rlf%ٟ !Ke3>Є<NC; BI_KxBJ"ĈM@\<˒@+KF_PL_^(*#wrz:F>Sq!S}u9y&V`>!\J޽2d)z-J \ cJi恛R}XQk-&H:|e~$ < `T=|E~hn'$h0ưa޴% ѐ{ߪnuN)=P0{n `XN+hkQA#dmY 8lqO JU;,P%+ךgk=":gi:Ն۴I ]Sm"cVKRجlj[u`'J@e;n)bruKMBafԷU݀P4j%M4 XvCdB-|Dݞ_6uumjo.X{0mu2`w*ؽ<,uGgIZX6{C+fKE﵋dūX<SI,vάީB߲+@@A؛'reendstream endobj 979 0 obj 2050 endobj 983 0 obj <> stream xXn8}W[wXhb@)B:X)Wm$6ЬuI@: P]E%eѻ2҉I_aZa}j*[ 1IgrL`:i@bU*ڲF5Gq0ax.x\#*sCd`y})etĴ88F35c9dM- Sv8paýxy>sL4ԧY?@U.,ɕ<W {Hk/+ 4>i S}UֵC>[ddSԝȫn0wW3M7 &Kv3VȰw2Pc)5}wu$Aw5~Я ҩN)S8T2QjeH[*@fZo}h` */gp<?b=,4azDvSn75*DiݿH'Q3 {>A " Y<6&ҩR?q]#;(t"2Ԑ D$WlSn""q&lZL lQC[l;tc^:^L<[۳_G!KD# PDaehϤ&];{f,YfI{}s*j9#)49!堶 kmn{ޠG"4 Nd@\1ty& ۍFCzv-(~{\]yxٳ -0 Kc`|IְL`+>geia[GXo.?G4bW> å]lK?/~Pޯ?H;ܖj}ml_e[+Aji߱kš,i?yN LwLlof̾ Re P Lf OgyNlW^endstream endobj 984 0 obj 1753 endobj 988 0 obj <> stream xXێ}WV²3=ћLb kac.R7I9՗+9@X,˩Sj`ؿy ;t+o+0'7X6&X%aE6~}ݬ??3Wm6a# bVwA1&H~gA#e?8oKu^1\B5N&89#AēȆt5{&˒5_Uޛ=u^vE}`Eߩrl$RmoOvEx>Vy@>*+&αzYJh⢻1OyOmݱϬFt&3Z^?6E7DTUjO3i~ṛ8+a? Y;u09v_I@Z]OU*Kܖuj۔WȲLZf D֩'}̸y۩<=+k,'dݝ]#R9Ы=t,ovjInWXLdVzy|, x,3lпޘ^XxoJ O{SǻRV۝Lf9H RT~5ԧMݙ:K_X]nVR3yu_/"^Ȑo0h#SVI:@5fH 9FPɸUjxi(xNU Cdє̾)f#RV-{Ta cZD$fюmēE!3v [c(azOiz4 Zu(Z&f84*ya[Ɠʋ} qz"^¡A5hXr "j]=𽟟6]j*c_[?Xy4/v̜a,2n7pAsw YQبu5QњQvQ V (ͮctޡc7M^5k|)KrmEI}5{g 6OO'sTS(;Hztp.#r1r/Ј"?b^1a3d}a};Jszgl+M2zu[ ⁇I!j:CCx,H)djoOuNDmST2ok$- A:7tKB0i Z'[Eg=Lb  _o!K</lu"@nE8UJ-h2 [(XA,n1{i9hD*h',Kؑh|%QT|PbFQMkҘ(:1'7O^Ov Y-n@:HXh!\#(@?Qq(5P|6Eu7D77;  kL,6A؛e B48S#,9 HoV͑endstream endobj 989 0 obj 1891 endobj 993 0 obj <> stream xWێF }W𥈓V]GyKX`$S,nd%~RɑFlba^Cl=ͮ aSl_ٗWо%;uFc5~qmxWY 2v#/V}~?^ꦱs(NYFBy(d\BE^Xy]ꅎXb\vPIPCY2ޙ(!TEs!(!xs\kqxe۫Hl,`K_Ae/Si}uo ɳtm@f,:xIR{wGqd8rԯpDYDq4bj̃ %R[F3bG۶Ƴ-8d Mc7@+(}T+^s'bINKzxp:| ~U ٤$kS 1j-ʒŒ7j79?{춘C^ˡg[QDZupLШ7U0Eiq\rȜ|z?Q@ 0Gthu֔BVu{c;O]H Z&.^4D_4j;Ċ%7d\iڎ̈́́ܰTa|`QOH! wU[b:0ʳqf1?O>M?h'5DPӊ]r!\Wnl8#5D;Luj}D}(b@RgҚufJ!f:ՍqA=0T6Q3c8\dBIvvRݜ2n4SumZcbE] ˤ)>.Kᓺل@+yj?ѭz1{9endstream endobj 994 0 obj 1512 endobj 998 0 obj <> stream xWn8}W[`Ŋ(}kEAo1 }mu+Y$7_:]]'0;p p6`O=F/?LG6fDs(Qpߕ0Fn>.X?]]\p1@e,Fj0a(6Vid1H&En;oqSqJgϻpD%'KEEEIH\~8\$ȶt MW * 2-ʈIi8hVɾY PĪv"0Sx4O'6 vur11m~]3;Q$yy}ń"Lk4{&,,¡BX AR35'J%}fqqf Qr9qs ``=ԇ.` (CKP!(Ȃ.T=,t"mǪy|mg'ܯE ڢeL{\x 1ZXh^%2ɠUULΞU{c;lg2G15F)^NSaEfm1Ĉ0/R>`DtӡcxH}PyۤHjn W-A2Z TzDX.p UAuB VmaڮӛŋmuϤj nY )\аci w7Ǟ-;d*8TӞpo0ՁWgɰi j}Or[Tُ<:ܗ5J te>tu o1^h$]‡G@ * ӡ"Cn #0M|l/{dآ=gO1+cx3q\Zŀ$bPm8YMZ |տnaS8 2E;/ǫ)Q[PM[t+ 1  c\ -=8yeo@7jU>XLi>֠'xG;gK'n;N}Ia_AI&O35{Q =W&gd?> stream xWێ6}W^fċH1o[(l$<}mq-I/IRzAP 33g80AT߫xD|o;9LHiU~2o&A`$Wp4'wV#u``?_Oox~흵b,gWt$VL)Y+pWF`L#Իdr]pL ^ܸ0Qg}J1 /s1=G.Y>0 R*[ x>RDqU=mk+sQ<.9`ZέB(|&()$CizIKo g)> W >q&4nk?x4\a%ENe"73/nNG1 B ya{Ϭœy^pQ+:mWrtXUU3摁Ԩ7b#J{tm{ :IevQATܿs} S)\Ф4V'A#R Upˋ\0aM%/֑uR ,|*}XU1V#smF>K}ta ޑ9 Hc]eY:gC@<towT0̔;n1Y0V/%P; \`RsBfHRz.-űϮ=*_8*uw1]kHYa m>ҘB8(p»DYSg( }*K=#\bF.Gݭz__ٕqt&bhJ0<7ci˵uNz>%BfTca4ݰLO3]VS7Ucӭ ]cZ[weёinx'ڳd=\ >y?0Dͼ|êQ5.2S1^nWb$ eu%Β > |:1K:r4}ђ9Kl/mVKŤX;jbɭǟr̡v\&5T`!v9tW3k@̿'9+endstream endobj 1004 0 obj 1171 endobj 1008 0 obj <> stream xW]O0}ϯoi5Gb{ou4iP -ڤJ~ҮS$NS ͹sހO(e?/GΉ3ލG `?.G& 7 Q &T@4ZO!}|G'èv3O91!qtSiMm0*;]vgY`6@jlJdP?vl͢&\]8=8w`06DZϲ8`Ty 0yLd1'$táupbː>+SMc~1W{X$n'{%@n39]wx[:VL/ӚqhFfyQ,/WJx1&(-uI6{e6H(gob"2*,p&z3Vz<L7wxIvqpS^w5V9_\qBv5qb4v?X&k:0]ܺ:4+W.{%32o8Ar^:iDQ/;N3t\)BO]b Vv !PY'wbpB-YӫA+_9|boJa҉A, 촕Xp6-\![-T%]>]Ѕ+Rƚ9$`!k3J4tO;s+bU/+."*y7hP5>qWնTһxXyOum$>N}_Գendstream endobj 1009 0 obj 894 endobj 1013 0 obj <> stream x͗n8sWI/S`w-F]`QBhW[neMy%u%JQ&. 0` oB0S.o^^H?Wa1" DAf,Y_iYc*9So7..cxy+0MClPn?B2B t0g*ƻ h} *>ji"6 ConԲ=,,(u:*9AUNmaVdLaPCޗN"C r(=r?L8o& ̳}q-6$DGx: ䷰:ܹAFĽ▕5*Kqki;1p|ξd#,@KL4-':0v|W#?&#}p.[}BfvJ^n13ה9٭f(T1v#=HGt4qҌ!(^L&QB'!ڏOO ۥU? ;zR|l R 7[XK*_`Pa٫Ne~`~)+ {c>endstream endobj 1014 0 obj 955 endobj 1018 0 obj <> stream xXMs6WqfBߒIǓ sIR+6IO % )VlK6-Ppի}O׳?pS\ ofw3@MA"3BH' ^|9~~K]|+ /㿚sx74q6;HNRA(2:ӡkC ]2mi$^ ڀ. =&O/8x+ ˖f9 돐@E ievu&Er >tyK:(D>qH <:(*6;=BTV˪Ȥɥb#T]/$zb|ܣ[;؃G6=q)MW8lWMU1VVB C&] 16?9ƃ- -eRK\7kHNaUUDaC]5JX_/s2?m,ڥG"[G "8y~]hl 1D' Wr-s5)e NR~e%r8ݔb-9%~߀1zW6ĭB=\YU`%{'cj8AsO3qQPE.7U3W$s:Y妴 pcٵ\_YO8CsKp;r' GN^ ˘KY/2mlǔH>ԻԨftO8WOu(hAϗxIȠc0]ҤzɱU-m-xoLt1M^|oV29O6JS}nl+GT2װ2/L[rvDopWuR s=&UUΤY[V[FG߾Ym?ĭtx.%endstream endobj 1019 0 obj 1076 endobj 1023 0 obj <> stream xXێ6}Wq żm PyPeVkQ^It)QJzva639 G8Ц9gxof3 Pg%q2~SPŴq!,0[wIу9vo7W_-7#'VME'\h+(OWzGG5ZXB~s߲Ȁ=%JQ8!̹a^]C AiU#SP) ޣUCa0JǮNxPȽ5wi^XzaOωg.l6#-Y7GJ_DE`O'x {endstream endobj 1024 0 obj 1182 endobj 1028 0 obj <> stream xXmo6_q9]!Cv0 hǛ-9zIٟ4BJE wܝ|W?`[,U|xI!!DE!$(e?.?;o.~Vo_^.^:x!$p)F/ad|Ƿ0ZDVyJfE( h.*O 嵀./JGoHˢơ $D؀1zY˹s}D6qj`\-UyY4!l뇈y'N_} eSFY!"^s~aT:azCÏ^^},JT41T5EѝNC>k`sߏ|> I*;ڏ/gTi\ *EQnȻeV8(}ƆoC#2s쌍,~ F 'Fx]/x|V eeF:J+Q@},0e? #K)0O9Lp 9YJ43"I*/0k$;D ψ)>{> stream xWn6}WS YԍR@[H[AD]Yr$9ir?$%ZI_lEahfxfp<;̾%fO};a%WB,׳NCg-?t,) P e6˛%|U'G1`,%FQ+ռIu>e&Eqټț_0Kǯ^khL>a߯.o?꧝"{Ps C{!j֐:2n`\0 LKC"=҃4'6 "1'6KI㰮1zVWDUVj!$װfIڰWS#sZU<9EP?GgT,|sqy( :H_y"oz/@LZ^Mc2'Q`14-h#N&N9RfWbM_ؕ2^[,%Q똡Y/Zv눘0mDƢ,;CddHJ͇n=.J @42`+tE]u|OVb>%bmQ1QB`˺6}O4YH0yNK*:C0mZڤ֍U'~w(u"8*]ze^6-τ+g};&i;YD2jiH&tNj óK `>野 CX`,Ʀ Y H T(.JWz.0KZ&MCTG[0#zxBV}]ZUl<dR) 3$/ܴ>bZUx65O\6;E1:ƾ[)/ӕQ90D ny:u<6fy#h}YwؽI$<܍{I-H,pK~2yVAWN6E$v' B'\. |g&;`(8thԢsOl5Y?6(6n67f<)"+a~nbt]eٞ6Tjn*(t5 oSAH%;1T?,goAendstream endobj 1034 0 obj 1122 endobj 1038 0 obj <> stream x՘R0~ -aVeR3 ֱ!6myKGɡ\d>\O;xoO"4.}ػHڟDk^#HR,Q&o;w}/':H_x;ǃqf!DL:gVL:tT7ӼDwM,#m0pc|&Y>IGLPjeZ(-"{c%%ZdԾ|VJqht;-+OA>y24gO(rڀ 9UFӽ3[$XHP(`M#Ɩ0_=gV"LMtz)-)~ƌprF=U~7s)7VSHX-裃V9\19daPXl%eiY9\'r\|#7(IrD@W"(RQ9Q.S") ;:B6Y[O 2D!d6e I"+/i܅8\9 CAwGI;XB`)vna w:BCg{嘇,P' Lekgu, +X¨7&2Zgn磳~l> stream x]O0+%H;4MH Ҧu۰&ā_O8mceeToߓ5X%(1~aZ|SJcPG810xabDSRRlSЇccY*c4tx+F(FWJ Wy+u<vvpt6- &'mfbm{3Gg'zL`]ˍIEPMKc@|@XQY <SwyYk!s<-ྕ#^Y:x漉%fNo :l}];uLoサkJl y>$ZDZ),  X jp(EKV' %^)ϑ6V^rQ| &e:⢙D?KE:< 5ic \e#?4e2d9lg|Qg⨧9d"+5G4lG6b7bOdJQ<}SÅ[e!أ˯s7_`ExJ -r:5~Tendstream endobj 1044 0 obj 898 endobj 1048 0 obj <> stream xn7 Dao$5 F@ Em׻.e%yJ?R{Ёvj([;g8 99}w փ|@}ɋ4Q$(Q I*Hz=8yӗW=8Nn$P5II'7!TD0Br;!O@s[iV3ƀ)|j{eHh*bKbMm7RԺ]TEMn[IN;M@WvۡwOMwYM|i 1x +QZf$R 0kg]yYsb!ugpq܇ _ Dŋ6/!=N ^`x{::ٍJJ܏7SE)!fUݘIJSZPfp<&QTR1<􈊀mdL;DA@ݐf0XCい; 8‹PB)A< 6JH=ú$ݹ|˻Px> Iq*& T,AjAc-˨tKFi꼙J$fQ`8HojS8J|N/~|~M׮͸,&nM|1HFDޞ<`A6Ƅ\?8Z?5Yf_4Y9x#Gfp7Ј#˿"7 YyY*s]j1?;w]f;Bt+z Y¿9勑5E/e]!a gMfŔ'n)%^3 H3uʴLm{8j1T K,9m$&ڍqfxaYsWۼȄtڗɥ>hX4_]i?y2UYS ܎4ϿI9endstream endobj 1049 0 obj 989 endobj 1053 0 obj <> stream xݘo6WmPq%J[ ChaشARIv$Kd7 Eψ`~к+''@=yaT(3@Cֈr1ӎ`|H?[N vU5SDC=. UhgDr> Vdڠ7U¾~1vV 1f2O悩~xs}yuz(99xQ*U1N:.rzwo'Tn4Ju.l"EitQYZ8{X)wߙ;_b5]'pxYl|qGcRbkatKM0C('G٫Is ,A<H`vreYi/vUA7O?8aLe[^{+P0q'sLPʨ;Ǥf`@@u#;:aX . +xxuP,8+l:XP1st\\yj"KU G[q1 4uVE!5&%Q".fT)SPHns*Xd4ړmםЉ^ݴwʲ\f6:?)1LބF;,YEr(#2`ϧ)2jl3C_ *37 8 1ųpN(sB %1͏M1 F2C=a gMuԬ`C)\Nj#e>]Dď/#K% W'шמ'%׬ʰ}pjF[aJ\QZ/k·ͥrij`f)&TBwr])=~B0JtǯH:ɭ͟wQ>"/z+T\leÑm> stream xXr6}W-NDoIqDL$v(r.@Aʖ%u!={`վɻ/ -ˉ~}qbL#(8Bh}u9z>}zzRN&&=L瓳b)uI7!5BVuU+EZK/Tw,$c鬁%ab,ݜ-RYfOہ~i,Iy8$sNi>yk&վiqqc<7m6eɏ(.<)ZY\b  l7c–L!pO&Vq]ɽ|?/o-"8QOcQZ:$u6H=5V2`%"^)جʈ꩔鱜C%k2:0LE!AlVRVȰ IQ0; $Zԓz5#r\*&"l*ֳs^C(h-Jg~AԘ=ruex׃*G3E,@ӹN3w*^ ;1 7 _Nbbv z.îoWqN)N7M} A2w=3jh!91@|3,>ƾ )OJ l"?Hӱl=566l=nZ $} 4oaPn]t٭IAROY& `ٵBiHm˒t{O+l_d^n>@: +WI:*&p_('26t'k4{E䅾C {%T:&=.y];U_M%tnmTەC|7 5ϑ7iى(DVIiS6Ta80Ur_ "-WX'lreZ/{9a<5=eE_]ԥmޫ;l  >DPav @[*+Fa(**H -ccJVƑ0_Fn̠=3dy;cߵZ];:0[E"f߁d=.~<ITHA>!z/ } S]0|!qwn2iMN%,fUh- `x\ۜ4S cd ɟ\gendstream endobj 1059 0 obj 1405 endobj 1063 0 obj <> stream xXn6+SԬHR-L)PmVGGfr>$K̢<{#r0A>?.F ףPHS9GO0E1q4Z"Ыzw63hnwo>"B u(l#vC*/(*PHmDD([?/Xl$cȴo7j֜W0+$tOR2.$ףdGJHtl2Q">|ʳ}y*>~صr66{=]2*]"Fs"uQyO(yGr_rK;Nnw\QnLCᅥ{1L߈a1m`&0RMʾhS+ߤry *^\~wm273O"<5xa Hh%!t+hj̮Tnn6nNVsCY*u>Wg+L.]TM&+$Z%3$^Yt'%JAoPRkl+ZQ`g"RFFEenWVJڥr3'=m(q"Mu O6Yd}腨V^ICv, > stream xXݒ6SޙZE ԻI҄t& l˄C}} 6?]o;c9 Gu􁣸9Wxǣ\k:!FcFޢwN} oZ *@'pjh>%EA(0(ZإF5/ţ5H\_ue)3QVf.,~RܶuS{|TQeZZnNyLbcJ1Ub^%!2ɳٸ]*Gr(/DriY0itLY;`ZE_'4*;T/ll n,Մcxd8M?WnE1',ǹJ+dB*Ɨ".£{ vFR6y%PEQ&@"U[Q _4)+՟]<&qYw'hyEd='&VU,1!xKG->TѾUUyȘQ|∦n*MJJatkB=voavΘT!vjѡP#Ky=3\l`DȬJ:q XS`Y%E -6Z>o#Tf ,VLO";m燠ޜD 腡NxAT*¨|ǜ86{M =l6#1؂:3_ǜٝF6ȍt9ޙyNX8v:vc&[T-Gv|EGGQSf>w;&kj;A/8s3O%paa+ȷr"_.͔|fuX*v?K]^?uNms6-)*:=6d~kVG:?endstream endobj 1069 0 obj 1053 endobj 1073 0 obj <> stream xXr6}WQє(GwɌIj!5*$eOxKh<`w]3r1Ann_m˙(ߒm Bb5zE{ -w{s7t\ ,4l,џW>^]7r>AԒu|bȋF4hƤؕ[ːObUxa{4fv) Ik[#RV q$s$yQLx8C|cVd^C;Qu˪Hֶh L$Ʈm:섬/CKE%TPr{/XR+,3#@SD~2Q}GnhB҅[3L;W Crt&S>C|j& c\J~=^DbDr'\VCGxqbn<Y5%[̃vo B>N5Q|x/+yC:J(SߡGhW5 ۑ͈.~vM2[< صt)]u|=ZQ["f BiKD@=ň<x02럣NtP(f hkYaM}oL~҉qH(&8``Y&Hr^_endstream endobj 1074 0 obj 1196 endobj 1078 0 obj <> stream xXr0}W)Œ|o S-0L"b| S/$V5qN鴝4ju`#zyiwоLSxRj18;aj>>wۣw+0:`h{&Yhn"0fbmX( hQNT6ؕ$R1떛tX(\!Y;`b.m7K˾:%l+Z4u6<APi$:|!xަE!'yv\xC==2pܓѓr6[ FAd?͈Dui %d*0MH.owNy=nZѴڤ옙%ܔ_w?z"uCߦܒ6nD?{DKWE06j)lfgvt{"c0aaG>k؋<ݏtl? n2x_GEfF%وa2BzZg ? m u yM{r! !au܌6-+%ocXYT̠~L^0Y-Uendstream endobj 1079 0 obj 917 endobj 1083 0 obj <> stream xV]o0}W1O?v4Uv!e#g'\iM ( {?~"Dڃ~) "^xCF$KeQuSG" tlﭵٵ~^ܜ8DҰ\$q넂U1{ ʪqȷ8DBr8B$8M lCGE"2mҎC .V;T"F4LLv6%-G7ARh'x~v}yN I(%@7*]т)+gcC,Q1(eV4K"u)3z}m8_ {=<#r 9W$AdE$Ϗ;$Xiy+qX;.8$y> stream xXmo6_q5CRD]fˆAb ~P`K$7ɿOQ/DYv`C 0l^xG^% >g+k̡'/kxH̝RDB)<ѷoGtӓ,S@s>\8BAe36GT7x:*wz麕&}{ZZ"Uז(.--y.mO_@T!.\~컍1cjB s-Y~GIL #\⻔bM1,Y]s 0!̅s"(BvҀ pN`/t k $u"oXQ0Ve& ujB2tE ؏u:_qV^01WmX+ɑ1BE YW}bĸĪUˇKvPfz5&E~a֓P{3H"`rS#~A8A:L\^n!OUr^PNEԎ}m¥Du<_&a !G@-رp8 (UwX<]oޤK:RWtG|ď.^4ILpl0at8nqvp8 &38f]Zn@&N\g9̓:X=5k,uPzhLkQ-6皸APMjROGG/%o1VAzR-R:})߽RAw̺l94OmmM#78]|Lϒb^o"6k̨ ”RdI<*]AKBHGa"on=O%?]늒颌F_أ GMi8K u<ˣ$93Z&0q뗶Os`Ťy!bv2x]{'5UrB[FY1 eٕ({74vesYߕNCËcУ$ϑ'Gϖ,McXr2q8n%(J0twE̪^[ ph~ ,"g@Xhreˌ,!d920L/x!N(̫Sl| &endstream endobj 1089 0 obj 1220 endobj 1093 0 obj <> stream xXrF+Sq2 覤ҩ"@r@"&?=HQRD.-\u0~\$* 0+"g(ȩxp]E  W8 NfX %l.z7wcFp,2c%T`r]nOP5nJ"*NmjrntqVFkEXd,Ur.\}@)"]O焐%>>iT9QD\C €3A|LsRr(/&ӷSr1˻РY M\db8`Rx9F{g99F>%ѥ)KB|< ɋҎ@lW9&U H$?7 8Ef`Bw̫ t:,)+2M 0|ͽΨȄ7N ! ?hL}A"fkjv1H[x$`E7Fg 1QxM\G@s]_P٬sEQs<2qYG{`غ;%K}o䷲`VđpQE69X.:ݩOU0WCZ{D)~9Hرz`8D^ +m=/%3q0 ̳rmYTa~3;倃m;qg9Rqj6C0<qeKX퓼iL;rVR/C33?916:*Ӓ1 eϓUib%tw; Qyc 93DeE-'9Q>wG9W;2PSTgz'͓O7Op2pf[2Ռcn02̗ #pB!?Xendstream endobj 1094 0 obj 1210 endobj 1098 0 obj <> stream xݘn6ZlOd k}1 ɅknFr$yiy"-4(Ra>:|}G:>ArB\M'@ BF Me)JToW:޾}fz2_NS@N!8DBbrnJ#z"D\&( \: suURA U97W&>a81oLtV"+Ց-ʗ4qT"h¬"6L"4â椻\bIm~͊Kk,.xYd•Kf ?ɚX)vX`.$><[bX(y1~[pSf}?-:FG Ga]ul.x1ϳSdlQ11|ik@/eZ/=X(w8#/6EbvMK/%1_ k{w2̞\b kp6#lBh1ӽgw9a6{dքmq^B7rǍЛ\S;칂c{:gU@Ųeq,-c쭜ڵ$1܈ woOs|C >LbB „8֍jlxcti\xwq[ꓧu2CͩeJsG|oS; h6 .bE3`os_B:u̘w҄DGC-d{C ^XA_j$Nxcd:u>&endstream endobj 1099 0 obj 1125 endobj 1103 0 obj <> stream xn6:zV'to>x܀o;b<(Q*n08Qdgnc% 7o>_/?_vJ4qJ oq=L$?/+UC q`(r+|^n_4&IFiO6@r_.>\}:5Q#ƲЊ\2(c\Q(j=zkR :6|n8,'MKLv<6̓Q38:rŠ+"󯏉_#peaJ"tR3WvfmcTo ;TPSs5qT\k&4ZRu)]2."aX|C*c01D,c4;Iv v$ 87ղ'AX]2lIw c42/6dq{ƅjA۳Ng߮v2\2ÒO'| 7endstream endobj 1104 0 obj 1189 endobj 1108 0 obj <> stream xWێ6}W[@R 6X$i"<(2m3ؕY|RHJ%Jvf7m@˙9G#`DO_{a0> stream xn:)|ۉRB*bެQK_Gq'Y]ЪǞ5'rw/]-1ͿYi#^=Xm<(Cb1N2&dKGf@k(:T0-9_ &lد}5K>:* i*Ȋ8R+cD0X4\Ά{6qW猣c#<⨲Q'k}uV<$m\wօ^YYjl:I  o:=,JYU܋.P7ΝsPغu4Ń,Bȕ$qi+eɭ^=Sm,H, lD<+muUk(}72SguP;O6\yi!f+ƔaNT6ؕC{0Y}|=QFXПiP;l1M3p!!;:+_,vg$OBWcã㙺ܽx:cF,>"ЌKLuoWKB0endstream endobj 1114 0 obj 1016 endobj 1118 0 obj <> stream xo6W`bEJľ[6d54v8R"QM2ҎRlg">w$u ._LWCX~ƿvB+hH@դF!b$0N>{ o./?̜g8^@(qt3[NF΄8^H'4k[6~H\cS;}OxyVp˥Jb-AR~o8ae͈Tm#ukߩB>0ȴ| I\TӥBSR wJ_IsUd)4*K RQ(jjz#A,)R~jZkB:7;4Yc Ҧh0AZQͺTPaZfm&^S _4b~fE4QiÛGμp}bx٣Nɡ%߱gB7$E)/XEX8$jB N{C4(%0.*.7Atڤ]ì^:)9i@=xSJmdl+(yᄇ> stream xX[o6~VX22Ȳvq uvɒ+u؟CRԅ9;#1Ak?W_3Xmћ1b=3zS -l%-*E8A~W{q@?]?4rA(IZc9_Y2!mEn6~W;@(Y+<0upR./XNL3*xiPFZ Qw5lFT%KQnk8Px$s . fl8RR\J@zVdTf_ cANJ )38o8-@Yi/Fr9r~HdSl PYHwNd&amCGIz\4hOz3'0MR~r#"Qt<$~`9c qo=p 8P!pMN( yFh`վ]Beh}XrNj.1NOG  eZ0)< -41jG﫰Puvi $쉢Fu >(/v ӌptL`+p>M N!t4^nLph,UVU=Q]VgBD}[;45_5j*uU ?w!i2ok,{Ah81uf.N)WS)e(Fg*}ϡY e 7P!J `Ԏ/F9)Cǰ1`=)gDUQ{s GrPf9;4gP:QU۫Lv̊:ȶJBUU"=+)v_4bWp}S0@Bӱ<\_-qB4㯪\:82Tc%TgfB$0zZ\WwQY aڲ‰)ȅQ[@}֮僰KDP^x&grF0 IVۗthPW RH -rṫ턅:ۉuUW@0&tE ie Ŏ#I2,0 Uڱ)UaFZ26r*J5o@=y(bM;rd֩WMli'|KXZo iJWM(yϿOUQI>mo}+xK $qCMw_c?)_6N8_~ts5K(7@IFae~&kxFOWii?oܺ7'~\_}endstream endobj 1124 0 obj 1414 endobj 1128 0 obj <> stream xXn8}W}iX\o6"-.@rڒKe?i7Y'EHbgfΜ;1Ag~fol&>/''D #[W30b(E|#(8EI0 l=9tq~z}37H~q:\O1-&'R J"mD,UFֶ!5Ģmx{x1&O?γ1@nD}U5y:1%ӟ6ipƷ 4!P5rB($&?E"RdmU9x=$f̉;?P{-BU~/#ã3F1fQȦ.Fk4ExYV-(R,P[9 h`Bj+zHH31m''hlMjr)=_e/<PޭV*?S$#K4 ?hˆoqU˻4QhC(S$'&^J/H" kmESLlFŸT("//>(R o i]E|@N װei owN[ \K^DɡPQ]1+ R'ݬ_eH}SޱW'$zDBPaWUznE-y|UsHL-[Ni}0˅EY4 A0u!Z^]DR 30^RQuU\W+`t#5*x*鮼M]e>U8Ry#Sg*n*SIu]C>"rZh$QBve^mWB@"ۛ0m| UKh?LNc4qIIG[Mx]#=2\9&rX?nW!.pW =15ˑD__J iq;Љu(U){{>Xn秚7|թ<"u0努.}#)VRvj/ O!P([VAFh^;J~<0{gGDŽԁ}h.(JGLx%Pc}4k|bk6(e\@YyrXڐZ+;A-Ɖsh^ n:v(srM5Q!` bA(/: .UcY}mE@(C`:02iZdxlu+lAìV%zSaEA2ā \.Lj+ǣWaD%$2c,|0O7rtH{ĥ-8*Hb֥ݵ<$?EKendstream endobj 1129 0 obj 1777 endobj 1133 0 obj <> stream xXoF~篘&cw}K震YcZ >?,P(I%13||338_zg=bEkh;iFBX+uaX:\x$~Ygo?py.~2v.J=MmEXؤ2n3*H x l?>b&r/ VgCZAR?v?kdIz:#e!rXUYJN8#~(kUdCzY$ȘvbPաJ0[Yu tdUB9*. ,FގOI,Z |\WsnWQ;j/nƉP7$~0Ǫ8Al2>4:wUxz"Wn`a^nj?^/G~cl6,A\_N(r=Sbv~y3ƌld긏h4>*1mo4`xI6(b6һ5'>xזyF?-{٬#{oL_$n^@9$u0r/N秃+7 cJCnKK,p7ڸCteAw8?JƨYda"}Gߪ,i9VNĶʢDfl[;/"&)J `LLE `eKUY6)yZ>en&U6&Js/ Vsx3pڤM P$&`~>6O0Z>Hp# H󻣴VLqa4*BWX> stream xWn6}WmbE([MAv1q6mD#_:BrPF`ǚ9W`2˝g6_o}2@mC`PkO8C4fhf\}z.o^8?~_䃋 0#R٧|QH6"DOb)ۚ+(bv[F fqŅ xJyzwyCHc|ajYtQ@ oC[DOq#ʑd]W;? Hq[Z꙱=@l9*ʧ0h1[uh໼\J\| 18b_ ҈U=̀YAصˋ.#6ڮ"]Ż^'s]np͋V{Ǚ0LYDW6ɟ$)q%t> c쫐x*m5SԖ9qbipQhǑQsF_B᤽`bTRF@)T ʼnC5Xӂ2=Az<z.vt^]7躑I~AKW\}H#dC8BM2G' t&vo'nm)+9}:8Y;Ũ.S6 *xvȻS)5.:J"4Vuu,)Y@NY~ fo]KGK_#Xmά4,jS`&_paGt[!uE!ǺuqJF@Z3dbt]JzjLh S9Ktr1ِylHzu:Uu`2{[ ^;/@ +/{ 8V5871e! /~s\ͽv endstream endobj 1139 0 obj 1216 endobj 1143 0 obj <> stream xXmo6_q69Q7h`Ig]Q-Ѷ6Yr):N~Ҏ$۴ A`':=w BQ?g>y3p7#[¯J?&9G!ąOa ߲9&iX {I@'`x.W7 #@yADG^D/F ΖF#$z-Wk [Q'5jM-,\C5̘h:$ `Ag?|xo 8>(˕,x{<U&2Ġ†nGV5 \ \7/U{ُb5R{GImʚ܄^+ H> i'q]֠bfEa&pWBL؂E]$lV)j*&sLǡFxJirVՉJN~LgRa<wXZj`ktVe)9guNΕ&AEٜoLd tiuv3F1eT\18͢S)=Mt[M%+*Tbmxxu[Z2Q)*_N.$V\y1r9~e^y50~^\ޤ5Hn -hT k^d,L{D֧n1_06Egs.G}:i(XP+E޹]Kw8@.im gD""Vuc4N;?> I6]%MalnY>̎SVR[@_yMwmMGlOB>h^B6;O#~V⧿=7gG~x=PTN'L-_Nd=9kV9}gl]JՁ[&~ ky;&$CI_ˆ'M/4qV r,Go'ڑjTc 88߁Q)방͊!pೣ #6c^R{AeFNagFm( H vM֍M sJd[7kgr=sHÓ9ɈcG+7fFĵgг*Zv(L.)t2@!=ؗlҴh~sczʣpzl RDjQɛymIDwsH[:J `RZgjv-vH=UKS߉zppzCaksi,KOFb*:Qzj#͙^x 5?Pjw o[=nǫID}A\ƙe@yxGcoÒ/^]Kjor\y+coA)QN^QrsN(_0 Ͽ 9endstream endobj 1144 0 obj 1503 endobj 1148 0 obj <> stream xWrH}+mh"y䪤yJ zIsB`HE٢4t~ {ȕIuEo2DW(A٢<8H]|L?C_1Μf0\̾)L6]|KjC'mc4Qt6 1Slx NB$)8Nï0' ;(M5Ga*qȊ}ݕLЬP5` bj CG+Tex ՉB6ޱz8[fuT:;g`k9`7*(BwK쇧6RtQA:J< R)Gt& *Y)GAXAk҉4΋O|VU"p|J(WmvR֣nY7E^eh7ߛۑ)(}#I*crL6n()^'a *;M#{L~aS zS;Iw<mf= Bk0P%0~HLP1ի~,gb]S)x0r_nCiZFwCc#fXԗ.ǣy ^3rzw51/gb80[FR, K 9O&X*R|ݚoؒUza8~ZX2_35I:|hXATF1&wQv~j9-!Qc21˴|nʘƾ^(|^ueCBql/\Sg,@4CA# vĥlnЊŐL@!C:IitZCbo` y:j~.u>Sn)3%$ }Ͽendstream endobj 1149 0 obj 1143 endobj 1153 0 obj <> stream xXێ6SIRY:r{I&mNl6YJz?eAԋE6A7of@Hj7lY@ÌĽvb=I$eYf/7pZmNgx81M8(f/݂{[1<8y'aFE(2sdyԒEȶ%$r#oI jysKTB94IIH0H!󊹈%8̩|P::l0m+X}ZiP_6},%-@jUD[<PPC Mp0eM|T5e`*xi;ZD$ >Jn*+r;@nUaK>Mh0NơQ 57&h9\_z a @KdԘS nJYӕ>794c֪`J#: a/81XMhdY ݵż)}g2%r^LlS9yE}TʣakC^i}HtUAUbWPk|!K%z%~^mkYK0o]gYÒ}q(eҋT0L?,["dcuEz:&5|MbdAFBI2=CN6V0”I kߪ{2d._oXJ><{ܦ7?+m&ó@)o7[W{ ) ^ɀY|d]/!Ѓ[_!:M+|axɧ`[9-wG&>ئUSGjqD'n0.xpaЀ{sUֵ^ws.j4o Z]f~W0,`&70-[q$Р °1`.z%5p$r.jR%vndZT4LQ.jH;..>ħMgQ<`A`a 'yr{1/dIi R!ޱ׹*[C,XB Q`pt* :.Ծ+s-,r+XQ8vq^aR'}Fv))9-~(℆ؗk;u%c޶jcIn =4eES$3t`oLta%_k$`RNCj^p2y\Rq- c*\Xin^>\3Xlޓ{+'}E&eݿ,&Y9rrvwI補 ~sC7gZJ 7 x2X?˓endstream endobj 1154 0 obj 2050 endobj 1158 0 obj <> stream xX[sF}KjW[ހL <N肓߳ɒl'd qv'eQ_r3c@nˑC~ǿ ~[nȫ96E$$c$4$(d}pI^'ׯN_'goD-\̿+p'.kC|+ Ԗ3q}Q_w{qdKJ",$.ISuZ$ò$$r9k'YRѴ{0nHe+L(!s{+oe+q3{h`r2a. (R;U]~r`:QHx9u-67ĈͭuDED! A@՞СnD&\ B#reؗ$wd4,)u)|u^ ?ۺҗЧRWsH]Dfѡ<2W$κ_5|ˊv>Z9[L A/ø32U~'F$,BM[85o9uK lJ-72CxG>RԄOE7es=1xQ/d]\ Q41b'GL~fNĜzTO"!T U=j.fMw U. aKh+12lt[CC'3~ o)yw`o$Ktgèv-XJXR-X*!ii b.jE<7Cg> uֲgQdLaz\HP $=Uayq pQ; x"CRp8M) QM{>Ȓtrzh_C>;fd_b\>lr|P7M4iΖ<*dۙ}4厚s&!%^utEiRGOb&Ӟ[4!^#}b/};d4X{%eܛL+4}ei3$([U>Z 3/SbFyw@8&RYz$zyg #ARhdLt%:U(I@Uzld76>rLdd׺H[q^j/AȇxM0fT){,4"rVI3rJ iP\Kh|@Fs'Z)0[*@U-`H)M1-I}e;VI-g" ]=3N~Ȟ,Lk,Pi}< X%X >hhj:48}n(78RVs 죲5yadsxմ/@꼞?!PjlxS|sRPؕ%KK ~M/c蟫ܞ|"jM4ϪVYK<nͭO]V:|΅~a>n?:I1S'uyuQ'!E_geF%~1| ? tnNMh/Y877YTͦ|'endstream endobj 1159 0 obj 1833 endobj 1163 0 obj <> stream x}QMs0+ީPKqҺCdeWojq,THnjwWTBF^T6 *jJdu٨i Uu$b}ZР6u=ą,1lD-0k7.s<>$& t`GňPVyi.XrislH˼Թr!)#)O3Sm-$q`kL0c1#'1>.cR6Zf(ЇJU(<7>p9 Ht?yG_ ?ZwfTb*nqEKendstream endobj 1164 0 obj 542 endobj 1168 0 obj <> stream xY[sݶ~?OcYdxqj)qt:>X4JV~}WN;[$v>(Q$~rSHj.ըBw* +Tfugr8>J K4Vߝ$IՒ ŅX5AZU^WrÉ|1PiuQo|8~C\EŊG$I<C 0ɢ$K]JZW=~#{KOGx[3pk9!<^ _FK9J!_Exg˓}#º\,XH r9ᶣ35syG_2 -GLj{VWFŪ$ 3 :Ң!ȹI,,ĕ,%%9:wE cTNDjªN$U,- ܤt8^iK"0Җs<%ٜ& J @̳0ʁ4+<W(*y+<:\0{$lBH@J?/ړ'հaKwQZM n 0i5u,6ibO\u2quT'ංwxv@DbhuyW?Ф$=p?k$MUT~m'&7+$Ҧ'gv2I:FM0IG<*VcI{0ƶuX%MS\G #0͖7:˷'7/^N(Sp{Ĭ[;_cW[zQG^+ [ -V dZ4 s.m~aZ5;BYV4_qhKOr5e3f`E0"}cmxs.((>li `p6]M'-j]-n?TBW4S!n񣜓@LH`$rA/^Dt}PdzC|i ֵ4BjXj^[O=dVswN[[x-nDĶL˖rKSGDн2Y]ts?]Z 8!Ju⮫*lb:}VC_!̴l27[K8y\H m#+;]aw-Ã҈ u ڵjhT1D+/#w9B/AeCsudP9S>`"{zҋ$VФzdV B]jFE ɱǻ?7/endstream endobj 1169 0 obj 2426 endobj 1173 0 obj <> stream xYm8>B:w Й^w; }T%ֱSٙiDzĢMS$!kJBgV_~ɡ ɿݏ;n Ou"pS ;%]G$O5M+;pEߞTwxs\V4c+/憧M銔tEh pgLRfR4}C(%>{fAd 39f uͅκ^h/m2< FHnA=F.[̌IZ2)X}ӊkȏG hFמΆ+uXftYuJ yNptb^i6'y9:p"ض`I¥)6o !uLp>+&K[+6kXs,YnKuYF aɋ:H:H@+@]J `{Nϟ7>sr1\3Y9@42@ B4StI[ZnXU|D 2b b/B)63~%X[sJ=_@q\toxkx%.Q8tRdw̲; `(rBoUptbNg潮C[6̉"uT2ݚ<腧2/1/.pX83 &5ꀸްkLaF294mkmLN=QcE `<#{Lgq O-92?uҳf1hw)PEW-r&rf{b6ukd/W+F ;Ek֩J|%-GlCS46JbLV4I^N|yC.*Vl:Ȧdz)Uvxx'7#YTzImig3MY Y| 0"VZ <[W!R8Cr\/%,z>W5jۤ(٢1'[/0{;΂5Ғ̘5gDgr*cF+Zܖ<^ITC)PzEr(9a7BNR3{JsWƚ JkmuT!A:b$};B-6\ewN=W 2eP8%Z +8 R;\[ɢ/{sSTYChQݫj1S*/L83[ (b % 'QN>RX/nՄ h~#{CaoBoh⧼|N-6\Ȋ\/D$2/Kç JùH - i"m!$&(cSpɌEwFv t8 `>%p}4+ӭ+ѬiaT[5{ ׅצFfl/S#X5s{wgi|m>a?Mn8J7hiL=t84٭AhpHIo0\W w}ޗ.u 7y".Ct< ٌI!*R;1+^q93Ƈm3}%AOK㜙SiosG]X vą&&}V߸yzFgD`en"Z4 l!|3Y-g'(;B&.R$p(k9}mңΌLoejԁ]*Eݎ|7oI۩ =!v 3፪[*CWmF:@Ǡ-{lMK:+\S܋N^Z&dجl![9*ז&߅[V͕> stream xYK8W*rDzw+nO6ٮ"KnIv!"{RScH(l>Ӱ#wڼl@&e$%Ǎ4إ$aَ2l?}b&| SYHw~ aSS KeF;JLZ~nvP~ݖi?\i|naPXֺ*oI@330kF]āa4&ƛ%M^>4QG(Vjiܼ9:q{. #ә4SՑo.Q!C]V#6SӪtV-~G.\_v~@ I$?XyU>9ny߱UN+<MI-6 ~^ssPǪka*hLu!4Ɲf*X}$Å [W C0NaQ_`c8#qQõk_ ouCc/[P=nj>p^yJ EU׹JN2 dg]VnC•SR1,baq[J縭7%R%.Zpɒ x-yXJijN*bH蚣17ߠ7 D}bp\b iU_R7z0Z=Um^w:T*'E &fl{4ЈAg<`~y,#4]R&3稚*5s=؃8! U[D2VcdhW;BZeVs<(S:yE(U0/2E4eT{Z}L]{K^4k'9$]EPd+` >& 4Y}2vEp&ڰ5i*WËV~! |h-ĩLMuVe`Aٔ/V:Y)ty"\Syz*yr-m5PHri+})n>|WOs%{/`c,N|iu̔6rtFsCkBѾZ4kHN[(PZgǫ0~fKz:k-x\PC ʋhG~ԹdK)aI>qŸ?`\7Yf7Lk"%dPPx@R=rvQ]vKWi(Ky?pE>Ln8R0(BQF"qAL$6,|[`'weNkǾeSQ~~D޿Yd5kZO/KQ^cGy ~~ ʵendstream endobj 1179 0 obj 2604 endobj 1183 0 obj <> stream xYYo8~[E{߲dn{6 ns,뷊NdaiŪbWw>O_WwBGW߯|9&e8pR$]J0s)H]xSZayxt9[0Ac7M=1MZAJcsd9Jw6<7,ʋ"hY3pѠb0|eK8F\Yc}!_,3|kw ܙѴhIfb}w7ZA^M8};m54$J;z⇙@:fa CX|~;RBw8;(~I0#[ 7R+ܠޛa켹ºXɋIh-jE :W^a@Zvs\flNy$QO0 {b7NwffڿtJ~HuBMQ%#_xziD #ۘaNtDQ JMRmY#nx _ƦPy&Cd󌚔&e;@،˛3'R Nz <fThAejP1š2{@L) aab&XzN]2׏&qMsrM9%xG%Vz&ēO})6&E~R\C@zusd]e9x+*  Et#;nwi:a4}GyfYG٥u=z~ىzFۉJ(4M;raq4aWkoQ2ozR!?a#Ha $K0ָ o_Gy DywmN<LᆳUc-TVjRu@!BWmӖhrN=ۺ*c\u=OvRF]2}7jQEVGA84VA RW^ȶFLQ&< :hm"\G>UxRaӘKR,!0[]]v,Cb/x1s&1)o#2aaԉ'JTL&?Jg@F|P,,Xd]Ռ=$3A(ӁCKjۇX}zɟIPyu4̶P)t}yd a[Sȍp$ ;cit7L(Fv{SlN[mLKqBf_S3.^ϤFN,]p?x@oj IdqXF ΋ǼiXEMi,NiΡbAKLsV~D څre Q׹QsiO`-h i%z#=?Ceu@lks:>iM1;z|^ɍppP q|;*O/x^D+qV״&"v }GOLAF;GOY@'չ$5אZwt:.#݀yԆxԾ іNȕ`)_t*n}$%$ط?E/&r~ q&On6WP똃=4G9yÀ K-3=/@(x*n ogֈHjŏ vH|K +nNvY,qq5%uGbLx>_>՗7${t9=m=tĊ tmOLpdjv5?EMOcUikod}~P[~wY-4̝;TQGZ§S~&AW:wewŀ\oYO:kh+ColąNF\ UZ8ռ1GιZa@4Dර\ fi=pSܣ`rQsw.wD`.0Iu3 8QwT6Avfendstream endobj 1184 0 obj 2759 endobj 1188 0 obj <> stream xYIs WfTKѾ'T\o"KtbmHBv^HA?co^%faǻ;Wf{R;NX&| k;V={{T>qF(QC7=ZQVԱc'I*D,N"3i 4@o󤡖V8aAvN/rlω'aIeU K˖&Iw:B:kS9'vG KYF瞲l ֜u0pH\u&^:.iXOџj9Ł0!oQ;3OIgj }4?C?\2_VNoyVqpYwmR>YeFS6,W|[܀xsNvQJH tm/2:<;vHEYXe v_rvxKtP8k(9G?2"J(sR WesAHv&W!TY9yBU0aSRqbvYK!:<  -gWNeZ+nhhq(/O]rcsGx{'p'BLCꫳy]Y]?i P%`u6*a>J&a}<'1x?#{ 5NdSHp3ͻCgk?2ȅBYA3KRmU l!-K궧XY.^7* pO"Ax"ܨL!˔(5l66.k#"~p"\JW >6;>$ΟX^I-wM|-h;D?@`=e I$2Iy` %4Xi,[j%r/̟WH! Hb.KVm/b3j%f3)um*κFYFS? E_ug1tw`u+, ?YE=ÿE(endstream endobj 1189 0 obj 2544 endobj 1193 0 obj <> stream xuXKom8I`CN[5C̯OI5II1c+X*DaL"1䲜"ww9}b_@~}M5II ):3>^E/$I7ie~ϯЃ4 .ն7:LJ,(5qz{aEIꜟI%+8JYHV唥a'ikH|W23w^⸰D8R@sAwfu\lA|!ovm_P}X:{BǍΉxl~8OGJWSE+Ru74u3qw+I:c M?HU%tTK[3ݯp`T:jSgSk032:(eozcUiZpΎpy~vsVn*n @oHۗe0R+b܊&lC5y_9>s wwh)?Cs8`{XоϫG1[9)^?Nb cEȹJҩә?~endstream endobj 1194 0 obj 2019 endobj 1198 0 obj <> stream xY[o~uhlatn݇p$Ό6I$;D:hXx#~9'#& Ǜ* Oy&?ࡂdwQ(C?'Y\4&?v_哰#) cdWޘII 8py0A֝@4C.h@ZpXmdM tjz~]K;Y[|nNeq#spF@,\]#_ oᥳg9 7uS| 2 2U Nxo'P/0tՈJ( u2"%E&퐉Aѹ=Y#Vd/+8vƷ`bqz0ďhoHzFPzsg"??@>S^+5S3ϼ{21u\8`LH᝾$Qsߪ)rTqwhqګHr+^y4Byvw {3{ S-fHm&$䫀,ДLR\A,K;PKH7N{9-Pԅ<\pL70,-m7Q>\X>/8IsS?>O~~_7Oe3܈1.`75P"ѣ8gQu#+t:Cvr1#[,ϖa0 !20B? uhVndaduC k7s5YoѢK`Ymkq ) ?K]bx&WPmj+j9ʚi\?wIs4w{J p[+9˽LL4C9g;dM [@eShŕ\ٙNݎN%^M<Ԧz]u0-ہE} /s4JC!9jH1UxW(KMKZ% &.*SG@Bqp h g#ψV,jxw0ԉO.TfS{i9_DwXLB*2ӢN V[xxفPH `; "pꚊA7؊ i@%Z2{s^ A8͕u"hWW2lnGm@ uxZde> f]ד4/ľwЙwk$u=WޘewQnDjt%}!b nkfD[޺{;)z f/uwZ3K%V$J8PRNæ#qtظ&D{{? ˶;i ݴgD݄=@no05kɧLP4 x ɀǴ7wZ4G};9ĦyAۀtc\I؎[V^/ `_FzJ{HqE.B}ӕi18?$ti[]<'h^lRQs\g=@KXBAR7]YUnYC<<;m7zcDI 5 L(BU//:kEO:j"j7|3s[s<=ǘ&ߘy3`.88-ޜ2nd> 2OA>3~7kx 1Vy dL)Lbjo1v!Ft?hpAǎgH9L󰙶Θg:\oUZuxOÿ G9+endstream endobj 1199 0 obj 2740 endobj 1203 0 obj <> stream xTn0+x,IQt!]PpQA ֖m6Ht𷗛lvOa7pA >|g`|Y`g\NL C @"t٩ID <>ӑz|Q47sQl2H("GڡCFkA1Q9W ر]YQ 5otKUL> stream xMs8}=IULYcdG[|ؒp&%"+jv=L]>ld vxfu!t3i0bs -&_һ^e.Wi[0 bA$F2&_^oDS?wp)36p_Jb/] ]LI\ ]32#wmʹi4T*QeZZfr`ٻ 4#m96$s#8OaGxSۚCr }ͥzzX1bKoYMWJy =  \X.gҺ^ThI3iq#R%l_r=&3,,v(+gksPQui 51ja2A6ӎG}SdEcU>uM0GI7v?L Z4M4މ.IA O@6E߂(,}U]'{H+^]FaXf\Uc̷b5?LrZ0N@TeWpS*AGerFr(ȒKt}nT^9U<ϭ042p&6lz z^"S+3;D`%]ϝGC+59C l~QHָ\0LQ*~ @jXC'|C7VT^LWZmv yYX۬,X<7-Aƈ>ԣ`+uDk7Kl.^AQ*˨0|*VyOvIp:(h; 8CzNϿ*4endstream endobj 1209 0 obj 970 endobj 1213 0 obj <> stream xKs:Z.LyXuLɌ5c)ñ[!I{Nct=qr[L%_sϼn|pQs|$+g6ʼn^/pyVzwzys\At^9"' Ҥ m5 }{ yä Wsd营RDndC5?r%E4D9Ny Il$ Ӫ( D`j21-`qgt?de2Q-X]qz2, >vO^8u}VpRJf*< j:ɯA,f_A*7z 5G@hfZ%_Գd8kNDӝsutB)Bp4kbtʝugIc*`0q b Jƴ1wc6Tibߜ[V7~ƨC5'0[ي6—w8҆0 CO~0vm#17,?R!?7{#cy}cp 揬*%^u;z}3kDFVi1ԊO5_̫(T`g쏖)*TCs.8B}(wLtLW+q4qN26cm_bYM'u6ӐHF%|sx| g4GkRq L =$2Сugw[=k[6_UU!(`p߂1mUIeN6C]L/\(7f:T ;.UQ†JO+>%Gendstream endobj 1214 0 obj 938 endobj 1218 0 obj <> stream xVM8+:IUsl äRa Nj[c#L_-cʶX.SZԯ 倭?3)FCʑ ^GN#)!Ơ DN0"׊ 'C\bߞ`mϗcFa^h."tt")$!&f'uc['$c†V'n:sIi7);59's,i^g0UJmD^tI?ƾ!F8&YAxg@kd7YXImg,[Xj{ R{3B J9-Ȃ%2 0۲~iJL)bZpaMTkP T!<U1C}E4=(QB';gG"$2,ŠJX00c =\IlG8LӖcRWU61!ȓ'|3fs,-uI^@ݯS|==Xc;@xzsl^i8M3"gv-0~=H HFmm jLS݇)'d'UbkԎ[ pA f9)KzJTz8A߄־oh^'3&7Q&M0]j_a/p 8 m{%˪ rL!;sk &xjچ\? yOvZ|7!SJQ'wҦXmK ,:eo 94endstream endobj 1219 0 obj 992 endobj 1223 0 obj <> stream xVnH}+JڇH f^VHLEnglng~V70$Vd%XVꮪsN 9FiEo=L?Q !.wF0m-R`ŸzZc<{ du?YyǠ}}1-- b$'"?%Pl;nbڎW_8_EN:mCK02$Y <:%3؎acxXJVHX  NQƕؖQ,c4C?*t=H_}96)XTEtD[L,B7fA3$߱$0(Ipjlc^b#I:g!K)hBm;C#e"YPTo64]8+"Naf8gCTYocRpy,1+N'=E?.~| Ixn}"m2%v,UC-YRη}94n¨I: 妈XARUxB+ .0fކw4Gkۏ[nbFY^J"%;uTncQ+;hZ{0K&yN=oIwtV,׵^\_ D-HeFH\ HS} &wt]v7ȆI)F$Vߓu ۿ$ó&%LgO V_ݰȄKYs2i B$vܫᚮ(_n7 ZDl˔f5qmy_Թ3<Ѧ̣:4#"/8=UJb 6/qGBkQ ƐHZ!G-PY <,f%,_3Uڰ"PLK.\" K7m_p*^'dpWkP),ׇKg M5wLX:SMI)w:cj(MUlӔXg NXĥ{E[I 5x|MfHRahk ggGloi˟=LJendstream endobj 1224 0 obj 1125 endobj 1228 0 obj <> stream xMO0s=ԍMmwhgĤA(ce%°UٲV_g|۴S[χދ]fCXʻLW X/aM[(LXrOL2N ^0 F,v7ٌR ǁّ;}XjIX`!qJDDASs0/e;'pGQCwy*ʢe"Cmʳg0XʲhjXvuj;<&iBhW\ 3Nd@\i-4)>'uЗSR zj{UIBJs4 W tռFͱ2 j4{ [Dj,4ViJn幝\,n4'ڢfW)Sz§G]ObK@:Wę軍v$J7I-S4Iswf 6tBx-]G@t޲(܌2rkdr0'I7HE?4I5MY;SWj_#wx8yR L rzL9*)gE]endstream endobj 1229 0 obj 617 endobj 1233 0 obj <> stream x+T03T0A(˥d^e\\` P*9W)$g`fg`nbgh˥PVlRklignT¥R eendstream endobj 1234 0 obj 123 endobj 1238 0 obj <> stream xXr6WAKR:؉8$5 3ˈ%wDsJI*- _~-r1AhG껏>ڕ+vE Q6Us<ĄMr._molFg WS"ybM4@k@}RʷՅ*x!CR{yͳ`xp` [9UfN \Ҝ͉ʾ$?(S*dbt󀪽C!6~"pt 0C=YT<֧y0YsX;}B9=,L,ԡ/uH/?Jq8îчԽTF.eTy}֠Pi4睝sf`]N%:V[#Y${s|a~{M5ymK0de!`zpÞIQٓ9kiM똆XΡ٘;JIڃ2$}탽*ԺTk:7*DD.,W %1@<( q(c"D2gV8ւ 74ai;Gw{R  dVRS<ʶ1q(sبn$1XKU$0;$))zMUϾY(^@ Scןr4^.Ըo}{a$Ev&*] .zx#] v>a2&I>`@)Nl%ҝ@ͦQ=_,,P[^;-q<< 'j4)2^MuAM@Pm HA#\5¤E72l~WMܜ)gQWFJtUL)bhMܛ7jK(q swaƉ Ji:Ze Ƴf|ֵa `;  DFU-L0)Y_LAُbH>ag1A1ۙej$sUaCl1̀*@j 0Zqm g} $FE5};whSk\mzFUf㷡6H`ܲPfHSKX}d~PhC3M!6즠{s.90ݽwS?@Uf"jB0bTryzĊz=r4de'C3gƊxD/M\BZ'0 `)- dà 0)0~uXfO`{sh9Rhݛ<1/ٞ-@`@wLC29%`D?Ϋ"BW/!/xx~qDF ] vE%Vv鬬& %{tD!.ːgoڢ\rC IlR-+# Er42a^ ,&.T.= >b!iLD/ڥv(hf69N,Ov}Yi|pŰW\|*tMme[7> /Contents 5 0 R >> endobj 12 0 obj <> /Contents 13 0 R >> endobj 17 0 obj <> /Contents 18 0 R >> endobj 22 0 obj <> /Contents 23 0 R >> endobj 27 0 obj <> /Contents 28 0 R >> endobj 34 0 obj <> /Contents 35 0 R >> endobj 39 0 obj <> /Contents 40 0 R >> endobj 45 0 obj <> /Contents 46 0 R >> endobj 50 0 obj <> /Contents 51 0 R >> endobj 56 0 obj <> /Contents 57 0 R >> endobj 61 0 obj <> /Contents 62 0 R >> endobj 67 0 obj <> /Contents 68 0 R >> endobj 72 0 obj <> /Contents 73 0 R >> endobj 77 0 obj <> /Contents 78 0 R >> endobj 82 0 obj <> /Contents 83 0 R >> endobj 87 0 obj <> /Contents 88 0 R >> endobj 92 0 obj <> /Contents 93 0 R >> endobj 97 0 obj <> /Contents 98 0 R >> endobj 102 0 obj <> /Contents 103 0 R >> endobj 107 0 obj <> /Contents 108 0 R >> endobj 112 0 obj <> /Contents 113 0 R >> endobj 117 0 obj <> /Contents 118 0 R >> endobj 122 0 obj <> /Contents 123 0 R >> endobj 127 0 obj <> /Contents 128 0 R >> endobj 132 0 obj <> /Contents 133 0 R >> endobj 137 0 obj <> /Contents 138 0 R >> endobj 142 0 obj <> /Contents 143 0 R >> endobj 147 0 obj <> /Contents 148 0 R >> endobj 152 0 obj <> /Contents 153 0 R >> endobj 158 0 obj <> /Contents 159 0 R >> endobj 163 0 obj <> /Contents 164 0 R >> endobj 168 0 obj <> /Contents 169 0 R >> endobj 173 0 obj <> /Contents 174 0 R >> endobj 178 0 obj <> /Contents 179 0 R >> endobj 183 0 obj <> /Contents 184 0 R >> endobj 188 0 obj <> /Contents 189 0 R >> endobj 193 0 obj <> /Contents 194 0 R >> endobj 198 0 obj <> /Contents 199 0 R >> endobj 203 0 obj <> /Contents 204 0 R >> endobj 208 0 obj <> /Contents 209 0 R >> endobj 213 0 obj <> /Contents 214 0 R >> endobj 218 0 obj <> /Contents 219 0 R >> endobj 223 0 obj <> /Contents 224 0 R >> endobj 228 0 obj <> /Contents 229 0 R >> endobj 233 0 obj <> /Contents 234 0 R >> endobj 238 0 obj <> /Contents 239 0 R >> endobj 243 0 obj <> /Contents 244 0 R >> endobj 248 0 obj <> /Contents 249 0 R >> endobj 253 0 obj <> /Contents 254 0 R >> endobj 258 0 obj <> /Contents 259 0 R >> endobj 263 0 obj <> /Contents 264 0 R >> endobj 268 0 obj <> /Contents 269 0 R >> endobj 273 0 obj <> /Contents 274 0 R >> endobj 278 0 obj <> /Contents 279 0 R >> endobj 283 0 obj <> /Contents 284 0 R >> endobj 288 0 obj <> /Contents 289 0 R >> endobj 293 0 obj <> /Contents 294 0 R >> endobj 298 0 obj <> /Contents 299 0 R >> endobj 303 0 obj <> /Contents 304 0 R >> endobj 308 0 obj <> /Contents 309 0 R >> endobj 313 0 obj <> /Contents 314 0 R >> endobj 318 0 obj <> /Contents 319 0 R >> endobj 323 0 obj <> /Contents 324 0 R >> endobj 328 0 obj <> /Contents 329 0 R >> endobj 333 0 obj <> /Contents 334 0 R >> endobj 338 0 obj <> /Contents 339 0 R >> endobj 343 0 obj <> /Contents 344 0 R >> endobj 348 0 obj <> /Contents 349 0 R >> endobj 353 0 obj <> /Contents 354 0 R >> endobj 358 0 obj <> /Contents 359 0 R >> endobj 363 0 obj <> /Contents 364 0 R >> endobj 368 0 obj <> /Contents 369 0 R >> endobj 373 0 obj <> /Contents 374 0 R >> endobj 378 0 obj <> /Contents 379 0 R >> endobj 383 0 obj <> /Contents 384 0 R >> endobj 388 0 obj <> /Contents 389 0 R >> endobj 393 0 obj <> /Contents 394 0 R >> endobj 398 0 obj <> /Contents 399 0 R >> endobj 403 0 obj <> /Contents 404 0 R >> endobj 408 0 obj <> /Contents 409 0 R >> endobj 413 0 obj <> /Contents 414 0 R >> endobj 418 0 obj <> /Contents 419 0 R >> endobj 423 0 obj <> /Contents 424 0 R >> endobj 428 0 obj <> /Contents 429 0 R >> endobj 433 0 obj <> /Contents 434 0 R >> endobj 438 0 obj <> /Contents 439 0 R >> endobj 443 0 obj <> /Contents 444 0 R >> endobj 448 0 obj <> /Contents 449 0 R >> endobj 453 0 obj <> /Contents 454 0 R >> endobj 458 0 obj <> /Contents 459 0 R >> endobj 463 0 obj <> /Contents 464 0 R >> endobj 468 0 obj <> /Contents 469 0 R >> endobj 473 0 obj <> /Contents 474 0 R >> endobj 478 0 obj <> /Contents 479 0 R >> endobj 483 0 obj <> /Contents 484 0 R >> endobj 488 0 obj <> /Contents 489 0 R >> endobj 493 0 obj <> /Contents 494 0 R >> endobj 498 0 obj <> /Contents 499 0 R >> endobj 503 0 obj <> /Contents 504 0 R >> endobj 508 0 obj <> /Contents 509 0 R >> endobj 513 0 obj <> /Contents 514 0 R >> endobj 518 0 obj <> /Contents 519 0 R >> endobj 523 0 obj <> /Contents 524 0 R >> endobj 528 0 obj <> /Contents 529 0 R >> endobj 533 0 obj <> /Contents 534 0 R >> endobj 538 0 obj <> /Contents 539 0 R >> endobj 543 0 obj <> /Contents 544 0 R >> endobj 548 0 obj <> /Contents 549 0 R >> endobj 553 0 obj <> /Contents 554 0 R >> endobj 558 0 obj <> /Contents 559 0 R >> endobj 563 0 obj <> /Contents 564 0 R >> endobj 568 0 obj <> /Contents 569 0 R >> endobj 573 0 obj <> /Contents 574 0 R >> endobj 578 0 obj <> /Contents 579 0 R >> endobj 583 0 obj <> /Contents 584 0 R >> endobj 588 0 obj <> /Contents 589 0 R >> endobj 593 0 obj <> /Contents 594 0 R >> endobj 598 0 obj <> /Contents 599 0 R >> endobj 603 0 obj <> /Contents 604 0 R >> endobj 608 0 obj <> /Contents 609 0 R >> endobj 613 0 obj <> /Contents 614 0 R >> endobj 618 0 obj <> /Contents 619 0 R >> endobj 623 0 obj <> /Contents 624 0 R >> endobj 628 0 obj <> /Contents 629 0 R >> endobj 633 0 obj <> /Contents 634 0 R >> endobj 638 0 obj <> /Contents 639 0 R >> endobj 643 0 obj <> /Contents 644 0 R >> endobj 648 0 obj <> /Contents 649 0 R >> endobj 653 0 obj <> /Contents 654 0 R >> endobj 658 0 obj <> /Contents 659 0 R >> endobj 663 0 obj <> /Contents 664 0 R >> endobj 668 0 obj <> /Contents 669 0 R >> endobj 673 0 obj <> /Contents 674 0 R >> endobj 678 0 obj <> /Contents 679 0 R >> endobj 685 0 obj <> /Contents 686 0 R >> endobj 693 0 obj <> /Contents 694 0 R >> endobj 701 0 obj <> /Contents 702 0 R >> endobj 709 0 obj <> /Contents 710 0 R >> endobj 717 0 obj <> /Contents 718 0 R >> endobj 725 0 obj <> /Contents 726 0 R >> endobj 733 0 obj <> /Contents 734 0 R >> endobj 740 0 obj <> /Contents 741 0 R >> endobj 745 0 obj <> /Contents 746 0 R >> endobj 750 0 obj <> /Contents 751 0 R >> endobj 755 0 obj <> /Contents 756 0 R >> endobj 760 0 obj <> /Contents 761 0 R >> endobj 765 0 obj <> /Contents 766 0 R >> endobj 770 0 obj <> /Contents 771 0 R >> endobj 775 0 obj <> /Contents 776 0 R >> endobj 780 0 obj <> /Contents 781 0 R >> endobj 785 0 obj <> /Contents 786 0 R >> endobj 790 0 obj <> /Contents 791 0 R >> endobj 795 0 obj <> /Contents 796 0 R >> endobj 800 0 obj <> /Contents 801 0 R >> endobj 805 0 obj <> /Contents 806 0 R >> endobj 810 0 obj <> /Contents 811 0 R >> endobj 815 0 obj <> /Contents 816 0 R >> endobj 820 0 obj <> /Contents 821 0 R >> endobj 825 0 obj <> /Contents 826 0 R >> endobj 830 0 obj <> /Contents 831 0 R >> endobj 835 0 obj <> /Contents 836 0 R >> endobj 842 0 obj <> /Contents 843 0 R >> endobj 847 0 obj <> /Contents 848 0 R >> endobj 852 0 obj <> /Contents 853 0 R >> endobj 857 0 obj <> /Contents 858 0 R >> endobj 862 0 obj <> /Contents 863 0 R >> endobj 867 0 obj <> /Contents 868 0 R >> endobj 872 0 obj <> /Contents 873 0 R >> endobj 877 0 obj <> /Contents 878 0 R >> endobj 882 0 obj <> /Contents 883 0 R >> endobj 887 0 obj <> /Contents 888 0 R >> endobj 892 0 obj <> /Contents 893 0 R >> endobj 897 0 obj <> /Contents 898 0 R >> endobj 902 0 obj <> /Contents 903 0 R >> endobj 907 0 obj <> /Contents 908 0 R >> endobj 912 0 obj <> /Contents 913 0 R >> endobj 917 0 obj <> /Contents 918 0 R >> endobj 922 0 obj <> /Contents 923 0 R >> endobj 927 0 obj <> /Contents 928 0 R >> endobj 932 0 obj <> /Contents 933 0 R >> endobj 937 0 obj <> /Contents 938 0 R >> endobj 942 0 obj <> /Contents 943 0 R >> endobj 947 0 obj <> /Contents 948 0 R >> endobj 952 0 obj <> /Contents 953 0 R >> endobj 957 0 obj <> /Contents 958 0 R >> endobj 962 0 obj <> /Contents 963 0 R >> endobj 967 0 obj <> /Contents 968 0 R >> endobj 972 0 obj <> /Contents 973 0 R >> endobj 977 0 obj <> /Contents 978 0 R >> endobj 982 0 obj <> /Contents 983 0 R >> endobj 987 0 obj <> /Contents 988 0 R >> endobj 992 0 obj <> /Contents 993 0 R >> endobj 997 0 obj <> /Contents 998 0 R >> endobj 1002 0 obj <> /Contents 1003 0 R >> endobj 1007 0 obj <> /Contents 1008 0 R >> endobj 1012 0 obj <> /Contents 1013 0 R >> endobj 1017 0 obj <> /Contents 1018 0 R >> endobj 1022 0 obj <> /Contents 1023 0 R >> endobj 1027 0 obj <> /Contents 1028 0 R >> endobj 1032 0 obj <> /Contents 1033 0 R >> endobj 1037 0 obj <> /Contents 1038 0 R >> endobj 1042 0 obj <> /Contents 1043 0 R >> endobj 1047 0 obj <> /Contents 1048 0 R >> endobj 1052 0 obj <> /Contents 1053 0 R >> endobj 1057 0 obj <> /Contents 1058 0 R >> endobj 1062 0 obj <> /Contents 1063 0 R >> endobj 1067 0 obj <> /Contents 1068 0 R >> endobj 1072 0 obj <> /Contents 1073 0 R >> endobj 1077 0 obj <> /Contents 1078 0 R >> endobj 1082 0 obj <> /Contents 1083 0 R >> endobj 1087 0 obj <> /Contents 1088 0 R >> endobj 1092 0 obj <> /Contents 1093 0 R >> endobj 1097 0 obj <> /Contents 1098 0 R >> endobj 1102 0 obj <> /Contents 1103 0 R >> endobj 1107 0 obj <> /Contents 1108 0 R >> endobj 1112 0 obj <> /Contents 1113 0 R >> endobj 1117 0 obj <> /Contents 1118 0 R >> endobj 1122 0 obj <> /Contents 1123 0 R >> endobj 1127 0 obj <> /Contents 1128 0 R >> endobj 1132 0 obj <> /Contents 1133 0 R >> endobj 1137 0 obj <> /Contents 1138 0 R >> endobj 1142 0 obj <> /Contents 1143 0 R >> endobj 1147 0 obj <> /Contents 1148 0 R >> endobj 1152 0 obj <> /Contents 1153 0 R >> endobj 1157 0 obj <> /Contents 1158 0 R >> endobj 1162 0 obj <> /Contents 1163 0 R >> endobj 1167 0 obj <> /Contents 1168 0 R >> endobj 1172 0 obj <> /Contents 1173 0 R >> endobj 1177 0 obj <> /Contents 1178 0 R >> endobj 1182 0 obj <> /Contents 1183 0 R >> endobj 1187 0 obj <> /Contents 1188 0 R >> endobj 1192 0 obj <> /Contents 1193 0 R >> endobj 1197 0 obj <> /Contents 1198 0 R >> endobj 1202 0 obj <> /Contents 1203 0 R >> endobj 1207 0 obj <> /Contents 1208 0 R >> endobj 1212 0 obj <> /Contents 1213 0 R >> endobj 1217 0 obj <> /Contents 1218 0 R >> endobj 1222 0 obj <> /Contents 1223 0 R >> endobj 1227 0 obj <> /Contents 1228 0 R >> endobj 1232 0 obj <> /Contents 1233 0 R >> endobj 1237 0 obj <> /Contents 1238 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 12 0 R 17 0 R 22 0 R 27 0 R 34 0 R 39 0 R 45 0 R 50 0 R 56 0 R 61 0 R 67 0 R 72 0 R 77 0 R 82 0 R 87 0 R 92 0 R 97 0 R 102 0 R 107 0 R 112 0 R 117 0 R 122 0 R 127 0 R 132 0 R 137 0 R 142 0 R 147 0 R 152 0 R 158 0 R 163 0 R 168 0 R 173 0 R 178 0 R 183 0 R 188 0 R 193 0 R 198 0 R 203 0 R 208 0 R 213 0 R 218 0 R 223 0 R 228 0 R 233 0 R 238 0 R 243 0 R 248 0 R 253 0 R 258 0 R 263 0 R 268 0 R 273 0 R 278 0 R 283 0 R 288 0 R 293 0 R 298 0 R 303 0 R 308 0 R 313 0 R 318 0 R 323 0 R 328 0 R 333 0 R 338 0 R 343 0 R 348 0 R 353 0 R 358 0 R 363 0 R 368 0 R 373 0 R 378 0 R 383 0 R 388 0 R 393 0 R 398 0 R 403 0 R 408 0 R 413 0 R 418 0 R 423 0 R 428 0 R 433 0 R 438 0 R 443 0 R 448 0 R 453 0 R 458 0 R 463 0 R 468 0 R 473 0 R 478 0 R 483 0 R 488 0 R 493 0 R 498 0 R 503 0 R 508 0 R 513 0 R 518 0 R 523 0 R 528 0 R 533 0 R 538 0 R 543 0 R 548 0 R 553 0 R 558 0 R 563 0 R 568 0 R 573 0 R 578 0 R 583 0 R 588 0 R 593 0 R 598 0 R 603 0 R 608 0 R 613 0 R 618 0 R 623 0 R 628 0 R 633 0 R 638 0 R 643 0 R 648 0 R 653 0 R 658 0 R 663 0 R 668 0 R 673 0 R 678 0 R 685 0 R 693 0 R 701 0 R 709 0 R 717 0 R 725 0 R 733 0 R 740 0 R 745 0 R 750 0 R 755 0 R 760 0 R 765 0 R 770 0 R 775 0 R 780 0 R 785 0 R 790 0 R 795 0 R 800 0 R 805 0 R 810 0 R 815 0 R 820 0 R 825 0 R 830 0 R 835 0 R 842 0 R 847 0 R 852 0 R 857 0 R 862 0 R 867 0 R 872 0 R 877 0 R 882 0 R 887 0 R 892 0 R 897 0 R 902 0 R 907 0 R 912 0 R 917 0 R 922 0 R 927 0 R 932 0 R 937 0 R 942 0 R 947 0 R 952 0 R 957 0 R 962 0 R 967 0 R 972 0 R 977 0 R 982 0 R 987 0 R 992 0 R 997 0 R 1002 0 R 1007 0 R 1012 0 R 1017 0 R 1022 0 R 1027 0 R 1032 0 R 1037 0 R 1042 0 R 1047 0 R 1052 0 R 1057 0 R 1062 0 R 1067 0 R 1072 0 R 1077 0 R 1082 0 R 1087 0 R 1092 0 R 1097 0 R 1102 0 R 1107 0 R 1112 0 R 1117 0 R 1122 0 R 1127 0 R 1132 0 R 1137 0 R 1142 0 R 1147 0 R 1152 0 R 1157 0 R 1162 0 R 1167 0 R 1172 0 R 1177 0 R 1182 0 R 1187 0 R 1192 0 R 1197 0 R 1202 0 R 1207 0 R 1212 0 R 1217 0 R 1222 0 R 1227 0 R 1232 0 R 1237 0 R ] /Count 241 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 10 0 obj <> endobj 11 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <> endobj 25 0 obj <> endobj 26 0 obj <> endobj 32 0 obj <> endobj 33 0 obj <> endobj 37 0 obj <> endobj 38 0 obj <> endobj 43 0 obj <> endobj 44 0 obj <> endobj 48 0 obj <> endobj 49 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <> endobj 85 0 obj <> endobj 86 0 obj <> endobj 90 0 obj <> endobj 91 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 105 0 obj <> endobj 106 0 obj <> endobj 110 0 obj <> endobj 111 0 obj <> endobj 115 0 obj <> endobj 116 0 obj <> endobj 120 0 obj <> endobj 121 0 obj <> endobj 125 0 obj <> endobj 126 0 obj <> endobj 130 0 obj <> endobj 131 0 obj <> endobj 135 0 obj <> endobj 136 0 obj <> endobj 140 0 obj <> endobj 141 0 obj <> endobj 145 0 obj <> endobj 146 0 obj <> endobj 150 0 obj <> endobj 151 0 obj <> endobj 156 0 obj <> endobj 157 0 obj <> endobj 161 0 obj <> endobj 162 0 obj <> endobj 166 0 obj <> endobj 167 0 obj <> endobj 171 0 obj <> endobj 172 0 obj <> endobj 176 0 obj <> endobj 177 0 obj <> endobj 181 0 obj <> endobj 182 0 obj <> endobj 186 0 obj <> endobj 187 0 obj <> endobj 191 0 obj <> endobj 192 0 obj <> endobj 196 0 obj <> endobj 197 0 obj <> endobj 201 0 obj <> endobj 202 0 obj <> endobj 206 0 obj <> endobj 207 0 obj <> endobj 211 0 obj <> endobj 212 0 obj <> endobj 216 0 obj <> endobj 217 0 obj <> endobj 221 0 obj <> endobj 222 0 obj <> endobj 226 0 obj <> endobj 227 0 obj <> endobj 231 0 obj <> endobj 232 0 obj <> endobj 236 0 obj <> endobj 237 0 obj <> endobj 241 0 obj <> endobj 242 0 obj <> endobj 246 0 obj <> endobj 247 0 obj <> endobj 251 0 obj <> endobj 252 0 obj <> endobj 256 0 obj <> endobj 257 0 obj <> endobj 261 0 obj <> endobj 262 0 obj <> endobj 266 0 obj <> endobj 267 0 obj <> endobj 271 0 obj <> endobj 272 0 obj <> endobj 276 0 obj <> endobj 277 0 obj <> endobj 281 0 obj <> endobj 282 0 obj <> endobj 286 0 obj <> endobj 287 0 obj <> endobj 291 0 obj <> endobj 292 0 obj <> endobj 296 0 obj <> endobj 297 0 obj <> endobj 301 0 obj <> endobj 302 0 obj <> endobj 306 0 obj <> endobj 307 0 obj <> endobj 311 0 obj <> endobj 312 0 obj <> endobj 316 0 obj <> endobj 317 0 obj <> endobj 321 0 obj <> endobj 322 0 obj <> endobj 326 0 obj <> endobj 327 0 obj <> endobj 331 0 obj <> endobj 332 0 obj <> endobj 336 0 obj <> endobj 337 0 obj <> endobj 341 0 obj <> endobj 342 0 obj <> endobj 346 0 obj <> endobj 347 0 obj <> endobj 351 0 obj <> endobj 352 0 obj <> endobj 356 0 obj <> endobj 357 0 obj <> endobj 361 0 obj <> endobj 362 0 obj <> endobj 366 0 obj <> endobj 367 0 obj <> endobj 371 0 obj <> endobj 372 0 obj <> endobj 376 0 obj <> endobj 377 0 obj <> endobj 381 0 obj <> endobj 382 0 obj <> endobj 386 0 obj <> endobj 387 0 obj <> endobj 391 0 obj <> endobj 392 0 obj <> endobj 396 0 obj <> endobj 397 0 obj <> endobj 401 0 obj <> endobj 402 0 obj <> endobj 406 0 obj <> endobj 407 0 obj <> endobj 411 0 obj <> endobj 412 0 obj <> endobj 416 0 obj <> endobj 417 0 obj <> endobj 421 0 obj <> endobj 422 0 obj <> endobj 426 0 obj <> endobj 427 0 obj <> endobj 431 0 obj <> endobj 432 0 obj <> endobj 436 0 obj <> endobj 437 0 obj <> endobj 441 0 obj <> endobj 442 0 obj <> endobj 446 0 obj <> endobj 447 0 obj <> endobj 451 0 obj <> endobj 452 0 obj <> endobj 456 0 obj <> endobj 457 0 obj <> endobj 461 0 obj <> endobj 462 0 obj <> endobj 466 0 obj <> endobj 467 0 obj <> endobj 471 0 obj <> endobj 472 0 obj <> endobj 476 0 obj <> endobj 477 0 obj <> endobj 481 0 obj <> endobj 482 0 obj <> endobj 486 0 obj <> endobj 487 0 obj <> endobj 491 0 obj <> endobj 492 0 obj <> endobj 496 0 obj <> endobj 497 0 obj <> endobj 501 0 obj <> endobj 502 0 obj <> endobj 506 0 obj <> endobj 507 0 obj <> endobj 511 0 obj <> endobj 512 0 obj <> endobj 516 0 obj <> endobj 517 0 obj <> endobj 521 0 obj <> endobj 522 0 obj <> endobj 526 0 obj <> endobj 527 0 obj <> endobj 531 0 obj <> endobj 532 0 obj <> endobj 536 0 obj <> endobj 537 0 obj <> endobj 541 0 obj <> endobj 542 0 obj <> endobj 546 0 obj <> endobj 547 0 obj <> endobj 551 0 obj <> endobj 552 0 obj <> endobj 556 0 obj <> endobj 557 0 obj <> endobj 561 0 obj <> endobj 562 0 obj <> endobj 566 0 obj <> endobj 567 0 obj <> endobj 571 0 obj <> endobj 572 0 obj <> endobj 576 0 obj <> endobj 577 0 obj <> endobj 581 0 obj <> endobj 582 0 obj <> endobj 586 0 obj <> endobj 587 0 obj <> endobj 591 0 obj <> endobj 592 0 obj <> endobj 596 0 obj <> endobj 597 0 obj <> endobj 601 0 obj <> endobj 602 0 obj <> endobj 606 0 obj <> endobj 607 0 obj <> endobj 611 0 obj <> endobj 612 0 obj <> endobj 616 0 obj <> endobj 617 0 obj <> endobj 621 0 obj <> endobj 622 0 obj <> endobj 626 0 obj <> endobj 627 0 obj <> endobj 631 0 obj <> endobj 632 0 obj <> endobj 636 0 obj <> endobj 637 0 obj <> endobj 641 0 obj <> endobj 642 0 obj <> endobj 646 0 obj <> endobj 647 0 obj <> endobj 651 0 obj <> endobj 652 0 obj <> endobj 656 0 obj <> endobj 657 0 obj <> endobj 661 0 obj <> endobj 662 0 obj <> endobj 666 0 obj <> endobj 667 0 obj <> endobj 671 0 obj <> endobj 672 0 obj <> endobj 676 0 obj <> endobj 677 0 obj <> endobj 682 0 obj <> endobj 683 0 obj <> endobj 681 0 obj <>/Length 629>>stream %Du:^"po;x;qnkga3R{:8e.IR:v θ.-:xe.UQR:KS)q=q2:0κ3:2 ԏg\7Rw|20^Ap.)~{:R4*Fv$ %lZ<0ʑ.%\2J<2 ȷ +*E[<0ʐ![ ʐ!2RI^*@B0ʐ͞UZ2#< S/<3 3|3 >3o Y>pϵ\2K >h3 l*+e;>ضϱK ϰ<2& >PelfϺ[>.3섈[GϺxexaApMaq}Vvs<2*)ogY9.D:J{8]pZ g+9NE8B8q 9<20^(E3*\3QTEQ4U;!!dHDB$,B$"B:/%3F"tJJQ ":H#HIDtkDu/莽":F66i@ endstream endobj 684 0 obj <> endobj 690 0 obj <> endobj 691 0 obj <> endobj 689 0 obj <>/Length 622>>stream E;?H<$H ʐ.*@L2Yʑ^*EWSI2Qʐ*Bh{*BDuʐʐJeHIj6":L eHRR1[*I?2ORWʒʐ?eHTi22[*I^*UTRҿˣ<<-&T2TAt*Th6*Sʗ*]ReJ*Qʓ!&T+fٞ+f_em.VҴ쭭{+k6elIC4gH[U[TemOFA+jB#쭅2쭂[elK+e~V+e7Q_V[V}M&VelJ}iV/elƓ+i=wemG\4F/ HSVTLѴ^ϽD|2+d{>ᕺZLζ}VIqcg4 Wt:֐gX̫Χ- WX3aoX\\Ƌy\X\wHD4TREMp8B$"B$,!dHE _EQ, TPIӤGVDum莒#N6""<@ endstream endobj 688 0 obj <>/Length 522>>stream %ԇPDu쎵e7e7ߦSqԺ4_H#[)sOHL6̿K]*2[R_KKWKe.I픺}REѧ Ce. m^\DvRKe.Y~Ke.U)\e./lūvRKĭ}\e.]GK1":KljhOe.DvR6R6R/lS)q)t)zRlRȶRRKe/=~)|K^-:eHeHgYthʒRDtlZ%T}(LUhڇTGgTvyEvSAB3S @X3H Qifz\ ~ę|BBfJ FCB"L'2K DUSEQ戝#E#DNh:4Y:4Fd# `_*t":X]DuJ,2I 0mDDF  endstream endobj 692 0 obj <> endobj 698 0 obj <> endobj 699 0 obj <> endobj 697 0 obj <>/Length 557>>stream 2O(p_KeHTʒѧ":A%eHA(hڲ:Rkʔt.KeKi_띥녲ml8?!j٧?+fY:DtᲶ]$UҶVֺ[Y/GѢV4":^?J+j.FK쭪J[SKemKWel/_V’l_[+`ҶVzliDu}/J+e[F=GBVؿ]-dVRVاL$[J[J[Kel [0DjҠڀF~DDt>˥[[>&>!>,3a3a} ϻ8 ̖I^ yڂEDJRv R0\TY "!dHD!HDHY!!dHS L_R*hYUT":ZiGR'E S 8@ endstream endobj 696 0 obj <>/Length 523>>stream 2Nѝ#_ex.i"+DtG_DuKeH?eH_;K@{*GH// ":6"R[*S_/ʗueK?JL_󴵗_HHTP 'i TJ_R5O_镳4[2J_[KK[JJ[[Femi$":l?PMPV1Jel*ڪ_ڧ>[+j_[ 2 -DVRXVtVʲ!+e)$GOPKlelY&[HD~آ[+b}$26[+`il%a-dV[VTϰ}Aa-i VϽAAa @ Ϻm@f,ЬrTv %`5DTIS$"HY!!dHD!, > `UőTUH#馐Du"Y+.!I 8pӈ@ endstream endobj 700 0 obj <> endobj 706 0 obj <> endobj 707 0 obj <> endobj 705 0 obj <>/Length 539>>stream 2US$Dt"/_2 G F6L/Pee$'Ie(2/K}:Ht(T6_/쪟VZ(5KQ_Re#eK}EKFzH\.ѴmHDGY*ʏ]S_&*3I/h=D~ؿ쭋%elU+tV?'+elKVƿJ[4FŲcHS/S i Ѵ[+j[Q-[+`ҦV˥V%3[Ni[+u%L[[>Ж[8J[AS>}K >,32J>/Length 597>>stream 2 Aa$%R:UA{*THKeJ~?(l.ѴʗRTʕT/ҦT:_#^_V?VVGF/GI$ {+f_0ApK 해VV֒[+k=lL瑢$G_K[$JIjڮ"?[T>U/VlVR[V[Q쭄J[tV+b[dh[+u$ engމT .+d 6kem 쭝-%l%L g%}K  2jTfXgK,3 T0Q-x3r&RDR;T T)RUTD` $"B$,B$"B $"BbeJSGbȪGIDtH"::,_Фj8iD` endstream endobj 708 0 obj <> endobj 714 0 obj <> endobj 715 0 obj <> endobj 713 0 obj <>/Length 476>>stream 2N:AAmI""+,2lQ/ʔүz_T/*Y+eJRR!KeHV;lS5HV̱ 6_VҒ[[J_쭬[XKT+demU/emQ/#EDt $(_hڇD쭅*_-N]-[,2V+eIRV?3Dt+b+bFA![쭊%elO2%-lKel2 [H4*emG/ -l[N2Keo@@ ͺ m)EA* e!d`R:(Y!!dHD`!O12%h#dUR#h":iHJhRH5N4"0 endstream endobj 712 0 obj <>/Length 402>>stream XDuWKT:K | |G_~rP~Duue`"넿RK_K}":K_J\/)pU)rR})Z\]vRl֙K\ vu.K[g\t׬+rf_x`λi% T&82VMc%"PU! ?;cAyAjݝ޹SEM4TS\!dP $"HY!"B(ZL%(ih'H#R#Dt?}_#Hѵ i6hh """""# endstream endobj 716 0 obj <> endobj 722 0 obj <> endobj 723 0 obj <> endobj 721 0 obj <>/Length 3265>>stream xݿ%񳕨lE!AD""T$J>_B([DNAPQ*h($4B|5Μ{=^s(sg^3yk?]Xo… U6LgkcVڃs=========={k^{饗nִMnL8?_y]6}'v\%﷽vŋnLܩ3v, ߎ;S^榷}/~w8yev_ʯzO>矯ޯ3p\}W_=/'~W^}뭷o/⧟~j 'bwmaIᖿnv{aǞ{̸8smۿwyGi|'v846>m_-;/n/W{7<C=̅8p0țolc=6,/s=G;Zmq~xm\w8>Uy'u]m?>얝޸>='=>3k?rh 1l}{ʕW_}m0 Xcnvkn9Ic8iųmo϶O=xٸ& 7얝<}<nwc ߶>~kUcioHoܧ=yiLMwgѓ-Mgnexl@W{o.<{_ ~hO1>vsF]jox7Thi/iv7B[?sT sGx{;]|M馛.^x }ўm ;0!zj{0t|(6S8F[{[y ]Wl_~o> 7h]ko\v>kM&N͵ojVƍ;yҨ}Z-}Gd=/{åKvJ,˕+W~_ގ5555555555555555555555555555βZVe 9 _o9}hjhjk[ט7xc݆qҥ7zk?ow>9G2[UR{=z=================PõFsNB{R+,麪Kڃ>c>[ڃڃڃڃyG F͇sG_G&|I{1_{d^G&|I{1_{d^G&|I{1_{dꪽ ~e]푩 VXE{d갽zr.5Uzkom1=K{y{+1Twj#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#b[{+DfU{+#Vm{[Ǣk³pw9]*t]ՑI{U{+1p8zkԴG2|I{1_{d^G&|I{1_{d^G&|I{1_{d^G&|I{1_{d^G&|푩6^&pGۛ.ZI,VW.5Ưw.kR;XڋGs]jHW\[{=i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bg{kwE鰽!S6]K{dꭽ˴h^=2u<9ezkokd]7_X{,V|R)hdڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#Soͯ,SWͯZI,VW͗a{=BMw]jۛ.:2u՞Z8 ]NM{$^G&|I{1_{d^G&|I{1_{d^G&|I{1_{d^m{h6.)Q΄b>.-|I{1_{dꭽ3f8W]wJ窫k^,=2޸>ץNyE魽Ŵbui-jL]L{1_{d^G&|I{1_{d^G&|I{1_{d^G&|I{1_{d^G&|I{1_{d갽%[/\3E魽4)cjopǢt|IXޞRSۛG&Z#S|Ruhdڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#bȤ=2i/kLڋ#Sfy{bi/>/Length 340>>stream fDu.߯~?/莡?KG_PKG_fG^}(Dt]KKK/zZW]K ]0 L  . J&.JDkd.\y;$ !`cfMDTTEMrB$"!HEB$"B4^j_Z4DP2RDt*DtH#^#kDu56m&ѵmMDDDDDD` endstream endobj 724 0 obj <> endobj 730 0 obj <> endobj 731 0 obj <> endobj 729 0 obj <>/Length 3033>>stream xݽeI%TjQ AID1X)~ZZ.V/}pxqޏ{ٹ"3{&̙2dw̙Mx s:qA?c-䘹)awy/۷o_r>לe'-/ԟٳ/^,O<1,,+\t_8쯏ZrB駟w7nh㫯Xn [;In)z˖&Sw&Y_F(zreYއ4^8Zvew\]TERݳ>;m[U)Zwұ?9eh݌}kl6G۰u~4ŕ|Yvoh7裏{W~MiȳopG_͛7_|qr;S(;~-|ݵ͊Q7-_" ay9]v֭[wqGyQ:)au~uWGUFSt~+oÿe=U~?+mE*n'3Mx#E9zj9 K)]ȏ5ȯ'?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?H#?Hs \˪s1 Z~uۋKNiH%%Ep{`̓qw}$mzj ^OCʾ-?Q#n}uuu[x5vN~j 3OA^7.vpǪk?&KQ~+CAAA{7"`S}~O M&הol}u[Ѻz+ʵG*ׯ6,?jXW ,apG?X;F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~F~R~ײuu[]'A~ ,s44z4>x᛬&lvcC+/&?*_L~T @~1QbGɏ /&?*_L~T @~1QbGɏ /&?*_L~T @~1QbGɏ /&?*_L~T @~1QbGk~cjmGO>GUV^p%u[Uj;/++?cGɏ /&?*_L~T @~1QbGɏ /&?*_L~T @~1QbGɏ /&?*_L~T @~1QbGɏ /&?*_L~T @~1Qbz-^_V빻;U#~eɏ9tp%u^~+G>xɏ |zK:/>\~s Xṕb7/>\~s Xṕb7/>\~s Xṕb7/>\~s Xṕbym/^ϓb[ْ_,}x>[oqgK~-Nzl/>[-҇8y%X'o=|K䭇ϖb[ْ_,}x>[oqgK~-Nekڿݑb[𬃶b[pv.9_V~6<%kN~3mxf:2`8ቛlq>!{. ' -:vf44l';NCg{vg~ 4444444->{^f,ȕ??6'l[{xTi4444444444444444Wq`FT#?H#?H#?H#?H?u V endstream endobj 728 0 obj <>/Length 3525>>stream xݿeM1U,M,`j&-,-cJ@0&RL6hi_ 3{} 9?f}3q?!hA{@ bt;tPԦwrfE{hA{@ bĠ= 1hA{@ u~=z~>_|q8ݻw?N9t[⹮Qi϶LL:vK?yŋ{nqpC'Nqƅ 2k[v?|޽Ǐ_|v><(=޿7ln,>SW\)?[5c߷oO>Ǐng端/ʷW^}w2/_nzua>kzӧ=zꫯXYg}V/8뚏l~=ڳ^(3,=~o#[{z7}ӼҞ+_v_Q}_~LC2Ç+E'O,\{QdE?y^mzo?ܻ?lsuxg6pG^-ll~勲#j96lm{v~2'o01-@{ʵ-= 1hA{@ bʩS,C:Jio<C: ThOB{Bh/B{ОK^*'R=! ThOB{Bh/B{Оgls㎅xW= h(ўc,D׹es ?"[5.CО-e8^  {#=!| ThOB{Bh/B{ОK^*'R=! ThOB{Bh/B{ОK^*'R=! ThOB{Bh/B{ОK^*'sB{B8/u*'$`7"v 0ڛ ~km̴LhOﵤB{B!gОK^*'R=! ThOB{Bh/B{ОK^*'R=! ThOB{Bh/B{ОK^*'R=! ThOH9+OH{=!1xmğ~LhOHX{O8/hOk{.9uB{B[$B {! qzm>ge G{Bl=B{ОK^*'R=! ThOB{Bh/B{ОK^*'R=! =o%!mwiOybBhOy=F{0`hО7ڃ=oC{hܸE`v~Nڃq:7n,Ի|^jڃ>=ڃi{Cސir^0ͭ=koYoW5Bhot~sr 0C{0Nsk {=F{0`hО7ڃ=oC{h y=F{0`hО7ڃ=oC{h y=F{0`hО7ڃ=o^לonڳҖw =ަ6I{01ǜ87syg[6Bhot3mdO'srV.3^Uͭ{=F{0`hО7ڃ=oC{h y=F{0`hО7ڃ=oC{h y=F{0`hО7ڃ=oC{hƯ=ihƩ58/VΣB{9椽ͭL XjknhfotNI;hmg u6:syg^hF^ {Wy^hf5փՉN5B{uS^T=!W':hOՉN5B{uS^T=!W':hOՉN5B{uS^T=!W':hOՉN5B{uS^T=!W':hOՉN5B{uS>4\q^\q6:.;[>ga5_s^jGz9e!Rj'd~oGz9G{΃+sWy,s5}pő|hNtўګj'D :ѩF{BhNtўګj'D :ѩF{BhNtўګj'D :ѩF{BhNtўګj'D dw n/$tpő|hNtўګj'D :ѩF{BhNtўګj'$3$tpő|bԉ'+s2t#O:[~@Ӎl/7ho\^`@>slo*#O:ȓٴ7Ǒ'\qIObxWys`bĠ= 1hO2t#2" _LM墏ϿPä]n èw6ګb"r{)k:W1?hBۼp$#*}֬u<ࣣ*$FV|L^O4d[hxL|` bĠ= 1hA{@ bĠ= 1hA{@9n+ַ1hA{@ bא endstream endobj 732 0 obj <> endobj 737 0 obj <> endobj 738 0 obj <> endobj 736 0 obj <>/Length 3676>>stream x?TCE VF-,kaA20ZX@BBB4@JcaFbA-Oɹ~tɣGn޼y+W~Çssy+.O?/E/ӡ_;vlg4O31m]>|0}ȑW_}֭[\^yKahz?Lu9sƍ{}Gv6 i34aiOoǏ1_v^J-zt]zO/Bw^Ko{!]߯ͿwΝ;sM/\.^?W~W^yLL7}ۏ}зoΑ'?7]soa[믟ytaoVzMl"o&Q?=v𩧞JMp#&]kxW,':thⱑ*"of{iwO?mO~f۟;wخg4tgS+Ҳ ;YZJ?L~Yy~-kp4oC!Hc7v}NomZ])/pEkܮ`SM7ӧOᗫ3 0s+oݕto{w}gToZOBvy%#t/Ç|Xt9^{;-nܧnt{޸{n*Mr6Wdx\qg}6rJ.~mrϷ>Sk@_z#￿[kR;|tMu?w6|NW)~ѣG?~ݦW R|ATk;ҽ v!|Yi.j֥#ҥKY}Aփ0U{7v02Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~랸}I-_uR гdG~Vk~[6/_Jp%̯ w F_3[4Ê C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~B ճ<.D~sZOVKєӓjz/پ'G4~ƈi~ݏJ /049P-Ȑ C~Nr]q@w 8zO`O`O`O`O`O`O`O`O`O`O`O`O`O`O`O`O`O`O`xOYFc"^`OC~5o/0F~0=BßFDs VL4?!?Iw=B׾gv_ oӋ GCWtJ^bE~5Xx#C#|v9; ?                       xO@c<5E~54?^(_Zr5}1y1nˏՂh^` /0&A~0 ='/0F~0]`7CC~)q_$W@~>G~X ?a#?,|@~>G~X ?a#?,|@~>G~Xr };$?,`,Mϴ;2D~{}U_˘{ e9~l/0F~t(~,ǫ%+_`9<^-o5jgw"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?"?Z.?sO%.ǫP~YM/0F~YWKsMc%.ǫi~֯xG~xÃjgw"?"?"?"?"?"?"?"?"?"?"?"?"?"??d+k|XsVr9#?h+q9>5Vr9#?h+q9񜑟O~x'?J\sVr9#?h+q9񜑟O~x'?J\s+hq_A厓 Z.w|Wr#.?ϧ{6xוVZ=uro)/-d;^r‹'u~Af' (\b_%.;٬%.; ?@d!?@dJo?߲1^f/*/_Ǜn] u7Y}M2"׻]}Lf/WʏeyǻW|4bϫNCAݟ\~:Ho_gQ"v0h5ϫN+q2,jx˿Vx)sߒ 77\}q >Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2Ȑ C~ 2S["=?!?@d/ endstream endobj 739 0 obj <> endobj 743 0 obj <> endobj 744 0 obj <> endobj 748 0 obj <> endobj 749 0 obj <> endobj 753 0 obj <> endobj 754 0 obj <> endobj 758 0 obj <> endobj 759 0 obj <> endobj 763 0 obj <> endobj 764 0 obj <> endobj 768 0 obj <> endobj 769 0 obj <> endobj 773 0 obj <> endobj 774 0 obj <> endobj 778 0 obj <> endobj 779 0 obj <> endobj 783 0 obj <> endobj 784 0 obj <> endobj 788 0 obj <> endobj 789 0 obj <> endobj 793 0 obj <> endobj 794 0 obj <> endobj 798 0 obj <> endobj 799 0 obj <> endobj 803 0 obj <> endobj 804 0 obj <> endobj 808 0 obj <> endobj 809 0 obj <> endobj 813 0 obj <> endobj 814 0 obj <> endobj 818 0 obj <> endobj 819 0 obj <> endobj 823 0 obj <> endobj 824 0 obj <> endobj 828 0 obj <> endobj 829 0 obj <> endobj 833 0 obj <> endobj 834 0 obj <> endobj 839 0 obj <> endobj 840 0 obj <> endobj 838 0 obj <>/Length 24203>>stream xlU}Foi  ڄLjFj+-Z%ZaX#M(+.qL 07@~Ѳ sϹϹscsϹ>E2@EK/?S2я~IhQPiw~_4{*PQPiE>ڵk=-ՏQOi?i>OՈ"x(rFVQE^9HLNN^|;11jժ*4{*D^iE}}}N"#(=9:߯ߺ6y `Q: hrrimmݻwMyzz'{m޼9i888(f'(*F̊+̷Ǐ߲eKO6]ѣGmfw߾}W1yQ{UЏ۟z꩹nr;_reɒ%Ski6X\DEK.\2ۥ.] ٳ'"EG5X/f%`DEQ؍ɓ"#"EGLj"#l-4Q{DQ#255e}kԮ'i7o<::_OOOǯ `QPW ]PUdOƏ1t%fb/*dtuu('N]468H(rFQ0cџʕ+###RDR詤~{g۶m6xgi]vQDYEW(ZWEGx UDE)^(pQ{DQ \EQz "#z: "#1"x(=#`(Lj"#1"x(=#`(Lj"#1"x(=#`(Lj"#1"x(=#`(Lj"#1"x(=#`(Lj"#1"x(=#`(Lj"#@uww˿hKDE }ݧ_9rdG3QDESNuuu%Dի'&&VZU5(7pC/ @pa```Ϟ= w<ל?۶m{3Q{DQ6RD7x_4 z{{;;;O>iӦzw<׼k{|lٲz("#YTf_WE.MSo9DPGDEE ٽ{|{҅(;yhkk;ZZZ,Yŋy睶O8100 _ݻw͚5+V=Lؘ>s{{֭[m‚QdD(=(PA&x ']FFTNӡǏ >ȷGݶm~+tRS}@fcѕ+WdT-6p,4[O~–"X"! =B>zM7~ÑV]PGGn1 )2-t뭷-S{DQ6DbOzIBIaDEH3Fό҈FQ |_E.6< ֭=7j۔Μ9}|6[$2"#!TD.\(ғ.;^H/g3 G$}ٞ}gϚ-ʃΟ?K/%AQ Q w}OCڲeK| JO@'C޵k-7D 3锼[BEEGeC*(!jBټyKV\int mωFQt U떨]x(=(P5zs͙V?x9:H>x=n::1]C[PDEEJсQcW/ڟ6Uرc7lk%w}wddk׮]$:un;ȧs×m"#!%]DEEN!`(ʆ(p Q{DQ6DS"#ZŤlTP(lEѓe|*(=( FѲeFFF=!X|y&l*E_?G?"#!&PYDEEpQ,l"(TQ{DQ6DD*(=(n"EQ Q7E"`(ʆ("@eEGeCMD"#!&PYDEEpQ,l"(TQ{DQ6DD*(=(n"EQ Q7E"`(ʆ("@eEGeCMD"#!&PYDEEpQ,l"(TQ{DQ6DxɌIߖ.]nݺfOGEGeCMG.hUg DEEpQ$3N'~oWg DEEpQMT.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q eU.EX(Q ۹/;mmm׏Tm D>V!E(g||7oί}kK,BQ~Β?c\.EGeSgDQwq]w\Ro:sO+K[bMMZNrrRcI:JCɓ'\~իW:l2sdD"IKA,]4DEٔYF:[Q䋂H>{kQ Ltnq >AnٳgE7ݴ(Qtt4x |z&ͳuQ|^x>6f(@F>n%Q{DQ6x_ajjJw!|Ѭ(2ȋ(=jG:}7==̹dJ֯_bŊBQ0myEh:|Y>㉉uϿ/" )q:"|Qlٲ4R|;kŞ}Μ ^(tOi3gl߾6F򯺬\,H'>x4 T(?-xA>>~DQP.H@eϷ~3C!Qs~zW^ICtSd)`xxxhh(xÜlGOKyclΥI =\U"ySg?|rYN:$Bn)*sͯxJxH-qH@eCM.Sp4zREzM>2yk\ծM )%Hݜ&T,JO@<לQyY;(BDQG|k`;ǮC&DQ6xfib9+w  sϭ\2S)G}4zP@,{1݉Nwty( ]a)e;鼃SRvYcS")E-d)jזi65 )slFƈhSGQ+,htѣG. 1oROOOZ=:tPp3^\5*3ZF}EN"ϹsRJNkNիyƙk||昨ZvJ\Z*R@VE-d/E>7ŋ X )s0dqCɨN~="_E2ӴѬܜd{wV'9==Kڵ+7NCEL 7vQx2217333O>Lah9رcu2G. yr,udu>(Eѕ+W?3]cPDQ6x_Kh!(EQ4hr,u|Q$Ƣ۷o_Vt;ﴵ7]7!]˶uV3 '?{hs>V!ziI(BYc W"="InmڵW kdR(].\ҝ%ksN׎W\BhW^=tвe|?ӝc(_D/"UՖP(jHhޮ/Y!sw\2iΝO<\O)Tc'_U|E PVU[h@YH7o5QGQ%ueBjŞ.5XSX"E(BYUm eZEf3Q-cծT|v9cg+ǺQ/DʪjK] (qE7MMM9sL(]]^S~^c_(Q eU.8j4nB(Akx{rKE"|AЀrG;[73q\EXv7nhpН>n}SNID/O$ e[M|E"|AЀD Q/DʪjK] ` Q/DʪjK] ` Q/DʪjK] ` Q/DʪjK] ` Q/DʪjK] ` Q/DʪjK] ` Q/DʪjK] ` Q/^D8͞wo].EGeCM^Dа,u4(=(nrĉ޽{׬YbŊ3'D"#!l633{n͌IsTCO(rM7Ed^Zf͍M>}N;{ tj}ٞKH\:7n >sOC*(z"vͲe^}o=t;QDQGG֭[^$frR {Pb%LaPoow߭Œx/,|66`POC*(=(j)jNڱM >K?ʜkA^kgjz](O@*(=(jE633sر={LNN^ZK\)]sf;Oc%Μ9'9rHpUO"EQ QdT:o;w^pz' jp0<<|%x.+WS;֜.?M(TQ{DQ6DS$3y59!PzQ,JC_|EssVs΅Έ.x$̉4PYDEE6OU{f)t;OZCccc###ѣAtEh{NcS{`D2bE#˗/7{*7\ӕeH(=(1RB#?%Wk5'?x`nrJ1:;;ɥΝ;gM{u21p~b5{*EGeC5$ 'T/z v7rN8~߹&4c I~XbFݵk<;22/wMk%1Gџ͞ xo/HE?V^-i{Y(+l"(6{*1D `C2 b=(n"=z 74{ZYz bpDQc`(ʆ(>覛nj?~-Q;#!&%ׂlEa=(n"Pb~-Q;#!&%ׂlEa=(n"Pb~-Q;#!&%ׂlEa=(n"Pb~-Q;#!&%ׂlEa=(n"Pb~-Q;#!&%ׂlEa=(n"Pb~-Q;#!&%ׂlEa=(n"Pb~-夻[=p@'$_DQc`(ʆ("_ "gI[n;֬Y|"*+ (n"]xwikk3 իW.]Zre7|s={xryK/]7 |EEpQTo٩vuuy_ז,Y˅>7:K?|OOOm' M6< ~-%|K7)… ֭s1wQ Q7EQCܱc]weVOMM9sfhh'ذaC1Smx[Z'Nlٲ%tccf~--\կ~uɒ%c6Rf~-ym޼ytttzz:E\Qg;x(ʆ(7C,d_`EWjժcccw_kk'ï4o96xq#š I/oݺ5q) [O7?u|-? M@05,ݱcGKKKNZ"|EEpQde22۷o_=u}Z֒7ۃ+,2aΝ2.3Lƣ>*g(j>.-VO S^aE~-Ms"x9]0<ҿã7-tF{{Ç屺q5CM(2ɯ!!&IGWf_<Y{n]iE`ѕFѡΞ=Pyg}V~P>NN\5:::_r}lhJDQG~[Vg;x(ʆ("#B-xg I8G /䢛nC+EW{n&<ңv^/C}M膲*9 ҏ"yuଁ(tBEQFEk4u|8X"ƑD G|ܝ&tk=@\}fݺuz C,M90]'+{䁚e{Z uLs87C'ǶSQ433Oӹ{ӦM1=>:Ͼ|(=(rDK/twE(2dn7Ojg GU&2o/_lvjʩ]>%~l9zUNY;H[Hz5WgB.]Z2o{;h:sЛMGիnSg>gs'&o]sOsc>/UD⢨^ nw QM)Ȉ֑#c,Qd$QQT3zIQC+VWWc=u)cA*Q:=e;/8%g7ď)tMa8 EQBwsjpo喻;y ©Spj 3x@_m=9d4O{lڦ-_(h2(EO?]|E}NoمQ~s^jwuI]/.GtQ4 2t:;;>Νӑ,m^uصj9x`Z抴vJ"TkChHR"zu"jYBi!l4Cqbbm""XFQ"L?aGGǗ⣨6MCZBDzKooo4~wGFF%Nv:J'ލvQx2217ǎmooeKKK貭/ZOBEw#̕#Q+|Z`pYܹ3rj D5l4[ҜXV]`AE2jRTYԔ-E( G(%gNѳ,$\ɓ>WwGeScjZy5"U1EGYEׂStSoaF5lJE۷oߺuXʚEz,l{{{="kA)Ǐ_D799911DQc`(ʦ|Q$-$YiTYS(y"kA5zlsVYpy睅)$1wGeS(jii2TYQ$32( D `(j Eٔ#k,ReEFQ"kA 60Q Q7E(1D `(j EEpQkA 60Q Q7E(1D `(j EEpQkA 60Q Q7E(1D `(j EEpQkA 60Q Q7E(1D `(j EEpQkA 60Q Q7E(1D `(j EEpQkA 60Q Q7E(1D `(j EEpQkA 60Q Q7E(1Dzo{DQVDEEpQkAX͞ (ʊ(=(n"=G ͞ mݺuK.mT(=(n"Pn,$ `(ʆ("CQ Q7E"`(ʆ("@eEGeCMD"#!&PYDEEpQ,l"(TQ{DQ6DD*(=(n"EQ Q7E"`(ʆ("@eEGeCMD"#!&PYDEEpQ,l"(TQ{DQ6DD*(=(n"EQ Q7E"`(ʆ("@eEGeCMD"#!&PYDEEpQ,l"(TQ{DQ6DD*(=(n"EQ Q7E"`(ʆ("@eEGeCMD"#!&PYDEEpQ,l"(TQ{DQ6DD*(=(n"EQ Q79E_?fO<݂H>)S}G7tSDEEpQrnADQQ{DQ6DE (23+l"(B "`efVDEEpQqAD̬"#!&%よ( YEGeCMDJQ,3"`(ʆ(" "6XffEQ Q7E(1DDl̊(=(n"Pb>."`Q{DQ6DD|\E23+l"(B "`efVDEEpQqAD̬"#!&%よ( YEGeCMDJQ,3"`(ʆ(" "6XffEQ Q7E8]xwikk3 Q,VVYf.l"(g||7oί}kK,B#>XG7rʂQo;c͚5˗//r"(=(n"$}zӦMyOF`1#IXQ2I ^ 1T___ggѣG2(YDQVDEٔ W#<p wq,RMEQQۻo߾{ʕ+9_d,bXdی`-"y5Y2DQVDEٔ#WЯI8"((^9ڵkøǏ-Le\X jΝ2IA&GյʩQQ{DQ6e"#4ud,57zuT|ZEG<g ]c_xӇ4BdLLFv*͎,L uu9r}lV:8(ʊ(=(SMu04=a2kP"tENhAW^d7z/WMM՛6O)H2=z|[ul˿,cgI)Mutt{BEQFEjڵwqG"svPlذ[o-ue̗|nٲEA"/h߿f/su-E~.miN=OvQm~cH*F %8ׂL룇d~VЦ*xEf(_cu{Wpg,QPKq Q{DQ$: 1EQ q{p̙3\5zB,(҉O>NQd&)rזzHrZG>Y%GQm>%{+Wjzxn.H(2Q{DQD cYMQu\Kgxxxhh(v9Y{E[K^n16 u&&&DsW _%H[|Jy}LTPob+O>Y? n ޴iET#F#14cYG"XPQc'EHX;#p'56&^|ٜ)FhMEZ( 8o,b>j!(=$2[NiQt3Q_ZNi%&3т:oyCEAU|@0X֑TXezůԭ@@zQC+M"{1]/fj? rCU7/YGDk!(=ʤBm.7$?$W.JxuB)JxFQ ]Q,"S( I`AEQc+n/]weRA27ߔ^ . ME֫^%8|4w}Ԃ7+@S/.)9wAƔN2e~'NzzsV{k'jVC$8+b,^H2a][nMg`(BG"XQKF2[z{{>==Kڵ+tNCEV)vQxKq2ǎ 7eqlk֣\2VǝwޙQp?yr-f z/jzL y[ʿ."ܹ3sj82S!y}"#DZH5E(1DDS,  L'Od9+29Q{D8&%よ(rubdxxة"̎(=I|TQqAD9Ŝׯ7;MNNNLLoq̬"#DZH5E(1DDk\Ν5 bQ{D8&%よ( YEG!cj"Pb>."`Q{D8&%よ( YEG!cj"Pb>."`Q{D8&%よ( YEG!cj"Pb>."`Q{D8&%よ( YEG!cj"Pb>."`Q{D8&%よ( YEG!cj"Pb>."`Q{D8&%よ( YEG!cj"Pb>."`Q{D8&%よ( YH?7fO |%Qz|TQqAD̬t@8^DQ8&/%K=-[ix77{Zۿ%O~rԩfO@zٓ(j^DQnAQ쩀߈"!DQEp裛n|SEPmDQ"$ C!Q E!QT "Q/ EH@|EH@(B@(B0DE(_DE!(E"(* QD(QDQa"$ DQ"$ C!Q E!QT "Q/ EH@|EH@(B@(B0DE(_DE!(E"(* QD(QDQa"$ DQ"$ C!Q E!QT "Q/ EH@|EH@(B@(B0DE(_DE!(E"(* QD(QDQa"$ DQ"$ C!Q E!QT "Q/ EH@|EH@(B@(B0DE(_DE!(E"(* QD(QDQa"$ DQ"$ C!Q E!QT "Q/ EH@|EH@(B@(B0DE(_DE!(E"(* QD(QDQa"$ DQ"$ C!Q E!QT "Q/ EH@|EH@(B@(B0DE(_DE!(E"(* QD(QDQa"$ DQ"$ C!Q E!QT "Q/ EH@|9E~-ɟڵk $ԈEjnnŋN[[[h-8pn:@ˑ(W}_n" (o~>E (矝}#DQ܉ZӧOoڴ.\Xn]@DQaE:]reɒ%MĤy/7ͩ(ʗQ'N4c@;c 0͍7Ǐ߼ys}TDˋ(JQ8KQP^ڑUE_}ͩ(ʗQ455%õÇ~4333666444::*wغukh; {]f͊+B?77wI}رA:ZԩSu-nTno^3=)3M<(*LHf^c;|kX}f~9U"E"{zz&&&VZ]D#Ic r9[,1;_w^LNNj~P_+xӧ_ۃ9ٳ6lg~gezL?E41xmLzzy;vL~```Ϟ=kVפ~B/r73煋]}3xr<%ڵkŊѻ-%o,MD( t;O2NڹsO<R ɂ[l :::BȨHj/^6==|rK. nגScJT?EEib\zǞn!Xuؤ(Z>+WY###XTFp^蜢pFQ&`_We! ,m^}Uͪ\RG&"`OOoMG]#$3^o=m6iDU('g;"jGݭxDQaE2◁y늃-ԫcS?4IIK9XgۓӬ|)# !ofO4(ʗQ:H8FRJDaEGKsSҽ}^~eyQTa~qXHAtgzػ>{EDnh\xniVtQ&)9UGlokw=}ݦ@Er6juwzj4;v0[!/syGw!*{}z!y@'M"=-4וNQWIycօfKY Ke[GHb6oެ}n.Y.YV{2_gS^(=2qƃ>耣vmDrҥ+W9͵&%TΜ9#}UO#G;EQ}dN|e˖%QSH;(zZ(JŽ182':2 E!u$2ַ?Ϝ;1aV- $EE FbΫWGGQɸ =x:z:8K>Cv:%=ҌBCU\pN4b)QPERF$łu~ծv Ջ9n{{?+҂'' }-hvϓYi({E/_l"\dlc@vѣHW/uoݓ{dcʗT%2Xy|sCs2[A`5F^!'|Rb&tE|dҴ(PoQ{/XV|Dw0#k.SOvPtmH7M@j渣'lt2ϦO.SG;wN?!^uOUցyyU6 " #KEz0wJ߁-$Q^{PrXN|p E:EzKv8J.%ZcT1-d;gy/LskڵD*X/CMS5-5!^y啖_YկGӣ(کYWkloaʽ\+O;==JرcNzzte[./ˀ\R^7STzcp sJ mٲE>I"wuzq[c bo e ҡcW>fޑo?D^}ٲezR,a< EnuCق+_ @Y[0? 7&YpTpv^W` Q$/Q^,~;=}!,FQ̍EQp-u- fJPtZb'8==<͟NB"}&VH ɓӼ<|/9x1h _|Q&Ɯ?n+_ @Y FQZH EP'"M~:z)k"K91f]HƟΒ,_-d8E/EF(DEdNJh!(BtebsLQ(jW`(jFQQDK. ӕjDPaDQ#֭[BQDQa"$OW26)b9|EH@Qp},(*(¬&Bg\,&8 (_DE)w-x}$#\! ?ׯu;=1C}<ꫯIz y2Xb,E"(*LRkO_v鼶 e襄ͷ"4f@OÛ-(* Q+/",:QDQ-p … ]]]o1Ö.]Zw QTGQ֕  kfffŊ8(W98hӉ6ET֭;(*LӣrajjG]pB*ő.(W(؇E$ B#T * (_UC@,0G {V * (_cC !x!֭[7m/Z0G TDQJEݳjǎ9hӳvکAZnuttȿBׯzC-[fw0~EQ(eF8u|]ۛCΥKV\Y `V7$kXpdzNZ=55uԩze[L¸EfB 2/Y; s2+NຆZj[:<@( DQ"$ (*=, (_DE!uWx=EA(B0DQ޼ '(|EH@(ʛ]Q/ EJ~7E(_DE!SE(_DE!(ڱBAD3 01 N~{=u[A+.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E.QD ƈ"Q(Eh("E#XK""Q(:h NM 8z^.[8#&^\S;>X^QzL~WpjmED5QlM[ED5QlM[ED5QlM[ED_| endstream endobj 841 0 obj <> endobj 845 0 obj <> endobj 846 0 obj <> endobj 850 0 obj <> endobj 851 0 obj <> endobj 855 0 obj <> endobj 856 0 obj <> endobj 860 0 obj <> endobj 861 0 obj <> endobj 865 0 obj <> endobj 866 0 obj <> endobj 870 0 obj <> endobj 871 0 obj <> endobj 875 0 obj <> endobj 876 0 obj <> endobj 880 0 obj <> endobj 881 0 obj <> endobj 885 0 obj <> endobj 886 0 obj <> endobj 890 0 obj <> endobj 891 0 obj <> endobj 895 0 obj <> endobj 896 0 obj <> endobj 900 0 obj <> endobj 901 0 obj <> endobj 905 0 obj <> endobj 906 0 obj <> endobj 910 0 obj <> endobj 911 0 obj <> endobj 915 0 obj <> endobj 916 0 obj <> endobj 920 0 obj <> endobj 921 0 obj <> endobj 925 0 obj <> endobj 926 0 obj <> endobj 930 0 obj <> endobj 931 0 obj <> endobj 935 0 obj <> endobj 936 0 obj <> endobj 940 0 obj <> endobj 941 0 obj <> endobj 945 0 obj <> endobj 946 0 obj <> endobj 950 0 obj <> endobj 951 0 obj <> endobj 955 0 obj <> endobj 956 0 obj <> endobj 960 0 obj <> endobj 961 0 obj <> endobj 965 0 obj <> endobj 966 0 obj <> endobj 970 0 obj <> endobj 971 0 obj <> endobj 975 0 obj <> endobj 976 0 obj <> endobj 980 0 obj <> endobj 981 0 obj <> endobj 985 0 obj <> endobj 986 0 obj <> endobj 990 0 obj <> endobj 991 0 obj <> endobj 995 0 obj <> endobj 996 0 obj <> endobj 1000 0 obj <> endobj 1001 0 obj <> endobj 1005 0 obj <> endobj 1006 0 obj <> endobj 1010 0 obj <> endobj 1011 0 obj <> endobj 1015 0 obj <> endobj 1016 0 obj <> endobj 1020 0 obj <> endobj 1021 0 obj <> endobj 1025 0 obj <> endobj 1026 0 obj <> endobj 1030 0 obj <> endobj 1031 0 obj <> endobj 1035 0 obj <> endobj 1036 0 obj <> endobj 1040 0 obj <> endobj 1041 0 obj <> endobj 1045 0 obj <> endobj 1046 0 obj <> endobj 1050 0 obj <> endobj 1051 0 obj <> endobj 1055 0 obj <> endobj 1056 0 obj <> endobj 1060 0 obj <> endobj 1061 0 obj <> endobj 1065 0 obj <> endobj 1066 0 obj <> endobj 1070 0 obj <> endobj 1071 0 obj <> endobj 1075 0 obj <> endobj 1076 0 obj <> endobj 1080 0 obj <> endobj 1081 0 obj <> endobj 1085 0 obj <> endobj 1086 0 obj <> endobj 1090 0 obj <> endobj 1091 0 obj <> endobj 1095 0 obj <> endobj 1096 0 obj <> endobj 1100 0 obj <> endobj 1101 0 obj <> endobj 1105 0 obj <> endobj 1106 0 obj <> endobj 1110 0 obj <> endobj 1111 0 obj <> endobj 1115 0 obj <> endobj 1116 0 obj <> endobj 1120 0 obj <> endobj 1121 0 obj <> endobj 1125 0 obj <> endobj 1126 0 obj <> endobj 1130 0 obj <> endobj 1131 0 obj <> endobj 1135 0 obj <> endobj 1136 0 obj <> endobj 1140 0 obj <> endobj 1141 0 obj <> endobj 1145 0 obj <> endobj 1146 0 obj <> endobj 1150 0 obj <> endobj 1151 0 obj <> endobj 1155 0 obj <> endobj 1156 0 obj <> endobj 1160 0 obj <> endobj 1161 0 obj <> endobj 1165 0 obj <> endobj 1166 0 obj <> endobj 1170 0 obj <> endobj 1171 0 obj <> endobj 1175 0 obj <> endobj 1176 0 obj <> endobj 1180 0 obj <> endobj 1181 0 obj <> endobj 1185 0 obj <> endobj 1186 0 obj <> endobj 1190 0 obj <> endobj 1191 0 obj <> endobj 1195 0 obj <> endobj 1196 0 obj <> endobj 1200 0 obj <> endobj 1201 0 obj <> endobj 1205 0 obj <> endobj 1206 0 obj <> endobj 1210 0 obj <> endobj 1211 0 obj <> endobj 1215 0 obj <> endobj 1216 0 obj <> endobj 1220 0 obj <> endobj 1221 0 obj <> endobj 1225 0 obj <> endobj 1226 0 obj <> endobj 1230 0 obj <> endobj 1231 0 obj <> endobj 1235 0 obj <> endobj 1236 0 obj <> endobj 1240 0 obj <> endobj 1241 0 obj <> endobj 64 0 obj <> endobj 31 0 obj <> endobj 30 0 obj <> endobj 1242 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 155 0 obj <> endobj 53 0 obj <> endobj 42 0 obj <> endobj 1243 0 obj <>stream Name not found%%EndComments nyquistman.mss endstream endobj 2 0 obj <>endobj xref 0 1244 0000000000 65535 f 0000549639 00000 n 0000619272 00000 n 0000547627 00000 n 0000507266 00000 n 0000000015 00000 n 0000000387 00000 n 0000549706 00000 n 0000617558 00000 n 0000617623 00000 n 0000549747 00000 n 0000549777 00000 n 0000507426 00000 n 0000000406 00000 n 0000000586 00000 n 0000549816 00000 n 0000549846 00000 n 0000507588 00000 n 0000000606 00000 n 0000003032 00000 n 0000549876 00000 n 0000549906 00000 n 0000507750 00000 n 0000003053 00000 n 0000003264 00000 n 0000549945 00000 n 0000549975 00000 n 0000507912 00000 n 0000003284 00000 n 0000005769 00000 n 0000617365 00000 n 0000617302 00000 n 0000550005 00000 n 0000550035 00000 n 0000508074 00000 n 0000005790 00000 n 0000008018 00000 n 0000550096 00000 n 0000550126 00000 n 0000508236 00000 n 0000008039 00000 n 0000010407 00000 n 0000617823 00000 n 0000550176 00000 n 0000550206 00000 n 0000508398 00000 n 0000010428 00000 n 0000012626 00000 n 0000550267 00000 n 0000550297 00000 n 0000508560 00000 n 0000012647 00000 n 0000015006 00000 n 0000617755 00000 n 0000550347 00000 n 0000550377 00000 n 0000508722 00000 n 0000015027 00000 n 0000016720 00000 n 0000550438 00000 n 0000550468 00000 n 0000508884 00000 n 0000016741 00000 n 0000018108 00000 n 0000617230 00000 n 0000550529 00000 n 0000550559 00000 n 0000509046 00000 n 0000018129 00000 n 0000019909 00000 n 0000550642 00000 n 0000550672 00000 n 0000509208 00000 n 0000019930 00000 n 0000020661 00000 n 0000550733 00000 n 0000550763 00000 n 0000509370 00000 n 0000020681 00000 n 0000020875 00000 n 0000550815 00000 n 0000550845 00000 n 0000509532 00000 n 0000020895 00000 n 0000023364 00000 n 0000550875 00000 n 0000550905 00000 n 0000509694 00000 n 0000023385 00000 n 0000025676 00000 n 0000550966 00000 n 0000550996 00000 n 0000509856 00000 n 0000025697 00000 n 0000028308 00000 n 0000551057 00000 n 0000551087 00000 n 0000510018 00000 n 0000028329 00000 n 0000030961 00000 n 0000551148 00000 n 0000551179 00000 n 0000510182 00000 n 0000030982 00000 n 0000031767 00000 n 0000551232 00000 n 0000551263 00000 n 0000510348 00000 n 0000031788 00000 n 0000031985 00000 n 0000551305 00000 n 0000551336 00000 n 0000510514 00000 n 0000032006 00000 n 0000034989 00000 n 0000551367 00000 n 0000551398 00000 n 0000510680 00000 n 0000035011 00000 n 0000037889 00000 n 0000551460 00000 n 0000551491 00000 n 0000510846 00000 n 0000037911 00000 n 0000040349 00000 n 0000551564 00000 n 0000551595 00000 n 0000511012 00000 n 0000040371 00000 n 0000042783 00000 n 0000551657 00000 n 0000551688 00000 n 0000511178 00000 n 0000042805 00000 n 0000045298 00000 n 0000551761 00000 n 0000551792 00000 n 0000511344 00000 n 0000045320 00000 n 0000047700 00000 n 0000551854 00000 n 0000551885 00000 n 0000511510 00000 n 0000047722 00000 n 0000050598 00000 n 0000551947 00000 n 0000551978 00000 n 0000511676 00000 n 0000050620 00000 n 0000053443 00000 n 0000552029 00000 n 0000552060 00000 n 0000511842 00000 n 0000053465 00000 n 0000056493 00000 n 0000617689 00000 n 0000552122 00000 n 0000552153 00000 n 0000512008 00000 n 0000056515 00000 n 0000058969 00000 n 0000552217 00000 n 0000552248 00000 n 0000512174 00000 n 0000058991 00000 n 0000062332 00000 n 0000552310 00000 n 0000552341 00000 n 0000512340 00000 n 0000062354 00000 n 0000062551 00000 n 0000552416 00000 n 0000552447 00000 n 0000512506 00000 n 0000062572 00000 n 0000064541 00000 n 0000552478 00000 n 0000552509 00000 n 0000512672 00000 n 0000064563 00000 n 0000066510 00000 n 0000552582 00000 n 0000552613 00000 n 0000512838 00000 n 0000066532 00000 n 0000068499 00000 n 0000552675 00000 n 0000552706 00000 n 0000513004 00000 n 0000068521 00000 n 0000070720 00000 n 0000552768 00000 n 0000552799 00000 n 0000513170 00000 n 0000070742 00000 n 0000072573 00000 n 0000552861 00000 n 0000552892 00000 n 0000513336 00000 n 0000072595 00000 n 0000074920 00000 n 0000552945 00000 n 0000552976 00000 n 0000513502 00000 n 0000074942 00000 n 0000077257 00000 n 0000553038 00000 n 0000553069 00000 n 0000513668 00000 n 0000077279 00000 n 0000079827 00000 n 0000553120 00000 n 0000553151 00000 n 0000513834 00000 n 0000079849 00000 n 0000081649 00000 n 0000553193 00000 n 0000553224 00000 n 0000514000 00000 n 0000081671 00000 n 0000081868 00000 n 0000553266 00000 n 0000553297 00000 n 0000514166 00000 n 0000081889 00000 n 0000084413 00000 n 0000553328 00000 n 0000553359 00000 n 0000514332 00000 n 0000084435 00000 n 0000086196 00000 n 0000553421 00000 n 0000553452 00000 n 0000514498 00000 n 0000086218 00000 n 0000087941 00000 n 0000553525 00000 n 0000553556 00000 n 0000514664 00000 n 0000087963 00000 n 0000090400 00000 n 0000553629 00000 n 0000553660 00000 n 0000514830 00000 n 0000090422 00000 n 0000092636 00000 n 0000553722 00000 n 0000553753 00000 n 0000514996 00000 n 0000092658 00000 n 0000094643 00000 n 0000553815 00000 n 0000553846 00000 n 0000515162 00000 n 0000094665 00000 n 0000097461 00000 n 0000553908 00000 n 0000553939 00000 n 0000515328 00000 n 0000097483 00000 n 0000098804 00000 n 0000553992 00000 n 0000554023 00000 n 0000515494 00000 n 0000098826 00000 n 0000100999 00000 n 0000554085 00000 n 0000554116 00000 n 0000515660 00000 n 0000101021 00000 n 0000103095 00000 n 0000554178 00000 n 0000554209 00000 n 0000515826 00000 n 0000103117 00000 n 0000105806 00000 n 0000554271 00000 n 0000554302 00000 n 0000515992 00000 n 0000105828 00000 n 0000108559 00000 n 0000554375 00000 n 0000554406 00000 n 0000516158 00000 n 0000108581 00000 n 0000111811 00000 n 0000554479 00000 n 0000554510 00000 n 0000516324 00000 n 0000111833 00000 n 0000114562 00000 n 0000554574 00000 n 0000554605 00000 n 0000516490 00000 n 0000114584 00000 n 0000117498 00000 n 0000554669 00000 n 0000554700 00000 n 0000516656 00000 n 0000117520 00000 n 0000120813 00000 n 0000554773 00000 n 0000554804 00000 n 0000516822 00000 n 0000120835 00000 n 0000123630 00000 n 0000554868 00000 n 0000554899 00000 n 0000516988 00000 n 0000123652 00000 n 0000126252 00000 n 0000554952 00000 n 0000554983 00000 n 0000517154 00000 n 0000126274 00000 n 0000129609 00000 n 0000555045 00000 n 0000555076 00000 n 0000517320 00000 n 0000129631 00000 n 0000132481 00000 n 0000555129 00000 n 0000555160 00000 n 0000517486 00000 n 0000132503 00000 n 0000135659 00000 n 0000555224 00000 n 0000555255 00000 n 0000517652 00000 n 0000135681 00000 n 0000138884 00000 n 0000555317 00000 n 0000555348 00000 n 0000517818 00000 n 0000138906 00000 n 0000142172 00000 n 0000555421 00000 n 0000555452 00000 n 0000517984 00000 n 0000142194 00000 n 0000144533 00000 n 0000555505 00000 n 0000555536 00000 n 0000518150 00000 n 0000144555 00000 n 0000146685 00000 n 0000555598 00000 n 0000555629 00000 n 0000518316 00000 n 0000146707 00000 n 0000149408 00000 n 0000555682 00000 n 0000555713 00000 n 0000518482 00000 n 0000149430 00000 n 0000152557 00000 n 0000555766 00000 n 0000555797 00000 n 0000518648 00000 n 0000152579 00000 n 0000155587 00000 n 0000555859 00000 n 0000555890 00000 n 0000518814 00000 n 0000155609 00000 n 0000159076 00000 n 0000555943 00000 n 0000555974 00000 n 0000518980 00000 n 0000159098 00000 n 0000161063 00000 n 0000556027 00000 n 0000556058 00000 n 0000519146 00000 n 0000161085 00000 n 0000163800 00000 n 0000556111 00000 n 0000556142 00000 n 0000519312 00000 n 0000163822 00000 n 0000166772 00000 n 0000556204 00000 n 0000556235 00000 n 0000519478 00000 n 0000166794 00000 n 0000169755 00000 n 0000556288 00000 n 0000556319 00000 n 0000519644 00000 n 0000169777 00000 n 0000172563 00000 n 0000556372 00000 n 0000556403 00000 n 0000519810 00000 n 0000172585 00000 n 0000175860 00000 n 0000556465 00000 n 0000556496 00000 n 0000519976 00000 n 0000175882 00000 n 0000181237 00000 n 0000556560 00000 n 0000556591 00000 n 0000520142 00000 n 0000181259 00000 n 0000183999 00000 n 0000556666 00000 n 0000556697 00000 n 0000520308 00000 n 0000184021 00000 n 0000186752 00000 n 0000556770 00000 n 0000556801 00000 n 0000520474 00000 n 0000186774 00000 n 0000189842 00000 n 0000556865 00000 n 0000556896 00000 n 0000520640 00000 n 0000189864 00000 n 0000193218 00000 n 0000556958 00000 n 0000556989 00000 n 0000520806 00000 n 0000193240 00000 n 0000195690 00000 n 0000557051 00000 n 0000557082 00000 n 0000520972 00000 n 0000195712 00000 n 0000198290 00000 n 0000557135 00000 n 0000557166 00000 n 0000521138 00000 n 0000198312 00000 n 0000201000 00000 n 0000557239 00000 n 0000557270 00000 n 0000521304 00000 n 0000201022 00000 n 0000204058 00000 n 0000557334 00000 n 0000557365 00000 n 0000521470 00000 n 0000204080 00000 n 0000207820 00000 n 0000557427 00000 n 0000557458 00000 n 0000521636 00000 n 0000207842 00000 n 0000210871 00000 n 0000557531 00000 n 0000557562 00000 n 0000521802 00000 n 0000210893 00000 n 0000214031 00000 n 0000557615 00000 n 0000557646 00000 n 0000521968 00000 n 0000214053 00000 n 0000217464 00000 n 0000557708 00000 n 0000557739 00000 n 0000522134 00000 n 0000217486 00000 n 0000220914 00000 n 0000557792 00000 n 0000557823 00000 n 0000522300 00000 n 0000220936 00000 n 0000224136 00000 n 0000557887 00000 n 0000557918 00000 n 0000522466 00000 n 0000224158 00000 n 0000227218 00000 n 0000557971 00000 n 0000558002 00000 n 0000522632 00000 n 0000227240 00000 n 0000230359 00000 n 0000558075 00000 n 0000558106 00000 n 0000522798 00000 n 0000230381 00000 n 0000233396 00000 n 0000558159 00000 n 0000558190 00000 n 0000522964 00000 n 0000233418 00000 n 0000236400 00000 n 0000558243 00000 n 0000558274 00000 n 0000523130 00000 n 0000236422 00000 n 0000239380 00000 n 0000558347 00000 n 0000558378 00000 n 0000523296 00000 n 0000239402 00000 n 0000242217 00000 n 0000558442 00000 n 0000558473 00000 n 0000523462 00000 n 0000242239 00000 n 0000244766 00000 n 0000558535 00000 n 0000558566 00000 n 0000523628 00000 n 0000244788 00000 n 0000247157 00000 n 0000558619 00000 n 0000558650 00000 n 0000523794 00000 n 0000247179 00000 n 0000249482 00000 n 0000558712 00000 n 0000558743 00000 n 0000523960 00000 n 0000249504 00000 n 0000250546 00000 n 0000558805 00000 n 0000558836 00000 n 0000524126 00000 n 0000250567 00000 n 0000253803 00000 n 0000558887 00000 n 0000558918 00000 n 0000524292 00000 n 0000253825 00000 n 0000254708 00000 n 0000558980 00000 n 0000559011 00000 n 0000524458 00000 n 0000254729 00000 n 0000257258 00000 n 0000559064 00000 n 0000559095 00000 n 0000524624 00000 n 0000257280 00000 n 0000259753 00000 n 0000559146 00000 n 0000559177 00000 n 0000524790 00000 n 0000259775 00000 n 0000262015 00000 n 0000559239 00000 n 0000559270 00000 n 0000524956 00000 n 0000262037 00000 n 0000264423 00000 n 0000559332 00000 n 0000559363 00000 n 0000525122 00000 n 0000264445 00000 n 0000267062 00000 n 0000559425 00000 n 0000559456 00000 n 0000525288 00000 n 0000267084 00000 n 0000269074 00000 n 0000559518 00000 n 0000559549 00000 n 0000525454 00000 n 0000269096 00000 n 0000270404 00000 n 0000559622 00000 n 0000559653 00000 n 0000525620 00000 n 0000270426 00000 n 0000271586 00000 n 0000559704 00000 n 0000559735 00000 n 0000525786 00000 n 0000271608 00000 n 0000273335 00000 n 0000559788 00000 n 0000559819 00000 n 0000525952 00000 n 0000273357 00000 n 0000275352 00000 n 0000559881 00000 n 0000559912 00000 n 0000526118 00000 n 0000275374 00000 n 0000277572 00000 n 0000559985 00000 n 0000560016 00000 n 0000526284 00000 n 0000277594 00000 n 0000280242 00000 n 0000560067 00000 n 0000560098 00000 n 0000526450 00000 n 0000280264 00000 n 0000282126 00000 n 0000560160 00000 n 0000560191 00000 n 0000526616 00000 n 0000282148 00000 n 0000284067 00000 n 0000560242 00000 n 0000560273 00000 n 0000526782 00000 n 0000284089 00000 n 0000287261 00000 n 0000560335 00000 n 0000560366 00000 n 0000526948 00000 n 0000287283 00000 n 0000290007 00000 n 0000560428 00000 n 0000560459 00000 n 0000527114 00000 n 0000290029 00000 n 0000290489 00000 n 0000560532 00000 n 0000560563 00000 n 0000527280 00000 n 0000290510 00000 n 0000290708 00000 n 0000560616 00000 n 0000560647 00000 n 0000527446 00000 n 0000290729 00000 n 0000293416 00000 n 0000560678 00000 n 0000560709 00000 n 0000527612 00000 n 0000293438 00000 n 0000295905 00000 n 0000560771 00000 n 0000560802 00000 n 0000527778 00000 n 0000295927 00000 n 0000298884 00000 n 0000560864 00000 n 0000560895 00000 n 0000527944 00000 n 0000298906 00000 n 0000299104 00000 n 0000560948 00000 n 0000560979 00000 n 0000528110 00000 n 0000299125 00000 n 0000301639 00000 n 0000561010 00000 n 0000561041 00000 n 0000528276 00000 n 0000301661 00000 n 0000303900 00000 n 0000561103 00000 n 0000561134 00000 n 0000528442 00000 n 0000303922 00000 n 0000306404 00000 n 0000561196 00000 n 0000561227 00000 n 0000528608 00000 n 0000306426 00000 n 0000309407 00000 n 0000561289 00000 n 0000561320 00000 n 0000528774 00000 n 0000309429 00000 n 0000311839 00000 n 0000561382 00000 n 0000561413 00000 n 0000528940 00000 n 0000311861 00000 n 0000314670 00000 n 0000561475 00000 n 0000561506 00000 n 0000529106 00000 n 0000314692 00000 n 0000318265 00000 n 0000561568 00000 n 0000561599 00000 n 0000529272 00000 n 0000318287 00000 n 0000320380 00000 n 0000561727 00000 n 0000561661 00000 n 0000561692 00000 n 0000562544 00000 n 0000529463 00000 n 0000320402 00000 n 0000321715 00000 n 0000563495 00000 n 0000562685 00000 n 0000562606 00000 n 0000562637 00000 n 0000564205 00000 n 0000529654 00000 n 0000321737 00000 n 0000322850 00000 n 0000565091 00000 n 0000564346 00000 n 0000564267 00000 n 0000564298 00000 n 0000565802 00000 n 0000529845 00000 n 0000322872 00000 n 0000324075 00000 n 0000566670 00000 n 0000565943 00000 n 0000565864 00000 n 0000565895 00000 n 0000567455 00000 n 0000530036 00000 n 0000324097 00000 n 0000325344 00000 n 0000568260 00000 n 0000567596 00000 n 0000567517 00000 n 0000567548 00000 n 0000568850 00000 n 0000530227 00000 n 0000325366 00000 n 0000326286 00000 n 0000572459 00000 n 0000568991 00000 n 0000568912 00000 n 0000568943 00000 n 0000572987 00000 n 0000530426 00000 n 0000326307 00000 n 0000326707 00000 n 0000576364 00000 n 0000573128 00000 n 0000573049 00000 n 0000573080 00000 n 0000580092 00000 n 0000530617 00000 n 0000326728 00000 n 0000328074 00000 n 0000580209 00000 n 0000580143 00000 n 0000580174 00000 n 0000584088 00000 n 0000530808 00000 n 0000328096 00000 n 0000330275 00000 n 0000584150 00000 n 0000584181 00000 n 0000530974 00000 n 0000330297 00000 n 0000333512 00000 n 0000584232 00000 n 0000584263 00000 n 0000531140 00000 n 0000333534 00000 n 0000335895 00000 n 0000584316 00000 n 0000584347 00000 n 0000531306 00000 n 0000335917 00000 n 0000338617 00000 n 0000584409 00000 n 0000584440 00000 n 0000531472 00000 n 0000338639 00000 n 0000341688 00000 n 0000584493 00000 n 0000584524 00000 n 0000531638 00000 n 0000341710 00000 n 0000344182 00000 n 0000584577 00000 n 0000584608 00000 n 0000531804 00000 n 0000344204 00000 n 0000346820 00000 n 0000584661 00000 n 0000584692 00000 n 0000531970 00000 n 0000346842 00000 n 0000350016 00000 n 0000584745 00000 n 0000584776 00000 n 0000532136 00000 n 0000350038 00000 n 0000352418 00000 n 0000584838 00000 n 0000584869 00000 n 0000532302 00000 n 0000352440 00000 n 0000354204 00000 n 0000584931 00000 n 0000584962 00000 n 0000532468 00000 n 0000354226 00000 n 0000354424 00000 n 0000585024 00000 n 0000585055 00000 n 0000532634 00000 n 0000354445 00000 n 0000357159 00000 n 0000585086 00000 n 0000585117 00000 n 0000532800 00000 n 0000357181 00000 n 0000360248 00000 n 0000585179 00000 n 0000585210 00000 n 0000532966 00000 n 0000360270 00000 n 0000363153 00000 n 0000585272 00000 n 0000585303 00000 n 0000533132 00000 n 0000363175 00000 n 0000366211 00000 n 0000585365 00000 n 0000585396 00000 n 0000533298 00000 n 0000366233 00000 n 0000369327 00000 n 0000585458 00000 n 0000585489 00000 n 0000533464 00000 n 0000369349 00000 n 0000371742 00000 n 0000585551 00000 n 0000585582 00000 n 0000533630 00000 n 0000371764 00000 n 0000374538 00000 n 0000585644 00000 n 0000585675 00000 n 0000533796 00000 n 0000374560 00000 n 0000377093 00000 n 0000585728 00000 n 0000585759 00000 n 0000533962 00000 n 0000377115 00000 n 0000378916 00000 n 0000585887 00000 n 0000585821 00000 n 0000585852 00000 n 0000610296 00000 n 0000534153 00000 n 0000378938 00000 n 0000380351 00000 n 0000610347 00000 n 0000610378 00000 n 0000534319 00000 n 0000380373 00000 n 0000382131 00000 n 0000610429 00000 n 0000610460 00000 n 0000534485 00000 n 0000382153 00000 n 0000383283 00000 n 0000610522 00000 n 0000610553 00000 n 0000534651 00000 n 0000383305 00000 n 0000383649 00000 n 0000610604 00000 n 0000610635 00000 n 0000534817 00000 n 0000383670 00000 n 0000383868 00000 n 0000610677 00000 n 0000610708 00000 n 0000534983 00000 n 0000383889 00000 n 0000386569 00000 n 0000610739 00000 n 0000610770 00000 n 0000535149 00000 n 0000386591 00000 n 0000388966 00000 n 0000610832 00000 n 0000610863 00000 n 0000535315 00000 n 0000388988 00000 n 0000392470 00000 n 0000610936 00000 n 0000610967 00000 n 0000535481 00000 n 0000392492 00000 n 0000395329 00000 n 0000611040 00000 n 0000611071 00000 n 0000535647 00000 n 0000395351 00000 n 0000398315 00000 n 0000611124 00000 n 0000611155 00000 n 0000535813 00000 n 0000398337 00000 n 0000401192 00000 n 0000611208 00000 n 0000611239 00000 n 0000535979 00000 n 0000401214 00000 n 0000404358 00000 n 0000611292 00000 n 0000611323 00000 n 0000536145 00000 n 0000404380 00000 n 0000404578 00000 n 0000611385 00000 n 0000611416 00000 n 0000536311 00000 n 0000404599 00000 n 0000407381 00000 n 0000611447 00000 n 0000611478 00000 n 0000536477 00000 n 0000407403 00000 n 0000409838 00000 n 0000611529 00000 n 0000611560 00000 n 0000536643 00000 n 0000409860 00000 n 0000410733 00000 n 0000611622 00000 n 0000611653 00000 n 0000536809 00000 n 0000410754 00000 n 0000410952 00000 n 0000611695 00000 n 0000611726 00000 n 0000536975 00000 n 0000410973 00000 n 0000413540 00000 n 0000611757 00000 n 0000611788 00000 n 0000537141 00000 n 0000413562 00000 n 0000415608 00000 n 0000611850 00000 n 0000611881 00000 n 0000537307 00000 n 0000415630 00000 n 0000418111 00000 n 0000611954 00000 n 0000611985 00000 n 0000537473 00000 n 0000418133 00000 n 0000419735 00000 n 0000612047 00000 n 0000612078 00000 n 0000537639 00000 n 0000419757 00000 n 0000420263 00000 n 0000612151 00000 n 0000612182 00000 n 0000537805 00000 n 0000420284 00000 n 0000422523 00000 n 0000612222 00000 n 0000612253 00000 n 0000537971 00000 n 0000422545 00000 n 0000424306 00000 n 0000612304 00000 n 0000612335 00000 n 0000538137 00000 n 0000424328 00000 n 0000425764 00000 n 0000612397 00000 n 0000612428 00000 n 0000538303 00000 n 0000425786 00000 n 0000427733 00000 n 0000612490 00000 n 0000612521 00000 n 0000538469 00000 n 0000427755 00000 n 0000429818 00000 n 0000612594 00000 n 0000612625 00000 n 0000538635 00000 n 0000429840 00000 n 0000431964 00000 n 0000612698 00000 n 0000612729 00000 n 0000538801 00000 n 0000431986 00000 n 0000433813 00000 n 0000612802 00000 n 0000612833 00000 n 0000538967 00000 n 0000433835 00000 n 0000435800 00000 n 0000612895 00000 n 0000612926 00000 n 0000539133 00000 n 0000435822 00000 n 0000437408 00000 n 0000612999 00000 n 0000613030 00000 n 0000539299 00000 n 0000437430 00000 n 0000438588 00000 n 0000613103 00000 n 0000613135 00000 n 0000539467 00000 n 0000438610 00000 n 0000439857 00000 n 0000613198 00000 n 0000613230 00000 n 0000539637 00000 n 0000439880 00000 n 0000440850 00000 n 0000613284 00000 n 0000613316 00000 n 0000539807 00000 n 0000440872 00000 n 0000441903 00000 n 0000613379 00000 n 0000613411 00000 n 0000539977 00000 n 0000441925 00000 n 0000443077 00000 n 0000613474 00000 n 0000613506 00000 n 0000540147 00000 n 0000443100 00000 n 0000444358 00000 n 0000613560 00000 n 0000613592 00000 n 0000540317 00000 n 0000444381 00000 n 0000445538 00000 n 0000613646 00000 n 0000613678 00000 n 0000540487 00000 n 0000445561 00000 n 0000446759 00000 n 0000613741 00000 n 0000613773 00000 n 0000540657 00000 n 0000446782 00000 n 0000447712 00000 n 0000613836 00000 n 0000613868 00000 n 0000540827 00000 n 0000447734 00000 n 0000448708 00000 n 0000613922 00000 n 0000613954 00000 n 0000540997 00000 n 0000448730 00000 n 0000449795 00000 n 0000614008 00000 n 0000614040 00000 n 0000541167 00000 n 0000449817 00000 n 0000451276 00000 n 0000614103 00000 n 0000614135 00000 n 0000541337 00000 n 0000451299 00000 n 0000452780 00000 n 0000614189 00000 n 0000614221 00000 n 0000541507 00000 n 0000452803 00000 n 0000454166 00000 n 0000614284 00000 n 0000614316 00000 n 0000541677 00000 n 0000454189 00000 n 0000455318 00000 n 0000614379 00000 n 0000614411 00000 n 0000541847 00000 n 0000455341 00000 n 0000456613 00000 n 0000614474 00000 n 0000614506 00000 n 0000542017 00000 n 0000456636 00000 n 0000457629 00000 n 0000614560 00000 n 0000614592 00000 n 0000542187 00000 n 0000457651 00000 n 0000458539 00000 n 0000614655 00000 n 0000614687 00000 n 0000542357 00000 n 0000458561 00000 n 0000459857 00000 n 0000614741 00000 n 0000614773 00000 n 0000542527 00000 n 0000459880 00000 n 0000461166 00000 n 0000614836 00000 n 0000614868 00000 n 0000542697 00000 n 0000461189 00000 n 0000462390 00000 n 0000614931 00000 n 0000614963 00000 n 0000542867 00000 n 0000462413 00000 n 0000463678 00000 n 0000615017 00000 n 0000615049 00000 n 0000543037 00000 n 0000463701 00000 n 0000464753 00000 n 0000615103 00000 n 0000615135 00000 n 0000543207 00000 n 0000464775 00000 n 0000465867 00000 n 0000615198 00000 n 0000615230 00000 n 0000543377 00000 n 0000465890 00000 n 0000466999 00000 n 0000615284 00000 n 0000615316 00000 n 0000543547 00000 n 0000467022 00000 n 0000468512 00000 n 0000615379 00000 n 0000615411 00000 n 0000543717 00000 n 0000468535 00000 n 0000470388 00000 n 0000615474 00000 n 0000615506 00000 n 0000543887 00000 n 0000470411 00000 n 0000471585 00000 n 0000615560 00000 n 0000615592 00000 n 0000544057 00000 n 0000471608 00000 n 0000472900 00000 n 0000615646 00000 n 0000615678 00000 n 0000544227 00000 n 0000472923 00000 n 0000474502 00000 n 0000615741 00000 n 0000615773 00000 n 0000544397 00000 n 0000474525 00000 n 0000475744 00000 n 0000615836 00000 n 0000615868 00000 n 0000544567 00000 n 0000475767 00000 n 0000477893 00000 n 0000615922 00000 n 0000615954 00000 n 0000544737 00000 n 0000477916 00000 n 0000479825 00000 n 0000616017 00000 n 0000616049 00000 n 0000544907 00000 n 0000479848 00000 n 0000480466 00000 n 0000616112 00000 n 0000616144 00000 n 0000545077 00000 n 0000480488 00000 n 0000482990 00000 n 0000616196 00000 n 0000616228 00000 n 0000545247 00000 n 0000483013 00000 n 0000486026 00000 n 0000616269 00000 n 0000616301 00000 n 0000545417 00000 n 0000486049 00000 n 0000488729 00000 n 0000616333 00000 n 0000616365 00000 n 0000545587 00000 n 0000488752 00000 n 0000491587 00000 n 0000616397 00000 n 0000616429 00000 n 0000545757 00000 n 0000491610 00000 n 0000494230 00000 n 0000616461 00000 n 0000616493 00000 n 0000545927 00000 n 0000494253 00000 n 0000496348 00000 n 0000616525 00000 n 0000616557 00000 n 0000546097 00000 n 0000496371 00000 n 0000499187 00000 n 0000616589 00000 n 0000616621 00000 n 0000546267 00000 n 0000499210 00000 n 0000500044 00000 n 0000616653 00000 n 0000616685 00000 n 0000546437 00000 n 0000500066 00000 n 0000501112 00000 n 0000616717 00000 n 0000616749 00000 n 0000546607 00000 n 0000501134 00000 n 0000502148 00000 n 0000616790 00000 n 0000616822 00000 n 0000546777 00000 n 0000502170 00000 n 0000503238 00000 n 0000616863 00000 n 0000616895 00000 n 0000546947 00000 n 0000503260 00000 n 0000504461 00000 n 0000616936 00000 n 0000616968 00000 n 0000547117 00000 n 0000504484 00000 n 0000505177 00000 n 0000617009 00000 n 0000617041 00000 n 0000547287 00000 n 0000505199 00000 n 0000505398 00000 n 0000617082 00000 n 0000617114 00000 n 0000547457 00000 n 0000505420 00000 n 0000507243 00000 n 0000617146 00000 n 0000617178 00000 n 0000617445 00000 n 0000617891 00000 n trailer << /Size 1244 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 619456 %%EOF nyquist-3.05/doc/part2.html0000644000175000000620000005757211537432671014677 0ustar stevestaffIntroduction and Overview Previous Section | Next Section | Table of Contents | Index | Title Page

    Introduction and Overview

    Nyquist is a language for sound synthesis and music composition. Unlike score languages that tend to deal only with events, or signal processing languages that tend to deal only with signals and synthesis, Nyquist handles both in a single integrated system. Nyquist is also flexible and easy to use because it is based on an interactive Lisp interpreter.

    With Nyquist, you can design instruments by combining functions (much as you would using the orchestra languages of Music V, cmusic, or Csound). You can call upon these instruments and generate a sound just by typing a simple expression. You can combine simple expressions into complex ones to create a whole composition.

    Nyquist runs under Linux, Apple Mac OS X, Microsoft Windows NT, 2000, XP, and Vista, and it produces sound files or directly generates audio. Recent versions have also run on AIX, NeXT, SGI, DEC pmax, and Sun Sparc machines. (Makefiles for many of these are included, but out-of-date). Let me know if you have problems with any of these machines.

    To use Nyquist, you should have a basic knowledge of Lisp. An excellent text by Touretzky is recommended (Touretzky 1984). Appendix "XLISP: An Object-oriented Lisp" is the reference manual for XLISP, of which Nyquist is a superset. Starting with Version 3, Nyquist supports a variant of SAL, which is also available in Common Music. Since there are some differences, one should generally call this implementation "Nyquist SAL;" however, in this manual, I will just call it "SAL." SAL offers most of the capabilities of Lisp, but it uses an Algol-like syntax that may be more familiar to programmers with experience in Java, C, Basic, etc.

    Installation

    Nyquist is a C++ program intended to run under various operating systems including Unix, Mac OS X, and Windows. Nyquist is based on Lisp, but it includes its own Lisp interpreter (a modified version of XLISP), so you do not need to install some other Lisp to run Nyquist. Other Lisp systems are not compatible with Nyquist.

    Most Nyquist users run Nyquist under the Nyquist IDE, which is written in Java and depends on the Java runtime system. Most systems already have Java, but if you do not, you will need to install it. When you install the Nyquist IDE, you will automatically get Nyquist and a set of runtime libraries.

    There are generally two ways to install Nyquist:

    • Get a pre-compiled version of the Nyquist IDE for Windows or Mac OS X. The Windows version comes packaged in an installer that installs and configures the Nyquist IDE. The Mac OS X version unpacks to a complete OS X application.
    • Compile from sources. There is one set of sources for Mac, Windows, and Unix. Instructions for building applications from the sources are provided in the files sys/win/README.txt, sys/mac/README.txt, and sys/unix/README.txt.

    You can download source code and precompiled versions from the Nyquist project on SourceForge (http://sourceforge.net/projects/nyquist). The latest source code can be obtained via Subversion (svn) using the following:

    svn co https://nyquist.svn.sourceforge.net/svnroot/nyquist/trunk nyquist
    
    or by checking out nyquist using a graphical interface svn client such as TortoiseSVN for Windows.

    Using NyquistIDE

    The program named NyquistIDE is an "integrated development environment" for Nyquist. When you run NyquistIDE, it starts the Nyquist program and displays all Nyquist output in a window. NyquistIDE helps you by providing a Lisp and SAL editor, hints for command completion and function parameters, some graphical interfaces for editing envelopes and graphical equalizers, and a panel of buttons for common operations. A more complete description of NyquistIDE is in Chapter "The NyquistIDE Program".

    For now, all you really need to know is that you can enter Nyquist commands by typing into the upper left window. When you type return, the expression you typed is sent to Nyquist, and the results appear in the window below. You can edit files by clicking on the New File or Open File buttons. After editing some text, you can load the text into Nyquist by clicking the Load button. NyquistIDE always saves the file first; then it tells Nyquist to load the file. You will be prompted for a file name the first time you load a new file.

    Using SAL

    SAL mode means that Nyquist reads and evaluates SAL commands rather than Lisp. The SAL mode prompt is "SAL> " while the Lisp mode prompt is "> ". When Nyquist starts it normally enters SAL mode automatically, but certain errors may exit SAL mode. You can reenter SAL mode by typing the Lisp expression (sal).

    In SAL mode, you type commands in the SAL programming language. Nyquist reads the commands, compiles them into Lisp, and evaluates the commands. Commands can be entered manually by typing into the upper left text box in NyquistIDE.

    Helpful Hints

    Under Win95 and Win98, the console sometimes locks up. Activating another window and then reactivating the Nyquist window should unlock the output. (We suggest you use JNyqIDE, the interactive development environment rather than a console window.)

    You can cut and paste text into Nyquist, but for serious work, you will want to use the Lisp load command. To save even more time, write a function to load your working file, e.g. (defun l () (load "myfile.lsp")). Then you can type (l) to (re)load your file.

    Using SAL, you can type

    define function l () load "myfile.lsp"
    
    and then
    exec l()
    
    to (re)load the file.

    The Emacs editor is free GNU software and will help you balance parentheses if you use Lisp mode. In fact, you can run nyquist (without the IDE) as a subprocess to Emacs. A helful discussion is at //http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/examples/emacs/main.html. If you use Emacs, there is also a SAL mode (the file is sal-mode.el) included with the Common Music distribution, which you can find on the Web at sourceforge.net.

    The NyquistIDE also runs Nyquist as a subprocess and has built-in Lisp and SAL editors. If your editor does not help you balance parentheses, you may find yourself counting parens and searching for unbalanced expressions. If you are confused or desperate and using Lisp syntax, try the :print t option of the load function. By looking at the expressions printed, you should be able to tell where the last unbalanced expression starts. Alternatively, type (file-sexprs) and type the lisp file name at the prompt. This function will read and print expressions from the file, reporting an error when an extra paren or end-of-file is reached unexpectedly.

    Using Lisp

    Lisp mode means that Nyquist reads and evaluates Nyquist expressions in Lisp syntax. Since Nyquist is build on a Lisp interpreter, this is the "native" or machine language of Nyquist, and certain errors and functions may break out of the SAL interpreter, leaving you with a prompt for a Lisp expression. Alternatively, you can exit SAL simply by typing exit to get a Lisp prompt (> ). Commands can be entered manually by typing into the upper left text box in NyquistIDE.

    Examples

    We will begin with some simple Nyquist programs. Throughout the manual, we will assume SAL mode and give examples in SAL, but it should be emphasized that all of these examples can be performed using Lisp syntax. See Section "Interoperability of SAL and XLISP" on the relationship between SAL and Lisp.

    Detailed explanations of the functions used in these examples will be presented in later chapters, so at this point, you should just read these examples to get a sense of how Nyquist is used and what it can do. The details will come later. Most of these examples can be found in the file nyquist/demos/examples.sal. Corresponding Lisp syntax examples are in the file nyquist/demos/examples.lsp.

    Our first example makes and plays a sound:

    ;; Making a sound.
    play osc(60) ; generate a loud sine wave
     
    This example is about the simplest way to create a sound with Nyquist. The osc function generates a sound using a table-lookup oscillator. There are a number of optional parameters, but the default is to compute a sinusoid with an amplitude of 1.0. The parameter 60 designates a pitch of middle C. (Pitch specification will be described in greater detail later.) The result of the osc function is a sound. To hear a sound, you must use the play command, which plays the file through the machine's D/A converters. It also writes a soundfile in case the computation cannot keep up with real time. You can then (re)play the file by typing:
    exec r()
    
    This (r) function is a general way to "replay" the last thing written by play.

    Note: when Nyquist plays a sound, it scales the signal by 2^(15)-1 and (by default) converts to a 16-bit integer format. A signal like (osc 60), which ranges from +1 to -1, will play as a full-scale 16-bit audio signal.

    Waveforms

    Our next example will be presented in several steps. The goal is to create a sound using a wavetable consisting of several harmonics as opposed to a simple sinusoid. In order to build a table, we will use a function that computes a single harmonic and add harmonics to form a wavetable. An oscillator will be used to compute the harmonics.

    The function mkwave calls upon build-harmonic to generate a total of four harmonics with amplitudes 0.5, 0.25, 0.125, and 0.0625. These are scaled and added (using +) to create a waveform which is bound temporarily to *table*.

    A complete Nyquist waveform is a list consisting of a sound, a pitch, and T, indicating a periodic waveform. The pitch gives the nominal pitch of the sound. (This is implicit in a single cycle wave table, but a sampled sound may have many periods of the fundamental.) Pitch is expressed in half-steps, where middle C is 60 steps, as in MIDI pitch numbers. The list of sound, pitch, and T is formed in the last line of mkwave: since build-harmonic computes signals with a duration of one second, the fundamental is 1 Hz, and the hz-to-step function converts to pitch (in units of steps) as required.

    define function mkwave()
      begin
        set *table* = 0.5 * build-harmonic(1.0, 2048) +
                      0.25 * build-harmonic(2.0, 2048) +
                      0.125 * build-harmonic(3.0, 2048) +
                      0.0625 * build-harmonic(4.0, 2048)
        set *table* = list(*table*, hz-to-step(1.0), #t)
      end
    

    Now that we have defined a function, the last step of this example is to build the wave. The following code calls mkwave the first time the code is executed (loaded from a file). The second time, the variable *mkwave* will be true, so mkwave will not be invoked:

    if ! fboundp(quote(*mkwave*)) then
      begin
        exec mkwave()
        set *mkwave* = #t
      end
    

    Wavetables

    When Nyquist starts, several waveforms are created and stored in global variables for convenience. They are: *sine-table*, *saw-table*, and *tri-table*, implementing sinusoid, sawtooth, and triangle waves, respectively. The variable *table* is initialized to *sine-table*, and it is *table* that forms the default wave table for many Nyquist oscillator behaviors. If you want a proper, band-limited waveform, you should construct it yourself, but if you do not understand this sentence and/or you do not mind a bit of aliasing, give *saw-table* and *tri-table* a try.

    Note that in Lisp and SAL, global variables often start and end with asterisks (*). These are not special syntax, they just happen to be legal characters for names, and their use is purely a convention.

    Sequences

    Finally, we define my-note to use the waveform, and play several notes in a simple score. Note that the function my-note has only one command (a return command), so it is not necessary to use begin and end. These are only necessary when the function body consists of a sequence of statements:
    define function my-note(pitch, dur)
      return osc(pitch, dur, *table*)
    

    play seq(my-note(c4, i), my-note(d4, i), my-note(f4, i), my-note(g4, i), my-note(d4, q))

    Here, my-note is defined to take pitch and duration as parameters; it calls osc to do the work of generating a waveform, using *table* as a wave table.

    The seq function is used to invoke a sequence of behaviors. Each note is started at the time the previous note finishes. The parameters to my-note are predefined in Nyquist: c4 is middle C, i (for eIghth note) is 0.5, and q (for Quarter note) is 1.0. See Section "Predefined Constants" for a complete description. The result is the sum of all the computed sounds.

    Sequences can also be constructed using the at transformation to specify time offsets. See sequence_example.htm demos, sequence for more examples and explanation.

    Envelopes

    The next example will illustrate the use of envelopes. In Nyquist, envelopes are just ordinary sounds (although they normally have a low sample rate). An envelope is applied to another sound by multiplication using the mult function. The code shows the definition of env-note, defined in terms of the note function in the previous example. In env-note, a 4-phase envelope is generated using the env function, which is illustrated in Figure 1.




    Figure 1: An envelope generated by the env function.


    ; env-note produces an enveloped note.  The duration
    ;   defaults to 1.0, but stretch can be used to change
    ;   the duration.
    ;   Uses my-note, defined above.
    ;
    define function env-note(p)
      return my-note(p, 1.0) *
             env(0.05, 0.1, 0.5, 1.0, 0.5, 0.4)
    

    ; try it out: ; play env-note(c4)

    While this example shows a smooth envelope multiplied by an audio signal, you can also multiply audio signals to achieve what is often called ring modulation. See the code and description in demos/scratch_tutorial.htm for an interesting use of ring modulation to create "scratch" sounds.

    In the next example, The stretch operator (~) is used to modify durations:

    ; now use stretch to play different durations
    ;
    play seq(seq(env-note(c4), env-note(d4)) ~ 0.25,
             seq(env-note(f4), env-note(g4)) ~ 0.5,
             env-note(c4))
    

    In addition to stretch, there are a number of transformations supported by Nyquist, and transformations of abstract behaviors is perhaps the fundamental idea behind Nyquist. Chapter "Behavioral Abstraction" is devoted to explaining this concept, and further elaboration can be found elsewhere (Dannenberg and Frayley 1989).

    Piece-wise Linear Functions

    It is often convenient to construct signals in Nyquist using a list of (time, value) breakpoints which are linearly interpolated to form a smooth signal. Envelopes created by env are a special case of the more general piece-wise linear functions created by pwl. Since pwl is used in some examples later on, we will take a look at pwl now. The pwl function takes a list of parameters which denote (time, value) pairs. There is an implicit initial (time, value) pair of (0, 0), and an implicit final value of 0. There should always be an odd number of parameters, since the final value (but not the final time) is implicit. Here are some examples:
    ; symetric rise to 10 (at time 1) and fall back to 0 (at time 2):
    ;
    pwl(1, 10, 2)
    

    ; a square pulse of height 10 and duration 5. ; Note that the first pair (0, 10) overrides the default initial ; point of (0, 0). Also, there are two points specified at time 5: ; (5, 10) and (5, 0). (The last 0 is implicit). The conflict is ; automatically resolved by pushing the (5, 10) breakpoint back to ; the previous sample, so the actual time will be 5 - 1/sr, where ; sr is the sample rate. ; pwl(0, 10, 5, 10, 5)

    ; a constant function with the value zero over the time interval ; 0 to 3.5. This is a very degenerate form of pwl. Recall that there ; is an implicit initial point at (0, 0) and a final implicit value of ; 0, so this is really specifying two breakpoints: (0, 0) and (3.5, 0): ; pwl(3.5)

    ; a linear ramp from 0 to 10 and duration 1. ; Note the ramp returns to zero at time 1. As with the square pulse ; above, the breakpoint (1, 10) is pushed back to the previous sample. ; pwl(1, 10, 1)

    ; If you really want a linear ramp to reach its final value at the ; specified time, you need to make a signal that is one sample longer. ; The RAMP function does this: ; ramp(10) ; ramp from 0 to 10 with duration 1 + one sample period ; ; RAMP is based on PWL; it is defined in nyquist.lsp. ;

    Predefined Constants

    For convenience and readability, Nyquist pre-defines some constants, mostly based on the notation of the Adagio score language, as follows:

    More Examples

    More examples can be found in the directory demos, part of the standard Nyquist release. The file demos/examples_home.htm is an index to all the demo descriptions. In this directory, you will find the following and more:


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/part6.html0000644000175000000620000006531211537432671014672 0ustar stevestaffMore Examples Previous Section | Next Section | Table of Contents | Index | Title Page

    More Examples

    This chapter explores Nyquist through additional examples. The reader may wish to browse through these and move on to Chapter "Nyquist Functions", which is a reference section describing Nyquist functions.

    Stretching Sampled Sounds

    This example illustrates how to stretch a sound, resampling it in the process. Because sounds in Nyquist are values that contain the sample rate, start time, etc., use sound to convert a sound into a behavior that can be stretched, e.g. sound(a-snd). This behavior stretches a sound according to the stretch factor in the environment, set using stretch. For accuracy and efficiency, Nyquist does not resample a stretched sound until absolutely necessary. The force-srate function is used to resample the result so that we end up with a "normal" sample rate that is playable on ordinary sound cards.

    ; if a-snd is not loaded, load sound sample:
    ;
    if not(boundp(quote(a-snd))) then
      set a-snd = s-read("demo-snd.aiff")
    

    ; the SOUND operator shifts, stretches, clips and scales ; a sound according to the current environment ; define function ex23() play force-srate(*default-sound-srate*, sound(a-snd) ~ 3.0)

    define function down() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.2, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.6)) play down()

    ; that was so much fun, let's go back up: ; define function up() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.5, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.2))

    ; and write a sequence ; play seq(down(), up(), down())

    Notice the use of the sound behavior as opposed to cue. The cue behavior shifts and scales its sound according to *warp* and *loud*, but it does not change the duration or resample the sound. In contrast, sound not only shifts and scales its sound, but it also stretches it by resampling or changing the effective sample rate according to *warp*. If *warp* is a continuous warping function, then the sound will be stretched by time-varying amounts. (The *transpose* element of the environment is ignored by both cue and sound.)

    Note: sound may use linear interpolation rather than a high-quality resampling algorithm. In some cases, this may introduce errors audible as noise. Use resample (see Section "Sound Synthesis") for high-quality interpolation.

    In the functions up and down, the *warp* is set by stretch (~), which simply scales time by a constant scale factor. In this case, sound can "stretch" the signal simply by changing the sample rate without any further computation. When seq tries to add the signals together, it discovers the sample rates do not match and uses linear interpolation to adjust all sample rates to match that of the first sound in the sequence. The result of seq is then converted using force-srate to convert the sample rate, again using linear interpolation. It would be slightly better, from a computational standpoint, to apply force-srate individually to each stretched sound rather than applying force-srate after seq.

    Notice that the overall duration of sound(a-snd) ~ 0.5 will be half the duration of a-snd.

    Saving Sound Files

    So far, we have used the play command to play a sound. The play command works by writing a sound to a file while simultaneously playing it. This can be done one step at a time, and it is often convenient to save a sound to a particular file for later use:
    ; write the sample to a file, 
    ;    the file name can be any Unix filename.  Prepending a "./" tells
    ;    s-save to not prepend *default-sf-dir*
    ;
    exec s-save(a-snd, 1000000000, "./a-snd-file.snd")
    

    ; play a file ; play command normally expects an expression for a sound ; but if you pass it a string, it will open and play a ; sound file play "./a-snd-file.snd"

    ; delete the file (do this with care!) ; only works under Unix (not Windows) exec system("rm ./a-snd-file.snd")

    ; now let's do it using a variable as the file name ; set my-sound-file = "./a-snd-file.snd"

    exec s-save(a-snd, 1000000000, my-sound-file)

    ; play-file is a function to open and play a sound file exec play-file(my-sound-file)

    exec system(strcat("rm ", my-sound-file))

    This example shows how s-save can be used to save a sound to a file.

    This example also shows how the system function can be used to invoke Unix shell commands, such as a command to play a file or remove it. Finally, notice that strcat can be used to concatenate a command name to a file name to create a complete command that is then passed to system. (This is convenient if the sound file name is stored in a parameter or variable.)

    Memory Space and Normalization

    Sound samples take up lots of memory, and often, there is not enough primary (RAM) memory to hold a complete composition. For this reason, Nyquist can compute sounds incrementally, saving the final result on disk. However, Nyquist can also save sounds in memory so that they can be reused efficiently. In general, if a sound is saved in a global variable, memory will be allocated as needed to save and reuse it.

    The standard way to compute a sound and write it to disk is to pass an expression to the play command:

    play my-composition()
    

    Often it is nice to normalize sounds so that they use the full available dynamic range of 16 bits. Nyquist has an automated facility to help with normalization. By default, Nyquist computes up to 1 million samples (using about 4MB of memory) looking for the peak. The entire sound is normalized so that this peak will not cause clipping. If the sound has less than 1 million samples, or if the first million samples are a good indication of the overall peak, then the signal will not clip.

    With this automated normalization technique, you can choose the desired peak value by setting *autonorm-target*, which is initialized to 0.9. The number of samples examined is *autonorm-max-samples*, initially 1 million. You can turn this feature off by executing:

    exec autonorm-off()
    
    and turn it back on by typing:
    exec autonorm-on()
    
    This normalization technique is in effect when *autonorm-type* is quote(lookahead), which is the default.

    An alternative normalization method uses the peak value from the previous call to play. After playing a file, Nyquist can adjust an internal scale factor so that if you play the same file again, the peak amplitude will be *autonorm-target*, which is initialized to 0.9. This can be useful if you want to carefully normalize a big sound that does not have its peak near the beginning. To select this style of normalization, set *autonorm-type* to the (quoted) atom quote(previous).

    You can also create your own normalization method in Nyquist. The peak function computes the maximum value of a sound. The peak value is also returned from the play macro. You can normalize in memory if you have enough memory; otherwise you can compute the sound twice. The two techniques are illustrated here:

    ; normalize in memory.  First, assign the sound to a variable so
    ; it will be retained:
    set mysound = sim(osc(c4), osc(c5))
    ; now compute the maximum value (ny:all is 1 giga-samples, you may want a
    ; smaller constant if you have less than 4GB of memory:
    set mymax = snd-max(mysound, NY:ALL)
    display "Computed max", mymax
    ; now write out and play the sound from memory with a scale factor:
    play mysound * (0.9 / mymax)
    

    ; if you don't have space in memory, here's how to do it: define function myscore() return sim(osc(c4), osc(c5)) ; compute the maximum: set mymax = snd-max(list(quote(myscore)), NY:ALL) display "Computed max", mymax ; now we know the max, but we don't have a the sound (it was garbage ; collected and never existed all at once in memory). Compute the sound ; again, this time with a scale factor: play myscore() * (0.9 / mymax)

    You can also write a sound as a floating point file. This file can then be converted to 16-bit integer with the proper scaling applied. If a long computation was involved, it should be much faster to scale the saved sound file than to recompute the sound from scratch. Although not implemented yet in Nyquist, some header formats can store maximum amplitudes, and some soundfile player programs can rescale floating point files on the fly, allowing normalized soundfile playback without an extra normalization pass (but at a cost of twice the disk space of 16-bit samples). You can use Nyquist to rescale a floating point file and convert it to 16-bit samples for playback.

    Frequency Modulation

    The next example uses the Nyquist frequency modulation behavior fmosc to generate various sounds. The parameters to fmosc are:
    fmosc(pitch modulator table phase)
    
    Note that pitch is the number of half-steps, e.g. c4 has the value of 60 which is middle-C, and phase is in degrees. Only the first two parameters are required:
    ; make a short sine tone with no frequency modulation
    ;
    play fmosc(c4, pwl(0.1))
    

    ; make a longer sine tone -- note that the duration of ; the modulator determines the duration of the tone ; play fmosc(c4, pwl(0.5))

    In the example above, pwl (for Piece-Wise Linear) is used to generate sounds that are zero for the durations of 0.1 and 0.5 seconds, respectively. In effect, we are using an FM oscillator with no modulation input, and the result is a sine tone. The duration of the modulation determines the duration of the generated tone (when the modulation signal ends, the oscillator stops).

    The next example uses a more interesting modulation function, a ramp from zero to C4, expressed in hz. More explanation of pwl is in order. This operation constructs a piece-wise linear function sampled at the *control-srate*. The first breakpoint is always at (0, 0), so the first two parameters give the time and value of the second breakpoint, the second two parameters give the time and value of the third breakpoint, and so on. The last breakpoint has a value of 0, so only the time of the last breakpoint is given. In this case, we want the ramp to end at C4, so we cheat a bit by having the ramp return to zero "almost" instantaneously between times 0.5 and 0.501.

    The pwl behavior always expects an odd number of parameters. The resulting function is shifted and stretched linearly according to *warp* in the environment. Now, here is the example:

    ; make a frequency sweep of one octave; the piece-wise linear function
    ; sweeps from 0 to (step-to-hz c4) because, when added to the c4
    ; fundamental, this will double the frequency and cause an octave sweep.
    ;
    play fmosc(c4, pwl(0.5, step-to-hz(c4),  0.501))
    

    The same idea can be applied to a non-sinusoidal carrier. Here, we assume that *fm-voice* is predefined (the next section shows how to define it):

    ; do the same thing with a non-sine table
    ;
    play fmosc(cs2, pwl(0.5, step-to-hz(cs2), 0.501),
               *fm-voice*, 0.0)
    

    The next example shows how a function can be used to make a special frequency modulation contour. In this case the contour generates a sweep from a starting pitch to a destination pitch:

    ; make a function to give a frequency sweep, starting
    ; after <delay> seconds, then sweeping from <pitch-1>
    ; to <pitch-2> in <sweep-time> seconds and then
    ; holding at <pitch-2> for <hold-time> seconds.
    ;
    define function sweep(delay, pitch-1, sweep-time, 
                          pitch-2, hold-time)
      begin
        with interval = step-to-hz(pitch-2) - step-to-hz(pitch-1)
        return pwl(delay, 0.0,
                   ; sweep from pitch 1 to pitch 2
                   delay + sweep-time, interval,
                   ; hold until about 1 sample from the end
                   delay + sweep-time + hold-time - 0.0005, 
                   interval,
                   ; quickly ramp to zero (pwl always does this,
                   ;    so make it short)
                   delay + sweep-time + hold-time)
      end
    

    ; now try it out ; play fmosc(cs2, sweep(0.1, cs2, 0.6, gs2, 0.5), *fm-voice*, 0.0)

    FM can be used for vibrato as well as frequency sweeps. Here, we use the lfo function to generate vibrato. The lfo operation is similar to osc, except it generates sounds at the *control-srate*, and the parameter is hz rather than a pitch:

    play fmosc(cs2, 10.0 * lfo(6.0), *fm-voice*, 0.0)
    

    What kind of manual would this be without the obligatory FM sound? Here, a sinusoidal modulator (frequency C4) is multiplied by a slowly increasing ramp from zero to 1000.0.

    set modulator = pwl(1.0, 1000.0, 1.0005) * 
                    osc(c4)
    ; make the sound
    play fmosc(c4, modulator)
    

    For more simple examples of FM in Nyquist, see demos/warble_tutorial.htm. Another interesting FM sound reminiscent of "scratching" can be found with a detailed explanation in demos/scratch_tutorial.htm. .

    Building a Wavetable

    In Section "Waveforms", we saw how to synthesize a wavetable. A wavetable for osc also can be extracted from any sound. This is especially interesting if the sound is digitized from some external sound source and loaded using the s-read function. Recall that a table is a list consisting of a sound, the pitch of that sound, and T (meaning the sound is periodic).

    In the following, a sound is first read from the file demo-snd.nh. Then, the extract function is used to extract the portion of the sound between 0.110204 and 0.13932 seconds. (These numbers might be obtained by first plotting the sound and estimating the beginning and end of a period, or by using some software to look for good zero crossings.) The result of extract becomes the first element of a list. The next element is the pitch (24.848422), and the last element is T. The list is assigned to *fm-voice*.

    if not(boundp(quote(a-snd))) then
      set a-snd = s-read("demo-snd.aiff")
    

    set *fm-voice* = list(extract(0.110204, 0.13932, cue(a-snd)), 24.848422, #T)

    The file demos/examples.sal contains an extensive example of how to locate zero-crossings, extract a period, build a waveform, and generate a tone from it. (See ex37 through ex40 in the file.)

    Filter Examples

    Nyquist provides a variety of filters. All of these filters take either real numbers or signals as parameters. If you pass a signal as a filter parameter, the filter coefficients are recomputed at the sample rate of the control signal. Since filter coefficients are generally expensive to compute, you may want to select filter control rates carefully. Use control-srate-abs (Section "Transformations") to specify the default control sample rate, or use force-srate (Section "Sound Synthesis") to resample a signal before passing it to a filter.

    Before presenting examples, let's generate some unfiltered white noise:

    play noise()
    
    Now low-pass filter the noise with a 1000Hz cutoff:
    play lp(noise(), 1000.0)
    
    The high-pass filter is the inverse of the low-pass:
    play hp(noise(), 1000.0)
    

    Here is a low-pass filter sweep from 100Hz to 2000Hz:

    play lp(noise(), pwl(0.0, 100.0, 1.0, 2000.0, 1.0))
    
    And a high-pass sweep from 50Hz to 4000Hz:
    play hp(noise(), pwl(0.0, 50.0, 1.0, 4000.0, 1.0))
    

    The band-pass filter takes a center frequency and a bandwidth parameter. This example has a 500Hz center frequency with a 20Hz bandwidth. The scale factor is necessary because, due to the resonant peak of the filter, the signal amplitude exceeds 1.0:

      
    play reson(10.0 * noise(), 500.0, 20.0, 1)
    
    In the next example, the center frequency is swept from 100 to 1000Hz, using a constant 20Hz bandwidth:
    play reson(0.04 * noise(),
               pwl(0.0, 200.0, 1.0, 1000.0, 1.0),
               20.0)
    

    For another example with explanations, see demos/wind_tutorial.htm.

    DSP in Lisp

    In almost any signal processing system, the vast majority of computation takes place in the inner loops of DSP algorithms, and Nyquist is designed so that these time-consuming inner loops are in highly-optimized machine code rather than relatively slow interpreted lisp code. As a result, Nyquist typically spends 95% of its time in these inner loops; the overhead of using a Lisp interpreter is negligible.

    The drawback is that Nyquist must provide the DSP operations you need, or you are out of luck. When Nyquist is found lacking, you can either write a new primitive signal operation, or you can perform DSP in Lisp code. Neither option is recommended for inexperienced programmers. Instructions for extending Nyquist are given in Appendix "Extending Nyquist". This section describes the process of writing a new signal processing function in Lisp.

    Before implementing a new DSP function, you should decide which approach is best. First, figure out how much of the new function can be implemented using existing Nyquist functions. For example, you might think that a tapped-delay line would require a new function, but in fact, it can be implemented by composing sound transformations to accomplish delays, scale factors for attenuation, and additions to combine the intermediate results. This can all be packaged into a new Lisp function, making it easy to use. If the function relies on built-in DSP primitives, it will execute very efficiently.

    Assuming that built-in functions cannot be used, try to define a new operation that will be both simple and general. Usually, it makes sense to implement only the kernel of what you need, combining it with existing functions to build a complete instrument or operation. For example, if you want to implement a physical model that requires a varying breath pressure with noise and vibrato, plan to use Nyquist functions to add a basic pressure envelope to noise and vibrato signals to come up with a composite pressure signal. Pass that signal into the physical model rather than synthesizing the envelope, noise, and vibrato within the model. This not only simplifies the model, but gives you the flexibility to use all of Nyquist's operations to synthesize a suitable breath pressure signal.

    Having designed the new "kernel" DSP operation that must be implemented, decide whether to use C or Lisp. (At present, SAL is not a good option because it has no support for object-oriented programming.) To use C, you must have a C compiler, the full source code for Nyquist, and you must learn about extending Nyquist by reading Appendix "Extending Nyquist". This is the more complex approach, but the result will be very efficient. A C implementation will deal properly with sounds that are not time-aligned or matched in sample rates. To use Lisp, you must learn something about the XLISP object system, and the result will be about 50 times slower than C. Also, it is more difficult to deal with time alignment and differences in sample rates. The remainder of this section gives an example of a Lisp version of snd-prod to illustrate how to write DSP functions for Nyquist in Lisp.

    The snd-prod function is the low-level multiply routine. It has two sound parameters and returns a sound which is the product of the two. To keep things simple, we will assume that two sounds to be multiplied have a matched sample rate and matching start times. The DSP algorithm for each output sample is simply to fetch a sample from each sound, multiply them, and return the product.

    To implement snd-prod in Lisp, three components are required:

    1. An object is used to store the two parameter sounds. This object will be called upon to yield samples of the result sound;
    2. Within the object, the snd-fetch routine is used to fetch samples from the two input sounds as needed;
    3. The result must be of type SOUND, so snd-fromobject is used to create the result sound.

    The combined solution will work as follows: The result is a value of type sound that retains a reference to the object. When Nyquist needs samples from the sound, it invokes the sound's "fetch" function, which in turn sends an XLISP message to the object. The object will use snd-fetch to get a sample from each stored sound, multiply the samples, and return a result.

    Thus the goal is to design an XLISP object that, in response to a :next message will return a proper sequence of samples. When the sound reaches the termination time, simply return NIL.

    The XLISP manual (see Appendix "XLISP: An Object-oriented Lisp" describes the object system, but in a very terse style, so this example will include some explanation of how the object system is used. First, we need to define a class for the objects that will compute sound products. Every class is a subclass of class class, and you create a subclass by sending :new to a class.

    (setf product-class (send class :new '(s1 s2)))
    
    The parameter '(s1 s2) says that the new class will have two instance variables, s1 and s2. In other words, every object which is an instance of class product-class will have its own copy of these two variables.

    Next, we will define the :next method for product-class:

    (send product-class :answer :next '()
      '((let ((f1 (snd-fetch s1))
              (f2 (snd-fetch s2)))
          (cond ((and f1 f2)
                 (* f1 f2))
                (t nil)))))
    
    The :answer message is used to insert a new method into our new product-class. The method is described in three parts: the name (:next), a parameter list (empty in this case), and a list of expressions to be evaluated. In this case, we fetch samples from s1 and s2. If both are numbers, we return their product. If either is NIL, we terminate the sound by returning nil.

    The :next method assumes that s1 and s2 hold the sounds to be multiplied. These must be installed when the object is created. Objects are created by sending :new to a class. A new object is created, and any parameters passed to :new are then sent in a :isnew message to the new object. Here is the :isnew definition for product-class:

    (send product-class :answer :isnew '(p1 p2) 
      '((setf s1 (snd-copy p1))
        (setf s2 (snd-copy p2))))
    
    Take careful note of the use of snd-copy in this initialization. The sounds s1 and s2 are modified when accessed by snd-fetch in the :next method defined above, but this destroys the illusion that sounds are immutable values. The solution is to copy the sounds before accessing them; the original sounds are therefore unchanged. (This copy also takes place implicitly in most Nyquist sound functions.)

    To make this code safer for general use, we should add checks that s1 and s2 are sounds with identical starting times and sample rates; otherwise, an incorrect result might be computed.

    Now we are ready to write snd-product, an approximate replacement for snd-prod:

    (defun snd-product (s1 s2)
      (let (obj)
        (setf obj (send product-class :new s1 s2))
        (snd-fromobject (snd-t0 s1) (snd-srate s1) obj)))
    
    This code first creates obj, an instance of product-class, to hold s1 and s2. Then, it uses obj to create a sound using snd-fromobject. This sound is returned from snd-product. Note that in snd-fromobject, you must also specify the starting time and sample rate as the first two parameters. These are copied from s1, again assuming that s1 and s2 have matching starting times and sample rates.

    Note that in more elaborate DSP algorithms we could expect the object to have a number of instance variables to hold things such as previous samples, waveform tables, and other parameters.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/part3.html0000644000175000000620000003776111537432671014676 0ustar stevestaffThe NyquistIDE Program Previous Section | Next Section | Table of Contents | Index | Title Page

    The NyquistIDE Program

    The NyquistIDE program combines many helpful functions and interfaces to help you get the most out of Nyquist. NyquistIDE is implemented in Java, and you will need the Java runtime system or development system installed on your computer to use NyquistIDE. The best way to learn about NyquistIDE is to just use it. This chapter introduces some of the less obvious features. If you are confused by something and you do not find the information you need here, please contact the author.

    NyquistIDE Overview

    The NyquistIDE runs the command-line version of Nyquist as a subtask, so everything that works in Nyquist should work when using the NyquistIDE and vice-versa. Input to Nyquist is usually entered in the top left window of the NyquistIDE. When you type return, if the expression or statement appears to be complete, the expression you typed is sent to Nyquist. Output from Nyquist appears in a window below. You cannot type into or edit the output window text.

    The normal way to use the NyquistIDE is to create or open one or more files. You edit these files and then click the Load button. To load a file, NyquistIDE saves the file, sets the current directory of Nyquist to that of the file, then issues a load command to Nyquist. In this case and several others, you may notice that NyquistIDE sends expressions to Nyquist automatically for evaluation. You can always see the commands and their results in the output window.

    Notice that when you load a selected file window, NyquistIDE uses setdir to change Nyquist's current directory. This helps to keep the two programs in sync. Normally, you should keep all the files of a project in the same directory and avoid manually changing Nyquist's current directory (i.e. avoid calling setdir in your code).

    Arranging windows in the NyquistIDE can be time-consuming, and depending on the operating system, it is possible for a window to get into a position where you cannot drag it to a new position. The Window:Tile menu command can be used to automatically lay out windows in a rational way. There is a preference setting to determine the height of the completion list relative to the height of the output window.

    The Button Bar

    There are a number of buttons with frequently-used operations. These are:

    Command Completion

    To help with programming, NyquistIDE maintains a command-completion window. As you type the first letters of function names, NyquistIDE lists matching functions and their parameters in the Completion List window. If you click on an entry in this window, the displayed expression will replace the incompletely typed function name. A preference allows you to match initial letters or any substring of the complete function name. This is controlled by the "Use full search for code completion" preference.

    In addition, if you right click (or under Mac OS X, hold down the Alt/Option key and click) on an entry, NyquistIDE will display documentation for the function. Documentation can come from a local copy or from the online copy (determined by the "Use online manual instead of local copy" preference). Documentation can be displayed within the NyquistIDE window or in an external browser (determined by the "Use window in NyquistIDE for help browser" preference.) Currently, the external browser option does not seem to locate documentation properly, but this should be fixed in the future.

    Browser

    If you click on the Browse button or use the Window:Browse menu command, NyquistIDE will display a browser window that is pre-loaded with a number of Nyquist commands to create sounds. You can adjust parameters, audition the sounds, and capture the expression that creates the sound. In many cases, the expression checks to see if necessary functions are defined, loading files if necessary before playing the sound. If you want to use a sound in your own program, you can often simplify things by explicitly loading the required file just once at the beginning of your file.

    Since Nyquist now supports a mix of Lisp and SAL, you may find yourself in the position of having code from the browser in one language while you are working in the other. The best way to handle this is to put the code for the sound you want into a function defined in a Lisp (.lsp) or SAL (.sal) file. Load the file (from Lisp, use the sal-load command to load a SAL file), and call the function from the language of your choice.

    Envelope Editor

    The envelope editor allows you graphically to design and edit piece-wise linear and exponential envelopes. The editor maintains a list of envelopes and you select the one to edit or delete using the drop down list in the Saved Envelopes List area. The current envelope appears in the Graphical Envelope Editor area. You can click to add or drag points. Alternatively, you can use the Envelope Points window to select and edit any breakpoint by typing coordinates. The duration of the envelope is controlled by the Stop field in the Range area, and the vertical axis is controlled by the Min and Max fields.

    When you click the Save button, all envelopes are written to Nyquist. You can then use the envelope by treating the envelope name as a function. For example, if you define an envelope named "fast-attack," then you can create the envelope within a Nyquist SAL program by writing the expression fast-attack().

    These edited envelopes are saved to a file named workspace.lsp in the current directory. The workspace is Nyquist's mechanism for saving data of all kinds (see Section "Workspaces"). The normal way to work with workspaces is to (1) load the workspace, i.e. load "workspace", as soon as you start Nyquist; (2) invoke the envelope editor to change values in the workspace; and (3) save the workspace at any time, especially before you exit NyquistIDE. If you follow these steps, envelopes will be preserved from session to session, and the entire collection of envelopes will appear in the editor. Be sure to make backups of your workspace.lsp file along with your other project files.

    The envelope editor can create linear and exponential envelopes. Use the Type pull-down menu to select the type you want. Envelopes can be created using default starting and ending values using pwl or pwe, or you can specify the initial values using pwlv or pwev. The envelope editor uses pwl or pwe if no point is explicitly entered as the initial or final point. To create a pwlv or pwev function, create a point and drag it to the leftmost or rightmost edge of the graphical editing window. You will see the automatically generated default starting or ending point disappear from the graph.

    Exponential envelopes should never decay to zero. If you enter a zero amplitude, you will see that the envelope remains at zero to the next breakpoint. To get an exponential decay to "silence," try using an amplitude of about 0.001 (about -60dB). To enter small values like this, you can type them into the Amplitude box and click "Update Point."

    The Load button refreshes the editor from data saved in the Nyquist process. Normally, there is no need to use this because the editor automatically loads data when you open it.

    Equalizer Editor

    The Equalizer Editor provides a graphical EQ interface for creating and adjusting equalizers. Unlike the envelope editor, where you can type any envelope name, equalizers are named eq-0, eq-1, etc., and you select the equalizer to edit using a pull-down menu. The Set button should be use to record changes.

    UPIC Editor

    The UPIC Editor is inspired by the UPIC system by Iannis Xenakis at the Centre d'Edudes de Mathematique et Automatique Musicales (CEMaMu). The UPIC Editor is accessed by the "Upic Edit" menu item in the "Window" menu of the NyquistIDE. Once opened, you can draw pitch contours in the main panel by pressing the left mouse button and dragging with the mouse down. Contours represent tones in a frequency vs. time coordinate system. Any contour can be deleted by right-clicking (or shift-clicking on an Apple computer) to select the contour (indicated by the color red), and typing the Delete key.

    A collection of contours can be saved to a file and later retrieved using the items in the File menu (use the File menu in the UPIC Editor window, not in the main NyquistIDE window.) The file is a SAL program in a special format that can be parsed by the UPIC Editor. The file can also be loaded into Nyquist using the File:Load menu item, or by executing a load command in Nyquist.

    The panel at the top of the editor offers control over various parameters. The Name box is a Nyquist variable name. This name takes effect when you save a file from the UPIC Editor. The variable name is stored in the file so that when a UPIC Editor-generated file is loaded into Nyquist, the data is assigned to this variable name. The data is a list of contours, where each contour specifies a waveform, an envelope, and a list of time-frequency coordinates.

    The next item in the panel is the Waveform box. The Waveform box names a waveform for a contour. Default waveforms are sinusoid, triangle, and sawtooth, but you can type in your own names. The currently selected waveform is stored with the contour when it is created (entered by drawing). You cannot change or edit the waveform name associated with a contour once the contour is created, but you can always delete the contour and replace it. The Envelope box names an envelope for a contour. The envelope names a Nyquist function. The default, upic-env is a trapezoid shape with an onset time and offset time of 10ms. As with waveforms, the envelope is stored with each contour when the contour is created and cannot be edited.

    The Stop Time box gives the duration of the drawing area in seconds. The Min Freq box gives the minimum frequency (at the bottom of the drawing area), and the Max Freq box gives the maximum frequency (at the top of the drawing area). The vertical frequency axis can use a linear scale corresponding to frequency in Hertz or a logarithmic scale corresponding to semitones. The "linear" checkbox selects the linear scale. When any of these parameters (described in this paragraph and delimited by the border labeled "Range" on the control panel) is changed, you must press the Update Range button for the change to take effect.

    The Background menu lets you display a grid that indicates pitch locations. The "C's" item draws a line at C in every visible octave. E.g. middle C is about 260 Hz, so a reference line will be drawn near 260 Hz. Lines will be drawn around 130 Hz (an octave below middle C), and around 520 Hz (an octave above middle C), etc. The "GrandStaff" menu item draws reference lines for each line of the grand staff commonly used for piano music. The pitches are G2, B2, D3, F3, A3, E4, G4, B4, D5, and F5. Finally, you can load a picture using the Background:Load Picture... menu item. Then, the Background:Show Picture menu item toggles whether the picture is displayed or not. This feature allows you to trace an image. (For example, see the Sonic Self-Portrait at http://www.cs.cmu.edu/~rbd.) You may wish to use an image editor to lighten the image so that superimposed contours will be more visible.

    Each change to the Range data, background choice, and each entry of a contour is an action that you can undo or redo with the Undo and Redo buttons.

    To convert UPIC data into sound, first load upic.sal and load a file generated by the UPIC Editor. Now, suppose the variable name used is upicdata. You can play the data by writing

    play upic(upicdata)
    
    If you created your own names for waveforms or envelopes, you must be sure that these exist before calling the upic function. Each waveform must be the name of a variable which is set to a Nyquist wave table. (See Section
    "Waveforms" for information on how to create a wave table.) Also, each envelope must name a function with no parameters that will return an amplitude envelope. The following is the built-in definition for upic-env:
    define function upic-env()
      return env(0.01, 0.01, 0.01, 1, 1, 1)
    
    To make a custom envelope function named upic-smooth with a 0.2 second attack and a 0.3 second decay, you could write:
    define function upic-smooth()
      return env(0.2, 0.01, 0.3, 1, 1, 1)
    


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/geometric-fig.gif0000644000175000000620000000657611466723256016172 0ustar stevestaffGIF89a*\w1!Software: Microsoft Office!,RMMM|||hhh` dihlp,tm|pH,Ȥrl:AtJZجv+zxzm5RWv L]CX ̜> " ; ش  $];]R% mݻm3CˆD ,P4B|8s @ x/ pEDTxCf"KJHy 83h=tH"R2BsТ@^Xff ƐڢK˖:+SVK#hL-]@̸}(\᷈Kv˗\; cA,XF[ K 7BոvȚ)HXq=[R@I(i/Q?'P@Q݈/n\|a<pk뾎;<@KD`L0mEL AE"D+Gph(gbC"bU3h#$ި㎕㏾) i9"I.%->)%%MNiU^egQnY~)ai0gGj nƹrivEzI~ h}JhZghm> iNjf̃|f&*j٨ TQfp뮼+k&l= Vkfv+&,+֫- jA,[$' 7,fWlB,c /1Ut(5q0|ol*83:iD=pН&1L7-/;-B]3Xg.krdk-ve=q,#HDMc HZb|c%yIrdI$0>$2GTLbe#])Q1e-RRY$$K` Ғ%( 8aʎ$3-`"4ƹυ6QVψ8SV\'9hNԤ YMwN0Bga ]/[KqFԒμpjlG]=EgхoCZyXbg]Z͘jwN+Ӟ5^֞zЩ)C *HZ~vN8;9ҺJmkWkx&3v45jk{x&uG'vtڠ6)n;45=;}ZqߛMr+ EoHϷAn \kySǵr$<xQ{;oyx9]|o+/?Y>GS茿T\Ɵ W˺e.antW]aGS v?ZMz??֝Hw+w\ OSoC8yI]k_=_ö|}qp?+%_x3d;+`A#pϮ}@?}4WH{c}~߷'C|hӷԀt{*Xoe}悊C*g,uX62h4~:i5B6@(wE8}dsQ(M藁Wx7NHdY[7]Xv xDHDdZX闆h^7R(HXXqH|S!؆`p_e`0HM{\s؃~hw8Ge8Qgh<艕JXux؇xh7XZ=rt؊vH-{h!ȸXw7u$ edDXrxwE8x嘍pۧ"Ǝ8XxhjV281m m)7 Y Y'iِ;*vO"$$YGr(I$*BҒ.#!o1YB8I V=6':I@ޥ4ECi@tpl 䥑dMe\[@ {P:iV'U=a>c\$`9uY.jiO U 3t)9hYwɔ았\RxiIt阧@9{׳9|;)9:ByY27ٕٓ!)0<򚰩#96R9#.i"™ Yp) WLҜ9y&ڙٝ,9Yy9!;nyquist-3.05/doc/part9.html0000644000175000000620000001514011537432671014667 0ustar stevestaffNyquist Globals Previous Section | Next Section | Table of Contents | Index | Title Page

    Nyquist Globals

    There are many global variables in Nyquist. A convention in Lisp is to place asterisks (*) around global variables, e.g. *table*. This is only a convention, and the asterisks are just like any other letter as far as variable names are concerned. Here are some globals users should know about:

    *table*
    Default table used by osc and other oscillators.

    *A4-Hertz*
    Frequency of A4 in Hertz.. Note: you must call (set-pitch-names) to recompute pitches after changing *A4-Hertz*.

    *autonorm*
    The normalization factor to be applied to the next sound when *autonorm-type* is 'previous. See Sections "Memory Space and Normalization" and "Sound File Input and Output".

    *autonormflag*
    Enables the automatic normalization feature of the play command. You should use (autonorm-on) and (autonorm-off) rather than setting *autonormflag* directly. See Sections "Memory Space and Normalization" and "Sound File Input and Output".

    *autonorm-max-samples*
    Specifies how many samples will be computed searching for a peak value when *autonorm-type* is 'lookahead. See Sections "Memory Space and Normalization" and "Sound File Input and Output".

    *autonorm-previous-peak*
    The peak of the previous sound generated by play. This is used to compute the scale factor for the next sound when *autonorm-type* is 'previous. See Sections "Memory Space and Normalization" and "Sound File Input and Output".

    *autonorm-target*
    The target peak amplitude for the autonorm feature. The default value is 0.9. See Sections "Memory Space and Normalization" and "Sound File Input and Output".

    *autonorm-type*
    Determines how the autonorm feature is implemented. Valid values are 'lookahead (the default) and 'previous. See Sections "Memory Space and Normalization" and "Sound File Input and Output".

    *breakenable*
    Controls whether XLISP enters a break loop when an error is encountered. See Section "Profiling".

    *control-srate*
    Part of the environment, establishes the control sample rate. See Section "The Environment" for details.

    *default-sf-bits*
    The default bits-per-sample for sound files. Typically 16.

    *default-sf-dir*
    The default sound file directory. Unless you give a full path for a file, audio files are assumed to be in this directory. (Applies to many functions that deal with sound files. Check the function description to see if *default-sf-dir* applies.)

    *default-sf-format*
    The default sound file format. When you write a file, this will be the default format: AIFF for Mac and most Unix systems, NeXT for NeXT systems, and WAV for Win32.

    *default-sf-srate*
    The default sample rate for sound files. Typically 44100.0, but often set to 22050.0 for speed in non-critical tasks.

    *default-control-srate*
    Default value for *control-srate*. This value is restored when you execute (top) to pop out of a debugging session. Change it by calling (set-control-srate value).

    *default-sound-srate*
    Default value for *sound-srate*. This value is restored when you execute (top) to pop out of a debugging session. Change it by calling (set-sound-srate value).

    *file-separator*
    The character that separates directories in a path, e.g. "/" for Unix, ":" for Mac, and "\" for Win32. This is normally set in system.lsp.

    *rslt*
    When a function returns more than one value, *rslt* is set to a list of the "extra" values. This provides a make-shift version of the multiple-value-return facility in Common Lisp.

    *sound-srate*
    Part of the environment, establishes the audio sample rate. See Section "The Environment" for details.

    *soundenable*
    Controls whether writes to a sound file will also be played as audio. Set this variable by calling (sound-on) or (sound-off).

    *tracenable*
    Controls whether XLISP prints a backtrace when an error is encountered.

    XLISP variables
    See Section "Profiling" for a list of global variables defined by XLISP.

    Environment variables
    See Section "The Environment" for definitions of variables used in the environment for behaviors. In general, you should never set or access these variables directly.

    Various constants
    See Section "Predefined Constants" for definitions of predefined constants for loudness, duration, and pitch.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/bilateral-fig.gif0000644000175000000620000000211411466723256016133 0ustar stevestaffGIF87a w!Software: Microsoft Office, t޼edrʶ CWzЈ\b|Ģ KC 8%Jjr N춛cjy?|'8$GCŨh9IaX1ç( ::IbJ yژJz*;kg*z˶ |\tll@ ]4kӅUN~s^>!N,J->~U{ɣVJur0%ZTPQōmH1NjXI*1dR{)]ΤErCRۙgN$oG֚eͩRМ>ZTѶZVĎ%ցY~e;OpmɝX]yIeo%IjҟcR\Kj8peE '#M=R:iԩ-oZѳٱ]]m sZܷ༅"Nڸh 5+üBd[vٯGta_yK~ L__ ~LM Re)x B*B^ZC20^sF642!3׉(n# 28c*ȣ1~bq>c49BJ"BFd@6SRYeN> eB6:Ib))ɦȂIPg邜ɥzf&:9hz2 fRh^bUч}fZ#J$'*Dꌬ:T0rꜢ#["bl=D&gDt;vXvh?E;-3ە~VKG,Q_Cp\^/ 'px{T1pAwm4d\ɉtllg02j~k\ K43=L;4L[TKg4H vbMvfvjvACh&ǝ5ٍ77ڦRnd,|^ >@4.۶2 1$~DyQ;nyquist-3.05/doc/nyqman.txt0000644000175000000620000235530011537432671015015 0ustar stevestaff NYQUIST REFERENCE MANUAL Version 3.05 Copyright 2011 by Roger B. Dannenberg 14 March 2011 Carnegie Mellon University School of Computer Science Pittsburgh, PA 15213, U.S.A. . Preface This manual is a guide for users of Nyquist, a language for composition and sound synthesis. Nyquist grew out of a series of research projects, notably the languages Arctic and Canon. Along with Nyquist, these languages promote a functional style of programming and incorporate time into the language semantics. Please help by noting any errors, omissions, or suggestions you may have. You can send your suggestions to Dannenberg@CS.CMU.EDU (internet) via computer mail, or by campus mail to Roger B. Dannenberg, School of Computer Science, or by ordinary mail to Roger B. Dannenberg, School of Computer Science, Carnegie Mellon University, 5000 Forbes Ave., Pittsburgh, PA 15213-3890, USA. Nyquist is a successor to Fugue, a language originally implemented by Chris Fraley, and extended by George Polly and Roger Dannenberg. Peter Velikonja and Dean Rubine were early users, and they proved the value as well as discovered some early problems of the system. This led to Nyquist, a reimplementation of Fugue by Roger Dannenberg with help from Joe Newcomer and Cliff Mercer. Ning Hu ported Zheng (Geoffrey) Hua and Jim Beauchamp's piano synthesizer to Nyquist and also built NyqIDE, the Nyquist Integrated Development Environment for Windows. Dave Mowatt contributed the original version of NyquistIDE, the cross-platform interactive development environment. Dominic Mazzoni made a special version of Nyquist that runs within the Audacity audio editor, giving Nyquist a new interface and introducing Nyquist to many new users. Many others have since contributed to Nyquist. Chris Tchou and Morgan Green worked on the Windows port. Eli Brandt contributed a number of filters and other synthesis functions. Pedro J. Morales, Eduardo Reck Miranda, Ann Lewis, and Erich Neuwirth have all contributed nyquist examples found in the demos folder of the Nyquist distribution. Philip Yam ported some synthesis functions from Perry Cook and Gary Scavone's STK to Nyquist. Pedro Morales ported many more STK instruments to Nyquist. Dave Borel wrote the Dolby Pro-Logic encoding library and Adam Hartman wrote stereo and spatialization effects. Stephen Mangiat wrote the MiniMoog emulator. Phil Light recorded the drum samples and wrote drum machine software. The Xmusic library, particularly the pattern specification, was inspired by Rick Taube's Common Music. The functions for generating probability distributions were implemented by Andreas Pfenning. Starting with Version 3, Nyquist supports a version of SAL, providing an alternative to Lisp syntax. SAL was designed by Rick Taube, and the SAL implementation in Nyquist is based on Taube's original implementation as part of his Common Music system. The current NyquistIDE includes contributions from many. Chris Yealy and Derek D'Souza implemented early versions of the envelope editor. Daren Makuck and Michael Rivera wrote the original equalizer editor. Priyanka Raghavan implemented the sound browser. Dmitry Portnoy wrote the original "UPIC" editor. Many others have made contributions, offered suggestions, and found bugs. If you were expecting to find your name here, I apologize for the omission, and please let me know. I also wish to acknowledge support from CMU, Yamaha, and IBM for this work. . 1. Introduction and Overview Nyquist is a language for sound synthesis and music composition. Unlike score languages that tend to deal only with events, or signal processing languages that tend to deal only with signals and synthesis, Nyquist handles both in a single integrated system. Nyquist is also flexible and easy to use because it is based on an interactive Lisp interpreter. With Nyquist, you can design instruments by combining functions (much as you would using the orchestra languages of Music V, cmusic, or Csound). You can call upon these instruments and generate a sound just by typing a simple expression. You can combine simple expressions into complex ones to create a whole composition. Nyquist runs under Linux, Apple Mac OS X, Microsoft Windows NT, 2000, XP, and Vista, and it produces sound files or directly generates audio. Recent versions have also run on AIX, NeXT, SGI, DEC pmax, and Sun Sparc machines. (Makefiles for many of these are included, but out-of-date). Let me know if you have problems with any of these machines. To use Nyquist, you should have a basic knowledge of Lisp. An excellent text by Touretzky is recommended [Touretzky 84]. Appendix IV is the reference manual for XLISP, of which Nyquist is a superset. Starting with Version 3, Nyquist supports a variant of SAL, which is also available in Common Music. Since there are some differences, one should generally call this implementation ``Nyquist SAL;'' however, in this manual, I will just call it ``SAL.'' SAL offers most of the capabilities of Lisp, but it uses an Algol-like syntax that may be more familiar to programmers with experience in Java, C, Basic, etc. 1.1. Installation Nyquist is a C++ program intended to run under various operating systems including Unix, Mac OS X, and Windows. Nyquist is based on Lisp, but it includes its own Lisp interpreter (a modified version of XLISP), so you do not need to install some other Lisp to run Nyquist. Other Lisp systems are not compatible with Nyquist. Most Nyquist users run Nyquist under the Nyquist IDE, which is written in Java and depends on the Java runtime system. Most systems already have Java, but if you do not, you will need to install it. When you install the Nyquist IDE, you will automatically get Nyquist and a set of runtime libraries. There are generally two ways to install Nyquist: - Get a pre-compiled version of the Nyquist IDE for Windows or Mac OS X. The Windows version comes packaged in an installer that installs and configures the Nyquist IDE. The Mac OS X version unpacks to a complete OS X application. - Compile from sources. There is one set of sources for Mac, Windows, and Unix. Instructions for building applications from the sources are provided in the files sys/win/README.txt, sys/mac/README.txt, and sys/unix/README.txt. You can download source code and precompiled versions from the Nyquist project on SourceForge (http://sourceforge.net/projects/nyquist). The latest source code can be obtained via Subversion (svn) using the following: svn co https://nyquist.svn.sourceforge.net/svnroot/nyquist/trunk nyquis or by checking out nyquist using a graphical interface svn client such as TortoiseSVN for Windows. 1.2. Using NyquistIDE The program named NyquistIDE is an ``integrated development environment'' for Nyquist. When you run NyquistIDE, it starts the Nyquist program and displays all Nyquist output in a window. NyquistIDE helps you by providing a Lisp and SAL editor, hints for command completion and function parameters, some graphical interfaces for editing envelopes and graphical equalizers, and a panel of buttons for common operations. A more complete description of NyquistIDE is in Chapter 2. For now, all you really need to know is that you can enter Nyquist commands by typing into the upper left window. When you type return, the expression you typed is sent to Nyquist, and the results appear in the window below. You can edit files by clicking on the New File or Open File buttons. After editing some text, you can load the text into Nyquist by clicking the Load button. NyquistIDE always saves the file first; then it tells Nyquist to load the file. You will be prompted for a file name the first time you load a new file. 1.3. Using SAL SAL mode means that Nyquist reads and evaluates SAL commands rather than Lisp. The SAL mode prompt is "SAL> " while the Lisp mode prompt is "> ". When Nyquist starts it normally enters SAL mode automatically, but certain errors may exit SAL mode. You can reenter SAL mode by typing the Lisp expression (sal). In SAL mode, you type commands in the SAL programming language. Nyquist reads the commands, compiles them into Lisp, and evaluates the commands. Commands can be entered manually by typing into the upper left text box in NyquistIDE. 1.4. Helpful Hints Under Win95 and Win98, the console sometimes locks up. Activating another window and then reactivating the Nyquist window should unlock the output. (We suggest you use JNyqIDE, the interactive development environment rather than a console window.) You can cut and paste text into Nyquist, but for serious work, you will want to use the Lisp load command. To save even more time, write a function to load your working file, e.g. (defun l () (load "myfile.lsp")). Then you can type (l) to (re)load your file. Using SAL, you can type define function l () load "myfile.lsp" and then exec l() to (re)load the file. The Emacs editor is free GNU software and will help you balance parentheses if you use Lisp mode. In fact, you can run nyquist (without the IDE) as a subprocess to Emacs. A helful discussion is at //http://www.audacity- forum.de/download/edgar/nyquist/nyquist-doc/examples/emacs/main.html. If you use Emacs, there is also a SAL mode (the file is sal-mode.el) included with the Common Music distribution, which you can find on the Web at sourceforge.net. The NyquistIDE also runs Nyquist as a subprocess and has built-in Lisp and SAL editors. If your editor does not help you balance parentheses, you may find yourself counting parens and searching for unbalanced expressions. If you are confused or desperate and using Lisp syntax, try the :print t option of the load function. By looking at the expressions printed, you should be able to tell where the last unbalanced expression starts. Alternatively, type (file-sexprs) and type the lisp file name at the prompt. This function will read and print expressions from the file, reporting an error when an extra paren or end-of-file is reached unexpectedly. 1.5. Using Lisp Lisp mode means that Nyquist reads and evaluates Nyquist expressions in Lisp syntax. Since Nyquist is build on a Lisp interpreter, this is the ``native'' or machine language of Nyquist, and certain errors and functions may break out of the SAL interpreter, leaving you with a prompt for a Lisp expression. Alternatively, you can exit SAL simply by typing exit to get a Lisp prompt (> ). Commands can be entered manually by typing into the upper left text box in NyquistIDE. 1.6. Examples We will begin with some simple Nyquist programs. Throughout the manual, we will assume SAL mode and give examples in SAL, but it should be emphasized that all of these examples can be performed using Lisp syntax. See Section 6.2 on the relationship between SAL and Lisp. Detailed explanations of the functions used in these examples will be presented in later chapters, so at this point, you should just read these examples to get a sense of how Nyquist is used and what it can do. The details will come later. Most of these examples can be found in the file nyquist/demos/examples.sal. Corresponding Lisp syntax examples are in the file nyquist/demos/examples.lsp. Our first example makes and plays a sound: ;; Making a sound. play osc(60) ; generate a loud sine wave This example is about the simplest way to create a sound with Nyquist. The osc function generates a sound using a table-lookup oscillator. There are a number of optional parameters, but the default is to compute a sinusoid with an amplitude of 1.0. The parameter 60 designates a pitch of middle C. (Pitch specification will be described in greater detail later.) The result of the osc function is a sound. To hear a sound, you must use the play command, which plays the file through the machine's D/A converters. It also writes a soundfile in case the computation cannot keep up with real time. You can then (re)play the file by typing: exec r() This (r) function is a general way to ``replay'' the last thing written by play. 15 Note: when Nyquist plays a sound, it scales the signal by 2 -1 and (by default) converts to a 16-bit integer format. A signal like (osc 60), which ranges from +1 to -1, will play as a full-scale 16-bit audio signal. 1.6.1. Waveforms Our next example will be presented in several steps. The goal is to create a sound using a wavetable consisting of several harmonics as opposed to a simple sinusoid. In order to build a table, we will use a function that computes a single harmonic and add harmonics to form a wavetable. An oscillator will be used to compute the harmonics. The function mkwave calls upon build-harmonic to generate a total of four harmonics with amplitudes 0.5, 0.25, 0.125, and 0.0625. These are scaled and added (using +) to create a waveform which is bound temporarily to *table*. A complete Nyquist waveform is a list consisting of a sound, a pitch, and T, indicating a periodic waveform. The pitch gives the nominal pitch of the sound. (This is implicit in a single cycle wave table, but a sampled sound may have many periods of the fundamental.) Pitch is expressed in half-steps, where middle C is 60 steps, as in MIDI pitch numbers. The list of sound, pitch, and T is formed in the last line of mkwave: since build-harmonic computes signals with a duration of one second, the fundamental is 1 Hz, and the hz-to-step function converts to pitch (in units of steps) as required. define function mkwave() begin set *table* = 0.5 * build-harmonic(1.0, 2048) + 0.25 * build-harmonic(2.0, 2048) + 0.125 * build-harmonic(3.0, 2048) + 0.0625 * build-harmonic(4.0, 2048) set *table* = list(*table*, hz-to-step(1.0), #t) end Now that we have defined a function, the last step of this example is to build the wave. The following code calls mkwave the first time the code is executed (loaded from a file). The second time, the variable *mkwave* will be true, so mkwave will not be invoked: if ! fboundp(quote(*mkwave*)) then begin exec mkwave() set *mkwave* = #t end 1.6.2. Wavetables When Nyquist starts, several waveforms are created and stored in global variables for convenience. They are: *sine-table*, *saw-table*, and *tri-table*, implementing sinusoid, sawtooth, and triangle waves, respectively. The variable *table* is initialized to *sine-table*, and it is *table* that forms the default wave table for many Nyquist oscillator behaviors. If you want a proper, band-limited waveform, you should construct it yourself, but if you do not understand this sentence and/or you do not mind a bit of aliasing, give *saw-table* and *tri-table* a try. Note that in Lisp and SAL, global variables often start and end with asterisks (*). These are not special syntax, they just happen to be legal characters for names, and their use is purely a convention. 1.6.3. Sequences Finally, we define my-note to use the waveform, and play several notes in a simple score. Note that the function my-note has only one command (a return command), so it is not necessary to use begin and end. These are only necessary when the function body consists of a sequence of statements: define function my-note(pitch, dur) return osc(pitch, dur, *table*) play seq(my-note(c4, i), my-note(d4, i), my-note(f4, i), my-note(g4, i), my-note(d4, q)) Here, my-note is defined to take pitch and duration as parameters; it calls osc to do the work of generating a waveform, using *table* as a wave table. The seq function is used to invoke a sequence of behaviors. Each note is started at the time the previous note finishes. The parameters to my-note are predefined in Nyquist: c4 is middle C, i (for eIghth note) is 0.5, and q (for Quarter note) is 1.0. See Section 1.7 for a complete description. The result is the sum of all the computed sounds. Sequences can also be constructed using the at transformation to specify time offsets. See sequence_example.htmdemos, sequence for more examples and explanation. 1.6.4. Envelopes The next example will illustrate the use of envelopes. In Nyquist, envelopes are just ordinary sounds (although they normally have a low sample rate). An envelope is applied to another sound by multiplication using the mult function. The code shows the definition of env-note, defined in terms of the note function in the previous example. In env-note, a 4-phase envelope is generated using the env function, which is illustrated in Figure 1. Figure 1: An envelope generated by the env function. ; env-note produces an enveloped note. The duration ; defaults to 1.0, but stretch can be used to change ; the duration. ; Uses my-note, defined above. ; define function env-note(p) return my-note(p, 1.0) * env(0.05, 0.1, 0.5, 1.0, 0.5, 0.4) ; try it out: ; play env-note(c4) While this example shows a smooth envelope multiplied by an audio signal, you can also multiply audio signals to achieve what is often called ring modulation. See the code and description in demos/scratch_tutorial.htm for an interesting use of ring modulation to create ``scratch'' sounds. In the next example, The stretch operator (~)is used to modify durations: ; now use stretch to play different durations ; play seq(seq(env-note(c4), env-note(d4)) ~ 0.25, seq(env-note(f4), env-note(g4)) ~ 0.5, env-note(c4)) In addition to stretch, there are a number of transformations supported by Nyquist, and transformations of abstract behaviors is perhaps the fundamental idea behind Nyquist. Chapter 3 is devoted to explaining this concept, and further elaboration can be found elsewhere [Dannenberg 89]. 1.6.5. Piece-wise Linear Functions It is often convenient to construct signals in Nyquist using a list of (time, value) breakpoints which are linearly interpolated to form a smooth signal. Envelopes created by env are a special case of the more general piece-wise linear functions created by pwl. Since pwl is used in some examples later on, we will take a look at pwl now. The pwl function takes a list of parameters which denote (time, value) pairs. There is an implicit initial (time, value) pair of (0, 0), and an implicit final value of 0. There should always be an odd number of parameters, since the final value (but not the final time) is implicit. Here are some examples: ; symetric rise to 10 (at time 1) and fall back to 0 (at time 2): ; pwl(1, 10, 2) ; a square pulse of height 10 and duration 5. ; Note that the first pair (0, 10) overrides the default initial ; point of (0, 0). Also, there are two points specified at time 5: ; (5, 10) and (5, 0). (The last 0 is implicit). The conflict is ; automatically resolved by pushing the (5, 10) breakpoint back to ; the previous sample, so the actual time will be 5 - 1/sr, where ; sr is the sample rate. ; pwl(0, 10, 5, 10, 5) ; a constant function with the value zero over the time interval ; 0 to 3.5. This is a very degenerate form of pwl. Recall that there ; is an implicit initial point at (0, 0) and a final implicit value of ; 0, so this is really specifying two breakpoints: (0, 0) and (3.5, 0): ; pwl(3.5) ; a linear ramp from 0 to 10 and duration 1. ; Note the ramp returns to zero at time 1. As with the square pulse ; above, the breakpoint (1, 10) is pushed back to the previous sample. ; pwl(1, 10, 1) ; If you really want a linear ramp to reach its final value at the ; specified time, you need to make a signal that is one sample longer. ; The RAMP function does this: ; ramp(10) ; ramp from 0 to 10 with duration 1 + one sample period ; ; RAMP is based on PWL; it is defined in nyquist.lsp. ; 1.7. Predefined Constants For convenience and readability, Nyquist pre-defines some constants, mostly based on the notation of the Adagio score language, as follows: - Dynamics Note: these dynamics values are subject to change. lppp = -12.0 (dB) lpp = -9.0 lp = -6.0 lmp = -3.0 lmf = 3.0 lf = 6.0 lff = 9.0 lfff = 12.0 dB0 = 1.00 dB1 = 1.122 dB10 = 3.1623 - Durations s = Sixteenth = 0.25 i = eIghth = 0.5 q = Quarter = 1.0 h = Half = 2.0 w = Whole = 4.0 sd, id, qd, hd, wd = dotted durations. st, it, qt, ht, wt = triplet durations. - PitchesPitches are based on an A4 of 440Hz. To achieve a different tuning, set *A4-Hertz* to the desired frequency for A4, and call (set-pitch-names). This will recompute the names listed below with a different tuning. In all cases, the pitch value 69.0 corresponds exactly to 440Hz, but fractional values are allowed, so for example, if you set *A4-Hertz* to 444 (Hz), then the symbol A4 will be bound to 69.1567, and C4 (middle C), which is normally 60.0, will be 60.1567. c0 = 12.0 cs0, df0 = 13.0 d0 = 14.0 ds0, ef0 = 15.0 e0 = 16.0 f0 = 17.0 fs0, gf0 = 18.0 g0 = 19.0 gs0, af0 = 20.0 a0 = 21.0 as0, bf0 = 22.0 b0 = 23.0 c1 ... b1 = 24.0 ... 35.0 c2 ... b2 = 36.0 ... 47.0 c3 ... b3 = 48.0 ... 59.0 c4 ... b4 = 60.0 ... 71.0 c5 ... b5 = 72.0 ... 83.0 c6 ... b6 = 84.0 ... 95.0 c7 ... b7 = 96.0 ... 107.0 c8 ... b8 = 108.0 ... 119.0 - Miscellaneous ny:all = ``all the samples'' (i.e. a big number) = 1000000000 1.8. More Examples More examples can be found in the directory demos, part of the standard Nyquist release. The file demos/examples_home.htm is an index to all the demo descriptions. In this directory, you will find the following and more: - How to make arpeggios (demos/arpeggiator.htm and arp.sal - Gong sounds by additive synthesis(demos/pmorales/b1.lsp and demos/mateos/gong.lsp - Risset's spectral analysis of a chord (demos/pmorales/b2.lsp) - Bell sounds (demos/pmorales/b3.lsp, demos/pmorales/e2.lsp, demos/pmorales/partial.lsp, and demos/mateos/bell.lsp) - Drum sounds by Risset (demos/pmorales/b8.lsp - Shepard tones (demos/shepard.lsp and demos/pmorales/b9.lsp) - Random signals (demos/pmorales/c1.lsp) - Buzz with formant filters (demos/pmorales/buzz.lsp - Computing samples directly in Lisp (using Karplus-Strong and physical modelling as examples) (demos/pmorales/d1.lsp - FM Synthesis examples, including bell, wood drum, brass sounds, tuba sound (demos/mateos/tuba.lsp and clarinet sounds (demos/pmorales/e2.lsp - Rhythmic patterns (demos/rhythm_tutorial.htm - Drum Samples and Drum Machine (demos/plight/drum.lsp. (See Section 14.13). 2. The NyquistIDE Program The NyquistIDE program combines many helpful functions and interfaces to help you get the most out of Nyquist. NyquistIDE is implemented in Java, and you will need the Java runtime system or development system installed on your computer to use NyquistIDE. The best way to learn about NyquistIDE is to just use it. This chapter introduces some of the less obvious features. If you are confused by something and you do not find the information you need here, please contact the author. 2.1. NyquistIDE Overview The NyquistIDE runs the command-line version of Nyquist as a subtask, so everything that works in Nyquist should work when using the NyquistIDE and vice-versa. Input to Nyquist is usually entered in the top left window of the NyquistIDE. When you type return, if the expression or statement appears to be complete, the expression you typed is sent to Nyquist. Output from Nyquist appears in a window below. You cannot type into or edit the output window text. The normal way to use the NyquistIDE is to create or open one or more files. You edit these files and then click the Load button. To load a file, NyquistIDE saves the file, sets the current directory of Nyquist to that of the file, then issues a load command to Nyquist. In this case and several others, you may notice that NyquistIDE sends expressions to Nyquist automatically for evaluation. You can always see the commands and their results in the output window. Notice that when you load a selected file window, NyquistIDE uses setdir to change Nyquist's current directory. This helps to keep the two programs in sync. Normally, you should keep all the files of a project in the same directory and avoid manually changing Nyquist's current directory (i.e. avoid calling setdir in your code). Arranging windows in the NyquistIDE can be time-consuming, and depending on the operating system, it is possible for a window to get into a position where you cannot drag it to a new position. The Window:Tile menu command can be used to automatically lay out windows in a rational way. There is a preference setting to determine the height of the completion list relative to the height of the output window. 2.2. The Button Bar There are a number of buttons with frequently-used operations. These are: - Info M Print information about Nyquist memory utilization, including the number of free cons cells, the number of garbage collections, the total number of cons cells, the total amount of sample buffer memory, and the amount of memory in free sample buffers. - Break M Send a break character to XLISP. This can be used to enter the debugger (the break loop) while a program is running. Resume by typing (co). - SAL/Lisp M Switch modes. The button names the mode (SAL or Lisp) you will switch to, not the current mode. For example, if you are in Lisp mode and want to type a SAL command, click the SAL button first. - Top M Enters (top) into Nyquist. If the XLISP prompt is 1> or some other integer followed by ``>'', clicking the Top button will exit the debug loop and return to the top-level prompt. - Replay M Enters (r) into Nyquist. This command replays the last computed sound. - F2-F12 M Enters (f2) etc. into Nyquist. These commands are not built-in, and allow users to define their own custom actions. - Browse M Equivalent to the Window:Browse menu item. (See Section 2.4.) - EQ M Equivalent to the Window:EQ menu item. (See Section 2.6.) - EnvEdit M Equivalent to the Window:Envelope Edit menu item. (See Section 2.5.) - NewFile M Equivalent to the File:New menu item. Opens a new file editing window for creating and loading a Lisp or SAL program file. - OpenFile M Equivalent to the File:Open menu item. Opens an existing Lisp or SAL program file for editing and loading. - SaveFile M Equivalent to the File:Save menu item (found on the editing window's menu bar). Saves the contents of an editing window to its associated file. - Load M Equivalent to the File:Load menu item (found on the editing window's menu bar). Performs a Save operation, then sends a command to Nyquist that loads the file as a program. - Mark M Sends a Control-A to Nyquist. While playing a sound, this displays and records the approximate time in the audio stream. (See Section 7.5 for more detail.) 2.3. Command Completion To help with programming, NyquistIDE maintains a command-completion window. As you type the first letters of function names, NyquistIDE lists matching functions and their parameters in the Completion List window. If you click on an entry in this window, the displayed expression will replace the incompletely typed function name. A preference allows you to match initial letters or any substring of the complete function name. This is controlled by the ``Use full search for code completion'' preference. In addition, if you right click (or under Mac OS X, hold down the Alt/Option key and click) on an entry, NyquistIDE will display documentation for the function. Documentation can come from a local copy or from the online copy (determined by the ``Use online manual instead of local copy'' preference). Documentation can be displayed within the NyquistIDE window or in an external browser (determined by the ``Use window in NyquistIDE for help browser'' preference.) Currently, the external browser option does not seem to locate documentation properly, but this should be fixed in the future. 2.4. Browser If you click on the Browse button or use the Window:Browse menu command, NyquistIDE will display a browser window that is pre-loaded with a number of Nyquist commands to create sounds. You can adjust parameters, audition the sounds, and capture the expression that creates the sound. In many cases, the expression checks to see if necessary functions are defined, loading files if necessary before playing the sound. If you want to use a sound in your own program, you can often simplify things by explicitly loading the required file just once at the beginning of your file. Since Nyquist now supports a mix of Lisp and SAL, you may find yourself in the position of having code from the browser in one language while you are working in the other. The best way to handle this is to put the code for the sound you want into a function defined in a Lisp (.lsp) or SAL (.sal) file. Load the file (from Lisp, use the sal-load command to load a SAL file), and call the function from the language of your choice. 2.5. Envelope Editor The envelope editor allows you graphically to design and edit piece-wise linear and exponential envelopes. The editor maintains a list of envelopes and you select the one to edit or delete using the drop down list in the Saved Envelopes List area. The current envelope appears in the Graphical Envelope Editor area. You can click to add or drag points. Alternatively, you can use the Envelope Points window to select and edit any breakpoint by typing coordinates. The duration of the envelope is controlled by the Stop field in the Range area, and the vertical axis is controlled by the Min and Max fields. When you click the Save button, all envelopes are written to Nyquist. You can then use the envelope by treating the envelope name as a function. For example, if you define an envelope named ``fast-attack,'' then you can create the envelope within a Nyquist SAL program by writing the expression fast-attack(). These edited envelopes are saved to a file named workspace.lsp in the current directory. The workspace is Nyquist's mechanism for saving data of all kinds (see Section 13.4.5). The normal way to work with workspaces is to (1) load the workspace, i.e. load "workspace", as soon as you start Nyquist; (2) invoke the envelope editor to change values in the workspace; and (3) save the workspace at any time, especially before you exit NyquistIDE. If you follow these steps, envelopes will be preserved from session to session, and the entire collection of envelopes will appear in the editor. Be sure to make backups of your workspace.lsp file along with your other project files. The envelope editor can create linear and exponential envelopes. Use the Type pull-down menu to select the type you want. Envelopes can be created using default starting and ending values using pwl or pwe, or you can specify the initial values using pwlv or pwev. The envelope editor uses pwl or pwe if no point is explicitly entered as the initial or final point. To create a pwlv or pwev function, create a point and drag it to the leftmost or rightmost edge of the graphical editing window. You will see the automatically generated default starting or ending point disappear from the graph. Exponential envelopes should never decay to zero. If you enter a zero amplitude, you will see that the envelope remains at zero to the next breakpoint. To get an exponential decay to ``silence,'' try using an amplitude of about 0.001 (about -60dB). To enter small values like this, you can type them into the Amplitude box and click ``Update Point.'' The Load button refreshes the editor from data saved in the Nyquist process. Normally, there is no need to use this because the editor automatically loads data when you open it. 2.6. Equalizer Editor The Equalizer Editor provides a graphical EQ interface for creating and adjusting equalizers. Unlike the envelope editor, where you can type any envelope name, equalizers are named eq-0, eq-1, etc., and you select the equalizer to edit using a pull-down menu. The Set button should be use to record changes. 2.7. UPIC Editor The UPIC Editor is inspired by the UPIC system by Iannis Xenakis at the Centre d'Edudes de Mathematique et Automatique Musicales (CEMaMu). The UPIC Editor is accessed by the ``Upic Edit'' menu item in the ``Window'' menu of the NyquistIDE. Once opened, you can draw pitch contours in the main panel by pressing the left mouse button and dragging with the mouse down. Contours represent tones in a frequency vs. time coordinate system. Any contour can be deleted by right-clicking (or shift-clicking on an Apple computer) to select the contour (indicated by the color red), and typing the Delete key. A collection of contours can be saved to a file and later retrieved using the items in the File menu (use the File menu in the UPIC Editor window, not in the main NyquistIDE window.) The file is a SAL program in a special format that can be parsed by the UPIC Editor. The file can also be loaded into Nyquist using the File:Load menu item, or by executing a load command in Nyquist. The panel at the top of the editor offers control over various parameters. The Name box is a Nyquist variable name. This name takes effect when you save a file from the UPIC Editor. The variable name is stored in the file so that when a UPIC Editor-generated file is loaded into Nyquist, the data is assigned to this variable name. The data is a list of contours, where each contour specifies a waveform, an envelope, and a list of time-frequency coordinates. The next item in the panel is the Waveform box. The Waveform box names a waveform for a contour. Default waveforms are sinusoid, triangle, and sawtooth, but you can type in your own names. The currently selected waveform is stored with the contour when it is created (entered by drawing). You cannot change or edit the waveform name associated with a contour once the contour is created, but you can always delete the contour and replace it. The Envelope box names an envelope for a contour. The envelope names a Nyquist function. The default, upic-env is a trapezoid shape with an onset time and offset time of 10ms. As with waveforms, the envelope is stored with each contour when the contour is created and cannot be edited. The Stop Time box gives the duration of the drawing area in seconds. The Min Freq box gives the minimum frequency (at the bottom of the drawing area), and the Max Freq box gives the maximum frequency (at the top of the drawing area). The vertical frequency axis can use a linear scale corresponding to frequency in Hertz or a logarithmic scale corresponding to semitones. The ``linear'' checkbox selects the linear scale. When any of these parameters (described in this paragraph and delimited by the border labeled ``Range'' on the control panel) is changed, you must press the Update Range button for the change to take effect. The Background menu lets you display a grid that indicates pitch locations. The ``C's'' item draws a line at C in every visible octave. E.g. middle C is about 260 Hz, so a reference line will be drawn near 260 Hz. Lines will be drawn around 130 Hz (an octave below middle C), and around 520 Hz (an octave above middle C), etc. The ``GrandStaff'' menu item draws reference lines for each line of the grand staff commonly used for piano music. The pitches are G2, B2, D3, F3, A3, E4, G4, B4, D5, and F5. Finally, you can load a picture using the Background:Load Picture... menu item. Then, the Background:Show Picture menu item toggles whether the picture is displayed or not. This feature allows you to trace an image. (For example, see the Sonic Self-Portrait at http://www.cs.cmu.edu/~rbd.) You may wish to use an image editor to lighten the image so that superimposed contours will be more visible. Each change to the Range data, background choice, and each entry of a contour is an action that you can undo or redo with the Undo and Redo buttons. To convert UPIC data into sound, first load upic.sal and load a file generated by the UPIC Editor. Now, suppose the variable name used is upicdata. You can play the data by writing play upic(upicdata) If you created your own names for waveforms or envelopes, you must be sure that these exist before calling the upic function. Each waveform must be the name of a variable which is set to a Nyquist wave table. (See Section 1.6.1 for information on how to create a wave table.) Also, each envelope must name a function with no parameters that will return an amplitude envelope. The following is the built-in definition for upic-env: define function upic-env() return env(0.01, 0.01, 0.01, 1, 1, 1) To make a custom envelope function named upic-smooth with a 0.2 second attack and a 0.3 second decay, you could write: define function upic-smooth() return env(0.2, 0.01, 0.3, 1, 1, 1) 3. Behavioral Abstraction In Nyquist, all functions are subject to transformations. You can think of transformations as additional parameters to every function, and functions are free to use these additional parameters in any way. The set of transformation parameters is captured in what is referred to as the transformation environment. (Note that the term environment is heavily overloaded in computer science. This is yet another usage of the term.) Behavioral abstraction is the ability of functions to adapt their behavior to the transformation environment. This environment may contain certain abstract notions, such as loudness, stretching a sound in time, etc. These notions will mean different things to different functions. For example, an oscillator should produce more periods of oscillation in order to stretch its output. An envelope, on the other hand, might only change the duration of the sustain portion of the envelope in order to stretch. Stretching a sample could mean resampling it to change its duration by the appropriate amount. Thus, transformations in Nyquist are not simply operations on signals. For example, if I want to stretch a note, it does not make sense to compute the note first and then stretch the signal. Doing so would cause a drop in the pitch. Instead, a transformation modifies the transformation environment in which the note is computed. Think of transformations as making requests to functions. It is up to the function to carry out the request. Since the function is always in complete control, it is possible to perform transformations with ``intelligence;'' that is, the function can perform an appropriate transformation, such as maintaining the desired pitch and stretching only the ''sustain'' portion of an envelope to obtain a longer note. 3.1. The Environment The transformation environment consists of a set of special variables. These variables should not be read directly and should never be set directly by the programmer. Instead, there are functions to read them, and they are automatically set and restored by transformation operators, which will be described below. The transformation environment consists of the following elements. Although each element has a ``standard interpretation,'' the designer of an instrument or the composer of a complex behavior is free to interpret the environment in any way. For example, a change in *loud* may change timbre more than amplitude, and *transpose* may be ignored by percussion instruments: *warp* Time transformation, including time shift, time stretch, and continuous time warp. The value of *warp* is interpreted as a function from logical (local score) time to physical (global real) time. Do not access *warp* directly. Instead, use local-to-global(t) to convert from a logical (local) time to real (global) time. Most often, you will call local-to- global(0). Several transformation operators operate on *warp*, including at (@), stretch (~), and warp. See also get-duration() and get-warp(). *loud* Loudness, expressed in decibels. The default (nominal) loudness is 0.0 dB (no change). Do not access *loud* directly. Instead, use get-loud() to get the current value of *loud* and either loud or loud-abs to modify it. *transpose* Pitch transposition, expressed in semitones. (Default: 0.0). Do not access *transpose* directly. Instead, use get-transpose() to get the current value of *transpose* and either transpose or transpose-abs to modify it. *sustain* The ``sustain,'' ``articulation,'' ``duty factor,'' or amount by which to separate or overlap sequential notes. For example, staccato might be expressed with a *sustain* of 0.5, while very legato playing might be expressed with a *sustain* of 1.2. Specifically, *sustain* stretches the duration of notes (sustain) without affecting the inter-onset time (the rhythm). Do not access *sustain* directly. Instead, use get-sustain() to get the current value of *sustain* and either sustain or sustain-abs to modify it. *start* Start time of a clipping region. Note: unlike the previous elements of the environment, *start* has a precise interpretation: no sound should be generated before *start*. This is implemented in all the low-level sound functions, so it can generally be ignored. You can read *start* directly, but use extract or extract-abs to modify it. Note 2: Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, *start* is not fully implemented. *stop* Stop time of clipping region. By analogy to *start*, no sound should be generated after this time. *start* and *stop* allow a composer to preview a small section of a work without computing it from beginning to end. You can read *stop* directly, but use extract or extract-abs to modify it. Note: Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, *stop* is not fully implemented. *control-srate* Sample rate of control signals. This environment element provides the default sample rate for control signals. There is no formal distinction between a control signal and an audio signal. You can read *control-srate* directly, but use control-srate or control-srate-abs to modify it. *sound-srate* Sample rate of musical sounds. This environment element provides the default sample rate for musical sounds. You can read *sound-srate* directly, but use sound-srate or sound-srate-abs to modify it. 3.2. Sequential Behavior Previous examples have shown the use of seq, the sequential behavior operator. We can now explain seq in terms of transformations. Consider the simple expression: play seq(my-note(c4, q), my-note(d4, i)) The idea is to create the first note at time 0, and to start the next note when the first one finishes. This is all accomplished by manipulating the environment. In particular, *warp* is modified so that what is locally time 0 for the second note is transformed, or warped, to the logical stop time of the first note. One way to understand this in detail is to imagine how it might be executed: first, *warp* is set to an initial value that has no effect on time, and my-note(c4, q) is evaluated. A sound is returned and saved. The sound has an ending time, which in this case will be 1.0 because the duration q is 1.0. This ending time, 1.0, is used to construct a new *warp* that has the effect of shifting time by 1.0. The second note is evaluated, and will start at time 1. The sound that is returned is now added to the first sound to form a composite sound, whose duration will be 2.0. *warp* is restored to its initial value. Notice that the semantics of seq can be expressed in terms of transformations. To generalize, the operational rule for seq is: evaluate the first behavior according to the current *warp*. Evaluate each successive behavior with *warp* modified to shift the new note's starting time to the ending time of the previous behavior. Restore *warp* to its original value and return a sound which is the sum of the results. In the Nyquist implementation, audio samples are only computed when they are needed, and the second part of the seq is not evaluated until the ending time (called the logical stop time) of the first part. It is still the case that when the second part is evaluated, it will see *warp* bound to the ending time of the first part. A language detail: Even though Nyquist defers evaluation of the second part of the seq, the expression can reference variables according to ordinary Lisp/SAL scope rules. This is because the seq captures the expression in a closure, which retains all of the variable bindings. 3.3. Simultaneous Behavior Another operator is sim, which invokes multiple behaviors at the same time. For example, play 0.5 * sim(my-note(c4, q), my-note(d4, i)) will play both notes starting at the same time. The operational rule for sim is: evaluate each behavior at the current *warp* and return the sum of the results. (In SAL, the sim function applied to sounds is equivalent to adding them with the infix + operator. The following section illustrates two concepts: first, a sound is not a behavior, and second, the sim operator and and the at transformation can be used to place sounds in time. 3.4. Sounds vs. Behaviors The following example loads a sound from a file in the current directory and stores it in a-snd: ; load a sound ; set a-snd = s-read(strcat(current-path(), "demo-snd.aiff")) ; play it ; play a-snd One might then be tempted to write the following: play seq(a-snd, a-snd) ;WRONG! Why is this wrong? Recall that seq works by modifying *warp*, not by operating on sounds. So, seq will proceed by evaluating a-snd with different values of *warp*. However, the result of evaluating a-snd (a variable) is always the same sound, regardless of the environment; in this case, the second a-snd should start at time 0.0, just like the first. In this case, after the first sound ends, Nyquist is unable to ``back up'' to time zero, so in fact, this will play two sounds in sequence, but that is a result of an implementation detail rather than correct program execution. In fact, a future version of Nyquist might (correctly) stop and report an error when it detects that the second sound in the sequence has a real start time that is before the requested one. How then do we obtain a sequence of two sounds properly? What we really need here is a behavior that transforms a given sound according to the current transformation environment. That job is performed by cue. For example, the following will behave as expected, producing a sequence of two sounds: play seq(cue(a-snd), cue(a-snd)) This example is correct because the second expression will shift the sound stored in a-snd to start at the end time of the first expression. The lesson here is very important: sounds are not behaviors! Behaviors are computations that generate sounds according to the transformation environment. Once a sound has been generated, it can be stored, copied, added to other sounds, and used in many other operations, but sounds are not subject to transformations. To transform a sound, use cue, sound, or control. The differences between these operations are discussed later. For now, here is a ``cue sheet'' style score that plays 4 copies of a-snd: ; use sim and at to place sounds in time ; play sim(cue(a-snd) @ 0.0, cue(a-snd) @ 0.7, cue(a-snd) @ 1.0, cue(a-snd) @ 1.2) 3.5. The At Transformation The second concept introduced by the previous example is the @ operation, which shifts the *warp* component of the environment. For example, cue(a-snd) @ 0.7 can be explained operationally as follows: modify *warp* by shifting it by 0.7 and evaluate cue(a-snd). Return the resulting sound after restoring *warp* to its original value. Notice how @ is used inside a sim construct to locate copies of a-snd in time. This is the standard way to represent a note-list or a cue-sheet in Nyquist. This also explains why sounds need to be cue'd in order to be shifted in time or arranged in sequence. If this were not the case, then sim would take all of its parameters (a set of sounds) and line them up to start at the same time. But cue(a-snd) @ 0.7 is just a sound, so sim would ``undo'' the effect of @, making all of the sounds in the previous example start simultaneously, in spite of the @! Since sim respects the intrinsic starting times of sounds, a special operation, cue, is needed to create a new sound with a new starting time. 3.6. The Stretch Transformation In addition to At (denoted in SAL by the @ operator, the Stretch transformation is very important. It appeared in the introduction, and it is denoted in SAL by the ~ operator (or in LISP by the stretch special form). Stretch also operates on the *warp* component of the environment. For example, osc(c4) ~ 3 does the following: modify *warp*, scaling the degree of "stretch" by 3, and evaluate osc(c4). The osc behavior uses the stretch factor to determime the duration, so it will return a sound that is 3 seconds long. Restore *warp* to its original value. Like At, Stretch only affects behaviors. a-snd ~ 10 is equivalent to a-snd because a-snd is a sound, not a behavior. Behaviors are functions that compute sounds according to the environment and return a sound. 3.7. Nested Transformations Transformations can be combined using nested expressions. For example, sim(cue(a-snd), loud(6.0, cue(a-snd) @ 3)) scales the amplitude as well as shifts the second entrance of a-snd. Why use loud instead of simply multiplying a-snd by some scale factor? Using loud gives the behavior the chance to implement the abstract property loudness in an appropriate way, e.g. by including timbral changes. In this case, the behavior is cue, which implements loudness by simple amplitude scaling, so the result is equivalent to multiplication by db-to-linear(6.0). Transformations can also be applied to groups of behaviors: loud(6.0, sim(cue(a-snd) @ 0.0, cue(a-snd) @ 0.7)) 3.8. Defining Behaviors Groups of behaviors can be named using define (we already saw this in the definitions of my-note and env-note). Here is another example of a behavior definition and its use. The definition has one parameter: define function snds(dly) return sim(cue(a-snd) @ 0.0, cue(a-snd) @ 0.7, cue(a-snd) @ 1.0, cue(a-snd) @ (1.2 + dly)) play snds(0.1) play loud(0.25, snds(0.3) ~ 0.9) In the last line, snds is transformed: the transformations will apply to the cue behaviors within snds. The loud transformation will scale the sounds by 0.25, and the stretch (~) will apply to the shift (@) amounts 0.0, 0.7, 1.0, and 1.2 + dly. The sounds themselves (copies of a-snd) will not be stretched because cue never stretches sounds. Section 7.3 describes the full set of transformations. 3.9. Overriding Default Transformations In Nyquist, behaviors are the important abstraction mechanism. A behavior represents a class of related functions or sounds. For example, a behavior can represent a musical note. When a note is stretched, it usually means that the tone sustains for more oscillations, but if the ``note'' is a drum roll, the note sustains by more repetitions of the component drum strokes. The concept of sustain is so fundamental that we do not really think of different note durations as being different instances of an abstract behavior, but in a music programming language, we need a way to model these abtract behaviors. As the tone and drum roll examples show, there is no one right way to ``stretch,'' so the language must allow users to define exactly what it means to stretch. By extension, the Nyquist programmer can define how all of the transformations affect different behaviors. To make programming easier, almost all Nyquist sounds are constructed from primitive behaviors that obey the environment in obvious ways: Stretch transformations make things longer and At transformations shift things in time. But sometimes you have to override the default behaviors. Maybe the attack phase of an envelope should not stretch when the note is stretched, or maybe when you stretch a trill, you should get more notes rather than a slower trill. To override default behaviors, you almost always follow the same programming pattern: first, capture the environment in a local variable; then, use one of the absolute transformations to ``turn off'' the environment's effect and compute the sound as desired. The following example creates a very simple envelope with a fixed rise time to illustrate the technique. define function two-phase-env(rise-time) begin with dur = get-duration(1) return pwl(rise-time, 1, dur) ~~ 1.0 end To ``capture the environment in a local variable,'' a with construct is used to create the local variable dur and set it to the value of get-duration(1), which answers the question: ``If I apply use the environment to stretch something whose nominal duration is 1, what is the resulting duration?'' (Since time transformations can involve continuous time deformations, this question is not as simple as it may sound, so please use the provided function rather than peeking inside the *warp* structure and trying to do it yourself.) Next, we ``turn off'' stretching using the stretch-abs form, which in SAL is denoted by the ~~ operator. Finally, we are ready to compute the envelope using pwl. Here, we use absolute durations. The first breakpoint is at rise-time, so the attack time is given by the rise-time parameter. The pwl decays back to zero at time dur, so the overall duration matches the duration expected from the environment encountered by this instance of two-phase-env. Note, however, that since the pwl is evaluated in a different environment established by ~~, it is not stretched (or perhaps more accurately, it is stretched by 1.0). This is good because it means rise-time will not be stretched, but we must be careful to extend the envelope to dur so that it has the expected duration. 3.10. Sample Rates The global environment contains *sound-srate* and *control-srate*, which determine the sample rates of sounds and control signals. These can be overridden at any point by the transformations sound-srate-abs and control-srate-abs; for example, sound-srate-abs(44100.0, osc(c4) will compute a tone using a 44.1Khz sample rate even if the default rate is set to something different. As with other components of the environment, you should never change *sound-srate* or *control-srate* directly. The global environment is determined by two additional variables: *default-sound-srate* and *default- control-srate*. You can add lines like the following to your init.lsp file to change the default global environment: (setf *default-sound-srate* 44100.0) (setf *default-control-srate* 1102.5) You can also do this using preferences in NyquistIDE. If you have already started Nyquist and want to change the defaults, the preferences or the following functions can be used: exec set-control-srate(1102.5)exec set-sound-srate(22050.0) These modify the default values and reinitialize the Nyquist environment. 4. Continuous Transformations and Time Warps Nyquist transformations were discussed in the previous chapter, but all of the examples used scalar values. For example, we saw the loud transformation used to change loudness by a fixed amount. What if we want to specify a crescendo, where the loudness changes gradually over time? It turns out that all transformations can accept signals as well as numbers, so transformations can be continuous over time. This raises some interesting questions about how to interpret continuous transformations. Should a loudness transformation apply to the internal details of a note or only affect the initial loudness? It might seem unnatural for a decaying piano note to perform a crescendo. On the other hand, a sustained trumpet sound should probably crescendo continuously. In the case of time warping (tempo changes), it might be best for a drum roll to maintain a steady rate, a trill may or may not change rates with tempo, and a run of sixteenth notes will surely change its rate. These issues are complex, and Nyquist cannot hope to automatically do the right thing in all cases. However, the concept of behavioral abstraction provides an elegant solution. Since transformations merely modify the environment, behaviors are not forced to implement any particular style of transformation. Nyquist is designed so that the default transformation is usually the right one, but it is always possible to override the default transformation to achieve a particular effect. 4.1. Simple Transformations The ``simple'' transformations affect some parameter, but have no effect on time itself. The simple transformations that support continuously changing parameters are: sustain, loud, and transpose. As a first example, Let us use transpose to create a chromatic scale. First define a sequence of tones at a steady pitch. The seqrep ``function'' works like seq except that it creates copies of a sound by evaluating an expression multiple times. Here, i takes on 16 values from 0 to 15, and the expression for the sound could potentially use i. Technically, seqrep is not really a function but an abbreviation for a special kind of loop construct. define function tone-seq() return seqrep(i, 16, osc-note(c4) ~ 0.25) Now define a linearly increasing ramp to serve as a transposition function: define function pitch-rise() return sustain-abs(1.0, 16 * ramp() ~ 4) This ramp has a duration of 4 seconds, and over that interval it rises from 0 to 16 (corresponding to the 16 semitones we want to transpose). The ramp is inside a sustain-abs transformation, which prevents a sustain transformation from having any effect on the ramp. (One of the drawbacks of behavioral abstraction is that built-in behaviors sometimes do the wrong thing implicitly, requiring some explicit correction to turn off the unwanted transformation.) Now, pitch-rise is used to transpose tone-seq: define function chromatic-scale() return transpose(pitch-rise(), tone-seq()) Similar transformations can be constructed to change the sustain or ``duty factor'' of notes and their loudness. The following expression plays the chromatic-scale behavior with increasing note durations. The rhythm is unchanged, but the note length changes from staccato to legato: play sustain((0.2 + ramp()) ~ 4, chromatic-scale()) The resulting sustain function will ramp from 0.2 to 1.2. A sustain of 1.2 denotes a 20 percent overlap between notes. The sum has a stretch factor of 4, so it will extend over the 4 second duration of chromatic-scale. If you try this, you will discover that the chromatic-scale no longer plays a chromatic scale. You will hear the first 4 notes going up in intervals of 5 semitones (perfect fourths) followed by repeated pitches. What is happening is that the sustain operation applies to pitch-rise in addition to tone-seq, so now the 4s ramp from 0 to 16 becomes a 0.8s ramp. To fix this problem, we need to shield pitch-rise from the effect of sustain using the sustain-abs transformation. Here is a corrected version of chromatic-scale: define function chromatic-scale() return transpose(sustain-abs(1, pitch-rise()), tone-seq()) What do these transformations mean? How did the system know to produce a pitch rise rather than a continuous glissando? This all relates to the idea of behavioral abstraction. It is possible to design sounds that do glissando under the transpose transform, and you can even make sounds that ignore transpose altogether. As explained in Chapter 3, the transformations modify the environment, and behaviors can reference the environment to determine what signals to generate. All built-in functions, such as osc, have a default behavior. The default behavior for sound primitives under transpose, sustain, and loud transformations is to sample the environment at the beginning of the note. Transposition is not quantized to semitones or any other scale, but in our example, we arranged for the transposition to work out to integer numbers of semitones, so we obtained a chromatic scale anyway. Transposition only applies to the oscillator and sampling primitives osc, partial, sampler, sine, fmosc, and amosc. Sustain applies to osc, env, ramp, and pwl. (Note that partial, amosc, and fmosc get their durations from the modulation signal, so they may indirectly depend upon the sustain.) Loud applies to osc, sampler, cue, sound, fmosc, and amosc. (But not pwl or env.) 4.2. Time Warps The most interesting transformations have to do with transforming time itself. The warp transformation provides a mapping function from logical (score) time to real time. The slope of this function tells us how many units of real time are covered by one unit of score time. This is proportional to 1/tempo. A higher slope corresponds to a slower tempo. To demonstrate warp, we will define a time warp function using pwl: define function warper() return pwl(0.25, .4, .75, .6, 1.0, 1.0, 2.0, 2.0, 2.0) This function has an initial slope of .4/.25 = 1.6. It may be easier to think in reciprocal terms: the initial tempo is .25/.4 = .625. Between 0.25 and 0.75, the tempo is .5/.2 = 2.5, and from 0.75 to 1.0, the tempo is again .625. It is important for warp functions to completely span the interval of interest (in our case it will be 0 to 1), and it is safest to extend a bit beyond the interval, so we extend the function on to 2.0 with a tempo of 1.0. Next, we stretch and scale the warper function to cover 4 seconds of score time and 4 seconds of real time: define function warp4() return 4 * warper() ~ 4 Figure 2: The result of (warp4), intended to map 4 seconds of score time into 4 seconds of real time. The function extends beyond 4 seconds (the dashed lines) to make sure the function is well-defined at location (4, 4). Nyquist sounds are ordinarily open on the right. Figure 2 shows a plot of this warp function. Now, we can warp the tempo of the tone-seq defined above using warp4: play warp(warp4(), tone-seq()) Figure 3 shows the result graphically. Notice that the durations of the tones are warped as well as their onsets. Envelopes are not shown in detail in the figure. Because of the way env is defined, the tones will have constant attack and decay times, and the sustain will be adjusted to fit the available time. Figure 3: When (warp4) is applied to (tone-seq-2), the note onsets and durations are warped. 4.3. Abstract Time Warps We have seen a number of examples where the default behavior did the ``right thing,'' making the code straightforward. This is not always the case. Suppose we want to warp the note onsets but not the durations. We will first look at an incorrect solution and discuss the error. Then we will look at a slightly more complex (but correct) solution. The default behavior for most Nyquist built-in functions is to sample the time warp function at the nominal starting and ending score times of the primitive. For many built-in functions, including osc, the starting logical time is 0 and the ending logical time is 1, so the time warp function is evaluated at these points to yield real starting and stopping times, say 15.23 and 16.79. The difference (e.g. 1.56) becomes the signal duration, and there is no internal time warping. The pwl function behaves a little differently. Here, each breakpoint is warped individually, but the resulting function is linear between the breakpoints. A consequence of the default behavior is that notes stretch when the tempo slows down. Returning to our example, recall that we want to warp only the note onset times and not the duration. One would think that the following would work: define function tone-seq-2 () return seqrep(i, 16, osc-note(c4) ~~ 0.25) play warp(warp4(), tone-seq-2()) Here, we have redefined tone-seq, renaming it to tone-seq-2 and changing the stretch (~) to absolute stretch (~~). The absolute stretch should override the warp function and produce a fixed duration. If you play the example, you will hear steady sixteenths and no tempo changes. What is wrong? In a sense, the ``fix'' works too well. Recall that sequences (including seqrep) determine the starting time of the next note from the logical stop time of the previous sound in the sequence. When we forced the stretch to 0.25, we also forced the logical stop time to 0.25 real seconds from the beginning, so every note starts 0.25 seconds after the previous one, resulting in a constant tempo. Now let us design a proper solution. The trick is to use absolute stretch (~~) as before to control the duration, but to restore the logical stop time to a value that results in the proper inter-onset time interval: define function tone-seq-3() return seqrep(i, 16, set-logical-stop(osc-note(c4) ~~ 0.25, 0.25)) play warp(warp4(), tone-seq-3()) Notice the addition of set-logical-stop enclosing the absolute stretch (~~) expression to set the logical stop time. A possible point of confusion here is that the logical stop time is set to 0.25, the same number given to ~~! How does setting the logical stop time to 0.25 result in a tempo change? When used within a warp transformation, the second argument to set-logical-stop refers to score time rather than real time. Therefore, the score duration of 0.25 is warped into real time, producing tempo changes according to the enviroment. Figure 4 illustrates the result graphically. Figure 4: When (warp4) is applied to (tone-seq-3), the note onsets are warped, but not the duration, which remains a constant 0.25 seconds. In the fast middle section, this causes notes to overlap. Nyquist will sum (mix) them. 4.4. Nested Transformations Transformations can be nested. In particular, a simple transformation such as transpose can be nested within a time warp transformation. Suppose we want to warp our chromatic scale example with the warp4 time warp function. As in the previous section, we will show an erroneous simple solution followed by a correct one. The simplest approach to a nested transformation is to simply combine them and hope for the best: play warp(warp4(), transpose(pitch-rise(), tone-seq())) This example will not work the way you might expect. Here is why: the warp transformation applies to the (pitch-rise) expression, which is implemented using the ramp function. The default behavior of ramp is to interpolate linearly (in real time) between two points. Thus, the ``warped'' ramp function will not truly reflect the internal details of the intended time warp. When the notes are moving faster, they will be closer together in pitch, and the result is not chromatic. What we need is a way to properly compose the warp and ramp functions. If we continuously warp the ramp function in the same way as the note sequence, a chromatic scale should be obtained. This will lead to a correct solution. Here is the modified code to properly warp a transposed sequence. Note that the original sequence is used without modification. The only complication is producing a properly warped transposition function: play warp(warp4(), transpose( control-warp(get-warp(), warp-abs(nil, pitch-rise())), tone-seq())) To properly warp the pitch-rise transposition function, we use control-warp, which applies a warp function to a function of score time, yielding a function of real time. We need to pass the desired function to control-warp, so we fetch it from the environment with get-warp(). Finally, since the warping is done here, we want to shield the pitch-rise expression from further warping, so we enclose it in warp-abs(nil, ...). An aside: This last example illustrates a difficulty in the design of Nyquist. To support behavioral abstraction universally, we must rely upon behaviors to ``do the right thing.'' In this case, we would like the ramp function to warp continuously according to the environment. But this is inefficient and unnecessary in many other cases where ramp and especially pwl are used. (pwl warps its breakpoints, but still interpolates linearly between them.) Also, if the default behavior of primitives is to warp in a continuous manner, this makes it difficult to build custom abstract behaviors. The final vote is not in. 5. More Examples This chapter explores Nyquist through additional examples. The reader may wish to browse through these and move on to Chapter 7, which is a reference section describing Nyquist functions. 5.1. Stretching Sampled Sounds This example illustrates how to stretch a sound, resampling it in the process. Because sounds in Nyquist are values that contain the sample rate, start time, etc., use sound to convert a sound into a behavior that can be stretched, e.g. sound(a-snd). This behavior stretches a sound according to the stretch factor in the environment, set using stretch. For accuracy and efficiency, Nyquist does not resample a stretched sound until absolutely necessary. The force-srate function is used to resample the result so that we end up with a ``normal'' sample rate that is playable on ordinary sound cards. ; if a-snd is not loaded, load sound sample: ; if not(boundp(quote(a-snd))) then set a-snd = s-read("demo-snd.aiff") ; the SOUND operator shifts, stretches, clips and scales ; a sound according to the current environment ; define function ex23() play force-srate(*default-sound-srate*, sound(a-snd) ~ 3.0) define function down() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.2, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.6)) play down() ; that was so much fun, let's go back up: ; define function up() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.5, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.2)) ; and write a sequence ; play seq(down(), up(), down()) Notice the use of the sound behavior as opposed to cue. The cue behavior shifts and scales its sound according to *warp* and *loud*, but it does not change the duration or resample the sound. In contrast, sound not only shifts and scales its sound, but it also stretches it by resampling or changing the effective sample rate according to *warp*. If *warp* is a continuous warping function, then the sound will be stretched by time-varying amounts. (The *transpose* element of the environment is ignored by both cue and sound.) Note: sound may use linear interpolation rather than a high-quality resampling algorithm. In some cases, this may introduce errors audible as noise. Use resample (see Section 7.2.2) for high-quality interpolation. In the functions up and down, the *warp* is set by stretch (~), which simply scales time by a constant scale factor. In this case, sound can ``stretch'' the signal simply by changing the sample rate without any further computation. When seq tries to add the signals together, it discovers the sample rates do not match and uses linear interpolation to adjust all sample rates to match that of the first sound in the sequence. The result of seq is then converted using force-srate to convert the sample rate, again using linear interpolation. It would be slightly better, from a computational standpoint, to apply force-srate individually to each stretched sound rather than applying force-srate after seq. Notice that the overall duration of sound(a-snd) ~ 0.5 will be half the duration of a-snd. 5.2. Saving Sound Files So far, we have used the play command to play a sound. The play command works by writing a sound to a file while simultaneously playing it. This can be done one step at a time, and it is often convenient to save a sound to a particular file for later use: ; write the sample to a file, ; the file name can be any Unix filename. Prepending a "./" tells ; s-save to not prepend *default-sf-dir* ; exec s-save(a-snd, 1000000000, "./a-snd-file.snd") ; play a file ; play command normally expects an expression for a sound ; but if you pass it a string, it will open and play a ; sound file play "./a-snd-file.snd" ; delete the file (do this with care!) ; only works under Unix (not Windows) exec system("rm ./a-snd-file.snd") ; now let's do it using a variable as the file name ; set my-sound-file = "./a-snd-file.snd" exec s-save(a-snd, 1000000000, my-sound-file) ; play-file is a function to open and play a sound file exec play-file(my-sound-file) exec system(strcat("rm ", my-sound-file)) This example shows how s-save can be used to save a sound to a file. This example also shows how the system function can be used to invoke Unix shell commands, such as a command to play a file or remove it. Finally, notice that strcat can be used to concatenate a command name to a file name to create a complete command that is then passed to system. (This is convenient if the sound file name is stored in a parameter or variable.) 5.3. Memory Space and Normalization Sound samples take up lots of memory, and often, there is not enough primary (RAM) memory to hold a complete composition. For this reason, Nyquist can compute sounds incrementally, saving the final result on disk. However, Nyquist can also save sounds in memory so that they can be reused efficiently. In general, if a sound is saved in a global variable, memory will be allocated as needed to save and reuse it. The standard way to compute a sound and write it to disk is to pass an expression to the play command: play my-composition() Often it is nice to normalize sounds so that they use the full available dynamic range of 16 bits. Nyquist has an automated facility to help with normalization. By default, Nyquist computes up to 1 million samples (using about 4MB of memory) looking for the peak. The entire sound is normalized so that this peak will not cause clipping. If the sound has less than 1 million samples, or if the first million samples are a good indication of the overall peak, then the signal will not clip. With this automated normalization technique, you can choose the desired peak value by setting *autonorm-target*, which is initialized to 0.9. The number of samples examined is *autonorm-max-samples*, initially 1 million. You can turn this feature off by executing: exec autonorm-off() and turn it back on by typing: exec autonorm-on() This normalization technique is in effect when *autonorm-type* is quote(lookahead), which is the default. An alternative normalization method uses the peak value from the previous call to play. After playing a file, Nyquist can adjust an internal scale factor so that if you play the same file again, the peak amplitude will be *autonorm-target*, which is initialized to 0.9. This can be useful if you want to carefully normalize a big sound that does not have its peak near the beginning. To select this style of normalization, set *autonorm-type* to the (quoted) atom quote(previous). You can also create your own normalization method in Nyquist. The peak function computes the maximum value of a sound. The peak value is also returned from the play macro. You can normalize in memory if you have enough memory; otherwise you can compute the sound twice. The two techniques are illustrated here: ; normalize in memory. First, assign the sound to a variable so ; it will be retained: set mysound = sim(osc(c4), osc(c5)) ; now compute the maximum value (ny:all is 1 giga-samples, you may want ; smaller constant if you have less than 4GB of memory: set mymax = snd-max(mysound, NY:ALL) display "Computed max", mymax ; now write out and play the sound from memory with a scale factor: play mysound * (0.9 / mymax) ; if you don't have space in memory, here's how to do it: define function myscore() return sim(osc(c4), osc(c5)) ; compute the maximum: set mymax = snd-max(list(quote(myscore)), NY:ALL) display "Computed max", mymax ; now we know the max, but we don't have a the sound (it was garbage ; collected and never existed all at once in memory). Compute the soun ; again, this time with a scale factor: play myscore() * (0.9 / mymax) You can also write a sound as a floating point file. This file can then be converted to 16-bit integer with the proper scaling applied. If a long computation was involved, it should be much faster to scale the saved sound file than to recompute the sound from scratch. Although not implemented yet in Nyquist, some header formats can store maximum amplitudes, and some soundfile player programs can rescale floating point files on the fly, allowing normalized soundfile playback without an extra normalization pass (but at a cost of twice the disk space of 16-bit samples). You can use Nyquist to rescale a floating point file and convert it to 16-bit samples for playback. 5.4. Frequency Modulation The next example uses the Nyquist frequency modulation behavior fmosc to generate various sounds. The parameters to fmosc are: fmosc(pitch modulator table phase) Note that pitch is the number of half-steps, e.g. c4 has the value of 60 which is middle-C, and phase is in degrees. Only the first two parameters are required: ; make a short sine tone with no frequency modulation ; play fmosc(c4, pwl(0.1)) ; make a longer sine tone -- note that the duration of ; the modulator determines the duration of the tone ; play fmosc(c4, pwl(0.5)) In the example above, pwl (for Piece-Wise Linear) is used to generate sounds that are zero for the durations of 0.1 and 0.5 seconds, respectively. In effect, we are using an FM oscillator with no modulation input, and the result is a sine tone. The duration of the modulation determines the duration of the generated tone (when the modulation signal ends, the oscillator stops). The next example uses a more interesting modulation function, a ramp from zero to C , expressed in hz. More explanation of pwl is in order. This 4 operation constructs a piece-wise linear function sampled at the *control-srate*. The first breakpoint is always at (0, 0), so the first two parameters give the time and value of the second breakpoint, the second two parameters give the time and value of the third breakpoint, and so on. The last breakpoint has a value of 0, so only the time of the last breakpoint is given. In this case, we want the ramp to end at C , so we cheat a bit by 4 having the ramp return to zero ``almost'' instantaneously between times 0.5 and 0.501. The pwl behavior always expects an odd number of parameters. The resulting function is shifted and stretched linearly according to *warp* in the environment. Now, here is the example: ; make a frequency sweep of one octave; the piece-wise linear function ; sweeps from 0 to (step-to-hz c4) because, when added to the c4 ; fundamental, this will double the frequency and cause an octave sweep ; play fmosc(c4, pwl(0.5, step-to-hz(c4), 0.501)) The same idea can be applied to a non-sinusoidal carrier. Here, we assume that *fm-voice* is predefined (the next section shows how to define it): ; do the same thing with a non-sine table ; play fmosc(cs2, pwl(0.5, step-to-hz(cs2), 0.501), *fm-voice*, 0.0) The next example shows how a function can be used to make a special frequency modulation contour. In this case the contour generates a sweep from a starting pitch to a destination pitch: ; make a function to give a frequency sweep, starting ; after seconds, then sweeping from ; to in seconds and then ; holding at for seconds. ; define function sweep(delay, pitch-1, sweep-time, pitch-2, hold-time) begin with interval = step-to-hz(pitch-2) - step-to-hz(pitch-1) return pwl(delay, 0.0, ; sweep from pitch 1 to pitch 2 delay + sweep-time, interval, ; hold until about 1 sample from the end delay + sweep-time + hold-time - 0.0005, interval, ; quickly ramp to zero (pwl always does this, ; so make it short) delay + sweep-time + hold-time) end ; now try it out ; play fmosc(cs2, sweep(0.1, cs2, 0.6, gs2, 0.5), *fm-voice*, 0.0) FM can be used for vibrato as well as frequency sweeps. Here, we use the lfo function to generate vibrato. The lfo operation is similar to osc, except it generates sounds at the *control-srate*, and the parameter is hz rather than a pitch: play fmosc(cs2, 10.0 * lfo(6.0), *fm-voice*, 0.0) What kind of manual would this be without the obligatory FM sound? Here, a sinusoidal modulator (frequency C ) is multiplied by a slowly increasing ramp 4 from zero to 1000.0. set modulator = pwl(1.0, 1000.0, 1.0005) * osc(c4) ; make the sound play fmosc(c4, modulator) For more simple examples of FM in Nyquist, see demos/warble_tutorial.htm. Another interesting FM sound reminiscent of ``scratching'' can be found with a detailed explanation in demos/scratch_tutorial.htm.. 5.5. Building a Wavetable In Section 1.6.1, we saw how to synthesize a wavetable. A wavetable for osc also can be extracted from any sound. This is especially interesting if the sound is digitized from some external sound source and loaded using the s-read function. Recall that a table is a list consisting of a sound, the pitch of that sound, and T (meaning the sound is periodic). In the following, a sound is first read from the file demo-snd.nh. Then, the extract function is used to extract the portion of the sound between 0.110204 and 0.13932 seconds. (These numbers might be obtained by first plotting the sound and estimating the beginning and end of a period, or by using some software to look for good zero crossings.) The result of extract becomes the first element of a list. The next element is the pitch (24.848422), and the last element is T. The list is assigned to *fm-voice*. if not(boundp(quote(a-snd))) then set a-snd = s-read("demo-snd.aiff") set *fm-voice* = list(extract(0.110204, 0.13932, cue(a-snd)), 24.848422, #T) The file demos/examples.sal contains an extensive example of how to locate zero-crossings, extract a period, build a waveform, and generate a tone from it. (See ex37 through ex40 in the file.) 5.6. Filter Examples Nyquist provides a variety of filters. All of these filters take either real numbers or signals as parameters. If you pass a signal as a filter parameter, the filter coefficients are recomputed at the sample rate of the control signal. Since filter coefficients are generally expensive to compute, you may want to select filter control rates carefully. Use control-srate-abs (Section 7.3) to specify the default control sample rate, or use force-srate (Section 7.2.2) to resample a signal before passing it to a filter. Before presenting examples, let's generate some unfiltered white noise: play noise() Now low-pass filter the noise with a 1000Hz cutoff: play lp(noise(), 1000.0) The high-pass filter is the inverse of the low-pass: play hp(noise(), 1000.0) Here is a low-pass filter sweep from 100Hz to 2000Hz: play lp(noise(), pwl(0.0, 100.0, 1.0, 2000.0, 1.0)) And a high-pass sweep from 50Hz to 4000Hz: play hp(noise(), pwl(0.0, 50.0, 1.0, 4000.0, 1.0)) The band-pass filter takes a center frequency and a bandwidth parameter. This example has a 500Hz center frequency with a 20Hz bandwidth. The scale factor is necessary because, due to the resonant peak of the filter, the signal amplitude exceeds 1.0: play reson(10.0 * noise(), 500.0, 20.0, 1) In the next example, the center frequency is swept from 100 to 1000Hz, using a constant 20Hz bandwidth: play reson(0.04 * noise(), pwl(0.0, 200.0, 1.0, 1000.0, 1.0), 20.0) For another example with explanations, see demos/wind_tutorial.htm. 5.7. DSP in Lisp In almost any signal processing system, the vast majority of computation takes place in the inner loops of DSP algorithms, and Nyquist is designed so that these time-consuming inner loops are in highly-optimized machine code rather than relatively slow interpreted lisp code. As a result, Nyquist typically spends 95% of its time in these inner loops; the overhead of using a Lisp interpreter is negligible. The drawback is that Nyquist must provide the DSP operations you need, or you are out of luck. When Nyquist is found lacking, you can either write a new primitive signal operation, or you can perform DSP in Lisp code. Neither option is recommended for inexperienced programmers. Instructions for extending Nyquist are given in Appendix I. This section describes the process of writing a new signal processing function in Lisp. Before implementing a new DSP function, you should decide which approach is best. First, figure out how much of the new function can be implemented using existing Nyquist functions. For example, you might think that a tapped-delay line would require a new function, but in fact, it can be implemented by composing sound transformations to accomplish delays, scale factors for attenuation, and additions to combine the intermediate results. This can all be packaged into a new Lisp function, making it easy to use. If the function relies on built-in DSP primitives, it will execute very efficiently. Assuming that built-in functions cannot be used, try to define a new operation that will be both simple and general. Usually, it makes sense to implement only the kernel of what you need, combining it with existing functions to build a complete instrument or operation. For example, if you want to implement a physical model that requires a varying breath pressure with noise and vibrato, plan to use Nyquist functions to add a basic pressure envelope to noise and vibrato signals to come up with a composite pressure signal. Pass that signal into the physical model rather than synthesizing the envelope, noise, and vibrato within the model. This not only simplifies the model, but gives you the flexibility to use all of Nyquist's operations to synthesize a suitable breath pressure signal. Having designed the new ``kernel'' DSP operation that must be implemented, decide whether to use C or Lisp. (At present, SAL is not a good option because it has no support for object-oriented programming.) To use C, you must have a C compiler, the full source code for Nyquist, and you must learn about extending Nyquist by reading Appendix I. This is the more complex approach, but the result will be very efficient. A C implementation will deal properly with sounds that are not time-aligned or matched in sample rates. To use Lisp, you must learn something about the XLISP object system, and the result will be about 50 times slower than C. Also, it is more difficult to deal with time alignment and differences in sample rates. The remainder of this section gives an example of a Lisp version of snd-prod to illustrate how to write DSP functions for Nyquist in Lisp. The snd-prod function is the low-level multiply routine. It has two sound parameters and returns a sound which is the product of the two. To keep things simple, we will assume that two sounds to be multiplied have a matched sample rate and matching start times. The DSP algorithm for each output sample is simply to fetch a sample from each sound, multiply them, and return the product. To implement snd-prod in Lisp, three components are required: 1. An object is used to store the two parameter sounds. This object will be called upon to yield samples of the result sound; 2. Within the object, the snd-fetch routine is used to fetch samples from the two input sounds as needed; 3. The result must be of type SOUND, so snd-fromobject is used to create the result sound. The combined solution will work as follows: The result is a value of type sound that retains a reference to the object. When Nyquist needs samples from the sound, it invokes the sound's ``fetch'' function, which in turn sends an XLISP message to the object. The object will use snd-fetch to get a sample from each stored sound, multiply the samples, and return a result. Thus the goal is to design an XLISP object that, in response to a :next message will return a proper sequence of samples. When the sound reaches the termination time, simply return NIL. The XLISP manual (see Appendix IV describes the object system, but in a very terse style, so this example will include some explanation of how the object system is used. First, we need to define a class for the objects that will compute sound products. Every class is a subclass of class class, and you create a subclass by sending :new to a class. (setf product-class (send class :new '(s1 s2))) The parameter '(s1 s2) says that the new class will have two instance variables, s1 and s2. In other words, every object which is an instance of class product-class will have its own copy of these two variables. Next, we will define the :next method for product-class: (send product-class :answer :next '() '((let ((f1 (snd-fetch s1)) (f2 (snd-fetch s2))) (cond ((and f1 f2) (* f1 f2)) (t nil))))) The :answer message is used to insert a new method into our new product-class. The method is described in three parts: the name (:next), a parameter list (empty in this case), and a list of expressions to be evaluated. In this case, we fetch samples from s1 and s2. If both are numbers, we return their product. If either is NIL, we terminate the sound by returning nil. The :next method assumes that s1 and s2 hold the sounds to be multiplied. These must be installed when the object is created. Objects are created by sending :new to a class. A new object is created, and any parameters passed to :new are then sent in a :isnew message to the new object. Here is the :isnew definition for product-class: (send product-class :answer :isnew '(p1 p2) '((setf s1 (snd-copy p1)) (setf s2 (snd-copy p2)))) Take careful note of the use of snd-copy in this initialization. The sounds s1 and s2 are modified when accessed by snd-fetch in the :next method defined above, but this destroys the illusion that sounds are immutable values. The solution is to copy the sounds before accessing them; the original sounds are therefore unchanged. (This copy also takes place implicitly in most Nyquist sound functions.) To make this code safer for general use, we should add checks that s1 and s2 are sounds with identical starting times and sample rates; otherwise, an incorrect result might be computed. Now we are ready to write snd-product, an approximate replacement for snd-prod: (defun snd-product (s1 s2) (let (obj) (setf obj (send product-class :new s1 s2)) (snd-fromobject (snd-t0 s1) (snd-srate s1) obj))) This code first creates obj, an instance of product-class, to hold s1 and s2. Then, it uses obj to create a sound using snd-fromobject. This sound is returned from snd-product. Note that in snd-fromobject, you must also specify the starting time and sample rate as the first two parameters. These are copied from s1, again assuming that s1 and s2 have matching starting times and sample rates. Note that in more elaborate DSP algorithms we could expect the object to have a number of instance variables to hold things such as previous samples, waveform tables, and other parameters. 6. SAL Nyquist supports two languages: XLISP and SAL. In some sense, XLISP and SAL are the same language, but with differing syntax. This chapter describes SAL: how it works, SAL syntax and semantics, and the relationship between SAL and XLISP, and differences between Nyquist SAL and Common Music SAL. Nyquist SAL is based on Rick Taube's SAL language, which is part of Common Music. SAL offers the power of Lisp but features a simple, Algol-like syntax. SAL is implemented in Lisp: Lisp code translates SAL into a Lisp program and uses the underlying Lisp engine to evaluate the program. Aside from the translation time, which is quite fast, SAL programs execute at about the same speed as the corresponding Lisp program. (Nyquist SAL programs run just slightly slower than XLISP because of some runtime debugging support automatically added to user programs by the SAL compiler.) From the user's perspective, these implementation details are hidden. You can enter SAL mode from XLISP by typing (SAL) to the XLISP prompt. The SAL input prompt (SAL> ) will be displayed. From that point on, you simply type SAL commands, and they will be executed. By setting a preference in the NyquistIDE program, SAL mode will be entered automatically. It is possible to encounter errors that will take you from the SAL interpreter to an XLISP prompt. In general, the way to get back to SAL is by typing (top) to get back to the top level XLISP interpreter and reset the Nyquist environment. Then type (sal) to restart the SAL interpreter. 6.1. SAL Syntax and Semantics The most unusual feature of SAL syntax is that identifiers are Lisp-like, including names such as ``play-file'' and even ``*warp*.'' In SAL, most operators must be separated from identifiers by white space. For example, play-file is one identifier, but play - file is an expression for ``play minus file,'' where play and file are two separate identifiers. Fortunately, no spaces are needed around commas and parentheses. In SAL, whitespace (any sequence of space, newline, or tab characters) is sometimes necessary to separate lexical tokens, but otherwise, spaces and indentation are ignored. To make SAL readable, it is strongly advised that you indent SAL programs as in the examples here. The NyquistIDE program is purposely insistent about SAL indentation, so if you use it to edit SAL programs, your indentation should be both beautiful and consistent. As in Lisp (but very unlike C or Java), comments are indicated by semicolons. Any text from an unquoted semicolon to the end of the line is ignored. ; this is a comment ; comments are ignored by the compiler print "Hello World" ; this is a SAL statement As in Lisp, identifiers are translated to upper-case, making SAL case-insensitive. For example, the function name autonorm can be typed in lower case or as AUTONORM, AutoNorm, or even AuToNoRm. All forms denote the same function. The recommended approach is to write programs in all lower case. SAL is organized around statements, most of which contain expressions. We will begin with expressions and then look at statements. 6.1.1. Expressions 6.1.1.1. Simple Expressions As in XLISP, simple expressions include: - integers (FIXNUM's), such as 1215, - floats (FLONUM's) such as 12.15, - strings (STRING's) such as "Magna Carta", and - symbols (SYMBOL's) such as magna-carta. A symbol with a leading colon (:) evaluates to itself as in Lisp. Otherwise, a symbol denotes either a local variable, a formal parameter, or a global variable. As in Lisp, variables do not have data types or type declarations. The type of a variable is determined at runtime by its value. Additional simple expressions in SAL are: - lists such as {c 60 e 64}. Note that there are no commas to separate list elements, and symbols in lists are not evaluated as variables but stand for themselves. Lists may contain numbers, booleans, symbols, strings, and other lists. - Booleans: SAL interprets #t as true and #fas false. (As far as the SAL compiler is concerned, t and nil are just variables. Since these are the Lisp versions of true and false, they are interchangeable with #t and #f, respectively.) A curious property of Lisp and Sal is that false and the empty list are the same value. Since SAL is based on Lisp, #f and {} (the empty list) are equal. 6.1.1.2. Operators Expressions can be formed with unary and binary operators using infix notation. The operators are: - + - addition, including sounds - - - subtraction, including sounds - * - multiplication, including sounds - / - division (due to divide-by-zero problems, does not operate on sounds) - % - modulus (remainder after division) - ^ - exponentiation - = - equal (using Lisp eql) - != - not equal - > - greater than - < - less than - >= - greater than or equal - <= - less than or equal - ~= - general equality (using Lisp equal) - & - logical and - | - logical or - ! - logical not (unary) - @ - time shift - @@ - time shift to absolute time - ~ - time stretch - ~~ - time stretch to absolute stretch factor Again, remember that operators must be delimited from their operands using spaces or parentheses. Operator precedence is based on the following levels of precedence: @ @@ ~ ~~ ^ / * % - + ~= <= >= > ~= = ! & | 6.1.1.3. Function Calls A function call is a function name followed by zero or more comma-delimited argument expressions enclosed within parentheses: list() piano-note(2.0, c4 + interval, 100) Some functions use named parameters, in which case the name of the argument with a colon precedes the argument expression. s-save(my-snd(), ny:all, "tmp.wav", play: #t, bits: 16) 6.1.1.4. Array Notation An array reference is a variable identifier followed by an index expression in square brackets, e.g.: x[23] + y[i] 6.1.1.5. Conditional Values The special operator #? evaluates the first argument expression. If the result is true, the second expression is evaluated and its value is returned. If false, the third expression is evaluated and returned (or false is returned if there is no third expression): #?(random(2) = 0, unison, major-third) #?(pitch >= c4, pitch - c4) ; returns false if pitch < c4 6.1.2. SAL Statements SAL compiles and evaluates statements one at a time. You can type statements at the SAL prompt or load a file containing SAL statements. SAL statements are described below. The syntax is indicated at the beginning of each statement type description: this font indicates literal terms such as keywords, the italic font indicates a place-holder for some other statement or expression. Bracket [like this] indicate optional (zero or one) syntax elements, while braces with a plus {like this}+ indicate one or more occurrences of a syntax element. Braces with a star {like this}* indicate zero or more occurrences of a syntax element: { non-terminal }* is equivalent to [ {non-terminal}+ ]. 6.1.2.1. begin and end begin [with-stmt] {statement}+ end A begin-end statement consists of a sequence of statements surrounded by the begin and end keywords. This form is often used for function definitions and after then or else where the syntax demands a single statement but you want to perform more than one action. Variables may be declared using an optional with statement immediately after begin. For example: begin with db = 12.0, linear = db-to-linear(db) print db, "dB represents a factor of", linear set scale-factor = linear end 6.1.2.2. chdir chdir expression The chdir statement changes the working directory. This statement is provided for compatibility with Common Music SAL, but it really should be avoided if you use NyquistIDE. The expression following the chdir keyword should evaluate to a string that is a directory path name. Note that literal strings themselves are valid expressions. chdir "/Users/rbd/tmp" 6.1.2.3. define variable [define] variable name [= expression] {, name [= expression]}* Global variables can be declared and initialized. A list of variable names, each with an optional initialization follows the define variable keywords. (Since variable is a keyword, define is redundant and optional in Nyquist SAL, but required in Common Music SAL.) If the initialization part is omitted, the variable is initialized to false. Global variables do not really need to be declared: just using the name implicitly creates the corresponding variable. However, it is an error to use a global variable that has not been initialized; define variable is a good way to introduce a variable (or constant) with an initial value into your program. define variable transposition = 2, print-debugging-info, ; initially false output-file-name = "salmon.wav" 6.1.2.4. define function [define] function name ( [parameter], {, parameter}* ) statement Before a function be called from an expression (as described above), it must be defined. A function definition gives the function name, a list of parameters, and a statement. When a function is called, the actual parameter expressions are evaluated from left to right and the formal parameters of the function definition are set to these values. Then, statement is evaluated. The formal parameters may be positional parameters that are matched with actual parameters by position from left to right. Syntactically, these are symbols and these symbols are essentially local variables that exist only until statement completes or a return statement causes the function evaluation to end. As in Lisp, parameters are passed by value, so assigning a new value to a formal parameter has no effect on the actual value. However, lists and arrays are not copied, so internal changes to a list or array produce observable side effects. Alternatively, formal parameters may be keyword parameters. Here the parameter is actually a pair: a keyword parameter, which is a symbol followed by a colon, and a default value, given by any expression. Within the body of the function, the keyword parameter is named by a symbol whose name matches the keyword parameter except there is no final colon. define function foo(x: 1, y: bar(2, 3)) display "foo", x, y exec foo(x: 6, y: 7) In this example, x is bound to the value 6 and y is bound to the value 7, so the example prints ``foo : X = 6, Y = 7''. Note that while the keyword parameters are x: and y:, the corresponding variable names in the function body are x and y, respectively. The parameters are meaningful only within the lexical (static) scope of statement. They are not accessible from within other functions even if they are called by this function. Use a begin-end statement if the body of the function should contain more than one statement or you need to define local variables. Use a return statement to return a value from the function. If statement completes without a return, the value false is returned. 6.1.2.5. display display string {, expression}* The display statement is handy for debugging. At present, it is only implemented in Nyquist SAL. When executed, display prints the string followed by a colon and then, for each expression, the expression and its value are printed, after the last expression, a newline is printed. For example, display "In function foo", bar, baz prints In function foo : bar = 23, baz = 5.3 SAL may print the expressions using Lisp syntax, e.g. if the expression is ``bar + baz,'' do not be surprised if the output is ``(sum bar baz) = 28.3.'' 6.1.2.6. exec exec expression Unlike most other programming languages, you cannot simply type an expression as a statement. If you want to evaluate an expression, e.g. call a function, you must use an exec statement. The statement simply evaluates the expression. For example, exec set-sound-srate(22050.0) ; change default sample rate 6.1.2.7. if if test-expr then true-stmt [else false-stmt] An if statement evaluates the expression test-expr. If it is true, it evaluates the statement true-stmt. If false, the statement false-stmt is evaluated. Use a begin-end statement to evaluate more than one statement in then then or else parts. if x < 0 then x = -x ; x gets its absoute value if x > upper-bound then begin print "x too big, setting to", upper-bound x = upper-bound end else if x < lower-bound then begin print "x too small, setting to", lower-bound x = lower-bound end Notice in this example that the else part is another if statement. An if may also be the then part of another if, so there could be two possible if's with which to associate an else. An else clause always associates with the closest previous if that does not already have an else clause. 6.1.2.8. when when test statement The when statement is similar to if, but there is no else clause. when *debug-flag* print "you are here" 6.1.2.9. unless unless test statement The unless statement is similar to when (and if) but the statement is executed when the test expression is false. unless count = 0 set average = sum / count 6.1.2.10. load load expression The load command loads a file named by expression, which must evauate to a string path name for the file. To load a file, SAL interprets each statement in the file, stopping when the end of the file or an error is encountered. If the file ends in .lsp, the file is assumed to contain Lisp expressions, which are evaluated by the XLISP interpreter. In general, SAL files should end with the extension .sal. 6.1.2.11. loop loop [with-stmt] {stepping}* {stopping* action+ [finally] end The loop statement is by far the most complex statement in SAL, but it offers great flexibility for just about any kind of iteration. The basic function of a loop is to repeatedly evaluate a sequence of action's which are statements. Before the loop begins, local variables may be declared in with-stmt, a with statement. The stepping clauses do several things. They introduce and initialize additional local variables similar to the with-stmt. However, these local variables are updated to new values after the action's. In addition, some stepping clauses have associated stopping conditions, which are tested on each iteration before evaluating the action's. There are also stopping clauses that provide additional tests to stop the iteration. These are also evaluated and tested on each iteration before evaluating the action's. When some stepping or stopping condition causes the iteration to stop, the finally clause is evaluated (if present). Local variables and their values can still be accessed in the finally clause. After the finally clause, the loop statement completes. The stepping clauses are the following: repeat expression Sets the number of iterations to the value of expression, which should be an integer (FIXNUM). for var = expression [ then expr2 ] Introduces a new local variable named var and initializes it to expression. Before each subsequent iteration, var is set to the value of expr2. If the then part is omitted, expression is re-evaluated and assigned to var on each subsequent iteration. Note that this differs from a with-stmt where expressions are evaluated and variables are only assigned their values once. for var in expression Evaluates expression to obtain a list and creates a new local variable initialized to the first element of the list. After each iteration, var is assigned the next element of the list. Iteration stops when var has assumed all values from the list. If the list is initially empty, the loop action's are not evaluated (there are zero iterations). for var [from from-expr] [[to | below | downto | above] to-expr] [by step-expr] Introduces a new local variable named var and intialized to the value of the expression from-expr (with a default value of 0). After each iteration of the loop, var is incremented by the value of step-expr (with a default value of 1). The iteration ends when var is greater than the value of to-expr if there is a to clause, greater than or equal to the value of to-expr if there is a below clause, less than the value of to-expr if there is a downto clause, or less than or equal to the value of to-expr if there is a above clause. (In the cases of downto and above, the default increment value is -1. If there is no to, below, downto, above, or below clause, no interation stop test is created for this stepping clause. The stopping clauses are the following: while expression The iterations are stopped when expression evaluates to false. Anything not false is considered to mean true. until expression The iterations are stopped when expression evaluates to true. The finally clause is defined as follows: finally statement The statement is evaluated when one of the stepping or stopping clauses ends the loop. As always, statement may be a begin-end statement. If an action evaluates a return statement, the finally statement is not executed. Loops often fall into common patterns, such as iteratiing a fixed number of times, performing an operation on some range of integers, collecting results in a list, and linearly searching for a solution. These forms are illustrated in the examples below. ; iterate 10 times loop repeat 10 print random(100) end ; print even numbers from 10 to 20 ; note that 20 is printed. On the next iteration, ; i = 22, so i >= 22, so the loop exits. loop for i from 10 to 22 by 2 print i end ; collect even numbers in a list loop with lis for i = 0 to 10 by 2 set lis @= i ; push integers on front of list, ; which is much faster than append, ; but list is built in reverse finally result = reverse(lis) end ; now, the variable result has a list of evens ; find the first even number in a list result = #f ; #f means "false" loop for elem in lis until evenp(elem) finally result = elem end ; result has first even value in lis (or it is #f) 6.1.2.12. print print expr {, expr}* The print statement prints the values separated by spaces and followed by a newline. [Note that in the original SAL, the newline is printed before the values, not after.] print "The value of x is", x 6.1.2.13. return return expression The return statement can only be used inside a function. It evaluates expression and then the function returns the value of the expression to its caller. 6.1.2.14. set set var op expression {, var op expression}* The set statement changes the value of a variable var according to the operator op and the value of the expression. The operators are: = The value of expression is assigned to var. += The value of expression is added to var. *= The value of var is multiplied by the value of the expression. &= The value of expression is inserted as the last element of the list referenced by var. If var is the empty list (denoted by #f), then var is assigned a newly constructed list of one element, the value of expression. ^= The value of expression, a list, is appended to the list referenced by var. If var is the empty list (denoted by #f), then var is assigned the (list) value of expression. @= Pushes the value of expression onto the front of the list referenced by var. If var is empty (denoted by #f), then var is assigned a newly constructed list of one element, the value of expression. <= Sets the new value of var to the minimum of the old value of var and the value of expression. >= Sets the new value of var to the maximum of the old value of var and the value of expression. ; example from Rick Taube's SAL description loop with a, b = 0, c = 1, d = {}, e = {}, f = -1, g = 0 for i below 5 set a = i, b += 1, c *= 2, d &= i, e @= i, f <= i, g >= i finally display "results", a, b, c, d, e, f, g end 6.1.2.15. with with var [= expression] {, var [= expression]}* The with statement declares and initializes local variables. It can appear only after begin or loop. If the expression is omitted, the initial value is false. The variables are visible only inside the begin-end or loop statement where the with statement appears. Even in loop's the variables are intialized only when the loop is entered, not on each iteration. 6.1.2.16. exit exit [nyquist] The exit statement is unique to Nyquist SAL. It returns from SAL mode to the XLISP interpreter. (Return to SAL mode by typing ``(sal)''). If nyquist is included in the statement, then the entire Nyquist process will exit. 6.2. Interoperability of SAL and XLISP When SAL evaluatas command or loads files, it translates SAL into XLISP. You can think of SAL as a program that translates everything you write into XLISP and entering it for you. Thus, when you define a SAL function, the function actually exists as an XLISP function (created using Lisp's defun special form). When you set or evaluate global variables in SAL, these are exactly the same Lisp global variables. Thus, XLISP functions can call SAL functions and vice-versa. At run time, everything is Lisp. 6.2.1. Function Calls In general, there is a very simple translation from SAL to Lisp syntax and back. A function call is SAL, for example, osc(g4, 2.0) is translated to Lisp by moving the open parenthesis in front of the function name and removing the commas: (osc g4 2.0) Similarly, if you want to translate a Lisp function call to SAL, just reverse the translation. 6.2.2. Symbols and Functions SAL translates keywords with trailing colons (such as foo:) into Lisp keywords with leading colons (such as :foo), but SAL keywords are not treated as expressions as they are in Lisp. You cannot write open("myfile.txt", direction: output:) because SAL expects an expression after direction. A special form keyword is defined to generate a Lisp keyword as an expression. The argument is the keyword without a colon, e.g. open("myfile.txt", direction: keyword(output)). Alternatively, you can write the Lisp-style keyword with the leading colon, e.g. open("myfile.txt", direction: :output). In Nyquist SAL, the hash character (#), can be used as a prefix to a Lisp function name. For example, the following command is not legal because print is a SAL command name, not a legal function name: set v = append(print(a), print(b)). (Here the intent is to print arguments to append). However, you can use the hash character to access the Lisp print function: set v = append(#print(a), #print(b)). 6.2.3. Playing Tricks On the SAL Compiler In many cases, the close coupling between SAL and XLISP gives SAL unexpected expressive power. A good example is seqrep. This is a special looping construct in Nyquist, implemented as a macro in XLISP. In Lisp, you would write something like: (seqrep (i 10) (pluck c4)) One might expect SAL would have to define a special seqrep statement to express this, but since statements do not return values, this approach would be problematic. The solution (which is already fully implemented in Nyquist) is to define a new macro sal-seqrep that is equivalent to seqrep except that it is called as follows: (sal-seqrep i 10 (pluck c4)) The SAL compiler automatically translates the identifier seqrep to sal-seqrep. Now, in SAL, you can just write seqrep(i, 10, pluck(c4)) which is translated in a pretty much semantics-unaware fashion to (sal-seqrep i 10 (pluck c4)) and viola!, we have Nyquist control constructs in SAL even though SAL is completely unaware that seqrep is actually a special form. 7. Nyquist Functions This chapter provides a language reference for Nyquist. Operations are categorized by functionality and abstraction level. Nyquist is implemented in two important levels: the ``high level'' supports behavioral abstraction, which means that operations like stretch and at can be applied. These functions are the ones that typical users are expected to use, and most of these functions are written in XLISP. The ``low-level'' primitives directly operate on sounds, but know nothing of environmental variables (such as *warp*, etc.). The names of most of these low-level functions start with ``snd-''. In general, programmers should avoid any function with the ``snd-'' prefix. Instead, use the ``high-level'' functions, which know about the environment and react appropriately. The names of high-level functions do not have prefixes like the low-level functions. There are certain low-level operations that apply directly to sounds (as opposed to behaviors) and are relatively ``safe'' for ordinary use. These are marked as such. Nyquist uses both linear frequency and equal-temperament pitch numbers to specify repetition rates. Frequency is always specified in either cycles per second (hz), or pitch numbers, also referred to as ``steps,'' as in steps of the chromatic scale. Steps are floating point numbers such that 60 = Middle C, 61 = C#, 61.23 is C# plus 23 cents, etc. The mapping from pitch number to frequency is the standard exponential conversion, and fractional pitch numbers (pitch-69)/12 are allowed: frequency=440*2 . There are many predefined pitch names. By default these are tuned in equal temperament, with A4 = 440Hz, but these may be changed. (See Section 1.7). 7.1. Sounds A sound is a primitive data type in Nyquist. Sounds can be created, passed as parameters, garbage collected, printed, and set to variables just like strings, atoms, numbers, and other data types. 7.1.1. What is a Sound? Sounds have 5 components: - srate M the sample rate of the sound. - samples M the samples. - signal-start M the time of the first sample. - signal-stop M the time of one past the last sample. - logical-stop M the time at which the sound logically ends, e.g. a sound may end at the beginning of a decay. This value defaults to signal-stop, but may be set to any value. It may seem that there should be logical-start to indicate the logical or perceptual beginning of a sound as well as a logical-stop to indicate the logical ending of a sound. In practice, only logical-stop is needed; this attribute tells when the next sound should begin to form a sequence of sounds. In this respect, Nyquist sounds are asymmetric: it is possible to compute sequences forward in time by aligning the logical start of each sound with the logical-stop of the previous one, but one cannot compute ``backwards'', aligning the logical end of each sound with the logical start of its successor. The root of this asymmetry is the fact that when we invoke a behavior, we say when to start, and the result of the behavior tells us its logical duration. There is no way to invoke a behavior with a direct specification of when to stop[Most behaviors will stop at time 1, warped according to *warp* to some real time, but this is by convention and is not a direct specification.]. Note: there is no way to enforce the intended ``perceptual'' interpretation of logical-stop. As far as Nyquist is concerned, these are just numbers to guide the alignment of sounds within various control constructs. 7.1.2. Multichannel Sounds Multichannel sounds are represented by Lisp arrays of sounds. To create an array of sounds the XLISP vector function is useful. Most low-level Nyquist functions (the ones starting with snd-) do not operate on multichannel sounds. Most high-level functions do operate on multichannel sounds. 7.1.3. Accessing and Creating Sound Several functions display information concerning a sound and can be used to query the components of a sound. There are functions that access samples in a sound and functions that construct sounds from samples. sref(sound, time) [SAL] (sref sound time) [LISP] Accesses sound at the point time, which is a local time. If time does not correspond to a sample time, then the nearest samples are linearly interpolated to form the result. To access a particular sample, either convert the sound to an array (see snd-samples below), or use snd-srate and snd-t0 (see below) to find the sample rate and starting time, and compute a time (t) from the sample number (n):t=(n/srate)+t0 Thus, the th lisp code to access the n sample of a sound would look like: (sref sound (global-to-local (+ (/ n (snd-srate sound)) (snd-t0 sound)))) Here is why sref interprets its time argument as a local time: > (sref (ramp 1) 0.5) ; evaluate a ramp at time 0.5 0.5 > (at 2.0 (sref (ramp 1) 0.5)) ; ramp is shifted to start at 2.0 ; the time, 0.5, is shifted to 2.5 0.5 If you were to use snd-sref, which treats time as global, instead of sref, which treats time as local, then the first example above would return the same answer (0.5), but the second example would return 0. Why? Because the (ramp 1) behavior would be shifted to start at time 2.0, but the resulting sound would be evaluated at global time 0.5. By definition, sounds have a value of zero before their start time. sref-inverse(sound, value) [SAL] (sref-inverse sound value) [LISP] Search sound for the first point at which it achieves value and return the corresponding (linearly interpolated) time. If no inverse exists, an error is raised. This function is used by Nyquist in the implementation of time warping. snd-from-array(t0, sr, array) [SAL] (snd-from-array t0 sr array) [LISP] Converts a lisp array of FLONUMs into a sound with starting time t0 and sample rate sr. Safe for ordinary use. Be aware that arrays of floating-point samples use 14 bytes per sample, and an additional 4 bytes per sample are allocated by this function to create a sound type. snd-fromarraystream(t0, sr, object) [SAL] (snd-fromarraystream t0 sr object) [LISP] Creates a sound for which samples come from object. The starting time is t0 (a FLONUM), and the sample rate is sr. The object is an XLISP object (see Section IV.11 for information on objects.) A sound is returned. When the sound needs samples, they are generated by sending the message :next to object. If object returns NIL, the sound terminates. Otherwise, object must return an array of FLONUMs. The values in these arrays are concatenated to form the samples of the resulting sound. There is no provision for object to specify the logical stop time of the sound, so the logical stop time is the termination time. snd-fromobject(t0, sr, object) [SAL] (snd-fromobject t0 sr object) [LISP] Creates a sound for which samples come from object. The starting time is t0 (a FLONUM), and the sample rate is sr. The object is an XLISP object (see Section IV.11 for information on objects. A sound is returned. When the sound needs samples, they are generated by sending the message :next to object. If object returns NIL, the sound terminates. Otherwise, object must return a FLONUM. There is no provision for object to specify the logical stop time of the sound, so the logical stop time is the termination time. snd-extent(sound, maxsamples) [SAL] (snd-extent sound maxsamples) [LISP] Returns a list of two numbers: the starting time of sound and the terminate time of sound. Finding the terminate time requires that samples be computed. Like most Nyquist functions, this is non-destructive, so memory will be allocated to preserve the sound samples. If the sound is very long or infinite, this may exhaust all memory, so the maxsamples parameter specifies a limit on how many samples to compute. If this limit is reached, the terminate time will be (incorrectly) based on the sound having maxsamples samples. This function is safe for ordinary use. snd-fetch(sound) [SAL] (snd-fetch sound) [LISP] Reads samples sequentially from sound. This returns a FLONUM after each call, or NIL when sound terminates. Note: snd-fetch modifies sound; it is strongly recommended to copy sound using snd-copy and access only the copy with snd-fetch. snd-fetch-array(sound, len, step) [SAL] (snd-fetch-array sound len step) [LISP] Reads sequential arrays of samples from sound, returning either an array of FLONUMs or NIL when the sound terminates. The len parameter, a FIXNUM, indicates how many samples should be returned in the result array. After the array is returned, sound is modified by skipping over step (a FIXNUM) samples. If step equals len, then every sample is returned once. If step is less than len, each returned array will overlap the previous one, so some samples will be returned more than once. If step is greater than len, then some samples will be skipped and not returned in any array. The step and len may change at each call, but in the current implementation, an internal buffer is allocated for sound on the first call, so subsequent calls may not specify a greater len than the first. When an array is returned, it will have len samples. If necessary, snd-fetch-array will read zeros beyond the end of the sound to fill the array. When this happens, *rslt* is set to a FIXNUM number of samples in the array that were read from the sound before the physical stop time of the sound. If all samples in the array are ``valid'' samples from the sound (coming from the sound before the sound terminates), *rslt* is set to NIL. The *rslt* variable is global and used to return extra results from other functions, so programs should not assume *rslt* is valid after subsequent function calls. Note: snd-fetch-array modifies sound; it is strongly recommended to copy sound using snd-copy and access only the copy with snd-fetch-array. snd-flatten(sound, maxlen) [SAL] (snd-flatten sound maxlen) [LISP] This function is identical to snd-length. You would use this function to force samples to be computed in memory. Normally, this is not a good thing to do, but here is one appropriate use: In the case of sounds intended for wavetables, the unevaluated sound may be larger than the evaluated (and typically short) one. Calling snd-flatten will compute the samples and allow the unit generators to be freed in the next garbage collection. Note: If a sound is computed from many instances of table-lookup oscillators, calling snd-flatten will free the oscillators and their tables. Calling (stats) will print how many total bytes have been allocated to tables. snd-length(sound, maxlen) [SAL] (snd-length sound maxlen) [LISP] Counts the number of samples in sound up to the physical stop time. If the sound has more than maxlen samples, maxlen is returned. Calling this function will cause all samples of the sound to be computed and saved in memory (about 4 bytes per sample). Otherwise, this function is safe for ordinary use. snd-maxsamp(sound) [SAL] (snd-maxsamp sound) [LISP] Computes the maximum of the absolute value of the samples in sound. Calling this function will cause samples to be computed and saved in memory. (This function should have a maxlen parameter to allow self-defense against sounds that would exhaust available memory.) Otherwise, this function is safe for ordinary use. This function will probably be removed in a future version. See peak, a replacement ( page 30). snd-play(expression) [SAL] (snd-play expression) [LISP] Evaluates expression to obtain a sound or array of sounds, computes all of the samples (without retaining them in memory), and returns. Originally, this was a placeholder for a facility to play samples directly to an audio output device, but playback is now accomplished by s-save. Meanwhile, since this function does not save samples in memory or write them to a disk, it is useful in determining how much time is spent calculating samples. See s-save (Section 7.5) for saving samples to a file, and play (Section 7.5) to play a sound. This function is safe for ordinary use. snd-print-tree(sound) [SAL] (snd-print-tree sound) [LISP] Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. This function is safe for ordinary use. snd-samples(sound, limit) [SAL] (snd-samples sound limit) [LISP] Converts the samples into a lisp array. The data is taken directly from the samples, ignoring shifts. For example, if the sound starts at 3.0 seconds, the first sample will refer to time 3.0, not time 0.0. A maximum of limit samples is returned. This function is safe for ordinary use, but like snd-from-array, it requires a total of slightly over 18 bytes per sample. snd-srate(sound) [SAL] (snd-srate sound) [LISP] Returns the sample rate of the sound. Safe for ordinary use. snd-time(sound) [SAL] (snd-time sound) [LISP] Returns the start time of the sound. This will probably go away in a future version, so use snd-t0 instead. snd-t0(sound) [SAL] (snd-t0 sound) [LISP] Returns the time of the first sample of the sound. Note that Nyquist operators such as add always copy the sound and are allowed to shift the copy up to one half sample period in either direction to align the samples of two operands. Safe for ordinary use. snd-print(expression, maxlen) [SAL] (snd-print expression maxlen) [LISP] Evaluates expression to yield a sound or an array of sounds, then prints up to maxlen samples to the screen (stdout). This is similar to snd-save, but samples appear in text on the screen instead of in binary in a file. This function is intended for debugging. Safe for ordinary use. snd-set-logical-stop(sound, time) [SAL] (snd-set-logical-stop sound time) [LISP] Returns a sound which is sound, except that the logical stop of the sound occurs at time. Note: do not call this function. When defining a behavior, use set-logical-stop or set-logical-stop-abs instead. snd-sref(sound, time) [SAL] (snd-sref sound time) [LISP] Evaluates sound at the global time given by time. Safe for ordinary use, but normally, you should call sref instead. snd-stop-time(sound) [SAL] (snd-stop-time sound) [LISP] Returns the stop time of sound. Sounds can be ``clipped'' or truncated at a particular time. This function returns that time or MAX-STOP-TIME if he programmer has not specified a stop time for the sound. Safe for ordinary use. soundp(sound) [SAL] (soundp sound) [LISP] Returns true iff sound is a SOUND. Safe for ordinary use. stats() [SAL] (stats) [LISP] Prints the memory usage status. See also the XLISP mem function. Safe for ordinary use. This is the only way to find out how much memory is being used by table-lookup oscillator instances. 7.1.4. Miscellaneous Functions These are all safe and recommended for ordinary use. db-to-linear(x) [SAL] (db-to-linear x) [LISP] Returns the conversion of x from decibels to linear. 0dB is converted to 1. 20dB represents a linear factor of 10. If x is a sound, each sample is converted and a sound is returned. If x is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. Note: With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Sample rates, start times, etc. are taken from x. follow(sound, floor, risetime, falltime, lookahead) [SAL] (follow sound floor risetime falltime lookahead) [LISP] An envelope follower intended as a commponent for compressor and limiter functions. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The floor is the minimum output value. The risetime is the time (in seconds) it takes for the output to rise (exponentially) from floor to unity (1.0) and the falltime is the time it takes for the output to fall (exponentially) from unity to floor. The algorithm looks ahead for peaks and will begin to increase the output signal according to risetime in anticipation of a peak. The amount of anticipation (in seconds) is given by lookahead. The algorithm is as follows: the output value is allowed to increase according to risetime or decrease according to falltime. If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to risetime to meet the new value. The algorithm will only work backward as far as lookahead. If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by falltime, the output fall rate will be limited by falltime, and the fall in output will stop when the output reaches floor. This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See snd-avg for a function that can help to generate a low-sample-rate input for follow. See snd-chase in Section 7.6.3 for a related filter. gate(sound, lookahead, risetime, falltime, floor, threshold) [SAL] (gate sound lookahead risetime falltime floor threshold) [LISP] Generate an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead (a FLONUM in seconds). (The signal begins to drop when the signal crosses threshold, not after lookahead.) Decay continues until the value reaches floor (a FLONUM), at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the ouptut value will rise to unity (1.0) at the point the signal crosses the threshold. Because of internal lookahead, the signal actually begins to rise before the signal crosses threshold. The rise is a constant-rate exponential and set so that a rise from floor to unity occurs in risetime. Similary, the fall is a constant-rate exponential such that a fall from unity to floor takes falltime. hz-to-step(freq) [SAL] (hz-to-step freq) [LISP] Returns a step number for freq (in hz), which can be either a number of a SOUND. The result has the same type as the argument. See also step-to-hz (below). linear-to-db(x) [SAL] (linear-to-db x) [LISP] Returns the conversion of x from linear to decibels. 1 is converted to 0. 0 is converted to -INF (a special IEEE floating point value.) A factor of 10 represents a 20dB change. If x is a sound, each sample is converted and a sound is returned. If x is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. Note: With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Start times, sample rates, etc. are taken from x. log(x) [SAL] (log x) [LISP] Calculates the natural log of x (a FLONUM). (See s-log for a version that operates on signals.) set-control-srate(rate) [SAL] (set-control-srate rate) [LISP] Sets the default sampling rate for control signals to rate by setting *default-control-srate* and reinitializing the environment. Do not call this within any synthesis function (see the control-srate-abs transformation, Section 7.3). set-sound-srate(rate) [SAL] (set-sound-srate rate) [LISP] Sets the default sampling rate for audio signals to rate by setting *default-sound-srate* and reinitializing the environment. Do not call this within any synthesis function (see the sound-srate-abs transformation, Section 7.3). set-pitch-names() [SAL] (set-pitch-names) [LIS] Initializes pitch variables (c0, cs0, df0, d0, ... b0, c1, ... b7). A440 (the default tuning) is represented by the step 69.0, so the variable a4 (fourth octave A) is set to 69.0. You can change the tuning by setting *A4-Hertz* to a value (in Hertz) and calling set-pitch-names to reinitialize the pitch variables. Note that this will result in non-integer step values. It does not alter the mapping from step values to frequency. There is no built-in provision for stretched scales or non-equal temperament, although users can write or compute any desired fractional step values. step-to-hz(pitch) [SAL] (step-to-hz pitch) [LISP] Returns a frequency in hz for pitch, a step number or a SOUND type representing a time-varying step number. The result is a FLONUM if pitch is a number, and a SOUND if pitch is a SOUND. See also hz-to-step (above). get-duration(dur) [SAL] (get-duration dur) [LISP] Gets the actual duration of of something starting at a local time of 0 and ending at a local time of dur times the current sustain. For convenience, *rslt* is set to the global time corresponding to local time zero. get-loud() [SAL] (get-loud) [LISP] Gets the current value of the *loud* environment variable. If *loud* is a signal, it is evaluated at local time 0 and a number (FLONUM) is returned. get-sustain() [SAL] (get-sustain) [LISP] Gets the current value of the *sustain* environment variable. If *sustain* is a signal, it is evaluated at local time 0 and a number (FLONUM) is returned. get-transpose() [SAL] (get-transpose) [LISP] Gets the current value of the *transpose* environment variable. If *transpose* is a signal, it is evaluated at local time 0 and a number (FLONUM) is returned. get-warp() [SAL] (get-warp) [LISP] Gets a function corresponding to the current value of the *warp* environment variable. For efficiency, *warp* is stored in three parts representing a shift, a scale factor, and a continuous warp function. Get-warp is used to retrieve a signal that maps logical time to real time. This signal combines the information of all three components of *warp* into a single signal. If the continuous warp function component is not present (indicating that the time warp is a simple combination of at and stretch transformations), an error is raised. This function is mainly for internal system use. In the future, get-warp will probably be reimplemented to always return a signal and never raise an error. LOCAL-to-global(local-time) [SAL] (local-to-global local-time) [LISP] Converts a score (local) time to a real (global) time according to the current environment. osc-enable(flag) [SAL] (osc-enable flag) [LISP] Enable or disable Open Sound Control. (See Appendix II.) Enabling creates a socket and a service that listens for UDP packets on port 7770. Currently, only two messages are accepted by Nyquist. The first is of the form /slider with an integer index and a floating point value. These set internal slider values accessed by the snd-slider function. The second is of the form /wii/orientation with two floating point values. This message is a special case to support the DarwiinRemoteOsc program which can relay data from a Nintendo WiiMote device to Nyquist via OSC. The two orientation values control sliders 0 and 1. Disabling terminates the service (polling for messages) and closes the socket. The previous state of enablement is returned, e.g. if OSC is enabled and flag is nil, OSC is disabled and T (true) is returned because OSC was enabled at the time of the call. This function only exists if Nyquist is compiled with the compiler flag OSC. Otherwise, the function exists but always returns the symbol DISABLED. Consider lowering the audio latency using snd-set- latency. Warning: there is the potential for network-based attacks using OSC. It is tempting to add the ability to evaluate XLISP expressions sent via OSC, but this would create unlimited and unprotected access to OSC clients. For now, it is unlikely that an attacker could do more than manipulate slider values. snd-set-latency(latency) [SAL] (snd-set-latency latency) [LISP] Set the latency requested when Nyquist plays sound to latency, a FLONUM. The previous value is returned. The default is 0.3 seconds. To avoid glitches, the latency should be greater than the time required for garbage collection and message printing and any other system activity external to Nyquist. 7.2. Behaviors 7.2.1. Using Previously Created Sounds These behaviors take a sound and transform that sound according to the environment. These are useful when writing code to make a high-level function from a low-level function, or when cuing sounds which were previously created: cue(sound) [SAL] (cue sound) [LISP] Applies *loud*, the starting time from *warp*, *start*, and *stop* to sound. cue-file(filename) [SAL] (cue-file filename) [LISP] Same as cue, except the sound comes from the named file, samples from which are coerced to the current default *sound-srate* sample rate. sound(sound) [SAL] (sound sound) [LISP] Applies *loud*, *warp*, *start*, and *stop* to sound. control(sound) [SAL] (control sound) [LISP] This function is identical to sound, but by convention is used when sound is a control signal rather than an audio signal. 7.2.2. Sound Synthesis These functions provide musically interesting creation behaviors that react to their environment; these are the ``unit generators'' of Nyquist: const(value [, duration]) [SAL] (const value [duration]) [LISP] Creates a constant function at the *control-srate*. Every sample has the given value, and the default duration is 1.0. See also s-rest, which is equivalent to calling const with zero, and note that you can pass scalar constants (numbers) to sim, sum, and mult where they are handled more efficiently than constant functions. env(t , t , t , l , l , l , [dur]) [SAL] 1 2 4 1 2 3 (env t t t l l l dur) [LISP] 1 2 4 1 2 3 Creates a 4-phase envelope. t is the duration of phase i, and l is the i i final level of phase i. t is implied by the duration dur, and l is 0.0. 3 4 If dur is not supplied, then 1.0 is assumed. The envelope duration is the product of dur, *stretch*, and *sustain*. If t + t + 2ms + t is 1 2 4 greater than the envelope duration, then a two-phase envelope is substituted that has an attack/release time ratio of t /t . The sample 1 4 rate of the returned sound is *control-srate*. (See pwl for a more general piece-wise linear function generator.) The effect of time warping is to warp the starting time and ending time. The intermediate breakpoints are then computed as described above. exp-dec(hold, halfdec, length) [SAL] (exp-dec hold halfdec length) [LISP] This convenient envelope shape is a special case of pwev (see Section 7.2.2.2). The envelope starts at 1 and is constant for hold seconds. It then decays with a half life of halfdec seconds until length. (The total duration is length.) In other words, the amplitude falls by half each halfdec seconds. When stretched, this envelope scales linearly, which means the hold time increases and the half decay time increases. force-srate(srate, sound) [SAL] (force-srate srate sound) [LISP] Returns a sound which is up- or down-sampled to srate. Interpolation is linear, and no prefiltering is applied in the down-sample case, so aliasing may occur. See also resample. lfo(freq [, duration, table, phase]) [SAL] (lfo freq duration table phase) [LISP] Just like osc (below) except this computes at the *control-srate* and frequency is specified in Hz. Phase is specified in degrees. The *transpose* and *sustain* is not applied. The effect of time warping is to warp the starting and ending times. The signal itself will have a constant unwarped frequency. fmlfo(freq [, table, phase]) [SAL] (fmlfo freq [table phase]) [LISP] A low-frequency oscillator that computes at the *control-srate* using a sound to specify a time-varying frequency in Hz. Phase is a FLONUM in degrees. The duration of the result is determined by freq. maketable(sound) [SAL] (maketable sound) [LISP] Assumes that the samples in sound constitute one period of a wavetable, and returns a wavetable suitable for use as the table argument to the osc function (see below). Currently, tables are limited to 1,000,000 samples. This limit is the compile-time constant max_table_len set in sound.h. build-harmonic(n, table-size) [SAL] (build-harmonic n table-size) [LISP] Intended for constructing wavetables, this function returns a sound of length table-size samples containing n periods of a sinusoid. These can be scaled and summed to form a waveform with the desired harmonic content. See page 1 for an example. control-warp(warp-fn, signal, [wrate]) [SAL] (control-warp warp-fn signal wrate) [LISP] Applies a warp function warp-fn to signal using function composition. If wrate is omitted, linear interpolation is used. warp-fn is a mapping from score (logical) time to real time, and signal is a function from score time to real values. The result is a function from real time to real values at a sample rate of *control-srate*. See sound-warp for an explanation of wrate and high-quality warping. mult(beh , beh , ...) [SAL] 1 2 (mult beh beh ...) [LISP] 1 2 Returns the product of behaviors. The arguments may also be numbers, in which case simple multiplication is performed. If a number and sound are mixed, the scale function is used to scale the sound by the number. When sounds are multiplied, the resulting sample rate is the maximum sample rate of the factors. prod(beh , beh , ...) [SAL] 1 2 (prod beh beh ...) [LISP] 1 2 Same as mult. pan(sound, where) [SAL] (pan sound where) [LISP] Pans sound (a behavior) according to where (another behavior or a number). Sound must be monophonic. Where may be a monophonic sound (e.g. (ramp) or simply a number (e.g. 0.5). In either case, where should range from 0 to 1, where 0 means pan completely left, and 1 means pan completely right. For intermediate values, the sound to each channel is scaled linearly. Presently, pan does not check its arguments carefully. prod(beh , beh , ...) [SAL] 1 2 (prod beh beh ...) [LISP] 1 2 Same as mult. resample(sound, srate) [SAL] (resample sound srate) [LISP] Similar to force-srate, except high-quality interpolation is used to prefilter and reconstruct the signal at the new sample rate. Also, the result is scaled by 0.95 to reduce problems with clipping. (See also sound-warp.) scale(scale, sound) [SAL] (scale scale sound) [LISP] Scales the amplitude of sound by the factor scale. Identical function to snd-scale, except that it handles multichannel sounds. Sample rates, start times, etc. are taken from sound. scale-db(db, sound) [SAL] (scale-db db sound) [LISP] Scales the amplitude of sound by the factor db, expressed in decibels. Sample rates, start times, etc. are taken from sound. scale-srate(sound, scale) [SAL] (scale-srate sound scale) [LISP] Scales the sample rate of sound by scale factor. This has the effect of linearly shrinking or stretching time (the sound is not upsampled or downsampled). This is a special case of snd-xform (see Section 7.6.2). shift-time(sound, shift) [SAL] (shift-time sound shift) [LISP] Shift sound by shift seconds. If the sound is f(t), then the result is f(t-shift). See Figure 5. This is a special case of snd-xform (see Section 7.6.2). Figure 5: The shift-time function shifts a sound in time according to its shift argument. sound-warp(warp-fn, signal [, wrate]) [SAL] (sound-warp warp-fn signal [wrate]) [LISP] Applies a warp function warp-fn to signal using function composition. If the optional parameter wrate is omitted or NIL, linear interpolation is used. Otherwise, high-quality sample interpolation is used, and the result is scaled by 0.95 to reduce problems with clipping (interpolated samples can exceed the peak values of the input samples.) warp-fn is a mapping from score (logical) time to real time, and signal is a function from score time to real values. The result is a function from real time to real values at a sample rate of *sound-srate*. See also control-warp. If wrate is not NIL, it must be a number. The parameter indicates that high-quality resampling should be used and specifies the sample rate for the inverse of warp-fn. Use the lowest number you can. (See below for details.) Note that high-quality resampling is much slower than linear interpolation. To perform high-quality resampling by a fixed ratio, as opposed to a variable ratio allowed in sound-warp, use scale-srate to stretch or shrink the sound, and then resample to restore the original sample rate. Sound-warp and control-warp both take the inverse of warp-fn to get a function from real time to score time. Each sample of this inverse is thus a score time; signal is evaluated at each of these score times to yield a value, which is the desired result. The sample rate of the inverse warp function is somewhat arbitrary. With linear interpolation, the inverse warp function sample rate is taken to be the output sample rate. Note, however, that the samples of the inverse warp function are stored as 32-bit floats, so they have limited precision. Since these floats represent sample times, rounding can be a problem. Rounding in this case is equivalent to adding jitter to the sample times. Nyquist ignores this problem for ordinary warping, but for high-quality warping, the jitter cannot be ignored. The solution is to use a rather low sample rate for the inverse warp function. Sound-warp can then linearly interpolate this signal using double-precision floats to minimize jitter between samples. The sample rate is a compromise: a low sample rate minimizes jitter, while a high sample rate does a better job of capturing detail (e.g. rapid fluctuations) in the warp function. A good rule of thumb is to use at most 1,000 to 10,000 samples for the inverse warp function. For example, if the result will be 1 minute of sound, use a sample rate of 3000 samples / 60 seconds = 50 samples/second. Because Nyquist has no advance information about the warp function, the inverse warp function sample rate must be provided as a parameter. When in doubt, just try something and let your ears be the judge. integrate(signal) [SAL] (integrate signal) [LISP] Computes the integral of signal. The start time, sample rate, etc. are taken from signal. slope(signal) [SAL] (slope signal) [LISP] Computes the first derivative (slope) of signal. The start time, sample rate, etc. are taken from signal. 7.2.2.1. Oscillators osc(pitch [, duration, table, phase]) [SAL] (osc pitch [duration table phase]) [LISP] Returns a sound which is the table oscillated at pitch for the given duration, starting with the phase (in degrees). Defaults are: duration 1.0 (second), table *table*, phase 0.0. The default value of *table* is a sinusoid. Duration is stretched by *warp* and *sustain*, amplitude is nominally 1, but scaled by *loudness*, the start time is logical time 0, transformed by *warp*, and the sample rate is *sound-srate*. The effect of time-warping is to warp the starting and ending times only; the signal has a constant unwarped frequency. Note 1: table is a list of the form (sound pitch-number periodic) where the first element is a sound, the second is the pitch of the sound (this is not redundant, because the sound may represent any number of periods), and the third element is T if the sound is one period of a periodic signal, or nil if the sound is a sample that should not be looped. The maximum table size is set by max_table_len in sound.h, and is currently set to 1,000,000. Note 2: in the current implementation, it is assumed that the output should be periodic. See snd-down and snd-up for resampling one-shot sounds to a desired sample rate. A future version of osc will handle both cases. Note 3: When osc is called, memory is allocated for the table, and samples are copied from the sound (the first element of the list which is the table parameter) to the memory. Every instance of osc has a private copy of the table, so the total storage can become large in some cases, for example in granular synthesis with many instances of osc. In some cases, it may make sense to use snd-flatten (see Section 7.1.3) to cause the sound to be fully realized, after which the osc and its table memory can be reclaimed by garbage collection. The partial function (see below) does not need a private table and does not use much space. partial(pitch, env) [SAL] (partial pitch env) [LISP] Returns a sinusoid at the indicated pitch; the sound is multiplied by env. The start time and duration are taken from env, which is of course subject to transformations. The sample rate is *sound-srate*. The partial function is faster than osc. sine(pitch [, duration]) [SAL] (sine pitch [duration]) [LISP] Returns a sinusoid at the indicated pitch. The sample rate is *sound-srate*. This function is like osc with respect to transformations. The sine function is faster than osc. hzosc(hz [, table, phase]) [SAL] (hzosc hz [table phase]) [LISP] Returns a sound which is the table oscillated at hz starting at phase degrees. The default table is *table* and the default phase is 0.0. The default duration is 1.0, but this is stretched as in osc (see above). The hz parameter may be a SOUND, in which case the duration of the result is the duration of hz. The sample rate is *sound-srate*. osc-saw(hz) [SAL] (osc-saw hz) [LISP] Returns a sawtooth waveshape at the indicated frequency (in Hertz). The sample rate is *sound-srate*. The hz parameter may be a sound as in hzosc (see above). osc-tri(hz) [SAL] (osc-tri hz) [LISP] Returns a triangle waveshape at the indicated frequency (in Hertz). The sample rate is *sound-srate*. The hz parameter may be a sound as in hzosc (see above). osc-pulse(hz, bias [, compare-shape]) [SAL] (osc-pulse hz bias [compare-shape]) [LISP] Returns a square pulse with variable width at the indicated frequency (in Hertz). The bias parameter controls the pulse width and should be between -1 and +1, giving a pulse width from 0% (always at -1) to 100% (always at +1). When bias is zero, a square wave is generated. Bias may be a SOUND to create varying pulse width. If bias changes rapidly, strange effects may occur. The optional compare-shape defaults to a hard step at zero, but other shapes may be used to achieve non-square pulses. The osc-pulse behavior is written in terms of other behaviors and defined in the file nyquist.lsp using just a few lines of code. Read the code for the complete story. amosc(pitch, modulation [, table, phase]) [SAL] (amosc pitch modulation [table phase]) [LISP] Returns a sound which is table oscillated at pitch. The output is multiplied by modulation for the duration of the sound modulation. osc-table defaults to *table*, and phase is the starting phase (default 0.0 degrees) within osc-table. The sample rate is *sound-srate*. fmosc(pitch, modulation [, table, phase]) [SAL] (fmosc pitch modulation [table phase]) [LISP] Returns a sound which is table oscillated at pitch plus modulation for the duration of the sound modulation. osc-table defaults to *table*, and phase is the starting phase (default 0.0 degrees) within osc-table. The modulation is expressed in hz, e.g. a sinusoid modulation signal with an amplitude of 1.0 (2.0 peak to peak), will cause a +/N 1.0 hz frequency deviation in sound. Negative frequencies are correctly handled. The sample rate is *sound-srate*. fmfb(pitch, index [, dur]) [SAL] (fmfb pitch index [dur]) [LISP] Returns a sound generated by feedback FM synthesis. The pitch parameter (given in the usual half-step units) controls the fundamental frequency. The index is the amount of feedback, which may be a SOUND or a FLONUM. If index is a FLONUM, dur must be provided (a FLONUM) to specify the duration. Otherwise, dur is ignored if present and the duration is determined by that of index. The sample rate is *sound-srate*. A sinusoid table is used. If index is below 1.1, this generates a sawtooth-like waveform. buzz(n, pitch, modulation) [SAL] (buzz n pitch modulation) [LISP] Returns a sound with n harmonics of equal amplitude and a total amplitude of 1.0, using a well-known function of two cosines. If n (an integer) is less than 1, it is set to 1. Aliasing will occur if n is too large. The duration is determined by the duration of the sound modulation, which is a frequency modulation term expressed in Hz (see Section 7.2.2.1). Negative frequencies are correctly handled. The sample rate is *sound-srate*. pluck(pitch [, duration, final-amplitude]) [SAL] (pluck pitch [duration final-amplitude]) [LISP] Returns a sound at the given pitch created using a modified Karplus-Strong plucked string algorithm. The tone decays from an amplitude of about 1.0 to about final-amplitude in duration seconds. The default values are to decay to 0.001 (-60dB) in 1 second. The sample rate is *sound-srate*. siosc(pitch, modulation, tables) [SAL] (siosc pitch modulation tables) [LISP] Returns a sound constructed by interpolating through a succession of periodic waveforms. The frequency is given (in half steps) by pitch to which a modulation signal (in hz) is added, exactly as in fmosc. The tables specify a list of waveforms as follows: (table0 time1 table2 ... timeN tableN), where each table is a sound representing one period. Each time is a time interval measured from the starting time. The time is scaled by the nominal duration (computed using (local-to-global (get-sustain))) to get the actual time. Note that this implies linear stretching rather than continuous timewarping of the interpolation or the breakpoints. The waveform is table0 at the starting time, table1 after time1 (scaled as described), and so on. The duration and logical stop time is given by modulation. If modulation is shorter than timeN, then the full sequence of waveforms is not used. If modulation is longer than timeN, tableN is used after timeN without further interpolation. sampler(pitch, modulation [, sample, npoints]) [SAL] (sampler pitch modulation [sample npoints]) [LISP] Returns a sound constructed by reading a sample from beginning to end and then splicing on copies of the same sound from a loop point to the end. The pitch and modulation parameters are used as in fmosc described above. The optional sample (which defaults to the global variable *table* is a list of the form (sound pitch-number loop-start) where the first element is a sound containing the sample, the second is the pitch of the sample, and the third element is the time of the loop point. If the loop point is not in the bounds of the sound, it is set to zero. The optional npoints specifies how many points should be used for sample interpolation. Currently this parameter defaults to 2 and only 2-point (linear) interpolation is implemented. It is an error to modulate such that the frequency is negative. Note also that the loop point may be fractional. The sample rate is *sound-srate*. 7.2.2.2. Piece-wise Approximations There are a number of related behaviors for piece-wise approximations to functions. The simplest of these, pwl was mentioned earlier in the manual. It takes a list of breakpoints, assuming an initial point at (0, 0), and a final value of 0. An analogous piece-wise exponential function, pwe, is provided. Its implicit starting and stopping values are 1 rather than 0. Each of these has variants. You can specify the initial and final values (instead of taking the default). You can specify time in intervals rather than cummulative time. Finally, you can pass a list rather than an argument list. This leads to 16 versions: Piece-wise Linear Functions: Cummulative Time: Default initial point at (0, 0), final value at 0: pwl pwl-list Explicit initial value: pwlv pwlv-list Relative Time: Default initial point at (0, 0), final value at 0: pwlr pwlr-list Explicit initial value: pwlvr pwlvr-list Piece-wise Exponential Functions: Cummulative Time: Default initial point at (0, 1), final value at 1: pwe pwe-list Explicit initial value: pwev pwev-list Relative Time: Default initial point at (0, 1), final value at 1: pwer pwer-list Explicit initial value: pwevr pwevr-list All of these functions are implemented in terms of pwl (see nyquist.lsp for the implementations. There are infinite opportunities for errors in these functions: if you leave off a data point, try to specify points in reverse order, try to create an exponential that goes to zero or negative values, or many other bad things, the behavior is not well-defined. Nyquist should not crash, but Nyquist does not necessarily attempt to report errors at this time. pwl(t , l , t , l , ... t ) [SAL] 1 1 2 2 n (pwl t l t l ... t ) [LISP] 1 1 2 2 n Creates a piece-wise linear envelope with breakpoints at (0, 0), (t , l ), 1 1 (t , l ), ... (t , 0). The breakpoint times are scaled linearly by the 2 2 n value of *sustain* (if *sustain* is a SOUND, it is evaluated once at the starting time of the envelope). Each breakpoint time is then mapped according to *warp*. The result is a linear interpolation (unwarped) between the breakpoints. The sample rate is *control-srate*. Breakpoint times are quantized to the nearest sample time. If you specify one or more breakpoints withing one sample period, pwl attempts to give a good approximation to the specified function. In particular, if two breakpoints are simultaneous, pwl will move one of them to an adjacent sample, producing a steepest possible step in the signal. The exact details of this ``breakpoint munging'' is subject to change in future versions. Please report any cases where breakpoint lists give unexpected behaviors. The author will try to apply the ``principle of least surprise'' to the design. Note that the times are relative to 0; they are not durations of each envelope segment. pwl-list(breakpoints) [SAL] (pwl-list breakpoints) [LISP] If you have a list of breakpoints, you can use apply to apply the pwl function to the breakpoints, but if the list is very long (hundreds or thousands of points), you might get a stack overflow because XLISP has a fixed-size argument stack. Instead, call pwl-list, passing one argument, the list of breakpoints. pwlv(l , t , l , t , t , ... t , l ) [SAL] 1 2 2 3 3 n n (pwlv l t l t t ... t l ) [LISP] 1 2 2 3 3 n n Creates a piece-wise linear envelope with breakpoints at (0, l ), (t , 1 2 l ), etc., ending with (t , l . Otherwise, the behavior is like that of 2 n n pwl. pwlv-list(breakpoints) [SAL] (pwlv-list breakpoints) [LISP] A version of pwlv that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. pwlr(i , l , i , l , ... i ) [SAL] 1 1 2 2 n (pwlr i l i l ... i ) [LISP] 1 1 2 2 n Creates a piece-wise linear envelope with breakpoints at (0, 0), (t , l ), 1 1 (t , l ), ... (t , 0), where t is the sum of i through i . In other 2 2 n j 1 j words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwl. pwlr-list(breakpoints) [SAL] (pwlr-list breakpoints) [LISP] A version of pwlr that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. pwlvr(l , i , l , i , i , ... i , l ) [SAL] 1 2 2 3 3 n n (pwlvr l i l i i ... i l ) [LISP] 1 2 2 3 3 n n Creates a piece-wise linear envelope with breakpoints at (0, l ), (t , 1 2 l ), etc., ending with (t , l , where t is the sum of i through i . In 2 n n j 2 j other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwlv. pwlvr-list(breakpoints) [SAL] (pwlvr-list breakpoints) [LISP] A version of pwlvr that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. pwe(t , l , t , l , ... t ) [SAL] 1 1 2 2 n (pwe t l t l ... t ) [LISP] 1 1 2 2 n Creates a piece-wise exponential envelope with breakpoints at (0, 1), (t , 1 l ), (t , l ), ... (t , 1). Exponential segments means that the ratio of 1 2 2 n values from sample to sample is constant within the segment. (The current implementation actually takes the log of each value, computes a piece-wise exponential from the points using pwl, then exponentiates each resulting sample. A faster implementation is certainly possible!) Breakpoint values (l ) must be greater than zero. Otherwise, this function is j similar to pwl, including stretch by *sustain*, mapping according to *warp*, sample rate based on *control-srate*, and "breakpoint munging" (see pwl described above). Default initial and final values are of dubious value with exponentials. See pwev below for the function you are probably looking for. pwe-list(breakpoints) [SAL] (pwe-list breakpoints) [LISP] A version of pwe that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. pwev(l , t , l , t , t , ... t , l ) [SAL] 1 2 2 3 3 n n (pwev l t l t t ... t l ) [LISP] 1 2 2 3 3 n n Creates a piece-wise exponential envelope with breakpoints at (0, l ), 1 (t , l ), etc., ending with (t , l ). Otherwise, the behavior is like 2 2 n n that of pwe. pwev-list(breakpoints) [SAL] (pwev-list breakpoints) [LISP] A version of pwev that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. pwer(i , l , i , l , ... i ) [SAL] 1 1 2 2 n (pwer i l i l ... i ) [LISP] 1 1 2 2 n Creates a piece-wise exponential envelope with breakpoints at (0, 1), (t , 1 l ), (t , l ), ... (t , 1), where t is the sum of i through i . In 1 2 2 n j 1 j other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwe. Consider using pwerv instead of this one. pwer-list(breakpoints) [SAL] (pwer-list breakpoints) [LISP] A version of pwer that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. pwevr(l , i , l , i , i , ... i , l ) [SAL] 1 2 2 3 3 n n (pwevr l i l i i ... i l ) [LISP] 1 2 2 3 3 n n Creates a piece-wise exponential envelope with breakpoints at (0, l ), 1 (t , l ), etc., ending with (t , l , where t is the sum of i through i . 2 2 n n j 2 j In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwev. Note that this is similar to the csound GEN05 generator. Which is uglier, GEN05 or pwevr? pwevr-list(breakpoints) [SAL] (pwevr-list breakpoints) [LISP] A version of pwevr that takes a single list of breakpoints as its argument. See pwl-list above for the rationale. 7.2.2.3. Filter Behaviors alpass(sound, decay, hz [, minhz]) [SAL] (alpass sound decay hz [minhz]) [LISP] Applies an all-pass filter to sound. This all-pass filter creates a delay effect without the resonances of a comb filter. The decay time of the filter is given by decay. The hz parameter must be a number or sound greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The decay may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert decay into the feedback parameter, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide decay at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of sound. If hz is of type SOUND, the delay may be time-varying. Linear interpolation is then used for fractional sample delay, but it should be noted that linear interpolation implies a low-pass transfer function. Thus, this filter may behave differently with a constant SOUND than it does with a FLONUM value for hz. In addition, if hz is of type SOUND, then minhz is required. The hz parameter will be clipped to be greater than minhz, placing an upper bound on the delay buffer length. comb(sound, decay, hz) [SAL] (comb sound decay hz) [LISP] Applies a comb filter to sound. A comb filter emphasizes (resonates at) frequencies that are multiples of a hz. The decay time of the resonance is given by decay. This is a variation on feedback-delay (see below). The hz parameter must be a number greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The decay may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert decay into the feedback parameter for feedback-delay, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide decay at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of sound. congen(gate, risetime, falltime) [SAL] (congen gate risetime falltime) [LISP] Implements an analog synthesizer-style contour generator. The input gate normally goes from 0.0 to 1.0 to create an attack and from 1.0 to 0.0 to start a release. During the attack (output is increasing), the output converges half-way to gate in risetime (a FLONUM) seconds. During the decay, the half-time is falltime seconds. The sample rate, start time, logical stop, and terminate time all come from gate. If you want a nice decay, be sure that the gate goes to zero and stays there for awhile before gate terminates, because congen (and all Nyquist sounds) go immediately to zero at termination time. For example, you can use pwl to build a pulse followed by some zero time: (pwl 0 1 duty 1 duty 0 1) Assuming duty is less than 1.0, this will be a pulse of duration duty followed by zero for a total duration of 1.0. (congen (pwl 0 1 duty 1 duty 0 1) 0.01 0.05) will have a duration of 1.0 because that is the termination time of the pwl input. The decaying release of the resulting envelope will be truncated to zero at time 1.0. (Since the decay is theoretically infinite, there is no way to avoid truncation, although you could multiply by another envelope that smoothly truncates to zero in the last millisecond or two to get both an exponential decay and a smooth final transition to zero.) convolve(sound, response) [SAL] (convolve sound response) [LISP] Convolves two signals. The first can be any length, but the computation time per sample and the total space required are proportional to the length of response. feedback-delay(sound, delay, feedback) [SAL] (feedback-delay sound delay feedback) [LISP] Applies feedback delay to sound. The delay must be a number (in seconds). It is rounded to the nearest sample to determine the length of the delay. The sample rate is the maximum from sound and feedback (if feedback is also a sound). The amound of feedback should be less than one to avoid an exponential increase in amplitude. The start time and stop time, and logical stop time are taken from sound. Since output is truncated at the stop time of sound, you may want to append some silence to sound to give the filter time to decay. lp(sound, cutoff) [SAL] (lp sound cutoff) [LISP] Filters sound using a first-order Butterworth low-pass filter. Cutoff may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of cutoff. The resulting sample rate, start time, etc. are taken from sound. tone(sound, cutoff) [SAL] (tone sound cutoff) [LISP] No longer defined; use lp instead, or define it by adding (setfn tone lp) to your program. hp(sound, cutoff) [SAL] (hp sound cutoff) [LISP] Filters sound using a first-order Butterworth high-pass filter. Cutoff may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of cutoff. This filter is an exact complement of lp. atone(sound, cutoff) [SAL] (atone sound cutoff) [LISP] No longer defined; use hp instead, or define it by adding (setfn atone hp) to your program. reson(sound, center, bandwidth, n) [SAL] (reson sound center bandwidth n) [LISP] Apply a resonating filter to sound with center frequency center (in hertz), which may be a float or a signal. Bandwidth is the filter bandwidth (in hertz), which may also be a signal. Filter coefficients (requiring trig functions) are recomputed at each new sample of either center or bandwidth, and coefficients are not interpolated. The last parameter n specifies the type of normalization as in Csound: A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than hz are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The resulting sample rate, start time, etc. are taken from sound. One application of reson is to simulate resonances in the human vocal tract. See demos/voice_synthesis.htmfor sample code and documentation. areson(sound, center, bandwidth, n) [SAL] (areson sound center bandwidth n) [LISP] The areson filter is an exact complement of reson such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. shape(signal, table, origin) [SAL] (shape signal table origin) [LISP] A waveshaping function. Use table as a function; apply the function to each sample of signal to yield a new sound. Signal should range from -1 to +1. Anything beyond these bounds is clipped. Table is also a sound, but it is converted into a lookup table (similar to table-lookup oscillators). The origin is a FLONUM and gives the time which should be considered the origin of table. (This is important because table cannot have values at negative times, but signal will often have negative values. The origin gives an offset so that you can produce suitable tables.) The output at time t is: table(origin + clip(signal(t)) where clip(x) = max(1, min(-1, x)). (E.g. if table is a signal defined over the interval [0, 2], then origin should be 1.0. The value of table at time 1.0 will be output when the input signal is zero.) The output has the same start time, sample rate, etc. as signal. The shape function will also accept multichannel signals and tables. Further discussion and examples can be found in demos/distortion.htm. The shape function is also used to map frequency to amplitude to achieve a spectral envelope for Shepard tones in demos/shepard.lsp. biquad(signal, b0, b1, b2, a0, a1, a2) [SAL] (biquad signal b0 b1 b2 a0 a1 a2) [LISP] A fixed-parameter biquad filter. All filter coefficients are FLONUMs. See also lowpass2, highpass2, bandpass2, notch2, allpass2, eq-lowshelf, eq-highshelf, eq-band, lowpass4, lowpass6, highpass4, and highpass8 in this section for convenient variations based on the same filter. The equations for the filter are: z = s + a1 * z + a2 * z , and y = z n n n-1 n-2 n n * b0 + z * b1 + z * b2. n-1 n-2 biquad-m(signal, b0, b1, b2, a0, a1, a2) [SAL] (biquad-m signal b0 b1 b2 a0 a1 a2) [LISP] A fixed-parameter biquad filter with Matlab sign conventions for a0, a1, and a2. All filter coefficients are FLONUMs. lowpass2(signal, hz [, q]) [SAL] (lowpass2 signal hz [q]) [LISP] A fixed-parameter, second-order lowpass filter based on snd-biquad. The cutoff frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM). highpass2(signal, hz [, q]) [SAL] (highpass2 signal hz [q]) [LISP] A fixed-parameter, second-order highpass filter based on snd-biquad. The cutoff frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM). bandpass2(signal, hz [, q]) [SAL] (bandpass2 signal hz [q]) [LISP] A fixed-parameter, second-order bandpass filter based on snd-biquad. The center frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM). notch2(signal, hz [, q]) [SAL] (notch2 signal hz [q]) [LISP] A fixed-parameter, second-order notch filter based on snd-biquad. The center frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM). allpass2(signal, hz [, q]) [SAL] (allpass2 signal hz [q]) [LISP] A fixed-parameter, second-order allpass filter based on snd-biquad. The frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM). eq-lowshelf(signal, hz, gain [, slope]) [SAL] (eq-lowshelf signal hz gain [slope]) [LISP] A fixed-parameter, second-order bass shelving equalization (EQ) filter based on snd-biquad. The hz parameter (a FLONUM)is the halfway point in the transition, and gain (a FLONUM) is the bass boost (or cut) in dB. The optional slope (a FLONUM) is 1.0 by default, and response becomes peaky at values greater than 1.0. eq-highshelf(signal, hz, gain [, slope]) [SAL] (eq-highshelf signal hz gain [slope]) [LISP] A fixed-parameter, second-order treble shelving equalization (EQ) filter based on snd-biquad. The hz parameter (a FLONUM)is the halfway point in the transition, and gain (a FLONUM) is the treble boost (or cut) in dB. The optional slope (a FLONUM) is 1.0 by default, and response becomes peaky at values greater than 1.0. eq-band(signal, hz, gain, width) [SAL] (eq-band signal hz gain width) [LISP] A fixed- or variable-parameter, second-order midrange equalization (EQ) filter based on snd-biquad, snd-eqbandcv and snd-eqbandvvv. The hz parameter (a FLONUM) is the center frequency, gain (a FLONUM) is the boost (or cut) in dB, and width (a FLONUM) is the half-gain width in octaves. Alternatively, hz, gain, and width may be SOUNDs, but they must all have the same sample rate, e.g. they should all run at the control rate or at the sample rate. lowpass4(signal, hz) [SAL] (lowpass4 signal hz) [LISP] A four-pole Butterworth lowpass filter. The cutoff frequency is hz (a FLONUM). lowpass6(signal, hz) [SAL] (lowpass6 signal hz) [LISP] A six-pole Butterworth lowpass filter. The cutoff frequency is hz (a FLONUM). lowpass8(signal, hz) [SAL] (lowpass8 signal hz) [LISP] An eight-pole Butterworth lowpass filter. The cutoff frequency is hz (a FLONUM). highpass4(signal, hz) [SAL] (highpass4 signal hz) [LISP] A four-pole Butterworth highpass filter. The cutoff frequency is hz (a FLONUM). highpass6(signal, hz) [SAL] (highpass6 signal hz) [LISP] A six-pole Butterworth highpass filter. The cutoff frequency is hz (a FLONUM). highpass8(signal, hz) [SAL] (highpass8 signal hz) [LISP] An eight-pole Butterworth highpass filter. The cutoff frequency is hz (a FLONUM). tapv(sound, offset, vardelay, maxdelay) [SAL] (tapv sound offset vardelay maxdelay) [LISP] A delay line with a variable position tap. Identical to snd-tapv. See it for details (7.6.2). 7.2.2.4. Effects nrev(sound, decay, mix) [SAL] (nrev sound decay mix) [LISP] jcrev(sound, decay, mix) [SAL] (jcrev sound decay mix) [LISP] prcrev(sound, decay, mix) [SAL] (prcrev sound decay mix) [LISP] These reverbs (nrev, jcrev, and prcrev) are implemented in STK (running within Nyquist). nrev derives from Common Music's NRev, which consists of 6 comb filters followed by 3 allpass filters, a lowpass filter, and another allpass in series followed by two allpass filters in parallel. jcrev is the John Chowning reverberator which is based on the use of networks of simple allpass and comb delay filters. This reverb implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. prcrev is a Perry Cook's reverberator which is based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This one implements two series allpass units and two parallel comb filters. The sound input may be single or multi-channel. The decay time is in seconds, and mix sets the mixture of input sound reverb sound, where 0.0 means input only (dry) and 1.0 means reverb only (wet). stkchorus(sound, depth, freq, mix [, delay]) [SAL] (stkchorus sound depth freq mix [delay]) [LISP] Chorus implemented in STK. The input sound can be single or multi-channel. The FLONUM parameters depth and freq set the modulation depth from 0 to 1 and modulation frequency (in Hz), and mix sets the mixture of input sound and chorused sound, where 0.0 means input sound only (dry) and 1.0 means chorused sound only (wet). The parameter delay is a FIXNUM representing the median desired delay length in samples. pitshift(sound, shift, mix) [SAL] (pitshift sound shift mix) [LISP] A pitch shifter implemented in STK. The input sound, a single-channel or multi-channel SOUND is pitch-shifted by shift, a FLONUM ratio. A value of 1.0 means no shift. The parameter mix sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). 7.2.2.5. Physical Models clarinet(step, breath-env) [SAL] (clarinet step breath-env) [LISP] A physical model of a clarinet from STK. The step parameter is a FLONUM that controls the tube length, and the breath-env (a SOUND) controls the air pressure and also determines the length of the resulting sound. The breath-env signal should range from zero to one. clarinet-freq(step, breath-env, freq-env) [SAL] (clarinet-freq step breath-env freq-env) [LISP] A variation of clarinet that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrarily set to 30. clarinet-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, reed-stiffness, noise) [SAL] (clarinet-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise) [LISP] A variation of clarinet-freq that includes controls vibrato-freq (a FLONUM for vibrato frequency in Hertz), vibrato-gain (a FLONUM for the amount of amplitude vibrato), reed-stiffness (a FLONUM or SOUND controlling reed stiffness in the clarinet model), and noise (a FLONUM or SOUND controlling noise amplitude in the input air pressure). The vibrato-gain is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The reed-stiffness parameter varies from zero to one. The duration of the resulting sound is the minimum duration of breath-env, freq-env, reed-stiffness, and noise. As with clarinet-freq, these parameters may be either FLONUMs or SOUNDs, and FLONUMs are coerced to sounds with a nominal duration of 30. sax(step, breath-env) [SAL] (sax step breath-env) [LISP] A physical model of a sax from STK. The step parameter is a FLONUM that controls the tube length, and the breath-env controls the air pressure and also determines the length of the resulting sound. The breath-env signal should range from zero to one. sax-freq(step, breath-env, freq-env) [SAL] (sax-freq step breath-env freq-env) [LISP] A variation of sax that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrarily set to 30. sax-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, reed-stiffness, noise, blow-pos, reed-table-offset) [SAL] (sax-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise blow-pos reed-table-offset) [LISP] A variation of sax-freq that includes controls vibrato-freq (a FLONUM for vibrato frequency in Hertz), vibrato-gain (a FLONUM for the amount of amplitude vibrato), reed-stiffness (a SOUND controlling reed stiffness in the sax model), noise (a SOUND controlling noise amplitude in the input air pressure), blow-pos (a SOUND controlling the point of excitation of the air column), and reed-table-offset (a SOUND controlling a parameter of the reed model). The vibrato-gain is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The reed-stiffness, blow-pos, and reed-table-offset parameters all vary from zero to one. The duration of the resulting sound is the minimum duration of breath-env, freq-env, reed-stiffness, noise, breath-env, blow-pos, and reed-table-offset. As with sax-freq, these parameters may be either FLONUMs or SOUNDs, and FLONUMs are coerced to sounds with a nominal duration of 30. flute(step, breath-env) [SAL] (flute step breath-env) [LISP] A physical model of a flute from STK. The step parameter is a FLONUM that controls the tube length, and the breath-env controls the air pressure and also determines the starting time and length of the resulting sound. The breath-env signal should range from zero to one. flute-freq(step, breath-env, freq-env) [SAL] (flute-freq step breath-env freq-env) [LISP] A variation of flute that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrary set to 30. flute-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, jet-delay, noise) [SAL] (flute-all step breath-env freq-env vibrato-freq vibrato-gain jet-delay noise) [LISP] A variation of clarinet-freq that includes controls vibrato-freq (a FLONUM for vibrato frequency in Hz), vibrato-gain (a FLONUM for the amount of amplitude vibrato), jet-delay (a FLONUM or SOUND controlling jet delay in the flute model), and noise (a FLONUM or SOUND controlling noise amplitude in the input air pressure). The vibrato-gain is a number from zero to one where zero means no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one, where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The jet-delay is a ratio that controls a delay length from the flute model, and therefore it changes the pitch of the resulting sound. A value of 0.5 will maintain the pitch indicated by the step parameter. The duration of the resulting sound is the minimum duration of breath-env, freq-env, jet-delay, and noise. These parameters may be either FLONUMs or SOUNDs, and FLONUMs are coerced to sounds with a nominal duration of 30. bowed(step, bowpress-env) [SAL] (bowed step bowpress-env) [LISP] A physical model of a bowed string instrument from STK. The step parameter is a FLONUM that controls the string length, and the bowpress-env controls the bow pressure and also determines the duration of the resulting sound. The bowpress-env signal should range from zero to one. bowed-freq(step, bowpress-env, freq-env) [SAL] (bowed-freq step bowpress-env freq-env) [LISP] A variation of bowed that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of bowpress-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrarily set to 30s. mandolin(step, dur, &optional detune) [SAL] (mandolin step dur detune) [LISP] A physical model of a plucked double-string instrument from STK. The step parameter is a FLONUM wich specifies the desired pitch, dur means the duration of the resulting sound and detune is a FLONUM that controls the relative detune of the two strings. A value of 1.0 means unison. The default value is 4.0. Note: body-size (see snd-mandolin does not seem to work correctly, so a default value is always used by mandolin. wg-uniform-bar(step, bowpress-env) [SAL] (wg-uniform-bar step bowpress-env) [LISP] wg-tuned-bar(step, bowpress-env) [SAL] (wg-tuned-bar step bowpress-env) [LISP] wg-glass-harm(step, bowpress-env) [SAL] (wg-glass-harm step bowpress-env) [LISP] wg-tibetan-bowl(step, bowpress-env) [SAL] (wg-tibetan-bowl step bowpress-env) [LISP] These sounds are presets for a Banded Wave Guide Percussion instrument implemented in STK. The parameter step is a FLONUM that controls the resultant pitch, and bowpress-env is a SOUND ranging from zero to one that controls a parameter of the model. In addition, bowpress-env determines the duration of the resulting sound. (Note: The bowpress-env does not seems influence the timbral quality of the resulting sound). modalbar(preset, step, dur) [SAL] (modalbar preset step dur) [LISP] A physical model of a struck bar instrument implemented in STK. The parameter preset is one of the symbols MARIMBA, VIBRAPHONE, AGOGO, WOOD1, RESO, WOOD2, BEATS, TWO-FIXED, or CLUMP. The symbol must be quoted, e.g. for SAL syntax use quote(marimba), and for Lisp syntax use 'marimba. The parameter step is a FLONUM that sets the pitch (in steps), and dur is the duration in seconds. sitar(step, dur) [SAL] (sitar step dur) [LISP] A sitar physical model implemented in STK. The parameter step is a FLONUM that sets the pitch, and dur is the duration. 7.2.2.6. More Behaviors clip(sound, peak) [SAL] (clip sound peak) [LISP] Hard limit sound to the given peak, a positive number. The samples of sound are constrained between an upper value of peak and a lower value of N()peak. If sound is a number, clip will return sound limited by peak. If sound is a multichannel sound, clip returns a multichannel sound where each channel is clipped. The result has the type, sample rate, starting time, etc. of sound. s-abs(sound) [SAL] (s-abs sound) [LISP] A generalized absolute value function. If sound is a SOUND, compute the absolute value of each sample. If sound is a number, just compute the absolute value. If sound is a multichannel sound, return a multichannel sound with s-abs applied to each element. The result has the type, sample rate, starting time, etc. of sound. s-sqrt(sound) [SAL] (s-sqrt sound) [LISP] A generalized square root function. If sound is a SOUND, compute the square root of each sample. If sound is a number, just compute the square root. If sound is a multichannel sound, return a multichannel sound with s-sqrt applied to each element. The result has the type, sample rate, starting time, etc. of sound. In taking square roots, if an input sample is less than zero, the corresponding output sample is zero. This is done because the square root of a negative number is undefined. s-exp(sound) [SAL] (s-exp sound) [LISP] x A generalized exponential function. If sound is a SOUND, compute e for x each sample x. If sound is a number x, just compute e . If sound is a multichannel sound, return a multichannel sound with s-exp applied to each element. The result has the type, sample rate, starting time, etc. of sound. s-log(sound) [SAL] (s-log sound) [LISP] A generalized natural log function. If sound is a SOUND, compute ln(x) for each sample x. If sound is a number x, just compute ln(x). If sound is a multichannel sound, return a multichannel sound with s-log applied to each element. The result has the type, sample rate, starting time, etc. of sound. Note that the ln of 0 is undefined (some implementations return negative infinity), so use this function with care. s-max(sound1, sound2) [SAL] (s-max sound1 sound2) [LISP] Compute the maximum of two functions, sound1 and sound2. This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of sound1 and sound2. The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of sound1 and sound2. Note, therefore, that the result value is zero except within the bounds of both input sounds. s-min(sound1, sound2) [SAL] (s-min sound1 sound2) [LISP] Compute the minimum of two functions, sound1 and sound2. This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of sound1 and sound2. The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of sound1 and sound2. Note, therefore, that the result value is zero except within the bounds of both input sounds. osc-note(pitch [, duration, env, loud, table]) [SAL] (osc-note pitch [duration env loud table]) [LISP] Same as osc, but osc-note multiplies the result by env. The env may be a sound, or a list supplying (t t t l l l ). The result has a sample 1 2 4 1 2 3 rate of *sound-srate*. quantize(sound, steps) [SAL] (quantize sound steps) [LISP] Quantizes sound as follows: sound is multiplied by steps and rounded to the nearest integer. The result is then divided by steps. For example, if steps is 127, then a signal that ranges from -1 to +1 will be quantized to 255 levels (127 less than zero, 127 greater than zero, and zero itself). This would match the quantization Nyquist performs when writing a signal to an 8-bit audio file. The sound may be multi-channel. ramp([duration]) [SAL] (ramp [duration]) [LISP] Returns a linear ramp from 0 to 1 over duration (default is 1). The function actually reaches 1 at duration, and therefore has one extra sample, making the total duration be duration + 1/*Control-srate*. See Figure 6 for more detail. Ramp is unaffected by the sustain transformation. The effect of time warping is to warp the starting and ending times only. The ramp itself is unwarped (linear). The sample rate is *control-srate*. rms(sound [, rate, window-size]) [SAL] (rms sound [rate window-size]) [LISP] Computes the RMS of sound using a square window of size window-size. The result has a sample rate of rate. The default value of rate is 100 Hz, and the default window size is 1/rate seconds (converted to samples). The rate is a FLONUM and window-size is a FIXNUM. Figure 6: Ramps generated by pwl and ramp functions. The pwl version ramps toward the breakpoint (1, 1), but in order to ramp back to zero at breakpoint (1, 0), the function never reaches an amplitude of 1. If used at the beginning of a seq construct, the next sound will begin at time 1. The ramp version actually reaches breakpoint (1, 1); notice that it is one sample longer than the pwl version. If used in a sequence, the next sound after ramp would start at time 1 + P, where P is the sample period. recip(sound) [SAL] (recip sound) [LISP] A generalized reciprocal function. If sound is a SOUND, compute 1/x for each sample x. If sound is a number x, just compute 1/x. If sound is a multichannel sound, return a multichannel sound with recip applied to each element. The result has the type, sample rate, starting time, etc. of sound. Note that the reciprocal of 0 is undefined (some implementations return infinity), so use this function with care on sounds. Division of sounds is accomplished by multiplying by the reciprocal. Again, be careful not to divide by zero. s-rest([duration]) [SAL] (s-rest [duration]) [LISP] Create silence (zero samples) for the given duration at the sample rate *sound-srate*. Default duration is 1.0 sec, and the sound is transformed in time according to *warp*. Note: rest is a Lisp function that is equivalent to cdr. Be careful to use s-rest when you need a sound! noise([duration]) [SAL] (noise duration) [LISP] Generate noise with the given duration. Duration (default is 1.0) is transformed according to *warp*. The sample rate is *sound-srate* and the amplitude is +/- *loud*. yin(sound, minstep, maxstep, stepsize) [SAL] (yin sound minstep maxstep stepsize) [LISP] Fundamental frequency estimation (pitch detection. Use the YIN algorithm to estimate the fundamental frequency of sound, which must be a SOUND. The minstep, a FLONUM, is the minimum frequency considered (in steps), maxstep, a FLONUM, is the maximum frequency considered (in steps), and stepsize, a FIXNUM, is the desired hop size. The result is a ``stereo'' signal, i.e. an array of two SOUNDs, both at the same sample rate, which is approximately the sample rate of sound divided by stepsize. The first SOUND consists of frequency estimates. The second sound consists of values that measure the confidence or reliability of the frequency estimate. A small value (less than 0.1) indicates fairly high confidence. A larger value indicates lower confidence. This number can also be thought of as a ratio of non-periodic power to periodic power. When the number is low, it means the signal is highly periodic at that point in time, so the period estimate will be reliable. Hint #1: See Alain de Cheveigne and Hideki Kawahara's article "YIN, a Fundamental Frequency Estimator for Speech and Music" in the Journal of the Acoustic Society of America, April 2002 for details on the yin algorithm. Hint #2: Typically, the stepsize should be at least the expected number of samples in one period so that the fundamental frequency estimates are calculated at a rate far below the sample rate of the signal. Frequency does not change rapidly and the yin algorithm is fairly slow. To optimize speed, you may want to use less than 44.1 kHz sample rates for input sounds. Yin uses interpolation to achieve potentially fractional-sample-accurate estimates, so higher sample rates do not necessarily help the algorithm and definitely slow it down. The 2 computation time is O(n ) per estimate, where n is the number of samples in the longest period considered. Therefore, each increase of minstep by 12 (an octave) gives you a factor of 4 speedup, and each decrease of the sample rate of sound by a factor of two gives you another factor of 4 speedup. Finally, the number of estimates is inversely proportional to stepsize. Hint #3: Use snd-srate (see Section 7.1.3) to get the exact sample rate of the result, which will be the sample rate of sound divided by stepsize. E.g. (snd-srate (aref yin-output 0)), where yin-output is a result returned by yin, will be the sample rate of the estimates. 7.3. Transformations These functions change the environment that is seen by other high-level functions. Note that these changes are usually relative to the current environment. There are also ``absolute'' versions of each transformation function, with the exception of seq, seqrep, sim, and simrep. The ``absolute'' versions (starting or ending with ``abs'') do not look at the current environment, but rather set an environment variable to a specific value. In this way, sections of code can be insulated from external transformations. abs-env(beh) [SAL] (abs-env beh) [LISP] Compute beh in the default environment. This is useful for computing waveform tables and signals that are ``outside'' of time. For example, (at 10.0 (abs-env (my-beh))) is equivalent to (abs-env (my-beh)) because abs-env forces the default environment. Or in SAL, we would say abs-env(my-beh()) @ 10 is equivalent to abs-env(my-beh()). at(time, beh) [SAL] (at time beh) [LISP] Evaluate beh with *warp* shifted by time. In SAL, you can use the infix operator @ as in beh @ time. To discover how the environment is shifting time, use local-to-global(time). Most commonly, you call local-to- global(0) to find when a sound created in the current environment will start, expressed in absolute (global) terms. This can be regarded as the ``current time.'' at-abs(time, beh) [SAL] (at-abs time beh) [LISP] Evaluate beh with *warp* shifted so that local time 0 maps to time. In SAL, you can use the infix operator @@ as in beh @@ time. continuous-control-warp(beh) [SAL] (continuous-control-warp beh) [LISP] Applies the current warp environment to the signal returned by beh. The result has the default control sample rate *control-srate*. Linear interpolation is currently used. Implementation: beh is first evaluated without any shifting, stretching, or warping. The result is functionally composed with the inverse of the environment's warp function. continuous-sound-warp(beh) [SAL] (continuous-sound-warp beh) [LISP] Applies the current warp environment to the signal returned by beh. The result has the default sound sample rate *sound-srate*. Linear interpolation is currently used. See continuous-control-warp for implementation notes. control-srate-abs(srate, beh) [SAL] (control-srate-abs srate beh) [LISP] Evaluate beh with *control-srate*set to sample rate srate. Note: there is no ``relative'' version of this function. extract(start, stop, beh) [SAL] (extract start stop beh) [LISP] Returns a sound which is the portion of beh between start and stop. Note that this is done relative to the current *warp*. The result is shifted to start according to *warp*, so normally the result will start without a delay of start. extract-abs(start, stop, beh) [SAL] (extract-abs start stop beh) [LISP] Returns a sound which is the portion of beh between start and stop, independent of the current *warp*. The result is shifted to start according to *warp*. loud(volume, beh) [SAL] (loud volume beh) [LISP] Evaluates beh with *loud* incremented by volume. (Recall that *loud* is in decibels, so increment is the proper operation.) loud-abs(volume, beh) [SAL] (loud-abs volume beh) [LISP] Evaluates beh with *loud* set to volume. sound-srate-abs(srate, beh) [SAL] (sound-srate-abs srate beh) [LISP] Evaluate beh with *sound-srate* set to sample rate srate. Note: there is no ``relative'' version of this function. stretch(factor, beh) [SAL] (stretch factor beh) [LISP] Evaluates beh with *warp* scaled by factor. The effect is to ``stretch'' the result of beh (under the current environment) by factor. See Chapter 4 for more information. Use get-duration(dur) to get the nominal actual duration of a behavior that locally has a duration of dur. Here, ``nominal'' means what would be expected if the behavior obeys the shift, stretch, and warp components of the environment. (Any behavior is free to deviate from the nominal timing. For example, a percussion sound might have a fixed duration independent of the stretch factor.) Also, ``actual'' means global or absolute time, and ``locally'' means within the environment where get-duration is called. get-duration works by mapping the current time (local time 0) using local-to-global to obtain an actual start time, and mapping dur to obtain an actual end time. The difference is returned. stretch-abs(factor, beh) [SAL] (stretch-abs factor beh) [LISP] Evaluates beh with *warp* set to a linear time transformation where each unit of logical time maps to factor units of real time. The effect is to stretch the nominal behavior of beh (under the default global environment) by factor. See Chapter 4 for more information. sustain(factor, beh) [SAL] (sustain factor beh) [LISP] Evaluates beh with *sustain* scaled by factor. The effect is to ``stretch'' the result of beh (under the current environment) by factor; however, the logical stop times are not stretched. Therefore, the overall duration of a sequence is not changed, and sounds will tend to overlap if *sustain* is greater than one (legato) and be separated by silence if *sustain* is less than one. sustain-abs(factor, beh) [SAL] (sustain-abs factor beh) [LISP] Evaluates beh with *sustain* set to factor. (See sustain, above.) transpose(amount, beh) [SAL] (transpose amount beh) [LISP] Evaluates beh with *transpose* shifted by amount. The effect is relative transposition by amount semitones. transpose-abs(amount, beh) [SAL] (transpose-abs amount beh) [LISP] Evaluates beh with *transpose* set to amount. The effect is the transposition of the nominal pitches in beh (under the default global environment) by amount. warp(fn, beh) [SAL] (warp fn beh) [LISP] Evaluates beh with *warp* modified by fn. The idea is that beh and fn are written in the same time system, and fn warps that time system to local time. The current environment already contains a mapping from local time to global (real) time. The value of *warp* in effect when beh is evaluated is the functional composition of the initial *warp* with fn. warp-abs(fn, beh) [SAL] (warp-abs fn beh) [LISP] Evaluates beh with *warp* set to fn. In other words, the current *warp* is ignored and not composed with fn to form the new *warp*. 7.4. Combination and Time Structure These behaviors combine component behaviors into structures, including sequences (melodies), simultaneous sounds (chords), and structures based on iteration. seq(beh [, beh , ...]) [SAL] 1 2 (seq beh [beh ...]) [LISP] 1 2 Evaluates the first behavior beh according to *time* and each successive 1 behavior at the logical-stop time of the previous one. The results are summed to form a sound whose logical-stop is the logical-stop of the last behavior in the sequence. Each behavior can result in a multichannel sound, in which case, the logical stop time is considered to be the maximum logical stop time of any channel. The number of channels in the result is the number of channels of the first behavior. If other behaviors return fewer channels, new channels are created containing constant zero signals until the required number of channels is obtained. If other behaviors return a simple sound rather than multichannel sounds, the sound is automatically assigned to the first channel of a multichannel sound that is then filled out with zero signals. If another behavior returns more channels than the first behavior, the error is reported and the computation is stopped. Sample rates are converted up or down to match the sample rate of the first sound in a sequence. seqrep(var, limit, beh) [SAL] (seqrep var limit beh) [LISP] Iteratively evaluates beh with the atom var set with values from 0 to limit-1, inclusive. These sounds are placed sequentially in time as if by seq. The symbol var is a read-only local variable to beh. Assignments are not restricted or detected, but may cause a run-time error or crash. In LISP, the syntax is (seqrep (var limit) beh). sim([beh , beh , ...]) [SAL] 1 2 (sim [beh beh ...]) [LISP] 1 2 Returns a sound which is the sum of the given behaviors evaluated with current value of *warp*. If behaviors return multiple channel sounds, the corresponding channels are added. If the number of channels does not match, the result has the maximum. For example, if a two-channel sound [L, R] is added to a four-channel sound [C1, C2, C3, C4], the result is [L + C1, R + C2, C3, C4]. Arguments to sim may also be numbers. If all arguments are numbers, sim is equivalent (although slower than) the + function. If a number is added to a sound, snd-offset is used to add the number to each sample of the sound. The result of adding a number to two or more sounds with different durations is not defined. Use const to coerce a number to a sound of a specified duration. An important limitation of sim is that it cannot handle hundreds of behaviors due to a stack size limitation in XLISP. To compute hundreds of sounds (e.g. notes) at specified times, see timed-seq, below. See also sum below. simrep(var, limit, beh) [SAL] (simrep var limit beh) [LISP] Iteratively evaluates beh with the atom var set with values from 0 to limit-1, inclusive. These sounds are then placed simultaneously in time as if by sim. In LISP, the syntax is (seqrep (var limit) beh). trigger(s, beh) [SAL] (trigger s beh) [LISP] Returns a sound which is the sum of instances of the behavior beh. One instance is created each time SOUND s makes a transition from less than or equal to zero to greater than zero. (If the first sample of s is greater than zero, an instance is created immediately.) The sample rate of s and all behaviors must be the same, and the behaviors must be (monophonic) SOUNDs. This function is particularly designed to allow behaviors to be invoked in real time by making s a function of a Nyquist slider, which can be controlled by a graphical interface or by OSC messages. See snd-slider in Section 7.6.1. set-logical-stop(beh, time) [SAL] (set-logical-stop beh time) [LISP] Returns a sound with time as the logical stop time. sum(a [, b, ...]) [SAL] (sum a [b ...]) [LISP] Returns the sum of a, b, ..., allowing mixed addition of sounds, multichannel sounds and numbers. Identical to sim. In SAL, use the infix ``+'' operator. mult(a [, b, ...]) [SAL] (mult a [b ...]) [LISP] Returns the product of a, b, ..., allowing mixed multiplication of sounds, multichannel sounds and numbers. diff(a, b) [SAL] (diff a b) [LISP] Returns the difference between a and b. This function is defined as (sum a (prod -1 b)). timed-seq(score) [SAL] (timed-seq score) [LISP] Computes sounds from a note list or ``score.'' The score is of the form: `((time1 stretch1 beh1) (time2 stretch2 beh2) ...), where timeN is the starting time, stretchN is the stretch factor, and behN is the behavior. Note that score is normally a quoted list! The times must be in increasing order, and each behN is evaluated using lisp's eval, so the behN behaviors cannot refer to local parameters or local variables. The advantage of this form over seq is that the behaviors are evaluated one-at-a-time which can take much less stack space and overall memory. One special ``behavior'' expression is interpreted directly by timed-seq: (SCORE-BEGIN-END) is ignored, not evaluated as a function. Normally, this special behavior is placed at time 0 and has two parameters: the score start time and the score end time. These are used in Xmusic functions. If the behavior has a :pitch keyword parameter which is a list, the list represents a chord, and the expression is replaced by a set of behaviors, one for each note in the chord. It follows that if :pitch is nil, the behavior represents a rest and is ignored. 7.5. Sound File Input and Output play sound [SAL] (play sound) [LISP] Play the sound through the DAC. Note that play is a command in SAL. In XLISP, it is a function, so the syntax is (play sound), and in SAL, you can call the XLISP function as #play(sound). The play command or function writes a file and plays it. The details of this are system-dependent, but play is defined in the file system.lsp. The variable *default-sf-dir* names a directory into which to save a sound file. Be careful not to call play or sound-play within a function and then invoke that function from another play command. By default, Nyquist will try to normalize sounds using the method named by *autonorm-type*, which is 'lookahead by default. The lookahead method precomputes and buffers *autonorm-max-samples* samples, finds the peak value, and normalizes accordingly. The 'previous method bases the normalization of the current sound on the peak value of the (entire) previous sound. This might be good if you are working with long sounds that start rather softly. See Section 5.3 for more details. If you want precise control over output levels, you should turn this feature off by typing (using SAL syntax): autonorm-off() Reenable the automatic normalization feature by typing: autonorm-on() Play normally produces real-time output. The default is to send audio data to the DAC as it is computed in addition to saving samples in a file. If computation is slower than real-time, output will be choppy, but since the samples end up in a file, you can type (r) to replay the stored sound. Real-time playback can be disabled by (using SAL syntax): sound-off() and reenabled by: sound-on() Disabling real-time playback has no effect on (play-file) or (r). While sounds are playing, typing control-A to Nyquist will push the estimated elapsed audio time onto the head of the list stored in *audio-markers*. Because samples are computed in blocks and because there is latency between sample computation and sample playback, the elapsed time may not be too accurate, and the computed elapsed time may not advance after all samples have been computed but the sound is still playing. play-file(filename) [SAL] (play-file filename) [LISP] Play the contents of a sound file named by filename. The s-read function is used to read the file, and unless filename specifies an absolute path or starts with ``.'', it will be read from *default-sf-dir*. autonorm-on() [SAL] (autonorm-on) [LISP] Enable automatic adjustment of a scale factor applied to sounds computed using the play command. autonorm-off() [SAL] (autonorm-off) [LISP] Disable automatic adjustment of a scale factor applied to sounds computed using the play command. sound-on() [SAL] (sound-on) [LISP] Enable real-time audio output when sound is computed by the the play command. sound-off() [SAL] (sound-off) [LISP] Disable real-time audio output when sound is computed by the the play command. s-save(expression, maxlen, filename, format: format, mode: mode, bits: bits, swap: flag, play: play) [SAL] (s-save expression maxlen filename :format format :mode mode :bits bits :swap flag :play play) [LISP] Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. A FLONUM is returned giving the maximum absolute value of all samples written. (This is useful for normalizing sounds and detecting sample overflow.) If play is not NIL, the sound will be output through the computer's audio output system. (play: [SAL] or :play [LISP] is not implemented on all systems; if it is implemented, and filename is NIL, then this will play the file without also writing a file.) The latency (length of audio buffering) used to play the sound is 0.3s by default, but see snd-set-latency. If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. A header is written according to format, samples are encoded according to mode, using bits bits/sample, and bytes are swapped if flag is not NIL. Defaults for these are *default-sf-format*, *default-sf- mode*, and *default-sf-bits*. The default for flag is NIL. The bits parameter may be 8, 16, or 32. The values for the format and mode options are described below: Format snd-head-none The format is unknown and should be determined by reading the file. snd-head-raw A raw format file has no header. snd-head-AIFF AIFF format header. snd-head-IRCAM IRCAM format header. snd-head-NeXT 1024-byte NeXT/SUN format header followed by IRCAM header ala CMIX. Note that the NeXT/SUN format has a header-length field, so it really is legal to have a large header, even though the normal minimal header is only 24 bytes. The additional space leaves room for maximum amplitudes, which can be used for normalizing floating- point soundfiles, and for other data. Nyquist follows the CMIX convention of placing an IRCAM format header immediately after the NeXT-style header. snd-head-Wave Microsoft Wave format header. snd-head-* See sndfnint.lsp for more formats. Mode snd-mode-adpcm ADPCM mode (not supported). snd-mode-pcm signed binary PCM mode. snd-mode-ulaw 8-bit U-Law mode. snd-mode-alaw 8-bit A-Law mode (not supported). snd-mode-float 32-bit floating point mode. snd-mode-upcm unsigned binary PCM mode. snd-mode-* See sndfnint.lsp for more modes. The defaults for format, mode, and bits are as follows: NeXT and Sun machines: snd-head-NeXT, snd-mode-pcm, 16 SGI and Macintosh machines: snd-head-AIFF, snd-mode-pcm, 16 s-read(filename, time-offset: offset, srate: sr, dur: dur, nchans: chans, format: format, mode: mode, bits: n, swap: flag) [SAL] (s-read filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag) [LISP] Reads a sound from filename. The global *default-sf-dir* applies. If a header is detected, the header is used to determine the format of the file, and header information overrides format information provided by keywords (except for time-offset: and dur:). s-read("mysound.snd", srate: 44100) specifies a sample rate of 44100 hz, but if the file has a header specifying 22050 hz, the resulting sample rate will be 22050. The parameters are: - offset M the amount of time (in seconds) to skip from the beginning of the file. The default is 0.0. - sr M the sample rate of the samples in the file. Default is *default-sf-srate* , which is normally 44100. - dur M the maximum duration in seconds to read. Default is 10000. - chans M the number of channels to read. It is assumed that samples from each channel are interleaved. Default is 1. - format M the header format. See s-save for details. Default is *default-sf-format*, although this parameter is currently ignored. - mode M the sample representation, e.g. PCM or float. See s-save for details. Default is *default-sf-format*. - n M the number of bits per sample. See s-save for details. Default is *default-sf-bits*. - flag M (T or NIL) swap byte order of each sample. Default is NIL. If there is an error, for example if offset is greater than the length of the file, then NIL is returned rather than a sound. Information about the sound is also returned by s-read through *rslt*[Since XLISP does not support multiple value returns, multiple value returns are simulated by having the function assign additional return values in a list to the global variable *rslt*. Since this is a global, it should be inspected or copied immediately after the function return to insure that return values are not overwritten by another function.]. The list assigned to *rslt* is of the form: (format channels mode bits samplerate duration flags byte-offset), which are defined as follows: - format M the header format. See s-save for details. - channels M the number of channels. - mode M the sample representation, e.g. PCM or float. See s-save for details. - bits M the number of bits per sample. - samplerate M the sample rate, expressed as a FLONUM. - duration M the duration of the sound, in seconds. - flags M The values for format, channels, mode, bits, samplerate, and duration are initially just the values passed in as parameters or default values to s-read. If a value is actually read from the sound file header, a flag is set. The flags are: snd-head-format, snd-head-channels, snd-head-mode, snd-head- bits, snd-head-srate, and snd-head-dur. For example, (let ((flags (caddr (cddddr *rslt*)))) (not (zerop (logand flags snd-head-srate)))) tells whether the sample rate was specified in the file. See also sf-info below. - byte-offset M the byte offset into the file of the first sample to be read (this is used by the s-overwrite and s-add-to functions). s-add-to(expression, maxlen, filename [, offset]) [SAL] (s-add-to expression maxlen filename [offset]) [LISP] Evaluates the expression, which should result in a sound or an array of sounds, and adds the result to the given filename. The global *default-sf-dir* applies. A FLONUM is returned, giving the maximum absolute value of all samples written. The sample rate(s) of expression must match those of the file. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. If offset is specified, the new sound is added to the file beginning at an offset from the beginning (in seconds). The file is extended if necessary to accommodate the new addition, but if offset falls outside of the original file, the file is not modified. (If necessary, use s-add-to to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file). s-overwrite(expression, maxlen, filename [, offset]) [SAL] (s-overwrite expression maxlen filename [offset]) [LISP] Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename. The global *default-sf-dir* applies. A FLONUM is returned, giving the maximum absolute value of all samples written. The sample rate(s) of expression must match those of the file. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. If offset is specified, the new sound is written to the file beginning at an offset from the beginning (in seconds). The file is extended if necessary to accommodate the new insert, but if offset falls outside of the original file, the file is not modified. (If necessary, use s-add-to to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file). sf-info(filename) [SAL] (sf-info filename) [LISP] Prints information about a sound file. The parameter filename is a string. The file is assumed to be in *default-sf-dir* (see soundfilename below) unless the filename begins with ``.'' or ``/''. The source for this function is in the runtime and provides an example of how to determine sound file parameters. soundfilename(name) [SAL] (soundfilename name) [LISP] Converts a string name to a soundfile name. If name begins with ``.'' or ``/'', the name is returned without alteration. Otherwise, a path taken from *default-sf-dir* is prepended to name. The s-plot, s-read, and s-save functions all use soundfilename translate filenames. s-plot(sound [, dur, n]) [SAL] (s-plot sound [dur n]) [LISP] Plots sound in a window. This function was designed to run a plot program on a Unix workstation, but now is primarily used with NyquistIDE, which has self-contained plotting. Normally, time/value pairs in ascii are written to points.dat and system-dependent code (or the NyquistIDE program) takes it from there. If the sound is longer than the optional dur (default is 2 seconds), only the first dur seconds are plotted. If there are more than n samples to be plotted, the signal is interpolated to have n samples before plotting. The data file used is *default-plot-file*: *default-plot-file* The file containing the data points, defaults to "points.dat". s-print-tree(sound) [SAL] (s-print-tree sound) [LISP] Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. Identical to snd-print-tree. 7.6. Low-level Functions Nyquist includes many low-level functions that are used to implement the functions and behaviors described in previous sections. For completeness, these functions are described here. Remember that these are low-level functions that are not intended for normal use. Unless you are trying to understand the inner workings of Nyquist, you can skip this section. 7.6.1. Creating Sounds The basic operations that create sounds are described here. snd-const(value, t0, srate, duration) [SAL] (snd-const value t0 srate duration) [LISP] Returns a sound with constant value, starting at t0 with the given duration, at the sample rate srate. You might want to use pwl (see Section 7.2.2.2) instead. snd-read(filename, offset, t0, format, channels, mode, bits, swap, sr, dur) [SAL] (snd-read filename offset t0 format channels mode bits swap sr dur) [LISP] Loads a sound from a file with name filename. Files are assumed to consist of a header followed by frames consisting of one sample from each channel. The format specifies the type of header, but this information is currently ignored. Nyquist looks for a number of header formats and automatically figures out which format to read. If a header can be identified, the header is first read from the file. Then, the file pointer is advanced by the indicated offset (in seconds). If there is an unrecognized header, Nyquist will assume the file has no header. If the header size is a multiple of the frame size (bytes/sample * number-of-channels), you can use offset to skip over the header. To skip N bytes, use an offset of: (/ (float N) sr (/ bits 8) channels) If the header is not a multiple of the frame size, either write a header or contact the author (dannenberg@cs.cmu.edu) for assistance. Nyquist will round offset to the nearest sample. The resulting sound will start at time t0. If a header is found, the file will be interpreted according to the header information. If no header was found, channels tells how many channels there are, the samples are encoded according to mode, the sample length is bits, and sr is the sample rate. The swap flag is 0 or 1, where 1 means to swap sample bytes. The duration to be read (in seconds) is given by dur. If dur is longer than the data in the file, then a shorter duration will be returned. If the file contains one channel, a sound is returned. If the file contains 2 or more channels, an array of sounds is returned. Note: you probably want to call s-read (see Section 7.5) instead of snd-read. Also, see Section 7.5 for information on the mode and format parameters. snd-save(expression, maxlen, filename, format, mode, bits, swap, play) [SAL] (snd-save expression maxlen filename format mode bits swap play) [LISP] Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. A header is written according to format, samples are encoded according to mode, using bits bits/sample, and swapping bytes if swap is 1 (otherwise it should be 0). If play is not null, the audio is played in real time (to the extent possible) as it is computed. The peak value of the sound is returned. In addition, the symbol *RSLT* is bound to a list containing the sample rate, number of channels, and duration (in that order) of the saved sound. Note: you probably want to call s-save (see Section 7.5) instead. The format and mode parameters are described in Section 7.5. snd-overwrite(expression, maxlen, filename, offset, format, mode, bits, swap) [SAL] (snd-overwrite expression maxlen filename offset format mode bits swap) [LISP] Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename, writing the first frame at a time of offset seconds. The offset must be less than or equal to the duration of the existing file. The duration of the written samples may be greater than that of the file, in which case the file is extended as necessary. The sample rate(s) of expression and the number of channels must match those of the file. If format is SND-HEAD-RAW, then the file format is given by mode (see snd-save, bits (per channel), swap (1 means to swap bytes and 0 means write them in the native byte order), and the number of channels and sample rate of the sound returned by evaluating expression. If the file is a known audio file format, format should be SND-HEAD-NONE, and the other parameters are ignored. Up to a maximum of maxlen samples will be written per channel. The peak value of the sound is returned. In addition, the symbol *RSLT* is bound to a list containing the duration of the written sound (which may not be the duration of the sound file). Use s-add-to (in Section 7.5 or s-overwrite (in Section 7.5 instead of this function. snd-coterm(s1, s2) [SAL] (snd-coterm s1 s2) [LISP] Returns a copy of s1, except the start time is the maximum of the start times of s1 and s2, and the termination time is the minimum of s1 and s2. (After the termination time, the sound is zero as if s1 is gated by s2.) Some rationale follows: In order to implement s-add-to, we need to read from the target sound file, add the sounds to a new sound, and overwrite the result back into the file. We only want to write as many samples into the file as there are samples in the new sound. However, if we are adding in samples read from the file, the result of a snd-add in Nyquist will have the maximum duration of either sound. Therefore, we may read to the end of the file. What we need is a way to truncate the read, but we cannot easily do that, because we do not know in advance how long the new sound will be. The solution is to use snd-coterm, which will allow us to truncate the sound that is read from the file (s1) according to the duration of the new sound (s2). When this truncated sound is added to the new sound, the result will have only the duration of the new sound, and this can be used to overwrite the file. This function is used in the implementation of s-add-to, which is defined in runtime/fileio.lsp. (snd-from-array ...) [SAL] (snd-from-array ...) [LISP] See page 17. snd-white(t0, sr, d) [SAL] (snd-white t0 sr d) [LISP] Generate white noise, starting at t0, with sample rate sr, and duration d. You probably want to use noise (see Section 7.2.2.6). snd-zero(t0, srate) [SAL] (snd-zero t0 srate) [LISP] Creates a sound that is zero everywhere, starts at t0, and has sample rate srate. The logical stop time is immediate, i.e. also at t0. You probably want to use pwl (see Section 7.2.2.2) instead. get-slider-value(index) [SAL] (get-slider-value index) [LISP] Return the current value of the slider named by index (an integer index into the array of sliders). Note that this ``slider'' is just a floating point value in an array. Sliders can be changed by OSC messages (see osc-enable) and by sending character sequences to Nyquist's standard input. (Normally, these character sequences would not be typed but generated by the NyquistIDE interactive development environment, which runs Nyquist as a sub-process, and which present the user with graphical sliders.) snd-slider(index, t0, srate, duration) [SAL] (snd-slider index t0 srate duration) [LISP] Create a sound controlled by the slider named by index (an integer index into the array of sliders; see get-slider-value for more information). The function returns a sound. Since Nyquist sounds are computed in blocks of samples, and each block is computed at once, each block will contain copies of the current slider value. To obtain reasonable responsiveness, slider sounds should have high (audio) sample rates so that the block rate will be reasonably high. Also, consider lowering the audio latency using snd-set-latency. To ``trigger'' a Nyquist behavior using slider input, see the trigger function in Section 7.4. 7.6.2. Signal Operations This next set of functions take sounds as arguments, operate on them, and return a sound. snd-abs(sound) [SAL] (snd-abs sound) [LISP] Computes a new sound where each sample is the absolute value of the corresponding sample in sound. You should probably use s-abs instead. (See Section 7.2.2.6.) snd-sqrt(sound) [SAL] (snd-sqrt sound) [LISP] Computes a new sound where each sample is the square root of the corresponding sample in sound. If a sample is negative, it is taken to be zero to avoid raising a floating point error. You should probably use s-sqrt instead. (See Section 7.2.2.6.) snd-add(sound1, sound) [SAL] (snd-add sound1 sound) [LISP] Adds two sounds. The resulting start time is the minimum of the two parameter start times, the logical stop time is the maximum of the two parameter stop times, and the sample rate is the maximum of the two parameter sample rates. Use sim or sum instead of snd-add (see Section 7.4). snd-offset(sound, offset) [SAL] (snd-offset sound offset) [LISP] Add an offset to a sound. The resulting start time, logical stop time, stop time, and sample rate are those of sound. Use sum instead (see Section 7.4). snd-avg(sound, blocksize, stepsize, operation) [SAL] (snd-avg sound blocksize stepsize operation) [LISP] Computes the averages or peak values of blocks of samples. Each output sample is an average or peak of blocksize (a fixnum) adjacent samples from the input sound. After each average or peak is taken, the input is advanced by stepsize, a fixnum which may be greater or less than blocksize. The output sample rate is the sound (input) sample rate divided by stepsize. This function is useful for computing low-sample-rate rms or peak amplitude signals for input to snd-gate or snd-follow. To select the operation, operation should be one of OP-AVERAGE or OP-PEAK. (These are global lisp variables; the actual operation parameter is an integer.) For RMS computation, see rms in Section 7.2.2.6. snd-clip(sound, peak) [SAL] (snd-clip sound peak) [LISP] Hard limit sound to the given peak, a positive number. The samples of sound are constrained between an upper value of peak and a lower value of N()peak. Use clip instead (see Section 7.2.2.6). snd-compose(f, g) [SAL] (snd-compose f g) [LISP] Compose two signals, i.e. compute f(g(t)), where f and g are sounds. This function is used primarily to implement time warping, but it can be used in other applications such as frequency modulation. For each sample x in g, snd-compose looks up the value of f(x) using linear interpolation. The resulting sample rate, start time, etc. are taken from g. The sound f is used in effect as a lookup table, but it is assumed that g is non-decreasing, so that f is accessed in time order. This allows samples of f to be computed and discarded incrementally. If in fact g decreases, the current sample of g is replaced by the previous one, forcing g into compliance with the non-decreasing restriction. See also sref, shape, and snd-resample. For an extended example that uses snd-compose for variable pitch shifting, see demos/pitch_change.htm. snd-tapv(sound, offset, vardelay, maxdelay) [SAL] (snd-tapv sound offset vardelay maxdelay) [LISP] A variable delay: sound is delayed by the sum of offset (a FIXNUM or FLONUM) and vardelay (a SOUND). The specified delay is adjusted to lie in the range of zero to maxdelay seconds to yield the actual delay, and the delay is implemented using linear interpolation. This function was designed specifically for use in a chorus effect: the offset is set to half of maxdelay, and the vardelay input is a slow sinusoid. The maximum delay is limited to maxdelay, which determines the length of a fixed-sized buffer. The function tapv is equivalent and preferred (see Section 7.2.2.3). snd-tapf(sound, offset, vardelay, maxdelay) [SAL] (snd-tapf sound offset vardelay maxdelay) [LISP] A variable delay like snd-tapv except there is no linear interpolation. By eliminating interpolation, the output is an exact copy of the input with no filtering or distortion. On the other hand, delays jump by samples causing samples to double or skip even when the delay is changed smoothly. snd-copy(sound) [SAL] (snd-copy sound) [LISP] Makes a copy of sound. Since operators always make (logical) copies of their sound parameters, this function should never be needed. This function is here for debugging. snd-down(srate, sound) [SAL] (snd-down srate sound) [LISP] Linear interpolation of samples down to the given sample rate srate, which must be lower than the sample rate of sound. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call force-srate (see Section 7.2.2). snd-exp(sound) [SAL] (snd-exp sound) [LISP] Compute the exponential of each sample of sound. Use s-exp instead (see Section 7.2.2.6). snd-follow(sound, floor, risetime, falltime, lookahead) [SAL] (snd-follow sound floor risetime falltime lookahead) [LISP] An envelope follower. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The floor is the minimum output value. The risetime is the time (in seconds) it takes for the output to rise (exponentially) from floor to unity (1.0) and the falltime is the time it takes for the output to fall (exponentially) from unity to floor. The algorithm looks ahead for peaks and will begin to increase the output signal according to risetime in anticipation of a peak. The amount of anticipation (in sampless) is given by lookahead. The algorithm is as follows: the output value is allowed to increase according to risetime or decrease according to falltime. If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to risetime to meet the new value. The algorithm will only work backward as far as lookahead. If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by falltime, the output fall rate will be limited by falltime, and the fall in output will stop when the output reaches floor. This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See snd-avg above for a function that can help to generate a low-sample-rate input for snd-follow. See snd-chase in Section 7.6.3 for a related filter. snd-gate(sound, lookahead, risetime, falltime, floor, threshold) [SAL] (snd-gate sound lookahead risetime falltime floor threshold) [LISP] This function generates an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to unity (1.0) at the point the signal crosses the threshold. Again, look-ahead is used, so the rise actually starts before the signal crosses the threshold. The rise is a constant-rate exponential and set so that a rise from floor to unity occurs in risetime. Similarly, the fall is a constant-rate exponential such that a fall from unity to floor takes falltime. The result is delayed by lookahead, so the output is not actually synchronized with the input. To compensate, you should drop the initial lookahead of samples. Thus, snd-gate is not recommended for direct use. Use gate instead (see Section 7.1.4). snd-inverse(signal, start, srate) [SAL] (snd-inverse signal start srate) [LISP] Compute the function inverse of signal, that is, compute g(t) such that signal(g(t)) = t. This function assumes that signal is non-decreasing, it uses linear interpolation, the resulting sample rate is srate, and the result is shifted to have a starting time of start. If signal decreases, the true inverse may be undefined, so we define snd-inverse operationally as follows: for each output time point t, scan ahead in signal until the value of signal exceeds t. Interpolate to find an exact time point x from signal and output x at time t. This function is intended for internal system use in implementing time warps. snd-log(sound) [SAL] (snd-log sound) [LISP] Compute the natural logorithm of each sample of sound. Use s-log instead (see Section 7.2.2.6). peak(expression, maxlen) [SAL] (peak expression maxlen) [LISP] Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating expression (as in s-save). Only the first maxlen samples are evaluated. The expression is automatically quoted (peak is a macro), so do not quote this parameter. If expression is a variable, then the global binding of that variable will be used. Also, since the variable retains a reference to the sound, the sound will be evaluated and left in memory. See Section 5.3 on page 10 for examples. snd-max(expression, maxlen) [SAL] (snd-max expression maxlen) [LISP] Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating expression (as in snd-save), which is therefore normally quoted by the caller. At most maxlen samples are computed. The result is the maximum of the absolute values of the samples. Notes: It is recommended to use peak (see above) instead. If you want to find the maximum of a sound bound to a local variable and it is acceptable to save the samples in memory, then this is probably the function to call. Otherwise, use peak. snd-maxv(sound1, sound2) [SAL] (snd-maxv sound1 sound2) [LISP] Compute the maximum of sound1 and sound2 on a sample-by-sample basis. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. The physical stop time is the minimum of the physical stop times of the two sounds. Note that this violates the ``normal'' interpretation that sounds are zero outside their start and stop times. For example, even if sound1 extends beyond sound2 and is greater than zero, the result value in this extension will be zero because it will be after the physical stop time, whereas if we simply treated sound2 as zero in this region and took the maximum, we would get a non-zero result. Use s-max instead (see Section 7.2.2.6). snd-normalize(sound) [SAL] (snd-normalize sound) [LISP] Internally, sounds are stored with a scale factor that applies to all samples of the sound. All operators that take sound arguments take this scale factor into account (although it is not always necessary to perform an actual multiply per sample), so you should never need to call this function. This function multiplies each sample of a sound by its scale factor, returning a sound that represents the same signal, but whose scale factor is 1.0. snd-oneshot(sound, threshold, ontime) [SAL] (snd-oneshot sound threshold ontime) [LISP] Computes a new sound that is zero except where sound exceeds threshold. From these points, the result is 1.0 until sound remains below threshold for ontime (in seconds). The result has the same sample rate, start time, logical stop time, and duration as sound. snd-prod(sound1, sound2) [SAL] (snd-prod sound1 sound2) [LISP] Computes the product of sound1 and sound2. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. Do not use this function. Use mult or prod instead (see Section 7.2.2). Sample rate, start time, etc. are taken from sound. snd-pwl(t0, sr, lis) [SAL] (snd-pwl t0 sr lis) [LISP] Computes a piece-wise linear function according to the breakpoints in lis. The starting time is t0, and the sample rate is sr. The breakpoints are passed in an XLISP list (of type LVAL) where the list alternates sample numbers (FIXNUMs, computed in samples from the beginning of the pwl function) and values (the value of the pwl function, given as a FLONUM). There is an implicit starting point of (0, 0). The list must contain an odd number of points, the omitted last value being implicitly zero (0). The list is assumed to be well-formed. Do not call this function. Use pwl instead (see Section 7.2.2.2). snd-quantize(sound, steps) [SAL] (snd-quantize sound steps) [LISP] Quantizes a sound. See Section 7.2.2.6 for details. snd-recip(sound) [SAL] (snd-recip sound) [LISP] Compute the reciprocal of each sample of sound. Use recip instead (see Section 7.2.2.6). snd-resample(f, rate) [SAL] (snd-resample f rate) [LISP] Resample sound f using high-quality interpolation, yielding a new sound with the specified rate. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. The resulting start time, etc. are taken from f. Use resample instead. snd-resamplev(f, rate, g) [SAL] (snd-resamplev f rate g) [LISP] Compose two signals, i.e. compute f(g(t)), where f and g are sounds. The result has sample rate given by rate. At each time t (according to the rate), g is linearly interpolated to yield an increasing sequence of high-precision score-time values. f is then interpolated at each value to yield a result sample. If in fact g decreases, the current sample of g is replaced by the previous one, forcing g into compliance with the non-decreasing restriction. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. Note that if g has a high sample rate, this may introduce unwanted jitter into sample times. See sound-warp for a detailed discussion. See snd-compose for a fast, low-quality alternative to this function. Normally, you should use sound-warp instead of this function. snd-scale(scale, sound) [SAL] (snd-scale scale sound) [LISP] Scales the amplitude of sound by the factor scale. Use scale instead (see Section 7.2.2). snd-shape(signal, table, origin) [SAL] (snd-shape signal table origin) [LISP] A waveshaping function. This is the primitive upon which shape is based. The snd-shape function is like shape except that signal and table must be (single-channel) sounds. Use shape instead (see Section 7.2.2.3). snd-up(srate, sound) [SAL] (snd-up srate sound) [LISP] Increases sample rate by linear interpolation. The sound is the signal to be up-sampled, and srate is the output sample rate. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call force-srate (see Section 7.2.2). snd-xform(sound, sr, time, start, stop, scale) [SAL] (snd-xform sound sr time start stop scale) [LISP] Makes a copy of sound and then alters it in the following order: (1) the start time (snd-t0) of the sound is shifted to time, (1) the sound is stretched as a result of setting the sample rate to sr (the start time is unchanged by this), (3) the sound is clipped from start to stop, (4) if start is greater than time, the sound is shifted shifted by time - start, so that the start time is time, (5) the sound is scaled by scale. An empty (zero) sound at time will be returned if all samples are clipped. Normally, you should accomplish all this using transformations. A transformation applied to a sound has no effect, so use cue to create a transformable sound (see Section 7.2.1). snd-yin(sound, minstep, maxstep, rate) [SAL] (snd-yin sound minstep maxstep rate) [LISP] Identical to yin. See Section 7.2.2.6. 7.6.3. Filters These are also ``Signal Operators,'' the subject of the previous section, but there are so many filter functions, they are documented in this special section. Some filters allow time-varying filter parameters. In these functions, filter coefficients are calculated at the sample rate of the filter parameter, and coefficients are not interpolated. snd-alpass(sound, delay, feedback) [SAL] (snd-alpass sound delay feedback) [LISP] An all-pass filter. This produces a repeating echo effect without the resonances of snd-delay. The feedback should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use alpass instead (see Section 7.2.2.3). snd-alpasscv(sound, delay, feedback) [SAL] (snd-alpasscv sound delay feedback) [LISP] An all-pass filter with variable feedback. This is just like snd-alpass except feedback is a sound. You should use alpass instead (see Section 7.2.2.3). snd-alpassvv(sound, delay, feedback, maxdelay) [SAL] (snd-alpassvv sound delay feedback maxdelay) [LISP] An all-pass filter with variable feedback and delay. This is just like snd-alpass except feedback and delay are sounds, and there is an additional FLONUM parameter, maxdelay, that gives an upper bound on the value of delay. Note: delay must remain between zero and maxdelay. If not, results are undefined, and Nyquist may crash. You should use alpass instead (see Section 7.2.2.3). snd-areson(sound, hz, bw, normalization) [SAL] (snd-areson sound hz bw normalization) [LISP] A notch filter modeled after the areson unit generator in Csound. The snd-areson filter is an exact complement of snd-reson such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. Note that because of this complementary design, the power is not normalized as in snd-reson. See snd-reson for details on normalization. You should use areson instead (see Section 7.2.2.3). snd-aresoncv(sound, hz, bw, normalization) [SAL] (snd-aresoncv sound hz bw normalization) [LISP] This function is identical to snd-areson except the bw (bandwidth) parameter is a sound. Filter coefficients are updated at the sample rate of bw. The ``cv'' suffix stands for Constant, Variable, indicating that hz and bw are constant (a number) and variable (a sound), respectively. This naming convention is used throughout. You should use areson instead (see Section 7.2.2.3). snd-aresonvc(sound, hz, bw, normalization) [SAL] (snd-aresonvc sound hz bw normalization) [LISP] This function is identical to snd-areson except the hz (center frequency) parameter is a sound. Filter coefficients are updated at the sample rate of hz. You should use areson instead (see Section 7.2.2.3). snd-aresonvv(sound, hz, bw, normalization) [SAL] (snd-aresonvv sound hz bw normalization) [LISP] This function is identical to snd-areson except both hz (center frequency) and bw (bandwidth) are sounds. Filter coefficients are updated at the next sample of either hz or bw. You should use areson instead (see Section 7.2.2.3). snd-atone(sound, hz) [SAL] (snd-atone sound hz) [LISP] A high-pass filter modeled after the atone unit generator in Csound. The snd-atone filter is an exact complement of snd-tone such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. You should use hp instead (see Section 7.2.2.3). snd-atonev(sound, hz) [SAL] (snd-atonev sound hz) [LISP] This is just like snd-atone except that the hz cutoff frequency is a sound. Filter coefficients are updated at the sample rate of hz. You should use hp instead (see Section 7.2.2.3). snd-biquad(sound, b0, b1, b2, a1, a2, z1init, z2init) [SAL] (snd-biquad sound b0 b1 b2 a1 a2 z1init z2init) [LISP] A general second order IIR filter, where a0 is assumed to be unity. For a1 and a2, the sign convention is opposite to that of Matlab. All parameters except the input sound are of type FLONUM. You should probably use one of lowpass2, highpass2, bandpass2, notch2, allpass2, eq-lowshelf, eq- highshelf, eq-band, lowpass4, lowpass6, lowpass8, highpass4, highpass6, or highpass8, which are all based on snd-biquad and described in Section 7.2.2.3. For completeness, you will also find biquad and biquad-m described in that section. snd-chase(sound, risetime, falltime) [SAL] (snd-chase sound risetime falltime) [LISP] A slew rate limiter. The output ``chases'' the input at rates determined by risetime and falltime. If the input changes too fast, the output will lag behind the input. This is a form of lowpass filter, but it was created to turn hard-switching square waves into smoother control signals that could be used for linear crossfades. If the input switches from 0 to 1, the output will linearly rise to 1 in risetime seconds. If the input switches from 1 to 0, the output will linearly fall to 0 in falltime seconds. The generated slope is constant; the transition is linear; this is not an exponential rise or fall. The risetime and falltime must be scalar constants; complain to the author if this is not adequate. The snd-chase function is safe for ordinary use. See snd-follow in Section 7.6.2 for a related function. snd-congen(gate, risetime, falltime) [SAL] (snd-congen gate risetime falltime) [LISP] A simple ``contour generator'' based on analog synthesizers. The gate is a sound that normally steps from 0.0 to 1.0 at the start of an envelop and goes from 1.0 back to 0.0 at the beginning of the release. At each sample, the output converges to the input exponentially. If gate is greater than the output, e.g. the attack, then the output converges half-way to the output in risetime. If the gate is less than the output, the half-time is falltime. The sample rate, starting time, logical-stop-time, and terminate time are taken from gate. You should use congen instead (see Section 7.2.2.3. snd-convolve(sound, response) [SAL] (snd-convolve sound response) [LISP] Convolves sound by response using a simple O(N x M) algorithm. The sound can be any length, but the response is computed and stored in a table. The required compuation time per sample and total space are proportional to the length of response. Use convolve instead (see Section 7.2.2.3). snd-delay(sound, delay, feedback) [SAL] (snd-delay sound delay feedback) [LISP] Feedback delay. The output, initially sound, is recursively delayed by delay, scaled by feedback, and added to itself, producing an repeating echo effect. The feedback should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use feedback-delay instead (see Section 7.2.2.3) snd-delaycv(sound, delay, feedback) [SAL] (snd-delaycv sound delay feedback) [LISP] Feedback delay with variable feedback. This is just like snd-delay except feedback is a sound. You should use feedback-delay instead (see Section 7.2.2.3). snd-reson(sound, hz, bw, normalization) [SAL] (snd-reson sound hz bw normalization) [LISP] A second-order resonating (bandpass) filter with center frequency hz and bandwidth bw, modeled after the reson unit generator in Csound. The normalization parameter must be an integer and (like in Csound) specifies a scaling factor. A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than hz are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The result sample rate, start time, etc. are takend from sound. You should use reson instead (see Section 7.2.2.3). snd-resoncv(sound, hz, bw, normalization) [SAL] (snd-resoncv sound hz bw normalization) [LISP] This function is identical to snd-reson except bw (bandwidth) is a sound. Filter coefficients are updated at the sample rate of bw. You should use reson instead (see Section 7.2.2.3). snd-resonvc(sound, hz, bw, normalization) [SAL] (snd-resonvc sound hz bw normalization) [LISP] This function is identical to snd-reson except hz (center frequency) is a sound. Filter coefficients are updated at the sample rate of hz. You should use reson instead (see Section 7.2.2.3). snd-resonvv(sound, hz, bw, normalization) [SAL] (snd-resonvv sound hz bw normalization) [LISP] This function is identical to snd-reson except botth hz (center frequency) and bw (bandwidth) are sounds. Filter coefficients are updated at the next sample from either hz or bw. You should use reson instead (see Section 7.2.2.3). snd-stkchorus(sound, delay, depth, freq, mix, sr) [SAL] (snd-stkchorus sound delay depth freq mix sr) [LISP] A chorus implemented in STK. The parameter delay is a FIXNUM representing the median desired delay length in samples. A typical value is 6000. The FLONUM parameters depth and freq set the modulation depth (from 0 to 1) and modulation frequency (in Hz), mix sets the mixture of input sound and chorused sound, where a value of 0.0 means input sound only (dry) and a value of 1.0 means chorused sound only (wet). The parameter sr is the desired sample rate of the resulting sound[This is probably a mistake since sample rate is implied by sound. This parameter may be removed in a future release.] You should use pitshift instead (see Section 7.2.2.4). snd-stkpitshift(sound, shift, mix, sr) [SAL] (snd-stkpitshift sound shift mix sr) [LISP] A pitch shifter implemented in STK. The sound is shifted in pitch by shift, a FLONUM representing the shift factor. A value of 1.0 means no shift. The parameter mix sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). The sr is the desired sampling frequency.[This is probably a mistake since sample rate is implied by sound. This parameter may be removed in a future release.] You should use pitshift instead (see Section 7.2.2.4). snd-stkrev(rev-type, sound, decay, mix, sr) [SAL] (snd-stkrev rev-type sound decay mix sr) [LISP] A reverb implemented in STK. The parameter rev-type is a FIXNUM ranging from zero to two and selects the type of reverb. Zero selects NRev type, one selects JCRev, and two selects PRCRev. The input sound is processed by the reverb with a decay time in seconds (a FLONUM). The mix, a FLONUM, sets the mixture of dry input and reverb output. A value of 0.0 means input only (dry) and a value of 1.0 means reverb only (wet). The sample rate is sr[This is probably a mistake since sample rate is implied by sound. This parameter may be removed in a future release.] You should use nrev, jcrev or prcrev instead (see Section 7.2.2.4). snd-tone(sound, hz) [SAL] (snd-tone sound hz) [LISP] A first-order recursive low-pass filter, based on the tone unit generator of Csound. The hz parameter is the cutoff frequency, the response curve's half-power point. The result sample rate, start time, etc. are takend from sound. You should use lp instead (see Section 7.2.2.3). snd-tonev(sound, hz) [SAL] (snd-tonev sound hz) [LISP] This function is identical to snd-tone except hz (cutoff frequency) is a sound. The filter coefficients are updated at the sample rate of hz. You should use lp instead (see Section 7.2.2.3). 7.6.4. Table-Lookup Oscillator Functions These functions all use a sound to describe one period of a periodic waveform. In the current implementation, the sound samples are copied to an array (the waveform table) when the function is called. To make a table-lookup oscillator generate a specific pitch, we need to have several pieces of information: - A waveform to put into the table. This comes from the sound parameter. - The length (in samples) of the waveform. This is obtained by reading samples (starting at the sound's start time, not necessarily at time zero) until the physical stop time of the sound. (If you read the waveform from a file or generate it with functions like sim and sine, then the physical and logical stop times will be the same and will correspond to the duration you specified, rounded to the nearest sample.) - The intrinsic sample rate of the waveform. This sample rate is simply the sample rate property of sound. - The pitch of the waveform. This is supplied by the step parameter and indicates the pitch (in steps) of sound. You might expect that the pitch would be related to the period (length) of sound, but there is the interesting case that synthesis based on sampling often loops over multiple periods. This means that the fundamental frequency of a generated tone may be some multiple of the looping rate. In Nyquist, you always specify the perceived pitch of the looped sound if the sound is played at the sound's own sample rate. - The desired pitch. This is specified by the hz parameter in Hertz (cycles per second) in these low-level functions. Note that this is not necessarily the ``loop'' rate at which the table is scanned. Instead, Nyquist figures what sample rate conversion would be necessary to ``transpose'' from the step which specifies the original pitch of sound to hz, which gives the desired pitch. The mixed use of steps and Hertz came about because it seemed that sample tables would be tagged with steps (``I sampled a middle-C''), whereas frequency deviation in the fmosc function is linear, thus calling for a specification in Hertz. - The desired sample rate. This is given by the sr parameter in Hertz. Other parameters common to all of these oscillator functions are: - t0, the starting time, and - phase, the starting phase in degrees. Note that if the step parameter indicates that the table holds more than one fundamental period, then a starting phase of 360 will be different than a starting phase of 0. snd-amosc(sound, step, sr, hz, t0, am, phase) [SAL] (snd-amosc sound step sr hz t0 am phase) [LISP] An oscillator with amplitude modulation. The sound am specifies the amplitude and the logical stop time. The physical stop time is also that of am. You should use amosc instead (see Section 7.2.2.1). snd-fmosc(s, step, sr, hz, t0, fm, phase) [SAL] (snd-fmosc s step sr hz t0 fm phase) [LISP] A Frequency Modulation oscillator. The sound fm specifies frequency deviation (in Hertz) from hz. You should use fmosc instead (see Section 7.2.2.1). snd-fmfb(t0, hz, sr, index, dur) [SAL] (snd-fmfb t0 hz sr index dur) [LISP] A Feedback FM oscillator. The resulting sound starts at t0, has a fundamental frequency of hz, a sample rate of sr, and a duration of dur seconds. The index is a FLONUM that specifies the amount of feedback. You should use fmfb instead (see Section 7.2.2.1). snd-fmfbv(t0, hz, sr, index) (snd-fmfv t0 hz sr index) [LISP] A Feedback FM oscillator. The resulting sound starts at t0, has a fundamental frequency of hz, and a sample rate of sr. The index is a SOUND that specifies the amount of feedback and determines the duration. You should use fmfb instead (see Section 7.2.2.1). snd-buzz(n, sr, hz, t0, fm) [SAL] (snd-buzz n sr hz t0 fm) [LISP] A buzz oscillator, which generates n harmonics of equal amplitude. The fm specifies frequency deviation (in Hertz) from hz. You should use buzz instead (see Section 7.2.2.1). snd-pluck(sr, hz, t0, d, final-amp) [SAL] (snd-pluck sr hz t0 d final-amp) [LISP] A Karplus-Strong plucked string oscillator with sample rate sr, fundamental frequency hz, starting time t0, duration d, initial amplitude approximately 1.0 (not exact because the string is initialized with random values) and final amplitude approximately final-amp. You should use pluck instead (see Section 7.2.2.1). snd-osc(s, step, sr, hz, t0, d, phase) [SAL] (snd-osc s step sr hz t0 d phase) [LISP] A simple table lookup oscillator with fixed frequency. The duration is d seconds. You should use osc instead (see Section 7.2.2.1). snd-partial(sr, hz, t0, env) [SAL] (snd-partial sr hz t0 env) [LISP] This is a special case of snd-amosc that generates a sinusoid starting at phase 0 degrees. The env parameter gives the envelope or any other amplitude modulation. You should use partial instead (see Section 7.2.2.1). snd-sine(t0, hz, sr, d) [SAL] (snd-sine t0 hz sr d) [LISP] This is a special case of snd-osc that always generates a sinusoid with initial phase of 0 degrees. You should use sine instead (see Section 7.2.2.1). snd-siosc(tables, sr, hz, t0, fm) [SAL] (snd-siosc tables sr hz t0 fm) [LISP] A Spectral Interpolation Oscillator with frequency modulation. The tables is a list of sounds and sample counts as follows: (table0 count1 table1 ... countN tableN). The initial waveform is given by table0, which is interpolated linearly to table1 over the first count1 samples. From count1 to count2 samples, the waveform is interpolated from table1 to table2, and so on. If more than countN samples are generated, tableN is used for the remainder of the sound. The duration and logical stop time of the sound is taken from fm, which specified frequency modulation (deviation) in Hertz. You should use siosc instead (see Section 7.2.2.1). 7.6.5. Physical Model Functions These functions perform some sort of physically-based modeling synthesis. (snd-bandedwg freq bowpress-env preset sr) (snd-bandedwg freq bowpress-env preset sr) [LISP] A Banded Wave Guide Percussion instrument implemented in STK. The parameter freq is a FLONUM in Hz, bowpress-env is a SOUND that ranges from zero to one, preset is a FIXNUM, and sr is the desired sample rate in Hz. Currently, there are four presets: uniform-bar (0), tuned-bar (1), glass-harmonica (2), and tibetan-bowl (3). You should use wg-uniform-bar, wg-tuned-bar, wg-glass-harm, or wg-tibetan-bowl instead (see Section 7.2.2.5). snd-bowed(freq, bowpress-env, sr) [SAL] (snd-bowed freq bowpress-env sr) [LISP] A bowed string instrument implemented in STK. The freq is a FLONUM in Hertz, bowpress-env is a SOUND that ranges from z ero to one, and sr is the desired sample rate (a FLONUM). You should use bowed instead (see Section 7.2.2.5). snd-bowed-freq(freq, bowpress-env, freq-env, sr) [SAL] (snd-bowed-freq freq bowpress-env freq-env sr) [LISP] A bowed model just like snd-bowed but with an additional parameter for continuous frequency control. You should use bowed-freq instead (see Section 7.2.2.5). snd-clarinet(freq, breath-env, sr) [SAL] (snd-clarinet freq breath-env sr) [LISP] A clarinet model implemented in STK. The freq is a FLONUM in Hertz, breath-env is a SOUND that ranges from zero to one, and sr is the desired sample rate (a FLONUM). You should use clarinet instead (see Section 7.2.2.5). snd-clarinet-freq(freq, breath-env, freq-env, sr) [SAL] (snd-clarinet-freq freq breath-env freq-env sr) [LISP] A clarinet model just like snd-clarinet but with an additional parameter for continuous frequency control. You should use clarinet-freq instead (see Section 7.2.2.5). snd-clarinet-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, reed-stiffness, noise, sr) [SAL] (snd-clarinet-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise sr) [LISP] A clarinet model just like snd-clarinet-freq but with additional parameters for vibrato generation and continuous control of reed stiffness and breath noise. You should use clarinet-all instead (see Section 7.2.2.5). snd-flute(freq, breath-env, sr) [SAL] (snd-flute freq breath-env sr) [LISP] A flute implemented in STK. The freq is a FLONUM in Hertz, breath-env is a SOUND that ranges from zero to one, and sr is the desired sample rate (a FLONUM). You should use flute instead (see Section 7.2.2.5). snd-flute-freq(freq, breath-env, freq-env, sr) [SAL] (snd-flute-freq freq breath-env freq-env sr) [LISP] A flute model just like snd-flute but with an additional parameter for continuous frequency control. You should use flute-freq instead (see Section 7.2.2.5). snd-flute-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, jet-delay, noise, sr) [SAL] (snd-flute-all freq vibrato-freq vibrato-gain freq-env breath-env jet-delay noise sr) [LISP] A flute model just like snd-flute-freq but with additional parameters for vibrato generation and continuous control of breath noise. You should use flute-all instead (see Section 7.2.2.5). snd-mandolin(t0, freq, dur, body-size, detune, sr) [SAL] (snd-mandolin t0 freq dur body-size detune sr) [LISP] A plucked double-string instrument model implemented in STK. The t0 parameter is the starting time (in seconds), freq is a FLONUM in Hz, body-size and detune are FLONUMs, and sr is the desired sample rate. You should use mandolin instead (see Section 7.2.2.5). snd-modalbar(t0, freq, preset, dur, sr) [SAL] (snd-modalbar t0 freq preset dur sr) [LISP] Struck bar instrument model implemented in STK. The parameter t0 is the starting time (in seconds), freq is a FLONUM in Hz, preset is a FIXNUM ranging from 0 to 8, dur is a FLONUM that sets the duration (in seconds) and sr is the desired sample rate. You should use modalbar instead (see Section 7.2.2.5). snd-sax(freq, breath-env, sr) [SAL] (snd-sax freq breath-env sr) [LISP] A sax model implemented in STK. The freq is a FLONUM in Hertz, breath-env is a SOUND that ranges from zero to one, and sr is the desired sample rate (a FLONUM). You should use sax instead (see Section 7.2.2.5). snd-sax-freq(freq, freq-env, breath-env, sr) [SAL] (snd-sax-freq freq freq-env breath-env sr) [LISP] A sax model just like snd-sax but with an additional parameter for continuous frequency control. You should use sax-freq instead (see Section 7.2.2.5). snd-sax-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, reed-stiffness, noise, blow-pos, reed-table-offset, sr) [SAL] (snd-sax-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise blow-pos reed-table-offset sr) [LISP] A sax model just like snd-sax-freq but with additional parameters for vibrato generation and continuous control of reed stiffness, breath noise, excitation position, and reed table offset. You should use sax-all instead (see Section 7.2.2.5). snd-sitar(t0, freq, dur, sr) [SAL] (snd-sitar t0 freq dur sr) [LISP] A sitar model implemented in STK. The parameter t0 is the starting time, freq is a FLONUM (in Hz), E dur sets the duration and sr is the sample rate (in Hz) of the resulting sound. You should use sitar instead (see Section 7.2.2.5). 7.6.6. Sequence Support Functions The next two functions are used to implement Nyquist's seq construct. snd-seq(sound, closure) [SAL] (snd-seq sound closure) [LISP] This function returns sound until the logical stop time of sound. Then, the XLISP closure is evaluated, passing it the logical stop time of sound as a parameter. The closure must return a sound, which is then added to sound. (An add is used so that sound can continue past its logical stop if desired.) Do not call this function. See seq in Section 7.4. snd-multiseq(array, closure) [SAL] (snd-multiseq array closure) [LISP] This function is similar to snd-seq except the first parameter is a multichannel sound rather than a single sound. A multichannel sound is simply an XLISP array of sounds. An array of sounds is returned which is the sum of array and another array of sounds returned by closure. The closure is passed the logical stop time of the multichannel sound, which is the maximum logical stop time of any element of array. Do not call this function. See seq in Section 7.4. snd-trigger(s, closure) [SAL] (snd-trigger s closure) [LISP] This is one of the only ways in which a behavior instance can be created by changes in a signal. When s (a SOUND) makes a transition from less than or equal to zero to greater than zero, the closure, which takes a starting time parameter, is evaluated. The closure must return a SOUND. The sum of all these sounds is returned. If there are no sounds, the result will be zero. The stop time of the result is the maximum stop time of s and all sounds returned by the closure. The sample rate of the return value is the sample rate of s, and the sounds returned by the closure must all have that same sample rate. Do not call this function. See trigger in Section 7.4. An implementation note: There is no way to have snd-trigger return a multichannel sound. An alternative implementation would be a built-in function to scan ahead in a sound to find the time of the next zero crossing. This could be combined with some LISP code similar to seq to sum up instances of the closure. However, this would force arbitrary look-ahead and therefore would not work with real-time inputs, which was the motivation for snd-trigger in the first place. 8. Nyquist Globals There are many global variables in Nyquist. A convention in Lisp is to place asterisks (*) around global variables, e.g. *table*. This is only a convention, and the asterisks are just like any other letter as far as variable names are concerned. Here are some globals users should know about: *table* Default table used by osc and other oscillators. *A4-Hertz* Frequency of A4 in Hertz.. Note: you must call (set-pitch-names) to recompute pitches after changing *A4-Hertz*. *autonorm* The normalization factor to be applied to the next sound when *autonorm-type* is 'previous. See Sections 5.3 and 7.5. *autonormflag* Enables the automatic normalization feature of the play command. You should use (autonorm-on) and (autonorm-off) rather than setting *autonormflag* directly. See Sections 5.3 and 7.5. *autonorm-max-samples* Specifies how many samples will be computed searching for a peak value when *autonorm-type* is 'lookahead. See Sections 5.3 and 7.5. *autonorm-previous-peak* The peak of the previous sound generated by play. This is used to compute the scale factor for the next sound when *autonorm-type* is 'previous. See Sections 5.3 and 7.5. *autonorm-target* The target peak amplitude for the autonorm feature. The default value is 0.9. See Sections 5.3 and 7.5. *autonorm-type* Determines how the autonorm feature is implemented. Valid values are 'lookahead (the default) and 'previous. See Sections 5.3 and 7.5. *breakenable* Controls whether XLISP enters a break loop when an error is encountered. See Section IV.14. *control-srate* Part of the environment, establishes the control sample rate. See Section 3.1 for details. *default-sf-bits* The default bits-per-sample for sound files. Typically 16. *default-sf-dir* The default sound file directory. Unless you give a full path for a file, audio files are assumed to be in this directory. (Applies to many functions that deal with sound files. Check the function description to see if *default-sf-dir* applies.) *default-sf-format* The default sound file format. When you write a file, this will be the default format: AIFF for Mac and most Unix systems, NeXT for NeXT systems, and WAV for Win32. *default-sf-srate* The default sample rate for sound files. Typically 44100.0, but often set to 22050.0 for speed in non-critical tasks. *default-control-srate* Default value for *control-srate*. This value is restored when you execute (top) to pop out of a debugging session. Change it by calling (set-control-srate value). *default-sound-srate* Default value for *sound-srate*. This value is restored when you execute (top) to pop out of a debugging session. Change it by calling (set-sound-srate value). *file-separator* The character that separates directories in a path, e.g. ``/'' for Unix, ``:'' for Mac, and ``\'' for Win32. This is normally set in system.lsp. *rslt* When a function returns more than one value, *rslt* is set to a list of the ``extra'' values. This provides a make-shift version of the multiple-value-return facility in Common Lisp. *sound-srate* Part of the environment, establishes the audio sample rate. See Section 3.1 for details. *soundenable* Controls whether writes to a sound file will also be played as audio. Set this variable by calling (sound-on) or (sound-off). *tracenable* Controls whether XLISP prints a backtrace when an error is encountered. XLISP variables See Section IV.14 for a list of global variables defined by XLISP. Environment variables See Section 3.1 for definitions of variables used in the environment for behaviors. In general, you should never set or access these variables directly. Various constants See Section 1.7 for definitions of predefined constants for loudness, duration, and pitch. 9. Time/Frequency Transformation Nyquist provides functions for FFT and inverse FFT operations on streams of audio data. Because sounds can be of any length, but an FFT operates on a fixed amount of data, FFT processing is typically done in short blocks or windows that move through the audio. Thus, a stream of samples is converted in to a sequence of FFT frames representing short-term spectra. Nyquist does not have a special data type corresponding to a sequence of FFT frames. This would be nice, but it would require creating a large set of operations suitable for processing frame sequences. Another approach, and perhaps the most ``pure'' would be to convert a single sound into a multichannel sound, with one channel per bin of the FFT. Instead, Nyquist violates its ``pure'' functional model and resorts to objects for FFT processing. A sequence of frames is represented by an XLISP object. Whenever you send the selector :next to the object, you get back either NIL, indicating the end of the sequence, or you get an array of FFT coefficients. The Nyquist function snd-fft (mnemonic, isn't it?) returns one of the frame sequence generating objects. You can pass any frame sequence generating object to another function, snd-ifft, and turn the sequence back into audio. With snd-fft and snd-ifft, you can create all sorts of interesting processes. The main idea is to create intermediate objects that both accept and generate sequences of frames. These objects can operate on the frames to implement the desired spectral-domain processes. Examples of this can be found in the file fft_tutorial.htm, which is part of the standard Nyquist release. The documentation for snd-fft and snd-ifft follows. snd-fft(sound, length, skip, window) [SAL] (snd-fft sound length skip window) [LISP] This function performs an FFT on the first samples in sound and returns a Lisp array of FLONUMs. The function modifies the sound, violating the normal rule that sounds are immutable in Nyquist, so it is advised that you copy the sound using snd-copy if there are any other references to sound. The length of the FFT is specified by length, a FIXNUM (integer) which must be a power of 2. After each FFT, the sound is advanced by skip samples, also of type FIXNUM. Overlapping FFTs, where skip is less than length, are allowed. If window is not NIL, it must be a sound. The first length samples of window are multiplied by length samples of sound before performing the FFT. When there are no more samples in sound to transform, this function returns NIL. The coefficients in the returned array, in order, are the DC coefficient, the first real, the first imaginary, the second real, the second imaginary, etc. The last array element corresponds to the real coefficient at the Nyquist frequency. snd-ifft(time, srate, iterator, skip, window) [SAL] (snd-ifft time srate iterator skip window) [LISP] This function performs an IFFT on a sequence of spectral frames obtained from iterator and returns a sound. The start time of the sound is given by time. Typically, this would be computed by calling (local-to-global 0). The sample rate is given by srate. Typically, this would be *sound-srate*, but it might also depend upon the sample rate of the sound from which the spectral frames were derived. To obtain each frame, the function sends the message :next to the iterator object, using XLISP's primitives for objects and message passing. The object should return an array in the same format as obtained from snd-fft, and the object should return NIL when the end of the sound is reached. After each frame is inverse transformed into the time domain, it is added to the resulting sound. Each successive frame is added with a sample offset specified by skip relative to the previous frame. This must be an integer greater than zero. If window is not NIL, it must be a sound. This window signal is multiplied by the inverse transformed frame before the frame is added to the output sound. The length of each frame should be the same power of 2. The length is implied by the array returned by iterator, so it does not appear as a parameter. This length is also the number of samples used from window. Extra samples are ignored, and window is padded with zeros if necessary, so be sure window is the right length. The resulting sound is computed on demand as with other Nyquist sounds, so :next messages are sent to iterator only when new frames are needed. One should be careful not to reuse or modify iterator once it is passed to snd-ifft. 10. MIDI, Adagio, and Sequences Nyquist includes facilities to read and write MIDI files as well as an ASCII text-based score representation language, Adagio. XLISP and Nyquist can be used to generate MIDI files using compositional algorithms. (See also Section 13.) A tutorial on using the Adadio representation and MIDI can be found in demos/midi_tutorial.htm. The Adagio language is described below. Adagio was originally developed as part of the CMU MIDI Toolkit, which included a program to record and play MIDI using the Adagio representation. Some of the MIDI features of Adagio may not be useful within Nyquist. Nyquist offers a number of different score representations, and you may find this confusing. In general, MIDI files are a common way to exchange music performance data, especially with sequencers and score notation systems. The demos/midi_tutorial.htm examples show how to get the most precise control when generating MIDI data. Adagio is most useful as a text-based score entry language, and it is certainly more compact than Lisp expressions for MIDI-like data. The Xmusic library (Chapter 13) is best for algorithmic generation of music and score manipulation. There are functions to convert between the Adagio, MIDI sequence data, and Xmusic score representations. Adagio is an easy-to-use, non-procedural notation for scores. In Adagio, text commands are used to specify each note. If you are new to Adagio, you may want to glance at the examples in Section 10.3 starting on page 37 before reading any further. A note is described in Adagio by a set of attributes, and any attribute not specified is ``inherited'' from the previous line. Attributes may appear in any order and must be separated by one or more blanks. An attribute may not contain any blanks. The attributes are: time, pitch, loudness, voice number, duration, and articulation. Adagio has been used to program a variety of hardware and software synthesizers, and the Adagio compiler can be easily adapted to new environments. Although not originally intended for MIDI, Adagio works quite well as a representation for MIDI scores. Adagio has been extended to allow MIDI controller data such as modulation wheels, pitch bend, and volume, MIDI program commands to change timbre, and System Exclusive messages. A note command in Adagio must be separated from other notes. Usually, notes are distinguished by writing each one on a separate line. Notes can also be separated by using a comma or semicolon as will be described below. Besides notes, there are several other types of commands: 1. An asterisk (*) in column one (or immediately after a comma, semicolon, or space) indicates that the rest of the line is a comment. The line is ignored by Adagio, and is therefore a good way to insert text to be read by people. Here are some examples: * This is a comment. T150 G4 * This is a comment too! T150 G4 ;* So is this. 2. An empty command (a blank line, for example) is ignored as if it were a comment(To be consistent, a blank line ought to specify zero attributes and generate a note that inherits all of its attributes from the previous one. Adagio is intentionally inconsistent in this respect.). 3. An exclamation point (!) in column one (or immediately after a comma or semicolon) indicates a special command. A special command does not generate a note. Special commands follow the ``!'' with no intervening spaces and extend to the end of the line, for example: !TEMPO 100 4. Control change commands are used to control parameters like pitch bend, modulation, and program (timbre). Control change commands can be specified along with notes or by themselves. A command that specifies control changes without specifying a pitch will not produce a note. Adagio is insensitive to case, thus ``A'' is equivalent to ``a'', and you can mix upper and lower case letters freely. 10.1. Specifying Attributes A note is indicated by a set of attributes. Attributes are indicated by a string of characters with no intervening spaces because spaces separate attributes. The attributes are described below. th The default unit of time is a centisecond (100 's), but this can be changed th to a millisecond (1000 's) using the !MSEC command and reset to centiseconds with !CSEC (see Section 10.4.1). In the descriptions below, the term ``time unit'' will be used to mean whichever convention is currently in effect. 10.1.1. Time The time attribute specifies when to start the note. A time is specified by a ``T'' followed by a number representing time units or by a duration (durations are described below). Examples: T150 ** 1.5 sec (or .15 sec) TQ3 ** 3 quarter note's duration If no time is specified, the default time is the sum of the time and duration attributes of the previous note. (But see Section 10.1.4.) Time is measured relative to the time of the most recent Tempo or Rate command. (See the examples in Section 10.3 for some clarification of this point.) 10.1.2. Pitch The pitch attribute specifies what frequency to produce. Standard scale pitches are named by name, using S for sharp, F for flat, and (optionally) N for natural. For example, C and CN represent the same pitch, as do FS and GF (F sharp and G flat). Note that there are no bar lines, and accidentals to not carry forward to any other notes as in common practice notation. Octaves are specified by number. C4 is middle C, and B3 is a half step lower. F5 is the top line of the treble clef, etc. (Adagio octave numbering follows the ISO standard, but note that this is not universal. In particular, Yamaha refers to middle C as C3.) Accidentals can go before or after the octave number, so FS3 and F3S have the same meaning. An alternate notation for pitch is Pn, where n is an integer representing the pitch.Middle C (C4) is equivalent to P60, CS4 is P61, etc. If you do not specify an octave, Adagio will choose one for you. This is done by picking the octave that will make the current pitch as close to the previous pitch as possible. In the case of augmented fourths or diminished fifths, there are two equally good choices. Adagio chooses the lower octave. 10.1.3. Duration Duration is specified by a letter indicating a number of beats, followed by one or several modifiers. The basic duration codes are: W (whole, 4 beats), H (half, 2 beats), Q (quarter, 1 beat), I (eighth, 1/2 beat), S (sixteenth, 1/4 beat), % (thirtysecond, 1/8 beat), and ^ (sixtyfourth, 1/16 beat). Note that E is a pitch, so eighth-notes use the duration code I. The default tempo is 100 beats per minute (see Section 10.1.10). These codes may be followed by a T (triplet), indicating a duration of 2/3 the normal. A dot (.) after a duration code extends it by half to 3/2 the normal. An integer after a note multiplies its duration by the indicated value (the result is still just one note). Finally, a slash followed by an integer divides the duration by the integer. Like all attributes, duration attributes may not have embedded spaces. Examples: Q 1 beat (quarter note) QT 2/3 beat (quarter triplet) W. 6 beats(dotted whole note) ST6 1 beat (6 sixteenth triplets) H5 10 beats(5 half notes) Q3/7 3/7 beats th A duration may be noted by Un, where n is an integer indicating 100 's of a th second (or 1000 's), see Section 10.4.1. For example, U25 is twenty-five time units. Durations may be combined using a plus sign: Q+IT ** a quarter tied to an eighth triplet Q/7+W+Q2/7 ** a 7th beat tied to a whole tied to 2/7th beat Q+U10 ** a quarter plus 10 time units 10.1.4. Next Time The time of the next command (the next command in the Adagio program text) is normally the time of the current note command plus the duration of the current note. This can be overridden by a field consisting of the letter N followed by a number indicating time units, or followed by a duration as described above. The next note will then start at the time of the current note plus the duration specified after N. If the next note has an explicit time attribute (T), then the specified time will override the one based on the previous note. Examples: N0 ** start the next note at the same time as this one N50 ** start the next note 0.5 seconds after this one NQT ** start the next note 2/3 beat after the current one NU10+Q ** start after 0.1 seconds plus a quarter A comma has an effect similar to N0 and is explained in Section 10.4.2. Articulation effects such as staccato can be produced using N, but it is more convenient to use the articulation attribute described in Section 10.1.6. 10.1.5. Rest Rests are obtained by including the field R in a note command. The effect of an R field is to omit the note that would otherwise occur as the result of the current note command. In all other respects, the command is processed just like any other line. This means that attributes such as duration, loudness, and pitch can be specified, and anything specified will be inherited by the note in the next command. Normally, a rest will include just R and a duration. The fact that a note command specifies a rest is not inherited. For example: R H ** a half (two beat) rest RH ** illegal, R must be separated from H by space(s) Because some synthesizers (e.g. a DX7) cannot change programs (presets) rapidly, it may be desirable to change programs in a rest so that the synthesizer will be ready to play by the end of the rest. See Section 10.1.9 for an example. 10.1.6. Articulation Articulation in Adagio refers to the percentage of time a note is on relative to the indicated duration. For example, to play a note staccato, you would normally play the note about half of its indicated duration. In Adagio, articulation is indicated by # followed by an integer number indicating a percentage. The articulation attribute does not affect the time of the next command. This example plays two staccato quarter notes: C Q #50 D To produce overlapping notes, the articulation may be greater than 100. Be aware that overlapping notes on the same pitch can be a problem for some synthesizers. The following example illustrates this potential problem: !TEMPO 60 C Q #160 * starts at time 0, ends at 1.6 sec D I * starts at time 1, ends at 1.8 sec C Q * starts at time 1.5, ends at 3.1 sec? At one beat per second (tempo 60), these three notes will start at times 0, 1, and 1.5 seconds, respectively. Since these notes have an articulation of 160, each will be on 160% of its nominal duration, so the first note (C) will remain on until 1.6 seconds. But the third note (another C) will start at time 1.5 seconds. Thus, the second C will be started before the first one ends. Depending on the synthesizer, this may cancel the first C or play a second C in unison. In either case, a note-off message will be sent at time 1.6 seconds. If this cancels the second C, its actual duration will be 0.1 rather than 1.6 seconds as intended. A final note-off will be sent at time 3.1 seconds. 10.1.7. Loudness Loudness is indicated by an L followed by a dynamic marking from the following: PPP, PP, P, MP, MF, F, FF, FFF. Alternatively, a number from 1 to 127 may be used. The loudness attribute is the MIDI note velocity. (Note that a MIDI velocity of 0 means ``note-off,'' so the minimum loudness is 1.) The dynamicmarkings are translated into numbers as follows: Lppp 20 Lmf 58 Lpp 26 Lf 75 Lp 34 Lff 98 Lmp 44 Lfff 127 10.1.8. Voice The voice attribute tells which of the 16 MIDI channels to use for the note. The voice attribute consists of a V followed by an integer from 1 (the default) to 16. There is a limit to how many notes can be played at the same time on a given voice (MIDI channel). Since the limit depends upon the synthesizer, Adagio cannot tell you when you exceed the limit. Similarly, Adagio cannot tell whether your synthesizer is set up to respond to a given channel, so there is no guarantee that what you write will actually be heard. 10.1.9. Timbre (MIDI Program) A MIDI program (synthesizer preset) can be selected using the attribute Zn, where n is the program number (from 1 to 128). Notice that in MIDI, changing the program on a given channel will affect all notes on that channel and possibly others. Adagio treats MIDI program changes as a form of control change. For many synthesizers, you will not be able to change programs at the start of a note or during a note. Change the program during a rest instead. For example: R I Z23 V4 ** change MIDI channel 4 to program 23 during rest A4 ** play a note on channel 4 Check how your synthesizer interprets program numbers. For example, the cartridge programs on a DX7 can be accessed by adding 32 to the cartridge program number. Cartridge program number 10 is specified by Z42. As in MIDI, the Adagio timbre is a property of the voice (MIDI channel), so the timbre will not be inherited by notes on a different channel; to change the timbre on multiple voices (channels), you must explicitly notate each change. 10.1.10. Tempo The length of a beat may be changed using a Tempo command: !TEMPO n where n indicates beats per minute. The exclamation mark tells Adagio that this is a special command line rather than a note definition. A special command takes the place of a note specification. No other attributes should be written on a line with a special command. The !TEMPO command is associated with a time, computed as if the !TEMPO command were a note. The time attribute (T) of all succeeding notes is now measured relative to the time of the !TEMPO command. The new tempo starts at the !TEMPO command time and affects all succeeding notes. Durations specified in time units (for example U58, N15) are not affected by the !TEMPO command, and numerical times (for example T851) are computed relative to the time of the last !TEMPO command. The !TEMPO command is fairly clever about default durations. If the last duration specified before the !TEMPO command is symbolic (using one of ^,%, S, I, Q, H, or W ), then the default duration for the node after the !TEMPO command will be modified according to the tempo change. Consider the following tempo change: !TEMPO 60 A4 H !TEMPO 120 G In this example, the first note will last 2 seconds (2 beats at 60 beats per minute). The second note inherits the duration (H) from the first note, but at 120 beats per minute, the second note will last only 1 second. If the duration had been specified U200 (also a duration of 2 seconds), the second note would also last 2 seconds because the !TEMPO command does not affect times or durations specified numerically in time units. If the duration is the sum of a symbolic and a numeric specification, the inherited duration after a !TEMPO command is undefined. 10.1.11. Rate The !RATE command scales all times including those specified in hundredths of seconds. A rate of 100 means no change, 200 means twice as fast, and 50 means half as fast. For example, to make a piece play 10% faster, you can add the following command at the beginning of the score: !RATE 110 !RATE and !TEMPO commands combine, so !RATE 200 !TEMPO 70 will play 70 beats per minute at double the normal speed, or 140 beats per minute. Like !TEMPO, the time of the !RATE command is added to the time attribute of all following notes up to the next !TEMPO or !RATE command. Two !RATE commands do not combine, so a !RATE command only affects the rate until the next !RATE command. Although !TEMPO and !RATE can occur in the middle of a note (using N, T, etc.) they do not affect a note already specified. This property allows multiple tempi to exist simultaneously (see Section 10.4.4). 10.2. Default Attributes If an attribute is omitted, the previous one is used by default (with the exception of the time attribute). The default values for the first note, which are inherited by succeeding notes until something else is specified, are given below in Adagio notation: Time T0 Pitch C4 Duration Q Articulation #100 Loudness LFFF Voice V1 Tempo !TEMPO 100 Rate !RATE 100 Control changes (including timbre or MIDI program, specified by Z) have no default value and are only sent as specified in the score. Important: the rules for determining when a command will play a note are as follows (and this has changed slightly from previous versions): 1. If a special (!) command or nothing is specified, e.g. a blank line, do not play a note. 2. If R (for ``rest'') is specified, do not play a note. 3. Otherwise, if a pitch is specified, do play a note. 4. Otherwise, if no control changes (or program changes) are specified (so this is a command with non-pitch attributes and no control changes), do play a note. Another way to say this is ``Special commands and commands with rests (R) do not play notes. Otherwise, play a note if a pitch is specified or if no control is specified.'' 10.3. Examples The following plays the first two bars of ``Happy Birthday''. Note that Adagio knows nothing of bar lines, so the fact that the first note occurs on beat 3 or that the meter is three-four is of no consequence: *Example 1 ** Happy Birthday tune (C major) !TEMPO 120 G4 I. LF G4 S A4 Q G4 C5 B4 H The time attribute for the first note is zero (0). The second note will occur a dotted eighth later, etc. Notice that no timbre or rate was specified. Adagio will provide reasonable default values of 1 and 100, respectively. The following example plays the first four bars of an exercise from Bartok's Mikrokosmos (Vol. 1, No. 12). An extra quarter note is inserted at the beginning of each voice in order to allow time to change MIDI programs. The right hand part is played on voice (MIDI channel) 1 and the left hand part on voice 2. Notice the specification of the time attribute to indicate that voice 2 starts at time 0. Also, default octaves are used to reduce typing. *Example 2 ** Bartok *voice 1, right hand R Q Z10 V1 ** extra rest for program change A4 H B Q C D H C D Q C B A B C D R *voice 2, left hand T0 R Q Z15 V2 ** extra rest for program change G3 H F Q E D H E D Q E F G F E D R The next example is the same piece expressed in a different manner, illustrating the interaction between the !TEMPO command and the time attribute. Recall that the time attribute is measured relative to the time of the last !TEMPO command: *Example 3 ** 4 measures in 2 sections !Tempo 100 *Voice 1, Measures 1 & 2 R Q Z10 V1 A4 H B Q C D H C *Voice 2, Measures 1 & 2 T0 R Q Z15 V2 G3 H F Q E D H E H !TEMPO 100 *Voice 1, Measures 3 & 4 * note that Z10 is still in effect for V1 V1 D4 Q C B A B C D R *Voice 2, Measures 3 & 4 T0 V2 D3 Q E F G F E D R The piece is written in 4 sections. The first plays a rest followed by two measures, starting at time 0. The next section changes the time back to zero and plays two measures of the left hand part (voice 2). The next command (!TEMPO 100) sets the tempo to 100 (it already is) and sets the reference time to be two measures into the piece. Therefore, the next note (D4) will begin measure 3. The D3 that begins the last group of notes has a T0 attribute, so it will also start at measure 3. Notice how the !TEMPO command can serve to divide a piece into sections. The last example will show yet another way to express the same piece of music using the ``Next'' attribute. Only the first bar of music is given. *Example 4 ** use of the Next attribute !Tempo 100 R Q Z10 V1 N0 R Q Z15 V2 A4 H V1 N0 G3 V2 B4 Q V1 N0 F3 V2 C4 Q V1 N0 E3 V2 Here, each pair of lines represents two simultaneous notes. The N0 attribute forces the second line to start at the same time as the first line of each pair. Because of the large intervals, octave numbers (3 and 4) are necessary to override the default octave for these pitches. 10.4. Advanced Features Beyond the simple notation described above, Adagio supports a number of features. (See also the next chapter.) 10.4.1. Time Units and Resolution th The default time unit is 10ms (ten milliseconds or one centisecond or 100 th of a second), but it is possible to change the basic unit to 1ms, or 1000 of a second. The time unit can be specified by: th !CSEC centisecond time units = 100 th !MSEC millisecond time units = 1000 The time unit remains in effect until the next !CSEC or !MSEC command. 10.4.2. Multiple Notes Per Line Notes can be separated by commas or semicolons as well as by starting a new line. A comma is equivalent to typing N0 and starting a new line. In other words, the next note after a comma will start at the same time as the note before the comma. In general, use commas to separate the notes of a chord. A semicolon is equivalent to starting a new line. In general, use semicolons to group notes in a melody. Here is yet another rendition of the Bartok: *Example 5 ** use of semicolons !Tempo 100 R Q Z10 V1 A4 H; B Q; C; D H; C; D Q; C; B; A; B; C; D; R T0 R Q Z15 V2 G3 H; F Q; E; D H; E; D Q; E; F; G; F; E; D; R This example is similar to Example 2, except semicolons are used. Note how semicolons make the two lines of music stand out. The next example is similar to Example 4, except commas are used and four bars are notated. The music below is treated as a sequence of 2-note chords, with each chord on a separate line: *Example 6 ** use of commas !Tempo 100 R Q Z10 V1, R Q Z15 V2 A4 H V1, G3 V2 B4 Q V1, F3 V2 C4 V1, E3 V2 D4 H V1, D3 V2 C4 V1, E3 V2 D4 Q V1, D3 V2 C4 V1, E3 V2 B4 V1, F3 V2 A4 V1, G3 V2 B4 V1, F3 V2 C4 V1, E3 V2 D4 V1, D3 V2 R 10.4.3. Control Change Commands Any control change can be specified using the syntax ``~n(v)'', where n is the controller number (0 - 127), and v is the value. In addition, Adagio has some special syntax for some of the commonly used control changes (note that Pitch bend, Aftertouch, and MIDI Program Change are technically not MIDI control changes but have their own special message format and status bytes): K Portamento switch M Modulation wheel O Aftertouch X Volume Y Pitch bend Z Program Change The letter listed beside each control function is the Adagio command letter. For example, M23 is the command for setting the modulation wheel to 23. Except for pitch bend, the portamento switch, and MIDI Program Change, all values range from 0 to 127. Pitch bend is ``off'' or centered at 128, and has a range from 0 to 255 (MIDI allows for more precision, but Adagio does not). Turn on portamento with K127 and off with K0. Programs are numbered 1 to 128 to correspond to synthesizer displays. About volume: Midi volume is just a control, and the Midi standard does not say what it means. Typically it does what the volume pedal does; that is, it scales the amplitude in a continuously changeable fashion. In contrast, Midi velocity, which is controlled by the L (loudness) attribute, is part of a Midi note-on command and is fixed for the duration of the note. Typically, these two ways of controlling loudness and amplitude operate independently. In some low-cost synthesizers the numbers seem to be added together internally and volume changes are ignored after the note starts. About pitch bend: Midi pitch bend is a number from 0 to 16383, where 8192 is the center position. To convert to Midi, Adagio simply multiplies your number by 64, giving values from 0 to 16320. Note that Y128 translates exactly to 8192. The meaning of pitch bend depends upon your synthesizer and its setting. Most synthesizers let you specify a ``pitch bend range.'' A range of one semitone means that Y255 will produce a bend of approximately one semitone up, and Y0 will bend one semitone down. If the range is 12 semitones, then the same Y255 will bend an octave. Typically, pitch bend is exponential, so each increment in the pitch bend value will bend an equal number of cents in pitch. Control changes can be part of a note specification or independent. In the following example, a middle C is played with a modulation wheel setting of 50 and a pitch bend of 120. Then, at 10 unit intervals, the pitch bend is decreased by 10. The last line sets the portamento time (controller 5) to 80: *Example 7 C4 LMF M50 Y120 U100 N10 Y110 N10; Y100 N10; Y90 N10; Y80 N10 Y70 N10; Y60 N10; Y50 N10 ~5(80) See Section 10.2 on page 37 for rules on whether or not a command will play a note. 10.4.4. Multiple Tempi Writing a piece with multiple tempi requires no new commands; you just have to be clever in the use of Tempo and Time. The following plays a 7 note diatonic scale on voice 1, and a 12 note chromatic scale on voice 2: *Example 8 ** multiple tempi !TEMPO 70 V1 C4; D; E; F; G; A; B T0 R N0 !TEMPO 120 V2 C4; CS; D; DS; E; F; FS; G; GS; A; AS; B !TEMPO 100 V1 C5, V2 C5 The third line plays the 7-note diatonic scale on voice 1. The next line contains the tricky part: notice that the time is set back to zero, there is a rest, and a next (N) attribute is used to specify that the next default time will be at the same time as the current one. This is tricky because a !TEMPO command cannot have a time (T0) attribute, and a T0 by itself would create a note with a duration. T0 R N0 says: ``go to time 0, do not play a note, and do not advance the time before the next command''. Thus, the time of the !TEMPO 120 command is zero. After the 12 note scale, the tempo is changed to 100 and a final note is played on each voice. A little arithmetic will show that 7 notes at tempo 70 and 12 notes at tempo 120 each take 6 seconds, so the final notes (C5) of each scale will happen at the same time. 10.4.5. MIDI Synchronization The Adagio program (but not Nyquist) can synchronize with external devices using MIDI real time messages. Thus, Adagio has a !CLOCK command. This command is currently of no use to Nyquist users but is documented here for completeness (it's part of the language syntax even if it does not do anything). Since Adagio supports multiple tempi, and Midi clock is based on beats, it is necessary to be explicit in the score about where the clock should start and what is the duration of a quarter note. The !CLOCK command in Adagio turns on a 24 pulse-per-quarter (PPQ) clock at the current tempo and time: !TEMPO 100 !CLOCK A !CLOCK command must also be inserted for each tempo change that is to be reflected in the Midi clock. Typically, each !TEMPO command will be followed by a !CLOCK command. Clock commands and thus tempo changes can take place at arbitrary times. It is th assumed that tempo changes on an exact 24 of a beat subdivision (for example, exactly on a beat). If not, the tempo change will take place on the nearest th exact 24 of a beat subdivision. This may be earlier or later than the requested time. 10.4.6. System Exclusive Messages Adagio has a definition facility that makes it possible to send system exclusive parameters. Often, there are parameters on Midi synthesizers that can only be controlled by system exclusive messages. Examples include the FM ratio and LFO rate on a DX7 synthesizer. The following example defines a macro for the DX7 LFO rate and then shows how the macro is used to set the LFO rate for a B-flat whole note in the score. The macro definition is given in hexadecimal, except v is replaced by the channel (voice) and %1 is replaced by the first parameter. A macro is invoked by writing ``~'' followed by the macro name and a list of parameters: !DEF LFO F0 43 0v 01 09 %1 F7 Bf5 W ~LFO(25) In general, the !DEF command can define any single MIDI message including a system exclusive message. The message must be complete (including the status byte), and each !DEF must correspond to just one message. The symbol following !DEF can be any name consisting of alphanumeric characters. Following the name is a hexadecimal string (with optional spaces), all on one line. Embedded in the string may be the following special characters: v Insert the 4-bit voice (MIDI channel) number. If v occurs in the place of a high-order hexadecimal digit, replace v with 0v so that the channel number is always placed in the low-order 4 bits of a data byte. In other words, v is padded if necessary to fall into the low-order bits. %n Insert a data byte with the low-order 7 bits of parameter number n. Parameters are numbered 1 through 9. If the parameter value is greater than 127, the high-order bits are discarded. ^n Insert a data byte with bits 7 through 13 of parameter number n. In other words, shift the value right 7 places then clear all but the first 7 bits. Note that 14-bit numbers can be encoded by referencing the same parameter twice; for example, %4^4 will insert the low-order followed by the high-order parts of parameter 4 into two successive data bytes. Parameters are separated by commas, but there may be no spaces. The maximum number of parameters allowed is 9. Here is an example of definitions to send a full-resolution pitch bend command and to send a system exclusive command to change a DX7 parameter[My TX816 Owner's Manual gives an incorrect format for the change parameter sysex command (according to the manual, there is no data in the message!) I am assuming that the data should be the last byte before the EOX and that there is no byte count. If you are reading this, assume that I have not tested this guess, nor have I tested this example.]. * Define macro for pitch bend commands: !DEF bend Ev %1 ^1 A ~bend(8192) ** 8192 is "pitch bend off" * Change the LFO SPEED: * SYSEX = F0, Yamaha = 43, Substatus/Channel = 1v, * Group# = 01, Parameter# = 9, Data = 0-99, EOX = F7 !DEF lfospeed F0 43 1v 01 09 %1 F7 * now use the definitions: G4 ~bend(7567) N40 ~lfospeed(30) N35 10.4.7. Control Ramps The !RAMP command can specify a smooth control change from one value to another. It consists of a specification of the starting and ending values of some control change, a duration specifying how often to send a new value, and a duration specifying the total length of the ramp. !RAMP X10 X100 Q W2 !RAMP ~23(10) ~23(50) U20 W !RAMP ~lfo(15) ~lfo(35) U10 The first line says to ramp the volume control (controller number 7) from 10 to 100, changing at each quarter note for the duration of two whole notes. The second line says to ramp controller number 23 from value 10 to value 50, sending a new control change message every 20 time units. The overall duration of the ramp should be equivalent to a whole note (W). As shown in the third line, even system exclusive messages controlled by parameters can be specified. If the system exclusive message has more than one parameter, only one parameter may be ``ramped''; the others must remain the same. For example, the following would ramp the second parameter: !RAMP ~mysysex(4,23,75) ~mysysex(4,100,75) U10 W A rather curious and extreme use of macros and ramps is illustrated in the following example. The noteon macro starts a note, and noteoff ends it. Ramps can now be used to emit a series of notes with changing pitches or velocities. Since Adagio has no idea that these macros are turning on notes, it is up to the programmer to turn them off! !DEF noteon 9v %1 %2 !DEF noteoff 8v %1 %2 ~noteon(48,125) ~noteoff(48,126) * turn on some notes !RAMP ~noteon(36,125) ~noteon(60,125) Q W NW * turn them off !RAMP ~noteoff(60,50) ~noteoff(36,50) Q W NW 10.4.8. The !End Command The special command !END marks the end of a score. Everything beyond that is ignored, for example: * this is a score C; D; E; F; G W !END since the score has ended, this text will be ignored 10.4.9. Calling C Routines It is possible to call C routines from within Adagio scores when using specially linked versions, but this feature is disabled in Nyquist. The syntax is described here for completeness. The !CALL command calls a C routine that can in turn invoke a complex sequence of operations. Below is a call to a trill routine, which is a standard routine in Adagio. The parameters are the base pitch of the trill, the total duration of the trill, the interval in semitones, the duration of each note of the trill, and the loudness. Notice that both numbers and Adagio notation can be used as parameters: !CALL trill(A5,W,2,S,Lmf) T278 V1 The parameter list should have no spaces, and parameters are separated by commas. Following the close parenthesis, you may specify other attributes such as the starting time and voice as shown in the example above. A parameter may be an Adagio pitch specification, an Adagio duration, an Adagio loudness, a number, or an ASCII character within single quotes, e.g. 'a' is equivalent to 97 because 97 is the decimal encoding of ``a'' in ASCII. The !CALL may be followed by a limited set of attributes. These are time (T), voice (V), and next time (N). The !CALL is made at the current time if no time is specified, and the time of the next adagio command is the time of the !CALL unless a next time is specified. In other words, the default is N0. 10.4.10. Setting C Variables In addition to calling C routines, there is another way in which scores can communicate with C. As with !CALL, specific C code must be linked before these commands can be used, and this is not supported in Nyquist. The !SETI command sets an integer variable to a value, and the !SETV command sets an element of an integer array. For example, the next line sets the variable delay to 200 and sets transposition[5] to -4 at time 200: !SETI delay 200 !SETV transposition 5 -4 T200 As with the !CALL command, these commands perform their operations at particular times according to their place in the Adagio score. This makes it very easy to implement time-varying parameters that control various aspects of an interactive music system. 11. Linear Prediction Analysis and Synthesis Nyquist provides functions to perform Linear Prediction Coding (LPC) analysis and synthesis. In simple terms, LPC analysis assumes that a sound is the result of an all-pole filter applied to a source with a flat spectrum. LPC is good for characterizing the general spectral shape of a signal, which may be time-varying as in speech sounds. For synthesis, any source can be filtered, allowing the general spectral shape of one signal (used in analysis) to be applied to any source (used in synthesis). A popular effect is to give vowel-like spectra to musical tones, creating an artificial (or sometimes natural) singing voice. Examples of LPC analysis and synthesis can be found in the file lpc_tutorial.htm, which is part of the standard Nyquist release. As with FFT processing, LPC analysis takes a sound as input and returns a stream of frames. Frames are returned from an object using the :next selector just as with FFT frames. An LPC frame is a list consisting of: RMS1, the energy of the input signal, RMS2, the energy of the residual signal, ERR, the square root of RMS1/RMS2, and FILTER-COEFS, an array of filter coefficients. To make code more readable and to avoid code dependence on the exact format of a frame, the functions lpc-frame-rms1, lpc-frame-rms2, lpc-frame-err, and lpc-frame-filter-coefs can be applied to a frame to obtain the respective fields. The z transform of the filter is H(z) = 1/A(z), where A(z) is a polynomial of the form A(z) = 1 + a z + a z + ... + a z. The FILTER-COEFS array has the form 1 2 p #(a a ... a a a ). p p-1 3 2 1 The file lpc.lsp defines some useful classes and functions. The file is not automatically loaded with Nyquist, so you must execute (load "lpc") before using them. 11.1. LPC Classes and Functions make-lpanal-iterator(sound, framedur, skiptime, npoles) [SAL] (make-lpanal-iterator sound framedur skiptime npoles) [LISP] Makes an iterator object, an instance of lpanal-class, that returns LPC frames from successive frames of samples in sound. The duration (in seconds) of each frame is given by framedur, a FLONUM. The skip size (in seconds) between successive frames is given by skiptime, a FLONUM. Typical values for framedur and skiptime are 0.08 and 0.04, giving 25 frames per second and a 50% frame overlap. The number of poles is given by npoles, a FIXNUM. The result is an object that responds to the :next selector by returning a frame as described above. NIL is returned when sound terminates. (Note that one or more of the last analysis windows may be padded with zeros. NIL is only returned when the corresponding window would begin after the termination time of the sound.) make-lpc-file-iterator(filename) [SAL] (make-lpc-file-iterator filename) [LISP] Another way to get LPC frames is to read them from a file. This function opens an ASCII file containing LPC frames and creates an iterator object, an instance of class lpc-file-class to access them. Create a file using save-lpc-file (see below). save-lpc-file(lpc-iterator, filename) [SAL] (save-lpc-file lpc-iterator filename) [LISP] Create a file containing LPC frames. This file can be read by make-lpc-file-iterator (see above). show-lpc-data(lpc-iterator, iniframe, endframe [, poles?]) [SAL] (show-lpc-data lpc-iterator iniframe endframe [poles?]) [LISP] Print values of LPC frames from an LPC iterator object. The object is lpc-iterator, which is typically an instance of lpanal-class or lpc-file-class. Frames are numbered from zero, and only files starting at iniframe (a FIXNUM) and ending before endframe (also a FIXNUM) are printed. By default, only the values for RMS1, RMS2, and ERR are printed, but if optional parameter poles? is non-NIL, then the LPC coefficients are also printed. allpoles-from-lpc(snd, lpc-frame) [SAL] (allpoles-from-lpc snd lpc-frame) [LISP] A single LPC frame defines a filter. Use allpoles-from-lpc to apply this filter to snd, a SOUND. To obtain lpc-frame, a LIST containing an LPC frame, either send :next to an LPC iterator, or use nth-frame (see below). The result is a SOUND whose duration is the same as that of snd. lpreson(snd, lpc-iterator, skiptime) [SAL] (lpreson snd lpc-iterator skiptime) [LISP] Implements a time-varying all-pole filter controlled by a sequence of LPC frames from an iterator. The SOUND to be filtered is snd, and the source of LPC frames is lpc-iterator, typically an instance of lpanal-class or lpc-file-class. The frame period (in seconds) is given by skiptime (a FLONUM). This number does not have to agree with the skiptime used to analyze the frames. (Greater values will cause the filter evolution slow down, and smaller values will cause it to speed up.) The result is a SOUND. The duration of the result is the minimum of the duration of snd and that of the sequence of frames. lpc-frame-rms1(frame) [SAL] (lpc-frame-rms1 frame) [LISP] Get the energy of the input signal from a frame. lpc-frame-rms2(frame) [SAL] (lpc-frame-rms2 frame) [LISP] Get the energy of the residual from a frame. lpc-frame-err(frame) [SAL] (lpc-frame-err frame) [LISP] Get the square root of RMS1/RMS2 from a frame. lpc-frame-filter-coefs(frame) [SAL] (lpc-frame-filter-coefs frame) [LISP] Get the filter coefficients from a frame. 11.2. Low-level LPC Functions The lowest-level Nyquist functions for LPC are - snd-lpanal for analysis, - snd-allpoles, an all-pole filter with fixed coefficients, and - snd-lpreson, an all-pole filter that takes frames from an LPC iterator. snd-lpanal(samps, npoles) [SAL] (snd-lpanal samps npoles) [LISP] Compute an LPC frame with npoles (a FIXNUM) poles from an ARRAY of samples (FLONUMS). Note that snd-fetch-array can be used to fetch a sequence of frames from a sound. Ordinarily, you should not use this function. Use make-lpanal-iterator instead. snd-allpoles(snd, lpc-coefs, gain) [SAL] (snd-allpoles snd lpc-coefs gain) [LISP] A fixed all-pole filter. The input is snd, a SOUND. The filter coefficients are given by lpc-coefs (an ARRAY), and the filter gain is given by gain, a FLONUM. The result is a SOUND whose duration matches that of snd. Ordinarily, you should use allpoles-from-lpc instead (see above). snd-lpreson(snd, lpc-iterator, skiptime) [SAL] (snd-lpreson snd lpc-iterator skiptime) [LISP] This function is identical to lpreson (see above). 12. Developing and Debugging in Nyquist There are a number of tools, functions, and techniques that can help to debug Nyquist programs. Since these are described in many places throughout this manual, this chapter brings together many suggestions and techniques for developing code and debugging. You really should read this chapter before you spend too much time with Nyquist. Many problems that you will certainly run into are addressed here. 12.1. Debugging Probably the most important debugging tool is the backtrace. There are two kinds of backtrace: one for SAL, and one for Lisp. SAL mode is actually just an XLISP function (sal) that reads input and evaluates it. When SAL encounters an error, it normally prints a trace of the SAL stack (all the active functions written in SAL), exists the current command, and reads the next command. If you call XLISP functions from SAL, including most Nyquist sound processing functions, and an error occurs within these XLISP functions, you will only see the SAL function that called the XLISP functions listed in the stack trace. Sometimes you need more details. When Nyquist encounters an error when it is not running SAL, it normally suspends execution and prints an error message. To find out where in the program the error occurred and how you got there, start by typing (bt). This will print out the last several function calls and their arguments, which is usually sufficient to see what is going on. In order for (bt) to work, you must have a couple of global variables set: *tracenable* is ordinarily set to NIL. If it is true, then a backtrace is automatically printed when an error occurs; *breakenable* must be set to T, as it enables the execution to be suspended when an error is encountered. If *breakenable* is NIL (false), then execution stops when an error occurs but the stack is not saved and you cannot get a backtrace. Finally, bt is just a macro to save typing. The actual backtrace function is baktrace, which takes an integer argument telling how many levels to print. All of these things are set up by default when you start Nyquist. To get this XLISP backtrace behavior when SAL encounters an error, you need to have *breakenable* set while SAL is running. The best way to do this is to run within the NyquistIDE program, open the Preferences dialog, and choose the desired settings, e.g. ``Enable XLISP break on SAL error.'' Since Nyquist sounds are executed with a lazy evaluation scheme, some errors are encountered when samples are being generated. In this case, it may not be clear which expression is in error. Sometimes, it is best to explore a function or set of functions by examining intermediate results. Any expression that yields a sound can be assigned to a variable and examined using one or more of: s-plot, snd-print-tree, and of course play. The snd-print-tree function prints a lot of detail about the inner representaion of the sound. Keep in mind that if you assign a sound to a global variable and then look at the samples (e.g. with play or s-plot), the samples will be retained in memory. At 4 bytes per sample, a big sound may use all of your memory and cause a crash. Another technique is to use low sample rates so that it is easier to plot results or look at samples directly. The calls: set-sound-srate(100) set-control-srate(100) set the default sample rates to 100, which is too slow for audio, but useful for examining programs and results. The function snd-samples(sound, limit) will convert up to limit samples from sound into a Lisp array. This is another way to look at results in detail. The trace function is sometimes useful. It prints the name of a function and its arguments everytimg the function is called, and the result is printed when the function exits. To trace the osc function, type: trace(osc) and to stop tracing, type untrace(osc). If a variable needs a value or a function is undefined, and if *breakenable* was set, you will get a prompt where you can fix the error (by setting the variable or loading the function definition) and keep going. At the debug (or break) prompt, your input must be in XLISP, not SAL syntax. Use (co), short for (continue) to reevaluate the variable or function and continue execution. When you finish debugging a particular call, you can ``pop'' up to the top level by typing (top), a short name for (top-level). There is a button named "Top" in the NyquistIDE that takes you back to the top level (ready to accept XLISP expressions), and another button named "SAL" that puts you back in SAL mode. 12.2. Useful Functions grindef(name) [SAL] (grindef name) [LISP] Prints a formatted listing of a lisp function. This is often useful to quickly inspect a function without searching for it in source files. Do not forget to quote the name, e.g. (grindef 'prod). args(name) [SAL] (args name) [LISP] Similar to grindef, this function prints the arguments to a function. This may be faster than looking up a function in the documentation if you just need a reminder. For example, (args 'lp) prints ``(LP S C),'' which may help you to remember that the arguments are a sound (S) followed by the cutoff (C) frequency. The following functions are useful short-cuts that might have been included in XLISP. They are so useful that they are defined as part of Nyquist. incf(symbol) [SAL] (incf symbol) [LISP] Increment symbol by one. This is a macro, and symbol can be anything that can be set by setf. Typically, symbol is a variable: ``(incf i),'' but symbol can also be an array element: ``(incf (aref myarray i)).'' decf(symbol) [SAL] (decf symbol) [LISP] Decrement symbol by one. (See incf, above.) push(val, lis) [SAL] (push val lis) [LISP] Push val onto lis (a Lisp list). This is a macro that is equivalent to writing (in Lisp) (setf lis (cons val lis)). pop(lis) [SAL] (pop lis) [LISP] Remove (pop) the first item from lis (a Lisp list). This is a macro that is equivalent to writing (in Lisp) (setf lis (cdr lis)). Note that the remaining list is returned, not the head of the list that has been popped. Retrieve the head of the list (i.e. the top of the stack) using first or, equivalently, car. The following macros are useful control constructs. while(test, expr1, expr2, ...) [SAL] (while test expr1 expr2 ...) [LISP] A conventional ``while'' loop. If test is true, evaluate expressions (expr1, expr2, etc.) and repeat. If test is false, return. This expression evaluates to NIL unless the expression (return expr) is evaluated, in which case the value of expr is returned. In SAL, the loop statement is preferred. when(test, action) [SAL] (when test action) [LISP] A conventional ``if-then'' statement. If test is true, action is evaluated and returned. Otherwise, NIL is returned. (Use if or cond to implement ``if-then-else'' and more complex conditional forms. It is often necessary to load a file only if it has not already been loaded. For example, the pianosyn library loads very slowly, so if some other file already loaded it, it would be good to avoid loading it again. How can you load a file once? Nyquist does not keep track of files that are loaded, but you must be loading a file to define some function, so the idea is to tell Nyquist "I require function from file"; if the function does not yet exist, Nyquist satisfies the requirement by loading the file. require-from(fnsymbol, filename [, path]) [SAL] (require-from fnsymbol filename [path]) [LISP] Tests whether fnsymbol, an unquoted function name, is defined. If not, filename, a STRING, is loaded. Normally fnsymbol is a function that will be called from within the current file, and filename is the file that defines fnsymbol. The path, if a STRING, is prepended to filename. If path is t (true), then the directory of the current file is used as the path. Sometimes it is important to load files relative to the current file. For example, the lib/piano.lsp library loads data files from the lib/piano directory, but how can we find out the full path of lib? The solution is: current-path() [SAL] (current-path) [LISP] Returns the full path name of the file that is currently being loaded (see load). Returns NIL if no file is being loaded. Finally, there are some helpful math functions: real-random(from, to) [SAL] (real-random from to) [LISP] Returns a random FLONUM between from and to. (See also rrandom, which is equivalent to (real-random 0 1)). power(x, y) [SAL] (power x y) [LISP] Returns x raised to the y power. 13. Xmusic and Algorithmic Composition Several Nyquist libraries offer support for algorithmic composition. Xmusic is a library for generating sequences and patterns of data. Included in Xmusic is the score-gen macro which helps to generate scores from patterns. Another important facility is the distributions.lsp library, containing many different random number generators. 13.1. Xmusic Basics Xmusic is inspired by and based on Common Music by Rick Taube. Currently, Xmusic only implements patterns and some simple support for scores to be realized as sound by Nyquist. In contrast, Common Music supports MIDI and various other synthesis languages and includes a graphical interface, some visualization tools, and many other features. Common Music runs in Common Lisp and Scheme, but not XLISP, which is the base language for Nyquist. Xmusic patterns are objects that generate data streams. For example, the cycle-class of objects generate cyclical patterns such as "1 2 3 1 2 3 1 2 3 ...", or "1 2 3 4 3 2 1 2 3 4 ...". Patterns can be used to specify pitch sequences, rhythm, loudness, and other parameters. Xmusic functions are automatically loaded when you start Nyquist. To use a pattern object, you first create the pattern, e.g. set pitch-source = make-cycle(list(c4, d4, e4, f4)) After creating the pattern, you can access it repeatedly with next to generate data, e.g. play seqrep(i, 13, pluck(next(pitch-source), 0.2)) This will create a sequence of notes with the following pitches: c, d, e, f, c, d, e, f, c, d, e, f, c. If you evaluate this again, the pitch sequence will continue, starting on "d". It is very important not to confuse the creation of a sequence with its access. Consider this example: play seqrep(i, 13, pluck(next(make-cycle(list(c4, d4, e4, f4))), 0.2)) This looks very much like the previous example, but it only repeats notes on middle-C. The reason is that every time pluck is evaluated, make-cycle is called and creates a new pattern object. After the first item of the pattern is extracted with next, the cycle is not used again, and no other items are generated. To summarize this important point, there are two steps to using a pattern. First, the pattern is created and stored in a variable using setf. Second, the pattern is accessed (multiple times) using next. Patterns can be nested, that is, you can write patterns of patterns. In general, the next function does not return patterns. Instead, if the next item in a pattern is a (nested) pattern, next recursively gets the next item of the nested pattern. While you might expect that each call to next would advance the top-level pattern to the next item, and descend recursively if necessary to the inner-most nesting level, this is not how next works. Instead, next remembers the last top-level item, and if it was a pattern, next continues to generate items from that same inner pattern until the end of the inner pattern's period is reached. The next paragraph explains the concept of the period. The data returned by a pattern object is structured into logical groups called periods. You can get an entire period (as a list) by calling next(pattern, t). For example: set pitch-source = make-cycle(list(c4, d4, e4, f4)) print next(pitch-source, t) This prints the list (60 62 64 65), which is one period of the cycle. You can also get explicit markers that delineate periods by calling send(pattern, :next). In this case, the value returned is either the next item of the pattern, or the symbol +eop+ if the end of a period has been reached. What determines a period? This is up to the specific pattern class, so see the documentation for specifics. You can override the ``natural'' period using the keyword for:, e.g. set pitch-source = make-cycle(list(c4, d4, e4, f4), for: 3) print next(pitch-source, t) print next(pitch-source, t) This prints the lists (60 62 64) (65 60 62). Notice that these periods just restructure the stream of items into groups of 3. Nested patterns are probably easier to understand by example than by specification. Here is a simple nested pattern of cycles: set cycle-1 = make-cycle({a b c}) set cycle-2 = make-cycle({x y z}) set cycle-3 = make-cycle(list(cycle-1, cycle-2)) exec dotimes(i, 9, format(t, "~A ", next(cycle-3))) This will print "A B C X Y Z A B C". Notice that the inner-most cycles cycle-1 and cycle-2 generate a period of items before the top-level cycle-3 advances to the next pattern. Before describing specific pattern classes, there are several optional parameters that apply in the creating of any pattern object. These are: for: The length of a period. This overrides the default by providing a numerical length. The value of this optional parameter may be a pattern that generates a sequence of integers that determine the length of each successive period. A period length may not be negative, but it may be zero. name: A pattern object may be given a name. This is useful if the trace: option is used. trace: If non-null, this optional parameter causes information about the pattern to be printed each time an item is generated from the pattern. The built-in pattern classes are described in the following section. 13.2. Pattern Classes 13.2.1. cycle The cycle-class iterates repeatedly through a list of items. For example, two periods of make-cycle({a b c}) would be (A B C) (A B C). make-cycle(items, for: for, name: name, trace: trace) [SAL] (make-cycle items :for for :name name :trace trace) [LISP] Make a cycle pattern that iterates over items. The default period length is the length of items. (See above for a description of the optional parameters.) If items is a pattern, a period of the pattern becomes the list from which items are generated. The list is replaced every period of the cycle. 13.2.2. line The line-class is similar to the cycle class, but when it reaches the end of the list of items, it simply repeats the last item in the list. For example, two periods of make-line({a b c}) would be (A B C) (C C C). make-line(items, for: for, name: name, trace: trace) [SAL] (make-line items :for for :name name :trace trace) [LISP] Make a line pattern that iterates over items. The default period length is the length of items. As with make-cycle, items may be a pattern. (See above for a description of the optional parameters.) 13.2.3. random The random-class generates items at random from a list. The default selection is uniform random with replacement, but items may be further specified with a weight, a minimum repetition count, and a maximum repetition count. Weights give the relative probability of the selection of the item (with a default weight of one). The minimum count specifies how many times an item, once selected at random, will be repeated. The maximum count specifies the maximum number of times an item can be selected in a row. If an item has been generated n times in succession, and the maximum is equal to n, then the item is disqualified in the next random selection. Weights (but not currently minima and maxima) can be patterns. The patterns (thus the weights) are recomputed every period. make-random(items, for: for, name: name, trace: trace) [SAL] (make-random items :for for :name name :trace trace) [LISP] Make a random pattern that selects from items. Any (or all) element(s) of items may be lists of the following form: (value :weight weight :min mincount :max maxcount), where value is the item (or pattern) to be generated, weight is the (optional) relative probability of selecting this item, mincount is the (optional) minimum number of repetitions when this item is selected, and maxcount is the (optional) maximum number of repetitions allowed before selecting some other item. The default period length is the length of items. If items is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. 13.2.4. palindrome The palindrome-class repeatedly traverses a list forwards and then backwards. For example, two periods of make-palindrome({a b c}) would be (A B C C B A) (A B C C B A). The elide: keyword parameter controls whether the first and/or last elements are repeated: make-palindrome({a b c}, elide: nil) ;; generates A B C C B A A B C C B A ... make-palindrome({a b c}, elide: t) ;; generates A B C B A B C B ... make-palindrome({a b c}, elide: :first) ;; generates A B C C B A B C C B ... make-palindrome({a b c}, elide: :last) ;; generates A B C B A A B C B A ... make-palindrome(items, elide: elide, for: for, name: name, trace: trace) [SAL] (make-palindrome items :elide elide :for for :name name :trace trace) [LISP] Generate items from list alternating in-order and reverse-order sequencing. The keyword parameter elide can have the values :first, :last, t, or nil to control repetition of the first and last elements. The elide parameter can also be a pattern, in which case it is evaluated every period. One period is one complete forward and backward traversal of the list. If items is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. 13.2.5. heap The heap-class selects items in random order from a list without replacement, which means that all items are generated once before any item is repeated. For example, two periods of make-heap({a b c}) might be (C A B) (B A C). Normally, repetitions can occur even if all list elements are distinct. This happens when the last element of a period is chosen first in the next period. To avoid repetitions, the max: keyword argument can be set to 1. The max: keyword only controls repetitions from the end of one period to the beginning of the next. If the list contains more than one copy of the same value, it may be repeated within a period regardless of the value of max:. make-heap(items, for: for, max: max, name: name, trace: trace) [SAL] (make-heap items :for for :max max :name name :trace trace) [LISP] Generate items randomly from list without replacement. If max is 1, the first element of a new period will not be the same as the last element of the previous period, avoiding repetition. The default value of max is 2, meaning repetition is allowed. The period length is the length of items. If items is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. 13.2.6. accumulation The accumulation-class takes a list of values and returns the first, followed by the first two, followed by the first three, etc. In other words, for each list item, return all items from the first through the item. For example, if the list is (A B C), each generated period is (A A B A B C). make-accumulation(items, name: name, trace: trace) [SAL] (make-accumulation items :name name :trace trace) [LISP] For each item, generate items from the first to the item including the 2 item. The period length is (n + n) / 2 where n is the length of items. If items is a pattern, a period from that pattern becomes the list from which items are generated, and a new list is generated every period. Note that this is similar in name but different from make-accumulate. 13.2.7. copier The copier-class makes copies of periods from a sub-pattern. For example, three periods of make-copier(make-cycle({a b c}, for: 1), repeat: 2, merge: t) would be (A A) (B B) (C C). Note that entire periods (not individual items) are repeated, so in this example the for: keyword was used to force periods to be of length one so that each item is repeated by the repeat: count. make-copier(sub-pattern, repeat: repeat, merge: merge, for: for, name: name, trace: trace) [SAL] (make-copier sub-pattern :repeat repeat :merge merge :for for :name name :trace trace) [LISP] Generate a period from sub-pattern and repeat it repeat times. If merge is false (the default), each repetition of a period from sub-pattern results in a period by default. If merge is true (non-null), then all repeat repetitions of the period are merged into one result period by default. If the for: keyword is used, the same items are generated, but the items are grouped into periods determined by the for: parameter. If the for: parameter is a pattern, it is evaluated every result period. The repeat and merge values may be patterns that return a repeat count and a boolean value, respectively. If so, these patterns are evaluated initially and after each repeat copies are made (independent of the for: keyword parameter, if any). The repeat value returned by a pattern can also be negative. A negative number indicates how many periods of sub-pattern to skip. After skipping these patterns, new repeat and merge values are generated. 13.2.8. accumulate The accumulate-class forms the sum of numbers returned by another pattern. For example, each period of make-accumulate(make-cycle({1 2 -3})) is (1 3 0). The default output period length is the length of the input period. make-accumulate(sub-pattern, for: for, max: maximum, min: minimum, name: name, trace: trace) [SAL] (make-accumulate sub-pattern :for for :max maximum :min minimum :name name :trace trace) [LISP] Keep a running sum of numbers generated by sub-pattern. The default period lengths match the period lengths from sub-pattern. If maximum (a pattern or a number) is specified, and the running sum exceeds maximum, the running sum is reset to maximum. If minimum (a pattern or a number) is specified, and the running sum falls below minimum, the running sum is reset to minimum. If minimum is greater than maximum, the running sum will be set to one of the two values. Note that this is similar in name but not in function to make-accumulation. 13.2.9. sum The sum-class forms the sum of numbers, one from each of two other patterns. For example, each period of make-sum(make-cycle({1 2 3}), make-cycle({4 5 6})) is (5 7 9). The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number. make-sum(x, y, for: for, name: name, trace: trace) [SAL] (make-sum x y :for for :name name :trace trace) [LISP] Form sums of items (which must be numbers) from pattern x and pattern or number y. The default period lengths match the period lengths from x. 13.2.10. product The product-class forms the product of numbers, one from each of two other patterns. For example, each period of make-product(make-cycle({1 2 3}), make-cycle({4 5 6})) is (4 10 18). The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number. make-product(x, y, for: for, name: name, trace: trace) [SAL] (make-product x y :for for :name name :trace trace) [LISP] Form products of items (which must be numbers) from pattern x and pattern or number y. The default period lengths match the period lengths from x. 13.2.11. eval The eval-class evaluates an expression to produce each output item. The default output period length is 1. make-eval(expr, for: for, name: name, trace: trace) [SAL] (make-eval expr :for for :name name :trace trace) [LISP] Evaluate expr to generate each item. If expr is a pattern, each item is generated by getting the next item from expr and evaluating it. 13.2.12. length The length-class generates periods of a specified length from another pattern. This is similar to using the for: keyword, but for many patterns, the for: parameter alters the points at which other patterns are generated. For example, if the palindrome pattern has an elide: pattern parameter, the value will be computed every period. If there is also a for: parameter with a value of 2, then elide: will be recomputed every 2 items. In contrast, if the palindrome (without a for: parameter) is embedded in a length pattern with a lenght of 2, then the periods will all be of length 2, but the items will come from default periods of the palindrome, and therefore the elide: values will be recomputed at the beginnings of default palindrome periods. make-length(pattern, length-pattern, name: name, trace: trace) [SAL] (make-length pattern length-pattern :name name :trace trace) [LISP] Make a pattern of class length-class that regroups items generated by a pattern according to pattern lengths given by length-pattern. Note that length-pattern is not optional: There is no default pattern length and no for: keyword. 13.2.13. window The window-class groups items from another pattern by using a sliding window. If the skip value is 1, each output period is formed by dropping the first item of the previous perioda and appending the next item from the pattern. The skip value and the output period length can change every period. For a simple example, if the period length is 3 and the skip value is 1, and the input pattern generates the sequence A, B, C, ..., then the output periods will be (A B C), (B C D), (C D E), (D E F), .... make-window(pattern, length-pattern, skip-pattern, name: name, trace: trace) [SAL] (make-window pattern length-pattern skip-pattern :name name :trace trace) [LISP] Make a pattern of class window-class that regroups items generated by a pattern according to pattern lengths given by length-pattern and where the period advances by the number of items given by skip-pattern. Note that length-pattern is not optional: There is no default pattern length and no for: keyword. 13.2.14. markov The markov-class generates items from a Markov model. A Markov model generates a sequence of states according to rules which specify possible future states given the most recent states in the past. For example, states might be pitches, and each pitch might lead to a choice of pitches for the next state. In the markov-class, states can be either symbols or numbers, but not arbitrary values or patterns. This makes it easier to specify rules. However, symbols can be mapped to arbitrary values including pattern objects, and these become the actual generated items. By default, all future states are weighted equally, but weights may be associated with future states. A Markov model must be initialized with a sequence of past states using the past: keyword. The most common form of Markov model is a "first order Markov model" in which the future item depends only upon one past item. However, higher order models where the future items depend on two or more past items are possible. A "zero-order" Markov model, which depends on no past states, is essentially equivalent to the random pattern. As an example of a first-order Markov pattern, two periods of make-markov({{a -> b c} {b -> c} {c -> a}}, past: {a}) might be (C A C) (A B C). make-markov(rules, past: past, produces: produces, for: for, name: name, trace: trace) [SAL] (make-markov rules past :produces produces :for for :name name :trace trace) [LISP] Generate a sequence of items from a Markov process. The rules parameter has the form: (prev1 prev2 ... prevn -> next1 next2 ... nextn) where prev1 through prevn represent a sequence of most recent (past) states. The symbol * is treated specially: it matches any previous state. If prev1 through prevn (which may be just one state as in the example above) match the previously generated states, this rule applies. Note that every rule must specify the same number of previous states; this number is known as the order of the Markov model. The first rule in rules that applies is used to select the next state. If no rule applies, the next state is NIL (which is a valid state that can be used in rules). Assuming a rule applies, the list of possible next states is specified by next1 through nextn. Notice that these are alternative choices for the next state, not a sequence of future states, and each rule can have any number of choices. Each choice may be the state itself (a symbol or a number), or the choice may be a list consisting of the state and a weight. The weight may be given by a pattern, in which case the next item of the pattern is obtained every time the rule is applied. For example, this rules says that if the previous states were A and B, the next state can be A with a weight of 0.5 or C with an implied weight of 1: (A B -> (A 0.5) C). The default length of the period is the length of rules. The past parameter must be provided. It is a list of states whose length matches the order of the Markov model. The keyword parameter produces may be used to map from state symbols or numbers to other values or patterns. The parameter is a list of alternating symbols and values. For example, to map A to 69 and B to 71, use list(quote(a), 69, quote(b), 71). You can also map symbols to patterns, for example list(quote(a), make-cycle({57 69}), quote(b), make-random({59 71})). The next item of the pattern is is generated each time the Markov model generates the corresponding state. Finally, the produces keyword can be eval:, which means to evaluate the Markov model state. This could be useful if states are Nyquist global variables such as C4, CS4, D4, ]..., which evaluate to numerical values (60, 61, 62, .... markov-create-rules(sequence, order [, generalize]) [SAL] (markov-create-rules sequence order [generalize]) [LISP] Generate a set of rules suitable for the make-markov function. The sequence is a ``typical'' sequence of states, and order is the order of the Markov model. It is often the case that a sample sequence will not have a transition from the last state to any other state, so the generated Markov model can reach a ``dead end'' where no rule applies. This might lead to an infinite stream of NIL's. To avoid this, the optional parameter generalize can be set to t (true), indicating that there should be a fallback rule that matches any previous states and whose future states are weighted according to their frequency in sequence. For example, if sequence contains 5 A's, 5 B's and 10 G's, the default rule will be (* -> (A 5) (B 5) (G 10)). This rule will be appended to the end so it will only apply if no other rule does. 13.3. Random Number Generators The distributions.lsp library implements random number generators that return random values with various probability distributions. Without this library, you can generate random numbers with uniform distributions. In a uniform distribution, all values are equally likely. To generate a random integer in some range, use random. To generate a real number (FLONUM) in some range, use real-random (or rrandom if the range is 0-1). But there are other interesting distributions. For example, the Gaussian distribution is often used to model real-world errors and fluctuations where values are clustered around some central value and large deviations are more unlikely than small ones. See Dennis Lorrain, "A Panoply of Stochastic 'Canons'," Computer Music Journal vol. 4, no. 1, 1980, pp. 53-81. In most of the random number generators described below, there are optional parameters to indicate a maximum and/or minimum value. These can be used to truncate the distribution. For example, if you basically want a Gaussian distribution, but you never want a value greater than 5, you can specify 5 as the maximum value. The upper and lower bounds are implemented simply by drawing a random number from the full distribution repeatedly until a number falling into the desired range is obtained. Therefore, if you select an acceptable range that is unlikely, it may take Nyquist a long time to find each acceptable random number. The intended use of the upper and lower bounds is to weed out values that are already fairly unlikely. linear-dist(g) [SAL] (linear-dist g) [LISP] Return a FLONUM value from a linear distribution, where the probability of a value decreases linearly from zero to g which must be greater than zero. (See Figure 7.) The linear distribution is useful for generating for generating time and pitch intervals. Figure 7: The Linear Distribution, g = 1. exponential-dist(delta [, high]) [SAL] (exponential-dist delta [high]) [LISP] Return a FLONUM value from an exponential distribution. The initial downward slope is steeper with larger values of delta, which must be greater than zero. (See Figure 8. The optional high parameter puts an artificial upper bound on the return value. The exponential distribution generates values greater than 0, and can be used to generate time intervals. Natural random intervals such as the time intervals between the release of atomic particles or the passing of yellow volkswagons in traffic have exponential distributions. The exponential distribution is memory-less: knowing that a random number from this distribution is greater than some value (e.g. a note duration is at least 1 second) tells you nothing new about how soon the note will end. This is a continuous distribution, but geometric-dist (described below) implements the discrete form. Figure 8: The Exponential Distribution, delta = 1. gamma-dist(nu [, high]) [SAL] (gamma-dist nu [high]) [LISP] Return a FLONUM value from a Gamma distribution. The value is greater than zero, has a mean of nu (a FIXNUM greater than zero), and a mode (peak) of around nu - 1. The optional high parameter puts an artificial upper bound on the return value. Figure 9: The Gamma Distribution, nu = 4. bilateral-exponential-dist(xmu, tau [, low, high]) [SAL] (bilateral-exponential-dist xmu tau [low high]) [LISP] Returns a FLONUM value from a bilateral exponential distribution, where xmu is the center of the double exponential and tau controls the spread of the distribution. A larger tau gives a wider distribution (greater variance), and tau must be greater than zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively. This distribution is similar to the exponential, except it is centered at 0 and can output negative values as well. Like the exponential, it can be used to generate time intervals; however, it might be necessary to add a lower bound so as not to compute a negative time interval. Figure 10: The Bilateral Exponential Distribution. cauchy-dist(tau [, low, high]) [SAL] (cauchy-dist tau [low high]) [LISP] Returns a FLONUM from the Cauchy distribution, a symetric distribution with a high peak at zero and a width (variance) that increases with parameter tau, which must be greater than zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively. Figure 11: The Cauchy Distribution, tau = 1. hyperbolic-cosine-dist([low, high]) [SAL] (hyperbolic-cosine-dist [low high)] [LISP] Returns a FLONUM value from the hyperbolic cosine distribution, a symetric distribution with its peak at zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively. Figure 12: The Hyperbolic Cosine Distribution. logistic-dist(alpha, beta [, low, high]) [SAL] (logistic-dist alpha beta [low high]) [LISP] Returns a FLONUM value from the logistic distribution, which is symetric about the mean. The alpha parameter primarily affects dispersion (variance), with larger values resulting in values closer to the mean (less variance), and the beta parameter primarily influences the mean. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively. Figure 13: The Logistic Distribution, alpha = 1, beta = 2. arc-sine-dist() [SAL] (arc-sine-dist) [LISP] Returns a FLONUM value from the arc sine distribution, which outputs values between 0 and 1. It is symetric about the mean of 1/2, but is more likely to generate values closer to 0 and 1. Figure 14: The Arc Sine Distribution. gaussian-dist(xmu, sigma [, low, high]) [SAL] (gaussian-dist xmu sigma [low high]) [LISP] Returns a FLONUM value from the Gaussian or Gauss-Laplace distribution, a linear function of the normal distribution. It is symetric about the mean of xmu, with a standard deviation of sigma, which must be greater than zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively. Figure 15: The Gauss-Laplace (Gaussian) Distribution, xmu = 0, sigma = 1. beta-dist(a, b) [SAL] (beta-dist a b) [LISP] Returns a FLONUM value from the Beta distribution. This distribution outputs values between 0 and 1, with outputs more likely to be close to 0 or 1. The parameter a controls the height (probability) of the right side of the distribution (at 1) and b controls the height of the left side (at 0). The distribution is symetric about 1/2 when a = b. Figure 16: The Beta Distribution, alpha = .5, beta = .25. bernoulli-dist(px1 [, x1, x2]) [SAL] (bernoulli-dist px1 [x1 x2]) [LISP] Returns either x1 (default value is 1) with probability px1 or x2 (default value is 0) with probability 1 - px1. The value of px1 should be between 0 and 1. By convention, a result of x1 is viewed as a success while x2 is viewed as a failure. Figure 17: The Bernoulli Distribution, px1 = .75. binomial-dist(n, p) [SAL] (binomial-dist n p) [LISP] Returns a FIXNUM value from the binomial distribution, where n is the number of Bernoulli trials run (a FIXNUM) and p is the probability of success in the Bernoulli trial (a FLONUM from 0 to 1). The mean is the product of n and p. Figure 18: The Binomial Distribution, n = 5, p = .5. geometric-dist(p) [SAL] (geometric-dist p) [LISP] Returns a FIXNUM value from the geometric distribution, which is defined as the number of failures before a success is achieved in a Bernoulli trial with probability of success p (a FLONUM from 0 to 1). Figure 19: The Geometric Distribution, p = .4. poisson-dist(delta) [SAL] (poisson-dist delta) [LISP] Returns a FIXNUM value from the Poisson distribution with a mean of delta (a FIXNUM). The Poisson distribution is often used to generate a sequence of time intervals, resulting in random but often pleasing rhythms. Figure 20: The Poisson Distribution, delta = 3. 13.4. Score Generation and Manipulation A common application of pattern generators is to specify parameters for notes. (It should be understood that ``notes'' in this context means any Nyquist behavior, whether it represents a conventional note, an abstract sound object, or even some micro-sound event that is just a low-level component of a hierarchical sound organization. Similarly, ``score'' should be taken to mean a specification for a sequence of these ``notes.'') The score-gen macro (defined by loading xm.lsp) establishes a convention for representing scores and for generating them using patterns. The timed-seq macro, described in Section 7.4, already provides a way to represent a ``score'' as a list of expressions. The Xmusic representation goes a bit further by specifying that all notes are specified by an alternation of keywords and values, where some keywords have specific meanings and interpretations. The basic idea of score-gen is you provide a template for notes in a score as a set of keywords and values. For example, set pitch-pattern = make-cycle(list(c4, d4, e4, f4)) score-gen(dur: 0.4, name: quote(my-sound), pitch: next(pitch-pattern), score-len: 9) generates a score of 9 notes as follows: ((0 0 (SCORE-BEGIN-END 0 3.6)) (0 0.4 (MY-SOUND :PITCH 60)) (0.4 0.4 (MY-SOUND :PITCH 62)) (0.8 0.4 (MY-SOUND :PITCH 64)) (1.2 0.4 (MY-SOUND :PITCH 65)) (1.6 0.4 (MY-SOUND :PITCH 60)) (2 0.4 (MY-SOUND :PITCH 62)) (2.4 0.4 (MY-SOUND :PITCH 64)) (2.8 0.4 (MY-SOUND :PITCH 65)) (3.2 0.4 (MY-SOUND :PITCH 60))) The use of keywords like :PITCH helps to make scores readable and easy to process without specific knowledge of about the functions called in the score. For example, one could write a transpose operation to transform all the :pitch parameters in a score without having to know that pitch is the first parameter of pluck and the second parameter of piano-note. Keyword parameters are also used to give flexibility to note specification with score-gen. Since this approach requires the use of keywords, the next section is a brief explanation of how to define functions that use keyword parameters. 13.4.1. Keyword Parameters Keyword parameters are parameters whose presence is indicated by a special symbol, called a keyword, followed by the actual parameter. Keyword parameters in SAL have default values that are used if no actual parameter is provided by the caller of the function. (See Appendix IV to learn about keywords in XLISP.) To specify that a parameter is a keyword parameter, use a keyword symbol (one that ends in a colon) followed by a default value. For example, here is a function that accepts keyword parameters and invokes the pluck function: define function k-pluck(pitch: 60, dur: 1) return pluck(pitch, dur) Now, we can call k-pluck with keyword parameters. The keywords are simply the formal parameter names with a prepended colon character (:pitch and :dur in this example), so a function call would look like: pluck(pitch: c3, dur: 3) Usually, it is best to give keyword parameters useful default values. That way, if a parameter such as dur: is missing, a reasonable default value (1) can be used automatically. It is never an error to omit a keyword parameter, but the called function can check to see if a keyword parameter was supplied or not. Because of default values, we can call k-pluck(pitch: c3) with no duration, k-pluck(dur: 3) with only a duration, or even k-pluck() with no parameters. In XLISP, there is additional syntax to specify an alternate symbol to be used as the keyword and to allow the called function to determine whether or not a keyword parameter was supplied, but these features are little-used. See the XLISP manual for details. 13.4.2. Using score-gen The score-gen macro computes a score based on keyword parameters. Some keywords have a special meaning, while others are not interpreted but merely placed in the score. The resulting score can be synthesized using timed-seq (see Section 7.4). The form of a call to score-gen is simply: score-gen(k1: e1, k2: e2, ...) [SAL] (score-gen :k1 e1 :k2 e2 ...) [LISP] where the k's are keywords and the e's are expressions. A score is generated by evaluating the expressions once for each note and constructing a list of keyword-value pairs. A number of keywords have special interpretations. The rules for interpreting these parameters will be explained through a set of "How do I ..." questions below. How many notes will be generated? The keyword parameter score-len: specifies an upper bound on the number of notes. (Note: in LISP syntax, keywords are always preceded by colons, so you would write :score-len instead.) The keyword score-dur: specifies an upper bound on the starting time of the last note in the score. (To be more precise, the score-dur: bound is reached when the default starting time of the next note is greater than or equal to the score-dur: value. This definition is necessary because note times are not strictly increasing.) When either bound is reached, score generation ends. At least one of these two parameters must be specified or an error is raised. These keyword parameters are evaluated just once and are not copied into the parameter lists of generated notes. What is the duration of generated notes? The keyword dur: defaults to 1 and specifies the nominal duration in seconds. Since the generated note list is compatible with timed-seq, the starting time and duration (to be precise, the stretch factor) are not passed as parameters to the notes. Instead, they control the Nyquist environment in which the note will be evaluated. What is the start time of a note? The default start time of the first note is zero. Given a note, the default start time of the next note is the start time plus the inter-onset time, which is given by the ioi: parameter. If no ioi: parameter is specified, the inter-onset time defaults to the duration, given by dur:. In all cases, the default start time of a note can be overridden by the keyword parameter time:. When does the score begin and end? The behavior SCORE-BEGIN-END contains the beginning and ending of the score (these are used for score manipulations, e.g. when scores are merged, their begin times can be aligned.) When timed-seq is used to synthesize a score, the SCORE-BEGIN-END marker is not evaluated. The score-gen macro inserts a ``note'' of the form (0 0 (SCORE-BEGIN-END begin-time end-time)) at the time given by the begin: keyword, with begin-time and end-time determined by the begin: and end: keyword parameters, respectively. If the begin: keyword is not provided, the score begins at zero. If the end: keyword is not provided, the score ends at the default start time of what would be the next note after the last note in the score (as described in the previous paragraph). Note: if time: is used to compute note starting times, and these times are not increasing, it is strongly advised to use end: to specify an end time for the score, because the default end time may be anywhere in the middle of the generated sequence. What function is called to synthesize the note? The name: parameter names the function. Like other parameters, the value can be any expression, including something like next(fn-name-pattern), allowing function names to be recomputed for each note. The default value is note. Can I make parameters depend upon the starting time or the duration of the note? Parameter expressions can use the variable sg:time to access the start time of the note, sg:ioi to access the inter-onset time, and sg:dur to access the duration (stretch factor) of the note. Also, sg:count counts how many notes have been computed so far, starting at 0. The order of computation is: sg:time first, then sg:ioi and sg:dur, so for example, an expression to compute sg:dur can depend on sg:ioi. Can parameters depend on each other? The keyword pre: introduces an expression that is evaluated before each note, and post: provides an expression to be evaluated after each note. The pre: expression can assign one or more global variables which are then used in one or more expressions for parameters. How do I debug score-gen expressions? You can set the trace: parameter to true (t) to enable a print statement for each generated note. How can I save scores generated by score-gen that I like? If the keyword parameter save: is set to a symbol, the global variable named by the symbol is set to the value of the generated sequence. Of course, the value returned by score-gen is just an ordinary list that can be saved like any other value. In summary, the following keywords have special interpretations in score-gen: begin:, end:, time:, dur:, name:, ioi:, trace:, save:, score-len:, score-dur:, pre:, post:. All other keyword parameters are expressions that are evaluated once for each note and become the parameters of the notes. 13.4.3. Score Manipulation Nyquist encourages the representation of music as executable programs, or behaviors, and there are various ways to modify behaviors, including time stretching, transposition, etc. An alternative to composing executable programs is to manipulate scores as editable data. Each approach has its strengths and weaknesses. This section describes functions intended to manipulate Xmusic scores as generated by, or at least in the form generated by, score-gen. Recall that this means scores are lists of events (e.g. notes), where events are three-element lists of the form (time duration expression, and where expression is a standard lisp function call where all parameters are keyword parameters. In addition, the first ``note'' may be the special SCORE-BEGIN-END expression. If this is missing, the score begins at zero and ends at the end of the last note. For convenience, a set of functions is offered to access properties of events (or notes) in scores. Although lisp functions such as car, cadr, and caddr can be used, code is more readable when more mnemonic functions are used to access events. event-time(event) [SAL] (event-time event) [LISP] Retrieve the time field from an event. event-set-time(event, time) [SAL] (event-set-time event time) [LISP] Construct a new event where the time of event is replaced by time. event-dur(event) [SAL] (event-dur event) [LISP] Retrieve the duration (i.e. the stretch factor) field from an event. event-set-dur(event, dur) [SAL] (event-set-dur event dur) [LISP] Construct a new event where the duration (or stretch factor) of event is replaced by dur. event-expression(event) [SAL] (event-expression event) [LISP] Retrieve the expression field from an event. event-set-expression(event, dur) [SAL] (event-set-expression event dur) [LISP] Construct a new event where the expression of event is replaced by expression. event-end(event) [SAL] (event-end event) [LISP] Retrieve the end time of event, its time plus its duration. expr-has-attr(expression, attribute) [SAL] (expr-has-attr expression attribute) [LISP] Test whether a score event expression has the given attribute. expr-get-attr(expression, attribute [, default]) [SAL] (expr-get-attr expression attribute [default]) [LISP] Get the value of the given attribute from a score event expression. If attribute is not present, return default if specified, and otherwise nil. expr-set-attr(expr, attribute, value) [SAL] (expr-set-attr expr attribute value) [LISP] Construct a new expression identical to expr except that the attribute has value. event-has-attr(event, attribute) [SAL] (event-has-attr event attribute) [LISP] Test whether a given score event's expression has the given attribute. event-get-attr(event, attribute, [default]) [SAL] (event-get-attr event attribute [default]) [LISP] Get the value of the given attribute from a score event's expression. If attribute is not present, return default if specified, and otherwise nil. event-set-attr(event, attribute, value) [SAL] (event-set-attr event attribute value) [LISP] Construct a new event identical to event except that the attribute has value. Functions are provided to shift the starting times of notes, stretch times and durations, stretch only durations, add an offset to a keyword parameter, scale a keyword parameter, and other manipulations. Functions are also provided to extract ranges of notes, notes that match criteria, and to combine scores. Most of these functions (listed below in detail) share a set of keyword parameters that optionally limit the range over which the transformation operates. The from-index: and to-index: parameters specify the index of the first note and the index of the last note to be changed. If these numbers are negative, they are offsets from the end of the score, e.g. -1 denotes the last note of the score. The from-time: and to-time: indicate a range of starting times of notes that will be affected by the manipulation. Only notes whose time is greater than or equal to the from-time and strictly less than the to-time are modified. If both index and time ranges are specified, only notes that satisfy both constraints are selected. (Note: in LISP syntax, colons precede the keyword, so use :from-index, :to-index, :from-time, and :to-time.) score-sorted(score) [SAL] (score-sorted score) [LISP] Test if score is sorted. score-sort(score [, copy-flag]) [SAL] (score-sort score [copy-flag]) [LISP] Sort the notes in a score into start-time order. If copy-flag is nil, this is a destructive operation which should only be performed if the top-level score list is a fresh copy that is not shared by any other variables. (The copy-flag is intended for internal system use only.) For the following operations, it is assumed that scores are sorted, and all operations return a sorted score. score-shift(score, offset, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-shift score offset :from-index i :to-index j :from-time x :to-time y) [LISP] Add a constant offset to the starting time of a set of notes in score. By default, all notes are modified, but the range of notes can be limited with the keyword parameters. The begin time of the score is not changed, but the end time is increased by offset. The original score is not modified, and a new score is returned. score-stretch(score, factor, dur: dur-flag, time: time-flag, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-stretch score factor :dur dur-flag :time time-flag :from-index i :to-index j :from-time x :to-time y) [LISP] Stretch note times and durations by factor. The default dur-flag is non-null, but if dur-flag is null, the original durations are retained and only times are stretched. Similarly, the default time-flag is non-null, but if time-flag is null, the original times are retained and only durations are stretched. If both dur-flag and time-flag are null, the score is not changed. If a range of notes is specified, times are scaled within that range, and notes after the range are shifted so that the stretched region does not create a "hole" or overlap with notes that follow. If the range begins or ends with a time (via from-time: and to-time:), time stretching takes place over the indicated time interval independent of whether any notes are present or where they start. In other words, the ``rests'' are stretched along with the notes. The original score is not modified, and a new score is returned. score-transpose(score, keyword, amount, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-transpose score keyword amount :from-index i :to-index j :from-time x :to-time y) [LISP] For each note in the score and in any indicated range, if there is a keyword parameter matching keyword and the parameter value is a number, increment the parameter value by amount. For example, to tranpose up by a whole step, write (score-transpose 2 :pitch score). The original score is not modified, and a new score is returned. score-scale(score, keyword, amount, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-scale score keyword amount :from-index i :to-index j :from-time x :to-time y) [LISP] For each note in the score and in any indicated range, if there is a keyword parameter matching keyword and the parameter value is a number, multiply the parameter value by amount. The original score is not modified, and a new score is returned. score-sustain(score, factor, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-sustain score factor :from-index i :to-index j :from-time x :to-time y) [LISP] For each note in the score and in any indicated range, multiply the duration (stretch factor) by amount. This can be used to make notes sound more legato or staccato, and does not change their starting times. The original score is not modified, and a new score is returned. score-voice(score, replacement-list, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-voice score replacement-list :from-index i :to-index j :from-time x :to-time y) [LISP] For each note in the score and in any indicated range, replace the behavior (function) name using replacement-list, which has the format: ((old1 new1) (old2 new2) ...), where oldi indicates a current behavior name and newi is the replacement. If oldi is *, it matches anything. For example, to replace my-note-1 by trombone and my-note-2 by horn, use score-voice(score, {{my-note-1 trombone} {my-note-2 horn}}). To replace all instruments with piano, use score-voice(score, {{* piano}}). The original score is not modified, and a new score is returned. score-merge(score1, score2, ...) [SAL] (score-merge score1 score2 ...) [LISP] Create a new score containing all the notes of the parameters, which are all scores. The resulting notes retain their original times and durations. The merged score begin time is the minimum of the begin times of the parameters and the merged score end time is the maximum of the end times of the parameters. The original scores are not modified, and a new score is returned. score-append(score1, score2, ...) [SAL] (score-append score1 score2 ...) [LISP] Create a new score containing all the notes of the parameters, which are all scores. The begin time of the first score is unaltered. The begin time of each other score is aligned to the end time of the previous score; thus, scores are ``spliced'' in sequence. The original scores are not modified, and a new score is returned. score-select(score, predicate, from-index: i, to-index: j, from-time: x, to-time: y, reject: flag) [SAL] (score-select score predicate :from-index i :to-index j :from-time x :to-time y :reject flag) [LISP] Select (or reject) notes to form a new score. Notes are selected if they fall into the given ranges of index and time and they satisfy predicate, a function of three parameters that is applied to the start time, duration, and the expression of the note. Alternatively, predicate may be t, indicating that all notes in range are to be selected. The selected notes along with the existing score begin and end markers, are combined to form a new score. Alternatively, if the reject: parameter is non-null, the notes not selected form the new score (in other words the selected notes are rejected or removed to form the new score). The original score is not modified, and a new score is returned. score-set-begin(score, time) [SAL] (score-set-begin score time) [LISP] The begin time from the score's SCORE-BEGIN-END marker is set to time. The original score is not modified, and a new score is returned. score-get-begin(score) [SAL] (score-get-begin score) [LISP] Return the begin time of the score. score-set-end(score, time) [SAL] (score-set-end score time) [LISP] The end time from the score's SCORE-BEGIN-END marker is set to time. The original score is not modified, and a new score is returned. score-get-end(score) [SAL] (score-get-end score) [LISP] Return the end time of the score. score-must-have-begin-end(score) [SAL] (score-must-have-begin-end score) [LISP] If score does not have a begin and end time, construct a score with a SCORE-BEGIN-END expression and return it. If score already has a begin and end time, just return the score. The orignal score is not modified. score-filter-length(score, cutoff) [SAL] (score-filter-length score cutoff) [LISP] Remove notes that extend beyond the cutoff time. This is similar to score-select, but the here, events are removed when their nominal ending time (start time plus duration) exceeds the cutoff, whereas the to-time: parameter is compared to the note's start time. The original score is not modified, and a new score is returned. score-repeat(score, n) [SAL] (score-repeat score n) [LISP] Make a sequence of n copies of score. Each copy is shifted to that it's begin time aligns with the end time of the previous copy, as in score-append. The original score is not modified, and a new score is returned. score-stretch-to-length(score, length) [SAL] (score-stretch-to-length score length) [LISP] Stretch the score so that the end time of the score is the score's begin time plus length. The original score is not modified, and a new score is returned. score-filter-overlap(score) [SAL] (score-filter-overlap score) [LISP] Remove overlapping notes (based on the note start time and duration), giving priority to the positional order within the note list (which is also time order). The original score is not modified, and a new score is returned. score-print(score) [SAL] (score-print score) [LISP] Print a score with one note per line. Returns nil. score-play(score) [SAL] (score-play score) [LISP] Play score using timed-seq to convert the score to a sound, and play to play the sound. score-adjacent-events(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-adjacent-events score function :from-index i :to-index j :from-time x :to-time y) [LISP] Call (function A B C), where A, B, and C are consecutive notes in the score. The result replaces B. If the result is nil, B is deleted, and the next call will be (function A C D), etc. The first call is to (function nil A B) and the last is to (function Y Z nil). If there is just one note in the score, (function nil A nil) is called. Function calls are not made if the note is outside of the indicated range. This function allows notes and their parameters to be adjusted according to their immediate context. The original score is not modified, and a new score is returned. score-apply(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-apply score function :from-index i :to-index j :from-time x :to-time y) [LISP] Replace each note in the score with the result of (function time dur expression) (in Lisp) or function(time, dur, expression) (in SAL), where time, dur, and expression are the time, duration, and expression of the note. If a range is indicated, only notes in the range are replaced. The original score is not modified, and a new score is returned. score-indexof(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-indexof score function :from-index i :to-index j :from-time x :to-time y) [LISP] Return the index (position) of the first score event (in range) for which applying function using (function time dur expression) returns true. score-last-indexof(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-last-indexof score function :from-index i :to-index j :from-time x :to-time y) [LISP] Return the index (position) of the last score event (in range) for which applying function using (function time dur expression) returns true. score-randomize-start(score, amt, from-index: i, to-index: j, from-time: x, to-time: y) [SAL] (score-randomize-start score amt :from-index i :to-index j :from-time x :to-time y) [LISP] Alter the start times of notes by a random amount up to plus or minus amt. The original score is not modified, and a new score is returned. 13.4.4. Xmusic and Standard MIDI Files Nyquist has a general facility to read and write MIDI files. You can even translate to and from a text representation, as described in Chapter 10. It is also useful sometimes to read notes from Standard MIDI Files into Xmusic scores and vice versa. At present, Xmusic only translates notes, ignoring the various controls, program changes, pitch bends, and other messages. MIDI notes are translated to Xmusic score events as follows: (time dur (NOTE :chan channel :pitch keynum :vel velocity)), where channel, keynum, and velocity come directly from the MIDI message (channels are numbered starting from zero). Note also that note-off messages are implied by the stretch factor dur which is duration in seconds. score-read-smf(filename) [SAL] (score-read-smf filename) [LISP] Read a standard MIDI file from filename. Return an Xmusic score, or nil if the file could not be opened. The start time is zero, and the end time is the maximum end time of all notes. A very limited interface is offered to extract MIDI program numbers from the file: The global variable *rslt* is set to a list of MIDI program numbers for each channel. E.g. if *rslt* is (0 20 77), then program for channel 0 is 0, for channel 1 is 20, and for channel 2 is 77. Program changes were not found on other channels. The default program number is 0, so in this example, it is not known whether the program 0 on channel 0 is the result of a real MIDI program change command or just a default value. If more than one program change exists on a channel, the last program number is recorded and returned, so this information will only be completely correct when the MIDI file sends single program change per channel before any notes are played. This, however, is a fairly common practice. Note that the list returned as *rslt* can be passed to score-write-smf, described below. score-write-smf(score, filename, [programs]) [SAL] (score-write-smf score filename programs) [LISP] Write a standard MIDI file to filename with notes in score. In this function, every event in the score with a pitch: attribute, regardless of the ``instrument'' (or function name), generates a MIDI note, using the chan: attribute for the channel (default 0) and the vel: attribute for velocity (default 100). There is no facility (in the current implementation) to issue control changes, but to allow different instruments, MIDI programs may be set in two ways. The simplest is to associate programs with channels using the optional programs parameter, which is simply a list of up to 16 MIDI program numbers. Corresponding program change commands are added to the beginning of the MIDI file. If programs has less than 16 elements, program change commands are only sent on the first n channels. The second way to issue MIDI program changes is to add a program: keyword parameter to a note in the score. Typically, the note will have a pitch: of nil so that no actual MIDI note-on message is generated. If program changes and notes have the same starting times, their relative playback order is undefined, and the note may be cut off by an immediately following program change. Therefore, program changes should occur slightly, e.g. 1 ms, before any notes. Program numbers and channels are numbered starting at zero, matching the internal MIDI representation. This may be one less than displayed on MIDI hardware, sequencers, etc. 13.4.5. Workspaces When working with scores, you may find it necessary to save them in files between work sessions. This is not an issue with functions because they are normally edited in files and loaded from them. In contrast, scores are created as Lisp data, and unless you take care to save them, they will be destroyed when you exit the Nyquist program. A simple mechanism called a workspace has been created to manage scores (and any other Lisp data, for that matter). A workspace is just a set of lisp global variables. These variables are stored in the file workspace.lsp. For simplicity, there is only one workspace, and no backups or versions are maintained, but the user is free to make backups and copies of workspace.lsp. To help remember what each variable is for, you can also associate and retrieve a text string with each variable. The following functions manage workspaces. In addition, when a workspace is loaded, you can request that functions be called. For example, the workspace might store descriptions of a graphical interface. When the workspace is loaded, a function might run to convert saved data into a graphical interface. (This is how sliders are saved by the IDE.) add-to-workspace(symbol) [SAL] (add-to-workspace symbol) [LISP] Adds a global variable to the workspace. The symbol should be a (quoted) symbol. save-workspace() [SAL] (save-workspace) [LISP] All global variables in the workspace are saved to workspace.lsp (in the current directory), overwriting the previous file. describe(symbol [, description]) [SAL] (describe symbol [description)] [LISP] If description, a text string, is present, associate description with the variable named by the symbol. If symbol is not already in the workspace, it is added. If description is omitted, the function returns the current description (from a previous call) for symbol. add-action-to-workspace(symbol) [SAL] (add-action-to-workspace symbol) [LISP] Requests that the function named by symbol be called when the workspace is loaded (if the function is defined). To restore a workspace, use the command load "workspace". This restores the values of the workspace variables to the values they had when save-workspace was last called. It also restores the documentation strings, if set, by describe. If you load two or more workspace.lsp files, the variables will be merged into a single workspace. The current set of workspace variables are saved in the list *workspace*. To clear the workspace, set *workspace* to nil. This does not delete any variables, but means that no variables will be saved by save-workspace until variables are added again. Functions to be called are saved in the list *workspace-actions*. to clear the functions, set *workspace-actions* to nil. Restore functions to the list with add-action-to-workspace. 13.4.6. Utility Functions This chapter concludes with details of various utility functions for score manipulation. patternp(expression) [SAL] (patternp expression) [LISP] Test if expression is an Xmusic pattern. params-transpose(params, keyword, amount) [SAL] (params-transpose params keyword amount) [LISP] Add a transposition amount to a score event parameter. The params parameter is a list of keyword/value pairs (not preceded by a function name). The keyword is the keyword of the value to be altered, and amount is a number to be added to the value. If no matching keyword is present in params, then params is returned. Otherwise, a new parameter list is constructed and returned. The original params is not changed. params-scale(params, keyword, amount) [SAL] (params-scale params keyword amount) [LISP] Scale a score event parameter by some factor. This is like params-transpose, only using multiplication. The params list is a list of keyword/value pairs, keyword is the parameter keyword, and amount is the scale factor. interpolate(x, x1, y1, x2, y2) [SAL] (interpolate x x1 y1 x2 y2) [LISP] Linearly interpolate (or extrapolate) between points (x1, y1) and (x2, y2) to compute the y value corresponding to x. intersection(a, b) [SAL] (intersection a b) [LISP] Compute the set intersection of lists a and b. union(a, b) [SAL] (union a b) [LISP] Compute the set union of lists a and b. set-difference(a, b) [SAL] (set-difference a b) [LISP] Compute the set of all elements that are in a but not in b. subsetp(a, b) [SAL] (subsetp a b) [LISP] Returns true iff a is a subset of b, that is, each element of a is a member of b. 14. Nyquist Libraries Nyquist is always growing with new functions. Functions that are most fundamental are added to the core language. These functions are automatically loaded when you start Nyquist, and they are documented in the preceding chapters. Other functions seem less central and are implemented as lisp files that you can load. These are called library functions, and they are described here. To use a library function, you must first load the library, e.g. (load "pianosyn") loads the piano synthesis library. The libraries are all located in the lib directory, and you should therefore include this directory on your XLISPPATH variable. (See Section 1.) Each library is documented in one of the following sections. When you load the library described by the section, all functions documented in that section become available. 14.1. Piano Synthesizer The piano synthesizer (library name is pianosyn.lsp) generates realistic piano tones using a multiple wavetable implementation by Zheng (Geoffrey) Hua and Jim Beauchamp, University of Illinois. Please see the notice about acknowledgements that prints when you load the file. Further informations and example code can be found in demos/piano.htm. There are several useful functions in this library: piano-note(duration, step, dynamic) [SAL] (piano-note duration step dynamic) [LISP] Synthesizes a piano tone. Duration is the duration to the point of key release, after which there is a rapid decay. Step is the pitch in half steps, and dynamic is approximately equivalent to a MIDI key velocity parameter. Use a value near 100 for a loud sound and near 10 for a soft sound. piano-note-2(step, dynamic) [SAL] (piano-note-2 step dynamic) [LISP] Similar to piano-note except the duration is nominally 1.0. piano-midi(midi-file-name) [SAL] (piano-midi midi-file-name) [LISP] Use the piano synthesizer to play a MIDI file. The file name (a string) is given by midi-file-name. piano-midi2file(midi-file-name, sound-file-name) [SAL] (piano-midi2file midi-file-name sound-file-name) [LISP] Use the piano synthesizer to play a MIDI file. The MIDI file is given by midi-file-name and the (monophonic) result is written to the file named sound-file-name. 14.2. Dymanics Compression To use these functions, load the file compress.lsp. This library implements a compressor originally intended for noisy speech audio, but usable in a variety of situations. There are actually two compressors that can be used in series. The first, compress, is a fairly standard one: it detects signal level with an RMS detector and uses table-lookup to determine how much gain to place on the original signal at that point. One bit of cleverness here is that the RMS envelope is ``followed'' or enveloped using snd-follow, which does look-ahead to anticipate peaks before they happen. The other interesting feature is compress-map, which builds a map in terms of compression and expansion. For speech, the recommended procedure is to figure out the noise floor on the signal you are compressing (for example, look at the signal where the speaker is not talking). Use a compression map that leaves the noise alone and boosts signals that are well above the noise floor. Alas, the compress-map function is not written in these terms, so some head-scratching is involved, but the results are quite good. The second compressor is called agc, and it implements automatic gain control that keeps peaks at or below 1.0. By combining compress and agc, you can process poorly recorded speech for playback on low-quality speakers in noisy environments. The compress function modulates the short-term gain to to minimize the total dynamic range, keeping the speech at a generally loud level, and the agc function rides the long-term gain to set the overall level without clipping. compress-map(compress-ratio, compress-threshold, expand-ratio, expand-ratio, limit: limit, transition: transition) [SAL] (compress-map compress-ratio compress-threshold expand-ratio expand-ratio :limit limit :transition transition]) [LISP] Construct a map for the compress function. The map consists of two parts: a compression part and an expansion part. The intended use is to compress everything above compress-threshold by compress-ratio, and to downward expand everything below expand-ratio by expand-ratio. Thresholds are in dB and ratios are dB-per-dB. 0dB corresponds to a peak amplitude of 1.0 or rms amplitude of 0.7 If the input goes above 0dB, the output can optionally be limited by setting limit: (a keyword parameter) to T. This effectively changes the compression ratio to infinity at 0dB. If limit: is nil (the default), then the compression-ratio continues to apply above 0dB. Another keyword parameter, transition:, sets the amount below the thresholds (in dB) that a smooth transition starts. The default is 0, meaning that there is no smooth transition. The smooth transition is a 2nd-order polynomial that matches the slopes of the straight-line compression curve and interpolates between them. It is assumed that expand-threshold <= compress-threshold <= 0 The gain is unity at 0dB so if compression-ratio > 1, then gain will be greater than unity below 0dB. The result returned by this function is a sound for use in the shape function. The sound maps input dB to gain. Time 1.0 corresponds to 0dB, time 0.0 corresponds to -100 dB, and time 2.0 corresponds to +100dB, so this is a 100hz ``sample rate'' sound. The sound gives gain in dB. db-average(input) [SAL] (db-average input) [LISP] Compute the average amplitude of input in dB. compress(input, map, rise-time, fall-time [, lookahead]) [SAL] (compress input map rise-time fall-time [lookahead)] [LISP] Compress input using map, a compression curve probably generated by compress-map (see above). Adjustments in gain have the given rise-time and fall-time. Lookahead tells how far ahead to look at the signal, and is rise-time by default. agc(input, range, rise-time, fall-time [, lookahead]) [SAL] (agc input range rise-time fall-time [lookahead]) [LISP] An automatic gain control applied to input. The maximum gain in dB is range. Peaks are attenuated to 1.0, and gain is controlled with the given rise-time and fall-time. The look-ahead time default is rise-time. 14.3. Clipping Softener This library, in soften.lsp, was written to improve the quality of poorly recorded speech. In recordings of speech, extreme clipping generates harsh high frequency noise. This can sound particulary bad on small speakers that will emphasize high frequencies. This problem can be ameliorated by low-pass filtering regions where clipping occurs. The effect is to dull the harsh clipping. Intelligibility is not affected by much, and the result can be much more pleasant on the ears. Clipping is detected simply by looking for large signal values. Assuming 8-bit recording, this level is set to 126/127. The function works by cross-fading between the normal signal and a filtered signal as opposed to changing filter coefficients. soften-clipping(snd, cutoff) [SAL] (soften-clipping snd cutoff) [LISP] Filter the loud regions of a signal where clipping is likely to have generated additional high frequencies. The input signal is snd and cutoff is the filter cutoff frequency (4 kHz is recommended for speech). 14.4. Graphical Equalizer There's nothing really ``graphical'' about this library (grapheq.lsp), but this is a common term for multi-band equalizers. This implementation uses Nyquist's eq-band function to split the incoming signal into different frequency bands. Bands are spaced geometrically, e.g. each band could be one octave, meaning that each successive band has twice the bandwidth. An interesting possibility is using computed control functions to make the equalization change over time. nband-range(input, gains, lowf, highf) [SAL] (nband-range input gains lowf highf) [LISP] A graphical equalizer applied to input (a SOUND). The gain controls and number of bands is given by gains, an ARRAY of SOUNDs (in other words, a Nyquist multichannel SOUND). Any sound in the array may be replaced by a FLONUM. The bands are geometrically equally spaced from the lowest frequency lowf to the highest frequency highf (both are FLONUMs). nband(input, gains) [SAL] (nband input gains) [LISP] A graphical equalizer, identical to nband-range with a range of 20 to 20,000 Hz. 14.5. Sound Reversal The reverse.lsp library implements functions to play sounds in reverse. s-reverse(snd) [SAL] (s-reverse snd) [LISP] Reverses snd (a SOUND). Sound must be shorter than *max-reverse-samples*, which is currently initialized to 25 million samples. Reversal allocates about 4 bytes per sample. This function uses XLISP in the inner sample loop, so do not be surprised if it calls the garbage collector a lot and runs slowly. The result starts at the starting time given by the current environment (not necessarily the starting time of snd). If snd has multiple channels, a multiple channel, reversed sound is returned. s-read-reverse(filename, time-offset: offset, srate: sr, dur: dur, nchans: chans, format: format, mode: mode, bits: n, swap: flag) [SAL] (s-read-reverse filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag) [LISP] This function is identical to s-read (see 7.5), except it reads the indicated samples in reverse. Like s-reverse (see above), it uses XLISP in the inner loop, so it is slow. Unlike s-reverse, s-read-reverse uses a fixed amount of memory that is independent of how many samples are computed. Multiple channels are handled. 14.6. Time Delay Functions The time-delay-fns.lsp library implements chorus, phaser, and flange effects. phaser(snd) [SAL] (phaser snd) [LISP] A phaser effect applied to snd (a SOUND). There are no parameters, but feel free to modify the source code of this one-liner. flange(snd) [SAL] (flange snd) [LISP] A flange effect applied to snd. To vary the rate and other parameters, see the source code. stereo-chorus(snd) [SAL] (stereo-chorus snd) [LISP] A chorus effect applied to snd, a SOUND (monophonic). The output is a stereo sound. All parameters are built-in, but see the simple source code to make modifications. chorus(snd, maxdepth, depth, rate, saturation) [SAL] (chorus snd maxdepth depth rate saturation) [LISP] A chorus effect applied to snd. All parameters may be arrays as usual. The maxdepth is a FLONUM giving twice the maximum value of depth, which may be a FLONUM or a SOUND. The chorus is implemented as a variable delay modulated by a sinusoid running at rate Hz (a FLONUM). The sinusoid is scaled by depth and offset by maxdepth/2. The delayed signal is mixed with the original, and saturation gives the fraction of the delayed signal (from 0 to 1) in the mix. A reasonable choice of parameter values is maxdepth = 0.05, depth = 0.025, rate = 0.5, and saturation = 0.5. 14.7. Multiple Band Effects The bandfx.lsp library implements several effects based on multiple frequency bands. The idea is to separate a signal into different frequency bands, apply a slightly different effect to each band, and sum the effected bands back together to form the result. This file includes its own set of examples. After loading the file, try f2(), f3(), f4(), and f5() to hear them. There is much room for expansion and experimentation with this library. Other effects might include distortion in certain bands (for example, there are commercial effects that add distortion to low frequencies to enhance the sound of the bass), separating bands into different channels for stereo or multi-channel effects, adding frequency-dependent reverb, and performing dynamic compression, limiting, or noise gate functions on each band. There are also opportunities for cross-synthesis: using the content of bands extracted from one signal to modify the bands of another. The simplest of these would be to apply amplitude envelopes of one sound to another. Please contact us (dannenberg@cs.cmu.edu) if you are interested in working on this library. apply-banded-delay(s, lowp, highp, num-bands, lowd, highd, fb, wet) [SAL] (apply-banded-delay s lowp highp num-bands lowd highd fb wet) [LISP] Separates input SOUND s into FIXNUM num-bands bands from a low frequency of lowp to a high frequency of highp (these are FLONUMS that specify steps, not Hz), and applies a delay to each band. The delay for the lowest band is given by the FLONUM lowd (in seconds) and the delay for the highest band is given by the FLONUM highd. The delays for other bands are linearly interpolated between these values. Each delay has feedback gain controlled by FLONUM fb. The delayed bands are scaled by FLONUM wet, and the original sound is scaled by 1 - wet. All are summed to form the result, a SOUND. apply-banded-bass-boost(s, lowp, highp, num-bands, num-boost, gain) [SAL] (apply-banded-bass-boost s lowp highp num-bands num-boost gain) [LISP] Applies a boost to low frequencies. Separates input SOUND s into FIXNUM num-bands bands from a low frequency of lowp to a high frequency of highp (these are FLONUMS that specify steps, not Hz), and scales the lowest num-boost (a FIXNUM) bands by gain, a FLONUM. The bands are summed to form the result, a SOUND. apply-banded-treble-boost(s, lowp, highp, num-bands, num-boost, gain) [SAL] (apply-banded-treble-boost s lowp highp num-bands num-boost gain) [LISP] Applies a boost to high frequencies. Separates input SOUND s into FIXNUM num-bands bands from a low frequency of lowp to a high frequency of highp (these are FLONUMS that specify steps, not Hz), and scales the highest num-boost (a FIXNUM) bands by gain, a FLONUM. The bands are summed to form the result, a SOUND. 14.8. Granular Synthesis Some granular synthesis functions are implemented in the gran.lsp library file. There are many variations and control schemes one could adopt for granular synthesis, so it is impossible to create a single universal granular synthesis function. One of the advantages of Nyquist is the integration of control and synthesis functions, and users are encouraged to build their own granular synthesis functions incorporating their own control schemes. The gran.lsp file includes many comments and is intended to be a useful starting point. Another possibility is to construct a score with an event for each grain. Estimate a few hundred bytes per score event (obviously, size depends on the number of parameters) and avoid using all of your computer's memory. sf-granulate(filename, grain-dur, grain-dev, ioi, ioi-dev, pitch-dev, [file-start, file-end]) [SAL] (sf-granulate filename grain-dur grain-dev ioi ioi-dev pitch-dev [file-start file-end]) [LISP] Granular synthesis using a sound file named filename as the source for grains. Grains are extracted from a sound file named by filename by stepping through the file in equal increments. Each grain duration is the sum of grain-dur and a random number from 0 to grain-dev. Grains are then multiplied by a raised cosine smoothing window and resampled at a ratio between 1.0 and pitch-dev. If pitch-dev is greater than one, grains are stretched and the pitch (if any) goes down. If pitch-dev is less than one, grains are shortened and the pitch goes up. Grains are then output with an inter-onset interval between successive grains (which may overlap) determined by the sum of ioi and a random number from 0 to ioi-dev. The duration of the resulting sound is determined by the stretch factor (not by the sound file). The number of grains is the total sound duration (determined by the stretch factor) divided by the mean inter-onset interval, which is ioi + ioi-dev * 0.5. The grains are taken from equally-spaced starting points in filename, and depending on grain size and number, the grains may or may not overlap. The output duration will simply be the sum of the inter-onset intervals and the duration of the last grain. If ioi-dev is non-zero, the output duration will vary, but the expected value of the duration is the stretch factor. To achieve a rich granular synthesis effect, it is often a good idea to sum four or more copies of sf-granulate together. (See the gran-test function in gran.lsp.) 14.9. MIDI Utilities The midishow.lsp library has functions that can print the contents fo MIDI files. This intended as a debugging aid. midi-show-file(file-name) [SAL] (midi-show-file file-name) [LISP] Print the contents of a MIDI file to the console. midi-show(the-seq [, out-file]) [SAL] (midi-show the-seq [out-file]) [LISP] Print the contents of the sequence the-seq to the file out-file (whose default value is the console.) 14.10. Reverberation The reverb.lsp library implements artificial reverberation. reverb(snd, time) [SAL] (reverb snd time) [LISP] Artificial reverberation applied to snd with a decay time of time. 14.11. DTMF Encoding The dtmf.lsp library implements DTMF encoding. DTMF is the ``touch tone'' code used by telephones. dtmf-tone(key, len, space) [SAL] (dtmf-tone key len space) [LISP] Generate a single DTMF tone. The key parameter is either a digit (a FIXNUM from 0 through 9) or the atom STAR or POUND. The duration of the done is given by len (a FLONUM) and the tone is followed by silence of duration space (a FLONUM). speed-dial(thelist) [SAL] (speed-dial thelist) [LISP] Generates a sequence of DTMF tones using the keys in thelist (a LIST of keys as described above under dtmf-tone). The duration of each tone is 0.2 seconds, and the space between tones is 0.1 second. Use stretch to change the ``dialing'' speed. 14.12. Dolby Surround(R), Stereo and Spatialization Effects The spatial.lsp library implements various functions for stereo manipulation and spatialization. It also includes some functions for Dolby Pro-Logic panning, which encodes left, right, center, and surround channels into stereo. The stereo signal can then be played through a Dolby decoder to drive a surround speaker array. This library has a somewhat simplified encoder, so you should certainly test the output. Consider using a high-end encoder for critical work. There are a number of functions in spatial.lsp for testing. See the source code for comments about these. stereoize(snd) [SAL] (stereoize snd) [LISP] Convert a mono sound, snd, to stereo. Four bands of equalization and some delay are used to create a stereo effect. widen(snd, amt) [SAL] (widen snd amt) [LISP] Artificially widen the stereo field in snd, a two-channel sound. The amount of widening is amt, which varies from 0 (snd is unchanged) to 1 (maximum widening). The amt can be a SOUND or a number. span(snd, amt) [SAL] (span snd amt) [LISP] Pan the virtual center channel of a stereo sound, snd, by amt, where 0 pans all the way to the left, while 1 pans all the way to the right. The amt can be a SOUND or a number. swapchannels(snd) [SAL] (swapchannels snd) [LISP] Swap left and right channels in snd, a stereo sound. prologic(l, c, r, s) [SAL] (prologic l c r s) [LISP] Encode four monaural SOUNDs representing the front-left, front-center, front-right, and rear channels, respectively. The return value is a stereo sound, which is a Dolby-encoded mix of the four input sounds. pl-left(snd) [SAL] (pl-left snd) [LISP] Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the front left channel. pl-center(snd) [SAL] (pl-center snd) [LISP] Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the front center channel. pl-right(snd) [SAL] (pl-right snd) [LISP] Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the front right channel. pl-rear(snd) [SAL] (pl-rear snd) [LISP] Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the rear, or surround, channel. pl-pan2d(snd, x, y) [SAL] (pl-pan2d snd x y) [LISP] Comparable to Nyquist's existing pan function, pl-pan2d provides not only left-to-right panning, but front-to-back panning as well. The function accepts three parameters: snd is the (monophonic) input SOUND, x is a left-to-right position, and y is a front-to-back position. Both position parameters may be numbers or SOUNDs. An x value of 0 means left, and 1 means right. Intermediate values map linearly between these extremes. Similarly, a y value of 0 causes the sound to play entirely through the front speakers(s), while 1 causes it to play entirely through the rear. Intermediate values map linearly. Note that, although there are usually two rear speakers in Pro-Logic systems, they are both driven by the same signal. Therefore any sound that is panned totally to the rear will be played over both rear speakers. For example, it is not possible to play a sound exclusively through the rear left speaker. pl-position(snd, x, y, config) [SAL] (pl-position snd x y config) [LISP] The position function builds upon speaker panning to allow more abstract placement of sounds. Like pl-pan2d, it accepts a (monaural) input sound as well as left-to-right (x) and front-to-back (y) coordinates, which may be FLONUMs or SOUNDs. A fourth parameter config specifies the distance from listeners to the speakers (in meters). Current settings assume this to be constant for all speakers, but this assumption can be changed easily (see comments in the code for more detail). There are several important differences between pl-position and pl-pan2d. First, pl-position uses a Cartesian coordinate system that allows x and y coordinates outside of the range (0, 1). This model assumes a listener position of (0,0). Each speaker has a predefined position as well. The input sound's position, relative to the listener, is given by the vector (x,y). pl-doppler(snd, r) [SAL] (pl-doppler snd r) [LISP] Pitch-shift moving sounds according to the equation: fr = f0((c+vr)/c), where fr is the output frequency, f0 is the emitted (source) frequency, c is the speed of sound (assumed to be 344.31 m/s), and vr is the speed at which the emitter approaches the receiver. (vr is the first derivative of parameter r, the distance from the listener in meters. 14.13. Drum Machine The drum machine software in demos/plight deserves further explanation. to use the software, load the code by evaluating: load "../demos/plight/drum.lsp" exec load-props-file(strcat(*plight-drum-path*, "beats.props")) exec create-drum-patches() exec create-patterns() Drum sounds and patterns are specified in the beats.props file (or whatever name you give to load-props-file). This file contains two types of specifications. First, there are sound file specifications. Sound files are located by a line of the form: set sound-directory = "kit/" This gives the name of the sound file directory, relative to the beats.props file. Then, for each sound file, there should be a line of the form: track.2.5 = big-tom-5.wav This says that on track 2, a velocity value of 5 means to play the sound file big-tom-5.wav. (Tracks and velocity values are described below.) The beats.props file contains specifications for all the sound files in demos/plight/kit using 8 tracks. If you make your own specifications file, tracks should be numbered consecutively from 1, and velocities should be in the range of 1 to 9. The second set of specifications is of beat patterns. A beat pattern is given by a line in the following form: beats.5 = 2--32--43-4-5--- The number after beats is just a pattern number. Each pattern is given a unique number. After the equal sign, the digits and dashes are velocity values where a dash means ``no sound.'' Beat patterns should be numbered consecutively from 1. Once data is loaded, there are several functions to access drum patterns and create drum sounds (described below). The demos/plight/drums.lsp file contains an example function plight-drum-example to play some drums. There is also the file demos/plight/beats.props to serve as an example of how to specify sound files and beat patterns. drum(tracknum, patternnum, bpm) [SAL] (drum tracknum patternnum bpm) [LISP] Create a sound by playing drums sounds associated with track tracknum (a FIXNUM) using pattern patternnum. The tempo is given by bpm in beats per minute. Normally patterns are a sequence of sixteenth notes, so the tempo is in sixteenth notes per minute. For example, if patternnum is 10, then use the pattern specified for beats.10. If the third character of this pattern is 3 and tracknum is 5, then on the third beat, play the soundfile assigned to track.5.3. This function returns a SOUND. drum-loop(snd, duration, numtimes) [SAL] (drum-loop snd duration numtimes) [LISP] Repeat the sound given by snd numtimes times. The repetitions occur at a time offset of duration, regardless of the actual duration of snd. A SOUND is returned. length-of-beat(bpm) [SAL] (length-of-beat bpm) [LISP] Given a tempo of bpm, return the duration of the beat in seconds. Note that this software has no real notion of beat. A ``beat'' is just the duration of each character in the beat pattern strings. This function returns a FLONUM. 14.14. Minimoog-inspired Synthesis The moog.lsp library gives the Nyquist user easy access to ``classic'' synthesizer sounds through an emulation of the Minimoog Synthesizer. Unlike modular Moogs that were very large, the Minimoog was the first successful and commonly used portable synthesizer. The trademark filter attack was unique and easily recognizable. The goal of this Nyquist instrument is not only to provide the user with default sounds, but also to give control over many of the ``knobs'' found on the Minimoog. In this implementation, these parameters are controlled using keywords. The input to the moog instrument is a user-defined sequence of notes, durations, and articulations that simulate notes played on a keyboard. These are translated into control voltages that drive multiple oscillators, similar to the Voltage Controlled Oscillator or VCO found in the original analog Moog. The basic functionality of the Minimoog has been implemented, including the often-used "glide". The glide feature essentially low-pass filters the control voltage sequence in order to create sweeps between notes. Figure 21 is a simplified schematic of the data flow in the Moog. The control lines have been omitted. Figure 21: System diagram for Minimoog emulator. The most recognizable feature of the Minimoog is its resonant filter, a Four-Pole Ladder Filter invented by Robert Moog. It is simply implemented in a circuit with four transistors and provides an outstanding 24 dB/octave rolloff. It is modeled here using the built-in Nyquist resonant filter. One of the Moog filter features is a constant Q, or center frequency to bandwidth ratio. This is implemented and the user can control the Q. The user can control many parameters using keywords. Their default values, acceptable ranges, and descriptions are shown below. The defaults were obtained by experimenting with the official Minimoog software synthesizer by Arturia. 14.14.1. Oscillator Parameters range-osc1 (2) range-osc2 (1) range-osc3 (3) These parameters control the octave of each oscillator. A value of 1 corresponds to the octave indicated by the input note. A value of 3 is two octaves above the fundamental. The allowable range is 1 to 7. detun2 (-.035861) detun3 (.0768) Detuning of two oscillators adds depth to the sound. A value of 1 corresponds to an increase of a single semitone and a -1 corresponds to a decrease in a semitone. The range is -1 to 1. shape-osc1 (*saw-table*) shape-osc2 (*saw-table*) shape-osc3 (*saw-table*) Oscilators can use any wave shape. The default sawtooth waveform is a built-in Nyquist variable. Other waveforms can be defined by the user. volume-osc1 (1) volume-osc2 (1) volume-osc3 (1) These parameters control the relative volume of each oscillator. The range is any FLONUM greater than or equal to zero. 14.14.2. Noise Parameters noiselevel (.05) This parameter controls the relative volume of the noise source. The range is any FLONUM greater than or equal to zero. 14.14.3. Filter Parameters filter-cutoff (768) The cutoff frequency of the filter in given in Hz. The range is zero to 20,000 Hz. Q (2) Q is the ratio of center frequency to bandwidth. It is held constant by making the bandwidth a function of frequency. The range is any FLONUM greater than zero. contour (.65) Contour controls the range of the transient frequency sweep from a high to low cutoff frequency when a note is played. The high frequency is proportional to contour. A contour of 0 removes this sweep. The range is 0 to 1. filter-attack (.0001) Filter attack controls the attack time of the filter, i.e. the time to reach the high cutoff frequency. The range is any FLONUM greater than zero (seconds). filter-decay (.5) Filter decay controls the decay time of the filter, i.e. the time of the sweep from the high to low cutoff frequency. The range is any FLONUM greater than zero (seconds). filter-sustain (.8) Filter sustain controls the percentage of the filter cutoff frequency that the filter settles on following the sweep. The range is 0 to 1. 14.14.4. Amplitude Parameters amp-attack (.01) This parameter controls the amplitude envelope attack time, i.e. the time to reach maximum amplitude. The range is any FLONUM greater than zero (seconds). amp-decay (1) This parameter controls the amplitude envelope decay time, i.e. the time between the maximum and sustain volumes. The range is any FLONUM greater than zero (seconds). amp-sustain (1) This parameter controls the amplitude envelope sustain volume, a fraction of the maximum. The range is 0 to 1. amp-release (0) This parameter controls the amplitude envelope release time, i.e. the time it takes between the sustain volume and 0 once the note ends. The duration controls the overall length of the sound. The range of amp-release is any FLONUM greater than zero (seconds). 14.14.5. Other Parameters glide (0) Glide controls the low-pass filter on the control voltages. This models the glide knob on a Minimoog. A higher value corresponds to a lower cutoff frequency and hence a longer "glide" between notes. A value of 0 corresponds to no glide. The range is zero to 10. 14.14.6. Input Format A single note or a series of notes can be input to the Moog instrument by defining a list with the following format: list(list(frequency, duration, articulation), ... ) where frequency is a FLONUM in steps, duration is the duration of each note in seconds (regardless of the release time of the amplifier), and articulation is a percentage of the duration that a sound will be played, representing the amount of time that a key is pressed. The filter and amplitude envelopes are only triggered if a note is played when the articulation of the previous note is less than 1, or a key is not down at the same time. This Moog instrument is a monophonic instrument, so only one note can sound at a time. The release section of the amplifier is triggered when the articulation is less than 1 at the time (duration * articulation). 14.14.7. Sample Code/Sounds Sound 1 (default parameters): set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99} {29 .5 .99} {31 2 1}} play moog(s) Sound 2 (articulation, with amplitude release): set s = {{24 .5 .5} {26 .5 1} {28 .5 .25} {29 .5 1} {31 1 .8}} play moog(s, amp-release: .2) Sound 3 (glide): set s = {{24 .5 .5} {38 .5 1} {40 .5 .25} {53 .5 1} {55 2 1} {31 2 .8} {36 2 .8}} play moog(s, amp-release: .2, glide: .5) Sound 4 (keyword parameters): Filter attack and decay are purposely longer than notes being played with articulation equal to 1. set s = {{20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1} {20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1}} play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*, filter-attack: 2, filter-decay: 2, filter-cutoff: 300, contour: .8, glide: .2, Q: 8) Sound 5: This example illustrates the ability to completely define a new synthesizer with different parameters creating a drastically different sound. Sine waves are used for wavetables. There is a high value for glide. define function my-moog(freq) return moog(freq, range-osc1: 3, range-osc2: 2, range-osc3: 4, detun2: -.043155, detun3: .015016, noiselevel: 0, filter-cutoff: 400, Q: .1, contour: .0000001, filter-attack: 0, filter-decay: .01, filter-sustain: 1, shape-osc1: *sine-table*, shape-osc2: *sine-table*, shape-osc3: *sine-table*, volume-osc1: 1, volume-osc2: 1, volume-osc3: .1, amp-attack: .1, amp-decay: 0, amp-sustain: 1, amp-release: .3, glide: 2) set s = {{80 .4 .75} {28 .2 1} {70 .5 1} {38 1 .5}} play my-moog(s) Sound 6: This example has another variation on the default parameters. set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99} {29 .5 .99} {31 2 1}} play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*, filter-attack: .5, contour: .5) I. Extending Nyquist WARNING: Nyquist sound functions look almost like a human wrote them; they even have a fair number of comments for human readers. Don't be fooled: virtually all Nyquist functions are written by a special translator. If you try to write a new function by hand, you will probably not succeed, and even if you do, you will waste a great deal of time. (End of Warning.) I.1. Translating Descriptions to C Code The translator code used to extend Nyquist resides in the trnsrc directory. This directory also contains a special init.lsp, so if you start XLisp or Nyquist in this directory, it will automatically read init.lsp, which in turn will load the translator code (which resides in several files). Also in the trnsrc directory are a number of .alg files, which contain the source code for the translator (more on these will follow), and a number of corresponding .h and .c files. To translate a .alg file to .c and .h files, you start XLisp or Nyquist in the trnsrc directory and type (translate "prod") where "prod" should really be replaced by the filename (without a suffix) you want to translate. Be sure you have a saved, working copy of Nyquist or Xlisp before you recompile! Note: On the Macintosh, just run Nyquist out of the runtime directory and then use the Load menu command to load init.lsp from the trnsrc directory. This will load the translation code and change Nyquist's current directory to trnsrc so that commands like (translate "prod") will work. I.2. Rebuilding Nyquist After generating prod.c and prod.h, you need to recompile Nyquist. For Unix systems, you will want to generate a new Makefile. Modify transfiles.lsp in your main Nyquist directory, run Xlisp or Nyquist and load makefile.lsp. Follow the instructions to set your machine type, etc., and execute (makesrc) and (makefile). I.3. Accessing the New Function The new Lisp function will generally be named with a snd- prefix, e.g. snd-prod. You can test this by running Nyquist. Debugging is usually a combination of calling the code from within the interpreter, reading the generated code when things go wrong, and using a C debugger to step through the inner loop of the generated code. An approach I like is to set the default sample rate to 10 hertz. Then, a one-second sound has only 10 samples, which are easy to print and study on a text console. For some functions, you must write some Lisp code to impose ordinary Nyquist behaviors such as stretching and time shifting. A good approach is to find some structurally similar functions and see how they are implemented. Most of the Lisp code for Nyquist is in nyquist.lsp. Finally, do not forget to write up some documentation. Also, contributions are welcome. Send your .alg file, documentation, Lisp support functions for nyquist.lsp, and examples or test programs to rbd@cs.cmu.edu. I will either put them in the next release or make them available at a public ftp site. I.4. Why Translation? Many of the Nyquist signal processing operations are similar in form, but they differ in details. This code is complicated by many factors: Nyquist uses lazy evaluation, so the operator must check to see that input samples are available before trying to access them. Nyquist signals can have different sample rates, different block sizes, different block boundaries, and different start times, all of which must be taken into account. The number of software tests is enormous. (This may sound like a lot of overhead, but the overhead is amortized over many iterations of the inner loop. Of course setting up the inner loop to run efficiently is one more programming task.) The main idea behind the translation is that all of the checks and setup code are similar and relatively easy to generate automatically. Programmers often use macros for this sort of task, but the C macro processor is too limited for the complex translation required here. To tell the translator how to generate code, you write .alg files, which provide many details about the operation in a declarative style. For example, the code generator can make some optimizations if you declare that two input signals are commutative (they can be exchanged with one another). The main part of the .alg file is the inner loop which is the heart of the signal processing code. I.5. Writing a .alg File WARNING: Translation relies heavily on string substitution, which is fragile. In particular, variables with names that are substrings of other variables will cause problems. For example if you declare STATE variables "phase" and "iphase", then the translator will globally substitute "phase_reg" for "phase", converting "phase" to "phase_reg" and iphase" to "iphase_reg". Then it will substitute "iphase_reg" for iphase" which will convert the existing "iphase_reg" to "iphase_reg_reg". This will be confusing and will not compile. (End of WARNING) To give you some idea how functions are specified, here is the specification for snd-prod, which generates over 250 lines of C code: (PROD-ALG (NAME "prod") (ARGUMENTS ("sound_type" "s1") ("sound_type" "s2")) (START (MAX s1 s2)) (COMMUTATIVE (s1 s2)) (INNER-LOOP "output = s1 * s2") (LINEAR s1 s2) (TERMINATE (MIN s1 s2)) (LOGICAL-STOP (MIN s1 s2)) ) A .alg file is always of the form: (name (attribute value) (attribute value) ... ) There should be just one of these algorithms descriptions per file. The name field is arbitrary: it is a Lisp symbol whose property list is used to save the following attribute/value pairs. There are many attributes described below. For more examples, see the .alg files in the trnsrc directory. Understanding what the attributes do is not easy, so here are three recommendations for implementors. First, if there is an existing Nyquist operator that is structurally similar to something you want to implement, make a copy of the corresponding .alg file and work from there. In some cases, you can merely rename the parameters and substitute a new inner loop. Second, read the generated code, especially the generated inner loop. It may not all make sense, but sometimes you can spot obvious errors and work your way back to the error in the .alg file. Third, if you know where something bad is generated, see if you can find where the code is generated. (The code generator files are listed in init.lsp.) This code is poorly written and poorly documented, but in some cases it is fairly straightforward to determine what attribute in the .alg file is responsible for the erroneous output. I.6. Attributes Here are the attributes used for code generation. Attributes and values may be specified in any order. (NAME "string") specifies a base name for many identifiers. In particular, the generated filenames will be string.c and string.h, and the XLisp function generated will be snd-string. (ARGUMENTS arglist) describes the arguments to be passed from XLisp. Arglist has the form: (type1 name1) (type2 name2) ..., where type and name are strings in double quotes, e.g. ("sound_type" "s") specifies a SOUND parameter named s. Note that arglist is not surrounded by parentheses. As seen in this example, the type names and parameter names are C identifiers. Since the parameters are passed in from XLisp, they must be chosen from a restricted set. Valid type names are: "sound_type", "rate_type", "double", "long", "string", and "LVAL". (STATE statelist) describes additional state (variables) needed to perform the computation. A statelist is similar to an arglist (see ARGUMENTS above), and has the form: (type1 name1 init1 [TEMP]) (type2 name2 init2 [TEMP]) .... The types and names are as in arglist, and the "inits" are double-quoted initial values. Initial values may be any C expression. State is initialized in the order implied by statelist when the operation is first called from XLisp. If TEMP is omitted the state is preserved in a structure until the sound computation completes. Otherwise, the state variable only exists at state initialization time. (INNER-LOOP innerloop-code) describes the inner loop, written as C code. The innerloop-code is in double quotes, and may extend over multiple lines. To make generated code extra-beautiful, prefix each line of innerloop-code with 12 spaces. Temporary variables should not be declared at the beginning of innerloop-code. Use the INNER-LOOP-LOCALS attribute instead. Within innerloop-code, each ARGUMENT of type sound_type must be referenced exactly one time. If you need to use a signal value twice, assign it once to a temporary and use the temporary twice. The inner loop must also assign one time to the psuedo-variable output. The model here is that the name of a sound argument denotes the value of the corresponding signal at the current output sample time. The inner loop code will be called once for each output sample. In practice, the code generator will substitute some expression for each signal name. For example, prod.alg specifies (INNER-LOOP "output = s1 * s2") (s1 and s2 are ARGUMENTS.) This expands to the following inner loop in prod.c: *out_ptr_reg++ = *s1_ptr_reg++ * *s2_ptr_reg++; In cases where arguments have different sample rates, sample interpolation is in-lined, and the expressions can get very complex. The translator is currently very simple-minded about substituting access code in the place of parameter names, and this is a frequent source of bugs. Simple string substitution is performed, so you must not use a parameter or state name that is a substring of another. For example, if two sound parameters were named s and s2, the translator might substitute for ``s'' in two places rather than one. If this problem occurs, you will almost certainly get a C compiler syntax error. The fix is to use ``more unique'' parameter and state variable names. (INNER-LOOP-LOCALS "innerloop-code") The innerloop-code contains C declarations of local variables set and referenced in the inner loop. (SAMPLE-RATE "expr") specifies the output sample rate; expr can be any C expression, including a parameter from the ARGUMENTS list. You can also write (SAMPLE-RATE (MAX name1 name2 ...)) where names are unquoted names of arguments. (SUPPORT-HEADER "c-code") specifies arbitrary C code to be inserted in the generated .h file. The code typically contains auxiliarly function declarations and definitions of constants. (SUPPORT-FUNCTIONS "c-code") specifies arbitrary C code to be inserted in the generated .c file. The code typically contains auxiliarly functions and definitions of constants. (FINALIZATION "c-code") specifies code to execute when the sound has been fully computed and the state variables are about to be decallocated. This is the place to deallocate buffer memory, etc. (CONSTANT "name1" "name2" ...) specifies state variables that do not change value in the inner loop. The values of state variables are loaded into registers before entering the inner loop so that access will be fast within the loop. On exiting the inner loop, the final register values are preserved in a ``suspension'' structure. If state values do not change in the inner loop, this CONSTANT declaration can eliminate the overhead of storing these registers. (START spec) specifies when the output sound should start (a sound is zero and no processing is done before the start time). The spec can take several forms: (MIN name1 name2 ...) means the start time is the minimum of the start times of input signals name1, name2, .... Note that these names are not quoted. (TERMINATE spec) specifies when the output sound terminates (a sound is zero after this termination time and no more samples are computed). The spec can take several forms: (MIN name1 name2 ...) means the terminate time is the minimum of the terminate times of input arguments name1, name2, .... Note that these names are not quoted. To terminate at the time of a single argument s1, specify (MIN s1). To terminate after a specific duration, use (AFTER "c-expr"), where c-expr is a C variable or expression. To terminate at a particular time, use (AT "c-expr"). spec may also be COMPUTED, which means to use the maximum sample rate of any input signal. (LOGICAL-STOP spec) specifies the logical stop time of the output sound. This spec is just like the one for TERMINATE. If no LOGICAL-STOP attribute is present, the logical stop will coincide with the terminate time. (ALWAYS-SCALE name1 name2 ...) says that the named sound arguments (not in quotes) should always be multiplied by a scale factor. This is a space-time tradeoff. When Nyquist sounds are scaled, the scale factor is merely stored in a structure. It is the responsibility of the user of the samples to actually scale them (unless the scale factor is exactly 1.0). The default is to generate code with and without scaling and to select the appropriate code at run N time. If there are N signal inputs, this will generate 2 versions of the code. To avoid this code explosion, use the ALWAYS-SCALE attribute. (INLINE-INTERPOLATION T) specifies that sample rate interpolation should be performed in-line in the inner loop. There are two forms of sample rate interpolation. One is intended for use when the rate change is large and many points will be interpolated. This form uses a divide instruction and some setup at the low sample rate, but the inner loop overhead is just an add. The other form, intended for less drastic sample rate changes, performs interpolation with 2 multiplies and several adds per sample at the high sample rate. Nyquist generates various inner loops and selects the appropriate one at run-time. If INLINE-INTERPOLATION is not set, then much less code is generated and interpolation is performed as necessary by instantiating a separate signal processing operation. (STEP-FUNCTION name1 name2 ...) Normally all argument signals are linearly interpolated to the output sample rate. The linear interpolation can be turned off with this attribute. This is used, for example, in Nyquist variable filters so that filter coefficients are computed at low sample rates. In fact, this attribute was added for the special case of filters. (DEPENDS spec1 spec2 ...) Specifies dependencies. This attribute was also introduced to handle the case of filter coefficients (but may have other applications.) Use it when a state variable is a function of a potentially low-sample-rate input where the input is in the STEP-FUNCTION list. Consider a filter coefficient that depends upon an input signal such as bandwidth. In this case, you want to compute the filter coefficient only when the input signal changes rather than every output sample, since output may occur at a much higher sample rate. A spec is of the form ("name" "arg" "expr" [TEMP "type"]) which is interpreted as follows: name depends upon arg; when arg changes, recompute expr and assign it to name. The name must be declared as a STATE variable unless TEMP is present, in which case name is not preserved and is used only to compute other state. Variables are updated in the order of the DEPENDS list. (FORCE-INTO-REGISTER name1 name2 ...) causes name1, name2, ... to be loaded into registers before entering the inner loop. If the inner loop references a state variable or argument, this happens automatically. Use this attribute only if references are ``hidden'' in a #define'd macro or referenced in a DEPENDS specification. (NOT-REGISTER name1 name2 ...) specifies state and arguments that should not be loaded into registers before entering an inner loop. This is sometimes an optimization for infrequently accessed state. (NOT-IN-INNER-LOOP "name1" "name2" ...) says that certain arguments are not used in the inner loop. Nyquist assumes all arguments are used in the inner loop, so specify them here if not. For example, tables are passed into functions as sounds, but these sounds are not read sample-by-sample in the inner loop, so they should be listed here. (MAINTAIN ("name1" "expr1") ("name2" "expr2") ... ) Sometimes the IBM XLC compiler generates better loop code if a variable referenced in the loop is not referenced outside of the loop after the loop exit. Technically, optimization is better when variables are dead upon loop exit. Sometimes, there is an efficient way to compute the final value of a state variable without actually referencing it, in which case the variable and the computation method are given as a pair in the MAINTAIN attribute. This suppresses a store of the value of the named variable, making it a dead variable. Where the store would have been, the expression is computed and assigned to the named variable. See partial.alg for an example. This optimization is never necessary and is only for fine-tuning. (LINEAR name1 name2 ...) specifies that named arguments (without quotes) are linear with respect to the output. What this really means is that it is numerically OK to eliminate a scale factor from the named argument and store it in the output sound descriptor, avoiding a potential multiply in this inner loop. For example, both arguments to snd-prod (signal multiplication) are ``linear.'' The inner loop has a single multiplication operator to multiply samples vs. a potential 3 multiplies if each sample were also scaled. To handle scale factors on the input signals, the scale factors are automatically multiplied and the product becomes the scale factor of the resulting output. (This effectively ``passes the buck'' to some other, or perhaps more than one, signal processing function, which is not always optimal. On the other hand, it works great if you multiply a number of scaled signals together: all the scale factors are ultimately handled with a single multiply.) (INTERNAL-SCALING name1 name2 ...) indicates that scaling is handled in code that is hidden from the code generator for name1, name2, ..., which are sound arguments. Although it is the responsibility of the reader of samples to apply any given scale factor, sometimes scaling can be had for free. For example, the snd-recip operation computes the reciprocal of the input samples by peforming a division. The simple approach would be to specify an inner loop of output = 1.0/s1, where s1 is the input. With scaling, this would generate an inner loop something like this: *output++ = 1.0 / (s1_scale_factor * *s1++); but a much better approach would be the following: *output++ = my_scale_factor / *s1++ where my_scale_factor is initialized to 1.0 / s1->scale. Working backward from the desired inner loop to the .alg inner loop specification, a first attempt might be to specify: (INNER-LOOP "output = my_scale_factor / s1") but this will generate the following: *output++=my_scale_factor/(s1_scale_factor * *s1++); Since the code generator does not know that scaling is handled elsewhere, the scaling is done twice! The solution is to put s1 in the INTERNAL-SCALING list, which essentially means ``I've already incorporated scaling into the algorithm, so suppress the multiplication by a scale factor.'' (COMMUTATIVE (name1 name2 ...)) specifies that the results will not be affected by interchanging any of the listed arguments. When arguments are commutative, Nyquist rearranges them at run-time into decreasing order of sample rates. If interpolation is in-line, this can dramatically reduce the amount of code generated to handle all the different cases. The prime example is prod.alg. (TYPE-CHECK "code") specifies checking code to be inserted after argument type checking at initialization time. See downproto.alg for an example where a check is made to guarantee that the output sample rate is not greater than the input sample rate. Otherwise an error is raised. I.7. Generated Names The resulting .c file defines a number of procedures. The procedures that do actual sample computation are named something like name_interp-spec_FETCH, where name is the NAME attribute from the .alg file, and interp-spec is an interpolation specification composed of a string of the following letters: n, s, i, and r. One letter corresponds to each sound argument, indicating no interpolation (r), scaling only (s), ordinary linear interpolation with scaling (i), and ramp (incremental) interpolation with scaling (r). The code generator determines all the combinations of n, s, i, and r that are necessary and generates a separate fetch function for each. Another function is name_toss_fetch, which is called when sounds are not time-aligned and some initial samples must be discarded from one or more inputs. The function that creates a sound is snd_make_name. This is where state allocation and initialization takes place. The proper fetch function is selected based on the sample rates and scale factors of the sound arguments, and a sound_type is returned. Since Nyquist is a functional language, sound operations are not normally allowed to modify their arguments through side effects, but even reading samples from a sound_type causes side effects. To hide these from the Nyquist programmer, sound_type arguments are first copied (this only copies a small structure. The samples themselves are on a shared list). The function snd_name performs the necessary copies and calls snd_make_name. It is the snd_name function that is called by XLisp. The XLisp name for the function is SND-NAME. Notice that the underscore in C is converted to a dash in XLisp. Also, XLisp converts identifiers to upper case when they are read, so normally, you would type snd-name to call the function. I.8. Scalar Arguments If you want the option of passing either a number (scalar) or a signal as one of the arguments, you have two choices, neither of which is automated. Choice 1 is to coerce the constant into a signal from within XLisp. The naming convention would be to DEFUN a new function named NAME or S-NAME for ordinary use. The NAME function tests the arguments using XLisp functions such as TYPE-OF, NUMBERP, and SOUNDP. Any number is converted to a SOUND, e.g. using CONST. Then SND-NAME is called with all sound arguments. The disadvantage of this scheme is that scalars are expanded into a sample stream, which is slower than having a special inner loop where the scalar is simply kept in a register, avoiding loads, stores, and addressing overhead. Choice 2 is to generate a different sound operator for each case. The naming convention here is to append a string of c's and v's, indicating constant (scalar) or variable (signal) inputs. For example, the reson operator comes in four variations: reson, resoncv, resonvc, and resonvv. The resonvc version implements a resonating filter with a variable center frequency (a sound type) and a constant bandwidth (a FLONUM). The RESON function in Nyquist is an ordinary Lisp function that checks types and calls one of SND-RESON, SND-RESONCV, SND-RESONVC, or SND-RESONVV. Since each of these SND- functions performs further selection of implementation based on sample rates and the need for scaling, there are 25 different functions for computing RESON! So far, however, Nyquist is smaller than Common Lisp and it's about half the size of Microsoft Word. Hopefully, exponential growth in memory density will outpace linear (as a function of programming effort) growth of Nyquist. II. Open Sound Control and Nyquist Open Sound Control (OSC) is a simple protocol for communicating music control parameters between software applications and across networks. For more information, see http://www.cnmat.berkeley.edu/OpenSoundControl/. The Nyquist implementation of Open Sound Control is simple: an array of floats can be set by OSC messages and read by Nyquist functions. That is about all there is to it. Note: Open Sound Control must be enabled by calling osc-enable(t). If this fails under Windows, see the installation instructions in sys/win/README.txt regarding SystemRoot. To control something in (near) real-time, you need to access a slider value as if it a signal, or more properly, a Nyquist SOUND type. The function snd-slider, described in Section 7.6.1, takes a slider number and returns a SOUND type representing the current value of the slider. To fully understand this function, you need to know something about how Nyquist is actually computing sounds. Sounds are normally computed on demand. So the result returned by snd-slider does not immediately compute any samples. Samples are only computed when something tries to use this signal. At that time, the slider value is read. Normally, if the slider is used to control a sound, you will hear changes in the sound pretty soon after the slider value changes. However, one thing that can interfere with this is that SOUND samples are computed in blocks of about 1000 samples. When the slider value is read, the same value is used to fill a block of 1000 samples, so even if the sample rate is 44,100 Hz, the effective slider sample rate is 44,100/1000, or 44.1 Hz. If you give the slider a very low sample rate, say 1000, then slider value changes will only be noticed by Nyquist approximately once per second. For this reason, you should normally use the audio sample rate (typically 44,100 Hz) for the rate of the snd-slider output SOUND. (Yes, this is terribly wasteful to represent each slider value with 1000 samples, but Nyquist was not designed for low-latency computation, and this is an expedient work-around.) In addition to reading sliders as continually changing SOUNDs, you can get the slider value as a Lisp FLONUM (a floating point number) using get-slider-value, described in Section 7.6.1. This might be useful if you are computing a sequence of many notes (or other sound events) and want to apply the current slider value to the whole note or sound event. Note that if you store the value returned by snd-slider in a variable, you will capture the history of the slider changes. This will take a lot of memory, so be careful. Suppose you write a simple expression such as (hzosc (mult 1000 (snd-slider 0 ...))) (or in SAL, hzosc(1000 * snd-slider(0 ...))) to control an oscillator frequency with a slider. How long does this sound last? The duration of hzosc is the duration of the frequency control, so what is the duration of a slider? To avoid infinitely long signals, you must specify a duration as one of the parameters of snd-slider. You might be thinking, what if I just want to tell the slider when to stop? At present, you cannot do that, but in the future there should be a function that stops when its input goes to zero. Then, moving a slider to zero could end the signal (and if you multiplied a complex sound by one of these ending functions, everything in the sound would end and be garbage collected). Another thing you might want to do with interactive control is start some sound. The trigger function computes an instance of a behavior each time an input SOUND goes from zero to greater-than-zero. This could be used, for example, to create a sequence of notes. The snd-slider function has some parameters that may be unfamiliar. The second parameter, t0, is the starting time of the sound. This should normally be local-to-global(0), an expression that computes the instantiation time of the current expression. This will often be zero, but if you call snd-slider from inside a seq or seq-rep, the starting time may not be zero. The srate parameter is the sample rate to return. This should normally be the audio sample rate you are working with, which is typically *default-sound- srate*. II.1. Sending Open Sound Control Messages A variety of programs support OSC. The only OSC message interpreted by Nyquist has an address of /slider, and two parameters: an integer slider number and a float value, nominally from 0.0 to 1.0. Two small programs are included in the Nyquist distribution for sending OSC messages. (Both can be found in the same directory as the nyquist executable.) The first one, osc-test-client sends a sequence of messages that just cause slider 0 to ramp slowly up and down. If you run this on a command line, you can use "?" or "h" to get help information. There is an interactive mode that lets you send each OSC message by typing RETURN. II.2. The ser-to-osc Program The second program is ser-to-osc, a program that reads serial input (for example from a PIC-based microcontroller) and sends OSC messages. Run this command-line program from a shell (a terminal window under OS X or Linux; use the CMD program under Windows). You must name the serial input device on the command line, e.g. under OS X, you might run: ./ser-to-osc /dev/tty.usbserial-0000103D (Note that the program name is preceded by ``./". This tells the shell exactly where to find the executable program in case the current directory is not on the search path for executable programs.) Under Windows, you might run: ser-to-osc com4 (Note that you do not type ``./'' in front of a windows program.) To use ser-to-osc, you will have to find the serial device. On the Macintosh and Linux, try the following: ls /dev/*usb* This will list all serial devices with ``usb'' in their names. Probably, one will be a name similar to /dev/tty.usbserial-0000103D. The ser-to-osc program will echo data that it receives, so you should know if things are working correctly. Under Windows, open Control Panel from the Start menu, and open the System control panel. Select the Hardware tab and click the Device Manager button. Look in the device list under Ports (COM & LPT). When you plug in your serial or USB device, you should see a new entry appear, e.g. COM4. This is the device name you need. The format for the serial input is: any non-whitespace character(s), a slider number, a slider value, and a newline (control-j or ASCII 0x0A). These fields need to be separated by tabs or spaces. An optional carriage return (control-m or ASCII 0x0D) preceding the ASCII 0x0A is ignored. The slider number should be in decimal, and theh slider value is a decimal number from 0 to 255. This is scaled to the range 0.0 to 1.0 (so an input of 255 translates to 1.0). There is a simple test program in demos/osc-test.lsp you can run to try out control with Open Sound Control. There are two examples in that file. One uses snd-slider to control the frequency of an oscillator. The other uses get-slider-value to control the pitch of grains in a granular synthesis process. III. Intgen This documentation describes Intgen, a program for generating XLISP to C interfaces. Intgen works by scanning .h files with special comments in them. Intgen builds stubs that implement XLISP SUBR's. When the SUBR is called, arguments are type-checked and passed to the C routine declared in the .h file. Results are converted into the appropriate XLISP type and returned to the calling XLISP function. Intgen lets you add C functions into the XLISP environment with very little effort. The interface generator will take as command-line input: - the name of the .c file to generate (do not include the .c extension; e.g. write xlexten, not xlexten.c); - a list of .h files. Alternatively, the command line may specify a command file from which to read file names. The command file name should be preceded by "@", for example: intgen @sndfns.cl reads sndfns.cl to get the command-line input. Only one level of indirection is allowed. The output is: - a single .c file with one SUBR defined for each designated routine in a .h file. - a .h file that declares each new C routine. E.g. if the .c file is named xlexten.c, this file will be named xlextendefs.h; - a .h file that extends the SUBR table used by Xlisp. E.g. if the .c file is named xlexten.c, then this file is named xlextenptrs.h; - a .lsp file with lisp initialization expressions copied from the .h files. This file is only generated if at least one initialization expression is encountered. For example, the command line intgen seint ~setypes.h access.h generates the file seint.c, using declarations in setypes.h and access.h. Normally, the .h files are included by the generated file using #include commands. A ~ before a file means do not include the .h file. (This may be useful if you extend xlisp.h, which will be included anyway). Also generated will be setintdefs.h and seintptrs.h. III.0.1. Extending Xlisp Any number of .h files may be named on the command line to Intgen, and Intgen will make a single .c file with interface routines for all of the .h files. On the other hand, it is not necessary to put all of the extensions to Xlisp into a single interface file. For example, you can run Intgen once to build interfaces to window manager routines, and again to build interfaces to a new data type. Both interfaces can be linked into Xlisp. To use the generated files, you must compile the .c files and link them with all of the standard Xlisp object files. In addition, you must edit the file localdefs.h to contain an #include for each *defs.h file, and edit the file localptrs.h to include each *ptrs.h file. For example, suppose you run Intgen to build soundint.c, fugueint.c, and tableint.c. You would then edit localdefs.h to contain the following: #include "soundintdefs.h" #include "fugueintdefs.h" #include "tableintdefs.h" and edit localptrs.h to contain: #include "soundintptrs.h" #include "fugueintptrs.h" #include "tableintptrs.h" These localdefs.h and localptrs.h files are in turn included by xlftab.c which is where Xlisp builds a table of SUBRs. To summarize, building an interface requires just a few simple steps: - Write C code to be called by Xlisp interface routines. This C code does the real work, and in most cases is completely independent of Xlisp. - Add comments to .h files to tell Intgen which routines to build interfaces to, and to specify the types of the arguments. - Run Intgen to build interface routines. - Edit localptrs.h and localdefs.h to include generated .h files. - Compile and link Xlisp, including the new C code. III.1. Header file format Each routine to be interfaced with Xlisp must be declared as follows: type-name routine-name(); /* LISP: (func-name type type ...) */ 1 2 The comment may be on the line following the declaration, but the declaration and the comment must each be on no more than one line. The characters LISP: at the beginning of the comment mark routines to put in the interface. The comment also gives the type and number of arguments. The function, when accessed from lisp will be known as func-name, which need not bear any relationship to routine-name. By convention, underscores in the C routine-name should be converted to dashes in func-name, and func-name should be in all capitals. None of this is enforced or automated though. Legal type_names are: LVAL returns an Xlisp datum. atom_type equivalent to LVAL, but the result is expected to be an atom. value_type a value as used in Dannenberg's score editor. event_type an event as used in Dannenberg's score editor. int interface will convert int to Xlisp FIXNUM. boolean interface will convert int to T or nil. float or double interface converts to FLONUM. char * or string or string_type interface converts to STRING. The result string will be copied into the XLISP heap. void interface will return nil. It is easy to extend this list. Any unrecognized type will be coerced to an int and then returned as a FIXNUM, and a warning will be issued. The ``*'' after char must be followed by routine-name with no intervening space. Parameter types may be any of the following: FIXNUM C routine expects an int. FLONUM or FLOAT C routine expects a double. STRING C routine expects char *, the string is not copied. VALUE C routine expects a value_type. (Not applicable to Fugue.) EVENT C routine expects an event_type. (Not applicable to Fugue.) ANY C routine expects LVAL. ATOM C routine expects LVAL which is a lisp atom. FILE C routine expects FILE *. SOUND C routine expects a SoundPtr. Any of these may be followed by ``*'': FIXNUM*, FLONUM*, STRING*, ANY*, FILE*, indicating C routine expects int *, double *, char **, LVAL *, or FILE ** . This is basically a mechanism for returning more than one value, not a mechanism for clobbering XLisp values. In this spirit, the interface copies the value (an int, double, char *, LVAL, or FILE *) to a local variable and passes the address of that variable to the C routine. On return, a list of resulting ``*'' parameters is constructed and bound to the global XLisp symbol *RSLT*. (Strings are copied.) If the C routine is void, then the result list is also returned by the corresponding XLisp function. Note 1: this does not support C routines like strcpy that modify strings, because the C routine gets a pointer to the string in the XLisp heap. However, you can always add an intermediate routine that allocates space and then calls strcpy, or whatever. Note 2: it follows that a new XLisp STRING will be created for each STRING* parameter. Note 3: putting results on a (global!) symbol seems a bit unstructured, but note that one could write a multiple-value binding macro that hides this ugliness from the user if desired. In practice, I find that pulling the extra result values from *RSLT* when needed is perfectly acceptable. For parameters that are result values only, the character ``^'' may be substituted for ``*''. In this case, the parameter is not to be passed in the XLisp calling site. However, the address of an initialized local variable of the given type is passed to the corresponding C function, and the resulting value is passed back through *RSLT* as ordinary result parameter as described above. The local variables are initialized to zero or NULL. III.2. Using #define'd macros If a comment of the form: /* LISP: type-name (routine-name-2 type-1 type-2 ...) */ appears on a line by itself and there was a #define on the previous line, then the preceding #define is treated as a C routine, e.g. #define leftshift(val, count) ((val) << (count)) /* LISP: int (LOGSHIFT INT INT) */ will implement the LeLisp function LOGSHIFT. The type-name following ``LISP:'' should have no spaces, e.g. use ANY*, not ANY *. III.3. Lisp Include Files Include files often define constants that we would like to have around in the Lisp world, but which are easier to initialize just by loading a text file. Therefore, a comment of the form: /* LISP-SRC: (any lisp expression) */ will cause Intgen to open a file name.lsp and append (any lisp expression) to name.lsp, where name is the interface name passed on the command line. If none of the include files examined have comments of this form, then no name.lsp file is generated. Note: the LISP-SRC comment must be on a new line. III.4. Example This file was used for testing Intgen. It uses a trick (ok, it's a hack) to interface to a standard library macro (tolower). Since tolower is already defined, the macro ToLower is defined just to give Intgen a name to call. Two other routines, strlen and tough, are interfaced as well. /* igtest.h -- test interface for intgen */ #define ToLower(c) tolower(c) /* LISP: int (TOLOWER FIXNUM) */ int strlen(); /* LISP: (STRLEN STRING) */ void tough(); /* LISP: (TOUGH FIXNUM* FLONUM* STRING ANY FIXNUM) */ III.5. More Details Intgen has some compiler switches to enable/disable the use of certain types, including VALUE and EVENT types used by Dannenberg's score editing work, the SOUND type used by Fugue, and DEXT and SEXT types added for Dale Amon. Enabling all of these is not likely to cause problems, and the chances of an accidental use of these types getting through the compiler and linker seems very small. IV. XLISP: An Object-oriented Lisp Version 2.0 February 6, 1988 by David Michael Betz 127 Taylor Road Peterborough, NH 03458 Copyright (c) 1988, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use IV.1. Introduction XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers. Implementations of XLISP run on virtually every operating system. XLISP is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users. Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects Object and Class as primitives. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances (it is the only object that is an instance of itself). This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming. I recommend the book Lisp by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp. You will probably also need a copy of Common Lisp: The Language by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document. IV.2. A Note From The Author If you have any problems with XLISP, feel free to contact me [me being David Betz - RBD] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users [e.g. that Dannenberg fellow - RBD] have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me. If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it. Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However, PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!! I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run. IV.3. XLISP Command Loop When XLISP is started, it first tries to load the workspace xlisp.wks from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols. Then XLISP attempts to load init.lsp from the current directory. It then loads any files named as parameters on the command line (after appending .lsp to their names). XLISP then issues the following prompt: > This indicates that XLISP is waiting for an expression to be typed. When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed. IV.4. Special Characters When XLISP is running from a console, some control characters invoke operations: - Backspace and Delete characters erase the previous character on the input line (if any). - Control-U erases the entire input line. - Control-C executes the TOP-LEVEL function. - Control-G executes the CLEAN-UP function. - Control-P executes the CONTINUE function. - Control-B stops execution and enters the break command loop. Execution can be continued by typing Control-P or (CONTINUE). - Control-E turns on character echoing (Linux and Mac OS X only). - Control-F turns off character echoing (Linux and Mac OS X only). - Control-T evaluates the INFO function. IV.5. Break Command Loop When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way: If the symbol *breakenable* is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed. If the symbol *tracenable* is true, a trace back is printed. The number of entries printed depends on the value of the symbol *tracelimit*. If this symbol is set to something other than a number, the entire trace back stack is printed. XLISP then enters a read/eval/print loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level read/eval/print loop in that if the user invokes the function continue, XLISP will continue from a correctable error. If the user invokes the function clean-up, XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt. If the symbol *breakenable* is nil, XLISP looks for a surrounding errset function. If one is found, XLISP examines the value of the print flag. If this flag is true, the error message is printed. In any case, XLISP causes the errset function call to return nil. If there is no surrounding errset function, XLISP prints the error message and returns to the top level. IV.6. Data Types There are several different data types available to XLISP programmers. - lists - symbols - strings - integers - characters - floats - objects - arrays - streams - subrs (built-in functions) - fsubrs (special forms) - closures (user defined functions) IV.7. The Evaluator The process of evaluation in XLISP: - Strings, integers, characters, floats, objects, arrays, streams, subrs, fsubrs and closures evaluate to themselves. - Symbols act as variables and are evaluated by retrieving the value associated with their current binding. - Lists are evaluated by examining the first element of the list and then taking one of the following actions: * If it is a symbol, the functional binding of the symbol is retrieved. * If it is a lambda expression, a closure is constructed for the function described by the lambda expression. * If it is a subr, fsubr or closure, it stands for itself. * Any other value is an error. Then, the value produced by the previous step is examined: * If it is a subr or closure, the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments. * If it is an fsubr, the fsubr is called using the remaining list elements as arguments (unevaluated). * If it is a macro, the macro is expanded using the remaining list elements as arguments (unevaluated). The macro expansion is then evaluated in place of the original macro call. IV.8. Lexical Conventions The following conventions must be followed when entering XLISP programs: Comments in XLISP code begin with a semi-colon character and continue to the end of the line. Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following: ( ) ' ` , " ; Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input. Integer literals consist of a sequence of digits optionally beginning with a + or -. The range of values an integer can represent is limited by the size of a C long on the machine on which XLISP is running. Floating point literals consist of a sequence of digits optionally beginning with a + or - and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C float (double on machines with 32 bit addresses) on the machine on which XLISP is running. Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the ``\'' character is used to allow non-printable characters to be included. The codes recognized are: - \\ means the character ``\'' - \n means newline - \t means tab - \r means return - \f means form feed - \nnn means the character whose octal code is nnn IV.9. Readtables The behavior of the reader is controlled by a data structure called a readtable. The reader uses the symbol *readtable* to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things: - NIL M Indicating an invalid character - :CONSTITUENT M Indicating a symbol constituent - :WHITE-SPACE M Indicating a whitespace character - (:TMACRO . fun) M Terminating readmacro - (:NMACRO . fun) M Non-terminating readmacro - :SESCAPE M Single escape character ('\') - :MESCAPE M Multiple escape character ('|') In the case of :TMACRO and :NMACRO, the fun component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return NIL to indicate that the character should be treated as white space or a value consed with NIL to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream. XLISP defines several useful read macros: - ' == (quote ) - #' == (function ) - #(...) == an array of the specified expressions - #x == a hexadecimal number (0-9,A-F) - #o == an octal number (0-7) - #b == a binary number (0-1) - #\ == the ASCII code of the character - #| ... |# == a comment - #: == an uninterned symbol - ` == (backquote ) - , == (comma ) - ,@ == (comma-at ) IV.10. Lambda Lists There are several forms in XLISP that require that a ``lambda list'' be specified. A lambda list is a definition of the arguments accepted by a function. There are four different types of arguments. The lambda list starts with required arguments. Required arguments must be specified in every call to the function. The required arguments are followed by the &optional arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an &optional argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to NIL. It is also possible to provide the name of a supplied-p variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the supplied- p variable will be bound to T if a value was specified in the call and NIL if the default value was used. The &optional arguments are followed by the &rest argument. The &rest argument gets bound to the remainder of the argument list after the required and &optional arguments have been removed. The &rest argument is followed by the &key arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol (a symbol that begins with a ``:''). The value of the second expression is the value of the keyword argument. Like &optional arguments, &key arguments can have initialization expressions and supplied-p variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a ``:'' to the beginning of the keyword argument symbol is used. In other words, if the keyword argument symbol is foo, the keyword will be :foo. The &key arguments are followed by the &aux variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the &aux variables. Here is the complete syntax for lambda lists: (rarg... [&optional [oarg | (oarg [init [svar]])]...] [&rest rarg] [&key [karg | ([karg | (key karg)] [init [svar]])]... &allow-other-keys] [&aux [aux | (aux [init])]...]) where: rarg is a required argument symbol oarg is an &optional argument symbol rarg is the &rest argument symbol karg is a &key argument symbol key is a keyword symbol aux is an auxiliary variable symbol init is an initialization expression svar is a supplied-p variable symbol IV.11. Objects Definitions: - selector M a symbol used to select an appropriate method - message M a selector and a list of actual arguments - method M the code that implements a message Since XLISP was created to provide a simple basis for experimenting with object-oriented programming, one of the primitive data types included is object. In XLISP, an object consists of a data structure containing a pointer to the object's class as well as an array containing the values of the object's instance variables. Officially, there is no way to see inside an object (look at the values of its instance variables). The only way to communicate with an object is by sending it a message. You can send a message to an object using the send function. This function takes the object as its first argument, the message selector as its second argument (which must be a symbol) and the message arguments as its remaining arguments. The send function determines the class of the receiving object and attempts to find a method corresponding to the message selector in the set of messages defined for that class. If the message is not found in the object's class and the class has a super-class, the search continues by looking at the messages defined for the super-class. This process continues from one super-class to the next until a method for the message is found. If no method is found, an error occurs. When a method is found, the evaluator binds the receiving object to the symbol self and evaluates the method using the remaining elements of the original list as arguments to the method. These arguments are always evaluated prior to being bound to their corresponding formal arguments. The result of evaluating the method becomes the result of the expression. Within the body of a method, a message can be sent to the current object by calling the (send self ...). The method lookup starts with the object's class regardless of the class containing the current method. Sometimes it is desirable to invoke a general method in a superclass even when it is overridden by a more specific method in a subclass. This can be accomplished by calling send-super, which begins the method lookup in the superclass of the class defining the current method rather than in the class of the current object. The send-super function takes a selector as its first argument (which must be a symbol) and the message arguments as its remaining arguments. Notice that send-super can only be sent from within a method, and the target of the message is always the current object (self). (send-super ...) is similar to (send self ...) except that method lookup begins in the superclass of the class containing the current method rather than the class of the current object. IV.12. The ``Object'' Class Object M the top of the class hierarchy. Messages: :show M show an object's instance variables. returns M the object :class M return the class of an object returns M the class of the object :isa class M test if object inherits from class returns M t if object is an instance of class or a subclass of class, otherwise nil :isnew M the default object initialization routine returns M the object IV.13. The ``Class'' Class Class M class of all object classes (including itself) Messages: :new M create a new instance of a class returns M the new class object :isnew ivars [cvars [super]] M initialize a new class ivars M the list of instance variable symbols cvars M the list of class variable symbols super M the superclass (default is object) returns M the new class object :answer msg fargs code M add a message to a class msg M the message symbol fargs M the formal argument list (lambda list) code M a list of executable expressions returns M the object When a new instance of a class is created by sending the message :new to an existing class, the message :isnew followed by whatever parameters were passed to the :new message is sent to the newly created object. When a new class is created by sending the :new message to the object Class, an optional parameter may be specified indicating the superclass of the new class. If this parameter is omitted, the new class will be a subclass of Object. A class inherits all instance variables, class variables, and methods from its super-class. IV.14. Profiling The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where eval is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an eval in the immediately (lexically) enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls. The list of all functions executed is maintained on the global *profile* variable. These functions in turn have *profile* properties, which maintain the counts. The profile system merely increments counters and puts symbols on the *profile* list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the profile function. Unfortunately, methods cannot be profiled with this facility. IV.15. Symbols - self M the current object (within a method context) - *obarray* M the object hash table - *standard-input* M the standard input stream - *standard-output* M the standard output stream - *error-output* M the error output stream - *trace-output* M the trace output stream - *debug-io* M the debug i/o stream - *breakenable* M flag controlling entering break loop on errors - *tracelist* M list of names of functions to trace - *tracenable* M enable trace back printout on errors - *tracelimit* M number of levels of trace back information - *evalhook* M user substitute for the evaluator function - *applyhook* M (not yet implemented) - *readtable* M the current readtable - *unbound* M indicator for unbound symbols - *gc-flag* M controls the printing of gc messages - *gc-hook* M function to call after garbage collection - *integer-format* M format for printing integers (``%d'' or ``%ld'') - *float-format* M format for printing floats (``%g'') - *print-case* M symbol output case (:upcase or :downcase) There are several symbols maintained by the read/eval/print loop. The symbols +, ++, and +++ are bound to the most recent three input expressions. The symbols *, ** and *** are bound to the most recent three results. The symbol - is bound to the expression currently being evaluated. It becomes the value of + at the end of the evaluation. IV.16. Evaluation Functions eval(expr) [SAL] (eval expr) [LISP] M evaluate an xlisp expression expr M the expression to be evaluated returns M the result of evaluating the expression apply(fun, args) [SAL] (apply fun args) [LISP] M apply a function to a list of arguments fun M the function to apply (or function symbol) args M the argument list returns M the result of applying the function to the arguments funcall(fun, arg...) [SAL] (funcall fun arg...) [LISP] M call a function with arguments fun M the function to call (or function symbol) arg M arguments to pass to the function returns M the result of calling the function with the arguments quote(expr) [SAL] (quote expr) [LISP] M return an expression unevaluated expr M the expression to be quoted (quoted) returns M expr unevaluated function(expr) [SAL] (function expr) [LISP] M get the functional interpretation expr M the symbol or lambda expression (quoted) returns M the functional interpretation backquote(expr) [SAL] (backquote expr) [LISP] M fill in a template expr M the template returns M a copy of the template with comma and comma-at expressions expanded lambda(args, expr...) [SAL] (lambda args expr...) [LISP] M make a function closure args M formal argument list (lambda list) (quoted) expr M expressions of the function body returns M the function closure get-lambda-expression(closure) [SAL] (get-lambda-expression closure) [LISP] M get the lambda expression closure M the closure returns M the original lambda expression macroexpand(form) [SAL] (macroexpand form) [LISP] M recursively expand macro calls form M the form to expand returns M the macro expansion macroexpand-1(form) [SAL] (macroexpand-1 form) [LISP] M expand a macro call form M the macro call form returns M the macro expansion IV.17. Symbol Functions set(sym, expr) [SAL] (set sym expr) [LISP] M set the value of a symbol sym M the symbol being set expr M the new value returns M the new value setq([sym, expr]...) [SAL] (setq [sym expr]...) [LISP] M set the value of a symbol sym M the symbol being set (quoted) expr M the new value returns M the new value psetq([sym, expr]...) [SAL] (psetq [sym expr]...) [LISP] M parallel version of setq sym M the symbol being set (quoted) expr M the new value returns M the new value setf([place, expr]...) [SAL] (setf [place expr]...) [LISP] M set the value of a field place M the field specifier (quoted): sym M set value of a symbol (car expr) M set car of a cons node (cdr expr) M set cdr of a cons node (nth n expr) M set nth car of a list (aref expr n) M set nth element of an array (get sym prop) M set value of a property (symbol-value sym) M set value of a symbol (symbol-function sym) M set functional value of a symbol (symbol-plist sym) M set property list of a symbol expr M the new value returns M the new value (defun sym fargs expr...) [LISP] M define a function (defmacro sym fargs expr...) [LISP] M define a macro sym M symbol being defined (quoted) fargs M formal argument list (lambda list) (quoted) expr M expressions constituting the body of the function (quoted) returns M the function symbol gensym([tag]) [SAL] (gensym [tag]) [LISP] M generate a symbol tag M string or number returns M the new symbol intern(pname) [SAL] (intern pname) [LISP] M make an interned symbol pname M the symbol's print name string returns M the new symbol make-symbol(pname) [SAL] (make-symbol pname) [LISP] M make an uninterned symbol pname M the symbol's print name string returns M the new symbol symbol-name(sym) [SAL] (symbol-name sym) [LISP] M get the print name of a symbol sym M the symbol returns M the symbol's print name symbol-value(sym) [SAL] (symbol-value sym) [LISP] M get the value of a symbol sym M the symbol returns M the symbol's value symbol-function(sym) [SAL] (symbol-function sym) [LISP] M get the functional value of a symbol sym M the symbol returns M the symbol's functional value symbol-plist(sym) [SAL] (symbol-plist sym) [LISP] M get the property list of a symbol sym M the symbol returns M the symbol's property list hash(sym, n) [SAL] (hash sym n) [LISP] M compute the hash index for a symbol sym M the symbol or string n M the table size (integer) returns M the hash index (integer) IV.18. Property List Functions get(sym, prop) [SAL] (get sym prop) [LISP] M get the value of a property sym M the symbol prop M the property symbol returns M the property value or nil putprop(sym, val, prop) [SAL] (putprop sym val prop) [LISP] M put a property onto a property list sym M the symbol val M the property value prop M the property symbol returns M the property value remprop(sym, prop) [SAL] (remprop sym prop) [LISP] M remove a property sym M the symbol prop M the property symbol returns M nil IV.19. Array Functions aref(array, n) [SAL] (aref array n) [LISP] M get the nth element of an array array M the array n M the array index (integer) returns M the value of the array element make-array(size) [SAL] (make-array size) [LISP] M make a new array size M the size of the new array (integer) returns M the new array vector(expr...) [SAL] (vector expr...) [LISP] M make an initialized vector expr M the vector elements returns M the new vector IV.20. List Functions car(expr) [SAL] (car expr) [LISP] M return the car of a list node expr M the list node returns M the car of the list node cdr(expr) [SAL] (cdr expr) [LISP] M return the cdr of a list node expr M the list node returns M the cdr of the list node cxxr(expr) [SAL] (cxxr expr) [LISP] M all cxxr combinations cxxxr(expr) [SAL] (cxxxr expr) [LISP] M all cxxxr combinations cxxxxr(expr) [SAL] (cxxxxr expr) [LISP] M all cxxxxr combinations first(expr) [SAL] (first expr) [LISP] M a synonym for car second(expr) [SAL] (second expr) [LISP] M a synonym for cadr third(expr) [SAL] (third expr) [LISP] M a synonym for caddr fourth(expr) [SAL] (fourth expr) [LISP] M a synonym for cadddr rest(expr) [SAL] (rest expr) [LISP] M a synonym for cdr cons(expr1, expr2) [SAL] (cons expr1 expr2) [LISP] M construct a new list node expr1 M the car of the new list node expr2 M the cdr of the new list node returns M the new list node list(expr...) [SAL] (list expr...) [LISP] M create a list of values expr M expressions to be combined into a list returns M the new list append(expr...) [SAL] (append expr...) [LISP] M append lists expr M lists whose elements are to be appended returns M the new list reverse(expr) [SAL] (reverse expr) [LISP] M reverse a list expr M the list to reverse returns M a new list in the reverse order last(list) [SAL] (last list) [LISP] M return the last list node of a list list M the list returns M the last list node in the list member(expr, list, test: test, test-not: test-not) [SAL] (member expr list &key :test :test-not) [LISP] M find an expression in a list expr M the expression to find list M the list to search :test M the test function (defaults to eql) :test-not M the test function (sense inverted) returns M the remainder of the list starting with the expression assoc(expr, alist, test: test, test-not: test-not) [SAL] (assoc expr alist &key :test :test-not) [LISP] M find an expression in an a-list expr M the expression to find alist M the association list :test M the test function (defaults to eql) :test-not M the test function (sense inverted) returns M the alist entry or nil remove(expr, list, test: test, test-not: test-not) [SAL] (remove expr list &key :test :test-not) [LISP] M remove elements from a list expr M the element to remove list M the list :test M the test function (defaults to eql) :test-not M the test function (sense inverted) returns M copy of list with matching expressions removed remove-if(test, list) [SAL] (remove-if test list) [LISP] M remove elements that pass test test M the test predicate list M the list returns M copy of list with matching elements removed remove-if-not(test, list) [SAL] (remove-if-not test list) [LISP] M remove elements that fail test test M the test predicate list M the list returns M copy of list with non-matching elements removed length(expr) [SAL] (length expr) [LISP] M find the length of a list, vector or string expr M the list, vector or string returns M the length of the list, vector or string nth(n, list) [SAL] (nth n list) [LISP] M return the nth element of a list n M the number of the element to return (zero origin) list M the list returns M the nth element or nil if the list isn't that long nthcdr(n, list) [SAL] (nthcdr n list) [LISP] M return the nth cdr of a list n M the number of the element to return (zero origin) list M the list returns M the nth cdr or nil if the list isn't that long mapc(fcn, list1, list...) [SAL] (mapc fcn list1 list...) [LISP] M apply function to successive cars fcn M the function or function name listn M a list for each argument of the function returns M the first list of arguments mapcar(fcn, list1, list...) [SAL] (mapcar fcn list1 list...) [LISP] M apply function to successive cars fcn M the function or function name listn M a list for each argument of the function returns M a list of the values returned mapl(fcn, list1, list...) [SAL] (mapl fcn list1 list...) [LISP] M apply function to successive cdrs fcn M the function or function name listn M a list for each argument of the function returns M the first list of arguments maplist(fcn, list1, list...) [SAL] (maplist fcn list1 list...) [LISP] M apply function to successive cdrs fcn M the function or function name listn M a list for each argument of the function returns M a list of the values returned subst(to, from, expr, test: test, test-not: test-not) [SAL] (subst to from expr &key :test :test-not) [LISP] M substitute expressions to M the new expression from M the old expression expr M the expression in which to do the substitutions :test M the test function (defaults to eql) :test-not M the test function (sense inverted) returns M the expression with substitutions sublis(alist, expr, test: test, test-not: test-not) [SAL] (sublis alist expr &key :test :test-not) [LISP] M substitute with an a-list alist M the association list expr M the expression in which to do the substitutions :test M the test function (defaults to eql) :test-not M the test function (sense inverted) returns M the expression with substitutions IV.21. Destructive List Functions rplaca(list, expr) [SAL] (rplaca list expr) [LISP] M replace the car of a list node list M the list node expr M the new value for the car of the list node returns M the list node after updating the car rplacd(list, expr) [SAL] (rplacd list expr) [LISP] M replace the cdr of a list node list M the list node expr M the new value for the cdr of the list node returns M the list node after updating the cdr nconc(list...) [SAL] (nconc list...) [LISP] M destructively concatenate lists list M lists to concatenate returns M the result of concatenating the lists delete(expr, test: test, test-not: test-not) [SAL] (delete expr &key :test :test-not) [LISP] M delete elements from a list expr M the element to delete list M the list :test M the test function (defaults to eql) :test-not M the test function (sense inverted) returns M the list with the matching expressions deleted delete-if(test, list) [SAL] (delete-if test list) [LISP] M delete elements that pass test test M the test predicate list M the list returns M the list with matching elements deleted delete-if-not(test, list) [SAL] (delete-if-not test list) [LISP] M delete elements that fail test test M the test predicate list M the list returns M the list with non-matching elements deleted sort(list, test) [SAL] (sort list test) [LISP] M sort a list list M the list to sort test M the comparison function returns M the sorted list IV.22. Predicate Functions atom(expr) [SAL] (atom expr) [LISP] M is this an atom? expr M the expression to check returns M t if the value is an atom, nil otherwise symbolp(expr) [SAL] (symbolp expr) [LISP] M is this a symbol? expr M the expression to check returns M t if the expression is a symbol, nil otherwise numberp(expr) [SAL] (numberp expr) [LISP] M is this a number? expr M the expression to check returns M t if the expression is a number, nil otherwise null(expr) [SAL] (null expr) [LISP] M is this an empty list? expr M the list to check returns M t if the list is empty, nil otherwise not(expr) [SAL] (not expr) [LISP] M is this false? expr M the expression to check return M t if the value is nil, nil otherwise listp(expr) [SAL] (listp expr) [LISP] M is this a list? expr M the expression to check returns M t if the value is a cons or nil, nil otherwise endp(list) [SAL] (endp list) [LISP] M is this the end of a list list M the list returns M t if the value is nil, nil otherwise consp(expr) [SAL] (consp expr) [LISP] M is this a non-empty list? expr M the expression to check returns M t if the value is a cons, nil otherwise integerp(expr) [SAL] (integerp expr) [LISP] M is this an integer? expr M the expression to check returns M t if the value is an integer, nil otherwise floatp(expr) [SAL] (floatp expr) [LISP] M is this a float? expr M the expression to check returns M t if the value is a float, nil otherwise stringp(expr) [SAL] (stringp expr) [LISP] M is this a string? expr M the expression to check returns M t if the value is a string, nil otherwise characterp(expr) [SAL] (characterp expr) [LISP] M is this a character? expr M the expression to check returns M t if the value is a character, nil otherwise arrayp(expr) [SAL] (arrayp expr) [LISP] M is this an array? expr M the expression to check returns M t if the value is an array, nil otherwise streamp(expr) [SAL] (streamp expr) [LISP] M is this a stream? expr M the expression to check returns M t if the value is a stream, nil otherwise objectp(expr) [SAL] (objectp expr) [LISP] M is this an object? expr M the expression to check returns M t if the value is an object, nil otherwise filep(expr) [SAL] (filep expr) [LISP](This is not part of standard XLISP nor is it built-in. Nyquist defines it though.) M is this a file? expr M the expression to check returns M t if the value is an object, nil otherwise boundp(sym) [SAL] (boundp sym) [LISP] M is a value bound to this symbol? sym M the symbol returns M t if a value is bound to the symbol, nil otherwise fboundp(sym) [SAL] (fboundp sym) [LISP] M is a functional value bound to this symbol? sym M the symbol returns M t if a functional value is bound to the symbol, nil otherwise minusp(expr) [SAL] (minusp expr) [LISP] M is this number negative? expr M the number to test returns M t if the number is negative, nil otherwise zerop(expr) [SAL] (zerop expr) [LISP] M is this number zero? expr M the number to test returns M t if the number is zero, nil otherwise plusp(expr) [SAL] (plusp expr) [LISP] M is this number positive? expr M the number to test returns M t if the number is positive, nil otherwise evenp(expr) [SAL] (evenp expr) [LISP] M is this integer even? expr M the integer to test returns M t if the integer is even, nil otherwise oddp(expr) [SAL] (oddp expr) [LISP] M is this integer odd? expr M the integer to test returns M t if the integer is odd, nil otherwise eq(expr1, expr2) [SAL] (eq expr1 expr2) [LISP] M are the expressions identical? expr1 M the first expression expr2 M the second expression returns M t if they are equal, nil otherwise eql(expr1, expr2) [SAL] (eql expr1 expr2) [LISP] M are the expressions identical? (works with all numbers) expr1 M the first expression expr2 M the second expression returns M t if they are equal, nil otherwise equal(expr1, expr2) [SAL] (equal expr1 expr2) [LISP] M are the expressions equal? expr1 M the first expression expr2 M the second expression returns M t if they are equal, nil otherwise IV.23. Control Constructs (cond pair...) [LISP] M evaluate conditionally pair M pair consisting of: (pred expr...) where: pred M is a predicate expression expr M evaluated if the predicate is not nil returns M the value of the first expression whose predicate is not nil and(expr...) [SAL] (and expr...) [LISP] M the logical and of a list of expressions expr M the expressions to be anded returns M nil if any expression evaluates to nil, otherwise the value of the last expression (evaluation of expressions stops after the first expression that evaluates to nil) or(expr...) [SAL] (or expr...) [LISP] M the logical or of a list of expressions expr M the expressions to be ored returns M nil if all expressions evaluate to nil, otherwise the value of the first non-nil expression (evaluation of expressions stops after the first expression that does not evaluate to nil) if(texpr, expr1[, expr2]) [SAL] (if texpr expr1 [expr2]) [LISP] M evaluate expressions conditionally texpr M the test expression expr1 M the expression to be evaluated if texpr is non-nil expr2 M the expression to be evaluated if texpr is nil returns M the value of the selected expression when(texpr, expr...) [SAL] (when texpr expr...) [LISP] M evaluate only when a condition is true texpr M the test expression expr M the expression(s) to be evaluated if texpr is non-nil returns M the value of the last expression or nil unless(texpr, expr...) [SAL] (unless texpr expr...) [LISP] M evaluate only when a condition is false texpr M the test expression expr M the expression(s) to be evaluated if texpr is nil returns M the value of the last expression or nil (case expr case...) [LISP] M select by case expr M the selection expression case M pair consisting of: (value expr...) where: value M is a single expression or a list of expressions (unevaluated) expr M are expressions to execute if the case matches returns M the value of the last expression of the matching case (let (binding...) expr...) [LISP] M create local bindings (let* (binding...) expr...) [LISP] M let with sequential binding binding M the variable bindings each of which is either: 1) a symbol (which is initialized to nil) 2) a list whose car is a symbol and whose cadr is an initialization expression expr M the expressions to be evaluated returns M the value of the last expression (flet (binding...) expr...) [LISP] M create local functions (labels (binding...) expr...) [LISP] M flet with recursive functions (macrolet (binding...) expr...) [LISP] M create local macros binding M the function bindings each of which is: (sym fargs expr...) where: sym M the function/macro name fargs M formal argument list (lambda list) expr M expressions constituting the body of the function/macro expr M the expressions to be evaluated returns M the value of the last expression catch(sym, expr...) [SAL] (catch sym expr...) [LISP] M evaluate expressions and catch throws sym M the catch tag expr M expressions to evaluate returns M the value of the last expression the throw expression throw(sym[, expr]) [SAL] (throw sym [expr]) [LISP] M throw to a catch sym M the catch tag expr M the value for the catch to return (defaults to nil) returns M never returns unwind-protect(expr, cexpr...) [SAL] (unwind-protect expr cexpr...) [LISP] M protect evaluation of an expression expr M the expression to protect cexpr M the cleanup expressions returns M the value of the expression Note: unwind-protect guarantees to execute the cleanup expressions even if a non-local exit terminates the evaluation of the protected expression IV.24. Looping Constructs (loop expr...) [LISP] M basic looping form expr M the body of the loop returns M never returns (must use non-local exit) (do (binding...) (texpr rexpr...) expr...) [LISP] (do* (binding...) (texpr rexpr...) expr...) [LISP] binding M the variable bindings each of which is either: 1) a symbol (which is initialized to nil) 2) a list of the form: (sym init [step]) where: sym M is the symbol to bind init M is the initial value of the symbol step M is a step expression texpr M the termination test expression rexpr M result expressions (the default is nil) expr M the body of the loop (treated like an implicit prog) returns M the value of the last result expression (dolist (sym expr [rexpr]) expr...) [LISP] M loop through a list sym M the symbol to bind to each list element expr M the list expression rexpr M the result expression (the default is nil) expr M the body of the loop (treated like an implicit prog) (dotimes (sym expr [rexpr]) expr...) [LISP] M loop from zero to n-1 sym M the symbol to bind to each value from 0 to n-1 expr M the number of times to loop rexpr M the result expression (the default is nil) expr M the body of the loop (treated like an implicit prog) IV.25. The Program Feature (prog (binding...) expr...) [LISP] M the program feature (prog* (binding...) expr...) [LISP] M prog with sequential binding binding M the variable bindings each of which is either: 1) a symbol (which is initialized to nil) 2) a list whose car is a symbol and whose cadr is an initialization expression expr M expressions to evaluate or tags (symbols) returns M nil or the argument passed to the return function block(name, expr...) [SAL] (block name expr...) [LISP] M named block name M the block name (symbol) expr M the block body returns M the value of the last expression (return [expr]) [LISP] M cause a prog construct to return a value expr M the value (defaults to nil) returns M never returns return-from(name[, value]) [SAL] (return-from name [value]) [LISP] M return from a named block name M the block name (symbol) value M the value to return (defaults to nil) returns M never returns tagbody(expr...) [SAL] (tagbody expr...) [LISP] M block with labels expr M expression(s) to evaluate or tags (symbols) returns M nil go(sym) [SAL] (go sym) [LISP] M go to a tag within a tagbody or prog sym M the tag (quoted) returns M never returns (progv slist vlist expr...) [LISP] M dynamically bind symbols slist M list of symbols vlist M list of values to bind to the symbols expr M expression(s) to evaluate returns M the value of the last expression prog1(expr1, expr...) [SAL] (prog1 expr1 expr...) [LISP] M execute expressions sequentially expr1 M the first expression to evaluate expr M the remaining expressions to evaluate returns M the value of the first expression prog2(expr1, expr2, expr...) [SAL] (prog2 expr1 expr2 expr...) [LISP] M execute expressions sequentially expr1 M the first expression to evaluate expr2 M the second expression to evaluate expr M the remaining expressions to evaluate returns M the value of the second expression progn(expr...) [SAL] (progn expr...) [LISP] M execute expressions sequentially expr M the expressions to evaluate returns M the value of the last expression (or nil) IV.26. Debugging and Error Handling trace(sym) [SAL] (trace sym) [LISP] M add a function to the trace list sym M the function to add (quoted) returns M the trace list untrace(sym) [SAL] (untrace sym) [LISP] M remove a function from the trace list sym M the function to remove (quoted) returns M the trace list error(emsg[, arg]) [SAL] (error emsg [arg]) [LISP] M signal a non-correctable error emsg M the error message string arg M the argument expression (printed after the message) returns M never returns cerror(cmsg, emsg[, arg]) [SAL] (cerror cmsg emsg [arg]) [LISP] M signal a correctable error cmsg M the continue message string emsg M the error message string arg M the argument expression (printed after the message) returns M nil when continued from the break loop break([bmsg[, arg]]) [SAL] (break [bmsg [arg]]) [LISP] M enter a break loop bmsg M the break message string (defaults to **break**) arg M the argument expression (printed after the message) returns M nil when continued from the break loop (clean-up) [LISP] M clean-up after an error returns M never returns (top-level) [LISP] M clean-up after an error and return to the top level returns M never returns (continue) [LISP] M continue from a correctable error returns M never returns (errset expr [pflag]) [LISP] M trap errors expr M the expression to execute pflag M flag to control printing of the error message returns M the value of the last expression consed with nil or nil on error (baktrace [n]) [LISP] M print n levels of trace back information n M the number of levels (defaults to all levels) returns M nil (evalhook expr ehook ahook [env]) [LISP] M evaluate with hooks expr M the expression to evaluate ehook M the value for *evalhook* ahook M the value for *applyhook* env M the environment (default is nil) returns M the result of evaluating the expression profile(flag) [SAL] (profile flag) [LISP](This is not a standard XLISP 2.0 function.) M turn profiling on or off. flag M nil turns profiling off, otherwise on returns M the previous state of profiling. IV.27. Arithmetic Functions truncate(expr) [SAL] (truncate expr) [LISP] M truncates a floating point number to an integer expr M the number returns M the result of truncating the number float(expr) [SAL] (float expr) [LISP] M converts an integer to a floating point number expr M the number returns M the result of floating the integer (+ expr...) [LISP] M add a list of numbers expr M the numbers returns M the result of the addition (- expr...) [LISP] M subtract a list of numbers or negate a single number expr M the numbers returns M the result of the subtraction (* expr...) [LISP] M multiply a list of numbers expr M the numbers returns M the result of the multiplication (/ expr...) [LISP] M divide a list of numbers expr M the numbers returns M the result of the division (1+ expr) [LISP] M add one to a number expr M the number returns M the number plus one (1- expr) [LISP] M subtract one from a number expr M the number returns M the number minus one rem(expr...) [SAL] (rem function) expr...) [LISP] M remainder of a list of numbers expr M the numbers returns M the result of the remainder operation min(expr...) [SAL] (min expr...) [LISP] M the smallest of a list of numbers expr M the expressions to be checked returns M the smallest number in the list max(expr...) [SAL] (max expr...) [LISP] M the largest of a list of numbers expr M the expressions to be checked returns M the largest number in the list abs(expr) [SAL] (abs expr) [LISP] M the absolute value of a number expr M the number returns M the absolute value of the number gcd(n1, n2...) [SAL] (gcd n1 n2...) [LISP] M compute the greatest common divisor n1 M the first number (integer) n2 M the second number(s) (integer) returns M the greatest common divisor random(n) [SAL] (random n) [LISP] M compute a random number between 0 and n-1 inclusive n M the upper bound (integer) returns M a random number rrandom() [SAL] (rrandom) [LISP] M compute a random real number between 0 and 1 inclusive returns M a random floating point number sin(expr) [SAL] (sin expr) [LISP] M compute the sine of a number expr M the floating point number returns M the sine of the number cos(expr) [SAL] (cos expr) [LISP] M compute the cosine of a number expr M the floating point number returns M the cosine of the number tan(expr) [SAL] (tan expr) [LISP] M compute the tangent of a number expr M the floating point number returns M the tangent of the number atan(expr[, expr2]) [SAL] (atan expr [expr2]) [LISP](This is not a standard XLISP 2.0 function.) M compute the arctangent expr M the value of x expr2 M the value of y (default value is 1.0) returns M the arctangent of x/y expt(x-expr, y-expr) [SAL] (expt x-expr y-expr) [LISP] M compute x to the y power x-expr M the floating point number y-expr M the floating point exponent returns M x to the y power exp(x-expr) [SAL] (exp x-expr) [LISP] M compute e to the x power x-expr M the floating point number returns M e to the x power sqrt(expr) [SAL] (sqrt expr) [LISP] M compute the square root of a number expr M the floating point number returns M the square root of the number (< n1 n2...) [LISP] M test for less than (<= n1 n2...) [LISP] M test for less than or equal to (= n1 n2...) [LISP] M test for equal to (/= n1 n2...) [LISP] M test for not equal to (>= n1 n2...) [LISP] M test for greater than or equal to (> n1 n2...) [LISP] M test for greater than n1 M the first number to compare n2 M the second number to compare returns M t if the results of comparing n1 with n2, n2 with n3, etc., are all true. IV.28. Bitwise Logical Functions logand(expr...) [SAL] (logand expr...) [LISP] M the bitwise and of a list of numbers expr M the numbers returns M the result of the and operation logior(expr...) [SAL] (logior expr...) [LISP] M the bitwise inclusive or of a list of numbers expr M the numbers returns M the result of the inclusive or operation logxor(expr...) [SAL] (logxor expr...) [LISP] M the bitwise exclusive or of a list of numbers expr M the numbers returns M the result of the exclusive or operation lognot(expr) [SAL] (lognot expr) [LISP] M the bitwise not of a number expr M the number returns M the bitwise inversion of number IV.29. String Functions string(expr) [SAL] (string expr) [LISP] M make a string from a value expr M an integer (which is first converted into its ASCII character value), string, character, or symbol returns M the string representation of the argument string-search(pat, str, start: start, end: end) [SAL] (string-search pat str &key :start :end) [LISP](This is not a standard XLISP 2.0 function.) M search for pattern in string pat M a string to search for str M the string to be searched :start M the starting offset in str :end M the ending offset + 1 returns M index of pat in str or NIL if not found string-trim(bag, str) [SAL] (string-trim bag str) [LISP] M trim both ends of a string bag M a string containing characters to trim str M the string to trim returns M a trimed copy of the string string-left-trim(bag, str) [SAL] (string-left-trim bag str) [LISP] M trim the left end of a string bag M a string containing characters to trim str M the string to trim returns M a trimed copy of the string string-right-trim(bag, str) [SAL] (string-right-trim bag str) [LISP] M trim the right end of a string bag M a string containing characters to trim str M the string to trim returns M a trimed copy of the string string-upcase(str, start: start, end: end) [SAL] (string-upcase str &key :start :end) [LISP] M convert to uppercase str M the string :start M the starting offset :end M the ending offset + 1 returns M a converted copy of the string string-downcase(str, start: start, end: end) [SAL] (string-downcase str &key :start :end) [LISP] M convert to lowercase str M the string :start M the starting offset :end M the ending offset + 1 returns M a converted copy of the string nstring-upcase(str, start: start, end: end) [SAL] (nstring-upcase str &key :start :end) [LISP] M convert to uppercase str M the string :start M the starting offset :end M the ending offset + 1 returns M the converted string (not a copy) nstring-downcase(str, start: start, end: end) [SAL] (nstring-downcase str &key :start :end) [LISP] M convert to lowercase str M the string :start M the starting offset :end M the ending offset + 1 returns M the converted string (not a copy) strcat(expr...) [SAL] (strcat expr...) [LISP] M concatenate strings expr M the strings to concatenate returns M the result of concatenating the strings subseq(string, start[, end]) [SAL] (subseq string start [end]) [LISP] M extract a substring string M the string start M the starting position (zero origin) end M the ending position + 1 (defaults to end) returns M substring between start and end string<(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string< str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string<=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string<= str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string= str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string/=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string/= str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string>=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string>= str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string>(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string> str1 str2 &key :start1 :end1 :start2 :end2) [LISP] str1 M the first string to compare str2 M the second string to compare :start1 M first substring starting offset :end1 M first substring ending offset + 1 :start2 M second substring starting offset :end2 M second substring ending offset + 1 returns M t if predicate is true, nil otherwise Note: case is significant with these comparison functions. string-lessp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string-lessp str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string-not-greaterp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string-not-greaterp str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string-equalp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string-equalp str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string-not-equalp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string-not-equalp str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string-not-lessp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string-not-lessp str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string-greaterp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL] (string-greaterp str1 str2 &key :start1 :end1 :start2 :end2) [LISP] str1 M the first string to compare str2 M the second string to compare :start1 M first substring starting offset :end1 M first substring ending offset + 1 :start2 M second substring starting offset :end2 M second substring ending offset + 1 returns M t if predicate is true, nil otherwise Note: case is not significant with these comparison functions. IV.30. Character Functions char(string, index) [SAL] (char string index) [LISP] M extract a character from a string string M the string index M the string index (zero relative) returns M the ascii code of the character upper-case-p(chr) [SAL] (upper-case-p chr) [LISP] M is this an upper case character? chr M the character returns M t if the character is upper case, nil otherwise lower-case-p(chr) [SAL] (lower-case-p chr) [LISP] M is this a lower case character? chr M the character returns M t if the character is lower case, nil otherwise both-case-p(chr) [SAL] (both-case-p chr) [LISP] M is this an alphabetic (either case) character? chr M the character returns M t if the character is alphabetic, nil otherwise digit-char-p(chr) [SAL] (digit-char-p chr) [LISP] M is this a digit character? chr M the character returns M the digit weight if character is a digit, nil otherwise char-code(chr) [SAL] (char-code chr) [LISP] M get the ascii code of a character chr M the character returns M the ascii character code (integer) code-char(code) [SAL] (code-char code) [LISP] M get the character with a specified ascii code code M the ascii code (integer) returns M the character with that code or nil char-upcase(chr) [SAL] (char-upcase chr) [LISP] M convert a character to upper case chr M the character returns M the upper case character char-downcase(chr) [SAL] (char-downcase chr) [LISP] M convert a character to lower case chr M the character returns M the lower case character digit-char(n) [SAL] (digit-char n) [LISP] M convert a digit weight to a digit n M the digit weight (integer) returns M the digit character or nil char-int(chr) [SAL] (char-int chr) [LISP] M convert a character to an integer chr M the character returns M the ascii character code int-char(int) [SAL] (int-char int) [LISP] M convert an integer to a character int M the ascii character code returns M the character with that code char<(chr1, chr2...) [SAL] (char< chr1 chr2...) [LISP] char<=(chr1, chr2...) [SAL] (char<= chr1 chr2...) [LISP] char=(chr1, chr2...) [SAL] (char= chr1 chr2...) [LISP] char/=(chr1, chr2...) [SAL] (char/= chr1 chr2...) [LISP] char>=(chr1, chr2...) [SAL] (char>= chr1 chr2...) [LISP] char>(chr1, chr2...) [SAL] (char> chr1 chr2...) [LISP] chr1 M the first character to compare chr2 M the second character(s) to compare returns M t if predicate is true, nil otherwise Note: case is significant with these comparison functions. char-lessp(chr1, chr2...) [SAL] (char-lessp chr1 chr2...) [LISP] char-not-greaterp(chr1, chr2...) [SAL] (char-not-greaterp chr1 chr2...) [LISP] char-equalp(chr1, chr2...) [SAL] (char-equalp chr1 chr2...) [LISP] char-not-equalp(chr1, chr2...) [SAL] (char-not-equalp chr1 chr2...) [LISP] char-not-lessp(chr1, chr2...) [SAL] (char-not-lessp chr1 chr2...) [LISP] char-greaterp(chr1, chr2...) [SAL] (char-greaterp chr1 chr2...) [LISP] chr1 M the first string to compare chr2 M the second string(s) to compare returns M t if predicate is true, nil otherwise Note: case is not significant with these comparison functions. IV.31. Input/Output Functions read([stream[, eof[, rflag]]]) [SAL] (read [stream [eof [rflag]]]) [LISP] M read an expression stream M the input stream (default is standard input) eof M the value to return on end of file (default is nil) rflag M recursive read flag (default is nil) returns M the expression read (print expr [stream]) [LISP] M print an expression on a new line expr M the expression to be printed stream M the output stream (default is standard output) returns M the expression prin1(expr[, stream]) [SAL] (prin1 expr [stream]) [LISP] M print an expression expr M the expression to be printed stream M the output stream (default is standard output) returns M the expression princ(expr[, stream]) [SAL] (princ expr [stream]) [LISP] M print an expression without quoting expr M the expressions to be printed stream M the output stream (default is standard output) returns M the expression pprint(expr[, stream]) [SAL] (pprint expr [stream]) [LISP] M pretty print an expression expr M the expressions to be printed stream M the output stream (default is standard output) returns M the expression terpri([stream]) [SAL] (terpri [stream]) [LISP] M terminate the current print line stream M the output stream (default is standard output) returns M nil flatsize(expr) [SAL] (flatsize expr) [LISP] M length of printed representation using prin1 expr M the expression returns M the length flatc(expr) [SAL] (flatc expr) [LISP] M length of printed representation using princ expr M the expression returns M the length IV.32. The Format Function format(stream, fmt, arg...) [SAL] (format stream fmt arg...) [LISP] M do formated output stream M the output stream fmt M the format string arg M the format arguments returns M output string if stream is nil, nil otherwise The format string can contain characters that should be copied directly to the output and formatting directives. The formatting directives are: ~A M print next argument using princ ~S M print next argument using prin1 ~% M start a new line ~~ M print a tilde character ~ M ignore this one newline and white space on the next line up to the first non-white-space character or newline. This allows strings to continue across multiple lines IV.33. File I/O Functions Note that files are ordinarily opened as text. Binary files (such as standard midi files) must be opened with open-binary on non-unix systems. open(fname, direction: direction) [SAL] (open fname &key :direction) [LISP] M open a file stream fname M the file name string or symbol :direction M :input or :output (default is :input) returns M a stream open-binary(fname, direction: direction) [SAL] (open-binary fname &key :direction) [LISP] M open a binary file stream fname M the file name string or symbol :direction M :input or :output (default is :input) returns M a stream close(stream) [SAL] (close stream) [LISP] M close a file stream stream M the stream returns M nil setdir(path[, verbose]) [SAL] (setdir path [verbose]) [LISP](This is not a standard XLISP 2.0 function.) M set current directory path M the path of the new directory verbose M print error message if current directory cannot be changed to path returns M the resulting full path, e.g. (setdir ".") gets the current working directory, or nil if an error occurs listdir(path) [SAL] (listdir path) [LISP](This is not a standard XLISP 2.0 function.) M get a directory listing path M the path of the directory to be listed returns M list of filenames in the directory get-temp-path() [SAL] (get-temp-path) [LISP](This is not a standard XLISP 2.0 function.) M get a path where a temporary file can be created. Under Windows, this is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice c:\windows\. returns M the resulting full path as a string get-user() [SAL] (get-user) [LISP](This is not a standard XLISP 2.0 function.) M get the user ID. In Unix systems (including OS X and Linux), this is the value of the USER environment variable. In Windows, this is currently just ``nyquist'', which is also returned if the environment variable cannot be accessed. This function is used to avoid the case of two users creating files of the same name in the same temp directory. returns M the string naming the user find-in-xlisp-path(filename) [SAL] (find-in-xlisp-path filename) [LISP](This is not a standard XLISP 2.0 function.) M search the XLISP search path (e.g. XLISPPATH from the environment) for filename. If filename is not found as is, and there is no file extension, append ".lsp" to filename and search again. The current directory is not searched. filename M the name of the file to search for returns M a full path name to the first occurrence found read-char([stream]) [SAL] (read-char [stream]) [LISP] M read a character from a stream stream M the input stream (default is standard input) returns M the character peek-char([flag[, stream]]) [SAL] (peek-char [flag [stream]]) [LISP] M peek at the next character flag M flag for skipping white space (default is nil) stream M the input stream (default is standard input) returns M the character (integer) write-char(ch[, stream]) [SAL] (write-char ch [stream]) [LISP] M write a character to a stream ch M the character to write stream M the output stream (default is standard output) returns M the character read-int([stream[, length]]) [SAL] (read-int [stream [length]]) [LISP] M read a binary integer from a stream stream M the input stream (default is standard input) length M the length of the integer in bytes (default is 4) returns M the integer Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. write-int(ch[, stream[, length]]) [SAL] (write-int ch [stream [length]]) [LISP] M write a binary integer to a stream ch M the character to write stream M the output stream (default is standard output) length M the length of the integer in bytes (default is 4) returns M the integer Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. read-float([stream[, length]]) [SAL] (read-float [stream [length]]) [LISP] M read a binary floating-point number from a stream stream M the input stream (default is standard input) length M the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8) returns M the integer Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. write-float(ch[, stream[, length]]) [SAL] (write-float ch [stream [length]]) [LISP] M write a binary floating-point number to a stream ch M the character to write stream M the output stream (default is standard output) length M the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8) returns M the integer Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. read-line([stream]) [SAL] (read-line [stream]) [LISP] M read a line from a stream stream M the input stream (default is standard input) returns M the string read-byte([stream]) [SAL] (read-byte [stream]) [LISP] M read a byte from a stream stream M the input stream (default is standard input) returns M the byte (integer) write-byte(byte[, stream]) [SAL] (write-byte byte [stream]) [LISP] M write a byte to a stream byte M the byte to write (integer) stream M the output stream (default is standard output) returns M the byte (integer) IV.34. String Stream Functions These functions operate on unnamed streams. An unnamed output stream collects characters sent to it when it is used as the destination of any output function. The functions get-output-stream-string and get-output-stream-list return a string or a list of characters. An unnamed input stream is setup with the make-string-input-stream function and returns each character of the string when it is used as the source of any input function. make-string-input-stream(str[, start[, end]]) [SAL] (make-string-input-stream str [start [end]]) [LISP] str M the string start M the starting offset end M the ending offset + 1 returns M an unnamed stream that reads from the string make-string-output-stream)() [SAL] (make-string-output-stream) [LISP] returns M an unnamed output stream get-output-stream-string(stream) [SAL] (get-output-stream-string stream) [LISP] stream M the output stream returns M the output so far as a string Note: the output stream is emptied by this function get-output-stream-list(stream) [SAL] (get-output-stream-list stream) [LISP] stream M the output stream returns M the output so far as a list Note: the output stream is emptied by this function IV.35. System Functions Note: the load function first tries to load a file from the current directory. A .lsp extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. (The Macintosh version has no search path.) get-env(name) [SAL] (get-env name) [LISP] M get from an environment variable name M the name of the environment variable returns M string value of the environment variable, nil if variable does not exist (load fname &key :verbose :print) [LISP] M load a source file fname M the filename string or symbol :verbose M the verbose flag (default is t) :print M the print flag (default is nil) returns M the filename save(fname) [SAL] (save fname) [LISP] M save workspace to a file fname M the filename string or symbol returns M t if workspace was written, nil otherwise restore(fname) [SAL] (restore fname) [LISP] M restore workspace from a file fname M the filename string or symbol returns M nil on failure, otherwise never returns dribble([fname]) [SAL] (dribble [fname]) [LISP] M create a file with a transcript of a session fname M file name string or symbol (if missing, close current transcript) returns M t if the transcript is opened, nil if it is closed gc() [SAL] (gc) [LISP] M force garbage collection returns M nil expand(num) [SAL] (expand num) [LISP] M expand memory by adding segments num M the number of segments to add returns M the number of segments added alloc(num) [SAL] (alloc num) [LISP] M change number of nodes to allocate in each segment num M the number of nodes to allocate returns M the old number of nodes to allocate info() [SAL] (info) [LISP] M show information about memory usage. returns M nil room() [SAL] (room) [LISP] M show memory allocation statistics returns M nil type-of(expr) [SAL] (type-of expr) [LISP] M returns the type of the expression expr M the expression to return the type of returns M nil if the value is nil otherwise one of the symbols: SYMBOL M for symbols OBJECT M for objects CONS M for conses SUBR M for built-in functions FSUBR M for special forms CLOSURE M for defined functions STRING M for strings FIXNUM M for integers FLONUM M for floating point numbers CHARACTER M for characters FILE-STREAM M for file pointers UNNAMED-STREAM M for unnamed streams ARRAY M for arrays peek(addrs) [SAL] (peek addrs) [LISP] M peek at a location in memory addrs M the address to peek at (integer) returns M the value at the specified address (integer) poke(addrs, value) [SAL] (poke addrs value) [LISP] M poke a value into memory addrs M the address to poke (integer) value M the value to poke into the address (integer) returns M the value bigendianp() [SAL] (bigendianp) [LISP] M is this a big-endian machine? returns M T if this a big-endian architecture, storing the high-order byte of an integer at the lowest byte address of the integer; otherwise, NIL. (This is not a standard XLISP 2.0 function.) address-of(expr) [SAL] (address-of expr) [LISP] M get the address of an xlisp node expr M the node returns M the address of the node (integer) exit() [SAL] (exit) [LISP] M exit xlisp returns M never returns setup-console() [SAL] (setup-console) [LISP] M set default console attributes returns M NIL Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of ``Nyquist.'' This is normally accomplished by calling setup-console in system.lsp. In Nyquist, you can avoid this behavior by setting *setup-console* to NIL in your init.lsp file. If setup-console is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example. echoenabled(flag) [SAL] (echoenabled flag) [LISP] M turn console input echoing on or off flag M T to enable echo, NIL to disable returns M NIL Note: This function is only implemented under Linux and Mac OS X. If Nyquist I/O is redirected through pipes, the Windows version does not echo the input, but the Linux and Mac versions do. You can turn off echoing with this function. Under windows it is defined to do nothing. IV.36. File I/O Functions IV.36.1. Input from a File To open a file for input, use the open function with the keyword argument :direction set to :input. To open a file for output, use the open function with the keyword argument :direction set to :output. The open function takes a single required argument which is the name of the file to be opened. This name can be in the form of a string or a symbol. The open function returns an object of type FILE-STREAM if it succeeds in opening the specified file. It returns the value nil if it fails. In order to manipulate the file, it is necessary to save the value returned by the open function. This is usually done by assigning it to a variable with the setq special form or by binding it using let or let*. Here is an example: (setq fp (open "init.lsp" :direction :input)) Evaluating this expression will result in the file init.lsp being opened. The file object that will be returned by the open function will be assigned to the variable fp. It is now possible to use the file for input. To read an expression from the file, just supply the value of the fp variable as the optional stream argument to read. (read fp) Evaluating this expression will result in reading the first expression from the file init.lsp. The expression will be returned as the result of the read function. More expressions can be read from the file using further calls to the read function. When there are no more expressions to read, the read function will return nil (or whatever value was supplied as the second argument to read). Once you are done reading from the file, you should close it. To close the file, use the following expression: (close fp) Evaluating this expression will cause the file to be closed. IV.36.2. Output to a File Writing to a file is pretty much the same as reading from one. You need to open the file first. This time you should use the open function to indicate that you will do output to the file. For example: (setq fp (open "test.dat" :direction :output)) Evaluating this expression will open the file test.dat for output. If the file already exists, its current contents will be discarded. If it doesn't already exist, it will be created. In any case, a FILE-STREAM object will be returned by the OPEN function. This file object will be assigned to the fp variable. It is now possible to write to this file by supplying the value of the fp variable as the optional stream parameter in the print function. (print "Hello there" fp) Evaluating this expression will result in the string ``Hello there'' being written to the file test.dat. More data can be written to the file using the same technique. Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file. (close fp) Evaluating this expression will close the output file and make it permanent. IV.36.3. A Slightly More Complicated File Example This example shows how to open a file, read each Lisp expression from the file and print it. It demonstrates the use of files and the use of the optional stream argument to the read function. (do* ((fp (open "test.dat" :direction :input)) (ex (read fp) (read fp))) ((null ex) nil) (print ex)) REFERENCES [Dannenberg 89] Dannenberg, R. B. and C. L. Fraley. Fugue: Composition and Sound Synthesis With Lazy Evaluation and Behavioral Abstraction. In T. Wells and D. Butler (editor), Proceedings of the 1989 International Computer Music Conference, pages 76-79. International Computer Music Association, San Francisco, 1989. [Touretzky 84] Touretzky, David S. LISP: a gentle introduction to symbolic computation. Harper & Row, New York, 1984. Index Banded treble boost 52 Digit-char 69 ! 13, 36 Bandfx.lsp 52 Digit-char-p 69 != 13 Bandpass filter 23 Directory listing 70 !Call 40 Bandpass2 23 Directory, default sound !Clock 39 Bartok 38 file 27 !csec 38 Begin 13 Display statement, sal !Def 39 Behavioral abstraction 6 14 !End 40 Behaviors 19 Distortion tutorial 23 !msec 38 Bell sound 3 Distributions, probability !Ramp 39 Bernoulli distribution 45 !Rate 37 46 Division 25 !Seti 40 Bernoulli-dist 46 Do 67 !Setv 40 Beta distribution 46 Do* 67 !Tempo 37 Beta-dist 46 Dolby Pro-Logic 52 Big endian 71 Dolby Surround 52 # (Adagio articulation)Bigendianp 71 Dolist 67 37 Bilateral exponentialDoppler effect 53 #?, sal 13 distribution 45 Dot 36 #define'd macros 59 Bilateral-exponential-distDotimes 67 #f 13 45 Dotted durations 2 #t 13 Binary files 70 Dribble 71 Binomial distribution 46Drum samples 3 % (Adagio thirtysecondBinomial-dist 46 Drum 53 note) 36 Biquad 23 Drum machine 3, 53 % 13 Biquad-m 23 Drum sound 3 Bitwise Logical FunctionsDrum-loop 53 & 13 68 DSP in Lisp 3, 11 &= 15 Blank 36 Dtmf 52 Block 67 Dtmf-tone 52 * 13, 68 Both-case-p 69 Dubugging 29 *= 15 Boundp 66 Duration 36 *A4-Hertz* 19, 34 Bowed 24 Duration notation 2 *applyhook* 64 Bowed-freq 24 Duration of another sound *audio-markers* 27 Brass sound 3 28 *autonorm* 34 Break 62, 68 DX7 36 *autonorm-max-samples* Break button 4 Dynamic markings 37 34 Browse button 4 *autonorm-previous-peak* Browser, jnyqide 4 Echo 22 34 Build-harmonic 1, 19 Echoenabled 71 *autonorm-target* 34 Button bar 4 Editor for envelopes 4 *autonorm-type* 34 Buzz 21 Effect, reverberation *autonormflag* 34 23, 23 *breakenable* 34, 62, 64Call command 40 Effect, chorus 23, 31, *control-srate* 6, 26,Car 65 52 34 Case 36, 67 Effect, flange 51 *debug-io* 64 Case-insensitive 13 Effect, pitch shift 24, *default-control-srate* Catch 67 31 34 Cauchy distribution 45 Effect, reverberation *default-plot-file* 28 Cauchy-dist 45 31, 52 *default-sf-bits* 34 Cdr 65 Effect, stereo 52 *default-sf-dir* 27, 34 Cerror 68 Effect, stereo pan 52 *default-sf-format* 34 Change directory 70 Effect, swap channels 52 *default-sf-srate* 27,Char 69 Effect, widen 52 34 Char-code 69 Effects, phaser 51 *default-sound-srate* 34Char-downcase 69 EIghth note 2, 36 *error-output* 64 Char-equalp 70 Elapsed audio time 27 *evalhook* 64 Char-greaterp 70 Emacs, using Nyquist with *file-separator* 34 Char-int 69 71 *float-format* 64 Char-lessp 70 Empty list 13 *gc-flag* 64 Char-not-equalp 70 End 13 *gc-hook* 64 Char-not-greaterp 70 End command 40 *integer-format* 64 Char-not-lessp 70 Endian 71 *loud* 6 Char-upcase 69 Endless tones 3 *obarray* 64 Char/= 70 Endp 66 *print-case* 64 Char< 70 Env 2, 19 *readtable* 63, 64 Char<= 70 Env-note 2 *rslt* 34, 59 Char= 70 Envedit button 4 *sound-srate* 6, 26, 34 Char> 70 Envelope 2 *soundenable* 34 Char>= 70 Envelope editor 4 *standard-input* 64 Character Functions 69 Envelope follower 18, 29 *standard-output* 64 Characterp 66 Envelope generator 22 *start* 6 Chdir, sal 14 Envelopes 2 *stop* 6 Chorus 23, 29, 31, 51,Environment 6 *sustain* 6 52 Environment variables 71 *table* 34 Clarinet 24 Eq 67 *trace-output* 64 Clarinet sound 3 Eq button 4 *tracelimit* 62, 64 Clarinet-all 24 Eq-band 23 *tracelist* 64 Clarinet-freq 24 Eq-highshelf 23 *tracenable* 34, 62, 64 Class 64 Eq-lowshelf 23 *transpose* 6 Class class 64 Eql 67 *unbound* 64 Clean-up 68 Equal 67 *warp* 6, 25 Clip 10, 24, 29 Equalization 23, 51 Clipping repair 51 Equalization editor 4 + 13, 68 Clock 39 Error 68 += 15 Clock command 39 Error Handling 68 Close 70 Errors iii , (Adagio) 38 Co-termination 28 Errset 68 Code-char 69 Estimate frequency 25 - 13, 68 Comb 22 Eval 64 Comb filter 22 Eval pattern 44 . (Adagio) 36 Combination 26 Evalhook 68 Command Loop 62 Evaluation functions 64 / 13, 68 Commas 38 Evaluator 62 /= 68 Comment 36 Evenp 66 Comments 13 Event-dur 48 1+ 68 Compose 29 Event-end 48 1- 68 Compress 51 Event-expression 48 Compress-map 51 Event-get-attr 48 :answer 64 Compressor 18 Event-has-attr 48 :class 64 Concatenate strings 69 Event-set-attr 48 :isa 64 Cond 67 Event-set-dur 48 :isnew 64 Conditional expression,Event-set-expression 48 :new 64 sal 13 Event-set-time 48 :show 64 Configure nyquist 1 Event-time 48 Congen 22 Exclamation point 36 ; (Adagio) 38 Cons 65 Exec statement, sal 14 Console, XLISP 71 Exit 71 < 13, 68 Consp 66 Exit statement, sal 15 <= 13, 15, 68 Const 19 Exp 68 Constant function 19 Exp-dec 19 = 13, 68 Continue 68 Expand 71 Continuous-control-warp Exponent 42 > 13, 68 25 Exponential 25 >= 13, 15, 68 Continuous-sound-warp 26Exponential distribution Contour generator 22 45 @ 13 Control 19 Exponential envelope 19 @= 15 Control change 38 Exponential-dist 45 @@ 13 Control characters, XLISPExpr-get-attr 48 62 Expr-has-attr 48 A440 19 Control Constructs 67 Expr-set-attr 48 Abs 68 Control-A 27 Expression pattern 44 Abs-env 25 Control-srate-abs 26 Expressions, sal 13 Absolute stretch, sal 13Control-warp 19 Expt 68 Absolute time shift, salConvert sound to arrayExtending Xlisp 59 13 18 Extract 26 Absolute value 24, 29 Convolution 22 Extract-abs 26 Access samples 17 Convolve 22 Accidentals 36 Copier pattern 44 F (Adagio dynamic) 37 Accumulate pattern 44 Cos 68 F (Adagio Flat) 36 Accumulation pattern 44 Cue 19 Fast fourier transform Adagio 36 Cue-file 19 tutorial 35 Add offset to sound 29 Current-path 42 Fboundp 66 Add to file samples 28 Cxxr 65 Feedback FM Oscillator Add-action-to-workspace Cxxxr 65 21 50 Cxxxxr 65 Feedback-delay 22 Add-to-workspace 50 Cycle pattern 43 Feel factor 49 Additive synthesis, gongs FF (Adagio dynamic) 37 3 DarwiinRemoteOsc 19 FFF (Adagio dynamic) 37 Address-of 71 Data Types 62 Fft 35 Aftertouch 38 Db-average 51 Fft tutorial 35 Agc 51 Db-to-linear 18 File I/O Functions 70, Algorithmic CompositionDB0 2 72 43 DB1 2 Filep 66 All pass filter 22 DB10 2 Filter example 11 Alloc 71 Debugging 18, 28, 42, 68Finally clause, sal 15 Allpass2 23 Decf 42 Find string 69 Allpoles-from-lpc 41 Decrement 42 Find-in-xlisp-path 70 Alpass 22 Default durations 37 FIR filter 22 Alpass filter 22 Default 37 First 65 Amosc 21 Default sample rate 7 First derivative 20 Analog synthesizer 53 Default sound fileFlange 51 And 67 directory 27 Flange effect 51 Append 65 Default time 36 Flat 36 Apply 64 Define function 14 Flatc 70 Apply-banded-bass-boost Define variable 14 Flatsize 70 52 Defining Behaviors 7 Flet 67 Apply-banded-delay 52 Defmacro 64 Float 68 Apply-banded-treble-boost Defun 64 Floatp 66 52 Delay 22 Flute 24 Approximation 21 Delay, variable 29, 29 Flute sound 3 Arc-sine-dist 46 Delete 66 Flute-all 24 Arcsine distribution 46 Delete-if 66 Flute-freq 24 Aref 65 Delete-if-not 66 FM synthesis 11 Areson 23 Demos, bell sound 3 Fmfb 21 Args 42 Demos, distortion 23 Fmlfo 19 Arguments to a lispDemos, drum machine 3 Fmosc 21 function 42 Demos, drum sound 3 Fn button 4 Arithmetic Functions 68 Demos, fft 35 Follow 18 Arpeggiator 3 Demos, FM 11 Follower 29 Array from sound 18 Demos, FM synthesis 3 Force-srate 19 Array Functions 65 Demos, formants 3 Format 70 Array notation, sal 13 Demos, gong sound 3 Fourth 65 Arrayp 66 Demos, lpc 41 Frequency analysis 25 Articulation 36, 37 Demos, midi 36 Frequency Modulation 10 Assoc 65 Demos, piano 51 Full path name 42 Asterisk 36 Demos, pitch change 29 Funcall 64 At 25 Demos, rhythmic patternFunction 64 At Transformation 7 3 Function calls, sal 13 At, sal 13 Demos, ring modulation 2Function, sal 14 At-abs 25 Demos, sample-by-sampleFundamenal frequency At-abs, sal 13 3 estimation 25 Atan 68 Demos, scratch tutorial Atom 66 11 Gain 51 Atone 23 Demos, Shepard tones 23 Gamma-dist 45 Attributes 36 Demos, spectral analysisGate 18, 29 Audio markers 27 of a chord 3 Gaussian distribution 46 Automatic gain controlDemos, voice synthesisGaussian-dist 46 51 23 Gc 71 Autonorm-off 10, 27 Demos, wind sound 11 Gcd 68 Autonorm-on 10, 27 Derivative 20 GEN05 22 Average 29 Describe 50 Gensym 65 Destructive List FunctionsGeometric distribution Backquote 64 66 46 Backward 51 Developing code 42 Geometric-dist 46 Baktrace 68 Diff 26 Get 65 Banded bass boost 52 Difference 50 Get char 70 Banded delay 52 Difference of sounds 26 Get-duration 19 Get-env 71 Make-sum 44 Prod 20 Get-lambda-expression 64Make-symbol 65 Product 26 Get-loud 19 Make-window 44 Product pattern 44 Get-output-stream-list Maketable 19 Profile 68 71 Mandolin 24 Profiling 64 Get-output-stream-string Manipulation of scoresProg 67 71 48 Prog* 67 Get-slider-value 29 Mapc 66 Prog1 67 Get-sustain 19 Mapcar 66 Prog2 67 Get-temp-path 70 Mapl 66 Progn 68 Get-transpose 19 Maplist 66 Program 38 Get-user 70 Mark button 4 Program change 36 Get-warp 19 Markers, audio 27 Progv 67 Getenv 71 Markov analysis 45 Prologic 52 Global Variables 34 Markov pattern 44 Property List Functions Global variables, sal 14Markov-create-rules 45 65 Go 67 Max 68 Psetq 64 Gong sounds 3 Maximum 25, 68 Pulse oscillator 21 Granular synthesis 52 Maximum amplitude 10, 30Pulse-width modulation Graphical envelope editorMaximum of two sounds 30 21 4 Member 65 Push 42 Graphical equalization 4Memory usage 18 Putprop 65 Graphical equalizer 51 MF (Adagio dynamic) 37 Pwe 22 Grindef 42 Middle C 36 Pwe-list 22 MIDI 36 Pwer 22 H (Adagio Half note) 36 MIDI Clock 39 Pwer-list 22 H 2 MIDI file 49, 50 Pwev 22 Half note 2, 36 MIDI program 37 Pwev-list 22 Harmonic 19 Midi-show 52 Pwevr 22 Hash 65 Midi-show-file 52 Pwevr-list 22 Hd 2 Mikrokosmos 38 Pwl 21 Header file format 59 Min 68 Pwl-list 21 Heap pattern 44 Minimoog 53 Pwlr 21 High-pass filter 23 Minimum 25, 68 Pwlr-list 22 Highpass2 23 Minusp 66 Pwlv 21 Highpass4 23 Mix 26 Pwlv-list 21 Highpass6 23 Mix to file 28 Pwlvr 22 Highpass8 23 Mkwave 1 Pwlvr-list 22 Hp 23 Modalbar 24 Ht 2 Modulation wheel 38 Q (Adagio Quarter note) Hyperbolic-cosine-dist Modulo (rem 68 36 45 Mono to stereo 52 Q 2 Hz-to-step 18 Moog 53 Qd 2 Hzosc 20 Moving average 29 Qt 2 MP (Adagio dynamic) 37 Quantize 25 I (Adagio eIght note) 36Mult 2, 19, 26 Quarter note 2, 36 I 2 Multichannel Sounds 17 Quote 64 Iannis Xenakis 4 Multiple band effects 52 Id 2 Multiple commands 38 R (Adagio Rest) 36 IDE 1 Multiple tempi 39 Ramp 25 If 67 Multiplication 30 Random 42, 45, 68 If statement, sal 14 Multiply signals 26 Random pattern 43 Ifft 35 My-note 2 Rate 36, 37 Incf 42 Read 70 Increment 42 N (Adagio Next) 36 Read directory 70 Info 71 Natural 36 Read macros 63 Info button 4 Natural log 25 Read samples 17 Input from a File 72 Nband 51 Read samples from file Input/Output FunctionsNband-range 51 27 70 Nconc 66 Read samples in reverse Installation 1 Nested Transformations 7 51 Int-char 70 Newfile button 4 Read-byte 71 Integerp 66 Next Adagio command 36 Read-char 70 Integrate 20 Next in pattern 43 Read-float 71 Integrated DevelopmentNext pattern 43 Read-int 70 Environment 1 Nintendo WiiMote 19 Read-line 71 Intern 65 Noise 25 Readtables 63 Interoperability, sal andNoise gate 29 Real-random 42 lisp 15 Noise-gate 18 Recip 25 Interpolate 50 Normalization 10 Reciprocal 25 Intersection 50 Not 66 Rem 68 Intgen 59 Not enough memory forRemainder 68 Inverse 30 normalization 10Remove 65 Inverse fft 35 Notch filter 23 Remove-if 65 It 2 Notch2 23 Remove-if-not 65 Note list 26 Remprop 65 Jcrev 23 Nrev 23 Replace file samples 28 Jitter 49 Nstring-downcase 69 Replay button 4 Nstring-upcase 69 Require-from 42 K (Adagio control) 38 Nth 65 Resample 20 Karplus-Strong 21 Nthcdr 65 Resampling 19, 29 Karplus-Strong synthesisNull 66 Rescaling 10 3 Numberp 66 Resolution 38 Keyword parameters 47 Ny:all 3 Reson 23 NyquistIDE 1 Rest 25, 65 Labels 67 Restore 71 Lambda 64 O (Adagio control) 38 Rests 36 Lambda Lists 63 Object 64 Return 67 Last 65 Object Class 64 Return statement, sal 15 Latency 19 Objectp 66 Return-from 67 Legato 26, 37 Objects 63 Reverb 23, 31, 52 Length 65 Octave specification 36 Reverse 65 Length pattern 44 Oddp 67 Reverse, sound 51 Length-of-beat 53 Offset 49 Ring modulation 2 Let 67 Offset to a sound 29 Risset 3 Let* 67 Omissions iii Rms 25, 29 Lexical conventions 62 Oneshot 30 Room 71 LF (Adagio dynamic) 37 Open 70 Rplaca 66 Lf 2 Open sound control 19,Rplacd 66 LFF (Adagio dynamic) 37 58 Rrandom 68 Lff 2 Open-binary 70 LFFF (Adagio dynamic) 37Openfile button 4 S (Adagio Sharp) 36 Lfff 2 Or 67 S (Adagio Sixteenth note) Lfo 19 Osc 1, 19, 20 36 Libraries 51 Osc-enable 19 S 2 Limit 24 Osc-note 25 S-abs 24 Limiter 18 Osc-pulse 21 S-add-to 28 Line pattern 43 Osc-saw 20 S-exp 25 Linear distribution 45 Osc-tri 21 S-log 25 Linear interpolation 50 Output samples to fileS-max 10, 25 Linear Prediction 41 27 S-min 10, 25 Linear prediction tutorialOutput to a File 72 S-overwrite 28 41 Overlap 26 S-plot 28 Linear-dist 45 Overwrite samples 28 S-print-tree 28 Linear-to-db 18 S-read 27 Lisp button 4 P (Adagio dynamic) 37 S-read-reverse 51 Lisp DSP 3, 11 P (Adagio Pitch) 36 S-rest 25 Lisp Include Files 60 Palindrome pattern 43 S-reverse 51 List 65 Pan 20, 52 S-save 27 List directory 70 Pan, stereo 52 S-sqrt 24 List Functions 65 Parameters, keyword 47 SAL 13 Listdir 70 Params-scale 50 Sal and lisp 15 Listing of lisp functionParams-transpose 50 SAL button 4 42 Partial 20 Sal expressions 13 Listp 66 Path, current 42 Sample interpolation 30 Little endian 71 Pattern, length 44 Sample rate, forcing 19 LMF (Adagio dynamic) 37 Pattern, window 44 Sample rates 7 Lmf 2 Pattern, accumulate 44 Sampler 21 LMP (Adagio dynamic) 37 Pattern, accumulation 44Samples 17, 18 Lmp 2 Pattern, copier 44 Samples, reading 17 Load 71 Pattern, cycle 43 Sampling rate 18 Load button 4 Pattern, eval 44 Save 71 Load file conditionallyPattern, expression 44 Save samples to file 27 42 Pattern, heap 44 Save-lpc-file 41 Load statement, sal 14 Pattern, line 43 Save-workspace 50 Local-to-global 19 Pattern, markov 44 Savefile button 4 Log 18 Pattern, palindrome 43 Saving Sound Files 10 Log function 18 Pattern, product 44 Sawtooth oscillator 20 Logand 68 Pattern, random 43 Sawtooth wave 2 Logical-stop 17 Pattern, sum 44 Sax 24 Logior 69 Patternp 50 Sax-all 24 Logistic distribution 46Peak 30 Sax-freq 24 Logistic-dist 46 Peak amplitude 10 Scale 20 Lognot 69 Peak, maximum amplitudeScale-db 20 Logorithm 25 30 Scale-srate 20 Logxor 69 Peek 71 Scan directory 70 Loop 67 Peek-char 70 Score 26 Loop examples, sal 15 Period estimation 25 Score manipulation 48 Loop statement, sal 14 Phaser 51 Score, musical 2 Looping Constructs 67 Physical model 3 Score-adjacent-events 49 Loud 26 Piano synthesizer 51 Score-append 49 Loud-abs 26 Piano synthesizer tutorialScore-apply 49 Loudness 36, 37 51 Score-filter 49 Low-frequency oscillatorPiano-midi 51 Score-filter-length 49 19 Piano-midi2file 51 Score-filter-overlap 49 Low-pass filter 22, 31 Piano-note 51 Score-gen 47 Lower-case-p 69 Piano-note-2 51 Score-get-begin 49 Lowpass2 23 Piece-wise 21 Score-get-end 49 Lowpass4 23 Piece-wise linear 30 Score-indexof 49 Lowpass6 23 Pitch 36 Score-last-indexof 49 Lowpass8 23 Pitch bend 38 Score-merge 49 LP (Adagio dynamic) 37 Pitch detection 25 Score-must-have-begin-end Lp 2, 22 Pitch notation 2 49 LPC 41 Pitch shift 24, 31 Score-play 49 Lpc tutorial 41 Pitch shifting 29 Score-print 49 Lpc-frame-err 41 Pitshift 24 Score-randomize-start 49 Lpc-frame-filter-coefs Pl-center 52 Score-read-smf 49 41 Pl-doppler 53 Score-repeat 49 Lpc-frame-rms1 41 Pl-left 52 Score-scale 49 Lpc-frame-rms2 41 Pl-pan2d 52 Score-select 49 LPP (Adagio dynamic) 37 Pl-position 53 Score-set-begin 49 Lpp 2 Pl-rear 52 Score-set-end 49 LPPP (Adagio dynamic) 37Pl-right 52 Score-shift 48 Lppp 2 Play 1, 27 Score-sort 48 Lpreson 41 Play in reverse 51 Score-sorted 48 Play-file 27 Score-stretch 48 M (Adagio control) 38 Plot 28 Score-stretch-to-length Macroexpand 64 Pluck 21 49 Macroexpand-1 64 Plucked string 21 Score-sustain 49 Macrolet 67 Plusp 66 Score-transpose 48 Make-accumulate 44 Poisson distribution 47 Score-voice 49 Make-accumulation 44 Poisson-dist 47 Score-write-smf 50 Make-array 65 Poke 71 Scratch sound 11 Make-copier 44 Polyrhythm 39 Sd 2 Make-cycle 43 Pop 42 Second 65 Make-eval 44 Portamento switch 38 Sections, Adagio 38 Make-heap 44 Power 42 Self 64 Make-length 44 PP (Adagio dynamic) 37 Semicolon, Adagio 38 Make-line 43 PPP (Adagio dynamic) 37 Seq 26 Make-lpanal-iterator 41 Pprint 70 Seqrep 26 Make-lpc-file-iterator Prcrev 23 Sequences 2, 36 41 Predicate Functions 66 Sequence_example.htm 2 Make-markov 44 Preset 37 Sequential behavior 6 Make-palindrome 43 Prin1 70 Set 64 Make-product 44 Princ 70 Set intersection 50 Make-random 43 Print 70 Set statement, sal 15 Make-string-input-stream Print midi file 52 Set union 50 71 Print statement, sal 15 Set-control-srate 7, 18 Make-string-output-stream Probability distributionsSet-difference 50 71 45 Set-logical-stop 26 Set-pitch-names 18 Stk clarinet 24, 32 ~= 13 Set-sound-srate 7, 18 STK flute 24, 32 ~~ 13 Setdir 70 STK glass harmonica 24 Setf 64 STK jcreverb 23 Seti commnad 40 STK mandolin 32 Setq 64 STK mandolon 24 Setup nyquist 1 STK modal bar 24, 32 Setup-console 71 STK nreverb 23 Setv command 40 STK pitch shift 24, 31 Sf-granulate 52 STK prcreverb 23 Sf-info 28 STK reverb 31 Shape 23 Stk sax 24, 32 Sharp 36 STK sitar 24, 33 Shepard tones 3, 23 STK tibetan bowl 24 Shift-time 20 STK tuned bar 24 Show midi file 52 STK uniform bar 24 Show-lpc-data 41 Stkchorus 23 Signal composition 29,Stochastic functions 45 30 Strcat 69 Signal multiplication 30Streamp 66 Signal-start 17 Stretch 2, 26 Signal-stop 17 Stretch Transformation 7 Sim 1, 26 Stretch, sal 13 Simrep 26 Stretch-abs 26 Simultaneous Behavior 6 Stretching Sampled Sounds Sin 68 10 Sine 20 String 69 Siosc 21 String Functions 69 Sitar 24 String Stream Functions Sixteenth note 2, 36 71 Sixtyfourth note 36 String synthesis 21 Slope 20 String-downcase 69 Smooth 20 String-equalp 69 Snd-abs 29 String-greaterp 69 Snd-add 29 String-left-trim 69 Snd-allpoles 41 String-lessp 69 Snd-alpass 30 String-not-equalp 69 Snd-alpasscv 30 String-not-greaterp 69 Snd-alpassvv 30 String-not-lessp 69 Snd-amosc 32 String-right-trim 69 Snd-areson 30 String-search 69 Snd-aresoncv 31 String-trim 69 Snd-aresonvc 31 String-upcase 69 Snd-aresonvv 31 String/= 69 Snd-atone 31 String< 69 Snd-atonev 31 String<= 69 Snd-avg 29 String= 69 Snd-bandedwg 32 String> 69 Snd-biquad 31 String>= 69 Snd-bowed 32 Stringp 66 Snd-bowed-freq 32 Sublis 66 Snd-buzz 32 Subseq 69 Snd-chase 31 Subset 50 Snd-clarinet 32 Subsetp 50 Snd-clarinet-all 32 Subst 66 Snd-clarinet-freq 32 Suggestions iii Snd-clip 29 Sum pattern 44 Snd-compose 29 Sum 26 Snd-congen 31 Surround Sound 52 Snd-const 28 Sustain 26 Snd-convolve 31 Sustain-abs 26 Snd-copy 29 Swap channels 52 Snd-coterm 28 Swapchannels 52 Snd-delay 31 Symbol Functions 64 Snd-delaycv 31 Symbol-function 65 Snd-down 29 Symbol-name 65 Snd-exp 29 Symbol-plist 65 Snd-extent 17 Symbol-value 65 Snd-fetch 17 Symbolp 66 Snd-fetch-array 17 Symbols 64 Snd-fft 35 Synchronization 39 Snd-flatten 17 System Functions 71 Snd-flute 32 Snd-flute-all 32 T (Adagio Triplet) 36 Snd-flute-freq 32 T 36 Snd-fmfb 32 Table 23 Snd-fmfbv 32 Table memory 18 Snd-fmosc 32 Tagbody 67 Snd-follow 29 Tan 68 Snd-from-array 17 Tap 29 Snd-fromarraystream 17 Tapped delay 23 Snd-fromobject 17 Tapv 23 Snd-gate 29 Temp file 70 Snd-ifft 35 Tempo 36, 37 Snd-inverse 30 Temporary files 70 Snd-length 18 Temporary sound files Snd-log 30 directory 27 Snd-lpanal 41 Terpri 70 Snd-lpreson 41 The Format Function 70 Snd-mandolin 32 The Program Feature 67 Snd-max 30 Third 65 Snd-maxsamp 18 Thirtysecond note 36 Snd-maxv 30 Threshold 30 Snd-modalbar 32 Throw 67 Snd-multiseq 33 Time 36, 37 Snd-normalize 30 Time shift, sal 13 Snd-offset 29 Time Structure 26 Snd-oneshot 30 Time units 38 Snd-osc 32 Timed-seq 26 Snd-overwrite 28 Tone 23 Snd-partial 32 Top button 4 Snd-play 18 Top-level 68 Snd-pluck 32 Touch tone 52 Snd-print 18 Trace 68 Snd-print-tree 18, 28 Transformation environment Snd-prod 30 6 Snd-pwl 30 Transformations 6, 25 Snd-quantize 30 Transpose 26 Snd-read 28 Transpose-abs 26 Snd-recip 30 Triangle oscillator 21 Snd-resample 30 Triangle wave 2 Snd-resamplev 30 Trigger 26 Snd-reson 31 Trill 40 Snd-resoncv 31 Triplet 36 Snd-resonvc 31 Triplet durations 2 Snd-resonvv 31 Truncate 68 Snd-samples 18 Tuba 3 Snd-save 28 Tuning 19 Snd-sax 32 Tutorial, FM 11 Snd-sax-all 33 Type-of 71 Snd-sax-freq 32 Snd-scale 30 U 36 Snd-seq 33 Uniform random 42, 68 Snd-set-latency 19 Union 50 Snd-set-logical-stop 18 Unless 67 Snd-shape 30 Untrace 68 Snd-sine 32 Unwind-protect 67 Snd-siosc 32 UPIC 4 Snd-sitar 33 Upper-case-p 69 Snd-slider 29 User name 70 Snd-sqrt 29 Snd-srate 18 V (Adagio Voice) 37 Snd-sref 18 Variable delay 23, 29 Snd-stkchorus 31 Variable-resample function Snd-stkpitshift 31 29 Snd-stkrev 31 Vector 65 Snd-stop-time 18 Velocity 37 Snd-t0 18 Vinal scratch 11 Snd-tapf 29 Vocal sound 3 Snd-tapv 29 Voice 36, 37 Snd-time 18 Voice synthesis 23 Snd-tone 31 Volume 38 Snd-tonev 31 Snd-trigger 33 W (Adagio Whole note) 36 Snd-up 30 W 2 Snd-white 29 Warble 11 Snd-xform 30 Warp 26 Snd-yin 30 Warp-abs 26 Snd-zero 29 Waveforms 2, 19 Soften-clipping 51 Waveshaping 23 Sort 66 Wavetables 2, 19 Sound 19 Wd 2 accessing point 17 Wg-glass-harm 24 creating from arrayWg-tibetan-bowl 24 17 Wg-tuned-bar 24 Sound browser, jnyqide 4Wg-uniform-bar 24 Sound file directoryWhen 42, 67 default 27 While 42 Sound file I/O 27 Whole note 2, 36 Sound file info 28 Widen 52 Sound from Lisp data 17 Wii Controller 19 Sound-off 27 Wind sound 11 Sound-on 27 Window initialization 71 Sound-srate-abs 26 Window pattern 44 Sound-warp 20 Wind_tutorial.htm 11 Soundfilename 28 With statement, sal 15 Soundp 18 Wood drum sound 3 Sounds 17 Workspace 4, 50 Sounds vs. Behaviors 6 Write samples to file 27 Span 52 Write-byte 71 Spatialization 52 Write-char 70 Special command 36 Write-float 71 Spectral interpolationWrite-int 70 21 Wt 2 Speed-dial 52 Splines 21 X (Adagio control) 38 Sqrt 68 Xenakis 4 Square oscillator 21 XLISP Command Loop 62 Square root 24, 29 XLISP Data Types 62 Srate 17 XLISP evaluator 62 Sref 17 XLISP Lexical Conventions Sref-inverse 17 62 St 2 Xmusic 43 Stacatto 26 Staccato 37 Y (Adagio control) 38 Stack trace 68 Yin 25 Standard MIDI File 49 Statements, sal 13 Z (Adagio program) 37, Stats 18 38 Step-to-hz 19 Zerop 66 Stereo 52 Stereo pan 52 ^ (Adagio sixtyfourth Stereo panning 20 note) 36 Stereo-chorus 51 ^ 13 Stereoize 52 ^= 15 STK banded waveguide 32 Stk bowed 32 | 13 STK bowed string 24 STK bowed-freq 24 ~ (Adagio) 38 STK chorus 23, 31 ~ 13 Table of Contents Preface iii 1. Introduction and Overview 1 1.1. Installation 1 1.2. Using NyquistIDE 1 1.3. Using SAL 1 1.4. Helpful Hints 1 1.5. Using Lisp 1 1.6. Examples 1 1.6.1. Waveforms 1 1.6.2. Wavetables 2 1.6.3. Sequences 2 1.6.4. Envelopes 2 1.6.5. Piece-wise Linear Functions 2 1.7. Predefined Constants 2 1.8. More Examples 3 2. The NyquistIDE Program 4 2.1. NyquistIDE Overview 4 2.2. The Button Bar 4 2.3. Command Completion 4 2.4. Browser 4 2.5. Envelope Editor 4 2.6. Equalizer Editor 4 2.7. UPIC Editor 4 3. Behavioral Abstraction 6 3.1. The Environment 6 3.2. Sequential Behavior 6 3.3. Simultaneous Behavior 6 3.4. Sounds vs. Behaviors 6 3.5. The At Transformation 7 3.6. The Stretch Transformation 7 3.7. Nested Transformations 7 3.8. Defining Behaviors 7 3.9. Overriding Default Transformations 7 3.10. Sample Rates 7 4. Continuous Transformations and Time Warps 8 4.1. Simple Transformations 8 4.2. Time Warps 8 4.3. Abstract Time Warps 8 4.4. Nested Transformations 9 5. More Examples 10 5.1. Stretching Sampled Sounds 10 5.2. Saving Sound Files 10 5.3. Memory Space and Normalization 10 5.4. Frequency Modulation 10 5.5. Building a Wavetable 11 5.6. Filter Examples 11 5.7. DSP in Lisp 11 6. SAL 13 6.1. SAL Syntax and Semantics 13 6.1.1. Expressions 13 6.1.1.1. Simple Expressions 13 6.1.1.2. Operators 13 6.1.1.3. Function Calls 13 6.1.1.4. Array Notation 13 6.1.1.5. Conditional Values 13 6.1.2. SAL Statements 13 6.1.2.1. begin and end 13 6.1.2.2. chdir 14 6.1.2.3. define variable 14 6.1.2.4. define function 14 6.1.2.5. display 14 6.1.2.6. exec 14 6.1.2.7. if 14 6.1.2.8. when 14 6.1.2.9. unless 14 6.1.2.10. load 14 6.1.2.11. loop 14 6.1.2.12. print 15 6.1.2.13. return 15 6.1.2.14. set 15 6.1.2.15. with 15 6.1.2.16. exit 15 6.2. Interoperability of SAL and XLISP 15 6.2.1. Function Calls 15 6.2.2. Symbols and Functions 15 6.2.3. Playing Tricks On the SAL Compiler 16 7. Nyquist Functions 17 7.1. Sounds 17 7.1.1. What is a Sound? 17 7.1.2. Multichannel Sounds 17 7.1.3. Accessing and Creating Sound 17 7.1.4. Miscellaneous Functions 18 7.2. Behaviors 19 7.2.1. Using Previously Created Sounds 19 7.2.2. Sound Synthesis 19 7.2.2.1. Oscillators 20 7.2.2.2. Piece-wise Approximations 21 7.2.2.3. Filter Behaviors 22 7.2.2.4. Effects 23 7.2.2.5. Physical Models 24 7.2.2.6. More Behaviors 24 7.3. Transformations 25 7.4. Combination and Time Structure 26 7.5. Sound File Input and Output 27 7.6. Low-level Functions 28 7.6.1. Creating Sounds 28 7.6.2. Signal Operations 29 7.6.3. Filters 30 7.6.4. Table-Lookup Oscillator Functions 31 7.6.5. Physical Model Functions 32 7.6.6. Sequence Support Functions 33 8. Nyquist Globals 34 9. Time/Frequency Transformation 35 10. MIDI, Adagio, and Sequences 36 10.1. Specifying Attributes 36 10.1.1. Time 36 10.1.2. Pitch 36 10.1.3. Duration 36 10.1.4. Next Time 36 10.1.5. Rest 36 10.1.6. Articulation 37 10.1.7. Loudness 37 10.1.8. Voice 37 10.1.9. Timbre (MIDI Program) 37 10.1.10. Tempo 37 10.1.11. Rate 37 10.2. Default Attributes 37 10.3. Examples 37 10.4. Advanced Features 38 10.4.1. Time Units and Resolution 38 10.4.2. Multiple Notes Per Line 38 10.4.3. Control Change Commands 38 10.4.4. Multiple Tempi 39 10.4.5. MIDI Synchronization 39 10.4.6. System Exclusive Messages 39 10.4.7. Control Ramps 39 10.4.8. The !End Command 40 10.4.9. Calling C Routines 40 10.4.10. Setting C Variables 40 11. Linear Prediction Analysis and Synthesis 41 11.1. LPC Classes and Functions 41 11.2. Low-level LPC Functions 41 12. Developing and Debugging in Nyquist 42 12.1. Debugging 42 12.2. Useful Functions 42 13. Xmusic and Algorithmic Composition 43 13.1. Xmusic Basics 43 13.2. Pattern Classes 43 13.2.1. cycle 43 13.2.2. line 43 13.2.3. random 43 13.2.4. palindrome 43 13.2.5. heap 44 13.2.6. accumulation 44 13.2.7. copier 44 13.2.8. accumulate 44 13.2.9. sum 44 13.2.10. product 44 13.2.11. eval 44 13.2.12. length 44 13.2.13. window 44 13.2.14. markov 44 13.3. Random Number Generators 45 13.4. Score Generation and Manipulation 47 13.4.1. Keyword Parameters 47 13.4.2. Using score-gen 47 13.4.3. Score Manipulation 48 13.4.4. Xmusic and Standard MIDI Files 49 13.4.5. Workspaces 50 13.4.6. Utility Functions 50 14. Nyquist Libraries 51 14.1. Piano Synthesizer 51 14.2. Dymanics Compression 51 14.3. Clipping Softener 51 14.4. Graphical Equalizer 51 14.5. Sound Reversal 51 14.6. Time Delay Functions 51 14.7. Multiple Band Effects 52 14.8. Granular Synthesis 52 14.9. MIDI Utilities 52 14.10. Reverberation 52 14.11. DTMF Encoding 52 14.12. Dolby Surround(R), Stereo and Spatialization Effects 52 14.13. Drum Machine 53 14.14. Minimoog-inspired Synthesis 53 14.14.1. Oscillator Parameters 53 14.14.2. Noise Parameters 53 14.14.3. Filter Parameters 53 14.14.4. Amplitude Parameters 54 14.14.5. Other Parameters 54 14.14.6. Input Format 54 14.14.7. Sample Code/Sounds 54 I. Extending Nyquist 55 I.1. Translating Descriptions to C Code 55 I.2. Rebuilding Nyquist 55 I.3. Accessing the New Function 55 I.4. Why Translation? 55 I.5. Writing a .alg File 55 I.6. Attributes 55 I.7. Generated Names 57 I.8. Scalar Arguments 57 II. Open Sound Control and Nyquist 58 II.1. Sending Open Sound Control Messages 58 II.2. The ser-to-osc Program 58 III. Intgen 59 III.0.1. Extending Xlisp 59 III.1. Header file format 59 III.2. Using #define'd macros 59 III.3. Lisp Include Files 60 III.4. Example 60 III.5. More Details 60 IV. XLISP: An Object-oriented Lisp 61 IV.1. Introduction 62 IV.2. A Note From The Author 62 IV.3. XLISP Command Loop 62 IV.4. Special Characters 62 IV.5. Break Command Loop 62 IV.6. Data Types 62 IV.7. The Evaluator 62 IV.8. Lexical Conventions 62 IV.9. Readtables 63 IV.10. Lambda Lists 63 IV.11. Objects 63 IV.12. The ``Object'' Class 64 IV.13. The ``Class'' Class 64 IV.14. Profiling 64 IV.15. Symbols 64 IV.16. Evaluation Functions 64 IV.17. Symbol Functions 64 IV.18. Property List Functions 65 IV.19. Array Functions 65 IV.20. List Functions 65 IV.21. Destructive List Functions 66 IV.22. Predicate Functions 66 IV.23. Control Constructs 67 IV.24. Looping Constructs 67 IV.25. The Program Feature 67 IV.26. Debugging and Error Handling 68 IV.27. Arithmetic Functions 68 IV.28. Bitwise Logical Functions 68 IV.29. String Functions 69 IV.30. Character Functions 69 IV.31. Input/Output Functions 70 IV.32. The Format Function 70 IV.33. File I/O Functions 70 IV.34. String Stream Functions 71 IV.35. System Functions 71 IV.36. File I/O Functions 72 IV.36.1. Input from a File 72 IV.36.2. Output to a File 72 IV.36.3. A Slightly More Complicated File Example 72 Index 74 List of Figures Figure 1: An envelope generated by the env function. 2 Figure 2: The result of (warp4), intended to map 4 seconds of score 8 time into 4 seconds of real time. The function extends beyond 4 seconds (the dashed lines) to make sure the function is well-defined at location (4, 4). Nyquist sounds are ordinarily open on the right. Figure 3: When (warp4) is applied to (tone-seq-2), the note onsets 8 and durations are warped. Figure 4: When (warp4) is applied to (tone-seq-3), the note onsets 9 are warped, but not the duration, which remains a constant 0.25 seconds. In the fast middle section, this causes notes to overlap. Nyquist will sum (mix) them. Figure 5: The shift-time function shifts a sound in time according to 20 its shift argument. Figure 6: Ramps generated by pwl and ramp functions. The pwl version 25 ramps toward the breakpoint (1, 1), but in order to ramp back to zero at breakpoint (1, 0), the function never reaches an amplitude of 1. If used at the beginning of a seq construct, the next sound will begin at time 1. The ramp version actually reaches breakpoint (1, 1); notice that it is one sample longer than the pwl version. If used in a sequence, the next sound after ramp would start at time 1 + P, where P is the sample period. Figure 7: The Linear Distribution, g = 1. 45 Figure 8: The Exponential Distribution, delta = 1. 45 Figure 9: The Gamma Distribution, nu = 4. 45 Figure 10: The Bilateral Exponential Distribution. 45 Figure 11: The Cauchy Distribution, tau = 1. 46 Figure 12: The Hyperbolic Cosine Distribution. 46 Figure 13: The Logistic Distribution, alpha = 1, beta = 2. 46 Figure 14: The Arc Sine Distribution. 46 Figure 15: The Gauss-Laplace (Gaussian) Distribution, xmu = 0, sigma 46 = 1. Figure 16: The Beta Distribution, alpha = .5, beta = .25. 46 Figure 17: The Bernoulli Distribution, px1 = .75. 46 Figure 18: The Binomial Distribution, n = 5, p = .5. 47 Figure 19: The Geometric Distribution, p = .4. 47 Figure 20: The Poisson Distribution, delta = 3. 47 Figure 21: System diagram for Minimoog emulator. 53 nyquist-3.05/doc/part17.html0000644000175000000620000002071411537432671014751 0ustar stevestaffPrevious Section | Next Section | Table of Contents | Index | Title Page
    Appendix 2: Open Sound Control and Nyquist

    Appendix 2: Open Sound Control and Nyquist

    Open Sound Control (OSC) is a simple protocol for communicating music control parameters between software applications and across networks. For more information, see http://www.cnmat.berkeley.edu/OpenSoundControl/. The Nyquist implementation of Open Sound Control is simple: an array of floats can be set by OSC messages and read by Nyquist functions. That is about all there is to it.

    Note: Open Sound Control must be enabled by calling osc-enable(t). If this fails under Windows, see the installation instructions in sys/win/README.txt regarding SystemRoot.

    To control something in (near) real-time, you need to access a slider value as if it a signal, or more properly, a Nyquist SOUND type. The function snd-slider, described in Section "Creating Sounds", takes a slider number and returns a SOUND type representing the current value of the slider. To fully understand this function, you need to know something about how Nyquist is actually computing sounds.

    Sounds are normally computed on demand. So the result returned by snd-slider does not immediately compute any samples. Samples are only computed when something tries to use this signal. At that time, the slider value is read. Normally, if the slider is used to control a sound, you will hear changes in the sound pretty soon after the slider value changes. However, one thing that can interfere with this is that SOUND samples are computed in blocks of about 1000 samples. When the slider value is read, the same value is used to fill a block of 1000 samples, so even if the sample rate is 44,100 Hz, the effective slider sample rate is 44,100/1000, or 44.1 Hz. If you give the slider a very low sample rate, say 1000, then slider value changes will only be noticed by Nyquist approximately once per second. For this reason, you should normally use the audio sample rate (typically 44,100 Hz) for the rate of the snd-slider output SOUND. (Yes, this is terribly wasteful to represent each slider value with 1000 samples, but Nyquist was not designed for low-latency computation, and this is an expedient work-around.)

    In addition to reading sliders as continually changing SOUNDs, you can get the slider value as a Lisp FLONUM (a floating point number) using get-slider-value, described in Section "Creating Sounds". This might be useful if you are computing a sequence of many notes (or other sound events) and want to apply the current slider value to the whole note or sound event.

    Note that if you store the value returned by snd-slider in a variable, you will capture the history of the slider changes. This will take a lot of memory, so be careful.

    Suppose you write a simple expression such as (hzosc (mult 1000 (snd-slider 0 ...))) (or in SAL, hzosc(1000 * snd-slider(0 ...))) to control an oscillator frequency with a slider. How long does this sound last? The duration of hzosc is the duration of the frequency control, so what is the duration of a slider? To avoid infinitely long signals, you must specify a duration as one of the parameters of snd-slider.

    You might be thinking, what if I just want to tell the slider when to stop? At present, you cannot do that, but in the future there should be a function that stops when its input goes to zero. Then, moving a slider to zero could end the signal (and if you multiplied a complex sound by one of these ending functions, everything in the sound would end and be garbage collected).

    Another thing you might want to do with interactive control is start some sound. The trigger function computes an instance of a behavior each time an input SOUND goes from zero to greater-than-zero. This could be used, for example, to create a sequence of notes.

    The snd-slider function has some parameters that may be unfamiliar. The second parameter, t0, is the starting time of the sound. This should normally be local-to-global(0), an expression that computes the instantiation time of the current expression. This will often be zero, but if you call snd-slider from inside a seq or seq-rep, the starting time may not be zero.

    The srate parameter is the sample rate to return. This should normally be the audio sample rate you are working with, which is typically *default-sound-srate*.

    Sending Open Sound Control Messages

    A variety of programs support OSC. The only OSC message interpreted by Nyquist has an address of /slider, and two parameters: an integer slider number and a float value, nominally from 0.0 to 1.0.

    Two small programs are included in the Nyquist distribution for sending OSC messages. (Both can be found in the same directory as the nyquist executable.) The first one, osc-test-client sends a sequence of messages that just cause slider 0 to ramp slowly up and down. If you run this on a command line, you can use "?" or "h" to get help information. There is an interactive mode that lets you send each OSC message by typing RETURN.

    The ser-to-osc Program

    The second program is ser-to-osc, a program that reads serial input (for example from a PIC-based microcontroller) and sends OSC messages. Run this command-line program from a shell (a terminal window under OS X or Linux; use the CMD program under Windows). You must name the serial input device on the command line, e.g. under OS X, you might run:
    ./ser-to-osc /dev/tty.usbserial-0000103D
    (Note that the program name is preceded by "./". This tells the shell exactly where to find the executable program in case the current directory is not on the search path for executable programs.) Under Windows, you might run:
    ser-to-osc com4
    (Note that you do not type "./" in front of a windows program.)

    To use ser-to-osc, you will have to find the serial device. On the Macintosh and Linux, try the following:

    ls /dev/*usb*
    This will list all serial devices with "usb" in their names. Probably, one will be a name similar to /dev/tty.usbserial-0000103D. The ser-to-osc program will echo data that it receives, so you should know if things are working correctly.

    Under Windows, open Control Panel from the Start menu, and open the System control panel. Select the Hardware tab and click the Device Manager button. Look in the device list under Ports (COM & LPT). When you plug in your serial or USB device, you should see a new entry appear, e.g. COM4. This is the device name you need.

    The format for the serial input is: any non-whitespace character(s), a slider number, a slider value, and a newline (control-j or ASCII 0x0A). These fields need to be separated by tabs or spaces. An optional carriage return (control-m or ASCII 0x0D) preceding the ASCII 0x0A is ignored. The slider number should be in decimal, and theh slider value is a decimal number from 0 to 255. This is scaled to the range 0.0 to 1.0 (so an input of 255 translates to 1.0).

    There is a simple test program in demos/osc-test.lsp you can run to try out control with Open Sound Control. There are two examples in that file. One uses snd-slider to control the frequency of an oscillator. The other uses get-slider-value to control the pitch of grains in a granular synthesis process.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/musicbib.html0000644000175000000620000000150511466723256015430 0ustar stevestaffReferences Table of Contents | Index | Title Page

    References

    Touretzky, D. (1983) A Gentle Introduction to Symbolic Computation. New York: Harper and Row.

    Dannenberg, R. and C. Frayley. (1989) ``Fugue: A Signal Manipulation System with Lazy Evaluation and Behavioral Abstraction.'' In 1989 International Computer Music Conference, San Francisco: Computer Musici Association, (October 1989), pp 76-79.


    Table of Contents | Index | Title Page nyquist-3.05/doc/hyperbolic-fig.gif0000644000175000000620000000221311466723256016334 0ustar stevestaffGIF87a w!Software: Microsoft Office, t޼bu扦ʂe L ~ ~Ģ J Ѫ-Z h۰l춯-ov-ǠhxH"DƄ X()IȨI*j: zzj9*k8VۛPk;|lL e̛\,|<mMms-ݍ'=Ia>.O.^/=?9t `=B/G^%n▆.b  ~6Q-O5Ed_syMo8VڙgI@y&9Z4[O?b[SQNuVfV7DjXz%,R6nES]Vq5WP}d7MMMJ%uFu\ihΘ?Wte6.VٱݠN 6^M3qȓP ţKGu+MXۻxNw'yNg=vR˧9cߟ-рHKY~2Gǂ4` IokUQ j6!3*Ah6ȂS*"0w#_>)1FCؤe2BoG΀tYRV^)ÖÉp^egf b&YiKo~)g&i'Bjy&z癍Hҟ^VGkTFBh&oJ$tפʣ ªnZk|qh+zٯc1(죤[ϒWnm&孷$n6'v#MZoRQ 7I[g1$rd׾^{"IO ůbagGVƫr npr)jܹ|1^07Dz$2waռCWD@KMtH4I5&+P+ʻOW=.\kbZi}Z|G/Rji7efw벬N /.81~+.1@8}MyL_yoyz袏bW:8ꨨ뮧w/"vbZ{{]̮Lq|{m'̸7z/;nyquist-3.05/doc/logistic-fig.gif0000644000175000000620000000220211466723256016007 0ustar stevestaffGIF87a w!Software: Microsoft Office, ޼b1eȶ 2J+Yy.V1L*s;E#&V歁䲹EM'j 'n>x|sgB(rxHѥI"H'yQY0 j(:yZZ j(k+Z({۫+;F|| ]Y/}f_!7u-Szra}H!HmޅHvR!# )Nb-16c' {7P;wIF?It! )ҡtdI>ݦ$EFiob\bܖcvgk3osVwvצ{ӧVf|Z2M2ZxJ)jZZiSY$Zj*knF魸'zEhڠ5qJjWC5kbg|"t_d%*-(r.[>X]د~OXװ`Tàs̝㉛#{'9?,5ٓ u38Ϲ sjA<(V`wҋ,kMb^AL5_u l0D͆h-**꾖-ms lM߂Nxx/x?ZSC:yR]a^IE{>$(9a.{Mpz;C(z0CܹTn;nyquist-3.05/doc/cauchy-fig.gif0000644000175000000620000000216711466723256015460 0ustar stevestaffGIF87a w!Software: Microsoft Office, t޼bu扦ʂe L Ģs)̦s>*셵j 6 LJNV筤|WWhHa&Dxwvcy 88*jzj ۧ*[8Ik+ {\<Hl|< ]@mM ]n>]~>-o@/ \ܧuuʕ^}0on(ԥ1G)$tɓ2ˌ.cFf~ wrczMV xNxx/x#^d=98W6K]l -S&~J{~|N-M۾y ;nyquist-3.05/doc/fig1.gif0000644000175000000620000000337610144436365014264 0ustar stevestaffGIF87a,ڋ޼H扦ʶ L ĢL*̦ JԪjܮ N Va8xGȠ'Q8׈&g I XX 8 9r88hڙzaJەIh ,lkjLܧ( yk}' YJ nn^,}yX.. ?/^k]:Xz =hU3-|Αh 8zm<138œd1ǙLBvD!DU&9g8ZI3)z۸yLS$ړ =_^]]SagYkӺ5aܷtڽ7޽| 8W-xČ.n 9ȔN>Vf7" ZM(C&3Ӭ^=);+{cIMU*ݾx!rƛ@~ar2GAv;ןg8LJ?/G1w0,|gj~oU]=u`ְ NȐuqEH~B1 f!mXb%'"dxbu"!c"4ؐj$iO|I*O#9eUZ[eqCf aE#yd_Ym梜9eoy~\{t F((J꘣V)fşF:::(ʓ*g)ֺ}B3_갎wm&BeަZ{b_fk}vږӡtґK o²Iȋr븠 Pj 0_BF cpM6qpO1a1]W"?Ar_<|ҁQܚi\:$>|]a]e6 93tMgJGfUM՚aGFbڅZd<6pyaޞ=Y~j6kMV7܉k% +.Gn+`y-Qm1爦`{pB㱏;+{SaSBn&<[$)oDDR![rk3} Ɵ[{H* p*p l`ȈEEP@""' %Tl$A, &x=v<THB%4%PͪbFAby6:-hj]bӈx7E/+(uD_W72q#VTELXb.7Fdэ9p;|c94lF\Xc!ۓGQ{|HӐJA"PrGBnU Ilft.O($З;pa-_@GDf0]s4jeg!# M JyT X6Z 0,سŒg|c.P PXm&zBVΌw$E.I '8!N5(K-ЗХ2JP9^Oe.EdM753G~ŦVБJuf3)U#W ְuhTWV:ǝaF=$CO;)KV1DljcC摯\ ,45mac=8>Vx4 *9Q2,Aك f\leZТvmk_ ;nyquist-3.05/doc/guide.html0000644000175000000620000035135311537432671014736 0ustar stevestaffLinks

    !-~ A B C D E F G H
    I J K L M N O P Q
    R S T U V W X Y Z

    Table of Contents

    Index

    !-~

    TOP
    ! 1 2
    !=
    !call
    !clock
    !csec
    !def
    !end
    !msec
    !ramp
    !rate
    !seti
    !setv
    !tempo
    # (adagio articulation)
    #?, sal
    #define'd macros
    #f
    #t
    %
    % (adagio thirtysecond note)
    &
    &=
    * 1 2
    *=
    *a4-hertz* 1 2
    *applyhook*
    *audio-markers*
    *autonorm*
    *autonorm-max-samples*
    *autonorm-previous-peak*
    *autonorm-target*
    *autonorm-type*
    *autonormflag*
    *breakenable* 1 2 3 4
    *control-srate* 1 2 3
    *debug-io*
    *default-control-srate*
    *default-plot-file*
    *default-sf-bits*
    *default-sf-dir* 1 2
    *default-sf-format*
    *default-sf-srate* 1 2
    *default-sound-srate*
    *error-output*
    *evalhook*
    *file-separator*
    *float-format*
    *gc-flag*
    *gc-hook*
    *integer-format*
    *loud*
    *obarray*
    *print-case*
    *readtable* 1 2
    *rslt* 1 2
    *sound-srate* 1 2 3
    *soundenable*
    *standard-input*
    *standard-output*
    *start*
    *stop*
    *sustain*
    *table*
    *trace-output*
    *tracelimit* 1 2
    *tracelist*
    *tracenable* 1 2 3
    *transpose*
    *unbound*
    *warp* 1 2 3
    + 1 2
    +=
    , (adagio)
    - 1 2
    . (adagio)
    / 1 2
    /=
    1+
    1-
    :answer
    :class
    :isa
    :isnew 1 2
    :new
    :show
    ; (adagio)
    < 1 2
    <= 1 2 3
    = 1 2
    > 1 2
    >= 1 2 3
    @
    @=
    @@
    ^
    ^ (adagio sixtyfourth note)
    ^=
    |
    ~
    ~ (adagio)
    ~=
    ~~

    A

    TOP
    *a4-hertz* 1 2
    A440
    Abs
    Abs-env
    Absolute stretch, sal
    Absolute time shift, sal
    Absolute value 1 2
    Access samples
    Accidentals
    Accumulate pattern
    Accumulation pattern
    Adagio
    # (adagio articulation)
    ^ (adagio sixtyfourth note)
    % (adagio thirtysecond note)
    ~ (adagio)
    ; (adagio)
    , (adagio)
    . (adagio)
    Add offset to sound
    Add to file samples
    Add-action-to-workspace
    Add-to-workspace
    Additive synthesis, gongs
    Address-of
    Aftertouch
    Agc
    Algorithmic composition
    All pass filter
    Alloc
    Allpass2
    Allpoles-from-lpc
    Alpass
    Alpass filter
    Amosc
    Analog synthesizer
    And
    :answer
    Append
    Apply
    Apply-banded-bass-boost
    Apply-banded-delay
    Apply-banded-treble-boost
    *applyhook*
    Approximation
    Arc-sine-dist
    Arcsine distribution
    Aref
    Areson
    Args
    Arguments to a lisp function
    Arithmetic functions
    Arpeggiator
    Array from sound
    Array functions
    Array notation, sal
    Arrayp
    Articulation 1 2
    Assoc
    Asterisk
    At
    At transformation
    At, sal
    At-abs
    At-abs, sal
    Atan
    Atom
    Atone
    Attributes
    Audio markers
    *audio-markers*
    Automatic gain control
    *autonorm*
    *autonorm-max-samples*
    Autonorm-off 1 2 3
    Autonorm-on 1 2 3
    *autonorm-previous-peak*
    *autonorm-target*
    *autonorm-type*
    *autonormflag*
    Average

    B

    TOP
    Backquote
    Backward
    Baktrace
    Banded bass boost
    Banded delay
    Banded treble boost
    Bandfx.lsp
    Bandpass filter
    Bandpass2
    Bartok
    Begin
    Behavioral abstraction
    Behaviors
    Bell sound 1 2
    Bernoulli distribution
    Bernoulli-dist
    Beta distribution
    Beta-dist
    Big endian
    Bigendianp
    Bilateral exponential distribution
    Bilateral-exponential-dist
    Binary files
    Binomial distribution
    Binomial-dist
    Biquad
    Biquad-m
    Bitwise logical functions
    Blank
    Block
    Both-case-p
    Boundp
    Bowed
    Bowed-freq
    Brass sound
    Break 1 2
    Break button
    *breakenable* 1 2 3 4
    Browse button
    Browser, jnyqide
    Build-harmonic 1 2
    Button bar
    Buzz

    C

    TOP
    !call
    Call command
    Car
    Case 1 2
    Case-insensitive
    Catch
    Cauchy distribution
    Cauchy-dist
    Cdr
    Cerror
    Change directory
    Char
    Char-code
    Char-downcase
    Char-equalp
    Char-greaterp
    Char-int
    Char-lessp
    Char-not-equalp
    Char-not-greaterp
    Char-not-lessp
    Char-upcase
    Char/=
    Char<
    Char<=
    Char=
    Char>
    Char>=
    Character functions
    Characterp
    Chdir, sal
    Chorus 1 2 3 4 5
    Clarinet 1 2 3
    Clarinet sound
    Clarinet-all
    Clarinet-freq
    Class
    :class
    Class class
    Clean-up
    Clip 1 2 3
    Clipping repair
    !clock
    Clock
    Clock command
    Close
    Co-termination
    Code-char
    Comb
    Comb filter
    Combination
    Command loop
    Commas
    Comment 1 2
    Comments
    Compose
    Compress
    Compress-map
    Compressor
    Concatenate strings
    Cond
    Conditional expression, sal
    Configure nyquist
    Congen
    Cons
    Console, xlisp
    Consp
    Const
    Constant function
    Continue
    Continuous-control-warp
    Continuous-sound-warp
    Contour generator
    Control
    Control change
    Control characters, xlisp
    Control constructs
    Control-a
    *control-srate* 1 2 3
    Control-srate-abs
    Control-warp
    Convert sound to array
    Convolution
    Convolve
    Copier pattern
    Cos
    !csec
    Cue
    Cue-file
    Current-path
    Cxxr
    Cxxxr
    Cxxxxr
    Cycle pattern

    D

    TOP
    Darwiinremoteosc
    Data types
    Db-average
    Db-to-linear
    Db0
    Db1
    Db10
    *debug-io*
    Debugging 1 2 3 4 5
    Decf
    Decrement
    !def
    Default
    Default durations
    Default sample rate
    Default sound file directory
    Default time
    *default-control-srate*
    *default-plot-file*
    *default-sf-bits*
    *default-sf-dir* 1 2
    *default-sf-format*
    *default-sf-srate* 1 2
    *default-sound-srate*
    Define function
    Define variable
    #define'd macros
    Defining behaviors
    Defmacro
    Defun
    Delay
    Delay, variable
    Delay, variable
    Delete
    Delete-if
    Delete-if-not
    Demos, bell sound
    Demos, distortion
    Demos, drum machine
    Demos, drum sound
    Demos, fft
    Demos, fm
    Demos, fm synthesis
    Demos, formants
    Demos, gong sound
    Demos, lpc
    Demos, midi
    Demos, piano
    Demos, pitch change
    Demos, rhythmic pattern
    Demos, ring modulation
    Demos, sample-by-sample
    Demos, scratch tutorial
    Demos, shepard tones
    Demos, spectral analysis of a chord
    Demos, voice synthesis
    Demos, wind sound
    Derivative
    Describe
    Destructive list functions
    Developing code
    Diff
    Difference
    Difference of sounds
    Digit-char
    Digit-char-p
    Directory listing
    Directory, default sound file
    Display statement, sal
    Distortion tutorial
    Distributions, probability
    Division
    Do
    Do*
    Dolby pro-logic
    Dolby surround
    Dolist
    Doppler effect
    Dot
    Dotimes
    Dotted durations
    Dribble
    Drum
    Drum samples
    Drum machine 1 2
    Drum sound
    Drum-loop
    Dsp in lisp 1 2
    Dtmf
    Dtmf-tone
    Dubugging
    Duration 1 2
    Duration notation
    Duration of another sound
    Dx7
    Dynamic markings

    E

    TOP
    Echo
    Echoenabled
    Editor for envelopes
    Effect, reverberation 1 2
    Effect, reverberation
    Effect, chorus 1 2 3
    Effect, flange
    Effect, pitch shift 1 2
    Effect, reverberation 1 2
    Effect, stereo
    Effect, stereo pan
    Effect, swap channels
    Effect, widen
    Effects, phaser
    Eighth note 1 2
    Elapsed audio time
    Emacs, using nyquist with
    Empty list
    !end
    End
    End command
    Endian
    Endless tones
    Endp
    Env 1 2
    Env-note
    Envedit button
    Envelope
    Envelope editor
    Envelope follower 1 2
    Envelope generator
    Envelopes
    Environment
    Environment variables
    Eq
    Eq button
    Eq-band
    Eq-highshelf
    Eq-lowshelf
    Eql
    Equal
    Equalization 1 2 3 4
    Equalization editor
    Error
    Error handling
    *error-output*
    Errors
    Errset
    Estimate frequency
    Eval
    Eval pattern
    Evalhook
    *evalhook*
    Evaluation functions
    Evaluator
    Evenp
    Event-dur
    Event-end
    Event-expression
    Event-get-attr
    Event-has-attr
    Event-set-attr
    Event-set-dur
    Event-set-expression
    Event-set-time
    Event-time
    Exclamation point
    Exec statement, sal
    Exit
    Exit statement, sal
    Exp
    Exp-dec
    Expand
    Exponent
    Exponential
    Exponential distribution
    Exponential envelope
    Exponential-dist
    Expr-get-attr
    Expr-has-attr
    Expr-set-attr
    Expression pattern
    Expressions, sal
    Expt
    Extending xlisp
    Extract
    Extract-abs

    F

    TOP
    #f
    F (adagio dynamic)
    F (adagio flat)
    Fast fourier transform tutorial
    Fboundp
    Feedback fm oscillator
    Feedback-delay
    Feel factor
    Ff (adagio dynamic)
    Fff (adagio dynamic)
    Fft
    Fft tutorial
    File i/o functions 1 2
    *file-separator*
    Filep
    Filter example
    Finally clause, sal
    Find string
    Find-in-xlisp-path
    Fir filter
    First
    First derivative
    Flange
    Flange effect
    Flat
    Flatc
    Flatsize
    Flet
    Float
    *float-format*
    Floatp
    Flute
    Flute sound
    Flute-all
    Flute-freq
    Fm synthesis
    Fmfb
    Fmlfo
    Fmosc
    Fn button
    Follow
    Follower
    Force-srate
    Format
    Fourth
    Frequency analysis
    Frequency modulation
    Full path name
    Funcall
    Function
    Function calls, sal
    Function, sal
    Fundamenal frequency estimation

    G

    TOP
    Gain
    Gamma-dist
    Gate 1 2
    Gaussian distribution
    Gaussian-dist
    Gc
    *gc-flag*
    *gc-hook*
    Gcd
    Gen05
    Gensym
    Geometric distribution
    Geometric-dist
    Get
    Get char
    Get-duration
    Get-env
    Get-lambda-expression
    Get-loud
    Get-output-stream-list
    Get-output-stream-string
    Get-slider-value
    Get-sustain
    Get-temp-path
    Get-transpose
    Get-user
    Get-warp
    Getenv
    Global variables
    Global variables, sal
    Go
    Gong sounds
    Granular synthesis
    Graphical envelope editor
    Graphical equalization
    Graphical equalizer
    Grindef

    H

    TOP
    H
    H (adagio half note)
    Half note 1 2
    Harmonic
    Hash
    Hd
    Header file format
    Heap pattern
    High-pass filter
    Highpass2
    Highpass4
    Highpass6
    Highpass8
    Hp
    Ht
    Hyperbolic-cosine-dist
    Hz-to-step
    Hzosc

    I

    TOP
    I
    I (adagio eight note)
    Iannis xenakis
    Id
    Ide
    If
    If statement, sal
    Ifft
    Incf
    Increment
    Info
    Info button
    Input from a file
    Input/output functions
    Installation
    Int-char
    *integer-format*
    Integerp
    Integrate
    Integrated development environment
    Intern
    Interoperability, sal and lisp
    Interpolate
    Intersection
    Intgen
    Inverse
    Inverse fft
    :isa
    :isnew 1 2
    It

    J

    TOP
    Jcrev
    Jitter

    K

    TOP
    K (adagio control)
    Karplus-strong
    Karplus-strong synthesis
    Keyword parameters

    L

    TOP
    Labels
    Lambda
    Lambda lists
    Last
    Latency
    Legato 1 2
    Length
    Length pattern
    Length-of-beat
    Let
    Let*
    Lexical conventions
    Lf
    Lf (adagio dynamic)
    Lff
    Lff (adagio dynamic)
    Lfff
    Lfff (adagio dynamic)
    Lfo
    Libraries
    Limit
    Limiter
    Line pattern
    Linear distribution
    Linear interpolation
    Linear prediction
    Linear prediction tutorial
    Linear-dist
    Linear-to-db
    Lisp button
    Lisp dsp 1 2
    Lisp include files
    List
    List directory
    List functions
    Listdir
    Listing of lisp function
    Listp
    Little endian
    Lmf
    Lmf (adagio dynamic)
    Lmp
    Lmp (adagio dynamic)
    Load
    Load button
    Load file conditionally
    Load statement, sal
    Local-to-global
    Log
    Log function
    Logand
    Logical-stop
    Logior
    Logistic distribution
    Logistic-dist
    Lognot
    Logorithm
    Logxor
    Loop
    Loop examples, sal
    Loop statement, sal
    Looping constructs
    Loud
    *loud*
    Loud-abs
    Loudness 1 2
    Low-frequency oscillator
    Low-pass filter 1 2
    Lower-case-p
    Lowpass2
    Lowpass4
    Lowpass6
    Lowpass8
    Lp 1 2
    Lp (adagio dynamic)
    Lpc
    Lpc tutorial
    Lpc-frame-err 1 2
    Lpc-frame-filter-coefs 1 2
    Lpc-frame-rms1 1 2
    Lpc-frame-rms2 1 2
    Lpp
    Lpp (adagio dynamic)
    Lppp
    Lppp (adagio dynamic)
    Lpreson

    M

    TOP
    M (adagio control)
    Macroexpand
    Macroexpand-1
    Macrolet
    Make-accumulate
    Make-accumulation
    Make-array
    Make-copier
    Make-cycle
    Make-eval
    Make-heap
    Make-length
    Make-line
    Make-lpanal-iterator
    Make-lpc-file-iterator
    Make-markov
    Make-palindrome
    Make-product
    Make-random
    Make-string-input-stream
    Make-string-output-stream
    Make-sum
    Make-symbol
    Make-window
    Maketable
    Mandolin
    Manipulation of scores
    Mapc
    Mapcar
    Mapl
    Maplist
    Mark button
    Markers, audio
    Markov analysis
    Markov pattern
    Markov-create-rules
    Max
    Maximum 1 2
    Maximum amplitude 1 2
    Maximum of two sounds
    Member
    Memory usage
    Mf (adagio dynamic)
    Middle c
    Midi
    Midi clock
    Midi file 1 2 3
    Midi program
    Midi-show
    Midi-show-file
    Mikrokosmos
    Min
    Minimoog
    Minimum 1 2
    Minusp
    Mix
    Mix to file
    Mkwave
    Modalbar
    Modulation wheel
    Modulo (rem
    Mono to stereo
    Moog
    Moving average
    Mp (adagio dynamic)
    !msec
    Mult 1 2 3
    Multichannel sounds
    Multiple band effects
    Multiple commands
    Multiple tempi
    Multiplication
    Multiply signals
    My-note

    N

    TOP
    N (adagio next)
    Natural
    Natural log
    Nband
    Nband-range
    Nconc
    Nested transformations
    :new
    Newfile button
    Next adagio command
    Next in pattern
    Next pattern
    Nintendo wiimote
    Noise
    Noise gate
    Noise-gate
    Normalization
    Not
    Not enough memory for normalization
    Notch filter
    Notch2
    Note list
    Nrev
    Nstring-downcase
    Nstring-upcase
    Nth
    Nthcdr
    Null
    Numberp
    Ny:all
    Nyquistide

    O

    TOP
    O (adagio control)
    *obarray*
    Object
    Object class
    Objectp
    Objects
    Octave specification 1 2
    Oddp
    Offset
    Offset to a sound
    Omissions
    Oneshot
    Open 1 2
    Open sound control 1 2
    Open-binary
    Openfile button
    Or
    Osc 1 2 3
    Osc-enable
    Osc-note
    Osc-pulse
    Osc-saw
    Osc-tri
    Output samples to file
    Output to a file
    Overlap
    Overwrite samples

    P

    TOP
    P (adagio dynamic)
    P (adagio pitch)
    Palindrome pattern
    Pan 1 2
    Pan, stereo
    Parameters, keyword
    Params-scale
    Params-transpose
    Partial
    Path, current
    Pattern, length
    Pattern, window
    Pattern, accumulate
    Pattern, accumulation
    Pattern, copier
    Pattern, cycle
    Pattern, eval
    Pattern, expression
    Pattern, heap
    Pattern, line
    Pattern, markov
    Pattern, palindrome
    Pattern, product
    Pattern, random
    Pattern, sum
    Patternp
    Peak
    Peak amplitude
    Peak, maximum amplitude
    Peek
    Peek-char
    Period estimation
    Phaser
    Physical model
    Piano synthesizer
    Piano synthesizer tutorial
    Piano-midi
    Piano-midi2file
    Piano-note
    Piano-note-2
    Piece-wise
    Piece-wise linear
    Pitch 1 2
    Pitch bend
    Pitch detection
    Pitch notation
    Pitch shift 1 2
    Pitch shifting
    Pitshift
    Pl-center
    Pl-doppler
    Pl-left
    Pl-pan2d
    Pl-position
    Pl-rear
    Pl-right
    Play 1 2
    Play in reverse
    Play-file
    Plot
    Pluck
    Plucked string
    Plusp
    Poisson distribution
    Poisson-dist
    Poke
    Polyrhythm
    Pop
    Portamento switch
    Power
    Pp (adagio dynamic)
    Ppp (adagio dynamic)
    Pprint
    Prcrev
    Predicate functions
    Preset
    Prin1
    Princ
    Print
    Print midi file
    Print statement, sal
    *print-case*
    Probability distributions
    Prod 1 2
    Product
    Product pattern
    Profile
    Profiling
    Prog
    Prog*
    Prog1
    Prog2
    Progn
    Program
    Program change
    Progv
    Prologic
    Property list functions
    Psetq
    Pulse oscillator
    Pulse-width modulation
    Push
    Putprop
    Pwe
    Pwe-list
    Pwer
    Pwer-list
    Pwev
    Pwev-list
    Pwevr
    Pwevr-list
    Pwl
    Pwl-list
    Pwlr
    Pwlr-list
    Pwlv
    Pwlv-list
    Pwlvr
    Pwlvr-list

    Q

    TOP
    Q
    Q (adagio quarter note)
    Qd
    Qt
    Quantize
    Quarter note 1 2
    Quote

    R

    TOP
    R (adagio rest)
    !ramp
    Ramp
    Random 1 2 3
    Random pattern
    !rate
    Rate 1 2
    Read
    Read directory
    Read macros
    Read samples
    Read samples from file
    Read samples in reverse
    Read-byte
    Read-char
    Read-float
    Read-int
    Read-line
    *readtable* 1 2
    Readtables
    Real-random
    Recip
    Reciprocal
    Rem
    Remainder
    Remove
    Remove-if
    Remove-if-not
    Remprop
    Replace file samples
    Replay button
    Require-from
    Resample
    Resampling 1 2
    Rescaling
    Resolution
    Reson
    Rest 1 2
    Restore
    Rests
    Return
    Return statement, sal
    Return-from
    Reverb 1 2 3 4 5
    Reverse
    Reverse, sound
    Ring modulation
    Risset
    Rms 1 2
    Room
    Rplaca
    Rplacd
    Rrandom
    *rslt* 1 2

    S

    TOP
    S
    S (adagio sharp)
    S (adagio sixteenth note)
    S-abs
    S-add-to
    S-exp
    S-log
    S-max 1 2
    S-min 1 2
    S-overwrite
    S-plot
    S-print-tree
    S-read
    S-read-reverse
    S-rest
    S-reverse
    S-save
    S-sqrt
    #?, sal
    Sal
    Sal and lisp
    Sal button
    Sal expressions
    Sample interpolation 1 2
    Sample rate, forcing
    Sample rates
    Sampler
    Samples 1 2
    Samples, reading
    Sampling rate 1 2
    Save
    Save samples to file
    Save-lpc-file
    Save-workspace
    Savefile button
    Saving sound files
    Sawtooth oscillator
    Sawtooth wave
    Sax 1 2 3
    Sax-all
    Sax-freq
    Scale
    Scale-db
    Scale-srate
    Scan directory
    Score
    Score manipulation
    Score, musical
    Score-adjacent-events
    Score-append
    Score-apply
    Score-filter
    Score-filter-length
    Score-filter-overlap
    Score-gen 1 2 3
    Score-get-begin
    Score-get-end
    Score-indexof
    Score-last-indexof
    Score-merge
    Score-must-have-begin-end
    Score-play
    Score-print
    Score-randomize-start
    Score-read-smf
    Score-repeat
    Score-scale
    Score-select
    Score-set-begin
    Score-set-end
    Score-shift
    Score-sort
    Score-sorted
    Score-stretch
    Score-stretch-to-length
    Score-sustain
    Score-transpose
    Score-voice
    Score-write-smf
    Scratch sound
    Sd
    Second
    Sections, adagio
    Self
    Semicolon, adagio
    Seq
    Seqrep
    Sequence_example.htm
    Sequences 1 2
    Sequential behavior
    Set
    Set intersection
    Set statement, sal
    Set union
    Set-control-srate 1 2
    Set-difference
    Set-logical-stop
    Set-pitch-names
    Set-sound-srate 1 2
    Setdir
    Setf
    !seti
    Seti commnad
    Setq
    Setup nyquist
    Setup-console
    !setv
    Setv command
    Sf-granulate
    Sf-info
    Shape
    Sharp
    Shepard tones 1 2
    Shift-time
    :show
    Show midi file
    Show-lpc-data
    Signal composition 1 2
    Signal multiplication
    Signal-start
    Signal-stop
    Sim 1 2
    Simrep
    Simultaneous behavior
    Sin
    Sine
    Siosc
    Sitar
    Sixteenth note 1 2
    Sixtyfourth note
    Slope
    Smooth
    Snd-abs
    Snd-add
    Snd-allpoles
    Snd-alpass
    Snd-alpasscv
    Snd-alpassvv
    Snd-amosc
    Snd-areson
    Snd-aresoncv
    Snd-aresonvc
    Snd-aresonvv
    Snd-atone
    Snd-atonev
    Snd-avg
    Snd-bandedwg
    Snd-biquad
    Snd-bowed
    Snd-bowed-freq
    Snd-buzz
    Snd-chase
    Snd-clarinet
    Snd-clarinet-all
    Snd-clarinet-freq
    Snd-clip
    Snd-compose
    Snd-congen
    Snd-const
    Snd-convolve
    Snd-copy
    Snd-coterm
    Snd-delay
    Snd-delaycv
    Snd-down
    Snd-exp
    Snd-extent
    Snd-fetch
    Snd-fetch-array
    Snd-fft
    Snd-flatten
    Snd-flute
    Snd-flute-all
    Snd-flute-freq
    Snd-fmfb
    Snd-fmfbv
    Snd-fmosc
    Snd-follow
    Snd-from-array
    Snd-fromarraystream
    Snd-fromobject
    Snd-gate
    Snd-ifft
    Snd-inverse
    Snd-length
    Snd-log
    Snd-lpanal
    Snd-lpreson
    Snd-mandolin
    Snd-max
    Snd-maxsamp
    Snd-maxv
    Snd-modalbar
    Snd-multiseq
    Snd-normalize
    Snd-offset
    Snd-oneshot
    Snd-osc
    Snd-overwrite
    Snd-partial
    Snd-play
    Snd-pluck
    Snd-print
    Snd-print-tree 1 2
    Snd-prod
    Snd-pwl
    Snd-quantize
    Snd-read
    Snd-recip
    Snd-resample
    Snd-resamplev
    Snd-reson
    Snd-resoncv
    Snd-resonvc
    Snd-resonvv
    Snd-samples
    Snd-save
    Snd-sax
    Snd-sax-all
    Snd-sax-freq
    Snd-scale
    Snd-seq
    Snd-set-latency
    Snd-set-logical-stop
    Snd-shape
    Snd-sine
    Snd-siosc
    Snd-sitar
    Snd-slider
    Snd-sqrt
    Snd-srate
    Snd-sref
    Snd-stkchorus
    Snd-stkpitshift
    Snd-stkrev
    Snd-stop-time
    Snd-t0
    Snd-tapf
    Snd-tapv
    Snd-time
    Snd-tone
    Snd-tonev
    Snd-trigger
    Snd-up
    Snd-white
    Snd-xform
    Snd-yin
    Snd-zero
    Soften-clipping
    Sort
    Sound
    Sound browser, jnyqide
    Sound file directory default
    Sound file i/o
    Sound file info
    Sound from lisp data
    Sound, accessing point
    Sound, creating from array
    Sound-off 1 2
    Sound-on 1 2
    *sound-srate* 1 2 3
    Sound-srate-abs
    Sound-warp
    *soundenable*
    Soundfilename
    Soundp
    Sounds
    Sounds vs. behaviors
    Span
    Spatialization
    Special command
    Spectral interpolation
    Speed-dial
    Splines
    Sqrt
    Square oscillator
    Square root 1 2
    Srate
    Sref
    Sref-inverse
    St
    Stacatto
    Staccato
    Stack trace
    Standard midi file
    *standard-input*
    *standard-output*
    *start*
    Statements, sal
    Stats
    Step-to-hz
    Stereo
    Stereo pan
    Stereo panning
    Stereo-chorus
    Stereoize
    Stk banded waveguide
    Stk bowed 1 2
    Stk bowed string
    Stk bowed-freq
    Stk chorus 1 2
    Stk clarinet 1 2 3 4 5
    Stk flute 1 2 3 4 5 6
    Stk glass harmonica
    Stk jcreverb
    Stk mandolin
    Stk mandolon
    Stk modal bar 1 2
    Stk nreverb
    Stk pitch shift 1 2
    Stk prcreverb
    Stk reverb
    Stk sax 1 2 3 4
    Stk sitar 1 2
    Stk tibetan bowl
    Stk tuned bar
    Stk uniform bar
    Stkchorus
    Stochastic functions
    *stop*
    Strcat
    Streamp
    Stretch 1 2
    Stretch transformation
    Stretch, sal
    Stretch-abs
    Stretching sampled sounds
    String
    String functions
    String stream functions
    String synthesis
    String-downcase
    String-equalp
    String-greaterp
    String-left-trim
    String-lessp
    String-not-equalp
    String-not-greaterp
    String-not-lessp
    String-right-trim
    String-search
    String-trim
    String-upcase
    String/=
    String<
    String<=
    String=
    String>
    String>=
    Stringp
    Sublis
    Subseq
    Subset
    Subsetp
    Subst
    Suggestions
    Sum
    Sum pattern
    Surround sound
    Sustain
    *sustain*
    Sustain-abs
    Swap channels
    Swapchannels
    Symbol functions
    Symbol-function
    Symbol-name
    Symbol-plist
    Symbol-value
    Symbolp
    Symbols
    Synchronization
    System functions

    T

    TOP
    T
    #t
    T (adagio triplet)
    Table
    Table memory
    *table*
    Tagbody
    Tan
    Tap
    Tapped delay
    Tapv
    Temp file 1 2
    !tempo
    Tempo 1 2
    Temporary files
    Temporary sound files directory
    Terpri
    The format function
    The program feature
    Third
    Thirtysecond note
    Threshold
    Throw
    Time 1 2 3
    Time shift, sal
    Time structure
    Time units
    Timed-seq
    Tone
    Top button
    Top-level
    Touch tone
    Trace
    *trace-output*
    *tracelimit* 1 2
    *tracelist*
    *tracenable* 1 2 3
    Transformation environment
    Transformations 1 2
    Transpose
    *transpose*
    Transpose-abs
    Triangle oscillator
    Triangle wave
    Trigger
    Trill
    Triplet
    Triplet durations
    Truncate
    Tuba
    Tuning
    Tutorial, fm
    Type-of

    U

    TOP
    U
    *unbound*
    Uniform random 1 2
    Union
    Unless
    Untrace
    Unwind-protect
    Upic
    Upper-case-p
    User name

    V

    TOP
    V (adagio voice)
    Variable delay 1 2 3
    Variable-resample function
    Vector
    Velocity
    Vinal scratch
    Vocal sound
    Voice 1 2
    Voice synthesis
    Volume

    W

    TOP
    W
    W (adagio whole note)
    Warble
    Warp
    *warp* 1 2 3
    Warp-abs
    Waveforms 1 2
    Waveshaping
    Wavetables 1 2
    Wd
    Wg-glass-harm
    Wg-tibetan-bowl
    Wg-tuned-bar
    Wg-uniform-bar
    When 1 2
    While
    Whole note 1 2
    Widen
    Wii controller
    Wind sound
    Wind_tutorial.htm
    Window initialization
    Window pattern
    With statement, sal
    Wood drum sound
    Workspace 1 2
    Write samples to file
    Write-byte
    Write-char
    Write-float
    Write-int
    Wt

    X

    TOP
    X (adagio control)
    Xenakis
    Xlisp command loop
    Xlisp data types
    Xlisp evaluator
    Xlisp lexical conventions
    Xmusic

    Y

    TOP
    Y (adagio control)
    Yin

    Z

    TOP
    Z (adagio program) 1 2
    Zerop
    nyquist-3.05/doc/exponential-fig.gif0000644000175000000620000000172311466723256016527 0ustar stevestaffGIF87a w!Software: Microsoft Office, ڋ޼c$G扦ZL׶@Lʦ AjBڮ[Q4k4 WzPd'hxx1R)8iyYI) 'ZjCj**+;k t{ <$IlT,=}mfM ;'BY[- N)k M^e^n?%W E@$w}X=_!U}, /ITLkK1gb8Ц4f2u6'"BY Z4Ѥö!e)TRjtd*֬=XCڄu:6z ;oʫ3[];k5@BsI |aO3b$$%O>e y5hCgsAUf5eGQvue;,e&~81/R9/ΥQ9ڣ|=nq_ѓO>'Y7g޶L=Czf`p%s !j!! UZz^f% ^Xbrh""f,x"W9h1+@Dː g$8<-9N&)CV_xYsUǏ'^a)Q;gb"6 ]xJM?d:d8ݢ9BHj Z A:pڣyZ*cF6`ZjG*Sj8ŭ[DKkE*,AzT8Ôvk,{JSmT;u:+H-m hK .-'kr+Ӟ!pp /p? n5-[,_)RwF&zq!hPm{,XL/;0$;aR;nyquist-3.05/doc/indx.html0000644000175000000620000025352611537432671014606 0ustar stevestaffPrevious Section | Table of Contents | Title Page
    Index

    Index

    !-~

    TOP
    ! 1 2
    !=
    !call
    !clock
    !csec
    !def
    !end
    !msec
    !ramp
    !rate
    !seti
    !setv
    !tempo
    # (adagio articulation)
    #?, sal
    #define'd macros
    #f
    #t
    %
    % (adagio thirtysecond note)
    &
    &=
    * 1 2
    *=
    *a4-hertz* 1 2
    *applyhook*
    *audio-markers*
    *autonorm*
    *autonorm-max-samples*
    *autonorm-previous-peak*
    *autonorm-target*
    *autonorm-type*
    *autonormflag*
    *breakenable* 1 2 3 4
    *control-srate* 1 2 3
    *debug-io*
    *default-control-srate*
    *default-plot-file*
    *default-sf-bits*
    *default-sf-dir* 1 2
    *default-sf-format*
    *default-sf-srate* 1 2
    *default-sound-srate*
    *error-output*
    *evalhook*
    *file-separator*
    *float-format*
    *gc-flag*
    *gc-hook*
    *integer-format*
    *loud*
    *obarray*
    *print-case*
    *readtable* 1 2
    *rslt* 1 2
    *sound-srate* 1 2 3
    *soundenable*
    *standard-input*
    *standard-output*
    *start*
    *stop*
    *sustain*
    *table*
    *trace-output*
    *tracelimit* 1 2
    *tracelist*
    *tracenable* 1 2 3
    *transpose*
    *unbound*
    *warp* 1 2 3
    + 1 2
    +=
    , (adagio)
    - 1 2
    . (adagio)
    / 1 2
    /=
    1+
    1-
    :answer
    :class
    :isa
    :isnew 1 2
    :new
    :show
    ; (adagio)
    < 1 2
    <= 1 2 3
    = 1 2
    > 1 2
    >= 1 2 3
    @
    @=
    @@
    ^
    ^ (adagio sixtyfourth note)
    ^=
    |
    ~
    ~ (adagio)
    ~=
    ~~

    A

    TOP
    *a4-hertz* 1 2
    A440
    Abs
    Abs-env
    Absolute stretch, sal
    Absolute time shift, sal
    Absolute value 1 2
    Access samples
    Accidentals
    Accumulate pattern
    Accumulation pattern
    Adagio
    # (adagio articulation)
    ^ (adagio sixtyfourth note)
    % (adagio thirtysecond note)
    ~ (adagio)
    ; (adagio)
    , (adagio)
    . (adagio)
    Add offset to sound
    Add to file samples
    Add-action-to-workspace
    Add-to-workspace
    Additive synthesis, gongs
    Address-of
    Aftertouch
    Agc
    Algorithmic composition
    All pass filter
    Alloc
    Allpass2
    Allpoles-from-lpc
    Alpass
    Alpass filter
    Amosc
    Analog synthesizer
    And
    :answer
    Append
    Apply
    Apply-banded-bass-boost
    Apply-banded-delay
    Apply-banded-treble-boost
    *applyhook*
    Approximation
    Arc-sine-dist
    Arcsine distribution
    Aref
    Areson
    Args
    Arguments to a lisp function
    Arithmetic functions
    Arpeggiator
    Array from sound
    Array functions
    Array notation, sal
    Arrayp
    Articulation 1 2
    Assoc
    Asterisk
    At
    At transformation
    At, sal
    At-abs
    At-abs, sal
    Atan
    Atom
    Atone
    Attributes
    Audio markers
    *audio-markers*
    Automatic gain control
    *autonorm*
    *autonorm-max-samples*
    Autonorm-off 1 2 3
    Autonorm-on 1 2 3
    *autonorm-previous-peak*
    *autonorm-target*
    *autonorm-type*
    *autonormflag*
    Average

    B

    TOP
    Backquote
    Backward
    Baktrace
    Banded bass boost
    Banded delay
    Banded treble boost
    Bandfx.lsp
    Bandpass filter
    Bandpass2
    Bartok
    Begin
    Behavioral abstraction
    Behaviors
    Bell sound 1 2
    Bernoulli distribution
    Bernoulli-dist
    Beta distribution
    Beta-dist
    Big endian
    Bigendianp
    Bilateral exponential distribution
    Bilateral-exponential-dist
    Binary files
    Binomial distribution
    Binomial-dist
    Biquad
    Biquad-m
    Bitwise logical functions
    Blank
    Block
    Both-case-p
    Boundp
    Bowed
    Bowed-freq
    Brass sound
    Break 1 2
    Break button
    *breakenable* 1 2 3 4
    Browse button
    Browser, jnyqide
    Build-harmonic 1 2
    Button bar
    Buzz

    C

    TOP
    !call
    Call command
    Car
    Case 1 2
    Case-insensitive
    Catch
    Cauchy distribution
    Cauchy-dist
    Cdr
    Cerror
    Change directory
    Char
    Char-code
    Char-downcase
    Char-equalp
    Char-greaterp
    Char-int
    Char-lessp
    Char-not-equalp
    Char-not-greaterp
    Char-not-lessp
    Char-upcase
    Char/=
    Char<
    Char<=
    Char=
    Char>
    Char>=
    Character functions
    Characterp
    Chdir, sal
    Chorus 1 2 3 4 5
    Clarinet 1 2 3
    Clarinet sound
    Clarinet-all
    Clarinet-freq
    Class
    :class
    Class class
    Clean-up
    Clip 1 2 3
    Clipping repair
    !clock
    Clock
    Clock command
    Close
    Co-termination
    Code-char
    Comb
    Comb filter
    Combination
    Command loop
    Commas
    Comment 1 2
    Comments
    Compose
    Compress
    Compress-map
    Compressor
    Concatenate strings
    Cond
    Conditional expression, sal
    Configure nyquist
    Congen
    Cons
    Console, xlisp
    Consp
    Const
    Constant function
    Continue
    Continuous-control-warp
    Continuous-sound-warp
    Contour generator
    Control
    Control change
    Control characters, xlisp
    Control constructs
    Control-a
    *control-srate* 1 2 3
    Control-srate-abs
    Control-warp
    Convert sound to array
    Convolution
    Convolve
    Copier pattern
    Cos
    !csec
    Cue
    Cue-file
    Current-path
    Cxxr
    Cxxxr
    Cxxxxr
    Cycle pattern

    D

    TOP
    Darwiinremoteosc
    Data types
    Db-average
    Db-to-linear
    Db0
    Db1
    Db10
    *debug-io*
    Debugging 1 2 3 4 5
    Decf
    Decrement
    !def
    Default
    Default durations
    Default sample rate
    Default sound file directory
    Default time
    *default-control-srate*
    *default-plot-file*
    *default-sf-bits*
    *default-sf-dir* 1 2
    *default-sf-format*
    *default-sf-srate* 1 2
    *default-sound-srate*
    Define function
    Define variable
    #define'd macros
    Defining behaviors
    Defmacro
    Defun
    Delay
    Delay, variable
    Delay, variable
    Delete
    Delete-if
    Delete-if-not
    Demos, bell sound
    Demos, distortion
    Demos, drum machine
    Demos, drum sound
    Demos, fft
    Demos, fm
    Demos, fm synthesis
    Demos, formants
    Demos, gong sound
    Demos, lpc
    Demos, midi
    Demos, piano
    Demos, pitch change
    Demos, rhythmic pattern
    Demos, ring modulation
    Demos, sample-by-sample
    Demos, scratch tutorial
    Demos, shepard tones
    Demos, spectral analysis of a chord
    Demos, voice synthesis
    Demos, wind sound
    Derivative
    Describe
    Destructive list functions
    Developing code
    Diff
    Difference
    Difference of sounds
    Digit-char
    Digit-char-p
    Directory listing
    Directory, default sound file
    Display statement, sal
    Distortion tutorial
    Distributions, probability
    Division
    Do
    Do*
    Dolby pro-logic
    Dolby surround
    Dolist
    Doppler effect
    Dot
    Dotimes
    Dotted durations
    Dribble
    Drum
    Drum samples
    Drum machine 1 2
    Drum sound
    Drum-loop
    Dsp in lisp 1 2
    Dtmf
    Dtmf-tone
    Dubugging
    Duration 1 2
    Duration notation
    Duration of another sound
    Dx7
    Dynamic markings

    E

    TOP
    Echo
    Echoenabled
    Editor for envelopes
    Effect, reverberation 1 2
    Effect, reverberation
    Effect, chorus 1 2 3
    Effect, flange
    Effect, pitch shift 1 2
    Effect, reverberation 1 2
    Effect, stereo
    Effect, stereo pan
    Effect, swap channels
    Effect, widen
    Effects, phaser
    Eighth note 1 2
    Elapsed audio time
    Emacs, using nyquist with
    Empty list
    !end
    End
    End command
    Endian
    Endless tones
    Endp
    Env 1 2
    Env-note
    Envedit button
    Envelope
    Envelope editor
    Envelope follower 1 2
    Envelope generator
    Envelopes
    Environment
    Environment variables
    Eq
    Eq button
    Eq-band
    Eq-highshelf
    Eq-lowshelf
    Eql
    Equal
    Equalization 1 2 3 4
    Equalization editor
    Error
    Error handling
    *error-output*
    Errors
    Errset
    Estimate frequency
    Eval
    Eval pattern
    Evalhook
    *evalhook*
    Evaluation functions
    Evaluator
    Evenp
    Event-dur
    Event-end
    Event-expression
    Event-get-attr
    Event-has-attr
    Event-set-attr
    Event-set-dur
    Event-set-expression
    Event-set-time
    Event-time
    Exclamation point
    Exec statement, sal
    Exit
    Exit statement, sal
    Exp
    Exp-dec
    Expand
    Exponent
    Exponential
    Exponential distribution
    Exponential envelope
    Exponential-dist
    Expr-get-attr
    Expr-has-attr
    Expr-set-attr
    Expression pattern
    Expressions, sal
    Expt
    Extending xlisp
    Extract
    Extract-abs

    F

    TOP
    #f
    F (adagio dynamic)
    F (adagio flat)
    Fast fourier transform tutorial
    Fboundp
    Feedback fm oscillator
    Feedback-delay
    Feel factor
    Ff (adagio dynamic)
    Fff (adagio dynamic)
    Fft
    Fft tutorial
    File i/o functions 1 2
    *file-separator*
    Filep
    Filter example
    Finally clause, sal
    Find string
    Find-in-xlisp-path
    Fir filter
    First
    First derivative
    Flange
    Flange effect
    Flat
    Flatc
    Flatsize
    Flet
    Float
    *float-format*
    Floatp
    Flute
    Flute sound
    Flute-all
    Flute-freq
    Fm synthesis
    Fmfb
    Fmlfo
    Fmosc
    Fn button
    Follow
    Follower
    Force-srate
    Format
    Fourth
    Frequency analysis
    Frequency modulation
    Full path name
    Funcall
    Function
    Function calls, sal
    Function, sal
    Fundamenal frequency estimation

    G

    TOP
    Gain
    Gamma-dist
    Gate 1 2
    Gaussian distribution
    Gaussian-dist
    Gc
    *gc-flag*
    *gc-hook*
    Gcd
    Gen05
    Gensym
    Geometric distribution
    Geometric-dist
    Get
    Get char
    Get-duration
    Get-env
    Get-lambda-expression
    Get-loud
    Get-output-stream-list
    Get-output-stream-string
    Get-slider-value
    Get-sustain
    Get-temp-path
    Get-transpose
    Get-user
    Get-warp
    Getenv
    Global variables
    Global variables, sal
    Go
    Gong sounds
    Granular synthesis
    Graphical envelope editor
    Graphical equalization
    Graphical equalizer
    Grindef

    H

    TOP
    H
    H (adagio half note)
    Half note 1 2
    Harmonic
    Hash
    Hd
    Header file format
    Heap pattern
    High-pass filter
    Highpass2
    Highpass4
    Highpass6
    Highpass8
    Hp
    Ht
    Hyperbolic-cosine-dist
    Hz-to-step
    Hzosc

    I

    TOP
    I
    I (adagio eight note)
    Iannis xenakis
    Id
    Ide
    If
    If statement, sal
    Ifft
    Incf
    Increment
    Info
    Info button
    Input from a file
    Input/output functions
    Installation
    Int-char
    *integer-format*
    Integerp
    Integrate
    Integrated development environment
    Intern
    Interoperability, sal and lisp
    Interpolate
    Intersection
    Intgen
    Inverse
    Inverse fft
    :isa
    :isnew 1 2
    It

    J

    TOP
    Jcrev
    Jitter

    K

    TOP
    K (adagio control)
    Karplus-strong
    Karplus-strong synthesis
    Keyword parameters

    L

    TOP
    Labels
    Lambda
    Lambda lists
    Last
    Latency
    Legato 1 2
    Length
    Length pattern
    Length-of-beat
    Let
    Let*
    Lexical conventions
    Lf
    Lf (adagio dynamic)
    Lff
    Lff (adagio dynamic)
    Lfff
    Lfff (adagio dynamic)
    Lfo
    Libraries
    Limit
    Limiter
    Line pattern
    Linear distribution
    Linear interpolation
    Linear prediction
    Linear prediction tutorial
    Linear-dist
    Linear-to-db
    Lisp button
    Lisp dsp 1 2
    Lisp include files
    List
    List directory
    List functions
    Listdir
    Listing of lisp function
    Listp
    Little endian
    Lmf
    Lmf (adagio dynamic)
    Lmp
    Lmp (adagio dynamic)
    Load
    Load button
    Load file conditionally
    Load statement, sal
    Local-to-global
    Log
    Log function
    Logand
    Logical-stop
    Logior
    Logistic distribution
    Logistic-dist
    Lognot
    Logorithm
    Logxor
    Loop
    Loop examples, sal
    Loop statement, sal
    Looping constructs
    Loud
    *loud*
    Loud-abs
    Loudness 1 2
    Low-frequency oscillator
    Low-pass filter 1 2
    Lower-case-p
    Lowpass2
    Lowpass4
    Lowpass6
    Lowpass8
    Lp 1 2
    Lp (adagio dynamic)
    Lpc
    Lpc tutorial
    Lpc-frame-err 1 2
    Lpc-frame-filter-coefs 1 2
    Lpc-frame-rms1 1 2
    Lpc-frame-rms2 1 2
    Lpp
    Lpp (adagio dynamic)
    Lppp
    Lppp (adagio dynamic)
    Lpreson

    M

    TOP
    M (adagio control)
    Macroexpand
    Macroexpand-1
    Macrolet
    Make-accumulate
    Make-accumulation
    Make-array
    Make-copier
    Make-cycle
    Make-eval
    Make-heap
    Make-length
    Make-line
    Make-lpanal-iterator
    Make-lpc-file-iterator
    Make-markov
    Make-palindrome
    Make-product
    Make-random
    Make-string-input-stream
    Make-string-output-stream
    Make-sum
    Make-symbol
    Make-window
    Maketable
    Mandolin
    Manipulation of scores
    Mapc
    Mapcar
    Mapl
    Maplist
    Mark button
    Markers, audio
    Markov analysis
    Markov pattern
    Markov-create-rules
    Max
    Maximum 1 2
    Maximum amplitude 1 2
    Maximum of two sounds
    Member
    Memory usage
    Mf (adagio dynamic)
    Middle c
    Midi
    Midi clock
    Midi file 1 2 3
    Midi program
    Midi-show
    Midi-show-file
    Mikrokosmos
    Min
    Minimoog
    Minimum 1 2
    Minusp
    Mix
    Mix to file
    Mkwave
    Modalbar
    Modulation wheel
    Modulo (rem
    Mono to stereo
    Moog
    Moving average
    Mp (adagio dynamic)
    !msec
    Mult 1 2 3
    Multichannel sounds
    Multiple band effects
    Multiple commands
    Multiple tempi
    Multiplication
    Multiply signals
    My-note

    N

    TOP
    N (adagio next)
    Natural
    Natural log
    Nband
    Nband-range
    Nconc
    Nested transformations
    :new
    Newfile button
    Next adagio command
    Next in pattern
    Next pattern
    Nintendo wiimote
    Noise
    Noise gate
    Noise-gate
    Normalization
    Not
    Not enough memory for normalization
    Notch filter
    Notch2
    Note list
    Nrev
    Nstring-downcase
    Nstring-upcase
    Nth
    Nthcdr
    Null
    Numberp
    Ny:all
    Nyquistide

    O

    TOP
    O (adagio control)
    *obarray*
    Object
    Object class
    Objectp
    Objects
    Octave specification 1 2
    Oddp
    Offset
    Offset to a sound
    Omissions
    Oneshot
    Open 1 2
    Open sound control 1 2
    Open-binary
    Openfile button
    Or
    Osc 1 2 3
    Osc-enable
    Osc-note
    Osc-pulse
    Osc-saw
    Osc-tri
    Output samples to file
    Output to a file
    Overlap
    Overwrite samples

    P

    TOP
    P (adagio dynamic)
    P (adagio pitch)
    Palindrome pattern
    Pan 1 2
    Pan, stereo
    Parameters, keyword
    Params-scale
    Params-transpose
    Partial
    Path, current
    Pattern, length
    Pattern, window
    Pattern, accumulate
    Pattern, accumulation
    Pattern, copier
    Pattern, cycle
    Pattern, eval
    Pattern, expression
    Pattern, heap
    Pattern, line
    Pattern, markov
    Pattern, palindrome
    Pattern, product
    Pattern, random
    Pattern, sum
    Patternp
    Peak
    Peak amplitude
    Peak, maximum amplitude
    Peek
    Peek-char
    Period estimation
    Phaser
    Physical model
    Piano synthesizer
    Piano synthesizer tutorial
    Piano-midi
    Piano-midi2file
    Piano-note
    Piano-note-2
    Piece-wise
    Piece-wise linear
    Pitch 1 2
    Pitch bend
    Pitch detection
    Pitch notation
    Pitch shift 1 2
    Pitch shifting
    Pitshift
    Pl-center
    Pl-doppler
    Pl-left
    Pl-pan2d
    Pl-position
    Pl-rear
    Pl-right
    Play 1 2
    Play in reverse
    Play-file
    Plot
    Pluck
    Plucked string
    Plusp
    Poisson distribution
    Poisson-dist
    Poke
    Polyrhythm
    Pop
    Portamento switch
    Power
    Pp (adagio dynamic)
    Ppp (adagio dynamic)
    Pprint
    Prcrev
    Predicate functions
    Preset
    Prin1
    Princ
    Print
    Print midi file
    Print statement, sal
    *print-case*
    Probability distributions
    Prod 1 2
    Product
    Product pattern
    Profile
    Profiling
    Prog
    Prog*
    Prog1
    Prog2
    Progn
    Program
    Program change
    Progv
    Prologic
    Property list functions
    Psetq
    Pulse oscillator
    Pulse-width modulation
    Push
    Putprop
    Pwe
    Pwe-list
    Pwer
    Pwer-list
    Pwev
    Pwev-list
    Pwevr
    Pwevr-list
    Pwl
    Pwl-list
    Pwlr
    Pwlr-list
    Pwlv
    Pwlv-list
    Pwlvr
    Pwlvr-list

    Q

    TOP
    Q
    Q (adagio quarter note)
    Qd
    Qt
    Quantize
    Quarter note 1 2
    Quote

    R

    TOP
    R (adagio rest)
    !ramp
    Ramp
    Random 1 2 3
    Random pattern
    !rate
    Rate 1 2
    Read
    Read directory
    Read macros
    Read samples
    Read samples from file
    Read samples in reverse
    Read-byte
    Read-char
    Read-float
    Read-int
    Read-line
    *readtable* 1 2
    Readtables
    Real-random
    Recip
    Reciprocal
    Rem
    Remainder
    Remove
    Remove-if
    Remove-if-not
    Remprop
    Replace file samples
    Replay button
    Require-from
    Resample
    Resampling 1 2
    Rescaling
    Resolution
    Reson
    Rest 1 2
    Restore
    Rests
    Return
    Return statement, sal
    Return-from
    Reverb 1 2 3 4 5
    Reverse
    Reverse, sound
    Ring modulation
    Risset
    Rms 1 2
    Room
    Rplaca
    Rplacd
    Rrandom
    *rslt* 1 2

    S

    TOP
    S
    S (adagio sharp)
    S (adagio sixteenth note)
    S-abs
    S-add-to
    S-exp
    S-log
    S-max 1 2
    S-min 1 2
    S-overwrite
    S-plot
    S-print-tree
    S-read
    S-read-reverse
    S-rest
    S-reverse
    S-save
    S-sqrt
    #?, sal
    Sal
    Sal and lisp
    Sal button
    Sal expressions
    Sample interpolation 1 2
    Sample rate, forcing
    Sample rates
    Sampler
    Samples 1 2
    Samples, reading
    Sampling rate 1 2
    Save
    Save samples to file
    Save-lpc-file
    Save-workspace
    Savefile button
    Saving sound files
    Sawtooth oscillator
    Sawtooth wave
    Sax 1 2 3
    Sax-all
    Sax-freq
    Scale
    Scale-db
    Scale-srate
    Scan directory
    Score
    Score manipulation
    Score, musical
    Score-adjacent-events
    Score-append
    Score-apply
    Score-filter
    Score-filter-length
    Score-filter-overlap
    Score-gen 1 2 3
    Score-get-begin
    Score-get-end
    Score-indexof
    Score-last-indexof
    Score-merge
    Score-must-have-begin-end
    Score-play
    Score-print
    Score-randomize-start
    Score-read-smf
    Score-repeat
    Score-scale
    Score-select
    Score-set-begin
    Score-set-end
    Score-shift
    Score-sort
    Score-sorted
    Score-stretch
    Score-stretch-to-length
    Score-sustain
    Score-transpose
    Score-voice
    Score-write-smf
    Scratch sound
    Sd
    Second
    Sections, adagio
    Self
    Semicolon, adagio
    Seq
    Seqrep
    Sequence_example.htm
    Sequences 1 2
    Sequential behavior
    Set
    Set intersection
    Set statement, sal
    Set union
    Set-control-srate 1 2
    Set-difference
    Set-logical-stop
    Set-pitch-names
    Set-sound-srate 1 2
    Setdir
    Setf
    !seti
    Seti commnad
    Setq
    Setup nyquist
    Setup-console
    !setv
    Setv command
    Sf-granulate
    Sf-info
    Shape
    Sharp
    Shepard tones 1 2
    Shift-time
    :show
    Show midi file
    Show-lpc-data
    Signal composition 1 2
    Signal multiplication
    Signal-start
    Signal-stop
    Sim 1 2
    Simrep
    Simultaneous behavior
    Sin
    Sine
    Siosc
    Sitar
    Sixteenth note 1 2
    Sixtyfourth note
    Slope
    Smooth
    Snd-abs
    Snd-add
    Snd-allpoles
    Snd-alpass
    Snd-alpasscv
    Snd-alpassvv
    Snd-amosc
    Snd-areson
    Snd-aresoncv
    Snd-aresonvc
    Snd-aresonvv
    Snd-atone
    Snd-atonev
    Snd-avg
    Snd-bandedwg
    Snd-biquad
    Snd-bowed
    Snd-bowed-freq
    Snd-buzz
    Snd-chase
    Snd-clarinet
    Snd-clarinet-all
    Snd-clarinet-freq
    Snd-clip
    Snd-compose
    Snd-congen
    Snd-const
    Snd-convolve
    Snd-copy
    Snd-coterm
    Snd-delay
    Snd-delaycv
    Snd-down
    Snd-exp
    Snd-extent
    Snd-fetch
    Snd-fetch-array
    Snd-fft
    Snd-flatten
    Snd-flute
    Snd-flute-all
    Snd-flute-freq
    Snd-fmfb
    Snd-fmfbv
    Snd-fmosc
    Snd-follow
    Snd-from-array
    Snd-fromarraystream
    Snd-fromobject
    Snd-gate
    Snd-ifft
    Snd-inverse
    Snd-length
    Snd-log
    Snd-lpanal
    Snd-lpreson
    Snd-mandolin
    Snd-max
    Snd-maxsamp
    Snd-maxv
    Snd-modalbar
    Snd-multiseq
    Snd-normalize
    Snd-offset
    Snd-oneshot
    Snd-osc
    Snd-overwrite
    Snd-partial
    Snd-play
    Snd-pluck
    Snd-print
    Snd-print-tree 1 2
    Snd-prod
    Snd-pwl
    Snd-quantize
    Snd-read
    Snd-recip
    Snd-resample
    Snd-resamplev
    Snd-reson
    Snd-resoncv
    Snd-resonvc
    Snd-resonvv
    Snd-samples
    Snd-save
    Snd-sax
    Snd-sax-all
    Snd-sax-freq
    Snd-scale
    Snd-seq
    Snd-set-latency
    Snd-set-logical-stop
    Snd-shape
    Snd-sine
    Snd-siosc
    Snd-sitar
    Snd-slider
    Snd-sqrt
    Snd-srate
    Snd-sref
    Snd-stkchorus
    Snd-stkpitshift
    Snd-stkrev
    Snd-stop-time
    Snd-t0
    Snd-tapf
    Snd-tapv
    Snd-time
    Snd-tone
    Snd-tonev
    Snd-trigger
    Snd-up
    Snd-white
    Snd-xform
    Snd-yin
    Snd-zero
    Soften-clipping
    Sort
    Sound
    Sound browser, jnyqide
    Sound file directory default
    Sound file i/o
    Sound file info
    Sound from lisp data
    Sound, accessing point
    Sound, creating from array
    Sound-off 1 2
    Sound-on 1 2
    *sound-srate* 1 2 3
    Sound-srate-abs
    Sound-warp
    *soundenable*
    Soundfilename
    Soundp
    Sounds
    Sounds vs. behaviors
    Span
    Spatialization
    Special command
    Spectral interpolation
    Speed-dial
    Splines
    Sqrt
    Square oscillator
    Square root 1 2
    Srate
    Sref
    Sref-inverse
    St
    Stacatto
    Staccato
    Stack trace
    Standard midi file
    *standard-input*
    *standard-output*
    *start*
    Statements, sal
    Stats
    Step-to-hz
    Stereo
    Stereo pan
    Stereo panning
    Stereo-chorus
    Stereoize
    Stk banded waveguide
    Stk bowed 1 2
    Stk bowed string
    Stk bowed-freq
    Stk chorus 1 2
    Stk clarinet 1 2 3 4 5
    Stk flute 1 2 3 4 5 6
    Stk glass harmonica
    Stk jcreverb
    Stk mandolin
    Stk mandolon
    Stk modal bar 1 2
    Stk nreverb
    Stk pitch shift 1 2
    Stk prcreverb
    Stk reverb
    Stk sax 1 2 3 4
    Stk sitar 1 2
    Stk tibetan bowl
    Stk tuned bar
    Stk uniform bar
    Stkchorus
    Stochastic functions
    *stop*
    Strcat
    Streamp
    Stretch 1 2
    Stretch transformation
    Stretch, sal
    Stretch-abs
    Stretching sampled sounds
    String
    String functions
    String stream functions
    String synthesis
    String-downcase
    String-equalp
    String-greaterp
    String-left-trim
    String-lessp
    String-not-equalp
    String-not-greaterp
    String-not-lessp
    String-right-trim
    String-search
    String-trim
    String-upcase
    String/=
    String<
    String<=
    String=
    String>
    String>=
    Stringp
    Sublis
    Subseq
    Subset
    Subsetp
    Subst
    Suggestions
    Sum
    Sum pattern
    Surround sound
    Sustain
    *sustain*
    Sustain-abs
    Swap channels
    Swapchannels
    Symbol functions
    Symbol-function
    Symbol-name
    Symbol-plist
    Symbol-value
    Symbolp
    Symbols
    Synchronization
    System functions

    T

    TOP
    T
    #t
    T (adagio triplet)
    Table
    Table memory
    *table*
    Tagbody
    Tan
    Tap
    Tapped delay
    Tapv
    Temp file 1 2
    !tempo
    Tempo 1 2
    Temporary files
    Temporary sound files directory
    Terpri
    The format function
    The program feature
    Third
    Thirtysecond note
    Threshold
    Throw
    Time 1 2 3
    Time shift, sal
    Time structure
    Time units
    Timed-seq
    Tone
    Top button
    Top-level
    Touch tone
    Trace
    *trace-output*
    *tracelimit* 1 2
    *tracelist*
    *tracenable* 1 2 3
    Transformation environment
    Transformations 1 2
    Transpose
    *transpose*
    Transpose-abs
    Triangle oscillator
    Triangle wave
    Trigger
    Trill
    Triplet
    Triplet durations
    Truncate
    Tuba
    Tuning
    Tutorial, fm
    Type-of

    U

    TOP
    U
    *unbound*
    Uniform random 1 2
    Union
    Unless
    Untrace
    Unwind-protect
    Upic
    Upper-case-p
    User name

    V

    TOP
    V (adagio voice)
    Variable delay 1 2 3
    Variable-resample function
    Vector
    Velocity
    Vinal scratch
    Vocal sound
    Voice 1 2
    Voice synthesis
    Volume

    W

    TOP
    W
    W (adagio whole note)
    Warble
    Warp
    *warp* 1 2 3
    Warp-abs
    Waveforms 1 2
    Waveshaping
    Wavetables 1 2
    Wd
    Wg-glass-harm
    Wg-tibetan-bowl
    Wg-tuned-bar
    Wg-uniform-bar
    When 1 2
    While
    Whole note 1 2
    Widen
    Wii controller
    Wind sound
    Wind_tutorial.htm
    Window initialization
    Window pattern
    With statement, sal
    Wood drum sound
    Workspace 1 2
    Write samples to file
    Write-byte
    Write-char
    Write-float
    Write-int
    Wt

    X

    TOP
    X (adagio control)
    Xenakis
    Xlisp command loop
    Xlisp data types
    Xlisp evaluator
    Xlisp lexical conventions
    Xmusic

    Y

    TOP
    Y (adagio control)
    Yin

    Z

    TOP
    Z (adagio program) 1 2
    Zerop

    Previous Section | Table of Contents | Title Page nyquist-3.05/doc/part1.html0000644000175000000620000000747511537432671014673 0ustar stevestaffPreface Previous Section | Next Section | Table of Contents | Index | Title Page

    Preface

    This manual is a guide for users of Nyquist, a language for composition and sound synthesis. Nyquist grew out of a series of research projects, notably the languages Arctic and Canon. Along with Nyquist, these languages promote a functional style of programming and incorporate time into the language semantics.

    Please help by noting any errors, omissions, or suggestions you may have. You can send your suggestions to Dannenberg@CS.CMU.EDU (internet) via computer mail, or by campus mail to Roger B. Dannenberg, School of Computer Science, or by ordinary mail to Roger B. Dannenberg, School of Computer Science, Carnegie Mellon University, 5000 Forbes Ave., Pittsburgh, PA 15213-3890, USA.

    Nyquist is a successor to Fugue, a language originally implemented by Chris Fraley, and extended by George Polly and Roger Dannenberg. Peter Velikonja and Dean Rubine were early users, and they proved the value as well as discovered some early problems of the system. This led to Nyquist, a reimplementation of Fugue by Roger Dannenberg with help from Joe Newcomer and Cliff Mercer. Ning Hu ported Zheng (Geoffrey) Hua and Jim Beauchamp's piano synthesizer to Nyquist and also built NyqIDE, the Nyquist Integrated Development Environment for Windows. Dave Mowatt contributed the original version of NyquistIDE, the cross-platform interactive development environment. Dominic Mazzoni made a special version of Nyquist that runs within the Audacity audio editor, giving Nyquist a new interface and introducing Nyquist to many new users.

    Many others have since contributed to Nyquist. Chris Tchou and Morgan Green worked on the Windows port. Eli Brandt contributed a number of filters and other synthesis functions. Pedro J. Morales, Eduardo Reck Miranda, Ann Lewis, and Erich Neuwirth have all contributed nyquist examples found in the demos folder of the Nyquist distribution. Philip Yam ported some synthesis functions from Perry Cook and Gary Scavone's STK to Nyquist. Pedro Morales ported many more STK instruments to Nyquist. Dave Borel wrote the Dolby Pro-Logic encoding library and Adam Hartman wrote stereo and spatialization effects. Stephen Mangiat wrote the MiniMoog emulator. Phil Light recorded the drum samples and wrote drum machine software. The Xmusic library, particularly the pattern specification, was inspired by Rick Taube's Common Music. The functions for generating probability distributions were implemented by Andreas Pfenning.

    Starting with Version 3, Nyquist supports a version of SAL, providing an alternative to Lisp syntax. SAL was designed by Rick Taube, and the SAL implementation in Nyquist is based on Taube's original implementation as part of his Common Music system.

    The current NyquistIDE includes contributions from many. Chris Yealy and Derek D'Souza implemented early versions of the envelope editor. Daren Makuck and Michael Rivera wrote the original equalizer editor. Priyanka Raghavan implemented the sound browser. Dmitry Portnoy wrote the original "UPIC" editor.

    Many others have made contributions, offered suggestions, and found bugs. If you were expecting to find your name here, I apologize for the omission, and please let me know.

    I also wish to acknowledge support from CMU, Yamaha, and IBM for this work.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/home.html0000644000175000000620000000053211466723256014562 0ustar stevestaffNyquist Reference Manual <body><p>This browser does not support frames. <p><a href=title.html>The no-frames version is here.</a> </body> nyquist-3.05/doc/part11.html0000644000175000000620000012047211537432671014745 0ustar stevestaffMIDI, Adagio, and Sequences Previous Section | Next Section | Table of Contents | Index | Title Page

    MIDI, Adagio, and Sequences

    Nyquist includes facilities to read and write MIDI files as well as an ASCII text-based score representation language, Adagio. XLISP and Nyquist can be used to generate MIDI files using compositional algorithms. (See also Section "Xmusic and Algorithmic Composition".) A tutorial on using the Adadio representation and MIDI can be found in demos/midi_tutorial.htm. The Adagio language is described below. Adagio was originally developed as part of the CMU MIDI Toolkit, which included a program to record and play MIDI using the Adagio representation. Some of the MIDI features of Adagio may not be useful within Nyquist.

    Nyquist offers a number of different score representations, and you may find this confusing. In general, MIDI files are a common way to exchange music performance data, especially with sequencers and score notation systems. The demos/midi_tutorial.htm examples show how to get the most precise control when generating MIDI data. Adagio is most useful as a text-based score entry language, and it is certainly more compact than Lisp expressions for MIDI-like data. The Xmusic library (Chapter "Xmusic and Algorithmic Composition") is best for algorithmic generation of music and score manipulation. There are functions to convert between the Adagio, MIDI sequence data, and Xmusic score representations.

    Adagio is an easy-to-use, non-procedural notation for scores. In Adagio, text commands are used to specify each note. If you are new to Adagio, you may want to glance at the examples in Section "Examples" starting on page "Examples" before reading any further.

    A note is described in Adagio by a set of attributes, and any attribute not specified is "inherited" from the previous line. Attributes may appear in any order and must be separated by one or more blanks. An attribute may not contain any blanks. The attributes are: time, pitch, loudness, voice number, duration, and articulation.

    Adagio has been used to program a variety of hardware and software synthesizers, and the Adagio compiler can be easily adapted to new environments. Although not originally intended for MIDI, Adagio works quite well as a representation for MIDI scores. Adagio has been extended to allow MIDI controller data such as modulation wheels, pitch bend, and volume, MIDI program commands to change timbre, and System Exclusive messages.

    A note command in Adagio must be separated from other notes. Usually, notes are distinguished by writing each one on a separate line. Notes can also be separated by using a comma or semicolon as will be described below.

    Besides notes, there are several other types of commands:

    1. An asterisk (*) in column one (or immediately after a comma, semicolon, or space) indicates that the rest of the line is a comment. The line is ignored by Adagio, and is therefore a good way to insert text to be read by people. Here are some examples:
      * This is a comment.
      T150 G4  * This is a comment too!
      T150 G4  ;* So is this.
      
    2. An empty command (a blank line, for example) is ignored as if it were a comment (Footnote 6) .
    3. An exclamation point (!) in column one (or immediately after a comma or semicolon) indicates a special command. A special command does not generate a note. Special commands follow the "!" with no intervening spaces and extend to the end of the line, for example:
      !TEMPO 100
      
    4. Control change commands are used to control parameters like pitch bend, modulation, and program (timbre). Control change commands can be specified along with notes or by themselves. A command that specifies control changes without specifying a pitch will not produce a note.

    Adagio is insensitive to case, thus "A" is equivalent to "a", and you can mix upper and lower case letters freely.

    Specifying Attributes

    A note is indicated by a set of attributes. Attributes are indicated by a string of characters with no intervening spaces because spaces separate attributes. The attributes are described below.

    The default unit of time is a centisecond (100^(th)'s), but this can be changed to a millisecond (1000^(th)'s) using the !MSEC command and reset to centiseconds with !CSEC (see Section "Time Units and Resolution"). In the descriptions below, the term "time unit" will be used to mean whichever convention is currently in effect.

    Time

    The time attribute specifies when to start the note. A time is specified by a "T" followed by a number representing time units or by a duration (durations are described below). Examples:
    T150	** 1.5 sec (or .15 sec)
    TQ3	** 3 quarter note's duration
    
    If no time is specified, the default time
    is the sum of the time and duration attributes of the previous note. (But see Section "Next Time".) Time is measured relative to the time of the most recent Tempo or Rate command. (See the examples in Section "Examples" for some clarification of this point.)

    Pitch

    The pitch attribute specifies what frequency to produce. Standard scale pitches are named by name, using S for sharp, F for flat, and (optionally) N for natural. For example, C and CN represent the same pitch, as do FS and GF (F sharp and G flat). Note that there are no bar lines, and accidentals to not carry forward to any other notes as in common practice notation.

    Octaves are specified by number. C4 is middle C, and B3 is a half step lower. F5 is the top line of the treble clef, etc. (Adagio octave numbering follows the ISO standard, but note that this is not universal. In particular, Yamaha refers to middle C as C3.) Accidentals can go before or after the octave number, so FS3 and F3S have the same meaning.

    An alternate notation for pitch is Pn, where n is an integer representing the pitch. Middle C (C4) is equivalent to P60, CS4 is P61, etc.

    If you do not specify an octave, Adagio will choose one for you. This is done by picking the octave that will make the current pitch as close to the previous pitch as possible. In the case of augmented fourths or diminished fifths, there are two equally good choices. Adagio chooses the lower octave.

    Duration

    Duration is specified by a letter indicating a number of beats, followed by one or several modifiers. The basic duration codes are:
    W (whole, 4 beats),
    H
    (half, 2 beats),
    Q
    (quarter, 1 beat),
    I
    (eighth, 1/2 beat),
    S
    (sixteenth, 1/4 beat),
    %
    (thirtysecond, 1/8 beat), and
    ^
    (sixtyfourth, 1/16 beat).
    Note that E is a pitch, so eighth-notes use the duration code I. The default tempo is 100 beats per minute (see Section "Tempo"). These codes may be followed by a T (triplet), indicating a duration of 2/3 the normal. A dot (.) after a duration code extends it by half to 3/2 the normal. An integer after a note multiplies its duration by the indicated value (the result is still just one note). Finally, a slash followed by an integer divides the duration by the integer. Like all attributes, duration attributes may not have embedded spaces. Examples:
    Q1 beat (quarter note)
    QT2/3 beat (quarter triplet)
    W.6 beats(dotted whole note)
    ST61 beat (6 sixteenth triplets)
    H510 beats(5 half notes)
    Q3/73/7 beats
    A duration may be noted by Un
    , where n is an integer indicating 100^(th)'s of a second (or 1000^(th)'s), see Section "Time Units and Resolution". For example, U25 is twenty-five time units.

    Durations may be combined using a plus sign:

    Q+IT	    ** a quarter tied to an eighth triplet
    Q/7+W+Q2/7  ** a 7th beat tied to a whole tied to 2/7th beat
    Q+U10	    ** a quarter plus 10 time units
    

    Next Time

    The time of the next command (the next command in the Adagio program text) is normally the time of the current note command plus the duration of the current note. This can be overridden by a field consisting of the letter N followed by a number indicating time units, or followed by a duration as described above. The next note will then start at the time of the current note plus the duration specified after N. If the next note has an explicit time attribute (T), then the specified time will override the one based on the previous note. Examples:
    N0	** start the next note at the same time as this one
    N50	** start the next note 0.5 seconds after this one
    NQT	** start the next note 2/3 beat after the current one
    NU10+Q  ** start after 0.1 seconds plus a quarter
    
    A comma has an effect similar to N0 and is explained in Section
    "Multiple Notes Per Line". Articulation effects such as staccato can be produced using N, but it is more convenient to use the articulation attribute described in Section "Articulation".

    Rest

    Rests are obtained by including the field R in a note command. The effect of an R field is to omit the note that would otherwise occur as the result of the current note command. In all other respects, the command is processed just like any other line. This means that attributes such as duration, loudness, and pitch can be specified, and anything specified will be inherited by the note in the next command. Normally, a rest will include just R and a duration. The fact that a note command specifies a rest is not inherited. For example:
    R H	** a half (two beat) rest
    RH	** illegal, R must be separated from H by space(s)
    
    Because some synthesizers (e.g. a DX7
    ) cannot change programs (presets) rapidly, it may be desirable to change programs in a rest so that the synthesizer will be ready to play by the end of the rest. See Section "Timbre (MIDI Program)" for an example.

    Articulation

    Articulation in Adagio refers to the percentage of time a note is on relative to the indicated duration. For example, to play a note staccato, you would normally play the note about half of its indicated duration. In Adagio, articulation is indicated by # followed by an integer number indicating a percentage. The articulation attribute does not affect the time of the next command. This example plays two staccato quarter notes:
    C Q #50
    D
    
    To produce overlapping notes, the articulation may be greater than 100.

    Be aware that overlapping notes on the same pitch can be a problem for some synthesizers. The following example illustrates this potential problem:

    !TEMPO 60
    C Q #160   * starts at time 0,   ends at 1.6 sec
    D I        * starts at time 1,   ends at 1.8 sec
    C Q        * starts at time 1.5, ends at 3.1 sec?
    
    At one beat per second (tempo 60), these three notes will start at times 0, 1, and 1.5 seconds, respectively. Since these notes have an articulation of 160, each will be on 160% of its nominal duration, so the first note (C) will remain on until 1.6 seconds. But the third note (another C) will start at time 1.5 seconds. Thus, the second C will be started before the first one ends. Depending on the synthesizer, this may cancel the first C or play a second C in unison. In either case, a note-off message will be sent at time 1.6 seconds. If this cancels the second C, its actual duration will be 0.1 rather than 1.6 seconds as intended. A final note-off will be sent at time 3.1 seconds.

    Loudness

    Loudness is indicated by an L followed by a dynamic marking from the following: PPP, PP, P, MP, MF, F, FF, FFF. Alternatively, a number from 1 to 127 may be used. The loudness attribute is the MIDI note velocity. (Note that a MIDI velocity of 0 means "note-off," so the minimum loudness is 1.) The dynamic markings are translated into numbers as follows:
    Lppp20Lmf58
    Lpp26Lf75
    Lp34Lff98
    Lmp44Lfff127

    Voice

    The voice attribute tells which of the 16 MIDI channels to use for the note. The voice attribute consists of a V followed by an integer from 1 (the default) to 16. There is a limit to how many notes can be played at the same time on a given voice (MIDI channel). Since the limit depends upon the synthesizer, Adagio cannot tell you when you exceed the limit. Similarly, Adagio cannot tell whether your synthesizer is set up to respond to a given channel, so there is no guarantee that what you write will actually be heard.

    Timbre (MIDI Program)

    A MIDI program (synthesizer preset) can be selected using the attribute Zn, where n is the program number (from 1 to 128). Notice that in MIDI, changing the program on a given channel will affect all notes on that channel and possibly others. Adagio treats MIDI program changes as a form of control change. For many synthesizers, you will not be able to change programs at the start of a note or during a note. Change the program during a rest instead. For example:
    R I Z23 V4	** change MIDI channel 4 to program 23 during rest
    A4		** play a note on channel 4
    
    Check how your synthesizer interprets program numbers. For example, the cartridge programs on a DX7 can be accessed by adding 32 to the cartridge program number. Cartridge program number 10 is specified by Z42.

    As in MIDI, the Adagio timbre is a property of the voice (MIDI channel), so the timbre will not be inherited by notes on a different channel; to change the timbre on multiple voices (channels), you must explicitly notate each change.

    Tempo

    The length of a beat may be changed using a Tempo command:
    !TEMPO n
    
    where n indicates beats per minute. The exclamation mark tells Adagio that this is a special command line rather than a note definition. A special command takes the place of a note specification. No other attributes should be written on a line with a special command. The !TEMPO command is associated with a time, computed as if the !TEMPO command were a note. The time
    attribute (T) of all succeeding notes is now measured relative to the time of the !TEMPO command. The new tempo starts at the !TEMPO command time and affects all succeeding notes. Durations specified in time units (for example U58, N15) are not affected by the !TEMPO command, and numerical times (for example T851) are computed relative to the time of the last !TEMPO command.

    The !TEMPO command is fairly clever about default durations. If the last duration specified before the !TEMPO command is symbolic (using one of ^,%, S, I, Q, H, or W ), then the default duration for the node after the !TEMPO command will be modified according to the tempo change. Consider the following tempo change:

    !TEMPO 60
    A4 H
    !TEMPO 120
    G
    
    In this example, the first note will last 2 seconds (2 beats at 60 beats per minute). The second note inherits the duration (H) from the first note, but at 120 beats per minute, the second note will last only 1 second. If the duration had been specified U200 (also a duration of 2 seconds), the second note would also last 2 seconds because the !TEMPO command does not affect times or durations specified numerically in time units. If the duration is the sum of a symbolic and a numeric specification, the inherited duration after a !TEMPO command is undefined.

    Rate

    The !RATE command scales all times including those specified in hundredths of seconds. A rate of 100 means no change, 200 means twice as fast, and 50 means half as fast. For example, to make a piece play 10% faster, you can add the following command at the beginning of the score:
    !RATE 110
    
    !RATE and !TEMPO commands combine, so
    !RATE 200
    !TEMPO 70
    
    will play 70 beats per minute at double the normal speed, or 140 beats per minute. Like !TEMPO, the time of the !RATE command is added to the time attribute of all following notes up to the next !TEMPO or !RATE command.

    Two !RATE commands do not combine, so a !RATE command only affects the rate until the next !RATE command.

    Although !TEMPO and !RATE can occur in the middle of a note (using N, T, etc.) they do not affect a note already specified. This property allows multiple tempi to exist simultaneously (see Section "Multiple Tempi").

    Default Attributes

    If an attribute is omitted, the previous one is used by default (with the exception of the time attribute). The default values for the first note, which are inherited by succeeding notes until something else is specified, are given below in Adagio notation:
    Time T0
    Pitch C4
    Duration Q
    Articulation #100
    Loudness LFFF
    Voice V1
    Tempo !TEMPO 100
    Rate !RATE 100
    Control changes (including timbre or MIDI program, specified by Z) have no default value and are only sent as specified in the score.

    Important: the rules for determining when a command will play a note are as follows (and this has changed slightly from previous versions):

    1. If a special (!) command or nothing is specified, e.g. a blank line, do not play a note.
    2. If R (for "rest") is specified, do not play a note.
    3. Otherwise, if a pitch is specified, do play a note.
    4. Otherwise, if no control changes (or program changes) are specified (so this is a command with non-pitch attributes and no control changes), do play a note.
    Another way to say this is "Special commands and commands with rests (R) do not play notes. Otherwise, play a note if a pitch is specified or if no control is specified."

    Examples

    The following plays the first two bars of "Happy Birthday". Note that Adagio knows nothing of bar lines, so the fact that the first note occurs on beat 3 or that the meter is three-four is of no consequence:
    *Example 1 ** Happy Birthday tune (C major)
    !TEMPO 120
    G4 I. LF
    G4 S
    A4 Q
    G4
    C5
    B4 H
    
    The time attribute for the first note is zero (0). The second note will occur a dotted eighth later, etc. Notice that no timbre or rate was specified. Adagio will provide reasonable default values of 1 and 100, respectively.

    The following example plays the first four bars of an exercise from Bartok's Mikrokosmos (Vol. 1, No. 12). An extra quarter note is inserted at the beginning of each voice in order to allow time to change MIDI programs. The right hand part is played on voice (MIDI channel) 1 and the left hand part on voice 2. Notice the specification of the time attribute to indicate that voice 2 starts at time 0. Also, default octaves are used to reduce typing.

    *Example 2 ** Bartok
    *voice 1, right hand
    R Q Z10 V1   ** extra rest for program change
    A4 H
    B Q
    C
    D H
    C
    D Q
    C
    B
    A
    B
    C
    D
    R
    

    *voice 2, left hand T0 R Q Z15 V2 ** extra rest for program change G3 H F Q E D H E D Q E F G F E D R

    The next example is the same piece expressed in a different manner, illustrating the interaction between the !TEMPO command and the time attribute. Recall that the time attribute is measured relative to the time of the last !TEMPO command:

    *Example 3 ** 4 measures in 2 sections
    !Tempo 100
    *Voice 1, Measures 1 & 2
    R Q Z10 V1
    A4 H
    B Q
    C
    D H
    C
    

    *Voice 2, Measures 1 & 2 T0 R Q Z15 V2 G3 H F Q E D H E H

    !TEMPO 100 *Voice 1, Measures 3 & 4 * note that Z10 is still in effect for V1 V1 D4 Q C B A B C D R

    *Voice 2, Measures 3 & 4 T0 V2 D3 Q E F G F E D R

    The piece is written in 4 sections. The first plays a rest followed by two measures, starting at time 0. The next section changes the time back to zero and plays two measures of the left hand part (voice 2). The next command (!TEMPO 100) sets the tempo to 100 (it already is) and sets the reference time to be two measures into the piece. Therefore, the next note (D4) will begin measure 3. The D3 that begins the last group of notes has a T0 attribute, so it will also start at measure 3. Notice how the !TEMPO command can serve to divide a piece into sections.

    The last example will show yet another way to express the same piece of music using the "Next" attribute. Only the first bar of music is given.

    *Example 4 ** use of the Next attribute
    !Tempo 100
    R Q Z10 V1 N0
    R Q Z15 V2
    

    A4 H V1 N0 G3 V2

    B4 Q V1 N0 F3 V2

    C4 Q V1 N0 E3 V2

    Here, each pair of lines represents two simultaneous notes. The N0 attribute forces the second line to start at the same time as the first line of each pair. Because of the large intervals, octave numbers (3 and 4) are necessary to override the default octave for these pitches.

    Advanced Features

    Beyond the simple notation described above, Adagio supports a number of features. (See also the next chapter.)

    Time Units and Resolution

    The default time unit is 10ms (ten milliseconds or one centisecond or 100^(th) of a second), but it is possible to change the basic unit to 1ms, or 1000^(th) of a second. The time unit can be specified by:
    !CSECcentisecond time units = 100^(th)
    !MSEC
    millisecond time units = 1000^(th)
    The time unit remains in effect until the next !CSEC or !MSEC command.

    Multiple Notes Per Line

    Notes can be separated by commas or semicolons as well as by starting a new line. A comma is equivalent to typing N0 and starting a new line. In other words, the next note after a comma will start at the same time as the note before the comma. In general, use commas to separate the notes of a chord.

    A semicolon is equivalent to starting a new line. In general, use semicolons to group notes in a melody. Here is yet another rendition of the Bartok:

    *Example 5 ** use of semicolons
    !Tempo 100
    R Q Z10 V1
    A4 H; B Q; C; D H; C; D Q; C; B; A; B; C; D; R
    

    T0 R Q Z15 V2 G3 H; F Q; E; D H; E; D Q; E; F; G; F; E; D; R

    This example is similar to Example 2, except semicolons are used. Note how semicolons make the two lines of music stand out. The next example is similar to Example 4, except commas are used and four bars are notated. The music below is treated as a sequence of 2-note chords, with each chord on a separate line:
    *Example 6 ** use of commas
    !Tempo 100
    R Q Z10 V1, R Q Z15 V2
    A4 H V1, G3 V2
    B4 Q V1, F3 V2
    C4   V1, E3 V2
    D4 H V1, D3 V2
    C4   V1, E3 V2
    D4 Q V1, D3 V2
    C4   V1, E3 V2
    B4   V1, F3 V2
    A4   V1, G3 V2
    B4   V1, F3 V2
    C4   V1, E3 V2
    D4   V1, D3 V2
    R
    

    Control Change Commands

    Any control change can be specified using the syntax "~n(v)", where n is the controller number (0 - 127), and v is the value. In addition, Adagio has some special syntax for some of the commonly used control changes (note that Pitch bend, Aftertouch, and MIDI Program Change are technically not MIDI control changes but have their own special message format and status bytes):

    KPortamento switch

    MModulation wheel

    OAftertouch

    XVolume

    YPitch bend

    ZProgram Change

    The letter listed beside each control function is the Adagio command letter. For example, M23 is the command for setting the modulation wheel to 23. Except for pitch bend, the portamento switch, and MIDI Program Change, all values range from 0 to 127. Pitch bend is "off" or centered at 128, and has a range from 0 to 255 (MIDI allows for more precision, but Adagio does not). Turn on portamento with K127 and off with K0. Programs are numbered 1 to 128 to correspond to synthesizer displays.

    About volume: Midi volume is just a control, and the Midi standard does not say what it means. Typically it does what the volume pedal does; that is, it scales the amplitude in a continuously changeable fashion. In contrast, Midi velocity, which is controlled by the L (loudness) attribute, is part of a Midi note-on command and is fixed for the duration of the note. Typically, these two ways of controlling loudness and amplitude operate independently. In some low-cost synthesizers the numbers seem to be added together internally and volume changes are ignored after the note starts.

    About pitch bend: Midi pitch bend is a number from 0 to 16383, where 8192 is the center position. To convert to Midi, Adagio simply multiplies your number by 64, giving values from 0 to 16320. Note that Y128 translates exactly to 8192. The meaning of pitch bend depends upon your synthesizer and its setting. Most synthesizers let you specify a "pitch bend range." A range of one semitone means that Y255 will produce a bend of approximately one semitone up, and Y0 will bend one semitone down. If the range is 12 semitones, then the same Y255 will bend an octave. Typically, pitch bend is exponential, so each increment in the pitch bend value will bend an equal number of cents in pitch.

    Control changes can be part of a note specification or independent. In the following example, a middle C is played with a modulation wheel setting of 50 and a pitch bend of 120. Then, at 10 unit intervals, the pitch bend is decreased by 10. The last line sets the portamento time (controller 5) to 80:

    *Example 7
    C4 LMF M50 Y120 U100 N10
    Y110 N10; Y100 N10; Y90 N10; Y80 N10
    Y70 N10; Y60 N10; Y50 N10
    ~5(80)
    

    See Section "Default Attributes" on page "Default Attributes" for rules on whether or not a command will play a note.

    Multiple Tempi

    Writing a piece with multiple tempi requires no new commands; you just have to be clever in the use of Tempo and Time. The following plays a 7 note diatonic scale on voice 1, and a 12 note chromatic scale on voice 2:
    *Example 8 ** multiple tempi
    !TEMPO 70
    V1 C4; D; E; F; G; A; B
    T0 R N0
    

    !TEMPO 120 V2 C4; CS; D; DS; E; F; FS; G; GS; A; AS; B

    !TEMPO 100 V1 C5, V2 C5

    The third line plays the 7-note diatonic scale on voice 1. The next line contains the tricky part: notice that the time is set back to zero, there is a rest, and a next (N) attribute is used to specify that the next default time will be at the same time as the current one. This is tricky because a !TEMPO command cannot have a time (T0) attribute, and a T0 by itself would create a note with a duration. T0 R N0 says: "go to time 0, do not play a note, and do not advance the time before the next command". Thus, the time of the !TEMPO 120 command is zero. After the 12 note scale, the tempo is changed to 100 and a final note is played on each voice. A little arithmetic will show that 7 notes at tempo 70 and 12 notes at tempo 120 each take 6 seconds, so the final notes (C5) of each scale will happen at the same time.

    MIDI Synchronization

    The Adagio program (but not Nyquist) can synchronize with external devices using MIDI real time messages. Thus, Adagio has a !CLOCK command. This command is currently of no use to Nyquist users but is documented here for completeness (it's part of the language syntax even if it does not do anything).

    Since Adagio supports multiple tempi, and Midi clock is based on beats, it is necessary to be explicit in the score about where the clock should start and what is the duration of a quarter note. The !CLOCK command in Adagio turns on a 24 pulse-per-quarter (PPQ) clock at the current tempo and time:

    !TEMPO 100
    !CLOCK
    
    A !CLOCK command must also be inserted for each tempo change that is to be reflected in the Midi clock. Typically, each !TEMPO command will be followed by a !CLOCK command. Clock commands and thus tempo changes can take place at arbitrary times. It is assumed that tempo changes on an exact 24^(th) of a beat subdivision (for example, exactly on a beat). If not, the tempo change will take place on the nearest exact 24^(th) of a beat subdivision. This may be earlier or later than the requested time.

    System Exclusive Messages

    Adagio has a definition facility that makes it possible to send system exclusive parameters. Often, there are parameters on Midi synthesizers that can only be controlled by system exclusive messages. Examples include the FM ratio and LFO rate on a DX7 synthesizer. The following example defines a macro for the DX7 LFO rate and then shows how the macro is used to set the LFO rate for a B-flat whole note in the score. The macro definition is given in hexadecimal, except v is replaced by the channel (voice) and %1 is replaced by the first parameter. A macro is invoked by writing "~" followed by the macro name and a list of parameters:
    !DEF LFO F0 43 0v 01 09 %1 F7
    Bf5 W ~LFO(25)
    

    In general, the !DEF command can define any single MIDI message including a system exclusive message. The message must be complete (including the status byte), and each !DEF must correspond to just one message. The symbol following !DEF can be any name consisting of alphanumeric characters. Following the name is a hexadecimal string (with optional spaces), all on one line. Embedded in the string may be the following special characters:

    v
    Insert the 4-bit voice (MIDI channel) number. If v occurs in the place of a high-order hexadecimal digit, replace v with 0v so that the channel number is always placed in the low-order 4 bits of a data byte. In other words, v is padded if necessary to fall into the low-order bits.

    %n
    Insert a data byte with the low-order 7 bits of parameter number n. Parameters are numbered 1 through 9. If the parameter value is greater than 127, the high-order bits are discarded.

    ^n
    Insert a data byte with bits 7 through 13 of parameter number n. In other words, shift the value right 7 places then clear all but the first 7 bits. Note that 14-bit numbers can be encoded by referencing the same parameter twice; for example, %4^4 will insert the low-order followed by the high-order parts of parameter 4 into two successive data bytes.

    Parameters are separated by commas, but there may be no spaces. The maximum number of parameters allowed is 9. Here is an example of definitions to send a full-resolution pitch bend command and to send a system exclusive command to change a DX7 parameter (Footnote 7) .

    * Define macro for pitch bend commands:
    !DEF bend Ev %1 ^1
    

    A ~bend(8192) ** 8192 is "pitch bend off"

    * Change the LFO SPEED: * SYSEX = F0, Yamaha = 43, Substatus/Channel = 1v, * Group# = 01, Parameter# = 9, Data = 0-99, EOX = F7 !DEF lfospeed F0 43 1v 01 09 %1 F7

    * now use the definitions: G4 ~bend(7567) N40 ~lfospeed(30) N35

    Control Ramps

    The !RAMP command can specify a smooth control change from one value to another. It consists of a specification of the starting and ending values of some control change, a duration specifying how often to send a new value, and a duration specifying the total length of the ramp.
    !RAMP X10 X100 Q W2
    !RAMP ~23(10) ~23(50) U20 W
    !RAMP ~lfo(15) ~lfo(35) U10
    
    The first line says to ramp the volume control (controller number 7) from 10 to 100, changing at each quarter note for the duration of two whole notes. The second line says to ramp controller number 23 from value 10 to value 50, sending a new control change message every 20 time units. The overall duration of the ramp should be equivalent to a whole note (W). As shown in the third line, even system exclusive messages controlled by parameters can be specified. If the system exclusive message has more than one parameter, only one parameter may be "ramped"; the others must remain the same. For example, the following would ramp the second parameter:
    !RAMP ~mysysex(4,23,75) ~mysysex(4,100,75) U10 W
    

    A rather curious and extreme use of macros and ramps is illustrated in the following example. The noteon macro starts a note, and noteoff ends it. Ramps can now be used to emit a series of notes with changing pitches or velocities. Since Adagio has no idea that these macros are turning on notes, it is up to the programmer to turn them off!

    !DEF noteon 9v %1 %2
    !DEF noteoff 8v %1 %2
    ~noteon(48,125)
    ~noteoff(48,126)
    * turn on some notes
    !RAMP ~noteon(36,125) ~noteon(60,125) Q W NW
    * turn them off
    !RAMP ~noteoff(60,50) ~noteoff(36,50) Q W NW
    

    The !End Command

    The special command !END marks the end of a score. Everything beyond that is ignored, for example:
    * this is a score
    C; D; E; F; G W
    !END
    since the score has ended, this text will be ignored
    

    Calling C Routines

    It is possible to call C routines from within Adagio scores when using specially linked versions, but this feature is disabled in Nyquist. The syntax is described here for completeness.

    The !CALL command calls a C routine that can in turn invoke a complex sequence of operations. Below is a call to a trill routine, which is a standard routine in Adagio. The parameters are the base pitch of the trill, the total duration of the trill, the interval in semitones, the duration of each note of the trill, and the loudness. Notice that both numbers and Adagio notation can be used as parameters:

    !CALL trill(A5,W,2,S,Lmf)  T278 V1
    
    The parameter list should have no spaces, and parameters are separated by commas. Following the close parenthesis, you may specify other attributes such as the starting time and voice as shown in the example above.

    A parameter may be an Adagio pitch specification, an Adagio duration, an Adagio loudness, a number, or an ASCII character within single quotes, e.g. 'a' is equivalent to 97 because 97 is the decimal encoding of "a" in ASCII.

    The !CALL may be followed by a limited set of attributes. These are time (T), voice (V), and next time (N). The !CALL is made at the current time if no time is specified, and the time of the next adagio command is the time of the !CALL unless a next time is specified. In other words, the default is N0.

    Setting C Variables

    In addition to calling C routines, there is another way in which scores can communicate with C. As with !CALL, specific C code must be linked before these commands can be used, and this is not supported in Nyquist. The !SETI command sets an integer variable to a value, and the !SETV command sets an element of an integer array. For example, the next line sets the variable delay to 200 and sets transposition[5] to -4 at time 200:
    !SETI delay 200
    !SETV transposition 5 -4  T200
    
    As with the !CALL command, these commands perform their operations at particular times according to their place in the Adagio score. This makes it very easy to implement time-varying parameters that control various aspects of an interactive music system.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/linear-fig.gif0000644000175000000620000000176011466723256015454 0ustar stevestaffGIF87a w!Software: Microsoft Office, ڋ޼gH扦ȈL׶,LvĢ J9j? I0Nc_u:kX2'hx8Xh(i2yQىy9%zEJWfJ[3+[u;{K|1[XOom݅/Bv $kAchaB\QDkcG2؈pr$(yD/ lXΛ)v)$j(RBY5]J(4OWV 2QOVA$˝YcEKc *x 'yKpOk_ě1513@YFfb+w,hգB:/նmڻ#MGr8ʿ1F&ڍ4Xx-><}O>5eq?-ogxpBC GE1xR܄.c!2d8~2bI ى%x("@0H7bEF s=6:L ]D\HG d$0@RԑGV e4E%Bf& m9]Xpy.9g|IʞQg١Ihb26aB:ifɥi1&yiYa ħƐꝂnߪ*)lojYka@cðͣlr:F'a+|n[*Ǵ.fHhn[TnCB]ދoo pLp۴**|" :lmȻ~lv X6ؗ}lBIf$k 'L5&25{pL&1c۳V#e셠c;kFĴ;nyquist-3.05/doc/part15.html0000644000175000000620000012464511537432671014757 0ustar stevestaffNyquist Libraries Previous Section | Next Section | Table of Contents | Index | Title Page

    Nyquist Libraries

    Nyquist is always growing with new functions. Functions that are most fundamental are added to the core language. These functions are automatically loaded when you start Nyquist, and they are documented in the preceding chapters. Other functions seem less central and are implemented as lisp files that you can load. These are called library functions, and they are described here.

    To use a library function, you must first load the library, e.g. (load "pianosyn") loads the piano synthesis library. The libraries are all located in the lib directory, and you should therefore include this directory on your XLISPPATH variable. (See Section "Introduction and Overview".) Each library is documented in one of the following sections. When you load the library described by the section, all functions documented in that section become available.

    Piano Synthesizer

    The piano synthesizer (library name is pianosyn.lsp) generates realistic piano tones using a multiple wavetable implementation by Zheng (Geoffrey) Hua and Jim Beauchamp, University of Illinois. Please see the notice about acknowledgements that prints when you load the file. Further informations and example code can be found in demos/piano.htm. There are several useful functions in this library:
    piano-note(duration, step, dynamic) [SAL]
    (piano-note duration step dynamic) [LISP]
    Synthesizes a piano tone. Duration is the duration to the point of key release, after which there is a rapid decay. Step is the pitch in half steps, and dynamic is approximately equivalent to a MIDI key velocity parameter. Use a value near 100 for a loud sound and near 10 for a soft sound.

    piano-note-2(step, dynamic) [SAL]
    (piano-note-2 step dynamic) [LISP]
    Similar to piano-note except the duration is nominally 1.0.

    piano-midi(midi-file-name) [SAL]
    (piano-midi midi-file-name) [LISP]
    Use the piano synthesizer to play a MIDI file. The file name (a string) is given by midi-file-name.

    piano-midi2file(midi-file-name, sound-file-name) [SAL]
    (piano-midi2file midi-file-name sound-file-name) [LISP]
    Use the piano synthesizer to play a MIDI file. The MIDI file is given by midi-file-name and the (monophonic) result is written to the file named sound-file-name.

    Dymanics Compression

    To use these functions, load the file compress.lsp. This library implements a compressor originally intended for noisy speech audio, but usable in a variety of situations. There are actually two compressors that can be used in series. The first, compress, is a fairly standard one: it detects signal level with an RMS detector and uses table-lookup to determine how much gain to place on the original signal at that point. One bit of cleverness here is that the RMS envelope is "followed" or enveloped using snd-follow, which does look-ahead to anticipate peaks before they happen.

    The other interesting feature is compress-map, which builds a map in terms of compression and expansion. For speech, the recommended procedure is to figure out the noise floor on the signal you are compressing (for example, look at the signal where the speaker is not talking). Use a compression map that leaves the noise alone and boosts signals that are well above the noise floor. Alas, the compress-map function is not written in these terms, so some head-scratching is involved, but the results are quite good.

    The second compressor is called agc, and it implements automatic gain control that keeps peaks at or below 1.0. By combining compress and agc, you can process poorly recorded speech for playback on low-quality speakers in noisy environments. The compress function modulates the short-term gain to to minimize the total dynamic range, keeping the speech at a generally loud level, and the agc function rides the long-term gain to set the overall level without clipping.

    compress-map(compress-ratio, compress-threshold, expand-ratio, expand-ratio, limit: limit, transition: transition) [SAL]
    (compress-map compress-ratio compress-threshold expand-ratio expand-ratio :limit limit :transition transition]) [LISP]
    Construct a map for the compress function. The map consists of two parts: a compression part and an expansion part. The intended use is to compress everything above compress-threshold by compress-ratio, and to downward expand everything below expand-ratio by expand-ratio. Thresholds are in dB and ratios are dB-per-dB. 0dB corresponds to a peak amplitude of 1.0 or rms amplitude of 0.7 If the input goes above 0dB, the output can optionally be limited by setting limit: (a keyword parameter) to T. This effectively changes the compression ratio to infinity at 0dB. If limit: is nil (the default), then the compression-ratio continues to apply above 0dB.

    Another keyword parameter, transition:, sets the amount below the thresholds (in dB) that a smooth transition starts. The default is 0, meaning that there is no smooth transition. The smooth transition is a 2nd-order polynomial that matches the slopes of the straight-line compression curve and interpolates between them.

    It is assumed that expand-threshold <= compress-threshold <= 0 The gain is unity at 0dB so if compression-ratio > 1, then gain will be greater than unity below 0dB.

    The result returned by this function is a sound for use in the shape function. The sound maps input dB to gain. Time 1.0 corresponds to 0dB, time 0.0 corresponds to -100 dB, and time 2.0 corresponds to +100dB, so this is a 100hz "sample rate" sound. The sound gives gain in dB.

    db-average(input) [SAL]
    (db-average input) [LISP]
    Compute the average amplitude of input in dB.

    compress(input, map, rise-time, fall-time [, lookahead]) [SAL]
    (compress input map rise-time fall-time [lookahead)] [LISP]
    Compress input using map, a compression curve probably generated by compress-map (see above). Adjustments in gain have the given rise-time and fall-time. Lookahead tells how far ahead to look at the signal, and is rise-time by default.

    agc(input, range, rise-time, fall-time [, lookahead]) [SAL]
    (agc input range rise-time fall-time [lookahead]) [LISP]
    An automatic gain control applied to input. The maximum gain in dB is range. Peaks are attenuated to 1.0, and gain is controlled with the given rise-time and fall-time. The look-ahead time default is rise-time.

    Clipping Softener

    This library, in soften.lsp, was written to improve the quality of poorly recorded speech. In recordings of speech, extreme clipping generates harsh high frequency noise. This can sound particulary bad on small speakers that will emphasize high frequencies. This problem can be ameliorated by low-pass filtering regions where clipping occurs. The effect is to dull the harsh clipping. Intelligibility is not affected by much, and the result can be much more pleasant on the ears. Clipping is detected simply by looking for large signal values. Assuming 8-bit recording, this level is set to 126/127.

    The function works by cross-fading between the normal signal and a filtered signal as opposed to changing filter coefficients.

    soften-clipping(snd, cutoff) [SAL]
    (soften-clipping snd cutoff) [LISP]
    Filter the loud regions of a signal where clipping is likely to have generated additional high frequencies. The input signal is snd and cutoff is the filter cutoff frequency (4 kHz is recommended for speech).

    Graphical Equalizer

    There's nothing really "graphical" about this library (grapheq.lsp), but this is a common term for multi-band equalizers. This implementation uses Nyquist's eq-band function to split the incoming signal into different frequency bands. Bands are spaced geometrically, e.g. each band could be one octave, meaning that each successive band has twice the bandwidth. An interesting possibility is using computed control functions to make the equalization change over time.

    nband-range(input, gains, lowf, highf) [SAL]
    (nband-range input gains lowf highf) [LISP]
    A graphical equalizer applied to input (a SOUND). The gain controls and number of bands is given by gains, an ARRAY of SOUNDs (in other words, a Nyquist multichannel SOUND). Any sound in the array may be replaced by a FLONUM. The bands are geometrically equally spaced from the lowest frequency lowf to the highest frequency highf (both are FLONUMs).

    nband(input, gains) [SAL]
    (nband input gains) [LISP]
    A graphical equalizer, identical to nband-range with a range of 20 to 20,000 Hz.

    Sound Reversal

    The reverse.lsp library implements functions to play sounds in reverse.

    s-reverse(snd) [SAL]
    (s-reverse snd) [LISP]
    Reverses snd (a SOUND). Sound must be shorter than *max-reverse-samples*, which is currently initialized to 25 million samples. Reversal allocates about 4 bytes per sample. This function uses XLISP in the inner sample loop, so do not be surprised if it calls the garbage collector a lot and runs slowly. The result starts at the starting time given by the current environment (not necessarily the starting time of snd). If snd has multiple channels, a multiple channel, reversed sound is returned.

    s-read-reverse(filename, time-offset: offset, srate: sr, dur: dur, nchans: chans, format: format, mode: mode, bits: n, swap: flag) [SAL]
    (s-read-reverse filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag) [LISP]
    This function is identical to s-read (see "Sound File Input and Output"), except it reads the indicated samples in reverse. Like s-reverse (see above), it uses XLISP in the inner loop, so it is slow. Unlike s-reverse, s-read-reverse uses a fixed amount of memory that is independent of how many samples are computed. Multiple channels are handled.

    Time Delay Functions

    The time-delay-fns.lsp library implements chorus, phaser, and flange effects.

    phaser(snd) [SAL]
    (phaser snd) [LISP]
    A phaser effect applied to snd (a SOUND). There are no parameters, but feel free to modify the source code of this one-liner.

    flange(snd) [SAL]
    (flange snd) [LISP]
    A flange effect applied to snd. To vary the rate and other parameters, see the source code.

    stereo-chorus(snd) [SAL]
    (stereo-chorus snd) [LISP]
    A chorus effect applied to snd, a SOUND (monophonic). The output is a stereo sound. All parameters are built-in, but see the simple source code to make modifications.

    chorus(snd, maxdepth, depth, rate, saturation) [SAL]
    (chorus snd maxdepth depth rate saturation) [LISP]
    A chorus effect applied to snd. All parameters may be arrays as usual. The maxdepth is a FLONUM giving twice the maximum value of depth, which may be a FLONUM or a SOUND. The chorus is implemented as a variable delay modulated by a sinusoid running at rate Hz (a FLONUM). The sinusoid is scaled by depth and offset by maxdepth/2. The delayed signal is mixed with the original, and saturation gives the fraction of the delayed signal (from 0 to 1) in the mix. A reasonable choice of parameter values is maxdepth = 0.05, depth = 0.025, rate = 0.5, and saturation = 0.5.

    Multiple Band Effects

    The bandfx.lsp library implements several effects based on multiple frequency bands. The idea is to separate a signal into different frequency bands, apply a slightly different effect to each band, and sum the effected bands back together to form the result. This file includes its own set of examples. After loading the file, try f2(), f3(), f4(), and f5() to hear them.

    There is much room for expansion and experimentation with this library. Other effects might include distortion in certain bands (for example, there are commercial effects that add distortion to low frequencies to enhance the sound of the bass), separating bands into different channels for stereo or multi-channel effects, adding frequency-dependent reverb, and performing dynamic compression, limiting, or noise gate functions on each band. There are also opportunities for cross-synthesis: using the content of bands extracted from one signal to modify the bands of another. The simplest of these would be to apply amplitude envelopes of one sound to another. Please contact us (dannenberg@cs.cmu.edu) if you are interested in working on this library.

    apply-banded-delay(s, lowp, highp, num-bands, lowd, highd, fb, wet) [SAL]
    (apply-banded-delay s lowp highp num-bands lowd highd fb wet) [LISP]
    Separates input SOUND s into FIXNUM num-bands bands from a low frequency of lowp to a high frequency of highp (these are FLONUMS that specify steps, not Hz), and applies a delay to each band. The delay for the lowest band is given by the FLONUM lowd (in seconds) and the delay for the highest band is given by the FLONUM highd. The delays for other bands are linearly interpolated between these values. Each delay has feedback gain controlled by FLONUM fb. The delayed bands are scaled by FLONUM wet, and the original sound is scaled by 1 - wet. All are summed to form the result, a SOUND.

    apply-banded-bass-boost(s, lowp, highp, num-bands, num-boost, gain) [SAL]
    (apply-banded-bass-boost s lowp highp num-bands num-boost gain) [LISP]
    Applies a boost to low frequencies. Separates input SOUND s into FIXNUM num-bands bands from a low frequency of lowp to a high frequency of highp (these are FLONUMS that specify steps, not Hz), and scales the lowest num-boost (a FIXNUM) bands by gain, a FLONUM. The bands are summed to form the result, a SOUND.

    apply-banded-treble-boost(s, lowp, highp, num-bands, num-boost, gain) [SAL]
    (apply-banded-treble-boost s lowp highp num-bands num-boost gain) [LISP]
    Applies a boost to high frequencies. Separates input SOUND s into FIXNUM num-bands bands from a low frequency of lowp to a high frequency of highp (these are FLONUMS that specify steps, not Hz), and scales the highest num-boost (a FIXNUM) bands by gain, a FLONUM. The bands are summed to form the result, a SOUND.

    Granular Synthesis

    Some granular synthesis functions are implemented in the gran.lsp library file. There are many variations and control schemes one could adopt for granular synthesis, so it is impossible to create a single universal granular synthesis function. One of the advantages of Nyquist is the integration of control and synthesis functions, and users are encouraged to build their own granular synthesis functions incorporating their own control schemes. The gran.lsp file includes many comments and is intended to be a useful starting point. Another possibility is to construct a score with an event for each grain. Estimate a few hundred bytes per score event (obviously, size depends on the number of parameters) and avoid using all of your computer's memory.

    sf-granulate(filename, grain-dur, grain-dev, ioi, ioi-dev, pitch-dev, [file-start, file-end]) [SAL]
    (sf-granulate filename grain-dur grain-dev ioi ioi-dev pitch-dev [file-start file-end]) [LISP]
    Granular synthesis using a sound file named filename as the source for grains. Grains are extracted from a sound file named by filename by stepping through the file in equal increments. Each grain duration is the sum of grain-dur and a random number from 0 to grain-dev. Grains are then multiplied by a raised cosine smoothing window and resampled at a ratio between 1.0 and pitch-dev. If pitch-dev is greater than one, grains are stretched and the pitch (if any) goes down. If pitch-dev is less than one, grains are shortened and the pitch goes up. Grains are then output with an inter-onset interval between successive grains (which may overlap) determined by the sum of ioi and a random number from 0 to ioi-dev. The duration of the resulting sound is determined by the stretch factor (not by the sound file). The number of grains is the total sound duration (determined by the stretch factor) divided by the mean inter-onset interval, which is ioi + ioi-dev * 0.5. The grains are taken from equally-spaced starting points in filename, and depending on grain size and number, the grains may or may not overlap. The output duration will simply be the sum of the inter-onset intervals and the duration of the last grain. If ioi-dev is non-zero, the output duration will vary, but the expected value of the duration is the stretch factor. To achieve a rich granular synthesis effect, it is often a good idea to sum four or more copies of sf-granulate together. (See the gran-test function in gran.lsp.)

    MIDI Utilities

    The midishow.lsp library has functions that can print the contents fo MIDI files. This intended as a debugging aid.

    midi-show-file(file-name) [SAL]
    (midi-show-file file-name) [LISP]
    Print the contents of a MIDI file to the console.

    midi-show(the-seq [, out-file]) [SAL]
    (midi-show the-seq [out-file]) [LISP]
    Print the contents of the sequence the-seq to the file out-file (whose default value is the console.)

    Reverberation

    The reverb.lsp library implements artificial reverberation.

    reverb(snd, time) [SAL]
    (reverb snd time) [LISP]
    Artificial reverberation applied to snd with a decay time of time.

    DTMF Encoding

    The dtmf.lsp library implements DTMF encoding. DTMF is the "touch tone" code used by telephones.

    dtmf-tone(key, len, space) [SAL]
    (dtmf-tone key len space) [LISP]
    Generate a single DTMF tone. The key parameter is either a digit (a FIXNUM from 0 through 9) or the atom STAR or POUND. The duration of the done is given by len (a FLONUM) and the tone is followed by silence of duration space (a FLONUM).

    speed-dial(thelist) [SAL]
    (speed-dial thelist) [LISP]
    Generates a sequence of DTMF tones using the keys in thelist (a LIST of keys as described above under dtmf-tone). The duration of each tone is 0.2 seconds, and the space between tones is 0.1 second. Use stretch to change the "dialing" speed.

    Dolby Surround(R), Stereo and Spatialization Effects

    The spatial.lsp library implements various functions for stereo manipulation and spatialization. It also includes some functions for Dolby Pro-Logic panning, which encodes left, right, center, and surround channels into stereo. The stereo signal can then be played through a Dolby decoder to drive a surround speaker array. This library has a somewhat simplified encoder, so you should certainly test the output. Consider using a high-end encoder for critical work. There are a number of functions in spatial.lsp for testing. See the source code for comments about these.

    stereoize(snd) [SAL]
    (stereoize snd) [LISP]
    Convert a mono sound, snd, to stereo. Four bands of equalization and some delay are used to create a stereo effect.

    widen(snd, amt) [SAL]
    (widen snd amt) [LISP]
    Artificially widen the stereo field in snd, a two-channel sound. The amount of widening is amt, which varies from 0 (snd is unchanged) to 1 (maximum widening). The amt can be a SOUND or a number.

    span(snd, amt) [SAL]
    (span snd amt) [LISP]
    Pan the virtual center channel of a stereo sound, snd, by amt, where 0 pans all the way to the left, while 1 pans all the way to the right. The amt can be a SOUND or a number.

    swapchannels(snd) [SAL]
    (swapchannels snd) [LISP]
    Swap left and right channels in snd, a stereo sound.

    prologic(l, c, r, s) [SAL]
    (prologic l c r s) [LISP]
    Encode four monaural SOUNDs representing the front-left, front-center, front-right, and rear channels, respectively. The return value is a stereo sound, which is a Dolby-encoded mix of the four input sounds.

    pl-left(snd) [SAL]
    (pl-left snd) [LISP]
    Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the front left channel.

    pl-center(snd) [SAL]
    (pl-center snd) [LISP]
    Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the front center channel.

    pl-right(snd) [SAL]
    (pl-right snd) [LISP]
    Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the front right channel.

    pl-rear(snd) [SAL]
    (pl-rear snd) [LISP]
    Produce a Dolby-encoded (stereo) signal with snd, a SOUND, encoded as the rear, or surround, channel.

    pl-pan2d(snd, x, y) [SAL]
    (pl-pan2d snd x y) [LISP]
    Comparable to Nyquist's existing pan function, pl-pan2d provides not only left-to-right panning, but front-to-back panning as well. The function accepts three parameters: snd is the (monophonic) input SOUND, x is a left-to-right position, and y is a front-to-back position. Both position parameters may be numbers or SOUNDs. An x value of 0 means left, and 1 means right. Intermediate values map linearly between these extremes. Similarly, a y value of 0 causes the sound to play entirely through the front speakers(s), while 1 causes it to play entirely through the rear. Intermediate values map linearly. Note that, although there are usually two rear speakers in Pro-Logic systems, they are both driven by the same signal. Therefore any sound that is panned totally to the rear will be played over both rear speakers. For example, it is not possible to play a sound exclusively through the rear left speaker.

    pl-position(snd, x, y, config) [SAL]
    (pl-position snd x y config) [LISP]
    The position function builds upon speaker panning to allow more abstract placement of sounds. Like pl-pan2d, it accepts a (monaural) input sound as well as left-to-right (x) and front-to-back (y) coordinates, which may be FLONUMs or SOUNDs. A fourth parameter config specifies the distance from listeners to the speakers (in meters). Current settings assume this to be constant for all speakers, but this assumption can be changed easily (see comments in the code for more detail). There are several important differences between pl-position and pl-pan2d. First, pl-position uses a Cartesian coordinate system that allows x and y coordinates outside of the range (0, 1). This model assumes a listener position of (0,0). Each speaker has a predefined position as well. The input sound's position, relative to the listener, is given by the vector (x,y).

    pl-doppler(snd, r) [SAL]
    (pl-doppler snd r) [LISP]
    Pitch-shift moving sounds according to the equation: fr = f0((c+vr)/c), where fr is the output frequency, f0 is the emitted (source) frequency, c is the speed of sound (assumed to be 344.31 m/s), and vr is the speed at which the emitter approaches the receiver. (vr is the first derivative of parameter r, the distance from the listener in meters.

    Drum Machine

    The drum machine software in demos/plight deserves further explanation. to use the software, load the code by evaluating:
    load "../demos/plight/drum.lsp"
    exec load-props-file(strcat(*plight-drum-path*, 
                                "beats.props"))
    exec create-drum-patches()
    exec create-patterns()
    

    Drum sounds and patterns are specified in the beats.props file (or whatever name you give to load-props-file). This file contains two types of specifications. First, there are sound file specifications. Sound files are located by a line of the form:

    set sound-directory = "kit/"
    
    This gives the name of the sound file directory, relative to the beats.props file. Then, for each sound file, there should be a line of the form:
    track.2.5 = big-tom-5.wav
    
    This says that on track 2, a velocity value of 5 means to play the sound file big-tom-5.wav. (Tracks and velocity values are described below.) The beats.props file contains specifications for all the sound files in demos/plight/kit using 8 tracks. If you make your own specifications file, tracks should be numbered consecutively from 1, and velocities should be in the range of 1 to 9.

    The second set of specifications is of beat patterns. A beat pattern is given by a line in the following form:

    beats.5 = 2--32--43-4-5---
    
    The number after beats is just a pattern number. Each pattern is given a unique number. After the equal sign, the digits and dashes are velocity values where a dash means "no sound." Beat patterns should be numbered consecutively from 1.

    Once data is loaded, there are several functions to access drum patterns and create drum sounds (described below). The demos/plight/drums.lsp file contains an example function plight-drum-example to play some drums. There is also the file demos/plight/beats.props to serve as an example of how to specify sound files and beat patterns.

    drum(tracknum, patternnum, bpm) [SAL]
    (drum tracknum patternnum bpm) [LISP]
    Create a sound by playing drums sounds associated with track tracknum (a FIXNUM) using pattern patternnum. The tempo is given by bpm in beats per minute. Normally patterns are a sequence of sixteenth notes, so the tempo is in sixteenth notes per minute. For example, if patternnum is 10, then use the pattern specified for beats.10. If the third character of this pattern is 3 and tracknum is 5, then on the third beat, play the soundfile assigned to track.5.3. This function returns a SOUND.

    drum-loop(snd, duration, numtimes) [SAL]
    (drum-loop snd duration numtimes) [LISP]
    Repeat the sound given by snd numtimes times. The repetitions occur at a time offset of duration, regardless of the actual duration of snd. A SOUND is returned.

    length-of-beat(bpm) [SAL]
    (length-of-beat bpm) [LISP]
    Given a tempo of bpm, return the duration of the beat in seconds. Note that this software has no real notion of beat. A "beat" is just the duration of each character in the beat pattern strings. This function returns a FLONUM.

    Minimoog-inspired Synthesis

    The moog.lsp library gives the Nyquist user easy access to "classic" synthesizer sounds through an emulation of the Minimoog Synthesizer. Unlike modular Moogs that were very large, the Minimoog was the first successful and commonly used portable synthesizer. The trademark filter attack was unique and easily recognizable. The goal of this Nyquist instrument is not only to provide the user with default sounds, but also to give control over many of the "knobs" found on the Minimoog. In this implementation, these parameters are controlled using keywords. The input to the moog instrument is a user-defined sequence of notes, durations, and articulations that simulate notes played on a keyboard. These are translated into control voltages that drive multiple oscillators, similar to the Voltage Controlled Oscillator or VCO found in the original analog Moog.

    The basic functionality of the Minimoog has been implemented, including the often-used "glide". The glide feature essentially low-pass filters the control voltage sequence in order to create sweeps between notes. Figure 21 is a simplified schematic of the data flow in the Moog. The control lines have been omitted.




    Figure 21: System diagram for Minimoog emulator.


    The most recognizable feature of the Minimoog is its resonant filter, a Four-Pole Ladder Filter invented by Robert Moog. It is simply implemented in a circuit with four transistors and provides an outstanding 24 dB/octave rolloff. It is modeled here using the built-in Nyquist resonant filter. One of the Moog filter features is a constant Q, or center frequency to bandwidth ratio. This is implemented and the user can control the Q.

    The user can control many parameters using keywords. Their default values, acceptable ranges, and descriptions are shown below. The defaults were obtained by experimenting with the official Minimoog software synthesizer by Arturia.

    Oscillator Parameters

    range-osc1 (2)
    range-osc2 (1)
    range-osc3 (3)
    These parameters control the octave of each oscillator. A value of 1 corresponds to the octave indicated by the input note. A value of 3 is two octaves above the fundamental. The allowable range is 1 to 7.

    detun2 (-.035861)
    detun3 (.0768)
    Detuning of two oscillators adds depth to the sound. A value of 1 corresponds to an increase of a single semitone and a -1 corresponds to a decrease in a semitone. The range is -1 to 1.

    shape-osc1 (*saw-table*)
    shape-osc2 (*saw-table*)
    shape-osc3 (*saw-table*)
    Oscilators can use any wave shape. The default sawtooth waveform is a built-in Nyquist variable. Other waveforms can be defined by the user.

    volume-osc1 (1)
    volume-osc2 (1)
    volume-osc3 (1)
    These parameters control the relative volume of each oscillator. The range is any FLONUM greater than or equal to zero.

    Noise Parameters

    noiselevel (.05)
    This parameter controls the relative volume of the noise source. The range is any FLONUM greater than or equal to zero.

    Filter Parameters

    filter-cutoff (768)
    The cutoff frequency of the filter in given in Hz. The range is zero to 20,000 Hz.

    Q (2)
    Q is the ratio of center frequency to bandwidth. It is held constant by making the bandwidth a function of frequency. The range is any FLONUM greater than zero.

    contour (.65)
    Contour controls the range of the transient frequency sweep from a high to low cutoff frequency when a note is played. The high frequency is proportional to contour. A contour of 0 removes this sweep. The range is 0 to 1.

    filter-attack (.0001)
    Filter attack controls the attack time of the filter, i.e. the time to reach the high cutoff frequency. The range is any FLONUM greater than zero (seconds).

    filter-decay (.5)
    Filter decay controls the decay time of the filter, i.e. the time of the sweep from the high to low cutoff frequency. The range is any FLONUM greater than zero (seconds).

    filter-sustain (.8)
    Filter sustain controls the percentage of the filter cutoff frequency that the filter settles on following the sweep. The range is 0 to 1.

    Amplitude Parameters

    amp-attack (.01)
    This parameter controls the amplitude envelope attack time, i.e. the time to reach maximum amplitude. The range is any FLONUM greater than zero (seconds).

    amp-decay (1)
    This parameter controls the amplitude envelope decay time, i.e. the time between the maximum and sustain volumes. The range is any FLONUM greater than zero (seconds).

    amp-sustain (1)
    This parameter controls the amplitude envelope sustain volume, a fraction of the maximum. The range is 0 to 1.

    amp-release (0)
    This parameter controls the amplitude envelope release time, i.e. the time it takes between the sustain volume and 0 once the note ends. The duration controls the overall length of the sound. The range of amp-release is any FLONUM greater than zero (seconds).

    Other Parameters

    glide (0)
    Glide controls the low-pass filter on the control voltages. This models the glide knob on a Minimoog. A higher value corresponds to a lower cutoff frequency and hence a longer "glide" between notes. A value of 0 corresponds to no glide. The range is zero to 10.

    Input Format

    A single note or a series of notes can be input to the Moog instrument by defining a list with the following format:
    list(list(frequency, duration, articulation), ... )
    
    where frequency is a FLONUM in steps, duration is the duration of each note in seconds (regardless of the release time of the amplifier), and articulation is a percentage of the duration that a sound will be played, representing the amount of time that a key is pressed. The filter and amplitude envelopes are only triggered if a note is played when the articulation of the previous note is less than 1, or a key is not down at the same time. This Moog instrument is a monophonic instrument, so only one note can sound at a time. The release section of the amplifier is triggered when the articulation is less than 1 at the time (duration * articulation).

    Sample Code/Sounds

    Sound 1 (default parameters):
    set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99}
    {29 .5 .99} {31 2 1}}
    play moog(s)

    Sound 2 (articulation, with amplitude release):

    set s = {{24 .5 .5} {26 .5 1} {28 .5 .25} {29 .5 1} {31 1 .8}}
    play moog(s, amp-release: .2)

    Sound 3 (glide):

    set s = {{24 .5 .5} {38 .5 1} {40 .5 .25}
    {53 .5 1} {55 2 1} {31 2 .8} {36 2 .8}}
    play moog(s, amp-release: .2, glide: .5)

    Sound 4 (keyword parameters): Filter attack and decay are purposely longer than notes being played with articulation equal to 1.

    set s = {{20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1}
    {20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1}}
    play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*,
    filter-attack: 2, filter-decay: 2,
    filter-cutoff: 300, contour: .8, glide: .2, Q: 8)

    Sound 5: This example illustrates the ability to completely define a new synthesizer with different parameters creating a drastically different sound. Sine waves are used for wavetables. There is a high value for glide.

    define function my-moog(freq)
    return moog(freq,
    range-osc1: 3, range-osc2: 2, range-osc3: 4,
    detun2: -.043155, detun3: .015016,
    noiselevel: 0,
    filter-cutoff: 400, Q: .1, contour: .0000001,
    filter-attack: 0, filter-decay: .01, filter-sustain: 1,
    shape-osc1: *sine-table*, shape-osc2: *sine-table*,
    shape-osc3: *sine-table*, volume-osc1: 1, volume-osc2: 1,
    volume-osc3: .1, amp-attack: .1, amp-decay: 0,
    amp-sustain: 1, amp-release: .3, glide: 2)

    set s = {{80 .4 .75} {28 .2 1} {70 .5 1} {38 1 .5}}
    play my-moog(s)

    Sound 6: This example has another variation on the default parameters.

    set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99}
    {29 .5 .99} {31 2 1}}
    play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*,
    filter-attack: .5, contour: .5)


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/part12.html0000644000175000000620000002242411537432671014744 0ustar stevestaffLinear Prediction Analysis and Synthesis Previous Section | Next Section | Table of Contents | Index | Title Page

    Linear Prediction Analysis and Synthesis

    Nyquist provides functions to perform Linear Prediction Coding (LPC) analysis and synthesis. In simple terms, LPC analysis assumes that a sound is the result of an all-pole filter applied to a source with a flat spectrum. LPC is good for characterizing the general spectral shape of a signal, which may be time-varying as in speech sounds. For synthesis, any source can be filtered, allowing the general spectral shape of one signal (used in analysis) to be applied to any source (used in synthesis). A popular effect is to give vowel-like spectra to musical tones, creating an artificial (or sometimes natural) singing voice.

    Examples of LPC analysis and synthesis can be found in the file lpc_tutorial.htm, which is part of the standard Nyquist release.

    As with FFT processing, LPC analysis takes a sound as input and returns a stream of frames. Frames are returned from an object using the :next selector just as with FFT frames. An LPC frame is a list consisting of: RMS1, the energy of the input signal, RMS2, the energy of the residual signal, ERR, the square root of RMS1/RMS2, and FILTER-COEFS, an array of filter coefficients. To make code more readable and to avoid code dependence on the exact format of a frame, the functions lpc-frame-rms1, lpc-frame-rms2, lpc-frame-err, and lpc-frame-filter-coefs can be applied to a frame to obtain the respective fields.

    The z transform of the filter is H(z) = 1/A(z), where A(z) is a polynomial of the form A(z) = 1 + a1z + a2z + ... + apz. The FILTER-COEFS array has the form #(ap ap-1 ... a3 a2 a1).

    The file lpc.lsp defines some useful classes and functions. The file is not automatically loaded with Nyquist, so you must execute (load "lpc") before using them.

    LPC Classes and Functions

    make-lpanal-iterator(sound, framedur, skiptime, npoles) [SAL]
    (make-lpanal-iterator sound framedur skiptime npoles) [LISP]
    Makes an iterator object, an instance of lpanal-class, that returns LPC frames from successive frames of samples in sound. The duration (in seconds) of each frame is given by framedur, a FLONUM. The skip size (in seconds) between successive frames is given by skiptime, a FLONUM. Typical values for framedur and skiptime are 0.08 and 0.04, giving 25 frames per second and a 50% frame overlap. The number of poles is given by npoles, a FIXNUM. The result is an object that responds to the :next selector by returning a frame as described above. NIL is returned when sound terminates. (Note that one or more of the last analysis windows may be padded with zeros. NIL is only returned when the corresponding window would begin after the termination time of the sound.)

    make-lpc-file-iterator(filename) [SAL]
    (make-lpc-file-iterator filename) [LISP]
    Another way to get LPC frames is to read them from a file. This function opens an ASCII file containing LPC frames and creates an iterator object, an instance of class lpc-file-class to access them. Create a file using save-lpc-file (see below).

    save-lpc-file(lpc-iterator, filename) [SAL]
    (save-lpc-file lpc-iterator filename) [LISP]
    Create a file containing LPC frames. This file can be read by make-lpc-file-iterator (see above).

    show-lpc-data(lpc-iterator, iniframe, endframe [, poles?]) [SAL]
    (show-lpc-data lpc-iterator iniframe endframe [poles?]) [LISP]
    Print values of LPC frames from an LPC iterator object. The object is lpc-iterator, which is typically an instance of lpanal-class or lpc-file-class. Frames are numbered from zero, and only files starting at iniframe (a FIXNUM) and ending before endframe (also a FIXNUM) are printed. By default, only the values for RMS1, RMS2, and ERR are printed, but if optional parameter poles? is non-NIL, then the LPC coefficients are also printed.

    allpoles-from-lpc(snd, lpc-frame) [SAL]
    (allpoles-from-lpc snd lpc-frame) [LISP]
    A single LPC frame defines a filter. Use allpoles-from-lpc to apply this filter to snd, a SOUND. To obtain lpc-frame, a LIST containing an LPC frame, either send :next to an LPC iterator, or use nth-frame (see below). The result is a SOUND whose duration is the same as that of snd.

    lpreson(snd, lpc-iterator, skiptime) [SAL]
    (lpreson snd lpc-iterator skiptime) [LISP]
    Implements a time-varying all-pole filter controlled by a sequence of LPC frames from an iterator. The SOUND to be filtered is snd, and the source of LPC frames is lpc-iterator, typically an instance of lpanal-class or lpc-file-class. The frame period (in seconds) is given by skiptime (a FLONUM). This number does not have to agree with the skiptime used to analyze the frames. (Greater values will cause the filter evolution slow down, and smaller values will cause it to speed up.) The result is a SOUND. The duration of the result is the minimum of the duration of snd and that of the sequence of frames.

    lpc-frame-rms1(frame) [SAL]
    (lpc-frame-rms1 frame) [LISP]
    Get the energy of the input signal from a frame.

    lpc-frame-rms2(frame) [SAL]
    (lpc-frame-rms2 frame) [LISP]
    Get the energy of the residual from a frame.

    lpc-frame-err(frame) [SAL]
    (lpc-frame-err frame) [LISP]
    Get the square root of RMS1/RMS2 from a frame.

    lpc-frame-filter-coefs(frame) [SAL]
    (lpc-frame-filter-coefs frame) [LISP]
    Get the filter coefficients from a frame.

    Low-level LPC Functions

    The lowest-level Nyquist functions for LPC are
    • snd-lpanal for analysis,
    • snd-allpoles, an all-pole filter with fixed coefficients, and
    • snd-lpreson, an all-pole filter that takes frames from an LPC iterator.

    snd-lpanal(samps, npoles) [SAL]
    (snd-lpanal samps npoles) [LISP]
    Compute an LPC frame with npoles (a FIXNUM) poles from an ARRAY of samples (FLONUMS). Note that snd-fetch-array can be used to fetch a sequence of frames from a sound. Ordinarily, you should not use this function. Use make-lpanal-iterator instead.

    snd-allpoles(snd, lpc-coefs, gain) [SAL]
    (snd-allpoles snd lpc-coefs gain) [LISP]
    A fixed all-pole filter. The input is snd, a SOUND. The filter coefficients are given by lpc-coefs (an ARRAY), and the filter gain is given by gain, a FLONUM. The result is a SOUND whose duration matches that of snd. Ordinarily, you should use allpoles-from-lpc instead (see above).

    snd-lpreson(snd, lpc-iterator, skiptime) [SAL]
    (snd-lpreson snd lpc-iterator skiptime) [LISP]
    This function is identical to lpreson (see above).


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/part14.html0000644000175000000620000024054311537432671014752 0ustar stevestaffXmusic and Algorithmic Composition Previous Section | Next Section | Table of Contents | Index | Title Page

    Xmusic and Algorithmic Composition

    Several Nyquist libraries offer support for algorithmic composition. Xmusic is a library for generating sequences and patterns of data. Included in Xmusic is the score-gen macro which helps to generate scores from patterns. Another important facility is the distributions.lsp library, containing many different random number generators.

    Xmusic Basics

    Xmusic is inspired by and based on Common Music by Rick Taube. Currently, Xmusic only implements patterns and some simple support for scores to be realized as sound by Nyquist. In contrast, Common Music supports MIDI and various other synthesis languages and includes a graphical interface, some visualization tools, and many other features. Common Music runs in Common Lisp and Scheme, but not XLISP, which is the base language for Nyquist.

    Xmusic patterns are objects that generate data streams. For example, the cycle-class of objects generate cyclical patterns such as "1 2 3 1 2 3 1 2 3 ...", or "1 2 3 4 3 2 1 2 3 4 ...". Patterns can be used to specify pitch sequences, rhythm, loudness, and other parameters.

    Xmusic functions are automatically loaded when you start Nyquist. To use a pattern object, you first create the pattern, e.g.

    set pitch-source = make-cycle(list(c4, d4, e4, f4))
    
    After creating the pattern, you can access it repeatedly with next to generate data, e.g.
    play seqrep(i, 13, pluck(next(pitch-source), 0.2))
    
    This will create a sequence of notes with the following pitches: c, d, e, f, c, d, e, f, c, d, e, f, c. If you evaluate this again, the pitch sequence will continue, starting on "d".

    It is very important not to confuse the creation of a sequence with its access. Consider this example:

    play seqrep(i, 13,
             pluck(next(make-cycle(list(c4, d4, e4, f4))), 0.2))
    
    This looks very much like the previous example, but it only repeats notes on middle-C. The reason is that every time pluck is evaluated, make-cycle is called and creates a new pattern object. After the first item of the pattern is extracted with next, the cycle is not used again, and no other items are generated.

    To summarize this important point, there are two steps to using a pattern. First, the pattern is created and stored in a variable using setf. Second, the pattern is accessed (multiple times) using next.

    Patterns can be nested, that is, you can write patterns of patterns. In general, the next function does not return patterns. Instead, if the next item in a pattern is a (nested) pattern, next recursively gets the next item of the nested pattern.

    While you might expect that each call to next would advance the top-level pattern to the next item, and descend recursively if necessary to the inner-most nesting level, this is not how next works. Instead, next remembers the last top-level item, and if it was a pattern, next continues to generate items from that same inner pattern until the end of the inner pattern's period is reached. The next paragraph explains the concept of the period.

    The data returned by a pattern object is structured into logical groups called periods. You can get an entire period (as a list) by calling next(pattern, t). For example:

    set pitch-source = make-cycle(list(c4, d4, e4, f4))
    print next(pitch-source, t)
    
    This prints the list (60 62 64 65), which is one period of the cycle.

    You can also get explicit markers that delineate periods by calling send(pattern, :next). In this case, the value returned is either the next item of the pattern, or the symbol +eop+ if the end of a period has been reached. What determines a period? This is up to the specific pattern class, so see the documentation for specifics. You can override the "natural" period using the keyword for:, e.g.

    set pitch-source = make-cycle(list(c4, d4, e4, f4), for: 3)
    print next(pitch-source, t)
    print next(pitch-source, t)
    
    This prints the lists (60 62 64) (65 60 62). Notice that these periods just restructure the stream of items into groups of 3.

    Nested patterns are probably easier to understand by example than by specification. Here is a simple nested pattern of cycles:

    set cycle-1 = make-cycle({a b c})
    set cycle-2 = make-cycle({x y z})
    set cycle-3 = make-cycle(list(cycle-1, cycle-2))
    exec dotimes(i, 9, format(t, "~A ", next(cycle-3)))
    
    This will print "A B C X Y Z A B C". Notice that the inner-most cycles cycle-1 and cycle-2 generate a period of items before the top-level cycle-3 advances to the next pattern.

    Before describing specific pattern classes, there are several optional parameters that apply in the creating of any pattern object. These are:

    for:
    The length of a period. This overrides the default by providing a numerical length. The value of this optional parameter may be a pattern that generates a sequence of integers that determine the length of each successive period. A period length may not be negative, but it may be zero.

    name:
    A pattern object may be given a name. This is useful if the trace: option is used.

    trace:
    If non-null, this optional parameter causes information about the pattern to be printed each time an item is generated from the pattern.

    The built-in pattern classes are described in the following section.

    Pattern Classes

    cycle

    The cycle-class iterates repeatedly through a list of items. For example, two periods of make-cycle({a b c}) would be (A B C) (A B C).

    make-cycle(items, for: for, name: name, trace: trace) [SAL]
    (make-cycle items :for for :name name :trace trace) [LISP]
    Make a cycle pattern that iterates over items. The default period length is the length of items. (See above for a description of the optional parameters.) If items is a pattern, a period of the pattern becomes the list from which items are generated. The list is replaced every period of the cycle.

    line

    The line-class is similar to the cycle class, but when it reaches the end of the list of items, it simply repeats the last item in the list. For example, two periods of make-line({a b c}) would be (A B C) (C C C).

    make-line(items, for: for, name: name, trace: trace) [SAL]
    (make-line items :for for :name name :trace trace) [LISP]
    Make a line pattern that iterates over items. The default period length is the length of items. As with make-cycle, items may be a pattern. (See above for a description of the optional parameters.)

    random

    The random-class generates items at random from a list. The default selection is uniform random with replacement, but items may be further specified with a weight, a minimum repetition count, and a maximum repetition count. Weights give the relative probability of the selection of the item (with a default weight of one). The minimum count specifies how many times an item, once selected at random, will be repeated. The maximum count specifies the maximum number of times an item can be selected in a row. If an item has been generated n times in succession, and the maximum is equal to n, then the item is disqualified in the next random selection. Weights (but not currently minima and maxima) can be patterns. The patterns (thus the weights) are recomputed every period.

    make-random(items, for: for, name: name, trace: trace) [SAL]
    (make-random items :for for :name name :trace trace) [LISP]
    Make a random pattern that selects from items. Any (or all) element(s) of items may be lists of the following form: (value :weight weight :min mincount :max maxcount), where value is the item (or pattern) to be generated, weight is the (optional) relative probability of selecting this item, mincount is the (optional) minimum number of repetitions when this item is selected, and maxcount is the (optional) maximum number of repetitions allowed before selecting some other item. The default period length is the length of items. If items is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period.

    palindrome

    The palindrome-class repeatedly traverses a list forwards and then backwards. For example, two periods of make-palindrome({a b c}) would be (A B C C B A) (A B C C B A). The elide: keyword parameter controls whether the first and/or last elements are repeated:
    make-palindrome({a b c}, elide: nil)
         ;; generates A B C C B A A B C C B A ...
    

    make-palindrome({a b c}, elide: t) ;; generates A B C B A B C B ...

    make-palindrome({a b c}, elide: :first) ;; generates A B C C B A B C C B ...

    make-palindrome({a b c}, elide: :last) ;; generates A B C B A A B C B A ...

    make-palindrome(items, elide: elide, for: for, name: name, trace: trace) [SAL]
    (make-palindrome items :elide elide :for for :name name :trace trace) [LISP]
    Generate items from list alternating in-order and reverse-order sequencing. The keyword parameter elide can have the values :first, :last, t, or nil to control repetition of the first and last elements. The elide parameter can also be a pattern, in which case it is evaluated every period. One period is one complete forward and backward traversal of the list. If items is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period.

    heap

    The heap-class selects items in random order from a list without replacement, which means that all items are generated once before any item is repeated. For example, two periods of make-heap({a b c}) might be (C A B) (B A C). Normally, repetitions can occur even if all list elements are distinct. This happens when the last element of a period is chosen first in the next period. To avoid repetitions, the max: keyword argument can be set to 1. The max: keyword only controls repetitions from the end of one period to the beginning of the next. If the list contains more than one copy of the same value, it may be repeated within a period regardless of the value of max:.

    make-heap(items, for: for, max: max, name: name, trace: trace) [SAL]
    (make-heap items :for for :max max :name name :trace trace) [LISP]
    Generate items randomly from list without replacement. If max is 1, the first element of a new period will not be the same as the last element of the previous period, avoiding repetition. The default value of max is 2, meaning repetition is allowed. The period length is the length of items. If items is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period.

    accumulation

    The accumulation-class takes a list of values and returns the first, followed by the first two, followed by the first three, etc. In other words, for each list item, return all items from the first through the item. For example, if the list is (A B C), each generated period is (A A B A B C).

    make-accumulation(items, name: name, trace: trace) [SAL]
    (make-accumulation items :name name :trace trace) [LISP]
    For each item, generate items from the first to the item including the item. The period length is (n^(2) + n) / 2 where n is the length of items. If items is a pattern, a period from that pattern becomes the list from which items are generated, and a new list is generated every period. Note that this is similar in name but different from make-accumulate.

    copier

    The copier-class makes copies of periods from a sub-pattern. For example, three periods of make-copier(make-cycle({a b c}, for: 1), repeat: 2, merge: t) would be (A A) (B B) (C C). Note that entire periods (not individual items) are repeated, so in this example the for: keyword was used to force periods to be of length one so that each item is repeated by the repeat: count.

    make-copier(sub-pattern, repeat: repeat, merge: merge, for: for, name: name, trace: trace) [SAL]
    (make-copier sub-pattern :repeat repeat :merge merge :for for :name name :trace trace) [LISP]
    Generate a period from sub-pattern and repeat it repeat times. If merge is false (the default), each repetition of a period from sub-pattern results in a period by default. If merge is true (non-null), then all repeat repetitions of the period are merged into one result period by default. If the for: keyword is used, the same items are generated, but the items are grouped into periods determined by the for: parameter. If the for: parameter is a pattern, it is evaluated every result period. The repeat and merge values may be patterns that return a repeat count and a boolean value, respectively. If so, these patterns are evaluated initially and after each repeat copies are made (independent of the for: keyword parameter, if any). The repeat value returned by a pattern can also be negative. A negative number indicates how many periods of sub-pattern to skip. After skipping these patterns, new repeat and merge values are generated.

    accumulate

    The accumulate-class forms the sum of numbers returned by another pattern. For example, each period of make-accumulate(make-cycle({1 2 -3})) is (1 3 0). The default output period length is the length of the input period.

    make-accumulate(sub-pattern, for: for, max: maximum, min: minimum, name: name, trace: trace) [SAL]
    (make-accumulate sub-pattern :for for :max maximum :min minimum :name name :trace trace) [LISP]
    Keep a running sum of numbers generated by sub-pattern. The default period lengths match the period lengths from sub-pattern. If maximum (a pattern or a number) is specified, and the running sum exceeds maximum, the running sum is reset to maximum. If minimum (a pattern or a number) is specified, and the running sum falls below minimum, the running sum is reset to minimum. If minimum is greater than maximum, the running sum will be set to one of the two values. Note that this is similar in name but not in function to make-accumulation.

    sum

    The sum-class forms the sum of numbers, one from each of two other patterns. For example, each period of make-sum(make-cycle({1 2 3}), make-cycle({4 5 6})) is (5 7 9). The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number.

    make-sum(x, y, for: for, name: name, trace: trace) [SAL]
    (make-sum x y :for for :name name :trace trace) [LISP]
    Form sums of items (which must be numbers) from pattern x and pattern or number y. The default period lengths match the period lengths from x.

    product

    The product-class forms the product of numbers, one from each of two other patterns. For example, each period of make-product(make-cycle({1 2 3}), make-cycle({4 5 6})) is (4 10 18). The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number.

    make-product(x, y, for: for, name: name, trace: trace) [SAL]
    (make-product x y :for for :name name :trace trace) [LISP]
    Form products of items (which must be numbers) from pattern x and pattern or number y. The default period lengths match the period lengths from x.

    eval

    The eval-class evaluates an expression to produce each output item. The default output period length is 1.

    make-eval(expr, for: for, name: name, trace: trace) [SAL]
    (make-eval expr :for for :name name :trace trace) [LISP]
    Evaluate expr to generate each item. If expr is a pattern, each item is generated by getting the next item from expr and evaluating it.

    length

    The length-class generates periods of a specified length from another pattern. This is similar to using the for: keyword, but for many patterns, the for: parameter alters the points at which other patterns are generated. For example, if the palindrome pattern has an elide: pattern parameter, the value will be computed every period. If there is also a for: parameter with a value of 2, then elide: will be recomputed every 2 items. In contrast, if the palindrome (without a for: parameter) is embedded in a length pattern with a lenght of 2, then the periods will all be of length 2, but the items will come from default periods of the palindrome, and therefore the elide: values will be recomputed at the beginnings of default palindrome periods.

    make-length(pattern, length-pattern, name: name, trace: trace) [SAL]
    (make-length pattern length-pattern :name name :trace trace) [LISP]
    Make a pattern of class length-class that regroups items generated by a pattern according to pattern lengths given by length-pattern. Note that length-pattern is not optional: There is no default pattern length and no for: keyword.

    window

    The window-class groups items from another pattern by using a sliding window. If the skip value is 1, each output period is formed by dropping the first item of the previous perioda and appending the next item from the pattern. The skip value and the output period length can change every period. For a simple example, if the period length is 3 and the skip value is 1, and the input pattern generates the sequence A, B, C, ..., then the output periods will be (A B C), (B C D), (C D E), (D E F), ....

    make-window(pattern, length-pattern, skip-pattern, name: name, trace: trace) [SAL]
    (make-window pattern length-pattern skip-pattern :name name :trace trace) [LISP]
    Make a pattern of class window-class that regroups items generated by a pattern according to pattern lengths given by length-pattern and where the period advances by the number of items given by skip-pattern. Note that length-pattern is not optional: There is no default pattern length and no for: keyword.

    markov

    The markov-class generates items from a Markov model. A Markov model generates a sequence of states according to rules which specify possible future states given the most recent states in the past. For example, states might be pitches, and each pitch might lead to a choice of pitches for the next state. In the markov-class, states can be either symbols or numbers, but not arbitrary values or patterns. This makes it easier to specify rules. However, symbols can be mapped to arbitrary values including pattern objects, and these become the actual generated items. By default, all future states are weighted equally, but weights may be associated with future states. A Markov model must be initialized with a sequence of past states using the past: keyword. The most common form of Markov model is a "first order Markov model" in which the future item depends only upon one past item. However, higher order models where the future items depend on two or more past items are possible. A "zero-order" Markov model, which depends on no past states, is essentially equivalent to the random pattern. As an example of a first-order Markov pattern, two periods of make-markov({{a -> b c} {b -> c} {c -> a}}, past: {a}) might be (C A C) (A B C).

    make-markov(rules, past: past, produces: produces, for: for, name: name, trace: trace) [SAL]
    (make-markov rules past :produces produces :for for :name name :trace trace) [LISP]
    Generate a sequence of items from a Markov process. The rules parameter has the form: (prev1 prev2 ... prevn -> next1 next2 ... nextn) where prev1 through prevn represent a sequence of most recent (past) states. The symbol * is treated specially: it matches any previous state. If prev1 through prevn (which may be just one state as in the example above) match the previously generated states, this rule applies. Note that every rule must specify the same number of previous states; this number is known as the order of the Markov model. The first rule in rules that applies is used to select the next state. If no rule applies, the next state is NIL (which is a valid state that can be used in rules). Assuming a rule applies, the list of possible next states is specified by next1 through nextn. Notice that these are alternative choices for the next state, not a sequence of future states, and each rule can have any number of choices. Each choice may be the state itself (a symbol or a number), or the choice may be a list consisting of the state and a weight. The weight may be given by a pattern, in which case the next item of the pattern is obtained every time the rule is applied. For example, this rules says that if the previous states were A and B, the next state can be A with a weight of 0.5 or C with an implied weight of 1: (A B -> (A 0.5) C). The default length of the period is the length of rules. The past parameter must be provided. It is a list of states whose length matches the order of the Markov model. The keyword parameter produces may be used to map from state symbols or numbers to other values or patterns. The parameter is a list of alternating symbols and values. For example, to map A to 69 and B to 71, use list(quote(a), 69, quote(b), 71). You can also map symbols to patterns, for example list(quote(a), make-cycle({57 69}), quote(b), make-random({59 71})). The next item of the pattern is is generated each time the Markov model generates the corresponding state. Finally, the produces keyword can be eval:, which means to evaluate the Markov model state. This could be useful if states are Nyquist global variables such as C4, CS4, D4, ]..., which evaluate to numerical values (60, 61, 62, ....

    markov-create-rules(sequence, order [, generalize]) [SAL]
    (markov-create-rules sequence order [generalize]) [LISP]
    Generate a set of rules suitable for the make-markov function. The sequence is a "typical" sequence of states, and order is the order of the Markov model. It is often the case that a sample sequence will not have a transition from the last state to any other state, so the generated Markov model can reach a "dead end" where no rule applies. This might lead to an infinite stream of NIL's. To avoid this, the optional parameter generalize can be set to t (true), indicating that there should be a fallback rule that matches any previous states and whose future states are weighted according to their frequency in sequence. For example, if sequence contains 5 A's, 5 B's and 10 G's, the default rule will be (* -> (A 5) (B 5) (G 10)). This rule will be appended to the end so it will only apply if no other rule does.

    Random Number Generators

    The distributions.lsp library implements random number generators that return random values with various probability distributions. Without this library, you can generate random numbers with uniform distributions. In a uniform distribution, all values are equally likely. To generate a random integer in some range, use random. To generate a real number (FLONUM) in some range, use real-random (or rrandom if the range is 0-1). But there are other interesting distributions. For example, the Gaussian distribution is often used to model real-world errors and fluctuations where values are clustered around some central value and large deviations are more unlikely than small ones. See Dennis Lorrain, "A Panoply of Stochastic 'Canons'," Computer Music Journal vol. 4, no. 1, 1980, pp. 53-81.

    In most of the random number generators described below, there are optional parameters to indicate a maximum and/or minimum value. These can be used to truncate the distribution. For example, if you basically want a Gaussian distribution, but you never want a value greater than 5, you can specify 5 as the maximum value. The upper and lower bounds are implemented simply by drawing a random number from the full distribution repeatedly until a number falling into the desired range is obtained. Therefore, if you select an acceptable range that is unlikely, it may take Nyquist a long time to find each acceptable random number. The intended use of the upper and lower bounds is to weed out values that are already fairly unlikely.

    linear-dist(g) [SAL]
    (linear-dist g) [LISP]
    Return a FLONUM value from a linear distribution, where the probability of a value decreases linearly from zero to g which must be greater than zero. (See Figure 7.) The linear distribution is useful for generating for generating time and pitch intervals.




    Figure 7: The Linear Distribution, g = 1.


    exponential-dist(delta [, high]) [SAL]
    (exponential-dist delta [high]) [LISP]
    Return a FLONUM value from an exponential distribution. The initial downward slope is steeper with larger values of delta, which must be greater than zero. (See Figure 8. The optional high parameter puts an artificial upper bound on the return value. The exponential distribution generates values greater than 0, and can be used to generate time intervals. Natural random intervals such as the time intervals between the release of atomic particles or the passing of yellow volkswagons in traffic have exponential distributions. The exponential distribution is memory-less: knowing that a random number from this distribution is greater than some value (e.g. a note duration is at least 1 second) tells you nothing new about how soon the note will end. This is a continuous distribution, but geometric-dist (described below) implements the discrete form.




    Figure 8: The Exponential Distribution, delta = 1.


    gamma-dist(nu [, high]) [SAL]
    (gamma-dist nu [high]) [LISP]
    Return a FLONUM value from a Gamma distribution. The value is greater than zero, has a mean of nu (a FIXNUM greater than zero), and a mode (peak) of around nu - 1. The optional high parameter puts an artificial upper bound on the return value.




    Figure 9: The Gamma Distribution, nu = 4.


    bilateral-exponential-dist(xmu, tau [, low, high]) [SAL]
    (bilateral-exponential-dist xmu tau [low high]) [LISP]
    Returns a FLONUM value from a bilateral exponential distribution, where xmu is the center of the double exponential and tau controls the spread of the distribution. A larger tau gives a wider distribution (greater variance), and tau must be greater than zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively. This distribution is similar to the exponential, except it is centered at 0 and can output negative values as well. Like the exponential, it can be used to generate time intervals; however, it might be necessary to add a lower bound so as not to compute a negative time interval.




    Figure 10: The Bilateral Exponential Distribution.


    cauchy-dist(tau [, low, high]) [SAL]
    (cauchy-dist tau [low high]) [LISP]
    Returns a FLONUM from the Cauchy distribution, a symetric distribution with a high peak at zero and a width (variance) that increases with parameter tau, which must be greater than zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively.




    Figure 11: The Cauchy Distribution, tau = 1.


    hyperbolic-cosine-dist([low, high]) [SAL]
    (hyperbolic-cosine-dist [low high)] [LISP]
    Returns a FLONUM value from the hyperbolic cosine distribution, a symetric distribution with its peak at zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively.




    Figure 12: The Hyperbolic Cosine Distribution.


    logistic-dist(alpha, beta [, low, high]) [SAL]
    (logistic-dist alpha beta [low high]) [LISP]
    Returns a FLONUM value from the logistic distribution, which is symetric about the mean. The alpha parameter primarily affects dispersion (variance), with larger values resulting in values closer to the mean (less variance), and the beta parameter primarily influences the mean. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively.




    Figure 13: The Logistic Distribution, alpha = 1, beta = 2.


    arc-sine-dist() [SAL]
    (arc-sine-dist) [LISP]
    Returns a FLONUM value from the arc sine distribution, which outputs values between 0 and 1. It is symetric about the mean of 1/2, but is more likely to generate values closer to 0 and 1.




    Figure 14: The Arc Sine Distribution.


    gaussian-dist(xmu, sigma [, low, high]) [SAL]
    (gaussian-dist xmu sigma [low high]) [LISP]
    Returns a FLONUM value from the Gaussian or Gauss-Laplace distribution, a linear function of the normal distribution. It is symetric about the mean of xmu, with a standard deviation of sigma, which must be greater than zero. The low and high parameters give optional artificial bounds on the minimum and maximum output values, respectively.




    Figure 15: The Gauss-Laplace (Gaussian) Distribution, xmu = 0, sigma = 1.


    beta-dist(a, b) [SAL]
    (beta-dist a b) [LISP]
    Returns a FLONUM value from the Beta distribution. This distribution outputs values between 0 and 1, with outputs more likely to be close to 0 or 1. The parameter a controls the height (probability) of the right side of the distribution (at 1) and b controls the height of the left side (at 0). The distribution is symetric about 1/2 when a = b.




    Figure 16: The Beta Distribution, alpha = .5, beta = .25.


    bernoulli-dist(px1 [, x1, x2]) [SAL]
    (bernoulli-dist px1 [x1 x2]) [LISP]
    Returns either x1 (default value is 1) with probability px1 or x2 (default value is 0) with probability 1 - px1. The value of px1 should be between 0 and 1. By convention, a result of x1 is viewed as a success while x2 is viewed as a failure.




    Figure 17: The Bernoulli Distribution, px1 = .75.


    binomial-dist(n, p) [SAL]
    (binomial-dist n p) [LISP]
    Returns a FIXNUM value from the binomial distribution, where n is the number of Bernoulli trials run (a FIXNUM) and p is the probability of success in the Bernoulli trial (a FLONUM from 0 to 1). The mean is the product of n and p.




    Figure 18: The Binomial Distribution, n = 5, p = .5.


    geometric-dist(p) [SAL]
    (geometric-dist p) [LISP]
    Returns a FIXNUM value from the geometric distribution, which is defined as the number of failures before a success is achieved in a Bernoulli trial with probability of success p (a FLONUM from 0 to 1).




    Figure 19: The Geometric Distribution, p = .4.


    poisson-dist(delta) [SAL]
    (poisson-dist delta) [LISP]
    Returns a FIXNUM value from the Poisson distribution with a mean of delta (a FIXNUM). The Poisson distribution is often used to generate a sequence of time intervals, resulting in random but often pleasing rhythms.




    Figure 20: The Poisson Distribution, delta = 3.


    Score Generation and Manipulation

    A common application of pattern generators is to specify parameters for notes. (It should be understood that "notes" in this context means any Nyquist behavior, whether it represents a conventional note, an abstract sound object, or even some micro-sound event that is just a low-level component of a hierarchical sound organization. Similarly, "score" should be taken to mean a specification for a sequence of these "notes.") The score-gen macro (defined by loading xm.lsp) establishes a convention for representing scores and for generating them using patterns.

    The timed-seq macro, described in Section "Combination and Time Structure", already provides a way to represent a "score" as a list of expressions. The Xmusic representation goes a bit further by specifying that all notes are specified by an alternation of keywords and values, where some keywords have specific meanings and interpretations.

    The basic idea of score-gen is you provide a template for notes in a score as a set of keywords and values. For example,

    set pitch-pattern = make-cycle(list(c4, d4, e4, f4))
    score-gen(dur: 0.4, name: quote(my-sound),
              pitch: next(pitch-pattern), score-len: 9)
    
    generates a score of 9 notes as follows:
    ((0 0 (SCORE-BEGIN-END 0 3.6))
     (0 0.4 (MY-SOUND :PITCH 60))
     (0.4 0.4 (MY-SOUND :PITCH 62))
     (0.8 0.4 (MY-SOUND :PITCH 64))
     (1.2 0.4 (MY-SOUND :PITCH 65))
     (1.6 0.4 (MY-SOUND :PITCH 60))
     (2 0.4 (MY-SOUND :PITCH 62))
     (2.4 0.4 (MY-SOUND :PITCH 64))
     (2.8 0.4 (MY-SOUND :PITCH 65))
     (3.2 0.4 (MY-SOUND :PITCH 60)))
    
    The use of keywords like :PITCH helps to make scores readable and easy to process without specific knowledge of about the functions called in the score. For example, one could write a transpose operation to transform all the :pitch parameters in a score without having to know that pitch is the first parameter of pluck and the second parameter of piano-note. Keyword parameters are also used to give flexibility to note specification with score-gen. Since this approach requires the use of keywords, the next section is a brief explanation of how to define functions that use keyword parameters.

    Keyword Parameters

    Keyword parameters are parameters whose presence is indicated by a special symbol, called a keyword, followed by the actual parameter. Keyword parameters in SAL have default values that are used if no actual parameter is provided by the caller of the function. (See Appendix "XLISP: An Object-oriented Lisp" to learn about keywords in XLISP.)

    To specify that a parameter is a keyword parameter, use a keyword symbol (one that ends in a colon) followed by a default value. For example, here is a function that accepts keyword parameters and invokes the pluck function:

    define function k-pluck(pitch: 60, dur: 1)
      return pluck(pitch, dur)
    
    Now, we can call k-pluck with keyword parameters. The keywords are simply the formal parameter names with a prepended colon character (:pitch and :dur in this example), so a function call would look like:
    pluck(pitch: c3, dur: 3)
    
    Usually, it is best to give keyword parameters useful default values. That way, if a parameter such as dur: is missing, a reasonable default value (1) can be used automatically. It is never an error to omit a keyword parameter, but the called function can check to see if a keyword parameter was supplied or not. Because of default values, we can call k-pluck(pitch: c3) with no duration, k-pluck(dur: 3) with only a duration, or even k-pluck() with no parameters.

    In XLISP, there is additional syntax to specify an alternate symbol to be used as the keyword and to allow the called function to determine whether or not a keyword parameter was supplied, but these features are little-used. See the XLISP manual for details.

    Using score-gen

    The score-gen macro computes a score based on keyword parameters. Some keywords have a special meaning, while others are not interpreted but merely placed in the score. The resulting score can be synthesized using timed-seq (see Section "Combination and Time Structure").

    The form of a call to score-gen is simply:

    score-gen(k1: e1, k2: e2, ...) [SAL]
    (score-gen :k1 e1 :k2 e2 ...) [LISP]
    where the k's are keywords and the e's are expressions. A score is generated by evaluating the expressions once for each note and constructing a list of keyword-value pairs. A number of keywords have special interpretations. The rules for interpreting these parameters will be explained through a set of "How do I ..." questions below.

    How many notes will be generated? The keyword parameter score-len: specifies an upper bound on the number of notes. (Note: in LISP syntax, keywords are always preceded by colons, so you would write :score-len instead.) The keyword score-dur: specifies an upper bound on the starting time of the last note in the score. (To be more precise, the score-dur: bound is reached when the default starting time of the next note is greater than or equal to the score-dur: value. This definition is necessary because note times are not strictly increasing.) When either bound is reached, score generation ends. At least one of these two parameters must be specified or an error is raised. These keyword parameters are evaluated just once and are not copied into the parameter lists of generated notes.

    What is the duration of generated notes? The keyword dur: defaults to 1 and specifies the nominal duration in seconds. Since the generated note list is compatible with timed-seq, the starting time and duration (to be precise, the stretch factor) are not passed as parameters to the notes. Instead, they control the Nyquist environment in which the note will be evaluated.

    What is the start time of a note? The default start time of the first note is zero. Given a note, the default start time of the next note is the start time plus the inter-onset time, which is given by the ioi: parameter. If no ioi: parameter is specified, the inter-onset time defaults to the duration, given by dur:. In all cases, the default start time of a note can be overridden by the keyword parameter time:.

    When does the score begin and end? The behavior SCORE-BEGIN-END contains the beginning and ending of the score (these are used for score manipulations, e.g. when scores are merged, their begin times can be aligned.) When timed-seq is used to synthesize a score, the SCORE-BEGIN-END marker is not evaluated. The score-gen macro inserts a "note" of the form (0 0 (SCORE-BEGIN-END begin-time end-time)) at the time given by the begin: keyword, with begin-time and end-time determined by the begin: and end: keyword parameters, respectively. If the begin: keyword is not provided, the score begins at zero. If the end: keyword is not provided, the score ends at the default start time of what would be the next note after the last note in the score (as described in the previous paragraph). Note: if time: is used to compute note starting times, and these times are not increasing, it is strongly advised to use end: to specify an end time for the score, because the default end time may be anywhere in the middle of the generated sequence.

    What function is called to synthesize the note? The name: parameter names the function. Like other parameters, the value can be any expression, including something like next(fn-name-pattern), allowing function names to be recomputed for each note. The default value is note.

    Can I make parameters depend upon the starting time or the duration of the note? Parameter expressions can use the variable sg:time to access the start time of the note, sg:ioi to access the inter-onset time, and sg:dur to access the duration (stretch factor) of the note. Also, sg:count counts how many notes have been computed so far, starting at 0. The order of computation is: sg:time first, then sg:ioi and sg:dur, so for example, an expression to compute sg:dur can depend on sg:ioi.

    Can parameters depend on each other? The keyword pre: introduces an expression that is evaluated before each note, and post: provides an expression to be evaluated after each note. The pre: expression can assign one or more global variables which are then used in one or more expressions for parameters.

    How do I debug score-gen expressions? You can set the trace: parameter to true (t) to enable a print statement for each generated note.

    How can I save scores generated by score-gen that I like? If the keyword parameter save: is set to a symbol, the global variable named by the symbol is set to the value of the generated sequence. Of course, the value returned by score-gen is just an ordinary list that can be saved like any other value.

    In summary, the following keywords have special interpretations in score-gen: begin:, end:, time:, dur:, name:, ioi:, trace:, save:, score-len:, score-dur:, pre:, post:. All other keyword parameters are expressions that are evaluated once for each note and become the parameters of the notes.

    Score Manipulation

    Nyquist encourages the representation of music as executable programs, or behaviors, and there are various ways to modify behaviors, including time stretching, transposition, etc. An alternative to composing executable programs is to manipulate scores as editable data. Each approach has its strengths and weaknesses. This section describes functions intended to manipulate Xmusic scores as generated by, or at least in the form generated by, score-gen. Recall that this means scores are lists of events (e.g. notes), where events are three-element lists of the form (time duration expression, and where expression is a standard lisp function call where all parameters are keyword parameters. In addition, the first "note" may be the special SCORE-BEGIN-END expression. If this is missing, the score begins at zero and ends at the end of the last note.

    For convenience, a set of functions is offered to access properties of events (or notes) in scores. Although lisp functions such as car, cadr, and caddr can be used, code is more readable when more mnemonic functions are used to access events.

    event-time(event) [SAL]
    (event-time event) [LISP]
    Retrieve the time field from an event.

    event-set-time(event, time) [SAL]
    (event-set-time event time) [LISP]
    Construct a new event where the time of event is replaced by time.

    event-dur(event) [SAL]
    (event-dur event) [LISP]
    Retrieve the duration (i.e. the stretch factor) field from an event.

    event-set-dur(event, dur) [SAL]
    (event-set-dur event dur) [LISP]
    Construct a new event where the duration (or stretch factor) of event is replaced by dur.

    event-expression(event) [SAL]
    (event-expression event) [LISP]
    Retrieve the expression field from an event.

    event-set-expression(event, dur) [SAL]
    (event-set-expression event dur) [LISP]
    Construct a new event where the expression of event is replaced by expression.

    event-end(event) [SAL]
    (event-end event) [LISP]
    Retrieve the end time of event, its time plus its duration.

    expr-has-attr(expression, attribute) [SAL]
    (expr-has-attr expression attribute) [LISP]
    Test whether a score event expression has the given attribute.

    expr-get-attr(expression, attribute [, default]) [SAL]
    (expr-get-attr expression attribute [default]) [LISP]
    Get the value of the given attribute from a score event expression. If attribute is not present, return default if specified, and otherwise nil.

    expr-set-attr(expr, attribute, value) [SAL]
    (expr-set-attr expr attribute value) [LISP]
    Construct a new expression identical to expr except that the attribute has value.

    event-has-attr(event, attribute) [SAL]
    (event-has-attr event attribute) [LISP]
    Test whether a given score event's expression has the given attribute.

    event-get-attr(event, attribute, [default]) [SAL]
    (event-get-attr event attribute [default]) [LISP]
    Get the value of the given attribute from a score event's expression. If attribute is not present, return default if specified, and otherwise nil.

    event-set-attr(event, attribute, value) [SAL]
    (event-set-attr event attribute value) [LISP]
    Construct a new event identical to event except that the attribute has value.

    Functions are provided to shift the starting times of notes, stretch times and durations, stretch only durations, add an offset to a keyword parameter, scale a keyword parameter, and other manipulations. Functions are also provided to extract ranges of notes, notes that match criteria, and to combine scores. Most of these functions (listed below in detail) share a set of keyword parameters that optionally limit the range over which the transformation operates. The from-index: and to-index: parameters specify the index of the first note and the index of the last note to be changed. If these numbers are negative, they are offsets from the end of the score, e.g. -1 denotes the last note of the score. The from-time: and to-time: indicate a range of starting times of notes that will be affected by the manipulation. Only notes whose time is greater than or equal to the from-time and strictly less than the to-time are modified. If both index and time ranges are specified, only notes that satisfy both constraints are selected. (Note: in LISP syntax, colons precede the keyword, so use :from-index, :to-index, :from-time, and :to-time.)

    score-sorted(score) [SAL]
    (score-sorted score) [LISP]
    Test if score is sorted.

    score-sort(score [, copy-flag]) [SAL]
    (score-sort score [copy-flag]) [LISP]
    Sort the notes in a score into start-time order. If copy-flag is nil, this is a destructive operation which should only be performed if the top-level score list is a fresh copy that is not shared by any other variables. (The copy-flag is intended for internal system use only.) For the following operations, it is assumed that scores are sorted, and all operations return a sorted score.

    score-shift(score, offset, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-shift score offset :from-index i :to-index j :from-time x :to-time y) [LISP]
    Add a constant offset to the starting time of a set of notes in score. By default, all notes are modified, but the range of notes can be limited with the keyword parameters. The begin time of the score is not changed, but the end time is increased by offset. The original score is not modified, and a new score is returned.

    score-stretch(score, factor, dur: dur-flag, time: time-flag, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-stretch score factor :dur dur-flag :time time-flag :from-index i :to-index j :from-time x :to-time y) [LISP]
    Stretch note times and durations by factor. The default dur-flag is non-null, but if dur-flag is null, the original durations are retained and only times are stretched. Similarly, the default time-flag is non-null, but if time-flag is null, the original times are retained and only durations are stretched. If both dur-flag and time-flag are null, the score is not changed. If a range of notes is specified, times are scaled within that range, and notes after the range are shifted so that the stretched region does not create a "hole" or overlap with notes that follow. If the range begins or ends with a time (via from-time: and to-time:), time stretching takes place over the indicated time interval independent of whether any notes are present or where they start. In other words, the "rests" are stretched along with the notes. The original score is not modified, and a new score is returned.

    score-transpose(score, keyword, amount, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-transpose score keyword amount :from-index i :to-index j :from-time x :to-time y) [LISP]
    For each note in the score and in any indicated range, if there is a keyword parameter matching keyword and the parameter value is a number, increment the parameter value by amount. For example, to tranpose up by a whole step, write (score-transpose 2 :pitch score). The original score is not modified, and a new score is returned.

    score-scale(score, keyword, amount, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-scale score keyword amount :from-index i :to-index j :from-time x :to-time y) [LISP]
    For each note in the score and in any indicated range, if there is a keyword parameter matching keyword and the parameter value is a number, multiply the parameter value by amount. The original score is not modified, and a new score is returned.

    score-sustain(score, factor, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-sustain score factor :from-index i :to-index j :from-time x :to-time y) [LISP]
    For each note in the score and in any indicated range, multiply the duration (stretch factor) by amount. This can be used to make notes sound more legato or staccato, and does not change their starting times. The original score is not modified, and a new score is returned.

    score-voice(score, replacement-list, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-voice score replacement-list :from-index i :to-index j :from-time x :to-time y) [LISP]
    For each note in the score and in any indicated range, replace the behavior (function) name using replacement-list, which has the format: ((old1 new1) (old2 new2) ...), where oldi indicates a current behavior name and newi is the replacement. If oldi is *, it matches anything. For example, to replace my-note-1 by trombone and my-note-2 by horn, use score-voice(score, {{my-note-1 trombone} {my-note-2 horn}}). To replace all instruments with piano, use score-voice(score, {{* piano}}). The original score is not modified, and a new score is returned.

    score-merge(score1, score2, ...) [SAL]
    (score-merge score1 score2 ...) [LISP]
    Create a new score containing all the notes of the parameters, which are all scores. The resulting notes retain their original times and durations. The merged score begin time is the minimum of the begin times of the parameters and the merged score end time is the maximum of the end times of the parameters. The original scores are not modified, and a new score is returned.

    score-append(score1, score2, ...) [SAL]
    (score-append score1 score2 ...) [LISP]
    Create a new score containing all the notes of the parameters, which are all scores. The begin time of the first score is unaltered. The begin time of each other score is aligned to the end time of the previous score; thus, scores are "spliced" in sequence. The original scores are not modified, and a new score is returned.

    score-select(score, predicate, from-index: i, to-index: j, from-time: x, to-time: y, reject: flag) [SAL]
    (score-select score predicate :from-index i :to-index j :from-time x :to-time y :reject flag) [LISP]
    Select (or reject) notes to form a new score. Notes are selected if they fall into the given ranges of index and time and they satisfy predicate, a function of three parameters that is applied to the start time, duration, and the expression of the note. Alternatively, predicate may be t, indicating that all notes in range are to be selected. The selected notes along with the existing score begin and end markers, are combined to form a new score. Alternatively, if the reject: parameter is non-null, the notes not selected form the new score (in other words the selected notes are rejected or removed to form the new score). The original score is not modified, and a new score is returned.

    score-set-begin(score, time) [SAL]
    (score-set-begin score time) [LISP]
    The begin time from the score's SCORE-BEGIN-END marker is set to time. The original score is not modified, and a new score is returned.

    score-get-begin(score) [SAL]
    (score-get-begin score) [LISP]
    Return the begin time of the score.

    score-set-end(score, time) [SAL]
    (score-set-end score time) [LISP]
    The end time from the score's SCORE-BEGIN-END marker is set to time. The original score is not modified, and a new score is returned.

    score-get-end(score) [SAL]
    (score-get-end score) [LISP]
    Return the end time of the score.

    score-must-have-begin-end(score) [SAL]
    (score-must-have-begin-end score) [LISP]
    If score does not have a begin and end time, construct a score with a SCORE-BEGIN-END expression and return it. If score already has a begin and end time, just return the score. The orignal score is not modified.

    score-filter-length(score, cutoff) [SAL]
    (score-filter-length score cutoff) [LISP]
    Remove notes that extend beyond the cutoff time. This is similar to score-select, but the here, events are removed when their nominal ending time (start time plus duration) exceeds the cutoff, whereas the to-time: parameter is compared to the note's start time. The original score is not modified, and a new score is returned.

    score-repeat(score, n) [SAL]
    (score-repeat score n) [LISP]
    Make a sequence of n copies of score. Each copy is shifted to that it's begin time aligns with the end time of the previous copy, as in score-append. The original score is not modified, and a new score is returned.

    score-stretch-to-length(score, length) [SAL]
    (score-stretch-to-length score length) [LISP]
    Stretch the score so that the end time of the score is the score's begin time plus length. The original score is not modified, and a new score is returned.

    score-filter-overlap(score) [SAL]
    (score-filter-overlap score) [LISP]
    Remove overlapping notes (based on the note start time and duration), giving priority to the positional order within the note list (which is also time order). The original score is not modified, and a new score is returned.

    score-print(score) [SAL]
    (score-print score) [LISP]
    Print a score with one note per line. Returns nil.

    score-play(score) [SAL]
    (score-play score) [LISP]
    Play score using timed-seq to convert the score to a sound, and play to play the sound.

    score-adjacent-events(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-adjacent-events score function :from-index i :to-index j :from-time x :to-time y) [LISP]
    Call (function A B C), where A, B, and C are consecutive notes in the score. The result replaces B. If the result is nil, B is deleted, and the next call will be (function A C D), etc. The first call is to (function nil A B) and the last is to (function Y Z nil). If there is just one note in the score, (function nil A nil) is called. Function calls are not made if the note is outside of the indicated range. This function allows notes and their parameters to be adjusted according to their immediate context. The original score is not modified, and a new score is returned.

    score-apply(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-apply score function :from-index i :to-index j :from-time x :to-time y) [LISP]
    Replace each note in the score with the result of (function time dur expression) (in Lisp) or function(time, dur, expression) (in SAL), where time, dur, and expression are the time, duration, and expression of the note. If a range is indicated, only notes in the range are replaced. The original score is not modified, and a new score is returned.

    score-indexof(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-indexof score function :from-index i :to-index j :from-time x :to-time y) [LISP]
    Return the index (position) of the first score event (in range) for which applying function using (function time dur expression) returns true.

    score-last-indexof(score, function, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-last-indexof score function :from-index i :to-index j :from-time x :to-time y) [LISP]
    Return the index (position) of the last score event (in range) for which applying function using (function time dur expression) returns true.

    score-randomize-start(score, amt, from-index: i, to-index: j, from-time: x, to-time: y) [SAL]
    (score-randomize-start score amt :from-index i :to-index j :from-time x :to-time y) [LISP]
    Alter the start times of notes by a random amount up to plus or minus amt. The original score is not modified, and a new score is returned.

    Xmusic and Standard MIDI Files

    Nyquist has a general facility to read and write MIDI files. You can even translate to and from a text representation, as described in Chapter "MIDI, Adagio, and Sequences". It is also useful sometimes to read notes from Standard MIDI Files into Xmusic scores and vice versa. At present, Xmusic only translates notes, ignoring the various controls, program changes, pitch bends, and other messages.

    MIDI notes are translated to Xmusic score events as follows:

    (time dur (NOTE :chan channel :pitch keynum :vel velocity)),
    where channel, keynum, and velocity come directly from the MIDI message (channels are numbered starting from zero). Note also that note-off messages are implied by the stretch factor dur which is duration in seconds.

    score-read-smf(filename) [SAL]
    (score-read-smf filename) [LISP]
    Read a standard MIDI file from filename. Return an Xmusic score, or nil if the file could not be opened. The start time is zero, and the end time is the maximum end time of all notes. A very limited interface is offered to extract MIDI program numbers from the file: The global variable *rslt* is set to a list of MIDI program numbers for each channel. E.g. if *rslt* is (0 20 77), then program for channel 0 is 0, for channel 1 is 20, and for channel 2 is 77. Program changes were not found on other channels. The default program number is 0, so in this example, it is not known whether the program 0 on channel 0 is the result of a real MIDI program change command or just a default value. If more than one program change exists on a channel, the last program number is recorded and returned, so this information will only be completely correct when the MIDI file sends single program change per channel before any notes are played. This, however, is a fairly common practice. Note that the list returned as *rslt* can be passed to score-write-smf, described below.

    score-write-smf(score, filename, [programs]) [SAL]
    (score-write-smf score filename programs) [LISP]
    Write a standard MIDI file to filename with notes in score. In this function, every event in the score with a pitch: attribute, regardless of the "instrument" (or function name), generates a MIDI note, using the chan: attribute for the channel (default 0) and the vel: attribute for velocity (default 100). There is no facility (in the current implementation) to issue control changes, but to allow different instruments, MIDI programs may be set in two ways. The simplest is to associate programs with channels using the optional programs parameter, which is simply a list of up to 16 MIDI program numbers. Corresponding program change commands are added to the beginning of the MIDI file. If programs has less than 16 elements, program change commands are only sent on the first n channels. The second way to issue MIDI program changes is to add a program: keyword parameter to a note in the score. Typically, the note will have a pitch: of nil so that no actual MIDI note-on message is generated. If program changes and notes have the same starting times, their relative playback order is undefined, and the note may be cut off by an immediately following program change. Therefore, program changes should occur slightly, e.g. 1 ms, before any notes. Program numbers and channels are numbered starting at zero, matching the internal MIDI representation. This may be one less than displayed on MIDI hardware, sequencers, etc.

    Workspaces

    When working with scores, you may find it necessary to save them in files between work sessions. This is not an issue with functions because they are normally edited in files and loaded from them. In contrast, scores are created as Lisp data, and unless you take care to save them, they will be destroyed when you exit the Nyquist program.

    A simple mechanism called a workspace has been created to manage scores (and any other Lisp data, for that matter). A workspace is just a set of lisp global variables. These variables are stored in the file workspace.lsp. For simplicity, there is only one workspace, and no backups or versions are maintained, but the user is free to make backups and copies of workspace.lsp. To help remember what each variable is for, you can also associate and retrieve a text string with each variable. The following functions manage workspaces.

    In addition, when a workspace is loaded, you can request that functions be called. For example, the workspace might store descriptions of a graphical interface. When the workspace is loaded, a function might run to convert saved data into a graphical interface. (This is how sliders are saved by the IDE.)

    add-to-workspace(symbol) [SAL]
    (add-to-workspace symbol) [LISP]
    Adds a global variable to the workspace. The symbol should be a (quoted) symbol.

    save-workspace() [SAL]
    (save-workspace) [LISP]
    All global variables in the workspace are saved to workspace.lsp (in the current directory), overwriting the previous file.

    describe(symbol [, description]) [SAL]
    (describe symbol [description)] [LISP]
    If description, a text string, is present, associate description with the variable named by the symbol. If symbol is not already in the workspace, it is added. If description is omitted, the function returns the current description (from a previous call) for symbol.

    add-action-to-workspace(symbol) [SAL]
    (add-action-to-workspace symbol) [LISP]
    Requests that the function named by symbol be called when the workspace is loaded (if the function is defined).

    To restore a workspace, use the command load "workspace". This restores the values of the workspace variables to the values they had when save-workspace was last called. It also restores the documentation strings, if set, by describe. If you load two or more workspace.lsp files, the variables will be merged into a single workspace. The current set of workspace variables are saved in the list *workspace*. To clear the workspace, set *workspace* to nil. This does not delete any variables, but means that no variables will be saved by save-workspace until variables are added again.

    Functions to be called are saved in the list *workspace-actions*. to clear the functions, set *workspace-actions* to nil. Restore functions to the list with add-action-to-workspace.

    Utility Functions

    This chapter concludes with details of various utility functions for score manipulation.

    patternp(expression) [SAL]
    (patternp expression) [LISP]
    Test if expression is an Xmusic pattern.

    params-transpose(params, keyword, amount) [SAL]
    (params-transpose params keyword amount) [LISP]
    Add a transposition amount to a score event parameter. The params parameter is a list of keyword/value pairs (not preceded by a function name). The keyword is the keyword of the value to be altered, and amount is a number to be added to the value. If no matching keyword is present in params, then params is returned. Otherwise, a new parameter list is constructed and returned. The original params is not changed.

    params-scale(params, keyword, amount) [SAL]
    (params-scale params keyword amount) [LISP]
    Scale a score event parameter by some factor. This is like params-transpose, only using multiplication. The params list is a list of keyword/value pairs, keyword is the parameter keyword, and amount is the scale factor.

    interpolate(x, x1, y1, x2, y2) [SAL]
    (interpolate x x1 y1 x2 y2) [LISP]
    Linearly interpolate (or extrapolate) between points (x1, y1) and (x2, y2) to compute the y value corresponding to x.

    intersection(a, b) [SAL]
    (intersection a b) [LISP]
    Compute the set intersection of lists a and b.

    union(a, b) [SAL]
    (union a b) [LISP]
    Compute the set union of lists a and b.

    set-difference(a, b) [SAL]
    (set-difference a b) [LISP]
    Compute the set of all elements that are in a but not in b.

    subsetp(a, b) [SAL]
    (subsetp a b) [LISP]
    Returns true iff a is a subset of b, that is, each element of a is a member of b.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/bernoulli-fig.gif0000644000175000000620000000641711466723256016201 0ustar stevestaffGIF89a)]w1!Software: Microsoft Office!,SMMM|||hhh` dihlp,tm|pH,Ȥrl:@tJZجV+zxz]5q|\Nrv%^R;$ :?Ch&%s]]Cc ʁ] " "  ܥR"# ]uG7ۘJAfUnC (8@v,>t1_tZ86: &\$Q!}IG- 7N(!ip>I@N/v5L#7 ΰyŹWNbM"`nHB#Mf]IIxmF!f[0 5Vu03glR+:_ۮmnV!ϪnJ4:`{L'zC5)BLyn=47Y[F,{FΗ)AO8/`1z_qLRH@LLK.h~wIw0UQ.m""׈HKs"D4jX8>!c<ָc@cDj2dHFrdLF4. }HI啞Oi)f"Vie&im)'qi^ީ'y'})(j(& 6Qgv> Nf=ɘ*ZJͪ)ثp뮼+k&,Q < Vkfv+#*њ+֋-Ȋ,kY' 7lpg7,Wúiw<1/$L/ȕ]ѯ,j4rn"׬\<->{H'o+2-3TWݭ*[bm\]9mdSl 6mvYmwoC|wb& E*+;~:D;*{nF n^.޲5_/_{'o|M+|+1boILO= k-)n/w/m~觏03?agwH:J}GL =93P#e5DKIdQ@X~R_tly.k/W>,) %d|a3LEzt_5=vbX7c<+kDɝsc7 r:)L-I5,&,X< z>.t"HJASh(:->˞kԨ8*-+"ݨ>a$}@9QRtYnԦ++Mկv _ֺu-e TIx&06A*ԎVfS7:ލ"FL6 ^g)ݮ8k3<\<߉;cx?co}*GjcJyL*/ø8爋&D F9 ze:s9m,gu/Fk=CX3 Mcf1泛mi]xȕGWaM pv\γum'J:ȈHkP˴ș2+ lVźo}ScѶ5Mi#tWԮ naWz~o]l^ن5wMnG kwܜwc? W.O3q.\Q?=qzD=Svql[;䰅8s]yk%me雯m~r:zq >?eҳ>;}~n(~oJ5~W~ rۦ~8uVthvxy7v%h~'~#yuhX1x xt/5HWhthwaԷs;8x3"WDMZP[Q(TequOX5`cEXgjl؆npȆYhbC'uxكJ(=vȇzs`~X{H}+CxHh81xr)w)%XWr8%OҊ$H2H$2Xh)d5abPm aYʨ62H@('B)Hݨ#RU)ԋ=( c0jepaxm{ǨrxPӡ6$w'bDCȐu&)$&''(訒38)&#.)<3 9)7;#7=C#X "A)ؐٔ 0Y$nKy7Z%Sٕ`b9@•fe6ln^)ti vyz) qٗ#—9h򗈉{٘闑)9ٙ)!;nyquist-3.05/doc/part7.html0000644000175000000620000007362611537432671014702 0ustar stevestaffSAL Previous Section | Next Section | Table of Contents | Index | Title Page

    SAL

    Nyquist supports two languages: XLISP and SAL. In some sense, XLISP and SAL are the same language, but with differing syntax. This chapter describes SAL: how it works, SAL syntax and semantics, and the relationship between SAL and XLISP, and differences between Nyquist SAL and Common Music SAL.

    Nyquist SAL is based on Rick Taube's SAL language, which is part of Common Music. SAL offers the power of Lisp but features a simple, Algol-like syntax. SAL is implemented in Lisp: Lisp code translates SAL into a Lisp program and uses the underlying Lisp engine to evaluate the program. Aside from the translation time, which is quite fast, SAL programs execute at about the same speed as the corresponding Lisp program. (Nyquist SAL programs run just slightly slower than XLISP because of some runtime debugging support automatically added to user programs by the SAL compiler.)

    From the user's perspective, these implementation details are hidden. You can enter SAL mode from XLISP by typing (SAL) to the XLISP prompt. The SAL input prompt (SAL> ) will be displayed. From that point on, you simply type SAL commands, and they will be executed. By setting a preference in the NyquistIDE program, SAL mode will be entered automatically.

    It is possible to encounter errors that will take you from the SAL interpreter to an XLISP prompt. In general, the way to get back to SAL is by typing (top) to get back to the top level XLISP interpreter and reset the Nyquist environment. Then type (sal) to restart the SAL interpreter.

    SAL Syntax and Semantics

    The most unusual feature of SAL syntax is that identifiers are Lisp-like, including names such as "play-file" and even "*warp*." In SAL, most operators must be separated from identifiers by white space. For example, play-file is one identifier, but play - file is an expression for "play minus file," where play and file are two separate identifiers. Fortunately, no spaces are needed around commas and parentheses.

    In SAL, whitespace (any sequence of space, newline, or tab characters) is sometimes necessary to separate lexical tokens, but otherwise, spaces and indentation are ignored. To make SAL readable, it is strongly advised that you indent SAL programs as in the examples here. The NyquistIDE program is purposely insistent about SAL indentation, so if you use it to edit SAL programs, your indentation should be both beautiful and consistent.

    As in Lisp (but very unlike C or Java), comments are indicated by semicolons. Any text from an unquoted semicolon to the end of the line is ignored.

    ; this is a comment
    ; comments are ignored by the compiler
    print "Hello World" ; this is a SAL statement
    

    As in Lisp, identifiers are translated to upper-case, making SAL case-insensitive. For example, the function name autonorm can be typed in lower case or as AUTONORM, AutoNorm, or even AuToNoRm. All forms denote the same function. The recommended approach is to write programs in all lower case.

    SAL is organized around statements, most of which contain expressions. We will begin with expressions and then look at statements.

    Expressions

    Simple Expressions
    As in XLISP, simple expressions include:
    • integers (FIXNUM's), such as 1215,
    • floats (FLONUM's) such as 12.15,
    • strings (STRING's) such as "Magna Carta", and
    • symbols (SYMBOL's) such as magna-carta. A symbol with a leading colon (:) evaluates to itself as in Lisp. Otherwise, a symbol denotes either a local variable, a formal parameter, or a global variable. As in Lisp, variables do not have data types or type declarations. The type of a variable is determined at runtime by its value.

    Additional simple expressions in SAL are:

    A curious property of Lisp and Sal is that false and the empty list are the same value. Since SAL is based on Lisp, #f and {} (the empty list) are equal.

    Operators
    Expressions can be formed with unary and binary operators using infix notation. The operators are: Again, remember that operators must be delimited from their operands using spaces or parentheses. Operator precedence is based on the following levels of precedence:
    @ @@ ~ ~~
    ^
    / * 
    % - +
    ~= <= >= > ~= =
    !
    &
    |
    

    Function Calls
    A function call is a function name followed by zero or more comma-delimited argument expressions enclosed within parentheses:
    list()
    piano-note(2.0, c4 + interval, 100)
    
    Some functions use named parameters, in which case the name of the argument with a colon precedes the argument expression.
    s-save(my-snd(), ny:all, "tmp.wav", play: #t, bits: 16)
    

    Array Notation
    An array reference is a variable identifier followed by an index expression in square brackets, e.g.:
    x[23] + y[i]
    

    Conditional Values
    The special operator #? evaluates the first argument expression. If the result is true, the second expression is evaluated and its value is returned. If false, the third expression is evaluated and returned (or false is returned if there is no third expression):
    #?(random(2) = 0, unison, major-third)
    #?(pitch >= c4, pitch - c4) ; returns false if pitch < c4
    

    SAL Statements

    SAL compiles and evaluates statements one at a time. You can type statements at the SAL prompt or load a file containing SAL statements. SAL statements are described below. The syntax is indicated at the beginning of each statement type description: this font indicates literal terms such as keywords, the italic font indicates a place-holder for some other statement or expression. Bracket [like this] indicate optional (zero or one) syntax elements, while braces with a plus {like this}+ indicate one or more occurrences of a syntax element. Braces with a star {like this}* indicate zero or more occurrences of a syntax element: { non-terminal }* is equivalent to [ {non-terminal}+ ].

    begin and end
    begin [with-stmt] {statement}+ end

    A begin-end statement consists of a sequence of statements surrounded by the begin and end keywords. This form is often used for function definitions and after then or else where the syntax demands a single statement but you want to perform more than one action. Variables may be declared using an optional with statement immediately after begin. For example:

    begin
      with db = 12.0,
           linear = db-to-linear(db)
      print db, "dB represents a factor of", linear
      set scale-factor = linear
    end  
    

    chdir
    chdir expression

    The chdir statement changes the working directory. This statement is provided for compatibility with Common Music SAL, but it really should be avoided if you use NyquistIDE. The expression following the chdir keyword should evaluate to a string that is a directory path name. Note that literal strings themselves are valid expressions.

    chdir "/Users/rbd/tmp"
    

    define variable
    [define] variable name [= expression] {, name [= expression]}*

    Global variables can be declared and initialized. A list of variable names, each with an optional initialization follows the define variable keywords. (Since variable is a keyword, define is redundant and optional in Nyquist SAL, but required in Common Music SAL.) If the initialization part is omitted, the variable is initialized to false. Global variables do not really need to be declared: just using the name implicitly creates the corresponding variable. However, it is an error to use a global variable that has not been initialized; define variable is a good way to introduce a variable (or constant) with an initial value into your program.

    define variable transposition = 2,
                    print-debugging-info, ; initially false
                    output-file-name = "salmon.wav"
    

    define function
    [define] function name ( [parameter], {, parameter}* ) statement

    Before a function be called from an expression (as described above), it must be defined. A function definition gives the function name, a list of parameters, and a statement. When a function is called, the actual parameter expressions are evaluated from left to right and the formal parameters of the function definition are set to these values. Then, statement is evaluated.

    The formal parameters may be positional parameters that are matched with actual parameters by position from left to right. Syntactically, these are symbols and these symbols are essentially local variables that exist only until statement completes or a return statement causes the function evaluation to end. As in Lisp, parameters are passed by value, so assigning a new value to a formal parameter has no effect on the actual value. However, lists and arrays are not copied, so internal changes to a list or array produce observable side effects.

    Alternatively, formal parameters may be keyword parameters. Here the parameter is actually a pair: a keyword parameter, which is a symbol followed by a colon, and a default value, given by any expression. Within the body of the function, the keyword parameter is named by a symbol whose name matches the keyword parameter except there is no final colon.

    define function foo(x: 1, y: bar(2, 3))
        display "foo", x, y
    

    exec foo(x: 6, y: 7)

    In this example, x is bound to the value 6 and y is bound to the value 7, so the example prints "foo : X = 6, Y = 7". Note that while the keyword parameters are x: and y:, the corresponding variable names in the function body are x and y, respectively.

    The parameters are meaningful only within the lexical (static) scope of statement. They are not accessible from within other functions even if they are called by this function.

    Use a begin-end statement if the body of the function should contain more than one statement or you need to define local variables. Use a return statement to return a value from the function. If statement completes without a return, the value false is returned.

    display
    display string {, expression}*

    The display statement is handy for debugging. At present, it is only implemented in Nyquist SAL. When executed, display prints the string followed by a colon and then, for each expression, the expression and its value are printed, after the last expression, a newline is printed. For example,

    display "In function foo", bar, baz
    
    prints
    In function foo : bar = 23, baz = 5.3
    
    SAL may print the expressions using Lisp syntax, e.g. if the expression is "bar + baz," do not be surprised if the output is "(sum bar baz) = 28.3."

    exec
    exec expression

    Unlike most other programming languages, you cannot simply type an expression as a statement. If you want to evaluate an expression, e.g. call a function, you must use an exec statement. The statement simply evaluates the expression. For example,

    exec set-sound-srate(22050.0) ; change default sample rate
    

    if
    if test-expr then true-stmt [else false-stmt]

    An if statement evaluates the expression test-expr. If it is true, it evaluates the statement true-stmt. If false, the statement false-stmt is evaluated. Use a begin-end statement to evaluate more than one statement in then then or else parts.

    if x < 0 then x = -x ; x gets its absoute value
    

    if x > upper-bound then begin print "x too big, setting to", upper-bound x = upper-bound end else if x < lower-bound then begin print "x too small, setting to", lower-bound x = lower-bound end

    Notice in this example that the else part is another if statement. An if may also be the then part of another if, so there could be two possible if's with which to associate an else. An else clause always associates with the closest previous if that does not already have an else clause.

    when
    when test statement

    The when statement is similar to if, but there is no else clause.

    when *debug-flag* print "you are here"
    

    unless
    unless test statement

    The unless statement is similar to when (and if) but the statement is executed when the test expression is false.

    unless count = 0 set average = sum / count
    

    load
    load expression

    The load command loads a file named by expression, which must evauate to a string path name for the file. To load a file, SAL interprets each statement in the file, stopping when the end of the file or an error is encountered. If the file ends in .lsp, the file is assumed to contain Lisp expressions, which are evaluated by the XLISP interpreter. In general, SAL files should end with the extension .sal.

    loop
    loop [with-stmt] {stepping}* {stopping* action+ [finally] end

    The loop statement is by far the most complex statement in SAL, but it offers great flexibility for just about any kind of iteration. The basic function of a loop is to repeatedly evaluate a sequence of action's which are statements. Before the loop begins, local variables may be declared in with-stmt, a with statement.

    The stepping clauses do several things. They introduce and initialize additional local variables similar to the with-stmt. However, these local variables are updated to new values after the action's. In addition, some stepping clauses have associated stopping conditions, which are tested on each iteration before evaluating the action's.

    There are also stopping clauses that provide additional tests to stop the iteration. These are also evaluated and tested on each iteration before evaluating the action's.

    When some stepping or stopping condition causes the iteration to stop, the finally clause is evaluated (if present). Local variables and their values can still be accessed in the finally clause. After the finally clause, the loop statement completes.

    The stepping clauses are the following:

    repeat expression
    Sets the number of iterations to the value of expression, which should be an integer (FIXNUM).

    for var = expression [ then expr2 ]
    Introduces a new local variable named var and initializes it to expression. Before each subsequent iteration, var is set to the value of expr2. If the then part is omitted, expression is re-evaluated and assigned to var on each subsequent iteration. Note that this differs from a with-stmt where expressions are evaluated and variables are only assigned their values once.

    for var in expression
    Evaluates expression to obtain a list and creates a new local variable initialized to the first element of the list. After each iteration, var is assigned the next element of the list. Iteration stops when var has assumed all values from the list. If the list is initially empty, the loop action's are not evaluated (there are zero iterations).

    for var [from from-expr] [[to | below | downto | above] to-expr] [by step-expr]
    Introduces a new local variable named var and intialized to the value of the expression from-expr (with a default value of 0). After each iteration of the loop, var is incremented by the value of step-expr (with a default value of 1). The iteration ends when var is greater than the value of to-expr if there is a to clause, greater than or equal to the value of to-expr if there is a below clause, less than the value of to-expr if there is a downto clause, or less than or equal to the value of to-expr if there is a above clause. (In the cases of downto and above, the default increment value is -1. If there is no to, below, downto, above, or below clause, no interation stop test is created for this stepping clause.

    The stopping clauses are the following:

    while expression
    The iterations are stopped when expression evaluates to false. Anything not false is considered to mean true.

    until expression
    The iterations are stopped when expression evaluates to true.

    The finally clause is defined as follows:

    finally statement
    The statement is evaluated when one of the stepping or stopping clauses ends the loop. As always, statement may be a begin-end statement. If an action evaluates a return statement, the finally statement is not executed.

    Loops often fall into common patterns, such as iteratiing a fixed number of times, performing an operation on some range of integers, collecting results in a list, and linearly searching for a solution. These forms are illustrated in the examples below.

    ; iterate 10 times
    loop
      repeat 10
      print random(100)
    end
    

    ; print even numbers from 10 to 20 ; note that 20 is printed. On the next iteration, ; i = 22, so i >= 22, so the loop exits. loop for i from 10 to 22 by 2 print i end

    ; collect even numbers in a list loop with lis for i = 0 to 10 by 2 set lis @= i ; push integers on front of list, ; which is much faster than append, ; but list is built in reverse finally result = reverse(lis) end ; now, the variable result has a list of evens

    ; find the first even number in a list result = #f ; #f means "false" loop for elem in lis until evenp(elem) finally result = elem end ; result has first even value in lis (or it is #f)

    print
    print expr {, expr}*

    The print statement prints the values separated by spaces and followed by a newline. [Note that in the original SAL, the newline is printed before the values, not after.]

    print "The value of x is", x
    

    return
    return expression

    The return statement can only be used inside a function. It evaluates expression and then the function returns the value of the expression to its caller.

    set
    set var op expression {, var op expression}*

    The set statement changes the value of a variable var according to the operator op and the value of the expression. The operators are:

    =
    The value of expression is assigned to var.

    +=
    The value of expression is added to var.

    *=
    The value of var is multiplied by the value of the expression.

    &=
    The value of expression is inserted as the last element of the list referenced by var. If var is the empty list (denoted by #f), then var is assigned a newly constructed list of one element, the value of expression.

    ^=
    The value of expression, a list, is appended to the list referenced by var. If var is the empty list (denoted by #f), then var is assigned the (list) value of expression.

    @=
    Pushes the value of expression onto the front of the list referenced by var. If var is empty (denoted by #f), then var is assigned a newly constructed list of one element, the value of expression.

    <=
    Sets the new value of var to the minimum of the old value of var and the value of expression.

    >=
    Sets the new value of var to the maximum of the old value of var and the value of expression.

    ; example from Rick Taube's SAL description
    loop
      with a, b = 0, c = 1, d = {}, e = {}, f = -1, g = 0
      for i below 5
      set a = i, b += 1, c *= 2, d &= i, e @= i, f <= i, g >= i
      finally display "results", a, b, c, d, e, f, g
    end
    

    with
    with var [= expression] {, var [= expression]}*

    The with statement declares and initializes local variables. It can appear only after begin or loop. If the expression is omitted, the initial value is false. The variables are visible only inside the begin-end or loop statement where the with statement appears. Even in loop's the variables are intialized only when the loop is entered, not on each iteration.

    exit
    exit [nyquist]

    The exit statement is unique to Nyquist SAL. It returns from SAL mode to the XLISP interpreter. (Return to SAL mode by typing "(sal)"). If nyquist is included in the statement, then the entire Nyquist process will exit.

    Interoperability of SAL and XLISP

    When SAL evaluatas command or loads files, it translates SAL into XLISP. You can think of SAL as a program that translates everything you write into XLISP and entering it for you. Thus, when you define a SAL function, the function actually exists as an XLISP function (created using Lisp's defun special form). When you set or evaluate global variables in SAL, these are exactly the same Lisp global variables. Thus, XLISP functions can call SAL functions and vice-versa. At run time, everything is Lisp.

    Function Calls

    In general, there is a very simple translation from SAL to Lisp syntax and back. A function call is SAL, for example,
    osc(g4, 2.0)
    
    is translated to Lisp by moving the open parenthesis in front of the function name and removing the commas:
    (osc g4 2.0)
    
    Similarly, if you want to translate a Lisp function call to SAL, just reverse the translation.

    Symbols and Functions

    SAL translates keywords with trailing colons (such as foo:) into Lisp keywords with leading colons (such as :foo), but SAL keywords are not treated as expressions as they are in Lisp. You cannot write open("myfile.txt", direction: output:) because SAL expects an expression after direction. A special form keyword is defined to generate a Lisp keyword as an expression. The argument is the keyword without a colon, e.g. open("myfile.txt", direction: keyword(output)). Alternatively, you can write the Lisp-style keyword with the leading colon, e.g. open("myfile.txt", direction: :output).

    In Nyquist SAL, the hash character (#), can be used as a prefix to a Lisp function name. For example, the following command is not legal because print is a SAL command name, not a legal function name: set v = append(print(a), print(b)). (Here the intent is to print arguments to append). However, you can use the hash character to access the Lisp print function: set v = append(#print(a), #print(b)).

    Playing Tricks On the SAL Compiler

    In many cases, the close coupling between SAL and XLISP gives SAL unexpected expressive power. A good example is seqrep. This is a special looping construct in Nyquist, implemented as a macro in XLISP. In Lisp, you would write something like:
    (seqrep (i 10) (pluck c4))
    
    One might expect SAL would have to define a special seqrep statement to express this, but since statements do not return values, this approach would be problematic. The solution (which is already fully implemented in Nyquist) is to define a new macro sal-seqrep that is equivalent to seqrep except that it is called as follows:
    (sal-seqrep i 10 (pluck c4))
    
    The SAL compiler automatically translates the identifier seqrep to sal-seqrep. Now, in SAL, you can just write
    seqrep(i, 10, pluck(c4))
    
    which is translated in a pretty much semantics-unaware fashion to
    (sal-seqrep i 10 (pluck c4))
    
    and viola!, we have Nyquist control constructs in SAL even though SAL is completely unaware that seqrep is actually a special form.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/moog-fig.gif0000644000175000000620000004417411466723256015151 0ustar stevestaffGIF87a\[ !!!"""###$$$%%%&&&'''((()))***+++,,,...///000111222333444555666777888:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___aaabbbcccdddeeefffggghhhiiijjjkkkmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxzzz{{{|||}}}~~~!,\[@ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲKbʌ͛8sɳϟ@ H L2-In2 kWMÊKٳhӪUXڷ#i.`R]E^ ǐ#KLʶ3;DϠCM,ҝ9^ͺװcW>-ڸsͻo-'iBI68u;-߀ opN<|%r#T(h&E5 uc]x>evQ*Aa5 VX7UA+_,Ay4a7YkaDiJ7񨖏F 閒TVi%EI^Y9EJd)Pf~%e^&bڴfI)FsJfYogM}џ&VT(d(D4w5FgsHNi^h ש;`gRՏa@ҵ"|%R -U i :j1u b܎:|z(wgk覫+kPLJL2Őn$ZdLCXK,PGI݅ib|"}?#b}1)J8C4@$i-AW$}܊-25,XQ*IoJSQ$ǿ.fܸc;5`c ڥ8_dU(mSUo JX@:ӠI@br7NZ-ٟJ,ؓQ|)`HVMr4 A8n"+g8E#d/rYL`&3%d[ A~q#!.@fJx8ޭ+{ #3@ /CB]1Q$]& D"ɔ6H $[ {Mڱ"#d2M&t\WΉ#iPL t0#$ , #9x-6w=G+RQK+#dZ-?aEdđ߁I09ȥ%t6IψKa0lVْzjX1h9rVp_"#nNͨF7юz ͨD&qI̹tzG$L#bT,'D4җRt@ *zBD&aN\z B)D9a*u ծT*prPD4JD- ;۩Ք ԃk X%ֆX$XI[ՑՃ{=[ 5Que]GWX: Zɑ )F.ƃr =EݸE_ls ̚)ou-Z`ŕ\I5 6%\Q/8-2n|sx-T[P&Y]cY)h q  hH3̣` ͥ@ʓG–\)s9l1)Y\zgL9.J2 mZTS@XXz¥wb|CߐWv;&#*M0ɏ3s=x9Mc,pSɐwXqkdbyT#<Â6p Tf sγ>˙X ^LB|:WF;5~'MJ%Җδ7BFӠGԨNUհvtcMZzB^MbNf;ЎMj[ڿK&:mqvL~MŻηsp R}f?O8fw-.;w8" sGvo,01XP>7 K5uIZ/;"ny+3q_%)X6GշA?x۶@FC3Aq1v HaB#?k{+;:{Qۻ]ʨ[kX{ʻpЛ[;1auֻ۽-[;{껾2[Aa;& ([#67pC' l%( \|T>"$&l((L*!,¹ 1(OGs8\:1lr a4R`CwǴ-F0<1199}y`xZ܇ 4R=@#A#G Pr450( e22?D*!7aIn*뮩z?;Z q#統(x0ztAV)Ȍ+*;rCqYHa]0)+Aꙧ!Ca]r@ g*$p9 Hٍʽ'^a) ,k FeTΉMa~YrIbdtLay`JBMB<|OXEq<-SџGw7"6}pB?D_FHJo<^{'d  1 qxA>iD ]”6ܓ=x]4ɋA=אLCT"q[&q/>[`D^3#/9~ZO]9m24byr9B 2:m|oǠ -a=:3_5_)P?Tlx]3ߝ_Ю Q!cOR܏ߕ՟Xv?4_.a@ DPB >`$^ĘQF=~RH%MDRH,W$2m>`͙7/=H"RM>UTU9\jUֆC̹C>5zUx͈Ȍ9:Pg4@!ځu kr$v-2QXʕ-_ƜY3e=3ZhҥMFMsB0a?5+#ug7# .oqkխ_ǞjgAVkrm-A#t`miY!nx&H@\.A20B 'B /0C 7C?|!nD)Ntj:>@o1GwǜbD4h#2!!dVɵ^d&љ*%4H$K2Gt&(c.DʠD*2NĬ3O=KS5aj;4IND4CDOILA_*G/IћM@BB㯁)J?X C>4Rj0W! u(=Rc=MW7HTHaUGYĽ92%WUIߞֿKҕߡ_ .H=yАBLvŌ\U)#keV$Z m{6LobLK挌%Mji4%4!}F-i{p旧Zgm mi$MB4)8%*+#&[iϾ㎌1 9$mcFH#*lہd6Hj /-N|%&qC!P#%| X%/7k 2[}~=j:g"l>8㗲I{c:JHHy矇诇~B雤nH9@2ppE{q@l(׹85r+ g3I*M=KR*iCP1&R ,(ăB7± yYaaBw+#8uS c=)yljvX7 qb $Vw[`h$̌ 8d[TD0#cBESA4ŗ|QNxGVj|D KbE`br"WbG@%1 $9IJVҒĤ$'?6t=&3GO!Rd*UʋuEɶ|e.uˈD"%$-RJ떮e2K_.#$ !Kb<2tf6yfn#4IBMXsf:inEx(kYcН';O%yLDtӠMR;ڸ`: ,z}.ԢՎB1ϐs$䬌9wXВ.'EiJURM4&diLe:SRUE9 hsH+Z#b,A}F(Gz*NiREXj!Y]SUL$UHcHRիBJք5AbE(Y;b֏+je![GbWda &d2kTWy#ZP"lD a%q\DK1체c3 K YBGʓfFb١:9nr Tw R {R-ps؛(kr3L 8ci'q=yL[ l [F{ҵ+ }IpOрhʽ8MP!#ALg̅96+0F;R0ljurCj dP* p`gM1XLrfKR! C\Q#"Cp7lZΰ/Ҡ.0geaXbg inc4d˚+A#[C?[vfz-1~\/ϕӖ h\uj9bhpoیhOm.ޛAz$ީda/N;BOfcz6ݤj%q9w}u{d޾}7IMoD }w)8>59;5S{8G.^eZb/96N/ Fqd?zЅ>tD'U&qt7Ozԟ."4kuUzֵu7]{>~gG{ծJo{ܩvwǻw?xmx7>`5w|%? |nyw:A?zҗޫ7}UU}czG2 ~{ G|7CZ?}ꆿ&~_o?L~տ~$~ӧ2<+Td??=,:0@I_̼ ޳ @6 3͜DܥȣA A]l !#DS­`·r³)\)<*Ԋ+,-|.C dAA(|+4L[Ck@-C:; 1*23d?ľĩ ĥ2DjAURE̻FG4H\ITJĻĨD1p4ù N4DY2 E(ř@@0Q5Rx WHbloĪ⠉!p\Qi\k АŔpEPkSR?:]^|_D0p$X)`d,ChVC=Y(…H2 G0* ɵ[FYH01ǔPItɔ9țȂph ihȌ1$y 5sȉDUIJDJh aa r @ pk4Ɉx}4r]9QԈInIZJ"iʲC ѐ)[qqL$ yLp[x0ÈLYUG ُtIٌLyGTdQ?S?P]'Q%R#SUUuU0U5\e]M^ݒ_-`V#Vo2*AV0Re5fݦgehݢiVm$V)noͦp%qmr5CWgR!a$rw=4}~ *=D ؂5؃E؄U؅e؆u؇؈؉؄W|،؍؎؏ِّ%ْ5ٓEٔUY tٗ٘5k %ٜٝmٟ['- ڥ*W݈dڪ +]*Ө [I5}܌XSEZudS} mOجNM۽}MtN HM &ePÍڭuɥ\ŵ\`mr\:\}ʽզ5Z?MЀ1֝SXY3 A@Z]0lg^]g] =U^ZJތ[齎]3;ũ(de;)5#U&e,*"M&7+>@&6.AV=+ N , fA )ϱ`#~>jTu0ͻ֊j)@aۖ" +%S>C᪫ p Tg\ebt02` "A`T₨bo.1Q :cޮߌb0COD0GdzU+ 4-^.>=pJh1l]5Vrd%dr䩠Jvބݡ!Ӈ(uɋD;pm~ r#{gwR7yv z[gh hc1^}$qtR]hhGKަՐFFlRi`epҁi~N֛&ʢFiejiiNN֦f 1:&WVy2&VBjfZ"$;@VYnW&>$г{Sk{7kk>"h~'Ier숸에썦l6̎͆Ҏ.l5mBmPr2?).v.*ֆ#>R߶ n> nPf l NTM {ci҆`EMbz5nyj@RBR@P`oNH= IAFdbt9m 8F]YLlxm\ψWV߈Hb׼` 6N"ʪlyK;Ѩ/W}KRsq)ڪU:H"ӐR~Z@%âZ,#fƌ&Y}%(_?*G+ -l=.`cS4E&0obMNt- 8Om=rBJ79#LYIO4s&;.GɣS7>wœÄ+.KOX;c(=5HMGMwA3@4W{4c r}Bn=¯k/l,W܎sxKꚘ@p̔*G)x8xdm'oe>L a9o"XN3gj3yyqygR؁0>DNOex(zC8z2Iz&ٌ.@su3~1fz2z0zlY/{`p}LфuO$v#]jaB |If A|͒gw|[|/Ho-GgwOد1fz7bݟ&WSgOo5~{o|N]W羬}B~~Tw O7,h „ 2l!Ĉ'R7r| "G$ʔ*G%̘2gҬi&Μ:weϠBb;jcH#M*mJ@RRj*֬Z-֢`a"ېٴm-ܸrJJLx)vU.l0v3~1¾rVDQ`NC.m40.且+Z9MI7pӬm:6# M (g%1bh\3Gs:HʈW2<~Fӯo_wCFVDEygt}AՉ&A`DAޅ"Ew")R~+e18#5':I =@X0#(gg- us :a]^G&%a٢`O]Jw$&\:y )ЈY&$AD^(FWSk&5YGJwXA=XЕFP* !{EV+EN]zS9ؖi]APha=xˡ f녺: *t\YkNjhU,2t#//oKTA%Ӳj5[8} 0[|1۩S,<pO pZ M;c718;秎!NY^&>Y/&sB,P~ZraE4ubCy aFx5h]Fz D02wu=SChbAVO.(j"s`X{F2S)7>tzb zb 2(`DB|Үx& ڋtRg-*y F" ^h+L0a$ v;0 6k,] _r)x #2GrVG$veN@ڐ0ƈ̑&ȽIp! C1SǼ9yss(ZĬBқleDX~n<=EO,[Z!AJs24!S: P $oHIAfG`ISHFN7-Nsӝ>)P*TNFT%HiҾyJ(꩐k~?F( W&er,]PɳƩ"e BT^RY֖zrxTQT젱},d#+Rld3 IU[=*!'=eUJY!խ^=Ȑ2[ef;N BnKC%ل ` 4%ϲĨz2BUCRbND wSqAUfIRqu6YT gLjb>0uғ.j Sp;؎#gi2]H{C"WՍu}7A-D 'ѝ.+! }BjF+(^2[TM'D5ё aB,~@Y3:şTyu =QuMr$#d΁>KçdIqBeXX~ _r;N`Fn:ubJS96v Y׾V-UE`#Fڭ$JRUg*bHK*;˽wC}kw)ѶJo"7/RnT6 5nvnپWd&&x ~T%h;'ŕqhΑ rw+ S"oK%%@s>9N:ԣ.SE56dzw$(Ulot=;Ӯv=%H0.ӽvN6+9ĺn}?<}@s#^' ث">>_"|yHc. }Tg.L`}‹M ]DmnmSrD89JpT _ucf:V"!܈?NZAduesJ)5h`Fxdfq WBJ&2]ΐ槓J9(%%]S=%y'}fy#NcBȤ&]PH,muEctH_aRm)n2l֩֎Ȅ kn&(Of\!d)uy|8%DXs$e'f Oz8jԪAT52Wnl-ĂTRH)'RoTdq>)ӌNxājjHdb*IAI^ E+h\I 45,ȲH3C8fS*"T҉#plklu8+vvWPhP!ܐæFʢe,J~tOQɚ}٨&`llpicZ)!m,p`җN,~̬-mԞdbm6lzr}XSVخ8mi(m-CRYmVp+-dA-魱Bm+!UnncA8)nnanU@.H.binBn.`a:nn2n)/Ӂ9k0J,Jsm+r鶆j/Uj֯Ӓ0iܯҕp/0'7?}/O0WR1go`00[x p0 0 0H ǰ p0 0vڰh/11'+ /?71O1W1g _wS01111DZϱ101^1  !!"/$2#?2$G#G2%WrL%g& &o'17(A)2**2++2,Dz,2-ײ-2..2//20031132 D\$34G4O35W5_36g6o37w738A$@:3s:3<ظ<׳= =߳>ﳤ3?3@?4A| A'BOB/C?a44DO4E˅DW4Fg4X\FwGOGH93I4J;4KtLKǴLOLϴMtB4NM4OK4PI 5QG5R/uE+5S?C;UVUJ^5W/TTW9cAߵDVHf%~߄5UuYuw5[[4ҙ5u]ϳ\\uak5`vTv\/5c d;de`G.fg6lvSt}b#ii+jje_hĶQ6vn oopp/qP$-4w6tۇtuuvKvo7}twO|w}wyz4_Ovb6k3sw?߷[_7C|ׇ{ϭx$N,858}<焅χ wj|8N8h8q83+kϸM8>8pۄO.'9,yM4y=oDyN9뇕k9w׸Z9ykȸ'Fτ+aܹL9mKmUxVAZ&QKNƕ[P%Nyj .FH\1}"S:X:Lzi˄_~7K FTFoKz#Ĵijg]e'Tj"'%IgJG':jX&nP)qϝdl9hI90= z,BѾ&9 J({ łRA _ʓBVNil|H\m&(q:1ʂѭ)eFRFiCPg-P{0'7Ĺ*TE|~̛ D[-$PkN^`2PcEKXGRэ U[2KkmDE.ji^).џuo!.ojI=[ =|)Ȱ_oULhƮw˞A:=A҈ۯCS(3jӦoF_muJ&f, ˼f:w' `zԻD%+@| :92nDhPbD"@*Z\@MQT%:괔9fM7q3},'NdF=\(F"D HNG25Puϐ2 unE""gad)OEq3y 4,Zn !<+ 1PÚpD\3OE4Ȓ% +̑qyG:QB5L&,j0B2K")!%$*":K/+:7S 唳:KC7O TAϣG92[:NBsN-TM2ԿUf!0<#%I]T+UGԴU]wԿL%uFL׃X}-:RgViT\b2!W[?cMUhUCy{UZ ۖg#4hAr+r]uNCVWu1 \pKԍ1+2ᣌJH٨nJDn6ߛqYg q2TLSe}2 =a\8YJpdȻF)..R7jGލޝN[m^ϡX/i^^ ⠟E:Si;{o϶{o3U|w[JN[ urs̝pPWTuv\yoLi,B) &s]=g^I^⫒K)?h]n/gMo~m޴+u/ё\3IB2\CKQRI3B@ެO~u? a_(m%4i4xBOUT'8Bΐ5TI m˅dC!8$AXȩGtqfD'&qSK$bE-JKG8D,neTLQc4%jsF:BB8)> stream xuQ=o0my{^Q@hC@ҤJ@}mP*Cξ.y9{|&HYy`<RĈ 4+ou ZZO9D;JP}">etĿ+4nCv QuՎUmlQΐ 3lix%F[e^iKm6υC AOk =24,] yS1RňJ%.}d+(6"Fb؜Iܧl:rn.^> &G*gk~!yijEJ?ѧ_0'$R*VTrl<\~2endstream endobj 2 0 obj << /Type /Page /Contents 3 0 R /Resources 1 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 13 0 R >> endobj 1 0 obj << /Font << /F20 6 0 R /F21 9 0 R /F22 12 0 R >> /ProcSet [ /PDF /Text ] >> endobj 16 0 obj << /Length 8 /Filter /FlateDecode >> stream xendstream endobj 15 0 obj << /Type /Page /Contents 16 0 R /Resources 14 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 13 0 R >> endobj 14 0 obj << /ProcSet [ /PDF ] >> endobj 19 0 obj << /Length 877 /Filter /FlateDecode >> stream xKs0> =V#t ܀Cbgl|zv%)fhK.jy2{t(e"8܋dvh) k l2KDS`$`4$xm3TЏ9T0YNLt,|]u ==/^L2SEqGBo.Ќ;.\(80ݴ5]q~p~Ѩ/iNmW:J+Xp IYtќ_lwih\^W^]BnEm>io_7(G]mA䍂UͼjTA }B(2}{F 7)u-+-Hly5WU. SFˁF@&'Ԓ6Su= FQn>gҥUW,S>fS\ɿpp -1JaAn]@g)[a@M=P!ȝ]PWqL35Gz(kVu> z&=5pgHiKqhN!f5Q LCIl v'h4Z7}Xn9^1 m߿bGƳ 3*UYg4i%Eٵt]Vq|ox9HM=vr扟퍡ri?,rYtg L.2!E`SoIȌc7''U|9R=a=5 ]1N>e+?l v@ۆ/? J_v1-rx<δK~[/(Yr;gsAv"^@-nlj&X(3<5ny=%=n?5Vw{Og{fsendstream endobj 18 0 obj << /Type /Page /Contents 19 0 R /Resources 17 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 13 0 R >> endobj 17 0 obj << /Font << /F22 12 0 R /F20 6 0 R /F26 22 0 R /F15 25 0 R /F27 28 0 R /F39 31 0 R >> /ProcSet [ /PDF /Text ] >> endobj 34 0 obj << /Length 3615 /Filter /FlateDecode >> stream x[I6e[Ɏ:v&V&$6nFK%JM<<|orqJ]K׋$BYcedvXx6BLF?{OPf{;mݵIURu-xyq-M ]Jb]R"mfs-2L 4`yk9| nRDWT%jyUo`uRP|<"OD:TWͯBzɵw3hvܴ_=fln ua_> K81\?쐗_m:7zdGQ eջg!p2S[bEQ)u*+lߦceȺE*[mh'nF%2JSTS@D04fqd,bJʸȅcHZG EQ]XQ9r ,XκۆgŦ=4Qc=KAJl}؇l 14Bd]_n+hKndvvuFgQ$2\p%*4Cp3?3O(0~Ã~Ic$S`*I/ t+3"'A'$+\ˊU&,bSGԏ';eoY8O`Kc|4z[) ;g%$E Vy$Qŭ⎺c*E&RKW0-`+҅`we㌟`܂;fPIa3)U !Yӈ=mHU&I jM?14,kO *wdSNOޛ/-1KWvKu: >CCCmCHүoWhs'>upozy%.->e\43f}꟞"*My~@1!FKD& ą,t"E` d HM9zwl .126DIAb~\ p1cT&7ŗ1GҁƏ `Xs 0kSk9L3 *Rxnv7(qJ{u$9&O8X Yl'pcfNZe KS[p'"M- ?M]$ݷ ֍U\JƉK~rYGregvq۔whz* ]H1I4hI-=MXvQڇ(k[R}l4VBiZ:+0XIVH[0U>~T➢ඣ{Mr0wcyÌd[>yMڑ P;@FyTځqqm]s]  0񣇅bf| kԔ 0 }*§|w00zf,trO6ч&7r=Ӣ?[v(DSh4{Tv Ygvdj SAT#Y5e]/*Ԥxٙ&&+x=?ϖ G'fmKOm/inw *62s -9e؍ L%pB[j)~%xV)pHȲ۷9.p2xlx w2\=w'HPIfl!giA0 6(,9Y}@UL-ѓU==,Ky3=ǵah_#I\hsp{\Q,zkVK޻>zc܋A皨s'C>4Sg/}y$2 ԥt/zn5~σ{}GbY@ϓ_&jS؀+c:8LQ50}"3S*= ,Ã:ʾ߲ 6((;6 qBm[XÓ2tq{endstream endobj 33 0 obj << /Type /Page /Contents 34 0 R /Resources 32 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 13 0 R >> endobj 32 0 obj << /Font << /F22 12 0 R /F20 6 0 R /F15 25 0 R /F27 28 0 R /F29 37 0 R /F43 40 0 R /F33 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 46 0 obj << /Length 3765 /Filter /FlateDecode >> stream xَ}b2chhn*ْk pwe#_:&YY 4j?K)"M4ۻMebaJvqq)Wk%q%ݲCӪ]ŲlJ,x~|^iYPۯ?Rx+ii[IzzEM˲Z\]V׃6+RLEJiv<8?z{Bl+pȑء`{mqGEI%$JhǷ}ex:n塳`H+"! ^a`'?{>'JIlPvG+Wܱ+gnYx8 ?;Pޏx) ~ЅdD 8,]];X"Bp9#TXv" 1&U/(ȾC P`x \X]g5]0p2jN!6~~c3w]d7q]?ճX l 8y2܂WwǞʏ<3)JOHynujo> pʄ@>vĎ{ 7`KLB$Svryw~i|9;1uR)l /}]'.3pi!֨'l]kAQ`BљMȲгyq"r%EP,P6#6ʁ2'B ?'_5_ 6# P&0K,V"2p>L&?"u Aɓ

    #K<|]>s;2:FE'&3ҧa1XC)~FI+}< h*`;AϚ]7k0rvϽ+Qp7s|n1?̗<,fRhW mw\ ?hX3H)-YdApI҉&F$HE@1la*KLc&$MoP~wGT$]4TGt%HB]Ut&$;\GJu`Z,ѹ k`($sJ&/ARh8\ Ⱦe@*ۮ:[3g,'?nA=2ޫ)6h#CGBݚeҗjC ľ bK_$XV FFv2dStm_mԂfa)gǩ92fai^yj O> {\U\lT 8c=>t&O/8:o7"°( t0 C]tQQ*KqBB.3%P2nl<+^F0L`j!t WM%ZQ'G=;ai/X"pb1WzҔ]hn ܿyPDf+|ftcW]o8g[4\$Nnֻ*!g p,d55Oʀ>9mŠX+#"XE.- " ;1>uLƒE!¥ٜϗCZz0*ƬDzvNĨc!*zQ-l۔/*d* L'"Ѽ`rx?f]WKV5(p\$ssXkX nyLfi .gfj2?x` T؉Kqe H$g;[@VM]Trt`HRY{]+qܒE:%޼ `LzKd s )zBs2lJlj?f±W5gMd fY"S3q"0z7SȀT` mǹ1o"w~2?_ ;\%͹ux!09VK4 |} ͹sgſS]]endstream endobj 45 0 obj << /Type /Page /Contents 46 0 R /Resources 44 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 13 0 R >> endobj 44 0 obj << /Font << /F22 12 0 R /F15 25 0 R /F27 28 0 R /F43 40 0 R /F33 43 0 R /F20 6 0 R /F29 37 0 R /F28 49 0 R /F45 52 0 R >> /ProcSet [ /PDF /Text ] >> endobj 55 0 obj << /Length 3172 /Filter /FlateDecode >> stream x\[oF~RPb` $MuѦFEh@KM.D'u}ϙR#px;ιQ^FMWvMKf&OSNfN_z36}39O)p hf)"Lpr1SlZ5P›Lo M.Rf5+5Ӻ$|yU,r]*~U|ʺdZXeϼӻĴޅBnjo ͨ׻^ {f\zb,)jWPA;$EmKy2ˈ#+0@6])FV8ӏ#ɳW3 ~Y¬ON>D8&`͙Ԇu3>{{"8kGH(SBOR*2`yh/&8c4ډ 5m5%fqc8x>I%&F85X߄95pkLxb#NsOSB-~~jf_a1? f0(ܶrۯ pb9vsPGjv Nl:|_rQ?FFKHX]__ a^ o._;\kǾ6B?|.Orzw ) B I("9xՔ|&2} /F'+gRN>[tW7*=zP9\sHqD5)dLzzaP\Y7zc.b#I͸|C|.0)B8atl!GM AÓuc&#n0߫6?nP7MʩnNB`+.S HŌ( R猩Raިe؆_6z_9wN8XZh+$2c Z;ofz L`%+֌`(\o}+`Or2ﶾj _lXkbe+r)"nJaP{jz+&)!la]mgm5 RҗpԕabK?2-l|;\P7\(S?6GI+9=>uTh&Yt:LXtd<7fixyNgHwxiNn9*}q]^և!8V8Pww B~&JnM[n@ >fLu\6ZѼW)˲.J#u0-ó?8v Qu~֦0ow > <`Ye| m")~~f?fn^5a0owGlq;-!9K),V1_N|ǑSF[}t cl>[1S }|g~s[PQc|~KIjO@HϘSt# N7bOp yYuMIX /=;DbԂD%N I|c؋!('FC|^ F^ι Ld< m` ҇0iS! ! 2$Qq|Rr8P&?W]ӯ kҏvEAPӚ0:;AZ ?آ񶅜rYp J_ WgJYőnS7d@~,,4ɦ9Vx%p MEHqU >m؜&:qW'%96wMlK `Rzۜv^~+AhrD&n 0Q ɞX؅$u4Ϳ}c>̭HEJ%4V[82; %9"Jżxv;/>g ˸%}z~|:͏oh&o6mf 1} *5Zv֫T8Һ6f-ZwYmhhn#^L2>IaUp fE;жS#֕V5:83ʢUW/b`Ę!L> endobj 53 0 obj << /Font << /F22 12 0 R /F27 28 0 R /F15 25 0 R /F43 40 0 R /F29 37 0 R /F20 6 0 R /F28 49 0 R /F45 52 0 R /F50 58 0 R >> /ProcSet [ /PDF /Text ] >> endobj 61 0 obj << /Length 2819 /Filter /FlateDecode >> stream xZmo6_?XH ڼ.'7mZ9+@H:!)ii:{EgyX?.N{#ČLgqYLHxI:-EUL{sU=^dB??}&\(_jÎGY\ wiLJ:å0!ثWK|M dfEBtܜE " ( }#zak:nWH]Y#cx԰?;+zw".K1PhZZj#lfҚkTo@0Qn['m~DYI%(,gf*OQͮ"!Yd5 X[XTkڒ.0+?2dBFP+&Dvp~n!l(YC3hq]%׆ λ "nWH .s䶻۲Z'`w +o^iH fE5t Bo'uYHD@`L*?`2&!*'`9B&運. +vhHtLPzL>PX'm7y3r3` 'b~que/A/6*@ F\M6?n^H(j ?}}x>*4NLH9!#k- R%"m|evݢg{hlL,cyk2o0ŒcWDz9b\TƵł0pa1n4A5tةZPYk~Mf 6!0B 7`[I<pO>?[NУjq v}"ÈE< Lqr}sK/:c@g); 1P7R KH 2-bG*L1E!!pș!U@@I$\1`QIw`؇$waubkI1vΟ3\K/}umjW{E<-zC"BɸT>!FHݱf~}ԷBd_nYDא̅M:H .{SCҮ2-NbkS`VmSWsjY^Hݦ f%Atr[$u-K*6VϹ ڐm0ak+[S`ό4Z!x,~+` )blFꭏme6Me7Zy(~4"rLU bS)nLTKkz{Œy6d: ^`mچ 6V/?9 =o/K 4ĦJ3W drЅN&:LwLqڹ:_T NIWUamǻ=-/(|[#XzƏ(+=͎tٮ?ь !}Om5l+bRHWM-\׸;AҬH[3k_@1C1ϫjJfIGw+}&}x.Bر3ŽdG?"u@Qo0,]63!M-U6^m#&Z;(vc`π, 3)TۮVqt6\,7]NA뚘mzrdnFKzA$kt*y QgYLK7HO۩v޴s7r+ uӁyUKTl~Yhي9(B*gN3vtڎ&dRch啱G™y矩<;3ø?na9PdaUdzÄ+dK@H$~ {A+,$+@1[eӮT3 '̜/qŋ37h=jyۆ/cJIpTw@= ah?J0fenRJ3$!ՔZȗmGqڤ ]_>+mGu* )*b7RM%։Qb~&,3 %UژGr,b_ )Z7URaIP32xLKi|4M ,Xbbijj`*'3eUǷe`龴ùԊ$ N`_1%66j]GIendstream endobj 60 0 obj << /Type /Page /Contents 61 0 R /Resources 59 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 65 0 R >> endobj 59 0 obj << /Font << /F22 12 0 R /F39 31 0 R /F15 25 0 R /F27 28 0 R /F43 40 0 R /F20 6 0 R /F33 43 0 R /F29 37 0 R /F28 49 0 R /F45 52 0 R /F51 64 0 R >> /ProcSet [ /PDF /Text ] >> endobj 68 0 obj << /Length 2522 /Filter /FlateDecode >> stream xڭZ[s۶~[NF\C.Nǝ$I9mgH9tB4zrbA$X|.ˋ_s>cXjly=Qۙւpl#d`Kf,sw/C gi&|W؀#69n@g &8 ٫c /fy_;\L2/~u SaUUay2ۡhM,E aFsg\Qaj}?'! (?[|x݆;w*Tsk?N%\s``r:bH8|+x)qO"t肔.,@K'|Ӝ3oL!\Pknh*OtqHݬ^wߠʑ$w;LaD&ST!%K"ʯ`  Ff_a'*ҜLPxR(EV<,>=mR蘂YnШGtNf@8jj?s.UeuA,-u_7`nelUAFqF{V1l-@]Jܬ֩aaޒe*TP7Ef@^x*F4F|r{HJ0c:99O&<%bP wBzSy;ɾ1XpE=vɣi Sg!aCmi)f|H-+' 4 + km;Oa"6Cn dߴ[Ria3"s#4P ߱(fQi: m[**K.`p&q?w#:@(:X<{~ߜ" &HF @ O4y@=>$XjT.ZgT20*:_@ɓ9ҷyqR89|Lxdv%Te@_SD!܄:mD)$4=: E߮-SrɁl[fiZjHӵc2L|Lܔ~KІ~@h 1'!Vګ&NՊ *{!o*UE]7S/Sl]dMm5" d8t]M{0A3.)9 m3=:}HdSA4W1zػymzh*,z)S :Gfcx'c#o}>-ׯ.emѴ' )#~: 0:q7*Үkq;󕛮ܘ\;pGNRt/kW?La;F=åكGqʦ} u>wO7TqEk gv>o"1j"aܯy2ysJ+?~KChb5>ȍ?PF$4j\yOcY ~\h܏a{i*;Rfg&Q4q of --eq;˯Σ|Npq@U* %g?ze~_(aL aT|?DIb TR2 -0#A A`F],ylCg'6 Y]佱zA/ҩN=a@=M^C4?cӀ*E8َO8 '>Z=IP'hdt_ORY{5.8 ;O6@. To!N d9 y:zջ8XbOׯ2Re-o@99}oh9ߑ;nBrY"@٭iWL%4={x;wǽhf?َ?:Zw;F哸sE:D>|_=D5OpH+c# }3d_ q◟r5m!iDPIE4POB-rFCD>`z䧸>i:ǧIM|I)'k|zx$}Vqߡ;V?DiQ{3_I۳5b+o26\6c<@ߔ x25 MrEczf4^otr@/+\,Zj16P@hGe>314Re9fPcYt{Ag!՗yOd oendstream endobj 67 0 obj << /Type /Page /Contents 68 0 R /Resources 66 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 65 0 R >> endobj 66 0 obj << /Font << /F22 12 0 R /F20 6 0 R /F15 25 0 R /F33 43 0 R /F27 28 0 R /F43 40 0 R /F39 31 0 R /F28 49 0 R /F29 37 0 R /F45 52 0 R >> /ProcSet [ /PDF /Text ] >> endobj 71 0 obj << /Length 3106 /Filter /FlateDecode >> stream x\]}_x)ۄWal_?ʫ? 7cՙ}CG.5ѧp^6rz ?]9;PГdf|׫:hV/:Cd1: ;o^a0#X~Mb?&~ divԷݚoowk!,5\o?15LHr$$¶7paPG-e [Xa8.䯻_ͻR6pۻ?d+`:%eM wV6:9 w[H9~C`U#~[B;&?5M&KOX3zC\sW`Uч ΉJ^YcjeQģ%#N /DZ t> \6k]j;梺 lHrAϒՈ}P#GHBG|/mu#WН7jj~b™%3!9Fg) U< f3덒`Z:v_:Si鬔˾Q$a~2Ng녂X"i?* ?15S-™s$dBW@8xpV.d0#b犱r#Z˒6f?%[A 7*5W2c{tV (S! ZDɒ/a{Ťr DVt^:JJ*gbk_ΊyV"=!q)%k l2.v/h4l Ҵw4~s" [{XĈaQB^G8TqmIB !ؽ>!XfA?|ͻ`QLS,|0X94蜲j Q>B&3`Ŀ$e2f0<𚤨!QҝCm-ZE!amVYE)akVզOgY_V-7ex0E4ugUiB(Y3a砇ߘc_Uݶ^>5|vo+Udz_.#B2UR, ,ZCd1v@%f)owXEsUp/ &26=Td~TlkL'(,bm -lAɔ)̐|oH C}Pptf/EeB1b pKId _{'-Eť=Z  fr ҆DIX!܉6[=.4N,Y7}X@aDQ95֜`qI%&3W"EL C2`ėTrA"3<`jV%nvbœi3,۰ռޒQl.لCr ²52 ,3r̮U14YC8bl9N(vZ".Y!isA.DDD]HqP,#(c XJ&Rgr~g;w)*Ta:~_~iZ,Żb>endstream endobj 70 0 obj << /Type /Page /Contents 71 0 R /Resources 69 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 65 0 R >> endobj 69 0 obj << /Font << /F22 12 0 R /F29 37 0 R /F43 40 0 R /F20 6 0 R /F15 25 0 R /F27 28 0 R >> /ProcSet [ /PDF /Text ] >> endobj 74 0 obj << /Length 3014 /Filter /FlateDecode >> stream x[[s~ׯL~qIcwIfIf(-/ Iտ9.]KFǝ"Ş=QcDiwcᒙ懩 9N߾z ӷ367!_B؇=0951:sE5m0>aVRVJlΝ.θ.p}=\bnw!473np逃+0jyل ->>j S!lh7=i0jBrb~m.rM4\cgvn}\Z|b]P  5aK<Dj!~w݆1t8OMz 9qpj)#U< H5p_< Сy@!Bmp0ML>+SF++Z%[2EwR~6 sH"H@Cy/" 0tbrd6wd6)2es> ?iQ^ay*%pE*4&*R/ݒr =s=";t=r qb&Cd_^ˀ ͘:e6rg7v5+F$uOѫ^Do^=haC)AQk9 vs:wuٯc\ J}`wUxxW"TYGM#JRjb0a0y%PSA Y&G&EXřПt %B= %pSA9kV# u!U!/P/0<0\YӾR)VT-^#D\>/rSB^4a4y:BZ$&oza~oP\ko)'heM']u1S[˶֗3$|*6PvӲte4ώ»YB5M;ꔯw9TfETxoS9v{lWR%)bqixc(nO|.p) WcN ” `ɟRs0zlo "fz ԑU(zaAy5RqHJمfD.: D%2f^\uۜ6dIlmEft:?߄k{%}G@w@\*>ݵ2k)8X0gԨ# zߚB,r:Szڬ*,>|$=NഴG /u"b@BJ^# vg%5XYxF)pc\Mˤ;8*QFw NLvY|@H¯P@Ur^sTHv˹s+.eE,`0֞S.:cUHc!*NvzM_,!АaGcnT G<O_ ?{[M7Q:,[8m?LvN>xY-8bjseb C'k3& 83|Ya!s|Ca4G_]|='8t]wg j8sq>U%IsNiBDSsP19. (`:)5Y>{*^<s-%tf41Y{V ԡYPS+%tZ|;,"?% 1w<9O j5*sj'JMPWEhAc'Kԋ;2;OaDHjv5U-{gNm_lֽ+Y^7+E9H9";8WR{/{]¸ZAy!UJQIM`gviP="EC EiE FƭY(&G8J+@vt~Dw~]YNٸϡvBT#|3!Y;s(ٝUkIHDA_*FFELM9#3 f9,#/pcW Iy!Z*RYgV5Jbq;~UyĜ<3 c*CRA@' ŶeY|aYղ,19BQ'm&"#"8dųDr]J,M o?>@,=l(Vx` ܰTb:Νk5/~oendstream endobj 73 0 obj << /Type /Page /Contents 74 0 R /Resources 72 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 65 0 R >> endobj 72 0 obj << /Font << /F22 12 0 R /F20 6 0 R /F15 25 0 R /F43 40 0 R /F27 28 0 R /F29 37 0 R /F33 43 0 R >> /ProcSet [ /PDF /Text ] >> endobj 77 0 obj << /Length 3001 /Filter /FlateDecode >> stream x[]o}K/|8Y$ihч}`$: Y$'M}p5C0E.=gȹz>!ȣPhhQ6ZN!B9wðj\0' ćID1©ty?hvAG\P"U 1Ln?Yk(ǁa`.4Vf%f(%FQC؞Sn3F{4RH;N(guT^qC`94oI=xSE&n;]w}a>Pz:IDp!YF UʒZ Y#tzFEgfhtQm4̆+rR-p:X'ge~PӪ0[m?}Uu>|+m6QJ;¥(&_DMWfow:t;[oէ:?X畤] Fue;-ùN0/ql"B.900~Tū_'OkHϾb)#I9'%hJ$ )!0RC,#'[2K3)WRVKmgDrQt5G!d<2ȯXH~I Tɸg{.EږTq@S.- J%4e2BUH5x*{`.B4*䙒AZG*ɶp*Kɻ8d^#|tu_ d癔bŔDS^b!d<\6bW%b6]շU^b $$5Ҋp!B³ ]Ca|^ aP_KI{)/ңpR%76*Zsdyi7[onջ9ާv65>}T}6̑,ϯ&$L7 ܄C׋Ek!\{X]صENw-?u: ^m?Vn! x;t]F6dVI/Uۏ^6=Zgz g N1BQYG{yyD~m§F_UnSV`$04agx7qD>i{apA`/oe",˓@BwXG]4n# jذl<ⶳE{kۺvΏ}61Rz&C=v3ͳhgD[8ЄR@C̆ù9EDY%/Gy A2u/p'\20+MEut?/mvq/GҲVRKaQ7"SD t<)ΐaCw.U !,+Y-/LCax5q;rh?,;:@ÇhV_.; V.2?w3CCOk4tr|ؑ  ];Wv~tq{z%|ӷCv* +Q,WD?٤ZB ݰyk %-yO 3Iݸab1Y@!tuEmtmwI[ۍ׾2>nSw9Ӡgm b~ /*DuOҲ w,it!wЦɿ!T2b9(s/sYG,.caSJu%!2.@ $m9cd[ 8dvE ;xSww2# g )px/ڒ9$ؾFFo/d;-cBw\H~Im&t&lȔ> ˧*%L3f5 5%o#_ҚX~ I8TO 8OAk]QȁӘxQ4'ԄZ(c9cw4E27߀3?̎]_~:T]s4}jݭnxѰKH>M)&?^ԔPļ܀?ˊXEIP yseD*^0x? R, SA> endobj 75 0 obj << /Font << /F22 12 0 R /F20 6 0 R /F43 40 0 R /F15 25 0 R /F29 37 0 R /F27 28 0 R /F52 80 0 R >> /ProcSet [ /PDF /Text ] >> endobj 83 0 obj << /Length 2820 /Filter /FlateDecode >> stream x\[o7~R)_mjHD>}P-TWɿ!g]cA" s8G~vKJG# nGB"i)Df7?L xMȸ|0p~/f$QJZSB )0JPf]rs$(]~;<9ã0bFCUdui`{AF=MDc5"ƻb2Tg._]Pw|ϫ٫7=ƟМؿaaB b0$ )H1)“0% Lf4 5Qir֤N!*м1ר"P$ ̨g5PH)Se: Lc*2) H %J̈gH)d: ƈjm(*%4)\tI M"1Ӿ yȥBh"Sf/C`g5kY{=փCwG*.y3nv.Q|mdJո|<_B7=n܉_ެ'T-4,{8|;_Uں&BC]cq;>R!,F@z{pࡋ}[ux֝l>8nSkz4e\!C(Y~]4e4|$}q- d &8 $yr4s$~%0Bx~, Ƹi$c.%dz痑E}}_zY.Xnm?o:lj,c/N?Ԓ R_f" )rd&1,c~Bg]UߺK.0t1D)F#N 0iJ24=e*mA[ns%%-ɌJhyл R=an# U%;b>tS)~X]82x݊L8IJ.cuxj-1i%YjKhGѹc_v:,ǓQ&ju4U~ qd<<P`L<66 :q:t:NH+bj!gz*%2DU$+.b :B騣 ]o}>|8TpA|̐L 1Ch23}y]viCvPcuuUC2s Nqɀ!4zYB^ͦWo9b_, rt+?4Юݬ| _%)g?.#' qYt9Ẍzg=Vx{w)d> ŬN, lY%' l3]2PBL8fH^4 Lfпf)a 1no+UUVGVvf"Zd" A<{X]f0`_̙2HrP&=߾b|z= Oד$z_Aȝ$CqIAT HI"N#)&U==,d8{ `v2 ae1 q A/bF;K9=Y.B1q >Cf+]r' 4!RN "٩0 2H5e%dF?K:?},Pf'f\⑺BH d:̨Rur(;("n9!ö$x)/`1O;?f, ;ݲڌ!Áx=@D/' qJ%AؠTb$_|m#Mڪźm ?]e%ϗvt3j?+'wMeæ0򓭗\i¿wPjK &R!o[7M-JrJ@%9o׀<,A#?lvo!rkP[;GW뉥v^j*nڭjFb̯[[o_܃n]GPkw)vZlOUj;`1pM"WQK1A1W^|^\..fNx9,"Yډ—&((/G& F{8_|^ȭ ]%$$@ W ܰ;zAaɝ`1N@h2wz dLoۦDz^!ǁu=;iHnrwHRmi' 0JaS%J&L' qَvAzqE.VYGYx!4_6K8SLC:{GuZm\S8W}csIN!ƸBR/% Zv 04θh۽ D8fg낦P9oA0$z{΢:Ir$u I+hclXiŶ4s 2Hۨ|-hdEdf݋dKA;J>Gw{DpHace 2XL׼=䥜-C|j07_ EXLT׊]aobO0Hoӕ O;iaB".ɟkendstream endobj 82 0 obj << /Type /Page /Contents 83 0 R /Resources 81 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 65 0 R >> endobj 81 0 obj << /Font << /F22 12 0 R /F29 37 0 R /F43 40 0 R /F15 25 0 R /F27 28 0 R /F20 6 0 R /F26 22 0 R >> /ProcSet [ /PDF /Text ] >> endobj 86 0 obj << /Length 2222 /Filter /FlateDecode >> stream xZko8_a`yq&U`HAv'|Pl֏,7{h[r(0uy9TF?^R:&e8#Xa$cl{B$e)7Ɠb;II2 Ir6,*0my+ )%T)dRlD%Αl<_9<^F,b e^Y&!({i0F(8g(ԺG0F 3FgҺw,$T$ŮM[K܏wsa45p4ك[(c$"s6Q$C<w+ pPaDSYE/#ILe&ƒ)c_K(o/YRkߢu/#fTm~2ȽPDL6Ԭ7TEIXkXa#*lX?oS&)`:;q\:Z &"CqFGIoPiM܉c'tN;FO/+.m]tᯮ-Î/'b89  QB{)0r:6yLI'ܳ,S$Z*n׳Wb6}8wLo]/4AtD5Bݓ$"n 9R9+/3X?tC$*$aI'2y?Ǐ{'xAe "N0G+Wa! L (pA7 n#~GdɌ(tC^&,j#: Ґ2e[S(CmmϿbSEeZUy5jw2,9GK_^ ʔ+@`ZUln Ըb#coί o۫v6$s\oMݭ]ÛI1SMgn՗;x\}>7UޏDĖ`x)UB3w髹/|t30/''8VW4I9~t/ogoyZF}#؄yjBU3k aY ,r^q.&XnM?^çWyV ]$ϢXXxrnqJ؆CEnᰃBmZ/7}z@t=-ہlQ9T!,cZmº)43׉Iܵ=P*_!>[;qժb([d(-xF(f`rkq_+_M};y\,$P8 .y`/fgt=ҊBfSc~\>~Hyp(̇ _.Z5Cm'> IU<}#6/;9e9Qj#dF7Vڽ-t?d'-wACdp;d v~֘5g 5i۔7 i1'[ݭ[`/lLq;J_Ǻx X<={oO!Gv6 yuY\J[ujIu*C `V#DN8e]`gl3[\Rp>5.\OS0:j\+|*AB–PeYZzP@]*Qp: i^[wBVڏ5)Cw]+ 81Yt{\aԡt)}^Y5C<ҵSښoWOӐ!I.c/)a؝OEbga@^X5; ,=0)2!?? E^_Kې}̛iG CmIT+[X£Qm3CvD۽QMT ' ^L2UTȧ-]Z 8SgEM:W*L0DzC _wendstream endobj 85 0 obj << /Type /Page /Contents 86 0 R /Resources 84 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 87 0 R >> endobj 84 0 obj << /Font << /F22 12 0 R /F29 37 0 R /F43 40 0 R /F20 6 0 R /F15 25 0 R /F27 28 0 R >> /ProcSet [ /PDF /Text ] >> endobj 90 0 obj << /Length 2419 /Filter /FlateDecode >> stream xڵY[ܶ~8@v"uCF\8A|h#i*e#i΅JZH_v)7P_|F)Ld~wc0Tv$QLnmL?}cPQo yr+7w^oUy (-t6iH'vw?l&zss޾z NHH3_&H0`@PFJr? 0ܵo |-R!0 .:v)!YO8LT"`C5</Kȹ]LGL /~ц~ %C ʼnj==J0{%#L KOC< m*o:gҞ&kTzj&1jed8$Z!ir0*b e +GG_WER]2*Z{9Nf-_UyYBxzʉ8Ԓe=7R1jY*PdPD)9gyw$@O"ANx-98 Gem†#le>6J\.oVN"`̥?Ǒ5ܥa=FZG>buA#tpPo]羋P}Mc`T]?88bR |k53])i,WDJ:L( 1;ͪx'}!Ep}\k"\|xLܱ~y͵,pn[WhK Мʳ3rZN]5TʎnW9"}9$TڍE!D ~%6H?V.<VDd'a46J|ӷ%?;uGE +PߜWH0~̏e,%n!(W#(erCC!vtz8{D뢞fwlY8q;eλgW.sXê[V5ZmX_7Z4sJc>ƴ(T&zТ~N&'*7\# @㗻sAt~pdG…!cv'0J%jx<6Yjs'yKa!o=M0+O a+i掘=]Rb݀β5F:VzJ&fiMRvDp;\WobNJK(t47ְ d8 tFL a1gɯ[Bg?4!&2dklܽ}[Px{ L X`㧊 f•;by"T% sNgL qEG\A=g>}DI09;"_J%*הBP[$_)Z\UJgV)gMM=Tm0palC%W<l|;~O}Lx GS?Qd!qr_ ZĢȎDr.' J`nHL 4T:2Ϻ_LDv 0 d`dm2+7DFpf_ȄF2SBcߺܹO&ɗP6=endstream endobj 89 0 obj << /Type /Page /Contents 90 0 R /Resources 88 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 87 0 R >> endobj 88 0 obj << /Font << /F22 12 0 R /F53 93 0 R /F15 25 0 R /F43 40 0 R /F27 28 0 R /F20 6 0 R >> /ProcSet [ /PDF /Text ] >> endobj 96 0 obj << /Length 320 /Filter /FlateDecode >> stream xMQn0+8R!xM\6Rʭb)vzנbValE1^m++hD[ m9tl6 {4qq^h TT=YuQ®M!1Tijvd~Nf6.DF= ,^vwH]#=Zf"O7ZhM.ރ5\hf֩5EI{myI z?1dh s5=P.v]WڴgQ/tIU 5dy}$P YZ#$ga endstream endobj 95 0 obj << /Type /Page /Contents 96 0 R /Resources 94 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 87 0 R >> endobj 94 0 obj << /Font << /F22 12 0 R /F15 25 0 R >> /ProcSet [ /PDF /Text ] >> endobj 92 0 obj << /Length1 856 /Length2 1858 /Length3 532 /Length 2455 /Filter /FlateDecode >> stream xiXSg-(BE:ȂHRbY Yh "AFPh- nʦfY(ՠ \u,؏3{9s=1$RY#5 1x@$1hD l̥d.06"08}8@`Gi!\x/ M P XȍFt:p}8 r@v$HE0Jp@0Ƅ[rf05"S*ds Sd@,&=A0; : 7L}1Nw'3޷8 =_#< " K <%i[f0L1f4#R=i\JDsqI4&P^>D'CƟnC֓LcrDzC1 ͈Mߡh4B/Ns`RXTZ s,@f0h? 2Ƥ<AQH& \ R}#aa(? @9oTAPO)Iwuhvv,S3sPEܿ )l6~XJh8]@ lpE<W\P]TgCRe%阥JPI;CiWͻ^CQժlcIvSyES_ŔAj!QdÖn\|҇o_ć%t*@Oֺ^3:V9Y?=/ݠx'lD)"(۟o )UHmpj$>jzO`vTVۛ<֢Fy,/D.P)DU1I=c\'>ZVtQQVsr=ΜS-)uE5ξ #i._ iiUgWʽрH;orqT+|U1I5o_{5R1Bz_=sRuIh}κc_zM d]i|ؾxd㹕k]XXNU_OZ<+0?K}WSpowC=WC*% gp  8";Ѣ,rƲ8gZwC~HDib"fsK] pB' XBL5(P-FN^wdr/%~GC/\g}WEݮ.s׵[?q ߠQZ- iD֚Gձ7L>O0#:P.ںE=J%+h] 6빦]|ccR(WSKεύ=PЛkp!*NC2x=w%<8`Vf\qu933"Eup9Л-]+eV\ :T!l,5#ؠF!7VE?W_j(鲂ŷ*rIck7r&L)/͊cn* 7fg zȮV*^]) Cu Uޜ~-< .,ٸΟ*qqt Xyw4k◕/tNLϦl~k4]=Xt ֎V;Lp)yt;[gw^5]S:s(fۀG:'&Ti% lBWҬ#.iex1{iC'ZRC;)35 uM_nÕ]{[>M-ĺryQםTC.T6ZA*cek{EWev6ߟ<1Ma͕ͮ #;EƓv!;ApXShzcc)jhٞψ~!e͞:szּrl(tvGNГUW~ec̬@.Áo3N6.&&U=:|s;oyJ}{.k:`E&e)k\AxYz0[}Oqokܜ&]ota  $鮲ùƌm|Lc G)ȃmK 9$#}fejoZ_%%Y ;昁mĻsTwΎE~un)"DPn"ua޽Ԗ%,Vk^ 7o9R/^q{a*Er ~/k}T& 򷊴uAx}=؝S %nvDzYT۹,{Jf~;<#%_)g35 6?|`o?рBl.Af Rendstream endobj 93 0 obj << /Type /Font /Subtype /Type1 /Encoding 97 0 R /FirstChar 65 /LastChar 85 /Widths 98 0 R /BaseFont /VYMGOQ+CMSSI10 /FontDescriptor 91 0 R >> endobj 91 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /VYMGOQ+CMSSI10 /ItalicAngle -12 /StemV 80 /XHeight 444 /FontBBox [-97 -250 1077 759] /Flags 4 /CharSet (/A/B/C/D/I/L/M/S/U) /FontFile 92 0 R >> endobj 98 0 obj [667 667 639 722 0 0 0 0 278 0 0 542 875 0 0 0 0 0 556 0 688 ] endobj 97 0 obj << /Type /Encoding /Differences [ 0 /.notdef 65/A/B/C/D 69/.notdef 73/I 74/.notdef 76/L/M 78/.notdef 83/S 84/.notdef 85/U 86/.notdef] >> endobj 79 0 obj << /Length1 942 /Length2 3150 /Length3 532 /Length 3793 /Filter /FlateDecode >> stream xi<})Hv Ȗ}Ř91ز.-[TآB"K(K${D?y9qǏ[jbΠ.OCH@ .rǵ %ϡ( MoW~+#4M n@J[Hād,LP7G@<K R'``zdΠ+dw!1Ŀ|@- E ) "bxO@`ڿ@ZPz{zp?lӿ P8H87$& H.`qPPX&d:Kḇ@!{? {Z~ƀZX5ן(,bO?7ӺDrrpthw6F@1àxvu&p!!?ƊP`nD7|hÃEp99 in_7T`_ȿ T`_o> --_me%%@IE)d2\u8b,m@DCF 37u {J3Fz( ӻ3o5@UH.wl)g}EqRZ3-9+}+˒yy/9p7cgGf52ˣ>OˍKq C{k!]#liDR΢0R~>k`x[L<:'mp!)SO3)%z3 v&eը f}~SyAp {)C4'cbSL7 +6ުV?!`mk<夋ͺzc鑹8+@Rq_"L}j" Ӣ#z+?w`7b[)FRO H>kgoFl k<Ӓg;fr݌NRՁ7:KsFG;=IF1^qej&i/Isq'=m-+ej-s&m/S l:8>P(4f YwflꇶϪe,A:fD,q2h[=qZr9Pb"8)|ciC)|<ٳ 2{K^[<}Ipzor['RWhmFL -gy!/VQ~:7Pm^isi#hU(܎H@Zo =o=# ꤺ>M./0Ooo֥XDk(+ʻkW~̾SG |DvNm%IV {y ]0}}뫩h:;b*L ~f ޙ⟑>{}y/rkv_'c)u2^ 9ay}[p)rpSܥg뚃7ww_I ْ-#A4,56Bu? x)^g ㉧n, ʖoIϼDlƺ%\("\4TmjFsTx<~Di;u7#ٺ g'0չmR[GR'^Ekj(45g'cNbj _wY,gvrEষֺjOyZp ϑĉ< 1X`+EwT%::Q~tJ3Sks+&ϩfΪ,Ee+zP)ɄOz_ėM'9~zt {8qʀ!vg T+aBUQuzaEJBcN'&>˞&_}JNx^GF=k^b5e_I񏻸2M]VE7bg|8"E}[0KTcOD]0f;V{yH˼cՃWQeȳ2eMZ5>jЧ&.rPJGzQd$?U{G ʾ{DX~0~BtHq>k@J->v|.[Qk-}M-ⷱ&% B_oWu 25҈[TjE\BO#vq~wlUeKc1+_w?vTܩ4Y5{(@k,vMyc] ܼH<."5+?zErKa!knbC~^Z^7W Y}kl#1$t>.y|ޒ(86ВH^:{ͽؠ:ƕ{s&4( /t\?^Ys|$3J9DT$>}0NJoCfXOe}'OFЬrW?uJ@hC3y52# +^εO{iAi. ,MmelK}_¹()2;r\>/;*r ..E;'*7ȋ"pZqNhPtMk]eHf=1Mc8EW筵CA-o!g8*rF6*8j3uvsDM|(N021W-g)5 d^veK\d,r =i&Fe9;Dpf|D>t]Lpzс4uq2~ZYHTKȦ*͘ERu"Z'O- 88> endobj 78 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /PXRUNV+CMITT10 /ItalicAngle -14.04 /StemV 69 /XHeight 431 /FontBBox [11 -233 669 696] /Flags 4 /CharSet (/hyphen/N/a/d/e/i/l/p/q/r/s/t/u/y) /FontFile 79 0 R >> endobj 100 0 obj [525 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 525 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 525 0 0 525 525 0 0 0 525 0 0 525 0 0 0 525 525 525 525 525 525 0 0 0 525 ] endobj 99 0 obj << /Type /Encoding /Differences [ 0 /.notdef 45/hyphen 46/.notdef 78/N 79/.notdef 97/a 98/.notdef 100/d/e 102/.notdef 105/i 106/.notdef 108/l 109/.notdef 112/p/q/r/s/t/u 118/.notdef 121/y 122/.notdef] >> endobj 63 0 obj << /Length1 845 /Length2 2540 /Length3 532 /Length 3144 /Filter /FlateDecode >> stream xy<K Ec;O PvB%413Y slMv-K)kZ,'[bHdSsϹ?|{>Gq=܀@=R) 8Z(*AD6B~ FFiB#*E'yfFoCH'qc}xI d _ A N$  ȜB??-˅0HR,!H+*.K߀ԏL|8͏,)?:?ذ sל#O2Ə:ה 6$4@đ}uBwK޳(  P?57": D!P(4w]&<@xjNDZ (2F"(T & Ro;= +\)4  IZOFH_$@R"$/k]=*CC*3j.;Z A ޏN)"7?42A<%Ůl] Nɏh,OAL>reD"EHE;# D Q=2O.Xf= ~ōҴ'#]/c{gyX~@kfAc}61/+A~<ʩL'-OfSs[%\RM=ޯSb9-/R `LhKZfe;̌t׎smbSLDՑ랢܋ f9)Ez2D"#ơ! n_O:D~cA֠&.9Kt0K?,hwYU ed [ԍ,Ck+#2j&ȻJ vZAC6uTiywl?cK!;ݛ֤KgʔYV*, 7{54iZ?sEԲawŠV9ڌ!{!7#ė}6NoZx!JsP^2D;?Uv%X{b |UxWeP6q9&bt<23|oU]R_bc𾢱~ySwÝͯwFGz>RhBS)32lo\8z |uyj[ruEzQwK}?FKw :^{yujd.x)gֿaRX+vi߸=:>)h!Y±rKc^_oOZ/f-t r(RrTBOɆ ןIB?׻maq􊪱9\vRԯET[O)x:?/+q*w6ɴwހ'5{ l2LHzjÃ?^?KcXY%PGm?K'+<2$%#; ZZ =:ߜ{D~ .իpP1ɬۥ~D9`F?ps/PX1(.i5]WiаL*<\w›aeuP'uryJCSޭWZ3dtCMj'9yu'iX] /2`$ zmPGcy/aLcMOD-kng>w>je^f]0EUpI]Tb$"v.rȫm3K`9UUrJ M,ٙxU9q{o%ț:ӃZJX>쇛]]Ul\ov8iM3 ?(}g^.dhJdPa9{r>cķ{/p+X lzy@YkFҩ-O5,MMg\IW,Jlo>Ŝ}eQAo7p&XBECIWdJH .ft> endobj 62 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /LEVTCH+CMTI9 /ItalicAngle -14.04 /StemV 70 /XHeight 431 /FontBBox [-35 -250 1148 750] /Flags 4 /CharSet (/C/L/i/m/n/o/p/s) /FontFile 63 0 R >> endobj 102 0 obj [735 0 0 0 0 0 0 0 0 644 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 315 0 0 0 840 577 525 525 0 0 420 ] endobj 101 0 obj << /Type /Encoding /Differences [ 0 /.notdef 67/C 68/.notdef 76/L 77/.notdef 105/i 106/.notdef 109/m/n/o/p 113/.notdef 115/s 116/.notdef] >> endobj 57 0 obj << /Length1 871 /Length2 2241 /Length3 532 /Length 2847 /Filter /FlateDecode >> stream xy<ǭdVM?b,c0 CLDBZ,c7Lf3f0HbPVETr"Y(["EVY9u;}Y?yUX AgtQ @AmX Mawؠ)21AV?@_@Bˢ  c(D _H{D VT*ಚA +$BP(D!_ЏB W a YA|Q_&HbЩ\! ~/!8@[-: 4 a, , ¡gݏ zM %$9SD ؾ)@Z[۸9j}_73Bgr] ƨ C?_z҉ ο@`\0QNC0Kg)$G2Yݦ!@s }L$/BE  ?>HO ?!dA?P5#4\70І ȿ9,HgRBd2= >;q#8BW(Bگrܪ.Dsik$TRKl"3N _= ZjԲѠF٣g34Hp*[m[*RX4Uvy3y;)z<sGn)B@#Zo\7齾G4o u7*?q#S, "w;Y͐ o重 ^/}oA{V'0QUs4<@&4rDR]>9s&ңyո#oz\<ҸBdHB;ǽLcף{X׻|͎a/M Ji5&gv8̽3wU7$/ݱ=szUAEc-*R0i'Z{˦21#5J+]&H7·===Ll1%Ѵ@KlQٌיCλ4X#\/L!s5GdBd5UyE푉r$td0kbyM [}Dz*Qed'|P]qO,=t%'BD+L:j/g*ƿHLy E2;vU݉.;D!=k36Vڸ\-̽< R;й,QJSl=B QK}~ p@Bpz^%cߎa,u@R"I%=D{aOmnTॻf9缥a-g-yvtϘ aCUg2 Ϻs@'Cړ'f^j化mhrA; _COJ۝rC?EH^{S9=`B=B{Gp8ʹЏ`$: d߸ ֹJK~zr1mndX5qSQ;\G%[佉v8672P!wh=rPOã5{4*3%QT՚D.}zq=1 +J5dLOxaZ[sBY5CMѯloD,jGq8'tN<2A^_Peήk/ /5OG+y2c'9hKGTɎ5rW[;6]]X-5L{6n;ñAQs&:6K@nixA}E{}M浰bIHJm^]# Y|IE1LC/-"Yd$ݪ̈́,hS^HxM֬[N}Mrcj27X|=֗T1IrJn4Gv)w 3^1#͹c_.%5 l{M@9hIܨ^R0ء7"2+ t(cvt-'0iPaG3P0hr<%=\ X䣒-O~xx\| M=I_p=L5[21$wX)u)mUIʈԷс 7 +xgѾC琶Qi78j`.9ܶ %S}ݯ/0k>f>lMwح@ 9cp)Fģ1mɕ/OAuW/nᲗ!{qhć!daַv_rep;Eᖙ$[NBH\rSAݙzD*H`4+O@Hcendstream endobj 58 0 obj << /Type /Font /Subtype /Type1 /Encoding 103 0 R /FirstChar 45 /LastChar 121 /Widths 104 0 R /BaseFont /BBCULT+CMTT9 /FontDescriptor 56 0 R >> endobj 56 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /BBCULT+CMTT9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-6 -233 542 698] /Flags 4 /CharSet (/hyphen/a/c/e/l/o/p/r/s/y) /FontFile 57 0 R >> endobj 104 0 obj [525 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 525 0 525 0 525 0 0 0 0 0 0 525 0 0 525 525 0 525 525 0 0 0 0 0 525 ] endobj 103 0 obj << /Type /Encoding /Differences [ 0 /.notdef 45/hyphen 46/.notdef 97/a 98/.notdef 99/c 100/.notdef 101/e 102/.notdef 108/l 109/.notdef 111/o/p 113/.notdef 114/r/s 116/.notdef 121/y 122/.notdef] >> endobj 51 0 obj << /Length1 1179 /Length2 5897 /Length3 532 /Length 6637 /Filter /FlateDecode >> stream xe\QBBPaPAR@J:D:jin)Av^Wٙ7=<)" uq^$T N.lI } vAq's7K^Al$jn`d nqmJ`G 3B8?N8bʉ L&c9 ݿS8R d ManS6P|i!N`?#g߲`a6vN`R-ȿԔ P'fPq[sk_!(\ 1U:Xpȟq?%cS(/)+mRCmjG q8@B߿ ()[)| HxP[S+rGȑx`\&h?C|߄,@(7J!/@ /q!C=DC" "%!"5lFR"5`awp{=DZ9C=DZwzVn?  A7/ryB'㟯6rfPC iPeJcpT2tMu]8qYj зh]n(moGcSnݛ)Oӕ6]?imyͷDެ\ۏP3ӭ5Bj_Щ>M/ Yty8mmDppIoFBuHu[ 铚2j-rل) ǏIGB؛۴ |KE/ - g anc-MjQ3 gt2&pQj̈́HZR#T#8tKSܨhW5qԳ:W+,,JOzGbѰ85P e4]3J wO9am`y_,~N=%1Qbh.i} 4S!1R{noq!"ݴUT NIN,8sl/~Y(3wBo+qv==di`E3e5rk)P*X2^6 @4e4yhn絎F^ (,gUGG4_ZJ&6lFʉ S}2̎i&ZUfgjmH">ONv%УDd$|1,$HF\It2˛z0lukpd Dq(}jtnډ?Ͷ>+/;8UQϚ p^ȋ ڟG!~N|<͙ Օ@Hތ?~W\vMޤe{0yAR$:5]+{9z?[ZHyJ?>Xfe&2/&ayZIΌz0R QJASB_ZܔgloI:*$5n;rԼ0;hC!.>V&uoߏF1H^aw/\\HRT$AN?/.Mj+'yM97o):In,_>m<7F# uuˋ; &-ŋytQő[ڦi-څrPՏ? 4* x~FFI{>^&ˌc8ʄ+f]2W"j$ыW ==??9FF< }[[if$D|")#:yJ=|Xe`.,Yls$ccկ~O{+f' *OLq]m6z$ĆҢ 3|E1|BS󛮪a[ !O"5zfؖb/uNZKYыٞU?^xLy`YQL4Bl1ުi>oD d\\@тJ>&VxzeG//6LG`a燖)l٧Ĩ]{^ )i<>⮶}}5kL  :| ,p(R/0S:x^ Xg2$X74\Nљj0|3q0{hlVؾEuԾkQA\v!K=r}1"l3ie\ <!]L{lvXaaHFꙎÈ8Udb~hjs@/JuچGXNxf6[*q({0tF  ?s~)t Z-"rƾ[=MT:bۑy}{q Q2x&lWV2קA&"ĥoDJxb}i(Nrb+(V\:rc~6˙Mή(`;^4h3_-EF썽 Zȁo}W.kIiʤRի "*Uܡ?9yo(_ߕ~$G{vq ԰ O9c#Ǿzf8y&$tp~ ].OR$J%3P'rYw-qQNєA #e"*A.Gn^ʭo]tGv;@Q6w |L2[u'qEҀ=ptSAaZ^ș(H}ufvRߥw1s"K 1絏guxFrώTۚbqt?W6(9N?Yx8R,G=C ?y/]Wz(W()ٽjNmѸORutTP{qP͌s֕%uVA`+u;8W#1ظf7 9{#1M@J8SN_W*ϲ91|J#ry/,P\GcZ|; Obʻi(ڍM|MŰ5-TjvXm)7u\^4EE0kooP8Q@t%Ua~Da8,&B ͚n>1ܔ _vW+ E& HíXw E`(68<ָ3QFQ#>$zj 9a>X6Y&Fb7;rLH[(n^ wFmEFhU-sp!4쇶kbψyhx($,ͪӊR,̤Y~Cgs~]Ɗ:ɯhomL&MNcex-zio&3}vpJ2vn<߀w`q -}8baw*]:e#hz$8E]Fԟ+]XdM D[ƺAiU}FOiFP!2)R1~IyøTk't߱ZGiFco)Ͻʔ1{^РϲIan <|E|eFL/ wGY!١Ggm6PDMsio#pr]vn r~^T_]u].cńZ*C#n3}x;H |wk-j:z~ Q^UuN'un=Şe+|V3Gd]6:w`wjڪ宪D C]%sjA*.byU)Hvy).  @X#}(c.7Cf˗~8w\VH bgyڷ@4zJGTQ,7HD]a~R6nDL7:_` UNfBK,h /2B-"<[qy难Vҝ9 Dτt˒`1PH 0. )bmf?)jzjпJT;>|sl?fLH WH DX*_W::Lv0Ncb而S*`SyHgޒ@RR3qxb.^I z +#SE#eRe˘' RF¾@V@7Tto)t#oh.Enh_ȭS5:4*GRgDO{;cI<1S.̀(#9.*-X>#YkʘB`d,j5/ pwQ3Rx&A}l1A.P\g@ jWo .yΑd8Kx(D#N"D*S5Fդ') m$kj~iT)iXOba 3Xc9][U(M@sT>r?Dkfvd^Pendstream endobj 52 0 obj << /Type /Font /Subtype /Type1 /Encoding 105 0 R /FirstChar 46 /LastChar 121 /Widths 106 0 R /BaseFont /JCCZEW+CMR9 /FontDescriptor 50 0 R >> endobj 50 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /JCCZEW+CMR9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-39 -250 1036 750] /Flags 4 /CharSet (/period/A/B/E/I/M/P/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y) /FontFile 51 0 R >> endobj 106 0 obj [285 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 771 728 0 0 699 0 0 0 371 0 0 0 942 0 0 699 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 514 571 457 571 457 314 514 571 285 0 542 285 856 571 514 571 542 402 405 400 571 542 742 542 542 ] endobj 105 0 obj << /Type /Encoding /Differences [ 0 /.notdef 46/period 47/.notdef 65/A/B 67/.notdef 69/E 70/.notdef 73/I 74/.notdef 77/M 78/.notdef 80/P 81/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y 122/.notdef] >> endobj 48 0 obj << /Length1 786 /Length2 1519 /Length3 532 /Length 2088 /Filter /FlateDecode >> stream xRy<(M%),ؗHS2323f3c`B p" QIdמetn:C{y_s}}O] 0Ab)AxHdA0݆}4167037<c@,@L24t i"  I!, /` dp@2d@-9H2L)@SdR Y$t* 7L}/n˦ReyQFi>L a@A{'՚HشYD*D Z$B,R @!RJ7!ma\i!:0/䟢a@\D1";U$ E`d  "! 21D'\t%:"(0f lPPO@/ }Eٌ_zƀH 6A&F# HgL(oA.HB $AYէJuIj 4>_;xZz ' 9[$TCv0":lO}Kc9NW!;?ƾt;#1'^-y3wߞsմ9z#UM>M'M9Tj2 Ce2$wFKul"{l;g|7Ov: gQ!l:xͮ{#E!cƵ yS[]XľS.RdB<[_ YFxV=̉NN |?2xԀ\=p$3l[M;Eu/Skj̎C, $^7R9jSᩨ藹^n5#&4p$EQmcuubB[H"l(2,w̒>XkakoZ'WO([JC#_vt-.*֢todZ}M|\s顛B~v`~5~l/P$mjꎜ[ftz Ks4}?^ә:WO$Q=)M1?h2gN#H1[uBO@Kořŧ N~Kuѳ]zѨaUiM #[՞\(.D0/8!PZ&SOhvߋv%]*r8z l s ߰du'q=;ؘ (:dT. VW7~52D(}/žfpËΡ )a%# kWQ2Outj)(a'+Vb7"7.ӽby_7H#Rϧ 'AwvOZ~EQpNY%ܶS&.&wGYgO MZ^]"9gc0&;X,I+$3L~G|n+U3B) 516o#S\OJs?ؐ5\3qr\6T\e՜7R/^3:i%Y%>S<)p#d3WN u'{Pť>>d=Q7!Da3 G~Q> endobj 47 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /LTTKCV+CMR8 /ItalicAngle 0 /StemV 76 /XHeight 431 /FontBBox [-36 -250 1070 750] /Flags 4 /CharSet (/one/two/three/four) /FontFile 48 0 R >> endobj 108 0 obj [531 531 531 531 ] endobj 107 0 obj << /Type /Encoding /Differences [ 0 /.notdef 49/one/two/three/four 53/.notdef] >> endobj 42 0 obj << /Length1 750 /Length2 576 /Length3 532 /Length 1110 /Filter /FlateDecode >> stream xSU uLOJu+53Rp 44P03RUu.JM,sI,IR04Tp,MW04U002225RUp/,L(Qp)2WpM-LNSM,HZRQZZTeh\ǥrg^Z9D8&UZT tБ @'T*qJB7ܭ4'/1d<80s3s**s JKR|SRЕB盚Y.Y옗khg`l ,vˬHM ,IPHK)N楠;|`軺kC,WRY`P "P*ʬP6300*B+2׼̼t#S3ĢJ.` L 2RR+R+./jQMBZ~(ZI? % q.L89WTY*Z 644S077EQ\ZTWN+2AZuZ~uKmm+\_XŪڗ7D쨛Rl:/P1dɫϾ(l=Uhd_OܗEkv-X1tލ`i_y. 1dz:un~Q?3/S}] $e~s]F1ʻ/Q?m򻳷|<ċݺ/q'}I+6EgxT.GgtvՏGU|~]Rޅ_k9:{pG d}dN<6-uBoH=cMvHzqaRK~,K̞}˛myo~v _s>.#ҭߦ{/əkܗ\m|rXϾadj|ǝR/,2p0, HIM,*M,Irzendstream endobj 43 0 obj << /Type /Font /Subtype /Type1 /Encoding 109 0 R /FirstChar 15 /LastChar 15 /Widths 110 0 R /BaseFont /EDLPPS+CMSY10 /FontDescriptor 41 0 R >> endobj 41 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /EDLPPS+CMSY10 /ItalicAngle -14.035 /StemV 85 /XHeight 431 /FontBBox [-29 -960 1116 775] /Flags 4 /CharSet (/bullet) /FontFile 42 0 R >> endobj 110 0 obj [500 ] endobj 109 0 obj << /Type /Encoding /Differences [ 0 /.notdef 15/bullet 16/.notdef] >> endobj 39 0 obj << /Length1 1877 /Length2 11985 /Length3 532 /Length 13036 /Filter /FlateDecode >> stream xUXݲpiw$8 wwn+<< Fz;|Uԙ,@f@i3?@BQC*DM-4u9Jl||1';7EH]lt$.6榎ES7k=@dntfytx-6n3#?Nr -ܝg K9{,H,J p7 ,.nodOn`c 'w7 @dtqTm)-lsU\`BWhULm4]1o@lDgͤA6Vv.n7 qz^`afGxO NrZ_A.?l' `1upGM(W0'+h+HfWvݟ X`'vq?#`q7u]@`g#utv6 p6eu]o˺=r 7XoC|qQn ϙq?`?n/%77G;!pW??S7!p?[oݵ  V 9B_ v!/k8ALaq 5B_m ;B_`+l|y2q |XW xx tNmv{C̽l#я *OjWHK5U*bعB ^"u,|d+L)M*?Jր?u&0*X&t-٭t2M\ 87d©S~_ m .3^WW;q;c[5s"#!&izC/9Te2yhUV3XqH]0f6+.F;e/^mz"׌˰2뇕n̹{S /Ȳ]v^gp*z1oum}{‡"X ,G0$t{W4FDH -tIP;7 7P5 yx}0 `u0!KP G :I< ZVqLי#t"ÕIA Of!\y{yR9 VPE3Xpj;s5o}7I ߩj \茻McjWv2eK8_ L'8_Vx,"I/-䕦fŸrxR f !ZiH~AvX8r&|q.NaQYL2luE2[A6:ۨNjO[iaOQռ#r[±*pue\˵=M5mK0 IBr:b0OzT9Zthɛ<hC}N6]yG/ =Wr*#ѡ!5?/~Î$|Pq^whBaDwh~]GX %~4>k]aerGJ8Fլ~1O,cQ㬍Z )#M8_f=M<+fa4#*|bgmDt8j^ 硪ؕڰ+DNxb:3 FrȡX\-T VH@k/|IJ-KiR~-WtڝW [VA./Itv̧[^S{|2ь t:ɔX^e7 uI`"I}.rpƚ<ջ8yits9 ? )v`r=!\Y!X-C酈VZ)~AE5>FeSC웨!t\\$*4~a:>&:f+йlo"3pDyX5@9'⯶=ܜШVVfl lr~T;y)X8s߻ jA/w 3`H'jN_ -*0WR4SRC ԏs,*pʬ/|gRcDSZ2Mjiܩe>yѬ:*:X6w:j|0@ }Hg+}",b}\"a/홈y/4;s~̕CxGA§HњGYl,,]bAO-a?怜=[4&;r@K)5Ӄ!EWӂfxNJ!=HMi|^_!EC& Ave o,WZc/ğL Hkڲ]Zӕ)nc/^5FyA7p19Eu!)(W02,i#Al$Ds3*! T|njJ1M,\S;|Qɡoww3ƅ p7O|ogOk0GSwۗ3 nù>gXRg1]OՎ/y-_koqT̒X}Æx~Vx\=_ob1B0Z6c}ve_FY[cptVŌ7TNR  `0og֚ 75lMC tP0 AOXB@@W1>с8N^nNwȽP00bcU @9Csy{|V~Ja+ny,ocX%·鉈Uk8YP#KZ1+X2ERY ~p^Gf"=/i+s?I~F{-hf T V8sz &!$a%+NkGWn*{ 3.b)Z}FE>7'b-n}$x_֯7vhSQco=u[-Z΄Z띚/t!TkNcn8J1A1iz yj.HO>9SL9f8R@ 8j445ھW{ۭD)d^*\( V\Q=Ilsj\ km7g.Ȑf<D\,af6CeNJUxmfYgM̟ MU)iiL ńfnBOxU;=mFv|n"GU#=)gYW5x  /4J^fUZ+ ^Ջ+B6\DfB_ $a~Z'bUct}&QKVo_CAW}4+:H`hҭ}0Dqd ')X70I]xaIM"Ec",]M݊~8։ԇjXK`G.&oB$k՜uTZ$k\a|g!=~\߾Ԫ ɠJMUV޶/6 Qݢ N ɬHc ékÃO4s7mCÆ"Ӧ1A_Lo&QNXY:xꛃ&MQpqGeTrr8SlD)SS3v] naZifEKJچc 'AgG:%7waX۪ 19#/W%Iɭ|!͔=e I[g6`?|(szň{V#8HQ2o}nPisvn۩7_]yQ +{{ȖtSun#2n[gdZC"ұCGHt۝ON2[t|WIo.^^c9G,#h(TF71Pny&fv_ Qef>M0z)KypGM>~̖q*ZY f>0f @2΅}^w7($` NRy-W"hMʼX~̫{=0!&O+X:pE7/:8,y6JGPܭU_V^sQ~"i(AD PYE?d+;:5_O˶{SQ(Fe.Jz6V^LA%Fs$ &ek /w'HTHFkW1Pg$kvo9sg˿ח[LH+9ٲ|& h`bg9$jܗqp?(Sx"Ľ=CWe,ةpX(}$?Cur yCUd3{Wjk=z.^5{qʎSm)xM{f6 Հc dHa[yc/?W9>,둋H 5$~>jC ZER4)Sbv@#чJ2]w^liԵPMYv Էai(wr'Y wng~}lBOvԑ&Q{6"qV77U2W?Nhrբ32 WY:#%~H͂@—c|ig-MX4%Z5w;\ ij6(˹F\]ް]HGy6"*9V7}.:tdӢ3# e A@~NH.¼dr]"h. 1NhLB~jG |L7'urN7M#4vs/'WW'- >2xO]|sj{4yB+bSBN ]U6Tq6G嫽ɮ3_9Pvp+b>iN7tӽ5U^+ y2f/Hm!hHߨ?-9 Em|ɿ)z=n1[9:3Ek^8] ]zK,Vs]^B^R[8ʤw|S2߱EP"%b! j LtlT/1{4U"{xMKys R0ߥWIMXIWmE?\v\, BOບQn6#wO˞oShHv;f=ճtM*m,.6)Sz1/ e;_N׹]8)LZr uG42fbp,r -/ ?60x^r?\<{[P%BzuH 70ڴ-\x$ތ~n_>6uLAOzQnT O|epnv{oMG FI~EUqEӍ]ĒN ,[W8։}&y7 RHe1+ v:ڢ!sl~+E/(CGmbݯ(:jFTQ@DR識yW8A1f`\CA{N2awJI)p,A;vӞ5cW&M M9hh2ؕ:XP$,xFŋ) Y¬{3B hfHNLB- CRs-rH`y!ۇC2k+H{>"jݺP(ՁWI@׺&O3.㕺2 a'a_^< K-Sye |RښzBLO'_l%>,.gJR}YWE+FTwYl/r.>)ˆƢdCҀDҳ2 !ouWSEfF+ʂ!%tF{bϐuq%(]Χ~z/+U׌}>Ⱦ%He]dϸizt!Ѻļ&HDu-EN ֿ!DB= ?Ģv X1'ƴH8^*$J]˭M g@,k{9>6Gj~ 83_pTaQ֎#/A Z ~wYՉm"a5鲋PRFQz@&"~Al@жYm < )p{)m(wjm僫V?nK&Vg<ί}^υu1$+D,T! J>.{Cg2FAX%vK3RUC ~y\-?~d5Yaa.M;/fΊ^C_ oIZPJ}z# ú/W,%Td;sa qs +aLёq\dڛCj[;Q"Y<{i>M!vmՔU-uhox=䃝ͩ ä+'ڡ#+ֲB-!OrrvS2E%n³ƀtmؼup|k^1Ta!i52vpMZ44#{Nd\bJ6X>y69Wasa3kt 9^|xTNIr颾DkP$&H.,ߥ9~u }̵otnߺp9y˝kakˊ  `@gsK#LΝC_^@hQ;r ׶P?C>fʡy劎.QsM`U7)]l oDUok@܇E󀑷^dN#[ƞ؋vT|e{~y P?eV cUi/ %jDeWp۴*n7/N"V19-}}lZNߤԊ:iSwX`c/8z²&Iw|Gn*EEavJc$jjVPo*[z1MDj9ב"u6!ґ'|˪66ltބL9&JDFDYD^\8׻qkF~|ݡMppC(zt~$3,͗ŊYM69 T|WXk@ ?aE^ Z0ےqf b9c/S5"j_*4B?c/"tjI%kxd~I]:Z d@λCk$K[d,% 1c%[FݼrD?[U֬{W5UG; 6/Էe˵JJb~!sHkZ\HyD'M>GU 򡺔Jaʺ+r~5"ictҎKwPhgqO'ש'eDzjWIzb2xMEC:'Pg0 }Ra\QUP+F }58-'A0_2 T^87߼znm͓W:s7NͿ(im,&`h{ҺGS*ў>8I'P9Gfp,30MλbN7=)~aehOKJRƾ r-@9= . 1@MϬӴv^-SPWcjf]BUbߑJ .3 8?&ҩJOX74xnH­x@%uߴ'`ZrO+$~@ܕ.gպ*e)"5q0pD"=d:ZSޓ'm({Mst^z__{Ör|c\DMI#nm|/y6gilvب6!c*AKz's_5qzDm>τP%LF"lMr2rg|^פ }:ӉQxƧ5GX[Z$l?!߳Rw,C;w[1?r2TZ~YԴeOBf1eGnAM<($RޒM1ɢ_f.g5D TD[*oesTPqDsg讦y?Ŕ`ӟ*iѬs5> endobj 38 0 obj << /Ascent 611 /CapHeight 611 /Descent -222 /FontName /ALDDEX+CMTT10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-4 -235 731 800] /Flags 4 /CharSet (/quotedbl/numbersign/ampersand/quoteright/parenleft/parenright/asterisk/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/equal/greater/A/B/C/D/E/F/G/H/I/L/M/N/O/P/R/S/T/U/V/W/quoteleft/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 39 0 R >> endobj 112 0 obj [525 525 0 0 525 525 525 525 525 0 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 0 525 525 0 0 525 525 525 525 525 525 525 525 525 0 0 525 525 525 525 525 0 525 525 525 525 525 525 0 0 0 0 0 0 0 0 525 525 525 525 525 525 525 525 525 525 0 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 ] endobj 111 0 obj << /Type /Encoding /Differences [ 0 /.notdef 34/quotedbl/numbersign 36/.notdef 38/ampersand/quoteright/parenleft/parenright/asterisk 43/.notdef 44/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon 60/.notdef 61/equal/greater 63/.notdef 65/A/B/C/D/E/F/G/H/I 74/.notdef 76/L/M/N/O/P 81/.notdef 82/R/S/T/U/V/W 88/.notdef 96/quoteleft/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 123/.notdef] >> endobj 36 0 obj << /Length1 889 /Length2 2612 /Length3 532 /Length 3240 /Filter /FlateDecode >> stream xSi<"FY)3WJv:*K̃cf̂^.D0f+dϒ}}Q({N9<ϗ}߷qS -20Ycd`PDx. 0UUEq H:xvr&:-WF"p 2<,`GA2Ub+H9H J(4 8NhD{K8G%gXm:veӲJY}f7;i=Rx2ELeyV |-(Jfm;ҧ"W?%Sn bZ|{Hd̈́-M? α+RZv:Vhnځ:me۳oˏ8R=$I, X7f^C`ML\h6zb].z%e> x5Ʀsz./2yj]thаz&c7#o"ѾB1&՗ MG iE {?ؽ)5Ľu`sG/ٚhR+·%Xt/ϧ#s{KΓ7=x[s?QqR/ڻ:hQU[MM?oI_Gnji@fFJ.&S/2n,t3<^c]g+=Lj.8\QT#_-B+~ UI8xJP(!X^^ 殷;94  ٛV}AE%X/A&#NZƬP$șGY;_CC1[M!>慆=XhG+}B%'x/y69#ls*>bq'f|*Mֺ1|'NYC#/,21 zI@|r$9q^xdr̍)0doj~; K'!]=T+xY\kNB)C߼3z .OlI;迨 zYoWr8[礂Vkwv"ZR7XOfyʃQt?ȩes>1ȿF_}lh{EM~x<=;klyoOÜZ=s]H}S]8L BcwUF\̭c$lMJ{Ͼ3YJp~*6C52Tsd/FoOJ HqK l7ɔp':è>#Lݎ.^<mt W쨰Zh@yrK.{[,ni,cO4i˻vI vK4_Mj5Y~󡹙JW fƻ-2'5։P8]?/yȧsS Wu]#te|_|.G\ JgX\'ZvkQ\ Xt= R.{HmSL䉛{l:LT3U'5BuI$PĤNȮՃJl_RtBG30LK'xka&M#jټH`gբۤSn,NL?߭ JKͺ$lAC $DxWwְendstream endobj 37 0 obj << /Type /Font /Subtype /Type1 /Encoding 113 0 R /FirstChar 48 /LastChar 57 /Widths 114 0 R /BaseFont /GPZGKH+CMR6 /FontDescriptor 35 0 R >> endobj 35 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /GPZGKH+CMR6 /ItalicAngle 0 /StemV 83 /XHeight 431 /FontBBox [-20 -250 1193 750] /Flags 4 /CharSet (/zero/one/two/three/four/five/six/seven/eight/nine) /FontFile 36 0 R >> endobj 114 0 obj [611 611 611 611 611 611 611 611 611 611 ] endobj 113 0 obj << /Type /Encoding /Differences [ 0 /.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine 58/.notdef] >> endobj 30 0 obj << /Length1 1085 /Length2 5717 /Length3 532 /Length 6425 /Filter /FlateDecode >> stream xe\TvsfP@@bFB)IA iSiA9f}u=uy" m WC܄ & ɸ1pReiiPB$e$dDE@e7ikUK$ Ttc6PPfwaump7oa#@#+ A @ h E@eD!@a|Ǹ^^^GQ@AC_{OjzPלCuB:zu08RS?)H ꈴQD:B1a?HW5ft"ps\O #]mMؿ_@(7og8[7C~0H/X \ >Y* Cl"@(&>B$| "Q0u$B]/^O@cWI0W$/V&1 7]+ME&) 7IA6")@xiA?6rk#(9F?u"ם<JJhB"@!MJBw rǻ>\d<^p28F6>:jp!+KjApSHe,WL͐ >M=:i[C/0U+v?5Ltߠ~mLki')=|˶\#;q4DXaڎ x71~q0%Oq|K"lI?XwEc{,_]bfGfnJGfh9Ewxi8a9K>)9HtT@9mVG;H0I`^t}EW%SӠ9( V/g-s8nsG{!+ioq3N{UD9G7:@ej43ޣ|\˓ޙ<|y {? ~Sqb,+CG5ذ*̧ l16@7_imdF|ҍnTHROehybRc]fc?(l lNݟNҳmﴥZg 8ZEpʎ^p$۠-:'4)P^&E)'|#TȹglX΁wo'}Ýu0bnڌG/>)<9[+!/B c"MR&oRƲ0X@d;B wZDڒZrf:eGo,z{ o5O05 q\Ns'0`X.5LJlLIE>sG>bL 씦߲,'$JF~D⤜m,褸^1!'[@k:u/>W^I*d1DN_uXP532j  #賻)bKLhs1/UTP79SYต81qer؏/6gtQ+̦^O|{ta mK7߫ƪpދx:gȝqc.;OE=8OlVb$#߫G}Fv}LD=j+/6M I׮qO $\gC^1UaO8ia#*;hQIM3Y ?C W!wk%H*-A?S~hbHP$g䒹WZA5mh6^ ^!^ 0JVLE}`; na+A)P5y>]Ztq\sYPl!ݑH:]WhsKظ `Hn E~}لc;htfкJXY]oe"qr{3Hʈ +(qQl'GciXS%5i nǾ0~cE>C?KE2<v@Om ;C2bB(Qїw/`?'s˗oŪ/(¨YJl_^ O/MʤfJ^(>ZyRقwLct4 ]=3qhی.h]3+c˄Z.apfo.`ws,\~ ]E]r|ZU-^3ᠵ$fK|@̐x21+Lva X6ٮEub7#-{v }_pkZ%-漢ce`pX~dz[;d"N,<|8_7۝[+0%( iZP !T{5JWĂM{$q?閨w5}ch5m1{fs/cDL1A{gfbly^d H>xZEGF4nWm|q+"ԡG M JLefAPQпZJjDX_Dş0_$kXY&lCHvƪr1xUvR?-M'd#ĕ\4`~$.yMX,+OTtypob-Vse>rHi225?K>HZ A.8.ZgqШ/=8&N[NsHvj.h4;Ӆ I ;tLxG>ɺ9VꤿÒ\#cosŤi{뙯&}q߷jI3OMzT9?~LSn+OE9BiBQǔvl#ԒYj wlխLÚPɆk* A[t*Snq=w\y![K\#6-*>4AY4v&sގmjR{>VuI7x[U$:ɸH榺>pA+/ >9EL[jzU,Z#*M4ʿ۰]<IhpjY4ri1#?٥$/%"g ȹ77iMt{|h@zbiFOq2"||bdod'Xם2t d,:!8jMUF~ 8U&nH7x !] ^lvn`IxY1GOq"ψ j;/؏jOCSsgA$N$Tܲj XTUgDTBo:7vۏm_p\jYB2\d`'[jǏ^:)#}x&MLNgz ;z?:"foѥqmV59H̍ߍ5x.9굗FzmS ӈ7it wkEK&%ʍU6 |:+J\UZ7 RJ'Hos :;n]]TїMP)IB^K݆vI]睳`EUmq')!'d/YQ ٠0@ېmYo~P '!ReF&DM:#ĜO"C+Qzyכ/̔ ]<sg!*stNl t~7Hi1T){0N%ᜟtSG҈pެТ1CCfߋmdI[Zx6qi /5J6+'e N2 Ӯ﩮}ŷ |mUz(qT!ea63UWxE*nj0ӮNp,#̢1D4F| TݙR.taPszTd^^6UJZC0VŐL!Ru? FU0FLTn,^%jņߠq;c_0t)C'"WS$;ig?so{KJvI l?h0}C]zmx6hтg "%ytz[e&Y%}KDnǴEYݲ`jT2@SpY.Svا/H=gxNﮛ+|ƾR1IىVSR2J,#YhKxዯ/Bfvc[z8ai2W ZZVX1ppD*v|ȎeU;zϷ x<6NӴ&Y'IGZ^IˆR^0 BL߇75BڂQ\Lҩ B#k >B8nc;ƿJ~HwW?yF׃yy |z' >'TWx*ht<U}ZkWbo0SU/#9qa Y|Z'㲿3eYhFgeb`XF꽡iB$UF8Irl34_PaOèj#]uҡyWEanE W4qC1nh'(Ɓ4pendstream endobj 31 0 obj << /Type /Font /Subtype /Type1 /Encoding 115 0 R /FirstChar 70 /LastChar 121 /Widths 116 0 R /BaseFont /RMKIHV+CMBXTI10 /FontDescriptor 29 0 R >> endobj 29 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName /RMKIHV+CMBXTI10 /ItalicAngle -14.04 /StemV 107 /XHeight 444 /FontBBox [-29 -250 1274 754] /Flags 4 /CharSet (/F/G/M/P/T/W/a/b/c/d/e/g/h/i/l/m/n/o/p/r/s/t/u/y) /FontFile 30 0 R >> endobj 116 0 obj [727 895 0 0 0 0 0 1073 0 0 787 0 0 0 796 0 0 1160 0 0 0 0 0 0 0 0 0 591 532 532 591 532 0 532 591 356 0 0 297 944 650 591 591 0 502 487 385 621 0 0 0 562 ] endobj 115 0 obj << /Type /Encoding /Differences [ 0 /.notdef 70/F/G 72/.notdef 77/M 78/.notdef 80/P 81/.notdef 84/T 85/.notdef 87/W 88/.notdef 97/a/b/c/d/e 102/.notdef 103/g/h/i 106/.notdef 108/l/m/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 121/y 122/.notdef] >> endobj 27 0 obj << /Length1 1290 /Length2 8341 /Length3 532 /Length 9142 /Filter /FlateDecode >> stream xU\\ %k8 4BpwwKp'A~d\\ovj=Oj*O"v& I;#++@LAM"DE%;Yځō@|V^^6$cBٻC,-4bJ؂ @c0@dZhlPZܙ"66pA)++0[IlfaSg 4ؤ4۸LAfH̊vjW/7lgqIgEcS[f;; ;S22tϨ%Pln0r0p׸`flg6O'-Nj ˟6 bey2k￿CL 38;!z%N'+l r^33^^; 0 k_9vN Sڲ?.ٙ0{ vxv`п,^+&nz͔Cf?:O`VCkֿ{e6 ? {=uz]/d0W՚_/|m_*k _uW]U/|Յk^8\ ۫?pQQ;7OFV.v#'˿d\K&y'fW rAVI !%>ypSF;3c@@$Ve'r̦f "^ (ش9oπGzЃYh{;gK.pUܹ'%sO>־cɦ?Z@#RvyvxzXϋݫS+()`fSYh6ǐXӬI2y_1 }JYPD.*rA'!;{y1T͕I8`b|RؼDsǛ!O#00,c|13fèul3NQ39#GH pY~^׏b!ɽMHKjt c 'C ̈X$Pĩ\o5U˜U`E&N,Pxdkʃǯ -%MV1Dv},/5z Z&J}yo4J΂M}0+H9$H'mL28)sޭS'),"[!E91&ݫ-UθzMEֻT";qLm)~H~H2y(vuŴ:[BGܽL /Dױ:IH;(pmr=< ~C|[_Ox`zFէѨ}UT|ǀ+rQd3xm2>VuBbn]7V\ӂ*M~tTUލCBB36Y ""̥Qc2s_:S*/~ߊuGb ! DHN.U_5Ug:1F4޲6كQB͎Uf,NQNm>*̥8wa xꕅ/dHHQRicRrWoLO%uj32`&{\N*BcD׏۝  @}@(Qx;FW؈Č䗃^gYa_qm!fCUTF滜[NFqxK?N2 N@'$/v߂OY1-w~o?~VMbntwt q>1>7jG87g'RoŶœ uV.3.s_Rͩ pxϜ (9zJiMKKT%t$DW[yHLy|.pC*Dy&H"zX7 ~Ny( !h~ŨT7-KkVDFU/MM-}17V9O&Eyv&r1+ .POt:ufAWIkwT{S_ `ZX!`-(.K)-Ah6|T|Ojo) }OAhS_ Y n"7EH9&X:%k#fܦbzFAlv_M:^^Hv5C}DŽn6IC!}enQT;rHahҴEU%Jrx06sq˙܅= qx_־|eJ!;3\0~Oxe=Q3c7fѝ3 ږDė8%Ϧ+Q)a38'_W+R3co$0 ΐkKW}Ok˟+>7S % v ^^% NS_ys 9;[Q'ͱ`S)Ϧ+(IZt!kK޹rL\F+-N !h@Q?KweY}| { =GmSrw۴^|ch"YŗBn"wb?(B0eI=zǝ(7WN c~ϛL$JH f̤YJ xK h2L'qo>@1a7-)=KcIĺ]BaL$p<&-XbQY)y7ל7EAPXB_G>7UߪOzꧯ=*0I]otm9H]}c>~ .- _isrCkIxj6UYHdݼ4rPis2iu]Yr7oQZ8# r6$87p{a 7HW,-w r-/k7x]$\PS_>.ˆ4ŃVkR)\]o8onω9 Exb)yUQ0{Cуdh:oMO &JYpq";p,%M($ͩ""mF/fH7k]L[WГgc1܂x9$m/^b[ Y %֓JZp_]]${y HnGLE}m1PHhs<@lbQ ;!x?D6Rva/h#b+2:ƭp {Ҿ_}afóEI5nU˦Ѹky49h2卻)\Iqho2$B;XfAHz~i[h'oIwA\0r{Wi OPﻧ&.~ ۶ɰ$dM~Va!tfN} BY'hZӦ6}ƌݢȈި7vgAgV<߇gch I-)ٻ>sk?& O,,2>k}T-Byvs!j TɐEǑ73ȬSDW2hA,dSؿ9'o7G]P7UOU!K7G8?(4ISiG̱q]>r[SDRvgpveq*X",&s^r 5. 4zx_hƭ^^&&V.JJ=~ٳ4Z}I_kՌ%Ye&HsH)Xvsހ5diwH&j͑.k<`.Y,.0p&PelB0ƣ/-y&¢Bh['[<3J>d?u=fRjHk.W5BDg}\8ã;N~oٯ!֜Zrz0ϟt:->߫ ,P ͜ΔQyOfQyEV]߃5fGIy3]&–F6xXl~EVب@uW7kox5_BbUr}ݤW-+=R#Z0KnR''_g!ϕl?KfK?(t~y$vLN(LP7R1\VS [U:vl ssѕ3FɟQꄫMr#(~oW8+8Iˢ۸N$v&D!,R0+KY䷜ "̯ւI q']7{VnKwtMa[ aexmHL>mMF!ۋz~Ej`=eQz~53xQ`黬A2X[T%}D JݯM ؛{=)%Im)3M;[+˚f)f,ǭ*􄎍,Ood {sȼ~g8abd.#_'QH~CdYѨ2闚iR?F2dnd!PMWu#G' vo` wbB' MY|?>E9K;qn*vp*9ҁ'M>V|B0Ԕ3}Zwb;[3]-xYp5 ߸Ǖ .O[%FC5!'j&ǜAƕwLA[9E](zIϺ0,[>ŵ_"'}N[ Q{p1D?<+E7GGg}bSVQXb1K㺞=>?ճq gI~TT%j'͔E|P̭FI\@ٿLr S1ZxD5M8`+Q#w e? ͔x;\N cɵ^g;w7gaH\E3)Զ{pdSB[l5%>sLB1$T{W=M_ѡ׋ Mn."e0(7'eٹjGD|3L/* _ Ia__hcVϪK0oY+hQ "腹BVeozMbQ} x1}+i[+4aDEtpZ'P/LyH d''P:7,M3a%2Fn9? (fjufRj f]%JxޜUE:t;(hﲏPE^?XOJ\T1LWJ2C#l5:V-PUDu5$>cpUmhCy&L*V'Gwr,{^**z7(MS'mL]FK+"K۰*ŒB? 8CPO~'==<yΪ~SH}N6p/r)^\7^td`Rf)Z|7knIDh.O#e e]钛ѡUo}unAG;AXx3VWcrmg#ɚz\"5OwU?Cj`amZaZl<,]=ݤ,3 SG5 M=9MatZ ',\S1`rjšX,\ f "M+Ic&]RYZ-hCJ4z.~NH=ʾ(0eSf ںܤFP'~O(qmI8 Sęxp,{/-X=fn 5lZQ8|N-a X(@6'񐬼NWP.-mAp_3}t $ވugJە‡xgXDLvί .23L=Y8je IIL$uxjX$u'-M=rQUwǴ ^ϝo|DhJ&zeBt1W%?_V+#nSK_ڋ?Wt:Bb_LUamT8,]=e v&4f76u6bmpIT ~5uoq.ogMּFM>OBvѻhqGόEKj+o]p\ RC~,vT[GosM!N{}Hi,S S1 Nl rf\kIkW7mਭsac3>Kkݐ~|0үRm= Fp)9b*X aҍ.LBL@ɧ)mlg&*靴0s'*P z$@Z-*ǰ/U@ >QRv6 9t Z?;`VXD*9*\ZCOBX d6p46Vcf)̇ZeS h+2(A l1;`N/jmxOO ;&hԮ|#z4n)>5L/y=ڮupqayo31]pΗ{ }Hk\TB,AZ.Tq!9b,]@ 𙈒rQg7~^qWw-BNX:/tw}h1%]yz31D6 {G‘؆ыG%(F+~9;|4T3aI2Lm¼EљsJ厄؉lݥxurYKwo_iqy#TgnMe<^3"kA0,$jg{ S)T.35{E'Qu`Dd q5X#FO9endstream endobj 28 0 obj << /Type /Font /Subtype /Type1 /Encoding 117 0 R /FirstChar 34 /LastChar 121 /Widths 118 0 R /BaseFont /DYBUAM+CMTI10 /FontDescriptor 26 0 R >> endobj 26 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /DYBUAM+CMTI10 /ItalicAngle -14.04 /StemV 68 /XHeight 431 /FontBBox [-163 -250 1146 969] /Flags 4 /CharSet (/quotedblright/period/zero/one/A/B/D/F/L/M/N/S/T/X/quotedblleft/a/b/c/d/e/f/g/h/i/l/m/n/o/p/q/r/s/t/u/v/y) /FontFile 27 0 R >> endobj 118 0 obj [514 0 0 0 0 0 0 0 0 0 0 0 307 0 511 511 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 743 704 0 755 0 653 0 0 0 0 0 627 897 743 0 0 0 0 562 716 0 0 0 743 0 0 0 514 0 0 0 0 511 460 460 511 460 307 460 511 307 0 0 256 818 562 511 511 460 422 409 332 537 460 0 0 486 ] endobj 117 0 obj << /Type /Encoding /Differences [ 0 /.notdef 34/quotedblright 35/.notdef 46/period 47/.notdef 48/zero/one 50/.notdef 65/A/B 67/.notdef 68/D 69/.notdef 70/F 71/.notdef 76/L/M/N 79/.notdef 83/S/T 85/.notdef 88/X 89/.notdef 92/quotedblleft 93/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 108/l/m/n/o/p/q/r/s/t/u/v 119/.notdef 121/y 122/.notdef] >> endobj 24 0 obj << /Length1 1784 /Length2 13246 /Length3 532 /Length 14249 /Filter /FlateDecode >> stream xeTݺMP]Cq).P] E[pwwwwwww(vuj>?'uOy?s>IȈeY [~acgd010Ò Xk[ j0rp0u@@o,X`NƆFJ:uRڶFf9t ]c}[':g @^F^_gk 746GIﰞ5[ۀҤ$,́N=}Xzi P6}Zsra; PZ)Ѭmf t,,lRzݤg6X`wFQ_OV` W\\J*/z>iUA_j*:Yg:0:Ǝ5PyAA?r ZXN"V #\O3 j0炂9bF&Af ?40-́;k0h+HO 4E,-8aVßvVP~[#kz* ;?elW a_f͍  g3e [i),(C4C !@C!P? @(+(C!P>?*V+!PvAgptLd/g ;ÿg: b 'ӿ$ aYAЩ7 AV!/YY +-lB_ AVr_r AVo t@o TzYN4@7bcЭT_Q_vqB$޿](gaCtMtB`o +jd4=="4 %z]Bɭ}dfxͩSZ@]Efո|'|z10/>\ovHs9@Vʆr ;7RF+Nn b/5}$z3ULY>f 6T* M=L&S2"u"deIXG'f`IkL:zN!W'4e@]O 4jxNޱ s[{Y8HP?]/s҇$!4 ֌c䣉 d:~%إH l- Ad=t<IkS^::ƘPlְA'ofBEP-1(ɵR(G%gF%.mZG>5[D6YڸlX8JTi]@ra=z: ;~'y7Lxd##[BK'w>ӉbY=؅olعdHD|&L<mTF;&6F;rM> >rMsrQ1TbXU:B(hJ{GAA*xgS)#JH[s3x4Di9DqRtj~XraG*j#3ӢGqѣ.GqR~Y6nn7b1mrLHMX]cy\W v?WsrJ57xl!/.)99OM*{ڵKS3Kdf#ił =?ƳV/zd6HDc:!.Rs8|Lpfm ݹT̢,tnhq~2~,jUEFV\VDkl_imrx m]v /Ý'k‘~=Y'5ny4f" v&G utC6(?3tn.Bũt/čX0uL/zԭ,8K~LtSqm==N:5YFҹ9wZR&~nTA:>}UAG~eu@ز+ƳAW{0LǾK#5 Z1E|5^ om6Hk2v;bEc7vBXgG K[-jtEX)CEQ=/%@\>f]uLˋF[#:qF_4CuMF!cnz Hk'zB.`t7En wSu~ Iuz 9#cMJKi~1Ï^x̋$L+1XK6u$"w71-fA9J =brCʯ?b !PsX+/oeK}^W`=r_ Em5>Hf׶צYQ?+$by]ߵzc(Lz;ijU -&0E&?6-VYnS gg "4<&b0ēԅy!6ph5i-/Loc]ƹ. |cJJ]()/Gzּ:U|S?ǫBe % TXW\0g^WaL]kp=l07 \SExm0n*/>P(1{FŨOzCDעGR`z ȂCP.Or~טJ,3FH<RނR(>t/$twm<ғO@X lg_0F$"j{pR !..9J5G}v͸m7J )4pj6PU`1,hHgeD; c3[vOn]k3bM/IKpЧAx,[+n"F )]2/x:w}U6; ttU* KxaSO(p&1ؚ 4~o`rvj2]UEI^4`IڅmSVÄ2dž$Ikp`a`r9>+b`7,n~ØLֳʬ؜C5ޝl5PH A@6?:[뀖zM^ Ǐ_O0%)+ŵ//gtxe̦35`51\ pFng-z8X~ (/]_[ԯSV]h Ĩ=pXT.2!N]tBFmo=ֱ\,^ a< N)Ϗ~NI6D[ea՞DiPXWsְ?x욓,I?/\߉qbU|'("BRƕ6k0Z[!! jT<(˃{ wy%.3zb7鵞` mp Kv9;>t.ff${ .\nUuG!B$7o=1EXKf2\*6cޯ66csLDz`8FM÷]gf糧/W#k?j~3<Ư=]yyܸG\.x 8 nPUkMNMd#B0[X@wX-iGh! G^-+Ռx18d8`EPp!uk ~̡7`G-UvcZ Zo_ZaqFl<ߒ_4r~~VqpU3>0%J6YLl캗;("`Z#+o({!'?$5*)MLo{h7ǽ`DzXZGbt4Yༀa0# 5UI;|_T&Nxc㔩q#_c,`FN ehq"DӒp9%{īpT^ ZR{h"Hp-1և0%q~+Gr}4:NNɣFԔ4j=kD#>K/aQC&w٨{IKtrh7M>9ߋݸqHϾ嵥Y;PUok-S1JUǃrc5tG$gWx܄anQacysNc gnmW|(3 BIVuD8}*2ϠT`Іoosn,}:Jya%I?&bs{l*ӏ8 ʀcSs7*-b8Ld&и9vrJ$}0H]Ϩ$@3p>˴E/xe[Hk +ð4^ݦe 'gqs\]AU1e)z\ n0 x[t T5j~P bVfT84wߡD[Gu@E04/Z(+;-~g>YP=:J*/M#!R4@9ž~S])ZhG\!cL=}ho<PÁS"k$F*dQlEF/sR9 .^b9 qd]mxjo?RG$ѭ TNӷ VIӀ=RË8aHE z80jRZ^~K/KW`M6%].IGY/kT` `Hy'3>?VVԲP^`i%}YkQ ]:3沂#zg2CRa2vNe}6GMUR{_)Z xv4.Tէ[WW+Ԏ9ou]!xW+Wς7]ԠHg1 ^4ݸ~;4@w D_Ȗ E-V+8 Sg#EE|_-( $s?pʏA l#TR!; .̯Uzrd5rNa.vMV6M>H$P˞!0e ,j3#IVIs%(gG=!:o¯Dvv s7T[ۊnk\ $}x~5sYXlrlufoڪP-&_r#Ph(ĐSdtܒ[ Ó3Ej܉{)`apLJ9xs.G8k 6!$ky/f7ǙD63|)Pq/p!$7%'Eߠ_N_' ˻O s8\'poK[rT Ex=;:u0X-O9iBSڥ6~XՉ~5{R(}6cy-ʴ:p>p1]dZmF$R7 6g^28VQ@0H[C\Nm_ z,mBL0wXN`zIQ?O̞ܓV3N8{Es%/Qzb_RQ8YPWV)y/P himD~O8ӏRu^ :~ z{=KsOL!o}Ȫh>Xz2황L"I΍&sj e&qw@43iotY6[-ͥv p;P|bv鄙D5SO Sϑe mn+y\zuI^ϥ`/t`lF1&~m3hFu \d4s Q`/Nv℈|^}K2RGJs~ `*~@E@qW-j~ɻufnҚ3hz{WY#LV ҋ~:0XMzwbZ:Dr•7*/"SXl9 QtPD%rZf@Eadϛ Zg^nͩzOFyL7d"67dfl?H SxUgM{uDLGl%_YuhE}kF=tf(=GJvZm0ɛ Ϊ&W+E'3Sl> g- k'(,L#F%Yod(RU;pXn*q|tUjU)2[ÔMt}$=OX4ޚVQݗ4LT7-pF㪢ˋ*_USUiݠ\!k|>PߗU!nrd6x^hbZ 51N~72aEF &~m5@/('Q# 'g 8] e. _,QWPjKTbyS3X VW-vxxq.Kp|r}ZPa|ܡmĖ3!|UhPs#Tw'9yX+MjV9xڶMFfG]7$oBmtTAB0x^:3W<䌆%)zI<-`kTȝnI1n7vSY~60ŕ)v `j@_V vx;sjtR\D] a-itF͚v: "(X5Y Vs?Pns[.]=KLB'Um!-gMkSϋ@-WOՕ%8)n֞fi劐AO}DԒE$zV7YGy0Ű/6C`z? :;q߆ҳ*<]BrB@~g!;NZ^+K,wc]@cԀ%Ӧ[Ǚ!2|4TcdS,7bp?qЧ+>( He+&c]v>d ƣȄPj:I_ROb}l?Co(-Ha iUVg9WUewcŤkn^eL=֍[wA4Y 8\ғTp k6RI=bC4 D?AD,%ݲsȞWzaͭZ箻Ts0G̏]Go*I0-@&21\[(g1;VI),z!Bv .E#sM?>"lĄhg:{7q Blv8R󼸻QǶRk 6Npo.'Hɝ+A EFŭm_뛶7\8鷥՛3˙ԡ]=PhHG]?/,;HOs,jAѩZt}c-Gw%Rp#l HDYHKvնc툍S\S#u&\l}[ 1QS=:3̵M(NsG͑XICͲB=BöoǻA׃`Jۃb&r')tbrGh \ݻK-zl utt,3U]GfbeƒˀŊ{..jbKfLŎ|H 򱧯=! 3,c1ܑr[RSc3uar\@DQKתoh)Q1_٧:Ce9r j?I$}?OpxÑuq:xf@Q5QLqYj'0`'ip'5kG7:c\"R]?+[!ФIfSC]9Uַ4<0kmh-/%7f گ$=5.[wXla+%X/k `{qus=`@baSY S:L6F7KBW_e[!Un8)neUx!>TZD{Q\Hē,Rvz^AIvY)E+O/͉еFhFPl _<6Ӯ:jtޫLyMb绿[70 7ܼܗjL`mn3(#_G~Z ty ߄EOCoA0`X4H}XjDJD˒5G4@N\zwیpqX➻t %pj=(䣻u:Kl i7"SV-^b5aH tO/Uf'Cp#;-5m@6XTj䥒h.YhjޫLGq|~渑NW訮'zxeˆ?)ryEh˪~EC:E8'IplY""o>uԷl6550x12CHTe;-y÷5L$t-׍756#T;b싲p^b* FFaqjJ IXNu6 IK6%|b?ɋύRF=?!=ح^lf;DAwh&($z654La>I@YCoNWJ"(ڃxcg/@ŢuqRw1ɻ_$CO/-Cz%qd#ۚvn9sCЌF6qL(ٰ4!˼6V4\-oG $r-H#FXcYxtHTaf\.վR4J;z cUG8,i覶TQq|:[`Ew=ܬ3RərUӝD:tЍ˰wb.IdQa*n9P$%,DꠊC'cq\Eg]WSK2Wtp(B0cm8_լOfowIMfB6E٤}D t@G+kj+wYScHRDɔ|qz2IM;/Dn׏d-3ʻtG6“3;!V⥏LL%]^}b^$'561` wוJ|F"JjOoH,}5r_ɀ%o_.hXM /EX@+ OD [Q7[%Ϸ ?j3Z`F+]$- 9*^w4W9#Jr֛Z:T^Px]ʍ 7q%^ ,\|ܜFoNwUhe_zޯU=i"䥮3|L(Zz‚E> Yr8'';TPq\H&+ 7L*-::.pܱjDp&\ R=MpoSA/f=.OoPpܽH0| @mmkamm kYendstream endobj 25 0 obj << /Type /Font /Subtype /Type1 /Encoding 119 0 R /FirstChar 11 /LastChar 122 /Widths 120 0 R /BaseFont /SSANZD+CMR10 /FontDescriptor 23 0 R >> endobj 23 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /SSANZD+CMR10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-251 -250 1009 969] /Flags 4 /CharSet (/ff/fi/fl/ffi/parenleft/parenright/comma/hyphen/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/equal/A/B/C/D/E/F/H/I/L/M/N/O/P/Q/R/S/T/U/W/X/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 24 0 R >> endobj 120 0 obj [583 556 556 833 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 389 389 0 0 278 333 278 0 500 500 500 500 500 500 500 500 500 500 278 278 0 778 0 0 0 750 708 722 764 681 653 0 750 361 0 0 625 917 750 778 681 778 736 556 722 750 0 1028 750 0 0 0 0 0 0 0 0 500 556 444 556 444 306 500 556 278 306 528 278 833 556 500 556 528 392 394 389 556 528 722 528 528 444 ] endobj 119 0 obj << /Type /Encoding /Differences [ 0 /.notdef 11/ff/fi/fl/ffi 15/.notdef 40/parenleft/parenright 42/.notdef 44/comma/hyphen/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon 60/.notdef 61/equal 62/.notdef 65/A/B/C/D/E/F 71/.notdef 72/H/I 74/.notdef 76/L/M/N/O/P/Q/R/S/T/U 86/.notdef 87/W/X 89/.notdef 97/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 123/.notdef] >> endobj 21 0 obj << /Length1 1215 /Length2 6940 /Length3 532 /Length 7709 /Filter /FlateDecode >> stream xe\A%AjFkF.A@$gf^u{~׺=3LtZ/@0K<#Qx@i\&&89Z "aa^<y? 2d`Np-*W pX lVP Fxr^@Ϳph]p70 X!`#._aAN^r]d M`POl˭ C^oP_[8@sprE wT=Ià%B^8@ByAX-.`GZ@6o r**rs/[@ڞN+o!# $͵++)B/6؏%/"<L6n]%r)*tȊZF*~$]}%xUhNF'[sZf 2%yن?;(&&^=+C'WՠY@2G)ئvfrC(SVgYC¸>/S\Ə#e'L@U:hzG zeo/ [NYxv.=W8x6 JoO^2Wu0镽ı0w'hR&g96D F#yqp C6BWٹ=]% "TS\Q{_`MZ;9UpT}`y(<GZe? K]G3Hf<.,$9ɱ>p 4v:(tr/tDZ@#db zv]SlԌ͢gBLwhF;DƐnI/(|V{?OVB4')j" 8,$  F2/spն8q EV} 3lO6TO3vޯv54+dbP'I8#(sRr.Akc[4ߒcKa 1hq+%\D;JLƿ}!=F-\c%^&5mA c䧺or!@vssgVv7rN) oPGVU(,)D?O>{1E֊qILKϦEw.]N۶<z,dž+C(AmI]j@\4! fkK + (Ym̂cp0婽3|=;l( K6~WpP_J%P5}#ΣTh:_!^JHWIq1?oI/<ʸcOPS/YDH^%:7lf@Q7٥`p15np'+e|kC+|6\*Ȼ* o{lo9\٢t{&4m@0Q7.wAVV؛=G|`^iB-ojy ]Uwf\$f|2IS)8VX\f;"uFV%?,î]22CV1,ڷi 뤢SaRV<x$PnBUy1D{ s zKG4˾aAdL@+D^\:*o&ZܕGq}2Q틭7iyI4lO]~T}D#ذ9:UBj!%FL^1D*6B?oIS;m(kzg}  1-.gsq( [d<vσE86$3&ϪpMuzCF.$;{j`|}d+@ 94[y=!;NW`xdV|сcx]čl46lQGYR)[>`{X^| >q*z5`tdzBQ8=azT)."J TJ^*;nbXʠAНıkک*ꃘv"ullFGg^S-h$%M?kdknӆls0T!WyL4%jBkvŷncf6O -g`(Vls 6 e4]=,UtϚxy43yۗR@|)th}l 4Qja:cl|ℏfW515>'>gnaY ԇCA-0Y):c^tg±":2ZD_ 鬒~.GiB5>qqQ)ƣ~_xAh>D݁:sԡ9NLo04O 5L_eR/֝u m%Ҟg&r2BKS*N1UO]گW3U_HIrVnݴYS6%jj_f8p[ZY L$`8+OwY B=V6Wyrs\)u|OHfۗj v*e'];Zi,cmVٰh&]~ڀ0La羠}Skfw}x4SHEIwZIJfG."7=<* t#w q&{c/-R.{twn<|E/G)7GV+i:R%>q߆MEc/ңg_xPo+,Ƥe0mB=]{a^֑~'--(ȥYZF[.nj ~Jk^aSȞ*+JTXoTm)ٛƷ~[z9_wϹ0hHj=>W@dq@dӞ3|F^3;b2YkuEB/7 aE!JscD3M:rK#]|s|ٔ'~ǯc\TuIl"Ru#M?G X[}CW!^3h8vn3|L i~xFΗMo67j,lfs}17OmvZE3A?+QK3 ݭL|Y7< Tm$A EJf| SudP 3i CsX {GQV9R65mQǫ4ւtO8xP.%_`p' XApn ^endstream endobj 22 0 obj << /Type /Font /Subtype /Type1 /Encoding 121 0 R /FirstChar 48 /LastChar 121 /Widths 122 0 R /BaseFont /GEMMKE+CMBX10 /FontDescriptor 20 0 R >> endobj 20 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName /GEMMKE+CMBX10 /ItalicAngle 0 /StemV 114 /XHeight 444 /FontBBox [-301 -250 1164 946] /Flags 4 /CharSet (/zero/one/two/three/four/five/six/colon/D/F/I/R/W/a/b/c/d/e/f/g/i/k/l/m/n/o/p/r/s/t/u/y) /FontFile 21 0 R >> endobj 122 0 obj [575 575 575 575 575 575 575 0 0 0 319 0 0 0 0 0 0 0 0 0 882 0 724 0 0 436 0 0 0 0 0 0 0 0 862 0 0 0 0 1189 0 0 0 0 0 0 0 0 0 559 639 511 639 527 351 575 0 319 0 607 319 958 639 575 639 0 474 454 447 639 0 0 0 607 ] endobj 121 0 obj << /Type /Encoding /Differences [ 0 /.notdef 48/zero/one/two/three/four/five/six 55/.notdef 58/colon 59/.notdef 68/D 69/.notdef 70/F 71/.notdef 73/I 74/.notdef 82/R 83/.notdef 87/W 88/.notdef 97/a/b/c/d/e/f/g 104/.notdef 105/i 106/.notdef 107/k/l/m/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 121/y 122/.notdef] >> endobj 11 0 obj << /Length1 1503 /Length2 6335 /Length3 532 /Length 7211 /Filter /FlateDecode >> stream xe\mahA@@RbnaH F$$%FZI i3ڟ=7]k]kֺQ[[a UDQ`P^CO y@y$ CXb@((fC,@yfgs$ u"a+8P euFX9ur u"ݡ6<0hP;"-(/˿]P+Z-h;ym^MLiWV0'@8Hg_4607`Y hP{+o;n"Ѓ[ѿV08J埴E[F x@ 0:SC608H H+/lI m@'Z1/B/ E m(Xk@9A]]ayeZAг" n-.DܚDP$ր΃fyQ~A0?"7䭁mV⊞?,f;~kA+caB/%[B'nHFxKfn [ТUo ]O4n ]O!t=[BJn ]O:?*n}KH~ ZV`%q@:N?uљ_g":7 ,'|-r󡏭(z‚W Q?Wl CP'B@ăRCKGKq814k;[ 1 ?=\1>/KKqI3<.mzr-t U-mA /KL zzrٟěgi^י,$ldRϨK$\ l,){a$! >ō<?'9ux3<Ntnbn`,C~0-yܵ挳JW-@x* \)RPs-G_oи 1bkΌ&I_&x`G}Yj {69;i]~e>1&q>94?_u$AV.2jcxL-u-cpī,ljËN}v}]b-7l{Gym'RM{TYnX$ mPdSQ%.;Vf~LBZ,c,cj]- v)r͙I|?5:}K+\bӫτU eDGϝ{e!&>KȌFCQKQ 4wan0&G;"1\zsiQ Efͺ8tu)`g6i'ҩ*! eE&~qQEHXYT8S8SL^cەN,58TH|-%h*#cB_ZRyN)%3 uNz-@[푕jr ƳV|# k,깴lv ("")k KR [.k|ԣzϦFlL@FoE6N%mIS[=aIc.m'nlQ](B)l79)} _ڝ8Y|<_Ǒiow\2$H/M7wķb+tOdsfa$p<`MigPu*}hRf4|xAQ ".fO_411~y[MKŨ6(VbDuyeG31LC$-6Y$z|ZjW}F:ٴ7/Q_ 8$_y= h)$A* {%g*h! gh-Nr83ˆ%Iһw(|>q9=K"S )sɇxLG+Xby {z=HQSf$=^56_R><](>cތ73t63"?K/}5d; 8IK<]Ygbz'茪KvvMWă_* $4/,\մ9#MV)]KFQ;6t~X 8:Sza`Rp Kl8ny}u Re35 K[|X^XcyT7!Xi>Lq4(RK"+.{pU=`"wL}izB>CRKdyQU+ >]VR>H lNɢ>SƋGϺ䯑 킹RE-ZgQV)f?}fŵj ߼=>u=7rzY ؊xaRC".D'սb%w2 i5UĪxR;ݧucј* &i.V _k_]z?L/ދdZs'ZOVx@GyM[\jE⍓NdBOђe$PIbN>RB7Jhd9_crC%ӏ㮮7˹rp%y=2cEx%gV8ϡkۣuՓcHJY."h۹^伴'lbkRP3HH5wEMdcw5j1N\07qHM񌑛$ݪvݒ/)(?ָDAU,-{|vWDKƋ;ʌ.:|cy0~;$#12Q$epjp`GrLM}g?wYw*16ړ2 C; o \Tuͽrg'UF>46T|B&1t7۞Iu `(dB(y9_>~)[~X]H, dT[Z8+}ݲ1wΫߝ lTnz9v/ƸR~O; lfGeE}6viU ϐ?&cB4Ȇ5]?(qP(A&'t |VP_̞kR#T\^(z+_PBnGaAۥR3Nk\d>"cWYlExuKTU*Dt$IrۺusRrQ*.#3r:P@y:Bx|rZ<ᚈ[e<5O},u̩z/'AFe/{34{ZXU|iޡ['mJ Ϝ'DR)xHoϋ6ju4/~cv'.M C7u+mc3br|~znh!,X-vv 55gz /N0Ax^ {5g"Z&Hӥt_2xeyTbikD>'Vi)t9QieG~2@cbs~ߝQQl WwExNR( s O`L፝fjUHZP&lvD3TK(+^C`J-_˪4Wi㎓2Ee+űDq/IsWNws(ZC׻/B9#ntӔ:dkXq/ڌZ''2%z }snPҺGe+|"ڀ^bDD|#iP{Ҥ]p|^R TW@'eZ7!!(؉':~tX׋*X_DGΔzT*+g!6-:_*a.T#4# k5!gL:S'\S~QjEP؄s*7<0PN1pȝXKCV4W7E#߇E<7у%v'FK'¦L1 9{&Se\a_qp<#~Iͺb799AH H õs]d^3]n8kj,ɔ">fؐjR,Dy(4Y%TR41pO %!`Ka` W 0ɺs.L?'!k,xMMϝ%hSP_VmڗHL٣X5̾hc{*lɍ4^JlBoQ^( 3R{]\)㫼;g9IRtC*H|ʉ R;+ y?, [g^j* UV!^3T7T2>øp2i"6V7?ݙ8L{?67 ŸuG RhhZ,7Aɤ`i3rOy؞?nx7U|yN(@HO>a[KkOJ I_OG_#P̸jqKƀ?$YQZ4ߚHt4~qgQԤ͟pVxZj ӬI>_=K 9TqhVo:}Y[Ynǘ1%s1u\ 7/Ņ.k|u X*ٞ Tzݽ@FyŁ _1UV_laK L ?\-7.Ӷi91V@[-35m (Kh>[n<~Z* 'Q^AU@N^M~漟7VGcʼ~ pQ.x\FTXjcPԣj4S1+?V%KUSGFMv4ut)ϳE(ud*%K'Gp Rي~Ũ'߭{ħ@D]Χu >rrj7#u\m'!16 uNՇkӳyy0}~z3?=D(ƥ '.KNKft7|B)&Ňȋ u> endobj 10 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /CGQTXA+CMSS10 /ItalicAngle 0 /StemV 78 /XHeight 444 /FontBBox [-61 -250 999 759] /Flags 4 /CharSet (/dotlessi/acute/comma/period/zero/one/two/three/four/five/six/seven/eight/nine/A/B/C/D/E/F/G/I/J/L/M/N/O/P/R/S/T/U/Y/a/b/c/d/e/g/h/i/l/n/o/p/r/s/t/u/y/z) /FontFile 11 0 R >> endobj 124 0 obj [239 0 0 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 278 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 667 667 639 722 597 569 667 0 278 472 0 542 875 708 736 639 0 646 556 681 688 0 0 0 667 0 0 0 0 0 0 0 481 517 444 517 444 0 500 517 239 0 0 239 0 517 500 517 0 342 383 361 517 0 0 0 461 435 ] endobj 123 0 obj << /Type /Encoding /Differences [ 0 /.notdef 16/dotlessi 17/.notdef 19/acute 20/.notdef 44/comma 45/.notdef 46/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine 58/.notdef 65/A/B/C/D/E/F/G 72/.notdef 73/I/J 75/.notdef 76/L/M/N/O/P 81/.notdef 82/R/S/T/U 86/.notdef 89/Y 90/.notdef 97/a/b/c/d/e 102/.notdef 103/g/h/i 106/.notdef 108/l 109/.notdef 110/n/o/p 113/.notdef 114/r/s/t/u 118/.notdef 121/y/z 123/.notdef] >> endobj 8 0 obj << /Length1 870 /Length2 1972 /Length3 532 /Length 2574 /Filter /FlateDecode >> stream xy<s" Ǟ%-?[ef0(NИƌ̘ƚe"DeWZ%;-pn{{?<&GQ2M7,NNp}XPA H![bh74H:Іp}##!DD Pس A*!h  bHKi,-I"# R N 8""]Wtq?] qEq2@<jKJ~,HSH$i @Sp cawqhG=HÐX$@&b0qDcH$~܆!Alti!iάʮGo0o·Jd0- ?~hvdI aA%d@&W1TLqSP"< Y_>E6@:E܍A1!Ep(r3ߡ%p%r7sܿ D`c# "-KRA2mFD@ b!1?V\qKJ'TVw9Cn}lMիIq]!kIuOPg:8: wAƂcfDkoXEu=*>^r}L¦OFeC.[O !ܭ(}8A7~0DiHx:%_3{ tISk$l65^ Ht3kPs?b_8y+R{@=ZZ :9l\5$qME#y.Ҫ/ֺjJxcF@5St3"ᶮ|7> =R&q;_ tf :{Om.4|l4Cfn:C۞# #g9ir늋&h}%f9zHw4*NJk]*OEɾW ?߶ֽbvL~3|If$MHʽ*boQwX D/o)GOfVD\Xcm3!ݎ;ٕTcL{5 1zΊA;ǰC?,[v鏽YjGGOo"~7;bk0djLjiwRZ$2kv9-:߼n^rdGB[H X @&&luɑgz^nw=sIy:\7d̦IO5u=t|?x;DTo(+h"N Va,}>f gbs9̎CƯOwa-(W2s9);l[g |ѹWqFFE-^D-njW962:]ymUC!*wmު}ˆ 7-Э< }0Fl=Z(8ZZg[&$Ԛ sͣm|raq7lãkWsC.7-f,,npoTs`A&NTU6#!G'w펨wO+XS*zEBkQ[1vpcC[{ͽN@Cs>C5ّAf=yJ\k1`bsayRbN:۾$qLLdG5stVه}[.uwA롫J۹CY}@~{os8=O1d^;Dl,jz䖺S)i@Bbj&ܤRl!_tVpQ *擺8C>D ՙéoڈ>V-/,bZ Uz;[NyV$a({{m[#_67uv$1%#s,OI 1C76nZxt̴FHگ}f tM O6L4 ,e\g^O!kP2`@z|%"67gl/ʳobW|BSM彍I3P[ﲍ;SDAPFКhPq=0qJeRB[&UJ($X;F-PG^4^Mv t<7[LMQP1z+$Fl?jx[®&q[}pcCƪ>yV$CQ1ȿQsendstream endobj 9 0 obj << /Type /Font /Subtype /Type1 /Encoding 125 0 R /FirstChar 77 /LastChar 117 /Widths 126 0 R /BaseFont /HJAIHW+CMSS17 /FontDescriptor 7 0 R >> endobj 7 0 obj << /Ascent 694 /CapHeight 694 /Descent -195 /FontName /HJAIHW+CMSS17 /ItalicAngle 0 /StemV 76 /XHeight 430 /FontBBox [-58 -250 939 758] /Flags 4 /CharSet (/M/R/a/c/e/f/l/n/r/u) /FontFile 8 0 R >> endobj 126 0 obj [820 0 0 0 0 606 0 0 0 0 0 0 0 0 0 0 0 0 0 0 451 0 418 0 418 287 0 0 0 0 0 223 0 484 0 0 0 320 0 0 484 ] endobj 125 0 obj << /Type /Encoding /Differences [ 0 /.notdef 77/M 78/.notdef 82/R 83/.notdef 97/a 98/.notdef 99/c 100/.notdef 101/e/f 103/.notdef 108/l 109/.notdef 110/n 111/.notdef 114/r 115/.notdef 117/u 118/.notdef] >> endobj 5 0 obj << /Length1 1457 /Length2 7681 /Length3 532 /Length 8529 /Filter /FlateDecode >> stream xe\] VZCCc``;;FC)%9sJI9zx ܈ӊXb+|DKW !n@ K9GKiae~h.2JB:B3D8Du DDm+S+9V|>ڜ DxĬƦ(C=ّ4NMO/uU (mۦy%~Hޱqqœ_=Sv+xBorUQg3Dﰀ+6eMpe_UCr?d6p.gSB&}f匮U_1EąA*V 4+e!MFjQ(Ix#n>E$,✀\-g ̣m&ri_9jr MD%FSv&TTUr7=X-%}u~]ְ3[5ݘg$T4Ni\>d-:iDs \1TV[UPxSI+Qʛ-=㭗;bS Wj(.2/s:{L17!NtdzJOOڬ#fX' zģ~kx>xWl%Ev=Ei){6.>MJh `#H\?WDE!I.':رmw#U̐XKާ7*Gא/}0[PR~\>ޗf@ĥrdC*^8^Q`!oP63 |yi&m΍?›406KwP~N(%=G{5A#ЗkG͓žC 5;w +_T]}uL䘱L^+q-ΛB>JOh@J33nČVq8yQHՎ-:mؘ^NsHo N)/@ ̮XVgܱ EO#lHqR8hCH2 ۾{?vߐ=~x@UN6(^ Bj\&4m8.VNꭒb| zi_ot=H"^h,M]K}L@qS<  `#m|ƈ}7lp>GZHoɂj]nJApΥTb93x&]M@vsJ1ꦑ^ω]]u}bdn| loҍkdn5OdHvXIEk@jw/)Ǒbat/ߌqn O"_LvԦ rOSuSxc $(/Fp}_'^[C-´E;#4KæSQ^hxՎ%DaG{!Ze؟0I>]4/Cb5"֡vyd^Ӓ>i`{iG^= ZA⠔Jx^୽i=WޥrU#0\kyv꾹XVcCl*7OW- hXo[_z;47֎X,ZxnXNz-Xe7d4/y,ah3QVCw醇qKY<) |&+yg-Ϗ~Tc3?ןLNQ0Z:7Om>I}v"5 Y5._~􅒓 is|"͵P^0v=>ԳĄždo3B~$Ou)b)pL_ۯpK>Hy׷T q1X[?5E#?ս8>M?5RmF>}pIuNȈ(dues WP뾝'JK}}J tDžcT^V΀OsA'Qx'fit2mL 6#$^HCaOq@yDk7XqGyz]ҷq%|,aP.1 T6ÿ )nO=S;&bv,Щy%qW sDetj=u.}lqq8>'NRmt~Wt`SH+s} *hx\Ռ2D:ߦU%S~DrĠj*=C\E!;Q455k';e4[tk~AN =--lV9ʣ,3$,+z= J1vn(0ӌ̀=S_=FȺ7RT4 wQLڧ7 ioB]*%/ߋ=4R d54˔+gFRl[bcakT3Q̺Q$HK}'at7?\i뽒:bǞv{'hg1uֿ 8*+u'}̋}+I%W;N ~3࿥|k^S[{Mnư$}HMX׍2}VM0.TPt)'2ySqI? )ޣeJLmR_>Ж`yra=$h :Ksַi %2 @R"Fj%~r xBcXBo[_΄R [YtjNW8h<,R a_>&nʡBlv :=U'V0m06?ҟP#՟|.l)dsK G)WW,}'V3^E] +t %k+X #uhro7wgD<=w%1(k]%"6M wZq3O]mxbxnNp0OriӲ>Y]o bzm?sj lUPV>l1G d6<\"XY+ww;[w^^.5ABlvBȆ77%=E%]2z0ՈkX]sg2AQR@ !y:ZmYຘ+!`+h3?r ߋir:l*;Wm 7L!w*:霄Sߘ|!Z4ۅV CMRqp鶾nikeUirl 7tJ`F/ ˬh"ݸ4}G*)(^%A2h)%85k:=gNz!q\ٗ!U|m;NtȔ t$@J;dcߦcN}v+A:U#XJSDra4(2HY$uY*Ϩ(+]p i0x ZQEz)E> lM 3ZNH|'/Ya:"H8ߢ/]m%r~`=p^G|ųwuut dTf9q6eXK#E8Q&;lJk@N }"YelRxΦt ] v@щYnc^#ul_ZzYd81,ߞ02`{ְ@xլi c;.*,m={ɵB$*7t1)@K2$ZnllK/ 62Ṿ~lA-I?-qͫ+آm@eFx=wƮEIW ABqʢymE}o7JRb/H9\({TY)& =0y?:\u~%R]k{lʤREe>DSQ]OHI(\`l+citX19N? Ŝ|]UQ\gYL餮UKD2¿Pμ ro?V{S.ˀbd^ELzW]1tL41eWb$ӠtH(n{ @9Ҍ:5 KfÐ[0 <_{I+(J̏Gs#G{t0+7-7:eqo{Ϭ8!ېr>wln:U'sO_N#+%~ +>X:jiO956RQoR;[[j J_谭8sc3 OR3`crM-طFy|w?6Pf)y8[ E-th6K 2Vjʔ+v\EQŠJyz ]?4@cY )-[bAb7oz;ثv!ϒ"o4W̅U&,1ݍa{? {QC҂ jxm_H\g>R>z#\9@mAA؝GL35qu!] ǃ%ߖG9_ On1q\ x/(9 Mh<|}7|uQfh=JP+ ouMQRQj>tS/U)K׼gZĦuϹBYbdA;19҃RZKrw  51xɒv ik]t0i}`Η% ?P,_ϫ"=ɵm"T K#21zs={@5ԖCxB)LXY_ FN:BHxZK aF\8ˋDV|zI~WjrՋ~-*bz摑ɵfXוAT=H'I:rv'4/ݫ}O/7:XVRN9(ncQ5 0[oR۷JK /W0-+*ѳ!Ҙ\lY*HY9kRP^ ڰLH~ءQ[[e:1![ T8nNkFzyUHg.:E{B˰G5P5SQѷo.l[ڤ- AucJ;V%gl*]G2˄kqᕶ VH72&'xА S^7R#"Ŭtg>3fKm%ęO(]" NeyBW2V&aԤr*_CiƜ̖ӽЭ^ WOn'躗$q߹eAzi?[([59*"\1Q#vWd pO'dӭ\P%lKqx(pPYVPR,NɃ0)Ȟ8{F#.9ߟk[^:zjh"3"049 dRz|FWg| ҈D@FׇOmqɊUרx O*HC+t Ρ؛);S5v$trBl fNTWX!.qǭ Zr_Ba]mXhj8Γl<}_UpǾvN|8X}|m)gﲀBNNJ3jV"cUB2g Ǘ.Ӎz<`W$ՠk㴽_$s!cʼ}7||| qC#,o}GgXzLqplK'u,vzHufrfwVNfqN4~װrp2l9%r8V]M`5J[i]V OkU앾OP2ȁ-` &@x,Jԏ&j"S4W>,mȱŒnΈ{-+3ԘՍζ=ۃ~W|Է,4n8ڡV7ށt}'DX@KdH>:|:>r6J!)Zv Fpޱq?\\TD}#/̱ ,NHNY^*j <:|ΧG B,! _%endstream endobj 6 0 obj << /Type /Font /Subtype /Type1 /Encoding 127 0 R /FirstChar 12 /LastChar 122 /Widths 128 0 R /BaseFont /YFKKLU+CMSSBX10 /FontDescriptor 4 0 R >> endobj 4 0 obj << /Ascent 694 /CapHeight 694 /Descent -194 /FontName /YFKKLU+CMSSBX10 /ItalicAngle 0 /StemV 136 /XHeight 458 /FontBBox [-71 -250 1099 780] /Flags 4 /CharSet (/fi/period/zero/one/two/three/four/five/six/seven/eight/nine/A/C/D/F/I/L/M/N/O/P/R/S/T/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/r/s/t/u/v/x/y/z) /FontFile 5 0 R >> endobj 128 0 obj [586 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 306 0 550 550 550 550 550 550 550 550 550 550 0 0 0 0 0 0 0 733 0 703 794 0 611 0 0 331 0 0 581 978 794 794 703 0 703 611 733 0 0 0 0 0 0 0 0 0 0 0 0 525 561 489 561 511 336 550 561 256 0 531 256 867 561 550 561 0 372 422 404 561 500 0 500 500 476 ] endobj 127 0 obj << /Type /Encoding /Differences [ 0 /.notdef 12/fi 13/.notdef 46/period 47/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine 58/.notdef 65/A 66/.notdef 67/C/D 69/.notdef 70/F 71/.notdef 73/I 74/.notdef 76/L/M/N/O/P 81/.notdef 82/R/S/T 85/.notdef 97/a/b/c/d/e/f/g/h/i 106/.notdef 107/k/l/m/n/o/p 113/.notdef 114/r/s/t/u/v 119/.notdef 120/x/y/z 123/.notdef] >> endobj 13 0 obj << /Type /Pages /Count 6 /Parent 129 0 R /Kids [2 0 R 15 0 R 18 0 R 33 0 R 45 0 R 54 0 R] >> endobj 65 0 obj << /Type /Pages /Count 6 /Parent 129 0 R /Kids [60 0 R 67 0 R 70 0 R 73 0 R 76 0 R 82 0 R] >> endobj 87 0 obj << /Type /Pages /Count 3 /Parent 129 0 R /Kids [85 0 R 89 0 R 95 0 R] >> endobj 129 0 obj << /Type /Pages /Count 15 /Kids [13 0 R 65 0 R 87 0 R] >> endobj 130 0 obj << /Type /Catalog /Pages 129 0 R >> endobj 131 0 obj << /Producer (pdfeTeX-1.21a) /Creator (TeX) /CreationDate (D:20070725125302+02'00') /PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4) >> endobj xref 0 132 0000000000 65535 f 0000000558 00000 n 0000000443 00000 n 0000000009 00000 n 0000148351 00000 n 0000139543 00000 n 0000148191 00000 n 0000138987 00000 n 0000136137 00000 n 0000138829 00000 n 0000135003 00000 n 0000127512 00000 n 0000134843 00000 n 0000149403 00000 n 0000000854 00000 n 0000000736 00000 n 0000000649 00000 n 0000001968 00000 n 0000001850 00000 n 0000000894 00000 n 0000126666 00000 n 0000118677 00000 n 0000126506 00000 n 0000117459 00000 n 0000102930 00000 n 0000117300 00000 n 0000101999 00000 n 0000092577 00000 n 0000101839 00000 n 0000091890 00000 n 0000085183 00000 n 0000091728 00000 n 0000005909 00000 n 0000005791 00000 n 0000002097 00000 n 0000084751 00000 n 0000081235 00000 n 0000084594 00000 n 0000079954 00000 n 0000066637 00000 n 0000079794 00000 n 0000066319 00000 n 0000064932 00000 n 0000066160 00000 n 0000010012 00000 n 0000009894 00000 n 0000006050 00000 n 0000064586 00000 n 0000062222 00000 n 0000064429 00000 n 0000061481 00000 n 0000054566 00000 n 0000061323 00000 n 0000013546 00000 n 0000013428 00000 n 0000010177 00000 n 0000053942 00000 n 0000050817 00000 n 0000053783 00000 n 0000016727 00000 n 0000016609 00000 n 0000013711 00000 n 0000050311 00000 n 0000046889 00000 n 0000050152 00000 n 0000149512 00000 n 0000019635 00000 n 0000019517 00000 n 0000016916 00000 n 0000023115 00000 n 0000022997 00000 n 0000019812 00000 n 0000026455 00000 n 0000026337 00000 n 0000023244 00000 n 0000029794 00000 n 0000029676 00000 n 0000026596 00000 n 0000046236 00000 n 0000042164 00000 n 0000046076 00000 n 0000032952 00000 n 0000032834 00000 n 0000029935 00000 n 0000035512 00000 n 0000035394 00000 n 0000033093 00000 n 0000149622 00000 n 0000038257 00000 n 0000038139 00000 n 0000035641 00000 n 0000041717 00000 n 0000038985 00000 n 0000041559 00000 n 0000038903 00000 n 0000038785 00000 n 0000038386 00000 n 0000042011 00000 n 0000041932 00000 n 0000046669 00000 n 0000046467 00000 n 0000050659 00000 n 0000050525 00000 n 0000054352 00000 n 0000054158 00000 n 0000061974 00000 n 0000061740 00000 n 0000064833 00000 n 0000064797 00000 n 0000066550 00000 n 0000066526 00000 n 0000080763 00000 n 0000080423 00000 n 0000085053 00000 n 0000084993 00000 n 0000092314 00000 n 0000092140 00000 n 0000102572 00000 n 0000102304 00000 n 0000118252 00000 n 0000117871 00000 n 0000127182 00000 n 0000126949 00000 n 0000135684 00000 n 0000135348 00000 n 0000139320 00000 n 0000139198 00000 n 0000149016 00000 n 0000148678 00000 n 0000149711 00000 n 0000149786 00000 n 0000149839 00000 n trailer << /Size 132 /Root 130 0 R /Info 131 0 R /ID [<415498295F883007358DF15772EB8174> <415498295F883007358DF15772EB8174>] >> startxref 150043 %%EOF nyquist-3.05/doc/poisson-fig.gif0000644000175000000620000000766611466723256015707 0ustar stevestaffGIF89a*]w1!Software: Microsoft Office!,SMMMhhh|||` dihlp,tm|pH,Ȥrl:AtJZجv+zxzm5.N2H~ҨlJQ(b2>1mG.y"@1L{=HP-( l pv̢EylP^DmCzcmۼn+u &̏5%/"."Lqo_ӝg.Qxd\c5| =;ggxƃS^{NV*!Vzf )vJi9j.iuj jJkjzkjDӯ© @j/2{B j2 t+k覫 D2h;,l'0/C= Wlg;LJ$l(̯۾ 0,4?jԬ朇bnդ7rMNM.*΄^.<̺pՃ|ŴkhG0b 1y!S?-\-|oO3ȣ~'k߱,+ ` /k[ ;em@'HA\s X^ C8A ~`XBd"\ [hNc! khC3l {)N4"!QK_*1jbA,bLzx10ҏmɸ/3n\#8хsdgq 1{K%9avS$ll=ֱ4Wq"wJψQ(.zakVHI5(X8-vy<24X*wپZ1DJZLf.-ӏє&Ύ1f3`oO&!yiMdgcq֌Д Js| Zl:QXRtm&XӬe{۫b[(kۚz(l v+lW]6nP+5WjN[jfyrӚ+ Y>F]- +"ۯx+7[` /PM'|BU3TA_cqIPep-\0qyL0@1'u/#7'F&Q&9_W+VCy_nJ%E3L.X;Fs;Ӕ9rsLVs@63˲]?C/ z-%=τr9ZaX0j}:a1#MJW'KuW-MVׁuF]cXٴuv]m]ֆ}d g8ɘ&խivktl|İRmѻu V|eoQw6~E+x"^- S|᜾YqqܩSx>ZW|ז' r\"of\.ɁqjXDC~sRu<]^s7ߖ:ի|;7twIgyڳ.vg&pә8k{6{^zv=xpW|˽},'?{7ws~7\~zt}慛ϗ򭏽EH%z'7?^~Qy۰~zwtg/?~q-x K~jurFvd S<V%u}hW}oa~~yW8'_nt!H})~aX^Fz+x X~~GL}8}G-/xtH@|I!J$#V(DՃB}|5X9WW؅L8f؄Y慂h_Xq(Khr7o,ah>8u臅8ȅjxx9e舏X(7H(E~ƉXT(xgv~()w?8AxvhHv(5kxN]o؋Ϩr؇(pl3Ljȍ3hhLȋ8X٨F#lX84I6 Y y(E@6vXf8xUxَɆ iSVH49h2y9ٍ4?VNJ<ɐd&>EJaKfO MMS<` :'czMVgNnpr:t*lJ6`ëˤº=Hm;*BtϷ>:%'߶ uՓ`ߚZ:J*r$`CʯZ䃯b +J6ʯ m6*;6قZ,̚l,&.f2[4[z8:ڳ>'1X2D;%F{LJ(@۴e´Pk R;PVk'u\۵^`#;nyquist-3.05/doc/foot.html0000644000175000000620000000475311466723256014612 0ustar stevestaffFootnotes

    Footnotes

    1. Most behaviors will stop at time 1, warped according to *warp* to some real time, but this is by convention and is not a direct specification.

    2. Since XLISP does not support multiple value returns, multiple value returns are simulated by having the function assign additional return values in a list to the global variable *rslt*. Since this is a global, it should be inspected or copied immediately after the function return to insure that return values are not overwritten by another function.

    3. This is probably a mistake since sample rate is implied by sound. This parameter may be removed in a future release.

    4. This is probably a mistake since sample rate is implied by sound. This parameter may be removed in a future release.

    5. This is probably a mistake since sample rate is implied by sound. This parameter may be removed in a future release.

    6. To be consistent, a blank line ought to specify zero attributes and generate a note that inherits all of its attributes from the previous one. Adagio is intentionally inconsistent in this respect.

    7. My TX816 Owner's Manual gives an incorrect format for the change parameter sysex command (according to the manual, there is no data in the message!) I am assuming that the data should be the last byte before the EOX and that there is no byte count. If you are reading this, assume that I have not tested this guess, nor have I tested this example.

    8. This is not part of standard XLISP nor is it built-in. Nyquist defines it though.

    9. This is not a standard XLISP 2.0 function.

    10. This is not a standard XLISP 2.0 function.

    11. This is not a standard XLISP 2.0 function.

    12. This is not a standard XLISP 2.0 function.

    13. This is not a standard XLISP 2.0 function.

    14. This is not a standard XLISP 2.0 function.

    15. This is not a standard XLISP 2.0 function.

    16. This is not a standard XLISP 2.0 function.

    17. This is not a standard XLISP 2.0 function.

    nyquist-3.05/doc/part4.html0000644000175000000620000005370111537432671014667 0ustar stevestaffBehavioral Abstraction Previous Section | Next Section | Table of Contents | Index | Title Page


    Behavioral Abstraction

    In Nyquist, all functions are subject to transformations. You can think of transformations as additional parameters to every function, and functions are free to use these additional parameters in any way. The set of transformation parameters is captured in what is referred to as the transformation environment. (Note that the term environment is heavily overloaded in computer science. This is yet another usage of the term.)

    Behavioral abstraction is the ability of functions to adapt their behavior to the transformation environment. This environment may contain certain abstract notions, such as loudness, stretching a sound in time, etc. These notions will mean different things to different functions. For example, an oscillator should produce more periods of oscillation in order to stretch its output. An envelope, on the other hand, might only change the duration of the sustain portion of the envelope in order to stretch. Stretching a sample could mean resampling it to change its duration by the appropriate amount.

    Thus, transformations in Nyquist are not simply operations on signals. For example, if I want to stretch a note, it does not make sense to compute the note first and then stretch the signal. Doing so would cause a drop in the pitch. Instead, a transformation modifies the transformation environment in which the note is computed. Think of transformations as making requests to functions. It is up to the function to carry out the request. Since the function is always in complete control, it is possible to perform transformations with "intelligence;" that is, the function can perform an appropriate transformation, such as maintaining the desired pitch and stretching only the "sustain" portion of an envelope to obtain a longer note.

    The Environment

    The transformation environment consists of a set of special variables. These variables should not be read directly and should never be set directly by the programmer. Instead, there are functions to read them, and they are automatically set and restored by transformation operators, which will be described below.

    The transformation environment consists of the following elements. Although each element has a "standard interpretation," the designer of an instrument or the composer of a complex behavior is free to interpret the environment in any way. For example, a change in *loud* may change timbre more than amplitude, and *transpose* may be ignored by percussion instruments:

    *warp*
    Time transformation, including time shift, time stretch, and continuous time warp. The value of *warp* is interpreted as a function from logical (local score) time to physical (global real) time. Do not access *warp* directly. Instead, use local-to-global(t) to convert from a logical (local) time to real (global) time. Most often, you will call local-to-global(0). Several transformation operators operate on *warp*, including at (@), stretch (~), and warp. See also get-duration() and get-warp().

    *loud*
    Loudness, expressed in decibels. The default (nominal) loudness is 0.0 dB (no change). Do not access *loud* directly. Instead, use get-loud() to get the current value of *loud* and either loud or loud-abs to modify it.

    *transpose*
    Pitch transposition, expressed in semitones. (Default: 0.0). Do not access *transpose* directly. Instead, use get-transpose() to get the current value of *transpose* and either transpose or transpose-abs to modify it.

    *sustain*
    The "sustain," "articulation," "duty factor," or amount by which to separate or overlap sequential notes. For example, staccato might be expressed with a *sustain* of 0.5, while very legato playing might be expressed with a *sustain* of 1.2. Specifically, *sustain* stretches the duration of notes (sustain) without affecting the inter-onset time (the rhythm). Do not access *sustain* directly. Instead, use get-sustain() to get the current value of *sustain* and either sustain or sustain-abs to modify it.

    *start*
    Start time of a clipping region. Note: unlike the previous elements of the environment, *start* has a precise interpretation: no sound should be generated before *start*. This is implemented in all the low-level sound functions, so it can generally be ignored. You can read *start* directly, but use extract or extract-abs to modify it. Note 2: Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, *start* is not fully implemented.

    *stop*
    Stop time of clipping region. By analogy to *start*, no sound should be generated after this time. *start* and *stop* allow a composer to preview a small section of a work without computing it from beginning to end. You can read *stop* directly, but use extract or extract-abs to modify it. Note: Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, *stop* is not fully implemented.

    *control-srate*
    Sample rate of control signals. This environment element provides the default sample rate for control signals. There is no formal distinction between a control signal and an audio signal. You can read *control-srate* directly, but use control-srate or control-srate-abs to modify it.

    *sound-srate*
    Sample rate of musical sounds. This environment element provides the default sample rate for musical sounds. You can read *sound-srate* directly, but use sound-srate or sound-srate-abs to modify it.

    Sequential Behavior

    Previous examples have shown the use of seq, the sequential behavior operator. We can now explain seq in terms of transformations. Consider the simple expression:
    play seq(my-note(c4, q), my-note(d4, i))
    
    The idea is to create the first note at time 0, and to start the next note when the first one finishes. This is all accomplished by manipulating the environment. In particular, *warp* is modified so that what is locally time 0 for the second note is transformed, or warped, to the logical stop time of the first note.

    One way to understand this in detail is to imagine how it might be executed: first, *warp* is set to an initial value that has no effect on time, and my-note(c4, q) is evaluated. A sound is returned and saved. The sound has an ending time, which in this case will be 1.0 because the duration q is 1.0. This ending time, 1.0, is used to construct a new *warp* that has the effect of shifting time by 1.0. The second note is evaluated, and will start at time 1. The sound that is returned is now added to the first sound to form a composite sound, whose duration will be 2.0. *warp* is restored to its initial value.

    Notice that the semantics of seq can be expressed in terms of transformations. To generalize, the operational rule for seq is: evaluate the first behavior according to the current *warp*. Evaluate each successive behavior with *warp* modified to shift the new note's starting time to the ending time of the previous behavior. Restore *warp* to its original value and return a sound which is the sum of the results.

    In the Nyquist implementation, audio samples are only computed when they are needed, and the second part of the seq is not evaluated until the ending time (called the logical stop time) of the first part. It is still the case that when the second part is evaluated, it will see *warp* bound to the ending time of the first part.

    A language detail: Even though Nyquist defers evaluation of the second part of the seq, the expression can reference variables according to ordinary Lisp/SAL scope rules. This is because the seq captures the expression in a closure, which retains all of the variable bindings.

    Simultaneous Behavior

    Another operator is sim, which invokes multiple behaviors at the same time. For example,
    play 0.5 * sim(my-note(c4, q), my-note(d4, i))
    
    will play both notes starting at the same time.

    The operational rule for sim is: evaluate each behavior at the current *warp* and return the sum of the results. (In SAL, the sim function applied to sounds is equivalent to adding them with the infix + operator. The following section illustrates two concepts: first, a sound is not a behavior, and second, the sim operator and and the at transformation can be used to place sounds in time.

    Sounds vs. Behaviors

    The following example loads a sound from a file in the current directory and stores it in a-snd:
    ; load a sound
    ;
    set a-snd = s-read(strcat(current-path(), "demo-snd.aiff"))
    

    ; play it ; play a-snd

    One might then be tempted to write the following:

    play seq(a-snd, a-snd)  ;WRONG!
    
    Why is this wrong? Recall that seq works by modifying *warp*, not by operating on sounds. So, seq will proceed by evaluating a-snd with different values of *warp*. However, the result of evaluating a-snd (a variable) is always the same sound, regardless of the environment; in this case, the second a-snd should start at time 0.0, just like the first. In this case, after the first sound ends, Nyquist is unable to "back up" to time zero, so in fact, this will play two sounds in sequence, but that is a result of an implementation detail rather than correct program execution. In fact, a future version of Nyquist might (correctly) stop and report an error when it detects that the second sound in the sequence has a real start time that is before the requested one.

    How then do we obtain a sequence of two sounds properly? What we really need here is a behavior that transforms a given sound according to the current transformation environment. That job is performed by cue. For example, the following will behave as expected, producing a sequence of two sounds:

    play seq(cue(a-snd), cue(a-snd))
    
    This example is correct because the second expression will shift the sound stored in a-snd to start at the end time of the first expression.

    The lesson here is very important: sounds are not behaviors! Behaviors are computations that generate sounds according to the transformation environment. Once a sound has been generated, it can be stored, copied, added to other sounds, and used in many other operations, but sounds are not subject to transformations. To transform a sound, use cue, sound, or control. The differences between these operations are discussed later. For now, here is a "cue sheet" style score that plays 4 copies of a-snd:

    ; use sim and at to place sounds in time
    ;
    play sim(cue(a-snd) @ 0.0,
             cue(a-snd) @ 0.7,
             cue(a-snd) @ 1.0,
             cue(a-snd) @ 1.2)
    

    The At Transformation

    The second concept introduced by the previous example is the @ operation, which shifts the *warp* component of the environment. For example,
    cue(a-snd) @ 0.7
    
    can be explained operationally as follows: modify *warp* by shifting it by 0.7 and evaluate cue(a-snd). Return the resulting sound after restoring *warp* to its original value. Notice how @ is used inside a sim construct to locate copies of a-snd in time. This is the standard way to represent a note-list or a cue-sheet in Nyquist.

    This also explains why sounds need to be cue'd in order to be shifted in time or arranged in sequence. If this were not the case, then sim would take all of its parameters (a set of sounds) and line them up to start at the same time. But cue(a-snd) @ 0.7 is just a sound, so sim would "undo" the effect of @, making all of the sounds in the previous example start simultaneously, in spite of the @! Since sim respects the intrinsic starting times of sounds, a special operation, cue, is needed to create a new sound with a new starting time.

    The Stretch Transformation

    In addition to At (denoted in SAL by the @ operator, the Stretch transformation is very important. It appeared in the introduction, and it is denoted in SAL by the ~ operator (or in LISP by the stretch special form). Stretch also operates on the *warp* component of the environment. For example,
    osc(c4) ~ 3
    
    does the following: modify *warp*, scaling the degree of "stretch" by 3, and evaluate osc(c4). The osc behavior uses the stretch factor to determime the duration, so it will return a sound that is 3 seconds long. Restore *warp* to its original value. Like At, Stretch only affects behaviors. a-snd ~ 10 is equivalent to a-snd because a-snd is a sound, not a behavior. Behaviors are functions that compute sounds according to the environment and return a sound.

    Nested Transformations

    Transformations can be combined using nested expressions. For example,
    sim(cue(a-snd),
        loud(6.0, cue(a-snd) @ 3))
    
    scales the amplitude as well as shifts the second entrance of a-snd.

    Why use loud instead of simply multiplying a-snd by some scale factor? Using loud gives the behavior the chance to implement the abstract property loudness in an appropriate way, e.g. by including timbral changes. In this case, the behavior is cue, which implements loudness by simple amplitude scaling, so the result is equivalent to multiplication by db-to-linear(6.0).

    Transformations can also be applied to groups of behaviors:

    loud(6.0, sim(cue(a-snd) @ 0.0,
                  cue(a-snd) @ 0.7))
    

    Defining Behaviors

    Groups of behaviors can be named using define (we already saw this in the definitions of my-note and env-note). Here is another example of a behavior definition and its use. The definition has one parameter:
    define function snds(dly)
      return sim(cue(a-snd) @ 0.0,
                 cue(a-snd) @ 0.7,
                 cue(a-snd) @ 1.0,
                 cue(a-snd) @ (1.2 + dly))
    

    play snds(0.1) play loud(0.25, snds(0.3) ~ 0.9)

    In the last line, snds is transformed: the transformations will apply to the cue behaviors within snds. The loud transformation will scale the sounds by 0.25, and the stretch (~) will apply to the shift (@) amounts 0.0, 0.7, 1.0, and 1.2 + dly. The sounds themselves (copies of a-snd) will not be stretched because cue never stretches sounds.

    Section "Transformations" describes the full set of transformations.

    Overriding Default Transformations

    In Nyquist, behaviors are the important abstraction mechanism. A behavior represents a class of related functions or sounds. For example, a behavior can represent a musical note. When a note is stretched, it usually means that the tone sustains for more oscillations, but if the "note" is a drum roll, the note sustains by more repetitions of the component drum strokes. The concept of sustain is so fundamental that we do not really think of different note durations as being different instances of an abstract behavior, but in a music programming language, we need a way to model these abtract behaviors. As the tone and drum roll examples show, there is no one right way to "stretch," so the language must allow users to define exactly what it means to stretch. By extension, the Nyquist programmer can define how all of the transformations affect different behaviors.

    To make programming easier, almost all Nyquist sounds are constructed from primitive behaviors that obey the environment in obvious ways: Stretch transformations make things longer and At transformations shift things in time. But sometimes you have to override the default behaviors. Maybe the attack phase of an envelope should not stretch when the note is stretched, or maybe when you stretch a trill, you should get more notes rather than a slower trill.

    To override default behaviors, you almost always follow the same programming pattern: first, capture the environment in a local variable; then, use one of the absolute transformations to "turn off" the environment's effect and compute the sound as desired. The following example creates a very simple envelope with a fixed rise time to illustrate the technique.

    define function two-phase-env(rise-time)
      begin
        with dur = get-duration(1)
        return pwl(rise-time, 1, dur) ~~ 1.0
      end
    
    To "capture the environment in a local variable," a with construct is used to create the local variable dur and set it to the value of get-duration(1), which answers the question: "If I apply use the environment to stretch something whose nominal duration is 1, what is the resulting duration?" (Since time transformations can involve continuous time deformations, this question is not as simple as it may sound, so please use the provided function rather than peeking inside the *warp* structure and trying to do it yourself.) Next, we "turn off" stretching using the stretch-abs form, which in SAL is denoted by the ~~ operator. Finally, we are ready to compute the envelope using pwl. Here, we use absolute durations. The first breakpoint is at rise-time, so the attack time is given by the rise-time parameter. The pwl decays back to zero at time dur, so the overall duration matches the duration expected from the environment encountered by this instance of two-phase-env. Note, however, that since the pwl is evaluated in a different environment established by ~~, it is not stretched (or perhaps more accurately, it is stretched by 1.0). This is good because it means rise-time will not be stretched, but we must be careful to extend the envelope to dur so that it has the expected duration.

    Sample Rates

    The global environment contains *sound-srate* and *control-srate*, which determine the sample rates of sounds and control signals. These can be overridden at any point by the transformations sound-srate-abs and control-srate-abs; for example,
    sound-srate-abs(44100.0, osc(c4)
    
    will compute a tone using a 44.1Khz sample rate even if the default rate is set to something different.

    As with other components of the environment, you should never change *sound-srate* or *control-srate* directly. The global environment is determined by two additional variables: *default-sound-srate* and *default-control-srate*. You can add lines like the following to your init.lsp file to change the default global environment:

    (setf *default-sound-srate* 44100.0)
    (setf *default-control-srate* 1102.5)
    
    You can also do this using preferences in NyquistIDE. If you have already started Nyquist and want to change the defaults, the preferences or the following functions can be used:
    exec set-control-srate(1102.5)
    exec set-sound-srate(22050.0)
    
    These modify the default values and reinitialize the Nyquist environment.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/fig6.gif0000644000175000000620000000411210144436365014256 0ustar stevestaffGIF87a , ڋ޼H扦ʶ L ĢL*̦ JԪjܮ N (8HXhx)9IYiy *:JZjz +;K[k{,F^.?/n^OxfϠ@X2\ARbQ"W2>ȱG CN#*\&2G撛 yɩ3π7tSҤQ"Ss΀*r)S YyD@ױ+j6ڵEm{XoHoټ=R˰j뢵1ܩOLXW-o݉X<ã:{ Ldaޢ3՘ 7~H7n! lÃ(oΚm䶠Pu{;~@Gӻ07FWo~Jb^P(2(F+|k-f۶{fnoЂKкyt{$nkj骋%ι͔Flx,VžJCr&_q&^qS)r7-;rr @Ɲt:}LCGJ20[+W|M3ׇ5A bȴ5u7+6mA}pܺv݂ܴԈe <]^Gp4Ў!Bv+xt7#^w䥛tf:US8N87ЗvTlvT.{ |Ur8=ٵ^6_[^=w>>҇}koLǿ4}g}SpvrIc &aIUdW M|r$Vr* OAn(qhNCOQ@\(rІY D aIs,'ՃNgjw\8ِ|qg(ӝ,e72"N?P OtEя>ΙQ:JJ҅띖2bRm,H7ӆ^';}G:S OBTj%蒌a բEߤJKkJfT [JuD:2}˫_ v )aY2mcWj ӒiJlʢS#jZMU7#mE1 m(Uhz[ ul9 [!VNmr]cܛ\AJPXˎw w-yϋL'5vO^."uu Sb/wߒ8/+x n *&qW Yktn$~ڤ~ 5_|_2O޸Jв!~{-X,?鳌GOxJ<2xBQ:l;*2֊ȩYX)P fNyquist Reference Manual

    Nyquist Reference Manual

    Version 3.05

    Copyright 2011 by Roger B. Dannenberg

    Carnegie Mellon University
    School of Computer Science
    Pittsburgh, PA 15213, U.S.A.


    Next Section | Index |

    Table of Contents


    Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/gamma-fig.gif0000644000175000000620000000215511466723256015263 0ustar stevestaffGIF87a w!Software: Microsoft Office, ڋ޼H&ʶL}YA+"QDb\J %`EDnd;r9D7-tw<ί'XS88sTBiIQْv9I!Zr:ZZbEJɂ+;;{i{>P/?y~ ?OAHL`6 &pȏ(>HGR7YcD!Y?vTwKL0QΛ6mȔgdgNq4^.MҧemTuXnڕYԉaY~=YV+k:kc%KPÊO./o5Y:p(.8c5o֙xc :iTJ^M5+ذRr}NlڎlanS^6|ZÒ7?Zʥ"n٭A;<ݴ gx{ï]ȗW?FUUVJTeƉ KVI$҆V]E0"6V1~O'%J(bhTHȈ#أxeV@$])VeAiS v$M`i^dgg~ljo'pr %M遞ڦ2^XhSK IF`M 7mTE[y*]6c~ڪGS&X-z)uk$)PyXY+"l B-0kJQ[-`mORn.qnwo n[ZZblƅyG՘@SRa 1SJM|}^NƼBrvQ|"sH2Ǧ.'q͏2 N*32FʓR= 3}Rҳ.ʹF\\SZ/ɗSG-dfl2 wrMwvߍwzw~ xTS%^>*/ޑLQT5 =^%H.1"Id0]Xg^_v4\8ߎ{;nyquist-3.05/doc/part18.html0000644000175000000620000003025011537432671014746 0ustar stevestaffPrevious Section | Next Section | Table of Contents | Index | Title Page
    Appendix 3: Intgen

    Appendix 3: Intgen

    This documentation describes Intgen, a program for generating XLISP to C interfaces. Intgen works by scanning .h files with special comments in them. Intgen builds stubs that implement XLISP SUBR's. When the SUBR is called, arguments are type-checked and passed to the C routine declared in the .h file. Results are converted into the appropriate XLISP type and returned to the calling XLISP function. Intgen lets you add C functions into the XLISP environment with very little effort.

    The interface generator will take as command-line input:

    • the name of the .c file to generate (do not include the .c extension; e.g. write xlexten, not xlexten.c);
    • a list of .h files.
    Alternatively, the command line may specify a command file from which to read file names. The command file name should be preceded by "@", for example:
    intgen @sndfns.cl
    
    reads sndfns.cl to get the command-line input. Only one level of indirection is allowed.

    The output is:

    • a single .c file with one SUBR defined for each designated routine in a .h file.
    • a .h file that declares each new C routine. E.g. if the .c file is named xlexten.c, this file will be named xlextendefs.h;
    • a .h file that extends the SUBR table used by Xlisp. E.g. if the .c file is named xlexten.c, then this file is named xlextenptrs.h;
    • a .lsp file with lisp initialization expressions copied from the .h files. This file is only generated if at least one initialization expression is encountered.

    For example, the command line

    intgen seint ~setypes.h access.h
    
    generates the file seint.c, using declarations in setypes.h and access.h. Normally, the .h files are included by the generated file using #include commands. A ~ before a file means do not include the .h file. (This may be useful if you extend xlisp.h, which will be included anyway). Also generated will be setintdefs.h and seintptrs.h.

    Extending Xlisp

    Any number of .h files may be named on the command line to Intgen, and Intgen will make a single .c file with interface routines for all of the .h files. On the other hand, it is not necessary to put all of the extensions to Xlisp into a single interface file. For example, you can run Intgen once to build interfaces to window manager routines, and again to build interfaces to a new data type. Both interfaces can be linked into Xlisp.

    To use the generated files, you must compile the .c files and link them with all of the standard Xlisp object files. In addition, you must edit the file localdefs.h to contain an #include for each *defs.h file, and edit the file localptrs.h to include each *ptrs.h file. For example, suppose you run Intgen to build soundint.c, fugueint.c, and tableint.c. You would then edit localdefs.h to contain the following:

    #include "soundintdefs.h"
    #include "fugueintdefs.h"
    #include "tableintdefs.h"
    
    and edit localptrs.h to contain:
    #include "soundintptrs.h"
    #include "fugueintptrs.h"
    #include "tableintptrs.h"
    
    These localdefs.h and localptrs.h files are in turn included by xlftab.c which is where Xlisp builds a table of SUBRs.

    To summarize, building an interface requires just a few simple steps:

    • Write C code to be called by Xlisp interface routines. This C code does the real work, and in most cases is completely independent of Xlisp.
    • Add comments to .h files to tell Intgen which routines to build interfaces to, and to specify the types of the arguments.
    • Run Intgen to build interface routines.
    • Edit localptrs.h and localdefs.h to include generated .h files.
    • Compile and link Xlisp, including the new C code.

    Header file format

    Each routine to be interfaced with Xlisp must be declared as follows:
    type-name routine-name(); /* LISP: (func-name type1 type2 ...) */
    
    The comment may be on the line following the declaration, but the declaration and the comment must each be on no more than one line. The characters LISP: at the beginning of the comment mark routines to put in the interface. The comment also gives the type and number of arguments. The function, when accessed from lisp will be known as func-name, which need not bear any relationship to routine-name. By convention, underscores in the C routine-name should be converted to dashes in func-name, and func-name should be in all capitals. None of this is enforced or automated though.

    Legal type_names are:

    LVAL
    returns an Xlisp datum.

    atom_type
    equivalent to LVAL, but the result is expected to be an atom.

    value_type
    a value as used in Dannenberg's score editor.

    event_type
    an event as used in Dannenberg's score editor.

    int
    interface will convert int to Xlisp FIXNUM.

    boolean
    interface will convert int to T or nil.

    float or double
    interface converts to FLONUM.

    char * or string or string_type
    interface converts to STRING. The result string will be copied into the XLISP heap.

    void
    interface will return nil.

    It is easy to extend this list. Any unrecognized type will be coerced to an int and then returned as a FIXNUM, and a warning will be issued.

    The "*" after char must be followed by routine-name with no intervening space.

    Parameter types may be any of the following:

    FIXNUM
    C routine expects an int.

    FLONUM or FLOAT
    C routine expects a double.

    STRING
    C routine expects char *, the string is not copied.

    VALUE
    C routine expects a value_type. (Not applicable to Fugue.)

    EVENT
    C routine expects an event_type. (Not applicable to Fugue.)

    ANY
    C routine expects LVAL.

    ATOM
    C routine expects LVAL which is a lisp atom.

    FILE
    C routine expects FILE *.

    SOUND
    C routine expects a SoundPtr.

    Any of these may be followed by "*": FIXNUM*, FLONUM*, STRING*, ANY*, FILE*, indicating C routine expects int *, double *, char **, LVAL *, or FILE ** . This is basically a mechanism for returning more than one value, not a mechanism for clobbering XLisp values. In this spirit, the interface copies the value (an int, double, char *, LVAL, or FILE *) to a local variable and passes the address of that variable to the C routine. On return, a list of resulting "*" parameters is constructed and bound to the global XLisp symbol *RSLT*
    . (Strings are copied.) If the C routine is void, then the result list is also returned by the corresponding XLisp function.

    Note 1: this does not support C routines like strcpy that modify strings, because the C routine gets a pointer to the string in the XLisp heap. However, you can always add an intermediate routine that allocates space and then calls strcpy, or whatever.

    Note 2: it follows that a new XLisp STRING will be created for each STRING* parameter.

    Note 3: putting results on a (global!) symbol seems a bit unstructured, but note that one could write a multiple-value binding macro that hides this ugliness from the user if desired. In practice, I find that pulling the extra result values from *RSLT* when needed is perfectly acceptable.

    For parameters that are result values only, the character "^" may be substituted for "*". In this case, the parameter is not to be passed in the XLisp calling site. However, the address of an initialized local variable of the given type is passed to the corresponding C function, and the resulting value is passed back through *RSLT* as ordinary result parameter as described above. The local variables are initialized to zero or NULL.

    Using #define'd macros

    If a comment of the form:
    /* LISP: type-name (routine-name-2 type-1 type-2 ...) */
    
    appears on a line by itself and there was a #define on the previous line, then the preceding #define is treated as a C routine, e.g.
    #define leftshift(val, count) ((val) << (count))
    /* LISP: int (LOGSHIFT INT INT) */
    
    will implement the LeLisp function LOGSHIFT.

    The type-name following "LISP:" should have no spaces, e.g. use ANY*, not ANY *.

    Lisp Include Files

    Include files often define constants that we would like to have around in the Lisp world, but which are easier to initialize just by loading a text file. Therefore, a comment of the form:
    /* LISP-SRC: (any lisp expression) */
    
    will cause Intgen to open a file name.lsp and append
    (any lisp expression)
    
    to name.lsp, where name is the interface name passed on the command line. If none of the include files examined have comments of this form, then no name.lsp file is generated. Note: the LISP-SRC comment must be on a new line.

    Example

    This file was used for testing Intgen. It uses a trick (ok, it's a hack) to interface to a standard library macro (tolower). Since tolower is already defined, the macro ToLower is defined just to give Intgen a name to call. Two other routines, strlen and tough, are interfaced as well.
    /* igtest.h -- test interface for intgen */
    

    #define ToLower(c) tolower(c) /* LISP: int (TOLOWER FIXNUM) */

    int strlen(); /* LISP: (STRLEN STRING) */

    void tough(); /* LISP: (TOUGH FIXNUM* FLONUM* STRING ANY FIXNUM) */

    More Details

    Intgen has some compiler switches to enable/disable the use of certain types, including VALUE and EVENT types used by Dannenberg's score editing work, the SOUND type used by Fugue, and DEXT and SEXT types added for Dale Amon. Enabling all of these is not likely to cause problems, and the chances of an accidental use of these types getting through the compiler and linker seems very small.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/gaussian-fig.gif0000644000175000000620000000211011466723256016002 0ustar stevestaffGIF87a w!Software: Microsoft Office, t޼Ր)ʶ ](̆ l pکJT2xhBܮ ;NKQ 9G4g#HX5d44B(iy9@I):YB*ֆj: ){JK*d닷;<'K̬L}\}4ͭ=>wM.2*)>O'N_f?O/࿁$px c#!‡$N@j|1GJenˉf*pDK>.aI Ĉ6 dOmMTqh,=*u4ӥ6ӊVʬzW^uJٵin6 f׮ztׯG TØ;f1aȍ=$VLY͙%]sAREIVk@kϦ m=e[o9C xaȉ(n2uԥ깵{ukfp`N!<4ZuW{o kɋ~WtG FWS rG!C^,l~b6x-hb肏H$ZȤ}C, YߑVe_fcgdkv(foifsdZ6'/yTv}vh(Npyg^%E眖NTs)}V:Yzzjh૱phg2藷⚩Bv9.&[8~.Vk rK,Gjknۤ[rѮk/Zp1|Fװ(V cL \΍ Øɨ2b* ɼ?eLSʫX:2 *9_"bҁ:/>ʹURtZou^ vbMvfv] ̹ܰMvRo.U{ӡwFv_%l>7v7-2n4 ry-E;nyquist-3.05/doc/fig4.gif0000644000175000000620000000344210144436365014261 0ustar stevestaffGIF87a8,8ڋ޼H扦ʶ L ĢL*̦ JԪjܮ N (8HXhx)9IYiy *:JZjz +;K[k{ ,\x EuRҥgˎr5kبSt;4pBuO(^:x &W.!^OYvƛӎ!b>Njgʃ3|ܫ}tZzA`@6(y}7V`0mz !(a &%,^1*h3b<[v"%ʨH:㒗:5L )eJҨe\^yy$mieX%U $ogzɦk҉'Mgn9(iߜAyv#%Z*"?j:iVohxGjvu'm ৢFi&yʫa K)k`j(l6묧"޴靲+ŦAl-snj_vZb/ߪx* .JK>/*<h:lZ3q,z~%*2w>kVƁ#,V$.;<2J A㈘4N}uT] I Kn>-"=6Q{xWpmvdwF6ݽtՉ{4m$ w' 8y~Mk9拴G9:̊[Tꪹ눣^˧APޞ11kUz+<={[<Y=Fo',^/z作eLD>I[ya"pT|O*?Ѐ@Ь@qf#BPjPx9Q Srߤ0:)AOa(;TH_ vD,$*qLl(JqT,jq\0qd,ψ4qll8qt,Z݊VQpuWU`WF0맬~ d+X2֔,`3XĂ \mgPYcmk_ vmovo w-q*;nyquist-3.05/doc/arcsine-fig.gif0000644000175000000620000000202411466723256015620 0ustar stevestaffGIF87a w!Software: Microsoft Office, ڋxH rߌכoyĢb7 )/ij 'S\ -o;^in'8EFxgG89!Ig)I Zz& Aj ([Jk۠; \ ëDl'\ # }LMMމ[q?M0^~/ίo[1H| -D0È'RLh⿌q#}FC6 IJ ʗF3sV ɒB, (eJk ѨRU8j-Z%fʊ+XSbǂ*kVmi66CqoUMxWƷo V A˸1^TDle̟43aЉ4&}eIk3g3m'չ[tC^\(f^籸 y.$FL3w/|ӫ2{4ϧ|}2S JHD6 ^61Bbᅎ9蟆equX=0+ b%0AbR݂6J3c{:(@Ud=bzJhO6C2SRY%WY#[-w_g.cog?lZӌd6&ğvઠj :Jůf"nI6 ƴǦ9n;jKjyֵ{s榫'nJ;/V{o{ ND:YG\ܩp ; q [|nq r"Lr̢r- S12q/l%\thL"p;{if=+]Db9-48VܜFtY/js?Z%_h)3K1Q;nyquist-3.05/doc/beta-fig.gif0000644000175000000620000000172411466723256015115 0ustar stevestaffGIF87a w!Software: Microsoft Office, ڋ,υH`歇L4|L(-L*pR6 X. {$6t sm(8bG4xU(8' aI ZJEjdڇz׊ [;Ckkk \f-]-Cm --^Dn~޾?./^oO~ϯϜ'$4ASu(\ !! eEunLGG!G+i2ʔVe2YU 9'bB+jtҤ2}RKݬ*VMZRΰJǒmj*b?a{8( &O1hAփM*z;|xO"nO "!آ8KA"rcq;h#  WeG81ds?#lĭPj˹fq!Af'vTgf&&I$JXVDO(&Rphy1J6)uihjAG`BfZէjfak l5&yƙ*,fh١!FmzjZ .mK. n oKo9, (hdBNcFIЁ"i%L>\luƷ%{ljt',a6a\$8+ 吳G;nyquist-3.05/doc/part19.html0000644000175000000620000041542011537432671014755 0ustar stevestaffPrevious Section | Next Section (Index) | Table of Contents | Title Page
    Appendix 4: XLISP: An Object-oriented Lisp

    Appendix 4: XLISP: An Object-oriented Lisp

    Version 2.0

    February 6, 1988

    by
    David Michael Betz
    127 Taylor Road
    Peterborough, NH 03458

    Copyright (c) 1988, by David Michael Betz
    All Rights Reserved
    Permission is granted for unrestricted non-commercial use

    Introduction

    XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers.

    Implementations of XLISP run on virtually every operating system. XLISP is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users.

    Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects Object and Class as primitives. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances (it is the only object that is an instance of itself).

    This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming.

    I recommend the book Lisp by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp.

    You will probably also need a copy of Common Lisp: The Language by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document.

    A Note From The Author

    If you have any problems with XLISP, feel free to contact me [me being David Betz - RBD] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users [e.g. that Dannenberg fellow - RBD] have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me.

    If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it.

    Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However, PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!! I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run.

    XLISP Command Loop

    When XLISP is started, it first tries to load the workspace xlisp.wks from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols.

    Then XLISP attempts to load init.lsp from the current directory. It then loads any files named as parameters on the command line (after appending .lsp to their names).

    XLISP then issues the following prompt:

            >
    
    This indicates that XLISP is waiting for an expression to be typed.

    When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed.

    Special Characters

    When XLISP is running from a console, some control characters invoke operations:
    • Backspace and Delete characters erase the previous character on the input line (if any).
    • Control-U erases the entire input line.
    • Control-C executes the TOP-LEVEL function.
    • Control-G executes the CLEAN-UP function.
    • Control-P executes the CONTINUE function.
    • Control-B stops execution and enters the break command loop. Execution can be continued by typing Control-P or (CONTINUE).
    • Control-E turns on character echoing (Linux and Mac OS X only).
    • Control-F turns off character echoing (Linux and Mac OS X only).
    • Control-T evaluates the INFO function.

    Break Command Loop

    When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way:

    If the symbol *breakenable* is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed.

    If the symbol *tracenable* is true, a trace back is printed. The number of entries printed depends on the value of the symbol *tracelimit*. If this symbol is set to something other than a number, the entire trace back stack is printed.

    XLISP then enters a read/eval/print loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level read/eval/print loop in that if the user invokes the function continue, XLISP will continue from a correctable error. If the user invokes the function clean-up, XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt.

    If the symbol *breakenable* is nil, XLISP looks for a surrounding errset function. If one is found, XLISP examines the value of the print flag. If this flag is true, the error message is printed. In any case, XLISP causes the errset function call to return nil.

    If there is no surrounding errset function, XLISP prints the error message and returns to the top level.

    Data Types

    There are several different data types available to XLISP programmers.

    • lists
    • symbols
    • strings
    • integers
    • characters
    • floats
    • objects
    • arrays
    • streams
    • subrs (built-in functions)
    • fsubrs (special forms)
    • closures (user defined functions)

    The Evaluator

    The process of evaluation in XLISP:
    • Strings, integers, characters, floats, objects, arrays, streams, subrs, fsubrs and closures evaluate to themselves.
    • Symbols act as variables and are evaluated by retrieving the value associated with their current binding.
    • Lists are evaluated by examining the first element of the list and then taking one of the following actions:
      • If it is a symbol, the functional binding of the symbol is retrieved.
      • If it is a lambda expression, a closure is constructed for the function described by the lambda expression.
      • If it is a subr, fsubr or closure, it stands for itself.
      • Any other value is an error.
      Then, the value produced by the previous step is examined:
      • If it is a subr or closure, the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments.
      • If it is an fsubr, the fsubr is called using the remaining list elements as arguments (unevaluated).
      • If it is a macro, the macro is expanded using the remaining list elements as arguments (unevaluated). The macro expansion is then evaluated in place of the original macro call.

    Lexical Conventions

    The following conventions must be followed when entering XLISP programs:

    Comments in XLISP code begin with a semi-colon character and continue to the end of the line.

    Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following:

                    ( ) ' ` , " ;
    
    Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input.

    Integer literals consist of a sequence of digits optionally beginning with a + or -. The range of values an integer can represent is limited by the size of a C long on the machine on which XLISP is running.

    Floating point literals consist of a sequence of digits optionally beginning with a + or - and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C float (double on machines with 32 bit addresses) on the machine on which XLISP is running.

    Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the "\" character is used to allow non-printable characters to be included. The codes recognized are:

    • \\ means the character "\"
    • \n means newline
    • \t means tab
    • \r means return
    • \f means form feed
    • \nnn means the character whose octal code is nnn

    Readtables

    The behavior of the reader is controlled by a data structure called a readtable. The reader uses the symbol *readtable* to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things:
    • NIL - Indicating an invalid character
    • :CONSTITUENT - Indicating a symbol constituent
    • :WHITE-SPACE - Indicating a whitespace character
    • (:TMACRO . fun) - Terminating readmacro
    • (:NMACRO . fun) - Non-terminating readmacro
    • :SESCAPE - Single escape character ('\')
    • :MESCAPE - Multiple escape character ('|')

    In the case of :TMACRO and :NMACRO, the fun component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return NIL to indicate that the character should be treated as white space or a value consed with NIL to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream.

    XLISP defines several useful read macros:

    Lambda Lists

    There are several forms in XLISP that require that a "lambda list" be specified. A lambda list is a definition of the arguments accepted by a function. There are four different types of arguments.

    The lambda list starts with required arguments. Required arguments must be specified in every call to the function.

    The required arguments are followed by the &optional arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an &optional argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to NIL. It is also possible to provide the name of a supplied-p variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the supplied- p variable will be bound to T if a value was specified in the call and NIL if the default value was used.

    The &optional arguments are followed by the &rest argument. The &rest argument gets bound to the remainder of the argument list after the required and &optional arguments have been removed.

    The &rest argument is followed by the &key arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol (a symbol that begins with a ":"). The value of the second expression is the value of the keyword argument. Like &optional arguments, &key arguments can have initialization expressions and supplied-p variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a ":" to the beginning of the keyword argument symbol is used. In other words, if the keyword argument symbol is foo, the keyword will be :foo.

    The &key arguments are followed by the &aux variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the &aux variables.

    Here is the complete syntax for lambda lists:

    (rarg...
    [&optional [oarg | (oarg [init [svar]])]...]
    [&rest rarg]
    [&key
    [karg | ([karg | (key karg)] [init [svar]])]...
    &allow-other-keys]
    [&aux
    [aux | (aux [init])]...])

    where:

    rarg is a required argument symbol
    oarg is an &optional argument symbol
    rarg is the &rest argument symbol
    karg is a &key argument symbol
    key is a keyword symbol
    aux is an auxiliary variable symbol
    init is an initialization expression
    svar is a supplied-p variable symbol

    Objects

    Definitions:
    • selector - a symbol used to select an appropriate method
    • message - a selector and a list of actual arguments
    • method - the code that implements a message
    Since XLISP was created to provide a simple basis for experimenting with object-oriented programming, one of the primitive data types included is object. In XLISP, an object consists of a data structure containing a pointer to the object's class as well as an array containing the values of the object's instance variables.

    Officially, there is no way to see inside an object (look at the values of its instance variables). The only way to communicate with an object is by sending it a message.

    You can send a message to an object using the send function. This function takes the object as its first argument, the message selector as its second argument (which must be a symbol) and the message arguments as its remaining arguments.

    The send function determines the class of the receiving object and attempts to find a method corresponding to the message selector in the set of messages defined for that class. If the message is not found in the object's class and the class has a super-class, the search continues by looking at the messages defined for the super-class. This process continues from one super-class to the next until a method for the message is found. If no method is found, an error occurs.

    When a method is found, the evaluator binds the receiving object to the symbol self and evaluates the method using the remaining elements of the original list as arguments to the method. These arguments are always evaluated prior to being bound to their corresponding formal arguments. The result of evaluating the method becomes the result of the expression.

    Within the body of a method, a message can be sent to the current object by calling the (send self ...). The method lookup starts with the object's class regardless of the class containing the current method.

    Sometimes it is desirable to invoke a general method in a superclass even when it is overridden by a more specific method in a subclass. This can be accomplished by calling send-super, which begins the method lookup in the superclass of the class defining the current method rather than in the class of the current object.

    The send-super function takes a selector as its first argument (which must be a symbol) and the message arguments as its remaining arguments. Notice that send-super can only be sent from within a method, and the target of the message is always the current object (self). (send-super ...) is similar to (send self ...) except that method lookup begins in the superclass of the class containing the current method rather than the class of the current object.

    The "Object" Class

    Object - the top of the class hierarchy.

    Messages:

    :show - show an object's instance variables.
    returns - the object

    :class - return the class of an object
    returns - the class of the object

    :isa class - test if object inherits from class
    returns - t if object is an instance of class or a subclass of class, otherwise nil

    :isnew - the default object initialization routine
    returns - the object

    The "Class" Class

    Class - class of all object classes (including itself)

    Messages:

    :new - create a new instance of a class
    returns - the new class object

    :isnew ivars [cvars [super]] - initialize a new class
    ivars - the list of instance variable symbols
    cvars - the list of class variable symbols
    super - the superclass (default is object)
    returns - the new class object

    :answer msg fargs code - add a message to a class
    msg - the message symbol
    fargs - the formal argument list (lambda list)
    code - a list of executable expressions
    returns - the object

    When a new instance of a class is created by sending the message :new to an existing class, the message :isnew followed by whatever parameters were passed to the :new message is sent to the newly created object.

    When a new class is created by sending the :new message to the object Class, an optional parameter may be specified indicating the superclass of the new class. If this parameter is omitted, the new class will be a subclass of Object. A class inherits all instance variables, class variables, and methods from its super-class.

    Profiling

    The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where eval is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an eval in the immediately (lexically) enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls. The list of all functions executed is maintained on the global *profile* variable. These functions in turn have *profile* properties, which maintain the counts. The profile system merely increments counters and puts symbols on the *profile* list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the profile function. Unfortunately, methods cannot be profiled with this facility.

    Symbols

    There are several symbols maintained by the read/eval/print loop. The symbols +, ++, and +++ are bound to the most recent three input expressions. The symbols *, ** and *** are bound to the most recent three results. The symbol - is bound to the expression currently being evaluated. It becomes the value of + at the end of the evaluation.

    Evaluation Functions

    eval(expr) [SAL]
    (eval
    expr) [LISP] - evaluate an xlisp expression
    expr - the expression to be evaluated
    returns - the result of evaluating the expression

    apply(fun, args) [SAL]
    (apply
    fun args) [LISP] - apply a function to a list of arguments
    fun - the function to apply (or function symbol)
    args - the argument list
    returns - the result of applying the function to the arguments

    funcall(fun, arg...) [SAL]
    (funcall
    fun arg...) [LISP] - call a function with arguments
    fun - the function to call (or function symbol)
    arg - arguments to pass to the function
    returns - the result of calling the function with the arguments

    quote(expr) [SAL]
    (quote
    expr) [LISP] - return an expression unevaluated
    expr - the expression to be quoted (quoted)
    returns - expr unevaluated

    function(expr) [SAL]
    (function
    expr) [LISP] - get the functional interpretation
    expr - the symbol or lambda expression (quoted)
    returns - the functional interpretation

    backquote(expr) [SAL]
    (backquote
    expr) [LISP] - fill in a template
    expr - the template
    returns - a copy of the template with comma and comma-at
    expressions expanded

    lambda(args, expr...) [SAL]
    (lambda
    args expr...) [LISP] - make a function closure
    args - formal argument list (lambda list) (quoted)
    expr - expressions of the function body
    returns - the function closure

    get-lambda-expression(closure) [SAL]
    (get-lambda-expression
    closure) [LISP] - get the lambda expression
    closure - the closure
    returns - the original lambda expression

    macroexpand(form) [SAL]
    (macroexpand
    form) [LISP] - recursively expand macro calls
    form - the form to expand
    returns - the macro expansion

    macroexpand-1(form) [SAL]
    (macroexpand-1
    form) [LISP] - expand a macro call
    form - the macro call form
    returns - the macro expansion

    Symbol Functions

    set(sym, expr) [SAL]
    (set
    sym expr) [LISP] - set the value of a symbol
    sym - the symbol being set
    expr - the new value
    returns - the new value

    setq([sym, expr]...) [SAL]
    (setq
    [sym expr]...) [LISP] - set the value of a symbol
    sym - the symbol being set (quoted)
    expr - the new value
    returns - the new value

    psetq([sym, expr]...) [SAL]
    (psetq
    [sym expr]...) [LISP] - parallel version of setq
    sym - the symbol being set (quoted)
    expr - the new value
    returns - the new value

    setf([place, expr]...) [SAL]
    (setf
    [place expr]...) [LISP] - set the value of a field
    place - the field specifier (quoted):
    sym - set value of a symbol
    (car expr) - set car of a cons node
    (cdr expr) - set cdr of a cons node
    (nth n expr) - set nth car of a list
    (aref expr n) - set nth element of an array
    (get sym prop) - set value of a property
    (symbol-value sym) - set value of a symbol
    (symbol-function sym) - set functional value of a symbol
    (symbol-plist sym) - set property list of a symbol
    expr - the new value
    returns - the new value

    (defun sym fargs expr...) [LISP] - define a function
    (defmacro
    sym fargs expr...) [LISP] - define a macro
    sym - symbol being defined (quoted)
    fargs - formal argument list (lambda list) (quoted)
    expr - expressions constituting the body of the
    function (quoted) returns - the function symbol

    gensym([tag]) [SAL]
    (gensym
    [tag]) [LISP] - generate a symbol
    tag - string or number
    returns - the new symbol

    intern(pname) [SAL]
    (intern
    pname) [LISP] - make an interned symbol
    pname - the symbol's print name string
    returns - the new symbol

    make-symbol(pname) [SAL]
    (make-symbol
    pname) [LISP] - make an uninterned symbol
    pname - the symbol's print name string
    returns - the new symbol

    symbol-name(sym) [SAL]
    (symbol-name
    sym) [LISP] - get the print name of a symbol
    sym - the symbol
    returns - the symbol's print name

    symbol-value(sym) [SAL]
    (symbol-value
    sym) [LISP] - get the value of a symbol
    sym - the symbol
    returns - the symbol's value

    symbol-function(sym) [SAL]
    (symbol-function
    sym) [LISP] - get the functional value of a symbol
    sym - the symbol
    returns - the symbol's functional value

    symbol-plist(sym) [SAL]
    (symbol-plist
    sym) [LISP] - get the property list of a symbol
    sym - the symbol
    returns - the symbol's property list

    hash(sym, n) [SAL]
    (hash
    sym n) [LISP] - compute the hash index for a symbol
    sym - the symbol or string
    n - the table size (integer)
    returns - the hash index (integer)

    Property List Functions

    get(sym, prop) [SAL]
    (get
    sym prop) [LISP] - get the value of a property
    sym - the symbol
    prop - the property symbol
    returns - the property value or nil

    putprop(sym, val, prop) [SAL]
    (putprop
    sym val prop) [LISP] - put a property onto a property list
    sym - the symbol
    val - the property value
    prop - the property symbol
    returns - the property value

    remprop(sym, prop) [SAL]
    (remprop
    sym prop) [LISP] - remove a property
    sym - the symbol
    prop - the property symbol
    returns - nil

    Array Functions

    aref(array, n) [SAL]
    (aref
    array n) [LISP] - get the nth element of an array
    array - the array
    n - the array index (integer)
    returns - the value of the array element

    make-array(size) [SAL]
    (make-array
    size) [LISP] - make a new array
    size - the size of the new array (integer)
    returns - the new array

    vector(expr...) [SAL]
    (vector
    expr...) [LISP] - make an initialized vector
    expr - the vector elements
    returns - the new vector

    List Functions

    car(expr) [SAL]
    (car
    expr) [LISP] - return the car of a list node
    expr - the list node
    returns - the car of the list node

    cdr(expr) [SAL]
    (cdr
    expr) [LISP] - return the cdr of a list node
    expr - the list node
    returns - the cdr of the list node

    cxxr(expr) [SAL]
    (cxxr
    expr) [LISP] - all cxxr combinations


    cxxxr(expr) [SAL]
    (cxxxr
    expr) [LISP] - all cxxxr combinations


    cxxxxr(expr) [SAL]
    (cxxxxr
    expr) [LISP] - all cxxxxr combinations


    first(expr) [SAL]
    (first
    expr) [LISP] - a synonym for car


    second(expr) [SAL]
    (second
    expr) [LISP] - a synonym for cadr


    third(expr) [SAL]
    (third
    expr) [LISP] - a synonym for caddr


    fourth(expr) [SAL]
    (fourth
    expr) [LISP] - a synonym for cadddr


    rest(expr) [SAL]
    (rest
    expr) [LISP] - a synonym for cdr


    cons(expr1, expr2) [SAL]
    (cons
    expr1 expr2) [LISP] - construct a new list node
    expr1 - the car of the new list node
    expr2 - the cdr of the new list node
    returns - the new list node

    list(expr...) [SAL]
    (list
    expr...) [LISP] - create a list of values
    expr - expressions to be combined into a list
    returns - the new list

    append(expr...) [SAL]
    (append
    expr...) [LISP] - append lists
    expr - lists whose elements are to be appended
    returns - the new list

    reverse(expr) [SAL]
    (reverse
    expr) [LISP] - reverse a list
    expr - the list to reverse
    returns - a new list in the reverse order

    last(list) [SAL]
    (last
    list) [LISP] - return the last list node of a list
    list - the list
    returns - the last list node in the list

    member(expr, list, test: test, test-not: test-not) [SAL]
    (member
    expr list &key :test :test-not) [LISP] - find an expression in a list
    expr - the expression to find
    list - the list to search
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the remainder of the list starting with the expression

    assoc(expr, alist, test: test, test-not: test-not) [SAL]
    (assoc
    expr alist &key :test :test-not) [LISP] - find an expression in an a-list
    expr - the expression to find
    alist - the association list
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the alist entry or nil

    remove(expr, list, test: test, test-not: test-not) [SAL]
    (remove
    expr list &key :test :test-not) [LISP] - remove elements from a list
    expr - the element to remove
    list - the list
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - copy of list with matching expressions removed

    remove-if(test, list) [SAL]
    (remove-if
    test list) [LISP] - remove elements that pass test
    test - the test predicate
    list - the list
    returns - copy of list with matching elements removed

    remove-if-not(test, list) [SAL]
    (remove-if-not
    test list) [LISP] - remove elements that fail test
    test - the test predicate
    list - the list
    returns - copy of list with non-matching elements removed

    length(expr) [SAL]
    (length
    expr) [LISP] - find the length of a list, vector or string
    expr - the list, vector or string
    returns - the length of the list, vector or string

    nth(n, list) [SAL]
    (nth
    n list) [LISP] - return the nth element of a list
    n - the number of the element to return (zero origin)
    list - the list
    returns - the nth element or nil if the list isn't that long

    nthcdr(n, list) [SAL]
    (nthcdr
    n list) [LISP] - return the nth cdr of a list
    n - the number of the element to return (zero origin)
    list - the list
    returns - the nth cdr or nil if the list isn't that long

    mapc(fcn, list1, list...) [SAL]
    (mapc
    fcn list1 list...) [LISP] - apply function to successive cars
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - the first list of arguments

    mapcar(fcn, list1, list...) [SAL]
    (mapcar
    fcn list1 list...) [LISP] - apply function to successive cars
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - a list of the values returned

    mapl(fcn, list1, list...) [SAL]
    (mapl
    fcn list1 list...) [LISP] - apply function to successive cdrs
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - the first list of arguments

    maplist(fcn, list1, list...) [SAL]
    (maplist
    fcn list1 list...) [LISP] - apply function to successive cdrs
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - a list of the values returned

    subst(to, from, expr, test: test, test-not: test-not) [SAL]
    (subst
    to from expr &key :test :test-not) [LISP] - substitute expressions
    to - the new expression
    from - the old expression
    expr - the expression in which to do the substitutions
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the expression with substitutions

    sublis(alist, expr, test: test, test-not: test-not) [SAL]
    (sublis
    alist expr &key :test :test-not) [LISP] - substitute with an a-list
    alist - the association list
    expr - the expression in which to do the substitutions
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the expression with substitutions

    Destructive List Functions

    rplaca(list, expr) [SAL]
    (rplaca
    list expr) [LISP] - replace the car of a list node
    list - the list node
    expr - the new value for the car of the list node
    returns - the list node after updating the car

    rplacd(list, expr) [SAL]
    (rplacd
    list expr) [LISP] - replace the cdr of a list node
    list - the list node
    expr - the new value for the cdr of the list node
    returns - the list node after updating the cdr

    nconc(list...) [SAL]
    (nconc
    list...) [LISP] - destructively concatenate lists
    list - lists to concatenate
    returns - the result of concatenating the lists

    delete(expr, test: test, test-not: test-not) [SAL]
    (delete
    expr &key :test :test-not) [LISP] - delete elements from a list
    expr - the element to delete
    list - the list
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the list with the matching expressions deleted

    delete-if(test, list) [SAL]
    (delete-if
    test list) [LISP] - delete elements that pass test
    test - the test predicate
    list - the list
    returns - the list with matching elements deleted

    delete-if-not(test, list) [SAL]
    (delete-if-not
    test list) [LISP] - delete elements that fail test
    test - the test predicate
    list - the list
    returns - the list with non-matching elements deleted

    sort(list, test) [SAL]
    (sort
    list test) [LISP] - sort a list
    list - the list to sort
    test - the comparison function
    returns - the sorted list

    Predicate Functions

    atom(expr) [SAL]
    (atom
    expr) [LISP] - is this an atom?
    expr - the expression to check
    returns - t if the value is an atom, nil otherwise

    symbolp(expr) [SAL]
    (symbolp
    expr) [LISP] - is this a symbol?
    expr - the expression to check
    returns - t if the expression is a symbol, nil otherwise

    numberp(expr) [SAL]
    (numberp
    expr) [LISP] - is this a number?
    expr - the expression to check
    returns - t if the expression is a number, nil otherwise

    null(expr) [SAL]
    (null
    expr) [LISP] - is this an empty list?
    expr - the list to check
    returns - t if the list is empty, nil otherwise

    not(expr) [SAL]
    (not
    expr) [LISP] - is this false?
    expr - the expression to check
    return - t if the value is nil, nil otherwise

    listp(expr) [SAL]
    (listp
    expr) [LISP] - is this a list?
    expr - the expression to check
    returns - t if the value is a cons or nil, nil otherwise

    endp(list) [SAL]
    (endp
    list) [LISP] - is this the end of a list
    list - the list
    returns - t if the value is nil, nil otherwise

    consp(expr) [SAL]
    (consp
    expr) [LISP] - is this a non-empty list?
    expr - the expression to check
    returns - t if the value is a cons, nil otherwise

    integerp(expr) [SAL]
    (integerp
    expr) [LISP] - is this an integer?
    expr - the expression to check
    returns - t if the value is an integer, nil otherwise

    floatp(expr) [SAL]
    (floatp
    expr) [LISP] - is this a float?
    expr - the expression to check
    returns - t if the value is a float, nil otherwise

    stringp(expr) [SAL]
    (stringp
    expr) [LISP] - is this a string?
    expr - the expression to check
    returns - t if the value is a string, nil otherwise

    characterp(expr) [SAL]
    (characterp
    expr) [LISP] - is this a character?
    expr - the expression to check
    returns - t if the value is a character, nil otherwise

    arrayp(expr) [SAL]
    (arrayp
    expr) [LISP] - is this an array?
    expr - the expression to check
    returns - t if the value is an array, nil otherwise

    streamp(expr) [SAL]
    (streamp
    expr) [LISP] - is this a stream?
    expr - the expression to check
    returns - t if the value is a stream, nil otherwise

    objectp(expr) [SAL]
    (objectp
    expr) [LISP] - is this an object?
    expr - the expression to check
    returns - t if the value is an object, nil otherwise

    filep(expr) [SAL]
    (filep
    expr) [LISP] (Footnote 8) - is this a file?
    expr - the expression to check
    returns - t if the value is an object, nil otherwise

    boundp(sym) [SAL]
    (boundp sym) [LISP] - is a value bound to this symbol?
    sym - the symbol
    returns - t if a value is bound to the symbol, nil otherwise

    fboundp(sym) [SAL]
    (fboundp
    sym) [LISP] - is a functional value bound to this symbol?
    sym - the symbol
    returns - t if a functional value is bound to the symbol,
    nil otherwise

    minusp(expr) [SAL]
    (minusp
    expr) [LISP] - is this number negative?
    expr - the number to test
    returns - t if the number is negative, nil otherwise

    zerop(expr) [SAL]
    (zerop
    expr) [LISP] - is this number zero?
    expr - the number to test
    returns - t if the number is zero, nil otherwise

    plusp(expr) [SAL]
    (plusp
    expr) [LISP] - is this number positive?
    expr - the number to test
    returns - t if the number is positive, nil otherwise

    evenp(expr) [SAL]
    (evenp
    expr) [LISP] - is this integer even?
    expr - the integer to test
    returns - t if the integer is even, nil otherwise

    oddp(expr) [SAL]
    (oddp
    expr) [LISP] - is this integer odd?
    expr - the integer to test
    returns - t if the integer is odd, nil otherwise

    eq(expr1, expr2) [SAL]
    (eq
    expr1 expr2) [LISP] - are the expressions identical?
    expr1 - the first expression
    expr2 - the second expression
    returns - t if they are equal, nil otherwise

    eql(expr1, expr2) [SAL]
    (eql
    expr1 expr2) [LISP] - are the expressions identical? (works with all numbers)
    expr1 - the first expression
    expr2 - the second expression
    returns - t if they are equal, nil otherwise

    equal(expr1, expr2) [SAL]
    (equal
    expr1 expr2) [LISP] - are the expressions equal?
    expr1 - the first expression
    expr2 - the second expression
    returns - t if they are equal, nil otherwise

    Control Constructs

    (cond pair...) [LISP] - evaluate conditionally
    pair - pair consisting of:
    (pred expr...)
    where:
    pred - is a predicate expression
    expr - evaluated if the predicate is not nil
    returns - the value of the first expression whose predicate is not nil

    and(expr...) [SAL]
    (and
    expr...) [LISP] - the logical and of a list of expressions
    expr - the expressions to be anded
    returns - nil if any expression evaluates to nil, otherwise the value of the last expression (evaluation of expressions stops after the first expression that evaluates to nil)

    or(expr...) [SAL]
    (or
    expr...) [LISP] - the logical or of a list of expressions
    expr - the expressions to be ored
    returns - nil if all expressions evaluate to nil, otherwise the value of the first non-nil expression (evaluation of expressions stops after the first expression that does not evaluate to nil)

    if(texpr, expr1[, expr2]) [SAL]
    (if
    texpr expr1 [expr2]) [LISP] - evaluate expressions conditionally
    texpr - the test expression
    expr1 - the expression to be evaluated if texpr is non-nil
    expr2 - the expression to be evaluated if texpr is nil
    returns - the value of the selected expression

    when(texpr, expr...) [SAL]
    (when
    texpr expr...) [LISP] - evaluate only when a condition is true
    texpr - the test expression
    expr - the expression(s) to be evaluated if texpr is non-nil
    returns - the value of the last expression or nil

    unless(texpr, expr...) [SAL]
    (unless
    texpr expr...) [LISP] - evaluate only when a condition is false
    texpr - the test expression
    expr - the expression(s) to be evaluated if texpr is nil
    returns - the value of the last expression or nil

    (case expr case...) [LISP] - select by case
    expr - the selection expression
    case - pair consisting of:
    (value expr...)
    where:
    value - is a single expression or a list of expressions (unevaluated)
    expr - are expressions to execute if the case matches
    returns - the value of the last expression of the matching case

    (let (binding...) expr...) [LISP] - create local bindings
    (let*
    (binding...) expr...) [LISP] - let with sequential binding
    binding - the variable bindings each of which is either:
    1) a symbol (which is initialized to nil)
    2) a list whose car is a symbol and whose cadr is an initialization expression
    expr - the expressions to be evaluated
    returns - the value of the last expression

    (flet (binding...) expr...) [LISP] - create local functions
    (labels
    (binding...) expr...) [LISP] - flet with recursive functions
    (macrolet
    (binding...) expr...) [LISP] - create local macros
    binding - the function bindings each of which is:
    (sym fargs expr...)
    where:
    sym - the function/macro name
    fargs - formal argument list (lambda list)
    expr - expressions constituting the body of the function/macro
    expr - the expressions to be evaluated
    returns - the value of the last expression

    catch(sym, expr...) [SAL]
    (catch
    sym expr...) [LISP] - evaluate expressions and catch throws
    sym - the catch tag
    expr - expressions to evaluate
    returns - the value of the last expression the throw expression

    throw(sym[, expr]) [SAL]
    (throw
    sym [expr]) [LISP] - throw to a catch
    sym - the catch tag
    expr - the value for the catch to return (defaults to nil)
    returns - never returns

    unwind-protect(expr, cexpr...) [SAL]
    (unwind-protect
    expr cexpr...) [LISP] - protect evaluation of an expression
    expr - the expression to protect
    cexpr - the cleanup expressions
    returns - the value of the expression
    Note: unwind-protect guarantees to execute the cleanup expressions even if a non-local exit terminates the evaluation of the protected expression

    Looping Constructs

    (loop expr...) [LISP] - basic looping form
    expr - the body of the loop
    returns - never returns (must use non-local exit)

    (do (binding...) (texpr rexpr...) expr...) [LISP] (do* (binding...) (texpr rexpr...) expr...) [LISP]
    binding - the variable bindings each of which is either:
    1) a symbol (which is initialized to nil)
    2) a list of the form: (sym init [step]) where:
    sym - is the symbol to bind
    init - is the initial value of the symbol
    step - is a step expression
    texpr - the termination test expression
    rexpr - result expressions (the default is nil)
    expr - the body of the loop (treated like an implicit prog)
    returns - the value of the last result expression

    (dolist (sym expr [rexpr]) expr...) [LISP] - loop through a list
    sym - the symbol to bind to each list element
    expr - the list expression
    rexpr - the result expression (the default is nil)
    expr - the body of the loop (treated like an implicit prog)

    (dotimes (sym expr [rexpr]) expr...) [LISP] - loop from zero to n-1
    sym - the symbol to bind to each value from 0 to n-1
    expr - the number of times to loop
    rexpr - the result expression (the default is nil)
    expr - the body of the loop (treated like an implicit prog)

    The Program Feature

    (prog (binding...) expr...) [LISP] - the program feature
    (prog*
    (binding...) expr...) [LISP] - prog with sequential binding
    binding - the variable bindings each of which is either:
    1) a symbol (which is initialized to nil)
    2) a list whose car is a symbol and whose cadr is an initialization expression
    expr - expressions to evaluate or tags (symbols)
    returns - nil or the argument passed to the return function

    block(name, expr...) [SAL]
    (block
    name expr...) [LISP] - named block
    name - the block name (symbol)
    expr - the block body
    returns - the value of the last expression

    (return [expr]) [LISP] - cause a prog construct to return a value
    expr - the value (defaults to nil)
    returns - never returns

    return-from(name[, value]) [SAL]
    (return-from
    name [value]) [LISP] - return from a named block
    name - the block name (symbol)
    value - the value to return (defaults to nil)
    returns - never returns

    tagbody(expr...) [SAL]
    (tagbody
    expr...) [LISP] - block with labels
    expr - expression(s) to evaluate or tags (symbols)
    returns - nil

    go(sym) [SAL]
    (go
    sym) [LISP] - go to a tag within a tagbody or prog
    sym - the tag (quoted)
    returns - never returns

    (progv slist vlist expr...) [LISP] - dynamically bind symbols
    slist - list of symbols
    vlist - list of values to bind to the symbols
    expr - expression(s) to evaluate
    returns - the value of the last expression

    prog1(expr1, expr...) [SAL]
    (prog1
    expr1 expr...) [LISP] - execute expressions sequentially
    expr1 - the first expression to evaluate
    expr - the remaining expressions to evaluate
    returns - the value of the first expression

    prog2(expr1, expr2, expr...) [SAL]
    (prog2
    expr1 expr2 expr...) [LISP] - execute expressions sequentially
    expr1 - the first expression to evaluate
    expr2 - the second expression to evaluate
    expr - the remaining expressions to evaluate
    returns - the value of the second expression

    progn(expr...) [SAL]
    (progn
    expr...) [LISP] - execute expressions sequentially
    expr - the expressions to evaluate
    returns - the value of the last expression (or nil)

    Debugging and Error Handling

    trace(sym) [SAL]
    (trace
    sym) [LISP] - add a function to the trace list
    sym - the function to add (quoted)
    returns - the trace list

    untrace(sym) [SAL]
    (untrace
    sym) [LISP] - remove a function from the trace list
    sym - the function to remove (quoted)
    returns - the trace list

    error(emsg[, arg]) [SAL]
    (error
    emsg [arg]) [LISP] - signal a non-correctable error
    emsg - the error message string
    arg - the argument expression (printed after the message)
    returns - never returns

    cerror(cmsg, emsg[, arg]) [SAL]
    (cerror
    cmsg emsg [arg]) [LISP] - signal a correctable error
    cmsg - the continue message string
    emsg - the error message string
    arg - the argument expression (printed after the message)
    returns - nil when continued from the break loop

    break([bmsg[, arg]]) [SAL]
    (break
    [bmsg [arg]]) [LISP] - enter a break loop
    bmsg - the break message string (defaults to **break**)
    arg - the argument expression (printed after the message)
    returns - nil when continued from the break loop

    (clean-up) [LISP] - clean-up after an error
    returns - never returns

    (top-level) [LISP] - clean-up after an error and return to the top level
    returns - never returns

    (continue) [LISP] - continue from a correctable error
    returns - never returns

    (errset expr [pflag]) [LISP] - trap errors
    expr - the expression to execute
    pflag - flag to control printing of the error message
    returns - the value of the last expression consed with nil
    or nil on error

    (baktrace [n]) [LISP] - print n levels of trace back information
    n - the number of levels (defaults to all levels)
    returns - nil

    (evalhook expr ehook ahook [env]) [LISP] - evaluate with hooks
    expr - the expression to evaluate
    ehook - the value for *evalhook*
    ahook - the value for *applyhook*
    env - the environment (default is nil)
    returns - the result of evaluating the expression

    profile(flag) [SAL]
    (profile
    flag) [LISP] (Footnote 9) - turn profiling on or off.
    flag - nil turns profiling off, otherwise on
    returns - the previous state of profiling.

    Arithmetic Functions

    truncate(expr) [SAL]
    (truncate
    expr) [LISP] - truncates a floating point number to an integer
    expr - the number
    returns - the result of truncating the number

    float(expr) [SAL]
    (float
    expr) [LISP] - converts an integer to a floating point number
    expr - the number
    returns - the result of floating the integer

    (+ expr...) [LISP] - add a list of numbers
    expr - the numbers
    returns - the result of the addition

    (- expr...) [LISP] - subtract a list of numbers or negate a single number
    expr - the numbers
    returns - the result of the subtraction

    (* expr...) [LISP] - multiply a list of numbers
    expr - the numbers
    returns - the result of the multiplication

    (/ expr...) [LISP] - divide a list of numbers
    expr - the numbers
    returns - the result of the division

    (1+ expr) [LISP] - add one to a number
    expr - the number
    returns - the number plus one

    (1- expr) [LISP] - subtract one from a number
    expr - the number
    returns - the number minus one

    rem(expr...) [SAL]
    (rem
    function) expr...) [LISP] - remainder of a list of numbers
    expr - the numbers
    returns - the result of the remainder operation

    min(expr...) [SAL]
    (min
    expr...) [LISP] - the smallest of a list of numbers
    expr - the expressions to be checked
    returns - the smallest number in the list

    max(expr...) [SAL]
    (max
    expr...) [LISP] - the largest of a list of numbers
    expr - the expressions to be checked
    returns - the largest number in the list

    abs(expr) [SAL]
    (abs
    expr) [LISP] - the absolute value of a number
    expr - the number
    returns - the absolute value of the number

    gcd(n1, n2...) [SAL]
    (gcd
    n1 n2...) [LISP] - compute the greatest common divisor
    n1 - the first number (integer)
    n2 - the second number(s) (integer)
    returns - the greatest common divisor

    random(n) [SAL]
    (random
    n) [LISP] - compute a random number between 0 and n-1 inclusive
    n - the upper bound (integer)
    returns - a random number

    rrandom() [SAL]
    (rrandom
    ) [LISP] - compute a random real number between 0 and 1 inclusive
    returns - a random floating point number

    sin(expr) [SAL]
    (sin
    expr) [LISP] - compute the sine of a number
    expr - the floating point number
    returns - the sine of the number

    cos(expr) [SAL]
    (cos
    expr) [LISP] - compute the cosine of a number
    expr - the floating point number
    returns - the cosine of the number

    tan(expr) [SAL]
    (tan
    expr) [LISP] - compute the tangent of a number
    expr - the floating point number
    returns - the tangent of the number

    atan(expr[, expr2]) [SAL]
    (atan
    expr [expr2]) [LISP] (Footnote 10) - compute the arctangent
    expr - the value of x
    expr2 - the value of y (default value is 1.0)
    returns - the arctangent of x/y

    expt(x-expr, y-expr) [SAL]
    (expt x-expr y-expr) [LISP] - compute x to the y power
    x-expr - the floating point number
    y-expr - the floating point exponent
    returns - x to the y power

    exp(x-expr) [SAL]
    (exp
    x-expr) [LISP] - compute e to the x power
    x-expr - the floating point number
    returns - e to the x power

    sqrt(expr) [SAL]
    (sqrt
    expr) [LISP] - compute the square root of a number
    expr - the floating point number
    returns - the square root of the number

    (< n1 n2...) [LISP] - test for less than
    (<=
    n1 n2...) [LISP] - test for less than or equal to
    (=
    n1 n2...) [LISP] - test for equal to
    (/=
    n1 n2...) [LISP] - test for not equal to
    (>=
    n1 n2...) [LISP] - test for greater than or equal to
    (>
    n1 n2...) [LISP] - test for greater than
    n1 - the first number to compare
    n2 - the second number to compare
    returns - t if the results of comparing n1 with n2, n2 with n3, etc., are all true.

    Bitwise Logical Functions

    logand(expr...) [SAL]
    (logand
    expr...) [LISP] - the bitwise and of a list of numbers
    expr - the numbers
    returns - the result of the and operation

    logior(expr...) [SAL]
    (logior
    expr...) [LISP] - the bitwise inclusive or of a list of numbers
    expr - the numbers
    returns - the result of the inclusive or operation

    logxor(expr...) [SAL]
    (logxor
    expr...) [LISP] - the bitwise exclusive or of a list of numbers
    expr - the numbers
    returns - the result of the exclusive or operation

    lognot(expr) [SAL]
    (lognot
    expr) [LISP] - the bitwise not of a number
    expr - the number
    returns - the bitwise inversion of number

    String Functions

    string(expr) [SAL]
    (string
    expr) [LISP] - make a string from a value
    expr - an integer (which is first converted into its ASCII character value), string, character, or symbol
    returns - the string representation of the argument

    string-search(pat, str, start: start, end: end) [SAL]
    (string-search
    pat str &key :start :end) [LISP] (Footnote 11) - search for pattern in string
    pat - a string to search for
    str - the string to be searched
    :start - the starting offset in str
    :end - the ending offset + 1
    returns - index of pat in str or NIL if not found

    string-trim(bag, str) [SAL]
    (string-trim bag str) [LISP] - trim both ends of a string
    bag - a string containing characters to trim
    str - the string to trim
    returns - a trimed copy of the string

    string-left-trim(bag, str) [SAL]
    (string-left-trim
    bag str) [LISP] - trim the left end of a string
    bag - a string containing characters to trim
    str - the string to trim
    returns - a trimed copy of the string

    string-right-trim(bag, str) [SAL]
    (string-right-trim
    bag str) [LISP] - trim the right end of a string
    bag - a string containing characters to trim
    str - the string to trim
    returns - a trimed copy of the string

    string-upcase(str, start: start, end: end) [SAL]
    (string-upcase
    str &key :start :end) [LISP] - convert to uppercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - a converted copy of the string

    string-downcase(str, start: start, end: end) [SAL]
    (string-downcase
    str &key :start :end) [LISP] - convert to lowercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - a converted copy of the string

    nstring-upcase(str, start: start, end: end) [SAL]
    (nstring-upcase
    str &key :start :end) [LISP] - convert to uppercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - the converted string (not a copy)

    nstring-downcase(str, start: start, end: end) [SAL]
    (nstring-downcase
    str &key :start :end) [LISP] - convert to lowercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - the converted string (not a copy)

    strcat(expr...) [SAL]
    (strcat
    expr...) [LISP] - concatenate strings
    expr - the strings to concatenate
    returns - the result of concatenating the strings

    subseq(string, start[, end]) [SAL]
    (subseq
    string start [end]) [LISP] - extract a substring
    string - the string
    start - the starting position (zero origin)
    end - the ending position + 1 (defaults to end)
    returns - substring between start and end

    string<(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string<
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP] string<=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string<=
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string=
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string/=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string/=
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string>=(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string>=
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string>(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string>
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    str1 - the first string to compare
    str2 - the second string to compare
    :start1 - first substring starting offset
    :end1 - first substring ending offset + 1
    :start2 - second substring starting offset
    :end2 - second substring ending offset + 1
    returns - t if predicate is true, nil otherwise
    Note: case is significant with these comparison functions.

    string-lessp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string-lessp
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string-not-greaterp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string-not-greaterp
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string-equalp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string-equalp
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string-not-equalp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string-not-equalp
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string-not-lessp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string-not-lessp
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    string-greaterp(str1, str2, start1: start1, end1: end1, start2: start2, end2: end2) [SAL]
    (string-greaterp
    str1 str2 &key :start1 :end1 :start2 :end2) [LISP]
    str1 - the first string to compare
    str2 - the second string to compare
    :start1 - first substring starting offset
    :end1 - first substring ending offset + 1
    :start2 - second substring starting offset
    :end2 - second substring ending offset + 1
    returns - t if predicate is true, nil otherwise
    Note: case is not significant with these comparison functions.

    Character Functions

    char(string, index) [SAL]
    (char
    string index) [LISP] - extract a character from a string
    string - the string
    index - the string index (zero relative)
    returns - the ascii code of the character

    upper-case-p(chr) [SAL]
    (upper-case-p
    chr) [LISP] - is this an upper case character?
    chr - the character
    returns - t if the character is upper case, nil otherwise

    lower-case-p(chr) [SAL]
    (lower-case-p
    chr) [LISP] - is this a lower case character?
    chr - the character
    returns - t if the character is lower case, nil otherwise

    both-case-p(chr) [SAL]
    (both-case-p
    chr) [LISP] - is this an alphabetic (either case) character?
    chr - the character
    returns - t if the character is alphabetic, nil otherwise

    digit-char-p(chr) [SAL]
    (digit-char-p
    chr) [LISP] - is this a digit character?
    chr - the character
    returns - the digit weight if character is a digit, nil otherwise

    char-code(chr) [SAL]
    (char-code
    chr) [LISP] - get the ascii code of a character
    chr - the character
    returns - the ascii character code (integer)

    code-char(code) [SAL]
    (code-char
    code) [LISP] - get the character with a specified ascii code
    code - the ascii code (integer)
    returns - the character with that code or nil

    char-upcase(chr) [SAL]
    (char-upcase
    chr) [LISP] - convert a character to upper case
    chr - the character
    returns - the upper case character

    char-downcase(chr) [SAL]
    (char-downcase
    chr) [LISP] - convert a character to lower case
    chr - the character
    returns - the lower case character

    digit-char(n) [SAL]
    (digit-char
    n) [LISP] - convert a digit weight to a digit
    n - the digit weight (integer)
    returns - the digit character or nil

    char-int(chr) [SAL]
    (char-int
    chr) [LISP] - convert a character to an integer
    chr - the character
    returns - the ascii character code

    int-char(int) [SAL]
    (int-char
    int) [LISP] - convert an integer to a character
    int - the ascii character code
    returns - the character with that code

    char<(chr1, chr2...) [SAL]
    (char<
    chr1 chr2...) [LISP]
    char<=(chr1, chr2...) [SAL]
    (char<=
    chr1 chr2...) [LISP]
    char=(chr1, chr2...) [SAL]
    (char=
    chr1 chr2...) [LISP]
    char/=(chr1, chr2...) [SAL]
    (char/=
    chr1 chr2...) [LISP]
    char>=(chr1, chr2...) [SAL]
    (char>=
    chr1 chr2...) [LISP]
    char>(chr1, chr2...) [SAL]
    (char>
    chr1 chr2...) [LISP]
    chr1 - the first character to compare
    chr2 - the second character(s) to compare
    returns - t if predicate is true, nil otherwise
    Note: case is significant with these comparison functions.

    char-lessp(chr1, chr2...) [SAL]
    (char-lessp
    chr1 chr2...) [LISP]
    char-not-greaterp(chr1, chr2...) [SAL]
    (char-not-greaterp
    chr1 chr2...) [LISP]
    char-equalp(chr1, chr2...) [SAL]
    (char-equalp
    chr1 chr2...) [LISP]
    char-not-equalp(chr1, chr2...) [SAL]
    (char-not-equalp
    chr1 chr2...) [LISP]
    char-not-lessp(chr1, chr2...) [SAL]
    (char-not-lessp
    chr1 chr2...) [LISP]
    char-greaterp(chr1, chr2...) [SAL]
    (char-greaterp
    chr1 chr2...) [LISP]
    chr1 - the first string to compare
    chr2 - the second string(s) to compare
    returns - t if predicate is true, nil otherwise
    Note: case is not significant with these comparison functions.

    Input/Output Functions

    read([stream[, eof[, rflag]]]) [SAL]
    (read
    [stream [eof [rflag]]]) [LISP] - read an expression
    stream - the input stream (default is standard input)
    eof - the value to return on end of file (default is nil)
    rflag - recursive read flag (default is nil)
    returns - the expression read

    (print expr [stream]) [LISP] - print an expression on a new line
    expr - the expression to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    prin1(expr[, stream]) [SAL]
    (prin1
    expr [stream]) [LISP] - print an expression
    expr - the expression to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    princ(expr[, stream]) [SAL]
    (princ
    expr [stream]) [LISP] - print an expression without quoting
    expr - the expressions to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    pprint(expr[, stream]) [SAL]
    (pprint
    expr [stream]) [LISP] - pretty print an expression
    expr - the expressions to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    terpri([stream]) [SAL]
    (terpri
    [stream]) [LISP] - terminate the current print line
    stream - the output stream (default is standard output)
    returns - nil

    flatsize(expr) [SAL]
    (flatsize
    expr) [LISP] - length of printed representation using prin1
    expr - the expression
    returns - the length

    flatc(expr) [SAL]
    (flatc
    expr) [LISP] - length of printed representation using princ
    expr - the expression
    returns - the length

    The Format Function

    format(stream, fmt, arg...) [SAL]
    (format
    stream fmt arg...) [LISP] - do formated output
    stream - the output stream
    fmt - the format string
    arg - the format arguments
    returns - output string if stream is nil, nil otherwise

    The format string can contain characters that should be copied directly to the output and formatting directives. The formatting directives are:
    ~A - print next argument using princ
    ~S - print next argument using prin1
    ~% - start a new line
    ~~ - print a tilde character
    ~<newline> - ignore this one newline and white space on the
    next line up to the first non-white-space character or newline. This
    allows strings to continue across multiple lines

    File I/O Functions

    Note that files are ordinarily opened as text. Binary files (such as standard midi files) must be opened with open-binary on non-unix systems.
    open(fname, direction: direction) [SAL]
    (open
    fname &key :direction) [LISP] - open a file stream
    fname - the file name string or symbol
    :direction - :input or :output (default is :input)
    returns - a stream

    open-binary(fname, direction: direction) [SAL]
    (open-binary
    fname &key :direction) [LISP] - open a binary file stream
    fname - the file name string or symbol
    :direction - :input or :output (default is :input)
    returns - a stream

    close(stream) [SAL]
    (close
    stream) [LISP] - close a file stream
    stream - the stream
    returns - nil

    setdir(path[, verbose]) [SAL]
    (setdir
    path [verbose]) [LISP] (Footnote 12) - set current directory
    path - the path of the new directory
    verbose - print error message if current directory cannot be changed to path
    returns - the resulting full path, e.g. (setdir ".") gets the current working directory, or nil if an error occurs

    listdir(path) [SAL]
    (listdir path) [LISP] (Footnote 13) - get a directory listing
    path - the path of the directory to be listed
    returns - list of filenames in the directory

    get-temp-path() [SAL]
    (get-temp-path) [LISP] (Footnote 14) - get a path where a temporary file can be created. Under Windows, this is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice c:\windows\.
    returns - the resulting full path as a string

    get-user() [SAL]
    (get-user) [LISP] (Footnote 15) - get the user ID. In Unix systems (including OS X and Linux), this is the value of the USER environment variable. In Windows, this is currently just "nyquist", which is also returned if the environment variable cannot be accessed. This function is used to avoid the case of two users creating files of the same name in the same temp directory.
    returns - the string naming the user

    find-in-xlisp-path(filename) [SAL]
    (find-in-xlisp-path filename) [LISP] (Footnote 16) - search the XLISP search path (e.g. XLISPPATH from the environment) for filename. If filename is not found as is, and there is no file extension, append ".lsp" to filename and search again. The current directory is not searched.
    filename - the name of the file to search for
    returns - a full path name to the first occurrence found

    read-char([stream]) [SAL]
    (read-char [stream]) [LISP] - read a character from a stream
    stream - the input stream (default is standard input)
    returns - the character

    peek-char([flag[, stream]]) [SAL]
    (peek-char
    [flag [stream]]) [LISP] - peek at the next character
    flag - flag for skipping white space (default is nil)
    stream - the input stream (default is standard input)
    returns - the character (integer)

    write-char(ch[, stream]) [SAL]
    (write-char
    ch [stream]) [LISP] - write a character to a stream
    ch - the character to write
    stream - the output stream (default is standard output)
    returns - the character

    read-int([stream[, length]]) [SAL]
    (read-int
    [stream [length]]) [LISP] - read a binary integer from a stream
    stream - the input stream (default is standard input)
    length - the length of the integer in bytes (default is 4)
    returns - the integer
    Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    write-int(ch[, stream[, length]]) [SAL]
    (write-int
    ch [stream [length]]) [LISP] - write a binary integer to a stream
    ch - the character to write
    stream - the output stream (default is standard output)
    length - the length of the integer in bytes (default is 4)
    returns - the integer
    Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    read-float([stream[, length]]) [SAL]
    (read-float
    [stream [length]]) [LISP] - read a binary floating-point number from a stream
    stream - the input stream (default is standard input)
    length - the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8)
    returns - the integer
    Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    write-float(ch[, stream[, length]]) [SAL]
    (write-float
    ch [stream [length]]) [LISP] - write a binary floating-point number to a stream
    ch - the character to write
    stream - the output stream (default is standard output)
    length - the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8)
    returns - the integer
    Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    read-line([stream]) [SAL]
    (read-line
    [stream]) [LISP] - read a line from a stream
    stream - the input stream (default is standard input)
    returns - the string

    read-byte([stream]) [SAL]
    (read-byte
    [stream]) [LISP] - read a byte from a stream
    stream - the input stream (default is standard input)
    returns - the byte (integer)

    write-byte(byte[, stream]) [SAL]
    (write-byte
    byte [stream]) [LISP] - write a byte to a stream
    byte - the byte to write (integer)
    stream - the output stream (default is standard output)
    returns - the byte (integer)

    String Stream Functions

    These functions operate on unnamed streams. An unnamed output stream collects characters sent to it when it is used as the destination of any output function. The functions get-output-stream-string and get-output-stream-list return a string or a list of characters.

    An unnamed input stream is setup with the make-string-input-stream function and returns each character of the string when it is used as the source of any input function.


    make-string-input-stream(str[, start[, end]]) [SAL]
    (make-string-input-stream
    str [start [end]]) [LISP]
    str - the string
    start - the starting offset
    end - the ending offset + 1
    returns - an unnamed stream that reads from the string

    make-string-output-stream)() [SAL]
    (make-string-output-stream) [LISP]
    returns - an unnamed output stream

    get-output-stream-string(stream) [SAL]
    (get-output-stream-string
    stream) [LISP]
    stream - the output stream
    returns - the output so far as a string
    Note: the output stream is emptied by this function

    get-output-stream-list(stream) [SAL]
    (get-output-stream-list
    stream) [LISP]
    stream - the output stream
    returns - the output so far as a list
    Note: the output stream is emptied by this function

    System Functions

    Note: the load function first tries to load a file from the current directory. A .lsp extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. (The Macintosh version has no search path.)

    get-env(name) [SAL]
    (get-env
    name) [LISP] - get from an environment variable
    name - the name of the environment variable
    returns - string value of the environment variable, nil if variable does not exist

    (load fname &key :verbose :print) [LISP] - load a source file
    fname - the filename string or symbol
    :verbose - the verbose flag (default is t)
    :print - the print flag (default is nil)
    returns - the filename

    save(fname) [SAL]
    (save
    fname) [LISP] - save workspace to a file
    fname - the filename string or symbol
    returns - t if workspace was written, nil otherwise

    restore(fname) [SAL]
    (restore
    fname) [LISP] - restore workspace from a file
    fname - the filename string or symbol
    returns - nil on failure, otherwise never returns

    dribble([fname]) [SAL]
    (dribble
    [fname]) [LISP] - create a file with a transcript of a session
    fname - file name string or symbol (if missing, close current transcript)
    returns - t if the transcript is opened, nil if it is closed

    gc() [SAL]
    (gc
    ) [LISP] - force garbage collection
    returns - nil

    expand(num) [SAL]
    (expand
    num) [LISP] - expand memory by adding segments
    num - the number of segments to add
    returns - the number of segments added

    alloc(num) [SAL]
    (alloc
    num) [LISP] - change number of nodes to allocate in each segment
    num - the number of nodes to allocate
    returns - the old number of nodes to allocate

    info() [SAL]
    (info
    ) [LISP] - show information about memory usage.
    returns - nil

    room() [SAL]
    (room
    ) [LISP] - show memory allocation statistics
    returns - nil

    type-of(expr) [SAL]
    (type-of
    expr) [LISP] - returns the type of the expression
    expr - the expression to return the type of
    returns - nil if the value is nil otherwise one of the symbols:
    SYMBOL - for symbols
    OBJECT - for objects
    CONS - for conses
    SUBR - for built-in functions
    FSUBR - for special forms
    CLOSURE - for defined functions
    STRING - for strings
    FIXNUM - for integers
    FLONUM - for floating point numbers
    CHARACTER - for characters
    FILE-STREAM - for file pointers
    UNNAMED-STREAM - for unnamed streams
    ARRAY - for arrays

    peek(addrs) [SAL]
    (peek
    addrs) [LISP] - peek at a location in memory
    addrs - the address to peek at (integer)
    returns - the value at the specified address (integer)

    poke(addrs, value) [SAL]
    (poke
    addrs value) [LISP] - poke a value into memory
    addrs - the address to poke (integer)
    value - the value to poke into the address (integer)
    returns - the value

    bigendianp() [SAL]
    (bigendianp
    ) [LISP] - is this a big-endian machine?
    returns - T if this a big-endian architecture, storing the high-order byte of an integer at the lowest byte address of the integer; otherwise, NIL. (Footnote 17)

    address-of(expr) [SAL]
    (address-of expr) [LISP] - get the address of an xlisp node
    expr - the node
    returns - the address of the node (integer)

    exit() [SAL]
    (exit
    ) [LISP] - exit xlisp
    returns - never returns

    setup-console() [SAL]
    (setup-console
    ) [LISP] - set default console attributes
    returns - NIL
    Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of "Nyquist." This is normally accomplished by calling setup-console in system.lsp. In Nyquist, you can avoid this behavior by setting *setup-console* to NIL in your init.lsp file. If setup-console is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.


    echoenabled(flag) [SAL]
    (echoenabled
    flag) [LISP] - turn console input echoing on or off
    flag - T to enable echo, NIL to disable
    returns - NIL
    Note: This function is only implemented under Linux and Mac OS X. If Nyquist I/O is redirected through pipes, the Windows version does not echo the input, but the Linux and Mac versions do. You can turn off echoing with this function. Under windows it is defined to do nothing.

    File I/O Functions

    Input from a File

    To open a file for input, use the open function with the keyword argument :direction set to :input. To open a file for output, use the open function with the keyword argument :direction set to :output. The open function takes a single required argument which is the name of the file to be opened. This name can be in the form of a string or a symbol. The open function returns an object of type FILE-STREAM if it succeeds in opening the specified file. It returns the value nil if it fails. In order to manipulate the file, it is necessary to save the value returned by the open function. This is usually done by assigning it to a variable with the setq special form or by binding it using let or let*. Here is an example:
    (setq fp (open "init.lsp" :direction :input))
    
    Evaluating this expression will result in the file init.lsp being opened. The file object that will be returned by the open function will be assigned to the variable fp.

    It is now possible to use the file for input. To read an expression from the file, just supply the value of the fp variable as the optional stream argument to read.

    (read fp)
    
    Evaluating this expression will result in reading the first expression from the file init.lsp. The expression will be returned as the result of the read function. More expressions can be read from the file using further calls to the read function. When there are no more expressions to read, the read function will return nil (or whatever value was supplied as the second argument to read).

    Once you are done reading from the file, you should close it. To close the file, use the following expression:

    (close fp)
    
    Evaluating this expression will cause the file to be closed.

    Output to a File

    Writing to a file is pretty much the same as reading from one. You need to open the file first. This time you should use the open function to indicate that you will do output to the file. For example:
    (setq fp (open "test.dat" :direction :output))
    
    Evaluating this expression will open the file test.dat for output. If the file already exists, its current contents will be discarded. If it doesn't already exist, it will be created. In any case, a FILE-STREAM object will be returned by the OPEN function. This file object will be assigned to the fp variable.

    It is now possible to write to this file by supplying the value of the fp variable as the optional stream parameter in the print function.

    (print "Hello there" fp)
    
    Evaluating this expression will result in the string "Hello there" being written to the file test.dat. More data can be written to the file using the same technique.

    Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file.

    (close fp)
    
    Evaluating this expression will close the output file and make it permanent.

    A Slightly More Complicated File Example

    This example shows how to open a file, read each Lisp expression from the file and print it. It demonstrates the use of files and the use of the optional stream argument to the read function.
    (do* ((fp (open "test.dat" :direction :input))
          (ex (read fp) (read fp)))
         ((null ex) nil)
      (print ex))
    


    Previous Section | Next Section (Index) | Table of Contents | Title Page nyquist-3.05/doc/part8.html0000644000175000000620000065315211537432671014701 0ustar stevestaffNyquist Functions Previous Section | Next Section | Table of Contents | Index | Title Page

    Nyquist Functions

    This chapter provides a language reference for Nyquist. Operations are categorized by functionality and abstraction level. Nyquist is implemented in two important levels: the "high level" supports behavioral abstraction, which means that operations like stretch and at can be applied. These functions are the ones that typical users are expected to use, and most of these functions are written in XLISP.

    The "low-level" primitives directly operate on sounds, but know nothing of environmental variables (such as *warp*, etc.). The names of most of these low-level functions start with "snd-". In general, programmers should avoid any function with the "snd-" prefix. Instead, use the "high-level" functions, which know about the environment and react appropriately. The names of high-level functions do not have prefixes like the low-level functions.

    There are certain low-level operations that apply directly to sounds (as opposed to behaviors) and are relatively "safe" for ordinary use. These are marked as such.

    Nyquist uses both linear frequency and equal-temperament pitch numbers to specify repetition rates. Frequency is always specified in either cycles per second (hz), or pitch numbers, also referred to as "steps," as in steps of the chromatic scale. Steps are floating point numbers such that 60 = Middle C, 61 = C#, 61.23 is C# plus 23 cents, etc. The mapping from pitch number to frequency is the standard exponential conversion, and fractional pitch numbers are allowed:

    frequency = 440 * 2^((pitch - 69)/12)
    There are many predefined pitch names. By default these are tuned in equal temperament, with A4 = 440Hz, but these may be changed. (See Section "Predefined Constants").

    Sounds

    A sound is a primitive data type in Nyquist. Sounds can be created, passed as parameters, garbage collected, printed, and set to variables just like strings, atoms, numbers, and other data types.

    What is a Sound?

    Sounds have 5 components: It may seem that there should be logical-start to indicate the logical or perceptual beginning of a sound as well as a logical-stop to indicate the logical ending of a sound. In practice, only logical-stop is needed; this attribute tells when the next sound should begin to form a sequence of sounds. In this respect, Nyquist sounds are asymmetric: it is possible to compute sequences forward in time by aligning the logical start of each sound with the logical-stop of the previous one, but one cannot compute "backwards", aligning the logical end of each sound with the logical start of its successor. The root of this asymmetry is the fact that when we invoke a behavior, we say when to start, and the result of the behavior tells us its logical duration. There is no way to invoke a behavior with a direct specification of when to stop (Footnote 1) .

    Note: there is no way to enforce the intended "perceptual" interpretation of logical-stop. As far as Nyquist is concerned, these are just numbers to guide the alignment of sounds within various control constructs.

    Multichannel Sounds

    Multichannel sounds are represented by Lisp arrays of sounds. To create an array of sounds the XLISP vector function is useful. Most low-level Nyquist functions (the ones starting with snd-) do not operate on multichannel sounds. Most high-level functions do operate on multichannel sounds.

    Accessing and Creating Sound

    Several functions display information concerning a sound and can be used to query the components of a sound. There are functions that access samples in a sound and functions that construct sounds from samples.

    sref(sound, time) [SAL]
    (sref sound time) [LISP]
    Accesses sound at the point time, which is a local time. If time does not correspond to a sample time, then the nearest samples are linearly interpolated to form the result. To access a particular sample, either convert the sound to an array (see snd-samples below), or use snd-srate and snd-t0 (see below) to find the sample rate and starting time, and compute a time (t) from the sample number (n):
    t = (n / srate) + t0
    Thus, the lisp code to access the n^(th) sample of a sound would look like: (sref sound (global-to-local (+ (/ n (snd-srate sound)) (snd-t0 sound)))) Here is why sref interprets its time argument as a local time:
    > (sref (ramp 1) 0.5) ; evaluate a ramp at time 0.5
    0.5
    > (at 2.0 (sref (ramp 1) 0.5)) ; ramp is shifted to start at 2.0
    		; the time, 0.5, is shifted to 2.5
    0.5
    
    If you were to use snd-sref, which treats time as global, instead of sref, which treats time as local, then the first example above would return the same answer (0.5), but the second example would return 0. Why? Because the (ramp 1) behavior would be shifted to start at time 2.0, but the resulting sound would be evaluated at global time 0.5. By definition, sounds have a value of zero before their start time.

    sref-inverse(sound, value) [SAL]
    (sref-inverse sound value) [LISP]
    Search sound for the first point at which it achieves value and return the corresponding (linearly interpolated) time. If no inverse exists, an error is raised. This function is used by Nyquist in the implementation of time warping.

    snd-from-array(t0, sr, array) [SAL]
    (snd-from-array t0 sr array) [LISP]
    Converts a lisp array of FLONUMs into a sound with starting time t0 and sample rate sr. Safe for ordinary use. Be aware that arrays of floating-point samples use 14 bytes per sample, and an additional 4 bytes per sample are allocated by this function to create a sound type.

    snd-fromarraystream(t0, sr, object) [SAL]
    (snd-fromarraystream t0 sr object) [LISP]
    Creates a sound for which samples come from object. The starting time is t0 (a FLONUM), and the sample rate is sr. The object is an XLISP object (see Section "Objects" for information on objects.) A sound is returned. When the sound needs samples, they are generated by sending the message :next to object. If object returns NIL, the sound terminates. Otherwise, object must return an array of FLONUMs. The values in these arrays are concatenated to form the samples of the resulting sound. There is no provision for object to specify the logical stop time of the sound, so the logical stop time is the termination time.

    snd-fromobject(t0, sr, object) [SAL]
    (snd-fromobject t0 sr object) [LISP]
    Creates a sound for which samples come from object. The starting time is t0 (a FLONUM), and the sample rate is sr. The object is an XLISP object (see Section "Objects" for information on objects. A sound is returned. When the sound needs samples, they are generated by sending the message :next to object. If object returns NIL, the sound terminates. Otherwise, object must return a FLONUM. There is no provision for object to specify the logical stop time of the sound, so the logical stop time is the termination time.

    snd-extent(sound, maxsamples) [SAL]
    (snd-extent sound maxsamples) [LISP]
    Returns a list of two numbers: the starting time of sound and the terminate time of sound. Finding the terminate time requires that samples be computed. Like most Nyquist functions, this is non-destructive, so memory will be allocated to preserve the sound samples. If the sound is very long or infinite, this may exhaust all memory, so the maxsamples parameter specifies a limit on how many samples to compute. If this limit is reached, the terminate time will be (incorrectly) based on the sound having maxsamples samples. This function is safe for ordinary use.

    snd-fetch(sound) [SAL]
    (snd-fetch sound) [LISP]
    Reads samples sequentially from sound. This returns a FLONUM after each call, or NIL when sound terminates. Note: snd-fetch modifies sound; it is strongly recommended to copy sound using snd-copy and access only the copy with snd-fetch.

    snd-fetch-array(sound, len, step) [SAL]
    (snd-fetch-array sound len step) [LISP]
    Reads sequential arrays of samples from sound, returning either an array of FLONUMs or NIL when the sound terminates. The len parameter, a FIXNUM, indicates how many samples should be returned in the result array. After the array is returned, sound is modified by skipping over step (a FIXNUM) samples. If step equals len, then every sample is returned once. If step is less than len, each returned array will overlap the previous one, so some samples will be returned more than once. If step is greater than len, then some samples will be skipped and not returned in any array. The step and len may change at each call, but in the current implementation, an internal buffer is allocated for sound on the first call, so subsequent calls may not specify a greater len than the first. When an array is returned, it will have len samples. If necessary, snd-fetch-array will read zeros beyond the end of the sound to fill the array. When this happens, *rslt* is set to a FIXNUM number of samples in the array that were read from the sound before the physical stop time of the sound. If all samples in the array are "valid" samples from the sound (coming from the sound before the sound terminates), *rslt* is set to NIL. The *rslt* variable is global and used to return extra results from other functions, so programs should not assume *rslt* is valid after subsequent function calls. Note: snd-fetch-array modifies sound; it is strongly recommended to copy sound using snd-copy and access only the copy with snd-fetch-array.

    snd-flatten(sound, maxlen) [SAL]
    (snd-flatten sound maxlen) [LISP]
    This function is identical to snd-length. You would use this function to force samples to be computed in memory. Normally, this is not a good thing to do, but here is one appropriate use: In the case of sounds intended for wavetables, the unevaluated sound may be larger than the evaluated (and typically short) one. Calling snd-flatten will compute the samples and allow the unit generators to be freed in the next garbage collection. Note: If a sound is computed from many instances of table-lookup oscillators, calling snd-flatten will free the oscillators and their tables. Calling (stats) will print how many total bytes have been allocated to tables.

    snd-length(sound, maxlen) [SAL]
    (snd-length sound maxlen) [LISP]
    Counts the number of samples in sound up to the physical stop time. If the sound has more than maxlen samples, maxlen is returned. Calling this function will cause all samples of the sound to be computed and saved in memory (about 4 bytes per sample). Otherwise, this function is safe for ordinary use.

    snd-maxsamp(sound) [SAL]
    (snd-maxsamp sound) [LISP]
    Computes the maximum of the absolute value of the samples in sound. Calling this function will cause samples to be computed and saved in memory. (This function should have a maxlen parameter to allow self-defense against sounds that would exhaust available memory.) Otherwise, this function is safe for ordinary use. This function will probably be removed in a future version. See peak, a replacement ("Signal Operations").

    snd-play(expression) [SAL]
    (snd-play expression) [LISP]
    Evaluates expression to obtain a sound or array of sounds, computes all of the samples (without retaining them in memory), and returns. Originally, this was a placeholder for a facility to play samples directly to an audio output device, but playback is now accomplished by s-save. Meanwhile, since this function does not save samples in memory or write them to a disk, it is useful in determining how much time is spent calculating samples. See s-save (Section "Sound File Input and Output") for saving samples to a file, and play (Section "Sound File Input and Output") to play a sound. This function is safe for ordinary use.

    snd-print-tree(sound) [SAL]
    (snd-print-tree sound) [LISP]
    Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. This function is safe for ordinary use.

    snd-samples(sound, limit) [SAL]
    (snd-samples sound limit) [LISP]
    Converts the samples into a lisp array. The data is taken directly from the samples, ignoring shifts. For example, if the sound starts at 3.0 seconds, the first sample will refer to time 3.0, not time 0.0. A maximum of limit samples is returned. This function is safe for ordinary use, but like snd-from-array, it requires a total of slightly over 18 bytes per sample.

    snd-srate(sound) [SAL]
    (snd-srate sound) [LISP]
    Returns the sample rate of the sound. Safe for ordinary use.

    snd-time(sound) [SAL]
    (snd-time sound) [LISP]
    Returns the start time of the sound. This will probably go away in a future version, so use snd-t0 instead.

    snd-t0(sound) [SAL]
    (snd-t0 sound) [LISP]
    Returns the time of the first sample of the sound. Note that Nyquist operators such as add always copy the sound and are allowed to shift the copy up to one half sample period in either direction to align the samples of two operands. Safe for ordinary use.

    snd-print(expression, maxlen) [SAL]
    (snd-print expression maxlen) [LISP]
    Evaluates expression to yield a sound or an array of sounds, then prints up to maxlen samples to the screen (stdout). This is similar to snd-save, but samples appear in text on the screen instead of in binary in a file. This function is intended for debugging. Safe for ordinary use.

    snd-set-logical-stop(sound, time) [SAL]
    (snd-set-logical-stop sound time) [LISP]
    Returns a sound which is sound, except that the logical stop of the sound occurs at time. Note: do not call this function. When defining a behavior, use set-logical-stop or set-logical-stop-abs instead.

    snd-sref(sound, time) [SAL]
    (snd-sref sound time) [LISP]
    Evaluates sound at the global time given by time. Safe for ordinary use, but normally, you should call sref instead.

    snd-stop-time(sound) [SAL]
    (snd-stop-time sound) [LISP]
    Returns the stop time of sound. Sounds can be "clipped" or truncated at a particular time. This function returns that time or MAX-STOP-TIME if he programmer has not specified a stop time for the sound. Safe for ordinary use.

    soundp(sound) [SAL]
    (soundp sound) [LISP]
    Returns true iff sound is a SOUND. Safe for ordinary use.

    stats() [SAL]
    (stats) [LISP]
    Prints the memory usage status. See also the XLISP mem function. Safe for ordinary use. This is the only way to find out how much memory is being used by table-lookup oscillator instances.

    Miscellaneous Functions

    These are all safe and recommended for ordinary use.

    db-to-linear(x) [SAL]
    (db-to-linear x) [LISP]
    Returns the conversion of x from decibels to linear. 0dB is converted to 1. 20dB represents a linear factor of 10. If x is a sound, each sample is converted and a sound is returned. If x is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. Note: With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Sample rates, start times, etc. are taken from x.

    follow(sound, floor, risetime, falltime, lookahead) [SAL]
    (follow sound floor risetime falltime lookahead) [LISP]
    An envelope follower intended as a commponent for compressor and limiter functions. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The floor is the minimum output value. The risetime is the time (in seconds) it takes for the output to rise (exponentially) from floor to unity (1.0) and the falltime is the time it takes for the output to fall (exponentially) from unity to floor. The algorithm looks ahead for peaks and will begin to increase the output signal according to risetime in anticipation of a peak. The amount of anticipation (in seconds) is given by lookahead. The algorithm is as follows: the output value is allowed to increase according to risetime or decrease according to falltime. If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to risetime to meet the new value. The algorithm will only work backward as far as lookahead. If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by falltime, the output fall rate will be limited by falltime, and the fall in output will stop when the output reaches floor. This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See snd-avg for a function that can help to generate a low-sample-rate input for follow. See snd-chase in Section "Filters" for a related filter.

    gate(sound, lookahead, risetime, falltime, floor, threshold) [SAL]
    (gate sound lookahead risetime falltime floor threshold) [LISP]
    Generate an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead (a FLONUM in seconds). (The signal begins to drop when the signal crosses threshold, not after lookahead.) Decay continues until the value reaches floor (a FLONUM), at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the ouptut value will rise to unity (1.0) at the point the signal crosses the threshold. Because of internal lookahead, the signal actually begins to rise before the signal crosses threshold. The rise is a constant-rate exponential and set so that a rise from floor to unity occurs in risetime. Similary, the fall is a constant-rate exponential such that a fall from unity to floor takes falltime.

    hz-to-step(freq) [SAL]
    (hz-to-step freq) [LISP]
    Returns a step number for freq (in hz), which can be either a number of a SOUND. The result has the same type as the argument. See also step-to-hz (below).

    linear-to-db(x) [SAL]
    (linear-to-db x) [LISP]
    Returns the conversion of x from linear to decibels. 1 is converted to 0. 0 is converted to -INF (a special IEEE floating point value.) A factor of 10 represents a 20dB change. If x is a sound, each sample is converted and a sound is returned. If x is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. Note: With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Start times, sample rates, etc. are taken from x.

    log(x) [SAL]
    (log x) [LISP]
    Calculates the natural log of x (a FLONUM). (See s-log for a version that operates on signals.)

    set-control-srate(rate) [SAL]
    (set-control-srate rate) [LISP]
    Sets the default sampling rate for control signals to rate by setting *default-control-srate* and reinitializing the environment. Do not call this within any synthesis function (see the control-srate-abs transformation, Section "Transformations").

    set-sound-srate(rate) [SAL]
    (set-sound-srate rate) [LISP]
    Sets the default sampling rate for audio signals to rate by setting *default-sound-srate* and reinitializing the environment. Do not call this within any synthesis function (see the sound-srate-abs transformation, Section "Transformations").

    set-pitch-names() [SAL]
    (set-pitch-names) [LIS]
    Initializes pitch variables (c0, cs0, df0, d0, ... b0, c1, ... b7). A440 (the default tuning) is represented by the step 69.0, so the variable a4 (fourth octave A) is set to 69.0. You can change the tuning by setting *A4-Hertz* to a value (in Hertz) and calling set-pitch-names to reinitialize the pitch variables. Note that this will result in non-integer step values. It does not alter the mapping from step values to frequency. There is no built-in provision for stretched scales or non-equal temperament, although users can write or compute any desired fractional step values.

    step-to-hz(pitch) [SAL]
    (step-to-hz pitch) [LISP]
    Returns a frequency in hz for pitch, a step number or a SOUND type representing a time-varying step number. The result is a FLONUM if pitch is a number, and a SOUND if pitch is a SOUND. See also hz-to-step (above).

    get-duration(dur) [SAL]
    (get-duration dur) [LISP]
    Gets the actual duration of of something starting at a local time of 0 and ending at a local time of dur times the current sustain. For convenience, *rslt* is set to the global time corresponding to local time zero.

    get-loud() [SAL]
    (get-loud) [LISP]
    Gets the current value of the *loud* environment variable. If *loud* is a signal, it is evaluated at local time 0 and a number (FLONUM) is returned.

    get-sustain() [SAL]
    (get-sustain) [LISP]
    Gets the current value of the *sustain* environment variable. If *sustain* is a signal, it is evaluated at local time 0 and a number (FLONUM) is returned.

    get-transpose() [SAL]
    (get-transpose) [LISP]
    Gets the current value of the *transpose* environment variable. If *transpose* is a signal, it is evaluated at local time 0 and a number (FLONUM) is returned.

    get-warp() [SAL]
    (get-warp) [LISP]
    Gets a function corresponding to the current value of the *warp* environment variable. For efficiency, *warp* is stored in three parts representing a shift, a scale factor, and a continuous warp function. Get-warp is used to retrieve a signal that maps logical time to real time. This signal combines the information of all three components of *warp* into a single signal. If the continuous warp function component is not present (indicating that the time warp is a simple combination of at and stretch transformations), an error is raised. This function is mainly for internal system use. In the future, get-warp will probably be reimplemented to always return a signal and never raise an error.

    LOCAL-to-global(local-time) [SAL]
    (local-to-global local-time) [LISP]
    Converts a score (local) time to a real (global) time according to the current environment.

    osc-enable(flag) [SAL]
    (osc-enable flag) [LISP]
    Enable or disable Open Sound Control. (See Appendix "Open Sound Control and Nyquist".) Enabling creates a socket and a service that listens for UDP packets on port 7770. Currently, only two messages are accepted by Nyquist. The first is of the form /slider with an integer index and a floating point value. These set internal slider values accessed by the snd-slider function. The second is of the form /wii/orientation with two floating point values. This message is a special case to support the DarwiinRemoteOsc program which can relay data from a Nintendo WiiMote device to Nyquist via OSC. The two orientation values control sliders 0 and 1. Disabling terminates the service (polling for messages) and closes the socket. The previous state of enablement is returned, e.g. if OSC is enabled and flag is nil, OSC is disabled and T (true) is returned because OSC was enabled at the time of the call. This function only exists if Nyquist is compiled with the compiler flag OSC. Otherwise, the function exists but always returns the symbol DISABLED. Consider lowering the audio latency using snd-set-latency. Warning: there is the potential for network-based attacks using OSC. It is tempting to add the ability to evaluate XLISP expressions sent via OSC, but this would create unlimited and unprotected access to OSC clients. For now, it is unlikely that an attacker could do more than manipulate slider values.

    snd-set-latency(latency) [SAL]
    (snd-set-latency latency) [LISP]
    Set the latency requested when Nyquist plays sound to latency, a FLONUM. The previous value is returned. The default is 0.3 seconds. To avoid glitches, the latency should be greater than the time required for garbage collection and message printing and any other system activity external to Nyquist.

    Behaviors

    Using Previously Created Sounds

    These behaviors take a sound and transform that sound according to the environment. These are useful when writing code to make a high-level function from a low-level function, or when cuing sounds which were previously created:
    cue(sound) [SAL]
    (cue sound) [LISP]
    Applies *loud*, the starting time from *warp*, *start*, and *stop* to sound.

    cue-file(filename) [SAL]
    (cue-file filename) [LISP]
    Same as cue, except the sound comes from the named file, samples from which are coerced to the current default *sound-srate* sample rate.

    sound(sound) [SAL]
    (sound sound) [LISP]
    Applies *loud*, *warp*, *start*, and *stop* to sound.

    control(sound) [SAL]
    (control sound) [LISP]
    This function is identical to sound, but by convention is used when sound is a control signal rather than an audio signal.

    Sound Synthesis

    These functions provide musically interesting creation behaviors that react to their environment; these are the "unit generators" of Nyquist:

    const(value [, duration]) [SAL]
    (const value [duration]) [LISP]
    Creates a constant function at the *control-srate*. Every sample has the given value, and the default duration is 1.0. See also s-rest, which is equivalent to calling const with zero, and note that you can pass scalar constants (numbers) to sim, sum, and mult where they are handled more efficiently than constant functions.

    env(t1, t2, t4, l1, l2, l3, [dur]) [SAL]
    (env t1 t2 t4 l1 l2 l3 dur) [LISP]
    Creates a 4-phase envelope. ti is the duration of phase i, and li is the final level of phase i. t3 is implied by the duration dur, and l4 is 0.0. If dur is not supplied, then 1.0 is assumed. The envelope duration is the product of dur, *stretch*, and *sustain*. If t1 + t2 + 2ms + t4 is greater than the envelope duration, then a two-phase envelope is substituted that has an attack/release time ratio of t1/t4. The sample rate of the returned sound is *control-srate*. (See pwl for a more general piece-wise linear function generator.) The effect of time warping is to warp the starting time and ending time. The intermediate breakpoints are then computed as described above.

    exp-dec(hold, halfdec, length) [SAL]
    (exp-dec hold halfdec length) [LISP]
    This convenient envelope shape is a special case of pwev (see Section "Piece-wise Approximations"). The envelope starts at 1 and is constant for hold seconds. It then decays with a half life of halfdec seconds until length. (The total duration is length.) In other words, the amplitude falls by half each halfdec seconds. When stretched, this envelope scales linearly, which means the hold time increases and the half decay time increases.

    force-srate(srate, sound) [SAL]
    (force-srate srate sound) [LISP]
    Returns a sound which is up- or down-sampled to srate. Interpolation is linear, and no prefiltering is applied in the down-sample case, so aliasing may occur. See also resample.

    lfo(freq [, duration, table, phase]) [SAL]
    (lfo freq duration table phase) [LISP]
    Just like osc (below) except this computes at the *control-srate* and frequency is specified in Hz. Phase is specified in degrees. The *transpose* and *sustain* is not applied. The effect of time warping is to warp the starting and ending times. The signal itself will have a constant unwarped frequency.

    fmlfo(freq [, table, phase]) [SAL]
    (fmlfo freq [table phase]) [LISP]
    A low-frequency oscillator that computes at the *control-srate* using a sound to specify a time-varying frequency in Hz. Phase is a FLONUM in degrees. The duration of the result is determined by freq.

    maketable(sound) [SAL]
    (maketable sound) [LISP]
    Assumes that the samples in sound constitute one period of a wavetable, and returns a wavetable suitable for use as the table argument to the osc function (see below). Currently, tables are limited to 1,000,000 samples. This limit is the compile-time constant max_table_len set in sound.h.

    build-harmonic(n, table-size) [SAL]
    (build-harmonic n table-size) [LISP]
    Intended for constructing wavetables, this function returns a sound of length table-size samples containing n periods of a sinusoid. These can be scaled and summed to form a waveform with the desired harmonic content. See "Waveforms" for an example.

    control-warp(warp-fn, signal, [wrate]) [SAL]
    (control-warp warp-fn signal wrate) [LISP]
    Applies a warp function warp-fn to signal using function composition. If wrate is omitted, linear interpolation is used. warp-fn is a mapping from score (logical) time to real time, and signal is a function from score time to real values. The result is a function from real time to real values at a sample rate of *control-srate*. See sound-warp for an explanation of wrate and high-quality warping.

    mult(beh1, beh2, ...) [SAL]
    (mult beh1 beh2 ...) [LISP]
    Returns the product of behaviors. The arguments may also be numbers, in which case simple multiplication is performed. If a number and sound are mixed, the scale function is used to scale the sound by the number. When sounds are multiplied, the resulting sample rate is the maximum sample rate of the factors.

    prod(beh1, beh2, ...) [SAL]
    (prod beh1 beh2 ...) [LISP]
    Same as mult.

    pan(sound, where) [SAL]
    (pan sound where) [LISP]
    Pans sound (a behavior) according to where (another behavior or a number). Sound must be monophonic. Where may be a monophonic sound (e.g. (ramp) or simply a number (e.g. 0.5). In either case, where should range from 0 to 1, where 0 means pan completely left, and 1 means pan completely right. For intermediate values, the sound to each channel is scaled linearly. Presently, pan does not check its arguments carefully.

    prod(beh1, beh2, ...) [SAL]
    (prod beh1 beh2 ...) [LISP]
    Same as mult.

    resample(sound, srate) [SAL]
    (resample sound srate) [LISP]
    Similar to force-srate, except high-quality interpolation is used to prefilter and reconstruct the signal at the new sample rate. Also, the result is scaled by 0.95 to reduce problems with clipping. (See also sound-warp.)

    scale(scale, sound) [SAL]
    (scale scale sound) [LISP]
    Scales the amplitude of sound by the factor scale. Identical function to snd-scale, except that it handles multichannel sounds. Sample rates, start times, etc. are taken from sound.

    scale-db(db, sound) [SAL]
    (scale-db db sound) [LISP]
    Scales the amplitude of sound by the factor db, expressed in decibels. Sample rates, start times, etc. are taken from sound.

    scale-srate(sound, scale) [SAL]
    (scale-srate sound scale) [LISP]
    Scales the sample rate of sound by scale factor. This has the effect of linearly shrinking or stretching time (the sound is not upsampled or downsampled). This is a special case of snd-xform (see Section "Signal Operations").

    shift-time(sound, shift) [SAL]
    (shift-time sound shift) [LISP]
    Shift sound by shift seconds. If the sound is f(t), then the result is f(t - shift). See Figure 5. This is a special case of snd-xform (see Section "Signal Operations").




    Figure 5: The shift-time function shifts a sound in time according to its shift argument.


    sound-warp(warp-fn, signal [, wrate]) [SAL]
    (sound-warp warp-fn signal [wrate]) [LISP]
    Applies a warp function warp-fn to signal using function composition. If the optional parameter wrate is omitted or NIL, linear interpolation is used. Otherwise, high-quality sample interpolation is used, and the result is scaled by 0.95 to reduce problems with clipping (interpolated samples can exceed the peak values of the input samples.) warp-fn is a mapping from score (logical) time to real time, and signal is a function from score time to real values. The result is a function from real time to real values at a sample rate of *sound-srate*. See also control-warp.

    If wrate is not NIL, it must be a number. The parameter indicates that high-quality resampling should be used and specifies the sample rate for the inverse of warp-fn. Use the lowest number you can. (See below for details.) Note that high-quality resampling is much slower than linear interpolation.

    To perform high-quality resampling by a fixed ratio, as opposed to a variable ratio allowed in sound-warp, use scale-srate to stretch or shrink the sound, and then resample to restore the original sample rate.

    Sound-warp and control-warp both take the inverse of warp-fn to get a function from real time to score time. Each sample of this inverse is thus a score time; signal is evaluated at each of these score times to yield a value, which is the desired result. The sample rate of the inverse warp function is somewhat arbitrary. With linear interpolation, the inverse warp function sample rate is taken to be the output sample rate. Note, however, that the samples of the inverse warp function are stored as 32-bit floats, so they have limited precision. Since these floats represent sample times, rounding can be a problem. Rounding in this case is equivalent to adding jitter to the sample times. Nyquist ignores this problem for ordinary warping, but for high-quality warping, the jitter cannot be ignored.

    The solution is to use a rather low sample rate for the inverse warp function. Sound-warp can then linearly interpolate this signal using double-precision floats to minimize jitter between samples. The sample rate is a compromise: a low sample rate minimizes jitter, while a high sample rate does a better job of capturing detail (e.g. rapid fluctuations) in the warp function. A good rule of thumb is to use at most 1,000 to 10,000 samples for the inverse warp function. For example, if the result will be 1 minute of sound, use a sample rate of 3000 samples / 60 seconds = 50 samples/second. Because Nyquist has no advance information about the warp function, the inverse warp function sample rate must be provided as a parameter. When in doubt, just try something and let your ears be the judge.

    integrate(signal) [SAL]
    (integrate signal) [LISP]
    Computes the integral of signal. The start time, sample rate, etc. are taken from signal.

    slope(signal) [SAL]
    (slope signal) [LISP]
    Computes the first derivative (slope) of signal. The start time, sample rate, etc. are taken from signal.

    Oscillators
    osc(pitch [, duration, table, phase]) [SAL]
    (osc pitch [duration table phase]) [LISP]
    Returns a sound which is the table oscillated at pitch for the given duration, starting with the phase (in degrees). Defaults are: duration 1.0 (second), table *table*, phase 0.0. The default value of *table* is a sinusoid. Duration is stretched by *warp* and *sustain*, amplitude is nominally 1, but scaled by *loudness*, the start time is logical time 0, transformed by *warp*, and the sample rate is *sound-srate*. The effect of time-warping is to warp the starting and ending times only; the signal has a constant unwarped frequency. Note 1: table is a list of the form
    (sound pitch-number periodic)
    where the first element is a sound, the second is the pitch of the sound (this is not redundant, because the sound may represent any number of periods), and the third element is T if the sound is one period of a periodic signal, or nil if the sound is a sample that should not be looped. The maximum table size is set by max_table_len in sound.h, and is currently set to 1,000,000. Note 2: in the current implementation, it is assumed that the output should be periodic. See snd-down and snd-up for resampling one-shot sounds to a desired sample rate. A future version of osc will handle both cases. Note 3: When osc is called, memory is allocated for the table, and samples are copied from the sound (the first element of the list which is the table parameter) to the memory. Every instance of osc has a private copy of the table, so the total storage can become large in some cases, for example in granular synthesis with many instances of osc. In some cases, it may make sense to use snd-flatten (see Section
    "Accessing and Creating Sound") to cause the sound to be fully realized, after which the osc and its table memory can be reclaimed by garbage collection. The partial function (see below) does not need a private table and does not use much space.

    partial(pitch, env) [SAL]
    (partial pitch env) [LISP]
    Returns a sinusoid at the indicated pitch; the sound is multiplied by env. The start time and duration are taken from env, which is of course subject to transformations. The sample rate is *sound-srate*. The partial function is faster than osc.

    sine(pitch [, duration]) [SAL]
    (sine pitch [duration]) [LISP]
    Returns a sinusoid at the indicated pitch. The sample rate is *sound-srate*. This function is like osc with respect to transformations. The sine function is faster than osc.

    hzosc(hz [, table, phase]) [SAL]
    (hzosc hz [table phase]) [LISP]
    Returns a sound which is the table oscillated at hz starting at phase degrees. The default table is *table* and the default phase is 0.0. The default duration is 1.0, but this is stretched as in osc (see above). The hz parameter may be a SOUND, in which case the duration of the result is the duration of hz. The sample rate is *sound-srate*.

    osc-saw(hz) [SAL]
    (osc-saw hz) [LISP]
    Returns a sawtooth waveshape at the indicated frequency (in Hertz). The sample rate is *sound-srate*. The hz parameter may be a sound as in hzosc (see above).

    osc-tri(hz) [SAL]
    (osc-tri hz) [LISP]
    Returns a triangle waveshape at the indicated frequency (in Hertz). The sample rate is *sound-srate*. The hz parameter may be a sound as in hzosc (see above).

    osc-pulse(hz, bias [, compare-shape]) [SAL]
    (osc-pulse hz bias [compare-shape]) [LISP]
    Returns a square pulse with variable width at the indicated frequency (in Hertz). The bias parameter controls the pulse width and should be between -1 and +1, giving a pulse width from 0% (always at -1) to 100% (always at +1). When bias is zero, a square wave is generated. Bias may be a SOUND to create varying pulse width. If bias changes rapidly, strange effects may occur. The optional compare-shape defaults to a hard step at zero, but other shapes may be used to achieve non-square pulses. The osc-pulse behavior is written in terms of other behaviors and defined in the file nyquist.lsp using just a few lines of code. Read the code for the complete story.

    amosc(pitch, modulation [, table, phase]) [SAL]
    (amosc pitch modulation [table phase]) [LISP]
    Returns a sound which is table oscillated at pitch. The output is multiplied by modulation for the duration of the sound modulation. osc-table defaults to *table*, and phase is the starting phase (default 0.0 degrees) within osc-table. The sample rate is *sound-srate*.

    fmosc(pitch, modulation [, table, phase]) [SAL]
    (fmosc pitch modulation [table phase]) [LISP]
    Returns a sound which is table oscillated at pitch plus modulation for the duration of the sound modulation. osc-table defaults to *table*, and phase is the starting phase (default 0.0 degrees) within osc-table. The modulation is expressed in hz, e.g. a sinusoid modulation signal with an amplitude of 1.0 (2.0 peak to peak), will cause a +/- 1.0 hz frequency deviation in sound. Negative frequencies are correctly handled. The sample rate is *sound-srate*.

    fmfb(pitch, index [, dur]) [SAL]
    (fmfb pitch index [dur]) [LISP]
    Returns a sound generated by feedback FM synthesis. The pitch parameter (given in the usual half-step units) controls the fundamental frequency. The index is the amount of feedback, which may be a SOUND or a FLONUM. If index is a FLONUM, dur must be provided (a FLONUM) to specify the duration. Otherwise, dur is ignored if present and the duration is determined by that of index. The sample rate is *sound-srate*. A sinusoid table is used. If index is below 1.1, this generates a sawtooth-like waveform.

    buzz(n, pitch, modulation) [SAL]
    (buzz n pitch modulation) [LISP]
    Returns a sound with n harmonics of equal amplitude and a total amplitude of 1.0, using a well-known function of two cosines. If n (an integer) is less than 1, it is set to 1. Aliasing will occur if n is too large. The duration is determined by the duration of the sound modulation, which is a frequency modulation term expressed in Hz (see Section "Oscillators"). Negative frequencies are correctly handled. The sample rate is *sound-srate*.

    pluck(pitch [, duration, final-amplitude]) [SAL]
    (pluck pitch [duration final-amplitude]) [LISP]
    Returns a sound at the given pitch created using a modified Karplus-Strong plucked string algorithm. The tone decays from an amplitude of about 1.0 to about final-amplitude in duration seconds. The default values are to decay to 0.001 (-60dB) in 1 second. The sample rate is *sound-srate*.

    siosc(pitch, modulation, tables) [SAL]
    (siosc pitch modulation tables) [LISP]
    Returns a sound constructed by interpolating through a succession of periodic waveforms. The frequency is given (in half steps) by pitch to which a modulation signal (in hz) is added, exactly as in fmosc. The tables specify a list of waveforms as follows: (table0 time1 table2 ... timeN tableN), where each table is a sound representing one period. Each time is a time interval measured from the starting time. The time is scaled by the nominal duration (computed using (local-to-global (get-sustain))) to get the actual time. Note that this implies linear stretching rather than continuous timewarping of the interpolation or the breakpoints. The waveform is table0 at the starting time, table1 after time1 (scaled as described), and so on. The duration and logical stop time is given by modulation. If modulation is shorter than timeN, then the full sequence of waveforms is not used. If modulation is longer than timeN, tableN is used after timeN without further interpolation.

    sampler(pitch, modulation [, sample, npoints]) [SAL]
    (sampler pitch modulation [sample npoints]) [LISP]
    Returns a sound constructed by reading a sample from beginning to end and then splicing on copies of the same sound from a loop point to the end. The pitch and modulation parameters are used as in fmosc described above. The optional sample (which defaults to the global variable *table* is a list of the form
    (sound pitch-number loop-start)
    where the first element is a sound containing the sample, the second is the pitch of the sample, and the third element is the time of the loop point. If the loop point is not in the bounds of the sound, it is set to zero. The optional npoints specifies how many points should be used for sample interpolation. Currently this parameter defaults to 2 and only 2-point (linear) interpolation is implemented. It is an error to modulate such that the frequency is negative. Note also that the loop point may be fractional. The sample rate is *sound-srate*.

    Piece-wise Approximations
    There are a number of related behaviors for piece-wise approximations to functions. The simplest of these, pwl was mentioned earlier in the manual. It takes a list of breakpoints, assuming an initial point at (0, 0), and a final value of 0. An analogous piece-wise exponential function, pwe, is provided. Its implicit starting and stopping values are 1 rather than 0. Each of these has variants. You can specify the initial and final values (instead of taking the default). You can specify time in intervals rather than cummulative time. Finally, you can pass a list rather than an argument list. This leads to 16 versions:
    Piece-wise Linear Functions:
    	Cummulative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwl
    			pwl-list
    		Explicit initial value:
    			pwlv
    			pwlv-list
    	Relative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwlr
    			pwlr-list
    		Explicit initial value:
    			pwlvr
    			pwlvr-list
    

    Piece-wise Exponential Functions: Cummulative Time: Default initial point at (0, 1), final value at 1: pwe pwe-list Explicit initial value: pwev pwev-list Relative Time: Default initial point at (0, 1), final value at 1: pwer pwer-list Explicit initial value: pwevr pwevr-list

    All of these functions are implemented in terms of pwl (see nyquist.lsp for the implementations. There are infinite opportunities for errors in these functions: if you leave off a data point, try to specify points in reverse order, try to create an exponential that goes to zero or negative values, or many other bad things, the behavior is not well-defined. Nyquist should not crash, but Nyquist does not necessarily attempt to report errors at this time.

    pwl(t1, l1, t2, l2, ... tn) [SAL]
    (pwl t1 l1 t2 l2 ... tn) [LISP]
    Creates a piece-wise linear envelope with breakpoints at (0, 0), (t1, l1), (t2, l2), ... (tn, 0). The breakpoint times are scaled linearly by the value of *sustain* (if *sustain* is a SOUND, it is evaluated once at the starting time of the envelope). Each breakpoint time is then mapped according to *warp*. The result is a linear interpolation (unwarped) between the breakpoints. The sample rate is *control-srate*. Breakpoint times are quantized to the nearest sample time. If you specify one or more breakpoints withing one sample period, pwl attempts to give a good approximation to the specified function. In particular, if two breakpoints are simultaneous, pwl will move one of them to an adjacent sample, producing a steepest possible step in the signal. The exact details of this "breakpoint munging" is subject to change in future versions. Please report any cases where breakpoint lists give unexpected behaviors. The author will try to apply the "principle of least surprise" to the design. Note that the times are relative to 0; they are not durations of each envelope segment.

    pwl-list(breakpoints) [SAL]
    (pwl-list breakpoints) [LISP]
    If you have a list of breakpoints, you can use apply to apply the pwl function to the breakpoints, but if the list is very long (hundreds or thousands of points), you might get a stack overflow because XLISP has a fixed-size argument stack. Instead, call pwl-list, passing one argument, the list of breakpoints.

    pwlv(l1, t2, l2, t3, t3, ... tn, ln) [SAL]
    (pwlv l1 t2 l2 t3 t3 ... tn ln) [LISP]
    Creates a piece-wise linear envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln. Otherwise, the behavior is like that of pwl.

    pwlv-list(breakpoints) [SAL]
    (pwlv-list breakpoints) [LISP]
    A version of pwlv that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.

    pwlr(i1, l1, i2, l2, ... in) [SAL]
    (pwlr i1 l1 i2 l2 ... in) [LISP]
    Creates a piece-wise linear envelope with breakpoints at (0, 0), (t1, l1), (t2, l2), ... (tn, 0), where tj is the sum of i1 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwl.

    pwlr-list(breakpoints) [SAL]
    (pwlr-list breakpoints) [LISP]
    A version of pwlr that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.

    pwlvr(l1, i2, l2, i3, i3, ... in, ln) [SAL]
    (pwlvr l1 i2 l2 i3 i3 ... in ln) [LISP]
    Creates a piece-wise linear envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln, where tj is the sum of i2 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwlv.

    pwlvr-list(breakpoints) [SAL]
    (pwlvr-list breakpoints) [LISP]
    A version of pwlvr that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.

    pwe(t1, l1, t2, l2, ... tn) [SAL]
    (pwe t1 l1 t2 l2 ... tn) [LISP]
    Creates a piece-wise exponential envelope with breakpoints at (0, 1), (t1, l1), (t2, l2), ... (tn, 1). Exponential segments means that the ratio of values from sample to sample is constant within the segment. (The current implementation actually takes the log of each value, computes a piece-wise exponential from the points using pwl, then exponentiates each resulting sample. A faster implementation is certainly possible!) Breakpoint values (lj) must be greater than zero. Otherwise, this function is similar to pwl, including stretch by *sustain*, mapping according to *warp*, sample rate based on *control-srate*, and "breakpoint munging" (see pwl described above). Default initial and final values are of dubious value with exponentials. See pwev below for the function you are probably looking for.

    pwe-list(breakpoints) [SAL]
    (pwe-list breakpoints) [LISP]
    A version of pwe that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.

    pwev(l1, t2, l2, t3, t3, ... tn, ln) [SAL]
    (pwev l1 t2 l2 t3 t3 ... tn ln) [LISP]
    Creates a piece-wise exponential envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln). Otherwise, the behavior is like that of pwe.

    pwev-list(breakpoints) [SAL]
    (pwev-list breakpoints) [LISP]
    A version of pwev that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.

    pwer(i1, l1, i2, l2, ... in) [SAL]
    (pwer i1 l1 i2 l2 ... in) [LISP]
    Creates a piece-wise exponential envelope with breakpoints at (0, 1), (t1, l1), (t2, l2), ... (tn, 1), where tj is the sum of i1 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwe. Consider using pwerv instead of this one.

    pwer-list(breakpoints) [SAL]
    (pwer-list breakpoints) [LISP]
    A version of pwer that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.

    pwevr(l1, i2, l2, i3, i3, ... in, ln) [SAL]
    (pwevr l1 i2 l2 i3 i3 ... in ln) [LISP]
    Creates a piece-wise exponential envelope with breakpoints at (0, l1), (t2, l2), etc., ending with (tn, ln, where tj is the sum of i2 through ij. In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of pwev. Note that this is similar to the csound GEN05 generator. Which is uglier, GEN05 or pwevr?

    pwevr-list(breakpoints) [SAL]
    (pwevr-list breakpoints) [LISP]
    A version of pwevr that takes a single list of breakpoints as its argument. See pwl-list above for the rationale.
    Filter Behaviors
    alpass(sound, decay, hz [, minhz]) [SAL]
    (alpass sound decay hz [minhz]) [LISP]
    Applies an all-pass filter to sound. This all-pass filter creates a delay effect without the resonances of a comb filter. The decay time of the filter is given by decay. The hz parameter must be a number or sound greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The decay may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert decay into the feedback parameter, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide decay at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of sound. If hz is of type SOUND, the delay may be time-varying. Linear interpolation is then used for fractional sample delay, but it should be noted that linear interpolation implies a low-pass transfer function. Thus, this filter may behave differently with a constant SOUND than it does with a FLONUM value for hz. In addition, if hz is of type SOUND, then minhz is required. The hz parameter will be clipped to be greater than minhz, placing an upper bound on the delay buffer length.

    comb(sound, decay, hz) [SAL]
    (comb sound decay hz) [LISP]
    Applies a comb filter to sound. A comb filter emphasizes (resonates at) frequencies that are multiples of a hz. The decay time of the resonance is given by decay. This is a variation on feedback-delay (see below). The hz parameter must be a number greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The decay may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert decay into the feedback parameter for feedback-delay, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide decay at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of sound.

    congen(gate, risetime, falltime) [SAL]
    (congen gate risetime falltime) [LISP]
    Implements an analog synthesizer-style contour generator. The input gate normally goes from 0.0 to 1.0 to create an attack and from 1.0 to 0.0 to start a release. During the attack (output is increasing), the output converges half-way to gate in risetime (a FLONUM) seconds. During the decay, the half-time is falltime seconds. The sample rate, start time, logical stop, and terminate time all come from gate. If you want a nice decay, be sure that the gate goes to zero and stays there for awhile before gate terminates, because congen (and all Nyquist sounds) go immediately to zero at termination time. For example, you can use pwl to build a pulse followed by some zero time:
    (pwl 0 1 duty 1 duty 0 1)
    
    Assuming duty is less than 1.0, this will be a pulse of duration duty followed by zero for a total duration of 1.0.
    (congen (pwl 0 1 duty 1 duty 0 1) 0.01 0.05)
    
    will have a duration of 1.0 because that is the termination time of the pwl input. The decaying release of the resulting envelope will be truncated to zero at time 1.0. (Since the decay is theoretically infinite, there is no way to avoid truncation, although you could multiply by another envelope that smoothly truncates to zero in the last millisecond or two to get both an exponential decay and a smooth final transition to zero.)

    convolve(sound, response) [SAL]
    (convolve sound response) [LISP]
    Convolves two signals. The first can be any length, but the computation time per sample and the total space required are proportional to the length of response.

    feedback-delay(sound, delay, feedback) [SAL]
    (feedback-delay sound delay feedback) [LISP]
    Applies feedback delay to sound. The delay must be a number (in seconds). It is rounded to the nearest sample to determine the length of the delay. The sample rate is the maximum from sound and feedback (if feedback is also a sound). The amound of feedback should be less than one to avoid an exponential increase in amplitude. The start time and stop time, and logical stop time are taken from sound. Since output is truncated at the stop time of sound, you may want to append some silence to sound to give the filter time to decay.

    lp(sound, cutoff) [SAL]
    (lp sound cutoff) [LISP]
    Filters sound using a first-order Butterworth low-pass filter. Cutoff may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of cutoff. The resulting sample rate, start time, etc. are taken from sound.

    tone(sound, cutoff) [SAL]
    (tone sound cutoff) [LISP]
    No longer defined; use lp instead, or define it by adding (setfn tone lp) to your program.

    hp(sound, cutoff) [SAL]
    (hp sound cutoff) [LISP]
    Filters sound using a first-order Butterworth high-pass filter. Cutoff may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of cutoff. This filter is an exact complement of lp.

    atone(sound, cutoff) [SAL]
    (atone sound cutoff) [LISP]
    No longer defined; use hp instead, or define it by adding (setfn atone hp) to your program.

    reson(sound, center, bandwidth, n) [SAL]
    (reson sound center bandwidth n) [LISP]
    Apply a resonating filter to sound with center frequency center (in hertz), which may be a float or a signal. Bandwidth is the filter bandwidth (in hertz), which may also be a signal. Filter coefficients (requiring trig functions) are recomputed at each new sample of either center or bandwidth, and coefficients are not interpolated. The last parameter n specifies the type of normalization as in Csound: A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than hz are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The resulting sample rate, start time, etc. are taken from sound.

    One application of reson is to simulate resonances in the human vocal tract. See demos/voice_synthesis.htm for sample code and documentation.

    areson(sound, center, bandwidth, n) [SAL]
    (areson sound center bandwidth n) [LISP]
    The areson filter is an exact complement of reson such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal.

    shape(signal, table, origin) [SAL]
    (shape signal table origin) [LISP]
    A waveshaping function. Use table as a function; apply the function to each sample of signal to yield a new sound. Signal should range from -1 to +1. Anything beyond these bounds is clipped. Table is also a sound, but it is converted into a lookup table (similar to table-lookup oscillators). The origin is a FLONUM and gives the time which should be considered the origin of table. (This is important because table cannot have values at negative times, but signal will often have negative values. The origin gives an offset so that you can produce suitable tables.) The output at time t is:
    table(origin + clip(signal(t))
    where clip(x) = max(1, min(-1, x)). (E.g. if table is a signal defined over the interval [0, 2], then origin should be 1.0. The value of table at time 1.0 will be output when the input signal is zero.) The output has the same start time, sample rate, etc. as signal. The shape function will also accept multichannel signals and tables.

    Further discussion and examples can be found in demos/distortion.htm. The shape function is also used to map frequency to amplitude to achieve a spectral envelope for Shepard tones in demos/shepard.lsp.

    biquad(signal, b0, b1, b2, a0, a1, a2) [SAL]
    (biquad signal b0 b1 b2 a0 a1 a2) [LISP]
    A fixed-parameter biquad filter. All filter coefficients are FLONUMs. See also lowpass2, highpass2, bandpass2, notch2, allpass2, eq-lowshelf, eq-highshelf, eq-band, lowpass4, lowpass6, highpass4, and highpass8 in this section for convenient variations based on the same filter. The equations for the filter are: zn = sn + a1 * zn-1 + a2 * zn-2, and yn = zn * b0 + zn-1 * b1 + zn-2 * b2.

    biquad-m(signal, b0, b1, b2, a0, a1, a2) [SAL]
    (biquad-m signal b0 b1 b2 a0 a1 a2) [LISP]
    A fixed-parameter biquad filter with Matlab sign conventions for a0, a1, and a2. All filter coefficients are FLONUMs.

    lowpass2(signal, hz [, q]) [SAL]
    (lowpass2 signal hz [q]) [LISP]
    A fixed-parameter, second-order lowpass filter based on snd-biquad. The cutoff frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM).

    highpass2(signal, hz [, q]) [SAL]
    (highpass2 signal hz [q]) [LISP]
    A fixed-parameter, second-order highpass filter based on snd-biquad. The cutoff frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM).

    bandpass2(signal, hz [, q]) [SAL]
    (bandpass2 signal hz [q]) [LISP]
    A fixed-parameter, second-order bandpass filter based on snd-biquad. The center frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM).

    notch2(signal, hz [, q]) [SAL]
    (notch2 signal hz [q]) [LISP]
    A fixed-parameter, second-order notch filter based on snd-biquad. The center frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM).

    allpass2(signal, hz [, q]) [SAL]
    (allpass2 signal hz [q]) [LISP]
    A fixed-parameter, second-order allpass filter based on snd-biquad. The frequency is given by hz (a FLONUM) and an optional Q factor is given by q (a FLONUM).

    eq-lowshelf(signal, hz, gain [, slope]) [SAL]
    (eq-lowshelf signal hz gain [slope]) [LISP]
    A fixed-parameter, second-order bass shelving equalization (EQ) filter based on snd-biquad. The hz parameter (a FLONUM)is the halfway point in the transition, and gain (a FLONUM) is the bass boost (or cut) in dB. The optional slope (a FLONUM) is 1.0 by default, and response becomes peaky at values greater than 1.0.

    eq-highshelf(signal, hz, gain [, slope]) [SAL]
    (eq-highshelf signal hz gain [slope]) [LISP]
    A fixed-parameter, second-order treble shelving equalization (EQ) filter based on snd-biquad. The hz parameter (a FLONUM)is the halfway point in the transition, and gain (a FLONUM) is the treble boost (or cut) in dB. The optional slope (a FLONUM) is 1.0 by default, and response becomes peaky at values greater than 1.0.

    eq-band(signal, hz, gain, width) [SAL]
    (eq-band signal hz gain width) [LISP]
    A fixed- or variable-parameter, second-order midrange equalization (EQ) filter based on snd-biquad, snd-eqbandcv and snd-eqbandvvv. The hz parameter (a FLONUM) is the center frequency, gain (a FLONUM) is the boost (or cut) in dB, and width (a FLONUM) is the half-gain width in octaves. Alternatively, hz, gain, and width may be SOUNDs, but they must all have the same sample rate, e.g. they should all run at the control rate or at the sample rate.

    lowpass4(signal, hz) [SAL]
    (lowpass4 signal hz) [LISP]
    A four-pole Butterworth lowpass filter. The cutoff frequency is hz (a FLONUM).

    lowpass6(signal, hz) [SAL]
    (lowpass6 signal hz) [LISP]
    A six-pole Butterworth lowpass filter. The cutoff frequency is hz (a FLONUM).

    lowpass8(signal, hz) [SAL]
    (lowpass8 signal hz) [LISP]
    An eight-pole Butterworth lowpass filter. The cutoff frequency is hz (a FLONUM).

    highpass4(signal, hz) [SAL]
    (highpass4 signal hz) [LISP]
    A four-pole Butterworth highpass filter. The cutoff frequency is hz (a FLONUM).

    highpass6(signal, hz) [SAL]
    (highpass6 signal hz) [LISP]
    A six-pole Butterworth highpass filter. The cutoff frequency is hz (a FLONUM).

    highpass8(signal, hz) [SAL]
    (highpass8 signal hz) [LISP]
    An eight-pole Butterworth highpass filter. The cutoff frequency is hz (a FLONUM).

    tapv(sound, offset, vardelay, maxdelay) [SAL]
    (tapv sound offset vardelay maxdelay) [LISP]
    A delay line with a variable position tap. Identical to snd-tapv. See it for details ("Signal Operations").

    Effects
    nrev(sound, decay, mix) [SAL]
    (nrev sound decay mix) [LISP]

    jcrev(sound, decay, mix) [SAL]
    (jcrev sound decay mix) [LISP]

    prcrev(sound, decay, mix) [SAL]
    (prcrev sound decay mix) [LISP] These reverbs (nrev, jcrev, and prcrev) are implemented in STK (running within Nyquist). nrev derives from Common Music's NRev, which consists of 6 comb filters followed by 3 allpass filters, a lowpass filter, and another allpass in series followed by two allpass filters in parallel. jcrev is the John Chowning reverberator which is based on the use of networks of simple allpass and comb delay filters. This reverb implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. prcrev is a Perry Cook's reverberator which is based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This one implements two series allpass units and two parallel comb filters. The sound input may be single or multi-channel. The decay time is in seconds, and mix sets the mixture of input sound reverb sound, where 0.0 means input only (dry) and 1.0 means reverb only (wet).

    stkchorus(sound, depth, freq, mix [, delay]) [SAL]
    (stkchorus sound depth freq mix [delay]) [LISP]
    Chorus implemented in STK. The input sound can be single or multi-channel. The FLONUM parameters depth and freq set the modulation depth from 0 to 1 and modulation frequency (in Hz), and mix sets the mixture of input sound and chorused sound, where 0.0 means input sound only (dry) and 1.0 means chorused sound only (wet). The parameter delay is a FIXNUM representing the median desired delay length in samples.

    pitshift(sound, shift, mix) [SAL]
    (pitshift sound shift mix) [LISP]
    A pitch shifter implemented in STK. The input sound, a single-channel or multi-channel SOUND is pitch-shifted by shift, a FLONUM ratio. A value of 1.0 means no shift. The parameter mix sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet).

    Physical Models
    clarinet(step, breath-env) [SAL]
    (clarinet step breath-env) [LISP]
    A physical model of a clarinet from STK. The step parameter is a FLONUM that controls the tube length, and the breath-env (a SOUND) controls the air pressure and also determines the length of the resulting sound. The breath-env signal should range from zero to one.

    clarinet-freq(step, breath-env, freq-env) [SAL]
    (clarinet-freq step breath-env freq-env) [LISP]
    A variation of clarinet that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrarily set to 30.

    clarinet-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, reed-stiffness, noise) [SAL]
    (clarinet-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise) [LISP]
    A variation of clarinet-freq that includes controls vibrato-freq (a FLONUM for vibrato frequency in Hertz), vibrato-gain (a FLONUM for the amount of amplitude vibrato), reed-stiffness (a FLONUM or SOUND controlling reed stiffness in the clarinet model), and noise (a FLONUM or SOUND controlling noise amplitude in the input air pressure). The vibrato-gain is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The reed-stiffness parameter varies from zero to one. The duration of the resulting sound is the minimum duration of breath-env, freq-env, reed-stiffness, and noise. As with clarinet-freq, these parameters may be either FLONUMs or SOUNDs, and FLONUMs are coerced to sounds with a nominal duration of 30.

    sax(step, breath-env) [SAL]
    (sax step breath-env) [LISP]
    A physical model of a sax from STK. The step parameter is a FLONUM that controls the tube length, and the breath-env controls the air pressure and also determines the length of the resulting sound. The breath-env signal should range from zero to one.

    sax-freq(step, breath-env, freq-env) [SAL]
    (sax-freq step breath-env freq-env) [LISP]
    A variation of sax that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrarily set to 30.

    sax-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, reed-stiffness, noise, blow-pos, reed-table-offset) [SAL]
    (sax-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise blow-pos reed-table-offset) [LISP]
    A variation of sax-freq that includes controls vibrato-freq (a FLONUM for vibrato frequency in Hertz), vibrato-gain (a FLONUM for the amount of amplitude vibrato), reed-stiffness (a SOUND controlling reed stiffness in the sax model), noise (a SOUND controlling noise amplitude in the input air pressure), blow-pos (a SOUND controlling the point of excitation of the air column), and reed-table-offset (a SOUND controlling a parameter of the reed model). The vibrato-gain is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The reed-stiffness, blow-pos, and reed-table-offset parameters all vary from zero to one. The duration of the resulting sound is the minimum duration of breath-env, freq-env, reed-stiffness, noise, breath-env, blow-pos, and reed-table-offset. As with sax-freq, these parameters may be either FLONUMs or SOUNDs, and FLONUMs are coerced to sounds with a nominal duration of 30.

    flute(step, breath-env) [SAL]
    (flute step breath-env) [LISP]
    A physical model of a flute from STK. The step parameter is a FLONUM that controls the tube length, and the breath-env controls the air pressure and also determines the starting time and length of the resulting sound. The breath-env signal should range from zero to one.

    flute-freq(step, breath-env, freq-env) [SAL]
    (flute-freq step breath-env freq-env) [LISP]
    A variation of flute that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of breath-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrary set to 30.

    flute-all(step, breath-env, freq-env, vibrato-freq, vibrato-gain, jet-delay, noise) [SAL]
    (flute-all step breath-env freq-env vibrato-freq vibrato-gain jet-delay noise) [LISP]
    A variation of clarinet-freq that includes controls vibrato-freq (a FLONUM for vibrato frequency in Hz), vibrato-gain (a FLONUM for the amount of amplitude vibrato), jet-delay (a FLONUM or SOUND controlling jet delay in the flute model), and noise (a FLONUM or SOUND controlling noise amplitude in the input air pressure). The vibrato-gain is a number from zero to one where zero means no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the noise parameter ranges from zero to one, where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the breath-env. The jet-delay is a ratio that controls a delay length from the flute model, and therefore it changes the pitch of the resulting sound. A value of 0.5 will maintain the pitch indicated by the step parameter. The duration of the resulting sound is the minimum duration of breath-env, freq-env, jet-delay, and noise. These parameters may be either FLONUMs or SOUNDs, and FLONUMs are coerced to sounds with a nominal duration of 30. bowed(step, bowpress-env) [SAL]
    (bowed step bowpress-env) [LISP]
    A physical model of a bowed string instrument from STK. The step parameter is a FLONUM that controls the string length, and the bowpress-env controls the bow pressure and also determines the duration of the resulting sound. The bowpress-env signal should range from zero to one.

    bowed-freq(step, bowpress-env, freq-env) [SAL]
    (bowed-freq step bowpress-env freq-env) [LISP]
    A variation of bowed that includes a variable frequency control, freq-env, which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of bowpress-env and freq-env. These parameters may be of type FLONUM or SOUND. FLONUMs are coerced into SOUNDs with a nominal duration arbitrarily set to 30s.

    mandolin(step, dur, &optional detune) [SAL]
    (mandolin step dur detune) [LISP]
    A physical model of a plucked double-string instrument from STK. The step parameter is a FLONUM wich specifies the desired pitch, dur means the duration of the resulting sound and detune is a FLONUM that controls the relative detune of the two strings. A value of 1.0 means unison. The default value is 4.0. Note: body-size (see snd-mandolin does not seem to work correctly, so a default value is always used by mandolin.

    wg-uniform-bar(step, bowpress-env) [SAL]
    (wg-uniform-bar step bowpress-env) [LISP]

    wg-tuned-bar(step, bowpress-env) [SAL]
    (wg-tuned-bar step bowpress-env) [LISP]

    wg-glass-harm(step, bowpress-env) [SAL]
    (wg-glass-harm step bowpress-env) [LISP]

    wg-tibetan-bowl(step, bowpress-env) [SAL]
    (wg-tibetan-bowl step bowpress-env) [LISP]
    These sounds are presets for a Banded Wave Guide Percussion instrument implemented in STK. The parameter step is a FLONUM that controls the resultant pitch, and bowpress-env is a SOUND ranging from zero to one that controls a parameter of the model. In addition, bowpress-env determines the duration of the resulting sound. (Note: The bowpress-env does not seems influence the timbral quality of the resulting sound).

    modalbar(preset, step, dur) [SAL]
    (modalbar preset step dur) [LISP]
    A physical model of a struck bar instrument implemented in STK. The parameter preset is one of the symbols MARIMBA, VIBRAPHONE, AGOGO, WOOD1, RESO, WOOD2, BEATS, TWO-FIXED, or CLUMP. The symbol must be quoted, e.g. for SAL syntax use quote(marimba), and for Lisp syntax use 'marimba. The parameter step is a FLONUM that sets the pitch (in steps), and dur is the duration in seconds.

    sitar(step, dur) [SAL]
    (sitar step dur) [LISP]
    A sitar physical model implemented in STK. The parameter step is a FLONUM that sets the pitch, and dur is the duration.

    More Behaviors
    clip(sound, peak) [SAL]
    (clip sound peak) [LISP]
    Hard limit sound to the given peak, a positive number. The samples of sound are constrained between an upper value of peak and a lower value of -peak. If sound is a number, clip will return sound limited by peak. If sound is a multichannel sound, clip returns a multichannel sound where each channel is clipped. The result has the type, sample rate, starting time, etc. of sound.

    s-abs(sound) [SAL]
    (s-abs sound) [LISP]
    A generalized absolute value function. If sound is a SOUND, compute the absolute value of each sample. If sound is a number, just compute the absolute value. If sound is a multichannel sound, return a multichannel sound with s-abs applied to each element. The result has the type, sample rate, starting time, etc. of sound.

    s-sqrt(sound) [SAL]
    (s-sqrt sound) [LISP]
    A generalized square root function. If sound is a SOUND, compute the square root of each sample. If sound is a number, just compute the square root. If sound is a multichannel sound, return a multichannel sound with s-sqrt applied to each element. The result has the type, sample rate, starting time, etc. of sound. In taking square roots, if an input sample is less than zero, the corresponding output sample is zero. This is done because the square root of a negative number is undefined.

    s-exp(sound) [SAL]
    (s-exp sound) [LISP]
    A generalized exponential function. If sound is a SOUND, compute e^(x) for each sample x. If sound is a number x, just compute e^(x). If sound is a multichannel sound, return a multichannel sound with s-exp applied to each element. The result has the type, sample rate, starting time, etc. of sound.

    s-log(sound) [SAL]
    (s-log sound) [LISP]
    A generalized natural log function. If sound is a SOUND, compute ln(x) for each sample x. If sound is a number x, just compute ln(x). If sound is a multichannel sound, return a multichannel sound with s-log applied to each element. The result has the type, sample rate, starting time, etc. of sound. Note that the ln of 0 is undefined (some implementations return negative infinity), so use this function with care.

    s-max(sound1, sound2) [SAL]
    (s-max sound1 sound2) [LISP]
    Compute the maximum of two functions, sound1 and sound2. This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of sound1 and sound2. The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of sound1 and sound2. Note, therefore, that the result value is zero except within the bounds of both input sounds.

    s-min(sound1, sound2) [SAL]
    (s-min sound1 sound2) [LISP]
    Compute the minimum of two functions, sound1 and sound2. This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of sound1 and sound2. The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of sound1 and sound2. Note, therefore, that the result value is zero except within the bounds of both input sounds.

    osc-note(pitch [, duration, env, loud, table]) [SAL]
    (osc-note pitch [duration env loud table]) [LISP]
    Same as osc, but osc-note multiplies the result by env. The env may be a sound, or a list supplying (t1 t2 t4 l1 l2 l3). The result has a sample rate of *sound-srate*.

    quantize(sound, steps) [SAL]
    (quantize sound steps) [LISP]
    Quantizes sound as follows: sound is multiplied by steps and rounded to the nearest integer. The result is then divided by steps. For example, if steps is 127, then a signal that ranges from -1 to +1 will be quantized to 255 levels (127 less than zero, 127 greater than zero, and zero itself). This would match the quantization Nyquist performs when writing a signal to an 8-bit audio file. The sound may be multi-channel.

    ramp([duration]) [SAL]
    (ramp [duration]) [LISP]
    Returns a linear ramp from 0 to 1 over duration (default is 1). The function actually reaches 1 at duration, and therefore has one extra sample, making the total duration be duration + 1/*Control-srate*. See Figure 6 for more detail. Ramp is unaffected by the sustain transformation. The effect of time warping is to warp the starting and ending times only. The ramp itself is unwarped (linear). The sample rate is *control-srate*.

    rms(sound [, rate, window-size]) [SAL]
    (rms sound [rate window-size]) [LISP]
    Computes the RMS of sound using a square window of size window-size. The result has a sample rate of rate. The default value of rate is 100 Hz, and the default window size is 1/rate seconds (converted to samples). The rate is a FLONUM and window-size is a FIXNUM.




    Figure 6: Ramps generated by pwl and ramp functions. The pwl version ramps toward the breakpoint (1, 1), but in order to ramp back to zero at breakpoint (1, 0), the function never reaches an amplitude of 1. If used at the beginning of a seq construct, the next sound will begin at time 1. The ramp version actually reaches breakpoint (1, 1); notice that it is one sample longer than the pwl version. If used in a sequence, the next sound after ramp would start at time 1 + P, where P is the sample period.


    recip(sound) [SAL]
    (recip sound) [LISP]
    A generalized reciprocal function. If sound is a SOUND, compute 1/x for each sample x. If sound is a number x, just compute 1/x. If sound is a multichannel sound, return a multichannel sound with recip applied to each element. The result has the type, sample rate, starting time, etc. of sound. Note that the reciprocal of 0 is undefined (some implementations return infinity), so use this function with care on sounds. Division of sounds is accomplished by multiplying by the reciprocal. Again, be careful not to divide by zero.

    s-rest([duration]) [SAL]
    (s-rest [duration]) [LISP]
    Create silence (zero samples) for the given duration at the sample rate *sound-srate*. Default duration is 1.0 sec, and the sound is transformed in time according to *warp*. Note: rest is a Lisp function that is equivalent to cdr. Be careful to use s-rest when you need a sound!

    noise([duration]) [SAL]
    (noise duration) [LISP]
    Generate noise with the given duration. Duration (default is 1.0) is transformed according to *warp*. The sample rate is *sound-srate* and the amplitude is +/- *loud*.

    yin(sound, minstep, maxstep, stepsize) [SAL]
    (yin sound minstep maxstep stepsize) [LISP]
    Fundamental frequency estimation (pitch detection. Use the YIN algorithm to estimate the fundamental frequency of sound, which must be a SOUND. The minstep, a FLONUM, is the minimum frequency considered (in steps), maxstep, a FLONUM, is the maximum frequency considered (in steps), and stepsize, a FIXNUM, is the desired hop size. The result is a "stereo" signal, i.e. an array of two SOUNDs, both at the same sample rate, which is approximately the sample rate of sound divided by stepsize. The first SOUND consists of frequency estimates. The second sound consists of values that measure the confidence or reliability of the frequency estimate. A small value (less than 0.1) indicates fairly high confidence. A larger value indicates lower confidence. This number can also be thought of as a ratio of non-periodic power to periodic power. When the number is low, it means the signal is highly periodic at that point in time, so the period estimate will be reliable. Hint #1: See Alain de Cheveigne and Hideki Kawahara's article "YIN, a Fundamental Frequency Estimator for Speech and Music" in the Journal of the Acoustic Society of America, April 2002 for details on the yin algorithm. Hint #2: Typically, the stepsize should be at least the expected number of samples in one period so that the fundamental frequency estimates are calculated at a rate far below the sample rate of the signal. Frequency does not change rapidly and the yin algorithm is fairly slow. To optimize speed, you may want to use less than 44.1 kHz sample rates for input sounds. Yin uses interpolation to achieve potentially fractional-sample-accurate estimates, so higher sample rates do not necessarily help the algorithm and definitely slow it down. The computation time is O(n^(2)) per estimate, where n is the number of samples in the longest period considered. Therefore, each increase of minstep by 12 (an octave) gives you a factor of 4 speedup, and each decrease of the sample rate of sound by a factor of two gives you another factor of 4 speedup. Finally, the number of estimates is inversely proportional to stepsize. Hint #3: Use snd-srate (see Section "Accessing and Creating Sound") to get the exact sample rate of the result, which will be the sample rate of sound divided by stepsize. E.g. (snd-srate (aref yin-output 0)), where yin-output is a result returned by yin, will be the sample rate of the estimates.

    Transformations

    These functions change the environment that is seen by other high-level functions. Note that these changes are usually relative to the current environment. There are also "absolute" versions of each transformation function, with the exception of seq, seqrep, sim, and simrep. The "absolute" versions (starting or ending with "abs") do not look at the current environment, but rather set an environment variable to a specific value. In this way, sections of code can be insulated from external transformations.

    abs-env(beh) [SAL]
    (abs-env beh) [LISP]
    Compute beh in the default environment. This is useful for computing waveform tables and signals that are "outside" of time. For example, (at 10.0 (abs-env (my-beh))) is equivalent to (abs-env (my-beh)) because abs-env forces the default environment. Or in SAL, we would say abs-env(my-beh()) @ 10 is equivalent to abs-env(my-beh()).

    at(time, beh) [SAL]
    (at time beh) [LISP]
    Evaluate beh with *warp* shifted by time. In SAL, you can use the infix operator @ as in beh @ time. To discover how the environment is shifting time, use local-to-global(time). Most commonly, you call local-to-global(0) to find when a sound created in the current environment will start, expressed in absolute (global) terms. This can be regarded as the "current time."

    at-abs(time, beh) [SAL]
    (at-abs time beh) [LISP]
    Evaluate beh with *warp* shifted so that local time 0 maps to time. In SAL, you can use the infix operator @@ as in beh @@ time.

    continuous-control-warp(beh) [SAL]
    (continuous-control-warp beh) [LISP]
    Applies the current warp environment to the signal returned by beh. The result has the default control sample rate *control-srate*. Linear interpolation is currently used. Implementation: beh is first evaluated without any shifting, stretching, or warping. The result is functionally composed with the inverse of the environment's warp function.

    continuous-sound-warp(beh) [SAL]
    (continuous-sound-warp beh) [LISP]
    Applies the current warp environment to the signal returned by beh. The result has the default sound sample rate *sound-srate*. Linear interpolation is currently used. See continuous-control-warp for implementation notes.

    control-srate-abs(srate, beh) [SAL]
    (control-srate-abs srate beh) [LISP]
    Evaluate beh with *control-srate* set to sample rate srate. Note: there is no "relative" version of this function.

    extract(start, stop, beh) [SAL]
    (extract start stop beh) [LISP]
    Returns a sound which is the portion of beh between start and stop. Note that this is done relative to the current *warp*. The result is shifted to start according to *warp*, so normally the result will start without a delay of start.

    extract-abs(start, stop, beh) [SAL]
    (extract-abs start stop beh) [LISP]
    Returns a sound which is the portion of beh between start and stop, independent of the current *warp*. The result is shifted to start according to *warp*.

    loud(volume, beh) [SAL]
    (loud volume beh) [LISP]
    Evaluates beh with *loud* incremented by volume. (Recall that *loud* is in decibels, so increment is the proper operation.)

    loud-abs(volume, beh) [SAL]
    (loud-abs volume beh) [LISP]
    Evaluates beh with *loud* set to volume.

    sound-srate-abs(srate, beh) [SAL]
    (sound-srate-abs srate beh) [LISP]
    Evaluate beh with *sound-srate* set to sample rate srate. Note: there is no "relative" version of this function.

    stretch(factor, beh) [SAL]
    (stretch factor beh) [LISP]
    Evaluates beh with *warp* scaled by factor. The effect is to "stretch" the result of beh (under the current environment) by factor. See Chapter "Continuous Transformations and Time Warps" for more information. Use get-duration(dur) to get the nominal actual duration of a behavior that locally has a duration of dur. Here, "nominal" means what would be expected if the behavior obeys the shift, stretch, and warp components of the environment. (Any behavior is free to deviate from the nominal timing. For example, a percussion sound might have a fixed duration independent of the stretch factor.) Also, "actual" means global or absolute time, and "locally" means within the environment where get-duration is called. get-duration works by mapping the current time (local time 0) using local-to-global to obtain an actual start time, and mapping dur to obtain an actual end time. The difference is returned.

    stretch-abs(factor, beh) [SAL]
    (stretch-abs factor beh) [LISP]
    Evaluates beh with *warp* set to a linear time transformation where each unit of logical time maps to factor units of real time. The effect is to stretch the nominal behavior of beh (under the default global environment) by factor. See Chapter "Continuous Transformations and Time Warps" for more information.

    sustain(factor, beh) [SAL]
    (sustain factor beh) [LISP]
    Evaluates beh with *sustain* scaled by factor. The effect is to "stretch" the result of beh (under the current environment) by factor; however, the logical stop times are not stretched. Therefore, the overall duration of a sequence is not changed, and sounds will tend to overlap if *sustain* is greater than one (legato) and be separated by silence if *sustain* is less than one.

    sustain-abs(factor, beh) [SAL]
    (sustain-abs factor beh) [LISP]
    Evaluates beh with *sustain* set to factor. (See sustain, above.)

    transpose(amount, beh) [SAL]
    (transpose amount beh) [LISP]
    Evaluates beh with *transpose* shifted by amount. The effect is relative transposition by amount semitones.

    transpose-abs(amount, beh) [SAL]
    (transpose-abs amount beh) [LISP]
    Evaluates beh with *transpose* set to amount. The effect is the transposition of the nominal pitches in beh (under the default global environment) by amount.

    warp(fn, beh) [SAL]
    (warp fn beh) [LISP]
    Evaluates beh with *warp* modified by fn. The idea is that beh and fn are written in the same time system, and fn warps that time system to local time. The current environment already contains a mapping from local time to global (real) time. The value of *warp* in effect when beh is evaluated is the functional composition of the initial *warp* with fn.

    warp-abs(fn, beh) [SAL]
    (warp-abs fn beh) [LISP]
    Evaluates beh with *warp* set to fn. In other words, the current *warp* is ignored and not composed with fn to form the new *warp*.

    Combination and Time Structure

    These behaviors combine component behaviors into structures, including sequences (melodies), simultaneous sounds (chords), and structures based on iteration.

    seq(beh1 [, beh2, ...]) [SAL]
    (seq beh1 [beh2 ...]) [LISP]
    Evaluates the first behavior beh1 according to *time* and each successive behavior at the logical-stop time of the previous one. The results are summed to form a sound whose logical-stop is the logical-stop of the last behavior in the sequence. Each behavior can result in a multichannel sound, in which case, the logical stop time is considered to be the maximum logical stop time of any channel. The number of channels in the result is the number of channels of the first behavior. If other behaviors return fewer channels, new channels are created containing constant zero signals until the required number of channels is obtained. If other behaviors return a simple sound rather than multichannel sounds, the sound is automatically assigned to the first channel of a multichannel sound that is then filled out with zero signals. If another behavior returns more channels than the first behavior, the error is reported and the computation is stopped. Sample rates are converted up or down to match the sample rate of the first sound in a sequence.

    seqrep(var, limit, beh) [SAL]
    (seqrep var limit beh) [LISP]
    Iteratively evaluates beh with the atom var set with values from 0 to limit-1, inclusive. These sounds are placed sequentially in time as if by seq. The symbol var is a read-only local variable to beh. Assignments are not restricted or detected, but may cause a run-time error or crash. In LISP, the syntax is (seqrep (var limit) beh).

    sim([beh1, beh2, ...]) [SAL]
    (sim [beh1 beh2 ...]) [LISP]
    Returns a sound which is the sum of the given behaviors evaluated with current value of *warp*. If behaviors return multiple channel sounds, the corresponding channels are added. If the number of channels does not match, the result has the maximum. For example, if a two-channel sound [L, R] is added to a four-channel sound [C1, C2, C3, C4], the result is [L + C1, R + C2, C3, C4]. Arguments to sim may also be numbers. If all arguments are numbers, sim is equivalent (although slower than) the + function. If a number is added to a sound, snd-offset is used to add the number to each sample of the sound. The result of adding a number to two or more sounds with different durations is not defined. Use const to coerce a number to a sound of a specified duration. An important limitation of sim is that it cannot handle hundreds of behaviors due to a stack size limitation in XLISP. To compute hundreds of sounds (e.g. notes) at specified times, see timed-seq, below. See also sum below.

    simrep(var, limit, beh) [SAL]
    (simrep var limit beh) [LISP]
    Iteratively evaluates beh with the atom var set with values from 0 to limit-1, inclusive. These sounds are then placed simultaneously in time as if by sim. In LISP, the syntax is (seqrep (var limit) beh).

    trigger(s, beh) [SAL]
    (trigger s beh) [LISP]
    Returns a sound which is the sum of instances of the behavior beh. One instance is created each time SOUND s makes a transition from less than or equal to zero to greater than zero. (If the first sample of s is greater than zero, an instance is created immediately.) The sample rate of s and all behaviors must be the same, and the behaviors must be (monophonic) SOUNDs. This function is particularly designed to allow behaviors to be invoked in real time by making s a function of a Nyquist slider, which can be controlled by a graphical interface or by OSC messages. See snd-slider in Section "Creating Sounds".

    set-logical-stop(beh, time) [SAL]
    (set-logical-stop beh time) [LISP]
    Returns a sound with time as the logical stop time.

    sum(a [, b, ...]) [SAL]
    (sum a [b ...]) [LISP]
    Returns the sum of a, b, ..., allowing mixed addition of sounds, multichannel sounds and numbers. Identical to sim. In SAL, use the infix "+" operator.

    mult(a [, b, ...]) [SAL]
    (mult a [b ...]) [LISP]
    Returns the product of a, b, ..., allowing mixed multiplication of sounds, multichannel sounds and numbers.

    diff(a, b) [SAL]
    (diff a b) [LISP]
    Returns the difference between a and b. This function is defined as (sum a (prod -1 b)).

    timed-seq(score) [SAL]
    (timed-seq score) [LISP]
    Computes sounds from a note list or "score." The score is of the form: `((time1 stretch1 beh1) (time2 stretch2 beh2) ...), where timeN is the starting time, stretchN is the stretch factor, and behN is the behavior. Note that score is normally a quoted list! The times must be in increasing order, and each behN is evaluated using lisp's eval, so the behN behaviors cannot refer to local parameters or local variables. The advantage of this form over seq is that the behaviors are evaluated one-at-a-time which can take much less stack space and overall memory. One special "behavior" expression is interpreted directly by timed-seq: (SCORE-BEGIN-END) is ignored, not evaluated as a function. Normally, this special behavior is placed at time 0 and has two parameters: the score start time and the score end time. These are used in Xmusic functions. If the behavior has a :pitch keyword parameter which is a list, the list represents a chord, and the expression is replaced by a set of behaviors, one for each note in the chord. It follows that if :pitch is nil, the behavior represents a rest and is ignored.

    Sound File Input and Output

    play sound [SAL]
    (play sound) [LISP]
    Play the sound through the DAC. Note that play is a command in SAL. In XLISP, it is a function, so the syntax is (play sound), and in SAL, you can call the XLISP function as #play(sound). The play command or function writes a file and plays it. The details of this are system-dependent, but play is defined in the file system.lsp. The variable *default-sf-dir* names a directory into which to save a sound file. Be careful not to call play or sound-play within a function and then invoke that function from another play command.

    By default, Nyquist will try to normalize sounds using the method named by *autonorm-type*, which is 'lookahead by default. The lookahead method precomputes and buffers *autonorm-max-samples* samples, finds the peak value, and normalizes accordingly. The 'previous method bases the normalization of the current sound on the peak value of the (entire) previous sound. This might be good if you are working with long sounds that start rather softly. See Section "Memory Space and Normalization" for more details.

    If you want precise control over output levels, you should turn this feature off by typing (using SAL syntax):
    autonorm-off()
    
    Reenable the automatic normalization feature by typing:
    autonorm-on()
    
    Play normally produces real-time output. The default is to send audio data to the DAC as it is computed in addition to saving samples in a file. If computation is slower than real-time, output will be choppy, but since the samples end up in a file, you can type (r) to replay the stored sound. Real-time playback can be disabled by (using SAL syntax):
    sound-off()
    
    and reenabled by:
    sound-on()
    
    Disabling real-time playback has no effect on (play-file) or (r).

    While sounds are playing, typing control-A to Nyquist will push the estimated elapsed audio time onto the head of the list stored in *audio-markers*. Because samples are computed in blocks and because there is latency between sample computation and sample playback, the elapsed time may not be too accurate, and the computed elapsed time may not advance after all samples have been computed but the sound is still playing.

    play-file(filename) [SAL]
    (play-file filename) [LISP]
    Play the contents of a sound file named by filename. The s-read function is used to read the file, and unless filename specifies an absolute path or starts with ".", it will be read from *default-sf-dir*.

    autonorm-on() [SAL]
    (autonorm-on) [LISP]
    Enable automatic adjustment of a scale factor applied to sounds computed using the play command.

    autonorm-off() [SAL]
    (autonorm-off) [LISP]
    Disable automatic adjustment of a scale factor applied to sounds computed using the play command.

    sound-on() [SAL]
    (sound-on) [LISP]
    Enable real-time audio output when sound is computed by the the play command.

    sound-off() [SAL]
    (sound-off) [LISP]
    Disable real-time audio output when sound is computed by the the play command.

    s-save(expression, maxlen, filename, format: format, mode: mode, bits: bits, swap: flag, play: play) [SAL]
    (s-save expression maxlen filename :format format :mode mode :bits bits :swap flag :play play) [LISP]
    Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. A FLONUM is returned giving the maximum absolute value of all samples written. (This is useful for normalizing sounds and detecting sample overflow.) If play is not NIL, the sound will be output through the computer's audio output system. (play: [SAL] or :play [LISP] is not implemented on all systems; if it is implemented, and filename is NIL, then this will play the file without also writing a file.) The latency (length of audio buffering) used to play the sound is 0.3s by default, but see snd-set-latency. If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. A header is written according to format, samples are encoded according to mode, using bits bits/sample, and bytes are swapped if flag is not NIL. Defaults for these are *default-sf-format*, *default-sf-mode*, and *default-sf-bits*. The default for flag is NIL. The bits parameter may be 8, 16, or 32. The values for the format and mode options are described below:
    Format
    snd-head-none
    The format is unknown and should be determined by reading the file.

    snd-head-raw
    A raw format file has no header.

    snd-head-AIFF
    AIFF format header.

    snd-head-IRCAM
    IRCAM format header.

    snd-head-NeXT
    1024-byte NeXT/SUN format header followed by IRCAM header ala CMIX. Note that the NeXT/SUN format has a header-length field, so it really is legal to have a large header, even though the normal minimal header is only 24 bytes. The additional space leaves room for maximum amplitudes, which can be used for normalizing floating-point soundfiles, and for other data. Nyquist follows the CMIX convention of placing an IRCAM format header immediately after the NeXT-style header.

    snd-head-Wave
    Microsoft Wave format header.

    snd-head-*
    See sndfnint.lsp for more formats.

    Mode

    snd-mode-adpcm
    ADPCM mode (not supported).

    snd-mode-pcm
    signed binary PCM mode.

    snd-mode-ulaw
    8-bit U-Law mode.

    snd-mode-alaw
    8-bit A-Law mode (not supported).

    snd-mode-float
    32-bit floating point mode.

    snd-mode-upcm
    unsigned binary PCM mode.

    snd-mode-*
    See sndfnint.lsp for more modes.

    The defaults for format, mode, and bits are as follows:

    NeXT and Sun machines:
    snd-head-NeXT, snd-mode-pcm, 16

    SGI and Macintosh machines:
    snd-head-AIFF, snd-mode-pcm, 16

    s-read(filename, time-offset: offset, srate: sr, dur: dur, nchans: chans, format: format, mode: mode, bits: n, swap: flag) [SAL]
    (s-read filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag) [LISP]
    Reads a sound from filename. The global *default-sf-dir* applies. If a header is detected, the header is used to determine the format of the file, and header information overrides format information provided by keywords (except for time-offset: and dur:).
    s-read("mysound.snd", srate: 44100)
    
    specifies a sample rate of 44100 hz, but if the file has a header specifying 22050 hz, the resulting sample rate will be 22050. The parameters are:
    If there is an error, for example if offset is greater than the length of the file, then NIL is returned rather than a sound. Information about the sound is also returned by s-read through *rslt* (Footnote 2) . The list assigned to *rslt* is of the form: (format channels mode bits samplerate duration flags byte-offset), which are defined as follows:
    • format - the header format. See s-save for details.
    • channels - the number of channels.
    • mode - the sample representation, e.g. PCM or float. See s-save for details.
    • bits - the number of bits per sample.
    • samplerate - the sample rate, expressed as a FLONUM.
    • duration - the duration of the sound, in seconds.
    • flags - The values for format, channels, mode, bits, samplerate, and duration are initially just the values passed in as parameters or default values to s-read. If a value is actually read from the sound file header, a flag is set. The flags are: snd-head-format, snd-head-channels, snd-head-mode, snd-head-bits, snd-head-srate, and snd-head-dur. For example,
      (let ((flags (caddr (cddddr  *rslt*))))
        (not (zerop (logand flags snd-head-srate))))
      
      tells whether the sample rate was specified in the file. See also sf-info below.
    • byte-offset - the byte offset into the file of the first sample to be read (this is used by the s-overwrite and s-add-to functions).


    s-add-to(expression, maxlen, filename [, offset]) [SAL]
    (s-add-to expression maxlen filename [offset]) [LISP]
    Evaluates the expression, which should result in a sound or an array of sounds, and adds the result to the given filename. The global *default-sf-dir* applies. A FLONUM is returned, giving the maximum absolute value of all samples written. The sample rate(s) of expression must match those of the file. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. If offset is specified, the new sound is added to the file beginning at an offset from the beginning (in seconds). The file is extended if necessary to accommodate the new addition, but if offset falls outside of the original file, the file is not modified. (If necessary, use s-add-to to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file).

    s-overwrite(expression, maxlen, filename [, offset]) [SAL]
    (s-overwrite expression maxlen filename [offset]) [LISP]
    Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename. The global *default-sf-dir* applies. A FLONUM is returned, giving the maximum absolute value of all samples written. The sample rate(s) of expression must match those of the file. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. If offset is specified, the new sound is written to the file beginning at an offset from the beginning (in seconds). The file is extended if necessary to accommodate the new insert, but if offset falls outside of the original file, the file is not modified. (If necessary, use s-add-to to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file).

    sf-info(filename) [SAL]
    (sf-info filename) [LISP]
    Prints information about a sound file. The parameter filename is a string. The file is assumed to be in *default-sf-dir* (see soundfilename below) unless the filename begins with "." or "/". The source for this function is in the runtime and provides an example of how to determine sound file parameters.

    soundfilename(name) [SAL]
    (soundfilename name) [LISP]
    Converts a string name to a soundfile name. If name begins with "." or "/", the name is returned without alteration. Otherwise, a path taken from *default-sf-dir* is prepended to name. The s-plot, s-read, and s-save functions all use soundfilename translate filenames.

    s-plot(sound [, dur, n]) [SAL]
    (s-plot sound [dur n]) [LISP]
    Plots sound in a window. This function was designed to run a plot program on a Unix workstation, but now is primarily used with NyquistIDE, which has self-contained plotting. Normally, time/value pairs in ascii are written to points.dat and system-dependent code (or the NyquistIDE program) takes it from there. If the sound is longer than the optional dur (default is 2 seconds), only the first dur seconds are plotted. If there are more than n samples to be plotted, the signal is interpolated to have n samples before plotting. The data file used is *default-plot-file*:

    *default-plot-file*
    The file containing the data points, defaults to "points.dat".

    s-print-tree(sound) [SAL]
    (s-print-tree sound) [LISP]
    Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. Identical to snd-print-tree.

    Low-level Functions

    Nyquist includes many low-level functions that are used to implement the functions and behaviors described in previous sections. For completeness, these functions are described here. Remember that these are low-level functions that are not intended for normal use. Unless you are trying to understand the inner workings of Nyquist, you can skip this section.

    Creating Sounds

    The basic operations that create sounds are described here.

    snd-const(value, t0, srate, duration) [SAL]
    (snd-const value t0 srate duration) [LISP]
    Returns a sound with constant value, starting at t0 with the given duration, at the sample rate srate. You might want to use pwl (see Section "Piece-wise Approximations") instead.

    snd-read(filename, offset, t0, format, channels, mode, bits, swap, sr, dur) [SAL]
    (snd-read filename offset t0 format channels mode bits swap sr dur) [LISP]
    Loads a sound from a file with name filename. Files are assumed to consist of a header followed by frames consisting of one sample from each channel. The format specifies the type of header, but this information is currently ignored. Nyquist looks for a number of header formats and automatically figures out which format to read. If a header can be identified, the header is first read from the file. Then, the file pointer is advanced by the indicated offset (in seconds). If there is an unrecognized header, Nyquist will assume the file has no header. If the header size is a multiple of the frame size (bytes/sample * number-of-channels), you can use offset to skip over the header. To skip N bytes, use an offset of:
    (/ (float N) sr (/ bits 8) channels)
    
    If the header is not a multiple of the frame size, either write a header or contact the author (dannenberg@cs.cmu.edu) for assistance. Nyquist will round offset to the nearest sample. The resulting sound will start at time t0. If a header is found, the file will be interpreted according to the header information. If no header was found, channels tells how many channels there are, the samples are encoded according to mode, the sample length is bits, and sr is the sample rate. The swap flag is 0 or 1, where 1 means to swap sample bytes. The duration to be read (in seconds) is given by dur. If dur is longer than the data in the file, then a shorter duration will be returned. If the file contains one channel, a sound is returned. If the file contains 2 or more channels, an array of sounds is returned. Note: you probably want to call s-read (see Section
    "Sound File Input and Output") instead of snd-read. Also, see Section "Sound File Input and Output" for information on the mode and format parameters.

    snd-save(expression, maxlen, filename, format, mode, bits, swap, play) [SAL]
    (snd-save expression maxlen filename format mode bits swap play) [LISP]
    Evaluates the expression, which should result in a sound or an array of sounds, and writes the result to the given filename. If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by maxlen, which allows writing the initial part of a very long or infinite sound. A header is written according to format, samples are encoded according to mode, using bits bits/sample, and swapping bytes if swap is 1 (otherwise it should be 0). If play is not null, the audio is played in real time (to the extent possible) as it is computed. The peak value of the sound is returned. In addition, the symbol *RSLT* is bound to a list containing the sample rate, number of channels, and duration (in that order) of the saved sound. Note: you probably want to call s-save (see Section "Sound File Input and Output") instead. The format and mode parameters are described in Section "Sound File Input and Output".

    snd-overwrite(expression, maxlen, filename, offset, format, mode, bits, swap) [SAL]
    (snd-overwrite expression maxlen filename offset format mode bits swap) [LISP]
    Evaluates the expression, which should result in a sound or an array of sounds, and replaces samples in the given filename, writing the first frame at a time of offset seconds. The offset must be less than or equal to the duration of the existing file. The duration of the written samples may be greater than that of the file, in which case the file is extended as necessary. The sample rate(s) of expression and the number of channels must match those of the file. If format is SND-HEAD-RAW, then the file format is given by mode (see snd-save, bits (per channel), swap (1 means to swap bytes and 0 means write them in the native byte order), and the number of channels and sample rate of the sound returned by evaluating expression. If the file is a known audio file format, format should be SND-HEAD-NONE, and the other parameters are ignored. Up to a maximum of maxlen samples will be written per channel. The peak value of the sound is returned. In addition, the symbol *RSLT* is bound to a list containing the duration of the written sound (which may not be the duration of the sound file). Use s-add-to (in Section "Sound File Input and Output" or s-overwrite (in Section "Sound File Input and Output" instead of this function.

    snd-coterm(s1, s2) [SAL]
    (snd-coterm s1 s2) [LISP]
    Returns a copy of s1, except the start time is the maximum of the start times of s1 and s2, and the termination time is the minimum of s1 and s2. (After the termination time, the sound is zero as if s1 is gated by s2.) Some rationale follows: In order to implement s-add-to, we need to read from the target sound file, add the sounds to a new sound, and overwrite the result back into the file. We only want to write as many samples into the file as there are samples in the new sound. However, if we are adding in samples read from the file, the result of a snd-add in Nyquist will have the maximum duration of either sound. Therefore, we may read to the end of the file. What we need is a way to truncate the read, but we cannot easily do that, because we do not know in advance how long the new sound will be. The solution is to use snd-coterm, which will allow us to truncate the sound that is read from the file (s1) according to the duration of the new sound (s2). When this truncated sound is added to the new sound, the result will have only the duration of the new sound, and this can be used to overwrite the file. This function is used in the implementation of s-add-to, which is defined in runtime/fileio.lsp.

    (snd-from-array ...) [SAL]
    (snd-from-array ...) [LISP]
    See "Accessing and Creating Sound".

    snd-white(t0, sr, d) [SAL]
    (snd-white t0 sr d) [LISP]
    Generate white noise, starting at t0, with sample rate sr, and duration d. You probably want to use noise (see Section "More Behaviors").

    snd-zero(t0, srate) [SAL]
    (snd-zero t0 srate) [LISP]
    Creates a sound that is zero everywhere, starts at t0, and has sample rate srate. The logical stop time is immediate, i.e. also at t0. You probably want to use pwl (see Section "Piece-wise Approximations") instead.

    get-slider-value(index) [SAL]
    (get-slider-value index) [LISP]
    Return the current value of the slider named by index (an integer index into the array of sliders). Note that this "slider" is just a floating point value in an array. Sliders can be changed by OSC messages (see osc-enable) and by sending character sequences to Nyquist's standard input. (Normally, these character sequences would not be typed but generated by the NyquistIDE interactive development environment, which runs Nyquist as a sub-process, and which present the user with graphical sliders.)

    snd-slider(index, t0, srate, duration) [SAL]
    (snd-slider index t0 srate duration) [LISP]
    Create a sound controlled by the slider named by index (an integer index into the array of sliders; see get-slider-value for more information). The function returns a sound. Since Nyquist sounds are computed in blocks of samples, and each block is computed at once, each block will contain copies of the current slider value. To obtain reasonable responsiveness, slider sounds should have high (audio) sample rates so that the block rate will be reasonably high. Also, consider lowering the audio latency using snd-set-latency. To "trigger" a Nyquist behavior using slider input, see the trigger function in Section "Combination and Time Structure".

    Signal Operations

    This next set of functions take sounds as arguments, operate on them, and return a sound.

    snd-abs(sound) [SAL]
    (snd-abs sound) [LISP]
    Computes a new sound where each sample is the absolute value of the corresponding sample in sound. You should probably use s-abs instead. (See Section "More Behaviors".)

    snd-sqrt(sound) [SAL]
    (snd-sqrt sound) [LISP]
    Computes a new sound where each sample is the square root of the corresponding sample in sound. If a sample is negative, it is taken to be zero to avoid raising a floating point error. You should probably use s-sqrt instead. (See Section "More Behaviors".)

    snd-add(sound1, sound) [SAL]
    (snd-add sound1 sound) [LISP]
    Adds two sounds. The resulting start time is the minimum of the two parameter start times, the logical stop time is the maximum of the two parameter stop times, and the sample rate is the maximum of the two parameter sample rates. Use sim or sum instead of snd-add (see Section "Combination and Time Structure").

    snd-offset(sound, offset) [SAL]
    (snd-offset sound offset) [LISP]
    Add an offset to a sound. The resulting start time, logical stop time, stop time, and sample rate are those of sound. Use sum instead (see Section "Combination and Time Structure").

    snd-avg(sound, blocksize, stepsize, operation) [SAL]
    (snd-avg sound blocksize stepsize operation) [LISP]
    Computes the averages or peak values of blocks of samples. Each output sample is an average or peak of blocksize (a fixnum) adjacent samples from the input sound. After each average or peak is taken, the input is advanced by stepsize, a fixnum which may be greater or less than blocksize. The output sample rate is the sound (input) sample rate divided by stepsize. This function is useful for computing low-sample-rate rms or peak amplitude signals for input to snd-gate or snd-follow. To select the operation, operation should be one of OP-AVERAGE or OP-PEAK. (These are global lisp variables; the actual operation parameter is an integer.) For RMS computation, see rms in Section "More Behaviors".

    snd-clip(sound, peak) [SAL]
    (snd-clip sound peak) [LISP]
    Hard limit sound to the given peak, a positive number. The samples of sound are constrained between an upper value of peak and a lower value of -peak. Use clip instead (see Section "More Behaviors").

    snd-compose(f, g) [SAL]
    (snd-compose f g) [LISP]
    Compose two signals, i.e. compute f(g(t)), where f and g are sounds. This function is used primarily to implement time warping, but it can be used in other applications such as frequency modulation. For each sample x in g, snd-compose looks up the value of f(x) using linear interpolation. The resulting sample rate, start time, etc. are taken from g. The sound f is used in effect as a lookup table, but it is assumed that g is non-decreasing, so that f is accessed in time order. This allows samples of f to be computed and discarded incrementally. If in fact g decreases, the current sample of g is replaced by the previous one, forcing g into compliance with the non-decreasing restriction. See also sref, shape, and snd-resample.

    For an extended example that uses snd-compose for variable pitch shifting, see demos/pitch_change.htm.

    snd-tapv(sound, offset, vardelay, maxdelay) [SAL]
    (snd-tapv sound offset vardelay maxdelay) [LISP]
    A variable delay: sound is delayed by the sum of offset (a FIXNUM or FLONUM) and vardelay (a SOUND). The specified delay is adjusted to lie in the range of zero to maxdelay seconds to yield the actual delay, and the delay is implemented using linear interpolation. This function was designed specifically for use in a chorus effect: the offset is set to half of maxdelay, and the vardelay input is a slow sinusoid. The maximum delay is limited to maxdelay, which determines the length of a fixed-sized buffer. The function tapv is equivalent and preferred (see Section "Filter Behaviors").

    snd-tapf(sound, offset, vardelay, maxdelay) [SAL]
    (snd-tapf sound offset vardelay maxdelay) [LISP]
    A variable delay like snd-tapv except there is no linear interpolation. By eliminating interpolation, the output is an exact copy of the input with no filtering or distortion. On the other hand, delays jump by samples causing samples to double or skip even when the delay is changed smoothly.

    snd-copy(sound) [SAL]
    (snd-copy sound) [LISP]
    Makes a copy of sound. Since operators always make (logical) copies of their sound parameters, this function should never be needed. This function is here for debugging.

    snd-down(srate, sound) [SAL]
    (snd-down srate sound) [LISP]
    Linear interpolation of samples down to the given sample rate srate, which must be lower than the sample rate of sound. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call force-srate (see Section "Sound Synthesis").

    snd-exp(sound) [SAL]
    (snd-exp sound) [LISP]
    Compute the exponential of each sample of sound. Use s-exp instead (see Section "More Behaviors").

    snd-follow(sound, floor, risetime, falltime, lookahead) [SAL]
    (snd-follow sound floor risetime falltime lookahead) [LISP]
    An envelope follower. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The floor is the minimum output value. The risetime is the time (in seconds) it takes for the output to rise (exponentially) from floor to unity (1.0) and the falltime is the time it takes for the output to fall (exponentially) from unity to floor. The algorithm looks ahead for peaks and will begin to increase the output signal according to risetime in anticipation of a peak. The amount of anticipation (in sampless) is given by lookahead. The algorithm is as follows: the output value is allowed to increase according to risetime or decrease according to falltime. If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to risetime to meet the new value. The algorithm will only work backward as far as lookahead. If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by falltime, the output fall rate will be limited by falltime, and the fall in output will stop when the output reaches floor. This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See snd-avg above for a function that can help to generate a low-sample-rate input for snd-follow. See snd-chase in Section "Filters" for a related filter.

    snd-gate(sound, lookahead, risetime, falltime, floor, threshold) [SAL]
    (snd-gate sound lookahead risetime falltime floor threshold) [LISP]
    This function generates an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to unity (1.0) at the point the signal crosses the threshold. Again, look-ahead is used, so the rise actually starts before the signal crosses the threshold. The rise is a constant-rate exponential and set so that a rise from floor to unity occurs in risetime. Similarly, the fall is a constant-rate exponential such that a fall from unity to floor takes falltime. The result is delayed by lookahead, so the output is not actually synchronized with the input. To compensate, you should drop the initial lookahead of samples. Thus, snd-gate is not recommended for direct use. Use gate instead (see Section "Miscellaneous Functions").

    snd-inverse(signal, start, srate) [SAL]
    (snd-inverse signal start srate) [LISP]
    Compute the function inverse of signal, that is, compute g(t) such that signal(g(t)) = t. This function assumes that signal is non-decreasing, it uses linear interpolation, the resulting sample rate is srate, and the result is shifted to have a starting time of start. If signal decreases, the true inverse may be undefined, so we define snd-inverse operationally as follows: for each output time point t, scan ahead in signal until the value of signal exceeds t. Interpolate to find an exact time point x from signal and output x at time t. This function is intended for internal system use in implementing time warps.

    snd-log(sound) [SAL]
    (snd-log sound) [LISP]
    Compute the natural logorithm of each sample of sound. Use s-log instead (see Section "More Behaviors").

    peak(expression, maxlen) [SAL]
    (peak expression maxlen) [LISP]
    Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating expression (as in s-save). Only the first maxlen samples are evaluated. The expression is automatically quoted (peak is a macro), so do not quote this parameter. If expression is a variable, then the global binding of that variable will be used. Also, since the variable retains a reference to the sound, the sound will be evaluated and left in memory. See Section "Memory Space and Normalization" on "Memory Space and Normalization" for examples.

    snd-max(expression, maxlen) [SAL]
    (snd-max expression maxlen) [LISP]
    Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating expression (as in snd-save), which is therefore normally quoted by the caller. At most maxlen samples are computed. The result is the maximum of the absolute values of the samples. Notes: It is recommended to use peak (see above) instead. If you want to find the maximum of a sound bound to a local variable and it is acceptable to save the samples in memory, then this is probably the function to call. Otherwise, use peak.

    snd-maxv(sound1, sound2) [SAL]
    (snd-maxv sound1 sound2) [LISP]
    Compute the maximum of sound1 and sound2 on a sample-by-sample basis. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. The physical stop time is the minimum of the physical stop times of the two sounds. Note that this violates the "normal" interpretation that sounds are zero outside their start and stop times. For example, even if sound1 extends beyond sound2 and is greater than zero, the result value in this extension will be zero because it will be after the physical stop time, whereas if we simply treated sound2 as zero in this region and took the maximum, we would get a non-zero result. Use s-max instead (see Section "More Behaviors").

    snd-normalize(sound) [SAL]
    (snd-normalize sound) [LISP]
    Internally, sounds are stored with a scale factor that applies to all samples of the sound. All operators that take sound arguments take this scale factor into account (although it is not always necessary to perform an actual multiply per sample), so you should never need to call this function. This function multiplies each sample of a sound by its scale factor, returning a sound that represents the same signal, but whose scale factor is 1.0.

    snd-oneshot(sound, threshold, ontime) [SAL]
    (snd-oneshot sound threshold ontime) [LISP]
    Computes a new sound that is zero except where sound exceeds threshold. From these points, the result is 1.0 until sound remains below threshold for ontime (in seconds). The result has the same sample rate, start time, logical stop time, and duration as sound.

    snd-prod(sound1, sound2) [SAL]
    (snd-prod sound1 sound2) [LISP]
    Computes the product of sound1 and sound2. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. Do not use this function. Use mult or prod instead (see Section "Sound Synthesis"). Sample rate, start time, etc. are taken from sound.

    snd-pwl(t0, sr, lis) [SAL]
    (snd-pwl t0 sr lis) [LISP]
    Computes a piece-wise linear function according to the breakpoints in lis. The starting time is t0, and the sample rate is sr. The breakpoints are passed in an XLISP list (of type LVAL) where the list alternates sample numbers (FIXNUMs, computed in samples from the beginning of the pwl function) and values (the value of the pwl function, given as a FLONUM). There is an implicit starting point of (0, 0). The list must contain an odd number of points, the omitted last value being implicitly zero (0). The list is assumed to be well-formed. Do not call this function. Use pwl instead (see Section "Piece-wise Approximations").

    snd-quantize(sound, steps) [SAL]
    (snd-quantize sound steps) [LISP]
    Quantizes a sound. See Section "More Behaviors" for details.

    snd-recip(sound) [SAL]
    (snd-recip sound) [LISP]
    Compute the reciprocal of each sample of sound. Use recip instead (see Section "More Behaviors").

    snd-resample(f, rate) [SAL]
    (snd-resample f rate) [LISP]
    Resample sound f using high-quality interpolation, yielding a new sound with the specified rate. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. The resulting start time, etc. are taken from f. Use resample instead.

    snd-resamplev(f, rate, g) [SAL]
    (snd-resamplev f rate g) [LISP]
    Compose two signals, i.e. compute f(g(t)), where f and g are sounds. The result has sample rate given by rate. At each time t (according to the rate), g is linearly interpolated to yield an increasing sequence of high-precision score-time values. f is then interpolated at each value to yield a result sample. If in fact g decreases, the current sample of g is replaced by the previous one, forcing g into compliance with the non-decreasing restriction. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. Note that if g has a high sample rate, this may introduce unwanted jitter into sample times. See sound-warp for a detailed discussion. See snd-compose for a fast, low-quality alternative to this function. Normally, you should use sound-warp instead of this function.

    snd-scale(scale, sound) [SAL]
    (snd-scale scale sound) [LISP]
    Scales the amplitude of sound by the factor scale. Use scale instead (see Section "Sound Synthesis").

    snd-shape(signal, table, origin) [SAL]
    (snd-shape signal table origin) [LISP]
    A waveshaping function. This is the primitive upon which shape is based. The snd-shape function is like shape except that signal and table must be (single-channel) sounds. Use shape instead (see Section "Filter Behaviors").

    snd-up(srate, sound) [SAL]
    (snd-up srate sound) [LISP]
    Increases sample rate by linear interpolation. The sound is the signal to be up-sampled, and srate is the output sample rate. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call force-srate (see Section "Sound Synthesis").

    snd-xform(sound, sr, time, start, stop, scale) [SAL]
    (snd-xform sound sr time start stop scale) [LISP]
    Makes a copy of sound and then alters it in the following order: (1) the start time (snd-t0) of the sound is shifted to time, (1) the sound is stretched as a result of setting the sample rate to sr (the start time is unchanged by this), (3) the sound is clipped from start to stop, (4) if start is greater than time, the sound is shifted shifted by time - start, so that the start time is time, (5) the sound is scaled by scale. An empty (zero) sound at time will be returned if all samples are clipped. Normally, you should accomplish all this using transformations. A transformation applied to a sound has no effect, so use cue to create a transformable sound (see Section "Using Previously Created Sounds").

    snd-yin(sound, minstep, maxstep, rate) [SAL]
    (snd-yin sound minstep maxstep rate) [LISP]
    Identical to yin. See Section "More Behaviors".

    Filters

    These are also "Signal Operators," the subject of the previous section, but there are so many filter functions, they are documented in this special section.

    Some filters allow time-varying filter parameters. In these functions, filter coefficients are calculated at the sample rate of the filter parameter, and coefficients are not interpolated.

    snd-alpass(sound, delay, feedback) [SAL]
    (snd-alpass sound delay feedback) [LISP]
    An all-pass filter. This produces a repeating echo effect without the resonances of snd-delay. The feedback should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use alpass instead (see Section "Filter Behaviors").

    snd-alpasscv(sound, delay, feedback) [SAL]
    (snd-alpasscv sound delay feedback) [LISP]
    An all-pass filter with variable feedback. This is just like snd-alpass except feedback is a sound. You should use alpass instead (see Section "Filter Behaviors").

    snd-alpassvv(sound, delay, feedback, maxdelay) [SAL]
    (snd-alpassvv sound delay feedback maxdelay) [LISP]
    An all-pass filter with variable feedback and delay. This is just like snd-alpass except feedback and delay are sounds, and there is an additional FLONUM parameter, maxdelay, that gives an upper bound on the value of delay. Note: delay must remain between zero and maxdelay. If not, results are undefined, and Nyquist may crash. You should use alpass instead (see Section "Filter Behaviors").

    snd-areson(sound, hz, bw, normalization) [SAL]
    (snd-areson sound hz bw normalization) [LISP]
    A notch filter modeled after the areson unit generator in Csound. The snd-areson filter is an exact complement of snd-reson such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. Note that because of this complementary design, the power is not normalized as in snd-reson. See snd-reson for details on normalization. You should use areson instead (see Section "Filter Behaviors").

    snd-aresoncv(sound, hz, bw, normalization) [SAL]
    (snd-aresoncv sound hz bw normalization) [LISP]
    This function is identical to snd-areson except the bw (bandwidth) parameter is a sound. Filter coefficients are updated at the sample rate of bw. The "cv" suffix stands for Constant, Variable, indicating that hz and bw are constant (a number) and variable (a sound), respectively. This naming convention is used throughout. You should use areson instead (see Section "Filter Behaviors").

    snd-aresonvc(sound, hz, bw, normalization) [SAL]
    (snd-aresonvc sound hz bw normalization) [LISP]
    This function is identical to snd-areson except the hz (center frequency) parameter is a sound. Filter coefficients are updated at the sample rate of hz. You should use areson instead (see Section "Filter Behaviors").

    snd-aresonvv(sound, hz, bw, normalization) [SAL]
    (snd-aresonvv sound hz bw normalization) [LISP]
    This function is identical to snd-areson except both hz (center frequency) and bw (bandwidth) are sounds. Filter coefficients are updated at the next sample of either hz or bw. You should use areson instead (see Section "Filter Behaviors").

    snd-atone(sound, hz) [SAL]
    (snd-atone sound hz) [LISP]
    A high-pass filter modeled after the atone unit generator in Csound. The snd-atone filter is an exact complement of snd-tone such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. You should use hp instead (see Section "Filter Behaviors").

    snd-atonev(sound, hz) [SAL]
    (snd-atonev sound hz) [LISP]
    This is just like snd-atone except that the hz cutoff frequency is a sound. Filter coefficients are updated at the sample rate of hz. You should use hp instead (see Section "Filter Behaviors").

    snd-biquad(sound, b0, b1, b2, a1, a2, z1init, z2init) [SAL]
    (snd-biquad sound b0 b1 b2 a1 a2 z1init z2init) [LISP]
    A general second order IIR filter, where a0 is assumed to be unity. For a1 and a2, the sign convention is opposite to that of Matlab. All parameters except the input sound are of type FLONUM. You should probably use one of lowpass2, highpass2, bandpass2, notch2, allpass2, eq-lowshelf, eq-highshelf, eq-band, lowpass4, lowpass6, lowpass8, highpass4, highpass6, or highpass8, which are all based on snd-biquad and described in Section "Filter Behaviors". For completeness, you will also find biquad and biquad-m described in that section.

    snd-chase(sound, risetime, falltime) [SAL]
    (snd-chase sound risetime falltime) [LISP]
    A slew rate limiter. The output "chases" the input at rates determined by risetime and falltime. If the input changes too fast, the output will lag behind the input. This is a form of lowpass filter, but it was created to turn hard-switching square waves into smoother control signals that could be used for linear crossfades. If the input switches from 0 to 1, the output will linearly rise to 1 in risetime seconds. If the input switches from 1 to 0, the output will linearly fall to 0 in falltime seconds. The generated slope is constant; the transition is linear; this is not an exponential rise or fall. The risetime and falltime must be scalar constants; complain to the author if this is not adequate. The snd-chase function is safe for ordinary use. See snd-follow in Section "Signal Operations" for a related function.

    snd-congen(gate, risetime, falltime) [SAL]
    (snd-congen gate risetime falltime) [LISP]
    A simple "contour generator" based on analog synthesizers. The gate is a sound that normally steps from 0.0 to 1.0 at the start of an envelop and goes from 1.0 back to 0.0 at the beginning of the release. At each sample, the output converges to the input exponentially. If gate is greater than the output, e.g. the attack, then the output converges half-way to the output in risetime. If the gate is less than the output, the half-time is falltime. The sample rate, starting time, logical-stop-time, and terminate time are taken from gate. You should use congen instead (see Section "Filter Behaviors".

    snd-convolve(sound, response) [SAL]
    (snd-convolve sound response) [LISP]
    Convolves sound by response using a simple O(N x M) algorithm. The sound can be any length, but the response is computed and stored in a table. The required compuation time per sample and total space are proportional to the length of response. Use convolve instead (see Section "Filter Behaviors").

    snd-delay(sound, delay, feedback) [SAL]
    (snd-delay sound delay feedback) [LISP]
    Feedback delay. The output, initially sound, is recursively delayed by delay, scaled by feedback, and added to itself, producing an repeating echo effect. The feedback should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use feedback-delay instead (see Section "Filter Behaviors")

    snd-delaycv(sound, delay, feedback) [SAL]
    (snd-delaycv sound delay feedback) [LISP]
    Feedback delay with variable feedback. This is just like snd-delay except feedback is a sound. You should use feedback-delay instead (see Section "Filter Behaviors").

    snd-reson(sound, hz, bw, normalization) [SAL]
    (snd-reson sound hz bw normalization) [LISP]
    A second-order resonating (bandpass) filter with center frequency hz and bandwidth bw, modeled after the reson unit generator in Csound. The normalization parameter must be an integer and (like in Csound) specifies a scaling factor. A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than hz are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The result sample rate, start time, etc. are takend from sound. You should use reson instead (see Section "Filter Behaviors").

    snd-resoncv(sound, hz, bw, normalization) [SAL]
    (snd-resoncv sound hz bw normalization) [LISP]
    This function is identical to snd-reson except bw (bandwidth) is a sound. Filter coefficients are updated at the sample rate of bw. You should use reson instead (see Section "Filter Behaviors").

    snd-resonvc(sound, hz, bw, normalization) [SAL]
    (snd-resonvc sound hz bw normalization) [LISP]
    This function is identical to snd-reson except hz (center frequency) is a sound. Filter coefficients are updated at the sample rate of hz. You should use reson instead (see Section "Filter Behaviors").

    snd-resonvv(sound, hz, bw, normalization) [SAL]
    (snd-resonvv sound hz bw normalization) [LISP]
    This function is identical to snd-reson except botth hz (center frequency) and bw (bandwidth) are sounds. Filter coefficients are updated at the next sample from either hz or bw. You should use reson instead (see Section "Filter Behaviors").

    snd-stkchorus(sound, delay, depth, freq, mix, sr) [SAL]
    (snd-stkchorus sound delay depth freq mix sr) [LISP]
    A chorus implemented in STK. The parameter delay is a FIXNUM representing the median desired delay length in samples. A typical value is 6000. The FLONUM parameters depth and freq set the modulation depth (from 0 to 1) and modulation frequency (in Hz), mix sets the mixture of input sound and chorused sound, where a value of 0.0 means input sound only (dry) and a value of 1.0 means chorused sound only (wet). The parameter sr is the desired sample rate of the resulting sound (Footnote 3) You should use pitshift instead (see Section "Effects").

    snd-stkpitshift(sound, shift, mix, sr) [SAL]
    (snd-stkpitshift sound shift mix sr) [LISP]
    A pitch shifter implemented in STK. The sound is shifted in pitch by shift, a FLONUM representing the shift factor. A value of 1.0 means no shift. The parameter mix sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). The sr is the desired sampling frequency. (Footnote 4) You should use pitshift instead (see Section "Effects").

    snd-stkrev(rev-type, sound, decay, mix, sr) [SAL]
    (snd-stkrev rev-type sound decay mix sr) [LISP]
    A reverb implemented in STK. The parameter rev-type is a FIXNUM ranging from zero to two and selects the type of reverb. Zero selects NRev type, one selects JCRev, and two selects PRCRev. The input sound is processed by the reverb with a decay time in seconds (a FLONUM). The mix, a FLONUM, sets the mixture of dry input and reverb output. A value of 0.0 means input only (dry) and a value of 1.0 means reverb only (wet). The sample rate is sr (Footnote 5) You should use nrev, jcrev or prcrev instead (see Section "Effects").

    snd-tone(sound, hz) [SAL]
    (snd-tone sound hz) [LISP]
    A first-order recursive low-pass filter, based on the tone unit generator of Csound. The hz parameter is the cutoff frequency, the response curve's half-power point. The result sample rate, start time, etc. are takend from sound. You should use lp instead (see Section "Filter Behaviors").

    snd-tonev(sound, hz) [SAL]
    (snd-tonev sound hz) [LISP]
    This function is identical to snd-tone except hz (cutoff frequency) is a sound. The filter coefficients are updated at the sample rate of hz. You should use lp instead (see Section "Filter Behaviors").

    Table-Lookup Oscillator Functions

    These functions all use a sound to describe one period of a periodic waveform. In the current implementation, the sound samples are copied to an array (the waveform table) when the function is called. To make a table-lookup oscillator generate a specific pitch, we need to have several pieces of information:
    • A waveform to put into the table. This comes from the sound parameter.
    • The length (in samples) of the waveform. This is obtained by reading samples (starting at the sound's start time, not necessarily at time zero) until the physical stop time of the sound. (If you read the waveform from a file or generate it with functions like sim and sine, then the physical and logical stop times will be the same and will correspond to the duration you specified, rounded to the nearest sample.)
    • The intrinsic sample rate of the waveform. This sample rate is simply the sample rate property of sound.
    • The pitch of the waveform. This is supplied by the step parameter and indicates the pitch (in steps) of sound. You might expect that the pitch would be related to the period (length) of sound, but there is the interesting case that synthesis based on sampling often loops over multiple periods. This means that the fundamental frequency of a generated tone may be some multiple of the looping rate. In Nyquist, you always specify the perceived pitch of the looped sound if the sound is played at the sound's own sample rate.
    • The desired pitch. This is specified by the hz parameter in Hertz (cycles per second) in these low-level functions. Note that this is not necessarily the "loop" rate at which the table is scanned. Instead, Nyquist figures what sample rate conversion would be necessary to "transpose" from the step which specifies the original pitch of sound to hz, which gives the desired pitch. The mixed use of steps and Hertz came about because it seemed that sample tables would be tagged with steps ("I sampled a middle-C"), whereas frequency deviation in the fmosc function is linear, thus calling for a specification in Hertz.
    • The desired sample rate. This is given by the sr parameter in Hertz.

    Other parameters common to all of these oscillator functions are:

    • t0, the starting time, and
    • phase, the starting phase in degrees. Note that if the step parameter indicates that the table holds more than one fundamental period, then a starting phase of 360 will be different than a starting phase of 0.

    snd-amosc(sound, step, sr, hz, t0, am, phase) [SAL]
    (snd-amosc sound step sr hz t0 am phase) [LISP]
    An oscillator with amplitude modulation. The sound am specifies the amplitude and the logical stop time. The physical stop time is also that of am. You should use amosc instead (see Section "Oscillators").

    snd-fmosc(s, step, sr, hz, t0, fm, phase) [SAL]
    (snd-fmosc s step sr hz t0 fm phase) [LISP]
    A Frequency Modulation oscillator. The sound fm specifies frequency deviation (in Hertz) from hz. You should use fmosc instead (see Section "Oscillators").

    snd-fmfb(t0, hz, sr, index, dur) [SAL]
    (snd-fmfb t0 hz sr index dur) [LISP]
    A Feedback FM oscillator. The resulting sound starts at t0, has a fundamental frequency of hz, a sample rate of sr, and a duration of dur seconds. The index is a FLONUM that specifies the amount of feedback. You should use fmfb instead (see Section "Oscillators").

    snd-fmfbv(t0, hz, sr, index)
    (snd-fmfv t0 hz sr index) [LISP]
    A Feedback FM oscillator. The resulting sound starts at t0, has a fundamental frequency of hz, and a sample rate of sr. The index is a SOUND that specifies the amount of feedback and determines the duration. You should use fmfb instead (see Section "Oscillators").

    snd-buzz(n, sr, hz, t0, fm) [SAL]
    (snd-buzz n sr hz t0 fm) [LISP]
    A buzz oscillator, which generates n harmonics of equal amplitude. The fm specifies frequency deviation (in Hertz) from hz. You should use buzz instead (see Section "Oscillators").

    snd-pluck(sr, hz, t0, d, final-amp) [SAL]
    (snd-pluck sr hz t0 d final-amp) [LISP]
    A Karplus-Strong plucked string oscillator with sample rate sr, fundamental frequency hz, starting time t0, duration d, initial amplitude approximately 1.0 (not exact because the string is initialized with random values) and final amplitude approximately final-amp. You should use pluck instead (see Section "Oscillators").

    snd-osc(s, step, sr, hz, t0, d, phase) [SAL]
    (snd-osc s step sr hz t0 d phase) [LISP]
    A simple table lookup oscillator with fixed frequency. The duration is d seconds. You should use osc instead (see Section "Oscillators").

    snd-partial(sr, hz, t0, env) [SAL]
    (snd-partial sr hz t0 env) [LISP]
    This is a special case of snd-amosc that generates a sinusoid starting at phase 0 degrees. The env parameter gives the envelope or any other amplitude modulation. You should use partial instead (see Section "Oscillators").

    snd-sine(t0, hz, sr, d) [SAL]
    (snd-sine t0 hz sr d) [LISP]
    This is a special case of snd-osc that always generates a sinusoid with initial phase of 0 degrees. You should use sine instead (see Section "Oscillators").

    snd-siosc(tables, sr, hz, t0, fm) [SAL]
    (snd-siosc tables sr hz t0 fm) [LISP]
    A Spectral Interpolation Oscillator with frequency modulation. The tables is a list of sounds and sample counts as follows: (table0 count1 table1 ... countN tableN). The initial waveform is given by table0, which is interpolated linearly to table1 over the first count1 samples. From count1 to count2 samples, the waveform is interpolated from table1 to table2, and so on. If more than countN samples are generated, tableN is used for the remainder of the sound. The duration and logical stop time of the sound is taken from fm, which specified frequency modulation (deviation) in Hertz. You should use siosc instead (see Section "Oscillators").

    Physical Model Functions

    These functions perform some sort of physically-based modeling synthesis.
    (snd-bandedwg freq bowpress-env preset sr)
    (snd-bandedwg freq bowpress-env preset sr) [LISP]
    A Banded Wave Guide Percussion instrument implemented in STK. The parameter freq is a FLONUM in Hz, bowpress-env is a SOUND that ranges from zero to one, preset is a FIXNUM, and sr is the desired sample rate in Hz. Currently, there are four presets: uniform-bar (0), tuned-bar (1), glass-harmonica (2), and tibetan-bowl (3). You should use wg-uniform-bar, wg-tuned-bar, wg-glass-harm, or wg-tibetan-bowl instead (see Section "Physical Models").

    snd-bowed(freq, bowpress-env, sr) [SAL]
    (snd-bowed freq bowpress-env sr) [LISP]
    A bowed string instrument implemented in STK. The freq is a FLONUM in Hertz, bowpress-env is a SOUND that ranges from z ero to one, and sr is the desired sample rate (a FLONUM). You should use bowed instead (see Section "Physical Models").

    snd-bowed-freq(freq, bowpress-env, freq-env, sr) [SAL]
    (snd-bowed-freq freq bowpress-env freq-env sr) [LISP]
    A bowed model just like snd-bowed but with an additional parameter for continuous frequency control. You should use bowed-freq instead (see Section "Physical Models").

    snd-clarinet(freq, breath-env, sr) [SAL]
    (snd-clarinet freq breath-env sr) [LISP]
    A clarinet model implemented in STK. The freq is a FLONUM in Hertz, breath-env is a SOUND that ranges from zero to one, and sr is the desired sample rate (a FLONUM). You should use clarinet instead (see Section "Physical Models").

    snd-clarinet-freq(freq, breath-env, freq-env, sr) [SAL]
    (snd-clarinet-freq freq breath-env freq-env sr) [LISP]
    A clarinet model just like snd-clarinet but with an additional parameter for continuous frequency control. You should use clarinet-freq instead (see Section "Physical Models").

    snd-clarinet-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, reed-stiffness, noise, sr) [SAL]
    (snd-clarinet-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise sr) [LISP]
    A clarinet model just like snd-clarinet-freq but with additional parameters for vibrato generation and continuous control of reed stiffness and breath noise. You should use clarinet-all instead (see Section "Physical Models").

    snd-flute(freq, breath-env, sr) [SAL]
    (snd-flute freq breath-env sr) [LISP]
    A flute implemented in STK. The freq is a FLONUM in Hertz, breath-env is a SOUND that ranges from zero to one, and sr is the desired sample rate (a FLONUM). You should use flute instead (see Section "Physical Models").

    snd-flute-freq(freq, breath-env, freq-env, sr) [SAL]
    (snd-flute-freq freq breath-env freq-env sr) [LISP]
    A flute model just like snd-flute but with an additional parameter for continuous frequency control. You should use flute-freq instead (see Section "Physical Models").

    snd-flute-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, jet-delay, noise, sr) [SAL]
    (snd-flute-all freq vibrato-freq vibrato-gain freq-env breath-env jet-delay noise sr) [LISP]
    A flute model just like snd-flute-freq but with additional parameters for vibrato generation and continuous control of breath noise. You should use flute-all instead (see Section "Physical Models").

    snd-mandolin(t0, freq, dur, body-size, detune, sr) [SAL]
    (snd-mandolin t0 freq dur body-size detune sr) [LISP]
    A plucked double-string instrument model implemented in STK. The t0 parameter is the starting time (in seconds), freq is a FLONUM in Hz, body-size and detune are FLONUMs, and sr is the desired sample rate. You should use mandolin instead (see Section "Physical Models").

    snd-modalbar(t0, freq, preset, dur, sr) [SAL]
    (snd-modalbar t0 freq preset dur sr) [LISP]
    Struck bar instrument model implemented in STK. The parameter t0 is the starting time (in seconds), freq is a FLONUM in Hz, preset is a FIXNUM ranging from 0 to 8, dur is a FLONUM that sets the duration (in seconds) and sr is the desired sample rate. You should use modalbar instead (see Section "Physical Models").

    snd-sax(freq, breath-env, sr) [SAL]
    (snd-sax freq breath-env sr) [LISP]
    A sax model implemented in STK. The freq is a FLONUM in Hertz, breath-env is a SOUND that ranges from zero to one, and sr is the desired sample rate (a FLONUM). You should use sax instead (see Section "Physical Models").

    snd-sax-freq(freq, freq-env, breath-env, sr) [SAL]
    (snd-sax-freq freq freq-env breath-env sr) [LISP]
    A sax model just like snd-sax but with an additional parameter for continuous frequency control. You should use sax-freq instead (see Section "Physical Models").

    snd-sax-all(freq, vibrato-freq, vibrato-gain, freq-env, breath-env, reed-stiffness, noise, blow-pos, reed-table-offset, sr) [SAL]
    (snd-sax-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise blow-pos reed-table-offset sr) [LISP]
    A sax model just like snd-sax-freq but with additional parameters for vibrato generation and continuous control of reed stiffness, breath noise, excitation position, and reed table offset. You should use sax-all instead (see Section "Physical Models").

    snd-sitar(t0, freq, dur, sr) [SAL]
    (snd-sitar t0 freq dur sr) [LISP]
    A sitar model implemented in STK. The parameter t0 is the starting time, freq is a FLONUM (in Hz), E dur sets the duration and sr is the sample rate (in Hz) of the resulting sound. You should use sitar instead (see Section "Physical Models").

    Sequence Support Functions

    The next two functions are used to implement Nyquist's seq construct.

    snd-seq(sound, closure) [SAL]
    (snd-seq sound closure) [LISP]
    This function returns sound until the logical stop time of sound. Then, the XLISP closure is evaluated, passing it the logical stop time of sound as a parameter. The closure must return a sound, which is then added to sound. (An add is used so that sound can continue past its logical stop if desired.) Do not call this function. See seq in Section "Combination and Time Structure".

    snd-multiseq(array, closure) [SAL]
    (snd-multiseq array closure) [LISP]
    This function is similar to snd-seq except the first parameter is a multichannel sound rather than a single sound. A multichannel sound is simply an XLISP array of sounds. An array of sounds is returned which is the sum of array and another array of sounds returned by closure. The closure is passed the logical stop time of the multichannel sound, which is the maximum logical stop time of any element of array. Do not call this function. See seq in Section "Combination and Time Structure".

    snd-trigger(s, closure) [SAL]
    (snd-trigger s closure) [LISP]
    This is one of the only ways in which a behavior instance can be created by changes in a signal. When s (a SOUND) makes a transition from less than or equal to zero to greater than zero, the closure, which takes a starting time parameter, is evaluated. The closure must return a SOUND. The sum of all these sounds is returned. If there are no sounds, the result will be zero. The stop time of the result is the maximum stop time of s and all sounds returned by the closure. The sample rate of the return value is the sample rate of s, and the sounds returned by the closure must all have that same sample rate. Do not call this function. See trigger in Section "Combination and Time Structure".

    An implementation note: There is no way to have snd-trigger return a multichannel sound. An alternative implementation would be a built-in function to scan ahead in a sound to find the time of the next zero crossing. This could be combined with some LISP code similar to seq to sum up instances of the closure. However, this would force arbitrary look-ahead and therefore would not work with real-time inputs, which was the motivation for snd-trigger in the first place.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/binomial-fig.gif0000644000175000000620000000762011466723256015775 0ustar stevestaffGIF89a)]w1!Software: Microsoft Office!,SMMM|||hhh` dihlp,tm|pH,Ȥrl:@tJZجV+zxz]5q|\Nrh%{?n$ :d%X$wd]cCuY [ybfR    ۢ" <]"#"  \qz@hDAB !Di8y&Xt@A:&e;g͒B@]]- Y#Kch;L` `;Ƴis$_)_Y~0B{2m@œiWQU5>I$)_hӅغzk2vTdA<}&;uŌU]Q#ǝZڕ@6f Z;#17RNimFepن-_}a&:"4( IX;ɍ@@ :x#l8*R1X &@䒍PBdTVٛXfYĔZv^%bfijnƉrv9z ~:& 6Fzgʘ_\́*jVjʪ2&kԭ&#*򊩯_+,+pF+Vkfv+.QiK=+kK:첦k' 7/ ZmW[ؤvmiikY֨mmFa:1V.FVMlr7kҐ 5Kad{/VQN;^rM/qOkwݮSycSMpx_F]߻Q5L/~8Fv8yb ^ܵ/Ul37~W;fKvrEZdUuQ>ڔaL_YuY6ږqYta.ژ\'/.?[cgrvrܹ;,V3{:}y_|W;Α?y7]g>y~ڗ7[=q'wnwxA5&g~Gspv~h:,XvHu~Z assM#t8+scW} 9085W7768^<  cH#zw뷁N؃wze8(~VxOzghb'5dqQXa8aЇ5oC`W('tȅ oyLJp65uph{w5mx}8xhzh4耏('߇3Xxo}7~؈HGx8XHH/:؉sx؅xX3XHhH'茛x1YPhe֘h3۸ih6؍7 ȐHNCl5n)3iɉr(H=v%ɈL&1iKvȒ'92W?GW5y8Y )3Z66ْ21b获WX(ɔa c_i9&cAYCBXɗ{}Mn8}ɑfj(FɓXVr)Cyw^)bɘYLɖ9I3)٘:IGIHYv;yDŹmɜɆ0z9yɘ9s Iٝ 9?嚞ٞP>xI~ 멖myrɞ I靻Yu jڟy阴 5㙠ɗ)ڔ))J0H #Z㈙vs ʝyI\y8,z> BZ]Y8'$.HfY6MPC{E:ZrcJe{i\6^Z8r:tZvzt>1) MʧNLCmʅfaCC"ju,+'yZ'Zqr&諸iҪZ&j`tc:sRQaG!-|Ŋ!+scZڨzULJjzZ꺮b)zZM"ڮڭ:ٺaw)KR7)ک:k{˪۱ +";a&$(K,$._"R4[%1{:K <۳B;D[F{H+!;nyquist-3.05/doc/part13.html0000644000175000000620000002642711537432671014754 0ustar stevestaffDeveloping and Debugging in Nyquist Previous Section | Next Section | Table of Contents | Index | Title Page

    Developing and Debugging in Nyquist

    There are a number of tools, functions, and techniques that can help to debug Nyquist programs. Since these are described in many places throughout this manual, this chapter brings together many suggestions and techniques for developing code and debugging. You really should read this chapter before you spend too much time with Nyquist. Many problems that you will certainly run into are addressed here.

    Debugging

    Probably the most important debugging tool is the backtrace. There are two kinds of backtrace: one for SAL, and one for Lisp.

    SAL mode is actually just an XLISP function (sal) that reads input and evaluates it. When SAL encounters an error, it normally prints a trace of the SAL stack (all the active functions written in SAL), exists the current command, and reads the next command.

    If you call XLISP functions from SAL, including most Nyquist sound processing functions, and an error occurs within these XLISP functions, you will only see the SAL function that called the XLISP functions listed in the stack trace. Sometimes you need more details.

    When Nyquist encounters an error when it is not running SAL, it normally suspends execution and prints an error message. To find out where in the program the error occurred and how you got there, start by typing (bt). This will print out the last several function calls and their arguments, which is usually sufficient to see what is going on.

    In order for (bt) to work, you must have a couple of global variables set: *tracenable* is ordinarily set to NIL. If it is true, then a backtrace is automatically printed when an error occurs; *breakenable* must be set to T, as it enables the execution to be suspended when an error is encountered. If *breakenable* is NIL (false), then execution stops when an error occurs but the stack is not saved and you cannot get a backtrace. Finally, bt is just a macro to save typing. The actual backtrace function is baktrace, which takes an integer argument telling how many levels to print. All of these things are set up by default when you start Nyquist.

    To get this XLISP backtrace behavior when SAL encounters an error, you need to have *breakenable* set while SAL is running. The best way to do this is to run within the NyquistIDE program, open the Preferences dialog, and choose the desired settings, e.g. "Enable XLISP break on SAL error."

    Since Nyquist sounds are executed with a lazy evaluation scheme, some errors are encountered when samples are being generated. In this case, it may not be clear which expression is in error. Sometimes, it is best to explore a function or set of functions by examining intermediate results. Any expression that yields a sound can be assigned to a variable and examined using one or more of: s-plot, snd-print-tree, and of course play. The snd-print-tree function prints a lot of detail about the inner representaion of the sound. Keep in mind that if you assign a sound to a global variable and then look at the samples (e.g. with play or s-plot), the samples will be retained in memory. At 4 bytes per sample, a big sound may use all of your memory and cause a crash.

    Another technique is to use low sample rates so that it is easier to plot results or look at samples directly. The calls:

    set-sound-srate(100)
    set-control-srate(100)
    
    set the default sample rates to 100, which is too slow for audio, but useful for examining programs and results. The function
    snd-samples(sound, limit)
    
    will convert up to limit samples from sound into a Lisp array. This is another way to look at results in detail.

    The trace function is sometimes useful. It prints the name of a function and its arguments everytimg the function is called, and the result is printed when the function exits. To trace the osc function, type:

    trace(osc)
    
    and to stop tracing, type untrace(osc).

    If a variable needs a value or a function is undefined, and if *breakenable* was set, you will get a prompt where you can fix the error (by setting the variable or loading the function definition) and keep going. At the debug (or break) prompt, your input must be in XLISP, not SAL syntax. Use (co), short for (continue) to reevaluate the variable or function and continue execution.

    When you finish debugging a particular call, you can "pop" up to the top level by typing (top), a short name for (top-level). There is a button named "Top" in the NyquistIDE that takes you back to the top level (ready to accept XLISP expressions), and another button named "SAL" that puts you back in SAL mode.

    Useful Functions

    grindef(name) [SAL]
    (grindef name) [LISP]
    Prints a formatted listing of a lisp function. This is often useful to quickly inspect a function without searching for it in source files. Do not forget to quote the name, e.g. (grindef 'prod).

    args(name) [SAL]
    (args name) [LISP]
    Similar to grindef, this function prints the arguments to a function. This may be faster than looking up a function in the documentation if you just need a reminder. For example, (args 'lp) prints "(LP S C)," which may help you to remember that the arguments are a sound (S) followed by the cutoff (C) frequency.

    The following functions are useful short-cuts that might have been included in XLISP. They are so useful that they are defined as part of Nyquist.

    incf(symbol) [SAL]
    (incf symbol) [LISP]
    Increment symbol by one. This is a macro, and symbol can be anything that can be set by setf. Typically, symbol is a variable: "(incf i)," but symbol can also be an array element: "(incf (aref myarray i))."

    decf(symbol) [SAL]
    (decf symbol) [LISP]
    Decrement symbol by one. (See incf, above.)

    push(val, lis) [SAL]
    (push val lis) [LISP]
    Push val onto lis (a Lisp list). This is a macro that is equivalent to writing (in Lisp) (setf lis (cons val lis)).

    pop(lis) [SAL]
    (pop lis) [LISP]
    Remove (pop) the first item from lis (a Lisp list). This is a macro that is equivalent to writing (in Lisp) (setf lis (cdr lis)). Note that the remaining list is returned, not the head of the list that has been popped. Retrieve the head of the list (i.e. the top of the stack) using first or, equivalently, car.

    The following macros are useful control constructs.

    while(test, expr1, expr2, ...) [SAL]
    (while test expr1 expr2 ...) [LISP]
    A conventional "while" loop. If test is true, evaluate expressions (expr1, expr2, etc.) and repeat. If test is false, return. This expression evaluates to NIL unless the expression (return expr) is evaluated, in which case the value of expr is returned. In SAL, the loop statement is preferred.

    when(test, action) [SAL]
    (when test action) [LISP]
    A conventional "if-then" statement. If test is true, action is evaluated and returned. Otherwise, NIL is returned. (Use if or cond to implement "if-then-else" and more complex conditional forms.

    It is often necessary to load a file only if it has not already been loaded. For example, the pianosyn library loads very slowly, so if some other file already loaded it, it would be good to avoid loading it again. How can you load a file once? Nyquist does not keep track of files that are loaded, but you must be loading a file to define some function, so the idea is to tell Nyquist "I require function from file"; if the function does not yet exist, Nyquist satisfies the requirement by loading the file.

    require-from(fnsymbol, filename [, path]) [SAL]
    (require-from fnsymbol filename [path]) [LISP]
    Tests whether fnsymbol, an unquoted function name, is defined. If not, filename, a STRING, is loaded. Normally fnsymbol is a function that will be called from within the current file, and filename is the file that defines fnsymbol. The path, if a STRING, is prepended to filename. If path is t (true), then the directory of the current file is used as the path.

    Sometimes it is important to load files relative to the current file. For example, the lib/piano.lsp library loads data files from the lib/piano directory, but how can we find out the full path of lib? The solution is:

    current-path() [SAL]
    (current-path) [LISP]
    Returns the full path name of the file that is currently being loaded (see load). Returns NIL if no file is being loaded.

    Finally, there are some helpful math functions:

    real-random(from, to) [SAL]
    (real-random from to) [LISP]
    Returns a random FLONUM between from and to. (See also rrandom, which is equivalent to (real-random 0 1)).

    power(x, y) [SAL]
    (power x y) [LISP]
    Returns x raised to the y power.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/part16.html0000644000175000000620000006613611537432671014760 0ustar stevestaffPrevious Section | Next Section | Table of Contents | Index | Title Page
    Appendix 1: Extending Nyquist

    Appendix 1: Extending Nyquist

    WARNING: Nyquist sound functions look almost like a human wrote them; they even have a fair number of comments for human readers. Don't be fooled: virtually all Nyquist functions are written by a special translator. If you try to write a new function by hand, you will probably not succeed, and even if you do, you will waste a great deal of time. (End of Warning.)

    Translating Descriptions to C Code

    The translator code used to extend Nyquist resides in the trnsrc directory. This directory also contains a special init.lsp, so if you start XLisp or Nyquist in this directory, it will automatically read init.lsp, which in turn will load the translator code (which resides in several files).

    Also in the trnsrc directory are a number of .alg files, which contain the source code for the translator (more on these will follow), and a number of corresponding .h and .c files.

    To translate a .alg file to .c and .h files, you start XLisp or Nyquist in the trnsrc directory and type

    (translate "prod")
    
    where "prod" should really be replaced by the filename (without a suffix) you want to translate. Be sure you have a saved, working copy of Nyquist or Xlisp before you recompile!

    Note: On the Macintosh, just run Nyquist out of the runtime directory and then use the Load menu command to load init.lsp from the trnsrc directory. This will load the translation code and change Nyquist's current directory to trnsrc so that commands like (translate "prod") will work.

    Rebuilding Nyquist

    After generating prod.c and prod.h, you need to recompile Nyquist. For Unix systems, you will want to generate a new Makefile. Modify transfiles.lsp in your main Nyquist directory, run Xlisp or Nyquist and load makefile.lsp. Follow the instructions to set your machine type, etc., and execute (makesrc) and (makefile).

    Accessing the New Function

    The new Lisp function will generally be named with a snd- prefix, e.g. snd-prod. You can test this by running Nyquist. Debugging is usually a combination of calling the code from within the interpreter, reading the generated code when things go wrong, and using a C debugger to step through the inner loop of the generated code. An approach I like is to set the default sample rate to 10 hertz. Then, a one-second sound has only 10 samples, which are easy to print and study on a text console.

    For some functions, you must write some Lisp code to impose ordinary Nyquist behaviors such as stretching and time shifting. A good approach is to find some structurally similar functions and see how they are implemented. Most of the Lisp code for Nyquist is in nyquist.lsp.

    Finally, do not forget to write up some documentation. Also, contributions are welcome. Send your .alg file, documentation, Lisp support functions for nyquist.lsp, and examples or test programs to rbd@cs.cmu.edu. I will either put them in the next release or make them available at a public ftp site.

    Why Translation?

    Many of the Nyquist signal processing operations are similar in form, but they differ in details. This code is complicated by many factors: Nyquist uses lazy evaluation, so the operator must check to see that input samples are available before trying to access them. Nyquist signals can have different sample rates, different block sizes, different block boundaries, and different start times, all of which must be taken into account. The number of software tests is enormous. (This may sound like a lot of overhead, but the overhead is amortized over many iterations of the inner loop. Of course setting up the inner loop to run efficiently is one more programming task.)

    The main idea behind the translation is that all of the checks and setup code are similar and relatively easy to generate automatically. Programmers often use macros for this sort of task, but the C macro processor is too limited for the complex translation required here. To tell the translator how to generate code, you write .alg files, which provide many details about the operation in a declarative style. For example, the code generator can make some optimizations if you declare that two input signals are commutative (they can be exchanged with one another). The main part of the .alg file is the inner loop which is the heart of the signal processing code.

    Writing a .alg File

    WARNING: Translation relies heavily on string substitution, which is fragile. In particular, variables with names that are substrings of other variables will cause problems. For example if you declare STATE variables "phase" and "iphase", then the translator will globally substitute "phase_reg" for "phase", converting "phase" to "phase_reg" and iphase" to "iphase_reg". Then it will substitute "iphase_reg" for iphase" which will convert the existing "iphase_reg" to "iphase_reg_reg". This will be confusing and will not compile. (End of WARNING)

    To give you some idea how functions are specified, here is the specification for snd-prod, which generates over 250 lines of C code:

    (PROD-ALG
      (NAME "prod")
      (ARGUMENTS ("sound_type" "s1") ("sound_type" "s2"))
      (START (MAX s1 s2))
      (COMMUTATIVE (s1 s2))
      (INNER-LOOP "output = s1 * s2")
      (LINEAR s1 s2)
      (TERMINATE (MIN s1 s2))
      (LOGICAL-STOP (MIN s1 s2))
    )
    
    A .alg file is always of the form:
    (name
      (attribute value)
      (attribute value)
      ...
    )
    
    There should be just one of these algorithms descriptions per file. The name field is arbitrary: it is a Lisp symbol whose property list is used to save the following attribute/value pairs. There are many attributes described below. For more examples, see the .alg files in the trnsrc directory.

    Understanding what the attributes do is not easy, so here are three recommendations for implementors. First, if there is an existing Nyquist operator that is structurally similar to something you want to implement, make a copy of the corresponding .alg file and work from there. In some cases, you can merely rename the parameters and substitute a new inner loop. Second, read the generated code, especially the generated inner loop. It may not all make sense, but sometimes you can spot obvious errors and work your way back to the error in the .alg file. Third, if you know where something bad is generated, see if you can find where the code is generated. (The code generator files are listed in init.lsp.) This code is poorly written and poorly documented, but in some cases it is fairly straightforward to determine what attribute in the .alg file is responsible for the erroneous output.

    Attributes

    Here are the attributes used for code generation. Attributes and values may be specified in any order.
    (NAME "string")
    specifies a base name for many identifiers. In particular, the generated filenames will be string.c and string.h, and the XLisp function generated will be snd-string.

    (ARGUMENTS arglist)
    describes the arguments to be passed from XLisp. Arglist has the form: (type1 name1) (type2 name2) ..., where type and name are strings in double quotes, e.g. ("sound_type" "s") specifies a SOUND parameter named s. Note that arglist is not surrounded by parentheses. As seen in this example, the type names and parameter names are C identifiers. Since the parameters are passed in from XLisp, they must be chosen from a restricted set. Valid type names are: "sound_type", "rate_type", "double", "long", "string", and "LVAL".

    (STATE statelist)
    describes additional state (variables) needed to perform the computation. A statelist is similar to an arglist (see ARGUMENTS above), and has the form: (type1 name1 init1 [TEMP]) (type2 name2 init2 [TEMP]) .... The types and names are as in arglist, and the "inits" are double-quoted initial values. Initial values may be any C expression. State is initialized in the order implied by statelist when the operation is first called from XLisp. If TEMP is omitted the state is preserved in a structure until the sound computation completes. Otherwise, the state variable only exists at state initialization time.

    (INNER-LOOP innerloop-code)
    describes the inner loop, written as C code. The innerloop-code is in double quotes, and may extend over multiple lines. To make generated code extra-beautiful, prefix each line of innerloop-code with 12 spaces. Temporary variables should not be declared at the beginning of innerloop-code. Use the INNER-LOOP-LOCALS attribute instead. Within innerloop-code, each ARGUMENT of type sound_type must be referenced exactly one time. If you need to use a signal value twice, assign it once to a temporary and use the temporary twice. The inner loop must also assign one time to the psuedo-variable output. The model here is that the name of a sound argument denotes the value of the corresponding signal at the current output sample time. The inner loop code will be called once for each output sample. In practice, the code generator will substitute some expression for each signal name. For example, prod.alg specifies
    (INNER-LOOP "output = s1 * s2")
    (s1 and s2 are ARGUMENTS.) This expands to the following inner loop in prod.c:
    *out_ptr_reg++ = *s1_ptr_reg++ * *s2_ptr_reg++;
    In cases where arguments have different sample rates, sample interpolation is in-lined, and the expressions can get very complex. The translator is currently very simple-minded about substituting access code in the place of parameter names, and this is a frequent source of bugs. Simple string substitution is performed, so you must not use a parameter or state name that is a substring of another. For example, if two sound parameters were named s and s2, the translator might substitute for "s" in two places rather than one. If this problem occurs, you will almost certainly get a C compiler syntax error. The fix is to use "more unique" parameter and state variable names.

    (INNER-LOOP-LOCALS "innerloop-code")
    The innerloop-code contains C declarations of local variables set and referenced in the inner loop.

    (SAMPLE-RATE "expr")
    specifies the output sample rate; expr can be any C expression, including a parameter from the ARGUMENTS list. You can also write (SAMPLE-RATE (MAX name1 name2 ...)) where names are unquoted names of arguments.

    (SUPPORT-HEADER "c-code")
    specifies arbitrary C code to be inserted in the generated .h file. The code typically contains auxiliarly function declarations and definitions of constants.

    (SUPPORT-FUNCTIONS "c-code")
    specifies arbitrary C code to be inserted in the generated .c file. The code typically contains auxiliarly functions and definitions of constants.

    (FINALIZATION "c-code")
    specifies code to execute when the sound has been fully computed and the state variables are about to be decallocated. This is the place to deallocate buffer memory, etc.

    (CONSTANT "name1" "name2" ...)
    specifies state variables that do not change value in the inner loop. The values of state variables are loaded into registers before entering the inner loop so that access will be fast within the loop. On exiting the inner loop, the final register values are preserved in a "suspension" structure. If state values do not change in the inner loop, this CONSTANT declaration can eliminate the overhead of storing these registers.

    (START spec)
    specifies when the output sound should start (a sound is zero and no processing is done before the start time). The spec can take several forms: (MIN name1 name2 ...) means the start time is the minimum of the start times of input signals name1, name2, .... Note that these names are not quoted.

    (TERMINATE spec)
    specifies when the output sound terminates (a sound is zero after this termination time and no more samples are computed). The spec can take several forms: (MIN name1 name2 ...) means the terminate time is the minimum of the terminate times of input arguments name1, name2, .... Note that these names are not quoted. To terminate at the time of a single argument s1, specify (MIN s1). To terminate after a specific duration, use (AFTER "c-expr"), where c-expr is a C variable or expression. To terminate at a particular time, use (AT "c-expr"). spec may also be COMPUTED, which means to use the maximum sample rate of any input signal.

    (LOGICAL-STOP spec)
    specifies the logical stop time of the output sound. This spec is just like the one for TERMINATE. If no LOGICAL-STOP attribute is present, the logical stop will coincide with the terminate time.

    (ALWAYS-SCALE name1 name2 ...)
    says that the named sound arguments (not in quotes) should always be multiplied by a scale factor. This is a space-time tradeoff. When Nyquist sounds are scaled, the scale factor is merely stored in a structure. It is the responsibility of the user of the samples to actually scale them (unless the scale factor is exactly 1.0). The default is to generate code with and without scaling and to select the appropriate code at run time. If there are N signal inputs, this will generate 2^(N) versions of the code. To avoid this code explosion, use the ALWAYS-SCALE attribute.

    (INLINE-INTERPOLATION T)
    specifies that sample rate interpolation should be performed in-line in the inner loop. There are two forms of sample rate interpolation. One is intended for use when the rate change is large and many points will be interpolated. This form uses a divide instruction and some setup at the low sample rate, but the inner loop overhead is just an add. The other form, intended for less drastic sample rate changes, performs interpolation with 2 multiplies and several adds per sample at the high sample rate. Nyquist generates various inner loops and selects the appropriate one at run-time. If INLINE-INTERPOLATION is not set, then much less code is generated and interpolation is performed as necessary by instantiating a separate signal processing operation.

    (STEP-FUNCTION name1 name2 ...)
    Normally all argument signals are linearly interpolated to the output sample rate. The linear interpolation can be turned off with this attribute. This is used, for example, in Nyquist variable filters so that filter coefficients are computed at low sample rates. In fact, this attribute was added for the special case of filters.

    (DEPENDS spec1 spec2 ...)
    Specifies dependencies. This attribute was also introduced to handle the case of filter coefficients (but may have other applications.) Use it when a state variable is a function of a potentially low-sample-rate input where the input is in the STEP-FUNCTION list. Consider a filter coefficient that depends upon an input signal such as bandwidth. In this case, you want to compute the filter coefficient only when the input signal changes rather than every output sample, since output may occur at a much higher sample rate. A spec is of the form
    ("name" "arg" "expr" [TEMP "type"])
    which is interpreted as follows: name depends upon arg; when arg changes, recompute expr and assign it to name. The name must be declared as a STATE variable unless TEMP is present, in which case name is not preserved and is used only to compute other state. Variables are updated in the order of the DEPENDS list.

    (FORCE-INTO-REGISTER name1 name2 ...)
    causes name1, name2, ... to be loaded into registers before entering the inner loop. If the inner loop references a state variable or argument, this happens automatically. Use this attribute only if references are "hidden" in a #define'd macro or referenced in a DEPENDS specification.

    (NOT-REGISTER name1 name2 ...)
    specifies state and arguments that should not be loaded into registers before entering an inner loop. This is sometimes an optimization for infrequently accessed state.

    (NOT-IN-INNER-LOOP "name1" "name2" ...)
    says that certain arguments are not used in the inner loop. Nyquist assumes all arguments are used in the inner loop, so specify them here if not. For example, tables are passed into functions as sounds, but these sounds are not read sample-by-sample in the inner loop, so they should be listed here.

    (MAINTAIN ("name1" "expr1") ("name2" "expr2") ... )
    Sometimes the IBM XLC compiler generates better loop code if a variable referenced in the loop is not referenced outside of the loop after the loop exit. Technically, optimization is better when variables are dead upon loop exit. Sometimes, there is an efficient way to compute the final value of a state variable without actually referencing it, in which case the variable and the computation method are given as a pair in the MAINTAIN attribute. This suppresses a store of the value of the named variable, making it a dead variable. Where the store would have been, the expression is computed and assigned to the named variable. See partial.alg for an example. This optimization is never necessary and is only for fine-tuning.

    (LINEAR name1 name2 ...)
    specifies that named arguments (without quotes) are linear with respect to the output. What this really means is that it is numerically OK to eliminate a scale factor from the named argument and store it in the output sound descriptor, avoiding a potential multiply in this inner loop. For example, both arguments to snd-prod (signal multiplication) are "linear." The inner loop has a single multiplication operator to multiply samples vs. a potential 3 multiplies if each sample were also scaled. To handle scale factors on the input signals, the scale factors are automatically multiplied and the product becomes the scale factor of the resulting output. (This effectively "passes the buck" to some other, or perhaps more than one, signal processing function, which is not always optimal. On the other hand, it works great if you multiply a number of scaled signals together: all the scale factors are ultimately handled with a single multiply.)

    (INTERNAL-SCALING name1 name2 ...)
    indicates that scaling is handled in code that is hidden from the code generator for name1, name2, ..., which are sound arguments. Although it is the responsibility of the reader of samples to apply any given scale factor, sometimes scaling can be had for free. For example, the snd-recip operation computes the reciprocal of the input samples by peforming a division. The simple approach would be to specify an inner loop of output = 1.0/s1, where s1 is the input. With scaling, this would generate an inner loop something like this:
    *output++ = 1.0 / (s1_scale_factor * *s1++);
    but a much better approach would be the following:
    *output++ = my_scale_factor / *s1++
    where my_scale_factor is initialized to 1.0 / s1->scale. Working backward from the desired inner loop to the .alg inner loop specification, a first attempt might be to specify:
    (INNER-LOOP "output = my_scale_factor / s1")
    but this will generate the following:
    *output++=my_scale_factor/(s1_scale_factor * *s1++);
    Since the code generator does not know that scaling is handled elsewhere, the scaling is done twice! The solution is to put s1 in the INTERNAL-SCALING list, which essentially means "I've already incorporated scaling into the algorithm, so suppress the multiplication by a scale factor."

    (COMMUTATIVE (name1 name2 ...))
    specifies that the results will not be affected by interchanging any of the listed arguments. When arguments are commutative, Nyquist rearranges them at run-time into decreasing order of sample rates. If interpolation is in-line, this can dramatically reduce the amount of code generated to handle all the different cases. The prime example is prod.alg.

    (TYPE-CHECK "code")
    specifies checking code to be inserted after argument type checking at initialization time. See downproto.alg for an example where a check is made to guarantee that the output sample rate is not greater than the input sample rate. Otherwise an error is raised.

    Generated Names

    The resulting .c file defines a number of procedures. The procedures that do actual sample computation are named something like name_interp-spec_FETCH, where name is the NAME attribute from the .alg file, and interp-spec is an interpolation specification composed of a string of the following letters: n, s, i, and r. One letter corresponds to each sound argument, indicating no interpolation (r), scaling only (s), ordinary linear interpolation with scaling (i), and ramp (incremental) interpolation with scaling (r). The code generator determines all the combinations of n, s, i, and r that are necessary and generates a separate fetch function for each.

    Another function is name_toss_fetch, which is called when sounds are not time-aligned and some initial samples must be discarded from one or more inputs.

    The function that creates a sound is snd_make_name. This is where state allocation and initialization takes place. The proper fetch function is selected based on the sample rates and scale factors of the sound arguments, and a sound_type is returned.

    Since Nyquist is a functional language, sound operations are not normally allowed to modify their arguments through side effects, but even reading samples from a sound_type causes side effects. To hide these from the Nyquist programmer, sound_type arguments are first copied (this only copies a small structure. The samples themselves are on a shared list). The function snd_name performs the necessary copies and calls snd_make_name. It is the snd_name function that is called by XLisp. The XLisp name for the function is SND-NAME. Notice that the underscore in C is converted to a dash in XLisp. Also, XLisp converts identifiers to upper case when they are read, so normally, you would type snd-name to call the function.

    Scalar Arguments

    If you want the option of passing either a number (scalar) or a signal as one of the arguments, you have two choices, neither of which is automated. Choice 1 is to coerce the constant into a signal from within XLisp. The naming convention would be to DEFUN a new function named NAME or S-NAME for ordinary use. The NAME function tests the arguments using XLisp functions such as TYPE-OF, NUMBERP, and SOUNDP. Any number is converted to a SOUND, e.g. using CONST. Then SND-NAME is called with all sound arguments. The disadvantage of this scheme is that scalars are expanded into a sample stream, which is slower than having a special inner loop where the scalar is simply kept in a register, avoiding loads, stores, and addressing overhead.

    Choice 2 is to generate a different sound operator for each case. The naming convention here is to append a string of c's and v's, indicating constant (scalar) or variable (signal) inputs. For example, the reson operator comes in four variations: reson, resoncv, resonvc, and resonvv. The resonvc version implements a resonating filter with a variable center frequency (a sound type) and a constant bandwidth (a FLONUM). The RESON function in Nyquist is an ordinary Lisp function that checks types and calls one of SND-RESON, SND-RESONCV, SND-RESONVC, or SND-RESONVV.

    Since each of these SND- functions performs further selection of implementation based on sample rates and the need for scaling, there are 25 different functions for computing RESON! So far, however, Nyquist is smaller than Common Lisp and it's about half the size of Microsoft Word. Hopefully, exponential growth in memory density will outpace linear (as a function of programming effort) growth of Nyquist.


    Previous Section | Next Section | Table of Contents | Index | Title Page nyquist-3.05/doc/fig5.gif0000644000175000000620000000277610144436365014273 0ustar stevestaffGIF87a , ڋ޼H扦ʶ L ĢL*̦ JԪjܮ N (8HXhx)9IYiy *:JZjz ;'K{{g \6ll 6L,=}MU Tm N[n>.tO3_osſO ,P ;,'aRE7qVEt̘j@_<%23 OJi$.;$rň5%T(N=EҢ: c)BNYA!uj3Ȫ `z glɲ5آs9ܾ΁\F0S&Gx󐰗~9hw1ȎFq+Y=i@.<ӧU͆u<,[h{rp3\z̛;=ԫ[ܻ{>g%'wS8uoO5x^w}5&`%E]6闁f &vaP҂`}h \H3":HO0HcgF9#㎸4.#/fEN3($N>dQ*Cwe^~ fbIfffjfn grIgvމgzg~ hJhڡf(5Dcm-j.(Pr&ig 4)"XIA; !nYc͑aTNi%y1wR .kYL+쉣*kyBΰn$3I-`v[kºd+=L"/Dp /p? qOLq_qo1Sw< <2^%v2|l,K&,s&ּ8wq[s1D`+MFLQ},QW+P5MPȭ6ksf*p = wgݮ<{]j xz|?uG;.^t@A^8c%yL9ykb靎D^z{;lzj<{j-7}ɯV|XWo_S-=4|3~WtL5v/:?,G p,h h/]CPص@q#QQ@~A!h`N?L߭¹0&,tV@Hh/0dWCq9!?RD#roJEjXh ꢱkKd!u*0ʊHN^ŷ4/zhTjXkqb !$9I-;qJV\bH*A J[$Cꐓ+J$(Eɾ}Rb䤣S6+:%PLZT,:vIƵo▼!.`>3[:lf ps,9ωtsl; xs=i;nyquist-3.05/nyqstk/0002755000175000000620000000000011537433122013517 5ustar stevestaffnyquist-3.05/nyqstk/src/0002755000175000000620000000000011537433122014306 5ustar stevestaffnyquist-3.05/nyqstk/src/DelayL.cpp0000644000175000000620000000655011466723256016203 0ustar stevestaff/***************************************************/ /*! \class DelayL \brief STK linear interpolating delay line class. This Delay subclass implements a fractional- length digital delay-line using first-order linear interpolation. A fixed maximum length of 4095 and a delay of zero is set using the default constructor. Alternatively, the delay and maximum length can be set during instantiation with an overloaded constructor. Linear interpolation is an efficient technique for achieving fractional delay lengths, though it does introduce high-frequency signal attenuation to varying degrees depending on the fractional delay setting. The use of higher order Lagrange interpolators can typically improve (minimize) this attenuation characteristic. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "DelayL.h" using namespace Nyq; DelayL :: DelayL() : Delay() { doNextOut_ = true; } DelayL :: DelayL(StkFloat delay, unsigned long maxDelay) { if ( delay < 0.0 || maxDelay < 1 ) { errorString_ << "DelayL::DelayL: delay must be >= 0.0, maxDelay must be > 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( delay > (StkFloat) maxDelay ) { errorString_ << "DelayL::DelayL: maxDelay must be > than delay argument!"; handleError( StkError::FUNCTION_ARGUMENT ); } // Writing before reading allows delays from 0 to length-1. if ( maxDelay > inputs_.size()-1 ) { inputs_.resize( maxDelay+1 ); this->clear(); } inPoint_ = 0; this->setDelay(delay); doNextOut_ = true; } DelayL :: ~DelayL() { } void DelayL :: setDelay(StkFloat delay) { StkFloat outPointer; if ( delay > inputs_.size() - 1 ) { // The value is too big. errorString_ << "DelayL::setDelay: argument (" << delay << ") too big ... setting to maximum!"; handleError( StkError::WARNING ); // Force delay to maxLength outPointer = inPoint_ + 1.0; delay_ = inputs_.size() - 1; } else if (delay < 0 ) { errorString_ << "DelayL::setDelay: argument (" << delay << ") less than zero ... setting to zero!"; handleError( StkError::WARNING ); outPointer = inPoint_; delay_ = 0; } else { outPointer = inPoint_ - delay; // read chases write delay_ = delay; } while (outPointer < 0) outPointer += inputs_.size(); // modulo maximum length outPoint_ = (long) outPointer; // integer part if ( outPoint_ == inputs_.size() ) outPoint_ = 0; alpha_ = outPointer - outPoint_; // fractional part omAlpha_ = (StkFloat) 1.0 - alpha_; } StkFloat DelayL :: getDelay(void) const { return delay_; } StkFloat DelayL :: nextOut(void) { if ( doNextOut_ ) { // First 1/2 of interpolation nextOutput_ = inputs_[outPoint_] * omAlpha_; // Second 1/2 of interpolation if (outPoint_+1 < inputs_.size()) nextOutput_ += inputs_[outPoint_+1] * alpha_; else nextOutput_ += inputs_[0] * alpha_; doNextOut_ = false; } return nextOutput_; } StkFloat DelayL :: computeSample( StkFloat input ) { inputs_[inPoint_++] = input; // Increment input pointer modulo length. if (inPoint_ == inputs_.size()) inPoint_ = 0; outputs_[0] = nextOut(); doNextOut_ = true; // Increment output pointer modulo length. if (++outPoint_ == inputs_.size()) outPoint_ = 0; return outputs_[0]; } nyquist-3.05/nyqstk/src/FileWvIn.cpp0000644000175000000620000001360111466723256016507 0ustar stevestaff/***************************************************/ /*! \class FileWvIn \brief STK audio file input class. This class inherits from WvIn. It provides a "tick-level" interface to the FileRead class. It also provides variable-rate "playback" functionality. Audio file support is provided by the FileRead class. Linear interpolation is used for fractional "read rates". FileWvIn supports multi-channel data. It is important to distinguish the tick() methods, which return samples produced by averaging across sample frames, from the tickFrame() methods, which return references to multi-channel sample frames. FileWvIn will either load the entire content of an audio file into local memory or incrementally read file data from disk in chunks. This behavior is controlled by the optional constructor arguments \e chunkThreshold and \e chunkSize. File sizes greater than \e chunkThreshold (in sample frames) will be read incrementally in chunks of \e chunkSize each (also in sample frames). When the end of a file is reached, subsequent calls to the tick() functions return zero-valued data. See the FileRead class for a description of the supported audio file formats. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "FileWvIn.h" #include using namespace Nyq; FileWvIn :: FileWvIn( unsigned long chunkThreshold, unsigned long chunkSize ) : finished_(true), interpolate_(false), time_(0.0), chunkThreshold_(chunkThreshold), chunkSize_(chunkSize) { } FileWvIn :: FileWvIn( std::string fileName, bool raw, bool doNormalize, unsigned long chunkThreshold, unsigned long chunkSize ) : finished_(true), interpolate_(false), time_(0.0), chunkThreshold_(chunkThreshold), chunkSize_(chunkSize) { openFile( fileName, raw, doNormalize ); } FileWvIn :: ~FileWvIn() { this->closeFile(); } void FileWvIn :: closeFile( void ) { if ( file_.isOpen() ) file_.close(); finished_ = true; } void FileWvIn :: openFile( std::string fileName, bool raw, bool doNormalize ) { // Call close() in case another file is already open. this->closeFile(); // Attempt to open the file ... an error might be thrown here. file_.open( fileName, raw ); // Determine whether chunking or not. if ( file_.fileSize() > chunkThreshold_ ) { chunking_ = true; chunkPointer_ = 0; data_.resize( chunkSize_, file_.channels() ); if ( doNormalize ) normalizing_ = true; else normalizing_ = false; } else { chunking_ = false; data_.resize( (size_t) file_.fileSize(), file_.channels() ); } // Load all or part of the data. file_.read( data_, 0, doNormalize ); // Resize our lastOutputs container. lastOutputs_.resize( 1, file_.channels() ); // Set default rate based on file sampling rate. this->setRate( data_.dataRate() / Stk::sampleRate() ); if ( doNormalize & !chunking_ ) this->normalize(); this->reset(); } void FileWvIn :: reset(void) { time_ = (StkFloat) 0.0; for ( unsigned int i=0; inormalize( 1.0 ); } // Normalize all channels equally by the greatest magnitude in all of the data. void FileWvIn :: normalize( StkFloat peak ) { // When chunking, the "normalization" scaling is performed by FileRead. if ( chunking_ ) return; size_t i; StkFloat max = 0.0; for ( i=0; i max ) max = (StkFloat) fabs((double) data_[i]); } if (max > 0.0) { max = 1.0 / max; max *= peak; for ( i=0; i file_.fileSize() - 1.0 ) { time_ = file_.fileSize() - 1.0; for ( unsigned int i=0; i (StkFloat) ( file_.fileSize() - 1.0 ) ) { for ( unsigned int i=0; i (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) { while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame if ( chunkPointer_ < 0 ) chunkPointer_ = 0; } while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) // at end of file chunkPointer_ = file_.fileSize() - chunkSize_; } // Load more data. file_.read( data_, chunkPointer_, normalizing_ ); } // Adjust index for the current buffer. tyme -= chunkPointer_; } if ( interpolate_ ) { for ( unsigned int i=0; i using namespace Nyq; WvIn :: WvIn() { } WvIn :: ~WvIn() { } StkFloat WvIn :: lastOut( void ) const { if ( lastOutputs_.empty() ) return 0.0; if ( lastOutputs_.size() == 1 ) return lastOutputs_[0]; StkFloat output = 0.0; for ( unsigned int i=0; i= frames.channels() ) { errorString_ << "WvIn::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( frames.channels() == 1 ) { for ( unsigned int i=0; icomputeFrame(); for ( j=0; jcomputeFrame(); index = i; for ( j=0; jsetDelay( 0.5 ); apInput_ = 0.0; doNextOut_ = true; } DelayA :: DelayA(StkFloat delay, unsigned long maxDelay) { if ( delay < 0.0 || maxDelay < 1 ) { errorString_ << "DelayA::DelayA: delay must be >= 0.0, maxDelay must be > 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( delay > (StkFloat) maxDelay ) { errorString_ << "DelayA::DelayA: maxDelay must be > than delay argument!"; handleError( StkError::FUNCTION_ARGUMENT ); } // Writing before reading allows delays from 0 to length-1. if ( maxDelay > inputs_.size()-1 ) { inputs_.resize( maxDelay+1 ); this->clear(); } inPoint_ = 0; this->setDelay(delay); apInput_ = 0.0; doNextOut_ = true; } DelayA :: ~DelayA() { } void DelayA :: clear() { Delay::clear(); apInput_ = 0.0; } void DelayA :: setDelay(StkFloat delay) { StkFloat outPointer; unsigned long length = inputs_.size(); if ( delay > inputs_.size() - 1 ) { // The value is too big. errorString_ << "DelayA::setDelay: argument (" << delay << ") too big ... setting to maximum!"; handleError( StkError::WARNING ); // Force delay to maxLength outPointer = inPoint_ + 1.0; delay_ = length - 1; } else if (delay < 0.5) { errorString_ << "DelayA::setDelay: argument (" << delay << ") less than 0.5 not possible!"; handleError( StkError::WARNING ); outPointer = inPoint_ + 0.4999999999; delay_ = 0.5; } else { outPointer = inPoint_ - delay + 1.0; // outPoint chases inpoint delay_ = delay; } if (outPointer < 0) outPointer += length; // modulo maximum length outPoint_ = (long) outPointer; // integer part if ( outPoint_ == length ) outPoint_ = 0; alpha_ = 1.0 + outPoint_ - outPointer; // fractional part if (alpha_ < 0.5) { // The optimal range for alpha is about 0.5 - 1.5 in order to // achieve the flattest phase delay response. outPoint_ += 1; if (outPoint_ >= length) outPoint_ -= length; alpha_ += (StkFloat) 1.0; } coeff_ = ((StkFloat) 1.0 - alpha_) / ((StkFloat) 1.0 + alpha_); // coefficient for all pass } StkFloat DelayA :: getDelay(void) const { return delay_; } StkFloat DelayA :: nextOut(void) { if ( doNextOut_ ) { // Do allpass interpolation delay. nextOutput_ = -coeff_ * outputs_[0]; nextOutput_ += apInput_ + (coeff_ * inputs_[outPoint_]); doNextOut_ = false; } return nextOutput_; } StkFloat DelayA :: computeSample( StkFloat input ) { inputs_[inPoint_++] = input; // Increment input pointer modulo length. if (inPoint_ == inputs_.size()) inPoint_ = 0; outputs_[0] = nextOut(); doNextOut_ = true; // Save the allpass input and increment modulo length. apInput_ = inputs_[outPoint_++]; if (outPoint_ == inputs_.size()) outPoint_ = 0; return outputs_[0]; } nyquist-3.05/nyqstk/src/BiQuad.cpp0000644000175000000620000000465111466723256016176 0ustar stevestaff/***************************************************/ /*! \class BiQuad \brief STK biquad (two-pole, two-zero) filter class. This protected Filter subclass implements a two-pole, two-zero digital filter. A method is provided for creating a resonance in the frequency response while maintaining a constant filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "BiQuad.h" #include using namespace Nyq; BiQuad :: BiQuad() : Filter() { std::vector b(3, 0.0); std::vector a(3, 0.0); b[0] = 1.0; a[0] = 1.0; Filter::setCoefficients( b, a ); } BiQuad :: ~BiQuad() { } void BiQuad :: clear(void) { Filter::clear(); } void BiQuad :: setB0(StkFloat b0) { b_[0] = b0; } void BiQuad :: setB1(StkFloat b1) { b_[1] = b1; } void BiQuad :: setB2(StkFloat b2) { b_[2] = b2; } void BiQuad :: setA1(StkFloat a1) { a_[1] = a1; } void BiQuad :: setA2(StkFloat a2) { a_[2] = a2; } void BiQuad :: setResonance(StkFloat frequency, StkFloat radius, bool normalize) { a_[2] = radius * radius; a_[1] = -2.0 * radius * cos(TWO_PI * frequency / Stk::sampleRate()); if ( normalize ) { // Use zeros at +- 1 and normalize the filter peak gain. b_[0] = 0.5 - 0.5 * a_[2]; b_[1] = 0.0; b_[2] = -b_[0]; } } void BiQuad :: setNotch(StkFloat frequency, StkFloat radius) { // This method does not attempt to normalize the filter gain. b_[2] = radius * radius; b_[1] = (StkFloat) -2.0 * radius * cos(TWO_PI * (double) frequency / Stk::sampleRate()); } void BiQuad :: setEqualGainZeroes() { b_[0] = 1.0; b_[1] = 0.0; b_[2] = -1.0; } void BiQuad :: setGain(StkFloat gain) { Filter::setGain(gain); } StkFloat BiQuad :: getGain(void) const { return Filter::getGain(); } StkFloat BiQuad :: lastOut(void) const { return Filter::lastOut(); } StkFloat BiQuad :: computeSample( StkFloat input ) { inputs_[0] = gain_ * input; outputs_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] + b_[2] * inputs_[2]; outputs_[0] -= a_[2] * outputs_[2] + a_[1] * outputs_[1]; inputs_[2] = inputs_[1]; inputs_[1] = inputs_[0]; outputs_[2] = outputs_[1]; outputs_[1] = outputs_[0]; return outputs_[0]; } StkFloat BiQuad :: tick( StkFloat input ) { return this->computeSample( input ); } StkFrames& BiQuad :: tick( StkFrames& frames, unsigned int channel ) { return Filter::tick( frames, channel ); } nyquist-3.05/nyqstk/src/ModalBar.cpp0000644000175000000620000001403011466723256016502 0ustar stevestaff/***************************************************/ /*! \class ModalBar \brief STK resonant bar instrument class. This class implements a number of different struck bar instruments. It inherits from the Modal class. Control Change Numbers: - Stick Hardness = 2 - Stick Position = 4 - Vibrato Gain = 8 - Vibrato Frequency = 11 - Direct Stick Mix = 1 - Volume = 128 - Modal Presets = 16 - Marimba = 0 - Vibraphone = 1 - Agogo = 2 - Wood1 = 3 - Reso = 4 - Wood2 = 5 - Beats = 6 - Two Fixed = 7 - Clump = 8 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "ModalBar.h" #include "SKINI.msg" #include using namespace Nyq; ModalBar :: ModalBar() : Modal() { // Concatenate the STK rawwave path to the rawwave file wave_ = new FileWvIn( (Stk::rawwavePath() + "marmstk1.raw").c_str(), true ); wave_->setRate( 0.5 * 22050.0 / Stk::sampleRate() ); // Set the resonances for preset 0 (marimba). this->setPreset( 0 ); } ModalBar :: ~ModalBar() { delete wave_; } void ModalBar :: setStickHardness(StkFloat hardness) { stickHardness_ = hardness; if ( hardness < 0.0 ) { errorString_ << "ModalBar::setStickHardness: parameter is less than zero ... setting to 0.0!"; handleError( StkError::WARNING ); stickHardness_ = 0.0; } else if ( hardness > 1.0 ) { errorString_ << "ModalBar::setStickHarness: parameter is greater than one ... setting to 1.0!"; handleError( StkError::WARNING ); stickHardness_ = 1.0; } wave_->setRate( (0.25 * pow(4.0, stickHardness_) ) ); masterGain_ = 0.1 + (1.8 * stickHardness_); } void ModalBar :: setStrikePosition(StkFloat position) { strikePosition_ = position; if ( position < 0.0 ) { errorString_ << "ModalBar::setStrikePosition: parameter is less than zero ... setting to 0.0!"; handleError( StkError::WARNING ); strikePosition_ = 0.0; } else if ( position > 1.0 ) { errorString_ << "ModalBar::setStrikePosition: parameter is greater than one ... setting to 1.0!"; handleError( StkError::WARNING ); strikePosition_ = 1.0; } // Hack only first three modes. StkFloat temp2 = position * PI; StkFloat temp = sin(temp2); this->setModeGain(0, 0.12 * temp); temp = sin(0.05 + (3.9 * temp2)); this->setModeGain(1, -0.03 * temp); temp = sin(-0.05 + (11 * temp2)); this->setModeGain(2, 0.11 * temp); } void ModalBar :: setPreset(int preset) { // Presets: // First line: relative modal frequencies (negative number is // a fixed mode that doesn't scale with frequency // Second line: resonances of the modes // Third line: mode volumes // Fourth line: stickHardness, strikePosition, and direct stick // gain (mixed directly into the output static StkFloat presets[9][4][4] = { {{1.0, 3.99, 10.65, -2443}, // Marimba {0.9996, 0.9994, 0.9994, 0.999}, {0.04, 0.01, 0.01, 0.008}, {0.429688, 0.445312, 0.093750}}, {{1.0, 2.01, 3.9, 14.37}, // Vibraphone {0.99995, 0.99991, 0.99992, 0.9999}, {0.025, 0.015, 0.015, 0.015 }, {0.390625,0.570312,0.078125}}, {{1.0, 4.08, 6.669, -3725.0}, // Agogo {0.999, 0.999, 0.999, 0.999}, {0.06, 0.05, 0.03, 0.02}, {0.609375,0.359375,0.140625}}, {{1.0, 2.777, 7.378, 15.377}, // Wood1 {0.996, 0.994, 0.994, 0.99}, {0.04, 0.01, 0.01, 0.008}, {0.460938,0.375000,0.046875}}, {{1.0, 2.777, 7.378, 15.377}, // Reso {0.99996, 0.99994, 0.99994, 0.9999}, {0.02, 0.005, 0.005, 0.004}, {0.453125,0.250000,0.101562}}, {{1.0, 1.777, 2.378, 3.377}, // Wood2 {0.996, 0.994, 0.994, 0.99}, {0.04, 0.01, 0.01, 0.008}, {0.312500,0.445312,0.109375}}, {{1.0, 1.004, 1.013, 2.377}, // Beats {0.9999, 0.9999, 0.9999, 0.999}, {0.02, 0.005, 0.005, 0.004}, {0.398438,0.296875,0.070312}}, {{1.0, 4.0, -1320.0, -3960.0}, // 2Fix {0.9996, 0.999, 0.9994, 0.999}, {0.04, 0.01, 0.01, 0.008}, {0.453125,0.453125,0.070312}}, {{1.0, 1.217, 1.475, 1.729}, // Clump {0.999, 0.999, 0.999, 0.999}, {0.03, 0.03, 0.03, 0.03 }, {0.390625,0.570312,0.078125}}, }; int temp = (preset % 9); for (unsigned int i=0; isetRatioAndRadius(i, presets[temp][0][i], presets[temp][1][i]); this->setModeGain(i, presets[temp][2][i]); } this->setStickHardness(presets[temp][3][0]); this->setStrikePosition(presets[temp][3][1]); directGain_ = presets[temp][3][2]; if (temp == 1) // vibraphone vibratoGain_ = 0.2; else vibratoGain_ = 0.0; } void ModalBar :: controlChange(int number, StkFloat value) { StkFloat norm = value * ONE_OVER_128; if ( norm < 0 ) { norm = 0.0; errorString_ << "ModalBar::controlChange: control value less than zero ... setting to zero!"; handleError( StkError::WARNING ); } else if ( norm > 1.0 ) { norm = 1.0; errorString_ << "ModalBar::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_StickHardness_) // 2 this->setStickHardness( norm ); else if (number == __SK_StrikePosition_) // 4 this->setStrikePosition( norm ); else if (number == __SK_ProphesyRibbon_) // 16 this->setPreset((int) value); else if (number == __SK_Balance_) // 8 vibratoGain_ = norm * 0.3; else if (number == __SK_ModWheel_) // 1 directGain_ = norm; else if (number == __SK_ModFrequency_) // 11 vibrato_.setFrequency( norm * 12.0 ); else if (number == __SK_AfterTouch_Cont_) // 128 envelope_.setTarget( norm ); else { errorString_ << "ModalBar::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "ModalBar::controlChange: number = " << number << ", value = " << value << '.'; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/WaveLoop.cpp0000644000175000000620000001244711466723256016567 0ustar stevestaff/***************************************************/ /*! \class WaveLoop \brief STK waveform oscillator class. This class inherits from FileWvIn and provides audio file looping functionality. Any audio file that can be loaded by FileRead can be looped using this class. WaveLoop supports multi-channel data. It is important to distinguish the tick() methods, which return samples produced by averaging across sample frames, from the tickFrame() methods, which return references or pointers to multi-channel sample frames. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "WaveLoop.h" #include using namespace Nyq; WaveLoop :: WaveLoop( unsigned long chunkThreshold, unsigned long chunkSize ) : FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0) { } WaveLoop :: WaveLoop( std::string fileName, bool raw, bool doNormalize, unsigned long chunkThreshold, unsigned long chunkSize ) : FileWvIn( chunkThreshold, chunkSize ), phaseOffset_(0.0) { this->openFile( fileName, raw, doNormalize ); } WaveLoop :: ~WaveLoop() { } void WaveLoop :: openFile( std::string fileName, bool raw, bool doNormalize ) { // Call close() in case another file is already open. this->closeFile(); // Attempt to open the file ... an error might be thrown here. file_.open( fileName, raw ); // Determine whether chunking or not. if ( file_.fileSize() > chunkThreshold_ ) { chunking_ = true; chunkPointer_ = 0; data_.resize( chunkSize_, file_.channels() ); if ( doNormalize ) normalizing_ = true; else normalizing_ = false; } else { chunking_ = false; data_.resize( file_.fileSize() + 1, file_.channels() ); } // Load all or part of the data. file_.read( data_, 0, doNormalize ); if ( chunking_ ) { // If chunking, save the first sample frame for later. firstFrame_.resize( 1, data_.channels() ); for ( unsigned int i=0; isetRate( data_.dataRate() / Stk::sampleRate() ); if ( doNormalize & !chunking_ ) this->normalize(); this->reset(); } void WaveLoop :: setRate( StkFloat rate ) { rate_ = rate; if ( fmod( rate_, 1.0 ) != 0.0 ) interpolate_ = true; else interpolate_ = false; } void WaveLoop :: setFrequency( StkFloat frequency ) { // This is a looping frequency. this->setRate( file_.fileSize() * frequency / Stk::sampleRate() ); } void WaveLoop :: addTime( StkFloat time ) { // Add an absolute time in samples. time_ += time; StkFloat fileSize = file_.fileSize(); while ( time_ < 0.0 ) time_ += fileSize; while ( time_ >= fileSize ) time_ -= fileSize; } void WaveLoop :: addPhase( StkFloat angle ) { // Add a time in cycles (one cycle = fileSize). StkFloat fileSize = file_.fileSize(); time_ += fileSize * angle; while ( time_ < 0.0 ) time_ += fileSize; while ( time_ >= fileSize ) time_ -= fileSize; } void WaveLoop :: addPhaseOffset( StkFloat angle ) { // Add a phase offset in cycles, where 1.0 = fileSize. phaseOffset_ = file_.fileSize() * angle; } void WaveLoop :: computeFrame( void ) { // Check limits of time address ... if necessary, recalculate modulo // fileSize. StkFloat fileSize = file_.fileSize(); while ( time_ < 0.0 ) time_ += fileSize; while ( time_ >= fileSize ) time_ -= fileSize; StkFloat tyme; if ( phaseOffset_ ) { tyme = time_ + phaseOffset_; while ( tyme < 0.0 ) tyme += fileSize; while ( tyme >= fileSize ) tyme -= fileSize; } else { tyme = time_; } if (chunking_) { // Check the time address vs. our current buffer limits. if ( ( time_ < (StkFloat) chunkPointer_ ) || ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) ) { while ( time_ < (StkFloat) chunkPointer_ ) { // negative rate chunkPointer_ -= chunkSize_ - 1; // overlap chunks by one frame if ( chunkPointer_ < 0 ) chunkPointer_ = 0; } while ( time_ > (StkFloat) ( chunkPointer_ + chunkSize_ - 1 ) ) { // positive rate chunkPointer_ += chunkSize_ - 1; // overlap chunks by one frame if ( chunkPointer_ + chunkSize_ > file_.fileSize() ) { // at end of file chunkPointer_ = file_.fileSize() - chunkSize_ + 1; // leave extra frame at end of buffer // Now fill extra frame with first frame data. for ( unsigned int j=0; j value_) { value_ += rate_; if (value_ >= target_) { value_ = target_; state_ = 0; } } else { value_ -= rate_; if (value_ <= target_) { value_ = target_; state_ = 0; } } } lastOutput_ = value_; return value_; } nyquist-3.05/nyqstk/src/PluckTwo.cpp0000644000175000000620000000700411466723256016574 0ustar stevestaff/***************************************************/ /*! \class PluckTwo \brief STK enhanced plucked string model class. This class implements an enhanced two-string, plucked physical model, a la Jaffe-Smith, Smith, and others. PluckTwo is an abstract class, with no excitation specified. Therefore, it can't be directly instantiated. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "PluckTwo.h" using namespace Nyq; PluckTwo :: PluckTwo(StkFloat lowestFrequency) { length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1); lastLength_ = length_ * 0.5; delayLine_.setMaximumDelay( length_ ); delayLine_.setDelay( lastLength_ ); delayLine2_.setMaximumDelay( length_ ); delayLine2_.setDelay( lastLength_ ); combDelay_.setMaximumDelay( length_ ); combDelay_.setDelay( lastLength_ ); baseLoopGain_ = 0.995; loopGain_ = 0.999; pluckAmplitude_ = 0.3; pluckPosition_ = 0.4; detuning_ = 0.995; lastFrequency_ = lowestFrequency * 2.0; } PluckTwo :: ~PluckTwo() { } void PluckTwo :: clear() { delayLine_.clear(); delayLine2_.clear(); combDelay_.clear(); filter_.clear(); filter2_.clear(); } void PluckTwo :: setFrequency(StkFloat frequency) { lastFrequency_ = frequency; if ( lastFrequency_ <= 0.0 ) { errorString_ << "Clarinet::setFrequency: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); lastFrequency_ = 220.0; } // Delay = length - approximate filter delay. lastLength_ = Stk::sampleRate() / lastFrequency_; StkFloat delay = (lastLength_ / detuning_) - 0.5; if ( delay <= 0.0 ) delay = 0.3; else if ( delay > length_ ) delay = length_; delayLine_.setDelay( delay ); delay = (lastLength_ * detuning_) - 0.5; if ( delay <= 0.0 ) delay = 0.3; else if ( delay > length_ ) delay = length_; delayLine2_.setDelay( delay ); loopGain_ = baseLoopGain_ + (frequency * 0.000005); if ( loopGain_ > 1.0 ) loopGain_ = 0.99999; } void PluckTwo :: setDetune(StkFloat detune) { detuning_ = detune; if ( detuning_ <= 0.0 ) { errorString_ << "Clarinet::setDeturn: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); detuning_ = 0.1; } delayLine_.setDelay(( lastLength_ / detuning_) - 0.5); delayLine2_.setDelay( (lastLength_ * detuning_) - 0.5); } void PluckTwo :: setFreqAndDetune(StkFloat frequency, StkFloat detune) { detuning_ = detune; this->setFrequency( frequency ); } void PluckTwo :: setPluckPosition(StkFloat position) { pluckPosition_ = position; if ( position < 0.0 ) { errorString_ << "PluckTwo::setPluckPosition: parameter is less than zero ... setting to 0.0!"; handleError( StkError::WARNING ); pluckPosition_ = 0.0; } else if ( position > 1.0 ) { errorString_ << "PluckTwo::setPluckPosition: parameter is greater than one ... setting to 1.0!"; handleError( StkError::WARNING ); pluckPosition_ = 1.0; } } void PluckTwo :: setBaseLoopGain(StkFloat aGain) { baseLoopGain_ = aGain; loopGain_ = baseLoopGain_ + (lastFrequency_ * 0.000005); if ( loopGain_ > 0.99999 ) loopGain_ = 0.99999; } void PluckTwo :: noteOff(StkFloat amplitude) { loopGain_ = (1.0 - amplitude) * 0.5; #if defined(_STK_DEBUG_) errorString_ << "PluckTwo::NoteOff: amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/FileRead.cpp0000644000175000000620000005377511511415575016510 0ustar stevestaff/***************************************************/ /*! \class FileRead \brief STK audio file input class. This class provides input support for various audio file formats. Multi-channel (>2) soundfiles are supported. The file data is returned via an external StkFrames object passed to the read() function. This class does not store its own copy of the file data, rather the data is read directly from disk. FileRead currently supports uncompressed WAV, AIFF/AIFC, SND (AU), MAT-file (Matlab), and STK RAW file formats. Signed integer (8-, 16-, and 32-bit) and floating-point (32- and 64-bit) data types are supported. Compressed data types are not supported. STK RAW files have no header and are assumed to contain a monophonic stream of 16-bit signed integers in big-endian byte order at a sample rate of 22050 Hz. MAT-file data should be saved in an array with each data channel filling a matrix row. The sample rate for MAT-files is assumed to be 44100 Hz. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "string.h" #include "FileRead.h" #include #include #include #include #include #include using namespace Nyq; FileRead :: FileRead() : fd_(0) { } FileRead :: FileRead( std::string fileName, bool typeRaw ) : fd_(0) { open( fileName, typeRaw ); } FileRead :: ~FileRead() { if ( fd_ ) fclose( fd_ ); } void FileRead :: close( void ) { if ( fd_ ) fclose( fd_ ); fd_ = 0; wavFile_ = false; } bool FileRead :: isOpen( void ) { if ( fd_ ) return true; else return false; } void FileRead :: open( std::string fileName, bool typeRaw ) { // If another file is open, close it. close(); // Try to open the file. fd_ = fopen( fileName.c_str(), "rb" ); if ( !fd_ ) { errorString_ << "FileRead::open: could not open or find file (" << fileName << ")!"; handleError( StkError::FILE_NOT_FOUND ); } // Attempt to determine file type from header (unless RAW). bool result = false; if ( typeRaw ) result = getRawInfo( fileName.c_str() ); else { char header[12]; if ( fread( &header, 4, 3, fd_ ) != 3 ) goto error; if ( !strncmp( header, "RIFF", 4 ) && !strncmp( &header[8], "WAVE", 4 ) ) result = getWavInfo( fileName.c_str() ); else if ( !strncmp( header, ".snd", 4 ) ) result = getSndInfo( fileName.c_str() ); else if ( !strncmp( header, "FORM", 4 ) && ( !strncmp( &header[8], "AIFF", 4 ) || !strncmp(&header[8], "AIFC", 4) ) ) result = getAifInfo( fileName.c_str() ); else { if ( fseek( fd_, 126, SEEK_SET ) == -1 ) goto error; if ( fread( &header, 2, 1, fd_ ) != 1 ) goto error; if ( !strncmp( header, "MI", 2 ) || !strncmp( header, "IM", 2 ) ) result = getMatInfo( fileName.c_str() ); else { errorString_ << "FileRead::open: file (" << fileName << ") format unknown."; handleError( StkError::FILE_UNKNOWN_FORMAT ); } } } // If here, we had a file type candidate but something else went wrong. if ( result == false ) handleError( StkError::FILE_ERROR ); // Check for empty files. if ( fileSize_ == 0 ) { errorString_ << "FileRead::open: file (" << fileName << ") data size is zero!"; handleError( StkError::FILE_ERROR ); } return; error: errorString_ << "FileRead::open: error reading file (" << fileName << ")!"; handleError( StkError::FILE_ERROR ); } bool FileRead :: getRawInfo( const char *fileName ) { // Use the system call "stat" to determine the file length. struct stat filestat; if ( stat(fileName, &filestat) == -1 ) { errorString_ << "FileRead: Could not stat RAW file (" << fileName << ")."; return false; } // STK rawwave files have no header and are assumed to contain a // monophonic stream of 16-bit signed integers in big-endian byte // order at a sample rate of 22050 Hz. channels_ = 1; fileSize_ = (long) filestat.st_size / 2; // length in 2-byte samples dataOffset_ = 0; fileRate_ = 22050.0; dataType_ = STK_SINT16; byteswap_ = false; #ifdef __LITTLE_ENDIAN__ byteswap_ = true; #endif return true; } bool FileRead :: getWavInfo( const char *fileName ) { // Find "format" chunk ... it must come before the "data" chunk. char id[4]; SINT32 chunkSize; if ( fread(&id, 4, 1, fd_) != 1 ) goto error; while ( strncmp(id, "fmt ", 4) ) { if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap32((unsigned char *)&chunkSize); #endif if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error; if ( fread(&id, 4, 1, fd_) != 1 ) goto error; } // Check that the data is not compressed. unsigned short format_tag; if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; // Read fmt chunk size. if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap16((unsigned char *)&format_tag); swap32((unsigned char *)&chunkSize); #endif if ( format_tag == 0xFFFE ) { // WAVE_FORMAT_EXTENSIBLE dataOffset_ = ftell(fd_); if ( fseek(fd_, 14, SEEK_CUR) == -1 ) goto error; unsigned short extSize; if ( fread(&extSize, 2, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap16((unsigned char *)&extSize); #endif if ( extSize == 0 ) goto error; if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; if ( fread(&format_tag, 2, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap16((unsigned char *)&format_tag); #endif if ( fseek(fd_, dataOffset_, SEEK_SET) == -1 ) goto error; } if (format_tag != 1 && format_tag != 3 ) { // PCM = 1, FLOAT = 3 errorString_ << "FileRead: "<< fileName << " contains an unsupported data format type (" << format_tag << ")."; return false; } // Get number of channels from the header. SINT16 temp; if ( fread(&temp, 2, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap16((unsigned char *)&temp); #endif channels_ = (unsigned int ) temp; // Get file sample rate from the header. SINT32 srate; if ( fread(&srate, 4, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap32((unsigned char *)&srate); #endif fileRate_ = (StkFloat) srate; // Determine the data type. dataType_ = 0; if ( fseek(fd_, 6, SEEK_CUR) == -1 ) goto error; // Locate bits_per_sample info. if ( fread(&temp, 2, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap16((unsigned char *)&temp); #endif if ( format_tag == 1 ) { if (temp == 8) dataType_ = STK_SINT8; else if (temp == 16) dataType_ = STK_SINT16; else if (temp == 32) dataType_ = STK_SINT32; } else if ( format_tag == 3 ) { if (temp == 32) dataType_ = STK_FLOAT32; else if (temp == 64) dataType_ = STK_FLOAT64; } if ( dataType_ == 0 ) { errorString_ << "FileRead: " << temp << " bits per sample with data format " << format_tag << " are not supported (" << fileName << ")."; return false; } // Jump over any remaining part of the "fmt" chunk. if ( fseek(fd_, chunkSize-16, SEEK_CUR) == -1 ) goto error; // Find "data" chunk ... it must come after the "fmt" chunk. if ( fread(&id, 4, 1, fd_) != 1 ) goto error; while ( strncmp(id, "data", 4) ) { if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap32((unsigned char *)&chunkSize); #endif chunkSize += chunkSize % 2; // chunk sizes must be even if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error; if ( fread(&id, 4, 1, fd_) != 1 ) goto error; } // Get length of data from the header. SINT32 bytes; if ( fread(&bytes, 4, 1, fd_) != 1 ) goto error; #ifndef __LITTLE_ENDIAN__ swap32((unsigned char *)&bytes); #endif fileSize_ = 8 * bytes / temp / channels_; // sample frames dataOffset_ = ftell(fd_); byteswap_ = false; #ifndef __LITTLE_ENDIAN__ byteswap_ = true; #endif wavFile_ = true; return true; error: errorString_ << "FileRead: error reading WAV file (" << fileName << ")."; return false; } bool FileRead :: getSndInfo( const char *fileName ) { // Determine the data type. UINT32 format; if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Locate format if ( fread(&format, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&format); #endif if (format == 2) dataType_ = STK_SINT8; else if (format == 3) dataType_ = STK_SINT16; else if (format == 4) dataType_ = STK_SINT24; else if (format == 5) dataType_ = STK_SINT32; else if (format == 6) dataType_ = STK_FLOAT32; else if (format == 7) dataType_ = STK_FLOAT64; else { errorString_ << "FileRead: data format in file " << fileName << " is not supported."; return false; } // Get file sample rate from the header. UINT32 srate; if ( fread(&srate, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&srate); #endif fileRate_ = (StkFloat) srate; // Get number of channels from the header. UINT32 chans; if ( fread(&chans, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&chans); #endif channels_ = chans; if ( fseek(fd_, 4, SEEK_SET) == -1 ) goto error; if ( fread(&dataOffset_, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&dataOffset_); #endif // Get length of data from the header. if ( fread(&fileSize_, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&fileSize_); #endif // Convert to sample frames. if ( dataType_ == STK_SINT8 ) fileSize_ /= channels_; if ( dataType_ == STK_SINT16 ) fileSize_ /= 2 * channels_; else if ( dataType_ == STK_SINT24 ) fileSize_ /= 3 * channels_; else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 ) fileSize_ /= 4 * channels_; else if ( dataType_ == STK_FLOAT64 ) fileSize_ /= 8 * channels_; byteswap_ = false; #ifdef __LITTLE_ENDIAN__ byteswap_ = true; #endif return true; error: errorString_ << "FileRead: Error reading SND file (" << fileName << ")."; return false; } bool FileRead :: getAifInfo( const char *fileName ) { bool aifc = false; char id[4]; // Determine whether this is AIFF or AIFC. if ( fseek(fd_, 8, SEEK_SET) == -1 ) goto error; if ( fread(&id, 4, 1, fd_) != 1 ) goto error; if ( !strncmp(id, "AIFC", 4) ) aifc = true; // Find "common" chunk SINT32 chunkSize; if ( fread(&id, 4, 1, fd_) != 1) goto error; while ( strncmp(id, "COMM", 4) ) { if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&chunkSize); #endif chunkSize += chunkSize % 2; // chunk sizes must be even if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error; if ( fread(&id, 4, 1, fd_) != 1 ) goto error; } // Get number of channels from the header. SINT16 temp; if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; // Jump over chunk size if ( fread(&temp, 2, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap16((unsigned char *)&temp); #endif channels_ = temp; // Get length of data from the header. SINT32 frames; if ( fread(&frames, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&frames); #endif fileSize_ = frames; // sample frames // Read the number of bits per sample. if ( fread(&temp, 2, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap16((unsigned char *)&temp); #endif // Get file sample rate from the header. For AIFF files, this value // is stored in a 10-byte, IEEE Standard 754 floating point number, // so we need to convert it first. unsigned char srate[10]; unsigned char exp; unsigned long mantissa; unsigned long last; if ( fread(&srate, 10, 1, fd_) != 1 ) goto error; mantissa = (unsigned long) *(unsigned long *)(srate+2); #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&mantissa); #endif exp = 30 - *(srate+1); last = 0; while (exp--) { last = mantissa; mantissa >>= 1; } if (last & 0x00000001) mantissa++; fileRate_ = (StkFloat) mantissa; // Determine the data format. dataType_ = 0; if ( aifc == false ) { if ( temp <= 8 ) dataType_ = STK_SINT8; else if ( temp <= 16 ) dataType_ = STK_SINT16; else if ( temp <= 24 ) dataType_ = STK_SINT24; else if ( temp <= 32 ) dataType_ = STK_SINT32; } else { if ( fread(&id, 4, 1, fd_) != 1 ) goto error; if ( !strncmp(id, "NONE", 4) ) { if ( temp <= 8 ) dataType_ = STK_SINT8; else if ( temp <= 16 ) dataType_ = STK_SINT16; else if ( temp <= 24 ) dataType_ = STK_SINT24; else if ( temp <= 32 ) dataType_ = STK_SINT32; } else if ( (!strncmp(id, "fl32", 4) || !strncmp(id, "FL32", 4)) && temp == 32 ) dataType_ = STK_FLOAT32; else if ( (!strncmp(id, "fl64", 4) || !strncmp(id, "FL64", 4)) && temp == 64 ) dataType_ = STK_FLOAT64; } if ( dataType_ == 0 ) { errorString_ << "FileRead: AIFF/AIFC file (" << fileName << ") has unsupported data type (" << id << ")."; return false; } // Start at top to find data (SSND) chunk ... chunk order is undefined. if ( fseek(fd_, 12, SEEK_SET) == -1 ) goto error; // Find data (SSND) chunk if ( fread(&id, 4, 1, fd_) != 1 ) goto error; while ( strncmp(id, "SSND", 4) ) { if ( fread(&chunkSize, 4, 1, fd_) != 1 ) goto error; #ifdef __LITTLE_ENDIAN__ swap32((unsigned char *)&chunkSize); #endif chunkSize += chunkSize % 2; // chunk sizes must be even if ( fseek(fd_, chunkSize, SEEK_CUR) == -1 ) goto error; if ( fread(&id, 4, 1, fd_) != 1 ) goto error; } // Skip over chunk size, offset, and blocksize fields if ( fseek(fd_, 12, SEEK_CUR) == -1 ) goto error; dataOffset_ = ftell(fd_); byteswap_ = false; #ifdef __LITTLE_ENDIAN__ byteswap_ = true; #endif return true; error: errorString_ << "FileRead: Error reading AIFF file (" << fileName << ")."; return false; } bool FileRead :: getMatInfo( const char *fileName ) { // MAT-file formatting information is available at: // http://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf // Verify this is a version 5 MAT-file format. char head[4]; if ( fseek(fd_, 0, SEEK_SET) == -1 ) goto error; if ( fread(&head, 4, 1, fd_) != 1 ) goto error; // If any of the first 4 characters of the header = 0, then this is // a Version 4 MAT-file. if ( strstr(head, "0") ) { errorString_ << "FileRead: " << fileName << " appears to be a Version 4 MAT-file, which is not currently supported."; return false; } // Determine the endian-ness of the file. char mi[2]; byteswap_ = false; // Locate "M" and "I" characters in header. if ( fseek(fd_, 126, SEEK_SET) == -1 ) goto error; if ( fread(&mi, 2, 1, fd_) != 1) goto error; #ifdef __LITTLE_ENDIAN__ if ( !strncmp(mi, "MI", 2) ) byteswap_ = true; else if ( strncmp(mi, "IM", 2) ) goto error; #else if ( !strncmp(mi, "IM", 2)) byteswap_ = true; else if ( strncmp(mi, "MI", 2) ) goto error; #endif // Check the data element type SINT32 datatype; if ( fread(&datatype, 4, 1, fd_) != 1 ) goto error; if ( byteswap_ ) swap32((unsigned char *)&datatype); if (datatype != 14) { errorString_ << "FileRead: The file does not contain a single Matlab array (or matrix) data element."; return false; } // Determine the array data type. SINT32 tmp; SINT32 size; if ( fseek(fd_, 168, SEEK_SET) == -1 ) goto error; if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; if (byteswap_) swap32((unsigned char *)&tmp); if (tmp == 1) { // array name > 4 characters if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; // get array name length if (byteswap_) swap32((unsigned char *)&tmp); size = (SINT32) ceil((float)tmp / 8); if ( fseek(fd_, size*8, SEEK_CUR) == -1 ) goto error; // jump over array name } else { // array name <= 4 characters, compressed data element if ( fseek(fd_, 4, SEEK_CUR) == -1 ) goto error; } if ( fread(&tmp, 4, 1, fd_) != 1 ) goto error; if (byteswap_) swap32((unsigned char *)&tmp); if ( tmp == 1 ) dataType_ = STK_SINT8; else if ( tmp == 3 ) dataType_ = STK_SINT16; else if ( tmp == 5 ) dataType_ = STK_SINT32; else if ( tmp == 7 ) dataType_ = STK_FLOAT32; else if ( tmp == 9 ) dataType_ = STK_FLOAT64; else { errorString_ << "FileRead: The MAT-file array data format (" << tmp << ") is not supported."; return false; } // Get number of rows from the header. SINT32 rows; if ( fseek(fd_, 160, SEEK_SET) == -1 ) goto error; if ( fread(&rows, 4, 1, fd_) != 1 ) goto error; if (byteswap_) swap32((unsigned char *)&rows); // Get number of columns from the header. SINT32 columns; if ( fread(&columns, 4, 1, fd_) != 1 ) goto error; if (byteswap_) swap32((unsigned char *)&columns); // Assume channels = smaller of rows or columns. if (rows < columns) { channels_ = rows; fileSize_ = columns; } else { errorString_ << "FileRead: Transpose the MAT-file array so that audio channels fill matrix rows (not columns)."; return false; } // Move read pointer to the data in the file. SINT32 headsize; if ( fseek(fd_, 132, SEEK_SET) == -1 ) goto error; if ( fread(&headsize, 4, 1, fd_) != 1 ) goto error; // file size from 132nd byte if (byteswap_) swap32((unsigned char *)&headsize); headsize -= fileSize_ * 8 * channels_; if ( fseek(fd_, headsize, SEEK_CUR) == -1 ) goto error; dataOffset_ = ftell(fd_); // Assume MAT-files have 44100 Hz sample rate. fileRate_ = 44100.0; return true; error: errorString_ << "FileRead: Error reading MAT-file (" << fileName << ")."; return false; } void FileRead :: read( StkFrames& buffer, unsigned long startFrame, bool doNormalize ) { // Make sure we have an open file. if ( fd_ == 0 ) { errorString_ << "FileRead::read: a file is not open!"; Stk::handleError( StkError::WARNING ); return; } // Check the buffer size. unsigned int nFrames = buffer.frames(); if ( nFrames == 0 ) { errorString_ << "FileRead::read: StkFrames buffer size is zero ... no data read!"; Stk::handleError( StkError::WARNING ); return; } if ( buffer.channels() != channels_ ) { errorString_ << "FileRead::read: StkFrames argument has incompatible number of channels!"; Stk::handleError( StkError::FUNCTION_ARGUMENT ); } // Check for file end. if ( startFrame + nFrames >= fileSize_ ) nFrames = fileSize_ - startFrame; long i, nSamples = (long) ( nFrames * channels_ ); unsigned long offset = startFrame * channels_; // Read samples into StkFrames data buffer. if ( dataType_ == STK_SINT16 ) { SINT16 *buf = (SINT16 *) &buffer[0]; if ( fseek( fd_, dataOffset_+(offset*2), SEEK_SET ) == -1 ) goto error; if ( fread( buf, nSamples * 2, 1, fd_ ) != 1 ) goto error; if ( byteswap_ ) { SINT16 *ptr = buf; for ( i=nSamples-1; i>=0; i-- ) swap16( (unsigned char *) ptr++ ); } if ( doNormalize ) { StkFloat gain = 1.0 / 32768.0; for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i] * gain; } else { for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i]; } } else if ( dataType_ == STK_SINT32 ) { SINT32 *buf = (SINT32 *) &buffer[0]; if ( fseek( fd_, dataOffset_+(offset*4 ), SEEK_SET ) == -1 ) goto error; if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error; if ( byteswap_ ) { SINT32 *ptr = buf; for ( i=nSamples-1; i>=0; i-- ) swap32( (unsigned char *) ptr++ ); } if ( doNormalize ) { StkFloat gain = 1.0 / 2147483648.0; for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i] * gain; } else { for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i]; } } else if ( dataType_ == STK_FLOAT32 ) { FLOAT32 *buf = (FLOAT32 *) &buffer[0]; if ( fseek( fd_, dataOffset_+(offset*4), SEEK_SET ) == -1 ) goto error; if ( fread( buf, nSamples * 4, 1, fd_ ) != 1 ) goto error; if ( byteswap_ ) { FLOAT32 *ptr = buf; for ( i=nSamples-1; i>=0; i-- ) swap32( (unsigned char *) ptr++ ); } for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i]; } else if ( dataType_ == STK_FLOAT64 ) { FLOAT64 *buf = (FLOAT64 *) &buffer[0]; if ( fseek( fd_, dataOffset_+(offset*8), SEEK_SET ) == -1 ) goto error; if ( fread( buf, nSamples * 8, 1, fd_ ) != 1 ) goto error; if ( byteswap_ ) { FLOAT64 *ptr = buf; for ( i=nSamples-1; i>=0; i-- ) swap64( (unsigned char *) ptr++ ); } for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i]; } else if ( dataType_ == STK_SINT8 && wavFile_ ) { // 8-bit WAV data is unsigned! unsigned char *buf = (unsigned char *) &buffer[0]; if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error; if ( fread( buf, nSamples, 1, fd_) != 1 ) goto error; if ( doNormalize ) { StkFloat gain = 1.0 / 128.0; for ( i=nSamples-1; i>=0; i-- ) buffer[i] = ( buf[i] - 128 ) * gain; } else { for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i] - 128.0; } } else if ( dataType_ == STK_SINT8 ) { // signed 8-bit data char *buf = (char *) &buffer[0]; if ( fseek( fd_, dataOffset_+offset, SEEK_SET ) == -1 ) goto error; if ( fread( buf, nSamples, 1, fd_ ) != 1 ) goto error; if ( doNormalize ) { StkFloat gain = 1.0 / 128.0; for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i] * gain; } else { for ( i=nSamples-1; i>=0; i-- ) buffer[i] = buf[i]; } } else if ( dataType_ == STK_SINT24 ) { // 24-bit values are harder to import efficiently since there is // no native 24-bit type. The following routine works but is much // less efficient that that used for the other data types. SINT32 buf; StkFloat gain = 1.0 / 8388608.0; if ( fseek(fd_, dataOffset_+(offset*3), SEEK_SET ) == -1 ) goto error; for ( i=0; i>= 8; if ( byteswap_ ) swap32( (unsigned char *) &buf ); if ( doNormalize ) buffer[i] = buf * gain; else buffer[i] = buf; } } buffer.setDataRate( fileRate_ ); return; error: errorString_ << "FileRead: Error reading file data."; handleError( StkError::FILE_ERROR); } nyquist-3.05/nyqstk/src/Noise.cpp0000644000175000000620000000201511466723256016076 0ustar stevestaff/***************************************************/ /*! \class Noise \brief STK noise generator. Generic random number generation using the C rand() function. The quality of the rand() function varies from one OS to another. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Noise.h" #include #include using namespace Nyq; Noise :: Noise() : Generator() { // Seed the random number generator with system time. this->setSeed( 0 ); lastOutput_ = (StkFloat) 0.0; } Noise :: Noise( unsigned int seed ) : Generator() { // Seed the random number generator this->setSeed( seed ); lastOutput_ = (StkFloat) 0.0; } Noise :: ~Noise() { } void Noise :: setSeed( unsigned int seed ) { if ( seed == 0 ) srand( (unsigned int) time(NULL) ); else srand( seed ); } StkFloat Noise :: computeSample() { lastOutput_ = (StkFloat) (2.0 * rand() / (RAND_MAX + 1.0) ); lastOutput_ -= 1.0; return lastOutput_; } nyquist-3.05/nyqstk/src/Chorus.cpp0000644000175000000620000000304711466723256016272 0ustar stevestaff/***************************************************/ /*! \class Chorus \brief STK chorus effect class. This class implements a chorus effect. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Chorus.h" #include using namespace Nyq; Chorus :: Chorus(StkFloat baseDelay) { delayLine_[0].setMaximumDelay( (unsigned long) (baseDelay * 1.414) + 2); delayLine_[0].setDelay( baseDelay ); delayLine_[1].setMaximumDelay( (unsigned long) (baseDelay * 1.414) + 2); delayLine_[1].setDelay( baseDelay ); baseLength_ = baseDelay; mods_[0].setFrequency(0.2); mods_[1].setFrequency(0.222222); modDepth_ = 0.05; effectMix_ = 0.5; this->clear(); } Chorus :: ~Chorus() { } void Chorus :: clear() { delayLine_[0].clear(); delayLine_[1].clear(); lastOutput_[0] = 0.0; lastOutput_[1] = 0.0; } void Chorus :: setModDepth(StkFloat depth) { modDepth_ = depth; } void Chorus :: setModFrequency(StkFloat frequency) { mods_[0].setFrequency(frequency); mods_[1].setFrequency(frequency * 1.1111); } StkFloat Chorus :: computeSample(StkFloat input) { delayLine_[0].setDelay( baseLength_ * 0.707 * (1.0 + modDepth_ * mods_[0].tick()) ); delayLine_[1].setDelay( baseLength_ * 0.5 * (1.0 - modDepth_ * mods_[1].tick()) ); lastOutput_[0] = input * (1.0 - effectMix_); lastOutput_[0] += effectMix_ * delayLine_[0].tick(input); lastOutput_[1] = input * (1.0 - effectMix_); lastOutput_[1] += effectMix_ * delayLine_[1].tick(input); return Effect::lastOut(); } nyquist-3.05/nyqstk/src/Clarinet.cpp0000644000175000000620000001123511466723256016566 0ustar stevestaff/***************************************************/ /*! \class Clarinet \brief STK clarinet physical model class. This class implements a simple clarinet physical model, as discussed by Smith (1986), McIntyre, Schumacher, Woodhouse (1983), and others. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Reed Stiffness = 2 - Noise Gain = 4 - Vibrato Frequency = 11 - Vibrato Gain = 1 - Breath Pressure = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Clarinet.h" #include "SKINI.msg" using namespace Nyq; Clarinet :: Clarinet(StkFloat lowestFrequency) { length_ = (long) (Stk::sampleRate() / lowestFrequency + 1); delayLine_.setMaximumDelay( length_ ); delayLine_.setDelay( length_ / 2.0 ); reedTable_.setOffset((StkFloat) 0.7); reedTable_.setSlope((StkFloat) -0.3); vibrato_.setFrequency((StkFloat) 5.735); outputGain_ = (StkFloat) 1.0; noiseGain_ = (StkFloat) 0.2; vibratoGain_ = (StkFloat) 0.1; } Clarinet :: ~Clarinet() { } void Clarinet :: clear() { delayLine_.clear(); filter_.tick((StkFloat) 0.0); } void Clarinet :: setFrequency(StkFloat frequency) { StkFloat freakency = frequency; if ( frequency <= 0.0 ) { errorString_ << "Clarinet::setFrequency: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); freakency = 220.0; } // Delay = length - approximate filter delay. StkFloat delay = (Stk::sampleRate() / freakency) * 0.5 - 1.5; if (delay <= 0.0) delay = 0.3; else if (delay > length_) delay = length_; delayLine_.setDelay(delay); } void Clarinet :: startBlowing(StkFloat amplitude, StkFloat rate) { envelope_.setRate(rate); envelope_.setTarget(amplitude); } void Clarinet :: stopBlowing(StkFloat rate) { envelope_.setRate(rate); envelope_.setTarget((StkFloat) 0.0); } void Clarinet :: noteOn(StkFloat frequency, StkFloat amplitude) { this->setFrequency(frequency); this->startBlowing((StkFloat) 0.55 + (amplitude * (StkFloat) 0.30), amplitude * (StkFloat) 0.005); outputGain_ = amplitude + (StkFloat) 0.001; #if defined(_STK_DEBUG_) errorString_ << "Clarinet::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.'; handleError( StkError::DEBUG_WARNING ); #endif } void Clarinet :: noteOff(StkFloat amplitude) { this->stopBlowing( amplitude * 0.01 ); #if defined(_STK_DEBUG_) errorString_ << "Clarinet::NoteOff: amplitude = " << amplitude << '.'; handleError( StkError::DEBUG_WARNING ); #endif } StkFloat Clarinet :: computeSample() { StkFloat pressureDiff; StkFloat breathPressure; // Calculate the breath pressure (envelope + noise + vibrato) breathPressure = envelope_.tick(); breathPressure += breathPressure * noiseGain_ * noise_.tick(); breathPressure += breathPressure * vibratoGain_ * vibrato_.tick(); // Perform commuted loss filtering. pressureDiff = -0.95 * filter_.tick(delayLine_.lastOut()); // Calculate pressure difference of reflected and mouthpiece pressures. pressureDiff = pressureDiff - breathPressure; // Perform non-linear scattering using pressure difference in reed function. lastOutput_ = delayLine_.tick(breathPressure + pressureDiff * reedTable_.tick(pressureDiff)); // Apply output gain. lastOutput_ *= outputGain_; return lastOutput_; } void Clarinet :: controlChange(int number, StkFloat value) { StkFloat norm = value * ONE_OVER_128; if ( norm < 0 ) { norm = 0.0; errorString_ << "Clarinet::controlChange: control value less than zero ... setting to zero!"; handleError( StkError::WARNING ); } else if ( norm > 1.0 ) { norm = 1.0; errorString_ << "Clarinet::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_ReedStiffness_) // 2 reedTable_.setSlope((StkFloat) -0.44 + ( (StkFloat) 0.26 * norm )); else if (number == __SK_NoiseLevel_) // 4 noiseGain_ = (norm * (StkFloat) 0.4); else if (number == __SK_ModFrequency_) // 11 vibrato_.setFrequency((norm * (StkFloat) 12.0)); else if (number == __SK_ModWheel_) // 1 vibratoGain_ = (norm * (StkFloat) 0.5); else if (number == __SK_AfterTouch_Cont_) // 128 envelope_.setValue(norm); else { errorString_ << "Clarinet::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "Clarinet::controlChange: number = " << number << ", value = " << value << '.'; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/NRev.cpp0000644000175000000620000000611311466723256015676 0ustar stevestaff/***************************************************/ /*! \class NRev \brief CCRMA's NRev reverberator class. This class is derived from the CLM NRev function, which is based on the use of networks of simple allpass and comb delay filters. This particular arrangement consists of 6 comb filters in parallel, followed by 3 allpass filters, a lowpass filter, and another allpass in series, followed by two allpass filters in parallel with corresponding right and left outputs. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "NRev.h" #include using namespace Nyq; NRev :: NRev(StkFloat T60) { int lengths[15] = {1433, 1601, 1867, 2053, 2251, 2399, 347, 113, 37, 59, 53, 43, 37, 29, 19}; double scaler = Stk::sampleRate() / 25641.0; int delay, i; for (i=0; i<15; i++) { delay = (int) floor(scaler * lengths[i]); if ( (delay & 1) == 0) delay++; while ( !this->isPrime(delay) ) delay += 2; lengths[i] = delay; } for (i=0; i<6; i++) { combDelays_[i].setMaximumDelay( lengths[i] ); combDelays_[i].setDelay( lengths[i] ); combCoefficient_[i] = pow(10.0, (-3 * lengths[i] / (T60 * Stk::sampleRate()))); } for (i=0; i<8; i++) { allpassDelays_[i].setMaximumDelay( lengths[i+6] ); allpassDelays_[i].setDelay( lengths[i+6] ); } this->setT60( T60 ); allpassCoefficient_ = 0.7; effectMix_ = 0.3; this->clear(); } NRev :: ~NRev() { } void NRev :: clear() { int i; for (i=0; i<6; i++) combDelays_[i].clear(); for (i=0; i<8; i++) allpassDelays_[i].clear(); lastOutput_[0] = 0.0; lastOutput_[1] = 0.0; lowpassState_ = 0.0; } void NRev :: setT60( StkFloat T60 ) { for ( int i=0; i<6; i++ ) combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate()))); } StkFloat NRev :: computeSample(StkFloat input) { StkFloat temp, temp0, temp1, temp2, temp3; int i; temp0 = 0.0; for (i=0; i<6; i++) { temp = input + (combCoefficient_[i] * combDelays_[i].lastOut()); temp0 += combDelays_[i].tick(temp); } for (i=0; i<3; i++) { temp = allpassDelays_[i].lastOut(); temp1 = allpassCoefficient_ * temp; temp1 += temp0; allpassDelays_[i].tick(temp1); temp0 = -(allpassCoefficient_ * temp1) + temp; } // One-pole lowpass filter. lowpassState_ = 0.7*lowpassState_ + 0.3*temp0; temp = allpassDelays_[3].lastOut(); temp1 = allpassCoefficient_ * temp; temp1 += lowpassState_; allpassDelays_[3].tick(temp1); temp1 = -(allpassCoefficient_ * temp1) + temp; temp = allpassDelays_[4].lastOut(); temp2 = allpassCoefficient_ * temp; temp2 += temp1; allpassDelays_[4].tick(temp2); lastOutput_[0] = effectMix_*(-(allpassCoefficient_ * temp2) + temp); temp = allpassDelays_[5].lastOut(); temp3 = allpassCoefficient_ * temp; temp3 += temp1; allpassDelays_[5].tick(temp3); lastOutput_[1] = effectMix_*(-(allpassCoefficient_ * temp3) + temp); temp = (1.0 - effectMix_) * input; lastOutput_[0] += temp; lastOutput_[1] += temp; return Effect::lastOut(); } nyquist-3.05/nyqstk/src/OneZero.cpp0000644000175000000620000000360011466723256016403 0ustar stevestaff/***************************************************/ /*! \class OneZero \brief STK one-zero filter class. This protected Filter subclass implements a one-zero digital filter. A method is provided for setting the zero position along the real axis of the z-plane while maintaining a constant filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "OneZero.h" using namespace Nyq; OneZero :: OneZero() : Filter() { std::vector b(2, 0.5); std::vector a(1, 1.0); Filter::setCoefficients( b, a ); } OneZero :: OneZero(StkFloat theZero) : Filter() { std::vector b(2); std::vector a(1, 1.0); // Normalize coefficients for unity gain. if (theZero > 0.0) b[0] = 1.0 / ((StkFloat) 1.0 + theZero); else b[0] = 1.0 / ((StkFloat) 1.0 - theZero); b[1] = -theZero * b[0]; Filter::setCoefficients( b, a ); } OneZero :: ~OneZero(void) { } void OneZero :: clear(void) { Filter::clear(); } void OneZero :: setB0(StkFloat b0) { b_[0] = b0; } void OneZero :: setB1(StkFloat b1) { b_[1] = b1; } void OneZero :: setZero(StkFloat theZero) { // Normalize coefficients for unity gain. if (theZero > 0.0) b_[0] = 1.0 / ((StkFloat) 1.0 + theZero); else b_[0] = 1.0 / ((StkFloat) 1.0 - theZero); b_[1] = -theZero * b_[0]; } void OneZero :: setGain(StkFloat gain) { Filter::setGain(gain); } StkFloat OneZero :: getGain(void) const { return Filter::getGain(); } StkFloat OneZero :: lastOut(void) const { return Filter::lastOut(); } StkFloat OneZero :: tick( StkFloat input ) { inputs_[0] = gain_ * input; outputs_[0] = b_[1] * inputs_[1] + b_[0] * inputs_[0]; inputs_[1] = inputs_[0]; return outputs_[0]; } StkFrames& OneZero :: tick( StkFrames& frames, unsigned int channel ) { return Filter::tick( frames, channel ); } nyquist-3.05/nyqstk/src/Function.cpp0000644000175000000620000000266011466723256016614 0ustar stevestaff/***************************************************/ /*! \class Function \brief STK abstract function parent class. This class provides common functionality for STK classes which implement tables or other types of input to output function mappings. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Function.h" using namespace Nyq; Function :: Function() : Stk() { lastOutput_ = (StkFloat) 0.0; } Function :: ~Function() { } StkFloat Function :: tick( StkFloat input ) { return computeSample( input ); } StkFrames& Function :: tick( StkFrames& frames, unsigned int channel ) { if ( channel >= frames.channels() ) { errorString_ << "Function::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( frames.channels() == 1 ) { for ( unsigned int i=0; i using namespace Nyq; BowTable :: BowTable() { offset_ = (StkFloat) 0.0; slope_ = (StkFloat) 0.1; } BowTable :: ~BowTable() { } void BowTable :: setOffset(StkFloat offset) { offset_ = offset; } void BowTable :: setSlope(StkFloat slope) { slope_ = slope; } StkFloat BowTable :: computeSample(StkFloat input) { // The input represents differential string vs. bow velocity. StkFloat sample; sample = input + offset_; // add bias to input sample *= slope_; // then scale it lastOutput_ = (StkFloat) fabs( (double) sample ) + (StkFloat) 0.75; lastOutput_ = (StkFloat) pow( lastOutput_, (StkFloat) -4.0 ); // Set minimum friction to 0.0 // if (lastOutput < 0.0 ) lastOutput = 0.0; // Set maximum friction to 1.0. if (lastOutput_ > 1.0 ) lastOutput_ = (StkFloat) 1.0; return lastOutput_; } nyquist-3.05/nyqstk/src/PoleZero.cpp0000644000175000000620000000345011466723256016564 0ustar stevestaff/***************************************************/ /*! \class PoleZero \brief STK one-pole, one-zero filter class. This protected Filter subclass implements a one-pole, one-zero digital filter. A method is provided for creating an allpass filter with a given coefficient. Another method is provided to create a DC blocking filter. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "PoleZero.h" using namespace Nyq; PoleZero :: PoleZero() : Filter() { // Default setting for pass-through. std::vector b(2, 0.0); std::vector a(2, 0.0); b[0] = 1.0; a[0] = 1.0; Filter::setCoefficients( b, a ); } PoleZero :: ~PoleZero() { } void PoleZero :: clear(void) { Filter::clear(); } void PoleZero :: setB0(StkFloat b0) { b_[0] = b0; } void PoleZero :: setB1(StkFloat b1) { b_[1] = b1; } void PoleZero :: setA1(StkFloat a1) { a_[1] = a1; } void PoleZero :: setAllpass(StkFloat coefficient) { b_[0] = coefficient; b_[1] = 1.0; a_[0] = 1.0; // just in case a_[1] = coefficient; } void PoleZero :: setBlockZero(StkFloat thePole) { b_[0] = 1.0; b_[1] = -1.0; a_[0] = 1.0; // just in case a_[1] = -thePole; } void PoleZero :: setGain(StkFloat gain) { Filter::setGain(gain); } StkFloat PoleZero :: getGain(void) const { return Filter::getGain(); } StkFloat PoleZero :: lastOut(void) const { return Filter::lastOut(); } StkFloat PoleZero :: tick( StkFloat input ) { inputs_[0] = gain_ * input; outputs_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] - a_[1] * outputs_[1]; inputs_[1] = inputs_[0]; outputs_[1] = outputs_[0]; return outputs_[0]; } StkFrames& PoleZero :: tick( StkFrames& frames, unsigned int channel ) { return Filter::tick( frames, channel ); } nyquist-3.05/nyqstk/src/Modal.cpp0000644000175000000620000001200711466723256016057 0ustar stevestaff/***************************************************/ /*! \class Modal \brief STK resonance model instrument. This class contains an excitation wavetable, an envelope, an oscillator, and N resonances (non-sweeping BiQuad filters), where N is set during instantiation. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Modal.h" #include using namespace Nyq; Modal :: Modal(unsigned int modes) : nModes_(modes) { if ( nModes_ == 0 ) { errorString_ << "Modal: 'modes' argument to constructor is zero!"; handleError( StkError::FUNCTION_ARGUMENT ); } // We don't make the excitation wave here yet, because we don't know // what it's going to be. ratios_.resize( nModes_ ); radii_.resize( nModes_ ); filters_ = (BiQuad **) calloc( nModes_, sizeof(BiQuad *) ); for (unsigned int i=0; isetEqualGainZeroes(); } // Set some default values. vibrato_.setFrequency( 6.0 ); vibratoGain_ = 0.0; directGain_ = 0.0; masterGain_ = 1.0; baseFrequency_ = 440.0; this->clear(); stickHardness_ = 0.5; strikePosition_ = 0.561; } Modal :: ~Modal() { for (unsigned int i=0; iclear(); } void Modal :: setFrequency(StkFloat frequency) { baseFrequency_ = frequency; for (unsigned int i=0; isetRatioAndRadius( i, ratios_[i], radii_[i] ); } void Modal :: setRatioAndRadius(unsigned int modeIndex, StkFloat ratio, StkFloat radius) { if ( modeIndex >= nModes_ ) { errorString_ << "Modal::setRatioAndRadius: modeIndex parameter is greater than number of modes!"; handleError( StkError::WARNING ); return; } StkFloat nyquist = Stk::sampleRate() / 2.0; StkFloat temp; if ( ratio * baseFrequency_ < nyquist ) { ratios_[modeIndex] = ratio; } else { temp = ratio; while (temp * baseFrequency_ > nyquist) temp *= 0.5; ratios_[modeIndex] = temp; #if defined(_STK_DEBUG_) errorString_ << "Modal::setRatioAndRadius: aliasing would occur here ... correcting."; handleError( StkError::DEBUG_WARNING ); #endif } radii_[modeIndex] = radius; if (ratio < 0) temp = -ratio; else temp = ratio * baseFrequency_; filters_[modeIndex]->setResonance(temp, radius); } void Modal :: setMasterGain(StkFloat aGain) { masterGain_ = aGain; } void Modal :: setDirectGain(StkFloat aGain) { directGain_ = aGain; } void Modal :: setModeGain(unsigned int modeIndex, StkFloat gain) { if ( modeIndex >= nModes_ ) { errorString_ << "Modal::setModeGain: modeIndex parameter is greater than number of modes!"; handleError( StkError::WARNING ); return; } filters_[modeIndex]->setGain(gain); } void Modal :: strike(StkFloat amplitude) { StkFloat gain = amplitude; if ( amplitude < 0.0 ) { errorString_ << "Modal::strike: amplitude is less than zero ... setting to zero!"; handleError( StkError::WARNING ); gain = 0.0; } else if ( amplitude > 1.0 ) { errorString_ << "Modal::strike: amplitude is greater than one ... setting to 1.0!"; handleError( StkError::WARNING ); gain = 1.0; } envelope_.setRate( 1.0 ); envelope_.setTarget( gain ); onepole_.setPole( 1.0 - gain ); envelope_.tick(); wave_->reset(); StkFloat temp; for (unsigned int i=0; isetResonance(temp, radii_[i]); } } void Modal :: noteOn(StkFloat frequency, StkFloat amplitude) { this->strike(amplitude); this->setFrequency(frequency); #if defined(_STK_DEBUG_) errorString_ << "Modal::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.'; handleError( StkError::DEBUG_WARNING ); #endif } void Modal :: noteOff(StkFloat amplitude) { // This calls damp, but inverts the meaning of amplitude (high // amplitude means fast damping). this->damp( 1.0 - (amplitude * 0.03) ); #if defined(_STK_DEBUG_) errorString_ << "Modal::NoteOff: amplitude = " << amplitude << '.'; handleError( StkError::DEBUG_WARNING ); #endif } void Modal :: damp(StkFloat amplitude) { StkFloat temp; for (unsigned int i=0; isetResonance(temp, radii_[i]*amplitude); } } StkFloat Modal :: computeSample() { StkFloat temp = masterGain_ * onepole_.tick( wave_->tick() * envelope_.tick() ); StkFloat temp2 = 0.0; for (unsigned int i=0; itick(temp); temp2 -= temp2 * directGain_; temp2 += directGain_ * temp; if (vibratoGain_ != 0.0) { // Calculate AM and apply to master out temp = 1.0 + (vibrato_.tick() * vibratoGain_); temp2 = temp * temp2; } lastOutput_ = temp2; return lastOutput_; } nyquist-3.05/nyqstk/src/Saxofony.cpp0000644000175000000620000001340711466723256016636 0ustar stevestaff/***************************************************/ /*! \class Saxofony \brief STK faux conical bore reed instrument class. This class implements a "hybrid" digital waveguide instrument that can generate a variety of wind-like sounds. It has also been referred to as the "blowed string" model. The waveguide section is essentially that of a string, with one rigid and one lossy termination. The non-linear function is a reed table. The string can be "blown" at any point between the terminations, though just as with strings, it is impossible to excite the system at either end. If the excitation is placed at the string mid-point, the sound is that of a clarinet. At points closer to the "bridge", the sound is closer to that of a saxophone. See Scavone (2002) for more details. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Reed Stiffness = 2 - Reed Aperture = 26 - Noise Gain = 4 - Blow Position = 11 - Vibrato Frequency = 29 - Vibrato Gain = 1 - Breath Pressure = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Saxofony.h" #include "SKINI.msg" using namespace Nyq; Saxofony :: Saxofony(StkFloat lowestFrequency) { length_ = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1); // Initialize blowing position to 0.2 of length / 2. position_ = 0.2; delays_[0].setMaximumDelay( length_ ); delays_[0].setDelay( (1.0-position_) * (length_ >> 1) ); delays_[1].setMaximumDelay( length_ ); delays_[1].setDelay( (1.0-position_) * (length_ >> 1) ); reedTable_.setOffset( 0.7 ); reedTable_.setSlope( 0.3 ); vibrato_.setFrequency((StkFloat) 5.735); outputGain_ = 0.3; noiseGain_ = 0.2; vibratoGain_ = 0.1; } Saxofony :: ~Saxofony() { } void Saxofony :: clear() { delays_[0].clear(); delays_[1].clear(); filter_.clear(); } void Saxofony :: setFrequency(StkFloat frequency) { StkFloat freakency = frequency; if ( frequency <= 0.0 ) { errorString_ << "Saxofony::setFrequency: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); freakency = 220.0; } StkFloat delay = (Stk::sampleRate() / freakency) - (StkFloat) 3.0; if (delay <= 0.0) delay = 0.3; else if (delay > length_) delay = length_; delays_[0].setDelay( (1.0-position_) * delay ); delays_[1].setDelay( position_ * delay ); } void Saxofony :: setBlowPosition(StkFloat position) { if ( position_ == position ) return; if ( position < 0.0 ) position_ = 0.0; else if ( position > 1.0 ) position_ = 1.0; else position_ = position; StkFloat totalDelay = delays_[0].getDelay(); totalDelay += delays_[1].getDelay(); delays_[0].setDelay( (1.0-position_) * totalDelay ); delays_[1].setDelay( position_ * totalDelay ); } void Saxofony :: startBlowing(StkFloat amplitude, StkFloat rate) { envelope_.setRate( rate ); envelope_.setTarget( amplitude ); } void Saxofony :: stopBlowing(StkFloat rate) { envelope_.setRate( rate ); envelope_.setTarget( 0.0 ); } void Saxofony :: noteOn(StkFloat frequency, StkFloat amplitude) { this->setFrequency( frequency ); this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 ); outputGain_ = amplitude + 0.001; #if defined(_STK_DEBUG_) errorString_ << "Saxofony::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Saxofony :: noteOff(StkFloat amplitude) { this->stopBlowing( amplitude * 0.01 ); #if defined(_STK_DEBUG_) errorString_ << "Saxofony::NoteOff: amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } StkFloat Saxofony :: computeSample() { StkFloat pressureDiff; StkFloat breathPressure; StkFloat temp; // Calculate the breath pressure (envelope + noise + vibrato) breathPressure = envelope_.tick(); breathPressure += breathPressure * noiseGain_ * noise_.tick(); breathPressure += breathPressure * vibratoGain_ * vibrato_.tick(); temp = -0.95 * filter_.tick( delays_[0].lastOut() ); lastOutput_ = temp - delays_[1].lastOut(); pressureDiff = breathPressure - lastOutput_; delays_[1].tick( temp ); delays_[0].tick( breathPressure - (pressureDiff * reedTable_.tick(pressureDiff)) - temp ); lastOutput_ *= outputGain_; return lastOutput_; } void Saxofony :: controlChange(int number, StkFloat value) { StkFloat norm = value * ONE_OVER_128; if ( norm < 0 ) { norm = 0.0; errorString_ << "Saxofony::controlChange: control value less than zero ... setting to zero!"; handleError( StkError::WARNING ); } else if ( norm > 1.0 ) { norm = 1.0; errorString_ << "Saxofony::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_ReedStiffness_) // 2 reedTable_.setSlope( 0.1 + (0.4 * norm) ); else if (number == __SK_NoiseLevel_) // 4 noiseGain_ = ( norm * 0.4 ); else if (number == 29) // 29 vibrato_.setFrequency( norm * 12.0 ); else if (number == __SK_ModWheel_) // 1 vibratoGain_ = ( norm * 0.5 ); else if (number == __SK_AfterTouch_Cont_) // 128 envelope_.setValue( norm ); else if (number == 11) // 11 this->setBlowPosition( norm ); else if (number == 26) // reed table offset reedTable_.setOffset(0.4 + ( norm * 0.6)); else { errorString_ << "Saxofony::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "Saxofony::controlChange: number = " << number << ", value = " << value << "."; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/PRCRev.cpp0000644000175000000620000000515411466723256016131 0ustar stevestaff/***************************************************/ /*! \class PRCRev \brief Perry's simple reverberator class. This class is based on some of the famous Stanford/CCRMA reverbs (NRev, KipRev), which were based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This class implements two series allpass units and two parallel comb filters. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "PRCRev.h" #include using namespace Nyq; PRCRev :: PRCRev(StkFloat T60) { // Delay lengths for 44100 Hz sample rate. int lengths[4]= {353, 1097, 1777, 2137}; double scaler = Stk::sampleRate() / 44100.0; // Scale the delay lengths if necessary. int delay, i; if ( scaler != 1.0 ) { for (i=0; i<4; i++) { delay = (int) floor(scaler * lengths[i]); if ( (delay & 1) == 0) delay++; while ( !this->isPrime(delay) ) delay += 2; lengths[i] = delay; } } for (i=0; i<2; i++) { allpassDelays_[i].setMaximumDelay( lengths[i] ); allpassDelays_[i].setDelay( lengths[i] ); combDelays_[i].setMaximumDelay( lengths[i+2] ); combDelays_[i].setDelay( lengths[i+2] ); } this->setT60( T60 ); allpassCoefficient_ = 0.7; effectMix_ = 0.5; this->clear(); } PRCRev :: ~PRCRev() { } void PRCRev :: clear() { allpassDelays_[0].clear(); allpassDelays_[1].clear(); combDelays_[0].clear(); combDelays_[1].clear(); lastOutput_[0] = 0.0; lastOutput_[1] = 0.0; } void PRCRev :: setT60( StkFloat T60 ) { combCoefficient_[0] = pow(10.0, (-3.0 * combDelays_[0].getDelay() / (T60 * Stk::sampleRate()))); combCoefficient_[1] = pow(10.0, (-3.0 * combDelays_[1].getDelay() / (T60 * Stk::sampleRate()))); } StkFloat PRCRev :: computeSample(StkFloat input) { StkFloat temp, temp0, temp1, temp2, temp3; temp = allpassDelays_[0].lastOut(); temp0 = allpassCoefficient_ * temp; temp0 += input; allpassDelays_[0].tick(temp0); temp0 = -(allpassCoefficient_ * temp0) + temp; temp = allpassDelays_[1].lastOut(); temp1 = allpassCoefficient_ * temp; temp1 += temp0; allpassDelays_[1].tick(temp1); temp1 = -(allpassCoefficient_ * temp1) + temp; temp2 = temp1 + (combCoefficient_[0] * combDelays_[0].lastOut()); temp3 = temp1 + (combCoefficient_[1] * combDelays_[1].lastOut()); lastOutput_[0] = effectMix_ * (combDelays_[0].tick(temp2)); lastOutput_[1] = effectMix_ * (combDelays_[1].tick(temp3)); temp = (1.0 - effectMix_) * input; lastOutput_[0] += temp; lastOutput_[1] += temp; return Effect::lastOut(); } nyquist-3.05/nyqstk/src/OnePole.cpp0000644000175000000620000000357211466723256016373 0ustar stevestaff/***************************************************/ /*! \class OnePole \brief STK one-pole filter class. This protected Filter subclass implements a one-pole digital filter. A method is provided for setting the pole position along the real axis of the z-plane while maintaining a constant peak filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "OnePole.h" using namespace Nyq; OnePole :: OnePole() : Filter() { std::vector b(1, 0.1); std::vector a(2, 1.0); a[1] = -0.9; Filter::setCoefficients( b, a ); } OnePole :: OnePole(StkFloat thePole) : Filter() { std::vector b(1); std::vector a(2, 1.0); a[1] = -thePole; // Normalize coefficients for peak unity gain. if (thePole > 0.0) b[0] = (StkFloat) (1.0 - thePole); else b[0] = (StkFloat) (1.0 + thePole); Filter::setCoefficients( b, a ); } OnePole :: ~OnePole() { } void OnePole :: clear(void) { Filter::clear(); } void OnePole :: setB0(StkFloat b0) { b_[0] = b0; } void OnePole :: setA1(StkFloat a1) { a_[1] = a1; } void OnePole :: setPole(StkFloat thePole) { // Normalize coefficients for peak unity gain. if (thePole > 0.0) b_[0] = (StkFloat) (1.0 - thePole); else b_[0] = (StkFloat) (1.0 + thePole); a_[1] = -thePole; } void OnePole :: setGain(StkFloat gain) { Filter::setGain(gain); } StkFloat OnePole :: getGain(void) const { return Filter::getGain(); } StkFloat OnePole :: lastOut(void) const { return Filter::lastOut(); } StkFloat OnePole :: tick( StkFloat input ) { inputs_[0] = gain_ * input; outputs_[0] = b_[0] * inputs_[0] - a_[1] * outputs_[1]; outputs_[1] = outputs_[0]; return outputs_[0]; } StkFrames& OnePole :: tick( StkFrames& frames, unsigned int channel ) { return Filter::tick( frames, channel ); } nyquist-3.05/nyqstk/src/BandedWG.cpp0000644000175000000620000002356111466723256016445 0ustar stevestaff/***************************************************/ /*! \class BandedWG \brief Banded waveguide modeling class. This class uses banded waveguide techniques to model a variety of sounds, including bowed bars, glasses, and bowls. For more information, see Essl, G. and Cook, P. "Banded Waveguides: Towards Physical Modelling of Bar Percussion Instruments", Proceedings of the 1999 International Computer Music Conference. Control Change Numbers: - Bow Pressure = 2 - Bow Motion = 4 - Strike Position = 8 (not implemented) - Vibrato Frequency = 11 - Gain = 1 - Bow Velocity = 128 - Set Striking = 64 - Instrument Presets = 16 - Uniform Bar = 0 - Tuned Bar = 1 - Glass Harmonica = 2 - Tibetan Bowl = 3 by Georg Essl, 1999 - 2004. Modified for Stk 4.0 by Gary Scavone. */ /***************************************************/ #include "BandedWG.h" #include "SKINI.msg" #include using namespace Nyq; BandedWG :: BandedWG() { doPluck_ = true; bowTable_.setSlope( 3.0 ); adsr_.setAllTimes( 0.02, 0.005, 0.9, 0.01); frequency_ = 220.0; this->setPreset(0); bowPosition_ = 0; baseGain_ = (StkFloat) 0.999; integrationConstant_ = 0.0; trackVelocity_ = false; bowVelocity_ = 0.0; bowTarget_ = 0.0; strikeAmp_ = 0.0; } BandedWG :: ~BandedWG() { } void BandedWG :: clear() { for (int i=0; i 1568.0) frequency_ = 1568.0; StkFloat radius; StkFloat base = Stk::sampleRate() / frequency_; StkFloat length; for (int i=0; i 2.0) { delay_[i].setDelay( length ); gains_[i]=basegains_[i]; // gains_[i]=(StkFloat) pow(basegains_[i], 1/((StkFloat)delay_[i].getDelay())); // std::cerr << gains_[i]; } else { nModes_ = i; break; } // std::cerr << std::endl; // Set the bandpass filter resonances radius = 1.0 - PI * 32 / Stk::sampleRate(); //frequency_ * modes_[i] / Stk::sampleRate()/32; if ( radius < 0.0 ) radius = 0.0; bandpass_[i].setResonance(frequency_ * modes_[i], radius, true); delay_[i].clear(); bandpass_[i].clear(); } //int olen = (int)(delay_[0].getDelay()); //strikePosition_ = (int)(strikePosition_*(length/modes_[0])/olen); } void BandedWG :: setStrikePosition(StkFloat position) { strikePosition_ = (int)(delay_[0].getDelay() * position / 2.0); } void BandedWG :: startBowing(StkFloat amplitude, StkFloat rate) { adsr_.setRate(rate); adsr_.keyOn(); maxVelocity_ = 0.03 + (0.1 * amplitude); } void BandedWG :: stopBowing(StkFloat rate) { adsr_.setRate(rate); adsr_.keyOff(); } void BandedWG :: pluck(StkFloat amplitude) { int j; StkFloat min_len = delay_[nModes_-1].getDelay(); for (int i=0; isetFrequency(frequency); if ( doPluck_ ) this->pluck(amplitude); else this->startBowing(amplitude, amplitude * 0.001); #if defined(_STK_DEBUG_) errorString_ << "BandedWG::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void BandedWG :: noteOff(StkFloat amplitude) { if ( !doPluck_ ) this->stopBowing((1.0 - amplitude) * 0.005); #if defined(_STK_DEBUG_) errorString_ << "BandedWG::NoteOff: amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } StkFloat BandedWG :: computeSample() { int k; StkFloat input = 0.0; if ( doPluck_ ) { input = 0.0; // input = strikeAmp_/nModes_; // strikeAmp_ = 0.0; } else { if (integrationConstant_ == 0.0) velocityInput_ = 0.0; else velocityInput_ = integrationConstant_ * velocityInput_; for (k=0; k 1.0 ) { norm = 1.0; errorString_ << "BandedWG::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_BowPressure_) { // 2 if ( norm == 0.0 ) doPluck_ = true; else { doPluck_ = false; bowTable_.setSlope( 10.0 - (9.0 * norm)); } } else if (number == 4) { // 4 if ( !trackVelocity_ ) trackVelocity_ = true; bowTarget_ += 0.005 * (norm - bowPosition_); bowPosition_ = norm; //adsr_.setTarget(bowPosition_); } else if (number == 8) // 8 this->setStrikePosition( norm ); else if (number == __SK_AfterTouch_Cont_) { // 128 //bowTarget_ += 0.02 * (norm - bowPosition_); //bowPosition_ = norm; if ( trackVelocity_ ) trackVelocity_ = false; maxVelocity_ = 0.13 * norm; adsr_.setTarget(norm); } else if (number == __SK_ModWheel_) { // 1 // baseGain_ = 0.9989999999 + (0.001 * norm ); baseGain_ = 0.8999999999999999 + (0.1 * norm); // std::cerr << "Yuck!" << std::endl; for (int i=0; isetPreset((int) value); else { errorString_ << "BandedWG::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "BandedWG::controlChange: number = " << number << ", value = " << value << "."; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/Bowed.cpp0000644000175000000620000001215711466723256016071 0ustar stevestaff/***************************************************/ /*! \class Bowed \brief STK bowed string instrument class. This class implements a bowed string model, a la Smith (1986), after McIntyre, Schumacher, Woodhouse (1983). This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Bow Pressure = 2 - Bow Position = 4 - Vibrato Frequency = 11 - Vibrato Gain = 1 - Volume = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Bowed.h" #include "SKINI.msg" using namespace Nyq; Bowed :: Bowed(StkFloat lowestFrequency) { unsigned long length; length = (long) ( Stk::sampleRate() / lowestFrequency + 1 ); neckDelay_.setMaximumDelay( length ); neckDelay_.setDelay( 100.0 ); length >>= 1; bridgeDelay_.setMaximumDelay( length ); bridgeDelay_.setDelay( 29.0 ); bowTable_.setSlope(3.0 ); vibrato_.setFrequency( 6.12723 ); vibratoGain_ = 0.0; stringFilter_.setPole( 0.6 - (0.1 * 22050.0 / Stk::sampleRate()) ); stringFilter_.setGain( 0.95 ); bodyFilter_.setResonance( 500.0, 0.85, true ); bodyFilter_.setGain( 0.2 ); adsr_.setAllTimes( 0.02, 0.005, 0.9, 0.01 ); betaRatio_ = 0.127236; // Necessary to initialize internal variables. this->setFrequency( 220.0 ); } Bowed :: ~Bowed() { } void Bowed :: clear() { neckDelay_.clear(); bridgeDelay_.clear(); } void Bowed :: setFrequency(StkFloat frequency) { StkFloat freakency = frequency; if ( frequency <= 0.0 ) { errorString_ << "Bowed::setFrequency: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); freakency = 220.0; } // Delay = length - approximate filter delay. baseDelay_ = Stk::sampleRate() / freakency - 4.0; if ( baseDelay_ <= 0.0 ) baseDelay_ = 0.3; bridgeDelay_.setDelay( baseDelay_ * betaRatio_ ); // bow to bridge length neckDelay_.setDelay( baseDelay_ * (1.0 - betaRatio_) ); // bow to nut (finger) length } void Bowed :: startBowing(StkFloat amplitude, StkFloat rate) { adsr_.setRate( rate ); adsr_.keyOn(); maxVelocity_ = 0.03 + ( 0.2 * amplitude ); } void Bowed :: stopBowing(StkFloat rate) { adsr_.setRate( rate ); adsr_.keyOff(); } void Bowed :: noteOn(StkFloat frequency, StkFloat amplitude) { this->startBowing( amplitude, amplitude * 0.001 ); this->setFrequency( frequency ); #if defined(_STK_DEBUG_) errorString_ << "Bowed::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Bowed :: noteOff(StkFloat amplitude) { this->stopBowing( (1.0 - amplitude) * 0.005 ); #if defined(_STK_DEBUG_) errorString_ << "Bowed::NoteOff: amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Bowed :: setVibrato(StkFloat gain) { vibratoGain_ = gain; } StkFloat Bowed :: computeSample() { StkFloat bowVelocity; StkFloat bridgeRefl; StkFloat nutRefl; StkFloat newVel; StkFloat velDiff; StkFloat stringVel; bowVelocity = maxVelocity_ * adsr_.tick(); bridgeRefl = -stringFilter_.tick( bridgeDelay_.lastOut() ); nutRefl = -neckDelay_.lastOut(); stringVel = bridgeRefl + nutRefl; // Sum is String Velocity velDiff = bowVelocity - stringVel; // Differential Velocity newVel = velDiff * bowTable_.tick( velDiff ); // Non-Linear Bow Function neckDelay_.tick(bridgeRefl + newVel); // Do string propagations bridgeDelay_.tick(nutRefl + newVel); if ( vibratoGain_ > 0.0 ) { neckDelay_.setDelay( (baseDelay_ * (1.0 - betaRatio_) ) + (baseDelay_ * vibratoGain_ * vibrato_.tick()) ); } lastOutput_ = bodyFilter_.tick( bridgeDelay_.lastOut() ); return lastOutput_; } void Bowed :: controlChange(int number, StkFloat value) { StkFloat norm = value * ONE_OVER_128; if ( norm < 0 ) { norm = 0.0; errorString_ << "Bowed::controlChange: control value less than zero ... setting to zero!"; handleError( StkError::WARNING ); } else if ( norm > 1.0 ) { norm = 1.0; errorString_ << "Bowed::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_BowPressure_) // 2 bowTable_.setSlope( 5.0 - (4.0 * norm) ); else if (number == __SK_BowPosition_) { // 4 betaRatio_ = 0.027236 + (0.2 * norm); bridgeDelay_.setDelay( baseDelay_ * betaRatio_ ); neckDelay_.setDelay( baseDelay_ * (1.0 - betaRatio_) ); } else if (number == __SK_ModFrequency_) // 11 vibrato_.setFrequency( norm * 12.0 ); else if (number == __SK_ModWheel_) // 1 vibratoGain_ = ( norm * 0.4 ); else if (number == __SK_AfterTouch_Cont_) // 128 adsr_.setTarget(norm); else { errorString_ << "Bowed::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "Bowed::controlChange: number = " << number << ", value = " << value << "."; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/Mandolin.cpp0000644000175000000620000001500411466723256016564 0ustar stevestaff/***************************************************/ /*! \class Mandolin \brief STK mandolin instrument model class. This class inherits from PluckTwo and uses "commuted synthesis" techniques to model a mandolin instrument. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Commuted Synthesis, in particular, is covered by patents, granted, pending, and/or applied-for. All are assigned to the Board of Trustees, Stanford University. For information, contact the Office of Technology Licensing, Stanford University. Control Change Numbers: - Body Size = 2 - Pluck Position = 4 - String Sustain = 11 - String Detuning = 1 - Microphone Position = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Mandolin.h" #include "SKINI.msg" using namespace Nyq; Mandolin :: Mandolin(StkFloat lowestFrequency) : PluckTwo(lowestFrequency) { // Concatenate the STK rawwave path to the rawwave files soundfile_[0] = new FileWvIn( (Stk::rawwavePath() + "mand1.raw").c_str(), true ); soundfile_[1] = new FileWvIn( (Stk::rawwavePath() + "mand2.raw").c_str(), true ); soundfile_[2] = new FileWvIn( (Stk::rawwavePath() + "mand3.raw").c_str(), true ); soundfile_[3] = new FileWvIn( (Stk::rawwavePath() + "mand4.raw").c_str(), true ); soundfile_[4] = new FileWvIn( (Stk::rawwavePath() + "mand5.raw").c_str(), true ); soundfile_[5] = new FileWvIn( (Stk::rawwavePath() + "mand6.raw").c_str(), true ); soundfile_[6] = new FileWvIn( (Stk::rawwavePath() + "mand7.raw").c_str(), true ); soundfile_[7] = new FileWvIn( (Stk::rawwavePath() + "mand8.raw").c_str(), true ); soundfile_[8] = new FileWvIn( (Stk::rawwavePath() + "mand9.raw").c_str(), true ); soundfile_[9] = new FileWvIn( (Stk::rawwavePath() + "mand10.raw").c_str(), true ); soundfile_[10] = new FileWvIn( (Stk::rawwavePath() + "mand11.raw").c_str(), true ); soundfile_[11] = new FileWvIn( (Stk::rawwavePath() + "mand12.raw").c_str(), true ); mic_ = 0; dampTime_ = 0; waveDone_ = soundfile_[mic_]->isFinished(); } Mandolin :: ~Mandolin() { for ( int i=0; i<12; i++ ) delete soundfile_[i]; } void Mandolin :: pluck(StkFloat amplitude) { // This function gets interesting, because pluck // may be longer than string length, so we just // reset the soundfile and add in the pluck in // the tick method. soundfile_[mic_]->reset(); waveDone_ = false; pluckAmplitude_ = amplitude; if ( amplitude < 0.0 ) { errorString_ << "Mandolin::pluck: amplitude parameter less than zero ... setting to 0.0!"; handleError( StkError::WARNING ); pluckAmplitude_ = 0.0; } else if ( amplitude > 1.0 ) { errorString_ << "Mandolin::pluck: amplitude parameter greater than one ... setting to 1.0!"; handleError( StkError::WARNING ); pluckAmplitude_ = 1.0; } // Set the pick position, which puts zeroes at position * length. combDelay_.setDelay( 0.5 * pluckPosition_ * lastLength_ ); dampTime_ = (long) lastLength_; // See tick method below. } void Mandolin :: pluck(StkFloat amplitude, StkFloat position) { // Pluck position puts zeroes at position * length. pluckPosition_ = position; if ( position < 0.0 ) { std::cerr << "Mandolin::pluck: position parameter less than zero ... setting to 0.0!"; handleError( StkError::WARNING ); pluckPosition_ = 0.0; } else if ( position > 1.0 ) { errorString_ << "Mandolin::pluck: amplitude parameter greater than one ... setting to 1.0!"; handleError( StkError::WARNING ); pluckPosition_ = 1.0; } this->pluck( amplitude ); } void Mandolin :: noteOn(StkFloat frequency, StkFloat amplitude) { this->setFrequency( frequency ); this->pluck( amplitude ); #if defined(_STK_DEBUG_) errorString_ << "Mandolin::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Mandolin :: setBodySize(StkFloat size) { // Scale the commuted body response by its sample rate (22050). StkFloat rate = size * 22050.0 / Stk::sampleRate(); for ( int i=0; i<12; i++ ) soundfile_[i]->setRate( rate ); } StkFloat Mandolin :: computeSample() { StkFloat temp = 0.0; if ( !waveDone_ ) { // Scale the pluck excitation with comb // filtering for the duration of the file. temp = soundfile_[mic_]->tick() * pluckAmplitude_; temp = temp - combDelay_.tick(temp); waveDone_ = soundfile_[mic_]->isFinished(); } // Damping hack to help avoid overflow on re-plucking. if ( dampTime_ >=0 ) { dampTime_ -= 1; // Calculate 1st delay filtered reflection plus pluck excitation. lastOutput_ = delayLine_.tick( filter_.tick( temp + (delayLine_.lastOut() * 0.7) ) ); // Calculate 2nd delay just like the 1st. lastOutput_ += delayLine2_.tick( filter2_.tick( temp + (delayLine2_.lastOut() * 0.7) ) ); } else { // No damping hack after 1 period. // Calculate 1st delay filtered reflection plus pluck excitation. lastOutput_ = delayLine_.tick( filter_.tick( temp + (delayLine_.lastOut() * loopGain_) ) ); // Calculate 2nd delay just like the 1st. lastOutput_ += delayLine2_.tick( filter2_.tick( temp + (delayLine2_.lastOut() * loopGain_) ) ); } lastOutput_ *= 0.3; return lastOutput_; } void Mandolin :: controlChange(int number, StkFloat value) { StkFloat norm = value * ONE_OVER_128; if ( norm < 0 ) { norm = 0.0; errorString_ << "Mandolin::controlChange: control value less than zero ... setting to zero!"; handleError( StkError::WARNING ); } else if ( norm > 1.0 ) { norm = 1.0; errorString_ << "Mandolin::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_BodySize_) // 2 this->setBodySize( norm * 2.0 ); else if (number == __SK_PickPosition_) // 4 this->setPluckPosition( norm ); else if (number == __SK_StringDamping_) // 11 this->setBaseLoopGain( 0.97 + (norm * 0.03)); else if (number == __SK_StringDetune_) // 1 this->setDetune( 1.0 - (norm * 0.1) ); else if (number == __SK_AfterTouch_Cont_) // 128 mic_ = (int) (norm * 11.0); else { errorString_ << "Mandolin::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "Mandolin::controlChange: number = " << number << ", value = " << value << "."; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/Generator.cpp0000644000175000000620000000251211466723256016751 0ustar stevestaff/***************************************************/ /*! \class Generator \brief STK abstract unit generator parent class. This class provides common functionality for STK unit generator sample-source subclasses. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Generator.h" using namespace Nyq; Generator :: Generator() : Stk() { lastOutput_ = 0.0; } Generator :: ~Generator() { } StkFloat Generator :: tick( void ) { return computeSample(); } StkFrames& Generator :: tick( StkFrames& frames, unsigned int channel ) { if ( channel >= frames.channels() ) { errorString_ << "Generator::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( frames.channels() == 1 ) { for ( unsigned int i=0; i using namespace Nyq; StkFloat Stk :: srate_ = (StkFloat) SRATE; std::string Stk :: rawwavepath_ = RAWWAVE_PATH; const Stk::StkFormat Stk :: STK_SINT8 = 0x1; const Stk::StkFormat Stk :: STK_SINT16 = 0x2; const Stk::StkFormat Stk :: STK_SINT24 = 0x4; const Stk::StkFormat Stk :: STK_SINT32 = 0x8; const Stk::StkFormat Stk :: STK_FLOAT32 = 0x10; const Stk::StkFormat Stk :: STK_FLOAT64 = 0x20; bool Stk :: showWarnings_ = false; bool Stk :: printErrors_ = true; Stk :: Stk(void) { } Stk :: ~Stk(void) { } void Stk :: setRawwavePath( std::string path ) { if ( !path.empty() ) rawwavepath_ = path; // Make sure the path includes a "/" if ( rawwavepath_[rawwavepath_.length()-1] != '/' ) rawwavepath_ += "/"; } void Stk :: swap16(unsigned char *ptr) { register unsigned char val; // Swap 1st and 2nd bytes val = *(ptr); *(ptr) = *(ptr+1); *(ptr+1) = val; } void Stk :: swap32(unsigned char *ptr) { register unsigned char val; // Swap 1st and 4th bytes val = *(ptr); *(ptr) = *(ptr+3); *(ptr+3) = val; //Swap 2nd and 3rd bytes ptr += 1; val = *(ptr); *(ptr) = *(ptr+1); *(ptr+1) = val; } void Stk :: swap64(unsigned char *ptr) { register unsigned char val; // Swap 1st and 8th bytes val = *(ptr); *(ptr) = *(ptr+7); *(ptr+7) = val; // Swap 2nd and 7th bytes ptr += 1; val = *(ptr); *(ptr) = *(ptr+5); *(ptr+5) = val; // Swap 3rd and 6th bytes ptr += 1; val = *(ptr); *(ptr) = *(ptr+3); *(ptr+3) = val; // Swap 4th and 5th bytes ptr += 1; val = *(ptr); *(ptr) = *(ptr+1); *(ptr+1) = val; } #if (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__)) #include #elif defined(__OS_WINDOWS__) #include #endif void Stk :: sleep(unsigned long milliseconds) { #if defined(__OS_WINDOWS__) Sleep((DWORD) milliseconds); #elif (defined(__OS_IRIX__) || defined(__OS_LINUX__) || defined(__OS_MACOSX__)) usleep( (unsigned long) (milliseconds * 1000.0) ); #endif } void Stk :: handleError( StkError::Type type ) { handleError( errorString_.str(), type ); errorString_.str( std::string() ); // reset the ostringstream buffer } void Stk :: handleError( const char *message, StkError::Type type ) { std::string msg( message ); handleError( msg, type ); } void Stk :: handleError( std::string message, StkError::Type type ) { if ( type == StkError::WARNING || type == StkError::STATUS ) { if ( !showWarnings_ ) return; std::cerr << '\n' << message << '\n' << std::endl; } else if (type == StkError::DEBUG_WARNING) { #if defined(_STK_DEBUG_) std::cerr << '\n' << message << '\n' << std::endl; #endif } else { if ( printErrors_ ) { // Print error message before throwing. std::cerr << '\n' << message << '\n' << std::endl; } throw StkError(message, type); } } // // StkFrames definitions // StkFrames :: StkFrames( unsigned int nFrames, unsigned int nChannels, bool interleaved ) : nFrames_( nFrames ), nChannels_( nChannels ), interleaved_( interleaved ) { size_ = nFrames_ * nChannels_; bufferSize_ = size_; if ( size_ > 0 ) { data_ = (StkFloat *) calloc( size_, sizeof( StkFloat ) ); #if defined(_STK_DEBUG_) if ( data_ == NULL ) { std::string error = "StkFrames: memory allocation error in constructor!"; Stk::handleError( error, StkError::MEMORY_ALLOCATION ); } #endif } else data_ = 0; dataRate_ = Stk::sampleRate(); } StkFrames :: StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels, bool interleaved ) : nFrames_( nFrames ), nChannels_( nChannels ), interleaved_( interleaved ) { size_ = nFrames_ * nChannels_; bufferSize_ = size_; if ( size_ > 0 ) { data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) ); #if defined(_STK_DEBUG_) if ( data_ == NULL ) { std::string error = "StkFrames: memory allocation error in constructor!"; Stk::handleError( error, StkError::MEMORY_ALLOCATION ); } #endif for ( long i=0; i<(long)size_; i++ ) data_[i] = value; } else data_ = 0; dataRate_ = Stk::sampleRate(); } StkFrames :: ~StkFrames() { if ( data_ ) free( data_ ); } bool StkFrames :: empty() const { if ( size_ > 0 ) return false; else return true; } void StkFrames :: resize( size_t nFrames, unsigned int nChannels ) { nFrames_ = nFrames; nChannels_ = nChannels; size_ = nFrames_ * nChannels_; if ( size_ > bufferSize_ ) { if ( data_ ) free( data_ ); data_ = (StkFloat *) malloc( size_ * sizeof( StkFloat ) ); #if defined(_STK_DEBUG_) if ( data_ == NULL ) { std::string error = "StkFrames::resize: memory allocation error!"; Stk::handleError( error, StkError::MEMORY_ALLOCATION ); } #endif bufferSize_ = size_; } } void StkFrames :: resize( size_t nFrames, unsigned int nChannels, StkFloat value ) { this->resize( nFrames, nChannels ); for ( size_t i=0; i= size_ ) { std::ostringstream error; error << "StkFrames::operator[]: invalid index (" << n << ") value!"; Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); } #endif return data_[n]; } StkFloat StkFrames :: operator[] ( size_t n ) const { #if defined(_STK_DEBUG_) if ( n >= size_ ) { std::ostringstream error; error << "StkFrames::operator[]: invalid index (" << n << ") value!"; Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); } #endif return data_[n]; } StkFloat& StkFrames :: operator() ( size_t frame, unsigned int channel ) { #if defined(_STK_DEBUG_) if ( frame >= nFrames_ || channel >= nChannels_ ) { std::ostringstream error; error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!"; Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); } #endif if ( interleaved_ ) return data_[ frame * nChannels_ + channel ]; else return data_[ channel * nFrames_ + frame ]; } StkFloat StkFrames :: operator() ( size_t frame, unsigned int channel ) const { #if defined(_STK_DEBUG_) if ( frame >= nFrames_ || channel >= nChannels_ ) { std::ostringstream error; error << "StkFrames::operator(): invalid frame (" << frame << ") or channel (" << channel << ") value!"; Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); } #endif if ( interleaved_ ) return data_[ frame * nChannels_ + channel ]; else return data_[ channel * nFrames_ + frame ]; } StkFloat StkFrames :: interpolate( StkFloat frame, unsigned int channel ) const { #if defined(_STK_DEBUG_) if ( frame >= (StkFloat) nFrames_ || channel >= nChannels_ ) { std::ostringstream error; error << "StkFrames::interpolate: invalid frame (" << frame << ") or channel (" << channel << ") value!"; Stk::handleError( error.str(), StkError::MEMORY_ACCESS ); } #endif size_t iIndex = ( size_t ) frame; // integer part of index StkFloat output, alpha = frame - (StkFloat) iIndex; // fractional part of index if ( interleaved_ ) { iIndex = iIndex * nChannels_ + channel; output = data_[ iIndex ]; output += ( alpha * ( data_[ iIndex + nChannels_ ] - output ) ); } else { iIndex += channel * nFrames_; output = data_[ iIndex ]; output += ( alpha * ( data_[ iIndex++ ] - output ) ); } return output; } nyquist-3.05/nyqstk/src/Instrmnt.cpp0000644000175000000620000000361111466723256016642 0ustar stevestaff/***************************************************/ /*! \class Instrmnt \brief STK instrument abstract base class. This class provides a common interface for all STK instruments. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Instrmnt.h" using namespace Nyq; Instrmnt :: Instrmnt() { } Instrmnt :: ~Instrmnt() { } void Instrmnt :: setFrequency(StkFloat frequency) { errorString_ << "Instrmnt::setFrequency: virtual setFrequency function call!"; handleError( StkError::WARNING ); } StkFloat Instrmnt :: lastOut() const { return lastOutput_; } // Support for stereo output: StkFloat Instrmnt :: lastOutLeft(void) const { return 0.5 * lastOutput_; } StkFloat Instrmnt :: lastOutRight(void) const { return 0.5 * lastOutput_; } StkFloat Instrmnt :: tick( void ) { return computeSample(); } StkFrames& Instrmnt :: tick( StkFrames& frames, unsigned int channel ) { if ( channel >= frames.channels() ) { errorString_ << "Instrmnt::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( frames.channels() == 1 ) { for ( unsigned int i=0; iclear(); inPoint_ = 0; outPoint_ = 0; delay_ = 0; } Delay :: Delay(unsigned long delay, unsigned long maxDelay) { // Writing before reading allows delays from 0 to length-1. // If we want to allow a delay of maxDelay, we need a // delay-line of length = maxDelay+1. if ( maxDelay < 1 ) { errorString_ << "Delay::Delay: maxDelay must be > 0!\n"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( delay > maxDelay ) { errorString_ << "Delay::Delay: maxDelay must be > than delay argument!\n"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( maxDelay > inputs_.size()-1 ) { inputs_.resize( maxDelay+1 ); this->clear(); } inPoint_ = 0; this->setDelay( delay ); } Delay :: ~Delay() { } void Delay :: clear(void) { for (unsigned int i=0; i inputs_.size() - 1 ) { // The value is too big. errorString_ << "Delay::setDelay: argument (" << delay << ") too big ... setting to maximum!\n"; handleError( StkError::WARNING ); // Force delay to maximum length. outPoint_ = inPoint_ + 1; if ( outPoint_ == inputs_.size() ) outPoint_ = 0; delay_ = inputs_.size() - 1; } else if ( delay < 0 ) { errorString_ << "Delay::setDelay: argument (" << delay << ") less than zero ... setting to zero!\n"; handleError( StkError::WARNING ); outPoint_ = inPoint_; delay_ = 0; } else { // read chases write if ( inPoint_ >= delay ) outPoint_ = inPoint_ - delay; else outPoint_ = inputs_.size() + inPoint_ - delay; delay_ = delay; } } unsigned long Delay :: getDelay(void) const { return (unsigned long) delay_; } StkFloat Delay :: energy(void) const { unsigned long i; register StkFloat e = 0; if (inPoint_ >= outPoint_) { for (i=outPoint_; i delay_) { errorString_ << "Delay::contentsAt: argument (" << tapDelay << ") too big!"; handleError( StkError::WARNING ); return 0.0; } long tap = inPoint_ - i; if (tap < 0) // Check for wraparound. tap += inputs_.size(); return inputs_[tap]; } StkFloat Delay :: lastOut(void) const { return Filter::lastOut(); } StkFloat Delay :: nextOut(void) { return inputs_[outPoint_]; } StkFloat Delay :: computeSample( StkFloat input ) { inputs_[inPoint_++] = input; // Check for end condition if (inPoint_ == inputs_.size()) inPoint_ = 0; // Read out next value outputs_[0] = inputs_[outPoint_++]; if (outPoint_ == inputs_.size()) outPoint_ = 0; return outputs_[0]; } StkFloat Delay :: tick( StkFloat input ) { return computeSample( input ); } StkFrames& Delay :: tick( StkFrames& frames, unsigned int channel ) { return Filter::tick( frames, channel ); } nyquist-3.05/nyqstk/src/Sitar.cpp0000644000175000000620000000571211466723256016112 0ustar stevestaff/***************************************************/ /*! \class Sitar \brief STK sitar string model class. This class implements a sitar plucked string physical model based on the Karplus-Strong algorithm. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. There exist at least two patents, assigned to Stanford, bearing the names of Karplus and/or Strong. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Sitar.h" #include using namespace Nyq; Sitar :: Sitar(StkFloat lowestFrequency) { unsigned long length = (unsigned long) (Stk::sampleRate() / lowestFrequency + 1); delayLine_.setMaximumDelay( length ); delay_ = 0.5 * length; delayLine_.setDelay( delay_ ); targetDelay_ = delay_; loopFilter_.setZero(0.01); loopGain_ = 0.999; envelope_.setAllTimes(0.001, 0.04, 0.0, 0.5); this->clear(); } Sitar :: ~Sitar() { } void Sitar :: clear() { delayLine_.clear(); loopFilter_.clear(); } void Sitar :: setFrequency(StkFloat frequency) { StkFloat freakency = frequency; if ( frequency <= 0.0 ) { errorString_ << "Sitar::setFrequency: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); freakency = 220.0; } targetDelay_ = (Stk::sampleRate() / freakency); delay_ = targetDelay_ * (1.0 + (0.05 * noise_.tick())); delayLine_.setDelay( delay_ ); loopGain_ = 0.995 + (freakency * 0.0000005); if ( loopGain_ > 0.9995 ) loopGain_ = 0.9995; } void Sitar :: pluck(StkFloat amplitude) { envelope_.keyOn(); } void Sitar :: noteOn(StkFloat frequency, StkFloat amplitude) { this->setFrequency( frequency ); this->pluck( amplitude ); amGain_ = 0.1 * amplitude; #if defined(_STK_DEBUG_) errorString_ << "Sitar::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Sitar :: noteOff(StkFloat amplitude) { loopGain_ = (StkFloat) 1.0 - amplitude; if ( loopGain_ < 0.0 ) { errorString_ << "Sitar::noteOff: amplitude is greater than 1.0 ... setting to 1.0!"; handleError( StkError::WARNING ); loopGain_ = 0.0; } else if ( loopGain_ > 1.0 ) { errorString_ << "Sitar::noteOff: amplitude is < 0.0 ... setting to 0.0!"; handleError( StkError::WARNING ); loopGain_ = 0.99999; } #if defined(_STK_DEBUG_) errorString_ << "Sitar::NoteOff: amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } StkFloat Sitar :: computeSample() { if ( fabs(targetDelay_ - delay_) > 0.001 ) { if ( targetDelay_ < delay_ ) delay_ *= 0.99999; else delay_ *= 1.00001; delayLine_.setDelay( delay_ ); } lastOutput_ = delayLine_.tick( loopFilter_.tick( delayLine_.lastOut() * loopGain_ ) + (amGain_ * envelope_.tick() * noise_.tick())); return lastOutput_; } nyquist-3.05/nyqstk/src/Effect.cpp0000644000175000000620000000433511466723256016224 0ustar stevestaff/***************************************************/ /*! \class Effect \brief STK abstract effects parent class. This class provides common functionality for STK effects subclasses. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Effect.h" #include using namespace Nyq; Effect :: Effect() { } Effect :: ~Effect() { } void Effect :: setEffectMix(StkFloat mix) { if ( mix < 0.0 ) { errorString_ << "Effect::setEffectMix: mix parameter is less than zero ... setting to zero!"; handleError( StkError::WARNING ); effectMix_ = 0.0; } else if ( mix > 1.0 ) { errorString_ << "Effect::setEffectMix: mix parameter is greater than 1.0 ... setting to one!"; handleError( StkError::WARNING ); effectMix_ = 1.0; } else effectMix_ = mix; } StkFloat Effect :: lastOut() const { return (lastOutput_[0] + lastOutput_[1]) * 0.5; } StkFloat Effect :: lastOutLeft() const { return lastOutput_[0]; } StkFloat Effect :: lastOutRight() const { return lastOutput_[1]; } StkFloat Effect :: tick( StkFloat input ) { return computeSample( input ); } StkFrames& Effect :: tick( StkFrames& frames, unsigned int channel ) { if ( channel >= frames.channels() ) { errorString_ << "Effect::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( frames.channels() == 1 ) { for ( unsigned int i=0; i 1, the reed has slammed shut and the // reflection function value saturates at 1.0. if (lastOutput_ > 1.0) lastOutput_ = (StkFloat) 1.0; // This is nearly impossible in a physical system, but // a reflection function value of -1.0 corresponds to // an open end (and no discontinuity in bore profile). if (lastOutput_ < -1.0) lastOutput_ = (StkFloat) -1.0; return lastOutput_; } nyquist-3.05/nyqstk/src/SineWave.cpp0000644000175000000620000000451011466723256016544 0ustar stevestaff/***************************************************/ /*! \class SineWave \brief STK sinusoid oscillator class. This class computes and saves a static sine "table" that can be shared by multiple instances. It has an interface similar to the WaveLoop class but inherits from the Generator class. Output values are computed using linear interpolation. The "table" length, set in SineWave.h, is 2048 samples by default. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "SineWave.h" #include using namespace Nyq; StkFrames SineWave :: table_; SineWave :: SineWave( void ) : time_(0.0), rate_(1.0), phaseOffset_(0.0) { if ( table_.empty() ) { table_.resize( TABLE_SIZE + 1, 1 ); StkFloat temp = 1.0 / TABLE_SIZE; for ( unsigned long i=0; i<=TABLE_SIZE; i++ ) table_[i] = sin( TWO_PI * i * temp ); } } SineWave :: ~SineWave() { } void SineWave :: reset(void) { time_ = 0.0; lastOutput_ = 0; } void SineWave :: setFrequency( StkFloat frequency ) { // This is a looping frequency. this->setRate( TABLE_SIZE * frequency / Stk::sampleRate() ); } void SineWave :: addTime( StkFloat time ) { // Add an absolute time in samples. time_ += time; while ( time_ < 0.0 ) time_ += TABLE_SIZE; while ( time_ >= TABLE_SIZE ) time_ -= TABLE_SIZE; } void SineWave :: addPhase( StkFloat angle ) { // Add a time in cycles (one cycle = TABLE_SIZE). time_ += TABLE_SIZE * angle; while ( time_ < 0.0 ) time_ += TABLE_SIZE; while ( time_ >= TABLE_SIZE ) time_ -= TABLE_SIZE; } void SineWave :: addPhaseOffset( StkFloat angle ) { // Add a phase offset in cycles, where 1.0 = TABLE_SIZE. phaseOffset_ = TABLE_SIZE * angle; } StkFloat SineWave :: computeSample( void ) { // Check limits of time address ... if necessary, recalculate modulo // TABLE_SIZE. while ( time_ < 0.0 ) time_ += TABLE_SIZE; while ( time_ >= TABLE_SIZE ) time_ -= TABLE_SIZE; StkFloat tyme; if ( phaseOffset_ ) { tyme = time_ + phaseOffset_; while ( tyme < 0.0 ) tyme += TABLE_SIZE; while ( tyme >= TABLE_SIZE ) tyme -= TABLE_SIZE; } else { tyme = time_; } lastOutput_ = table_.interpolate( tyme ); // Increment time, which can be negative. time_ += rate_; return lastOutput_; } nyquist-3.05/nyqstk/src/JCRev.cpp0000644000175000000620000000655711466723256016011 0ustar stevestaff/***************************************************/ /*! \class JCRev \brief John Chowning's reverberator class. This class is derived from the CLM JCRev function, which is based on the use of networks of simple allpass and comb delay filters. This class implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "JCRev.h" #include using namespace Nyq; JCRev :: JCRev(StkFloat T60) { // Delay lengths for 44100 Hz sample rate. int lengths[9] = {1777, 1847, 1993, 2137, 389, 127, 43, 211, 179}; double scaler = Stk::sampleRate() / 44100.0; int delay, i; if ( scaler != 1.0 ) { for (i=0; i<9; i++) { delay = (int) floor(scaler * lengths[i]); if ( (delay & 1) == 0) delay++; while ( !this->isPrime(delay) ) delay += 2; lengths[i] = delay; } } for (i=0; i<3; i++) { allpassDelays_[i].setMaximumDelay( lengths[i+4] ); allpassDelays_[i].setDelay( lengths[i+4] ); } for ( i=0; i<4; i++ ) { combDelays_[i].setMaximumDelay( lengths[i] ); combDelays_[i].setDelay( lengths[i] ); } this->setT60( T60 ); outLeftDelay_.setMaximumDelay( lengths[7] ); outLeftDelay_.setDelay( lengths[7] ); outRightDelay_.setMaximumDelay( lengths[8] ); outRightDelay_.setDelay( lengths[8] ); allpassCoefficient_ = 0.7; effectMix_ = 0.3; this->clear(); } JCRev :: ~JCRev() { } void JCRev :: clear() { allpassDelays_[0].clear(); allpassDelays_[1].clear(); allpassDelays_[2].clear(); combDelays_[0].clear(); combDelays_[1].clear(); combDelays_[2].clear(); combDelays_[3].clear(); outRightDelay_.clear(); outLeftDelay_.clear(); lastOutput_[0] = 0.0; lastOutput_[1] = 0.0; } void JCRev :: setT60( StkFloat T60 ) { for ( int i=0; i<4; i++ ) combCoefficient_[i] = pow(10.0, (-3.0 * combDelays_[i].getDelay() / (T60 * Stk::sampleRate()))); } StkFloat JCRev :: computeSample(StkFloat input) { StkFloat temp, temp0, temp1, temp2, temp3, temp4, temp5, temp6; StkFloat filtout; temp = allpassDelays_[0].lastOut(); temp0 = allpassCoefficient_ * temp; temp0 += input; allpassDelays_[0].tick(temp0); temp0 = -(allpassCoefficient_ * temp0) + temp; temp = allpassDelays_[1].lastOut(); temp1 = allpassCoefficient_ * temp; temp1 += temp0; allpassDelays_[1].tick(temp1); temp1 = -(allpassCoefficient_ * temp1) + temp; temp = allpassDelays_[2].lastOut(); temp2 = allpassCoefficient_ * temp; temp2 += temp1; allpassDelays_[2].tick(temp2); temp2 = -(allpassCoefficient_ * temp2) + temp; temp3 = temp2 + (combCoefficient_[0] * combDelays_[0].lastOut()); temp4 = temp2 + (combCoefficient_[1] * combDelays_[1].lastOut()); temp5 = temp2 + (combCoefficient_[2] * combDelays_[2].lastOut()); temp6 = temp2 + (combCoefficient_[3] * combDelays_[3].lastOut()); combDelays_[0].tick(temp3); combDelays_[1].tick(temp4); combDelays_[2].tick(temp5); combDelays_[3].tick(temp6); filtout = temp3 + temp4 + temp5 + temp6; lastOutput_[0] = effectMix_ * (outLeftDelay_.tick(filtout)); lastOutput_[1] = effectMix_ * (outRightDelay_.tick(filtout)); temp = (1.0 - effectMix_) * input; lastOutput_[0] += temp; lastOutput_[1] += temp; return Effect::lastOut(); } nyquist-3.05/nyqstk/src/JetTable.cpp0000644000175000000620000000173411466723256016522 0ustar stevestaff/***************************************************/ /*! \class JetTable \brief STK jet table class. This class implements a flue jet non-linear function, computed by a polynomial calculation. Contrary to the name, this is not a "table". Consult Fletcher and Rossing, Karjalainen, Cook, and others for more information. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "JetTable.h" using namespace Nyq; JetTable :: JetTable() : Function() { } JetTable :: ~JetTable() { } StkFloat JetTable :: computeSample( StkFloat input ) { // Perform "table lookup" using a polynomial // calculation (x^3 - x), which approximates // the jet sigmoid behavior. lastOutput_ = input * (input * input - (StkFloat) 1.0); // Saturate at +/- 1.0. if (lastOutput_ > 1.0) lastOutput_ = (StkFloat) 1.0; if (lastOutput_ < -1.0) lastOutput_ = (StkFloat) -1.0; return lastOutput_; } nyquist-3.05/nyqstk/src/ReedTabl.cpp0000644000175000000620000000342510144436365016503 0ustar stevestaff/***************************************************/ /*! \class ReedTabl \brief STK reed table class. This class implements a simple one breakpoint, non-linear reed function, as described by Smith (1986). This function is based on a memoryless non-linear spring model of the reed (the reed mass is ignored) which saturates when the reed collides with the mouthpiece facing. See McIntyre, Schumacher, & Woodhouse (1983), Smith (1986), Hirschman, Cook, Scavone, and others for more information. by Perry R. Cook and Gary P. Scavone, 1995 - 2002. */ /***************************************************/ #include "ReedTabl.h" ReedTabl :: ReedTabl() { offSet = (MY_FLOAT) 0.6; // Offset is a bias, related to reed rest position. slope = (MY_FLOAT) -0.8; // Slope corresponds loosely to reed stiffness. } ReedTabl :: ~ReedTabl() { } void ReedTabl :: setOffset(MY_FLOAT aValue) { offSet = aValue; } void ReedTabl :: setSlope(MY_FLOAT aValue) { slope = aValue; } MY_FLOAT ReedTabl :: lastOut() const { return lastOutput; } MY_FLOAT ReedTabl :: tick(MY_FLOAT input) { // The input is differential pressure across the reed. lastOutput = offSet + (slope * input); // If output is > 1, the reed has slammed shut and the // reflection function value saturates at 1.0. if (lastOutput > 1.0) lastOutput = (MY_FLOAT) 1.0; // This is nearly impossible in a physical system, but // a reflection function value of -1.0 corresponds to // an open end (and no discontinuity in bore profile). if (lastOutput < -1.0) lastOutput = (MY_FLOAT) -1.0; return lastOutput; } MY_FLOAT *ReedTabl :: tick(MY_FLOAT *vector, unsigned int vectorSize) { for (unsigned int i=0; i>= 1; jetDelay_.setMaximumDelay( length_ ); jetDelay_.setDelay( 49.0 ); vibrato_.setFrequency( 5.925 ); this->clear(); filter_.setPole( 0.7 - ((StkFloat) 0.1 * 22050.0 / Stk::sampleRate() ) ); filter_.setGain( -1.0 ); dcBlock_.setBlockZero(); adsr_.setAllTimes( 0.005, 0.01, 0.8, 0.010); endReflection_ = 0.5; jetReflection_ = 0.5; noiseGain_ = 0.15; // Breath pressure random component. vibratoGain_ = 0.05; // Breath periodic vibrato component. jetRatio_ = 0.32; maxPressure_ = 0.0; lastFrequency_ = 220.0; } Flute :: ~Flute() { } void Flute :: clear() { jetDelay_.clear(); boreDelay_.clear(); filter_.clear(); dcBlock_.clear(); } void Flute :: setFrequency(StkFloat frequency) { lastFrequency_ = frequency; if ( frequency <= 0.0 ) { errorString_ << "Flute::setFrequency: parameter is less than or equal to zero!"; handleError( StkError::WARNING ); lastFrequency_ = 220.0; } // We're overblowing here. lastFrequency_ *= 0.66666; // delay = length - approximate filter delay. StkFloat delay = Stk::sampleRate() / lastFrequency_ - (StkFloat) 2.0; if ( delay <= 0.0 ) delay = 0.3; else if ( delay > length_ ) delay = length_; boreDelay_.setDelay(delay); jetDelay_.setDelay(delay * jetRatio_); } void Flute :: startBlowing(StkFloat amplitude, StkFloat rate) { adsr_.setAttackRate( rate ); maxPressure_ = amplitude / (StkFloat) 0.8; adsr_.keyOn(); } void Flute :: stopBlowing(StkFloat rate) { adsr_.setReleaseRate( rate ); adsr_.keyOff(); } void Flute :: noteOn(StkFloat frequency, StkFloat amplitude) { this->setFrequency( frequency ); this->startBlowing( 1.1 + (amplitude * 0.20), amplitude * 0.02 ); outputGain_ = amplitude + 0.001; #if defined(_STK_DEBUG_) errorString_ << "Flute::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Flute :: noteOff(StkFloat amplitude) { this->stopBlowing( amplitude * 0.02 ); #if defined(_STK_DEBUG_) errorString_ << "Flute::NoteOff: amplitude = " << amplitude << "."; handleError( StkError::DEBUG_WARNING ); #endif } void Flute :: setJetReflection(StkFloat coefficient) { jetReflection_ = coefficient; } void Flute :: setEndReflection(StkFloat coefficient) { endReflection_ = coefficient; } void Flute :: setJetDelay(StkFloat aRatio) { // Delay = length - approximate filter delay. StkFloat temp = Stk::sampleRate() / lastFrequency_ - (StkFloat) 2.0; jetRatio_ = aRatio; jetDelay_.setDelay(temp * aRatio); // Scaled by ratio. } StkFloat Flute :: computeSample() { StkFloat pressureDiff; StkFloat breathPressure; // Calculate the breath pressure (envelope + noise + vibrato) breathPressure = maxPressure_ * adsr_.tick(); breathPressure += breathPressure * ( noiseGain_ * noise_.tick() + vibratoGain_ * vibrato_.tick() ); //breathPressure += breathPressure * vibratoGain_ * vibrato_.tick(); StkFloat temp = filter_.tick( boreDelay_.lastOut() ); temp = dcBlock_.tick( temp ); // Block DC on reflection. pressureDiff = breathPressure - (jetReflection_ * temp); pressureDiff = jetDelay_.tick( pressureDiff ); pressureDiff = jetTable_.tick( pressureDiff ) + (endReflection_ * temp); lastOutput_ = (StkFloat) 0.3 * boreDelay_.tick( pressureDiff ); lastOutput_ *= outputGain_; return lastOutput_; } void Flute :: controlChange(int number, StkFloat value) { StkFloat norm = value * ONE_OVER_128; if ( norm < 0 ) { norm = 0.0; errorString_ << "Flute::controlChange: control value less than zero ... setting to zero!"; handleError( StkError::WARNING ); } else if ( norm > 1.0 ) { norm = 1.0; errorString_ << "Flute::controlChange: control value greater than 128.0 ... setting to 128.0!"; handleError( StkError::WARNING ); } if (number == __SK_JetDelay_) // 2 this->setJetDelay( (StkFloat) (0.08 + (0.48 * norm)) ); else if (number == __SK_NoiseLevel_) // 4 noiseGain_ = ( norm * 0.4); else if (number == __SK_ModFrequency_) // 11 vibrato_.setFrequency( norm * 12.0); else if (number == __SK_ModWheel_) // 1 vibratoGain_ = ( norm * 0.4 ); else if (number == __SK_AfterTouch_Cont_) // 128 adsr_.setTarget( norm ); else { errorString_ << "Flute::controlChange: undefined control number (" << number << ")!"; handleError( StkError::WARNING ); } #if defined(_STK_DEBUG_) errorString_ << "Flute::controlChange: number = " << number << ", value = " << value << "."; handleError( StkError::DEBUG_WARNING ); #endif } nyquist-3.05/nyqstk/src/Filter.cpp0000644000175000000620000001410211466723256016246 0ustar stevestaff/***************************************************/ /*! \class Filter \brief STK filter class. This class implements a generic structure that can be used to create a wide range of filters. It can function independently or be subclassed to provide more specific controls based on a particular filter type. In particular, this class implements the standard difference equation: a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] - a[1]*y[n-1] - ... - a[na]*y[n-na] If a[0] is not equal to 1, the filter coefficients are normalized by a[0]. The \e gain parameter is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. This structure results in one extra multiply per computed sample, but allows easy control of the overall filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Filter.h" #include using namespace Nyq; Filter :: Filter() { // The default constructor should setup for pass-through. gain_ = 1.0; b_.push_back( 1.0 ); a_.push_back( 1.0 ); inputs_.push_back( 0.0 ); outputs_.push_back( 0.0 ); } Filter :: Filter( std::vector &bCoefficients, std::vector &aCoefficients ) { // Check the arguments. if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) { errorString_ << "Filter: a and b coefficient vectors must both have size > 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( aCoefficients[0] == 0.0 ) { errorString_ << "Filter: a[0] coefficient cannot == 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } gain_ = 1.0; b_ = bCoefficients; a_ = aCoefficients; inputs_ = std::vector ( b_.size() ); outputs_ = std::vector ( a_.size() ); this->clear(); } Filter :: ~Filter() { } void Filter :: clear(void) { unsigned int i; for (i=0; i &bCoefficients, std::vector &aCoefficients, bool clearState ) { // Check the arguments. if ( bCoefficients.size() == 0 || aCoefficients.size() == 0 ) { errorString_ << "Filter::setCoefficients: a and b coefficient vectors must both have size > 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( aCoefficients[0] == 0.0 ) { errorString_ << "Filter::setCoefficients: a[0] coefficient cannot == 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( b_.size() != bCoefficients.size() ) { b_ = bCoefficients; inputs_.clear(); inputs_ = std::vector ( b_.size() ); } else { for ( unsigned int i=0; i ( a_.size() ); } else { for ( unsigned int i=0; iclear(); // Scale coefficients by a[0] if necessary if ( a_[0] != 1.0 ) { unsigned int i; for ( i=0; i &bCoefficients, bool clearState ) { // Check the argument. if ( bCoefficients.size() == 0 ) { errorString_ << "Filter::setNumerator: coefficient vector must have size > 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( b_.size() != bCoefficients.size() ) { b_ = bCoefficients; inputs_.clear(); inputs_ = std::vector ( b_.size() ); } else { for ( unsigned int i=0; iclear(); } void Filter :: setDenominator( std::vector &aCoefficients, bool clearState ) { // Check the argument. if ( aCoefficients.size() == 0 ) { errorString_ << "Filter::setDenominator: coefficient vector must have size > 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( aCoefficients[0] == 0.0 ) { errorString_ << "Filter::setDenominator: a[0] coefficient cannot == 0!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( a_.size() != aCoefficients.size() ) { a_ = aCoefficients; outputs_.clear(); outputs_ = std::vector ( a_.size() ); } else { for ( unsigned int i=0; iclear(); // Scale coefficients by a[0] if necessary if ( a_[0] != 1.0 ) { unsigned int i; for ( i=0; i0; i--) { outputs_[0] += b_[i] * inputs_[i]; inputs_[i] = inputs_[i-1]; } outputs_[0] += b_[0] * inputs_[0]; for (i=a_.size()-1; i>0; i--) { outputs_[0] += -a_[i] * outputs_[i]; outputs_[i] = outputs_[i-1]; } return outputs_[0]; } StkFrames& Filter :: tick( StkFrames& frames, unsigned int channel ) { if ( channel >= frames.channels() ) { errorString_ << "Filter::tick(): channel and StkFrames arguments are incompatible!"; handleError( StkError::FUNCTION_ARGUMENT ); } if ( frames.channels() == 1 ) { for ( unsigned int i=0; isetAttackTime(aTime); this->setDecayTime(dTime); this->setSustainLevel(sLevel); this->setReleaseTime(rTime); } void ADSR :: setTarget(StkFloat target) { target_ = target; if (value_ < target_) { state_ = ATTACK; this->setSustainLevel(target_); rate_ = attackRate_; } if (value_ > target_) { this->setSustainLevel(target_); state_ = DECAY; rate_ = decayRate_; } } void ADSR :: setValue(StkFloat value) { state_ = SUSTAIN; target_ = value; value_ = value; this->setSustainLevel(value); rate_ = (StkFloat) 0.0; } int ADSR :: getState(void) const { return state_; } StkFloat ADSR :: computeSample() { switch (state_) { case ATTACK: value_ += rate_; if (value_ >= target_) { value_ = target_; rate_ = decayRate_; target_ = sustainLevel_; state_ = DECAY; } break; case DECAY: value_ -= decayRate_; if (value_ <= sustainLevel_) { value_ = sustainLevel_; rate_ = (StkFloat) 0.0; state_ = SUSTAIN; } break; case RELEASE: value_ -= releaseRate_; if (value_ <= 0.0) { value_ = (StkFloat) 0.0; state_ = DONE; } } lastOutput_ = value_; return value_; } nyquist-3.05/nyqstk/src/PitShift.cpp0000644000175000000620000000414311466723256016557 0ustar stevestaff/***************************************************/ /*! \class PitShift \brief STK simple pitch shifter effect class. This class implements a simple pitch shifter using delay lines. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "PitShift.h" #include using namespace Nyq; const int maxDelay = 5024; PitShift :: PitShift() { delayLength = maxDelay - 24; halfLength = delayLength / 2; delay_[0] = 12; delay_[1] = maxDelay / 2; delayLine_[0].setMaximumDelay( maxDelay ); delayLine_[0].setDelay( delay_[0] ); delayLine_[1].setMaximumDelay( maxDelay ); delayLine_[1].setDelay( delay_[1] ); effectMix_ = 0.5; rate_ = 1.0; } PitShift :: ~PitShift() { } void PitShift :: clear() { delayLine_[0].clear(); delayLine_[1].clear(); lastOutput_[0] = 0.0; lastOutput_[1] = 0.0; } void PitShift :: setShift(StkFloat shift) { if (shift < 1.0) { rate_ = 1.0 - shift; } else if (shift > 1.0) { rate_ = 1.0 - shift; } else { rate_ = 0.0; delay_[0] = halfLength+12; } } StkFloat PitShift :: computeSample(StkFloat input) { // Calculate the two delay length values, keeping them within the // range 12 to maxDelay-12. delay_[0] += rate_; while (delay_[0] > maxDelay-12) delay_[0] -= delayLength; while (delay_[0] < 12) delay_[0] += delayLength; delay_[1] = delay_[0] + halfLength; while (delay_[1] > maxDelay-12) delay_[1] -= delayLength; while (delay_[1] < 12) delay_[1] += delayLength; // Set the new delay line lengths. delayLine_[0].setDelay((long)delay_[0]); delayLine_[1].setDelay((long)delay_[1]); // Calculate a triangular envelope. env_[1] = fabs( (delay_[0] - halfLength + 12) * (1.0 / (halfLength+12) ) ); env_[0] = 1.0 - env_[1]; // Delay input and apply envelope. lastOutput_[0] = env_[0] * delayLine_[0].tick(input); lastOutput_[0] += env_[1] * delayLine_[1].tick(input); // Compute effect mix and output. lastOutput_[0] *= effectMix_; lastOutput_[0] += (1.0 - effectMix_) * input; lastOutput_[1] = lastOutput_[0]; return lastOutput_[0]; } nyquist-3.05/nyqstk/instr.h0000644000175000000620000000201611466723256015037 0ustar stevestaff#ifndef _INSTR_H #define _INSTR_H #include "globals.h" /* C interface to Instrmnt */ /* Instrument types */ #define CLARINET 0 #define SAXOFONY 1 #define BOWED 2 #define BANDEDWG 3 #define MANDOLIN 4 #define SITAR 5 #define MODALBAR 6 #define FLUTE 7 struct instr; #ifdef __cplusplus extern "C" { #endif struct stkgen *initStkGen(); int deleteStkGen(struct stkgen *); MY_FLOAT gentick(struct stkgen *); void setrawwavepath(char *); struct instr *initInstrument(int instr_type, int sample_rate); int deleteInstrument(struct instr* in); int noteOn(struct instr* in, MY_FLOAT frequency, MY_FLOAT amplitude); int noteOff(struct instr* in, MY_FLOAT amplitude); int setFrequency(struct instr* in, MY_FLOAT frequency); //MY_FLOAT lastOut(struct instr* in); MY_FLOAT tick(struct instr* in); //MY_FLOAT *multTicks(struct instr* in, MY_FLOAT *vector, unsigned int vectorSize); int controlChange(struct instr* in, int number, MY_FLOAT value); #ifdef __cplusplus } #endif #endif nyquist-3.05/nyqstk/globals.h0000644000175000000620000000011210144436365015310 0ustar stevestaff#ifndef _GLOBALS_H #define _GLOBALS_H typedef double MY_FLOAT; #endif nyquist-3.05/nyqstk/include/0002755000175000000620000000000011537433122015142 5ustar stevestaffnyquist-3.05/nyqstk/include/Flute.h0000644000175000000620000000534411466723256016411 0ustar stevestaff/***************************************************/ /*! \class Flute \brief STK flute physical model class. This class implements a simple flute physical model, as discussed by Karjalainen, Smith, Waryznyk, etc. The jet model uses a polynomial, a la Cook. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Jet Delay = 2 - Noise Gain = 4 - Vibrato Frequency = 11 - Vibrato Gain = 1 - Breath Pressure = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_FLUTE_H #define STK_FLUTE_H #include "Instrmnt.h" #include "JetTable.h" #include "DelayL.h" #include "OnePole.h" #include "PoleZero.h" #include "Noise.h" #include "ADSR.h" #include "SineWave.h" namespace Nyq { class Flute : public Instrmnt { public: //! Class constructor, taking the lowest desired playing frequency. /*! An StkError will be thrown if the rawwave path is incorrectly set. */ Flute(StkFloat lowestFrequency); //! Class destructor. ~Flute(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. void setFrequency(StkFloat frequency); //! Set the reflection coefficient for the jet delay (-1.0 - 1.0). void setJetReflection(StkFloat coefficient); //! Set the reflection coefficient for the air column delay (-1.0 - 1.0). void setEndReflection(StkFloat coefficient); //! Set the length of the jet delay in terms of a ratio of jet delay to air column delay lengths. void setJetDelay(StkFloat aRatio); //! Apply breath velocity to instrument with given amplitude and rate of increase. void startBlowing(StkFloat amplitude, StkFloat rate); //! Decrease breath velocity with given rate of decrease. void stopBlowing(StkFloat rate); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); protected: StkFloat computeSample( void ); DelayL jetDelay_; DelayL boreDelay_; JetTable jetTable_; OnePole filter_; PoleZero dcBlock_; Noise noise_; ADSR adsr_; SineWave vibrato_; unsigned long length_; StkFloat lastFrequency_; StkFloat maxPressure_; StkFloat jetReflection_; StkFloat endReflection_; StkFloat noiseGain_; StkFloat vibratoGain_; StkFloat outputGain_; StkFloat jetRatio_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/WvIn.h0000644000175000000620000000514211466723256016211 0ustar stevestaff/***************************************************/ /*! \class WvIn \brief STK audio input abstract base class. This class provides common functionality for a variety of audio data input subclasses. WvIn supports multi-channel data. It is important to distinguish the tick() methods, which return samples produced by averaging across sample frames, from the tickFrame() methods, which return references or pointers to multi-channel sample frames. Both interleaved and non-interleaved data is supported via the use of StkFrames objects. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_WVIN_H #define STK_WVIN_H #include "Stk.h" #include namespace Nyq { class WvIn : public Stk { public: //! Default constructor. WvIn(); //! Class destructor. virtual ~WvIn(); //! Return the number of audio channels in the data. unsigned int getChannels( void ) const { return data_.channels(); }; //! Return the average across the last output sample frame. /*! If no file data is loaded, the returned value is 0.0. */ StkFloat lastOut( void ) const; //! Return an StkFrames reference to the last output sample frame. /*! If no file data is loaded, an empty container is returned. */ const StkFrames& lastFrame( void ) const { return lastOutputs_; }; //! Read out the average across one sample frame of data. /*! If no file data is loaded, the returned value is 0.0. */ StkFloat tick( void ); //! Fill a channel of the StkFrames object with averaged sample frames. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is greater than or equal to the number of channels in the StkFrames object. If no file data is loaded, the container is filled with zeroes. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); //! Fill the StkFrames argument with data and return the same reference. /*! An StkError will be thrown if there is an incompatability between the number of channels in the loaded data and that in the StkFrames argument. If no file data is loaded, the container is filled with zeroes. */ StkFrames& tickFrame( StkFrames& frames ); protected: // This abstract function must be implemented in all subclasses. // It is used to get around a C++ problem with overloaded virtual // functions. virtual void computeFrame( void ) = 0; StkFrames data_; StkFrames lastOutputs_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/WaveLoop.h0000644000175000000620000000604711466723256017067 0ustar stevestaff/***************************************************/ /*! \class WaveLoop \brief STK waveform oscillator class. This class inherits from FileWvIn and provides audio file looping functionality. Any audio file that can be loaded by FileRead can be looped using this class. WaveLoop supports multi-channel data. It is important to distinguish the tick() methods, which return samples produced by averaging across sample frames, from the tickFrame() methods, which return references or pointers to multi-channel sample frames. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_WAVELOOP_H #define STK_WAVELOOP_H #include "FileWvIn.h" namespace Nyq { class WaveLoop : public FileWvIn { public: //! Default constructor. WaveLoop( unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 ); //! Class constructor that opens a specified file. WaveLoop( std::string fileName, bool raw = false, bool doNormalize = true, unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 ); //! Class destructor. virtual ~WaveLoop(); //! Open the specified file and load its data. /*! Data from a previously opened file will be overwritten by this function. An StkError will be thrown if the file is not found, its format is unknown, or a read error occurs. If the file data is to be loaded incrementally from disk and normalization is specified, a scaling will be applied with respect to fixed-point limits. If the data format is floating-point, no scaling is performed. */ void openFile( std::string fileName, bool raw = false, bool doNormalize = true ); //! Set the data read rate in samples. The rate can be negative. /*! If the rate value is negative, the data is read in reverse order. */ void setRate( StkFloat rate ); //! Set the data interpolation rate based on a looping frequency. /*! This function determines the interpolation rate based on the file size and the current Stk::sampleRate. The \e frequency value corresponds to file cycles per second. The frequency can be negative, in which case the loop is read in reverse order. */ void setFrequency( StkFloat frequency ); //! Increment the read pointer by \e time samples, modulo file size. void addTime( StkFloat time ); //! Increment current read pointer by \e angle, relative to a looping frequency. /*! This function increments the read pointer based on the file size and the current Stk::sampleRate. The \e anAngle value is a multiple of file size. */ void addPhase( StkFloat angle ); //! Add a phase offset to the current read pointer. /*! This function determines a time offset based on the file size and the current Stk::sampleRate. The \e angle value is a multiple of file size. */ void addPhaseOffset( StkFloat angle ); protected: virtual void computeFrame( void ); StkFrames firstFrame_; StkFloat phaseOffset_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/SKINI.msg0000644000175000000620000001047611466723256016550 0ustar stevestaff/*********************************************************/ /* Definition of SKINI Message Types and Special Symbols Synthesis toolKit Instrument Network Interface These symbols should have the form __SK__ Where is the string used in the SKINI stream. by Perry R. Cook, 1995 - 2002. */ /*********************************************************/ namespace Nyq { /***** MIDI COMPATIBLE MESSAGES *****/ /***** Status Bytes Have Channel=0 **/ #define NOPE -32767 #define YEP 1 #define SK_DBL -32766 #define SK_INT -32765 #define SK_STR -32764 #define __SK_NoteOff_ 128 #define __SK_NoteOn_ 144 #define __SK_PolyPressure_ 160 #define __SK_ControlChange_ 176 #define __SK_ProgramChange_ 192 #define __SK_AfterTouch_ 208 #define __SK_ChannelPressure_ __SK_AfterTouch_ #define __SK_PitchWheel_ 224 #define __SK_PitchBend_ __SK_PitchWheel_ #define __SK_PitchChange_ 249 #define __SK_Clock_ 248 #define __SK_SongStart_ 250 #define __SK_Continue_ 251 #define __SK_SongStop_ 252 #define __SK_ActiveSensing_ 254 #define __SK_SystemReset_ 255 #define __SK_Volume_ 7 #define __SK_ModWheel_ 1 #define __SK_Modulation_ __SK_ModWheel_ #define __SK_Breath_ 2 #define __SK_FootControl_ 4 #define __SK_Portamento_ 65 #define __SK_Balance_ 8 #define __SK_Pan_ 10 #define __SK_Sustain_ 64 #define __SK_Damper_ __SK_Sustain_ #define __SK_Expression_ 11 #define __SK_AfterTouch_Cont_ 128 #define __SK_ModFrequency_ __SK_Expression_ #define __SK_ProphesyRibbon_ 16 #define __SK_ProphesyWheelUp_ 2 #define __SK_ProphesyWheelDown_ 3 #define __SK_ProphesyPedal_ 18 #define __SK_ProphesyKnob1_ 21 #define __SK_ProphesyKnob2_ 22 /*** Instrument Family Specific ***/ #define __SK_NoiseLevel_ __SK_FootControl_ #define __SK_PickPosition_ __SK_FootControl_ #define __SK_StringDamping_ __SK_Expression_ #define __SK_StringDetune_ __SK_ModWheel_ #define __SK_BodySize_ __SK_Breath_ #define __SK_BowPressure_ __SK_Breath_ #define __SK_BowPosition_ __SK_PickPosition_ #define __SK_BowBeta_ __SK_BowPosition_ #define __SK_ReedStiffness_ __SK_Breath_ #define __SK_ReedRestPos_ __SK_FootControl_ #define __SK_FluteEmbouchure_ __SK_Breath_ #define __SK_JetDelay_ __SK_FluteEmbouchure_ #define __SK_LipTension_ __SK_Breath_ #define __SK_SlideLength_ __SK_FootControl_ #define __SK_StrikePosition_ __SK_PickPosition_ #define __SK_StickHardness_ __SK_Breath_ #define __SK_TrillDepth_ 1051 #define __SK_TrillSpeed_ 1052 #define __SK_StrumSpeed_ __SK_TrillSpeed_ #define __SK_RollSpeed_ __SK_TrillSpeed_ #define __SK_FilterQ_ __SK_Breath_ #define __SK_FilterFreq_ 1062 #define __SK_FilterSweepRate_ __SK_FootControl_ #define __SK_ShakerInst_ 1071 #define __SK_ShakerEnergy_ __SK_Breath_ #define __SK_ShakerDamping_ __SK_ModFrequency_ #define __SK_ShakerNumObjects_ __SK_FootControl_ #define __SK_Strumming_ 1090 #define __SK_NotStrumming_ 1091 #define __SK_Trilling_ 1092 #define __SK_NotTrilling_ 1093 #define __SK_Rolling_ __SK_Strumming_ #define __SK_NotRolling_ __SK_NotStrumming_ #define __SK_PlayerSkill_ 2001 #define __SK_Chord_ 2002 #define __SK_ChordOff_ 2003 #define __SK_SINGER_FilePath_ 3000 #define __SK_SINGER_Frequency_ 3001 #define __SK_SINGER_NoteName_ 3002 #define __SK_SINGER_Shape_ 3003 #define __SK_SINGER_Glot_ 3004 #define __SK_SINGER_VoicedUnVoiced_ 3005 #define __SK_SINGER_Synthesize_ 3006 #define __SK_SINGER_Silence_ 3007 #define __SK_SINGER_VibratoAmt_ __SK_ModWheel_ #define __SK_SINGER_RndVibAmt_ 3008 #define __SK_SINGER_VibFreq_ __SK_Expression_ } // namespace Nyq nyquist-3.05/nyqstk/include/ReedTable.h0000644000175000000620000000260111466723256017152 0ustar stevestaff/***************************************************/ /*! \class ReedTable \brief STK reed table class. This class implements a simple one breakpoint, non-linear reed function, as described by Smith (1986). This function is based on a memoryless non-linear spring model of the reed (the reed mass is ignored) which saturates when the reed collides with the mouthpiece facing. See McIntyre, Schumacher, & Woodhouse (1983), Smith (1986), Hirschman, Cook, Scavone, and others for more information. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_REEDTABLE_H #define STK_REEDTABLE_H #include "Function.h" namespace Nyq { class ReedTable : public Function { public: //! Default constructor. ReedTable(); //! Class destructor. ~ReedTable(); //! Set the table offset value. /*! The table offset roughly corresponds to the size of the initial reed tip opening (a greater offset represents a smaller opening). */ void setOffset(StkFloat offset); //! Set the table slope value. /*! The table slope roughly corresponds to the reed stiffness (a greater slope represents a harder reed). */ void setSlope(StkFloat slope); protected: StkFloat computeSample( StkFloat input ); StkFloat offset_; StkFloat slope_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Instrmnt.h0000644000175000000620000000362011466723256017143 0ustar stevestaff/***************************************************/ /*! \class Instrmnt \brief STK instrument abstract base class. This class provides a common interface for all STK instruments. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_INSTRMNT_H #define STK_INSTRMNT_H #include "Stk.h" namespace Nyq { class Instrmnt : public Stk { public: //! Default constructor. Instrmnt(); //! Class destructor. virtual ~Instrmnt(); //! Start a note with the given frequency and amplitude. virtual void noteOn(StkFloat frequency, StkFloat amplitude) = 0; //! Stop a note with the given amplitude (speed of decay). virtual void noteOff(StkFloat amplitude) = 0; //! Set instrument parameters for a particular frequency. virtual void setFrequency(StkFloat frequency); //! Return the last output value. StkFloat lastOut() const; //! Return the last left output value. StkFloat lastOutLeft() const; //! Return the last right output value. StkFloat lastOutRight() const; //! Compute one sample and output. StkFloat tick( void ); //! Fill a channel of the StkFrames object with computed outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). virtual void controlChange(int number, StkFloat value); protected: // This abstract function must be implemented in all subclasses. // It is used to get around a C++ problem with overloaded virtual // functions. virtual StkFloat computeSample( void ) = 0; StkFloat lastOutput_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/PoleZero.h0000644000175000000620000000475511466723256017076 0ustar stevestaff/***************************************************/ /*! \class PoleZero \brief STK one-pole, one-zero filter class. This protected Filter subclass implements a one-pole, one-zero digital filter. A method is provided for creating an allpass filter with a given coefficient. Another method is provided to create a DC blocking filter. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_POLEZERO_H #define STK_POLEZERO_H #include "Filter.h" namespace Nyq { class PoleZero : protected Filter { public: //! Default constructor creates a first-order pass-through filter. PoleZero(); //! Class destructor. ~PoleZero(); //! Clears the internal states of the filter. void clear(void); //! Set the b[0] coefficient value. void setB0(StkFloat b0); //! Set the b[1] coefficient value. void setB1(StkFloat b1); //! Set the a[1] coefficient value. void setA1(StkFloat a1); //! Set the filter for allpass behavior using \e coefficient. /*! This method uses \e coefficient to create an allpass filter, which has unity gain at all frequencies. Note that the \e coefficient magnitude must be less than one to maintain stability. */ void setAllpass(StkFloat coefficient); //! Create a DC blocking filter with the given pole position in the z-plane. /*! This method sets the given pole position, together with a zero at z=1, to create a DC blocking filter. \e thePole should be close to one to minimize low-frequency attenuation. */ void setBlockZero(StkFloat thePole = 0.99); //! Set the filter gain. /*! The gain is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. */ void setGain( StkFloat gain ); //! Return the current filter gain. StkFloat getGain( void ) const; //! Return the last computed output value. StkFloat lastOut( void ) const; //! Input one sample to the filter and return one output. StkFloat tick( StkFloat sample ); //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Function.h0000644000175000000620000000273011466723256017113 0ustar stevestaff/***************************************************/ /*! \class Function \brief STK abstract function parent class. This class provides common functionality for STK classes which implement tables or other types of input to output function mappings. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Stk.h" #ifndef STK_FUNCTION_H #define STK_FUNCTION_H namespace Nyq { class Function : public Stk { public: //! Class constructor. Function(); //! Class destructor. virtual ~Function(); //! Return the last output value. virtual StkFloat lastOut() const { return lastOutput_; }; //! Take one sample input and compute one sample of output. StkFloat tick( StkFloat input ); //! Take a channel of the StkFrames object as inputs to the function and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); protected: // This abstract function must be implemented in all subclasses. // It is used to get around a C++ problem with overloaded virtual // functions. virtual StkFloat computeSample( StkFloat input ) = 0; StkFloat lastOutput_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/DelayA.h0000644000175000000620000000423311466723256016465 0ustar stevestaff/***************************************************/ /*! \class DelayA \brief STK allpass interpolating delay line class. This Delay subclass implements a fractional-length digital delay-line using a first-order allpass filter. A fixed maximum length of 4095 and a delay of 0.5 is set using the default constructor. Alternatively, the delay and maximum length can be set during instantiation with an overloaded constructor. An allpass filter has unity magnitude gain but variable phase delay properties, making it useful in achieving fractional delays without affecting a signal's frequency magnitude response. In order to achieve a maximally flat phase delay response, the minimum delay possible in this implementation is limited to a value of 0.5. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_DELAYA_H #define STK_DELAYA_H #include "Delay.h" namespace Nyq { class DelayA : public Delay { public: //! Default constructor creates a delay-line with maximum length of 4095 samples and zero delay. DelayA(); //! Overloaded constructor which specifies the current and maximum delay-line lengths. /*! An StkError will be thrown if the delay parameter is less than zero, the maximum delay parameter is less than one, or the delay parameter is greater than the maxDelay value. */ DelayA(StkFloat delay, unsigned long maxDelay); //! Class destructor. ~DelayA(); //! Clears the internal state of the delay line. void clear(); //! Set the delay-line length /*! The valid range for \e theDelay is from 0.5 to the maximum delay-line length. */ void setDelay(StkFloat delay); //! Return the current delay-line length. StkFloat getDelay(void) const; //! Return the value which will be output by the next call to tick(). /*! This method is valid only for delay settings greater than zero! */ StkFloat nextOut(void); protected: StkFloat computeSample( StkFloat input ); StkFloat alpha_; StkFloat coeff_; StkFloat apInput_; StkFloat nextOutput_; bool doNextOut_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/NRev.h0000644000175000000620000000240511466723256016177 0ustar stevestaff/***************************************************/ /*! \class NRev \brief CCRMA's NRev reverberator class. This class is derived from the CLM NRev function, which is based on the use of networks of simple allpass and comb delay filters. This particular arrangement consists of 6 comb filters in parallel, followed by 3 allpass filters, a lowpass filter, and another allpass in series, followed by two allpass filters in parallel with corresponding right and left outputs. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_NREV_H #define STK_NREV_H #include "Effect.h" #include "Delay.h" namespace Nyq { class NRev : public Effect { public: //! Class constructor taking a T60 decay time argument (one second default value). NRev( StkFloat T60 = 1.0 ); //! Class destructor. ~NRev(); //! Reset and clear all internal state. void clear(); //! Set the reverberation T60 decay time. void setT60( StkFloat T60 ); protected: StkFloat computeSample( StkFloat input ); Delay allpassDelays_[8]; Delay combDelays_[6]; StkFloat allpassCoefficient_; StkFloat combCoefficient_[6]; StkFloat lowpassState_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/ADSR.h0000644000175000000620000000405711466723256016063 0ustar stevestaff/***************************************************/ /*! \class ADSR \brief STK ADSR envelope class. This Envelope subclass implements a traditional ADSR (Attack, Decay, Sustain, Release) envelope. It responds to simple keyOn and keyOff messages, keeping track of its state. The \e state = ADSR::DONE after the envelope value reaches 0.0 in the ADSR::RELEASE state. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_ADSR_H #define STK_ADSR_H #include "Envelope.h" namespace Nyq { class ADSR : public Envelope { public: //! Envelope states. enum { ATTACK, DECAY, SUSTAIN, RELEASE, DONE }; //! Default constructor. ADSR(void); //! Class destructor. ~ADSR(void); //! Set target = 1, state = \e ADSR::ATTACK. void keyOn(void); //! Set target = 0, state = \e ADSR::RELEASE. void keyOff(void); //! Set the attack rate. void setAttackRate(StkFloat rate); //! Set the decay rate. void setDecayRate(StkFloat rate); //! Set the sustain level. void setSustainLevel(StkFloat level); //! Set the release rate. void setReleaseRate(StkFloat rate); //! Set the attack rate based on a time duration. void setAttackTime(StkFloat time); //! Set the decay rate based on a time duration. void setDecayTime(StkFloat time); //! Set the release rate based on a time duration. void setReleaseTime(StkFloat time); //! Set sustain level and attack, decay, and release time durations. void setAllTimes(StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime); //! Set the target value. void setTarget(StkFloat target); //! Return the current envelope \e state (ATTACK, DECAY, SUSTAIN, RELEASE, DONE). int getState(void) const; //! Set to state = ADSR::SUSTAIN with current and target values of \e aValue. void setValue(StkFloat value); protected: StkFloat computeSample( void ); StkFloat attackRate_; StkFloat decayRate_; StkFloat sustainLevel_; StkFloat releaseRate_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Generator.h0000644000175000000620000000254711466723256017262 0ustar stevestaff/***************************************************/ /*! \class Generator \brief STK abstract unit generator parent class. This class provides common functionality for STK unit generator sample-source subclasses. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_GENERATOR_H #define STK_GENERATOR_H #include "Stk.h" namespace Nyq { class Generator : public Stk { public: //! Class constructor. Generator( void ); //! Class destructor. virtual ~Generator( void ); //! Return the last output value. virtual StkFloat lastOut( void ) const { return lastOutput_; }; //! Compute one sample and output. StkFloat tick( void ); //! Fill a channel of the StkFrames object with computed outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); protected: // This abstract function must be implemented in all subclasses. // It is used to get around a C++ problem with overloaded virtual // functions. virtual StkFloat computeSample( void ) = 0; StkFloat lastOutput_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/JCRev.h0000644000175000000620000000231011466723256016271 0ustar stevestaff/***************************************************/ /*! \class JCRev \brief John Chowning's reverberator class. This class is derived from the CLM JCRev function, which is based on the use of networks of simple allpass and comb delay filters. This class implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_JCREV_H #define STK_JCREV_H #include "Effect.h" #include "Delay.h" namespace Nyq { class JCRev : public Effect { public: //! Class constructor taking a T60 decay time argument (one second default value). JCRev( StkFloat T60 = 1.0 ); //! Class destructor. ~JCRev(); //! Reset and clear all internal state. void clear(); //! Set the reverberation T60 decay time. void setT60( StkFloat T60 ); protected: StkFloat computeSample( StkFloat input ); Delay allpassDelays_[3]; Delay combDelays_[4]; Delay outLeftDelay_; Delay outRightDelay_; StkFloat allpassCoefficient_; StkFloat combCoefficient_[4]; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/SineWave.h0000644000175000000620000000446711466723256017060 0ustar stevestaff/***************************************************/ /*! \class SineWave \brief STK sinusoid oscillator class. This class computes and saves a static sine "table" that can be shared by multiple instances. It has an interface similar to the WaveLoop class but inherits from the Generator class. Output values are computed using linear interpolation. The "table" length, set in SineWave.h, is 2048 samples by default. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_SINEWAVE_H #define STK_SINEWAVE_H namespace Nyq { const unsigned long TABLE_SIZE = 2048; } // namespace Nyq #include "Generator.h" namespace Nyq { class SineWave : public Generator { public: //! Default constructor. SineWave( void ); //! Class destructor. virtual ~SineWave( void ); //! Clear output and reset time pointer to zero. void reset( void ); //! Set the data read rate in samples. The rate can be negative. /*! If the rate value is negative, the data is read in reverse order. */ void setRate( StkFloat rate ) { rate_ = rate; }; //! Set the data interpolation rate based on a looping frequency. /*! This function determines the interpolation rate based on the file size and the current Stk::sampleRate. The \e frequency value corresponds to file cycles per second. The frequency can be negative, in which case the loop is read in reverse order. */ void setFrequency( StkFloat frequency ); //! Increment the read pointer by \e time samples, modulo file size. void addTime( StkFloat time ); //! Increment current read pointer by \e angle, relative to a looping frequency. /*! This function increments the read pointer based on the file size and the current Stk::sampleRate. The \e anAngle value is a multiple of file size. */ void addPhase( StkFloat angle ); //! Add a phase offset to the current read pointer. /*! This function determines a time offset based on the file size and the current Stk::sampleRate. The \e angle value is a multiple of file size. */ void addPhaseOffset( StkFloat angle ); protected: StkFloat computeSample( void ); static StkFrames table_; StkFloat time_; StkFloat rate_; StkFloat phaseOffset_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/OnePole.h0000644000175000000620000000437411466723256016675 0ustar stevestaff/***************************************************/ /*! \class OnePole \brief STK one-pole filter class. This protected Filter subclass implements a one-pole digital filter. A method is provided for setting the pole position along the real axis of the z-plane while maintaining a constant peak filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_ONEPOLE_H #define STK_ONEPOLE_H #include "Filter.h" namespace Nyq { class OnePole : protected Filter { public: //! Default constructor creates a first-order low-pass filter. OnePole(); //! Overloaded constructor which sets the pole position during instantiation. OnePole( StkFloat thePole ); //! Class destructor. ~OnePole(); //! Clears the internal state of the filter. void clear(void); //! Set the b[0] coefficient value. void setB0(StkFloat b0); //! Set the a[1] coefficient value. void setA1(StkFloat a1); //! Set the pole position in the z-plane. /*! This method sets the pole position along the real-axis of the z-plane and normalizes the coefficients for a maximum gain of one. A positive pole value produces a low-pass filter, while a negative pole value produces a high-pass filter. This method does not affect the filter \e gain value. */ void setPole(StkFloat thePole); //! Set the filter gain. /*! The gain is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. */ void setGain(StkFloat gain); //! Return the current filter gain. StkFloat getGain(void) const; //! Return the last computed output value. StkFloat lastOut(void) const; //! Input one sample to the filter and return one output. StkFloat tick(StkFloat sample); //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Mandolin.h0000644000175000000620000000375511466723256017077 0ustar stevestaff/***************************************************/ /*! \class Mandolin \brief STK mandolin instrument model class. This class inherits from PluckTwo and uses "commuted synthesis" techniques to model a mandolin instrument. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Commuted Synthesis, in particular, is covered by patents, granted, pending, and/or applied-for. All are assigned to the Board of Trustees, Stanford University. For information, contact the Office of Technology Licensing, Stanford University. Control Change Numbers: - Body Size = 2 - Pluck Position = 4 - String Sustain = 11 - String Detuning = 1 - Microphone Position = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_MANDOLIN_H #define STK_MANDOLIN_H #include "PluckTwo.h" #include "FileWvIn.h" namespace Nyq { class Mandolin : public PluckTwo { public: //! Class constructor, taking the lowest desired playing frequency. Mandolin(StkFloat lowestFrequency); //! Class destructor. ~Mandolin(); //! Pluck the strings with the given amplitude (0.0 - 1.0) using the current frequency. void pluck(StkFloat amplitude); //! Pluck the strings with the given amplitude (0.0 - 1.0) and position (0.0 - 1.0). void pluck(StkFloat amplitude,StkFloat position); //! Start a note with the given frequency and amplitude (0.0 - 1.0). void noteOn(StkFloat frequency, StkFloat amplitude); //! Set the body size (a value of 1.0 produces the "default" size). void setBodySize(StkFloat size); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); protected: StkFloat computeSample( void ); FileWvIn *soundfile_[12]; int mic_; long dampTime_; bool waveDone_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/OneZero.h0000644000175000000620000000436611466723256016716 0ustar stevestaff/***************************************************/ /*! \class OneZero \brief STK one-zero filter class. This protected Filter subclass implements a one-zero digital filter. A method is provided for setting the zero position along the real axis of the z-plane while maintaining a constant filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_ONEZERO_H #define STK_ONEZERO_H #include "Filter.h" namespace Nyq { class OneZero : protected Filter { public: //! Default constructor creates a first-order low-pass filter. OneZero(); //! Overloaded constructor which sets the zero position during instantiation. OneZero(StkFloat theZero); //! Class destructor. ~OneZero(); //! Clears the internal state of the filter. void clear(void); //! Set the b[0] coefficient value. void setB0(StkFloat b0); //! Set the b[1] coefficient value. void setB1(StkFloat b1); //! Set the zero position in the z-plane. /*! This method sets the zero position along the real-axis of the z-plane and normalizes the coefficients for a maximum gain of one. A positive zero value produces a high-pass filter, while a negative zero value produces a low-pass filter. This method does not affect the filter \e gain value. */ void setZero(StkFloat theZero); //! Set the filter gain. /*! The gain is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. */ void setGain(StkFloat gain); //! Return the current filter gain. StkFloat getGain(void) const; //! Return the last computed output value. StkFloat lastOut(void) const; //! Input one sample to the filter and return one output. StkFloat tick(StkFloat sample); //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Chorus.h0000644000175000000620000000201111466723256016561 0ustar stevestaff/***************************************************/ /*! \class Chorus \brief STK chorus effect class. This class implements a chorus effect. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_CHORUS_H #define STK_CHORUS_H #include "Effect.h" #include "DelayL.h" #include "SineWave.h" namespace Nyq { class Chorus : public Effect { public: //! Class constructor, taking the median desired delay length. /*! An StkError can be thrown if the rawwave path is incorrect. */ Chorus( StkFloat baseDelay = 6000 ); //! Class destructor. ~Chorus(); //! Reset and clear all internal state. void clear(); //! Set modulation depth. void setModDepth(StkFloat depth); //! Set modulation frequency. void setModFrequency(StkFloat frequency); protected: StkFloat computeSample( StkFloat input ); DelayL delayLine_[2]; SineWave mods_[2]; StkFloat baseLength_; StkFloat modDepth_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Delay.h0000644000175000000620000000667211466723256016375 0ustar stevestaff/***************************************************/ /*! \class Delay \brief STK non-interpolating delay line class. This protected Filter subclass implements a non-interpolating digital delay-line. A fixed maximum length of 4095 and a delay of zero is set using the default constructor. Alternatively, the delay and maximum length can be set during instantiation with an overloaded constructor. A non-interpolating delay line is typically used in fixed delay-length applications, such as for reverberation. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_DELAY_H #define STK_DELAY_H #include "Filter.h" namespace Nyq { class Delay : protected Filter { public: //! Default constructor creates a delay-line with maximum length of 4095 samples and zero delay. Delay(); //! Overloaded constructor which specifies the current and maximum delay-line lengths. /*! An StkError will be thrown if the delay parameter is less than zero, the maximum delay parameter is less than one, or the delay parameter is greater than the maxDelay value. */ Delay(unsigned long delay, unsigned long maxDelay); //! Class destructor. virtual ~Delay(); //! Clears the internal state of the delay line. void clear(); //! Set the maximum delay-line length. /*! This method should generally only be used during initial setup of the delay line. If it is used between calls to the tick() function, without a call to clear(), a signal discontinuity will likely occur. If the current maximum length is greater than the new length, no change will be made. */ void setMaximumDelay(unsigned long delay); //! Set the delay-line length. /*! The valid range for \e theDelay is from 0 to the maximum delay-line length. */ void setDelay(unsigned long delay); //! Return the current delay-line length. unsigned long getDelay(void) const; //! Calculate and return the signal energy in the delay-line. StkFloat energy(void) const; //! Return the value at \e tapDelay samples from the delay-line input. /*! The tap point is determined modulo the delay-line length and is relative to the last input value (i.e., a tapDelay of zero returns the last input value). */ StkFloat contentsAt(unsigned long tapDelay); //! Return the last computed output value. StkFloat lastOut(void) const; //! Return the value which will be output by the next call to tick(). /*! This method is valid only for delay settings greater than zero! */ virtual StkFloat nextOut(void); //! Input one sample to the filter and return one output. virtual StkFloat tick(StkFloat sample); //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); protected: // This function must be implemented in all subclasses. It is used // to get around a C++ problem with overloaded virtual functions. virtual StkFloat computeSample( StkFloat input ); unsigned long inPoint_; unsigned long outPoint_; StkFloat delay_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/PRCRev.h0000644000175000000620000000223311466723256016425 0ustar stevestaff/***************************************************/ /*! \class PRCRev \brief Perry's simple reverberator class. This class is based on some of the famous Stanford/CCRMA reverbs (NRev, KipRev), which were based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This class implements two series allpass units and two parallel comb filters. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_PRCREV_H #define STK_PRCREV_H #include "Effect.h" #include "Delay.h" namespace Nyq { class PRCRev : public Effect { public: //! Class constructor taking a T60 decay time argument (one second default value). PRCRev( StkFloat T60 = 1.0 ); //! Class destructor. ~PRCRev(); //! Reset and clear all internal state. void clear(); //! Set the reverberation T60 decay time. void setT60( StkFloat T60 ); protected: StkFloat computeSample( StkFloat input ); Delay allpassDelays_[2]; Delay combDelays_[2]; StkFloat allpassCoefficient_; StkFloat combCoefficient_[2]; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Clarinet.h0000644000175000000620000000426311466723256017072 0ustar stevestaff/***************************************************/ /*! \class Clarinet \brief STK clarinet physical model class. This class implements a simple clarinet physical model, as discussed by Smith (1986), McIntyre, Schumacher, Woodhouse (1983), and others. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Reed Stiffness = 2 - Noise Gain = 4 - Vibrato Frequency = 11 - Vibrato Gain = 1 - Breath Pressure = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_CLARINET_H #define STK_CLARINET_H #include "Instrmnt.h" #include "DelayL.h" #include "ReedTable.h" #include "OneZero.h" #include "Envelope.h" #include "Noise.h" #include "SineWave.h" namespace Nyq { class Clarinet : public Instrmnt { public: //! Class constructor, taking the lowest desired playing frequency. /*! An StkError will be thrown if the rawwave path is incorrectly set. */ Clarinet(StkFloat lowestFrequency); //! Class destructor. ~Clarinet(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. void setFrequency(StkFloat frequency); //! Apply breath pressure to instrument with given amplitude and rate of increase. void startBlowing(StkFloat amplitude, StkFloat rate); //! Decrease breath pressure with given rate of decrease. void stopBlowing(StkFloat rate); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); protected: StkFloat computeSample( void ); DelayL delayLine_; ReedTable reedTable_; OneZero filter_; Envelope envelope_; Noise noise_; SineWave vibrato_; long length_; StkFloat outputGain_; StkFloat noiseGain_; StkFloat vibratoGain_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/PitShift.h0000644000175000000620000000163311466723256017061 0ustar stevestaff/***************************************************/ /*! \class PitShift \brief STK simple pitch shifter effect class. This class implements a simple pitch shifter using delay lines. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_PITSHIFT_H #define STK_PITSHIFT_H #include "Effect.h" #include "DelayL.h" namespace Nyq { class PitShift : public Effect { public: //! Class constructor. PitShift(); //! Class destructor. ~PitShift(); //! Reset and clear all internal state. void clear(); //! Set the pitch shift factor (1.0 produces no shift). void setShift(StkFloat shift); protected: StkFloat computeSample( StkFloat input ); DelayL delayLine_[2]; StkFloat delay_[2]; StkFloat env_[2]; StkFloat rate_; unsigned long delayLength; unsigned long halfLength; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Envelope.h0000644000175000000620000000274411466723256017110 0ustar stevestaff/***************************************************/ /*! \class Envelope \brief STK envelope base class. This class implements a simple envelope generator which is capable of ramping to a target value by a specified \e rate. It also responds to simple \e keyOn and \e keyOff messages, ramping to 1.0 on keyOn and to 0.0 on keyOff. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_ENVELOPE_H #define STK_ENVELOPE_H #include "Generator.h" namespace Nyq { class Envelope : public Generator { public: //! Default constructor. Envelope(void); //! Copy constructor. Envelope( const Envelope& e ); //! Class destructor. virtual ~Envelope(void); //! Assignment operator. Envelope& operator= ( const Envelope& e ); //! Set target = 1. virtual void keyOn(void); //! Set target = 0. virtual void keyOff(void); //! Set the \e rate. void setRate(StkFloat rate); //! Set the \e rate based on a time duration. void setTime(StkFloat time); //! Set the target value. virtual void setTarget(StkFloat target); //! Set current and target values to \e aValue. virtual void setValue(StkFloat value); //! Return the current envelope \e state (0 = at target, 1 otherwise). virtual int getState(void) const; protected: virtual StkFloat computeSample( void ); StkFloat value_; StkFloat target_; StkFloat rate_; int state_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Bowed.h0000644000175000000620000000420611466723256016366 0ustar stevestaff/***************************************************/ /*! \class Bowed \brief STK bowed string instrument class. This class implements a bowed string model, a la Smith (1986), after McIntyre, Schumacher, Woodhouse (1983). This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Bow Pressure = 2 - Bow Position = 4 - Vibrato Frequency = 11 - Vibrato Gain = 1 - Volume = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_BOWED_H #define STK_BOWED_H #include "Instrmnt.h" #include "DelayL.h" #include "BowTable.h" #include "OnePole.h" #include "BiQuad.h" #include "SineWave.h" #include "ADSR.h" namespace Nyq { class Bowed : public Instrmnt { public: //! Class constructor, taking the lowest desired playing frequency. Bowed(StkFloat lowestFrequency); //! Class destructor. ~Bowed(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. void setFrequency(StkFloat frequency); //! Set vibrato gain. void setVibrato(StkFloat gain); //! Apply breath pressure to instrument with given amplitude and rate of increase. void startBowing(StkFloat amplitude, StkFloat rate); //! Decrease breath pressure with given rate of decrease. void stopBowing(StkFloat rate); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); protected: StkFloat computeSample( void ); DelayL neckDelay_; DelayL bridgeDelay_; BowTable bowTable_; OnePole stringFilter_; BiQuad bodyFilter_; SineWave vibrato_; ADSR adsr_; StkFloat maxVelocity_; StkFloat baseDelay_; StkFloat vibratoGain_; StkFloat betaRatio_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/BowTable.h0000644000175000000620000000215011466723256017021 0ustar stevestaff/***************************************************/ /*! \class BowTable \brief STK bowed string table class. This class implements a simple bowed string non-linear function, as described by Smith (1986). by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_BOWTABL_H #define STK_BOWTABL_H #include "Function.h" namespace Nyq { class BowTable : public Function { public: //! Default constructor. BowTable(); //! Class destructor. ~BowTable(); //! Set the table offset value. /*! The table offset is a bias which controls the symmetry of the friction. If you want the friction to vary with direction, use a non-zero value for the offset. The default value is zero. */ void setOffset(StkFloat offset); //! Set the table slope value. /*! The table slope controls the width of the friction pulse, which is related to bow force. */ void setSlope(StkFloat slope); protected: StkFloat computeSample( StkFloat input ); StkFloat offset_; StkFloat slope_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/FileWvIn.h0000644000175000000620000001107111466723256017007 0ustar stevestaff/***************************************************/ /*! \class FileWvIn \brief STK audio file input class. This class inherits from WvIn. It provides a "tick-level" interface to the FileRead class. It also provides variable-rate "playback" functionality. Audio file support is provided by the FileRead class. Linear interpolation is used for fractional "read rates". FileWvIn supports multi-channel data. It is important to distinguish the tick() methods, which return samples produced by averaging across sample frames, from the tickFrame() methods, which return references to multi-channel sample frames. FileWvIn will either load the entire content of an audio file into local memory or incrementally read file data from disk in chunks. This behavior is controlled by the optional constructor arguments \e chunkThreshold and \e chunkSize. File sizes greater than \e chunkThreshold (in sample frames) will be read incrementally in chunks of \e chunkSize each (also in sample frames). When the file end is reached, subsequent calls to the tick() functions return zero-valued data and isFinished() returns \e true. See the FileRead class for a description of the supported audio file formats. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_FILEWVIN_H #define STK_FILEWVIN_H #include "WvIn.h" #include "FileRead.h" namespace Nyq { class FileWvIn : public WvIn { public: //! Default constructor. FileWvIn( unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 ); //! Overloaded constructor for file input. /*! An StkError will be thrown if the file is not found, its format is unknown, or a read error occurs. */ FileWvIn( std::string fileName, bool raw = false, bool doNormalize = true, unsigned long chunkThreshold = 1000000, unsigned long chunkSize = 1024 ); //! Class destructor. virtual ~FileWvIn(); //! Open the specified file and load its data. /*! Data from a previously opened file will be overwritten by this function. An StkError will be thrown if the file is not found, its format is unknown, or a read error occurs. If the file data is to be loaded incrementally from disk and normalization is specified, a scaling will be applied with respect to fixed-point limits. If the data format is floating-point, no scaling is performed. */ void openFile( std::string fileName, bool raw = false, bool doNormalize = true ); //! Close a file if one is open. void closeFile( void ); //! Clear outputs and reset time (file) pointer to zero. void reset( void ); //! Normalize data to a maximum of +-1.0. /*! This function has no effect when data is incrementally loaded from disk. */ void normalize( void ); //! Normalize data to a maximum of \e +-peak. /*! This function has no effect when data is incrementally loaded from disk. */ void normalize( StkFloat peak ); //! Return the file size in sample frames. unsigned long getSize( void ) const { return data_.frames(); }; //! Return the input file sample rate in Hz (not the data read rate). /*! WAV, SND, and AIF formatted files specify a sample rate in their headers. STK RAW files have a sample rate of 22050 Hz by definition. MAT-files are assumed to have a rate of 44100 Hz. */ StkFloat getFileRate( void ) const { return data_.dataRate(); }; //! Query whether reading is complete. bool isFinished( void ) const { return finished_; }; //! Set the data read rate in samples. The rate can be negative. /*! If the rate value is negative, the data is read in reverse order. */ void setRate( StkFloat rate ); //! Increment the read pointer by \e time samples. /*! Note that this function will not modify the interpolation flag status. */ virtual void addTime( StkFloat time ); //! Turn linear interpolation on/off. /*! Interpolation is automatically off when the read rate is an integer value. If interpolation is turned off for a fractional rate, the time index is truncated to an integer value. */ void setInterpolate( bool doInterpolate ) { interpolate_ = doInterpolate; }; StkFloat lastOut( void ) const; protected: virtual void computeFrame( void ); FileRead file_; bool finished_; bool interpolate_; bool normalizing_; bool chunking_; StkFloat time_; StkFloat rate_; unsigned long chunkThreshold_; unsigned long chunkSize_; long chunkPointer_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Effect.h0000644000175000000620000000346011466723256016523 0ustar stevestaff/***************************************************/ /*! \class Effect \brief STK abstract effects parent class. This class provides common functionality for STK effects subclasses. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #include "Stk.h" #ifndef STK_EFFECT_H #define STK_EFFECT_H namespace Nyq { class Effect : public Stk { public: //! Class constructor. Effect(); //! Class destructor. virtual ~Effect(); //! Reset and clear all internal state. virtual void clear() = 0; //! Set the mixture of input and "effected" levels in the output (0.0 = input only, 1.0 = reverb only). void setEffectMix(StkFloat mix); //! Return the last output value. StkFloat lastOut() const; //! Return the last left output value. StkFloat lastOutLeft() const; //! Return the last right output value. StkFloat lastOutRight() const; //! Take one sample input and compute one sample of output. StkFloat tick( StkFloat input ); //! Take a channel of the StkFrames object as inputs to the effect and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); protected: // This abstract function must be implemented in all subclasses. // It is used to get around a C++ problem with overloaded virtual // functions. virtual StkFloat computeSample( StkFloat input ) = 0; // Returns true if argument value is prime. bool isPrime( int number ); StkFloat lastOutput_[2]; StkFloat effectMix_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/JetTable.h0000644000175000000620000000136711466723256017025 0ustar stevestaff/***************************************************/ /*! \class JetTable \brief STK jet table class. This class implements a flue jet non-linear function, computed by a polynomial calculation. Contrary to the name, this is not a "table". Consult Fletcher and Rossing, Karjalainen, Cook, and others for more information. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_JETTABL_H #define STK_JETTABL_H #include "Function.h" namespace Nyq { class JetTable : public Function { public: //! Default constructor. JetTable(); //! Class destructor. ~JetTable(); protected: StkFloat computeSample( StkFloat input ); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/BandedWG.h0000644000175000000620000000565211466723256016747 0ustar stevestaff/***************************************************/ /*! \class BandedWG \brief Banded waveguide modeling class. This class uses banded waveguide techniques to model a variety of sounds, including bowed bars, glasses, and bowls. For more information, see Essl, G. and Cook, P. "Banded Waveguides: Towards Physical Modelling of Bar Percussion Instruments", Proceedings of the 1999 International Computer Music Conference. Control Change Numbers: - Bow Pressure = 2 - Bow Motion = 4 - Strike Position = 8 (not implemented) - Vibrato Frequency = 11 - Gain = 1 - Bow Velocity = 128 - Set Striking = 64 - Instrument Presets = 16 - Uniform Bar = 0 - Tuned Bar = 1 - Glass Harmonica = 2 - Tibetan Bowl = 3 by Georg Essl, 1999 - 2004. Modified for Stk 4.0 by Gary Scavone. */ /***************************************************/ #ifndef STK_BANDEDWG_H #define STK_BANDEDWG_H namespace Nyq { const int MAX_BANDED_MODES = 20; } // namespace Nyq #include "Instrmnt.h" #include "DelayL.h" #include "BowTable.h" #include "ADSR.h" #include "BiQuad.h" namespace Nyq { class BandedWG : public Instrmnt { public: //! Class constructor. BandedWG(); //! Class destructor. ~BandedWG(); //! Reset and clear all internal state. void clear(); //! Set strike position (0.0 - 1.0). void setStrikePosition(StkFloat position); //! Select a preset. void setPreset(int preset); //! Set instrument parameters for a particular frequency. void setFrequency(StkFloat frequency); //! Apply bow velocity/pressure to instrument with given amplitude and rate of increase. void startBowing(StkFloat amplitude, StkFloat rate); //! Decrease bow velocity/breath pressure with given rate of decrease. void stopBowing(StkFloat rate); //! Pluck the instrument with given amplitude. void pluck(StkFloat amp); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); protected: StkFloat computeSample( void ); bool doPluck_; bool trackVelocity_; int nModes_; int presetModes_; BowTable bowTable_; ADSR adsr_; BiQuad bandpass_[MAX_BANDED_MODES]; DelayL delay_[MAX_BANDED_MODES]; StkFloat maxVelocity_; StkFloat modes_[MAX_BANDED_MODES]; StkFloat frequency_; StkFloat baseGain_; StkFloat gains_[MAX_BANDED_MODES]; StkFloat basegains_[MAX_BANDED_MODES]; StkFloat excitation_[MAX_BANDED_MODES]; StkFloat integrationConstant_; StkFloat velocityInput_; StkFloat bowVelocity_; StkFloat bowTarget_; StkFloat bowPosition_; StkFloat strikeAmp_; int strikePosition_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/ModalBar.h0000644000175000000620000000270311466723256017007 0ustar stevestaff/***************************************************/ /*! \class ModalBar \brief STK resonant bar instrument class. This class implements a number of different struck bar instruments. It inherits from the Modal class. Control Change Numbers: - Stick Hardness = 2 - Stick Position = 4 - Vibrato Gain = 1 - Vibrato Frequency = 11 - Direct Stick Mix = 8 - Volume = 128 - Modal Presets = 16 - Marimba = 0 - Vibraphone = 1 - Agogo = 2 - Wood1 = 3 - Reso = 4 - Wood2 = 5 - Beats = 6 - Two Fixed = 7 - Clump = 8 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_MODALBAR_H #define STK_MODALBAR_H #include "Modal.h" namespace Nyq { class ModalBar : public Modal { public: //! Class constructor. ModalBar(); //! Class destructor. ~ModalBar(); //! Set stick hardness (0.0 - 1.0). void setStickHardness(StkFloat hardness); //! Set stick position (0.0 - 1.0). void setStrikePosition(StkFloat position); //! Select a bar preset (currently modulo 9). void setPreset(int preset); //! Set the modulation (vibrato) depth. void setModulationDepth(StkFloat mDepth); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/DelayL.h0000644000175000000620000000411611466723256016500 0ustar stevestaff/***************************************************/ /*! \class DelayL \brief STK linear interpolating delay line class. This Delay subclass implements a fractional- length digital delay-line using first-order linear interpolation. A fixed maximum length of 4095 and a delay of zero is set using the default constructor. Alternatively, the delay and maximum length can be set during instantiation with an overloaded constructor. Linear interpolation is an efficient technique for achieving fractional delay lengths, though it does introduce high-frequency signal attenuation to varying degrees depending on the fractional delay setting. The use of higher order Lagrange interpolators can typically improve (minimize) this attenuation characteristic. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_DELAYL_H #define STK_DELAYL_H #include "Delay.h" namespace Nyq { class DelayL : public Delay { public: //! Default constructor creates a delay-line with maximum length of 4095 samples and zero delay. DelayL(); //! Overloaded constructor which specifies the current and maximum delay-line lengths. /*! An StkError will be thrown if the delay parameter is less than zero, the maximum delay parameter is less than one, or the delay parameter is greater than the maxDelay value. */ DelayL(StkFloat delay, unsigned long maxDelay); //! Class destructor. ~DelayL(); //! Set the delay-line length. /*! The valid range for \e theDelay is from 0 to the maximum delay-line length. */ void setDelay(StkFloat delay); //! Return the current delay-line length. StkFloat getDelay(void) const; //! Return the value which will be output by the next call to tick(). /*! This method is valid only for delay settings greater than zero! */ StkFloat nextOut(void); protected: StkFloat computeSample( StkFloat input ); StkFloat alpha_; StkFloat omAlpha_; StkFloat nextOutput_; bool doNextOut_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/PluckTwo.h0000644000175000000620000000433011466723256017074 0ustar stevestaff/***************************************************/ /*! \class PluckTwo \brief STK enhanced plucked string model class. This class implements an enhanced two-string, plucked physical model, a la Jaffe-Smith, Smith, and others. PluckTwo is an abstract class, with no excitation specified. Therefore, it can't be directly instantiated. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_PLUCKTWO_H #define STK_PLUCKTWO_H #include "Instrmnt.h" #include "DelayL.h" #include "DelayA.h" #include "OneZero.h" namespace Nyq { class PluckTwo : public Instrmnt { public: //! Class constructor, taking the lowest desired playing frequency. PluckTwo(StkFloat lowestFrequency); //! Class destructor. virtual ~PluckTwo(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. virtual void setFrequency(StkFloat frequency); //! Detune the two strings by the given factor. A value of 1.0 produces unison strings. void setDetune(StkFloat detune); //! Efficient combined setting of frequency and detuning. void setFreqAndDetune(StkFloat frequency, StkFloat detune); //! Set the pluck or "excitation" position along the string (0.0 - 1.0). void setPluckPosition(StkFloat position); //! Set the base loop gain. /*! The actual loop gain is set according to the frequency. Because of high-frequency loop filter roll-off, higher frequency settings have greater loop gains. */ void setBaseLoopGain(StkFloat aGain); //! Stop a note with the given amplitude (speed of decay). virtual void noteOff(StkFloat amplitude); protected: virtual StkFloat computeSample( void ) = 0; DelayA delayLine_; DelayA delayLine2_; DelayL combDelay_; OneZero filter_; OneZero filter2_; unsigned long length_; StkFloat loopGain_; StkFloat baseLoopGain_; StkFloat lastFrequency_; StkFloat lastLength_; StkFloat detuning_; StkFloat pluckAmplitude_; StkFloat pluckPosition_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/FileRead.h0000644000175000000620000000777211466723256017014 0ustar stevestaff/***************************************************/ /*! \class FileRead \brief STK audio file input class. This class provides input support for various audio file formats. Multi-channel (>2) soundfiles are supported. The file data is returned via an external StkFrames object passed to the read() function. This class does not store its own copy of the file data, rather the data is read directly from disk. FileRead currently supports uncompressed WAV, AIFF/AIFC, SND (AU), MAT-file (Matlab), and STK RAW file formats. Signed integer (8-, 16-, and 32-bit) and floating-point (32- and 64-bit) data types are supported. Compressed data types are not supported. STK RAW files have no header and are assumed to contain a monophonic stream of 16-bit signed integers in big-endian byte order at a sample rate of 22050 Hz. MAT-file data should be saved in an array with each data channel filling a matrix row. The sample rate for MAT-files is assumed to be 44100 Hz. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_FILEREAD_H #define STK_FILEREAD_H #include "Stk.h" namespace Nyq { class FileRead : public Stk { public: //! Default constructor. FileRead(); //! Overloaded constructor that opens a file during instantiation. /*! An StkError will be thrown if the file is not found or its format is unknown or unsupported. */ FileRead( std::string fileName, bool typeRaw = false ); //! Class destructor. ~FileRead(); //! Open the specified file and determine its formatting. /*! An StkError will be thrown if the file is not found or its format is unknown or unsupported. An optional parameter is provided to specify whether the input file is of type STK RAW (default = false). */ void open( std::string fileName, bool typeRaw = false ); //! If a file is open, close it. void close( void ); //! Returns \e true if a file is currently open. bool isOpen( void ); //! Return the file size in sample frames. unsigned long fileSize( void ) const { return fileSize_; }; //! Return the number of audio channels in the file. unsigned int channels( void ) const { return channels_; }; //! Return the file sample rate in Hz. /*! WAV, SND, and AIF formatted files specify a sample rate in their headers. By definition, STK RAW files have a sample rate of 22050 Hz. MAT-files are assumed to have a rate of 44100 Hz. */ StkFloat fileRate( void ) const { return fileRate_; }; //! Read sample frames from the file into an StkFrames object. /*! The number of sample frames to read will be determined from the number of frames of the StkFrames argument. If this size is larger than the available data in the file (given the file size and starting frame index), the extra frames will be unaffected (the StkFrames object will not be resized). Optional parameters are provided to specify the starting sample frame within the file (default = 0) and whether to normalize the data with respect to fixed-point limits (default = true). An StkError will be thrown if a file error occurs or if the number of channels in the StkFrames argument is not equal to that in the file. */ void read( StkFrames& buffer, unsigned long startFrame = 0, bool doNormalize = true ); protected: // Get STK RAW file information. bool getRawInfo( const char *fileName ); // Get WAV file header information. bool getWavInfo( const char *fileName ); // Get SND (AU) file header information. bool getSndInfo( const char *fileName ); // Get AIFF file header information. bool getAifInfo( const char *fileName ); // Get MAT-file header information. bool getMatInfo( const char *fileName ); FILE *fd_; bool byteswap_; bool wavFile_; unsigned long fileSize_; unsigned long dataOffset_; unsigned int channels_; StkFormat dataType_; StkFloat fileRate_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Sitar.h0000644000175000000620000000321611466723256016410 0ustar stevestaff/***************************************************/ /*! \class Sitar \brief STK sitar string model class. This class implements a sitar plucked string physical model based on the Karplus-Strong algorithm. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. There exist at least two patents, assigned to Stanford, bearing the names of Karplus and/or Strong. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_SITAR_H #define STK_SITAR_H #include "Instrmnt.h" #include "DelayA.h" #include "OneZero.h" #include "Noise.h" #include "ADSR.h" namespace Nyq { class Sitar : public Instrmnt { public: //! Class constructor, taking the lowest desired playing frequency. Sitar( StkFloat lowestFrequency = 20 ); //! Class destructor. ~Sitar(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. void setFrequency(StkFloat frequency); //! Pluck the string with the given amplitude using the current frequency. void pluck(StkFloat amplitude); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); protected: StkFloat computeSample( void ); DelayA delayLine_; OneZero loopFilter_; Noise noise_; ADSR envelope_; StkFloat loopGain_; StkFloat amGain_; StkFloat delay_; StkFloat targetDelay_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Saxofony.h0000644000175000000620000000572611466723256017144 0ustar stevestaff/***************************************************/ /*! \class Saxofony \brief STK faux conical bore reed instrument class. This class implements a "hybrid" digital waveguide instrument that can generate a variety of wind-like sounds. It has also been referred to as the "blowed string" model. The waveguide section is essentially that of a string, with one rigid and one lossy termination. The non-linear function is a reed table. The string can be "blown" at any point between the terminations, though just as with strings, it is impossible to excite the system at either end. If the excitation is placed at the string mid-point, the sound is that of a clarinet. At points closer to the "bridge", the sound is closer to that of a saxophone. See Scavone (2002) for more details. This is a digital waveguide model, making its use possibly subject to patents held by Stanford University, Yamaha, and others. Control Change Numbers: - Reed Stiffness = 2 - Reed Aperture = 26 - Noise Gain = 4 - Blow Position = 11 - Vibrato Frequency = 29 - Vibrato Gain = 1 - Breath Pressure = 128 by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_SAXOFONY_H #define STK_SAXOFONY_H #include "Instrmnt.h" #include "DelayL.h" #include "ReedTable.h" #include "OneZero.h" #include "Envelope.h" #include "Noise.h" #include "SineWave.h" namespace Nyq { class Saxofony : public Instrmnt { public: //! Class constructor, taking the lowest desired playing frequency. /*! An StkError will be thrown if the rawwave path is incorrectly set. */ Saxofony(StkFloat lowestFrequency); //! Class destructor. ~Saxofony(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. void setFrequency(StkFloat frequency); //! Set the "blowing" position between the air column terminations (0.0 - 1.0). void setBlowPosition(StkFloat aPosition); //! Apply breath pressure to instrument with given amplitude and rate of increase. void startBlowing(StkFloat amplitude, StkFloat rate); //! Decrease breath pressure with given rate of decrease. void stopBlowing(StkFloat rate); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). void controlChange(int number, StkFloat value); protected: StkFloat computeSample( void ); DelayL delays_[2]; ReedTable reedTable_; OneZero filter_; Envelope envelope_; Noise noise_; SineWave vibrato_; unsigned long length_; StkFloat outputGain_; StkFloat noiseGain_; StkFloat vibratoGain_; StkFloat position_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Filter.h0000644000175000000620000001017511466723256016555 0ustar stevestaff/***************************************************/ /*! \class Filter \brief STK filter class. This class implements a generic structure that can be used to create a wide range of filters. It can function independently or be subclassed to provide more specific controls based on a particular filter type. In particular, this class implements the standard difference equation: a[0]*y[n] = b[0]*x[n] + ... + b[nb]*x[n-nb] - a[1]*y[n-1] - ... - a[na]*y[n-na] If a[0] is not equal to 1, the filter coeffcients are normalized by a[0]. The \e gain parameter is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. This structure results in one extra multiply per computed sample, but allows easy control of the overall filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_FILTER_H #define STK_FILTER_H #include "Stk.h" #include namespace Nyq { class Filter : public Stk { public: //! Default constructor creates a zero-order pass-through "filter". Filter(void); //! Overloaded constructor which takes filter coefficients. /*! An StkError can be thrown if either of the coefficient vector sizes is zero, or if the a[0] coefficient is equal to zero. */ Filter( std::vector &bCoefficients, std::vector &aCoefficients ); //! Class destructor. virtual ~Filter(void); //! Sets all internal states of the filter to zero. void clear(void); //! Set filter coefficients. /*! An StkError can be thrown if either of the coefficient vector sizes is zero, or if the a[0] coefficient is equal to zero. If a[0] is not equal to 1, the filter coeffcients are normalized by a[0]. The internal state of the filter is not cleared unless the \e clearState flag is \c true. */ void setCoefficients( std::vector &bCoefficients, std::vector &aCoefficients, bool clearState = false ); //! Set numerator coefficients. /*! An StkError can be thrown if coefficient vector is empty. Any previously set denominator coefficients are left unaffected. Note that the default constructor sets the single denominator coefficient a[0] to 1.0. The internal state of the filter is not cleared unless the \e clearState flag is \c true. */ void setNumerator( std::vector &bCoefficients, bool clearState = false ); //! Set denominator coefficients. /*! An StkError can be thrown if the coefficient vector is empty or if the a[0] coefficient is equal to zero. Previously set numerator coefficients are unaffected unless a[0] is not equal to 1, in which case all coeffcients are normalized by a[0]. Note that the default constructor sets the single numerator coefficient b[0] to 1.0. The internal state of the filter is not cleared unless the \e clearState flag is \c true. */ void setDenominator( std::vector &aCoefficients, bool clearState = false ); //! Set the filter gain. /*! The gain is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. */ virtual void setGain(StkFloat gain); //! Return the current filter gain. virtual StkFloat getGain(void) const; //! Return the last computed output value. virtual StkFloat lastOut(void) const; //! Input one sample to the filter and return one output. virtual StkFloat tick( StkFloat input ); //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); protected: StkFloat gain_; std::vector b_; std::vector a_; std::vector outputs_; std::vector inputs_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Modal.h0000644000175000000620000000454311466723256016366 0ustar stevestaff/***************************************************/ /*! \class Modal \brief STK resonance model instrument. This class contains an excitation wavetable, an envelope, an oscillator, and N resonances (non-sweeping BiQuad filters), where N is set during instantiation. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_MODAL_H #define STK_MODAL_H #include "Instrmnt.h" #include "Envelope.h" #include "WaveLoop.h" #include "SineWave.h" #include "BiQuad.h" #include "OnePole.h" namespace Nyq { class Modal : public Instrmnt { public: //! Class constructor, taking the desired number of modes to create. /*! An StkError will be thrown if the rawwave path is incorrectly set. */ Modal( unsigned int modes = 4 ); //! Class destructor. virtual ~Modal(); //! Reset and clear all internal state. void clear(); //! Set instrument parameters for a particular frequency. virtual void setFrequency(StkFloat frequency); //! Set the ratio and radius for a specified mode filter. void setRatioAndRadius(unsigned int modeIndex, StkFloat ratio, StkFloat radius); //! Set the master gain. void setMasterGain(StkFloat aGain); //! Set the direct gain. void setDirectGain(StkFloat aGain); //! Set the gain for a specified mode filter. void setModeGain(unsigned int modeIndex, StkFloat gain); //! Initiate a strike with the given amplitude (0.0 - 1.0). virtual void strike(StkFloat amplitude); //! Damp modes with a given decay factor (0.0 - 1.0). void damp(StkFloat amplitude); //! Start a note with the given frequency and amplitude. void noteOn(StkFloat frequency, StkFloat amplitude); //! Stop a note with the given amplitude (speed of decay). void noteOff(StkFloat amplitude); //! Perform the control change specified by \e number and \e value (0.0 - 128.0). virtual void controlChange(int number, StkFloat value) = 0; protected: StkFloat computeSample( void ); Envelope envelope_; FileWvIn *wave_; BiQuad **filters_; OnePole onepole_; SineWave vibrato_; unsigned int nModes_; std::vector ratios_; std::vector radii_; StkFloat vibratoGain_; StkFloat masterGain_; StkFloat directGain_; StkFloat stickHardness_; StkFloat strikePosition_; StkFloat baseFrequency_; }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/Noise.h0000644000175000000620000000222611466723256016403 0ustar stevestaff/***************************************************/ /*! \class Noise \brief STK noise generator. Generic random number generation using the C rand() function. The quality of the rand() function varies from one OS to another. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_NOISE_H #define STK_NOISE_H #include "Generator.h" namespace Nyq { class Noise : public Generator { public: //! Default constructor which seeds the random number generator with the system time. Noise(); //! Constructor which seeds the random number generator with a given seed. /*! If the seed value is zero, the random number generator is seeded with the system time. */ Noise( unsigned int seed ); //! Class destructor. virtual ~Noise(); //! Seed the random number generator with a specific seed value. /*! If no seed is provided or the seed value is zero, the random number generator is seeded with the current system time. */ void setSeed( unsigned int seed = 0 ); protected: virtual StkFloat computeSample( void ); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/BiQuad.h0000644000175000000620000000705011466723256016473 0ustar stevestaff/***************************************************/ /*! \class BiQuad \brief STK biquad (two-pole, two-zero) filter class. This protected Filter subclass implements a two-pole, two-zero digital filter. A method is provided for creating a resonance in the frequency response while maintaining a constant filter gain. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_BIQUAD_H #define STK_BIQUAD_H #include "Filter.h" namespace Nyq { class BiQuad : protected Filter { public: //! Default constructor creates a second-order pass-through filter. BiQuad(); //! Class destructor. virtual ~BiQuad(); //! Clears all internal states of the filter. void clear(void); //! Set the b[0] coefficient value. void setB0(StkFloat b0); //! Set the b[1] coefficient value. void setB1(StkFloat b1); //! Set the b[2] coefficient value. void setB2(StkFloat b2); //! Set the a[1] coefficient value. void setA1(StkFloat a1); //! Set the a[2] coefficient value. void setA2(StkFloat a2); //! Sets the filter coefficients for a resonance at \e frequency (in Hz). /*! This method determines the filter coefficients corresponding to two complex-conjugate poles with the given \e frequency (in Hz) and \e radius from the z-plane origin. If \e normalize is true, the filter zeros are placed at z = 1, z = -1, and the coefficients are then normalized to produce a constant unity peak gain (independent of the filter \e gain parameter). The resulting filter frequency response has a resonance at the given \e frequency. The closer the poles are to the unit-circle (\e radius close to one), the narrower the resulting resonance width. */ void setResonance(StkFloat frequency, StkFloat radius, bool normalize = false); //! Set the filter coefficients for a notch at \e frequency (in Hz). /*! This method determines the filter coefficients corresponding to two complex-conjugate zeros with the given \e frequency (in Hz) and \e radius from the z-plane origin. No filter normalization is attempted. */ void setNotch(StkFloat frequency, StkFloat radius); //! Sets the filter zeroes for equal resonance gain. /*! When using the filter as a resonator, zeroes places at z = 1, z = -1 will result in a constant gain at resonance of 1 / (1 - R), where R is the pole radius setting. */ void setEqualGainZeroes(); //! Set the filter gain. /*! The gain is applied at the filter input and does not affect the coefficient values. The default gain value is 1.0. */ void setGain(StkFloat gain); //! Return the current filter gain. StkFloat getGain(void) const; //! Return the last computed output value. StkFloat lastOut(void) const; //! Input one sample to the filter and return one output. virtual StkFloat tick(StkFloat sample); //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. /*! The \c channel argument should be zero or greater (the first channel is specified by 0). An StkError will be thrown if the \c channel argument is equal to or greater than the number of channels in the StkFrames object. */ virtual StkFrames& tick( StkFrames& frames, unsigned int channel = 0 ); protected: // This function must be implemented in all subclasses. It is used // to get around a C++ problem with overloaded virtual functions. virtual StkFloat computeSample( StkFloat input ); }; } // namespace Nyq #endif nyquist-3.05/nyqstk/include/ReedTabl.h0000644000175000000620000000327710144436365017011 0ustar stevestaff/***************************************************/ /*! \class ReedTabl \brief STK reed table class. This class implements a simple one breakpoint, non-linear reed function, as described by Smith (1986). This function is based on a memoryless non-linear spring model of the reed (the reed mass is ignored) which saturates when the reed collides with the mouthpiece facing. See McIntyre, Schumacher, & Woodhouse (1983), Smith (1986), Hirschman, Cook, Scavone, and others for more information. by Perry R. Cook and Gary P. Scavone, 1995 - 2002. */ /***************************************************/ #if !defined(__REEDTABL_H) #define __REEDTABL_H #include "Stk.h" class ReedTabl : public Stk { public: //! Default constructor. ReedTabl(); //! Class destructor. ~ReedTabl(); //! Set the table offset value. /*! The table offset roughly corresponds to the size of the initial reed tip opening (a greater offset represents a smaller opening). */ void setOffset(MY_FLOAT aValue); //! Set the table slope value. /*! The table slope roughly corresponds to the reed stiffness (a greater slope represents a harder reed). */ void setSlope(MY_FLOAT aValue); //! Return the last output value. MY_FLOAT lastOut() const; //! Return the function value for \e input. /*! The function input represents the differential pressure across the reeds. */ MY_FLOAT tick(MY_FLOAT input); //! Take \e vectorSize inputs and return the corresponding function values in \e vector. MY_FLOAT *tick(MY_FLOAT *vector, unsigned int vectorSize); protected: MY_FLOAT offSet; MY_FLOAT slope; MY_FLOAT lastOutput; }; #endif nyquist-3.05/nyqstk/include/Stk.h0000644000175000000620000003036211466723256016071 0ustar stevestaff/***************************************************/ /*! \class Stk \brief STK base class Nearly all STK classes inherit from this class. The global sample rate and rawwave path variables can be queried and modified via Stk. In addition, this class provides error handling and byte-swapping functions. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ #ifndef STK_STK_H #define STK_STK_H #include #include #include namespace Nyq { // Most data in STK is passed and calculated with the // following user-definable floating-point type. You // can change this to "float" if you prefer or perhaps // a "long double" in the future. typedef double StkFloat; // The "MY_FLOAT" type was deprecated in STK // versions higher than 4.1.3 and replaced with the variable // "StkFloat". #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) typedef StkFloat MY_FLOAT; #pragma deprecated(MY_FLOAT) #elif defined(__GXX__) typedef StkFloat MY_FLOAT __attribute__ ((deprecated)); #else typedef StkFloat MY_FLOAT; // temporary #endif //! STK error handling class. /*! This is a fairly abstract exception handling class. There could be sub-classes to take care of more specific error conditions ... or not. */ class StkError { public: enum Type { STATUS, WARNING, DEBUG_WARNING, MEMORY_ALLOCATION, MEMORY_ACCESS, FUNCTION_ARGUMENT, FILE_NOT_FOUND, FILE_UNKNOWN_FORMAT, FILE_ERROR, PROCESS_THREAD, PROCESS_SOCKET, PROCESS_SOCKET_IPADDR, AUDIO_SYSTEM, MIDI_SYSTEM, UNSPECIFIED }; protected: std::string message_; Type type_; public: //! The constructor. StkError(const std::string& message, Type type = StkError::UNSPECIFIED) : message_(message), type_(type) {} //! The destructor. virtual ~StkError(void) {}; //! Prints thrown error message to stderr. virtual void printMessage(void) { std::cerr << '\n' << message_ << "\n\n"; } //! Returns the thrown error message type. virtual const Type& getType(void) { return type_; } //! Returns the thrown error message string. virtual const std::string& getMessage(void) { return message_; } //! Returns the thrown error message as a C string. virtual const char *getMessageCString(void) { return message_.c_str(); } }; class Stk { public: typedef unsigned long StkFormat; static const StkFormat STK_SINT8; /*!< -128 to +127 */ static const StkFormat STK_SINT16; /*!< -32768 to +32767 */ static const StkFormat STK_SINT24; /*!< Upper 3 bytes of 32-bit signed integer. */ static const StkFormat STK_SINT32; /*!< -2147483648 to +2147483647. */ static const StkFormat STK_FLOAT32; /*!< Normalized between plus/minus 1.0. */ static const StkFormat STK_FLOAT64; /*!< Normalized between plus/minus 1.0. */ //! Static method which returns the current STK sample rate. static StkFloat sampleRate(void) { return srate_; } //! Static method which sets the STK sample rate. /*! The sample rate set using this method is queried by all STK classes which depend on its value. It is initialized to the default SRATE set in Stk.h. Many STK classes use the sample rate during instantiation. Therefore, if you wish to use a rate which is different from the default rate, it is imperative that it be set \e BEFORE STK objects are instantiated. */ static void setSampleRate(StkFloat rate) { if (rate > 0.0) srate_ = rate; } //! Static method which returns the current rawwave path. static std::string rawwavePath(void) { return rawwavepath_; } //! Static method which sets the STK rawwave path. static void setRawwavePath(std::string path); //! Static method which byte-swaps a 16-bit data type. static void swap16(unsigned char *ptr); //! Static method which byte-swaps a 32-bit data type. static void swap32(unsigned char *ptr); //! Static method which byte-swaps a 64-bit data type. static void swap64(unsigned char *ptr); //! Static cross-platform method to sleep for a number of milliseconds. static void sleep(unsigned long milliseconds); //! Static function for error reporting and handling using c-strings. static void handleError( const char *message, StkError::Type type ); //! Static function for error reporting and handling using c++ strings. static void handleError( std::string message, StkError::Type type ); //! Toggle display of WARNING and STATUS messages. static void showWarnings( bool status ) { showWarnings_ = status; } //! Toggle display of error messages before throwing exceptions. static void printErrors( bool status ) { printErrors_ = status; } private: static StkFloat srate_; static std::string rawwavepath_; static bool showWarnings_; static bool printErrors_; protected: std::ostringstream errorString_; //! Default constructor. Stk(void); //! Class destructor. virtual ~Stk(void); //! Internal function for error reporting which assumes message in \c errorString_ variable. void handleError( StkError::Type type ); }; /***************************************************/ /*! \class StkFrames \brief An STK class to handle vectorized audio data. This class can hold single- or multi-channel audio data in either interleaved or non-interleaved formats. The data type is always StkFloat. In an effort to maintain efficiency, no out-of-bounds checks are performed in this class. Possible future improvements in this class could include functions to inter- or de-interleave the data and to convert to and return other data types. by Perry R. Cook and Gary P. Scavone, 1995 - 2005. */ /***************************************************/ class StkFrames { public: //! The default constructor initializes the frame data structure to size zero. StkFrames( unsigned int nFrames = 0, unsigned int nChannels = 0, bool interleaved = true ); //! Overloaded constructor that initializes the frame data to the specified size with \c value. StkFrames( const StkFloat& value, unsigned int nFrames, unsigned int nChannels, bool interleaved = true ); //! The destructor. ~StkFrames(); //! Subscript operator which returns a reference to element \c n of self. /*! The result can be used as an lvalue . This reference is valid until the resize function is called or the array is destroyed. The index \c n must be between 0 and size less one. No range checking is performed unless _STK_DEBUG_ is defined. */ StkFloat& operator[] ( size_t n ); //! Subscript operator that returns the value at element \c n of self. /*! The index \c n must be between 0 and size less one. No range checking is performed unless _STK_DEBUG_ is defined. */ StkFloat operator[] ( size_t n ) const; //! Channel / frame subscript operator that returns a reference. /*! The result can be used as an lvalue. This reference is valid until the resize function is called or the array is destroyed. The \c frame index must be between 0 and frames() - 1. The \c channel index must be between 0 and channels() - 1. No range checking is performed unless _STK_DEBUG_ is defined. */ StkFloat& operator() ( size_t frame, unsigned int channel ); //! Channel / frame subscript operator that returns a value. /*! The \c frame index must be between 0 and frames() - 1. The \c channel index must be between 0 and channels() - 1. No range checking is performed unless _STK_DEBUG_ is defined. */ StkFloat operator() ( size_t frame, unsigned int channel ) const; //! Return an interpolated value at the fractional frame index and channel. /*! This function performs linear interpolation. The \c frame index must be between 0.0 and frames() - 1. The \c channel index must be between 0 and channels() - 1. No range checking is performed unless _STK_DEBUG_ is defined. */ StkFloat interpolate( StkFloat frame, unsigned int channel = 0 ) const; //! Returns the total number of audio samples represented by the object. size_t size() const { return size_; }; //! Returns \e true if the object size is zero and \e false otherwise. bool empty() const; //! Resize self to represent the specified number of channels and frames. /*! Changes the size of self based on the number of frames and channels. No element assignment is performed. No memory deallocation occurs if the new size is smaller than the previous size. Further, no new memory is allocated when the new size is smaller or equal to a previously allocated size. */ void resize( size_t nFrames, unsigned int nChannels = 1 ); //! Resize self to represent the specified number of channels and frames and perform element initialization. /*! Changes the size of self based on the number of frames and channels, and assigns \c value to every element. No memory deallocation occurs if the new size is smaller than the previous size. Further, no new memory is allocated when the new size is smaller or equal to a previously allocated size. */ void resize( size_t nFrames, unsigned int nChannels, StkFloat value ); //! Return the number of channels represented by the data. unsigned int channels( void ) const { return nChannels_; }; //! Return the number of sample frames represented by the data. unsigned int frames( void ) const { return nFrames_; }; //! Set the sample rate associated with the StkFrames data. /*! By default, this value is set equal to the current STK sample rate at the time of instantiation. */ void setDataRate( StkFloat rate ) { dataRate_ = rate; }; //! Return the sample rate associated with the StkFrames data. /*! By default, this value is set equal to the current STK sample rate at the time of instantiation. */ StkFloat dataRate( void ) const { return dataRate_; }; //! Returns \c true if the data is in interleaved format, \c false if the data is non-interleaved. bool interleaved( void ) const { return interleaved_; }; //! Set the flag to indicate whether the internal data is in interleaved (\c true) or non-interleaved (\c false) format. /*! Note that this function does not modify the internal data order with respect to the argument value. It simply changes the indicator flag value. */ void setInterleaved( bool isInterleaved ) { interleaved_ = isInterleaved; }; private: StkFloat *data_; StkFloat dataRate_; size_t nFrames_; unsigned int nChannels_; size_t size_; size_t bufferSize_; bool interleaved_; }; // Here are a few other useful typedefs. typedef unsigned short UINT16; typedef unsigned int UINT32; typedef signed short SINT16; typedef signed int SINT32; typedef float FLOAT32; typedef double FLOAT64; // The default sampling rate. const StkFloat SRATE = 44100.0; // The default real-time audio input and output buffer size. If // clicks are occuring in the input and/or output sound stream, a // larger buffer size may help. Larger buffer sizes, however, produce // more latency. const unsigned int RT_BUFFER_SIZE = 512; // The default rawwave path value is set with the preprocessor // definition RAWWAVE_PATH. This can be specified as an argument to // the configure script, in an integrated development environment, or // below. The global STK rawwave path variable can be dynamically set // with the Stk::setRawwavePath() function. This value is // concatenated to the beginning of all references to rawwave files in // the various STK core classes (ex. Clarinet.cpp). If you wish to // move the rawwaves directory to a different location in your file // system, you will need to set this path definition appropriately. #if !defined(RAWWAVE_PATH) #define RAWWAVE_PATH "../../rawwaves/" #endif const StkFloat PI = 3.14159265358979; const StkFloat TWO_PI = 2 * PI; const StkFloat ONE_OVER_128 = 0.0078125; #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_MM__) #define __OS_WINDOWS__ #define __STK_REALTIME__ #elif defined(__LINUX_OSS__) || defined(__LINUX_ALSA__) || defined(__LINUX_JACK__) #define __OS_LINUX__ #define __STK_REALTIME__ #elif defined(__IRIX_AL__) #define __OS_IRIX__ #define __STK_REALTIME__ #elif defined(__MACOSX_CORE__) #define __OS_MACOSX__ #define __STK_REALTIME__ #endif //#define _STK_DEBUG_ } // namespace Nyq #endif nyquist-3.05/nyqstk/stkinit.h0000644000175000000620000000017210144436365015360 0ustar stevestaff/* stkinit.h -- set up stk path */ #ifdef __cplusplus extern "C" { #endif void stk_init(); #ifdef __cplusplus } #endif nyquist-3.05/nyqstk/stkint.h0000644000175000000620000000076711466723256015227 0ustar stevestafftypedef double StkFloat; #define NREV 0 #define JCREV 1 #define PRCREV 2 #ifdef __cplusplus extern "C" { #endif struct stkEffect; struct stkEffect * initStkEffect (int, StkFloat, int); int deleteStkEffect(struct stkEffect *); StkFloat stkEffectTick(struct stkEffect *, StkFloat); void stkEffectSetMix (struct stkEffect *, StkFloat); struct stkEffect * initStkPitShift(StkFloat, int); struct stkEffect * initStkChorus(StkFloat, StkFloat, StkFloat, int); #ifdef __cplusplus } #endif nyquist-3.05/nyqstk/stkinit.cpp0000644000175000000620000000234411466723256015724 0ustar stevestaff/* stk path initialization */ #include "stdlib.h" #include "string.h" // #include "instr.h" #include "Stk.h" #include "stkinit.h" #ifdef __cplusplus extern "C" { #endif #include "xlisp.h" #ifdef __cplusplus } #endif using namespace Nyq; const char *rawwave_path = NULL; extern "C" void stk_init() { /* wherever the sinewave.raw file is, that will become * the rawwave_path for STK */ char filename[32]; strcpy(filename, "rawwaves"); filename[8] = os_pathchar; filename[9] = '\0'; strcat(filename, "sinewave.raw"); /* find_in_xlisp_path returns const char *, but we're going to * alter it to get just the path, so we have to coerce out the * const attribute */ char *path = (char *) find_in_xlisp_path(filename); if (!path) { errputstr("\nERROR: Could not find sinewave.raw in rawwaves. Something is wrong with the installation or configuration.\n\n"); rawwave_path = ""; return; } /* remove sinewave.raw to get just the path */ path[strlen(path) - 12] = '\0'; rawwave_path = strcpy((char *) malloc(strlen(path) + 1), path); /* keep a copy */ /* note: rawwave_path is allocated but never freed */ Stk::setRawwavePath(path); // PJM } nyquist-3.05/nyqstk/stkint.cpp0000644000175000000620000000352111466723256015551 0ustar stevestaff// interface for STK Effects #include #include "stkint.h" #include "NRev.h" #include "JCRev.h" #include "PRCRev.h" using namespace Nyq; // Reverb Effects ========================================================== struct stkEffect { Effect * effectPtr; }; struct stkEffect *initStkEffect(int eff_type, ::StkFloat trev, int sample_rate) { struct stkEffect * eff = (struct stkEffect *) malloc(sizeof(struct stkEffect)); Stk::setSampleRate(sample_rate); switch(eff_type) { case NREV: eff->effectPtr = new NRev(trev); break; case JCREV: eff->effectPtr = new JCRev(trev); break; case PRCREV: eff->effectPtr = new PRCRev(trev); break; default: return NULL; } return eff; } int deleteStkEffect(struct stkEffect * eff) { delete(eff->effectPtr); free(eff); return 0; } ::StkFloat stkEffectTick(struct stkEffect * eff, ::StkFloat s) { return eff->effectPtr->tick(s); } void stkEffectSetMix (struct stkEffect * eff, ::StkFloat mix) { eff->effectPtr->setEffectMix(mix); } // PitShift =================================================== #include "PitShift.h" struct stkEffect *initStkPitShift(::StkFloat shift, int sample_rate) { PitShift * ps; ps = new PitShift(); ps->setShift(shift); struct stkEffect * eff = (struct stkEffect *) malloc(sizeof(struct stkEffect)); Stk::setSampleRate(sample_rate); eff->effectPtr = ps; return eff; } // Chorus ===================================================== #include "Chorus.h" struct stkEffect *initStkChorus(::StkFloat baseDelay, ::StkFloat depth, ::StkFloat freq, int sample_rate) { Chorus * ch; ch = new Chorus(baseDelay); ch->setModDepth(depth); ch->setModFrequency(freq); struct stkEffect * eff = (struct stkEffect *) malloc(sizeof(struct stkEffect)); Stk::setSampleRate(sample_rate); eff->effectPtr = ch; return eff; } nyquist-3.05/nyqstk/instr.cpp0000644000175000000620000000460511466723256015400 0ustar stevestaff#include "instr.h" #include "Instrmnt.h" #include "Clarinet.h" #include "Saxofony.h" #include "Bowed.h" #include "BandedWG.h" #include "Mandolin.h" #include "Sitar.h" #include "ModalBar.h" #include "Flute.h" #include "stdlib.h" #include "string.h" using namespace Nyq; /* C interface to Instrmnt */ struct instr { Instrmnt *instrObjPtr; }; struct instr *initInstrument(int instr_type, int sample_rate) { struct instr *in = (struct instr *) malloc(sizeof(struct instr)); Stk::setSampleRate(sample_rate); switch(instr_type) { case CLARINET: in->instrObjPtr = new Clarinet(10.0); break; case SAXOFONY: in->instrObjPtr = new Saxofony(10.0); break; case BOWED: in->instrObjPtr = new Bowed(10.0); break; case BANDEDWG: in->instrObjPtr = new BandedWG(); break; case MANDOLIN: in->instrObjPtr = new Mandolin(10.0); break; case SITAR: in->instrObjPtr = new Sitar(10.0); break; case MODALBAR: in->instrObjPtr = new ModalBar(); break; case FLUTE: in->instrObjPtr = new Flute(10.0); break; default: return NULL; } return in; } int deleteInstrument(struct instr* in) { delete(in->instrObjPtr); free(in); return 0; } //! Start a note with the given frequency and amplitude. int noteOn(struct instr* in, ::MY_FLOAT frequency, ::MY_FLOAT amplitude) { in->instrObjPtr->noteOn(frequency, amplitude); return 0; } //! Stop a note with the given amplitude (speed of decay). int noteOff(struct instr* in, ::MY_FLOAT amplitude) { in->instrObjPtr->noteOff(amplitude); return 0; } //! Set instrument parameters for a particular frequency. int setFrequency(struct instr* in, ::MY_FLOAT frequency) { in->instrObjPtr->setFrequency(frequency); return 0; } //! Return the last output value. /* MY_FLOAT lastOut(struct instr* in) { return in->instrObjPtr->lastOut(); } */ //! Compute one output sample. ::MY_FLOAT tick(struct instr* in) { return in->instrObjPtr->tick(); } // DELETED THIS. PJM //! Computer \e vectorSize outputs and return them in \e vector. //MY_FLOAT *multTicks(struct instr* in, MY_FLOAT *vector, unsigned int vectorSize) { // return in->instrObjPtr->tick(vector, vectorSize); //} //! Perform the control change specified by \e number and \e value (0.0 - 128.0). int controlChange(struct instr* in, int number, ::MY_FLOAT value) { in->instrObjPtr->controlChange(number, value); return 0; } nyquist-3.05/nyqsrc/0002755000175000000620000000000011537433122013505 5ustar stevestaffnyquist-3.05/nyqsrc/multiread.c0000644000175000000620000003053111466723256015652 0ustar stevestaff/* multiread.c -- read multichannel sound file */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "stdio.h" #ifdef UNIX #include "sys/file.h" #endif #ifndef mips #include "stdlib.h" #endif #include "sndfmt.h" #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "sndfile.h" #include "sndread.h" #include "multiread.h" /* allocate input buffer space for this many bytes/frame, * e.g. 8 allows 2 channels * If frames are bigger, then multiple reads will be issued. */ #define max_bytes_per_frame (sizeof(float) * 2) #define input_buffer_max (max_sample_block_len * max_bytes_per_frame) #define input_buffer_samps (max_sample_block_len * 2) /* multiread_fetch - read samples into multiple channels. */ /* * The susp is shared by all channels. The susp has backpointers * to the tail-most snd_list node of each channels, and it is by * extending the list at these nodes that sounds are read in. * To avoid a circularity, the reference counts on snd_list nodes * do not include the backpointers from this susp. When a snd_list * node refcount goes to zero, the multiread susp's free routine * is called. This must scan the backpointers to find the node that * has a zero refcount (the free routine is called before the node * is deallocated, so this is safe). The backpointer is then set * to NULL. When all backpointers are NULL, the susp itself is * deallocated, because it can only be referenced through the * snd_list nodes to which there are backpointers. */ void multiread_fetch(susp, snd_list) register read_susp_type susp; snd_list_type snd_list; { int i, j; int frames_read = 0; /* total frames read in this call to fetch */ int n; sample_block_type out; // char input_buffer[input_buffer_max]; float input_buffer[input_buffer_samps]; int file_frame_size; /* when we are called, the caller (SND_get_first) will insert a new * snd_list node. We need to do this here for all other channels. */ for (j = 0; j < susp->sf_info.channels; j++) { /* nyquist_printf("multiread_fetch: chan[%d] = ", j); print_snd_list_type(susp->chan[j]); stdputstr("\n"); */ if (!susp->chan[j]) { /* ignore non-existent channels */ /* nyquist_printf("multiread_fetch: ignore channel %d\n", j);*/ continue; } falloc_sample_block(out, "multiread_fetch"); /* nyquist_printf("multiread: allocated block %x\n", out); */ /* Since susp->chan[i] exists, we want to append a block of samples. * The block, out, has been allocated. Before we insert the block, * we must figure out whether to insert a new snd_list_type node for * the block. Recall that before SND_get_next is called, the last * snd_list_type in the list will have a null block pointer, and the * snd_list_type's susp field points to the suspension (in this case, * susp). When SND_get_next (in sound.c) is called, it appends a new * snd_list_type and points the previous one to internal_zero_block * before calling this fetch routine. On the other hand, since * SND_get_next is only going to be called on one of the channels, the * other channels will not have had a snd_list_type appended. * SND_get_next does not tell us directly which channel it wants (it * doesn't know), but we can test by looking for a non-null block in the * snd_list_type pointed to by our back-pointers in susp->chan[]. If * the block is null, the channel was untouched by SND_get_next, and * we should append a snd_list_type. If it is non-null, then it * points to internal_zero_block (the block inserted by SND_get_next) * and a new snd_list_type has already been appended. */ /* Before proceeding, it may be that garbage collection ran when we * allocated out, so check again to see if susp->chan[j] is Null: */ if (!susp->chan[j]) { ffree_sample_block(out, "multiread_fetch"); continue; } if (!susp->chan[j]->block) { snd_list_type snd_list = snd_list_create((snd_susp_type) susp); /* Now we have a snd_list to append to the channel, but a very * interesting thing can happen here. snd_list_create, which * we just called, MAY have invoked the garbage collector, and * the GC MAY have freed all references to this channel, in which * case multread_free(susp) will have been called, and susp->chan[j] * will now be NULL! */ if (!susp->chan[j]) { nyquist_printf("susp %p Channel %d disappeared!\n", susp, j); ffree_snd_list(snd_list, "multiread_fetch"); } else { susp->chan[j]->u.next = snd_list; } } /* see the note above: we don't know if susp->chan still exists */ /* Note: We DO know that susp still exists because even if we lost * some channels in a GC, someone is still calling SND_get_next on * some channel. I suppose that there might be some very pathological * code that could free a global reference to a sound that is in the * midst of being computed, perhaps by doing something bizarre in the * closure that snd_seq activates at the logical stop time of its first * sound, but I haven't thought that one through. */ if (susp->chan[j]) { susp->chan[j]->block = out; /* check some assertions */ if (susp->chan[j]->u.next->u.susp != (snd_susp_type) susp) { nyquist_printf("didn't find susp at end of list for chan %d\n", j); } } else { /* we allocated out, but don't need it anymore due to GC */ ffree_sample_block(out, "multiread_fetch"); } } file_frame_size = susp->sf_info.channels; /* now fill sample blocks with frames from the file until eof or end of blocks */ while (true) { /* compute how many frames to read to fill sample blocks */ long frame_count = max_sample_block_len - frames_read; long actual; /* how many frames actually read */ /* make sure frames will fit in buffer */ if (frame_count * file_frame_size > input_buffer_samps) { frame_count = input_buffer_samps / file_frame_size; } actual = sf_readf_float(susp->sndfile, input_buffer, frame_count); n = actual; /* don't read too many */ if (n > (susp->cnt - susp->susp.current)) { n = susp->cnt - susp->susp.current; } /* process one channel at a time, multiple passes through input */ for (j = 0; j < susp->sf_info.channels; j++) { register sample_block_values_type out_ptr; /* offset by channel number: */ float *float_ptr = input_buffer + j; /* ignore nonexistent channels */ if (!susp->chan[j]) continue; /* find pointer to sample buffer */ out_ptr = susp->chan[j]->block->samples + frames_read; /* copy samples */ for (i = 0; i < n; i++) { *out_ptr++ = *float_ptr; float_ptr += susp->sf_info.channels; } susp->chan[j]->block_len = frames_read + n; } /* jlh BECAUSE, at this point, all the code cares about is that n frames have been read and the samples put into their appropriate snd_node buffers. */ frames_read += n; susp->susp.current += n; if (frames_read == 0) { /* NOTE: this code should probably be removed -- how could we ever get here? Since file formats know the sample count, we'll always read frames. When we hit the end-of-file, the else clause below will run and terminate the sound, so we'll never try and read samples that are not there. The only exception is an empty sound file with no samples, in which case we could omit this if test and execute the else part below. This code *might* be good for formats that do not encode a sample count and where reading the end of file is the only way to detect the end of the data. Since it seeems to work, I'm going to leave this in place. One tricky point of the algorithm: when we get here, we set up susp->chan[j] to point to the right place and then call snd_list_terminate(). This deletes the snd_list that chan[j] is pointing to, but not before calling multiread_free(), which upon detecting that the sound is being freed, sets chan[j] to NULL. This works sequentially on each channel and than last time, this susp is freed because no channels are active. */ /* we didn't read anything, but can't return length zero, so * convert snd_list's to pointer to zero block. This loop * will free the susp via snd_list_unref(). */ for (j = 0; j < susp->sf_info.channels; j++) { if (susp->chan[j]) { snd_list_type the_snd_list = susp->chan[j]; /* this is done so that multiread_free works right: */ susp->chan[j] = susp->chan[j]->u.next; /* nyquist_printf("end of file, terminating channel %d\n", j); */ /* this fixes up the tail of channel j */ snd_list_terminate(the_snd_list); } } return; } else if (susp->cnt == susp->susp.current || actual < frame_count) { /* we've read the requested number of frames or we * reached end of file * last iteration will close file and free susp: */ for (j = 0; j < susp->sf_info.channels; j++) { snd_list_type the_snd_list = susp->chan[j]; /* nyquist_printf("reached susp->cnt, terminating chan %d\n", j); */ if (the_snd_list) { /* assert: */ if (the_snd_list->u.next->u.susp != (snd_susp_type) susp) { stdputstr("assertion violation"); } /* this is done so that multiread_free works right: */ susp->chan[j] = the_snd_list->u.next; snd_list_unref(the_snd_list->u.next); /* terminate by pointing to zero block */ the_snd_list->u.next = zero_snd_list; } } return; } else if (frames_read >= max_sample_block_len) { /* move pointer to next list node */ for (j = 0; j < susp->sf_info.channels; j++) { if (susp->chan[j]) susp->chan[j] = susp->chan[j]->u.next; } return; } } } /* multiread__fetch */ void multiread_free(read_susp_type susp) { int j; boolean active = false; /* stdputstr("multiread_free: "); */ for (j = 0; j < susp->sf_info.channels; j++) { if (susp->chan[j]) { if (susp->chan[j]->refcnt) active = true; else { susp->chan[j] = NULL; /* nyquist_printf("deactivating channel %d\n", j); */ } } } if (!active) { /* stdputstr("all channels freed, freeing susp now\n"); */ read_free(susp); } } LVAL multiread_create(susp) read_susp_type susp; { LVAL result; int j; xlsave1(result); result = newvector(susp->sf_info.channels); /* create array for sounds */ falloc_generic_n(susp->chan, snd_list_type, susp->sf_info.channels, "multiread_create"); /* create sounds to return */ for (j = 0; j < susp->sf_info.channels; j++) { sound_type snd = sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, 1.0); LVAL snd_lval = cvsound(snd); /* nyquist_printf("multiread_create: sound %d is %x, LVAL %x\n", j, snd, snd_lval); */ setelement(result, j, snd_lval); susp->chan[j] = snd->list; } xlpop(); return result; } nyquist-3.05/nyqsrc/fft-rbd.c0000644000175000000620000001155310144436365015205 0ustar stevestaff/* samples.c -- fugue sound data type */ #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "fft.h" /* NOTE: this code does not properly handle start times that do not * correspond to the time of the first actual sample */ /* snd_fetch_array -- fetch a lisp array of samples */ /* * storage layout: the extra field points to extra state that we'll use * extra[0] -> length of extra storage * extra[1] -> CNT (number of samples in current block) * extra[2] -> INDEX (current sample index in current block) * extra[3] -> FILLCNT (how many samples in buffer) * extra[4] -> TERMCNT (how many samples until termination) * extra[4 .. 4+len-1] -> samples (stored as floats) * * Termination details: * Return NIL when the sound terminates. * Termination is defined as the point where all original * signal samples have been shifted out of the samples buffer * so that all that's left are zeros from beyond the termination * point. * Implementation: when termination is discovered, set TERMCNT * to the number of samples to be shifted out. TERMCNT is initially * -1 as a flag that we haven't seen the termination yet. * Each time samples are shifted, decrement TERMCNT by the shift amount. * When TERMCNT goes to zero, return NULL. */ #define CNT extra[1] #define INDEX extra[2] #define FILLCNT extra[3] #define TERMCNT extra[4] #define OFFSET 5 #define SAMPLES list->block->samples LVAL snd_fft(sound_type s, long len, long step /* more parameters may belong here */) { long i, maxlen, skip, fillptr; float *samples; LVAL result; if (len < 1) xlfail("len < 1"); if (!s->extra) { /* this is the first call, so fix up s */ /* note: any storage required by fft must be allocated here in a contiguous * block of memory who's size is given by the first long in the block. * Here, there are 4 more longs after the size, and then room for len floats * (assumes that floats and longs take equal space). * * The reason for this storage restriction is that when a sound is freed, the * block of memory pointed to by extra is also freed. There is no function * call that might free a more complex structure (this could be added in sound.c * however if it's really necessary). */ falloc_generic_n(s->extra, long, len + OFFSET, "snd_fft"); s->extra[0] = sizeof(long) * (len + OFFSET); s->CNT = s->INDEX = s->FILLCNT = 0; s->TERMCNT = -1; maxlen = len; } else { maxlen = (s->extra[0] / sizeof(long)) - OFFSET; if (maxlen < 1) xlfail("sound in use by another iterator"); if (maxlen < len) xlfail("len grew"); } samples = (float *) &(s->extra[OFFSET]); /* step 1: refill buffer with samples */ fillptr = s->FILLCNT; while (fillptr < maxlen) { if (s->INDEX == s->CNT) { sound_get_next(s, &(s->CNT)); if (s->SAMPLES == zero_block->samples) { if (s->TERMCNT < 0) s->TERMCNT = fillptr; } s->INDEX = 0; } samples[fillptr++] = s->SAMPLES[s->INDEX++] * s->scale; } s->FILLCNT = fillptr; /* it is important to test here AFTER filling the buffer, because * if fillptr WAS 0 when we hit the zero_block, then filling the * buffer will set TERMCNT to 0. */ if (s->TERMCNT == 0) return NULL; /* logical stop time is ignored by this code -- to fix this, * you would need a way to return the logical stop time to * the caller. */ /* HERE IS WHERE THE FFT SHOULD TAKE PLACE ON samples. DO NOT * DESTROY SAMPLES IF YOU WANT TO ALLOW OVERLAPPED FFT'S. THE * CURRENT CODE RETURNS SAMPLES, BUT A REAL FFT WOULD RETURN * THE RESULT OF THE FFT IN STEP 2, WHICH FOLLOWS: */ /* step 2: construct an array and return it */ xlsave1(result); result = newvector(len); for (i = 0; i < len; i++) { setelement(result, i, cvflonum(samples[i])); } /* step 3: shift samples by step */ if (step < 0) xlfail("step < 0"); s->FILLCNT -= step; if (s->FILLCNT < 0) s->FILLCNT = 0; for (i = 0; i < s->FILLCNT; i++) { samples[i] = samples[i + step]; } if (s->TERMCNT >= 0) { s->TERMCNT -= step; if (s->TERMCNT < 0) s->TERMCNT = 0; } /* step 4: advance in sound to next sample we need * (only does work if step > size of buffer) */ skip = step - maxlen; while (skip > 0) { long remaining = s->CNT - s->INDEX; if (remaining >= skip) { s->INDEX += skip; skip = 0; } else { skip -= remaining; sound_get_next(s, &(s->CNT)); s->INDEX = 0; } } /* restore the stack */ xlpop(); return result; } /* snd_fetch_array */ nyquist-3.05/nyqsrc/lpanal.h0000644000175000000620000000014710144436365015132 0ustar stevestaff/* lpanal.h -- LPC analysis */ LVAL snd_lpanal(LVAL v, long P); /* LISP: (SND-LPANAL ANY FIXNUM) */ nyquist-3.05/nyqsrc/pvshell.h0000644000175000000620000001002611466723256015343 0ustar stevestaff/* pvshell.h -- a generic Nyquist primitive, esp. for phase vocoder */ /* how many doubles to provide for miscellaneous state info */ #define PVSHELL_STATE_MAX 8 /* define some bits to return conditions */ #define PVSHELL_FLAG_TERMINATE 4 #define PVSHELL_FLAG_LOGICAL_STOP 8 /* this function is called to compute samples. It should compute n * samples (floats == sample_type) and store them at out[i]. * You can return less than n samples by writing the actual number * of samples computed into *n. Normally, you return zero. * To indicate that the time of the FIRST sample is the logical stop * time, return PVSHELL_FLAG_LOGICAL_STOP. (If the logical stop time * is not at the first sample, but instead at sample j, then just * return j samples (from 0 to j-1), save the rest of the samples, * and the next time, the first sample will correspond to the logical * stop time, so you can return PVSHELL_FLAG_LOGICAL_STOP. * To indicate that the sound has terminated, return * PVSHELL_FLAG_TERMINATE. This should be the only time you return * zero samples. (As with logical stop time, if you have samples to * return before termination, then do it, and return * PVSHELL_FLAG_TERMINATE the next time you are called, at which * point you've returned all the samples, so you can set *n = 0. */ struct pvshell_struct; typedef long (*h_fn_type)(struct pvshell_struct *susp, sample_block_values_type out, long *n); typedef struct pvshell_struct { sound_type f; long f_cnt; sample_block_values_type f_ptr; sound_type g; long g_cnt; sample_block_values_type g_ptr; long flags; /* for terminated and logically stopped flags */ // state is extra storage for whatever you like double state[PVSHELL_STATE_MAX]; // h is a function that computes sound from f, g, x, y, state h_fn_type h; } pvshell_node, *pvshell_type; /* to get samples from f or g, use these macros. For each sample, call * PVSHELL_TEST_X to get logical stop and terminate flags (but do not * fetch a sample). Then, if you want, call PVSHELL_FETCH_X to get the * next sample. You can call PVSHELL_TEST_X multiple times before * calling PVSHELL_FETCH_X, e.g. you can return exit a loop when you * see a logical stop flag and later call PVSHELL_TEST_X again. You * CANNOT call PVSHELL_FETCH_X multiples times without an intervening * call to PVSHELL_TEST_X. Finally, the logical stop flag is only * returned once. Normally you should write something like: * new_flags = PVSHELL_TEST_F(susp); * susp->flags | = new_flags; // remember flags * if (new_flags) break; * in the sample loop so that you will break when you see logical_stop. * Outside the loop, you can return (*n ? 0 : susp->flags) which will * return 0 if you computed samples before the logical stop was detected. * Then the next time you are called, you will return the logical_stop * flag because you saved it in susp->flags, and the flag applies to the * *beginning* of the sample block. This code handles terminate too. */ #define PVSHELL_TEST_F(susp) ((susp)->f_cnt == 0 ? pvshell_test_f(susp) : 0) #define PVSHELL_FETCH_F(susp) ((susp)->f_cnt--, (*(susp)->f_ptr++)) #define PVSHELL_TEST_G(susp) ((susp)->g_cnt == 0 ? pvshell_test_g(susp) : 0) #define PVSHELL_FETCH_G(susp) ((susp)->g_cnt--, (*(susp)->g_ptr++)) /* snd_make_pvshell -- create an instance of pvshell. name -- string name of the operation, for debugging & printing (name is not copied. It must be a permanent, immutable string.) sr -- sample rate of output sound t0 -- start time of output sound h -- function that computes samples of output f -- first input sound, e.g. sound to be time-stretched g -- second input sound, e.g. sound to control varying stretch factor state -- initial state information needed by h n -- number of doubles in state (< PVSHELL_STATE_MAX) */ sound_type snd_make_pvshell(char *name, rate_type sr, time_type t0, h_fn_type h, sound_type f, sound_type g, double *state, long n); nyquist-3.05/nyqsrc/yin.h0000644000175000000620000000030310144436365014454 0ustar stevestaff/* yin.h -- Nyquist code for F0 estimation using YIN approach */ LVAL snd_yin(sound_type s, double low_step, double high_step, long stepsize); /* LISP: (SND-YIN SOUND ANYNUM ANYNUM FIXNUM) */ nyquist-3.05/nyqsrc/sndwrite.c0000644000175000000620000004715711466723256015537 0ustar stevestaff/* sndwrite.c -- write sounds to files */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "stdlib.h" #include "switches.h" #include "string.h" #ifdef UNIX #include "sys/types.h" #endif #ifdef WINDOWS #include #endif #include /* include sound.h first because it includes math.h * which declares abs(). cext.h #defines abs()! * sound.h depends on xlisp.h */ #include "xlisp.h" #include "sound.h" #include "cext.h" #include "userio.h" #include "falloc.h" #include "sndwrite.h" #include "extern.h" #include "snd.h" #ifdef UNIX #include "sys/file.h" /* #include */ /* #include */ #else #ifdef MACINTOSH #include #include #define L_SET SEEK_SET #define L_INCR SEEK_CUR #endif #endif #define D if (0) int sndwrite_trace = 0; /* debugging */ sample_type sound_save_sound(LVAL s_as_lval, long n, snd_type snd, char *buf, long *ntotal, snd_type player); sample_type sound_save_array(LVAL sa, long n, snd_type snd, char *buf, long *ntotal, snd_type player); unsigned char st_linear_to_ulaw(int sample); typedef struct { sound_type sound; long cnt; sample_block_values_type ptr; double scale; int terminated; } sound_state_node, *sound_state_type; LVAL prepare_audio(LVAL play, snd_type snd, snd_type player) { long flags; if (play == NIL) return NIL; player->format = snd->format; player->u.audio.devicename[0] = 0; player->u.audio.interfacename[0] = 0; if (snd_open(player, &flags) != SND_SUCCESS) { xlabort("snd_save -- could not open audio output"); } /* make sure player and snd are compatible -- if not, set player to NULL * and print a warning message */ if (player->format.channels == snd->format.channels && player->format.mode == snd->format.mode && player->format.bits == snd->format.bits) { /* ok so far, check out the sample rate */ if (player->format.srate != snd->format.srate) { char msg[100]; sprintf(msg, "%s(%g)%s(%g).\n", "Warning: file sample rate ", snd->format.srate, " differs from audio playback sample rate ", player->format.srate); stdputstr(msg); } } else { stdputstr("File format not supported by audio output.\n"); return NIL; } return play; } /* finish_audio -- flush the remaining samples, then close */ /**/ void finish_audio(snd_type player) { /* note that this is a busy loop! */ while (snd_flush(player) != SND_SUCCESS) ; snd_close(player); } /* write_to_audio -- handle audio output from buffer */ /* * We want to write as soon as space is available so that * a full sound buffer can be queued up for output. This * may require transferring only part of buf, so we keep * track of progress and output whenever space is available. */ void write_to_audio(snd_type player, void *buf, long buflen) { long rslt; while (buflen) { /* this loop is a busy-wait loop! */ rslt = snd_poll(player); /* wait for buffer space */ rslt = min(rslt, buflen); if (rslt) { snd_write(player, buf, rslt); buf = (void *) ((char *) buf + (rslt * snd_bytes_per_frame(player))); buflen -= rslt; } } } double sound_save( LVAL snd_expr, long n, unsigned char *filename, long format, long mode, long bits, long swap, double *sr, long *nchans, double *duration, LVAL play) { LVAL result; char *buf; long ntotal; double max_sample; snd_node snd; snd_node player; long flags; snd.device = SND_DEVICE_FILE; snd.write_flag = SND_WRITE; strcpy(snd.u.file.filename, (char *) filename); snd.u.file.file = -1; /* this is a marker that snd is unopened */ snd.u.file.header = format; snd.format.mode = mode; snd.format.bits = bits; snd.u.file.swap = swap; player.device = SND_DEVICE_AUDIO; player.write_flag = SND_WRITE; player.u.audio.devicename[0] = '\0'; player.u.audio.descriptor = NULL; player.u.audio.protocol = SND_COMPUTEAHEAD; player.u.audio.latency = 1.0; player.u.audio.granularity = 0.0; if ((buf = (char *) malloc(max_sample_block_len * MAX_SND_CHANNELS * sizeof(float))) == NULL) { xlabort("snd_save -- couldn't allocate memory"); } result = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE RESULT IS UNPROTECTED */ if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); *nchans = snd.format.channels = i; while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { xlerror("sound_save: array has non-sound element", result); } } /* assume all are the same: */ *sr = snd.format.srate = getsound(getelement(result, 0))->sr; /* note: if filename is "", then don't write file; therefore, * write the file if (filename[0]) */ if (filename[0] && snd_open(&snd, &flags) != SND_SUCCESS) { xlabort("snd_save -- could not open sound file"); } play = prepare_audio(play, &snd, &player); max_sample = sound_save_array(result, n, &snd, buf, &ntotal, (play == NIL ? NULL : &player)); *duration = ntotal / *sr; if (filename[0]) snd_close(&snd); if (play != NIL) finish_audio(&player); } else if (exttypep(result, a_sound)) { *nchans = snd.format.channels = 1; *sr = snd.format.srate = (getsound(result))->sr; if (filename[0] && snd_open(&snd, &flags) != SND_SUCCESS) { xlabort("snd_save -- could not open sound file"); } play = prepare_audio(play, &snd, &player); max_sample = sound_save_sound(result, n, &snd, buf, &ntotal, (play == NIL ? NULL : &player)); *duration = ntotal / *sr; if (filename[0]) snd_close(&snd); if (play != NIL) finish_audio(&player); } else { xlerror("sound_save: expression did not return a sound", result); max_sample = 0.0; } free(buf); return max_sample; } double sound_overwrite( LVAL snd_expr, long n, unsigned char *filename, long byte_offset, long header, long mode, long bits, long swap, double sr, long nchans, double *duration) { LVAL result; char *buf; char error[140]; long ntotal; double max_sample; snd_node snd; long flags; snd.device = SND_DEVICE_FILE; snd.write_flag = SND_OVERWRITE; strcpy(snd.u.file.filename, (char *) filename); snd.u.file.header = header; snd.u.file.byte_offset = byte_offset; snd.format.channels = nchans; snd.format.mode = mode; snd.format.bits = bits; snd.u.file.swap = swap; snd.format.srate = sr; if ((buf = (char *) malloc(max_sample_block_len * MAX_SND_CHANNELS * sizeof(float))) == NULL) { xlabort("snd_overwrite: couldn't allocate memory"); } if (snd_open(&snd, &flags) != SND_SUCCESS) { sprintf(error, "snd_overwrite: cannot open file %s and seek to %d", filename, (int)byte_offset); free(buf); xlabort(error); } result = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE RESULT IS UNPROTECTED */ if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); if (nchans != i) { sprintf(error, "%s%d%s%d%s", "snd_overwrite: number of channels in sound (", (int)i, ") does not match\n number of channels in file (", (int)nchans, ")"); free(buf); snd_close(&snd); xlabort(error); } while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { free(buf); snd_close(&snd); xlerror("sound_save: array has non-sound element", result); } } /* assume all are the same: */ if (sr != getsound(getelement(result, 0))->sr) { sprintf(error, "%s%g%s%g%s", "snd_overwrite: sample rate in sound (", getsound(getelement(result, 0))->sr, ") does not match\n sample rate in file (", sr, ")"); free(buf); snd_close(&snd); xlabort(error); } max_sample = sound_save_array(result, n, &snd, buf, &ntotal, NULL); *duration = ntotal / sr; } else if (exttypep(result, a_sound)) { if (nchans != 1) { sprintf(error, "%s%s%d%s", "snd_overwrite: number of channels in sound (1", ") does not match\n number of channels in file (", (int)nchans, ")"); free(buf); snd_close(&snd); xlabort(error); } if (sr != getsound(result)->sr) { sprintf(error, "%s%g%s%g%s", "snd_overwrite: sample rate in sound (", getsound(result)->sr, ") does not match\n sample rate in file (", sr, ")"); free(buf); snd_close(&snd); xlabort(error); } max_sample = sound_save_sound(result, n, &snd, buf, &ntotal, NULL); *duration = ntotal / sr; } else { free(buf); snd_close(&snd); xlerror("sound_save: expression did not return a sound", result); max_sample = 0.0; } free(buf); snd_close(&snd); return max_sample; } cvtfn_type find_cvt_to_fn(snd_type snd, char *buf) { cvtfn_type cvtfn; /* find the conversion function */ if (snd->format.bits == 8) cvtfn = cvt_to_8[snd->format.mode]; else if (snd->format.bits == 16) cvtfn = cvt_to_16[snd->format.mode]; else if (snd->format.bits == 24) cvtfn = cvt_to_24[snd->format.mode]; else if (snd->format.bits == 32) cvtfn = cvt_to_32[snd->format.mode]; else cvtfn = cvt_to_unknown; if (cvtfn == cvt_to_unknown) { char error[50]; sprintf(error, "Cannot write %d-bit samples in mode %s", (int)snd->format.bits, snd_mode_to_string(snd->format.mode)); free(buf); snd_close(snd); xlabort(error); } return cvtfn; } sample_type sound_save_sound(LVAL s_as_lval, long n, snd_type snd, char *buf, long *ntotal, snd_type player) { long blocklen; long buflen; sound_type s; long debug_unit; /* print messages at intervals of this many samples */ long debug_count; /* next point at which to print a message */ sample_type max_sample = 0.0F; cvtfn_type cvtfn; *ntotal = 0; /* if snd_expr was simply a symbol, then s now points to a shared sound_node. If we read samples from it, then the sound bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound_node. We need to make the new sound reachable by the garbage collector to that any lisp data reachable from the sound do not get collected. To make the sound reachable, we need to allocate a node, and the GC might run, so we need to protect the OLD s but then make it unreachable. We will let the GC collect the sound in the end. */ xlprot1(s_as_lval); s = sound_copy(getsound(s_as_lval)); s_as_lval = cvsound(s); /* destroys only ref. to original */ /* for debugging */ /* printing_this_sound = s;*/ debug_unit = debug_count = (long) max(snd->format.srate, 10000.0); cvtfn = find_cvt_to_fn(snd, buf); #ifdef MACINTOSH if (player) { gprintf(TRANS, "Playing audio: Click and hold mouse button to stop playback.\n"); } #endif while (n > 0) { long togo; float peak; sample_block_type sampblock = sound_get_next(s, &blocklen); oscheck(); #ifdef SNAPSHOTS stdputstr("."); if (sound_created_flag) { stdputstr("SNAPSHOT: "); sound_print_tree(printing_this_sound); sound_created_flag = false; } fflush(stdout); #endif if (sampblock == zero_block || blocklen == 0) { break; } togo = min(blocklen, n); buflen = (*cvtfn)((void *) buf, (void *) sampblock->samples, togo, s->scale, &peak); if (peak > max_sample) max_sample = peak; #ifdef MACINTOSH if (Button()) { if (player) { snd_reset(player); } gprintf(TRANS, "\n\nStopping playback...\n\n\n"); break; } #endif if (snd->u.file.file != -1) snd_write(snd, (void *) buf, buflen); if (player) write_to_audio(player, (void *) buf, buflen); n -= togo; *ntotal += togo; if (*ntotal > debug_count) { gprintf(TRANS, " %d ", *ntotal); fflush(stdout); debug_count += debug_unit; } } gprintf(TRANS, "\ntotal samples: %d\n", *ntotal); xlpop(); return max_sample; } sample_type sound_save_array(LVAL sa, long n, snd_type snd, char *buf, long *ntotal, snd_type player) { long i, chans; long buflen; sound_state_type state; double start_time = HUGE_VAL; float *float_bufp; LVAL sa_copy; long debug_unit; /* print messages at intervals of this many samples */ long debug_count; /* next point at which to print a message */ sample_type max_sample = 0.0F; cvtfn_type cvtfn; *ntotal = 0; /* THE ALGORITHM: first merge floating point samples from N channels * into consecutive multi-channel frames in buf. Then, treat buf * as just one channel and use one of the cvt_to_* functions to * convert the data IN PLACE in the buffer (this is ok because the * converted data will never take more space than the original 32-bit * floats, so the converted data will not overwrite any floats before * the floats are converted */ /* if snd_expr was simply a symbol, then sa now points to a shared sound_node. If we read samples from it, then the sounds bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound array. See also sound_save_sound() */ chans = getsize(sa); if (chans > MAX_SND_CHANNELS) { xlerror("sound_save: too many channels", sa); free(buf); snd_close(snd); } xlprot1(sa); sa_copy = newvector(chans); xlprot1(sa_copy); /* Why do we copy the array into an xlisp array instead of just * the state[i] array? Because some of these sounds may reference * the lisp heap. We must put the sounds in an xlisp array so that * the gc will find and mark them. xlprot1(sa_copy) makes the array * visible to gc. */ for (i = 0; i < chans; i++) { sound_type s = getsound(getelement(sa, i)); setelement(sa_copy, i, cvsound(sound_copy(s))); } sa = sa_copy; /* destroy original reference to allow GC */ state = (sound_state_type) malloc(sizeof(sound_state_node) * chans); for (i = 0; i < chans; i++) { state[i].sound = getsound(getelement(sa, i)); state[i].scale = state[i].sound->scale; D nyquist_printf("save scale factor %d = %g\n", (int)i, state[i].scale); state[i].terminated = false; state[i].cnt = 0; /* force a fetch */ start_time = min(start_time, state[i].sound->t0); } for (i = 0; i < chans; i++) { if (state[i].sound->t0 > start_time) sound_prepend_zeros(state[i].sound, start_time); } /* for debugging */ /* printing_this_sound = s;*/ cvtfn = find_cvt_to_fn(snd, buf); #ifdef MACINTOSH if (player) { gprintf(TRANS, "Playing audio: Click and hold mouse button to stop playback.\n"); } #endif debug_unit = debug_count = (long) max(snd->format.srate, 10000.0); while (n > 0) { /* keep the following information for each sound: has it terminated? pointer to samples number of samples remaining in block scan to find the minimum remaining samples and output that many in an inner loop. Stop outer loop if all sounds have terminated */ int terminated = true; int togo = n; int j; float peak; oscheck(); for (i = 0; i < chans; i++) { if (state[i].cnt == 0) { if (sndwrite_trace) { nyquist_printf("CALLING SOUND_GET_NEXT " "ON CHANNEL %d (%p)\n", (int)i, state[i].sound); sound_print_tree(state[i].sound); } state[i].ptr = sound_get_next(state[i].sound, &(state[i].cnt))->samples; if (sndwrite_trace) { nyquist_printf("RETURNED FROM CALL TO SOUND_GET_NEXT " "ON CHANNEL %d\n", (int)i); } if (state[i].ptr == zero_block->samples) { state[i].terminated = true; } } if (!state[i].terminated) terminated = false; togo = min(togo, state[i].cnt); } if (terminated) break; float_bufp = (float *) buf; for (j = 0; j < togo; j++) { for (i = 0; i < chans; i++) { double s = *(state[i].ptr++) * state[i].scale; *float_bufp++ = (float) s; } } // we're treating sound as mono for the conversion, so multiply // togo by chans to get proper number of samples, and divide by // chans to convert back to frame count required by snd_write buflen = (*cvtfn)((void *) buf, (void *) buf, togo * chans, 1.0F, &peak) / chans; if (peak > max_sample) max_sample = peak; #ifdef MACINTOSH if (Button()) { if (player) { snd_reset(player); } gprintf(TRANS, "\n\nStopping playback...\n\n\n"); break; } #endif if (snd->u.file.file != -1) snd_write(snd, (void *) buf, buflen); if (player) write_to_audio(player, (void *) buf, buflen); n -= togo; for (i = 0; i < chans; i++) { state[i].cnt -= togo; } *ntotal += togo; if (*ntotal > debug_count) { gprintf(TRANS, " %d ", *ntotal); fflush(stdout); debug_count += debug_unit; } } gprintf(TRANS, "total samples: %d x %d channels\n", *ntotal, chans); /* references to sounds are shared by sa_copy and state[]. * here, we dispose of state[], allowing GC to do the * sound_unref call that frees the sounds. (Freeing them now * would be a bug.) */ free(state); xlpop(); return max_sample; } nyquist-3.05/nyqsrc/resampv.c0000644000175000000620000003437210144436365015342 0ustar stevestaff/* resampv.c -- use sinc interpolation to resample at a time-varying sample rate */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm min->MIN, max->MAX */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "resampv.h" #include "fresample.h" #include "ffilterkit.h" #include "fsmallfilter.h" #include "assert.h" /* Algorithm: First compute a factor = ratio of new sample rate to original sample rate. We have Time, the offset into X We want Xoff = ((susp->Nmult + 1) / 2.0) * MAX(1.0, 1.0 / factor) + 10 samples on either side of Time before we interpolate. If Xoff * 2 > Xsize, then we're in trouble because X is not big enough. Assume this is a pathalogical case, raise the cutoff frequency to reduce Xoff to less than Xsize/2. If Time is too small, then we're in trouble because we've lost the beginning of the buffer. Raise the cutoff frequency until Xoff is less than Time. This should only happen if factor suddenly drops. If Time is too big, we can handle it: shift X down and load X with new samples. When X is shifted by N samples, N is subtracted from Time. To minimize the "Time is too small" case, don't shift too far: leave a cushion of Xoff * 2 samples rather than the usual Xoff. Now compute a sample at Time using SrcUD and output it. What is Time? Time is the offset into X, so Time is g_of_now - (sum of all X shifts) So, let Time = g_of_now - shift_sum Whenever shift_sum or g_of_now is updated, recompute Time To compute the next g_of_now, do a lookup of g at now + 1/sr, using linear interpolation (be sure to do computation with doubles to minimize sampling time jitter). */ /* maximum ratio for downsampling (downsampling will still take place, * but the lowest prefilter cutoff frequency will be * (original_sample_rate/2) / MAX_FACTOR_INVERSE */ #define MAX_FACTOR_INVERSE 64 typedef struct resamplev_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type f; long f_cnt; sample_block_values_type f_ptr; sound_type g; long g_cnt; sample_block_values_type g_ptr; double prev_g; /* data for interpolation: */ double next_g; double phase_in_g; double phase_in_g_increment; double g_of_now; float *X; long Xsize; double Time; /* location (offset) in X of next output sample */ double shift_sum; /* total amount by which we have shifted X; also, the sample number of X[0] */ double LpScl; double factor_inverse; /* computed at every sample from g */ /* this is the amount by which we step through the input signal, so factor_inverse is the output_sample_rate / input_sample_rate, and factor is the input_sample_rate / output_sample_rate. Alternatively, factor is the amount to downsample and factor_inverse is the amount to upsample. */ /* double factor; -- computed from factor_inverse */ sample_type *Imp; sample_type *ImpD; boolean interpFilt; int Nmult; int Nwing; int Xp; /* first free location at end of X */ int Xoff; /* number of extra samples at beginning and end of X */ } resamplev_susp_node, *resamplev_susp_type; void resamplev_free(); void resampv_refill(resamplev_susp_type susp); /* Sampling rate conversion subroutine * Note that this is not the same as SrcUD in resamp.c! * X[] is the input signal to be resampled, * dt is the ratio of sample rates; when dt=1, the skip size is * Npc/dt = Npc, where Npc is how many filter coefficients to * get the cutoff frequency equal to the Nyquist rate. As dt * gets larger, we step through the filter more slowly, so low-pass * filtering occurs. As dt gets smaller, it is X[] that limits * frequency, and we use the filter to interpolate samples (upsample). * Therefore, dt>1 means downsample, dt<1 means upsample. * dt is how much we increment Time to compute each output sample. * Time is the offset in samples, including fractional samples, of X * Nwing is the size of one wing of the filter * LpScl is a corrective scale factor to make the gain == 1 or whatever * (Nyquist uses a gain of 0.95 to minimize clipping when peaks are * interpolated.) * Imp[] and ImpD[] are the filter coefficient table and table differences * (for interpolation) * Interp is true to interpolate filter coefficient lookup */ static float SrcUD(float X[], double dt, double Time, int Nwing, double LpScl, float Imp[], float ImpD[], boolean Interp) { mem_float *Xp; fast_float v; double dh; /* Step through filter impulse response */ long iTime = (long) Time; dh = MIN(Npc, Npc/dt); /* Filter sampling period */ Xp = &X[iTime]; /* Ptr to current input sample */ v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, Time - iTime, -1, dh); /* Perform left-wing inner product */ v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (1 + iTime) - Time, 1, dh); /* Perform right-wing inner product */ v *= LpScl; /* Normalize for unity filter gain */ return (float) v; } void resamplev__fetch(register resamplev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_block_type out; /* note that in this fetch routine, out_ptr is used to remember where * to put the "real" output, while X_ptr_reg is used in the inner * loop that copies input samples into X, a buffer */ register sample_block_values_type out_ptr; falloc_sample_block(out, "resamplev__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* fetch g until we have points to interpolate */ while (susp->phase_in_g >= 1.0) { susp->prev_g = susp->next_g; if (susp->g_cnt == 0) { susp_get_samples(g, g_ptr, g_cnt); if (susp->g->logical_stop_cnt == susp->g->current - susp->g_cnt) { if (susp->susp.log_stop_cnt == UNKNOWN) { susp->susp.log_stop_cnt = susp->susp.current + cnt; } } if (susp->g_ptr == zero_block->samples && susp->terminate_cnt == UNKNOWN) { susp->terminate_cnt = susp->susp.current + cnt; } } susp->next_g = susp_fetch_sample(g, g_ptr, g_cnt); susp->phase_in_g -= 1.0; if (susp->next_g < susp->prev_g) { susp->next_g = susp->prev_g; // prevent time from going backward } /* factor_inverse = 1/factor = how many samples of f per * output sample = change-in-g / output-samples-per-g-sample * = change-in-g * phase_in_g_increment */ susp->factor_inverse = susp->phase_in_g_increment * (susp->next_g - susp->prev_g); if (susp->factor_inverse > MAX_FACTOR_INVERSE) susp->factor_inverse = MAX_FACTOR_INVERSE; /* update Xoff, which depends upon factor_inverse: */ susp->Xoff = (int) (((susp->Nmult + 1) / 2.0) * MAX(1.0, susp->factor_inverse)) + 10; if (susp->Xoff * 2 > susp->Xsize) { /* bad because X is not big enough for filter, so we'll * raise the cutoff frequency as necessary */ susp->factor_inverse = ((susp->Xsize / 2) - 10 ) / ((susp->Nmult + 1) / 2.0); susp->Xoff = (susp->Xsize / 2) - 2 /* fudge factor */; } } susp->g_of_now = susp->prev_g + susp->phase_in_g * (susp->next_g - susp->prev_g); susp->Time = susp->g_of_now - susp->shift_sum; susp->phase_in_g += susp->phase_in_g_increment; /* now we have a position (g_of_now) and a factor */ /* See if enough of f is in X */ if (susp->Xoff > susp->Time) { /* there are not enough samples before Time in X, so * modify factor_inverse to fix it */ susp->factor_inverse = (susp->Time - 10.0) / ((susp->Nmult + 1) / 2.0); } else if ((susp->Xsize - susp->Xoff) < susp->Time) { /* Time is too close to the end of the buffer, slide the samples down. If there's room, leave 2*Xoff samples at beginning of * buffer. Otherwise leave as little as Xoff: */ int i, dist, ntime; ntime = susp->Xoff * 2; /* shift Time near to this index in X */ dist = ((int) susp->Time) - ntime; if (dist < 1 && (ntime * 2 < susp->Xsize)) { /* not enough room, so leave at least Xoff. */ ntime = susp->Xoff; if (susp->Xsize / 2 - ntime > 2) { /* There is some extra space. Use half to extend ntime, allowing for a possible increase in Xoff that will require more history; the other half reduces the amount of buffer copying needed. */ ntime += (susp->Xsize / 2 - ntime) / 2; } dist = ((int) susp->Time) - ntime; } /* shift everything in X by dist, adjust Time etc. */ for (i = 0; i < susp->Xsize - dist; i++) { susp->X[i] = susp->X[i + dist]; } susp->Xp -= dist; resampv_refill(susp); susp->shift_sum += dist; susp->Time = susp->g_of_now - susp->shift_sum; } /* second, compute a sample to output */ /* don't run past terminate time */ if (susp->terminate_cnt == susp->susp.current + cnt) { snd_list->block_len = cnt; if (cnt > 0) { susp->susp.current += cnt; snd_list = snd_list->u.next; snd_list->u.next = snd_list_create(&susp->susp); snd_list->block = internal_zero_block; snd_list_terminate(snd_list); } else { snd_list_terminate(snd_list); } return; } else { double scale = susp->LpScl; float tmp; if (susp->factor_inverse > 1) scale /= susp->factor_inverse; tmp = SrcUD(susp->X, susp->factor_inverse, susp->Time, susp->Nwing, scale, susp->Imp, susp->ImpD, susp->interpFilt); *out_ptr++ = tmp; } cnt++; } snd_list->block_len = cnt; susp->susp.current += cnt; assert(cnt > 0); } /* resamplev__fetch */ void resampv_refill(resamplev_susp_type susp) { int togo, n; register sample_type *f_ptr_reg; register sample_type *X_ptr_reg; while (susp->Xp < susp->Xsize) { /* outer loop */ /* read samples from susp->f into X */ togo = susp->Xsize - susp->Xp; /* don't run past the f input sample block: */ susp_check_samples(f, f_ptr, f_cnt); togo = MIN(togo, susp->f_cnt); n = togo; f_ptr_reg = susp->f_ptr; X_ptr_reg = &(susp->X[susp->Xp]); if (n) do { /* the inner sample computation loop */ *X_ptr_reg++ = *f_ptr_reg++; } while (--n); /* inner loop */ /* using f_ptr_reg is a bad idea on RS/6000: */ susp->f_ptr += togo; susp_took(f_cnt, togo); susp->Xp += togo; } /* outer loop */ } void resamplev_mark(resamplev_susp_type susp) { sound_xlmark(susp->f); sound_xlmark(susp->g); } void resamplev_free(resamplev_susp_type susp) { sound_unref(susp->f); sound_unref(susp->g); free(susp->X); ffree_generic(susp, sizeof(resamplev_susp_node), "resamplev_free"); } void resamplev_print_tree(resamplev_susp_type susp, int n) { indent(n); nyquist_printf("f:"); sound_print_tree_1(susp->f, n); indent(n); nyquist_printf("g:"); sound_print_tree_1(susp->g, n); } sound_type snd_make_resamplev(sound_type f, rate_type sr, sound_type g) { register resamplev_susp_type susp; int i; falloc_generic(susp, resamplev_susp_node, "snd_make_resamplev"); susp->susp.fetch = resamplev__fetch; susp->Nmult = SMALL_FILTER_NMULT; susp->Imp = SMALL_FILTER_IMP; susp->ImpD = SMALL_FILTER_IMPD; susp->LpScl = SMALL_FILTER_SCALE / 32768.0; susp->LpScl /= 16384.0; /* this is just a fudge factor, is SMALL_FILTER_SCALE wrong? */ susp->LpScl /= 1.0011; susp->Nwing = SMALL_FILTER_NWING; susp->terminate_cnt = UNKNOWN; /* initialize susp state */ susp->susp.free = resamplev_free; susp->susp.sr = sr; susp->susp.t0 = f->t0; susp->susp.mark = resamplev_mark; susp->susp.print_tree = resamplev_print_tree; susp->susp.name = "resamplev"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(f); susp->susp.current = 0; susp->f = f; susp->f_cnt = 0; susp->g = g; susp->g_cnt = 0; susp->next_g = 0; susp->phase_in_g_increment = g->sr / sr; susp->phase_in_g = 2.0; /* can't use susp->factor because it is unknown and variable */ /* assume at most a down-sample by a factor of 2.0 and compute Xoff accordingly */ susp->Xoff = (int) (((susp->Nmult + 1) / 2.0) * 2.0) /* MAX(1.0, 1.0 / susp->factor) */ + 10; /* this size is not critical unless it is too small */ /* allow the block size plus a buffer of 2*Xoff at both ends for the tails of the filter */ susp->Xsize = max_sample_block_len + 4 * susp->Xoff; susp->X = calloc(susp->Xsize, sizeof(sample_type)); susp->Xp = susp->Xsize; susp->shift_sum = -susp->Xsize; susp->interpFilt = true; for (i = 0; i < susp->Xoff; i++) susp->X[i] = 0.0F; susp->LpScl *= 0.95; /* reduce probability of clipping */ return sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, 1.0 /* scale factor */); } sound_type snd_resamplev(sound_type f, rate_type sr, sound_type g) { sound_type f_copy = sound_copy(f); sound_type g_copy = sound_copy(g); g_copy->scale *= (float) sr; /* put g_copy in units of samples */ return snd_make_resamplev(f_copy, sr, g_copy); } nyquist-3.05/nyqsrc/nfilterkit.c0000644000175000000620000001524410144436365016035 0ustar stevestaff/* * nfilterkit.c - windowed low-pass filter support. * adapted from filterkit.c, by Julius Smith et al., CCRMA, Stanford University * /* * FilterUp() - Applies a filter to a given sample when up-converting. * FilterUD() - Applies a filter to a given sample when up- or down- * converting. */ #include "soundstruct.h" #include "nresample.h" #include "nfilterkit.h" /* #include */ #include #include #include #include fast_float FilterUp(float Imp[], float ImpD[], UHWORD Nwing, BOOL Interp, float *Xp, double Ph, HWORD Inc) { float *Hp, *Hdp = NULL, *End; fast_float a = 0; fast_float v, t; double exact_index = Ph * Npc; long index = exact_index; /* convert fraction to filter index */ /* printf("FilterUp, Inc %d, phase %g\n", Inc, Ph); */ v=0; Hp = &Imp[index]; End = &Imp[Nwing]; if (Interp) { Hdp = &ImpD[index]; a = exact_index - index; /* printf("fraction %g\n", a); */ } if (Inc == 1) /* If doing right wing... */ { /* ...drop extra coeff, so when Ph is */ End--; /* 0.5, we don't do too many mult's */ if (Ph == 0) /* If the phase is zero... */ { /* ...then we've already skipped the */ printf("Ph == 0\n"); Hp += Npc; /* first sample, so we must also */ Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */ } } if (Interp) { while (Hp < End) { t = *Hp; /* Get filter coeff */ /* t scaled by 2^(16 + NLpScl)/LpScl */ /* printf("coeff %g ", t); */ t += *Hdp *a; /* t is now interp'd filter coeff */ /* printf("interp'd coeff %g ", t);*/ Hdp += Npc; /* Filter coeff differences step */ /* printf("input sample %g ", *Xp); */ t *= *Xp; /* Mult coeff by input sample */ /* t scaled by 2^(16 + NLpScl)/LpScl */ /* printf("product %g\n", t); */ v += t; /* The filter output */ Hp += Npc; /* Filter coeff step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ } } else { while (Hp < End) { t = *Hp; /* Get filter coeff */ t *= *Xp; /* Mult coeff by input sample */ v += t; /* The filter output */ Hp += Npc; /* Filter coeff step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ } } /* printf("FilterUp, Inc %d returns %g\n", Inc, v); */ return(v); } fast_float FilterUD( float Imp[], float ImpD[], UHWORD Nwing, BOOL Interp, float *Xp, double Ph, HWORD Inc, double dhb) { double a; float *Hp, *Hdp, *End; fast_float v, t; double Ho; v=0; Ho = Ph*dhb; End = &Imp[Nwing]; if (Inc == 1) /* If doing right wing... */ { /* ...drop extra coeff, so when Ph is */ End--; /* 0.5, we don't do too many mult's */ if (Ph == 0) /* If the phase is zero... */ Ho += dhb; /* ...then we've already skipped the */ } /* first sample, so we must also */ /* skip ahead in Imp[] and ImpD[] */ if (Interp) { long HoIndex = Ho; while ((Hp = &Imp[HoIndex]) < End) { t = *Hp; /* Get IR sample */ Hdp = &ImpD[HoIndex]; /* get interp (lower Na) bits from diff table*/ a = Ho - HoIndex; /* a is logically between 0 and 1 */ t += *Hdp * a; /* t is now interp'd filter coeff */ t *= *Xp; /* Mult coeff by input sample */ v += t; /* The filter output */ Ho += dhb; /* IR step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ HoIndex = Ho; } } else { long HoIndex = Ho; while ((Hp = &Imp[HoIndex]) < End) { t = *Hp; /* Get IR sample */ t *= *Xp; /* Mult coeff by input sample */ v += t; /* The filter output */ Ho += dhb; /* IR step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ HoIndex = Ho; } } return(v); } /* Sampling rate up-conversion only subroutine; * Slightly faster than down-conversion; */ static int SrcUp(float X[], float Y[], double factor, double *Time, UHWORD Nx, UHWORD Nwing, double LpScl, float Imp[], float ImpD[], BOOL Interp) { mem_float *Xp, *Ystart; fast_float v; double dt; /* Step through input signal */ double endTime; /* When Time reaches EndTime, return to user */ /* printf("SrcUp: interpFilt %d\n", Interp);*/ dt = 1.0/factor; /* Output sampling period */ Ystart = Y; endTime = *Time + Nx; while (*Time < endTime) { long iTime = *Time; Xp = &X[iTime]; /* Ptr to current input sample */ /* Perform left-wing inner product */ v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, *Time - iTime, -1); /* Perform right-wing inner product */ v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (1 + iTime) - *Time, 1); v *= LpScl; /* Normalize for unity filter gain */ /* printf("SrcUp output sample %g\n", v); */ *Y++ = v; *Time += dt; /* Move to next sample by time increment */ } return (Y - Ystart); /* Return the number of output samples */ } /* Sampling rate conversion subroutine */ static int SrcUD(float X[], float Y[], double factor, double *Time, UHWORD Nx, UHWORD Nwing, double LpScl, float Imp[], float ImpD[], BOOL Interp) { mem_float *Xp, *Ystart; fast_float v; double dh; /* Step through filter impulse response */ double dt; /* Step through input signal */ double endTime; /* When Time reaches EndTime, return to user */ dt = 1.0/factor; /* Output sampling period */ dh = MIN(Npc, factor*Npc); /* Filter sampling period */ Ystart = Y; endTime = *Time + Nx; while (*Time < endTime) { long iTime = *Time; Xp = &X[iTime]; /* Ptr to current input sample */ v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, *Time - iTime, -1, dh); /* Perform left-wing inner product */ v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (1 + iTime) - *Time, 1, dh); /* Perform right-wing inner product */ v *= LpScl; /* Normalize for unity filter gain */ *Y++ = v; *Time += dt; /* Move to next sample by time increment */ } return (Y - Ystart); /* Return the number of output samples */ } nyquist-3.05/nyqsrc/stats.c0000644000175000000620000000126110144436365015012 0ustar stevestaff/* * stats.c * * produce statistics. */ #include "switches.h" #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" void stats() { nyquist_printf("\n\nNyquist statistics:\n\n"); nyquist_printf("Memory usage:\n"); nyquist_printf("\tconsumed %d pools of size %d\n", npools, MAXPOOLSIZE); nyquist_printf("\tdata structure usage:\n"); nyquist_printf("\t\tsounds\t%d\n", sound_used); nyquist_printf("\t\tsnd lists\t%d\n", snd_list_used); nyquist_printf("\t\tsample blocks\t%d\n", sample_block_used); nyquist_printf("\t\ttable space in bytes\t%ld\n", table_memory); nyquist_printf("\n"); } nyquist-3.05/nyqsrc/debug.h0000644000175000000620000000224211466723256014755 0ustar stevestaff#ifndef DEBUG_H #ifdef PARTIAL_DECLARATIONS typedef struct partial_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; long logical_stop_cnt; boolean logically_stopped; sound_type env; long env_cnt; sample_block_values_type env_ptr; /* support for interpolation of env */ sample_type env_x1_sample; double env_pHaSe; double env_pHaSe_iNcR; /* support for ramp between samples of env */ double output_per_env; long env_n; long phase; long ph_incr; double max_diff; double prev_output; } partial_susp_node, *partial_susp_type; #endif extern sound_type watch_table_sound; extern int table_ptr_check_enable; void print_sound_type(sound_type s); void print_sample_block_type(char *label, sample_block_type sampblock, int len); void watch_susp(snd_susp_type s); void watch_sound(sound_type s); void snd_list_debug(snd_list_type snd_list, char *s); void watch_snd_list(snd_list_type s); void dbg_mem_allocated(void *p, char *who); void dbg_mem_freed(void *p, char *who); void dbg_mem_print(char *msg, void *p); void table_ptr_check(); /* #define TRACESNDGC */ #define DEBUG_H #endif nyquist-3.05/nyqsrc/downsample.c0000644000175000000620000003041110144436365016024 0ustar stevestaff/* downsample.c -- linear interpolation to a lower sample rate */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "downsample.h" void down_free(); typedef struct down_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; /* support for interpolation of s */ sample_type s_x1_sample; double s_pHaSe; double s_pHaSe_iNcR; /* support for ramp between samples of s */ double output_per_s; long s_n; } down_susp_node, *down_susp_type; void down_n_fetch(susp, snd_list) register down_susp_type susp; snd_list_type snd_list; { int cnt = 0; /* how many samples computed */ int togo = 0; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "down_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = MIN(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); if (to_stop < togo && ((togo = to_stop) == 0)) break; } n = togo; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *s_ptr_reg++; } while (--n); /* inner loop */ /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* down_n_fetch */ void down_s_fetch(susp, snd_list) register down_susp_type susp; snd_list_type snd_list; { int cnt = 0; /* how many samples computed */ int togo = 0; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type s_scale_reg = susp->s->scale; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "down_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); if (to_stop < togo && ((togo = to_stop) == 0)) break; } n = togo; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (s_scale_reg * *s_ptr_reg++); } while (--n); /* inner loop */ susp->s_ptr = s_ptr_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* down_s_fetch */ void down_i_fetch(susp, snd_list) register down_susp_type susp; snd_list_type snd_list; { int cnt = 0; /* how many samples computed */ sample_type s_x2_sample; int togo = 0; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type s_pHaSe_iNcR_rEg = (sample_type) susp->s_pHaSe_iNcR; register double s_pHaSe_ReG; register sample_type s_x1_sample_reg; falloc_sample_block(out, "down_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(s, s_ptr, s_cnt); susp->s_x1_sample = susp_fetch_sample(s, s_ptr, s_cnt); } susp_check_term_log_samples(s, s_ptr, s_cnt); s_x2_sample = susp_current_sample(s, s_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo <= 0) { togo = 0; break; } } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); if (to_stop < togo && ((togo = to_stop) <= 0)) { togo = 0; break; } } n = togo; s_pHaSe_ReG = susp->s_pHaSe; s_x1_sample_reg = susp->s_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ while (s_pHaSe_ReG >= 1.0) { s_x1_sample_reg = s_x2_sample; /* pick up next sample as s_x2_sample: */ susp->s_ptr++; susp_took(s_cnt, 1); s_pHaSe_ReG -= 1.0; /* derived from susp_check_term_log_samples_break, but with a goto instead of a break */ if (susp->s_cnt == 0) { susp_get_samples(s, s_ptr, s_cnt); terminate_test(s_ptr, s, susp->s_cnt); /* see if newly discovered logical stop time: */ logical_stop_test(s, susp->s_cnt); if ((susp->terminate_cnt != UNKNOWN && susp->terminate_cnt < susp->susp.current + cnt + togo) || (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && susp->susp.log_stop_cnt < susp->susp.current + cnt + togo)) { goto breakout; } } s_x2_sample = susp_current_sample(s, s_ptr); } *out_ptr_reg++ = (sample_type) (s_x1_sample_reg * (1 - s_pHaSe_ReG) + s_x2_sample * s_pHaSe_ReG); s_pHaSe_ReG += s_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ breakout: togo -= n; susp->s_pHaSe = s_pHaSe_ReG; susp->s_x1_sample = s_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* down_i_fetch */ void down_toss_fetch(snd_list) snd_list_type snd_list; { register down_susp_type susp = (down_susp_type) snd_list->u.susp; long final_count = MIN(susp->susp.current + max_sample_block_len, susp->susp.toss_cnt); time_type final_time = susp->susp.t0 + final_count / susp->susp.sr; long n; /* fetch samples from s up to final_time for this block of zeros */ while (((long) ((final_time - susp->s->t0) * susp->s->sr + 0.5)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ if (final_count == susp->susp.toss_cnt) { n = ROUND((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; } snd_list->block_len = (short) (final_count - susp->susp.current); susp->susp.current = final_count; snd_list->u.next = snd_list_create((snd_susp_type) susp); snd_list->block = internal_zero_block; } void down_mark(down_susp_type susp) { sound_xlmark(susp->s); } void down_free(down_susp_type susp) { sound_unref(susp->s); ffree_generic(susp, sizeof(down_susp_node), "down_free"); } void down_print_tree(down_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_down(sr, s) rate_type sr; sound_type s; { register down_susp_type susp; /* sr specified as input parameter */ time_type t0 = s->t0; sample_type scale_factor = 1.0F; time_type t0_min = t0; if (s->sr < sr) { sound_unref(s); xlfail("snd-down: output sample rate must be lower than input"); } falloc_generic(susp, down_susp_node, "snd_make_down"); /* select a susp fn based on sample rates */ if (s->sr == sr) { susp->susp.fetch = ((s->scale == 1.0) ? down_n_fetch : down_s_fetch); } else { susp->susp.fetch = down_i_fetch; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); /* minimum start time over all inputs: */ t0_min = MIN(s->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = ROUND((t0 - t0_min) * sr); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = down_toss_fetch; t0 = t0_min; } /* initialize susp state */ susp->susp.free = down_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = down_mark; susp->susp.print_tree = down_print_tree; susp->susp.name = "down"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->started = false; susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->s_pHaSe = 0.0; susp->s_pHaSe_iNcR = s->sr / sr; susp->s_n = 0; susp->output_per_s = sr / s->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_down(sr, s) rate_type sr; sound_type s; { sound_type s_copy = sound_copy(s); return snd_make_down(sr, s_copy); } nyquist-3.05/nyqsrc/phasevocoder.h0000644000175000000620000000035411466723256016353 0ustar stevestaff/* phasevocoder.h -- this is a stub showing how you might hook a phase vocoder into Nyquist using pvshell */ sound_type snd_phasevocoder(sound_type f, sound_type g, double x); /* LISP: (snd-phasevocoder SOUND SOUND ANYNUM) */ nyquist-3.05/nyqsrc/add.c0000644000175000000620000010441011512143043014370 0ustar stevestaff/* add.c -- add two signals */ /* CHANGE LOG * 19May92 rbd fix t0 to mean time rather than samples fix to logically stop and terminate at MAX of 2 inputs * 28Apr03 dm changes for portability and fix compiler warnings */ /* DOCUMENTATION: Most DSP modules in Nyquist select a single fetch routine and use it until the signal terminates. The ADD operation instead can use a number of different fetch routines in sequence. This allows ADD to do the most efficient computation, such as simply copying pointers when only one input signal is defined (the other is zero.) Here's what the functions assume and do: add_s1_s2_nn_fetch: both arguments (s1, s2) have signals; add them. add_s1_nn_fetch: only s1 is active, so pass along pointers if possible. Revert to add_s1_s2_nn_fetch when s2 becomes active. add_s2_nn_fetch: symetric with add_s1_nn_fetch. add_zero_fill_nn_fetch: fill in when one input has terminated and the other hasn't begun. An important optimization (we think) is the ability to collapse ADD operations. When one operand goes to zero, the ADD just passes along pointers to blocks from the other operand. In some cases, we can just splice out the ADD suspension and link directly to the suspension of the second operand. Doing this requires that there be no scale factors, so ADD does not deal with scaling. If an operand comes in with a scale factor, ADD will create a rescaling of the operand. */ #include "switches.h" #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "scale.h" #include "multiseq.h" #include "add.h" #include "assert.h" #define debugA 0 #define A if (debugA) /* I don't know how these debug switches (A and D) differ: */ #define D A /* switch B is/was to look for a particular zero block length bug */ #define debugB 0 #define B if (debugB | debugA) /* #define GC_DEBUG 1 */ void add_s1_s2_nn_fetch(add_susp_type, snd_list_type); void add_s1_nn_fetch(add_susp_type, snd_list_type); void add_s2_nn_fetch(add_susp_type, snd_list_type); void add_zero_fill_nn_fetch(add_susp_type, snd_list_type); void add_free(); void add_s1_s2_nn_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list; { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type s1_ptr_reg; register sample_block_values_type s2_ptr_reg; register sample_block_values_type out_ptr_reg; #ifdef GC_DEBUG snd_list_report(snd_list, "add_s1_s2_nn_fetch"); #endif /* assume the snd_list is the one with a null block */ /* put a fresh, clean block in the snd_list (get new snd_list later) */ falloc_sample_block(out, "add_s1_s2_nn_fetch"); snd_list->block = out; out_ptr = out->samples; A nyquist_printf("add[%p,%p] (s1_s2_nn) %p new block %p\n", susp->s1, susp->s2, susp, out); /* fill up the new block */ while (cnt < max_sample_block_len && susp->terminate_bits == 0) { A nyquist_printf("add[%p,%p] (s1_s2_nn) %p starting outer loop, cnt %d\n", susp->s1, susp->s2, susp, cnt); /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ A nyquist_printf("add[%p,%p]: look for samples (for s1) \n", susp->s1, susp->s2); /* if (!susp->s1->list->block) watch_susp(susp->s1->list->u.susp); */ susp_check_term_log_block_samples(s1, s1_bptr, s1_ptr, s1_cnt, 1, 3); A nyquist_printf("add[%p,%p]: found samples (for s1) s1_cnt=%d\n", susp->s1, susp->s2, (int)susp->s1_cnt); togo = MIN(togo, susp->s1_cnt); if (susp->terminate_bits & 1) { A nyquist_printf("add[%p,%p]: terminate bits on (for s1) togo=%d\n", susp->s1, susp->s2, togo); } /* don't run past the s2 input sample block: */ A nyquist_printf("add[%p,%p]: look for samples (for s2) \n", susp->s1, susp->s2); susp_check_term_log_block_samples(s2, s2_bptr, s2_ptr, s2_cnt, 2, 3); A nyquist_printf("add[%p,%p]: found samples (for s2) s2_cnt=%d\n", susp->s1, susp->s2, (int)susp->s2_cnt); togo = MIN(togo, susp->s2_cnt); A if (susp->terminate_bits & 2) { nyquist_printf("add[%p,%p]: terminate bits on (for s2) togo=%d\n", susp->s1, susp->s2, togo); } /* don't run past logical stop time (need to check this even * if a sound has terminated) */ A nyquist_printf( "add[%p,%p] (s1_s2_nn) %p: logically_stopped %d, logical_stop_cnt %d, s1 logical_stop_cnt %ld, s2 logical_stop_cnt %ld \n", susp->s1, susp->s2, susp, susp->logically_stopped, (int) susp->susp.log_stop_cnt, susp->s1->logical_stop_cnt, susp->s2->logical_stop_cnt); if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && (susp->logical_stop_bits == 3)) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); A nyquist_printf("add[%p,%p]: to_stop = %d\n", susp->s1, susp->s2, to_stop); /* logical stops have to be indicated on block boundaries */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; /* block is non-empty, log-stop on next block */ } else /* to_stop is 0, indicate logical stop immediately */ susp->logically_stopped = true; } else { /* logical stop will take place on the following block, * so compute up to logical stop and return partial block */ togo = to_stop; } } } /* check please */ if (susp->terminate_bits) { break; } /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); D nyquist_printf("add[%p,%p]: togo = %d\n", susp->s1, susp->s2, togo); if (togo == 0) break; } n = togo; A nyquist_printf("add[%p,%p] (s1_s2_nn) %p starting inner loop, n %d\n", susp->s1, susp->s2, susp, n); s1_ptr_reg = susp->s1_ptr; s2_ptr_reg = susp->s2_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ /* scale? */ A nyquist_printf("add_s1_s2_nn: %g + %g\n", *s1_ptr_reg, *s2_ptr_reg); *out_ptr_reg++ = *(s1_ptr_reg++) + *(s2_ptr_reg++); } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000 */ susp->s1_ptr += togo; /* using s2_ptr_reg is a bad idea on RS/6000 */ susp->s2_ptr += togo; /* using out_ptr_reg is a bad idea on RS/6000 */ out_ptr += togo; susp_took(s1_cnt, togo); susp_took(s2_cnt, togo); cnt += togo; } /* outer loop */ A nyquist_printf("add[%p,%p] (s1_s2_nn) %p ending outer loop, cnt %d\n", susp->s1, susp->s2, susp, cnt); snd_list->block_len = cnt; /* test for logical stop - normally this is detected by * susp.log_stop_cnt == susp->susp.current, but then the logical * stop flag is set on the NEXT block. To remember to set on the * NEXT block, set susp->logically_stopped, which is also tested * below. One special case is if the current block should indicate * logically stopped (this happens sometimes when the sounds have * zero logical length) then susp->logically_stopped will be set * (see above) and we just never test susp->susp.log_stop_cnt. */ if (susp->logically_stopped) { A nyquist_printf("add[%p,%p] (s1_s2_nn) %p->logically_stopped already true\n", susp->s1, susp->s2, susp); snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current && susp->logical_stop_bits == 3) { A nyquist_printf("add[%p,%p] (s1_s2_nn) %p->logically_stopped set to true\n", susp->s1, susp->s2, susp); susp->logically_stopped = true; } /* test for termination of s1 */ if (susp->terminate_bits == 3) { D nyquist_printf("add[%p,%p] (s1_s2_nn) s1 and s2 terminated, unrefed\n", susp->s1, susp->s2); /* free susp and point to terminal zeros (leaving pending snd_lists)*/ if (cnt) { /* we have samples, put zero_block at end */ snd_list_unref(snd_list->u.next); snd_list->u.next = zero_snd_list; } else { /* no samples generated */ snd_list_terminate(snd_list); } D nyquist_printf("add[%p,%p] (s1_s2_nn) %p terminated.\n", susp->s1, susp->s2, susp); } else { if (susp->terminate_bits & 1) { D nyquist_printf("add[%p,%p] (s1_s2_nn) s1 terminated, unrefed\n", susp->s1, susp->s2); sound_unref(susp->s1); susp->s1 = NULL; susp->susp.fetch = add_s2_nn_fetch; D nyquist_printf("add_s1_s2_nn_fetch: add_s2_nn_fetch installed\n"); if (cnt == 0) { D nyquist_printf("add[%p,%p]: calling add_s2_nn_fetch\n", susp->s1, susp->s2); add_s2_nn_fetch(susp, snd_list); } } else if (susp->terminate_bits & 2) { D nyquist_printf("add[%p,%p] (s1_s2_nn) s2 terminated, unrefed\n", susp->s1, susp->s2); sound_unref(susp->s2); susp->s2 = NULL; susp->susp.fetch = add_s1_nn_fetch; D stdputstr("add_s1_s2_nn_fetch: add_s1_nn_fetch installed\n"); if (cnt == 0) { D nyquist_printf("add[%p,%p]: calling add_s1_nn_fetch\n", susp->s1, susp->s2); add_s1_nn_fetch(susp, snd_list); } } /* add a new snd_list for the susp */ susp->susp.current += cnt; } } /* add_s1_s2_nn_fetch */ /* Note that add_s1_nn_fetch and add_s2_nn_fetch are symetric. * They should probably be made into one routine, but for now, * any changes to one should be made to the other. */ void add_s1_nn_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list; { /* expansion of add_s_nn_fetch(snd_list,s1,s2,1); follows: */ int togo, s2_start=0; int n; sample_block_type out; register sample_block_values_type out_ptr; D nyquist_printf("add_s1_nn_fetch(susp %p, snd_list %p, s1_cnt %d)\n", susp, snd_list, (int)susp->s1_cnt); #ifdef GC_DEBUG snd_list_report(snd_list, "add_s1_nn_fetch"); #endif /* * first compute how many samples to copy (or transfer) */ /* see what the next samples look like */ susp_check_term_log_block_samples(s1, s1_bptr, s1_ptr, s1_cnt, 1, 3); B if (susp->terminate_bits & 1) nyquist_printf("add[%p,%p]: s1 terminates\n", susp->s1, susp->s2); /* don't run past the s1 input sample block: */ togo = susp->s1_cnt; B if (togo == 0) stdputstr("togo is zero at checkpoint 1\n"); /* don't run past terminate time of this signal */ /* if (susp->s1_ptr == zero_block->samples) { -sep21 RBD*/ if (susp->terminate_bits & 1) { if (susp->s2) { s2_start = (long) ((susp->s2->t0 - susp->susp.t0) * susp->s2->sr + 0.5); D nyquist_printf("add_s_nn_fetch: s2_start %d\n", s2_start); } togo = 0; B if (togo == 0) stdputstr("togo is zero at checkpoint 2\n"); if (susp->s2 && susp->susp.current == s2_start) { /* s2 starting and s1 stops */ /* go to s2 alone state */ sound_unref(susp->s1); susp->s1 = NULL; susp->susp.fetch = add_s2_nn_fetch; D stdputstr("add_s_nn_fetch: other installed, calling now...\n"); add_s2_nn_fetch(susp, snd_list); } else if (susp->s2 && susp->susp.current < s2_start) { /* s2 not started and s1 stops */ /* go to zero-fill state */ sound_unref(susp->s1); susp->s1 = NULL; susp->susp.fetch = add_zero_fill_nn_fetch; B stdputstr("add_s_nn_fetch: zero_fill installed\n"); add_zero_fill_nn_fetch(susp, snd_list); } else if (susp->s2) { D stdputstr("add_s_nn_fetch: unexpected condition\n"); EXIT(1); } else /* no s2 */ { snd_list_terminate(snd_list); } D nyquist_printf("add_s_nn_fetch: special return, susp %p\n", susp); return; /* fetching taken care of by another routine */ } /* if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + togo) { togo = susp->terminate_cnt - susp->susp.current; } */ /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && susp->logical_stop_bits == 3) { int to_stop = susp->susp.log_stop_cnt - susp->susp.current; if (to_stop < togo) { if (to_stop == 0) { susp->logically_stopped = true; } else togo = to_stop; } B if (togo == 0) stdputstr("togo is zero at checkpoint 3\n"); D nyquist_printf("add_s1_nn_fetch: to_stop %d togo %d\n", to_stop, togo); } /* consider other signal? don't run past its start time... */ if (susp->s2) { s2_start = ROUND((susp->s2->t0 - susp->susp.t0) * susp->s2->sr); if (s2_start < susp->susp.current + togo) togo = MIN(togo, s2_start - susp->susp.current); B if (togo == 0) stdputstr("togo is zero at checkpoint 4\n"); } /* * two cases: copy a partial block or manipulate pointers for * copyless transfer of whole block (may not be full block): * * copy partial block when: * o samples begin in middle of block * o stopping time is before end of block (when other signal * splits the block for this signal) * transfer (copyless) block when: * o the block is of maximum size * o the block is small due to logical stop time or termination * time */ if (susp->s1_ptr == susp->s1_bptr->samples && susp->s1_cnt == togo) { /* * we want to copy this whole block (starting at the beginning * and going to the rest of the block) -- just do pointers. */ /* just fetch and pass blocks on */ if (0) nyquist_printf("add[%p,%p] (s%d_nn) %p starting uncopy, togo %d\n", susp->s1, susp->s2, 1, susp, togo); snd_list->block = susp->s1_bptr; (susp->s1_bptr->refcnt)++; if (0) nyquist_printf("add[%p,%p] (s%d_nn) %p shared block %p zero_block %p\n",susp->s1, susp->s2, 1, susp, susp->s1_bptr, zero_block); susp_took(s1_cnt, togo); snd_list->block_len = togo; /* if other is terminated and sound_types match, collapse */ /* NOTE: in order to collapse, we need s2 to be generating * blocks and linking them onto a sound list. This is true * when the get_next fn is SND_get_next. (A counterexample is * SND_get_zeros, which returns zero blocks but does not link * them onto the sound list. */ if (0) nyquist_printf("s2 %p thissr %g suspsr %g get_next %d lsc %d\n", susp->s2, susp->s1->sr, susp->susp.sr, susp->s1->get_next == SND_get_next, susp->s1->logical_stop_cnt == UNKNOWN); if (susp->s2 == NULL && susp->s1->sr == susp->susp.sr && susp->s1->get_next == SND_get_next && susp->s1->logical_stop_cnt == UNKNOWN) { snd_list_type addend_list; D nyquist_printf("add[%p,%p]: collapsing! LSC %d\n", susp->s1, susp->s2, (int)susp->s1->logical_stop_cnt); D sound_print_tree(susp->s1); /* will "current" values match? */ /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } /* free the superfluous sound_type and susp */ addend_list = susp->s1->list->u.next; snd_list_ref(addend_list); snd_list_unref(snd_list->u.next); snd_list->u.next = addend_list; return; } } else { /* * we want to copy a partial block */ /* assume the snd_list is the one with a null block */ /* * put a fresh, clean block in the snd_list * (get new snd_list later) */ falloc_sample_block(out, "add_s1_nn_fetch"); snd_list->block = out; out_ptr = out->samples; B nyquist_printf("add[%p,%p] (s1_nn) %p new block %p, s1_ptr %p block %p s1_cnt %d togo %d\n", susp->s1, susp->s2, susp, out, susp->s1_ptr, susp->s1_bptr->samples, (int)susp->s1_cnt, togo); n = togo; B if (togo == 0) stdputstr("togo is zero at checkpoint 5\n"); B if (togo == 0) nyquist_printf( "add[%p,%p] (s%d_nn) %p starting copy loop, togo %d\n", susp->s1, susp->s2, 1, susp, togo); while (n--) { /* the inner sample computation loop */ /* scale? */ *out_ptr++ = *(susp->s1_ptr++); } /* inner loop */ susp_took(s1_cnt, togo); snd_list->block_len = togo; } /* add a new snd_list for the susp */ susp->susp.current += togo; D stdputstr("testing..."); /* * test for termination or change of state, * note s2_start computed earlier */ if (susp->s2 && susp->susp.current == s2_start && susp->s1->list != zero_snd_list) { /* s2 starting and s1 continues */ /* go to s1+s2 state */ susp->susp.fetch = add_s1_s2_nn_fetch; D stdputstr("add_s_nn_fetch: add_s1_s2_fetch installed\n"); } else if (susp->terminate_bits == 3) { /* s2 finished and s1 stops */ /* go to terminal state */ susp->s1 = NULL; D nyquist_printf("add_s_nn_fetch: go to terminal state. susp->s2 %p, \ susp->susp.current %d, s2_start %d, susp->s1->list %p, \ zero_snd_list %p\n", susp->s2, (int)susp->susp.current, s2_start, susp->s1->list, zero_snd_list); /* !!! free resources and set up pointers to terminal snd_list */ /* !!! logically stopped? */ } /* test for logical stop */ if (susp->logically_stopped) { D stdputstr("add_s_nn_fetch: snd_list->logically_stopped\n"); snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current && susp->logical_stop_bits == 3) { D stdputstr("add_s_nn_fetch: susp->logically_stopped\n"); susp->logically_stopped = true; } D { if (susp->logically_stopped || snd_list->logically_stopped) stdputstr("STOPPED\n"); else nyquist_printf("ok: current %d\n", (int)susp->susp.current); } } void add_s2_nn_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list; { int togo, s1_start=0; int n; sample_block_type out; register sample_block_values_type out_ptr; D nyquist_printf("add_s2_nn_fetch(susp %p, snd_list %p)\n", susp, snd_list); #ifdef GC_DEBUG snd_list_report(snd_list, "add_s2_nn_fetch"); #endif /* * first compute how many samples to copy (or transfer) */ /* see what the next samples look like */ susp_check_term_log_block_samples(s2, s2_bptr, s2_ptr, s2_cnt, 2, 3); /* don't run past the s2 input sample block: */ togo = susp->s2_cnt; assert(togo > 0); /* don't run past terminate time of this signal */ /* if (susp->s2_ptr == zero_block->samples) { -sep21 RBD*/ if (susp->terminate_bits & 2) { if (susp->s1) { s1_start = ROUND((susp->s1->t0 - susp->susp.t0) * susp->s1->sr); if (0) nyquist_printf("add_s_nn_fetch: s1_start %d\n", s1_start); } togo = 0; if (susp->s1 && susp->susp.current == s1_start) { /* s1 starting and s2 stops */ /* go to s1 alone state */ sound_unref(susp->s2); susp->s2 = NULL; susp->susp.fetch = add_s1_nn_fetch; D stdputstr("add_s_nn_fetch: other installed, calling now...\n"); add_s1_nn_fetch(susp, snd_list); } else if (susp->s1 && susp->susp.current < s1_start) { /* s1 not started and s2 stops */ /* go to zero-fill state */ sound_unref(susp->s2); susp->s2 = NULL; susp->susp.fetch = add_zero_fill_nn_fetch; D stdputstr("add_s_nn_fetch: zero_fill installed\n"); add_zero_fill_nn_fetch(susp, snd_list); } else if (susp->s1) { D stdputstr("add_s_nn_fetch: unexpected condition\n"); EXIT(1); } else /* no s1 */ { snd_list_terminate(snd_list); } D nyquist_printf("add_s_nn_fetch: special return, susp %p\n", susp); return; /* fetching taken care of by another routine */ } /* if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + togo) { togo = susp->terminate_cnt - susp->susp.current; } */ /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && /* check if we've seen the logical stop from s2. If so then log_stop_cnt is max of s1 and s2 stop times */ (susp->logical_stop_bits & 2)) { int to_stop; D nyquist_printf("add_s2_nn_fetch: susp->susp.log_stop_cnt %d\n", susp->susp.log_stop_cnt); D nyquist_printf("add_s2_nn_fetch: susp->susp.current %d\n", susp->susp.current); to_stop = susp->susp.log_stop_cnt - susp->susp.current; // to_stop can be less than zero if we've been adding in sounds with // t0 less than the time when the sound is added. E.g. if the user // wants a sequence of two sounds that start at 0, the second sound // will be spliced onto the first because we don't look at it until // the first finishes -- we cannot go back in time and start adding // from time 0. This creates a mismatch between the sample count and // the logical time, so we could actually set a logical stop time that // is back in history, and therefore before susp.current, resulting // in a negative to_stop. The problem is really with trying to // sequence two sounds rather than two behaviors, and a warning has // already been issued, so we'll just try not to crash here. It's too // late to compute the correct answer, which would respect t0 of both // sounds. if (to_stop < 0) to_stop = 0; if (to_stop < togo) { if (to_stop == 0) { susp->logically_stopped = true; } else togo = to_stop; } B if (togo == 0) stdputstr("togo is zero at checkpoint 3\n"); D nyquist_printf("add_s2_nn_fetch: to_stop %d togo %d\n", to_stop, togo); } /* consider other signal? don't run past its start time... */ if (susp->s1) { s1_start = ROUND((susp->s1->t0 - susp->susp.t0) * susp->s1->sr); if (s1_start < susp->susp.current + togo) togo = MIN(togo, s1_start - susp->susp.current); assert(togo > 0); } /* * two cases: copy a partial block or manipulate pointers for * copyless transfer of whole block (may not be full block): * * copy partial block when: * o samples begin in middle of block * o stopping time is before end of block (when other signal * splits the block for this signal) * transfer (copyless) block when: * o the block is of maximum size * o the block is small due to logical stop time or termination * time */ if (susp->s2_ptr == susp->s2_bptr->samples && susp->s2_cnt == togo) { /* * we want to copy this whole block (starting at the beginning * and going to the rest of the block) -- just do pointers. */ /* just fetch and pass blocks on */ D nyquist_printf("add[%p,%p] (s%d_nn) %p starting uncopy, togo %d\n", susp->s2, susp->s1, 2, susp, togo); snd_list->block = susp->s2_bptr; (susp->s2_bptr->refcnt)++; D nyquist_printf("add[%p,%p] (s%d_nn) %p shared block %p zero_block %p\n",susp->s2, susp->s1, 2, susp, susp->s2_bptr, zero_block); susp_took(s2_cnt, togo); snd_list->block_len = togo; /* if other is terminated and sound_types match, collapse */ /* NOTE: in order to collapse, we need s1 to be generating * blocks and linking them onto a sound list. This is true * when the get_next fn is SND_get_next. (A counterexample is * SND_get_zeros, which returns zero blocks but does not link * them onto the sound list. */ if (0) nyquist_printf("s1 %p thissr %g suspsr %g get_next %d lsc %d\n", susp->s1, susp->s2->sr, susp->susp.sr, susp->s2->get_next == SND_get_next, susp->s2->logical_stop_cnt == UNKNOWN); if (susp->s1 == NULL && susp->s2->sr == susp->susp.sr && susp->s2->get_next == SND_get_next && susp->s2->logical_stop_cnt == UNKNOWN) { snd_list_type addend_list; D nyquist_printf("add[%p,%p]: collapsing! LSC %d\n", susp->s2, susp->s1, (int)susp->s2->logical_stop_cnt); D sound_print_tree(susp->s2); /* will "current" values match? */ /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } /* free the superfluous sound_type and susp */ addend_list = susp->s2->list->u.next; snd_list_ref(addend_list); snd_list_unref(snd_list->u.next); snd_list->u.next = addend_list; return; } } else { /* * we want to copy a partial block */ /* assume the snd_list is the one with a null block */ /* * put a fresh, clean block in the snd_list * (get new snd_list later) */ falloc_sample_block(out, "add_s2_nn_fetch"); snd_list->block = out; out_ptr = out->samples; B nyquist_printf("add[%p,%p] (s2_nn) %p new block %p\n", susp->s2, susp->s1, susp, out); n = togo; if (n == 0) stdputstr("zero block length error in add_s2_nn_fetch\n"); assert(n > 0); B nyquist_printf( "add[%p,%p] (s2_nn) %p starting copy loop, togo %d\n", susp->s2, susp->s1, susp, togo); while (n--) { /* the inner sample computation loop */ /* scale? */ *out_ptr++ = *(susp->s2_ptr++); } /* inner loop */ susp_took(s2_cnt, togo); snd_list->block_len = togo; } /* add a new snd_list for the susp */ susp->susp.current += togo; if (0) stdputstr("testing..."); /* * test for termination or change of state, * note s1_start computed earlier */ if (susp->s1 && susp->susp.current == s1_start && susp->s2->list != zero_snd_list) { /* s1 starting and s2 continues */ /* go to s1+s2 state */ susp->susp.fetch = add_s1_s2_nn_fetch; D stdputstr("add_s_nn_fetch: add_s1_s2_fetch installed\n"); } /* else if (!susp->s1 && susp->s2->list == zero_snd_list) { */ else if (susp->terminate_bits == 3) { /* s1 finished and s2 stops */ /* go to terminal state */ susp->s2 = NULL; D nyquist_printf("add_s_nn_fetch: go to terminal state. susp->s1 %p, \ susp->susp.current %d, s1_start %d, susp->s2->list %p, \ zero_snd_list %p\n", susp->s1, (int)susp->susp.current, s1_start, susp->s2->list, zero_snd_list); /* !!! free resources and set up pointers to terminal snd_list */ /* !!! logically stopped? */ } /* test for logical stop */ if (susp->logically_stopped) { D stdputstr("add_s_nn_fetch: snd_list->logically_stopped\n"); snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current && (susp->logical_stop_bits & 2)) { D stdputstr("add_s_nn_fetch: susp->logically_stopped\n"); susp->logically_stopped = true; } if (0) { if (susp->logically_stopped || snd_list->logically_stopped) stdputstr("STOPPED\n"); else nyquist_printf("ok: current %d\n", (int)susp->susp.current); } } void add_zero_fill_nn_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list; { int togo, s_start=0; #ifdef GC_DEBUG snd_list_report(snd_list, "add_zero_fill_nn_fetch"); #endif togo = max_sample_block_len; if (0) fprintf(STDERR, "add_zero_fill_nn_fetch, susp.current %d\n", (int)susp->susp.current); /* don't run past start time ... */ if (susp->s1) { s_start = ROUND((susp->s1->t0 - susp->susp.t0) * susp->s1->sr); if (s_start < susp->susp.current + togo) { togo = s_start - susp->susp.current; } } else if (susp->s2) { s_start = ROUND((susp->s2->t0 - susp->susp.t0) * susp->s2->sr); if (s_start < susp->susp.current + togo) { togo = s_start - susp->susp.current; } } snd_list->block_len = togo; susp->susp.current += togo; /* * test for change of state, * note s_start computed earlier */ if (susp->s1 && susp->susp.current == s_start) { /* s1 starting, go to s1 state */ susp->susp.fetch = add_s1_nn_fetch; D stdputstr("add_zero_fill_nn_fetch: add_s1_nn_fetch installed\n"); } else if (susp->s2 && susp->susp.current == s_start) { /* s2 starting, go to s2 state */ susp->susp.fetch = add_s2_nn_fetch; D stdputstr("add_zero_fill_nn_fetch: add_s2_nn_fetch installed\n"); } } /* add_zero_fill_nn_fetch */ void add_free(add_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->s2); ffree_generic(susp, sizeof(add_susp_node), "add_free"); } void add_mark(add_susp_type susp) { /* nyquist_printf("add_mark(%p)\n", susp);*/ /* nyquist_printf("marking s1@%p in add@%p\n", susp->s1, susp);*/ sound_xlmark(susp->s1); /* nyquist_printf("marking s2@%p in add@%p\n", susp->s2, susp);*/ sound_xlmark(susp->s2); } void add_print_tree(add_susp_type susp, int n) { indent(n); nyquist_printf("logically_stopped %d logical_stop_bits %d terminate_bits %d\n", susp->logically_stopped, susp->logical_stop_bits, susp->terminate_bits); indent(n); stdputstr("s1:"); if (susp->s1) sound_print_tree_1(susp->s1, n); else stdputstr(" NULL\n"); indent(n); stdputstr("s2:"); if (susp->s2) sound_print_tree_1(susp->s2, n); else stdputstr(" NULL\n"); } sound_type snd_make_add(s1, s2) sound_type s1; sound_type s2; { register add_susp_type susp; rate_type sr = MAX(s1->sr, s2->sr); time_type t0 = MIN(s1->t0, s2->t0); int interp_desc = 0; double sample_offset; /* sort commutative signals: (S1 S2) */ snd_sort_2(&s1, &s2, sr); falloc_generic(susp, add_susp_node, "snd_make_add"); /* select a susp fn based on sample rates */ interp_desc = (interp_style(s1, sr) << 2) + interp_style(s2, sr); switch (interp_desc) { case INTERP_nn: case INTERP_ns: case INTERP_ss: /* eliminate scale factor on s1 if any */ if (((interp_desc >> INTERP_SHIFT) & INTERP_MASK) == INTERP_s) { /* stdputstr("add: prescaling s1\n");*/ s1 = snd_make_normalize(s1); } /* eliminate scale factor on s2 if any */ if ((interp_desc & INTERP_MASK) == INTERP_s) { /* stdputstr("add: prescaling s2\n"); */ s2 = snd_make_normalize(s2); } sample_offset = (s2->t0 - s1->t0) * sr; if (sample_offset >= 0.5) { /* s1 starts first */ susp->susp.fetch = add_s1_nn_fetch; D stdputstr("snd_make_add: add_s1_nn_fetch installed\n"); } else if (sample_offset < -0.5) { /* s2 starts first */ susp->susp.fetch = add_s2_nn_fetch; D stdputstr("snd_make_add: add_s2_nn_fetch installed\n"); } else { /* equal start times */ susp->susp.fetch = add_s1_s2_nn_fetch; D stdputstr("snd_make_add: add_s1_s2_nn_fetch installed\n"); } break; case INTERP_ni: case INTERP_nr: errputstr("add: can't interpolate!\n"); EXIT(1); default: errputstr("add: can't add these operands!\n"); EXIT(1); } susp->terminate_cnt = UNKNOWN; susp->terminate_bits = 0; /* bits for s1 and s2 termination */ susp->logical_stop_bits = 0; /* bits for s1 and s2 logical stop */ /* initialize susp state */ susp->susp.free = add_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = add_mark; susp->susp.print_tree = add_print_tree; susp->susp.name = "add"; susp->logically_stopped = false; susp->susp.log_stop_cnt = UNKNOWN; susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->s2 = s2; susp->s2_cnt = 0; #ifdef UPSAMPLECODE susp->susp.s2_phase = 0.0; susp->susp.s2_phase_incr = s2->sr / sr; susp->susp.output_per_s2 = sr / s2->sr; #endif return sound_create((snd_susp_type)susp, t0, sr, 1.0); } sound_type snd_add(s1, s2, t0) sound_type s1; sound_type s2; time_type t0; { sound_type s1_copy = sound_copy(s1); sound_type s2_copy = sound_copy(s2); /* nyquist_printf("snd_add %p %p copied to %p %p\n", s1, s2, s1_copy, s2_copy); */ return snd_make_add(s1_copy, s2_copy, t0); } nyquist-3.05/nyqsrc/sndread.c0000644000175000000620000002421011466723256015301 0ustar stevestaff/* sndread.c -- read sound files */ /* CHANGELOG * * 29Jun95 RBD ULAW fixed problems with signed chars * 28Apr03 dm explicitly declare sndread_file_open_count as int * 24Jul08 RBD & Judy Hawkins -- replace snd with PortAudio and libsndfile */ #include "switches.h" #include "stdio.h" #include "string.h" #ifdef UNIX #include "sys/file.h" #else /* #include */ #ifdef WINDOWS #include #include "io.h" #else #include #endif #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define PROTECTION #endif #ifndef mips #include "stdlib.h" #endif #include "sndfile.h" #include "xlisp.h" #include "sound.h" #include "sndfmt.h" #include "falloc.h" #include "sndread.h" #include "multiread.h" /* file.h doesn't define O_RDONLY under RS6K AIX */ #ifndef O_RDONLY #define O_RDONLY 0 #endif static int sndread_file_open_count = 0; void read__fetch(susp, snd_list) register read_susp_type susp; snd_list_type snd_list; { long n; /* jlh Changed type to long, trying to make move_samples_... work */ sample_block_type out; register sample_block_values_type out_ptr; /* allow up to 4 bytes/sample: jlh -- does this need to be 8? */ /* FIX -- why 8? for doubles? Maybe it should be sizeof(sample). I think this buffer was here to allow you to input any format and convert to float. The assumption was no sample would be longer than 4 bytes and after conversion, samples would be 4 byte floats. */ long in_count; /* jlh Trying to make move_samples_... work */ falloc_sample_block(out, "read__fetch"); out_ptr = out->samples; snd_list->block = out; in_count = sf_readf_float(susp->sndfile, out_ptr, max_sample_block_len); n = in_count; /* don't read too many */ if (n > (susp->cnt - susp->susp.current)) { n = susp->cnt - susp->susp.current; } snd_list->block_len = n; susp->susp.current += n; if (n == 0) { /* we didn't read anything, but can't return length zero, so convert snd_list to pointer to zero block */ snd_list_terminate(snd_list); } else if (n < max_sample_block_len) { /* this should close file and free susp */ snd_list_unref(snd_list->u.next); /* if something is in buffer, terminate by pointing to zero block */ snd_list->u.next = zero_snd_list; } } /* read__fetch */ void read_free(read_susp_type susp) { sf_close(susp->sndfile); sndread_file_open_count--; ffree_generic(susp, sizeof(read_susp_node), "read_free"); } void read_print_tree(read_susp_type susp, int n) { } LVAL snd_make_read( unsigned char *filename, /* file to read */ time_type offset, /* offset to skip (in seconds) */ time_type t0, /* start time of resulting sound */ long *format, /* AIFF, IRCAM, NeXT, etc. */ long *channels, /* number of channels */ long *mode, /* sample format: PCM, ALAW, etc. */ long *bits, /* BPS: bits per sample */ long *swap, /* swap bytes */ double *srate, /* srate: sample rate */ double *dur, /* duration (in seconds) to read */ long *flags, /* which parameters have been set */ long *byte_offset) /* byte offset in file of first sample */ { register read_susp_type susp; /* srate specified as input parameter */ sample_type scale_factor = 1.0F; sf_count_t frames; double actual_dur; falloc_generic(susp, read_susp_node, "snd_make_read"); memset(&(susp->sf_info), 0, sizeof(SF_INFO)); susp->sf_info.samplerate = ROUND(*srate); susp->sf_info.channels = *channels; switch (*mode) { case SND_MODE_ADPCM: susp->sf_info.format = SF_FORMAT_IMA_ADPCM; break; case SND_MODE_PCM: if (*bits == 8) susp->sf_info.format = SF_FORMAT_PCM_S8; else if (*bits == 16) susp->sf_info.format = SF_FORMAT_PCM_16; else if (*bits == 24) susp->sf_info.format = SF_FORMAT_PCM_24; else if (*bits == 32) susp->sf_info.format = SF_FORMAT_PCM_32; else { susp->sf_info.format = SF_FORMAT_PCM_16; *bits = 16; } break; case SND_MODE_ULAW: susp->sf_info.format = SF_FORMAT_ULAW; break; case SND_MODE_ALAW: susp->sf_info.format = SF_FORMAT_ALAW; break; case SND_MODE_FLOAT: susp->sf_info.format = SF_FORMAT_FLOAT; break; case SND_MODE_UPCM: susp->sf_info.format = SF_FORMAT_PCM_U8; *bits = 8; break; } if (*format == SND_HEAD_RAW) susp->sf_info.format |= SF_FORMAT_RAW; if (*swap) { /* set format to perform a byte swap (change from cpu endian-ness) */ /* write the code so it will only compile if one and only one ENDIAN setting is defined */ #ifdef XL_LITTLE_ENDIAN long format = SF_ENDIAN_BIG; #endif #ifdef XL_BIG_ENDIAN long format = SF_ENDIAN_LITTLE; #endif susp->sf_info.format |= format; } susp->sndfile = sf_open((const char *) filename, SFM_READ, &(susp->sf_info)); if (!susp->sndfile) { char error[240]; sprintf(error, "SND-READ: Cannot open file '%s'", filename); xlfail(error); } if (susp->sf_info.channels < 1) { sf_close(susp->sndfile); xlfail("Must specify 1 or more channels"); } /* report samplerate from file, but if user provided a double * as sample rate, don't replace it with an integer. */ if ((susp->sf_info.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) { *srate = susp->sf_info.samplerate; } /* compute dur */ frames = sf_seek(susp->sndfile, 0, SEEK_END); actual_dur = ((double) frames) / *srate; if (offset < 0) offset = 0; /* round offset to an integer frame count */ frames = (sf_count_t) (offset * *srate + 0.5); offset = ((double) frames) / *srate; actual_dur -= offset; if (actual_dur < 0) { sf_close(susp->sndfile); xlfail("SND-READ: offset is beyond end of file"); } if (actual_dur < *dur) *dur = actual_dur; sf_seek(susp->sndfile, frames, SEEK_SET); /* return to read loc in file */ /* initialize susp state */ susp->susp.sr = *srate; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = read_print_tree; /*jlh empty function... */ susp->susp.current = 0; susp->susp.log_stop_cnt = UNKNOWN; /* watch for overflow */ if (*dur * *srate + 0.5 > (unsigned long) 0xFFFFFFFF) { susp->cnt = 0x7FFFFFFF; } else { susp->cnt = ROUND((*dur) * *srate); } switch (susp->sf_info.format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV: *format = SND_HEAD_WAVE; break; case SF_FORMAT_AIFF: *format = SND_HEAD_AIFF; break; case SF_FORMAT_AU: *format = SND_HEAD_NEXT; break; case SF_FORMAT_RAW: *format = SND_HEAD_RAW; break; case SF_FORMAT_PAF: *format = SND_HEAD_PAF; break; case SF_FORMAT_SVX: *format = SND_HEAD_SVX; break; case SF_FORMAT_NIST: *format = SND_HEAD_NIST; break; case SF_FORMAT_VOC: *format = SND_HEAD_VOC; break; case SF_FORMAT_W64: *format = SND_HEAD_W64; break; case SF_FORMAT_MAT4: *format = SND_HEAD_MAT4; break; case SF_FORMAT_MAT5: *format = SND_HEAD_MAT5; break; case SF_FORMAT_PVF: *format = SND_HEAD_PVF; break; case SF_FORMAT_XI: *format = SND_HEAD_XI; break; case SF_FORMAT_HTK: *mode = SND_HEAD_HTK; break; case SF_FORMAT_SDS: *mode = SND_HEAD_SDS; break; case SF_FORMAT_AVR: *mode = SND_HEAD_AVR; break; case SF_FORMAT_WAVEX: *format = SND_HEAD_WAVE; break; case SF_FORMAT_SD2: *format = SND_HEAD_SD2; break; case SF_FORMAT_FLAC: *format = SND_HEAD_FLAC; break; case SF_FORMAT_CAF: *format = SND_HEAD_CAF; break; default: *format = SND_HEAD_NONE; break; } *channels = susp->sf_info.channels; switch (susp->sf_info.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_S8: *bits = 8; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_16: *bits = 16; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_24: *bits = 24; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_32: *bits = 32; *mode = SND_MODE_PCM; break; case SF_FORMAT_PCM_U8: *bits = 8; *mode = SND_MODE_UPCM; break; case SF_FORMAT_FLOAT: *bits = 32; *mode = SND_MODE_FLOAT; break; case SF_FORMAT_DOUBLE: *bits = 64; *mode = SND_MODE_DOUBLE; break; case SF_FORMAT_ULAW: *bits = 8; *mode = SND_MODE_ULAW; break; case SF_FORMAT_ALAW: *bits = 8; *mode = SND_MODE_ALAW; break; case SF_FORMAT_IMA_ADPCM: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_MS_ADPCM: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_GSM610: *bits = 16; *mode = SND_MODE_GSM610; break; case SF_FORMAT_VOX_ADPCM: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_G721_32: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_G723_24: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_G723_40: *bits = 16; *mode = SND_MODE_ADPCM; break; case SF_FORMAT_DWVW_12: *bits = 12; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DWVW_16: *bits = 16; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DWVW_24: *bits = 24; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DWVW_N: *bits = 32; *mode = SND_MODE_DWVW; break; case SF_FORMAT_DPCM_8: *bits = 8; *mode = SND_MODE_DPCM; break; case SF_FORMAT_DPCM_16: *bits = 16; *mode = SND_MODE_DPCM; break; default: *mode = SND_MODE_UNKNOWN; break; } sndread_file_open_count++; #ifdef MACINTOSH if (sndread_file_open_count > 24) { nyquist_printf("Warning: more than 24 sound files are now open\n"); } #endif /* report info back to caller */ if ((susp->sf_info.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) { *flags = SND_HEAD_CHANNELS | SND_HEAD_MODE | SND_HEAD_BITS | SND_HEAD_SRATE | SND_HEAD_LEN | SND_HEAD_TYPE; } if (susp->sf_info.channels == 1) { susp->susp.fetch = read__fetch; susp->susp.free = read_free; susp->susp.name = "read"; return cvsound(sound_create((snd_susp_type)susp, t0, *srate, scale_factor)); } else { susp->susp.fetch = multiread_fetch; susp->susp.free = multiread_free; susp->susp.name = "multiread"; return multiread_create(susp); } } nyquist-3.05/nyqsrc/sndseq.c0000644000175000000620000002634511466723256015171 0ustar stevestaff/* sndseq.c -- return a signal until its logical stop, then evaluate a closure to get a signal and convert to an add of two signals */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "scale.h" #include "add.h" #include "extern.h" #include "cext.h" #include "assert.h" #define SNDSEQDBG 0 #define D if (SNDSEQDBG) /* Note: this structure is identical to an add_susp structure up to the field output_per_s2 so that we can convert this into an add after eval'ing the closure. Since this struct is bigger than an add, make sure not to clobber the "free" routine (sndseq_free) or else we'll leak memory. */ typedef struct sndseq_susp_struct { snd_susp_node susp; boolean started; int terminate_bits; long terminate_cnt; int logical_stop_bits; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_type s1_bptr; /* block pointer */ sample_block_values_type s1_ptr; sound_type s2; long s2_cnt; sample_block_type s2_bptr; /* block pointer */ sample_block_values_type s2_ptr; /* support for interpolation of s2 */ sample_type s2_x1_sample; double s2_phase; double s2_phase_incr; /* support for ramp between samples of s2 */ double output_per_s2; /* sndseq-specific data starts here */ LVAL closure; } sndseq_susp_node, *sndseq_susp_type; void sndseq_fetch(sndseq_susp_type, snd_list_type); void sndseq_zero_fill_fetch(sndseq_susp_type, snd_list_type); void sndseq_free(); extern LVAL s_stdout; void sndseq_mark(sndseq_susp_type susp) { /* nyquist_printf("sndseq_mark(%x)\n", susp);*/ /* nyquist_printf("marking s1@%x in sndseq@%x\n", susp->s1, susp); */ sound_xlmark(susp->s1); if (susp->closure) mark(susp->closure); } /* sndseq_fetch returns blocks of s1 until the logical stop time of s1 */ /**/ void sndseq_fetch(susp, snd_list) register sndseq_susp_type susp; snd_list_type snd_list; { int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; /* nyquist_printf("sndseq_fetch called: s1_cnt %d\n", susp->s1_cnt); */ /* * first compute how many samples to copy (or transfer) */ /* get next samples; in add, the call is: * susp_check_term_log_block_samples(s1, s1_bptr, s1_ptr, s1_cnt, 1, 3); * * the plan here is tricky: if s1 has logically stopped, then evaluate * the closure to get signal s2. Then convert sndseq into an add. */ if (susp->s1_cnt == 0) { susp_get_block_samples(s1, s1_bptr, s1_ptr, s1_cnt); if (susp->s1_ptr == zero_block->samples) { susp->terminate_bits = 1; /* mark s1 as terminated */ } /* nyquist_printf("sndseq_fetch: s1-lsc %d, current %d cnt %d\n", susp->s1->logical_stop_cnt, susp->s1->current, susp->s1_cnt); */ } if (susp->s1->logical_stop_cnt != UNKNOWN && susp->s1->logical_stop_cnt == susp->s1->current - susp->s1_cnt) { time_type now = susp->susp.t0 + susp->susp.current / susp->susp.sr; /* note: cons args are protected from GC: */ LVAL result; long delay; /* sample delay to s2 */ /* stats();gc();stats();*/ xlsave1(result); D nyquist_printf("sndseq_fetch: about to eval closure at %g, " "susp->susp.t0 %g, susp.current %d:\n", now, susp->susp.t0, (int)susp->susp.current); result = xleval(cons(susp->closure, consa(cvflonum(now)))); susp->logical_stop_bits = 1; /* mark s1 as logically stopped */ if (exttypep(result, a_sound)) { susp->s2 = sound_copy(getsound(result)); D nyquist_printf("sndseq: copied result from closure is %p\n", susp->s2); } else xlerror("closure did not return a (monophonic) sound", result); D nyquist_printf("in sndseq: logically stopped; " "%p returned from evform\n", susp->s2); susp->closure = NULL; /* allow garbage collection now */ result = NIL; /**** Now convert to add ****/ susp->susp.mark = add_mark; susp->susp.log_stop_cnt = UNKNOWN; /* will be recomputed by add */ susp->susp.print_tree = add_print_tree; /* assume sample rates are the same */ if (susp->s1->sr != susp->s2->sr) xlfail("in sndseq: sample rates must match"); /* take care of scale factor, if any */ if (susp->s2->scale != 1.0) { // stdputstr("normalizing next sound in a seq\n"); susp->s2 = snd_make_normalize(susp->s2); } /* figure out which add fetch routine to use */ delay = ROUND((susp->s2->t0 - now) * susp->s1->sr); if (susp->terminate_bits) { /* s1 is done, just get s2 now */ sound_unref(susp->s1); susp->s1 = NULL; if (delay > 0) { /* need to fill zeros */ susp->susp.fetch = add_zero_fill_nn_fetch; susp->susp.name = "sndseq:add_zero_fill_nn_fetch"; } else { susp->susp.fetch = add_s2_nn_fetch; susp->susp.name = "sndseq:add_s2_nn_fetch"; } } else if (delay > 0) { /* fill hole between s1 and s2 */ D stdputstr("using add_s1_nn_fetch\n"); susp->susp.fetch = add_s1_nn_fetch; susp->susp.name = "sndseq:add_s1_nn_fetch"; } else { susp->susp.fetch = add_s1_s2_nn_fetch; susp->susp.name = "sndseq:add_s1_s2_nn_fetch"; } susp->s2_phase_incr = susp->s2->sr / susp->susp.sr; susp->output_per_s2 = susp->susp.sr / susp->s2->sr; D stdputstr("in sndseq: calling add's fetch\n"); (*(susp->susp.fetch))(susp, snd_list); D stdputstr("in sndseq: returned from add's fetch\n"); /* gc();*/ xlpop(); return; } /* don't run past the s1 input sample block: */ togo = susp->s1_cnt; /* nyquist_printf("sndseq_fetch: togo initially %d then ", togo); */ /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + togo) { togo = susp->terminate_cnt - susp->susp.current; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - susp->susp.current; togo = MIN(togo, to_stop); } assert(togo >= 0); /* nyquist_printf("%d\n", togo);*/ /* * two cases: copy a partial block or manipulate pointers for copyless * transfer of whole block (may not be full block): * * copy partial block when: * o samples begin in middle of block * o stopping time is before end of block (when other signal splits * the block for this signal). This happens if the logical * stop time was externally dictated and falls mid-block. * transfer (copyless) block when: * o the block is of maximum size * o the block is small due to logical stop time or termination time */ if (susp->s1_ptr == susp->s1_bptr->samples && susp->s1_cnt == togo) { /* * we want to copy this whole block (starting at the beginning * and going to the rest of the block) -- just do pointers. */ /* just fetch and pass blocks on */ /* nyquist_printf("sndseq (s1_nn) %x starting uncopy, togo %d\n", susp, togo); */ snd_list->block = susp->s1_bptr; /* the zero_block indicates termination, don't copy it! Use * internal_zero_block instead. It is also filled with zeros, * but does not indicate termination. We must check for zero_block * because the signal may have a logical stop time specified that * extends beyond its termination time. */ if (snd_list->block == zero_block) snd_list->block = internal_zero_block; (snd_list->block->refcnt)++; /* nyquist_printf("sndseq (s1_nn) %x shared block %x\n", susp, susp->s1_bptr);*/ susp_took(s1_cnt, togo); snd_list->block_len = togo; } else { /* * we want to copy a partial block */ /* snd_list is the one with a null block */ /* put a fresh, clean block in the snd_list (get new snd_list later) */ falloc_sample_block(out, "sndseq_fetch"); snd_list->block = out; out_ptr = out->samples; /* nyquist_printf("sndseq (s1_nn) %x new block %x\n", susp, out); */ n = togo; /* nyquist_printf("sndseq (s1_nn) %x starting copy loop, togo %d\n", susp, togo); */ while (n--) { /* the inner sample computation loop */ /* scale? */ *out_ptr++ = *(susp->s1_ptr++); } /* inner loop */ susp_took(s1_cnt, togo); snd_list->block_len = togo; } /* add a new snd_list for the susp */ susp->susp.current += togo; } /* sndseq_fetch */ void sndseq_free(sndseq_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->s2); ffree_generic(susp, sizeof(sndseq_susp_node), "sndseq_free"); } void sndseq_print_tree(sndseq_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("closure:"); stdprint(susp->closure); indent(n); stdputstr("s2:"); sound_print_tree_1(susp->s2, n); } sound_type snd_make_sndseq(s1, closure) sound_type s1; LVAL closure; { register sndseq_susp_type susp; /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; sound_type result; xlprot1(closure); falloc_generic(susp, sndseq_susp_node, "snd_make_sndseq"); if (s1->scale != 1.0) { /* stdputstr("normalizing first sound in a seq\n"); */ s1 = snd_make_normalize(s1); } susp->susp.fetch = sndseq_fetch; susp->terminate_cnt = UNKNOWN; susp->terminate_bits = 0; /* bits for s1 and s2 termination */ susp->logical_stop_bits = 0; /* bits for s1 and s2 logical stop */ /* initialize susp state */ susp->susp.free = sndseq_free; susp->susp.sr = s1->sr; susp->susp.t0 = s1->t0; susp->susp.mark = sndseq_mark; susp->susp.print_tree = sndseq_print_tree; susp->susp.name = "sndseq"; susp->logically_stopped = false; susp->susp.log_stop_cnt = s1->logical_stop_cnt; if (!(susp->susp.log_stop_cnt >= 0 || susp->susp.log_stop_cnt == UNKNOWN)) { xlerror("Behaviors in SEQ must appear in chronological order", closure); } susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->s2 = NULL; susp->s2_cnt = 0; susp->s2_phase = 0.0; /* susp->s2_phase_incr = ?? susp->output_per_s2 = ?? */ susp->closure = closure; result = sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, scale_factor); xlpopn(1); return result; } sound_type snd_sndseq(s1, closure) sound_type s1; LVAL closure; { sound_type s1_copy; s1_copy = sound_copy(s1); return snd_make_sndseq(s1_copy, closure); } nyquist-3.05/nyqsrc/f0.h0000644000175000000620000000032210144436365014163 0ustar stevestaff#ifndef _FLOAT_H #define _FLOAT_H float f0_estimate(float *samples, int n, int m, float threshold, float *results, float *min); float best_f0(float *samples, int n, int m, float threshold, int Tmax); #endif nyquist-3.05/nyqsrc/convolve.h0000644000175000000620000000025210144436365015513 0ustar stevestaffsound_type snd_make_convolve(sound_type x_snd, sound_type h_snd); sound_type snd_convolve(sound_type x_snd, sound_type h_snd); /* LISP: (snd-convolve SOUND SOUND) */ nyquist-3.05/nyqsrc/lpanal.c0000644000175000000620000000733110144436365015127 0ustar stevestaff/* lpc.c -- implement LPC analysis */ #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" void abs_max(double *x, long desde, long hasta, double *x_maxptr, long *indptr) { /* use: abs_max(s,0,10,&mimax,&miind); */ double x_max = x[desde]; long ind = desde; long i; for(i = desde+1; i x_max) { x_max = fabs(x[i]); ind = i; } *x_maxptr = x_max; *indptr = ind; } void xcorr(double *s, double *rxx, long N) { /* use: xcorr(s,rxx,N); */ long i,j; for(i=0; i < N; i++) { rxx[i] = 0.0; for(j=0; j < N-i; j++) rxx[i] += s[j]*s[j+i]; } } // SOUND PARAMETERS // w Lisp vector containinig signal values // P number of poles // N length of sound // AUTOCORRELEATION PARAMETERS // rxx array containing autocorrelation coefs // max_rxx temporal maximun value of rxx // i_max index of max_rxx // LPC PARAMETERS // alpha array of filter coefs // k reflection coef // E residual energy // rms1 energy of input signal (not RMS) // rms2 residual energy = E // unv voiced/unvoiced parameter = ERR = rms2/rms1 // PITCH DETECTION ALGORITHM: Implemented separately LVAL snd_lpanal(LVAL w, long P) { double *s, *rxx; long N; double *alpha; // double *k, *E; THIS ONLY FOR VECTORIZED k AND E double k, E; double rms1; // rms2=E; double unv; double suma, alphatemp; // help variables long i,j; LVAL result; xlsave1(result); //// end vars ///////////// //// allocate memory /////// N = getsize(w); s = calloc(sizeof(double),N); //signal rxx = calloc(sizeof(double),N); //autocorrelation alpha = calloc(sizeof(double), P); // filter coefs //k = calloc(sizeof(double), P); // reflection coefs //E = calloc(sizeof(double), P); // residual energy ////// copy Lisp array sound data to array of double /////// for(i=0; i> 1); j++) { //alphatemp = alpha[j] - k[i] * alpha[i-j-1]; //alpha[i-j-1] -= k[i] * alpha[j]; //alpha[j] = alphatemp; alphatemp = alpha[j] - k * alpha[i-j-1]; alpha[i-j-1] -= k * alpha[j]; alpha[j] = alphatemp; } //E[i] = E[i-1] * (1 - pow(k[i],2)); E *= (1 - pow(k,2)); } // input signal energy = rxx[0]; rms1 = rxx[0]; // voiced/unvoiced unv= sqrt(E/rms1); ///// HERE: CHECK STABILITY AND MODIFY COEFS ///////////// ///// not implemented // prepare output result result = newvector(P); for (i = 0; i < P; i++) setelement(result, i, cvflonum(alpha[P-i-1])); // alpoles format xlpop(); // free memory free(s); free(rxx); free(alpha); return (cons (cvflonum(rms1), // input signal energy cons(cvflonum(E), // residual energy cons(cvflonum(unv), // ERR, voiced/unvoiced cons(result, NULL))))); // coefs } nyquist-3.05/nyqsrc/exitpa.h0000644000175000000620000000010310144436365015145 0ustar stevestaff/* exitpa.h -- declare portaudio_exit() */ void portaudio_exit(); nyquist-3.05/nyqsrc/fsmallfilter.h0000644000175000000620000006113510144436365016353 0ustar stevestaff/* Included by resamplesubs.c */ #define SMALL_FILTER_NMULT 13 #define SMALL_FILTER_SCALE 13128 /* Unity-gain scale factor */ #define SMALL_FILTER_NWING 1536 /* Filter table length */ static float SMALL_FILTER_IMP[] /* Impulse response */ = { 32767.0F, 32766.0F, 32765.0F, 32762.0F, 32758.0F, 32753.0F, 32747.0F, 32739.0F, 32731.0F, 32722.0F, 32711.0F, 32699.0F, 32686.0F, 32672.0F, 32657.0F, 32641.0F, 32623.0F, 32605.0F, 32585.0F, 32565.0F, 32543.0F, 32520.0F, 32496.0F, 32471.0F, 32445.0F, 32417.0F, 32389.0F, 32359.0F, 32329.0F, 32297.0F, 32264.0F, 32230.0F, 32195.0F, 32159.0F, 32122.0F, 32084.0F, 32044.0F, 32004.0F, 31962.0F, 31920.0F, 31876.0F, 31832.0F, 31786.0F, 31739.0F, 31691.0F, 31642.0F, 31592.0F, 31541.0F, 31489.0F, 31436.0F, 31382.0F, 31327.0F, 31271.0F, 31214.0F, 31156.0F, 31096.0F, 31036.0F, 30975.0F, 30913.0F, 30849.0F, 30785.0F, 30720.0F, 30654.0F, 30586.0F, 30518.0F, 30449.0F, 30379.0F, 30308.0F, 30236.0F, 30163.0F, 30089.0F, 30014.0F, 29938.0F, 29861.0F, 29784.0F, 29705.0F, 29625.0F, 29545.0F, 29464.0F, 29381.0F, 29298.0F, 29214.0F, 29129.0F, 29043.0F, 28956.0F, 28869.0F, 28780.0F, 28691.0F, 28601.0F, 28510.0F, 28418.0F, 28325.0F, 28232.0F, 28137.0F, 28042.0F, 27946.0F, 27849.0F, 27752.0F, 27653.0F, 27554.0F, 27454.0F, 27353.0F, 27252.0F, 27149.0F, 27046.0F, 26943.0F, 26838.0F, 26733.0F, 26627.0F, 26520.0F, 26413.0F, 26305.0F, 26196.0F, 26086.0F, 25976.0F, 25865.0F, 25753.0F, 25641.0F, 25528.0F, 25415.0F, 25301.0F, 25186.0F, 25070.0F, 24954.0F, 24838.0F, 24720.0F, 24602.0F, 24484.0F, 24365.0F, 24245.0F, 24125.0F, 24004.0F, 23883.0F, 23761.0F, 23639.0F, 23516.0F, 23392.0F, 23268.0F, 23144.0F, 23019.0F, 22893.0F, 22767.0F, 22641.0F, 22514.0F, 22386.0F, 22259.0F, 22130.0F, 22001.0F, 21872.0F, 21743.0F, 21613.0F, 21482.0F, 21352.0F, 21220.0F, 21089.0F, 20957.0F, 20825.0F, 20692.0F, 20559.0F, 20426.0F, 20292.0F, 20158.0F, 20024.0F, 19889.0F, 19754.0F, 19619.0F, 19483.0F, 19347.0F, 19211.0F, 19075.0F, 18939.0F, 18802.0F, 18665.0F, 18527.0F, 18390.0F, 18252.0F, 18114.0F, 17976.0F, 17838.0F, 17700.0F, 17561.0F, 17422.0F, 17283.0F, 17144.0F, 17005.0F, 16866.0F, 16726.0F, 16587.0F, 16447.0F, 16307.0F, 16167.0F, 16027.0F, 15887.0F, 15747.0F, 15607.0F, 15467.0F, 15327.0F, 15187.0F, 15046.0F, 14906.0F, 14766.0F, 14625.0F, 14485.0F, 14345.0F, 14205.0F, 14065.0F, 13924.0F, 13784.0F, 13644.0F, 13504.0F, 13364.0F, 13225.0F, 13085.0F, 12945.0F, 12806.0F, 12666.0F, 12527.0F, 12388.0F, 12249.0F, 12110.0F, 11971.0F, 11833.0F, 11694.0F, 11556.0F, 11418.0F, 11280.0F, 11142.0F, 11005.0F, 10867.0F, 10730.0F, 10594.0F, 10457.0F, 10321.0F, 10185.0F, 10049.0F, 9913.0F, 9778.0F, 9643.0F, 9508.0F, 9374.0F, 9239.0F, 9105.0F, 8972.0F, 8839.0F, 8706.0F, 8573.0F, 8441.0F, 8309.0F, 8177.0F, 8046.0F, 7915.0F, 7785.0F, 7655.0F, 7525.0F, 7396.0F, 7267.0F, 7138.0F, 7010.0F, 6882.0F, 6755.0F, 6628.0F, 6502.0F, 6376.0F, 6250.0F, 6125.0F, 6001.0F, 5876.0F, 5753.0F, 5630.0F, 5507.0F, 5385.0F, 5263.0F, 5141.0F, 5021.0F, 4900.0F, 4781.0F, 4661.0F, 4543.0F, 4425.0F, 4307.0F, 4190.0F, 4073.0F, 3957.0F, 3842.0F, 3727.0F, 3613.0F, 3499.0F, 3386.0F, 3273.0F, 3161.0F, 3050.0F, 2939.0F, 2828.0F, 2719.0F, 2610.0F, 2501.0F, 2394.0F, 2286.0F, 2180.0F, 2074.0F, 1968.0F, 1864.0F, 1760.0F, 1656.0F, 1554.0F, 1451.0F, 1350.0F, 1249.0F, 1149.0F, 1050.0F, 951.0F, 853.0F, 755.0F, 658.0F, 562.0F, 467.0F, 372.0F, 278.0F, 185.0F, 92.0F, 0.0F, -90.0F, -181.0F, -271.0F, -360.0F, -448.0F, -536.0F, -623.0F, -709.0F, -795.0F, -880.0F, -964.0F, -1047.0F, -1130.0F, -1212.0F, -1293.0F, -1373.0F, -1453.0F, -1532.0F, -1610.0F, -1688.0F, -1764.0F, -1840.0F, -1916.0F, -1990.0F, -2064.0F, -2137.0F, -2209.0F, -2281.0F, -2351.0F, -2421.0F, -2491.0F, -2559.0F, -2627.0F, -2694.0F, -2760.0F, -2825.0F, -2890.0F, -2954.0F, -3017.0F, -3080.0F, -3141.0F, -3202.0F, -3262.0F, -3322.0F, -3380.0F, -3438.0F, -3495.0F, -3551.0F, -3607.0F, -3662.0F, -3716.0F, -3769.0F, -3821.0F, -3873.0F, -3924.0F, -3974.0F, -4024.0F, -4072.0F, -4120.0F, -4167.0F, -4214.0F, -4259.0F, -4304.0F, -4348.0F, -4392.0F, -4434.0F, -4476.0F, -4517.0F, -4558.0F, -4597.0F, -4636.0F, -4674.0F, -4712.0F, -4748.0F, -4784.0F, -4819.0F, -4854.0F, -4887.0F, -4920.0F, -4953.0F, -4984.0F, -5015.0F, -5045.0F, -5074.0F, -5103.0F, -5131.0F, -5158.0F, -5184.0F, -5210.0F, -5235.0F, -5259.0F, -5283.0F, -5306.0F, -5328.0F, -5349.0F, -5370.0F, -5390.0F, -5409.0F, -5428.0F, -5446.0F, -5463.0F, -5480.0F, -5496.0F, -5511.0F, -5526.0F, -5540.0F, -5553.0F, -5566.0F, -5578.0F, -5589.0F, -5600.0F, -5610.0F, -5619.0F, -5628.0F, -5636.0F, -5643.0F, -5650.0F, -5656.0F, -5662.0F, -5667.0F, -5671.0F, -5674.0F, -5678.0F, -5680.0F, -5682.0F, -5683.0F, -5684.0F, -5684.0F, -5683.0F, -5682.0F, -5680.0F, -5678.0F, -5675.0F, -5672.0F, -5668.0F, -5663.0F, -5658.0F, -5652.0F, -5646.0F, -5639.0F, -5632.0F, -5624.0F, -5616.0F, -5607.0F, -5597.0F, -5587.0F, -5577.0F, -5566.0F, -5554.0F, -5542.0F, -5529.0F, -5516.0F, -5503.0F, -5489.0F, -5474.0F, -5459.0F, -5444.0F, -5428.0F, -5412.0F, -5395.0F, -5378.0F, -5360.0F, -5342.0F, -5323.0F, -5304.0F, -5284.0F, -5264.0F, -5244.0F, -5223.0F, -5202.0F, -5180.0F, -5158.0F, -5136.0F, -5113.0F, -5090.0F, -5066.0F, -5042.0F, -5018.0F, -4993.0F, -4968.0F, -4943.0F, -4917.0F, -4891.0F, -4864.0F, -4838.0F, -4810.0F, -4783.0F, -4755.0F, -4727.0F, -4698.0F, -4670.0F, -4640.0F, -4611.0F, -4581.0F, -4551.0F, -4521.0F, -4490.0F, -4460.0F, -4428.0F, -4397.0F, -4365.0F, -4333.0F, -4301.0F, -4269.0F, -4236.0F, -4203.0F, -4170.0F, -4137.0F, -4103.0F, -4069.0F, -4035.0F, -4001.0F, -3966.0F, -3932.0F, -3897.0F, -3862.0F, -3827.0F, -3791.0F, -3755.0F, -3720.0F, -3684.0F, -3648.0F, -3611.0F, -3575.0F, -3538.0F, -3502.0F, -3465.0F, -3428.0F, -3390.0F, -3353.0F, -3316.0F, -3278.0F, -3241.0F, -3203.0F, -3165.0F, -3127.0F, -3089.0F, -3051.0F, -3013.0F, -2974.0F, -2936.0F, -2898.0F, -2859.0F, -2820.0F, -2782.0F, -2743.0F, -2704.0F, -2666.0F, -2627.0F, -2588.0F, -2549.0F, -2510.0F, -2471.0F, -2432.0F, -2393.0F, -2354.0F, -2315.0F, -2276.0F, -2237.0F, -2198.0F, -2159.0F, -2120.0F, -2081.0F, -2042.0F, -2003.0F, -1964.0F, -1925.0F, -1886.0F, -1847.0F, -1808.0F, -1770.0F, -1731.0F, -1692.0F, -1654.0F, -1615.0F, -1577.0F, -1538.0F, -1500.0F, -1462.0F, -1424.0F, -1386.0F, -1348.0F, -1310.0F, -1272.0F, -1234.0F, -1197.0F, -1159.0F, -1122.0F, -1084.0F, -1047.0F, -1010.0F, -973.0F, -936.0F, -900.0F, -863.0F, -827.0F, -790.0F, -754.0F, -718.0F, -682.0F, -646.0F, -611.0F, -575.0F, -540.0F, -505.0F, -470.0F, -435.0F, -401.0F, -366.0F, -332.0F, -298.0F, -264.0F, -230.0F, -197.0F, -163.0F, -130.0F, -97.0F, -64.0F, -31.0F, 0.0F, 32.0F, 64.0F, 96.0F, 128.0F, 159.0F, 190.0F, 221.0F, 252.0F, 283.0F, 313.0F, 343.0F, 373.0F, 403.0F, 432.0F, 462.0F, 491.0F, 519.0F, 548.0F, 576.0F, 604.0F, 632.0F, 660.0F, 687.0F, 714.0F, 741.0F, 768.0F, 794.0F, 821.0F, 847.0F, 872.0F, 898.0F, 923.0F, 948.0F, 972.0F, 997.0F, 1021.0F, 1045.0F, 1068.0F, 1092.0F, 1115.0F, 1138.0F, 1160.0F, 1183.0F, 1205.0F, 1227.0F, 1248.0F, 1270.0F, 1291.0F, 1311.0F, 1332.0F, 1352.0F, 1372.0F, 1392.0F, 1411.0F, 1430.0F, 1449.0F, 1468.0F, 1486.0F, 1504.0F, 1522.0F, 1539.0F, 1556.0F, 1573.0F, 1590.0F, 1607.0F, 1623.0F, 1639.0F, 1654.0F, 1669.0F, 1685.0F, 1699.0F, 1714.0F, 1728.0F, 1742.0F, 1756.0F, 1769.0F, 1782.0F, 1795.0F, 1808.0F, 1820.0F, 1832.0F, 1844.0F, 1855.0F, 1867.0F, 1878.0F, 1888.0F, 1899.0F, 1909.0F, 1919.0F, 1929.0F, 1938.0F, 1947.0F, 1956.0F, 1964.0F, 1973.0F, 1981.0F, 1989.0F, 1996.0F, 2003.0F, 2010.0F, 2017.0F, 2024.0F, 2030.0F, 2036.0F, 2042.0F, 2047.0F, 2052.0F, 2057.0F, 2062.0F, 2066.0F, 2071.0F, 2074.0F, 2078.0F, 2082.0F, 2085.0F, 2088.0F, 2091.0F, 2093.0F, 2095.0F, 2097.0F, 2099.0F, 2101.0F, 2102.0F, 2103.0F, 2104.0F, 2104.0F, 2105.0F, 2105.0F, 2105.0F, 2104.0F, 2104.0F, 2103.0F, 2102.0F, 2101.0F, 2100.0F, 2098.0F, 2096.0F, 2094.0F, 2092.0F, 2089.0F, 2087.0F, 2084.0F, 2081.0F, 2077.0F, 2074.0F, 2070.0F, 2066.0F, 2062.0F, 2058.0F, 2053.0F, 2048.0F, 2043.0F, 2038.0F, 2033.0F, 2028.0F, 2022.0F, 2016.0F, 2010.0F, 2004.0F, 1998.0F, 1991.0F, 1984.0F, 1978.0F, 1970.0F, 1963.0F, 1956.0F, 1948.0F, 1941.0F, 1933.0F, 1925.0F, 1917.0F, 1908.0F, 1900.0F, 1891.0F, 1882.0F, 1873.0F, 1864.0F, 1855.0F, 1846.0F, 1836.0F, 1826.0F, 1817.0F, 1807.0F, 1797.0F, 1787.0F, 1776.0F, 1766.0F, 1755.0F, 1745.0F, 1734.0F, 1723.0F, 1712.0F, 1701.0F, 1689.0F, 1678.0F, 1667.0F, 1655.0F, 1643.0F, 1632.0F, 1620.0F, 1608.0F, 1596.0F, 1583.0F, 1571.0F, 1559.0F, 1546.0F, 1534.0F, 1521.0F, 1509.0F, 1496.0F, 1483.0F, 1470.0F, 1457.0F, 1444.0F, 1431.0F, 1417.0F, 1404.0F, 1391.0F, 1377.0F, 1364.0F, 1350.0F, 1337.0F, 1323.0F, 1309.0F, 1296.0F, 1282.0F, 1268.0F, 1254.0F, 1240.0F, 1226.0F, 1212.0F, 1198.0F, 1184.0F, 1170.0F, 1156.0F, 1141.0F, 1127.0F, 1113.0F, 1099.0F, 1084.0F, 1070.0F, 1056.0F, 1041.0F, 1027.0F, 1013.0F, 998.0F, 984.0F, 969.0F, 955.0F, 940.0F, 926.0F, 911.0F, 897.0F, 882.0F, 868.0F, 854.0F, 839.0F, 825.0F, 810.0F, 796.0F, 781.0F, 767.0F, 753.0F, 738.0F, 724.0F, 709.0F, 695.0F, 681.0F, 667.0F, 652.0F, 638.0F, 624.0F, 610.0F, 596.0F, 581.0F, 567.0F, 553.0F, 539.0F, 525.0F, 511.0F, 498.0F, 484.0F, 470.0F, 456.0F, 442.0F, 429.0F, 415.0F, 402.0F, 388.0F, 375.0F, 361.0F, 348.0F, 335.0F, 321.0F, 308.0F, 295.0F, 282.0F, 269.0F, 256.0F, 243.0F, 230.0F, 217.0F, 205.0F, 192.0F, 180.0F, 167.0F, 155.0F, 142.0F, 130.0F, 118.0F, 106.0F, 94.0F, 82.0F, 70.0F, 58.0F, 46.0F, 35.0F, 23.0F, 11.0F, 0.0F, -10.0F, -22.0F, -33.0F, -44.0F, -55.0F, -66.0F, -77.0F, -87.0F, -98.0F, -109.0F, -119.0F, -130.0F, -140.0F, -150.0F, -160.0F, -170.0F, -180.0F, -190.0F, -200.0F, -209.0F, -219.0F, -228.0F, -238.0F, -247.0F, -256.0F, -265.0F, -274.0F, -283.0F, -292.0F, -301.0F, -309.0F, -318.0F, -326.0F, -335.0F, -343.0F, -351.0F, -359.0F, -367.0F, -375.0F, -382.0F, -390.0F, -397.0F, -405.0F, -412.0F, -419.0F, -426.0F, -433.0F, -440.0F, -447.0F, -454.0F, -460.0F, -467.0F, -473.0F, -479.0F, -486.0F, -492.0F, -498.0F, -504.0F, -509.0F, -515.0F, -521.0F, -526.0F, -531.0F, -537.0F, -542.0F, -547.0F, -552.0F, -557.0F, -561.0F, -566.0F, -571.0F, -575.0F, -579.0F, -584.0F, -588.0F, -592.0F, -596.0F, -600.0F, -604.0F, -607.0F, -611.0F, -614.0F, -618.0F, -621.0F, -624.0F, -627.0F, -630.0F, -633.0F, -636.0F, -638.0F, -641.0F, -644.0F, -646.0F, -648.0F, -651.0F, -653.0F, -655.0F, -657.0F, -658.0F, -660.0F, -662.0F, -664.0F, -665.0F, -666.0F, -668.0F, -669.0F, -670.0F, -671.0F, -672.0F, -673.0F, -674.0F, -675.0F, -675.0F, -676.0F, -676.0F, -677.0F, -677.0F, -677.0F, -677.0F, -677.0F, -677.0F, -677.0F, -677.0F, -677.0F, -676.0F, -676.0F, -675.0F, -675.0F, -674.0F, -674.0F, -673.0F, -672.0F, -671.0F, -670.0F, -669.0F, -668.0F, -667.0F, -665.0F, -664.0F, -663.0F, -661.0F, -660.0F, -658.0F, -656.0F, -654.0F, -653.0F, -651.0F, -649.0F, -647.0F, -645.0F, -643.0F, -641.0F, -638.0F, -636.0F, -634.0F, -631.0F, -629.0F, -626.0F, -624.0F, -621.0F, -619.0F, -616.0F, -613.0F, -610.0F, -608.0F, -605.0F, -602.0F, -599.0F, -596.0F, -593.0F, -589.0F, -586.0F, -583.0F, -580.0F, -576.0F, -573.0F, -570.0F, -566.0F, -563.0F, -559.0F, -556.0F, -552.0F, -549.0F, -545.0F, -541.0F, -538.0F, -534.0F, -530.0F, -526.0F, -522.0F, -519.0F, -515.0F, -511.0F, -507.0F, -503.0F, -499.0F, -495.0F, -491.0F, -487.0F, -482.0F, -478.0F, -474.0F, -470.0F, -466.0F, -462.0F, -457.0F, -453.0F, -449.0F, -445.0F, -440.0F, -436.0F, -432.0F, -427.0F, -423.0F, -419.0F, -414.0F, -410.0F, -406.0F, -401.0F, -397.0F, -392.0F, -388.0F, -383.0F, -379.0F, -375.0F, -370.0F, -366.0F, -361.0F, -357.0F, -352.0F, -348.0F, -343.0F, -339.0F, -334.0F, -330.0F, -325.0F, -321.0F, -316.0F, -312.0F, -307.0F, -303.0F, -298.0F, -294.0F, -290.0F, -285.0F, -281.0F, -276.0F, -272.0F, -267.0F, -263.0F, -259.0F, -254.0F, -250.0F, -245.0F, -241.0F, -237.0F, -232.0F, -228.0F, -224.0F, -219.0F, -215.0F, -211.0F, -207.0F, -202.0F, -198.0F, -194.0F, -190.0F, -185.0F, -181.0F, -177.0F, -173.0F, -169.0F, -165.0F, -161.0F, -157.0F, -153.0F, -149.0F, -145.0F, -141.0F, -137.0F, -133.0F, -129.0F, -125.0F, -121.0F, -117.0F, -113.0F, -110.0F, -106.0F, -102.0F, -98.0F, -95.0F, -91.0F, -87.0F, -84.0F, -80.0F, -77.0F, -73.0F, -69.0F, -66.0F, -62.0F, -59.0F, -56.0F, -52.0F, -49.0F, -46.0F, -42.0F, -39.0F, -36.0F, -32.0F, -29.0F, -26.0F, -23.0F, -20.0F, -17.0F, -14.0F, -11.0F, -8.0F, -5.0F, -2.0F, 0.0F, 3.0F, 6.0F, 8.0F, 11.0F, 14.0F, 17.0F, 19.0F, 22.0F, 25.0F, 27.0F, 30.0F, 32.0F, 35.0F, 37.0F, 40.0F, 42.0F, 44.0F, 47.0F, 49.0F, 51.0F, 54.0F, 56.0F, 58.0F, 60.0F, 62.0F, 64.0F, 66.0F, 68.0F, 70.0F, 72.0F, 74.0F, 76.0F, 78.0F, 80.0F, 82.0F, 83.0F, 85.0F, 87.0F, 89.0F, 90.0F, 92.0F, 93.0F, 95.0F, 96.0F, 98.0F, 99.0F, 101.0F, 102.0F, 104.0F, 105.0F, 106.0F, 107.0F, 109.0F, 110.0F, 111.0F, 112.0F, 113.0F, 114.0F, 116.0F, 117.0F, 118.0F, 119.0F, 120.0F, 120.0F, 121.0F, 122.0F, 123.0F, 124.0F, 125.0F, 125.0F, 126.0F, 127.0F, 128.0F, 128.0F, 129.0F, 129.0F, 130.0F, 131.0F, 131.0F, 132.0F, 132.0F, 133.0F, 133.0F, 133.0F, 134.0F, 134.0F, 134.0F, 135.0F, 135.0F, 135.0F, 135.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 137.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 136.0F, 135.0F, 135.0F, 135.0F, 135.0F, 135.0F, 134.0F, 134.0F, 134.0F, 133.0F, 133.0F, 133.0F, 132.0F, 132.0F, 131.0F, 131.0F, 131.0F, 130.0F, 130.0F, 129.0F, 129.0F, 128.0F, 128.0F, 127.0F, 127.0F, 126.0F, 125.0F, 125.0F, 124.0F, 124.0F, 123.0F, 122.0F, 122.0F, 121.0F, 120.0F, 120.0F, 119.0F, 118.0F, 118.0F, 117.0F, 116.0F, 115.0F, 115.0F, 114.0F, 113.0F, 112.0F, 112.0F, 111.0F, 110.0F, 109.0F, 108.0F, 108.0F, 107.0F, 106.0F, 105.0F, 104.0F, 103.0F, 103.0F, 102.0F, 101.0F, 100.0F, 99.0F, 98.0F, 97.0F, 96.0F, 96.0F, 95.0F, 94.0F, 93.0F, 92.0F, 91.0F, 90.0F, 89.0F, 88.0F, 87.0F, 87.0F, 86.0F, 85.0F, 84.0F, 83.0F, 82.0F, 81.0F, 80.0F, 79.0F, 78.0F, 77.0F, 76.0F, 76.0F, 75.0F, 74.0F, 73.0F, 72.0F, 71.0F, 70.0F, 69.0F, 68.0F, 67.0F, 66.0F, 65.0F, 65.0F, 64.0F, 63.0F, 62.0F, 61.0F, 60.0F, 59.0F, 58.0F, 57.0F, 57.0F, 56.0F, 55.0F, 54.0F, 53.0F, 52.0F, 51.0F, 51.0F, 50.0F, 49.0F, 48.0F, 47.0F, 46.0F, 46.0F, 45.0F, 44.0F, 43.0F, 42.0F, 42.0F, 41.0F, 40.0F, 39.0F, 38.0F, 38.0F, 37.0F, 36.0F, 35.0F, 35.0F, 34.0F, 33.0F, 33.0F, 32.0F, 31.0F, 30.0F, 30.0F, 29.0F, 28.0F, 28.0F}; static float SMALL_FILTER_IMPD[] = { -1.0F, -1.0F, -3.0F, -4.0F, -5.0F, -6.0F, -8.0F, -8.0F, -9.0F, -11.0F, -12.0F, -13.0F, -14.0F, -15.0F, -16.0F, -18.0F, -18.0F, -20.0F, -20.0F, -22.0F, -23.0F, -24.0F, -25.0F, -26.0F, -28.0F, -28.0F, -30.0F, -30.0F, -32.0F, -33.0F, -34.0F, -35.0F, -36.0F, -37.0F, -38.0F, -40.0F, -40.0F, -42.0F, -42.0F, -44.0F, -44.0F, -46.0F, -47.0F, -48.0F, -49.0F, -50.0F, -51.0F, -52.0F, -53.0F, -54.0F, -55.0F, -56.0F, -57.0F, -58.0F, -60.0F, -60.0F, -61.0F, -62.0F, -64.0F, -64.0F, -65.0F, -66.0F, -68.0F, -68.0F, -69.0F, -70.0F, -71.0F, -72.0F, -73.0F, -74.0F, -75.0F, -76.0F, -77.0F, -77.0F, -79.0F, -80.0F, -80.0F, -81.0F, -83.0F, -83.0F, -84.0F, -85.0F, -86.0F, -87.0F, -87.0F, -89.0F, -89.0F, -90.0F, -91.0F, -92.0F, -93.0F, -93.0F, -95.0F, -95.0F, -96.0F, -97.0F, -97.0F, -99.0F, -99.0F, -100.0F, -101.0F, -101.0F, -103.0F, -103.0F, -103.0F, -105.0F, -105.0F, -106.0F, -107.0F, -107.0F, -108.0F, -109.0F, -110.0F, -110.0F, -111.0F, -112.0F, -112.0F, -113.0F, -113.0F, -114.0F, -115.0F, -116.0F, -116.0F, -116.0F, -118.0F, -118.0F, -118.0F, -119.0F, -120.0F, -120.0F, -121.0F, -121.0F, -122.0F, -122.0F, -123.0F, -124.0F, -124.0F, -124.0F, -125.0F, -126.0F, -126.0F, -126.0F, -127.0F, -128.0F, -127.0F, -129.0F, -129.0F, -129.0F, -129.0F, -130.0F, -131.0F, -130.0F, -132.0F, -131.0F, -132.0F, -132.0F, -133.0F, -133.0F, -133.0F, -134.0F, -134.0F, -134.0F, -135.0F, -135.0F, -135.0F, -136.0F, -136.0F, -136.0F, -136.0F, -136.0F, -137.0F, -137.0F, -138.0F, -137.0F, -138.0F, -138.0F, -138.0F, -138.0F, -138.0F, -139.0F, -139.0F, -139.0F, -139.0F, -139.0F, -139.0F, -140.0F, -139.0F, -140.0F, -140.0F, -140.0F, -140.0F, -140.0F, -140.0F, -140.0F, -140.0F, -140.0F, -140.0F, -141.0F, -140.0F, -140.0F, -141.0F, -140.0F, -140.0F, -140.0F, -140.0F, -141.0F, -140.0F, -140.0F, -140.0F, -140.0F, -139.0F, -140.0F, -140.0F, -139.0F, -140.0F, -139.0F, -139.0F, -139.0F, -139.0F, -139.0F, -138.0F, -139.0F, -138.0F, -138.0F, -138.0F, -138.0F, -137.0F, -138.0F, -137.0F, -136.0F, -137.0F, -136.0F, -136.0F, -136.0F, -136.0F, -135.0F, -135.0F, -135.0F, -134.0F, -135.0F, -134.0F, -133.0F, -133.0F, -133.0F, -133.0F, -132.0F, -132.0F, -132.0F, -131.0F, -131.0F, -130.0F, -130.0F, -130.0F, -129.0F, -129.0F, -129.0F, -128.0F, -128.0F, -127.0F, -127.0F, -126.0F, -126.0F, -126.0F, -125.0F, -124.0F, -125.0F, -123.0F, -123.0F, -123.0F, -122.0F, -122.0F, -122.0F, -120.0F, -121.0F, -119.0F, -120.0F, -118.0F, -118.0F, -118.0F, -117.0F, -117.0F, -116.0F, -115.0F, -115.0F, -114.0F, -114.0F, -113.0F, -113.0F, -112.0F, -111.0F, -111.0F, -111.0F, -109.0F, -109.0F, -109.0F, -107.0F, -108.0F, -106.0F, -106.0F, -106.0F, -104.0F, -104.0F, -104.0F, -102.0F, -103.0F, -101.0F, -101.0F, -100.0F, -99.0F, -99.0F, -98.0F, -98.0F, -97.0F, -96.0F, -95.0F, -95.0F, -94.0F, -93.0F, -93.0F, -92.0F, -90.0F, -91.0F, -90.0F, -89.0F, -88.0F, -88.0F, -87.0F, -86.0F, -86.0F, -85.0F, -84.0F, -83.0F, -83.0F, -82.0F, -81.0F, -80.0F, -80.0F, -79.0F, -78.0F, -78.0F, -76.0F, -76.0F, -76.0F, -74.0F, -74.0F, -73.0F, -72.0F, -72.0F, -70.0F, -70.0F, -70.0F, -68.0F, -68.0F, -67.0F, -66.0F, -65.0F, -65.0F, -64.0F, -63.0F, -63.0F, -61.0F, -61.0F, -60.0F, -60.0F, -58.0F, -58.0F, -57.0F, -56.0F, -56.0F, -55.0F, -54.0F, -53.0F, -52.0F, -52.0F, -51.0F, -50.0F, -50.0F, -48.0F, -48.0F, -47.0F, -47.0F, -45.0F, -45.0F, -44.0F, -44.0F, -42.0F, -42.0F, -41.0F, -41.0F, -39.0F, -39.0F, -38.0F, -38.0F, -36.0F, -36.0F, -35.0F, -35.0F, -33.0F, -33.0F, -33.0F, -31.0F, -31.0F, -30.0F, -29.0F, -29.0F, -28.0F, -27.0F, -26.0F, -26.0F, -25.0F, -24.0F, -24.0F, -23.0F, -22.0F, -21.0F, -21.0F, -20.0F, -19.0F, -19.0F, -18.0F, -17.0F, -17.0F, -16.0F, -15.0F, -15.0F, -14.0F, -13.0F, -13.0F, -12.0F, -11.0F, -11.0F, -10.0F, -9.0F, -9.0F, -8.0F, -7.0F, -7.0F, -6.0F, -6.0F, -5.0F, -4.0F, -3.0F, -4.0F, -2.0F, -2.0F, -1.0F, -1.0F, 0.0F, 1.0F, 1.0F, 2.0F, 2.0F, 3.0F, 3.0F, 4.0F, 5.0F, 5.0F, 6.0F, 6.0F, 7.0F, 7.0F, 8.0F, 8.0F, 9.0F, 10.0F, 10.0F, 10.0F, 11.0F, 12.0F, 12.0F, 13.0F, 13.0F, 13.0F, 14.0F, 15.0F, 15.0F, 15.0F, 16.0F, 16.0F, 17.0F, 17.0F, 18.0F, 18.0F, 19.0F, 19.0F, 20.0F, 20.0F, 20.0F, 21.0F, 21.0F, 22.0F, 22.0F, 22.0F, 23.0F, 23.0F, 24.0F, 24.0F, 24.0F, 25.0F, 25.0F, 25.0F, 26.0F, 26.0F, 27.0F, 26.0F, 28.0F, 27.0F, 28.0F, 28.0F, 29.0F, 28.0F, 30.0F, 29.0F, 30.0F, 30.0F, 30.0F, 31.0F, 30.0F, 32.0F, 31.0F, 32.0F, 32.0F, 32.0F, 32.0F, 33.0F, 33.0F, 33.0F, 33.0F, 34.0F, 34.0F, 34.0F, 34.0F, 35.0F, 34.0F, 35.0F, 35.0F, 35.0F, 36.0F, 36.0F, 35.0F, 36.0F, 36.0F, 37.0F, 36.0F, 37.0F, 36.0F, 37.0F, 37.0F, 38.0F, 37.0F, 37.0F, 38.0F, 37.0F, 38.0F, 38.0F, 38.0F, 38.0F, 38.0F, 38.0F, 39.0F, 38.0F, 38.0F, 39.0F, 39.0F, 38.0F, 39.0F, 39.0F, 38.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 39.0F, 38.0F, 39.0F, 39.0F, 38.0F, 39.0F, 38.0F, 39.0F, 38.0F, 38.0F, 38.0F, 38.0F, 38.0F, 38.0F, 38.0F, 38.0F, 37.0F, 38.0F, 37.0F, 38.0F, 37.0F, 37.0F, 37.0F, 37.0F, 36.0F, 37.0F, 36.0F, 37.0F, 36.0F, 36.0F, 36.0F, 36.0F, 35.0F, 36.0F, 35.0F, 35.0F, 35.0F, 35.0F, 34.0F, 35.0F, 34.0F, 34.0F, 34.0F, 34.0F, 33.0F, 34.0F, 33.0F, 33.0F, 33.0F, 33.0F, 31.0F, 32.0F, 32.0F, 32.0F, 32.0F, 31.0F, 31.0F, 31.0F, 31.0F, 31.0F, 30.0F, 30.0F, 30.0F, 30.0F, 29.0F, 30.0F, 29.0F, 28.0F, 29.0F, 28.0F, 28.0F, 28.0F, 28.0F, 27.0F, 27.0F, 27.0F, 27.0F, 26.0F, 27.0F, 26.0F, 25.0F, 26.0F, 25.0F, 25.0F, 24.0F, 25.0F, 24.0F, 24.0F, 23.0F, 24.0F, 23.0F, 23.0F, 22.0F, 23.0F, 22.0F, 22.0F, 21.0F, 22.0F, 21.0F, 20.0F, 21.0F, 20.0F, 20.0F, 20.0F, 19.0F, 19.0F, 19.0F, 19.0F, 18.0F, 18.0F, 18.0F, 17.0F, 17.0F, 17.0F, 17.0F, 17.0F, 16.0F, 16.0F, 15.0F, 15.0F, 16.0F, 14.0F, 15.0F, 14.0F, 14.0F, 14.0F, 13.0F, 13.0F, 13.0F, 13.0F, 12.0F, 12.0F, 12.0F, 11.0F, 12.0F, 11.0F, 10.0F, 11.0F, 10.0F, 10.0F, 10.0F, 9.0F, 9.0F, 9.0F, 8.0F, 9.0F, 8.0F, 8.0F, 7.0F, 7.0F, 7.0F, 7.0F, 7.0F, 6.0F, 6.0F, 6.0F, 5.0F, 5.0F, 5.0F, 5.0F, 4.0F, 5.0F, 3.0F, 4.0F, 4.0F, 3.0F, 3.0F, 3.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 1.0F, 1.0F, 1.0F, 0.0F, 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -2.0F, -2.0F, -2.0F, -2.0F, -3.0F, -2.0F, -3.0F, -3.0F, -4.0F, -3.0F, -4.0F, -4.0F, -4.0F, -4.0F, -5.0F, -5.0F, -5.0F, -5.0F, -5.0F, -5.0F, -6.0F, -6.0F, -6.0F, -6.0F, -6.0F, -7.0F, -7.0F, -6.0F, -8.0F, -7.0F, -7.0F, -8.0F, -7.0F, -8.0F, -8.0F, -8.0F, -9.0F, -8.0F, -9.0F, -9.0F, -9.0F, -9.0F, -9.0F, -9.0F, -10.0F, -10.0F, -9.0F, -10.0F, -10.0F, -10.0F, -11.0F, -10.0F, -11.0F, -10.0F, -11.0F, -11.0F, -11.0F, -11.0F, -12.0F, -11.0F, -11.0F, -12.0F, -12.0F, -11.0F, -12.0F, -12.0F, -12.0F, -13.0F, -12.0F, -12.0F, -13.0F, -12.0F, -13.0F, -12.0F, -13.0F, -13.0F, -13.0F, -13.0F, -13.0F, -13.0F, -14.0F, -13.0F, -13.0F, -14.0F, -13.0F, -14.0F, -13.0F, -14.0F, -14.0F, -13.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -15.0F, -14.0F, -14.0F, -14.0F, -15.0F, -14.0F, -14.0F, -15.0F, -14.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -14.0F, -15.0F, -14.0F, -15.0F, -14.0F, -14.0F, -14.0F, -15.0F, -14.0F, -14.0F, -14.0F, -14.0F, -15.0F, -14.0F, -14.0F, -14.0F, -14.0F, -14.0F, -13.0F, -14.0F, -14.0F, -14.0F, -14.0F, -13.0F, -14.0F, -13.0F, -14.0F, -13.0F, -14.0F, -13.0F, -13.0F, -14.0F, -13.0F, -13.0F, -13.0F, -13.0F, -13.0F, -13.0F, -13.0F, -13.0F, -12.0F, -13.0F, -12.0F, -13.0F, -12.0F, -13.0F, -12.0F, -12.0F, -12.0F, -12.0F, -12.0F, -12.0F, -12.0F, -12.0F, -11.0F, -12.0F, -12.0F, -11.0F, -10.0F, -12.0F, -11.0F, -11.0F, -11.0F, -11.0F, -11.0F, -10.0F, -11.0F, -11.0F, -10.0F, -11.0F, -10.0F, -10.0F, -10.0F, -10.0F, -10.0F, -10.0F, -10.0F, -9.0F, -10.0F, -9.0F, -10.0F, -9.0F, -9.0F, -9.0F, -9.0F, -9.0F, -9.0F, -9.0F, -8.0F, -9.0F, -8.0F, -9.0F, -8.0F, -8.0F, -8.0F, -8.0F, -8.0F, -7.0F, -8.0F, -7.0F, -8.0F, -7.0F, -7.0F, -7.0F, -7.0F, -7.0F, -7.0F, -7.0F, -6.0F, -7.0F, -6.0F, -6.0F, -7.0F, -6.0F, -6.0F, -6.0F, -5.0F, -6.0F, -6.0F, -5.0F, -5.0F, -6.0F, -5.0F, -5.0F, -5.0F, -5.0F, -4.0F, -5.0F, -5.0F, -4.0F, -4.0F, -5.0F, -4.0F, -4.0F, -4.0F, -4.0F, -4.0F, -3.0F, -4.0F, -3.0F, -4.0F, -3.0F, -3.0F, -3.0F, -3.0F, -3.0F, -3.0F, -2.0F, -3.0F, -3.0F, -2.0F, -2.0F, -3.0F, -2.0F, -2.0F, -2.0F, -1.0F, -2.0F, -2.0F, -2.0F, -1.0F, -1.0F, -2.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, 0.0F, -1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 1.0F, 0.0F, 1.0F, 0.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 2.0F, 1.0F, 1.0F, 2.0F, 1.0F, 2.0F, 2.0F, 2.0F, 1.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 3.0F, 2.0F, 2.0F, 3.0F, 2.0F, 3.0F, 2.0F, 3.0F, 2.0F, 3.0F, 3.0F, 3.0F, 2.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 4.0F, 3.0F, 3.0F, 3.0F, 4.0F, 3.0F, 3.0F, 4.0F, 3.0F, 4.0F, 3.0F, 4.0F, 3.0F, 4.0F, 4.0F, 3.0F, 4.0F, 4.0F, 4.0F, 4.0F, 3.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 4.0F, 5.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 4.0F, 3.0F, 4.0F, 4.0F, 4.0F, 3.0F, 4.0F, 4.0F, 3.0F, 4.0F, 3.0F, 4.0F, 4.0F, 3.0F, 4.0F, 3.0F, 3.0F, 4.0F, 3.0F, 3.0F, 4.0F, 3.0F, 3.0F, 4.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 3.0F, 2.0F, 3.0F, 3.0F, 2.0F, 3.0F, 3.0F, 3.0F, 2.0F, 3.0F, 3.0F, 2.0F, 3.0F, 2.0F, 3.0F, 2.0F, 3.0F, 2.0F, 2.0F, 3.0F, 2.0F, 2.0F, 3.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 2.0F, 1.0F, 2.0F, 2.0F, 2.0F, 1.0F, 2.0F, 1.0F, 2.0F, 1.0F, 2.0F, 1.0F, 2.0F, 1.0F, 2.0F, 1.0F, 1.0F, 1.0F, 2.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 2.0F, 1.0F, 1.0F, 1.0F, 1.0F, 0.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 0.0F, 1.0F, 1.0F, 1.0F, 0.0F, 1.0F, 0.0F, 1.0F, 1.0F, 0.0F, 1.0F, 0.0F, 1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, -1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F, -1.0F, 0.0F, -1.0F, 0.0F, 0.0F, -1.0F, 0.0F, -1.0F, 0.0F, -1.0F, 0.0F, -1.0F, 0.0F, -1.0F, -1.0F, 0.0F, -1.0F, 0.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, -1.0F, 0.0F, -1.0F, -1.0F, 0.0F, -28.0F}; nyquist-3.05/nyqsrc/rfftw.h0000644000175000000620000001073510144436365015017 0ustar stevestaff/* * Copyright (c) 1997-1999 Massachusetts Institute of Technology * * 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 * */ /* rfftw.h -- system-wide definitions for rfftw */ #ifndef RFFTW_H #define RFFTW_H #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /****************************************************************************/ #define RFFTW_V2 typedef fftw_plan rfftw_plan; typedef fftwnd_plan rfftwnd_plan; #define FFTW_REAL_TO_COMPLEX FFTW_FORWARD #define FFTW_COMPLEX_TO_REAL FFTW_BACKWARD extern void rfftw(rfftw_plan plan, int howmany, fftw_real *in, int istride, int idist, fftw_real *out, int ostride, int odist); extern void rfftw_one(rfftw_plan plan, fftw_real *in, fftw_real *out); extern rfftw_plan rfftw_create_plan_specific(int n, fftw_direction dir, int flags, fftw_real *in, int istride, fftw_real *out, int ostride); extern rfftw_plan rfftw_create_plan(int n, fftw_direction dir, int flags); extern void rfftw_destroy_plan(rfftw_plan plan); extern void rfftw_fprint_plan(FILE *f, rfftw_plan p); extern void rfftw_print_plan(rfftw_plan p); extern void rfftw_executor_simple(int n, fftw_real *in, fftw_real *out, fftw_plan_node *p, int istride, int ostride); extern rfftwnd_plan rfftwnd_create_plan_specific(int rank, const int *n, fftw_direction dir, int flags, fftw_real *in, int istride, fftw_real *out, int ostride); extern rfftwnd_plan rfftw2d_create_plan_specific(int nx, int ny, fftw_direction dir, int flags, fftw_real *in, int istride, fftw_real *out, int ostride); extern rfftwnd_plan rfftw3d_create_plan_specific(int nx, int ny, int nz, fftw_direction dir, int flags, fftw_real *in, int istride, fftw_real *out, int ostride); extern rfftwnd_plan rfftwnd_create_plan(int rank, const int *n, fftw_direction dir, int flags); extern rfftwnd_plan rfftw2d_create_plan(int nx, int ny, fftw_direction dir, int flags); extern rfftwnd_plan rfftw3d_create_plan(int nx, int ny, int nz, fftw_direction dir, int flags); extern void rfftwnd_destroy_plan(rfftwnd_plan plan); extern void rfftwnd_fprint_plan(FILE *f, rfftwnd_plan plan); extern void rfftwnd_print_plan(rfftwnd_plan plan); extern void rfftwnd_real_to_complex(rfftwnd_plan p, int howmany, fftw_real *in, int istride, int idist, fftw_complex *out, int ostride, int odist); extern void rfftwnd_complex_to_real(rfftwnd_plan p, int howmany, fftw_complex *in, int istride, int idist, fftw_real *out, int ostride, int odist); extern void rfftwnd_one_real_to_complex(rfftwnd_plan p, fftw_real *in, fftw_complex *out); extern void rfftwnd_one_complex_to_real(rfftwnd_plan p, fftw_complex *in, fftw_real *out); /****************************************************************************/ #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* RFFTW_H */ nyquist-3.05/nyqsrc/phasevocoder.c0000644000175000000620000000725711466723256016357 0ustar stevestaff/* phasevocoder.c -- this is a stub showing how you might hook a phase vocoder into Nyquist using pvshell */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "pvshell.h" #include "phasevocoder.h" /* use the state[] info for sample interpolation */ #define X_VALUE state[0] /* a parameter value */ #define F_COUNT state[1] /* counts samples of f */ #define G_COUNT state[2] /* counts samples of g */ #define G_PREV state[3] /* previous value from g */ #define G_NEXT state[4] /* next (current?) value from g */ /* invariant: G_NEXT is the G_COUNT'th sample of g */ /* pv_fetch -- this is an example, but it doesn't really do * phase vocoding. Instead, it will just multiply f, g, and x * * To make things a bit more interesting, we will assume g has * an arbitrary sample rate with respect to f, and will interpolate. * */ long pv_fetch(pvshell_type susp, sample_block_values_type out, long *n) { int i; for (i = 0; i < *n; i++) { long new_flags; sample_type f; double g; /* NOTE: in DSP terms, this is poor code because of the * division operations -- it could be made faster */ /* To get a value from g, first compute the time */ double f_time = susp->F_COUNT / susp->f->sr; /* Now compute g count that is past the time */ double g_count = f_time * susp->g->sr; while (susp->G_COUNT < g_count) { PVSHELL_TEST_G(susp); /* prepare to get a sample */ /* ignore flags from g -- we could, if we wanted, * terminate when either f or g terminated, etc. */ susp->G_PREV = susp->G_NEXT; susp->G_NEXT = PVSHELL_FETCH_G(susp); susp->G_COUNT++; } /* now interpolate to get the value of g at f_time */ g = susp->G_PREV + (susp->G_NEXT - susp->G_PREV) * (g_count - (susp->G_COUNT - 1)); new_flags = PVSHELL_TEST_F(susp); susp->flags |= new_flags; if (new_flags) break; f = PVSHELL_FETCH_F(susp); susp->F_COUNT++; /* count how many samples we have taken */ /* now we have f, g, x */ *out++ = f * g * susp->X_VALUE; } /* i is the number of samples we acutally computed */ *n = i; /* if we computed samples, we want to return them before * returning flags that say we're done or stopped */ return (i ? 0 : susp->flags); } sound_type snd_phasevocoder(sound_type f, sound_type g, double x) { /* we're using 5 doubles of state. The first is a parameter, * and the rest are initialized to zero except for state[2], * aka G_COUNT. This is the number of samples we have read * from G. Since we're interpolating we need a one-sample * lookahead, and initializing the count to -1 causes an * extra fetch and hence 1-sample lookahead. This state is copied * into the pvshell structure, so we don't need to allocate * a vector on the heap. */ double state[5] = {0, 0, -1, 0, 0}; state[0] = x; /* If f and g do not start at the same time, we should really * should do something about it, but we'll just throw an error. * Be careful to allow small differences (within one sample). */ if (fabs(f->t0 - g->t0) * f->sr > 0.5) { xlfail("phasevocoder inputs must start at the same time"); } /* output the same sample rate and start time as f */ return snd_make_pvshell("snd_phasevocoder", f->sr, f->t0, &pv_fetch, f, g, state, sizeof(state) / sizeof(state[0])); } nyquist-3.05/nyqsrc/ffilterkit.c0000644000175000000620000001003110144436365016012 0ustar stevestaff/* * ffilterkit.c (library "filterkit.a"): * Kaiser-windowed low-pass filter support. */ /* ffilterkit.c * * FilterUp() - Applies a filter to a given sample when up-converting. * FilterUD() - Applies a filter to a given sample when up- or down- * converting. */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include #include #include #include "stdefs.h" #include "fresample.h" #include "ffilterkit.h" fast_float FilterUp(float Imp[], float ImpD[], int Nwing, boolean Interp, float *Xp, double Ph, int Inc) { float *Hp, *Hdp = NULL, *End; fast_float a = 0; fast_float v, t; double exact_index = Ph * Npc; long index = (long) exact_index; /* convert fraction to filter index */ /* nyquist_printf("FilterUp, Inc %d, phase %g\n", Inc, Ph); */ v=0; Hp = &Imp[index]; End = &Imp[Nwing]; if (Interp) { Hdp = &ImpD[index]; a = exact_index - index; /* nyquist_printf("fraction %g\n", a); */ } if (Inc == 1) /* If doing right wing... */ { /* ...drop extra coeff, so when Ph is */ End--; /* 0.5, we don't do too many mult's */ if (Ph == 0) /* If the phase is zero... */ { /* ...then we've already skipped the */ Hp += Npc; /* first sample, so we must also */ Hdp += Npc; /* skip ahead in Imp[] and ImpD[] */ } } if (Interp) { while (Hp < End) { t = *Hp; /* Get filter coeff */ /* t scaled by 2^(16 + NLpScl)/LpScl */ t += *Hdp *a; /* t is now interp'd filter coeff */ Hdp += Npc; /* Filter coeff differences step */ t *= *Xp; /* Mult coeff by input sample */ /* t scaled by 2^(16 + NLpScl)/LpScl */ v += t; /* The filter output */ Hp += Npc; /* Filter coeff step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ } } else { while (Hp < End) { t = *Hp; /* Get filter coeff */ t *= *Xp; /* Mult coeff by input sample */ v += t; /* The filter output */ Hp += Npc; /* Filter coeff step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ } } return(v); } fast_float FilterUD( float Imp[], float ImpD[], int Nwing, boolean Interp, float *Xp, double Ph, int Inc, double dhb) { double a; float *Hp, *Hdp, *End; fast_float v, t; double Ho; v=0; Ho = Ph*dhb; End = &Imp[Nwing]; if (Inc == 1) /* If doing right wing... */ { /* ...drop extra coeff, so when Ph is */ End--; /* 0.5, we don't do too many mult's */ if (Ph == 0) /* If the phase is zero... */ Ho += dhb; /* ...then we've already skipped the */ } /* first sample, so we must also */ /* skip ahead in Imp[] and ImpD[] */ if (Interp) { long HoIndex = (long) Ho; while ((Hp = &Imp[HoIndex]) < End) { t = *Hp; /* Get IR sample */ Hdp = &ImpD[HoIndex]; /* get interp (lower Na) bits from diff table*/ a = Ho - HoIndex; /* a is logically between 0 and 1 */ t += *Hdp * a; /* t is now interp'd filter coeff */ t *= *Xp; /* Mult coeff by input sample */ v += t; /* The filter output */ Ho += dhb; /* IR step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ HoIndex = (long) Ho; } } else { long HoIndex = (long) Ho; while ((Hp = &Imp[HoIndex]) < End) { t = *Hp; /* Get IR sample */ t *= *Xp; /* Mult coeff by input sample */ v += t; /* The filter output */ Ho += dhb; /* IR step */ Xp += Inc; /* Input signal step. NO CHECK ON BOUNDS */ HoIndex = (long) Ho; } } return(v); } nyquist-3.05/nyqsrc/sndfn.wcl0000644000175000000620000000345311466723256015342 0ustar stevestaffnyqsrc\sndfnint snd\snd.h nyqsrc\sound.h nyqsrc\add.h nyqsrc\avg.h nyqsrc\compose.h nyqsrc\convolve.h nyqsrc\downsample.h nyqsrc\fft.h nyqsrc\inverse.h nyqsrc\multiseq.h nyqsrc\resamp.h nyqsrc\resampv.h nyqsrc\samples.h nyqsrc\sndmax.h nyqsrc\sndread.h nyqsrc\sndseq.h nyqsrc\sndsliders.h nyqsrc\sndwrite.h nyqsrc\yin.h nyqsrc\nyq-osc-server.h nyqsrc\trigger.h nyqsrc\lpanal.h nyqsrc\phasevocoder.h nyqsrc\pvshell.h ~nyqsrc\sndheader.h tran\abs.h tran\allpoles.h tran\alpass.h tran\alpasscv.h tran\alpassvv.h tran\amosc.h tran\areson.h tran\aresonvc.h tran\aresoncv.h tran\aresonvv.h tran\atone.h tran\atonev.h tran\biquadfilt.h tran\buzz.h tran\chase.h tran\clip.h tran\congen.h tran\const.h tran\coterm.h tran\delaycc.h tran\delaycv.h tran\eqbandvvv.h tran\exp.h tran\follow.h tran\fmosc.h tran\fromobject.h tran\fromarraystream.h tran\gate.h tran\ifft.h tran\instrclar.h tran\instrclarall.h tran\instrclarfreq.h tran\instrsax.h tran\instrsaxall.h tran\instrsaxfreq.h tran\integrate.h tran\log.h tran\lpreson.h tran\maxv.h tran\offset.h tran\oneshot.h tran\osc.h tran\partial.h tran\pluck.h tran\prod.h tran\pwl.h tran\quantize.h tran\recip.h tran\reson.h tran\resonvc.h tran\resoncv.h tran\resonvv.h tran\sampler.h tran\scale.h tran\shape.h tran\sine.h tran\siosc.h tran\slope.h tran\sqrt.h tran\tapf.h tran\tapv.h tran\tone.h tran\tonev.h tran\upsample.h tran\white.h tran\stkrev.h tran\stkpitshift.h tran\stkchorus.h tran\instrbow.h tran\instrbowedfreq.h tran\instrbanded.h tran\instrmandolin.h tran\instrsitar.h tran\instrmodalbar.h tran\instrflute.h tran\instrflutefreq.h tran\instrfluteall.h tran\fmfb.h tran\fmfbv.h nyquist-3.05/nyqsrc/cque.h0000644000175000000620000000102310144436365014612 0ustar stevestaff/* * cque.h * macros for free lists. */ typedef struct cque { struct cque *qnext; } CQUE; #define Qinit(q1) { (q1) = 0; } /* q1 points to a stack CQUE*, new is an element to insert */ #define Qenter(q1,new) { \ ((CQUE *)(new))->qnext = ((CQUE *)(q1)); \ q1 = ((CQUE *)(new)); } /* q1 points to a list of CQUE*: remove elt and assign to new */ /* NOTE: q1 must be non-empty */ #define Qget(q1,newtype,new) { \ (new) = (newtype)(q1); \ q1 = ((CQUE *)(q1))->qnext; } #define Qempty(q1) ((q1) == 0) nyquist-3.05/nyqsrc/seqext.c0000644000175000000620000000320410144436365015164 0ustar stevestaff/* seqext.c -- seq extensions for xlisp */ /* This file extends xlisp with the data type SEQ, including functions to print and free SEQ type objects. */ /* (c) Copyright Carnegie Mellon University 1991, 1994 * For a statement of limited permission to use, see Permission.doc */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm portability fix: use %p instead of %lx */ #include "stdio.h" #include "xlisp.h" #include "cext.h" #include "userio.h" #include "midifns.h" #include "timebase.h" #include "seq.h" #include "moxc.h" #include "seqread.h" #include "seqext.h" #include "extern.h" LVAL s_seq; xtype_desc seq_desc; static void xlseq_print(); void nop() {} boolean seqp(s) LVAL s; { return exttypep(s, s_seq); } /* xlseq_free gets called by xlisp when the GC frees a seq object. * seq_free is a macro, so here we make it into a function pointer. */ static void xlseq_free(sequence) seq_type sequence; { seq_free(sequence); } static void xlseq_print(fptr, sequence) LVAL fptr; seq_type sequence; { char s[32]; sprintf(s, "#", sequence); xlputstr(fptr, s); } static void xlseq_save(fp, sequence) FILE *fp; seq_type sequence; { errputstr("xlseq_save called\n"); } static unsigned char *xlseq_restore(fp) FILE *fp; { errputstr("xlseq_restore called\n"); return 0; } void seqext_init() { /* printf("localinit called\n"); */ seq_desc = create_desc("SEQ", xlseq_free, xlseq_print, xlseq_save, xlseq_restore, NULL); moxcinit(0, (char **) NULL); } void seqext_symbols() { s_seq = xlenter("SEQ"); } nyquist-3.05/nyqsrc/fresample.h0000644000175000000620000000566010144436365015646 0ustar stevestaff/* * FILE: fresample.h * * The configuration constants below govern * the number of bits in the input sample and filter coefficients, the * number of bits to the right of the binary-point for fixed-point math, etc. * */ /* #include "stdefs.h" */ typedef double SAMPLE_TYPE; #define SCALE_FACTOR_TO_SHORT 32767 /* Conversion constants */ #define Nhc 8 /* #define Na 7 */ /* #define Np (Nhc+Na)*/ #define Npc (1<(y) ?(x):(y)) #endif #ifndef MIN #define MIN(x,y) ((x)<(y) ?(x):(y)) #endif #ifndef ABS #define ABS(x) ((x)<0 ?(-(x)):(x)) #endif #ifndef SGN #define SGN(x) ((x)<0 ?(-1):((x)==0?(0):(1))) #endif typedef float mem_float; typedef double fast_float; /* I took out this typedef because the same thing * exists in cext.h which causes a conflict: -RBD typedef unsigned char boolean; */ #include "cext.h" #define true 1 #define false 0 nyquist-3.05/nyqsrc/nyq-osc-server.h0000644000175000000620000000022611466723256016564 0ustar stevestaff/* * nyq-osc-server.h * nyquist * * Created by Roger Dannenberg on 10/1/06. * Copyright 2006 __MyCompanyName__. All rights reserved. * */ nyquist-3.05/nyqsrc/nyx.c0000644000175000000620000007136711466723256014516 0ustar stevestaff/********************************************************************** nyx.c Nyx: A very simple external interface to Nyquist Dominic Mazzoni **********************************************************************/ /* system includes */ #include #include #include #include #include #ifndef WIN32 #include #endif /* nyx includes */ #include "nyx.h" /* xlisp includes */ #include "switches.h" #include "xlisp.h" #include "cext.h" /* nyquist includes */ #include "sound.h" #include "samples.h" #include "falloc.h" /* use full copy */ #define NYX_FULL_COPY 1 /* show memory stats */ // #define NYX_MEMORY_STATS 1 /* show details of obarray copy */ // #define NYX_DEBUG_COPY 1 /* macro to compute the size of a segment (taken from xldmem.h) */ #define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node)) /* xldmem external variables */ extern long nnodes; extern long nfree; extern long total; extern int nsegs; extern SEGMENT *segs; extern SEGMENT *lastseg; extern LVAL fnodes; /* nyquist externs */ extern LVAL a_sound; extern snd_list_type zero_snd_list; /* globals */ LOCAL nyx_os_callback nyx_os_cb = NULL; LOCAL void *nyx_os_ud; LOCAL nyx_output_callback nyx_output_cb; LOCAL void *nyx_output_ud; LOCAL int nyx_expr_pos; LOCAL int nyx_expr_len; LOCAL const char *nyx_expr_string; LOCAL LVAL nyx_result; LOCAL nyx_rval nyx_result_type = nyx_error; LOCAL XLCONTEXT nyx_cntxt; LOCAL int nyx_first_time = 1; LOCAL LVAL nyx_obarray; LOCAL FLOTYPE nyx_warp_stretch; /* Suspension node */ typedef struct nyx_susp_struct { snd_susp_node susp; // Must be first nyx_audio_callback callback; void *userdata; long len; int channel; } nyx_susp_node, *nyx_susp_type; #if defined(NYX_DEBUG_COPY) && NYX_DEBUG_COPY static const char *_types_[] = { "FREE_NODE", "SUBR", "FSUBR", "CONS", "SYMBOL", "FIXNUM", "FLONUM", "STRING", "OBJECT", "STREAM", "VECTOR", "CLOSURE", "CHAR", "USTREAM", "EXTERN" }; // Dump the contents of the obarray LOCAL void nyx_show_obarray() { LVAL array = getvalue(obarray); LVAL sym; int i; for (i = 0; i < HSIZE; i++) { for (sym = getelement(array, i); sym; sym = cdr(sym)) { LVAL syma = car(sym); printf("_sym_ = "); xlprint(getvalue(s_stdout), syma, TRUE); if (getvalue(syma)) { printf(" _type_ = %s _val_ = ", _types_[ntype(getvalue(syma))]); xlprint(getvalue(s_stdout), getvalue(syma), TRUE); } if (getfunction(syma)) { printf(" _type_ = %s _fun_ = ", _types_[ntype(getfunction(syma))]); xlprint(getvalue(s_stdout), getfunction(syma), TRUE); } printf("\n"); } } } #endif // // Free empty segments // LOCAL void freesegs() { SEGMENT *seg; SEGMENT *next; // Free up as many nodes as possible gc(); // Reset free node tracking fnodes = NIL; nfree = 0L; // Reset the last segment pointer lastseg = NULL; // Scan all segments for (seg = segs; seg != NULL; seg = next) { int n = seg->sg_size; int empty = TRUE; int i; LVAL p; // Check this segment for in-use nodes p = &seg->sg_nodes[0]; for (i = n; --i >= 0; ++p) { if (ntype(p) != FREE_NODE) { empty = FALSE; break; } } // Retain pointer to next segment next = seg->sg_next; // Was the current segment empty? if (empty) { // Free the segment; free((void *) seg); // Unlink it from the list. No need to worry about a NULL lastseg // pointer here since the fixnum and char segments will always exist // at the head of the list and they will always have nodes. So, lastseg // will have been set before we find any empty nodes. lastseg->sg_next = next; // Reduce the stats total -= (long) segsize(n); nsegs--; nnodes -= n; } else { // Not empty, so remember this node as the last segment lastseg = seg; // Add all of the free nodes in this segment to the free list p = &seg->sg_nodes[0]; for (i = n; --i >= 0; ++p) { if (ntype(p) == FREE_NODE) { rplaca(p, NIL); rplacd(p, fnodes); fnodes = p; nfree++; } } } } } #if defined(NYX_FULL_COPY) && NYX_FULL_COPY // Copy a node (recursively if appropriate) LOCAL LVAL nyx_dup_value(LVAL val) { LVAL nval = val; // Protect old and new values xlprot1(val); xlprot1(nval); // Copy the node if (val != NIL) { switch (ntype(val)) { case FIXNUM: nval = cvfixnum(getfixnum(val)); break; case FLONUM: nval = cvflonum(getflonum(val)); break; case CHAR: nval = cvchar(getchcode(val)); break; case STRING: nval = cvstring((char *) getstring(val)); break; case VECTOR: { int len = getsize(val); int i; nval = newvector(len); nval->n_type = ntype(val); for (i = 0; i < len; i++) { if (getelement(val, i) == val) { setelement(nval, i, val); } else { setelement(nval, i, nyx_dup_value(getelement(val, i))); } } } break; case CONS: nval = cons(nyx_dup_value(car(val)), nyx_dup_value(cdr(val))); break; case SUBR: case FSUBR: nval = cvsubr(getsubr(val), ntype(val), getoffset(val)); break; // Symbols should never be copied since their addresses are cached // all over the place. case SYMBOL: nval = val; break; // Streams are not copied (although USTREAM could be) and reference // the original value. case USTREAM: case STREAM: nval = val; break; // Externals aren't copied because I'm not entirely certain they can be. case EXTERN: nval = val; break; // For all other types, just allow them to reference the original // value. Probably not the right thing to do, but easier. case OBJECT: case CLOSURE: default: nval = val; break; } } xlpop(); xlpop(); return nval; } // Make a copy of the original obarray, leaving the original in place LOCAL void nyx_save_obarray() { LVAL newarray; int i; // This provide permanent protection for nyx_obarray as we do not want it // to be garbage-collected. xlprot1(nyx_obarray); nyx_obarray = getvalue(obarray); // Create and set the new vector. This allows us to use xlenter() to // properly add the new symbol. Probably slower than adding directly, // but guarantees proper hashing. newarray = newvector(HSIZE); setvalue(obarray, newarray); // Scan all obarray vectors for (i = 0; i < HSIZE; i++) { LVAL sym; // Scan all elements for (sym = getelement(nyx_obarray, i); sym; sym = cdr(sym)) { LVAL syma = car(sym); char *name = (char *) getstring(getpname(syma)); LVAL nsym = xlenter(name); // Ignore *OBARRAY* since there's no need to copy it if (strcmp(name, "*OBARRAY*") == 0) { continue; } // Duplicate the symbol's values setvalue(nsym, nyx_dup_value(getvalue(syma))); setplist(nsym, nyx_dup_value(getplist(syma))); setfunction(nsym, nyx_dup_value(getfunction(syma))); } } // Swap the obarrays, so that the original is put back into service setvalue(obarray, nyx_obarray); nyx_obarray = newarray; } // Restore the symbol values to their original value and remove any added // symbols. LOCAL void nyx_restore_obarray() { LVAL obvec = getvalue(obarray); int i; // Scan all obarray vectors for (i = 0; i < HSIZE; i++) { LVAL last = NULL; LVAL dcon; for (dcon = getelement(obvec, i); dcon; dcon = cdr(dcon)) { LVAL dsym = car(dcon); char *name = (char *)getstring(getpname(dsym)); LVAL scon; // Ignore *OBARRAY* since setting it causes the input array to be // truncated. if (strcmp(name, "*OBARRAY*") == 0) { continue; } // Find the symbol in the original obarray. for (scon = getelement(nyx_obarray, hash(name, HSIZE)); scon; scon = cdr(scon)) { LVAL ssym = car(scon); // If found, then set the current symbols value to the original. if (strcmp(name, (char *)getstring(getpname(ssym))) == 0) { setvalue(dsym, nyx_dup_value(getvalue(ssym))); setplist(dsym, nyx_dup_value(getplist(ssym))); setfunction(dsym, nyx_dup_value(getfunction(ssym))); break; } } // If we didn't find the symbol in the original obarray, then it must've // been added since and must be removed from the current obarray. if (scon == NULL) { if (last) { rplacd(last, cdr(dcon)); } else { setelement(obvec, i, cdr(dcon)); } } // Must track the last dcon for symbol removal last = dcon; } } } #else LOCAL LVAL copylist(LVAL from) { LVAL nsym; if (from == NULL) { return NULL; } return cons(car(from), copylist(cdr(from))); } /* Make a copy of the obarray so that we can erase any changes the user makes to global variables */ LOCAL void nyx_copy_obarray() { LVAL newarray; int i; // Create and set the new vector. newarray = newvector(HSIZE); setvalue(obarray, newarray); for (i = 0; i < HSIZE; i++) { LVAL from = getelement(nyx_obarray, i); if (from) { setelement(newarray, i, copylist(from)); } } } #endif void nyx_init() { if (nyx_first_time) { char *argv[1]; argv[0] = "nyquist"; xlisp_main_init(1, argv); nyx_os_cb = NULL; nyx_output_cb = NULL; nyx_first_time = 0; #if defined(NYX_FULL_COPY) && NYX_FULL_COPY // Save a copy of the original obarray's contents. nyx_save_obarray(); #else // Permanently protect the original obarray value. This is needed since // it would be unreferenced in the new obarray and would be garbage // collected. We want to keep it around so we can make copies of it to // refresh the execution state. xlprot1(nyx_obarray); nyx_obarray = getvalue(obarray); #endif } #if !defined(NYX_FULL_COPY) || !NYX_FULL_COPY // Create a copy of the original obarray nyx_copy_obarray(); #endif // Keep nyx_result from being garbage-collected xlprot1(nyx_result); #if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS printf("\nnyx_init\n"); xmem(); #endif } void nyx_cleanup() { // Garbage-collect nyx_result xlpop(); #if defined(NYX_FULL_COPY) && NYX_FULL_COPY // Restore the original symbol values nyx_restore_obarray(); #else // Restore obarray to original state...but not the values setvalue(obarray, nyx_obarray); #endif // Make sure the sound nodes can be garbage-collected. Sounds are EXTERN // nodes whose value does not get copied during a full copy of the obarray. setvalue(xlenter("S"), NIL); // Free excess memory segments - does a gc() freesegs(); // No longer need the callbacks nyx_output_cb = NULL; nyx_os_cb = NULL; #if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS printf("\nnyx_cleanup\n"); xmem(); #endif } LOCAL void nyx_susp_fetch(register nyx_susp_type susp, snd_list_type snd_list) { sample_block_type out; sample_block_values_type out_ptr; long n; int err; falloc_sample_block(out, "nyx_susp_fetch"); out_ptr = out->samples; snd_list->block = out; n = max_sample_block_len; if (susp->susp.current + n > susp->len) n = susp->len - susp->susp.current; err = susp->callback(out_ptr, susp->channel, susp->susp.current, n, 0, susp->userdata); if (err) { // The user canceled or some other error occurred, so we use // xlsignal() to jump back to our error handler. xlsignal(NULL, NULL); // never get here. } snd_list->block_len = (short)n; susp->susp.current += n; if (n == 0) { /* we didn't read anything, but can't return length zero, so convert snd_list to pointer to zero block */ snd_list_terminate(snd_list); } else if (n < max_sample_block_len) { /* should free susp */ snd_list_unref(snd_list->u.next); /* if something is in buffer, terminate by pointing to zero block */ snd_list->u.next = zero_snd_list; } } LOCAL void nyx_susp_free(nyx_susp_type susp) { ffree_generic(susp, sizeof(nyx_susp_node), "nyx_susp_free"); } LOCAL void nyx_susp_print_tree(nyx_susp_type susp, int n) { } void nyx_capture_output(nyx_output_callback callback, void *userdata) { nyx_output_cb = callback; nyx_output_ud = userdata; } void nyx_set_audio_params(double rate, long len) { double stretch_len = (len > 0 ? len / rate : 1.0); LVAL warp; /* Bind the sample rate to the "*sound-srate*" global */ setvalue(xlenter("*SOUND-SRATE*"), cvflonum(rate)); /* Bind selection len to "len" global */ setvalue(xlenter("LEN"), cvflonum(len)); /* Set the "*warp*" global based on the length of the audio */ xlprot1(warp); warp = cons(cvflonum(0), /* time offset */ cons(cvflonum(stretch_len), /* time stretch */ cons(NULL, /* cont. time warp */ NULL))); setvalue(xlenter("*WARP*"), warp); xlpop(); } void nyx_set_input_audio(nyx_audio_callback callback, void *userdata, int num_channels, long len, double rate) { sample_type scale_factor = 1.0; time_type t0 = 0.0; nyx_susp_type *susp; sound_type *snd; int ch; nyx_set_audio_params(rate, len); susp = (nyx_susp_type *)malloc(num_channels * sizeof(nyx_susp_type)); snd = (sound_type *)malloc(num_channels * sizeof(sound_type)); for(ch=0; ch < num_channels; ch++) { falloc_generic(susp[ch], nyx_susp_node, "nyx_set_input_audio"); susp[ch]->callback = callback; susp[ch]->userdata = userdata; susp[ch]->len = len; susp[ch]->channel = ch; susp[ch]->susp.fetch = nyx_susp_fetch; susp[ch]->susp.keep_fetch = NULL; susp[ch]->susp.free = nyx_susp_free; susp[ch]->susp.mark = NULL; susp[ch]->susp.print_tree = nyx_susp_print_tree; susp[ch]->susp.name = "nyx"; susp[ch]->susp.toss_cnt = 0; susp[ch]->susp.current = 0; susp[ch]->susp.sr = rate; susp[ch]->susp.t0 = t0; susp[ch]->susp.log_stop_cnt = 0; snd[ch] = sound_create((snd_susp_type)susp[ch], t0, rate, scale_factor); } if (num_channels > 1) { LVAL array = newvector(num_channels); for(ch=0; chstop); } while(result==0) { for(ch=0; chget_next(snd, &cnt); if (block == zero_block || cnt == 0) { result = -1; break; } /* copy the data to a temporary buffer and scale it by the appropriate scale factor */ if (cnt > bufferlen) { if (buffer) free(buffer); buffer = (float *)malloc(cnt * sizeof(float)); if (buffer == NULL) { goto finish; } bufferlen = cnt; } memcpy(buffer, block->samples, cnt * sizeof(float)); for(i=0; iscale; result = callback(buffer, ch, totals[ch], cnt, lens[ch], userdata); if (result != 0) { // The user canceled or some other error occurred, so we use // xlsignal() to jump back to our error handler. xlsignal(NULL, NULL); // never get here. } totals[ch] += cnt; } } success = TRUE; xltoplevel(); finish: gc(); if (buffer) { free(buffer); } if (lens) { free(lens); } if (totals) { free(totals); } if (snds) { free(snds); } #if defined(NYX_MEMORY_STATS) && NYX_MEMORY_STATS printf("\nnyx_get_audio after\n"); xmem(); #endif return success; } int nyx_get_int() { if (nyx_get_type(nyx_result) != nyx_int) return -1; return getfixnum(nyx_result); } double nyx_get_double() { if (nyx_get_type(nyx_result) != nyx_double) return -1.0; return getflonum(nyx_result); } const char *nyx_get_string() { if (nyx_get_type(nyx_result) != nyx_string) return NULL; return (const char *)getstring(nyx_result); } unsigned int nyx_get_num_labels() { LVAL s = nyx_result; int count = 0; if (nyx_get_type(nyx_result) != nyx_labels) return 0; while(s) { count++; s = cdr(s); } return count; } void nyx_get_label(unsigned int index, double *start_time, double *end_time, const char **label) { LVAL s = nyx_result; LVAL label_expr; LVAL t0_expr; LVAL t1_expr; LVAL str_expr; if (nyx_get_type(nyx_result) != nyx_labels) return; while(index) { index--; s = cdr(s); if (s == NULL) { // index was larger than number of labels return; } } /* We either have (t0 "label") or (t0 t1 "label") */ label_expr = car(s); t0_expr = car(label_expr); t1_expr = car(cdr(label_expr)); if (stringp(t1_expr)) { str_expr = t1_expr; t1_expr = t0_expr; } else str_expr = car(cdr(cdr(label_expr))); if (floatp(t0_expr)) *start_time = getflonum(t0_expr); else if (fixp(t0_expr)) *start_time = (double)getfixnum(t0_expr); if (floatp(t1_expr)) *end_time = getflonum(t1_expr); else if (fixp(t1_expr)) *end_time = (double)getfixnum(t1_expr); *label = (const char *)getstring(str_expr); } const char *nyx_get_error_str() { return NULL; } void nyx_set_os_callback(nyx_os_callback callback, void *userdata) { nyx_os_cb = callback; nyx_os_ud = userdata; } void nyx_stop() { xlflush(); xltoplevel(); } void nyx_break() { xlflush(); xlbreak("BREAK", s_unbound); } void nyx_continue() { xlflush(); xlcontinue(); } int ostgetc() { if (nyx_expr_pos < nyx_expr_len) { fflush(stdout); return (nyx_expr_string[nyx_expr_pos++]); } else if (nyx_expr_pos == nyx_expr_len) { /* Add whitespace at the end so that the parser knows that this is the end of the expression */ nyx_expr_pos++; return '\n'; } else return EOF; } /* osinit - initialize */ void osinit(char *banner) { } /* osfinish - clean up before returning to the operating system */ void osfinish(void) { } /* oserror - print an error message */ void oserror(char *msg) { printf("nyx error: %s\n", msg); } long osrand(long n) { return (((int) rand()) % n); } /* cd .. open - open an ascii file */ FILE *osaopen(name,mode) char *name,*mode; { FILE *fp; fp = fopen(name,mode); return fp; } /* osbopen - open a binary file */ FILE *osbopen(char *name, char *mode) { char bmode[10]; FILE *fp; strncpy(bmode, mode, 8); strcat(bmode,"b"); fp = fopen(name,bmode); return fp; } /* osclose - close a file */ int osclose(FILE *fp) { return (fclose(fp)); } /* osagetc - get a character from an ascii file */ int osagetc(FILE *fp) { return (getc(fp)); } /* osaputc - put a character to an ascii file */ int osaputc(int ch, FILE *fp) { return (putc(ch,fp)); } /* osoutflush - flush output to a file */ void osoutflush(FILE *fp) { fflush(fp); } extern int dbgflg; /* osbgetc - get a character from a binary file */ /* int osbgetc(fp) FILE *fp; {return (getc(fp));} */ #ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 int osbgetc(FILE *fp) { return (getc(fp)); } #endif /* osbputc - put a character to a binary file */ int osbputc(int ch, FILE *fp) { return (putc(ch,fp)); } /* ostputc - put a character to the terminal */ void ostputc(int ch) { oscheck(); /* check for control characters */ if (nyx_output_cb) nyx_output_cb(ch, nyx_output_ud); else putchar(((char) ch)); } /* ostoutflush - flush output buffer */ void ostoutflush() { if (!nyx_output_cb) fflush(stdout); } /* osflush - flush the terminal input buffer */ void osflush(void) { } /* oscheck - check for control characters during execution */ void oscheck(void) { if (nyx_os_cb) { nyx_os_cb(nyx_os_ud); } /* if they hit control-c: xflush(); xltoplevel(); return; */ } /* xsystem - execute a system command */ #ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 LVAL xsystem() { if (moreargs()) { unsigned char *cmd; cmd = (unsigned char *)getstring(xlgastring()); fprintf(stderr, "Will not execute system command: %s\n", cmd); } return s_true; } #endif #ifndef WIN32 /* xsetdir -- set current directory of the process */ LVAL xsetdir() { char *dir = (char *)getstring(xlgastring()); int result; LVAL cwd = NULL; xllastarg(); result = chdir(dir); if (result) { perror("SETDIR"); } dir = getcwd(NULL, 1000); if (dir) { cwd = cvstring(dir); free(dir); } return cwd; } #endif /* xgetkey - get a key from the keyboard */ #ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 LVAL xgetkey() {xllastarg(); return (cvfixnum((FIXTYPE)getchar()));} #endif /* ossymbols - enter os specific symbols */ #ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 void ossymbols(void) {} #endif /* xsetupconsole -- used to configure window in Win32 version */ #ifndef WIN32 // duplicated in winfun.c, per James Crook, 7/4/2003 LVAL xsetupconsole() { return NULL; } #endif const char os_pathchar = '/'; const char os_sepchar = ':'; /* control-C handling */ void ctcinit() {} /* xechoenabled -- set/clear echo_enabled flag (unix only) */ LVAL xechoenabled() { return NULL; } /* osdir_list_start -- open a directory listing */ int osdir_list_start(char *path) { return FALSE; } /* osdir_list_next -- read the next entry from a directory */ char *osdir_list_next() { return NULL; } /* osdir_list_finish -- close an open directory */ void osdir_list_finish() { return; } #ifndef WIN32 /* xget_temp_path -- get a path to create temp files */ LVAL xget_temp_path() { char *tmp = getenv("TMPDIR"); if (!tmp || !*tmp) { tmp = getenv("TMP"); if (!tmp || !*tmp) { tmp = "/tmp/"; } } return cvstring(tmp); } #endif #ifndef WIN32 /* xget_user -- get a string identifying the user, for use in file names */ LVAL xget_user() { char *user = getenv("USER"); if (!user || !*user) { user = getenv("USERNAME"); if (!user || !*user) { errputstr("Warning: could not get user ID, using 'nyquist'\n"); user = "nyquist"; } } return cvstring(user); } #endif nyquist-3.05/nyqsrc/multiseq.h0000644000175000000620000000101210144436365015516 0ustar stevestaff/* this typedef goes here because it is needed by add */ typedef struct multiseq_struct { int not_logically_stopped_cnt; int nchans; /* greatest lower bound on logical stop time: */ time_type horizon; /* lowest time corresp to sample count on a snd_list: */ time_type low_water; snd_list_type *chans; time_type t0; rate_type sr; LVAL closure; } multiseq_node, *multiseq_type; LVAL snd_make_multiseq(LVAL s1, LVAL closure); /* LISP: (SND-MULTISEQ ANY ANY) */ nyquist-3.05/nyqsrc/inverse.h0000644000175000000620000000027310144436365015336 0ustar stevestaffsound_type snd_make_inverse(sound_type s, time_type t0, rate_type sr); sound_type snd_inverse(sound_type s, time_type t0, rate_type sr); /* LISP: (snd-inverse SOUND ANYNUM ANYNUM) */ nyquist-3.05/nyqsrc/seqinterf.h0000644000175000000620000000257110144436365015666 0ustar stevestaff/* seqinterf.h -- interface to sequence data type for XLISP */ boolean seq_next(seq_type seq); /* LISP: (SEQ-NEXT SEQ) */ void seq_get(seq_type seq, long *eventtype, long *time, long *line, long *chan, long *value1, long *value2, long *dur); /* LISP: (SEQ-GET SEQ FIXNUM^ FIXNUM^ FIXNUM^ FIXNUM^ FIXNUM^ FIXNUM^ FIXNUM^) */ /* LISP-SRC: (setfn seq-tag first) (setfn seq-time second) (setfn seq-line third) (setfn seq-channel fourth) (defun seq-value1 (e) (nth 4 e)) (setfn seq-pitch seq-value1) ; pitch of a note (setfn seq-control seq-value1) ; control number of a control change (setfn seq-program seq-value1) ; program number of a program change (setfn seq-bend seq-value1) ; pitch bend amount (setfn seq-touch seq-value1) ; aftertouch amount (defun seq-value2 (e) (nth 5 e)) (setfn seq-velocity seq-value2) ; velocity of a note (setfn seq-value seq-value2) ; value of a control change (defun seq-duration (e) (nth 6 e)) */ #define SEQ_DONE 0 /* LISP-SRC: (setf seq-done-tag 0) */ #define SEQ_OTHER 1 /* LISP-SRC: (setf seq-other-tag 1) */ #define SEQ_NOTE 2 /* LISP-SRC: (setf seq-note-tag 2) */ #define SEQ_CTRL 3 /* LISP-SRC: (setf seq-ctrl-tag 3) */ #define SEQ_PRGM 4 /* LISP-SRC: (setf seq-prgm-tag 4) */ #define SEQ_TOUCH 5 /* LISP-SRC: (setf seq-touch-tag 5) */ #define SEQ_BEND 6 /* LISP-SRC: (setf seq-bend-tag 6) */ nyquist-3.05/nyqsrc/compose.h0000644000175000000620000000022710144436365015327 0ustar stevestaffsound_type snd_make_compose(sound_type f, sound_type g); sound_type snd_compose(sound_type f, sound_type g); /* LISP: (snd-compose SOUND SOUND) */ nyquist-3.05/nyqsrc/avg.c0000644000175000000620000002015111466723256014436 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "avg.h" /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ void avg_free(); typedef sample_type (*process_block_type)(/* struct avg_susp_struct *susp */); typedef struct avg_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; /* blocksize is how many input samples to process for an output sample */ long blocksize; /* stepsize is how far to advance to get the next block of samples */ long stepsize; sample_type *buffer; sample_type *fillptr; /* samples are added to buffer at fillptr */ sample_type *endptr; /* until endptr is reached */ process_block_type process_block; } avg_susp_node, *avg_susp_type; sample_type average_block(avg_susp_type susp) { /* this version just computes average */ double sum = 0.0; int i; for (i = 0; i < susp->blocksize; i++) { sum += susp->buffer[i]; } for (i = susp->stepsize; i < susp->blocksize; i++) { susp->buffer[i - susp->stepsize] = susp->buffer[i]; } return (sample_type) (sum / susp->blocksize); } sample_type peak_block(avg_susp_type susp) { /* this version just computes average */ sample_type peak = 0.0F; sample_type minus_peak = 0.0F; int i; for (i = 0; i < susp->blocksize; i++) { sample_type s = susp->buffer[i]; if (s > peak) { peak = s; minus_peak = -s; } else if (s < minus_peak) { minus_peak = s; peak = -s; } } for (i = susp->stepsize; i < susp->blocksize; i++) { susp->buffer[i - susp->stepsize] = susp->buffer[i]; } return peak; } void avg_s_fetch(avg_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo = 0; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_type *fillptr_reg; register sample_type *endptr_reg = susp->endptr; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "avg_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = (max_sample_block_len - cnt) * susp->stepsize; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = MIN(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo/susp->stepsize) { togo = (susp->terminate_cnt - (susp->susp.current + cnt)) * susp->stepsize; if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo/susp->stepsize) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop * susp->stepsize; } } n = togo; s_ptr_reg = susp->s_ptr; fillptr_reg = susp->fillptr; if (n) do { /* the inner sample computation loop */ *fillptr_reg++ = *s_ptr_reg++; if (fillptr_reg >= endptr_reg) { *out_ptr++ = (*(susp->process_block))(susp); cnt++; fillptr_reg -= susp->stepsize; } } while (--n); /* inner loop */ /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; susp->fillptr = fillptr_reg; susp_took(s_cnt, togo); } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* avg_s_fetch */ void avg_toss_fetch(susp, snd_list) avg_susp_type susp; snd_list_type snd_list; { long final_count = MIN(susp->susp.current + max_sample_block_len, susp->susp.toss_cnt); time_type final_time = susp->susp.t0 + final_count / susp->susp.sr; long n; /* fetch samples from s up to final_time for this block of zeros */ while (((long) ((final_time - susp->s->t0) * susp->s->sr + 0.5)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ if (final_count == susp->susp.toss_cnt) { n = ROUND((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; } snd_list->block_len = (short) (final_count - susp->susp.current); susp->susp.current = final_count; snd_list->u.next = snd_list_create((snd_susp_type) susp); snd_list->block = internal_zero_block; } void avg_mark(avg_susp_type susp) { sound_xlmark(susp->s); } void avg_free(avg_susp_type susp) { sound_unref(susp->s); free(susp->buffer); ffree_generic(susp, sizeof(avg_susp_node), "avg_free"); } void avg_print_tree(avg_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_avg(sound_type s, long blocksize, long stepsize, long op) { long buffersize; register avg_susp_type susp; rate_type sr = s->sr; time_type t0 = s->t0; time_type t0_min = t0; falloc_generic(susp, avg_susp_node, "snd_make_avg"); susp->susp.fetch = avg_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); /* minimum start time over all inputs: */ t0_min = MIN(s->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = ROUND((t0 - t0_min) * sr); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = avg_toss_fetch; t0 = t0_min; } /* initialize susp state */ susp->susp.free = avg_free; susp->susp.sr = sr / stepsize; susp->susp.t0 = t0; susp->susp.mark = avg_mark; susp->susp.print_tree = avg_print_tree; susp->susp.name = "avg"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->blocksize = blocksize; susp->stepsize = stepsize; /* We need at least blocksize samples in buffer, but if stepsize > blocksize, it is convenient to put stepsize samples in buffer. This allows us to step ahead by stepsize samples just by flushing the buffer. */ buffersize = MAX(blocksize, stepsize); susp->buffer = (sample_type *) malloc(buffersize * sizeof(sample_type)); susp->fillptr = susp->buffer; susp->endptr = susp->buffer + buffersize; susp->process_block = average_block; if (op == op_peak) susp->process_block = peak_block; /* scale factor gets passed to output signal: */ return sound_create((snd_susp_type) susp, t0, susp->susp.sr, susp->s->scale); } sound_type snd_avg(sound_type s, long blocksize, long stepsize, long op) { sound_type s_copy = sound_copy(s); return snd_make_avg(s_copy, blocksize, stepsize, op); } nyquist-3.05/nyqsrc/sndfail.c0000644000175000000620000000062510144436365015277 0ustar stevestaff #include "stdio.h" #include "snd.h" #include "stdlib.h" #include "xlisp.h" #include "string.h" void snd_fail(char *msg) { char *bigger = (char *) malloc(strlen(msg) + 16); if (!bigger) xlfail("no memory"); strcpy(bigger, "(snd)"); strcat(bigger, msg); xlfail(bigger); // NOTE: there is a memory leak here } void snd_warn(char *msg) { stdputstr(msg); stdputstr("\n"); } nyquist-3.05/nyqsrc/multiread.h0000644000175000000620000000023110144436365015643 0ustar stevestaffLVAL multiread_create(read_susp_type susp); void multiread_fetch(read_susp_type susp, snd_list_type snd_list); void multiread_free(read_susp_type susp); nyquist-3.05/nyqsrc/seqfnint.lsp0000644000175000000620000000147310144436365016064 0ustar stevestaff (setfn seq-tag first) (setfn seq-time second) (setfn seq-line third) (setfn seq-channel fourth) (defun seq-value1 (e) (nth 4 e)) (setfn seq-pitch seq-value1) ; pitch of a note (setfn seq-control seq-value1) ; control number of a control change (setfn seq-program seq-value1) ; program number of a program change (setfn seq-bend seq-value1) ; pitch bend amount (setfn seq-touch seq-value1) ; aftertouch amount (defun seq-value2 (e) (nth 5 e)) (setfn seq-velocity seq-value2) ; velocity of a note (setfn seq-value seq-value2) ; value of a control change (defun seq-duration (e) (nth 6 e)) (setf seq-done-tag 0) (setf seq-other-tag 1) (setf seq-note-tag 2) (setf seq-ctrl-tag 3) (setf seq-prgm-tag 4) (setf seq-touch-tag 5) (setf seq-bend-tag 6) nyquist-3.05/nyqsrc/fftr4.c0000644000175000000620000001417610144436365014712 0ustar stevestaff#include #include #include #ifdef WIN32 #include #else #include #endif #define PI 3.14159265359 #define MAXPOW 24 struct complex { double r; double i; }; int pow_2[MAXPOW]; int pow_4[MAXPOW]; void twiddle(struct complex *W, int N, double stuff) { W->r=cos(stuff*2.0*PI/(double)N); W->i=-sin(stuff*2.0*PI/(double)N); } void bit_reverse_reorder(struct complex *W, int N) { int bits, i, j, k; double tempr, tempi; for (i=0; ii) /** Only make "up" swaps */ { tempr=W[i].r; tempi=W[i].i; W[i].r=W[j].r; W[i].i=W[j].i; W[j].r=tempr; W[j].i=tempi; } } } void bit_r4_reorder(struct complex *W, int N) { int bits, i, j, k; double tempr, tempi; for (i=0; ii) /** Only make "up" swaps */ { tempr=W[i].r; tempi=W[i].i; W[i].r=W[j].r; W[i].i=W[j].i; W[j].r=tempr; W[j].i=tempi; } } } /** RADIX-4 FFT ALGORITHM */ void radix4(struct complex *x, int N) { int n2, k1, N1, N2; struct complex W, bfly[4]; N1=4; N2=N/4; /** Do 4 Point DFT */ for (n2=0; n20, then evaluate a closure to get a signal and convert to an add of the new signal and a copy of this trigger object. The sample rate of the output is the sample rate of the input, and sounds returned by the closure must also have a matching sample rate. The trigger will take place on the first input sample (zero delay) if the first sample of the input is >0. The input scale factor is assumed to be 1, so caller should force scaling especially if the scale factor is negative (!) The trigger terminates when the input signal terminates (but any adds continue to run until all their inputs terminate). Some implementation notes: The closure gets evaluated at the time of the positive sample. When the positive sample is encountered, first close off the current output block. Next, evaluate the closure, clone the trigger, and convert the current trigger to an add. The next fetch will therefore go to the add susp and it will add the closure result to the zeros that continue to be generated by (a clone of) the trigger. It would be simple if we could back the clone up one sample: on the first call to the add, it will ask for samples from the trigger clone and the closure, but the trigger clone has already processed the positive sample, so it is one sample ahead of everyone else. Since we've just read a sample, we CAN back up just by carefully updating the input pointer to one less than we actually read, forcing a reread later. (We'll still store the previous value so re-reading will not re-trigger.) */ /* CHANGE LOG * -------------------------------------------------------------------- * 13Dec06 rbd created from sndseq.c */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "scale.h" #include "add.h" #include "extern.h" #include "cext.h" #include "assert.h" #define TRIGGERDBG 0 #define D if (TRIGGERDBG) /* Note: this structure is identical to an add_susp structure up to the field output_per_s2 so that we can convert this into an add after eval'ing the closure. Since this struct is bigger than an add, make sure not to clobber the "free" routine (trigger_free) or else we'll leak memory. */ typedef struct trigger_susp_struct { snd_susp_node susp; boolean started; int terminate_bits; long terminate_cnt; int logical_stop_bits; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_type s1_bptr; /* block pointer */ sample_block_values_type s1_ptr; sound_type s2; long s2_cnt; sample_block_type s2_bptr; /* block pointer */ sample_block_values_type s2_ptr; /* trigger-specific data starts here */ sample_type previous; LVAL closure; } trigger_susp_node, *trigger_susp_type; void trigger_fetch(trigger_susp_type, snd_list_type); void trigger_free(); extern LVAL s_stdout; void trigger_mark(trigger_susp_type susp) { sound_xlmark(susp->s1); if (susp->closure) mark(susp->closure); } /* trigger_fetch returns zero blocks until s1 goes from <=0 to >0 */ /**/ void trigger_fetch(trigger_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "trigger_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block */ togo = max_sample_block_len - cnt; /* don't run past the input sample block: */ susp_check_term_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; input_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ sample_type s = *input_ptr_reg++; if (susp->previous <= 0 && s > 0) { trigger_susp_type new_trigger; sound_type new_trigger_snd; LVAL result; long delay; /* sample delay to s2 */ time_type now; susp->previous = s; /* don't retrigger */ /**** close off block ****/ togo = togo - n; susp->s1_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; snd_list->block_len = cnt; susp->susp.current += cnt; now = susp->susp.t0 + susp->susp.current / susp->susp.sr; /**** eval closure and add result ****/ D nyquist_printf("trigger_fetch: about to eval closure at %g, " "susp->susp.t0 %g, susp.current %d:\n", now, susp->susp.t0, (int)susp->susp.current); xlsave1(result); result = xleval(cons(susp->closure, consa(cvflonum(now)))); if (exttypep(result, a_sound)) { susp->s2 = sound_copy(getsound(result)); D nyquist_printf("trigger: copied result from closure is %p\n", susp->s2); } else xlerror("closure did not return a (monophonic) sound", result); D nyquist_printf("in trigger: after evaluation; " "%p returned from evform\n", susp->s2); result = NIL; /**** cloan this trigger to become s1 ****/ falloc_generic(new_trigger, trigger_susp_node, "new_trigger"); memcpy(new_trigger, susp, sizeof(trigger_susp_node)); /* don't copy s2 -- it should only be referenced by add */ new_trigger->s2 = NULL; new_trigger_snd = sound_create((snd_susp_type) new_trigger, now, susp->susp.sr, 1.0F); susp->s1 = new_trigger_snd; /* add will have to ask new_trigger for samples, new_trigger * will continue reading samples from s1 (the original input) */ susp->s1_cnt = 0; susp->s1_ptr = NULL; /**** convert to add ****/ susp->susp.mark = add_mark; /* logical stop will be recomputed by add: */ susp->susp.log_stop_cnt = UNKNOWN; susp->susp.print_tree = add_print_tree; /* assume sample rates are the same */ if (susp->s1->sr != susp->s2->sr) xlfail("in trigger: sample rates must match"); /* take care of scale factor, if any */ if (susp->s2->scale != 1.0) { // stdputstr("normalizing next sound in a seq\n"); susp->s2 = snd_make_normalize(susp->s2); } /* figure out which add fetch routine to use */ delay = ROUND((susp->s2->t0 - now) * susp->s1->sr); if (delay > 0) { /* fill hole between s1 and s2 */ D stdputstr("using add_s1_nn_fetch\n"); susp->susp.fetch = add_s1_nn_fetch; susp->susp.name = "trigger:add_s1_nn_fetch"; } else { susp->susp.fetch = add_s1_s2_nn_fetch; susp->susp.name = "trigger:add_s1_s2_nn_fetch"; } D stdputstr("in trigger: calling add's fetch\n"); /* fetch will get called later .. (*(susp->susp.fetch))(susp, snd_list); */ D stdputstr("in trigger: returned from add's fetch\n"); xlpop(); susp->closure = NULL; /* allow garbage collection now */ /**** calculation tree modified, time to exit ****/ /* but if cnt == 0, then we haven't computed any samples */ /* call on new fetch routine to get some samples */ if (cnt == 0) { ffree_sample_block(out, "trigger-pre-adder"); // because adder will reallocate (*susp->susp.fetch)(susp, snd_list); } return; } else { susp->previous = s; /* output zero until ready to add in closure */ *out_ptr_reg++ = 0; } } while (--n); /* inner loop */ /* using input_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* trigger_fetch */ void trigger_free(trigger_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->s2); ffree_generic(susp, sizeof(trigger_susp_node), "trigger_free"); } void trigger_print_tree(trigger_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("closure:"); stdprint(susp->closure); indent(n); stdputstr("s2:"); sound_print_tree_1(susp->s2, n); } sound_type snd_make_trigger(s1, closure) sound_type s1; LVAL closure; { register trigger_susp_type susp; /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; sound_type result; xlprot1(closure); falloc_generic(susp, trigger_susp_node, "snd_make_trigger"); if (s1->scale != 1.0) { /* stdputstr("normalizing first sound in a seq\n"); */ s1 = snd_make_normalize(s1); } susp->susp.fetch = trigger_fetch; susp->terminate_cnt = UNKNOWN; susp->terminate_bits = 0; /* bits for s1 and s2 termination */ susp->logical_stop_bits = 0; /* bits for s1 and s2 logical stop */ /* initialize susp state */ susp->susp.free = trigger_free; susp->susp.sr = s1->sr; susp->susp.t0 = s1->t0; susp->susp.mark = trigger_mark; susp->susp.print_tree = trigger_print_tree; susp->susp.name = "trigger"; susp->logically_stopped = false; susp->susp.log_stop_cnt = s1->logical_stop_cnt; susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->s2 = NULL; susp->s2_cnt = 0; susp->closure = closure; susp->previous = 0; result = sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, scale_factor); xlpopn(1); return result; } sound_type snd_trigger(s1, closure) sound_type s1; LVAL closure; { sound_type s1_copy; s1_copy = sound_copy(s1); return snd_make_trigger(s1_copy, closure); } nyquist-3.05/nyqsrc/sndfnint.lsp0000644000175000000620000000221411466723256016060 0ustar stevestaff (setf snd-head-none 0) (setf snd-head-AIFF 1) (setf snd-head-IRCAM 2) (setf snd-head-NeXT 3) (setf snd-head-Wave 4) (setf snd-head-PAF 5) (setf snd-head-SVX 6) (setf snd-head-NIST 7) (setf snd-head-VOC 8) (setf snd-head-W64 9) (setf snd-head-MAT4 10) (setf snd-head-MAT5 11) (setf snd-head-PVF 12) (setf snd-head-XI 13) (setf snd-head-HTK 14) (setf snd-head-SDS 15) (setf snd-head-AVR 16) (setf snd-head-SD2 17) (setf snd-head-FLAC 18) (setf snd-head-CAF 19) (setf snd-head-raw 20) (setf snd-head-channels 1) (setf snd-head-mode 2) (setf snd-head-bits 4) (setf snd-head-srate 8) (setf snd-head-dur 16) (setf snd-head-latency 32) (setf snd-head-type 64) (setf snd-mode-adpcm 0) (setf snd-mode-pcm 1) (setf snd-mode-ulaw 2) (setf snd-mode-alaw 3) (setf snd-mode-float 4) (setf snd-mode-upcm 5) (setf snd-mode-unknown 6) (setf snd-mode-double 7) (setf snd-mode-GSM610 8) (setf snd-mode-DWVW 9) (setf snd-mode-DPCM 10) (setf snd-mode-msadpcm 11) (SETF MAX-STOP-TIME 10E20) (SETF MIN-START-TIME -10E20) (setf OP-AVERAGE 1) (setf OP-PEAK 2) nyquist-3.05/nyqsrc/falloc.h0000644000175000000620000001660211466723256015134 0ustar stevestaff/* * falloc.h * nyquist memory allocation data structures and macros * * there is an falloc and ffree for each major type of data structure * there is an falloc and ffree for generic (not so common) structures * there is an frelease for some structures. this reduces the * reference count for the particular structure by 1; it * does not continue recursively. */ /* Debugging support: * When DEBUG_MEM is set, each piece of allocated storage will contain * a pointer to a string naming the caller or other allocation info, * and a sequence number. (8 extra bytes are allocated for this info). * * When storage is freed, the ID is set to NULL, and the routine * dbg_mem_check(ptr) will abort if ID is NULL. Call this routine to * avoid following a pointer to data that was previously freed. * * The goal of this support is to allow you to "go back" to the point * where memory is corrupted; specifically where a memory block is freed * too early. * * When a memory-related bug is crashing the system: * (1) Recompile with DEBUG_MEM on. * (2) Develop some Nyquist code that will predictably crash the system. * (3) When Nyquist crashes, use a debugger to find where the bad * pointer came from. See if the source of the pointer was freed. * (4) If the source of the pointer was freed, then notice the sequence * number. * (5) Rerun with dbg_mem_seq_num set to the number noted in (4). * (6) Nyquist will print when the storage in question was allocated and * freed. Use the debugger to find out why the storage is * freed too early and who did it. * (7) If the source of the pointer in (3) was not freed, you're on your * own. * * The DEBUG_MEM related routines are: * dbg_mem_allocated: called when memory is allocated * dbg_mem_freed: called when memory is freed * dbg_mem_released: called when memory is released * dbg_mem_check: called to check memory * * see also xldmem.c: * by setting xldmem_trace to a pointer, you can trace when the * pointer is referenced by anything in the heap */ /* to get size_t on pmax: */ #ifdef pmax #include "sys/types.h" #endif #include "cque.h" #include "debug.h" #define DEBUG_MEM 0 #define DEBUG_MEM_INFO_SIZE (sizeof(long) + sizeof(char *)) /* special free lists */ extern CQUE *sample_block_free; /* really a sample_block_type */ /* special counts */ extern int sample_block_total; extern int sample_block_used; extern int snd_list_used; extern int sound_used; extern long table_memory; /* generic free lists */ #define MAXLISTS 128 extern CQUE *generic_free[MAXLISTS]; /* general memory pool */ #define MAXPOOLSIZE 1000000 extern char *poolp; extern char *poolend; /* sample block memory pool */ #define MAXSPOOLSIZE (256 * round_size(sizeof(sample_block_node))) extern char *spoolp; extern char *spoolend; extern int npools; extern int sample_blocks_since_gc; #if !defined(TRACK_POOLS) #define TRACK_POOLS 1 #endif #if defined(TRACK_POOLS) && TRACK_POOLS // extern CQUE *pools; void falloc_gc(); #endif void falloc_init(void); void new_pool(void); void new_spool(void); sample_block_type find_sample_block(void); char *get_from_pool(size_t siz); #define round_size(n) (((n) + 7) & ~7) /* check_pool -- returns true if enough bytes are available */ #if DEBUG_MEM #define check_pool(size) (poolp + (size) + DEBUG_MEM_INFO_SIZE <= poolend) #define check_spool(size) (spoolp + (size) + DEBUG_MEM_INFO_SIZE <= spoolend) #define DBG_MEM_ALLOCATED(p, who) dbg_mem_allocated(p, who) #define DBG_MEM_FREED(p, who) dbg_mem_freed(p, who) #define DBG_MEM_RELEASED(p, who) dbg_mem_released(p, who) #else #define check_pool(size) (poolp + (size) <= poolend) #define check_spool(size) (spoolp + (size) <= spoolend) #define DBG_MEM_ALLOCATED(p, who) #define DBG_MEM_FREED(p, who) #define DBG_MEM_RELEASED(p, who) #endif #define BLOCKS_PER_GC 100 #define falloc_sample_block(sp, who) { \ if (!Qempty(sample_block_free)) \ Qget(sample_block_free, sample_block_type, sp) \ else sp = find_sample_block(); \ /* sample_block_test(sp, "falloc_sample_block"); */ \ /* printf("[%x] ", sp); */ \ DBG_MEM_ALLOCATED(sp, who); \ sp->refcnt = 1; \ sample_block_used++; \ } #define ffree_sample_block(sp, who) { \ /* printf("freeing sample_block@%x\n", sp); */ \ DBG_MEM_FREED(sp, who); \ Qenter(sample_block_free, sp); \ sample_block_used--; \ } #define frelease_sample_block(sp, who) { \ sp->refcnt--; \ DBG_MEM_RELEASED(sp, who); \ if (sp->refcnt <= 0) { \ ffree_sample_block(sp); \ } \ } /* NOTE: This must not cause garbage collection. * LVAL parameters to snd_make_? functions are not * protected and falloc_sound is invoked there. */ #define snd_list_free (generic_free[round_size(sizeof(snd_list_node)) >> 3]) #define falloc_snd_list(sp, who) { \ if (!Qempty(snd_list_free)) \ Qget(snd_list_free, snd_list_type, sp) \ else \ sp = (snd_list_type)get_from_pool(round_size(sizeof(snd_list_node)));\ snd_list_used++; \ DBG_MEM_ALLOCATED(sp, who); \ } #define ffree_snd_list(sp, who) { \ DBG_MEM_FREED(sp, who); \ Qenter(snd_list_free, sp); \ snd_list_used--; \ } #define frelease_snd_list(sp, who) { \ sp->refcnt--; \ DBG_MEM_RELEASED(sp, who); \ if (sp->refcnt <= 0) { \ ffree_snd_list(sp, who); \ } \ } #define sound_free (generic_free[round_size(sizeof(sound_node)) >> 3]) #define NORMALSOUNDALLOC #ifdef NORMALSOUNDALLOC #define falloc_sound(sp, who) { \ if (!Qempty(sound_free)) { \ Qget(sound_free, sound_type, sp); \ } else { \ sp = (sound_type) get_from_pool(round_size(sizeof(sound_node))); \ } \ sound_used++; \ DBG_MEM_ALLOCATED(sp, who); \ } #else #define falloc_sound(sp) \ sp =(sound_type) \ get_from_pool(round_size(sizeof(sound_node))) #endif /* note: usually you call sound_unref, not this macro */ #define ffree_sound(sp, who) { \ /* sound_already_free_test(); */ \ DBG_MEM_FREED(sp, who); \ Qenter(sound_free, sp); \ sound_used--; \ } /* falloc_generic -- sp gets new node of type sptype */ /**/ #define falloc_generic(sp, sptype, who) { \ int size = round_size(sizeof(sptype)); \ falloc_generic_bytes(sp, sptype, size, who) } /* falloc_generic_n -- sp gets new array of n sptype's */ /**/ #define falloc_generic_n(sp, sptype, n, who) { \ int min_size = sizeof(sptype) * (n); \ int size = round_size(min_size); \ falloc_generic_bytes(sp, sptype, size, who) } #define falloc_generic_bytes(sp, sptype, size, who) \ if ((size >> 3) >= MAXLISTS) { \ stdputstr("falloc_generic problem\n"); \ sp = (sptype *) malloc(size); \ } else if (!Qempty(generic_free[size >> 3])) { \ Qget(generic_free[size >> 3], sptype *, sp); \ } else { \ sp = (sptype *) get_from_pool(size); \ } \ DBG_MEM_ALLOCATED(sp, who); \ /* printf("GENERIC ALLOC %x\n", sp); */ /* ffree_generic puts an item back on proper freelist */ /* NOTE: sIzE is capitalized funny so that it will not * match an actual parameter, e.g. if the caller writes * ffree_generic(ptr, size), we don't want the expanded * code to include: "int size = round_size(size) >> 3"! */ #define ffree_generic(sp, nn, who) { \ int sIzE = round_size(nn) >> 3; \ DBG_MEM_FREED(sp, who); \ /* printf("GENERIC FREE %x SIZE %d\n", sp, nnn); */ \ if ((sIzE) >= MAXLISTS) { \ free(sp); \ } else { \ Qenter(generic_free[sIzE], sp); \ } \ } nyquist-3.05/nyqsrc/f0.cpp0000644000175000000620000000716711466723256014542 0ustar stevestaff// f0 -- frequency estimation #include // Estimate a local minimum (or maximum) using parabolic // interpolation. The parabola is defined by the points // (x1,y1),(x2,y2), and (x3,y3). float parabolic_interp(float x1, float x2, float x3, float y1, float y2, float y3, float *min) { float a, b, c; float pos; // y1=a*x1^2+b*x1+c // y2=a*x2^2+b*x2+c // y3=a*x3^2+b*x3+c // y1-y2=a*(x1^2-x2^2)+b*(x1-x2) // y2-y3=a*(x2^2-x3^2)+b*(x2-x3) // (y1-y2)/(x1-x2)=a*(x1+x2)+b // (y2-y3)/(x2-x3)=a*(x2+x3)+b a= ((y1-y2)/(x1-x2)-(y2-y3)/(x2-x3))/(x1-x3); b= (y1-y2)/(x1-x2) - a*(x1+x2); c= y1-a*x1*x1-b*x1; *min= c; // dy/dx = 2a*x + b = 0 pos= -b/2.0/a; return pos; } float f0_estimate(float *samples, int n, int m, float threshold, float *results, float *min) // samples is a buffer of samples // n is the number of samples, equals twice longest period, must be even // m is the shortest period in samples // results is an array of size n/2 - m + 1, the number of different lags { // work from the middle of the buffer: int middle = n / 2; int i, j; // loop counters // how many different lags do we compute? float left_energy = 0; float right_energy = 0; // for each window, we keep the energy so we can compute the next one // incrementally. First, we need to compute the energies for lag m-1: for (i = 0; i < m - 1; i++) { float left = samples[middle - 1 - i]; left_energy += left * left; float right = samples[middle + i]; right_energy += right * right; } for (i = m; i <= middle; i++) { // i is the lag and the length of the window // compute the energy for left and right float left = samples[middle - i]; left_energy += left * left; float right = samples[middle - 1 + i]; right_energy += right * right; // compute the autocorrelation float auto_corr = 0; for (j = 0; j < i; j++) { auto_corr += samples[middle - i + j] * samples[middle + j]; } float non_periodic = (left_energy + right_energy - 2 * auto_corr);// / i; results[i - m] = non_periodic; } // normalize by the cumulative sum float cum_sum=0.0; for (i = m; i <= middle; i++) { cum_sum+=results[i-m]; results[i-m]=results[i-m]/(cum_sum/(i-m+1)); } int min_i=m; // value of initial estimate for (i = m; i <= middle; i++) { if (results[i - m] < threshold) { min_i=i; break; } else if (results[i-m]m && iMIN, max->MAX */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "assert.h" #include "falloc.h" #include "cext.h" #include "resamp.h" #include "fresample.h" #include "ffilterkit.h" #include "fsmallfilter.h" /* Algorithm: To resample, we convolve a sinc function with the input stream at times corresponding to the output samples. This requires a sliding window on the input samples. Since samples are accessed a block at a time, the places where the sliding window would span two blocks are too tricky for me. Instead of trying to manage the breaks across blocks, I copy the blocks into another buffer (called X). When the sliding window reaches the end of X, the samples at the end of X are copied to the beginning of X, the remainder of X is filled with new samples, and the computation continues. The trickiest part of all this is keeping all the pointers and phase accumulators correct when the sliding window is relocated from the end of X to the beginning. Although there are different ways to do this, I decided that the output would always go directly to a Nyquist sample block, so the resampling routines (SrcUp and SrcUD) are always called upon to compute max_sample_block_len samples (except that a partial block may be computed when the input sound terminates). To compute max_sample_block_len samples, the input buffer needs: - max_sample_block_len/factor samples, where factor is the ratio of the new sample rate to the old one. I.e. if upsampling by a factor of 2, the input buffer needs half the samples of the output block size. - additional samples the size of the sliding window. Since the output is taken from the center of the window, we can't take samples from the first or last windowsize/2 samples. - to simplify rounding, we throw in some extra samples. This costs only a bit of space and an extra copy for each spare sample. The window size is determined by the particular filter used and by factor (the sample rate ratio). The filter size is Nmult, the number of filter coefficients. When upsampling, this is the window size (the filter acts as a reconstruction filter for the additional samples). When downsampling, the filter is stretched by 1/factor (the filter acts as an anti-aliasing low-pass filter). */ void resample_free(); typedef struct resample_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; float *X; long Xsize; double Time; /* location (offset) in X of next output sample */ double LpScl; double factor; sample_type *Imp; sample_type *ImpD; boolean interpFilt; int Nmult; int Nwing; int Xp; /* first free location at end of X */ int Xoff; /* number of extra samples at beginning and end of X */ } resample_susp_node, *resample_susp_type; /* Sampling rate up-conversion only subroutine; * Slightly faster than down-conversion; */ static int SrcUp(float X[], float Y[], double factor, double *Time, int Nx, int Nwing, double LpScl, float Imp[], float ImpD[], boolean Interp) { mem_float *Xp, *Ystart; fast_float v; double dt; /* Step through input signal */ mem_float *Yend; /* When Y reaches Yend, return to user */ /* nyquist_printf("SrcUp: interpFilt %d\n", Interp);*/ dt = 1.0/factor; /* Output sampling period */ Ystart = Y; Yend = Y + Nx; while (Y < Yend) { long iTime = (long) *Time; Xp = &X[iTime]; /* Ptr to current input sample */ /* Perform left-wing inner product */ v = FilterUp(Imp, ImpD, Nwing, Interp, Xp, *Time - iTime, -1); /* Perform right-wing inner product */ v += FilterUp(Imp, ImpD, Nwing, Interp, Xp+1, (1 + iTime) - *Time, 1); v *= LpScl; /* Normalize for unity filter gain */ /* nyquist_printf("SrcUp output sample %g\n", v); */ *Y++ = (float) v; *Time += dt; /* Move to next sample by time increment */ } return (Y - Ystart); /* Return the number of output samples */ } /* Sampling rate conversion subroutine */ static int SrcUD(float X[], float Y[], double factor, double *Time, int Nx, int Nwing, double LpScl, float Imp[], float ImpD[], boolean Interp) { mem_float *Xp, *Ystart; fast_float v; double dh; /* Step through filter impulse response */ double dt; /* Step through input signal */ mem_float *Yend; /* When Y reaches Yend, return to user */ dt = 1.0/factor; /* Output sampling period */ dh = MIN(Npc, factor*Npc); /* Filter sampling period */ Ystart = Y; Yend = Y + Nx; while (Y < Yend) { long iTime = (long) *Time; Xp = &X[iTime]; /* Ptr to current input sample */ v = FilterUD(Imp, ImpD, Nwing, Interp, Xp, *Time - iTime, -1, dh); /* Perform left-wing inner product */ v += FilterUD(Imp, ImpD, Nwing, Interp, Xp+1, (1 + iTime) - *Time, 1, dh); /* Perform right-wing inner product */ v *= LpScl; /* Normalize for unity filter gain */ *Y++ = (float) v; *Time += dt; /* Move to next sample by time increment */ } return (Y - Ystart); /* Return the number of output samples */ } void resample__fetch(register resample_susp_type susp, snd_list_type snd_list) { int togo; int n; int Nout; sample_block_type out; /* note that in this fetch routine, out_ptr is used to remember where * to put the "real" output, while X_ptr_reg is used in the inner * loop that copies input samples into X, a buffer */ register sample_block_values_type out_ptr; register sample_block_values_type X_ptr_reg; register sample_type *s_ptr_reg; falloc_sample_block(out, "resample__fetch"); out_ptr = out->samples; snd_list->block = out; /* Algorithm: Fetch samples until X (the buffered input) is full. X stores enough contiguous samples that a sliding window convolving with the filter coefficients can output a full block without sliding beyond the range of X. Every time we reenter resample__fetch, we take the remaining samples at the end of X, shift them to the beginning, and refill. After X is full, call on SrcUp or SrcUD to compute an output block. The first time resample__fetch is called, the fill pointer Xp will point near the beginning of X, indicating that no previously read samples need to be shifted from the end of X to the beginning. */ /* first, shift samples from end of X to beginning if necessary */ if (susp->Xp > 2 * susp->Xoff) { int i; int shiftcount = (long) (susp->Time) - susp->Xoff; /* nyquist_printf("shift %d from %d to %lx\n", susp->Xsize + susp->Xoff - susp->Xp, susp->Xp - susp->Xoff, susp->X); */ for (i = 0; i < susp->Xp - shiftcount; i++) { susp->X[i] = susp->X[i + shiftcount]; /* if (susp->X[i] == 0.0) nyquist_printf("shifted zero to X[%d]\n", i);*/ } susp->Time -= shiftcount; susp->Xp -= shiftcount; } while (susp->Xp < susp->Xsize) { /* outer loop */ /* read samples from susp->s into X */ togo = susp->Xsize - susp->Xp; /* don't run past the s input sample block. If termination or * logical stop info become available, translate to susp->terminate_cnt * and susp->log_stop_cnt. */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = MIN(togo, susp->s_cnt); memcpy(susp->X + susp->Xp, susp->s_ptr, togo * sizeof(sample_type)); susp->s_ptr += togo; susp_took(s_cnt, togo); susp->Xp += togo; } /* outer loop */ /* second, compute samples to output, this is done in one pass because * we have enough data in X */ /* don't run past terminate time */ togo = max_sample_block_len; if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + max_sample_block_len) { togo = susp->terminate_cnt - susp->susp.current; } if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - susp->susp.current; assert(to_stop >= 0); if (to_stop < togo) { if (to_stop == 0) susp->logically_stopped = true; else togo = to_stop; } } if (togo == 0) { /* stdputstr("resamp calling snd_list_terminate\n"); */ snd_list_terminate(snd_list); } else { if (susp->factor >= 1) { /* SrcUp() is faster if we can use it */ Nout = SrcUp(susp->X, out_ptr, susp->factor, &susp->Time, togo, susp->Nwing, susp->LpScl, susp->Imp, susp->ImpD, susp->interpFilt); } else { Nout = SrcUD(susp->X, out_ptr, susp->factor, &susp->Time, togo, susp->Nwing, susp->LpScl, susp->Imp, susp->ImpD, susp->interpFilt); } snd_list->block_len = togo; susp->susp.current += togo; } #ifdef RESAMPTEST for (n = 0; n < snd_list->block_len; n++) { if (out->samples[n] == 0.0) { nyquist_printf("resamp: zero at samples[%d]\n", n); } } #endif /* if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } */ } /* resample__fetch */ void resample_mark(resample_susp_type susp) { sound_xlmark(susp->s); } void resample_free(resample_susp_type susp) { sound_unref(susp->s); free(susp->X); ffree_generic(susp, sizeof(resample_susp_node), "resample_free"); } void resample_print_tree(resample_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_resample(sound_type s, rate_type sr) { register resample_susp_type susp; int i; falloc_generic(susp, resample_susp_node, "snd_make_resample"); susp->susp.fetch = resample__fetch; susp->Nmult = SMALL_FILTER_NMULT; susp->Imp = SMALL_FILTER_IMP; susp->ImpD = SMALL_FILTER_IMPD; /* these scale factors are here because filter coefficients are expressed as integers, and so is SMALL_FILTER_SCALE: */ susp->LpScl = SMALL_FILTER_SCALE / 32768.0; susp->LpScl /= 16384.0; /* this is just a fudge factor, is SMALL_FILTER_SCALE wrong? */ susp->LpScl /= 1.0011; susp->Nwing = SMALL_FILTER_NWING; susp->factor = sr / s->sr; if (susp->factor < 1) susp->LpScl *= susp->factor; /* factor in the scale factor of s, since resample is linear */ susp->LpScl *= s->scale; susp->terminate_cnt = UNKNOWN; /* initialize susp state */ susp->susp.free = resample_free; susp->susp.sr = sr; susp->susp.t0 = s->t0; susp->susp.mark = resample_mark; susp->susp.print_tree = resample_print_tree; susp->susp.name = "resample"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->Xoff = (int) (((susp->Nmult + 1) / 2.0) * MAX(1.0, 1.0 / susp->factor) + 10); susp->Xsize = (long) ((max_sample_block_len / susp->factor) + 2 * susp->Xoff); susp->X = calloc(susp->Xsize, sizeof(sample_type)); susp->Xp = susp->Xoff; susp->Time = susp->Xoff; susp->interpFilt = true; for (i = 0; i < susp->Xoff; i++) susp->X[i] = 0.0F; return sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, 1.0 /* scale factor */); } sound_type snd_resample(sound_type s, rate_type sr) { sound_type s_copy = sound_copy(s); return snd_make_resample(s_copy, sr); } nyquist-3.05/nyqsrc/compose.c0000644000175000000620000002364210144436365015330 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "compose.h" /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ void compose_free(); typedef struct compose_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type f; long f_cnt; sample_block_values_type f_ptr; sample_type f_prev; double f_time; double f_time_increment; boolean started; sound_type g; long g_cnt; sample_block_values_type g_ptr; } compose_susp_node, *compose_susp_type; /* compose_fetch -- computes f(g(t)) */ /**/ void compose_fetch(register compose_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo = 0; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_block_values_type g_ptr_reg; register sample_block_values_type f_ptr_reg; falloc_sample_block(out, "compose_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure we are primed with first value of f */ /* This is a lot of work just to prefetch susp->f_prev! */ if (!susp->started) { susp->started = true; /* see comments below about susp_check_term_log_samples() */ if (susp->f_cnt == 0) { susp_get_samples(f, f_ptr, f_cnt); if (susp->f_ptr == zero_block->samples) { susp->terminate_cnt = susp->susp.current; } } susp->f_prev = susp_fetch_sample(f, f_ptr, f_cnt); susp->f_time += susp->f_time_increment; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the f input sample block: */ /* most fetch routines call susp_check_term_log_samples() here * but we can't becasue susp_check_term_log_samples() assumes * that output time progresses at the same rate as input time. * Here, some time warping is going on, so this doesn't work. * Instead, check for termination of f and fix terminate_cnt to * be the current output count rather than the current input time. */ if (susp->f_cnt == 0) { susp_get_samples(f, f_ptr, f_cnt); if (susp->f->logical_stop_cnt == susp->f->current - susp->f_cnt) { if (susp->susp.log_stop_cnt == UNKNOWN) { susp->susp.log_stop_cnt = susp->susp.current + cnt; } } if (susp->f_ptr == zero_block->samples) { susp->terminate_cnt = susp->susp.current + cnt; /* we can't simply terminate here because we might have * some output samples computed already, in which case we * want to return them now and terminate the NEXT time we're * called. */ } } #ifdef CUT /* don't run past the f input sample block: */ susp_check_term_log_samples(f, f_ptr, f_cnt); togo = MIN(togo, susp->f_cnt); #endif /* don't run past the g input sample block: */ susp_check_term_samples(g, g_ptr, g_cnt); togo = MIN(togo, susp->g_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); if (to_stop < togo && ((togo = to_stop) == 0)) break; } n = togo; g_ptr_reg = susp->g_ptr; f_ptr_reg = susp->f_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double g_of_t = *g_ptr_reg; #if 0 float tmp; /* for debugging */ nyquist_printf("output sample %d, g_of_t %g", susp->susp.current + cnt, g_of_t); #endif /* now we scan f and interpolate at time point g_of_t */ while (susp->f_time < g_of_t) { susp->f_time += susp->f_time_increment; susp->f_prev = *f_ptr_reg++; /* nyquist_printf(", (f_time %g, f %g)", susp->f_time, *f_ptr_reg); */ susp->f_ptr++; susp->f_cnt--; if (susp->f_cnt == 0) { togo -= n; /* stdputstr("\n\tf out of samples...\n"); */ goto f_out_of_samples; } } g_ptr_reg++; *out_ptr_reg++ /* = tmp */ = (sample_type) (*f_ptr_reg - (*f_ptr_reg - susp->f_prev) * (susp->f_time - g_of_t) * susp->f->sr); /* nyquist_printf(", output %g\n", tmp);*/ } while (--n); /* inner loop */ f_out_of_samples: /* using g_ptr_reg is a bad idea on RS/6000: */ susp->g_ptr += togo; out_ptr += togo; susp_took(g_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* compose_fetch */ void compose_toss_fetch(susp, snd_list) register compose_susp_type susp; snd_list_type snd_list; { long final_count = MIN(susp->susp.current + max_sample_block_len, susp->susp.toss_cnt); time_type final_time = susp->susp.t0 + final_count / susp->susp.sr; long n; /* fetch samples from f up to final_time for this block of zeros */ while (((long) ((final_time - susp->f->t0) * susp->f->sr + 0.5)) >= susp->f->current) susp_get_samples(f, f_ptr, f_cnt); /* fetch samples from g up to final_time for this block of zeros */ while (((long) ((final_time - susp->g->t0) * susp->g->sr + 0.5)) >= susp->g->current) susp_get_samples(g, g_ptr, g_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ if (final_count == susp->susp.toss_cnt) { n = ROUND((final_time - susp->f->t0) * susp->f->sr - (susp->f->current - susp->f_cnt)); susp->f_ptr += n; susp_took(f_cnt, n); n = ROUND((final_time - susp->g->t0) * susp->g->sr - (susp->g->current - susp->g_cnt)); susp->g_ptr += n; susp_took(g_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; } snd_list->block_len = (short) (final_count - susp->susp.current); susp->susp.current = final_count; snd_list->u.next = snd_list_create((snd_susp_type) susp); snd_list->block = internal_zero_block; } void compose_mark(compose_susp_type susp) { sound_xlmark(susp->f); sound_xlmark(susp->g); } void compose_free(compose_susp_type susp) { sound_unref(susp->f); sound_unref(susp->g); ffree_generic(susp, sizeof(compose_susp_node), "compose_free"); } void compose_print_tree(compose_susp_type susp, int n) { indent(n); stdputstr("f:"); sound_print_tree_1(susp->f, n); indent(n); stdputstr("g:"); sound_print_tree_1(susp->g, n); } sound_type snd_make_compose(sound_type f, sound_type g) { register compose_susp_type susp; rate_type sr = g->sr; time_type t0 = g->t0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (S1 S2) */ scale_factor *= f->scale; f->scale = 1.0F; /* scale factor in g effectively scales sample rate of f: */ f->sr *= g->scale; /* BUG */ /* probably need to correct f->t0, but I don't understand this, so I'll leave this until we have some test cases */ falloc_generic(susp, compose_susp_node, "snd_make_compose"); susp->susp.fetch = compose_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ /* BUG: do we need to prepend to f? if (t0 < f->t0) sound_prepend_zeros(f, t0); */ if (t0 < g->t0) sound_prepend_zeros(g, t0); /* minimum start time over all inputs: */ t0_min = MIN(g->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = ROUND((t0 - t0_min) * sr); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = compose_toss_fetch; t0 = t0_min; } /* initialize susp state */ susp->susp.free = compose_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = compose_mark; susp->susp.print_tree = compose_print_tree; susp->susp.name = "compose"; susp->logically_stopped = false; susp->susp.log_stop_cnt = f->logical_stop_cnt; if (susp->susp.log_stop_cnt > g->logical_stop_cnt) susp->susp.log_stop_cnt = g->logical_stop_cnt; susp->susp.current = 0; susp->f = f; susp->f_cnt = 0; susp->f_time = 0; susp->f_time_increment = 1 / f->sr; susp->g = g; susp->g_cnt = 0; susp->started = false; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_compose(sound_type f, sound_type g) { sound_type f_copy = sound_copy(f); sound_type g_copy = sound_copy(g); return snd_make_compose(f_copy, g_copy); } nyquist-3.05/nyqsrc/convolve.c0000644000175000000620000002356511466723256015530 0ustar stevestaff/* convolve.c -- implements (non-"fast") convolution */ /* * Note: this code is mostly generated by translate.lsp (see convole.tran * in the tran directory), but it has been modified by hand to extend the * stop time to include the "tail" of the convolution beyond the length * of the first parameter. */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "convolve.h" void convolve_free(); typedef struct convolve_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type x_snd; long x_snd_cnt; sample_block_values_type x_snd_ptr; table_type table; sample_type *h_buf; double length_of_h; long h_len; long x_buf_len; sample_type *x_buffer_pointer; sample_type *x_buffer_current; } convolve_susp_node, *convolve_susp_type; void h_reverse(sample_type *h, long len) { sample_type temp; int i; for (i = 0; i < len; i++) { temp = h[i]; h[i] = h[len - 1]; h[len - 1] = temp; len--; } } void convolve_s_fetch(register convolve_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n, i; int round; int ready = 0; float* Utb1; short* BRLow; long M; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type * h_buf_reg; register long h_len_reg; register long x_buf_len_reg; register sample_type * x_buffer_pointer_reg; register sample_type * x_buffer_current_reg; register sample_type x_snd_scale_reg = susp->x_snd->scale; register sample_block_values_type x_snd_ptr_reg; sample_type* Yk; sample_type* y_output_buffer; sample_type* x_input_buffer; falloc_sample_block(out, "convolve_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the x_snd input sample block: */ /* based on susp_check_term_log_samples, but offset by h_len */ /* THIS IS EXPANDED BELOW * susp_check_term_log_samples(x_snd, x_snd_ptr, x_snd_cnt); */ if (susp->x_snd_cnt == 0) { susp_get_samples(x_snd, x_snd_ptr, x_snd_cnt); /* THIS IS EXPANDED BELOW *logical_stop_test(x_snd, susp->x_snd_cnt); */ if (susp->x_snd->logical_stop_cnt == susp->x_snd->current - susp->x_snd_cnt) { min_cnt(&susp->susp.log_stop_cnt, susp->x_snd, (snd_susp_type) susp, susp->x_snd_cnt); } /* THIS IS EXPANDED BELOW * terminate_test(x_snd_ptr, x_snd, susp->x_snd_cnt); */ if (susp->x_snd_ptr == zero_block->samples) { /* ### modify this to terminate at an offset of (susp->h_len) */ /* Note: in the min_cnt function, susp->x_snd_cnt is *subtracted* * from susp->x_snd->current to form the terminate time, so to * increase the time, we need to *subtract* susp->h_len, which * due to the double negative, *adds* susp->h_len to the ultimate * terminate time calculation. */ min_cnt(&susp->terminate_cnt, susp->x_snd, (snd_susp_type) susp, susp->x_snd_cnt - susp->h_len); } } togo = min(togo, susp->x_snd_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; h_buf_reg = susp->h_buf; h_len_reg = susp->h_len; x_buf_len_reg = susp->x_buf_len; x_buffer_pointer_reg = susp->x_buffer_pointer; x_buffer_current_reg = susp->x_buffer_current; x_snd_ptr_reg = susp->x_snd_ptr; out_ptr_reg = out_ptr; //buffer's length is twice the h_len because convolution yields 2N-1 y_output_buffer[2 * (int)h_len_reg]; x_input_buffer[2 * (int)h_len_reg]; memset(y_output_buffer, (sample_type)0.0f, 2 * h_len_reg * sizeof(sample_type)); memset(x_input_buffer, (sample_type)0.0f, 2 * h_len_reg * sizeof(sample_type)); M = log(h_len_reg) / log(2); round = (int)M; if((long)round != M) round++; fftCosInit(round, Utb1); fftBRInit(round, BRLow); ffts1(h_buf_reg, round, 1.0, Utb1, BRLow); if (n) do { /* the inner sample computation loop */ if(ready <= 0){ //shift output buffer for(i = 0; i < x_buf_len_reg; i++){ y_output_buffer[i] = y_output_buffer[i+h_len_reg]; y_output_buffer[i+h_len_reg] = 0.0f; } ffts1(x_input_buffer, round, 1L, Utb1, BRLow); //multiply for(i = 0; i < 2 * h_len_reg; i++) Yk[i] = x_input_buffer[i] * h_buf_reg[i]; iffts1(Yk, round, 1.0, Utb1, BRLow); //overlap add for(i = 0; i < 2 * h_len_reg; i++) y_output_buffer[i] += Yk[i]; ready = h_len_reg; } //ready describes the reciprocal of location in the input/output buffer x_input_buffer[h_len_reg - ready] = x_snd_scale_reg * *x_snd_ptr_reg++; *out_ptr_reg++ = y_output_buffer[h_len_reg - ready]; ready--; } while (--n); /* inner loop */ susp->x_buffer_pointer = x_buffer_pointer_reg; susp->x_buffer_current = x_buffer_current_reg; /* using x_snd_ptr_reg is a bad idea on RS/6000: */ susp->x_snd_ptr += togo; out_ptr += togo; susp_took(x_snd_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* convolve_s_fetch */ void convolve_toss_fetch(susp, snd_list) register convolve_susp_type susp; snd_list_type snd_list; { time_type final_time = susp->susp.t0; long n; /* fetch samples from x_snd up to final_time for this block of zeros */ while ((round((final_time - susp->x_snd->t0) * susp->x_snd->sr)) >= susp->x_snd->current) susp_get_samples(x_snd, x_snd_ptr, x_snd_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->x_snd->t0) * susp->x_snd->sr - (susp->x_snd->current - susp->x_snd_cnt)); susp->x_snd_ptr += n; susp_took(x_snd_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void convolve_mark(convolve_susp_type susp) { sound_xlmark(susp->x_snd); } void convolve_free(convolve_susp_type susp) { table_unref(susp->table); free(susp->x_buffer_pointer); sound_unref(susp->x_snd); ffree_generic(susp, sizeof(convolve_susp_node), "convolve_free"); } void convolve_print_tree(convolve_susp_type susp, int n) { indent(n); stdputstr("x_snd:"); sound_print_tree_1(susp->x_snd, n); } sound_type snd_make_convolve(sound_type x_snd, sound_type h_snd) { register convolve_susp_type susp; rate_type sr = x_snd->sr; time_type t0 = x_snd->t0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, convolve_susp_node, "snd_make_convolve"); susp->table = sound_to_table(h_snd); susp->h_buf = susp->table->samples; susp->length_of_h = susp->table->length; susp->h_len = (long) susp->length_of_h; h_reverse(susp->h_buf, susp->h_len); susp->x_buf_len = 2 * susp->h_len; susp->x_buffer_pointer = calloc((2 * (susp->h_len)), sizeof(float)); susp->x_buffer_current = susp->x_buffer_pointer; susp->susp.fetch = convolve_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < x_snd->t0) sound_prepend_zeros(x_snd, t0); /* minimum start time over all inputs: */ t0_min = min(x_snd->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = convolve_toss_fetch; } /* initialize susp state */ susp->susp.free = convolve_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = convolve_mark; susp->susp.print_tree = convolve_print_tree; susp->susp.name = "convolve"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(x_snd); susp->susp.current = 0; susp->x_snd = x_snd; susp->x_snd_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_convolve(sound_type x_snd, sound_type h_snd) { sound_type x_snd_copy = sound_copy(x_snd); return snd_make_convolve(x_snd_copy, h_snd); } nyquist-3.05/nyqsrc/sound.h0000644000175000000620000004626111524127024015012 0ustar stevestaff/* sound.h -- new nyquist sound data type */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability: moved some defns out of here */ #include #include "stdefs.h" /* used for *AUDIO-MARKERS* */ extern long sound_frames; extern double sound_srate; #if OSC extern int nosc_enabled; /* enable polling for OSC messages */ #endif #if USE_PRINTF #define nyquist_printf printf #endif #define PERMS 0644 /* -rw-r--r-- */ /* default stop sample count (for clipping) */ #define MAX_STOP 0x7FFFFFFF /* default stop time (for clipping) */ #define MAX_STOP_TIME 10E20 /* LISP-SRC: (SETF MAX-STOP-TIME 10E20) */ #define MIN_START_TIME -10E20 /* LISP-SRC: (SETF MIN-START-TIME -10E20) */ /* conversion from float to integer */ #define SCALE_FACTOR_TO_BYTE 127 #define SCALE_FACTOR_TO_SHORT 32767 #define SCALE_FACTOR_TO_24BIT 0x7FFFFF #define SCALE_FACTOR_TO_LONG 2147483647 /* Note that the values assigned here are not arbitrary, but represent a dominance relationship among the interpolation types. */ #define INTERP_n 0 #define INTERP_s 1 #define INTERP_i 2 #define INTERP_r 3 #define INTERP_nn 0 #define INTERP_ns 1 #define INTERP_ni 2 #define INTERP_nr 3 #define INTERP_sn 4 #define INTERP_ss 5 #define INTERP_si 6 #define INTERP_sr 7 #define INTERP_nnn 0 #define INTERP_nns 1 #define INTERP_nni 2 #define INTERP_nnr 3 #define INTERP_nsn 4 #define INTERP_nss 5 #define INTERP_nsi 6 #define INTERP_nsr 7 #define INTERP_nin 8 #define INTERP_nis 9 #define INTERP_nii 10 #define INTERP_nir 11 #define INTERP_nrn 12 #define INTERP_nrs 13 #define INTERP_nri 14 #define INTERP_nrr 15 #define INTERP_snn 16 #define INTERP_sns 17 #define INTERP_sni 18 #define INTERP_snr 19 #define INTERP_ssn 20 #define INTERP_sss 21 #define INTERP_ssi 22 #define INTERP_ssr 23 #define INTERP_sin 24 #define INTERP_sis 25 #define INTERP_sii 26 #define INTERP_sir 27 #define INTERP_srn 28 #define INTERP_srs 29 #define INTERP_sri 30 #define INTERP_srr 31 #define INTERP_nnnn 0 #define INTERP_nnns 1 #define INTERP_nnsn 4 #define INTERP_nnss 5 #define INTERP_nsnn 16 #define INTERP_nsns 17 #define INTERP_nssn 20 #define INTERP_nsss 21 #define INTERP_snnn 64 #define INTERP_snns 65 #define INTERP_snsn 68 #define INTERP_snss 69 #define INTERP_ssnn 80 #define INTERP_ssns 81 #define INTERP_sssn 84 #define INTERP_ssss 85 #define INTERP_niii 42 #define INTERP_siii 106 #define INTERP_nrrr 63 #define INTERP_srrr 127 #define INTERP_nnnnnn 0 #define INTERP_ssssss 1365 #define INTERP_nnnnnnnn 0 #define INTERP_ssssssss 21845 #define INTERP_MASK 3 #define INTERP_SHIFT 2 LVAL snd_badsr(void); typedef double time_type; typedef double rate_type; typedef float sample_type; typedef double promoted_sample_type; /* use radians or degrees for phase? */ #define ANGLEBASE 360.0 /* used by sndwrite.c for output buffers. This should be * eliminated: */ #define MAX_SND_CHANNELS 24 #define max_table_len 100000 /* Set to 4 for debugging block allocation stuff, 1012? for production */ /* leave a few words short of 1024 in case we allocate powers of 2 */ #define max_sample_block_len 1020 /* #define max_sample_block_len 4 */ /* Defines needed for xlisp */ #define getsound(x) ((sound_type) getinst(x)) #define xlgasound() (testarg(typearg(soundp))) typedef short SFDataType, *SFDataPtr; typedef sample_type sample_block_values[max_sample_block_len], *sample_block_values_type; typedef struct { long refcnt; /* reference count */ sample_block_values samples; } sample_block_node, *sample_block_type; typedef struct snd_susp_struct { void (*fetch)(struct snd_susp_struct *, struct snd_susp_struct *); void (*keep_fetch)(struct snd_susp_struct *); void (*free)(struct snd_susp_struct *); void (*mark)(struct snd_susp_struct *); /* marks LVAL nodes for GC */ void (*print_tree)(struct snd_susp_struct *, int); /* debugging */ char * name; /* string name for debugging */ long toss_cnt; /* return this many zeros, then compute */ long current; /* current sample number */ double sr; /* sample rate */ time_type t0; /* starting time */ long log_stop_cnt; /* logical stop count */ /* other susp dependent stuff will be here... */ } snd_susp_node, *snd_susp_type; typedef struct snd_list_struct { sample_block_type block; /* pointer to block of samples */ union { struct snd_list_struct *next; snd_susp_type susp; } u; short refcnt; short block_len; boolean logically_stopped; } snd_list_node, *snd_list_type; extern snd_list_type list_watch; //DBY typedef struct table_struct { long refcount; /* reference count */ double length; /* number of samples in table (double allows fractional length)*/ sample_type samples[1]; /* arbitrary length array of sample */ } table_node, *table_type; /* some counts are biased by -max_sample_block_len, so UNKNOWN can't be -1 * Any number less than -max_sample_block should do */ #define UNKNOWN (-10-max_sample_block_len) typedef struct sound_struct { sample_block_type (*get_next)(struct sound_struct *snd, long *cnt); time_type time; /* logical starting time */ time_type t0; /* quantized time of first sample */ long stop; /* stop (clipping) sample no. */ time_type true_t0; /* exact time of first sample */ rate_type sr; /* sample rate */ long current; /* current sample number, if negative, then the first -current samples must be dropped in order to find the first sample */ long logical_stop_cnt; /* log stop sample no, -1=unknwn */ snd_list_type list; /* sample block list, starting at curr. samp */ sample_type scale; /* scale factor for the result */ long prepend_cnt; /* how many zeros to prepend */ /* function to use as get_next after prepended zeros are generated: */ sample_block_type (*after_prepend) (struct sound_struct * snd, long * cnt); table_type table; /* pointer to table-ized version of this sound */ long *extra; /* used for extra state information, first word of extra state should be the length of the extra state (see sound_unref()) */ } sound_node, *sound_type; /* convert number of samples to memory size: */ #define table_size_in_bytes(n) \ (sizeof(table_node) + sizeof(sample_type) * ((n) - 1)) extern sample_block_type zero_block; extern sample_block_type internal_zero_block; extern snd_list_type zero_snd_list; extern sound_type printing_this_sound; /* debugging global */ extern double sound_latency; /* controls output latency */ double snd_set_latency(double latency); /* LISP: (SND-SET-LATENCY FLONUM) */ double compute_phase(double phase, double key, long n, double srate, double new_srate, double freq, double *incr_ptr); boolean soundp(LVAL); /* LISP: (SOUNDP ANY) */ void snd_list_ref(snd_list_type list); void sound_unref(sound_type snd); void snd_list_unref(snd_list_type list); LVAL cvsound(sound_type); extern LVAL a_sound; sample_block_type SND_get_next(sound_type snd, long * cnt); sample_block_type SND_get_first(sound_type snd, long * cnt); sample_block_type SND_get_zeros(sound_type snd, long * cnt); sample_block_type SND_flush(sound_type snd, long * cnt); double hz_to_step(double); /* LISP: (HZ-TO-STEP ANYNUM) */ int interp_style(sound_type s, rate_type sr); void set_logical_stop_time(sound_type sound, time_type when); /* LISP: (SND-SET-LOGICAL-STOP SOUND ANYNUM) */ #define xlog(x) log(x) /* LISP: double (LOG FLONUM) */ snd_list_type snd_list_create(snd_susp_type susp); void snd_list_terminate(snd_list_type snd_list); void snd_sort_2(sound_type * s1_ptr, sound_type * s2_ptr, rate_type sr); double snd_sref(sound_type s, time_type t); /* LISP: (SND-SREF SOUND ANYNUM) */ double snd_sref_inverse(sound_type s, double val); /* LISP: (SREF-INVERSE SOUND ANYNUM) */ double snd_stop_time(sound_type s); /* LISP: (SND-STOP-TIME SOUND) */ #define snd_time(s) (s)->time /* LISP: double (SND-TIME SOUND) */ #define snd_srate(s) (s)->sr /* LISP: double (SND-SRATE SOUND) */ #define snd_t0(s) (s)->t0 /* LISP: double (SND-T0 SOUND) */ sound_type snd_xform(sound_type snd, rate_type sr, time_type time, time_type start_time, time_type stop_time, promoted_sample_type scale); /* LISP: (SND-XFORM SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ sound_type sound_create(snd_susp_type susp, time_type t0, rate_type sr, promoted_sample_type scale); void min_cnt(long *cnt_ptr, sound_type sound, snd_susp_type susp, long cnt); void indent(int n); void sound_prepend_zeros(sound_type snd, time_type t0); #ifndef GCBUG #define blocks_to_watch_max 50 extern long blocks_to_watch_len; extern sample_block_type blocks_to_watch[blocks_to_watch_max]; void block_watch(long sample_block); /* LISP: (BLOCK-WATCH FIXNUM) */ long sound_nth_block(sound_type snd, long n); /* LISP: (SOUND-NTH-BLOCK SOUND FIXNUM) */ #endif sound_type sound_copy(sound_type snd); /* LISP: (SND-COPY SOUND) */ void sound_xlmark(sound_type s); void sound_print(LVAL snd_expr, long n); /* LISP: (SND-PRINT ANY FIXNUM) */ void sound_play(LVAL snd_expr); /* LISP: (SND-PLAY ANY) */ void stats(void); /* LISP: (STATS) */ void sound_print_tree(sound_type snd); /* LISP: (SND-PRINT-TREE SOUND) */ void mark_audio_time(void); void sound_print_tree_1(sound_type snd, int n); sound_type sound_scale(double factor, sound_type snd); /* LISP: (SND-SCALE ANYNUM SOUND) */ void sound_init(void); void sound_symbols(void); table_type sound_to_table(sound_type s); void table_unref(table_type table); sound_type sound_zero(time_type t0, rate_type sr); /* LISP: (SND-ZERO ANYNUM ANYNUM) */ #define sound_get_next(s, n) ((*(s->get_next))(s, n)) #define susp_print_tree(s, n) (*((s)->print_tree))(s, n) double step_to_hz(double); /* LISP: (STEP-TO-HZ ANYNUM) */ /* macros for access to samples within a suspension */ /* NOTE: assume suspension structure is named "susp" */ /* susp_check_samples points sample_ptr to a new sample block if necessary */ #define susp_check_samples(sound, sample_ptr, sample_cnt) \ if (susp->sample_cnt == 0) \ susp_get_samples(sound, sample_ptr, sample_cnt) /* susp_check_samples_break is similar to susp_check_samples - "_break" * normally means that this code will break out of the inner loop, but in * this case, there is no reason (neither log nor term) to break. * x2_sample is taken from sound */ #define susp_check_samples_break(sound, sample_ptr, sample_cnt, x2_sample) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ x2_sample = susp_current_sample(sound, sample_ptr); } /* susp_get_samples always gets next block (useful only in initialization code) */ #define susp_get_samples(sound, sample_ptr, sample_cnt) \ susp->sample_ptr = sound_get_next(susp->sound, &(susp->sample_cnt))->samples /* susp_get_block_samples always gets next block (useful only in initialization code) */ #define susp_get_block_samples(sound, sample_block_ptr, sample_ptr, sample_cnt) \ susp->sample_block_ptr = sound_get_next(susp->sound, &susp->sample_cnt); \ susp->sample_ptr = susp->sample_block_ptr->samples /* susp_took is called after you've taken n samples */ #define susp_took(sample_cnt, n) susp->sample_cnt -= n /* susp_fetch_sample is used to grab just one sample, doesn't check for samples!, * but applies scale factor: */ #define susp_fetch_sample(sound, sample_ptr, sample_cnt) \ (susp->sound->scale * (susp->sample_cnt--, *(susp->sample_ptr++))) /* susp_current_sample grabs sample without advancing to next, applies scale * factor: */ #define susp_current_sample(sound, sample_ptr) \ (susp->sound->scale * (*(susp->sample_ptr))) /* susp_check_term_samples checks for samples; if new ones are fetched, then * run termination test on signal and record result. */ #define susp_check_term_samples(sound, sample_ptr, sample_cnt) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ terminate_test(sample_ptr, sound, susp->sample_cnt); } /* susp_check_term_log_samples checks for samples * if new ones are fetched, then run termination test and logical stop * test on signal and record results. */ #define susp_check_term_log_samples(sound, sample_ptr, sample_cnt) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ logical_stop_test(sound, susp->sample_cnt); \ terminate_test(sample_ptr, sound, susp->sample_cnt); } /* susp_check_term_log_block_samples checks for samples * if new ones are fetched, then run termination test and logical stop * test on signal and record results. In this case, termination and logical * stop happen at the MAXIMUM of termination and logical stop times, resp. * * Originally, this code assumed that logical stops occurred on block boundaries, * but because of the SET-LOGICAL-STOP function, which just writes a stop time * into the sound_struct, the logical stop can be anywhere. As soon as the * logical stop is known, we want to propagate the value from the sound being * read into the sound being computed. The propagation should set the logical * stop of the computed sound to the MAX of any current value and the new * value. When the bit fields indicate that all logical stop times have been * encountered, then the sound being computed will make the logical stop happen * on a block boundary and set the flag on the block of samples where the stop * occurs. */ #define susp_check_term_log_block_samples(sound, sample_block_ptr, sample_ptr, sample_cnt, bit, all) \ if (susp->sample_cnt == 0) { \ susp_get_block_samples(sound, sample_block_ptr, sample_ptr, sample_cnt); \ /*OLD if (susp->sound->logical_stop_cnt == \ susp->sound->current - susp->sample_cnt) { \ */ \ if (susp->sound->logical_stop_cnt != UNKNOWN && \ !(susp->logical_stop_bits & bit)) { \ susp->logical_stop_bits |= bit; \ /*OLD \ if (susp->logical_stop_bits == all) { \ susp->susp.log_stop_cnt = (long) \ ((((susp->sound->current - susp->sample_cnt) / \ susp->sound->sr + susp->sound->t0) - \ susp->susp.t0) * susp->susp.sr + 0.5); \ assert(susp->susp.log_stop_cnt >= 0); } } \ */ \ susp->susp.log_stop_cnt = max(susp->susp.log_stop_cnt, \ (((susp->sound->logical_stop_cnt / \ susp->sound->sr + susp->sound->t0) - \ susp->susp.t0) * susp->susp.sr + 0.5)); } \ if (susp->sample_ptr == zero_block->samples) { \ susp->terminate_bits |= bit; \ if (susp->terminate_bits == all) { \ susp->terminate_cnt = (long) \ ((((susp->sound->current - susp->sample_cnt) / \ susp->sound->sr + susp->sound->t0) - \ susp->susp.t0) * susp->susp.sr + 0.5); \ } } } /* logical_stop_cnt_cvt is used to convert from the logical stop count * at one sample rate to that of another sample rate -- this macro is * used by the snd_make_ routine in every .c file, and assumes * the target sample rate is susp->susp.sr. * * NOTE: this macro does not take into account the possibility of different * start times - maybe it should. */ #define logical_stop_cnt_cvt(sound) \ (sound->logical_stop_cnt == UNKNOWN ? UNKNOWN : \ ROUND((sound->logical_stop_cnt / sound->sr) * susp->susp.sr)) /* logical_stop_test tests to see if sound has logically stopped; if so, * sets susp->susp.log_stop_cnt. The resulting logical_stop_cnt will reflect * the minimum logical_stop time of all sounds to which this test is applied. */ #define logical_stop_test(sound, cnt) \ if (susp->sound->logical_stop_cnt == susp->sound->current - (cnt)) {\ min_cnt(&susp->susp.log_stop_cnt, susp->sound, (snd_susp_type) susp, cnt); } /* terminate_test checks to see if sound has terminated; if so, * sets susp->terminate_cnt. The resulting terminate_cnt will reflect * the minimum termination time of all sounds to which this test is applied. */ #define terminate_test(sample_ptr, sound, cnt) \ if (susp->sample_ptr == zero_block->samples) { \ min_cnt(&susp->terminate_cnt, susp->sound, (snd_susp_type) susp, cnt); } /* susp_check_log_samples checks for new samples then checks for * termination and logical stop conditions */ #define susp_check_log_samples(sound, sample_ptr, sample_cnt) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ logical_stop_test(sound, susp->sample_cnt); } /* susp_check_term_samples_break checks for new samples then checks for * termination condition; breaks from inner loop */ #define susp_check_term_samples_break( \ sound, sample_ptr, sample_cnt, x2_sample) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ x2_sample = susp_current_sample(sound, sample_ptr); \ terminate_test(sample_ptr, sound, susp->sample_cnt); \ if (susp->terminate_cnt < susp->susp.current + cnt + togo) { \ break; }} \ else x2_sample = susp_current_sample(sound, sample_ptr); /* susp_check_log_samples_break checks for new samples then checks for * logical stop conditions; breaks from inner loop */ #define susp_check_log_samples_break( \ sound, sample_ptr, sample_cnt, x2_sample) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ x2_sample = susp_current_sample(sound, sample_ptr); \ logical_stop_test(sound, susp->sample_cnt); \ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && \ (susp->susp.log_stop_cnt < susp->susp.current + cnt + togo)) { \ break; }} \ else x2_sample = susp_current_sample(sound, sample_ptr); /* susp_check_term_log_samples_break checks for new samples then checks for * termination and logical stop conditions; breaks from inner loop */ #define susp_check_term_log_samples_break( \ sound, sample_ptr, sample_cnt, x2_sample) \ if (susp->sample_cnt == 0) { \ susp_get_samples(sound, sample_ptr, sample_cnt); \ x2_sample = susp_current_sample(sound, sample_ptr); \ terminate_test(sample_ptr, sound, susp->sample_cnt); \ logical_stop_test(sound, susp->sample_cnt); \ if ((susp->terminate_cnt != UNKNOWN && \ susp->terminate_cnt < susp->susp.current + cnt + togo) || \ (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN && \ susp->susp.log_stop_cnt < susp->susp.current + cnt + togo)) { \ break; }} \ else x2_sample = susp_current_sample(sound, sample_ptr); nyquist-3.05/nyqsrc/add.h0000644000175000000620000000324211466723256014420 0ustar stevestaff/* this typedef goes here because it is needed by multiseq.c */ typedef struct add_susp_struct { snd_susp_node susp; boolean started; int terminate_bits; long terminate_cnt; int logical_stop_bits; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_type s1_bptr; /* block pointer */ sample_block_values_type s1_ptr; sound_type s2; long s2_cnt; sample_block_type s2_bptr; /* block pointer */ sample_block_values_type s2_ptr; #ifdef UPSAMPLECODE /* support for interpolation of s2 */ sample_type s2_x1_sample; double s2_phase; double s2_phase_incr; /* support for ramp between samples of s2 */ double output_per_s2; #endif /* pointer used to synchronize adds in multiseq */ struct multiseq_struct *multiseq; long s1_prepend; /* offset to susp.current */ } add_susp_node, *add_susp_type; sound_type snd_make_add(); sound_type snd_add(); /* LISP: (SND-ADD SOUND SOUND) */ /* we export these for seq.c and multiseq.c */ void add_zero_fill_nn_fetch(add_susp_type susp, snd_list_type snd_list); void add_s1_s2_nn_fetch(add_susp_type susp, snd_list_type snd_list); void add_s2_nn_fetch(add_susp_type susp, snd_list_type snd_list); void add_s1_nn_fetch(add_susp_type susp, snd_list_type snd_list); void add_mark(add_susp_type susp); void add_print_tree(add_susp_type susp, int n); void add_free(add_susp_type susp); nyquist-3.05/nyqsrc/multiseq.c0000644000175000000620000006304711466723256015537 0ustar stevestaff/* multiseq.c -- return a multichannel signal until its logical stop, then evaluate a closure to get another signal and convert to adds of two multichannel signals */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "multiseq.h" #include "add.h" #include "scale.h" #include "extern.h" #include "cext.h" /* #define MULTISEQ_GC_DEBUG */ #ifdef MULTISEQ_GC_DEBUG extern snd_list_type snd_list_to_watch; #endif /* #define GC_DEBUG */ #ifdef GC_DEBUG extern sound_type sound_to_watch; #endif #define D if(0) /* Design: This operator implements sequences of multichannel signals. A single data structure manages an array of susps that initially are used to fetch blocks from the first multichannel signal. When the LAST logical stop is reached, a closure is evaluated to yield a new multichannel signal. The component sounds of this are stored into the susps which are then converted into add suspensions. The other managing structures are then freed. The main constraint here is that the conversion to add susps must take place at the same time across all channels, so before the conversion, a fetch from the susp can only be made if it is known that the samples returned happen BEFORE the conversion will take place. Since the conversion takes place at the maximum of the logical stop times of all channels, we have to advance all channels synchronously. We keep track of a greatest lower bound, refered to as the horizon, on the maximum logical stop time. It is safe to fetch blocks up to the horizon, but not beyond. This synchronous fetching is done by a single routine and an auxilliarly structure that manages the whole multichannel array of susps. The basic idea is that a fetch from a suspension gets forwarded to the managing structure, which uses its array of susps to fetch from ALL suspensions up to the requested time or until the logical stop, whichever comes first. These "synchronous" fetches are not made by calling the fetch routines on the suspensions to avoid infinite recursion. At any time, there will be some set of channels whose logical stop time is unknown. The "s1" fields (s1, s1_ptr, s1_bptr) of these suspensions are used to look ahead by geting a block from s1. If no logical stop is indicated, then we can append the block to the snd_list and update the horizon, allowing fetches from other susps. In other words, the s1_bptr of each susp provides a one buffer lookahead by which we can obtain advance knowledge of the maximum logical stop time. The algorithm is as follows: 1. When fetch is called on a suspension, compute when any prefetched samples will end (if there are none, then fetch a block from s1 and compute the time at which the block ends). This becomes the target time for other fetches. 2. Call multiseq_advance(), passing the target time and the manager structure (which has pointers to all other channels). (Note: every susp has a pointer to the manager). The function of multiseq_advance() is to push the horizon for the logical stop forward. This is done by iterating over the array of susps until the target is reached. Actually, the array contains pointers to the snd_list_node that points to each susp and where the next block will be linked. The goal of this loop is to satisfy the original fetch, which means we have to push low_water to greater than or equal to the target. (Low water is the minimum time of the next sample to be returned by any multiseq susp.) This goal will be met unless we reach the last logical stop time, in which case we evaluate the closure for the next multichannel sound, convert everything to add's and let the additions take care of returning blocks. 3. The Iteration Loop: low_water is the lowest sample count of the next sample horizon is the greatest lower bound on the maximum logical stop time Iterate over susps until low_water >= target (Note: whenever data is fetched for a sound whose logical stop time is unknown, update the horizon. If a logical stop time becomes known, then test if the final maximum logical stop time is known (by keeping a count of how many are still unknown), and if the count goes to zero, evaluate the continuation and convert to multiple adds.) (Another Note: we may reach the logical stop time and convert to multiple adds before the loop terminates, in which case we return without finishing the loop. Take care that the caller does the right thing to produce a sample block in this case.) 3a. If a block hasn't been prefetched, do it. 3b. While the susp has prefetched a block that ends at or before horizon, put the block on the snd_list and prefetch another block. 3c. If the susp hasn't a known logical stop time, set new_horizon to the end time of the last sample prefetched in 3b. 3d. If new_horizon == horizon, signal an error, no progress was made. 3d. Set horizon to new_horizon and repeat the loop. NOTE ON A BUG FIX (1 Jul 95): old code assumed that when a logical stop was detected it was at the beginning of the next block, but if logical stop is explicit, then it may be way in the future. We could convert to adds at this point, but that would force early evaluation of the closure, which we'd like to delay (be lazy when possible). Therefore, we want to ignore knowledge of a logical stop time until the logical stop time falls within the currently known block of samples. By "currently known", I mean somewhere in the block referenced by ->s1_ptr and ->s1_cnt. */ /* extern LVAL s_stdout; */ void multiseq_convert(multiseq_type ms); void multiseq_free(add_susp_type susp); sample_block_type multiseq_get_next(sound_type snd, long * cnt); void multiseq_print_tree(add_susp_type susp, int n); #define susp_cnt_time(ssp, ms, cnt) (ssp->susp.t0 - ms->t0 + (cnt)/ssp->s1->sr) #define susp_time(ssp, ms) susp_cnt_time(ssp, ms, \ (ssp->susp.current + ssp->s1_cnt)) #define susp_low_water(ssp, ms) susp_cnt_time(ssp, ms, ssp->susp.current) #define susp_log_stop_time(ssp, ms) susp_cnt_time(ssp, ms, ssp->susp.log_stop_cnt) /* multiseq_advance fetches from each channel to advance to target time */ /* * If a channel terminates early, we must be careful: continuing to * fetch will return pointers to the zero_block, but this will * indicate termination to whoever is fetching from multiseq. We * must check the pointers and substitute internal_zero_block to * avoid premature termination. */ void multiseq_advance(multiseq_type ms, time_type target) { int i; time_type new_horizon; time_type new_low_water; D nyquist_printf("multiseq_advance: %p->low_water %g, target %g\n", ms, ms->low_water, target); while (ms->low_water < target - 0.000001) { new_horizon = 0.0; D nyquist_printf("multiseq_advance loop: target %g low_water %g horizon %g\n", target, ms->low_water, ms->horizon); /* new_low_water will be a minimum over every * channel, so start with a big number */ new_low_water = target; for (i = 0; i < ms->nchans; i++) { snd_list_type snd_list = ms->chans[i]; add_susp_type susp = (add_susp_type) snd_list->u.susp; time_type my_hor; time_type my_low_water; D nyquist_printf("chans[%d]: ", i); /* fetch up to horizon */ /* see if susp has an unprocessed block (test on susp->s1_ptr * is probably not necessary, in fact, it isn't initialized * until the first block is fetched, but s1_cnt is */ if (susp->s1_cnt && susp->s1_ptr && susp->s1_ptr == susp->s1_bptr->samples) { /* do nothing, unprocessed block already there as a * result of the initiating fetch */ } else if (susp->s1_cnt != 0) { stdputstr("multiseq_advance: s1_cnt != 0\n"); EXIT(1); /* this should never happen */ } else { /* otherwise fetch it */ D stdputstr("prefetching samples "); susp_get_block_samples(s1, s1_bptr, s1_ptr, s1_cnt); if (susp->s1_ptr == zero_block->samples) { susp->terminate_bits = 1; susp->s1_bptr = internal_zero_block; susp->s1_ptr = internal_zero_block->samples; } /* see if we've reached a logical stop * (I can't believe this code block is in 3 places - * there must be a better way... RBD) */ if (!susp->logical_stop_bits) { if (susp->s1->logical_stop_cnt != UNKNOWN) { if (susp->susp.current + susp->s1_cnt >= susp->s1->logical_stop_cnt) { susp->logical_stop_bits = 1; susp->susp.log_stop_cnt = susp->s1->logical_stop_cnt; ms->not_logically_stopped_cnt--; D nyquist_printf( "snd_make_multiseq: Logical stop reached, not_logically_stopped_cnt %d\n", ms->not_logically_stopped_cnt); } } } } D nyquist_printf(" current %d cnt %d ", (int)susp->susp.current, (int)susp->s1_cnt); /* while the susp has prefetched a block that ends at or * before horizon, put the block on the snd_list and * prefetch another block */ while (susp_time(susp, ms) < ms->horizon + 0.000001) { snd_list->block = susp->s1_bptr; snd_list->block_len = (short) susp->s1_cnt; susp->susp.current += susp->s1_cnt; (susp->s1_bptr->refcnt)++; susp->s1_cnt = 0; #ifdef MULTISEQ_GC_DEBUG nyquist_printf( "multiseq: output block %p%s on snd_list %p to chan %d\n", susp->s1_bptr, (susp->s1_bptr == internal_zero_block ? " (INTERNAL ZERO BLOCK)" : ""), snd_list, i); #endif snd_list->u.next = snd_list_create(&(susp->susp)); #ifdef MULTISEQ_GC_DEBUG snd_list_debug(snd_list, "multiseq_advance"); #endif ms->chans[i] = snd_list = snd_list->u.next; susp_get_block_samples(s1, s1_bptr, s1_ptr, s1_cnt); if (susp->s1_ptr == zero_block->samples) { susp->terminate_bits = 1; susp->s1_bptr = internal_zero_block; susp->s1_ptr = internal_zero_block->samples; } if (susp->s1_ptr != susp->s1_bptr->samples) { stdputstr("bug in multiseq_advance\n"); EXIT(1); } /* see if we've reached a logical stop * (I can't believe this code block is in 3 places - * there must be a better way... RBD) */ if (!susp->logical_stop_bits) { if (susp->s1->logical_stop_cnt != UNKNOWN) { if (susp->susp.current + susp->s1_cnt >= susp->s1->logical_stop_cnt) { susp->logical_stop_bits = 1; susp->susp.log_stop_cnt = susp->s1->logical_stop_cnt; ms->not_logically_stopped_cnt--; D nyquist_printf( "snd_make_multiseq: Logical stop reached, not_logically_stopped_cnt %d\n", ms->not_logically_stopped_cnt); } } } D nyquist_printf("\n\toutput block, current %d cnt %d ", (int)susp->susp.current, (int)susp->s1_cnt); } if (!susp->logical_stop_bits) my_hor = susp_time(susp, ms); else my_hor = susp_log_stop_time(susp, ms); if (new_horizon < my_hor) { D nyquist_printf("new_horizon %g ", my_hor); new_horizon = my_hor; } if (ms->not_logically_stopped_cnt == 0) { ms->horizon = new_horizon; /* pass t0 to multiseq_convert */ D stdputstr("Calling multiseq_convert\n"); multiseq_convert(ms); return; } my_low_water = susp_low_water(susp, ms); if (my_low_water < new_low_water) { new_low_water = my_low_water; } D stdputstr("\n"); } ms->low_water = new_low_water; if (new_horizon <= ms->horizon) { stdputstr("no progress in multiseq_advance\n"); EXIT(1); } else { ms->horizon = new_horizon; } } } /* multiseq_convert -- eval closure and convert to adds */ /**/ void multiseq_convert(multiseq_type ms) { LVAL result, new; sound_type snd; time_type now = ms->t0 + ms->horizon; int i; long size; xlsave1(result); result = xleval(cons(ms->closure, consa(cvflonum(now)))); if (exttypep(result, a_sound)) { snd = sound_copy(getsound(result)); result = newvector(ms->nchans); setelement(result, 0, cvsound(snd)); for (i = 1; i < ms->nchans; i++) { setelement(result, i, cvsound(sound_zero(now, ms->sr))); } } else if (vectorp(result)) { if (getsize(result) > ms->nchans) { xlerror("too few channels", result); } else if (getsize(result) < ms->nchans) { new = newvector(ms->nchans); for (i = 1; i < getsize(result); i++) { setelement(new, i, getelement(result, i)); } for (i = getsize(result); i < ms->nchans; i++) { setelement(new, i, cvsound(sound_zero(now, ms->sr))); } result = new; } } else xlerror("closure did not return a (multi-channel) sound", result); /* now result holds a vector of nchans, insert them into add_susp's */ for (i = 0; i < ms->nchans; i++) { snd_list_type snd_list = ms->chans[i]; add_susp_type susp = (add_susp_type) snd_list->u.susp; long sother_start; /* remove backpointer to ms */ susp->multiseq = NULL; susp->susp.print_tree = add_print_tree; susp->susp.free = add_free; susp->susp.mark = add_mark; susp->s2 = sound_copy(getsound(getelement(result, i))); if (susp->s1->sr != susp->s2->sr) xlfail("multiseq: sample rates must match"); if (susp->s2->scale != 1.0) { susp->s2 = snd_make_normalize(susp->s2); } sother_start = ROUND((susp->s2->t0 - susp->susp.t0) * susp->s2->sr); D nyquist_printf("sother_start computed for %p: %d\n", susp, (int)sother_start); if (sother_start > susp->susp.current) { D nyquist_printf("susp %p using add_s1_nn_fetch\n", susp); susp->susp.fetch = add_s1_nn_fetch; susp->susp.name = "multiseq:add_s1_nn_fetch"; } else if (susp->terminate_bits) { /* s1 is done, just get s2 now */ sound_unref(susp->s1); susp->s1 = NULL; D nyquist_printf("susp %p using add_s2_nn_fetch\n", susp); susp->susp.fetch = add_s2_nn_fetch; susp->susp.name = "multiseq:add_s2_nn_fetch"; } else { D nyquist_printf("susp %p using add_s1_s2_nn_fetch\n", susp); susp->susp.fetch = add_s1_s2_nn_fetch; susp->susp.name = "multiseq:add_s1_s2_nn_fetch"; } /* fix up logical stop info */ /* BUG: what if s2 is already stopped? */ susp->susp.log_stop_cnt = UNKNOWN; susp->logically_stopped = false; /* we need to compute at least 1 sample * (at this point we don't really know if we've * computed anything or not, so to be safe, do it. */ snd_list->u.next = snd_list_create(&(susp->susp)); snd_list->block = internal_zero_block; (*(susp->susp.fetch))(susp, snd_list); } /* now free the multiseq struct */ size = sizeof(snd_list_type) * ms->nchans; ffree_generic(ms->chans, size, "multiseq_convert"); ffree_generic(ms, sizeof(multiseq_node), "multiseq_convert(2)"); ms->closure = NIL; /* allow garbage collection now */ xlpop(); } /* multiseq_fetch returns blocks of s1 until the logical stop time of s1's */ /* * Fetch routines (in particular, the add_*_fetch routines that will * be installed on this susp at a later time) expect to be called with * a new snd_list installed and ready for a new block. However, since * we are going to call multiseq_advance to pull blocks out of susps * that will not be set up with a fresh snd_list in this way, it is * simpler to dispose of the preallocated snd_list so that all susps * look alike to multiseq_advance. Of course, multiseq_advance will * redo the work of allocating a snd_list. * * If a channel terminates early, we must be careful: continuing to * fetch will return pointers to the zero_block, but this will * indicate termination to whoever is fetching from multiseq. We * must check the pointers and substitute internal_zero_block to * avoid premature termination. */ void multiseq_fetch(susp, snd_list) register add_susp_type susp; snd_list_type snd_list; { time_type block_end_time; /* undo the preallocation of a snd_list_node */ /* we can bypass the reference counting code because we * know that this snd_list was just allocated and has no * other references */ #ifdef MULTISEQ_GC_DEBUG if (snd_list_to_watch == snd_list->u.next) { nyquist_printf("multiseq_fetch: backing out snd_list_to_watch from %p\n", snd_list_to_watch); watch_snd_list(snd_list); } #endif ffree_snd_list(snd_list->u.next, "multiseq_fetch"); snd_list->u.susp = (snd_susp_type) susp; snd_list->block = NULL; D nyquist_printf("multiseq_fetch called: susp %p s1_cnt %d\n", susp, (int)susp->s1_cnt); /* first compute how many samples we can generate from s1: */ if (susp->s1_cnt == 0) { susp_get_block_samples(s1, s1_bptr, s1_ptr, s1_cnt); if (susp->s1_ptr == zero_block->samples) { susp->terminate_bits = 1; /* mark s1 as terminated */ susp->s1_bptr = internal_zero_block; susp->s1_ptr = internal_zero_block->samples; } /* see if we've reached a logical stop * (I can't believe this code block is in 3 places - * there must be a better way... RBD) */ if (!susp->logical_stop_bits) { if (susp->s1->logical_stop_cnt != UNKNOWN) { if (susp->susp.current + susp->s1_cnt >= susp->s1->logical_stop_cnt) { susp->logical_stop_bits = 1; susp->susp.log_stop_cnt = susp->s1->logical_stop_cnt; susp->multiseq->not_logically_stopped_cnt--; D nyquist_printf( "snd_make_multiseq: Logical stop reached, not_logically_stopped_cnt %d\n", susp->multiseq->not_logically_stopped_cnt); } } } } /* s1_cnt has the number of samples we can return */ /* now compute time of the last sample */ block_end_time = susp_time(susp, susp->multiseq); D nyquist_printf("block_end_time of %p: %g\n", susp, block_end_time); multiseq_advance(susp->multiseq, block_end_time); } /* multiseq_mark -- mark routine for multiseq susps */ /**/ void multiseq_mark(add_susp_type susp) { int i; multiseq_type ms = susp->multiseq; D nyquist_printf("multiseq_mark(%p)\n", susp); /* nyquist_printf("marking s1@%p in add@%p\n", susp->s1, susp);*/ if (ms->closure) mark(ms->closure); /* mark s1 of each susp in multiseq */ for (i = 0; i < ms->nchans; i++) { snd_list_type snd_list = ms->chans[i]; if (snd_list) { while (snd_list->block != NULL) { if (snd_list == zero_snd_list) break; snd_list = snd_list->u.next; } sound_xlmark(((add_susp_type) snd_list->u.susp)->s1); } } } /* snd_make_multiseq -- make a multiseq from an array and a closure */ /* * NOTE: the resulting array of sounds will not use the normal * SND_get_first and SND_get_next routines to fetch new blocks * because these extend the snd_list of the sound immediately, * and this would confuse multiseq_advance() which has to extend * multiple snd_lists synchronously. So, we use multiseq_get_next() * instead. */ LVAL snd_make_multiseq(LVAL s1, LVAL closure) { multiseq_type ms; int i; LVAL result; xlsave1(result); /* allocate multiseq */ falloc_generic(ms, multiseq_node, "snd_make_multiseq"); /* install its array of snd_list_type */ if (!vectorp(s1) || getsize(s1) == 0) { ffree_generic(ms, sizeof(multiseq_node), "snd_make_multiseq"); xlerror("bad argument type", s1); } ms->nchans = getsize(s1); ms->closure = closure; ms->not_logically_stopped_cnt = 0; ms->low_water = 0.0; ms->horizon = 0.0; falloc_generic_n(ms->chans, snd_list_type, ms->nchans, "snd_make_multiseq"); /* allocate sounds to return */ result = newvector(ms->nchans); /* ms->t0 will be the minimum of all t0's in array */ ms->t0 = (getsound(getelement(s1, 0)))->t0; /* create sounds to return */ for (i = 0; i < ms->nchans; i++) { add_susp_type susp; sound_type snd; falloc_generic(susp, add_susp_node, "snd_make_multiseq(add_susp)"); susp->s1 = sound_copy(getsound(getelement(s1, i))); /* we used to only incr this if lsc was UNKNOWN, but that's wrong. Should move this out of the loop now. */ if (susp->s1->scale != 1.0) { /* stdputstr("normalizing first sound in a seq\n"); */ susp->s1 = snd_make_normalize(susp->s1); } ms->not_logically_stopped_cnt++; D nyquist_printf("snd_make_multiseq: not_logically_stopped_cnt %d\n", ms->not_logically_stopped_cnt); susp->s1_cnt = 0; susp->s2 = NULL; susp->s2_cnt = 0; susp->susp.fetch = multiseq_fetch; susp->susp.free = multiseq_free; susp->susp.sr = susp->s1->sr; susp->susp.mark = multiseq_mark; susp->susp.print_tree = multiseq_print_tree; susp->susp.name = "multiseq"; susp->susp.t0 = susp->s1->t0; susp->terminate_bits = 0; /* bits for s1 and s2 termination */ susp->terminate_cnt = UNKNOWN; susp->logical_stop_bits = 0; /* bits for s1 and s2 log. stop */ susp->susp.log_stop_cnt = UNKNOWN; susp->logically_stopped = false; susp->started = false; susp->susp.current = 0; susp->multiseq = ms; snd = sound_create((snd_susp_type) susp, susp->s1->t0, susp->susp.sr, 1.0); #ifdef GC_DEBUG if (snd == sound_to_watch) { nyquist_printf("watched sound is channel %d\n", i); } #endif setelement(result, i, cvsound(snd)); if (snd->list->block || !snd->list->u.susp) { stdputstr("data inconsistency in snd_make_seq\n"); EXIT(1); } ms->chans[i] = snd->list; D nyquist_printf("ms->chans[%d] = %p, %p->u.susp = %p\n", i, snd->list, snd->list, snd->list->u.susp); ms->t0 = MIN(ms->t0, susp->s1->t0); ms->sr = susp->s1->sr; /* assume all samp rates are equal */ D nyquist_printf("Multiseq sound[%d]: \n", i); D sound_print_tree(susp->s1); } D nyquist_printf("ms->t0 == %g\n", ms->t0); xlpop(); return result; } /* note: snd_multiseq is a noop, just call snd_make_multiseq */ void multiseq_free(add_susp_type susp) { int i; multiseq_type ms = susp->multiseq; boolean dead = true; sound_unref(susp->s1); sound_unref(susp->s2); /* probably not necessary */ /* tricky part: remove pointer from ms->chans */ for (i = 0; i < ms->nchans; i++) { if (ms->chans[i]) { dead = false; /* * note that ms->chans is still a valid * pointer (see snd_list_unref) */ if (ms->chans[i]->u.susp == (snd_susp_type) susp) { ms->chans[i] = NULL; D nyquist_printf("susp %p freed, ms@%p->chans[%d] = NULL\n", susp, ms, i); } } } /* if last element is freed, free the multiseq struct too */ if (dead) { i = sizeof(snd_list_type) * ms->nchans; ffree_generic(ms->chans, i, "multiseq_free"); ffree_generic(ms, sizeof(multiseq_node), "multiseq_free(2)"); } susp->multiseq = NULL; /* just to be safe */ ffree_generic(susp, sizeof(add_susp_node), "multiseq_free(3)"); } void multiseq_print_tree(add_susp_type susp, int n) { int i; indent(n); if (!susp->multiseq) { xlfail("internal error: missing multiseq structure"); } nyquist_printf("multiseq@%p = [ ", susp->multiseq); for (i = 0; i < susp->multiseq->nchans; i++) { if (susp->multiseq->chans[i]) { nyquist_printf("%p", susp->multiseq->chans[i]->u.susp); } else { stdputstr("NULL"); } } indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("closure:"); stdprint(susp->multiseq->closure); indent(n); } nyquist-3.05/nyqsrc/sliders.c0000644000175000000620000000756711466723256015346 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "sliders.h" #include "sndsliders.h" float slider_array[SLIDERS_MAX]; void set_slider(int index, float value) { if (index >= 0 && index < SLIDERS_MAX) { slider_array[index] = value; } } LVAL xslider_read(void) { LVAL arg = xlgafixnum(); int index = getfixnum(arg); xllastarg(); if (index >= 0 && index < SLIDERS_MAX) { return cvflonum(slider_array[index]); } return NIL; } LVAL xosc_enable(void) { LVAL arg = xlgetarg(); xllastarg(); #ifdef OSC if (nosc_enabled == !null(arg)) { return arg; /* no change */ } else if (null(arg)) { /* nosc_enabled must be true */ nosc_finish(); return s_true; } else { /* nosc_enabled must be false */ nosc_init(); return NIL; } #else return xlenter("DISABLED"); #endif } void slider_free(); typedef struct slider_susp_struct { snd_susp_node susp; long terminate_cnt; int index; } slider_susp_node, *slider_susp_type; void slider__fetch(register slider_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type c_reg; int limit = ((long) susp->susp.sr) / 50; falloc_sample_block(out, "slider__fetch"); out_ptr = out->samples; snd_list->block = out; /* compute no more than 20ms to preserve some interactivity */ if (limit < 1) limit = 1; if (limit > max_sample_block_len) limit = max_sample_block_len; while (cnt < limit) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = limit - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; c_reg = slider_array[susp->index]; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = c_reg; } while (--n); /* inner loop */ out_ptr += togo; cnt += togo; } /* outer loop */ /* printf("slider %d cnt %d\n", susp->index, cnt); */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* slider__fetch */ void slider_free(slider_susp_type susp) { ffree_generic(susp, sizeof(slider_susp_node), "slider_free"); } void slider_print_tree(slider_susp_type susp, int n) { } sound_type snd_make_slider(int index, time_type t0, rate_type sr, time_type d) { register slider_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; if (index < 0 || index >= SLIDERS_MAX) { xlerror("slider index out of range", NIL); } falloc_generic(susp, slider_susp_node, "snd_make_slider"); susp->susp.fetch = slider__fetch; susp->index = index; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = slider_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = slider_print_tree; susp->susp.name = "slider"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_slider(int index, time_type t0, rate_type sr, time_type d) { return snd_make_slider(index, t0, sr, d); } nyquist-3.05/nyqsrc/seqfn.cl0000644000175000000620000000022310144436365015141 0ustar stevestaff:nyqsrc:seqfnint :cmt:seqdecls.h :nyqsrc:seqext.h :cmt:seq.h :nyqsrc:seqinterf.h :cmt:seqread.h :cmt:seqmread.h :cmt:seqwrite.h :cmt:seqmwrite.h nyquist-3.05/nyqsrc/nyq-osc-server.c0000644000175000000620000000563411466723256016567 0ustar stevestaff/* nosc-server.c -- an OSC server for Nyquist */ /* * this enables OSC clients to set slider values in Nyquist * for security reasons, OSC clients cannot invoke Lisp expressions * the only operation allowed is to set a value in a Lisp array * * The API is: * * int nosc_init() -- initialize the server, return error, 0 means none * int nosc_poll() -- poll for messages and process them, return error, 0 means none * void nosc_finish() -- free data structures, return error, 0 means none */ #ifdef OSC #ifdef WIN32 #include #include #include #else #include #include #include #include #include #include #endif #include "xlisp.h" #include "sound.h" /* to get nosc_enabled */ #include "lo/lo.h" #include "sliders.h" static lo_server the_server = NULL; static int lo_fd; static void error(int num, const char *msg, const char *path) { char s[256]; sprintf(s, "liblo server error %d in path %s: %s\n", num, path, msg); stdputstr(s); } static int slider_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { // printf("%s <- %d, %g\n", path, argv[0]->i, argv[1]->f); // fflush(stdout); set_slider(argv[0]->i, argv[1]->f); return 0; } // wii_orientation_handler -- controls sliders 0 and 1 in range [0, 1] // using wii orientation messages from OSC static int wii_orientation_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { set_slider(0, min(1.0F, max(0.0F, (argv[0]->f / 180) + 0.5))); set_slider(1, min(1.0F, max(0.0F, (argv[1]->f / 180) + 0.5))); return 0; } int nosc_init() { the_server = lo_server_new("7770", error); /* add method that will match the path /slider, with two numbers, coerced * to int and float */ lo_server_add_method(the_server, "/slider", "if", slider_handler, NULL); lo_server_add_method(the_server, "/wii/orientation", "ff", wii_orientation_handler, NULL); lo_fd = lo_server_get_socket_fd(the_server); nosc_enabled = true; return 0; } int nosc_poll() { fd_set rfds; struct timeval tv; int retval; // loop, receiving all pending OSC messages while (true) { FD_ZERO(&rfds); FD_SET(lo_fd, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; retval = select(lo_fd + 1, &rfds, NULL, NULL, &tv); if (retval == -1) { stdputstr("select() error in nosc_poll\n"); return -1; } else if (retval > 0 && FD_ISSET(lo_fd, &rfds)) { /* printf("lo_server_recv_noblock 1\n"); */ lo_server_recv_noblock(the_server, 0); } else { return 0; } } } void nosc_finish() { lo_server_free(the_server); nosc_enabled = false; } #endif nyquist-3.05/nyqsrc/sndfmt.h0000644000175000000620000000623711466723256015172 0ustar stevestaff/* * sndfmt.h -- format constants for Nyquist programs */ /* * converted by Roger Dannenberg from snd.h, Jul 08 */ #ifdef SND_H error here #endif #define SND_H /* header formats */ #define SND_HEAD_NONE 0 /* LISP-SRC: (setf snd-head-none 0) */ #define SND_HEAD_AIFF 1 /* LISP-SRC: (setf snd-head-AIFF 1) */ #define SND_HEAD_IRCAM 2 /* LISP-SRC: (setf snd-head-IRCAM 2) */ #define SND_HEAD_NEXT 3 /* LISP-SRC: (setf snd-head-NeXT 3) */ #define SND_HEAD_WAVE 4 /* LISP-SRC: (setf snd-head-Wave 4) */ #define SND_HEAD_PAF 5 /* LISP-SRC: (setf snd-head-PAF 5) */ #define SND_HEAD_SVX 6 /* LISP-SRC: (setf snd-head-SVX 6) */ #define SND_HEAD_NIST 7 /* LISP-SRC: (setf snd-head-NIST 7) */ #define SND_HEAD_VOC 8 /* LISP-SRC: (setf snd-head-VOC 8) */ #define SND_HEAD_W64 9 /* LISP-SRC: (setf snd-head-W64 9) */ #define SND_HEAD_MAT4 10 /* LISP-SRC: (setf snd-head-MAT4 10) */ #define SND_HEAD_MAT5 11 /* LISP-SRC: (setf snd-head-MAT5 11) */ #define SND_HEAD_PVF 12 /* LISP-SRC: (setf snd-head-PVF 12) */ #define SND_HEAD_XI 13 /* LISP-SRC: (setf snd-head-XI 13) */ #define SND_HEAD_HTK 14 /* LISP-SRC: (setf snd-head-HTK 14) */ #define SND_HEAD_SDS 15 /* LISP-SRC: (setf snd-head-SDS 15) */ #define SND_HEAD_AVR 16 /* LISP-SRC: (setf snd-head-AVR 16) */ #define SND_HEAD_SD2 17 /* LISP-SRC: (setf snd-head-SD2 17) */ #define SND_HEAD_FLAC 18 /* LISP-SRC: (setf snd-head-FLAC 18) */ #define SND_HEAD_CAF 19 /* LISP-SRC: (setf snd-head-CAF 19) */ #define SND_HEAD_RAW 20 /* LISP-SRC: (setf snd-head-raw 20) */ #define SND_NUM_HEADS 21 /* bitfields for soundheaders */ #define SND_HEAD_CHANNELS (1<<0) /* LISP-SRC: (setf snd-head-channels 1) */ #define SND_HEAD_MODE (1<<1) /* LISP-SRC: (setf snd-head-mode 2) */ #define SND_HEAD_BITS (1<<2) /* LISP-SRC: (setf snd-head-bits 4) */ #define SND_HEAD_SRATE (1<<3) /* LISP-SRC: (setf snd-head-srate 8) */ /* when returned from lisp, len (samples) is converted to time (seconds) */ #define SND_HEAD_LEN (1<<4) /* LISP-SRC: (setf snd-head-dur 16) */ #define SND_HEAD_LATENCY (1<<5) /* LISP-SRC: (setf snd-head-latency 32) */ #define SND_HEAD_TYPE (1<<6) /* LISP-SRC: (setf snd-head-type 64) */ /* modes */ /* IMA ADPCM */ #define SND_MODE_ADPCM 0 /* LISP-SRC: (setf snd-mode-adpcm 0) */ #define SND_MODE_PCM 1 /* LISP-SRC: (setf snd-mode-pcm 1) */ #define SND_MODE_ULAW 2 /* LISP-SRC: (setf snd-mode-ulaw 2) */ #define SND_MODE_ALAW 3 /* LISP-SRC: (setf snd-mode-alaw 3) */ #define SND_MODE_FLOAT 4 /* LISP-SRC: (setf snd-mode-float 4) */ /* unsigned pcm (e.g. Microsoft 8-bit wav format): */ #define SND_MODE_UPCM 5 /* LISP-SRC: (setf snd-mode-upcm 5) */ #define SND_MODE_UNKNOWN 6 /* LISP-SRC: (setf snd-mode-unknown 6) */ #define SND_MODE_DOUBLE 7 /* LISP-SRC: (setf snd-mode-double 7) */ #define SND_MODE_GSM610 8 /* LISP-SRC: (setf snd-mode-GSM610 8) */ #define SND_MODE_DWVW 9 /* LISP-SRC: (setf snd-mode-DWVW 9) */ #define SND_MODE_DPCM 10 /* LISP-SRC: (setf snd-mode-DPCM 10) */ /* microsoft ADPCM */ #define SND_MODE_MSADPCM 11 /* LISP-SRC: (setf snd-mode-msadpcm 11) */ #define SND_NUM_MODES 12 #define SND_LOOP_NONE 0 #define SND_LOOP_FORWARD 1 #define SND_LOOP_FORWARD_BACKWARD 2 typedef struct { int mode; long begin; long end; } loop_node, *loop_type; nyquist-3.05/nyqsrc/fft.h0000644000175000000620000000023410144436365014437 0ustar stevestaff/* fft.h -- fft returned through a lisp array */ LVAL snd_fft(sound_type s, long len, long step, LVAL w); /* LISP: (SND-FFT SOUND FIXNUM FIXNUM ANY) */ nyquist-3.05/nyqsrc/debug.c0000644000175000000620000001427711466723256014763 0ustar stevestaff#include #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "debug.h" /* The DEBUG_MEM related routines are: * dbg_mem_allocated: called when memory is allocated * dbg_mem_freed: called when memory is freed * dbg_mem_released: called when memory is released */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #if DEBUG_MEM typedef struct { long seq_num; char *who; } dbg_mem_node, *dbg_mem_type; static long dbg_mem_last_seq_num = 0; long dbg_mem_seq_num = 0; long dbg_mem_trace = 0x410988; void dbg_mem_pause(void) { stdputstr("RETURN to continue: "); getchar(); } void dbg_mem_allocated(void *p, char *who) { dbg_mem_type info = (dbg_mem_type) p; if (p == (void *) dbg_mem_trace) { nyquist_printf("dbg_mem_allocated(%p, %s)\n", p, who); } info--; /* info is stored (hidden) BEFORE the data */ dbg_mem_last_seq_num++; if (dbg_mem_last_seq_num == dbg_mem_seq_num) { nyquist_printf("dbg_mem_allocated: " "%s just allocated %p as number %d\n", who, p, (int)dbg_mem_last_seq_num); dbg_mem_pause(); } info->seq_num = dbg_mem_last_seq_num; info->who = who; } void dbg_mem_freed(void *p, char *who) { dbg_mem_type info = (dbg_mem_type) p; if (p == (void *) dbg_mem_trace) { nyquist_printf("dbg_mem_freed(%p, %s)\n", p, who); } info--; /* info is stored (hidden) BEFORE the data */ if (!info->who) { nyquist_printf("MEMORY %p FREED TWICE!, " "second time by: %s, seq_num %d\n", p, who, (int)info->seq_num); fflush(stdout); dbg_mem_pause(); } if (info->seq_num == dbg_mem_seq_num) { nyquist_printf("dbg_mem_freed: %s freeing %p, number %d\n", who, p, (int)dbg_mem_seq_num); dbg_mem_pause(); } info->who = NULL; } void dbg_mem_released(void *p, char *who) { dbg_mem_type info = (dbg_mem_type) p; if (p == (void *) dbg_mem_trace) { nyquist_printf("dbg_mem_released(%p, %s)\n", p, who); } info--; /* info is stored (hidden) BEFORE the data */ if (!info->who) { nyquist_printf("MEMORY %p RELEASED BUT NOT ALLOCATED!, " "released by: %s, seq_num %d\n", p, who, (int)info->seq_num); fflush(stdout); dbg_mem_pause(); } if (info->seq_num == dbg_mem_seq_num) { nyquist_printf("dbg_mem_released: %s releasing %p, number %d\n", who, p, (int)dbg_mem_seq_num); dbg_mem_pause(); } } void dbg_mem_check(void *p, char *who) { dbg_mem_type info = (dbg_mem_type) p; if (!info) { nyquist_printf("DBG_MEM_CHECK (from %s): NULL POINTER!", who); fflush(stdout); dbg_mem_pause(); } info--; /* info is stored (hidden) BEFORE the data */ if (!info->who) { nyquist_printf("DBG_MEM_CHECK (from %s): %p IS FREE!, seq_num %d\n", who, p, (int)info->seq_num); fflush(stdout); dbg_mem_pause(); } } void dbg_mem_print(char *msg, void *p) { dbg_mem_type info = (dbg_mem_type) p; stdputstr(msg); if (!info) { stdputstr(" NULL POINTER"); } else { info--; /* info is stored (hidden) BEFORE the data */ if (!info->who) { nyquist_printf(" %p IS FREE!, ", p); } else { nyquist_printf(" %p allocated by %s, ", p, info->who); } nyquist_printf("seq_num %d\n", (int)info->seq_num); } } #endif void print_sound_type(sound_type s) { snd_list_type list; int blockcount; nyquist_printf("sound_type: 0x%p\n", s); nyquist_printf("\tt0: %f\n", s->t0); nyquist_printf("\tsr: %f\n", s->sr); nyquist_printf("\tcurrent: %d\n", (int)s->current); nyquist_printf("\tlogical_stop_cnt: %d\n", (int)s->logical_stop_cnt); nyquist_printf("\tlist: 0x%p\n", s->list); nyquist_printf("\tscale: %f\n", s->scale); list = s->list; blockcount = 0; nyquist_printf("\t(0x%p:0x%p)->", list, list->block); while (list->block) { list = list->u.next; if (blockcount < 5) { nyquist_printf("(0x%p:0x%p)->", list, list->block); } else if (blockcount == 5) { stdputstr(" ... "); break; } blockcount++; } stdputstr("\n"); } void print_snd_list_type(snd_list_type list) { nyquist_printf("%p: [%p[%d], %p] refcnt %d ls %d", list, list->block, list->block_len, list->u.next, list->refcnt, list->logically_stopped); } void print_sample_block_type(char *label, sample_block_type sampblock, int len) { int j; sample_block_values_type samp; samp = sampblock->samples; nyquist_printf("%s: [%p(ref %d): len %d]: =========>>", label, sampblock, (int)sampblock->refcnt, len); for (j = 0; j < len; j++) { nyquist_printf("%6g ", *samp++); } stdputstr("\n"); } /*******/ snd_susp_type susp_to_watch = NULL; void watch_susp(snd_susp_type s) { if (!susp_to_watch) { susp_to_watch = s; nyquist_printf("watching susp %p\n", s); } } sound_type sound_to_watch = NULL; void watch_sound(sound_type s) { if (!sound_to_watch) { sound_to_watch = s; nyquist_printf("watching sound %p\n", s); } } snd_list_type snd_list_to_watch = NULL; void watch_snd_list(snd_list_type s) { snd_list_to_watch = s; nyquist_printf("watching snd_list %p\n", s); } void snd_list_debug(snd_list_type snd_list, char *s) { if (snd_list == snd_list_to_watch) { nyquist_printf("%s%s\n", s, " appended to snd_list_to_watch."); watch_snd_list(snd_list->u.next); } } void snd_list_report(snd_list_type snd_list, char *s) { if (snd_list == snd_list_to_watch) { nyquist_printf("%s: fetching block for watched snd_list.\n", s); } } #ifdef IGNORE void test_it() { if (susp_to_watch && susp_to_watch->keep_fetch) stdputstr("WE FOUND A SERIOUS PROBLEM\n"); } #endif nyquist-3.05/nyqsrc/samples.h0000644000175000000620000000127110144436365015326 0ustar stevestaff/* samples.h -- convert sound (prefix) to lisp array */ /* these are used by snd_fromobject and snd_fromarraystream: */ extern LVAL s_next; extern LVAL s_send; void samples_symbols(); sound_type snd_from_array(double t0, double sr, LVAL array); /* LISP: (SND-FROM-ARRAY ANYNUM ANYNUM ANY) */ LVAL snd_samples(sound_type s, long len); /* LISP: (SND-SAMPLES SOUND FIXNUM) */ long snd_length(sound_type s, long len); /* LISP: (SND-LENGTH SOUND FIXNUM) */ double snd_maxsamp(sound_type s); /* LISP: (SND-MAXSAMP SOUND) */ LVAL snd_fetch(sound_type s); /* LISP: (SND-FETCH SOUND) */ LVAL snd_fetch_array(sound_type s, long len, long step); /* LISP: (SND-FETCH-ARRAY SOUND FIXNUM FIXNUM) */ nyquist-3.05/nyqsrc/resampv.h0000644000175000000620000000030010144436365015327 0ustar stevestaffsound_type snd_make_resamplev(sound_type f, rate_type sr, sound_type g); sound_type snd_resamplev(sound_type f, rate_type sr, sound_type g); /* LISP: (snd-resamplev SOUND ANYNUM SOUND) */ nyquist-3.05/nyqsrc/fftw.h0000644000175000000620000003255611466723256014650 0ustar stevestaff/* -*- C -*- */ /* * Copyright (c) 1997-1999 Massachusetts Institute of Technology * * 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 * */ /* fftw.h -- system-wide definitions */ /* $Id: fftw.h,v 1.1.1.1 2004/11/10 16:07:38 rbd Exp $ */ #ifndef FFTW_H #define FFTW_H #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Define for using single precision */ /* * If you can, use configure --enable-float instead of changing this * flag directly */ /* #undef FFTW_ENABLE_FLOAT */ /* our real numbers */ #ifdef FFTW_ENABLE_FLOAT typedef float fftw_real; #else typedef double fftw_real; #endif /********************************************* * Complex numbers and operations *********************************************/ typedef struct { fftw_real re, im; } fftw_complex; #define c_re(c) ((c).re) #define c_im(c) ((c).im) typedef enum { FFTW_FORWARD = -1, FFTW_BACKWARD = 1 } fftw_direction; /* backward compatibility with FFTW-1.3 */ typedef fftw_complex FFTW_COMPLEX; typedef fftw_real FFTW_REAL; #ifndef FFTW_1_0_COMPATIBILITY #define FFTW_1_0_COMPATIBILITY 0 #endif #if FFTW_1_0_COMPATIBILITY /* backward compatibility with FFTW-1.0 */ #define REAL fftw_real #define COMPLEX fftw_complex #endif /********************************************* * Success or failure status *********************************************/ typedef enum { FFTW_SUCCESS = 0, FFTW_FAILURE = -1 } fftw_status; /********************************************* * Codelets *********************************************/ typedef void (fftw_notw_codelet) (const fftw_complex *, fftw_complex *, int, int); typedef void (fftw_twiddle_codelet) (fftw_complex *, const fftw_complex *, int, int, int); typedef void (fftw_generic_codelet) (fftw_complex *, const fftw_complex *, int, int, int, int); typedef void (fftw_real2hc_codelet) (const fftw_real *, fftw_real *, fftw_real *, int, int, int); typedef void (fftw_hc2real_codelet) (const fftw_real *, const fftw_real *, fftw_real *, int, int, int); typedef void (fftw_hc2hc_codelet) (fftw_real *, const fftw_complex *, int, int, int); typedef void (fftw_rgeneric_codelet) (fftw_real *, const fftw_complex *, int, int, int, int); /********************************************* * Configurations *********************************************/ /* * A configuration is a database of all known codelets */ enum fftw_node_type { FFTW_NOTW, FFTW_TWIDDLE, FFTW_GENERIC, FFTW_RADER, FFTW_REAL2HC, FFTW_HC2REAL, FFTW_HC2HC, FFTW_RGENERIC }; /* description of a codelet */ typedef struct { const char *name; /* name of the codelet */ void (*codelet) (); /* pointer to the codelet itself */ int size; /* size of the codelet */ fftw_direction dir; /* direction */ enum fftw_node_type type; /* TWIDDLE or NO_TWIDDLE */ int signature; /* unique id */ int ntwiddle; /* number of twiddle factors */ const int *twiddle_order; /* * array that determines the order * in which the codelet expects * the twiddle factors */ } fftw_codelet_desc; /* On Win32, you need to do funny things to access global variables in shared libraries. Thanks to Andrew Sterian for this hack. */ #if defined(__WIN32__) || defined(WIN32) || defined(_WINDOWS) # if defined(BUILD_FFTW_DLL) # define DL_IMPORT(type) __declspec(dllexport) type # elif defined(USE_FFTW_DLL) # define DL_IMPORT(type) __declspec(dllimport) type # else # define DL_IMPORT(type) type # endif #else # define DL_IMPORT(type) type #endif extern DL_IMPORT(const char *) fftw_version; /***************************** * Plans *****************************/ /* * A plan is a sequence of reductions to compute a FFT of * a given size. At each step, the FFT algorithm can: * * 1) apply a notw codelet, or * 2) recurse and apply a twiddle codelet, or * 3) apply the generic codelet. */ /* structure that contains twiddle factors */ typedef struct fftw_twiddle_struct { int n; const fftw_codelet_desc *cdesc; fftw_complex *twarray; struct fftw_twiddle_struct *next; int refcnt; } fftw_twiddle; typedef struct fftw_rader_data_struct { struct fftw_plan_struct *plan; fftw_complex *omega; int g, ginv; int p, flags, refcount; struct fftw_rader_data_struct *next; fftw_codelet_desc *cdesc; } fftw_rader_data; typedef void (fftw_rader_codelet) (fftw_complex *, const fftw_complex *, int, int, int, fftw_rader_data *); /* structure that holds all the data needed for a given step */ typedef struct fftw_plan_node_struct { enum fftw_node_type type; union { /* nodes of type FFTW_NOTW */ struct { int size; fftw_notw_codelet *codelet; const fftw_codelet_desc *codelet_desc; } notw; /* nodes of type FFTW_TWIDDLE */ struct { int size; fftw_twiddle_codelet *codelet; fftw_twiddle *tw; struct fftw_plan_node_struct *recurse; const fftw_codelet_desc *codelet_desc; } twiddle; /* nodes of type FFTW_GENERIC */ struct { int size; fftw_generic_codelet *codelet; fftw_twiddle *tw; struct fftw_plan_node_struct *recurse; } generic; /* nodes of type FFTW_RADER */ struct { int size; fftw_rader_codelet *codelet; fftw_rader_data *rader_data; fftw_twiddle *tw; struct fftw_plan_node_struct *recurse; } rader; /* nodes of type FFTW_REAL2HC */ struct { int size; fftw_real2hc_codelet *codelet; const fftw_codelet_desc *codelet_desc; } real2hc; /* nodes of type FFTW_HC2REAL */ struct { int size; fftw_hc2real_codelet *codelet; const fftw_codelet_desc *codelet_desc; } hc2real; /* nodes of type FFTW_HC2HC */ struct { int size; fftw_direction dir; fftw_hc2hc_codelet *codelet; fftw_twiddle *tw; struct fftw_plan_node_struct *recurse; const fftw_codelet_desc *codelet_desc; } hc2hc; /* nodes of type FFTW_RGENERIC */ struct { int size; fftw_direction dir; fftw_rgeneric_codelet *codelet; fftw_twiddle *tw; struct fftw_plan_node_struct *recurse; } rgeneric; } nodeu; int refcnt; } fftw_plan_node; struct fftw_plan_struct { int n; int refcnt; fftw_direction dir; int flags; int wisdom_signature; enum fftw_node_type wisdom_type; struct fftw_plan_struct *next; fftw_plan_node *root; double cost; }; /* a plan is just an array of instructions */ typedef struct fftw_plan_struct *fftw_plan; /* flags for the planner */ #define FFTW_ESTIMATE (0) #define FFTW_MEASURE (1) #define FFTW_OUT_OF_PLACE (0) #define FFTW_IN_PLACE (8) #define FFTW_USE_WISDOM (16) #define FFTW_THREADSAFE (128) /* guarantee plan is read-only so that the same plan can be used in parallel by multiple threads */ #define FFTWND_FORCE_BUFFERED (256) /* internal, undocumented flag */ extern fftw_plan fftw_create_plan_specific(int n, fftw_direction dir, int flags, fftw_complex *in, int istride, fftw_complex *out, int ostride); #define FFTW_HAS_PLAN_SPECIFIC extern fftw_plan fftw_create_plan(int n, fftw_direction dir, int flags); extern void fftw_print_plan(fftw_plan plan); extern void fftw_destroy_plan(fftw_plan plan); extern void fftw(fftw_plan plan, int howmany, fftw_complex *in, int istride, int idist, fftw_complex *out, int ostride, int odist); extern void fftw_one(fftw_plan plan, fftw_complex *in, fftw_complex *out); extern void fftw_die(const char *s); extern void *fftw_malloc(size_t n); extern void fftw_free(void *p); extern void fftw_check_memory_leaks(void); extern void fftw_print_max_memory_usage(void); typedef void *(*fftw_malloc_type_function) (size_t n); typedef void (*fftw_free_type_function) (void *p); typedef void (*fftw_die_type_function) (const char *errString); extern DL_IMPORT(fftw_malloc_type_function) fftw_malloc_hook; extern DL_IMPORT(fftw_free_type_function) fftw_free_hook; extern DL_IMPORT(fftw_die_type_function) fftw_die_hook; extern size_t fftw_sizeof_fftw_real(void); /* Wisdom: */ /* * define this symbol so that users know we are using a version of FFTW * with wisdom */ #define FFTW_HAS_WISDOM extern void fftw_forget_wisdom(void); extern void fftw_export_wisdom(void (*emitter) (char c, void *), void *data); extern fftw_status fftw_import_wisdom(int (*g) (void *), void *data); extern void fftw_export_wisdom_to_file(FILE *output_file); extern fftw_status fftw_import_wisdom_from_file(FILE *input_file); extern char *fftw_export_wisdom_to_string(void); extern fftw_status fftw_import_wisdom_from_string(const char *input_string); /* * define symbol so we know this function is available (it is not in * older FFTWs) */ #define FFTW_HAS_FPRINT_PLAN extern void fftw_fprint_plan(FILE *f, fftw_plan plan); /***************************** * N-dimensional code *****************************/ typedef struct { int is_in_place; /* 1 if for in-place FFTs, 0 otherwise */ int rank; /* * the rank (number of dimensions) of the * array to be FFTed */ int *n; /* * the dimensions of the array to the * FFTed */ fftw_direction dir; int *n_before; /* * n_before[i] = product of n[j] for j < i */ int *n_after; /* n_after[i] = product of n[j] for j > i */ fftw_plan *plans; /* 1d fftw plans for each dimension */ int nbuffers, nwork; fftw_complex *work; /* * work array big enough to hold * nbuffers+1 of the largest dimension * (has nwork elements) */ } fftwnd_data; typedef fftwnd_data *fftwnd_plan; /* Initializing the FFTWND plan: */ extern fftwnd_plan fftw2d_create_plan(int nx, int ny, fftw_direction dir, int flags); extern fftwnd_plan fftw3d_create_plan(int nx, int ny, int nz, fftw_direction dir, int flags); extern fftwnd_plan fftwnd_create_plan(int rank, const int *n, fftw_direction dir, int flags); extern fftwnd_plan fftw2d_create_plan_specific(int nx, int ny, fftw_direction dir, int flags, fftw_complex *in, int istride, fftw_complex *out, int ostride); extern fftwnd_plan fftw3d_create_plan_specific(int nx, int ny, int nz, fftw_direction dir, int flags, fftw_complex *in, int istride, fftw_complex *out, int ostride); extern fftwnd_plan fftwnd_create_plan_specific(int rank, const int *n, fftw_direction dir, int flags, fftw_complex *in, int istride, fftw_complex *out, int ostride); /* Freeing the FFTWND plan: */ extern void fftwnd_destroy_plan(fftwnd_plan plan); /* Printing the plan: */ extern void fftwnd_fprint_plan(FILE *f, fftwnd_plan p); extern void fftwnd_print_plan(fftwnd_plan p); #define FFTWND_HAS_PRINT_PLAN /* Computing the N-Dimensional FFT */ extern void fftwnd(fftwnd_plan plan, int howmany, fftw_complex *in, int istride, int idist, fftw_complex *out, int ostride, int odist); extern void fftwnd_one(fftwnd_plan p, fftw_complex *in, fftw_complex *out); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* FFTW_H */ nyquist-3.05/nyqsrc/resamp.h0000644000175000000620000000023310144436365015146 0ustar stevestaffsound_type snd_make_resample(sound_type s, rate_type sr); sound_type snd_resample(sound_type s, rate_type sr); /* LISP: (snd-resample SOUND ANYNUM) */ nyquist-3.05/nyqsrc/seqfnintdefs.h0000644000175000000620000000071310144436365016353 0ustar stevestaffextern LVAL xlc_seq_reset(void); extern LVAL xlc_seq_insert_ctrl(void); extern LVAL xlc_seq_insert_ramp(void); extern LVAL xlc_seq_insert_macctrl(void); extern LVAL xlc_seq_insert_note(void); extern LVAL xlc_seq_copy(void); extern LVAL xlc_seq_create(void); extern LVAL xlc_seq_next(void); extern LVAL xlc_seq_get(void); extern LVAL xlc_seq_read(void); extern LVAL xlc_seq_read_smf(void); extern LVAL xlc_seq_write(void); extern LVAL xlc_seq_write_smf(void); nyquist-3.05/nyqsrc/ffilterkit.h0000644000175000000620000000077710144436365016037 0ustar stevestaff/*:filterkit.h */ /* * FilterUp() - Applies a filter to a given sample when up-converting. * FilterUD() - Applies a filter to a given sample when up- or down- * converting. */ fast_float FilterUp(mem_float Imp[], mem_float ImpD[], int Nwing, boolean Interp, mem_float *Xp, double Ph, int Inc); fast_float FilterUD(mem_float Imp[], mem_float ImpD[], int Nwing, boolean Interp, mem_float *Xp, double Ph, int Inc, double dhb); nyquist-3.05/nyqsrc/pvshell.c0000644000175000000620000001413411466723256015342 0ustar stevestaff// pvshell.c -- This is a skeleton for a Nyquist primitive that // returns a sound. The sound is obtained by calling a function // with a request consisting of a location to put samples and // a count of how many samples are needed. The function returns // the actual number of samples computed and flags indicating // if the signal has reached the logical stop or termination. // In addition, there are interfaces for extracting samples // from input sounds. // This code is designed for a time-stretching phase vocoder, // but could be used for other purposes. It is derived from // compose.c, which might have been implmented with this // skeleton had we started out with this abstraction. #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "pvshell.h" #include "assert.h" /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ void pvshell_free(); typedef struct pvshell_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; boolean started; pvshell_node pvshell; } pvshell_susp_node, *pvshell_susp_type; /* pvshell_test_f -- get next sample block and check flags * * Only call this from PVSHELL_TEST_F macro */ long pvshell_test_f(pvshell_type susp) { long flags = 0; susp_get_samples(f, f_ptr, f_cnt); /* warning: macro references susp */ if (susp->f->logical_stop_cnt == susp->f->current - susp->f_cnt) { flags |= PVSHELL_FLAG_LOGICAL_STOP; } if (susp->f_ptr == zero_block->samples) { flags |= PVSHELL_FLAG_TERMINATE; } return flags; } /* pvshell_test_g -- get next sample block and check flags * * Only call this from PVSHELL_TEST_G macro */ long pvshell_test_g(pvshell_type susp) { long flags = 0; susp_get_samples(g, g_ptr, g_cnt); /* warning: macro references susp */ if (susp->g->logical_stop_cnt == susp->g->current - susp->g_cnt) { flags |= PVSHELL_FLAG_LOGICAL_STOP; } if (susp->g_ptr == zero_block->samples) { flags |= PVSHELL_FLAG_TERMINATE; } return flags; } /* pvshell_fetch -- computes h(f, g, x, y) where f and g are * sounds, x and y are doubles, and h implemented via a function * pointer. This could certainly be generalized further, but * maybe we should take this one step at a time. /**/ void pvshell_fetch(register pvshell_susp_type susp, snd_list_type snd_list) { long n, flags; sample_block_type out; sample_block_values_type out_ptr; falloc_sample_block(out, "pvshell_fetch"); out_ptr = out->samples; snd_list->block = out; /* don't run past the f input sample block: */ /* most fetch routines call susp_check_term_log_samples() here * but we can't becasue susp_check_term_log_samples() assumes * that output time progresses at the same rate as input time. * Here, some time warping might be going on, so this doesn't work. * It is up to the user to tell us when it is the logical stop * time and the terminate time. */ /* don't run past terminate time */ // if (susp->terminate_cnt != UNKNOWN && // susp->terminate_cnt <= susp->susp.current + cnt + togo) { // togo = susp->terminate_cnt - (susp->susp.current + cnt); // if (togo == 0) break; // } /* don't run past logical stop time */ // if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { // int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); // if (to_stop < togo && ((togo = to_stop) == 0)) break; // } n = max_sample_block_len; // ideally, compute a whole block of samples flags = (susp->pvshell.h)(&(susp->pvshell), out_ptr, &n); /* test for termination */ if (flags & PVSHELL_FLAG_TERMINATE) { snd_list_terminate(snd_list); } else { snd_list->block_len = n; susp->susp.current += n; } /* test for logical stop */ if (flags & PVSHELL_FLAG_LOGICAL_STOP || susp->logically_stopped) { snd_list->logically_stopped = true; susp->logically_stopped = true; } } /* pvshell_fetch */ void pvshell_mark(pvshell_susp_type susp) { sound_xlmark(susp->pvshell.f); sound_xlmark(susp->pvshell.g); } void pvshell_free(pvshell_susp_type susp) { /* note that f or g can be NULL */ sound_unref(susp->pvshell.f); sound_unref(susp->pvshell.g); ffree_generic(susp, sizeof(pvshell_susp_node), "pvshell_free"); } void pvshell_print_tree(pvshell_susp_type susp, int n) { indent(n); stdputstr("f:"); sound_print_tree_1(susp->pvshell.f, n); indent(n); stdputstr("g:"); sound_print_tree_1(susp->pvshell.g, n); } sound_type snd_make_pvshell(char *name, rate_type sr, time_type t0, h_fn_type h, sound_type f, sound_type g, double *state, long n) { register pvshell_susp_type susp; int i; falloc_generic(susp, pvshell_susp_node, "snd_make_pvshell"); susp->susp.fetch = pvshell_fetch; susp->terminate_cnt = UNKNOWN; /* initialize susp state */ susp->susp.free = pvshell_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = pvshell_mark; susp->susp.print_tree = pvshell_print_tree; susp->susp.name = name; susp->logically_stopped = false; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; /* copy the sound so that we have a private "reader" object */ susp->pvshell.f = (f ? sound_copy(f) : f); susp->pvshell.f_cnt = 0; susp->pvshell.g = (g ? sound_copy(g) : g); susp->pvshell.g_cnt = 0; susp->pvshell.h = h; susp->pvshell.flags = 0; /* terminated and logically stopped flags -- these are for the client of pvshell to use */ assert(n <= PVSHELL_STATE_MAX); for (i = 0; i < n; i++) { susp->pvshell.state[i] = state[i]; } susp->started = false; return sound_create((snd_susp_type)susp, t0, sr, 1.0); } nyquist-3.05/nyqsrc/yin.c0000644000175000000620000005047111466723256014470 0ustar stevestaff#include "stdio.h" #ifdef UNIX #include "sys/file.h" #endif #ifndef mips #include "stdlib.h" #endif #include "sndfmt.h" #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "yin.h" void yin_free(); /* for multiple channel results, one susp is shared by all sounds */ /* the susp in turn must point back to all sound list tails */ typedef struct yin_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; long blocksize; long stepsize; sample_type *block; float *temp; sample_type *fillptr; sample_type *endptr; snd_list_type chan[2]; /* array of back pointers */ long cnt; /* how many sample frames to read */ long m; long middle; } yin_susp_node, *yin_susp_type; /* DEBUG CODE: * use this to print the sound created by yin sound_type ysnd[2]; void print_ysnds(char *label, yin_susp_type susp) { int i; printf("At %s:\n", label); for (i = 0; i < 2; i++) { snd_list_type snd_list; if (!susp->chan[i]) continue; snd_list = ysnd[i]->list; printf(" ysnd[%d]:\n", i, label); while (true) { printf(" snd_list %p block %p\n", snd_list, snd_list->block); if (snd_list == zero_snd_list) { printf(" (zero_snd_list)\n"); break; } else if (!snd_list->block) { printf(" susp %p (%s)\n", snd_list->u.susp, snd_list->u.susp->name); break; } snd_list = snd_list->u.next; } } printf(" susp->chan[0] = %p, susp->chan[1] = %p\n", susp->chan[0], susp->chan[1]); } * END OF DEBUG CODE */ // Uses cubic interpolation to return the value of x such // that the function defined by f(0), f(1), f(2), and f(3) // is maximized. // float CubicMaximize(float y0, float y1, float y2, float y3) { // Find coefficients of cubic float a, b, c, d; float da, db, dc; float discriminant; float x1, x2; float dda, ddb; a = (float) (y0/-6.0 + y1/2.0 - y2/2.0 + y3/6.0); b = (float) (y0 - 5.0*y1/2.0 + 2.0*y2 - y3/2.0); c = (float) (-11.0*y0/6.0 + 3.0*y1 - 3.0*y2/2.0 + y3/3.0); d = y0; // Take derivative da = 3*a; db = 2*b; dc = c; // Find zeroes of derivative using quadratic equation discriminant = db*db - 4*da*dc; if (discriminant < 0.0) return -1.0; // error x1 = (float) ((-db + sqrt(discriminant)) / (2 * da)); x2 = (float) ((-db - sqrt(discriminant)) / (2 * da)); // The one which corresponds to a local _maximum_ in the // cubic is the one we want - the one with a negative // second derivative dda = 2*da; ddb = db; if (dda*x1 + ddb < 0) return x1; else return x2; } float parabolic_interp(float x1, float x2, float x3, float y1, float y2, float y3, float *min) { float a, b, c; float pos; // y1=a*x1^2+b*x1+c // y2=a*x2^2+b*x2+c // y3=a*x3^2+b*x3+c // y1-y2=a*(x1^2-x2^2)+b*(x1-x2) // y2-y3=a*(x2^2-x3^2)+b*(x2-x3) // (y1-y2)/(x1-x2)=a*(x1+x2)+b // (y2-y3)/(x2-x3)=a*(x2+x3)+b a = ((y1 - y2) / (x1 - x2) - (y2 - y3) / (x2 - x3)) / (x1 - x3); b = (y1 - y2) / (x1 - x2) - a * (x1 + x2); c = y1 - a * x1 * x1 - b * x1; // dy/dx = 2a*x + b = 0 pos = (float) (-b / (a + a)); *min = /* ax^2 + bx + c */ (a * pos + b) * pos + c; return pos; } void yin_compute(yin_susp_type susp, float *pitch, float *harmonicity) // samples is a buffer of samples // n is the number of samples, equals twice longest period, must be even // m is the shortest period in samples // results is an array of size n/2 - m + 1, the number of different lags { float *samples = susp->block; int middle = susp->middle; int m = susp->m; float threshold = 0.1F; float *results = susp->temp; // work from the middle of the buffer: int i, j; // loop counters // how many different lags do we compute? float left_energy = 0; float right_energy = 0; float left, right, non_periodic; float auto_corr=0; float cum_sum=0.0; float period; int min_i; // for each window, we keep the energy so we can compute the next one // incrementally. First, we need to compute the energies for lag m-1: for (i = 0; i < m - 1; i++) { left = samples[middle - 1 - i]; left_energy += left * left; right = samples[middle + i]; right_energy += right * right; } for (i = m; i <= middle; i++) { // i is the lag and the length of the window // compute the energy for left and right left = samples[middle - i]; left_energy += left * left; right = samples[middle - 1 + i]; right_energy += right * right; // compute the autocorrelation auto_corr = 0; for (j = 0; j < i; j++) { auto_corr += samples[middle - i + j] * samples[middle + j]; } non_periodic = (left_energy + right_energy - 2 * auto_corr);// / i; results[i - m] = non_periodic; } // normalize by the cumulative sum for (i = m; i <= middle; i++) { cum_sum += results[i - m]; results[i - m]=results[i - m] / (cum_sum / (i - m + 1)); } min_i = m; // value of initial estimate for (i = m; i <= middle; i++) { if (results[i - m] < threshold) { min_i=i; break; } else if (results[i - m] < results[min_i - m]) min_i=i; } // This step is not part of the published algorithm. Just because we // found a point below the threshold does not mean we are at a local // minimum. E.g. a sine input will go way below threshold, so the // period estimate at the threshold crossing will be too low. In this // step, we continue to scan forward until we reach a local minimum. while (min_i < middle && results[min_i + 1 - m] < results[min_i - m]) { min_i++; } // use parabolic interpolation to improve estimate if (i>m && isusp.sr * susp->stepsize) / period); } /* yin_fetch - compute F0 and harmonicity using YIN approach. */ /* * The pitch (F0) is determined by finding two periods whose * inner product accounts for almost all of the energy. Let X and Y * be adjacent vectors of length N in the sample stream. Then, * if 2X*Y > threshold * (X*X + Y*Y) * then the period is given by N * In the algorithm, we compute different sizes until we find a * peak above threshold. Then, we use cubic interpolation to get * a precise value. If no peak above threshold is found, we return * the first peak. The second channel returns the value 2X*Y/(X*X+Y*Y) * which is refered to as the "harmonicity" -- the amount of energy * accounted for by periodicity. * * Low sample rates are advised because of the high cost of computing * inner products (fast autocorrelation is not used). * * The result is a 2-channel signal running at the requested rate. * The first channel is the estimated pitch, and the second channel * is the harmonicity. * * This code is adopted from multiread, currently the only other * multichannel suspension in Nyquist. Comments from multiread include: * The susp is shared by all channels. The susp has backpointers * to the tail-most snd_list node of each channel, and it is by * extending the list at these nodes that sounds are read in. * To avoid a circularity, the reference counts on snd_list nodes * do not include the backpointers from this susp. When a snd_list * node refcount goes to zero, the yin susp's free routine * is called. This must scan the backpointers to find the node that * has a zero refcount (the free routine is called before the node * is deallocated, so this is safe). The backpointer is then set * to NULL. When all backpointers are NULL, the susp itself is * deallocated, because it can only be referenced through the * snd_list nodes to which there are backpointers. */ void yin_fetch(yin_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; int i; sample_block_type f0; sample_block_values_type f0_ptr = NULL; sample_block_type harmonicity; sample_block_values_type harmonicity_ptr = NULL; register sample_block_values_type s_ptr_reg; register sample_type *fillptr_reg; register sample_type *endptr_reg = susp->endptr; /* DEBUG: print_ysnds("top of yin_fetch", susp); */ if (susp->chan[0]) { falloc_sample_block(f0, "yin_fetch"); f0_ptr = f0->samples; /* Since susp->chan[i] exists, we want to append a block of samples. * The block, out, has been allocated. Before we insert the block, * we must figure out whether to insert a new snd_list_type node for * the block. Recall that before SND_get_next is called, the last * snd_list_type in the list will have a null block pointer, and the * snd_list_type's susp field points to the suspension (in this case, * susp). When SND_get_next (in sound.c) is called, it appends a new * snd_list_type and points the previous one to internal_zero_block * before calling this fetch routine. On the other hand, since * SND_get_next is only going to be called on one of the channels, the * other channels will not have had a snd_list_type appended. * SND_get_next does not tell us directly which channel it wants (it * doesn't know), but we can test by looking for a non-null block in the * snd_list_type pointed to by our back-pointers in susp->chan[]. If * the block is null, the channel was untouched by SND_get_next, and * we should append a snd_list_type. If it is non-null, then it * points to internal_zero_block (the block inserted by SND_get_next) * and a new snd_list_type has already been appended. */ /* Before proceeding, it may be that garbage collection ran when we * allocated out, so check again to see if susp->chan[j] is Null: */ if (!susp->chan[0]) { ffree_sample_block(f0, "yin_fetch"); f0 = NULL; /* make sure we don't free it again */ f0_ptr = NULL; /* make sure we don't output f0 samples */ } else if (!susp->chan[0]->block) { snd_list_type snd_list = snd_list_create((snd_susp_type) susp); /* printf("created snd_list %x for chan 0 with susp %x\n", snd_list, snd_list->u.susp); */ /* Now we have a snd_list to append to the channel, but a very * interesting thing can happen here. snd_list_create, which * we just called, MAY have invoked the garbage collector, and * the GC MAY have freed all references to this channel, in which * case yin_free(susp) will have been called, and susp->chan[0] * will now be NULL! */ if (!susp->chan[0]) { ffree_snd_list(snd_list, "yin_fetch"); } else { susp->chan[0]->u.next = snd_list; } } /* see the note above: we don't know if susp->chan still exists */ /* Note: We DO know that susp still exists because even if we lost * some channels in a GC, someone is still calling SND_get_next on * some channel. I suppose that there might be some very pathological * code that could free a global reference to a sound that is in the * midst of being computed, perhaps by doing something bizarre in the * closure that snd_seq activates at the logical stop time of its first * sound, but I haven't thought that one through. */ if (susp->chan[0]) { susp->chan[0]->block = f0; /* check some assertions */ if (susp->chan[0]->u.next->u.susp != (snd_susp_type) susp) { nyquist_printf("didn't find susp at end of list for chan 0\n"); } } else if (f0) { /* we allocated f0, but don't need it anymore due to GC */ ffree_sample_block(f0, "yin_fetch"); f0_ptr = NULL; } } /* Now, repeat for channel 1 (comments omitted) */ if (susp->chan[1]) { falloc_sample_block(harmonicity, "yin_fetch"); harmonicity_ptr = harmonicity->samples; if (!susp->chan[1]) { ffree_sample_block(harmonicity, "yin_fetch"); harmonicity = NULL; /* make sure we don't free it again */ harmonicity_ptr = NULL; } else if (!susp->chan[1]->block) { snd_list_type snd_list = snd_list_create((snd_susp_type) susp); /* printf("created snd_list %x for chan 1 with susp %x\n", snd_list, snd_list->u.susp); */ if (!susp->chan[1]) { ffree_snd_list(snd_list, "yin_fetch"); } else { susp->chan[1]->u.next = snd_list; } } if (susp->chan[1]) { susp->chan[1]->block = harmonicity; if (susp->chan[1]->u.next->u.susp != (snd_susp_type) susp) { nyquist_printf("didn't find susp at end of list for chan 1\n"); } } else if (harmonicity) { /* we allocated harmonicity, but don't need it anymore due to GC */ ffree_sample_block(harmonicity, "yin_fetch"); harmonicity_ptr = NULL; } } /* DEBUG: print_ysnds("yin_fetch before outer loop", susp); */ while (cnt < max_sample_block_len) { /* outer loop */ /* first, compute how many samples to generate in inner loop: */ /* don't overflow the output sample block */ togo = (max_sample_block_len - cnt) * susp->stepsize; /* don't run past the s input sample block */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo/susp->stepsize) { togo = (susp->terminate_cnt - (susp->susp.current + cnt)) * susp->stepsize; if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop = 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the output block) */ if (to_stop < togo/susp->stepsize) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we can set * the logical stop flag on this output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new block a the LST */ togo = to_stop * susp->stepsize; } } n = togo; s_ptr_reg = susp->s_ptr; fillptr_reg = susp->fillptr; if (n) do { /* the inner sample computation loop */ *fillptr_reg++ = *s_ptr_reg++; if (fillptr_reg >= endptr_reg) { float f0; float harmonicity; yin_compute(susp, &f0, &harmonicity); if (f0_ptr) *f0_ptr++ = f0; if (harmonicity_ptr) *harmonicity_ptr++ = harmonicity; cnt++; // shift block by stepsize memmove(susp->block, susp->block + susp->stepsize, sizeof(sample_type) * (susp->blocksize - susp->stepsize)); fillptr_reg -= susp->stepsize; } } while (--n); /* inner loop */ /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; susp->fillptr = fillptr_reg; susp_took(s_cnt, togo); } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { /* single channels code: snd_list_terminate(snd_list); */ for (i = 0; i < 2; i++) { if (susp->chan[i]) { snd_list_type the_snd_list = susp->chan[i]; susp->chan[i] = the_snd_list->u.next; snd_list_terminate(the_snd_list); } } } else { /* single channel code: snd_list->block_len = cnt; */ susp->susp.current += cnt; for (i = 0; i < 2; i++) { if (susp->chan[i]) { susp->chan[i]->block_len = cnt; susp->chan[i] = susp->chan[i]->u.next; } } } /* test for logical stop */ if (susp->logically_stopped) { /* single channel code: snd_list->logically_stopped = true; */ if (susp->chan[0]) susp->chan[0]->logically_stopped = true; if (susp->chan[1]) susp->chan[1]->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* yin_fetch */ void yin_mark(yin_susp_type susp) { sound_xlmark(susp->s); } void yin_free(yin_susp_type susp) { int j; boolean active = false; /* stdputstr("yin_free: "); */ for (j = 0; j < 2; j++) { if (susp->chan[j]) { if (susp->chan[j]->refcnt) active = true; else { susp->chan[j] = NULL; /* nyquist_printf("deactivating channel %d\n", j); */ } } } if (!active) { /* stdputstr("all channels freed, freeing susp now\n"); */ ffree_generic(susp, sizeof(yin_susp_node), "yin_free"); sound_unref(susp->s); free(susp->block); free(susp->temp); } } void yin_print_tree(yin_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } LVAL snd_make_yin(sound_type s, double low_step, double high_step, long stepsize) { LVAL result; int j; register yin_susp_type susp; rate_type sr = s->sr; time_type t0 = s->t0; falloc_generic(susp, yin_susp_node, "snd_make_yin"); susp->susp.fetch = yin_fetch; susp->terminate_cnt = UNKNOWN; /* initialize susp state */ susp->susp.free = yin_free; susp->susp.sr = sr / stepsize; susp->susp.t0 = t0; susp->susp.mark = yin_mark; susp->susp.print_tree = yin_print_tree; susp->susp.name = "yin"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->m = (long) (sr / step_to_hz(high_step)); if (susp->m < 2) susp->m = 2; /* add 1 to make sure we round up */ susp->middle = (long) (sr / step_to_hz(low_step)) + 1; susp->blocksize = susp->middle * 2; susp->stepsize = stepsize; /* blocksize must be at least step size to implement stepping */ if (susp->stepsize > susp->blocksize) susp->blocksize = susp->stepsize; susp->block = (sample_type *) malloc(susp->blocksize * sizeof(sample_type)); susp->temp = (float *) malloc((susp->middle - susp->m + 1) * sizeof(float)); susp->fillptr = susp->block; susp->endptr = susp->block + susp->blocksize; xlsave1(result); result = newvector(2); /* create array for F0 and harmonicity */ /* create sounds to return */ for (j = 0; j < 2; j++) { sound_type snd = sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, 1.0); LVAL snd_lval = cvsound(snd); /* nyquist_printf("yin_create: sound %d is %x, LVAL %x\n", j, snd, snd_lval); */ setelement(result, j, snd_lval); susp->chan[j] = snd->list; /* DEBUG: ysnd[j] = snd; */ } xlpop(); return result; } LVAL snd_yin(sound_type s, double low_step, double high_step, long stepsize) { sound_type s_copy = sound_copy(s); return snd_make_yin(s_copy, low_step, high_step, stepsize); } nyquist-3.05/nyqsrc/oldyin.c0000644000175000000620000004140110144436365015152 0ustar stevestaff/* yin.c -- partial implementation of the YIN algorithm, with some * fixes by DM. This code should be replaced with the fall 2002 * intro to computer music implementation project. */ #include "stdio.h" #ifdef UNIX #include "sys/file.h" #endif #ifndef mips #include "stdlib.h" #endif #include "snd.h" #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "yin.h" void yin_free(); /* for multiple channel results, one susp is shared by all sounds */ /* the susp in turn must point back to all sound list tails */ typedef struct yin_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; long blocksize; long stepsize; sample_type *block; float *temp; sample_type *fillptr; sample_type *endptr; snd_list_type chan[2]; /* array of back pointers */ long cnt; /* how many sample frames to read */ long m; long middle; } yin_susp_node, *yin_susp_type; // Uses cubic interpolation to return the value of x such // that the function defined by f(0), f(1), f(2), and f(3) // is maximized. // float CubicMaximize(float y0, float y1, float y2, float y3) { // Find coefficients of cubic float a, b, c, d; float da, db, dc; float discriminant; float x1, x2; float dda, ddb; a = (float) (y0/-6.0 + y1/2.0 - y2/2.0 + y3/6.0); b = (float) (y0 - 5.0*y1/2.0 + 2.0*y2 - y3/2.0); c = (float) (-11.0*y0/6.0 + 3.0*y1 - 3.0*y2/2.0 + y3/3.0); d = y0; // Take derivative da = 3*a; db = 2*b; dc = c; // Find zeroes of derivative using quadratic equation discriminant = db*db - 4*da*dc; if (discriminant < 0.0) return -1.0; // error x1 = (float) ((-db + sqrt(discriminant)) / (2 * da)); x2 = (float) ((-db - sqrt(discriminant)) / (2 * da)); // The one which corresponds to a local _maximum_ in the // cubic is the one we want - the one with a negative // second derivative dda = 2*da; ddb = db; if (dda*x1 + ddb < 0) return x1; else return x2; } void yin_compute(yin_susp_type susp, float *pitch, float *harmonicity) { float *samples = susp->block; int middle = susp->middle; /* int n = middle * 2; */ int m = susp->m; float threshold = 0.9F; float *results = susp->temp; /* samples is a buffer of samples */ /* n is the number of samples, equals twice longest period, must be even */ /* m is the shortest period in samples */ /* results is an array of size n/2 - m + 1, the number of different lags */ /* work from the middle of the buffer: */ int i, j; /* loop counters */ /* how many different lags do we compute? */ /* int iterations = middle + 1 - m; */ float left_energy = 0; float right_energy = 0; /* for each window, we keep the energy so we can compute the next one */ /* incrementally. First, we need to compute the energies for lag m-1: */ *pitch = 0; for (i = 0; i < m - 1; i++) { float left = samples[middle - 1 - i]; float right = samples[middle + i]; left_energy += left * left; right_energy += right * right; } for (i = m; i <= middle; i++) { /* i is the lag and the length of the window */ /* compute the energy for left and right */ float left, right, energy, a; float harmonic; left = samples[middle - i]; left_energy += left * left; right = samples[middle - 1 + i]; right_energy += right * right; /* compute the autocorrelation */ a = 0; for (j = 0; j < i; j++) { a += samples[middle - i + j] * samples[middle + j]; } energy = left_energy + right_energy; harmonic = (2 * a) / energy; results[i - m] = harmonic; } for (i = m; i <= middle; i++) { if (results[i - m] > threshold) { float f_i = (i - 1) + CubicMaximize(results[i - m - 1], results[i - m], results[i - m + 1], results[i - m + 2]); if (f_i < i - m - 1 || f_i > i - m + 2) f_i = (float) i; *pitch = (float) hz_to_step((float) susp->susp.sr / f_i); *harmonicity = results[i - m]; break; } } } /* yin_fetch - compute F0 and harmonicity using YIN approach. */ /* * The pitch (F0) is determined by finding two periods whose * inner product accounts for almost all of the energy. Let X and Y * be adjacent vectors of length N in the sample stream. Then, * if 2X*Y > threshold * (X*X + Y*Y) * then the period is given by N * In the algorithm, we compute different sizes until we find a * peak above threshold. Then, we use cubic interpolation to get * a precise value. If no peak above threshold is found, we return * the first peak. The second channel returns the value 2X*Y/(X*X+Y*Y) * which is refered to as the "harmonicity" -- the amount of energy * accounted for by periodicity. * * Low sample rates are advised because of the high cost of computing * inner products (fast autocorrelation is not used). * * The result is a 2-channel signal running at the requested rate. * The first channel is the estimated pitch, and the second channel * is the harmonicity. * * This code is adopted from multiread, currently the only other * multichannel suspension in Nyquist. Comments from multiread include: * The susp is shared by all channels. The susp has backpointers * to the tail-most snd_list node of each channel, and it is by * extending the list at these nodes that sounds are read in. * To avoid a circularity, the reference counts on snd_list nodes * do not include the backpointers from this susp. When a snd_list * node refcount goes to zero, the yin susp's free routine * is called. This must scan the backpointers to find the node that * has a zero refcount (the free routine is called before the node * is deallocated, so this is safe). The backpointer is then set * to NULL. When all backpointers are NULL, the susp itself is * deallocated, because it can only be referenced through the * snd_list nodes to which there are backpointers. */ void yin_fetch(yin_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo = 0; int n; sample_block_type f0; sample_block_values_type f0_ptr = NULL; sample_block_type harmonicity; sample_block_values_type harmonicity_ptr = NULL; register sample_block_values_type s_ptr_reg; register sample_type *fillptr_reg; register sample_type *endptr_reg = susp->endptr; if (susp->chan[0]) { falloc_sample_block(f0, "yin_fetch"); f0_ptr = f0->samples; /* Since susp->chan[i] exists, we want to append a block of samples. * The block, out, has been allocated. Before we insert the block, * we must figure out whether to insert a new snd_list_type node for * the block. Recall that before SND_get_next is called, the last * snd_list_type in the list will have a null block pointer, and the * snd_list_type's susp field points to the suspension (in this case, * susp). When SND_get_next (in sound.c) is called, it appends a new * snd_list_type and points the previous one to internal_zero_block * before calling this fetch routine. On the other hand, since * SND_get_next is only going to be called on one of the channels, the * other channels will not have had a snd_list_type appended. * SND_get_next does not tell us directly which channel it wants (it * doesn't know), but we can test by looking for a non-null block in the * snd_list_type pointed to by our back-pointers in susp->chan[]. If * the block is null, the channel was untouched by SND_get_next, and * we should append a snd_list_type. If it is non-null, then it * points to internal_zero_block (the block inserted by SND_get_next) * and a new snd_list_type has already been appended. */ /* Before proceeding, it may be that garbage collection ran when we * allocated out, so check again to see if susp->chan[j] is Null: */ if (!susp->chan[0]) { ffree_sample_block(f0, "yin_fetch"); f0 = NULL; /* make sure we don't free it again */ f0_ptr = NULL; /* make sure we don't output f0 samples */ } else if (!susp->chan[0]->block) { snd_list_type snd_list = snd_list_create((snd_susp_type) susp); /* Now we have a snd_list to append to the channel, but a very * interesting thing can happen here. snd_list_create, which * we just called, MAY have invoked the garbage collector, and * the GC MAY have freed all references to this channel, in which * case yin_free(susp) will have been called, and susp->chan[0] * will now be NULL! */ if (!susp->chan[0]) { ffree_snd_list(snd_list, "yin_fetch"); } else { susp->chan[0]->u.next = snd_list; } } /* see the note above: we don't know if susp->chan still exists */ /* Note: We DO know that susp still exists because even if we lost * some channels in a GC, someone is still calling SND_get_next on * some channel. I suppose that there might be some very pathological * code that could free a global reference to a sound that is in the * midst of being computed, perhaps by doing something bizarre in the * closure that snd_seq activates at the logical stop time of its first * sound, but I haven't thought that one through. */ if (susp->chan[0]) { susp->chan[0]->block = f0; /* check some assertions */ if (susp->chan[0]->u.next->u.susp != (snd_susp_type) susp) { nyquist_printf("didn't find susp at end of list for chan 0\n"); } } else if (f0) { /* we allocated f0, but don't need it anymore due to GC */ ffree_sample_block(f0, "yin_fetch"); f0_ptr = NULL; } } /* Now, repeat for channel 1 (comments omitted) */ if (susp->chan[1]) { falloc_sample_block(harmonicity, "yin_fetch"); harmonicity_ptr = harmonicity->samples; if (!susp->chan[1]) { ffree_sample_block(harmonicity, "yin_fetch"); harmonicity = NULL; /* make sure we don't free it again */ harmonicity_ptr = NULL; } else if (!susp->chan[1]->block) { snd_list_type snd_list = snd_list_create((snd_susp_type) susp); if (!susp->chan[1]) { ffree_snd_list(snd_list, "yin_fetch"); } else { susp->chan[1]->u.next = snd_list; } } if (susp->chan[1]) { susp->chan[1]->block = harmonicity; if (susp->chan[1]->u.next->u.susp != (snd_susp_type) susp) { nyquist_printf("didn't find susp at end of list for chan 1\n"); } } else if (harmonicity) { /* we allocated harmonicity, but don't need it anymore due to GC */ ffree_sample_block(harmonicity, "yin_fetch"); harmonicity_ptr = NULL; } } while (cnt < max_sample_block_len) { /* outer loop */ /* first, compute how many samples to generate in inner loop: */ /* don't overflow the output sample block */ togo = (max_sample_block_len - cnt) * susp->stepsize; /* don't run past the s input sample block */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo/susp->stepsize) { togo = (susp->terminate_cnt - (susp->susp.current + cnt)) * susp->stepsize; if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop = 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the output block) */ if (to_stop < togo/susp->stepsize) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we can set * the logical stop flag on this output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new block a the LST */ togo = to_stop * susp->stepsize; } } n = togo; s_ptr_reg = susp->s_ptr; fillptr_reg = susp->fillptr; if (n) do { /* the inner sample computation loop */ *fillptr_reg++ = *s_ptr_reg++; if (fillptr_reg >= endptr_reg) { float f0; float harmonicity; yin_compute(susp, &f0, &harmonicity); if (f0_ptr) *f0_ptr++ = f0; if (harmonicity_ptr) *harmonicity_ptr++ = harmonicity; cnt++; fillptr_reg -= susp->stepsize; } } while (--n); /* inner loop */ /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; susp->fillptr = fillptr_reg; susp_took(s_cnt, togo); } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* yin_fetch */ void yin_mark(yin_susp_type susp) { sound_xlmark(susp->s); } void yin_free(yin_susp_type susp) { int j; boolean active = false; /* stdputstr("yin_free: "); */ for (j = 0; j < 2; j++) { if (susp->chan[j]) { if (susp->chan[j]->refcnt) active = true; else { susp->chan[j] = NULL; /* nyquist_printf("deactivating channel %d\n", j); */ } } } if (!active) { /* stdputstr("all channels freed, freeing susp now\n"); */ ffree_generic(susp, sizeof(yin_susp_node), "yin_free"); sound_unref(susp->s); free(susp->block); free(susp->temp); } } void yin_print_tree(yin_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } LVAL snd_make_yin(sound_type s, double low_step, double high_step, long stepsize) { LVAL result; int j; register yin_susp_type susp; rate_type sr = s->sr; time_type t0 = s->t0; falloc_generic(susp, yin_susp_node, "snd_make_yin"); susp->susp.fetch = yin_fetch; susp->terminate_cnt = UNKNOWN; /* initialize susp state */ susp->susp.free = yin_free; susp->susp.sr = sr / stepsize; susp->susp.t0 = t0; susp->susp.mark = yin_mark; susp->susp.print_tree = yin_print_tree; susp->susp.name = "yin"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->m = (long) (sr / step_to_hz(high_step)); if (susp->m < 2) susp->m = 2; /* add 1 to make sure we round up */ susp->middle = (long) (sr / step_to_hz(low_step)) + 1; susp->blocksize = susp->middle * 2; susp->stepsize = stepsize; /* blocksize must be at least step size to implement stepping */ if (susp->stepsize > susp->blocksize) susp->blocksize = susp->stepsize; susp->block = (sample_type *) malloc(susp->blocksize * sizeof(sample_type)); susp->temp = (float *) malloc((susp->middle - susp->m + 1) * sizeof(float)); susp->fillptr = susp->block; susp->endptr = susp->block + susp->blocksize; xlsave1(result); result = newvector(2); /* create array for F0 and harmonicity */ /* create sounds to return */ for (j = 0; j < 2; j++) { sound_type snd = sound_create((snd_susp_type)susp, susp->susp.t0, susp->susp.sr, 1.0); LVAL snd_lval = cvsound(snd); /* nyquist_printf("yin_create: sound %d is %x, LVAL %x\n", j, snd, snd_lval); */ setelement(result, j, snd_lval); susp->chan[j] = snd->list; } xlpop(); return result; } LVAL snd_yin(sound_type s, double low_step, double high_step, long stepsize) { sound_type s_copy = sound_copy(s); return snd_make_yin(s_copy, low_step, high_step, stepsize); } nyquist-3.05/nyqsrc/seqinterf.c0000644000175000000620000000512110144436365015653 0ustar stevestaff/* seqinterf.c -- interface to sequence data type for XLISP */ #include "switches.h" #include "xlisp.h" #include "stdio.h" #include "cext.h" #include "userio.h" #include "midifns.h" #include "timebase.h" #include "moxc.h" #include "seq.h" #include "seqinterf.h" /* seq_next -- advance to the next event, return TRUE if found */ /**/ boolean seq_next(seq_type seq) { if (seq->current) { seq->current = seq->current->next; } return seq->current != NULL; } /* seq_get -- get event data for the current event */ /**/ void seq_get(seq_type seq, long *eventtype, long *ntime, long *line, long *chan, long *value1, long *value2, long *dur) { event_type ev = seq->current; if (!ev) *eventtype = SEQ_DONE; else if (is_note(ev)) { if (ev->value != NO_PITCH) { *eventtype = SEQ_NOTE; *ntime = ev->ntime; *line = ev->nline; *chan = vc_voice(ev->nvoice); *value1 = ev->value; *value2 = ev->u.note.ndur & 0xFF; *dur = ev->u.note.ndur >> 8; } else { *eventtype = SEQ_OTHER; } } else { *eventtype = SEQ_CTRL; *ntime = ev->ntime; *line = ev->nline; *chan = vc_voice(ev->nvoice); *value2 = ev->value; switch (vc_ctrl(ev->nvoice)) { case PSWITCH_CTRL: *value1 = PORTASWITCH; break; case MODWHEEL_CTRL: *value1 = MODWHEEL; break; case TOUCH_CTRL: *eventtype = SEQ_TOUCH; *value1 = ev->value; break; case VOLUME_CTRL: *value1 = VOLUME; break; case BEND_CTRL: *eventtype = SEQ_BEND; *value1 = ev->value << 6; break; case PROGRAM_CTRL: *eventtype = SEQ_PRGM; *value1 = ev->value + 1; break; case ESC_CTRL: switch (ev->value) { case CALL_VALUE: case CLOCK_VALUE: case MACRO_VALUE: case CTRLRAMP_VALUE: case DEFRAMP_VALUE: case SETI_VALUE: *eventtype = SEQ_OTHER; break; case MACCTRL_VALUE: *value1 = ev->u.macctrl.ctrl_number; *value2 = ev->u.macctrl.value; break; default: xlabort("unexpected ESC_CTRL value\n"); break; } break; default: xlabort("unexpected seq data\n"); break; } } } nyquist-3.05/nyqsrc/falloc.c0000644000175000000620000001561311466723256015130 0ustar stevestaff/* * falloc.c * data for Nyquist memory allocation. */ #include #include #include "xlisp.h" #include "sound.h" #include "falloc.h" /* special free lists */ CQUE *sample_block_free = NULL; /* really a sample_block_type */ /* special counts */ int sample_block_used = 0; int sample_block_low_water = 0; int sample_block_total = 0; int snd_list_used = 0; int sound_used = 0; /* generic free lists */ CQUE *generic_free[MAXLISTS]; void falloc_init(void) { int i; for (i = 0; i < MAXLISTS; i++) generic_free[i] = NULL; } /* memory pool */ char *poolp = NULL; char *poolend = NULL; /* sample block memory pool */ char *spoolp = NULL; char *spoolend = NULL; int npools = 0; #if defined(TRACK_POOLS) && TRACK_POOLS #define POOL_HEAD_SIZE (round_size(sizeof(CQUE))) CQUE *pools = NULL; #endif void sound_already_free_test(s) sound_type s; { sound_type sp; for (sp = (sound_type) sound_free; sp; sp = (sound_type) ((CQUE *) sp)->qnext) { if (s == sp) { stdputstr("SOUND ALREADY FREE!!!"); fflush(stdout); sp = 0; sp->list = 0; /* trap to debugger */ } } } /* new_pool -- allocate a new pool from which mem is allocated */ /**/ void new_pool(void) { poolp = (char *) malloc(MAXPOOLSIZE); if (poolp == NULL) { fprintf(STDERR, "Nyquist: out of memory!\n"); EXIT(1); } poolend = poolp + MAXPOOLSIZE; npools++; /* stick to double word boundaries */ poolp = (char *) round_size(((long) poolp)); } /* new_spool -- allocate a new spool from which sample blocks are allocated */ /**/ void new_spool(void) { #if defined(TRACK_POOLS) && TRACK_POOLS spoolp = (char *) malloc(MAXSPOOLSIZE + POOL_HEAD_SIZE); #else spoolp = (char *) malloc(MAXSPOOLSIZE); #endif if (spoolp == NULL) { fprintf(STDERR, "Nyquist: out of memory!\n"); EXIT(1); } #if defined(TRACK_POOLS) && TRACK_POOLS Qenter(pools, spoolp); spoolp += POOL_HEAD_SIZE; #endif spoolend = spoolp + MAXSPOOLSIZE; npools++; /* stick to double word boundaries */ spoolp = (char *) round_size(((long) spoolp)); } /* find_sample_block -- get sample block when freelist is empty */ /* Try these strategies in order: 1) try free list 2) use pool to get sample_blocks_low_water + BLOCKS_PER_GC blocks or until pool runs out 3) GC and try free list again, set sample_blocks_low_water to sample_blocks_used 4) try pool again 5) allocate new pool and use it */ sample_block_type find_sample_block(void) { sample_block_type sp; if (sample_block_total < sample_block_low_water + BLOCKS_PER_GC && check_spool(round_size(sizeof(sample_block_node)))) { if (DEBUG_MEM) spoolp += DEBUG_MEM_INFO_SIZE; sp = (sample_block_type) spoolp; spoolp += round_size(sizeof(sample_block_node)); sample_block_total++; /* printf("fp%d ", sample_block_total - sample_block_low_water); */ } else { /* printf("falloc calling gc\n"); */ gc(); sample_block_low_water = sample_block_used; if (!Qempty(sample_block_free)) { Qget(sample_block_free, sample_block_type, sp); /* printf("gc, then from freelist\n"); */ } else if (check_spool(round_size(sizeof(sample_block_node)))) { if (DEBUG_MEM) spoolp += DEBUG_MEM_INFO_SIZE; sp = (sample_block_type) spoolp; spoolp += round_size(sizeof(sample_block_node)); sample_block_total++; /* printf("gc, then from spool\n"); */ } else { new_spool(); if (DEBUG_MEM) spoolp += DEBUG_MEM_INFO_SIZE; sp = (sample_block_type) spoolp; spoolp += round_size(sizeof(sample_block_node)); sample_block_total++; /* printf("gc, then new spool\n"); */ } } return sp; } /* get_from_pool -- return size bytes from pool memory */ /**/ char *get_from_pool(size_t siz) { if (!check_pool(siz)) { new_pool(); } poolp += siz; if (DEBUG_MEM) poolp += DEBUG_MEM_INFO_SIZE; /* allow for debug info */ return poolp - siz; } #if defined(TRACK_POOLS) && TRACK_POOLS /* falloc_gc -- return empty pools to the system */ /* * Algorithm: for each pool, move all free sample blocks * (on the sample_block_free list) to tlist. If tlist * has ALL of the blocks in the pool (determined by * byte counts), the pool is returned to the heap. */ void falloc_gc() { CQUE *lp = NULL; CQUE *cp; CQUE *np; CQUE *tlist = NULL; /* Scan all allocated pools */ for (cp = pools; cp; lp = cp, cp = np) { char *str = ((char *)cp) + POOL_HEAD_SIZE; char *end = str + MAXSPOOLSIZE; long tsiz = end - str; long csiz = 0; CQUE *tsave = NULL; CQUE *ln = NULL; CQUE *cn; CQUE *nn; /* Save pointer to next pool */ np = cp->qnext; /* Remember head of temp free list */ tsave = tlist; /* Scan all nodes on the free list */ for (cn = sample_block_free; cn; ln = cn, cn = nn) { /* Get next node */ nn = cn->qnext; /* Count it if the node belongs to this pool */ if (cn >= (CQUE *) str && cn <= (CQUE *) end) { csiz += round_size(sizeof(sample_block_node)); Qenter(tlist, cn); /* Unlink the node */ if (cn == sample_block_free) { sample_block_free = nn; cn = NULL; } else { ln->qnext = nn; cn = ln; } } } /* The pool had inuse nodes */ if (csiz != tsiz) { continue; } /* Remove the nodes from the temp free list */ tlist = tsave; /* Maintain stats */ sample_block_total -= (tsiz / round_size(sizeof(sample_block_node))); npools--; /* If this is the active pool, then reset current pointers */ if (spoolp >= str && spoolp <= end) { spoolp = NULL; spoolend = NULL; } /* Release the pool to the system */ free(cp); /* Unlink this pool from the list */ if (cp == pools) { pools = np; cp = NULL; } else { /* lp cannot be null here: On 1st iteration, lp == NULL, but * cp == pools, so code above is executed. Before the for-loop * iterates, pools == np (assigned above), and cp == NULL. The * for-loop update (lp=cp,cp=np) produces lp == NULL, cp == pools. * Since cp == pools, this else branch will not be taken. * The other path to this code is via the "continue" above. In that * case, the update (lp=cp,cp=np) makes lp a valid pointer or else * the loop exits. * The assert(lp) is here to possibly make static analyzers happy. */ assert(lp); lp->qnext = np; cp = lp; } } /* Resave list of free nodes */ sample_block_free = tlist; } #endif nyquist-3.05/nyqsrc/avg.h0000644000175000000620000000045210144436365014437 0ustar stevestaffsound_type snd_make_avg(sound_type s, long blocksize, long stepsize, long op); sound_type snd_avg(sound_type s, long blocksize, long stepsize, long op); /* LISP: (snd-avg SOUND FIXNUM FIXNUM FIXNUM) */ #define op_average 1 #define op_peak 2 /* LISP-SRC: (setf OP-AVERAGE 1) (setf OP-PEAK 2) */ nyquist-3.05/nyqsrc/fft.c0000644000175000000620000001567111466723256014453 0ustar stevestaff/* fft.c -- implement snd_fft */ #define _USE_MATH_DEFINES 1 /* for Visual C++ to get M_LN2 */ #include #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "fft.h" #include "fftext.h" /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm change for portability: min->MIN */ /* NOTE: this code does not properly handle start times that do not * correspond to the time of the first actual sample */ /* The snd_fft function is based on snd_fetch_array */ /* * storage layout: the extra field points to extra state that we'll use * extra[0] -> length of extra storage * extra[1] -> CNT (number of samples in current block) * extra[2] -> INDEX (current sample index in current block) * extra[3] -> FILLCNT (how many samples in buffer) * extra[4] -> TERMCNT (how many samples until termination) * extra[5 .. 5+len-1] -> samples (stored as floats) * extra[5+len .. 5+2*len-1] -> array of samples to fft * extra[5+2*len ... 5+3*len-1] -> window coefficients * * Termination details: * Return NIL when the sound terminates. * Termination is defined as the point where all original * signal samples have been shifted out of the samples buffer * so that all that's left are zeros from beyond the termination * point. * Implementation: when termination is discovered, set TERMCNT * to the number of samples to be shifted out. TERMCNT is initially * -1 as a flag that we haven't seen the termination yet. * Each time samples are shifted, decrement TERMCNT by the shift amount. * When TERMCNT goes to zero, return NULL. */ #define CNT extra[1] #define INDEX extra[2] #define FILLCNT extra[3] #define TERMCNT extra[4] #define OFFSET 5 #define SAMPLES list->block->samples /* DEBUGGING PRINT FUNCTION: void printfloats(char *caption, float *data, int len) { int i; printf("%s: ", caption); for (i = 0; i < len; i++) { printf("%d:%g ", i, data[i]); } printf("\n"); } */ void n_samples_from_sound(sound_type s, long n, float *table) { long blocklen; sample_type scale_factor = s->scale; s = sound_copy(s); while (n > 0) { sample_block_type sampblock = sound_get_next(s, &blocklen); long togo = MIN(blocklen, n); long i; sample_block_values_type sbufp = sampblock->samples; for (i = 0; i < togo; i++) { *table++ = (float) (*sbufp++ * scale_factor); } n -= togo; } sound_unref(s); } LVAL snd_fft(sound_type s, long len, long step, LVAL winval) { long i, m, maxlen, skip, fillptr; float *samples; float *temp_fft; float *window; LVAL result; if (len < 1) xlfail("len < 1"); if (!s->extra) { /* this is the first call, so fix up s */ sound_type w = NULL; if (winval) { if (soundp(winval)) { w = getsound(winval); } else { xlerror("expected a sound", winval); } } /* note: any storage required by fft must be allocated here in a * contiguous block of memory who's size is given by the first long * in the block. Here, there are 4 more longs after the size, and * then room for 3*len floats (assumes that floats and longs take * equal space). * * The reason for 3*len floats is to provide space for: * the samples to be transformed (len) * the complex FFT result (len) * the window coefficients (len) * * The reason for this storage restriction is that when a sound is * freed, the block of memory pointed to by extra is also freed. * There is no function call that might free a more complex * structure (this could be added in sound.c, however, if it's * really necessary). */ s->extra = (long *) malloc(sizeof(long) * (3 * len + OFFSET)); s->extra[0] = sizeof(long) * (3 * len + OFFSET); s->CNT = s->INDEX = s->FILLCNT = 0; s->TERMCNT = -1; maxlen = len; window = (float *) &(s->extra[OFFSET + 2 * len]); /* fill the window from w */ if (!w) { for (i = 0; i < len; i++) *window++ = 1.0F; } else { n_samples_from_sound(w, len, window); } } else { maxlen = ((s->extra[0] / sizeof(long)) - OFFSET) / 3; if (maxlen != len) xlfail("len changed from initial value"); } samples = (float *) &(s->extra[OFFSET]); temp_fft = samples + len; window = temp_fft + len; /* step 1: refill buffer with samples */ fillptr = s->FILLCNT; while (fillptr < maxlen) { if (s->INDEX == s->CNT) { sound_get_next(s, &(s->CNT)); if (s->SAMPLES == zero_block->samples) { if (s->TERMCNT < 0) s->TERMCNT = fillptr; } s->INDEX = 0; } samples[fillptr++] = s->SAMPLES[s->INDEX++] * s->scale; } s->FILLCNT = fillptr; /* it is important to test here AFTER filling the buffer, because * if fillptr WAS 0 when we hit the zero_block, then filling the * buffer will set TERMCNT to 0. */ if (s->TERMCNT == 0) return NULL; /* logical stop time is ignored by this code -- to fix this, * you would need a way to return the logical stop time to * the caller. */ /* step 2: construct an array and return it */ xlsave1(result); result = newvector(len); /* first len floats will be real part, second len floats imaginary * copy buffer to temp_fft with windowing */ for (i = 0; i < len; i++) { temp_fft[i] = samples[i] * *window++; } /* perform the fft: */ m = round(log(len) / M_LN2); /* compute log-base-2(len) */ if (!fftInit(m)) rffts(temp_fft, m, 1); else xlfail("FFT initialization error"); /* move results to Lisp array */ setelement(result, 0, cvflonum(temp_fft[0])); setelement(result, len - 1, cvflonum(temp_fft[1])); for (i = 2; i < len; i++) { setelement(result, i - 1, cvflonum(temp_fft[i])); } /* step 3: shift samples by step */ if (step < 0) xlfail("step < 0"); s->FILLCNT -= step; if (s->FILLCNT < 0) s->FILLCNT = 0; for (i = 0; i < s->FILLCNT; i++) { samples[i] = samples[i + step]; } if (s->TERMCNT >= 0) { s->TERMCNT -= step; if (s->TERMCNT < 0) s->TERMCNT = 0; } /* step 4: advance in sound to next sample we need * (only does work if step > size of buffer) */ skip = step - maxlen; while (skip > 0) { long remaining = s->CNT - s->INDEX; if (remaining >= skip) { s->INDEX += skip; skip = 0; } else { skip -= remaining; sound_get_next(s, &(s->CNT)); s->INDEX = 0; } } /* restore the stack */ xlpop(); return result; } /* snd_fetch_array */ nyquist-3.05/nyqsrc/seqext.h0000644000175000000620000000056510144436365015200 0ustar stevestaff/* seqext.h -- header for seq extensions for xlisp */ void seqext_init(); void seqext_symbols(); boolean seqp(); extern xtype_desc seq_desc; extern LVAL s_seq; #define cvptrbool(v) ((LVAL) ((v) ? s_true : NIL)) #define cvseq(v) ((LVAL) ((v) ? cvextern(seq_desc, (void *)(v)) : NIL)) #define xlgaseq() (testarg(typearg(seqp))) #define getseq(x) ((seq_type) getinst(x)) nyquist-3.05/nyqsrc/sndwrite.h0000644000175000000620000000116011466723256015524 0ustar stevestaff/* sndwrite.h -- header to write sounds to files */ double sound_save(LVAL snd_expr, long n, unsigned char *filename, long format, long mode, long bits, long swap, double *sr, long *nchans, double *duration, LVAL play); /* LISP: (SND-SAVE ANY FIXNUM STRING FIXNUM FIXNUM FIXNUM FIXNUM ANYNUM^ FIXNUM^ ANYNUM^ ANY) */ double sound_overwrite(LVAL snd_expr, long n, unsigned char *filename, double offset_secs, long format, long mode, long bits, long swap, double *duration); /* LISP: (SND-OVERWRITE ANY FIXNUM STRING ANYNUM FIXNUM FIXNUM FIXNUM FIXNUM ANYNUM^) */ nyquist-3.05/nyqsrc/sndread.h0000644000175000000620000000141411466723256015307 0ustar stevestaff/* fileio.h -- Nyquist code to read sound files */ /* for multiple channel files, one susp is shared by all sounds */ /* the susp in turn must point back to all sound list tails */ typedef struct read_susp_struct { snd_susp_node susp; SNDFILE *sndfile; SF_INFO sf_info; snd_list_type *chan; /* array of back pointers */ long cnt; /* how many sample frames to read */ } read_susp_node, *read_susp_type; LVAL snd_make_read(unsigned char *filename, time_type offset, time_type t0, long *format, long *channels, long *mode, long *bits, long *swap, double *srate, double *dur, long *flags, long *byte_offset); /* LISP: (SND-READ STRING ANYNUM ANYNUM FIXNUM* FIXNUM* FIXNUM* FIXNUM* FIXNUM* ANYNUM* ANYNUM* FIXNUM^ FIXNUM^) */ void read_free(); nyquist-3.05/nyqsrc/sndwritepa.c0000644000175000000620000006552211512143043016032 0ustar stevestaff/* sndwrite.c -- write sounds to files */ #include "stdlib.h" #include "switches.h" #include "string.h" #ifdef UNIX #include "sys/types.h" #endif #ifdef WINDOWS #include #endif #include /* include sound.h first because it includes math.h * which declares abs(). cext.h #defines abs()! * sound.h depends on xlisp.h */ #include "xlisp.h" #include "sound.h" #include "cext.h" #include "userio.h" #include "falloc.h" #include "sndfmt.h" #include "sndwrite.h" #include "extern.h" #include "sndfile.h" #ifdef UNIX #include "sys/file.h" /* #include */ #include #else #ifdef MACINTOSH #include #include #define L_SET SEEK_SET #define L_INCR SEEK_CUR #endif #endif /* Previously, Nyquist would wrap samples that * overflowed -- this produces horrible output, * but makes it really easy to detect clipping, * which I found helpful in my own work and good * for students too since the effect is impossible * to ignore. Now that Nyquist is doing IO to * libraries that clip, we're going to artificially * generate the wrapping here. This is floating point * wrapping, so +1.0 does not wrap (it would if it * were an integer since the maximum sample value for * 16-bit data is a bit less than 1.) Since this is extra * overhead, I'm trying to be a bit clever by using * the compare to max_sample to eliminate compares * for clipping in the common case. * * INPUTS: max_sample -- initially 0.0 * threshold -- initially 0.0 * s -- the value of the current sample * x -- if s has to be wrapped, put the value here */ #define COMPUTE_MAXIMUM_AND_WRAP(x) \ if (s > threshold) { \ if (s > max_sample) { \ max_sample = s; \ threshold = min(1.0, s); \ } \ if (s > 1.0) { \ s = fmod(s + 1.0, 2.0) - 1.0; \ (x) = s; \ } \ } else if (s < -threshold) { \ if (s < -max_sample) { \ max_sample = -s; \ threshold = min(1.0, -s); \ } \ if (s < -1.0) { \ s = -(fmod(-s + 1.0, 2.0) - 1.0); \ (x) = s; \ } \ } // the s < -threshold case is tricky: // flip the signal, do the wrap, flip again // in order to pass positive values to fmod /* When not using PCM encodings, we do not wrap * samples -- therefore float sample formats do * not wrap or clip when written to sound files */ #define COMPUTE_MAXIMUM() \ if (s > max_sample) { \ max_sample = s; \ } else if (s < -max_sample) { \ max_sample = -s; \ } // should be looking for local portaudio #include "portaudio.h" long flush_count = 0; /* how many samples to write to finish */ #define D if (0) int sndwrite_trace = 0; /* debugging */ static int portaudio_initialized = false; /* is PortAudio initialized? */ void portaudio_exit() { if (portaudio_initialized) { Pa_Terminate(); } } sample_type sound_save_sound(LVAL s_as_lval, long n, SF_INFO *sf_info, SNDFILE *snd_file, float *buf, long *ntotal, PaStream *audio_stream); sample_type sound_save_array(LVAL sa, long n, SF_INFO *sf_info, SNDFILE *snd_file, float *buf, long *ntotal, PaStream *audio_stream); unsigned char st_linear_to_ulaw(int sample);/* jlh not used anywhere */ typedef struct { sound_type sound; long cnt; sample_block_values_type ptr; double scale; int terminated; } sound_state_node, *sound_state_type; static int portaudio_error(PaError err, char *problem) { char msgbuffer[256]; if (err != paNoError) { sprintf(msgbuffer, "%s, error %d, %s.", problem, (int) err, Pa_GetErrorText(err)); xlerrprint("warning", NULL, msgbuffer, s_unbound); return true; } return false; } LVAL prepare_audio(LVAL play, SF_INFO *sf_info, PaStream **audio_stream) { PaStreamParameters output_parameters; int i; int num_devices; const PaDeviceInfo *device_info; const PaHostApiInfo *host_info; if (!portaudio_initialized) { if (portaudio_error(Pa_Initialize(), "could not initialize portaudio")) { return NIL; } portaudio_initialized = TRUE; } output_parameters.device = Pa_GetDefaultOutputDevice(); output_parameters.channelCount = sf_info->channels; output_parameters.sampleFormat = paFloat32; output_parameters.hostApiSpecificStreamInfo = NULL; /* remember that Nyquist has to do GC */ output_parameters.suggestedLatency = sound_latency; // Initialize the audio stream for output // If this is Linux, prefer to open ALSA device num_devices = Pa_GetDeviceCount(); for (i = 0; i < num_devices; i++) { device_info = Pa_GetDeviceInfo(i); host_info = Pa_GetHostApiInfo(device_info->hostApi); if (host_info->type == paALSA) { output_parameters.device = i; break; } } if (portaudio_error( Pa_OpenStream(audio_stream, NULL /* input */, &output_parameters, sf_info->samplerate, max_sample_block_len, paClipOff, NULL /* callback */, NULL /* userdata */), "could not open audio")) { return NIL; } flush_count = (long) (sf_info->samplerate * (sound_latency + 0.2)); if (portaudio_error(Pa_StartStream(*audio_stream), "could not start audio")) { return NIL; } return play; } /* finish_audio -- flush the remaining samples, then close */ /**/ void finish_audio(PaStream *audio_stream) { /* portaudio_error(Pa_StopStream(audio_stream), "could not stop stream"); */ /* write Latency frames of audio to make sure all samples are played */ float zero[MAX_SND_CHANNELS * 16]; int i; for (i = 0; i < MAX_SND_CHANNELS * 16; i++) zero[i] = 0.0F; while (flush_count > 0) { Pa_WriteStream(audio_stream, zero, 16); flush_count -= 16; } portaudio_error(Pa_CloseStream(audio_stream), "could not close audio"); } long lookup_format(long format, long mode, long bits, long swap) { long sf_mode; long sf_format; switch (format) { case SND_HEAD_NONE: return 0; break; // get info from file case SND_HEAD_AIFF: sf_format = SF_FORMAT_AIFF; break; case SND_HEAD_IRCAM: sf_format = SF_FORMAT_IRCAM; break; case SND_HEAD_NEXT: sf_format = SF_FORMAT_AU; break; case SND_HEAD_WAVE: sf_format = SF_FORMAT_WAV; break; case SND_HEAD_PAF: sf_format = SF_FORMAT_PAF; break; case SND_HEAD_SVX: sf_format = SF_FORMAT_SVX; break; case SND_HEAD_NIST: sf_format = SF_FORMAT_NIST; break; case SND_HEAD_VOC: sf_format = SF_FORMAT_VOC; break; case SND_HEAD_W64: sf_format = SF_FORMAT_W64; break; case SND_HEAD_MAT4: sf_format = SF_FORMAT_MAT4; break; case SND_HEAD_MAT5: sf_format = SF_FORMAT_MAT5; break; case SND_HEAD_PVF: sf_format = SF_FORMAT_PVF; break; case SND_HEAD_XI: sf_format = SF_FORMAT_XI; break; case SND_HEAD_HTK: sf_format = SF_FORMAT_HTK; break; case SND_HEAD_SDS: sf_format = SF_FORMAT_SDS; break; case SND_HEAD_AVR: sf_format = SF_FORMAT_AVR; break; case SND_HEAD_SD2: sf_format = SF_FORMAT_SD2; break; case SND_HEAD_FLAC: sf_format = SF_FORMAT_FLAC; break; case SND_HEAD_CAF: sf_format = SF_FORMAT_CAF; break; case SND_HEAD_RAW: sf_format = SF_FORMAT_RAW; #ifdef XL_BIG_ENDIAN sf_format |= (swap ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG); #endif #ifdef XL_LITTLE_ENDIAN sf_format |= (swap ? SF_ENDIAN_LITTLE : SF_ENDIAN_LITTLE); #endif break; default: sf_format = SF_FORMAT_WAV; nyquist_printf("s-save: unrecognized format, using SND_HEAD_WAVE\n"); break; } switch (mode) { case SND_MODE_ADPCM: sf_mode = SF_FORMAT_IMA_ADPCM; break; case SND_MODE_UPCM: if (bits <= 8) { sf_mode = SF_FORMAT_PCM_U8; break; } else { nyquist_printf("s-save: SND_MODE_UPCM is for 8-bit samples only, " "using PCM instead\n"); } /* no break here, fall through to SND_MODE_PCM... */ default: nyquist_printf("s-save: unrecognized mode (%ld), using PCM\n", mode); /* no break, fall through as SND_MODE_PCM */ case SND_MODE_PCM: if (bits <= 8) sf_mode = SF_FORMAT_PCM_S8; else if (bits <= 16) sf_mode = SF_FORMAT_PCM_16; else if (bits <= 24) sf_mode = SF_FORMAT_PCM_24; else if (bits <= 32) sf_mode = SF_FORMAT_PCM_32; else { sf_mode = SF_FORMAT_PCM_16; nyquist_printf( "s-save: bad bits parameter (%ld), using 16-bit PCM\n", bits); } break; case SND_MODE_ULAW: sf_mode = SF_FORMAT_ULAW; break; case SND_MODE_ALAW: sf_mode = SF_FORMAT_ALAW; break; case SND_MODE_FLOAT: sf_mode = SF_FORMAT_FLOAT; break; case SND_MODE_DOUBLE: sf_mode = SF_FORMAT_DOUBLE; break; case SND_MODE_UNKNOWN: sf_mode = SF_FORMAT_PCM_16; break; case SND_MODE_GSM610: sf_mode = SF_FORMAT_GSM610; break; case SND_MODE_DWVW: if (bits <= 12) sf_mode = SF_FORMAT_DWVW_12; else if (bits <= 16) sf_mode = SF_FORMAT_DWVW_16; else if (bits <= 24) sf_mode = SF_FORMAT_DWVW_24; else sf_mode = SF_FORMAT_DWVW_N; break; case SND_MODE_DPCM: if (bits <= 8) sf_mode = SF_FORMAT_DPCM_8; else if (bits <= 16) sf_mode = SF_FORMAT_DPCM_16; else { sf_mode = SF_FORMAT_DPCM_16; nyquist_printf( "s-save: bad bits parameter (%ld), using 16-bit DPCM\n", bits); } break; case SND_MODE_MSADPCM: sf_mode = SF_FORMAT_MS_ADPCM; break; } return sf_format | sf_mode; } double sound_save( LVAL snd_expr, long n, unsigned char *filename, long format, long mode, long bits, long swap, double *sr, long *nchans, double *duration, LVAL play) { LVAL result; float *buf; long ntotal; double max_sample; SNDFILE *sndfile = NULL; SF_INFO sf_info; PaStream *audio_stream = NULL; gc(); memset(&sf_info, 0, sizeof(sf_info)); sf_info.format = lookup_format(format, mode, bits, swap); result = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE RESULT IS UNPROTECTED */ if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); *nchans = sf_info.channels = i; while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { xlerror("sound_save: array has non-sound element", result); } } /* assume all are the same: */ *sr = sf_info.samplerate = ROUND(getsound(getelement(result, 0))->sr); /* note: if filename is "", then don't write file; therefore, * write the file if (filename[0]) */ if (filename[0]) { sndfile = sf_open((char *) filename, SFM_WRITE, &sf_info); if (sndfile) { /* use proper scale factor: 8000 vs 7FFF */ sf_command(sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE); } } if (play) play = prepare_audio(play, &sf_info, &audio_stream); if ((buf = (float *) malloc(max_sample_block_len * sf_info.channels * sizeof(float))) == NULL) { xlabort("snd_save -- couldn't allocate memory"); } max_sample = sound_save_array(result, n, &sf_info, sndfile, buf, &ntotal, audio_stream); *duration = ntotal / *sr; if (sndfile) sf_close(sndfile); if (play != NIL) finish_audio(audio_stream); } else if (exttypep(result, a_sound)) { *nchans = sf_info.channels = 1; sf_info.samplerate = ROUND((getsound(result))->sr); *sr = sf_info.samplerate; if (filename[0]) { sndfile = sf_open((char *) filename, SFM_WRITE, &sf_info); if (sndfile) { /* use proper scale factor: 8000 vs 7FFF */ sf_command(sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE); } else xlabort("snd_save -- could not open file or bad parameters"); } if (play) play = prepare_audio(play, &sf_info, &audio_stream); if ((buf = (float *) malloc(max_sample_block_len * sizeof(float))) == NULL) { xlabort("snd_save -- couldn't allocate memory"); } max_sample = sound_save_sound(result, n, &sf_info, sndfile, buf, &ntotal, audio_stream); *duration = ntotal / *sr; if (sndfile) sf_close(sndfile); if (play != NIL) finish_audio(audio_stream); } else { xlerror("sound_save: expression did not return a sound", result); max_sample = 0.0; } free(buf); return max_sample; } /* open_for_write -- helper function for sound_overwrite */ /* * if the format is RAW, then fill in sf_info according to * sound sample rate and channels. Otherwise, open the file * and see if the sample rate and channele match. */ SNDFILE *open_for_write(unsigned char *filename, long direction, long format, SF_INFO *sf_info, int channels, long srate, double offset, float **buf) /* channels and srate are based on the sound we're writing to the file */ { SNDFILE *sndfile; sf_count_t frames; // frame count passed into sf_seek char error[140]; // error messages are formatted here sf_count_t rslt; // frame count returned from sf_seek if (format == SND_HEAD_RAW) { sf_info->channels = channels; sf_info->samplerate = srate; } else { sf_info->format = 0; } sndfile = sf_open((const char *) filename, direction, sf_info); if (!sndfile) { sprintf(error, "snd_overwrite: cannot open file %s", filename); xlabort(error); } /* use proper scale factor: 8000 vs 7FFF */ sf_command(sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE); frames = round(offset * sf_info->samplerate); rslt = sf_seek(sndfile, frames, SEEK_SET); if (rslt < 0) { sprintf(error, "snd_overwrite: cannot seek to frame %lld of %s", frames, filename); xlabort(error); } if (sf_info->channels != channels) { sprintf(error, "%s%d%s%d%s", "snd_overwrite: number of channels in sound (", channels, ") does not match\n number of channels in file (", sf_info->channels, ")"); sf_close(sndfile); xlabort(error); } if (sf_info->samplerate != srate) { sprintf(error, "%s%ld%s%d%s", "snd_overwrite: sample rate in sound (", srate, ") does not match\n sample rate in file (", sf_info->samplerate, ")"); sf_close(sndfile); xlabort(error); } if ((*buf = (float *) malloc(max_sample_block_len * channels * sizeof(float))) == NULL) { xlabort("snd_overwrite: couldn't allocate memory"); } return sndfile; } double sound_overwrite( LVAL snd_expr, long n, unsigned char *filename, double offset_secs, long format, long mode, long bits, long swap, double *duration) { LVAL result; // the SOUND to be evaluated SF_INFO sf_info; // info about the sound file double max_sample; // return value long ntotal; // how many samples were overwritten /* long flags; */ // first check if sound file exists, do not create new file FILE *file = fopen((char *) filename, "rb"); // if not then fail if (!file) { *duration = 0; return 0.0; } else { fclose(file); } memset(&sf_info, 0, sizeof(sf_info)); sf_info.format = lookup_format(format, mode, bits, swap); result = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE RESULT IS UNPROTECTED */ if (vectorp(result)) { SNDFILE *sndfile; // opened sound file float *buf; // buffer for samples read in from sound file /* make sure all elements are of type a_sound */ long i = getsize(result); long channels = i; while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { xlerror("sound_save: array has non-sound element", result); } } sndfile = open_for_write(filename, SFM_RDWR, format, &sf_info, channels, ROUND(getsound(getelement(result, 0))->sr), offset_secs, &buf); max_sample = sound_save_array(result, n, &sf_info, sndfile, buf, &ntotal, NULL); *duration = ntotal / (double) sf_info.samplerate; free(buf); sf_close(sndfile); } else if (exttypep(result, a_sound)) { SNDFILE *sndfile; // opened sound file float *buf; // buffer for samples read in from sound file sndfile = open_for_write(filename, SFM_RDWR, format, &sf_info, 1, ROUND(getsound(result)->sr), offset_secs, &buf); max_sample = sound_save_sound(result, n, &sf_info, sndfile, buf, &ntotal, NULL); *duration = ntotal / (double) sf_info.samplerate; free(buf); sf_close(sndfile); } else { xlerror("sound_save: expression did not return a sound", result); max_sample = 0.0; } return max_sample; } int is_pcm(SF_INFO *sf_info) { long subtype = sf_info->format & SF_FORMAT_SUBMASK; return (subtype == SF_FORMAT_PCM_S8 || subtype == SF_FORMAT_PCM_16 || subtype == SF_FORMAT_PCM_24 || subtype == SF_FORMAT_PCM_32); } sample_type sound_save_sound(LVAL s_as_lval, long n, SF_INFO *sf_info, SNDFILE *sndfile, float *buf, long *ntotal, PaStream *audio_stream) { long blocklen; sound_type s; int i; sample_type *samps; long debug_unit; /* print messages at intervals of this many samples */ long debug_count; /* next point at which to print a message */ sample_type max_sample = 0.0F; sample_type threshold = 0.0F; /* jlh cvtfn_type cvtfn; */ *ntotal = 0; /* if snd_expr was simply a symbol, then s now points to a shared sound_node. If we read samples from it, then the sound bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound_node. We need to make the new sound reachable by the garbage collector to that any lisp data reachable from the sound do not get collected. To make the sound reachable, we need to allocate a node, and the GC might run, so we need to protect the OLD s but then make it unreachable. We will let the GC collect the sound in the end. */ xlprot1(s_as_lval); s = sound_copy(getsound(s_as_lval)); s_as_lval = cvsound(s); /* destroys only ref. to original */ /* for debugging */ /* printing_this_sound = s;*/ debug_unit = debug_count = (long) max(sf_info->samplerate, 10000.0); sound_frames = 0; sound_srate = sf_info->samplerate; while (n > 0) { long togo; sample_block_type sampblock = sound_get_next(s, &blocklen); oscheck(); #ifdef SNAPSHOTS stdputstr("."); if (sound_created_flag) { stdputstr("SNAPSHOT: "); sound_print_tree(printing_this_sound); sound_created_flag = false; } fflush(stdout); #endif if (sampblock == zero_block || blocklen == 0) { break; } togo = min(blocklen, n); if (s->scale != 1) { /* copy/scale samples into buf */ for (i = 0; i < togo; i++) { buf[i] = s->scale * sampblock->samples[i]; } samps = buf; } else { samps = sampblock->samples; } if (is_pcm(sf_info)) { for (i = 0; i < togo; i++) { sample_type s = samps[i]; COMPUTE_MAXIMUM_AND_WRAP(samps[i]); } } else { for (i = 0; i < togo; i++) { sample_type s = samps[i]; COMPUTE_MAXIMUM(); } } if (sndfile) { sf_writef_float(sndfile, samps, togo); } if (audio_stream) { Pa_WriteStream(audio_stream, samps, togo); sound_frames += togo; } n -= togo; *ntotal += togo; if (*ntotal > debug_count) { gprintf(TRANS, " %ld ", *ntotal); fflush(stdout); debug_count += debug_unit; } } gprintf(TRANS, "\ntotal samples: %ld\n", *ntotal); xlpop(); return max_sample; } sample_type sound_save_array(LVAL sa, long n, SF_INFO *sf_info, SNDFILE *sndfile, float *buf, long *ntotal, PaStream *audio_stream) { long i, chans; float *float_bufp; sound_state_type state; double start_time = HUGE_VAL; LVAL sa_copy; long debug_unit; /* print messages at intervals of this many samples */ long debug_count; /* next point at which to print a message */ sample_type max_sample = 0.0F; sample_type threshold = 0.0F; /* cvtfn_type cvtfn; jlh */ *ntotal = 0; /* THE ALGORITHM: first merge floating point samples from N channels * into consecutive multi-channel frames in buf. Then, treat buf * as just one channel and use one of the cvt_to_* functions to * convert the data IN PLACE in the buffer (this is ok because the * converted data will never take more space than the original 32-bit * floats, so the converted data will not overwrite any floats before * the floats are converted */ /* if snd_expr was simply a symbol, then sa now points to a shared sound_node. If we read samples from it, then the sounds bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound array. See also sound_save_sound() */ chans = getsize(sa); if (chans > MAX_SND_CHANNELS) { xlerror("sound_save: too many channels", sa); free(buf); sf_close(sndfile); } xlprot1(sa); sa_copy = newvector(chans); xlprot1(sa_copy); /* Why do we copy the array into an xlisp array instead of just * the state[i] array? Because some of these sounds may reference * the lisp heap. We must put the sounds in an xlisp array so that * the gc will find and mark them. xlprot1(sa_copy) makes the array * visible to gc. */ for (i = 0; i < chans; i++) { sound_type s = getsound(getelement(sa, i)); setelement(sa_copy, i, cvsound(sound_copy(s))); } sa = sa_copy; /* destroy original reference to allow GC */ state = (sound_state_type) malloc(sizeof(sound_state_node) * chans); for (i = 0; i < chans; i++) { state[i].sound = getsound(getelement(sa, i)); state[i].scale = state[i].sound->scale; D nyquist_printf("save scale factor %ld = %g\n", i, state[i].scale); state[i].terminated = false; state[i].cnt = 0; /* force a fetch */ start_time = min(start_time, state[i].sound->t0); } for (i = 0; i < chans; i++) { if (state[i].sound->t0 > start_time) sound_prepend_zeros(state[i].sound, start_time); } debug_unit = debug_count = (long) max(sf_info->samplerate, 10000.0); sound_frames = 0; sound_srate = sf_info->samplerate; while (n > 0) { /* keep the following information for each sound: has it terminated? pointer to samples number of samples remaining in block scan to find the minimum remaining samples and output that many in an inner loop. Stop outer loop if all sounds have terminated */ int terminated = true; int togo = n; int j; oscheck(); for (i = 0; i < chans; i++) { if (state[i].cnt == 0) { if (sndwrite_trace) { nyquist_printf("CALLING SOUND_GET_NEXT ON CHANNEL %ld (%lx)\n", i, (unsigned long) state[i].sound); /* jlh 64 bit issue */ sound_print_tree(state[i].sound); } state[i].ptr = sound_get_next(state[i].sound, &(state[i].cnt))->samples; if (sndwrite_trace) { nyquist_printf("RETURNED FROM CALL TO SOUND_GET_NEXT ON CHANNEL %ld\n", i); } if (state[i].ptr == zero_block->samples) { state[i].terminated = true; } } if (!state[i].terminated) terminated = false; togo = min(togo, state[i].cnt); } if (terminated) break; float_bufp = (float *) buf; if (is_pcm(sf_info)) { for (j = 0; j < togo; j++) { for (i = 0; i < chans; i++) { float s = (float) (*(state[i].ptr++) * (float) state[i].scale); COMPUTE_MAXIMUM_AND_WRAP(s); *float_bufp++ = s; } } } else { for (j = 0; j < togo; j++) { for (i = 0; i < chans; i++) { float s = (float) (*(state[i].ptr++) * (float) state[i].scale); COMPUTE_MAXIMUM(); *float_bufp++ = s; } } } /* Here we have interleaved floats. Before converting to the sound file format, call PortAudio to play them. */ if (audio_stream) { PaError err = Pa_WriteStream(audio_stream, buf, togo); if (err) { printf("Pa_WriteStream error %d\n", err); } sound_frames += togo; } if (sndfile) sf_writef_float(sndfile, buf, togo); n -= togo; for (i = 0; i < chans; i++) { state[i].cnt -= togo; } *ntotal += togo; if (*ntotal > debug_count) { gprintf(TRANS, " %ld ", *ntotal); fflush(stdout); debug_count += debug_unit; } } gprintf(TRANS, "total samples: %ld x %ld channels\n", *ntotal, chans); /* references to sounds are shared by sa_copy and state[]. * here, we dispose of state[], allowing GC to do the * sound_unref call that frees the sounds. (Freeing them now * would be a bug.) */ free(state); xlpop(); return max_sample; } nyquist-3.05/nyqsrc/local.c0000644000175000000620000000210110144436365014740 0ustar stevestaff/* local.c -- call initialization code for all extensions */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "xlisp.h" #include "sound.h" #include "samples.h" #ifdef CMTSTUFF #include "seqext.h" #endif #include "falloc.h" #include "sine.h" #include "stkinit.h" LVAL RSLT_sym; void localinit(void) { falloc_init(); /* probe_init(true);*/ sound_init(); #ifdef CMTSTUFF seqext_init(); #endif sine_init(); stk_init(); } void localsymbols(void) { RSLT_sym = xlenter("*RSLT*"); sound_symbols(); samples_symbols(); #ifdef CMTSTUFF seqext_symbols(); #endif } extern int sample_block_total; extern int sample_block_used; void print_local_gc_info(void) { char buf[50]; /* print sample blocks */ sprintf(buf, "; samples %dKB, %dKB free", (sample_block_total * max_sample_block_len) / 1024, ((sample_block_total - sample_block_used) * max_sample_block_len) / 1024); stdputstr(buf); } nyquist-3.05/nyqsrc/sndfnintptrs.h0000644000175000000620000001201411466723256016421 0ustar stevestaff { "SND-SET-LATENCY", S, xlc_snd_set_latency}, { "SOUNDP", S, xlc_soundp}, { "HZ-TO-STEP", S, xlc_hz_to_step}, { "SND-SET-LOGICAL-STOP", S, xlc_snd_set_logical_stop}, { "LOG", S, xlc_log}, { "SND-SREF", S, xlc_snd_sref}, { "SREF-INVERSE", S, xlc_sref_inverse}, { "SND-STOP-TIME", S, xlc_snd_stop_time}, { "SND-TIME", S, xlc_snd_time}, { "SND-SRATE", S, xlc_snd_srate}, { "SND-T0", S, xlc_snd_t0}, { "SND-XFORM", S, xlc_snd_xform}, { "BLOCK-WATCH", S, xlc_block_watch}, { "SOUND-NTH-BLOCK", S, xlc_sound_nth_block}, { "SND-COPY", S, xlc_snd_copy}, { "SND-PRINT", S, xlc_snd_print}, { "SND-PLAY", S, xlc_snd_play}, { "STATS", S, xlc_stats}, { "SND-PRINT-TREE", S, xlc_snd_print_tree}, { "SND-SCALE", S, xlc_snd_scale}, { "SND-ZERO", S, xlc_snd_zero}, { "STEP-TO-HZ", S, xlc_step_to_hz}, { "SND-ADD", S, xlc_snd_add}, { "SND-AVG", S, xlc_snd_avg}, { "SND-COMPOSE", S, xlc_snd_compose}, { "SND-CONVOLVE", S, xlc_snd_convolve}, { "SND-DOWN", S, xlc_snd_down}, { "SND-FFT", S, xlc_snd_fft}, { "SND-INVERSE", S, xlc_snd_inverse}, { "SND-MULTISEQ", S, xlc_snd_multiseq}, { "SND-RESAMPLE", S, xlc_snd_resample}, { "SND-RESAMPLEV", S, xlc_snd_resamplev}, { "SND-FROM-ARRAY", S, xlc_snd_from_array}, { "SND-SAMPLES", S, xlc_snd_samples}, { "SND-LENGTH", S, xlc_snd_length}, { "SND-MAXSAMP", S, xlc_snd_maxsamp}, { "SND-FETCH", S, xlc_snd_fetch}, { "SND-FETCH-ARRAY", S, xlc_snd_fetch_array}, { "SND-MAX", S, xlc_snd_max}, { "SND-READ", S, xlc_snd_read}, { "SND-SEQ", S, xlc_snd_seq}, { "SND-SLIDER", S, xlc_snd_slider}, { "SND-SAVE", S, xlc_snd_save}, { "SND-OVERWRITE", S, xlc_snd_overwrite}, { "SND-YIN", S, xlc_snd_yin}, { "SND-TRIGGER", S, xlc_snd_trigger}, { "SND-LPANAL", S, xlc_snd_lpanal}, { "SND-PHASEVOCODER", S, xlc_snd_phasevocoder}, { "SND-ABS", S, xlc_snd_abs}, { "SND-ALLPOLES", S, xlc_snd_allpoles}, { "SND-ALPASS", S, xlc_snd_alpass}, { "SND-ALPASSCV", S, xlc_snd_alpasscv}, { "SND-ALPASSVV", S, xlc_snd_alpassvv}, { "SND-AMOSC", S, xlc_snd_amosc}, { "SND-ARESON", S, xlc_snd_areson}, { "SND-ARESONVC", S, xlc_snd_aresonvc}, { "SND-ARESONCV", S, xlc_snd_aresoncv}, { "SND-ARESONVV", S, xlc_snd_aresonvv}, { "SND-ATONE", S, xlc_snd_atone}, { "SND-ATONEV", S, xlc_snd_atonev}, { "SND-BIQUAD", S, xlc_snd_biquad}, { "SND-BUZZ", S, xlc_snd_buzz}, { "SND-CHASE", S, xlc_snd_chase}, { "SND-CLIP", S, xlc_snd_clip}, { "SND-CONGEN", S, xlc_snd_congen}, { "SND-CONST", S, xlc_snd_const}, { "SND-COTERM", S, xlc_snd_coterm}, { "SND-DELAY", S, xlc_snd_delay}, { "SND-DELAYCV", S, xlc_snd_delaycv}, { "SND-EQBANDVVV", S, xlc_snd_eqbandvvv}, { "SND-EXP", S, xlc_snd_exp}, { "SND-FOLLOW", S, xlc_snd_follow}, { "SND-FMOSC", S, xlc_snd_fmosc}, { "SND-FROMOBJECT", S, xlc_snd_fromobject}, { "SND-FROMARRAYSTREAM", S, xlc_snd_fromarraystream}, { "SND-GATE", S, xlc_snd_gate}, { "SND-IFFT", S, xlc_snd_ifft}, { "SND-CLARINET", S, xlc_snd_clarinet}, { "SND-CLARINET_ALL", S, xlc_snd_clarinet_all}, { "SND-CLARINET_FREQ", S, xlc_snd_clarinet_freq}, { "SND-SAX", S, xlc_snd_sax}, { "SND-SAX_ALL", S, xlc_snd_sax_all}, { "SND-SAX_FREQ", S, xlc_snd_sax_freq}, { "SND-INTEGRATE", S, xlc_snd_integrate}, { "SND-LOG", S, xlc_snd_log}, { "SND-LPRESON", S, xlc_snd_lpreson}, { "SND-MAXV", S, xlc_snd_maxv}, { "SND-OFFSET", S, xlc_snd_offset}, { "SND-ONESHOT", S, xlc_snd_oneshot}, { "SND-OSC", S, xlc_snd_osc}, { "SND-PARTIAL", S, xlc_snd_partial}, { "SND-PLUCK", S, xlc_snd_pluck}, { "SND-PROD", S, xlc_snd_prod}, { "SND-PWL", S, xlc_snd_pwl}, { "SND-QUANTIZE", S, xlc_snd_quantize}, { "SND-RECIP", S, xlc_snd_recip}, { "SND-RESON", S, xlc_snd_reson}, { "SND-RESONVC", S, xlc_snd_resonvc}, { "SND-RESONCV", S, xlc_snd_resoncv}, { "SND-RESONVV", S, xlc_snd_resonvv}, { "SND-SAMPLER", S, xlc_snd_sampler}, { "SND-NORMALIZE", S, xlc_snd_normalize}, { "SND-SHAPE", S, xlc_snd_shape}, { "SND-SINE", S, xlc_snd_sine}, { "SND-SIOSC", S, xlc_snd_siosc}, { "SND-SLOPE", S, xlc_snd_slope}, { "SND-SQRT", S, xlc_snd_sqrt}, { "SND-TAPF", S, xlc_snd_tapf}, { "SND-TAPV", S, xlc_snd_tapv}, { "SND-TONE", S, xlc_snd_tone}, { "SND-TONEV", S, xlc_snd_tonev}, { "SND-UP", S, xlc_snd_up}, { "SND-WHITE", S, xlc_snd_white}, { "SND-STKREV", S, xlc_snd_stkrev}, { "SND-STKPITSHIFT", S, xlc_snd_stkpitshift}, { "SND-STKCHORUS", S, xlc_snd_stkchorus}, { "SND-BOWED", S, xlc_snd_bowed}, { "SND-BOWED_FREQ", S, xlc_snd_bowed_freq}, { "SND-BANDEDWG", S, xlc_snd_bandedwg}, { "SND-MANDOLIN", S, xlc_snd_mandolin}, { "SND-SITAR", S, xlc_snd_sitar}, { "SND-MODALBAR", S, xlc_snd_modalbar}, { "SND-FLUTE", S, xlc_snd_flute}, { "SND-FLUTE_FREQ", S, xlc_snd_flute_freq}, { "SND-FLUTE_ALL", S, xlc_snd_flute_all}, { "SND-FMFB", S, xlc_snd_fmfb}, { "SND-FMFBV", S, xlc_snd_fmfbv}, nyquist-3.05/nyqsrc/sound.c0000644000175000000620000015521311466723256015021 0ustar stevestaff/* sound.c -- nyquist sound data type */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ /* define size_t: */ #ifdef UNIX #include "sys/types.h" #endif #include #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "samples.h" #include "extern.h" #include "debug.h" #include "assert.h" #ifdef OSC #include "nyq-osc-server.h" #endif #include "cext.h" #include "userio.h" /* #define GC_DEBUG */ #ifdef GC_DEBUG extern sound_type sound_to_watch; #endif snd_list_type list_watch; //DBY /* #define SNAPSHOTS */ long table_memory; sample_block_type zero_block; sample_block_type internal_zero_block; snd_list_type zero_snd_list; xtype_desc sound_desc; LVAL a_sound; LVAL s_audio_markers; static void sound_xlfree(); static void sound_xlprint(); static void sound_xlsave(); static unsigned char *sound_xlrestore(); void sound_print_array(LVAL sa, long n); void sound_print_sound(sound_type s, long n); void sample_block_unref(sample_block_type sam); #ifdef SNAPSHOTS boolean sound_created_flag = false; #endif #ifdef OSC int nosc_enabled = false; #endif double sound_latency = 0.3; /* default value */ /* these are used so get times for *AUDIO-MARKERS* */ double sound_srate = 44100.0; long sound_frames = 0; double snd_set_latency(double latency) { double r = sound_latency; sound_latency = latency; return r; } /* xlbadsr - report a "bad combination of sample rates" error */ LVAL snd_badsr(void) { xlfail("bad combination of sample rates"); return NIL; /* never happens */ } /* compute-phase - given a phase in radians, a wavetable specified as * the nominal pitch (in half steps), the table length, and the sample * rate, compute the sample number corresponding to the phase. This * routine makes it easy to initialize the table pointer at the beginning * of various oscillator implementations in Nyquist. Note that the table * may represent several periods, in which case phase 360 is not the same * as 0. Also note that the phase increment is also computed and returned * through incr_ptr. */ double compute_phase(phase, key, n, srate, new_srate, freq, incr_ptr) double phase; /* phase in degrees (depends on ANGLEBASE) */ double key; /* the semitone number of the table played at srate */ long n; /* number of samples */ double srate; /* the sample rate of the table */ double new_srate; /* sample rate of the result */ double freq; /* the desired frequency */ double *incr_ptr; /* the sample increment */ { double period = 1.0 / step_to_hz(key); /* convert phase to sample units */ phase = srate * period * (phase / (double) ANGLEBASE); /* phase is now in sample units; if phase is less than zero, then increase it by some number of sLength's to make it positive: */ if (phase < 0) phase += (((int) ((-phase) / n)) + 1) * n; /* if phase is longer than the sample length, wrap it by subtracting the integer part of the division by sLength: */ if (phase > n) phase -= ((int) (phase / n)) * n; /* Now figure the phase increment: to reproduce original pitch required incr = srate / new_srate. To get the new frequency, scale by freq / nominal_freq = freq * period: */ *incr_ptr = (srate / new_srate) * freq * period; return phase; } #ifndef GCBUG snd_list_type gcbug_snd_list = 0; long blocks_to_watch_len = 0; sample_block_type blocks_to_watch[blocks_to_watch_max]; void block_watch(long sample_block) { if (blocks_to_watch_len >= blocks_to_watch_max) { stdputstr("block_watch - no more space to save pointers\n"); return; } blocks_to_watch[blocks_to_watch_len++] = (sample_block_type) sample_block; nyquist_printf("block_watch - added %d = %x\n", (int)sample_block, (int)sample_block); } /* fetch_zeros -- the fetch function for appended zeros */ /* * zeros are appended when the logical stop time exceeds the * (physical) terminate time. This fetch function is installed * by snd_list_terminate(). When appending zeros, we just return * a pointer to the internal_zero_block and increment current until * it reaches log_stop_cnt. Then we call snd_list_terminate() to * finish off the sound list. */ void fetch_zeros(snd_susp_type susp, snd_list_type snd_list) { int len = MIN(susp->log_stop_cnt - susp->current, max_sample_block_len); /* nyquist_printf("fetch_zeros, lsc %d current %d len %d\n", susp->log_stop_cnt, susp->current, len); */ if (len < 0) { char error[80]; sprintf(error, "fetch_zeros susp %p (%s) len %d", susp, susp->name, len); xlabort(error); } if (len == 0) { /* we've reached the logical stop time */ /* nyquist_printf("fetch_zeros: reached the logical stop in %s cnt %d\n", susp->name, susp->log_stop_cnt); */ snd_list_terminate(snd_list); } else { snd_list->block_len = len; susp->current += len; } } /* sound_nth_block - fetch the address of the nth sample block of a sound */ /* * NOTE: intended to be called from lisp. Lisp can then call block_watch * to keep an eye on the block. */ long sound_nth_block(sound_type snd, long n) { long i; snd_list_type snd_list = snd->list; for (i = 0; i < n; i++) { if (i == 1) { gcbug_snd_list = snd_list; nyquist_printf("gcbug_snd_list = 0x%p\n", gcbug_snd_list); } if (!snd_list->block) return 0; snd_list = snd_list->u.next; } if (snd_list->block) return (long) snd_list->block; else return 0; } #endif /**************************************************************************** * snd_list_create * Inputs: * snd_susp_type susp: A reference to the suspension * Result: snd_list_type * A newly-created sound list type * Effect: * Allocates and initializes a snd_list node: * block refcnt block_len susp logically_stopped * +--------+--------+-------+-------+---+ * |////////| 1 | 0 | susp | F | * +--------+--------+-------+-------+---+ ****************************************************************************/ /* snd_list_create -- alloc and initialize a snd_list node */ /**/ snd_list_type snd_list_create(snd_susp_type susp) { snd_list_type snd_list; falloc_snd_list(snd_list, "snd_list_create"); snd_list->block = NULL; /* no block of samples */ snd_list->u.susp = susp; /* point to suspension */ snd_list->refcnt = 1; /* one ref */ snd_list->block_len = 0; /* no samples */ snd_list->logically_stopped = false;/* not stopped */ /* nyquist_printf("snd_list_create => %p\n", snd_list);*/ return snd_list; } /**************************************************************************** * sound_create * Inputs: * snd_susp_type susp: The suspension block to be used for this sound * time_type t0: The initial time for this sound * rate_type sr: The sampling rate for this sound * sample_type scale: The scaling factor for this sound * sample_block_type (*proc)(...): The get_next_sound method * Result: sound_type * * Effect: * Creates and initializes a sound type * Notes: * The MSDOS conditional is actually a test for ANSI headers; the * presence of float parameters means that an ANSI prototype and * a non-ANSI header are incompatible. Better solution would be * to ANSIfy source. ****************************************************************************/ sound_type last_sound = NULL; sound_type sound_create( snd_susp_type susp, time_type t0, rate_type sr, promoted_sample_type scale) { sound_type sound; falloc_sound(sound, "sound_create"); if (((long) sound) & 3) errputstr("sound not word aligned\n"); last_sound = sound; /* debug */ if (t0 < 0) xlerror("attempt to create a sound with negative starting time", s_unbound); /* nyquist_printf("sound_create %p gets %g\n", sound, t0); */ sound->t0 = sound->true_t0 = sound->time = t0; sound->stop = MAX_STOP; sound->sr = sr; sound->current = 0; sound->scale = (float) scale; sound->list = snd_list_create(susp); sound->get_next = SND_get_first; sound->logical_stop_cnt = UNKNOWN; sound->table = NULL; sound->extra = NULL; /* nyquist_printf("sound_create susp %p snd_list %p\n", susp, sound->list); nyquist_printf("sound_create'd %p\n", sound); */ #ifdef SNAPSHOTS sound_created_flag = true; #endif #ifdef GC_DEBUG if (sound == sound_to_watch) { nyquist_printf("Created watched sound\n"); watch_snd_list(sound->list); } #endif return sound; } /* sound_prepend_zeros -- modify sound_type so that it starts at t0 */ /* * assumes t0 is earlier than snd->t0, so the sound should return zeros * until snd->t0 is reached, after which we revert to normal computation. * When we return, the new snd->t0 will be t0, meaning that the first * sample returned will be at time t0. * NOTE: t0 may not be an exact multiple of samples earlier than snd->t0, * but Nyquist allows any sound to be shifted by +/- 0.5 samples in * order to achieve alignment. Since sound_prepend_zeros can be called * many times on the same sound_type, there is a chance that rounding * errors could accumulate. My first solution was to return with * snd->t0 computed exactly and not reflecting any fractional sample * shift of the signal, but this caused problems for the caller: a * fractional sample shift at a low sample rate could correspond to * many client samples,fooling the client into thinking that some * initial samples should be discarded (or else requiring the client * to be pretty smart). The solution used here is to return to the * client with snd->t0 exactly equal to t0, but to save snd->true_t0 * equal to the time of the first sample with no sound shifting. This * time is used for any future sound_prepend_zeros operations so that * any accumulated rounding errors are due only to floating point * precision and not to accumulated fractional sample shifts of snd. */ void sound_prepend_zeros(sound_type snd, time_type t0) { long n; /* first, see if we're already prepending some zeros */ if (snd->get_next != SND_get_zeros) { /* nyquist_printf("sound_prepend_zeros 1: snd->t0 %g t0 %g\n", snd->t0, t0); */ /* if not, then initialize some fields that support prepending */ snd->prepend_cnt = 0; snd->true_t0 = snd->t0; /* save old get_next and plug in special get_next function */ snd->after_prepend = snd->get_next; snd->get_next = SND_get_zeros; } n = (long) (((snd->true_t0 - t0) * snd->sr) + 0.5); /* how many samples to prepend */ /* add to prepend_cnt so first sample will correspond to new t0 */ snd->prepend_cnt += n; /* compute the true t0 which corresponds to the time of first sample */ snd->true_t0 -= (n / snd->sr); /* make caller happy by claiming the sound now starts at exactly t0; * this is always true within 0.5 samples as allowed by Nyquist. */ snd->t0 = t0; /* nyquist_printf("sound_prepend_zeros: snd %p true_t0 %g sr %g n %d\n", snd, snd->true_t0, snd->sr, n);*/ } /* sound_array_copy -- copy an array of sounds */ /* * NOTE: be sure to protect the result from gc! */ LVAL sound_array_copy(LVAL sa) { long i = getsize(sa); LVAL new_sa = newvector(i); xlprot1(new_sa); while (i > 0) { i--; setelement(new_sa, i, cvsound(sound_copy(getsound(getelement(sa, i))))); } xlpop(); return new_sa; } /* sound_copy - copy a sound structure, do reference counts */ /**/ sound_type sound_copy(sound_type snd) { sound_type sndcopy; falloc_sound(sndcopy, "sound_copy"); *sndcopy = *snd; /* copy the whole structure */ sndcopy->extra = NULL; /* except for the (private) extra data */ snd_list_ref(snd->list); /* copied a reference so fix the count */ /* nyquist_printf("sound_copy'd %p to %p\n", snd, sndcopy); */ if (snd->table) snd->table->refcount++; #ifdef GC_DEBUG if (sndcopy == sound_to_watch) printf("sndcopy->table %x\n", sndcopy->table); #endif return sndcopy; } /* convert a sound to a wavetable, set length */ /**/ table_type sound_to_table(sound_type s) { long len = snd_length(s, max_table_len); long tx = 0; /* table index */ long blocklen; register double scale_factor = s->scale; sound_type original_s = s; table_type table; /* the new table */ long table_bytes; /* how big is the table */ if (s->table) { s->table->refcount++; return s->table; } if (len >= max_table_len) { char emsg[100]; sprintf(emsg, "maximum table size (%d) exceeded", max_table_len); xlcerror("use truncated sound for table", emsg, NIL); } else if (len == 0) { xlabort("table size must be greater than 0"); } len++; /* allocate extra sample at end of table */ s = sound_copy(s); /* nyquist_printf("sound_to_table: allocating table of size %d\n", len); */ table_bytes = table_size_in_bytes(len); table = (table_type) malloc(table_bytes); if (!table) xlfail("osc_init couldn't allocate memory for table"); table_memory += table_bytes; table->length = (double) (len - 1); while (len > 1) { sample_block_type sampblock = sound_get_next(s, &blocklen); long togo = MIN(blocklen, len); long i; sample_block_values_type sbufp = sampblock->samples; /* nyquist_printf("in sound_to_table, sampblock = %d\n", sampblock);*/ for (i = 0; i < togo; i++) { table->samples[tx++] = (float) (*sbufp++ * scale_factor); } len -= togo; } /* for interpolation, duplicate first sample at end of table */ table->samples[tx] = table->samples[0]; table->refcount = 2; /* one for the user, one from original_s */ sound_unref(s); s = NULL; original_s->table = table; return table; } void table_free(table_type table) { long len = (long) (table->length) + 1; long bytes = table_size_in_bytes(len); free(table); table_memory -= bytes; } void table_unref(table_type table) { if (!table) return; table->refcount--; if (table->refcount <= 0) { /* nyquist_printf("table refcount went to zero\n"); */ table_free(table); } } void sound_unref(sound_type snd) /* note that sounds do not have ref counts, so sound_unref * always frees the sound object */ { if (!snd) return; snd_list_unref(snd->list); table_unref(snd->table); /* nyquist_printf("\t\t\t\t\tfreeing sound@%p\n", snd);*/ if (snd->extra) free(snd->extra); ffree_sound(snd, "sound_unref"); } void snd_list_ref(snd_list_type list) { list->refcnt++; } void snd_list_terminate(snd_list) snd_list_type snd_list; { snd_susp_type susp = snd_list->u.next->u.susp; long lsc = susp->log_stop_cnt; long current = susp->current; /* unreference the empty sample block that was allocated: */ sample_block_unref(snd_list->block); /* use zero_block instead */ snd_list->block = zero_block; /* either fetch more zeros or terminate now */ if (lsc != UNKNOWN && lsc > current) { /* nyquist_printf("snd_list_terminate: lsc %d current %d\n", lsc, current); */ susp->fetch = fetch_zeros; fetch_zeros(susp, snd_list); } else { snd_list->block_len = max_sample_block_len; snd_list->logically_stopped = true; snd_list_unref(snd_list->u.next); snd_list->u.next = zero_snd_list; /* be zero forever */ } } void snd_list_unref(snd_list_type list) { void (*freefunc)(); if (list == NULL || list == zero_snd_list) { if (list == NULL) nyquist_printf("why did snd_list_unref get %p?\n", list); return; } list->refcnt--; /* nyquist_printf("snd_list_unref "); print_snd_list_type(list); stdputstr("\n"); */ if (list->refcnt == 0) { if (list->block && list->block != zero_block) { /* there is a next snd_list */ /* stdputstr("["); */ sample_block_unref(list->block); /* stdputstr("]"); */ snd_list_unref(list->u.next); } else if (list->block == NULL) { /* the next thing is the susp */ /* free suspension structure */ /* nyquist_printf("freeing susp@%p\n", list->u.susp); */ freefunc = list->u.susp->free; (*freefunc)(list->u.susp); } /* nyquist_printf("freeing snd_list@%p\n", list); */ //DBY if (list == list_watch) printf("freeing watched snd_list %p\n", list); //DBY ffree_snd_list(list, "snd_list_unref"); } } void sample_block_ref(sample_block_type sam) { sam->refcnt++; } void sample_block_test(sample_block_type sam, char *s) { /* see if this block is being watched */ int i; for (i = 0; i < blocks_to_watch_len; i++) { if ((sam > (blocks_to_watch[i] - 1)) && (sam < (blocks_to_watch[i] + 1))) { nyquist_printf( "WOOPS! %s(0x%p) refers to a block 0x%p on the watch list!\n", s, sam, blocks_to_watch[i]); } } } void sample_block_unref(sample_block_type sam) { sam->refcnt--; if (sam->refcnt == 0) { #ifndef GCBUG sample_block_test(sam, "sample_block_unref"); #endif /* nyquist_printf("freeing sample block %p\n", sam); */ ffree_sample_block(sam, "sample_block_unref"); } } /**************************************************************************** * interp_style * Inputs: * sound_type s: The sound we are using * rate_type sr: The sampling rate * Result: int * A small integer which is one of the symbolic values: * The values are ordered, smallest to largest, as * INTERP_n - none * INTERP_s - scale * INTERP_i - interpolated * INTERP_r - ramp * * Notes: * The sampling rate s->sr and scale factor s->scale are compared * with other values exactly (no fuzz). ****************************************************************************/ int interp_style(sound_type s, rate_type sr) { if (s->sr == sr) { /* same sample rate */ return ((s->scale == 1.0) ? INTERP_n : INTERP_s); } /* same sample rate */ else if (s->sr * 10.0 > sr) { /* 10x sample rate */ return INTERP_i; } /* 10x sample rate */ else return INTERP_r; } /**************************************************************************** * snd_sort_2 * Inputs: * sound_type * s1_ptr: * sound_type * s2_ptr: * rate_type sr: * Result: void * * Effect: * If the interp_style of s1 dominates the interp_style of s2, * the sound_types input are interchanged. ****************************************************************************/ /* snd_sort_2 -- sort 2 arguments by interpolation method */ void snd_sort_2(sound_type *s1_ptr, sound_type *s2_ptr, rate_type sr) { if (interp_style(*s1_ptr, sr) > interp_style(*s2_ptr, sr)) { sound_type s = *s1_ptr; *s1_ptr = *s2_ptr; *s2_ptr = s; } } /* snd_sref -- access a sound at a given time point */ /**/ double snd_sref(sound_type s, time_type t) { double exact_cnt; /* how many fractional samples to scan */ int cnt; /* how many samples to flush */ sample_block_type sampblock = NULL; long blocklen; sample_type x1, x2; /* interpolate between these samples */ /* changed true_t0 to just t0 based on comment that true_t0 is only * for use by snd_prepend_zeros -RBD */ exact_cnt = (t - s->t0) * s->sr; if (exact_cnt < 0.0) return 0.0; s = sound_copy(s); /* don't modify s, create new reader */ cnt = (long) exact_cnt; /* rounds down */ exact_cnt -= cnt; /* remember fractional remainder */ /* now flush cnt samples */ while (cnt >= 0) { sampblock = sound_get_next(s, &blocklen); cnt -= blocklen; if (sampblock == zero_block) { sound_unref(s); return 0.0; } } /* -blocklen <= cnt <= -1 */ /* get next 2 samples and interpolate */ x1 = sampblock->samples[blocklen + cnt]; if (cnt == -1) { sampblock = sound_get_next(s, &blocklen); cnt -= blocklen; } x2 = sampblock->samples[blocklen + cnt + 1]; sound_unref(s); /* free the reader */ return (x1 + exact_cnt * (x2 - x1)) * s->scale; } /* snd_sref_inverse -- find time point corresponding to some value */ /**/ double snd_sref_inverse(sound_type s, double val) { double exact_cnt; /* how many fractional samples to scan */ int i; sample_block_type sampblock; long blocklen; sample_type x1, x2; /* interpolate between these samples */ if (val < 0) { xlcerror("return 0", "negative value", cvflonum(val)); return 0.0; } s = sound_copy(s); /* don't modify s, create new reader */ x1 = 0.0F; /* now flush cnt samples */ while (true) { sampblock = sound_get_next(s, &blocklen); x2 = sampblock->samples[blocklen - 1]; if (x2 >= val) break; x1 = x2; if (sampblock == zero_block) { xlcerror("return 0", "too large, no inverse", cvflonum(val)); sound_unref(s); return 0.0; } } /* x1 = last sample of previous block, sampblock contains a value larger than val blocklen is the length of sampblock */ /* search for first element exceeding val - could * use binary search, but maximum block size places * an upper bound on how bad this can get and we * search for the right block linearly anyway. */ for (i = 0; i < blocklen && sampblock->samples[i] <= val; i++) ; /* now i is index of element exceeding val */ if (i > 1) x1 = sampblock->samples[i - 1]; x2 = sampblock->samples[i]; /* now interpolate to get fractional part */ if (x2 == x1) exact_cnt = 0; else exact_cnt = (val - x1) / (x2 - x1); /* and add the sample count of x1 */ exact_cnt += (s->current - blocklen) + (i - 1); /* negative counts are possible because the first x1 is at * sample -1, so force the location to be at least 0 */ if (exact_cnt < 0) exact_cnt = 0; /* compute time = t0 + count / samplerate; */ exact_cnt = s->t0 + exact_cnt / s->sr; sound_unref(s); /* free the reader */ return exact_cnt; } time_type snd_stop_time(sound_type s) { if (s->stop == MAX_STOP) return MAX_STOP_TIME; else return s->t0 + (s->stop + 0.5) / s->sr; } /* snd_xform -- return a sound with transformations applied */ /* * The "logical" sound starts at snd->time and runs until some * as yet unknown termination time. (There is also a possibly * as yet unknown logical stop time that is irrelevant here.) * The sound is clipped (zero) until snd->t0 and after snd->stop, * the latter being a sample count, not a time_type. * So, the "physical" sound starts at snd->t0 and runs for up to * snd->stop samples (or less if the sound terminates beforehand). * * The snd_xform procedure operates at the "logical" level, shifting * the sound from its snd->time to time. The sound is stretched as * a result of setting the sample rate to sr. It is then (further) * clipped between start_time and stop_time. If initial samples * are clipped, the sound is shifted again so that it still starts * at time. The sound is then scaled by scale. * * To support clipping of initial samples, the "physical" start time * t0 is set to when the first unclipped sample will be returned, but * the number of samples to clip is saved as a negative count. The * fetch routine SND_flush is installed to flush the clipped samples * at the time of the first fetch. SND_get_first is then installed * for future fetches. * * An empty (zero) sound will be returned if all samples are clipped. * */ sound_type snd_xform(sound_type snd, rate_type sr, time_type time, time_type start_time, time_type stop_time, promoted_sample_type scale) { long start_cnt, stop_cnt; /* clipping samples (sample 0 at new t0) */ /* start_cnt should reflect max of where the sound starts (t0) * and the new start_time. */ if (start_time == MIN_START_TIME) { start_cnt = 0; } else { double new_start_cnt = ((start_time - time) * sr) + 0.5; start_cnt = ((new_start_cnt > 0) ? (long) new_start_cnt : 0); } /* if (start_cnt < -(snd->current)) start_cnt = -(snd->current); */ /* stop_cnt should reflect min of the new stop_time and the previous * snd->stop. */ if (stop_time == MAX_STOP_TIME) { stop_cnt = MAX_STOP; } else { double new_stop_cnt = ((stop_time - time) * sr) + 0.5; if (new_stop_cnt < MAX_STOP) { stop_cnt = (long) new_stop_cnt; } else { errputstr("Warning: stop count overflow in snd_xform\n"); stop_cnt = MAX_STOP; } } if (stop_cnt > snd->stop) { stop_cnt = snd->stop; } if (stop_cnt < 0 || start_cnt >= stop_cnt) { snd = sound_create(NULL, time, sr, 1.0); /* sound_create goes ahead and allocates a snd_list node, so * we need to free it. * Calling snd_list_unref here seems like the right thing, but * it assumes too much structure is in place. ffree_snd_list * is simpler and more direct: */ ffree_snd_list(snd->list, "snd_xform"); snd->list = zero_snd_list; nyquist_printf("snd_xform: (stop_time < t0 or start >= stop) " "-> zero sound = %p\n", snd); } else { snd = sound_copy(snd); snd->t0 = time; if (start_cnt) { snd->current -= start_cnt; /* indicate flush with negative num. */ /* the following code assumes that SND_get_first is the routine to be called to get the first samples from this sound. We're going to replace it with SND_flush. First, make sure that the assumption is correct: */ if ((snd->get_next != SND_get_first) && (snd->get_next != SND_flush)) { errputstr("snd_xform: SND_get_first expected\n"); EXIT(1); } /* this will flush -current samples and revert to SND_get_first */ snd->get_next = SND_flush; stop_cnt -= start_cnt; } snd->stop = stop_cnt; snd->sr = sr; snd->scale *= (float) scale; } return snd; } /* SND_flush -- the get_next function for flushing clipped samples */ /* * this only gets called once: it flushes -current samples (a * non-real-time operation) and installs SND_get_next to return * blocks normally from then on. */ sample_block_type SND_flush(sound_type snd, long * cnt) { long mycnt; sample_block_type block = SND_get_first(snd, &mycnt); /* changed from < to <= because we want to read at least the first sample */ while (snd->current <= 0) { block = SND_get_next(snd, &mycnt); } /* at this point, we've read to and including the block with * the first samples we want to return. If the block boundary * is in the right place, we can do a minimal fixup and return: */ if (snd->current == snd->list->block_len) { *cnt = snd->current; /* == snd->list->block_len */ /* snd->get_next = SND_get_next; -- done by SND_get_first */ return block; } else /* snd->current < snd->list->block_len */ { long i; sample_block_values_type from_ptr; /* we have to return a partial block */ /* NOTE: if we had been smart, we would have had SND_get_next * return a pointer to samples rather than a pointer to the * block, which has a reference count. Since the caller * expects a pointer to a reference count, we have to copy * snd->current samples to a new block */ snd_list_type snd_list = snd_list_create((snd_susp_type) snd->list->u.next); snd_list->u.next->refcnt++; falloc_sample_block(snd_list->block, "SND_flush"); /* now copy samples */ from_ptr = block->samples + snd->list->block_len - snd->current; for (i = 0; i < snd->current; i++) { snd_list->block->samples[i] = from_ptr[i]; } snd_list_unref(snd->list); snd->list = snd_list; *cnt = snd->current; return snd_list->block; } } /* SND_get_zeros -- the get_next function for prepended zeros */ /* * when prepending zeros, we just return a pointer to the internal_zero_block * and decrement the prepend_cnt until it goes to zero. Then we revert to * the normal (original) get_next function. * */ sample_block_type SND_get_zeros(sound_type snd, long * cnt) { int len = MIN(snd->prepend_cnt, max_sample_block_len); /* stdputstr("SND_get_zeros: "); */ if (len < 0) { char error[80]; sprintf(error, "SND_get_zeros snd %p len %d", snd, len); xlabort(error); } if (len == 0) { /* we've finished prepending zeros */ snd->get_next = snd->after_prepend; /* stdputstr("done, calling sound_get_next\n"); fflush(stdout); */ return sound_get_next(snd, cnt); } else { *cnt = len; snd->current += len; snd->prepend_cnt -= len; /* nyquist_printf("returning internal_zero_block@%p\n", internal_zero_block); fflush(stdout); */ return internal_zero_block; } } /**************************************************************************** * SND_get_next * Inputs: * sound_type snd: The iterator whose next block is to be computed * int * cnt: Place to put count of samples returned * Result: snd_list_type * Pointer to the sample block computed ---------------------------+ * Effect: | * force suspension to compute next block of samples | * | * Here's the protocol for using this and related functions: | * Every client (sample reader) has a private sound_type (an iterator), | * and the sound_type's 'list' field points to a header (of type | * snd_list_type). The header in turn points to a block of samples. | * | * +---------------------------------------+ * | * | * | sample_block_type * (snd) V +---+--+--+--+--+--+--+-...-+--+ * sound_type: snd_list_type +-->|ref| | | | |//|//| |//| * +---------+ +----------+ | +---+--+--+--+--+--+--+-...-+--+ * | list +------->| block +--+ ^ * +---------+ +----------+ : * | t0 | | block_len|....................: * +---------+ +----------+ * | sr | | refcnt | * +---------+ +-+--------+ * | current | | next +---->... Note: the union u * +---------+ |u|........| snd_list_type points to only one * | rate | | | susp +---->... of the indicated * +---------+ +-+--------+ susp_type types * | scalse | |log_stop | * +---------+ +----------+ * | lsc | * +---------+ * |get_next +-----> SND_get_next() * +---------+ * * The sound_type keeps track of where the next sample block will * come from. The field 'current' is the number of the first sample of * the next block to be returned, where sample numbers start * at zero. The normal fetch procedure is this one, although special * cases may generate special block generators, e.g., CONST does not need * to allocate and refill a block and can reuse the same block over and * over again, so it may have its own fetch procedure. This is the * general fetch procedure, which assumes that the generator function * actually produces a slightly different value for each sample. * * The distinguishing characteristic of whether the 'u' field is to be * interpreted as 'next', a link to the next list element, or 'susp', a * reference to the suspension for generating a new sample block, is * whether the 'block' parameter is NULL or not. If it is NULL, then * u.susp tells how to generate the block; if it is not NULL, u.next is * a pointer to the next sound block in the list. * * When the 'block' pointer is NULL, we create a block of samples, and * create a new sound list element which follows it which has a NULL * 'block' pointer; the 'u' field of the current list element is now * interpreted as 'u.next'. * * The client calls SND_get_next to get a pointer to a block of samples. * The count of samples generated is returned via a ref parameter, and * SND_get_next will not be called again until this set is exhausted. * * The next time SND_get_next is called, it knows that the sample block * has been exhausted. It releases its reference to the block (and if * that was the last reference, frees the block to the block allocation * pool), allocates a new block from the block pool, and proceeds to * fill it with samples. * * Note that as an optimization, if the refcnt field goes to 0 it * could immediately re-use the block without freeing back to the block * pool and reallocating it. * * Because of the way we handle sound sample blocks, the sound sample blocks * themselves are ref-counted, so freeing the snd_list_type may not free * the sample block it references. At the level of this procedure, that * is transparently handled by the snd_list_unref function. * * Logical stop: * * Logical stop is handled by several mechanisms. The /intrinsic/ logical * stop is an immutable property of the signal, and is determined by the * specification in the algorithm description file. When it is encountered, * the 'logically_stopped' flag of the snd_list_node is set. * The generators guarantee that the first time this is encountered, it * will always be constructed so that the first sample of the block it * references is the logical stop time. * * In addition, the client may have set the /explicit logical stop time/ of * the iterator (e.g., in nyquist, the (set-logical-stop sound time) call copies * the sound, altering its logical stop). The logical stop time, when set * in this way, causes the logical_stop_cnt ('lsc' in the above diagram) * to be set to the count of the last sample to be generated before the * list; /* * If there is not a block of samples, we need to generate one. */ if (snd_list->block == NULL) { /* * Call the 'fetch' method for this sound_type to generate * a new block of samples. */ snd_susp_type susp = snd_list->u.susp; snd_list->u.next = snd_list_create(susp); snd_list->block = internal_zero_block; /* nyquist_printf("SND_get_first: susp->fetch %p\n", susp->fetch); */ assert(susp->log_stop_cnt == UNKNOWN || susp->log_stop_cnt >= 0); (*(susp->fetch))(susp, snd_list); #ifdef GC_DEBUG snd_list_debug(snd_list, "SND_get_first"); #endif /* nyquist_printf("SND_get_first: snd_list %p, block %p, length %d\n", snd_list, snd_list->block, snd_list->block_len); */ } if ((snd->logical_stop_cnt == UNKNOWN) && snd_list->logically_stopped) { /* nyquist_printf("SND_get_first/next: snd %p logically stopped at %d\n", snd, snd->current); */ snd->logical_stop_cnt = snd->current; } /* see if clipping needs to be applied */ if (snd->current + snd_list->block_len > snd->stop) { /* need to clip: is clip on a block boundary? */ if (snd->current == snd->stop) { /* block boundary: replace with zero sound */ snd->list = zero_snd_list; snd_list_unref(snd_list); } else { /* not a block boundary: build new list */ snd->list = snd_list_create((snd_susp_type) zero_snd_list); snd->list->block_len = (short) (snd->stop - snd->current); snd->list->block = snd_list->block; snd->list->block->refcnt++; snd_list_unref(snd_list); } snd_list = snd->list; /* used below to return block ptr */ } *cnt = snd_list->block_len; /* this should never happen */ if (*cnt == 0) { stdputstr("SND_get_first returned 0 samples\n"); #if DEBUG_MEM dbg_mem_print("snd_list info:", snd_list); dbg_mem_print("block info:", snd_list->block); #endif sound_print_tree(snd); stdputstr("It is possible that you created a recursive sound\n"); stdputstr("using something like: (SETF X (SEQ (SOUND X) ...))\n"); stdputstr("Nyquist aborts from non-recoverable error\n"); abort(); } snd->current += snd_list->block_len; /* count how many we read */ snd->get_next = SND_get_next; return snd_list->block; } sample_block_type SND_get_next(sound_type snd, long * cnt) { register snd_list_type snd_list = snd->list; /* * SND_get_next is installed by SND_get_first, so we know * when we are called that we are done with the current block * of samples, so free it now. */ snd_list_type cur = snd_list; snd->list = snd_list = cur->u.next; snd_list_ref(snd_list); snd_list_unref(cur); /* release the reference to the current block */ /* now that we've deallocated, we can use SND_get_first to finish the job */ return SND_get_first(snd, cnt); } /**************************************************************************** * make_zero_block * Inputs: * * Result: * * Effect: * ****************************************************************************/ sample_block_type make_zero_block(void) { sample_block_type zb; int i; falloc_sample_block(zb, "make_zero_block"); /* leave room for lots more references before overflow, but set the count high so that even a large number of dereferences will not lead to a deallocation */ zb->refcnt = 0x6FFFFFFF; for (i = 0; i < max_sample_block_len; i++) { /* fill with zeros */ zb->samples[i] = 0.0F; } /* fill with zeros */ return zb; } /* min_cnt -- help compute the logical stop or terminate as minimum */ /* * take the sound (which has just logically stopped or terminated at * current sample) and * convert the stop sample into the equivalent sample count as produced by * susp (which may have a different sample rate). If the count is less than * the current *cnt_ptr, overwrite cnt_ptr with a new minimum. By calling * this when each of S1, S2, ... Sn reach their logical stop or termiate * points, *cnt_ptr will end up with the minimum stop count, which is what * we want. NOTE: the logical stop time and terminate for signal addition * should be the MAX of logical stop times of arguments, so this routine * would not be used. */ void min_cnt(long *cnt_ptr, sound_type sound, snd_susp_type susp, long cnt) { long c = (long) ((((sound->current - cnt) / sound->sr + sound->t0) - susp->t0) * susp->sr + 0.5); /* if *cnt_ptr is uninitialized, just plug in c, otherwise compute min */ if ((*cnt_ptr == UNKNOWN) || (*cnt_ptr > c)) { /* nyquist_printf("min_cnt %p: new count is %d\n", susp, c);*/ /* if (c == 0) sound_print_tree(printing_this_sound);*/ *cnt_ptr = c; } } /**************************************************************************** * sound_init * Result: void * * Effect: * Module initialization * Allocates the 'zero block', the infinitely linked block of * 0-valued sounds. This is referenced by a list element which * refers to itself. ****************************************************************************/ void sound_init(void) { zero_block = make_zero_block(); internal_zero_block = make_zero_block(); falloc_snd_list(zero_snd_list, "sound_init"); zero_snd_list->block = zero_block; zero_snd_list->u.next = zero_snd_list; zero_snd_list->refcnt = 2; zero_snd_list->block_len = max_sample_block_len; zero_snd_list->logically_stopped = true; #ifdef GC_DEBUG { long s; stdputstr("sound_to_watch: "); scanf("%p", &s); watch_sound((sound_type) s); } #endif sound_desc = create_desc("SOUND", sound_xlfree, sound_xlprint, sound_xlsave, sound_xlrestore, sound_xlmark); } /* sound_scale -- copy and change scale factor of a sound */ /**/ sound_type sound_scale(double factor, sound_type snd) { sound_type sndcopy = sound_copy(snd); sndcopy->scale *= (float) factor; return sndcopy; } /**************************************************************************** * set_logical_stop_time * Inputs: * sound_type sound: The sound for which the logical stop time is * being set * time_type when: The logical stop time, expressed as an absolute * time. * Result: void * * Effect: * Converts the time 'when' into a count of samples. ****************************************************************************/ void set_logical_stop_time(sound_type sound, time_type when) { /* 'when' is an absolute time. The number of samples to be generated is the number of samples between 't0' and 'when'. -----------+---+---+---+---+---+---+---+---+---+ | | t0 when */ long n = (long) ((when - sound->t0) * sound->sr + 0.5); if (n < 0) { xlcerror("retain the current logical stop", "logical stop sample count is negative", NIL); } else { sound->logical_stop_cnt = n; } } /* for debugging */ sound_type printing_this_sound = NULL; void ((**watch_me)()) = NULL; void set_watch(where) void ((**where)()); { if (watch_me == NULL) { watch_me = where; nyquist_printf("set_watch: watch_me = %p\n", watch_me); } } /* * additional routines */ void sound_print(snd_expr, n) LVAL snd_expr; long n; { LVAL result; xlsave1(result); result = xleval(snd_expr); if (vectorp(result)) { /* make sure all elements are of type a_sound */ long i = getsize(result); while (i > 0) { i--; if (!exttypep(getelement(result, i), a_sound)) { xlerror("sound_print: array has non-sound element", result); } } sound_print_array(result, n); } else if (exttypep(result, a_sound)) { sound_print_sound(getsound(result), n); } else { xlerror("sound_print: expression did not return a sound", result); } xlpop(); } void sound_print_sound(sound_type s, long n) { int ntotal = 0; long blocklen; sample_block_type sampblock; /* for debugging */ printing_this_sound = s; nyquist_printf("sound_print: start at time %g\n", s->t0); while (ntotal < n) { if (s->logical_stop_cnt != UNKNOWN) nyquist_printf("LST=%d ", (int)s->logical_stop_cnt); sound_print_tree(s); sampblock = sound_get_next(s, &blocklen); if (sampblock == zero_block || blocklen == 0) { break; } print_sample_block_type("sound_print", sampblock, MIN(blocklen, n - ntotal)); ntotal += blocklen; } nyquist_printf("total samples: %d\n", ntotal); } void sound_print_array(LVAL sa, long n) { long blocklen; long i, len; long upper = 0; sample_block_type sampblock; time_type t0, tmax; len = getsize(sa); if (len == 0) { stdputstr("sound_print: 0 channels!\n"); return; } /* take care of prepending zeros if necessary */ t0 = tmax = (getsound(getelement(sa, 0)))->t0; for (i = 1; i < len; i++) { sound_type s = getsound(getelement(sa, i)); t0 = MIN(s->t0, t0); tmax = MAX(s->t0, tmax); } /* if necessary, prepend zeros */ if (t0 != tmax) { stdputstr("prepending zeros to channels: "); for (i = 0; i < len; i++) { sound_type s = getsound(getelement(sa, i)); if (t0 < s->t0) { nyquist_printf(" %d ", (int)i); sound_prepend_zeros(s, t0); } } stdputstr("\n"); } nyquist_printf("sound_print: start at time %g\n", t0); while (upper < n) { int i; boolean done = true; for (i = 0; i < len; i++) { sound_type s = getsound(getelement(sa, i)); long current = -1; /* always get first block */ while (current < upper) { sampblock = sound_get_next(s, &blocklen); if (sampblock != zero_block && blocklen != 0) { done = false; } current = s->current - blocklen; nyquist_printf("chan %d current %d:\n", i, (int)current); print_sample_block_type("sound_print", sampblock, MIN(blocklen, n - current)); current = s->current; upper = MAX(upper, current); } } if (done) break; } nyquist_printf("total: %d samples x %d channels\n", (int)upper, (int)len); } /* sound_play -- compute sound, do not retain samples */ /* * NOTE: we want the capability of computing a sound without * retaining samples. This requires that no references to * the sound exist, but if the sound is passed as an argument, * the argument stack will have a reference. So, we pass in * an expression that evaluates to the sound we want. The * expression is eval'd, the result copied (in case the * expression was a sound or a global variable and we really * want to preserve the sound), and then a GC is run to * get rid of the original if there really are no other * references. Finally, the copy is used to play the * sounds. */ void sound_play(snd_expr) LVAL snd_expr; { int ntotal; long blocklen; sample_block_type sampblock; LVAL result; sound_type s; xlsave1(result); result = xleval(snd_expr); if (!exttypep(result, a_sound)) { xlerror("sound_play: expression did not return a sound", result); } ntotal = 0; s = getsound(result); /* if snd_expr was simply a symbol, then s now points to a shared sound_node. If we read samples from it, then the sound bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound_node. We need to explicitly free the copy since the garbage collector cannot find it. */ s = sound_copy(s); while (1) { #ifdef OSC if (nosc_enabled) nosc_poll(); #endif sampblock = sound_get_next(s, &blocklen); if (sampblock == zero_block || blocklen == 0) { break; } /* print_sample_block_type("sound_play", sampblock, blocklen); */ ntotal += blocklen; } nyquist_printf("total samples: %d\n", ntotal); sound_unref(s); xlpop(); } /* sound_print_tree -- print a tree version of sound structure */ /**/ void sound_print_tree(snd) sound_type snd; { /* nyquist_printf("sample_block_free %p\n", sample_block_free);*/ nyquist_printf("SOUND PRINT TREE of %p\n", snd); sound_print_tree_1(snd, 0); } void indent(int n) { while (n-- > 0) stdputstr(" "); } void sound_print_tree_1(snd, n) sound_type snd; int n; { int i; snd_list_type snd_list; if (n > 100) { stdputstr("... (skipping remainder of sound)\n"); return; } if (!snd) { stdputstr("\n"); return; } nyquist_printf("sound_type@%p(%s@%p)t0 " "%g stop %d sr %g lsc %d scale %g pc %d", snd, (snd->get_next == SND_get_next ? "SND_get_next" : (snd->get_next == SND_get_first ? "SND_get_first" : "?")), snd->get_next, snd->t0, (int)snd->stop, snd->sr, (int)snd->logical_stop_cnt, snd->scale, (int)snd->prepend_cnt); snd_list = snd->list; nyquist_printf("->snd_list@%p", snd_list); if (snd_list == zero_snd_list) { stdputstr(" = zero_snd_list\n"); return; } for (i = 0; ; i++) { if (snd_list == zero_snd_list) { if (i > 1) nyquist_printf(" (skipping %d) ", i-1); stdputstr("->zero_snd_list\n"); return; } if (!snd_list->block) { if (i > 0) nyquist_printf(" (skipping %d) ", i); stdputstr("->\n"); indent(n + 2); nyquist_printf("susp@%p(%s)toss_cnt %d " "current %d lsc %d sr %g t0 %g %p\n", snd_list->u.susp, snd_list->u.susp->name, (int)snd_list->u.susp->toss_cnt, (int)snd_list->u.susp->current, (int)snd_list->u.susp->log_stop_cnt, snd_list->u.susp->sr, snd_list->u.susp->t0, snd_list); /* stdputstr("HI THERE AGAIN\n");*/ susp_print_tree(snd_list->u.susp, n + 4); return; } snd_list = snd_list->u.next; } } /* mark_audio_time -- record the current playback time * * The global variable *audio-markers* is treated as a list. * When the user types ^Q, this function pushes the current * playback time onto the list */ void mark_audio_time() { double playback_time = sound_frames / sound_srate - sound_latency; LVAL time_node = cvflonum(playback_time); setvalue(s_audio_markers, cons(time_node, getvalue(s_audio_markers))); gprintf(TRANS, " %g ", playback_time); fflush(stdout); } /* compute constants p1 and p2: pitchconvert(0) * 2 = pitchconvert(12) - octaves exp(p2) * 2 = exp(12 * p1 + p2) 2 = exp(12 * p1) log(2) = 12 * p1 p1 = log(2.0)/12; pitchconvert(69) gives 440Hz exp(69 * p1 + p2) = 440 69 * p1 + p2 = log(440) p2 = log(440.0) - (69 * p1); */ #define p1 0.0577622650466621 #define p2 2.1011784386926213 double hz_to_step(double hz) { return (log(hz) - p2) / p1; } double step_to_hz(steps) double steps; { return exp(steps * p1 + p2); } /* * from old stuff... */ static void sound_xlfree(s) sound_type s; { /* nyquist_printf("sound_xlfree(%p)\n", s);*/ sound_unref(s); } static void sound_xlprint(LVAL fptr, sound_type s) { /* the type cast from s to LVAL is OK because * putatm does not dereference the 3rd parameter */ putatm(fptr, "Sound", (LVAL) s); } static void sound_xlsave(fp, s) FILE *fp; sound_type s; { stdputstr("sound_save called\n"); } static unsigned char *sound_xlrestore(FILE *fp) { stdputstr("sound_restore called\n"); return NULL; } /* sound_xlmark -- mark LVAL nodes reachable from this sound */ /**/ void sound_xlmark(s) sound_type s; { snd_list_type snd_list; long counter = 0; #ifdef TRACESNDGC nyquist_printf("sound_xlmark(%p)\n", s); #endif if (!s) return; /* pointers to sounds are sometimes NULL */ snd_list = s->list; while (snd_list->block != NULL) { if (snd_list == zero_snd_list) { #ifdef TRACESNDGC stdputstr(" terminates at zero_snd_list\n"); #endif return; } else if (counter > 1000000) { stdputstr("You created a recursive sound! This is a Nyquist bug.\n"); stdputstr("The only known way to do this is by a SETF on a\n"); stdputstr("local variable or parameter that is being passed to SEQ\n"); stdputstr("or SEQREP. The garbage collector assumes that sounds are\n"); stdputstr("not recursive or circular, and follows sounds to their\n"); stdputstr("end. After following a million nodes, I'm pretty sure\n"); stdputstr("that there is a cycle here, but since this is a bug,\n"); stdputstr("I cannot promise to recover. Prepare to crash. If you\n"); stdputstr("cannot locate the cause of this, contact the author -RBD.\n"); } snd_list = snd_list->u.next; counter++; } if (snd_list->u.susp->mark) { #ifdef TRACESNDGC nyquist_printf(" found susp (%s) at %p with mark method\n", snd_list->u.susp->name, snd_list->u.susp); #endif (*(snd_list->u.susp->mark))(snd_list->u.susp); } else { #ifdef TRACESNDGC nyquist_printf(" no mark method on susp %p (%s)\n", snd_list->u.susp, snd_list->u.susp->name); #endif } } void sound_symbols() { a_sound = xlenter("SOUND"); s_audio_markers = xlenter("*AUDIO-MARKERS*"); setvalue(s_audio_markers, NIL); } /* The SOUND Type: */ boolean soundp(s) LVAL s; { return (exttypep(s, a_sound)); } /* sound_zero - create and return a zero that terminates now */ /**/ sound_type sound_zero(time_type t0,rate_type sr) { sound_type sound; falloc_sound(sound, "sound_zero"); sound->get_next = SND_get_first; sound->list = zero_snd_list; sound->logical_stop_cnt = sound->current = 0; sound->true_t0 = sound->t0 = sound->time = t0; sound->stop = MAX_STOP; sound->sr = sr; sound->scale = 1.0F; sound->table = NULL; sound->extra = NULL; return sound; } LVAL cvsound(s) sound_type s; { /* nyquist_printf("cvsound(%p)\n", s);*/ return (cvextern(sound_desc, (unsigned char *) s)); } nyquist-3.05/nyqsrc/probe.c0000644000175000000620000000135510144436365014767 0ustar stevestaff/* probe.c -- used to test resampling */ #include "stdio.h" #include "string.h" #include "xlisp.h" static FILE* probefile = NULL; static long line_num = 0; void probe_init(int readflag) { line_num = 0; probefile = fopen("probe.log", (readflag ? "r" : "w")); } double probe(char *s, double x) { fprintf(probefile, "%s %g\n", s, x); return x; } double probe2(char *s, double x) { char buf1[100], buf2[100]; sprintf(buf1, "%s %g\n", s, x); fgets(buf2, 100, probefile); line_num++; if (strcmp(buf1, buf2)) { nyquist_printf("probe2: difference at line %ld: \n", line_num); nyquist_printf("correct: %s", buf2); nyquist_printf("actual: %s", buf1); abort(); } return x; } nyquist-3.05/nyqsrc/sndfn.cl0000644000175000000620000000345311466723256015153 0ustar stevestaffnyqsrc/sndfnint snd/snd.h nyqsrc/sound.h nyqsrc/add.h nyqsrc/avg.h nyqsrc/compose.h nyqsrc/convolve.h nyqsrc/downsample.h nyqsrc/fft.h nyqsrc/inverse.h nyqsrc/multiseq.h nyqsrc/resamp.h nyqsrc/resampv.h nyqsrc/samples.h nyqsrc/sndmax.h nyqsrc/sndread.h nyqsrc/sndseq.h nyqsrc/sndsliders.h nyqsrc/sndwrite.h nyqsrc/yin.h nyqsrc/nyq-osc-server.h nyqsrc/trigger.h nyqsrc/lpanal.h nyqsrc/phasevocoder.h nyqsrc/pvshell.h ~nyqsrc/sndheader.h tran/abs.h tran/allpoles.h tran/alpass.h tran/alpasscv.h tran/alpassvv.h tran/amosc.h tran/areson.h tran/aresonvc.h tran/aresoncv.h tran/aresonvv.h tran/atone.h tran/atonev.h tran/biquadfilt.h tran/buzz.h tran/chase.h tran/clip.h tran/congen.h tran/const.h tran/coterm.h tran/delaycc.h tran/delaycv.h tran/eqbandvvv.h tran/exp.h tran/follow.h tran/fmosc.h tran/fromobject.h tran/fromarraystream.h tran/gate.h tran/ifft.h tran/instrclar.h tran/instrclarall.h tran/instrclarfreq.h tran/instrsax.h tran/instrsaxall.h tran/instrsaxfreq.h tran/integrate.h tran/log.h tran/lpreson.h tran/maxv.h tran/offset.h tran/oneshot.h tran/osc.h tran/partial.h tran/pluck.h tran/prod.h tran/pwl.h tran/quantize.h tran/recip.h tran/reson.h tran/resonvc.h tran/resoncv.h tran/resonvv.h tran/sampler.h tran/scale.h tran/shape.h tran/sine.h tran/siosc.h tran/slope.h tran/sqrt.h tran/tapf.h tran/tapv.h tran/tone.h tran/tonev.h tran/upsample.h tran/white.h tran/stkrev.h tran/stkpitshift.h tran/stkchorus.h tran/instrbow.h tran/instrbowedfreq.h tran/instrbanded.h tran/instrmandolin.h tran/instrsitar.h tran/instrmodalbar.h tran/instrflute.h tran/instrflutefreq.h tran/instrfluteall.h tran/fmfb.h tran/fmfbv.h nyquist-3.05/nyqsrc/seqfn.wcl0000644000175000000620000000021210144436365015326 0ustar stevestaffnyqsrc\seqfnint cmt\seqdecls.h nyqsrc\seqext.h cmt\seq.h nyqsrc\seqinterf.h cmt\seqread.h cmt\seqmread.h cmt\seqwrite.h cmt\seqmwrite.h nyquist-3.05/nyqsrc/sndmax.h0000644000175000000620000000017510144436365015156 0ustar stevestaff/* sndmax.h -- header to write sounds to files */ double sound_max(LVAL snd_expr, long n); /* LISP: (SND-MAX ANY FIXNUM) */ nyquist-3.05/nyqsrc/samples.c0000644000175000000620000002066611511415575015331 0ustar stevestaff/* samples.c -- various functions for the Nyquist sound data type */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm min->MIN, max->MAX */ #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "samples.h" LVAL s_next = NULL; LVAL s_send; void samples_symbols() { s_next = xlenter(":NEXT"); s_send = xlenter("SEND"); } /* snd_from_array -- convert lisp array to sound type */ /**/ sound_type snd_from_array(double t0, double sr, LVAL array) { sound_type result; snd_list_type snd_list; long total = 0; if (!vectorp(array)) xlerror("array expected", array); result = sound_create(NULL, t0, sr, 1.0); snd_list = result->list; while (total < getsize(array)) { long togo = MIN(getsize(array) - total, max_sample_block_len); sample_block_type block; int i; falloc_sample_block(block, "snd_from_array"); snd_list->block = block; for (i = 0; i < togo; i++) { LVAL elem = getelement(array, total + i); sample_type *ptr = block->samples + i; if (fixp(elem)) *ptr = (sample_type) getfixnum(elem); else if (floatp(elem)) *ptr = (sample_type) getflonum(elem); else xlerror("expecting array elem to be number", elem); } total += togo; snd_list->block_len = (short) togo; snd_list->u.next = snd_list_create(NULL); snd_list = snd_list->u.next; } snd_list->block_len = max_sample_block_len; snd_list->block = zero_block; snd_list->logically_stopped = true; snd_list->u.next = zero_snd_list; return result; } /* snd_length -- count how many samples are in a sound */ /**/ long snd_length(sound_type s, long len) { long total = 0; long blocklen; s = sound_copy(s); if (len > s->stop) len = s->stop; while (total < len) { sample_block_type sampblock = sound_get_next(s, &blocklen); if (sampblock == zero_block) break; total += blocklen; } if (total > len) total = len; sound_unref(s); return total; } /* snd_maxsamp -- compute the maximum value of samples in s */ /**/ double snd_maxsamp(sound_type s) { sample_type result = 0.0F; long blocklen; s = sound_copy(s); while (true) { sample_block_type sampblock = sound_get_next(s, &blocklen); long i; sample_block_values_type sbufp = sampblock->samples; if (sampblock == zero_block || blocklen == 0) { break; } for (i = 0; i < blocklen; i++) { register sample_type samp = *sbufp++; if (result < samp) result = samp; else if (result < -samp) result = -samp; } } return (double) (s->scale * result); } /* snd_samples -- convert sound (prefix) to lisp array */ /**/ LVAL snd_samples(sound_type s, long len) { LVAL v; long vx = 0; long blocklen; register double scale_factor = s->scale; len = snd_length(s, len); s = sound_copy(s); xlsave1(v); v = newvector(len); while (len > 0) { sample_block_type sampblock = sound_get_next(s, &blocklen); long togo = MIN(blocklen, len); long i; sample_block_values_type sbufp = sampblock->samples; for (i = 0; i < togo; i++) { setelement(v, vx++, cvflonum(*sbufp++ * scale_factor)); } len -= togo; } sound_unref(s); /* restore the stack */ xlpop(); return v; } /* NOTE: this code does not properly handle start times that do not * correspond to the time of the first actual sample */ /* NOTE: we need some addtional state to keep track of where we are. * We'll use the extra field of sound_type; first long is length, * so second field will be the count of how many samples we've read. */ #define CNT extra[1] #define INDEX extra[2] #define FIELDS 3 #define SAMPLES list->block->samples LVAL snd_fetch(sound_type s) { if (!s->extra) { /* this is the first call, so fix up s */ s->extra = (long *) malloc(sizeof(long) * FIELDS); s->extra[0] = sizeof(long) * FIELDS; s->CNT = s->INDEX = 0; } else if (s->extra[0] != sizeof(long) * FIELDS) { xlfail("sound in use by another iterator"); } if (s->CNT == s->INDEX) { sound_get_next(s, &(s->CNT)); s->INDEX = 0; } if (s->SAMPLES == zero_block->samples) { return NULL; } /* logical stop time is ignored by this code -- to fix this, * you would need a way to return the logical stop time to * the caller. */ return cvflonum(s->SAMPLES[s->INDEX++] * s->scale); } /* snd_fetch */ /* snd_fetch_array -- fetch a lisp array of samples */ /* * storage layout: the extra field points to extra state that we'll use * extra[0] -> length of extra storage * extra[1] -> CNT (number of samples in current block) * extra[2] -> INDEX (current sample index in current block) * extra[3] -> FILLCNT (how many samples in buffer) * extra[4] -> TERMCNT (how many samples until termination) * extra[4 .. 4+len-1] -> samples (stored as floats) * * Termination details: * Return NIL when the sound terminates. * Termination is defined as the point where all original * signal samples have been shifted out of the samples buffer * so that all that's left are zeros from beyond the termination * point. * Implementation: when termination is discovered, set TERMCNT * to the number of samples to be shifted out. TERMCNT is initially * -1 as a flag that we haven't seen the termination yet. * Each time samples are shifted, decrement TERMCNT by the shift amount. * When TERMCNT goes to zero, return NULL. */ /* these macros define entries in extra, more macros are defined above */ #define FILLCNT extra[3] #define TERMCNT extra[4] #define OFFSET 5 LVAL snd_fetch_array(sound_type s, long len, long step) { long i, maxlen, skip, fillptr; float *samples; LVAL result; LVAL rslt_symbol = xlenter("*RSLT*"); setvalue(rslt_symbol, NULL); if (len < 1) xlfail("len < 1"); if (!s->extra) { /* this is the first call, so fix up s */ s->extra = (long *) malloc(sizeof(long) * (len + OFFSET)); s->extra[0] = sizeof(long) * (len + OFFSET); s->CNT = s->INDEX = s->FILLCNT = 0; s->TERMCNT = -1; maxlen = len; } else { maxlen = (s->extra[0] / sizeof(long)) - OFFSET; if (maxlen < 1) xlfail("sound in use by another iterator"); if (maxlen < len) xlfail("len grew"); } samples = (float *) &(s->extra[OFFSET]); /* step 1: refill buffer with samples */ fillptr = s->FILLCNT; while (fillptr < maxlen) { if (s->INDEX == s->CNT) { sound_get_next(s, &(s->CNT)); if (s->SAMPLES == zero_block->samples) { setvalue(rslt_symbol, cvfixnum(fillptr)); if (s->TERMCNT < 0) s->TERMCNT = fillptr; } s->INDEX = 0; } samples[fillptr++] = s->SAMPLES[s->INDEX++] * s->scale; } s->FILLCNT = fillptr; /* it is important to test here AFTER filling the buffer, because * if fillptr WAS 0 when we hit the zero_block, then filling the * buffer will set TERMCNT to 0. */ if (s->TERMCNT == 0) return NULL; /* logical stop time is ignored by this code -- to fix this, * you would need a way to return the logical stop time to * the caller. */ /* step 2: construct an array and return it */ xlsave1(result); result = newvector(len); for (i = 0; i < len; i++) { setelement(result, i, cvflonum(samples[i])); } /* step 3: shift samples by step */ if (step < 0) xlfail("step < 0"); s->FILLCNT -= step; if (s->FILLCNT < 0) s->FILLCNT = 0; for (i = 0; i < s->FILLCNT; i++) { samples[i] = samples[i + step]; } if (s->TERMCNT >= 0) { s->TERMCNT -= step; if (s->TERMCNT < 0) s->TERMCNT = 0; } /* step 4: advance in sound to next sample we need * (only does work if step > size of buffer) */ skip = step - maxlen; while (skip > 0) { long remaining = s->CNT - s->INDEX; if (remaining >= skip) { s->INDEX += skip; skip = 0; } else { skip -= remaining; sound_get_next(s, &(s->CNT)); s->INDEX = 0; } } /* restore the stack */ xlpop(); return result; } /* snd_fetch_array */ nyquist-3.05/nyqsrc/seqfnint.c0000644000175000000620000001261110144436365015504 0ustar stevestaff/* nyqsrc/seqfnint.c -- interface to cmt/seqdecls.h, * nyqsrc/seqext.h, cmt/seq.h, nyqsrc/seqinterf.h, * cmt/seqread.h, cmt/seqmread.h, cmt/seqwrite.h, * cmt/seqmwrite.h */ #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" extern LVAL s_true; #define cvboolean(i) ((i) ? s_true : NIL) #define testarg2(e) (moreargs() ? (e) : (getflonum(xltoofew()))) #define xlgaanynum() (floatp(*xlargv) ? getflonum(nextarg()) : \ (fixp(*xlargv) ? (double) getfixnum(nextarg()) : \ getflonum(xlbadtype(*xlargv)))) #define getboolean(lval) ((lval) != NIL) extern LVAL RSLT_sym; #include "seqdecls.h" #include "seqext.h" #include "seq.h" /* xlc_seq_reset -- interface to C routine seq_reset */ /**/ LVAL xlc_seq_reset(void) { seq_type arg1 = getseq(xlgaseq()); xllastarg(); seq_reset(arg1); return NIL; } /* xlc_seq_insert_ctrl -- interface to C routine insert_ctrl */ /**/ LVAL xlc_seq_insert_ctrl(void) { seq_type arg1 = getseq(xlgaseq()); long arg2 = getfixnum(xlgafixnum()); long arg3 = getfixnum(xlgafixnum()); long arg4 = getfixnum(xlgafixnum()); long arg5 = getfixnum(xlgafixnum()); long arg6 = getfixnum(xlgafixnum()); xllastarg(); insert_ctrl(arg1, arg2, arg3, arg4, arg5, arg6); return NIL; } /* xlc_seq_insert_ramp -- interface to C routine insert_ctrlramp */ /**/ LVAL xlc_seq_insert_ramp(void) { seq_type arg1 = getseq(xlgaseq()); long arg2 = getfixnum(xlgafixnum()); long arg3 = getfixnum(xlgafixnum()); long arg4 = getfixnum(xlgafixnum()); long arg5 = getfixnum(xlgafixnum()); long arg6 = getfixnum(xlgafixnum()); long arg7 = getfixnum(xlgafixnum()); long arg8 = getfixnum(xlgafixnum()); long arg9 = getfixnum(xlgafixnum()); xllastarg(); insert_ctrlramp(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); return NIL; } /* xlc_seq_insert_macctrl -- interface to C routine insert_macctrl */ /**/ LVAL xlc_seq_insert_macctrl(void) { seq_type arg1 = getseq(xlgaseq()); long arg2 = getfixnum(xlgafixnum()); long arg3 = getfixnum(xlgafixnum()); long arg4 = getfixnum(xlgafixnum()); long arg5 = getfixnum(xlgafixnum()); long arg6 = getfixnum(xlgafixnum()); xllastarg(); insert_macctrl(arg1, arg2, arg3, arg4, arg5, arg6); return NIL; } /* xlc_seq_insert_note -- interface to C routine insert_note */ /**/ LVAL xlc_seq_insert_note(void) { seq_type arg1 = getseq(xlgaseq()); long arg2 = getfixnum(xlgafixnum()); long arg3 = getfixnum(xlgafixnum()); long arg4 = getfixnum(xlgafixnum()); long arg5 = getfixnum(xlgafixnum()); long arg6 = getfixnum(xlgafixnum()); long arg7 = getfixnum(xlgafixnum()); xllastarg(); insert_note(arg1, arg2, arg3, arg4, arg5, arg6, arg7); return NIL; } /* xlc_seq_copy -- interface to C routine seq_copy */ /**/ LVAL xlc_seq_copy(void) { seq_type arg1 = getseq(xlgaseq()); seq_type result; xllastarg(); result = seq_copy(arg1); return cvseq(result); } /* xlc_seq_create -- interface to C routine seq_create */ /**/ LVAL xlc_seq_create(void) { seq_type result; xllastarg(); result = seq_create(); return cvseq(result); } #include "seqinterf.h" /* xlc_seq_next -- interface to C routine seq_next */ /**/ LVAL xlc_seq_next(void) { seq_type arg1 = getseq(xlgaseq()); boolean result; xllastarg(); result = seq_next(arg1); return cvboolean(result); } /* xlc_seq_get -- interface to C routine seq_get */ /**/ LVAL xlc_seq_get(void) { seq_type arg1 = getseq(xlgaseq()); long arg2 = 0; long arg3 = 0; long arg4 = 0; long arg5 = 0; long arg6 = 0; long arg7 = 0; long arg8 = 0; LVAL result; xllastarg(); seq_get(arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8); { LVAL *next = &getvalue(RSLT_sym); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg2); next = &cdr(*next); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg3); next = &cdr(*next); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg4); next = &cdr(*next); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg5); next = &cdr(*next); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg6); next = &cdr(*next); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg7); next = &cdr(*next); *next = cons(NIL, NIL); car(*next) = cvfixnum(arg8); } result = getvalue(RSLT_sym); return result; } #include "seqread.h" /* xlc_seq_read -- interface to C routine seq_read */ /**/ LVAL xlc_seq_read(void) { seq_type arg1 = getseq(xlgaseq()); FILE * arg2 = getfile(xlgastream()); xllastarg(); seq_read(arg1, arg2); return NIL; } #include "seqmread.h" /* xlc_seq_read_smf -- interface to C routine seq_read_smf */ /**/ LVAL xlc_seq_read_smf(void) { seq_type arg1 = getseq(xlgaseq()); FILE * arg2 = getfile(xlgastream()); xllastarg(); seq_read_smf(arg1, arg2); return NIL; } #include "seqwrite.h" /* xlc_seq_write -- interface to C routine seq_write */ /**/ LVAL xlc_seq_write(void) { seq_type arg1 = getseq(xlgaseq()); FILE * arg2 = getfile(xlgastream()); int arg3 = getboolean(xlgetarg()); xllastarg(); seq_write(arg1, arg2, arg3); return NIL; } #include "seqmwrite.h" /* xlc_seq_write_smf -- interface to C routine seq_write_smf */ /**/ LVAL xlc_seq_write_smf(void) { seq_type arg1 = getseq(xlgaseq()); FILE * arg2 = getfile(xlgastream()); xllastarg(); seq_write_smf(arg1, arg2); return NIL; } nyquist-3.05/nyqsrc/inverse.c0000644000175000000620000001565410144436365015342 0ustar stevestaff/* inverse.c -- compute the inverse of a sampled function */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "cext.h" #include "falloc.h" #include "inverse.h" void inverse_free(); typedef struct inverse_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; double s_prev; double s_time; double s_time_increment; double out_time_increment; boolean started; } inverse_susp_node, *inverse_susp_type; void inverse_fetch(register inverse_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples read from s */ int out_cnt = 0; /* how many samples output */ int togo = 0; /* how many more to read from s in inner loop */ int n; sample_block_type out; double out_time = susp->susp.current * susp->out_time_increment; register sample_block_values_type out_ptr; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "inverse_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure we are primed with first value */ /* This is a lot of work just to prefetch susp->s_prev! */ if (!susp->started) { susp->started = true; /* see comments below about susp_check_term_log_samples() */ if (susp->s_cnt == 0) { susp_get_samples(s, s_ptr, s_cnt); if (susp->s_ptr == zero_block->samples) { susp->terminate_cnt = susp->susp.current; } } susp->s_prev = susp_fetch_sample(s, s_ptr, s_cnt); } while (out_cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't run past the s input sample block: */ /* most fetch routines call susp_check_term_log_samples() here * but we can't becasue susp_check_term_log_samples() assumes * that output time progresses at the same rate as input time. * Here, some time warping is going on, so this doesn't work. * Instead, check for termination of s and fix terminate_cnt to * be the current output count rather than the current input time. */ if (susp->s_cnt == 0) { susp_get_samples(s, s_ptr, s_cnt); if (susp->s_ptr == zero_block->samples) { susp->terminate_cnt = susp->susp.current + out_cnt; /* we can't simply terminate here because we might have * some output samples computed already, in which case we * want to return them now and terminate the NEXT time we're * called. */ } } togo = susp->s_cnt; /* if we ran past terminate time, fix up output */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + out_cnt) { /* pretend like we computed the correct number of samples */ togo = 0; out_cnt = susp->terminate_cnt - susp->susp.current; /* exit the loop to complete the termination */ break; } n = togo; s_ptr_reg = susp->s_ptr; if (n) do { /* the inner sample computation loop */ /* scan s_ptr_reg to time t, output and loop */ register double next_value = *s_ptr_reg++; while (out_time < next_value) { *out_ptr++ = (float) (susp->s_time + (out_time - susp->s_prev) / (susp->s->sr * (next_value - susp->s_prev))); out_time += susp->out_time_increment; if (++out_cnt >= max_sample_block_len) goto output_full; } susp->s_prev = next_value; susp->s_time += susp->s_time_increment; } while (--n); /* inner loop */ output_full: /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += (togo - n); susp_took(s_cnt, (togo - n)); cnt += (togo - n); } /* outer loop */ /* test for termination */ if (togo == 0 && out_cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = out_cnt; susp->susp.current += out_cnt; } } /* inverse_fetch */ void inverse_toss_fetch(susp, snd_list) register inverse_susp_type susp; snd_list_type snd_list; { long final_count = MIN(susp->susp.current + max_sample_block_len, susp->susp.toss_cnt); time_type final_time = susp->susp.t0 + final_count / susp->susp.sr; long n; /* fetch samples from s up to final_time for this block of zeros */ while (((long) ((final_time - susp->s->t0) * susp->s->sr + 0.5)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ if (final_count == susp->susp.toss_cnt) { n = ROUND((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; } snd_list->block_len = (short) (final_count - susp->susp.current); susp->susp.current = final_count; snd_list->u.next = snd_list_create((snd_susp_type) susp); snd_list->block = internal_zero_block; } void inverse_mark(inverse_susp_type susp) { sound_xlmark(susp->s); } void inverse_free(inverse_susp_type susp) { sound_unref(susp->s); ffree_generic(susp, sizeof(inverse_susp_node), "inverse_free"); } void inverse_print_tree(inverse_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_inverse(sound_type s, time_type t0, rate_type sr) { register inverse_susp_type susp; falloc_generic(susp, inverse_susp_node, "snd_make_inverse"); susp->susp.fetch = inverse_fetch; susp->terminate_cnt = UNKNOWN; /* initialize susp state */ susp->susp.free = inverse_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = inverse_mark; susp->susp.print_tree = inverse_print_tree; susp->susp.name = "inverse"; susp->logically_stopped = false; susp->susp.log_stop_cnt = UNKNOWN; /* log stop time = term time */ susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->s_prev = 0; susp->s_time = 0; susp->s_time_increment = 1 / s->sr; susp->out_time_increment = 1 / (sr * s->scale); susp->started = false; return sound_create((snd_susp_type)susp, t0, sr, 1.0 /* scale */); } sound_type snd_inverse(sound_type s, time_type t0, rate_type sr) { sound_type s_copy = sound_copy(s); return snd_make_inverse(s_copy, t0, sr); } nyquist-3.05/nyqsrc/localptrs.h0000644000175000000620000000033411466723256015672 0ustar stevestaff/* localptrs.h -- extend XLISP with these functions * * CHANGE LOG * 28-Apr-03 rbd Removed "include switches.h" -- already included */ /* extension to xlisp */ #include "sndfnintptrs.h" #include "seqfnintptrs.h" nyquist-3.05/nyqsrc/sndmax.c0000644000175000000620000000457611466723256015170 0ustar stevestaff/* sndmax.c -- computes the maximum amplitude in a sound */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm min->MIN; fix compiler warning * 31Jan07 rbd handle negative scale factors */ #ifdef UNIX #include "sys/types.h" #endif #include /* #include "snd.h" */ #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "sndmax.h" #include "extern.h" double sound_max(LVAL snd_expr, long n) { LVAL s_as_lval; sound_type s = NULL; long blocklen; sample_block_values_type sbufp; register double maximum = 0; s_as_lval = xleval(snd_expr); /* BE CAREFUL - DO NOT ALLOW GC TO RUN WHILE LVAL IS UNPROTECTED */ if (exttypep(s_as_lval, a_sound)) { /* if snd_expr was simply a symbol, then s now points to a shared sound_node. If we read samples from it, then the sound bound to the symbol will be destroyed, so copy it first. If snd_expr was a real expression that computed a new value, then the next garbage collection will reclaim the sound_node. We need to make the new sound reachable by the garbage collector to that any lisp data reachable from the sound do not get collected. To make the sound reachable, we need to allocate a node, and the GC might run, so we need to protect the OLD s but then make it unreachable. We will let the GC collect the sound in the end. */ xlprot1(s_as_lval); s = sound_copy(getsound(s_as_lval)); s_as_lval = cvsound(s); /* destroys only ref. to original */ /* printf("sound_max: copy is %x, lval %x\n", s, s_as_lval); */ while (n > 0) { long togo, j; sample_block_type sampblock = sound_get_next(s, &blocklen); if (sampblock == zero_block || blocklen == 0) { break; } togo = MIN(blocklen, n); sbufp = sampblock->samples; for (j = 0; j < togo; j++) { register double samp = *sbufp++; if (samp > maximum) maximum = samp; else if (-samp > maximum) maximum = -samp; } n -= togo; } xlpop(); } else { xlerror("sound_max: expression did not return a sound", s_as_lval); } return fabs(maximum * s->scale); } nyquist-3.05/tran/0002755000175000000620000000000011537433123013133 5ustar stevestaffnyquist-3.05/tran/instrsitar.c0000644000175000000620000000554311466723256015520 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrsitar.h" void sitar_free(); typedef struct sitar_susp_struct { snd_susp_node susp; long terminate_cnt; struct instr *mysitar; int temp_ret_value; } sitar_susp_node, *sitar_susp_type; #include "instr.h" void sitar__fetch(register sitar_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mysitar_reg; falloc_sample_block(out, "sitar__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mysitar_reg = susp->mysitar; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) tick(mysitar_reg); } while (--n); /* inner loop */ susp->mysitar = mysitar_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sitar__fetch */ void sitar_free(sitar_susp_type susp) { deleteInstrument(susp->mysitar); ffree_generic(susp, sizeof(sitar_susp_node), "sitar_free"); } void sitar_print_tree(sitar_susp_type susp, int n) { } sound_type snd_make_sitar(time_type t0, double freq, time_type dur, rate_type sr) { register sitar_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, sitar_susp_node, "snd_make_sitar"); susp->mysitar = initInstrument(SITAR, round(sr)); susp->temp_ret_value = noteOn(susp->mysitar, freq, 1.0); susp->susp.fetch = sitar__fetch; susp->terminate_cnt = round((dur) * sr); /* initialize susp state */ susp->susp.free = sitar_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = sitar_print_tree; susp->susp.name = "sitar"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sitar(time_type t0, double freq, time_type dur, rate_type sr) { return snd_make_sitar(t0, freq, dur, sr); } nyquist-3.05/tran/resoncv.h0000644000175000000620000000034510144436365014767 0ustar stevestaffsound_type snd_make_resoncv(sound_type s1, double hz, sound_type bw, int normalization); sound_type snd_resoncv(sound_type s1, double hz, sound_type bw, int normalization); /* LISP: (snd-resoncv SOUND ANYNUM SOUND FIXNUM) */ nyquist-3.05/tran/congen.alg0000644000175000000620000000117110144436365015073 0ustar stevestaff(CONGEN (NAME "congen") (ARGUMENTS ("sound_type" "sndin") ("double" "risetime") ("double" "falltime")) (START (MIN sndin)) (STATE ("double" "value" "0") ("double" "rise_factor" "exp(log(0.5) / (sndin->sr * risetime))") ("double" "fall_factor" "exp(log(0.5) / (sndin->sr * falltime))")) (CONSTANT "fall_factor" "rise_factor") (ALWAYS-SCALE sndin) (TERMINATE (MIN sndin)) (INNER-LOOP " sample_type current = sndin; if (current > value) { value = current - (current - value) * rise_factor; } else { value = current - (current - value) * fall_factor; } output = (sample_type) value;")) nyquist-3.05/tran/aresoncv.h0000644000175000000620000000035010144436365015124 0ustar stevestaffsound_type snd_make_aresoncv(sound_type s1, double hz, sound_type bw, int normalization); sound_type snd_aresoncv(sound_type s1, double hz, sound_type bw, int normalization); /* LISP: (snd-aresoncv SOUND ANYNUM SOUND FIXNUM) */ nyquist-3.05/tran/tone.alg0000644000175000000620000000072010144436365014566 0ustar stevestaff(TONE-ALG (NAME "tone") (ARGUMENTS ("sound_type" "input") ("double" "hz")) (START (MIN input)) (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) (STATE ("double" "b" "2.0 - cos(hz * PI2 / input->sr)" TEMP) ("double" "c2" "b - sqrt((b * b) - 1.0)") ("double" "c1" "(1.0 - susp->c2) * input->scale") ("double" "prev" "0.0")) (INTERNAL-SCALING input) (CONSTANT "c1" "c2") (INNER-LOOP "output = (sample_type) (prev = c1 * input + c2 * prev)") ) nyquist-3.05/tran/offset.c0000644000175000000620000002032510144436365014571 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "offset.h" void offset_free(); typedef struct offset_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sample_type offset; } offset_susp_node, *offset_susp_type; void offset_n_fetch(register offset_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type offset_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "offset_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *s1_ptr_reg++ + offset_reg; } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* offset_n_fetch */ void offset_s_fetch(register offset_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type offset_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "offset_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (s1_scale_reg * *s1_ptr_reg++) + offset_reg; } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* offset_s_fetch */ void offset_toss_fetch(susp, snd_list) register offset_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void offset_mark(offset_susp_type susp) { sound_xlmark(susp->s1); } void offset_free(offset_susp_type susp) { sound_unref(susp->s1); ffree_generic(susp, sizeof(offset_susp_node), "offset_free"); } void offset_print_tree(offset_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_offset(sound_type s1, double offset) { register offset_susp_type susp; rate_type sr = s1->sr; time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, offset_susp_node, "snd_make_offset"); susp->offset = (sample_type) offset; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = offset_n_fetch; break; case INTERP_s: susp->susp.fetch = offset_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = offset_toss_fetch; } /* initialize susp state */ susp->susp.free = offset_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = offset_mark; susp->susp.print_tree = offset_print_tree; susp->susp.name = "offset"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_offset(sound_type s1, double offset) { sound_type s1_copy = sound_copy(s1); return snd_make_offset(s1_copy, offset); } nyquist-3.05/tran/tone.c0000644000175000000620000001336710144436365014260 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "tone.h" void tone_free(); typedef struct tone_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; double c2; double c1; double prev; } tone_susp_node, *tone_susp_type; void tone_n_fetch(register tone_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c2_reg; register double c1_reg; register double prev_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "tone_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c2_reg = susp->c2; c1_reg = susp->c1; prev_reg = susp->prev; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (prev_reg = c1_reg * *input_ptr_reg++ + c2_reg * prev_reg); } while (--n); /* inner loop */ susp->prev = prev_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tone_n_fetch */ void tone_toss_fetch(susp, snd_list) register tone_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void tone_mark(tone_susp_type susp) { sound_xlmark(susp->input); } void tone_free(tone_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(tone_susp_node), "tone_free"); } void tone_print_tree(tone_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_tone(sound_type input, double hz) { register tone_susp_type susp; double b; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, tone_susp_node, "snd_make_tone"); b = 2.0 - cos(hz * PI2 / input->sr); susp->c2 = b - sqrt((b * b) - 1.0); susp->c1 = (1.0 - susp->c2) * input->scale; susp->prev = 0.0; susp->susp.fetch = tone_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = tone_toss_fetch; } /* initialize susp state */ susp->susp.free = tone_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = tone_mark; susp->susp.print_tree = tone_print_tree; susp->susp.name = "tone"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_tone(sound_type input, double hz) { sound_type input_copy = sound_copy(input); return snd_make_tone(input_copy, hz); } nyquist-3.05/tran/eqbandvvv.h0000644000175000000620000000037110144436365015303 0ustar stevestaffsound_type snd_make_eqbandvvv(sound_type input, sound_type hz, sound_type gain, sound_type width); sound_type snd_eqbandvvv(sound_type input, sound_type hz, sound_type gain, sound_type width); /* LISP: (snd-eqbandvvv SOUND SOUND SOUND SOUND) */ nyquist-3.05/tran/instrbow.c0000644000175000000620000001236311466723256015163 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrbow.h" void bowed_free(); typedef struct bowed_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type bowpress_env; long bowpress_env_cnt; sample_block_values_type bowpress_env_ptr; struct instr *mybow; int temp_ret_value; } bowed_susp_node, *bowed_susp_type; #include "instr.h" void bowed_s_fetch(register bowed_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mybow_reg; register sample_type bowpress_env_scale_reg = susp->bowpress_env->scale; register sample_block_values_type bowpress_env_ptr_reg; falloc_sample_block(out, "bowed_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the bowpress_env input sample block: */ susp_check_term_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); togo = min(togo, susp->bowpress_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mybow_reg = susp->mybow; bowpress_env_ptr_reg = susp->bowpress_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(mybow_reg, 128, BOW_CONTROL_CHANGE_CONST * (bowpress_env_scale_reg * *bowpress_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(mybow_reg); } while (--n); /* inner loop */ susp->mybow = mybow_reg; /* using bowpress_env_ptr_reg is a bad idea on RS/6000: */ susp->bowpress_env_ptr += togo; out_ptr += togo; susp_took(bowpress_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* bowed_s_fetch */ void bowed_toss_fetch(susp, snd_list) register bowed_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from bowpress_env up to final_time for this block of zeros */ while ((round((final_time - susp->bowpress_env->t0) * susp->bowpress_env->sr)) >= susp->bowpress_env->current) susp_get_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->bowpress_env->t0) * susp->bowpress_env->sr - (susp->bowpress_env->current - susp->bowpress_env_cnt)); susp->bowpress_env_ptr += n; susp_took(bowpress_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void bowed_mark(bowed_susp_type susp) { sound_xlmark(susp->bowpress_env); } void bowed_free(bowed_susp_type susp) { deleteInstrument(susp->mybow); sound_unref(susp->bowpress_env); ffree_generic(susp, sizeof(bowed_susp_node), "bowed_free"); } void bowed_print_tree(bowed_susp_type susp, int n) { indent(n); stdputstr("bowpress_env:"); sound_print_tree_1(susp->bowpress_env, n); } sound_type snd_make_bowed(double freq, sound_type bowpress_env, rate_type sr) { register bowed_susp_type susp; /* sr specified as input parameter */ time_type t0 = bowpress_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, bowed_susp_node, "snd_make_bowed"); susp->mybow = initInstrument(BOWED, round(sr)); controlChange(susp->mybow, 1, 0.0);; susp->temp_ret_value = noteOn(susp->mybow, freq, 1.0); susp->susp.fetch = bowed_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < bowpress_env->t0) sound_prepend_zeros(bowpress_env, t0); /* minimum start time over all inputs: */ t0_min = min(bowpress_env->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = bowed_toss_fetch; } /* initialize susp state */ susp->susp.free = bowed_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = bowed_mark; susp->susp.print_tree = bowed_print_tree; susp->susp.name = "bowed"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->bowpress_env = bowpress_env; susp->bowpress_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_bowed(double freq, sound_type bowpress_env, rate_type sr) { sound_type bowpress_env_copy = sound_copy(bowpress_env); return snd_make_bowed(freq, bowpress_env_copy, sr); } nyquist-3.05/tran/resonvv.h0000644000175000000620000000035610144436365015014 0ustar stevestaffsound_type snd_make_resonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization); sound_type snd_resonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization); /* LISP: (snd-resonvv SOUND SOUND SOUND FIXNUM) */ nyquist-3.05/tran/ifft-old.alg0000644000175000000620000000653010144436365015332 0ustar stevestaff(IFFT-ALG (NAME "ifft") (ARGUMENTS ("time_type" "t0") ("rate_type" "sr") ("LVAL" "src")) (SUPPORT-FUNCTIONS " /* IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either an * array of samples or NIL. The output of ifft is simply the * concatenation of the samples taken from the array. Later, * an ifft will be plugged in and this will return overlapped * adds of the ifft's. */ #include \"samples.h\" /* IFFT code goes here */ ") (SAMPLE-RATE "sr") (STATE ("long" "index" "0") ; samples index ("long" "length" "0"); samples length ("LVAL" "array" "NULL") ("LVAL" "src" "src") ("sample_type *" "samples" "NULL")) (OUTER-LOOP " if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->index >= susp->length) { long i; susp->index = 0; susp->array = xleval(cons(s_send, cons(susp->src, consa(s_next)))); susp->index = 0; if (susp->array == NULL) { susp->src = NULL; goto out; } else if (!vectorp(susp->array)) { xlerror(\"array expected\", susp->array); } else if (susp->samples == NULL) { /* assume arrays are all the same size as first one; now that we know the size, we just have to do this first allocation. */ susp->length = getsize(susp->array); if (susp->length < 1) xlerror(\"array has no elements\", susp->array); susp->samples = (sample_type *) calloc(susp->length, sizeof(sample_type)); } else if (getsize(susp->array) != susp->length) { xlerror(\"arrays must all be the same length\", susp->array); } /* at this point, we have a new array and a place to put samples */ for (i = 0; i < susp->length; i++) { LVAL elem = getelement(susp->array, i); if (ntype(elem) != FLONUM) { xlerror(\"flonum expected\", elem); } susp->samples[i] = (sample_type) getflonum(elem); } susp->array = NULL; /* free the array */ /* here is where the IFFT and windowing should take place */ /* temp_fft = (double *) malloc (susp->length * sizeof(double)); if (temp_fft == 0) return; big_samples = (double *) malloc (susp->length * sizeof(double)); if (big_samples == 0) return; for (i = 0; i < susp->length; i++) { big_samples[i] = (double) susp->samples[i]; } rp = rfftw_create_plan(susp->length, FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE); rfftw_one(rp, big_samples, temp_fft); rfftw_destroy_plan(rp); free(big_samples); for (i = 0; i < susp->length; i++) { setelement(result, i, cvflonum(temp_fft[i])); } free (temp_fft); */ } togo = min(togo, susp->length - susp->index); ") (INNER-LOOP "output = samples[index++];") (CONSTANT "length" "samples" "array" "src") (TERMINATE COMPUTED) (FINALIZATION " free(susp->samples); ") ) nyquist-3.05/tran/white.alg0000644000175000000620000000106010144436365014737 0ustar stevestaff(WHITE-ALG (NAME "white") (ARGUMENTS ("time_type" "t0") ("rate_type" "sr") ("time_type" "d")) (STATE ) (TERMINATE (AFTER "d")) (INNER-LOOP "output = (sample_type) (rand() * rand_scale - 1.0);") (SAMPLE-RATE "sr") (SUPPORT-HEADER " /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 rbd all systems now use rand(), based on DM's modifications */ #include #include /* rand returns from 0 to RAND_MAX. Scale and offset * to get range from -1 to +1 */ #define rand_scale (2.0/RAND_MAX) ") ) nyquist-3.05/tran/stkchorus.h0000644000175000000620000000045611466723256015346 0ustar stevestaffsound_type snd_make_stkchorus(sound_type s1, double baseDelay, double depth, double freq, double mix, rate_type sr); sound_type snd_stkchorus(sound_type s1, double baseDelay, double depth, double freq, double mix, rate_type sr); /* LISP: (snd-stkchorus SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/tonev.h0000644000175000000620000000022510144436365014440 0ustar stevestaffsound_type snd_make_tonev(sound_type s1, sound_type hz); sound_type snd_tonev(sound_type s1, sound_type hz); /* LISP: (snd-tonev SOUND SOUND) */ nyquist-3.05/tran/atone.h0000644000175000000620000000021410144436365014411 0ustar stevestaffsound_type snd_make_atone(sound_type s, double hz); sound_type snd_atone(sound_type s, double hz); /* LISP: (snd-atone SOUND ANYNUM) */ nyquist-3.05/tran/sqrt.c0000644000175000000620000001266310144436365014302 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "sqrt.h" void sqrt_free(); typedef struct sqrt_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; } sqrt_susp_node, *sqrt_susp_type; void sqrt_s_fetch(register sqrt_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "sqrt_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { sample_type i = (input_scale_reg * *input_ptr_reg++); if (i < 0) i = 0; *out_ptr_reg++ = (sample_type) sqrt(i); }; } while (--n); /* inner loop */ /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* sqrt_s_fetch */ void sqrt_toss_fetch(susp, snd_list) register sqrt_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void sqrt_mark(sqrt_susp_type susp) { sound_xlmark(susp->input); } void sqrt_free(sqrt_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(sqrt_susp_node), "sqrt_free"); } void sqrt_print_tree(sqrt_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_sqrt(sound_type input) { register sqrt_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, sqrt_susp_node, "snd_make_sqrt"); susp->susp.fetch = sqrt_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = sqrt_toss_fetch; } /* initialize susp state */ susp->susp.free = sqrt_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = sqrt_mark; susp->susp.print_tree = sqrt_print_tree; susp->susp.name = "sqrt"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sqrt(sound_type input) { sound_type input_copy = sound_copy(input); return snd_make_sqrt(input_copy); } nyquist-3.05/tran/recip.alg0000644000175000000620000000042711466723256014735 0ustar stevestaff(RECIP-ALG (NAME "recip") (ARGUMENTS ("sound_type" "s1")) (STATE ("double" "scale" "(1.0 / s1->scale)")) (INTERNAL-SCALING s1) (CONSTANT "scale") (START (MIN s1)) (INNER-LOOP "output = (sample_type) (scale / s1)") (TERMINATE (MIN s1)) (LOGICAL-STOP (MIN s1)) ) nyquist-3.05/tran/pluck.h0000644000175000000620000000037410144436365014430 0ustar stevestaffsound_type snd_make_pluck(rate_type sr, double hz, time_type t0, time_type d, double final_amp); sound_type snd_pluck(rate_type sr, double hz, time_type t0, time_type d, double final_amp); /* LISP: (snd-pluck ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/eqbandvvv.c0000644000175000000620000006664711466723256015326 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "eqbandvvv.h" void eqbandvvv_free(); typedef struct eqbandvvv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; sound_type hz; long hz_cnt; sample_block_values_type hz_ptr; /* support for interpolation of hz */ sample_type hz_x1_sample; double hz_pHaSe; double hz_pHaSe_iNcR; /* support for ramp between samples of hz */ double output_per_hz; long hz_n; sound_type gain; long gain_cnt; sample_block_values_type gain_ptr; /* support for interpolation of gain */ sample_type gain_x1_sample; double gain_pHaSe; double gain_pHaSe_iNcR; /* support for ramp between samples of gain */ double output_per_gain; long gain_n; sound_type width; long width_cnt; sample_block_values_type width_ptr; /* support for interpolation of width */ sample_type width_x1_sample; double width_pHaSe; double width_pHaSe_iNcR; /* support for ramp between samples of width */ double output_per_width; long width_n; double inp_scale; double w1; double sw; double cw; double J; double gg; double b0; double b1; double b2; double a0; double a1; double a2; double z1; double z2; boolean recompute; double inp_period; } eqbandvvv_susp_node, *eqbandvvv_susp_type; #define log_of_2_over_2 0.3465735902799726547086 void eqbandvvv_ssss_fetch(register eqbandvvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double w1_reg; register double sw_reg; register double cw_reg; register double J_reg; register double gg_reg; register double b0_reg; register double b1_reg; register double b2_reg; register double a0_reg; register double a1_reg; register double a2_reg; register double z1_reg; register double z2_reg; register boolean recompute_reg; register double inp_period_reg; register sample_type width_scale_reg = susp->width->scale; register sample_block_values_type width_ptr_reg; register sample_type gain_scale_reg = susp->gain->scale; register sample_block_values_type gain_ptr_reg; register sample_type hz_scale_reg = susp->hz->scale; register sample_block_values_type hz_ptr_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "eqbandvvv_ssss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the hz input sample block: */ susp_check_term_log_samples(hz, hz_ptr, hz_cnt); togo = min(togo, susp->hz_cnt); /* don't run past the gain input sample block: */ susp_check_term_log_samples(gain, gain_ptr, gain_cnt); togo = min(togo, susp->gain_cnt); /* don't run past the width input sample block: */ susp_check_term_log_samples(width, width_ptr, width_cnt); togo = min(togo, susp->width_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; w1_reg = susp->w1; sw_reg = susp->sw; cw_reg = susp->cw; J_reg = susp->J; gg_reg = susp->gg; b0_reg = susp->b0; b1_reg = susp->b1; b2_reg = susp->b2; a0_reg = susp->a0; a1_reg = susp->a1; a2_reg = susp->a2; z1_reg = susp->z1; z2_reg = susp->z2; recompute_reg = susp->recompute; inp_period_reg = susp->inp_period; width_ptr_reg = susp->width_ptr; gain_ptr_reg = susp->gain_ptr; hz_ptr_reg = susp->hz_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; w1_reg = PI2 * (hz_scale_reg * *hz_ptr_reg++) * inp_period_reg; sw_reg = sin(w1_reg); cw_reg = cos(w1_reg); b1_reg = -2.0 * cw_reg; a1_reg = -b1_reg; J_reg = sqrt((gain_scale_reg * *gain_ptr_reg++)); recompute_reg = true; recompute_reg = true; recompute_reg = true; if (recompute_reg) { /* a0_reg = 1.0 + gg_reg / J_reg; */ double a_0_recip = J_reg / (J_reg + gg_reg); recompute_reg = false; gg_reg = sw_reg * sinh(log_of_2_over_2 * (width_scale_reg * *width_ptr_reg++) * w1_reg / sw_reg); b0_reg = (1.0 + gg_reg * J_reg) * a_0_recip; b1_reg *= a_0_recip; b2_reg = (1.0 - gg_reg * J_reg) * a_0_recip; a1_reg *= a_0_recip; a2_reg = (gg_reg / J_reg - 1.0) * a_0_recip; } z0 = (input_scale_reg * *input_ptr_reg++) + a1_reg*z1_reg + a2_reg*z2_reg; *out_ptr_reg++ = (sample_type) (z0*b0_reg + z1_reg*b1_reg + z2_reg*b2_reg); z2_reg = z1_reg; z1_reg = z0;; } while (--n); /* inner loop */ susp->z1 = z1_reg; susp->z2 = z2_reg; susp->recompute = recompute_reg; /* using width_ptr_reg is a bad idea on RS/6000: */ susp->width_ptr += togo; /* using gain_ptr_reg is a bad idea on RS/6000: */ susp->gain_ptr += togo; /* using hz_ptr_reg is a bad idea on RS/6000: */ susp->hz_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(hz_cnt, togo); susp_took(gain_cnt, togo); susp_took(width_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* eqbandvvv_ssss_fetch */ void eqbandvvv_siii_fetch(register eqbandvvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double w1_reg; register double sw_reg; register double cw_reg; register double J_reg; register double gg_reg; register double b0_reg; register double b1_reg; register double b2_reg; register double a0_reg; register double a1_reg; register double a2_reg; register double z1_reg; register double z2_reg; register boolean recompute_reg; register double inp_period_reg; register double width_pHaSe_iNcR_rEg = susp->width_pHaSe_iNcR; register double width_pHaSe_ReG; register sample_type width_x1_sample_reg; register double gain_pHaSe_iNcR_rEg = susp->gain_pHaSe_iNcR; register double gain_pHaSe_ReG; register sample_type gain_x1_sample_reg; register double hz_pHaSe_iNcR_rEg = susp->hz_pHaSe_iNcR; register double hz_pHaSe_ReG; register sample_type hz_x1_sample_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "eqbandvvv_siii_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->w1 = PI2 * susp->hz_x1_sample * susp->inp_period; susp->sw = sin(susp->w1); susp->cw = cos(susp->w1); susp->b1 = -2.0 * susp->cw; susp->a1 = -susp->b1; susp->recompute = true; susp_check_term_log_samples(gain, gain_ptr, gain_cnt); susp->gain_x1_sample = susp_fetch_sample(gain, gain_ptr, gain_cnt); susp->J = sqrt(susp->gain_x1_sample); susp->recompute = true; susp_check_term_log_samples(width, width_ptr, width_cnt); susp->width_x1_sample = susp_fetch_sample(width, width_ptr, width_cnt); susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; w1_reg = susp->w1; sw_reg = susp->sw; cw_reg = susp->cw; J_reg = susp->J; gg_reg = susp->gg; b0_reg = susp->b0; b1_reg = susp->b1; b2_reg = susp->b2; a0_reg = susp->a0; a1_reg = susp->a1; a2_reg = susp->a2; z1_reg = susp->z1; z2_reg = susp->z2; recompute_reg = susp->recompute; inp_period_reg = susp->inp_period; width_pHaSe_ReG = susp->width_pHaSe; width_x1_sample_reg = susp->width_x1_sample; gain_pHaSe_ReG = susp->gain_pHaSe; gain_x1_sample_reg = susp->gain_x1_sample; hz_pHaSe_ReG = susp->hz_pHaSe; hz_x1_sample_reg = susp->hz_x1_sample; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; if (hz_pHaSe_ReG >= 1.0) { /* fixup-depends hz */ /* pick up next sample as hz_x1_sample: */ susp->hz_ptr++; susp_took(hz_cnt, 1); hz_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(hz, hz_ptr, hz_cnt, hz_x1_sample_reg); hz_x1_sample_reg = susp_current_sample(hz, hz_ptr); w1_reg = susp->w1 = PI2 * hz_x1_sample_reg * inp_period_reg; sw_reg = susp->sw = sin(w1_reg); cw_reg = susp->cw = cos(w1_reg); b1_reg = susp->b1 = -2.0 * cw_reg; a1_reg = susp->a1 = -b1_reg; recompute_reg = susp->recompute = true; } if (gain_pHaSe_ReG >= 1.0) { /* fixup-depends gain */ /* pick up next sample as gain_x1_sample: */ susp->gain_ptr++; susp_took(gain_cnt, 1); gain_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(gain, gain_ptr, gain_cnt, gain_x1_sample_reg); gain_x1_sample_reg = susp_current_sample(gain, gain_ptr); J_reg = susp->J = sqrt(gain_x1_sample_reg); recompute_reg = susp->recompute = true; } if (width_pHaSe_ReG >= 1.0) { /* fixup-depends width */ /* pick up next sample as width_x1_sample: */ susp->width_ptr++; susp_took(width_cnt, 1); width_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(width, width_ptr, width_cnt, width_x1_sample_reg); width_x1_sample_reg = susp_current_sample(width, width_ptr); recompute_reg = susp->recompute = true; } if (recompute_reg) { /* a0_reg = 1.0 + gg_reg / J_reg; */ double a_0_recip = J_reg / (J_reg + gg_reg); recompute_reg = false; gg_reg = sw_reg * sinh(log_of_2_over_2 * width_x1_sample_reg * w1_reg / sw_reg); b0_reg = (1.0 + gg_reg * J_reg) * a_0_recip; b1_reg *= a_0_recip; b2_reg = (1.0 - gg_reg * J_reg) * a_0_recip; a1_reg *= a_0_recip; a2_reg = (gg_reg / J_reg - 1.0) * a_0_recip; } z0 = (input_scale_reg * *input_ptr_reg++) + a1_reg*z1_reg + a2_reg*z2_reg; *out_ptr_reg++ = (sample_type) (z0*b0_reg + z1_reg*b1_reg + z2_reg*b2_reg); z2_reg = z1_reg; z1_reg = z0;; hz_pHaSe_ReG += hz_pHaSe_iNcR_rEg; gain_pHaSe_ReG += gain_pHaSe_iNcR_rEg; width_pHaSe_ReG += width_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->z1 = z1_reg; susp->z2 = z2_reg; susp->recompute = recompute_reg; susp->width_pHaSe = width_pHaSe_ReG; susp->width_x1_sample = width_x1_sample_reg; susp->gain_pHaSe = gain_pHaSe_ReG; susp->gain_x1_sample = gain_x1_sample_reg; susp->hz_pHaSe = hz_pHaSe_ReG; susp->hz_x1_sample = hz_x1_sample_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* eqbandvvv_siii_fetch */ void eqbandvvv_srrr_fetch(register eqbandvvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz_val; sample_type gain_val; sample_type width_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double cw_reg; register double b0_reg; register double b1_reg; register double b2_reg; register double a1_reg; register double a2_reg; register double z1_reg; register double z2_reg; register boolean recompute_reg; register double inp_period_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "eqbandvvv_srrr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz_pHaSe = 1.0; susp->gain_pHaSe = 1.0; susp->width_pHaSe = 1.0; } susp_check_term_log_samples(hz, hz_ptr, hz_cnt); susp_check_term_log_samples(gain, gain_ptr, gain_cnt); susp_check_term_log_samples(width, width_ptr, width_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* grab next hz_x1_sample when phase goes past 1.0; */ /* use hz_n (computed below) to avoid roundoff errors: */ if (susp->hz_n <= 0) { susp_check_term_log_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->hz_pHaSe -= 1.0; /* hz_n gets number of samples before phase exceeds 1.0: */ susp->hz_n = (long) ((1.0 - susp->hz_pHaSe) * susp->output_per_hz); susp->w1 = PI2 * susp->hz_x1_sample * susp->inp_period; susp->sw = sin(susp->w1); susp->cw = cos(susp->w1); susp->b1 = -2.0 * susp->cw; susp->a1 = -susp->b1; susp->recompute = true; } togo = min(togo, susp->hz_n); hz_val = susp->hz_x1_sample; /* grab next gain_x1_sample when phase goes past 1.0; */ /* use gain_n (computed below) to avoid roundoff errors: */ if (susp->gain_n <= 0) { susp_check_term_log_samples(gain, gain_ptr, gain_cnt); susp->gain_x1_sample = susp_fetch_sample(gain, gain_ptr, gain_cnt); susp->gain_pHaSe -= 1.0; /* gain_n gets number of samples before phase exceeds 1.0: */ susp->gain_n = (long) ((1.0 - susp->gain_pHaSe) * susp->output_per_gain); susp->J = sqrt(susp->gain_x1_sample); susp->recompute = true; } togo = min(togo, susp->gain_n); gain_val = susp->gain_x1_sample; /* grab next width_x1_sample when phase goes past 1.0; */ /* use width_n (computed below) to avoid roundoff errors: */ if (susp->width_n <= 0) { susp_check_term_log_samples(width, width_ptr, width_cnt); susp->width_x1_sample = susp_fetch_sample(width, width_ptr, width_cnt); susp->width_pHaSe -= 1.0; /* width_n gets number of samples before phase exceeds 1.0: */ susp->width_n = (long) ((1.0 - susp->width_pHaSe) * susp->output_per_width); susp->recompute = true; } togo = min(togo, susp->width_n); width_val = susp->width_x1_sample; if (susp->recompute) { /* susp->a0 = 1.0 + susp->gg / susp->J; */ double a_0_recip = susp->J / (susp->J + susp->gg); susp->recompute = false; susp->gg = susp->sw * sinh(log_of_2_over_2 * width_val * susp->w1 / susp->sw); susp->b0 = (1.0 + susp->gg * susp->J) * a_0_recip; susp->b1 *= a_0_recip; susp->b2 = (1.0 - susp->gg * susp->J) * a_0_recip; susp->a1 *= a_0_recip; susp->a2 = (susp->gg / susp->J - 1.0) * a_0_recip; } /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; cw_reg = susp->cw; b0_reg = susp->b0; b1_reg = susp->b1; b2_reg = susp->b2; a1_reg = susp->a1; a2_reg = susp->a2; z1_reg = susp->z1; z2_reg = susp->z2; recompute_reg = susp->recompute; inp_period_reg = susp->inp_period; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; z0 = (input_scale_reg * *input_ptr_reg++) + a1_reg*z1_reg + a2_reg*z2_reg; *out_ptr_reg++ = (sample_type) (z0*b0_reg + z1_reg*b1_reg + z2_reg*b2_reg); z2_reg = z1_reg; z1_reg = z0;; } while (--n); /* inner loop */ susp->z1 = z1_reg; susp->z2 = z2_reg; susp->recompute = recompute_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp->hz_pHaSe += togo * susp->hz_pHaSe_iNcR; susp->hz_n -= togo; susp->gain_pHaSe += togo * susp->gain_pHaSe_iNcR; susp->gain_n -= togo; susp->width_pHaSe += togo * susp->width_pHaSe_iNcR; susp->width_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* eqbandvvv_srrr_fetch */ void eqbandvvv_toss_fetch(susp, snd_list) register eqbandvvv_susp_type susp; snd_list_type snd_list; { time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* fetch samples from hz up to final_time for this block of zeros */ while ((round((final_time - susp->hz->t0) * susp->hz->sr)) >= susp->hz->current) susp_get_samples(hz, hz_ptr, hz_cnt); /* fetch samples from gain up to final_time for this block of zeros */ while ((round((final_time - susp->gain->t0) * susp->gain->sr)) >= susp->gain->current) susp_get_samples(gain, gain_ptr, gain_cnt); /* fetch samples from width up to final_time for this block of zeros */ while ((round((final_time - susp->width->t0) * susp->width->sr)) >= susp->width->current) susp_get_samples(width, width_ptr, width_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); n = round((final_time - susp->hz->t0) * susp->hz->sr - (susp->hz->current - susp->hz_cnt)); susp->hz_ptr += n; susp_took(hz_cnt, n); n = round((final_time - susp->gain->t0) * susp->gain->sr - (susp->gain->current - susp->gain_cnt)); susp->gain_ptr += n; susp_took(gain_cnt, n); n = round((final_time - susp->width->t0) * susp->width->sr - (susp->width->current - susp->width_cnt)); susp->width_ptr += n; susp_took(width_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void eqbandvvv_mark(eqbandvvv_susp_type susp) { sound_xlmark(susp->input); sound_xlmark(susp->hz); sound_xlmark(susp->gain); sound_xlmark(susp->width); } void eqbandvvv_free(eqbandvvv_susp_type susp) { sound_unref(susp->input); sound_unref(susp->hz); sound_unref(susp->gain); sound_unref(susp->width); ffree_generic(susp, sizeof(eqbandvvv_susp_node), "eqbandvvv_free"); } void eqbandvvv_print_tree(eqbandvvv_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); indent(n); stdputstr("hz:"); sound_print_tree_1(susp->hz, n); indent(n); stdputstr("gain:"); sound_print_tree_1(susp->gain, n); indent(n); stdputstr("width:"); sound_print_tree_1(susp->width, n); } sound_type snd_make_eqbandvvv(sound_type input, sound_type hz, sound_type gain, sound_type width) { register eqbandvvv_susp_type susp; rate_type sr = input->sr; time_type t0 = min(min(min(input->t0, hz->t0), gain->t0), width->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; long lsc; falloc_generic(susp, eqbandvvv_susp_node, "snd_make_eqbandvvv"); susp->inp_scale = input->scale; susp->w1 = 0.0; susp->sw = 0.0; susp->cw = 0.0; susp->J = 0.0; susp->gg = 0.0; susp->b0 = 0.0; susp->b1 = 0.0; susp->b2 = 0.0; susp->a0 = 0.0; susp->a1 = 0.0; susp->a2 = 0.0; susp->z1 = 0.0; susp->z2 = 0.0; susp->recompute = false; susp->inp_period = 1.0 / input->sr; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); interp_desc = (interp_desc << 2) + interp_style(hz, sr); interp_desc = (interp_desc << 2) + interp_style(gain, sr); interp_desc = (interp_desc << 2) + interp_style(width, sr); switch (interp_desc) { case INTERP_nnnn: /* handled below */ case INTERP_nnns: /* handled below */ case INTERP_nnsn: /* handled below */ case INTERP_nnss: /* handled below */ case INTERP_nsnn: /* handled below */ case INTERP_nsns: /* handled below */ case INTERP_nssn: /* handled below */ case INTERP_nsss: /* handled below */ case INTERP_snnn: /* handled below */ case INTERP_snns: /* handled below */ case INTERP_snsn: /* handled below */ case INTERP_snss: /* handled below */ case INTERP_ssnn: /* handled below */ case INTERP_ssns: /* handled below */ case INTERP_sssn: /* handled below */ case INTERP_ssss: susp->susp.fetch = eqbandvvv_ssss_fetch; break; case INTERP_niii: /* handled below */ case INTERP_siii: susp->susp.fetch = eqbandvvv_siii_fetch; break; case INTERP_nrrr: /* handled below */ case INTERP_srrr: susp->susp.fetch = eqbandvvv_srrr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); if (t0 < hz->t0) sound_prepend_zeros(hz, t0); if (t0 < gain->t0) sound_prepend_zeros(gain, t0); if (t0 < width->t0) sound_prepend_zeros(width, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, min(hz->t0, min(gain->t0, min(width->t0, t0)))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = eqbandvvv_toss_fetch; } /* initialize susp state */ susp->susp.free = eqbandvvv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = eqbandvvv_mark; susp->susp.print_tree = eqbandvvv_print_tree; susp->susp.name = "eqbandvvv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); lsc = logical_stop_cnt_cvt(hz); if (susp->susp.log_stop_cnt > lsc) susp->susp.log_stop_cnt = lsc; lsc = logical_stop_cnt_cvt(gain); if (susp->susp.log_stop_cnt > lsc) susp->susp.log_stop_cnt = lsc; lsc = logical_stop_cnt_cvt(width); if (susp->susp.log_stop_cnt > lsc) susp->susp.log_stop_cnt = lsc; susp->started = false; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; susp->hz = hz; susp->hz_cnt = 0; susp->hz_pHaSe = 0.0; susp->hz_pHaSe_iNcR = hz->sr / sr; susp->hz_n = 0; susp->output_per_hz = sr / hz->sr; susp->gain = gain; susp->gain_cnt = 0; susp->gain_pHaSe = 0.0; susp->gain_pHaSe_iNcR = gain->sr / sr; susp->gain_n = 0; susp->output_per_gain = sr / gain->sr; susp->width = width; susp->width_cnt = 0; susp->width_pHaSe = 0.0; susp->width_pHaSe_iNcR = width->sr / sr; susp->width_n = 0; susp->output_per_width = sr / width->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_eqbandvvv(sound_type input, sound_type hz, sound_type gain, sound_type width) { sound_type input_copy = sound_copy(input); sound_type hz_copy = sound_copy(hz); sound_type gain_copy = sound_copy(gain); sound_type width_copy = sound_copy(width); return snd_make_eqbandvvv(input_copy, hz_copy, gain_copy, width_copy); } nyquist-3.05/tran/fmosc.alg0000644000175000000620000000271210144436365014733 0ustar stevestaff(FMOSC-ALG (NAME "fmosc") (ARGUMENTS ("sound_type" "s") ("double" "step") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("sound_type" "s_fm") ("double" "phase")) (TABLE "s") (NOT-IN-INNER-LOOP "s") (STATE ("table_type" "the_table" "sound_to_table(s)") ("double" "table_len" "susp->the_table->length") ("double" "ph_incr" "0") ("sample_type *" "table_ptr" "susp->the_table->samples") ("double" "phase" "compute_phase(phase, step, (long) susp->table_len, s->sr, sr, hz, &susp->ph_incr); s_fm->scale *= hz != 0 ? (sample_type) (susp->ph_incr / hz) : s->sr / (sr * step_to_hz(step))") ) ; cancel 0/0 (ALWAYS-SCALE s_fm) (INLINE-INTERPOLATION T) ; so that modulation can be low frequency (STEP-FUNCTION s_fm) (TERMINATE (MIN s_fm)) (LOGICAL-STOP (MIN s_fm)) (INNER-LOOP-LOCALS " long table_index; double x1; ") (INNER-LOOP "table_index = (long) phase; x1 = table_ptr[table_index]; output = (sample_type) (x1 + (phase - table_index) * (table_ptr[table_index + 1] - x1)); phase += ph_incr + s_fm; while (phase > table_len) phase -= table_len; /* watch out for negative frequencies! */ while (phase < 0) phase += table_len") (CONSTANT "ph_incr" "table_len" "table_ptr" "table") (SAMPLE-RATE "sr") (FINALIZATION " table_unref(susp->the_table); ") ) nyquist-3.05/tran/instrbanded.alg0000644000175000000620000000143411466723256016127 0ustar stevestaff(INSTRBANDED-ALG (NAME "bandedwg") (ARGUMENTS ("double" "freq") ("sound_type" "bowpress_env") ("int" "preset")("rate_type" "sr")) (STATE ("struct instr *" "mybanded" "initInstrument(BANDEDWG, round(sr)); controlChange(susp->mybanded, 16, preset);") ("int" "temp_ret_value" "noteOn(susp->mybanded, freq, 1.0)")) (START (min bowpress_env)) (NOT-IN-INNER-LOOP "freq" "temp_ret_value" "preset") (SAMPLE-RATE "sr") (ALWAYS-SCALE bowpress_env) (TERMINATE (min bowpress_env)) (INNER-LOOP " controlChange(mybanded, 2, BANDEDWG_CONTROL_CHANGE_CONST * bowpress_env); output = (sample_type) tick(mybanded)") (SUPPORT-HEADER " #define BANDEDWG_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->mybanded); ") ) nyquist-3.05/tran/quantize.c0000644000175000000620000001301410144436365015140 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "quantize.h" void quantize_free(); typedef struct quantize_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; double factor; } quantize_susp_node, *quantize_susp_type; void quantize_n_fetch(register quantize_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double factor_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "quantize_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; factor_reg = susp->factor; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register long xx = (long) (*s1_ptr_reg++ * factor_reg); *out_ptr_reg++ = (float) xx;; } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* quantize_n_fetch */ void quantize_toss_fetch(susp, snd_list) register quantize_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void quantize_mark(quantize_susp_type susp) { sound_xlmark(susp->s1); } void quantize_free(quantize_susp_type susp) { sound_unref(susp->s1); ffree_generic(susp, sizeof(quantize_susp_node), "quantize_free"); } void quantize_print_tree(quantize_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_quantize(sound_type s1, long steps) { register quantize_susp_type susp; rate_type sr = s1->sr; time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, quantize_susp_node, "snd_make_quantize"); susp->factor = s1->scale * steps; scale_factor = (sample_type) (1.0 / steps);; susp->susp.fetch = quantize_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = quantize_toss_fetch; } /* initialize susp state */ susp->susp.free = quantize_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = quantize_mark; susp->susp.print_tree = quantize_print_tree; susp->susp.name = "quantize"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_quantize(sound_type s1, long steps) { sound_type s1_copy = sound_copy(s1); return snd_make_quantize(s1_copy, steps); } nyquist-3.05/tran/fmosc.h0000644000175000000620000000047610144436365014424 0ustar stevestaffsound_type snd_make_fmosc(sound_type s, double step, rate_type sr, double hz, time_type t0, sound_type s_fm, double phase); sound_type snd_fmosc(sound_type s, double step, rate_type sr, double hz, time_type t0, sound_type s_fm, double phase); /* LISP: (snd-fmosc SOUND ANYNUM ANYNUM ANYNUM ANYNUM SOUND ANYNUM) */ nyquist-3.05/tran/coterm.c0000644000175000000620000001524510144436365014601 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "coterm.h" void coterm_free(); typedef struct coterm_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type s2; long s2_cnt; sample_block_values_type s2_ptr; } coterm_susp_node, *coterm_susp_type; void coterm_nn_fetch(register coterm_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_block_values_type s2_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "coterm_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the s2 input sample block: */ susp_check_term_log_samples(s2, s2_ptr, s2_cnt); togo = min(togo, susp->s2_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; s2_ptr_reg = susp->s2_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ {sample_type dummy = *s2_ptr_reg++; *out_ptr_reg++ = *s1_ptr_reg++;}; } while (--n); /* inner loop */ /* using s2_ptr_reg is a bad idea on RS/6000: */ susp->s2_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(s2_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* coterm_nn_fetch */ void coterm_toss_fetch(susp, snd_list) register coterm_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from s2 up to final_time for this block of zeros */ while ((round((final_time - susp->s2->t0) * susp->s2->sr)) >= susp->s2->current) susp_get_samples(s2, s2_ptr, s2_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->s2->t0) * susp->s2->sr - (susp->s2->current - susp->s2_cnt)); susp->s2_ptr += n; susp_took(s2_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void coterm_mark(coterm_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->s2); } void coterm_free(coterm_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->s2); ffree_generic(susp, sizeof(coterm_susp_node), "coterm_free"); } void coterm_print_tree(coterm_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("s2:"); sound_print_tree_1(susp->s2, n); } sound_type snd_make_coterm(sound_type s1, sound_type s2) { register coterm_susp_type susp; rate_type sr = max(s1->sr, s2->sr); time_type t0 = max(s1->t0, s2->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; long lsc; /* combine scale factors of linear inputs (S1) */ scale_factor *= s1->scale; s1->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s1->sr < sr) { s1->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, coterm_susp_node, "snd_make_coterm"); susp->susp.fetch = coterm_nn_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < s2->t0) sound_prepend_zeros(s2, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(s2->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = coterm_toss_fetch; } /* initialize susp state */ susp->susp.free = coterm_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = coterm_mark; susp->susp.print_tree = coterm_print_tree; susp->susp.name = "coterm"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); lsc = logical_stop_cnt_cvt(s2); if (susp->susp.log_stop_cnt > lsc) susp->susp.log_stop_cnt = lsc; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->s2 = s2; susp->s2_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_coterm(sound_type s1, sound_type s2) { sound_type s1_copy = sound_copy(s1); sound_type s2_copy = sound_copy(s2); return snd_make_coterm(s1_copy, s2_copy); } nyquist-3.05/tran/tapf.alg0000644000175000000620000000333510144436365014560 0ustar stevestaff(TAPF-ALG (NAME "tapf") (ARGUMENTS ("sound_type" "s1") ("double" "offset") ("sound_type" "vardelay") ("double" "maxdelay")) (INLINE-INTERPOLATION T) (STEP-FUNCTION "vardelay") (INTERNAL-SCALING vardelay) (ALWAYS-SCALE s1) (START (MAX s1 vardelay)) (TERMINATE (MIN s1 vardelay)) (LOGICAL-STOP (MIN s1)) (STATE ("double" "offset" "offset * s1->sr") ("double" "vdscale" "vardelay->scale * s1->sr") ("long" "maxdelay" "(long)(maxdelay * s1->sr)") ("long" "bufflen" "max(2, (long) (susp->maxdelay + 0.5))") ("long" "index" "susp->bufflen") ("sample_type *" "buffer" "(sample_type *) calloc(susp->bufflen + 1, sizeof(sample_type))")) (SAMPLE-RATE (MAX s1)) (CONSTANT "maxdelay" "offset" "vdscale" "buffer") (INNER-LOOP-LOCALS " long phase; ") (INNER-LOOP " phase = (long) (vardelay * vdscale + offset); /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay) phase = maxdelay; phase = index - phase; /* now phase is a location in the buffer (before modulo) */ /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer[index++] = s1; if (index >= bufflen) { index = 0; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen; output = (sample_type) (buffer[phase]);") (FINALIZATION " free(susp->buffer); ") ) nyquist-3.05/tran/stkpitshift.h0000644000175000000620000000035011466723256015666 0ustar stevestaffsound_type snd_make_stkpitshift(sound_type s1, double shift, double mix, rate_type sr); sound_type snd_stkpitshift(sound_type s1, double shift, double mix, rate_type sr); /* LISP: (snd-stkpitshift SOUND ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/instrflutefreq.h0000644000175000000620000000046111466723256016372 0ustar stevestaffsound_type snd_make_flute_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr); sound_type snd_flute_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr); /* LISP: (snd-flute_freq ANYNUM SOUND SOUND ANYNUM) */ #define FLUTE_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/instrsaxall.h0000644000175000000620000000114010144436365015646 0ustar stevestaffsound_type snd_make_sax_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, sound_type blow_pos, sound_type reed_table_offset, rate_type sr); sound_type snd_sax_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, sound_type blow_pos, sound_type reed_table_offset, rate_type sr); /* LISP: (snd-sax_all ANYNUM SOUND SOUND ANYNUM ANYNUM SOUND SOUND SOUND SOUND ANYNUM) */ #define SAX_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/siosc.alg0000644000175000000620000001060011466723256014745 0ustar stevestaff(SIOSC-ALG (NAME "siosc") ; wave tables are provided in the argument "lis" as follows: ; (tab0 t1 tab1 t2 tab2 t3 tab3 ... tN tabN) ; where tab0 is the initial table, the table is linearly interpolated until ; sample t1, at which point the table is tab1. From there, tab1 is interpolated ; to tab2 at t2, etc. The sound stops at the terminate time of s_fm, so ; if that comes before tN, tabN is used for the remainder of the sound. ; t1, t2, ... tN are fixnums with sample counts (ARGUMENTS ("LVAL" "lis") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("sound_type" "s_fm")) (SUPPORT-FUNCTIONS " /* sisosc_table_init -- set up first two tables for interpolation */ /**/ void siosc_table_init(siosc_susp_type susp) { sound_type snd; if (!susp->lis) xlfail(\"bad table list in SIOSC\"); snd = getsound(car(susp->lis)); susp->table_b_ptr_ptr = sound_to_table(snd); susp->table_b_samps = susp->table_b_ptr_ptr->samples; susp->lis = cdr(susp->lis); susp->table_sr = snd->sr; susp->table_len = susp->table_b_ptr_ptr->length; } /* siosc_table_update -- outer loop processing, get next table */ /**/ long siosc_table_update(siosc_susp_type susp, long cur) { long n; /* swap ampramps: */ susp->ampramp_a = 1.0; susp->ampramp_b = 0.0; /* swap tables: */ table_unref(susp->table_a_ptr); susp->table_a_ptr = susp->table_b_ptr_ptr; susp->table_a_samps = susp->table_b_samps; susp->table_b_ptr_ptr = NULL; /* so we do not try to unref it */ if (susp->lis) { sound_type snd; /* compute slope */ susp->next_breakpoint = getfixnum(car(susp->lis)); susp->lis = cdr(susp->lis); n = susp->next_breakpoint - cur; susp->ampslope = 1.0 / n; /* build new table: */ if (!susp->lis) xlfail(\"bad table list in SIOSC\"); snd = getsound(car(susp->lis)); susp->table_b_ptr_ptr = sound_to_table(snd); susp->table_b_samps = susp->table_b_ptr_ptr->samples; if (susp->table_b_ptr_ptr->length != susp->table_len || susp->table_sr != snd->sr) xlfail(\"mismatched tables passed to SIOSC\") ; susp->lis = cdr(susp->lis); } else { /* use only table a */ susp->ampslope = 0.0; susp->next_breakpoint = 0x7FFFFFFF; n = 0x7FFFFFFF; } return n; } ") (STATE ("double" "table_len" "0.0") ("double" "ph_incr" "0.0") ("table_type" "table_a_ptr" "NULL") ("table_type" "table_b_ptr_ptr" "NULL") ("sample_type *" "table_a_samps" "NULL") ("sample_type *" "table_b_samps" "NULL") ("double" "table_sr" "0.0") ("double" "phase" "0.0") ("LVAL" "lis" "lis") ("long" "next_breakpoint" "0") ("double" "ampramp_a" "1.0") ("double" "ampramp_b" "0.0") ("double" "ampslope" "0.0; siosc_table_init(susp); susp->ph_incr = hz * susp->table_len / sr; s_fm->scale = (sample_type) (s_fm->scale * (susp->table_len / sr))") ) (ALWAYS-SCALE s_fm) (INLINE-INTERPOLATION T) ; so that modulation can be low frequency (STEP-FUNCTION s_fm) (TERMINATE (MIN s_fm)) (LOGICAL-STOP (MIN s_fm)) (INNER-LOOP-LOCALS " long table_index; double xa, xb; ") ; Implementation notes: ; "lis" points to the next time to be used, or NULL (OUTER-LOOP " { long cur = susp->susp.current + cnt; n = susp->next_breakpoint - cur; if (n == 0) n = siosc_table_update(susp, cur); } togo = min(n, togo); ") (INNER-LOOP " table_index = (long) phase; xa = table_a_samps[table_index]; xb = table_b_samps[table_index]; output = (sample_type) (ampramp_a * (xa + (phase - table_index) * (table_a_samps[table_index + 1] - xa)) + ampramp_b * (xb + (phase - table_index) * (table_b_samps[table_index + 1] - xb))); ampramp_a -= ampslope; ampramp_b += ampslope; phase += ph_incr + s_fm; while (phase > table_len) phase -= table_len; /* watch out for negative frequencies! */ while (phase < 0) phase += table_len") (CONSTANT "ph_incr" "table_len" "table_ptr" "table_a_samps" "table_b_samps" "ampslope" "table_a_ptr" "table_b_ptr_ptr") (SAMPLE-RATE "sr") (FINALIZATION " table_unref(susp->table_a_ptr); table_unref(susp->table_b_ptr_ptr); ") ) nyquist-3.05/tran/sine.alg0000644000175000000620000000160410144436365014561 0ustar stevestaff(SINE-ALG (NAME "sine") (ARGUMENTS ("time_type" "t0") ("double" "hz") ("rate_type" "sr") ("time_type" "d")) (STATE ("long" "phase" "0") ("long" "ph_incr" "round(((hz * SINE_TABLE_LEN) * (1 << SINE_TABLE_SHIFT) / sr))")) (TERMINATE (AFTER "d")) (INNER-LOOP "output = sine_table[phase >> SINE_TABLE_SHIFT]; phase += ph_incr; phase &= SINE_TABLE_MASK;") (MAINTAIN ("phase" "susp->phase = (susp->phase + susp->ph_incr * togo) & SINE_TABLE_MASK")) (CONSTANT "ph_incr") (SAMPLE-RATE "sr") (SUPPORT-HEADER "#define SINE_TABLE_LEN 2048 #define SINE_TABLE_MASK 0x7FFFFFFF #define SINE_TABLE_SHIFT 20 void sine_init(); extern sample_type sine_table[]; ") (SUPPORT-FUNCTIONS " sample_type sine_table[SINE_TABLE_LEN + 1]; void sine_init() { int i; for (i = 0; i <= SINE_TABLE_LEN; i++) sine_table[i] = (sample_type) (sin((PI * 2 * i) / SINE_TABLE_LEN)); } ") ) nyquist-3.05/tran/instrclarall.c0000644000175000000620000002411210144436365015773 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrclarall.h" void clarinet_all_free(); typedef struct clarinet_all_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; sound_type reed_stiffness; long reed_stiffness_cnt; sample_block_values_type reed_stiffness_ptr; sound_type noise; long noise_cnt; sample_block_values_type noise_ptr; struct instr *clar; double frequency; } clarinet_all_susp_node, *clarinet_all_susp_type; #include "instr.h" void clarinet_all_ssss_fetch(register clarinet_all_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * clar_reg; register double frequency_reg; register sample_type noise_scale_reg = susp->noise->scale; register sample_block_values_type noise_ptr_reg; register sample_type reed_stiffness_scale_reg = susp->reed_stiffness->scale; register sample_block_values_type reed_stiffness_ptr_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "clarinet_all_ssss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past the reed_stiffness input sample block: */ susp_check_samples(reed_stiffness, reed_stiffness_ptr, reed_stiffness_cnt); togo = min(togo, susp->reed_stiffness_cnt); /* don't run past the noise input sample block: */ susp_check_samples(noise, noise_ptr, noise_cnt); togo = min(togo, susp->noise_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; clar_reg = susp->clar; frequency_reg = susp->frequency; noise_ptr_reg = susp->noise_ptr; reed_stiffness_ptr_reg = susp->reed_stiffness_ptr; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(clar_reg, 128, CLAR_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); controlChange(clar_reg, 2, CLAR_CONTROL_CHANGE_CONST * (reed_stiffness_scale_reg * *reed_stiffness_ptr_reg++)); controlChange(clar_reg, 4, CLAR_CONTROL_CHANGE_CONST * (noise_scale_reg * *noise_ptr_reg++)); setFrequency(clar_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(clar_reg); } while (--n); /* inner loop */ susp->clar = clar_reg; /* using noise_ptr_reg is a bad idea on RS/6000: */ susp->noise_ptr += togo; /* using reed_stiffness_ptr_reg is a bad idea on RS/6000: */ susp->reed_stiffness_ptr += togo; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); susp_took(reed_stiffness_cnt, togo); susp_took(noise_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* clarinet_all_ssss_fetch */ void clarinet_all_toss_fetch(susp, snd_list) register clarinet_all_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* fetch samples from reed_stiffness up to final_time for this block of zeros */ while ((round((final_time - susp->reed_stiffness->t0) * susp->reed_stiffness->sr)) >= susp->reed_stiffness->current) susp_get_samples(reed_stiffness, reed_stiffness_ptr, reed_stiffness_cnt); /* fetch samples from noise up to final_time for this block of zeros */ while ((round((final_time - susp->noise->t0) * susp->noise->sr)) >= susp->noise->current) susp_get_samples(noise, noise_ptr, noise_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); n = round((final_time - susp->reed_stiffness->t0) * susp->reed_stiffness->sr - (susp->reed_stiffness->current - susp->reed_stiffness_cnt)); susp->reed_stiffness_ptr += n; susp_took(reed_stiffness_cnt, n); n = round((final_time - susp->noise->t0) * susp->noise->sr - (susp->noise->current - susp->noise_cnt)); susp->noise_ptr += n; susp_took(noise_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void clarinet_all_mark(clarinet_all_susp_type susp) { sound_xlmark(susp->breath_env); sound_xlmark(susp->freq_env); sound_xlmark(susp->reed_stiffness); sound_xlmark(susp->noise); } void clarinet_all_free(clarinet_all_susp_type susp) { deleteInstrument(susp->clar); sound_unref(susp->breath_env); sound_unref(susp->freq_env); sound_unref(susp->reed_stiffness); sound_unref(susp->noise); ffree_generic(susp, sizeof(clarinet_all_susp_node), "clarinet_all_free"); } void clarinet_all_print_tree(clarinet_all_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); indent(n); stdputstr("reed_stiffness:"); sound_print_tree_1(susp->reed_stiffness, n); indent(n); stdputstr("noise:"); sound_print_tree_1(susp->noise, n); } sound_type snd_make_clarinet_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, rate_type sr) { register clarinet_all_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, clarinet_all_susp_node, "snd_make_clarinet_all"); susp->clar = initInstrument(CLARINET, round(sr)); noteOn(susp->clar, freq, 1.0); controlChange(susp->clar, 11, CLAR_CONTROL_CHANGE_CONST * vibrato_freq); controlChange(susp->clar, 1, CLAR_CONTROL_CHANGE_CONST * vibrato_gain);; susp->frequency = freq; susp->susp.fetch = clarinet_all_ssss_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); if (t0 < reed_stiffness->t0) sound_prepend_zeros(reed_stiffness, t0); if (t0 < noise->t0) sound_prepend_zeros(noise, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, min(freq_env->t0, min(reed_stiffness->t0, min(noise->t0, t0)))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = clarinet_all_toss_fetch; } /* initialize susp state */ susp->susp.free = clarinet_all_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = clarinet_all_mark; susp->susp.print_tree = clarinet_all_print_tree; susp->susp.name = "clarinet_all"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; susp->reed_stiffness = reed_stiffness; susp->reed_stiffness_cnt = 0; susp->noise = noise; susp->noise_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_clarinet_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); sound_type freq_env_copy = sound_copy(freq_env); sound_type reed_stiffness_copy = sound_copy(reed_stiffness); sound_type noise_copy = sound_copy(noise); return snd_make_clarinet_all(freq, breath_env_copy, freq_env_copy, vibrato_freq, vibrato_gain, reed_stiffness_copy, noise_copy, sr); } nyquist-3.05/tran/instrmodalbar.alg0000644000175000000620000000112411466723256016467 0ustar stevestaff(INSTRMODALBAR-ALG (NAME "modalbar") (ARGUMENTS ("time_type" "t0")("double" "freq") ("int" "preset")("time_type" "dur") ("rate_type" "sr")) (STATE ("struct instr *" "mymbar" "initInstrument(MODALBAR, round(sr)); controlChange(susp->mymbar, 16, preset);") ("int" "temp_ret_value" "noteOn(susp->mymbar, freq, 1.0);")) (NOT-IN-INNER-LOOP "freq" "temp_ret_value") (SAMPLE-RATE "sr") (TERMINATE (after "dur")) (INNER-LOOP " output = (sample_type) tick(mymbar)") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->mymbar); ") ) nyquist-3.05/tran/congen.h0000644000175000000620000000031410144436365014555 0ustar stevestaffsound_type snd_make_congen(sound_type sndin, double risetime, double falltime); sound_type snd_congen(sound_type sndin, double risetime, double falltime); /* LISP: (snd-congen SOUND ANYNUM ANYNUM) */ nyquist-3.05/tran/instrclarall.alg0000644000175000000620000000316310144436365016317 0ustar stevestaff(INSTRCLAR-COMPLETE-ALG ;; parameters are: ;; freq_env -- frequency modulation, aftertouch 128 ;; breath_env -- amplitude envelope, aftertouch 128 ;; vibrato_freq -- vibrato frequency, ModFreq 11 ;; vibrato_gain -- vibrato gain, ModWheel 1 ;; reed_stiffness -- reed stiffness, ReedStiff 2 ;; noise -- noise, Noise 4 ;; (NAME "clarinet_all") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("sound_type" "freq_env") ("double" "vibrato_freq") ("double" "vibrato_gain") ("sound_type" "reed_stiffness") ("sound_type" "noise") ("rate_type" "sr")) ;; use a constant rate of 1.0 because it will actually be conrolled ;; by breath_env (STATE ("struct instr *" "clar" "initInstrument(CLARINET, round(sr)); noteOn(susp->clar, freq, 1.0); controlChange(susp->clar, 11, CLAR_CONTROL_CHANGE_CONST * vibrato_freq); controlChange(susp->clar, 1, CLAR_CONTROL_CHANGE_CONST * vibrato_gain);") ("double" "frequency" "freq")) (START (min breath_env)) (MATCHED-SAMPLE-RATE freq_env breath_env reed_stiffness noise) (ALWAYS-SCALE freq_env breath_env reed_stiffness noise) (CONSTANT "frequency") (SAMPLE-RATE "sr") (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(clar, 128, CLAR_CONTROL_CHANGE_CONST * breath_env); controlChange(clar, 2, CLAR_CONTROL_CHANGE_CONST * reed_stiffness); controlChange(clar, 4, CLAR_CONTROL_CHANGE_CONST * noise); setFrequency(clar, frequency + freq_env); output = (sample_type) tick(clar)") (SUPPORT-HEADER " #define CLAR_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->clar); ") ) nyquist-3.05/tran/instrbowedfreq.c0000644000175000000620000002314311466723256016350 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrbowedfreq.h" void bowed_freq_free(); typedef struct bowed_freq_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type bowpress_env; long bowpress_env_cnt; sample_block_values_type bowpress_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; struct instr *mybow; int temp_ret_value; double frequency; } bowed_freq_susp_node, *bowed_freq_susp_type; #include "instr.h" void bowed_freq_nn_fetch(register bowed_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mybow_reg; register double frequency_reg; register sample_block_values_type freq_env_ptr_reg; register sample_block_values_type bowpress_env_ptr_reg; falloc_sample_block(out, "bowed_freq_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the bowpress_env input sample block: */ susp_check_term_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); togo = min(togo, susp->bowpress_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mybow_reg = susp->mybow; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; bowpress_env_ptr_reg = susp->bowpress_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(mybow_reg, 128, BOW_CONTROL_CHANGE_CONST * *bowpress_env_ptr_reg++); setFrequency(mybow_reg, frequency_reg + *freq_env_ptr_reg++); *out_ptr_reg++ = (sample_type) tick(mybow_reg); } while (--n); /* inner loop */ susp->mybow = mybow_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using bowpress_env_ptr_reg is a bad idea on RS/6000: */ susp->bowpress_env_ptr += togo; out_ptr += togo; susp_took(bowpress_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* bowed_freq_nn_fetch */ void bowed_freq_ss_fetch(register bowed_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mybow_reg; register double frequency_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type bowpress_env_scale_reg = susp->bowpress_env->scale; register sample_block_values_type bowpress_env_ptr_reg; falloc_sample_block(out, "bowed_freq_ss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the bowpress_env input sample block: */ susp_check_term_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); togo = min(togo, susp->bowpress_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mybow_reg = susp->mybow; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; bowpress_env_ptr_reg = susp->bowpress_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(mybow_reg, 128, BOW_CONTROL_CHANGE_CONST * (bowpress_env_scale_reg * *bowpress_env_ptr_reg++)); setFrequency(mybow_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(mybow_reg); } while (--n); /* inner loop */ susp->mybow = mybow_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using bowpress_env_ptr_reg is a bad idea on RS/6000: */ susp->bowpress_env_ptr += togo; out_ptr += togo; susp_took(bowpress_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* bowed_freq_ss_fetch */ void bowed_freq_toss_fetch(susp, snd_list) register bowed_freq_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from bowpress_env up to final_time for this block of zeros */ while ((round((final_time - susp->bowpress_env->t0) * susp->bowpress_env->sr)) >= susp->bowpress_env->current) susp_get_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->bowpress_env->t0) * susp->bowpress_env->sr - (susp->bowpress_env->current - susp->bowpress_env_cnt)); susp->bowpress_env_ptr += n; susp_took(bowpress_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void bowed_freq_mark(bowed_freq_susp_type susp) { sound_xlmark(susp->bowpress_env); sound_xlmark(susp->freq_env); } void bowed_freq_free(bowed_freq_susp_type susp) { deleteInstrument(susp->mybow); sound_unref(susp->bowpress_env); sound_unref(susp->freq_env); ffree_generic(susp, sizeof(bowed_freq_susp_node), "bowed_freq_free"); } void bowed_freq_print_tree(bowed_freq_susp_type susp, int n) { indent(n); stdputstr("bowpress_env:"); sound_print_tree_1(susp->bowpress_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); } sound_type snd_make_bowed_freq(double freq, sound_type bowpress_env, sound_type freq_env, rate_type sr) { register bowed_freq_susp_type susp; /* sr specified as input parameter */ time_type t0 = bowpress_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, bowed_freq_susp_node, "snd_make_bowed_freq"); susp->mybow = initInstrument(BOWED, round(sr)); controlChange(susp->mybow, 1, 0.0);; susp->temp_ret_value = noteOn(susp->mybow, freq, 1.0); susp->frequency = freq; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(bowpress_env, sr); interp_desc = (interp_desc << 2) + interp_style(freq_env, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = bowed_freq_nn_fetch; break; case INTERP_ss: susp->susp.fetch = bowed_freq_ss_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < bowpress_env->t0) sound_prepend_zeros(bowpress_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); /* minimum start time over all inputs: */ t0_min = min(bowpress_env->t0, min(freq_env->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = bowed_freq_toss_fetch; } /* initialize susp state */ susp->susp.free = bowed_freq_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = bowed_freq_mark; susp->susp.print_tree = bowed_freq_print_tree; susp->susp.name = "bowed_freq"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->bowpress_env = bowpress_env; susp->bowpress_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_bowed_freq(double freq, sound_type bowpress_env, sound_type freq_env, rate_type sr) { sound_type bowpress_env_copy = sound_copy(bowpress_env); sound_type freq_env_copy = sound_copy(freq_env); return snd_make_bowed_freq(freq, bowpress_env_copy, freq_env_copy, sr); } nyquist-3.05/tran/slope.alg0000644000175000000620000000062710144436365014751 0ustar stevestaff(SLOPE-ALG (NAME "slope") (ARGUMENTS ("sound_type" "input")) (STATE ("sample_type" "prev" "0.0F") ("double" "scale" "input->sr * input->scale")) (INTERNAL-SCALING input) (CONSTANT "scale") (DELAY 1) (START (MIN input)) (INNER-LOOP "{ register sample_type x = input; output = (sample_type) ((x - prev) * scale); prev = x;}") (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) ) nyquist-3.05/tran/buzz.c0000644000175000000620000004104311466723256014303 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "buzz.h" void buzz_free(); typedef struct buzz_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s_fm; long s_fm_cnt; sample_block_values_type s_fm_ptr; /* support for interpolation of s_fm */ sample_type s_fm_x1_sample; double s_fm_pHaSe; double s_fm_pHaSe_iNcR; /* support for ramp between samples of s_fm */ double output_per_s_fm; long s_fm_n; double ph_incr; float n_2_r; float n_2_p1; double phase; } buzz_susp_node, *buzz_susp_type; #include "sine.h" void buzz_s_fetch(register buzz_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double ph_incr_reg; register float n_2_r_reg; register float n_2_p1_reg; register double phase_reg; register sample_type s_fm_scale_reg = susp->s_fm->scale; register sample_block_values_type s_fm_ptr_reg; falloc_sample_block(out, "buzz_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s_fm input sample block: */ susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); togo = min(togo, susp->s_fm_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; ph_incr_reg = susp->ph_incr; n_2_r_reg = susp->n_2_r; n_2_p1_reg = susp->n_2_p1; phase_reg = susp->phase; s_fm_ptr_reg = susp->s_fm_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; sample_type num, denom, samp; table_index = (long) phase_reg; x1 = sine_table[table_index]; denom = (sample_type) (x1 + (phase_reg - table_index) * (sine_table[table_index + 1] - x1)); if (denom < 0.001 && denom > -0.005) { samp = 1.0F; } else { double phn2p1 = phase_reg * n_2_p1_reg * (1.0/SINE_TABLE_LEN); phn2p1 = (phn2p1 - (long) phn2p1) * SINE_TABLE_LEN; table_index = (long) phn2p1; x1 = sine_table[table_index]; num = (sample_type) (x1 + (phn2p1 - table_index) * (sine_table[table_index + 1] - x1)); samp = ((num / denom) - 1.0F) * n_2_r_reg; } *out_ptr_reg++ = samp; phase_reg += ph_incr_reg + (s_fm_scale_reg * *s_fm_ptr_reg++); while (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += SINE_TABLE_LEN; } while (--n); /* inner loop */ susp->phase = phase_reg; /* using s_fm_ptr_reg is a bad idea on RS/6000: */ susp->s_fm_ptr += togo; out_ptr += togo; susp_took(s_fm_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* buzz_s_fetch */ void buzz_i_fetch(register buzz_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double ph_incr_reg; register float n_2_r_reg; register float n_2_p1_reg; register double phase_reg; register double s_fm_pHaSe_iNcR_rEg = susp->s_fm_pHaSe_iNcR; register double s_fm_pHaSe_ReG; register sample_type s_fm_x1_sample_reg; falloc_sample_block(out, "buzz_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; ph_incr_reg = susp->ph_incr; n_2_r_reg = susp->n_2_r; n_2_p1_reg = susp->n_2_p1; phase_reg = susp->phase; s_fm_pHaSe_ReG = susp->s_fm_pHaSe; s_fm_x1_sample_reg = susp->s_fm_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; sample_type num, denom, samp; if (s_fm_pHaSe_ReG >= 1.0) { /* fixup-depends s_fm */ /* pick up next sample as s_fm_x1_sample: */ susp->s_fm_ptr++; susp_took(s_fm_cnt, 1); s_fm_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(s_fm, s_fm_ptr, s_fm_cnt, s_fm_x1_sample_reg); s_fm_x1_sample_reg = susp_current_sample(s_fm, s_fm_ptr); } table_index = (long) phase_reg; x1 = sine_table[table_index]; denom = (sample_type) (x1 + (phase_reg - table_index) * (sine_table[table_index + 1] - x1)); if (denom < 0.001 && denom > -0.005) { samp = 1.0F; } else { double phn2p1 = phase_reg * n_2_p1_reg * (1.0/SINE_TABLE_LEN); phn2p1 = (phn2p1 - (long) phn2p1) * SINE_TABLE_LEN; table_index = (long) phn2p1; x1 = sine_table[table_index]; num = (sample_type) (x1 + (phn2p1 - table_index) * (sine_table[table_index + 1] - x1)); samp = ((num / denom) - 1.0F) * n_2_r_reg; } *out_ptr_reg++ = samp; phase_reg += ph_incr_reg + s_fm_x1_sample_reg; while (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += SINE_TABLE_LEN; s_fm_pHaSe_ReG += s_fm_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->phase = phase_reg; susp->s_fm_pHaSe = s_fm_pHaSe_ReG; susp->s_fm_x1_sample = s_fm_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* buzz_i_fetch */ void buzz_r_fetch(register buzz_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type s_fm_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double ph_incr_reg; register float n_2_r_reg; register float n_2_p1_reg; register double phase_reg; falloc_sample_block(out, "buzz_r_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->s_fm_pHaSe = 1.0; } susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* grab next s_fm_x1_sample when phase goes past 1.0; */ /* use s_fm_n (computed below) to avoid roundoff errors: */ if (susp->s_fm_n <= 0) { susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_pHaSe -= 1.0; /* s_fm_n gets number of samples before phase exceeds 1.0: */ susp->s_fm_n = (long) ((1.0 - susp->s_fm_pHaSe) * susp->output_per_s_fm); } togo = min(togo, susp->s_fm_n); s_fm_val = susp->s_fm_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; ph_incr_reg = susp->ph_incr; n_2_r_reg = susp->n_2_r; n_2_p1_reg = susp->n_2_p1; phase_reg = susp->phase; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; sample_type num, denom, samp; table_index = (long) phase_reg; x1 = sine_table[table_index]; denom = (sample_type) (x1 + (phase_reg - table_index) * (sine_table[table_index + 1] - x1)); if (denom < 0.001 && denom > -0.005) { samp = 1.0F; } else { double phn2p1 = phase_reg * n_2_p1_reg * (1.0/SINE_TABLE_LEN); phn2p1 = (phn2p1 - (long) phn2p1) * SINE_TABLE_LEN; table_index = (long) phn2p1; x1 = sine_table[table_index]; num = (sample_type) (x1 + (phn2p1 - table_index) * (sine_table[table_index + 1] - x1)); samp = ((num / denom) - 1.0F) * n_2_r_reg; } *out_ptr_reg++ = samp; phase_reg += ph_incr_reg + s_fm_val; while (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += SINE_TABLE_LEN; } while (--n); /* inner loop */ susp->phase = phase_reg; out_ptr += togo; susp->s_fm_pHaSe += togo * susp->s_fm_pHaSe_iNcR; susp->s_fm_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* buzz_r_fetch */ void buzz_toss_fetch(susp, snd_list) register buzz_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s_fm up to final_time for this block of zeros */ while ((round((final_time - susp->s_fm->t0) * susp->s_fm->sr)) >= susp->s_fm->current) susp_get_samples(s_fm, s_fm_ptr, s_fm_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s_fm->t0) * susp->s_fm->sr - (susp->s_fm->current - susp->s_fm_cnt)); susp->s_fm_ptr += n; susp_took(s_fm_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void buzz_mark(buzz_susp_type susp) { sound_xlmark(susp->s_fm); } void buzz_free(buzz_susp_type susp) { sound_unref(susp->s_fm); ffree_generic(susp, sizeof(buzz_susp_node), "buzz_free"); } void buzz_print_tree(buzz_susp_type susp, int n) { indent(n); stdputstr("s_fm:"); sound_print_tree_1(susp->s_fm, n); } sound_type snd_make_buzz(long n, rate_type sr, double hz, time_type t0, sound_type s_fm) { register buzz_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, buzz_susp_node, "snd_make_buzz"); susp->ph_incr = 0; susp->n_2_r = 1.0F / (n * 2); susp->n_2_p1 = (n * 2) + 1; susp->phase = compute_phase(PI*0.5, 69.0, SINE_TABLE_LEN, SINE_TABLE_LEN * 440.0, sr, hz * 0.5, &susp->ph_incr); s_fm->scale *= hz != 0 ? (sample_type) (susp->ph_incr / hz) : (sample_type) (SINE_TABLE_LEN * 0.5 / sr); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s_fm, sr); switch (interp_desc) { case INTERP_n: /* handled below */ case INTERP_s: susp->susp.fetch = buzz_s_fetch; break; case INTERP_i: susp->susp.fetch = buzz_i_fetch; break; case INTERP_r: susp->susp.fetch = buzz_r_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s_fm->t0) sound_prepend_zeros(s_fm, t0); /* minimum start time over all inputs: */ t0_min = min(s_fm->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = buzz_toss_fetch; } /* initialize susp state */ susp->susp.free = buzz_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = buzz_mark; susp->susp.print_tree = buzz_print_tree; susp->susp.name = "buzz"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s_fm); susp->started = false; susp->susp.current = 0; susp->s_fm = s_fm; susp->s_fm_cnt = 0; susp->s_fm_pHaSe = 0.0; susp->s_fm_pHaSe_iNcR = s_fm->sr / sr; susp->s_fm_n = 0; susp->output_per_s_fm = sr / s_fm->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_buzz(long n, rate_type sr, double hz, time_type t0, sound_type s_fm) { sound_type s_fm_copy = sound_copy(s_fm); return snd_make_buzz(n, sr, hz, t0, s_fm_copy); } nyquist-3.05/tran/delaycv.h0000644000175000000620000000031610144436365014735 0ustar stevestaffsound_type snd_make_delaycv(sound_type s, time_type delay, sound_type feedback); sound_type snd_delaycv(sound_type s, time_type delay, sound_type feedback); /* LISP: (snd-delaycv SOUND ANYNUM SOUND) */ nyquist-3.05/tran/sampler.c0000644000175000000620000003732310144436365014754 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "sampler.h" void sampler_free(); typedef struct sampler_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s_fm; long s_fm_cnt; sample_block_values_type s_fm_ptr; /* support for interpolation of s_fm */ sample_type s_fm_x1_sample; double s_fm_pHaSe; double s_fm_pHaSe_iNcR; /* support for ramp between samples of s_fm */ double output_per_s_fm; long s_fm_n; double loop_to; table_type the_table; sample_type *table_ptr; double table_len; double phase; double ph_incr; } sampler_susp_node, *sampler_susp_type; void sampler_s_fetch(register sampler_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double loop_to_reg; register sample_type * table_ptr_reg; register double table_len_reg; register double phase_reg; register double ph_incr_reg; register sample_type s_fm_scale_reg = susp->s_fm->scale; register sample_block_values_type s_fm_ptr_reg; falloc_sample_block(out, "sampler_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s_fm input sample block: */ susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); togo = min(togo, susp->s_fm_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; loop_to_reg = susp->loop_to; table_ptr_reg = susp->table_ptr; table_len_reg = susp->table_len; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; s_fm_ptr_reg = susp->s_fm_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; table_index = (long) phase_reg; x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg + (s_fm_scale_reg * *s_fm_ptr_reg++); while (phase_reg > table_len_reg) phase_reg -= (table_len_reg - loop_to_reg); /* watch out for negative frequencies! */ if (phase_reg < 0) phase_reg = 0; } while (--n); /* inner loop */ susp->phase = phase_reg; /* using s_fm_ptr_reg is a bad idea on RS/6000: */ susp->s_fm_ptr += togo; out_ptr += togo; susp_took(s_fm_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* sampler_s_fetch */ void sampler_i_fetch(register sampler_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double loop_to_reg; register sample_type * table_ptr_reg; register double table_len_reg; register double phase_reg; register double ph_incr_reg; register double s_fm_pHaSe_iNcR_rEg = susp->s_fm_pHaSe_iNcR; register double s_fm_pHaSe_ReG; register sample_type s_fm_x1_sample_reg; falloc_sample_block(out, "sampler_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; loop_to_reg = susp->loop_to; table_ptr_reg = susp->table_ptr; table_len_reg = susp->table_len; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; s_fm_pHaSe_ReG = susp->s_fm_pHaSe; s_fm_x1_sample_reg = susp->s_fm_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; if (s_fm_pHaSe_ReG >= 1.0) { /* fixup-depends s_fm */ /* pick up next sample as s_fm_x1_sample: */ susp->s_fm_ptr++; susp_took(s_fm_cnt, 1); s_fm_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(s_fm, s_fm_ptr, s_fm_cnt, s_fm_x1_sample_reg); s_fm_x1_sample_reg = susp_current_sample(s_fm, s_fm_ptr); } table_index = (long) phase_reg; x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg + s_fm_x1_sample_reg; while (phase_reg > table_len_reg) phase_reg -= (table_len_reg - loop_to_reg); /* watch out for negative frequencies! */ if (phase_reg < 0) phase_reg = 0; s_fm_pHaSe_ReG += s_fm_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->phase = phase_reg; susp->s_fm_pHaSe = s_fm_pHaSe_ReG; susp->s_fm_x1_sample = s_fm_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* sampler_i_fetch */ void sampler_r_fetch(register sampler_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type s_fm_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double loop_to_reg; register sample_type * table_ptr_reg; register double table_len_reg; register double phase_reg; register double ph_incr_reg; falloc_sample_block(out, "sampler_r_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->s_fm_pHaSe = 1.0; } susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* grab next s_fm_x1_sample when phase goes past 1.0; */ /* use s_fm_n (computed below) to avoid roundoff errors: */ if (susp->s_fm_n <= 0) { susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_pHaSe -= 1.0; /* s_fm_n gets number of samples before phase exceeds 1.0: */ susp->s_fm_n = (long) ((1.0 - susp->s_fm_pHaSe) * susp->output_per_s_fm); } togo = min(togo, susp->s_fm_n); s_fm_val = susp->s_fm_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; loop_to_reg = susp->loop_to; table_ptr_reg = susp->table_ptr; table_len_reg = susp->table_len; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; table_index = (long) phase_reg; x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg + s_fm_val; while (phase_reg > table_len_reg) phase_reg -= (table_len_reg - loop_to_reg); /* watch out for negative frequencies! */ if (phase_reg < 0) phase_reg = 0; } while (--n); /* inner loop */ susp->phase = phase_reg; out_ptr += togo; susp->s_fm_pHaSe += togo * susp->s_fm_pHaSe_iNcR; susp->s_fm_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* sampler_r_fetch */ void sampler_toss_fetch(susp, snd_list) register sampler_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s_fm up to final_time for this block of zeros */ while ((round((final_time - susp->s_fm->t0) * susp->s_fm->sr)) >= susp->s_fm->current) susp_get_samples(s_fm, s_fm_ptr, s_fm_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s_fm->t0) * susp->s_fm->sr - (susp->s_fm->current - susp->s_fm_cnt)); susp->s_fm_ptr += n; susp_took(s_fm_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void sampler_mark(sampler_susp_type susp) { sound_xlmark(susp->s_fm); } void sampler_free(sampler_susp_type susp) { table_unref(susp->the_table); sound_unref(susp->s_fm); ffree_generic(susp, sizeof(sampler_susp_node), "sampler_free"); } void sampler_print_tree(sampler_susp_type susp, int n) { indent(n); stdputstr("s_fm:"); sound_print_tree_1(susp->s_fm, n); } sound_type snd_make_sampler(sound_type s, double step, double loop_start, rate_type sr, double hz, time_type t0, sound_type s_fm, long npoints) { register sampler_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, sampler_susp_node, "snd_make_sampler"); susp->loop_to = loop_start * s->sr; susp->the_table = sound_to_table(s); susp->table_ptr = susp->the_table->samples; susp->table_len = susp->the_table->length; { long index = (long) susp->loop_to; double frac = susp->loop_to - index; if (index > round(susp->table_len) || index < 0) { index = 0; frac = 0; } susp->table_ptr[round(susp->table_len)] = /* copy interpolated start to last entry */ (sample_type) (susp->table_ptr[index] * (1.0 - frac) + susp->table_ptr[index + 1] * frac);}; susp->phase = 0.0; susp->ph_incr = (s->sr / sr) * hz / step_to_hz(step); s_fm->scale = (sample_type) (s_fm->scale * (susp->ph_incr / hz)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s_fm, sr); switch (interp_desc) { case INTERP_n: /* handled below */ case INTERP_s: susp->susp.fetch = sampler_s_fetch; break; case INTERP_i: susp->susp.fetch = sampler_i_fetch; break; case INTERP_r: susp->susp.fetch = sampler_r_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s_fm->t0) sound_prepend_zeros(s_fm, t0); /* minimum start time over all inputs: */ t0_min = min(s_fm->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = sampler_toss_fetch; } /* initialize susp state */ susp->susp.free = sampler_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = sampler_mark; susp->susp.print_tree = sampler_print_tree; susp->susp.name = "sampler"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s_fm); susp->started = false; susp->susp.current = 0; susp->s_fm = s_fm; susp->s_fm_cnt = 0; susp->s_fm_pHaSe = 0.0; susp->s_fm_pHaSe_iNcR = s_fm->sr / sr; susp->s_fm_n = 0; susp->output_per_s_fm = sr / s_fm->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sampler(sound_type s, double step, double loop_start, rate_type sr, double hz, time_type t0, sound_type s_fm, long npoints) { sound_type s_fm_copy = sound_copy(s_fm); return snd_make_sampler(s, step, loop_start, sr, hz, t0, s_fm_copy, npoints); } nyquist-3.05/tran/fmfb.h0000644000175000000620000000044711466723256014233 0ustar stevestaffsound_type snd_make_fmfb(time_type t0, double hz, rate_type sr, double index, time_type d); sound_type snd_fmfb(time_type t0, double hz, rate_type sr, double index, time_type d); /* LISP: (snd-fmfb ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ #include "sine.h" /* sine_table and SINE_TABLE_LEN */ nyquist-3.05/tran/amosc.alg0000644000175000000620000000217310144436365014727 0ustar stevestaff(AMOSC-ALG (NAME "amosc") (ARGUMENTS ("sound_type" "input") ("double" "step") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("sound_type" "amod") ("double" "phase")) (TABLE "input") (NOT-IN-INNER-LOOP "input") (START (MIN input)) (STATE ("double" "ph_incr" "0") ("table_type" "the_table" "sound_to_table(input)") ("sample_type *" "table_ptr" "susp->the_table->samples") ("double" "table_len" "susp->the_table->length") ("double" "phase" "compute_phase(phase, step, (long) susp->table_len, input->sr, sr, hz, &susp->ph_incr)") ) (ALWAYS-SCALE amod) (TERMINATE (MIN amod)) (LOGICAL-STOP (MIN amod)) (INNER-LOOP " long table_index = (long) phase; double x1 = (double) (table_ptr[table_index]); output = (sample_type) (x1 + (phase - table_index) * (table_ptr[table_index + 1] - x1)) * amod; phase += ph_incr; while (phase > table_len) phase -= table_len; ") (CONSTANT "ph_incr" "table_len" "table_ptr" "the_table") (SAMPLE-RATE "sr") (FINALIZATION " table_unref(susp->the_table); ") ) nyquist-3.05/tran/congen.c0000644000175000000620000001230510144436365014553 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "congen.h" void congen_free(); typedef struct congen_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type sndin; long sndin_cnt; sample_block_values_type sndin_ptr; double value; double rise_factor; double fall_factor; } congen_susp_node, *congen_susp_type; void congen_s_fetch(register congen_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double value_reg; register double rise_factor_reg; register double fall_factor_reg; register sample_type sndin_scale_reg = susp->sndin->scale; register sample_block_values_type sndin_ptr_reg; falloc_sample_block(out, "congen_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the sndin input sample block: */ susp_check_term_samples(sndin, sndin_ptr, sndin_cnt); togo = min(togo, susp->sndin_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; value_reg = susp->value; rise_factor_reg = susp->rise_factor; fall_factor_reg = susp->fall_factor; sndin_ptr_reg = susp->sndin_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ sample_type current = (sndin_scale_reg * *sndin_ptr_reg++); if (current > value_reg) { value_reg = current - (current - value_reg) * rise_factor_reg; } else { value_reg = current - (current - value_reg) * fall_factor_reg; } *out_ptr_reg++ = (sample_type) value_reg;; } while (--n); /* inner loop */ susp->value = value_reg; /* using sndin_ptr_reg is a bad idea on RS/6000: */ susp->sndin_ptr += togo; out_ptr += togo; susp_took(sndin_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* congen_s_fetch */ void congen_toss_fetch(susp, snd_list) register congen_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from sndin up to final_time for this block of zeros */ while ((round((final_time - susp->sndin->t0) * susp->sndin->sr)) >= susp->sndin->current) susp_get_samples(sndin, sndin_ptr, sndin_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->sndin->t0) * susp->sndin->sr - (susp->sndin->current - susp->sndin_cnt)); susp->sndin_ptr += n; susp_took(sndin_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void congen_mark(congen_susp_type susp) { sound_xlmark(susp->sndin); } void congen_free(congen_susp_type susp) { sound_unref(susp->sndin); ffree_generic(susp, sizeof(congen_susp_node), "congen_free"); } void congen_print_tree(congen_susp_type susp, int n) { indent(n); stdputstr("sndin:"); sound_print_tree_1(susp->sndin, n); } sound_type snd_make_congen(sound_type sndin, double risetime, double falltime) { register congen_susp_type susp; rate_type sr = sndin->sr; time_type t0 = sndin->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, congen_susp_node, "snd_make_congen"); susp->value = 0; susp->rise_factor = exp(log(0.5) / (sndin->sr * risetime)); susp->fall_factor = exp(log(0.5) / (sndin->sr * falltime)); susp->susp.fetch = congen_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < sndin->t0) sound_prepend_zeros(sndin, t0); /* minimum start time over all inputs: */ t0_min = min(sndin->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = congen_toss_fetch; } /* initialize susp state */ susp->susp.free = congen_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = congen_mark; susp->susp.print_tree = congen_print_tree; susp->susp.name = "congen"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->sndin = sndin; susp->sndin_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_congen(sound_type sndin, double risetime, double falltime) { sound_type sndin_copy = sound_copy(sndin); return snd_make_congen(sndin_copy, risetime, falltime); } nyquist-3.05/tran/log.h0000644000175000000620000000016110144436365014065 0ustar stevestaffsound_type snd_make_log(sound_type input); sound_type snd_log(sound_type input); /* LISP: (snd-log SOUND) */ nyquist-3.05/tran/instrbanded.h0000644000175000000620000000044111466723256015610 0ustar stevestaffsound_type snd_make_bandedwg(double freq, sound_type bowpress_env, int preset, rate_type sr); sound_type snd_bandedwg(double freq, sound_type bowpress_env, int preset, rate_type sr); /* LISP: (snd-bandedwg ANYNUM SOUND FIXNUM ANYNUM) */ #define BANDEDWG_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/fmfbv.c0000644000175000000620000004523011466723256014413 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "fmfbv.h" void fmfbv_free(); typedef struct fmfbv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type index; long index_cnt; sample_block_values_type index_ptr; /* support for interpolation of index */ sample_type index_x1_sample; double index_pHaSe; double index_pHaSe_iNcR; /* support for ramp between samples of index */ double output_per_index; long index_n; double yy; double sin_y; double phase; double ph_incr; } fmfbv_susp_node, *fmfbv_susp_type; void fmfbv_n_fetch(register fmfbv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double yy_reg; register double sin_y_reg; register double phase_reg; register double ph_incr_reg; register sample_block_values_type index_ptr_reg; falloc_sample_block(out, "fmfbv_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the index input sample block: */ susp_check_term_log_samples(index, index_ptr, index_cnt); togo = min(togo, susp->index_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; yy_reg = susp->yy; sin_y_reg = susp->sin_y; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; index_ptr_reg = susp->index_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ phase_reg += ph_incr_reg; if (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* PHASE is incremented and INDEX scaled to table INDEX, and sin_y_reg is a signal (-1 to +1) */ yy_reg = phase_reg + *index_ptr_reg++ * sin_y_reg; /* so yy_reg is a table index */ while (yy_reg > SINE_TABLE_LEN) yy_reg -= SINE_TABLE_LEN; while (yy_reg < 0) yy_reg += SINE_TABLE_LEN; sin_y_reg = sine_table[(int) yy_reg]; /* truncation gets valid index */ /* sin_y_reg is now a signal not ready for table lookup */ *out_ptr_reg++ = sin_y_reg;; } while (--n); /* inner loop */ susp->yy = yy_reg; susp->sin_y = sin_y_reg; susp->phase = phase_reg; /* using index_ptr_reg is a bad idea on RS/6000: */ susp->index_ptr += togo; out_ptr += togo; susp_took(index_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmfbv_n_fetch */ void fmfbv_s_fetch(register fmfbv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double yy_reg; register double sin_y_reg; register double phase_reg; register double ph_incr_reg; register sample_type index_scale_reg = susp->index->scale; register sample_block_values_type index_ptr_reg; falloc_sample_block(out, "fmfbv_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the index input sample block: */ susp_check_term_log_samples(index, index_ptr, index_cnt); togo = min(togo, susp->index_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; yy_reg = susp->yy; sin_y_reg = susp->sin_y; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; index_ptr_reg = susp->index_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ phase_reg += ph_incr_reg; if (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* PHASE is incremented and INDEX scaled to table INDEX, and sin_y_reg is a signal (-1 to +1) */ yy_reg = phase_reg + (index_scale_reg * *index_ptr_reg++) * sin_y_reg; /* so yy_reg is a table index */ while (yy_reg > SINE_TABLE_LEN) yy_reg -= SINE_TABLE_LEN; while (yy_reg < 0) yy_reg += SINE_TABLE_LEN; sin_y_reg = sine_table[(int) yy_reg]; /* truncation gets valid index */ /* sin_y_reg is now a signal not ready for table lookup */ *out_ptr_reg++ = sin_y_reg;; } while (--n); /* inner loop */ susp->yy = yy_reg; susp->sin_y = sin_y_reg; susp->phase = phase_reg; /* using index_ptr_reg is a bad idea on RS/6000: */ susp->index_ptr += togo; out_ptr += togo; susp_took(index_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmfbv_s_fetch */ void fmfbv_i_fetch(register fmfbv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double yy_reg; register double sin_y_reg; register double phase_reg; register double ph_incr_reg; register double index_pHaSe_iNcR_rEg = susp->index_pHaSe_iNcR; register double index_pHaSe_ReG; register sample_type index_x1_sample_reg; falloc_sample_block(out, "fmfbv_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(index, index_ptr, index_cnt); susp->index_x1_sample = susp_fetch_sample(index, index_ptr, index_cnt); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; yy_reg = susp->yy; sin_y_reg = susp->sin_y; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; index_pHaSe_ReG = susp->index_pHaSe; index_x1_sample_reg = susp->index_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (index_pHaSe_ReG >= 1.0) { /* fixup-depends index */ /* pick up next sample as index_x1_sample: */ susp->index_ptr++; susp_took(index_cnt, 1); index_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(index, index_ptr, index_cnt, index_x1_sample_reg); index_x1_sample_reg = susp_current_sample(index, index_ptr); } phase_reg += ph_incr_reg; if (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* PHASE is incremented and INDEX scaled to table INDEX, and sin_y_reg is a signal (-1 to +1) */ yy_reg = phase_reg + index_x1_sample_reg * sin_y_reg; /* so yy_reg is a table index */ while (yy_reg > SINE_TABLE_LEN) yy_reg -= SINE_TABLE_LEN; while (yy_reg < 0) yy_reg += SINE_TABLE_LEN; sin_y_reg = sine_table[(int) yy_reg]; /* truncation gets valid index */ /* sin_y_reg is now a signal not ready for table lookup */ *out_ptr_reg++ = sin_y_reg;; index_pHaSe_ReG += index_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->yy = yy_reg; susp->sin_y = sin_y_reg; susp->phase = phase_reg; susp->index_pHaSe = index_pHaSe_ReG; susp->index_x1_sample = index_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmfbv_i_fetch */ void fmfbv_r_fetch(register fmfbv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type index_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double yy_reg; register double sin_y_reg; register double phase_reg; register double ph_incr_reg; falloc_sample_block(out, "fmfbv_r_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->index_pHaSe = 1.0; } susp_check_term_log_samples(index, index_ptr, index_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* grab next index_x1_sample when phase goes past 1.0; */ /* use index_n (computed below) to avoid roundoff errors: */ if (susp->index_n <= 0) { susp_check_term_log_samples(index, index_ptr, index_cnt); susp->index_x1_sample = susp_fetch_sample(index, index_ptr, index_cnt); susp->index_pHaSe -= 1.0; /* index_n gets number of samples before phase exceeds 1.0: */ susp->index_n = (long) ((1.0 - susp->index_pHaSe) * susp->output_per_index); } togo = min(togo, susp->index_n); index_val = susp->index_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; yy_reg = susp->yy; sin_y_reg = susp->sin_y; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ phase_reg += ph_incr_reg; if (phase_reg > SINE_TABLE_LEN) phase_reg -= SINE_TABLE_LEN; /* PHASE is incremented and INDEX scaled to table INDEX, and sin_y_reg is a signal (-1 to +1) */ yy_reg = phase_reg + index_val * sin_y_reg; /* so yy_reg is a table index */ while (yy_reg > SINE_TABLE_LEN) yy_reg -= SINE_TABLE_LEN; while (yy_reg < 0) yy_reg += SINE_TABLE_LEN; sin_y_reg = sine_table[(int) yy_reg]; /* truncation gets valid index */ /* sin_y_reg is now a signal not ready for table lookup */ *out_ptr_reg++ = sin_y_reg;; } while (--n); /* inner loop */ susp->yy = yy_reg; susp->sin_y = sin_y_reg; susp->phase = phase_reg; out_ptr += togo; susp->index_pHaSe += togo * susp->index_pHaSe_iNcR; susp->index_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmfbv_r_fetch */ void fmfbv_toss_fetch(susp, snd_list) register fmfbv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from index up to final_time for this block of zeros */ while ((round((final_time - susp->index->t0) * susp->index->sr)) >= susp->index->current) susp_get_samples(index, index_ptr, index_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->index->t0) * susp->index->sr - (susp->index->current - susp->index_cnt)); susp->index_ptr += n; susp_took(index_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void fmfbv_mark(fmfbv_susp_type susp) { sound_xlmark(susp->index); } void fmfbv_free(fmfbv_susp_type susp) { sound_unref(susp->index); ffree_generic(susp, sizeof(fmfbv_susp_node), "fmfbv_free"); } void fmfbv_print_tree(fmfbv_susp_type susp, int n) { indent(n); stdputstr("index:"); sound_print_tree_1(susp->index, n); } sound_type snd_make_fmfbv(time_type t0, double hz, rate_type sr, sound_type index) { register fmfbv_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, fmfbv_susp_node, "snd_make_fmfbv"); susp->yy = 0.0; susp->sin_y = 0.0; susp->phase = 0.0; susp->ph_incr = hz * SINE_TABLE_LEN / sr; index->scale *= SINE_TABLE_LEN / PI2 ; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(index, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = fmfbv_n_fetch; break; case INTERP_s: susp->susp.fetch = fmfbv_s_fetch; break; case INTERP_i: susp->susp.fetch = fmfbv_i_fetch; break; case INTERP_r: susp->susp.fetch = fmfbv_r_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < index->t0) sound_prepend_zeros(index, t0); /* minimum start time over all inputs: */ t0_min = min(index->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = fmfbv_toss_fetch; } /* initialize susp state */ susp->susp.free = fmfbv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = fmfbv_mark; susp->susp.print_tree = fmfbv_print_tree; susp->susp.name = "fmfbv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(index); susp->started = false; susp->susp.current = 0; susp->index = index; susp->index_cnt = 0; susp->index_pHaSe = 0.0; susp->index_pHaSe_iNcR = index->sr / sr; susp->index_n = 0; susp->output_per_index = sr / index->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_fmfbv(time_type t0, double hz, rate_type sr, sound_type index) { sound_type index_copy = sound_copy(index); return snd_make_fmfbv(t0, hz, sr, index_copy); } nyquist-3.05/tran/clip.h0000644000175000000620000000021710144436365014235 0ustar stevestaffsound_type snd_make_clip(sound_type s, double level); sound_type snd_clip(sound_type s, double level); /* LISP: (snd-clip SOUND ANYNUM) */ nyquist-3.05/tran/aresoncv.alg0000644000175000000620000000247411466723256015457 0ustar stevestaff(ARESONCV-ALG (NAME "aresoncv") (ARGUMENTS ("sound_type" "s1") ("double" "hz") ("sound_type" "bw") ("int" "normalization")) (INLINE-INTERPOLATION T) (LINEAR s1) (ALWAYS-SCALE bw) (START (MAX s1 bw)) (TERMINATE (MIN s1 bw)) (LOGICAL-STOP (MIN s1)) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION bw) (STATE ("double" "c3co" "0.0") ("double" "coshz" "cos(hz * PI2 / s1->sr)") ("double" "c2" "0.0") ("double" "c1" "0.0") ("int" "normalization" "normalization") ("double" "y1" "0.0") ("double" "y2" "0.0; bw->scale = (float) (bw->scale * (-PI2 / s1->sr))")) (DEPENDS ("c3co" "hz" "exp(bw)") ("c3p1" "hz" "c3co + 1.0" TEMP "double") ("c3t4" "hz" "c3co * 4.0" TEMP "double") ("omc3" "hz" "1.0 - c3co" TEMP "double") ("c2" "hz" "c3t4 * coshz / c3p1") ("c1" "hz" "(normalization == 0 ? 0.0 : (normalization == 1 ? 1.0 - omc3 * sqrt(1.0 - c2 * c2 / c3t4) : 1.0 - sqrt(c3p1 * c3p1 - c2 * c2) * omc3 / c3p1))")) (CONSTANT "c1" "c2" "c3co" "coshz" "normalization") (FORCE-INTO-REGISTER normalization coshz scale1) (INNER-LOOP-LOCALS " register double y0, current;") (INNER-LOOP " current = s1; output = (float) (y0 = c1 * current + c2 * y1 - c3co * y2); y2 = y1; y1 = y0 - current") ) nyquist-3.05/tran/fmfb.alg0000644000175000000620000000211211466723256014536 0ustar stevestaff(FMFB-ALG (NAME "fmfb") (ARGUMENTS ("time_type" "t0")("double" "hz") ("rate_type" "sr")("double" "index") ("time_type" "d")) (TERMINATE (AFTER "d")) (STATE ("double" "yy" "0.0") ("double" "sin_y" "0.0") ("double" "xx" "0.0") ("double" "x_incr" "hz * SINE_TABLE_LEN / sr") ("double" "index" "index * SINE_TABLE_LEN / PI2")) (INNER-LOOP "xx += x_incr; if (xx > SINE_TABLE_LEN) xx -= SINE_TABLE_LEN; /* xx incremented and index scaled to table index, and sin_y is a signal (-1 to +1) */ yy = xx + index * sin_y; /* so yy is a table index */ while (yy > SINE_TABLE_LEN) yy -= SINE_TABLE_LEN; while (yy < 0) yy += SINE_TABLE_LEN; sin_y = sine_table[(int) yy]; /* truncation gets valid index */ /* sin_y is now a signal not ready for table lookup */ output = sin_y;") (CONSTANT "x_incr") (SAMPLE-RATE "sr") (SUPPORT-HEADER "#include \"sine.h\" /* sine_table and SINE_TABLE_LEN */ ") ) nyquist-3.05/tran/eqbandv.alg0000644000175000000620000000331010144436365015237 0ustar stevestaff; general order-2 IIR filter. ; a0 is assumed to be unity. ; for a1 and a2, our sign convention is opposite to Matlab's. (EQBANDVVV-ALG (NAME "eqbandvvv") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz")) ;; ("sound_type" "gain") ("sound_type" "width") ) (START (MIN s1 hz)) ;; gain width)) (TERMINATE (MIN s1 hz )) ;; gain width)) (LOGICAL-STOP (MIN s1 hz)) ;; gain width)) (SAMPLE-RATE (MAX s1)) (INTERNAL-SCALING s1) (INLINE-INTERPOLATION T) (ALWAYS-SCALE hz) (STEP-FUNCTION hz gain width) (STATE ("double" "scale1" "s1->scale") ("double" "w1" "0.0") ("double" "sw" "0.0") ("double" "cw" "0.0") ("double" "J" "0.0") ("double" "g" "0.0") ("double" "b0" "0.0") ("double" "b1" "0.0") ("double" "b2" "0.0") ("double" "a0" "0.0") ("double" "a1" "0.0") ("double" "a2" "0.0")) (DEPENDS ("w1" "hz" "PI2 * hz / s1->sr") ("sw" "hz" "sin(w1)") ("cw" "hz" "cos(w1)") ("b1" "hz" "-2.0 * cw") ("a1" "hz" "-b1") ;; ("J" "gain" "sqrt(gain)") ;; ("recompute" "width" "true") ("recompute" "hz" "true") ;; ("recompute" "gain" "true") ) ;; (JOINT-DEPENDENCY (("width" "hz") ;;"if (recompute) {" ;;" recompute = false;" ;;" g = sw * sinh(log_of_2_over_2 * width * w1 / sw);" ;;" b0 = 1.0 + g * J;" ;;" b2 = 1.0 - g * J;" ;;" a0 = 1.0 + g / J;" ;;" a2 = g / J - 1.0;" ;;"}")) (FORCE-INTO-REGISTER recompute) (STEP-FUNCTION hz) ;; gain width) (CONSTANT "w1" "sw" "cw" "J" "g" "b0" "b1" "b2" "b3" "a0" "a1" "a2") (INNER-LOOP-LOCALS "double z0;") (INNER-LOOP " z0 = s + a1*z1 + a2*z2; output = (sample_type) (z0*b0 + z1*b1 + z2*b2); z2 = z1; z1 = z0;") ) nyquist-3.05/tran/atone.alg0000644000175000000620000000116710144436365014735 0ustar stevestaff(ATONE-ALG (NAME "atone") (ARGUMENTS ("sound_type" "s") ("double" "hz")) (START (MIN s)) (TERMINATE (MIN s)) (LOGICAL-STOP (MIN s)) (STATE ("double" "bb" "2.0 - cos(hz * PI2 / s->sr)" TEMP) ("double" "cc" "bb - sqrt((bb * bb) - 1.0)") ("double" "prev" "0.0")) (CONSTANT "cc") (INNER-LOOP-LOCALS " double current; ") (INNER-LOOP "current = s; prev = cc * (prev + current); /* use prev as temp variable ... */ output = (float) prev; /* ... so we can do proper type conversion */ prev -= current;") ; old code was: ; prev = (output = cc * (prev + current)) - current;") ) nyquist-3.05/tran/reson.alg0000644000175000000620000000156210144436365014754 0ustar stevestaff(RESON-ALG (NAME "reson") (ARGUMENTS ("sound_type" "s") ("double" "hz") ("double" "bw") ("int" "normalization")) (START (MIN s)) (TERMINATE (MIN s)) (LOGICAL-STOP (MIN s)) (STATE ("double" "c3" "exp(bw * -PI2 / s->sr)") ("double" "c3p1" "susp->c3 + 1.0") ("double" "c3t4" "susp->c3 * 4.0") ("double" "omc3" "1.0 - susp->c3") ("double" "c2" "susp->c3t4 * cos(hz * PI2 / s->sr) / susp->c3p1") ("double" "c1" "(normalization == 0 ? 1.0 : (normalization == 1 ? susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1))") ("double" "y1" "0.0") ("double" "y2" "0.0")) (CONSTANT "c1" "c2" "c3") (INNER-LOOP "{ double y0 = c1 * s + c2 * y1 - c3 * y2; output = (sample_type) y0; y2 = y1; y1 = y0; }") ) nyquist-3.05/tran/prod.alg0000644000175000000620000000035310144436365014567 0ustar stevestaff(PROD-ALG (NAME "prod") (ARGUMENTS ("sound_type" "s1") ("sound_type" "s2")) (START (MAX s1 s2)) (COMMUTATIVE (s1 s2)) (INNER-LOOP "output = s1 * s2") (LINEAR s1 s2) (TERMINATE (MIN s1 s2)) (LOGICAL-STOP (MIN s1 s2)) ) nyquist-3.05/tran/writetoss.lsp0000644000175000000620000000640210144436365015722 0ustar stevestaff;; writetoss -- writes the "toss prepended samples" routine ;; modified May 3, 1999 by RBD to not adjust t0 when samples will be tossed ;; also, final_time is just susp->susp.t0, since t0 is unadjusted. (defun write-toss (alg stream) (let ((alg-name (get alg 'name)) (sound-names (get alg 'sound-names))) ;;---------------- ;; void ALG_toss_fetch(susp, snd_list) ;; register ALG_susp_type susp; ;; snd_list_type snd_list; ;; { ;; long final_count = susp->susp.toss_cnt); ;; time_type final_time = susp->susp.t0; ;; FORMERLY, THIS WAS: ;; time_type final_time = susp->susp.t0 + final_count / susp->susp.sr; ;; long n; ;;---------------- (format stream "~%~%void ~A_toss_fetch(susp, snd_list)~%" alg-name) (format stream " register ~A_susp_type susp;~%" alg-name) (format stream " snd_list_type snd_list;~%{~%") (format stream " long final_count = susp->susp.toss_cnt;~%") (format stream " time_type final_time = susp->susp.t0;~%") (format stream " long n;~%~%") (cond (*watch* (format stream " printf(\"~A_toss_fetch: final count %d final time %d\\n\", " alg-name) (format stream "final_count, final_time);~%"))) ;;------------------------------ ;; for each sound argument: ;; ;; /* fetch samples from NAME up to final_time for this block of zeros */ ;; while ((round((final_time - susp->NAME->t0) * susp->NAME->sr)) >= ;; susp->NAME->current) ;; susp_get_samples(NAME, NAME_ptr, NAME_cnt); ;;------------------------------ (dolist (name sound-names) (format stream " /* fetch samples from ~A up to final_time for this block of zeros */~%" name) (format stream " while ((round((final_time - susp->~A->t0) * susp->~A->sr)) >=~%" name name) (format stream "\t susp->~A->current)~%" name) (format stream "\tsusp_get_samples(~A, ~A_ptr, ~A_cnt);~%" name name name)) ;;---------------- ;; /* convert to normal processing when we hit final_count */ ;; /* we want each signal positioned at final_time */ ;;---------------- (format stream " /* convert to normal processing when we hit final_count */~%") (format stream " /* we want each signal positioned at final_time */~%") ;;---------------- ;; for each sound argument: ;; ;; n = round((final_time - susp->NAME->t0) * susp->NAME->sr - ;; (susp->NAME->current - susp->NAME_cnt)); ;; susp->NAME_ptr += n; ;; susp_took(NAME_cnt, n); ;;---------------- (dolist (name sound-names) (format stream " n = round((final_time - susp->~A->t0) * susp->~A->sr -~%" name name) (format stream " (susp->~A->current - susp->~A_cnt));~%" name name) (format stream " susp->~A_ptr += n;~%" name) (format stream " susp_took(~A_cnt, n);~%" name)) ;;---------------- ;; susp->susp.fetch = susp->susp.keep_fetch; ;; (*(susp->susp.fetch))(susp, snd_list); ;; } ;;---------------- (format stream " susp->susp.fetch = susp->susp.keep_fetch;~%") (format stream " (*(susp->susp.fetch))(susp, snd_list);~%") (format stream "}~%"))) nyquist-3.05/tran/instrsax.h0000644000175000000620000000035210144436365015161 0ustar stevestaffsound_type snd_make_sax(double freq, sound_type breath_env, rate_type sr); sound_type snd_sax(double freq, sound_type breath_env, rate_type sr); /* LISP: (snd-sax ANYNUM SOUND ANYNUM) */ #define SAX_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/areson.c0000644000175000000620000001530110144436365014570 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "areson.h" void areson_free(); typedef struct areson_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; double c3; double c2; double c1; double y1; double y2; } areson_susp_node, *areson_susp_type; void areson_n_fetch(register areson_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3_reg; register double c2_reg; register double c1_reg; register double y1_reg; register double y2_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "areson_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3_reg = susp->c3; c2_reg = susp->c2; c1_reg = susp->c1; y1_reg = susp->y1; y2_reg = susp->y2; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current;current = *input_ptr_reg++; *out_ptr_reg++ = (sample_type) (y0 = c1_reg * current + c2_reg * y1_reg - c3_reg * y2_reg); y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* areson_n_fetch */ void areson_toss_fetch(susp, snd_list) register areson_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void areson_mark(areson_susp_type susp) { sound_xlmark(susp->input); } void areson_free(areson_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(areson_susp_node), "areson_free"); } void areson_print_tree(areson_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_areson(sound_type input, double hz, double bw, int normalization) { register areson_susp_type susp; double c3p1; double c3t4; double omc3; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, areson_susp_node, "snd_make_areson"); susp->c3 = exp(bw * -PI2 / input->sr); c3p1 = susp->c3 + 1.0; c3t4 = susp->c3 * 4.0; omc3 = 1.0 - susp->c3; susp->c2 = c3t4 * cos(hz * PI2 / input->sr) / c3p1; susp->c1 = (normalization == 0 ? 0.0 : (normalization == 1 ? 1.0 - omc3 * sqrt(1.0 - susp->c2 * susp->c2 / c3t4) : 1.0 - sqrt(c3p1 * c3p1 - susp->c2 * susp->c2) * omc3 / c3p1)); susp->y1 = 0.0; susp->y2 = 0.0; susp->susp.fetch = areson_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = areson_toss_fetch; } /* initialize susp state */ susp->susp.free = areson_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = areson_mark; susp->susp.print_tree = areson_print_tree; susp->susp.name = "areson"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_areson(sound_type input, double hz, double bw, int normalization) { sound_type input_copy = sound_copy(input); return snd_make_areson(input_copy, hz, bw, normalization); } nyquist-3.05/tran/follow.c0000644000175000000620000002331210144436365014604 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "follow.h" void follow_free(); typedef struct follow_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type sndin; long sndin_cnt; sample_block_values_type sndin_ptr; long lookahead; sample_type *delaybuf; sample_type *delayptr; sample_type *prevptr; sample_type *endptr; double floor; double rise_factor; double fall_factor; double value; } follow_susp_node, *follow_susp_type; /* Description: this is a sophisticated envelope follower. The input is an envelope, e.g. something produced with the AVG function. The purpose of this function is to generate a smooth envelope that is generally not less than the input signal. In other words, we want to "ride" the peaks of the signal with a smooth function. The algorithm is as follows: keep a current output value (called the "value"). The value is allowed to increase by at most rise_factor and decrease by at most fall_factor. Therefore, the next value should be between value * rise_factor and value * fall_factor. If the input is in this range, then the next value is simply the input. If the input is less than value * fall_factor, then the next value is just value * fall_factor, which will be greater than the input signal. If the input is greater than value * rise_factor, then we compute a rising envelope that meets the input value by working bacwards in time, changing the previous values to input / rise_factor, input / rise_factor^2, input / rise_factor^3, etc. until this new envelope intersects the previously computed values. There is only a limited buffer in which we can work backwards, so if the new envelope does not intersect the old one, then make yet another pass, this time from the oldest buffered value forward, increasing on each sample by rise_factor to produce a maximal envelope. This will still be less than the input. The value has a lower limit of floor to make sure value has a reasonable positive value from which to begin an attack. Because this algorithm can make 2 passes through the buffer on sharply rising input signals, it is not particularly fast. The assumption is that it operates on fairly short buffers at low sample rates appropriate for gain control, so this should not matter. */ static sample_type *create_buf(double floor, long lookahead) { sample_type *buf = (sample_type *) malloc(lookahead * sizeof(sample_type)); int i; for (i = 0; i < lookahead; i++) buf[i] = (sample_type) floor; return buf; } void follow_s_fetch(register follow_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long lookahead_reg; register sample_type * delayptr_reg; register sample_type * prevptr_reg; register sample_type * endptr_reg; register double floor_reg; register double rise_factor_reg; register double fall_factor_reg; register sample_type sndin_scale_reg = susp->sndin->scale; register sample_block_values_type sndin_ptr_reg; falloc_sample_block(out, "follow_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the sndin input sample block: */ susp_check_term_samples(sndin, sndin_ptr, sndin_cnt); togo = min(togo, susp->sndin_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; lookahead_reg = susp->lookahead; delayptr_reg = susp->delayptr; prevptr_reg = susp->prevptr; endptr_reg = susp->endptr; floor_reg = susp->floor; rise_factor_reg = susp->rise_factor; fall_factor_reg = susp->fall_factor; sndin_ptr_reg = susp->sndin_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ sample_type current = (sndin_scale_reg * *sndin_ptr_reg++); sample_type high = (sample_type) (*prevptr_reg * rise_factor_reg); sample_type low = (sample_type) (*prevptr_reg * fall_factor_reg); if (low < floor_reg) low = (sample_type) floor_reg; if (current < low) *delayptr_reg = (sample_type) low; else if (current < high) *delayptr_reg = current; else /* current > high */ { /* work back from current */ double rise_inverse = 1.0 / rise_factor_reg; double temp = current * rise_inverse; boolean ok = false; sample_type *ptr = prevptr_reg; int i; for (i = 0; i < lookahead_reg - 2; i++) { if (*ptr < temp) { *ptr-- = (sample_type) temp; temp *= rise_inverse; if (ptr < susp->delaybuf) ptr = endptr_reg - 1; } else { ok = true; break; } } if (!ok && (*ptr < temp)) { temp = *ptr; for (i = 0; i < lookahead_reg - 1; i++) { ptr++; if (ptr == endptr_reg) ptr = susp->delaybuf; temp *= rise_factor_reg; *ptr = (sample_type) temp; } } else *delayptr_reg = current; } prevptr_reg = delayptr_reg++; if (delayptr_reg == endptr_reg) delayptr_reg = susp->delaybuf; *out_ptr_reg++ = *delayptr_reg;; } while (--n); /* inner loop */ togo -= n; susp->lookahead = lookahead_reg; susp->delayptr = delayptr_reg; susp->prevptr = prevptr_reg; susp->floor = floor_reg; /* using sndin_ptr_reg is a bad idea on RS/6000: */ susp->sndin_ptr += togo; out_ptr += togo; susp_took(sndin_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* follow_s_fetch */ void follow_toss_fetch(susp, snd_list) register follow_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from sndin up to final_time for this block of zeros */ while ((round((final_time - susp->sndin->t0) * susp->sndin->sr)) >= susp->sndin->current) susp_get_samples(sndin, sndin_ptr, sndin_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->sndin->t0) * susp->sndin->sr - (susp->sndin->current - susp->sndin_cnt)); susp->sndin_ptr += n; susp_took(sndin_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void follow_mark(follow_susp_type susp) { sound_xlmark(susp->sndin); } void follow_free(follow_susp_type susp) { free(susp->delaybuf); sound_unref(susp->sndin); ffree_generic(susp, sizeof(follow_susp_node), "follow_free"); } void follow_print_tree(follow_susp_type susp, int n) { indent(n); stdputstr("sndin:"); sound_print_tree_1(susp->sndin, n); } sound_type snd_make_follow(sound_type sndin, double floor, double risetime, double falltime, long lookahead) { register follow_susp_type susp; rate_type sr = sndin->sr; time_type t0 = sndin->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, follow_susp_node, "snd_make_follow"); susp->lookahead = lookahead = lookahead + 1; susp->delaybuf = create_buf(floor, lookahead); susp->delayptr = susp->delaybuf; susp->prevptr = susp->delaybuf + lookahead - 1; *(susp->prevptr) = (sample_type) floor;; susp->endptr = susp->delaybuf + lookahead; susp->floor = floor; floor = log(floor);; susp->rise_factor = exp(- floor / (sndin->sr * risetime + 0.5)); susp->fall_factor = exp(floor / (sndin->sr * falltime + 0.5)); susp->value = susp->floor; susp->susp.fetch = follow_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < sndin->t0) sound_prepend_zeros(sndin, t0); /* minimum start time over all inputs: */ t0_min = min(sndin->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = follow_toss_fetch; } /* initialize susp state */ susp->susp.free = follow_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = follow_mark; susp->susp.print_tree = follow_print_tree; susp->susp.name = "follow"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->sndin = sndin; susp->sndin_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_follow(sound_type sndin, double floor, double risetime, double falltime, long lookahead) { sound_type sndin_copy = sound_copy(sndin); return snd_make_follow(sndin_copy, floor, risetime, falltime, lookahead); } nyquist-3.05/tran/alpasscv.c0000644000175000000620000002274110144436365015123 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "alpasscv.h" void alpasscv_free(); typedef struct alpasscv_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type input; long input_cnt; sample_block_values_type input_ptr; sound_type feedback; long feedback_cnt; sample_block_values_type feedback_ptr; long delaylen; sample_type *delaybuf; sample_type *delayptr; sample_type *endptr; } alpasscv_susp_node, *alpasscv_susp_type; void alpasscv_nn_fetch(register alpasscv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type feedback_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpasscv_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, fb; y = *delayptr_reg; *delayptr_reg++ = z = (sample_type) ((fb = *feedback_ptr_reg++) * y + *input_ptr_reg++); *out_ptr_reg++ = (sample_type) (y - fb * z); if (delayptr_reg >= endptr_reg) delayptr_reg = susp->delaybuf;; } while (--n); /* inner loop */ susp->delayptr = delayptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpasscv_nn_fetch */ void alpasscv_ns_fetch(register alpasscv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_type feedback_scale_reg = susp->feedback->scale; register sample_block_values_type feedback_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpasscv_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, fb; y = *delayptr_reg; *delayptr_reg++ = z = (sample_type) ((fb = (feedback_scale_reg * *feedback_ptr_reg++)) * y + *input_ptr_reg++); *out_ptr_reg++ = (sample_type) (y - fb * z); if (delayptr_reg >= endptr_reg) delayptr_reg = susp->delaybuf;; } while (--n); /* inner loop */ susp->delayptr = delayptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpasscv_ns_fetch */ void alpasscv_toss_fetch(susp, snd_list) register alpasscv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* fetch samples from feedback up to final_time for this block of zeros */ while ((round((final_time - susp->feedback->t0) * susp->feedback->sr)) >= susp->feedback->current) susp_get_samples(feedback, feedback_ptr, feedback_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); n = round((final_time - susp->feedback->t0) * susp->feedback->sr - (susp->feedback->current - susp->feedback_cnt)); susp->feedback_ptr += n; susp_took(feedback_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void alpasscv_mark(alpasscv_susp_type susp) { sound_xlmark(susp->input); sound_xlmark(susp->feedback); } void alpasscv_free(alpasscv_susp_type susp) { free(susp->delaybuf); sound_unref(susp->input); sound_unref(susp->feedback); ffree_generic(susp, sizeof(alpasscv_susp_node), "alpasscv_free"); } void alpasscv_print_tree(alpasscv_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); indent(n); stdputstr("feedback:"); sound_print_tree_1(susp->feedback, n); } sound_type snd_make_alpasscv(sound_type input, time_type delay, sound_type feedback) { register alpasscv_susp_type susp; rate_type sr = max(input->sr, feedback->sr); time_type t0 = max(input->t0, feedback->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, alpasscv_susp_node, "snd_make_alpasscv"); susp->delaylen = max(1, round(input->sr * delay)); susp->delaybuf = (sample_type *) calloc (susp->delaylen, sizeof(sample_type)); susp->delayptr = susp->delaybuf; susp->endptr = susp->delaybuf + susp->delaylen; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); interp_desc = (interp_desc << 2) + interp_style(feedback, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = alpasscv_nn_fetch; break; case INTERP_ns: susp->susp.fetch = alpasscv_ns_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); if (t0 < feedback->t0) sound_prepend_zeros(feedback, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, min(feedback->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = alpasscv_toss_fetch; } /* initialize susp state */ susp->susp.free = alpasscv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = alpasscv_mark; susp->susp.print_tree = alpasscv_print_tree; susp->susp.name = "alpasscv"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; susp->feedback = feedback; susp->feedback_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_alpasscv(sound_type input, time_type delay, sound_type feedback) { sound_type input_copy = sound_copy(input); sound_type feedback_copy = sound_copy(feedback); return snd_make_alpasscv(input_copy, delay, feedback_copy); } nyquist-3.05/tran/stkrev.h0000644000175000000620000000040011466723256014624 0ustar stevestaffsound_type snd_make_stkrev(int rev_type, sound_type s1, time_type trev, double mix, rate_type sr); sound_type snd_stkrev(int rev_type, sound_type s1, time_type trev, double mix, rate_type sr); /* LISP: (snd-stkrev FIXNUM SOUND ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/abs.c0000644000175000000620000001262610144436365014055 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "abs.h" void abs_free(); typedef struct abs_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; } abs_susp_node, *abs_susp_type; void abs_s_fetch(register abs_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "abs_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { sample_type s = (input_scale_reg * *input_ptr_reg++); sample_type o = s; if (o < 0.0) o = -o; *out_ptr_reg++ = o; }; } while (--n); /* inner loop */ /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* abs_s_fetch */ void abs_toss_fetch(susp, snd_list) register abs_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void abs_mark(abs_susp_type susp) { sound_xlmark(susp->input); } void abs_free(abs_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(abs_susp_node), "abs_free"); } void abs_print_tree(abs_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_abs(sound_type input) { register abs_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, abs_susp_node, "snd_make_abs"); susp->susp.fetch = abs_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = abs_toss_fetch; } /* initialize susp state */ susp->susp.free = abs_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = abs_mark; susp->susp.print_tree = abs_print_tree; susp->susp.name = "abs"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_abs(sound_type input) { sound_type input_copy = sound_copy(input); return snd_make_abs(input_copy); } nyquist-3.05/tran/instrbow.h0000644000175000000620000000036411466723256015166 0ustar stevestaffsound_type snd_make_bowed(double freq, sound_type bowpress_env, rate_type sr); sound_type snd_bowed(double freq, sound_type bowpress_env, rate_type sr); /* LISP: (snd-bowed ANYNUM SOUND ANYNUM) */ #define BOW_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/instrflutefreq.c0000644000175000000620000002303111466723256016363 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrflutefreq.h" void flute_freq_free(); typedef struct flute_freq_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; struct instr *myflute; int temp_ret_value; double frequency; } flute_freq_susp_node, *flute_freq_susp_type; #include "instr.h" void flute_freq_nn_fetch(register flute_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * myflute_reg; register double frequency_reg; register sample_block_values_type freq_env_ptr_reg; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "flute_freq_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; myflute_reg = susp->myflute; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(myflute_reg, 128, FLUTE_CONTROL_CHANGE_CONST * *breath_env_ptr_reg++); setFrequency(myflute_reg, frequency_reg + *freq_env_ptr_reg++); *out_ptr_reg++ = (sample_type) tick(myflute_reg); } while (--n); /* inner loop */ susp->myflute = myflute_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* flute_freq_nn_fetch */ void flute_freq_ss_fetch(register flute_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * myflute_reg; register double frequency_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "flute_freq_ss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; myflute_reg = susp->myflute; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(myflute_reg, 128, FLUTE_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); setFrequency(myflute_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(myflute_reg); } while (--n); /* inner loop */ susp->myflute = myflute_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* flute_freq_ss_fetch */ void flute_freq_toss_fetch(susp, snd_list) register flute_freq_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void flute_freq_mark(flute_freq_susp_type susp) { sound_xlmark(susp->breath_env); sound_xlmark(susp->freq_env); } void flute_freq_free(flute_freq_susp_type susp) { deleteInstrument(susp->myflute); sound_unref(susp->breath_env); sound_unref(susp->freq_env); ffree_generic(susp, sizeof(flute_freq_susp_node), "flute_freq_free"); } void flute_freq_print_tree(flute_freq_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); } sound_type snd_make_flute_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr) { register flute_freq_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, flute_freq_susp_node, "snd_make_flute_freq"); susp->myflute = initInstrument(FLUTE, round(sr)); controlChange(susp->myflute, 1, 0.0);; susp->temp_ret_value = noteOn(susp->myflute, freq, 1.0); susp->frequency = freq; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(breath_env, sr); interp_desc = (interp_desc << 2) + interp_style(freq_env, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = flute_freq_nn_fetch; break; case INTERP_ss: susp->susp.fetch = flute_freq_ss_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, min(freq_env->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = flute_freq_toss_fetch; } /* initialize susp state */ susp->susp.free = flute_freq_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = flute_freq_mark; susp->susp.print_tree = flute_freq_print_tree; susp->susp.name = "flute_freq"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_flute_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); sound_type freq_env_copy = sound_copy(freq_env); return snd_make_flute_freq(freq, breath_env_copy, freq_env_copy, sr); } nyquist-3.05/tran/fmosc.c0000644000175000000620000003606211466723256014425 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "fmosc.h" void fmosc_free(); typedef struct fmosc_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s_fm; long s_fm_cnt; sample_block_values_type s_fm_ptr; /* support for interpolation of s_fm */ sample_type s_fm_x1_sample; double s_fm_pHaSe; double s_fm_pHaSe_iNcR; /* support for ramp between samples of s_fm */ double output_per_s_fm; long s_fm_n; table_type the_table; double table_len; double ph_incr; sample_type *table_ptr; double phase; } fmosc_susp_node, *fmosc_susp_type; void fmosc_s_fetch(register fmosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double table_len_reg; register double ph_incr_reg; register sample_type * table_ptr_reg; register double phase_reg; register sample_type s_fm_scale_reg = susp->s_fm->scale; register sample_block_values_type s_fm_ptr_reg; falloc_sample_block(out, "fmosc_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s_fm input sample block: */ susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); togo = min(togo, susp->s_fm_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; table_len_reg = susp->table_len; ph_incr_reg = susp->ph_incr; table_ptr_reg = susp->table_ptr; phase_reg = susp->phase; s_fm_ptr_reg = susp->s_fm_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; table_index = (long) phase_reg; x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg + (s_fm_scale_reg * *s_fm_ptr_reg++); while (phase_reg > table_len_reg) phase_reg -= table_len_reg; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += table_len_reg; } while (--n); /* inner loop */ susp->phase = phase_reg; /* using s_fm_ptr_reg is a bad idea on RS/6000: */ susp->s_fm_ptr += togo; out_ptr += togo; susp_took(s_fm_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmosc_s_fetch */ void fmosc_i_fetch(register fmosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double table_len_reg; register double ph_incr_reg; register sample_type * table_ptr_reg; register double phase_reg; register double s_fm_pHaSe_iNcR_rEg = susp->s_fm_pHaSe_iNcR; register double s_fm_pHaSe_ReG; register sample_type s_fm_x1_sample_reg; falloc_sample_block(out, "fmosc_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; table_len_reg = susp->table_len; ph_incr_reg = susp->ph_incr; table_ptr_reg = susp->table_ptr; phase_reg = susp->phase; s_fm_pHaSe_ReG = susp->s_fm_pHaSe; s_fm_x1_sample_reg = susp->s_fm_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; if (s_fm_pHaSe_ReG >= 1.0) { /* fixup-depends s_fm */ /* pick up next sample as s_fm_x1_sample: */ susp->s_fm_ptr++; susp_took(s_fm_cnt, 1); s_fm_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(s_fm, s_fm_ptr, s_fm_cnt, s_fm_x1_sample_reg); s_fm_x1_sample_reg = susp_current_sample(s_fm, s_fm_ptr); } table_index = (long) phase_reg; x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg + s_fm_x1_sample_reg; while (phase_reg > table_len_reg) phase_reg -= table_len_reg; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += table_len_reg; s_fm_pHaSe_ReG += s_fm_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->phase = phase_reg; susp->s_fm_pHaSe = s_fm_pHaSe_ReG; susp->s_fm_x1_sample = s_fm_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmosc_i_fetch */ void fmosc_r_fetch(register fmosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type s_fm_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double table_len_reg; register double ph_incr_reg; register sample_type * table_ptr_reg; register double phase_reg; falloc_sample_block(out, "fmosc_r_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->s_fm_pHaSe = 1.0; } susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* grab next s_fm_x1_sample when phase goes past 1.0; */ /* use s_fm_n (computed below) to avoid roundoff errors: */ if (susp->s_fm_n <= 0) { susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_pHaSe -= 1.0; /* s_fm_n gets number of samples before phase exceeds 1.0: */ susp->s_fm_n = (long) ((1.0 - susp->s_fm_pHaSe) * susp->output_per_s_fm); } togo = min(togo, susp->s_fm_n); s_fm_val = susp->s_fm_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; table_len_reg = susp->table_len; ph_incr_reg = susp->ph_incr; table_ptr_reg = susp->table_ptr; phase_reg = susp->phase; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double x1; table_index = (long) phase_reg; x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg + s_fm_val; while (phase_reg > table_len_reg) phase_reg -= table_len_reg; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += table_len_reg; } while (--n); /* inner loop */ susp->phase = phase_reg; out_ptr += togo; susp->s_fm_pHaSe += togo * susp->s_fm_pHaSe_iNcR; susp->s_fm_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* fmosc_r_fetch */ void fmosc_toss_fetch(susp, snd_list) register fmosc_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s_fm up to final_time for this block of zeros */ while ((round((final_time - susp->s_fm->t0) * susp->s_fm->sr)) >= susp->s_fm->current) susp_get_samples(s_fm, s_fm_ptr, s_fm_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s_fm->t0) * susp->s_fm->sr - (susp->s_fm->current - susp->s_fm_cnt)); susp->s_fm_ptr += n; susp_took(s_fm_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void fmosc_mark(fmosc_susp_type susp) { sound_xlmark(susp->s_fm); } void fmosc_free(fmosc_susp_type susp) { table_unref(susp->the_table); sound_unref(susp->s_fm); ffree_generic(susp, sizeof(fmosc_susp_node), "fmosc_free"); } void fmosc_print_tree(fmosc_susp_type susp, int n) { indent(n); stdputstr("s_fm:"); sound_print_tree_1(susp->s_fm, n); } sound_type snd_make_fmosc(sound_type s, double step, rate_type sr, double hz, time_type t0, sound_type s_fm, double phase) { register fmosc_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, fmosc_susp_node, "snd_make_fmosc"); susp->the_table = sound_to_table(s); susp->table_len = susp->the_table->length; susp->ph_incr = 0; susp->table_ptr = susp->the_table->samples; susp->phase = compute_phase(phase, step, (long) susp->table_len, s->sr, sr, hz, &susp->ph_incr); s_fm->scale *= hz != 0 ? (sample_type) (susp->ph_incr / hz) : s->sr / (sr * step_to_hz(step)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s_fm, sr); switch (interp_desc) { case INTERP_n: /* handled below */ case INTERP_s: susp->susp.fetch = fmosc_s_fetch; break; case INTERP_i: susp->susp.fetch = fmosc_i_fetch; break; case INTERP_r: susp->susp.fetch = fmosc_r_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s_fm->t0) sound_prepend_zeros(s_fm, t0); /* minimum start time over all inputs: */ t0_min = min(s_fm->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = fmosc_toss_fetch; } /* initialize susp state */ susp->susp.free = fmosc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = fmosc_mark; susp->susp.print_tree = fmosc_print_tree; susp->susp.name = "fmosc"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s_fm); susp->started = false; susp->susp.current = 0; susp->s_fm = s_fm; susp->s_fm_cnt = 0; susp->s_fm_pHaSe = 0.0; susp->s_fm_pHaSe_iNcR = s_fm->sr / sr; susp->s_fm_n = 0; susp->output_per_s_fm = sr / s_fm->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_fmosc(sound_type s, double step, rate_type sr, double hz, time_type t0, sound_type s_fm, double phase) { sound_type s_fm_copy = sound_copy(s_fm); return snd_make_fmosc(s, step, sr, hz, t0, s_fm_copy, phase); } nyquist-3.05/tran/instrbanded.c0000644000175000000620000001263611466723256015614 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrbanded.h" void bandedwg_free(); typedef struct bandedwg_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type bowpress_env; long bowpress_env_cnt; sample_block_values_type bowpress_env_ptr; struct instr *mybanded; int temp_ret_value; } bandedwg_susp_node, *bandedwg_susp_type; #include "instr.h" void bandedwg_s_fetch(register bandedwg_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mybanded_reg; register sample_type bowpress_env_scale_reg = susp->bowpress_env->scale; register sample_block_values_type bowpress_env_ptr_reg; falloc_sample_block(out, "bandedwg_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the bowpress_env input sample block: */ susp_check_term_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); togo = min(togo, susp->bowpress_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mybanded_reg = susp->mybanded; bowpress_env_ptr_reg = susp->bowpress_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(mybanded_reg, 2, BANDEDWG_CONTROL_CHANGE_CONST * (bowpress_env_scale_reg * *bowpress_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(mybanded_reg); } while (--n); /* inner loop */ susp->mybanded = mybanded_reg; /* using bowpress_env_ptr_reg is a bad idea on RS/6000: */ susp->bowpress_env_ptr += togo; out_ptr += togo; susp_took(bowpress_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* bandedwg_s_fetch */ void bandedwg_toss_fetch(susp, snd_list) register bandedwg_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from bowpress_env up to final_time for this block of zeros */ while ((round((final_time - susp->bowpress_env->t0) * susp->bowpress_env->sr)) >= susp->bowpress_env->current) susp_get_samples(bowpress_env, bowpress_env_ptr, bowpress_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->bowpress_env->t0) * susp->bowpress_env->sr - (susp->bowpress_env->current - susp->bowpress_env_cnt)); susp->bowpress_env_ptr += n; susp_took(bowpress_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void bandedwg_mark(bandedwg_susp_type susp) { sound_xlmark(susp->bowpress_env); } void bandedwg_free(bandedwg_susp_type susp) { deleteInstrument(susp->mybanded); sound_unref(susp->bowpress_env); ffree_generic(susp, sizeof(bandedwg_susp_node), "bandedwg_free"); } void bandedwg_print_tree(bandedwg_susp_type susp, int n) { indent(n); stdputstr("bowpress_env:"); sound_print_tree_1(susp->bowpress_env, n); } sound_type snd_make_bandedwg(double freq, sound_type bowpress_env, int preset, rate_type sr) { register bandedwg_susp_type susp; /* sr specified as input parameter */ time_type t0 = bowpress_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, bandedwg_susp_node, "snd_make_bandedwg"); susp->mybanded = initInstrument(BANDEDWG, round(sr)); controlChange(susp->mybanded, 16, preset);; susp->temp_ret_value = noteOn(susp->mybanded, freq, 1.0); susp->susp.fetch = bandedwg_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < bowpress_env->t0) sound_prepend_zeros(bowpress_env, t0); /* minimum start time over all inputs: */ t0_min = min(bowpress_env->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = bandedwg_toss_fetch; } /* initialize susp state */ susp->susp.free = bandedwg_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = bandedwg_mark; susp->susp.print_tree = bandedwg_print_tree; susp->susp.name = "bandedwg"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->bowpress_env = bowpress_env; susp->bowpress_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_bandedwg(double freq, sound_type bowpress_env, int preset, rate_type sr) { sound_type bowpress_env_copy = sound_copy(bowpress_env); return snd_make_bandedwg(freq, bowpress_env_copy, preset, sr); } nyquist-3.05/tran/gate.h0000644000175000000620000000050710144436365014230 0ustar stevestaffsound_type snd_make_gate(sound_type signal, time_type lookahead, double risetime, double falltime, double floor, double threshold); sound_type snd_gate(sound_type signal, time_type lookahead, double risetime, double falltime, double floor, double threshold); /* LISP: (snd-gate SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/white.h0000644000175000000620000000077010144436365014432 0ustar stevestaffsound_type snd_make_white(time_type t0, rate_type sr, time_type d); sound_type snd_white(time_type t0, rate_type sr, time_type d); /* LISP: (snd-white ANYNUM ANYNUM ANYNUM) */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 rbd all systems now use rand(), based on DM's modifications */ #include #include /* rand returns from 0 to RAND_MAX. Scale and offset * to get range from -1 to +1 */ #define rand_scale (2.0/RAND_MAX) nyquist-3.05/tran/sqrt.h0000644000175000000620000000016410144436365014300 0ustar stevestaffsound_type snd_make_sqrt(sound_type input); sound_type snd_sqrt(sound_type input); /* LISP: (snd-sqrt SOUND) */ nyquist-3.05/tran/alpasscv.alg0000644000175000000620000000151310144436365015436 0ustar stevestaff(ALPASSCV-ALG (NAME "alpasscv") (ARGUMENTS ("sound_type" "input") ("time_type" "delay") ("sound_type" "feedback")) (START (MAX input feedback)) (STATE ("long" "delaylen" "max(1, round(input->sr * delay))") ("sample_type *" "delaybuf" "(sample_type *) calloc (susp->delaylen, sizeof(sample_type))") ("sample_type *" "delayptr" "susp->delaybuf") ("sample_type *" "endptr" "susp->delaybuf + susp->delaylen")) (CONSTANT "delaylen" "endptr") (NOT-REGISTER delaybuf) (LINEAR input) (TERMINATE (MIN input)) (INNER-LOOP-LOCALS "register sample_type y, z, fb;\n") (INNER-LOOP " y = *delayptr; *delayptr++ = z = (sample_type) ((fb = feedback) * y + input); output = (sample_type) (y - fb * z); if (delayptr >= endptr) delayptr = susp->delaybuf;") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/instrfluteall.h0000644000175000000620000000075411466723256016212 0ustar stevestaffsound_type snd_make_flute_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type jet_delay, sound_type noise, rate_type sr); sound_type snd_flute_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type jet_delay, sound_type noise, rate_type sr); /* LISP: (snd-flute_all ANYNUM SOUND SOUND ANYNUM ANYNUM SOUND SOUND ANYNUM) */ #define FLUTE_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/follow.h0000644000175000000620000000042610144436365014612 0ustar stevestaffsound_type snd_make_follow(sound_type sndin, double floor, double risetime, double falltime, long lookahead); sound_type snd_follow(sound_type sndin, double floor, double risetime, double falltime, long lookahead); /* LISP: (snd-follow SOUND ANYNUM ANYNUM ANYNUM FIXNUM) */ nyquist-3.05/tran/resonvv.alg0000644000175000000620000000320410144436365015323 0ustar stevestaff(RESONVV-ALG (NAME "resonvv") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz1") ("sound_type" "bw") ("int" "normalization")) (INLINE-INTERPOLATION T) (ALWAYS-SCALE hz1 bw) (START (MAX s1 hz1 bw)) (TERMINATE (MIN s1 hz1 bw)) (LOGICAL-STOP (MIN s1)) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION hz1 bw) (STATE ("double" "scale1" "s1->scale") ("double" "c3co" "0.0") ("double" "c3p1" "0.0") ("double" "c3t4" "0.0") ("double" "omc3" "0.0") ("double" "coshz" "0.0") ("double" "c2" "0.0") ("double" "c1" "0.0") ("boolean" "recompute" "false") ("int" "normalization" "normalization") ("double" "y1" "0.0") ("double" "y2" "0.0; hz1->scale = (sample_type) (hz1->scale * (PI2 / s1->sr)); bw->scale = (sample_type) (bw->scale * (-PI2 / s1->sr));")) (DEPENDS ("c3co" "bw" "exp(bw)") ("c3p1" "bw" "c3co + 1.0") ("c3t4" "bw" "c3co * 4.0") ("omc3" "bw" "1.0 - c3co") ("recompute" "bw" "true") ("coshz" "hz1" "cos(hz1)") ("recompute" "hz1" "true")) (JOINT-DEPENDENCY (("hz1" "bw") "if (recompute) {" " recompute = false;" " c2 = c3t4 * coshz / c3p1;" " c1 = (normalization == 0 ? 1.0 :" " (normalization == 1 ? omc3 * sqrt(1.0 - c2 * c2 / c3t4) :" " sqrt(c3p1 * c3p1 - c2 * c2) * omc3 / c3p1)) * scale1;" "}")) (CONSTANT "c1" "c2" "c3co" "coshz" "c3p1" "c3t4" "omc3" "normalization" "scale1") (FORCE-INTO-REGISTER recompute) ;c3t4 c3p1 normalization omc3 scale1 (INNER-LOOP "{ double y0 = c1 * s1 + c2 * y1 - c3co * y2; output = (sample_type) y0; y2 = y1; y1 = y0; }") ) nyquist-3.05/tran/maxv.alg0000644000175000000620000000043710144436365014601 0ustar stevestaff(MAXV-ALG (NAME "maxv") (ARGUMENTS ("sound_type" "s1") ("sound_type" "s2")) (ALWAYS-SCALE s1 s2) (START (MAX s1 s2)) (INNER-LOOP "double x1 = s1; double x2 = s2; output = (sample_type) (x1 > x2 ? x1 : x2)") (TERMINATE (MIN s1 s2)) (LOGICAL-STOP (MIN s1 s2)) ) nyquist-3.05/tran/resonvv.c0000644000175000000620000031376310144436365015020 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "resonvv.h" void resonvv_free(); typedef struct resonvv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type hz1; long hz1_cnt; sample_block_values_type hz1_ptr; /* support for interpolation of hz1 */ sample_type hz1_x1_sample; double hz1_pHaSe; double hz1_pHaSe_iNcR; /* support for ramp between samples of hz1 */ double output_per_hz1; long hz1_n; sound_type bw; long bw_cnt; sample_block_values_type bw_ptr; /* support for interpolation of bw */ sample_type bw_x1_sample; double bw_pHaSe; double bw_pHaSe_iNcR; /* support for ramp between samples of bw */ double output_per_bw; long bw_n; double scale1; double c3co; double c3p1; double c3t4; double omc3; double coshz; double c2; double c1; boolean recompute; int normalization; double y1; double y2; } resonvv_susp_node, *resonvv_susp_type; void resonvv_nss_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nss_fetch */ void resonvv_nsi_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nsi_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nsi_fetch */ void resonvv_nsr_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nsr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nsr_fetch */ void resonvv_nis_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nis_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nis_fetch */ void resonvv_nii_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nii_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nii_fetch */ void resonvv_nir_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nir_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nir_fetch */ void resonvv_nrs_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nrs_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nrs_fetch */ void resonvv_nri_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nri_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nri_fetch */ void resonvv_nrr_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_nrr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; susp->bw_pHaSe = 1.0; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; if (susp->recompute) { susp->recompute = false; susp->c2 = susp->c3t4 * susp->coshz / susp->c3p1; susp->c1 = (susp->normalization == 0 ? 1.0 : (susp->normalization == 1 ? susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)) * susp->scale1; } /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_nrr_fetch */ void resonvv_sss_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_sss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_sss_fetch */ void resonvv_ssi_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_ssi_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_ssi_fetch */ void resonvv_ssr_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_ssr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_ssr_fetch */ void resonvv_sis_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_sis_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_sis_fetch */ void resonvv_sii_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_sii_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_sii_fetch */ void resonvv_sir_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_sir_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_sir_fetch */ void resonvv_srs_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_srs_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_srs_fetch */ void resonvv_sri_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_sri_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_sri_fetch */ void resonvv_srr_fetch(register resonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register double y1_reg; register double y2_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvv_srr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; susp->bw_pHaSe = 1.0; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; if (susp->recompute) { susp->recompute = false; susp->c2 = susp->c3t4 * susp->coshz / susp->c3p1; susp->c1 = (susp->normalization == 0 ? 1.0 : (susp->normalization == 1 ? susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)) * susp->scale1; } /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { double y0 = c1_reg * (s1_scale_reg * *s1_ptr_reg++) + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvv_srr_fetch */ void resonvv_toss_fetch(susp, snd_list) register resonvv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from hz1 up to final_time for this block of zeros */ while ((round((final_time - susp->hz1->t0) * susp->hz1->sr)) >= susp->hz1->current) susp_get_samples(hz1, hz1_ptr, hz1_cnt); /* fetch samples from bw up to final_time for this block of zeros */ while ((round((final_time - susp->bw->t0) * susp->bw->sr)) >= susp->bw->current) susp_get_samples(bw, bw_ptr, bw_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->hz1->t0) * susp->hz1->sr - (susp->hz1->current - susp->hz1_cnt)); susp->hz1_ptr += n; susp_took(hz1_cnt, n); n = round((final_time - susp->bw->t0) * susp->bw->sr - (susp->bw->current - susp->bw_cnt)); susp->bw_ptr += n; susp_took(bw_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void resonvv_mark(resonvv_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->hz1); sound_xlmark(susp->bw); } void resonvv_free(resonvv_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->hz1); sound_unref(susp->bw); ffree_generic(susp, sizeof(resonvv_susp_node), "resonvv_free"); } void resonvv_print_tree(resonvv_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("hz1:"); sound_print_tree_1(susp->hz1, n); indent(n); stdputstr("bw:"); sound_print_tree_1(susp->bw, n); } sound_type snd_make_resonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization) { register resonvv_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(max(s1->t0, hz1->t0), bw->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, resonvv_susp_node, "snd_make_resonvv"); susp->scale1 = s1->scale; susp->c3co = 0.0; susp->c3p1 = 0.0; susp->c3t4 = 0.0; susp->omc3 = 0.0; susp->coshz = 0.0; susp->c2 = 0.0; susp->c1 = 0.0; susp->recompute = false; susp->normalization = normalization; susp->y1 = 0.0; susp->y2 = 0.0; hz1->scale = (sample_type) (hz1->scale * (PI2 / s1->sr)); bw->scale = (sample_type) (bw->scale * (-PI2 / s1->sr));; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(hz1, sr); interp_desc = (interp_desc << 2) + interp_style(bw, sr); switch (interp_desc) { case INTERP_nnn: /* handled below */ case INTERP_nns: /* handled below */ case INTERP_nsn: /* handled below */ case INTERP_nss: susp->susp.fetch = resonvv_nss_fetch; break; case INTERP_nni: /* handled below */ case INTERP_nsi: susp->susp.fetch = resonvv_nsi_fetch; break; case INTERP_nnr: /* handled below */ case INTERP_nsr: susp->susp.fetch = resonvv_nsr_fetch; break; case INTERP_nin: /* handled below */ case INTERP_nis: susp->susp.fetch = resonvv_nis_fetch; break; case INTERP_nii: susp->susp.fetch = resonvv_nii_fetch; break; case INTERP_nir: susp->susp.fetch = resonvv_nir_fetch; break; case INTERP_nrn: /* handled below */ case INTERP_nrs: susp->susp.fetch = resonvv_nrs_fetch; break; case INTERP_nri: susp->susp.fetch = resonvv_nri_fetch; break; case INTERP_nrr: susp->susp.fetch = resonvv_nrr_fetch; break; case INTERP_snn: /* handled below */ case INTERP_sns: /* handled below */ case INTERP_ssn: /* handled below */ case INTERP_sss: susp->susp.fetch = resonvv_sss_fetch; break; case INTERP_sni: /* handled below */ case INTERP_ssi: susp->susp.fetch = resonvv_ssi_fetch; break; case INTERP_snr: /* handled below */ case INTERP_ssr: susp->susp.fetch = resonvv_ssr_fetch; break; case INTERP_sin: /* handled below */ case INTERP_sis: susp->susp.fetch = resonvv_sis_fetch; break; case INTERP_sii: susp->susp.fetch = resonvv_sii_fetch; break; case INTERP_sir: susp->susp.fetch = resonvv_sir_fetch; break; case INTERP_srn: /* handled below */ case INTERP_srs: susp->susp.fetch = resonvv_srs_fetch; break; case INTERP_sri: susp->susp.fetch = resonvv_sri_fetch; break; case INTERP_srr: susp->susp.fetch = resonvv_srr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < hz1->t0) sound_prepend_zeros(hz1, t0); if (t0 < bw->t0) sound_prepend_zeros(bw, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(hz1->t0, min(bw->t0, t0))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = resonvv_toss_fetch; } /* initialize susp state */ susp->susp.free = resonvv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = resonvv_mark; susp->susp.print_tree = resonvv_print_tree; susp->susp.name = "resonvv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->hz1 = hz1; susp->hz1_cnt = 0; susp->hz1_pHaSe = 0.0; susp->hz1_pHaSe_iNcR = hz1->sr / sr; susp->hz1_n = 0; susp->output_per_hz1 = sr / hz1->sr; susp->bw = bw; susp->bw_cnt = 0; susp->bw_pHaSe = 0.0; susp->bw_pHaSe_iNcR = bw->sr / sr; susp->bw_n = 0; susp->output_per_bw = sr / bw->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_resonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization) { sound_type s1_copy = sound_copy(s1); sound_type hz1_copy = sound_copy(hz1); sound_type bw_copy = sound_copy(bw); return snd_make_resonvv(s1_copy, hz1_copy, bw_copy, normalization); } nyquist-3.05/tran/fromarraystream.c0000644000175000000620000001167210144436365016526 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "fromarraystream.h" void fromarraystream_free(); typedef struct fromarraystream_susp_struct { snd_susp_node susp; long index; long length; LVAL array; LVAL src; sample_type *samples; } fromarraystream_susp_node, *fromarraystream_susp_type; /* IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either an * array of samples or NIL. The output of ifft is simply the * concatenation of the samples taken from the array. Later, * an ifft will be plugged in and this will return overlapped * adds of the ifft's. */ #include "samples.h" void fromarraystream__fetch(register fromarraystream_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long index_reg; register sample_type * samples_reg; falloc_sample_block(out, "fromarraystream__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->index >= susp->length) { long i; susp->index = 0; susp->array = xleval(cons(s_send, cons(susp->src, consa(s_next)))); susp->index = 0; if (susp->array == NULL) { susp->src = NULL; goto out; } else if (!vectorp(susp->array)) { xlerror("array expected", susp->array); } else if (susp->samples == NULL) { /* assume arrays are all the same size as first one; now that we know the size, we just have to do this first allocation. */ susp->length = getsize(susp->array); if (susp->length < 1) xlerror("array has no elements", susp->array); susp->samples = (sample_type *) calloc(susp->length, sizeof(sample_type)); } else if (getsize(susp->array) != susp->length) { xlerror("arrays must all be the same length", susp->array); } /* at this point, we have a new array and a place to put samples */ for (i = 0; i < susp->length; i++) { LVAL elem = getelement(susp->array, i); if (ntype(elem) != FLONUM) { xlerror("flonum expected", elem); } susp->samples[i] = (sample_type) getflonum(elem); } susp->array = NULL; /* free the array */ } togo = min(togo, susp->length - susp->index); n = togo; index_reg = susp->index; samples_reg = susp->samples; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = samples_reg[index_reg++];; } while (--n); /* inner loop */ susp->index = index_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* fromarraystream__fetch */ void fromarraystream_mark(fromarraystream_susp_type susp) { if (susp->src) mark(susp->src); if (susp->array) mark(susp->array); } void fromarraystream_free(fromarraystream_susp_type susp) { free(susp->samples); ffree_generic(susp, sizeof(fromarraystream_susp_node), "fromarraystream_free"); } void fromarraystream_print_tree(fromarraystream_susp_type susp, int n) { } sound_type snd_make_fromarraystream(time_type t0, rate_type sr, LVAL src) { register fromarraystream_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, fromarraystream_susp_node, "snd_make_fromarraystream"); susp->index = 0; susp->length = 0; susp->array = NULL; susp->src = src; susp->samples = NULL;; susp->susp.fetch = fromarraystream__fetch; /* initialize susp state */ susp->susp.free = fromarraystream_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = fromarraystream_mark; susp->susp.print_tree = fromarraystream_print_tree; susp->susp.name = "fromarraystream"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_fromarraystream(time_type t0, rate_type sr, LVAL src) { return snd_make_fromarraystream(t0, sr, src); } nyquist-3.05/tran/osc.alg0000644000175000000620000000201410144436365014403 0ustar stevestaff(OSC-ALG (NAME "osc") (ARGUMENTS ("sound_type" "input") ("double" "step") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("time_type" "d") ("double" "phase")) (TABLE "input") (NOT-IN-INNER-LOOP "input") (STATE ("double" "ph_incr" "0") ("table_type" "the_table" "sound_to_table(input)") ("sample_type *" "table_ptr" "susp->the_table->samples") ("double" "table_len" "susp->the_table->length") ("double" "phase" "compute_phase(phase, step, (long) susp->table_len, input->sr, sr, hz, &susp->ph_incr)") ) ; "((hz * susp->table_len) / sr)") (TERMINATE (AFTER "d")) (INNER-LOOP " long table_index = (long) phase; double x1 = table_ptr[table_index]; output = (sample_type) (x1 + (phase - table_index) * (table_ptr[table_index + 1] - x1)); phase += ph_incr; while (phase >= table_len) phase -= table_len; ") (CONSTANT "ph_incr" "table_len" "table_ptr") (SAMPLE-RATE "sr") (FINALIZATION " table_unref(susp->the_table); ") ) nyquist-3.05/tran/shape.h0000644000175000000620000000027410144436365014411 0ustar stevestaffsound_type snd_make_shape(sound_type sin, sound_type fn, double origin); sound_type snd_shape(sound_type sin, sound_type fn, double origin); /* LISP: (snd-shape SOUND SOUND ANYNUM) */ nyquist-3.05/tran/atone.c0000644000175000000620000002137010144436365014412 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "atone.h" void atone_free(); typedef struct atone_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; double cc; double prev; } atone_susp_node, *atone_susp_type; void atone_n_fetch(register atone_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double cc_reg; register double prev_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "atone_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; cc_reg = susp->cc; prev_reg = susp->prev; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double current; current = *s_ptr_reg++; prev_reg = cc_reg * (prev_reg + current); /* use prev_reg as temp variable ... */ *out_ptr_reg++ = (float) prev_reg; /* ... so we can do proper type conversion */ prev_reg -= current;; } while (--n); /* inner loop */ susp->prev = prev_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* atone_n_fetch */ void atone_s_fetch(register atone_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double cc_reg; register double prev_reg; register sample_type s_scale_reg = susp->s->scale; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "atone_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; cc_reg = susp->cc; prev_reg = susp->prev; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double current; current = (s_scale_reg * *s_ptr_reg++); prev_reg = cc_reg * (prev_reg + current); /* use prev_reg as temp variable ... */ *out_ptr_reg++ = (float) prev_reg; /* ... so we can do proper type conversion */ prev_reg -= current;; } while (--n); /* inner loop */ susp->prev = prev_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* atone_s_fetch */ void atone_toss_fetch(susp, snd_list) register atone_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s up to final_time for this block of zeros */ while ((round((final_time - susp->s->t0) * susp->s->sr)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void atone_mark(atone_susp_type susp) { sound_xlmark(susp->s); } void atone_free(atone_susp_type susp) { sound_unref(susp->s); ffree_generic(susp, sizeof(atone_susp_node), "atone_free"); } void atone_print_tree(atone_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_atone(sound_type s, double hz) { register atone_susp_type susp; double bb; rate_type sr = s->sr; time_type t0 = s->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, atone_susp_node, "snd_make_atone"); bb = 2.0 - cos(hz * PI2 / s->sr); susp->cc = bb - sqrt((bb * bb) - 1.0); susp->prev = 0.0; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = atone_n_fetch; break; case INTERP_s: susp->susp.fetch = atone_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); /* minimum start time over all inputs: */ t0_min = min(s->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = atone_toss_fetch; } /* initialize susp state */ susp->susp.free = atone_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = atone_mark; susp->susp.print_tree = atone_print_tree; susp->susp.name = "atone"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_atone(sound_type s, double hz) { sound_type s_copy = sound_copy(s); return snd_make_atone(s_copy, hz); } nyquist-3.05/tran/resonvc.alg0000644000175000000620000000234610144436365015306 0ustar stevestaff(RESONVC-ALG (NAME "resonvc") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz") ("double" "bw") ("int" "normalization")) (INLINE-INTERPOLATION T) (INTERNAL-SCALING s1) (ALWAYS-SCALE hz) (START (MAX s1 hz)) (TERMINATE (MIN s1 hz)) (LOGICAL-STOP (MIN s1)) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION hz) (STATE ("double" "scale1" "s1->scale") ("double" "c3co" "exp(bw * -PI2 / s1->sr)") ("double" "c3p1" "susp->c3co + 1.0") ("double" "c3t4" "susp->c3co * 4.0") ("double" "omc3" "1.0 - susp->c3co") ("double" "c2" "0.0") ("double" "c1" "0.0") ("int" "normalization" "normalization") ("double" "y1" "0.0") ("double" "y2" "0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr))")) (DEPENDS ("c2" "hz" "c3t4 * cos(hz) / c3p1") ("c1" "hz" "(normalization == 0 ? scale1 : (normalization == 1 ? omc3 * sqrt(1.0 - c2 * c2 / c3t4) : sqrt(c3p1 * c3p1 - c2 * c2) * omc3 / c3p1)) * scale1")) (CONSTANT "c1" "c2" "c3co" "c3p1" "c3t4" "omc3" "normalization" "scale1") (FORCE-INTO-REGISTER c3t4 c3p1 normalization omc3 scale1) (INNER-LOOP "{ double y0 = c1 * s1 + c2 * y1 - c3co * y2; output = (sample_type) y0; y2 = y1; y1 = y0; }") ) nyquist-3.05/tran/translate.lsp0000644000175000000620000007701011466723256015665 0ustar stevestaff;************* ; Change Log ; Date | Change ;-----------+------------------------------------ ; 18-Dec-91 | [1.2] Created ; 18-Dec-91 | [1.2] added *ANSI* tests ; 13-Jan-92 | [1.2] ANSI header includes stdlib.h, excludes decl of ; | malloc ; 13-Jan-92 | [1.2] upgraded to support new sound block structure ; 15-Jan-92 | [1.2] added declarations for UNKNOWN, isunknown() ; 15-Jan-92 | [1.2] commented out boolean, true, false now declared ; | in sound.h ;************* ;; translate.lsp -- build signal processing code from high level descr. (setf *ANSI* t) (setf *debug* t) ;;********** ;; combinations - generate all combinations ;; Inputs: ;; n - number of combinations to generate ;; Result: ;; list of the form ;; ( (a1 b1) (a2 b2) (a3 b3) ... (an bn) ) ;; ;;********** (defun combinations (n) (let (comb) (cond ((eq n 0) '(nil)) (t (setf comb (combinations (1- n))) (append (insert 'ramp comb) (insert 'interp comb) (insert 'scale comb) (insert 'none comb)))))) (print 'comb) (defun lt () (load "translate")) (defun ls () (load "writesusp")) (defun lm () (load "writemake")) (defun lo () (load "writetoss")) (defun li () (load "innerloop")) (defun ma () (translate "partial")) (defun mb () (translate "buzz")) (defun mal () (translate "alpass")) (defun macv () (translate "alpasscv")) (defun mavv () (translate "alpassvv")) (defun mf () (translate "follow")) (defun mfas () (translate "fromarraystream")) (defun mfo () (translate "fromobject")) (defun mp () (translate "prod")) (defun mc () (translate "const")) (defun mct () (translate "coterm")) (defun mcl () (translate "clip")) (defun meqb () (translate "eqbandvvv")) (defun me () (translate "exp")) (defun mg () (translate "gate")) ;(defun mr () (translate "ramp")) (defun ms () (translate "sine")) (defun msh () (translate "shape")) (defun mpw () (translate "pwl")) ;(defun msfr () (translate "sfread")) (defun mde () (translate "delaycc")) (defun mdcv () (translate "delaycv")) ; note: downproto is hand retouched to make downsample ;(defun md () (translate "downproto")) (defun mu () (translate "upsample")) (defun ml () (translate "scale")) (defun mlo () (translate "log")) (defun mm () (translate "maxv")) (defun mo () (translate "osc")) (defun mof () (translate "offset")) (defun mam () (translate "amosc")) (defun mfm () (translate "fmosc")) (defun mi () (translate "integrate")) (defun msl () (translate "slope")) (defun mw () (translate "white")) (defun mt () (translate "tone")) (defun mta () (translate "tapv")) (defun mtf () (translate "tapf")) (defun mat () (translate "atone")) (defun mre () (translate "reson")) (defun mrec () (translate "recip")) (defun mar () (translate "areson")) (defun mtv () (translate "tonev")) (defun matv () (translate "atonev")) (defun mrvc () (translate "resonvc")) (defun mrcv () (translate "resoncv")) (defun marvc () (translate "aresonvc")) (defun marcv () (translate "aresoncv")) (defun mrvv () (translate "resonvv")) (defun marvv () (translate "aresonvv")) (defun msa () (translate "sampler")) (defun msio () (translate "siosc")) (defun mq () (translate "quantize")) (defun mbq () (translate "biquadfilt")) (defun mabs () (translate "abs")) (defun msqrt () (translate "sqrt")) (defun mifft () (translate "ifft")) (defun mcg () (translate "congen")) (defun mcv () (translate "convolve")) ;; this does not generate the final version ;; see the hand-modified version of convolve.c in nyqsrc directory (defun mos () (translate "oneshot")) (defun mch () (translate "chase")) (defun mpl () (translate "pluck")) (defun icl () (translate "instrclar")) (defun isx () (translate "instrsax")) (defun icla () (translate "instrclarall")) (defun isxa () (translate "instrsaxall")) (defun iclf () (translate "instrclarfreq")) (defun isxf () (translate "instrsaxfreq")) (defun mla () (translate "allpoles")) (defun mlr () (translate "lpreson")) (defun mstk () (icl) (isx) (icla) (isxa) (iclf) (isxf)) (defun mfmfb () (translate "fmfb") (translate "fmfbv")) (defun m () (mf) (mp) (mc) (mcl) (mg) ;;;;;; (mr) (msfr) (md) (mm) (ms) (msh) (mpw) (ma) (mb) (mde) (mdcv) (mi) (mu) (ml) (mlo) (mo) (mof) (mam) (mfm) (mw) (msl) (mt) (mat) (mre) (mrec) (mar) (mtv) (mta) (mtf) (matv) (mrvc) (mrcv) (marvc) (marcv) (mrvv) (marvv) (me) (msa) (msio) (mq) (mcg) (mifft) (mfas) (mfo) (mct) (mal) (mos) (mch) (mbq) (mpl) (mabs) (msqrt) (macv) (mavv) ; (mcv) must be managed by hand (mstk) (mla) (mlr) (load "translate-stk") (mfmfb)) ; call this when you change writesusp.lsp: "N"ew "S"usp (defun ns () (ls) (m)) ; call this when you change writemake.lsp: (defun nm () (lm) (m)) ; call this when you change innerloop.lsp: (defun ni () (li) (m)) ;;********** ;; any-ramp-in -- see if interpolation-list has 'ramp ;; ;; note: lis is a list of lists of atoms ;;********** (defun any-ramp-in (lis) (dolist (spec lis) (cond ((member 'RAMP spec) (return t))))) ;;********** ;; any-ramp-or-interp-in -- see if interpolation-list has 'ramp or 'interp ;; ;;********** (defun any-ramp-or-interp-in (lis) (or (any-ramp-in lis) (dolist (spec lis) (cond ((member 'INTERP spec) (return t)))))) ;;********** ;; encode -- come up with ascii string for interp spec ;; ;; e.g. (none ramp) -> "nr" ;; ;;********** (defun encode (interpolation) (let (first-letter (result "")) (dolist (interp interpolation) (setf first-letter (string (char (symbol-name interp) 0))) (setf result (strcat result first-letter))) (string-downcase result))) ;; **************** ;; header-list ;; ;; Result: ;; '( "s1" "s2" ... "sn" ) ;; where s1, s2, etc. are the strings for the header part of the ;; resulting .c file ;; Notes: ;; Kludgy. Fix this up for easier maintenance ;; **************** (if *ANSI* ; ANSI (setf header-list '("#include \"stdio.h\"\n" "#ifndef mips\n" "#include \"stdlib.h\"\n" "#endif\n" "#include \"xlisp.h\"\n" "#include \"sound.h\"\n\n" "#include \"falloc.h\"\n" "#include \"cext.h\"\n" )) ; non-ANSI (setf header-list '("#include \"stdio.h\"\n" "#include \"xlisp.h\"\n" "#include \"sound.h\"\n" "#include \"falloc.h\"\n"))) (setf h-boilerplate nil) ;--------------obsolete boilerplate------------- ;; Note that we use "-1" and "< 0". We rely upon C's semantics to ;; make this work correctly if it is being assigned to a long, float, or ;; double, and if a long, float, or double is being compared ; '("\n#ifndef UNKNOWN\n" ; "#define UNKNOWN -1\n" ; "#define isunknown(x) ( (x) < 0)\n" ; "#endif /* UNKNOWN */\n")) ;------------------------- ;;********** ;; code-gen -- do the output ;; ;; Inputs: ;; alg - ;; stream - ;; hstream - ;;********** (defun code-gen (alg stream hstream) (let (interpolation-list (support-functions (get-slot alg 'support-functions)) (support-header (get-slot alg 'support-header)) (name (get-slot alg 'name))) ;(display "code-gen: " alg stream hstream) (print-strings header-list stream) (format stream "#include \"~A\"~%" (get-slot alg 'hfile)) (display "code-gen: printed header") (format stream "~%void ~A_free();~%" name) (setf interpolation-list (make-interpolation-list alg)) (display "code-gen: " interpolation-list) (put-slot alg interpolation-list 'interpolation-list) (put-slot alg (make-interpolation-rationale alg) 'interpolation-rationale) (write-typedef alg stream) (display "code-gen: wrote typedef") (cond (support-functions (format stream "~%~A" support-functions))) (dolist (interpolation interpolation-list) (put-slot alg interpolation 'interpolation) (display "code-gen: going to write susp for " interpolation) (write-susp alg stream) (display "code-gen: wrote susp for" interpolation)) ;; this is a special case for no sound arguments (cond ((null interpolation-list) (write-susp alg stream))) ;; write the function that is called to read and toss ;; samples up to the start time (but only if there are sound arguments) (cond ((get-slot alg 'sound-names) (write-toss alg stream))) ;; write the GC marking function (cond ((needs-mark-routine alg) (write-mark alg stream))) (write-make alg stream) (display "code-gen: wrote make") (write-xlmake alg stream) (display "code-gen: wrote xlmake") (write-header alg hstream) (cond ( support-header (print-strings support-header hstream))) (print-strings h-boilerplate hstream) (display "code-gen: wrote header"))) ;;********** ;; commute-check -- ;; ;; Purpose: ;; see if interpolation spec is redundant due to commutativity ;; Algorithm: ;; for each list of "commutable" sounds, make sure spec asks for ;; cannonical ordering: NONE > SCALE > INTERP > RAMP ;;********** (defun commute-check (alg spec) (let ((sounds (get-slot alg 'sound-args)) (commute-list (get-slot alg 'commutative)) (result t) s1 s2) (dolist (commute commute-list) (dotimes (n (1- (length commute))) ; look at all pairs (setf s1 (nth n commute)) (setf s2 (nth (1+ n) commute)) (setf s1 (index s1 sounds)) (setf s2 (index s2 sounds)) (setf s1 (nth s1 spec)) (setf s2 (nth s2 spec)) (cond ((< (eval s1) (eval s2)) (setf result nil) (return))))) result)) (setf NONE 4) (setf SCALE 3) (setf INTERP 2) (setf RAMP 1) (print 'ramp) ;;********** ;; concatenate -- string concatenation ;; ;; Inputs: ;; "s1" - string ;; "s2" - string ;; Result: ;; "s1s2" ;;********** (defun concatenate (type s1 s2) (cond ((eq type 'string) (strcat s1 s2)) (t (error "concatenate type")))) ;;********** ;; get-slot -- access the algorithm description, return single value ;; ;;********** (setfn get-slot get) ;;********** ;; index -- find location of list element ;; ;; Inputs: ;; atom - atom to be found in list ;; lis - list searched for ;; Result: ;; integer - index of atom in lis ;; NIL - atom not member of lis ;;********** (defun index (atom lis) (let ((i 0)) (dolist (elt lis) (cond ((eq elt atom) (return i))) (setf i (1+ i))))) ;;********** ;; insert -- insert an atom at the front of each element of a list ;; ;; Inputs: ;; atom - ;; list-of-lists - lists of the form ( (L1) (L2) ... (Ln)) ;; Result: ;; ( (atom L1) (atom L2) ... (atom Ln) ) ;;********** (defun insert (atom list-of-lists) (mapcar '(lambda (lis) (cons atom lis)) list-of-lists)) (print 'insert) ;; interp-check -- check to see that no interpolation is being done ;; (unless the algorithm is the up-sample algorithm, a special case ;; (defun interp-check (alg spec) (or *INLINE-INTERPOLATION* (get alg 'inline-interpolation) (and (not (member 'INTERP spec)) (not (member 'RAMP spec))))) (print 'interp-check) ;;********** ;; make-interpolation-list -- figure out the possible interpolation forms ;; ;; Inputs: ;; alg - algorithm description ;; Output: ;; List of interpolation styles, e.g. ;; ((NONE NONE) (NONE INTERP) (NONE RAMP)), where the styles ;; are in the same order as the sound arguments (sound-args) ;; ;;********** (defun make-interpolation-list (alg) (let (sound-args specs real-specs sound-names sound-to-name (sr (get-slot alg 'sample-rate)) (not-in-inner-loop (get-slot alg 'not-in-inner-loop))) ; derive some lists: ; sound-args are atom names of sound-type arguments ; sound-names are the corresponding string names ; sound-to-name is an assoc list mapping atom to case-sensitive string ; (display "make-interpolation-list") (dolist (arg (get-slot alg 'arguments)) (cond ((and (equal (car arg) "sound_type") (not (member (cadr arg) not-in-inner-loop :test #'equal))) (setf sound-names (cons (cadr arg) sound-names)) (setf sound-args (cons (name-to-symbol (cadr arg)) sound-args)) (setf sound-to-name (cons (cons (car sound-args) (car sound-names)) sound-to-name)) ; (display "in make-interpolation-list" sound-to-name) ))) ; (display "make-interpolation-list: " (reverse sound-args)) (put-slot alg (reverse sound-args) 'sound-args) ; (display "make-interpolation-list: " (reverse sound-names)) (put-slot alg (reverse sound-names) 'sound-names) (put-slot alg sound-to-name 'sound-to-name) ; make all combinations of interpolations (setf specs (combinations (length sound-args))) ;; don't print this or you'll die when the list is huge ;; (display "make-interpolation-list: " specs) ;; we really should have filtered with match-check inside combinations ;; to avoid exponential explosion ; reject combinations based on commutativity, linearity, and sample rate: ; if sample-rate is not specified, then some interpolation must be 'NONE, ; i.e. sample-rate is specified OR an interpolation is 'NONE: ; if INLINE-INTERPOLATION is turned off, don't allow RAMP or INTERP ; if INTERNAL-SCALING applies, then don't allow SCALE (dolist (spec specs) (cond ((and spec (interp-check alg spec) (commute-check alg spec) (scale-check alg spec) (match-check alg spec) (sr-check alg spec)) (setf real-specs (cons spec real-specs))))) (cond ((and (car specs) (null real-specs)) (error "no interpolation specs"))) (print real-specs))) ; MAKE-INTERPOLATION-RATIONALE -- record the rationale for ; interpolation combinations: ; NIL means no special considerations ; ALWAYS-SCALE means 'n' eliminated, use 's' instead ; LINEAR means 's' eliminated and unnecessary ; INTERNAL-SCALING means 's' eliminated, use 'n' instead ; (defun make-interpolation-rationale (alg) (let (interpolation-rationale len snd (sounds (get-slot alg 'sound-args)) (linear (get-slot alg 'linear)) (internal-scaling (get-slot alg 'internal-scaling)) (always-scale (get-slot alg 'always-scale))) (setf interpolation-rationale (mapcar #'return-nil sounds)) (setf len (length interpolation-rationale)) (dotimes (n len) (setf snd (nth n sounds)) (cond ((member snd always-scale) (setf (nth n interpolation-rationale) 'ALWAYS-SCALE))) (cond ((member snd linear) (cond ((nth n interpolation-rationale) (error "parameter is both linear and always-scale" snd))) (setf (nth n interpolation-rationale) 'LINEAR))) (cond ((member snd internal-scaling) (cond ((nth n interpolation-rationale) (error "parameter is both linear and always-scale or internal-scaling" snd))) (setf (nth n interpolation-rationale) 'INTERNAL-SCALING)))) (display "make-interpolation-rationale" interpolation-rationale) interpolation-rationale)) (print 'hi) ;;********** ;; make-schema-from-slots -- take attr/value pairs and make property list ;; ;; Inputs: ;; slots - a list of the form ;; (name ;; (attribute1 value1) (attribute2 value2) ;; ... (attributen valuen) ) ;; Result: ;; The atom 'name' with the attached property list ;; Effect: ;; Adds properties to the atom 'name' based on the attribute-value ;; pairs. ;; Notes: ;; The property-list representation is chosen for time efficiency of ;; access ;;********** (defun make-schema-from-slots (slots) (let ((name (car slots))) (setf (symbol-plist name) nil) (dolist (slot (cdr slots)) (putprop name (cdr slot) (car slot))) name)) ;;**************** ;; name-to-symbol -- convert from case-sensitive C name to internal symbol ;;**************** (defun name-to-symbol (name) (intern (string-upcase name))) ;;********** ;; position -- find a pattern in a string ;; ;; Inputs: ;; s - ;; p - ;;********** (defun position (s p) (let (result (len (length p))) (dotimes (n (+ 1 (length s) (- len))) (cond ((equal (subseq s n (+ n len)) p) (setf result n) (return)))) result)) ;;********** ;; print a list of strings to a stream ;; ;; Inputs: ;; strings - a list of strings ;; stream - stream on which to write the strings ;; Effect: ;; ;;********** (defun print-strings (strings stream) (dolist (s strings) (princ s stream))) ;;********** ;; put-slot: ;; ;; Inputs: ;; schema - name of the schema ;; value - value of the attribute to be added or modified ;; property - name of the attribute to be modified ;; ;;********** (setfn put-slot putprop) (defun return-nil (ignore) nil) ;;********** ;; scale-check -- make sure scale method is not used on linear input or ;; on input where scaling is factored into other computation; ;; Also, don't use NONE scale method if sound appears on always-scale ;; list (these sounds have low likelihood of ever using 'NONE method - ;; see fmosc for an example). Note that if you say always-scale (removing ;; NONE) and linear or internal-scaling (removing SCALE), ;; then you'll be in big trouble. ;; ;; Inputs: ;; alg - algorithm description ;; spec - ;; Notes: ;; ;;********** (defun scale-check (alg spec) (let ((sounds (get-slot alg 'sound-args)) (linear (get-slot alg 'linear)) (internal-scaling (get-slot alg 'internal-scaling)) (always-scale (get-slot alg 'always-scale)) snd (result t) ) ; initially, the rationale list is nil for each sound: (cond (always-scale (dotimes (n (length spec)) ; look at each method in spec (cond ((eq 'NONE (nth n spec)) (setf snd (nth n sounds)) (cond ((member snd always-scale) (setf result nil) (return)))))))) (cond ((member 'SCALE spec) ; quick test (dotimes (n (length spec)) ; look at each method in spec (cond ((eq 'SCALE (nth n spec)) (setf snd (nth n sounds)) (cond ((or (member snd linear) (member snd internal-scaling)) (if (member snd internal-scaling) (format t "WARNING internal scaling not fully debugged, check your results...\n")) (setf result nil) (return)))))))) result)) ;; match-check -- make sure spec is consistent with inputs whose sample-rates ;; are matched. If a set of inputs appears on a MATCHED-SAMPLE-RATE clause, ;; then the spec for each input must be the same. This is used to control ;; combinatorial explosions. ;; (defun match-check (alg spec) (let ((sounds (get-slot alg 'sound-args)) (matched-sample-rate (get-slot alg 'matched-sample-rate)) kind ;; kind of access used by all matched sounds snd ;; the current sound in list (result t)) ;; algorithm: scan list for members of matched-sample-rate ;; when first is found, set kind; after than, insist that ;; other members have matching spec (cond (matched-sample-rate (dotimes (n (length spec)) (setf snd (nth n sounds)) (cond ((member snd matched-sample-rate) (cond ((null kind) (setf kind (nth n spec))) ((eq (nth n spec) kind)) (t (setf result nil)))))))) result)) ;;**************** ;; space-if-no-trailing-star -- returns "" if arg ends with "*", else space ;;**************** (defun space-if-no-trailing-star (str) (if (equal #\* (char str (1- (length str)))) "" #\Space)) ;; SPEC-IS-NONE-OR-SCALE -- see if spec is none or scale, called by sr-check ;; ;; sig is the search key ;; sound-args is a list, one element matches sig ;; spec is list of specs corresponding to elements in sound-args ;; return t if (eq sig (nth n sound-args)) and (nth n spec) is ;; either 'none or 'scale ;; (defun spec-is-none-or-scale (sig sound-args spec) (dolist (arg sound-args) (cond ((eq sig arg) (return (member (car spec) '(NONE SCALE))))) (setf spec (cdr spec)))) ;;**************** ;; sr-check -- see if interpolation spec is ok wrt sample rate spec ;;**************** (defun sr-check (alg spec) (let ((sample-rate (get-slot alg 'sample-rate)) (sound-args (get-slot alg 'sound-args)) (result t)) ;; if expression given, then anything is ok (cond ((stringp sample-rate) t) ;; if (MAX ...) expression given, then one of signals must be NONE or SCALE ((and (listp sample-rate) (eq (car sample-rate) 'MAX)) (dolist (sig (cdr sample-rate)) ; for all sig in max list ... (cond ((not (spec-is-none-or-scale sig sound-args spec)) (setf result nil)))) result) ;; if no expression given, then one signal must be NONE or SCALE ((or (member 'NONE spec) (member 'SCALE spec)) t) ;; o.w. return false (t nil)))) ;;**************** ;; symbol-to-name -- convert from internal symbol to case-sensitive C name ;;**************** (defun symbol-to-name (symbol) (get symbol 'string-name)) ;;********** ;; translate -- main procedure ;; ;; Inputs: ;; name - string which is name of file to translate ;; Effect: ;; Reads the algorithm specification as "name.alg" ;; Generates output files "name.c" and "name.h" ;;********** (defun translate (name) (prog* ((infile (concatenate 'string name ".alg")) (outfile (concatenate 'string name ".c")) (hfile (concatenate 'string name ".h")) (inf (open infile :direction :input)) (hf (open hfile :direction :output)) (outf (open outfile :direction :output))) (if (null inf) (error "translate: couldn't open inf")) (if (null hf) (error "translate: couldn't open hf")) (if (null outf) (error "translate: couldn't open outf")) (display "FILES" inf hf outf) (if *WATCH* (print "**** TRACING HOOKS ENABLED! ****") (print "**** NO TRACING ****") ) loop ;; read the algorithm description (setq alg (read inf)) ;; if the algorithm is NIL, we had some sort of failure (cond ((null alg) (close inf) (close hf) (close outf) (return))) ;; we have read in the high-level schema specification ;; convert it to a schema (display "translate: " infile alg) (setf alg (make-schema-from-slots alg)) (display "translate: schema " alg) ;; save the .h file name (put-slot alg hfile 'hfile) ;; perform the type-check on the schema parameters (type-check-and-transform alg) (display "translate: transformed schema" alg) (code-gen alg outf hf) (display "translate: finished code-gen") (setf save-alg alg) (go loop) ) ) (print 'translate) ;;********** ;; type-check-and-transform -- fix up slots in an algorithm schema ;; ;; Inputs: ;; alg - the name of the algorithm; values are its property list ;; Notes: ;; Report an error if required slot values are absent ;; Any slot which should be a single value and is a list is ;; coerced to be the car of the list ;; Put argument string names on argument symbols for conversion. ;;********** (defun type-check-and-transform (alg) ;; the quoted list that follows 'slot' is the list of required ;; parameters. If any parameter is missing, this will cause an ;; error (dolist (slot '(name inner-loop)) ; other necessarily non-nil slots go here (cond ((null (get-slot alg slot)) (error "missing slot")))) ; fix single-value slots to not be stored as lists: ; If the value is a list, the value is coerced to ; be the car of the list (dolist (slot '(name lispname inner-loop sample-rate support-functions inline-interpolation delay )) (put-slot alg (car (get-slot alg slot)) slot)) ; Make sure there are no strings, only symbols, in TERMINATE and ; LOGICAL-STOP MIN lists: (TERMINATE (MIN "s1")) is wrong, it should be ; (TERMINATE (MIN s1)) (dolist (field '(terminate logical-stop)) (setf spec (get-slot alg field)) (display "type-check" spec field) (cond ((and spec (listp (car spec)) (member (caar spec) '(MIN MAX))) (dolist (entry (cdar spec)) (display "type-check" spec field entry) (cond ((eq (type-of entry) 'STRING) (error "MIN and MAX args are symbols, not strings" spec))))))) ; (ARGUMENTS ( "type1" "name1") ("type2" "name2") ... ("typen" "namen") ) ; if "sr" is the name of an argument, its type must be "rate_type" ; i.e. ("rate_type" "sr") (dolist (arg (get-slot alg 'arguments)) (cond ((and (equal (cadr arg) "sr") (not (equal (car arg) "rate_type"))) (error "argument sr must be of type rate_type")) ((equal (car arg) "sound_type") (putprop (name-to-symbol (cadr arg)) (cadr arg) 'string-name))))) ;;********** ;; union-of-nth -- get the union of the nth element of each sublist ;; ;;********** (defun union-of-nth (lis n) (let (result a) (dolist (sublis lis) (setf a (nth n sublis)) (cond ((not (member a result)) (setf result (cons a result))))) result)) (print 'union-of-nth) ;;********** ;; write-header -- write a header file for the suspension create routine ;; ;; Inputs: ;; alg - algorithm name ;; stream - output stream for .h file ;; Effect: ;; Writes to the stream ;; sound_type snd_make_NAME(); ;; Notes: ;; Uses NAME property of algorithm to emit the procedure header to ;; the .h file ;;********** (setf c-to-xlisp-type '( ("double" . "ANYNUM") ("float" . "ANYNUM") ("time_type" . "ANYNUM") ("rate_type" . "ANYNUM") ("sample_type" . "ANYNUM") ("sound_type" . "SOUND") ("char *" . "STRING") ("LVAL" . "ANY") ("int" . "FIXNUM") ("long" . "FIXNUM") ("boolean" . "BOOLEAN") )) (defun write-header (alg stream) ;; (format stream "sound_type snd_make_~A();~%" (get-slot alg 'name)) (let ((arguments (get-slot alg 'arguments)) (name (get-slot alg 'name)) (lisp-name (get-slot alg 'lispname))) (cond ((null lisp-name) (setf lisp-name name))) (format stream "sound_type snd_make_~A" name) (write-ansi-prototype-list stream "" arguments) (format stream ";~%") ; write the xlisp interface routine (format stream "sound_type snd_~A" name) (write-ansi-prototype-list stream "" arguments) (format stream ";~%") ; write the type specification for intgen (format stream " /* LISP: (snd-~A" lisp-name) (dolist (arg arguments) (let ((xltype (assoc (car arg) c-to-xlisp-type :test #'equal))) (cond ((null xltype) (error "couldn't translate c-type" (car arg)))) (format stream " ~A" (cdr xltype)))) (format stream ") */~%"))) ;;********** ;; write-typedef -- compile the suspension type definition ;; ;; Inputs: ;; alg - the algorithm specification ;; stream - stream to which to write it ;; Effect: ;; typedef struct NAME_susp_struct { ;; ... ;; } NAME_susp_node, *NAME_susp_type; ;; ;; A side-effect of write-typedef is the initialization ;; of slot xlisp-pointers in alg. This is used later by ;; write-mark to generate the garbage collection mark routine. ;;********** (defun write-typedef (alg stream) (let (arg-type args interpolation-list sound-names arg (alg-name (get-slot alg 'name)) name xlisp-pointers (state-list (get-slot alg 'state)) (logical-stop (car (get-slot alg 'logical-stop))) (terminate (car (get-slot alg 'terminate)))) ;---------------------------- ; typedef struct NAME_susp_strct { ; snd_susp_node susp; ;---------------------------- (format stream "~%~%typedef struct ~A_susp_struct {~%~A~%" alg-name " snd_susp_node susp;") ; go through interpolation list: ; NONE means use each sample ; INTERP means interpolate between samples ; RAMP means do ramp generation between samples ; NIL means this is not a signal (setf interpolation-list (get-slot alg 'interpolation-list)) (setf sound-names (get-slot alg 'sound-names)) ; declare started flag if there is a ramp or interp signal anywhere (cond ((any-ramp-or-interp-in interpolation-list) ;--------------------- ; INTERP/RAMP: ; boolean started; ;--------------------- (format stream " boolean started;~%"))) (display "in translate.lsp" terminate alg (terminate-check-needed terminate alg)) (cond ((terminate-check-needed terminate alg) ;---------------- ; long terminate_cnt; ;---------------- (format stream " long terminate_cnt;~%"))) (cond ((logical-stop-check-needed logical-stop) ;---------------- ; boolean logically_stopped; ;---------------- (format stream " boolean logically_stopped;~%"))) ; each sound argument has a variety of ways it might be ; interpolated. These are stored on interpolation-list, and union-of-nth ; is used to gather all the interpolation styles that must be supported ; for a given signal - we then declare whatever state is necessary for ; each possible interpolation (dotimes (n (length (get alg 'sound-args))) (let ((interpolation (union-of-nth interpolation-list n))) (setf name (nth n sound-names)) ; get name of signal ;------------------------ ; sound_type NAMEi; ; long NAME_cnt; ; sample_block_values_type NAME_ptr; ;------------------------ (format stream " sound_type ~A;~%" name) (format stream " long ~A_cnt;~%" name) (format stream " sample_block_values_type ~A_ptr;~%" name) (cond ((or (member 'INTERP interpolation) (member 'RAMP interpolation)) ;----------------- ; /* support for interpolation of NAMEi */ ;----------------- (format stream "~% /* support for interpolation of ~A */~%" name) ;----------------- ; sample_type NAME_x1_sample; ;----------------- (format stream " sample_type ~A_x1_sample;~%" name) ;----------------- ; double NAME_pHaSe; ; double NAME_pHaSe_iNcR; ;----------------- (format stream " double ~A_pHaSe;~%" name) (format stream " double ~A_pHaSe_iNcR;~%" name))) (cond ((member 'RAMP interpolation) ;----------------- ; RAMP: ; /* support for ramp between samples of NAME */ ; double output_per_NAME; ; long NAME_n; ;----------------- (format stream "~% /* support for ramp between samples of ~A */~%" name) (format stream " double output_per_~A;~%" name) (format stream " long ~A_n;~%" name) )))) ;---------------------------- ; STATE ; TYPEi VARNAMEi ; ;---------------------------- ;; now write state variables ;; (STATE (s1) (s2)... (sn) ) ;; each (si) is of the form ;; ("type" "varname" "?" [TEMP]) (cond (state-list (format stream "~%"))) (dolist (state state-list) (cond ((equal "LVAL" (car state)) (push (cadr state) xlisp-pointers))) (cond ((and (cdddr state) (cadddr state) (eq (cadddr state) 'TEMP)) ; no field allocated for local/temp variables ) (t (let ((sep (space-if-no-trailing-star (car state)))) (format stream " ~A~A~A;~%" (car state) sep (cadr state)))))) (put-slot alg xlisp-pointers 'xlisp-pointers) ;---------------------------- ; } ALG-NAME_susp_node, *ALG-NAME_susp_type; ;---------------------------- (format stream "} ~A_susp_node, *~A_susp_type;~%" alg-name alg-name))) (print 'end) nyquist-3.05/tran/instrclar.alg0000644000175000000620000000132610144436365015625 0ustar stevestaff(INSTRCLAR-ALG (NAME "clarinet") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("rate_type" "sr")) (STATE ("struct instr *" "clar" "initInstrument(CLARINET, round(sr)); controlChange(susp->clar, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->clar, freq, 1.0)")) (START (min breath_env)) (NOT-IN-INNER-LOOP "freq" "temp_ret_value") (SAMPLE-RATE "sr") (ALWAYS-SCALE breath_env) (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(clar, 128, CLAR_CONTROL_CHANGE_CONST * breath_env); output = (sample_type) tick(clar)") (SUPPORT-HEADER " #define CLAR_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->clar); ") ) nyquist-3.05/tran/lpreson.c0000644000175000000620000002221510144436365014765 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "lpreson.h" void lpreson_free(); typedef struct lpreson_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type x_snd; long x_snd_cnt; sample_block_values_type x_snd_ptr; long fr_indx; long ak_len; long frame_length; LVAL src; LVAL frame; double *ak_coefs; double *zk_buf; double gain; long index; } lpreson_susp_node, *lpreson_susp_type; #include "samples.h" void lpreson_s_fetch(register lpreson_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long fr_indx_reg; register long ak_len_reg; register double * ak_coefs_reg; register double * zk_buf_reg; register double gain_reg; register long index_reg; register sample_type x_snd_scale_reg = susp->x_snd->scale; register sample_block_values_type x_snd_ptr_reg; falloc_sample_block(out, "lpreson_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the x_snd input sample block: */ susp_check_term_log_samples(x_snd, x_snd_ptr, x_snd_cnt); togo = min(togo, susp->x_snd_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->fr_indx >= susp->frame_length) susp->fr_indx -= susp->frame_length; if (susp->fr_indx==0) { long i; susp->frame = xleval(cons(s_send, cons(susp->src, consa(s_next)))); if (susp->frame == NULL) { susp->src = NULL; goto out; /* en susp->frame tenemos la lista proporcionada por el objeto */ } else if (!listp(susp->frame) || !listp(cdr(susp->frame)) || !listp(cdr(cdr(susp->frame))) || !listp(cdr(cdr(cdr(susp->frame))))) { xlerror("list expected", susp->frame); } /* frame is a list: (RMS1 RMS2 ERR FILTER-COEFS) */ /* gain is square root of RMS2 */ susp->gain = sqrt(getflonum(car(cdr(susp->frame)))); /* get filter coefs */ susp->frame=car(cdr(cdr(cdr(susp->frame)))); if (!vectorp(susp->frame)) { xlerror("array expected", susp->frame); } else if (susp->ak_coefs == NULL) { susp->ak_len = getsize(susp->frame); if (susp->ak_len < 1) xlerror("array has no elements", susp->frame); susp->ak_coefs = (double *) calloc(susp->ak_len, sizeof(double)); susp->zk_buf = (double *) calloc(susp->ak_len, sizeof(double)); } /* at this point we have a new array and a place to put ak coefs */ for (i=0; i < susp->ak_len; i++) { LVAL elem = getelement(susp->frame, i); if (ntype(elem) != FLONUM) { xlerror("flonum expected", elem); } susp->ak_coefs[i] = getflonum(elem); } // printf("NUEVO FILTRO: "); /* here for debug */ // for(k=0; k < susp->ak_len; k++) printf(" %g ", susp->ak_coefs[k]); // printf("GAIN %g AKLEN %d ", susp->gain, susp->ak_len); susp->frame = NULL; /* free the array */ } togo = min(susp->frame_length - susp->fr_indx, togo); n = togo; fr_indx_reg = susp->fr_indx; ak_len_reg = susp->ak_len; ak_coefs_reg = susp->ak_coefs; zk_buf_reg = susp->zk_buf; gain_reg = susp->gain; index_reg = susp->index; x_snd_ptr_reg = susp->x_snd_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; long xi; long xj; z0 = (x_snd_scale_reg * *x_snd_ptr_reg++) * gain_reg; for (xi=0; xi < ak_len_reg; xi++) { xj = index_reg + xi; if (xj >= ak_len_reg) xj -= ak_len_reg; z0 += ak_coefs_reg[xi] * zk_buf_reg[xj]; } zk_buf_reg[index_reg] = z0; index_reg++; if (index_reg == ak_len_reg) index_reg = 0; fr_indx_reg++; *out_ptr_reg++ = (sample_type) z0; ; } while (--n); /* inner loop */ susp->fr_indx = fr_indx_reg; susp->ak_len = ak_len_reg; susp->ak_coefs = ak_coefs_reg; susp->zk_buf = zk_buf_reg; susp->gain = gain_reg; susp->index = index_reg; /* using x_snd_ptr_reg is a bad idea on RS/6000: */ susp->x_snd_ptr += togo; out_ptr += togo; susp_took(x_snd_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* lpreson_s_fetch */ void lpreson_toss_fetch(susp, snd_list) register lpreson_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from x_snd up to final_time for this block of zeros */ while ((round((final_time - susp->x_snd->t0) * susp->x_snd->sr)) >= susp->x_snd->current) susp_get_samples(x_snd, x_snd_ptr, x_snd_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->x_snd->t0) * susp->x_snd->sr - (susp->x_snd->current - susp->x_snd_cnt)); susp->x_snd_ptr += n; susp_took(x_snd_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void lpreson_mark(lpreson_susp_type susp) { if (susp->frame) mark(susp->frame); if (susp->src) mark(susp->src); sound_xlmark(susp->x_snd); } void lpreson_free(lpreson_susp_type susp) { free(susp->ak_coefs); free(susp->zk_buf); sound_unref(susp->x_snd); ffree_generic(susp, sizeof(lpreson_susp_node), "lpreson_free"); } void lpreson_print_tree(lpreson_susp_type susp, int n) { indent(n); stdputstr("x_snd:"); sound_print_tree_1(susp->x_snd, n); } sound_type snd_make_lpreson(sound_type x_snd, LVAL src, time_type frame_time) { register lpreson_susp_type susp; rate_type sr = x_snd->sr; time_type t0 = x_snd->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, lpreson_susp_node, "snd_make_lpreson"); susp->fr_indx = 0; susp->ak_len = 0; susp->frame_length = (long) (frame_time*x_snd->sr); susp->src = src; susp->frame = NULL; susp->ak_coefs = NULL; susp->zk_buf = NULL; susp->gain = 1.0; susp->index = 0; susp->susp.fetch = lpreson_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < x_snd->t0) sound_prepend_zeros(x_snd, t0); /* minimum start time over all inputs: */ t0_min = min(x_snd->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = lpreson_toss_fetch; } /* initialize susp state */ susp->susp.free = lpreson_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = lpreson_mark; susp->susp.print_tree = lpreson_print_tree; susp->susp.name = "lpreson"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(x_snd); susp->susp.current = 0; susp->x_snd = x_snd; susp->x_snd_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_lpreson(sound_type x_snd, LVAL src, time_type frame_time) { sound_type x_snd_copy = sound_copy(x_snd); return snd_make_lpreson(x_snd_copy, src, frame_time); } nyquist-3.05/tran/white.c0000644000175000000620000000475610144436365014435 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "white.h" void white_free(); typedef struct white_susp_struct { snd_susp_node susp; long terminate_cnt; } white_susp_node, *white_susp_type; void white__fetch(register white_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; falloc_sample_block(out, "white__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (rand() * rand_scale - 1.0);; } while (--n); /* inner loop */ out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* white__fetch */ void white_free(white_susp_type susp) { ffree_generic(susp, sizeof(white_susp_node), "white_free"); } void white_print_tree(white_susp_type susp, int n) { } sound_type snd_make_white(time_type t0, rate_type sr, time_type d) { register white_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, white_susp_node, "snd_make_white"); susp->susp.fetch = white__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = white_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = white_print_tree; susp->susp.name = "white"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_white(time_type t0, rate_type sr, time_type d) { return snd_make_white(t0, sr, d); } nyquist-3.05/tran/atonev.c0000644000175000000620000003622210144436365014602 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "atonev.h" void atonev_free(); typedef struct atonev_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type hz; long hz_cnt; sample_block_values_type hz_ptr; /* support for interpolation of hz */ sample_type hz_x1_sample; double hz_pHaSe; double hz_pHaSe_iNcR; /* support for ramp between samples of hz */ double output_per_hz; long hz_n; double cc; double prev; } atonev_susp_node, *atonev_susp_type; void atonev_ns_fetch(register atonev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double cc_reg; register double prev_reg; register sample_type hz_scale_reg = susp->hz->scale; register sample_block_values_type hz_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "atonev_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz input sample block: */ susp_check_term_samples(hz, hz_ptr, hz_cnt); togo = min(togo, susp->hz_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; cc_reg = susp->cc; prev_reg = susp->prev; hz_ptr_reg = susp->hz_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double current; register double bb; bb = 2.0 - cos((hz_scale_reg * *hz_ptr_reg++)); cc_reg = bb - sqrt((bb * bb) - 1.0); current = *s1_ptr_reg++; prev_reg = cc_reg * (prev_reg + current); *out_ptr_reg++ = (sample_type) prev_reg; prev_reg -= current;; } while (--n); /* inner loop */ susp->prev = prev_reg; /* using hz_ptr_reg is a bad idea on RS/6000: */ susp->hz_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* atonev_ns_fetch */ void atonev_ni_fetch(register atonev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double cc_reg; register double prev_reg; register double hz_pHaSe_iNcR_rEg = susp->hz_pHaSe_iNcR; register double hz_pHaSe_ReG; register sample_type hz_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "atonev_ni_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { register double bb; susp->started = true; susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); bb = 2.0 - cos(susp->hz_x1_sample); susp->cc = bb - sqrt((bb * bb) - 1.0); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; cc_reg = susp->cc; prev_reg = susp->prev; hz_pHaSe_ReG = susp->hz_pHaSe; hz_x1_sample_reg = susp->hz_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double current; if (hz_pHaSe_ReG >= 1.0) { /* fixup-depends hz */ register double bb; /* pick up next sample as hz_x1_sample: */ susp->hz_ptr++; susp_took(hz_cnt, 1); hz_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz, hz_ptr, hz_cnt, hz_x1_sample_reg); hz_x1_sample_reg = susp_current_sample(hz, hz_ptr); bb = 2.0 - cos(hz_x1_sample_reg); cc_reg = susp->cc = bb - sqrt((bb * bb) - 1.0); } current = *s1_ptr_reg++; prev_reg = cc_reg * (prev_reg + current); *out_ptr_reg++ = (sample_type) prev_reg; prev_reg -= current;; hz_pHaSe_ReG += hz_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->prev = prev_reg; susp->hz_pHaSe = hz_pHaSe_ReG; susp->hz_x1_sample = hz_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* atonev_ni_fetch */ void atonev_nr_fetch(register atonev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double cc_reg; register double prev_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "atonev_nr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz_pHaSe = 1.0; } susp_check_term_samples(hz, hz_ptr, hz_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz_x1_sample when phase goes past 1.0; */ /* use hz_n (computed below) to avoid roundoff errors: */ if (susp->hz_n <= 0) { register double bb; susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->hz_pHaSe -= 1.0; /* hz_n gets number of samples before phase exceeds 1.0: */ susp->hz_n = (long) ((1.0 - susp->hz_pHaSe) * susp->output_per_hz); bb = 2.0 - cos(susp->hz_x1_sample); susp->cc = bb - sqrt((bb * bb) - 1.0); } togo = min(togo, susp->hz_n); hz_val = susp->hz_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; cc_reg = susp->cc; prev_reg = susp->prev; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double current; current = *s1_ptr_reg++; prev_reg = cc_reg * (prev_reg + current); *out_ptr_reg++ = (sample_type) prev_reg; prev_reg -= current;; } while (--n); /* inner loop */ susp->prev = prev_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz_pHaSe += togo * susp->hz_pHaSe_iNcR; susp->hz_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* atonev_nr_fetch */ void atonev_toss_fetch(susp, snd_list) register atonev_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from hz up to final_time for this block of zeros */ while ((round((final_time - susp->hz->t0) * susp->hz->sr)) >= susp->hz->current) susp_get_samples(hz, hz_ptr, hz_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->hz->t0) * susp->hz->sr - (susp->hz->current - susp->hz_cnt)); susp->hz_ptr += n; susp_took(hz_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void atonev_mark(atonev_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->hz); } void atonev_free(atonev_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->hz); ffree_generic(susp, sizeof(atonev_susp_node), "atonev_free"); } void atonev_print_tree(atonev_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("hz:"); sound_print_tree_1(susp->hz, n); } sound_type snd_make_atonev(sound_type s1, sound_type hz) { register atonev_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, hz->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (S1) */ scale_factor *= s1->scale; s1->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s1->sr < sr) { s1->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, atonev_susp_node, "snd_make_atonev"); susp->cc = 0.0; susp->prev = 0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(hz, sr); switch (interp_desc) { case INTERP_nn: /* handled below */ case INTERP_ns: susp->susp.fetch = atonev_ns_fetch; break; case INTERP_ni: susp->susp.fetch = atonev_ni_fetch; break; case INTERP_nr: susp->susp.fetch = atonev_nr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < hz->t0) sound_prepend_zeros(hz, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(hz->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = atonev_toss_fetch; } /* initialize susp state */ susp->susp.free = atonev_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = atonev_mark; susp->susp.print_tree = atonev_print_tree; susp->susp.name = "atonev"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->hz = hz; susp->hz_cnt = 0; susp->hz_pHaSe = 0.0; susp->hz_pHaSe_iNcR = hz->sr / sr; susp->hz_n = 0; susp->output_per_hz = sr / hz->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_atonev(sound_type s1, sound_type hz) { sound_type s1_copy = sound_copy(s1); sound_type hz_copy = sound_copy(hz); return snd_make_atonev(s1_copy, hz_copy); } nyquist-3.05/tran/shape.c0000644000175000000620000001537510144436365014414 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "shape.h" void shape_free(); typedef struct shape_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type sin; long sin_cnt; sample_block_values_type sin_ptr; double time_to_index; double origin; table_type the_table; sample_type *fcn_table; double table_len; } shape_susp_node, *shape_susp_type; void shape_s_fetch(register shape_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double time_to_index_reg; register double origin_reg; register sample_type * fcn_table_reg; register double table_len_reg; register sample_type sin_scale_reg = susp->sin->scale; register sample_block_values_type sin_ptr_reg; falloc_sample_block(out, "shape_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the sin input sample block: */ susp_check_term_log_samples(sin, sin_ptr, sin_cnt); togo = min(togo, susp->sin_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; time_to_index_reg = susp->time_to_index; origin_reg = susp->origin; fcn_table_reg = susp->fcn_table; table_len_reg = susp->table_len; sin_ptr_reg = susp->sin_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double offset, x1; register long table_index; register double phase = (sin_scale_reg * *sin_ptr_reg++); if (phase > 1.0) phase = 1.0; else if (phase < -1.0) phase = -1.0; offset = (phase + origin_reg) * time_to_index_reg; table_index = (long) offset; if (table_index < 0) { table_index = 0; offset = 0; } if (table_index >= table_len_reg) { offset = table_len_reg - 1; table_index = (long) offset; } x1 = fcn_table_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (offset - table_index) * (fcn_table_reg[table_index + 1] - x1)); ; } while (--n); /* inner loop */ susp->origin = origin_reg; /* using sin_ptr_reg is a bad idea on RS/6000: */ susp->sin_ptr += togo; out_ptr += togo; susp_took(sin_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* shape_s_fetch */ void shape_toss_fetch(susp, snd_list) register shape_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from sin up to final_time for this block of zeros */ while ((round((final_time - susp->sin->t0) * susp->sin->sr)) >= susp->sin->current) susp_get_samples(sin, sin_ptr, sin_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->sin->t0) * susp->sin->sr - (susp->sin->current - susp->sin_cnt)); susp->sin_ptr += n; susp_took(sin_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void shape_mark(shape_susp_type susp) { sound_xlmark(susp->sin); } void shape_free(shape_susp_type susp) { table_unref(susp->the_table); sound_unref(susp->sin); ffree_generic(susp, sizeof(shape_susp_node), "shape_free"); } void shape_print_tree(shape_susp_type susp, int n) { indent(n); stdputstr("sin:"); sound_print_tree_1(susp->sin, n); } sound_type snd_make_shape(sound_type sin, sound_type fn, double origin) { register shape_susp_type susp; rate_type sr = sin->sr; time_type t0 = sin->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, shape_susp_node, "snd_make_shape"); susp->time_to_index = fn->sr; susp->origin = origin; susp->the_table = sound_to_table(fn); susp->fcn_table = susp->the_table->samples; susp->table_len = susp->the_table->length; susp->susp.fetch = shape_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < sin->t0) sound_prepend_zeros(sin, t0); /* minimum start time over all inputs: */ t0_min = min(sin->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = shape_toss_fetch; } /* initialize susp state */ susp->susp.free = shape_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = shape_mark; susp->susp.print_tree = shape_print_tree; susp->susp.name = "shape"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(sin); susp->susp.current = 0; susp->sin = sin; susp->sin_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_shape(sound_type sin, sound_type fn, double origin) { sound_type sin_copy = sound_copy(sin); return snd_make_shape(sin_copy, fn, origin); } nyquist-3.05/tran/clip.alg0000644000175000000620000000046011466723256014557 0ustar stevestaff(CLIP-ALG (NAME "clip") (ARGUMENTS ("sound_type" "s") ("double" "level")) (STATE ("sample_type" "level" "(sample_type) level")) (START (MIN s)) (INNER-LOOP "double x = s; output = (sample_type) (x > level ? level : (x < -level ? -level : x))") (TERMINATE (MIN s)) (LOGICAL-STOP (MIN s)) ) nyquist-3.05/tran/oneshot.c0000644000175000000620000002175211466723256014775 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "oneshot.h" void oneshot_free(); typedef struct oneshot_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; double lev; long oncount; long cnt; } oneshot_susp_node, *oneshot_susp_type; void oneshot_n_fetch(register oneshot_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double lev_reg; register long oncount_reg; register long cnt_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "oneshot_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; lev_reg = susp->lev; oncount_reg = susp->oncount; cnt_reg = susp->cnt; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x = *input_ptr_reg++; if (x > lev_reg) cnt_reg = oncount_reg; cnt_reg--; *out_ptr_reg++ = (cnt_reg >= 0 ? 1.0F : 0.0F);; } while (--n); /* inner loop */ susp->cnt = cnt_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* oneshot_n_fetch */ void oneshot_s_fetch(register oneshot_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double lev_reg; register long oncount_reg; register long cnt_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "oneshot_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; lev_reg = susp->lev; oncount_reg = susp->oncount; cnt_reg = susp->cnt; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x = (input_scale_reg * *input_ptr_reg++); if (x > lev_reg) cnt_reg = oncount_reg; cnt_reg--; *out_ptr_reg++ = (cnt_reg >= 0 ? 1.0F : 0.0F);; } while (--n); /* inner loop */ susp->cnt = cnt_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* oneshot_s_fetch */ void oneshot_toss_fetch(susp, snd_list) register oneshot_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void oneshot_mark(oneshot_susp_type susp) { sound_xlmark(susp->input); } void oneshot_free(oneshot_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(oneshot_susp_node), "oneshot_free"); } void oneshot_print_tree(oneshot_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_oneshot(sound_type input, double level, double ontime) { register oneshot_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, oneshot_susp_node, "snd_make_oneshot"); susp->lev = level; susp->oncount = round(ontime * input->sr); susp->cnt = 0; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = oneshot_n_fetch; break; case INTERP_s: susp->susp.fetch = oneshot_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = oneshot_toss_fetch; } /* initialize susp state */ susp->susp.free = oneshot_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = oneshot_mark; susp->susp.print_tree = oneshot_print_tree; susp->susp.name = "oneshot"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_oneshot(sound_type input, double level, double ontime) { sound_type input_copy = sound_copy(input); return snd_make_oneshot(input_copy, level, ontime); } nyquist-3.05/tran/exp.c0000644000175000000620000001232610144436365014101 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "exp.h" void exp_free(); typedef struct exp_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type in; long in_cnt; sample_block_values_type in_ptr; } exp_susp_node, *exp_susp_type; void exp_s_fetch(register exp_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type in_scale_reg = susp->in->scale; register sample_block_values_type in_ptr_reg; falloc_sample_block(out, "exp_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the in input sample block: */ susp_check_term_log_samples(in, in_ptr, in_cnt); togo = min(togo, susp->in_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; in_ptr_reg = susp->in_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) exp((in_scale_reg * *in_ptr_reg++)); } while (--n); /* inner loop */ /* using in_ptr_reg is a bad idea on RS/6000: */ susp->in_ptr += togo; out_ptr += togo; susp_took(in_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* exp_s_fetch */ void exp_toss_fetch(susp, snd_list) register exp_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from in up to final_time for this block of zeros */ while ((round((final_time - susp->in->t0) * susp->in->sr)) >= susp->in->current) susp_get_samples(in, in_ptr, in_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->in->t0) * susp->in->sr - (susp->in->current - susp->in_cnt)); susp->in_ptr += n; susp_took(in_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void exp_mark(exp_susp_type susp) { sound_xlmark(susp->in); } void exp_free(exp_susp_type susp) { sound_unref(susp->in); ffree_generic(susp, sizeof(exp_susp_node), "exp_free"); } void exp_print_tree(exp_susp_type susp, int n) { indent(n); stdputstr("in:"); sound_print_tree_1(susp->in, n); } sound_type snd_make_exp(sound_type in) { register exp_susp_type susp; rate_type sr = in->sr; time_type t0 = in->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, exp_susp_node, "snd_make_exp"); susp->susp.fetch = exp_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < in->t0) sound_prepend_zeros(in, t0); /* minimum start time over all inputs: */ t0_min = min(in->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = exp_toss_fetch; } /* initialize susp state */ susp->susp.free = exp_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = exp_mark; susp->susp.print_tree = exp_print_tree; susp->susp.name = "exp"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(in); susp->susp.current = 0; susp->in = in; susp->in_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_exp(sound_type in) { sound_type in_copy = sound_copy(in); return snd_make_exp(in_copy); } nyquist-3.05/tran/aresonvv.h0000644000175000000620000000036110144436365015151 0ustar stevestaffsound_type snd_make_aresonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization); sound_type snd_aresonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization); /* LISP: (snd-aresonvv SOUND SOUND SOUND FIXNUM) */ nyquist-3.05/tran/scale.alg0000644000175000000620000000041010144436365014704 0ustar stevestaff(SCALE-ALG (NAME "normalize") (ARGUMENTS ("sound_type" "s1")) (STATE ("sample_type" "scale" "s1->scale")) (CONSTANT "scale") (START (MIN s1)) (INTERNAL-SCALING s1) (INNER-LOOP "output = s1 * scale") (TERMINATE (MIN s1)) (LOGICAL-STOP (MIN s1)) ) nyquist-3.05/tran/allpoles.c0000644000175000000620000001733311466723256015131 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "allpoles.h" void allpoles_free(); typedef struct allpoles_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type x_snd; long x_snd_cnt; sample_block_values_type x_snd_ptr; long ak_len; LVAL ak_array; double gain; double *ak_coefs; double *zk_buf; long index; } allpoles_susp_node, *allpoles_susp_type; void allpoles_s_fetch(register allpoles_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long ak_len_reg; register double gain_reg; register double * ak_coefs_reg; register double * zk_buf_reg; register long index_reg; register sample_type x_snd_scale_reg = susp->x_snd->scale; register sample_block_values_type x_snd_ptr_reg; falloc_sample_block(out, "allpoles_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the x_snd input sample block: */ susp_check_term_log_samples(x_snd, x_snd_ptr, x_snd_cnt); togo = min(togo, susp->x_snd_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } if (susp->ak_array == NULL) { togo = 0; /* indicate termination */ break; /* we're done */ } else if (!vectorp(susp->ak_array)) xlerror("array expected", susp->ak_array); else if (susp->ak_coefs == NULL) { long i; susp->ak_len = getsize(susp->ak_array); if (susp->ak_len < 1) xlerror("array has not elements", susp->ak_array); susp->ak_coefs = (double *) calloc(susp->ak_len, sizeof(double)); susp->zk_buf = (double *) calloc(susp->ak_len, sizeof(double)); /* at this point we have a new array and a place to put ak coefs */ for(i=0; i < susp->ak_len; i++) { LVAL elem = getelement(susp->ak_array,i); if (ntype(elem) != FLONUM) { xlerror("flonum expected", elem); } susp->ak_coefs[i] = getflonum(elem); } } n = togo; ak_len_reg = susp->ak_len; gain_reg = susp->gain; ak_coefs_reg = susp->ak_coefs; zk_buf_reg = susp->zk_buf; index_reg = susp->index; x_snd_ptr_reg = susp->x_snd_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; long xi; long xj; z0 = (x_snd_scale_reg * *x_snd_ptr_reg++)*gain_reg; for (xi=0; xi < ak_len_reg ; xi++) { xj = index_reg + xi; if (xj >= ak_len_reg) xj -= ak_len_reg; z0 += ak_coefs_reg[xi] * zk_buf_reg[xj]; } zk_buf_reg[index_reg] = z0; index_reg++; if (index_reg == ak_len_reg) index_reg = 0; *out_ptr_reg++ = (sample_type) z0; ; } while (--n); /* inner loop */ susp->zk_buf = zk_buf_reg; susp->index = index_reg; /* using x_snd_ptr_reg is a bad idea on RS/6000: */ susp->x_snd_ptr += togo; out_ptr += togo; susp_took(x_snd_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* allpoles_s_fetch */ void allpoles_toss_fetch(susp, snd_list) register allpoles_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from x_snd up to final_time for this block of zeros */ while ((round((final_time - susp->x_snd->t0) * susp->x_snd->sr)) >= susp->x_snd->current) susp_get_samples(x_snd, x_snd_ptr, x_snd_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->x_snd->t0) * susp->x_snd->sr - (susp->x_snd->current - susp->x_snd_cnt)); susp->x_snd_ptr += n; susp_took(x_snd_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void allpoles_mark(allpoles_susp_type susp) { if (susp->ak_array) mark(susp->ak_array); sound_xlmark(susp->x_snd); } void allpoles_free(allpoles_susp_type susp) { free(susp->zk_buf); free(susp->ak_coefs); susp->ak_array = NULL; /* free array */ sound_unref(susp->x_snd); ffree_generic(susp, sizeof(allpoles_susp_node), "allpoles_free"); } void allpoles_print_tree(allpoles_susp_type susp, int n) { indent(n); stdputstr("x_snd:"); sound_print_tree_1(susp->x_snd, n); } sound_type snd_make_allpoles(sound_type x_snd, LVAL ak_array, double gain) { register allpoles_susp_type susp; rate_type sr = x_snd->sr; time_type t0 = x_snd->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, allpoles_susp_node, "snd_make_allpoles"); susp->ak_len = 0; susp->ak_array = ak_array; susp->gain = gain; susp->ak_coefs = NULL; susp->zk_buf = NULL; susp->index = 0; susp->susp.fetch = allpoles_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < x_snd->t0) sound_prepend_zeros(x_snd, t0); /* minimum start time over all inputs: */ t0_min = min(x_snd->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = allpoles_toss_fetch; } /* initialize susp state */ susp->susp.free = allpoles_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = allpoles_mark; susp->susp.print_tree = allpoles_print_tree; susp->susp.name = "allpoles"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(x_snd); susp->susp.current = 0; susp->x_snd = x_snd; susp->x_snd_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_allpoles(sound_type x_snd, LVAL ak_array, double gain) { sound_type x_snd_copy = sound_copy(x_snd); return snd_make_allpoles(x_snd_copy, ak_array, gain); } nyquist-3.05/tran/fromarraystream.h0000644000175000000620000000031110144436365016517 0ustar stevestaffsound_type snd_make_fromarraystream(time_type t0, rate_type sr, LVAL src); sound_type snd_fromarraystream(time_type t0, rate_type sr, LVAL src); /* LISP: (snd-fromarraystream ANYNUM ANYNUM ANY) */ nyquist-3.05/tran/aresonvv.alg0000644000175000000620000000336110144436365015470 0ustar stevestaff(ARESONVV-ALG (NAME "aresonvv") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz1") ("sound_type" "bw") ("int" "normalization")) (INLINE-INTERPOLATION T) (ALWAYS-SCALE hz1 bw) (START (MAX s1 hz1 bw)) (TERMINATE (MIN s1 hz1 bw)) (LOGICAL-STOP (MIN s1)) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION hz1 bw) (LINEAR s1) (STATE ("double" "scale1" "s1->scale") ("double" "c3co" "0.0") ("double" "c3p1" "0.0") ("double" "c3t4" "0.0") ("double" "omc3" "0.0") ("double" "coshz" "0.0") ("double" "c2" "0.0") ("double" "c1" "0.0") ("boolean" "recompute" "false") ("int" "normalization" "normalization") ("double" "y1" "0.0") ("double" "y2" "0.0; hz1->scale = (sample_type) (hz1->scale * (PI2 / s1->sr)); bw->scale = (sample_type) (bw->scale * (-PI2 / s1->sr));")) (DEPENDS ("coshz" "hz1" "cos(hz1)") ("recompute" "hz1" "true") ("c3co" "bw" "exp(bw)") ("c3p1" "bw" "c3co + 1.0") ("c3t4" "bw" "c3co * 4.0") ("omc3" "bw" "1.0 - c3co") ("recompute" "bw" "true")) (JOINT-DEPENDENCY (("hz1" "bw") "if (recompute) {" " recompute = false;" " c2 = c3t4 * coshz / c3p1;" " c1 = (normalization == 0 ? 0.0 :" " (normalization == 1 ? 1.0 - omc3 * sqrt(1.0 - c2 * c2 / c3t4) :" " 1.0 - sqrt(c3p1 * c3p1 - c2 * c2) * omc3 / c3p1));" "}")) (CONSTANT "c1" "c2" "c3co" "coshz" "c3p1" "c3t4" "omc3" "normalization" "scale1") (FORCE-INTO-REGISTER recompute) ;c3t4 c3p1 normalization omc3 scale1 (INNER-LOOP-LOCALS " register double y0, current;") (INNER-LOOP "current = s1; y0 = c1 * current + c2 * y1 - c3co * y2; output = (sample_type) y0; y2 = y1; y1 = y0 - current") ) nyquist-3.05/tran/instrflute.c0000644000175000000620000001226111466723256015510 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrflute.h" void flute_free(); typedef struct flute_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; struct instr *myflute; int temp_ret_value; } flute_susp_node, *flute_susp_type; #include "instr.h" void flute_s_fetch(register flute_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * myflute_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "flute_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; myflute_reg = susp->myflute; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(myflute_reg, 128, FLUTE_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(myflute_reg); } while (--n); /* inner loop */ susp->myflute = myflute_reg; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* flute_s_fetch */ void flute_toss_fetch(susp, snd_list) register flute_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void flute_mark(flute_susp_type susp) { sound_xlmark(susp->breath_env); } void flute_free(flute_susp_type susp) { deleteInstrument(susp->myflute); sound_unref(susp->breath_env); ffree_generic(susp, sizeof(flute_susp_node), "flute_free"); } void flute_print_tree(flute_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); } sound_type snd_make_flute(double freq, sound_type breath_env, rate_type sr) { register flute_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, flute_susp_node, "snd_make_flute"); susp->myflute = initInstrument(FLUTE, round(sr)); controlChange(susp->myflute, 1, 0.0);; susp->temp_ret_value = noteOn(susp->myflute, freq, 1.0); susp->susp.fetch = flute_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = flute_toss_fetch; } /* initialize susp state */ susp->susp.free = flute_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = flute_mark; susp->susp.print_tree = flute_print_tree; susp->susp.name = "flute"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_flute(double freq, sound_type breath_env, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); return snd_make_flute(freq, breath_env_copy, sr); } nyquist-3.05/tran/oneshot.h0000644000175000000620000000030510144436365014763 0ustar stevestaffsound_type snd_make_oneshot(sound_type input, double level, double ontime); sound_type snd_oneshot(sound_type input, double level, double ontime); /* LISP: (snd-oneshot SOUND ANYNUM ANYNUM) */ nyquist-3.05/tran/osc.c0000644000175000000620000000703010144436365014065 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "osc.h" void osc_free(); typedef struct osc_susp_struct { snd_susp_node susp; long terminate_cnt; double ph_incr; table_type the_table; sample_type *table_ptr; double table_len; double phase; } osc_susp_node, *osc_susp_type; void osc__fetch(register osc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double ph_incr_reg; register sample_type * table_ptr_reg; register double table_len_reg; register double phase_reg; falloc_sample_block(out, "osc__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; ph_incr_reg = susp->ph_incr; table_ptr_reg = susp->table_ptr; table_len_reg = susp->table_len; phase_reg = susp->phase; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index = (long) phase_reg; double x1 = table_ptr_reg[table_index]; *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)); phase_reg += ph_incr_reg; while (phase_reg >= table_len_reg) phase_reg -= table_len_reg; ; } while (--n); /* inner loop */ susp->phase = phase_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* osc__fetch */ void osc_free(osc_susp_type susp) { table_unref(susp->the_table); ffree_generic(susp, sizeof(osc_susp_node), "osc_free"); } void osc_print_tree(osc_susp_type susp, int n) { } sound_type snd_make_osc(sound_type input, double step, rate_type sr, double hz, time_type t0, time_type d, double phase) { register osc_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, osc_susp_node, "snd_make_osc"); susp->ph_incr = 0; susp->the_table = sound_to_table(input); susp->table_ptr = susp->the_table->samples; susp->table_len = susp->the_table->length; susp->phase = compute_phase(phase, step, (long) susp->table_len, input->sr, sr, hz, &susp->ph_incr); susp->susp.fetch = osc__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = osc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = osc_print_tree; susp->susp.name = "osc"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_osc(sound_type input, double step, rate_type sr, double hz, time_type t0, time_type d, double phase) { return snd_make_osc(input, step, sr, hz, t0, d, phase); } nyquist-3.05/tran/stkrev.c0000644000175000000620000002105211466723256014625 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "stkrev.h" void stkrev_free(); typedef struct stkrev_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; struct stkEffect *myrv; } stkrev_susp_node, *stkrev_susp_type; #include "stkint.h" void stkrev_n_fetch(register stkrev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct stkEffect * myrv_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "stkrev_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; myrv_reg = susp->myrv; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (stkEffectTick(myrv_reg, *s1_ptr_reg++)) ; } while (--n); /* inner loop */ susp->myrv = myrv_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* stkrev_n_fetch */ void stkrev_s_fetch(register stkrev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct stkEffect * myrv_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "stkrev_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; myrv_reg = susp->myrv; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (stkEffectTick(myrv_reg, (s1_scale_reg * *s1_ptr_reg++))) ; } while (--n); /* inner loop */ susp->myrv = myrv_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* stkrev_s_fetch */ void stkrev_toss_fetch(susp, snd_list) register stkrev_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void stkrev_mark(stkrev_susp_type susp) { sound_xlmark(susp->s1); } void stkrev_free(stkrev_susp_type susp) { deleteStkEffect(susp->myrv); sound_unref(susp->s1); ffree_generic(susp, sizeof(stkrev_susp_node), "stkrev_free"); } void stkrev_print_tree(stkrev_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_stkrev(int rev_type, sound_type s1, time_type trev, double mix, rate_type sr) { register stkrev_susp_type susp; /* sr specified as input parameter */ time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, stkrev_susp_node, "snd_make_stkrev"); susp->myrv = initStkEffect(rev_type, trev, round(sr)); stkEffectSetMix(susp->myrv, mix); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = stkrev_n_fetch; break; case INTERP_s: susp->susp.fetch = stkrev_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = stkrev_toss_fetch; } /* initialize susp state */ susp->susp.free = stkrev_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = stkrev_mark; susp->susp.print_tree = stkrev_print_tree; susp->susp.name = "stkrev"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_stkrev(int rev_type, sound_type s1, time_type trev, double mix, rate_type sr) { sound_type s1_copy = sound_copy(s1); return snd_make_stkrev(rev_type, s1_copy, trev, mix, sr); } nyquist-3.05/tran/areson.alg0000644000175000000620000000172610144436365015117 0ustar stevestaff(ARESON-ALG (NAME "areson") (ARGUMENTS ("sound_type" "input") ("double" "hz") ("double" "bw") ("int" "normalization")) (START (MIN input)) (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) (LINEAR input) (STATE ("double" "c3" "exp(bw * -PI2 / input->sr)") ("double" "c3p1" "susp->c3 + 1.0" TEMP) ("double" "c3t4" "susp->c3 * 4.0" TEMP) ("double" "omc3" "1.0 - susp->c3" TEMP) ("double" "c2" "c3t4 * cos(hz * PI2 / input->sr) / c3p1") ("double" "c1" "(normalization == 0 ? 0.0 : (normalization == 1 ? 1.0 - omc3 * sqrt(1.0 - susp->c2 * susp->c2 / c3t4) : 1.0 - sqrt(c3p1 * c3p1 - susp->c2 * susp->c2) * omc3 / c3p1))") ("double" "y1" "0.0") ("double" "y2" "0.0")) (CONSTANT "c1" "c2" "c3") (INNER-LOOP-LOCALS " register double y0, current;") (INNER-LOOP "current = input; output = (sample_type) (y0 = c1 * current + c2 * y1 - c3 * y2); y2 = y1; y1 = y0 - current") ) nyquist-3.05/tran/instrclarfreq.c0000644000175000000620000002306510144436365016166 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrclarfreq.h" void clarinet_freq_free(); typedef struct clarinet_freq_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; struct instr *clar; int temp_ret_value; double frequency; } clarinet_freq_susp_node, *clarinet_freq_susp_type; #include "instr.h" void clarinet_freq_nn_fetch(register clarinet_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * clar_reg; register double frequency_reg; register sample_block_values_type freq_env_ptr_reg; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "clarinet_freq_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; clar_reg = susp->clar; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(clar_reg, 128, CLAR_CONTROL_CHANGE_CONST * *breath_env_ptr_reg++); setFrequency(clar_reg, frequency_reg + *freq_env_ptr_reg++); *out_ptr_reg++ = (sample_type) tick(clar_reg); } while (--n); /* inner loop */ susp->clar = clar_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* clarinet_freq_nn_fetch */ void clarinet_freq_ss_fetch(register clarinet_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * clar_reg; register double frequency_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "clarinet_freq_ss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; clar_reg = susp->clar; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(clar_reg, 128, CLAR_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); setFrequency(clar_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(clar_reg); } while (--n); /* inner loop */ susp->clar = clar_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* clarinet_freq_ss_fetch */ void clarinet_freq_toss_fetch(susp, snd_list) register clarinet_freq_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void clarinet_freq_mark(clarinet_freq_susp_type susp) { sound_xlmark(susp->breath_env); sound_xlmark(susp->freq_env); } void clarinet_freq_free(clarinet_freq_susp_type susp) { deleteInstrument(susp->clar); sound_unref(susp->breath_env); sound_unref(susp->freq_env); ffree_generic(susp, sizeof(clarinet_freq_susp_node), "clarinet_freq_free"); } void clarinet_freq_print_tree(clarinet_freq_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); } sound_type snd_make_clarinet_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr) { register clarinet_freq_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, clarinet_freq_susp_node, "snd_make_clarinet_freq"); susp->clar = initInstrument(CLARINET, round(sr)); controlChange(susp->clar, 1, 0.0);; susp->temp_ret_value = noteOn(susp->clar, freq, 1.0); susp->frequency = freq; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(breath_env, sr); interp_desc = (interp_desc << 2) + interp_style(freq_env, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = clarinet_freq_nn_fetch; break; case INTERP_ss: susp->susp.fetch = clarinet_freq_ss_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, min(freq_env->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = clarinet_freq_toss_fetch; } /* initialize susp state */ susp->susp.free = clarinet_freq_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = clarinet_freq_mark; susp->susp.print_tree = clarinet_freq_print_tree; susp->susp.name = "clarinet_freq"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_clarinet_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); sound_type freq_env_copy = sound_copy(freq_env); return snd_make_clarinet_freq(freq, breath_env_copy, freq_env_copy, sr); } nyquist-3.05/tran/biquadfilt.alg0000644000175000000620000000153311466723256015756 0ustar stevestaff; general order-2 IIR filter. ; a0 is assumed to be unity. ; for a1 and a2, our sign convention is opposite to Matlab's. (SNDBIQUAD-ALG (NAME "biquadfilt") (LISPNAME "biquad") (ARGUMENTS ("sound_type" "s") ("double" "b0") ("double" "b1") ("double" "b2") ("double" "a1") ("double" "a2") ("double" "z1init") ("double" "z2init")) (START (MIN s)) (TERMINATE (MIN s)) (LOGICAL-STOP (MIN s)) (STATE ("double" "z1" "z1init") ("double" "z2" "z2init") ("double" "b0" "b0") ("double" "b1" "b1") ("double" "b2" "b2") ("double" "a1" "a1") ("double" "a2" "a2")) (CONSTANT "b0" "b1" "b2" "a1" "a2") (INNER-LOOP-LOCALS "double z0;") (INNER-LOOP " z0 = s + a1*z1 + a2*z2; output = (sample_type) (z0*b0 + z1*b1 + z2*b2); z2 = z1; z1 = z0;") ) nyquist-3.05/tran/stkrev.alg0000644000175000000620000000102511466723256015144 0ustar stevestaff(STKREV-ALG (NAME "stkrev") (ARGUMENTS ("int" "rev_type")("sound_type" "s1")("time_type" "trev")("double" "mix")("rate_type" "sr")) (STATE ("struct stkEffect *" "myrv" "initStkEffect(rev_type, trev, round(sr)); stkEffectSetMix(susp->myrv, mix)")) (START (MIN s1)) (TERMINATE (MIN s1)) (LOGICAL-STOP (MIN s1)) (NOT-IN-INNER-LOOP "myrv" "trev") (SAMPLE-RATE "sr") (SUPPORT-FUNCTIONS " #include \"stkint.h\" ") (INNER-LOOP " output = (sample_type) (stkEffectTick(myrv, s1)) ") (FINALIZATION " deleteStkEffect(susp->myrv); ") )nyquist-3.05/tran/shape.alg0000644000175000000620000000276410144436365014733 0ustar stevestaff(SHAPE-ALG (NAME "shape") (ARGUMENTS ("sound_type" "sin") ("sound_type" "fn") ("double" "origin")) (START (MIN sin)) (TABLE "fn") (NOT-IN-INNER-LOOP "fn") (STATE ("double" "time_to_index" "fn->sr") ("double" "origin" "origin") ("table_type" "the_table" "sound_to_table(fn)") ("sample_type *" "fcn_table" "susp->the_table->samples") ("double" "table_len" "susp->the_table->length") ) (TERMINATE (MIN sin)) (LOGICAL-STOP (MIN sin)) (INNER-LOOP " register double offset, x1; register long table_index; register double phase = sin; if (phase > 1.0) phase = 1.0; else if (phase < -1.0) phase = -1.0; offset = (phase + origin) * time_to_index; table_index = (long) offset; if (table_index < 0) { table_index = 0; offset = 0; } if (table_index >= table_len) { offset = table_len - 1; table_index = (long) offset; } x1 = fcn_table[table_index]; output = (sample_type) (x1 + (offset - table_index) * (fcn_table[table_index + 1] - x1)); ") (ALWAYS-SCALE sin) (CONSTANT "table_len" "time_to_index" "origen" "fcn_table" "the_table") (FINALIZATION "table_unref(susp->the_table);") ) nyquist-3.05/tran/instrflute.alg0000644000175000000620000000134511466723256016032 0ustar stevestaff(INSTRFLUTE-ALG (NAME "flute") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("rate_type" "sr")) (STATE ("struct instr *" "myflute" "initInstrument(FLUTE, round(sr)); controlChange(susp->myflute, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->myflute, freq, 1.0)")) (START (min breath_env)) (NOT-IN-INNER-LOOP "freq" "temp_ret_value") (SAMPLE-RATE "sr") (ALWAYS-SCALE breath_env) (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(myflute, 128, FLUTE_CONTROL_CHANGE_CONST * breath_env); output = (sample_type) tick(myflute)") (SUPPORT-HEADER " #define FLUTE_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->myflute); ") ) nyquist-3.05/tran/alpassvc.alg0000644000175000000620000000534010144436365015440 0ustar stevestaff(ALPASSVC-ALG ;; ;; delay is variable -- but we don't want to reallocate the delay buffer, so ;; use an additional parameter for the maximum allowable delay. The sound will ;; be written into the buffer every sample, but read using linear ;; interpolation. As in tapv, duplicate the sample at the first and last ;; locations in the buffer. ;; (NAME "alpassvc") (ARGUMENTS ("sound_type" "input") ("sound_type" "delaysnd") ("double" "feedback") ("double" "maxdelay")) (START (MAX input delaysnd)) (STATE ("float" "delay_scale_factor" "(float) (input->sr * delaysnd->scale)") ("double" "feedback" "feedback") ("long" "buflen" "max(2, (long) (input->sr * maxdelay + 2.5))") ("sample_type *" "delaybuf" "(sample_type *) calloc (susp->buflen + 1, sizeof(sample_type))") ("sample_type *" "delayptr" "susp->delaybuf") ;; since we allocate one extra sample, endptr points to the last sample ("sample_type *" "endptr" "susp->delaybuf + susp->buflen")) (CONSTANT "feedback" "delaylen" "endptr" "delay_scale_factor") (NOT-REGISTER delaybuf) (LINEAR input) (TERMINATE (MIN input)) (INNER-LOOP-LOCALS " register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr;\n") (INNER-LOOP " /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ delaysamp = delaysnd * delay_scale_factor; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr + buflen - (delayi + 1); if (yptr >= endptr) yptr -= buflen; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr++ = z = (sample_type) (feedback * y + input); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr > endptr) { delayptr = susp->delaybuf; *delayptr++ = *endptr; } output = (sample_type) (y - feedback * z);") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/fmfb.c0000644000175000000620000000732711466723256014232 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "fmfb.h" void fmfb_free(); typedef struct fmfb_susp_struct { snd_susp_node susp; long terminate_cnt; double yy; double sin_y; double xx; double x_incr; double index; } fmfb_susp_node, *fmfb_susp_type; void fmfb__fetch(register fmfb_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double yy_reg; register double sin_y_reg; register double xx_reg; register double x_incr_reg; register double index_reg; falloc_sample_block(out, "fmfb__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; yy_reg = susp->yy; sin_y_reg = susp->sin_y; xx_reg = susp->xx; x_incr_reg = susp->x_incr; index_reg = susp->index; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ xx_reg += x_incr_reg; if (xx_reg > SINE_TABLE_LEN) xx_reg -= SINE_TABLE_LEN; /* xx_reg incremented and index_reg scaled to table index_reg, and sin_y_reg is a signal (-1 to +1) */ yy_reg = xx_reg + index_reg * sin_y_reg; /* so yy_reg is a table index_reg */ while (yy_reg > SINE_TABLE_LEN) yy_reg -= SINE_TABLE_LEN; while (yy_reg < 0) yy_reg += SINE_TABLE_LEN; sin_y_reg = sine_table[(int) yy_reg]; /* truncation gets valid index_reg */ /* sin_y_reg is now a signal not ready for table lookup */ *out_ptr_reg++ = sin_y_reg;; } while (--n); /* inner loop */ susp->yy = yy_reg; susp->sin_y = sin_y_reg; susp->xx = xx_reg; susp->index = index_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* fmfb__fetch */ void fmfb_free(fmfb_susp_type susp) { ffree_generic(susp, sizeof(fmfb_susp_node), "fmfb_free"); } void fmfb_print_tree(fmfb_susp_type susp, int n) { } sound_type snd_make_fmfb(time_type t0, double hz, rate_type sr, double index, time_type d) { register fmfb_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, fmfb_susp_node, "snd_make_fmfb"); susp->yy = 0.0; susp->sin_y = 0.0; susp->xx = 0.0; susp->x_incr = hz * SINE_TABLE_LEN / sr; susp->index = index * SINE_TABLE_LEN / PI2; susp->susp.fetch = fmfb__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = fmfb_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = fmfb_print_tree; susp->susp.name = "fmfb"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_fmfb(time_type t0, double hz, rate_type sr, double index, time_type d) { return snd_make_fmfb(t0, hz, sr, index, d); } nyquist-3.05/tran/exp.h0000644000175000000620000000015310144436365014101 0ustar stevestaffsound_type snd_make_exp(sound_type in); sound_type snd_exp(sound_type in); /* LISP: (snd-exp SOUND) */ nyquist-3.05/tran/sqrt.alg0000644000175000000620000000040310144436365014610 0ustar stevestaff(SQRT-ALG (NAME "sqrt") (ARGUMENTS ("sound_type" "input")) (ALWAYS-SCALE input) (START (MIN input)) (INNER-LOOP "{ sample_type i = input; if (i < 0) i = 0; output = (sample_type) sqrt(i); }") (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) ) nyquist-3.05/tran/scale.c0000644000175000000620000001265611466723256014410 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "scale.h" void normalize_free(); typedef struct normalize_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sample_type scale; } normalize_susp_node, *normalize_susp_type; void normalize_n_fetch(register normalize_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type scale_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "normalize_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale_reg = susp->scale; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *s1_ptr_reg++ * scale_reg; } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* normalize_n_fetch */ void normalize_toss_fetch(susp, snd_list) register normalize_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void normalize_mark(normalize_susp_type susp) { sound_xlmark(susp->s1); } void normalize_free(normalize_susp_type susp) { sound_unref(susp->s1); ffree_generic(susp, sizeof(normalize_susp_node), "normalize_free"); } void normalize_print_tree(normalize_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_normalize(sound_type s1) { register normalize_susp_type susp; rate_type sr = s1->sr; time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, normalize_susp_node, "snd_make_normalize"); susp->scale = s1->scale; susp->susp.fetch = normalize_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = normalize_toss_fetch; } /* initialize susp state */ susp->susp.free = normalize_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = normalize_mark; susp->susp.print_tree = normalize_print_tree; susp->susp.name = "normalize"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_normalize(sound_type s1) { sound_type s1_copy = sound_copy(s1); return snd_make_normalize(s1_copy); } nyquist-3.05/tran/innerloop.lsp0000644000175000000620000002744510144436365015676 0ustar stevestaff;; innerloop.lsp -- code to generate inner loops from specs ;; the inner loop has a setup, a loop, and a cleanup ;; in the setup, structure fields used in the inner loop are ;; copied or "cached" into register variables ;; in the inner loop, access expressions are substituted for ;; variable names in the spec ;; in the cleanup, resulting register variable "cache" is copied ;; back into the structure fields (defun compute-inner-loop (alg inner-loop) (let ((interp (get-slot alg 'interpolation)) (sound-names (get alg 'sound-names)) (state-list (get-slot alg 'state)) (step-function (get alg 'step-function)) (maintain-list (get-slot alg 'maintain)) (constant-list (get-slot alg 'constant)) (force-into-register (get-slot alg 'force-into-register)) (not-register (get-slot alg 'not-register)) register-decl register-init register-cleanup new-state-list ) ;; this loop computes and applies substitutions to the INNER-LOOP spec (setf inner-loop (substitute inner-loop "output" "*out_ptr_reg++" nil)) (push "\tout_ptr_reg = out_ptr;\n" register-init) (push "\tout_ptr += togo;\n" register-cleanup) (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp)) expression) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((eq method 'NONE) ;----------------- ; NONE: ; ::= *NAME_ptr_reg++ ;----------------- (pushnew (format nil " register sample_block_values_type ~A_ptr_reg;~%" name) register-decl) (pushnew (format nil "\t~A_ptr_reg = susp->~A_ptr;~%" name name) register-init) (pushnew (format nil "\t/* using ~A_ptr_reg is a bad idea on RS/6000: */~ ~%\tsusp->~A_ptr += togo;~%" name name name) register-cleanup) (setf expression (format nil "*~A_ptr_reg++" name))) ((eq method 'SCALE) ;----------------- ; SCALE ; ::= (NAME_scale_reg * *NAME_ptr_reg++) ;----------------- (pushnew (format nil " register sample_block_values_type ~A_ptr_reg;~%" name) register-decl) (pushnew (format nil " register sample_type ~A_scale_reg = susp->~A->scale;~%" name name) register-decl) (pushnew (format nil "\t~A_ptr_reg = susp->~A_ptr;~%" name name) register-init) (pushnew (format nil "\t/* using ~A_ptr_reg is a bad idea on RS/6000: */~ ~%\tsusp->~A_ptr += togo;~%" name name name) register-cleanup) (setf expression (format nil "(~A_scale_reg * *~A_ptr_reg++)" name name))) ((and interpolate-samples (eq method 'INTERP)) ;----------------- ; INTERP: ; ::= susp->NAME_x1_sample * (1 - ; susp->NAME_pHaSe + ; susp->NAME_x2_sample * susp->NAME_pHaSe) ;----------------- (pushnew (format nil " register sample_type ~A_x1_sample_reg;~%" name) register-decl) (pushnew (format nil " register double ~A_pHaSe_ReG;~%" name) register-decl) (pushnew (format nil " register double ~A_pHaSe_iNcR_rEg = susp->~A_pHaSe_iNcR;~%" name name) register-decl) (pushnew (format nil "\t~A_x1_sample_reg = susp->~A_x1_sample;~%" name name) register-init) (pushnew (format nil "\t~A_pHaSe_ReG = susp->~A_pHaSe;~%" name name) register-init) (pushnew (format nil "\tsusp->~A_x1_sample = ~A_x1_sample_reg;~%" name name) register-cleanup) (pushnew (format nil "\tsusp->~A_pHaSe = ~A_pHaSe_ReG;~%" name name) register-cleanup) (setf expression (format nil "\n\t\t(~A_x1_sample_reg * (1 - ~A_pHaSe_ReG) + ~A_x2_sample * ~A_pHaSe_ReG)" name name name name))) ((eq method 'INTERP) ;----------------- ; STEP FUNCTION: ; ::= NAME_x1_sample_reg ;----------------- (pushnew (format nil " register sample_type ~A_x1_sample_reg;~%" name) register-decl) (pushnew (format nil " register double ~A_pHaSe_ReG;~%" name) register-decl) (pushnew (format nil " register double ~A_pHaSe_iNcR_rEg = susp->~A_pHaSe_iNcR;~%" name name) register-decl) (pushnew (format nil "\t~A_x1_sample_reg = susp->~A_x1_sample;~%" name name) register-init) (pushnew (format nil "\t~A_pHaSe_ReG = susp->~A_pHaSe;~%" name name) register-init) (pushnew (format nil "\tsusp->~A_x1_sample = ~A_x1_sample_reg;~%" name name) register-cleanup) (pushnew (format nil "\tsusp->~A_pHaSe = ~A_pHaSe_ReG;~%" name name) register-cleanup) (setf expression (format nil "~A_x1_sample_reg" name))) ((and interpolate-samples (eq method 'RAMP)) ;----------------- ; RAMP: ; ::= NAME_val ;----------------- (setf expression (format nil "~A_val" name))) ((eq method 'RAMP) ;----------------- ; RAMP: ; ::= NAME_val ;----------------- ; this doesn't seem to be used -RBD 7/97 ;(pushnew (format nil ;" register sample_type ~A_x1_sample_reg;~%" name) ;register-decl) (setf expression (format nil "~A_val" name)))) (setf inner-loop (substitute inner-loop name expression nil)) )) ;; determine the members of state-list that are actually referenced in ;; the inner loop. If not, don't cache the state in registers before ;; starting the loop. (dolist (state state-list) (let ((var-name (cadr state))) (cond ((and (or (string-search var-name inner-loop) (member (name-to-symbol var-name) force-into-register)) (not (member (name-to-symbol var-name) not-register))) (push state new-state-list))))) ;; this loop applies substitutions for state variables: ;; the specified state variable name is the cadr of state-list element ;; the state variable is replaced in inner-loop by _reg (dolist (state new-state-list) (let ((var-name (cadr state)) maintain) (pushnew (format nil " register ~A ~A_reg;~%" (car state) var-name) register-decl) (pushnew (format nil "\t~A_reg = susp->~A;~%" var-name var-name) register-init) (setf maintain (find-maintain-stmt var-name maintain-list)) ; (display "find-maintain-stmt returned:" maintain) (cond (maintain (pushnew (format nil "\t~A;~%" maintain) register-cleanup)) ((not (is-constant-in-inner-loop var-name constant-list)) ;(pushnew (format nil "var-name: ~A constant-list: ~A~%" var-name constant-list) ; register-cleanup) (pushnew (format nil "\tsusp->~A = ~A_reg;~%" var-name var-name) register-cleanup))) (setf inner-loop (substitute inner-loop var-name (format nil "~A_reg" var-name) t)) )) ;(display "register decls" state-list register-decl) (read) ;; if the user-written code has a break statement or if the interpolation ;; type is INTERP, we need to write out "togo -= n;" to get an accurate ;; count of how many times we went through the loop. Otherwise don't do it ;; because it makes n a live variable and affects compiler optimization. (cond ((or (member 'INTERP interp) (string-search "break" inner-loop)) (push "\ttogo -= n;\n" register-cleanup))) (put-slot alg inner-loop 'inner-loop-stmts) (put-slot alg register-decl 'register-decl) (put-slot alg register-init 'register-init) (put-slot alg register-cleanup 'register-cleanup) ;----------------- ; WATCH: ; ; show_samples(1,s1,s1_ptr - s1->samples) ; ; Note: this is not right because we need to have the correct ; parameter for s1, but that is part of the s1_ptr++ computation ; so I don't know where to get it... ;----------------- ; (if *WATCH* ; (format stream "\t show_samples(1,s1,s1_ptr - s1_samples);~%") ; ) )) ;; find-maintain-list -- find an assignment for variable in a MAINTAIN spec ;; (defun find-maintain-stmt (var specs) (let ((spec (assoc var specs :test #'equal))) (if spec (cadr spec)))) ;; is-constant-in-inner-loop -- see if var is in constant-list ;; (defun is-constant-in-inner-loop (var constant-list) (member var constant-list :test #'equal)) ;; pushnew -- pushes string onto list unless already there ;; (defmacro pushnew (string var) `(if (not (member ,string ,var :test #'equal)) (push ,string ,var))) ;;********** ;; substitute -- string substitution ;; Inputs: ;; s - input string ;; pat - pattern ;; repl - replacement for pattern ;; all - T or NIL (T : replace everywhere; NIL : replace once) ;; ;;********** (defun substitute (s pat repl all) ; (display "substitute" s pat repl) (let ((p (position s pat)) (l (length pat))) (cond (p (strcat (subseq s 0 p) repl ;; the remainder of the string depends on all. If T, then ;; use recursion to continue substitutions: (cond (all (substitute (subseq s (+ p l)) pat repl all)) (t (subseq s (+ p l)))))) (t s)))) (defun write-inner-loop (alg stream) (let ((interp (get-slot alg 'interpolation)) (step-function (get alg 'step-function)) (sound-names (get alg 'sound-names)) ) (format stream "~A;~%" (get-slot alg 'inner-loop-stmts)) (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((eq method 'INTERP) ;----------------- ; INTERP: ; ; NAME_pHaSe_ReG += NAME_pHaSe_iNcR_rEg; ;----------------- (format stream "\t ~A_pHaSe_ReG += ~A_pHaSe_iNcR_rEg;~%" name name)) ((and interpolate-samples (eq method 'RAMP)) ;----------------- ; RAMP: ; NAME_val += NAME_DeLtA ;----------------- (format stream "\t ~A_val += ~A_DeLtA;~%" name name))))) ;---------------------------- ; WATCH: ; show_samples(0,out,out_ptr - 1 - out->samples); ;---------------------------- ; (if *WATCH* ; (format stream "\t show_samples(0,out,out_ptr - 1 - out->samples);~%")) ;---------------------------- ; } while (--n); /* inner loop */ ;---------------------------- (format stream "\t} while (--n); /* inner loop */~%~%"))) nyquist-3.05/tran/osc.h0000644000175000000620000000047110144436365014074 0ustar stevestaffsound_type snd_make_osc(sound_type input, double step, rate_type sr, double hz, time_type t0, time_type d, double phase); sound_type snd_osc(sound_type input, double step, rate_type sr, double hz, time_type t0, time_type d, double phase); /* LISP: (snd-osc SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/tapv.c0000644000175000000620000005104011466723256014261 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "tapv.h" void tapv_free(); typedef struct tapv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type vardelay; long vardelay_cnt; sample_block_values_type vardelay_ptr; /* support for interpolation of vardelay */ sample_type vardelay_x1_sample; double vardelay_pHaSe; double vardelay_pHaSe_iNcR; /* support for ramp between samples of vardelay */ double output_per_vardelay; long vardelay_n; double offset; double vdscale; double maxdelay; long bufflen; long index; sample_type *buffer; } tapv_susp_node, *tapv_susp_type; void tapv_sn_fetch(register tapv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double offset_reg; register double vdscale_reg; register double maxdelay_reg; register long bufflen_reg; register long index_reg; register sample_type * buffer_reg; register sample_block_values_type vardelay_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tapv_sn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the vardelay input sample block: */ susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); togo = min(togo, susp->vardelay_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; vdscale_reg = susp->vdscale; maxdelay_reg = susp->maxdelay; bufflen_reg = susp->bufflen; index_reg = susp->index; buffer_reg = susp->buffer; vardelay_ptr_reg = susp->vardelay_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double phase; long i; phase = *vardelay_ptr_reg++ * vdscale_reg + offset_reg; /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay_reg) phase = maxdelay_reg; phase = (double) index_reg - phase; /* now phase is a location in the buffer_reg (before modulo) */ /* Time out to update the buffer_reg: * this is a tricky buffer_reg: buffer_reg[0] == buffer_reg[bufflen_reg] * the logical length is bufflen_reg, but the actual length * is bufflen_reg + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer_reg[index_reg++] = (s1_scale_reg * *s1_ptr_reg++); if (index_reg > bufflen_reg) { buffer_reg[0] = buffer_reg[bufflen_reg]; index_reg = 1; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen_reg; i = (long) phase; /* put integer part in i */ phase -= (double) i; /* put fractional part in phase */ *out_ptr_reg++ = (sample_type) (buffer_reg[i] * (1.0 - phase) + buffer_reg[i + 1] * phase);; } while (--n); /* inner loop */ susp->bufflen = bufflen_reg; susp->index = index_reg; /* using vardelay_ptr_reg is a bad idea on RS/6000: */ susp->vardelay_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(vardelay_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tapv_sn_fetch */ void tapv_si_fetch(register tapv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type vardelay_x2_sample; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double offset_reg; register double vdscale_reg; register double maxdelay_reg; register long bufflen_reg; register long index_reg; register sample_type * buffer_reg; register double vardelay_pHaSe_iNcR_rEg = susp->vardelay_pHaSe_iNcR; register double vardelay_pHaSe_ReG; register sample_type vardelay_x1_sample_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tapv_si_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); susp->vardelay_x1_sample = (susp->vardelay_cnt--, *(susp->vardelay_ptr)); } susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); vardelay_x2_sample = *(susp->vardelay_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; vdscale_reg = susp->vdscale; maxdelay_reg = susp->maxdelay; bufflen_reg = susp->bufflen; index_reg = susp->index; buffer_reg = susp->buffer; vardelay_pHaSe_ReG = susp->vardelay_pHaSe; vardelay_x1_sample_reg = susp->vardelay_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double phase; long i; if (vardelay_pHaSe_ReG >= 1.0) { vardelay_x1_sample_reg = vardelay_x2_sample; /* pick up next sample as vardelay_x2_sample: */ susp->vardelay_ptr++; susp_took(vardelay_cnt, 1); vardelay_pHaSe_ReG -= 1.0; susp_check_term_samples_break(vardelay, vardelay_ptr, vardelay_cnt, vardelay_x2_sample); } phase = (vardelay_x1_sample_reg * (1 - vardelay_pHaSe_ReG) + vardelay_x2_sample * vardelay_pHaSe_ReG) * vdscale_reg + offset_reg; /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay_reg) phase = maxdelay_reg; phase = (double) index_reg - phase; /* now phase is a location in the buffer_reg (before modulo) */ /* Time out to update the buffer_reg: * this is a tricky buffer_reg: buffer_reg[0] == buffer_reg[bufflen_reg] * the logical length is bufflen_reg, but the actual length * is bufflen_reg + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer_reg[index_reg++] = (s1_scale_reg * *s1_ptr_reg++); if (index_reg > bufflen_reg) { buffer_reg[0] = buffer_reg[bufflen_reg]; index_reg = 1; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen_reg; i = (long) phase; /* put integer part in i */ phase -= (double) i; /* put fractional part in phase */ *out_ptr_reg++ = (sample_type) (buffer_reg[i] * (1.0 - phase) + buffer_reg[i + 1] * phase);; vardelay_pHaSe_ReG += vardelay_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->bufflen = bufflen_reg; susp->index = index_reg; susp->vardelay_pHaSe = vardelay_pHaSe_ReG; susp->vardelay_x1_sample = vardelay_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tapv_si_fetch */ void tapv_sr_fetch(register tapv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type vardelay_DeLtA; sample_type vardelay_val; sample_type vardelay_x2_sample; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double offset_reg; register double vdscale_reg; register double maxdelay_reg; register long bufflen_reg; register long index_reg; register sample_type * buffer_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tapv_sr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->vardelay_pHaSe = 1.0; } susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); vardelay_x2_sample = *(susp->vardelay_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next vardelay_x2_sample when phase goes past 1.0; */ /* we use vardelay_n (computed below) to avoid roundoff errors: */ if (susp->vardelay_n <= 0) { susp->vardelay_x1_sample = vardelay_x2_sample; susp->vardelay_ptr++; susp_took(vardelay_cnt, 1); susp->vardelay_pHaSe -= 1.0; susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); vardelay_x2_sample = *(susp->vardelay_ptr); /* vardelay_n gets number of samples before phase exceeds 1.0: */ susp->vardelay_n = (long) ((1.0 - susp->vardelay_pHaSe) * susp->output_per_vardelay); } togo = min(togo, susp->vardelay_n); vardelay_DeLtA = (sample_type) ((vardelay_x2_sample - susp->vardelay_x1_sample) * susp->vardelay_pHaSe_iNcR); vardelay_val = (sample_type) (susp->vardelay_x1_sample * (1.0 - susp->vardelay_pHaSe) + vardelay_x2_sample * susp->vardelay_pHaSe); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; vdscale_reg = susp->vdscale; maxdelay_reg = susp->maxdelay; bufflen_reg = susp->bufflen; index_reg = susp->index; buffer_reg = susp->buffer; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double phase; long i; phase = vardelay_val * vdscale_reg + offset_reg; /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay_reg) phase = maxdelay_reg; phase = (double) index_reg - phase; /* now phase is a location in the buffer_reg (before modulo) */ /* Time out to update the buffer_reg: * this is a tricky buffer_reg: buffer_reg[0] == buffer_reg[bufflen_reg] * the logical length is bufflen_reg, but the actual length * is bufflen_reg + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer_reg[index_reg++] = (s1_scale_reg * *s1_ptr_reg++); if (index_reg > bufflen_reg) { buffer_reg[0] = buffer_reg[bufflen_reg]; index_reg = 1; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen_reg; i = (long) phase; /* put integer part in i */ phase -= (double) i; /* put fractional part in phase */ *out_ptr_reg++ = (sample_type) (buffer_reg[i] * (1.0 - phase) + buffer_reg[i + 1] * phase);; vardelay_val += vardelay_DeLtA; } while (--n); /* inner loop */ susp->bufflen = bufflen_reg; susp->index = index_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->vardelay_pHaSe += togo * susp->vardelay_pHaSe_iNcR; susp->vardelay_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tapv_sr_fetch */ void tapv_toss_fetch(susp, snd_list) register tapv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from vardelay up to final_time for this block of zeros */ while ((round((final_time - susp->vardelay->t0) * susp->vardelay->sr)) >= susp->vardelay->current) susp_get_samples(vardelay, vardelay_ptr, vardelay_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->vardelay->t0) * susp->vardelay->sr - (susp->vardelay->current - susp->vardelay_cnt)); susp->vardelay_ptr += n; susp_took(vardelay_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void tapv_mark(tapv_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->vardelay); } void tapv_free(tapv_susp_type susp) { free(susp->buffer); sound_unref(susp->s1); sound_unref(susp->vardelay); ffree_generic(susp, sizeof(tapv_susp_node), "tapv_free"); } void tapv_print_tree(tapv_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("vardelay:"); sound_print_tree_1(susp->vardelay, n); } sound_type snd_make_tapv(sound_type s1, double offset, sound_type vardelay, double maxdelay) { register tapv_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, vardelay->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, tapv_susp_node, "snd_make_tapv"); susp->offset = offset * s1->sr; susp->vdscale = vardelay->scale * s1->sr; susp->maxdelay = maxdelay * s1->sr; susp->bufflen = max(2, (long) (susp->maxdelay + 1.5)); susp->index = susp->bufflen; susp->buffer = (sample_type *) calloc(susp->bufflen + 1, sizeof(sample_type)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(vardelay, sr); switch (interp_desc) { case INTERP_ns: /* handled below */ case INTERP_nn: /* handled below */ case INTERP_ss: /* handled below */ case INTERP_sn: susp->susp.fetch = tapv_sn_fetch; break; case INTERP_ni: /* handled below */ case INTERP_si: susp->susp.fetch = tapv_si_fetch; break; case INTERP_nr: /* handled below */ case INTERP_sr: susp->susp.fetch = tapv_sr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < vardelay->t0) sound_prepend_zeros(vardelay, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(vardelay->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = tapv_toss_fetch; } /* initialize susp state */ susp->susp.free = tapv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = tapv_mark; susp->susp.print_tree = tapv_print_tree; susp->susp.name = "tapv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->vardelay = vardelay; susp->vardelay_cnt = 0; susp->vardelay_pHaSe = 0.0; susp->vardelay_pHaSe_iNcR = vardelay->sr / sr; susp->vardelay_n = 0; susp->output_per_vardelay = sr / vardelay->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_tapv(sound_type s1, double offset, sound_type vardelay, double maxdelay) { sound_type s1_copy = sound_copy(s1); sound_type vardelay_copy = sound_copy(vardelay); return snd_make_tapv(s1_copy, offset, vardelay_copy, maxdelay); } nyquist-3.05/tran/instrflute.h0000644000175000000620000000036211466723256015514 0ustar stevestaffsound_type snd_make_flute(double freq, sound_type breath_env, rate_type sr); sound_type snd_flute(double freq, sound_type breath_env, rate_type sr); /* LISP: (snd-flute ANYNUM SOUND ANYNUM) */ #define FLUTE_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/sampler.h0000644000175000000620000000056110144436365014753 0ustar stevestaffsound_type snd_make_sampler(sound_type s, double step, double loop_start, rate_type sr, double hz, time_type t0, sound_type s_fm, long npoints); sound_type snd_sampler(sound_type s, double step, double loop_start, rate_type sr, double hz, time_type t0, sound_type s_fm, long npoints); /* LISP: (snd-sampler SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM SOUND FIXNUM) */ nyquist-3.05/tran/buzz.alg0000644000175000000620000000421511466723256014624 0ustar stevestaff(BUZZ-ALG (NAME "buzz") (ARGUMENTS ("long" "n") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("sound_type" "s_fm")) (SUPPORT-FUNCTIONS " #include \"sine.h\" ") (STATE ("double" "ph_incr" "0") ("float" "n_2_r" "1.0F / (n * 2)") ("float" "n_2_p1" "(n * 2) + 1") ;; note: hz * 0.5 because this formula generates tones an octave up, ;; we also have to correct for the modulation s_fm. If hz != 0, then ;; ph_incr is the increment per hz, so ph_incr/hz is the right scale ;; factor. If hz == 0, then the ph_incr/hz is SINE_TABLE_LEN * 0.5 / sr. ("double" "phase" "compute_phase(PI*0.5, 69.0, SINE_TABLE_LEN, SINE_TABLE_LEN * 440.0, sr, hz * 0.5, &susp->ph_incr); s_fm->scale *= hz != 0 ? (sample_type) (susp->ph_incr / hz) : (sample_type) (SINE_TABLE_LEN * 0.5 / sr)")) ;cancel 0/0 (ALWAYS-SCALE s_fm) (INLINE-INTERPOLATION T) ; so that modulation can be low frequency (STEP-FUNCTION s_fm) (TERMINATE (MIN s_fm)) (LOGICAL-STOP (MIN s_fm)) (INNER-LOOP-LOCALS " long table_index; double x1; sample_type num, denom, samp; ") (INNER-LOOP " table_index = (long) phase; x1 = sine_table[table_index]; denom = (sample_type) (x1 + (phase - table_index) * (sine_table[table_index + 1] - x1)); if (denom < 0.001 && denom > -0.005) { samp = 1.0F; } else { double phn2p1 = phase * n_2_p1 * (1.0/SINE_TABLE_LEN); phn2p1 = (phn2p1 - (long) phn2p1) * SINE_TABLE_LEN; table_index = (long) phn2p1; x1 = sine_table[table_index]; num = (sample_type) (x1 + (phn2p1 - table_index) * (sine_table[table_index + 1] - x1)); samp = ((num / denom) - 1.0F) * n_2_r; } output = samp; phase += ph_incr + s_fm; while (phase > SINE_TABLE_LEN) phase -= SINE_TABLE_LEN; /* watch out for negative frequencies! */ while (phase < 0) phase += SINE_TABLE_LEN") (CONSTANT "ph_incr" "n_2_p1" "n_2_r") (SAMPLE-RATE "sr") ) nyquist-3.05/tran/clip.c0000644000175000000620000002042111466723256014235 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "clip.h" void clip_free(); typedef struct clip_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; sample_type level; } clip_susp_node, *clip_susp_type; void clip_n_fetch(register clip_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type level_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "clip_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; level_reg = susp->level; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x = *s_ptr_reg++; *out_ptr_reg++ = (sample_type) (x > level_reg ? level_reg : (x < -level_reg ? -level_reg : x)); } while (--n); /* inner loop */ susp->level = level_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* clip_n_fetch */ void clip_s_fetch(register clip_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type level_reg; register sample_type s_scale_reg = susp->s->scale; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "clip_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; level_reg = susp->level; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x = (s_scale_reg * *s_ptr_reg++); *out_ptr_reg++ = (sample_type) (x > level_reg ? level_reg : (x < -level_reg ? -level_reg : x)); } while (--n); /* inner loop */ susp->level = level_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* clip_s_fetch */ void clip_toss_fetch(susp, snd_list) register clip_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s up to final_time for this block of zeros */ while ((round((final_time - susp->s->t0) * susp->s->sr)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void clip_mark(clip_susp_type susp) { sound_xlmark(susp->s); } void clip_free(clip_susp_type susp) { sound_unref(susp->s); ffree_generic(susp, sizeof(clip_susp_node), "clip_free"); } void clip_print_tree(clip_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_clip(sound_type s, double level) { register clip_susp_type susp; rate_type sr = s->sr; time_type t0 = s->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, clip_susp_node, "snd_make_clip"); susp->level = (sample_type) level; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = clip_n_fetch; break; case INTERP_s: susp->susp.fetch = clip_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); /* minimum start time over all inputs: */ t0_min = min(s->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = clip_toss_fetch; } /* initialize susp state */ susp->susp.free = clip_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = clip_mark; susp->susp.print_tree = clip_print_tree; susp->susp.name = "clip"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_clip(sound_type s, double level) { sound_type s_copy = sound_copy(s); return snd_make_clip(s_copy, level); } nyquist-3.05/tran/log.alg0000644000175000000620000000032610144436365014404 0ustar stevestaff(LOG-ALG (NAME "log") (ARGUMENTS ("sound_type" "input")) (ALWAYS-SCALE input) (START (MIN input)) (INNER-LOOP "output = (sample_type) log(input)") (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) ) nyquist-3.05/tran/resonvc.c0000644000175000000620000004327010144436365014766 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "resonvc.h" void resonvc_free(); typedef struct resonvc_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type hz; long hz_cnt; sample_block_values_type hz_ptr; /* support for interpolation of hz */ sample_type hz_x1_sample; double hz_pHaSe; double hz_pHaSe_iNcR; /* support for ramp between samples of hz */ double output_per_hz; long hz_n; double scale1; double c3co; double c3p1; double c3t4; double omc3; double c2; double c1; int normalization; double y1; double y2; } resonvc_susp_node, *resonvc_susp_type; void resonvc_ns_fetch(register resonvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type hz_scale_reg = susp->hz->scale; register sample_block_values_type hz_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvc_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz input sample block: */ susp_check_term_samples(hz, hz_ptr, hz_cnt); togo = min(togo, susp->hz_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz_ptr_reg = susp->hz_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ c2_reg = c3t4_reg * cos((hz_scale_reg * *hz_ptr_reg++)) / c3p1_reg; c1_reg = (normalization_reg == 0 ? scale1_reg : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using hz_ptr_reg is a bad idea on RS/6000: */ susp->hz_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvc_ns_fetch */ void resonvc_ni_fetch(register resonvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double hz_pHaSe_iNcR_rEg = susp->hz_pHaSe_iNcR; register double hz_pHaSe_ReG; register sample_type hz_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvc_ni_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->c2 = susp->c3t4 * cos(susp->hz_x1_sample) / susp->c3p1; susp->c1 = (susp->normalization == 0 ? susp->scale1 : (susp->normalization == 1 ? susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)) * susp->scale1; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz_pHaSe_ReG = susp->hz_pHaSe; hz_x1_sample_reg = susp->hz_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz_pHaSe_ReG >= 1.0) { /* fixup-depends hz */ /* pick up next sample as hz_x1_sample: */ susp->hz_ptr++; susp_took(hz_cnt, 1); hz_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz, hz_ptr, hz_cnt, hz_x1_sample_reg); hz_x1_sample_reg = susp_current_sample(hz, hz_ptr); c2_reg = susp->c2 = c3t4_reg * cos(hz_x1_sample_reg) / c3p1_reg; c1_reg = susp->c1 = (normalization_reg == 0 ? scale1_reg : (normalization_reg == 1 ? omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; hz_pHaSe_ReG += hz_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->hz_pHaSe = hz_pHaSe_ReG; susp->hz_x1_sample = hz_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvc_ni_fetch */ void resonvc_nr_fetch(register resonvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resonvc_nr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz_pHaSe = 1.0; } susp_check_term_samples(hz, hz_ptr, hz_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz_x1_sample when phase goes past 1.0; */ /* use hz_n (computed below) to avoid roundoff errors: */ if (susp->hz_n <= 0) { susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->hz_pHaSe -= 1.0; /* hz_n gets number of samples before phase exceeds 1.0: */ susp->hz_n = (long) ((1.0 - susp->hz_pHaSe) * susp->output_per_hz); susp->c2 = susp->c3t4 * cos(susp->hz_x1_sample) / susp->c3p1; susp->c1 = (susp->normalization == 0 ? susp->scale1 : (susp->normalization == 1 ? susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)) * susp->scale1; } togo = min(togo, susp->hz_n); hz_val = susp->hz_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz_pHaSe += togo * susp->hz_pHaSe_iNcR; susp->hz_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resonvc_nr_fetch */ void resonvc_toss_fetch(susp, snd_list) register resonvc_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from hz up to final_time for this block of zeros */ while ((round((final_time - susp->hz->t0) * susp->hz->sr)) >= susp->hz->current) susp_get_samples(hz, hz_ptr, hz_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->hz->t0) * susp->hz->sr - (susp->hz->current - susp->hz_cnt)); susp->hz_ptr += n; susp_took(hz_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void resonvc_mark(resonvc_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->hz); } void resonvc_free(resonvc_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->hz); ffree_generic(susp, sizeof(resonvc_susp_node), "resonvc_free"); } void resonvc_print_tree(resonvc_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("hz:"); sound_print_tree_1(susp->hz, n); } sound_type snd_make_resonvc(sound_type s1, sound_type hz, double bw, int normalization) { register resonvc_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, hz->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, resonvc_susp_node, "snd_make_resonvc"); susp->scale1 = s1->scale; susp->c3co = exp(bw * -PI2 / s1->sr); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->c2 = 0.0; susp->c1 = 0.0; susp->normalization = normalization; susp->y1 = 0.0; susp->y2 = 0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(hz, sr); switch (interp_desc) { case INTERP_sn: /* handled below */ case INTERP_ss: /* handled below */ case INTERP_nn: /* handled below */ case INTERP_ns: susp->susp.fetch = resonvc_ns_fetch; break; case INTERP_si: /* handled below */ case INTERP_ni: susp->susp.fetch = resonvc_ni_fetch; break; case INTERP_sr: /* handled below */ case INTERP_nr: susp->susp.fetch = resonvc_nr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < hz->t0) sound_prepend_zeros(hz, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(hz->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = resonvc_toss_fetch; } /* initialize susp state */ susp->susp.free = resonvc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = resonvc_mark; susp->susp.print_tree = resonvc_print_tree; susp->susp.name = "resonvc"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->hz = hz; susp->hz_cnt = 0; susp->hz_pHaSe = 0.0; susp->hz_pHaSe_iNcR = hz->sr / sr; susp->hz_n = 0; susp->output_per_hz = sr / hz->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_resonvc(sound_type s1, sound_type hz, double bw, int normalization) { sound_type s1_copy = sound_copy(s1); sound_type hz_copy = sound_copy(hz); return snd_make_resonvc(s1_copy, hz_copy, bw, normalization); } nyquist-3.05/tran/instrmodalbar.c0000644000175000000620000000600411466723256016150 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrmodalbar.h" void modalbar_free(); typedef struct modalbar_susp_struct { snd_susp_node susp; long terminate_cnt; struct instr *mymbar; int temp_ret_value; } modalbar_susp_node, *modalbar_susp_type; #include "instr.h" void modalbar__fetch(register modalbar_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mymbar_reg; falloc_sample_block(out, "modalbar__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mymbar_reg = susp->mymbar; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) tick(mymbar_reg); } while (--n); /* inner loop */ susp->mymbar = mymbar_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* modalbar__fetch */ void modalbar_free(modalbar_susp_type susp) { deleteInstrument(susp->mymbar); ffree_generic(susp, sizeof(modalbar_susp_node), "modalbar_free"); } void modalbar_print_tree(modalbar_susp_type susp, int n) { } sound_type snd_make_modalbar(time_type t0, double freq, int preset, time_type dur, rate_type sr) { register modalbar_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, modalbar_susp_node, "snd_make_modalbar"); susp->mymbar = initInstrument(MODALBAR, round(sr)); controlChange(susp->mymbar, 16, preset);; susp->temp_ret_value = noteOn(susp->mymbar, freq, 1.0);; susp->susp.fetch = modalbar__fetch; susp->terminate_cnt = round((dur) * sr); /* initialize susp state */ susp->susp.free = modalbar_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = modalbar_print_tree; susp->susp.name = "modalbar"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_modalbar(time_type t0, double freq, int preset, time_type dur, rate_type sr) { return snd_make_modalbar(t0, freq, preset, dur, sr); } nyquist-3.05/tran/offset.alg0000644000175000000620000000042010144436365015104 0ustar stevestaff(SCALE-ALG (NAME "offset") (ARGUMENTS ("sound_type" "s1") ("double" "offset")) (STATE ("sample_type" "offset" "(sample_type) offset")) (CONSTANT "offset") (START (MIN s1)) (INNER-LOOP "output = s1 + offset") (TERMINATE (MIN s1)) (LOGICAL-STOP (MIN s1)) ) nyquist-3.05/tran/coterm.alg0000644000175000000620000000040210144436365015107 0ustar stevestaff(COTERM-ALG (NAME "coterm") (ARGUMENTS ("sound_type" "s1") ("sound_type" "s2")) (START (MAX s1 s2)) (INNER-LOOP "{sample_type dummy = s2; output = s1;}") (LINEAR s1) (TERMINATE (MIN s1 s2)) (LOGICAL-STOP (MIN s1 s2)) (INTERNAL-SCALING s2) ) nyquist-3.05/tran/aresonvc.alg0000644000175000000620000000240310144436365015441 0ustar stevestaff(ARESONVC-ALG (NAME "aresonvc") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz") ("double" "bw") ("int" "normalization")) (LINEAR s1) (INLINE-INTERPOLATION T) (ALWAYS-SCALE hz) (START (MAX s1 hz)) (TERMINATE (MIN s1 hz)) (LOGICAL-STOP (MIN s1)) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION hz) (STATE ("double" "c3co" "exp(bw * -PI2 / s1->sr)") ("double" "c3p1" "susp->c3co + 1.0") ("double" "c3t4" "susp->c3co * 4.0") ("double" "omc3" "1.0 - susp->c3co") ("double" "c2" "0.0") ("double" "c1" "0.0") ("int" "normalization" "normalization") ("double" "y1" "0.0") ("double" "y2" "0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr))")) (DEPENDS ("c2" "hz" "c3t4 * cos(hz) / c3p1") ("c1" "hz" "(normalization == 0 ? 0.0 : (normalization == 1 ? 1.0 - omc3 * sqrt(1.0 - c2 * c2 / c3t4) : 1.0 - sqrt(c3p1 * c3p1 - c2 * c2) * omc3 / c3p1))")) (CONSTANT "c1" "c2" "c3co" "c3p1" "c3t4" "omc3" "normalization") (FORCE-INTO-REGISTER c3t4 c3p1 normalization omc3) (INNER-LOOP-LOCALS " register double y0, current;") (INNER-LOOP "current = s1; y0 = c1 * current + c2 * y1 - c3co * y2; output = (sample_type) y0; y2 = y1; y1 = y0 - current") ) nyquist-3.05/tran/siosc.h0000644000175000000620000000036010144436365014425 0ustar stevestaffsound_type snd_make_siosc(LVAL lis, rate_type sr, double hz, time_type t0, sound_type s_fm); sound_type snd_siosc(LVAL lis, rate_type sr, double hz, time_type t0, sound_type s_fm); /* LISP: (snd-siosc ANY ANYNUM ANYNUM ANYNUM SOUND) */ nyquist-3.05/tran/instrclar.c0000644000175000000620000001235010144436365015303 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrclar.h" void clarinet_free(); typedef struct clarinet_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; struct instr *clar; int temp_ret_value; } clarinet_susp_node, *clarinet_susp_type; #include "instr.h" void clarinet_s_fetch(register clarinet_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * clar_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "clarinet_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; clar_reg = susp->clar; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(clar_reg, 128, CLAR_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(clar_reg); } while (--n); /* inner loop */ susp->clar = clar_reg; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* clarinet_s_fetch */ void clarinet_toss_fetch(susp, snd_list) register clarinet_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void clarinet_mark(clarinet_susp_type susp) { sound_xlmark(susp->breath_env); } void clarinet_free(clarinet_susp_type susp) { deleteInstrument(susp->clar); sound_unref(susp->breath_env); ffree_generic(susp, sizeof(clarinet_susp_node), "clarinet_free"); } void clarinet_print_tree(clarinet_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); } sound_type snd_make_clarinet(double freq, sound_type breath_env, rate_type sr) { register clarinet_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, clarinet_susp_node, "snd_make_clarinet"); susp->clar = initInstrument(CLARINET, round(sr)); controlChange(susp->clar, 1, 0.0);; susp->temp_ret_value = noteOn(susp->clar, freq, 1.0); susp->susp.fetch = clarinet_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = clarinet_toss_fetch; } /* initialize susp state */ susp->susp.free = clarinet_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = clarinet_mark; susp->susp.print_tree = clarinet_print_tree; susp->susp.name = "clarinet"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_clarinet(double freq, sound_type breath_env, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); return snd_make_clarinet(freq, breath_env_copy, sr); } nyquist-3.05/tran/instrsaxall.c0000644000175000000620000003227410144436365015655 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrsaxall.h" void sax_all_free(); typedef struct sax_all_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; sound_type reed_stiffness; long reed_stiffness_cnt; sample_block_values_type reed_stiffness_ptr; sound_type noise; long noise_cnt; sample_block_values_type noise_ptr; sound_type blow_pos; long blow_pos_cnt; sample_block_values_type blow_pos_ptr; sound_type reed_table_offset; long reed_table_offset_cnt; sample_block_values_type reed_table_offset_ptr; struct instr *sax; double frequency; } sax_all_susp_node, *sax_all_susp_type; #include "instr.h" void sax_all_ssssss_fetch(register sax_all_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register double frequency_reg; register sample_type reed_table_offset_scale_reg = susp->reed_table_offset->scale; register sample_block_values_type reed_table_offset_ptr_reg; register sample_type blow_pos_scale_reg = susp->blow_pos->scale; register sample_block_values_type blow_pos_ptr_reg; register sample_type noise_scale_reg = susp->noise->scale; register sample_block_values_type noise_ptr_reg; register sample_type reed_stiffness_scale_reg = susp->reed_stiffness->scale; register sample_block_values_type reed_stiffness_ptr_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_all_ssssss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past the reed_stiffness input sample block: */ susp_check_samples(reed_stiffness, reed_stiffness_ptr, reed_stiffness_cnt); togo = min(togo, susp->reed_stiffness_cnt); /* don't run past the noise input sample block: */ susp_check_samples(noise, noise_ptr, noise_cnt); togo = min(togo, susp->noise_cnt); /* don't run past the blow_pos input sample block: */ susp_check_samples(blow_pos, blow_pos_ptr, blow_pos_cnt); togo = min(togo, susp->blow_pos_cnt); /* don't run past the reed_table_offset input sample block: */ susp_check_samples(reed_table_offset, reed_table_offset_ptr, reed_table_offset_cnt); togo = min(togo, susp->reed_table_offset_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; frequency_reg = susp->frequency; reed_table_offset_ptr_reg = susp->reed_table_offset_ptr; blow_pos_ptr_reg = susp->blow_pos_ptr; noise_ptr_reg = susp->noise_ptr; reed_stiffness_ptr_reg = susp->reed_stiffness_ptr; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); controlChange(sax_reg, 2, SAX_CONTROL_CHANGE_CONST * (reed_stiffness_scale_reg * *reed_stiffness_ptr_reg++)); controlChange(sax_reg, 4, SAX_CONTROL_CHANGE_CONST * (noise_scale_reg * *noise_ptr_reg++)); controlChange(sax_reg, 11, SAX_CONTROL_CHANGE_CONST * (blow_pos_scale_reg * *blow_pos_ptr_reg++)); controlChange(sax_reg, 26, SAX_CONTROL_CHANGE_CONST * (reed_table_offset_scale_reg * *reed_table_offset_ptr_reg++)); setFrequency(sax_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using reed_table_offset_ptr_reg is a bad idea on RS/6000: */ susp->reed_table_offset_ptr += togo; /* using blow_pos_ptr_reg is a bad idea on RS/6000: */ susp->blow_pos_ptr += togo; /* using noise_ptr_reg is a bad idea on RS/6000: */ susp->noise_ptr += togo; /* using reed_stiffness_ptr_reg is a bad idea on RS/6000: */ susp->reed_stiffness_ptr += togo; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); susp_took(reed_stiffness_cnt, togo); susp_took(noise_cnt, togo); susp_took(blow_pos_cnt, togo); susp_took(reed_table_offset_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_all_ssssss_fetch */ void sax_all_toss_fetch(susp, snd_list) register sax_all_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* fetch samples from reed_stiffness up to final_time for this block of zeros */ while ((round((final_time - susp->reed_stiffness->t0) * susp->reed_stiffness->sr)) >= susp->reed_stiffness->current) susp_get_samples(reed_stiffness, reed_stiffness_ptr, reed_stiffness_cnt); /* fetch samples from noise up to final_time for this block of zeros */ while ((round((final_time - susp->noise->t0) * susp->noise->sr)) >= susp->noise->current) susp_get_samples(noise, noise_ptr, noise_cnt); /* fetch samples from blow_pos up to final_time for this block of zeros */ while ((round((final_time - susp->blow_pos->t0) * susp->blow_pos->sr)) >= susp->blow_pos->current) susp_get_samples(blow_pos, blow_pos_ptr, blow_pos_cnt); /* fetch samples from reed_table_offset up to final_time for this block of zeros */ while ((round((final_time - susp->reed_table_offset->t0) * susp->reed_table_offset->sr)) >= susp->reed_table_offset->current) susp_get_samples(reed_table_offset, reed_table_offset_ptr, reed_table_offset_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); n = round((final_time - susp->reed_stiffness->t0) * susp->reed_stiffness->sr - (susp->reed_stiffness->current - susp->reed_stiffness_cnt)); susp->reed_stiffness_ptr += n; susp_took(reed_stiffness_cnt, n); n = round((final_time - susp->noise->t0) * susp->noise->sr - (susp->noise->current - susp->noise_cnt)); susp->noise_ptr += n; susp_took(noise_cnt, n); n = round((final_time - susp->blow_pos->t0) * susp->blow_pos->sr - (susp->blow_pos->current - susp->blow_pos_cnt)); susp->blow_pos_ptr += n; susp_took(blow_pos_cnt, n); n = round((final_time - susp->reed_table_offset->t0) * susp->reed_table_offset->sr - (susp->reed_table_offset->current - susp->reed_table_offset_cnt)); susp->reed_table_offset_ptr += n; susp_took(reed_table_offset_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void sax_all_mark(sax_all_susp_type susp) { sound_xlmark(susp->breath_env); sound_xlmark(susp->freq_env); sound_xlmark(susp->reed_stiffness); sound_xlmark(susp->noise); sound_xlmark(susp->blow_pos); sound_xlmark(susp->reed_table_offset); } void sax_all_free(sax_all_susp_type susp) { deleteInstrument(susp->sax); sound_unref(susp->breath_env); sound_unref(susp->freq_env); sound_unref(susp->reed_stiffness); sound_unref(susp->noise); sound_unref(susp->blow_pos); sound_unref(susp->reed_table_offset); ffree_generic(susp, sizeof(sax_all_susp_node), "sax_all_free"); } void sax_all_print_tree(sax_all_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); indent(n); stdputstr("reed_stiffness:"); sound_print_tree_1(susp->reed_stiffness, n); indent(n); stdputstr("noise:"); sound_print_tree_1(susp->noise, n); indent(n); stdputstr("blow_pos:"); sound_print_tree_1(susp->blow_pos, n); indent(n); stdputstr("reed_table_offset:"); sound_print_tree_1(susp->reed_table_offset, n); } sound_type snd_make_sax_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, sound_type blow_pos, sound_type reed_table_offset, rate_type sr) { register sax_all_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, sax_all_susp_node, "snd_make_sax_all"); susp->sax = initInstrument(SAXOFONY, round(sr)); noteOn(susp->sax, freq, 1.0); controlChange(susp->sax, 29, SAX_CONTROL_CHANGE_CONST * vibrato_freq); controlChange(susp->sax, 1, SAX_CONTROL_CHANGE_CONST * vibrato_gain);; susp->frequency = freq; susp->susp.fetch = sax_all_ssssss_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); if (t0 < reed_stiffness->t0) sound_prepend_zeros(reed_stiffness, t0); if (t0 < noise->t0) sound_prepend_zeros(noise, t0); if (t0 < blow_pos->t0) sound_prepend_zeros(blow_pos, t0); if (t0 < reed_table_offset->t0) sound_prepend_zeros(reed_table_offset, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, min(freq_env->t0, min(reed_stiffness->t0, min(noise->t0, min(blow_pos->t0, min(reed_table_offset->t0, t0)))))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = sax_all_toss_fetch; } /* initialize susp state */ susp->susp.free = sax_all_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = sax_all_mark; susp->susp.print_tree = sax_all_print_tree; susp->susp.name = "sax_all"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; susp->reed_stiffness = reed_stiffness; susp->reed_stiffness_cnt = 0; susp->noise = noise; susp->noise_cnt = 0; susp->blow_pos = blow_pos; susp->blow_pos_cnt = 0; susp->reed_table_offset = reed_table_offset; susp->reed_table_offset_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sax_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, sound_type blow_pos, sound_type reed_table_offset, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); sound_type freq_env_copy = sound_copy(freq_env); sound_type reed_stiffness_copy = sound_copy(reed_stiffness); sound_type noise_copy = sound_copy(noise); sound_type blow_pos_copy = sound_copy(blow_pos); sound_type reed_table_offset_copy = sound_copy(reed_table_offset); return snd_make_sax_all(freq, breath_env_copy, freq_env_copy, vibrato_freq, vibrato_gain, reed_stiffness_copy, noise_copy, blow_pos_copy, reed_table_offset_copy, sr); } nyquist-3.05/tran/tapf.c0000644000175000000620000004732211466723256014251 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "tapf.h" void tapf_free(); typedef struct tapf_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type vardelay; long vardelay_cnt; sample_block_values_type vardelay_ptr; /* support for interpolation of vardelay */ sample_type vardelay_x1_sample; double vardelay_pHaSe; double vardelay_pHaSe_iNcR; /* support for ramp between samples of vardelay */ double output_per_vardelay; long vardelay_n; double offset; double vdscale; long maxdelay; long bufflen; long index; sample_type *buffer; } tapf_susp_node, *tapf_susp_type; void tapf_sn_fetch(register tapf_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double offset_reg; register double vdscale_reg; register long maxdelay_reg; register long bufflen_reg; register long index_reg; register sample_type * buffer_reg; register sample_block_values_type vardelay_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tapf_sn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the vardelay input sample block: */ susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); togo = min(togo, susp->vardelay_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; vdscale_reg = susp->vdscale; maxdelay_reg = susp->maxdelay; bufflen_reg = susp->bufflen; index_reg = susp->index; buffer_reg = susp->buffer; vardelay_ptr_reg = susp->vardelay_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long phase; phase = (long) (*vardelay_ptr_reg++ * vdscale_reg + offset_reg); /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay_reg) phase = maxdelay_reg; phase = index_reg - phase; /* now phase is a location in the buffer_reg (before modulo) */ /* Time out to update the buffer_reg: * this is a tricky buffer_reg: buffer_reg[0] == buffer_reg[bufflen_reg] * the logical length is bufflen_reg, but the actual length * is bufflen_reg + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer_reg[index_reg++] = (s1_scale_reg * *s1_ptr_reg++); if (index_reg >= bufflen_reg) { index_reg = 0; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen_reg; *out_ptr_reg++ = (sample_type) (buffer_reg[phase]);; } while (--n); /* inner loop */ susp->bufflen = bufflen_reg; susp->index = index_reg; /* using vardelay_ptr_reg is a bad idea on RS/6000: */ susp->vardelay_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(vardelay_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tapf_sn_fetch */ void tapf_si_fetch(register tapf_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type vardelay_x2_sample; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double offset_reg; register double vdscale_reg; register long maxdelay_reg; register long bufflen_reg; register long index_reg; register sample_type * buffer_reg; register double vardelay_pHaSe_iNcR_rEg = susp->vardelay_pHaSe_iNcR; register double vardelay_pHaSe_ReG; register sample_type vardelay_x1_sample_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tapf_si_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); susp->vardelay_x1_sample = (susp->vardelay_cnt--, *(susp->vardelay_ptr)); } susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); vardelay_x2_sample = *(susp->vardelay_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; vdscale_reg = susp->vdscale; maxdelay_reg = susp->maxdelay; bufflen_reg = susp->bufflen; index_reg = susp->index; buffer_reg = susp->buffer; vardelay_pHaSe_ReG = susp->vardelay_pHaSe; vardelay_x1_sample_reg = susp->vardelay_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long phase; if (vardelay_pHaSe_ReG >= 1.0) { vardelay_x1_sample_reg = vardelay_x2_sample; /* pick up next sample as vardelay_x2_sample: */ susp->vardelay_ptr++; susp_took(vardelay_cnt, 1); vardelay_pHaSe_ReG -= 1.0; susp_check_term_samples_break(vardelay, vardelay_ptr, vardelay_cnt, vardelay_x2_sample); } phase = (long) ( (vardelay_x1_sample_reg * (1 - vardelay_pHaSe_ReG) + vardelay_x2_sample * vardelay_pHaSe_ReG) * vdscale_reg + offset_reg); /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay_reg) phase = maxdelay_reg; phase = index_reg - phase; /* now phase is a location in the buffer_reg (before modulo) */ /* Time out to update the buffer_reg: * this is a tricky buffer_reg: buffer_reg[0] == buffer_reg[bufflen_reg] * the logical length is bufflen_reg, but the actual length * is bufflen_reg + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer_reg[index_reg++] = (s1_scale_reg * *s1_ptr_reg++); if (index_reg >= bufflen_reg) { index_reg = 0; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen_reg; *out_ptr_reg++ = (sample_type) (buffer_reg[phase]);; vardelay_pHaSe_ReG += vardelay_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->bufflen = bufflen_reg; susp->index = index_reg; susp->vardelay_pHaSe = vardelay_pHaSe_ReG; susp->vardelay_x1_sample = vardelay_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tapf_si_fetch */ void tapf_sr_fetch(register tapf_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type vardelay_DeLtA; sample_type vardelay_val; sample_type vardelay_x2_sample; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double offset_reg; register double vdscale_reg; register long maxdelay_reg; register long bufflen_reg; register long index_reg; register sample_type * buffer_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tapf_sr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->vardelay_pHaSe = 1.0; } susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); vardelay_x2_sample = *(susp->vardelay_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next vardelay_x2_sample when phase goes past 1.0; */ /* we use vardelay_n (computed below) to avoid roundoff errors: */ if (susp->vardelay_n <= 0) { susp->vardelay_x1_sample = vardelay_x2_sample; susp->vardelay_ptr++; susp_took(vardelay_cnt, 1); susp->vardelay_pHaSe -= 1.0; susp_check_term_samples(vardelay, vardelay_ptr, vardelay_cnt); vardelay_x2_sample = *(susp->vardelay_ptr); /* vardelay_n gets number of samples before phase exceeds 1.0: */ susp->vardelay_n = (long) ((1.0 - susp->vardelay_pHaSe) * susp->output_per_vardelay); } togo = min(togo, susp->vardelay_n); vardelay_DeLtA = (sample_type) ((vardelay_x2_sample - susp->vardelay_x1_sample) * susp->vardelay_pHaSe_iNcR); vardelay_val = (sample_type) (susp->vardelay_x1_sample * (1.0 - susp->vardelay_pHaSe) + vardelay_x2_sample * susp->vardelay_pHaSe); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; offset_reg = susp->offset; vdscale_reg = susp->vdscale; maxdelay_reg = susp->maxdelay; bufflen_reg = susp->bufflen; index_reg = susp->index; buffer_reg = susp->buffer; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long phase; phase = (long) (vardelay_val * vdscale_reg + offset_reg); /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay_reg) phase = maxdelay_reg; phase = index_reg - phase; /* now phase is a location in the buffer_reg (before modulo) */ /* Time out to update the buffer_reg: * this is a tricky buffer_reg: buffer_reg[0] == buffer_reg[bufflen_reg] * the logical length is bufflen_reg, but the actual length * is bufflen_reg + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer_reg[index_reg++] = (s1_scale_reg * *s1_ptr_reg++); if (index_reg >= bufflen_reg) { index_reg = 0; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen_reg; *out_ptr_reg++ = (sample_type) (buffer_reg[phase]);; vardelay_val += vardelay_DeLtA; } while (--n); /* inner loop */ susp->bufflen = bufflen_reg; susp->index = index_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->vardelay_pHaSe += togo * susp->vardelay_pHaSe_iNcR; susp->vardelay_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tapf_sr_fetch */ void tapf_toss_fetch(susp, snd_list) register tapf_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from vardelay up to final_time for this block of zeros */ while ((round((final_time - susp->vardelay->t0) * susp->vardelay->sr)) >= susp->vardelay->current) susp_get_samples(vardelay, vardelay_ptr, vardelay_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->vardelay->t0) * susp->vardelay->sr - (susp->vardelay->current - susp->vardelay_cnt)); susp->vardelay_ptr += n; susp_took(vardelay_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void tapf_mark(tapf_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->vardelay); } void tapf_free(tapf_susp_type susp) { free(susp->buffer); sound_unref(susp->s1); sound_unref(susp->vardelay); ffree_generic(susp, sizeof(tapf_susp_node), "tapf_free"); } void tapf_print_tree(tapf_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("vardelay:"); sound_print_tree_1(susp->vardelay, n); } sound_type snd_make_tapf(sound_type s1, double offset, sound_type vardelay, double maxdelay) { register tapf_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, vardelay->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, tapf_susp_node, "snd_make_tapf"); susp->offset = offset * s1->sr; susp->vdscale = vardelay->scale * s1->sr; susp->maxdelay = (long)(maxdelay * s1->sr); susp->bufflen = max(2, (long) (susp->maxdelay + 0.5)); susp->index = susp->bufflen; susp->buffer = (sample_type *) calloc(susp->bufflen + 1, sizeof(sample_type)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(vardelay, sr); switch (interp_desc) { case INTERP_ns: /* handled below */ case INTERP_nn: /* handled below */ case INTERP_ss: /* handled below */ case INTERP_sn: susp->susp.fetch = tapf_sn_fetch; break; case INTERP_ni: /* handled below */ case INTERP_si: susp->susp.fetch = tapf_si_fetch; break; case INTERP_nr: /* handled below */ case INTERP_sr: susp->susp.fetch = tapf_sr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < vardelay->t0) sound_prepend_zeros(vardelay, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(vardelay->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = tapf_toss_fetch; } /* initialize susp state */ susp->susp.free = tapf_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = tapf_mark; susp->susp.print_tree = tapf_print_tree; susp->susp.name = "tapf"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->vardelay = vardelay; susp->vardelay_cnt = 0; susp->vardelay_pHaSe = 0.0; susp->vardelay_pHaSe_iNcR = vardelay->sr / sr; susp->vardelay_n = 0; susp->output_per_vardelay = sr / vardelay->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_tapf(sound_type s1, double offset, sound_type vardelay, double maxdelay) { sound_type s1_copy = sound_copy(s1); sound_type vardelay_copy = sound_copy(vardelay); return snd_make_tapf(s1_copy, offset, vardelay_copy, maxdelay); } nyquist-3.05/tran/instrbow.alg0000644000175000000620000000133511466723256015501 0ustar stevestaff(INSTRBOW-ALG (NAME "bowed") (ARGUMENTS ("double" "freq") ("sound_type" "bowpress_env") ("rate_type" "sr")) (STATE ("struct instr *" "mybow" "initInstrument(BOWED, round(sr)); controlChange(susp->mybow, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->mybow, freq, 1.0)")) (START (min bowpress_env)) (NOT-IN-INNER-LOOP "freq" "temp_ret_value") (SAMPLE-RATE "sr") (ALWAYS-SCALE bowpress_env) (TERMINATE (min bowpress_env)) (INNER-LOOP " controlChange(mybow, 128, BOW_CONTROL_CHANGE_CONST * bowpress_env); output = (sample_type) tick(mybow)") (SUPPORT-HEADER " #define BOW_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->mybow); ") ) nyquist-3.05/tran/exprel.alg0000644000175000000620000000315310144436365015123 0ustar stevestaff;; this is the beginnings of a new function that just passes input to output until ;; a given "release time" at which point the output decays exponentially to zero. ;; this is hard to do in Nyquist without a new primitive because the amplitude of ;; the exponential decay depends on the value of the input at some given time. ;; (Yes, you can evaluate that point, but then you have to compute all the samples, ;; and they will be held in memory, which might not be a good thing.) (EXPREL-ALG (NAME "exprel") (ARGUMENTS ("sound_type" "signal") ("time_type" "release_time") ("double" "fall_time")) (SUPPORT-FUNCTIONS "#define ST_HOLD 0 #define ST_FALL 1 #define ST_FALL_UNTIL 2 #define ST_OFF 3 #define ST_OFF_UNTIL 4 #define ST_RISE 5 /* Overview: This operation passes its input to its output until the release time. Then, it takes the last sample output as a starting point for an exponential decay, with a duration of falltime. */ ") (STATE ("long" "release_time" "signal->sr * release_time + 0.5") ("double" "fall_time" "signal->sr * falltime + 0.5") ("sample_type" "value" "0") ("bool" "falling" "0")) (TERMINATE (MIN signal)) (LOGICAL-STOP "release_time") (LINEAR signal) (INNER-LOOP "{ sample_type result; if (falling) { value = value * decay; result = value; } else { result = signal; if (release_time <= susp->susp.current + cnt + togo - n) { value = result; falling = 1; } } output = (sample_type) value; }") ) need to do logical stop time and termination time nyquist-3.05/tran/alpasscv.h0000644000175000000620000000033110144436365015117 0ustar stevestaffsound_type snd_make_alpasscv(sound_type input, time_type delay, sound_type feedback); sound_type snd_alpasscv(sound_type input, time_type delay, sound_type feedback); /* LISP: (snd-alpasscv SOUND ANYNUM SOUND) */ nyquist-3.05/tran/atonev.h0000644000175000000620000000023010144436365014575 0ustar stevestaffsound_type snd_make_atonev(sound_type s1, sound_type hz); sound_type snd_atonev(sound_type s1, sound_type hz); /* LISP: (snd-atonev SOUND SOUND) */ nyquist-3.05/tran/recip.h0000644000175000000620000000016110144436365014406 0ustar stevestaffsound_type snd_make_recip(sound_type s1); sound_type snd_recip(sound_type s1); /* LISP: (snd-recip SOUND) */ nyquist-3.05/tran/exp.alg0000644000175000000620000000030410144436365014413 0ustar stevestaff(EXP-ALG (NAME "exp") (ARGUMENTS ("sound_type" "in")) (ALWAYS-SCALE in) (START (MIN in)) (INNER-LOOP "output = (sample_type) exp(in)") (TERMINATE (MIN in)) (LOGICAL-STOP (MIN in)) ) nyquist-3.05/tran/chase.h0000644000175000000620000000031110144436365014364 0ustar stevestaffsound_type snd_make_chase(sound_type input, double risetime, double falltime); sound_type snd_chase(sound_type input, double risetime, double falltime); /* LISP: (snd-chase SOUND ANYNUM ANYNUM) */ nyquist-3.05/tran/fmfbv.alg0000644000175000000620000000223111466723256014726 0ustar stevestaff(FMFBV-ALG (NAME "fmfbv") (ARGUMENTS ("time_type" "t0")("double" "hz") ("rate_type" "sr")("sound_type" "index")) (START (MIN index)) (TERMINATE (MIN index)) (LOGICAL-STOP (MIN index)) (STEP-FUNCTION index) (INLINE-INTERPOLATION T) (STATE ("double" "yy" "0.0") ("double" "sin_y" "0.0") ("double" "phase" "0.0") ("double" "ph_incr" "hz * SINE_TABLE_LEN / sr; index->scale *= SINE_TABLE_LEN / PI2 ")) (INNER-LOOP "phase += ph_incr; if (phase > SINE_TABLE_LEN) phase -= SINE_TABLE_LEN; /* PHASE is incremented and INDEX scaled to table INDEX, and sin_y is a signal (-1 to +1) */ yy = phase + index * sin_y; /* so yy is a table index */ while (yy > SINE_TABLE_LEN) yy -= SINE_TABLE_LEN; while (yy < 0) yy += SINE_TABLE_LEN; sin_y = sine_table[(int) yy]; /* truncation gets valid index */ /* sin_y is now a signal not ready for table lookup */ output = sin_y;") (CONSTANT "ph_incr") (SAMPLE-RATE "sr") (SUPPORT-HEADER "#include \"sine.h\" /* sine_table and SINE_TABLE_LEN */ ") ) nyquist-3.05/tran/abs.h0000644000175000000620000000016110144436365014051 0ustar stevestaffsound_type snd_make_abs(sound_type input); sound_type snd_abs(sound_type input); /* LISP: (snd-abs SOUND) */ nyquist-3.05/tran/aresonvc.c0000644000175000000620000004335210144436365015130 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "aresonvc.h" void aresonvc_free(); typedef struct aresonvc_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type hz; long hz_cnt; sample_block_values_type hz_ptr; /* support for interpolation of hz */ sample_type hz_x1_sample; double hz_pHaSe; double hz_pHaSe_iNcR; /* support for ramp between samples of hz */ double output_per_hz; long hz_n; double c3co; double c3p1; double c3t4; double omc3; double c2; double c1; int normalization; double y1; double y2; } aresonvc_susp_node, *aresonvc_susp_type; void aresonvc_ns_fetch(register aresonvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type hz_scale_reg = susp->hz->scale; register sample_block_values_type hz_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvc_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz input sample block: */ susp_check_term_samples(hz, hz_ptr, hz_cnt); togo = min(togo, susp->hz_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz_ptr_reg = susp->hz_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; c2_reg = c3t4_reg * cos((hz_scale_reg * *hz_ptr_reg++)) / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using hz_ptr_reg is a bad idea on RS/6000: */ susp->hz_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvc_ns_fetch */ void aresonvc_ni_fetch(register aresonvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double hz_pHaSe_iNcR_rEg = susp->hz_pHaSe_iNcR; register double hz_pHaSe_ReG; register sample_type hz_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvc_ni_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->c2 = susp->c3t4 * cos(susp->hz_x1_sample) / susp->c3p1; susp->c1 = (susp->normalization == 0 ? 0.0 : (susp->normalization == 1 ? 1.0 - susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : 1.0 - sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz_pHaSe_ReG = susp->hz_pHaSe; hz_x1_sample_reg = susp->hz_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (hz_pHaSe_ReG >= 1.0) { /* fixup-depends hz */ /* pick up next sample as hz_x1_sample: */ susp->hz_ptr++; susp_took(hz_cnt, 1); hz_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz, hz_ptr, hz_cnt, hz_x1_sample_reg); hz_x1_sample_reg = susp_current_sample(hz, hz_ptr); c2_reg = susp->c2 = c3t4_reg * cos(hz_x1_sample_reg) / c3p1_reg; c1_reg = susp->c1 = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; hz_pHaSe_ReG += hz_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->hz_pHaSe = hz_pHaSe_ReG; susp->hz_x1_sample = hz_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvc_ni_fetch */ void aresonvc_nr_fetch(register aresonvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvc_nr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz_pHaSe = 1.0; } susp_check_term_samples(hz, hz_ptr, hz_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz_x1_sample when phase goes past 1.0; */ /* use hz_n (computed below) to avoid roundoff errors: */ if (susp->hz_n <= 0) { susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->hz_pHaSe -= 1.0; /* hz_n gets number of samples before phase exceeds 1.0: */ susp->hz_n = (long) ((1.0 - susp->hz_pHaSe) * susp->output_per_hz); susp->c2 = susp->c3t4 * cos(susp->hz_x1_sample) / susp->c3p1; susp->c1 = (susp->normalization == 0 ? 0.0 : (susp->normalization == 1 ? 1.0 - susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : 1.0 - sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)); } togo = min(togo, susp->hz_n); hz_val = susp->hz_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current;current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz_pHaSe += togo * susp->hz_pHaSe_iNcR; susp->hz_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvc_nr_fetch */ void aresonvc_toss_fetch(susp, snd_list) register aresonvc_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from hz up to final_time for this block of zeros */ while ((round((final_time - susp->hz->t0) * susp->hz->sr)) >= susp->hz->current) susp_get_samples(hz, hz_ptr, hz_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->hz->t0) * susp->hz->sr - (susp->hz->current - susp->hz_cnt)); susp->hz_ptr += n; susp_took(hz_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void aresonvc_mark(aresonvc_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->hz); } void aresonvc_free(aresonvc_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->hz); ffree_generic(susp, sizeof(aresonvc_susp_node), "aresonvc_free"); } void aresonvc_print_tree(aresonvc_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("hz:"); sound_print_tree_1(susp->hz, n); } sound_type snd_make_aresonvc(sound_type s1, sound_type hz, double bw, int normalization) { register aresonvc_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, hz->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (S1) */ scale_factor *= s1->scale; s1->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s1->sr < sr) { s1->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, aresonvc_susp_node, "snd_make_aresonvc"); susp->c3co = exp(bw * -PI2 / s1->sr); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->c2 = 0.0; susp->c1 = 0.0; susp->normalization = normalization; susp->y1 = 0.0; susp->y2 = 0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(hz, sr); switch (interp_desc) { case INTERP_nn: /* handled below */ case INTERP_ns: susp->susp.fetch = aresonvc_ns_fetch; break; case INTERP_ni: susp->susp.fetch = aresonvc_ni_fetch; break; case INTERP_nr: susp->susp.fetch = aresonvc_nr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < hz->t0) sound_prepend_zeros(hz, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(hz->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = aresonvc_toss_fetch; } /* initialize susp state */ susp->susp.free = aresonvc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = aresonvc_mark; susp->susp.print_tree = aresonvc_print_tree; susp->susp.name = "aresonvc"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->hz = hz; susp->hz_cnt = 0; susp->hz_pHaSe = 0.0; susp->hz_pHaSe_iNcR = hz->sr / sr; susp->hz_n = 0; susp->output_per_hz = sr / hz->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_aresonvc(sound_type s1, sound_type hz, double bw, int normalization) { sound_type s1_copy = sound_copy(s1); sound_type hz_copy = sound_copy(hz); return snd_make_aresonvc(s1_copy, hz_copy, bw, normalization); } nyquist-3.05/tran/prod.c0000644000175000000620000001544110144436365014252 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "prod.h" void prod_free(); typedef struct prod_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type s2; long s2_cnt; sample_block_values_type s2_ptr; } prod_susp_node, *prod_susp_type; void prod_nn_fetch(register prod_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_block_values_type s2_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "prod_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the s2 input sample block: */ susp_check_term_log_samples(s2, s2_ptr, s2_cnt); togo = min(togo, susp->s2_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; s2_ptr_reg = susp->s2_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *s1_ptr_reg++ * *s2_ptr_reg++; } while (--n); /* inner loop */ /* using s2_ptr_reg is a bad idea on RS/6000: */ susp->s2_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(s2_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* prod_nn_fetch */ void prod_toss_fetch(susp, snd_list) register prod_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from s2 up to final_time for this block of zeros */ while ((round((final_time - susp->s2->t0) * susp->s2->sr)) >= susp->s2->current) susp_get_samples(s2, s2_ptr, s2_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->s2->t0) * susp->s2->sr - (susp->s2->current - susp->s2_cnt)); susp->s2_ptr += n; susp_took(s2_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void prod_mark(prod_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->s2); } void prod_free(prod_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->s2); ffree_generic(susp, sizeof(prod_susp_node), "prod_free"); } void prod_print_tree(prod_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("s2:"); sound_print_tree_1(susp->s2, n); } sound_type snd_make_prod(sound_type s1, sound_type s2) { register prod_susp_type susp; rate_type sr = max(s1->sr, s2->sr); time_type t0 = max(s1->t0, s2->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; long lsc; /* sort commutative signals: (S1 S2) */ snd_sort_2(&s1, &s2, sr); /* combine scale factors of linear inputs (S1 S2) */ scale_factor *= s1->scale; s1->scale = 1.0F; scale_factor *= s2->scale; s2->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s1->sr < sr) { s1->scale = scale_factor; scale_factor = 1.0F; } else if (s2->sr < sr) { s2->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, prod_susp_node, "snd_make_prod"); susp->susp.fetch = prod_nn_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < s2->t0) sound_prepend_zeros(s2, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(s2->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = prod_toss_fetch; } /* initialize susp state */ susp->susp.free = prod_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = prod_mark; susp->susp.print_tree = prod_print_tree; susp->susp.name = "prod"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); lsc = logical_stop_cnt_cvt(s2); if (susp->susp.log_stop_cnt > lsc) susp->susp.log_stop_cnt = lsc; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->s2 = s2; susp->s2_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_prod(sound_type s1, sound_type s2) { sound_type s1_copy = sound_copy(s1); sound_type s2_copy = sound_copy(s2); return snd_make_prod(s1_copy, s2_copy); } nyquist-3.05/tran/ifft.alg0000644000175000000620000001563111466723256014566 0ustar stevestaff(IFFT-ALG (NAME "ifft") (ARGUMENTS ("time_type" "t0") ("rate_type" "sr") ("LVAL" "src") ("long" "stepsize") ("LVAL" "window")) (SUPPORT-FUNCTIONS " /* index: index into outbuf whree we get output samples * length: size of the frame, window, and outbuf; half size of samples * array: spectral frame goes here (why not a local var?) * window_len: size of window, should equal length * outbuf: real part of samples are multiplied by window and added to * outbuf (after shifting) * src: send :NEXT to this object to get next frame * stepsize: shift by this many and add each frame * samples: result of ifft goes here, real and imag * window: multiply samples by window if any * * IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either an * array of samples or NIL. The output of ifft is simply the * concatenation of the samples taken from the array. Later, * an ifft will be plugged in and this will return overlapped * adds of the ifft's. * * OVERLAP: stepsize must be less than or equal to the length * of real part of the transformed spectrum. A transform step * works like this: * (1) shift the output buffer by stepsize samples, filling * the end of the buffer with zeros * (2) get and transform an array of spectral coefficients * (3) multiply the result by a window * (4) add the result to the output buffer * (5) output the first stepsize samples of the buffer * * DATA FORMAT: the DC component goes in array elem 0 * Cosine part is in elements 2*i-1 * Sine part is in elements 2*i * Nyquist frequency is in element length-1 */ #include \"samples.h\" #include \"fftext.h\" #define MUST_BE_FLONUM(e) \\ if (!(e) || ntype(e) != FLONUM) { xlerror(\"flonum expected\", (e)); } table_type get_window_samples(LVAL window, sample_type **samples, long *len) { table_type result = NULL; if (soundp(window)) { sound_type window_sound = getsound(window); xlprot1(window); /* maybe not necessary */ result = sound_to_table(window_sound); xlpop(); *samples = result->samples; *len = (long) (result->length + 0.5); } return result; } ") (SAMPLE-RATE "sr") (STATE ("long" "index" "stepsize") ; samples index ("long" "length" "0") ; samples length ("LVAL" "array" "NULL") ("long" "window_len" "0") ("sample_type *" "outbuf" "NULL") ("LVAL" "src" "src") ("long" "stepsize" "stepsize") ("sample_type *" "window" "NULL") ; window samples ("sample_type *" "samples" "NULL") ("table_type" "table" "get_window_samples(window, &susp->window, &susp->window_len)")) (OUTER-LOOP " if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->index >= susp->stepsize) { long i; long m, n; LVAL elem; susp->index = 0; susp->array = xleval(cons(s_send, cons(susp->src, consa(s_next)))); if (susp->array == NULL) { susp->src = NULL; goto out; } else if (!vectorp(susp->array)) { xlerror(\"array expected\", susp->array); } else if (susp->samples == NULL) { /* assume arrays are all the same size as first one; now that we know the size, we just have to do this first allocation. */ susp->length = getsize(susp->array); if (susp->length < 1) xlerror(\"array has no elements\", susp->array); if (susp->window && (susp->window_len != susp->length)) xlerror(\"window size and spectrum size differ\", susp->array); /* tricky non-power of 2 detector: only if this is a * power of 2 will the highest 1 bit be cleared when * we subtract 1 ... */ if (susp->length & (susp->length - 1)) xlfail(\"spectrum size must be a power of 2\"); susp->samples = (sample_type *) calloc(susp->length, sizeof(sample_type)); susp->outbuf = (sample_type *) calloc(susp->length, sizeof(sample_type)); } else if (getsize(susp->array) != susp->length) { xlerror(\"arrays must all be the same length\", susp->array); } /* at this point, we have a new array to put samples */ /* the incoming array format is [DC, R1, I1, R2, I2, ... RN] * where RN is the real coef at the Nyquist frequency * but susp->samples should be organized as [DC, RN, R1, I1, ...] */ n = susp->length; /* get the DC (real) coef */ elem = getelement(susp->array, 0); MUST_BE_FLONUM(elem) susp->samples[0] = (sample_type) getflonum(elem); /* get the Nyquist (real) coef */ elem = getelement(susp->array, n - 1); MUST_BE_FLONUM(elem); susp->samples[1] = (sample_type) getflonum(elem); /* get the remaining coef */ for (i = 1; i < n - 1; i++) { elem = getelement(susp->array, i); MUST_BE_FLONUM(elem) susp->samples[i + 1] = (sample_type) getflonum(elem); } susp->array = NULL; /* free the array */ /* here is where the IFFT and windowing should take place */ //fftnf(1, &n, susp->samples, susp->samples + n, -1, 1.0); m = round(log2(n)); if (!fftInit(m)) riffts(susp->samples, m, 1); else xlfail(\"FFT initialization error\"); if (susp->window) { n = susp->length; for (i = 0; i < n; i++) { susp->samples[i] *= susp->window[i]; } } /* shift the outbuf */ n = susp->length - susp->stepsize; for (i = 0; i < n; i++) { susp->outbuf[i] = susp->outbuf[i + susp->stepsize]; } /* clear end of outbuf */ for (i = n; i < susp->length; i++) { susp->outbuf[i] = 0; } /* add in the ifft result */ n = susp->length; for (i = 0; i < n; i++) { susp->outbuf[i] += susp->samples[i]; } } togo = min(togo, susp->stepsize - susp->index); ") (INNER-LOOP "output = outbuf[index++];") (CONSTANT "length" "samples" "array" "src" "window") (TERMINATE COMPUTED) (FINALIZATION " if (susp->samples) free(susp->samples); if (susp->table) table_unref(susp->table); if (susp->outbuf) free(susp->outbuf); ") ) nyquist-3.05/tran/instrclarall.h0000644000175000000620000000077610144436365016012 0ustar stevestaffsound_type snd_make_clarinet_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, rate_type sr); sound_type snd_clarinet_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type reed_stiffness, sound_type noise, rate_type sr); /* LISP: (snd-clarinet_all ANYNUM SOUND SOUND ANYNUM ANYNUM SOUND SOUND ANYNUM) */ #define CLAR_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/resoncv.c0000644000175000000620000004334010144436365014764 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "resoncv.h" void resoncv_free(); typedef struct resoncv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type bw; long bw_cnt; sample_block_values_type bw_ptr; /* support for interpolation of bw */ sample_type bw_x1_sample; double bw_pHaSe; double bw_pHaSe_iNcR; /* support for ramp between samples of bw */ double output_per_bw; long bw_n; double scale1; double c3co; double coshz; double c2; double c1; int normalization; double y1; double y2; } resoncv_susp_node, *resoncv_susp_type; void resoncv_ns_fetch(register resoncv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resoncv_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double c3p1; double c3t4; double omc3; c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1 = c3co_reg + 1.0; c3t4 = c3co_reg * 4.0; omc3 = 1.0 - c3co_reg; c2_reg = c3t4 * coshz_reg / c3p1; c1_reg = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3 * sqrt(1.0 - c2_reg * c2_reg / c3t4) : sqrt(c3p1 * c3p1 - c2_reg * c2_reg) * omc3 / c3p1)) * scale1_reg; { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resoncv_ns_fetch */ void resoncv_ni_fetch(register resoncv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resoncv_ni_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { double c3p1; double c3t4; double omc3; susp->started = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); c3p1 = susp->c3co + 1.0; c3t4 = susp->c3co * 4.0; omc3 = 1.0 - susp->c3co; susp->c2 = c3t4 * susp->coshz / c3p1; susp->c1 = (susp->normalization == 0 ? 1.0 : (susp->normalization == 1 ? omc3 * sqrt(1.0 - susp->c2 * susp->c2 / c3t4) : sqrt(c3p1 * c3p1 - susp->c2 * susp->c2) * omc3 / c3p1)) * susp->scale1; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ double c3p1; double c3t4; double omc3; /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1 = c3co_reg + 1.0; c3t4 = c3co_reg * 4.0; omc3 = 1.0 - c3co_reg; c2_reg = susp->c2 = c3t4 * coshz_reg / c3p1; c1_reg = susp->c1 = (normalization_reg == 0 ? 1.0 : (normalization_reg == 1 ? omc3 * sqrt(1.0 - c2_reg * c2_reg / c3t4) : sqrt(c3p1 * c3p1 - c2_reg * c2_reg) * omc3 / c3p1)) * scale1_reg; } { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resoncv_ni_fetch */ void resoncv_nr_fetch(register resoncv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c3co_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "resoncv_nr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { double c3p1; double c3t4; double omc3; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); c3p1 = susp->c3co + 1.0; c3t4 = susp->c3co * 4.0; omc3 = 1.0 - susp->c3co; susp->c2 = c3t4 * susp->coshz / c3p1; susp->c1 = (susp->normalization == 0 ? 1.0 : (susp->normalization == 1 ? omc3 * sqrt(1.0 - susp->c2 * susp->c2 / c3t4) : sqrt(c3p1 * c3p1 - susp->c2 * susp->c2) * omc3 / c3p1)) * susp->scale1; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c3co_reg = susp->c3co; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { double y0 = c1_reg * *s1_ptr_reg++ + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* resoncv_nr_fetch */ void resoncv_toss_fetch(susp, snd_list) register resoncv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from bw up to final_time for this block of zeros */ while ((round((final_time - susp->bw->t0) * susp->bw->sr)) >= susp->bw->current) susp_get_samples(bw, bw_ptr, bw_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->bw->t0) * susp->bw->sr - (susp->bw->current - susp->bw_cnt)); susp->bw_ptr += n; susp_took(bw_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void resoncv_mark(resoncv_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->bw); } void resoncv_free(resoncv_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->bw); ffree_generic(susp, sizeof(resoncv_susp_node), "resoncv_free"); } void resoncv_print_tree(resoncv_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("bw:"); sound_print_tree_1(susp->bw, n); } sound_type snd_make_resoncv(sound_type s1, double hz, sound_type bw, int normalization) { register resoncv_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, bw->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, resoncv_susp_node, "snd_make_resoncv"); susp->scale1 = s1->scale; susp->c3co = 0.0; susp->coshz = cos(hz * PI2 / s1->sr); susp->c2 = 0.0; susp->c1 = 0.0; susp->normalization = normalization; susp->y1 = 0.0; susp->y2 = 0.0; bw->scale = (sample_type) (bw->scale * (-PI2 / s1->sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(bw, sr); switch (interp_desc) { case INTERP_sn: /* handled below */ case INTERP_ss: /* handled below */ case INTERP_nn: /* handled below */ case INTERP_ns: susp->susp.fetch = resoncv_ns_fetch; break; case INTERP_si: /* handled below */ case INTERP_ni: susp->susp.fetch = resoncv_ni_fetch; break; case INTERP_sr: /* handled below */ case INTERP_nr: susp->susp.fetch = resoncv_nr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < bw->t0) sound_prepend_zeros(bw, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(bw->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = resoncv_toss_fetch; } /* initialize susp state */ susp->susp.free = resoncv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = resoncv_mark; susp->susp.print_tree = resoncv_print_tree; susp->susp.name = "resoncv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->bw = bw; susp->bw_cnt = 0; susp->bw_pHaSe = 0.0; susp->bw_pHaSe_iNcR = bw->sr / sr; susp->bw_n = 0; susp->output_per_bw = sr / bw->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_resoncv(sound_type s1, double hz, sound_type bw, int normalization) { sound_type s1_copy = sound_copy(s1); sound_type bw_copy = sound_copy(bw); return snd_make_resoncv(s1_copy, hz, bw_copy, normalization); } nyquist-3.05/tran/instrsax.c0000644000175000000620000001612610144436365015162 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrsax.h" void sax_free(); typedef struct sax_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; struct instr *sax; int temp_ret_value; } sax_susp_node, *sax_susp_type; #include "instr.h" void sax_n_fetch(register sax_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * *breath_env_ptr_reg++); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_n_fetch */ void sax_s_fetch(register sax_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_s_fetch */ void sax_toss_fetch(susp, snd_list) register sax_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void sax_mark(sax_susp_type susp) { sound_xlmark(susp->breath_env); } void sax_free(sax_susp_type susp) { deleteInstrument(susp->sax); sound_unref(susp->breath_env); ffree_generic(susp, sizeof(sax_susp_node), "sax_free"); } void sax_print_tree(sax_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); } sound_type snd_make_sax(double freq, sound_type breath_env, rate_type sr) { register sax_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, sax_susp_node, "snd_make_sax"); susp->sax = initInstrument(SAXOFONY, round(sr)); controlChange(susp->sax, 1, 0.0);; susp->temp_ret_value = noteOn(susp->sax, freq, 1.0); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(breath_env, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = sax_n_fetch; break; case INTERP_s: susp->susp.fetch = sax_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = sax_toss_fetch; } /* initialize susp state */ susp->susp.free = sax_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = sax_mark; susp->susp.print_tree = sax_print_tree; susp->susp.name = "sax"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sax(double freq, sound_type breath_env, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); return snd_make_sax(freq, breath_env_copy, sr); } nyquist-3.05/tran/reson.c0000644000175000000620000002255110144436365014434 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "reson.h" void reson_free(); typedef struct reson_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; double c3; double c3p1; double c3t4; double omc3; double c2; double c1; double y1; double y2; } reson_susp_node, *reson_susp_type; void reson_n_fetch(register reson_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3_reg; register double c2_reg; register double c1_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "reson_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3_reg = susp->c3; c2_reg = susp->c2; c1_reg = susp->c1; y1_reg = susp->y1; y2_reg = susp->y2; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { double y0 = c1_reg * *s_ptr_reg++ + c2_reg * y1_reg - c3_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* reson_n_fetch */ void reson_s_fetch(register reson_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3_reg; register double c2_reg; register double c1_reg; register double y1_reg; register double y2_reg; register sample_type s_scale_reg = susp->s->scale; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "reson_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3_reg = susp->c3; c2_reg = susp->c2; c1_reg = susp->c1; y1_reg = susp->y1; y2_reg = susp->y2; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { double y0 = c1_reg * (s_scale_reg * *s_ptr_reg++) + c2_reg * y1_reg - c3_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0; }; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* reson_s_fetch */ void reson_toss_fetch(susp, snd_list) register reson_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s up to final_time for this block of zeros */ while ((round((final_time - susp->s->t0) * susp->s->sr)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void reson_mark(reson_susp_type susp) { sound_xlmark(susp->s); } void reson_free(reson_susp_type susp) { sound_unref(susp->s); ffree_generic(susp, sizeof(reson_susp_node), "reson_free"); } void reson_print_tree(reson_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_reson(sound_type s, double hz, double bw, int normalization) { register reson_susp_type susp; rate_type sr = s->sr; time_type t0 = s->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, reson_susp_node, "snd_make_reson"); susp->c3 = exp(bw * -PI2 / s->sr); susp->c3p1 = susp->c3 + 1.0; susp->c3t4 = susp->c3 * 4.0; susp->omc3 = 1.0 - susp->c3; susp->c2 = susp->c3t4 * cos(hz * PI2 / s->sr) / susp->c3p1; susp->c1 = (normalization == 0 ? 1.0 : (normalization == 1 ? susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)); susp->y1 = 0.0; susp->y2 = 0.0; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = reson_n_fetch; break; case INTERP_s: susp->susp.fetch = reson_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); /* minimum start time over all inputs: */ t0_min = min(s->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = reson_toss_fetch; } /* initialize susp state */ susp->susp.free = reson_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = reson_mark; susp->susp.print_tree = reson_print_tree; susp->susp.name = "reson"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_reson(sound_type s, double hz, double bw, int normalization) { sound_type s_copy = sound_copy(s); return snd_make_reson(s_copy, hz, bw, normalization); } nyquist-3.05/tran/oneshot.alg0000644000175000000620000000107211466723256015307 0ustar stevestaff(ONESHOT-ALG (NAME "oneshot") (ARGUMENTS ("sound_type" "input") ("double" "level") ("double" "ontime")) ; (INTERNAL-SCALING input) ; scale factor not handled in level because scale could be negative (STATE ("double" "lev" "level") ("long" "oncount" "round(ontime * input->sr)") ("long" "cnt" "0")) (START (MIN input)) (INNER-LOOP " double x = input; if (x > lev) cnt = oncount; cnt--; output = (cnt >= 0 ? 1.0F : 0.0F);") (CONSTANT "lev" "oncount") (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) ) nyquist-3.05/tran/maxv.h0000644000175000000620000000022210144436365014255 0ustar stevestaffsound_type snd_make_maxv(sound_type s1, sound_type s2); sound_type snd_maxv(sound_type s1, sound_type s2); /* LISP: (snd-maxv SOUND SOUND) */ nyquist-3.05/tran/pwl.alg0000644000175000000620000000515610144436365014433 0ustar stevestaff(PWL-ALG (NAME "pwl") (ARGUMENTS ("time_type" "t0") ("rate_type" "sr") ("LVAL" "lis")) (SUPPORT-FUNCTIONS " /* IMPLEMENTATION NOTE: * The lis argument is a list of alternating sample numbers and values * which are taken in pairs, with an implicit (0, 0) starting point. The * last point is a sample number only, the value being implicitly 0. * The bpt_ptr points to the next sample number in the list. * The incr is set to the increment per sample, and lvl is the next * sample value. * * The list is assumed to be well-formed, so it should be checked by * the caller (users should not call this directly). */ /* compute_lvl -- setup the susp with level, advance bpt_ptr */ /* * returns true if it is time to terminate * * Note: compute_lvl gets called in the outer loop to skip over * a breakpoint pair before starting the compute_incr loop, which * searches for a breakpoint that is some number of samples in the * future. This code is not embedded in compute_incr because it is * NOT called from the initialization, where it would be wrong to * skip over the first breakpoint. */ boolean compute_lvl(pwl_susp_type susp) { if (!cdr(susp->bpt_ptr)) return true; susp->lvl = getflonum(car(cdr(susp->bpt_ptr))); susp->bpt_ptr = cdr(cdr(susp->bpt_ptr)); return !susp->bpt_ptr; } /* compute_incr -- setup the susp with level and increment */ /* * returns true if it is time to terminate */ boolean compute_incr(pwl_susp_type susp, long *n, long cur) { double target; while (*n == 0) { *n = getfixnum(car(susp->bpt_ptr)) - cur; /* if there is a 2nd element of the pair, get the target */ if (cdr(susp->bpt_ptr)) target = getflonum(car(cdr(susp->bpt_ptr))); else target = 0.0; if (*n > 0) susp->incr = (target - susp->lvl) / *n; else if (compute_lvl(susp)) return true; } return false; } ") (SAMPLE-RATE "sr") (STATE ("LVAL" "bpt_ptr" "lis") ("double" "incr" "0.0") ("double" "lvl" "0.0; { long temp = 0; compute_incr(susp, &temp, 0); }")) (OUTER-LOOP " if (susp->bpt_ptr == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } { long cur = susp->susp.current + cnt; long nn = getfixnum(car(susp->bpt_ptr)) - cur; if (nn == 0) { if (compute_lvl(susp) || compute_incr(susp, &nn, cur)) goto out; } togo = min(nn, togo); } ") (INNER-LOOP "output = (sample_type) lvl; lvl += incr;") (MAINTAIN ("lvl" "susp->lvl += susp->incr * togo")) (CONSTANT "incr") (TERMINATE COMPUTED) ) nyquist-3.05/tran/slope.h0000644000175000000620000000016710144436365014434 0ustar stevestaffsound_type snd_make_slope(sound_type input); sound_type snd_slope(sound_type input); /* LISP: (snd-slope SOUND) */ nyquist-3.05/tran/instrsaxfreq.c0000644000175000000620000003431610144436365016041 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrsaxfreq.h" void sax_freq_free(); typedef struct sax_freq_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; struct instr *sax; int temp_ret_value; double frequency; } sax_freq_susp_node, *sax_freq_susp_type; #include "instr.h" void sax_freq_nn_fetch(register sax_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register double frequency_reg; register sample_block_values_type freq_env_ptr_reg; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_freq_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * *breath_env_ptr_reg++); setFrequency(sax_reg, frequency_reg + *freq_env_ptr_reg++); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_freq_nn_fetch */ void sax_freq_ns_fetch(register sax_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register double frequency_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_freq_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * *breath_env_ptr_reg++); setFrequency(sax_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_freq_ns_fetch */ void sax_freq_sn_fetch(register sax_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register double frequency_reg; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_freq_sn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); setFrequency(sax_reg, frequency_reg + *freq_env_ptr_reg++); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_freq_sn_fetch */ void sax_freq_ss_fetch(register sax_freq_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * sax_reg; register double frequency_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "sax_freq_ss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; sax_reg = susp->sax; frequency_reg = susp->frequency; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(sax_reg, 128, SAX_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); setFrequency(sax_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(sax_reg); } while (--n); /* inner loop */ susp->sax = sax_reg; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sax_freq_ss_fetch */ void sax_freq_toss_fetch(susp, snd_list) register sax_freq_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void sax_freq_mark(sax_freq_susp_type susp) { sound_xlmark(susp->breath_env); sound_xlmark(susp->freq_env); } void sax_freq_free(sax_freq_susp_type susp) { deleteInstrument(susp->sax); sound_unref(susp->breath_env); sound_unref(susp->freq_env); ffree_generic(susp, sizeof(sax_freq_susp_node), "sax_freq_free"); } void sax_freq_print_tree(sax_freq_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); } sound_type snd_make_sax_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr) { register sax_freq_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, sax_freq_susp_node, "snd_make_sax_freq"); susp->sax = initInstrument(SAXOFONY, round(sr)); controlChange(susp->sax, 1, 0.0);; susp->temp_ret_value = noteOn(susp->sax, freq, 1.0); susp->frequency = freq; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(breath_env, sr); interp_desc = (interp_desc << 2) + interp_style(freq_env, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = sax_freq_nn_fetch; break; case INTERP_ns: susp->susp.fetch = sax_freq_ns_fetch; break; case INTERP_sn: susp->susp.fetch = sax_freq_sn_fetch; break; case INTERP_ss: susp->susp.fetch = sax_freq_ss_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, min(freq_env->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = sax_freq_toss_fetch; } /* initialize susp state */ susp->susp.free = sax_freq_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = sax_freq_mark; susp->susp.print_tree = sax_freq_print_tree; susp->susp.name = "sax_freq"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sax_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); sound_type freq_env_copy = sound_copy(freq_env); return snd_make_sax_freq(freq, breath_env_copy, freq_env_copy, sr); } nyquist-3.05/tran/scale.h0000644000175000000620000000017510144436365014400 0ustar stevestaffsound_type snd_make_normalize(sound_type s1); sound_type snd_normalize(sound_type s1); /* LISP: (snd-normalize SOUND) */ nyquist-3.05/tran/partial.alg0000644000175000000620000000112610144436365015256 0ustar stevestaff(PARTIAL-ALG (NAME "partial") (ARGUMENTS ("rate_type" "sr") ("double" "hz") ("sound_type" "env")) (SUPPORT-FUNCTIONS " #include \"sine.h\" ") (START (MIN env)) (STATE ("long" "phase" "0") ("long" "ph_incr" "round((hz * SINE_TABLE_LEN) * (1 << SINE_TABLE_SHIFT) / sr)")) (TERMINATE (MIN env)) (LOGICAL-STOP (MIN env)) (INNER-LOOP "output = sine_table[phase >> SINE_TABLE_SHIFT] * env; phase += ph_incr; phase &= SINE_TABLE_MASK;") (MAINTAIN ("phase" "susp->phase = (susp->phase + susp->ph_incr * togo) & SINE_TABLE_MASK")) (CONSTANT "ph_incr") (SAMPLE-RATE "sr") ) nyquist-3.05/tran/stkpitshift.alg0000644000175000000620000000102011466723256016175 0ustar stevestaff(STKPITSHIFT-ALG (NAME "stkpitshift") (ARGUMENTS ("sound_type" "s1")("double" "shift")("double" "mix")("rate_type" "sr")) (STATE ("struct stkEffect *" "mych" "initStkPitShift(shift, round(sr)); stkEffectSetMix(susp->mych, mix)")) (START (MIN s1)) (TERMINATE (MIN s1)) (LOGICAL-STOP (MIN s1)) (NOT-IN-INNER-LOOP "mych" "shift" "mix" "sr") (SAMPLE-RATE "sr") (SUPPORT-FUNCTIONS " #include \"stkint.h\" ") (INNER-LOOP " output = (sample_type) (stkEffectTick(mych, s1)) ") (FINALIZATION " deleteStkEffect(susp->mych); ") )nyquist-3.05/tran/chase.alg0000644000175000000620000000114010144436365014701 0ustar stevestaff(CHASE-ALG (NAME "chase") (ARGUMENTS ("sound_type" "input") ("double" "risetime") ("double" "falltime")) (STATE ("double" "level" "0.0") ("double" "upslope" "1.0/(input->sr * risetime)") ("double" "downslope" "1.0/(input->sr * falltime)")) (START (MIN input)) (INNER-LOOP " double x = input; if (x > level) { level += upslope; if (x < level) level = x; } else { level -= downslope; if (x > level) level = x; } output = (sample_type) level;") (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) ) nyquist-3.05/tran/stkpitshift.c0000644000175000000620000002125611466723256015671 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "stkpitshift.h" void stkpitshift_free(); typedef struct stkpitshift_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; struct stkEffect *mych; } stkpitshift_susp_node, *stkpitshift_susp_type; #include "stkint.h" void stkpitshift_n_fetch(register stkpitshift_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct stkEffect * mych_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "stkpitshift_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; mych_reg = susp->mych; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (stkEffectTick(mych_reg, *s1_ptr_reg++)) ; } while (--n); /* inner loop */ susp->mych = mych_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* stkpitshift_n_fetch */ void stkpitshift_s_fetch(register stkpitshift_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct stkEffect * mych_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "stkpitshift_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; mych_reg = susp->mych; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (stkEffectTick(mych_reg, (s1_scale_reg * *s1_ptr_reg++))) ; } while (--n); /* inner loop */ susp->mych = mych_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* stkpitshift_s_fetch */ void stkpitshift_toss_fetch(susp, snd_list) register stkpitshift_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void stkpitshift_mark(stkpitshift_susp_type susp) { sound_xlmark(susp->s1); } void stkpitshift_free(stkpitshift_susp_type susp) { deleteStkEffect(susp->mych); sound_unref(susp->s1); ffree_generic(susp, sizeof(stkpitshift_susp_node), "stkpitshift_free"); } void stkpitshift_print_tree(stkpitshift_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_stkpitshift(sound_type s1, double shift, double mix, rate_type sr) { register stkpitshift_susp_type susp; /* sr specified as input parameter */ time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, stkpitshift_susp_node, "snd_make_stkpitshift"); susp->mych = initStkPitShift(shift, round(sr)); stkEffectSetMix(susp->mych, mix); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = stkpitshift_n_fetch; break; case INTERP_s: susp->susp.fetch = stkpitshift_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = stkpitshift_toss_fetch; } /* initialize susp state */ susp->susp.free = stkpitshift_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = stkpitshift_mark; susp->susp.print_tree = stkpitshift_print_tree; susp->susp.name = "stkpitshift"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_stkpitshift(sound_type s1, double shift, double mix, rate_type sr) { sound_type s1_copy = sound_copy(s1); return snd_make_stkpitshift(s1_copy, shift, mix, sr); } nyquist-3.05/tran/delay.alg0000644000175000000620000000140610144436365014721 0ustar stevestaff(DELAY-ALG (NAME "delay") (ARGUMENTS ("sound_type" "input") ("time_type" "delay") ("double" "feedback")) (START (MIN input)) (STATE ("double" "feedback" "feedback") ("long" "delaylen" "max(1, round(input->sr * delay))") ("sample_type *" "delaybuf" "(sample_type *) calloc (susp->delaylen, sizeof(sample_type))") ("sample_type *" "delayptr" "susp->delaybuf") ("sample_type *" "endptr" "susp->delaybuf + susp->delaylen")) (CONSTANT "feedback" "delaylen" "endptr") (NOT-REGISTER delaybuf) (LINEAR input) (TERMINATE (MIN input)) (INNER-LOOP "output = *delayptr; *delayptr = (sample_type) (*delayptr * feedback) + input; if (++delayptr >= endptr) delayptr = susp->delaybuf;") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/tonev.alg0000644000175000000620000000134110144436365014754 0ustar stevestaff(TONEV-ALG (NAME "tonev") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz")) (INLINE-INTERPOLATION T) (INTERNAL-SCALING s1) (ALWAYS-SCALE hz) (START (MAX s1 hz)) (TERMINATE (MIN s1 hz)) (LOGICAL-STOP (MIN s1)) (STATE ("double" "scale1" "s1->scale") ("double" "c2" "0.0") ("double" "c1" "0.0") ("double" "prev" "0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr))")) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION hz) (DEPENDS ("b" "hz" "2.0 - cos(hz)" TEMP "register double") ("c2" "hz" "b - sqrt((b * b) - 1.0)") ("c1" "hz" "(1.0 - c2) * scale1")) (CONSTANT "c1" "c2" "b" "scale1") (FORCE-INTO-REGISTER scale1) (INNER-LOOP " output = (sample_type) (prev = c1 * s1 + c2 * prev)") ) nyquist-3.05/tran/pluck.alg0000644000175000000620000001171010144436365014740 0ustar stevestaff;; PLUCK.ALG is based on the Pluck.t instrument from M4C ;; ; to assist with debugging, here are some calculated parameters ; dumped from a run of M4C: ; ; Setup Pluck at t= 6.000 ; DUR= 1.000, pitch= 8.060, amp= 10000, DB_drop= 60.0, rfrac=0.00 ; freq 369.995 ; freq = 369.995361 ; Final = 1000.000000, t= 0.052715, y = 0.000000, lF = 6.907755 ; tdecay = 13.430565, sT = 369.995361, rho = 0.982869, stretch = 0.500000 ; N = 59, x = 0.095342, cons = 0.825914 ; x2 0.412957 x3 0.912957 stretch 0.5 cons 0.825914 SR 22050 ; complete Pluck setup ;; (PLUCK-ALG (NAME "pluck") (ARGUMENTS ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("time_type" "d") ("double" "final_amp")) (SUPPORT-FUNCTIONS " #define MAXLENGTH 20000 long pluck_parameters(double hz, double sr, double final, double dur, double *stretch, double *cons, double *rho) { double t = PI * (hz / sr); double y = fabs(cos(t)); /* original m4c code used ratio of initial amp to final amp in dB and then converted to a ratio, e.g. you specify 60 and the parameter Final is 1000.0. This is counterintuitive to me (RBD) because I would expect the value to be -60dB or 0.001. That is what I implemented, so to get this back into correspondence with the m4c algorithm, I take the NEGATIVE log to get lf, whereas m4c takes the positive log: */ double lf = -log(final); double tdecay = -lf / (hz * log(y)); double st; long len; double x; if (hz <= sr / MAXLENGTH) { xlfail(\"pluck hz is too low\"); } else if (hz >= sr / 3) { xlfail(\"pluck hz is too high\"); } /* * if desired decay time is shorter than the natural decay time, * then introduce a loss factor. Otherwise, stretch note out. */ st = hz * dur; if (dur < tdecay) { *rho = exp(-lf / st) / y; *stretch = 0.5; } else { *rho = 1; *stretch = 0.5 + sqrt(0.25 - (1 - exp(2 * lf * (hz - sr) / (st * sr))) / (2 - 2 * cos(2 * t))); } /* delay line length is */ len = (int) ((sr / hz) - *stretch - 0.001); /* tuning constant is */ x = (sr / hz) - len - *stretch; *cons = (1.0 - x) / (1.0 + x); if (len <= 1) { xlfail(\"internal error: pluck delay line length too short\"); } return len; } static unsigned int rnext = 1; int krand() { rnext = rnext * 1103515245 + 12345; return (rnext >> 16) & 0x7fff; } void pluck_initialize(sample_type *shiftreg, sample_type *array, long len, double cons) { sample_type suma = 0.0F; long k; sample_type avea; array[1] = 0; for (k = len; k > 0; k--, array--) { /* note: the m4c code has a bug. It claims to filter the initial values, but it really just sets the values to +1 or -1. The following does the same thing with much less code: */ *array = (krand() & 2) - 1; suma += *array; /* compute sum for the average */ } avea = suma / len; /* zero the average */ for (k = 0; k <= len + 1; k++) shiftreg[k] -= avea; shiftreg[len] = 0; shiftreg[len + 1] = 0; }") (STATE ("double" "stretch" "0") ("double" "cons" "0") ("double" "loss" "0") ("long" "len" "pluck_parameters(hz, sr, final_amp, d, &susp->stretch, &susp->cons, &susp->loss)") ("double" "x2" "-susp->cons * (susp->stretch - 1)") ("double" "x3" "susp->cons * susp->stretch - susp->stretch + 1") ("sample_type *" "shiftreg" ;; I think susp->len + 2 is the correct value, but I use +4 to be safe "(sample_type *) calloc (susp->len + 4, sizeof(sample_type))") ("sample_type *" "i1" "susp->shiftreg + susp->len + 1") ("sample_type *" "i2" "susp->shiftreg + susp->len") ("sample_type *" "i3" "susp->shiftreg + susp->len - 1") ("sample_type *" "i4" "susp->shiftreg + susp->len - 2") ("sample_type *" "endptr" "susp->shiftreg + susp->len + 2; pluck_initialize(susp->shiftreg, susp->i3, susp->len, susp->cons)")) (CONSTANT "stretch" "cons" "loss" "len" "x2" "x3" "endptr") (SAMPLE-RATE "sr") (NOT-REGISTER shiftreg) (TERMINATE (AFTER "d")) (INNER-LOOP " sample_type sum = (sample_type) ((*i1++ * x2) + (*i2++ * x3) + (*i3++ * stretch) - (*i4++ * cons)); /* wrap pointers around shift register if necessary */ if (i1 == endptr) i1 = susp->shiftreg; if (i2 == endptr) i2 = susp->shiftreg; if (i3 == endptr) i3 = susp->shiftreg; if (i4 == endptr) i4 = susp->shiftreg; /* store new value in shift register */ *i4 = (sample_type) (sum * loss); /* deliver sample */ output = sum; ") (FINALIZATION " free(susp->shiftreg);\n") ) nyquist-3.05/tran/eqbandvvv.alg0000644000175000000620000000416110144436365015620 0ustar stevestaff; general order-2 IIR filter. ; a0 is assumed to be unity. ; for a1 and a2, our sign convention is opposite to Matlab's. (EQBANDVVV-ALG (NAME "eqbandvvv") (ARGUMENTS ("sound_type" "input") ("sound_type" "hz") ("sound_type" "gain") ("sound_type" "width") ) (SUPPORT-FUNCTIONS "#define log_of_2_over_2 0.3465735902799726547086\n") (START (MIN input hz gain width)) (TERMINATE (MIN input hz gain width)) (LOGICAL-STOP (MIN input hz gain width)) (SAMPLE-RATE (MAX input)) ;;(INTERNAL-SCALING input hz gain width) (INLINE-INTERPOLATION T) (MATCHED-SAMPLE-RATE hz gain width) (ALWAYS-SCALE input hz gain width) (STEP-FUNCTION hz gain width) (STATE ("double" "inp_scale" "input->scale") ("double" "w1" "0.0") ("double" "sw" "0.0") ("double" "cw" "0.0") ("double" "J" "0.0") ("double" "gg" "0.0") ("double" "b0" "0.0") ("double" "b1" "0.0") ("double" "b2" "0.0") ("double" "a0" "0.0") ("double" "a1" "0.0") ("double" "a2" "0.0") ("double" "z1" "0.0") ("double" "z2" "0.0") ("boolean" "recompute" "false") ("double" "inp_period" "1.0 / input->sr")) (DEPENDS ("w1" "hz" "PI2 * hz * inp_period") ("sw" "hz" "sin(w1)") ("cw" "hz" "cos(w1)") ("b1" "hz" "-2.0 * cw") ("a1" "hz" "-b1") ("J" "gain" "sqrt(gain)") ("recompute" "width" "true") ("recompute" "hz" "true") ("recompute" "gain" "true") ) (JOINT-DEPENDENCY (("width" "hz") "if (recompute) {" " /* a0 = 1.0 + gg / J; */" " double a_0_recip = J / (J + gg);" " recompute = false;" " gg = sw * sinh(log_of_2_over_2 * width * w1 / sw);" " b0 = (1.0 + gg * J) * a_0_recip;" " b1 *= a_0_recip;" " b2 = (1.0 - gg * J) * a_0_recip;" " a1 *= a_0_recip;" " a2 = (gg / J - 1.0) * a_0_recip;" "}")) (FORCE-INTO-REGISTER recompute inp_period cw) (CONSTANT "w1" "sw" "cw" "J" "gg" "b0" "b1" "b2" "b3" "a0" "a1" "a2" "inp_period") (INNER-LOOP-LOCALS " double z0;\n") (INNER-LOOP " z0 = input + a1*z1 + a2*z2; output = (sample_type) (z0*b0 + z1*b1 + z2*b2); z2 = z1; z1 = z0;") ) nyquist-3.05/tran/upsample.c0000644000175000000620000003173010144436365015133 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "upsample.h" void up_free(); typedef struct up_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; /* support for interpolation of input */ sample_type input_x1_sample; double input_pHaSe; double input_pHaSe_iNcR; /* support for ramp between samples of input */ double output_per_input; long input_n; } up_susp_node, *up_susp_type; void up_n_fetch(register up_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "up_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) *input_ptr_reg++; } while (--n); /* inner loop */ /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* up_n_fetch */ void up_i_fetch(register up_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type input_x2_sample; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double input_pHaSe_iNcR_rEg = susp->input_pHaSe_iNcR; register double input_pHaSe_ReG; register sample_type input_x1_sample_reg; falloc_sample_block(out, "up_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(input, input_ptr, input_cnt); susp->input_x1_sample = susp_fetch_sample(input, input_ptr, input_cnt); } susp_check_term_log_samples(input, input_ptr, input_cnt); input_x2_sample = susp_current_sample(input, input_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; input_pHaSe_ReG = susp->input_pHaSe; input_x1_sample_reg = susp->input_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (input_pHaSe_ReG >= 1.0) { input_x1_sample_reg = input_x2_sample; /* pick up next sample as input_x2_sample: */ susp->input_ptr++; susp_took(input_cnt, 1); input_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(input, input_ptr, input_cnt, input_x2_sample); } *out_ptr_reg++ = (sample_type) (input_x1_sample_reg * (1 - input_pHaSe_ReG) + input_x2_sample * input_pHaSe_ReG); input_pHaSe_ReG += input_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->input_pHaSe = input_pHaSe_ReG; susp->input_x1_sample = input_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* up_i_fetch */ void up_r_fetch(register up_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type input_DeLtA; sample_type input_val; sample_type input_x2_sample; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; falloc_sample_block(out, "up_r_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->input_pHaSe = 1.0; } susp_check_term_log_samples(input, input_ptr, input_cnt); input_x2_sample = susp_current_sample(input, input_ptr); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* grab next input_x2_sample when phase goes past 1.0; */ /* we use input_n (computed below) to avoid roundoff errors: */ if (susp->input_n <= 0) { susp->input_x1_sample = input_x2_sample; susp->input_ptr++; susp_took(input_cnt, 1); susp->input_pHaSe -= 1.0; susp_check_term_log_samples(input, input_ptr, input_cnt); input_x2_sample = susp_current_sample(input, input_ptr); /* input_n gets number of samples before phase exceeds 1.0: */ susp->input_n = (long) ((1.0 - susp->input_pHaSe) * susp->output_per_input); } togo = min(togo, susp->input_n); input_DeLtA = (sample_type) ((input_x2_sample - susp->input_x1_sample) * susp->input_pHaSe_iNcR); input_val = (sample_type) (susp->input_x1_sample * (1.0 - susp->input_pHaSe) + input_x2_sample * susp->input_pHaSe); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) input_val; input_val += input_DeLtA; } while (--n); /* inner loop */ out_ptr += togo; susp->input_pHaSe += togo * susp->input_pHaSe_iNcR; susp->input_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* up_r_fetch */ void up_toss_fetch(susp, snd_list) register up_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void up_mark(up_susp_type susp) { sound_xlmark(susp->input); } void up_free(up_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(up_susp_node), "up_free"); } void up_print_tree(up_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_up(rate_type sr, sound_type input) { register up_susp_type susp; /* sr specified as input parameter */ time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } if (input->sr > sr) { sound_unref(input); xlfail("snd-up: output sample rate must be higher than input"); } falloc_generic(susp, up_susp_node, "snd_make_up"); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = up_n_fetch; break; case INTERP_i: susp->susp.fetch = up_i_fetch; break; case INTERP_r: susp->susp.fetch = up_r_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = up_toss_fetch; } /* initialize susp state */ susp->susp.free = up_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = up_mark; susp->susp.print_tree = up_print_tree; susp->susp.name = "up"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->started = false; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; susp->input_pHaSe = 0.0; susp->input_pHaSe_iNcR = input->sr / sr; susp->input_n = 0; susp->output_per_input = sr / input->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_up(rate_type sr, sound_type input) { sound_type input_copy = sound_copy(input); return snd_make_up(sr, input_copy); } nyquist-3.05/tran/tapv.h0000644000175000000620000000035410144436365014262 0ustar stevestaffsound_type snd_make_tapv(sound_type s1, double offset, sound_type vardelay, double maxdelay); sound_type snd_tapv(sound_type s1, double offset, sound_type vardelay, double maxdelay); /* LISP: (snd-tapv SOUND ANYNUM SOUND ANYNUM) */ nyquist-3.05/tran/instrsaxfreq.h0000644000175000000620000000045110144436365016037 0ustar stevestaffsound_type snd_make_sax_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr); sound_type snd_sax_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr); /* LISP: (snd-sax_freq ANYNUM SOUND SOUND ANYNUM) */ #define SAX_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/alpass.c0000644000175000000620000001303110144436365014562 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "alpass.h" void alpass_free(); typedef struct alpass_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type input; long input_cnt; sample_block_values_type input_ptr; double feedback; long delaylen; sample_type *delaybuf; sample_type *delayptr; sample_type *endptr; } alpass_susp_node, *alpass_susp_type; void alpass_n_fetch(register alpass_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double feedback_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpass_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; feedback_reg = susp->feedback; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z; y = *delayptr_reg; *delayptr_reg++ = z = (sample_type) (feedback_reg * y + *input_ptr_reg++); *out_ptr_reg++ = (sample_type) (y - feedback_reg * z); if (delayptr_reg >= endptr_reg) delayptr_reg = susp->delaybuf;; } while (--n); /* inner loop */ susp->delayptr = delayptr_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpass_n_fetch */ void alpass_toss_fetch(susp, snd_list) register alpass_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void alpass_mark(alpass_susp_type susp) { sound_xlmark(susp->input); } void alpass_free(alpass_susp_type susp) { free(susp->delaybuf); sound_unref(susp->input); ffree_generic(susp, sizeof(alpass_susp_node), "alpass_free"); } void alpass_print_tree(alpass_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_alpass(sound_type input, time_type delay, double feedback) { register alpass_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, alpass_susp_node, "snd_make_alpass"); susp->feedback = feedback; susp->delaylen = max(1, round(input->sr * delay)); susp->delaybuf = (sample_type *) calloc (susp->delaylen, sizeof(sample_type)); susp->delayptr = susp->delaybuf; susp->endptr = susp->delaybuf + susp->delaylen; susp->susp.fetch = alpass_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = alpass_toss_fetch; } /* initialize susp state */ susp->susp.free = alpass_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = alpass_mark; susp->susp.print_tree = alpass_print_tree; susp->susp.name = "alpass"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_alpass(sound_type input, time_type delay, double feedback) { sound_type input_copy = sound_copy(input); return snd_make_alpass(input_copy, delay, feedback); } nyquist-3.05/tran/instrmandolin.c0000644000175000000620000000616111466723256016174 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrmandolin.h" void mandolin_free(); typedef struct mandolin_susp_struct { snd_susp_node susp; long terminate_cnt; struct instr *mymand; int temp_ret_value; } mandolin_susp_node, *mandolin_susp_type; #include "instr.h" void mandolin__fetch(register mandolin_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * mymand_reg; falloc_sample_block(out, "mandolin__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; mymand_reg = susp->mymand; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) tick(mymand_reg); } while (--n); /* inner loop */ susp->mymand = mymand_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* mandolin__fetch */ void mandolin_free(mandolin_susp_type susp) { deleteInstrument(susp->mymand); ffree_generic(susp, sizeof(mandolin_susp_node), "mandolin_free"); } void mandolin_print_tree(mandolin_susp_type susp, int n) { } sound_type snd_make_mandolin(time_type t0, double freq, time_type d, double body_size, double detune, rate_type sr) { register mandolin_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, mandolin_susp_node, "snd_make_mandolin"); susp->mymand = initInstrument(MANDOLIN, round(sr)); controlChange(susp->mymand, 1, detune); controlChange(susp->mymand, 2, MAND_CONTROL_CHANGE_CONST * body_size);; susp->temp_ret_value = noteOn(susp->mymand, freq, 1.0); susp->susp.fetch = mandolin__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = mandolin_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = mandolin_print_tree; susp->susp.name = "mandolin"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_mandolin(time_type t0, double freq, time_type d, double body_size, double detune, rate_type sr) { return snd_make_mandolin(t0, freq, d, body_size, detune, sr); } nyquist-3.05/tran/instrsaxfreq.alg0000644000175000000620000000146510144436365016361 0ustar stevestaff(INSTRSAX-FREQ-ALG (NAME "sax_freq") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("sound_type" "freq_env") ("rate_type" "sr")) (STATE ("struct instr *" "sax" "initInstrument(SAXOFONY, round(sr)); controlChange(susp->sax, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->sax, freq, 1.0)") ("double" "frequency" "freq")) (START (min breath_env)) (NOT-IN-INNER-LOOP "temp_ret_value") (CONSTANT "frequency") (SAMPLE-RATE "sr") (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(sax, 128, SAX_CONTROL_CHANGE_CONST * breath_env); setFrequency(sax, frequency + freq_env); output = (sample_type) tick(sax)") (SUPPORT-HEADER " #define SAX_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->sax); ") ) nyquist-3.05/tran/integrate.alg0000644000175000000620000000050210144436365015601 0ustar stevestaff(INTEGRATE-ALG (NAME "integrate") (ARGUMENTS ("sound_type" "input")) (START (MIN input)) (TERMINATE (MIN input)) (LINEAR input) (LOGICAL-STOP (MIN input)) (STATE ("double" "integral" "0.0; scale_factor = (sample_type) (scale_factor / input->sr)")) (INNER-LOOP "output = (sample_type) integral; integral += input;") ) nyquist-3.05/tran/integrate.h0000644000175000000620000000020310144436365015263 0ustar stevestaffsound_type snd_make_integrate(sound_type input); sound_type snd_integrate(sound_type input); /* LISP: (snd-integrate SOUND) */ nyquist-3.05/tran/upsample.alg0000644000175000000620000000064510144436365015455 0ustar stevestaff(UP-ALG (NAME "up") (ARGUMENTS ("rate_type" "sr") ("sound_type" "input")) (INLINE-INTERPOLATION T) (SAMPLE-RATE "sr") (START (MIN input)) (INNER-LOOP "output = (sample_type) input") (LINEAR input) (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) (TYPE-CHECK " if (input->sr > sr) { sound_unref(input); xlfail(\"snd-up: output sample rate must be higher than input\"); } ") ) nyquist-3.05/tran/instrmandolin.h0000644000175000000620000000053211466723256016175 0ustar stevestaffsound_type snd_make_mandolin(time_type t0, double freq, time_type d, double body_size, double detune, rate_type sr); sound_type snd_mandolin(time_type t0, double freq, time_type d, double body_size, double detune, rate_type sr); /* LISP: (snd-mandolin ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ #define MAND_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/gate.c0000644000175000000620000002737010144436365014232 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "gate.h" void gate_free(); typedef struct gate_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type signal; long signal_cnt; sample_block_values_type signal_ptr; double rise_time; double fall_time; double floor; double threshold; long on_count; long off_count; double rise_factor; double fall_factor; long start_fall; long start_rise; long stop_count; long delay_len; int state; double value; } gate_susp_node, *gate_susp_type; #define ST_HOLD 0 #define ST_FALL 1 #define ST_FALL_UNTIL 2 #define ST_OFF 3 #define ST_OFF_UNTIL 4 #define ST_RISE 5 /* Overview: This operation generates an exponential rise and decay suitable for implementing a noise gate. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to 1.0 (0dB) at the point the signal crosses the threshold. Again, lookahead is used, so the rise actually starts before the signal crosses the threshold. The rise rate is constant and set so that a rise from floor to 0dB occurs in the specified risetime. Similarly, the fall rate is constant such that a fall from 0dB to the floor takes falltime. Rather than looking ahead, the output actually lags the input by lookahead. The caller should advance the time of the input signal in order to get a correct output signal, and this will be taken care of in Lisp code. The implementation is a finite-state machine that simultaneously computes the value and scans ahead for threshold crossings. Time points, remembered as sample counts are saved in variables: on_count -- the time at which the rise should complete off_count -- the time at which the fall should begin rise_factor -- multiply by this to get exponential rise fall_factor -- multiply by this to get exponential fall rise_time -- number of samples for a full rise fall_time -- number of samples for a full fall floor -- the lowest value to output threshold -- compare the signal s to this value start_rise -- the sample count at which a rise begins delay_len -- number of samples to look ahead, length of buffer state -- the current state of finite state machine (see the individual 'case' statements for description of states) value -- the current output value computing fall_factor: factor ^ (sample_rate * time) == floor log(factor) * sample_rate * time == log(floor) log(factor) == log(floor) / (sample_rate * time) factor == exp(log(floor) / (sample_rate * time)) */ void compute_start_rise(gate_susp_type susp) { /* to compute when to start rise to achieve 0dB at on_count: By similar triangles: truncated rise time truncated fall time ------------------- == ------------------- full rise time full fall time when you enter ST_FALL, set start_fall = now then if (on_count - start_fall) < (rise_time + fall_time) then start rise at on_time - rise_time * (on_count-start_fall)/(rise_time+fall_time) */ long total = (long) (susp->rise_time + susp->fall_time); if ((susp->on_count - susp->start_fall) < total) { susp->start_rise = (long) (susp->on_count - (susp->rise_time * susp->on_count - susp->start_fall) / total); } else susp->start_rise = (long) (susp->on_count - susp->rise_time); } void gate_n_fetch(register gate_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double threshold_reg; register long off_count_reg; register long stop_count_reg; register long delay_len_reg; register int state_reg; register double value_reg; register sample_block_values_type signal_ptr_reg; falloc_sample_block(out, "gate_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the signal input sample block: */ susp_check_term_samples(signal, signal_ptr, signal_cnt); togo = min(togo, susp->signal_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; threshold_reg = susp->threshold; off_count_reg = susp->off_count; stop_count_reg = susp->stop_count; delay_len_reg = susp->delay_len; state_reg = susp->state; value_reg = susp->value; signal_ptr_reg = susp->signal_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { sample_type future = *signal_ptr_reg++; long now = susp->susp.current + cnt + togo - n; switch (state_reg) { /* hold at 1.0 and look for the moment to begin fall: */ case ST_HOLD: if (future >= threshold_reg) { off_count_reg = now + delay_len_reg; } else if (now >= off_count_reg) { state_reg = ST_FALL; stop_count_reg = (long) (now + susp->fall_time); susp->start_fall = now; } break; /* fall until stop_count_reg while looking for next rise time */ case ST_FALL: if (future >= threshold_reg) { off_count_reg = susp->on_count = now + delay_len_reg; compute_start_rise(susp); state_reg = ST_FALL_UNTIL; } else if (now == stop_count_reg) { state_reg = ST_OFF; value_reg = susp->floor; } else value_reg *= susp->fall_factor; break; /* fall until start_rise while looking for next fall time */ case ST_FALL_UNTIL: value_reg *= susp->fall_factor; if (future >= threshold_reg) { off_count_reg = now + delay_len_reg; } if (now >= susp->start_rise) { state_reg = ST_RISE; } else if (now >= stop_count_reg) { state_reg = ST_OFF_UNTIL; value_reg = susp->floor; } break; /* hold at floor (minimum value_reg) and look for next rise time */ case ST_OFF: if (future >= threshold_reg) { off_count_reg = susp->on_count = now + delay_len_reg; compute_start_rise(susp); state_reg = ST_OFF_UNTIL; } break; /* hold at floor until start_rise while looking for next fall time */ case ST_OFF_UNTIL: if (future >= threshold_reg) { off_count_reg = now + delay_len_reg; } if (now >= susp->start_rise) { state_reg = ST_RISE; } break; /* rise while looking for fall time */ case ST_RISE: value_reg *= susp->rise_factor; if (future >= threshold_reg) { off_count_reg = now + delay_len_reg; } if (now >= susp->on_count) { value_reg = 1.0; state_reg = ST_HOLD; } break; } *out_ptr_reg++ = (sample_type) value_reg; }; } while (--n); /* inner loop */ togo -= n; susp->off_count = off_count_reg; susp->stop_count = stop_count_reg; susp->state = state_reg; susp->value = value_reg; /* using signal_ptr_reg is a bad idea on RS/6000: */ susp->signal_ptr += togo; out_ptr += togo; susp_took(signal_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* gate_n_fetch */ void gate_toss_fetch(susp, snd_list) register gate_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from signal up to final_time for this block of zeros */ while ((round((final_time - susp->signal->t0) * susp->signal->sr)) >= susp->signal->current) susp_get_samples(signal, signal_ptr, signal_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->signal->t0) * susp->signal->sr - (susp->signal->current - susp->signal_cnt)); susp->signal_ptr += n; susp_took(signal_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void gate_mark(gate_susp_type susp) { sound_xlmark(susp->signal); } void gate_free(gate_susp_type susp) { sound_unref(susp->signal); ffree_generic(susp, sizeof(gate_susp_node), "gate_free"); } void gate_print_tree(gate_susp_type susp, int n) { indent(n); stdputstr("signal:"); sound_print_tree_1(susp->signal, n); } sound_type snd_make_gate(sound_type signal, time_type lookahead, double risetime, double falltime, double floor, double threshold) { register gate_susp_type susp; rate_type sr = signal->sr; time_type t0 = signal->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (SIGNAL) */ scale_factor *= signal->scale; signal->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (signal->sr < sr) { signal->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, gate_susp_node, "snd_make_gate"); susp->rise_time = signal->sr * risetime + 0.5; susp->fall_time = signal->sr * falltime + 0.5; susp->floor = floor; floor = log(floor);; susp->threshold = threshold; susp->on_count = 0; susp->off_count = 0; susp->rise_factor = exp(- floor / susp->rise_time); susp->fall_factor = exp(floor / susp->fall_time); susp->start_fall = 0; susp->start_rise = 0; susp->stop_count = 0; susp->delay_len = max(1, round(signal->sr * lookahead)); susp->state = ST_OFF; susp->value = susp->floor; susp->susp.fetch = gate_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < signal->t0) sound_prepend_zeros(signal, t0); /* minimum start time over all inputs: */ t0_min = min(signal->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = gate_toss_fetch; } /* initialize susp state */ susp->susp.free = gate_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = gate_mark; susp->susp.print_tree = gate_print_tree; susp->susp.name = "gate"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->signal = signal; susp->signal_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_gate(sound_type signal, time_type lookahead, double risetime, double falltime, double floor, double threshold) { sound_type signal_copy = sound_copy(signal); return snd_make_gate(signal_copy, lookahead, risetime, falltime, floor, threshold); } nyquist-3.05/tran/convolve.alg0000644000175000000620000000347210144436365015463 0ustar stevestaff(CONVOLVE-ALG (NAME "convolve") (SUPPORT-FUNCTIONS " void h_reverse(sample_type *h, long len) { sample_type temp; int i; for (i = 0; i < len; i++) { temp = h[i]; h[i] = h[len - 1]; h[len - 1] = temp; len--; } } ") (ARGUMENTS ("sound_type" "x_snd") ("sound_type" "h_snd") ) (TABLE "h_snd") (START (MIN x_snd)) (NOT-IN-INNER-LOOP "h_snd") (STATE ("table_type" "table" "sound_to_table(h_snd)") ("sample_type *" "h_buf" "susp->table->samples") ("double" "length_of_h" "susp->table->length") ("long" "h_len" "(long) susp->length_of_h; h_reverse(susp->h_buf, susp->h_len)") ("long" "x_buf_len" "2 * susp->h_len") ("sample_type *" "x_buffer_pointer" "calloc((2 * (susp->h_len)), sizeof(float))") ("sample_type *" "x_buffer_current" "susp->x_buffer_pointer") ) (ALWAYS-SCALE x_snd) (TERMINATE (MIN x_snd)) (LOGICAL-STOP (MIN x_snd)) (INNER-LOOP-LOCALS "long i; double sum;") (INNER-LOOP " /* see if we've reached end of x_buffer */ if ((x_buffer_pointer + x_buf_len) <= (x_buffer_current + h_len)) { /* shift x_buffer from current back to base */ for (i = 1; i < h_len; i++) { x_buffer_pointer[i-1] = x_buffer_current[i]; } /* this will be incremented back to x_buffer_pointer below */ x_buffer_current = x_buffer_pointer - 1; } x_buffer_current++; x_buffer_current[h_len - 1] = x_snd; sum = 0.0; for (i = 0; i < h_len; i++) { sum += x_buffer_current[i] * h_buf[i]; } output = (sample_type) sum; ") (CONSTANT "h_buf" "h_len" "x_buf_len" "table") (SAMPLE-RATE "x_snd->sr") (FINALIZATION " table_unref(susp->table); free(susp->x_buffer_pointer);") ) nyquist-3.05/tran/alpassvc.h0000644000175000000620000000040210144436365015116 0ustar stevestaffsound_type snd_make_alpassvc(sound_type input, sound_type delaysnd, double feedback, double maxdelay); sound_type snd_alpassvc(sound_type input, sound_type delaysnd, double feedback, double maxdelay); /* LISP: (snd-alpassvc SOUND SOUND ANYNUM ANYNUM) */ nyquist-3.05/tran/chase.c0000644000175000000620000002270310144436365014370 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "chase.h" void chase_free(); typedef struct chase_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; double level; double upslope; double downslope; } chase_susp_node, *chase_susp_type; void chase_n_fetch(register chase_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double level_reg; register double upslope_reg; register double downslope_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "chase_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; level_reg = susp->level; upslope_reg = susp->upslope; downslope_reg = susp->downslope; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x = *input_ptr_reg++; if (x > level_reg) { level_reg += upslope_reg; if (x < level_reg) level_reg = x; } else { level_reg -= downslope_reg; if (x > level_reg) level_reg = x; } *out_ptr_reg++ = (sample_type) level_reg;; } while (--n); /* inner loop */ susp->level = level_reg; susp->upslope = upslope_reg; susp->downslope = downslope_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* chase_n_fetch */ void chase_s_fetch(register chase_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double level_reg; register double upslope_reg; register double downslope_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "chase_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; level_reg = susp->level; upslope_reg = susp->upslope; downslope_reg = susp->downslope; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x = (input_scale_reg * *input_ptr_reg++); if (x > level_reg) { level_reg += upslope_reg; if (x < level_reg) level_reg = x; } else { level_reg -= downslope_reg; if (x > level_reg) level_reg = x; } *out_ptr_reg++ = (sample_type) level_reg;; } while (--n); /* inner loop */ susp->level = level_reg; susp->upslope = upslope_reg; susp->downslope = downslope_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* chase_s_fetch */ void chase_toss_fetch(susp, snd_list) register chase_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void chase_mark(chase_susp_type susp) { sound_xlmark(susp->input); } void chase_free(chase_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(chase_susp_node), "chase_free"); } void chase_print_tree(chase_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_chase(sound_type input, double risetime, double falltime) { register chase_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, chase_susp_node, "snd_make_chase"); susp->level = 0.0; susp->upslope = 1.0/(input->sr * risetime); susp->downslope = 1.0/(input->sr * falltime); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = chase_n_fetch; break; case INTERP_s: susp->susp.fetch = chase_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = chase_toss_fetch; } /* initialize susp state */ susp->susp.free = chase_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = chase_mark; susp->susp.print_tree = chase_print_tree; susp->susp.name = "chase"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_chase(sound_type input, double risetime, double falltime) { sound_type input_copy = sound_copy(input); return snd_make_chase(input_copy, risetime, falltime); } nyquist-3.05/tran/reson.h0000644000175000000620000000032610144436365014435 0ustar stevestaffsound_type snd_make_reson(sound_type s, double hz, double bw, int normalization); sound_type snd_reson(sound_type s, double hz, double bw, int normalization); /* LISP: (snd-reson SOUND ANYNUM ANYNUM FIXNUM) */ nyquist-3.05/tran/delaycv.c0000644000175000000620000002206610144436365014736 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "delaycv.h" void delaycv_free(); typedef struct delaycv_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type s; long s_cnt; sample_block_values_type s_ptr; sound_type feedback; long feedback_cnt; sample_block_values_type feedback_ptr; long delaylen; sample_type *delaybuf; sample_type *delayptr; sample_type *endptr; } delaycv_susp_node, *delaycv_susp_type; void delaycv_nn_fetch(register delaycv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type feedback_ptr_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "delaycv_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *delayptr_reg; *delayptr_reg = *delayptr_reg * *feedback_ptr_reg++ + *s_ptr_reg++; if (++delayptr_reg >= endptr_reg) delayptr_reg = susp->delaybuf;; } while (--n); /* inner loop */ susp->delayptr = delayptr_reg; susp->endptr = endptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* delaycv_nn_fetch */ void delaycv_ns_fetch(register delaycv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_type feedback_scale_reg = susp->feedback->scale; register sample_block_values_type feedback_ptr_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "delaycv_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *delayptr_reg; *delayptr_reg = *delayptr_reg * (feedback_scale_reg * *feedback_ptr_reg++) + *s_ptr_reg++; if (++delayptr_reg >= endptr_reg) delayptr_reg = susp->delaybuf;; } while (--n); /* inner loop */ susp->delayptr = delayptr_reg; susp->endptr = endptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* delaycv_ns_fetch */ void delaycv_toss_fetch(susp, snd_list) register delaycv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s up to final_time for this block of zeros */ while ((round((final_time - susp->s->t0) * susp->s->sr)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* fetch samples from feedback up to final_time for this block of zeros */ while ((round((final_time - susp->feedback->t0) * susp->feedback->sr)) >= susp->feedback->current) susp_get_samples(feedback, feedback_ptr, feedback_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); n = round((final_time - susp->feedback->t0) * susp->feedback->sr - (susp->feedback->current - susp->feedback_cnt)); susp->feedback_ptr += n; susp_took(feedback_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void delaycv_mark(delaycv_susp_type susp) { sound_xlmark(susp->s); sound_xlmark(susp->feedback); } void delaycv_free(delaycv_susp_type susp) { free(susp->delaybuf); sound_unref(susp->s); sound_unref(susp->feedback); ffree_generic(susp, sizeof(delaycv_susp_node), "delaycv_free"); } void delaycv_print_tree(delaycv_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); indent(n); stdputstr("feedback:"); sound_print_tree_1(susp->feedback, n); } sound_type snd_make_delaycv(sound_type s, time_type delay, sound_type feedback) { register delaycv_susp_type susp; rate_type sr = max(s->sr, feedback->sr); time_type t0 = max(s->t0, feedback->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (S) */ scale_factor *= s->scale; s->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s->sr < sr) { s->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, delaycv_susp_node, "snd_make_delaycv"); susp->delaylen = round(s->sr * delay); susp->delaybuf = (sample_type *) calloc (sizeof(double), susp->delaylen); susp->delayptr = susp->delaybuf; susp->endptr = susp->delaybuf + susp->delaylen; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s, sr); interp_desc = (interp_desc << 2) + interp_style(feedback, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = delaycv_nn_fetch; break; case INTERP_ns: susp->susp.fetch = delaycv_ns_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); if (t0 < feedback->t0) sound_prepend_zeros(feedback, t0); /* minimum start time over all inputs: */ t0_min = min(s->t0, min(feedback->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = delaycv_toss_fetch; } /* initialize susp state */ susp->susp.free = delaycv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = delaycv_mark; susp->susp.print_tree = delaycv_print_tree; susp->susp.name = "delaycv"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; susp->feedback = feedback; susp->feedback_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_delaycv(sound_type s, time_type delay, sound_type feedback) { sound_type s_copy = sound_copy(s); sound_type feedback_copy = sound_copy(feedback); return snd_make_delaycv(s_copy, delay, feedback_copy); } nyquist-3.05/tran/biquadfilt.c0000644000175000000620000002307411466723256015441 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "biquadfilt.h" void biquadfilt_free(); typedef struct biquadfilt_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s; long s_cnt; sample_block_values_type s_ptr; double z1; double z2; double b0; double b1; double b2; double a1; double a2; } biquadfilt_susp_node, *biquadfilt_susp_type; void biquadfilt_n_fetch(register biquadfilt_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double z1_reg; register double z2_reg; register double b0_reg; register double b1_reg; register double b2_reg; register double a1_reg; register double a2_reg; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "biquadfilt_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; z1_reg = susp->z1; z2_reg = susp->z2; b0_reg = susp->b0; b1_reg = susp->b1; b2_reg = susp->b2; a1_reg = susp->a1; a2_reg = susp->a2; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; z0 = *s_ptr_reg++ + a1_reg*z1_reg + a2_reg*z2_reg; *out_ptr_reg++ = (sample_type) (z0*b0_reg + z1_reg*b1_reg + z2_reg*b2_reg); z2_reg = z1_reg; z1_reg = z0;; } while (--n); /* inner loop */ susp->z1 = z1_reg; susp->z2 = z2_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* biquadfilt_n_fetch */ void biquadfilt_s_fetch(register biquadfilt_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double z1_reg; register double z2_reg; register double b0_reg; register double b1_reg; register double b2_reg; register double a1_reg; register double a2_reg; register sample_type s_scale_reg = susp->s->scale; register sample_block_values_type s_ptr_reg; falloc_sample_block(out, "biquadfilt_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s input sample block: */ susp_check_term_log_samples(s, s_ptr, s_cnt); togo = min(togo, susp->s_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; z1_reg = susp->z1; z2_reg = susp->z2; b0_reg = susp->b0; b1_reg = susp->b1; b2_reg = susp->b2; a1_reg = susp->a1; a2_reg = susp->a2; s_ptr_reg = susp->s_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double z0; z0 = (s_scale_reg * *s_ptr_reg++) + a1_reg*z1_reg + a2_reg*z2_reg; *out_ptr_reg++ = (sample_type) (z0*b0_reg + z1_reg*b1_reg + z2_reg*b2_reg); z2_reg = z1_reg; z1_reg = z0;; } while (--n); /* inner loop */ susp->z1 = z1_reg; susp->z2 = z2_reg; /* using s_ptr_reg is a bad idea on RS/6000: */ susp->s_ptr += togo; out_ptr += togo; susp_took(s_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* biquadfilt_s_fetch */ void biquadfilt_toss_fetch(susp, snd_list) register biquadfilt_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s up to final_time for this block of zeros */ while ((round((final_time - susp->s->t0) * susp->s->sr)) >= susp->s->current) susp_get_samples(s, s_ptr, s_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s->t0) * susp->s->sr - (susp->s->current - susp->s_cnt)); susp->s_ptr += n; susp_took(s_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void biquadfilt_mark(biquadfilt_susp_type susp) { sound_xlmark(susp->s); } void biquadfilt_free(biquadfilt_susp_type susp) { sound_unref(susp->s); ffree_generic(susp, sizeof(biquadfilt_susp_node), "biquadfilt_free"); } void biquadfilt_print_tree(biquadfilt_susp_type susp, int n) { indent(n); stdputstr("s:"); sound_print_tree_1(susp->s, n); } sound_type snd_make_biquadfilt(sound_type s, double b0, double b1, double b2, double a1, double a2, double z1init, double z2init) { register biquadfilt_susp_type susp; rate_type sr = s->sr; time_type t0 = s->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, biquadfilt_susp_node, "snd_make_biquadfilt"); susp->z1 = z1init; susp->z2 = z2init; susp->b0 = b0; susp->b1 = b1; susp->b2 = b2; susp->a1 = a1; susp->a2 = a2; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = biquadfilt_n_fetch; break; case INTERP_s: susp->susp.fetch = biquadfilt_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s->t0) sound_prepend_zeros(s, t0); /* minimum start time over all inputs: */ t0_min = min(s->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = biquadfilt_toss_fetch; } /* initialize susp state */ susp->susp.free = biquadfilt_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = biquadfilt_mark; susp->susp.print_tree = biquadfilt_print_tree; susp->susp.name = "biquadfilt"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s); susp->susp.current = 0; susp->s = s; susp->s_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_biquadfilt(sound_type s, double b0, double b1, double b2, double a1, double a2, double z1init, double z2init) { sound_type s_copy = sound_copy(s); return snd_make_biquadfilt(s_copy, b0, b1, b2, a1, a2, z1init, z2init); } nyquist-3.05/tran/pluck.c0000644000175000000620000001643011466723256014431 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "pluck.h" void pluck_free(); typedef struct pluck_susp_struct { snd_susp_node susp; long terminate_cnt; double stretch; double cons; double loss; long len; double x2; double x3; sample_type *shiftreg; sample_type *i1; sample_type *i2; sample_type *i3; sample_type *i4; sample_type *endptr; } pluck_susp_node, *pluck_susp_type; #define MAXLENGTH 20000 long pluck_parameters(double hz, double sr, double final, double dur, double *stretch, double *cons, double *rho) { double t = PI * (hz / sr); double y = fabs(cos(t)); /* original m4c code used ratio of initial amp to final amp in dB and then converted to a ratio, e.g. you specify 60 and the parameter Final is 1000.0. This is counterintuitive to me (RBD) because I would expect the value to be -60dB or 0.001. That is what I implemented, so to get this back into correspondence with the m4c algorithm, I take the NEGATIVE log to get lf, whereas m4c takes the positive log: */ double lf = -log(final); double tdecay = -lf / (hz * log(y)); double st; long len; double x; if (hz <= sr / MAXLENGTH) { xlfail("pluck hz is too low"); } else if (hz >= sr / 3) { xlfail("pluck hz is too high"); } /* * if desired decay time is shorter than the natural decay time, * then introduce a loss factor. Otherwise, stretch note out. */ st = hz * dur; if (dur < tdecay) { *rho = exp(-lf / st) / y; *stretch = 0.5; } else { *rho = 1; *stretch = 0.5 + sqrt(0.25 - (1 - exp(2 * lf * (hz - sr) / (st * sr))) / (2 - 2 * cos(2 * t))); } /* delay line length is */ len = (int) ((sr / hz) - *stretch - 0.001); /* tuning constant is */ x = (sr / hz) - len - *stretch; *cons = (1.0 - x) / (1.0 + x); if (len <= 1) { xlfail("internal error: pluck delay line length too short"); } return len; } static unsigned int rnext = 1; int krand() { rnext = rnext * 1103515245 + 12345; return (rnext >> 16) & 0x7fff; } void pluck_initialize(sample_type *shiftreg, sample_type *array, long len, double cons) { sample_type suma = 0.0F; long k; sample_type avea; array[1] = 0; for (k = len; k > 0; k--, array--) { /* note: the m4c code has a bug. It claims to filter the initial values, but it really just sets the values to +1 or -1. The following does the same thing with much less code: */ *array = (krand() & 2) - 1; suma += *array; /* compute sum for the average */ } avea = suma / len; /* zero the average */ for (k = 0; k <= len + 1; k++) shiftreg[k] -= avea; shiftreg[len] = 0; shiftreg[len + 1] = 0; } void pluck__fetch(register pluck_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double stretch_reg; register double cons_reg; register double loss_reg; register double x2_reg; register double x3_reg; register sample_type * i1_reg; register sample_type * i2_reg; register sample_type * i3_reg; register sample_type * i4_reg; register sample_type * endptr_reg; falloc_sample_block(out, "pluck__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; stretch_reg = susp->stretch; cons_reg = susp->cons; loss_reg = susp->loss; x2_reg = susp->x2; x3_reg = susp->x3; i1_reg = susp->i1; i2_reg = susp->i2; i3_reg = susp->i3; i4_reg = susp->i4; endptr_reg = susp->endptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ sample_type sum = (sample_type) ((*i1_reg++ * x2_reg) + (*i2_reg++ * x3_reg) + (*i3_reg++ * stretch_reg) - (*i4_reg++ * cons_reg)); /* wrap pointers around shift register if necessary */ if (i1_reg == endptr_reg) i1_reg = susp->shiftreg; if (i2_reg == endptr_reg) i2_reg = susp->shiftreg; if (i3_reg == endptr_reg) i3_reg = susp->shiftreg; if (i4_reg == endptr_reg) i4_reg = susp->shiftreg; /* store new value in shift register */ *i4_reg = (sample_type) (sum * loss_reg); /* deliver sample */ *out_ptr_reg++ = sum; ; } while (--n); /* inner loop */ susp->i1 = i1_reg; susp->i2 = i2_reg; susp->i3 = i3_reg; susp->i4 = i4_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* pluck__fetch */ void pluck_free(pluck_susp_type susp) { free(susp->shiftreg); ffree_generic(susp, sizeof(pluck_susp_node), "pluck_free"); } void pluck_print_tree(pluck_susp_type susp, int n) { } sound_type snd_make_pluck(rate_type sr, double hz, time_type t0, time_type d, double final_amp) { register pluck_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, pluck_susp_node, "snd_make_pluck"); susp->stretch = 0; susp->cons = 0; susp->loss = 0; susp->len = pluck_parameters(hz, sr, final_amp, d, &susp->stretch, &susp->cons, &susp->loss); susp->x2 = -susp->cons * (susp->stretch - 1); susp->x3 = susp->cons * susp->stretch - susp->stretch + 1; susp->shiftreg = (sample_type *) calloc (susp->len + 4, sizeof(sample_type)); susp->i1 = susp->shiftreg + susp->len + 1; susp->i2 = susp->shiftreg + susp->len; susp->i3 = susp->shiftreg + susp->len - 1; susp->i4 = susp->shiftreg + susp->len - 2; susp->endptr = susp->shiftreg + susp->len + 2; pluck_initialize(susp->shiftreg, susp->i3, susp->len, susp->cons); susp->susp.fetch = pluck__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = pluck_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = pluck_print_tree; susp->susp.name = "pluck"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_pluck(rate_type sr, double hz, time_type t0, time_type d, double final_amp) { return snd_make_pluck(sr, hz, t0, d, final_amp); } nyquist-3.05/tran/pwl.h0000644000175000000620000000024510144436365014111 0ustar stevestaffsound_type snd_make_pwl(time_type t0, rate_type sr, LVAL lis); sound_type snd_pwl(time_type t0, rate_type sr, LVAL lis); /* LISP: (snd-pwl ANYNUM ANYNUM ANY) */ nyquist-3.05/tran/instrflutefreq.alg0000644000175000000620000000161311466723256016706 0ustar stevestaff(INSTRFLUTE-FREQ--ALG (NAME "flute_freq") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("sound_type" "freq_env") ("rate_type" "sr")) (STATE ("struct instr *" "myflute" "initInstrument(FLUTE, round(sr)); controlChange(susp->myflute, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->myflute, freq, 1.0)") ("double" "frequency" "freq")) (START (min breath_env)) (NOT-IN-INNER-LOOP "temp_ret_value") (CONSTANT "frequency") (SAMPLE-RATE "sr") (MATCHED-SAMPLE-RATE freq_env breath_env) (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(myflute, 128, FLUTE_CONTROL_CHANGE_CONST * breath_env); setFrequency(myflute, frequency + freq_env); output = (sample_type) tick(myflute)") (SUPPORT-HEADER " #define FLUTE_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->myflute); ") ) nyquist-3.05/tran/offset.h0000644000175000000620000000023110144436365014570 0ustar stevestaffsound_type snd_make_offset(sound_type s1, double offset); sound_type snd_offset(sound_type s1, double offset); /* LISP: (snd-offset SOUND ANYNUM) */ nyquist-3.05/tran/alpassvv.alg0000644000175000000620000000532110144436365015462 0ustar stevestaff(ALPASSVC-ALG ;; ;; delay is variable -- but we don't want to reallocate the delay buffer, so ;; use an additional parameter for the maximum allowable delay. The sound will ;; be written into the buffer every sample, but read using linear ;; interpolation. As in tapv, duplicate the sample at the first and last ;; locations in the buffer. ;; (NAME "alpassvv") (ARGUMENTS ("sound_type" "input") ("sound_type" "delaysnd") ("sound_type" "feedback") ("double" "maxdelay")) (START (MAX input delaysnd)) (STATE ("float" "delay_scale_factor" "(float) (input->sr * delaysnd->scale)") ("long" "buflen" "max(2, (long) (input->sr * maxdelay + 2.5))") ("sample_type *" "delaybuf" "(sample_type *) calloc (susp->buflen + 1, sizeof(sample_type))") ("sample_type *" "delayptr" "susp->delaybuf") ;; since we allocate one extra sample, endptr points to the last sample ("sample_type *" "endptr" "susp->delaybuf + susp->buflen")) (CONSTANT "delaylen" "endptr" "delay_scale_factor") (NOT-REGISTER delaybuf) (LINEAR input) (TERMINATE (MIN input)) (INNER-LOOP-LOCALS " register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr;\n") (INNER-LOOP " /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ register sample_type fb = feedback; delaysamp = delaysnd * delay_scale_factor; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr + buflen - (delayi + 1); if (yptr >= endptr) yptr -= buflen; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr++ = z = (sample_type) (fb * y + input); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr > endptr) { delayptr = susp->delaybuf; *delayptr++ = *endptr; } output = (sample_type) (y - fb * z);") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/amosc.h0000644000175000000620000000050610144436365014411 0ustar stevestaffsound_type snd_make_amosc(sound_type input, double step, rate_type sr, double hz, time_type t0, sound_type amod, double phase); sound_type snd_amosc(sound_type input, double step, rate_type sr, double hz, time_type t0, sound_type amod, double phase); /* LISP: (snd-amosc SOUND ANYNUM ANYNUM ANYNUM ANYNUM SOUND ANYNUM) */ nyquist-3.05/tran/siosc.c0000644000175000000620000004725511466723256014444 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "siosc.h" void siosc_free(); typedef struct siosc_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s_fm; long s_fm_cnt; sample_block_values_type s_fm_ptr; /* support for interpolation of s_fm */ sample_type s_fm_x1_sample; double s_fm_pHaSe; double s_fm_pHaSe_iNcR; /* support for ramp between samples of s_fm */ double output_per_s_fm; long s_fm_n; double table_len; double ph_incr; table_type table_a_ptr; table_type table_b_ptr_ptr; sample_type *table_a_samps; sample_type *table_b_samps; double table_sr; double phase; LVAL lis; long next_breakpoint; double ampramp_a; double ampramp_b; double ampslope; } siosc_susp_node, *siosc_susp_type; /* sisosc_table_init -- set up first two tables for interpolation */ /**/ void siosc_table_init(siosc_susp_type susp) { sound_type snd; if (!susp->lis) xlfail("bad table list in SIOSC"); snd = getsound(car(susp->lis)); susp->table_b_ptr_ptr = sound_to_table(snd); susp->table_b_samps = susp->table_b_ptr_ptr->samples; susp->lis = cdr(susp->lis); susp->table_sr = snd->sr; susp->table_len = susp->table_b_ptr_ptr->length; } /* siosc_table_update -- outer loop processing, get next table */ /**/ long siosc_table_update(siosc_susp_type susp, long cur) { long n; /* swap ampramps: */ susp->ampramp_a = 1.0; susp->ampramp_b = 0.0; /* swap tables: */ table_unref(susp->table_a_ptr); susp->table_a_ptr = susp->table_b_ptr_ptr; susp->table_a_samps = susp->table_b_samps; susp->table_b_ptr_ptr = NULL; /* so we do not try to unref it */ if (susp->lis) { sound_type snd; /* compute slope */ susp->next_breakpoint = getfixnum(car(susp->lis)); susp->lis = cdr(susp->lis); n = susp->next_breakpoint - cur; susp->ampslope = 1.0 / n; /* build new table: */ if (!susp->lis) xlfail("bad table list in SIOSC"); snd = getsound(car(susp->lis)); susp->table_b_ptr_ptr = sound_to_table(snd); susp->table_b_samps = susp->table_b_ptr_ptr->samples; if (susp->table_b_ptr_ptr->length != susp->table_len || susp->table_sr != snd->sr) xlfail("mismatched tables passed to SIOSC") ; susp->lis = cdr(susp->lis); } else { /* use only table a */ susp->ampslope = 0.0; susp->next_breakpoint = 0x7FFFFFFF; n = 0x7FFFFFFF; } return n; } void siosc_s_fetch(register siosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double table_len_reg; register double ph_incr_reg; register sample_type * table_a_samps_reg; register sample_type * table_b_samps_reg; register double phase_reg; register double ampramp_a_reg; register double ampramp_b_reg; register double ampslope_reg; register sample_type s_fm_scale_reg = susp->s_fm->scale; register sample_block_values_type s_fm_ptr_reg; falloc_sample_block(out, "siosc_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s_fm input sample block: */ susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); togo = min(togo, susp->s_fm_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } { long cur = susp->susp.current + cnt; n = susp->next_breakpoint - cur; if (n == 0) n = siosc_table_update(susp, cur); } togo = min(n, togo); n = togo; table_len_reg = susp->table_len; ph_incr_reg = susp->ph_incr; table_a_samps_reg = susp->table_a_samps; table_b_samps_reg = susp->table_b_samps; phase_reg = susp->phase; ampramp_a_reg = susp->ampramp_a; ampramp_b_reg = susp->ampramp_b; ampslope_reg = susp->ampslope; s_fm_ptr_reg = susp->s_fm_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double xa, xb; table_index = (long) phase_reg; xa = table_a_samps_reg[table_index]; xb = table_b_samps_reg[table_index]; *out_ptr_reg++ = (sample_type) (ampramp_a_reg * (xa + (phase_reg - table_index) * (table_a_samps_reg[table_index + 1] - xa)) + ampramp_b_reg * (xb + (phase_reg - table_index) * (table_b_samps_reg[table_index + 1] - xb))); ampramp_a_reg -= ampslope_reg; ampramp_b_reg += ampslope_reg; phase_reg += ph_incr_reg + (s_fm_scale_reg * *s_fm_ptr_reg++); while (phase_reg > table_len_reg) phase_reg -= table_len_reg; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += table_len_reg; } while (--n); /* inner loop */ susp->phase = phase_reg; susp->ampramp_a = ampramp_a_reg; susp->ampramp_b = ampramp_b_reg; /* using s_fm_ptr_reg is a bad idea on RS/6000: */ susp->s_fm_ptr += togo; out_ptr += togo; susp_took(s_fm_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* siosc_s_fetch */ void siosc_i_fetch(register siosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double table_len_reg; register double ph_incr_reg; register sample_type * table_a_samps_reg; register sample_type * table_b_samps_reg; register double phase_reg; register double ampramp_a_reg; register double ampramp_b_reg; register double ampslope_reg; register double s_fm_pHaSe_iNcR_rEg = susp->s_fm_pHaSe_iNcR; register double s_fm_pHaSe_ReG; register sample_type s_fm_x1_sample_reg; falloc_sample_block(out, "siosc_i_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } { long cur = susp->susp.current + cnt; n = susp->next_breakpoint - cur; if (n == 0) n = siosc_table_update(susp, cur); } togo = min(n, togo); n = togo; table_len_reg = susp->table_len; ph_incr_reg = susp->ph_incr; table_a_samps_reg = susp->table_a_samps; table_b_samps_reg = susp->table_b_samps; phase_reg = susp->phase; ampramp_a_reg = susp->ampramp_a; ampramp_b_reg = susp->ampramp_b; ampslope_reg = susp->ampslope; s_fm_pHaSe_ReG = susp->s_fm_pHaSe; s_fm_x1_sample_reg = susp->s_fm_x1_sample; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double xa, xb; if (s_fm_pHaSe_ReG >= 1.0) { /* fixup-depends s_fm */ /* pick up next sample as s_fm_x1_sample: */ susp->s_fm_ptr++; susp_took(s_fm_cnt, 1); s_fm_pHaSe_ReG -= 1.0; susp_check_term_log_samples_break(s_fm, s_fm_ptr, s_fm_cnt, s_fm_x1_sample_reg); s_fm_x1_sample_reg = susp_current_sample(s_fm, s_fm_ptr); } table_index = (long) phase_reg; xa = table_a_samps_reg[table_index]; xb = table_b_samps_reg[table_index]; *out_ptr_reg++ = (sample_type) (ampramp_a_reg * (xa + (phase_reg - table_index) * (table_a_samps_reg[table_index + 1] - xa)) + ampramp_b_reg * (xb + (phase_reg - table_index) * (table_b_samps_reg[table_index + 1] - xb))); ampramp_a_reg -= ampslope_reg; ampramp_b_reg += ampslope_reg; phase_reg += ph_incr_reg + s_fm_x1_sample_reg; while (phase_reg > table_len_reg) phase_reg -= table_len_reg; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += table_len_reg; s_fm_pHaSe_ReG += s_fm_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->phase = phase_reg; susp->ampramp_a = ampramp_a_reg; susp->ampramp_b = ampramp_b_reg; susp->s_fm_pHaSe = s_fm_pHaSe_ReG; susp->s_fm_x1_sample = s_fm_x1_sample_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* siosc_i_fetch */ void siosc_r_fetch(register siosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type s_fm_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double table_len_reg; register double ph_incr_reg; register sample_type * table_a_samps_reg; register sample_type * table_b_samps_reg; register double phase_reg; register double ampramp_a_reg; register double ampramp_b_reg; register double ampslope_reg; falloc_sample_block(out, "siosc_r_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->s_fm_pHaSe = 1.0; } susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* grab next s_fm_x1_sample when phase goes past 1.0; */ /* use s_fm_n (computed below) to avoid roundoff errors: */ if (susp->s_fm_n <= 0) { susp_check_term_log_samples(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_x1_sample = susp_fetch_sample(s_fm, s_fm_ptr, s_fm_cnt); susp->s_fm_pHaSe -= 1.0; /* s_fm_n gets number of samples before phase exceeds 1.0: */ susp->s_fm_n = (long) ((1.0 - susp->s_fm_pHaSe) * susp->output_per_s_fm); } togo = min(togo, susp->s_fm_n); s_fm_val = susp->s_fm_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } { long cur = susp->susp.current + cnt; n = susp->next_breakpoint - cur; if (n == 0) n = siosc_table_update(susp, cur); } togo = min(n, togo); n = togo; table_len_reg = susp->table_len; ph_incr_reg = susp->ph_incr; table_a_samps_reg = susp->table_a_samps; table_b_samps_reg = susp->table_b_samps; phase_reg = susp->phase; ampramp_a_reg = susp->ampramp_a; ampramp_b_reg = susp->ampramp_b; ampslope_reg = susp->ampslope; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index; double xa, xb; table_index = (long) phase_reg; xa = table_a_samps_reg[table_index]; xb = table_b_samps_reg[table_index]; *out_ptr_reg++ = (sample_type) (ampramp_a_reg * (xa + (phase_reg - table_index) * (table_a_samps_reg[table_index + 1] - xa)) + ampramp_b_reg * (xb + (phase_reg - table_index) * (table_b_samps_reg[table_index + 1] - xb))); ampramp_a_reg -= ampslope_reg; ampramp_b_reg += ampslope_reg; phase_reg += ph_incr_reg + s_fm_val; while (phase_reg > table_len_reg) phase_reg -= table_len_reg; /* watch out for negative frequencies! */ while (phase_reg < 0) phase_reg += table_len_reg; } while (--n); /* inner loop */ susp->phase = phase_reg; susp->ampramp_a = ampramp_a_reg; susp->ampramp_b = ampramp_b_reg; out_ptr += togo; susp->s_fm_pHaSe += togo * susp->s_fm_pHaSe_iNcR; susp->s_fm_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* siosc_r_fetch */ void siosc_toss_fetch(susp, snd_list) register siosc_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s_fm up to final_time for this block of zeros */ while ((round((final_time - susp->s_fm->t0) * susp->s_fm->sr)) >= susp->s_fm->current) susp_get_samples(s_fm, s_fm_ptr, s_fm_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s_fm->t0) * susp->s_fm->sr - (susp->s_fm->current - susp->s_fm_cnt)); susp->s_fm_ptr += n; susp_took(s_fm_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void siosc_mark(siosc_susp_type susp) { if (susp->lis) mark(susp->lis); sound_xlmark(susp->s_fm); } void siosc_free(siosc_susp_type susp) { table_unref(susp->table_a_ptr); table_unref(susp->table_b_ptr_ptr); sound_unref(susp->s_fm); ffree_generic(susp, sizeof(siosc_susp_node), "siosc_free"); } void siosc_print_tree(siosc_susp_type susp, int n) { indent(n); stdputstr("s_fm:"); sound_print_tree_1(susp->s_fm, n); } sound_type snd_make_siosc(LVAL lis, rate_type sr, double hz, time_type t0, sound_type s_fm) { register siosc_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, siosc_susp_node, "snd_make_siosc"); susp->table_len = 0.0; susp->ph_incr = 0.0; susp->table_a_ptr = NULL; susp->table_b_ptr_ptr = NULL; susp->table_a_samps = NULL; susp->table_b_samps = NULL; susp->table_sr = 0.0; susp->phase = 0.0; susp->lis = lis; susp->next_breakpoint = 0; susp->ampramp_a = 1.0; susp->ampramp_b = 0.0; susp->ampslope = 0.0; siosc_table_init(susp); susp->ph_incr = hz * susp->table_len / sr; s_fm->scale = (sample_type) (s_fm->scale * (susp->table_len / sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s_fm, sr); switch (interp_desc) { case INTERP_n: /* handled below */ case INTERP_s: susp->susp.fetch = siosc_s_fetch; break; case INTERP_i: susp->susp.fetch = siosc_i_fetch; break; case INTERP_r: susp->susp.fetch = siosc_r_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s_fm->t0) sound_prepend_zeros(s_fm, t0); /* minimum start time over all inputs: */ t0_min = min(s_fm->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = siosc_toss_fetch; } /* initialize susp state */ susp->susp.free = siosc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = siosc_mark; susp->susp.print_tree = siosc_print_tree; susp->susp.name = "siosc"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s_fm); susp->started = false; susp->susp.current = 0; susp->s_fm = s_fm; susp->s_fm_cnt = 0; susp->s_fm_pHaSe = 0.0; susp->s_fm_pHaSe_iNcR = s_fm->sr / sr; susp->s_fm_n = 0; susp->output_per_s_fm = sr / s_fm->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_siosc(LVAL lis, rate_type sr, double hz, time_type t0, sound_type s_fm) { sound_type s_fm_copy = sound_copy(s_fm); return snd_make_siosc(lis, sr, hz, t0, s_fm_copy); } nyquist-3.05/tran/recip.c0000644000175000000620000001250211466723256014411 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "recip.h" void recip_free(); typedef struct recip_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; double scale; } recip_susp_node, *recip_susp_type; void recip_n_fetch(register recip_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "recip_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale_reg = susp->scale; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (scale_reg / *s1_ptr_reg++); } while (--n); /* inner loop */ /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* recip_n_fetch */ void recip_toss_fetch(susp, snd_list) register recip_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void recip_mark(recip_susp_type susp) { sound_xlmark(susp->s1); } void recip_free(recip_susp_type susp) { sound_unref(susp->s1); ffree_generic(susp, sizeof(recip_susp_node), "recip_free"); } void recip_print_tree(recip_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_recip(sound_type s1) { register recip_susp_type susp; rate_type sr = s1->sr; time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, recip_susp_node, "snd_make_recip"); susp->scale = 1.0 / s1->scale; susp->susp.fetch = recip_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = recip_toss_fetch; } /* initialize susp state */ susp->susp.free = recip_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = recip_mark; susp->susp.print_tree = recip_print_tree; susp->susp.name = "recip"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_recip(sound_type s1) { sound_type s1_copy = sound_copy(s1); return snd_make_recip(s1_copy); } nyquist-3.05/tran/downproto.alg0000644000175000000620000000060610144436365015657 0ustar stevestaff(DOWNSAMPLE-PROTO-ALG (NAME "down") (ARGUMENTS ("rate_type" "sr") ("sound_type" "s")) (SAMPLE-RATE "sr") (START (MIN s)) (INLINE-INTERPOLATION T) (STATE ) (INNER-LOOP "output = s") (TERMINATE (MIN s)) (LOGICAL-STOP (MIN s)) (TYPE-CHECK " if (s->sr < sr) { sound_unref(s); xlfail(\"snd-down: output sample rate must be lower than input\"); } ") ) nyquist-3.05/tran/amosc.c0000644000175000000620000001516410144436365014412 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "amosc.h" void amosc_free(); typedef struct amosc_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type amod; long amod_cnt; sample_block_values_type amod_ptr; double ph_incr; table_type the_table; sample_type *table_ptr; double table_len; double phase; } amosc_susp_node, *amosc_susp_type; void amosc_s_fetch(register amosc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double ph_incr_reg; register sample_type * table_ptr_reg; register double table_len_reg; register double phase_reg; register sample_type amod_scale_reg = susp->amod->scale; register sample_block_values_type amod_ptr_reg; falloc_sample_block(out, "amosc_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the amod input sample block: */ susp_check_term_log_samples(amod, amod_ptr, amod_cnt); togo = min(togo, susp->amod_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; ph_incr_reg = susp->ph_incr; table_ptr_reg = susp->table_ptr; table_len_reg = susp->table_len; phase_reg = susp->phase; amod_ptr_reg = susp->amod_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ long table_index = (long) phase_reg; double x1 = (double) (table_ptr_reg[table_index]); *out_ptr_reg++ = (sample_type) (x1 + (phase_reg - table_index) * (table_ptr_reg[table_index + 1] - x1)) * (amod_scale_reg * *amod_ptr_reg++); phase_reg += ph_incr_reg; while (phase_reg > table_len_reg) phase_reg -= table_len_reg; ; } while (--n); /* inner loop */ susp->phase = phase_reg; /* using amod_ptr_reg is a bad idea on RS/6000: */ susp->amod_ptr += togo; out_ptr += togo; susp_took(amod_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* amosc_s_fetch */ void amosc_toss_fetch(susp, snd_list) register amosc_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from amod up to final_time for this block of zeros */ while ((round((final_time - susp->amod->t0) * susp->amod->sr)) >= susp->amod->current) susp_get_samples(amod, amod_ptr, amod_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->amod->t0) * susp->amod->sr - (susp->amod->current - susp->amod_cnt)); susp->amod_ptr += n; susp_took(amod_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void amosc_mark(amosc_susp_type susp) { sound_xlmark(susp->amod); } void amosc_free(amosc_susp_type susp) { table_unref(susp->the_table); sound_unref(susp->amod); ffree_generic(susp, sizeof(amosc_susp_node), "amosc_free"); } void amosc_print_tree(amosc_susp_type susp, int n) { indent(n); stdputstr("amod:"); sound_print_tree_1(susp->amod, n); } sound_type snd_make_amosc(sound_type input, double step, rate_type sr, double hz, time_type t0, sound_type amod, double phase) { register amosc_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, amosc_susp_node, "snd_make_amosc"); susp->ph_incr = 0; susp->the_table = sound_to_table(input); susp->table_ptr = susp->the_table->samples; susp->table_len = susp->the_table->length; susp->phase = compute_phase(phase, step, (long) susp->table_len, input->sr, sr, hz, &susp->ph_incr); susp->susp.fetch = amosc_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < amod->t0) sound_prepend_zeros(amod, t0); /* minimum start time over all inputs: */ t0_min = min(amod->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = amosc_toss_fetch; } /* initialize susp state */ susp->susp.free = amosc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = amosc_mark; susp->susp.print_tree = amosc_print_tree; susp->susp.name = "amosc"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(amod); susp->susp.current = 0; susp->amod = amod; susp->amod_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_amosc(sound_type input, double step, rate_type sr, double hz, time_type t0, sound_type amod, double phase) { sound_type amod_copy = sound_copy(amod); return snd_make_amosc(input, step, sr, hz, t0, amod_copy, phase); } nyquist-3.05/tran/log.c0000644000175000000620000001255110144436365014066 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "log.h" void log_free(); typedef struct log_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; } log_susp_node, *log_susp_type; void log_s_fetch(register log_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type input_scale_reg = susp->input->scale; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "log_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) log((input_scale_reg * *input_ptr_reg++)); } while (--n); /* inner loop */ /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* log_s_fetch */ void log_toss_fetch(susp, snd_list) register log_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void log_mark(log_susp_type susp) { sound_xlmark(susp->input); } void log_free(log_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(log_susp_node), "log_free"); } void log_print_tree(log_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_log(sound_type input) { register log_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, log_susp_node, "snd_make_log"); susp->susp.fetch = log_s_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = log_toss_fetch; } /* initialize susp state */ susp->susp.free = log_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = log_mark; susp->susp.print_tree = log_print_tree; susp->susp.name = "log"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_log(sound_type input) { sound_type input_copy = sound_copy(input); return snd_make_log(input_copy); } nyquist-3.05/tran/prod.h0000644000175000000620000000022210144436365014246 0ustar stevestaffsound_type snd_make_prod(sound_type s1, sound_type s2); sound_type snd_prod(sound_type s1, sound_type s2); /* LISP: (snd-prod SOUND SOUND) */ nyquist-3.05/tran/follow.alg0000644000175000000620000001133710144436365015131 0ustar stevestaff(FOLLOW-ALG (NAME "follow") (SUPPORT-FUNCTIONS "/* Description: this is a sophisticated envelope follower. The input is an envelope, e.g. something produced with the AVG function. The purpose of this function is to generate a smooth envelope that is generally not less than the input signal. In other words, we want to \"ride\" the peaks of the signal with a smooth function. The algorithm is as follows: keep a current output value (called the \"value\"). The value is allowed to increase by at most rise_factor and decrease by at most fall_factor. Therefore, the next value should be between value * rise_factor and value * fall_factor. If the input is in this range, then the next value is simply the input. If the input is less than value * fall_factor, then the next value is just value * fall_factor, which will be greater than the input signal. If the input is greater than value * rise_factor, then we compute a rising envelope that meets the input value by working bacwards in time, changing the previous values to input / rise_factor, input / rise_factor^2, input / rise_factor^3, etc. until this new envelope intersects the previously computed values. There is only a limited buffer in which we can work backwards, so if the new envelope does not intersect the old one, then make yet another pass, this time from the oldest buffered value forward, increasing on each sample by rise_factor to produce a maximal envelope. This will still be less than the input. The value has a lower limit of floor to make sure value has a reasonable positive value from which to begin an attack. Because this algorithm can make 2 passes through the buffer on sharply rising input signals, it is not particularly fast. The assumption is that it operates on fairly short buffers at low sample rates appropriate for gain control, so this should not matter. */ static sample_type *create_buf(double floor, long lookahead) { sample_type *buf = (sample_type *) malloc(lookahead * sizeof(sample_type)); int i; for (i = 0; i < lookahead; i++) buf[i] = (sample_type) floor; return buf; } ") (ARGUMENTS ("sound_type" "sndin") ("double" "floor") ("double" "risetime") ("double" "falltime") ("long" "lookahead")) (START (MIN sndin)) (STATE ("long" "lookahead" "lookahead = lookahead + 1") ("sample_type *" "delaybuf" "create_buf(floor, lookahead)") ("sample_type *" "delayptr" "susp->delaybuf") ("sample_type *" "prevptr" "susp->delaybuf + lookahead - 1; *(susp->prevptr) = (sample_type) floor;") ("sample_type *" "endptr" "susp->delaybuf + lookahead") ("double" "floor" "floor; floor = log(floor);") ("double" "rise_factor" "exp(- floor / (sndin->sr * risetime + 0.5))") ("double" "fall_factor" "exp(floor / (sndin->sr * falltime + 0.5))") ("double" "value" "susp->floor")) (CONSTANT "feedback" "rise_factor" "fall_factor" "endptr") (NOT-REGISTER delaybuf) (ALWAYS-SCALE sndin) (TERMINATE (MIN sndin)) (INNER-LOOP " sample_type current = sndin; sample_type high = (sample_type) (*prevptr * rise_factor); sample_type low = (sample_type) (*prevptr * fall_factor); if (low < floor) low = (sample_type) floor; if (current < low) *delayptr = (sample_type) low; else if (current < high) *delayptr = current; else /* current > high */ { /* work back from current */ double rise_inverse = 1.0 / rise_factor; double temp = current * rise_inverse; boolean ok = false; sample_type *ptr = prevptr; int i; for (i = 0; i < lookahead - 2; i++) { if (*ptr < temp) { *ptr-- = (sample_type) temp; temp *= rise_inverse; if (ptr < susp->delaybuf) ptr = endptr - 1; } else { ok = true; break; } } if (!ok && (*ptr < temp)) { temp = *ptr; for (i = 0; i < lookahead - 1; i++) { ptr++; if (ptr == endptr) ptr = susp->delaybuf; temp *= rise_factor; *ptr = (sample_type) temp; } } else *delayptr = current; } prevptr = delayptr++; if (delayptr == endptr) delayptr = susp->delaybuf; output = *delayptr;") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/instrclarfreq.alg0000644000175000000620000000157210144436365016506 0ustar stevestaff(INSTRCLAR-FREQ-ALG (NAME "clarinet_freq") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("sound_type" "freq_env") ("rate_type" "sr")) (STATE ("struct instr *" "clar" "initInstrument(CLARINET, round(sr)); controlChange(susp->clar, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->clar, freq, 1.0)") ("double" "frequency" "freq")) (START (min breath_env)) (NOT-IN-INNER-LOOP "temp_ret_value") (CONSTANT "frequency") (SAMPLE-RATE "sr") (MATCHED-SAMPLE-RATE freq_env breath_env) (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(clar, 128, CLAR_CONTROL_CHANGE_CONST * breath_env); setFrequency(clar, frequency + freq_env); output = (sample_type) tick(clar)") (SUPPORT-HEADER " #define CLAR_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->clar); ") ) nyquist-3.05/tran/lpreson.alg0000644000175000000620000000660110144436365015307 0ustar stevestaff(LPRESON-ALG (NAME "lpreson") (ARGUMENTS ("sound_type" "x_snd")("LVAL" "src")("time_type" "frame_time")) (SUPPORT-FUNCTIONS " #include \"samples.h\" ") (START (MIN x_snd)) (ALWAYS-SCALE x_snd) (TERMINATE (MIN x_snd)) (LOGICAL-STOP (MIN x_snd)) (SAMPLE-RATE "x_snd->sr") (STATE ("long" "fr_indx" "0") ("long" "ak_len" "0") ; length of coefs ak array ("long" "frame_length" "(long) (frame_time*x_snd->sr)") ; samples length ("LVAL" "src" "src") ("LVAL" "frame" "NULL") ("double *" "ak_coefs" "NULL") ; coefs array ("double *" "zk_buf" "NULL") ; last values of output ("double" "gain" "1.0") ("long" "index" "0") ) (OUTER-LOOP " if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->fr_indx >= susp->frame_length) susp->fr_indx -= susp->frame_length; if (susp->fr_indx==0) { long i; susp->frame = xleval(cons(s_send, cons(susp->src, consa(s_next)))); if (susp->frame == NULL) { susp->src = NULL; goto out; /* en susp->frame tenemos la lista proporcionada por el objeto */ } else if (!listp(susp->frame) || !listp(cdr(susp->frame)) || !listp(cdr(cdr(susp->frame))) || !listp(cdr(cdr(cdr(susp->frame))))) { xlerror(\"list expected\", susp->frame); } /* frame is a list: (RMS1 RMS2 ERR FILTER-COEFS) */ /* gain is square root of RMS2 */ susp->gain = sqrt(getflonum(car(cdr(susp->frame)))); /* get filter coefs */ susp->frame=car(cdr(cdr(cdr(susp->frame)))); if (!vectorp(susp->frame)) { xlerror(\"array expected\", susp->frame); } else if (susp->ak_coefs == NULL) { susp->ak_len = getsize(susp->frame); if (susp->ak_len < 1) xlerror(\"array has no elements\", susp->frame); susp->ak_coefs = (double *) calloc(susp->ak_len, sizeof(double)); susp->zk_buf = (double *) calloc(susp->ak_len, sizeof(double)); } /* at this point we have a new array and a place to put ak coefs */ for (i=0; i < susp->ak_len; i++) { LVAL elem = getelement(susp->frame, i); if (ntype(elem) != FLONUM) { xlerror(\"flonum expected\", elem); } susp->ak_coefs[i] = getflonum(elem); } // printf(\"NUEVO FILTRO: \"); /* here for debug */ // for(k=0; k < susp->ak_len; k++) printf(\" %g \", susp->ak_coefs[k]); // printf(\"GAIN %g AKLEN %d \", susp->gain, susp->ak_len); susp->frame = NULL; /* free the array */ } togo = min(susp->frame_length - susp->fr_indx, togo); ") (INNER-LOOP-LOCALS "double z0; long xi; long xj;") (INNER-LOOP " z0 = x_snd * gain; for (xi=0; xi < ak_len; xi++) { xj = index + xi; if (xj >= ak_len) xj -= ak_len; z0 += ak_coefs[xi] * zk_buf[xj]; } zk_buf[index] = z0; index++; if (index == ak_len) index = 0; fr_indx++; output = (sample_type) z0; ") (CONSTANT "frame_length" "src") (FINALIZATION " free(susp->ak_coefs); free(susp->zk_buf); ") ) nyquist-3.05/tran/delaycc.c0000644000175000000620000001266410144436365014716 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "delaycc.h" void delay_free(); typedef struct delay_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type input; long input_cnt; sample_block_values_type input_ptr; double feedback; long delaylen; sample_type *delaybuf; sample_type *delayptr; sample_type *endptr; } delay_susp_node, *delay_susp_type; void delay_n_fetch(register delay_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double feedback_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "delay_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; feedback_reg = susp->feedback; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = *delayptr_reg; *delayptr_reg = (sample_type) (*delayptr_reg * feedback_reg) + *input_ptr_reg++; if (++delayptr_reg >= endptr_reg) delayptr_reg = susp->delaybuf;; } while (--n); /* inner loop */ susp->delayptr = delayptr_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* delay_n_fetch */ void delay_toss_fetch(susp, snd_list) register delay_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void delay_mark(delay_susp_type susp) { sound_xlmark(susp->input); } void delay_free(delay_susp_type susp) { free(susp->delaybuf); sound_unref(susp->input); ffree_generic(susp, sizeof(delay_susp_node), "delay_free"); } void delay_print_tree(delay_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_delay(sound_type input, time_type delay, double feedback) { register delay_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, delay_susp_node, "snd_make_delay"); susp->feedback = feedback; susp->delaylen = max(1, round(input->sr * delay)); susp->delaybuf = (sample_type *) calloc (susp->delaylen, sizeof(sample_type)); susp->delayptr = susp->delaybuf; susp->endptr = susp->delaybuf + susp->delaylen; susp->susp.fetch = delay_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = delay_toss_fetch; } /* initialize susp state */ susp->susp.free = delay_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = delay_mark; susp->susp.print_tree = delay_print_tree; susp->susp.name = "delay"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_delay(sound_type input, time_type delay, double feedback) { sound_type input_copy = sound_copy(input); return snd_make_delay(input_copy, delay, feedback); } nyquist-3.05/tran/alpass.h0000644000175000000620000000031410144436365014567 0ustar stevestaffsound_type snd_make_alpass(sound_type input, time_type delay, double feedback); sound_type snd_alpass(sound_type input, time_type delay, double feedback); /* LISP: (snd-alpass SOUND ANYNUM ANYNUM) */ nyquist-3.05/tran/areson.h0000644000175000000620000000034110144436365014573 0ustar stevestaffsound_type snd_make_areson(sound_type input, double hz, double bw, int normalization); sound_type snd_areson(sound_type input, double hz, double bw, int normalization); /* LISP: (snd-areson SOUND ANYNUM ANYNUM FIXNUM) */ nyquist-3.05/tran/tone.h0000644000175000000620000000022110144436365014246 0ustar stevestaffsound_type snd_make_tone(sound_type input, double hz); sound_type snd_tone(sound_type input, double hz); /* LISP: (snd-tone SOUND ANYNUM) */ nyquist-3.05/tran/delaycv.alg0000644000175000000620000000126110144436365015251 0ustar stevestaff(DELAYCV-ALG (NAME "delaycv") (ARGUMENTS ("sound_type" "s") ("time_type" "delay") ("sound_type" "feedback")) (START (MAX s feedback)) (STATE ("long" "delaylen" "round(s->sr * delay)") ("sample_type *" "delaybuf" "(sample_type *) calloc (sizeof(double), susp->delaylen)") ("sample_type *" "delayptr" "susp->delaybuf") ("sample_type *" "endptr" "susp->delaybuf + susp->delaylen")) (CONSTANT "delaylen" "delaybuf") (NOT-REGISTER delaybuf) (LINEAR s) (TERMINATE (MIN s)) (INNER-LOOP "output = *delayptr; *delayptr = *delayptr * feedback + s; if (++delayptr >= endptr) delayptr = susp->delaybuf;") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/instrmandolin.alg0000644000175000000620000000141311466723256016510 0ustar stevestaff(INSTRMANDOLIN-ALG (NAME "mandolin") (ARGUMENTS ("time_type" "t0")("double" "freq") ("time_type" "d") ("double" "body_size")("double" "detune")("rate_type" "sr")) (STATE ("struct instr *" "mymand" "initInstrument(MANDOLIN, round(sr)); controlChange(susp->mymand, 1, detune); controlChange(susp->mymand, 2, MAND_CONTROL_CHANGE_CONST * body_size);") ("int" "temp_ret_value" "noteOn(susp->mymand, freq, 1.0)")) (NOT-IN-INNER-LOOP "freq" "temp_ret_value" "body_size" "detune") (SAMPLE-RATE "sr") (TERMINATE (after "d")) (INNER-LOOP " output = (sample_type) tick(mymand)") (SUPPORT-HEADER " #define MAND_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->mymand); ") ) nyquist-3.05/tran/aresonvv.c0000644000175000000620000015412210144436365015151 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "aresonvv.h" void aresonvv_free(); typedef struct aresonvv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type hz1; long hz1_cnt; sample_block_values_type hz1_ptr; /* support for interpolation of hz1 */ sample_type hz1_x1_sample; double hz1_pHaSe; double hz1_pHaSe_iNcR; /* support for ramp between samples of hz1 */ double output_per_hz1; long hz1_n; sound_type bw; long bw_cnt; sample_block_values_type bw_ptr; /* support for interpolation of bw */ sample_type bw_x1_sample; double bw_pHaSe; double bw_pHaSe_iNcR; /* support for ramp between samples of bw */ double output_per_bw; long bw_n; double scale1; double c3co; double c3p1; double c3t4; double omc3; double coshz; double c2; double c1; boolean recompute; int normalization; double y1; double y2; } aresonvv_susp_node, *aresonvv_susp_type; void aresonvv_nss_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nss_fetch */ void aresonvv_nsi_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nsi_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nsi_fetch */ void aresonvv_nsr_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type hz1_scale_reg = susp->hz1->scale; register sample_block_values_type hz1_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nsr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz1 input sample block: */ susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); togo = min(togo, susp->hz1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz1_ptr_reg = susp->hz1_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; coshz_reg = cos((hz1_scale_reg * *hz1_ptr_reg++)); recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using hz1_ptr_reg is a bad idea on RS/6000: */ susp->hz1_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nsr_fetch */ void aresonvv_nis_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nis_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nis_fetch */ void aresonvv_nii_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nii_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nii_fetch */ void aresonvv_nir_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double hz1_pHaSe_iNcR_rEg = susp->hz1_pHaSe_iNcR; register double hz1_pHaSe_ReG; register sample_type hz1_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nir_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; hz1_pHaSe_ReG = susp->hz1_pHaSe; hz1_x1_sample_reg = susp->hz1_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (hz1_pHaSe_ReG >= 1.0) { /* fixup-depends hz1 */ /* pick up next sample as hz1_x1_sample: */ susp->hz1_ptr++; susp_took(hz1_cnt, 1); hz1_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz1, hz1_ptr, hz1_cnt, hz1_x1_sample_reg); hz1_x1_sample_reg = susp_current_sample(hz1, hz1_ptr); coshz_reg = susp->coshz = cos(hz1_x1_sample_reg); recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; hz1_pHaSe_ReG += hz1_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->hz1_pHaSe = hz1_pHaSe_ReG; susp->hz1_x1_sample = hz1_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nir_fetch */ void aresonvv_nrs_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nrs_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; c3co_reg = exp((bw_scale_reg * *bw_ptr_reg++)); c3p1_reg = c3co_reg + 1.0; c3t4_reg = c3co_reg * 4.0; omc3_reg = 1.0 - c3co_reg; recompute_reg = true; if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nrs_fetch */ void aresonvv_nri_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c3p1_reg; register double c3t4_reg; register double omc3_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nri_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c3p1_reg = susp->c3p1; c3t4_reg = susp->c3t4; omc3_reg = susp->omc3; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); c3co_reg = susp->c3co = exp(bw_x1_sample_reg); c3p1_reg = susp->c3p1 = c3co_reg + 1.0; c3t4_reg = susp->c3t4 = c3co_reg * 4.0; omc3_reg = susp->omc3 = 1.0 - c3co_reg; recompute_reg = susp->recompute = true; } if (recompute_reg) { recompute_reg = false; c2_reg = c3t4_reg * coshz_reg / c3p1_reg; c1_reg = (normalization_reg == 0 ? 0.0 : (normalization_reg == 1 ? 1.0 - omc3_reg * sqrt(1.0 - c2_reg * c2_reg / c3t4_reg) : 1.0 - sqrt(c3p1_reg * c3p1_reg - c2_reg * c2_reg) * omc3_reg / c3p1_reg)); } current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nri_fetch */ void aresonvv_nrr_fetch(register aresonvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz1_val; sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double c2_reg; register double c1_reg; register boolean recompute_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresonvv_nrr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz1_pHaSe = 1.0; susp->bw_pHaSe = 1.0; } susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz1_x1_sample when phase goes past 1.0; */ /* use hz1_n (computed below) to avoid roundoff errors: */ if (susp->hz1_n <= 0) { susp_check_term_samples(hz1, hz1_ptr, hz1_cnt); susp->hz1_x1_sample = susp_fetch_sample(hz1, hz1_ptr, hz1_cnt); susp->hz1_pHaSe -= 1.0; /* hz1_n gets number of samples before phase exceeds 1.0: */ susp->hz1_n = (long) ((1.0 - susp->hz1_pHaSe) * susp->output_per_hz1); susp->coshz = cos(susp->hz1_x1_sample); susp->recompute = true; } togo = min(togo, susp->hz1_n); hz1_val = susp->hz1_x1_sample; /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); susp->c3co = exp(susp->bw_x1_sample); susp->c3p1 = susp->c3co + 1.0; susp->c3t4 = susp->c3co * 4.0; susp->omc3 = 1.0 - susp->c3co; susp->recompute = true; } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; if (susp->recompute) { susp->recompute = false; susp->c2 = susp->c3t4 * susp->coshz / susp->c3p1; susp->c1 = (susp->normalization == 0 ? 0.0 : (susp->normalization == 1 ? 1.0 - susp->omc3 * sqrt(1.0 - susp->c2 * susp->c2 / susp->c3t4) : 1.0 - sqrt(susp->c3p1 * susp->c3p1 - susp->c2 * susp->c2) * susp->omc3 / susp->c3p1)); } /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; c2_reg = susp->c2; c1_reg = susp->c1; recompute_reg = susp->recompute; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current;current = *s1_ptr_reg++; y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg; *out_ptr_reg++ = (sample_type) y0; y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->recompute = recompute_reg; susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz1_pHaSe += togo * susp->hz1_pHaSe_iNcR; susp->hz1_n -= togo; susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresonvv_nrr_fetch */ void aresonvv_toss_fetch(susp, snd_list) register aresonvv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from hz1 up to final_time for this block of zeros */ while ((round((final_time - susp->hz1->t0) * susp->hz1->sr)) >= susp->hz1->current) susp_get_samples(hz1, hz1_ptr, hz1_cnt); /* fetch samples from bw up to final_time for this block of zeros */ while ((round((final_time - susp->bw->t0) * susp->bw->sr)) >= susp->bw->current) susp_get_samples(bw, bw_ptr, bw_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->hz1->t0) * susp->hz1->sr - (susp->hz1->current - susp->hz1_cnt)); susp->hz1_ptr += n; susp_took(hz1_cnt, n); n = round((final_time - susp->bw->t0) * susp->bw->sr - (susp->bw->current - susp->bw_cnt)); susp->bw_ptr += n; susp_took(bw_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void aresonvv_mark(aresonvv_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->hz1); sound_xlmark(susp->bw); } void aresonvv_free(aresonvv_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->hz1); sound_unref(susp->bw); ffree_generic(susp, sizeof(aresonvv_susp_node), "aresonvv_free"); } void aresonvv_print_tree(aresonvv_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("hz1:"); sound_print_tree_1(susp->hz1, n); indent(n); stdputstr("bw:"); sound_print_tree_1(susp->bw, n); } sound_type snd_make_aresonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization) { register aresonvv_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(max(s1->t0, hz1->t0), bw->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (S1) */ scale_factor *= s1->scale; s1->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s1->sr < sr) { s1->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, aresonvv_susp_node, "snd_make_aresonvv"); susp->scale1 = s1->scale; susp->c3co = 0.0; susp->c3p1 = 0.0; susp->c3t4 = 0.0; susp->omc3 = 0.0; susp->coshz = 0.0; susp->c2 = 0.0; susp->c1 = 0.0; susp->recompute = false; susp->normalization = normalization; susp->y1 = 0.0; susp->y2 = 0.0; hz1->scale = (sample_type) (hz1->scale * (PI2 / s1->sr)); bw->scale = (sample_type) (bw->scale * (-PI2 / s1->sr));; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(hz1, sr); interp_desc = (interp_desc << 2) + interp_style(bw, sr); switch (interp_desc) { case INTERP_nnn: /* handled below */ case INTERP_nns: /* handled below */ case INTERP_nsn: /* handled below */ case INTERP_nss: susp->susp.fetch = aresonvv_nss_fetch; break; case INTERP_nni: /* handled below */ case INTERP_nsi: susp->susp.fetch = aresonvv_nsi_fetch; break; case INTERP_nnr: /* handled below */ case INTERP_nsr: susp->susp.fetch = aresonvv_nsr_fetch; break; case INTERP_nin: /* handled below */ case INTERP_nis: susp->susp.fetch = aresonvv_nis_fetch; break; case INTERP_nii: susp->susp.fetch = aresonvv_nii_fetch; break; case INTERP_nir: susp->susp.fetch = aresonvv_nir_fetch; break; case INTERP_nrn: /* handled below */ case INTERP_nrs: susp->susp.fetch = aresonvv_nrs_fetch; break; case INTERP_nri: susp->susp.fetch = aresonvv_nri_fetch; break; case INTERP_nrr: susp->susp.fetch = aresonvv_nrr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < hz1->t0) sound_prepend_zeros(hz1, t0); if (t0 < bw->t0) sound_prepend_zeros(bw, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(hz1->t0, min(bw->t0, t0))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = aresonvv_toss_fetch; } /* initialize susp state */ susp->susp.free = aresonvv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = aresonvv_mark; susp->susp.print_tree = aresonvv_print_tree; susp->susp.name = "aresonvv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->hz1 = hz1; susp->hz1_cnt = 0; susp->hz1_pHaSe = 0.0; susp->hz1_pHaSe_iNcR = hz1->sr / sr; susp->hz1_n = 0; susp->output_per_hz1 = sr / hz1->sr; susp->bw = bw; susp->bw_cnt = 0; susp->bw_pHaSe = 0.0; susp->bw_pHaSe_iNcR = bw->sr / sr; susp->bw_n = 0; susp->output_per_bw = sr / bw->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_aresonvv(sound_type s1, sound_type hz1, sound_type bw, int normalization) { sound_type s1_copy = sound_copy(s1); sound_type hz1_copy = sound_copy(hz1); sound_type bw_copy = sound_copy(bw); return snd_make_aresonvv(s1_copy, hz1_copy, bw_copy, normalization); } nyquist-3.05/tran/alpassvv.c0000644000175000000620000005640510144436365015152 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "alpassvv.h" void alpassvv_free(); typedef struct alpassvv_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type input; long input_cnt; sample_block_values_type input_ptr; sound_type delaysnd; long delaysnd_cnt; sample_block_values_type delaysnd_ptr; sound_type feedback; long feedback_cnt; sample_block_values_type feedback_ptr; float delay_scale_factor; long buflen; sample_type *delaybuf; sample_type *delayptr; sample_type *endptr; } alpassvv_susp_node, *alpassvv_susp_type; void alpassvv_nnn_fetch(register alpassvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register float delay_scale_factor_reg; register long buflen_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type feedback_ptr_reg; register sample_block_values_type delaysnd_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpassvv_nnn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the delaysnd input sample block: */ susp_check_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); togo = min(togo, susp->delaysnd_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delay_scale_factor_reg = susp->delay_scale_factor; buflen_reg = susp->buflen; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; delaysnd_ptr_reg = susp->delaysnd_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr; /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ register sample_type fb = *feedback_ptr_reg++; delaysamp = *delaysnd_ptr_reg++ * delay_scale_factor_reg; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr_reg + buflen_reg - (delayi + 1); if (yptr >= endptr_reg) yptr -= buflen_reg; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr_reg++ = z = (sample_type) (fb * y + *input_ptr_reg++); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr_reg > endptr_reg) { delayptr_reg = susp->delaybuf; *delayptr_reg++ = *endptr_reg; } *out_ptr_reg++ = (sample_type) (y - fb * z);; } while (--n); /* inner loop */ susp->buflen = buflen_reg; susp->delayptr = delayptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using delaysnd_ptr_reg is a bad idea on RS/6000: */ susp->delaysnd_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(delaysnd_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpassvv_nnn_fetch */ void alpassvv_nns_fetch(register alpassvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register float delay_scale_factor_reg; register long buflen_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_type feedback_scale_reg = susp->feedback->scale; register sample_block_values_type feedback_ptr_reg; register sample_block_values_type delaysnd_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpassvv_nns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the delaysnd input sample block: */ susp_check_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); togo = min(togo, susp->delaysnd_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delay_scale_factor_reg = susp->delay_scale_factor; buflen_reg = susp->buflen; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; delaysnd_ptr_reg = susp->delaysnd_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr; /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ register sample_type fb = (feedback_scale_reg * *feedback_ptr_reg++); delaysamp = *delaysnd_ptr_reg++ * delay_scale_factor_reg; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr_reg + buflen_reg - (delayi + 1); if (yptr >= endptr_reg) yptr -= buflen_reg; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr_reg++ = z = (sample_type) (fb * y + *input_ptr_reg++); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr_reg > endptr_reg) { delayptr_reg = susp->delaybuf; *delayptr_reg++ = *endptr_reg; } *out_ptr_reg++ = (sample_type) (y - fb * z);; } while (--n); /* inner loop */ susp->buflen = buflen_reg; susp->delayptr = delayptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using delaysnd_ptr_reg is a bad idea on RS/6000: */ susp->delaysnd_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(delaysnd_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpassvv_nns_fetch */ void alpassvv_nsn_fetch(register alpassvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register float delay_scale_factor_reg; register long buflen_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type feedback_ptr_reg; register sample_type delaysnd_scale_reg = susp->delaysnd->scale; register sample_block_values_type delaysnd_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpassvv_nsn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the delaysnd input sample block: */ susp_check_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); togo = min(togo, susp->delaysnd_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delay_scale_factor_reg = susp->delay_scale_factor; buflen_reg = susp->buflen; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; delaysnd_ptr_reg = susp->delaysnd_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr; /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ register sample_type fb = *feedback_ptr_reg++; delaysamp = (delaysnd_scale_reg * *delaysnd_ptr_reg++) * delay_scale_factor_reg; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr_reg + buflen_reg - (delayi + 1); if (yptr >= endptr_reg) yptr -= buflen_reg; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr_reg++ = z = (sample_type) (fb * y + *input_ptr_reg++); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr_reg > endptr_reg) { delayptr_reg = susp->delaybuf; *delayptr_reg++ = *endptr_reg; } *out_ptr_reg++ = (sample_type) (y - fb * z);; } while (--n); /* inner loop */ susp->buflen = buflen_reg; susp->delayptr = delayptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using delaysnd_ptr_reg is a bad idea on RS/6000: */ susp->delaysnd_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(delaysnd_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpassvv_nsn_fetch */ void alpassvv_nss_fetch(register alpassvv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register float delay_scale_factor_reg; register long buflen_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_type feedback_scale_reg = susp->feedback->scale; register sample_block_values_type feedback_ptr_reg; register sample_type delaysnd_scale_reg = susp->delaysnd->scale; register sample_block_values_type delaysnd_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpassvv_nss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the delaysnd input sample block: */ susp_check_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); togo = min(togo, susp->delaysnd_cnt); /* don't run past the feedback input sample block: */ susp_check_samples(feedback, feedback_ptr, feedback_cnt); togo = min(togo, susp->feedback_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delay_scale_factor_reg = susp->delay_scale_factor; buflen_reg = susp->buflen; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; feedback_ptr_reg = susp->feedback_ptr; delaysnd_ptr_reg = susp->delaysnd_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr; /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ register sample_type fb = (feedback_scale_reg * *feedback_ptr_reg++); delaysamp = (delaysnd_scale_reg * *delaysnd_ptr_reg++) * delay_scale_factor_reg; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr_reg + buflen_reg - (delayi + 1); if (yptr >= endptr_reg) yptr -= buflen_reg; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr_reg++ = z = (sample_type) (fb * y + *input_ptr_reg++); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr_reg > endptr_reg) { delayptr_reg = susp->delaybuf; *delayptr_reg++ = *endptr_reg; } *out_ptr_reg++ = (sample_type) (y - fb * z);; } while (--n); /* inner loop */ susp->buflen = buflen_reg; susp->delayptr = delayptr_reg; /* using feedback_ptr_reg is a bad idea on RS/6000: */ susp->feedback_ptr += togo; /* using delaysnd_ptr_reg is a bad idea on RS/6000: */ susp->delaysnd_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(delaysnd_cnt, togo); susp_took(feedback_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpassvv_nss_fetch */ void alpassvv_toss_fetch(susp, snd_list) register alpassvv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* fetch samples from delaysnd up to final_time for this block of zeros */ while ((round((final_time - susp->delaysnd->t0) * susp->delaysnd->sr)) >= susp->delaysnd->current) susp_get_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); /* fetch samples from feedback up to final_time for this block of zeros */ while ((round((final_time - susp->feedback->t0) * susp->feedback->sr)) >= susp->feedback->current) susp_get_samples(feedback, feedback_ptr, feedback_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); n = round((final_time - susp->delaysnd->t0) * susp->delaysnd->sr - (susp->delaysnd->current - susp->delaysnd_cnt)); susp->delaysnd_ptr += n; susp_took(delaysnd_cnt, n); n = round((final_time - susp->feedback->t0) * susp->feedback->sr - (susp->feedback->current - susp->feedback_cnt)); susp->feedback_ptr += n; susp_took(feedback_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void alpassvv_mark(alpassvv_susp_type susp) { sound_xlmark(susp->input); sound_xlmark(susp->delaysnd); sound_xlmark(susp->feedback); } void alpassvv_free(alpassvv_susp_type susp) { free(susp->delaybuf); sound_unref(susp->input); sound_unref(susp->delaysnd); sound_unref(susp->feedback); ffree_generic(susp, sizeof(alpassvv_susp_node), "alpassvv_free"); } void alpassvv_print_tree(alpassvv_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); indent(n); stdputstr("delaysnd:"); sound_print_tree_1(susp->delaysnd, n); indent(n); stdputstr("feedback:"); sound_print_tree_1(susp->feedback, n); } sound_type snd_make_alpassvv(sound_type input, sound_type delaysnd, sound_type feedback, double maxdelay) { register alpassvv_susp_type susp; rate_type sr = max(max(input->sr, delaysnd->sr), feedback->sr); time_type t0 = max(input->t0, delaysnd->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, alpassvv_susp_node, "snd_make_alpassvv"); susp->delay_scale_factor = (float) (input->sr * delaysnd->scale); susp->buflen = max(2, (long) (input->sr * maxdelay + 2.5)); susp->delaybuf = (sample_type *) calloc (susp->buflen + 1, sizeof(sample_type)); susp->delayptr = susp->delaybuf; susp->endptr = susp->delaybuf + susp->buflen; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); interp_desc = (interp_desc << 2) + interp_style(delaysnd, sr); interp_desc = (interp_desc << 2) + interp_style(feedback, sr); switch (interp_desc) { case INTERP_nnn: susp->susp.fetch = alpassvv_nnn_fetch; break; case INTERP_nns: susp->susp.fetch = alpassvv_nns_fetch; break; case INTERP_nsn: susp->susp.fetch = alpassvv_nsn_fetch; break; case INTERP_nss: susp->susp.fetch = alpassvv_nss_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); if (t0 < delaysnd->t0) sound_prepend_zeros(delaysnd, t0); if (t0 < feedback->t0) sound_prepend_zeros(feedback, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, min(delaysnd->t0, min(feedback->t0, t0))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = alpassvv_toss_fetch; } /* initialize susp state */ susp->susp.free = alpassvv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = alpassvv_mark; susp->susp.print_tree = alpassvv_print_tree; susp->susp.name = "alpassvv"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; susp->delaysnd = delaysnd; susp->delaysnd_cnt = 0; susp->feedback = feedback; susp->feedback_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_alpassvv(sound_type input, sound_type delaysnd, sound_type feedback, double maxdelay) { sound_type input_copy = sound_copy(input); sound_type delaysnd_copy = sound_copy(delaysnd); sound_type feedback_copy = sound_copy(feedback); return snd_make_alpassvv(input_copy, delaysnd_copy, feedback_copy, maxdelay); } nyquist-3.05/tran/instrsitar.alg0000644000175000000620000000077711466723256016045 0ustar stevestaff(INSTRSITAR-ALG (NAME "sitar") (ARGUMENTS ("time_type" "t0")("double" "freq")("time_type" "dur")("rate_type" "sr")) (STATE ("struct instr *" "mysitar" "initInstrument(SITAR, round(sr))") ("int" "temp_ret_value" "noteOn(susp->mysitar, freq, 1.0)")) (NOT-IN-INNER-LOOP "freq" "temp_ret_value") (SAMPLE-RATE "sr") (TERMINATE (after "dur")) (INNER-LOOP " output = (sample_type) tick(mysitar)") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->mysitar); ") ) nyquist-3.05/tran/instrclarfreq.h0000644000175000000620000000047110144436365016167 0ustar stevestaffsound_type snd_make_clarinet_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr); sound_type snd_clarinet_freq(double freq, sound_type breath_env, sound_type freq_env, rate_type sr); /* LISP: (snd-clarinet_freq ANYNUM SOUND SOUND ANYNUM) */ #define CLAR_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/tapf.h0000644000175000000620000000035410144436365014242 0ustar stevestaffsound_type snd_make_tapf(sound_type s1, double offset, sound_type vardelay, double maxdelay); sound_type snd_tapf(sound_type s1, double offset, sound_type vardelay, double maxdelay); /* LISP: (snd-tapf SOUND ANYNUM SOUND ANYNUM) */ nyquist-3.05/tran/slope.c0000644000175000000620000001332510144436365014427 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "slope.h" void slope_free(); typedef struct slope_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; sample_type prev; double scale; } slope_susp_node, *slope_susp_type; void slope_n_fetch(register slope_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type prev_reg; register double scale_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "slope_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; prev_reg = susp->prev; scale_reg = susp->scale; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ { register sample_type x = *input_ptr_reg++; *out_ptr_reg++ = (sample_type) ((x - prev_reg) * scale_reg); prev_reg = x;}; } while (--n); /* inner loop */ susp->prev = prev_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* slope_n_fetch */ void slope_toss_fetch(susp, snd_list) register slope_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void slope_mark(slope_susp_type susp) { sound_xlmark(susp->input); } void slope_free(slope_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(slope_susp_node), "slope_free"); } void slope_print_tree(slope_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_slope(sound_type input) { register slope_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, slope_susp_node, "snd_make_slope"); susp->prev = 0.0F; susp->scale = input->sr * input->scale; susp->susp.fetch = slope_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ /* Toss an extra 1 samples to make up for internal buffering: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 1.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = slope_toss_fetch; } /* initialize susp state */ susp->susp.free = slope_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = slope_mark; susp->susp.print_tree = slope_print_tree; susp->susp.name = "slope"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_slope(sound_type input) { sound_type input_copy = sound_copy(input); return snd_make_slope(input_copy); } nyquist-3.05/tran/init.lsp0000644000175000000620000000072110144436365014620 0ustar stevestaff(expand 50) (load "../runtime/xlinit.lsp") (load "../runtime/misc.lsp") ;; set to T to get interpolation within inner loops (setf *INLINE-INTERPOLATION* nil) ;; set to T to get ANSI headers and NIL to get antique headers (setf *ANSI* NIL) ;; set to T to generate tracing code, NIL to disable tracing code (setf *WATCH* NIL) (load "translate") (load "writesusp") (load "writemake") (load "writetoss") (load "innerloop") (setf *gc-flag* t) (setf *watch* nil) nyquist-3.05/tran/sine.c0000644000175000000620000000611210144436365014237 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "sine.h" void sine_free(); typedef struct sine_susp_struct { snd_susp_node susp; long terminate_cnt; long phase; long ph_incr; } sine_susp_node, *sine_susp_type; sample_type sine_table[SINE_TABLE_LEN + 1]; void sine_init() { int i; for (i = 0; i <= SINE_TABLE_LEN; i++) sine_table[i] = (sample_type) (sin((PI * 2 * i) / SINE_TABLE_LEN)); } void sine__fetch(register sine_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long phase_reg; register long ph_incr_reg; falloc_sample_block(out, "sine__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = sine_table[phase_reg >> SINE_TABLE_SHIFT]; phase_reg += ph_incr_reg; phase_reg &= SINE_TABLE_MASK;; } while (--n); /* inner loop */ susp->phase = (susp->phase + susp->ph_incr * togo) & SINE_TABLE_MASK; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* sine__fetch */ void sine_free(sine_susp_type susp) { ffree_generic(susp, sizeof(sine_susp_node), "sine_free"); } void sine_print_tree(sine_susp_type susp, int n) { } sound_type snd_make_sine(time_type t0, double hz, rate_type sr, time_type d) { register sine_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, sine_susp_node, "snd_make_sine"); susp->phase = 0; susp->ph_incr = round(((hz * SINE_TABLE_LEN) * (1 << SINE_TABLE_SHIFT) / sr)); susp->susp.fetch = sine__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = sine_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = sine_print_tree; susp->susp.name = "sine"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_sine(time_type t0, double hz, rate_type sr, time_type d) { return snd_make_sine(t0, hz, sr, d); } nyquist-3.05/tran/instrbowedfreq.h0000644000175000000620000000046311466723256016355 0ustar stevestaffsound_type snd_make_bowed_freq(double freq, sound_type bowpress_env, sound_type freq_env, rate_type sr); sound_type snd_bowed_freq(double freq, sound_type bowpress_env, sound_type freq_env, rate_type sr); /* LISP: (snd-bowed_freq ANYNUM SOUND SOUND ANYNUM) */ #define BOW_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/resoncv.alg0000644000175000000620000000244310144436365015304 0ustar stevestaff(RESONCV-ALG (NAME "resoncv") (ARGUMENTS ("sound_type" "s1") ("double" "hz") ("sound_type" "bw") ("int" "normalization")) (INLINE-INTERPOLATION T) (INTERNAL-SCALING s1) (ALWAYS-SCALE bw) (START (MAX s1 bw)) (TERMINATE (MIN s1 bw)) (LOGICAL-STOP (MIN s1)) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION bw) (STATE ("double" "scale1" "s1->scale") ("double" "c3co" "0.0") ("double" "coshz" "cos(hz * PI2 / s1->sr)") ("double" "c2" "0.0") ("double" "c1" "0.0") ("int" "normalization" "normalization") ("double" "y1" "0.0") ("double" "y2" "0.0; bw->scale = (sample_type) (bw->scale * (-PI2 / s1->sr))")) (DEPENDS ("c3co" "bw" "exp(bw)") ("c3p1" "bw" "c3co + 1.0" TEMP "double") ("c3t4" "bw" "c3co * 4.0" TEMP "double") ("omc3" "bw" "1.0 - c3co" TEMP "double") ("c2" "bw" "c3t4 * coshz / c3p1") ("c1" "bw" "(normalization == 0 ? 1.0 : (normalization == 1 ? omc3 * sqrt(1.0 - c2 * c2 / c3t4) : sqrt(c3p1 * c3p1 - c2 * c2) * omc3 / c3p1)) * scale1")) (CONSTANT "c1" "c2" "c3co" "coshz" "normalization" "scale1") (FORCE-INTO-REGISTER normalization coshz scale1) (INNER-LOOP "{ double y0 = c1 * s1 + c2 * y1 - c3co * y2; output = (sample_type) y0; y2 = y1; y1 = y0; }") ) nyquist-3.05/tran/ifft.c0000644000175000000620000002215511466723256014244 0ustar stevestaff#include "stdio.h" #define _USE_MATH_DEFINES 1 /* for Visual C++ to get M_LN2 */ #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "ifft.h" void ifft_free(); typedef struct ifft_susp_struct { snd_susp_node susp; long index; long length; LVAL array; long window_len; sample_type *outbuf; LVAL src; long stepsize; sample_type *window; sample_type *samples; table_type table; } ifft_susp_node, *ifft_susp_type; /* index: index into outbuf whree we get output samples * length: size of the frame, window, and outbuf; half size of samples * array: spectral frame goes here (why not a local var?) * window_len: size of window, should equal length * outbuf: real part of samples are multiplied by window and added to * outbuf (after shifting) * src: send :NEXT to this object to get next frame * stepsize: shift by this many and add each frame * samples: result of ifft goes here, real and imag * window: multiply samples by window if any * * IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either an * array of samples or NIL. The output of ifft is simply the * concatenation of the samples taken from the array. Later, * an ifft will be plugged in and this will return overlapped * adds of the ifft's. * * OVERLAP: stepsize must be less than or equal to the length * of real part of the transformed spectrum. A transform step * works like this: * (1) shift the output buffer by stepsize samples, filling * the end of the buffer with zeros * (2) get and transform an array of spectral coefficients * (3) multiply the result by a window * (4) add the result to the output buffer * (5) output the first stepsize samples of the buffer * * DATA FORMAT: the DC component goes in array elem 0 * Cosine part is in elements 2*i-1 * Sine part is in elements 2*i * Nyquist frequency is in element length-1 */ #include "samples.h" #include "fftext.h" #define MUST_BE_FLONUM(e) \ if (!(e) || ntype(e) != FLONUM) { xlerror("flonum expected", (e)); } table_type get_window_samples(LVAL window, sample_type **samples, long *len) { table_type result = NULL; if (soundp(window)) { sound_type window_sound = getsound(window); xlprot1(window); /* maybe not necessary */ result = sound_to_table(window_sound); xlpop(); *samples = result->samples; *len = (long) (result->length + 0.5); } return result; } void ifft__fetch(register ifft_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long index_reg; register sample_type * outbuf_reg; falloc_sample_block(out, "ifft__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->index >= susp->stepsize) { long i; long m, n; LVAL elem; susp->index = 0; susp->array = xleval(cons(s_send, cons(susp->src, consa(s_next)))); if (susp->array == NULL) { susp->src = NULL; goto out; } else if (!vectorp(susp->array)) { xlerror("array expected", susp->array); } else if (susp->samples == NULL) { /* assume arrays are all the same size as first one; now that we know the size, we just have to do this first allocation. */ susp->length = getsize(susp->array); if (susp->length < 1) xlerror("array has no elements", susp->array); if (susp->window && (susp->window_len != susp->length)) xlerror("window size and spectrum size differ", susp->array); /* tricky non-power of 2 detector: only if this is a * power of 2 will the highest 1 bit be cleared when * we subtract 1 ... */ if (susp->length & (susp->length - 1)) xlfail("spectrum size must be a power of 2"); susp->samples = (sample_type *) calloc(susp->length, sizeof(sample_type)); susp->outbuf = (sample_type *) calloc(susp->length, sizeof(sample_type)); } else if (getsize(susp->array) != susp->length) { xlerror("arrays must all be the same length", susp->array); } /* at this point, we have a new array to put samples */ /* the incoming array format is [DC, R1, I1, R2, I2, ... RN] * where RN is the real coef at the Nyquist frequency * but susp->samples should be organized as [DC, RN, R1, I1, ...] */ n = susp->length; /* get the DC (real) coef */ elem = getelement(susp->array, 0); MUST_BE_FLONUM(elem) susp->samples[0] = (sample_type) getflonum(elem); /* get the Nyquist (real) coef */ elem = getelement(susp->array, n - 1); MUST_BE_FLONUM(elem); susp->samples[1] = (sample_type) getflonum(elem); /* get the remaining coef */ for (i = 1; i < n - 1; i++) { elem = getelement(susp->array, i); MUST_BE_FLONUM(elem) susp->samples[i + 1] = (sample_type) getflonum(elem); } susp->array = NULL; /* free the array */ /* here is where the IFFT and windowing should take place */ //fftnf(1, &n, susp->samples, susp->samples + n, -1, 1.0); m = round(log(n) / M_LN2); if (!fftInit(m)) riffts(susp->samples, m, 1); else xlfail("FFT initialization error"); if (susp->window) { n = susp->length; for (i = 0; i < n; i++) { susp->samples[i] *= susp->window[i]; } } /* shift the outbuf */ n = susp->length - susp->stepsize; for (i = 0; i < n; i++) { susp->outbuf[i] = susp->outbuf[i + susp->stepsize]; } /* clear end of outbuf */ for (i = n; i < susp->length; i++) { susp->outbuf[i] = 0; } /* add in the ifft result */ n = susp->length; for (i = 0; i < n; i++) { susp->outbuf[i] += susp->samples[i]; } } togo = min(togo, susp->stepsize - susp->index); n = togo; index_reg = susp->index; outbuf_reg = susp->outbuf; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = outbuf_reg[index_reg++];; } while (--n); /* inner loop */ susp->index = index_reg; susp->outbuf = outbuf_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* ifft__fetch */ void ifft_mark(ifft_susp_type susp) { if (susp->src) mark(susp->src); if (susp->array) mark(susp->array); } void ifft_free(ifft_susp_type susp) { if (susp->samples) free(susp->samples); if (susp->table) table_unref(susp->table); if (susp->outbuf) free(susp->outbuf); ffree_generic(susp, sizeof(ifft_susp_node), "ifft_free"); } void ifft_print_tree(ifft_susp_type susp, int n) { } sound_type snd_make_ifft(time_type t0, rate_type sr, LVAL src, long stepsize, LVAL window) { register ifft_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, ifft_susp_node, "snd_make_ifft"); susp->index = stepsize; susp->length = 0; susp->array = NULL; susp->window_len = 0; susp->outbuf = NULL; susp->src = src; susp->stepsize = stepsize; susp->window = NULL; susp->samples = NULL; susp->table = get_window_samples(window, &susp->window, &susp->window_len); susp->susp.fetch = ifft__fetch; /* initialize susp state */ susp->susp.free = ifft_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = ifft_mark; susp->susp.print_tree = ifft_print_tree; susp->susp.name = "ifft"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_ifft(time_type t0, rate_type sr, LVAL src, long stepsize, LVAL window) { return snd_make_ifft(t0, sr, src, stepsize, window); } nyquist-3.05/tran/alpassvv.h0000644000175000000620000000041110144436365015141 0ustar stevestaffsound_type snd_make_alpassvv(sound_type input, sound_type delaysnd, sound_type feedback, double maxdelay); sound_type snd_alpassvv(sound_type input, sound_type delaysnd, sound_type feedback, double maxdelay); /* LISP: (snd-alpassvv SOUND SOUND SOUND ANYNUM) */ nyquist-3.05/tran/delaycc.alg0000644000175000000620000000140611466723256015235 0ustar stevestaff(DELAY-ALG (NAME "delay") (ARGUMENTS ("sound_type" "input") ("time_type" "delay") ("double" "feedback")) (START (MIN input)) (STATE ("double" "feedback" "feedback") ("long" "delaylen" "max(1, round(input->sr * delay))") ("sample_type *" "delaybuf" "(sample_type *) calloc (susp->delaylen, sizeof(sample_type))") ("sample_type *" "delayptr" "susp->delaybuf") ("sample_type *" "endptr" "susp->delaybuf + susp->delaylen")) (CONSTANT "feedback" "delaylen" "endptr") (NOT-REGISTER delaybuf) (LINEAR input) (TERMINATE (MIN input)) (INNER-LOOP "output = *delayptr; *delayptr = (sample_type) (*delayptr * feedback) + input; if (++delayptr >= endptr) delayptr = susp->delaybuf;") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/alpassvc.c0000644000175000000620000003153710144436365015126 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "alpassvc.h" void alpassvc_free(); typedef struct alpassvc_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type input; long input_cnt; sample_block_values_type input_ptr; sound_type delaysnd; long delaysnd_cnt; sample_block_values_type delaysnd_ptr; float delay_scale_factor; double feedback; long buflen; sample_type *delaybuf; sample_type *delayptr; sample_type *endptr; } alpassvc_susp_node, *alpassvc_susp_type; void alpassvc_nn_fetch(register alpassvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register float delay_scale_factor_reg; register double feedback_reg; register long buflen_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_block_values_type delaysnd_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpassvc_nn_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the delaysnd input sample block: */ susp_check_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); togo = min(togo, susp->delaysnd_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delay_scale_factor_reg = susp->delay_scale_factor; feedback_reg = susp->feedback; buflen_reg = susp->buflen; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; delaysnd_ptr_reg = susp->delaysnd_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr; /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ delaysamp = *delaysnd_ptr_reg++ * delay_scale_factor_reg; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr_reg + buflen_reg - (delayi + 1); if (yptr >= endptr_reg) yptr -= buflen_reg; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr_reg++ = z = (sample_type) (feedback_reg * y + *input_ptr_reg++); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr_reg > endptr_reg) { delayptr_reg = susp->delaybuf; *delayptr_reg++ = *endptr_reg; } *out_ptr_reg++ = (sample_type) (y - feedback_reg * z);; } while (--n); /* inner loop */ susp->buflen = buflen_reg; susp->delayptr = delayptr_reg; /* using delaysnd_ptr_reg is a bad idea on RS/6000: */ susp->delaysnd_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(delaysnd_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpassvc_nn_fetch */ void alpassvc_ns_fetch(register alpassvc_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register float delay_scale_factor_reg; register double feedback_reg; register long buflen_reg; register sample_type * delayptr_reg; register sample_type * endptr_reg; register sample_type delaysnd_scale_reg = susp->delaysnd->scale; register sample_block_values_type delaysnd_ptr_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "alpassvc_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past the delaysnd input sample block: */ susp_check_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); togo = min(togo, susp->delaysnd_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; delay_scale_factor_reg = susp->delay_scale_factor; feedback_reg = susp->feedback; buflen_reg = susp->buflen; delayptr_reg = susp->delayptr; endptr_reg = susp->endptr; delaysnd_ptr_reg = susp->delaysnd_ptr; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register sample_type y, z, delaysamp; register int delayi; register sample_type *yptr; /* compute where to read y, we want y to be delay_snd samples * after delay_ptr, where we write the new sample. First, * conver from seconds to samples. Note: don't use actual sound_type * names in comments! The translator isn't smart enough. */ delaysamp = (delaysnd_scale_reg * *delaysnd_ptr_reg++) * delay_scale_factor_reg; delayi = (int) delaysamp; /* get integer part */ delaysamp = delaysamp - delayi; /* get phase */ yptr = delayptr_reg + buflen_reg - (delayi + 1); if (yptr >= endptr_reg) yptr -= buflen_reg; /* now get y, the out-put of the delay, using interpolation */ /* note that as phase increases, we use more of yptr[0] because positive phase means longer buffer means read earlier sample */ y = (float) ((yptr[0] * delaysamp) + (yptr[1] * (1.0 - delaysamp))); /* WARNING: no check to keep delaysamp in range, so do this in LISP */ *delayptr_reg++ = z = (sample_type) (feedback_reg * y + *input_ptr_reg++); /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ if (delayptr_reg > endptr_reg) { delayptr_reg = susp->delaybuf; *delayptr_reg++ = *endptr_reg; } *out_ptr_reg++ = (sample_type) (y - feedback_reg * z);; } while (--n); /* inner loop */ susp->buflen = buflen_reg; susp->delayptr = delayptr_reg; /* using delaysnd_ptr_reg is a bad idea on RS/6000: */ susp->delaysnd_ptr += togo; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); susp_took(delaysnd_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* alpassvc_ns_fetch */ void alpassvc_toss_fetch(susp, snd_list) register alpassvc_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* fetch samples from delaysnd up to final_time for this block of zeros */ while ((round((final_time - susp->delaysnd->t0) * susp->delaysnd->sr)) >= susp->delaysnd->current) susp_get_samples(delaysnd, delaysnd_ptr, delaysnd_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); n = round((final_time - susp->delaysnd->t0) * susp->delaysnd->sr - (susp->delaysnd->current - susp->delaysnd_cnt)); susp->delaysnd_ptr += n; susp_took(delaysnd_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void alpassvc_mark(alpassvc_susp_type susp) { sound_xlmark(susp->input); sound_xlmark(susp->delaysnd); } void alpassvc_free(alpassvc_susp_type susp) { free(susp->delaybuf); sound_unref(susp->input); sound_unref(susp->delaysnd); ffree_generic(susp, sizeof(alpassvc_susp_node), "alpassvc_free"); } void alpassvc_print_tree(alpassvc_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); indent(n); stdputstr("delaysnd:"); sound_print_tree_1(susp->delaysnd, n); } sound_type snd_make_alpassvc(sound_type input, sound_type delaysnd, double feedback, double maxdelay) { register alpassvc_susp_type susp; rate_type sr = max(input->sr, delaysnd->sr); time_type t0 = max(input->t0, delaysnd->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, alpassvc_susp_node, "snd_make_alpassvc"); susp->delay_scale_factor = (float) (input->sr * delaysnd->scale); susp->feedback = feedback; susp->buflen = max(2, (long) (input->sr * maxdelay + 2.5)); susp->delaybuf = (sample_type *) calloc (susp->buflen + 1, sizeof(sample_type)); susp->delayptr = susp->delaybuf; susp->endptr = susp->delaybuf + susp->buflen; /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(input, sr); interp_desc = (interp_desc << 2) + interp_style(delaysnd, sr); switch (interp_desc) { case INTERP_nn: susp->susp.fetch = alpassvc_nn_fetch; break; case INTERP_ns: susp->susp.fetch = alpassvc_ns_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); if (t0 < delaysnd->t0) sound_prepend_zeros(delaysnd, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, min(delaysnd->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = alpassvc_toss_fetch; } /* initialize susp state */ susp->susp.free = alpassvc_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = alpassvc_mark; susp->susp.print_tree = alpassvc_print_tree; susp->susp.name = "alpassvc"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; susp->delaysnd = delaysnd; susp->delaysnd_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_alpassvc(sound_type input, sound_type delaysnd, double feedback, double maxdelay) { sound_type input_copy = sound_copy(input); sound_type delaysnd_copy = sound_copy(delaysnd); return snd_make_alpassvc(input_copy, delaysnd_copy, feedback, maxdelay); } nyquist-3.05/tran/resonvc.h0000644000175000000620000000034510144436365014767 0ustar stevestaffsound_type snd_make_resonvc(sound_type s1, sound_type hz, double bw, int normalization); sound_type snd_resonvc(sound_type s1, sound_type hz, double bw, int normalization); /* LISP: (snd-resonvc SOUND SOUND ANYNUM FIXNUM) */ nyquist-3.05/tran/const.c0000644000175000000620000000510510144436365014430 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "const.h" void const_free(); typedef struct const_susp_struct { snd_susp_node susp; long terminate_cnt; sample_type c; } const_susp_node, *const_susp_type; void const__fetch(register const_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type c_reg; falloc_sample_block(out, "const__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; c_reg = susp->c; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = c_reg; } while (--n); /* inner loop */ out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* const__fetch */ void const_free(const_susp_type susp) { ffree_generic(susp, sizeof(const_susp_node), "const_free"); } void const_print_tree(const_susp_type susp, int n) { } sound_type snd_make_const(double c, time_type t0, rate_type sr, time_type d) { register const_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, const_susp_node, "snd_make_const"); susp->c = (sample_type) c; susp->susp.fetch = const__fetch; susp->terminate_cnt = round((d) * sr); /* initialize susp state */ susp->susp.free = const_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = NULL; susp->susp.print_tree = const_print_tree; susp->susp.name = "const"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_const(double c, time_type t0, rate_type sr, time_type d) { return snd_make_const(c, t0, sr, d); } nyquist-3.05/tran/aresonvc.h0000644000175000000620000000035010144436365015124 0ustar stevestaffsound_type snd_make_aresonvc(sound_type s1, sound_type hz, double bw, int normalization); sound_type snd_aresonvc(sound_type s1, sound_type hz, double bw, int normalization); /* LISP: (snd-aresonvc SOUND SOUND ANYNUM FIXNUM) */ nyquist-3.05/tran/lpreson.h0000644000175000000620000000031010144436365014762 0ustar stevestaffsound_type snd_make_lpreson(sound_type x_snd, LVAL src, time_type frame_time); sound_type snd_lpreson(sound_type x_snd, LVAL src, time_type frame_time); /* LISP: (snd-lpreson SOUND ANY ANYNUM) */ nyquist-3.05/tran/partial.h0000644000175000000620000000027110144436365014742 0ustar stevestaffsound_type snd_make_partial(rate_type sr, double hz, sound_type env); sound_type snd_partial(rate_type sr, double hz, sound_type env); /* LISP: (snd-partial ANYNUM ANYNUM SOUND) */ nyquist-3.05/tran/partial.c0000644000175000000620000002161010144436365014735 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "partial.h" void partial_free(); typedef struct partial_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type env; long env_cnt; sample_block_values_type env_ptr; long phase; long ph_incr; } partial_susp_node, *partial_susp_type; #include "sine.h" void partial_n_fetch(register partial_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long phase_reg; register long ph_incr_reg; register sample_block_values_type env_ptr_reg; falloc_sample_block(out, "partial_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the env input sample block: */ susp_check_term_log_samples(env, env_ptr, env_cnt); togo = min(togo, susp->env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; env_ptr_reg = susp->env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = sine_table[phase_reg >> SINE_TABLE_SHIFT] * *env_ptr_reg++; phase_reg += ph_incr_reg; phase_reg &= SINE_TABLE_MASK;; } while (--n); /* inner loop */ susp->phase = (susp->phase + susp->ph_incr * togo) & SINE_TABLE_MASK; /* using env_ptr_reg is a bad idea on RS/6000: */ susp->env_ptr += togo; out_ptr += togo; susp_took(env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* partial_n_fetch */ void partial_s_fetch(register partial_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register long phase_reg; register long ph_incr_reg; register sample_type env_scale_reg = susp->env->scale; register sample_block_values_type env_ptr_reg; falloc_sample_block(out, "partial_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the env input sample block: */ susp_check_term_log_samples(env, env_ptr, env_cnt); togo = min(togo, susp->env_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; phase_reg = susp->phase; ph_incr_reg = susp->ph_incr; env_ptr_reg = susp->env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = sine_table[phase_reg >> SINE_TABLE_SHIFT] * (env_scale_reg * *env_ptr_reg++); phase_reg += ph_incr_reg; phase_reg &= SINE_TABLE_MASK;; } while (--n); /* inner loop */ susp->phase = (susp->phase + susp->ph_incr * togo) & SINE_TABLE_MASK; /* using env_ptr_reg is a bad idea on RS/6000: */ susp->env_ptr += togo; out_ptr += togo; susp_took(env_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* partial_s_fetch */ void partial_toss_fetch(susp, snd_list) register partial_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from env up to final_time for this block of zeros */ while ((round((final_time - susp->env->t0) * susp->env->sr)) >= susp->env->current) susp_get_samples(env, env_ptr, env_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->env->t0) * susp->env->sr - (susp->env->current - susp->env_cnt)); susp->env_ptr += n; susp_took(env_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void partial_mark(partial_susp_type susp) { sound_xlmark(susp->env); } void partial_free(partial_susp_type susp) { sound_unref(susp->env); ffree_generic(susp, sizeof(partial_susp_node), "partial_free"); } void partial_print_tree(partial_susp_type susp, int n) { indent(n); stdputstr("env:"); sound_print_tree_1(susp->env, n); } sound_type snd_make_partial(rate_type sr, double hz, sound_type env) { register partial_susp_type susp; /* sr specified as input parameter */ time_type t0 = env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, partial_susp_node, "snd_make_partial"); susp->phase = 0; susp->ph_incr = round((hz * SINE_TABLE_LEN) * (1 << SINE_TABLE_SHIFT) / sr); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(env, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = partial_n_fetch; break; case INTERP_s: susp->susp.fetch = partial_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < env->t0) sound_prepend_zeros(env, t0); /* minimum start time over all inputs: */ t0_min = min(env->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = partial_toss_fetch; } /* initialize susp state */ susp->susp.free = partial_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = partial_mark; susp->susp.print_tree = partial_print_tree; susp->susp.name = "partial"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(env); susp->susp.current = 0; susp->env = env; susp->env_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_partial(rate_type sr, double hz, sound_type env) { sound_type env_copy = sound_copy(env); return snd_make_partial(sr, hz, env_copy); } nyquist-3.05/tran/instrfluteall.alg0000644000175000000620000000314311466723256016521 0ustar stevestaff(INSTRFLUTEALL-ALG ;; parameters are: ;; freq_env -- frequency modulation, aftertouch 128 ;; breath_env -- amplitude envelope, aftertouch 128 ;; vibrato_freq -- vibrato frequency, ModFreq 11 ;; vibrato_gain -- vibrato gain, ModWheel 1 ;; jet_delay -- jet delay, 2 ;; noise -- noise, Noise 4 ;; (NAME "flute_all") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("sound_type" "freq_env") ("double" "vibrato_freq") ("double" "vibrato_gain") ("sound_type" "jet_delay") ("sound_type" "noise") ("rate_type" "sr")) ;; use a constant rate of 1.0 because it will actually be conrolled ;; by breath_env (STATE ("struct instr *" "myflute" "initInstrument(FLUTE, round(sr)); noteOn(susp->myflute, freq, 1.0); controlChange(susp->myflute, 11, FLUTE_CONTROL_CHANGE_CONST * vibrato_freq); controlChange(susp->myflute, 1, FLUTE_CONTROL_CHANGE_CONST * vibrato_gain);") ("double" "frequency" "freq")) (START (min breath_env)) (MATCHED-SAMPLE-RATE freq_env breath_env jet_delay noise) (ALWAYS-SCALE freq_env breath_env jet_delay noise) (CONSTANT "frequency") (SAMPLE-RATE "sr") (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(myflute, 128, FLUTE_CONTROL_CHANGE_CONST * breath_env); controlChange(myflute, 2, FLUTE_CONTROL_CHANGE_CONST * jet_delay); controlChange(myflute, 4, FLUTE_CONTROL_CHANGE_CONST * noise); setFrequency(myflute, frequency + freq_env); output = (sample_type) tick(myflute)") (SUPPORT-HEADER " #define FLUTE_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->myflute); ") ) nyquist-3.05/tran/buzz.h0000644000175000000620000000035410144436365014302 0ustar stevestaffsound_type snd_make_buzz(long n, rate_type sr, double hz, time_type t0, sound_type s_fm); sound_type snd_buzz(long n, rate_type sr, double hz, time_type t0, sound_type s_fm); /* LISP: (snd-buzz FIXNUM ANYNUM ANYNUM ANYNUM SOUND) */ nyquist-3.05/tran/tapv.alg0000644000175000000620000000370610144436365014602 0ustar stevestaff(TAPV-ALG (NAME "tapv") (ARGUMENTS ("sound_type" "s1") ("double" "offset") ("sound_type" "vardelay") ("double" "maxdelay")) (INLINE-INTERPOLATION T) (INTERNAL-SCALING vardelay) (ALWAYS-SCALE s1) (START (MAX s1 vardelay)) (TERMINATE (MIN s1 vardelay)) (LOGICAL-STOP (MIN s1)) (STATE ("double" "offset" "offset * s1->sr") ("double" "vdscale" "vardelay->scale * s1->sr") ("double" "maxdelay" "maxdelay * s1->sr") ("long" "bufflen" "max(2, (long) (susp->maxdelay + 1.5))") ("long" "index" "susp->bufflen") ("sample_type *" "buffer" "(sample_type *) calloc(susp->bufflen + 1, sizeof(sample_type))")) (SAMPLE-RATE (MAX s1)) (CONSTANT "maxdelay" "offset" "vdscale" "buffer") (INNER-LOOP-LOCALS " double phase; long i; ") (INNER-LOOP " phase = vardelay * vdscale + offset; /* now phase should give number of samples of delay */ if (phase < 0) phase = 0; else if (phase > maxdelay) phase = maxdelay; phase = (double) index - phase; /* now phase is a location in the buffer (before modulo) */ /* Time out to update the buffer: * this is a tricky buffer: buffer[0] == buffer[bufflen] * the logical length is bufflen, but the actual length * is bufflen + 1 to allow for a repeated sample at the * end. This allows for efficient interpolation. */ buffer[index++] = s1; if (index > bufflen) { buffer[0] = buffer[bufflen]; index = 1; } /* back to the phase calculation: * use conditional instead of modulo */ if (phase < 0) phase += bufflen; i = (long) phase; /* put integer part in i */ phase -= (double) i; /* put fractional part in phase */ output = (sample_type) (buffer[i] * (1.0 - phase) + buffer[i + 1] * phase);") (FINALIZATION " free(susp->buffer); ") ) nyquist-3.05/tran/pwl.c0000644000175000000620000001126210144436365014105 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "pwl.h" void pwl_free(); typedef struct pwl_susp_struct { snd_susp_node susp; LVAL bpt_ptr; double incr; double lvl; } pwl_susp_node, *pwl_susp_type; /* IMPLEMENTATION NOTE: * The lis argument is a list of alternating sample numbers and values * which are taken in pairs, with an implicit (0, 0) starting point. The * last point is a sample number only, the value being implicitly 0. * The bpt_ptr points to the next sample number in the list. * The incr is set to the increment per sample, and lvl is the next * sample value. * * The list is assumed to be well-formed, so it should be checked by * the caller (users should not call this directly). */ /* compute_lvl -- setup the susp with level, advance bpt_ptr */ /* * returns true if it is time to terminate * * Note: compute_lvl gets called in the outer loop to skip over * a breakpoint pair before starting the compute_incr loop, which * searches for a breakpoint that is some number of samples in the * future. This code is not embedded in compute_incr because it is * NOT called from the initialization, where it would be wrong to * skip over the first breakpoint. */ boolean compute_lvl(pwl_susp_type susp) { if (!cdr(susp->bpt_ptr)) return true; susp->lvl = getflonum(car(cdr(susp->bpt_ptr))); susp->bpt_ptr = cdr(cdr(susp->bpt_ptr)); return !susp->bpt_ptr; } /* compute_incr -- setup the susp with level and increment */ /* * returns true if it is time to terminate */ boolean compute_incr(pwl_susp_type susp, long *n, long cur) { double target; while (*n == 0) { *n = getfixnum(car(susp->bpt_ptr)) - cur; /* if there is a 2nd element of the pair, get the target */ if (cdr(susp->bpt_ptr)) target = getflonum(car(cdr(susp->bpt_ptr))); else target = 0.0; if (*n > 0) susp->incr = (target - susp->lvl) / *n; else if (compute_lvl(susp)) return true; } return false; } void pwl__fetch(register pwl_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double incr_reg; register double lvl_reg; falloc_sample_block(out, "pwl__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; if (susp->bpt_ptr == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } { long cur = susp->susp.current + cnt; long nn = getfixnum(car(susp->bpt_ptr)) - cur; if (nn == 0) { if (compute_lvl(susp) || compute_incr(susp, &nn, cur)) goto out; } togo = min(nn, togo); } n = togo; incr_reg = susp->incr; lvl_reg = susp->lvl; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) lvl_reg; lvl_reg += incr_reg;; } while (--n); /* inner loop */ susp->lvl += susp->incr * togo; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* pwl__fetch */ void pwl_mark(pwl_susp_type susp) { if (susp->bpt_ptr) mark(susp->bpt_ptr); } void pwl_free(pwl_susp_type susp) { ffree_generic(susp, sizeof(pwl_susp_node), "pwl_free"); } void pwl_print_tree(pwl_susp_type susp, int n) { } sound_type snd_make_pwl(time_type t0, rate_type sr, LVAL lis) { register pwl_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, pwl_susp_node, "snd_make_pwl"); susp->bpt_ptr = lis; susp->incr = 0.0; susp->lvl = 0.0; { long temp = 0; compute_incr(susp, &temp, 0); }; susp->susp.fetch = pwl__fetch; /* initialize susp state */ susp->susp.free = pwl_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = pwl_mark; susp->susp.print_tree = pwl_print_tree; susp->susp.name = "pwl"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_pwl(time_type t0, rate_type sr, LVAL lis) { return snd_make_pwl(t0, sr, lis); } nyquist-3.05/tran/fmfbv.h0000644000175000000620000000042011466723256014410 0ustar stevestaffsound_type snd_make_fmfbv(time_type t0, double hz, rate_type sr, sound_type index); sound_type snd_fmfbv(time_type t0, double hz, rate_type sr, sound_type index); /* LISP: (snd-fmfbv ANYNUM ANYNUM ANYNUM SOUND) */ #include "sine.h" /* sine_table and SINE_TABLE_LEN */ nyquist-3.05/tran/sampler.alg0000644000175000000620000000346110144436365015271 0ustar stevestaff(SAMPLER-ALG (NAME "sampler") (ARGUMENTS ("sound_type" "s") ("double" "step") ("double" "loop_start") ("rate_type" "sr") ("double" "hz") ("time_type" "t0") ("sound_type" "s_fm") ("long" "npoints")) (TABLE "s") (NOT-IN-INNER-LOOP "s") (STATE ("double" "loop_to" "loop_start * s->sr") ("table_type" "the_table" "sound_to_table(s)") ("sample_type *" "table_ptr" "susp->the_table->samples") ("double" "table_len" "susp->the_table->length; { long index = (long) susp->loop_to; double frac = susp->loop_to - index; if (index > round(susp->table_len) || index < 0) { index = 0; frac = 0; } susp->table_ptr[round(susp->table_len)] = /* copy interpolated start to last entry */ (sample_type) (susp->table_ptr[index] * (1.0 - frac) + susp->table_ptr[index + 1] * frac);}") ("double" "phase" "0.0") ("double" "ph_incr" "(s->sr / sr) * hz / step_to_hz(step); s_fm->scale = (sample_type) (s_fm->scale * (susp->ph_incr / hz))") ) (ALWAYS-SCALE s_fm) (INLINE-INTERPOLATION T) ; so that modulation can be low frequency (STEP-FUNCTION s_fm) (TERMINATE (MIN s_fm)) (LOGICAL-STOP (MIN s_fm)) (INNER-LOOP-LOCALS " long table_index; double x1; ") (INNER-LOOP "table_index = (long) phase; x1 = table_ptr[table_index]; output = (sample_type) (x1 + (phase - table_index) * (table_ptr[table_index + 1] - x1)); phase += ph_incr + s_fm; while (phase > table_len) phase -= (table_len - loop_to); /* watch out for negative frequencies! */ if (phase < 0) phase = 0") (CONSTANT "ph_incr" "table_len" "table_ptr" "loop_to") (SAMPLE-RATE "sr") (FINALIZATION " table_unref(susp->the_table); ") ) nyquist-3.05/tran/atonev.alg0000644000175000000620000000126710144436365015124 0ustar stevestaff(ATONEV-ALG (NAME "atonev") (ARGUMENTS ("sound_type" "s1") ("sound_type" "hz")) (INLINE-INTERPOLATION T) (LINEAR hz) (ALWAYS-SCALE hz) (START (MAX s1 hz)) (TERMINATE (MIN s1 hz)) (LOGICAL-STOP (MIN s1)) (STATE ("double" "cc" "0.0") ("double" "prev" "0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr))")) (LINEAR s1) (SAMPLE-RATE (MAX s1)) (STEP-FUNCTION hz) (DEPENDS ("bb" "hz" "2.0 - cos(hz)" TEMP "register double") ("cc" "hz" "bb - sqrt((bb * bb) - 1.0)")) (CONSTANT "cc") (INNER-LOOP-LOCALS " double current; ") (INNER-LOOP "current = s1; prev = cc * (prev + current); output = (sample_type) prev; prev -= current;") ) nyquist-3.05/tran/const.alg0000644000175000000620000000037510144436365014755 0ustar stevestaff(CONST-ALG (NAME "const") (ARGUMENTS ("double" "c") ("time_type" "t0") ("rate_type" "sr") ("time_type" "d")) (STATE ("sample_type" "c" "(sample_type) c")) (CONSTANT "c") (TERMINATE (AFTER "d")) (INNER-LOOP "output = c") (SAMPLE-RATE "sr") ) nyquist-3.05/tran/instrsaxall.alg0000644000175000000620000000277410144436365016200 0ustar stevestaff(INSTRSAX-COMPLETE-ALG (NAME "sax_all") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("sound_type" "freq_env") ("double" "vibrato_freq") ("double" "vibrato_gain") ("sound_type" "reed_stiffness") ("sound_type" "noise") ("sound_type" "blow_pos") ("sound_type" "reed_table_offset") ("rate_type" "sr")) (STATE ("struct instr *" "sax" "initInstrument(SAXOFONY, round(sr)); noteOn(susp->sax, freq, 1.0); controlChange(susp->sax, 29, SAX_CONTROL_CHANGE_CONST * vibrato_freq); controlChange(susp->sax, 1, SAX_CONTROL_CHANGE_CONST * vibrato_gain);") ("double" "frequency" "freq")) (START (min breath_env)) (MATCHED-SAMPLE-RATE freq_env breath_env reed_stiffness noise blow_pos reed_table_offset) (CONSTANT "frequency") (ALWAYS-SCALE freq_env breath_env reed_stiffness noise blow_pos reed_table_offset) (SAMPLE-RATE "sr") (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(sax, 128, SAX_CONTROL_CHANGE_CONST * breath_env); controlChange(sax, 2, SAX_CONTROL_CHANGE_CONST * reed_stiffness); controlChange(sax, 4, SAX_CONTROL_CHANGE_CONST * noise); controlChange(sax, 11, SAX_CONTROL_CHANGE_CONST * blow_pos); controlChange(sax, 26, SAX_CONTROL_CHANGE_CONST * reed_table_offset); setFrequency(sax, frequency + freq_env); output = (sample_type) tick(sax)") (SUPPORT-HEADER " #define SAX_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->sax); ") ) nyquist-3.05/tran/gate.alg0000644000175000000620000001523210144436365014545 0ustar stevestaff(GATE-ALG (NAME "gate") (ARGUMENTS ("sound_type" "signal") ("time_type" "lookahead") ("double" "risetime") ("double" "falltime") ("double" "floor") ("double" "threshold")) (START (MIN signal)) (SUPPORT-FUNCTIONS "#define ST_HOLD 0 #define ST_FALL 1 #define ST_FALL_UNTIL 2 #define ST_OFF 3 #define ST_OFF_UNTIL 4 #define ST_RISE 5 /* Overview: This operation generates an exponential rise and decay suitable for implementing a noise gate. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to 1.0 (0dB) at the point the signal crosses the threshold. Again, lookahead is used, so the rise actually starts before the signal crosses the threshold. The rise rate is constant and set so that a rise from floor to 0dB occurs in the specified risetime. Similarly, the fall rate is constant such that a fall from 0dB to the floor takes falltime. Rather than looking ahead, the output actually lags the input by lookahead. The caller should advance the time of the input signal in order to get a correct output signal, and this will be taken care of in Lisp code. The implementation is a finite-state machine that simultaneously computes the value and scans ahead for threshold crossings. Time points, remembered as sample counts are saved in variables: on_count -- the time at which the rise should complete off_count -- the time at which the fall should begin rise_factor -- multiply by this to get exponential rise fall_factor -- multiply by this to get exponential fall rise_time -- number of samples for a full rise fall_time -- number of samples for a full fall floor -- the lowest value to output threshold -- compare the signal s to this value start_rise -- the sample count at which a rise begins delay_len -- number of samples to look ahead, length of buffer state -- the current state of finite state machine (see the individual 'case' statements for description of states) value -- the current output value computing fall_factor: factor ^ (sample_rate * time) == floor log(factor) * sample_rate * time == log(floor) log(factor) == log(floor) / (sample_rate * time) factor == exp(log(floor) / (sample_rate * time)) */ void compute_start_rise(gate_susp_type susp) { /* to compute when to start rise to achieve 0dB at on_count: By similar triangles: truncated rise time truncated fall time ------------------- == ------------------- full rise time full fall time when you enter ST_FALL, set start_fall = now then if (on_count - start_fall) < (rise_time + fall_time) then start rise at on_time - rise_time * (on_count-start_fall)/(rise_time+fall_time) */ long total = (long) (susp->rise_time + susp->fall_time); if ((susp->on_count - susp->start_fall) < total) { susp->start_rise = (long) (susp->on_count - (susp->rise_time * susp->on_count - susp->start_fall) / total); } else susp->start_rise = (long) (susp->on_count - susp->rise_time); } ") (STATE ("double" "rise_time" "signal->sr * risetime + 0.5") ("double" "fall_time" "signal->sr * falltime + 0.5") ("double" "floor" "floor; floor = log(floor);") ("double" "threshold" "threshold") ("long" "on_count" "0") ("long" "off_count" "0") ("double" "rise_factor" "exp(- floor / susp->rise_time)") ("double" "fall_factor" "exp(floor / susp->fall_time)") ("long" "start_fall" "0") ("long" "start_rise" "0") ("long" "stop_count" "0") ("long" "delay_len" "max(1, round(signal->sr * lookahead))") ("int" "state" "ST_OFF") ("double" "value" "susp->floor")) (CONSTANT "lookahead" "rise_time" "fall_time" "floor" "threshold" "delay_len" "end_ptr" "rise_factor" "fall_factor") (NOT-REGISTER delay_buf rise_factor fall_factor rise_time fall_time floor on_count start_fall start_rise) (LINEAR signal) (TERMINATE (MIN signal)) (INNER-LOOP "{ sample_type future = signal; long now = susp->susp.current + cnt + togo - n; switch (state) { /* hold at 1.0 and look for the moment to begin fall: */ case ST_HOLD: if (future >= threshold) { off_count = now + delay_len; } else if (now >= off_count) { state = ST_FALL; stop_count = (long) (now + susp->fall_time); susp->start_fall = now; } break; /* fall until stop_count while looking for next rise time */ case ST_FALL: if (future >= threshold) { off_count = susp->on_count = now + delay_len; compute_start_rise(susp); state = ST_FALL_UNTIL; } else if (now == stop_count) { state = ST_OFF; value = susp->floor; } else value *= susp->fall_factor; break; /* fall until start_rise while looking for next fall time */ case ST_FALL_UNTIL: value *= susp->fall_factor; if (future >= threshold) { off_count = now + delay_len; } if (now >= susp->start_rise) { state = ST_RISE; } else if (now >= stop_count) { state = ST_OFF_UNTIL; value = susp->floor; } break; /* hold at floor (minimum value) and look for next rise time */ case ST_OFF: if (future >= threshold) { off_count = susp->on_count = now + delay_len; compute_start_rise(susp); state = ST_OFF_UNTIL; } break; /* hold at floor until start_rise while looking for next fall time */ case ST_OFF_UNTIL: if (future >= threshold) { off_count = now + delay_len; } if (now >= susp->start_rise) { state = ST_RISE; } break; /* rise while looking for fall time */ case ST_RISE: value *= susp->rise_factor; if (future >= threshold) { off_count = now + delay_len; } if (now >= susp->on_count) { value = 1.0; state = ST_HOLD; } break; } output = (sample_type) value; }") ) nyquist-3.05/tran/delaycc.h0000644000175000000620000000031110144436365014705 0ustar stevestaffsound_type snd_make_delay(sound_type input, time_type delay, double feedback); sound_type snd_delay(sound_type input, time_type delay, double feedback); /* LISP: (snd-delay SOUND ANYNUM ANYNUM) */ nyquist-3.05/tran/allpoles.alg0000644000175000000620000000417610144436365015445 0ustar stevestaff(ALLPOLES-ALG (NAME "allpoles") (ARGUMENTS ("sound_type" "x_snd")("LVAL" "ak_array")("double" "gain")) (START (MIN x_snd)) (NOT-IN-INNER-LOOP "ak_array") (ALWAYS-SCALE x_snd) (TERMINATE (MIN x_snd)) (LOGICAL-STOP (MIN x_snd)) (STATE ("long" "ak_len" "0") ; length of coefs ak array ("LVAL" "ak_array" "ak_array") ("double" "gain" "gain") ("double *" "ak_coefs" "NULL") ; coefs array ("double *" "zk_buf" "NULL") ; last values of output ("long" "index" "0") ) (OUTER-LOOP " if (susp->ak_array == NULL) { togo = 0; /* indicate termination */ break; /* we're done */ } else if (!vectorp(susp->ak_array)) xlerror(\"array expected\", susp->ak_array); else if (susp->ak_coefs == NULL) { long i; susp->ak_len = getsize(susp->ak_array); if (susp->ak_len < 1) xlerror(\"array has not elements\", susp->ak_array); susp->ak_coefs = (double *) calloc(susp->ak_len, sizeof(double)); susp->zk_buf = (double *) calloc(susp->ak_len, sizeof(double)); /* at this point we have a new array and a place to put ak coefs */ for(i=0; i < susp->ak_len; i++) { LVAL elem = getelement(susp->ak_array,i); if (ntype(elem) != FLONUM) { xlerror(\"flonum expected\", elem); } susp->ak_coefs[i] = getflonum(elem); } } ") (CONSTANT "ak_array" "ak_coefs" "ak_len" "gain") (SAMPLE-RATE "x_snd->sr") (INNER-LOOP-LOCALS "double z0; long xi; long xj;") (INNER-LOOP " z0 = x_snd*gain; for (xi=0; xi < ak_len ; xi++) { xj = index + xi; if (xj >= ak_len) xj -= ak_len; z0 += ak_coefs[xi] * zk_buf[xj]; } zk_buf[index] = z0; index++; if (index == ak_len) index = 0; output = (sample_type) z0; ") (FINALIZATION " free(susp->zk_buf); free(susp->ak_coefs); susp->ak_array = NULL; /* free array */ ") ) nyquist-3.05/tran/allpoles.h0000644000175000000620000000030310144436365015115 0ustar stevestaffsound_type snd_make_allpoles(sound_type x_snd, LVAL ak_array, double gain); sound_type snd_allpoles(sound_type x_snd, LVAL ak_array, double gain); /* LISP: (snd-allpoles SOUND ANY ANYNUM) */ nyquist-3.05/tran/fromobject.alg0000644000175000000620000000177510144436365015766 0ustar stevestaff(FROMOBJ-ALG (NAME "fromobject") (ARGUMENTS ("time_type" "t0") ("rate_type" "sr") ("LVAL" "src")) (SUPPORT-FUNCTIONS " /* IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either a * FLONUM sample or NIL. The output of fromobj is simply the * sequence of the samples. */ #include \"samples.h\" ") (SAMPLE-RATE "sr") (STATE ("boolean" "done" "false") ("LVAL" "src" "src")) (OUTER-LOOP " if (susp->done) { togo = 0; /* indicate termination */ break; /* we're done */ } ") (INNER-LOOP " LVAL rslt = xleval(cons(s_send, cons(src, consa(s_next)))); if (floatp(rslt)) { output = (sample_type) getflonum(rslt); } else { done = true; /* adjust togo to what it should have been */ break; }") (CONSTANT "length" "samples" "array" "src") (TERMINATE COMPUTED) ) nyquist-3.05/tran/maxv.c0000644000175000000620000001507410144436365014263 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "maxv.h" void maxv_free(); typedef struct maxv_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type s2; long s2_cnt; sample_block_values_type s2_ptr; } maxv_susp_node, *maxv_susp_type; void maxv_ss_fetch(register maxv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register sample_type s2_scale_reg = susp->s2->scale; register sample_block_values_type s2_ptr_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "maxv_ss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the s2 input sample block: */ susp_check_term_log_samples(s2, s2_ptr, s2_cnt); togo = min(togo, susp->s2_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; s2_ptr_reg = susp->s2_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ double x1 = (s1_scale_reg * *s1_ptr_reg++); double x2 = (s2_scale_reg * *s2_ptr_reg++); *out_ptr_reg++ = (sample_type) (x1 > x2 ? x1 : x2); } while (--n); /* inner loop */ /* using s2_ptr_reg is a bad idea on RS/6000: */ susp->s2_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(s2_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* maxv_ss_fetch */ void maxv_toss_fetch(susp, snd_list) register maxv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from s2 up to final_time for this block of zeros */ while ((round((final_time - susp->s2->t0) * susp->s2->sr)) >= susp->s2->current) susp_get_samples(s2, s2_ptr, s2_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->s2->t0) * susp->s2->sr - (susp->s2->current - susp->s2_cnt)); susp->s2_ptr += n; susp_took(s2_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void maxv_mark(maxv_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->s2); } void maxv_free(maxv_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->s2); ffree_generic(susp, sizeof(maxv_susp_node), "maxv_free"); } void maxv_print_tree(maxv_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("s2:"); sound_print_tree_1(susp->s2, n); } sound_type snd_make_maxv(sound_type s1, sound_type s2) { register maxv_susp_type susp; rate_type sr = max(s1->sr, s2->sr); time_type t0 = max(s1->t0, s2->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; long lsc; falloc_generic(susp, maxv_susp_node, "snd_make_maxv"); susp->susp.fetch = maxv_ss_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < s2->t0) sound_prepend_zeros(s2, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(s2->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = maxv_toss_fetch; } /* initialize susp state */ susp->susp.free = maxv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = maxv_mark; susp->susp.print_tree = maxv_print_tree; susp->susp.name = "maxv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); lsc = logical_stop_cnt_cvt(s2); if (susp->susp.log_stop_cnt > lsc) susp->susp.log_stop_cnt = lsc; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->s2 = s2; susp->s2_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_maxv(sound_type s1, sound_type s2) { sound_type s1_copy = sound_copy(s1); sound_type s2_copy = sound_copy(s2); return snd_make_maxv(s1_copy, s2_copy); } nyquist-3.05/tran/fromobject.c0000644000175000000620000000637610144436365015447 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "fromobject.h" void fromobject_free(); typedef struct fromobject_susp_struct { snd_susp_node susp; boolean done; LVAL src; } fromobject_susp_node, *fromobject_susp_type; /* IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either a * FLONUM sample or NIL. The output of fromobj is simply the * sequence of the samples. */ #include "samples.h" void fromobject__fetch(register fromobject_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register boolean done_reg; register LVAL src_reg; falloc_sample_block(out, "fromobject__fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; if (susp->done) { togo = 0; /* indicate termination */ break; /* we're done */ } n = togo; done_reg = susp->done; src_reg = susp->src; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ LVAL rslt = xleval(cons(s_send, cons(src_reg, consa(s_next)))); if (floatp(rslt)) { *out_ptr_reg++ = (sample_type) getflonum(rslt); } else { done_reg = true; /* adjust togo to what it should have been */ break; }; } while (--n); /* inner loop */ togo -= n; susp->done = done_reg; out_ptr += togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* fromobject__fetch */ void fromobject_mark(fromobject_susp_type susp) { if (susp->src) mark(susp->src); } void fromobject_free(fromobject_susp_type susp) { ffree_generic(susp, sizeof(fromobject_susp_node), "fromobject_free"); } void fromobject_print_tree(fromobject_susp_type susp, int n) { } sound_type snd_make_fromobject(time_type t0, rate_type sr, LVAL src) { register fromobject_susp_type susp; /* sr specified as input parameter */ /* t0 specified as input parameter */ sample_type scale_factor = 1.0F; falloc_generic(susp, fromobject_susp_node, "snd_make_fromobject"); susp->done = false; susp->src = src; susp->susp.fetch = fromobject__fetch; /* initialize susp state */ susp->susp.free = fromobject_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = fromobject_mark; susp->susp.print_tree = fromobject_print_tree; susp->susp.name = "fromobject"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_fromobject(time_type t0, rate_type sr, LVAL src) { return snd_make_fromobject(t0, sr, src); } nyquist-3.05/tran/tonev.c0000644000175000000620000003652410144436365014446 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "tonev.h" void tonev_free(); typedef struct tonev_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type hz; long hz_cnt; sample_block_values_type hz_ptr; /* support for interpolation of hz */ sample_type hz_x1_sample; double hz_pHaSe; double hz_pHaSe_iNcR; /* support for ramp between samples of hz */ double output_per_hz; long hz_n; double scale1; double c2; double c1; double prev; } tonev_susp_node, *tonev_susp_type; void tonev_ns_fetch(register tonev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c2_reg; register double c1_reg; register double prev_reg; register sample_type hz_scale_reg = susp->hz->scale; register sample_block_values_type hz_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tonev_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the hz input sample block: */ susp_check_term_samples(hz, hz_ptr, hz_cnt); togo = min(togo, susp->hz_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c2_reg = susp->c2; c1_reg = susp->c1; prev_reg = susp->prev; hz_ptr_reg = susp->hz_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double b; b = 2.0 - cos((hz_scale_reg * *hz_ptr_reg++)); c2_reg = b - sqrt((b * b) - 1.0); c1_reg = (1.0 - c2_reg) * scale1_reg; *out_ptr_reg++ = (sample_type) (prev_reg = c1_reg * *s1_ptr_reg++ + c2_reg * prev_reg); } while (--n); /* inner loop */ susp->prev = prev_reg; /* using hz_ptr_reg is a bad idea on RS/6000: */ susp->hz_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(hz_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tonev_ns_fetch */ void tonev_ni_fetch(register tonev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c2_reg; register double c1_reg; register double prev_reg; register double hz_pHaSe_iNcR_rEg = susp->hz_pHaSe_iNcR; register double hz_pHaSe_ReG; register sample_type hz_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tonev_ni_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { register double b; susp->started = true; susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); b = 2.0 - cos(susp->hz_x1_sample); susp->c2 = b - sqrt((b * b) - 1.0); susp->c1 = (1.0 - susp->c2) * susp->scale1; } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c2_reg = susp->c2; c1_reg = susp->c1; prev_reg = susp->prev; hz_pHaSe_ReG = susp->hz_pHaSe; hz_x1_sample_reg = susp->hz_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ if (hz_pHaSe_ReG >= 1.0) { /* fixup-depends hz */ register double b; /* pick up next sample as hz_x1_sample: */ susp->hz_ptr++; susp_took(hz_cnt, 1); hz_pHaSe_ReG -= 1.0; susp_check_term_samples_break(hz, hz_ptr, hz_cnt, hz_x1_sample_reg); hz_x1_sample_reg = susp_current_sample(hz, hz_ptr); b = 2.0 - cos(hz_x1_sample_reg); c2_reg = susp->c2 = b - sqrt((b * b) - 1.0); c1_reg = susp->c1 = (1.0 - c2_reg) * scale1_reg; } *out_ptr_reg++ = (sample_type) (prev_reg = c1_reg * *s1_ptr_reg++ + c2_reg * prev_reg); hz_pHaSe_ReG += hz_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->prev = prev_reg; susp->hz_pHaSe = hz_pHaSe_ReG; susp->hz_x1_sample = hz_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tonev_ni_fetch */ void tonev_nr_fetch(register tonev_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type hz_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double scale1_reg; register double c2_reg; register double c1_reg; register double prev_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "tonev_nr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->hz_pHaSe = 1.0; } susp_check_term_samples(hz, hz_ptr, hz_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next hz_x1_sample when phase goes past 1.0; */ /* use hz_n (computed below) to avoid roundoff errors: */ if (susp->hz_n <= 0) { register double b; susp_check_term_samples(hz, hz_ptr, hz_cnt); susp->hz_x1_sample = susp_fetch_sample(hz, hz_ptr, hz_cnt); susp->hz_pHaSe -= 1.0; /* hz_n gets number of samples before phase exceeds 1.0: */ susp->hz_n = (long) ((1.0 - susp->hz_pHaSe) * susp->output_per_hz); b = 2.0 - cos(susp->hz_x1_sample); susp->c2 = b - sqrt((b * b) - 1.0); susp->c1 = (1.0 - susp->c2) * susp->scale1; } togo = min(togo, susp->hz_n); hz_val = susp->hz_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; scale1_reg = susp->scale1; c2_reg = susp->c2; c1_reg = susp->c1; prev_reg = susp->prev; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (prev_reg = c1_reg * *s1_ptr_reg++ + c2_reg * prev_reg); } while (--n); /* inner loop */ susp->prev = prev_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->hz_pHaSe += togo * susp->hz_pHaSe_iNcR; susp->hz_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* tonev_nr_fetch */ void tonev_toss_fetch(susp, snd_list) register tonev_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from hz up to final_time for this block of zeros */ while ((round((final_time - susp->hz->t0) * susp->hz->sr)) >= susp->hz->current) susp_get_samples(hz, hz_ptr, hz_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->hz->t0) * susp->hz->sr - (susp->hz->current - susp->hz_cnt)); susp->hz_ptr += n; susp_took(hz_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void tonev_mark(tonev_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->hz); } void tonev_free(tonev_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->hz); ffree_generic(susp, sizeof(tonev_susp_node), "tonev_free"); } void tonev_print_tree(tonev_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("hz:"); sound_print_tree_1(susp->hz, n); } sound_type snd_make_tonev(sound_type s1, sound_type hz) { register tonev_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, hz->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, tonev_susp_node, "snd_make_tonev"); susp->scale1 = s1->scale; susp->c2 = 0.0; susp->c1 = 0.0; susp->prev = 0.0; hz->scale = (sample_type) (hz->scale * (PI2 / s1->sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(hz, sr); switch (interp_desc) { case INTERP_sn: /* handled below */ case INTERP_ss: /* handled below */ case INTERP_nn: /* handled below */ case INTERP_ns: susp->susp.fetch = tonev_ns_fetch; break; case INTERP_si: /* handled below */ case INTERP_ni: susp->susp.fetch = tonev_ni_fetch; break; case INTERP_sr: /* handled below */ case INTERP_nr: susp->susp.fetch = tonev_nr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < hz->t0) sound_prepend_zeros(hz, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(hz->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = tonev_toss_fetch; } /* initialize susp state */ susp->susp.free = tonev_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = tonev_mark; susp->susp.print_tree = tonev_print_tree; susp->susp.name = "tonev"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->hz = hz; susp->hz_cnt = 0; susp->hz_pHaSe = 0.0; susp->hz_pHaSe_iNcR = hz->sr / sr; susp->hz_n = 0; susp->output_per_hz = sr / hz->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_tonev(sound_type s1, sound_type hz) { sound_type s1_copy = sound_copy(s1); sound_type hz_copy = sound_copy(hz); return snd_make_tonev(s1_copy, hz_copy); } nyquist-3.05/tran/fromarraystream.alg0000644000175000000620000000506210144436365017043 0ustar stevestaff(FRMASTRM-ALG (NAME "fromarraystream") (ARGUMENTS ("time_type" "t0") ("rate_type" "sr") ("LVAL" "src")) (SUPPORT-FUNCTIONS " /* IMPLEMENTATION NOTE: * The src argument is an XLisp object that returns either an * array of samples or NIL. The output of ifft is simply the * concatenation of the samples taken from the array. Later, * an ifft will be plugged in and this will return overlapped * adds of the ifft's. */ #include \"samples.h\" ") (SAMPLE-RATE "sr") (STATE ("long" "index" "0") ; samples index ("long" "length" "0"); samples length ("LVAL" "array" "NULL") ("LVAL" "src" "src") ("sample_type *" "samples" "NULL;")) (OUTER-LOOP " if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if (susp->index >= susp->length) { long i; susp->index = 0; susp->array = xleval(cons(s_send, cons(susp->src, consa(s_next)))); susp->index = 0; if (susp->array == NULL) { susp->src = NULL; goto out; } else if (!vectorp(susp->array)) { xlerror(\"array expected\", susp->array); } else if (susp->samples == NULL) { /* assume arrays are all the same size as first one; now that we know the size, we just have to do this first allocation. */ susp->length = getsize(susp->array); if (susp->length < 1) xlerror(\"array has no elements\", susp->array); susp->samples = (sample_type *) calloc(susp->length, sizeof(sample_type)); } else if (getsize(susp->array) != susp->length) { xlerror(\"arrays must all be the same length\", susp->array); } /* at this point, we have a new array and a place to put samples */ for (i = 0; i < susp->length; i++) { LVAL elem = getelement(susp->array, i); if (ntype(elem) != FLONUM) { xlerror(\"flonum expected\", elem); } susp->samples[i] = (sample_type) getflonum(elem); } susp->array = NULL; /* free the array */ } togo = min(togo, susp->length - susp->index); ") (INNER-LOOP "output = samples[index++];") (CONSTANT "length" "samples" "array" "src") (TERMINATE COMPUTED) (FINALIZATION " free(susp->samples); ") ) nyquist-3.05/tran/stkchorus.c0000644000175000000620000002130511466723256015335 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "stkchorus.h" void stkchorus_free(); typedef struct stkchorus_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; struct stkEffect *mych; } stkchorus_susp_node, *stkchorus_susp_type; #include "stkint.h" void stkchorus_n_fetch(register stkchorus_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct stkEffect * mych_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "stkchorus_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; mych_reg = susp->mych; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (stkEffectTick(mych_reg, *s1_ptr_reg++)) ; } while (--n); /* inner loop */ susp->mych = mych_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* stkchorus_n_fetch */ void stkchorus_s_fetch(register stkchorus_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct stkEffect * mych_reg; register sample_type s1_scale_reg = susp->s1->scale; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "stkchorus_s_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; mych_reg = susp->mych; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) (stkEffectTick(mych_reg, (s1_scale_reg * *s1_ptr_reg++))) ; } while (--n); /* inner loop */ susp->mych = mych_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* stkchorus_s_fetch */ void stkchorus_toss_fetch(susp, snd_list) register stkchorus_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void stkchorus_mark(stkchorus_susp_type susp) { sound_xlmark(susp->s1); } void stkchorus_free(stkchorus_susp_type susp) { deleteStkEffect(susp->mych); sound_unref(susp->s1); ffree_generic(susp, sizeof(stkchorus_susp_node), "stkchorus_free"); } void stkchorus_print_tree(stkchorus_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); } sound_type snd_make_stkchorus(sound_type s1, double baseDelay, double depth, double freq, double mix, rate_type sr) { register stkchorus_susp_type susp; /* sr specified as input parameter */ time_type t0 = s1->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, stkchorus_susp_node, "snd_make_stkchorus"); susp->mych = initStkChorus(baseDelay, depth, freq, round(sr)); stkEffectSetMix(susp->mych, mix); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); switch (interp_desc) { case INTERP_n: susp->susp.fetch = stkchorus_n_fetch; break; case INTERP_s: susp->susp.fetch = stkchorus_s_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = stkchorus_toss_fetch; } /* initialize susp state */ susp->susp.free = stkchorus_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = stkchorus_mark; susp->susp.print_tree = stkchorus_print_tree; susp->susp.name = "stkchorus"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_stkchorus(sound_type s1, double baseDelay, double depth, double freq, double mix, rate_type sr) { sound_type s1_copy = sound_copy(s1); return snd_make_stkchorus(s1_copy, baseDelay, depth, freq, mix, sr); } nyquist-3.05/tran/instrclar.h0000644000175000000620000000037210144436365015311 0ustar stevestaffsound_type snd_make_clarinet(double freq, sound_type breath_env, rate_type sr); sound_type snd_clarinet(double freq, sound_type breath_env, rate_type sr); /* LISP: (snd-clarinet ANYNUM SOUND ANYNUM) */ #define CLAR_CONTROL_CHANGE_CONST 128 nyquist-3.05/tran/stkchorus.alg0000644000175000000620000000113011466723256015650 0ustar stevestaff(STKCHORUS-ALG (NAME "stkchorus") (ARGUMENTS ("sound_type" "s1")("double" "baseDelay")("double" "depth")("double" "freq") ("double" "mix")("rate_type" "sr")) (STATE ("struct stkEffect *" "mych" "initStkChorus(baseDelay, depth, freq, round(sr)); stkEffectSetMix(susp->mych, mix)")) (START (MIN s1)) (TERMINATE (MIN s1)) (LOGICAL-STOP (MIN s1)) (NOT-IN-INNER-LOOP "mych" "baseDelay" "depth" "freq" "mix" "sr") (SAMPLE-RATE "sr") (SUPPORT-FUNCTIONS " #include \"stkint.h\" ") (INNER-LOOP " output = (sample_type) (stkEffectTick(mych, s1)) ") (FINALIZATION " deleteStkEffect(susp->mych); ") )nyquist-3.05/tran/ifft.h0000644000175000000620000000035310144436365014237 0ustar stevestaffsound_type snd_make_ifft(time_type t0, rate_type sr, LVAL src, long stepsize, LVAL window); sound_type snd_ifft(time_type t0, rate_type sr, LVAL src, long stepsize, LVAL window); /* LISP: (snd-ifft ANYNUM ANYNUM ANY FIXNUM ANY) */ nyquist-3.05/tran/instrsax.alg0000644000175000000620000000125610144436365015501 0ustar stevestaff(INSTRSAX-ALG (NAME "sax") (ARGUMENTS ("double" "freq") ("sound_type" "breath_env") ("rate_type" "sr")) (STATE ("struct instr *" "sax" "initInstrument(SAXOFONY, round(sr)); controlChange(susp->sax, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->sax, freq, 1.0)")) (START (min breath_env)) (NOT-IN-INNER-LOOP "freq" "temp_ret_value") (SAMPLE-RATE "sr") (TERMINATE (min breath_env)) (INNER-LOOP " controlChange(sax, 128, SAX_CONTROL_CHANGE_CONST * breath_env); output = (sample_type) tick(sax)") (SUPPORT-HEADER " #define SAX_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->sax); ") ) nyquist-3.05/tran/translate-stk.lsp0000644000175000000620000000051411466723256016457 0ustar stevestaff(translate "stkrev") (translate "stkpitshift") (translate "stkchorus") (translate "instrbow") (translate "instrbowedfreq") (translate "instrbanded") (translate "instrmandolin") (translate "instrsitar") (translate "instrmodalbar") (translate "instrflute") (translate "instrflutefreq") (translate "instrfluteall") nyquist-3.05/tran/upsample.h0000644000175000000620000000022110144436365015127 0ustar stevestaffsound_type snd_make_up(rate_type sr, sound_type input); sound_type snd_up(rate_type sr, sound_type input); /* LISP: (snd-up ANYNUM SOUND) */ nyquist-3.05/tran/instrsitar.h0000644000175000000620000000033111466723256015513 0ustar stevestaffsound_type snd_make_sitar(time_type t0, double freq, time_type dur, rate_type sr); sound_type snd_sitar(time_type t0, double freq, time_type dur, rate_type sr); /* LISP: (snd-sitar ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/alpass.alg0000644000175000000620000000155010144436365015106 0ustar stevestaff(ALPASS-ALG (NAME "alpass") (ARGUMENTS ("sound_type" "input") ("time_type" "delay") ("double" "feedback")) (START (MIN input)) (STATE ("double" "feedback" "feedback") ("long" "delaylen" "max(1, round(input->sr * delay))") ("sample_type *" "delaybuf" "(sample_type *) calloc (susp->delaylen, sizeof(sample_type))") ("sample_type *" "delayptr" "susp->delaybuf") ("sample_type *" "endptr" "susp->delaybuf + susp->delaylen")) (CONSTANT "feedback" "delaylen" "endptr") (NOT-REGISTER delaybuf) (LINEAR input) (TERMINATE (MIN input)) (INNER-LOOP-LOCALS "register sample_type y, z;\n") (INNER-LOOP " y = *delayptr; *delayptr++ = z = (sample_type) (feedback * y + input); output = (sample_type) (y - feedback * z); if (delayptr >= endptr) delayptr = susp->delaybuf;") (FINALIZATION "free(susp->delaybuf);") ) nyquist-3.05/tran/fromobject.h0000644000175000000620000000027210144436365015441 0ustar stevestaffsound_type snd_make_fromobject(time_type t0, rate_type sr, LVAL src); sound_type snd_fromobject(time_type t0, rate_type sr, LVAL src); /* LISP: (snd-fromobject ANYNUM ANYNUM ANY) */ nyquist-3.05/tran/coterm.h0000644000175000000620000000023010144436365014572 0ustar stevestaffsound_type snd_make_coterm(sound_type s1, sound_type s2); sound_type snd_coterm(sound_type s1, sound_type s2); /* LISP: (snd-coterm SOUND SOUND) */ nyquist-3.05/tran/integrate.c0000644000175000000620000001366710144436365015300 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "integrate.h" void integrate_free(); typedef struct integrate_susp_struct { snd_susp_node susp; long terminate_cnt; boolean logically_stopped; sound_type input; long input_cnt; sample_block_values_type input_ptr; double integral; } integrate_susp_node, *integrate_susp_type; void integrate_n_fetch(register integrate_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double integral_reg; register sample_block_values_type input_ptr_reg; falloc_sample_block(out, "integrate_n_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the input input sample block: */ susp_check_term_log_samples(input, input_ptr, input_cnt); togo = min(togo, susp->input_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; integral_reg = susp->integral; input_ptr_reg = susp->input_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ *out_ptr_reg++ = (sample_type) integral_reg; integral_reg += *input_ptr_reg++;; } while (--n); /* inner loop */ susp->integral = integral_reg; /* using input_ptr_reg is a bad idea on RS/6000: */ susp->input_ptr += togo; out_ptr += togo; susp_took(input_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* integrate_n_fetch */ void integrate_toss_fetch(susp, snd_list) register integrate_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from input up to final_time for this block of zeros */ while ((round((final_time - susp->input->t0) * susp->input->sr)) >= susp->input->current) susp_get_samples(input, input_ptr, input_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->input->t0) * susp->input->sr - (susp->input->current - susp->input_cnt)); susp->input_ptr += n; susp_took(input_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void integrate_mark(integrate_susp_type susp) { sound_xlmark(susp->input); } void integrate_free(integrate_susp_type susp) { sound_unref(susp->input); ffree_generic(susp, sizeof(integrate_susp_node), "integrate_free"); } void integrate_print_tree(integrate_susp_type susp, int n) { indent(n); stdputstr("input:"); sound_print_tree_1(susp->input, n); } sound_type snd_make_integrate(sound_type input) { register integrate_susp_type susp; rate_type sr = input->sr; time_type t0 = input->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (INPUT) */ scale_factor *= input->scale; input->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (input->sr < sr) { input->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, integrate_susp_node, "snd_make_integrate"); susp->integral = 0.0; scale_factor = (sample_type) (scale_factor / input->sr); susp->susp.fetch = integrate_n_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < input->t0) sound_prepend_zeros(input, t0); /* minimum start time over all inputs: */ t0_min = min(input->t0, t0); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = integrate_toss_fetch; } /* initialize susp state */ susp->susp.free = integrate_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = integrate_mark; susp->susp.print_tree = integrate_print_tree; susp->susp.name = "integrate"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(input); susp->susp.current = 0; susp->input = input; susp->input_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_integrate(sound_type input) { sound_type input_copy = sound_copy(input); return snd_make_integrate(input_copy); } nyquist-3.05/tran/writemake.lsp0000644000175000000620000010362510144436365015654 0ustar stevestaff;;************ ;; writemake.lsp -- generate the sound create routine ;;************ ;;************ ;; Change Log ;; Date | Change ;;-----------+-------------------- ;; 17-Dec-91 | [1.1] Created ;; 17-Dec-91 | [1.1] return sound_create(...) cast type to correct ;; | type ;; 21-Dec-91 | [1.2] added start-time, default 0.0 ;; 21-Dec-91 | [1.2] prefix creation local variables with C_ ;; 13-Jan-92 | [1.2] reformatted and recommented ;; 3-May-99 | modified toss_fetch code to retain proper t0 ;;************ ;; check-for-no-interpolation - if you see an "s", make sure there ;; is a corresponding "n", if not use "s" to cover the "n" case. And vice versa. ;; (defun check-for-no-interpolation (encoding interpolation-rationale stream) ; *cfni-output* used to keep track of newline output (setf *cfni-output* nil) (check-for-no-interpolation-1 encoding 0 interpolation-rationale stream)) ;; Hint: this algorithm constructs the 2^n variations by substituting ;; (or not) 'n' for 's' whereever s'es occur. The search is cut off ;; however, when an altered string is found in the encoding-list, which ;; tells what cases are handled directly. ;; ;; Wow, returning to the description above after several months, I couldn't make ;; heads or tails of it, and I wrote it! Here's another perhaps better, description: ;; ;; We generated various _fetch routines that differ in their assumptions about how to ;; access signal arguments. There are (now) 4 variations: NONE, SCALE, INTERP, and ;; RAMP. All 4^N combinations of these are generated initially, but many combinations ;; are deleted before any code is generated. Reasons for removing a combination include ;; the use of symetry, linearity, and simply the promise that input arguments will be ;; interpolated externally. In most of these cases, combinations are removed because ;; they cannot occur in practice. But in others, combinations are removed because they ;; should be handled by different code. For example, an input signal matching the output ;; sample rate and with a scale factor of 1 is normally handled by NONE style ;; "interpolation". Note: "interpolation" is used throughout this code, but a better term ;; would be "access method," because no interpolation is involved in the NONE and ;; SCALE variants. The inner loop access code for NONE style is something like "*s++". ;; However, an input signal suitable for NONE style interpolation can also be handled ;; by SCALE style interpolation (which looks something like "(*s++ * s_scale)", i.e. ;; an extra multiplication is required. If the attribute INTERNAL-SCALING is used, ;; then the scale factor does not actually appear at the access point because it has been ;; factored into a filter coefficient or some other factor, saving the multiply. ;; Alternatively, the ALWAYS-SCALE attribute can specify that there is little to be ;; gained by saving a multiply. In these cases, we want to handle NONE style signals ;; with SCALE style interpolation. Let's run through these possibilities again and ;; describe how they are handled: ;; ;; ALWAYS-SCALE: here we delete the NONE variant(s) and only generate fetch ;; routines that have scaling code in them. When we get an actual parameter with ;; a scale factor of 1 (implying NONE interpolation), we handle it with the SCALE ;; fetch routine. ;; INTERNAL-SCALING: here we generate NONE fetch routines because the ;; scale factor is taken care of elsewhere in the code, e.g. in a filter coefficient. ;; LINEAR: here, the scale factor of the actual argument becomes a scale factor ;; on the output (part of the data structure), deferring multiplies until later. We ;; then modify the argument scale factor to 1, and NONE style interpolation applies. ;; There is no need to generate SCALE style routines, because there will never be ;; any need for them. ;; ;; For a given signal parameter, these 3 cases are mutually exclusive. ;; ;; Looking at these three cases, we see that sometimes there will be SCALE style ;; routines handling NONE arguments, sometimes NONE style routines handling ;; SCALE arguments, and sometimes NONE style routines because there will ;; never be a need for SCALE. ;; This code is going to generate labels so that other fetch routines ;; handle the "missing" ones. ;; To do this, we generate extra labels in the case ;; statement that selects the fetch routine (interpolation is in the inner loop in the ;; fetch routine. For example, we might generate this code: ;; ... ;; case INTERP_nn: ;; case INTERP_sn: ;; case INTERP_ns: ;; case INTERP_ss: susp->susp.fetch = tonev_ss_fetch; break; ;; ... ;; Here, a single fetch routine (tonev_ss_fetch) handles all variations of NONE and ;; SCALE (n and s) types of the two signal arguments. The basic rule is: if you did not ;; generate a fetch routine for the NONE case, then handle it with the SCALE case, and ;; if you did not generate a fetch routine for the SCALE case, handle it with the NONE ;; case. ;; ;; The algorithm uses the list interpolation-rationale, which lists for each sound ;; parameter one of {NIL, LINEAR, ALWAYS-SCALE, INTERNAL-SCALING}. ;; Using this list, the code enumerates all the possible cases that might be handled ;; by the current fetch routine (represented by the "encoding" parameter). ;; This is a recursive algorithm because, if there are n SCALE type parameters, then ;; there are 2^N possible variations to enumerate. (E.g. look at the 4 variations in ;; the code example above.) ;; ;; (defun check-for-no-interpolation-1 (encoding index interpolation-rationale stream) (cond ((= index (length encoding)) (display "check-for-no-interpolation output" encoding) ; see if we need a newline (*cfni-output* is initially nil) (if *cfni-output* (format stream "/* handled below */~%")) (setf *cfni-output* t) (format stream " case INTERP_~A: " encoding)) (t (let ((ch (char encoding index))) (display "cfni" index ch) (cond ((eql ch #\s) (let ((new-encoding (strcat (subseq encoding 0 index) "n" (subseq encoding (1+ index))))) (cond ((eq (nth index interpolation-rationale) 'ALWAYS-SCALE) (check-for-no-interpolation-1 new-encoding (1+ index) interpolation-rationale stream))))) ((eql ch #\n) (let ((new-encoding (strcat (subseq encoding 0 index) "s" (subseq encoding (1+ index))))) (cond ((eq (nth index interpolation-rationale) 'INTERNAL-SCALING) (check-for-no-interpolation-1 new-encoding (1+ index) interpolation-rationale stream)))))) (check-for-no-interpolation-1 encoding (1+ index) interpolation-rationale stream))))) ;;************ ;; is-argument -- see if string is in argument list ;; ;;************ (defun is-argument (arg arguments) (dolist (a arguments) (cond ((equal arg (cadr a)) (return t))))) ;; needs-mark-routine -- is there anything for GC to mark here? ;; (defun needs-mark-routine (alg) (or (get-slot alg 'sound-names) (get-slot alg 'xlisp-pointers))) ;; lsc-needed-p -- see if we need the lsc variable declared (defun lsc-needed-p (alg) (let ((spec (get-slot alg 'logical-stop))) (and spec (listp (car spec)) (eq (caar spec) 'MIN) (cdar spec) (cddar spec)))) ;; write-initial-logical-stop-cnt -- writes part of snd_make_ ;; (defun write-initial-logical-stop-cnt (alg stream) (let ((spec (get-slot alg 'logical-stop)) min-list) (cond ((and spec (listp (car spec)) (eq (caar spec) 'MIN) (cdar spec)) (setf min-list (cdar spec)) ; take stop_cnt from first argument in MIN list (format stream " susp->susp.log_stop_cnt = logical_stop_cnt_cvt(~A);\n" (symbol-to-name (cadar spec))) ; modify stop_cnt to be minimum over all remaining arguments (dolist (sym (cddar spec)) (let ((name (symbol-to-name sym))) (format stream " lsc = logical_stop_cnt_cvt(~A);\n" name) (format stream " if (susp->susp.log_stop_cnt > lsc)\n" name) (format stream " susp->susp.log_stop_cnt = lsc;\n" name)))) (t (format stream " susp->susp.log_stop_cnt = UNKNOWN;\n"))) )) ;;************ ;; write-mark ;; ;; Inputs: ;; alg - algorithm description ;; stream - stream on which to write .c file ;; Effect: ;; writes NAME_mark(...) ;;************ (defun write-mark (alg stream) (let ((name (get-slot alg 'name)) (sound-names (get-slot alg 'sound-names)) (xlisp-pointers (get-slot alg 'xlisp-pointers))) ;---------------- ; void NAME_mark(NAME_susp_type susp) ; { ; *WATCH*: printf("NAME_mark(%x)\n", susp); ;---------------- (format stream "~%~%void ~A_mark(~A_susp_type susp)~%{~%" name name) (if *WATCH* (format stream " printf(\"~A_mark(%x)\\n\", susp);~%" name)) ;---------------- ; for each LVAL argument: ; ; if (susp->NAME) mark(susp->NAME); ;---------------- (dolist (name xlisp-pointers) (format stream " if (susp->~A) mark(susp->~A);~%" name name)) ;---------------- ; for each sound argument: ; ; *WATCH*: printf("marking SND@%x in NAME@%x\n", susp->snd, susp); ; sound_xlmark(susp->NAME); ;---------------- (dolist (snd sound-names) (if *watch* (format stream " printf(\"marking ~A@%x in ~A@%x\\n\", susp->~A, susp);~%" snd name snd)) (format stream " sound_xlmark(susp->~A);~%" snd)) ;---------------- ; } ;---------------- (format stream "}~%"))) (print 'write-mark) ;;************ ;; write-make ;; ;; Inputs: ;; alg - algorithm description ;; stream - stream on which to write .c file ;; Effect: ;; writes NAME_free(...), NAME_print_tree, and snd_make_NAME(...) ;;************ (defun write-make (alg stream) (let ((name (get-slot alg 'name)) (sr (get-slot alg 'sample-rate)) (else-prefix "") first-time (sound-names (get-slot alg 'sound-names)) (logical-stop (car (get-slot alg 'logical-stop))) (sound-to-name (get-slot alg 'sound-to-name)) (state-list (get-slot alg 'state)) (linear (get-slot alg 'linear)) (arguments (get-slot alg 'arguments)) (finalization (get-slot alg 'finalization)) (interpolation-list (get-slot alg 'interpolation-list)) (interpolation-rationale (get-slot alg 'interpolation-rationale)) encoding-list (terminate (car (get-slot alg 'terminate))) (type-check (car (get-slot alg 'type-check))) (delay (get-slot alg 'delay)) (start (get-slot alg 'start))) ;-------------------- ; void NAME_free(NAME_susp_type susp) ; { ;---------------- (format stream "~%~%void ~A_free(~A_susp_type susp)~%{~%" name name) ;---------------- ; if there's a finalization, do it ;---------------- (if finalization (print-strings finalization stream)) ;---------------- ; for each sound argument: ; ; sound_unref(susp->NAME); ;---------------- (dolist (name sound-names) (format stream " sound_unref(susp->~A);~%" name)) ;---------------- ; ffree_generic(susp, sizeof(NAME_susp_node), "fn-name"); ; } ;-------------------- (format stream " ffree_generic(susp, sizeof(~A_susp_node), \"~A_free\");~%}~%" name name) ;-------------------- ; void NAME_print_tree(NAME_susp_type susp, int n) ; { ;---------------- (format stream "~%~%void ~A_print_tree(~A_susp_type susp, int n)~%{~%" name name) ;---------------- ; for each sound argument: ; ; indent(n); ; printf("NAME:"); ; sound_print_tree_1(susp->NAME, n); ;---------------- (setf first-time t) (dolist (name sound-names) (cond (first-time (setf first-time nil)) (t ; space between each iteration (format stream "~%"))) (format stream " indent(n);~% stdputstr(\"~A:\");~%" name) (format stream " sound_print_tree_1(susp->~A, n);~%" name)) ;---------------- ; } ;-------------------- (format stream "}~%") ;-------------------- ; sound_type snd_make_NAME ;-------------------- (format stream "~%~%sound_type snd_make_~A" name) ;-------------------- ; ( type name, ...) ;-------------------- (write-ansi-parameter-list stream "" arguments) (format stream "~%") (if (not *ANSI*) (dolist (arg arguments) (format stream " ~A ~A;~%" (car arg) (cadr arg)))) ;-------------------- ; NAME_susp_type susp; ;-------------------- (format stream "{~% register ~A_susp_type susp;~%" name); ;; declare "state" variables with TEMP flag ;-------------------- ; ; ;-------------------- (dolist (state state-list) (cond ((and (cdddr state) (cadddr state) (eq (cadddr state) 'TEMP)) (format stream " ~A ~A;~%" (car state) (cadr state))))) (write-sample-rate stream sr sound-names arguments) ; compute the t0 for new signal (default: use zero): ; (write-start-time stream start arguments) ;-------------------- ; int interp_desc = 0; ;-------------------- (cond (interpolation-list (format stream " int interp_desc = 0;~%"))) ;-------------------- ; sample_type scale_factor = 1.0F; ; time_type t0_min; -- but only if there are sound args, implied by non-null sound-names ; long lsc; ;-------------------- (format stream " sample_type scale_factor = 1.0F;~%") (if sound-names (format stream " time_type t0_min = t0;~%")) (if (lsc-needed-p alg) (format stream " long lsc;~%")) ; now do canonical ordering of commutable sounds ; (dolist (lis (get-slot alg 'commutative)) ;-------------------- ; /* sort commuative signals: s1 s2 ... */ ; snd_sort_ ; (...) ;-------------------- (format stream " /* sort commutative signals: ~A */~%" lis) (format stream " snd_sort_~A" (length lis)) (write-parameter-list stream "" (append (mapcar '(lambda (snd) (strcat "&" (cdr (assoc snd sound-to-name)))) lis) '("sr"))) (format stream ";~%~%")) ; figure scale factor -- if signal is linear wrt some interpolated or ; ramped signal (which do the multiply anyway), then put the scale ; factor there. ;-------------------- ; /* combine scale factors of linear inputs */ ;-------------------- (cond (linear (format stream " /* combine scale factors of linear inputs ~A */~%" linear))) ;-------------------- ; scale_factor *= NAME ->scale; ; NAME ->scale = 1.0F; ;-------------------- (dolist (snd linear) (let ((name (cdr (assoc snd sound-to-name)))) (format stream " scale_factor *= ~A->scale;~%" name) (format stream " ~A->scale = 1.0F;~%" name))) ;-------------------- ; /* try to push scale_factor back to a low sr input */ ;-------------------- (cond (linear (format stream "~% /* try to push scale_factor back to a low sr input */~%"))) ;-------------------- ; if (NAME ->sr < sr) { ; NAME ->scale = scale_factor; scale_factor = 1.0F; } ;-------------------- (dolist (snd linear) (let ((name (cdr (assoc snd sound-to-name)))) (format stream " ~Aif (~A->sr < sr) { ~A->scale = scale_factor; scale_factor = 1.0F; }~%" else-prefix name name) (setf else-prefix "else "))) (if linear (format stream "~%")) ;------------------- ; insert TYPE-CHECK code here ;------------------- (display "write-make" type-check) (if type-check (format stream type-check)) ;-------------------- ; falloc_generic(susp, NAME_susp_node, "fn-name"); ;-------------------- (format stream " falloc_generic(susp, ~A_susp_node, \"snd_make_~A\");~%" name name) ;; initialize state: the state list has (type field initialization [temp]) ;-------------------- ; susp-> = ;-------------------- ;; if TEMP is present, generate: ;-------------------- ; = ;-------------------- (dolist (state state-list) (let ((prefix "susp->")) (cond ((and (cdddr state) (cadddr state) (eq (cadddr state) 'TEMP)) (setf prefix ""))) (format stream " ~A~A = ~A;~%" prefix (cadr state) (caddr state)))) ; if we have a choice of implementations, select one (cond ((< 1 (length interpolation-list)) ;-------------------- ; /* select a susp fn based on sample rates */ ;-------------------- ; build a descriptor (format stream "~% /* select a susp fn based on sample rates */~%") ;------------------------ ; interp_desc = (interp_desc << 2) + interp_style( NAME, sr); ;------------------------ (dolist (snd sound-names) (format stream " interp_desc = (interp_desc << 2) + interp_style(~A, sr);~%" snd)) ;-------------------- ; switch (interp_desc) { ;-------------------- (cond (interpolation-list (format stream " switch (interp_desc) {~%"))) ;-------------------------- ; case INTERP_: susp->susp.fetch = ; NAME__fetch; break; ;-------------------------- (setf encoding-list (mapcar #'encode interpolation-list)) (dolist (encoding encoding-list) (check-for-no-interpolation encoding interpolation-rationale stream) (format stream "susp->susp.fetch = ~A_~A_fetch; break;~%" name encoding)) ;-------------------------- ; default: snd_badsr(); break; ;-------------------------- (format stream " default: snd_badsr(); break;~%") ;-------------------- ; } /* initialize susp state */ ;------------------------- (format stream " }~%~%")) (interpolation-list (format stream " susp->susp.fetch = ~A_~A_fetch;~%" name (encode (car interpolation-list)))) (t ;------------------------- ; susp->susp.fetch = NAME__fetch; ;------------------------- (format stream " susp->susp.fetch = ~A__fetch;~%~%" name))) ;---------------- ; /* compute terminate count */ ;---------------- (cond ((terminate-check-needed terminate alg) (cond ((eq (car terminate) 'AT) (let ((time-expr (cadr terminate))) ;---------------- ; susp->terminate_cnt = round(((TIME-EXPR) - t0) * sr); ;---------------- (format stream " susp->terminate_cnt = round(((~A) - t0) * sr);~%" time-expr))) ((eq (car terminate) 'AFTER) (let ((dur-expr (cadr terminate))) ;---------------- ; susp->terminate_cnt = round((DUR-EXPR) * sr); ;---------------- (format stream " susp->terminate_cnt = round((~A) * sr);~%" dur-expr))) (t ;---------------- ; susp->terminate_cnt = UNKNOWN; ;---------------- (format stream " susp->terminate_cnt = UNKNOWN;~%"))))) ;---------------- ; /* handle unequal start times, if any */ ;---------------- (if sound-names (format stream " /* handle unequal start times, if any */~%")) ;---------------- ; for each sound argument: ; if (t0 < NAME->t0) sound_prepend_zeros(NAME, t0); ;---------------- (dolist (name sound-names) (format stream " if (t0 < ~A->t0) sound_prepend_zeros(~A, t0);~%" name name)) ;---------------- ; t0_min = min(NAME1->t0, min(NAME2->t0, ... NAMEn->t0, t0)...); ;---------------- (cond (sound-names (format stream " /* minimum start time over all inputs: */~%") (format stream " t0_min = ") (dolist (name sound-names) (format stream "min(~A->t0, " name)) (format stream "t0") (dolist (name sound-names) (format stream ")")) (format stream ";~%"))) ;---------------- ; /* how many samples to toss before t0: */ ; susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + .5); ; if (susp->susp.toss_cnt > 0) { ; susp->susp.keep_fetch = susp->susp.fetch; ; susp->susp.fetch = NAME_toss_fetch; ; t0 = t0_min; -- DELETED 3MAY99 by RBD ; } ;---------------- (cond (sound-names (format stream " /* how many samples to toss before t0: */\n") (if delay (format stream " /* Toss an extra ~A samples to make up for internal buffering: */\n" delay)) (format stream " susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + ~A.5);\n" (if delay delay 0)) (format stream " if (susp->susp.toss_cnt > 0) {\n") (format stream "\tsusp->susp.keep_fetch = susp->susp.fetch;\n") (format stream "\tsusp->susp.fetch = ~A_toss_fetch;~%" name) ; (format stream "\tt0 = t0_min;~% }\n\n"))) (format stream " }\n\n"))) ;-------------------- ; /* initialize susp state */ ; susp->susp.free = NAME_free; ; susp->susp.sr = sr; ; susp->susp.t0 = t0; ;-------------------- (format stream " /* initialize susp state */~%") (format stream " susp->susp.free = ~A_free;~%" name) (format stream " susp->susp.sr = sr;~%") (format stream " susp->susp.t0 = t0;~%") ;---------------- ; if there are sound arguments: ; susp->susp.mark = NAME_mark; ; otherwise... ; susp->susp.mark = NULL; ;---------------- (let ((value "NULL")) (cond ((needs-mark-routine alg) (setf value (strcat name "_mark")))) (format stream " susp->susp.mark = ~A;~%" value)) ;---------------- ; for debugging... ; susp->susp.print_tree = NAME_print_tree; ; susp->susp.name = "NAME"; ;---------------- (format stream " susp->susp.print_tree = ~A_print_tree;~%" name) (format stream " susp->susp.name = \"~A\";~%" name) ;---------------- ; if there is a logical stop attribute: ; susp->logically_stopped = false; ; susp->susp.log_stop_cnt = UNKNOWN; ;---------------- (cond ((logical-stop-check-needed logical-stop) (format stream " susp->logically_stopped = false;\n"))) (write-initial-logical-stop-cnt alg stream) ;-------------------- ; ramped or interpolated: ; ; susp->started = false; ;-------------------- (cond ((any-ramp-or-interp-in interpolation-list) (format stream " susp->started = false;~%"))) ;-------------------- ; susp->susp.current = 0; ;-------------------- (format stream " susp->susp.current = 0;~%") ;---------------------------- ; For each sound arg: ; ; susp-> = ; ; susp-> _cnt = 0; ;---------------------------- (dotimes (n (length (get alg 'sound-args))) (let ((interpolation (union-of-nth interpolation-list n))) (setf arg (nth n sound-names)) ; get name of signal (format stream " susp->~A = ~A;~%" arg arg) (format stream " susp->~A_cnt = 0;~%" arg) ;----------------------------------------------- ; Interpolation: ; ; susp-> _pHaSe = 0.0; ; susp-> _pHaSe_iNcR = ->sr ;----------------------------------------------- (cond ((member 'INTERP interpolation) (format stream " susp->~A_pHaSe = 0.0;~%" arg) (format stream " susp->~A_pHaSe_iNcR = ~A->sr / sr;~%" arg arg))) ;----------------------------------------------- ; Ramp: ; ; susp->output_per_ = ->sr; ;----------------------------------------------- (cond ((member 'RAMP interpolation) (format stream " susp->~A_n = 0;~%" arg) (format stream " susp->output_per_~A = sr / ~A->sr;~%" arg arg))))) ;---------------------------- ; return sound_create (snd_susp_type)susp, t0, sr, scale_factor); ;---------------------------- (format stream " return sound_create((snd_susp_type)susp, t0, sr, scale_factor);~%}~%"))) (print 'write-make) ;;************ ;; write-parameter-list -- with comma separator, open and close parens ;; ;;************ (defun write-parameter-list (stream prefix strings) (let ((comma "")) (format stream "(") (dolist (parm strings) (format stream "~A~A~A" comma prefix parm) (setf comma ", ")) (format stream ")"))) ;;************ ;; write-ansi-prototype-list -- with comma separator, open and close parens ;; ;; Inputs: ;; stream - output stream ;; prefix - arg prefix, perhaps "" ;; args - argument type/name pairs of the form ;; ( (type1 name1) (type2 name2) ... ) ;; Effect: ;; if *ANSI* is set T, writes ANSI-style parameter list of the form ;; type name, ... ;; if *ANSI* is set NIL, writes antique-style parameter list of the form ;; () ;;************ (defun write-ansi-prototype-list (stream prefix args) (let ((comma "")) (format stream "(") (if *ANSI* (dolist (parm args) ;-------------------- ; for each parameter ; type ;-------------------- (format stream "~A~A ~A~A" comma (car parm) prefix (cadr parm)) (setf comma ", ")) ) (format stream ")"))) ;;************ ;; write-ansi-parameter-list ;; ;; Inputs: ;; stream - output stream ;; prefix - arg prefix, perhaps "" ;; args - argument type/name pairs of the form ;; ( (type1 name1) (type2 name2) ... ) ;; Effect: ;; if *ANSI* is set T, writes ANSI-style parameter list of the form ;; (type name, ...) ;; if *ANSI* is set NIL, writes antique-style parameter list of the form ;; (name, ...) ;; Note: ;; to get a space between types and arguments, a space is prepended to prefix if ;; this is an *ANSI* arg list. ;;************ (defun write-ansi-parameter-list (stream prefix args) (let ((comma "")) (format stream "(") (cond (*ANSI* (setf prefix (strcat " " prefix)))) (dolist (parm args) (format stream "~A~A~A~A" comma (if *ANSI* (car parm) "") prefix (cadr parm)) (setf comma ", ") ) (format stream ")"))) ;;************ ;; write-sample-rate ;; Effect: ;; declare sr and compute the sample rate for the new signal ;; Notes: ;; If sr is an input parameter, it is not declared ;; If (SAMPLE-RATE expr) is specified, declare sr to be initialized ;; to the expr ;; If (SAMPLE-RATE (MAX s1 s2 ...)), sr is initialized to the max. ;; Otherwise, sr is initialized to the max of the sample rates of ;; all the sound-type arguments ;;************ (defun write-sample-rate (stream sr sound-names arguments) ;; if sr is "sr" and "sr" is a parameter, then do nothing: (display "write-sample-rate: " sr sound-names arguments) (cond ( (and (equal sr "sr") (is-argument "sr" arguments)) ;--------------------- ; /* sr specified as input parameter */ ;--------------------- (format stream " /* sr specified as input parameter */~%") ) ;; else if sample rate is specified, use it to initialize sr: ((stringp sr) (display "write-sample-rate: using specified sr" sr) ;--------------------- ; rate_type sr = ; ;--------------------- (format stream " rate_type sr = ~A;~%" sr) ) ;; else look for (MAX ...) expression ((and (listp sr) (eq (car sr) 'MAX)) (format stream " rate_type sr = ") (write-redux-of-names stream "max" (mapcar #'symbol-to-name (cdr sr)) "->sr") (format stream ";~%") ) ;; else assume sr is max of sr's of all sound arguments (sound-names ;--------------------- ; rate_type sr = max( ->sr, ->sr); ;--------------------- (format stream " rate_type sr = ") ; jmn (write-redux-of-names stream "max" sound-names "->sr") (format stream ";~%") ) (t (error "Missing SAMPLE-RATE specification.")) ) ) (defun write-redux-of-names (stream fn sound-names suffix) (dotimes (n (1- (length sound-names))) (format stream "~A(" fn)) (format stream "~A~A" (car sound-names) suffix) (dolist (snd (cdr sound-names)) (format stream ", ~A~A)" snd suffix))) ;;************ ;; write-start-time ;; Effect: ;; declare sr and compute the start time for the new signal ;; Notes: ;; If t0 is an input parameter, it is not declared ;; If (START (AT expr)) is specified, declare t0 to be initialized ;; to the expr ;; Otherwise, t0 is initialized to 0 ;;************ (defun write-start-time (stream start arguments) ;; if t0 is "t0" and "t0" is a parameter, then do nothing: (display "write-start time:" start arguments) (cond ((is-argument "t0" arguments) ;--------------------- ; /* t0 specified as input parameter */ ;--------------------- (format stream " /* t0 specified as input parameter */~%")) ;; else if start time is specified, use it to initialize sr: (t (cond (start ;--------------- ; (START (AT )) specified: ; ; time_type t0 = ; ;--------------- (setf start (car start)) (cond ((eq (car start) 'AT) (format stream " time_type t0 = ~A;~%" (cadr start))) ((eq (car start) 'MIN) (format stream " time_type t0 = ") (write-redux-of-names stream "min" (c-names (cdr start)) "->t0") (format stream ";~%")) ((eq (car start) 'MAX) (format stream " time_type t0 = ") (write-redux-of-names stream "max" (c-names (cdr start)) "->t0") (format stream ";~%")) (t (error (format nil "Unrecognized START specification ~A" start))))) ;--------------- ; time_type t0 = 0.0; ;--------------- (t (format stream " time_type t0 = 0.0;~%")))))) ;; c-names -- get the C names corresponding to list of symbols ;; (defun c-names (syms) (mapcar '(lambda (sym) (string-downcase (symbol-name sym))) syms)) (defun is-table (alg snd) (dolist (table (get-slot alg 'table)) (cond ((equal snd table) (display "is-table" snd table) (return t))))) ;; write-xlmake -- write out a function snd_NAME to be called by xlisp ; ; this function copies any sound arguments and passes them on to snd_make_NAME ; (defun write-xlmake (alg stream) (let ((name (get-slot alg 'name)) (sound-names (get-slot alg 'sound-names)) (arguments (get-slot alg 'arguments)) comma) ;-------------------- ; sound_type snd_NAME ;-------------------- (format stream "~%~%sound_type snd_~A" name) ;-------------------- ; ( type name, ...) ; { ;-------------------- (write-ansi-parameter-list stream "" arguments) (format stream "~%") (if (not *ANSI*) (dolist (arg arguments) (format stream " ~A ~A;~%" (car arg) (cadr arg)))) (format stream "{~%") ;---------------- ; for each sound argument that is not a table ; sound_type SND_copy = sound_copy(SND); ;---------------- (dolist (arg arguments) (cond ((equal (car arg) "sound_type") (let ((snd (cadr arg))) (cond ((not (is-table alg snd)) (format stream " sound_type ~A_copy = sound_copy(~A);~%" snd snd))))))) ;---------------- ; now call snd_make_ALG. When SND is a sound_type that is not a table, ; substitute SND_copy for SND. ;---------------- (format stream " return snd_make_~A(" name) (setf comma "") (dolist (arg arguments) (let ((suffix "")) (cond ((and (equal (car arg) "sound_type") (not (is-table alg (cadr arg)))) (setf suffix "_copy"))) (format stream "~A~A~A" comma (cadr arg) suffix) (setf comma ", "))) (format stream ");~%}~%"))) nyquist-3.05/tran/abs.alg0000644000175000000620000000040310144436365014364 0ustar stevestaff(ABS-ALG (NAME "abs") (ARGUMENTS ("sound_type" "input")) (ALWAYS-SCALE input) (START (MIN input)) (INNER-LOOP "{ sample_type s = input; sample_type o = s; if (o < 0.0) o = -o; output = o; }") (TERMINATE (MIN input)) (LOGICAL-STOP (MIN input)) ) nyquist-3.05/tran/instrmodalbar.h0000644000175000000620000000040111466723256016150 0ustar stevestaffsound_type snd_make_modalbar(time_type t0, double freq, int preset, time_type dur, rate_type sr); sound_type snd_modalbar(time_type t0, double freq, int preset, time_type dur, rate_type sr); /* LISP: (snd-modalbar ANYNUM ANYNUM FIXNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/biquadfilt.h0000644000175000000620000000052511466723256015442 0ustar stevestaffsound_type snd_make_biquadfilt(sound_type s, double b0, double b1, double b2, double a1, double a2, double z1init, double z2init); sound_type snd_biquadfilt(sound_type s, double b0, double b1, double b2, double a1, double a2, double z1init, double z2init); /* LISP: (snd-biquad SOUND ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/quantize.alg0000644000175000000620000000056710144436365015472 0ustar stevestaff(QUANTIZE-ALG (NAME "quantize") (ARGUMENTS ("sound_type" "s1") ("long" "steps")) (INTERNAL-SCALING s1) (START (MIN s1)) (STATE ("double" "factor" "s1->scale * steps; scale_factor = (sample_type) (1.0 / steps);")) (INNER-LOOP "register long xx = (long) (s1 * factor); output = (float) xx;") (TERMINATE (MIN s1)) (CONSTANT "factor") (LOGICAL-STOP (MIN s1)) ) nyquist-3.05/tran/const.h0000644000175000000620000000031710144436365014435 0ustar stevestaffsound_type snd_make_const(double c, time_type t0, rate_type sr, time_type d); sound_type snd_const(double c, time_type t0, rate_type sr, time_type d); /* LISP: (snd-const ANYNUM ANYNUM ANYNUM ANYNUM) */ nyquist-3.05/tran/instrbowedfreq.alg0000644000175000000620000000160211466723256016665 0ustar stevestaff(INSTRBOWED-FREQ-ALG (NAME "bowed_freq") (ARGUMENTS ("double" "freq") ("sound_type" "bowpress_env") ("sound_type" "freq_env") ("rate_type" "sr")) (STATE ("struct instr *" "mybow" "initInstrument(BOWED, round(sr)); controlChange(susp->mybow, 1, 0.0);") ("int" "temp_ret_value" "noteOn(susp->mybow, freq, 1.0)") ("double" "frequency" "freq")) (START (min bowpress_env)) (NOT-IN-INNER-LOOP "temp_ret_value") (CONSTANT "frequency") (SAMPLE-RATE "sr") (MATCHED-SAMPLE-RATE freq_env bowpress_env) (TERMINATE (min bowpress_env)) (INNER-LOOP " controlChange(mybow, 128, BOW_CONTROL_CHANGE_CONST * bowpress_env); setFrequency(mybow, frequency + freq_env); output = (sample_type) tick(mybow)") (SUPPORT-HEADER " #define BOW_CONTROL_CHANGE_CONST 128 ") (SUPPORT-FUNCTIONS " #include \"instr.h\" ") (FINALIZATION " deleteInstrument(susp->mybow); ") ) nyquist-3.05/tran/sine.h0000644000175000000620000000053410144436365014246 0ustar stevestaffsound_type snd_make_sine(time_type t0, double hz, rate_type sr, time_type d); sound_type snd_sine(time_type t0, double hz, rate_type sr, time_type d); /* LISP: (snd-sine ANYNUM ANYNUM ANYNUM ANYNUM) */ #define SINE_TABLE_LEN 2048 #define SINE_TABLE_MASK 0x7FFFFFFF #define SINE_TABLE_SHIFT 20 void sine_init(); extern sample_type sine_table[]; nyquist-3.05/tran/quantize.h0000644000175000000620000000023110144436365015142 0ustar stevestaffsound_type snd_make_quantize(sound_type s1, long steps); sound_type snd_quantize(sound_type s1, long steps); /* LISP: (snd-quantize SOUND FIXNUM) */ nyquist-3.05/tran/instrfluteall.c0000644000175000000620000002347511466723256016212 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "instrfluteall.h" void flute_all_free(); typedef struct flute_all_susp_struct { snd_susp_node susp; long terminate_cnt; sound_type breath_env; long breath_env_cnt; sample_block_values_type breath_env_ptr; sound_type freq_env; long freq_env_cnt; sample_block_values_type freq_env_ptr; sound_type jet_delay; long jet_delay_cnt; sample_block_values_type jet_delay_ptr; sound_type noise; long noise_cnt; sample_block_values_type noise_ptr; struct instr *myflute; double frequency; } flute_all_susp_node, *flute_all_susp_type; #include "instr.h" void flute_all_ssss_fetch(register flute_all_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register struct instr * myflute_reg; register double frequency_reg; register sample_type noise_scale_reg = susp->noise->scale; register sample_block_values_type noise_ptr_reg; register sample_type jet_delay_scale_reg = susp->jet_delay->scale; register sample_block_values_type jet_delay_ptr_reg; register sample_type freq_env_scale_reg = susp->freq_env->scale; register sample_block_values_type freq_env_ptr_reg; register sample_type breath_env_scale_reg = susp->breath_env->scale; register sample_block_values_type breath_env_ptr_reg; falloc_sample_block(out, "flute_all_ssss_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the breath_env input sample block: */ susp_check_term_samples(breath_env, breath_env_ptr, breath_env_cnt); togo = min(togo, susp->breath_env_cnt); /* don't run past the freq_env input sample block: */ susp_check_samples(freq_env, freq_env_ptr, freq_env_cnt); togo = min(togo, susp->freq_env_cnt); /* don't run past the jet_delay input sample block: */ susp_check_samples(jet_delay, jet_delay_ptr, jet_delay_cnt); togo = min(togo, susp->jet_delay_cnt); /* don't run past the noise input sample block: */ susp_check_samples(noise, noise_ptr, noise_cnt); togo = min(togo, susp->noise_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } n = togo; myflute_reg = susp->myflute; frequency_reg = susp->frequency; noise_ptr_reg = susp->noise_ptr; jet_delay_ptr_reg = susp->jet_delay_ptr; freq_env_ptr_reg = susp->freq_env_ptr; breath_env_ptr_reg = susp->breath_env_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ controlChange(myflute_reg, 128, FLUTE_CONTROL_CHANGE_CONST * (breath_env_scale_reg * *breath_env_ptr_reg++)); controlChange(myflute_reg, 2, FLUTE_CONTROL_CHANGE_CONST * (jet_delay_scale_reg * *jet_delay_ptr_reg++)); controlChange(myflute_reg, 4, FLUTE_CONTROL_CHANGE_CONST * (noise_scale_reg * *noise_ptr_reg++)); setFrequency(myflute_reg, frequency_reg + (freq_env_scale_reg * *freq_env_ptr_reg++)); *out_ptr_reg++ = (sample_type) tick(myflute_reg); } while (--n); /* inner loop */ susp->myflute = myflute_reg; /* using noise_ptr_reg is a bad idea on RS/6000: */ susp->noise_ptr += togo; /* using jet_delay_ptr_reg is a bad idea on RS/6000: */ susp->jet_delay_ptr += togo; /* using freq_env_ptr_reg is a bad idea on RS/6000: */ susp->freq_env_ptr += togo; /* using breath_env_ptr_reg is a bad idea on RS/6000: */ susp->breath_env_ptr += togo; out_ptr += togo; susp_took(breath_env_cnt, togo); susp_took(freq_env_cnt, togo); susp_took(jet_delay_cnt, togo); susp_took(noise_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } } /* flute_all_ssss_fetch */ void flute_all_toss_fetch(susp, snd_list) register flute_all_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from breath_env up to final_time for this block of zeros */ while ((round((final_time - susp->breath_env->t0) * susp->breath_env->sr)) >= susp->breath_env->current) susp_get_samples(breath_env, breath_env_ptr, breath_env_cnt); /* fetch samples from freq_env up to final_time for this block of zeros */ while ((round((final_time - susp->freq_env->t0) * susp->freq_env->sr)) >= susp->freq_env->current) susp_get_samples(freq_env, freq_env_ptr, freq_env_cnt); /* fetch samples from jet_delay up to final_time for this block of zeros */ while ((round((final_time - susp->jet_delay->t0) * susp->jet_delay->sr)) >= susp->jet_delay->current) susp_get_samples(jet_delay, jet_delay_ptr, jet_delay_cnt); /* fetch samples from noise up to final_time for this block of zeros */ while ((round((final_time - susp->noise->t0) * susp->noise->sr)) >= susp->noise->current) susp_get_samples(noise, noise_ptr, noise_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->breath_env->t0) * susp->breath_env->sr - (susp->breath_env->current - susp->breath_env_cnt)); susp->breath_env_ptr += n; susp_took(breath_env_cnt, n); n = round((final_time - susp->freq_env->t0) * susp->freq_env->sr - (susp->freq_env->current - susp->freq_env_cnt)); susp->freq_env_ptr += n; susp_took(freq_env_cnt, n); n = round((final_time - susp->jet_delay->t0) * susp->jet_delay->sr - (susp->jet_delay->current - susp->jet_delay_cnt)); susp->jet_delay_ptr += n; susp_took(jet_delay_cnt, n); n = round((final_time - susp->noise->t0) * susp->noise->sr - (susp->noise->current - susp->noise_cnt)); susp->noise_ptr += n; susp_took(noise_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void flute_all_mark(flute_all_susp_type susp) { sound_xlmark(susp->breath_env); sound_xlmark(susp->freq_env); sound_xlmark(susp->jet_delay); sound_xlmark(susp->noise); } void flute_all_free(flute_all_susp_type susp) { deleteInstrument(susp->myflute); sound_unref(susp->breath_env); sound_unref(susp->freq_env); sound_unref(susp->jet_delay); sound_unref(susp->noise); ffree_generic(susp, sizeof(flute_all_susp_node), "flute_all_free"); } void flute_all_print_tree(flute_all_susp_type susp, int n) { indent(n); stdputstr("breath_env:"); sound_print_tree_1(susp->breath_env, n); indent(n); stdputstr("freq_env:"); sound_print_tree_1(susp->freq_env, n); indent(n); stdputstr("jet_delay:"); sound_print_tree_1(susp->jet_delay, n); indent(n); stdputstr("noise:"); sound_print_tree_1(susp->noise, n); } sound_type snd_make_flute_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type jet_delay, sound_type noise, rate_type sr) { register flute_all_susp_type susp; /* sr specified as input parameter */ time_type t0 = breath_env->t0; int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; falloc_generic(susp, flute_all_susp_node, "snd_make_flute_all"); susp->myflute = initInstrument(FLUTE, round(sr)); noteOn(susp->myflute, freq, 1.0); controlChange(susp->myflute, 11, FLUTE_CONTROL_CHANGE_CONST * vibrato_freq); controlChange(susp->myflute, 1, FLUTE_CONTROL_CHANGE_CONST * vibrato_gain);; susp->frequency = freq; susp->susp.fetch = flute_all_ssss_fetch; susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < breath_env->t0) sound_prepend_zeros(breath_env, t0); if (t0 < freq_env->t0) sound_prepend_zeros(freq_env, t0); if (t0 < jet_delay->t0) sound_prepend_zeros(jet_delay, t0); if (t0 < noise->t0) sound_prepend_zeros(noise, t0); /* minimum start time over all inputs: */ t0_min = min(breath_env->t0, min(freq_env->t0, min(jet_delay->t0, min(noise->t0, t0)))); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = flute_all_toss_fetch; } /* initialize susp state */ susp->susp.free = flute_all_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = flute_all_mark; susp->susp.print_tree = flute_all_print_tree; susp->susp.name = "flute_all"; susp->susp.log_stop_cnt = UNKNOWN; susp->susp.current = 0; susp->breath_env = breath_env; susp->breath_env_cnt = 0; susp->freq_env = freq_env; susp->freq_env_cnt = 0; susp->jet_delay = jet_delay; susp->jet_delay_cnt = 0; susp->noise = noise; susp->noise_cnt = 0; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_flute_all(double freq, sound_type breath_env, sound_type freq_env, double vibrato_freq, double vibrato_gain, sound_type jet_delay, sound_type noise, rate_type sr) { sound_type breath_env_copy = sound_copy(breath_env); sound_type freq_env_copy = sound_copy(freq_env); sound_type jet_delay_copy = sound_copy(jet_delay); sound_type noise_copy = sound_copy(noise); return snd_make_flute_all(freq, breath_env_copy, freq_env_copy, vibrato_freq, vibrato_gain, jet_delay_copy, noise_copy, sr); } nyquist-3.05/tran/aresoncv.c0000644000175000000620000004010711466723256015131 0ustar stevestaff#include "stdio.h" #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" #include "sound.h" #include "falloc.h" #include "cext.h" #include "aresoncv.h" void aresoncv_free(); typedef struct aresoncv_susp_struct { snd_susp_node susp; boolean started; long terminate_cnt; boolean logically_stopped; sound_type s1; long s1_cnt; sample_block_values_type s1_ptr; sound_type bw; long bw_cnt; sample_block_values_type bw_ptr; /* support for interpolation of bw */ sample_type bw_x1_sample; double bw_pHaSe; double bw_pHaSe_iNcR; /* support for ramp between samples of bw */ double output_per_bw; long bw_n; double c3co; double coshz; double c2; double c1; int normalization; double y1; double y2; } aresoncv_susp_node, *aresoncv_susp_type; void aresoncv_ns_fetch(register aresoncv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_type bw_scale_reg = susp->bw->scale; register sample_block_values_type bw_ptr_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresoncv_ns_fetch"); out_ptr = out->samples; snd_list->block = out; while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past the bw input sample block: */ susp_check_term_samples(bw, bw_ptr, bw_cnt); togo = min(togo, susp->bw_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_ptr_reg = susp->bw_ptr; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; current = *s1_ptr_reg++; *out_ptr_reg++ = (float) (y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg); y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using bw_ptr_reg is a bad idea on RS/6000: */ susp->bw_ptr += togo; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp_took(bw_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresoncv_ns_fetch */ void aresoncv_ni_fetch(register aresoncv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register double bw_pHaSe_iNcR_rEg = susp->bw_pHaSe_iNcR; register double bw_pHaSe_ReG; register sample_type bw_x1_sample_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresoncv_ni_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); } while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; bw_pHaSe_ReG = susp->bw_pHaSe; bw_x1_sample_reg = susp->bw_x1_sample; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; if (bw_pHaSe_ReG >= 1.0) { /* fixup-depends bw */ /* pick up next sample as bw_x1_sample: */ susp->bw_ptr++; susp_took(bw_cnt, 1); bw_pHaSe_ReG -= 1.0; susp_check_term_samples_break(bw, bw_ptr, bw_cnt, bw_x1_sample_reg); bw_x1_sample_reg = susp_current_sample(bw, bw_ptr); } current = *s1_ptr_reg++; *out_ptr_reg++ = (float) (y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg); y2_reg = y1_reg; y1_reg = y0 - current; bw_pHaSe_ReG += bw_pHaSe_iNcR_rEg; } while (--n); /* inner loop */ togo -= n; susp->y1 = y1_reg; susp->y2 = y2_reg; susp->bw_pHaSe = bw_pHaSe_ReG; susp->bw_x1_sample = bw_x1_sample_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresoncv_ni_fetch */ void aresoncv_nr_fetch(register aresoncv_susp_type susp, snd_list_type snd_list) { int cnt = 0; /* how many samples computed */ sample_type bw_val; int togo; int n; sample_block_type out; register sample_block_values_type out_ptr; register sample_block_values_type out_ptr_reg; register double c3co_reg; register double coshz_reg; register double c2_reg; register double c1_reg; register int normalization_reg; register double y1_reg; register double y2_reg; register sample_block_values_type s1_ptr_reg; falloc_sample_block(out, "aresoncv_nr_fetch"); out_ptr = out->samples; snd_list->block = out; /* make sure sounds are primed with first values */ if (!susp->started) { susp->started = true; susp->bw_pHaSe = 1.0; } susp_check_term_samples(bw, bw_ptr, bw_cnt); while (cnt < max_sample_block_len) { /* outer loop */ /* first compute how many samples to generate in inner loop: */ /* don't overflow the output sample block: */ togo = max_sample_block_len - cnt; /* don't run past the s1 input sample block: */ susp_check_term_log_samples(s1, s1_ptr, s1_cnt); togo = min(togo, susp->s1_cnt); /* grab next bw_x1_sample when phase goes past 1.0; */ /* use bw_n (computed below) to avoid roundoff errors: */ if (susp->bw_n <= 0) { susp_check_term_samples(bw, bw_ptr, bw_cnt); susp->bw_x1_sample = susp_fetch_sample(bw, bw_ptr, bw_cnt); susp->bw_pHaSe -= 1.0; /* bw_n gets number of samples before phase exceeds 1.0: */ susp->bw_n = (long) ((1.0 - susp->bw_pHaSe) * susp->output_per_bw); } togo = min(togo, susp->bw_n); bw_val = susp->bw_x1_sample; /* don't run past terminate time */ if (susp->terminate_cnt != UNKNOWN && susp->terminate_cnt <= susp->susp.current + cnt + togo) { togo = susp->terminate_cnt - (susp->susp.current + cnt); if (togo == 0) break; } /* don't run past logical stop time */ if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); /* break if to_stop == 0 (we're at the logical stop) * AND cnt > 0 (we're not at the beginning of the * output block). */ if (to_stop < togo) { if (to_stop == 0) { if (cnt) { togo = 0; break; } else /* keep togo as is: since cnt == 0, we * can set the logical stop flag on this * output block */ susp->logically_stopped = true; } else /* limit togo so we can start a new * block at the LST */ togo = to_stop; } } n = togo; c3co_reg = susp->c3co; coshz_reg = susp->coshz; c2_reg = susp->c2; c1_reg = susp->c1; normalization_reg = susp->normalization; y1_reg = susp->y1; y2_reg = susp->y2; s1_ptr_reg = susp->s1_ptr; out_ptr_reg = out_ptr; if (n) do { /* the inner sample computation loop */ register double y0, current; current = *s1_ptr_reg++; *out_ptr_reg++ = (float) (y0 = c1_reg * current + c2_reg * y1_reg - c3co_reg * y2_reg); y2_reg = y1_reg; y1_reg = y0 - current; } while (--n); /* inner loop */ susp->y1 = y1_reg; susp->y2 = y2_reg; /* using s1_ptr_reg is a bad idea on RS/6000: */ susp->s1_ptr += togo; out_ptr += togo; susp_took(s1_cnt, togo); susp->bw_pHaSe += togo * susp->bw_pHaSe_iNcR; susp->bw_n -= togo; cnt += togo; } /* outer loop */ /* test for termination */ if (togo == 0 && cnt == 0) { snd_list_terminate(snd_list); } else { snd_list->block_len = cnt; susp->susp.current += cnt; } /* test for logical stop */ if (susp->logically_stopped) { snd_list->logically_stopped = true; } else if (susp->susp.log_stop_cnt == susp->susp.current) { susp->logically_stopped = true; } } /* aresoncv_nr_fetch */ void aresoncv_toss_fetch(susp, snd_list) register aresoncv_susp_type susp; snd_list_type snd_list; { long final_count = susp->susp.toss_cnt; time_type final_time = susp->susp.t0; long n; /* fetch samples from s1 up to final_time for this block of zeros */ while ((round((final_time - susp->s1->t0) * susp->s1->sr)) >= susp->s1->current) susp_get_samples(s1, s1_ptr, s1_cnt); /* fetch samples from bw up to final_time for this block of zeros */ while ((round((final_time - susp->bw->t0) * susp->bw->sr)) >= susp->bw->current) susp_get_samples(bw, bw_ptr, bw_cnt); /* convert to normal processing when we hit final_count */ /* we want each signal positioned at final_time */ n = round((final_time - susp->s1->t0) * susp->s1->sr - (susp->s1->current - susp->s1_cnt)); susp->s1_ptr += n; susp_took(s1_cnt, n); n = round((final_time - susp->bw->t0) * susp->bw->sr - (susp->bw->current - susp->bw_cnt)); susp->bw_ptr += n; susp_took(bw_cnt, n); susp->susp.fetch = susp->susp.keep_fetch; (*(susp->susp.fetch))(susp, snd_list); } void aresoncv_mark(aresoncv_susp_type susp) { sound_xlmark(susp->s1); sound_xlmark(susp->bw); } void aresoncv_free(aresoncv_susp_type susp) { sound_unref(susp->s1); sound_unref(susp->bw); ffree_generic(susp, sizeof(aresoncv_susp_node), "aresoncv_free"); } void aresoncv_print_tree(aresoncv_susp_type susp, int n) { indent(n); stdputstr("s1:"); sound_print_tree_1(susp->s1, n); indent(n); stdputstr("bw:"); sound_print_tree_1(susp->bw, n); } sound_type snd_make_aresoncv(sound_type s1, double hz, sound_type bw, int normalization) { register aresoncv_susp_type susp; rate_type sr = s1->sr; time_type t0 = max(s1->t0, bw->t0); int interp_desc = 0; sample_type scale_factor = 1.0F; time_type t0_min = t0; /* combine scale factors of linear inputs (S1) */ scale_factor *= s1->scale; s1->scale = 1.0F; /* try to push scale_factor back to a low sr input */ if (s1->sr < sr) { s1->scale = scale_factor; scale_factor = 1.0F; } falloc_generic(susp, aresoncv_susp_node, "snd_make_aresoncv"); susp->c3co = 0.0; susp->coshz = cos(hz * PI2 / s1->sr); susp->c2 = 0.0; susp->c1 = 0.0; susp->normalization = normalization; susp->y1 = 0.0; susp->y2 = 0.0; bw->scale = (float) (bw->scale * (-PI2 / s1->sr)); /* select a susp fn based on sample rates */ interp_desc = (interp_desc << 2) + interp_style(s1, sr); interp_desc = (interp_desc << 2) + interp_style(bw, sr); switch (interp_desc) { case INTERP_nn: /* handled below */ case INTERP_ns: susp->susp.fetch = aresoncv_ns_fetch; break; case INTERP_ni: susp->susp.fetch = aresoncv_ni_fetch; break; case INTERP_nr: susp->susp.fetch = aresoncv_nr_fetch; break; default: snd_badsr(); break; } susp->terminate_cnt = UNKNOWN; /* handle unequal start times, if any */ if (t0 < s1->t0) sound_prepend_zeros(s1, t0); if (t0 < bw->t0) sound_prepend_zeros(bw, t0); /* minimum start time over all inputs: */ t0_min = min(s1->t0, min(bw->t0, t0)); /* how many samples to toss before t0: */ susp->susp.toss_cnt = (long) ((t0 - t0_min) * sr + 0.5); if (susp->susp.toss_cnt > 0) { susp->susp.keep_fetch = susp->susp.fetch; susp->susp.fetch = aresoncv_toss_fetch; } /* initialize susp state */ susp->susp.free = aresoncv_free; susp->susp.sr = sr; susp->susp.t0 = t0; susp->susp.mark = aresoncv_mark; susp->susp.print_tree = aresoncv_print_tree; susp->susp.name = "aresoncv"; susp->logically_stopped = false; susp->susp.log_stop_cnt = logical_stop_cnt_cvt(s1); susp->started = false; susp->susp.current = 0; susp->s1 = s1; susp->s1_cnt = 0; susp->bw = bw; susp->bw_cnt = 0; susp->bw_pHaSe = 0.0; susp->bw_pHaSe_iNcR = bw->sr / sr; susp->bw_n = 0; susp->output_per_bw = sr / bw->sr; return sound_create((snd_susp_type)susp, t0, sr, scale_factor); } sound_type snd_aresoncv(sound_type s1, double hz, sound_type bw, int normalization) { sound_type s1_copy = sound_copy(s1); sound_type bw_copy = sound_copy(bw); return snd_make_aresoncv(s1_copy, hz, bw_copy, normalization); } nyquist-3.05/tran/writesusp.lsp0000644000175000000620000012206511466723256015736 0ustar stevestaff;;************ ;; Change Log ;; Date | Change ;;----------+--------------------- ;; 17-Dec-91 | [1.1] Created ;; 17-Dec-91 | [1.1] cast arg of snd_list_create to correct type ;; 17-Dec-91 | [1.1] cast truncation as (int) explicitly, avoid lint ;; | errors ;; 13-Jan-92 | [1.2] reformatted and recommented ;;************ ;;**************** ;; depended-on-in-inner-loop - test if variables updated in inner loop ;;**************** (defun depended-on-in-inner-loop (vars interp sound-names step-function) (dotimes (n (length interp)) (let ((method (nth n interp)) (name (nth n sound-names)) interpolate-samples) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((and (or (member method '(NONE SCALE INTERP)) interpolate-samples) (member name vars :test #'equal)) (return t)))))) ;;**************** ;; fixup-depends-prime - write code to update depend variables ;; this code is only run the first time the suspension ;; is invoked ;;**************** (defun fixup-depends-prime (alg stream name indent var-name) (let ((depends (get-slot alg 'depends))) (dolist (dep depends) (cond ((equal name (cadr dep)) (cond ((eq (cadddr dep) 'TEMP) (format stream "~A~A = ~A;~%" indent (car dep) (fixup-substitutions-prime alg (caddr dep) name var-name))) (t (format stream "~Asusp->~A = ~A;~%" indent (car dep) (fixup-substitutions-prime alg (caddr dep) name var-name))))))))) (print 'fixup-depends-prime) ;;**************** ;; fixup-depends-prime-decls - write declarations for temp depend variables ;; this code is only run the first time the suspension ;; is invoked ;;**************** (defun fixup-depends-prime-decls (alg stream name) (let ((depends (get-slot alg 'depends))) (dolist (dep depends) (cond ((equal name (cadr dep)) (cond ((eq (cadddr dep) 'TEMP) (format stream "\t ~A ~A;~%" (car (cddddr dep)) (car dep))))))))) (print 'fixup-depends-prime-decls) ;;**************** ;; fixup-substitutions-prime - substitute susp-> for for each ;; state variable in code, also substitute var-name for name ;; (this is the depended-on value) ;;**************** (defun fixup-substitutions-prime (alg code name var-name) (dolist (state (get-slot alg 'state)) (let ((var (cadr state))) (setf code (substitute code var (strcat "susp->" var) t)))) (if name (setf code (substitute code name var-name nil))) code) (print 'fixup-substitutions-prime) ;; fixup-substitutions-for-depends is used to prepare joint-dependency ;; code for use outside the inner loop. In this position, the state ;; variables must be accessed using "susp->" and signals must ;; be accessed using the local variable _val ;; (defun fixup-substitutions-for-depends (alg code) (setf code (fixup-substitutions-prime alg code nil nil)) (let ((interp (get alg 'interpolation)) (step-function (get-slot alg 'step-function)) (sound-names (get-slot alg 'sound-names))) (dotimes (n (length interp)) ;(display "fixup-loop" n name interp sound-names) (let* ((name (nth n sound-names)) (method (nth n interp)) (is-step (member (name-to-symbol name) step-function))) (cond ((and is-step (eq method 'RAMP)) (setf code (substitute code name (strcat name "_val") t)) ;(display "fixup-check" name) )))) code)) ;;**************** ;; fixup-depends - write code to declare and update depend variables ;; this is called at declaration time (the point where ;; declarations should be output), but also generates code ;; to be output after the depended-on variable is updated ;;**************** (defun fixup-depends (alg stream name) (format stream "/* fixup-depends ~A */~%" name) (let ((depends (get-slot alg 'depends)) (fixup-code "") (var-name (strcat name "_x1_sample_reg"))) (dolist (dep depends) (cond ((equal name (cadr dep)) (cond ((eq (cadddr dep) 'TEMP) (format stream "\t\t~A ~A; ~%" (car (cddddr dep)) (car dep)) (setf fixup-code (format nil "~A\t\t~A = ~A;~%" fixup-code (car dep) (fixup-substitutions alg (caddr dep) name var-name)))) (t (setf fixup-code (format nil "~A\t\t~A_reg = susp->~A = ~A;~%" fixup-code (car dep) (car dep) (fixup-substitutions alg (caddr dep) name var-name)))))))) (put-slot alg fixup-code 'fixup-code))) (print 'fixup-depends) ;;**************** ;; fixup-substitutions - substitute _reg for for each ;; state variable in code, also substitute var-name for name ;; (this is the depended-on value) ;;**************** (defun fixup-substitutions (alg code name var-name) (dolist (state (get-slot alg 'state)) (let ((var (cadr state))) (setf code (substitute code var (strcat var "_reg") t)))) (substitute code name var-name nil)) (print 'fixup-substitutions) ;;**************** ;; in-min-list - see if name is in TERMINATE MIN list or ;; LOGICAL-STOP MIN list ;; ;; returns true if algorithm specified, say (TERMINATE (MIN s1 s2 s3)) and ;; name is, say, "s2". ;; NOTE: name is a string, so we have to do a lookup to get the symbol name ;;**************** (defun in-min-list (name alg terminate-or-logical-stop) (let ((spec (get alg terminate-or-logical-stop))) ; (display "in-min-list" name alg terminate-or-logical-stop spec) (and spec (listp (car spec)) (eq (caar spec) 'MIN) (member (name-to-symbol name) (cdar spec))))) ;;**************** ;; logical-stop-check-needed -- says if we need to check for logical stop ;; after the outer loop ;; the argument is the logical-stop clause from the algorithm prop list ;;**************** (defun logical-stop-check-needed (logical-stop) (cond ((and logical-stop (listp logical-stop) (or (eq (car logical-stop) 'MIN) (eq (car logical-stop) 'AT)))))) ;;**************** ;; susp-check-fn -- find fn to check need for new block of samples ;; ;; To simply check if susp->S_ptr points to something, you call ;; susp_check_samples(S, S_ptr, S_cnt), but during this check, it is ;; also necessary to check for termination condition and logical stop ;; condition, BUT ONLY if S is in a MIN list for the TERMINATE or ;; LOGICAL-STOP attributes (i.e. this signal stops when S does). ;; ;; The algorithm is: if S is on the LOGICAL-STOP MIN list and on ;; the TERMINATE MIN list, then call susp_check_term_log_samples. ;;Otherwise if S is on the LOGICAL-STOP MIN list then call ;; susp_check_log_samples. Otherwise, if S is on the TERMINATE MIN ;; list, call susp_check_term_samples. The "normal" case should be ;; susp_check_term_samples, which happens when the LOGICAL-STOP ;; MIN list is empty (nothing was specified). Note that a signal logically ;; stops at termination time anyway, so this achieves the logically stopped ;; condition with no checking. ;;**************** (defun susp-check-fn (name alg) (let ((in-log-list (in-min-list name alg 'logical-stop)) (in-term-list (in-min-list name alg 'terminate))) (cond ((and in-log-list in-term-list) "susp_check_term_log_samples") (in-log-list "susp_check_log_samples") (in-term-list "susp_check_term_samples") (t "susp_check_samples")))) ;;************ ;; write-depend-decls -- declare TEMP depends variables ;; ;;************ ;(defun write-depend-decls (alg stream) ; (dolist (dep (get-slot alg 'depends)) ; (cond ((eq (cadddr dep) 'TEMP) ; (format stream "\t~A ~A; ~%" (car (cddddr dep)) (car dep)))))) ;-------- (defun write-depend-decls (alg stream interp sound-names step-function) (dotimes (n (length interp)) (let ((name (nth n sound-names)) (method (nth n interp)) is-step) (cond ((eq method 'INTERP) (setf is-step (member (name-to-symbol name) step-function)) (cond (is-step (fixup-depends-prime-decls alg stream name)))))))) ;;************ ;; write-prime -- write conditional code to prime input sounds and susp ;; ;;************ (defun write-prime (alg stream interp sound-names) (let ((step-function (get-slot alg 'step-function)) (internal-scaling (get-slot alg 'internal-scaling))) ;------------------------------ ; /* make sure sounds are primed with first values */ ;------------------------------ (format stream "~% /* make sure sounds are primed with first values */~%") ;------------------------------ ; if (!susp->started) { ; susp->started = true; ;------------------------------ (format stream " if (!susp->started) {~%") ; this is generating extraneous declarations, is it necessary? ; yes, at least sometimes, so we're leaving it in ; "atonev.alg" is a good test case to prove you can't comment this out (write-depend-decls alg stream interp sound-names step-function) (format stream "\tsusp->started = true;~%") ;------------------------------ ; for each method ;------------------------------ (dotimes (n (length interp)) (let ((name (nth n sound-names)) (method (nth n interp)) is-step) (cond ((eq method 'INTERP) ;-------------------- ; susp_XX_samples(NAME, NAME_ptr, NAME_cnt); ; susp->NAME_x1_sample = susp_fetch_sample(NAME, NAME_ptr, ; NAME_cnt); ; (if a step function) ;-------------------- (format stream "\t~A(~A, ~A_ptr, ~A_cnt);~%" (susp-check-fn name alg) name name name) (cond ((member (name-to-symbol name) internal-scaling) (format stream "\tsusp->~A_x1_sample = (susp->~A_cnt--, *(susp->~A_ptr));~%" name name name)) (t (format stream "\tsusp->~A_x1_sample = susp_fetch_sample(~A, ~A_ptr, ~A_cnt);~%" name name name name))) (setf is-step (member (name-to-symbol name) step-function)) (cond (is-step (fixup-depends-prime alg stream name "\t" (strcat "susp->" name "_x1_sample"))))) ((eq method 'RAMP) ;-------------------- ; susp->NAME_pHaSe = 1.0; ;-------------------- (format stream "\tsusp->~A_pHaSe = ~A;~%" name "1.0"))))) ;-------------------- ; *WATCH* ; show_samples(2,susp->NAME_x2,0); ;-------------------- ; (if *WATCH* ; (format stream "\tshow_samples(2,~A_x2,0);~%" name)) ;-------------------- ; } ;-------------------- (format stream " }~%"))) (print 'write-prime) ;;************ ;; show-samples-option ;; ;; Inputs: ;; stream: output stream for file ;; name: token to use for forming name ;; Effect: ;; Writes sampling clause ;;************ (defun show-samples-option (stream name) ;---------------------------- ; else ; { /* just show NAME */ ; show_samples(1,NAME,NAME_ptr - NAME->samples); ; } /* just show NAME */ ;---------------------------- ; (format stream "\t show_samples(1, ~A, 0);~%\t} else {~%" name) ; (format stream "\t show_samples(1, ~A, ~A_ptr - ~A->samples);~%~%" ; name name name) ) (print "show-samples-option") ;;************ ;; write-susp -- compile the suspension according to interpolation spec ;; ;;************ (defun write-susp (alg stream) (let* ((interp (get alg 'interpolation)) (encoding (encode interp)) (internal-scaling (get alg 'internal-scaling)) (sound-names (get alg 'sound-names)) (name (get-slot alg 'name)) (logical-stop (car (get-slot alg 'logical-stop))) (terminate (car (get-slot alg 'terminate))) (outer-loop (get-slot alg 'outer-loop)) (step-function (get-slot alg 'step-function)) (depends (get-slot alg 'depends)) (inner-loop (get-slot alg 'inner-loop)) n s m p fn-name loop-prefix joint-depend) (display "write-susp" interp encoding) ;--------------------------- ; non-ANSI: ; void NAME__fetch(susp, snd_list) ; register pwl_susp_type susp; ; snd_list_type snd_list; ; { ; ANSI: ; void NAME__fetch(register susp_type susp, snd_list_type snd_list) ; { ;--------------------------- (setf fn-name (format nil "~A_~A_fetch" name encoding)) (cond (*ANSI* (format stream "~%~%void ~A(register ~A_susp_type susp, snd_list_type snd_list)~%{~%" fn-name name)) (t (format stream "~%~%void ~A(susp, snd_list)~% register ~A_susp_type susp;~%~A~%" fn-name name " snd_list_type snd_list;\n{"))) ;----------------------------- ; int cnt = 0; /* how many samples computed */ ;----------------------------- (format stream " int cnt = 0; /* how many samples computed */~%") (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((and interpolate-samples (eq method 'INTERP)) (format stream " sample_type ~A_x2_sample;~%" name)) ((eq method 'INTERP)) ((and interpolate-samples (eq method 'RAMP)) ;----------------- ; sample_type NAME_DeLtA; ; sample_type NAME_val; ;----------------- (format stream " sample_type ~A_DeLtA;~%" name) (format stream " sample_type ~A_val;~%" name) (format stream " sample_type ~A_x2_sample;~%" name)) ((eq method 'RAMP) ;----------------- ; sample_type NAME_val; ;----------------- (format stream " sample_type ~A_val;~%" name))))) ;----------------------------- ; int togo; ; int n; ; sample_block_type out; ; register sample_block_values_type out_ptr; ; register sample_block_values_type out_ptr_reg; ;----------------------------- (format stream " int togo;~%") (format stream " int n;~%") (format stream " sample_block_type out;~%") (format stream " register sample_block_values_type out_ptr;~%~%") (format stream " register sample_block_values_type out_ptr_reg;~%~%") ;; computations for DEPENDS variables added to inner loop (setf loop-prefix "") (dolist (dep depends) (dotimes (n (length interp)) (let ((method (nth n interp)) (name (nth n sound-names)) interpolate-samples) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((and (equal name (cadr dep)) (or (member method '(NONE SCALE)) interpolate-samples)) (setf loop-prefix (format nil "~A\t ~A = ~A;~%" loop-prefix (car dep) (caddr dep)))))))) ;; computation of JOINT-DEPENDENCY, if applicable (setf joint-depend "") (dolist (dep (get-slot alg 'joint-dependency)) ;; if any depended on var is recomputed in inner loop, add the stmts (cond ((depended-on-in-inner-loop (car dep) interp sound-names step-function) (dolist (stmt (cdr dep)) (setf joint-depend (strcat joint-depend "\t " stmt "\n")))))) ; this computes some additional declarations (compute-inner-loop alg (strcat loop-prefix joint-depend inner-loop)) ; make the declarations (print-strings (get-slot alg 'register-decl) stream) ;----------------------------- ; falloc_sample_block(out, "caller"); ; out_ptr = out->samples; ; snd_list->block = out; ;----------------------------- (format stream " falloc_sample_block(out, \"~A\");~%" fn-name) (format stream " out_ptr = out->samples;~%") (format stream " snd_list->block = out;~%") ;----------------------------- ; prime the ramp/interp streams ;----------------------------- ;; run this code the first time the suspension is called (cond ((or (member 'RAMP interp) (member 'INTERP interp)) (write-prime alg stream interp sound-names))) (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((or (and interpolate-samples (eq method 'INTERP)) (eq method 'RAMP)) ;------------- ; susp_check_XX_samples(NAME, NAME_ptr, NAME_cnt); ;------------- (format stream "~% ~A(~A, ~A_ptr, ~A_cnt);~%" (susp-check-fn name alg) name name name))) (cond ((and interpolate-samples (eq method 'INTERP)) ;------------- ; susp->NAME_x2_sample = susp->NAME->scale * susp->NAME_x2_ptr); ;------------- (cond ((member (name-to-symbol name) internal-scaling) (format stream " ~A_x2_sample = *(susp->~A_ptr);~%" name name)) (t (format stream " ~A_x2_sample = susp_current_sample(~A, ~A_ptr);~%" name name name)))) ((eq method 'INTERP) ;------------- ; ;------------- ) ((and interpolate-samples (eq method 'RAMP)) ;---------------- ; susp->NAME_x2_sample = susp_current_sample(NAME, NAME_ptr); ;---------------- (cond ((member (name-to-symbol name) internal-scaling) (format stream " ~A_x2_sample = *(susp->~A_ptr);~%" name name)) (t (format stream " ~A_x2_sample = susp_current_sample(~A, ~A_ptr);~%" name name name)))) ((eq method 'RAMP) )))) ;---------------------------- ; *WATCH*: printf("NAME %x new block %x\n", susp, out); ;---------------------------- (if *watch* (format stream " printf(\"~A %x new block %x\\n\", susp, out);~%" name)) ;---------------------------- ; while (cnt < max_sample_block_len) { /* outer loop */ ; /* first compute how many samples to generate in inner loop: */ ; /* don't overflow the output sample block: */ ; togo = max_sample_block_len - cnt; ;---------------------------- (format stream "~% while (cnt < max_sample_block_len) { /* outer loop */~%") (format stream "\t/* first compute how many samples to generate in inner loop: */~%") (format stream "\t/* don't overflow the output sample block: */~%") (format stream "\ttogo = max_sample_block_len - cnt;~%~%") ;; this loop gets ready to execute the INNER-LOOP (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((member method '(NONE SCALE)) ;----------------- ; NONE: ; /* don't run past the NAME input sample block */ ; susp_check_XX_for_samples(NAME, NAME_ptr, NAME_cnt); ; togo = min(togo, susp->NAME_cnt); ;----------------- (format stream "\t/* don't run past the ~A input sample block: */~%" name) (display "don't run past the ..." name (susp-check-fn name alg)) (format stream "\t~A(~A, ~A_ptr, ~A_cnt);~%" (susp-check-fn name alg) name name name) (format stream "\ttogo = min(togo, susp->~A_cnt);~%~%" name)) ((eq method 'INTERP)) ((and interpolate-samples (eq method 'RAMP)) ;----------------- ; RAMP: ; ; /* grab next NAME_x2_sample when phase goes past 1.0 */ ; /* we use NAME_n (computed below) to avoid roundoff errors: */ ; if (susp->NAME_n <= 0) { ; susp->NAME_x1_sample = NAME_x2_sample; ; susp->NAME_ptr++; ; susp_took(NAME_cnt, 1); ; susp->NAME_pHaSe -= 1.0; ; susp_check_log_samples(NAME, NAME_ptr, NAME_cnt); ; NAME_x2_sample = susp_current_sample(NAME, NAME_ptr); ; } ; /* NAME_n gets number of samples before phase exceeds 1.0: */ ; susp->NAME_n = 0.5 + (long) ((1.0 - susp->NAME_pHaSe) * susp->output_per_NAME); ; togo = min(togo, susp->NAME_n); ; NAME_DeLtA = (sample_type) ((NAME_x2_sample - susp->NAME_x1_sample) * susp->NAME_pHaSe_iNcR); ; NAME_val = (sample_type) (susp->NAME_x1_sample * (1.0 - susp->NAME_pHaSe) + ; NAME_x2_sample * susp->NAME_pHaSe); ;----------------- (format stream "\t/* grab next ~A_x2_sample when phase goes past 1.0; */~%" name) (format stream "\t/* we use ~A_n (computed below) to avoid roundoff errors: */~%" name) (format stream "\tif (susp->~A_n <= 0) {~%" name) (format stream "\t susp->~A_x1_sample = ~A_x2_sample;~%" name name) (format stream "\t susp->~A_ptr++;~%" name); (format stream "\t susp_took(~A_cnt, 1);~%" name); (format stream "\t susp->~A_pHaSe -= 1.0;~%" name); (format stream "\t ~A(~A, ~A_ptr, ~A_cnt);~%" (susp-check-fn name alg) name name name) (cond ((member (name-to-symbol name) internal-scaling) (format stream "\t ~A_x2_sample = *(susp->~A_ptr);~%" name name)) (t (format stream "\t ~A_x2_sample = susp_current_sample(~A, ~A_ptr);~%" name name name))) (format stream "\t /* ~A_n gets number of samples before phase exceeds 1.0: */~%" name) (format stream "\t susp->~A_n = (long) ((1.0 - susp->~A_pHaSe) *~%" name name) (format stream "\t\t\t\t\tsusp->output_per_~A);~%\t}~%" name) (format stream "\ttogo = min(togo, susp->~A_n);~%" name) (format stream "\t~A_DeLtA = (sample_type) ((~A_x2_sample - susp->~A_x1_sample) * susp->~A_pHaSe_iNcR);~%" name name name name) (format stream "\t~A_val = (sample_type) (susp->~A_x1_sample * (1.0 - susp->~A_pHaSe) +~%" name name name) (format stream "\t\t ~A_x2_sample * susp->~A_pHaSe);~%~%" name name)) ((eq method 'RAMP) ;----------------- ; SLOW STEP FUNCTION ; ; /* grab next NAME_x1_sample when phase goes past 1.0 */ ; /* use NAME_n (computed below) to avoid roundoff errors: */ ; if (susp->NAME_n <= 0) { ; ; susp_check_log_samples(NAME, NAME_ptr, NAME_cnt); ; susp->NAME_x1_sample = susp_fetch_sample(NAME, NAME_ptr, ; NAME_cnt); ; susp->NAME_pHaSe -= 1.0; ; /* NAME_n gets number of samples before phase ; exceeds 1.0: */ ; susp->NAME_n = (long) ((1.0 - susp->NAME_pHaSe) * ; susp->output_per_NAME); ; ; } ; togo = min(togo, susp->NAME_n); ; NAME_val = susp->NAME_x1_sample; ;----------------- (format stream "\t/* grab next ~A_x1_sample when phase goes past 1.0; */~%" name) (format stream "\t/* use ~A_n (computed below) to avoid roundoff errors: */~%" name) (format stream "\tif (susp->~A_n <= 0) {~%" name) (fixup-depends-prime-decls alg stream name) (format stream "\t ~A(~A, ~A_ptr, ~A_cnt);~%" (susp-check-fn name alg) name name name) (format stream "\t susp->~A_x1_sample = susp_fetch_sample(~A, ~A_ptr, ~A_cnt);~%" name name name name) (format stream "\t susp->~A_pHaSe -= 1.0;~%" name); (format stream "\t /* ~A_n gets number of samples before phase exceeds 1.0: */~%" name) (format stream "\t susp->~A_n = (long) ((1.0 - susp->~A_pHaSe) *~%" name name) (format stream "\t\t\t\t\tsusp->output_per_~A);~%" name) (fixup-depends-prime alg stream name "\t " (strcat "susp->" name "_x1_sample")) (format stream "\t}~%" name) (format stream "\ttogo = min(togo, susp->~A_n);~%" name) (format stream "\t~A_val = susp->~A_x1_sample;~%" name name) )))) ;--------------- ; see if there are joint-dependencies that should be output now ; output here if none of depended-on signals are updated in inner loop ;--------------- ;; computation of JOINT-DEPENDENCY, if applicable (setf joint-depend "") (dolist (dep (get-slot alg 'joint-dependency)) (cond ((not (depended-on-in-inner-loop (car dep) interp sound-names step-function)) (dolist (stmt (cdr dep)) (setf joint-depend (strcat joint-depend "\t" stmt "\n")))))) (display "joint-depend before fixup" joint-depend) (setf joint-depend (fixup-substitutions-for-depends alg joint-depend)) (if joint-depend (format stream joint-depend)) (display "joint-depend outside loop" joint-depend) ;---------------- ; if the teminate time is a MIN of some signals or AT some expression ; (i.e. specified at all) see if we're coming to the terminate cnt: ; ; /* don't run past terminate time */ ; if (susp->terminate_cnt != UNKNOWN && ; susp->terminate_cnt <= susp->susp.current) { ; int to_stop = (susp->terminate_cnt + max_sample_block_len) - ; (susp->susp.current + cnt); ; if (to_stop < togo && ((togo = to_stop) == 0)) break; ; } ;---------------- (cond ((terminate-check-needed terminate alg) (print-strings '( "\t/* don't run past terminate time */\n" "\tif (susp->terminate_cnt != UNKNOWN &&\n" "\t susp->terminate_cnt <= susp->susp.current + cnt + togo) {\n" "\t togo = susp->terminate_cnt - (susp->susp.current + cnt);\n" "\t if (togo == 0) break;\n" "\t}\n\n") stream))) ;---------------- ; if the logical-stop attribute is MIN of some signals or AT some expression ; see if we're coming to the logical stop: ; ; /* don't run past logical stop time */ ; if (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) { ; int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt); ; /* break if to_stop == 0 (we're at the logical stop) ; * AND cnt > 0 (we're not at the beginning of the ; * output block). ; */ ; if (to_stop < togo) { ; if (to_stop == 0) { ; if (cnt) { ; togo = 0; ; break; ; } else /* keep togo as is: since cnt == 0, we ; * can set the logical stop flag on this ; * output block ; */ ; susp->logically_stopped = true; ; } else /* limit togo so we can start a new ; * block at the LST ; */ ; togo = to_stop; ; } ; } ;---------------- (cond (logical-stop (print-strings '( "\n\t/* don't run past logical stop time */\n" "\tif (!susp->logically_stopped && susp->susp.log_stop_cnt != UNKNOWN) {\n" "\t int to_stop = susp->susp.log_stop_cnt - (susp->susp.current + cnt);\n" "\t /* break if to_stop == 0 (we're at the logical stop)\n" "\t * AND cnt > 0 (we're not at the beginning of the\n" "\t * output block).\n" "\t */\n" "\t if (to_stop < togo) {\n" "\t\tif (to_stop == 0) {\n" "\t\t if (cnt) {\n" "\t\t\ttogo = 0;\n" "\t\t\tbreak;\n" "\t\t } else /* keep togo as is: since cnt == 0, we\n" "\t\t * can set the logical stop flag on this\n" "\t\t * output block\n" "\t\t */\n" "\t\t\tsusp->logically_stopped = true;\n" "\t\t} else /* limit togo so we can start a new\n" "\t\t * block at the LST\n" "\t\t */\n" "\t\t togo = to_stop;\n" "\t }\n" "\t}\n\n") stream))) (cond (outer-loop (print-strings outer-loop stream) (format stream "~%"))) ;---------------------------- ; n = togo; ; *WATCH*: printf("ALG %x starting inner loop, n %d\n", susp, n); ;---------------------------- (format stream "\tn = togo;~%") (if *watch* (format stream "\tprintf(\"~A %x starting inner loop, n %d\\n\", susp, n);~%" name)) (dotimes (n (length interp)) (let ((name (nth n sound-names)) (method (nth n interp))) (cond ((eq method 'NONE)) ;----------------- ; NONE: ;----------------- ((eq method 'RAMP)) ;----------------- ; RAMP: ;----------------- ((and (eq method 'INTERP) (eq n 0)) ;----------------- ; INTERP (first arg only) ; ; susp->NAME_cnt -= togo; ;----------------- ; (format stream "\tsusp->~A_cnt -= togo;~%" name) )))) (print-strings (get-slot alg 'register-init) stream) ;---------------------------- ; if (n) do { /* inner loop */ ;---------------------------- (format stream "\tif (n) do { /* the inner sample computation loop */~%") ;;---------------------------- ;; write local declarations supplied by user ;;---------------------------- (print-strings (get-slot alg 'inner-loop-locals) stream) ;;---------------------------- ;; declare temps that depend on signals ;;---------------------------- (dotimes (n (length interp)) (let ((method (nth n interp)) interpolate-samples (name (nth n sound-names))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((or (member method '(NONE SCALE)) interpolate-samples) (dolist (dep depends) (cond ((and (equal (cadr dep) name) (eq (cadddr dep) 'TEMP)) (format stream "\t ~A ~A;~%" (car (cddddr dep)) (car dep))))))))) ;; this loop writes code that runs in the INNER-LOOP and checks to see ;; if we need to advance to the next pair of interpolated points for ;; each interpolated sound (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((and interpolate-samples (eq method 'INTERP)) ;----------------- ; INTERP: ; ; if (susp->NAME_pHaSe >= 1.0) { ; NAME_x1_sample_reg =NAME_x2_sample_reg; ; /* pick up next sample as NAME_x2_sample */ ; susp->NAME_ptr++; ; susp_took(NAME_cnt, 1); ; susp->NAME_pHaSe -= 1.0; ; susp_check_XX_samples_break(NAME, NAME_ptr, NAME_cnt, NAME_x2_sample); ; } ; ;----------------- (format stream "\t if (~A_pHaSe_ReG >= 1.0) {~%" name) (format stream "\t\t~A_x1_sample_reg = ~A_x2_sample;~%" name name) (format stream "\t\t/* pick up next sample as ~A_x2_sample: */~%" name) (format stream "\t\tsusp->~A_ptr++;~%" name) (format stream "\t\tsusp_took(~A_cnt, 1);~%" name) (format stream "\t\t~A_pHaSe_ReG -= 1.0;~%" name) (format stream "\t\t~A_break(~A, ~A_ptr, ~A_cnt, ~A_x2_sample);~%" (susp-check-fn name alg) name name name name) ; (format stream "\t\t~A_x2_sample = susp_current_sample(~A, ~A_ptr);~%" ; name name name) ; show_samples(2, susp->NAME_x2, susp->NAME_x2_ptr - ; NAME_x2->block->samples); ;----------------- ; (if *WATCH* ; (format stream "\t\tshow_samples(2,susp->~A_x2,susp->~A_x2_ptr - susp->~A_x2->block->samples);~%" ; name name name) ; ) ;----------------- ; } ;----------------- (format stream "\t }~%") ) ((eq method 'INTERP) ;----------------- ; STEP FUNCTION: ; ; if (susp->NAME_pHaSe >= 1.0) { ; ; /* pick up next sample as NAME_x1_sample */ ; susp->NAME_ptr++; ; susp_took(NAME_cnt, 1); ; susp->NAME_pHaSe -= 1.0; ; susp_check_XX_samples_break(NAME, NAME_ptr, NAME_cnt, NAME_x1_sample); ; NAME_x1_sample_reg = susp_current_sample(NAME, NAME_ptr); ; ; } ;----------------- (format stream "\t if (~A_pHaSe_ReG >= 1.0) {~%" name) (fixup-depends alg stream name) (format stream "\t\t/* pick up next sample as ~A_x1_sample: */~%" name) (format stream "\t\tsusp->~A_ptr++;~%" name) (format stream "\t\tsusp_took(~A_cnt, 1);~%" name) (format stream "\t\t~A_pHaSe_ReG -= 1.0;~%" name) (format stream "\t\t~A_break(~A, ~A_ptr, ~A_cnt, ~A_x1_sample_reg);~%" (susp-check-fn name alg) name name name name) (format stream "\t\t~A_x1_sample_reg = susp_current_sample(~A, ~A_ptr);~%" name name name) ; show_samples(2, susp->NAME_x2, susp->NAME_x2_ptr - ; NAME_x2->block->samples); ;----------------- ; (if *WATCH* ; (format stream "\t\tshow_samples(2,susp->~A_x2,susp->~A_x2_ptr - susp->~A_x2->block->samples);~%" ; name name name) ; ) (let ((fixup-code (get-slot alg 'fixup-code))) (if fixup-code (format stream fixup-code))) ;----------------- ; } ;----------------- (format stream "\t }~%"))))) (write-inner-loop alg stream) (print-strings (get-slot alg 'register-cleanup) stream) ;; this loop calls loop tail computations on all sounds (dotimes (n (length interp)) (let ((name (nth n sound-names)) interpolate-samples (method (nth n interp))) (setf interpolate-samples (not (member (name-to-symbol name) step-function))) (cond ((member method '(NONE SCALE)) ;----------------- ; NONE: ; susp_took(NAME_cnt, togo - n); ;----------------- (format stream "\tsusp_took(~A_cnt, togo);~%" name)) ((eq method 'INTERP)) ((eq method 'RAMP) ;----------------- ; RAMP: ; susp->NAME_pHaSe += togo * susp->NAME_pHaSe_iNcR; ; susp->NAME_n -= togo; ;----------------- (format stream "\tsusp->~A_pHaSe += togo * susp->~A_pHaSe_iNcR;~%" name name) (format stream "\tsusp->~A_n -= togo;~%" name) )))) ;----------------------------- ; cnt += togo; ; } /* outer loop */ ; ; snd_list->block_len = cnt; ;----------------------------- (format stream "~A~%~A~%~%" "\tcnt += togo;" " } /* outer loop */") ;----------------------------- ; if terminate is not NONE (infinite), check for it as follows: ; /* test for termination */ ; if (togo == 0 && cnt == 0) { ; snd_list_terminate(snd_list); ; *WATCH*: printf("NAME %x terminated\n", susp); ; } else { ; snd_list->block_len = cnt; ; susp->susp.current += cnt; ; } ;----------------------------- (cond ((terminate-possible terminate alg) (print-strings '( " /* test for termination */\n" " if (togo == 0 && cnt == 0) {\n" "\tsnd_list_terminate(snd_list);\n") stream) (if *watch* (format stream "\tprintf(\"~A %x terminated.\\n\", susp);~%" name)) (print-strings '( " } else {\n" "\tsnd_list->block_len = cnt;\n" "\tsusp->susp.current += cnt;\n" " }\n") stream)) (t ;---------------- ; OTHERWISE (no termination test): ; snd_list->block_len = cnt; ; susp->susp.current += cnt; ;---------------- (print-strings '( " snd_list->block_len = cnt;\n" " susp->susp.current += cnt;\n") stream))) ;---------------- ; if logical-stop is not the default check for it as follows: ; /* test for logical stop */ ; if (susp->logically_stopped) { ; snd_list-> logically_stopped = true; ; } else if (susp->susp.log_stop_cnt == susp->susp.current) { ; susp->logically_stopped = true; ; } ;---------------- (cond ((logical-stop-check-needed logical-stop) (print-strings '( " /* test for logical stop */\n" " if (susp->logically_stopped) {\n" "\tsnd_list->logically_stopped = true;\n" " } else if (susp->susp.log_stop_cnt == susp->susp.current) {\n" "\tsusp->logically_stopped = true;\n" " }\n") stream))) ;---------------- ; } /* name_encoding_fetch */ ;---------------- (format stream "} /* ~A_~A_fetch */~%" name encoding))) (print 'write-susp) ; terminate-check-needed -- see if this is either a terminate clause ; that specifies MIN or AT, or is NIL (meaning none-specified so take ; the default) and there are signal parameters ; (defun terminate-check-needed (terminate alg) (cond (terminate (cond ((listp terminate) (cond ((member (car terminate) '(MIN AT AFTER)) t) (t nil))) ((member terminate '(COMPUTED NONE)) nil) (t (error "TERMINATE clause should specify a list")))) ((get alg 'sound-args) t))) ; same as terminate-check-needed, but also returns true for COMPUTED ; termination ; (defun terminate-possible (terminate alg) (cond (terminate (cond ((listp terminate) (cond ((member (car terminate) '(MIN AT AFTER COMPUTED)) t) (t nil))) ((eq terminate 'NONE) nil) ((eq terminate 'COMPUTED) t) (t (error "TERMINATE clause should specify a list")))) ((get alg 'sound-args) t))) nyquist-3.05/license.txt0000644000175000000620000001253111466723256014364 0ustar stevestaffLICENSE INFORMATION Nyquist is built upon and derived from XLISP. Both are copyrighted software. Two copyright notices and licenses appear below. In addition, Nyquist uses two LGPL libraries: libsndfile and liblo. These libraries are NOT covered by the Nyquist license, and Nyquist is NOT licensed under or restricted by GPL or LGPL licenses. The license agreements for libsndfile and liblo can be found in the Nyquist source libraries nyquist/nylsf and nyquist/liblo, respectively. -------------------------------------------------------------------------------- COPYRIGHT AND LICENSE INFORMATION FOR NYQUIST Copyright (c) 2000-2002, by Roger B. Dannenberg All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions of source code must retain the copyright notice, the list of conditions, and the disclaimer, all three of which appear below under "COPYRIGHT AND LICENSE INFORMATION FOR XLISP." Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Redistributions in binary form must reproduce the copyright notice, the list of conditions, and the disclaimer, all three of which appear below under "COPYRIGHT AND LICENSE INFORMATION FOR XLISP," in the documentation and/or other materials provided with the distribution. Neither the name of Roger B. Dannenberg, Carnegie Mellon University, nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. What follows is not a part of the license: Please send bug fixes and improvements to me at the address below. Please do not distribute modified versions of Nyquist without permission. Any redistribution of Nyquist should include a notice that Nyquist can be obtained free from http://www.cs.cmu.edu/~music. In addition, as a courtesy, I ask that you send me a copy of any product that makes substantial use of Nyquist. Please contact me at the address below for my current mailing address. I am asking this because I enjoy learning about applications of my software. When Nyquist is used to generate music and conduct research, please mention and acknowledge the use of Nyquist in program notes, acknowledgement sections of papers, and whereever thanks or credits would normally be given. Roger B. Dannenberg roger.dannenberg@cs.cmu.edu -------------------------------------------------------------------------------- COPYRIGHT AND LICENSE INFORMATION FOR XLISP Copyright (c) 1984-2002, by David Michael Betz All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of David Michael Betz nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. What follows is not a part of the license: Please send bug fixes and improvements to me at the address below. In addition, as a courtesy, I ask that you send me a copy of any product that makes substantial use of XLISP. Please contact me at the address below for my current mailing address. I am asking this because I enjoy learning about applications of my software. David Betz dbetz@xlisper.mv.com nyquist-3.05/fft/0002755000175000000620000000000011537433122012745 5ustar stevestaffnyquist-3.05/fft/fftn.c0000644000175000000620000006711710144436365014065 0ustar stevestaff/*--------------------------------*-C-*---------------------------------* * File: * fftn.c * * Public: * fft_free (); * fftn / fftnf (); * * Private: * fftradix / fftradixf (); * * Descript: * multivariate complex Fourier transform, computed in place * using mixed-radix Fast Fourier Transform algorithm. * * Fortran code by: * RC Singleton, Stanford Research Institute, Sept. 1968 * * translated by f2c (version 19950721). * * Revisions: * 26 July 95 John Beale * - added maxf and maxp as parameters to fftradix() * * 28 July 95 Mark Olesen * - cleaned-up the Fortran 66 goto spaghetti, only 3 labels remain. * * - added fft_free() to provide some measure of control over * allocation/deallocation. * * - added fftn() wrapper for multidimensional FFTs * * - use -DFFT_NOFLOAT or -DFFT_NODOUBLE to avoid compiling that * precision. Note suffix `f' on the function names indicates * float precision. * * - revised documentation * * 31 July 95 Mark Olesen * - added GNU Public License * - more cleanup * - define SUN_BROKEN_REALLOC to use malloc() instead of realloc() * on the first pass through, apparently needed for old libc * - removed #error directive in favour of some code that simply * won't compile (generate an error that way) * * 1 Aug 95 Mark Olesen * - define FFT_RADIX4 to only have radix 2, radix 4 transforms * - made fftradix /fftradixf () static scope, just use fftn() * instead. If you have good ideas about fixing the factors * in fftn() please do so. * * ======================================================================* * NIST Guide to Available Math Software. * Source for module FFT from package GO. * Retrieved from NETLIB on Wed Jul 5 11:50:07 1995. * ======================================================================* * *-----------------------------------------------------------------------* * * int fftn (int ndim, const int dims[], REAL Re[], REAL Im[], * int iSign, double scaling); * * NDIM = the total number dimensions * DIMS = a vector of array sizes * if NDIM is zero then DIMS must be zero-terminated * * RE and IM hold the real and imaginary components of the data, and return * the resulting real and imaginary Fourier coefficients. Multidimensional * data *must* be allocated contiguously. There is no limit on the number * of dimensions. * * ISIGN = the sign of the complex exponential (ie, forward or inverse FFT) * the magnitude of ISIGN (normally 1) is used to determine the * correct indexing increment (see below). * * SCALING = normalizing constant by which the final result is *divided* * if SCALING == -1, normalize by total dimension of the transform * if SCALING < -1, normalize by the square-root of the total dimension * * example: * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] * * int dims[3] = {n1,n2,n3} * fftn (3, dims, Re, Im, 1, scaling); * *-----------------------------------------------------------------------* * int fftradix (REAL Re[], REAL Im[], size_t nTotal, size_t nPass, * size_t nSpan, int iSign, size_t max_factors, * size_t max_perm); * * RE, IM - see above documentation * * Although there is no limit on the number of dimensions, fftradix() must * be called once for each dimension, but the calls may be in any order. * * NTOTAL = the total number of complex data values * NPASS = the dimension of the current variable * NSPAN/NPASS = the spacing of consecutive data values while indexing the * current variable * ISIGN - see above documentation * * example: * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] * * fftradix (Re, Im, n1*n2*n3, n1, n1, 1, maxf, maxp); * fftradix (Re, Im, n1*n2*n3, n2, n1*n2, 1, maxf, maxp); * fftradix (Re, Im, n1*n2*n3, n3, n1*n2*n3, 1, maxf, maxp); * * single-variate transform, * NTOTAL = N = NSPAN = (number of complex data values), * * fftradix (Re, Im, n, n, n, 1, maxf, maxp); * * The data can also be stored in a single array with alternating real and * imaginary parts, the magnitude of ISIGN is changed to 2 to give correct * indexing increment, and data [0] and data [1] used to pass the initial * addresses for the sequences of real and imaginary values, * * example: * REAL data [2*NTOTAL]; * fftradix ( &data[0], &data[1], NTOTAL, nPass, nSpan, 2, maxf, maxp); * * for temporary allocation: * * MAX_FACTORS >= the maximum prime factor of NPASS * MAX_PERM >= the number of prime factors of NPASS. In addition, * if the square-free portion K of NPASS has two or more prime * factors, then MAX_PERM >= (K-1) * * storage in FACTOR for a maximum of 15 prime factors of NPASS. if NPASS * has more than one square-free factor, the product of the square-free * factors must be <= 210 array storage for maximum prime factor of 23 the * following two constants should agree with the array dimensions. * *-----------------------------------------------------------------------* * * void fft_free (void); * * free-up allocated temporary storage after finished all the Fourier * transforms. * *----------------------------------------------------------------------*/ #ifndef _FFTN_C #define _FFTN_C #include #include #include #include "fftn.h" /* double precision routine */ static int fftradix (double Re[], double Im[], size_t nTotal, size_t nPass, size_t nSpan, int isign, int max_factors, int max_perm); /* float precision routine */ static int fftradixf (float Re[], float Im[], size_t nTotal, size_t nPass, size_t nSpan, int isign, int max_factors, int max_perm); /* parameters for memory management */ static size_t SpaceAlloced = 0; static size_t MaxPermAlloced = 0; /* temp space, (void *) since both float and double routines use it */ static void *Tmp0 = NULL; /* temp space for real part */ static void *Tmp1 = NULL; /* temp space for imaginary part */ static void *Tmp2 = NULL; /* temp space for Cosine values */ static void *Tmp3 = NULL; /* temp space for Sine values */ static int *Perm = NULL; /* Permutation vector */ #define NFACTOR 11 static int factor [NFACTOR]; void fft_free (void) { SpaceAlloced = MaxPermAlloced = 0; if (Tmp0 != NULL) { free (Tmp0); Tmp0 = NULL; } if (Tmp1 != NULL) { free (Tmp1); Tmp1 = NULL; } if (Tmp2 != NULL) { free (Tmp2); Tmp2 = NULL; } if (Tmp3 != NULL) { free (Tmp3); Tmp3 = NULL; } if (Perm != NULL) { free (Perm); Perm = NULL; } } #ifndef M_PI # define M_PI 3.14159265358979323846264338327950288 #endif #ifndef SIN60 # define SIN60 0.86602540378443865 /* sin(60 deg) */ # define COS72 0.30901699437494742 /* cos(72 deg) */ # define SIN72 0.95105651629515357 /* sin(72 deg) */ #endif /* re-include this source file on the second pass through */ #undef REAL #undef FFTN #undef FFTNS #undef FFTRADIX #undef FFTRADIXS #ifndef FFT_NOFLOAT # define REAL float # define FFTN fftnf /* trailing 'f' for float */ # define FFTNS "fftnf" /* name for error message */ # define FFTRADIX fftradixf /* trailing 'f' for float */ # define FFTRADIXS "fftradixf" /* name for error message */ # include "fftn.c" /* include this file again */ #endif #undef REAL #undef FFTN #undef FFTNS #undef FFTRADIX #undef FFTRADIXS #ifndef FFT_NODOUBLE # define REAL double # define FFTN fftn # define FFTNS "fftn" # define FFTRADIX fftradix # define FFTRADIXS "fftradix" # include "fftn.c" /* include this file again */ #endif #if defined (FFT_NOFLOAT) && defined (FFT_NODOUBLE) && !defined (lint) Error: cannot have both -DFFT_NOFLOAT and -DFFT_NODOUBLE #endif #else /* _FFTN_C */ /* * */ int FFTN (int ndim, const int dims[], REAL Re [], REAL Im [], int iSign, double scaling) { size_t nSpan, nPass, nTotal; int ret, i, max_factors, max_perm; /* * tally the number of elements in the data array * and determine the number of dimensions */ nTotal = 1; if (ndim && dims [0]) { for (i = 0; i < ndim; i++) { if (dims [i] <= 0) { fputs ("Error: " FFTNS "() - dimension error\n", stderr); fft_free (); /* free-up memory */ return -1; } nTotal *= dims [i]; } } else { ndim = 0; for (i = 0; dims [i]; i++) { if (dims [i] <= 0) { fputs ("Error: " FFTNS "() - dimension error\n", stderr); fft_free (); /* free-up memory */ return -1; } nTotal *= dims [i]; ndim++; } } /* determine maximum number of factors and permuations */ #if 1 /* * follow John Beale's example, just use the largest dimension and don't * worry about excess allocation. May be someone else will do it? */ max_factors = max_perm = 1; for (i = 0; i < ndim; i++) { nSpan = dims [i]; if (nSpan > max_factors) max_factors = nSpan; if (nSpan > max_perm) max_perm = nSpan; } #else /* use the constants used in the original Fortran code */ max_factors = 23; max_perm = 209; #endif /* loop over the dimensions: */ nPass = 1; for (i = 0; i < ndim; i++) { nSpan = dims [i]; nPass *= nSpan; ret = FFTRADIX (Re, Im, nTotal, nSpan, nPass, iSign, max_factors, max_perm); /* exit, clean-up already done */ if (ret) return ret; } /* Divide through by the normalizing constant: */ if (scaling && scaling != 1.0) { if (iSign < 0) iSign = -iSign; if (scaling < 0.0) { scaling = nTotal; if (scaling < -1.0) scaling = sqrt (scaling); } scaling = 1.0 / scaling; /* multiply is often faster */ for (i = 0; i < nTotal; i += iSign) { Re [i] *= scaling; Im [i] *= scaling; } } return 0; } /* * singleton's mixed radix routine * * could move allocation out to fftn(), but leave it here so that it's * possible to make this a standalone function */ static int FFTRADIX (REAL Re[], REAL Im[], size_t nTotal, size_t nPass, size_t nSpan, int iSign, int max_factors, int max_perm) { int ii, mfactor, kspan, ispan, inc; int j, jc, jf, jj, k, k1, k2, k3, k4, kk, kt, nn, ns, nt; REAL radf; REAL c1, c2, c3, cd, aa, aj, ak, ajm, ajp, akm, akp; REAL s1, s2, s3, sd, bb, bj, bk, bjm, bjp, bkm, bkp; REAL *Rtmp = NULL; /* temp space for real part*/ REAL *Itmp = NULL; /* temp space for imaginary part */ REAL *Cos = NULL; /* Cosine values */ REAL *Sin = NULL; /* Sine values */ REAL s60 = SIN60; /* sin(60 deg) */ REAL c72 = COS72; /* cos(72 deg) */ REAL s72 = SIN72; /* sin(72 deg) */ REAL pi2 = M_PI; /* use PI first, 2 PI later */ /* gcc complains about k3 being uninitialized, but I can't find out where * or why ... it looks okay to me. * * initialize to make gcc happy */ k3 = 0; /* gcc complains about c2, c3, s2,s3 being uninitialized, but they're * only used for the radix 4 case and only AFTER the (s1 == 0.0) pass * through the loop at which point they will have been calculated. * * initialize to make gcc happy */ c2 = c3 = s2 = s3 = 0.0; /* Parameter adjustments, was fortran so fix zero-offset */ Re--; Im--; if (nPass < 2) return 0; /* allocate storage */ if (SpaceAlloced < max_factors * sizeof (REAL)) { #ifdef SUN_BROKEN_REALLOC if (!SpaceAlloced) /* first time */ { SpaceAlloced = max_factors * sizeof (REAL); Tmp0 = (void *) malloc (SpaceAlloced); Tmp1 = (void *) malloc (SpaceAlloced); Tmp2 = (void *) malloc (SpaceAlloced); Tmp3 = (void *) malloc (SpaceAlloced); } else { #endif SpaceAlloced = max_factors * sizeof (REAL); Tmp0 = (void *) realloc (Tmp0, SpaceAlloced); Tmp1 = (void *) realloc (Tmp1, SpaceAlloced); Tmp2 = (void *) realloc (Tmp2, SpaceAlloced); Tmp3 = (void *) realloc (Tmp3, SpaceAlloced); #ifdef SUN_BROKEN_REALLOC } #endif } else { /* allow full use of alloc'd space */ max_factors = SpaceAlloced / sizeof (REAL); } if (MaxPermAlloced < max_perm) { #ifdef SUN_BROKEN_REALLOC if (!MaxPermAlloced) /* first time */ Perm = (int *) malloc (max_perm * sizeof(int)); else #endif Perm = (int *) realloc (Perm, max_perm * sizeof(int)); MaxPermAlloced = max_perm; } else { /* allow full use of alloc'd space */ max_perm = MaxPermAlloced; } if (Tmp0 == NULL || Tmp1 == NULL || Tmp2 == NULL || Tmp3 == NULL || Perm == NULL) goto Memory_Error_Label; /* assign pointers */ Rtmp = (REAL *) Tmp0; Itmp = (REAL *) Tmp1; Cos = (REAL *) Tmp2; Sin = (REAL *) Tmp3; /* * Function Body */ inc = iSign; if (iSign < 0) { s72 = -s72; s60 = -s60; pi2 = -pi2; inc = -inc; /* absolute value */ } /* adjust for strange increments */ nt = inc * nTotal; ns = inc * nSpan; kspan = ns; nn = nt - inc; jc = ns / nPass; radf = pi2 * (double) jc; pi2 *= 2.0; /* use 2 PI from here on */ ii = 0; jf = 0; /* determine the factors of n */ mfactor = 0; k = nPass; while (k % 16 == 0) { mfactor++; factor [mfactor - 1] = 4; k /= 16; } j = 3; jj = 9; do { while (k % jj == 0) { mfactor++; factor [mfactor - 1] = j; k /= jj; } j += 2; jj = j * j; } while (jj <= k); if (k <= 4) { kt = mfactor; factor [mfactor] = k; if (k != 1) mfactor++; } else { if (k - (k / 4 << 2) == 0) { mfactor++; factor [mfactor - 1] = 2; k /= 4; } kt = mfactor; j = 2; do { if (k % j == 0) { mfactor++; factor [mfactor - 1] = j; k /= j; } j = ((j + 1) / 2 << 1) + 1; } while (j <= k); } if (kt) { j = kt; do { mfactor++; factor [mfactor - 1] = factor [j - 1]; j--; } while (j); } /* test that mfactors is in range */ if (mfactor > NFACTOR) { fputs ("Error: " FFTRADIXS "() - exceeded number of factors\n", stderr); goto Memory_Error_Label; } /* compute fourier transform */ for (;;) { sd = radf / (double) kspan; cd = sin(sd); cd = 2.0 * cd * cd; sd = sin(sd + sd); kk = 1; ii++; switch (factor [ii - 1]) { case 2: /* transform for factor of 2 (including rotation factor) */ kspan /= 2; k1 = kspan + 2; do { do { k2 = kk + kspan; ak = Re [k2]; bk = Im [k2]; Re [k2] = Re [kk] - ak; Im [k2] = Im [kk] - bk; Re [kk] += ak; Im [kk] += bk; kk = k2 + kspan; } while (kk <= nn); kk -= nn; } while (kk <= jc); if (kk > kspan) goto Permute_Results_Label; /* exit infinite loop */ do { c1 = 1.0 - cd; s1 = sd; do { do { do { k2 = kk + kspan; ak = Re [kk] - Re [k2]; bk = Im [kk] - Im [k2]; Re [kk] += Re [k2]; Im [kk] += Im [k2]; Re [k2] = c1 * ak - s1 * bk; Im [k2] = s1 * ak + c1 * bk; kk = k2 + kspan; } while (kk < nt); k2 = kk - nt; c1 = -c1; kk = k1 - k2; } while (kk > k2); ak = c1 - (cd * c1 + sd * s1); s1 = sd * c1 - cd * s1 + s1; c1 = 2.0 - (ak * ak + s1 * s1); s1 *= c1; c1 *= ak; kk += jc; } while (kk < k2); k1 += inc + inc; kk = (k1 - kspan) / 2 + jc; } while (kk <= jc + jc); break; case 4: /* transform for factor of 4 */ ispan = kspan; kspan /= 4; do { c1 = 1.0; s1 = 0.0; do { do { k1 = kk + kspan; k2 = k1 + kspan; k3 = k2 + kspan; akp = Re [kk] + Re [k2]; akm = Re [kk] - Re [k2]; ajp = Re [k1] + Re [k3]; ajm = Re [k1] - Re [k3]; bkp = Im [kk] + Im [k2]; bkm = Im [kk] - Im [k2]; bjp = Im [k1] + Im [k3]; bjm = Im [k1] - Im [k3]; Re [kk] = akp + ajp; Im [kk] = bkp + bjp; ajp = akp - ajp; bjp = bkp - bjp; if (iSign < 0) { akp = akm + bjm; bkp = bkm - ajm; akm -= bjm; bkm += ajm; } else { akp = akm - bjm; bkp = bkm + ajm; akm += bjm; bkm -= ajm; } /* avoid useless multiplies */ if (s1 == 0.0) { Re [k1] = akp; Re [k2] = ajp; Re [k3] = akm; Im [k1] = bkp; Im [k2] = bjp; Im [k3] = bkm; } else { Re [k1] = akp * c1 - bkp * s1; Re [k2] = ajp * c2 - bjp * s2; Re [k3] = akm * c3 - bkm * s3; Im [k1] = akp * s1 + bkp * c1; Im [k2] = ajp * s2 + bjp * c2; Im [k3] = akm * s3 + bkm * c3; } kk = k3 + kspan; } while (kk <= nt); c2 = c1 - (cd * c1 + sd * s1); s1 = sd * c1 - cd * s1 + s1; c1 = 2.0 - (c2 * c2 + s1 * s1); s1 *= c1; c1 *= c2; /* values of c2, c3, s2, s3 that will get used next time */ c2 = c1 * c1 - s1 * s1; s2 = 2.0 * c1 * s1; c3 = c2 * c1 - s2 * s1; s3 = c2 * s1 + s2 * c1; kk = kk - nt + jc; } while (kk <= kspan); kk = kk - kspan + inc; } while (kk <= jc); if (kspan == jc) goto Permute_Results_Label; /* exit infinite loop */ break; default: /* transform for odd factors */ #ifdef FFT_RADIX4 fputs ("Error: " FFTRADIXS "(): compiled for radix 2/4 only\n", stderr); fft_free (); /* free-up memory */ return -1; break; #else /* FFT_RADIX4 */ k = factor [ii - 1]; ispan = kspan; kspan /= k; switch (k) { case 3: /* transform for factor of 3 (optional code) */ do { do { k1 = kk + kspan; k2 = k1 + kspan; ak = Re [kk]; bk = Im [kk]; aj = Re [k1] + Re [k2]; bj = Im [k1] + Im [k2]; Re [kk] = ak + aj; Im [kk] = bk + bj; ak -= 0.5 * aj; bk -= 0.5 * bj; aj = (Re [k1] - Re [k2]) * s60; bj = (Im [k1] - Im [k2]) * s60; Re [k1] = ak - bj; Re [k2] = ak + bj; Im [k1] = bk + aj; Im [k2] = bk - aj; kk = k2 + kspan; } while (kk < nn); kk -= nn; } while (kk <= kspan); break; case 5: /* transform for factor of 5 (optional code) */ c2 = c72 * c72 - s72 * s72; s2 = 2.0 * c72 * s72; do { do { k1 = kk + kspan; k2 = k1 + kspan; k3 = k2 + kspan; k4 = k3 + kspan; akp = Re [k1] + Re [k4]; akm = Re [k1] - Re [k4]; bkp = Im [k1] + Im [k4]; bkm = Im [k1] - Im [k4]; ajp = Re [k2] + Re [k3]; ajm = Re [k2] - Re [k3]; bjp = Im [k2] + Im [k3]; bjm = Im [k2] - Im [k3]; aa = Re [kk]; bb = Im [kk]; Re [kk] = aa + akp + ajp; Im [kk] = bb + bkp + bjp; ak = akp * c72 + ajp * c2 + aa; bk = bkp * c72 + bjp * c2 + bb; aj = akm * s72 + ajm * s2; bj = bkm * s72 + bjm * s2; Re [k1] = ak - bj; Re [k4] = ak + bj; Im [k1] = bk + aj; Im [k4] = bk - aj; ak = akp * c2 + ajp * c72 + aa; bk = bkp * c2 + bjp * c72 + bb; aj = akm * s2 - ajm * s72; bj = bkm * s2 - bjm * s72; Re [k2] = ak - bj; Re [k3] = ak + bj; Im [k2] = bk + aj; Im [k3] = bk - aj; kk = k4 + kspan; } while (kk < nn); kk -= nn; } while (kk <= kspan); break; default: if (k != jf) { jf = k; s1 = pi2 / (double) k; c1 = cos(s1); s1 = sin(s1); if (jf > max_factors) goto Memory_Error_Label; Cos [jf - 1] = 1.0; Sin [jf - 1] = 0.0; j = 1; do { Cos [j - 1] = Cos [k - 1] * c1 + Sin [k - 1] * s1; Sin [j - 1] = Cos [k - 1] * s1 - Sin [k - 1] * c1; k--; Cos [k - 1] = Cos [j - 1]; Sin [k - 1] = -Sin [j - 1]; j++; } while (j < k); } do { do { k1 = kk; k2 = kk + ispan; ak = aa = Re [kk]; bk = bb = Im [kk]; j = 1; k1 += kspan; do { k2 -= kspan; j++; Rtmp [j - 1] = Re [k1] + Re [k2]; ak += Rtmp [j - 1]; Itmp [j - 1] = Im [k1] + Im [k2]; bk += Itmp [j - 1]; j++; Rtmp [j - 1] = Re [k1] - Re [k2]; Itmp [j - 1] = Im [k1] - Im [k2]; k1 += kspan; } while (k1 < k2); Re [kk] = ak; Im [kk] = bk; k1 = kk; k2 = kk + ispan; j = 1; do { k1 += kspan; k2 -= kspan; jj = j; ak = aa; bk = bb; aj = 0.0; bj = 0.0; k = 1; do { k++; ak += Rtmp [k - 1] * Cos [jj - 1]; bk += Itmp [k - 1] * Cos [jj - 1]; k++; aj += Rtmp [k - 1] * Sin [jj - 1]; bj += Itmp [k - 1] * Sin [jj - 1]; jj += j; if (jj > jf) { jj -= jf; } } while (k < jf); k = jf - j; Re [k1] = ak - bj; Im [k1] = bk + aj; Re [k2] = ak + bj; Im [k2] = bk - aj; j++; } while (j < k); kk += ispan; } while (kk <= nn); kk -= nn; } while (kk <= kspan); break; } /* multiply by rotation factor (except for factors of 2 and 4) */ if (ii == mfactor) goto Permute_Results_Label; /* exit infinite loop */ kk = jc + 1; do { c2 = 1.0 - cd; s1 = sd; do { c1 = c2; s2 = s1; kk += kspan; do { do { ak = Re [kk]; Re [kk] = c2 * ak - s2 * Im [kk]; Im [kk] = s2 * ak + c2 * Im [kk]; kk += ispan; } while (kk <= nt); ak = s1 * s2; s2 = s1 * c2 + c1 * s2; c2 = c1 * c2 - ak; kk = kk - nt + kspan; } while (kk <= ispan); c2 = c1 - (cd * c1 + sd * s1); s1 += sd * c1 - cd * s1; c1 = 2.0 - (c2 * c2 + s1 * s1); s1 *= c1; c2 *= c1; kk = kk - ispan + jc; } while (kk <= kspan); kk = kk - kspan + jc + inc; } while (kk <= jc + jc); break; #endif /* FFT_RADIX4 */ } } /* permute the results to normal order---done in two stages */ /* permutation for square factors of n */ Permute_Results_Label: Perm [0] = ns; if (kt) { k = kt + kt + 1; if (mfactor < k) k--; j = 1; Perm [k] = jc; do { Perm [j] = Perm [j - 1] / factor [j - 1]; Perm [k - 1] = Perm [k] * factor [j - 1]; j++; k--; } while (j < k); k3 = Perm [k]; kspan = Perm [1]; kk = jc + 1; k2 = kspan + 1; j = 1; if (nPass != nTotal) { /* permutation for multivariate transform */ Permute_Multi_Label: do { do { k = kk + jc; do { /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; kk += inc; k2 += inc; } while (kk < k); kk += ns - jc; k2 += ns - jc; } while (kk < nt); k2 = k2 - nt + kspan; kk = kk - nt + jc; } while (k2 < ns); do { do { k2 -= Perm [j - 1]; j++; k2 = Perm [j] + k2; } while (k2 > Perm [j - 1]); j = 1; do { if (kk < k2) goto Permute_Multi_Label; kk += jc; k2 += kspan; } while (k2 < ns); } while (kk < ns); } else { /* permutation for single-variate transform (optional code) */ Permute_Single_Label: do { /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; kk += inc; k2 += kspan; } while (k2 < ns); do { do { k2 -= Perm [j - 1]; j++; k2 = Perm [j] + k2; } while (k2 > Perm [j - 1]); j = 1; do { if (kk < k2) goto Permute_Single_Label; kk += inc; k2 += kspan; } while (k2 < ns); } while (kk < ns); } jc = k3; } if ((kt << 1) + 1 >= mfactor) return 0; ispan = Perm [kt]; /* permutation for square-free factors of n */ j = mfactor - kt; factor [j] = 1; do { factor [j - 1] *= factor [j]; j--; } while (j != kt); kt++; nn = factor [kt - 1] - 1; if (nn > max_perm) goto Memory_Error_Label; j = jj = 0; for (;;) { k = kt + 1; k2 = factor [kt - 1]; kk = factor [k - 1]; j++; if (j > nn) break; /* exit infinite loop */ jj += kk; while (jj >= k2) { jj -= k2; k2 = kk; k++; kk = factor [k - 1]; jj += kk; } Perm [j - 1] = jj; } /* determine the permutation cycles of length greater than 1 */ j = 0; for (;;) { do { j++; kk = Perm [j - 1]; } while (kk < 0); if (kk != j) { do { k = kk; kk = Perm [k - 1]; Perm [k - 1] = -kk; } while (kk != j); k3 = kk; } else { Perm [j - 1] = -j; if (j == nn) break; /* exit infinite loop */ } } max_factors *= inc; /* reorder a and b, following the permutation cycles */ for (;;) { j = k3 + 1; nt -= ispan; ii = nt - inc + 1; if (nt < 0) break; /* exit infinite loop */ do { do { j--; } while (Perm [j - 1] < 0); jj = jc; do { kspan = jj; if (jj > max_factors) { kspan = max_factors; } jj -= kspan; k = Perm [j - 1]; kk = jc * k + ii + jj; k1 = kk + kspan; k2 = 0; do { k2++; Rtmp [k2 - 1] = Re [k1]; Itmp [k2 - 1] = Im [k1]; k1 -= inc; } while (k1 != kk); do { k1 = kk + kspan; k2 = k1 - jc * (k + Perm [k - 1]); k = -Perm [k - 1]; do { Re [k1] = Re [k2]; Im [k1] = Im [k2]; k1 -= inc; k2 -= inc; } while (k1 != kk); kk = k2; } while (k != j); k1 = kk + kspan; k2 = 0; do { k2++; Re [k1] = Rtmp [k2 - 1]; Im [k1] = Itmp [k2 - 1]; k1 -= inc; } while (k1 != kk); } while (jj); } while (j != 1); } return 0; /* exit point here */ /* alloc or other problem, do some clean-up */ Memory_Error_Label: fputs ("Error: " FFTRADIXS "() - insufficient memory.\n", stderr); fft_free (); /* free-up memory */ return -1; } #endif /* _FFTN_C */ /* ---------------------- end-of-file (c source) ---------------------- */ nyquist-3.05/fft/fftn.h0000644000175000000620000000223010144436365014053 0ustar stevestaff/*--------------------------------*-C-*---------------------------------* * File: * fftn.h * ---------------------------------------------------------------------* * Re[]: real value array * Im[]: imaginary value array * nTotal: total number of complex values * nPass: number of elements involved in this pass of transform * nSpan: nspan/nPass = number of bytes to increment pointer * in Re[] and Im[] * isign: exponent: +1 = forward -1 = reverse * scaling: normalizing constant by which the final result is *divided* * scaling == -1, normalize by total dimension of the transform * scaling < -1, normalize by the square-root of the total dimension * * ---------------------------------------------------------------------- * See the comments in the code for correct usage! */ #ifndef _FFTN_H #define _FFTN_H extern void fft_free (void); /* double precision routine */ extern int fftn (int ndim, const int dims[], double Re[], double Im[], int isign, double scaling); /* float precision routine */ extern int fftnf (int ndim, const int dims[], float Re[], float Im[], int isign, double scaling); #endif /* _FFTN_H */ nyquist-3.05/release.bat0000644000175000000620000000205211466723256014306 0ustar stevestaffrmdir /s /q nyqrel mkdir nyqrel xcopy runtime nyqrel\runtime /s /i del nyqrel\runtime\CVS /q rmdir nyqrel\runtime\CVS /q copy sys\win\msvc\system.lsp nyqrel\runtime xcopy doc nyqrel\doc /s /i del nyqrel\doc\CVS /q rmdir nyqrel\doc\CVS /q xcopy lib nyqrel\lib /s /i del nyqrel\lib\CVS /q rmdir nyqrel\lib\CVS /q xcopy demos nyqrel\demos /s /i del nyqrel\demos\jones\docs /q rmdir nyqrel\demos\jones\docs /q del nyqrel\demos\jones\nydoc /q rmdir nyqrel\demos\jones\nydoc /q del nyqrel\demos\jones\sjlib /q rmdir nyqrel\demos\jones\sjlib /q del nyqrel\demos\jones /q rmdir nyqrel\demos\jones /q del nyqrel\demos\plight\kit /q rmdir nyqrel\demos\plight\kit /q del nyqrel\demos\plight /q rmdir nyqrel\demos\plight /q del nyqrel\demos\CVS /q rmdir nyqrel\demos\CVS /q del nyqrel\demos\pmorales\CVS /q rmdir nyqrel\demos\pmorales\CVS /q copy WinRel\nyquist.exe nyqrel copy liblo\test-client\Release\osc-test-client.exe nyqrel copy liblo\ser-to-osc\Release\ser-to-osc.exe nyqrel copy advantages.txt nyqrel copy readme.txt nyqrel copy todo.txt nyqrel copy license.txt nyqrel nyquist-3.05/comp-ide.bat0000644000175000000620000000065111537224066014360 0ustar stevestaffrem comp-ide.bat -- compile the jnyqide on Windows: just type comp-ide rem rem On windows, we compile everything but SpecialMacHandler.java rem echo ****COMPILING JNYQIDE****************************** cd jnyqide ren SpecialMacHandler.java SpecialMacHandler.hidden javac *.java ren SpecialMacHandler.hidden SpecialMacHandler.java cd .. rem jnyqide\jNyqIDE.jar jar -cfm jnyqide\jNyqIDE.jar jnyqide/manifest.txt jnyqide/*.class nyquist-3.05/snd/0002755000175000000620000000000011537433122012752 5ustar stevestaffnyquist-3.05/snd/sndfailwin32.c0000644000175000000620000000051510144436365015425 0ustar stevestaff/* sndfailwin32.c -- version of sndfail that puts up a message box */ /* this should not be compiled into an snd library! handling snd_fail * is application specific */ #include void snd_fail(char *msg) { MessageBox(0, msg, 0, 0); exit(1); } void snd_warn(char *msg) { MessageBox(0, msg, 0, MB_OK); } nyquist-3.05/snd/audiopa.c0000644000175000000620000000130010144436365014535 0ustar stevestaff#include "snd.h" long audio_poll(snd_type snd) { return 0; } long audio_read(snd_type snd, void *buffer, long length) { return 0; } long audio_write(snd_type snd, void *buffer, long length) { return 0; } int audio_open(snd_type snd, long *flags) { return 0; } int audio_close(snd_type snd) { return 0; } /* audio_flush -- finish audio output */ int audio_flush(snd_type snd) { return 0; } int audio_reset(snd_type snd) { return 0; } snd_fns_node mmsystem_dictionary = { audio_poll, audio_read, audio_write, audio_open, audio_close, audio_reset, audio_flush }; void snd_init() { snd_add_device("PortAudio", "default", &mmsystem_dictionary); } nyquist-3.05/snd/sndfreebsd.h0000644000175000000620000000057510144436365015254 0ustar stevestaff/* sndfreebsd.h -- system-specific definitions */ typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflicts if already defined: */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/snd/sndsystem.c0000644000175000000620000000075610144436365015162 0ustar stevestaff/* sndsystem.c * * Roger Dannenberg * 21 Jun 1997 * */ #include "stdlib.h" #include "stdio.h" #include "snd.h" #ifdef __cplusplus extern "C" { #endif #ifndef __WX__ void snd_fail(char *msg) { printf("ERROR: %s\n", msg); } #endif void *snd_alloc(size_t s) { void *res; /* printf("snd_alloc of %ld ", s); */ res = malloc(s); return res; } void snd_free(void *a) { /* printf("snd_free of %lx\n", a);*/ free(a); } #ifdef __cplusplus } // extern "C" #endif nyquist-3.05/snd/snd.htm0000644000175000000620000005766310144436365014274 0ustar stevestaff Sndlib: Audio File, Format Conversion, and I/O Utilities

    Sndlib: Audio File, Format Conversion, and I/O Utilities

    Roger B. Dannenberg

    History

    • 18 June 97: Created.
    • 6 July 97: Revised
    • 7 May 00: Revised with multiple interface support and inner architecture documentation

    Abstract

    This document describes a set of portable C utilities for digital audio input and output to and from files and audio interfaces. The purpose is to read and write sound files in a variety of formats and to play and record audio. This code is intended for use in interactive and general purpose audio systems, and should be portable to virtually any computer system that supports C and has a file system.

    Overview

    There is basically one interesting data type: snd_type is a pointer to a descriptor for an audio stream, which is either being read from or written to a file or audio interface. The snd_type contains a structure that describes the sample format, sample rate, number of channels, etc.

    Routines exist to initialize sound transfer (snd_open()), perform transfers (snd_read(), snd_write()) and to finalize a transfer (snd_close()). Other routines allow you to transfer data to/from buffers and to convert formats. Sample rate conversion is not currently supported, but would be a welcome addition.

    typedef struct {
        long channels;	/* number of channels */
        long mode;		/* ADPCM, PCM, ULAW, ALAW, FLOAT, UPCM */
        long bits;		/* bits per sample */
        double srate;	/* sample rate */
    } format_node;
    
    #define snd_string_max 258
    
    
    /* the snd_type structure for applications to use: */
    typedef struct snd_struct {
        short device; 	/* file, audio, or memory */
        short write_flag;	/* SND_READ, SND_WRITE, SND_OVERWRITE */
        format_node format;	/* sample format: channels, mode, bits, srate */
        snd_fns_type dictionary;    /* for internal use only */
        union {
          struct {
    	char filename[snd_string_max];	/* file name */
    	char filetype[snd_string_max];  /* file type if known */ 
    	int file;             /* OS file number */
    	long header;          /* None, AIFF, IRCAM, NEXT, WAVE */
    	long byte_offset;     /* file offset of first sample */
    	long end_offset;      /* byte_offset of last byte + 1 */
            long current_offset;  /* current (computed) file offset */
    	int swap;         /* flag to swap bytes on input/output */
    	/* fields from AIFF sample files: */
    	int loop_info;    /* Boolean: is this loop info valid? */
    	double native_hz; /* original pitch in hz */
            float gain;       /* gain: scale factor */
            double low_hz;
            double high_hz;
            char low_velocity;
            char high_velocity;
    	loop_node sustain_loop;
    	loop_node release_loop;
          } file;
          struct {
            char interfacename[snd_string_max]; /* (optional) to specify interface */
    	char devicename[snd_string_max]; /* (optional) to specify device */
    	void *descriptor;
    	long protocol;	/* SND_REALTIME or SND_COMPUTEAHEAD */
    	double latency;	/* app + os worst case latency (seconds) */
    	double granularity; /* expected period of app computation (s) */
    	/* note: pass 0.0 for default latency and granularity */
          } audio;
          struct {
    	long buffer_max;    /* size of buffer memory */
    	char *buffer;       /* memory buffer */
    	long buffer_len;    /* length of data in buffer */
    	long buffer_pos;    /* current location in buffer */
          } mem;
        } u;
    } snd_node, *snd_type;
    

    The meanings of fields are as follows:

    • device: one of SND_DEVICE_FILE (data to/from file), SND_DEVICE_AUDIO (data to/from audio I/O device), SND_DEVICE_MEM (data to/from in-memory buffer), or SND_DEVICE_NONE (records that snd_open failed).
    • write_flag: one of SND_WRITE (create a file and write to it), SND_READ (read from a file), SND_OVERWRITE (overwrite some samples within a file, leaving the header and other samples untouched).
    • format: contains
      • channels: number of audio channels
      • mode: one of SND_MODE_ADPCM (adaptive delta modulation), SND_MODE_PCM (pulse code modulation, i.e. simple linear encoding), SND_MODE_ULAW (Mu-Law), SND_MODE_ALAW (A-Law), SND_MODE_FLOAT (float), or SND_MODE_UPCM (unsigned PCM).
      • bits: number of per sample.
      • srate: sample rate in samples per second (Hz).

    These are additional fields for when device is SND_DEVICE_FILE:

    • filename: string name for file.
    • filetype: string name for file type (see "Unknown File Types" below)
    • file: the file number or handle returned by the operating system. (In some implementations, this may be a pointer to a file descriptor object cast into an integer.)
    • header: the type and format of header, one of SND_HEAD_NONE (no header), SND_HEAD_AIFF, SND_HEAD_IRCAM, SND_HEAD_NEXT (Sun and NeXT format), or SND_HEAD_WAVE.
    • byte_offset: the byte offset in the file. After opening the file, this is the offset of the first sample. This value is updated after each read or write.
    • end_offset: offset of the byte just beyond the last byte of the file.

    These are additional fields for when device is SND_DEVICE_AUDIO:

    • devicename: string name for device (to select among multiple devices). This may be set to the empty string (devicename[0] = 0;) to indicate the default audio device, or it may be set to a name obtained from snd_devicename().
    • descriptor: a field to store system-dependent data protocol: SND_REALTIME (use this if you are trying to compute ahead by a constant amount, especially for low-latency output) or SND_COMPUTEAHEAD (use this if you want to keep output buffers as full as possible, which will cause greater compute-ahead).
    • latency: (minimum) amount to be kept in buffer(s). This should be at least as great as the longest computational delay of the application PLUS the worst case latency for scheduling the application to run.
    • granularity: expected period of the periodic computation that generates samples. Also, granularity indicates the largest number of samples that will be written with snd_write or read with snd_read by the application.

    The following fields are for when device is SND_DEVICE_MEM (in-memory data):

    • buffer_max: the size of the buffer memory (in bytes)
    • buffer: the memory buffer address
    • buffer_len: the length of data in the buffer
    • buffer_pos: the current location of the input/output in memory.

    Routine descriptions

    Terminology

    A sample is one amplitude measurement from one channel. Ordinarily, a sound file can contain multiple channels. All channels have the same sample rate and length, and samples are treated as occurring simultaneously across all channels. The collection of samples occurring simultaneously is called a frame. Samples are stored in frame order. Within a frame, samples are stored in order of increasing channel number.

    All routines described here measure data in units of frames (not samples, not bytes). One exception is snd_seek(), which measures file position in seconds of time, expressed as a double.

    int snd_open(snd_type snd, long *flags);

    To open a file, fill in fields of a snd_type and call snd_open(). If there is header information in the file or device characteristics for the audio interface, fields of snd are filled in. The flags parameter tells which fields were specified by the snd_open() process. E.g. if you open a raw file, there is no header info, so the format will be as specified in snd. On the other hand, if you open an AIFF file, the file will specify the sample rate, channels, bits, etc., so all these values will be written into snd, and bits will be set in flags to indicate the information was picked up from the file.

    Returns SND_SUCCESS iff successful. If not successful, attempts to open a file will place the (system dependent) return code from open() into the u.file.file field.

    Before calling snd_open(), all general fields and fields corresponding to the device (e.g. u.file for SND_DEVICE_FILE) should be set, with the following exceptions: u.file.header (for SND_WRITE), byte_offset, end_offset, descriptor. The field filetype is set but not read by snd_open().

    NOTE: For SND_DEVICE_MEM, fill in the u.mem fields directly and call snd_open(), which merely sets the dictionary field with function pointers. The application is responsible for maintaining u.mem: u.mem.buffer_len is the write pointer (snd_write() data goes here), and u.mem.buffer_pos is the read pointer (snd_read() data comes from here).

    NOTE 2: for SND_DEVICE_MEM, you can set write_flag to SND_WRITE, write data into the buffer, then set write_flag to SND_READ and read the buffer. Use snd_reset() before reading the buffer again to read from the beginning of the buffer, or simply reset read and write pointers directly to read/write different parts of the buffer.

    int snd_close(snd_type snd);

    Closes a file or audio device. There is no need to call snd_close for SND_DEVICE_MEMORY, but this is not an error.

    Returns SND_SUCCESS iff successful.

    int snd_seek(snd_type snd, double when);

    After opening a file for reading or overwriting, you can seek ahead to a specific time point by calling snd_seek(). The when parameter is in seconds and indicates seconds of time relative to the beginning of the sound.

    Returns SND_SUCCESS iff successful.

    int snd_reset(snd_type snd);

    Resets non-file buffers. If snd has SND_DEVICE_AUDIO, then the sample buffers are flushed. This might be a good idea before reading samples after a long pause that would cause buffers to overflow and contain old data, or before writing samples if you want the samples to play immediately, overriding anything already in the buffers.

    If snd has SND_DEVICE_MEM and SND_READ, then the buffer read pointer (buffer_pos) is reset to zero. If SND_WRITE is set, then the buffer read pointer (buffer_pos) and write pointer (buffer_len) are reset to zero.

    If snd has SND_DEVICE_FILE, nothing happens.

    Returns SND_SUCCESS iff successful.

    long snd_read(snd_type snd, void *buffer, long length);

    Read up to length frames into buffer.

    Returns the number of frames actually read.

    int snd_write(snd_type snd, void *buffer, long length);

    Writes length frames from buffer to file or device.

    Returns number of frames actually written.

    long snd_convert(snd_type snd1, void *buffer1,
                     snd_type snd2, void *buffer2, long length);

    To read from a source and write to a sink, you may have to convert formats. This routine provides simple format conversions according to what is specified in snd1 and snd2. The number of frames to convert is given by length, and the number of frames is returned.

    long snd_poll(snd_type snd);

    The standard way to play files is to put something in the event loop that refills an output buffer managed by the device driver. This routine allows you to ask whether there is space to output more samples. If SND_REALTIME is selected, the number returned by snd_poll() will grow fairly smoothly at the sample rate, i.e. if the sample rate is 8KHz, then the result of snd_poll() will increase by 8 per millisecond. On the other hand, if SND_COMPUTEAHEAD is selected, then snd_poll() will return zero until a sample buffer becomes available, at which time the value returned will be the entire buffer size.

    In some implementations, with SND_REALTIME, snd_poll() can be used to furnish a time reference that is synchronized to the sample clock. In other words, the number of frames written plus the value returned by snd_poll() increases steadily in steps no larger than granularity.

    Note: some low-level functions are implemented for conversion from buffers of floats to various representations and from these representations back to floats. See snd.h for their declarations.

    int snd_flush(snd_type snd);

    When the device is SND_DEVICE_AUDIO, writes are buffered. After the last write, call snd_flush() to transfer samples from the buffer to the output device. snd_flush() returns immediately, but it only returns SND_SUCCESS after the data has been output to the audio device. Since calling snd_close() will terminate output, the proper way to finish audio output is to call snd_flush() repeatedly until it returns SND_SUCCESS. Then call snd_close() to close the audio device and free buffers.

    If snd_flush is called on any open snd_type other than a SND_DEVICE_AUDIO opened for output, it returns SND_SUCCESS. Results are undefined if snd_flush() is called on a non-open snd_type.

    long snd_bytes_per_frame(snd_type snd);

    Calculates the number of bytes in a frame (a frame has one sample per channel; sound files are stored as a sequence of frames).

    char *snd_mode_to_string(long mode);

    Returns a string describing the mode (SND_MODE_PCM, etc.).

    int snd_device(int n, char *interf, char *device);

    Sets strings describing the n-th audio device. interf is set to the interface name and device is set to the device name. Both should be allocated to be at least snd_string_max bytes in length. Returns NULL if n is greater or equal to the number of audio devices. Available devices are numbered, starting with the default device at n=0. Before opening an audio device, an application can use this to enumerate all possible devices, select one (e.g. by presenting a list to the user), and then copy the strings into the devicename and interfacename fields of the snd_type structure. If the devicename field is the empty string, device 0 will be opened.

    Unknown File Types

    Normally, the caller does not need to know anything about a file other than its name in order to open and read it. The library figures out the file encoding from header information. Only in the case of headerless files does the caller need to supply format parameters. If the file format is not recognized, snd_open() opens the file according to the supplied format parameters. If the file format is recognized but not supported, snd_open() will return SND_FAILURE, and the flags parameter will indicate what format information was detected. For example, if the number of channels is 4, format.channels is set to 4 and the SND_HEAD_CHANNELS bit is set in flags. If the name of the format is known, e.g. "MP3," but there is no decoder for the format, then the filetype field is set to that string name, and the SND_HEAD_FILETYPE bit is set in flags.

    To detect and report an unknown file type, test the result of snd_open() for SND_SUCCESS. If not successful, test flags to see what information is valid. You may wish to report back to the user, especially if the SND_HEAD_FILETYPE bit is set.

    Examples

    See convert.c for examples of:

    • Printing information about a sound file
    • Converting sound file formats
    • Playing audio from a file
    • Reading audio from audio input

    Compiling the source code

    To compile convert.c under Visual C++, add all the .c files to a console application project and add these libraries to the Object/library modules list under the Link tab in the Project Settings dialog box: winmm.lib wsock32.lib. If wsock32.lib does not work, try ws2_32.lib. The purpose of these libraries is to get functions that perform byte swapping in a system-independent way.

    Inner architecture description

    To modify or extend the Sndlib code, it is important to understand the architecture and design. The main issues are the structure used to obtain portability, and the support for multiple device interfaces within a given system.

    Portability

    The include file snd.h declares most of the library structures and routines. snd.h includes sndconfig.h, which handles system dependencies.

    System-dependent code is selected using conditional compilation. The following compile-time symbols are defined:

    • WIN32: Some version of Windows (95, 98, or NT)
    • UNIX: Some version of Unix. One of the following should also be defined:
      • LINUX: The Linux Operating System.
      • IRIX: The SGI Irix Operating System.
    • MACINTOSH: Some version of MacOS.

    sndconfig.h is responsible for defining a number of routines and/or macros, including the macro that selects the system. E.g. under Visual C++, the macro _WIN32 is defined, so sndconfig.h defines WIN32. If _WIN32 is defined. The other routines and macros to be defined are described in sndconfig.h itself. To avoid too many conditional compilation statements that make code hard to read, sndconfig.h works by conditionally including another .h file. The files are named sndwin32.h, sndlinux.h, sndirix.h, and sndmac.h, and other systems should implement include files in the same manner.

    In addition to the Unix, Windows, Macintosh distinction, this library also supports WX, a graphical user interface library. WX provides its own routines for file IO, and WX runs under Windows, Unix, and the Macintosh. This adds some confusion because WX functions cut across the Windows, Unix, Macintosh spectrum for things like file IO, but WX functions do not implement audio, so we still need to distinguish systems. To handle WX, a set of IO functions have been created, e.g. snd_open(), snd_read(), and snd_write(), and these are defined in sndwin32.h etc. only if WX is not defined. If WX is defined, then another include file sndwx.h is included into sndconfig.h to define the IO routines independently of what system is being compiled.

    Multiple interface support

    In the original designed, it was assumed that each operating system would provide one and only one audio interface, and this library would provide an abstract layer above that. It turned out that many operating systems offer multiple interfaces, e.g. Windows has both the multimedia interface and DirectSound, and Linux has several competing interfaces. Windows machines also have ASIO and other interface possibilities.

    To support multiple interfaces, the library has the call snd_devicename() which returns the name of the nth audio device. Where do these names come from? System-specific parts of the library call a non-system specific function as follows:

    /* these types are for internal use: */
    typedef int (*snd_reset_fn)(snd_type snd);
    typedef long (*snd_poll_fn)(snd_type snd);
    typedef long (*snd_read_fn)(snd_type snd, void *buffer, long length);
    typedef long (*snd_write_fn)(snd_type snd, void *buffer, long length);
    typedef int (*snd_open_fn)(snd_type snd, long *flags);
    typedef int (*snd_close_fn)(snd_type snd);
    typedef int (*snd_reset_fn)(snd_type snd);
    typedef int (*snd_flush_fn)(snd_type snd);
    
    typedef struct {
        snd_reset_fn reset;
        snd_poll_fn poll;
        snd_read_fn read;
        snd_write_fn write;
        snd_open_fn open;
        snd_close_fn close;
        snd_reset_fn reset;
        snd_flush_fn flush;
    } snd_fns_node, *snd_fns_type;
    
    void snd_add_device(char *devicename, snd_fns_type dictionary);
    

    This is called for each different device or interface. In the general case, there might be several physical devices, each supporting several logical devices (front stereo, rear stereo, and quad), and there might be several different system APIs that access these (MM and DirectSound). The system-specific code provides a string name for each of these and a dictionary of function pointers for each.

    When does the system-specific code call snd_add_device()? When either snd_open() or snd_devicename() is called for the first time, a call is made to snd_init(), which is defined in system-specific code. snd_init() is responsible for calling detection and initialization code for each supported device.

    The snd_fns_node structure contains function pointers that implement the library functions. A pointer to this structure is found in the snd_type structure which is passed to nearly every library function. These library functions are implemented by making indirect calls through these function pointers.

    Note that most of these functions take byte-counts as length parameters rather than frames. This is because standard system calls such as read() and write() use bytes.

    !sys/switches.h.template /* switches.h template file */ #undef HAS_STDLIB_H #undef HAS_SYS_TYPES_H #undef HAS_SYS_STAT_H #undef HAS_STAT_H #undef HAS_MALLOC_H #undef HAS_GETTIMEOFDAY #undef READLINE #undef XL_BIG_ENDIAN #undef XL_LITTLE_ENDIAN #undef USE_RAND #undef USE_RANDOM /* define this to be printf, or define your own fn of the form void nyquist_printf(char *format, ...); (for a GUI) */ #undef nyquist_printf #undef NEED_ULONG #undef NEED_USHORT #undef NEED_BYTE #undef NEED_DEFINE_MALLOC #undef NEED_ROUND /* explicitly choose a platform */ #undef UNIX #undef WINDOWS #undef MICROSOFT #undef DOS #undef MACINTOSH #undef BUFFERED_SYNCHRONOUS_INPUT #define SPACE_FOR_PLAY 10000 #define MAX_CHANNELS 16 /* this will enable code to read midi files, etc. */ #define CMTSTUFF /* NYQUIST tells some CMT code that we're really in * XLISP and NYQUIST */ #define NYQUIST #include "swlogic.h" nyquist-3.05/snd/audionone.c0000644000175000000620000000127310144436365015105 0ustar stevestaff#include "snd.h" long audio_poll(snd_type snd) { return 0; } long audio_read(snd_type snd, void *buffer, long length) { return 0; } long audio_write(snd_type snd, void *buffer, long length) { return 0; } int audio_open(snd_type snd, long *flags) { return 0; } int audio_close(snd_type snd) { return 0; } /* audio_flush -- finish audio output */ int audio_flush(snd_type snd) { return 0; } int audio_reset(snd_type snd) { return 0; } snd_fns_node mmsystem_dictionary = { audio_poll, audio_read, audio_write, audio_open, audio_close, audio_reset, audio_flush }; void snd_init() { snd_add_device("None", "default", &mmsystem_dictionary); } nyquist-3.05/snd/ieeecvt.c0000644000175000000620000001302510144436365014546 0ustar stevestaff/* * C O N V E R T T O I E E E E X T E N D E D */ /* Copyright (C) 1988-1991 Apple Computer, Inc. * All rights reserved. * * Machine-independent I/O routines for IEEE floating-point numbers. * * NaN's and infinities are converted to HUGE_VAL or HUGE, which * happens to be infinity on IEEE machines. Unfortunately, it is * impossible to preserve NaN's in a machine-independent way. * Infinities are, however, preserved on IEEE machines. * * These routines have been tested on the following machines: * Apple Macintosh, MPW 3.1 C compiler * Apple Macintosh, THINK C compiler * Silicon Graphics IRIS, MIPS compiler * Cray X/MP and Y/MP * Digital Equipment VAX * * * Implemented by Malcolm Slaney and Ken Turkowski. * * Malcolm Slaney contributions during 1988-1990 include big- and little- * endian file I/O, conversion to and from Motorola's extended 80-bit * floating-point format, and conversions to and from IEEE single- * precision floating-point format. * * In 1991, Ken Turkowski implemented the conversions to and from * IEEE double-precision format, added more precision to the extended * conversions, and accommodated conversions involving +/- infinity, * NaN's, and denormalized numbers. */ #include "math.h" #ifndef HUGE_VAL #ifdef HUGE #define HUGE_VAL HUGE #else /* WARNING: this is machine-dependent and should come from math.h */ #define HUGE_VAL 1.797693134862315e308 #endif /* HUGE */ #endif /*HUGE_VAL*/ # define FloatToUnsigned(f) ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L) + 1) void ConvertToIeeeExtended(double num, char *bytes) { int sign; int expon; double fMant, fsMant; unsigned long hiMant, loMant; if (num < 0) { sign = 0x8000; num *= -1; } else { sign = 0; } if (num == 0) { expon = 0; hiMant = 0; loMant = 0; } else { fMant = frexp(num, &expon); if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */ expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */ } else { /* Finite */ expon += 16382; if (expon < 0) { /* denormalized */ fMant = ldexp(fMant, expon); expon = 0; } expon |= sign; fMant = ldexp(fMant, 32); fsMant = floor(fMant); hiMant = FloatToUnsigned(fsMant); fMant = ldexp(fMant - fsMant, 32); fsMant = floor(fMant); loMant = FloatToUnsigned(fsMant); } } bytes[0] = (char) (expon >> 8); bytes[1] = (char) expon; bytes[2] = (char) (hiMant >> 24); bytes[3] = (char) (hiMant >> 16); bytes[4] = (char) (hiMant >> 8); bytes[5] = (char) hiMant; bytes[6] = (char) (loMant >> 24); bytes[7] = (char) (loMant >> 16); bytes[8] = (char) (loMant >> 8); bytes[9] = (char) loMant; } /* * C O N V E R T F R O M I E E E E X T E N D E D */ /* * Copyright (C) 1988-1991 Apple Computer, Inc. * All rights reserved. * * Machine-independent I/O routines for IEEE floating-point numbers. * * NaN's and infinities are converted to HUGE_VAL or HUGE, which * happens to be infinity on IEEE machines. Unfortunately, it is * impossible to preserve NaN's in a machine-independent way. * Infinities are, however, preserved on IEEE machines. * * These routines have been tested on the following machines: * Apple Macintosh, MPW 3.1 C compiler * Apple Macintosh, THINK C compiler * Silicon Graphics IRIS, MIPS compiler * Cray X/MP and Y/MP * Digital Equipment VAX * * * Implemented by Malcolm Slaney and Ken Turkowski. * * Malcolm Slaney contributions during 1988-1990 include big- and little- * endian file I/O, conversion to and from Motorola's extended 80-bit * floating-point format, and conversions to and from IEEE single- * precision floating-point format. * * In 1991, Ken Turkowski implemented the conversions to and from * IEEE double-precision format, added more precision to the extended * conversions, and accommodated conversions involving +/- infinity, * NaN's, and denormalized numbers. */ #ifndef HUGE_VAL # define HUGE_VAL HUGE #endif /*HUGE_VAL*/ # define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) /**************************************************************** * Extended precision IEEE floating-point conversion routine. ****************************************************************/ double ConvertFromIeeeExtended(unsigned char *bytes /* LCN */) { double f; int expon; unsigned long hiMant, loMant; expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | ((unsigned long)(bytes[3] & 0xFF) << 16) | ((unsigned long)(bytes[4] & 0xFF) << 8) | ((unsigned long)(bytes[5] & 0xFF)); loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | ((unsigned long)(bytes[7] & 0xFF) << 16) | ((unsigned long)(bytes[8] & 0xFF) << 8) | ((unsigned long)(bytes[9] & 0xFF)); if (expon == 0 && hiMant == 0 && loMant == 0) { f = 0; } else { if (expon == 0x7FFF) { /* Infinity or NaN */ f = HUGE_VAL; } else { expon -= 16383; f = ldexp(UnsignedToFloat(hiMant), expon-=31); f += ldexp(UnsignedToFloat(loMant), expon-=32); } } if (bytes[0] & 0x80) return -f; else return f; } nyquist-3.05/snd/sndio.c0000644000175000000620000000156011511415575014236 0ustar stevestaff/* sndio.c -- read/write sound file data */ /* CHANGELOG * * 29Jun95 RBD ULAW fixed problems with signed chars */ /* Standard includes */ #include "stdio.h" #include "memory.h" #ifndef mips #include "stdlib.h" #endif #include "snd.h" #ifdef LINUX #include "sys/file.h" #else /* #include */ #ifdef WIN32 #include #include "io.h" #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) #include #else #include #endif #endif //#include "audio.h" /* was "#ifndef WIN32" */ #if !defined(WIN32) && !defined(IRIX) && !defined(SGI) void _swab(char *to, char *from, long length) { short *to16 = (short *) to; short *from16 = (short *) from; int i = 1; while (i < length) { short data = *from16++; *to16++ = (data << 8) | ((data >> 8) & 0xFF); i += 2; } } #endif nyquist-3.05/snd/sndsystem.h0000644000175000000620000000265710144436365015171 0ustar stevestaff/* sndsystem.h -- system-specific definitions */ /* NOTES: you need a different sndswitches.h for each implementation, so this is a separate file. Things you need to define here: 1) Either UNIX, WIN32, or MACINTOSH should be defined. 2) Either the following function declaration: void snd_fail(char *msg); or #define snd_fail(msg) ... 3) typedef FASTFLOAT to be either a double or a float, whichever computes faster (PowerPCs are faster at double math than float math) 4) typedef MEMFLOAT to be how you would store a sample in memory (this should normally be float) 5) min() must be defined (either a macro or a function) 6) max() must be defined (either a macro or a function) */ #ifdef __WXMAC__ #ifndef __WX__ #define __WX__ #endif #endif #ifdef __WXMSW__ #ifndef __WX__ #define __WX__ #endif #endif #ifdef __WXGTK__ #ifndef __WX__ #define __WX__ #endif #endif #ifdef __cplusplus extern "C" { #endif void snd_fail(char *msg); #ifdef __cplusplus } // extern "C" #endif #define _snd_fail(X) snd_fail(X) #define _snd_free(X) snd_free(X) #define _snd_alloc(X) snd_alloc(X) typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflict with Windows */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/snd/snd.c0000644000175000000620000002757311466723256013731 0ustar stevestaff/* snd.c -- low-level sound I/O * * Roger Dannenberg * 21 Jun 1997 * * based on sndheader.c: * * Jim Zelenka, CMU/ITC, 9 Jun 1992 (rewritten from my old sources) * Roger Dannenberg, CMU, Mar 1993 (extensive changes and additions) * * and on sndread.c & sndwrite.c: * * Roger Dannenberg */ /* Standard includes */ #include #include #include "snd.h" #include "sndfileio.h" #include "sndheader.h" static int snd_initialized = FALSE; typedef struct { char *interf; char *device; snd_fns_type dictionary; } descriptor_node, *descriptor_type; static int descriptor_index = 0; #define snd_descriptor_max 32 static descriptor_node descriptors[snd_descriptor_max]; /* snd_add_device -- describe interface/device pair to library * * This is called at intialization time, once for each * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1) * The strings are retained but NOT COPIED, so do not destroy them! */ void snd_add_device(char *interf, char *device, snd_fns_type dictionary) { if (descriptor_index >= snd_descriptor_max) { snd_fail("snd_add_device: snd_descriptor_max exceeded"); } descriptors[descriptor_index].interf = interf; descriptors[descriptor_index].device = device; descriptors[descriptor_index].dictionary = dictionary; descriptor_index++; } int snd_device(int n, char *interf, char *device) { if (!snd_initialized) { snd_init(); snd_initialized = TRUE; } if (n >= 0 && n < descriptor_index) { strcpy(interf, descriptors[n].interf); strcpy(device, descriptors[n].device); return SND_SUCCESS; } return !SND_SUCCESS; } /* failure_fn -- "noop" function pointer */ /**/ static int failure_fn(snd_type snd) { return !SND_SUCCESS; } /* success_fn -- "noop" function pointer */ /**/ static int success_fn(snd_type snd) { return SND_SUCCESS; } static long file_poll(snd_type snd) { return MAX_FILE_BUF_LEN; } static long mem_poll(snd_type snd) { if (snd->write_flag == SND_READ) { return (snd->u.mem.buffer_len - snd->u.mem.buffer_pos); } else { return (snd->u.mem.buffer_max - snd->u.mem.buffer_len); } } static long none_poll(snd_type snd) { return 0; } #if !defined(WIN32) && !defined(IRIX) && !defined(SGI) static void _swab(char *to, char *from, long length) { short *to16 = (short *) to; short *from16 = (short *) from; int i = 1; while (i < length) { short data = *from16++; *to16++ = (data << 8) | ((data >> 8) & 0xFF); i += 2; } } #endif void change_byte_order(snd_type snd, void *buffer, long length) { int bytes = (snd->format.bits + 7) >> 3; switch (bytes) { case 1: break; case 2: _swab((char *) buffer, (char *) buffer, length); break; case 3: { char *buff = (char *) buffer; while (length > 0) { char b = buff[0]; buff[0] = buff[2]; buff[2] = b; buff += 3; length -= 3; } break; } case 4: { long *buff = (long *) buffer; while (length > 0) { long data = *buff; *buff++ = ((data >> 24) & 0xFF) | ((data >> 8) & 0xFF00) | ((data << 8) & 0xFF0000) | (data << 24); length -= 4; } break; } default: { char msg[100]; sprintf(msg, "Cannot handle %d-byte samples", bytes); snd_fail(msg); break; } } } /* jlh Here I probably just need to make sure that swap is ALWAYS 0, and that snd/sndlinux.c/snd_file_read gives me what multiread_fetch and read__fetch expect, as in a sane batch of frames containing channels of samples. */ static long file_read(snd_type snd, void *buffer, long length) { long togo, cnt; togo = snd->u.file.end_offset - snd->u.file.current_offset; if (length > togo) length = togo; cnt = snd_file_read(snd->u.file.sffile, (float *) buffer, length); snd->u.file.current_offset += cnt; if (snd->u.file.swap) change_byte_order(snd, buffer, cnt); return cnt; } static long mem_read(snd_type snd, void *buffer, long length) { /* if there are fewer than length bytes, reduce length: */ if ((snd->u.mem.buffer_len - snd->u.mem.buffer_pos) < length) { length = snd->u.mem.buffer_len - snd->u.mem.buffer_pos; } memcpy(buffer, snd->u.mem.buffer + snd->u.mem.buffer_pos, length); snd->u.mem.buffer_pos += length; return length; } static long none_read(snd_type snd, void *buffer, long length) { return 0; } static long file_write(snd_type snd, void *buffer, long length) { long cnt; if (snd->u.file.swap) change_byte_order(snd, buffer, length); cnt = snd_file_write(snd->u.file.sffile, (float *) buffer, length); snd->u.file.end_offset += cnt; /* keep track of how much data */ return cnt; } static long mem_write(snd_type snd, void *buffer, long length) { /* if there are fewer than length bytes, reduce length: */ if ((snd->u.mem.buffer_max - snd->u.mem.buffer_len) < length) { length = snd->u.mem.buffer_max - snd->u.mem.buffer_len; } memcpy(snd->u.mem.buffer + snd->u.mem.buffer_len, buffer, length); snd->u.mem.buffer_len += length; return length; } static long none_write(snd_type snd, void *buffer, long length) { return 0; } static int mem_open(snd_type snd, long *flags) { return SND_SUCCESS; } static int none_open(snd_type snd, long *flags) { return !SND_SUCCESS; } static int file_close(snd_type snd) { /* jlh dropping this code, libsndfile does all this for me if (snd->write_flag == SND_WRITE) { write_sndheader_finish(snd); } end of dropped code jlh */ return snd_file_close(snd->u.file.sffile); } #define mem_close success_fn #define none_close failure_fn #define file_reset success_fn static int mem_reset(snd_type snd) { snd->u.mem.buffer_pos = 0; if (snd->write_flag != SND_READ) { snd->u.mem.buffer_len = 0; } return SND_SUCCESS; } #define none_reset failure_fn /* jlh I'm concerned about this; it would be easy to write... When I have things working I'll have to put a message into file_flush and see if it ever gets called. */ #define file_flush success_fn #define mem_flush success_fn #define none_flush failure_fn char *snd_mode_string[] = { "ADPCM", "PCM", "ULAW", "ALAW", "Float", "UPCM", "Unknown" }; char *snd_mode_to_string(long mode) { if (mode < 0 || mode >= SND_NUM_MODES) return "InvalidData"; else return snd_mode_string[mode]; } static snd_fns_node mem_dictionary = { mem_poll, mem_read, mem_write, mem_open, mem_close, mem_reset, mem_flush }; static snd_fns_node file_dictionary = { file_poll, file_read, file_write, snd_open_file, file_close, file_reset, file_flush }; snd_fns_node snd_none_dictionary = { none_poll, none_read, none_write, none_open, none_close, none_reset, none_flush }; long snd_poll(snd_type snd) { return (*snd->dictionary->poll)(snd); } /* snd_read -- read up to length frames from source into buffer */ /* * returns number of frames actually read */ long snd_read(snd_type snd, void *buffer, long length) { /* jlh betcha dollars to donuts this collapses to 1, since I am doing things in units of frames rather than bytes. No -- what is length? frames or samples??? must be frames, must be, must be! YES! IT IS! JACKPOT! */ int bpf = 1; /*snd_bytes_per_frame(snd);*/ return ((*snd->dictionary->read)(snd, buffer, length * bpf)) / bpf; } long snd_write(snd_type snd, void *buffer, long length) /* note: length is in frames, returns number of frames actually written */ { int bpf = 1; /* snd_bytes_per_frame(snd);*/ return (*snd->dictionary->write)(snd, buffer, length * bpf / bpf); } int snd_open(snd_type snd, long *flags) { if (!snd_initialized) { snd_init(); snd_initialized = TRUE; } *flags = 0; if (snd->device == SND_DEVICE_FILE) { snd->dictionary = &file_dictionary; } else if (snd->device == SND_DEVICE_AUDIO) { int i; for (i = 0; i < descriptor_index; i++) { /* take the first descriptor that matches both interface and device, where empty string matches anything: */ if ((snd->u.audio.interfacename[0] == 0 || strcmp(snd->u.audio.interfacename, descriptors[i].interf) == 0) && /*&& commented out by dmazzoni - don't want to compare dev && uncommented by rbd - please see previous comment/specification */ (snd->u.audio.devicename[0] == 0 || strcmp(snd->u.audio.devicename, descriptors[i].device) == 0)) { snd->dictionary = descriptors[i].dictionary; break; } } if (i >= descriptor_index) { return !SND_SUCCESS; } } else if (snd->device == SND_DEVICE_MEM) { snd->dictionary = &mem_dictionary; } return (*snd->dictionary->open)(snd, flags); } int snd_close(snd_type snd) { return (*snd->dictionary->close)(snd); } int snd_reset(snd_type snd) { return (*snd->dictionary->reset)(snd); } /* snd_flush -- allows client to finish audio output before closing */ /**/ int snd_flush(snd_type snd) { if (snd->write_flag != SND_READ) { return (*snd->dictionary->flush)(snd); } return SND_SUCCESS; } /* jlh Code lifted from sndcvt.c long snd_bytes_per_frame(snd_type snd) { return (((snd->format.bits + 7) >> 3) * snd->format.channels); } and my version thereof. I'll have to see if it flies... */ long snd_bytes_per_frame(snd_type snd) { return (sizeof(float) * snd->format.channels); } /* jlh more code lifted from sndcvt.c, and rewritten to move samples where needed. long cvt_from_float_32(void *buf1, void *buf2, long len2, float scale, float *peak) { float *floats1 = (float *) buf1; float *floats2 = (float *) buf2; int i; for (i = 0; i < len2; i++) { *floats1++ = *floats2++ * scale; } return len2; } long cvt_to_float_32(void *buf1, void *buf2, long len2, float scale, float *peak) { /* rbd I think this worked because when "converting" floats the conversion was always in place so really the task here is to compute peak and scale. Maybe I'm wrong -- there should at least be big warning comments that buf1 is ignored ===> There appears to have been a missing line here, I don't see how this function could have ever worked. Compare with cvt_to_pcm_16, for instance. float *floats = (float *) buf2; int i; FASTFLOAT max_sample = 0.0; for (i = 0; i < len2; i++) { FASTFLOAT s = *floats++ * scale; if (s > max_sample) max_sample = s; if (-s > max_sample) max_sample = -s; *floats++ = (float) s; } *peak = (float) max_sample; return len2; } What was _from_ was called on the read and I'm replacing _from_ with move_samples_inward. What was _to_ was called on the write and had the scale and peak calculations and I'm replacing _to_ with move_samples_outward. */ long move_samples_inward(void *buf1, void *buf2, long len2, float scale, float *peak) { float *floats1 = (float *)buf1; float *floats2 = (float *)buf2; int i; for (i = 0; i < len2; i++) { *floats1++ = *floats2++ * scale; } return len2; } long move_samples_outward(void *buf1, void *buf2, long len2, float scale, float *peak) { float *floats1 = (float *)buf1; float *floats2 = (float *)buf2; int i; FASTFLOAT max_sample = 0.0; for (i = 0; i < len2; i++) { FASTFLOAT s = *floats2++ * scale; if (s > max_sample) max_sample = s; if (-s > max_sample) max_sample = -s; *floats1++ = (float) s; } *peak = (float) max_sample; return len2; } nyquist-3.05/snd/sndcvt.c0000644000175000000620000000011311466723256014423 0ustar stevestaff/* sndcvt.c -- now probably obsolete -- stub to allow build to happen. */ nyquist-3.05/snd/audiomac.c0000644000175000000620000003336710144436365014717 0ustar stevestaff/* * audiomac.c * * Written by Dominic Mazzoni * * sndlib by Roger Dannenberg * * I rewrote this code in January 2001 to be compatible with both the old Mac OS * and the new CarbonLib required to run under Mac OS X. * * Brief description of algorithm: we keep two buffers. After the first one is filled * we pass it to the Sound Manager and ask it to call our callback function as soon as * it has finished playing. In the meantime we start filling the second buffer. * Whenever the first buffer completes, we copy the second buffer to the first buffer * and start playback on that buffer, unless the second buffer is empty, in which case * we play a small amount of silence, hoping the underlying process will catch up. * * Good references: * * http://devworld.apple.com/samplecode/Sample_Code/Sound/SndPlayDoubleBuffer.htm * http://devworld.apple.com/technotes/tn/tn1198.htm * */ #include #include #include "memory.h" #include "stdio.h" #include "snd.h" #include "audiomac.h" #include #ifdef __cplusplus extern "C" { #endif long audio_write(snd_node *n, void *buffer, long length); pascal void playbackCallback(SndChannelPtr channel, SndCommand *theCallBackCmd) { buffer_state *data = (buffer_state *)(theCallBackCmd->param2); if (data->busy) { SndDoCommand(channel, &data->callCmd, true); return; } data->busy = 1; // If there's data in the second buffer, copy it into the playback buffer // and mark the second buffer as empty again. if (data->curBuffer == 1 && data->curSize>0) { int bytes = data->curSize; if (bytes > data->bufferSize) bytes = data->bufferSize; BlockMove((Ptr)data->nextBuffer, (Ptr)data->buffer, bytes); if (bytes != data->curSize) BlockMove((Ptr)&data->nextBuffer[bytes], (Ptr)data->nextBuffer, data->curSize - bytes); data->header.numFrames = bytes / data->frameSize; data->curSize -= bytes; } else { // even when we get here, the sound output is not completed, so we count // how many empty buffers we've sent. The flush command can return true // when this number is high enough. data->empty += 1; // Otherwise, either we're finished playing or we're stalling if (!data->flushing) { // Send some silence through the speaker while we wait for // the program to catch up int waittime = 4096; int i; if (waittime > data->bufferSize) waittime = data->bufferSize; for(i=0; ibuffer)[i] = 0; data->header.numFrames = waittime / data->frameSize; } } data->busy = 0; if (!data->flushing) { SndDoCommand(channel, &data->playCmd, true); SndDoCommand(channel, &data->callCmd, true); } } pascal void recordingCallback(SPBPtr params, Ptr buffer, short peakAmplitude, long numBytes) { buffer_state *data = (buffer_state *)params->userLong; int bytesAvail; int bufferBytesUsed; int i; if (data->recqEnd >= data->recqStart) bufferBytesUsed = data->recqEnd - data->recqStart; else bufferBytesUsed = (data->recqEnd + (data->bufferSize - data->recqStart)); bytesAvail = data->bufferSize - data->frameSize - bufferBytesUsed; if (numBytes > bytesAvail) { numBytes = bytesAvail; data->starved++; } for(i=0; irecBuffer[(data->recqEnd+i) % data->bufferSize] = ((char *)buffer)[i]; if (numBytes > 0) data->recqEnd = ((data->recqEnd + numBytes) % data->bufferSize); } int audio_open(snd_node *n, long *f) { OSErr err; Fixed sampleRateFixed; int i; buffer_state *data = (buffer_state *)malloc(sizeof(buffer_state)); n->u.audio.descriptor = (void *)data; data->frameSize = snd_bytes_per_frame(n); data->bufferSize = (int) (n->format.srate * (double)data->frameSize); if (n->u.audio.latency > 0.0) data->bufferSize = (int)(n->format.srate * n->u.audio.latency) * data->frameSize; /* Calculate sample rate as an unsigned fixed-point number */ if (n->format.srate > 65535.0 || n->format.srate < 1.0) sampleRateFixed = 0xAC440000; /* Fixed for 44100 */ else { unsigned short numerator = (unsigned short)n->format.srate; unsigned short denominator = (unsigned short)(65536.0*(n->format.srate - numerator)); sampleRateFixed = (numerator << 16) | denominator; } /* Open device for recording or playback, depending on mode selected */ if (n->write_flag == SND_READ) { /* recording */ short gainControl = 0; /* off */ short numChannels = n->format.channels; short continuousRecording = 1; /* on */ short playthroughVolume = 0; /* off */ OSType quality = 'cd '; short sampleSize = 16; short twos = 0; /* i.e. signed */ OSType compression = 'NONE'; OSErr err; data->recording = 1; err = SPBOpenDevice("\p", siWritePermission, &data->refnum); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'qual', &quality); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'agc ', &gainControl); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'srat', &sampleRateFixed); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'ssiz', &sampleSize); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'chan', &numChannels); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'cont', &continuousRecording); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'plth', &playthroughVolume); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'twos', &twos); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'comp', &compression); if (err) return !SND_SUCCESS; data->recBuffer = (char *)malloc(data->bufferSize); data->recqStart = 0; data->recqEnd = 0; data->starved = 0; data->params.inRefNum = data->refnum; data->params.count = 0; /* data->bufferSize; /* bytes to record */ data->params.milliseconds = 0; /* param will be ignored; use count */ data->params.bufferLength = 0; /* ignore buffer */ data->params.bufferPtr = NULL; /* ignore buffer */ data->params.completionRoutine = NULL; data->params.userLong = (long)data; data->params.unused1 = 0; /* NOTE: This was NewSIInterruptUPP, but this isn't defined in my compiler -RBD */ data->params.interruptRoutine = NewSIInterruptProc(recordingCallback); err = SPBRecord(&data->params, true); if (err) return !SND_SUCCESS; } else { /* playback */ data->recording = 0; data->chan = NULL; err = SndNewChannel(&data->chan, sampledSynth, 0, NULL); if (err) return !SND_SUCCESS; data->buffer = (char *)malloc(data->bufferSize); data->nextBufferSize = data->bufferSize * 3; data->nextBuffer = (char *)malloc(data->nextBufferSize); if (!data->buffer || !data->nextBuffer) return !SND_SUCCESS; data->chan->callBack = NewSndCallBackProc(playbackCallback); data->header.samplePtr = data->buffer; data->header.numChannels = n->format.channels; data->header.sampleRate = sampleRateFixed; data->header.loopStart = 0; data->header.loopEnd = 0; data->header.encode = cmpSH; data->header.baseFrequency = kMiddleC; // data->header.AIFFSampleRate = 0; -- this parameter is unused data->header.markerChunk = NULL; data->header.format = kSoundNotCompressed; data->header.futureUse2 = NULL; data->header.stateVars = NULL; data->header.leftOverSamples = NULL; data->header.compressionID = 0; data->header.packetSize = 0; data->header.snthID = 0; data->header.sampleSize = 16; data->header.sampleArea[0] = 0; data->playCmd.cmd = bufferCmd; data->playCmd.param1 = 0; //unused data->playCmd.param2 = (long)&data->header; data->callCmd.cmd = callBackCmd; data->callCmd.param1 = 0; data->callCmd.param2 = (long)data; data->curBuffer = 0; data->curSize = 0; data->firstTime = 1; data->finished = 0; data->busy = 0; data->flushing = 0; data->empty = 1; // to avoid the glitch at the beginning of playback, write some zeros to prime the pump // use nextBuffer because it's convenient. We just need a buffer full of zeros. for (i = 0; i < data->bufferSize; i++) { data->nextBuffer[i] = 0; } audio_write(n, data->nextBuffer, data->bufferSize); } return SND_SUCCESS; } int audio_close(snd_node *n) { buffer_state *data = (buffer_state *)n->u.audio.descriptor; OSErr err; if (data->recording) { SPBStopRecording(data->refnum); SPBCloseDevice(data->refnum); if (data->starved) { data->starved = 0; } #ifndef TARGET_CARBON DisposeRoutineDescriptor(data->params.interruptRoutine); #endif free((void *)data->recBuffer); } else { SndCallBackUPP callBack; data->finished = 1; callBack = data->chan->callBack; err = SndDisposeChannel(data->chan, true // quiets the channel now ); #ifndef TARGET_CARBON DisposeRoutineDescriptor(callBack); #endif free((void *)data->buffer); free((void *)data->nextBuffer); } free((void *)data); return SND_SUCCESS; } int audio_flush(snd_type snd) // return SND_SUCCESS when sound has been delivered to output { buffer_state *data = (buffer_state *)snd->u.audio.descriptor; if (data->recording) { SPBStopRecording(data->refnum); } else { SCStatus status; OSErr err; //data->flushing = 1; /* Start playback if we haven't already */ /* if (data->firstTime) { data->header.numFrames = data->curSize / data->frameSize; SndDoCommand(data->chan, &data->playCmd, true); data->firstTime = 0; } do { err = SndChannelStatus(data->chan, sizeof(status), &status); } while (!err && status.scChannelBusy); */ //data->flushing = 0; } // I don't know how to figure out when the last sample has been // written to the DAC. The following waits until 8 buffers of // zeros have been written. This seems to work well, giving a // fraction of a second margin of extra silence at the end. return (data->empty >= 8 ? SND_SUCCESS : !SND_SUCCESS); } long audio_read(snd_node *n, void *buffer, long length) { buffer_state *data = (buffer_state *)n->u.audio.descriptor; if (data->recording) { int bufferBytesUsed; int i; if (data->recqEnd >= data->recqStart) bufferBytesUsed = data->recqEnd - data->recqStart; else bufferBytesUsed = (data->recqEnd + (data->bufferSize - data->recqStart)); if (length > bufferBytesUsed) length = bufferBytesUsed; for(i=0; irecBuffer[(data->recqStart+i) % data->bufferSize]; data->recqStart = ((data->recqStart + length) % data->bufferSize); return length; } else { /* This shouldn't happen */ return -1; } } long audio_write(snd_node *n, void *buffer, long length) { long written = 0; long block; buffer_state *data = (buffer_state *)n->u.audio.descriptor; while(data->busy) ; data->busy = 1; if (data->curBuffer==0 && length>0) { data->empty = 0; block = min(length, data->bufferSize - data->curSize); if (block>0) { Ptr dest = (Ptr)&data->buffer[data->curSize]; BlockMove((Ptr)buffer, dest, block); length -= block; written += block; data->curSize += block; buffer = &((char *)buffer)[block]; if (data->curSize == data->bufferSize) { data->curSize = 0; data->curBuffer = 1; } } } // Copy into the second buffer (the one we don't pass to the Sound Manager directly) if (data->curBuffer == 1 && length>0) { data->empty = 0; block = min(length, data->nextBufferSize - data->curSize); if (block > 0) { Ptr dest = (Ptr)&data->nextBuffer[data->curSize]; BlockMove((Ptr)buffer, dest, block); length -= block; written += block; data->curSize += block; } } // start playback immediately if (data->firstTime) { data->firstTime = 0; if (data->curBuffer==1) { data->header.numFrames = data->bufferSize / data->frameSize; } else { data->header.numFrames = data->curSize / data->frameSize; data->curBuffer = 1; data->curSize = 0; } data->busy = 0; SndDoCommand(data->chan, &data->playCmd, true); SndDoCommand(data->chan, &data->callCmd, true); } data->busy = 0; return written; } int audio_reset(snd_node *n) { /* audio reset not implemented */ return !SND_SUCCESS; } long audio_poll(snd_type snd) { buffer_state *data = (buffer_state *)snd->u.audio.descriptor; if (data->recording) { int bufferBytesUsed; if (data->recqEnd >= data->recqStart) bufferBytesUsed = data->recqEnd - data->recqStart; else bufferBytesUsed = (data->recqEnd + (data->bufferSize - data->recqStart)); return (bufferBytesUsed / data->frameSize); } else { long avail = data->bufferSize - data->curSize; if (data->curBuffer == 0) avail += data->bufferSize; /* Is this a bug in snd that I have to return frames here, and bytes everywhere else? */ return avail / data->frameSize; } } snd_fns_node mac_dictionary = { audio_poll, audio_read, audio_write, audio_open, audio_close, audio_reset, audio_flush }; void snd_init() { snd_add_device((char *)"Macintosh", (char *)"default", &mac_dictionary); } #ifdef __cplusplus } // extern "C" #endif nyquist-3.05/snd/audiomac.h0000644000175000000620000000174710144436365014721 0ustar stevestaff#include #ifdef __cplusplus extern "C" { #endif typedef struct { int recording; int bufferSize; int frameSize; /* Recording */ long refnum; SPB params; char *recBuffer; int recqStart; int recqEnd; int starved; /* Playback */ SndChannelPtr chan; CmpSoundHeader header; SndCommand playCmd; SndCommand callCmd; char *buffer; char *nextBuffer; int nextBufferSize; int curBuffer; int curSize; int firstTime; int finished; int flushing; int busy; int empty; } buffer_state; #ifdef __cplusplus } #endif nyquist-3.05/snd/sndconfig.h0000644000175000000620000000455611511415575015111 0ustar stevestaff// #include // for size_t /* sndconfig.h -- system-specific definitions */ /* NOTES: each implementation must have its own .h and .c files, e.g. sndwin32.h and sndwin32.c. These files implement the following: 1) Either LINUX, WIN32, or MACINTOSH should be defined. (WX can also be defined to override standard file IO with functions from WX, a graphical user interface library.) 2) The following function declaration: void snd_fail(char *msg); or #define snd_fail some_function (note that snd_fail must be a function pointer) 3) typedef FASTFLOAT to be either a double or a float, whichever computes faster (PowerPCs are faster at double math than float math) 4) typedef MEMFLOAT to be how you would store a sample in memory (this should normally be float) 5) min() must be defined (either a macro or a function) 6) max() must be defined (either a macro or a function) 7) the following file IO functions must be defined: int snd_file_open(char *fname, int mode); int snd_file_creat(char *fname); int snd_file_lseek(int file, int offset, int param); long snd_file_read(int fp, char *data, long len); long snd_file_write(int fp, char *data, long len); int snd_file_close(int fp); long snd_file_len(int fp); (some implementations cast a pointer to an int in snd_open, so it is assumed that int can at least hold a pointer) NOTE: snd_file_creat and snd_file_open return SND_FILE_FAILURE if the open fails. 8) The following function to report failure and exit: void snd_fail(char *msg); 9) The following memory allocation routines: void *snd_alloc(size_t s); void snd_free(void *a); 10) snd_string_max -- string length for filenames, etc. */ #define snd_string_max 258 void snd_fail(char *msg); void snd_warn(char *msg); void *snd_alloc(size_t s); void snd_free(void *a); #if defined(__linux__) #include "sndlinux.h" #elif defined(IRIX) #include "sndirix.h" #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include "sndfreebsd.h" #elif defined(_WIN32) #ifndef WIN32 #define WIN32 #endif #include "sndwin32.h" #elif defined(macintosh) || defined(__WXMAC__) || defined(__APPLE__) /* notice that now MAC can mean either PPC or i386 -RBD */ #ifndef MAC #define MAC #endif /* include sndmac.h for both ppc and i386 architectures */ #include "sndmac.h" #else Error: No system selected in sndconfig.h #endif nyquist-3.05/snd/convert.c0000644000175000000620000002057310144436365014610 0ustar stevestaff/* Standard includes */ #include "stdlib.h" #include "string.h" #include "stdio.h" /* snd includes */ #include "snd.h" /* set the length of buffers to be even multiple of Audio_... * to avoid fractional filling of * audio output buffers */ #define MAXLEN MAX_FILE_BUF_LEN char *header_string[] = { "none", "AIFF", "IRCAM", "NeXT", "Wave" }; char *header_to_string(long header) { if (header < 0 || header > 4) return "InvalidData"; else return header_string[header]; } void snd_print_info(snd_type snd) { if (snd->device == SND_DEVICE_AUDIO) { if (snd->write_flag == SND_READ) { printf("audio input"); } else { printf("audio output"); } } else if (snd->device == SND_DEVICE_MEM) { if (snd->write_flag == SND_READ) { printf("from memory buffer"); } else { printf("to memory buffer"); } } else { printf("header %s", header_to_string(snd->u.file.header)); } printf(", channels %d, mode %s, bits %d, srate %g", snd->format.channels, snd_mode_to_string(snd->format.mode), snd->format.bits, snd->format.srate); if (snd->device == SND_DEVICE_MEM) { if (snd->write_flag == SND_READ) { printf("length %d\n", snd->u.mem.buffer_len); } else { printf("length %d\n", snd->u.mem.buffer_max); } } else if (snd->device == SND_DEVICE_FILE && snd->write_flag == SND_READ) { printf(", length %d\n", (snd->u.file.end_offset - snd->u.file.byte_offset) / snd_bytes_per_frame(snd)); } else printf("\n"); } int main(int argc, char *argv[]) { char *fromfile = NULL; char *tofile = NULL; int i; long flags = 0; long frames; long len; long checksum = 0; long count = 0; int format = SND_HEAD_AIFF; int mode = SND_MODE_PCM; int channels = 1; int bits = 16; double srate = 44100.0; snd_node from_snd, to_snd; char from_buf[MAXLEN]; char to_buf[MAXLEN]; long frames_from_len; long frames_to_len; long from_len = 0; long to_len = 0; for (i = 1; i < argc; i++) { if (*(argv[i]) != '-') { if (!fromfile) fromfile = argv[i]; else if (!tofile) tofile = argv[i]; else { printf("%s: don't know what to do with 3rd file\n", argv[i]); return 1; } } else { char *flag = argv[i] + 1; if (*flag == '?') { printf("convert -- sound file conversion utility\n\n"); printf("usage: convert fromfile tofile -flag1 -flag2 ...\n"); printf(" -fa -- AIFF file format\n"); printf(" -fi -- IRCAM file format\n"); printf(" -fn -- NeXT/Sun file format\n"); printf(" -fw -- Wave file format\n"); printf(" -ep -- PCM\n"); printf(" -em -- u-Law\n"); printf(" -ef -- float\n"); printf(" -eu -- unsigned PCM\n"); printf(" -b1 -- 8-bit\n"); printf(" -b2 -- 16-bit\n"); printf(" -b4 -- 32-bit\n"); printf(" -c1 -- 1 channel, etc.\n"); printf("use 'ada' to get audio input or output\n"); } else if (*flag == 'f') { switch (flag[1]) { case 'a': format = SND_HEAD_AIFF; break; case 'i': format = SND_HEAD_IRCAM; break; case 'n': format = SND_HEAD_NEXT; break; case 'w': format = SND_HEAD_WAVE; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'e') { switch (flag[1]) { case 'p': mode = SND_MODE_PCM; break; case 'm': mode = SND_MODE_ULAW; break; case 'f': mode = SND_MODE_FLOAT; break; case 'u': mode = SND_MODE_UPCM; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'b') { switch (flag[1]) { case '1': bits = 8; break; case '2': bits = 16; break; case '4': bits = 32; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'r') { switch (flag[1]) { case '4': srate = 44100.0; break; case '2': srate = 22050.0; break; case '1': srate = 11025.0; break; case '8': srate = 8000.0; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'c') { channels = atoi(flag+1); if (channels < 1 || channels > 16) { channels = 1; printf("flag %s ignored, using 1 channel\n", argv[i]); } } } } if (!tofile) { printf("2 files not found, use -? for help\n"); return 1; } from_snd.device = SND_DEVICE_FILE; from_snd.write_flag = SND_READ; from_snd.u.file.byte_offset = 0; from_snd.format.channels = channels; from_snd.format.mode = mode; from_snd.format.bits = bits; from_snd.format.srate = srate; if (strcmp(fromfile, "ada") == 0) { from_snd.device = SND_DEVICE_AUDIO; from_snd.u.audio.protocol = SND_COMPUTEAHEAD; from_snd.u.audio.latency = 1.0; from_snd.u.audio.granularity = 0.1; strcpy(from_snd.u.file.filename, ""); } else { strcpy(from_snd.u.file.filename, fromfile); } if (snd_open(&from_snd, &flags) != SND_SUCCESS) { printf("error opening %s for input\n", fromfile); exit(1); } printf("Opened %s for input: ", from_snd.u.file.filename); snd_print_info(&from_snd); to_snd.device = SND_DEVICE_FILE; to_snd.write_flag = SND_WRITE; to_snd.format.channels = channels; to_snd.format.mode = mode; to_snd.format.bits = bits; to_snd.format.srate = from_snd.format.srate; to_snd.u.file.header = format; /* header format, e.g. AIFF */ if (to_snd.u.file.header == SND_HEAD_WAVE && to_snd.format.mode == SND_MODE_PCM && to_snd.format.bits == 8) to_snd.format.mode = SND_MODE_UPCM; if (strcmp(tofile, "ada") == 0) { to_snd.device = SND_DEVICE_AUDIO; to_snd.u.audio.protocol = SND_COMPUTEAHEAD; to_snd.u.audio.latency = 0.0; to_snd.u.audio.granularity = 0.1; strcpy(to_snd.u.audio.interfacename, ""); strcpy(to_snd.u.audio.devicename, ""); } else { strcpy(to_snd.u.file.filename, tofile); } if (snd_open(&to_snd, &flags) != SND_SUCCESS) { printf("error opening %s for output\n", tofile); exit(1); } printf("Opened %s for output: ", to_snd.u.file.filename); snd_print_info(&to_snd); /* figure out how much to convert on each iteration */ /* first, compute how many frames could fit in each buffer */ from_len = MAXLEN / snd_bytes_per_frame(&from_snd); to_len = MAXLEN / snd_bytes_per_frame(&to_snd); /* then compute the minimum of the two frame counts */ frames = min(from_len, to_len); while (1) { /* then convert back from frame counts to byte counts: */ while ((frames_from_len = snd_poll(&from_snd)) <=0); frames_from_len = min(frames_from_len, frames); while ((frames_to_len = snd_poll(&to_snd)) <= 0); frames_to_len = min(frames_to_len, frames); len = min(frames_to_len, frames_from_len); len = snd_read(&from_snd, from_buf, len); if (((from_snd.device == SND_DEVICE_AUDIO) && (count > from_snd.format.srate * 10)) || (!len)) { break; } for (i = 0; i < len * snd_bytes_per_frame(&from_snd); i++) { checksum += from_buf[i]; count++; } len = snd_convert(&to_snd, to_buf, &from_snd, from_buf, len); len = snd_write(&to_snd, to_buf, len); printf("#"); fflush(stdout); } snd_close(&from_snd); if (to_snd.device == SND_DEVICE_AUDIO) { while (snd_flush(&to_snd) != SND_SUCCESS) ; } snd_close(&to_snd); printf("Read %ld frames, checksum = %ld\n", count, checksum); exit(0); } nyquist-3.05/snd/sndfaillinux.c0000644000175000000620000000037210144436365015623 0ustar stevestaff/* sndfaillinux.c -- version of sndfail that prints a message */ /* this should not be compiled into an snd library! handling snd_fail * is application specific */ #include "stdio.h" void snd_fail(char *msg) { printf("ERROR: %s\n", msg); } nyquist-3.05/snd/audiors6k.c0000644000175000000620000000161110144436365015027 0ustar stevestaff/* this code is obsolete, and should be converted to be compatible with the current snd library. Maybe we should rename it to audionone.c (I never did get direct audio output from RS6K) This code should be used for any system that does not have audio I/O devices -RBD */ #include "snd.h" int audio_open() { printf("audio_open not implemented\n"); return SND_SUCCESS; } int audio_close() { printf("audio_close not implemented\n"); return SND_SUCCESS; } int audio_flush(snd_type snd) { printf("audio_flush not implemented\n"); return SND_SUCCESS; } long audio_read() { printf("audio_read not implemented\n"); return 0; } long audio_write() { printf("audio_write not implemented\n"); return 0; } int audio_reset() { printf("audio reset not implemented\n"); return SND_SUCCESS; } long audio_poll(snd_type snd) { return 1000000; } nyquist-3.05/snd/sndfileio.h0000644000175000000620000000074211466723256015113 0ustar stevestaff/* sndfileio.h -- defines system-independent file IO */ #define SND_SEEK_CUR 1 #define SND_SEEK_END 2 #define SND_SEEK_SET 0 #define SND_RDONLY 0 #define SND_RDWR 2 int snd_file_open(char *fname, int mode); int snd_file_creat(char *fname); int snd_file_lseek(int file, long offset, int param); long snd_file_read(SNDFILE *fp, float *data, long len); long snd_file_write(SNDFILE *fp, float *data, long len); long snd_file_close(SNDFILE *fp); long snd_file_len(int fp); nyquist-3.05/snd/sndnt.h0000644000175000000620000000213610144436365014256 0ustar stevestaff/* sndsystem.h -- system-specific definitions */ /* NOTES: you need a different sndswitches.h for each implementation, so this is a separate file. Things you need to define here: 1) Either UNIX, WIN32, or MACINTOSH should be defined. 2) Either the following function declaration: void snd_fail(char *msg); or #define snd_fail(msg) ... 3) typedef FASTFLOAT to be either a double or a float, whichever computes faster (PowerPCs are faster at double math than float math) 4) typedef MEMFLOAT to be how you would store a sample in memory (this should normally be float) 5) min() must be defined (either a macro or a function) 6) max() must be defined (either a macro or a function) */ #define WIN32 1 void snd_fail(char *msg); typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflict with Windows */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif void *snd_alloc(size_t s); void snd_free(void *a); nyquist-3.05/snd/sndwin32.c0000644000175000000620000000246010144436365014572 0ustar stevestaff#include #include #include #include #include "snd.h" #include "sndfileio.h" #define PERMISSION 0x0644 int snd_file_open(char *fname, int mode) { int file; if (mode == SND_RDONLY) mode = _O_RDONLY; else mode = _O_RDWR; file = _open(fname, mode | _O_BINARY); if (file < 0) file = SND_FILE_FAILURE; return file; } int snd_file_creat(char *fname) { int file = _open(fname, _O_TRUNC | _O_WRONLY | _O_CREAT | _O_BINARY, _S_IREAD | _S_IWRITE); if (file < 0) file = SND_FILE_FAILURE; return file; } long snd_file_len(int file) { long len; struct stat statbuf; fstat(file ,&statbuf); len = (long) statbuf.st_size; /* get length of file */ return len; } long snd_file_read(int fp, char *data, long len) { return read(fp, data, len); } long snd_file_write(int fp, char *data, long len) { return write(fp, data, len); } int snd_file_close(int fp) { return close(fp); } int snd_file_lseek(int file, long offset, int param) { if (param == SND_SEEK_CUR) param = SEEK_CUR; else if (param == SND_SEEK_SET) param = SEEK_SET; else param = SEEK_END; return _lseek(file, offset, param); } void *snd_alloc(size_t s) { return malloc(s); } void snd_free(void *a) { free(a); } nyquist-3.05/snd/audio.c0000644000175000000620000000122410144436365014221 0ustar stevestaff#include "memory.h" #include "stdio.h" #include "snd.h" int audio_open() { printf("audio_open not implemented\n"); return SND_SUCCESS; } int audio_close() { printf("audio_close not implemented\n"); return SND_SUCCESS; } int audio_flush(snd_type snd) { printf("audio_flush not implemented\n"); return SND_SUCCESS; } long audio_read() { printf("audio_read not implemented\n"); return 0; } long audio_write() { printf("audio_write not implemented\n"); return 0; } int audio_reset() { printf("audio reset not implemented\n"); return SND_SUCCESS; } long audio_poll(snd_type snd) { return 1000000; } nyquist-3.05/snd/sndsystemmac.h0000644000175000000620000000002410144436365015634 0ustar stevestaff#include "sndmac.h" nyquist-3.05/snd/sndmac.c0000644000175000000620000000371311466723256014400 0ustar stevestaff#include #include "snd.h" #include "sndfileio.h" #ifdef __WXMAC__ #include "wx/filefn.h" #endif /* FIX -- take out all this because by using libsndfile, file I/O should be machine independent */ int snd_file_open(char *fname, int mode) { // this function should work like open(), so it returns -1 on failure. // We're using fopen() on the mac, so we need to convert NULL to -1 // Note that -1 is never a valid FILE* because it would be an odd address int file; #ifdef __WXMAC__ file = (int)fopen(wxUnix2MacFilename( fname ), mode==SND_RDONLY? "rb" : "r+b"); #else file = (int)fopen(fname, mode==SND_RDONLY? "rb" : "r+b"); #endif return (file == NULL ? -1 : file); } int snd_file_creat(char *fname) { int file; #ifdef __WXMAC__ file = (int) fopen(wxUnix2MacFilename( fname ), "wb"); #else file = (int) fopen(fname, "wb"); #endif /* file is zero if there was an error opening the file */ if (file == 0) file = SND_FILE_FAILURE; return file; } long snd_file_len(int file) { FILE *fp = (FILE *)file; long save = ftell(fp); long len; fseek(fp, 0, SEEK_END); len = ftell(fp); fseek(fp, save, SEEK_SET); return len; } long snd_file_read(SNDFILE *fp, float *data, long len) { /* Original code return fread(data, 1, len, (FILE *)fp); */ return sf_readf_float(fp, data, len); } long snd_file_write(SNDFILE *fp, float *data, long len) { /* return fwrite(data, 1, len, (FILE *)fp); */ return sf_writef_float(fp, data, len); } long snd_file_close(SNDFILE *fp) { /* return fclose((FILE *)fp); */ return sf_close(fp); } int snd_file_lseek(int file, long offset, int param) { if (param == SND_SEEK_CUR) param = SEEK_CUR; else if (param == SND_SEEK_SET) param = SEEK_SET; else param = SEEK_END; fseek((FILE *)file, offset, param); return ftell((FILE *)file); } void *snd_alloc(size_t s) { return malloc(s); } void snd_free(void *a) { free(a); } nyquist-3.05/snd/sndlinux.c0000644000175000000620000000376011466723256015001 0ustar stevestaff/* sndlinux.c -- implementation of system-specific function for snd library */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm changes for portability and fix compiler warnings */ #include #include #include #include #include #include "snd.h" #include "sndfileio.h" #define PERMISSION 0644 #ifdef __cplusplus extern "C" { #endif // snd_fail moved to sndfaillinux.c -RBD /* jlh I don't think snd_file_open is used ANYWHERE. It's not getting put into any of the dictionaries. In fact, I don't think any of these are getting used anywhere... */ int snd_file_open(char *fname, int mode) { int file; if (mode == SND_RDONLY) mode = O_RDONLY; else mode = O_RDWR; file = open(fname, mode); if (file < 0) file = SND_FILE_FAILURE; return file; } int snd_file_creat(char *fname) { int file = creat(fname, PERMISSION); if (file < 0) file = SND_FILE_FAILURE; return file; } long snd_file_len(int file) { long len; struct stat statbuf; fstat(file ,&statbuf); len = (long) statbuf.st_size; /* get length of file */ return len; } /* This IS getting used, being called from the file_dictionary function file_read. */ long snd_file_read(SNDFILE *fp, float *data, long len) { /* Original code return read(fp, data, len); */ return sf_readf_float(fp, data, len); } long snd_file_write(SNDFILE *fp, float *data, long len) { /* Original code; return write(fp, data, len); */ return sf_writef_float(fp, data, len); } long snd_file_close(SNDFILE *fp) { return sf_close(fp); } int snd_file_lseek(int file, long offset, int param) { if (param == SND_SEEK_CUR) param = SEEK_CUR; else if (param == SND_SEEK_SET) param = SEEK_SET; else param = SEEK_END; return lseek(file, offset, param); } void *snd_alloc(size_t s) { return malloc(s); } void snd_free(void *a) { free(a); } #ifdef __cplusplus } #endif nyquist-3.05/snd/wxsnd.h0000644000175000000620000000161610144436365014275 0ustar stevestaff/* * Header file for wxWindows port of snd library * * Dominic Mazzoni */ #ifndef _WX_SND_ #define _WX_SND_ #undef WIN32 #ifdef __WXGTK__ #include #endif #define L_SET SEEK_SET #define L_INCR SEEK_CUR #define PROTECTION #define off_t int #define open(X,Y) wxsnd_open(X,Y) #define creat(X,Y) wxsnd_creat(X,Y) #define lseek(X,Y,Z) wxsnd_lseek(X,Y,Z) #define read(X,Y,Z) wxsnd_read(X,Y,Z) #define write(X,Y,Z) wxsnd_write(X,Y,Z) #define close(X) wxsnd_close(X) #define getfilelen(X) wxsnd_getfilelen(X) enum {O_RDONLY, O_RDWR}; #ifdef __cplusplus extern "C" { #endif int wxsnd_open(char *fname, int mode); int wxsnd_creat(char *fname, int perms); int wxsnd_lseek(int file, int offset, int param); int wxsnd_read(int fp, char *data, int len); int wxsnd_write(int fp, char *data, int len); int wxsnd_close(int fp); long wxsnd_getfilelen(int fp); #ifdef __cplusplus } #endif #endif nyquist-3.05/snd/sndheader.c0000644000175000000620000003362111466723256015071 0ustar stevestaff/* sndheader.c -- nice new empty */ /* functions to write or delete references from nyqsrc/sndread.c/snd_make_read() snd_seek() snd_bytes_per_frame() cvt_from_8 cvt_from_16 cvt_from_24 cvt_from_32 cvt_from_unknown references from nyqsrc/sndwritepa.c/find_cvt_to_fn cvt_from_8 cvt_from_16 cvt_from_24 cvt_from_32 cvt_from_unknown snd/audiooss.o: In function `audio_poll': snd_bytes_per_frame() snd/snd.o: In function `file_close': write_sndheader_finish() snd/snd.o: In function `snd_read': snd_bytes_per_frame() snd/snd.o: In function `snd_write': snd_bytes_per_frame() snd/snd.o: snd_open_file() in the file_dictionary snd_fns_node. */ /* sndheader.c -- low-level sound I/O * * * Judy Hawkins * Feb 2008 * * Rewritten to use libsndfile 1.0.17. * * Based on sndheader.c from Nyquist 3.01, which had * a long history courtesy of Jim Zelenka, CMU/ITC, 9 Jun 1992 * and Roger Dannenberg, CMU, Mar 1993 * * */ /* Standard includes */ #include #include #include #include "snd.h" /* probably going to modify this one */ /* jlh leaving a whole bunch of includes out; as needed I'll put them back in. */ #ifdef LINUX # ifdef WIN32 # error LINUX and WIN32 both? # endif #endif /* jlh leaving out a bunch of Macintosh specific stuff on the theory that libsndfile does all that now. */ /* jlh leaving out some AIFF marker and instrument structure definitions on the theory that if anyone is using them I'll figure out how to use libsndfile to access them, and write structures as needed to support libsndfile. */ /* jlh leaving out convert functions; libsndfile handles all that. */ /* jlh leaving out a bunch of little bitty file and data handling support functions; libsndfile... */ /* Local buffer for constructing useful messages */ #define STRBUFF_LEN 1024 static char strBuffer [STRBUFF_LEN] ; /* ===== * lifted verbatim from sndheader.c v301 */ void snd_open_fail(snd_type snd) { /* char msg[250]; */ snd->device = SND_DEVICE_NONE; snd->dictionary = &snd_none_dictionary; /* It's not fatal if the file does not exist... sprintf(msg, "snd_open: could not open file %s\n", snd->u.file.filename); snd_fail(msg); */ return; } /*===================== ** Convert libsndfile's minor format to nyquist's SND_MODE specifier. */ int get_ny_mode (SF_INFO *sfinfo) { int mode; mode = 0; switch (sfinfo->format & SF_FORMAT_SUBMASK ) { case SF_FORMAT_IMA_ADPCM: case SF_FORMAT_MS_ADPCM: case SF_FORMAT_VOX_ADPCM: case SF_FORMAT_G721_32: case SF_FORMAT_G723_24: case SF_FORMAT_G723_40: mode = SND_MODE_ADPCM; break; case SF_FORMAT_RAW: case SF_FORMAT_PCM_S8: case SF_FORMAT_PCM_16: case SF_FORMAT_PCM_24: case SF_FORMAT_PCM_32: case SF_FORMAT_DPCM_8: /* jlh or are these two the UPCM, see below? */ case SF_FORMAT_DPCM_16: mode = SND_MODE_PCM; break; case SF_FORMAT_ULAW: mode = SND_MODE_ULAW; break; case SF_FORMAT_ALAW: mode = SND_MODE_ALAW; break; case SF_FORMAT_FLOAT: mode = SND_MODE_FLOAT; break; /* jlh libsndfile doesn't do UPCM? or is that the same as DPCM, see above? And what about the special case in the sndheader.c-orig, about how 8 bit PCM WAV files are actually UPCM? JLH */ case SF_FORMAT_PCM_U8: /* jlh looks more like UPCM than anything else */ mode = SND_MODE_UPCM; break; default: #ifdef DEBUG_LSF printf(" at the default case in get_ny_mode -- check mask...\n"); #endif mode = SND_MODE_UNKNOWN; break; } return mode; } /*============== * Convert the libsndfile extension to what nyquist needs. */ int get_ny_head ( SF_INFO *sfinfo ) { int head; head = 0; /* this would already have been put in by snd_open_fail if the file open failed: SND_HEAD_NONE */ switch (sfinfo->format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_AIFF: head = SND_HEAD_AIFF; break; case SF_FORMAT_IRCAM: head = SND_HEAD_IRCAM; break; case SF_FORMAT_AU: head = SND_HEAD_NEXT; break; case SF_FORMAT_WAV: head = SND_HEAD_WAVE; break; default: head = SND_HEAD_NONE; break; } return head; } int get_ny_bits(SF_INFO *sfinfo) { int bits; bits = 0; /* does libsdnfile give me any help with this? making a lot of guesses I'll have to verify later... jlh*/ switch (sfinfo->format & SF_FORMAT_SUBMASK ) { /* 8 bit */ case SF_FORMAT_PCM_S8: case SF_FORMAT_DPCM_8: case SF_FORMAT_PCM_U8: case SF_FORMAT_RAW: bits = 8; break; /* 16 bit */ case SF_FORMAT_IMA_ADPCM: case SF_FORMAT_MS_ADPCM: case SF_FORMAT_VOX_ADPCM: case SF_FORMAT_PCM_16: case SF_FORMAT_DPCM_16: bits = 16; break; /* 24 bit */ case SF_FORMAT_G723_24: case SF_FORMAT_PCM_24: bits = 24; break; /* 32 bit */ case SF_FORMAT_G721_32: case SF_FORMAT_PCM_32: bits = 32; break; /* 40 bit */ case SF_FORMAT_G723_40: bits = 40; break; /* wild guess at 4 bytes = 32 bits */ case SF_FORMAT_ULAW: case SF_FORMAT_ALAW: case SF_FORMAT_FLOAT: bits = 32; break; default: #ifdef DEBUG_LSF printf(" at the default case in get_ny_bits -- check mask...\n"); #endif bits = 8; break; } return bits; } /*================== * Fill in the SF_INFO structure for opening a file for write or read/write. * * I am attempting to make this do double duty for SND_WRITE and * SND_OVERWRITE. Wish me luck. */ int make_sfinfo(snd_type snd) { int format; int subformat; subformat = format = 0; /* Translate nyquist/snd header, mode and bits into libsndfile values. */ switch(snd->u.file.header) { case SND_HEAD_AIFF: format = SF_FORMAT_AIFF; break; case SND_HEAD_IRCAM: format = SF_FORMAT_IRCAM; break; case SND_HEAD_NEXT: format = SF_FORMAT_AU; break; case SND_HEAD_WAVE: format = SF_FORMAT_WAV; break; default: format = SF_FORMAT_WAV; break; } switch(snd->format.mode) { case SND_MODE_ADPCM: subformat = SF_FORMAT_IMA_ADPCM; break; case SND_MODE_PCM: switch(snd->format.bits) { case 8: subformat = SF_FORMAT_PCM_S8; break; case 16: subformat = SF_FORMAT_PCM_16; break; case 24: subformat = SF_FORMAT_PCM_24; break; case 32: subformat = SF_FORMAT_PCM_32; break; default: subformat = SF_FORMAT_PCM_16; break; } break; case SND_MODE_ULAW: subformat = SF_FORMAT_ULAW; break; case SND_MODE_ALAW: subformat = SF_FORMAT_ALAW; break; case SND_MODE_FLOAT: subformat = SF_FORMAT_FLOAT; break; case SND_MODE_UPCM: subformat = SF_FORMAT_PCM_U8; break; default: /* I think for simplicity in this here not very limited first cut, I'll go for a default of WAV, 16 bit PCM. I could get a lot more complicated, but that can happen later. jlh.*/ format = SF_FORMAT_WAV; subformat = SF_FORMAT_PCM_16; break; } snd->u.file.sfinfo.format = format | subformat; if (snd->format.srate > 0) snd->u.file.sfinfo.samplerate = snd->format.srate; else snd->u.file.sfinfo.samplerate = 41000; if (snd->format.channels > 0) snd->u.file.sfinfo.channels = snd->format.channels; else snd->u.file.sfinfo.channels = 1; snd->u.file.sfinfo.frames = 0; return sf_format_check(&snd->u.file.sfinfo); } /*============================================================== * The beating heart of this libsndfile project. * * Code from the original sndheader.c, v301, is mostly gone; I tried * to keep error handling the same. * * Bits and pieces from libsndfile examples/ */ int snd_open_file ( snd_type snd, long *flags) { SNDFILE *sffile; (*flags) = 0; /* No file has successfully opened; at the end, when all checks have passed, flags will get set to values that say the file open worked and fields have valid values. */ if (snd->write_flag == SND_READ) { snd->u.file.loop_info = FALSE; /* jlh -- somewhere previous to here I have to make sure format is 0, except if this is a RAW file, in which case I have to set samplerate, channels and format fields. */ snd->u.file.sfinfo.format = 0; /* if raw... */ if ((sffile = sf_open (snd->u.file.filename, SFM_READ, &snd->u.file.sfinfo)) == NULL) { printf ("Error : Not able to open input file %s.\n", snd->u.file.filename) ; fflush (stdout) ; memset (strBuffer, 0, sizeof (strBuffer)) ; sf_command (sffile, SFC_GET_LOG_INFO, strBuffer, STRBUFF_LEN) ; puts (strBuffer) ; puts (sf_strerror (NULL)) ; snd_open_fail(snd); return SND_FILE_FAILURE; } /* snd_read_header OUTTA DA WINDOW!!! (sound of splintering code fragments) jlh */ /* jlh -- instead, I have put sfinfo into snd. Now I will make sure it is a good happy little structure. */ if ((sf_format_check(&snd->u.file.sfinfo)) != TRUE) { printf ("Error : sfinfo not ok on file open: %s.\n", snd->u.file.filename) ; fflush (stdout) ; memset (strBuffer, 0, sizeof (strBuffer)) ; sf_command (sffile, SFC_GET_LOG_INFO, strBuffer, STRBUFF_LEN) ; puts (strBuffer) ; puts (sf_strerror (NULL)) ; snd_open_fail(snd); return SND_FILE_FAILURE; } /* YEAH. cooking with hydrogen. */ /* Fill out the nyquist format structure. */ snd->format.mode = get_ny_mode(&snd->u.file.sfinfo); snd->format.channels = snd->u.file.sfinfo.channels; snd->format.srate = snd->u.file.sfinfo.samplerate; snd->format.bits = get_ny_bits(&snd->u.file.sfinfo); /* nyquist header value, used in lisp code (I believe. jlh )*/ snd->u.file.header = get_ny_head(&snd->u.file.sfinfo); } /* if (snd->write_flag == SND_READ) */ else if (snd->write_flag == SND_WRITE) { if (snd->u.file.header < 0 || snd->u.file.header >= SND_NUM_HEADS) { sprintf(strBuffer, "snd_open_file: can't write file %s: invalid snd header value\n", snd->u.file.filename); snd_fail (strBuffer); snd_open_fail(snd); return !SND_SUCCESS; } /* Writing a new file: clear the libsndfile structures for action */ memset (&snd->u.file.sfinfo, 0, sizeof(snd->u.file.sfinfo)); snd->u.file.sffile = NULL; if ( make_sfinfo(snd) == SF_FALSE ) { sprintf(strBuffer, "snd_open_file: Header information invalid for writing %s\n", snd->u.file.filename); snd_fail (strBuffer); snd_open_fail(snd); return !SND_SUCCESS; } /* Headers and info structures all filled out; now create the file */ if ((sffile = sf_open (snd->u.file.filename, SFM_WRITE, &snd->u.file.sfinfo)) == NULL) { sprintf(strBuffer, "snd_open_file: failed to open \"%s\" for write;\nLIBSNDFILE error: %s\n", snd->u.file.filename, sf_strerror(sffile)); snd_fail (strBuffer); snd_open_fail(snd); return !SND_SUCCESS; } snd->u.file.file = 0; /* Ok, this is going to make for noise, but I do want to know when .file is being accessed so I can fix it. jlh */ snd->u.file.sffile = sffile; /* prob redundant... but I may get rid of file.file. jlh */ /* JLH gee... is this all I need to do? that was easy. */ } /* if snd->write_flag == SND_WRITE */ else if (snd->write_flag == SND_OVERWRITE) { if (snd->u.file.header < 0 || snd->u.file.header >= SND_NUM_HEADS) { sprintf(strBuffer, "snd_open_file: can't write file %s: invalid snd header value\n", snd->u.file.filename); snd_fail (strBuffer); snd_open_fail(snd); return !SND_SUCCESS; } /* If sfinfo is valid, keep it; if not, make a new one. */ if (sf_format_check(&snd->u.file.sfinfo) == SF_FALSE) { memset (&snd->u.file.sfinfo, 0, sizeof(snd->u.file.sfinfo)); snd->u.file.sffile = NULL; if ( make_sfinfo(snd) == SF_FALSE ) { sprintf(strBuffer, "snd_open_file: Header information invalid for writing %s\n", snd->u.file.filename); snd_fail (strBuffer); snd_open_fail(snd); return !SND_SUCCESS; } } /* Headers and info structures all filled out; now create the file */ if ((sffile = sf_open (snd->u.file.filename, SFM_RDWR, &snd->u.file.sfinfo)) == NULL) { sprintf(strBuffer, "snd_open_file: failed to open \"%s\" for read/write;\nLIBSNDFILE error: %s\n", snd->u.file.filename, sf_strerror(sffile)); snd_fail (strBuffer); snd_open_fail(snd); return !SND_SUCCESS; } /* Don't need to find the beginning of the data, libsndfile handles that. */ } /* JLH I'm not doing anything with swap, I'm assuming libsndfile handles all that. */ snd->u.file.file = 0; /* jlh and fix problems as they occur */ snd->u.file.sffile = sffile; /* prob redundant... but I may get rid of file.file. jlh */ /* jlh The file must have opened successfully; make flags reflect that, using old nyquist/snd values; lots of things use these??? */ (*flags) = SND_HEAD_SRATE | SND_HEAD_CHANNELS | SND_HEAD_BITS | SND_HEAD_MODE | SND_HEAD_LEN; return SND_SUCCESS; } /*================== * used once, in sndread.c * */ /* FIX -- need to test this. I think offset is in seconds, so this function is not going to be compatible with previous one. */ int snd_seek(snd_type snd, double offset) { sf_count_t frames; sf_count_t tsk; int whence; frames = offset; /* Once again, the question of what units offset is in.... I'm going to assume frames until proven wrong. jlh */ whence = (int)snd->u.file.current_offset; /* jlh and what if.... */ tsk = sf_seek( snd->u.file.sffile, frames, whence); if (tsk < 0) { return !SND_SUCCESS; } else { snd->u.file.current_offset = (long)tsk; } return SND_SUCCESS; } nyquist-3.05/snd/rs6kplaydemo.c0000644000175000000620000000631110144436365015542 0ustar stevestaff/* This code shows (I think) how to play audio on an RS6K. It is not used for anything, but might be a nice reference in case anyone wants to support AIX under the snd library. -RBD */ #include #include #include #include #include #include void main(argc, argv) int argc; char *argv[]; { UMSBAUDDevice adev; UMSAudioDevice_ReturnCode rc; Environment *ev; UMSAudioTypes_Buffer buffer; long onesecsize ; long read_cnt, transferred_cnt; int file; long sw; long osamples; char *obyte_order; long lgain; long rgain; long time; long pos; int bytespersec ; int secondtorecord ; long channels ; long bits ; /* set up som enviroment */ ev = somGetGlobalEnvironment(); adev = UMSBAUDDeviceNew(); printf("start record session\n"); rc = UMSAudioDevice_open(adev,ev,"/dev/acpa0","RECORD", UMSAudioDevice_BlockingIO); /* establish audio attributes */ channels = 2 ; bits = 16 ; rc = UMSAudioDevice_set_sample_rate(adev,ev,22050,&osamples); rc = UMSAudioDevice_set_bits_per_sample(adev,ev,bits); rc = UMSAudioDevice_set_number_of_channels(adev,ev,channels); rc = UMSAudioDevice_set_audio_format_type(adev,ev,"PCM"); rc = UMSAudioDevice_set_byte_order(adev,ev,"MSB"); rc = UMSAudioDevice_set_number_format(adev,ev,"TWOS COMPLEMENT"); rc = UMSAudioDevice_get_byte_order(adev,ev,&obyte_order); /* you have to free the string after the query */ if (obyte_order) free(obyte_order); rc = UMSAudioDevice_set_volume(adev,ev,100); rc = UMSAudioDevice_set_balance(adev,ev,0); rc = UMSAudioDevice_set_time_format(adev,ev,UMSAudioTypes_Msecs); lgain = 100; /*maximum left input gain*/ rgain = 100; /*maimum right input gain*/ rc = UMSAudioDevice_enable_input(adev,ev,"LINE_IN",&lgain,&rgain); rc = UMSAudioDevice_set_monitor(adev,ev,TRUE); rc = UMSAudioDevice_initialize(adev,ev); secondtorecord = 10 ; bytespersec = (bits / 8) * channels ; onesecsize = bytespersec * osamples ; time = 1000 * secondtorecord ; buffer._length = onesecsize ; buffer._buffer = malloc(onesecsize); buffer._maximum = onesecsize ; file = open("/tmp/testaudio",O_WRONLY | O_CREAT | O_TRUNC,0644); rc = UMSAudioDevice_start(adev,ev); /* do the recording */ do { rc = UMSAudioDevice_read(adev,ev,&buffer,onesecsize,&sw); write(file,buffer._buffer, bytespersec * sw); rc = UMSAudioDevice_get_position(adev,ev,&pos); } while(time > pos); rc = UMSAudioDevice_stop(adev,ev); rc = UMSAudioDevice_close(adev,ev); close(file); /* playback session */ printf("start playback session\n"); rc = UMSAudioDevice_open(adev,ev,"/dev/acpa0","PLAY", UMSAudioDevice_BlockingIO); buffer._length = 0 ; buffer._maximum = onesecsize ; lgain = 100; /*maximum left input gain*/ rgain = 100; /*maimum right input gain*/ rc = UMSAudioDevice_enable_output(adev,ev,"LINE_OUT",&lgain,&rgain); rc = UMSAudioDevice_initialize(adev,ev); file = open("/tmp/testaudio",O_RDONLY,0); rc = UMSAudioDevice_start(adev,ev); while((transferred_cnt = read(file,buffer._buffer,onesecsize))) { read_cnt = transferred_cnt / bytespersec; buffer._length = transferred_cnt ; rc = UMSAudioDevice_write(adev,ev,&buffer,read_cnt,&sw); } rc = UMSAudioDevice_play_remaining_data(adev,ev,TRUE); UMSAudioDevice_stop(adev,ev); UMSAudioDevice_close(adev,ev); _somFree(adev); } nyquist-3.05/snd/sndheader.h0000644000175000000620000000013410144436365015061 0ustar stevestaffint snd_open_file(snd_type snd, long *flags); void write_sndheader_finish(snd_type snd); nyquist-3.05/snd/audiosgi.c0000644000175000000620000000115310144436365014725 0ustar stevestaff#include "snd.h" int audio_open() { printf("audio_open not implemented\n"); return SND_SUCCESS; } int audio_close() { printf("audio_close not implemented\n"); return SND_SUCCESS; } int audio_flush(snd_type snd) { printf("audio_flush not implemented\n"); return SND_SUCCESS; } long audio_read() { printf("audio_read not implemented\n"); return 0; } long audio_write() { printf("audio_write not implemented\n"); return 0; } int audio_reset() { printf("audio reset not implemented\n"); return SND_SUCCESS; } long audio_poll(snd_type snd) { return 1000000; } nyquist-3.05/snd/sndwin32.h0000644000175000000620000000057410144436365014603 0ustar stevestaff/* sndwin32.h -- system-specific definitions */ typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflicts if already defined: */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/snd/snd.h0000644000175000000620000002652111466723256013726 0ustar stevestaff/* * snd.h */ /* * based on sndheader.h, written by * Jim Zelenka, CMU/ITC * rewritten 9 Jun 1992 (from my original sources, * adding many new constants) * converted by Roger Dannenberg to snd.h, 21 Jun 97 */ #ifdef SND_H error here #endif #define SND_H /* Standard includes */ #include #include "sndconfig.h" /* FIX - remove stuff here */ /* jlh -- don't think this is being used at all #ifdef PORTAUDIO #include "pablio.h" #endif */ /* libsndfile includes */ #include /* header formats */ /* jlh -- looks like lisp uses these; keep them. But I may be wanting to add more... */ #define SND_HEAD_NONE 0 /* LISP-SRC: (setf snd-head-none 0) */ #define SND_HEAD_AIFF 1 /* LISP-SRC: (setf snd-head-AIFF 1) */ #define SND_HEAD_IRCAM 2 /* LISP-SRC: (setf snd-head-IRCAM 2) */ #define SND_HEAD_NEXT 3 /* LISP-SRC: (setf snd-head-NeXT 3) */ #define SND_HEAD_WAVE 4 /* LISP-SRC: (setf snd-head-Wave 4) */ #define SND_HEAD_PAF 5 /* LISP-SRC: (setf snd-head-PAF 5) */ #define SND_HEAD_SVX 6 /* LISP-SRC: (setf snd-head-SVX 6) */ #define SND_HEAD_NIST 7 /* LISP-SRC: (setf snd-head-NIST 7) */ #define SND_HEAD_VOC 8 /* LISP-SRC: (setf snd-head-VOC 8) */ #define SND_HEAD_W64 9 /* LISP-SRC: (setf snd-head-W64 9) */ #define SND_HEAD_MAT4 10 /* LISP-SRC: (setf snd-head-MAT4 10) */ #define SND_HEAD_MAT5 11 /* LISP-SRC: (setf snd-head-MAT5 11) */ #define SND_HEAD_PVF 12 /* LISP-SRC: (setf snd-head-PVF 12) */ #define SND_HEAD_XI 13 /* LISP-SRC: (setf snd-head-XI 13) */ #define SND_HEAD_HTK 14 /* LISP-SRC: (setf snd-head-HTK 14) */ #define SND_HEAD_SDS 15 /* LISP-SRC: (setf snd-head-SDS 15) */ #define SND_HEAD_AVR 16 /* LISP-SRC: (setf snd-head-AVR 16) */ #define SND_HEAD_SD2 17 /* LISP-SRC: (setf snd-head-SD2 17) */ #define SND_HEAD_FLAC 18 /* LISP-SRC: (setf snd-head-FLAC 18) */ #define SND_HEAD_CAF 19 /* LISP-SRC: (setf snd-head-CAF 19) */ #define SND_NUM_HEADS 20 /* bitfields for soundheaders */ #define SND_HEAD_CHANNELS (1<<0) /* LISP-SRC: (setf snd-head-channels 1) */ #define SND_HEAD_MODE (1<<1) /* LISP-SRC: (setf snd-head-mode 2) */ #define SND_HEAD_BITS (1<<2) /* LISP-SRC: (setf snd-head-bits 4) */ #define SND_HEAD_SRATE (1<<3) /* LISP-SRC: (setf snd-head-srate 8) */ /* when returned from lisp, len (samples) is converted to time (seconds) */ #define SND_HEAD_LEN (1<<4) /* LISP-SRC: (setf snd-head-dur 16) */ #define SND_HEAD_LATENCY (1<<5) /* LISP-SRC: (setf snd-head-latency 32) */ #define SND_HEAD_TYPE (1<<6) /* LISP-SRC: (setf snd-head-type 64) */ /* modes */ /* IMA ADPCM */ #define SND_MODE_ADPCM 0 /* LISP-SRC: (setf snd-mode-adpcm 0) */ #define SND_MODE_PCM 1 /* LISP-SRC: (setf snd-mode-pcm 1) */ #define SND_MODE_ULAW 2 /* LISP-SRC: (setf snd-mode-ulaw 2) */ #define SND_MODE_ALAW 3 /* LISP-SRC: (setf snd-mode-alaw 3) */ #define SND_MODE_FLOAT 4 /* LISP-SRC: (setf snd-mode-float 4) */ /* unsigned pcm (e.g. Microsoft 8-bit wav format): */ #define SND_MODE_UPCM 5 /* LISP-SRC: (setf snd-mode-upcm 5) */ #define SND_MODE_UNKNOWN 6 /* LISP-SRC: (setf snd-mode-unknown 6) */ #define SND_MODE_DOUBLE 7 /* LISP-SRC: (setf snd-mode-double 7) */ #define SND_MODE_GSM610 8 /* LISP-SRC: (setf snd-mode-GSM610 8) */ #define SND_MODE_DWVW 9 /* LISP-SRC: (setf snd-mode-DWVW 9) */ #define SND_MODE_DPCM 10 /* LISP-SRC: (setf snd-mode-DPCM 10) */ /* microsoft ADPCM */ #define SND_MODE_MSADPCM 11 /* LISP-SRC: (setf snd-mode-msadpcm 11) */ #define SND_NUM_MODES 12 /* if snd_open fails, source is set to SND_DEVICE_NONE */ #define SND_DEVICE_NONE 0 #define SND_DEVICE_FILE 1 #define SND_DEVICE_AUDIO 2 #define SND_DEVICE_MEM 3 /* this value is unique for both FILE* and file numbers, * either of which may be returned by snd_file_open or * snd_file_creat. It is used to indicate "no file" */ #define SND_FILE_FAILURE -1 /* write_flag values */ #define SND_READ 0 #define SND_WRITE 1 #define SND_OVERWRITE 2 #define SND_REALTIME 0 #define SND_COMPUTEAHEAD 1 #define SND_LOOP_NONE 0 #define SND_LOOP_FORWARD 1 #define SND_LOOP_FORWARD_BACKWARD 2 typedef struct { int mode; long begin; long end; } loop_node, *loop_type; typedef struct { long channels; /* number of channels */ long mode; /* ADPCM, PCM, ULAW, ALAW, FLOAT, UPCM */ long bits; /* bits per sample */ double srate; /* sample rate */ } format_node; /* notes on audio protocol: If you are writing audio to a device, there are two things you might want to optimize: (1) you want to maintain just enough buffered data to handle the system+application latency. You might want to output data incrementally in small units to avoid a long interval of audio computation. If buffers have a practical minimum length, a solution is to fill system buffers incrementally. This approach is supported by the SND_REALTIME protocol; (2) you can afford to compute large buffers in one step, and for simplicity you want to fill buffers as soon as they are available. This approach is supported by the SND_COMPUTEAHEAD protocol. In either case, the audio.latency field specifies the estimated worst case latency. (For example, the system may be swapping pages and the application may be garbage collecting.) Then buffer space will be at least large enough to hold audio.latency seconds of audio. The audio.granularity field specifies the maximum duration of a block of samples. The application will not compute samples until there is room for audio.granularity of samples (for example, it will test by calling snd_poll()). The application will pass at most audio.granularity of samples to snd_write(). On input, the application will wait until there are at least audio.granularity of samples and then read no more than that amount. For sound input, SND_REALTIME and SND_COMPUTEAHEAD serve similar purposes. Use SND_REALTIME if you want to read data incrementally a bit at a time. Use SND_COMPUTEAHEAD if you want to be informed (by snd_poll) of all the data as soon as it is available, regardless of how big the buffers are. [if I understand correctly: "Use SND_COMPUTEAHEAD if you want to be informed as soon as all the data is available....". -eub] */ /* Prevent compiler errors */ struct snd_struct; /* these do not use snd_type because it is not defined yet... */ typedef int (*snd_reset_fn)(struct snd_struct *snd); typedef long (*snd_poll_fn)(struct snd_struct *snd); typedef long (*snd_read_fn)(struct snd_struct *snd, void *buffer, long length); typedef long (*snd_write_fn)(struct snd_struct *snd, void *buffer, long length); typedef int (*snd_open_fn)(struct snd_struct *snd, long *flags); typedef int (*snd_close_fn)(struct snd_struct *snd); //typedef int (*snd_reset_fn)(struct snd_struct *snd); typedef int (*snd_flush_fn)(struct snd_struct *snd); typedef struct { snd_poll_fn poll; snd_read_fn read; snd_write_fn write; snd_open_fn open; snd_close_fn close; snd_reset_fn reset; snd_flush_fn flush; } snd_fns_node, *snd_fns_type; typedef struct snd_struct { short device; /* file, audio, or memory */ short write_flag; /* SND_READ, SND_WRITE, SND_OVERWRITE */ format_node format; /* sample format: channels, mode, bits, srate */ snd_fns_type dictionary; /* for internal use only */ union { struct { char filename[snd_string_max]; /* file name */ /* jlh - this doesn't seem to be used anywhere char filetype[snd_string_max]; /* file type/format description */ int file; /* OS file number */ SNDFILE *sffile; /* libsndfile audio file pointer */ SF_INFO sfinfo; /* libsndfile audio file info */ /* jlh - used in lisp code, I believe */ long header; /* None, AIFF, IRCAM, NEXT, WAVE */ /* jlh I have changed these from byte units to frame units; see comments in sndread.c for justification. */ long byte_offset; /* file offset of first sample */ long end_offset; /* byte_offset of last byte + 1 */ long current_offset; /* current (computed) file offset */ /* jlh Probably not needed ever again. */ int swap; /* flag to swap bytes on input/output */ /* FIX -- these are important for Nyquist, I hope libsndfile supports them */ /* jlh -- leave filling these out 'til later. */ /* fields from AIFF sample files: */ int loop_info; /* Boolean: is this loop info valid? */ double native_hz; /* original pitch in hz */ float gain; /* gain: scale factor */ double low_hz; double high_hz; char low_velocity; char high_velocity; loop_node sustain_loop; loop_node release_loop; } file; struct { char interfacename[snd_string_max]; /* (optional) to specify interface */ char devicename[snd_string_max]; /* (optional) to specify device */ void *descriptor; long protocol; /* SND_REALTIME or SND_COMPUTEAHEAD */ double latency; /* app + os worst case latency (seconds) */ double granularity; /* expected period of app computation (s) */ /* note: pass 0.0 for default latency and granularity */ } audio; struct { long buffer_max; /* size of buffer memory */ char *buffer; /* memory buffer */ long buffer_len; /* length of data in buffer */ long buffer_pos; /* current location in buffer */ } mem; } u; } snd_node, *snd_type; typedef long (*cvtfn_type)(void *buf1, void *buf2, long len2, float scale, float *peak); /* when open fails, the dictionary gets this set of functions: */ extern snd_fns_node snd_none_dictionary; /* snd_open, snd_close, snd_convert return SND_SUCESS if successful */ #define SND_SUCCESS 0 #ifdef __cplusplus extern "C" { #endif /* these two are for internal use only (and should really be declared * in another .h file not included by clients): */ void snd_init(); void snd_add_device(char *interf, char *device, snd_fns_type dictionary); /* jlh The next three are ones I messed with */ long snd_bytes_per_frame(snd_type snd); long move_samples_inward(void *buf1, void *buf2, long len2, float scale, float *peak); long move_samples_outward(void *buf1, void *buf2, long len2, float scale, float *peak); int snd_open(snd_type snd, long *flags); int snd_seek(snd_type snd, double skip); /* set current location in file */ int snd_reset(snd_type snd); /* flush non-file buffers */ int snd_close(snd_type snd); int snd_flush(snd_type snd); long snd_read(snd_type snd, void *buffer, long length); long snd_write(snd_type snd, void *buffer, long length); long snd_convert(snd_type snd1, void *buffer1, snd_type snd2, void *buffer2, long length); void change_byte_order(snd_type snd, void *buffer, long length); long snd_poll(snd_type snd); cvtfn_type select_cvtfn(snd_type snd1, snd_type snd2); /* some conversion function lookup tables: */ extern cvtfn_type cvt_from_8[]; extern cvtfn_type cvt_from_16[]; extern cvtfn_type cvt_from_24[]; extern cvtfn_type cvt_from_32[]; extern cvtfn_type cvt_to_8[]; extern cvtfn_type cvt_to_16[]; extern cvtfn_type cvt_to_24[]; extern cvtfn_type cvt_to_32[]; long cvt_from_unknown(void *buf1, void *buf2, long len2, float scale, float *peak); #define cvt_to_unknown cvt_from_unknown char *snd_mode_to_string(long mode); /* this number is returned by snd_poll if you pass it a file device */ #define MAX_FILE_BUF_LEN 20000 /* this is necessary for SGI */ #ifndef FALSE #define FALSE 0 #define TRUE 1 #endif #ifdef __cplusplus } #endif nyquist-3.05/snd/audiolinux.c0000644000175000000620000001262510144436365015310 0ustar stevestaff/* Standard includes */ #include "stdlib.h" #include "stdio.h" #include #include /* snd includes */ #include "snd.h" typedef struct { int portfd; snd_pcm_t *sound_handle; } descr_t, *descr_type; const char* snd_card_type_name (unsigned int card_type) { switch (card_type) { /* Gravis UltraSound */ case SND_CARD_TYPE_GUS_CLASSIC: return "GUS Classic"; case SND_CARD_TYPE_GUS_EXTREME: return "GUS Extreme"; case SND_CARD_TYPE_GUS_ACE: return "GUS ACE"; case SND_CARD_TYPE_GUS_MAX: return "GUS MAX"; case SND_CARD_TYPE_AMD_INTERWAVE: return "AMD Interwave"; /* Sound Blaster */ case SND_CARD_TYPE_SB_10: return "Sound Blaster 10"; case SND_CARD_TYPE_SB_20: return "Sound Blaster 20"; case SND_CARD_TYPE_SB_PRO: return "Sound Blaster Pro"; case SND_CARD_TYPE_SB_16: return "Sound Blaster 16"; case SND_CARD_TYPE_SB_AWE: return "Sound Blaster AWE"; /* Various */ case SND_CARD_TYPE_ESS_ES1688: return "ESS AudioDrive ESx688"; case SND_CARD_TYPE_OPL3_SA: return "Yamaha OPL3 SA"; case SND_CARD_TYPE_MOZART: return "OAK Mozart"; case SND_CARD_TYPE_S3_SONICVIBES: return "S3 SonicVibes"; case SND_CARD_TYPE_ENS1370: return "Ensoniq ES1370"; case SND_CARD_TYPE_ENS1371: return "Ensoniq ES1371"; case SND_CARD_TYPE_CS4232: return "CS4232/CS4232A"; case SND_CARD_TYPE_CS4236: return "CS4235/CS4236B/CS4237B/CS4238B/CS4239"; case SND_CARD_TYPE_AMD_INTERWAVE_STB: return "AMD InterWave + TEA6330T"; case SND_CARD_TYPE_ESS_ES1938: return "ESS Solo-1 ES1938"; case SND_CARD_TYPE_ESS_ES18XX: return "ESS AudioDrive ES18XX"; case SND_CARD_TYPE_CS4231: return "CS4231"; case SND_CARD_TYPE_SERIAL: return "Serial MIDI driver"; case SND_CARD_TYPE_AD1848: return "Generic AD1848 driver"; case SND_CARD_TYPE_TRID4DWAVEDX: return "Trident 4DWave DX"; case SND_CARD_TYPE_TRID4DWAVENX: return "Trident 4DWave NX"; case SND_CARD_TYPE_SGALAXY: return "Aztech Sound Galaxy"; case SND_CARD_TYPE_CS461X: return "Sound Fusion CS4610/12/15"; /* Turtle Beach WaveFront series */ case SND_CARD_TYPE_WAVEFRONT: return "TB WaveFront generic"; case SND_CARD_TYPE_TROPEZ: return "TB Tropez"; case SND_CARD_TYPE_TROPEZPLUS: return "TB Tropez+"; case SND_CARD_TYPE_MAUI: return "TB Maui"; case SND_CARD_TYPE_CMI8330: return "C-Media CMI8330"; case SND_CARD_TYPE_DUMMY: return "Dummy Soundcard"; /* --- */ case SND_CARD_TYPE_ALS100: return "Avance Logic ALS100"; /* --- */ default: if (card_type < SND_CARD_TYPE_LAST) return "Unknown"; return "Invalid"; } } descr_type cast_descrp(snd_type snd) { return (descr_type) snd->u.audio.descriptor; } int audio_reset(snd_type snd); int audio_formatmatch(format_node *demanded, DWORD avail, long *flags); int test_44(DWORD tested); int test_22(DWORD tested); int test_11(DWORD tested); int test_stereo(DWORD tested); int test_mono(DWORD tested); int test_16bit(DWORD tested); int test_8bit(DWORD tested); MMRESULT win_wave_open(snd_type snd, UINT devtoopen, HWAVE *hptr); void *audio_descr_build(snd_type snd); void mm_error_handler(snd_type snd, MMRESULT mmerror, void (*fp)()); int numofbits(long tested); int audio_dev(snd_type snd, char *name, UINT *device); long audio_poll(snd_type snd) { /* Not implemented by PL -RBD */ /* I have no idea how Aura works without audio_poll -RBD */ exit(0); return 0; } long audio_read(snd_type snd, void *buffer, long length) { /* Not implemented by PL -RBD */ return 0; } long audio_write(snd_type snd, void *buffer, long length) { descr_type dp = cast_descrp(snd); snd_pcm_write(dp->sound_handle, buffer, (int) length); return length; } int audio_open(snd_type snd, long *flags) { snd_pcm_info_t pcm_info = { 0, }; int perrno, fd; snd_pcm_t *sound_handle; perrno = snd_pcm_open(&sound_handle, 0, 0, SND_PCM_OPEN_PLAYBACK); if (perrno >= 0) { fd = snd_pcm_file_descriptor(sound_handle); if (fd < 0) { snd_pcm_close(sound_handle); perrno = fd; } } else { /* This printf should not be here -RBD */ printf("Sound device error: %d - %s \n", perrno, snd_strerror(perrno)); return !SND_SUCCESS; }; if (snd_pcm_info (sound_handle, &pcm_info) < 0) return !SND_SUCCESS; /* These printfs should not be here -RBD */ printf("Card name: %s", snd_card_type_name (pcm_info.type)); printf("Card ID: %d\n", pcm_info.id); return SND_SUCCESS; } int audio_close(snd_type snd) { snd_pcm_close(cast_descrp(snd)->sound_handle); return SND_SUCCESS; } /* audio_flush -- finish audio output */ /* * if any buffer is non-empty, send it out * return success when all buffers have been returned empty */ int audio_flush(snd_type snd) { exit(0); return SND_SUCCESS; } int audio_reset(snd_type snd) { return SND_SUCCESS; } snd_fns_node mmsystem_dictionary = { audio_poll, audio_read, audio_write, audio_open, audio_close, audio_reset, audio_flush }; void snd_init() { snd_add_device("ALSA", "default", &mmsystem_dictionary); } nyquist-3.05/snd/sndmac.h0000644000175000000620000000036611466723256014406 0ustar stevestaff/* sndmac.h -- system-specific definitions */ typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflicts if already defined: */ #ifndef max #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/snd/sndwrite.h0000644000175000000620000000121610144436365014765 0ustar stevestaff/* sndwrite.h -- header to write sounds to files */ double sound_save(LVAL snd_expr, long n, unsigned char *filename, long format, long mode, long bits, double *sr, long *nchans, double *duration); /* LISP: (SND-SAVE ANY FIXNUM STRING FIXNUM FIXNUM FIXNUM ANYNUM^ FIXNUM^ ANYNUM^) */ double sound_overwrite(LVAL snd_expr, long n, unsigned char *filename, long byte_offset, long mode, long bits, double sr, long nchans, double *duration); /* LISP: (SND-OVERWRITE ANY FIXNUM STRING FIXNUM FIXNUM FIXNUM ANYNUM FIXNUM ANYNUM^) */ nyquist-3.05/snd/snd.txt0000644000175000000620000002655011466723256014320 0ustar stevestaff Audio File, Format Conversion, and I/O Utilities Roger Dannenberg 18 June 97 Revised 6 July 97 Revised 7 May 00 with multiple interface support and inner architecture documentation This document describes a set of portable C utilities for digital audio input and output to and from files and audio interfaces. The goals are to be able to read and write sound files in a variety of formats and to play and record audio. This code is intended for use in Nyquist, Aura, Amulet, and other systems, and should be portable to virtually any computer system that supports C and has a file system. Overview: There is basically one interesting data type: snd_type is a pointer to a descriptor for an audio stream, which is either being read from or written to a file or audio interface. The snd_type contains a structure that describes the sample format, sample rate, number of channels, etc. Routines exist to initialize sound transfer (snd_open()), perform transfers (snd_read(), snd_write()) and to finalize a transfer (snd_close()). Other routines allow you to transfer data to/from buffers and to convert formats. Sample rate conversion is not currently supported, but would be a welcome addition. typedef struct { long channels; /* number of channels */ long mode; /* ADPCM, PCM, ULAW, ALAW, FLOAT, UPCM */ long bits; /* bits per sample */ double srate; /* sample rate */ } format_node; typedef struct { short device; /* file, audio, or memory */ short write_flag; /* SND_READ, SND_WRITE, SND_OVERWRITE */ union { struct { char filename[258]; /* file name */ int file; /* OS file number */ long header; /* None, AIFF, IRCAM, NEXT, WAVE */ long byte_offset; /* file offset of first sample */ long end_offset; /* byte_offset of last byte + 1 */ } file; struct { long buffer_max; /* size of buffer memory */ char *buffer; /* memory buffer */ long buffer_len; /* length of data in buffer */ long buffer_pos; /* current location in buffer */ } mem; struct { char devicename[258]; /* (optional) to specify device */ void *descriptor; long protocol; /* SND_REALTIME or SND_COMPUTEAHEAD */ double latency; /* app + os worst case latency (seconds) */ double granularity; /* expected period of app computation (s) */ /* note: pass 0.0 for default latency and granularity */ } audio; } u; format_node format; /* sample format: channels, mode, bits, srate */ } snd_node, *snd_type; The meanings of fields are as follows: device: one of SND_DEVICE_FILE (data to/from file), SND_DEVICE_AUDIO (data to/from audio I/O device), SND_DEVICE_MEM (data to/from in-memory buffer), or SND_DEVICE_NONE (records that snd_open failed). write_flag: one of SND_WRITE (create a file and write to it), SND_READ (read from a file), SND_OVERWRITE (overwrite some samples within a file, leaving the header and other samples untouched). format: contains number of channels, mode, number of bits per sample, and sample rate. mode is SND_MODE_ADPCM (adaptive delta modulation), SND_MODE_PCM (pulse code modulation, i.e. simple linear encoding), SND_MODE_ULAW (Mu-Law), SND_MODE_ALAW (A-Law), SND_MODE_FLOAT (float), or SND_MODE_UPCM (unsigned PCM) These are fields for SND_DEVICE_FILE: filename: string name for file. file: the file number or handle returned by the operating system. header: the type and format of header, one of SND_HEAD_NONE (no header), SND_HEAD_AIFF, SND_HEAD_IRCAM, SND_HEAD_NEXT (Sun and NeXT format), or SND_HEAD_WAVE. byte_offset: the byte offset in the file. After opening the file, this is the offset of the first sample. This value is updated after each read or write. end_offset: offset of the byte just beyond the last byte of the file. These are fields for SND_DEVICE_AUDIO devicename: string name for device (to select among multiple devices). This may be set to the empty string (devicename[0] = 0) to indicate the default audio device, or it may be set to a name obtained from snd_devicename(). descriptor: a field to store system-dependent data protocol: SND_REALTIME (use this if you are trying to compute ahead by a constant amount, especially for low-latency output) or SND_COMPUTEAHEAD (use this if you want to keep output buffers as full as possible, which will cause greater compute-ahead). latency: (minimum) amount to be kept in buffer(s). This should be at least as great as the longest computational delay of the application PLUS the worst case latency for scheduling the application to run. granularity: expected period of the periodic computation that generates samples. Also, granularity indicates the largest number of samples that will be written with snd_write or read with snd_read by the application. The following fields are for SND_DEVICE_MEM (in-memory data): buffer_max: the size of the buffer memory (in bytes) buffer: the memory buffer address buffer_len: the length of data in the buffer buffer_pos: the current location of the input/output in memory. Routine descriptions: int snd_open(snd_type snd, long *flags); To open a file, fill in fields of a snd_type and call snd_open. If there is header information in the file or device characteristics for the audio interface, fields of snd are filled in. The flags parameter tells which fields were specified by the snd_open process. E.g. if you open a raw file, there is no header info, so the format will be as specified in snd. On the other hand, if you open an AIFF file, the file will specify the sample rate, channels, bits, etc., so all these values will be written into snd, and bits will be set in flags to indicate the information was picked up from the file. Returns SND_SUCCESS iff successful. If not successful, attempts to open a file will place the return code from open() into the u.file.file field. Before calling snd_open, all general fields and fields corresponding to the device (e.g. u.file for SND_DEVICE_FILE) should be set, with the following exceptions: u.file.header (for SND_WRITE), byte_offset, end_offset, descriptor. NOTE: do not call snd_open for SND_DEVICE_MEM, just fill in the fields. u.mem.buffer_len is the write pointer (snd_write() data goes here), and u.mem.buffer_pos is the read pointer (snd_read() data comes from here). NOTE 2: for SND_DEVICE_MEM, you can set write_flag to SND_WRITE, write data into the buffer, then set write_flag to SND_READ and read the buffer. Use snd_reset() before reading the buffer again. int snd_close(snd_type snd); Closes a file or audio device. There is no need to call snd_close for SND_DEVICE_MEMORY, but this is not an error. Returns SND_SUCCESS iff successful. int snd_seek(snd_type snd, double skip); After opening a file for reading or overwriting, you can seek ahead to a specific time point by calling snd_seek. The skip parameter is in seconds. Returns SND_SUCCESS iff successful. int snd_reset(snd_type snd); Resets non-file buffers. If snd has SND_DEVICE_AUDIO, then the sample buffers are flushed. This might be a good idea before reading samples after a long pause that would cause buffers to overflow and contain old data, or before writing samples if you want the samples to play immediately, overriding anything already in the buffers. If snd has SND_DEVICE_MEM and SND_READ, then the buffer read pointer (buffer_pos) is reset to zero. If SND_WRITE is set, then the buffer read pointer (buffer_pos) and write pointer (buffer_len) are reset to zero. If snd has SND_DEVICE_FILE, nothing happens. Returns SND_SUCCESS iff successful. long snd_read(snd_type snd, void *buffer, long length); Read up to length frames into buffer. Returns the number of frames actually read. int snd_write(snd_type snd, void *buffer, long length); Writes length frames from buffer to file or device. Returns number of frames actually written. long snd_convert(snd_type snd1, void *buffer1, snd_type snd2, void *buffer2, long length); To read from a source and write to a sink, you may have to convert formats. This routine provides simple format conversions according to what is specified in snd1 and snd2. The number of frames to convert is given by length. Data in buffer2 are converted and written to bufffer1. long snd_poll(snd_type snd); The standard way to play files is to put something in the event loop that refills an output buffer managed by the device driver. This routine allows you to ask whether there is space to output more samples. If SND_REALTIME is selected, the number returned by snd_poll will grow fairly smoothly at the data rate, i.e. if the data rate is 8KB/s, then the result of snd_poll will increase by 8 bytes per millisecond. On the other hand, if SND_COMPUTEAHEAD is selected, then snd_poll will return zero until a sample buffer becomes available, at which time the value returned will be the entire buffer size. Note: some low-level functions are implemented for conversion from buffers of floats to various representations and from these representations back to floats. See snd.h for their declarations. int snd_flush(snd_type snd); When the device is SND_DEVICE_AUDIO, writes are buffered. After the last write, call snd_flush() to transfer samples from the buffer to the output device. snd_flush() returns immediately, but it only returns SND_SUCCESS after the data has been output to the audio device. Since calling snd_close() will terminate output, the proper way to finish audio output is to call snd_flush() repeatedly until it returns SND_SUCCESS. Then call snd_close() to close the audio device and free buffers. If snd_flush is called on any open snd_type other than a SND_DEVICE_AUDIO opened for output, it returns SUCCESS. Results are undefined if snd_flush is called on a non-open snd_type. long snd_bytes_per_frame(snd_type snd); Calculates the number of bytes in a frame (a frame has one sample per channel; sound files are stored as a sequence of frames). char *snd_mode_to_string(long mode); Returns a string describing the mode (SND_MODE_PCM, etc.). char *snd_devicename(int n); Returns a string describing the n-th audio device. Returns NULL if n is greater or equal to the number of audio devices. Available devices are numbered, starting with the default device at n=0. Before opening an audio device, an application can use this to enumerate all possible devices, select one (e.g. by presenting a list to the user), and then copy the string into the devicename field of the snd_type structure. If the devicename field is the empty string, device 0 will be opened. It is easy to construct a higher-level function to play a file, e.g. aio_node my_player; aio_play_init(&player, "mysound.wav"); playing = TRUE; Then, in the polling loop: if (playing) { if (!aio_play_poll(&player)) playing = FALSE; } Examples: see convert.c for examples of: Printing information about a sound file Converting sound file formats Playing audio from a file Reading audio from audio input To compile convert.c under NT: add all the .c files to a console application project and add these libraries to the Object/library modules list under the Link tab in the Project Settings dialog box: winmm.lib ws2_32.lib Inner architecture description Audio buffer and time management nyquist-3.05/snd/audiooss.c0000644000175000000620000001004010144436365014742 0ustar stevestaff/* Open Sound System (oss) implementation of snd by Dominic Mazzoni */ #include #include #include #include #include #include #include /* snd includes */ #include "snd.h" typedef struct { int audio_fd; } oss_info_struct, *oss_info; oss_info get_oss_info(snd_type snd) { return (oss_info) snd->u.audio.descriptor; } long audio_poll(snd_type snd) { oss_info dp = get_oss_info(snd); audio_buf_info info; if (snd->write_flag == SND_READ) ioctl(dp->audio_fd, SNDCTL_DSP_GETISPACE, &info); else ioctl(dp->audio_fd, SNDCTL_DSP_GETOSPACE, &info); /* Note that this returns frames while audio_write returns bytes */ return info.bytes / snd_bytes_per_frame(snd); } long audio_read(snd_type snd, void *buffer, long length_in_bytes) { oss_info dp = get_oss_info(snd); int rval = read(dp->audio_fd, buffer, length_in_bytes); return rval; } long audio_write(snd_type snd, void *buffer, long length_in_bytes) { oss_info dp = get_oss_info(snd); int rval = write(dp->audio_fd, buffer, length_in_bytes); return rval; } int audio_open(snd_type snd, long *flags) { int format; int channels; int rate; oss_info dp; const char *device = "/dev/dsp"; snd->u.audio.descriptor = (oss_info) malloc(sizeof(oss_info_struct)); dp = get_oss_info(snd); if (snd->u.audio.devicename[0] != 0) device = snd->u.audio.devicename; if (snd->write_flag == SND_READ) { /* open audio input */ /* Open /dev/dsp */ dp->audio_fd = open(device, O_RDONLY, 0); if (dp->audio_fd == -1) return !SND_SUCCESS; } else { /* open audio output */ /* Open /dev/dsp */ dp->audio_fd = open(device, O_WRONLY, 0); if (dp->audio_fd == -1) return !SND_SUCCESS; } /* Set format to signed 16-bit little-endian */ format = AFMT_S16_LE; if (ioctl(dp->audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) return !SND_SUCCESS; if (format != AFMT_S16_LE) /* this format is not supported */ return !SND_SUCCESS; /* Set number of channels */ channels = snd->format.channels; if (ioctl(dp->audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) return !SND_SUCCESS; if (channels != snd->format.channels) return !SND_SUCCESS; /* Set sampling rate. Must set sampling rate AFTER setting number of channels. */ rate = (int)(snd->format.srate + 0.5); if (ioctl(dp->audio_fd, SNDCTL_DSP_SPEED, &rate) == -1) return !SND_SUCCESS; if (rate - (int)(snd->format.srate + 0.5) > 100 || rate - (int)(snd->format.srate + 0.5) < -100) return !SND_SUCCESS; if (snd->write_flag == SND_READ) { /* start recording immediately */ struct timeval timeout; fd_set readfds; fd_set writefds; fd_set exceptfds; int n; timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FD_SET(dp->audio_fd, &readfds); n = dp->audio_fd + 1; select(n, &readfds, &writefds, &exceptfds, &timeout); } return SND_SUCCESS; } int audio_close(snd_type snd) { int dummy; oss_info dp = get_oss_info(snd); /* Stop playing immediately */ dummy = 0; ioctl(dp->audio_fd, SNDCTL_DSP_RESET, &dummy); close(dp->audio_fd); free((void *)snd->u.audio.descriptor); return SND_SUCCESS; } /* audio_flush -- finish audio output */ int audio_flush(snd_type snd) { int dummy; oss_info dp = get_oss_info(snd); dummy = 0; if (ioctl(dp->audio_fd, SNDCTL_DSP_SYNC, &dummy) == -1) return !SND_SUCCESS; return SND_SUCCESS; } int audio_reset(snd_type snd) { int dummy; oss_info dp = get_oss_info(snd); /* Stop playing immediately */ dummy = 0; ioctl(dp->audio_fd, SNDCTL_DSP_RESET, &dummy); return SND_SUCCESS; } snd_fns_node osssystem_dictionary = { audio_poll, audio_read, audio_write, audio_open, audio_close, audio_reset, audio_flush }; void snd_init() { snd_add_device("oss", "default", &osssystem_dictionary); } nyquist-3.05/snd/ieeecvt.h0000644000175000000620000000015310144436365014551 0ustar stevestaffvoid ConvertToIeeeExtended(double num, char *bytes); double ConvertFromIeeeExtended(unsigned char *bytes); nyquist-3.05/snd/sndhead.h0000644000175000000620000000400610144436365014534 0ustar stevestaff/* sndhead.h -- header info */ /* NeXT sound headers */ #define NEXT_SND_MAGIC (*((long *) ".snd")) // was: ((int)0x2e736e64) #define NEXT_SND_FORMAT_UNSPECIFIED (0) #define NEXT_SND_FORMAT_ULAW_8 (1) #define NEXT_SND_FORMAT_LINEAR_8 (2) #define NEXT_SND_FORMAT_LINEAR_16 (3) #define NEXT_SND_FORMAT_LINEAR_24 (4) #define NEXT_SND_FORMAT_LINEAR_32 (5) #define NEXT_SND_FORMAT_FLOAT (6) #define NEXT_SND_FORMAT_DOUBLE (7) #define NEXT_SND_FORMAT_INDIRECT (8) #define NEXT_SND_FORMAT_NESTED (9) #define NEXT_SND_FORMAT_DSP_CORE (10) #define NEXT_SND_FORMAT_DSP_DATA_8 (11) #define NEXT_SND_FORMAT_DSP_DATA_16 (12) #define NEXT_SND_FORMAT_DSP_DATA_24 (13) #define NEXT_SND_FORMAT_DSP_DATA_32 (14) #define NEXT_SND_FORMAT_DISPLAY (16) #define NEXT_SND_FORMAT_MULAW_SQUELCH (17) #define NEXT_SND_FORMAT_EMPHASIZED (18) #define NEXT_SND_FORMAT_COMPRESSED (19) #define NEXT_SND_FORMAT_COMPRESSED_EMPHASIZED (20) #define NEXT_SND_FORMAT_DSP_COMMANDS (21) #define NEXT_SND_FORMAT_DSP_COMMANDS_SAMPLES (22) /* for soundheaders (IRCAM) */ #define IRCAM_SND_MAGIC 107364L #define SIZEOF_IRCAM_HEADER 1024 #define IRCAM_SND_CHAR 0x101 #define IRCAM_SND_ALAW 0x102 #define IRCAM_SND_ULAW 0x103 #define IRCAM_SND_SHORT 0x104 #define IRCAM_SND_LONG 0x105 #define IRCAM_SND_FLOAT 0x106 #define IRCAM_SND_END 0 #define IRCAM_SND_MAXAMP 1 #define IRCAM_SND_AUDIOENCODE 2 #define IRCAM_SND_PVDATA 3 #define IRCAM_SND_COMMENT 4 #define IRCAM_SND_CODMAX 4 /* (Microsoft WAV sound headers */ /* purloined from public Microsoft RIFF docs */ #define WAVE_FORMAT_UNKNOWN (0x0000) #ifndef WIN32 // already defined (compatibly) by Microsoft header file: #define WAVE_FORMAT_PCM (0x0001) #endif #define WAVE_FORMAT_ADPCM (0x0002) #define WAVE_FORMAT_ALAW (0x0006) #define WAVE_FORMAT_MULAW (0x0007) #define WAVE_FORMAT_OKI_ADPCM (0x0010) #define WAVE_FORMAT_DIGISTD (0x0015) #define WAVE_FORMAT_DIGIFIX (0x0016) #define IBM_FORMAT_MULAW (0x0101) #define IBM_FORMAT_ALAW (0x0102) #define IBM_FORMAT_ADPCM (0x0103) nyquist-3.05/snd/audiowin32.c0000644000175000000620000007461510144436365015122 0ustar stevestaff/* Standard includes */ #include "stdlib.h" #include "stdio.h" /* snd includes */ #include "snd.h" #include "audiowin32.h" int audio_reset(snd_type snd); /* for timeBeginPeriod and timeEndPeriod, in case of SND_REALTIME device * handling */ int rt_devices_open = 0; /* also for RT devices */ #define TARGET_RESOLUTION 1 // 1-millisecond target resolution /* also (wTimerRes will contain the resolution that we can get */ TIMECAPS tc; UINT wTimerRes; int audio_formatmatch(format_node *demanded, DWORD avail, long *flags); int test_44(DWORD tested); int test_22(DWORD tested); int test_11(DWORD tested); int test_stereo(DWORD tested); int test_mono(DWORD tested); int test_16bit(DWORD tested); int test_8bit(DWORD tested); MMRESULT win_wave_open(snd_type snd, UINT devtoopen, HWAVE *hptr); void *audio_descr_build(snd_type snd); void mm_error_handler(snd_type snd, MMRESULT mmerror, void (*fp)()); int numofbits(long tested); int audio_dev(snd_type snd, char *name, UINT *device); long audio_poll(snd_type snd) { long availtemp; buffer_state *cur = ((buffer_state*) snd->u.audio.descriptor); LPWAVEHDR whdrs = cur->whdr; int i, test = 0; int numbuf = cur->numofbuffers; for (i=0; iu.audio.protocol == SND_REALTIME) { int last_buf, k; if (test < numbuf) { /* there is at least one buffer being processed by the * device (not "done") */ if (test) { /* there is at last one buffer done */ long bufferbytes; if (whdrs[cur->sync_buffer].dwFlags & WHDR_DONE){ k = (cur->sync_buffer + 1) % numbuf; while (k != cur->sync_buffer){ if (!(whdrs[k].dwFlags & WHDR_DONE)){ cur->sync_buffer = k; break; } k = (k + 1) % numbuf; } cur->sync_time = cur->prev_time; } else cur->prev_time = timeGetTime(); availtemp = (long) (((double)(cur->prev_time - cur->sync_time) * max_srate_dev / 1000 /*+ 2 * snd->u.audio.latency*/) * snd->format.srate); last_buf = (cur->sync_buffer + numbuf - 1) % numbuf; while (last_buf != cur->pollee) { availtemp += whdrs[last_buf].dwBufferLength; last_buf = (last_buf + numbuf - 1) % numbuf; } bufferbytes = test * (long) whdrs[0].dwBufferLength; if (bufferbytes < availtemp * snd_bytes_per_frame(snd)) { return bufferbytes / snd_bytes_per_frame(snd); } else { return availtemp; } } else { /* all buffer already passed to the device, it * should happen only just because we "overestimate" * the sample-rate */ cur->prev_time = timeGetTime(); cur->sync_time = cur->prev_time; return 0; } } else { //all buffers are done cur->prev_time = timeGetTime(); cur->sync_time = cur->prev_time; return ((numbuf - 1) * whdrs[0].dwBufferLength) / snd_bytes_per_frame(snd); } } else { /* protocol SND_COPMUTEAHEAD */ /* here is suppose that all buffer have the same length * (otherwise, sg like "for(i=0;iposinbuffer) / snd_bytes_per_frame(snd); } } long audio_read(snd_type snd, void *buffer, long length) { long i = 0, processed = 0, n; buffer_state *cur = (buffer_state *) snd->u.audio.descriptor; // int *index = &(cur->pollee); unsigned int *posinb = (unsigned int *) &(cur->posinbuffer); MMRESULT er; byte *in; byte *out; in = (byte *) (cur->whdr[cur->pollee].lpData + cur->posinbuffer); out = (byte *) buffer; while (length) { if (cur->whdr[cur->pollee].dwFlags & WHDR_DONE) { #if WHY_DOESNT_THIS_WORK // This seems correct and does work under NT, but sometimes // under Win95 and Win98 this generates an error. Although // we can't explain why the code is not necessary, everything // seems to work if we just comment this out. -RBD if (cur->posinbuffer == 0) { if (er = waveInUnprepareHeader(cur->u.h_in, &(cur->whdr[cur->pollee]), sizeof(WAVEINHDR))) { mm_error_handler(snd, er, snd_fail); return processed; } } #endif // WHY_DOESNT_THIS_WORK n = min((long) (cur->whdr[cur->pollee].dwBufferLength - cur->posinbuffer), length); memcpy(out, in, n); processed += n; cur->posinbuffer += n; length -= n; out += n; if (cur->posinbuffer >= (int) cur->whdr[cur->pollee].dwBufferLength) { if (er = waveInPrepareHeader(cur->u.h_in, &(cur->whdr[cur->pollee]), sizeof(WAVEHDR))) { mm_error_handler(snd, er, snd_fail); return(processed); } if (er = waveInAddBuffer(cur->u.h_in, &(cur->whdr[cur->pollee]), sizeof(WAVEHDR))) { waveInUnprepareHeader(cur->u.h_in, &(cur->whdr[cur->pollee]), sizeof(WAVEHDR)); mm_error_handler(snd, er, snd_fail); return processed; } //maybe the following line isn't necessary cur->posinbuffer = 0; if (++(cur->pollee) >= cur->numofbuffers){ cur->pollee = 0; } in = (byte *) (cur->whdr[cur->pollee].lpData); } } } return processed; } long audio_write(snd_type snd, void *buffer, long length) { long i = 0, processed = 0, n; buffer_state *cur = (buffer_state *)snd->u.audio.descriptor; unsigned int *posinb = (unsigned int *) &(cur->posinbuffer); MMRESULT er; byte *in; byte *out; in = (byte *) buffer; out = (byte *) (cur->whdr[cur->pollee].lpData + cur->posinbuffer); while (length) { if (cur->whdr[cur->pollee].dwFlags & WHDR_DONE) { #if WHY_DOESNT_THIS_WORK // This seems correct and does work under NT, but sometimes // under Win95 and Win98 this generates an error. Although // we can't explain why the code is not necessary, everything // seems to work if we just comment this out. -RBD if (cur->posinbuffer == 0) { if (er = waveOutUnprepareHeader(cur->h_wave, &(cur->whdr[cur->pollee]), sizeof(WAVEOUTHDR))) { mm_error_handler(snd, er, snd_fail); return processed; } } #endif // WHY_DOESNT_THIS_WORK n = min((long)(cur->whdr[cur->pollee].dwBufferLength - cur->posinbuffer), length); memcpy(out, in, n); processed += n; cur->posinbuffer += n; length -= n; in += n; if (cur->posinbuffer >= (int) cur->whdr[cur->pollee].dwBufferLength) { if (er = waveOutPrepareHeader(cur->u.h_out, &(cur->whdr[cur->pollee]), sizeof(WAVEHDR))) { mm_error_handler(snd, er, snd_fail); return processed; } if (er = waveOutWrite(cur->u.h_out, &(cur->whdr[cur->pollee]), sizeof(WAVEHDR))) { waveOutUnprepareHeader(cur->u.h_out, &(cur->whdr[cur->pollee]), sizeof(WAVEHDR)); mm_error_handler(snd, er, snd_fail); return processed; } //maybe the following line isn't necessary cur->posinbuffer = 0; if (++(cur->pollee) >= cur->numofbuffers) { cur->pollee = 0; } out = (byte*)(cur->whdr[cur->pollee].lpData); } } } return processed; } int audio_open(snd_type snd, long *flags) { UINT devtoopen; WAVEOUTCAPS outspec; WAVEINCAPS inspec; MMRESULT er; HWAVE h; if (snd->u.audio.devicename[0] != '\000'){ if (audio_dev(snd, snd->u.audio.devicename, &devtoopen)){ return(!SND_SUCCESS); } } else { devtoopen = WAVE_MAPPER; //open what you find } er = win_wave_open(snd, devtoopen, &h); if (er != (MMRESULT) MMSYSERR_NOERROR) { if (er != WAVERR_BADFORMAT) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } // The specified format isn't supported around here. // Let's try to use another one. if (devtoopen == WAVE_MAPPER) { UINT i, n, bestdev; format_node tempformat, bestformat = snd->format; long bestmatch = ((SND_HEAD_CHANNELS | SND_HEAD_MODE | SND_HEAD_BITS | SND_HEAD_SRATE) << 1) + 1; if (snd->write_flag == SND_READ) { n = waveInGetNumDevs(); for (i = 0; i < n; i++) { tempformat = snd->format; // non-zero means an error occurred: if (er = waveInGetDevCaps(i, &inspec, sizeof(WAVEINCAPS))) { char msg[64]; sprintf(msg, "Error at the %i device: %d\n", i, er); snd_fail(msg); } else { if (audio_formatmatch(&tempformat, inspec.dwFormats, flags) != SND_SUCCESS) { char msg[64]; sprintf(msg, "Problem with FormatMatching at device %i\n", i); } else if (numofbits(*flags) < numofbits(bestmatch)) { bestmatch = *flags; bestformat = tempformat; bestdev = i; } } } } else { n = waveOutGetNumDevs(); for (i = 0; i < n; i++) { tempformat = snd->format; // non-zero means an error occurred: if (er = waveOutGetDevCaps(i, &outspec, sizeof(WAVEOUTCAPS))) { char msg[64]; sprintf(msg, "Error at the %i device: %d\n", i, er); snd_fail(msg); } else { if (audio_formatmatch(&tempformat, outspec.dwFormats, flags) != SND_SUCCESS) { char msg[64]; sprintf(msg, "Problem with FormatMatching at device %i\n", i); } else if (numofbits(*flags) < numofbits(bestmatch)) { bestmatch = *flags; bestformat = tempformat; bestdev = i; } } } } if (bestmatch == ((long)-1)) { // We weren't able to pick up a device. Let's quit. return !SND_SUCCESS; } snd->format = bestformat; *flags = bestmatch; devtoopen = bestdev; // not devtoopen == WAVE_MAPPER, so open specified device, get format: } else if (snd->write_flag == SND_READ) { if (er = waveInGetDevCaps(devtoopen, &inspec, sizeof(WAVEINCAPS))) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } if (audio_formatmatch(&snd->format, inspec.dwFormats, flags)) { snd_fail("Something went wrong with FormatMatching"); return !SND_SUCCESS; } } else { // snd->write_flag != SND_READ if (er = waveOutGetDevCaps(devtoopen, &outspec, sizeof(WAVEOUTCAPS))) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } if (audio_formatmatch(&snd->format, outspec.dwFormats, flags)) { snd_fail("Something went wrong with FormatMatching"); return !SND_SUCCESS; } } if (er = win_wave_open(snd, devtoopen, &h)) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } } if (snd->u.audio.protocol == SND_REALTIME && !rt_devices_open) { if (er = timeGetDevCaps(&tc, sizeof(TIMECAPS))) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); if (er = timeBeginPeriod(wTimerRes)) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } rt_devices_open++; } snd->u.audio.descriptor = audio_descr_build(snd); if (snd->u.audio.descriptor == NULL) { snd_fail("Unable to create Device-state descriptor"); return !SND_SUCCESS; } ((buffer_state *) snd->u.audio.descriptor)->u.h_in = (HWAVEIN) h; if (snd->write_flag == SND_READ) { audio_reset(snd); // audio buffers should be passed to the device here, // like in the Reset() function } return SND_SUCCESS; } int audio_close(snd_type snd) { int i; MMRESULT er; buffer_state *bs = (buffer_state *) snd->u.audio.descriptor; if (snd->write_flag == SND_READ) { if (er = waveInReset(bs->u.h_in)) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } if (er = waveInClose(bs->u.h_in)) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } } else { // SND_WRITE if (er = waveOutReset(bs->u.h_out)) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } if (er = waveOutClose(bs->u.h_out)) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } } for (i = 0; i < bs->numofbuffers; i++) { snd_free(bs->whdr[i].lpData); } snd_free(bs->whdr); snd_free(bs); if (rt_devices_open) { timeEndPeriod(1); rt_devices_open--; } return SND_SUCCESS; } /* audio_flush -- finish audio output */ /* * if any buffer is non-empty, send it out * return success when all buffers have been returned empty */ int audio_flush(snd_type snd) { buffer_state *cur = (buffer_state *) snd->u.audio.descriptor; int *index = &(cur->pollee); LPWAVEHDR whdrs = cur->whdr; int i = 0; int test = 0; int processed = 0; int numbuf = cur->numofbuffers; MMRESULT er; if (snd->write_flag != SND_WRITE) return SND_SUCCESS; if (cur->posinbuffer > 0) { /* flush final partial buffer of data */ cur->whdr[*index].dwBufferLength = cur->posinbuffer; if (er = waveOutPrepareHeader(cur->u.h_out, &(cur->whdr[*index]), sizeof(WAVEHDR))) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } if (er = waveOutWrite(cur->u.h_out, &(cur->whdr[*index]), sizeof(WAVEHDR))) { waveOutUnprepareHeader(cur->u.h_out, &(cur->whdr[*index]), sizeof(WAVEHDR)); mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } cur->posinbuffer = 0; if (++(*index) >= cur->numofbuffers){ *index = 0; } } for (i = 0; i < numbuf; i++){ if (whdrs[i].dwFlags & WHDR_DONE) { test++; } } if (test < numbuf) return !SND_SUCCESS; else return SND_SUCCESS; } int audio_reset(snd_type snd) { MMRESULT er; int i; buffer_state *cur = (buffer_state *)snd->u.audio.descriptor; cur->pollee = 0; cur->posinbuffer = 0; if (snd->write_flag == SND_READ){ if (er = waveInReset(cur->u.h_in)) { mm_error_handler(snd, er, snd_fail); return (!SND_SUCCESS); } for (i=0; inumofbuffers; i++){ if (er = waveInPrepareHeader (cur->u.h_in, &(cur->whdr[i]), sizeof(WAVEHDR))) { mm_error_handler(snd, er, snd_fail); //this could be changed, as it's not necessery to return with error if at least one buffer didn't fail snd_fail("Not all of the buffers was initializable"); return(!SND_SUCCESS); } if (er = waveInAddBuffer (cur->u.h_in, &(cur->whdr[i]), sizeof(WAVEHDR))) { waveInUnprepareHeader (cur->u.h_in, &(cur->whdr[i]), sizeof(WAVEHDR)); mm_error_handler(snd, er, snd_fail); snd_fail("Not all of the buffers was initializable"); return(!SND_SUCCESS); } } if (er = waveInStart(cur->u.h_in)) { mm_error_handler(snd, er, snd_fail); return (!SND_SUCCESS); } } else { if (er = waveOutReset(cur->u.h_out)) { mm_error_handler(snd, er, snd_fail); return (!SND_SUCCESS); } } if (snd->u.audio.protocol == SND_REALTIME){ cur->sync_buffer = 0; cur->prev_time = timeGetTime(); cur->sync_time = cur->prev_time - (long)(2 * 1000 * snd->u.audio.latency + .5); } return(SND_SUCCESS); } //to choose that format (of those the device can support) that is equal or highest and //closest tp the one that the user required. Also, write out those parameters which were changed int audio_formatmatch(format_node *demanded, DWORD avail, long *flags) { *flags = 0; if (demanded->srate <= 11025.0){ if (test_11(avail)){ if (demanded->srate < 11025.0){ *flags = *flags | SND_HEAD_SRATE; demanded->srate = 11025.0; } }else { *flags = *flags | SND_HEAD_SRATE; if (test_22(avail)) demanded->srate = 22050.0; else if (test_44(avail)) demanded->srate = 44100.0; else { snd_fail("No available sample-rate (internal error)"); return(!SND_SUCCESS); } } }else if (demanded->srate <= 22050.0) { if (test_22(avail)){ if (demanded->srate < 22050.0){ *flags = *flags | SND_HEAD_SRATE; demanded->srate = 22050.0; } }else { *flags = *flags | SND_HEAD_SRATE; if (test_44(avail)) demanded->srate = 44100.0; else if (test_11(avail)) demanded->srate = 11025.0; else { snd_fail("No available sample-rate (internal error)"); return(!SND_SUCCESS); } } }else if (demanded->srate <= 44100.0) { if (test_44(avail)){ if (demanded->srate < 44100.0){ *flags = *flags | SND_HEAD_SRATE; demanded->srate = 44100.0; } }else { *flags = *flags | SND_HEAD_SRATE; if (test_22(avail)) demanded->srate = 22050.0; else if (test_11(avail)) demanded->srate = 11025.0; else { snd_fail("No available sample-rate (internal error)"); return(!SND_SUCCESS); } } }else { /* srate > 44100 */ *flags = *flags | SND_HEAD_SRATE; if (test_44(avail)) demanded->srate = 44100.0; else if (test_22(avail)) demanded->srate = 22050.0; else if (test_11(avail)) demanded->srate = 11025.0; else { snd_fail("No available sample-rate (internal error)"); return(!SND_SUCCESS); } } if (demanded->bits <= 8){ if (test_8bit(avail)){ if (demanded->bits < 8){ *flags = *flags | SND_HEAD_BITS; demanded->bits = 8; } }else { *flags = *flags | SND_HEAD_BITS; if (test_16bit(avail)) demanded->bits = 16; else { snd_fail("No available bit number (internal error)"); return(!SND_SUCCESS); } } }else { /* either between 8 and 16 bit, or higher than 16 bit -> use 16 bit */ if (test_16bit(avail)){ if (demanded->bits != 16){ *flags = *flags | SND_HEAD_BITS; demanded->bits = 16; } }else { *flags = *flags | SND_HEAD_BITS; if (test_8bit(avail)) demanded->bits = 8; else { snd_fail("No available bit number (internal error)"); return(!SND_SUCCESS); } } } if (demanded->channels == 1){ if (!(test_mono(avail))){ *flags = *flags | SND_HEAD_CHANNELS; if (test_stereo(avail)) demanded->channels = 2; else { snd_fail("No available channels number (internal error)"); return(!SND_SUCCESS); } } } else { /* otherwise, use stereo (for channels >= 2, or for invalid number, that is <1) */ if (test_stereo(avail)){ if (demanded->channels != 2){ *flags = *flags | SND_HEAD_CHANNELS; demanded->channels = 2; } } else { *flags = *flags | SND_HEAD_CHANNELS; if (test_mono(avail)) demanded->channels = 1; else { snd_fail("No available channels number (internal error)"); return(!SND_SUCCESS); } } } if (demanded->mode != SND_MODE_PCM){ *flags = *flags | SND_HEAD_MODE; demanded->mode = SND_MODE_PCM; } return (SND_SUCCESS); } //tests (based on dwFormats, see at WAVEOUTCAPS) that sr=44,1kHz is supported or not int test_44(DWORD tested) { return(tested & (WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16)); } int test_22(DWORD tested) { return(tested & (WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16)); } int test_11(DWORD tested) { return(tested & (WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16)); } int test_stereo(DWORD tested) { return(tested & ( WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16)); } int test_mono(DWORD tested) { return(tested & ( WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16)); } int test_16bit(DWORD tested) { return(tested & ( WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16)); } int test_8bit(DWORD tested) { return(tested & ( WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08)); } MMRESULT win_wave_open(snd_type snd, UINT devtoopen, HWAVE *hptr) { WAVEFORMATEX wfmt; int bperf; switch (snd->format.mode) { case SND_MODE_UNKNOWN: case SND_MODE_PCM: /* note: Windows uses signed PCM (PCM) for 16-bit data, and * unsigned PCM (UPCM) for 8-bit data */ if (snd->format.bits != 8) { wfmt.wFormatTag = WAVE_FORMAT_PCM; break; } else return WAVERR_BADFORMAT; case SND_MODE_ADPCM: case SND_MODE_ALAW: case SND_MODE_ULAW: case SND_MODE_FLOAT: case SND_MODE_UPCM: if (snd->format.bits == 8) { wfmt.wFormatTag = WAVE_FORMAT_PCM; break; } else return(WAVERR_BADFORMAT); default: return(MMSYSERR_INVALPARAM); } wfmt.nChannels = (unsigned short) snd->format.channels; wfmt.nSamplesPerSec = (long) (snd->format.srate + 0.5); bperf = snd_bytes_per_frame(snd); wfmt.nAvgBytesPerSec = (long) (bperf * snd->format.srate + 0.5); wfmt.nBlockAlign = (unsigned short) bperf; wfmt.wBitsPerSample = (unsigned short) snd->format.bits; wfmt.cbSize = 0; if (snd->write_flag != SND_READ) { /* Under Windows2000 on an IBM A21p Thinkpad, waveOutOpen will CRASH (!) if snd->format.srate is 110250, but it actually worked with 4000, and it worked with 96000, so I will assume sample rates above 96000 are bad. -RBD 24Jul02 */ if (wfmt.nSamplesPerSec > 96000) { return WAVERR_BADFORMAT; } /* otherwise, we're ready to open the device */ return waveOutOpen((LPHWAVEOUT) hptr, devtoopen, &wfmt, 0L, 0L, (DWORD) CALLBACK_NULL); } else { return waveInOpen((LPHWAVEIN) hptr, devtoopen, &wfmt, 0L, 0L, (DWORD) CALLBACK_NULL); } } void *audio_descr_build(snd_type snd) { int i, j; buffer_state *bufstate; double bufsize_in_frames; bufstate = (buffer_state *) snd_alloc(sizeof(buffer_state)); if (snd->u.audio.protocol == SND_REALTIME){ bufstate->numofbuffers = 3; } else { if (snd->u.audio.protocol != SND_COMPUTEAHEAD) snd_fail("Invalid protocol identifier. COMPUTEAHEAD method used instead"); bufstate->numofbuffers = 2; } if (NULL == (bufstate->whdr = (LPWAVEHDR)snd_alloc(bufstate->numofbuffers * sizeof(WAVEHDR)))){ snd_fail("Not enough memory, or similar"); snd_free(bufstate); return NULL; } bufsize_in_frames = max(Audio_out_min_buffersize, snd->format.srate * snd->u.audio.latency); if (bufsize_in_frames > snd->format.srate * snd->u.audio.latency) snd->u.audio.latency = bufsize_in_frames / snd->format.srate; for (i=0; inumofbuffers; i++){ bufstate->whdr[i].dwBufferLength = (long)(bufsize_in_frames + 0.5) * snd_bytes_per_frame(snd); if (NULL == (bufstate->whdr[i].lpData = (char *) snd_alloc(bufstate->whdr[i].dwBufferLength))){ snd_fail("Not enough memory, or similar"); for (j=0; jwhdr[j].lpData); } snd_free(bufstate); return NULL; } bufstate->whdr[i].dwUser = bufstate->whdr[i].dwLoops = 0; //idrk, what's that bufstate->whdr[i].dwFlags = WHDR_DONE; } bufstate->pollee = 0; bufstate->posinbuffer = 0; if (snd->u.audio.protocol == SND_REALTIME){ bufstate->sync_buffer = 0; bufstate->prev_time = timeGetTime(); bufstate->sync_time = bufstate->prev_time - (long)(2 * 1000 * snd->u.audio.latency + .5); } return (void *) bufstate; } void mm_error_handler(snd_type snd, MMRESULT mmerror, void (*fp)()) { char err[MAXERRORLENGTH]; MMRESULT errnum; if (snd->write_flag == SND_READ) { errnum = waveInGetErrorText(mmerror, err, MAXERRORLENGTH); } else { errnum = waveOutGetErrorText(mmerror, err, MAXERRORLENGTH); } if (MMSYSERR_NOERROR != errnum) { switch (errnum) { case MMSYSERR_BADERRNUM: (*fp)("Specified error number is out of range."); case MMSYSERR_NODRIVER: (*fp)("No device driver is present."); case MMSYSERR_NOMEM: (*fp)("Unable to allocate or lock memory."); } } else (*fp)(err); } int numofbits(long tested) { int r = 0; for (; tested; tested = tested >> 1){ r = r + (tested & 1); } return r; } int audio_dev(snd_type snd, char *name, UINT *device) { UINT i, numofdev; MMRESULT er; WAVEOUTCAPS outspec; WAVEINCAPS inspec; char *devname; numofdev = (snd->write_flag == SND_READ ? waveInGetNumDevs() : waveOutGetNumDevs()); if (numofdev <= 0) { snd_fail("There is no device at all."); return !SND_SUCCESS; } for (i = 0; i < numofdev; i++) { if (snd->write_flag == SND_READ) { er = waveInGetDevCaps(i, &inspec, sizeof(WAVEINCAPS)); devname = inspec.szPname; } else { er = waveOutGetDevCaps(i, &outspec, sizeof(WAVEOUTCAPS)); devname = outspec.szPname; } if (er) { mm_error_handler(snd, er, snd_fail); return !SND_SUCCESS; } if (strcmp(name, devname) == 0) { /* printf("Device found: %s\n", devicespec.szPname); */ *device = i; return SND_SUCCESS; } } snd_warn("There is no matching device, let's use an available one."); *device = WAVE_MAPPER; return SND_SUCCESS; } snd_fns_node mmsystem_dictionary = { audio_poll, audio_read, audio_write, audio_open, audio_close, audio_reset, audio_flush }; void snd_init() { snd_add_device("MMSystem", "default", &mmsystem_dictionary); } nyquist-3.05/snd/sndlinux.h0000644000175000000620000000063710144436365015000 0ustar stevestaff/* sndlinux.h -- system-specific definitions */ #ifndef LINUX #define LINUX #endif typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflicts if already defined: */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/snd/sndrs6k.h0000644000175000000620000000205110144436365014516 0ustar stevestaff/* sndsystem.h -- system-specific definitions */ /* NOTES: you need a different sndswitches.h for each implementation, so this is a separate file. Things you need to define here: 1) Either UNIX, WIN32, or MACINTOSH should be defined. 2) Either the following function declaration: void snd_fail(char *msg); or #define snd_fail(msg) ... 3) typedef FASTFLOAT to be either a double or a float, whichever computes faster (PowerPCs are faster at double math than float math) 4) typedef MEMFLOAT to be how you would store a sample in memory (this should normally be float) 5) min() must be defined (either a macro or a function) 6) max() must be defined (either a macro or a function) */ #define UNIX 1 void snd_fail(char *msg); typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflict with Windows */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/snd/wxsnd.cpp0000644000175000000620000000266610144436365014636 0ustar stevestaff/* * wxWindows port of snd library * * Dominic Mazzoni */ // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/file.h" #include "wxsnd.h" extern "C" { void snd_fail(char *msg) { wxMessageBox(msg); } int wxsnd_open(char *fname, int mode) { wxFile *f = new wxFile(); if (mode == O_RDONLY) f->Open(fname, wxFile::read); else f->Open(fname, wxFile::read_write); if (!f->IsOpened()) return 0; return (int)f; } int wxsnd_creat(char *fname, int perms) { wxFile *f = new wxFile(); f->Create(fname); if (!f->IsOpened()) return 0; return (int)f; } int wxsnd_lseek(int file, int offset, int param) { wxFile *f = (wxFile *)file; if (param == L_SET) f->Seek(offset, wxFromStart); else if (param == L_INCR) f->Seek(offset, wxFromCurrent); else f->Seek(offset, wxFromEnd); return offset; } int wxsnd_read(int fp, char *data, int len) { wxFile *f = (wxFile *)fp; return f->Read(data, len); } int wxsnd_write(int fp, char *data, int len) { wxFile *f = (wxFile *)fp; return f->Write(data, len); } int wxsnd_close(int fp) { wxFile *f = (wxFile *)fp; if (f) delete f; return 1; } long wxsnd_getfilelen(int fp) { wxFile *f = (wxFile *)fp; return f->Length(); } }; nyquist-3.05/snd/audiowin32.h0000644000175000000620000000333710144436365015120 0ustar stevestaff#include "windows.h" #include "mmsystem.h" #ifdef __cplusplus extern "C" { #endif /* #define audio_read audio_process #define audio_write audio_process */ #define Audio_out_min_buffersize 2 * 4096 //in samples #define max_srate_dev 1.1 //maximum deviation from the expected nominal sample_rate. this is some // device dependent number, the device won't play back faster than max_srate_dev*srate //there may be a need for minimums in separate units, like in samples (as above), in ms, ... typedef struct { union { HWAVEIN h_in; HWAVEOUT h_out; } u; LPWAVEHDR whdr; int numofbuffers; int pollee; int posinbuffer; long sync_time; int sync_buffer; long prev_time; } buffer_state; /* #define waveGetDevCaps(a,b,c,d) ((a!=SND_READ) ? waveOutGetDevCaps((b),(c),(d)) : waveInGetDevCaps((b), (WAVEINCAPS *) (c),(d))) #define waveGetNumDevs(a) ((a!=SND_READ) ? waveOutGetNumDevs() : waveInGetNumDevs()) #define waveOpen(a,b,c,d,e,f,g) ((a!=SND_READ) ? waveOutOpen((b),(c),(d),(e),(f),(g)) : waveInOpen((b),(c),(d),(e),(f),(g))) #define waveReset(a,b) ((a!=SND_READ) ? waveOutReset((b)) : waveInReset((b))) #define waveClose(a,b) ((a!=SND_READ) ? waveOutClose((b)) : waveInClose((b))) #define waveUnprepareHeader(a,b,c,d) ((a!=SND_READ) ? waveOutUnprepareHeader((b),(c),(d)) : waveInUnprepareHeader((b),(c),(d))) #define wavePrepareHeader(a,b,c,d) ((a!=SND_READ) ? waveOutPrepareHeader((b),(c),(d)) : waveInPrepareHeader((b),(c),(d))) #define waveProcess(a,b,c,d) ((a!=SND_READ) ? waveOutWrite((b),(c),(d)) : waveInAddBuffer((b),(c),(d))) #define waveGetErrorText(a,b,c,d) ((a!=SND_READ) ? waveInGetErrorText((b),(c),(d)) : waveOutGetErrorText((b),(c),(d))) */ #ifdef __cplusplus } #endif nyquist-3.05/macproject/0002755000175000000620000000000011537433122014315 5ustar stevestaffnyquist-3.05/macproject/nyquistdata/0002755000175000000620000000000011537433122016663 5ustar stevestaffnyquist-3.05/macproject/nyquistdata/CWSettingsMacOS.stg0000644000175000000620000001074410144436365022330 0ustar stevestaffcool((MacOS Project SettingsExpanded Group ListProject Document SettingsCurrent TargetTarget List SettingsVCS SetupSourceSafe Pref.=R\ lr  Mac InteNe StuffFILEIg GE4q2MAINMAINHBARRSZ1VBR1xknoneGraphics$/   I3ct E#32MAINMAINHBARkRSZ1VBR1f1t PPC Projectg  PPC Projectxtrasq1tTarget Settings   (mstr(mstlmstn((mstiP@pref|@mtuspref7prefIMthdc.prefMBvprefLd prefML"bkpt bkpt` 0bkptpprefJ@mtusMthdchbkpt bkpt`0bkptpref4bkptnyquist-3.05/macproject/NyquistIcon0000644000175000000620000000006110144436365016525 0ustar stevestaffThis file's resource fork holds the Nyquist Icon.nyquist-3.05/macproject/unpacker/0002755000175000000620000000000011537433122016125 5ustar stevestaffnyquist-3.05/macproject/unpacker/unpackerdata/0002755000175000000620000000000011537433122020567 5ustar stevestaffnyquist-3.05/macproject/unpacker/unpackerdata/unpacker/0002755000175000000620000000000011537433122022377 5ustar stevestaffnyquist-3.05/macproject/unpacker/unpackerdata/unpacker/TargetDataMacOS.tdt0000644000175000000620000032575210144436365026040 0ustar stevestaffcool(5MacOS Target Dataunpacker:Custom Keywordsunpacker:Access Pathsunpacker:Target Settingsunpacker:File Mappingsunpacker:Build Extrasunpacker:Debugger Targetunpacker:68K CodeGenunpacker:68K Disassemblerunpacker:68K Global Optimizerunpacker:68K Linkerunpacker:68K Projectunpacker:C/C++ Compilerunpacker:C/C++ Warningsunpacker:CFM68Kunpacker:MacOS Merge Panelunpacker:Pascal Compilerunpacker:Pascal Warningsunpacker:PPC CodeGenunpacker:PPC Disassemblerunpacker:PPC Global Optimizerunpacker:PPC Linkerunpacker:PPC PEFunpacker:PPC Projectunpacker:PPCAsm Panelunpacker:Rez Compiler/H_u   4D_x.  Lib Import PPCBalloon HelpMW C/C++ PPCGameCode ConverterFlex PreprocessorMW Pascal PPCRezPPCAsmBison PreprocessorXCOFF Import PPCPEF Import PPCMSL C++.PPC.Lib:BinMSL C.PPC.LibInterfaceLib:Libraries:MacOS CommonMathLibMSL RuntimePPC.Lib:Libraries:Runtime:Runtime PPCMSL SIOUX.PPC.Libunpacker.cconvert.cswitches.hswlogic.hFiles.h:Headers:Universal HeadersMacTypes.hConditionalMacros.hMixedMode.hOSUtils.hMacMemory.hPatches.hDateTimeUtils.hFinder.hQuickdraw.hQuickdrawText.hEvents.hScript.hIntlResources.hcext.hconvert.hstring.h:MSL Common:Public Includescstringansi_parms.hmslGlobals.hansi_prefix.mac.h:MSL Mac:Public Includesos_enum.hsize_t.hnull.hcstddefstdio.hcstdioeof.hva_list.hcwctype)<N\`g z .9:DOYa| !"#$%&'()%*/+8,T-\.i/v0123456789: +0-/()46,9!7%"' .31 #$&25*8   !"#$%&'  !"#$%&'  !#%'&$" @ @ @@@@ @,@1:@:** i(@(   ɭLcunpackerU'LMWOBPPC IIe8MWOBPPC MMWOBPPC :MWOBPPC I b early_eof early_eofdir_isvaliddirdir_isvaliddir X_mkdir_mkdir b make_path make_path 8mainmainlput_runput_run unpack_ascii unpack_ascii unpack_binary unpack_binary dir_separatorZh pauseflaglconvertconvert@@:@:::misc:@:::cmt::::sys:mac::Metrowerks Standard Library:MSL Precompiled Header:@:Metrowerks Standard Library:MSL C:@:Metrowerks Standard Library:MSL C++:@:MacOS Support:@:MacOS PPC Linkerunpacker Console:NoneMMPr@TEXT.lFlex PreprocessorTEXT.yBison PreprocessorJava LinkerAPPL`Appl`COkMW JavaClssMW JavaJjrf.jrfMWCD`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.htmlTEXT.javaMW JavaTEXT.lFlex PreprocessorTEXT.mfTEXT.rRezTEXT.yBison PreprocessorZIP MW Java@ZipFMW Javadocu`rsrc`.classMW Java.jar@.zipMW JavaMacOS 68K Linker APPL`Appl`MMLBLib Import 68KMPLFLib Import 68KMWCD`OBJ MPW Import 68KPLob`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ 68KTEXT.lFlex PreprocessorTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.ppuMW Pascal 68KTEXT.rRezTEXT.segTEXT.yBison Preprocessordocu`rsrc`shlbPEF Import 68KstubPEF Import 68K.docP.rsrc`MacOS Merge APPL`Appl`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.lFlex PreprocessorTEXT.rRezTEXT.yBison Preprocessorrsrc`shlbMacOS PPC LinkerAPPL`Appl`MMLBLib Import PPCMPLFLib Import PPCMWCD`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ PPCTEXT.c++MW C/C++ PPCTEXT.ccMW C/C++ PPCTEXT.cpMW C/C++ PPCTEXT.cppMW C/C++ PPCTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ PPCTEXT.lFlex PreprocessorTEXT.pMW Pascal PPCTEXT.pasMW Pascal PPCTEXT.pchMW C/C++ PPCTEXT.pch++MW C/C++ PPCTEXT.ppuMW Pascal PPCTEXT.rRezTEXT.sPPCAsmTEXT.yBison PreprocessorXCOFXCOFF Import PPCdocu`rsrc`shlbPEF Import PPCstubPEF Import PPC.docPMC LinkerCLUS@MMLBLib Import 68KMPLFLib Import 68KOBJ MPW Import 68KTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.clsMC Class CompilerTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.defTEXT.docTEXT.hTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.tsWin32 x86 LinkerTEXT.cMW C/C++ x86TEXT.c++MW C/C++ x86TEXT.ccMW C/C++ x86TEXT.cpMW C/C++ x86TEXT.cppMW C/C++ x86TEXT.defTEXT.gcGameCode Converter@TEXT.hMW C/C++ x86TEXT.lFlex PreprocessorTEXT.pMW Pascal x86TEXT.pasMW Pascal x86TEXT.pchMW C/C++ x86TEXT.pch++MW C/C++ x86TEXT.ppuMW Pascal x86TEXT.rcMW WinRCTEXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc Std C Console 68K????APPLX????U { __start Merge Out????APPLDLGXckidProjWSPC__sta__startunpackernsole PPC????APPL@X????P'CODE' 'DATA' 'PICT' o o    oorrVri^x !r"r#$r%<&r'r(Q o o$r%<Vri^x !r"r&r'r#(Qrro      !"#$%&'()**++--..//00 22!33"44#55$66%77&88'99(:: D0000000000000000000 MPLFCWIE88M  (8 MPLFCWIE88IIe  (8 stubMPS '' (' stubMPS '' (' MPLFCWIE9f9f:  (9f MPLFCWIE9 9 I   (9 TEXTCWIEoo   (oTEXTCWIEoo  (o TEXTCWIEooh  ( TEXTCWIEooh  ( TEXTCWIE(  ( TEXTCWIE(  ( TEXTCWIE  (  (TEXTCWIE(  (TEXTCWIE(  ( TEXTCWIE(  (!TEXTCWIE(  ("TEXTCWIE(  (#TEXTCWIE(  ($TEXTCWIE(  (%TEXTCWIE(  (&TEXTCWIE(  ('TEXTCWIE(  ((TEXTCWIE(  ()TEXTCWIEooh  (*TEXTCWIEooh  (+TEXTCWIErrh  (-TEXTCWIErr( (.TEXTCWIEV̲V(  (/TEXTCWIErr(  (0 TEXTCWIEi^xi^x(  ( 2TEXTCWIEDZ(  (!3TEXTCWIErr(  ("4TEXTCWIErr(  (#5TEXTCWIE胱( ($6TEXTCWIErrh  (%7TEXTCWIE<<( (&8TEXTCWIErr(  ('9TEXTCWIErr(  ((:TEXTCWIEQQ( (POWRMNP EgEzEr Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er  Er  Er  Er  Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er  Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er !Er "Er #Er $Er %Er &Er 'Er (Er )Er *Er +Er ,Er -Er .Er /Er 0Er 1Er 2Er 3Er 4Er 5Er 6Er 7Er 8Er 9Er :Er ;Er Er ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Eh)InterfaceLibATEventWideNegateKLMGetLastSPExtraLMSetUTableBaseLMGetSPATalkB SetScriptQDPatchAddressZoomWindowLMSetKbdLasteDirCreate.GetEntryUsageGetItemMarkYSetFScaleDisableGetMyZoneSetComponentRefconSPBPauseRecordingLMGetDSAlertTabSndSoundManagerVersionzHiliteWindowPBRenameSyncGetTrapVectorPBHGetVolParmsSyncSetControlColorSetResourceSizeDisableWUTimeELMSetPrintErrDebuggerGetMaxqSetSoundVolEditionHasFormat#HSetFInfoLMGetPaintWhite7RGB2HSL}InitGrafoFSpCatMovePBDTGetCommentAsyncSetScriptRecoverHandleSysCrsrDevButtonOpYRestoreEntriesFTActivate@CMListenLMGetSPATalkAHidePaletteWindowsControl'LMSetCPUFlag LMSetMMU32BitGetFSQHdrCMResetLMSetSysMapHndlSFindSInfoRecPtr%TMSetUserDataGetPortNameFromProcessSerialNumberwGetStandardFormatsTSMMenuSelectPBSetFInfoAsyncSectRgnLocalToGlobalgetmenuitemtextpt2rectCallComponentFunctionWithStoragesetmenuitemtextLMGetFCBSPtr,PBHRstFLockSyncPBDeleteFileIDRefSyncDisposeGWorldCRMGetIndToolNameHomeResFile{PBStatusImmedopendriverMenuChoice8LMSetGrayRgnLMSetWidthPtrRestoreForevPBHSetVolAsyncpRGB2CMYAGetToolboxTrapAddressGetNextProcess%LMGetEventQueueLMGetABusVarsPLMGetCurApName ScreenResHGetFInfoPBRstFLockSyncClosePolymLGetSelectPmForeColorWTMMenuLMGetScrapStategetfontnameaModemStatus{WideDivide#ASPCloseAll7PPCAcceptSyncPurgeSpacePBCatSearchAsyncGDeviceChangedFlushVolHSV2RGBCEraseRoundRectInvertPoly-Pixel2Char)newcontrolGetItemStylegDMIsMirroringOnLMSetTheZoneGetEditionOpenerProctTempTopMem%LMGetSPFontLMSetTimeDBRADMRemoveNotifyProcIUMagStringLMGetHiliteModeZShutDwnStart.LMSetROMFont0LMGetDefltStackPPCCloseSyncPDeleteMenuGetMemFragment)PBStatusAsyncPt2RectLMSetApplScratchcLMGetScrDmpEnboBeginUpdate\PBMakeFSSpecSyncequalstringGetWindowPicRandomGetProcessSerialNumberFromPortNameLMSetSoundLevel}AEGetParamPtrSCSIRBlindGetComponentVersion PrSetError|DeferUserFnFlashMenuBareequalptQDMEnableDisplayApplicationZone^CrsrDevButtonUpGetTextServiceLanguage~PBDeleteSync8IUCompPStringappendmenuFix2FracGetLastEditionContainerUsedGetOSDefaultUPBShareAsyncIPCListPortsSyncLMGetHeapEndTEGetStyleHandleYAEGetCoercionHandlermaddresourceCMActivateInitGDeviceNLMSetROMBaseLMGetTheGDevicetPBSetFVersAsyncFCMClosedMIDISetOffsetTimeInsTimeFfinddialogitemPrDrvrDCEMakeDataExecutable CrsrDevDoubleTimeiEraseOvalGetScriptLanguageSupportMLMGetANumberStdOvalOpenRgnVInstallFrameRoundRectSPBOpenDevicePBOpenRFAsyncSysBreakPBGetForeignPrivsSyncLMSetBufTgDate3CompactDictionaryClipAboveGetPatternPBOpenWDAsyncLMGetSoundBaseNewEmptyHandleSys`LMSetRndSeedPGetRequestAllocCursorlSerStatusiudatepstringSetPaletteUpdateshReplaceText!paramtextLMSetSPAlarmlLMGetHWCfgFlags7PBReadImmedCharacterByteTypeTMSetupFilterdDMDisposeDisplayBackColorLMGetDeskPatternHMGetBalloons,IPCListPortsAsynczLMGetTERecalDeleteUserIdentityTMGetToolNamePMgrVersionGetWDInfoTGetScriptAEInstallSpecialHandlerPBDTGetPathmNewWindow\PRelRspCBSlotVRemoveVPixMap32BitWritePartialResourceColor2IndexDMCheckDisplayModeDMRemoveDisplayDeleteTSMDocument_GetItemIconnewmenuPBGetFPosAsyncaPBDTResetAsyncCopyRgnNewPtrSysClearnewdialogLMGetScrapName;MIDISignOutCreateResFileOLMSetDeskCPatHStyledLineBreakSCSIMsgOutARGB2HSVGetIconSuiteSReadInfoLMGetTimeSCSIDBxinsertmenuitemPBExchangeFilesSync*HMBalloonRectExitToShellGetVCBQHdrLMGetLo3BytesStripDiacriticsAEResumeTheCurrentEvent?AEInstallEventHandlerCMIntlToEnglishVLMSetWordRedraw;LMSetSPValidRGetResourcePBOpenDFSyncJLMGetSaveUpdateSetTimeout.IdleUpdateGet1IndType PBCloseWDSyncActivatePalette'LoadIconCacheLsetdialogitemtext%InitCTBUtilities^Eject@HSetFLock SetToolTrapAddressCalcMaskGetScrapPBUnmountVolwMIDISignInBLMGetTheZonenewcolordialogLMGetMenuHookFTGetVersionSCSIMsgIn&SetResPurgeLMGetCrsrBusyKPBShareSyncSetMenuFlashWLSetCell\ejectInvertRgngInvertRect^HLockHiHMRemoveBalloonzDisposeIconSuiteMPBCloseWDAsyncCMRemoveSearchWideBitShift(ValidRectAEInteractWithUseropenresfileuCRMGetIndResourceDSeedCFillStringToFormatRecIntlScriptComponentSetTarget$FracSinrPBDTCloseDownDragControl PBSetVInfoAsync SndDisposeChannelPBReadAsyncDrawMenuBar_OpenComponentUncaptureComponentAESuspendTheCurrentEventPenModeIndex2ColorGetMCInfo:InitTSMAwareApplication/TESetScrapLengthLMGetGhostWindowCrsrDevDisposeDeviceLMSetCurApRefNum HRstFLockClipRectRetrievePictInfoiSetPortBitsCMGetUserData\DisableIdleWGetCursorHCreateResFileGetColorkIULDateStringAHideControlSCSIReadGetAliasInfo MIDIGetClientsBackPataBackPixPatODMSetDisplayComponentHSetRBitiPAttachPHCrsrDevMovebLGetCellCopyPixPatSNextSRsrcGetHandleSizeLMSetMinusOneTEStylePasteLMSetHeapEndHideDialogItemLMGetKbdLastPBHMapIDSyncLMGetMemTopFixDiv{LockMemoryGetNewCWindowBSetScriptVariablehSetDialogItemLMSetMBarHook4GetPictureCGetNodeAddress:DMSetGDeviceTableclothMoveHHiTEInsertAEGetAttributeDescLMSetSPConfig8LMGetSPClikCaret0KillPolySelectWindowPBSetVInfoSync0BlockMoveYLaunchDeskAccessoryQLAPRmvATQEnableItemPBCreateFileIDRefAsyncSetEventMaskGetFrontServiceWindowSPBGetDeviceInfo PNSendRequestsMoveControlwDrawControlsSLMGetBufTgFFlgTMCountTermKeysDBGetErrGetPaletteUpdates_MenuKeyfSysEnvirons8AEPutDescLMGetCPUFlagIPPCStartAsync^HUnlockjPBHGetLogInInfoAsyncLMSetSPVolCtlReadEditionPLMSetFCBSPtrMaxApplZoneSetIntlResourceAEGetSpecialHandler^SReadLongFixMul:CautionAlertAESizeOfAttribute8LMSetJFetchTMGetProcIDLMGetGrayRgnCountMItemsEOpenDefaultComponentFontToScriptTextFaceStandardNBPGetSoundHeaderOffsetSUpdateSRTTLMGetCurDeactive2IsATPOpen!GetApplLimitLMSetQDColorsJGetPixMapInfoNBPSetNTELMGetResumeProckopenrfperm5Debugger68k;addptStdBits5getdialogitemtext[LMGetPortBUseFreeMemClearMenuBardFix2Long$GetCPUSpeedFTAbortSetMCInfo8CallComponentFunction|SetCursorInitCPort TMSetupXCleanupPBHOpenAsyncSetPixelsStatePGetIconFromSuitepEAttachPHGetMainDevicenewwindowGPrOpenLMGetSPValidAERemoveCoercionHandlerPBHCreateSyncDeactivateTSMDocumentPrCloseoRestoreBackGetClip8StdTxMeasLMGetDragPatternNewPtrSys5LMGetFinderNameStandardGetFile!PBDTFlushAsynclsetcell|TMGetTermEnvironsSysErrorLMGetRndSeedQDialogSelectPBCatSearchSyncoRecordPictInfoWideAdd-IsRegisteredSectionHasDepthALMSetMemTopjLMGetSPAlarmNewDialogLMSetTopMenuItemPaintOvalPrOpenDocDisposeMenuLMSetTERecalWideShiftUpdateGWorldPRemoveNamewColorBitLineToTMActivateLMSetJournalRefDMRegisterNotifyProcGetNextDevice1LMGetMenuListlgetcellPBHGetVInfoAsyncInitiateTextServiceGetWMgrPortFillOvalPOpenSktGetIconCacheProcDMEndConfigureDisplaysQgetfnumIEAddMultipAEGetInteractionAllowedCRMRealToLocalIDTEDisposeGetFInfogLMSetMemErrfDoVBLTaskvGetMenuHandleInvalMenuBarGetPixPatBTextServiceEventFSpOpenDFGetControlMinimumxTextModeSetEntryUsage:LNextCellGetVInfoLMGetUTableBaseLMSetDSAlertTabTGetBridgeAddress5NewControlCRMReleaseResourceTempNewHandle\PBCloseImmedjFTNewFixTextServiceCloseServiceWindowiultimestringSndDoImmediateGetNextFONDFramePolyLMSetCurPageOptionAssociateSectionDMAddDisplayCRMInstallLMGetDeskCPatGetSharedLibraryDBGetSessionNumPtrAndHandLMSetSCCRdNSetPaletteLAPAddATQInvertArcUpperText5LMGetSPPortAVGetTextServiceMenu8ActivateTSMDocumentLMSetScrapStateSPBBytesToMillisecondsOffsetRectLMSetHiliteModeSetFInfoIULangOrderLMSetLo3Bytes6LMGetSPPortBNSetControlMinimum GetNewMBar GetNamedResource;CloseEditionUShowControlLMSetTimeSCCDBUpperStringFPPCEndSyncMIDIWakeUpNBPExtract'GetPageStateATPUnloadPBCreateAsyncstuffhexTextServiceMenuSelect9PrPicFileCMDefaultTMEnglishToIntl_GetMBarHeight`GetResAttrsSndRecordToFileInsetRgn5FreeMemSys[GetIconLMSetDefltStackLMGetDSAlertRectLMSetACountGetNewPaletteAppendMenufsdeletepInitCRMUseResFileCaptureComponentUCharWidthLMGetTEScrpHandle!LDelRowTESetWordBreak)CRMGetCRMVersionDisposePixMapTMGetErrorStringAllowPurgePixels3GetControlValueCallEditionOpenerProcCloseWDPtInRectLMGetSoundLevelPBSetVolAsyncECrsrDevMoveToFTSetupPreflightjSetDepthUseInputWindowSetItemMarkLMSetSPATalkBLTMGetIndTermKey LMGetCurActivate7PBSetEOFSyncVAFPCommandGetSoundVolLMSetTheGDevice3GetBackColorLCellSizeLMGetPrintErrDebuggerUnlockMemoryAECountItems4MIDIGetOffsetTimeiLMGetMenuDisablewDMGetFirstScreenDevice>getvinfojLMGetWidthTabHandleNewHandleClearBitOr9GetNewWindow0FSDeletesetwtitleSetEOFUnpackBitsPBDTOpenInformeCallFormatIOProcVSndStartFilePlayLMSetSPATalkACMAbort=getfinfoInitDBPackLoadResourceSaveBackTMDoTermKeyjERdCancelpLMSetResErrLMSetMenuFlashCMDisposeSetToolboxTrapAddressGetDefaultUserCMGetConnEnvironsDTInstalliGetIntlResourceTableLMGetMMU32BitcLMGetMemErrSizeControlLMGetGZMoveHndCRMGetIndex,FTGetProcIDnPortSize5TMGetUserDataPostHighLevelEventFix2SmallFract|LMSetSCCWrCheckUpdatesAERemoveSpecialHandler)Rename'PBHSetFLockSyncSetStdProcsLMSetHWCfgFlags|SetADBInfoFrac2XSPBSignOutDeviceFSpDeleteDrawTextsSetScriptManagerVariableNewIconSuiteDMDisableDisplaySystemMenuPBDirCreateSync~PBLockRangeAsyncSExecTEGetStyleEPBHGetVolAsync]PBHGetFInfoSync!AllocContig$LMGetWidthPtrtLMSetABusVarsSCopyPixMapMGetPaletteGetIntlResource)MIDIConnectTimeSetOriginALMGetScrVResLMSetTimeSCSIDBVTrackBoxPBSetFLockSyncTESetAlignmentEntry2Index&FindServiceWindowBCMChooseULMSetVCBQHdrsfgetfile!KeyScriptsetfinfoTextWidthLMGetCaretTimeLMGetScrapHandle~testcontrolLMGetACountPBHOpenRFAsyncInsertSRTRecbPrintCopyrightjHMGetMenuResIDExtendedToStringSDeleteSRTRecptinrectPBUnshareSyncLMGetWordRedraw4iutimestringLMGetROMFont0TEToScrapResizePaletteTMGetSelectePBKillIOSyncAECreateAppleEventBTMDefaultERelStringAOnIgnoreModembLMGetTimeDBRASetMCEntriesSetStringDisposeRgnPlotCIconHandleCount1Types]PortChanged3Get1ResourceToggleDateLMSetJDTInstallFSRead0LMSetDlgFont\PBGetVolMountInfoIsMetricLMGetAuxWinHeadSystemClick5LMSetDeviceListFillCOvalKillPicture_DragTheRgnLMGetBufTgFBkNum>iutimepstringStdComment SPBSignInDevice`CRMGet1ResourcePBOpenRFSyncITESetStyleTPBHSetFInfoAsyncACrsrDevUnitsPerInch5LMGetBootDrive)LMSetScrapSizeLMSetSaveUpdateGetDCtlEntry"RecoverHandleOpenPortMoveICrsrDevButtonDown4LMSetScratch20RegisterComponentResourceFileLMSetTEScrpHandleLMGetSCCWrSFindStructHMIsBalloonPBGetCatInfoAsyncTESetSelectHideCursorComp6to1=InfoScrapgCRMGetHeaderPBDTRemoveCommentAsyncLMSetVIAGetWTitlebSCSIGetlcellsizeSPBCloseDevice;LMGetQDColorsLMSetPortBUseTMSetupPreflightSFGetFileRLMGetGNEFilterPBVolumeMountlFracMulBDiskEjectWSetEmptyRgn|TEScrapHandleLMSetSPPortAAnimateEntry`NewHandlep2cstrgGetSubTableCrsrDevSetButtons~SetStdCProcsOffsetPoly0SPutPRAMRecASPGetStatus PrDrvrCloseLongSecondsToDateQStdLineTEPinScrollLMSetSPPortBAESetTheCurrentEventMIDIPollDBGetItemppinrect2GetEditionFormatMarkLMSetDAStringsHClrRBitDetachResourceShowHideBPGetAppleTalkInfoqGetControlMaximumnPrintDefaultFSMakeFSSpecRGetCTSeedPBDTGetCommentSyncHoldMemoryCMGetToolName8Long2FixInsertMenuItemCTab2PaletteAEGetNthDescDisposeControl3SerSetBrkAEDisposeDescCMSetupFilterCMIOKillSetDialogCancelItemMIDIGetRefConmDILoadIDelay.AEGetEventHandlerAESizeOfParam]PBGetVInfoAsyncPBFlushFileAsyncPrJobInitRestoreDeviceClutKFTReceiveLCRMGetToolNamedResourcePBDTRemoveAPPLSyncLMGetOldStructureFindSymbolTMEventSetHandleSizeBuildBDSIsfpputfile.LMGetCurJTOffsetSCSISelect1EWriteHSetVolStillDownlnewSerSetBuf9RealColorFracDiv-LClrCellTickCountSaveForeSetFLockCompactMem"GetDialogItemALMGetCurMapVshieldcursorLMGetTimecreate`PBExchangeFilesAsyncLMSetDABeeper9AEPutAttributePtrMIDIGetTCFormatiLwrTextYFrameRect%MIDIGetPortNamelShowCursorOpenXPP`TempInsertROMMapqunmountvolProtectEntryJFTSetupPostflight`CRMSearchOLLastClickeGetScriptVariable4RecordPixMapInfoMIDIUnConnectDataFracSqrtLMSetDSErrCodeSPBSetDeviceInfoZMakeIconCachehPinRectPBSetCatInfoSyncSetControlActionLSizekHiliteControlTMSetupSetupstdlinePurgeMemSysQCRMReleaseRFPKillSendReqDebuggerPollSetDialogTracksCursorCloseTextServicePBDTGetIconInfoSyncDMIDIStopTimePBRenameAsync+GetGDevice3LMSetWidthListHandPtrZone9PPCOpenAsyncInsXTime0InsertRecordToDictionarymStripTextCreate3PBCloseAsyncGetDefFontSize|GetDiskFragmentPGetMenuShieldCursor>CloseWindowJPlotIconIDLMSetTimeLMGetFractEnableFSpOpenRFCMGetVersionURstFLock"TopMemIDebuggerLockMemoryUpdateResFile@InvalRgnSectRect!LMSetMenuListDisposePtr7LAddColumnStatusPBFlushVolSyncGetDeviceListDIVerify2FindScriptRundGetDialogItemText-SetGWorldSetControlMaximumOpenPolyGet1NamedResourceWPostEventShutDwnRemoveEPBRstFLockAsyncSetPortPixLMSetScrVResPPCAcceptAsync:GetScriptQDPatchAddress*UnionRgnSGetBlockMIDISetRefConSndAddModifierCSCSICmdSetPalettePlotIconSuiteSPlotCIconOpenSlotGoToPublisherSectionPrimeTimePAddResponseAEProcessAppleEventBatteryStatussLMGetApplLimitEnableIdleSetMenuItemTextcLRectLMSetMenuHookLMGetVCBQHdrPPCCloseAsyncAEGetNthPtrkLMSetResumeProcShowPenGetGrayAEPutParamPtr SInitSRsrcTableLMSetFinderName5AddPtLMSetCrsrBusyOpenEditionMIDIAddPortAlertCharTypeqlrectgetvolCMGetProcID+X2FracsSetComponentInstanceErrorSCSIRegisterBusFracCos:SCSIResetDisposeRoutineDescriptordrawstringInitProcMenuTMSetSelection%SetWTitleeSetVolGetKeys GetSpecificHighLevelEventCharToPixelLMGetDlgFontTestDeviceAttributeCloseDictionaryCRMParseCAPSResourcePBDeleteAsyncFindWordHBitMapToRegionUIsDialogEventInitMenusYCRMGetToolResourceaNewSubscriberDialogCMSetUserDataRemoveResourceDelCompPBOffLineCrsrDevNewDevicePPCWriteSyncDrawNewSysBreakFunc\trackcontrolGetComponentInstanceA5%TMGetTMVersionMatchAliaspErrorSoundLComp3to1MeasureJustCMPBWriteOpenRFPermLMGetMinusOneOpenPicturelsetselectUnique1ID AEPutParamDescPPCReadSyncGetNewDialogLMGetSFSaveDiskRCustomGetFileCAERemoveEventHandler{setstringLMSetToolScratchSetA5:TruncTextGetCaretTimeOpenCPortPBGetUGEntryAsyncStringToDate LMGetMBarHookPBGetEOFSyncAEDeleteItemSTESetText DisposeCCursorReserveMemSysCRMRemovewDMSetMainDisplayCRMGetNamedResourceLMGetSPConfigLoadScrapYLMSetAtMenuBottomGetGrayRgn8SetEditionOpenerProcSCSIStatLMSetGZRootHndFTIntlToEnglishnumtostring9GetGWorld9FindRecordByIndexInDictionaryGetAlertStagesetflockShutDwnInstallDialogCutLMSetCurMapPKillGetReqPBDTRemoveAPPLAsyncPBEjectvInvertColorbCountComponentsNCMPBReadGetADBInfoLMGetSPVolCtlGetPixelPBHDeleteAsyncLMGetDefVCBPtrCTabChangedPBDTSetCommentAsyncStdPutPicQDErrorkrstflockFillParseTableResolveAliasFileEnterSupervisorModeDebuggerGetMaskTableLine}lclrcellHCreateSetDefaultStartupLMGetAtMenuBottomLMGetJournalRefHMGetIndHelpMsgTECalText IUStringOrderLMSetOldStructuregPPCInit4TEGetTexterelstring`TrackControlDisableItemPPageFaultFatalIShortenDITLkGetControlActionAPaintBehind$FillCRoundRectjDrvrInstallAddResourceLMSetScrHResxGetIndPatternAEGetParamDesc!DiffRgnSetGrowZoneSReadDrvrNameGetPenStateCMGetCMVersionGetFontInfojCMClearSearchCopyMaskSetDialogItemText{LMGetMinStackGetMCEntrysubptLMGetTheMenupNewStringPBGetForeignPrivsAsync;StdPolyGetTimeIULTimeStringPBSetForeignPrivsSyncdNewGestaltFindNextComponent ErasePolySetTextServiceCursorRectInIconIDFInitQueuePPCStartSyncCrsrDevButtonsLMSetJStashInitZoneGetSuiteLabelLMGetSdVolumeGetItemCmdLMGetIntlSpecGetStdFilterProc8SetSysBeepVolumeUnlockMemoryyLMSetROM85draggrayrgnaSetDefaultComponentDisposeCTableGetControlVariantzPConfirmNameASPCloseSessionqBOff8FSpSetFInfoPaintRect{AEInstallCoercionHandlerpLockMemoryContiguousPPCWriteAsyncpIUEqualPStringoUnionRectSIntRemovePBGetVolMountInfoSizeGetDefaultStartup`POpenATPSkt{OpenCPictureWaitNextEventPackBits{FrameRgneiucomppstring8SetTime>Frac2FixXorRgnSetTSMCursorLMGetTicksTEFromScrap FillRectzFSpExchangeFilesgSndPauseFilePlayCMValidate NewSubscriberExpDialogPBGetFCBInfoSyncEqualStringMGetCPixelSectionOptionsExpDialog^DebuggerExitTempMaxMemNSReadPRAMRecSNewPixPatGetResourceGetServiceListNewPublisherDialogPBGetVInfoSyncTESetStyleHandleDrawDialogPBCatMoveSyncqSetRect[TEInitPBSetEOFAsync|DMGetDisplayIDByGDeviceLMSetSysZoneLMGetApplScratchScalePtDragGrayRgnQStdArcXEraseArcDebugStrSPBGetRecordingStatusLMSetBufTgFFlgHSetCurrentA5FTSetConfigHOpenRFIconMethodToRgn=NewRoutineDescriptorChar2Pixel|InitFTUppercaseStripDiacriticsLMSetTicksTSMEventiuequalpstring NewPtrClearMIDIFlushlNewPictInfo]DBSendItemKGetMouseBuildDDPwdsLMSetCrsrThreshLMSetLastSPExtraLMGetROM85SRsrcInfoTEStyleInsert%PmBackColorDLMGetLastFONDcDMQDIsMirroringCapablewGetResInfoGGetIndSymbolBitSetNewTempScreenBufferGetIndString/OpColorAECreateList{PBResolveFileIDRefAsyncTruncStringFSpGetFInfoNewEmptyHandleShutDwnPowerComponentFunctionImplementedCopyDeepMask5PaintRoundRectDrawGrowIconFrontWindowSetResLoadPrOpenPageSecondsToDateuDeleteMenuItem>SetApplLimitLMSetDeskPatternLDisposePBDTDeleteAsync;AddIconToSuiteuDriveStatusGetFrontProcessLMSetOldContentZSetPortsInitUtilPBHSetDirAccessSyncELMGetMBarEnableLMSetSPKbdtGetPreserveGlyph ScriptOrder$PBSetForeignPrivsAsyncSInitPRAMRecs+PrValidateLGetCellDataLocationGetToolTrapAddress)PBCreateSyncGEmptyRgnFSClosejHMGetFontSizeLMSetROMMapInsertOSGetSRsrcPtrLMSetSaveVisRgnlTECustomHook[LMSetDTQueueCLMGetWMgrPortlInitDateCacheGetGWorldPixMapForeColor>PBCloseSyncShowWindowoPPCOpenSyncSetApplBase_DisposePictInfoLMSetScrnBase?PBGetFCBInfoAsynchReadLocationGetMaxResourceSizeLMGetBufTgFNumStringToNumAdibadmountSFindBigDevBasekFindControlTMResumeGetLabel\PtInRgnSndGetSysBeepStateSetFrontProcessYGetPortFSpCreateResFile[LUpdate!TextSizeSectionOptionsDialog0OpenWD>stringtonumPBDirCreateAsyncPBUnshareAsyncMIDIStartTimeLMSetKeyThresh:MIDIGetClientIcon:LMGetCurPageOptionDisposeCIconCloseResFile5GetWRefConjHNoPurgeTEDeactivateSPBMillisecondsToBytes_VisibleLengthCopyPaletteLMSetHiliteRGBSPrPurgePBDTGetInfoSyncDMGetDisplayMgrA5WorldBlockMoveDataKGetDictionaryInformation;AddCompDBGetConnInfoOffsetRgnDeleteMCEntriesInitFontsVGetCWMgrPortLMSetSysFontFam3PBOpenDFAsyncLMGetJStashgSlotVInstall\LActivate*InitCursorFTGetConfigtFSpDirCreate'LMSetSysResNameLMGetJVBLTask3HMScanTemplateItemsjFTStartPBWriteAsyncDeltaPointGetFontNameeldrawbSSearchSRTHMExtractHelpMsg*DisposeWindowflushvolWriteEditionPBHSetFLockAsynciLMSetCurDirStoreAppendResMenuDBInstallResultHandlerDebuggerEnteruPaintArc9LMGetFSFCBLenGetEditionInfoOLDrawDMUnmirrorDeviceInvertOvalTENumStylesMIDISetRunRateLMGetSEvtEnbPBGetFInfoSyncPBHGetVolSynczPBGetFPosSyncPrDrvrOpenfGetZoneListLMGetROMMapInsertHOpenLMGetSPKbdoc2pstr(CMDisposeIOPBEmptyHandleDateToSecondsRGBForeColorFTValidatehLMGetKbdTypegetnamedresource3LMSetMBarHeightFillArcAEGetAttributePtrPaintOne\CMStatusIUDatePStringSizeWindowASPAbortOSSelectDialogItemTextLMGetCurPitch^IUMagIDPString(FTChooseAOffSndSetSysBeepStateLMSetTopMapHndlSCardChangedPSetWinColorStdGetPicStripUpperTextSetCPixelKeyTranslateBitShiftCountResourcesInitSDeclMgrKsfputfilebChangedResourceInitCMPBAllocContigAsyncOpenRF+IUTimeString GetSysBeepVolumePBDTGetInfoAsyncTEUseStyleScrapTPKillNBP}TEFeatureFlag6LMSetWindowList8SOffsetDataPFTSetupSetupPrClosePageFSpCreatePBMountVolLMSetKeyRepThreshPBDTGetAPPLAsyncLMGetDragHookHOpenDFQLMGetTEDoTextMoveWindowPrStlInit PBHRenameSyncLMSetBufPtrsfpgetfileTESetClickLoopmGetComponentInstanceStorageQCRMIsDriverOpenGrowWindowSetResFileAttrsValidRgnCloseRgnLMGetSysMapFSpRstFLockTMSetupItem|PBHOpenRFDenySync HGetStateCharExtraLMGetExtStsDTCMEvent LowercaseTexttGetIconCacheDataZCMOpenClearIntlResourceCacheLMGetSysZoneLMSetSoundPtrLMSetGhostWindow DragWindowHTEGetStyleScrapHandleSleepQRemoveLMGetCurApRefNumMHideWindowLMSetSysEvtMask'SFindSRsrcPtrTMSetRefConnLMGetKeyRepThresh\SReadPBSizeSReadFHeadernewstringNewCWindow:FSpRenamehPBHSetDirAccessAsyncDMGetDisplayComponentOpenTextService{ReadPartialResourceATPLoadbMaxBlockTMValidate5LMSetMainDevice>stdtextSetResInfoLGetPixBaseAddreSFPutFileUpdateAliasQHMGetBalloonWindowjDisposeDialogDBDisposeQueryIUScriptOrderIUEqualStringCompactMemSysPBDTAddAPPLAsyncLMGetWidthListHandLMGetBufPtr*PBWriteImmed&GetIndResourceyIsOutlineLAddToCellEGetAuxWinDMGetNextMirroredDeviceNewAliasMinimal0TMGetLineIGetFNumLMSetSysMapFlushFontsCloseCPortLMSetDragPatternSCSIActionReleaseResource!DMMirrorDevicesIconIDToRgnPBGetWDInfoSyncInitWindowsPBSetFPosAsyncIUTextOrder`PopUpMenuSelect"CMWriteNQDMiscLMSetDeskHookyWideMultiply{StdFilterProcNewHandleSysClear1ForEachIconDoGetPixelsStatePPCBrowserHDeleteHidePenTEIdleTEGetScrapLengthSndDispVersionAReadDateTimeZRectInRgn&DMMoveDisplay=MIDISetSyncwPBAllocateAsyncjfindwindowLMSetScrapNameRegisterComponentResourceIUMagIDStringFTEnglishToIntlstringwidthbGetDateTimeGetComponentInstanceError'FMSwapFontNewSectionHMGetHelpMenuHandleSetIconCacheDataUPBDTGetIconAsyncLMGetDTQueueGetFormatOrderPBDTResetSynckADBReInitMaxMemSysCloseComponent>LMGetMenuCInfoPPCReadAsyncFCRMFindCommunicationsUDrawJustifiedHMGetDialogResIDResErrorPBHOpenSyncSetOutlinePreferredLMGetScrapCount2InvalRectILMGetCurrentA5$ValidDatekFTGetUserDataTSetDeskCPat\SetRectRgnInstallExceptionHandler}MIDIGetSyncLMGetTESysJust:TEScrollrDelSearchRealFontXDisposeScreenBufferDisposeZoneFindDialogItem FindRecordInDictionaryzLMGetTopMenuItemLMGetDoubleTimefsrenamePrGeneralCMGetConfigKMoveToSetWRefConDMCanMirrorNowGrafDeviceLAddRowBitTst8CustomPutFileUpdateDialogPBGetUGEntrySyncTMPaint%FindFolder1Count1ResourcesLMGetATalkHk2TMScroll^GestaltCountDITLlBitAndIsCmdCharWakeUpProcessLMSetGNEFilterRSFindDevBaseSCSIWrite)TerminateTextServiceFillCRgnqPBHMapNameAsync{FTEventATPKillAllGetReqaTMResetSLMSetWMgrPortPSetSelfSend~GetDefaultOutputVolume>TMRemoveSearchSCSISelAtnGetPtrSizePBUnlockRangeAsyncTempDisposeHandleaSetSuiteLabel4PPCEndAsyncMoreMastersTHMSetFontSizeDMSetDisplayModePBOpenImmedDisposePaletteTEAutoView}GetComponentInfolASPUserCommandLMGetScrnBaseSerResetfLMSetWidthTabHandle#LMGetDAStringsmFillRoundRectCRMGet1IndResourceSubPtPlotSICNHandleSGetTypeSRsrcTETextBoxPixPatChangedpNGetTrapAddressPlotIconHandle'CountComponentInstancesNewHandleSysyFTDefaultPPCInformSyncCRMReserveRFSetupSndHeaderPicCommentKHPurgeDMGetDeskRegionPWriteLAP#SerClrBrkNoPurgePixelsCloseDeskAccDraw1ControlMACEVersiongetresinfoqPBResolveFileIDRefSyncEventAvailDBState0DeviceLoopLMSetJVBLTaskCheckItemHiliteColorLMSetToExtFSEGetInfotrackboxSndManagerStatusAEPutArrayPRegisterNameSetOSTrapAddressQPrStlDialogTMResizehSetSysDirectionDMSetComponentAnimateTicksLMGetDSErrCodeCharByteDMapPt^GetIndTypeiLMSetFSFCBLen}PBSetFPosSyncSGetSRsrcAESend4SGetDriverPNewPaletteMeasureJustifiedFTGetRefConGetIndADB!EqualRgnMakeRGBPatIZeroScrapGetNewControlLDBRemoveResultHandlerHGetMaxDeviceGetCCursorfGetOSTrapAddressLMGetSPPrintLMGetCrsrThreshTrackGoAwayNewRgnEDisposeGDeviceOLMSetCurPitchSndChannelStatusLMSetSysFontSizeMapRectLMSetDSAlertRectLMSetLvl2DTFTSetupXCleanupaSReadWordAddDriveSetControlTitleTMClearStopAlertLMGetAppParmHandleFillCPolyLAutoScrollcCRMReleaseToolResourceLMGetVIAVTEClick?PBDTAddAPPLSync-PBHRenameAsyncFSOpenTESelViewTMGetConfigReplaceGestaltDBStartQueryInitializeDictionaryTMClickZTempHUnlockPPBAllocateSyncMIDISetClRefConkLMGetOneOneRsrcZoneInit UniqueID InitDialogsPlotIconMethod!PBFlushVolAsyncLMSetSPPrintSetDialogDefaultItemP2CStr?LMGetSysEvtMaskCMSetupPostflightReallocateHandlewGetFPoscHGetVol\SetCCursorPBControlSyncFillCRectIntlTokenizeSerGetBuf*DialogDeleteGetComponentRefcon,CMPBIOKillPgrowwindowSPBRecordToFileKPBDTGetIconSyncCatMovefsopenbLNewMapPolyRmvTime iuldatestring(DIBadMount?StdRgnySetSRsrcStateFEraseRgnLMSetCurJTOffset~SameProcessDBKillyLMGetMainDeviceLMGetDeskHookSLMSetFractEnablefAECreateDescPBHOpenDenyAsyncPBDTGetAPPLSync`CMSetupPreflightInitApplZoneSetDateTime4ResolveAlias5newcwindowDMDrawDesktopRegionASPGetParmsActivateTextServiceExp1to6jPBWriteSyncOSetZoneNLDelColumnGetVideoDefault9CMMenuLMGetTimeSCCDBmSetPtrSizeSetIconCacheProcWideSubtractTEGetPoint+FSpOpenResFile TENew%UpdateControlsqFrameArcSGetCStringGetZone IUMagPStringteclickExp1to3WDialogPasteWFTSetUserDataCMGetRefConEndUpdate/MenuSelect=PBHOpenDenySync.AcceptHighLevelEventSndPlayDoubleBufferMovePortTo9DrawChar?PlotIconLMGetResErrProcBitNot+MaxMem]TMGetCursorDialogCopyHOpenResFileNumToStringmsetresinfoPBGetCatInfoSyncUFTExecCloseComponentResFile8CurResFileNPBDTGetIconInfoAsyncCallComponentUPPLMSetATalkHk2=get1namedresourcebGetAuxiliaryControlRecordZStringToTimePBDTAddIconSync GetWUTime\PWriteDDPPtrToXHandsetvolxMIDISetClientName5DrawJustLMSetDragHookDMResolveDisplayComponentsALMSetTEDoTextPBLockRangeSyncResetAlertStageTMClearSearchSLMGetJIODoneKillIOPenSizeGetWVariantMemErrorPBDTRemoveCommentSyncFillRgnCRMLocalToRealID6TEKey TMAddSearch^PaintRgnMSysBeep DBUnGetItemAESetInteractionAllowed#WaitMouseUpGetDblTimeCMBreakInsertIntlResMenuFix2XtInsertResMenuASetMenuBar LMSetTmpResLoadParseTableaSendAEFromTSMComponent0SetEntryColor4SetFontLockSCSIKillXPTLMSetExtStsDTISetVideoDefaultqPBOpenAsyncTEPasteOSEventAvailNewAliasNGetResFileAttrshHMGetFont IUCompStringLMGetMenuFlash`LMGetResLoad4DMDrawDesktopRectPurgeMemLMGetSoundPtrEDetachPHStandardPutFile}WriteResourcePCloseSktSPBGetIndexedDevicePBSetVolSyncLMSetGZMoveHnd\AOnEReadMIDIGetPortInfoOutlineMetrics&PtrToHandAGetVol7InlineGetHandleSizeTMSetConfigCMAcceptDisposeHandleUHMSetFontopendeskacc;HLockLMSetOneOnePBDTDeleteSyncCPBHSetFInfoSynctCreateEditionContainerFileGetCurrentProcessIDMGetNextAnimateTimelDelegateComponentCallNewGDeviceGetDrvQHdrhGetLocalZonesLMSetDrvQHdrTEUpdateLMSetScrapCountLockPixelsTMStreambPPCRejectAsyncGetNextEvent1HiliteText+LMSetBootDrivevLMGetScratch20(MIDIUnConnectTimeLMGetScrapSizeSPBResumeRecordingTempFreeMemCMSetupItemOpenDeskAcc@PRelTCBMIDIWritePacketiudatestringWLMSetDoubleTimeWDMBlockMirroring?NewPtrDMBeginConfigureDisplaysInitPackEr ?Er @Er AEr BEr CEr DEr EEr FEr GEr HEr IEr JEr KEr LEr MEr NEr OEr PEr QEr REr SEr TEr UEr VEr WEr XEr YEr ZEr [Er \Er ]Er ^Er _Er `Er aEr bEr cEr dEr eEr fEr gEr hEr iEr jEr kEr lEr mEr nEr oEr pEr qEr rEr sEr tEr uEr vEr wEr xEr yEr zEr {Er |Er }Er ~Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er Er EhMathLib6__isfinitedtanlAlog1platanllogcadd2dec2fnearbyintl&pow8__isfinitefdec2numlHtruncl_FE_DFL_ENVbhypot/frexpcompoundcconj"logb__isfiniteceilnum2deccopysignl7__signbittanhroundtolfesetexceptatanh9log10l"fegetexcept ctanh7cLog9csquareFx80told&tanhlcopysign4gammal__inf.catandec2num-catanhatanhlfesetroundqxdivcatanroundtollstr2decremquo ldexplcxpwryccosldtox80num2declceillcosrintlogblQfrexplfabslx80todbmodffminyfesetenvhypotlexp2Kcasin8dec2lasin0powlfeupdateenvdec2strremainderlL__signbitf,loglwpilog2l+rinttolpcsubfloorlwrelationJ__signbitd6fmodfmaxferaiseexceptcargZfdimfdimldtox80fmaxlfloor)remainderZrelationlnextafterflog2erflexpm1lscalbl_annuitySfabsnextafterd ldexprinttollcxpwreFgammafeholdexcept?dec2sroundlnlog10}erfcl`asinhltruncnanlmodff expl"atan2lcepwrynearbyintlog1pktansinhl>fegetroundctanS__fpclassifyfVacoshllgammaVfetestexceptysinlasinlcacoshcxpwriacoscoshlfeclearexceptcacos!sqrtQ__fpclassifydexp2lxccoshcabsnextafterlcsinhsinEcoshscsqrtWacoshsqrtlcmulexpusinhatan2asinhmodflnanf3nan|fminlo__fpclassifyg__isnandcexproundcsinhcdivKrandomx__isnan__isnormal__isnormaldfegetenverfc"remquollgammali__isnanfexpm1]scalb)erflrintl__isnormalfcasinhIcosl[acoslPOWRX"zj g(EgEn(bUnexpected end of file while unpacking EkX b|!b8cH`8`H`H8!@|N A< .early_eofEt EtEuEu$EkL|!pa8aH`8aH`8`8888aBH`8aBH`8a<888H`|x4,@ 8`H$4,Ab4H`8`8!|N A._mkdirEu,Eu8EuLEtxEuEn bCould not create %s En bCreated directory %s $Ek b|!|~xxHl8a8xH`8|P8a8|8a8H,@88a8H,Ax88H`H4x88H`;x8:H`|x(@X8!P|N A .make_pathEt Et$Eu8EuTEudEuxEuEuEn" Usage: unpack input-file 0En# r En$ Couldn't open |%s| En% wEn& wbEk'0 |!!lb8alH`|zx,A 8|H`8`H`alc8H`|}x(@08|dxlH`8`H`H;; 8a8H`87$8a9H`8a9H`8|t,#@;8a9xH`|x(@H8a9H8a9xH`|x(@$8|dx89H`8`H`8|t,!@xx89H`H$8|t,#@xxH`(AxH`8a88xH`(@xH`8`X8!P|!N A.mainEt$EtEu( Et"8Eu$8$HWö>xH`x8H`,AH@(8((AW>$8$HW>xH`HW02;x8H`,AH@(8((AWĆ>$8$HWÆ>xH`x8H`,AH@(8((AW>$8$HW>xH`x8H`,AH@(8((AW>$8$HW>xH`Kx8H`,AH4}(8((A}$8$HxH`X8!P|N A.unpack_binaryEuV,Eu^pEuEuVEu^EuEuVEu^`EutEuVEuWEuVEu^8EuLEuVdEuWEuVEuWEuV$EuWlEuV|EuWEuVEuWEuV0Eu^lEo aEv.EvbEo cEv-EvbEo dEvUEvbEo eEv'EvbEo fEvEvbEo gEvEvbEo hEvEvbEo iEvEvbEn]Ev]En\Ev\En[Ev[En$Ev$En"Ev"EnEvEnEvEnEvEnEvEoEvEobEhSYMHs y , I$e0{LX1pe| f 8<   9 O$ c4 @ X d l x ! L Wf8<  ( , 0 @ -P U` p  f f!8  , 4 D3PFhepyc!Oh 4#@LPrdhx-712gl3f84T$(XYZM,f3[4SZ  8<(DHg  >xP|WY\T4fZYY$|Tml'tKxh|oD@LlPT\  'ct $f(utT4Y`(F 89:;<=?@AB j5L67>CDEFGHhI Jh$K(L,M0N4O8P<Q@RDSH/3-@179.early_eof__files!.fprintfx.exit_.dir_isvaliddir.strcpy.c2pstrg.FSMakeFSSpec+.FSpOpenDF`.FSClosepath?refnumkspecFSSpecvRefNumparIDname5errfilename<@190._mkdir.FSpDirCreate.printfppQdirid@201 @202F.make_path.strchrfull_nameptrdirectoryd@225e@226f@227g@228h@229.main.ccommandB.fopen.strlenm.puts.convert.unpack_ascii.unpack_binary/.fclose.fgetsargcargvmfiletype~outfl_FILE!handleamodeopen_modeio_modebuffer_modefile_kindwfile_orientationbinary_iostateio_statefree_buffereoferrorchar_bufferchar_buffer_overflowDungetc_bufferIungetwc_buffervpositionbufferobuffer_size~buffer_ptrbuffer_lenbuffer_alignmentsaved_buffer_lenbuffer_posposition_procread_procwrite_procclose_proc8idle_procinfs.put_run.fwide.__put_charffccnn @281!@282"@283.__get_char.ungetcllunpack_binary~TOCunpack_asciiput_runmainmake_pathg_mkdirdir_isvaliddirearly_eofPOWRDPmEgEo:En/WARNING: %s has one of ":\" and may not port. En5 '/' should be used as directory separator. Ek |!!|~x"BbxH`|xH||t,:A||t,\@8}xxH`8}dxH`,APx8H`,AH4}(8((A}$8$HxH`;,@\xH`|xH||;,@8:xH`|xH ||t,/@ |;,@h8!`|!N Ad.convertEtEtEtEt Et$Eu,EuhEuxEu Eu EuEuEmEo  EvEvEoEvEoEvEnEvEnEvEoEvEoEhSYMH(<N\pTW~,"<:D[Pkk f /5*dir_separator{@24|@25.convert=pauseflag__files.strlen!.fprintf.fwide.__get_charfilenameii1convert~TOCɭP(mstr(mstlmstn(mstr (mstl(mstnpHmtfl(mtfs(mtfp(mtfd(mtdcmtacxprefV_prefUw.2 prefU4>*lprefU^prefV6_prefUaprefU[a prefU`a prefUƋ aprefU{ aprefVYN b>prefVLQ c5prefUJ cCprefV }ebprefVEe8prefVge prefUeprefU~e prefUe prefUEeprefU&fprefVQgprefVBzhr.prefUyh prefU(mstimtfi>mtsip (msti<objdXobjdtobjdobjdHobjdmd robjdy&objdbrwsobjdbrwsj depgjmtbinyquist-3.05/macproject/unpacker/unpackerdata/CWSettingsMacOS.stg0000644000175000000620000000711010144436365024225 0ustar stevestaffcool(  @ MacOS Project SettingsExpanded Group ListProject Document SettingsCurrent TargetTarget List SettingsVCS SetupSourceSafe Pref.=R\ lr Er Er pGRUPSourcesFILEFILEGVmDebugger TargetgnoneGraphics$/(mstr(mstlmstn((mstiP@prefprefpref Npref A pref 'vpref & >pref RGnyquist-3.05/macproject/unpacker/unpacker.mcp0000644000175000000620000026171210144436365020452 0ustar stevestaffcool(Z\RCodeWarrior Project48& |pr67'+) #=>B<?@A"042[E(,* $!%/HJKYDIG.L- MC;&:9  NO PQWRST8UV153FZX\`\ ROOTGRUPSourcesFILEFILEGRUPANSI LibrariesFILE FILEFILE GRUP Mac LibrariesFILE FILE FILE o{o{o{o{o{o{o{o{o{o{JH݌```       JavaClasses.jarZIP MWZP D ɭ [\U'L Merge Out????APPLDLGXckidProjWSPCJavaClasses.zipJavaClasses.zip#CshPf0 AddPinRaPoiMIte tRes' MenuI tConk Cont oseCillCShowHideMove$GetCGetCRjzeColiteGetCtCTitlVainCt%Ctl Elue gl SeTestDragTrac Dra!"nded5#istT$r%&'()  **+B,d$`-}./shP001 Add2PinR3aPoi64MIteX5tRest6Menu7tCon8Cont9oseC:illC;Show#GetC}?etCR@zeCoABGetCCtCTiDtlVa8EinCtTFCtl qGlue Hl SeITestJDragKTrac L Dra "M ;N ^O P Q R S T U 1V OW mXKeys Y ZImpo [PW I \KBa ]lpM "^68K C_l 68 b`F Im a bnded cist dTarg ect D fSett 8g Set PheSaf ni@ j k l m n` 'o L Dp%s fqg: r sANSI t 68k uKeyw vI Cowk:Ac1xhsAMyole jzet S{ANSI| 68k}ppin~ConsBuil0ANSTr4Wz5Ux?]|Be @c*Hg -Po +Jj"B]5Wv6Us -Ng#Ec:Xu5Sp .Gf  % C f     !!8!U!s!!!!""3"P"n"""" #!#'"#F##d$#%#&#'#($)$#*$F+$c,$}-$.$/$0$1%2%53%S4%z5%6%7%8&9&1:&Y;&{<&=&>&?'@',A'OB'sC'D'E'F( G(,H(TI(vJ(K(L(M)N)&O)IP)kQ)R)S)T)U*V*0W*NX*qY*Z*[*\*]+^+&_+D`+ca+}b+c+d+e,f,&g,Ch,]i,{j,k,l,m,n-o-3p-Uq-tr-s-t-u-v.w.3x.Qy.rz.{.|.}.~//"/F/h////00 0?0^000001161X1111122,2B2[2p22222333,3E3^3s33333389:;47<=>36?@ABCDEFGHIJKL5MNOPVWXYRUZ[\QT]^_`abcdefghijSklmn~z}y|{$%&' #()*"+,-./012345678!9:;<`abc\_def[^ghijklmnopqrst]uvwx  BCDE>AFGH=@IJKLMNOPQRSTUV?WXYZtuvwpsxyzor{|}~q !"#$%&'()*+,-./012     !M\(J7OlFS`lin r dbjd*objd@O\jobqptlace=g !"#$$1%F& ['t(0)@*Jav+.zip,-./0ut!142F3Y4k5APPL~6GXck7PC89 :;%<=>*?=@bABCDEFG HI$J4KCLRM\NiOyPQRSTUVWXYZ [\kidProjWSPCJavaClasses.zipMSIEInternet ExplorerIexplore.exe a.out@U {MSIEInternet ExplorerIexplore.exe a.out@U {ANSI Console MultiFirst Segment:a.outLib Import 68KMPW Import 68KBalloon HelpMW C/C++ 68KMW Pascal 68KRezPEF Import 68KANSI Console 68kHelloWorld.cMSL C.68K Fa(4i_8d).LibMSL Runtime68K.LibMathLib68K Fa(4i/8d).LibMSL C++.68K Fa(4i_8d).LibMacOS.libMSL SIOUX.68K.LibANSI Console PPC:ANSI Console PPC.outLib Import PPCMW C/C++ PPCMW Pascal PPCPPCAsmXCOFF Import PPCPEF Import PPCMSL C++.PPC.LibMSL C.PPC.LibInterfaceLibMathLibMSL RuntimePPC.LibMSL SIOUX.PPC.Lib:ANSI Console 68k.outANSI Console FAT:Merge Out:ANSI Console FAT.outANSI Console 68k.outANSI Console PPC.outMathLib68K Fa(4i_8d).Lib:ANSI C Console 68kANSI C Console 68k:ANSI C Console PPCANSI C Console PPC:ANSI C Console FATANSI C Console FATGameCode ConverterFlex PreprocessorBison Preprocessor:Std C Console 68KStd C Console 68K:Std C Console PPCStd C Console PPC:Std C Console FATStd C Console FAT68K Standard C Console68K Std C ConsolePPC Std C ConsoleMSL C.68K (2i).LibMSL C++.68K (2i).LibMathLib68K (2i).Lib:HelloWorld.c:Bin:MSL C++.PPC.Lib:Bin:MSL C.PPC.Lib:Libraries:MacOS Common:InterfaceLib:Libraries:MacOS Common:MathLib:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib:Bin:MSL SIOUX.PPC.LibMacOS PPC LinkerCustom KeywordsAccess PathsTarget SettingsFile MappingsBuild ExtrasDebugger TargetC/C++ CompilerC/C++ WarningsFTP PanelIR OptimizerPascal CompilerPascal WarningsPPC CodeGenPPC DisassemblerPPC LinkerPPC PEFPPC ProjectPPCAsm PanelRez CompilerPPC Global Optimizerunpacker.cconvert.cunpacker:unpacker@:@:::misc:@:::cmt::::sys:mac::Metrowerks Standard Library:MSL Precompiled Header:@:Metrowerks Standard Library:MSL C:@:Metrowerks Standard Library:MSL C++:@:MacOS Support:@:MacOS PPC Linkerunpacker Console: Std C Console 68K????APPLX????U {__start__sta__startunpackernsole PPC????APPL@X????P'CODE' 'DATA' 'PICT'td C Console:Java Output68K Std C Console:Java Project68K Std C Console:Java VM68K Std C Console:MacOS Merge Panel68K Std C Console:Pascal Compiler68K Std C Console:Pascal Warnings68K Std C Console:PPC CodeGen68K Std C Console:PPC Disassembler68K Std C Console:PPC Linker68K Std C Console:PPC PEF68K Std C Console:PPC Project68K Std C Console:PPCAsm Panel68K Std C Console:Rez Compiler68K Std C Console:WinRC Compiler68K Std C Console:x86 CodeGen68K Std C Console:x86 Linker68K Std C Console:x86 ProjectPPC Std C Console:Custom KeywordsPPC Std C Console:Access PathsPPC Std C Console:Target SettingsPPC Std C Console:File MappingsPPC Std C Console:Build ExtrasPPC Std C Console:68K CodeGenPPC Std C Console:68K DisassemblerPPC Std C Console:68K LinkerPPC Std C Console:68K ProjectPPC Std C Console:C/C++ CompilerPPC Std C Console:C/C++ WarningsPPC Std C Console:CFM68KPPC Std C Console:IR OptimizerPPC Std C Console:Java OutputPPC Std C Console:Java ProjectPPC Std C Console:Java VMPPC Std C Console:MacOS Merge PanelPPC Std C Console:Pascal CompilerPPC Std C Console:Pascal WarningsPPC Std C Console:PPC CodeGenPPC Std C Console:PPC DisassemblerPPC Std C Console:PPC LinkerPPC Std C Console:PPC PEFPPC Std C Console:PPC ProjectPPC Std C Console:PPCAsm PanelPPC Std C Console:Rez CompilerPPC Std C Console:WinRC CompilerPPC Std C Console:x86 CodeGenPPC Std C Console:x86 LinkerPPC Std C Console:x86 ProjectPPC Std C Console:Java LanguagePPC Std C Console:Debugger TargetPPC Std C Console:FTP PanelPPC Std C Console:JavaDoc ProjectPPC Std C Console:x86 Exceptions PanelPPC Std C Console:68K Global OptimizerPPC Std C Console:PPC Global OptimizerMSIEInternet ExplorerIexplore.exe a.out@U {ANSI Console MultiFirst Segment:a.outLib Import 68KMPW Import 68KBalloon HelpMW C/C++ 68KMW Pascal 68KRezPEF Import 68KANSI Console 68kHelloWorld.cMSL C.68K Fa(4i_8d).LibMSL Runtime68K.LibMathLib68K Fa(4i/8d).LibMSL C++.68K Fa(4i_8d).LibMacOS.libMSL SIOUX.68K.LibANSI Console PPC:ANSI Console PPC.outLib Import PPCMW C/C++ PPCMW Pascal PPCPPCAsmXCOFF Import PPCPEF Import PPCMSL C++.PPC.LibMSL C.PPC.LibInterfaceLibMathLibMSL RuntimePPC.LibMSL SIOUX.PPC.Lib:ANSI Console 68k.outANSI Console FAT:Merge Out:ANSI Console FAT.outANSI Console 68k.outANSI Console PPC.outMathLib68K Fa(4i_8d).Lib:ANSI C Console 68kANSI C Console 68k:ANSI C Console PPCANSI C Console PPC:ANSI C Console FATANSI C Console FATGameCode ConverterFlex PreprocessorBison Preprocessor:Std C Console 68KStd C Console 68K:Std C Console PPCStd C Console PPC:Std C Console FATStd C Console FAT68K Standard C Console68K Std C ConsolePPC Std C ConsoleMSL C.68K (2i).LibMSL C++.68K (2i).LibMathLib68K (2i).Lib:HelloWorld.c:Bin:MSL C++.PPC.Lib:Bin:MSL C.PPC.Lib:Libraries:MacOS Common:InterfaceLib:Libraries:MacOS Common:MathLib:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib:Bin:MSL SIOUX.PPC.LibMacOS PPC LinkerCustom KeywordsAccess PathsTarget SettingsFile MappingsBuild ExtrasDebugger TargetC/C++ CompilerC/C++ WarningsFTP PanelIR OptimizerPascal CompilerPascal WarningsPPC CodeGenPPC DisassemblerPPC LinkerPPC PEFPPC ProjectPPCAsm PanelRez CompilerPPC Global Optimizerunpacker.cconvert.c     YZZebugCPorortap DMap %ix NEisat Ct PeBacketPi eRGB!#"B#`$}% & '(*0+N,k-@. /012$F4b5@{6789:k;-<@k`ce NewGDevicosvice SetGDevice GetGDevice Colorndndex2Color InvertColor RealColoretable UpdatePixMap MakeITable AddarddComp SetClientID ProtectEntry sentry SetEntriesQDError SetWinCor uxWin SetCtlColoP aetNeP a Qpk`~_34P`|}a4{|}b34ANSI Console Multi:Custom KeywordsANSI Console Multi:Access PathsANSI Console Multi:Target SettingsANSI Console Multi:File MappingsANSI Console Multi:Build ExtrasANSI Console Multi:68K CodeGenANSI Console Multi:68K DisassemblerANSI Console Multi:68K LinkerANSI Console Multi:68K ProjectANSI Console Multi:C/C++ CompilerANSI Console Multi:C/C++ WarningsANSI Console Multi:CFM68KANSI Console Multi:IR OptimizerANSI Console Multi:Java OutputANSI Console Multi:Java ProjectANSI Console Multi:Java VMANSI Console Multi:MacOS Merge PanelANSI Console Multi:Pascal CompilerANSI Console Multi:Pascal WarningsANSI Console Multi:PPC CodeGenANSI Console Multi:PPC DisassemblerANSI Console Multi:PPC LinkerANSI Console Multi:PPC PEFANSI Console Multi:PPC ProjectANSI Console Multi:PPCAsm PanelANSI Console Multi:Rez CompilerANSI Console Multi:WinRC CompilerANSI Console Multi:x86 CodeGenANSI Console Multi:x86 LinkerANSI Console Multi:x86 ProjectProject File ListANSI Console 68k:Custom KeywordsANSI Console 68k:Access PathsANSI Console 68k:Target SettingsANSI Console 68k:File MappingsANSI Console 68k:Build ExtrasANSI Console 68k:68K CodeGenANSI Console 68k:68K DisassemblerANSI Console 68k:68K LinkerANSI Console 68k:68K ProjectANSI Console 68k:C/C++ CompilerANSI Console 68k:C/C++ WarningsANSI Console 68k:CFM68KANSI Console 68k:IR OptimizerANSI Console 68k:Java OutputANSI Console 68k:Java ProjectANSI Console 68k:Java VMANSI Console 68k:MacOS Merge PanelANSI Console 68k:Pascal CompilerANSI Console 68k:Pascal WarningsANSI Console 68k:PPC CodeGenANSI Console 68k:PPC DisassemblerANSI Console 68k:PPC LinkerANSI Console 68k:PPC PEFANSI Console 68k:PPC ProjectANSI Console 68k:PPCAsm PanelANSI Console 68k:Rez CompilerANSI Console 68k:WinRC CompilerANSI Console 68k:x86 CodeGenANSI Console 68k:x86 LinkerANSI Console 68k:x86 ProjectANSI Console PPC:Custom KeywordsANSI Console PPC:Access PathsANSI Console PPC:Target SettingsANSI Console PPC:File MappingsANSI Console PPC:Build ExtrasANSI Console PPC:68K CodeGenANSI Console PPC:68K DisassemblerANSI Console PPC:68K LinkerANSI Console PPC:68K ProjectANSI Console PPC:C/C++ CompilerANSI Console PPC:C/C++ WarningsANSI Console PPC:CFM68KANSI Console PPC:IR OptimizerANSI Console PPC:Java OutputANSI Console PPC:Java ProjectANSI Console PPC:Java VMANSI Console PPC:MacOS Merge PanelANSI Console PPC:Pascal CompilerANSI Console PPC:Pascal WarningsANSI Console PPC:PPC CodeGenANSI Console PPC:PPC DisassemblerANSI Console PPC:PPC LinkerANSI Console PPC:PPC PEFANSI Console PPC:PPC ProjectANSI Console PPC:PPCAsm PanelANSI Console PPC:Rez CompilerANSI Console PPC:WinRC CompilerANSI Console PPC:x86 CodeGenANSI Console PPC:x86 LinkerANSI Console PPC:x86 ProjectANSI Console FAT:Custom KeywordsANSI Console FAT:Access PathsANSI Console FAT:Target SettingsANSI Console FAT:File MappingsANSI Console FAT:Build ExtrasANSI Console FAT:68K CodeGenANSI Console FAT:68K DisassemblerANSI Console FAT:68K LinkerANSI Console FAT:68K ProjectANSI Console FAT:C/C++ CompilerANSI Console FAT:C/C++ WarningsANSI Console FAT:CFM68KANSI Console FAT:IR OptimizerANSI Console FAT:Java OutputANSI Console FAT:Java ProjectANSI Console FAT:Java VMANSI Console FAT:MacOS Merge PanelANSI Console FAT:Pascal CompilerANSI Console FAT:Pascal WarningsANSI Console FAT:PPC CodeGenANSI Console FAT:PPC DisassemblerANSI Console FAT:PPC LinkerANSI Console FAT:PPC PEFANSI Console FAT:PPC ProjectANSI Console FAT:PPCAsm PanelANSI Console FAT:Rez CompilerANSI Console FAT:WinRC CompilerANSI Console FAT:x86 CodeGenANSI Console FAT:x86 LinkerANSI Console FAT:x86 ProjectANSI C Console 68k:Custom KeywordsANSI C Console 68k:Access PathsANSI C Console 68k:Target SettingsANSI C Console 68k:File MappingsANSI C Console 68k:Build ExtrasANSI C Console 68k:68K CodeGenANSI C Console 68k:68K DisassemblerANSI C Console 68k:68K LinkerANSI C Console 68k:68K ProjectANSI C Console 68k:C/C++ CompilerANSI C Console 68k:C/C++ WarningsANSI C Console 68k:CFM68KANSI C Console 68k:IR OptimizerANSI C Console 68k:MacOS Merge PanelANSI C Console 68k:Pascal CompilerANSI C Console 68k:Pascal WarningsANSI C Console 68k:PPC CodeGenANSI C Console 68k:PPC DisassemblerANSI C Console 68k:PPC LinkerANSI C Console 68k:PPC PEFANSI C Console 68k:PPC ProjectANSI C Console 68k:PPCAsm PanelANSI C Console 68k:Rez CompilerANSI C Console PPC:Custom KeywordsANSI C Console PPC:Access PathsANSI C Console PPC:Target SettingsANSI C Console PPC:File MappingsANSI C Console PPC:Build ExtrasANSI C Console PPC:68K CodeGenANSI C Console PPC:68K DisassemblerANSI C Console PPC:68K LinkerANSI C Console PPC:68K ProjectANSI C Console PPC:C/C++ CompilerANSI C Console PPC:C/C++ WarningsANSI C Console PPC:CFM68KANSI C Console PPC:IR OptimizerANSI C Console PPC:MacOS Merge PanelANSI C Console PPC:Pascal CompilerANSI C Console PPC:Pascal WarningsANSI C Console PPC:PPC CodeGenANSI C Console PPC:PPC DisassemblerANSI C Console PPC:PPC LinkerANSI C Console PPC:PPC PEFANSI C Console PPC:PPC ProjectANSI C Console PPC:PPCAsm PanelANSI C Console PPC:Rez CompilerANSI C Console FAT:Custom KeywordsANSI C Console FAT:Access PathsANSI C Console FAT:Target SettingsANSI C Console FAT:File MappingsANSI C Console FAT:Build ExtrasANSI C Console FAT:68K CodeGenANSI C Console FAT:68K DisassemblerANSI C Console FAT:68K LinkerANSI C Console FAT:68K ProjectANSI C Console FAT:C/C++ CompilerANSI C Console FAT:C/C++ WarningsANSI C Console FAT:CFM68KANSI C Console FAT:IR OptimizerANSI C Console FAT:MacOS Merge PanelANSI C Console FAT:Pascal CompilerANSI C Console FAT:Pascal WarningsANSI C Console FAT:PPC CodeGenANSI C Console FAT:PPC DisassemblerANSI C Console FAT:PPC LinkerANSI C Console FAT:PPC PEFANSI C Console FAT:PPC ProjectANSI C Console FAT:PPCAsm PanelANSI C Console FAT:Rez CompilerANSI C Console 68k:Java OutputANSI C Console 68k:Java ProjectANSI C Console 68k:Java VMANSI C Console 68k:WinRC CompilerANSI C Console 68k:x86 CodeGenANSI C Console 68k:x86 LinkerANSI C Console 68k:x86 ProjectANSI C Console PPC:Java OutputANSI C Console PPC:Java ProjectANSI C Console PPC:Java VMANSI C Console PPC:WinRC CompilerANSI C Console PPC:x86 CodeGenANSI C Console PPC:x86 LinkerANSI C Console PPC:x86 ProjectANSI C Console FAT:Java OutputANSI C Console FAT:Java ProjectANSI C Console FAT:Java VMANSI C Console FAT:WinRC CompilerANSI C Console FAT:x86 CodeGenANSI C Console FAT:x86 LinkerANSI C Console FAT:x86 ProjectStd C Console 68K:Custom KeywordsStd C Console 68K:Access PathsStd C Console 68K:Target SettingsStd C Console 68K:File MappingsStd C Console 68K:Build ExtrasStd C Console 68K:Bison PanelStd C Console 68K:Flex PanelStd C Console 68K:68K CodeGenStd C Console 68K:68K DisassemblerStd C Console 68K:68K LinkerStd C Console 68K:68K ProjectStd C Console 68K:C/C++ CompilerStd C Console 68K:C/C++ WarningsStd C Console 68K:CFM68KStd C Console 68K:IR OptimizerStd C Console 68K:Java OutputStd C Console 68K:Java ProjectStd C Console 68K:Java VMStd C Console 68K:MacOS Merge PanelStd C Console 68K:Pascal CompilerStd C Console 68K:Pascal WarningsStd C Console 68K:PPC CodeGenStd C Console 68K:PPC DisassemblerStd C Console 68K:PPC LinkerStd C Console 68K:PPC PEFStd C Console 68K:PPC ProjectStd C Console 68K:PPCAsm PanelStd C Console 68K:Rez CompilerStd C Console 68K:WinRC CompilerStd C Console 68K:x86 CodeGenStd C Console 68K:x86 LinkerStd C Console 68K:x86 ProjectStd C Console PPC:Custom KeywordsStd C Console PPC:Access PathsStd C Console PPC:Target SettingsStd C Console PPC:File MappingsStd C Console PPC:Build ExtrasStd C Console PPC:Bison PanelStd C Console PPC:Flex PanelStd C Console PPC:68K CodeGenStd C Console PPC:68K DisassemblerStd C Console PPC:68K LinkerStd C Console PPC:68K ProjectStd C Console PPC:C/C++ CompilerStd C Console PPC:C/C++ WarningsStd C Console PPC:CFM68KStd C Console PPC:IR OptimizerStd C Console PPC:Java OutputStd C Console PPC:Java ProjectStd C Console PPC:Java VMStd C Console PPC:MacOS Merge PanelStd C Console PPC:Pascal CompilerStd C Console PPC:Pascal WarningsStd C Console PPC:PPC CodeGenStd C Console PPC:PPC DisassemblerStd C Console PPC:PPC LinkerStd C Console PPC:PPC PEFStd C Console PPC:PPC ProjectStd C Console PPC:PPCAsm PanelStd C Console PPC:Rez CompilerStd C Console PPC:WinRC CompilerStd C Console PPC:x86 CodeGenStd C Console PPC:x86 LinkerStd C Console PPC:x86 ProjectStd C Console FAT:Custom KeywordsStd C Console FAT:Access PathsStd C Console FAT:Target SettingsStd C Console FAT:File MappingsStd C Console FAT:Build ExtrasStd C Console FAT:Bison PanelStd C Console FAT:Flex PanelStd C Console FAT:68K CodeGenStd C Console FAT:68K DisassemblerStd C Console FAT:68K LinkerStd C Console FAT:68K ProjectStd C Console FAT:C/C++ CompilerStd C Console FAT:C/C++ WarningsStd C Console FAT:CFM68KStd C Console FAT:IR OptimizerStd C Console FAT:Java OutputStd C Console FAT:Java ProjectStd C Console FAT:Java VMStd C Console FAT:MacOS Merge PanelStd C Console FAT:Pascal CompilerStd C Console FAT:Pascal WarningsStd C Console FAT:PPC CodeGenStd C Console FAT:PPC DisassemblerStd C Console FAT:PPC LinkerStd C Console FAT:PPC PEFStd C Console FAT:PPC ProjectStd C Console FAT:PPCAsm PanelStd C Console FAT:Rez CompilerStd C Console FAT:WinRC CompilerStd C Console FAT:x86 CodeGenStd C Console FAT:x86 LinkerStd C Console FAT:x86 Project68K Standard C Console:Custom Keywords68K Standard C Console:Access Paths68K Standard C Console:Target Settings68K Standard C Console:File Mappings68K Standard C Console:Build Extras68K Standard C Console:68K CodeGen68K Standard C Console:68K Disassembler68K Standard C Console:68K Linker68K Standard C Console:68K Project68K Standard C Console:C/C++ Compiler68K Standard C Console:C/C++ Warnings68K Standard C Console:CFM68K68K Standard C Console:IR Optimizer68K Standard C Console:Java Output68K Standard C Console:Java Project68K Standard C Console:Java VM68K Standard C Console:MacOS Merge Panel68K Standard C Console:Pascal Compiler68K Standard C Console:Pascal Warnings68K Standard C Console:PPC CodeGen68K Standard C Console:PPC Disassembler68K Standard C Console:PPC Linker68K Standard C Console:PPC PEF68K Standard C Console:PPC Project68K Standard C Console:PPCAsm Panel68K Standard C Console:Rez Compiler68K Standard C Console:WinRC Compiler68K Standard C Console:x86 CodeGen68K Standard C Console:x86 Linker68K Standard C Console:x86 Project68K Std C Console:Custom Keywords68K Std C Console:Access Paths68K Std C Console:Target Settings68K Std C Console:File Mappings68K Std C Console:Build Extras68K Std C Console:68K CodeGen68K Std C Console:68K Disassembler68K Std C Console:68K Linker68K Std C Console:68K Project68K Std C Console:C/C++ Compiler68K Std C Console:C/C++ Warnings68K Std C Console:CFM68K68K Std C Console:IR Optimizer68K Std C Console:Java Output68K Std C Console:Java Project68K Std C Console:Java VM68K Std C Console:MacOS Merge Panel68K Std C Console:Pascal Compiler68K Std C Console:Pascal Warnings68K Std C Console:PPC CodeGen68K Std C Console:PPC Disassembler68K Std C Console:PPC Linker68K Std C Console:PPC PEF68K Std C Console:PPC Project68K Std C Console:PPCAsm Panel68K Std C Console:Rez Compiler68K Std C Console:WinRC Compiler68K Std C Console:x86 CodeGen68K Std C Console:x86 Linker68K Std C Console:x86 ProjectPPC Std C Console:Custom KeywordsPPC Std C Console:Access PathsPPC Std C Console:Target SettingsPPC Std C Console:File MappingsPPC Std C Console:Build ExtrasPPC Std C Console:68K CodeGenPPC Std C Console:68K DisassemblerPPC Std C Console:68K LinkerPPC Std C Console:68K ProjectPPC Std C Console:C/C++ CompilerPPC Std C Console:C/C++ WarningsPPC Std C Console:CFM68KPPC Std C Console:IR OptimizerPPC Std C Console:Java OutputPPC Std C Console:Java ProjectPPC Std C Console:Java VMPPC Std C Console:MacOS Merge PanelPPC Std C Console:Pascal CompilerPPC Std C Console:Pascal WarningsPPC Std C Console:PPC CodeGenPPC Std C Console:PPC DisassemblerPPC Std C Console:PPC LinkerPPC Std C Console:PPC PEFPPC Std C Console:PPC ProjectPPC Std C Console:PPCAsm PanelPPC Std C Console:Rez CompilerPPC Std C Console:WinRC CompilerPPC Std C Console:x86 CodeGenPPC Std C Console:x86 LinkerPPC Std C Console:x86 ProjectPPC Std C Console:Java LanguagePPC Std C Console:Debugger TargetPPC Std C Console:FTP PanelPPC Std C Console:JavaDoc ProjectPPC Std C Console:x86 Exceptions PanelPPC Std C Console:68K Global OptimizerPPC Std C Console:PPC Global Optimizerunpacker:Custom Keywordsunpacker:Access Pathsunpacker:Target Settingsunpacker:File Mappingsunpacker:Build Extrasunpacker:Debugger Targetunpacker:68K CodeGenunpacker:68K Disassemblerunpacker:68K Global Optimizerunpacker:68K Linkerunpacker:68K Projectunpacker:C/C++ Compilerunpacker:C/C++ Warningsunpacker:CFM68Kunpacker:MacOS Merge Panelunpacker:Pascal Compilerunpacker:Pascal Warningsunpacker:PPC CodeGenunpacker:PPC Disassemblerunpacker:PPC Global Optimizerunpacker:PPC Linkerunpacker:PPC PEFunpacker:PPC Projectunpacker:PPCAsm Panelunpacker:Rez CompilerXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc__startMSIEInternet ExplorerIexplore.exe/ uJIT@:u9up^J MENUbTargSTR#PPobRidLaeteSTR prefFlagTMPLvers Drop"hi _j, .( Q-5@J T__sta__startStd C Console PPC????APPL@X????P'CODE' 'DATA' 'PICT'%@,%G%Ht%x/CWPlugin_GetDropInName &DdropInName %H%H%I%I>Ht%H%I, %%H%IL%rX^CWPlugin_GetDisplayName "displayName %I%I%I%I>Ht%I%J #<%I%J$&CWPlugin_GetPanelList %C8%fvpanelList %J %J%J%JF>Ht%Jd%J w%Jd%JUUbCWPlugin_GetFamilyList%M %E<%familyList %K`%Kp%K%K%K>Ht%K<%K   {d%K<%KTCWPlugin_GetHelpInfo  %G vhelpInfo%el %L8p%LH%L`%L%Lp)&>Ht%L%L  L%F0%L%L%M&CWGetPluginRequest%L %*L context\%Mp%M%M %MP0request@ @%ML%M`ery %M0vers>Ht%L%M f6!|%L%M4 ACWDonePluginRequestQ %*%NP$,%N Q%}resultCode O%N8 O1n%NYO/<>Ht%M%Nl g"(%M%NNNVCWGetAPIVersion/ %* <%O$%M%N0H %O F%N/Ht%N%O@ $$%N%O`%K%CWGetIDEInfo %*%O%M%O %=L%O-4%%O%>Ht%O%P %o`%O%P4%CWGetCallbackOSError %*%P%M%P8O \%P%PM88>Ht%Pt%P %Pt%Q %XCWSetPluginOSError %* %Q%M%Qp$,%QH>Ht%QP%Q %Q!d%QP%Q؀CWGetProjectFileff %*%R%M%R8projectSpec  %Rd%R|%RHffff>Ht%R%R <%R%R33%m,CWGetTargetName %*%S`%M%S$ 33%S%SP&'LmaxLength%S|%S4ff>Ht%S%S $Q%S%S33%{CWGetOutputFileDirectory %*ff%T%M%T8ioutputFileDirectory  %Td%T33%TH>Ht%T%T QL%T%Tff33&)CWGetProjectFileCount %*%Up%M%U4 33\%U`ff%UDff>Ht%U%U E\%U%Uff& CWGetFileInfo %*%V4%M%Vff%Vp%433& checkFileLocation%V%VPff%bfileinfo33 %733%V%V%V33>Ht%U%V 33%U%Vff%{CWFindAndLoadFileff33 %*%W%M%WP33filename33 33%W%W|%W %.%V%W%W`>Ht%W0%W ff%7%W0%X &+t#CWGetFileTextffff %*%X%M%Xh  %X%0%X 33 %X%Y$ k%XwwtextLength"" %YP%X%Y %0H%Y@%Xx>Ht%XL%Yl ""%XL%Y&.<DCWReleaseFileTextww %*DD%Z(%M%Y  k%Z%Y>Ht%Y%ZD "0%Y%Zd&lCWGetSegmentInfo %*%[ %M%Z&V4whichsegment⾾%[P%ZPsegmentinfo %1%[(%[@%Z>Ht%Z%[l ,D%Z%[gCWGetOverlay1GroupsCount %*%\0%M%[ \%\ %\>Ht%[%\L l%[%\lCWGetOverlay1GroupInfo %*%]%M%\whichgroup%]X%\%|<zgroupinfo %2%]0%]H%\>Ht%\%]t ! %\%]%CWGetOverlay1Info %*%^ %M%]%^X%\%Dwhichoverlay%^%^<% @overlayinfo %3%^t%^%^>Ht%]%^ |%]%^ؖCWGetOverlay1FileInfo %*%_h%M%_<%_%\%_%^<whichoverlayfile{{{zz%_%_|||{ %4dvu%V%_rrww%_Lllqq>Ht%_%` }h%_%`(&GCWReportMessage %*%`%M%`msgRefyyy %4yy%a%`%`uuttline1tsss ss%aT%`%aoonn%line2 %a%a0%aDerrorlevel%a%ap%uerrorNumber|{%axx}}%`rrww>Ht%`h%a nmmm$%`h%allCWAlertji %*dc%b%M%bL``eemsg1_^^^] ^]%b%bx%bZZYYmsg2YXXXW XW%c%b%bNNSSmsg3SRRRQ LK%c\%b%c HHkk%msg4kjjji dc%c8%cL``ee%b\ZZ__>Ht%b8%cx VUUU"j%b8%cTTYYHt%c%dx UUU|%c%dTTYYKCWUserBreakPP %*PP%M%dLLLK%eFFFE>Ht%d%e <===%e>===>Ht%e|%fd 9988`%e|%f2111%<vCWStorePluginData2111 %*++%g%M%f--,,%g,%4((('%gX%BB %+AA%f %gH>===%f8777>Ht%f%gt 3322t%f%g2111CWGetPluginData,, %*,,%h%M%g((('%h8%4$$%ht%  %+ %hT%f %hd%h>Ht%g%h "{L%g%h %'CWSetModDate %*%iH%M%i ##  ##%it%0%i8 %i%7%idisGenerated%i %i >Ht%h%i ;@%h%i&WkCWAddProjectEntry %*%j%M%jD0123  BC%j %jp\]^_%j%ixyz{projectEntryInfo %<\%k%j%j %4%k%jT>Ht%j$%k0 3`%j$%kP%CWCreateNewTextDocument %*U%l$,%k)%vdocinfo %;T ;%k%k)@%k%Q>Ht%k%l M $2\%k%l@CWAllocateMemory %*%l%M%lH%m+isPermanent%mL%l `ptr% %m%m,%m<%l>Ht%l%mh %l%m%CWFreeMemory %*mP%n %M%m  %n<%m,%n%lD %m>Ht%m%nX %m%nxCWAllocMemHandle %*%o%M%n%o<%luseTempMemory0%o%o  %+&08!handle$ %oX%oh%o|%n>Ht%n%o 0%n%oCWFreeMemHandle %*o%p`%M%p$  %+%oh%pP%p4>Ht%p%p| "@@%p%p%q%|.CWGetMemHandleSize%q\ %*9%q8%M%p %+%qd%oh%q( q%qT%q %>Ht%p%q %r%p%q&  CWResizeMemHandle%r %*%r<%M%r/ N %+%rl%oh%r,%r\^newSize %rX%r%r>Ht%q%r %s`%q%rCWLockMemHandle76 %*l%s@%M%s %+sT%sp%oh%s0%smoveHi%u%s%s\ t %s78%m,%s%u%s>Ht%r%s .htm"%r%s%{`CWUnlockMemHandle% %*t\%t%M%tH%u %+/.%oh%tt%%tX>Ht%t(%t 8?%t(%t%u%`CWMacOSErrToCWResult%ut %*%u`%M%u$%%w5errud%uP%vD%u4>Ht%u%u| %u%u%v$DROPINPANELAPIVERSION_1%u%v%vD1DROPINPANELAPIVERSION_2w$%v%vP2L%DROPINPANELAPIVERSION_3%vT%v3%tDROPINPANELAPIVERSION_4/ %v%v4DROPINPANELAPIVERSION_5%v%w/5w %0DROPINPANELAPIVERSION_6wd0%w%w@6w& <DROPINPANELAPIVERSION_7L%wD%w|%w7DROPINPANELAPIVERSION,%w%wDROPINPANELAPIVERSION_7%xl5kBadPrefVersionw%w%xsion1000VwkMissingPrefErrl%x %x<%x|1001>Ht%xx%xJ;reqInitPaneld%x%x\%xDx,%x\%xxhtml&$reqTermPanel %y%x%xD`,%x%x%y<Ht%% *xmenu_CutJ%%%$G@%%&lmenu_Copy%%T%%>%%%\menu_Paste%%%<%%<%T&menu_Clear%%%%! 4%%q%Pmenu_SelectAll%%!%%E%,@enum$1266PBackendx86_c PanelFlags%0%x%%H%0%\ %%A(%%%AX%%%A%L%%A& Tpanelfamily%% %8%B0@dataversion%h% panelscope%%P&>Ht%%0<%usesStrictAPI%P%%%%%HsupportsByteSwapping%%@J%%%%T@enum$1267PBackendx86_c>Ht%%PZpanelScopeGlobal%%%l%T(%l%(panelScopeProject%%$%%T %%%<mpanelScopeTarget%,%%T L%%$%@enum$1268PBackendx86_c%pDummyDialog%t%%$)t%t%%%CWDialog %%b@%%/FCWPanelCallbacks%@%$8%%`%T%$%8N%%PanelParameterBlock%l%%$Ϩ%l%%%%ML?%@20  %$%%M?X` ]%T% +G)& targetfile%%| %<,o( %"%%lAV $p%originalPrefsWD%%%Z8 $*%currentPrefs*%H%%^ $%IfactoryPrefs@%p%%,b% &%%`Chf baseItems%%j%Tl&.P"EcanRevert%%n%#canFactory's%0%o%T%`%"|p%recompile%%Hq%&/relink%%xr'prefsKeyword%%t%L&0(GprefsDesc%%#%x,debugOn%L%%D-coldtargfile% %4%|.`callbacks3 %$%%|%d07reparse %%%<  1pdragref%$%% &,(3!dragrect%D%T% %T9dragmouse%ˌ%ވ%<%t:toEndian%%l %+ˌ;originalPrefsMemHandle%%%% %+ =currentPrefsMemHandle%d%h%%%D %+%>RfactoryPrefsMemHandle%%4%D%D%PanelParameterBlockPtr% %T%4|%%tPanelParamBlk%L%%% %[PanelParamBlkPtr%%(%8%X%%Lextern%% CWPanlAppendItems %d%d1ppb %%%%7ditlID'%% >Ht%%& uL%%8ACWPanlDrawPanelBox %%%%% % P%%!>Ht%x% % "%x%,%CWPanlShowItem %%%%%%,showIt%%%>Ht%l%!2%l% %CWPanlEnableItem % %%%%%7enableIt%d$juVersionKWRD Current=6CASE Version 5=5CASE Version 4=4CASE Version 3=3CASE Version 2=2CASE6KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGRegister coloringBFLGInline intrinsic functionsBFLG#Disable Optimizations for DebuggingBFLGInstruction SchedulingBFLGAWRDTarget ProcessorDWRDGeneric 80x86=0CASE Pentium=1CASE Pentium Pro=2CASE Pentium II=3CASEAMD K6=4CASEExtended Instruction SetDWRDNone=0CASEMMX=1CASE MMX + K6 3D=2CASEK6 3D=3CASEVectorize LoopsBFLGreservedFBYTKEYE5KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGRegister coloringBFLGInline intrinsic functionsBFLG#Disable Optimizations for DebuggingBFLGInstruction SchedulingBFLGAWRDTarget ProcessorDWRDGeneric 80x86=0CASE Pentium=1CASE Pentium Pro=2CASE Pentium II=3CASEAMD K6=4CASEExtended Instruction SetDWRDNone=0CASEMMX=1CASE MMX + K6 3D=2CASEK6 3D=3CASEKEYE4KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGRegister coloringBFLGInline intrinsic functionsBFLGKEYE3KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGOptimize for spaceBFLGOptimize for speedBFLGCommon sub-expressionsBFLGLoop invariantsBFLGCopy/const propagationBFLGDead store eliminationBFLGStrength reductionBFLGDead code eliminationBFLGRegister coloringBFLGLog optimizationsBFLGKEYE2KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDKEYE%l 0 %tpP$HH"T`%t%6:X $E`"PEDj("C23j6"S"S"S"S"S"SL"SH ψ%t `ux>>>> ψ%u `t%u 0lEditTYP#Edit%v@  .$`%vp  $`%vP̔ 00HH3%v0"S("S"S"S$%wPHH"S%w0 v#`"p2%w0-$%w  rx ff3M@%wЫ ` ``00xx0>Ht%$F%w `#cc#'ww'$G8$GD%xP 0`STR#TMPL=FLTRTYP#%x dSIZE%x  hPICTbmap%y@%y rLCancel$DL$ 4<String:DȈ =Type: D M :Next{ :Prev%y`PT  $0H%z 8-,DisplaySet Text StyleTOutline optionsF-by IDby Nameby Size by Attributesby Databy File Input Order- Hide data1 Show sizes-x86 CodeGen.rsrcrc%z`  ψ%{P 0!wwwwwwUUUUUUDDDDDD""""""̙̙ffff333333ff33ffff33ffff3333ffffffff%{ps8LCancel$DL$ 4<String:DȈ =Type: D M :Next{ :Prev%|  File System%}P Pw prefsBE_X86Instruction = 'Bx17', // x86 instruction sets HX%}p@. Zd> d Select AlliReverseiNone dChangedHex@New@OpenInfoɀZdl@@MarkedP 0@P`ppBPBwColorX(hh(xx(((((( yz$%D D$ t$tP File BusyP File LockedP( File Protect@Type:%<Creator:̈Created:%̈ Modified:@ @l Keep hidden@@@DatapPwLabel@Ayb4%}0-% xFREF%0 0#12"U@%P  II%pp%pI%t%P%p px%tbr0f@qA+a3@_A1\45 1988-98 Mathemsthetics, Inc. All Rights Reserved.www.mathemaesthetics.com Version ^04Free Memory: ^1resorcerer@mathemaesthetics.comH`%~,%% @% 8L`t TimesGenevaGenevaGenevaGeneva0%@8L`t TimesGenevaGenevaGenevaGeneva% v  NONAME.EXE@U {MSIEhttp://java.sun.com/products/jdk/1.1/docs/api/EFGHIJK LOPQRXSTUVWNoneMMPr@TEXT.lFlex PreprocessorTEXT.yBison PreprocessorJava LinkerAPPL`Appl`COkMW JavaClssMW JavaJjrf.jrfMWCD`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.htmlTEXT.javaMW JavaTEXT.lFlex PreprocessorTEXT.mfTEXT.rRezTEXT.yBison PreprocessorZIP MW Java@ZipFMW Javadocu`rsrc`.classMW Java.jar@.zipMW JavaMacOS 68K Linker APPL`Appl`MMLBLib Import 68KMPLFLib Import 68KMWCD`OBJ MPW Import 68KPLob`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ 68KTEXT.lFlex PreprocessorTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.ppuMW Pascal 68KTEXT.rRezTEXT.segTEXT.yBison Preprocessordocu`rsrc`shlbPEF Import 68KstubPEF Import 68K.docP.rsrc`MacOS Merge APPL`Appl`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.lFlex PreprocessorTEXT.rRezTEXT.yBison Preprocessorrsrc`shlbMacOS PPC LinkerAPPL`Appl`MMLBLib Import PPCMPLFLib Import PPCMWCD`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ PPCTEXT.c++MW C/C++ PPCTEXT.ccMW C/C++ PPCTEXT.cpMW C/C++ PPCTEXT.cppMW C/C++ PPCTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ PPCTEXT.lFlex PreprocessorTEXT.pMW Pascal PPCTEXT.pasMW Pascal PPCTEXT.pchMW C/C++ PPCTEXT.pch++MW C/C++ PPCTEXT.ppuMW Pascal PPCTEXT.rRezTEXT.sPPCAsmTEXT.yBison PreprocessorXCOFXCOFF Import PPCdocu`rsrc`shlbPEF Import PPCstubPEF Import PPC.docPMC LinkerCLUS@MMLBLib Import 68KMPLFLib Import 68KOBJ MPW Import 68KTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.clsMC Class CompilerTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.defTEXT.docTEXT.hTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.tsWin32 x86 LinkerTEXT.cMW C/C++ x86TEXT.c++MW C/C++ x86TEXT.ccMW C/C++ x86TEXT.cpMW C/C++ x86TEXT.cppMW C/C++ x86TEXT.defTEXT.gcGameCode Converter@TEXT.hMW C/C++ x86TEXT.lFlex PreprocessorTEXT.pMW Pascal x86TEXT.pasMW Pascal x86TEXT.pchMW C/C++ x86TEXT.pch++MW C/C++ x86TEXT.ppuMW Pascal x86TEXT.rcMW WinRCTEXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc}c8mstr mstl mstn((msti7mstr'mstlPmstn(msti,mpsimtglPLst .pref̹-1IprefA. pref}/6$pref): prefO;6>pref4<6Jprefz= mtslxcmtplmtpsXmtpi mtlo,L.prefVK,zIprefnL0prefM0$prefX0 pref`GY0prefZ1JprefT.[ .prefikIprefj pref~Dkoc$prefUv prefVwopref%hxpJprefcypref prefCprefMb prefdoxpref, pref prefNN/| 2prefMU}%PprefMa~prefN],"prefMv`prefNS&prefM5'XJprefNK'pref*4prefc-prefs1prefmall1maplpref =?pref wQ pref 1*lpref 4>Wpref $IXpref zpref kNh pref 2K pref 6pref $Zpref NR>pref pref [pref  3bpref +8pref ӥ pref cpref  pref p+ pref ]pref dv^ypref J_pref +.pref `9 pref Іnyquist-3.05/macproject/packer/0002755000175000000620000000000011537433122015562 5ustar stevestaffnyquist-3.05/macproject/packer/packerdata/0002755000175000000620000000000011537433122017661 5ustar stevestaffnyquist-3.05/macproject/packer/packerdata/.DS_Store0000644000175000000620000001400410144436365021346 0ustar stevestaffBud1ttingsCWSettingsMacOS.stgIlocblobP   @ @ @ @ EDSDB ` @ @ @nyquist-3.05/macproject/packer/packer.mcp0000644000175000000620000026171210144436365017544 0ustar stevestaffcool(Z\RCodeWarrior Project34X:67'+) #=>B<?@A"[042E(,* $!%/HJKYDIG.L- MC;&:9  ZXNO PQWRST8UV153F\`\ xlfatal("f ROOTGRUPSourcesFILEFILEGRUPANSI LibrariesFILE FILEFILE GRUP Mac LibrariesFILE FILE FILE I$IS, xsend$I$I}, /*A8JH݌```   JavaClasses.jarZIP MWZPD f  [\c !T Merge Out????APPLDLGXckidProjWSPCJavaClasses.zipJavaClasses.zip#CshPf0 AddPinRaPoiMIte tRes' MenuI tConk Cont oseCillCShowHideMove$GetCGetCRjzeColiteGetCtCTitlVainCt%Ctl Elue gl SeTestDragTrac Dra!"nded5#istT$r%&'()  **+B,d$`-}./shP001 Add2PinR3aPoi64MIteX5tRest6Menu7tCon8Cont9oseC:illC;Show#GetC}?etCR@zeCoABGetCCtCTiDtlVa8EinCtTFCtl qGlue Hl SeITestJDragKTrac L Dra "M ;N ^O P Q R S T U 1V OW mXKeys Y ZImpo [PW I \KBa ]lpM "^68K C_l 68 b`F Im a bnded cist dTarg ect D fSett 8g Set PheSaf ni@ j k l m n` 'o L Dp%s fqg: r sANSI t 68k uKeyw vI Cowk:Ac1xhsAMyole jzet S{ANSI| 68k}ppin~ConsBuil0ANSTr4Wz5Ux?]|Be @c*Hg -Po +Jj"B]5Wv6Us -Ng#Ec:Xu5Sp .Gf  % C f     !!8!U!s!!!!""3"P"n"""" #!#'"#F##d$#%#&#'#($)$#*$F+$c,$}-$.$/$0$1%2%53%S4%z5%6%7%8&9&1:&Y;&{<&=&>&?'@',A'OB'sC'D'E'F( G(,H(TI(vJ(K(L(M)N)&O)IP)kQ)R)S)T)U*V*0W*NX*qY*Z*[*\*]+^+&_+D`+ca+}b+c+d+e,f,&g,Ch,]i,{j,k,l,m,n-o-3p-Uq-tr-s-t-u-v.w.3x.Qy.rz.{.|.}.~//"/F/h////00 0?0^000001161X1111122$282O2b2z22222233%3<3O3g3333389:;47<=>36?@ABCDEFGHIJKL5MNOPVWXYRUZ[\QT]^_`abcdefghijSklmn~z}y|{$%&' #()*"+,-./012345678!9:;<`abc\_def[^ghijklmnopqrst]uvwx  BCDE>AFGH=@IJKLMNOPQRSTUV?WXYZtuvwpsxyzor{|}~q !"#$%&'()*+,-./012     !M\(J7OlFS`lin r dbjd*objd@O\jobqptlace=g !"#$$1%F& ['t(0)@*Jav+.zip,-./0ut!142F3Y4k5APPL~6GXck7PC89 :;%<=>*?=@bABCDEFG HI$J4KCLRM\NiOyPQRSTUVWXYZ[\kidProjWSPCJavaClasses.zipMSIEInternet ExplorerIexplore.exe a.out@U {MSIEInternet ExplorerIexplore.exe a.out@U {ANSI Console Multi:Custom KeywordsANSI Console Multi:Access PathsANSI Console Multi:Target SettingsANSI Console Multi:File MappingsANSI Console Multi:Build ExtrasANSI Console Multi:68K CodeGenANSI Console Multi:68K DisassemblerANSI Console Multi:68K LinkerANSI Console Multi:68K ProjectANSI Console Multi:C/C++ CompilerANSI Console Multi:C/C++ WarningsANSI Console Multi:CFM68KANSI Console Multi:IR OptimizerANSI Console Multi:Java OutputANSI Console Multi:Java ProjectANSI Console Multi:Java VMANSI Console Multi:MacOS Merge PanelANSI Console Multi:Pascal CompilerANSI Console Multi:Pascal WarningsANSI Console Multi:PPC CodeGenANSI Console Multi:PPC DisassemblerANSI Console Multi:PPC LinkerANSI Console Multi:PPC PEFANSI Console Multi:PPC ProjectANSI Console Multi:PPCAsm PanelANSI Console Multi:Rez CompilerANSI Console Multi:WinRC CompilerANSI Console Multi:x86 CodeGenANSI Console Multi:x86 LinkerANSI Console Multi:x86 ProjectProject File ListANSI Console 68k:Custom KeywordsANSI Console 68k:Access PathsANSI Console 68k:Target SettingsANSI Console 68k:File MappingsANSI Console 68k:Build ExtrasANSI Console 68k:68K CodeGenANSI Console 68k:68K DisassemblerANSI Console 68k:68K LinkerANSI Console 68k:68K ProjectANSI Console 68k:C/C++ CompilerANSI Console 68k:C/C++ WarningsANSI Console 68k:CFM68KANSI Console 68k:IR OptimizerANSI Console 68k:Java OutputANSI Console 68k:Java ProjectANSI Console 68k:Java VMANSI Console 68k:MacOS Merge PanelANSI Console 68k:Pascal CompilerANSI Console 68k:Pascal WarningsANSI Console 68k:PPC CodeGenANSI Console 68k:PPC DisassemblerANSI Console 68k:PPC LinkerANSI Console 68k:PPC PEFANSI Console 68k:PPC ProjectANSI Console 68k:PPCAsm PanelANSI Console 68k:Rez CompilerANSI Console 68k:WinRC CompilerANSI Console 68k:x86 CodeGenANSI Console 68k:x86 LinkerANSI Console 68k:x86 ProjectANSI Console PPC:Custom KeywordsANSI Console PPC:Access PathsANSI Console PPC:Target SettingsANSI Console PPC:File MappingsANSI Console PPC:Build ExtrasANSI Console PPC:68K CodeGenANSI Console PPC:68K DisassemblerANSI Console PPC:68K LinkerANSI Console PPC:68K ProjectANSI Console PPC:C/C++ CompilerANSI Console PPC:C/C++ WarningsANSI Console PPC:CFM68KANSI Console PPC:IR OptimizerANSI Console PPC:Java OutputANSI Console PPC:Java ProjectANSI Console PPC:Java VMANSI Console PPC:MacOS Merge PanelANSI Console PPC:Pascal CompilerANSI Console PPC:Pascal WarningsANSI Console PPC:PPC CodeGenANSI Console PPC:PPC DisassemblerANSI Console PPC:PPC LinkerANSI Console PPC:PPC PEFANSI Console PPC:PPC ProjectANSI Console PPC:PPCAsm PanelANSI Console PPC:Rez CompilerANSI Console PPC:WinRC CompilerANSI Console PPC:x86 CodeGenANSI Console PPC:x86 LinkerANSI Console PPC:x86 ProjectANSI Console FAT:Custom KeywordsANSI Console FAT:Access PathsANSI Console FAT:Target SettingsANSI Console FAT:File MappingsANSI Console FAT:Build ExtrasANSI Console FAT:68K CodeGenANSI Console FAT:68K DisassemblerANSI Console FAT:68K LinkerANSI Console FAT:68K ProjectANSI Console FAT:C/C++ CompilerANSI Console FAT:C/C++ WarningsANSI Console FAT:CFM68KANSI Console FAT:IR OptimizerANSI Console FAT:Java OutputANSI Console FAT:Java ProjectANSI Console FAT:Java VMANSI Console FAT:MacOS Merge PanelANSI Console FAT:Pascal CompilerANSI Console FAT:Pascal WarningsANSI Console FAT:PPC CodeGenANSI Console FAT:PPC DisassemblerANSI Console FAT:PPC LinkerANSI Console FAT:PPC PEFANSI Console FAT:PPC ProjectANSI Console FAT:PPCAsm PanelANSI Console FAT:Rez CompilerANSI Console FAT:WinRC CompilerANSI Console FAT:x86 CodeGenANSI Console FAT:x86 LinkerANSI Console FAT:x86 ProjectANSI C Console 68k:Custom KeywordsANSI C Console 68k:Access PathsANSI C Console 68k:Target SettingsANSI C Console 68k:File MappingsANSI C Console 68k:Build ExtrasANSI C Console 68k:68K CodeGenANSI C Console 68k:68K DisassemblerANSI C Console 68k:68K LinkerANSI C Console 68k:68K ProjectANSI C Console 68k:C/C++ CompilerANSI C Console 68k:C/C++ WarningsANSI C Console 68k:CFM68KANSI C Console 68k:IR OptimizerANSI C Console 68k:MacOS Merge PanelANSI C Console 68k:Pascal CompilerANSI C Console 68k:Pascal WarningsANSI C Console 68k:PPC CodeGenANSI C Console 68k:PPC DisassemblerANSI C Console 68k:PPC LinkerANSI C Console 68k:PPC PEFANSI C Console 68k:PPC ProjectANSI C Console 68k:PPCAsm PanelANSI C Console 68k:Rez CompilerANSI C Console PPC:Custom KeywordsANSI C Console PPC:Access PathsANSI C Console PPC:Target SettingsANSI C Console PPC:File MappingsANSI C Console PPC:Build ExtrasANSI C Console PPC:68K CodeGenANSI C Console PPC:68K DisassemblerANSI C Console PPC:68K LinkerANSI C Console PPC:68K ProjectANSI C Console PPC:C/C++ CompilerANSI C Console PPC:C/C++ WarningsANSI C Console PPC:CFM68KANSI C Console PPC:IR OptimizerANSI C Console PPC:MacOS Merge PanelANSI C Console PPC:Pascal CompilerANSI C Console PPC:Pascal WarningsANSI C Console PPC:PPC CodeGenANSI C Console PPC:PPC DisassemblerANSI C Console PPC:PPC LinkerANSI C Console PPC:PPC PEFANSI C Console PPC:PPC ProjectANSI C Console PPC:PPCAsm PanelANSI C Console PPC:Rez CompilerANSI C Console FAT:Custom KeywordsANSI C Console FAT:Access PathsANSI C Console FAT:Target SettingsANSI C Console FAT:File MappingsANSI C Console FAT:Build ExtrasANSI C Console FAT:68K CodeGenANSI C Console FAT:68K DisassemblerANSI C Console FAT:68K LinkerANSI C Console FAT:68K ProjectANSI C Console FAT:C/C++ CompilerANSI C Console FAT:C/C++ WarningsANSI C Console FAT:CFM68KANSI C Console FAT:IR OptimizerANSI C Console FAT:MacOS Merge PanelANSI C Console FAT:Pascal CompilerANSI C Console FAT:Pascal WarningsANSI C Console FAT:PPC CodeGenANSI C Console FAT:PPC DisassemblerANSI C Console FAT:PPC LinkerANSI C Console FAT:PPC PEFANSI C Console FAT:PPC ProjectANSI C Console FAT:PPCAsm PanelANSI C Console FAT:Rez CompilerANSI C Console 68k:Java OutputANSI C Console 68k:Java ProjectANSI C Console 68k:Java VMANSI C Console 68k:WinRC CompilerANSI C Console 68k:x86 CodeGenANSI C Console 68k:x86 LinkerANSI C Console 68k:x86 ProjectANSI C Console PPC:Java OutputANSI C Console PPC:Java ProjectANSI C Console PPC:Java VMANSI C Console PPC:WinRC CompilerANSI C Console PPC:x86 CodeGenANSI C Console PPC:x86 LinkerANSI C Console PPC:x86 ProjectANSI C Console FAT:Java OutputANSI C Console FAT:Java ProjectANSI C Console FAT:Java VMANSI C Console FAT:WinRC CompilerANSI C Console FAT:x86 CodeGenANSI C Console FAT:x86 LinkerANSI C Console FAT:x86 ProjectStd C Console 68K:Custom KeywordsStd C Console 68K:Access PathsStd C Console 68K:Target SettingsStd C Console 68K:File MappingsStd C Console 68K:Build ExtrasStd C Console 68K:Bison PanelStd C Console 68K:Flex PanelStd C Console 68K:68K CodeGenStd C Console 68K:68K DisassemblerStd C Console 68K:68K LinkerStd C Console 68K:68K ProjectStd C Console 68K:C/C++ CompilerStd C Console 68K:C/C++ WarningsStd C Console 68K:CFM68KStd C Console 68K:IR OptimizerStd C Console 68K:Java OutputStd C Console 68K:Java ProjectStd C Console 68K:Java VMStd C Console 68K:MacOS Merge PanelStd C Console 68K:Pascal CompilerStd C Console 68K:Pascal WarningsStd C Console 68K:PPC CodeGenStd C Console 68K:PPC DisassemblerStd C Console 68K:PPC LinkerStd C Console 68K:PPC PEFStd C Console 68K:PPC ProjectStd C Console 68K:PPCAsm PanelStd C Console 68K:Rez CompilerStd C Console 68K:WinRC CompilerStd C Console 68K:x86 CodeGenStd C Console 68K:x86 LinkerStd C Console 68K:x86 ProjectStd C Console PPC:Custom KeywordsStd C Console PPC:Access PathsStd C Console PPC:Target SettingsStd C Console PPC:File MappingsStd C Console PPC:Build ExtrasStd C Console PPC:Bison PanelStd C Console PPC:Flex PanelStd C Console PPC:68K CodeGenStd C Console PPC:68K DisassemblerStd C Console PPC:68K LinkerStd C Console PPC:68K ProjectStd C Console PPC:C/C++ CompilerStd C Console PPC:C/C++ WarningsStd C Console PPC:CFM68KStd C Console PPC:IR OptimizerStd C Console PPC:Java OutputStd C Console PPC:Java ProjectStd C Console PPC:Java VMStd C Console PPC:MacOS Merge PanelStd C Console PPC:Pascal CompilerStd C Console PPC:Pascal WarningsStd C Console PPC:PPC CodeGenStd C Console PPC:PPC DisassemblerStd C Console PPC:PPC LinkerStd C Console PPC:PPC PEFStd C Console PPC:PPC ProjectStd C Console PPC:PPCAsm PanelStd C Console PPC:Rez CompilerStd C Console PPC:WinRC CompilerStd C Console PPC:x86 CodeGenStd C Console PPC:x86 LinkerStd C Console PPC:x86 ProjectStd C Console FAT:Custom KeywordsStd C Console FAT:Access PathsStd C Console FAT:Target SettingsStd C Console FAT:File MappingsStd C Console FAT:Build ExtrasStd C Console FAT:Bison PanelStd C Console FAT:Flex PanelStd C Console FAT:68K CodeGenStd C Console FAT:68K DisassemblerStd C Console FAT:68K LinkerStd C Console FAT:68K ProjectStd C Console FAT:C/C++ CompilerStd C Console FAT:C/C++ WarningsStd C Console FAT:CFM68KStd C Console FAT:IR OptimizerStd C Console FAT:Java OutputStd C Console FAT:Java ProjectStd C Console FAT:Java VMStd C Console FAT:MacOS Merge PanelStd C Console FAT:Pascal CompilerStd C Console FAT:Pascal WarningsStd C Console FAT:PPC CodeGenStd C Console FAT:PPC DisassemblerStd C Console FAT:PPC LinkerStd C Console FAT:PPC PEFStd C Console FAT:PPC ProjectStd C Console FAT:PPCAsm PanelStd C Console FAT:Rez CompilerStd C Console FAT:WinRC CompilerStd C Console FAT:x86 CodeGenStd C Console FAT:x86 LinkerStd C Console FAT:x86 Project68K Standard C Console:Custom Keywords68K Standard C Console:Access Paths68K Standard C Console:Target Settings68K Standard C Console:File Mappings68K Standard C Console:Build Extras68K Standard C Console:68K CodeGen68K Standard C Console:68K Disassembler68K Standard C Console:68K Linker68K Standard C Console:68K Project68K Standard C Console:C/C++ Compiler68K Standard C Console:C/C++ Warnings68K Standard C Console:CFM68K68K Standard C Console:IR Optimizer68K Standard C Console:Java Output68K Standard C Console:Java Project68K Standard C Console:Java VM68K Standard C Console:MacOS Merge Panel68K Standard C Console:Pascal Compiler68K Standard C Console:Pascal Warnings68K Standard C Console:PPC CodeGen68K Standard C Console:PPC Disassembler68K Standard C Console:PPC Linker68K Standard C Console:PPC PEF68K Standard C Console:PPC Project68K Standard C Console:PPCAsm Panel68K Standard C Console:Rez Compiler68K Standard C Console:WinRC Compiler68K Standard C Console:x86 CodeGen68K Standard C Console:x86 Linker68K Standard C Console:x86 Project68K Std C Console:Custom Keywords68K Std C Console:Access Paths68K Std C Console:Target Settings68K Std C Console:File Mappings68K Std C Console:Build Extras68K Std C Console:68K CodeGen68K Std C Console:68K Disassembler68K Std C Console:68K Linker68K Std C Console:68K Project68K Std C Console:C/C++ Compiler68K Std C Console:C/C++ Warnings68K Std C Console:CFM68K68K Std C Console:IR Optimizer68K Std C Console:Java Output68K Std C Console:Java Project68K Std C Console:Java VM68K Std C Console:MacOS Merge Panel68K Std C Console:Pascal Compiler68K Std C Console:Pascal Warnings68K Std C Console:PPC CodeGen68K Std C Console:PPC Disassembler68K Std C Console:PPC Linker68K Std C Console:PPC PEF68K Std C Console:PPC Project68K Std C Console:PPCAsm Panel68K Std C Console:Rez Compiler68K Std C Console:WinRC Compiler68K Std C Console:x86 CodeGen68K Std C Console:x86 Linker68K Std C Console:x86 ProjectPPC Std C Console:Custom KeywordsPPC Std C Console:Access PathsPPC Std C Console:Target SettingsPPC Std C Console:File MappingsPPC Std C Console:Build ExtrasPPC Std C Console:68K CodeGenPPC Std C Console:68K DisassemblerPPC Std C Console:68K LinkerPPC Std C Console:68K ProjectPPC Std C Console:C/C++ CompilerPPC Std C Console:C/C++ WarningsPPC Std C Console:CFM68KPPC Std C Console:IR OptimizerPPC Std C Console:Java OutputPPC Std C Console:Java ProjectPPC Std C Console:Java VMPPC Std C Console:MacOS Merge PanelPPC Std C Console:Pascal CompilerPPC Std C Console:Pascal WarningsPPC Std C Console:PPC CodeGenPPC Std C Console:PPC DisassemblerPPC Std C Console:PPC LinkerPPC Std C Console:PPC PEFPPC Std C Console:PPC ProjectPPC Std C Console:PPCAsm PanelPPC Std C Console:Rez CompilerPPC Std C Console:WinRC CompilerPPC Std C Console:x86 CodeGenPPC Std C Console:x86 LinkerPPC Std C Console:x86 ProjectPPC Std C Console:Java LanguagePPC Std C Console:Debugger TargetPPC Std C Console:FTP PanelPPC Std C Console:JavaDoc ProjectPPC Std C Console:x86 Exceptions PanelPPC Std C Console:68K Global OptimizerPPC Std C Console:PPC Global Optimizerpacker:Custom Keywordspacker:Access Pathspacker:Target Settingspacker:File Mappingspacker:Build Extraspacker:Debugger Targetpacker:68K CodeGenpacker:68K Disassemblerpacker:68K Global Optimizerpacker:68K Linkerpacker:68K Projectpacker:C/C++ Compilerpacker:C/C++ Warningspacker:CFM68Kpacker:MacOS Merge Panelpacker:Pascal Compilerpacker:Pascal Warningspacker:PPC CodeGenpacker:PPC Disassemblerpacker:PPC Global Optimizerpacker:PPC Linkerpacker:PPC PEFpacker:PPC Projectpacker:PPCAsm Panelpacker:Rez CompilerMSIEInternet ExplorerIexplore.exe a.out@U {ANSI Console MultiFirst Segment:a.outLib Import 68KMPW Import 68KBalloon HelpMW C/C++ 68KMW Pascal 68KRezPEF Import 68KANSI Console 68kHelloWorld.cMSL C.68K Fa(4i_8d).LibMSL Runtime68K.LibMathLib68K Fa(4i/8d).LibMSL C++.68K Fa(4i_8d).LibMacOS.libMSL SIOUX.68K.LibANSI Console PPC:ANSI Console PPC.outLib Import PPCMW C/C++ PPCMW Pascal PPCPPCAsmXCOFF Import PPCPEF Import PPCMSL C++.PPC.LibMSL C.PPC.LibInterfaceLibMathLibMSL RuntimePPC.LibMSL SIOUX.PPC.Lib:ANSI Console 68k.outANSI Console FAT:Merge Out:ANSI Console FAT.outANSI Console 68k.outANSI Console PPC.outMathLib68K Fa(4i_8d).Lib:ANSI C Console 68kANSI C Console 68k:ANSI C Console PPCANSI C Console PPC:ANSI C Console FATANSI C Console FATGameCode ConverterFlex PreprocessorBison Preprocessor:Std C Console 68KStd C Console 68K:Std C Console PPCStd C Console PPC:Std C Console FATStd C Console FAT68K Standard C Console68K Std C ConsolePPC Std C ConsoleMSL C.68K (2i).LibMSL C++.68K (2i).LibMathLib68K (2i).Lib:HelloWorld.c:Bin:MSL C++.PPC.Lib:Bin:MSL C.PPC.Lib:Libraries:MacOS Common:InterfaceLib:Libraries:MacOS Common:MathLib:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib:Bin:MSL SIOUX.PPC.LibMacOS PPC LinkerCustom KeywordsAccess PathsTarget SettingsFile MappingsBuild ExtrasDebugger TargetC/C++ CompilerC/C++ WarningsFTP PanelIR OptimizerPascal CompilerPascal WarningsPPC CodeGenPPC DisassemblerPPC LinkerPPC PEFPPC ProjectPPCAsm PanelRez CompilerPPC Global Optimizerpacker.cconvert.cpacker:packer     YZcrcrapGpPujebugCPorortap DMap %ix NEisat Ct PeBacketPi eRGB!#"B#`$}% & '(*0+N,k-@. /012$F4b5@{6789:k;-<@k`ce NewGDevicosvice SetGDevice GetGDevice Colorndndex2Color InvertColor RealColoretable UpdatePixMap MakeITable AddarddComp SetClientID ProtectEntry sentry SetEntriesQDError SetWinCor uxWin SetCtlColoP aetNeP a Qpk`~_34P`|}a4{|}b34@:@:::misc:@:::sys:mac::::cmt::nyquist:cmt::Metrowerks Standard Library:MSL Precompiled Header:@:Metrowerks Standard Library:MSL C:@:Metrowerks Standard Library:MSL C++:@:MacOS Support:@:MacOS PPC Linkerpacker C Console: Std C Console 68K????APPLX????U {__start__sta__start     packerConsole PPC????APPL@X????P'CODE' 'DATA' 'PICT'Balloon HelpTEXT.gcGameCode Converter@TEXT.lFlex PreprocessorTEXT.rRezTEXT.yBison Preprocessorrsrc`shlbMacOS PPC LinkerAPPL`Appl`MMLBLib Import PPCMPLFLib Import PPCMWCD`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ PPCTEXT.c++MW C/C++ PPCTEXT.ccMW C/C++ PPCTEXT.cpMW C/C++ PPCTEXT.cppMW C/C++ PPCTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ PPCTEXT.lFlex PreprocessorTEXT.pMW Pascal PPCTEXT.pasMW Pascal PPCTEXT.pchMW C/C++ PPCTEXT.pch++MW C/C++ PPCTEXT.ppuMW Pascal PPCTEXT.rRezTEXT.sPPCAsmTEXT.yBison PreprocessorXCOFXCOFF Import PPCdocu`rsrc`shlbPEF Import PPCstubPEF Import PPC.docPMC LinkerCLUS@MMLBLib Import 68KMPLFLib Import 68KOBJ MPW Import 68KTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.clsMC Class CompilerTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.defTEXT.docTEXT.hTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.tsWin32 x86 LinkerTEXT.cMW C/C++ x86TEXT.c++MW C/C++ x86TEXT.ccMW C/C++ x86TEXT.cpMW C/C++ x86TEXT.cppMW C/C++ x86TEXT.defTEXT.gcGameCode Converter@TEXT.hMW C/C++ x86TEXT.lFlex PreprocessorTEXT.pMW Pascal x86TEXT.pasMW Pascal x86TEXT.pchMW C/C++ x86TEXT.pch++MW C/C++ x86TEXT.ppuMW Pascal x86TEXT.rcMW WinRCTEXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc__startMSIEInternet ExplorerIexplore.exe/ uJIT@:u9up^J MENUbTargSTR#PPobRidLaeteSTR prefFlagTMPLvers Drop"hi _j, .( Q-5@J T__sta__startStd C Console PPC????APPL@X????P'CODE' 'DATA' 'PICT'%@,%G%Ht%x/CWPlugin_GetDropInName &DdropInName %H%H%I%I>Ht%H%I, %%H%IL%rX^CWPlugin_GetDisplayName "displayName %I%I%I%I>Ht%I%J #<%I%J$&CWPlugin_GetPanelList %C8%fvpanelList %J %J%J%JF>Ht%Jd%J w%Jd%JUUbCWPlugin_GetFamilyList%M %E<%familyList %K`%Kp%K%K%K>Ht%K<%K   {d%K<%KTCWPlugin_GetHelpInfo  %G vhelpInfo%el %L8p%LH%L`%L%Lp)&>Ht%L%L  L%F0%L%L%M&CWGetPluginRequest%L %*L context\%Mp%M%M %MP0request@ @%ML%M`ery %M0vers>Ht%L%M f6!|%L%M4 ACWDonePluginRequestQ %*%NP$,%N Q%}resultCode O%N8 O1n%NYO/<>Ht%M%Nl g"(%M%NNNVCWGetAPIVersion/ %* <%O$%M%N0H %O F%N/Ht%N%O@ $$%N%O`%K%CWGetIDEInfo %*%O%M%O %=L%O-4%%O%>Ht%O%P %o`%O%P4%CWGetCallbackOSError %*%P%M%P8O \%P%PM88>Ht%Pt%P %Pt%Q %XCWSetPluginOSError %* %Q%M%Qp$,%QH>Ht%QP%Q %Q!d%QP%Q؀CWGetProjectFileff %*%R%M%R8projectSpec  %Rd%R|%RHffff>Ht%R%R <%R%R33%m,CWGetTargetName %*%S`%M%S$ 33%S%SP&'LmaxLength%S|%S4ff>Ht%S%S $Q%S%S33%{CWGetOutputFileDirectory %*ff%T%M%T8ioutputFileDirectory  %Td%T33%TH>Ht%T%T QL%T%Tff33&)CWGetProjectFileCount %*%Up%M%U4 33\%U`ff%UDff>Ht%U%U E\%U%Uff& CWGetFileInfo %*%V4%M%Vff%Vp%433& checkFileLocation%V%VPff%bfileinfo33 %733%V%V%V33>Ht%U%V 33%U%Vff%{CWFindAndLoadFileff33 %*%W%M%WP33filename33 33%W%W|%W %.%V%W%W`>Ht%W0%W ff%7%W0%X &+t#CWGetFileTextffff %*%X%M%Xh  %X%0%X 33 %X%Y$ k%XwwtextLength"" %YP%X%Y %0H%Y@%Xx>Ht%XL%Yl ""%XL%Y&.<DCWReleaseFileTextww %*DD%Z(%M%Y  k%Z%Y>Ht%Y%ZD "0%Y%Zd&lCWGetSegmentInfo %*%[ %M%Z&V4whichsegment⾾%[P%ZPsegmentinfo %1%[(%[@%Z>Ht%Z%[l ,D%Z%[gCWGetOverlay1GroupsCount %*%\0%M%[ \%\ %\>Ht%[%\L l%[%\lCWGetOverlay1GroupInfo %*%]%M%\whichgroup%]X%\%|<zgroupinfo %2%]0%]H%\>Ht%\%]t ! %\%]%CWGetOverlay1Info %*%^ %M%]%^X%\%Dwhichoverlay%^%^<% @overlayinfo %3%^t%^%^>Ht%]%^ |%]%^ؖCWGetOverlay1FileInfo %*%_h%M%_<%_%\%_%^<whichoverlayfile{{{zz%_%_|||{ %4dvu%V%_rrww%_Lllqq>Ht%_%` }h%_%`(&GCWReportMessage %*%`%M%`msgRefyyy %4yy%a%`%`uuttline1tsss ss%aT%`%aoonn%line2 %a%a0%aDerrorlevel%a%ap%uerrorNumber|{%axx}}%`rrww>Ht%`h%a nmmm$%`h%allCWAlertji %*dc%b%M%bL``eemsg1_^^^] ^]%b%bx%bZZYYmsg2YXXXW XW%c%b%bNNSSmsg3SRRRQ LK%c\%b%c HHkk%msg4kjjji dc%c8%cL``ee%b\ZZ__>Ht%b8%cx VUUU"j%b8%cTTYYHt%c%dx UUU|%c%dTTYYKCWUserBreakPP %*PP%M%dLLLK%eFFFE>Ht%d%e <===%e>===>Ht%e|%fd 9988`%e|%f2111%<vCWStorePluginData2111 %*++%g%M%f--,,%g,%4((('%gX%BB %+AA%f %gH>===%f8777>Ht%f%gt 3322t%f%g2111CWGetPluginData,, %*,,%h%M%g((('%h8%4$$%ht%  %+ %hT%f %hd%h>Ht%g%h "{L%g%h %'CWSetModDate %*%iH%M%i ##  ##%it%0%i8 %i%7%idisGenerated%i %i >Ht%h%i ;@%h%i&WkCWAddProjectEntry %*%j%M%jD0123  BC%j %jp\]^_%j%ixyz{projectEntryInfo %<\%k%j%j %4%k%jT>Ht%j$%k0 3`%j$%kP%CWCreateNewTextDocument %*U%l$,%k)%vdocinfo %;T ;%k%k)@%k%Q>Ht%k%l M $2\%k%l@CWAllocateMemory %*%l%M%lH%m+isPermanent%mL%l `ptr% %m%m,%m<%l>Ht%l%mh %l%m%CWFreeMemory %*mP%n %M%m  %n<%m,%n%lD %m>Ht%m%nX %m%nxCWAllocMemHandle %*%o%M%n%o<%luseTempMemory0%o%o  %+&08!handle$ %oX%oh%o|%n>Ht%n%o 0%n%oCWFreeMemHandle %*o%p`%M%p$  %+%oh%pP%p4>Ht%p%p| "@@%p%p%q%|.CWGetMemHandleSize%q\ %*9%q8%M%p %+%qd%oh%q( q%qT%q %>Ht%p%q %r%p%q&  CWResizeMemHandle%r %*%r<%M%r/ N %+%rl%oh%r,%r\^newSize %rX%r%r>Ht%q%r %s`%q%rCWLockMemHandle76 %*l%s@%M%s %+sT%sp%oh%s0%smoveHi%u%s%s\ t %s78%m,%s%u%s>Ht%r%s .htm"%r%s%{`CWUnlockMemHandle% %*t\%t%M%tH%u %+/.%oh%tt%%tX>Ht%t(%t 8?%t(%t%u%`CWMacOSErrToCWResult%ut %*%u`%M%u$%%w5errud%uP%vD%u4>Ht%u%u| %u%u%v$DROPINPANELAPIVERSION_1%u%v%vD1DROPINPANELAPIVERSION_2w$%v%vP2L%DROPINPANELAPIVERSION_3%vT%v3%tDROPINPANELAPIVERSION_4/ %v%v4DROPINPANELAPIVERSION_5%v%w/5w %0DROPINPANELAPIVERSION_6wd0%w%w@6w& <DROPINPANELAPIVERSION_7L%wD%w|%w7DROPINPANELAPIVERSION,%w%wDROPINPANELAPIVERSION_7%xl5kBadPrefVersionw%w%xsion1000VwkMissingPrefErrl%x %x<%x|1001>Ht%xx%xJ;reqInitPaneld%x%x\%xDx,%x\%xxhtml&$reqTermPanel %y%x%xD`,%x%x%y<Ht%% *xmenu_CutJ%%%$G@%%&lmenu_Copy%%T%%>%%%\menu_Paste%%%<%%<%T&menu_Clear%%%%! 4%%q%Pmenu_SelectAll%%!%%E%,@enum$1266PBackendx86_c PanelFlags%0%x%%H%0%\ %%A(%%%AX%%%A%L%%A& Tpanelfamily%% %8%B0@dataversion%h% panelscope%%P&>Ht%%0<%usesStrictAPI%P%%%%%HsupportsByteSwapping%%@J%%%%T@enum$1267PBackendx86_c>Ht%%PZpanelScopeGlobal%%%l%T(%l%(panelScopeProject%%$%%T %%%<mpanelScopeTarget%,%%T L%%$%@enum$1268PBackendx86_c%pDummyDialog%t%%$)t%t%%%CWDialog %%b@%%/FCWPanelCallbacks%@%$8%%`%T%$%8N%%PanelParameterBlock%l%%$Ϩ%l%%%%ML?%@20  %$%%M?X` ]%T% +G)& targetfile%%| %<,o( %"%%lAV $p%originalPrefsWD%%%Z8 $*%currentPrefs*%H%%^ $%IfactoryPrefs@%p%%,b% &%%`Chf baseItems%%j%Tl&.P"EcanRevert%%n%#canFactory's%0%o%T%`%"|p%recompile%%Hq%&/relink%%xr'prefsKeyword%%t%L&0(GprefsDesc%%#%x,debugOn%L%%D-coldtargfile% %4%|.`callbacks3 %$%%|%d07reparse %%%<  1pdragref%$%% &,(3!dragrect%D%T% %T9dragmouse%ˌ%ވ%<%t:toEndian%%l %+ˌ;originalPrefsMemHandle%%%% %+ =currentPrefsMemHandle%d%h%%%D %+%>RfactoryPrefsMemHandle%%4%D%D%PanelParameterBlockPtr% %T%4|%%tPanelParamBlk%L%%% %[PanelParamBlkPtr%%(%8%X%%Lextern%% CWPanlAppendItems %d%d1ppb %%%%7ditlID'%% >Ht%%& uL%%8ACWPanlDrawPanelBox %%%%% % P%%!>Ht%x% % "%x%,%CWPanlShowItem %%%%%%,showIt%%%>Ht%l%!2%l% %CWPanlEnableItem % %%%%%7enableIt%d$juVersionKWRD Current=6CASE Version 5=5CASE Version 4=4CASE Version 3=3CASE Version 2=2CASE6KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGRegister coloringBFLGInline intrinsic functionsBFLG#Disable Optimizations for DebuggingBFLGInstruction SchedulingBFLGAWRDTarget ProcessorDWRDGeneric 80x86=0CASE Pentium=1CASE Pentium Pro=2CASE Pentium II=3CASEAMD K6=4CASEExtended Instruction SetDWRDNone=0CASEMMX=1CASE MMX + K6 3D=2CASEK6 3D=3CASEVectorize LoopsBFLGreservedFBYTKEYE5KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGRegister coloringBFLGInline intrinsic functionsBFLG#Disable Optimizations for DebuggingBFLGInstruction SchedulingBFLGAWRDTarget ProcessorDWRDGeneric 80x86=0CASE Pentium=1CASE Pentium Pro=2CASE Pentium II=3CASEAMD K6=4CASEExtended Instruction SetDWRDNone=0CASEMMX=1CASE MMX + K6 3D=2CASEK6 3D=3CASEKEYE4KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGRegister coloringBFLGInline intrinsic functionsBFLGKEYE3KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDSYM debug informationBFLGCodeView debug infoBFLGOptimize for spaceBFLGOptimize for speedBFLGCommon sub-expressionsBFLGLoop invariantsBFLGCopy/const propagationBFLGDead store eliminationBFLGStrength reductionBFLGDead code eliminationBFLGRegister coloringBFLGLog optimizationsBFLGKEYE2KEYBPeephole optimiserBFLGMachine code listingBFLGAWRD AlignmentDWRD1 byte=0CASE 2 bytes=1CASE 4 bytes=2CASE 8 bytes=3CASE 16 bytes=4CASEAWRDKEYE%l 0 %tpP$HH"T`%t%6:X $E`"PEDj("C23j6"S"S"S"S"S"SL"SH ψ%t `ux>>>> ψ%u `t%u 0lEditTYP#Edit%v@  .$`%vp  $`%vP̔ 00HH3%v0"S("S"S"S$%wPHH"S%w0 v#`"p2%w0-$%w  rx ff3M@%wЫ ` ``00xx0>Ht%$F%w `#cc#'ww'$G8$GD%xP 0`STR#TMPL=FLTRTYP#%x dSIZE%x  hPICTbmap%y@%y rLCancel$DL$ 4<String:DȈ =Type: D M :Next{ :Prev%y`PT  $0H%z 8-,DisplaySet Text StyleTOutline optionsF-by IDby Nameby Size by Attributesby Databy File Input Order- Hide data1 Show sizes-x86 CodeGen.rsrcrc%z`  ψ%{P 0!wwwwwwUUUUUUDDDDDD""""""̙̙ffff333333ff33ffff33ffff3333ffffffff%{ps8LCancel$DL$ 4<String:DȈ =Type: D M :Next{ :Prev%|  File System%}P Pw prefsBE_X86Instruction = 'Bx17', // x86 instruction sets HX%}p@. Zd> d Select AlliReverseiNone dChangedHex@New@OpenInfoɀZdl@@MarkedP 0@P`ppBPBwColorX(hh(xx(((((( yz$%D D$ t$tP File BusyP File LockedP( File Protect@Type:%<Creator:̈Created:%̈ Modified:@ @l Keep hidden@@@DatapPwLabel@Ayb4%}0-% xFREF%0 0#12"U@%P  II%pp%pI%t%P%p px%tbr0f@qA+a3@_A1\45 1988-98 Mathemsthetics, Inc. All Rights Reserved.www.mathemaesthetics.com Version ^04Free Memory: ^1resorcerer@mathemaesthetics.comH`%~,%% @% 8L`t TimesGenevaGenevaGenevaGeneva0%@8L`t TimesGenevaGenevaGenevaGeneva% v  NONAME.EXE@U {MSIEhttp://java.sun.com/products/jdk/1.1/docs/api/EFGHIJK LOPQRXSTUVWNoneMMPr@TEXT.lFlex PreprocessorTEXT.yBison PreprocessorJava LinkerAPPL`Appl`COkMW JavaClssMW JavaJjrf.jrfMWCD`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.htmlTEXT.javaMW JavaTEXT.lFlex PreprocessorTEXT.mfTEXT.rRezTEXT.yBison PreprocessorZIP MW Java@ZipFMW Javadocu`rsrc`.classMW Java.jar@.zipMW JavaMacOS 68K Linker APPL`Appl`MMLBLib Import 68KMPLFLib Import 68KMWCD`OBJ MPW Import 68KPLob`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ 68KTEXT.lFlex PreprocessorTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.ppuMW Pascal 68KTEXT.rRezTEXT.segTEXT.yBison Preprocessordocu`rsrc`shlbPEF Import 68KstubPEF Import 68K.docP.rsrc`MacOS Merge APPL`Appl`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.lFlex PreprocessorTEXT.rRezTEXT.yBison Preprocessorrsrc`shlbMacOS PPC LinkerAPPL`Appl`MMLBLib Import PPCMPLFLib Import PPCMWCD`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ PPCTEXT.c++MW C/C++ PPCTEXT.ccMW C/C++ PPCTEXT.cpMW C/C++ PPCTEXT.cppMW C/C++ PPCTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ PPCTEXT.lFlex PreprocessorTEXT.pMW Pascal PPCTEXT.pasMW Pascal PPCTEXT.pchMW C/C++ PPCTEXT.pch++MW C/C++ PPCTEXT.ppuMW Pascal PPCTEXT.rRezTEXT.sPPCAsmTEXT.yBison PreprocessorXCOFXCOFF Import PPCdocu`rsrc`shlbPEF Import PPCstubPEF Import PPC.docPMC LinkerCLUS@MMLBLib Import 68KMPLFLib Import 68KOBJ MPW Import 68KTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.clsMC Class CompilerTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.defTEXT.docTEXT.hTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.tsWin32 x86 LinkerTEXT.cMW C/C++ x86TEXT.c++MW C/C++ x86TEXT.ccMW C/C++ x86TEXT.cpMW C/C++ x86TEXT.cppMW C/C++ x86TEXT.defTEXT.gcGameCode Converter@TEXT.hMW C/C++ x86TEXT.lFlex PreprocessorTEXT.pMW Pascal x86TEXT.pasMW Pascal x86TEXT.pchMW C/C++ x86TEXT.pch++MW C/C++ x86TEXT.ppuMW Pascal x86TEXT.rcMW WinRCTEXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc74mstr mstl mstn((mstipcmstr'mstlPmstn(msti,mpsimtglPLst .pref̹-1IprefA. pref}/6$pref): prefO;6>pref4<6Jprefz= mtslxcmtplmtpsXmtpi mtlo,L.prefVK,zIprefnL0prefM0$prefX0 pref`GY0prefZ1JprefT.[ .prefikIprefj pref~Dkoc$prefUv prefVwopref%hxpJprefcypref prefCprefMb prefdoxpref, pref prefNN/| 2prefMU}%PprefMa~prefN],"prefMv`prefNS&prefM5'XJprefNK'pref*4prefc-prefs1prefmall1maplpref}cprefJ pref11*lprefprefprefIpref2Vh pref^ pref prefbprefz>prefRprefw$pref;K 3bpref `8prefB pref+prefm pref{+ prefSprefprefλpref+.prefI preflnyquist-3.05/macproject/NyquistIcon.sit0000644000175000000620000000262010144436365017326 0ustar stevestaffSIT!rLau, NyquistIcon,'B7`@TEXTttxt 11]lmmP#D"rNTJ'~@&ZC-~(KЦl1M5nIJi=ڡ&U'E[GMst3EÓEhcoz{1p*9}vCQKݓKar]ݎpыaڏ0Un;G+9C#|ۻd=oJnuʺ>ߧ4ʿ1W|V.NŖ(I9ܚ,6B,-c4KVV?5n˽ΛCOv.wYvVpŝy·Y:z-,% `w&6ȧ"TL(0fy4Pn{񓟄6&4E8:ηql֚E؎L|p$O43ϝ >Obf+Ogi3 ~{l:߰.A߽?}m { x+Q N-crӪOU },/Oߪ[x~HO G T鿅M?~zI-~wRD&ăZ~v >}N|}ƿ%†wFpTh9- D!`t$**S;"r@0l }ODT [߲qЎɽuO5[syIDyo(zҟM{{Nq/UOCǻrK^}]c[S\mkv-Ћxosͽ%CܜܜsŇpLr;p׿-~#V.^94uH*Am>97{|:lvΧp׮< W#'ʿu1ow^2ԟ}롩ONC?x?x'џL}?ړ<yקп82vR@Lt,=>C)碏G?]7=GRV{-(L51l(VThis file's resource fork holds the Nyquist Icon.nyquist-3.05/macproject/nyquist.mcp0000644000175000000620000050553310144436365016550 0ustar stevestaffcool(}~ `CodeWarrior ProjectjOUPj=introduced method UU ?a  MacHeaders.h * * MacOS Toolbox DEBUG 68K????APPLX????U { Merge Out????APPLDLGXckidProjWSPCRE  MacHeaders.h JavaClasses.zipZIP JAVA Merge Out????APPLDLGXckidProjWSPC __sta__start__sta__startJavaClasses.zipZIP JAVAJavaClasses.zipZIP JAVAMSIEInternet ExplorerIexplore.exe a.out@U {MSIEInternet ExplorerIexplore.exe a.out@U { a.out@U {MSIEInternet ExplorerIexplore.exeabcd]`efg\_hijklmnopqrstu^vwxyBCDE>AFGH=@IJKLMNOPQRSTUV?WXYZ$%&' #()*"+,-./012345678!9:;<~z}y|{  `abc\_def[^ghijklmnopqrst]uvwx%&'() #*+,$"-./01234567!JKLMNOPQR89:;<=>?@ABCDE FGHI&'()"%*+,!$-./01234567# S  TUVW  XYZ[>?@AB9<CDE8=;FGHIJKLMNOP:     WXYZ[RU\]^QVT_`abcdefghiS{~z}|ɻ"ɻ"????Basic Toolbox Multi:Custom KeywordsBasic Toolbox Multi:Access PathsBasic Toolbox Multi:Target SettingsBasic Toolbox Multi:File MappingsBasic Toolbox Multi:Build ExtrasBasic Toolbox Multi:68K CodeGenBasic Toolbox Multi:68K DisassemblerBasic Toolbox Multi:68K LinkerBasic Toolbox Multi:68K ProjectBasic Toolbox Multi:C/C++ CompilerBasic Toolbox Multi:C/C++ WarningsBasic Toolbox Multi:CFM68KBasic Toolbox Multi:IR OptimizerBasic Toolbox Multi:Java OutputBasic Toolbox Multi:Java ProjectBasic Toolbox Multi:Java VMBasic Toolbox Multi:MacOS Merge PanelBasic Toolbox Multi:Pascal CompilerBasic Toolbox Multi:Pascal WarningsBasic Toolbox Multi:PPC CodeGenBasic Toolbox Multi:PPC DisassemblerBasic Toolbox Multi:PPC LinkerBasic Toolbox Multi:PPC PEFBasic Toolbox Multi:PPC ProjectBasic Toolbox Multi:PPCAsm PanelBasic Toolbox Multi:Rez CompilerBasic Toolbox Multi:WinRC CompilerBasic Toolbox Multi:x86 CodeGenBasic Toolbox Multi:x86 LinkerBasic Toolbox Multi:x86 ProjectProject File ListBasic Toolbox 68k:Custom KeywordsBasic Toolbox 68k:Access PathsBasic Toolbox 68k:Target SettingsBasic Toolbox 68k:File MappingsBasic Toolbox 68k:Build ExtrasBasic Toolbox 68k:68K CodeGenBasic Toolbox 68k:68K DisassemblerBasic Toolbox 68k:68K LinkerBasic Toolbox 68k:68K ProjectBasic Toolbox 68k:C/C++ CompilerBasic Toolbox 68k:C/C++ WarningsBasic Toolbox 68k:CFM68KBasic Toolbox 68k:IR OptimizerBasic Toolbox 68k:Java OutputBasic Toolbox 68k:Java ProjectBasic Toolbox 68k:Java VMBasic Toolbox 68k:MacOS Merge PanelBasic Toolbox 68k:Pascal CompilerBasic Toolbox 68k:Pascal WarningsBasic Toolbox 68k:PPC CodeGenBasic Toolbox 68k:PPC DisassemblerBasic Toolbox 68k:PPC LinkerBasic Toolbox 68k:PPC PEFBasic Toolbox 68k:PPC ProjectBasic Toolbox 68k:PPCAsm PanelBasic Toolbox 68k:Rez CompilerBasic Toolbox 68k:WinRC CompilerBasic Toolbox 68k:x86 CodeGenBasic Toolbox 68k:x86 LinkerBasic Toolbox 68k:x86 ProjectBasci Toolbox PPC:Custom KeywordsBasci Toolbox PPC:Access PathsBasci Toolbox PPC:Target SettingsBasci Toolbox PPC:File MappingsBasci Toolbox PPC:Build ExtrasBasci Toolbox PPC:68K CodeGenBasci Toolbox PPC:68K DisassemblerBasci Toolbox PPC:68K LinkerBasci Toolbox PPC:68K ProjectBasci Toolbox PPC:C/C++ CompilerBasci Toolbox PPC:C/C++ WarningsBasci Toolbox PPC:CFM68KBasci Toolbox PPC:IR OptimizerBasci Toolbox PPC:Java OutputBasci Toolbox PPC:Java ProjectBasci Toolbox PPC:Java VMBasci Toolbox PPC:MacOS Merge PanelBasci Toolbox PPC:Pascal CompilerBasci Toolbox PPC:Pascal WarningsBasci Toolbox PPC:PPC CodeGenBasci Toolbox PPC:PPC DisassemblerBasci Toolbox PPC:PPC LinkerBasci Toolbox PPC:PPC PEFBasci Toolbox PPC:PPC ProjectBasci Toolbox PPC:PPCAsm PanelBasci Toolbox PPC:Rez CompilerBasci Toolbox PPC:WinRC CompilerBasci Toolbox PPC:x86 CodeGenBasci Toolbox PPC:x86 LinkerBasci Toolbox PPC:x86 ProjectBasic Toolbox PPC:Custom KeywordsBasic Toolbox PPC:Access PathsBasic Toolbox PPC:Target SettingsBasic Toolbox PPC:File MappingsBasic Toolbox PPC:Build ExtrasBasic Toolbox PPC:68K CodeGenBasic Toolbox PPC:68K DisassemblerBasic Toolbox PPC:68K LinkerBasic Toolbox PPC:68K ProjectBasic Toolbox PPC:C/C++ CompilerBasic Toolbox PPC:C/C++ WarningsBasic Toolbox PPC:CFM68KBasic Toolbox PPC:IR OptimizerBasic Toolbox PPC:Java OutputBasic Toolbox PPC:Java ProjectBasic Toolbox PPC:Java VMBasic Toolbox PPC:MacOS Merge PanelBasic Toolbox PPC:Pascal CompilerBasic Toolbox PPC:Pascal WarningsBasic Toolbox PPC:PPC CodeGenBasic Toolbox PPC:PPC DisassemblerBasic Toolbox PPC:PPC LinkerBasic Toolbox PPC:PPC PEFBasic Toolbox PPC:PPC ProjectBasic Toolbox PPC:PPCAsm PanelBasic Toolbox PPC:Rez CompilerBasic Toolbox PPC:WinRC CompilerBasic Toolbox PPC:x86 CodeGenBasic Toolbox PPC:x86 LinkerBasic Toolbox PPC:x86 ProjectBasic Toolbox FAT:Custom KeywordsBasic Toolbox FAT:Access PathsBasic Toolbox FAT:Target SettingsBasic Toolbox FAT:File MappingsBasic Toolbox FAT:Build ExtrasBasic Toolbox FAT:68K CodeGenBasic Toolbox FAT:68K DisassemblerBasic Toolbox FAT:68K LinkerBasic Toolbox FAT:68K ProjectBasic Toolbox FAT:C/C++ CompilerBasic Toolbox FAT:C/C++ WarningsBasic Toolbox FAT:CFM68KBasic Toolbox FAT:IR OptimizerBasic Toolbox FAT:Java OutputBasic Toolbox FAT:Java ProjectBasic Toolbox FAT:Java VMBasic Toolbox FAT:MacOS Merge PanelBasic Toolbox FAT:Pascal CompilerBasic Toolbox FAT:Pascal WarningsBasic Toolbox FAT:PPC CodeGenBasic Toolbox FAT:PPC DisassemblerBasic Toolbox FAT:PPC LinkerBasic Toolbox FAT:PPC PEFBasic Toolbox FAT:PPC ProjectBasic Toolbox FAT:PPCAsm PanelBasic Toolbox FAT:Rez CompilerBasic Toolbox FAT:WinRC CompilerBasic Toolbox FAT:x86 CodeGenBasic Toolbox FAT:x86 LinkerBasic Toolbox FAT:x86 ProjectBasic Toolbox DEBUG 68k:Custom KeywordsBasic Toolbox DEBUG 68k:Access PathsBasic Toolbox DEBUG 68k:Target SettingsBasic Toolbox DEBUG 68k:File MappingsBasic Toolbox DEBUG 68k:Build ExtrasBasic Toolbox DEBUG 68k:68K CodeGenBasic Toolbox DEBUG 68k:68K DisassemblerBasic Toolbox DEBUG 68k:68K LinkerBasic Toolbox DEBUG 68k:68K ProjectBasic Toolbox DEBUG 68k:C/C++ CompilerBasic Toolbox DEBUG 68k:C/C++ WarningsBasic Toolbox DEBUG 68k:CFM68KBasic Toolbox DEBUG 68k:IR OptimizerBasic Toolbox DEBUG 68k:MacOS Merge PanelBasic Toolbox DEBUG 68k:Pascal CompilerBasic Toolbox DEBUG 68k:Pascal WarningsBasic Toolbox DEBUG 68k:PPC CodeGenBasic Toolbox DEBUG 68k:PPC DisassemblerBasic Toolbox DEBUG 68k:PPC LinkerBasic Toolbox DEBUG 68k:PPC PEFBasic Toolbox DEBUG 68k:PPC ProjectBasic Toolbox DEBUG 68k:PPCAsm PanelBasic Toolbox DEBUG 68k:Rez CompilerBasic Toolbox DEBUG PPC:Custom KeywordsBasic Toolbox DEBUG PPC:Access PathsBasic Toolbox DEBUG PPC:Target SettingsBasic Toolbox DEBUG PPC:File MappingsBasic Toolbox DEBUG PPC:Build ExtrasBasic Toolbox DEBUG PPC:68K CodeGenBasic Toolbox DEBUG PPC:68K DisassemblerBasic Toolbox DEBUG PPC:68K LinkerBasic Toolbox DEBUG PPC:68K ProjectBasic Toolbox DEBUG PPC:C/C++ CompilerBasic Toolbox DEBUG PPC:C/C++ WarningsBasic Toolbox DEBUG PPC:CFM68KBasic Toolbox DEBUG PPC:IR OptimizerBasic Toolbox DEBUG PPC:MacOS Merge PanelBasic Toolbox DEBUG PPC:Pascal CompilerBasic Toolbox DEBUG PPC:Pascal WarningsBasic Toolbox DEBUG PPC:PPC CodeGenBasic Toolbox DEBUG PPC:PPC DisassemblerBasic Toolbox DEBUG PPC:PPC LinkerBasic Toolbox DEBUG PPC:PPC PEFBasic Toolbox DEBUG PPC:PPC ProjectBasic Toolbox DEBUG PPC:PPCAsm PanelBasic Toolbox DEBUG PPC:Rez CompilerMacOS Toolbox 68K:Custom KeywordsMacOS Toolbox 68K:Access PathsMacOS Toolbox 68K:Target SettingsMacOS Toolbox 68K:File MappingsMacOS Toolbox 68K:Build ExtrasMacOS Toolbox 68K:68K CodeGenMacOS Toolbox 68K:68K DisassemblerMacOS Toolbox 68K:68K LinkerMacOS Toolbox 68K:68K ProjectMacOS Toolbox 68K:C/C++ CompilerMacOS Toolbox 68K:C/C++ WarningsMacOS Toolbox 68K:CFM68KMacOS Toolbox 68K:IR OptimizerMacOS Toolbox 68K:MacOS Merge PanelMacOS Toolbox 68K:Pascal CompilerMacOS Toolbox 68K:Pascal WarningsMacOS Toolbox 68K:PPC CodeGenMacOS Toolbox 68K:PPC DisassemblerMacOS Toolbox 68K:PPC LinkerMacOS Toolbox 68K:PPC PEFMacOS Toolbox 68K:PPC ProjectMacOS Toolbox 68K:PPCAsm PanelMacOS Toolbox 68K:Rez CompilerMacOS Toolbox DEBUG 68K:Custom KeywordsMacOS Toolbox DEBUG 68K:Access PathsMacOS Toolbox DEBUG 68K:Target SettingsMacOS Toolbox DEBUG 68K:File MappingsMacOS Toolbox DEBUG 68K:Build ExtrasMacOS Toolbox DEBUG 68K:68K CodeGenMacOS Toolbox DEBUG 68K:68K DisassemblerMacOS Toolbox DEBUG 68K:68K LinkerMacOS Toolbox DEBUG 68K:68K ProjectMacOS Toolbox DEBUG 68K:C/C++ CompilerMacOS Toolbox DEBUG 68K:C/C++ WarningsMacOS Toolbox DEBUG 68K:CFM68KMacOS Toolbox DEBUG 68K:IR OptimizerMacOS Toolbox DEBUG 68K:MacOS Merge PanelMacOS Toolbox DEBUG 68K:Pascal CompilerMacOS Toolbox DEBUG 68K:Pascal WarningsMacOS Toolbox DEBUG 68K:PPC CodeGenMacOS Toolbox DEBUG 68K:PPC DisassemblerMacOS Toolbox DEBUG 68K:PPC LinkerMacOS Toolbox DEBUG 68K:PPC PEFMacOS Toolbox DEBUG 68K:PPC ProjectMacOS Toolbox DEBUG 68K:PPCAsm PanelMacOS Toolbox DEBUG 68K:Rez CompilerMacOS Toolbox DEBUG PPC:Custom KeywordsMacOS Toolbox DEBUG PPC:Access PathsMacOS Toolbox DEBUG PPC:Target SettingsMacOS Toolbox DEBUG PPC:File MappingsMacOS Toolbox DEBUG PPC:Build ExtrasMacOS Toolbox DEBUG PPC:68K CodeGenMacOS Toolbox DEBUG PPC:68K DisassemblerMacOS Toolbox DEBUG PPC:68K LinkerMacOS Toolbox DEBUG PPC:68K ProjectMacOS Toolbox DEBUG PPC:C/C++ CompilerMacOS Toolbox DEBUG PPC:C/C++ WarningsMacOS Toolbox DEBUG PPC:CFM68KMacOS Toolbox DEBUG PPC:IR OptimizerMacOS Toolbox DEBUG PPC:MacOS Merge PanelMacOS Toolbox DEBUG PPC:Pascal CompilerMacOS Toolbox DEBUG PPC:Pascal WarningsMacOS Toolbox DEBUG PPC:PPC CodeGenMacOS Toolbox DEBUG PPC:PPC DisassemblerMacOS Toolbox DEBUG PPC:PPC LinkerMacOS Toolbox DEBUG PPC:PPC PEFMacOS Toolbox DEBUG PPC:PPC ProjectMacOS Toolbox DEBUG PPC:PPCAsm PanelMacOS Toolbox DEBUG PPC:Rez CompilerMacOS Toolbox PPC:Custom KeywordsMacOS Toolbox PPC:Access PathsMacOS Toolbox PPC:Target SettingsMacOS Toolbox PPC:File MappingsMacOS Toolbox PPC:Build ExtrasMacOS Toolbox PPC:68K CodeGenMacOS Toolbox PPC:68K DisassemblerMacOS Toolbox PPC:68K LinkerMacOS Toolbox PPC:68K ProjectMacOS Toolbox PPC:C/C++ CompilerMacOS Toolbox PPC:C/C++ WarningsMacOS Toolbox PPC:CFM68KMacOS Toolbox PPC:IR OptimizerMacOS Toolbox PPC:MacOS Merge PanelMacOS Toolbox PPC:Pascal CompilerMacOS Toolbox PPC:Pascal WarningsMacOS Toolbox PPC:PPC CodeGenMacOS Toolbox PPC:PPC DisassemblerMacOS Toolbox PPC:PPC LinkerMacOS Toolbox PPC:PPC PEFMacOS Toolbox PPC:PPC ProjectMacOS Toolbox PPC:PPCAsm PanelMacOS Toolbox PPC:Rez CompilerMacOS Toolbox FAT:Custom KeywordsMacOS Toolbox FAT:Access PathsMacOS Toolbox FAT:Target SettingsMacOS Toolbox FAT:File MappingsMacOS Toolbox FAT:Build ExtrasMacOS Toolbox FAT:68K CodeGenMacOS Toolbox FAT:68K DisassemblerMacOS Toolbox FAT:68K LinkerMacOS Toolbox FAT:68K ProjectMacOS Toolbox FAT:C/C++ CompilerMacOS Toolbox FAT:C/C++ WarningsMacOS Toolbox FAT:CFM68KMacOS Toolbox FAT:IR OptimizerMacOS Toolbox FAT:MacOS Merge PanelMacOS Toolbox FAT:Pascal CompilerMacOS Toolbox FAT:Pascal WarningsMacOS Toolbox FAT:PPC CodeGenMacOS Toolbox FAT:PPC DisassemblerMacOS Toolbox FAT:PPC LinkerMacOS Toolbox FAT:PPC PEFMacOS Toolbox FAT:PPC ProjectMacOS Toolbox FAT:PPCAsm PanelMacOS Toolbox FAT:Rez CompilerMacOS Toolbox DEBUG 68K:Bison PanelMacOS Toolbox DEBUG 68K:Flex PanelMacOS Toolbox DEBUG 68K:Java OutputMacOS Toolbox DEBUG 68K:Java ProjectMacOS Toolbox DEBUG 68K:Java VMMacOS Toolbox DEBUG 68K:WinRC CompilerMacOS Toolbox DEBUG 68K:x86 CodeGenMacOS Toolbox DEBUG 68K:x86 LinkerMacOS Toolbox DEBUG 68K:x86 ProjectMacOS Toolbox DEBUG PPC:Bison PanelMacOS Toolbox DEBUG PPC:Flex PanelMacOS Toolbox DEBUG PPC:Java OutputMacOS Toolbox DEBUG PPC:Java ProjectMacOS Toolbox DEBUG PPC:Java VMMacOS Toolbox DEBUG PPC:WinRC CompilerMacOS Toolbox DEBUG PPC:x86 CodeGenMacOS Toolbox DEBUG PPC:x86 LinkerMacOS Toolbox DEBUG PPC:x86 ProjectMacOS Toolbox 68K:Bison PanelMacOS Toolbox 68K:Flex PanelMacOS Toolbox 68K:Java OutputMacOS Toolbox 68K:Java ProjectMacOS Toolbox 68K:Java VMMacOS Toolbox 68K:WinRC CompilerMacOS Toolbox 68K:x86 CodeGenMacOS Toolbox 68K:x86 LinkerMacOS Toolbox 68K:x86 ProjectMacOS Toolbox PPC:Bison PanelMacOS Toolbox PPC:Flex PanelMacOS Toolbox PPC:Java OutputMacOS Toolbox PPC:Java ProjectMacOS Toolbox PPC:Java VMMacOS Toolbox PPC:WinRC CompilerMacOS Toolbox PPC:x86 CodeGenMacOS Toolbox PPC:x86 LinkerMacOS Toolbox PPC:x86 Project68K Debug MacOS Toolbox:Custom Keywords68K Debug MacOS Toolbox:Access Paths68K Debug MacOS Toolbox:Target Settings68K Debug MacOS Toolbox:File Mappings68K Debug MacOS Toolbox:Build Extras68K Debug MacOS Toolbox:68K CodeGen68K Debug MacOS Toolbox:68K Disassembler68K Debug MacOS Toolbox:68K Linker68K Debug MacOS Toolbox:68K Project68K Debug MacOS Toolbox:C/C++ Compiler68K Debug MacOS Toolbox:C/C++ Warnings68K Debug MacOS Toolbox:CFM68K68K Debug MacOS Toolbox:IR Optimizer68K Debug MacOS Toolbox:Java Output68K Debug MacOS Toolbox:Java Project68K Debug MacOS Toolbox:Java VM68K Debug MacOS Toolbox:MacOS Merge Panel68K Debug MacOS Toolbox:Pascal Compiler68K Debug MacOS Toolbox:Pascal Warnings68K Debug MacOS Toolbox:PPC CodeGen68K Debug MacOS Toolbox:PPC Disassembler68K Debug MacOS Toolbox:PPC Linker68K Debug MacOS Toolbox:PPC PEF68K Debug MacOS Toolbox:PPC Project68K Debug MacOS Toolbox:PPCAsm Panel68K Debug MacOS Toolbox:Rez Compiler68K Debug MacOS Toolbox:WinRC Compiler68K Debug MacOS Toolbox:x86 CodeGen68K Debug MacOS Toolbox:x86 Linker68K Debug MacOS Toolbox:x86 ProjectPPC Debug MacOS Toolbox:Custom KeywordsPPC Debug MacOS Toolbox:Access PathsPPC Debug MacOS Toolbox:Target SettingsPPC Debug MacOS Toolbox:File MappingsPPC Debug MacOS Toolbox:Build ExtrasPPC Debug MacOS Toolbox:68K CodeGenPPC Debug MacOS Toolbox:68K DisassemblerPPC Debug MacOS Toolbox:68K LinkerPPC Debug MacOS Toolbox:68K ProjectPPC Debug MacOS Toolbox:C/C++ CompilerPPC Debug MacOS Toolbox:C/C++ WarningsPPC Debug MacOS Toolbox:CFM68KPPC Debug MacOS Toolbox:IR OptimizerPPC Debug MacOS Toolbox:Java OutputPPC Debug MacOS Toolbox:Java ProjectPPC Debug MacOS Toolbox:Java VMPPC Debug MacOS Toolbox:MacOS Merge PanelPPC Debug MacOS Toolbox:Pascal CompilerPPC Debug MacOS Toolbox:Pascal WarningsPPC Debug MacOS Toolbox:PPC CodeGenPPC Debug MacOS Toolbox:PPC DisassemblerPPC Debug MacOS Toolbox:PPC LinkerPPC Debug MacOS Toolbox:PPC PEFPPC Debug MacOS Toolbox:PPC ProjectPPC Debug MacOS Toolbox:PPCAsm PanelPPC Debug MacOS Toolbox:Rez CompilerPPC Debug MacOS Toolbox:WinRC CompilerPPC Debug MacOS Toolbox:x86 CodeGenPPC Debug MacOS Toolbox:x86 LinkerPPC Debug MacOS Toolbox:x86 Project68K Final MacOS Toolbox:Custom Keywords68K Final MacOS Toolbox:Access Paths68K Final MacOS Toolbox:Target Settings68K Final MacOS Toolbox:File Mappings68K Final MacOS Toolbox:Build Extras68K Final MacOS Toolbox:68K CodeGen68K Final MacOS Toolbox:68K Disassembler68K Final MacOS Toolbox:68K Linker68K Final MacOS Toolbox:68K Project68K Final MacOS Toolbox:C/C++ Compiler68K Final MacOS Toolbox:C/C++ Warnings68K Final MacOS Toolbox:CFM68K68K Final MacOS Toolbox:IR Optimizer68K Final MacOS Toolbox:Java Output68K Final MacOS Toolbox:Java Project68K Final MacOS Toolbox:Java VM68K Final MacOS Toolbox:MacOS Merge Panel68K Final MacOS Toolbox:Pascal Compiler68K Final MacOS Toolbox:Pascal Warnings68K Final MacOS Toolbox:PPC CodeGen68K Final MacOS Toolbox:PPC Disassembler68K Final MacOS Toolbox:PPC Linker68K Final MacOS Toolbox:PPC PEF68K Final MacOS Toolbox:PPC Project68K Final MacOS Toolbox:PPCAsm Panel68K Final MacOS Toolbox:Rez Compiler68K Final MacOS Toolbox:WinRC Compiler68K Final MacOS Toolbox:x86 CodeGen68K Final MacOS Toolbox:x86 Linker68K Final MacOS Toolbox:x86 ProjectPPC Final MacOS Toolbox:Custom KeywordsPPC Final MacOS Toolbox:Access PathsPPC Final MacOS Toolbox:Target SettingsPPC Final MacOS Toolbox:File MappingsPPC Final MacOS Toolbox:Build ExtrasPPC Final MacOS Toolbox:68K CodeGenPPC Final MacOS Toolbox:68K DisassemblerPPC Final MacOS Toolbox:68K LinkerPPC Final MacOS Toolbox:68K ProjectPPC Final MacOS Toolbox:C/C++ CompilerPPC Final MacOS Toolbox:C/C++ WarningsPPC Final MacOS Toolbox:CFM68KPPC Final MacOS Toolbox:IR OptimizerPPC Final MacOS Toolbox:Java OutputPPC Final MacOS Toolbox:Java ProjectPPC Final MacOS Toolbox:Java VMPPC Final MacOS Toolbox:MacOS Merge PanelPPC Final MacOS Toolbox:Pascal CompilerPPC Final MacOS Toolbox:Pascal WarningsPPC Final MacOS Toolbox:PPC CodeGenPPC Final MacOS Toolbox:PPC DisassemblerPPC Final MacOS Toolbox:PPC LinkerPPC Final MacOS Toolbox:PPC PEFPPC Final MacOS Toolbox:PPC ProjectPPC Final MacOS Toolbox:PPCAsm PanelPPC Final MacOS Toolbox:Rez CompilerPPC Final MacOS Toolbox:WinRC CompilerPPC Final MacOS Toolbox:x86 CodeGenPPC Final MacOS Toolbox:x86 LinkerPPC Final MacOS Toolbox:x86 ProjectFAT MacOS Toolbox:Custom KeywordsFAT MacOS Toolbox:Access PathsFAT MacOS Toolbox:Target SettingsFAT MacOS Toolbox:File MappingsFAT MacOS Toolbox:Build ExtrasFAT MacOS Toolbox:68K CodeGenFAT MacOS Toolbox:68K DisassemblerFAT MacOS Toolbox:68K LinkerFAT MacOS Toolbox:68K ProjectFAT MacOS Toolbox:C/C++ CompilerFAT MacOS Toolbox:C/C++ WarningsFAT MacOS Toolbox:CFM68KFAT MacOS Toolbox:IR OptimizerFAT MacOS Toolbox:Java OutputFAT MacOS Toolbox:Java ProjectFAT MacOS Toolbox:Java VMFAT MacOS Toolbox:MacOS Merge PanelFAT MacOS Toolbox:Pascal CompilerFAT MacOS Toolbox:Pascal WarningsFAT MacOS Toolbox:PPC CodeGenFAT MacOS Toolbox:PPC DisassemblerFAT MacOS Toolbox:PPC LinkerFAT MacOS Toolbox:PPC PEFFAT MacOS Toolbox:PPC ProjectFAT MacOS Toolbox:PPCAsm PanelFAT MacOS Toolbox:Rez CompilerFAT MacOS Toolbox:WinRC CompilerFAT MacOS Toolbox:x86 CodeGenFAT MacOS Toolbox:x86 LinkerFAT MacOS Toolbox:x86 ProjectPPC Debug MacOS Toolbox:Java LanguagePPC Final MacOS Toolbox:Java LanguagePPC Debug MacOS Toolbox:Debugger TargetPPC Debug MacOS Toolbox:FTP PanelPPC Debug MacOS Toolbox:JavaDoc ProjectPPC Debug MacOS Toolbox:x86 Exceptions PanelPPC Final MacOS Toolbox:Debugger TargetPPC Final MacOS Toolbox:FTP PanelPPC Final MacOS Toolbox:JavaDoc ProjectPPC Final MacOS Toolbox:x86 Exceptions PanelPPC Debug MacOS Toolbox:68K Global OptimizerPPC Debug MacOS Toolbox:PPC Global OptimizerPPC Final MacOS Toolbox:68K Global OptimizerPPC Final MacOS Toolbox:PPC Global OptimizerPPC Debug MacOS Toolbox:Java Command LinePPC Debug MacOS Toolbox:Java MacOS SettingsPPC Debug MacOS Toolbox:x86 Global OptimizerPPC Final MacOS Toolbox:Java Command LinePPC Final MacOS Toolbox:Java MacOS SettingsPPC Final MacOS Toolbox:x86 Global OptimizerNyquist:Custom KeywordsNyquist:Access PathsNyquist:Target SettingsNyquist:File MappingsNyquist:Build ExtrasNyquist:Debugger TargetNyquist:68K CodeGenNyquist:68K DisassemblerNyquist:68K Global OptimizerNyquist:68K LinkerNyquist:68K ProjectNyquist:C/C++ CompilerNyquist:C/C++ WarningsNyquist:CFM68KNyquist:MacOS Merge PanelNyquist:Pascal CompilerNyquist:Pascal WarningsNyquist:PPC CodeGenNyquist:PPC DisassemblerNyquist:PPC Global OptimizerNyquist:PPC LinkerNyquist:PPC PEFNyquist:PPC ProjectNyquist:PPCAsm PanelNyquist:Rez CompilerDebug:Custom KeywordsDebug:Access PathsDebug:Target SettingsDebug:File MappingsDebug:Build ExtrasDebug:Debugger TargetDebug:68K CodeGenDebug:68K DisassemblerDebug:68K Global OptimizerDebug:68K LinkerDebug:68K ProjectDebug:C/C++ CompilerDebug:C/C++ WarningsDebug:CFM68KDebug:MacOS Merge PanelDebug:Pascal CompilerDebug:Pascal WarningsDebug:PPC CodeGenDebug:PPC DisassemblerDebug:PPC Global OptimizerDebug:PPC LinkerDebug:PPC PEFDebug:PPC ProjectDebug:PPCAsm PanelDebug:Rez CompilerNyquist Optimized:Custom KeywordsNyquist Optimized:Access PathsNyquist Optimized:Target SettingsNyquist Optimized:File MappingsNyquist Optimized:Build ExtrasNyquist Optimized:Debugger TargetNyquist Optimized:68K CodeGenNyquist Optimized:68K DisassemblerNyquist Optimized:68K Global OptimizerNyquist Optimized:68K LinkerNyquist Optimized:68K ProjectNyquist Optimized:C/C++ CompilerNyquist Optimized:C/C++ WarningsNyquist Optimized:CFM68KNyquist Optimized:MacOS Merge PanelNyquist Optimized:Pascal CompilerNyquist Optimized:Pascal WarningsNyquist Optimized:PPC CodeGenNyquist Optimized:PPC DisassemblerNyquist Optimized:PPC Global OptimizerNyquist Optimized:PPC LinkerNyquist Optimized:PPC PEFNyquist Optimized:PPC ProjectNyquist Optimized:PPCAsm PanelNyquist Optimized:Rez CompilerNyquistDebug:Custom KeywordsNyquistDebug:Access PathsNyquistDebug:Target SettingsNyquistDebug:File MappingsNyquistDebug:Build ExtrasNyquistDebug:Debugger TargetNyquistDebug:68K CodeGenNyquistDebug:68K DisassemblerNyquistDebug:68K Global OptimizerNyquistDebug:68K LinkerNyquistDebug:68K ProjectNyquistDebug:C/C++ CompilerNyquistDebug:C/C++ WarningsNyquistDebug:CFM68KNyquistDebug:MacOS Merge PanelNyquistDebug:Pascal CompilerNyquistDebug:Pascal WarningsNyquistDebug:PPC CodeGenNyquistDebug:PPC DisassemblerNyquistDebug:PPC Global OptimizerNyquistDebug:PPC LinkerNyquistDebug:PPC PEFNyquistDebug:PPC ProjectNyquistDebug:PPCAsm PanelNyquistDebug:Rez Compilerreg$EillDi5 GettMoutDiadDia Dial0 ialoS wDiav ialo xt Iventelecalogalog5DialYItem}topAeAleonAldAlelertxt E>dGe_etDITextt MogDeurce urge!4"ndedV#istv$5%&'() 2*_casS+50l,-reg./illD05 1Get(2tMouJ3tDiah4dDia5Dial6ialo7wDia8ialo9xt I:vent?;elec]Dial?Item@topAABonAl:CdAleXDlert{Ext EFdGeGetDIHTextIt Mo JgDe 0Kurce NLurge mM N O P Q R 0S MT gU V W X Get Y Zc To [lti =\gmen _]Lib ~^68K _rt 6 `on H a bPasc cezP =dt 68 [e! |f! g! h! i! j! k! ,l! Pm! rn! o! p! q! r! s!*t!Iu!hv!Hw6~pxeycallzBC{HI#|NOE}TUe~Z[`afgndedist!TargBct D[Settz SeteSaf _cas509regWzillD5 GettMoutDia dDia.DialLialoiwDiaialoxt Iventelec"alogGalogkDialItemtopA)Hm 4Ww 2Z9`EiCe&Ca!Ca?d$Gk'Ow+Pu  5 Y !!6![!!!!"""E"e" " " " # #6#V#u####$$3$L$k$$$$%%1%K%i %!%"%#%$& %&*&&I'&g(&)&*&+&,'-' .'?/'c0'1'2'3'4(5(6(=7(\8({9(:(;(<) =)+>)R?)v@)A)B)C*D*(E*MF*mG*H*I*J*K+L+:M+XN+wO+P+Q+R+S, T,)U,FV,dW,X,Y,Z,[,\-]-?^-d_-`-a-b-c.$d.Ge.kf.g.h.i.j/!k/Fl/fm/n/o/p0q0-r0Ps0pt0u0v0w1x1)y1Lz1p{1|1}1~2 202T2}2223313V3z3334494]44445575^555566>6d666677D7k777788B8j88899"9F9k9999:":J:o:::;;/;R;v;;;<<,>4>W>{>>>>??;?^?{????@@1@P@j@@@@AA0AJAhAAAABB BFBlBBBC C3CUC}CCDD1D^DDDE E7EdE|E E E E E FFF6FIF]FtFFFFFFGG.GAGQGeGzG G!G"G#G$G%H &H'H4(HO)H`*Hr+H,H-H.H/H0H1H2I3I14IB5IP6Ib7Iu8I9I:I;I<J =J*>JL?Jj@JAJBJCJDKEK1FKJGKnHKIKJKKKLLML7NLQOLoPLQLRLSLTMUMVM6WMSXMlYMZM[M\M]M^N_N)`NHaNebNcNdNeNfNgOhO!iO;jBasic Toolbox MultiFirst Segment:a.outLib Import 68KMPW Import 68KBalloon HelpMW C/C++ 68KMW Pascal 68KRezPEF Import 68KBasic Toolbox 68k:Toolbox68k.outBasci Toolbox PPCBasic Toolbox PPCLib Import PPCMW C/C++ PPCMW Pascal PPCPPCAsmXCOFF Import PPCPEF Import PPC:ToolboxPPC.outSillyBalls.cSillyBalls.rsrcInterfaceLibMathLibMSL RuntimePPC.LibMSL C.PPC.LibMSL C++.PPC.LibMacOS.libMathLib68K Fa(4i/8d).LibMSL Runtime68K.LibMSL C.68K Fa(4i_8d).LibMSL C++.68K Fa(4i_8d).LibBasic Toolbox FAT:Merge Out:ToolboxFAT.outToolbox68k.outToolboxPPC.outMathLib68K Fa(4i_8d).LibMSL SIOUX.68K.LibMSL SIOUX.PPC.Lib:Toolbox68k:ToolboxPPC:ToolboxFAT:Basic Toolbox DEBUG 68kBasic Toolbox DEBUG 68k:Basic Toolbox DEBUG PPCBasic Toolbox DEBUG PPCMacOS Toolbox 68K:MacOS Toolbox DEBUG 68KMacOS Toolbox DEBUG 68K:MacOS Toolbox DEBUG PPCMacOS Toolbox DEBUG PPC:MacOS Toolbox 68K:MacOS Toolbox PPCMacOS Toolbox PPCMacOS Toolbox FAT:MacOS Toolbox FATGameCode ConverterFlex PreprocessorBison PreprocessorMSL C.68K (2i).LibMSL C++.68K (2i).LibMathLib68K (2i).Lib68K Debug MacOS ToolboxPPC Debug MacOS Toolbox68K Final MacOS ToolboxPPC Final MacOS ToolboxFAT MacOS ToolboxApplicationLibrariesMac LibrariesANSI Libraries:SillyBalls.c:SillyBalls.rsrc:Bin:MSL C.PPC.Lib:Bin:MSL C++.PPC.Lib:MacOS Common:InterfaceLib:MacOS Common:MathLib:Runtime:Runtime PPC:MSL RuntimePPC.Lib:Bin:MSL SIOUX.PPC.LibMacOS PPC LinkerCustom KeywordsAccess PathsTarget SettingsFile MappingsBuild ExtrasDebugger TargetC/C++ CompilerC/C++ WarningsFTP PanelIR OptimizerPascal CompilerPascal WarningsPPC CodeGenPPC DisassemblerPPC LinkerPPC PEFPPC ProjectPPCAsm PanelRez CompilerPPC Global Optimizeradd.cadd.havg.cavg.hcompose.ccompose.hcque.hdebug.cdebug.hdownsample.cdownsample.hfalloc.cfalloc.hffilterkit.cffilterkit.hfresample.hhandlers.cinverse.cinverse.hlocal.clocaldefs.hlocalptrs.hmultiread.cmultiread.hmultiseq.cmultiseq.hprobe.cprobe.hresamp.cresamp.hresampv.cresampv.hrfftw.hsamples.csamples.hseqext.cseqext.hseqfnint.cseqfnintdefs.hseqfnintptrs.hseqinterf.cseqinterf.hsndfail.csndfnint.csndfnintdefs.hsndfnintptrs.hsndmax.csndmax.hsndread.csndread.hsndseq.csndseq.hsndwrite.csndwrite.hsound.csound.hstats.cstdefs.hfftn.cfftn.hextern.cextern.hosdefs.hosptrs.hxlbfun.cxlcont.cxldbug.cxldmem.cxldmem.hxleval.cxlfio.cxlftab.cxlglob.cxlimage.cxlinit.cxlio.cxlisp.cxlisp.hxljump.cxllist.cxlmath.cxlobj.cxlpp.cxlprin.cxlread.cxlstr.cxlsubr.cxlsym.cxlsys.calpass.calpass.hamosc.camosc.hareson.careson.haresoncv.caresoncv.haresonvc.caresonvc.haresonvv.caresonvv.hatone.catone.hatonev.catonev.hbiquad.cbiquad.hbuzz.cbuzz.hchase.cchase.hclip.cclip.hcongen.ccongen.hconst.cconst.hconvolve.cconvolve.hcoterm.ccoterm.hdelay.cdelay.hdelaycv.cdelaycv.hexp.cexp.hfmosc.cfmosc.hfollow.cfollow.hfromarraystream.cfromarraystream.hfromobject.cfromobject.hgate.cgate.hifft.cifft.hintegrate.cintegrate.hlog.clog.hmaxv.cmaxv.hoffset.coffset.honeshot.coneshot.hosc.cosc.hpartial.cpartial.hpluck.cpluck.hprod.cprod.hpwl.cpwl.hquant.c.cquant.c.hquantize.cquantize.hrecip.crecip.hreson.creson.hresoncv.cresoncv.hresonvc.cresonvc.hresonvv.cresonvv.hsampler.csampler.hscale.cscale.hshape.cshape.hsine.csine.hsiosc.csiosc.hslope.cslope.htapv.ctapv.htone.ctone.htonev.ctonev.hupsample.cupsample.hwhite.cwhite.hmacaboutbox.cMacAE.cMacCommandWin.cMacDrag.cMacFileUtils.cmacfun.cMacGlobals.hMacHandleEv.cmacint.cmacint.hmacptrs.hmacstuff.csndsystem.hswitches.hcext.ccext.hcleanup.ccleanup.hcmdline.ccmdline.hcmtcmd.ccmtcmd.hhash.hhashrout.hmem.cmem.hmfmidi.hmidicode.hmidierr.hmidifile.cmidifile.hmidifns.cmidifns.hmoxc.cmoxc.hseq.cseq.hseqdecls.hseqmread.cseqmread.hseqmwrite.cseqmwrite.hseqread.cseqread.hseqwrite.cseqwrite.hswlogic.htempomap.ctempomap.htimebase.ctimebase.huserio.cuserio.haudio.caudiomac.caudiomac.hconvert.cieeecvt.cieeecvt.hsnd.csnd.hsndconfig.hsndcvt.csndfileio.hsndhead.hsndheader.csndheader.hsndio.csndmac.csndmac.hsndsystemmac.hdummyif.cdummyif.hmidibuff.hmidimgr.cmidimgr.hxlextstart.cpitch.hrecord.crecord.hfft.cMacDrag.hDragLibNyquist::MacOS Toolbox DEBUG PPC::NyquistDebugDebug:Nyquist::Nyquistnyquist.rsrcFullPath.cNyquist OptimizedNyquistDebugabs.cabs.hsqrt.csqrt.hyin.cyin.h@B}~,.LKPMN51396"OIJ) +#*SfgHE^_`hi -/! <VXY789:;<=>jkalRmnWop{pqqrDstyU;uZ:v?@bcwx[Fyz{G)*+,z-./012Q0248734?&ABCrDEFGHIstJK> ='(|}~|\] v^A_Ce`abc  wx   dLMNOPQRSTUVdefghijklmn5o6W TXYZ[!"#$$%%&\]'(uMacOS PPC LinkerNyquistDebugOS Toolbox:: MacOS Toolbox 68K????APPLX????U {__startNyquistDebugx DEBUG PPC????APPL}>X???? NyquistDebugx PPC????APPL}>X????P'CODE' 'DATA' 'PICT'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     __startP'CODE' 'DATA' 'PICT'      !"#$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#%&'()*MacOS PPC LinkerNyquist Optimizedolbox::  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~           !"#$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#%&'()*__sta__startJavaClasses.jarZIP MWZPMSIEInternet ExplorerIexplore.exe/ uJIT@ڠ:u9uPxZJ MENUbTargSTR#PPobRidLaeteSTR prefFlagTMPLvers Drop"hi _j, .( Q-5@J TP'CODE' 'DATA' 'PICT'  NONAME.EXE@U {!"!)!08*tGT!ao s !P  !p !)6<F!SH[n|@ """"!"#$(!%wi0&?'X(0j) |*8086+ ,H-./\0512-3E4^5v67@89%:";)<*=- >0?33@6GA_BwCDEFGHIJK LM3NNOdPQRSTUVWX YZ*[4\A]Q^a_m`~abcdefghijklmnopq)r2s;tHuUvawlxvyz{|}~  )2=L[gs}    # , 5 > G P Y b k t }     ' 0 8 @ I R ] h s ~    ! , 5 > F N X b h n v ~      % . 8 B H N X b j r y                   & . 6 > F M T \ d l t {! " # $ % & ' ( ) * + , - ./01)223;4E5P6\7g8n9u:;<=>?@ABCDEFGHI JKL#M)N/O:PEQPR\ShTrU|VWXYZ[\]^_`abc def"g.h7iCjMkYlemmnvopqrstuvwxyz{|}~"17@JWbtROOT GRUPMac Interface StuffFILEFILEFILEFILE FILE!FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEGRUP LibrariesFILEFILE FILEFILE FILE"FILE GRUP xlispFILEHFILEIFILEJFILEKFILELFILEMFILENFILEOFILEPFILEQFILERFILESFILETFILEUFILEVFILEWFILEXFILEYFILEZFILE[FILE\FILE]FILE^FILE_FILE`FILEaFILEbFILEcFILEdGRUPcmt,FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEGRUP nyqsrc;FILE FILE FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILE FILE!FILE"FILE#FILE$FILE%FILE(FILE3FILE4FILE5FILE6FILE7FILE8FILE9FILE:FILE;FILEFILE?FILE@FILEAFILEBFILECFILEDFILEEFILE)FILE*FILE+FILE,FILE-FILE.FILE/FILE0FILE1FILE2FILE)FILE*GRUP trannFILE%FILE&FILEeFILEfFILEgFILEhFILEiFILEjFILEkFILElFILEmFILEnFILEoFILEpFILEqFILErFILEsFILEtFILEuFILEvFILEwFILExFILEyFILEzFILE{FILE|FILE}FILE~FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILE'FILE(FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEGRUPsndFILEFILEFILEFILE FILE FILE FILE FILE FILEFILEFILEFILEFILEFILEFILEFILEGRUP fftFILEFFILEGGRUP ResourcesFILE#?oo !"#$%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^`ac d e f g hijklmnopstuxyz -!{"|#$  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~           !"#$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     ROOT GRUPMac Interface StuffFILEFILEFILEFILE FILE!FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEGRUP LibrariesFILEFILE FILEFILE FILE"FILE GRUP xlispFILEHFILEIFILEJFILEKFILELFILEMFILENFILEOFILEPFILEQFILERFILESFILETFILEUFILEVFILEWFILEXFILEYFILEZFILE[FILE\FILE]FILE^FILE_FILE`FILEaFILEbFILEcFILEdGRUPcmt,FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEGRUP nyqsrc9FILE FILE FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILE FILE!FILE"FILE#FILE$FILE%FILE(FILE3FILE4FILE5FILE6FILE7FILE8FILE9FILE:FILE;FILEFILE?FILE@FILEAFILEBFILECFILEDFILEEFILE)FILE*FILE+FILE,FILE-FILE.FILE/FILE0FILE1FILE2GRUP tranjFILEeFILEfFILEgFILEhFILEiFILEjFILEkFILElFILEmFILEnFILEoFILEpFILEqFILErFILEsFILEtFILEuFILEvFILEwFILExFILEyFILEzFILE{FILE|FILE}FILE~FILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEFILEGRUPsndFILEFILEFILEFILE FILE FILE FILE FILE FILEFILEFILEFILEFILEFILEFILEFILEGRUP fftFILEFFILEGGRUP ResourcesFILE#ӴHA LARC.O1MacLHALHA LARC.lzhMacLHAM__start????JavaClasses.jarZIP MWZPMSIEInternet ExplorerIexplore.exe/ uJITvP~:u9us`x[J MENUbTargSTR#PPobRidLaeteSTR prefFlagTMPLvers Drop"hi _j, .( Q-5@J T      !"#$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$  NONAME.EXE@U {MSIEhttp://java.sun.com/products/jdk/1.1/docs/api/MSIEhttp://java.sun.com/products/jdk/1.1/docs/api/ JBoundApp????WINDnull JBoundApp????WINDnullSTUVWXY Z]^_`fabcde@:@::nyqsrc:@ ::fft:@ ::xlisp:@ ::tran:@ ::sys:mac:@::cmt:@::snd:@:MacOS Support:Headers:Universal Headers:@:Metrowerks Standard Library:MSL C:@:Metrowerks Standard Library:MSL C++:@:MacOS Support:MacHeaders:@:MacOS Support:Libraries:@ :MacOS Support:@:NoneMMPr@TEXT.lFlex PreprocessorTEXT.yBison PreprocessorJava LinkerAPPL`Appl`COkMW JavaClssMW JavaJjrf.jrfMWCD`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.htmlTEXT.javaMW JavaTEXT.lFlex PreprocessorTEXT.mfTEXT.rRezTEXT.yBison PreprocessorZIP MW Java@ZipFMW Javadocu`rsrc`.classMW Java.jar@.zipMW JavaMacOS 68K Linker APPL`Appl`MMLBLib Import 68KMPLFLib Import 68KMWCD`OBJ MPW Import 68KPLob`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ 68KTEXT.lFlex PreprocessorTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.ppuMW Pascal 68KTEXT.rRezTEXT.segTEXT.yBison Preprocessordocu`rsrc`shlbPEF Import 68KstubPEF Import 68K.docP.rsrc`MacOS Merge APPL`Appl`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.lFlex PreprocessorTEXT.rRezTEXT.yBison Preprocessorrsrc`shlbMacOS PPC LinkerAPPL`Appl`MMLBLib Import PPCMPLFLib Import PPCMWCD`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ PPCTEXT.c++MW C/C++ PPCTEXT.ccMW C/C++ PPCTEXT.cpMW C/C++ PPCTEXT.cppMW C/C++ PPCTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ PPCTEXT.lFlex PreprocessorTEXT.pMW Pascal PPCTEXT.pasMW Pascal PPCTEXT.pchMW C/C++ PPCTEXT.pch++MW C/C++ PPCTEXT.ppuMW Pascal PPCTEXT.rRezTEXT.sPPCAsmTEXT.yBison PreprocessorXCOFXCOFF Import PPCdocu`rsrc`shlbPEF Import PPCstubPEF Import PPC.docPMC LinkerCLUS@MMLBLib Import 68KMPLFLib Import 68KOBJ MPW Import 68KTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.clsMC Class CompilerTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.defTEXT.docTEXT.hTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.tsWin32 x86 LinkerTEXT.cMW C/C++ x86TEXT.c++MW C/C++ x86TEXT.ccMW C/C++ x86TEXT.cpMW C/C++ x86TEXT.cppMW C/C++ x86TEXT.defTEXT.gcGameCode Converter@TEXT.hMW C/C++ x86TEXT.lFlex PreprocessorTEXT.pMW Pascal x86TEXT.pasMW Pascal x86TEXT.pchMW C/C++ x86TEXT.pch++MW C/C++ x86TEXT.ppuMW Pascal x86TEXT.rcMW WinRCTEXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc!"!)!08*tGT!ao s !P  !p !)6<F!SH[n|@ """"!"#$(!%wi0&?'X(0j) |*8086+ ,H-./\0512-3E4^5v67@89%:";)<*=- >0?33@6GA_BwCDEFGHIJK LM3NNOdPQRSTUVWX YZ*[4\A]Q^a_m`~abcdefghijklmnopq)r2s;tHuUvawlxvyz{|}~  )2=L[gs}    # , 5 > G P Y b k t }     ' 0 8 @ I R ] h s ~    ! , 5 > F N X b h n v ~      % . 8 B H N X b j r y                   & . 6 > F M T \ d l t {! " # $ % & ' ( ) * + , - ./01)223;4E5P6\7g8n9u:;<=>?@ABCDEFGHI JKL#M)N/O:PEQPR\ShTrU|VWXYZ[\]^_`abc def"g.h7iCjMkYlemmnvopqrstuvwxyz{|}~"17@JWbt@:@::nyqsrc:@ ::fft:@ ::xlisp:@ ::tran:@::sys:mac:@::cmt:@::snd:@:MacOS Support:Headers:Universal Headers:@:Metrowerks Standard Library:MSL C:@:Metrowerks Standard Library:MSL C++:@:MacOS Support:MacHeaders:@:MacOS Support:Libraries:@ :MacOS Support:@ :   ) g hijklmnopqrstuvwxyz {!|"}#~$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^`ac d e f g hijklmnopstuxyz -!{"|#%&'()*      !"#$%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^`ac d e f g hijklmnopstuxyz -!{"|#$NoneMMPr@TEXT.lFlex PreprocessorTEXT.yBison PreprocessorJava LinkerAPPL`Appl`COkMW JavaClssMW JavaJjrf.jrfMWCD`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.htmlTEXT.javaMW JavaTEXT.lFlex PreprocessorTEXT.mfTEXT.rRezTEXT.yBison PreprocessorZIP MW Java@ZipFMW Javadocu`rsrc`.classMW Java.jar@.zipMW JavaMacOS 68K Linker APPL`Appl`MMLBLib Import 68KMPLFLib Import 68KMWCD`OBJ MPW Import 68KPLob`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ 68KTEXT.lFlex PreprocessorTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.ppuMW Pascal 68KTEXT.rRezTEXT.segTEXT.yBison Preprocessordocu`rsrc`shlbPEF Import 68KstubPEF Import 68K.docP.rsrc`MacOS Merge APPL`Appl`RSRC`TEXT.bhBalloon HelpTEXT.gcGameCode Converter@TEXT.lFlex PreprocessorTEXT.rRezTEXT.yBison Preprocessorrsrc`shlbMacOS PPC LinkerAPPL`Appl`MMLBLib Import PPCMPLFLib Import PPCMWCD`RSRC`TEXT.bhBalloon HelpTEXT.cMW C/C++ PPCTEXT.c++MW C/C++ PPCTEXT.ccMW C/C++ PPCTEXT.cpMW C/C++ PPCTEXT.cppMW C/C++ PPCTEXT.expTEXT.gcGameCode Converter@TEXT.hMW C/C++ PPCTEXT.lFlex PreprocessorTEXT.pMW Pascal PPCTEXT.pasMW Pascal PPCTEXT.pchMW C/C++ PPCTEXT.pch++MW C/C++ PPCTEXT.ppuMW Pascal PPCTEXT.rRezTEXT.sPPCAsmTEXT.yBison PreprocessorXCOFXCOFF Import PPCdocu`rsrc`shlbPEF Import PPCstubPEF Import PPC.docPMC LinkerCLUS@MMLBLib Import 68KMPLFLib Import 68KOBJ MPW Import 68KTEXT.cMW C/C++ 68KTEXT.c++MW C/C++ 68KTEXT.ccMW C/C++ 68KTEXT.clsMC Class CompilerTEXT.cpMW C/C++ 68KTEXT.cppMW C/C++ 68KTEXT.defTEXT.docTEXT.hTEXT.pMW Pascal 68KTEXT.pasMW Pascal 68KTEXT.pchMW C/C++ 68KTEXT.pch++MW C/C++ 68KTEXT.tsWin32 x86 LinkerTEXT.cMW C/C++ x86TEXT.c++MW C/C++ x86TEXT.ccMW C/C++ x86TEXT.cpMW C/C++ x86TEXT.cppMW C/C++ x86TEXT.defTEXT.gcGameCode Converter@TEXT.hMW C/C++ x86TEXT.lFlex PreprocessorTEXT.pMW Pascal x86TEXT.pasMW Pascal x86TEXT.pchMW C/C++ x86TEXT.pch++MW C/C++ x86TEXT.ppuMW Pascal x86TEXT.rcMW WinRCTEXT.resWinRes ImportTEXT.yBison Preprocessor.docP.libLib Import x86.objObj Import x86MW JavaDoc Linker COkMW JavaDocClssMW JavaDocRSRCRez`TEXT.bhBalloon HelpTEXT.htmlTEXT.javaMW JavaDocTEXT.rRezZIP MW JavaDoc@ZipFMW JavaDocrsrcRez`.classMW JavaDoc.zipMW JavaDoc   ) g hijklmnopqrstuvwxyz {!|"}#~$%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^`ac d e f g hijklmnopstuxyz -!{"|#%&'()*.Pmstr~mstl mstn((mstimstrmstlmstnP(mstix,mpsi&4mtgl PLstQn .pref- Ipref5.pref/Q$pref:u pref\;prefu<Jprefs=| mtsl-mtplSmtpsmtpiYhmtlo .prefiIprefj prefke$prefv[ prefwpref-x@JprefeyX.pref܆IprefƟTpref $pref& prefprefdJprefi 4 mtslQ-mtpl۽mtpsmtpi=hmtloXprefN9` prefՐ: TprefBLB \ prefsC hprefFK p pref"`L |prefT. prefUt prefM:I2prefLPprefM#aprefM "prefMprefMUprefM%MJprefL`7 prefL7$2prefM,7VPprefM]uPprefMAB)"prefMBKprefL:B_prefMBJprefL˒C;prefIDKpref\Gc4prefMJprefMprefO4prefRpref{VpreftPmallg#maplV[prefRu[cPprefO^ pref^pref.cPpref g prefbprefg49gprefe:ձ pref&;*lpref_<prefH=+pref>pref? pref @ prefeYAprefe#BprefC>pref D;pref EsprefT{FbprefGI8prefEH prefUdIpref J* pref)K4 pref<=L TprefM pref;NprefO.prefOPM pref(RQpreftRģpref5S_ prefT'*lprefU-prefVkpref $Wpref!?X@ prefYl prefOZpref_O[sprefd&\ >pref&9]pref^ypref _bpref$` 8pref a  pref57b prefc % prefd pref4e preffÇprefgğprefh+.prefiG pref^jnyquist-3.05/macproject/mac_port_changes.txt0000644000175000000620000000416710144436365020365 0ustar stevestaffChanges to Nyquist: In audiomac.c: (Do byteswap:) long samples = srclength / 2; short *srcs = (short *)src; short *dsts = (short *)dst; long i; for(i=0; i> 8)); } In sndwrite.c (sound_save_sound and sound_save_array both): cvtfn = find_cvt_to_fn(snd, buf); > #ifdef macintosh > if (player) { > gprintf(TRANS, "Playing audio: Click and hold mouse button to stop playback.\n"); > } > #endif while (n > 0) { long togo; float peak; sample_block_type sampblock = sound_get_next(s, &blocklen); #ifdef SNAPSHOTS printf("."); if (sound_created_flag) { printf("SNAPSHOT: "); sound_print_tree(printing_this_sound); sound_created_flag = false; } fflush(stdout); #endif if (sampblock == zero_block || blocklen == 0) { break; } togo = min(blocklen, n); buflen = (*cvtfn)((void *) buf, (void *) sampblock->samples, togo, s->scale, &peak); if (peak > max_sample) max_sample = peak; > #ifdef macintosh > if (Button()) { > if (player) { > snd_reset(player); > } > gprintf(TRANS, "\n\nStopping playback...\n\n\n"); > break; > } > #endif In cext.h: + #ifdef round + #undef round + #endif In fft.c: /* perform the fft: */ fftnf(1, (const int *)&len, temp_fft, temp_fft + len, 1, -1.0); ^^^^^^^^^^^^^ In userio.h: #ifdef MACINTOSH + #undef false + #undef true + #include #define TRANS (long) 0 #define ERROR (long) 1 #define FATAL (long) 2 #define GDEBUG (long) 3 #endif In tran/ifft.c: #ifndef macintosh #include "crtdbg.h" #endif #ifndef macintosh _CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF); #endif In userio.c: strcpy((char *)Pstr, str); * C2PStr((char *)Pstr); strcpy((char *)Pfn, fn); * C2PStr((char *)Pfn); Get from Audacity: snd.c sndconfig.h sndheader.c sndio.c nyquist-3.05/macproject/nyquist.rsrc0000644000175000000620000000000010144436365016715 0ustar stevestaffnyquist-3.05/demos/0002755000175000000620000000000011537433132013276 5ustar stevestaffnyquist-3.05/demos/sequence_example.htm0000644000175000000620000000275710144436365017350 0ustar stevestaff Sequence Example

    Sequence Example

    A sequence of notes is often specified by a "note list," consisting of times, durations, other transformations, and a parameterized behavior to generate the sound. The following is an example:

    (defun ringpat1 () 
      (scale 0.8 
        (sim
          (scale 0.6 (at 0.0 (ring 0.6 45 2)))
          (scale 0.5 (at 0.2 (ring 0.8 40 1.5)))
          (scale 0.8 (at 0.6 (ring 1 44 1)))
          (scale 0.7 (at 0.8 (ring 1.2 32 0.8))) 
        )))

    Notice that there are 4 sounds. The sounds are shifted in time using the at transformation, and all four sounds are combined using the sim construction. Because of the time shifts, the sounds do not take place simultaneously, but they may overlap somewhat.

    Durations are specified by the first parameter to ring, so no stretch transformations are used here. Each sound is individually scaled.

    To play this sound, you need the ring function from Vinal Scratch Tutorial. Then you can type:

    (play (ringpat1))

    Try the following combination, which plays a short and long version of ringpat1 at about the same time:

    (play (sim
            (scale 1.0 (at 0.0 (ringpat1)))
            (scale 0.7 (at 0.05 (stretch 1.5 (ringpat1)))) ))
    
    
    
    nyquist-3.05/demos/scratch_tutorial.htm0000644000175000000620000000653610144436365017376 0ustar stevestaff Vinal Scratch Tutorial

    Vinal Scratch Tutorial

    This sound reminds me of the effect of dragging a needle across a vinal record.

    (defun ring (dur pch scl)
      (let ((modstep1 (hz-to-step (* (step-to-hz pch) (sqrt 2.0))))
            (modstep2 (hz-to-step (* (step-to-hz pch) (sqrt 11.0)))))
        (stretch dur 
          (mult 
            (env 0.05 0.1 0.2 1 0.6 0.24 1)
            (fmosc pch (mult 
    	             (pwl 0.07 1800 0.15 1000 0.4 680 0.8 240 1 100 1) 
    		     scl 
                         (osc modstep1)
                         (osc modstep2) ))) )))

    The following plays an example sound from this function:

    (play (ring 7.1 (hz-to-step 1) 1.2))

    Here is a brief description of how this function works: The sound is created by an FM oscillator. The modulation comes from two sinusoids operating at low frequencies multiplied together. The sinusoids are not harmonically related, so an irregular pulse is generated by their product. This is scaled further by a piece-wise linear envelope that adds more variation. To make the sinusoids inharmonically related, their frequencies are scaled by the square root of 2 and the square root of 11. The variables modstep1 and modstep2 are initialized to these computed frequencies.

    The following example combines several instances of ring with different parameters:

    (play (sim (scale 0.15 (at 2.9 (ring 7.1 (hz-to-step 1) 1.2)))
    	   (scale 0.175 (at 4.9 (ring 5.1 (hz-to-step 2) 1.414)))
    	   (scale 0.2 (at 6.9 (ring 3.1 (hz-to-step 4) 1.8)))))
    

    Other Sounds Using Ring

    The same ring function can be used to achieve other sounds. Listen to these examples:

    (play (sim 
            (scale 0.35 (at 1.5 (ring 4 1 1)))
    	(scale 0.325 (at 4 (ring 4 4 2)))
    	(scale 0.3 (at 7.5 (ring 4 10 4))) ))

    These instances use a higher pitch parameter than the previous ones.

    Another Related Sound

    The following creates a sound using FM and a wave table derived from a vocal sound.

    (defun vocrap (&optional (pch 16) (dur 1))
      (if (not (boundp '*voc-table1*)) (mk-voc1-table))
      (fmosc pch (stretch dur (pwl 0 3 0.1 -20 0.2 20 0.3 30
                                   0.4 -10 0.5 15 0.6 0
                                   0.8 -30 1 60 1)) *voc-table1*))

    This function uses a special test to make sure that *voc-table1* is initialized. If it is not, it would be an error to read or test it, but you can query to find out if the variable is bound or unbound. (Global variables become bound when you assign a value to them.) The boundp function takes an atom (note the use of the single quote to denote an atom, the name of the variable, rather then the variable's value) and returns true if the variable is bound.

    Here is the definition for mk-voc1-table. You might have to replace the filename depending upon how your system is configured.:

    (defun mk-voc1-table ()
        (if (not (boundp 'voc-snd1))
            (setf voc-snd1 (s-read "./test/voc1.snd")))
        (setf *voc-table1* (list voc-snd1 16 T)))

    The following shows one way to invoke vocrap:

    (play (seqrep (i 4) (vocrap)))
    
    
    
    
    nyquist-3.05/demos/softclip.jpg0000644000175000000620000002564410144436365015640 0ustar  stevestaffJFIFC
    
    
    
    
    C		
    
    "	
    }!1AQa"q2#BR$3br	
    %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz	
    w!1AQaq"2B	#3Rbr
    $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?CCxj.}NJw׳(A!Abp	DZO[4W?3wU<CiG-AׁQ@c9xtG^]x<CiG-AׁQ@c9xtG^]x<CiG-AׁQ@c9xtG^]x<CiG-AׁQ@c9xtG^]x<CiG-AׁQ@c9xtG^]x<CiUuoJLׅ')Rck2P%C s_Q]>,faL8%C)#íu~gϋ0PЯu˽rJG.!젷U-LT$_U߈Z=D	f3RV#rv	x^	DzEs{][Kۻ敮VWhEUTF#T/ŝOId|=ߊ?kZot9tJ+g8]h*v`t ?H?zŝ3Ic@}?H??lx#/.
    [4ǂ?r
     }?H??lx#/.
    [4ǂ?r
     }?H??lx#/.
    [4ǂ?r
     }?H??lx#/.
    [4ǂ?r
     }?H??lx#/.
    [4ǂ?r
     }?H??lx#/.
    [4mŚ<mgOo.o/vvN3+	#W?OїtTQEyW gl+h?_?gu^Y@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@y$_:^^BbΧP=ibΙנW_@~س,uQEQEQEQEQEQEQEQEQEQEQEW}Fז.끮'^,-?F]QE_/a,SyeQEQEQEQEQEQEQEQEQEQEQE/,K%zy$_:@$:g^^=ibΙנPEPEPEPEPEPEPEPEPEPEPEP]OY^Z5xw@EP~꼲O?3wUQEQEQEQEQEQEQEQEQEQEQE^Q{gQqH?+l:WBbΧV]-7M";6ij3,I$O>*O	àM8,ų[dHiH,C;RmPzŝ3Ic@?4gLX((((kk|7tx.n!HsQ
    +JtV\inuWʾ*x]/]^I!m=TlR٘7T$a
    T5⼖)e:xa	w,i&dYA*Idur9brb;\_'O?c~_K|'Q}d=+Xߵ	TG,oo*?O]}cE|[?
    ]-GcO0hc~_K|'Q}k%>i_2?vqw,oo*?O}CY==NjwE~0O!4Ueo4G"+);Q*;lqk7OsJ]/@h',qfɑA]R?&W%nyp*/*EP׾x<\tϸߚ2smo7[CR௃B[[yj)e3X;B6:"=xn#I5ƒ(;$UbszLogv|&X(-}L
    xGB]^t
    ImZoH@ʠFzJ֢e)MIݚQEHQ@Q@Q@Q@Q@w?jgyi2e{UQ@UA;?@WPEPEPEPEPEPEPEPEPEPEPEP^BbΧWWп@~%س,~_@~س,u,Kz_P-tۘl쭣ipYُ
    I<+4(?_eGpw71T3._.i
    +kj?e}.+&eȢp 
    @Dʻe^~ΊMnEu~u3V|aI|FXG?NL4񜎳AF7Za2&2">\[O;||@
    jWK$vr$A@MĻ 	TO=oᯅ^MºL:><ٝF?3,bH
    ppxl>ΛVoRUMT=_QE|QEQEQEQEQEQEQEQEW}Fז.끮'^,-?F]QE_/a,SyeQEQEQEQEQEQEQEQEQEQEQY"<)O['.yu>.лIp
    hWп@~%س,ᯈxtMSZDžu9eVkI>OL̫IFm/,K%,KrkKmo1t[FY3J~Xr>gE`kڣWo>|"w4خu`$e0AX`2n36(~?vcZ0w3H8`ܫpXڋTp4pt'1O`ז?+jba'_W9*pV7-;U|c&ştJ}UEcqq9h-%~}KTVEWaEPEPEPEPEPEPEPEPEP]OY^Z5xw@EP/x࿃[ĞVuIjAAjg局31Kq_Z0Wګ?@WP_Z0WڨB
    _@Q@?!j_jW*U}E|Ud/_?U2VU?ᐿ|`¯WP_Z0WڨB
    _@Q@?!j_j?ggmV/w&	΁I688lW*U_Z0Wګ
    (d/_?T!j_j(ᐿ|`¯QU>B
    G2VUW*Uscx/MsSLK]/QB&	U(`H'$u+#_
    8ht}-dHD+;<~TD@YۂpI
    s%
    iKVݵg˖AuH~+|g>Qc%Gr][DLNm"~]g~Vve>HYek^</xAl!4
    jQ[_I$I$$$I&ɒuWWa+=dd7u6~g
    )kĺW^c_CkQD<"Laa
    d} 5__Z0Wګ?g ?
    ?Y?:
    bjJi^OVٲJ*W*U_Z0Wګ
    +?!j_jW*U}E|Ud/_?U2VU?ᐿ|`¯WP_Z0WڨB
    _@Q@^UBZ5A,d\~1f*39_Z0Wګ
    (d/_?T!j_j(ᐿ|`¯QU>B
    G2VUW*U_Z0Wګ
    (d/_?T!j_j(ᐿ|`¯W~1yеMoŞ"myy`$b`h]w?jgyi2=(imct}BDu׳EY-d+O
    ĥ'}r+q	tPN.'ޭYn%ɁjB^:Ӽ6KamM/,63oyS-䪼8n@7ZIy5;{5,Xgyq
    (
    (
    (
    (
    (3rzLw[÷rXYMy1aFSp#wkcԄ3G{xW'gxUĬ<>h%aDewyq]5e0l~yW#2QEQEQEQ_*ZK?;:ܖ_i]YWLFsyeW~[7
    IY+ݒ]舔y|!Jo{kfCϝs
    0DP9R~~2isi>tѕQCrPNA!bTF>뺏>%x>r'kSͷ`
    FTilQJzɐe}?Ol-aGjTU*p+9?yis۷1hZn^hasF*,5>>7ycjҫIk(0ʳ#p
    )wfDq+ȷ^#дڽ|M+crXyŠXh?|lB.eggi YcUEQEQ(((((?۴^Icm	vC3dn}\*/d+?\,@x.|Q[Oz;fie"e*Osெ|~J6)&yg%G)ff|ȭbI(@WW꼲
    (
    (
    (
    (
    (
    (
    (
    (5F|=Amy	-mA=9ȉnP0ϵ>e
    ·B"j>\MJ.Ix40oTη4۩	
    ]671V~ڙ]3]ѨIDDDBd8]Dn~
    >Y-joy<9'lX&Fw|*T3gae?{}ŧ/zZ.2s>Ҿ,ۓE.
    >E<ݢUbC6؆ceY6	xC&M7hg2\].9N
    UkLL=$[B;z*0Qwz+4
    HĿu?%/ŝOIdzŝ3Ic@?4gLX(((((((((((('^,-?F]]OY^Zj(ʿh?_?gu^Y^A;(+Y]|$G-c0XHa;@9BXt @
    ߄~F>/ڶ>6JiڡWspڻp
    m9ZN4&\don?_:*
    K__B|2u??B|2u?oC";%CRuU'/'^'/'^&J?N?	3G7/}k	ׄGk	ׄGkɿD-S8On?_:*
    w5iSZ=llt˅\i#N$q8>
    	?M헀1g{m";nE"UՂeX#E5<;:ޏ")e@/$U_ڿūSvT7yJ>bGvĒEa=M}G$ebi!`A[$:VnPξ>/o	nxnGm4fS#
    FYskK
    {3S7G)FZOxxxs5o<timelabels voz-1))
    
    (defun vox-1 ()  (timed-seq  (sdl:normalize-score-duration (sdl->score voz-1))))
    (defun vox-2 ()  (timed-seq  (sdl:normalize-score-duration (sdl->score voz-2 *my-time-labels*))))
    
    (play (sim (vox-1) (vox-2)))
    I
    nyquist-3.05/demos/sdl/inv-08.lsp0000644000175000000620000001561311466723256015637 0ustar  stevestaff; *********************************************
    ; Inventio # 8 a 2 voci BWV 779. J. S. Bach.
    ; Score Description Library example
    ; Translated from a previous lambda Music score
    ; by Pedro J. Morales.
    ; Junio, 2005
    ; Revised: July 25 2007
    ; Nyquist 2.37
    ; *********************************************
    
    (load "sdl")
    
    (setf *autonorm-type* 'previous)
    
    
    (defun analog-saw (pitch dur atk rel det reson-freq)
      (let ((hz (step-to-hz pitch)))
        (set-logical-stop
         (reson
          (mult 0.5
    	    (sum -0.1 (pwev 0.1 atk 1 dur 0.8 (+ dur rel) 0.1))
    	    (sum (stretch (+ dur rel) (osc-saw  hz))
    		 ; (scale 0.5 (stretch (+ dur rel) (osc-saw (* 2 hz))))
    		 (stretch (+ dur rel) (osc-saw  (+ hz det)))))
          (sum (* 3 hz) (mult (* 8 hz) (sum -0.1 (pwev 1.1 (+ dur rel) 0.1))))
          reson-freq 1)
         dur)))
    
    
    (defun xan2 (&key pitch)
      (analog-saw pitch  0.001 0.02 2.0 2 4000))
    
    (defun xan3 (&key pitch (rel 2.5) (atk 0.02)(reson 4000)(din 1))
      (scale din (analog-saw pitch 0.001 atk rel 3 reson)))
    
    
    ; SCORE --------------------------------------------------------------------
    
    (setf voz-1
                '((ATTR :mm 120.0) ; 140?
    	      (INIT-INSTR "i1" xan3) (INSTRUMENT "i1")
    	      (PWL-POINT :rel 1.5)(ATTR :atk 0.005)
                 (DELTA 2) (f4 2) a4 f4 c5  f4
    (PWL-POINT :rel 2.5) 
    f5 (e5 1) d5 c5 d5 c5 :bb4 a4 :bb4 a4 g4 (f4 2)
                 a4 c5 a4 f5 c5
    ; linea 2
                (PWL-POINT :rel 1.0)
                (a5 1) c6 :bb5 c6 a5 c6 :bb5 c6 a5 c6 :bb5 c6
                :f5 :a5 :g5 :a5  :f5 :a5 :g5 :a5 :f5 :a5 :g5 :a5            
                :d5 :f5 :e5 :f5 :d5 :f5 :e5 :f5 :d5 :f5 :e5 :f5
    ; linea 3
    	    (PWL-POINT :rel 3.0)
              (MRK n5)
                (:b4 2) :g4 :d5 :b4 :f5 :d5
                (MRK n6)
                (:g5 1) :a5 :g5 :f5 :e5 :f5 :e5 :d5 :c5 :d5 :c5 :bb4
                (:a4 2)
                (MRK n7)
                (:d5 1) :c5 :b4 :c5 :b4 :a4 :g4 :a4 :g4 :f4
    ; linea 4
                :e4 :f4 :e4 :d4 (MRK n8)(:c4 2)
                (:c5 1) :b4 (:c5 2) 
                (PWL-POINT :rel 4)
                :e4 (PWL-POINT :rel 2) :f4 :c5 :e4 :c5 :d4 :b4 (MRK n9)
                (PWL-POINT :rel 1.5)(:c5 4) 4 (MRK n10) 4
    ; linea 5
                2 (:c5 2) :e5 :c5 :g5 :c5 :c6 (:b5 1) :a5 :g5 :a5 :g5 :f5 :e5 :f5 :e5
                (MRK n11) :d5 :c5 :bb4 :c5 :a5
                :c5 :a5 :bb4 :a5 :c5 :a5 :a4 :a5
    ; linea 6
                (PWL-POINT :rel 2.5)
                (:bb4 2)(PWL-POINT :rel 2) :g4 :bb4 :g4 :d5 :g4 :g5 (:f5 1) :eb5 :d5 :eb5 :d5 :c5 :bb4 :c5 :bb4 :a4 (:g4 2) :bb4 :d5 :bb4 :g5 :d5
    ; linea 7
                (PWL-POINT :rel 3)
                :bb5 :c#5 :bb5 :c#5 :bb5 :c#5
                (MRK n12)
                :d5 :a4 :f5 :d5 :a5 :f5
                (MRK n12b)
                (:g5 1) :f5 :g5 :bb5 :c5 :bb5 :d5 :bb5 :e5 :bb5 :c5 :bb5
    ; linea 8
                (MRK n12c)
                :f5 :e5 :f5 :a5  :b4 :a5 :c#5 :a5 :d5 :a5 :b4 :a5
                :e5 :d5 :e5 :g5  :a4 :g5 :b4 :g5 :c#5 :g5 :a4 :g5
                (MRK n13)
                (:f5 2) :d5 :bb4 :d5 :g4 :f5
    ; linea 9
                (MRK n14)
                :e5 :c5 :a4 :c5 :f4 :eb5
                (MRK n15)
                (:d5 1) :f5 :eb5 :f5 :d5 :f5 :eb5 :f5 :d5 :f5 :eb5 :f5
                (MRK n16)
                :bb4 :d5 :c5 :d5 :bb4 :d5 :c5 :d5 :bb4 :d5 :c5 
                (PWL-POINT :rel 3) :d5
                (PWL-POINT :rel 1)
    ; linea 10
                (MRK n17)
                :g4 :bb4 :a4 :bb4 :g4 :bb4 :a4 :bb4 :g4 :bb4 :a4 (PWL-POINT :rel 1.5) :bb4
                (MRK n18)
                (PWL-POINT :rel 2)
                (:e4 2) :c4 :g4 :e4 :bb4 :g4
                (MRK n19)
                (:c5 1) :d5 :c5 :bb4 :a4 :bb4 :a4 :g4 :f4 :g4 :f4 :eb4
    ; linea 11
                (:d4 2)
                (PWL-POINT :rel 4)
                (MRK n20)
                (:g4 1) :f4 :e4 :f4 :e4 :d4 :c4 :d4 :c4 :bb3 :a3 :bb3 :a3 :g3
                (:f3 2) (PWL-POINT :rel 2)
                (MRK n21)
                (:f4 1) :e4 (:f4 2) (MRK rall) :a3  
    ; rallentando
                (:bb3 2.2) (:f4 2.4) (:a3 2.6) (PWL-POINT :rel 1) (:f4 2.8)
                (MRK n22) (PWL-POINT :rel 3.2)
                (:g3 3) (:e4 3.4) (MRK final)(DUR 4) (PWL-POINT :rel 5)(ATTR :din 0.5)(CH :a3 :c4 :f4)))
    (setf voz-2
    
                '((ATTR :mm 120.0)
    	      (INIT-INSTR "i1" xan3) (INSTRUMENT "i1")
                  (PWL-POINT :reson 100)(PWL-POINT :rel 1)(PWL-POINT :din 2.5)
    	      (CHN 6)(PATCH 47) (DELTA 12)(DELTA 2) (:f3 2) :a3 :f3 :c4 :f3 
    	      (PWL-POINT :rel 1.5)(PWL-POINT :reson 500)(PWL-POINT :din 3)
    	      :f4 (:e4 1) :d4 :c4 :d4 :c4 :bb3 :a3 :bb3 :a3 :g3
    	      (PWL-POINT :din 1.5)
    ; linea 2
                (:f3 2) :a3 :c4 :a3 :f4 :c4 (:a4 1) :c5 :bb4 :c5 :a4 :c5 :bb4 :c5 :a4 :c5 :bb4 :c5
                :f4 :a4 :g4 :a4 :f4 :a4 :g4 :a4 :f4 :a4 :g4 :a4
    ; linea 3
    	    (PWL-POINT :reson 2500)
                :d4 :f4 :e4 :f4 :d4 :f4 :e4 :f4 :d4 :f4 :e4 :f4
                (:b3 2) :g3 :c4 :g3 :e4 :c4 
    	    (PWL-POINT :rel 2)
    	    (:f4 1) :g4 :f4 :e4 :d4 :e4 :d4 :c4 :b3 :c4 :b3 :a3
    ; linea 4
    	    (PWL-POINT :din 1)(PWL-POINT :rel 2)
                (:g3 2) (:c4 1) :b3 :a3 :b3 :a3 :g3 :f3 :g3 :f3 :e3 :d3 :e3 :d3 :c3 :g3 :f3 :e3 :f3 (:g3 2) :g2
    	    (PWL-POINT :rel 1.5)(PWL-POINT :reson 300)(PWL-POINT :din 3)
                2 :c3 (PWL-POINT :rel 2) :e3 :c3 :g3 :c3
    ; linea 5
    	    (PWL-POINT :rel 2.5)
    	    (PWL-POINT :rel 1.5)(PWL-POINT :reson 500)
                :c4 (:b3 1) :a3 :g3 :a3 :g3 :f3 :e3 :f3 :e3 :d3
                (:c3 2) :e3 :g3 :e3 :c4 :g3 :eb4 :f#3 :eb4 :f#3 :eb4 :f#3
    ; linea 6
                :g3 (:f3 1) :eb3 :d3 :eb3 :d3 :c3 :bb2 :c3 :bb2 :a2
    	    (PWL-POINT :rel 1.5)(PWL-POINT :din 1)
                (:g2 2) :g3 :bb3 :g3 :d4 :g3 :g4 (:f4 1) :eb4 :d4 :eb4 :d4 :c4 :bb3 :c4 :bb3 :a3
    ; linea 7
    	    (PWL-POINT :rel 1.5)(PWL-POINT :reson 1500)(PWL-POINT :din 2)
                :g3 :f3 :g3 :e4 :g3 :e4 :f3 :e4 :g3 :e4 :e3 :e4
                :f3 :e3 :f3 :d4 :f3 :d4 :e3 :d4 :f3 :d4 :d3 :d4
                (:bb3 2) :g3 :e3 :g3 :c3 :e3
    ; linea 8
                :a3 :f3 :d3 :f3 :b2 :d3 :g3 :e3 :c#3 :e3 :a2 (PWL-POINT :rel 1) :c#3
                (PWL-POINT :rel 1.5)
    	    (:d2 1) :d3 :c3 :d3 :g2 :d3 :a2 :d3 :bb2 :d3 :g2 (PWL-POINT :din 1.) :d3
    ; linea 9
    	    (PWL-POINT :din 1.)(PWL-POINT :rel 2)(PWL-POINT :reson 2000)
                :c2 :c3 :bb2 :c3 :f2 :c3 :g2 :c3 :a2 :c3 :f2 :c3
                (:bb2 2) :d3 :f3 :d3 :bb3 :f3
    	    (PWL-POINT :din 2)(PWL-POINT :reson 1000)
                (:d4 1) :f4 :eb4 :f4 :d4 :f4 :eb4 :f4 :d4 :f4 :eb4 :f4
    ; linea 10
                :bb3 :d4 :c4 :d4 :bb3 :d4 :c4 :d4 :bb3 :d4 :c4 :d4
                :g3 :bb3 :a3 :bb3 :g3 :bb3 :a3 :bb3 :g3 :bb3 :a3 :bb3
                (:e3 2) :c3 :f3 :c3 :a3 :f3
    ; linea 11
                (:bb3 1) :c4 :bb3 :a3 
    	    :g3  :a3 :g3  :f3 :e3 :f3 :e3 :d3 (:c3 2)
                (:f3 1) :e3 :d3 :e3 :d3 :c3 :bb2 :c3 :bb2 :a2 
    	    (:g2 1.1) :a2 (:g2 1.2) :f2
                (:c3 1.3) :bb2 (:a2 1.4) :bb2 (:c3 3.2)
    	    (PWL-POINT :din 1)
    	    (PWL-POINT :rel 2)(PWL-POINT :reson 3500) (:c2 3.4) (PWL-POINT :rel 4)(:f2 4)))
    
    
    (play
     (sum
      (scale 1 (timed-seq (sdl->score voz-1)))
      (timed-seq (sdl->score voz-2)))) 
    nyquist-3.05/demos/bandfx.htm0000644000175000000620000000455310144436365015263 0ustar  stevestaff
    
    
       
       
       Untitled Document
    
    
    
    

    Multiple Band Effects Tutorial

    This page describes how to use the bandfx library in Nyquist.

    What does it do?

    The idea is very simple: separate the incoming signal into different frequency bands. Apply an effect to each frequency band.
    For example, apply a delay, with longer delays at higher frequencies. Then sum the outputs of the effects. In the delay example,
    the result will be something like a filter sweep -- the low frequencies come out first, followed by increasingly higher frequencies.

    How does it work?

    Frequency bands are separated using Nyquist's reson filter. Although reson is not perfect for this job, it has the nice
    feature that there is a complementary areson filter that returns everything removed by reson. We split off the lowest
    frequency band with reson, then apply areson to get the remainder of the signal. We pass this through another reson
    tuned to the second band and use another areson to get the remainder. Using a series of filters, we pull off all the
    band except for the last one, which is just whatever is left over.

    The function separate-into-bands constructs an array of frequency bands. The function reconstruct-from-bands sums an
    array of frequency bands back into a single channel. Different functions apply effects to the frequency band representation.
    Consult the code (see lib/bandfx.lsp) for details. You can use the code as a template for creating your own multiple band effects.

    How can I use it?

    > (load "bandfx")
    > (f2)
    > (f3)
    > (f4)
    > (f5)
    The commands shown above will play some examples that are included in lib/bandfx.lsp. You can read the code for
    a description of the functions and to see examples of their use. The functions are also described in the Nyquist manual
    (see "multiple band effects" in the index).

    The manual also describes some ways this library might be extended. Please contribute some examples if you find these effects useful.
      nyquist-3.05/demos/examples.lsp0000644000175000000620000003044511466723256015652 0ustar stevestaff;; examples.lsp -- these are from the Nyquist Manual examples (defun ex1 () (play (osc 60))) (defun ex2 () (play (scale 0.5 (osc 60)))) ; build-harmonic is already defined in nyquist.lsp ; ;(defun build-harmonic (n) (snd-sine 0 n tablesize 1)) (defun mkwave () (setf *table* (sim (scale 0.5 (build-harmonic 1.0 2048)) (scale 0.25 (build-harmonic 2.0 2048)) (scale 0.125 (build-harmonic 3.0 2048)) (scale 0.062 (build-harmonic 4.0 2048)))) (setf *table* (list *table* (hz-to-step 1) T))) (cond ((not (boundp '*mkwave*)) (mkwave) (setf *mkwave* t))) (defun note (pitch dur) (osc pitch dur *table*)) (defun ex3 () (play (seq (note c4 i) (note d4 i) (note f4 i) (note g4 i) (note d4 q)))) (defun env-note (p) (mult (note p 1.0) (env 0.05 0.1 0.5 1.0 0.5 0.4))) (defun ex4 () (play (env-note c4))) (defun ex5 () (play (seq (stretch 0.25 (seq (env-note c4) (env-note d4))) (stretch 0.5 (seq (env-note f4) (env-note g4))) (env-note c4)))) (defun ex6 () (play (seq (note c4 q) (note d4 i)))) (defun ex7 () (play (scale 0.5 (sim (note c4 q) (note d4 i))))) ;; previous versions could not get current-path to locate demo-snd.aiff... ;(format t "~%examples.lsp tries to load demo-snd.aiff from the~%") ;(format t "default sound file directory, which is stored in~%") ;(format t "the variable *default-sf-dir*. The current value is:~%") ;(format t "\"~A\". If you get an error immediately, you should~%" ; *default-sf-dir*) ;(format t "either set *default-sf-dir* or copy demo-snd.aiff~%") ;(format t "where Nyquist will find it.~%") (display "examples.lsp" (current-path)) (if (not (boundp 'a-snd)) (setf a-snd (s-read (strcat (current-path) "demo-snd.aiff")))) (defun ex8 () (play a-snd)) (defun ex9 () (play (seq (cue a-snd) (cue a-snd)))) (defun ex10 () (play (sim (at 0.0 (cue a-snd)) (at 0.7 (cue a-snd)) (at 1.0 (cue a-snd)) (at 1.2 (cue a-snd))))) (defun ex11 () (play (sim (cue a-snd) (loud 6.0 (at 3.0 (cue a-snd)))))) (defun ex12 () (play (loud 6.0 (sim (at 0.0 (cue a-snd)) (at 0.7 (cue a-snd)))))) (defun snds (dly) (sim (at 0.0 (cue a-snd)) (at 0.7 (cue a-snd)) (at 1.0 (cue a-snd)) (at (+ 1.2 dly) (cue a-snd)))) (defun ex13 () (play (snds 0.1))) (defun ex14 () (play (loud 0.25 (stretch 0.9 (snds 0.3))))) (defun ex15 () (play (sound-srate-abs 44100.0 (osc c4)))) (defun tone-seq () (seqrep (i 16) (stretch 0.25 (osc-note c4)))) (defun pitch-rise () (stretch 4.0 (scale 16 (ramp)))) (defun chromatic-scale () (transpose (pitch-rise) (tone-seq))) (defun ex16 () (play (chromatic-scale))) (defun ex17 () (play (sustain (stretch 4 (sum 0.2 (ramp))) (chromatic-scale)))) (defun warper () (pwl .25 .4 .75 .6 1.0 1.0 2.0 2.0 2.0)) (defun warp4 () (stretch 4 (scale 4 (warper)))) (defun ex18 () (play (warp (warp4) (tone-seq)))) ; note: as explained in the manual, the following is NOT ; the solution to a fixed duration/variable tempo sequence: ; (defun tone-seq-2 () (seqrep (i 16) (stretch-abs 0.25 (osc-note c4)))) (defun ex19 () (play (warp (warp4) (tone-seq-2)))) ; here is the proper solution (vs. ex19): ; (defun tone-seq-3 () (seqrep (i 16) (set-logical-stop (stretch-abs 0.25 (osc-note c4)) 0.25))) (defun ex20 () (play (warp (warp4) (tone-seq-3)))) (defun ex21 () (play (warp (warp4) (transpose (pitch-rise) (tone-seq))))) (defun ex22 () (play (warp (warp4) (transpose (control-warp (get-warp) (warp-abs nil (pitch-rise))) (tone-seq))))) (defun ex23 () (play (force-srate *default-sound-srate* (stretch 3.0 (sound a-snd))))) (defun down () (force-srate *default-sound-srate* (seq (stretch 0.2 (sound a-snd)) (stretch 0.3 (sound a-snd)) (stretch 0.4 (sound a-snd)) (stretch 0.5 (sound a-snd)) (stretch 0.6 (sound a-snd))))) (defun ex24 () (play (down))) (defun up () (force-srate *default-sound-srate* (seq (stretch 0.5 (sound a-snd)) (stretch 0.4 (sound a-snd)) (stretch 0.3 (sound a-snd)) (stretch 0.2 (sound a-snd))))) (defun ex25 () (play (seq (down) (up) (down)))) (defun ex26 () (s-save a-snd 1000000000 "./a-snd-file.snd") (play-file "./a-snd-file.snd") (system "rm ./a-snd-file.snd")) (defun ex27 () (setf my-sound-file "./a-snd-file.snd") (s-save a-snd 1000000000 my-sound-file) (play-file my-sound-file) (system (strcat "rm " my-sound-file))) (defun ex28 () ; normalize in memory. First, assign the sound to a variable so ; it will be retained: (setf mysound (sim (osc c4) (osc c5))) ; now compute the maximum value (ny:all is a 1 giga-samples, you may want a ; smaller constant if you have less than 4GB of memory :-): (setf mymax (snd-max mysound NY:ALL)) (display "Computed max" mymax) ; now write out and play the sound from memory with a scale factor: (play (scale (/ 1.0 mymax) mysound))) (defun ex29 () ; if you don't have space in memory, here's how to do it: (defun myscore () (sim (osc c4) (osc c5))) ; compute the maximum, don't forget the quote!: (setf mymax (snd-max '(myscore) NY:ALL)) (display "Computed max" mymax) ; now we know the max, but we don't have a the sound (it was garbage ; collected and never existed all at once in memory). Compute the sound ; again, this time with a scale factor:] (play (scale (/ 1.0 mymax) (myscore)))) (defun ex30 () (play (fmosc c4 (pwl 0.1)))) (defun ex31 () (play (fmosc c4 (pwl 0.5)))) (defun ex32 () (play (fmosc c4 (pwl 0.5 (step-to-hz c4) 0.501)))) (defun ex33 () (setf *fm-voice* (list (extract 0.110204 0.13932 (cue a-snd)) 24.848422 T)) (play (fmosc cs2 (pwl 0.5 (step-to-hz cs2) 0.501) *fm-voice* 0.0))) (defun sweep (delay pitch-1 sweep-time pitch-2 hold-time) (let ((interval (- (step-to-hz pitch-2) (step-to-hz pitch-1)))) (pwl delay 0.0 ; sweep from pitch 1 to pitch 2 (+ delay sweep-time) interval ; hold until about 1 sample from the end (+ delay sweep-time hold-time -0.0005) interval ; quickly ramp to zero (pwl always does this, ; so make it short) (+ delay sweep-time hold-time)))) (defun ex34 () (play (fmosc cs2 (sweep 0.1 cs2 0.6 gs2 0.5) *fm-voice* 0.0))) (defun ex35 () (play (fmosc cs2 (scale 10.0 (lfo 6.0)) *fm-voice* 0.0))) (defun ex36 () (let (modulator) (setf modulator (mult (pwl 1.0 1000.0 1.0005) (osc c4))) (play (fmosc c4 modulator)))) ;;; FINDING ZERO CROSSINGS, SND-SAMPLES (setf max-samples-for-zeros 1000) (defun zeros (snd) ; start by getting the samples, only take 1000 samples max (prog ((s (snd-samples snd max-samples-for-zeros)) newsign sign n len result result2 starttime srate) ; go through the array looking for zero crossings (setf len (length s)) ; stop if there are no samples (if (= len 0) (return nil)) (setf sign (> 0.0 (aref s 0))) ; get the start time and sample rate of the sound for use below (setf starttime (car (snd-extent snd max-samples-for-zeros))) (setf srate (snd-srate snd)) (setf n 1) loop (if (>= n len) (go done)) (setf newsign (> 0.0 (aref s n))) (if (not (eq sign newsign)) (setf result (cons n result))) (setf sign newsign) (setf n (1+ n)) (go loop) done ; now we have the zero crossings, convert them to times (dolist (num result) ; return the time of the zero crossing, which is the start time of the snd plus the sample number / srate (setf result2 (cons (+ starttime (/ num srate)) result2))) (return result2))) (defun ex37 () ; extract a short piece of this sample (setf short (extract 0.1 0.14 (cue a-snd))) (setf z (zeros short)) (format t "Zero crossings from a-snd: ~A~%" z)) ; find the differences between zero crossings reported by zeros ; print the result in terms of samples for readability ; (defun periods (lis short) (prog (result prev srate) (if (null lis) (return nil)) (setf srate (snd-srate short)) loop (setf prev (car lis)) (setf lis (cdr lis)) (if (null lis) (return (reverse result))) (setf result (cons (* srate (- (car lis) prev)) result)) (go loop))) (defun ex38 () ; ex38 depends upon z, set by (ex37) (cond ((not (boundp 'z)) (ex37))) (setf p (periods z short)) (format t "The intervals (in samples) between zero crossings are: ~%~A~%" p)) ; build a wavetable using zero crossing information ; ; I interactively played with the data and decided to extract from the ; 5th period to the 21st period (these had 86 and 87 samples each and ; seem to indicate some kind of periodicity). The 1st period measures ; from the zeroth zero crossing to the first, so the 5th period measures ; from the 4th zero crossing to the 5th. I'll arbitrarily take ; the 4th and 20th zero crossing times (the 5th and 20th should work as ; well), and from the data, this looks like 2 waveform periods. ; This is very clear if you plot the data. ; ; arguments are: ; snd - the sound to extract from ; zeros - the result of (zeros snd) ; start - the number of the starting zero crossing ; stop - the number of the ending zero crossing ; n - number of periods contained in the extracted sound ; (defun extract-table (snd zeros start stop n) (let (starttime extent hz) ; Start by shifting snd to time zero: (setf starttime (car (snd-extent snd max-samples-for-zeros))) (setf snd (at (- starttime) (cue snd))) (format t "~A~%" snd) ; also get the start and stop times and shift them: (setf start (- (nth start zeros) starttime)) (setf stop (- (nth stop zeros) starttime)) (format t "table ~A start ~A stop ~A~%" snd start stop) ; now extract the samples of interest, note that we are ; overwriting our pointer to the snd argument (setf snd (extract start stop (cue snd))) (format t "table now ~A~%" snd) ; now we need to figure out the pitch this sound would represent ; when played at its samplerate. The pitch in hz is 1 / duration, ; and duration is the extent of the sound / n. Therefore, take ; n/extent (setf extent (snd-extent snd max-samples-for-zeros)) (setf hz (/ n (- (cadr extent) (car extent)))) ; an osc table is a list of the sound, pitch number, and T (periodic) (list snd (hz-to-step hz) T))) (defun ex39 () ; try it out (setf *a-voice* (extract-table short z 4 20 2)) ; now use the table with an oscillator (play (osc c3 1.0 *a-voice* ))) (defun ex40 () ; play it at its normal pitch (play (osc (cadr *a-voice*) 1.0 *a-voice*))) (defun ex41 () (play (noise))) (defun ex42 () (play (lp (noise) 1000.0))) (defun ex43 () (play (hp (noise) 1000.0))) ; low pass sweep from 100 hz to 2000 hz (defun ex44 () (play (lp (noise) (pwl 0.0 100.0 1.0 2000.0 1.0)))) ; high pass sweep from 50 hz to 4000 hz (defun ex45 () (play (hp (noise) (pwl 0.0 50.0 1.0 4000.0 1.0)))) ; band pass at 500 hz, 20 hz bandwidth (defun ex46 () (play (reson (scale 10.0 (noise)) 500.0 20.0 1))) ; band pass sweep from 100 to 1000 hz, 20 hz bandwidth (defun ex47 () (play (reson (scale 0.04 (noise)) (pwl 0.0 200.0 1.0 1000.0 1.0) 20.0))) (format t "\nType (ex1) through (ex47) to run these examples.\n") (format t "See demos/stktest.lsp for more simple sound examples.\n") (format t "\nI'm turning off Auto-normalization. See AUTONORM-ON\n") (format t "in the documentation for an explanation:\n\n") (autonorm-off) (defun ex-all () (format t "Warning: turning automatic normalization feature off~%") (autonorm-off) (dotimes (i 47) (let ((j (+ i 1)) fn) (setf fn (intern (format nil "EX~A" j))) (setf fn (list fn)) (format t "~A~%" fn) (eval fn)))) (format t "\n(ex-all) will compute and play all examples for testing purposes.\n") nyquist-3.05/demos/stktest.lsp0000644000175000000620000002666111466723256015542 0ustar stevestaff;; stktest.lsp -- test the STK instruments (autonorm-on) (print "Type (makedemo number) with number ranging from 1 to 17") (print "Type (all-stk-demos) to hear them all") (defun makedemo (n) (case n (1 (progn (nrev-demo)(print "NRev Demo"))) (2 (progn (jcrev-demo)(print "JCRev Demo"))) (3 (progn (prcrev-demo)(print "PRCRev Demo"))) (4 (progn (stkchorus-demo)(print "Chorus Demo"))) (5 (progn (pitshift-demo) (print "Pitch Shift Demo"))) (6 (progn (flute-demo)(print "Flute Demo"))) (7 (progn (flute-freq-demo)(print "Flute Freq Demo"))) (8 (progn (flute-all-demo)(print "Flute All Demo"))) (9 (progn (bowed-demo 0.4)(print "Bowed Instrument Demo"))) (10 (progn (bowed-freq-demo)(print "Bowed Freq Instrument Demo"))) (11 (progn (mandolin-demo)(print "Mandolin Demo"))) (12 (progn (wg-uniform-bar-demo) (print "Uniform Bar Wave Guide Demo"))) (13 (progn (wg-tuned-bar-demo)(print "Tuned Bar Wave Guide Demo"))) (14 (progn (wg-glass-harm-demo)(print "Glass Harmonica Wave Guide Demo"))) (15 (progn (wg-tibetan-bowl-demo)(print "Tibetan Bowl Prayer Wave Guide Demo"))) (16 (progn (modalbar-demo)(print "Modal Bar Demo"))) (17 (progn (sitar-demo) (print "Sitar Demo"))) (18 (progn (clarinet-example-1) (print "Clarinet Demo 1"))) (19 (progn (clarinet-example-2) (print "Clarinet Demo 2"))) (20 (progn (clarinet-example-3) (print "Clarinet Demo 3"))) (21 (progn (clarinet-example-4) (print "Clarinet Demo 4"))) (22 (progn (clarinet-example-5) (print "Clarinet Demo 5"))) (23 (progn (sax-example-1) (print "Sax Demo 1"))) (24 (progn (sax-example-2) (print "Sax Demo 2"))) (t (error "number ranges from 1 to 24")))) (defun all-stk-demos () (dotimes (i 24) (makedemo (1+ i)))) ;;; ******************************** ;;; ;;; EFFECTS DEMOS ;;; ;;; ******************************** ; design of a tubular-bell-like sound (setf *pi-over-2* (/ 3.141592 2)) (defun pan-fun-l (x) (* (/ (sqrt 2.0)) (- (cos (* x *pi-over-2*)) (sin (* x *pi-over-2*))))) (defun pan-fun-r (x) (* (/ (sqrt 2.0)) (+ (cos (* x *pi-over-2*)) (sin (* x *pi-over-2*))))) (defun pan-snd (snd pan) (vector (scale (pan-fun-l pan) snd) (scale (pan-fun-r pan) snd))) (defun tub-partial (scale-factor freq-factor time-factor pitch dur) (scale scale-factor (mult (sim -1.0 (pwev 10 (* dur time-factor) 1)) (osc (hz-to-step (* freq-factor (step-to-hz pitch))) (* dur time-factor))))) (defun tubular (pitch dur) (let ((hz (step-to-hz pitch))) (sim (tub-partial 0.1 1.0 1.0 pitch dur) (tub-partial 0.06 2.76 0.8 pitch dur) (tub-partial 0.04 5.4 0.7 pitch dur) (tub-partial 0.03 8.93 0.4 pitch dur) (tub-partial 0.02 13.34 0.2 pitch dur) (tub-partial 0.01 18.64 0.1 pitch dur) (tub-partial 0.005 31.87 0.05 pitch dur)))) (defun ktubular (&key pitch idur pan dyn) (pan-snd (scale dyn (tubular pitch idur)) pan)) ; (if rev (nrev snd 4 0.25) ; snd))) ; algorithmic score by means of Xmusic (setf pitches1 (make-cycle (list c5 g4 e4 c4) :for 8)) (setf pitches2 (make-cycle (list c5 a4 f4 d4) :for 8)) (setf *pitches* (make-cycle (list pitches1 pitches2) :for 6)) (setf *ioi* (make-cycle (list 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.6))) (setf *pan* (make-cycle (list 0 -0.2 0.2 -0.4 0.4 -0.45 0.45 -0.1 0.1 -0.25 0.25 -0.3 0.3))) (setf *dyn* (make-cycle (list 1 1 1 1 1 1 1 1.2 2 2 1 2 1 2 1 2 ))) (setf my-score (score-gen :name 'ktubular :dur 1 :idur 2 :ioi 0.2 :pitch (next *pitches*) :dyn (next *dyn*) :pan (next *pan*) :score-len 16)) (defun nrev-demo () (play (seq (timed-seq my-score) (nrev (timed-seq my-score) 4.0 0.25)))) ;(nrev-demo) (defun jcrev-demo () (play (seq (timed-seq my-score) (jcrev (timed-seq my-score) 4.0 0.25)))) ;(jcrev-demo) (defun prcrev-demo () (play (seq (timed-seq my-score) (prcrev (timed-seq my-score) 4.0 0.25)))) ;(prcrev-demo) (defun stkchorus-demo () (play (seq (timed-seq my-score) (stkchorus (timed-seq my-score) 0.1 0.2 0.5)))) ;(stkchorus-demo) (defun pitshift-demo () (play (seq (timed-seq my-score) (pitshift (timed-seq my-score) 2.0 0.9) (pitshift (timed-seq my-score) 0.4 0.7) (pitshift (timed-seq my-score) 6.0 0.7)))) ;(pitshift-demo) ; ******************************************* ; ; INSTRUMENTS DEMOS ; ; ******************************************* (defun env1 (d) (pwl 0.1 0.7 (- d 0.3) 0.5 d)) (defun flute-demo () (play (seq (flute e5 (env1 1)) (flute c5 (env1 1)) (flute g4 (env1 2))))) ;(flute-demo) (defun env2 (ampl d) (scale ampl (mult (pwlv 0.0 1.0 0.0 d 1.0) (lfo 5 d)))) (defun flute-freq-demo () (play (flute-freq c5 (env1 6) (env2 8 6)))) ;(flute-freq-demo) (defun env3 (d) (pwl (* d 0.5) 20 d)) (defun flute-all-demo () (play (flute-all c5 (env1 6) (env3 6) 6 0.2 0.5 0.06))) ;(flute-all-demo) (defun bow-env (d) (pwl 0.05 0.5 (- d 0.1) 0.3 d)) (defun bowed-demo (d) (play (seq (bowed g4 (bow-env d)) (bowed d5 (bow-env d)) (bowed b5 (bow-env d)) (bowed a5 (bow-env d)) (bowed b5 (bow-env d)) (bowed d5 (bow-env d)) (bowed b5 (bow-env d)) (bowed d5 (bow-env d)) (bowed g4 (bow-env d))))) ;(bowed-demo 0.4) (defun bowed-freq-demo () (play (bowed-freq c3 (bow-env 10) (env2 5 10)))) ;(bowed-freq-demo) (defun mandolin-demo () (play (seq (mandolin c4 1.0) (mandolin c4 1.0 2.0) (mandolin c4 1.0 3.0) (mandolin c4 1.0 4.0) (mandolin c4 1.0 5.0) (mandolin c4 1.0 6.0) (mandolin c4 1.0 7.0) (mandolin c4 1.0 8.0) (mandolin c4 1.0 9.0) (mandolin c4 1.0 10.0) (mandolin c4 1.0 11.0) (mandolin c4 1.0 12.0) (mandolin c4 1.0 13.0) (mandolin c4 1.0 14.0) (mandolin c4 1.0 15.0) (mandolin c4 1.0 16.0) (mandolin c4 1.0 17.0) (mandolin c4 1.0 18.0) (mandolin c4 1.0 19.0) (mandolin c4 1.0 20.0) (mandolin c4 1.0 25.0) (mandolin c4 1.0 30.0) (mandolin c4 1.0 35.0) (mandolin c4 1.0 40.0) (mandolin c4 1.0 45.0) (mandolin c4 1.0 50.0) (mandolin c4 1.0 55.0) (mandolin c4 1.0 60.0) (mandolin c4 1.0 65.0)))) ;(mandolin-demo) (defun wg-env (d) (pwlv 1 d 1)) (defun wg-uniform-bar-demo () (play (seq (wg-uniform-bar c4 (wg-env 0.2)) (wg-uniform-bar g3 (wg-env 0.2)) (wg-uniform-bar c4 (wg-env 0.2)) (wg-uniform-bar e4 (wg-env 0.2)) (wg-uniform-bar g4 (wg-env 2.2))))) ;(wg-uniform-bar-demo) (defun wg-tuned-bar-demo () (play (seq (wg-tuned-bar c4 (wg-env 0.2)) (wg-tuned-bar g3 (wg-env 0.2)) (wg-tuned-bar c4 (wg-env 0.2)) (wg-tuned-bar e4 (wg-env 0.2)) (wg-tuned-bar g4 (wg-env 0.2))))) ;(wg-tuned-bar-demo) (defun wg-glass-harm-demo () (play (seq (wg-glass-harm c4 (wg-env 0.2)) (wg-glass-harm g3 (wg-env 0.2)) (wg-glass-harm c4 (wg-env 0.2)) (wg-glass-harm e4 (wg-env 0.2)) (wg-glass-harm g4 (wg-env 1.2))))) ;(wg-glass-harm-demo) (defun wg-tibetan-bowl-demo () (play (seq (wg-tibetan-bowl c4 (wg-env 0.2)) (wg-tibetan-bowl ef4 (wg-env 0.2)) (wg-tibetan-bowl fs4 (wg-env 0.2)) (wg-tibetan-bowl a4 (wg-env 2.0))))) ;(wg-tibetan-bowl-demo) (defun modalbar-demo-1 (prst) (seq (modalbar prst c4 0.2) (modalbar prst g3 0.2) (modalbar prst c4 0.2) (modalbar prst e4 0.2) (modalbar prst g4 1.0))) (defun modalbar-demo () (play (seq (modalbar-demo-1 'MARIMBA) (modalbar-demo-1 'VIBRAPHONE) (modalbar-demo-1 'AGOGO) (modalbar-demo-1 'WOOD1) (modalbar-demo-1 'RESO) (modalbar-demo-1 'WOOD2) (modalbar-demo-1 'BEATS) (modalbar-demo-1 'TWO-FIXED) (modalbar-demo-1 'CLUMP)))) ;(modalbar-demo) (defun sitar-demo () (play (seq (sitar c3 0.6) (sitar g3 1.2) (sitar fs3 0.4) (sitar g3 0.4) (sitar af3 0.6) (sitar ef3 2.0)))) ;(sitar-demo) ;; simple clarinet sound (defun clarinet-example-1 () (play (clarinet bf3 (stk-breath-env 1 0.2 0.1)))) ;; clarinet sound with frequency sweep (glissando) (defun clarinet-example-2 () (play (clarinet-freq bf3 (stk-breath-env 3 0.2 0.1) (pwl 1.5 80 3 80 3)))) ;; clarinet sound with change in breath pressure (defun clarinet-example-3 () (play (clarinet bf3 (prod (pwl 0 1 1.5 0.9 3 1 3) (stk-breath-env 3 0.2 0.1))))) ;; clarinet sound using initial frequency sweep and built-in vibrato effect (defun clarinet-example-4 () (play (clarinet-all bf3 (stk-breath-env 3 0.5 0.05) (pwl 0.3 80 3 80 3) 5.7 0.5 0 0))) ;; clarinet sound with increasing then decreasing reed stiffness (defun clarinet-example-5 () (play (clarinet-all bf3 (stk-breath-env 3 0.5 0.05) 0 0 0 (pwl 1.5 0.75 3) 0))) ;; clarinet sound with increasing noise, with vibrato (defun clarinet-example-6 () (play (clarinet-all bf3 (stk-breath-env 3 0.5 0.05) 0 5.7 0.5 0 (pwl 3 1 3)))) ;(print "clarinet-example-1") ;(clarinet-example-1) ;(print "clarinet-example-2") ;(clarinet-example-2) ;(print "clarinet-example-3") ;(clarinet-example-3) ;(print "clarinet-example-4") ;(clarinet-example-4) ;(print "clarinet-example-5") ;(clarinet-example-5) ;(print "clarinet-example-6") ;(clarinet-example-6) (defun sax-example-1 () (scale 0.5 (timed-seq '( (0.0 1 (sax g3 (stk-breath-env 2 0.2 0.2))) (2.0 1 (sax-freq c4 (stk-breath-env 4 0.6 0.6) (scale 100 (mult (pwl 0 0.95 4 1.3 4))))) ))) ) (defun sax-example-2 () (scale 0.5 (timed-seq '( (0.0 1 (sax-freq bf3 (eight-sixteenths-env) (freqenv 1 bf3 (list 0 bf3 0.125 af4 0.25 g4 0.375 d4 0.5 f4 0.625 ef4 0.75 d4 0.875 ef4)))) (1.0 1 (sax-freq e4 (eight-sixteenths-env) (freqenv 1 e4 (list 0 e4 0.125 c4 0.25 a3 0.375 e3 0.5 fs3 0.625 e3 0.75 fs3 0.875 e4)))) (2.0 1 (sax-freq d4 (eight-sixteenths-env) (freqenv 1 d4 (list 0 d4 0.125 c4 0.25 b3 0.375 a3 0.5 g3 0.625 a3 0.75 b3 0.875 d4)))) (3.0 1 (sax-freq ef4 (eight-sixteenths-env) (freqenv 1 ef4 (list 0 ef4 0.125 cs4 0.25 b3 0.375 bf3 0.625 gf3 0.75 af3 0.875 bf4)))))))) (defun eight-sixteenths-env () (mult (envbreaks 1 (list 0.125 0.25 0.375 0.5 0.625 0.75 0.875)) (stk-breath-env 1 1 1))) (defun hzdiff (step1 step2) (- (step-to-hz step2) (step-to-hz step1))) ;; create a piecewise-constant (stairstep) function to control frequencies ;; timesteplist is (time0 step0 time1 step1 etc.) ;; (defun freqenv (dur step timesteplist) (let ((finalenv nil) hzdiff (tslist timesteplist) currt currs) (do () ((null tslist)) (setf currt (car tslist)) (setf currs (cadr tslist)) (setf tslist (cdr (cdr tslist))) (setf finalenv (append finalenv (list currt (hzdiff step currs) (if (null tslist) dur (car tslist)) (hzdiff step currs)) ))) (setf finalenv (append finalenv (list dur))) (pwl-list finalenv))) ;; create a breath envelope where pressure goes to zero at designated points ;; dur is overall duration ;; breaklist is places where pressure dips to zero during a 20ms window ;; (defun envbreaks (dur breaklist) (let ((finalenv nil)) (dolist (breakpt breaklist) (setf finalenv (append finalenv (list (- breakpt 0.01) 1 (- breakpt 0.001) 0 breakpt 1)))) (setf finalenv (append (list 0 1) finalenv (list dur))) (pwl-list finalenv))) ;(print "sax-example-1") ;(play (sax-example-1)) ;(print "sax-example-2") ;(play (sax-example-2)) nyquist-3.05/demos/fft_demo.lsp0000644000175000000620000001306211466723256015613 0ustar stevestaff;; this code is extracted from fft_tutorial.htm ;; ;; Roger B. Dannenberg, 2001 ;; ;; Please see fft_tutorial.htm for more in-depth comments and explanations. ;; (setf fft1-class (send class :new '(sound length skip))) (send fft1-class :answer :next '() '( (snd-fft sound length skip nil))) (send fft1-class :answer :isnew '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp))) (defun make-fft1-iterator (sound length skip) (send fft1-class :new (snd-copy sound) length skip)) ;; create a 1-second sinusoid with points samples at cycles hz: (defun short-sine (points cycles) (control-srate-abs points (lfo cycles))) (defun fft-test () (let (fft-iter) ;; signal will have 4 cycles in 32 points: (setf fft-iter (make-fft1-iterator (short-sine 32 4) 32 32)) (display "fft-test" (send fft-iter :next)))) (defun ifft-test () (let (fft-iter ifft-snd) (setf fft-iter (make-fft1-iterator (short-sine 32 4) 32 32)) (setf ifft-snd (snd-ifft 0 32 fft-iter 32 NIL)) (display "fft-ifft" (snd-length ifft-snd 200)) (display "fft-ifft" (snd-samples ifft-snd 200)) )) (defun file-fft1 (filename frame-length skip) (make-fft1-iterator (s-read filename) frame-length skip)) (defun play-fft1 (iterator skip) (play (snd-ifft 0 *sound-srate* iterator skip NIL))) ;; a convenient sound file name (change this to one of your soundfiles): (setf sfn "/Users/rbd/class/icm2009/sounds/talking.wav") (defun file-test () (play-fft1 (file-fft1 sfn 512 512) 512)) (setf fft-hp-class (send class :new '(source bins))) (send fft-hp-class :answer :next '() '( (let ((frame (send source :next))) (cond (frame (dotimes (i bins) (setf (aref frame i) 0.0)))) frame))) (send fft-hp-class :answer :isnew '(s b) '( (setf source s) (setf bins b))) (defun make-fft-hp (source bins) (send fft-hp-class :new source bins)) (defun hp-test () (play-fft1 (make-fft-hp (file-fft1 sfn 512 512) 11) 512)) (defun fm-tone (step mi1 mi2 mi3) (let ((hz (step-to-hz step))) (setf mi1 (* mi1 hz)) (setf mi2 (* mi2 hz)) (setf mi3 (* mi3 hz)) (fmosc c4 (partial step (control-srate-abs *sound-srate* (pwl 0 mi1 0.5 mi2 1 mi3 1)))))) (defun mod-snd (sfn) ; to get duration of file, open it and look at the 6th element ; of the extra return values in *rslt* (stretch (nth 6 (progn (s-read sfn) *rslt*)) (sum (fm-tone c3 15 20 15) ;; adjust FM parameters here (fm-tone d3 15 20 15) ;; adjust FM parameters here (fm-tone e3 15 20 15)))) ;; adjust FM parameters here (setf fft-modulator-class (send class :new '(src1 src2))) (send fft-modulator-class :answer :isnew '(s1 s2) '( (setf src1 s1) (setf src2 s2))) (send fft-modulator-class :answer :next '() '( (let ((frame1 (send src1 :next)) (frame2 (send src2 :next)) n half_n) (cond ((and frame1 frame2) ; multiply frame2 by the amplitude coefficients of frame1 (setf (aref frame2 0) (* (aref frame2 0) (aref frame1 0))) ;; DC (setf n (- (length frame1) 1)) ; Subtracted 1 because we already took care of DC component (setf half_n (/ n 2)) ; integer divide (dotimes (i half_n) (let* ((i2 (+ i i 2)) (i2m1 (- i2 1)) (amp (sqrt (+ (* (aref frame1 i2m1) (aref frame1 i2m1)) (* (aref frame1 i2) (aref frame1 i2)))))) (setf (aref frame2 i2m1) (* (aref frame2 i2m1) amp)) (setf (aref frame2 i2) (* (aref frame2 i2) amp)))) (cond ((= n (+ half_n half_n 2)) ;; n is even -> nyquist component (setf (aref frame2 n) (* (aref frame2 n) (aref frame1 n))))) frame2) (t nil))))) (defun make-fft-modulator (src1 src2) (send fft-modulator-class :new src1 src2)) (defun mod-test () (let ((fs 512)) ;; frame size (play-fft1 (make-fft-modulator (file-fft1 sfn fs fs) (make-fft1-iterator (mod-snd sfn) fs fs)) fs))) (defun raised-cosine () (scale 0.5 (sum (const 1) (lfo (/ 1.0 (get-duration 1)) 1 *sine-table* 270)))) (defun fft-window (frame-size) (control-srate-abs frame-size (raised-cosine))) (defun play-fft (iterator frame-size skip) (play (snd-ifft 0 *sound-srate* iterator skip (fft-window frame-size)))) (defun mod-test-w () (let ((fs 512)) ;; frame size (play-fft (make-fft-modulator (file-fft1 sfn fs (/ fs 2)) (make-fft1-iterator (mod-snd sfn) fs (/ fs 2))) fs (/ fs 2)))) (setf fft-class (send class :new '(sound length skip window))) (send fft-class :answer :next '() '( (snd-fft sound length skip window))) (send fft-class :answer :isnew '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp) (setf window (fft-window len)) )) (defun make-fft-iterator (sound length skip) (send fft-class :new (snd-copy sound) length skip)) (defun file-fft (filename frame-length skip) (make-fft-iterator (s-read filename) frame-length skip)) (defun mod-test-ww () (let ((fs 512)) ;; frame size (play-fft (make-fft-modulator (file-fft sfn fs (/ fs 2)) (make-fft-iterator (mod-snd sfn) fs (/ fs 2))) fs (/ fs 2)))) (defun mod-test-wws () (let ((fs 1024)) ;; frame size (play-fft (make-fft-modulator (file-fft sfn fs (/ fs 16)) (make-fft1-iterator (mod-snd sfn) fs (/ fs 16))) fs (/ fs 2)))) nyquist-3.05/demos/lpcdemo.lsp0000644000175000000620000001724411466723256015461 0ustar stevestaff;;; LPC demo 1 ;;; Pedro J. Morales. ;;; February, 04 ;;; Roger B. Dannenberg ;;; July, 04 ; where is the file lpc-exmpl.dat (setf *lpc-path* (current-path)) (setf *lpc-data* (strcat *lpc-path* "lpc-exmpl.dat")) ; this file generated by Nyquist will be loaded by Octave (or Matlab) (setf *default-octave-file* (strcat *lpc-path* "nyquist.dat")) ; make sure lpc.lsp is loaded (if (not (fboundp 'lpreson)) (load "lpc.lsp")) ; file-io tools ======================================================== (defun octave-1 (outf data varname datatype &optional (n 1000)) (prog ((points (case datatype (SND (snd-samples data (1+ n))) (ARR data))) len) (setf len (length points)) (cond ((> len n) (setf len n) (format t "WARNING: DATA TRUNCATED TO ~A POINTS~%" len))) (format outf "# name: ~A\n" varname) (format outf "# type: matrix\n# rows: 1\n# columns: ~A\n " len) (dotimes (i len) (format outf "~A " (aref points i))) (format outf "\n"))) (defun octave (data-lists) ; (data varname datatype &optional (n 1000)) (prog ((filename *default-octave-file*) outf) (setf outf (open filename :direction :output)) (cond ((null outf) (format t "octave: could not open ~A!~%" filename) (return nil))) (format t "octave: writing ~A ... ~%" filename) (cond ((null outf) (format t "octave: could not open ~A!~%" filename) (return nil))) ;(format t "octave: writing ~A ... ~%" filename) (dolist (l data-lists) (apply #'octave-1 (cons outf l))) (close outf))) ; LPANAL ====================================================== ; get lpc data --------------------------------------------------- (defun do-lpc-analysis () (let ((myfile (strcat *lpc-path* "a-snd-file.snd"))) (save-lpc-file (make-lpanal-iterator (s-read *myfile*) 0.08 0.04 50) "temp.dat"))) ; SHOW-LPC-DATA ------------------------------------------------ ; show values of LPC analysis frames ---------------------------- (defun ex-1 () ; do not show filter coefs (show-lpc-data (make-lpc-file-iterator *lpc-data*) 100 120 NIL)) ; ------- SAVE-FILE-DATA --------------------------------------- (defun ex-2 () (save-lpc-file (make-lpc-file-iterator *lpc-data*) "temp2.dat")) ;----------- LPC-FREQ ------------------------------------------ ; LPC-FREQ. Show frequency response of ALLPOLES filter. ; NEEDS MATLAB or OCTAVE ; (defun ex-3 () (lpc-freq "frm70" (make-lpc-file-iterator *lpc-data*) 70)) ; in MATLAB/OCTAVE: ; >> load -force nyquist.dat ; >> [H,W] = freqz(1, frm70, 512); ; >> plot(W,20*log10(abs(H))); ;------------------------------------------------------------------------- ; LPC-STABILITY Check for Stability of LPC filters ; NEEDS MATLAB/OCTAVE ; EXAMPLE ; (ex-3) ; in MATLAB/OCTAVE: ; >> load -force nyquist.dat ; >> find(abs(roots(frm70)) > 1) ; if any abs root is > 1.0 then UNSTABLE ;-------------------------------------------------------------------------- ; ALLPOLES LPC allpoles filter ; WARNING: this is a static filter ; for LPC resynthesis a dynamic LPC filter is needed ; EXAMPLE (defun ex-4 () (play (seq (allpoles-from-lpc (buzz 12 f2 (lfo 5.0 4.0)) (nth-frame (make-lpc-file-iterator *lpc-data*) 30)) (allpoles-from-lpc (buzz 12 f2 (lfo 5.1 4.0)) (nth-frame (make-lpc-file-iterator *lpc-data*) 60)) (allpoles-from-lpc (buzz 12 g2 (lfo 5.3 4.0)) (nth-frame (make-lpc-file-iterator *lpc-data*) 100)) ))) (setf a-lpcdata '(63.2144 0.674387 0.103287 #(-0.0381026 0.00804115 0.0109905 0.0145117 0.00199174 -0.00129314 0.0171826 0.0181176 0.00179391 -0.0114089 -0.0120949 -0.000410595 -0.0122539 -0.0209354 -0.00804976 -0.00345041 -0.00409532 -0.00227011 0.014224 0.0135451 0.0056023 -0.00651142 -0.00564953 -0.0168921 -0.0377939 -0.0449506 -0.0355592 -0.0339316 -0.0454434 1.19336))) (setf e-lpcdata '(40.7157 0.149753 0.0606467 #(0.0244574 -0.0225545 -0.0172724 -0.0122709 -0.0042946 0.00886974 0.0121516 0.0120936 0.00197545 -0.00582163 -0.018367 -0.0201546 -0.00440599 0.00638936 0.0166275 0.0185066 0.00890464 -0.00158013 -0.00494974 -0.00479037 0.0130814 0.0138648 -0.0022018 -0.021368 -0.0343532 -0.0312712 -0.0574975 -0.0918824 -0.112016 1.31398))) (setf i-lpcdata '(5.5391 0.0321825 0.0762238 #(-0.0341124 -0.0149688 -0.00585657 -0.0111572 0.00769712 0.0190367 0.00885366 0.0112762 0.0118286 -0.00059044 -0.0140864 -0.0123688 -0.0151128 0.00214354 -0.00810219 -0.00538188 0.00631382 0.020771 0.0356498 0.0295531 0.0242797 0.0124296 0.00445127 -0.013062 -0.0387178 -0.0527783 -0.0685511 -0.076575 -0.0846335 1.24521))) (defun noise-vocal (lpcdata dur) (allpoles-from-lpc (noise dur) lpcdata)) (defun ex-5 () (play (seq (noise-vocal a-lpcdata 1) (noise-vocal e-lpcdata 1) (noise-vocal i-lpcdata 1)))) (defun buzz-vocal (lpcdata dur) (allpoles-from-lpc (buzz 16 e2 (const 0.0 dur)) lpcdata)) (defun ex-6 () (play (seq (buzz-vocal a-lpcdata 1) (buzz-vocal e-lpcdata 1) (buzz-vocal i-lpcdata 1)))) ; ---- LPRESON ------------------------------------------------------------ ; (defun ex-7a () ;; parameters are sound, lpc-iterator, skiptime (lpreson (noise 6.5) (make-lpc-file-iterator *lpc-data*) 0.04)) (defun ex-7 () (play (ex-7a))) (defun ex-8a (p dur) (lpreson (buzz 16 p (scale 1.5 (lfo 3.0 dur))) (make-lpc-file-iterator *lpc-data*) 0.04)) (defun ex-8 () (play (sim (seq (ex-8a c4 1) (ex-8a g3 1) (ex-8a a3 1) (ex-8a b3 1) (ex-8a c4 1)) (seq (ex-8a c2 2) (ex-8a f2 1) (ex-8a g2 1) (ex-8a e2 1))))) (defun noalias-buzz (p nmax) (min (round (/ *sound-srate* (* 2.0 (step-to-hz p)))) nmax)) (defun ex-9a (p dur skiptime) (mult (env 0.01 0.01 0.1 1.0 1.0 1.0 dur) (lpreson (buzz (noalias-buzz p 16) p (scale 1.5 (lfo 3.0 dur))) (make-lpc-file-iterator *lpc-data*) skiptime))) (defun ex-9b (stretch skiptime) (play (sim (seq (ex-9a c4 (* 1 stretch) skiptime) (ex-9a g3 (* 1 stretch) skiptime) (ex-9a a3 (* 1 stretch) skiptime) (ex-9a b3 (* 1 stretch) skiptime) (ex-9a c4 (* 1 stretch) skiptime)) (seq (ex-9a c2 (* 2 stretch) skiptime) (ex-9a f2 (* 1 stretch) skiptime) (ex-9a g2 (* 1 stretch) skiptime) (ex-9a e2 (* 1 stretch) skiptime))))) (defun ex-9 () (ex-9b 1.0 0.04)) (defun ex-10 () (ex-9b 1.0 0.02)) (defun ex-11 () (ex-9b 2.0 0.04)) (defun ex-12 () (ex-9b 0.5 0.02)) (defun ex-13 () (ex-9b 4 0.02)) (defun ex-14a (p dur skiptime) (mult (env 0.01 0.01 0.1 1.0 1.0 1.0 dur) (lpreson (osc-saw (sim (step-to-hz (+ p 0)) (scale 1.5 (lfo 3.0 dur)))) (make-lpc-file-iterator *lpc-data*) skiptime))) (defun ex-14b (stretch skiptime) (play (sim (seq (ex-14a c4 (* 1 stretch) skiptime) (ex-14a g3 (* 1 stretch) skiptime) (ex-14a a3 (* 1 stretch) skiptime) (ex-14a b3 (* 1 stretch) skiptime) (ex-14a c4 (* 1 stretch) skiptime)) (seq (ex-14a c2 (* 2 stretch) skiptime) (ex-14a f2 (* 1 stretch) skiptime) (ex-14a g2 (* 1 stretch) skiptime) (ex-14a e2 (* 1 stretch) skiptime))))) (defun ex-14 () (ex-14b 1 0.04)) (defun ex-15 () (ex-14b 4 0.02)) (defun ex-16 () (ex-14b 8 0.08)) nyquist-3.05/demos/lpc-exmpl.dat0000644000175000000620000026342510144436365015707 0ustar stevestaff(0.0205328 0.000539653 0.162119 #(0.0172437 -0.00206371 0.0199834 0.0140023 -0.107106 0.105376 -0.014147 -0.0456254 -0.035733 0.000526876 0.024559 -0.077979 0.0379572 0.0550832 0.0251978 -0.0158793 0.000201547 0.0183836 0.0120267 -0.0145289 0.0270053 0.0215023 -0.0674045 0.0868633 -0.0759818 0.0123872 -0.100426 0.0670379 0.153223 -0.160887 0.0200027 0.00857184 -0.0319345 0.0372642 -0.039906 0.0370124 -0.0406953 0.0916241 -0.0794324 0.0994091 -0.152256 0.122422 -0.131096 0.143904 -0.182573 0.107067 -0.216319 0.338997 -0.171402 1.04299)) (0.0746031 0.000883533 0.108826 #(0.043002 -0.0168565 0.0116234 -0.031321 -0.0728684 0.134856 0.0052372 -0.0477521 -0.0767405 0.0307031 0.00286882 -0.0188694 -0.0103552 0.0410824 -0.00991496 0.0129631 -0.0070764 0.0446677 -0.0316206 0.0103328 -0.00314631 0.0721652 -0.028264 0.0429488 -0.0757499 0.0355948 -0.124679 0.0341884 0.147169 -0.115948 0.0350534 -0.022784 0.00255128 0.000132609 0.00266292 0.0235752 -0.0270638 0.00319338 -0.0405898 0.0510949 -0.0525406 0.112875 -0.120262 0.103579 -0.140658 0.030511 -0.195171 0.226418 -0.194436 1.19625)) (7.90651 0.00254103 0.0179272 #(0.0298438 -0.0150177 0.00856811 0.00178307 -0.156251 0.141521 0.0377321 -0.00862076 0.0358013 -0.0526648 -0.0746482 0.0176761 0.0180553 0.0110547 -0.0149859 -0.00274912 0.00753696 0.0570906 -0.00985159 -0.0460384 -0.0312089 0.0275762 -0.00179828 0.0498972 -0.0462076 0.111785 -0.101277 -0.0429219 0.135046 -0.118618 0.0320909 0.0152628 0.00229011 0.000619642 -0.00148223 0.0698463 -0.0192731 -0.061608 -0.105966 0.00760205 -0.0556964 0.172818 -0.0018539 0.14807 -0.115714 0.0485711 -0.341883 0.118442 -0.644804 1.76356)) (16.8204 0.00353871 0.0145046 #(0.0242379 0.0163801 -0.0441124 0.0515951 -0.165318 0.0553254 0.118888 -0.00888211 0.0686623 -0.103195 -0.109872 0.0873954 -0.00312068 -0.0157818 0.00793753 -0.0102677 0.0385871 0.0402539 0.0275778 -0.124176 -0.0224998 -0.0083091 0.139262 -0.0326057 -0.0686154 0.152026 -0.0710961 -0.100093 0.0921394 -0.0886168 0.0962788 0.0235546 -0.0835561 0.0289921 -0.0519826 0.0819953 0.0677047 -0.04636 -0.154177 0.0188317 -0.0733893 0.18706 -0.117089 0.276443 -0.188078 0.136406 -0.348012 0.354862 -1.21044 2.05642)) (15.7527 0.00488585 0.0176113 #(0.0410332 -0.0212341 -0.0186016 0.0139835 -0.10253 0.0317464 0.098534 0.0577219 -0.00603218 -0.119189 -0.0560336 0.0600247 0.00563636 -0.00741701 -0.022568 0.0551003 0.0172174 -0.0145449 0.0377798 -0.0774387 -0.0623132 0.0156745 0.116856 0.0167625 -0.0740776 0.0976961 -0.0589157 -0.0592283 0.0621122 -0.0668073 0.0672344 0.0433492 -0.0724394 -0.0149194 -0.0174723 0.0940844 0.0192709 -0.037947 -0.145742 0.0166333 -0.0382952 0.137928 -0.0235971 0.142885 -0.0641163 -0.0401743 -0.14418 0.182686 -1.00692 1.93978)) (16.3531 0.0136897 0.0289333 #(-0.024896 0.016421 0.00786502 -0.0118406 0.00603457 0.0343453 0.0250988 -0.00670104 -0.0483285 -0.0402459 0.00284676 0.0223309 0.00649693 -0.0116516 0.00923614 0.0111503 -0.000440774 -0.0275555 0.00682401 -0.0125723 0.00263826 0.0153074 0.0242379 0.0142031 0.0060273 0.0192062 -0.0368178 0.00965019 0.0058204 -0.00736851 0.0414994 0.00440613 -0.0394615 -0.0217087 0.0132956 0.0116567 -0.024931 -0.0592983 -0.0327111 0.00831445 0.0282831 0.0678891 0.00450369 0.00915988 -0.0181229 -0.0469828 -0.0555707 -0.0913728 -0.228273 1.41019)) (22.7776 0.0128829 0.0237823 #(-0.0244512 0.00852192 0.00355279 0.0100932 -0.00419528 0.0237172 0.0103759 -0.0137028 -0.0251104 -0.0134613 -0.000615256 0.00165147 -0.00407305 -0.00344569 -0.00120993 0.0089017 0.000495352 -0.000238208 0.00294549 0.00112805 0.00425276 0.0266437 0.0165051 -0.0296654 -0.00157895 0.0406957 -0.0203225 0.000875471 0.0187371 -0.00604564 0.0124178 0.00848914 -0.00870932 -0.0345038 -0.0166086 -0.00777551 -0.0127552 -0.0198208 -0.018883 0.00170381 0.0281818 0.0335668 0.00621638 0.000123257 -0.0400046 -0.0251494 -0.0599436 -0.0484318 -0.0953316 1.26394)) (25.9418 0.014063 0.023283 #(-0.0146976 0.0123669 -0.00238331 -0.00566441 0.000213927 0.0251708 0.0058586 -0.0152624 -0.0096643 0.000380473 -0.00692432 -0.0103325 -0.00570062 -0.00779317 -0.00373097 -0.00244446 0.0232326 0.00687431 -0.0123666 0.0136142 0.000873428 0.01297 0.00157535 -0.0189359 0.0103542 0.0149338 -0.00232667 0.018195 0.0122806 0.000705099 0.0180465 -0.00723085 -0.0333543 -0.0209618 -0.00258482 -0.00346647 -0.0161793 -0.00443528 -0.0107334 -0.00729346 0.0212632 0.017004 -0.0134609 -0.0122188 -0.0266593 -0.0240987 -0.0584669 -0.0204726 -0.0728998 1.23429)) (26.411 0.0454326 0.0414755 #(-0.0109339 -0.0010968 -0.0010053 0.00617609 0.00306015 0.000136934 0.00372594 -0.00564924 -0.00591968 -0.00522412 -0.00509402 -3.17432e-006 -0.00446083 0.00456961 0.00243643 0.00451923 0.00334826 0.00559344 0.00805774 0.000849614 0.00365901 -0.000214671 -0.00258062 0.00132718 0.00916179 0.00321858 -0.00441098 0.00674969 0.00362521 0.00233835 0.00103611 -0.00365412 -0.0110665 -0.0113001 -0.00483079 -0.00471838 -0.0072024 -0.0112189 -0.00842469 -0.00122134 0.00258161 -0.00404681 -0.0108012 -0.0163903 -0.0156165 -0.0101237 -0.0119205 -0.0127908 -0.0241693 1.1353)) (26.023 0.0171174 0.0256472 #(-0.00659148 -0.0022813 0.00245043 0.0119932 0.00673879 0.0106215 0.000193227 -0.0118672 -0.00229731 -8.44562e-005 -0.010244 -0.0224172 -0.0074773 0.00139424 0.00442344 -0.00372009 0.00631038 0.00399001 0.00074413 0.00143648 0.0117816 0.0167116 -0.011429 0.00660101 -0.0154429 0.0245051 0.00954568 0.00221017 0.00972422 0.00691179 0.00198784 0.00641321 -0.0164092 -0.0286664 -0.00348171 -0.00646432 -0.0149224 -0.00929398 0.000946284 -0.00786511 0.0105857 0.0116371 -0.0208869 -0.0167969 -0.039235 -0.0416232 -0.0188724 -0.0395318 -0.0672928 1.2529)) (20.1471 0.0413173 0.0452855 #(0.0028042 0.00238915 0.00320531 0.00204744 -0.00128491 -0.000625469 0.00121502 -0.00053792 -0.00926453 -0.00168529 -0.0176347 -0.00451895 0.000996928 0.00430582 0.00194222 -0.00398466 0.00259957 0.00390882 0.0116503 0.00167209 -0.001884 0.00309071 0.00380416 0.00551039 0.0052082 0.00707811 -0.00293764 0.0110331 0.0118179 0.000155053 0.0029885 -0.0120471 -0.00528422 -0.0186305 -0.00389795 -0.01138 -0.0130287 -0.0114016 -0.00348096 0.00720399 -0.00393767 -0.00782219 -0.00889679 -0.0106665 -0.0241594 -0.0212916 -0.0261109 -0.0222356 -0.042137 1.1898)) (15.5487 0.0153078 0.0313768 #(0.0038797 -0.00898583 -0.00129375 0.0135476 0.00658722 0.0365788 0.00343157 -0.0308747 -0.0106992 -0.00551437 0.00041832 -0.0139702 -0.0154675 -0.0119801 -0.00961124 0.0151818 0.00235315 -0.00360607 -0.00300882 0.0133151 0.00953059 0.00235415 -1.91313e-005 0.00280704 0.0099642 0.0205634 0.00397632 0.00529698 0.023866 -0.00799138 0.0100504 0.0079582 -0.0250386 -0.029848 -0.0097943 -0.00418491 -0.0133331 -0.0233978 -0.00335522 0.0048438 0.0168547 0.0205229 -0.0161785 -0.0256227 -0.0427417 -0.0322054 -0.0493791 -0.0330071 -0.0981295 1.29245)) (19.0253 0.00596731 0.0177102 #(-0.0146168 -0.0100904 0.00214927 0.0184939 0.01049 0.0612408 -0.00438104 -0.0265871 -0.026429 0.00668405 0.0269023 -0.0263329 -0.0230587 -0.0429497 0.00384385 0.0294333 -0.00318107 -0.0136982 -0.00792112 0.0090845 0.0366004 -0.0174499 -0.00897093 -0.00784815 -0.00441435 0.0551205 -0.0163865 0.00471411 0.0446577 -0.0132054 0.0401863 0.0217569 -0.0372981 -0.0637524 -0.0140608 0.0379691 -0.012396 -0.0571539 -0.0387487 0.0285809 0.0555209 0.0533837 -0.020053 -0.00430533 -0.102708 -0.0554588 -0.0775484 0.00345876 -0.257812 1.45669)) (24.3361 0.00252815 0.0101924 #(-0.0257512 -0.0008726 0.0176086 0.0124685 -0.0534896 0.100064 0.0398205 -0.0701561 -0.0307596 0.00460567 0.0732452 -0.00591591 -0.0655563 -0.0244842 0.0128442 0.0333025 -0.0171489 -0.0529101 -0.0145168 -0.00558627 0.0716373 0.0169233 -0.00522713 0.00671804 -0.0615778 0.0634442 -0.0921752 0.00951979 0.120483 -0.077487 0.0914363 0.104565 -0.0653618 -0.089458 -0.0420491 0.0741933 -0.0368942 -0.0224205 -0.159684 0.0706304 0.0604807 0.156387 -0.0368354 0.00141878 -0.11703 -0.0250188 -0.215087 0.140998 -0.528956 1.65826)) (25.4722 0.00168582 0.00813527 #(-0.0361914 0.0503908 -0.052739 0.0874611 -0.161167 0.205034 -0.030822 -0.0297436 -0.0881124 0.0515133 0.029009 0.0911085 -0.133234 0.00447612 -0.0102752 0.0672411 -0.0743354 0.0278325 -0.088049 0.0254583 0.00378763 0.110739 -0.0335123 0.0437825 -0.111471 0.143021 -0.205556 0.0105061 0.178276 -0.139079 0.108138 0.100769 -0.0514441 -0.061891 -0.0335699 0.078663 -0.0342434 -0.0322647 -0.218112 0.133516 -0.053587 0.327015 -0.200594 0.23237 -0.331232 0.175309 -0.44634 0.403636 -0.874447 1.84189)) (24.4789 0.00660193 0.0164225 #(-0.0129511 0.000294328 -0.0197443 0.0228973 0.0144379 0.0576108 -0.00978518 -0.00793303 -0.0138883 -0.0222251 0.0319748 -0.0148723 -0.0204648 -0.0414119 -0.0116904 0.010987 -0.0113676 0.0117234 -0.00638076 0.0237907 0.020048 0.00399678 -0.00498899 -0.00973827 -0.00584135 0.0192609 -0.0220209 0.0192987 0.0427776 -0.0141488 0.0260689 0.053246 -0.0359298 -0.0407085 -0.0153808 0.000894089 -0.0255827 -0.0505249 -0.0252819 0.0272812 0.0597201 0.0367404 0.00457889 -0.0014007 -0.0717525 -0.0699291 -0.107446 -0.0187547 -0.27242 1.49509)) (26.2758 0.0176864 0.0259442 #(0.0033549 -0.00945348 0.0065972 0.011377 0.00754275 0.0138938 0.00853247 0.000314037 -0.00732074 -0.0137922 -0.008441 -0.0188535 -0.0266481 -0.0205979 0.00421144 0.0117094 0.0169971 -0.0179554 -0.00098244 0.035148 0.00857569 -0.0052743 -0.000887931 0.00311146 -0.00552477 0.00948484 -0.000848823 0.0254957 0.0295882 -0.0096005 0.019213 0.00984905 -0.0239854 -0.0251062 -0.0378088 -0.00656597 -0.0252241 -0.0322219 0.024789 0.0259035 0.0228412 0.0272441 -0.00713364 -0.0104557 -0.0465321 -0.0714479 -0.0841954 -0.0538046 -0.134946 1.37684)) (33.8769 0.00801222 0.0153789 #(-0.00258214 -0.00821759 0.0196898 -0.000392261 0.0140521 0.00440578 -0.0286329 0.000567736 0.0125327 0.00426797 -0.0066993 0.0334311 -0.0281124 -0.0422645 -0.0221943 0.0377913 -0.00618192 -0.0265775 -0.00448782 0.027992 0.0456436 0.00158737 -0.0145791 -0.00474223 -0.0115839 0.0136965 -0.0283794 0.032301 0.000935378 -0.0386639 0.0497046 0.0790239 -0.0338661 -0.0499984 -0.00571791 0.0381896 -0.0512542 -0.0879677 -0.0317509 0.0295627 0.0690141 0.0544617 0.0545729 0.0472211 -0.0781932 -0.090823 -0.112884 -0.113677 -0.42381 1.68183)) (47.5854 0.03461 0.0269689 #(0.00703504 0.0042176 -0.007448 0.00601103 0.00320568 0.00838487 0.0062723 -0.0120179 0.000336154 0.000458805 -0.00549983 -0.000896449 -0.0239517 -0.0277963 -0.00199031 0.00441657 0.0118858 -0.00555538 0.0186382 0.000599233 0.0253149 0.00947596 -0.0151058 -0.0109278 -0.00257833 0.0161187 -0.000843106 0.0151509 0.00682266 0.00837561 0.0212141 0.019091 -0.0166389 -0.0383569 -0.0276626 -0.0067535 -0.0278646 -0.0358582 -0.00485826 0.02398 0.0407189 0.0544763 0.0300379 -0.00650959 -0.0404744 -0.0715788 -0.100036 -0.13855 -0.218292 1.50233)) (67.1502 0.0503262 0.0273762 #(0.00163764 0.00156368 0.000896518 -0.00356924 0.0146311 0.0115155 0.000718131 -0.010003 -0.00103783 0.00202199 -0.00199034 -0.0161105 -0.0194743 -0.0104963 -0.00591896 0.0121449 0.00486055 -0.00401805 0.00316407 0.00376875 0.0156482 0.00483055 -0.00410957 -0.00432992 -0.00485066 0.0143753 0.00558336 0.0130507 0.00596937 0.00550279 0.0213288 0.00884339 -0.00423094 -0.0320471 -0.0225288 -0.0132194 -0.0288979 -0.0323811 -0.0196434 0.0287962 0.0448142 0.0421381 0.0389864 -0.00463365 -0.0331114 -0.0584344 -0.112601 -0.149007 -0.247096 1.5331)) (87.0259 0.146162 0.040982 #(0.0066813 0.0031666 0.00524609 -0.0082533 -0.00391559 0.0131647 0.0226346 0.00201689 -0.0300066 -0.0164448 0.00249676 0.012122 -0.0120514 -0.0290936 -0.00477291 0.0062677 0.00679358 0.00355967 0.0074764 0.00641204 0.00203213 -0.000103927 0.00208319 0.00592471 -0.00531212 -0.00286345 0.0194362 0.0235452 0.0145299 0.000873052 0.0170015 0.00926635 -0.0249864 -0.0345525 -0.026674 -0.0209155 -0.0204941 -0.0180144 -0.000742368 0.0206704 0.0347392 0.0281013 0.0231078 0.00568184 -0.0455544 -0.0687793 -0.0774324 -0.112311 -0.16092 1.413)) (103.805 0.0839127 0.0284317 #(0.0305305 -0.0232935 -0.0123279 -0.00539001 0.00241112 0.0181144 0.0198195 -0.0119952 -0.00946969 -0.00768942 0.0176179 0.0159392 -0.0270933 -0.0533804 -0.0238979 0.042285 0.0419821 -0.0130642 -0.02037 0.00470052 0.0265474 0.00800111 -0.0193407 -0.00539329 -0.00768145 -0.00352887 0.00818424 0.0306883 0.00191179 -0.011258 0.0201576 0.0424102 0.000582659 -0.0480861 -0.0335357 0.00238416 -0.000149278 -0.0762318 -0.0235003 0.0537691 0.0525345 0.0284459 0.0125174 0.044311 -0.0359816 -0.0879433 -0.0942918 -0.141744 -0.328099 1.59425)) (124.841 0.162496 0.036078 #(0.0154669 -9.72884e-006 -0.0101342 -0.00793859 0.0059567 0.0228617 0.00768918 -0.0107367 -0.0153092 -0.00690622 0.00137529 0.00756771 -0.0173113 -0.0348903 -0.015329 0.0277865 0.0313134 0.00105124 -0.0143057 -0.00667794 0.011448 0.00558312 -0.00253005 0.000195594 -0.00582771 0.00497205 0.0183721 0.0241788 0.0151434 -0.0120356 0.00834879 0.019273 -0.0189529 -0.0436641 -0.017064 0.0110478 -0.0142619 -0.0454921 -0.0275606 0.0195142 0.0430997 0.0479311 0.0369613 0.00241956 -0.049964 -0.0670036 -0.063226 -0.132439 -0.269048 1.51163)) (180.716 0.293325 0.040288 #(0.0258335 -0.0119538 -0.0193954 -0.00626257 0.0234294 0.0231874 0.0109882 -0.0140674 -0.0204807 -0.0175573 0.000633931 0.000397377 -0.011624 -0.022438 -0.0107618 0.0178291 0.0325036 0.0112156 -0.0171066 -0.00548084 0.00984786 -0.00170732 -0.00485124 -0.00691943 -0.00247698 0.0118085 0.0178137 0.0244233 0.0229053 0.003698 -0.0103266 -0.00441229 -0.00122563 -0.0243714 -0.0381239 -0.0309188 -0.0100181 -0.00337076 -0.00420997 0.0204227 0.0439681 0.0382338 0.00823855 -0.0138448 -0.0326542 -0.0661078 -0.097244 -0.115524 -0.154429 1.42031)) (234.118 0.205985 0.029662 #(0.0192157 -0.0031935 -0.00784433 -0.00677489 0.00286156 0.0114244 0.0199407 0.00873447 -0.0210833 -0.0382217 0.00335562 0.018978 -0.0148748 -0.0242473 -0.0051396 0.0205883 0.00181457 -0.0139292 0.0109887 0.0201683 0.00322887 -0.00941825 -0.00196576 0.0112985 -0.0102269 -0.0019795 0.0216591 0.0239712 0.00292886 -0.0126777 0.0229174 0.0228922 -0.0279371 -0.0544655 -0.0105665 0.0201515 -0.0232041 -0.0500812 -0.0122807 0.0286273 0.0377097 0.0333467 0.0362003 0.00682096 -0.0421918 -0.0623608 -0.0697533 -0.142768 -0.286476 1.53382)) (240.477 0.393671 0.0404604 #(0.0141351 -0.00376777 -0.0127499 0.00507208 0.0136482 0.0136646 0.00963351 -0.00969488 -0.0204225 -0.0195809 -0.00608936 0.0113476 -0.00348937 -0.0263493 -0.00860379 0.0196824 0.0270435 0.00279308 -0.0216122 -0.00311376 0.0167268 0.0026715 -0.00951989 -0.00655211 -0.000521916 0.00286717 0.0195184 0.0369098 0.0212964 -0.00938696 -0.00852238 0.0157752 -0.010538 -0.0511757 -0.0367333 -0.00701777 -0.00496757 -0.0218476 -0.00180121 0.0358277 0.0423497 0.0250602 0.0161893 -0.00886896 -0.0517459 -0.0757613 -0.0763744 -0.0986088 -0.163602 1.41088)) (208.983 0.298555 0.0377969 #(0.0164121 0.0048719 -0.0123277 -0.0082839 0.00553303 0.0215874 0.00343585 -0.0106931 -0.0143605 -0.0149133 -0.000867135 0.00882374 -0.00160873 -0.0229544 -0.0199348 0.0112933 0.0268215 0.00930974 -0.0129465 0.00684308 0.00823984 -0.00100629 -0.00874536 -0.0125536 0.0018266 0.00222032 0.0179517 0.0318532 0.0216125 -0.00395573 0.00757547 0.000995567 -0.0228842 -0.0368795 -0.018438 -0.00111154 -0.0249076 -0.0299492 0.000929623 0.034715 0.0335621 0.0270658 0.0181262 -0.000710647 -0.0431774 -0.0595626 -0.0734814 -0.128686 -0.215031 1.46608)) (169.872 0.295057 0.0416766 #(0.0319486 -0.0152698 -0.0178871 -0.00121978 0.0101795 0.0113419 0.00466058 -0.0163847 -0.00962441 -0.00255257 0.0034453 0.00333557 -0.00638092 -0.0185545 -0.0171695 0.00620859 0.027439 0.00889597 -0.00634335 0.00222882 0.00733991 0.00272018 -0.00324214 -0.00743471 -0.0202102 -0.0144455 0.0143375 0.0353734 0.03177 0.0180433 0.00470567 0.00350029 -0.0211588 -0.0400762 -0.0312031 -0.00502416 -0.0137467 -0.0287056 -0.00591527 0.0317417 0.0557392 0.030424 0.00295205 -0.00796262 -0.0331349 -0.0705161 -0.0935693 -0.117755 -0.17632 1.44112)) (198.736 0.583121 0.0541678 #(0.0239533 -0.0108176 -0.0102808 0.00564068 0.0150349 0.00994732 -0.00604523 -0.00984589 -0.0142772 -0.0121714 -0.00415331 -9.11199e-005 -0.00732939 -0.0188397 -0.00379378 0.0155464 0.0238681 0.0102193 -0.00649659 -0.0166725 -0.00159701 0.0168372 0.00555774 -0.0076568 -0.0152812 0.00621925 0.0304524 0.0302777 0.0179796 -7.1259e-005 -0.0110991 -0.0120554 -0.0207771 -0.0196221 -0.019649 -0.0276093 -0.0267218 -0.00462518 0.0217483 0.0300955 0.0254635 0.0179527 0.00908021 -0.0147737 -0.0434505 -0.0549393 -0.067622 -0.0980195 -0.11752 1.34832)) (235.893 0.196632 0.0288715 #(0.0304126 -0.0184424 -0.0165599 -0.000407823 0.00801631 0.0195737 0.0118165 -0.00905007 -0.0134561 -0.0135 -0.00394936 0.00567199 0.00352691 -0.0209869 -0.0335421 0.00501761 0.033716 0.0178405 0.00147093 -0.011718 -0.00133608 -0.00135017 0.00902945 0.00737444 -0.0033788 -0.00925621 -0.0209713 0.0180258 0.0548861 0.0175237 -0.0085279 -0.00515863 -0.0139746 -0.031351 -0.0115241 0.00705294 -0.0364894 -0.0527857 -0.0113735 0.0463322 0.0573369 0.0344311 0.019218 0.00187843 -0.0302693 -0.0656353 -0.0907326 -0.155003 -0.284321 1.55441)) (250.351 0.920652 0.0606419 #(0.0221283 -0.00175026 -0.00689412 0.000872708 0.00825388 0.00110956 -0.00632789 -0.0125022 -0.0104057 -0.00936074 -0.00616766 0.00522704 0.000860839 -0.00548061 -0.0014818 0.00943791 0.00798624 0.000154997 -0.00816161 -0.00716682 0.000403966 0.00149304 0.00596023 0.00691071 0.00706264 0.0106029 0.0144444 0.01869 0.0103569 -0.00377258 -0.00598677 -0.011182 -0.0229358 -0.0277385 -0.0171593 -0.00963866 -0.0130767 -0.00448601 0.01284 0.0232398 0.0183027 0.00684207 0.000345183 -0.017907 -0.0388241 -0.0491714 -0.0555385 -0.0671155 -0.080383 1.27961)) (265.144 0.37479 0.037597 #(0.0178487 0.0013791 -0.0116388 -0.00507206 0.0138357 0.0176418 0.0040927 -0.0179262 -0.017936 -0.00558455 0.00209339 -0.00600955 -0.011245 -0.00868085 -0.00205561 0.000295947 0.0125599 0.0156985 -0.00318278 -0.0132323 -0.000274777 0.00777626 -0.00183865 0.00266585 0.0125194 0.00603461 -0.00305746 0.0220627 0.0328774 0.00937883 -0.00296813 -0.0139498 -0.023661 -0.0265224 -0.0152562 -0.00981502 -0.0187505 -0.0249964 -0.00613381 0.0245956 0.0383716 0.0292479 -0.00259061 -0.00982094 -0.0297847 -0.0422148 -0.0701577 -0.115859 -0.177598 1.41175)) (250.53 0.735674 0.0541892 #(0.0238545 -0.00486949 -0.00173591 0.00252099 0.00404998 0.00118642 -0.00418862 -0.0123793 -0.0138166 -0.00838696 -0.00266911 -0.000717441 -0.00433613 -0.00087901 3.08753e-005 0.00695944 0.00812309 0.00161619 -0.00106495 -0.00230766 -0.00318343 -0.00717512 0.00130251 0.0107457 0.00679086 0.00860716 0.0173261 0.0173051 0.0100283 0.00988019 0.00145606 -0.0181773 -0.0255863 -0.0227028 -0.0191551 -0.0156616 -0.0149123 -0.00943028 0.00703709 0.0185155 0.0208948 0.0180594 0.00541843 -0.016114 -0.0379061 -0.0507604 -0.0578965 -0.0768728 -0.0909356 1.29924)) (197.598 0.485401 0.0495631 #(0.0248193 -0.00306678 -0.00667275 -0.0014236 0.0114491 0.0091926 -0.0023926 -0.0167224 -0.0201609 -0.00339142 -0.00311447 -0.00213343 -0.00661917 -0.00708419 0.00117074 0.0105285 0.010503 0.000885714 -0.00157855 -0.00449273 -0.0024985 -0.000379483 -0.0043849 0.0022342 0.0114984 0.0120889 0.0118227 0.0206663 0.0203387 0.01268 -0.00367646 -0.0148372 -0.0196786 -0.0256279 -0.0246386 -0.0201119 -0.0148319 -0.00916508 -0.00126804 0.0198383 0.0319355 0.0159117 0.00101828 -0.0089909 -0.0292361 -0.0476222 -0.0687146 -0.089934 -0.113823 1.33378)) (125.124 0.316632 0.0503045 #(0.0130568 -0.00225892 0.00216152 0.0102169 0.00996052 -0.00255912 -0.0097279 -0.0196243 -0.00656228 -0.000937932 -6.12063e-005 -0.000608431 -0.00526008 -0.00223335 0.00268855 0.00317693 0.00183598 0.00660908 0.00583385 -0.00116981 -0.00278075 -0.00730575 -0.0127456 -0.00600758 0.00295042 0.00742113 0.0148913 0.0264792 0.0296855 0.00264396 -0.00385496 -0.00327753 -0.023196 -0.0218689 -0.015055 -0.00831472 -0.0139174 -0.0128882 -0.000967953 0.012294 0.0210776 0.0214656 0.0105105 -0.0134574 -0.0314187 -0.0453388 -0.0664272 -0.107779 -0.148171 1.37876)) (71.37 0.227496 0.0564585 #(-0.0142429 0.012727 0.0152038 0.013247 0.0124478 0.00703828 -0.0126102 -0.0229412 -0.0168578 -0.00561364 0.00559436 0.00298623 -0.0049227 -0.00038521 -0.00127981 0.00423441 0.000763587 0.00976382 0.0108994 0.00630644 -0.00368733 -0.0148032 -0.023322 -0.0161698 -0.000889858 0.011531 0.0186532 0.0329139 0.0305486 0.00665483 -0.0125951 -0.0144017 -0.0205354 -0.0305956 -0.0183857 -0.000585577 0.0114074 0.00891327 0.00153785 0.00446643 0.00473343 0.015059 0.0101803 -0.0146464 -0.0351526 -0.0511088 -0.0647666 -0.0850186 -0.118079 1.33668)) (40.4377 0.0852366 0.0459113 #(-0.0335089 0.029908 0.0183897 0.0176984 0.0101193 0.00829117 -0.0170098 -0.0268985 -0.022606 0.00232026 0.0189546 -0.0045041 -0.00575308 -0.0100939 0.00425405 0.00177554 0.00632439 0.0070991 0.0135077 0.0172888 -0.00309632 -0.0159993 -0.0288205 -0.0254887 -0.0108957 0.00733041 0.0214328 0.0301479 0.0306404 0.0070994 -0.0123194 -0.025963 -0.0100594 -0.00332728 -0.00658321 -0.000959254 0.00177248 0.00985076 -0.0049481 -0.00260225 0.00144116 0.00476165 0.00342908 -0.0128849 -0.0221734 -0.0326228 -0.0534822 -0.0924536 -0.143692 1.34984)) (27.3832 0.070801 0.0508484 #(-0.0140748 0.0135211 0.0169284 0.0134048 0.00664361 -0.000844623 -0.025384 -0.00976012 0.00801802 0.00636203 -0.00289115 -0.0127367 0.000562452 0.00700169 0.00416503 0.00548033 0.00503239 0.00518513 0.00212309 -0.00811506 -0.0249022 -0.0165552 -0.00808011 -0.0032732 -0.00323997 0.0128592 0.0143886 0.0210239 0.0149843 -0.0102482 -0.00523455 -0.0127067 -0.00629629 -0.0118239 -0.00186732 0.00661671 0.000807708 0.0076143 -0.00151332 -0.0141276 0.000588052 0.013716 -0.00222398 -0.0188076 -0.0188453 -0.0187286 -0.0391334 -0.0564238 -0.0793644 1.23514)) (30.7375 0.040934 0.0364929 #(-0.0243691 0.00812592 0.015261 0.01097 0.0205355 0.0101767 -0.0151796 -0.0251579 0.00184063 0.0088331 0.00252205 0.000583772 -0.00157531 -0.000798763 0.00905121 0.00117476 0.00355867 -0.00185548 0.00468458 -0.00729399 -0.0289016 -0.0190386 0.00930854 -0.00472978 -0.0131431 -0.00543118 0.00841419 0.0272355 0.0256443 -0.00636553 -0.00757628 -0.00558504 -0.000516058 -0.00121443 -0.0138289 0.00110727 0.00668947 0.00434654 -0.00919808 -0.0198922 0.00235468 0.0144602 -0.000975259 -0.0245124 -0.0246625 -0.015985 -0.0371288 -0.0397989 -0.0669062 1.22136)) (42.0859 0.00626129 0.0121973 #(-0.0734655 0.0296172 0.013634 0.0452539 0.00702914 0.057469 -0.0232954 -0.0727147 -0.0229838 0.0545064 0.022556 -0.0378221 -0.0116609 -0.0131154 0.0381253 0.0259823 -0.0219215 -0.0248628 0.0469329 -0.00591986 0.0161304 -0.0248895 -0.0474258 -0.0134104 -0.011063 0.0414246 -0.0607445 0.0508991 0.0641952 0.00526139 -0.0600509 0.00150282 0.00627574 -0.070137 0.0242186 0.0169948 0.0408282 0.0438345 -0.0204922 -0.0610643 -0.0804496 0.0966152 0.0588874 -0.0136561 -0.0697122 0.00834575 -0.047428 -0.0855743 -0.478215 1.63444)) (48.3822 0.0133138 0.0165886 #(-0.0991241 0.0620696 0.0256428 0.0325504 0.030601 0.0200286 -0.0346818 -0.0543453 -0.000353481 0.0292389 0.0225596 -0.0231814 -0.0230041 -0.00406665 0.0324386 0.00882869 -0.0235801 0.0419879 0.00354304 -0.0088214 0.00179125 -0.0386059 -0.020162 -0.0161291 -0.0274193 0.0200131 0.00125343 0.0450822 0.0571638 -0.0335057 -0.0273933 -0.0201817 -0.0220575 -0.0085605 -0.000251926 0.0202286 0.0402841 0.0305421 -0.0148375 -0.0251732 -0.04472 0.0420287 0.0255921 -0.0131808 -0.0380019 -0.0228509 -0.0479855 -0.104387 -0.277699 1.47947)) (52.3586 0.0659523 0.0354912 #(-0.0350294 0.0226496 0.0266707 0.0151374 0.00559978 -0.00178336 -0.0131273 -0.00792491 0.00702189 0.00803718 0.000224972 -0.0104286 -0.0107735 0.000890825 0.000619345 0.00514007 -0.000477151 0.00445113 0.0122391 0.00292333 -0.0091859 -0.0264601 -0.0178257 -0.00867586 0.00144957 0.00389939 -0.00103973 0.00526759 0.0114127 0.00266532 -0.0114983 -0.0129203 -0.0101913 0.00682779 0.023871 0.0120872 0.00875099 0.0033859 -0.00336156 -0.00727741 -0.00798061 0.00279848 -0.00798744 -0.0160221 -0.02748 -0.0249909 -0.0413176 -0.0503363 -0.0665837 1.23408)) (57.2864 0.0998289 0.0417448 #(-0.0107891 0.0182459 0.0133387 0.00654529 0.00351746 -0.0028236 -0.00652551 -0.00276973 0.00189705 0.00363537 -0.00543967 -0.00428984 -4.74181e-005 0.00728144 -0.000418819 -0.00318095 0.00296512 0.00149376 0.00209253 -0.0105876 -0.0105755 -0.00732988 -0.0124828 -0.00540931 -0.00364074 0.00253872 -0.000591894 0.0020125 0.00672111 -0.0103777 -0.00817489 -0.00341224 0.00892754 0.00393065 0.00183264 0.0170761 0.0103609 0.0093558 -0.00221637 -0.00689539 -0.00883095 -0.00260063 -0.00561736 -0.0152408 -0.0198652 -0.0251051 -0.0359384 -0.043327 -0.0516084 1.19939)) (63.2886 0.0659521 0.0322813 #(-0.0395131 0.0278336 0.0226114 0.0208169 0.00156559 -0.00586198 -0.00373168 -0.0129797 -0.000442788 0.00591266 0.00384389 -0.00649693 -0.000432298 0.00820201 0.00205019 -0.00693928 -0.00561469 0.00651516 0.00426545 -0.00287469 -0.0195372 -0.0148713 -0.00282639 -0.00135895 0.00476877 0.00385195 -0.00114983 0.00160519 0.0150339 -0.00888809 -0.0157333 -0.00871617 -0.00192295 0.00638566 0.00653376 0.0147419 0.00964909 0.00830972 -0.00471322 -0.00721979 -0.00854983 -0.00297041 0.000582071 -0.00321452 -0.0251575 -0.0448269 -0.0465566 -0.0617166 -0.0814745 1.26877)) (68.2143 0.127344 0.0432067 #(-0.00650372 0.0166661 0.0110006 0.0046084 -0.000191608 -0.000655383 -0.0075612 -0.00289214 0.00188358 0.00579054 0.000329202 -0.00681358 -0.00225101 -0.000353251 0.0031628 -0.0053415 -0.000525401 0.00656196 0.00272409 0.00256422 -0.0160209 -0.0140322 -0.00207772 -0.00301927 -0.000189949 -0.00236457 0.00311191 0.00706533 -0.000524762 -0.00984277 -0.0108244 -0.00768298 0.000888997 0.00214318 0.0071796 0.0118653 0.0159322 0.00963205 -0.00200409 -0.0107815 -0.00688397 0.000662548 0.00124322 -0.0216095 -0.024252 -0.0275861 -0.0290191 -0.0455658 -0.0594961 1.20854)) (74.5766 0.00960274 0.0113474 #(-0.0930925 0.0474147 0.0783675 0.00847634 -0.0083235 0.0389507 -0.0156469 -0.0811489 -0.00383005 0.0271399 0.0027488 -0.0036905 -0.0380551 0.0424861 0.036423 -0.0258928 -0.0261861 0.00709007 0.0423739 0.0478494 -0.0457433 -0.0682701 -0.0230027 0.0330979 0.0021217 -0.00664132 -0.0268997 0.0548632 0.100473 -0.0711387 -0.0110561 -0.0158289 -0.0476065 -0.0351137 0.00284219 0.0323319 0.0313311 0.0736398 0.0142766 -0.10177 -0.0582263 0.0770375 0.0914699 0.0357695 -0.12508 -0.0345359 -0.0237482 -0.0585581 -0.687455 1.80702)) (89.851 0.0668036 0.0272671 #(-0.047951 0.0391961 0.0312392 0.0264315 0.0152606 -0.0229461 -0.0203805 -0.0182092 -0.00178092 0.00435629 -0.00460121 -0.00718773 -0.00219992 0.00637422 0.00988643 0.00875952 0.00355863 0.0092556 -0.00376029 -0.00369781 -0.0084366 -0.0248106 -0.00997018 -0.00992863 -0.00298569 0.00552284 0.0193635 0.0324098 0.00560115 -0.0147652 -0.0174123 -0.0176175 -0.017063 -0.00976483 0.00645685 0.0115746 0.0243375 0.0212918 0.0038104 -0.00756 0.00845826 0.00991446 0.00809276 -0.000765567 -0.0407473 -0.0481121 -0.0785197 -0.118162 -0.175228 1.42139)) (111.491 0.0612596 0.0234406 #(-0.071768 0.0568083 0.0427606 0.0216603 -0.00175519 0.00236969 -0.0168044 -0.027955 -0.00413897 0.00759891 0.00307185 -0.0137154 -0.021489 0.00188837 0.0194342 0.0167963 0.0109949 -0.00132022 0.0129203 0.00409717 -0.016515 -0.035451 -0.0211164 -0.0147696 -0.00623048 0.017651 0.0231703 0.0352329 0.0277801 -0.0201851 -0.0270755 -0.0333369 -0.0135395 -0.0048966 -0.00213377 0.01776 0.0243864 0.0268 0.00479255 -0.0136091 0.00196506 0.0109521 0.0263541 0.00149658 -0.0351393 -0.0414662 -0.0804536 -0.15343 -0.262886 1.52039)) (131.563 0.0385887 0.0171263 #(-0.0518673 0.0134846 0.0263128 0.0468026 0.024454 0.0220736 -0.0400596 -0.0676488 -0.0114445 0.0413724 0.0448596 -0.0289181 -0.0607654 0.00419211 0.039212 0.0198165 -0.0106986 -0.00978497 0.0268256 0.0153281 -0.014289 -0.0258232 -0.021492 0.00140582 -0.0194537 -0.0176859 0.00346931 0.0616223 0.0476843 0.000242224 -0.0396149 -0.0480542 -0.0287999 0.00734256 0.00921102 0.0219239 0.0281868 0.0214498 0.0045841 -0.0526773 -0.0290021 0.0477786 0.066508 -0.00482082 -0.060896 0.00723903 0.00689539 -0.17291 -0.656903 1.81153)) (151.886 0.102626 0.0259939 #(-0.070856 0.0486957 0.0480601 0.0368429 0.0182886 -0.00829156 -0.0513057 -0.0475156 -0.00697538 0.0443591 0.0264049 -0.0186967 -0.046636 -0.00991082 0.0358113 0.0296259 -0.00965236 -0.00183771 0.0116684 0.0166791 -0.0164862 -0.0397139 -0.0181811 -0.0084272 -0.01239 -0.000257272 0.0267701 0.0470878 0.0342028 -0.0154802 -0.0370322 -0.0415501 -0.0235126 1.97047e-005 0.0225005 0.0265028 0.0239742 0.0125777 -0.00895148 -0.0232263 -0.000947537 0.0428729 0.0258008 -0.0298816 -0.037036 -0.00471161 -0.0249833 -0.174155 -0.397768 1.60503)) (165.11 0.169794 0.0320682 #(-0.0409658 0.0441689 0.0293712 0.0214998 0.0154116 -0.00248447 -0.0422952 -0.0478381 -0.00388453 0.0270632 0.0266513 -0.00557179 -0.022944 -0.0116277 0.0116475 0.0182246 0.00737678 -0.00598205 -0.00128794 0.00345216 -0.00394256 -0.00695017 -0.0256291 -0.0322332 -0.012631 0.0176517 0.0309905 0.0230604 0.0224319 -0.0106256 -0.0268479 -0.0207674 -0.00587152 -0.00570336 -0.00197812 0.0122906 0.0205968 0.031643 0.00252642 -0.0332331 -0.00542228 0.0405915 0.0309338 -0.0143715 -0.0384462 -0.0185082 -0.0347614 -0.166035 -0.349634 1.55773)) (177.174 0.178624 0.0317519 #(-0.0375195 0.0292643 0.0300942 0.0307154 0.0193178 -0.00509529 -0.0345436 -0.0373165 -0.0172528 0.0236766 0.0201161 -0.0183973 -0.0276741 0.00996924 0.0330329 0.0152227 -0.00951397 -0.0122329 -0.00113485 0.0194899 -0.0119267 -0.0292984 -0.015638 -0.0142287 -0.0148578 -0.000859865 0.0260062 0.0534978 0.0402742 -0.0219816 -0.040437 -0.0341774 -0.0049463 -0.0116811 -0.0123897 0.0190348 0.0504628 0.0449273 -0.00894907 -0.0495895 -0.0187866 0.0407222 0.046073 -0.00801632 -0.0446076 -0.0182126 -0.03077 -0.167466 -0.369669 1.57394)) (179.99 0.221245 0.03506 #(-0.037004 0.0260371 0.0372679 0.0497295 0.0157299 -0.0244911 -0.0537488 -0.0510671 0.00512908 0.05199 0.0203676 -0.0338469 -0.0238147 0.0127183 0.0230843 0.00442021 -0.0115414 0.00421587 0.0188467 -0.00272606 -0.0256457 -0.0344065 -0.0104499 -0.00267908 -0.00204974 0.00352165 0.02398 0.0343543 0.0255179 -0.0152773 -0.0303301 -0.0266642 -0.0139434 -0.00355751 -0.0084824 0.0107571 0.0423518 0.0526576 -0.00233367 -0.0445417 -0.0249914 0.0319504 0.0506834 -0.0160456 -0.0561795 -0.0084321 -0.00738221 -0.153557 -0.379863 1.55632)) (166.887 0.252327 0.038884 #(-0.0419053 0.0366535 0.0498127 0.0359369 0.00208074 -0.0250268 -0.0524974 -0.0402762 0.00682585 0.0354895 0.0297739 -0.0147708 -0.0304251 -0.00374599 0.0183841 0.0130221 0.00121661 0.00411938 0.00494517 0.000507366 -0.0263356 -0.0463632 -0.0168647 0.0149596 0.0144969 0.00307392 0.0082568 0.0288554 0.0295293 -0.00737698 -0.0363064 -0.0244228 -0.0110509 -0.00137184 -0.01354 0.00159516 0.0392046 0.0550105 0.0155153 -0.0394186 -0.0271276 0.0202588 0.0342747 -0.0055672 -0.0407041 -0.0119139 -0.0198007 -0.157004 -0.344951 1.53129)) (164.943 0.182476 0.0332611 #(-0.0614847 0.034366 0.0618075 0.0440773 0.010115 -0.0176925 -0.0502932 -0.0698586 -0.0117179 0.0583499 0.0553452 -0.0141319 -0.052825 -0.00920142 0.0291995 0.0159293 -0.00586749 -0.00306322 0.0226316 0.00427445 -0.0340741 -0.0437776 -0.0123615 0.00698813 0.00470649 0.00949797 0.00789906 0.0335011 0.0219034 -0.00266724 -0.0265675 -0.030155 -0.0143053 -0.0093868 -0.00158663 0.0163901 0.0203923 0.0417646 0.0187303 -0.0392964 -0.037276 0.0437944 0.0678762 -0.016769 -0.0789091 -0.0197703 0.0398731 -0.156601 -0.511722 1.65878)) (176.99 0.261053 0.0384053 #(-0.06 0.056536 0.045999 0.0280942 0.0117416 -0.0124533 -0.0449422 -0.0463361 -0.00718186 0.0308653 0.0198448 -0.0192072 -0.0242862 0.0065568 0.031481 0.0162032 -0.00801501 -0.00216827 0.0134013 -0.00587761 -0.0383848 -0.0362193 -0.0129257 0.0157857 0.00474063 -0.00184301 0.0202611 0.041013 0.0198278 -0.0191734 -0.029208 -0.0221024 -0.0116136 -0.0121702 -0.00611537 0.0173498 0.0404119 0.0315245 -0.00593292 -0.0237962 -0.000431722 0.0439062 0.0334822 -0.0297822 -0.0607389 -0.0164012 -0.00830834 -0.154607 -0.362478 1.54998)) (176.048 0.159462 0.0300963 #(-0.0377232 0.0103334 0.036835 0.0488153 0.0179723 -0.00819109 -0.0460628 -0.0619188 -0.00111458 0.0446256 0.032363 -0.00836746 -0.0360712 -0.00850298 0.0216202 0.0175984 -0.000914048 -0.0173185 0.00126597 0.0264074 -0.00629105 -0.043736 -0.017196 0.00494882 -0.000320422 -0.012511 0.00430157 0.0466093 0.0305521 -0.0031329 -0.0376142 -0.024873 0.00750779 -0.012678 -0.0104912 0.00134055 0.0376222 0.0412994 -0.0218273 -0.0452171 -0.0128663 0.072725 0.0680508 -0.0173601 -0.0684261 -0.0212582 0.0188153 -0.175166 -0.561992 1.72452)) (171.946 0.2352 0.0369847 #(-0.0512015 0.0329072 0.0503361 0.0280294 0.00184622 -0.0107644 -0.0348259 -0.0337681 0.00209173 0.0265416 0.028044 -0.0189349 -0.0371111 -0.000802031 0.0279831 0.0122725 -0.00874739 -0.00112342 0.0180879 0.000223799 -0.0259366 -0.0351892 -0.00449204 0.00197593 -0.0162875 -0.011366 0.0181628 0.0541492 0.0395807 -0.0167336 -0.0418708 -0.0160073 -0.00774302 -0.00128406 -0.00712924 -0.00703709 0.0178146 0.0397532 0.00726889 -0.0174794 -0.00498909 0.0427668 0.0408804 -0.0175914 -0.0525046 -0.0244365 -0.014682 -0.171468 -0.395718 1.59284)) (185.859 0.163683 0.0296764 #(-0.0468658 0.0116617 0.0555765 0.036102 0.0116869 -0.0136073 -0.0419413 -0.0311445 -0.015847 0.0536179 0.0374088 -0.0318291 -0.0562696 -0.0204646 0.0520056 0.0366832 -0.00267281 -0.0268453 0.00390152 0.0151844 -0.0141306 -0.026449 -0.00214409 -0.00146158 -0.0202671 -0.0306729 0.00986482 0.0542944 0.0595679 0.00293662 -0.0374089 -0.0316308 -0.0279362 -0.00383883 -0.00461755 -0.00381387 0.0302674 0.0462364 0.00234255 -0.0420869 -0.0176493 0.0621579 0.0781717 -0.0259631 -0.0837177 -0.0197173 0.0222038 -0.172749 -0.543442 1.71216)) (211.324 0.258974 0.0350069 #(-0.0303184 0.0212199 0.0351346 0.0323836 0.0108293 -0.0194528 -0.0440712 -0.0258231 0.0179244 0.0423101 0.00743043 -0.040367 -0.0363898 0.0067014 0.0337238 0.0109171 -0.0145224 -0.00777405 0.0187512 0.010748 -0.0157507 -0.020169 -0.00503133 -0.00636303 -0.0319918 -0.0279937 0.0172805 0.0607111 0.0519986 -0.00764891 -0.0419867 -0.0321224 0.0100713 0.00236086 -0.0196657 -0.0170583 0.0223451 0.0362193 0.000122523 -0.0184589 0.0140273 0.0644042 0.0497302 -0.0380606 -0.0744375 -0.0264989 -0.0209174 -0.164711 -0.384479 1.59087)) (230.546 0.254813 0.0332454 #(-0.0214216 0.00872379 0.0339929 0.0315809 0.0174031 -0.0232373 -0.0489485 -0.0241287 0.0209643 0.0453702 0.0190406 -0.0440306 -0.0441669 -0.00157853 0.0268724 0.0234296 -0.000401617 -0.0057701 0.000344993 -0.0054568 -0.0178071 0.0024068 0.0155485 0.000746876 -0.0375718 -0.0484998 0.00853225 0.0571187 0.0551759 -0.0142224 -0.0451274 -0.0277836 0.0263546 0.0402985 -0.0197452 -0.0401687 -0.00351748 0.0313089 0.00705256 -0.0369839 -0.00653953 0.0851077 0.0978434 -0.0156217 -0.102129 -0.0527658 0.00792703 -0.158984 -0.494505 1.67382)) (251.512 0.22152 0.0296775 #(0.00271906 -0.0125085 0.0301646 0.0306547 0.00855251 -0.0179234 -0.0350287 -0.0305762 0.00779454 0.053486 0.0394365 -0.0393962 -0.0650717 -0.0198502 0.0326874 0.039916 -0.0010092 -0.0179188 0.00205602 -0.00398159 -0.00877683 0.0106262 0.0187416 -0.0120917 -0.0564597 -0.0545574 0.0119312 0.0765 0.0649359 -0.0149672 -0.0521681 -0.0268912 0.0228738 0.0277597 -0.00505434 -0.0391086 -0.000955081 0.0337932 -0.00277864 -0.0493297 -0.0119853 0.100552 0.124828 -0.0159932 -0.127861 -0.0612138 0.0295559 -0.144989 -0.555044 1.70991)) (254.186 0.155867 0.0247629 #(0.011018 -0.035849 0.0315776 0.0392745 0.01848 -0.0184897 -0.0290829 -0.049739 -0.000114797 0.0517803 0.04403 -0.0251357 -0.0530782 -0.0079027 0.0214459 0.0319004 -0.0185972 -0.0210457 -0.00556451 0.0118538 0.000887009 0.0257463 0.0265477 -0.0284303 -0.0724463 -0.0721507 0.0469847 0.0785231 0.069301 -0.026447 -0.064972 -0.032767 0.00653783 0.0563972 0.0303594 -0.0350536 -0.0475477 0.0379776 0.00958391 -0.0490296 -0.0492565 0.0859668 0.161288 -0.000991608 -0.140484 -0.0439296 0.0763862 -0.147115 -0.750695 1.84834)) (225.37 0.0803291 0.0188794 #(0.0290101 -0.0687017 0.0407707 0.0383633 -0.0152389 0.00254714 0.0114647 -0.0328925 -0.021924 0.00257726 0.0623568 -0.00416147 -0.0660898 -0.0300196 0.0572706 0.0552422 -0.027837 -0.0653128 0.00149151 0.0264922 -0.00315019 0.0193053 0.0486365 0.00427569 -0.0987687 -0.0861261 0.00501995 0.0945006 0.109231 -0.0131216 -0.077788 -0.0512939 -0.00858637 0.0620822 0.041699 -0.0369608 -0.0380424 0.0273551 0.0409665 -0.0644617 -0.0854918 0.0805598 0.178136 0.0300991 -0.186435 -0.0584791 0.205418 -0.075875 -1.13303 2.07226)) (198.485 0.0417265 0.0144991 #(0.0414603 -0.0623938 0.0061811 0.0288222 -0.0158102 0.0252802 0.00307337 -0.00304176 0.00367747 -0.0489033 0.0357009 0.0204158 -0.0552591 -0.0256414 0.0346049 0.0958179 -0.0284009 -0.100873 -0.00722169 0.0205522 0.0295442 0.033256 0.0421494 0.00768483 -0.110423 -0.0846969 -0.0244979 0.0889337 0.157045 0.00102777 -0.0813333 -0.0900497 -0.0138341 0.0341514 0.0721558 0.00377355 -0.033424 0.010766 0.0245269 -0.0515001 -0.119286 0.0335791 0.213235 0.125951 -0.204453 -0.179761 0.270221 0.202002 -1.65027 2.32378)) (171.548 0.1509 0.0296587 #(0.0250778 -0.0426171 0.00843798 0.0396997 0.0226322 -0.0146932 -0.0283293 -0.01936 0.0069322 0.0354412 0.0250028 -0.0357834 -0.0414478 -0.0136723 0.0292158 0.020287 -0.00117164 -0.00726955 -0.00706735 0.000159039 -0.00407658 0.0190887 0.0257392 -0.0278326 -0.0682253 -0.0552612 0.0202806 0.0931883 0.0784599 -0.037487 -0.082894 -0.0424946 0.0518775 0.0627942 0.000169138 -0.0458972 -0.0190695 0.0107115 -0.00659794 -0.0314802 0.00511231 0.0991288 0.0788463 -0.0108271 -0.0699992 -0.0146887 -0.00873203 -0.228192 -0.553044 1.75651)) (138.651 0.0571929 0.02031 #(0.0213914 -0.0306978 0.00848927 0.0130779 0.00721775 0.00427365 0.00961346 -0.0314829 -0.018867 0.036295 0.03503 -0.0305203 -0.0463152 -0.0107846 0.0382213 0.0409777 -0.0373991 -0.0384969 0.0128019 0.00295524 0.0157249 0.0419502 0.0294107 -0.0318793 -0.11091 -0.0681277 0.0179675 0.131618 0.114326 -0.0427296 -0.109902 -0.0736138 0.0191553 0.091943 0.0543933 -0.0340794 -0.0436619 0.00746334 -0.0066161 -0.0679531 -0.0238454 0.0924077 0.161235 0.0122723 -0.139703 -0.0326624 0.115233 -0.166794 -0.931623 1.99133)) (113.308 0.193753 0.0413518 #(-0.0270571 0.018724 0.0316812 0.0297654 0.00202789 -0.0163134 -0.0290023 -0.0123064 0.0176842 0.0233915 -0.00357253 -0.0336344 -0.0271282 0.00653117 0.0284495 0.0179925 -0.004167 -0.0157728 -0.00964692 0.000267421 0.00122534 0.0146035 0.00149512 -0.0396562 -0.058053 -0.0255875 0.0451789 0.0754793 0.044493 -0.0379303 -0.0597916 -0.015322 0.0420665 0.0354546 -0.0132543 -0.0383832 -0.0285421 0.000937585 0.0195054 0.0265873 0.0502106 0.0593278 0.0136192 -0.0502636 -0.0466451 -0.0180557 -0.0524014 -0.164365 -0.318595 1.53476)) (103.037 0.0623253 0.0245944 #(-0.00724495 -0.00593484 0.0107629 0.0261896 0.0129414 0.00340164 -0.0251773 -0.0270683 0.00747135 0.0385192 0.018441 -0.0377958 -0.0304305 0.00450653 0.0229534 0.00567204 -0.0264594 -0.0176736 0.000876183 0.0471199 0.0172663 0.0124283 0.00241253 -0.0617734 -0.103682 -0.0406255 0.0578767 0.121063 0.0822661 -0.0454017 -0.102194 -0.042812 0.0321046 0.0833275 0.00602523 -0.0478943 -0.043304 0.000262387 0.00598665 -0.00374976 0.0385322 0.079333 0.0654235 -0.0354309 -0.092082 0.00159915 0.0131218 -0.204327 -0.571633 1.75234)) (92.5577 0.120027 0.0360108 #(-0.0398489 0.0324612 0.0367935 0.0220619 0.00704562 -0.0272926 -0.0200099 -0.00659618 0.0169783 0.015708 -0.00599385 -0.0153675 -0.0128987 0.0082064 0.0102226 -0.000522355 -0.00199441 -0.00674596 -0.00220103 -0.00689017 -0.00809083 0.00336812 -0.0126411 -0.0439452 -0.04063 0.00361202 0.0505336 0.0555444 0.02238 -0.0310165 -0.038806 -0.00364963 0.0180895 0.00954 -0.00503501 -0.0195219 -0.0205427 0.00318622 0.0185383 0.0345637 0.0376351 0.0372337 0.00566722 -0.0260961 -0.0314731 -0.0229805 -0.0612615 -0.148592 -0.24421 1.45165)) (66.5989 0.0842179 0.0355606 #(-0.0384904 0.0427509 0.0324356 0.0194716 -0.00585732 -0.0144022 -0.0118444 -0.00525952 0.0111836 0.00537657 -0.00948216 -0.00957872 -0.000929858 0.00996204 0.00650146 0.00151737 -0.00610687 -0.00883977 -0.0111524 -0.00821151 -0.0121669 -0.00254634 -0.0339117 -0.0355781 -0.013952 0.0280202 0.0436449 0.0292268 0.00874941 -0.0239858 -0.0194654 -0.00890681 0.0037191 -0.00475951 -0.00518569 -0.00236431 0.00776458 0.0118334 0.0107269 0.0178917 0.0261446 0.0384696 0.0138593 -0.0230752 -0.043364 -0.0319342 -0.0459236 -0.112816 -0.180369 1.35766)) (42.7254 0.0264534 0.0248827 #(-0.0413135 0.0213958 0.036281 0.0248983 -0.0151715 -0.0222269 -0.00567853 0.00505671 0.017208 0.024368 -0.0203921 -0.0162792 0.000440382 0.0151094 0.0109901 -0.000613158 -0.00984668 -0.00906093 -0.00789341 0.00260445 0.0124987 -0.0123556 -0.0457957 -0.0562666 -0.0106157 0.0486385 0.0540115 0.0360568 -0.00307563 -0.0466828 -0.0306841 0.00913136 0.0174993 0.00528422 -0.0273256 -0.0166686 0.00261137 0.0230377 0.0120899 -0.00600584 0.0223933 0.0459099 0.00977329 -0.0223494 -0.0479412 -0.0230021 -0.0404154 -0.102133 -0.204478 1.38436)) (30.9113 0.0516676 0.0408837 #(-0.014936 0.00941983 0.0118751 0.000575508 0.00581291 -0.00413739 -0.012136 0.0103523 0.00720992 0.0100773 -0.000124851 -0.00765056 0.00255218 0.000894253 0.00544408 0.000794387 -0.00215897 -0.00898489 -0.0117924 -0.00653947 -0.0064785 -0.00840759 -0.0105823 -0.0100678 0.000175767 0.0102663 0.00786819 0.0237505 -0.00215373 -0.0266525 -0.00900966 -0.00600343 -0.0028658 -0.00373159 -0.00238924 -0.00278976 -0.00429102 -0.00212087 0.00253061 0.0127614 0.0230914 0.0151189 0.00146143 -0.0117057 -0.00462498 -0.00318648 -0.0265484 -0.0369997 -0.0675645 1.14867)) (15.3693 0.00836665 0.0233319 #(-0.0341159 0.00806944 0.0216334 0.0174292 -0.0149921 0.016248 -0.0180928 -0.00306738 0.0350942 0.00513288 -0.00769301 0.00579646 -0.0107035 0.0131971 0.00589453 -0.00674269 0.00261838 -0.00786856 -0.00176616 0.00564664 -0.0345646 -0.0240044 -0.0148234 -0.0133658 -0.00412353 0.0369617 0.00196105 0.0368174 0.00564198 -0.0501549 -0.0297051 0.0178704 0.0210161 -0.0155626 -0.00837293 -0.0178571 0.00812323 0.00816448 0.00151141 0.0221456 -0.00390799 0.026406 0.0064334 -0.00797861 -0.0261832 0.013857 -0.0837799 -0.0591936 -0.120175 1.27127)) (7.76696 0.0131245 0.041107 #(-0.0123117 0.00617644 -0.00098044 0.00751582 -0.00251782 -0.00337365 -0.00106648 -0.00202962 0.024234 0.000865013 -0.000377017 0.00388929 -0.00333191 0.0133695 -0.00022004 -0.00378028 -0.00320862 -0.00759729 0.010062 -0.0256383 -0.0192849 -0.0214377 -0.0114302 -0.00124626 0.00155824 0.0193932 0.00236924 0.0225305 0.00325289 -0.026002 -0.0156565 0.0123504 0.013013 -0.00652565 -0.00493443 -0.0110295 -0.00472477 0.0120849 0.0080524 0.00918786 -0.00908903 0.0273415 -0.00444183 -0.0233399 -0.0047778 -0.00719849 -0.0426428 -0.018549 -0.0650151 1.15688)) (8.89632 0.0142545 0.0400286 #(-0.00575181 0.0168131 -0.000191827 -0.023498 -0.00423681 0.025755 -0.0183111 -0.00376236 0.0252077 0.008183 -0.0122062 -0.003721 0.00288939 0.0148372 0.00886276 0.00423061 -0.00963574 0.000873132 0.00541097 -0.0280967 -0.00998672 -0.0238806 -0.0217161 -0.00753574 0.000230236 0.0280799 -0.00512027 0.00849866 0.0322065 -0.0343016 -0.00927757 0.00120511 0.0135002 -0.00237087 -0.0093355 -0.00156968 -0.00792312 0.012794 0.00838747 -0.0119611 0.00605868 -0.00193377 0.0117903 0.00816965 -0.0157005 -0.000300004 -0.0367019 -0.0246368 -0.0709357 1.15223)) (9.78194 0.0170927 0.0418016 #(-0.0124638 0.0024989 -0.00185738 -0.00369259 -0.00329147 0.0015451 0.00184027 0.00970003 0.0141567 0.0120678 0.00775671 -0.00277263 0.00105104 0.000310846 0.00513042 -0.0141369 -0.008812 0.00521768 -0.00206552 -0.00604551 -0.0120649 -0.0176494 -0.0204137 -0.0115251 0.00627893 0.0162767 0.0108663 0.00560173 0.00467505 -0.02242 -0.0112209 0.000456198 0.00829053 2.30481e-005 0.00913467 -0.00846952 0.00517986 0.00864013 -0.00133154 0.00581594 -0.00610526 0.00869507 0.00727336 -0.00365842 -0.0143366 -0.0169279 -0.0336561 -0.0311221 -0.071088 1.16895)) (11.5445 0.0160741 0.0373143 #(-0.0249007 -0.00275895 -0.000517276 0.00756758 -0.00172192 0.0176724 0.00486407 0.00102775 0.0190812 0.027876 -0.00029893 -0.00443258 -0.00532617 -0.0133783 -0.00615458 -0.00822798 -0.00903328 0.00488343 0.0122464 -0.0119956 -0.0122127 -0.0164293 -0.0183456 -0.00082874 -0.00101657 0.00939199 0.0092591 0.0164931 -0.0114048 -0.0252425 -0.0161846 -0.00699262 0.00668263 0.0180297 0.000800448 0.00638066 0.00681553 0.0168308 0.0103385 -0.00081722 -0.00148622 0.00392006 -0.00755191 -0.0011792 -0.0241647 -0.0123012 -0.0393747 -0.0402423 -0.0754633 1.19146)) (13.3295 0.0127553 0.0309342 #(-0.0231698 0.0191559 -0.0139377 0.0092944 0.0121271 -0.000232179 -0.0124583 0.0134314 0.0164421 0.024357 -7.36386e-005 -0.0199401 -0.00337023 0.0151218 -0.00455778 -0.0115682 -0.0172743 0.000976708 0.017724 -0.0074562 -0.0285266 -0.0151716 -0.030822 0.00497904 0.00790638 0.0099445 0.0162362 0.0264739 0.0175367 -0.0501894 -0.0343044 -0.00901378 0.014952 0.0105903 -0.0101648 -0.000755211 0.0171476 0.0293293 0.00838466 -0.0102206 0.00315026 0.0306831 -0.00269206 0.00531439 -0.0326658 -0.0252288 -0.0474296 -0.0704353 -0.143764 1.28812)) (15.3429 0.0120405 0.0280135 #(-0.0309064 0.0271264 0.0147487 0.00498133 0.00106183 0.0147637 -0.040844 -0.0169095 0.0389369 0.0194572 -0.00221378 -0.0170094 -0.00138509 0.0162374 0.00582746 -0.0230331 -0.0117961 -0.00156591 0.0229133 0.027122 -0.0540262 -0.0410968 -0.013133 -0.00158327 -0.0109391 0.0261228 0.0330272 0.0405228 0.0323432 -0.0623613 -0.0561195 -0.00527043 0.00668445 0.0267738 -0.00936441 -0.0283996 0.0234758 0.0255722 0.014511 -0.0129606 0.00174176 0.0403901 0.0353441 -0.000116604 -0.0455759 -0.0479024 -0.0481118 -0.0843258 -0.209947 1.37135)) (17.6721 0.019402 0.0331344 #(-0.0350609 0.0339703 0.0145886 0.000690795 0.000922172 0.00738286 -0.01517 -0.0088783 0.0201723 0.0122574 -0.0158588 -0.0119165 -0.0019645 0.020945 -0.000870479 -0.0108681 -0.00586048 0.00538485 0.0104022 -0.00321434 -0.0157964 -0.0469299 -0.0215821 -0.00373954 0.00283885 0.0148254 0.0275313 0.0364303 0.0161417 -0.0308895 -0.0417433 -0.00377748 0.0165364 0.00397155 -0.0227846 -0.0260575 0.00618754 0.0551286 0.0147865 -0.0176932 0.00941883 0.0495573 0.031147 -0.00860301 -0.0380403 -0.0458936 -0.0610949 -0.096874 -0.18716 1.3588)) (20.0442 0.0140521 0.0264774 #(-0.0709867 0.0453836 0.0460421 0.0146813 -0.0179832 0.00433517 -0.0165851 -0.00628279 0.0245804 0.0150767 -0.0114593 -0.0368579 0.00386748 0.0248403 0.00774181 -0.0237615 -0.0110972 0.00908011 0.0143327 0.012267 0.00781146 -0.0256289 -0.0705544 -0.0244927 -0.0213969 0.0392408 0.0426976 0.0769561 0.011974 -0.0784876 -0.0580746 0.0130622 0.0449024 0.0142022 -0.0384532 -0.0269607 0.00680663 0.0207385 0.0149218 -0.0149792 0.0278171 0.0648385 0.0568704 -0.00419316 -0.0892845 -0.0271809 -0.0635848 -0.137194 -0.290703 1.49428)) (22.8017 0.0273646 0.0346427 #(-0.0720317 0.0448821 0.0348815 0.0233662 -0.000985435 0.00226309 -0.0135519 -0.0209769 0.0167468 0.0101012 -0.0194102 -0.00439263 0.00504041 0.0156837 0.00598467 -0.0264652 -0.0115608 0.0185426 -0.0068165 0.0100013 -0.00188157 -0.018496 -0.0458203 -0.0312296 -0.00116534 0.0335279 0.0330629 0.0395021 0.0183978 -0.0427994 -0.0459782 0.0054253 0.0243994 -0.00582722 -0.0111125 -0.0241409 0.0054475 0.0251814 0.00891366 -0.000905372 0.0228307 0.0523174 0.0382179 -0.00320691 -0.0354807 -0.0419394 -0.0835182 -0.139596 -0.249583 1.45587)) (26.3474 0.0219953 0.0288932 #(-0.0765435 0.0426832 0.0419785 0.0283921 0.00340572 -0.00535423 -0.0212032 -0.0116924 0.00206213 0.00816488 -0.0127589 0.00934433 0.0163962 0.00930891 -0.00568188 -0.0355663 -0.0130979 0.0042239 0.0221761 0.0294585 -0.00590132 -0.0300225 -0.0529725 -0.04428 -0.00514512 0.0547305 0.0372759 0.0478592 0.0239117 -0.0702372 -0.0687804 0.0195622 0.0191373 0.0223794 0.0135526 -0.038104 -0.00282542 0.00433172 0.00929822 -0.00582157 0.0154465 0.0665377 0.0342229 0.00927136 -0.0205276 -0.0192793 -0.0956723 -0.177253 -0.343554 1.56045)) (30.1984 0.030065 0.0315528 #(-0.0979213 0.0706986 0.0397353 0.027229 -0.00146723 -0.00438662 -0.0236935 -0.0188674 0.00900385 0.011066 0.00529251 -0.00704211 0.00609007 0.00670222 0.011048 -0.0216173 -0.0263168 0.00421382 0.0169606 0.0205924 -0.018071 -0.0136472 -0.0356033 -0.0382373 0.00240587 0.00751786 0.0412371 0.0584634 0.033329 -0.0663578 -0.0641406 -0.00811986 0.0285871 0.0444783 -0.00260303 -0.0335565 -0.018181 0.00985673 0.00558086 0.0118218 0.023386 0.0433098 0.0400329 0.0116843 -0.0148176 -0.058095 -0.0779079 -0.157939 -0.31358 1.52513)) (32.1428 0.0318259 0.0314665 #(-0.0775589 0.051683 0.0288251 0.0187194 0.00984706 0.00338128 -0.0202275 -0.00651548 0.0136416 -0.00760369 0.00215332 -0.0233182 0.0134451 0.0247162 -0.00404254 -0.0118734 -0.018538 0.0113604 0.00736548 0.00204067 -0.0115196 -0.0197442 -0.0154772 -0.0363295 -0.0150368 0.0175515 0.0394107 0.053815 0.00585165 -0.0330152 -0.054677 -0.0159929 0.0341672 0.015965 -0.00299163 -0.0189119 -0.0067154 0.0143037 -0.000256563 -0.00532035 0.0260945 0.0429435 0.0476952 0.0109455 -0.0235557 -0.0298008 -0.0826709 -0.176099 -0.325686 1.54201)) (31.4202 0.0318335 0.0318301 #(-0.0971744 0.0647286 0.0577288 0.0197214 -0.00649152 -0.0216951 -0.0189122 0.00437908 0.0284074 -0.000966733 -0.0171446 -0.0107114 0.00440035 0.0142388 0.00532634 -0.0126468 -0.02169 0.00523199 0.0297256 2.45184e-005 -0.00810739 -0.0215433 -0.0335994 -0.053856 -0.00465438 0.037238 0.0491757 0.0548962 0.014561 -0.073022 -0.0403319 -0.0130117 0.00834094 0.0434427 -0.00417276 -0.0078477 -0.0118494 0.00744896 -0.00313036 -0.0123154 0.0214602 0.059643 0.056315 0.00853147 -0.0377529 -0.0250175 -0.0860953 -0.178818 -0.327932 1.55029)) (32.4444 0.0301064 0.0304621 #(-0.0807 0.057348 0.0412646 0.0366669 -0.00996071 -0.0130091 -0.0387371 -0.00774177 0.0350818 0.0241313 -0.0154081 -0.0231186 0.00127267 0.0151109 -0.000317825 -0.0114935 -0.0136006 -0.00971232 0.0131985 0.0123626 0.0233086 -0.0265093 -0.0606854 -0.0258504 -0.0165391 0.0251411 0.0470309 0.053574 0.0180307 -0.0502542 -0.0485886 -0.0164236 0.019835 0.0329606 -0.00101179 -0.0302517 -0.0018849 0.0308459 -0.00743693 -0.0159462 0.0094627 0.0539938 0.0554317 0.0208811 -0.0307534 -0.0204858 -0.0821197 -0.181269 -0.37734 1.5857)) (40.9172 0.0650495 0.0398721 #(-0.0572582 0.0414552 0.0350494 0.0183922 0.00440463 -0.00850967 -0.00613651 -0.0179503 -0.00262387 0.0195232 -0.0131559 -0.00454892 0.00177392 0.0065445 0.00194393 -0.00781929 -0.00616173 -0.00313379 -0.000702812 -0.00178652 -0.014563 -0.0209123 -0.0269462 -0.0162782 0.00491859 0.0228838 0.0258315 0.027738 0.00459301 -0.0176909 -0.0295674 -0.0017052 0.0107792 -0.00448647 -0.00151116 -0.00392171 -0.00643332 0.00597558 0.0150378 0.0149934 0.0222908 0.0451681 0.0323751 0.00353828 -0.0263688 -0.050642 -0.0923144 -0.142247 -0.194605 1.40832)) (42.9245 0.0380718 0.0297817 #(-0.0619835 0.0538987 0.0254833 0.0191851 0.000713942 -0.00965684 -0.0114323 -0.0178469 0.0175577 0.0131995 -0.0072923 -0.00832834 -0.00811007 0.00959091 0.00557504 -0.00996733 -0.00855112 -0.00974844 0.00913783 0.0117909 -0.0045425 -0.0256592 -0.0292943 -0.0307577 -0.00238131 0.0201101 0.0259082 0.0446931 0.0181626 -0.0452096 -0.0297406 -0.0143662 0.023201 0.0203186 -0.00421108 -0.0211625 -0.00441318 0.019116 0.000645667 -0.00607597 0.0221206 0.0483723 0.0479185 0.015123 -0.02304 -0.0353189 -0.100976 -0.171954 -0.291149 1.51649)) (35.4435 0.0741689 0.0457449 #(-0.0592469 0.0408393 0.0310192 0.0213087 0.000897261 -0.0097075 -0.0127374 0.00034184 0.00697528 0.00416767 -0.00709337 -0.00543548 -0.00262597 -0.000460251 0.00462508 -0.000103108 -0.00210094 -0.000600998 -0.0064083 -0.00812498 -0.0110879 -0.014929 -0.0210607 -0.0126928 -0.00625044 0.0121755 0.0253735 0.0353037 0.00209597 -0.0177743 -0.0179092 -0.0111032 0.00635534 -0.000694276 -0.00804003 -0.00382186 0.00598897 0.00926817 0.00874331 0.0115986 0.0207321 0.0434171 0.0317387 0.00501884 -0.0295828 -0.0488442 -0.0859817 -0.140721 -0.179372 1.38875)) (31.5655 0.0508454 0.0401347 #(-0.0590031 0.0481201 0.0415922 0.0145118 -0.00625927 -0.010634 -0.022698 0.00794115 0.0129372 0.011031 -0.00684227 -0.0269145 0.000574552 0.0097944 0.00870401 -0.0154143 -0.00608816 -0.00337432 0.00658044 -0.000562268 -0.0114323 -0.0168882 -0.0267139 -0.0354475 -0.00491647 0.0324642 0.0368173 0.0353376 5.39129e-005 -0.039796 -0.021031 -0.00123375 0.0136188 -0.00348024 -0.00871654 0.00380723 0.0164729 0.0135323 -0.00439517 -0.0080045 0.0109003 0.0528155 0.0444091 0.0206946 -0.0118078 -0.0443984 -0.10415 -0.168437 -0.257971 1.47706)) (30.9527 0.0382595 0.0351577 #(-0.0677928 0.0651594 0.0430938 0.00356799 -0.0158889 0.000628987 -0.0127898 -0.00558382 0.0158968 -0.00226313 -0.00538957 -0.00778266 0.00155987 0.00443769 0.00375692 -0.0105507 -0.0224075 0.00426307 0.00792974 0.000294564 -0.000787178 -0.0161313 -0.0342735 -0.0403149 -0.00675935 0.0293195 0.0435918 0.0478281 0.00545949 -0.0534773 -0.037442 -0.0111263 0.0321929 0.020819 -0.00755799 -0.00482975 -0.00528935 0.0154923 0.00365394 -0.00549552 0.0121106 0.053678 0.0478409 0.019575 -0.0286409 -0.0335462 -0.0765612 -0.177995 -0.331 1.53233)) (31.4075 0.0364452 0.0340646 #(-0.0649986 0.0576299 0.0324902 0.00773543 -0.00458665 0.00495247 -0.0191388 0.000145591 0.000613326 0.00395394 0.000636622 -0.0207581 0.00467082 0.0155624 0.0110861 -0.0131649 -0.0232556 -0.00176555 0.00395216 0.00802351 -0.00893858 -0.021152 -0.016588 -0.0283998 -0.0138537 0.0249458 0.0287153 0.0452579 0.0204232 -0.053952 -0.0535749 0.00280977 0.0440965 0.0328232 -0.0150095 -0.0388665 -0.0096805 0.0162576 0.0154429 -0.00290426 0.029801 0.0596534 0.0460045 -0.00865289 -0.0497685 -0.0141297 -0.0805603 -0.160605 -0.335686 1.53526)) (31.6576 0.0348485 0.0331782 #(-0.0618954 0.0523533 0.0235303 0.0153525 0.00172889 -0.00168407 -0.0110182 -0.0142045 0.0170727 1.99435e-006 0.0017121 -0.0190737 -0.0111033 0.0169703 0.0280168 -0.01063 -0.0322064 0.00426402 -0.00485 0.0146215 -0.00758876 -0.0226077 -0.0252398 -0.0189545 -0.00568113 0.00980641 0.0269183 0.0392206 0.0257317 -0.0475402 -0.0534524 0.00178895 0.0586262 0.0278462 -0.0327184 -0.0414883 -0.0120922 0.029826 0.0131607 0.00598402 0.00931486 0.0642811 0.057244 -0.00679361 -0.0464739 -0.04173 -0.072625 -0.161229 -0.31275 1.52407)) (34.7383 0.0559897 0.0401467 #(-0.0415582 0.026703 0.0259679 0.0111422 0.00204608 -0.00618647 -0.00950887 0.0120808 0.0102095 -0.00150538 -0.0114168 -0.0193223 -0.00463892 0.0133971 0.0187653 -0.00583736 -0.0127744 -0.0100488 0.0111868 0.0106626 -0.0205418 -0.0312655 -0.0304695 -0.0160161 -0.00137347 0.0194299 0.0309445 0.0366569 0.00705069 -0.0166283 -0.0404884 -0.00764167 0.0169512 0.0132674 -0.00907035 -0.0275286 -0.0054365 0.0307347 0.0158178 0.00474018 0.0264909 0.0460957 0.0291759 -0.00850643 -0.0359522 -0.0586856 -0.0731063 -0.11696 -0.205816 1.40186)) (36.4119 0.0463771 0.0356887 #(-0.0389951 0.0307876 0.0205879 0.00908905 0.00555359 -0.0121034 -0.00687764 0.00752914 0.0176609 0.00566536 -0.0208413 -0.0229413 0.00156059 0.00543264 0.00694066 0.00249693 -0.00335328 0.000401892 0.0138262 0.00128668 -0.0283111 -0.0256373 -0.0237493 -0.0291584 -0.00703129 0.0152271 0.0393229 0.0452958 0.0231804 -0.0291094 -0.0417306 -0.00489797 0.0160917 0.000583816 -0.0194554 -0.0235409 0.00563181 0.0393978 0.0237208 -0.00447947 0.0171657 0.0551852 0.0282278 -0.022097 -0.0371377 -0.0598215 -0.0687185 -0.118988 -0.195594 1.40087)) (31.5195 0.0823719 0.0511211 #(-0.0506811 0.032627 0.0260271 0.0133287 0.00707792 -0.00716418 -0.00792555 -0.00164158 4.37169e-005 0.00655899 -0.00403331 -0.00510847 -0.00250636 0.00465444 0.012035 0.0010902 -0.00567664 -0.00723898 -0.00466529 -0.00771452 -0.0268553 -0.0264261 -0.00282889 0.000687852 0.00062155 0.00777579 0.0113666 0.0250398 0.020167 -0.0104087 -0.0261586 -0.0112883 -0.00423545 0.0070317 -0.000811418 -0.0200803 0.00317688 0.0237687 0.0201803 0.0121356 0.0175142 0.033371 0.0253085 -0.00456846 -0.0415392 -0.0596395 -0.0783815 -0.0936876 -0.114877 1.30627)) (25.4029 0.0602808 0.0487134 #(-0.0551556 0.0394576 0.0270103 0.0236226 0.00186073 -0.00761447 -0.00740441 -0.00712806 0.00591052 -0.00309897 -0.00157216 -0.0120145 -0.00111416 0.0139671 0.00880658 -0.0012513 0.00244409 -0.0133322 -0.00925009 0.00123142 -0.034305 -0.0168858 -0.00914378 -0.0110158 0.000306792 0.0116358 0.0236282 0.0251389 0.00218792 -0.00727665 -0.0207191 -0.00825958 0.00274023 -0.00288428 -0.00666814 -0.0172675 0.00904082 0.0154382 0.0150386 0.0254515 0.0314402 0.0294853 0.0295901 -0.00445611 -0.0469681 -0.0574121 -0.0877862 -0.106583 -0.135491 1.339)) (22.7468 0.078061 0.0585811 #(-0.04486 0.0298865 0.0293551 0.0157202 0.00558635 -0.00166327 -0.0153884 -0.00699228 0.00676223 0.00247051 -0.00958823 -0.00736895 0.00134663 0.00697311 0.0112086 -0.000206178 -0.00881016 -0.00624388 -0.00932781 -0.0197023 -0.0190608 -0.011131 -0.0120463 0.000508607 0.00205883 0.0130596 0.00678453 0.017637 0.0173591 -0.00929612 -0.0146321 -0.00917131 -0.0076256 0.0010683 -0.00392937 -0.00849227 0.006057 0.0173038 0.0170559 0.0185356 0.0307804 0.0321241 0.0197208 -0.00024348 -0.0379323 -0.0627024 -0.0771216 -0.096205 -0.116027 1.29578)) (22.8884 0.0716601 0.055954 #(-0.0482403 0.0307585 0.0275873 0.0182651 0.000529184 -0.0022478 -0.00768153 -0.00720601 0.00320312 0.000542559 -0.00613952 -0.00509576 0.000853576 0.00746592 0.00241067 0.00149092 -0.0103518 -0.00548361 0.00260866 -0.00854271 -0.0165325 -0.024049 -0.0159926 -0.0106845 0.00539235 0.0217353 0.013189 0.0138549 0.0113874 -0.00669787 -0.0144154 -0.00952096 -0.00989752 0.000984178 -0.00567269 -0.0075391 0.00597343 0.0157336 0.0231019 0.0212661 0.0260539 0.0267702 0.0234177 -0.00360673 -0.0411499 -0.0479637 -0.0797028 -0.101779 -0.123467 1.30416)) (25.0679 0.0404904 0.04019 #(-0.0569264 0.0393012 0.0442286 0.0105388 -0.0280166 0.0130403 -0.000293758 0.00097423 0.0019422 -0.0135517 -0.0129558 -0.00137247 0.0176797 0.0111486 -0.00223964 -0.00550807 -0.00602055 -0.00683842 -0.0111893 0.0040559 -0.00320025 -0.0210676 -0.0166252 -0.0273107 -0.00925243 0.0352852 0.0153395 0.028238 0.0100151 -0.0296035 -0.0250562 0.00185137 0.0255143 0.00681541 -0.0269629 -0.0225865 0.00339151 0.0176583 0.0135256 0.0128693 0.0308694 0.0396139 0.0268478 -0.00453411 -0.0321182 -0.0411832 -0.0894552 -0.13549 -0.18868 1.40068)) (26.172 0.0414675 0.0398048 #(-0.0630411 0.0445934 0.0340673 0.0179641 -0.0126086 -0.000847251 0.000227371 0.00106207 0.0131494 -0.0118745 -0.0160848 -0.00908814 0.00502605 0.0118554 0.0134411 0.006348 -0.0203072 1.60219e-005 -0.0092216 -0.0131313 0.00614179 -0.023434 -0.0225044 -0.0205765 -0.00759216 0.0190882 0.0216325 0.0341826 0.0139076 -0.0241181 -0.0163891 -0.0082327 0.0124357 -0.00390939 -0.0224453 -0.0154005 0.00127452 0.0147405 0.0170827 0.0260113 0.0421892 0.0303767 0.0235349 -0.0138023 -0.0474366 -0.0434775 -0.0753137 -0.111706 -0.172436 1.36862)) (24.9425 0.0127896 0.0226443 #(-0.0733194 0.0354206 0.0577736 0.0308347 -0.0289842 -0.00604918 -0.014531 -0.0101977 0.0240066 0.0242339 -0.0217081 -0.0255996 0.00547605 0.0210583 0.0282309 -0.0144568 -0.0284572 -0.0338683 0.0165173 0.0371958 0.00744609 0.00585112 -0.0600074 -0.0549116 0.000340121 0.0385451 -0.00124994 0.0513382 0.0555081 -0.0592178 -0.0733577 -0.0170409 0.0586459 0.0553344 -0.0225186 -0.0556362 -0.0233135 0.0506938 -0.00436045 -0.0332437 0.00902178 0.0879455 0.0599741 -0.000640262 -0.0442607 -0.0220114 -0.0610923 -0.165358 -0.458725 1.64915)) (22.7641 0.0174743 0.027706 #(-0.0584102 0.0459445 0.031618 0.0172284 -0.0102017 -0.00307119 -0.0147159 -0.0128069 0.0192186 0.0263737 -0.0162587 -0.0214138 -0.00164627 0.0164729 0.0190751 -0.00745766 -0.0243652 -0.0185078 -0.0136905 0.043886 0.0129518 -0.0298972 -0.0265289 -0.0403765 -0.00958069 0.0232809 0.0161453 0.044125 0.0361099 -0.0522329 -0.0619475 -0.000899218 0.0508566 0.0368301 -0.0180012 -0.0430501 -0.00970191 0.00226846 0.0163143 0.00440859 0.00654716 0.0745107 0.0559268 -0.0237278 -0.0297872 -0.0202482 -0.0711893 -0.150335 -0.394529 1.58051)) (19.5777 0.0125371 0.0253057 #(-0.0826795 0.0683275 0.0428367 0.02936 -0.021953 -0.0169267 -0.0348315 -0.00679442 0.025703 0.045118 -0.00592805 -0.0419876 -0.00936561 0.0199536 0.035517 -0.0131276 -0.0408877 -0.0219309 0.0500002 -0.0214081 0.0310525 -0.0126166 -0.046124 -0.0345309 -0.027267 0.0407647 0.00779675 0.0551954 0.0525408 -0.0538993 -0.0680158 -0.0475148 0.0549138 0.0610506 0.00643009 -0.0500036 -0.0294172 0.0234389 0.0124404 -0.0212963 0.0223014 0.0563873 0.0415865 0.0218463 -0.0398211 0.00419091 -0.103894 -0.150699 -0.43171 1.62141)) (18.2418 0.0253117 0.0372501 #(-0.0607523 0.0562677 0.0384613 0.00424439 -0.0162383 -0.00801906 -0.00889723 -0.00153158 0.0178735 0.00687857 -0.00841403 -0.0109761 -0.000752748 0.0188549 0.0145737 -0.0116472 -0.0244779 -0.0102738 0.00684694 -0.00289441 -0.0144796 -0.0119951 -0.0216497 -0.0176858 0.000835 0.00693356 0.0142641 0.0338318 0.0169442 -0.0304174 -0.03766 -0.00345847 0.0310024 0.00119207 -0.0121249 -0.0113758 -0.00784907 0.0241519 0.0161341 0.0165755 0.0178807 0.0323894 0.0223039 0.0113459 -0.0211709 -0.0354951 -0.0753201 -0.130449 -0.212926 1.39061)) (18.2633 0.0252861 0.0372093 #(-0.045203 0.0314978 0.0349495 0.00211169 -0.00893727 0.00352343 -0.0123056 -0.00291805 0.0126091 0.00904179 -0.00646769 -0.0145041 -0.00502528 0.0120276 0.0164997 -0.0114284 -0.0165834 -0.00612101 0.0129625 0.0025109 -0.0220033 -0.00506117 -0.0341916 -0.0253116 0.0116913 0.0206707 0.00947406 0.0215501 0.018648 -0.0253815 -0.0210033 -0.00128285 0.00803003 0.00165846 -0.00961188 -0.0112029 -0.00390969 0.018762 0.0176612 0.0141336 0.0162613 0.0423988 0.0169786 0.00664183 -0.0149723 -0.0514017 -0.0758318 -0.125953 -0.214712 1.39864)) (17.5015 0.0281862 0.0401311 #(-0.0467037 0.0285618 0.0290192 0.00889659 0.00523947 -0.0106185 -0.00584188 0.00343646 0.0078645 0.00378798 -0.0136156 -0.012084 0.00284047 0.0112584 0.00930852 -0.0112164 -0.00383024 -0.00982824 0.0153711 -0.00475254 -0.018373 -0.0203009 -0.0232701 -0.0175478 0.00286289 0.0183034 0.0126237 0.036949 0.00550275 -0.0201175 -0.0171514 0.000764537 0.00264071 -0.0167697 -0.00575089 -0.00377642 -0.00121029 0.0205625 0.019458 0.00863159 0.025104 0.0386815 0.0262647 -0.00411803 -0.0406888 -0.0471502 -0.083648 -0.103756 -0.174039 1.36212)) (17.2526 0.0295366 0.0413764 #(-0.0459645 0.0347026 0.0174516 0.0140821 0.00442935 -0.00595253 0.000786888 -0.00770935 0.00586936 0.00240675 0.00201615 -0.0114029 -0.00715992 0.0219725 0.00668619 -0.00508303 -0.0104611 -0.00929612 -0.00120529 -0.00989537 -0.0169932 -0.0133932 -0.0188951 -0.000876892 -0.000297876 0.000200907 0.0129674 0.0262989 0.00787067 -0.0241803 -0.0115058 -0.000143185 0.0150916 0.0138443 -0.0335769 -0.0206819 -0.00174932 0.0245576 0.0198266 0.017498 0.020447 0.0325335 0.0246589 0.00835593 -0.033657 -0.0520807 -0.0742558 -0.105502 -0.158577 1.3385)) (17.7939 0.0194564 0.0330671 #(-0.0393023 0.0249954 0.0281254 0.00881808 -0.0170303 -0.000254086 -0.0238422 0.0104953 0.0267727 0.0218212 -0.00832039 -0.0378733 -0.00966003 0.0208957 0.0258569 0.00523595 -0.0125616 -0.0198685 -0.00261361 0.0267587 -0.00756953 -0.0295961 -0.0220904 -0.0216108 -0.022352 0.010996 0.018242 0.0477541 0.0378138 -0.0342758 -0.0460006 -0.0110206 0.0200271 0.0216202 -0.0010694 -0.0481358 -0.00989713 0.0183853 0.0178495 0.0123016 0.00932306 0.0462944 0.0355045 0.00738312 -0.0433972 -0.0431022 -0.0752448 -0.111662 -0.22808 1.41783)) (16.2645 0.0198753 0.0349571 #(-0.0444276 0.0359794 0.0176339 0.0166024 -0.00509977 -0.00228653 -0.0161215 0.0145134 0.0174299 0.000749843 -0.00504707 -0.026946 -0.00241593 0.0172678 0.024325 -0.00596551 -0.0248575 -0.0135324 0.0111395 0.00225044 -0.0129778 -0.0134113 -0.0270257 -0.0234719 -0.000202711 0.0218519 0.00693315 0.0315688 0.0147574 -0.0374582 -0.0197909 -0.0087806 0.0357156 0.00379843 -0.0129535 -0.0288524 -0.0066429 0.02112 0.00394448 0.0222445 0.0191879 0.0458149 0.0290641 0.00188522 -0.0291704 -0.0394177 -0.0755161 -0.123621 -0.231673 1.41693)) (13.9843 0.0203448 0.0381422 #(-0.0406508 0.0247845 0.0280528 0.016247 -0.00667394 0.00575473 -0.00883099 -0.00538796 0.0124414 0.00246849 -0.0144231 -0.0122821 5.65498e-006 0.0240839 0.00861459 -0.00217033 -0.0235125 -0.0168742 0.0055966 -0.00328378 -0.00988276 -0.0124962 -0.0202922 -0.0046567 0.00286656 0.0025336 0.000137633 0.0296567 0.0200221 -0.0189908 -0.0237597 -0.000666055 0.0173422 0.0148898 -0.028545 -0.0280338 -0.00862389 0.0107104 0.0292579 0.0223673 0.0356336 0.027171 0.0365469 -0.00876548 -0.0413912 -0.0440555 -0.0862704 -0.0992445 -0.175119 1.36053)) (13.7519 0.0318418 0.0481192 #(-0.0439203 0.0286811 0.019099 0.0131209 0.00116507 0.00239283 -0.00349781 -0.00764389 0.00731754 0.00111961 -0.0119648 -0.0166307 0.0112826 0.0209392 0.00437699 0.00510248 -0.00768695 -0.0223086 -0.0103192 -0.00707175 -0.0131623 -0.0187769 0.00250121 -0.00532104 -0.0114664 0.00451569 0.0158921 0.0267952 0.00829616 -0.0112708 -0.0156018 -0.00644018 0.00364066 -0.00682353 -0.0102232 -0.0152849 -0.00104906 0.0131723 0.0312335 0.0306407 0.0224566 0.0393104 0.00734389 -0.0167909 -0.0521184 -0.0325935 -0.0547162 -0.0785076 -0.107318 1.25643)) (14.1001 0.036371 0.0507887 #(-0.0416909 0.0311513 0.0216856 0.010757 0.0023053 -0.00539498 -0.0122303 -0.00307753 0.0143497 -0.0013006 -0.00140553 -0.0114054 0.00277976 0.0180154 0.00290372 -0.000693336 -0.0231679 -0.00686742 -0.00978564 -0.00577415 -0.00821437 -0.0128852 -0.00872088 -0.0119665 0.00729519 0.00605096 0.00574081 0.0229577 0.00811213 -0.0167 -0.00908976 0.00335362 -0.00364028 -0.00150706 -0.00937789 -0.0185555 -0.000902989 0.0273121 0.0204276 0.0180267 0.0271863 0.0347298 0.0131781 -0.0189297 -0.042958 -0.0488664 -0.0552135 -0.0687342 -0.0978135 1.24792)) (14.2751 0.0340747 0.048857 #(-0.0375261 0.024581 0.0173357 0.0105803 0.00152478 5.81223e-005 -0.0049663 0.000233414 -0.0059578 0.0172982 -0.0123975 -0.0121001 0.00817213 0.00614464 0.0063125 0.00277281 -0.0072908 -0.00298882 -0.00532286 -0.0151193 -0.0130224 -0.0190079 -0.00477871 -0.00682809 -0.00484661 0.0136435 0.0106479 0.0201277 0.016766 -0.0148155 -0.0230016 0.0010569 0.00368719 -0.00836747 -0.0108471 -0.0115598 -0.000523546 0.020508 0.0238148 0.0105346 0.0278912 0.030346 0.015747 -0.00584426 -0.0429999 -0.0557868 -0.0671162 -0.0745447 -0.115248 1.28424)) (15.2833 0.022009 0.0379483 #(-0.0444502 0.0319226 0.0206898 0.00408402 0.0038444 0.00518289 -0.0102187 0.00644884 0.0154201 0.00243678 -0.0155881 -0.0226183 -0.00535144 0.0143481 0.0263679 -0.00816404 -0.00439294 -0.00726711 0.00245852 -0.0075432 -0.0210695 -0.022927 -0.0121272 -0.00257655 -0.0142863 0.0116892 0.0195945 0.0314798 0.0171628 -0.026222 -0.0236029 -0.00279915 0.0139127 -0.00411994 -0.0220793 -0.0223499 0.0130053 0.0163297 0.014851 0.0168635 0.030113 0.0393203 0.0185481 -0.0032677 -0.0508295 -0.049786 -0.0681459 -0.100596 -0.141854 1.3324)) (16.2369 0.0167683 0.0321361 #(-0.0461453 0.0336128 0.0171639 0.00638196 0.00304988 0.00700732 -0.0124934 -0.0014443 0.0229149 0.00812651 -0.0156464 -0.027978 0.00155632 0.0148617 0.0236262 -0.0053183 -0.0306435 0.0156539 0.00576177 -0.00936416 -0.019092 -0.0214782 -0.0106117 -0.0139679 -0.00487678 0.0153928 -0.000839796 0.0328364 0.0370444 -0.0267438 -0.0258321 -0.0084227 0.00140206 0.0170352 -0.0249207 -0.0137748 0.00622318 0.00877071 0.0176743 0.0140944 0.0160371 0.0299227 0.0280204 0.00486572 -0.0471303 -0.0549004 -0.0792787 -0.0862093 -0.156202 1.34944)) (15.8715 0.00862119 0.0233064 #(-0.0416665 0.0196847 0.0351245 0.00540738 0.000268711 0.000455022 -0.00585776 -0.00906765 0.019069 0.0231938 -0.0242396 -0.0320143 0.00375507 0.0115636 0.0160781 -0.00497688 0.0104297 -0.0136434 0.0112971 0.000516813 -0.0335269 -0.00981996 -0.0165414 -0.0128344 -0.00386654 0.0142686 -0.0124378 0.0254652 0.0577827 -0.0404511 -0.0399016 0.00257038 0.0284287 0.00205934 -0.00698707 -0.0282862 -0.0129552 0.0375839 -0.00052652 -0.00139833 0.010455 0.0601005 0.027725 0.00917528 -0.0452916 -0.0495308 -0.114218 -0.0824053 -0.228428 1.43507)) (14.8358 0.0137405 0.030433 #(-0.035238 0.0325776 0.00811017 0.00564153 0.00956963 0.00160376 -0.00735718 -0.0106363 0.00927161 0.0156551 -0.014077 -0.0256614 0.00892661 0.0141185 0.0219964 0.00497017 -0.0213388 -0.00393183 0.00307147 -0.00527207 -0.00932004 -0.0149748 -0.0293915 -0.0137217 0.0110029 0.00820573 -0.00731358 0.0228706 0.0342061 -0.0270083 -0.0231551 -0.00456665 0.0112681 -0.00073322 -0.00608638 -0.0299522 0.00616215 0.0218085 0.0147894 0.01267 0.0171617 0.0382049 0.0155666 0.00222878 -0.0301421 -0.0626113 -0.101723 -0.0618076 -0.14028 1.33014)) (12.9037 0.0170322 0.0363311 #(-0.0361427 0.0205666 0.0172627 0.017552 -0.00678439 0.00380304 -0.00573859 0.00913126 0.0155822 -0.00543546 -0.00759378 -0.0190302 -0.00357661 0.0192382 0.00804061 0.000652122 0.000361389 -0.0179953 -0.00446666 0.00560995 -0.0184849 -0.0113776 -0.0232038 -0.00865374 -0.000620224 0.00406897 0.00305195 0.0334702 0.0202773 -0.0270967 -0.0247178 0.00910172 -0.000104248 0.000138012 -0.0102208 -0.0169238 0.00120545 0.0203969 0.0133169 0.0181668 0.0202681 0.0266863 0.021128 -0.0131285 -0.0365628 -0.0378504 -0.0756192 -0.0782206 -0.137483 1.31255)) (10.7606 0.0176641 0.0405161 #(-0.0483414 0.0247989 0.0315676 0.00585319 -0.00234617 0.009571 0.00527321 -0.010687 0.0163059 0.00885164 -0.0125577 -0.0134762 -0.00967633 0.0164184 0.00952228 -0.00630756 -0.0123339 0.00271924 -0.00671046 -0.0020015 -0.00886391 -0.0281787 -0.0135787 -0.0134191 0.00144693 0.00931767 0.000242524 0.0183011 0.0329657 -0.0164957 -0.0380229 0.00540505 0.0215291 -0.00189809 -0.0201857 -0.0100815 0.00201447 0.0118938 0.00726428 0.0202927 0.0107608 0.0392477 0.0177106 -0.00825438 -0.0278289 -0.0360925 -0.0803767 -0.0690058 -0.118693 1.27992)) (9.692 0.0163592 0.0410842 #(-0.0435487 0.0238735 0.0221766 0.0130095 -0.0102838 0.0102648 -0.00263138 0.00405493 0.0139175 0.00368894 -0.0144828 -0.0187693 0.000191167 0.0191079 0.0188621 -0.00391941 -0.0163057 -0.0108496 0.0112138 -0.0054916 -0.0242603 -0.0107545 -0.03524 -0.00986785 0.00436468 0.0159444 0.00288566 0.0280451 0.0177601 -0.0226378 -0.0232638 -0.00458616 0.0132367 -0.00669003 -0.00879428 -0.0174804 -0.00444567 0.0183938 0.0174463 0.0192643 0.0206223 0.0364433 0.00547454 0.00493223 -0.0256411 -0.0374557 -0.0770796 -0.0699102 -0.107736 1.2591)) (10.6083 0.0116637 0.0331585 #(-0.0339536 0.0239064 0.0193139 -0.00206308 -0.00420809 0.0162964 -0.00446401 -0.00723342 0.032238 0.00872946 -0.0187994 -0.0242643 -0.0134408 0.0259891 0.0161434 0.00132369 -0.0197008 -0.00519451 0.00655926 -0.00738285 -0.0172127 -0.0237242 -0.0212511 -0.0206254 0.0103538 0.0122223 -0.00456432 0.0447003 0.0352811 -0.0406705 -0.0316736 0.00797188 0.00656864 -0.0115901 -0.0027629 -0.0128048 -0.00570429 0.0118761 0.0188073 0.0222462 0.0124456 0.0410702 0.00791332 -0.00379496 -0.0170523 -0.0476136 -0.0781826 -0.0542285 -0.143112 1.28919)) (13.6333 0.00775797 0.0238547 #(-0.0364152 0.0291058 0.0227928 0.00502204 -0.0253292 0.048831 -0.0291211 -0.014896 0.0320535 0.00774532 0.000503408 -0.0316866 -0.00546139 0.0360913 0.00840064 -0.0208066 -0.0145649 0.000116066 0.00307052 -0.0122648 -0.0118387 -0.0277435 -0.0112472 -0.0110968 0.0148855 -0.00123177 -0.021587 0.0284518 0.0631961 -0.0358807 -0.0443364 0.00976814 0.00940558 0.00815862 -0.0182798 -0.0167586 0.0109045 0.0136983 0.0074112 0.00384714 0.0165089 0.0481128 0.0182451 0.00169633 -0.0279793 -0.0379538 -0.093019 -0.0760834 -0.15798 1.33196)) (14.9529 0.0090799 0.0246421 #(-0.0173912 0.0117589 0.0215592 -0.000100125 -0.00958332 0.0178238 -0.0220747 0.00944662 0.0241577 0.0100921 -0.0118245 -0.0308733 -0.0111011 0.0260419 0.0364623 -0.0174218 -0.0250652 -0.02109 0.0203074 0.00684312 -0.0399599 -0.0207732 -0.0171705 -0.0007063 0.00839398 0.0148383 -0.0116208 0.0395184 0.0320917 -0.0477367 -0.0288544 -0.013006 0.0343035 0.0151606 -0.0250012 -0.0238014 0.010687 0.0287551 0.00443121 -0.00885899 0.0187292 0.0305535 0.0398672 0.0256628 -0.0622547 -0.0391768 -0.0803045 -0.063373 -0.174028 1.33167)) (15.4713 0.0103036 0.0258065 #(-0.0317778 0.0220012 0.023046 0.0107401 -0.00700271 0.0157947 -0.0168062 -0.0275037 0.0367403 0.0183112 -0.0155777 -0.0184876 0.00537082 0.00657688 0.00920857 -0.00738122 -0.0258576 -0.00495231 0.0158989 0.0138713 -0.0316929 -0.0372503 -0.00456503 0.00398878 -8.80907e-005 0.00931697 -0.0254795 0.0441872 0.0447222 -0.0413425 -0.0365677 -0.00544457 0.0244433 0.0112955 -0.0182531 -0.0124006 0.00266321 0.0168735 0.014526 -0.0109792 0.0141278 0.0440501 0.000770168 0.0424379 -0.0278247 -0.0526684 -0.0777227 -0.0873046 -0.175866 1.34552)) (14.1187 0.00916422 0.0254771 #(-0.045858 0.0400202 0.0205128 0.00743514 -0.00145771 0.00837235 -0.0248272 -0.00172827 0.0233621 0.0100241 -0.0135858 -0.0126684 -0.00336266 0.0149539 0.0171219 -0.016675 -0.0227132 -0.000102549 0.020379 0.00582718 -0.016864 -0.0320013 -0.0340711 0.00940389 -0.00660789 0.0171697 -0.029894 0.0563412 0.0606243 -0.07549 -0.0483998 -0.000330146 0.0359239 0.0257492 -0.00142432 -0.0289091 -0.0018749 0.012466 0.00260386 -0.0152575 0.00862908 0.053457 0.03697 0.0345913 -0.0435553 -0.039316 -0.0996627 -0.0778146 -0.205904 1.3743)) (12.5142 0.0109789 0.0296196 #(-0.0372881 0.0196089 0.0233113 0.000903561 -0.0047855 0.0192033 -0.00402685 -0.00304796 0.0072131 0.000961789 -0.00506267 -0.0118756 0.00342084 0.015397 0.00417627 0.00558174 -0.014547 -0.00178372 -0.00917506 0.0153024 -0.021183 -0.0321192 -0.0190146 -0.0116695 0.0083767 0.00252157 0.0031781 0.03148 0.0255226 -0.0305256 -0.0148153 0.00160903 0.010152 0.00196973 -0.0133266 -0.0138634 -0.0111339 0.0246016 0.00657759 0.0046415 0.0102237 0.0405588 0.0267124 -0.0205946 -0.0262742 -0.0302408 -0.0733365 -0.0751875 -0.141942 1.30887)) (13.1881 0.0149057 0.033619 #(-0.0392646 0.0235916 0.0113109 0.0165674 0.000356377 0.0096727 -0.00454504 -0.0118521 0.0189847 5.30982e-006 -0.00576891 -0.00829558 -0.00267612 0.0116296 0.0180062 -0.00463104 -0.015852 -0.0119515 0.00220159 0.00224108 -0.027798 -0.0126524 -0.0149994 -0.00157439 -0.00384594 0.00016854 0.00338744 0.0262442 0.0138858 -0.0262235 -0.0060537 -0.000456936 0.0188089 0.00153812 -0.0108762 -0.0196819 -0.00571758 0.0244648 0.0111209 0.00558558 0.0127132 0.0348169 0.015571 -0.0175171 -0.0217261 -0.045869 -0.0708379 -0.0505154 -0.114525 1.26721)) (12.7999 0.015072 0.0343149 #(-0.0333835 0.0122214 0.0259325 -0.000845576 -0.00411607 0.0249855 -0.00362802 -0.00123161 0.00374519 0.00881159 -0.00779002 -0.0221836 -0.00150112 0.0259934 0.00794084 -0.00206094 -0.0134564 -0.00876726 -0.00201227 -0.0224425 0.00930002 -0.0259136 -0.0165928 -0.00342897 -0.00262414 0.00704048 -0.00242533 0.0235934 0.0114056 -0.0151016 -0.0109616 0.00159531 0.0111167 -0.000793585 -0.00855475 -0.0193289 0.00818316 0.0173823 0.00418687 0.0104691 0.0231481 0.0104235 0.0158543 -0.00351913 -0.0424822 -0.0357488 -0.0522538 -0.0381995 -0.0936292 1.22602)) (12.2473 0.0193377 0.0397359 #(-0.0208312 0.0113622 0.0107963 0.0102407 -0.0113957 0.00688707 0.00914879 -0.00983215 0.00520417 0.00334524 -0.0068846 -0.004754 -0.00291994 0.0137996 0.0146112 -0.00155131 -0.0176285 0.00365784 -0.0104858 -0.0192718 -0.000923549 -0.0131308 -0.0111267 -0.00719019 0.000579761 0.0111471 -0.00676168 0.0234209 0.0115352 -0.0168934 0.0025673 -0.00926516 0.00685466 -0.00665536 -0.00981694 0.000390394 0.00485606 0.00488992 0.00723448 0.0167406 0.00949511 0.00968203 0.0148381 -0.0192989 -0.0238238 -0.0274632 -0.0505583 -0.0318813 -0.0690697 1.18902)) (12.5963 0.016594 0.0362957 #(-0.022897 0.0164408 0.00922307 0.00712825 0.00029965 0.0126678 -0.00781488 -0.00903336 0.00276701 0.00841422 -0.00438664 -0.00758085 0.00516114 0.00530365 0.00871018 -0.00177273 -0.00100205 -0.00497492 -0.00829477 -0.00643409 -0.0175788 -0.016037 -0.0116676 -0.00203718 -0.000523905 0.0101769 -0.00147634 0.0081845 0.0146411 -0.0119274 -0.00436797 -0.000224399 -0.00513704 -0.00984378 0.0115129 -0.0102507 0.00516442 0.00549147 0.00572397 0.0118901 0.0113157 0.0218897 0.00945389 -0.0113134 -0.0298536 -0.0302538 -0.053088 -0.0372686 -0.0642578 1.19366)) (13.5525 0.01008 0.0272723 #(-0.0123657 0.0053427 0.019458 -0.0176663 -0.0176549 0.0404966 -0.00390325 -0.00579765 0.00887555 0.00317001 0.00172718 -0.00829583 0.010417 0.0153962 -0.00556122 -0.00680748 -0.00745445 -0.00852993 -0.00462103 -0.0159715 -0.000628177 -0.0183191 -0.0147015 -0.00193298 -0.00415885 0.0236506 -0.0098982 0.015603 0.0132994 -0.0134173 -0.00543716 0.00140853 -0.000410987 -0.0155814 -0.00399504 -0.000352762 -0.00284362 0.0100352 0.0139833 0.0156556 0.00280102 0.00782334 -5.04827e-005 -0.0182239 -0.0189623 -0.0239327 -0.0540221 -0.0168124 -0.0578101 1.18215)) (12.068 0.00596845 0.0222389 #(-0.00770466 -0.00247063 0.020446 -0.00341433 -0.0175267 0.0299728 -0.00334073 -0.021708 0.0222189 0.00349176 -0.00219307 0.000507939 -0.000906229 0.0251413 -0.00347692 -0.0193672 -0.008356 0.0107288 -0.00522202 -0.0373399 0.0110019 0.00334983 -0.0260176 -0.00508717 0.0076833 0.0123874 -0.0218113 0.0217126 0.0137616 -0.0343426 0.00107652 -0.0108971 0.00723602 -0.0140256 0.00945629 0.008111 -0.013161 0.0263409 0.00322294 0.0169951 0.0125402 0.00634017 -0.0281478 0.00833678 -0.0210252 -0.0480639 -0.0657505 0.00962592 -0.0670183 1.193)) (8.95623 0.00286173 0.0178752 #(-0.0299596 -0.00271054 0.0316405 0.00830122 -0.0430843 0.052154 0.00778072 -0.0218403 0.015222 0.00900955 0.000450335 -0.0294424 0.0109118 0.0305165 0.0185617 -0.0211344 -0.00754338 0.000348268 -0.015125 0.000259483 -0.00953378 0.00744751 -0.0392438 -0.0133562 -0.0140394 0.0473366 -0.0574915 0.0274957 0.0739216 -0.0633229 -0.00625577 -0.00332914 0.0318236 -0.039495 -0.0259531 0.0239393 -0.0180297 0.0156937 0.0245471 0.0241233 0.00445331 0.0143366 -0.0112595 0.0136985 -0.0568217 -0.0400073 -0.106216 0.040655 -0.0915969 1.22924)) (6.49921 0.00445611 0.0261847 #(-0.0170517 -0.0101715 0.0184278 0.00588615 -0.0192503 0.0377397 -0.00414877 -0.0237132 0.0261238 0.0049736 -0.00638682 0.00527185 -0.00923617 0.0111306 0.0255296 -0.0039067 -0.0151077 0.00377979 7.06266e-005 -0.0208127 0.00467839 -0.022734 -0.0168833 -0.00336075 -0.01055 0.033853 -0.0379811 0.010155 0.0492233 -0.0412482 -0.00933746 -0.0204949 0.0208357 0.00125835 -0.0115378 -0.000968487 0.00445165 0.00835097 0.00622662 0.0115168 0.000545416 0.00342692 -0.00927968 0.0260598 -0.0528268 -0.0332704 -0.0524391 0.0325668 -0.0789734 1.17526)) (5.25729 0.00395311 0.0274213 #(-0.0240403 0.0205123 0.0153895 -0.0123595 -0.0220413 0.0554869 -0.00704868 -0.0433425 0.0501927 -0.00331648 -0.0181042 -0.0055328 -0.0079657 0.0218988 0.0184512 0.000216515 -0.0131423 -0.00679136 0.0172376 -0.0200239 0.00385909 -0.0187232 -0.0339574 -0.0205053 0.00639417 0.0217717 -0.022982 0.0227078 0.0735146 -0.0648862 -0.0373938 0.00153798 0.00527095 0.0142592 -0.0107342 -0.0298141 0.00548001 0.0163492 -0.00212356 0.00278833 0.0101466 0.0397622 0.0149 0.023642 -0.01529 -0.0428728 -0.0909119 0.00412615 -0.130688 1.23334)) (4.64889 0.00405787 0.0295443 #(-0.0083154 0.00615811 0.0229795 -0.0118895 -0.011159 0.0234972 -0.00391371 -0.0106054 0.0152195 0.0045161 -0.0309345 -0.0133451 0.0142733 0.0022754 0.0224104 0.00053866 -0.0105869 0.014126 -0.00594441 -0.016928 0.000217074 -0.00374499 -0.0370543 -0.0101543 -0.0131152 0.0467066 -0.0290259 0.0361985 0.048131 -0.0712857 -0.010248 0.0200725 -0.00527912 -0.033853 0.00625684 -0.0132771 -0.00059062 0.00807303 0.0207666 -0.005388 0.00403096 0.0390784 0.0263475 0.00420176 -0.0247701 -0.0169901 -0.0981137 0.00202813 -0.122794 1.22287)) (4.2687 0.00527028 0.0351374 #(0.0119431 0.000370011 0.00297805 -0.0086345 -0.00619318 0.0209268 -0.0214211 -0.00264095 0.000795118 0.0018904 0.00504403 -0.00221174 0.000734628 0.0115394 0.00269348 0.00862158 -0.0112626 0.0128954 -0.0100209 -0.0261409 -0.00341844 -0.00612675 -0.023003 0.0109423 -0.00282099 0.0203828 -0.0265252 0.0270202 0.0322998 -0.0362086 -0.00119129 -0.0153138 -0.00350063 0.00240223 -0.0210972 -0.00135233 -0.00711855 0.000712969 0.0123906 -0.00078104 0.000209776 0.0312843 -0.00727613 0.0274143 -0.0141633 -0.0350039 -0.0442454 0.0167168 -0.0482093 1.11671)) (5.08667 0.00434494 0.0292264 #(-0.00272251 0.00941567 0.00822995 -0.014127 -0.00472909 0.0256388 -0.0205545 -0.00637778 -0.0112651 0.0378657 -0.0158337 -0.00984417 0.00216444 0.030978 -0.00207667 -0.00625094 -0.00241573 0.000887676 -0.0113091 -0.0167408 -0.00726853 -0.00532588 -0.0106122 0.000375745 -0.00057362 0.0254724 -0.018358 0.0306097 0.0326059 -0.0225176 -0.0471872 0.00568396 -0.0101327 -0.0167238 -0.0112461 -0.0017848 -0.00424018 0.0120333 0.0037898 0.0135469 0.0227388 0.0193921 -0.0318962 0.0246949 -0.0262602 -0.0227707 -0.0672516 0.0572928 -0.0571018 1.11738)) (5.64243 0.00660276 0.0342082 #(0.00180166 0.00187813 0.00574493 -0.000219231 -0.0214208 0.0292124 -0.0171232 -0.0116133 0.0143524 -0.0080191 0.00040181 -0.000264368 0.00500117 0.0156718 0.00494422 0.00107104 -0.0174182 0.00156305 -0.00116767 -0.0143132 -0.00873124 0.00879861 -0.0235025 -0.00555377 0.0159542 0.0120798 -0.00968709 0.0101018 0.0241207 -0.0283285 -0.00464771 0.00488285 -0.0317064 0.000691314 -0.0122031 -0.0076785 0.00264264 0.00947001 0.0122303 0.00967777 0.0183964 0.00361356 -0.0121287 0.0116267 -0.0186891 -0.0143781 -0.0485434 0.0242676 -0.0335089 1.09521)) (4.34906 0.00506972 0.0341424 #(0.0023974 -0.00279862 0.0120042 -0.00157989 -0.0157521 0.0239786 -0.0126398 -0.0135926 -0.0020871 0.00151955 -0.00174203 -0.00773394 0.0159697 0.00780768 0.021657 0.00663021 -0.0142795 0.00149963 -0.00494957 -0.00158777 -0.0254905 -0.0117564 -0.017529 -0.00628616 0.00849666 0.00422017 -0.0116558 0.0310608 0.0345892 -0.0316539 -0.0132967 -0.00584913 0.00354922 -0.0173338 -0.0110622 -0.0096414 0.00859083 -0.0039589 0.0226801 0.0154026 0.00896204 0.0230092 0.00481482 0.00292927 -0.0234833 -0.0254714 -0.0981472 0.0441442 -0.0688532 1.14897)) (2.61565 0.00474862 0.0426083 #(0.00879548 -0.00707132 0.0105265 0.00589761 -0.0181165 0.0122799 0.000610275 -0.0196829 -0.011157 0.0120507 -0.0115164 -0.0105635 0.0167566 0.0110644 0.0208706 0.00165262 0.00444448 -0.00889109 -0.00448973 -0.00204069 -0.0176097 -0.0204983 -0.00444134 -0.0102928 -0.000729621 0.00828533 -0.0156112 0.0249824 0.046813 -0.034427 -0.0110774 -0.0109798 -0.00690826 -0.00195731 -0.0157386 -0.00195138 0.00642795 -0.00283065 0.0119922 0.0211103 0.0124749 0.0247881 0.0132657 -0.00455936 -0.0371286 -0.0106291 -0.0739445 0.0263266 -0.0843839 1.15059)) (2.02703 0.00255318 0.0354904 #(0.0134249 -0.00506588 0.00680395 0.0105582 -0.0323818 0.0493337 -0.0217674 -0.0241798 0.00928927 -0.023553 0.0104105 -0.0160771 0.00235487 0.00839372 0.0312377 0.00805041 0.000414273 -0.0136668 -0.0141831 0.0145558 -0.01835 -0.0176581 0.00780919 -0.0178566 -0.00798348 0.0228851 -0.0520132 0.0414188 0.066511 -0.0612651 0.00654983 -0.0331677 0.0129804 -0.0240143 0.0167766 -0.000209965 -0.0232557 0.0166038 0.0163538 0.0123617 -0.00410349 0.0241719 -0.00992855 0.0157116 -0.0186285 -0.0253129 -0.0767908 0.0521641 -0.0693304 1.12793)) (2.64432 0.00171959 0.0255009 #(-0.0191815 0.0127539 0.0107323 0.00105373 -0.0253985 0.0548691 -0.00350344 -0.0407332 0.00805417 -0.00516293 0.0269923 -0.0481122 0.045745 -0.00949443 0.029402 0.00253762 -0.0224486 0.00621702 -0.0126075 -0.000360755 -0.0107886 -0.00802914 -0.0263488 -0.00418882 0.00777657 0.0122917 -0.0655835 0.0318259 0.0745041 -0.046913 -0.0178272 -0.014913 0.00287156 -0.0266232 0.016267 0.00797917 0.00580041 0.0114133 0.00738462 0.0441676 -0.0136994 0.0335519 -0.0324743 0.0188773 -0.0348701 -0.0234333 -0.174669 0.177908 -0.0964444 1.12857)) (3.49525 0.0028907 0.0287582 #(-0.022997 0.00390569 0.0195987 -0.00368246 -0.0249804 0.0205793 -0.000749982 -0.0146779 0.0253093 -0.027436 -0.00506964 0.0229678 0.0122114 -0.00660955 0.0289347 0.00446956 -0.0240813 0.0124458 -0.000533498 -0.0357979 -0.00426894 0.00482643 -0.0216519 0.00376066 -0.0166858 0.0254196 -0.047756 0.0296842 0.05304 -0.053725 0.0233847 -0.00627376 -0.0327575 0.0242391 -0.00986949 0.0018908 0.0199183 -0.001377 0.00140167 0.0246927 0.00391399 0.00494078 -0.0242442 0.0174991 -0.0272264 -0.0343578 -0.0611368 0.0862893 -0.0566336 1.08269)) (3.59173 0.00241115 0.0259096 #(-0.0280463 0.00239539 0.0275002 -0.0139323 -0.0348279 0.0607939 -0.0263654 -0.0111383 0.00125177 0.0134574 -0.0201514 0.0256755 0.0152298 -0.0129894 0.040595 -0.0242227 0.0223003 -0.0198948 -0.00945686 -0.0104881 -0.0149074 0.000106048 -0.0155021 0.00164234 -0.0275243 0.0334275 -0.0597113 0.0490029 0.0458835 -0.0406038 -0.00296535 0.00162114 0.00027736 -0.0194494 0.0124248 -0.00222679 0.0104655 -0.00167292 0.00815926 0.0283748 -0.0225562 0.0143205 -0.0188394 0.00579293 -0.0147764 -0.0167599 -0.050156 0.0847534 -0.0659405 1.07315)) (2.26719 0.00255288 0.0335561 #(-0.0136514 -0.00925972 0.0167188 -0.00485284 -0.0336646 0.0412232 -0.000246899 -0.0298077 0.00712888 0.0134616 0.0103107 -0.00485241 -0.00127703 0.0164119 0.0132654 -0.019095 0.00456902 -0.00259853 -0.000275873 -0.0127027 -0.00593184 0.0101047 -0.0413224 0.018843 -0.0107773 0.0150738 -0.0289957 0.0254439 0.0380609 -0.0406301 -0.00392326 0.0172783 -0.00857435 -0.0223009 0.00749708 -0.0165367 0.0238457 0.018136 -0.00458933 0.00245699 0.00172918 0.00670983 -0.024566 0.00660529 -0.0205404 0.00950086 -0.0578217 0.0939725 -0.0510117 1.04425)) (0.609353 0.00163717 0.0518337 #(0.00316256 -0.0122567 0.00518264 0.0126123 -0.0397706 0.0392831 0.0116002 -0.0471934 0.00805918 -0.00560564 0.000558784 -0.00409364 -0.00452707 -0.00113856 0.0257756 -0.00932488 0.00381936 -0.00247659 0.00301922 0.00335715 -0.00619763 0.0345422 -0.0321831 0.00519092 -0.00104381 -0.021393 -0.028818 0.0308446 0.0615516 -0.0569711 -0.0213437 0.00541473 0.00891156 -0.00345845 -0.00526036 -0.0140875 0.0217332 0.0150425 0.00302012 0.000750344 -0.0227373 0.0355403 -0.0606219 0.0543924 -0.0197096 0.0106198 -0.0761164 0.133679 -0.0540805 1.00403)) (0.116473 0.000738204 0.0796116 #(-0.0020667 -0.00708028 0.00649903 0.00525495 -0.0577545 0.0708488 0.0241519 -0.0957537 0.0444855 0.00816514 -0.0260424 -0.00887706 0.0161092 -0.00643925 0.0365329 -0.0114855 -0.0214506 0.00323551 4.06337e-005 0.00984418 0.00579543 0.0340158 -0.0244511 -0.00303321 -0.0329481 0.0117391 -0.0672089 0.0657941 0.120411 -0.0823802 -0.0449917 0.00125354 0.00608117 -0.0209081 -0.0254859 0.0413741 -0.00546445 0.0228035 -0.0102555 0.0282721 -0.0411615 0.0264412 -0.0625765 0.0651369 -0.0960416 0.0914793 -0.12826 0.244372 -0.0968032 0.978677)) (0.0472545 0.000482073 0.101003 #(-0.0132409 -0.00177229 -0.00651967 0.0181785 -0.057867 0.0886454 -0.0060562 -0.0415304 -0.00604645 0.00809692 -0.0261498 0.0308232 -0.0207518 0.039377 0.0286866 -0.00414628 -0.101779 0.0925687 -0.0566329 0.0285281 -0.0124488 0.0429751 -0.0231868 0.00492606 -0.0382182 0.0353667 -0.0854897 0.072105 0.138783 -0.152908 0.0118608 -0.0236536 0.0280545 -0.0358662 -0.00158007 0.0410328 -0.0307116 0.0351427 -0.0487812 0.0650863 -0.105127 0.0931477 -0.118991 0.157664 -0.204664 0.186411 -0.180145 0.351459 -0.130844 0.92427)) (0.0200657 0.000490229 0.156305 #(-0.0167117 0.0226238 -0.0290179 0.0310399 -0.05596 0.0754746 -0.00102182 -0.0240663 -0.00557826 -0.00226293 0.00760277 0.00121096 -0.0371931 0.0368175 0.00439128 -0.00121828 -0.0701961 0.0851828 -0.0429475 0.0221135 -0.0202851 0.0294757 0.0173632 -0.014941 0.0101552 -0.0156045 -0.0714142 0.0373879 0.140392 -0.155288 0.0474913 -0.015392 0.010226 -0.0506144 0.00775825 0.0425248 -0.0111819 0.0198418 -0.0465491 0.0473969 -0.0958641 0.069069 -0.0800155 0.135248 -0.167486 0.159519 -0.163318 0.341011 -0.122999 0.899713)) (0.0189561 0.000463645 0.156394 #(0.0136824 -0.010146 -0.00340101 0.00501791 -0.052312 0.0825702 -0.0198587 -0.00941267 0.00742931 -0.00822124 -0.00559287 0.0070671 -0.0295775 0.0163785 -0.000200317 -0.0124918 -0.0388802 0.0517694 -0.0148913 -0.0019372 0.0130002 0.0529274 -0.051331 0.0468511 -0.0493757 0.0488883 -0.0877978 0.0390208 0.120372 -0.130924 0.00454228 0.0284801 -0.0370236 -0.0207961 0.00413483 0.0556726 -0.0461664 0.043992 -0.0572133 0.0680651 -0.129146 0.0933036 -0.0903923 0.0963898 -0.115223 0.173486 -0.16108 0.327376 -0.109485 0.877362)) (0.0157623 0.000457797 0.170422 #(0.00679172 0.0179331 -0.0180012 0.00985177 -0.0710897 0.0804711 -0.0138887 -0.00160079 -0.0130131 -0.0116605 -0.00195402 0.0102408 0.00544203 -0.00882841 -0.00664669 -0.000185585 -0.0333044 0.0571107 -0.0324269 0.00482369 0.00173713 0.0817342 -0.0689869 0.0314419 -0.0416472 0.0452527 -0.104628 0.0733021 0.109757 -0.112525 -0.040671 0.0457447 -0.033124 0.0189072 -0.0182032 0.0382207 -0.0430175 0.0633007 -0.0880582 0.0891837 -0.145313 0.126151 -0.130188 0.133809 -0.156576 0.210072 -0.192572 0.343954 -0.102867 0.867452)) (0.0193939 0.000457706 0.153625 #(-0.00460792 0.0355563 -0.0550596 0.043009 -0.0897849 0.0978742 -0.0187992 0.00582897 -0.0109002 0.000631806 -0.0163601 0.0133513 -0.0165699 0.0221935 -0.0312557 0.04581 -0.0629084 0.0434437 -0.0167021 0.0323193 -0.0250667 0.0627469 -0.0306966 -0.00490861 -0.0368386 0.0217197 -0.0728413 0.0668549 0.145474 -0.169416 0.0122649 0.00448438 0.013949 -0.0353851 0.020688 0.00875267 -0.0340474 0.0569403 -0.0747049 0.0865628 -0.127027 0.0997718 -0.118786 0.172951 -0.208013 0.216935 -0.215728 0.401293 -0.19069 0.923122)) (0.0267348 0.000456167 0.130624 #(0.0221721 0.012707 -0.0342673 0.0498141 -0.125798 0.0945948 -0.009383 -0.0118047 -0.00833615 0.0354772 -0.041698 0.0220065 -0.043747 0.0427328 -0.0334768 0.0279624 -0.0268537 0.00968139 0.00111546 0.0377293 -0.0348329 0.0808209 -0.0457136 0.00457449 -0.0453242 -0.0107467 -0.0188348 0.0300905 0.173791 -0.194862 0.0537233 -0.0419804 0.0496971 -0.0701674 0.0499813 -0.00747099 -0.0222291 0.0273433 -0.0549461 0.0661543 -0.122178 0.0944649 -0.101576 0.17229 -0.189446 0.207714 -0.21558 0.418696 -0.215629 0.931565)) (0.0200745 0.000471228 0.153212 #(0.0163527 0.00660207 -0.0143944 0.046632 -0.126296 0.118434 -0.0369965 -0.00451566 -0.0201182 0.0417401 -0.0308534 -0.00543496 -0.0172945 0.0438493 -0.0319897 -0.0176332 -0.00909391 0.00684448 0.00776292 0.0226499 -0.00129345 0.0597638 -0.057499 0.0439582 -0.0376084 -0.009205 -0.0282326 0.0349981 0.136497 -0.137021 0.0108061 -0.0220325 0.0138336 -0.0341895 0.00554748 0.0125278 -0.0174402 0.0430164 -0.0595981 0.048263 -0.112704 0.102835 -0.101221 0.15651 -0.167554 0.189205 -0.200076 0.383302 -0.1668 0.902884)) (0.0178948 0.000884452 0.222317 #(-0.00627428 0.017076 -0.0217517 0.0596357 -0.115011 0.137658 -0.140797 0.0413646 -0.025147 0.0409271 -0.0298679 0.0230878 -0.00804102 0.0133819 -0.0343905 0.081481 -0.0160831 0.031044 -0.0362416 0.0814956 -0.0892642 -0.0230409 -0.0232022 0.112084 -0.0729296 -0.0349948 0.00901226 -0.0373362 0.140441 -0.0702999 -0.00257567 -0.0348515 -0.00258082 0.0140751 -0.0718087 0.0880132 -0.061838 0.0690842 -0.118292 0.142831 -0.185955 0.190591 -0.155962 0.45873 -0.106312 0.127302 -0.523777 0.419269 -0.501987 1.22411)) (0.014956 0.000914502 0.247278 #(-0.023965 0.0260125 -0.0174047 0.0515138 -0.0830966 0.07056 -0.0839288 -0.00253678 0.0274258 -0.000953763 -0.00370321 0.0051892 0.0273904 -0.020619 -0.0100326 0.0564985 0.00785514 0.0225726 -0.0248022 0.0636671 -0.0849298 -0.0493795 0.0247842 0.0783257 -0.054683 -0.0485245 0.00161631 -0.0165824 0.139226 -0.0743001 -0.00122059 -0.0566757 0.0247024 0.00172735 -0.0647441 0.0783151 -0.0575751 0.0609131 -0.105484 0.127889 -0.170536 0.193175 -0.164876 0.462587 -0.105663 0.112055 -0.495609 0.396188 -0.497893 1.21815)) (0.00871568 0.000567858 0.255252 #(-0.0124666 0.0309579 -0.00109739 0.0135459 -0.057433 0.0477187 -0.0502651 0.00271826 0.0372547 0.0164188 -0.0446111 -0.0127535 -0.0377459 0.05085 -0.0332468 0.0648767 -0.0421368 0.0453716 -0.00560286 0.010505 -0.0502685 0.0272348 -0.0168195 0.0334298 -0.045445 0.0609193 -0.0939262 0.0603289 0.127758 -0.127759 -0.0161537 -0.0241133 0.0220789 0.0501327 -0.0297039 0.0276074 -0.0749799 0.0195223 -0.134458 0.0784379 -0.103965 0.143044 -0.0238226 0.243323 -0.14168 0.124602 -0.245754 0.281028 -0.225522 0.993662)) (0.0086891 0.000454286 0.228653 #(0.000182833 -0.00254678 0.0082363 -0.0153415 -0.0299224 0.0849131 -0.0489407 0.00623273 0.00330074 0.015936 -0.0400408 -0.020401 -0.0247914 0.0710104 -0.015902 0.00164445 -0.0397469 0.0223963 0.0144133 0.00597068 -0.0101367 0.0517253 -0.0400181 0.0204692 -0.0703128 0.0792271 -0.0877888 0.0647522 0.100521 -0.114483 -0.00566729 -0.0255629 0.0314529 0.0182582 -0.0152464 0.0337968 -0.0685177 0.0350596 -0.0735331 0.0771414 -0.107742 0.0609778 -0.0612328 0.122617 -0.132552 0.162598 -0.143835 0.327107 -0.115002 0.855719)) nyquist-3.05/demos/arpeggiator.htm0000644000175000000620000000204311536000246016304 0ustar stevestaff Untitled Document

    Arpeggiator Tutorial

    This page describes an arpeggiator example in Nyquist.

    What does it do?

    An arpeggiator plays a sequence of pitches over and over, usually outlining a chord.

    How does it work?

    The file arp.sal has example code to create arpeggiator effects. There are comments in the code to describe how it works.

    How can I use it?

    SAL> load "arp.sal"
    Or, open demos/arp.sal using the Nyquist IDE and load the file with the load button.

    You should hear a short piece. There are simpler examples in the code -- read the comments in the code to see all the examples and to find commands to try them out.

    nyquist-3.05/demos/allewis/0002755000175000000620000000000011537433125014740 5ustar stevestaffnyquist-3.05/demos/allewis/cell_aut.lsp0000644000175000000620000000624511510141774017252 0ustar stevestaff;; cell_aut.lsp -- cellular automata for sound generation ;; originally by Ann Lewis ;; revised by Roger B. Dannenberg ;; March 2004 ;; compute-update-rule -- compute the output given a rule and 3 inputs ;; (defun compute-update-rule (rule a b c) ;; this is the most interesting part of the whole program ;; the rule has 8 bits. Use a, b, c to index the rule bits ;; and determine the result. To do this, we want a bit in ;; the right position, e.g. if a=0,b=1,c=1, then the index ;; is 011 = 3, and we want a bit pattern with "1" in position 3: ;; 00001000. Note that this is 2^3 = a*2^4 + b*2^2 + c*2^1. So ;; we can test a, b, and c and multiply by 16, 4, and 2 to get ;; the right bit pattern. Then we can "and" it with rule to ;; get either zero or a non-zero as the result. (let ((abc 1)) (cond (a (setf abc 16))) (cond (b (setf abc (* abc 4)))) (cond (c (setf abc (* abc 2)))) (setf rule (logand rule abc)) (> rule 0))) ;; the main cellular automata implementation (defun cell-aut (sound-object-list duration update-rule iter) (let (prev current array-len score (now 0.0) tmp) ; create and initialize current and prev bit lists (setf array-len (length sound-object-list)) (setf prev (make-array array-len)) (setf current (make-array array-len)) (setf prev (make-array array-len)) (setf (aref prev (/ array-len 2)) t) ; create the score by computing iter generations of the automata (dotimes (i iter) (dotimes (j array-len) (princ (if (aref prev j) " X" " 0")) ; push a note on the list for each "true" in the prev array (if (aref prev j) (push (list now duration (nth j sound-object-list)) score))) (terpri) ; compute current from prev using update-rule ; first do endpoints, wrap-around style (setf (aref current 0) (compute-update-rule update-rule (aref prev (- array-len 1)) (aref prev 0) (aref prev 1))) (setf (aref current (- array-len 1)) (compute-update-rule update-rule (aref prev (- array-len 2)) (aref prev (- array-len 1)) (aref prev 0))) ; then loop through everything else ; want to cycle from 1 to array-len-2 (dotimes (j (- array-len 2)) (setf (aref current (+ j 1)) (compute-update-rule update-rule (aref prev j) (aref prev (+ j 1)) (aref prev (+ j 2)))) ) ; set prev to current (setf tmp prev) (setf prev current) (setf current tmp) ; increment the time (setf now (+ now duration))) ;; the score is now in reverse order, so fix it (setf score (reverse score)) ;; now we have a score, render it to sound and return it: (timed-seq score)) ) (defun cell-aut-major-scale () ;; for testing, this creates an 8-note scale ;; requires (load "pianosyn") to get the piano library (let (scale offsets) (setf offsets '(0 2 4 5 7 9 11 12)) (dolist (p offsets) (push (list 'piano-note-2 (+ A3 p) 100) scale)) (reverse scale))) (defun cell-aut-demo () (require-from piano-note-2 "pianosyn.lsp") (play (scale 0.5 (cell-aut (cell-aut-major-scale) 0.2 30 80)))) nyquist-3.05/demos/allewis/cmusic_pres.ppt0000644000175000000620000014400010144436365020000 0ustar stevestaffࡱ> _a`n'hWM>tmPNG  IHDRr믢bPLTEwwwoooiiiaaa[[[UUUSSSOOOMMMKKKGGGAAA===;;;777555333111///---+++)))'''%%%###!!! tttppphhhfffbbb```\\\ZZZXXXRRRNNNHHHDDDBBB<<<:::888444222...,,,***(((&&&$$$"""  q2r_`ZP|`x1P(XLHϊ;tRNS;bKGDH cmPPJCmp0712HsIDATx^]ic U7ee:F5c9*.6V]:5]Gb͝c\ !1s^pÞ}\F}<ӱ7Oz˓rfaLyt?0Gw$^ ;T/ {7]yV/O q`p|Ob'<>>ğr0L#=# K'H2uA;8֗Q}G|`{oE;x!~IxCBA"s>_N9G<7F1&e'sۋݵe2޴s[n9oM7`X?X{FH_[xY 9alk>̴,VŃ>G{DD|sX'>;x|zI9 }e0DU0wKXh2rr1 b2 !B0E:R)⽌q OcTGso<5{,=o9M${KoxQMĻ&v !j x5A;V ء&wT];X5Jk`b Rw LPĻC`@*񮁉jxwH%50CMUĻ&v !j ;Yu]jrRۉsۍgˑreȝ>?u"-vm-Xo{Qy|?F=n{Na5|Y:NE顟i-.DL]gP8t^ښH\ŵ n*<|-V)۠nO;5s0f❡Kv O$ g[LW3_9.:v_ixG x|G{ |vAr<NJ<5hJh?zYG-_K 1N?g%]- sC:b 㼌FqCSjYKOxp%%ނ%xca|T4=K&@zrcBVZkBca5I` Rڡ"|$c#Y:ؓ'x 5FЕJ$|] g+(uYfvо21cZӎ)Z6pxgP%j]D8KwGuծG5.Y߂Ίnʭ]Ķ| M᝛Ѫw~*s=]Gv]g%x'c\ uSx˾ N%&WuX7VM$#ox'| -rw¯](k;}Jc; +7wϳn0bYz}\oo1@;eTx֏}V%nx dkW.Wpwg [n. ?aV^8V+6Qɢ۞ga zb:۞m|3F,ς{kY^?p}.}T~tFWlyRĻNyĻNyĻNy ޾,ThNi 8Uvڭγr&b(`Smʋ˩rf <+g|'N*dlke]jWY9[_Sm.T;}r<޷fk <#yګ5F mWa7TMLZnWYHA B#Se7u <+:[>mu>kz]:,U|7DܤFl-7#mDm36G}Z>^wH۽feux_n;RknNc`!}O|ဘ 7Choms>O-p9F4h77XQ:y9;M|c5m~VCM}.pͦowI9݉Vٽ:U_Awu7_wܜ8/?|=T3K;N\k1Vo>ě{Ç]>|xoc ~kkQ)ߔd q"M|R&[,_x(M6㧜WDܒB}Ň ߕw@oXo/V|w_#ޕ7"FM|o[(ߔo7;ο{Tssss~_>>>>>_n忟Os|>|$_A1 +ߗea<;Цw琠Ƅ{ kۓjߺO%lB͌\| r6f)ߔoӨ~kM.t}M|RP}q>K~~~~~gTg'Qx* H`,~v&ߏI~[^'w (llGlSQ-9tB5ƾoMM%K}ޯȔo7;۸{w4ϵ%k) y{BiHSSSSS?>EX@<@3{83YTw澒@>gS0„ sn{?70TmYEV;?|WNpn @>*)W_|S1@u=r+ovmM|np]~D(fHS=Q m<|fv裏NWs)a~̑:h+([RrmHƄ'pE~,HUPhH [P6,su Hq0+v#@ځu(Hj1ަ:16d1廲֋ěxVg)ߔown8Sq>&_áom!*kZǰB}ߗ_|ACxҗ1pS'p[9|n{6򡨿1㬤WZH n ' r;5L CP;M6w6oCakϩϩ+]E-Esk͇RSSSoaŴ?s5A]sA}S\̗2|q[ տwHϠ?C1$!as,/d}8KjkxoJqO-4\g{~ >jo![oPw|>F|p"ɏQSSsss 双De6`1 %Z|1Z՜~T>q>>syAC;v}~ Kj._C_dKIW++?+2ka[ lӬmOTF)?F1by9(;S)ߦ.^B}N}ssN)9vv999ZS7`! 5@+(OOy4 ?{"{רA<[@)[~r;`K9`r3xSCw-Wtgo ߭Yd9@;n~Kiס(P8Fr;(@Q3֜|E i=oo&z.p>fkה|-b0ޒ?ns`@;sK>⹂=/O`T TaYњ{As?5 =叠98X ~Q0  ^M[Yn\Qv++K4שĻ%x{K(AQ뙨ϩM_p^Tߴ|{3 8D?75&k ql#>>>[_W| w;_A%R.poysR~!y)_5G9p@9R 9.oTXZRxIQV6`C;/Q³qnfm344-@\}c\ ϮG&ކ9#^ d+_ԅ:ZPS3m͠U jb2\a ֦%{QӃha 9 kJ&P 7-cK_c|͔&% z=̗?7y)ײٙ|?!xB~A:G@ ߿_ucև-d}8=uE?Haq[?r9N6>>:::888666444222000...,,,***(((&&&$$$"""  q2r_`ZP|`x1P(XLH9tRNS:e@bKGDH cmPPJCmp0712HsIDATx^] {۶ls,qԭl-FeqrW-K ҇߷52y 7z;6`9\N~{.7Gw4MY1x`rp,:8Zs/;(g"?S@=vj`zaly]Z`1v7Lm[<0l͢,Nv;ڈw8pkc=)D|wxcTSOa^4saa0# V`\"}<%qmCD|xg֋|cɍ(1p&cL\B,M5[E f"E?O[mz?`][צĻ59nµbפĻ KC]&\/ /vMzNp4Ļ59nµbפĻ KC]&\/ /vMzNp4Ļ59nµx P[u߂CS0J[Shj<2!˛#m( oC0 !|#ޅ?-8EwRoىPݎH]q<=[Py);5p]H]ΊV]wWvyV7[Urz}<#0x߬0߻W @o]e|Z6<&kZR)ߔ!- -)ߔo7;Zږ8K?sa5; uLe .+A]仒e!`?p ϸ߿d:Ty ]mvly,|,<)l[1bxOϋǏΦ?_ZQh5j;ũp״]wt5"qՇaA`ak4]=mImTvSvYl9Wi6+w3!s8Ոw3ȬF͙^gj/^5-Y U;JaV4pMW#Guak4ae,Bo٤-"潳iB=)qx;c;kx;c;kx;c;kx;c;kx;c;kx;c;kx;c;kx;c;kx;c;kx;c;kx;cp/_ }x׽ g9XS/x l7$;~fB޲wH갞x ĉ&sou4xS)Ҧu(ߔ|3Tqg~#Rhǯ#|&F-@4хo78- }ݷAě[2tC r)7$_wr,Ky=?eisP>zuVXoi=&;Qϵkr87m`QKSmVkB39~B7=Rs!տ1c0ݓןyׯ?/%}li r} _Wrj|v1]{; ěx,aG|S) U'&PSSSg5ssrkm_hiiiiT~!k(X?%ȿPN֕㳵þyv{)zgJzmbxowҷ9&-H}:F`(M.ϯM|S)hTLk*V;MҪo7Db4;s?/l v\^ᅼB o WкY.K8 @Y{T-x/bMw^ij>>ppMMN9@y~`<]ivX65rJ5k7Ok[i>׼}p ִߴߴ6'zn,O O%oug@p^LƄgX/,(1m -*7?Q/!Ļ~J[XbHMKI51"Uss-ϩ " [RQߴߴߴSSWX ki̊| )'f٠|w뮀=ʒw/o0p!p8}p~~~wh=y,| ;n?6 >~w{w}.~pao\CQߓџe 6ߡV| ;`Xn«[K->-iIχSS[j叴ߍ&޵{T>픧>>>/b'mۛԿbz=gZ) %fdxԻgz@}(tV5obZLP)߹DM]]lKѱsy>9F-7o)gFgsEnM.,*韧poi\^ᅼ~[;I;mز 39r]ρ\5tRD*P߫iw;`= 8z d~o9w,hiMjowzYGmO>>>O9xX^oa›`<-Wk-̷{۶ ?_ 7p o<$Łܲ`a> G I9p|;oH}z&ppCm>yYo]%ަ)9y|P=C}N}nqv~9b|?9yE:N|oc 6CjϩϩMVS1q+J_l4:ȯ ^{n3ppxL[-`p' ^mp/x+i*1hGȲw@d}s{`w_PsӖZ`=6Lj<|hj7[@D<:m1}@55S_sY)ߔowʁ:ʊ5kašhiJ999vpc~Gx_ۏ6jXCq0o{09uk@kfX[D?V i Euz_Q}N+65]S=܄`QSPX@}N}W׶7;oږσ wiiƪx񘬗t014ceꡁLMM}ˁϱ+y=:5%|' Wi\BWND5<2[ouC9 ȱ[?nQCҶ`X~o=,ӳngQEMssp6>`8=K6^O}~oB:M55! O>o{s8C{\sO->ۓ1c{N OwPNc+c ?  ؗ Bܑl7 4ӐI/J}CJѵ-}c~]׵Mݾw8HH)O$@$0Fwrƣ1B0DJ-p~ . ҟלDfGEi&ZHk5;qqXYCe'>WzPXsY)NҴ'%?QHҬDU%u}mܮUQg5 ((yCqʖ+wX)üEa|OJCSg$T[j:;f^kㅕywfWN"?aDWR!ԕEyۗD 6ԃJQ[g`g[(үCʖ?AZe8a\govZaAuf=ڲe`r]U5gRr}GU5R֚S:,҂7e63$z> YTjI48`)Ey+'U'~̨s~a|~=TFsS $rm4G$@$ ~-!$@$oY@$@$NfIHxS; Nدw}%x37GIv"~S+ 6oIENDB`S%(    Bitmap Image Paint.Picture0Bitmap Image/ 0LDArialh<$ 0< 04"@ .  @n?" dd@  @@`` \3  Ob$hWM>tm/b$z(C O~qN6@/$b$1LX [clo- 0AA@3ʚ;ʚ;g4BdBdT 0ppp@ <4ddddqt 0@ 80___PPT10  /Cellular Automata & Nyquist: So Happy Together 00(Ann Lewis 12/05/02 &Cellular AutomataBA cellular automaton is a collection of cells on a grid. Each cell evolves according to a set of rules based on the states of adjacent (or nearby) cells. One-dimensional, "elementary cellular automata," are represented by a single row of cells/states, each can have value 0 or 1. For a graphical automaton, 0/1 corresponds to black pixel/white pixel. Two-dimensional: cells depend on at least four neighbors. These are capable of simulating a Turing machine for some configuration of about 200,000 cells (Gardner 1983, p.227). Translation: cellular automata are very powerful..CZ/Elementary Cellular AutomataThe simplest class of one-dimensional cellular automata. Elementary cellular automata have two possible values for each cell (0 or 1), and rules that depend only on parent and parent neighbor values. The evolution of an elementary cellular automaton can completely be described by a 2D table, where entry (i, j) corresponds to state j at generation i. Since there are 2*2*2 = 23 = 8 possible binary states for the three cells neighboring a given cell, there are a total of 28 = 256 elementary cellular automata.ZExample: One-DimensionalExample: One-Dimensional}Steven Wolfram enumerated all possible elementary cellular automata and he calls this particular rule set Rule 30 Rule 30 is of special interest because it is chaotic (Wolfram 2002, p.871). This rule is used as the random number generator used for large integers in Mathematica (Wolfram 2002, p.317). Rule 90 (next slide) is also of interest because it generates fractal patterns,~Z  h  h Example #2 'What does this have to do with Nyquist?(((#Ever wonder what fractal patterns would sound like in music? Using cellular automata is a very efficient way of generating interesting musical patterns, because you only need to keep track of two generations at any given time. So I decided to implement a cellular automata feature in Nyquist  Cellular Automata within Nyquist!!(Recall the one-dimensional array of states, each of which can be either 0 or 1. The musical analogy for this idea is: instead of a row of states, you have an array of sounds. If a state has a value of 1, this sound is  turned on , if 0 its  turned off. Also, assume you have chosen some method by which you can combine turned-on sounds.SS ExamplepHere is a very simple array of sounds In this musical cellular automata structure, we choose the combining function to be SUM, for the sake of simplicity. Now if states 2,3, and 6 are turned on, we would get the Nyquist sound (sum (osc 65) (osc 67) (osc 76)), which is just a simple chord. The evolution of this automaton would be a sequential progression of chords.qZqP t  ImplementationI have implemented a cellular automata package in Nyquist that allows you to use any one-dimensional automaton on any array of sounds, using any combining function on the activated sounds. Usage: (cell-aut <num iterations> <combining function> <sound list> <update rule>) Since automata are differentiated by their evolution, or row update rules, you can specify the automaton you want to use just by specifying the update rule. The update rule is simply a function that takes in 3 (t/nil) values, and returns t or nil. The three input values will be the values of the cell s dependencies, and the output is the current cell s value. |P|,2 Example Update Rule  (defun wolfram-rule-30 (arg1 arg2 arg3) (if (and (eq arg1 t) (eq arg2 t) (eq arg3 t)) nil) (if (and (eq arg1 t) (eq arg2 t) (eq arg3 nil)) nil) (if (and (eq arg1 t) (eq arg2 nil) (eq arg3 t)) nil) (if (and (eq arg1 t) (eq arg2 nil) (eq arg3 nil)) t) (if (and (eq arg1 nil) (eq arg2 t) (eq arg3 t)) t) (if (and (eq arg1 nil) (eq arg2 t) (eq arg3 nil)) t) (if (and (eq arg1 nil) (eq arg2 nil) (eq arg3 t)) t) (if (and (eq arg1 nil) (eq arg2 nil) (eq arg3 nil)) nil) )$(ZZ 3     "                4Example Update Rule, con tThe previous slide corresponds with this visual implementation The user can create their own update rules 88 of the possible 256 update rules are known to be fundamentally inequivalent (Wolfram 2002, p.57).   -Example Music Created Using Cellular Automata..(pThese examples are very simple The sound arrays are just arrays of oscillators The samples use Wolfram s fractal rule (90) and Wolfram s chaotic rule (30) Combine function is just SUM.  Future WorkI plan to explore more complicated examples, including cellular automata of harmonics, and cellular automata of cellular automata How much musical structure can a cellular automaton describe? Music that is pleasant to the human ear is sparse over the set of all possible tone combinations over a given range of tones; cellular automata currently does not have this property. Can it be added?Z  ` 33` Sf3f` 33g` f` www3PP` ZXdbmo` \ғ3y`Ӣ` 3f3ff` 3f3FKf` hk]wwwfܹ` ff>>\`Y{ff` R>&- {p_/̴>?" dd@,|?" dd@   " @ ` n?" dd@   @@``PR    @ ` ` p>> f(    6XQ  `}  T Click to edit Master title style! !  0{  `  RClick to edit Master text styles Second level Third level Fourth level Fifth level!     S  0z ^ `  >*  0d ^   @*  0 ^ `  @*H  0޽h ? 3380___PPT10.BYQ Default Design$  $(  r  S `>  r  S  `    H  0޽h ? 3380___PPT10.BtW$  0 $(   r  S x~ `}  ~ r  S ~ ` ~ H  0޽h ? 3380___PPT10.Bs%$  @$(  r  S H{ `}   r  S  `  H  0޽h ? 3380___PPT10.BrZ  PZ(  r  S  `}     hA rimg3393  H  0޽h ? 3380___PPT10.B@u  D<p(  r  S 5 `}     hA rimg3393P  r  S p `  H  0޽h ? 3380___PPT10.B1Z  ,Z(  ,r , S  `}    , hA rimg3397  H , 0޽h ? 3380___PPT10.C0V9$  4$(  4r 4 S T `}   r 4 S Ȇ `  H 4 0޽h ? 3380___PPT10.C6VN$  8$(  8r 8 S  `}   r 8 S (C `  H 8 0޽h ? 3380___PPT10.C@[  <(  <r < S G `}  G x < c $ Gp ` G | <0 0A  `{  GH < 0޽h ? 3380___PPT10.C$   H$(  Hr H S G `}  G r H S G ` G H H 0޽h ? 3380___PPT10.DW$  0L$(  Lr L S  G `}  G r L S $G ` G H L 0޽h ? 3380___PPT10.DW  JB@P(  Pr P S G `}  G x P c $Gp ` G  P hA rimg3393  8  GH P 0޽h ? 3380___PPT10.DI$  `X$(  Xr X S G `}  G r X S hyG ` G H X 0޽h ? 3380___PPT10.E-$  p\$(  \r \ S - `}   r \ S  `  H \ 0޽h ? 3380___PPT10.E >})xYKE>wa|"8(> `2 • 5ND@AM\'rO_`&_;}S5]՜oeSOަE]t[ml.T'J)=*AQ-Bޣ+YWf+>t|.1c\?6Jae 2n|_GzO14_/<}L}=0AӽտUIh6#<k+|udij:.9jx}߿ֺu\gR1;% &;  #]DH?#'OOOOπςρ( __/'77HOki xVAUXa}>'Ύ/l5{uxBH䯾+.ѭU~cN6NmWחk?_{D{T'MߢsoΎFZ\7]>}a>%'~[|`#mնD!k;uMwdN}}"S H2 Z ʀk@ (ү &-L}PzaBM*[Ke€1Hㅚ*T~'R[c 5Ulۯmr=#"QUȶ;C"S|m(4dXLSggVePEȔs˭ eƩcT[HRξ1BjS}- - d#*V-EE4ʵ_;>ʆV{Hws736ױL\/qtYIM ӯg*;կ}կ2h! drAeem昚7&q 806⺬D|V͗Tg"_覶sE V؉>=˪-9ؑ_|M9jӯUm06B,{QV|Mٳ`T[x1ek/K쀐\_X^?٘JȰ_s@c}7`XD:xzD/`;W]I߯ózS}yBZO5zwskTҍh*IV/([\Ceo^LP_D7E7#l66 EW$՗)eZk^3%g(?s32UZ/ ؚ4^Be+y,^5;iPSVүDYj0`kv x @ DrH[%/31_357:+=W?AO9DeFHsKM  TOh+'0P `h  /Cellular Automata & Nyquist: perfect together eallewisallewis67eMicrosoft PowerPointyqu@X\@@B@3ySG0g  %  x-- @ !x--'@"Arial-. %2 :Cellular Automata &    ."SystemH-@"Arial-. 2 LNyquist2 .-@"Arial-.  2 : .-@"Arial-. 2 { So Happy .-@"Arial-. 2 Together  .-@"Arial-. 2 Ann Lewis   .-@"Arial-. 2 12/05/02   .-՜.+,0    $ On-screen ShowCarnegie Mellon Universityx> ArialDefault Design Bitmap Image0Cellular Automata & Nyquist: So Happy Together Cellular AutomataElementary Cellular AutomataExample: One-DimensionalExample: One-Dimensional Example #2(What does this have to do with Nyquist?!Cellular Automata within NyquistExampleImplementationExample Update Rule Example Update Rule, cont.Example Music Created Using Cellular Automata Future Work  Fonts UsedDesign TemplateEmbedded OLE Servers Slide Titles_LU~allewisallewis  !"#$%&'()*+,-./0123456789:;<=>?@ABCEFGHIJKMNOPQRSUVWXYZ[^Root EntrydO)Pictures1Current UserTSummaryInformation(DPowerPoint Document(pUDocumentSummaryInformation8LRoot EntrydO)@#4kjbPictures1Current UserYSummaryInformation(D  !"#$%&'()*+,-./0123456789:;<=>?@ABCEFGHIJKMNOPQRS^+_LURoger B. DannenbergRoger B. Dannenbergnyquist-3.05/demos/allewis/cellularautomata.htm0000644000175000000620000001103410144436365021010 0ustar stevestaffCellular Automata

    Cellular Automata Example

    Ann Lewis and Roger B. Dannenberg

    This example is based on a class project by Ann Lewis.This project harnesses the power of cellular automata for algorithmic composition. Cellular automata have been applied to graphics and visual patterns as well as music. In this work, the automaton consists of an array of boxes, where each box is initialized to either black or white (on/off, 0/1). At every step the next row/generation (represented visually as below the previous array) is computed from the first array using an update rule on each array element. An update rule (that defines the automaton itself) is simply a function from the array element's parent, and the parent's left and right neighbors. This concept is illustrated here:

    	A1 A2 A3 ... 
    	B1 B2 B3 ... 

    Let B2 be the element whose value is being computed. B2 is therefore dependent on the values of A1, A2, and A3 only. An example of an update rule would be:

    if A1 = A3 and A2 = 1 then B2 = 1, else B2 = 0

    There are 2 possible values for each of A1, A2, and A3 which means there are 2^3 = 8 possible configurations. And there are 2^8 = 256 possible functions from A1, A2, and A3 to B2. Therefore there are only 256 possible update rules. Note that the number of possible update rules is not dependent on the number of elements in the array. The rules can be numbered from 0 to 255. In the picture below, rule 30 is used to generate a series of rows, starting with a single "one" in the first row.

    Instead of B1 = 1 indicating that a box be colored black and B1 = 0 indicated that a box be colored white, in the music model this will correspond to turning certain sound objects on and off. For example, here we have an array of oscillators.

    Osc 60 Osc 65 Osc 67 Osc 70 Osc 75 Osc 76 Osc 79

    If only the 1st and 3rd elements are "turned on" this would result in the chord (sum (Osc 60) (Osc 67)). So each array, or level of the automata would correspond to a chord, and the chord progression would change over time as the automata developed.

    This feature very versatile, so the user can specify the basic sound array, the duration of each step, and which combining function to bring the activated sounds together. This design allows the user to use any expression to create sounds.

    The main function, cell-aut, takes the following parameters:

    1. an array of sound objects, specified using expressions to be evaluated
    2. the duration of each time step (also the duration for computing sound objects)
    3. the update rule to use on array evolution, specified by number (0 - 255)
    4. the number of iterations/generations the automata should allow itself to grow

    Some interesting rules to try are Wolram's two most famous rules: 30 (chaotic) and 90 (fractal patterns).

    Algorithm Outline

    Here is an outline of the algorithm implemented in cell-aut.lsp.

    1. create and initialize "current" and "previous" bit lists -- these should have the same length as the sound array the user gave this function) -- potentially there could be a feature here allowing the user to specify the initial state of the array.
    2. create and initialize the list of sounds to return
    3. loop iter times
      1. get the list of currently activated sounds from the "previous" bit list and extract the corresponding sounds from the sound array
      2. combine this set of sounds with the combining function (specified by the user), and add the resulting sound to the output list
      3. compute the "current" bit list from the "previous" bit list using the update rule iterated over all the elements -- this wraps around so that endpoints are treated as being adjacent to each other
      4. set the "previous" bit array to the "current" bit array
      5. (end loop)
    4. return the output list of sounds

    Demo

    The file demos/allewis/cell_aut.lsp includes the function cell-aut-demo defined as follows:

    (defun cell-aut-demo () 
      (play (scale 0.5 (cell-aut (cell-aut-major-scale) 0.2 30 80))))

    so you can run this to hear an example output from the cell-aut function.

     

    nyquist-3.05/demos/allewis/rule30.jpg0000644000175000000620000011475310144436365016567 0ustar stevestaffJFIFHHSoftware: Microsoft OfficeC    $.' ",#(7),01444'9=82<.342 i !1U"456AQRTabqst#$237BSrCDVe%Fu&c'8GHdfE(?пѿҿӿԿտֿ׿пѿҿӿԿs3.9G mkH̽|ױg) qQx :1SV̳jRxWQ$?տ_XyS8^dh(M:d7sdz b-"UTr[:3u{I/9\RsXLrOqs=ͻ*5x"2\c7cFԠz~zKs,.dfV3"Q ?69e y(5(Fȕi-{.22.bxO.ShUSXyCˌ 2qFd ҫe&:x ?R09CyxȒzͳ;L;Bc%cޢ-Zdҝm\r,zRD#IY赅=/ޫԣ)NB Ȉ̩f\@ڥ1߉V&ЯtA*[DV\X;/( oѼuFvmҲ"ܓ^aܦ_FkWK333U}[-1xI1TrDДfmfI)k5#Z:Rq$Iji2G5WFf:TC9U"eYs ]\LȎ{-AjkKHI*Qfěc3#0Zy;<ݜ}g*;Ԉ8hDec4miJM#{-\o_ ^[WS*u,[;DZ Gkb:aytǕ&TE1|UjH՞M)ѷV#.;/( oѼuFvmҲ"ܓ^aܦ_FkWK333U}[-1xI1TrDДfmfI)k5#Z:Rq$Iji2G5WF9pp.r93Y3h723$IY&fgDv#;~̹GJce"M^JU̸2[>*ա1M)e7"ǥ)J8I2;䕞Xj_o:ѿrLe썲5/ŵ\6gWlo_.'?2*;hkMJZ|tt^1Rlꑜl;cq:HF{W+\]gSKSd3̒MK2$2VofgeMl\q5^y"#UdDD[DEs3dcx8n%a '5,{W<֦HdITIIk^*.C,PjSV344IQ(Kњg4͸eaZCU:z5HuVّ/S *###If:-mAI)+IAxlATߌۓ!!FuZMsT$vmˋ Ji!7O8Ts ˚>!~P8z(Uܥ0K#]JG|2!4n [ iA)j$P)-asI ZRޡ"C#%6$Zmk:6" KL`vCƚEKBK\fzLf4a1< 86: )F$"J>ǐIęD¸F WZJqy(t 2I| JF4uRTP(֏rdI+,W3-G|S[E>O0T_H?O+[-$5C5E{pȮySiIHr#J3eS# HKMD-Ig))6$gdF38RqƇ4fzLf(Xf7ɡi,҄HԨFifcc;l6S)kd-%[Dids=:-1c> mA!ۨRX N2A4%Km,\[6Mis_g}k_ECC8T̋jUgs331F21.M 4H5f$FB5(sMFfg33_}SU Lg=Ouhr+ gHw7"#В+$p\M)fۍrN%,g|ݢes a`*Kizш) Y惲Ss#;ea=|%61z b% "+׷D"V5` Q2& qW4Qu(I4ger+]`gQF'/1oorU} 6׹ _'VccSTV7%KQ8vb4k=$ĕi]ؕ:lV Zk8msH)oCméQyHFy=XBfYrYHhØkR*AHsSiVg!jc3+qVrwkYd8Ẍ;^ֺ\lU$ NCGRYKmңjU&_w?UtX eE*_լNpEPPkM%. 唒JZv5`2 )-ˈkҢլiRL'W#-ef,:6@U"uK2Ɩg:6J###4)ڵt܌ZOd⏇1SC9sZAQqYI#-$VVhtCN\ &U1_4̌{iU좱uHuKԖ٥gK9;֓3癋")Zm q"y3QGjRGW3=ED N(@-&s:TЛW@[VWu`iSRJrh624m$w+I> S PAMJIIˊ-M(;ݴY`CCnDam Z fA\MǔfiuGR!*FJcJY9bMfFK(mN(I$DWskuQ2≒g"u7R[eh&թn'8&g26fTwciuq$&V22=FZ,+:@U^&u7>`j333$*۵dXl3'8sjFqRFc$/=է8ױKkBHl\MǔfiuGR!*FJcJY9CҮxBU* jTJH\QjiAEmZ̃2pDb$V hMW33#WY8XlSS֋Bo{%]m[&1Nn,%jҲm<#"P8b-󖥝̈mG'|k 9cjzhMo|䫠-sF4c??vz5ԶsDp܇>#l_lBdet|.cVjbBMh5Jӷo׷ `rbjZikq$F;Fgb+Y8XlSS֋Bo{%]m[7Qx3OѨNt-F)Zܸ^biQmT#IAmJY 9HԴh[kIJ=Rfj="-!qGG\?F:nwhNb\W-퓈Uv2#q]mV HI"-)Zv aZqht!6h#5c3,ԫggkش|u>P5Iα5=h&rUչps;d=[YO YX֜ul<eJ+Et\4x<8*$yڬ{r2hBUoA;@$!☮ΧNZ[eDI&ӲMH4ȍ%ki3P5Iα5=h&rUչpпW2ɗK솿ԿԳ33^M`ѿҿ1 hvNz9+ӽ9Q!˺!G>a*m*y7~,E9VSʌsSdSbyúl_eP ֚2;MMg,L)&h"= y$`/b×) l2F#(qԪ6_D5ŒUvoM-[buluĶGb/+wCKU;ZW]ImC3-+T}!2UzE#Rƣeo:3lb\S&gQcYS8ֿ׿PWWn9ʹl3Pgs"mNM.*KˈFFc!.ªIƄS%R3%b{h-C*KӶ> "i-Hece4R ,<Ӟ$$'l3g s ~3qm(/ hx534Pgo?jvZykBs#2!;1#;Hi5AX]B@пѿҿӿDBJ|[BVzH{iPˆRZϒp[YCKqk>H{)n-g|8e-Ŭ! $=ᔷ䇾> K~#tŸ`nZJo7c~Kqk>H{)n-g|8e-Ŭ! $=ᔷ䇾2|ÆRZϒF2aX9 $kCᔷ䇾2|ÆRZϒp[YCKqk>H{)n-g|8e-Ŭ!t(ʞ%J6Nhw$؏oC#RZϒp[YCKqk>H{)n-g|Ըe-Ŭ! $=ᔷ䇾>8bRյ=hw̽~Kqk>H{)n-g|8e-Ŭ! $=ᔷ䇾2|ÆRZϒH{)n-g|8e-Ŭ! $=H{)n-g|8e-Ŭ!u(Ȝ%R!Ѝhw2-2|ÆRZϒp[YCKqk>H{)n-g|8e-Ŭ! $=PD%BաKAc0Ek﷤տ$[ݡ )ybk",7mJu&jF{F5l^)wV݈igTݨ뎒$D5l^)wv!kîHZ댤O74r{zF+|Y"5WUI&D~}mԞ^q'j+<傻qԈaBNW2xi]f a;Rj$%;RmJI؍ "+iszF+|X=!p59 %֍I`#J[BA1 Cѿ^E1͜Ħ_륙R4T/wF1i(՞c*Y`N6#pԙϰcF➑x .,z<9Z$^lcp堭u$۬1F4LcC :s %*9DKKz GezF+|X$}cV**QxMMnQT'e.UZu:4Gr9:fLf\ zF+|ZXmMn9#SdV 1F"X()Z sVV$l7}awz7?Ae,A KfK//MӜwF>_}v3͇V#2ȗT58]awz7?A\)828s9&ٸ }Qƃ=#N6*v[q W$~Zm$2Y*֐}xiŁ\q!+M1I#3IsOcu-߼H͘ZMypOb+HdyS3?8awz7?A^(DQ!pRZ64%mMϞ+l^)wd)؇R\C&"2QQsw=Y)%cbR]5bfF#+qϔxc)ꬬC" )Ei:ySQK#oCް;3l[Zfӷq11F5 ?ʄ춾B'q'1P_!_Ⱥ;:z#pnw< _K2rYxC2al_3I7w._ Gʄ~"I[$w2|&gӳL :܄ZGMEr>oT}|Aw%e~sw MDǍn,ct:=+j&QѤ]]j-Eնj'A:wpvc"h瘶&OQMJ<3ݐm*Iqb9!߾lfˣGg\i ,DddQc7i[D-Qw5'󐓛H\c:MgW#+ؚ?|kJ4J=jI'TO8\I%)AXVc-c=TjE=bydfw+ۼ6Mn,TWu%T^4Ϛ>sn&Կ$[ݡ tw M4!鼟RyyĝC3&=?*oHQ=@Fx8&,>\*GP(m (N n7}g9kzh[ĿdEpJr"u ϙBP$m@)> Viү1lߘ]s7C|؀R\R;j/NLbgPjOq=!DR|bG.&BN库ֿ$[jݡ BQL;VK;ˣBn>Ԛ|Ȳ%ɝ%i&QĠ r$Pu:gSDkM!#(PۡJ7?ZM>lYS%ORL$\ ^X6?x׹S*'Y::\fahœ+2& W KΏR:|;!$ɶI$.V;-P@hDɼ| dOv&5f n`hֺv)O2}'&ŏ9e)ԸjZ 9+s[įde'r!EpFVN>%;{N#ȏ=zgNnmݑդAw6vPp |N E(${ӷ~ONwx>DǞti3A'6݁\G66 P ELwbRJ[OdW~ֺv)N_'?쳖h$晟37jOq=!кjɲK MhJdr=Cn+"S*g[jQiBaHJI}&BN嶓"'\̀fsZl\~ܦ>?nSnp)|8O۔۾'c1 {rwǒq+Rʑg(vڸѹ8O۔۾'c1 {rwÄ=L}~ܦ>?nSnX/eHK2s!=L}~ܦ>?nSnp)|8O۔۾'c1<&aYb#gXc# {rwÄ=L}~ܦ>?nSnp)|8O۔۾'cxKÚ훝cO۔۾'c1 {rwÄ=L}~ܦ>?nSnf7 {<īO۔۾'c1 {rwÄ=L}~ܦ>?nSnf ͈Ecҹ8O۔۾'c1 {rwÄ=L}~ܦ>?nSnx/gHk"*rO۔۾'c1 {rwÄ=L}~ܦ>?nSnɁ4"xӛnpӿyNo )y-3,K#ӚgbXlX`ՖT⤭ҨWZUͽA^, ^A12MΨOj47ThRTLV-%bS9*۝$_l[-c:Eyb"NVxl?ԿoIK0b_ZIQe koedAqi[$S9] )KbDFg%TH4 dFMտ,\6iM>V 4556 gL,2ƼJTut2NN\՝׵lBbSjO*% DI8YwӤM q8ZBq5Qĥ3a)D{Zo};cֿ H$UT\\A<ʐbVjt"E{G~**i:Z!hQ r~6]Ɛi2hBjO3;gqX~ # "RծD7Tk~I=(#׿пѿҿӿԿC*Umv3Mm&҃K#qBC鱓7jgר0UlԽMQW)%uLfdڙ5 )1 U`Mj^c~$uFnLݩ^Ý(Ej]9C3c&nPbˉ=$֦{6VLݩ^¨ǨET2n/ݤ] ݌S<ATP n/;Ui[h)iIq͌S<AVPI%ԽQIm_3vx z6$ԼRDgؐg? UZңmm_Nf#&395EX3ӪLF~ר=?OwUJL}AC*Cy͵k;3vx z :ėkRG{6ٗ@3v2fL65B[-ԻCki+2/!7jgר0FIvrWZfdimmf͌S<A^}*Lb6gPddڙ5 3*9G?J 㥤,XȌ/Lݩ^ {5/Sگŵ{[3vx z #j^n^|θfLݩ^ո=0Uyms S<A&=AɭKTλm_"27c&nPa΍P".vQ!7jgר0QaM֥rl[JQq͌S<A6HLW;3vx z|hN:Լmit!4ن=AVPI%ԽQIm_3vx z2 yyʹklC91]j^s%Gf2@>3vx z6Kzf"2MH3٩ ksm֥*ms ˠ;3vx z :̇kRם{6tA7jgר0鱪}NVl[IQ|q ͌S<@ sR$A$B֔$Ęֿk\JF}7_-,+萔^;_$Gax|*gw7PFt1b3r?NDM Lz.'iGC#y?Yy\fkWcѹOf/r'a^ACI(IGU{L׼`̾gPkעB'_1vYĠ;?lI<_ĀOaDq+ $escxBL`8\3 co~C1Eҡ'>EL L);ґ"ūcȶ[1" c~bPFPWv?$e'jv&пLwֲg>[R֕gF-[VKek;Nfzz%+ϑ0UaQQKzұZJU39z=z#+ϑ0E/Ud?? iXf|eb-XNΪ2w/zm =iXf|mn-Y45U2ѭ?ާZұZhMUFTHZIkJ31jQ*Jje.:>%\Lj(kNulJ@gUdSViѸDUVH2SLJEzVLS zDJ`jvZk.fJ3#0ZQMFR+F>IJ3#hjFmQ-vQ]p֕gFՍmQÿ61p֕gR*c tR (sT[W߶'t;ū|hXKԚi2A$ɞ%$E9?n7) O~=-nKՒj22.,.q7ZV7Y#aVV*cuVLӮ.e%_1?#j@j2*kK_a#+ϑ0ƨī2YU-Ew-i֟\sD2Eŭ:Nn>G:t&)N WW;G JLJ2Eh֝qһ5cuO~-YT8Ɗ)OZ_\$cu?hc'6{ӛ}p֕g|(y %00̹,һM$#K=禁&"rJz$%eW=51Q}>qӿ]kS;2r0HĘĪr"oh_c7q;J='+?)=7Z*s7xs; JHBLFR8ݧhcr35`<!^s@\SCvĘɈ]HܟHJʷRbLFW8/v1$ Sc8Լk{}"Gb.Wg >`ũ*gh_aLT>ЏDW0FaW`v>-]t~Eޑ9#2һ1&#)it%l|}#╶v=F4$I,5גW.w`c٨l$ IE4 f}2QO: [IE]Px%#h8-%v/WPIj5G[ŒřcgY1 7 .gvC0;/2!v1yĥ9^D]Q-d=NTE[R!Fkn5ڌg]Ia SM;:ҷzgH9# 5أ5$pivњ0r`w7,n]0ϰj2d֧*Q{=K.j2mQy(k -F(KxF֚Q^J8_H]A%:e o 5#mꅤGM?Qt<5j;6Ge3C1>F|J-j2-I̼[P_.Mfp%K.j2nfyj)$CSWQ43yMW2A|# f}2Q:kIE]Px%#hO8m%x/>j2=KBuDkEX׿k\JF}7_-,+萔^;_$Gax|*gw7PFt1b3r?NDM Lz.'iGC#y?Yy\fkWcѹOf/r'a^ACI(I84qE_nȜTKc%95DuBW-U^/HtɈ]HܟHJʷRbLFW8/v1$ Sc8`9D3i\*|STпD™Ȩ} `ü).|Z0g#/r7zF%ewcxbLFRx݇h`?ѿȚK#Y~k;Uh~-ͫ(N[L\F ~^l[==xk}9ɗɍVvvyps^u[^$N@e:g]RAh׉FӐ<~5Z"^dOqr/9pOߨnĞ[L\GVڬqĝe_JHUm}P'g˂iԎQG-FӐ<~ũZة j +>~ڭll\ِm׌qu֫zEA\?ҹ 5Zڙ~,w[֏^df+eǤ5ZX uvet%׌JӐ<~VN2\MkQĞ[L\QlU0zEظ4ǒnI3Y OlWpjN*'4܈˲J6Э I<] /q*VoR63!Z G-r0fX RuwmԒb3lWpj!jLzaQb Ӟ풪? [DP_ɗJ=7;H.B ݀q&lHMSjjK=oUw` U򅈎:bCqZ5T!h5d֫;9K9zǭЗ^$N@e:g\A㲵+oS_^$uN@e:g[Ιŭ[y׉FӐ<~©Z _8Vr/Uf[t6v+.eb}h_0+VJ;>\NFQ|HU5EKΙڊhO sU2 ZЗ^2u*N@e:ds%$)ezڭj Y~ĤZsfA]ӻ5*N@e3Y:lpIqԿ]kS;2r0HĘĪr"oh_c7q;J='+?)=7Z*s7xs; J(GF!}#DwSqiPkעBE|C}=~ r:r?x;މ AVWvݬIE>q>ygռk{}"Gb.Wg >`ũ*gh_aLT>ЏDW0FaW`v>-]t~Eޑ9#2һ1&#)TGV[bm]D}w)9~اG{<"K>Tbԗ\ةSu/>~\عSy|Gk bmMWe氏:ڙ~|=]sZv)Wb۵]]hϮ;/r5]-"-Mh{B{W!핍<-Ibj+ؚVԔL}OwnqvoPnߠxoQ׉i. eF4D+n#&Kj"L)c"3'fe# ]ݪwy~VCX?;RճZSF;4琵v,޷SG׎J)ժ6RMZnw!-핍<-3r?qb@3u7;sŝ] w_#jk^s벵^ަIg~Z6{;by{y։,SrQS]s[S~|Fn}w)9~«.1N"FZ]OSD}}u?7QU,SrQQ]sc%1N'օ9u͌:ڊ-wЗZ2ANDmu?7QMpmJJ{kq[o/>f~>bZ/>I~2ZNc;~y{y։,SrQ溡KIw^ɥ2!0пk\JF}7_-,+萔^;_$Gax|*gw7PFt1b3r?NDM Lz.'iGC#y?Yy\fkWcѹOfÅG-UNsb$z^vyo},Ѽ`̾gPkעB'_1vYĠ;?lI/SN_9[(En:wa}Ęq^cI#뗘pr-f#!]T$ȩ~3PB=\y]R$\v azF3^ oJJĘW$ҿgְM5-~'xG.mSFUY;Y }Vbٓj\IzŮ.m/*NM^u V}'Ik }Vb )jKȬm7_U;66SLA쮠m/*Nͪ*DA$vt*zC_U;:6 ] hz:>#ی^TRU:TUtq'R"O8lکGG"-MW=tw`ӸͪTr2ܙc i#ی^TQU:dUtq' tکS"heǮ.m/*Nͪ&H%$M]'O$:ыkӼ1)SjMhG#.+NOD}AԺ[qʓ#hjF$R IGZIiDǓH%^[~Nyn1yRw quE>Ƣ;ޟ8տ]kS;2r0HĘĪr"oh_c7q;J='+?)>x隷0$vcN|a#2C]DJn2_ {_o~s_dpn 1Ƙo69}N~6CTD\E>q>ygּk{}"Gb.Wg >`ũ*gh_aLT>ЏDW0FaW`v>-]t~Eޑ9#2һ1&#)fP7*QS-&"Z*ϒP.c~]rN=7eZL$vYǨw5Frb'^&U}4̣I} u'ezy\GP*"%H2$M>m|qI>cE[DD}xgo~(qTv&#Ğ?~ULy?=F}xgo* }uGˌ>!gfB`ѿk\JF}7_-,+萔^;_$Gax|*gw7PFt1b3r?NDM Lz.'iGC#pd9w럜xO.sWyyAw"#(|i# 1aX}?8MNŦ#)B>LFD劥XֳABLq<͎z/.s?I=萔gɧ9Ln&NA5N6G/1X[߫GŧB;r?I-OS;B g"z$23Hjã-g9߭>6ݏ1I㚯vݠIӿ+N>%fv[+dYW3*Rxz3:-_HJf#&TVuY)%d3!'k ^,uNJĎɯ%xX^͡k ^,eb*)%i'k ^,mrkE>gԉ-_Hf#qEjX/r= -_HJf1*E"i"ᙚGcG\&\DJTZz Yw}˔j[jI{{f]ԠQ-[JQwǔ"휏y)FsO$BTI˛1[72wſrÄGHM/DAlJ{=^T̸ ec=Ho~x%*HN̩IJ#-$HM}!+ŘQYb ZYc}q%k ^,Ɵ2E8ke*2_ioT/N{9/W*eёEyOFg-LTB1`E*eaesmk!v{=^Rr߂@r65LќDEx%*_H}$:dT"2='!C "P1.=JLXRSd]Ѿx%*dUQe-I-W=<ɯ%x5)xK?:SO%m`W+VZQ{ɯ%xΗ, uIeKZQ6} _HJf#pEi X?qNk [G3tz)xK/:ջʦb3TVb2Om#1'k ^,m'2G[&|(nm|Jh5Yw#>HF/{MLE傕^HJʯ{kcz|ֿ]kS;2r0HĘrRW}"ƯC+g!&8[rT<"G`\ܠJ)茉K&9ςSTN_(G9}.}_C=#l<&)4Oj׼k{}"Gb.Wg 1STпD™Ȩ} y]R$\v azF3^ oJ'JĘW$пu%zKŹ}o]K]ce{Q5 ? =Q#^#llmDRCI%[7?Gԫҩg"͕},mCf5ԼG)"T'~df溗1WgQ+LAcoBKf5ԼGc>E"vNDkxxxn* 6-lhIٞӁ[%S,X*U"lvqB 0ȇ(-G&|uwC I)'bGGF8ljҳSZ ]LcJTLѡ;7?q^$Njk"VyeFj_=?'8,⼛mehwO.9-ἕgTQh-b>8{%?һž<%8jQtAo^ĸzWxūMMɥU -uDڊsRScNo31MnRz4_C;٧nc-t0ʒZj/JbI.GB\[Nz֜ڹb\s=+[ѬnPy˽3~ĸzWxq߀V-6|K'w|~KqIr(ѠoF?}qo+f5D0%(Z mGbz%?һž%p Ę?Sr*-2 $dvzziۭc++x>ƳQ[RRhlyŠՐغƩAVcA}Cf5ԼGjg:-;R+֟T)՜dDeH Z]Q^#}ANcGgt(.1)UkE#_돪36o]KV5:$dmEVLu[7?GQFN= u;7?xTsRu>%樽0ҿk\JF}7_-,+萔^;_$Gax|*gw7PFt1c[ }H=7/᫲c?#$>Ҹ֯0ǣr $3 bZH쌐Q;R#qWO$Ӽ`̾gPkעBE|C}=~ up7UBJ<_ĀOaDq+ $escxBLiY[/CD‘Mr'`F.Wg >`ũ*gh_aLT>ЏDW0FaW`v>-]t~Eޑ9#2һ1&#)?."V"Ҷ%D{dg#sL/I&f$ْYywf =BԙEPCRib Ayb_g%wE06|'Uڌu7*{h2_dC{ÛV]MJnLce=dدsAգgS奵-L2LdC'Q;TU-j 7Zھ+~N<{˅1iH' FdW-6 3PR4K6ңY0i+sHNl?2mv)j%HIބ'Gڥv̕#F~w։-R O)x U2{W.i3|yx&Cm!KYf /< k(F]dxخHF/{MLE+萔S'&0*&z>ޟ8׿]kS{2Ҳ[]I8zoFM;q;r=" #v~O|ԯ1 .s E|j#ӟ Ǒ{e!uC>L!<,YvQ {_o~sI7Wy].Q3Y|J c0בlsйxp߼tЋOaDq+ ${k9nM>EL L){"E:>[?xs1[1(#(m+b25^?@ѿ#pq,w%s5_pdG(0jԞ^k+ꅷ% tx+ԕWij*cJRT-I >hש*K2F"xEOZqRLBtÎo|jQ)6FXi$}*RM} Y$#bj=##ŘȅL\7҄Ri R r:kI!s~NIJ5ͥ8>L̍gg{c-TQ04FMv&2F9_-7)rފ^llw-^jkO2Q\c:Jf?v&2Tk+ᆏQa?^CTcvp#|0J7!FRQI*-+[Y$aoCB̧*usI܏&ӿcDGew#>J!.\d禁'bE^HJX#jZkV.q A|z|>!]ea:D~>xA-9hwJx}Fד?u'c,\X"طt> ji! w?lOwu4bh/GC&!]%"E-MZ hb_;1bÄ[A|HĥB2Eh.< Iع#i%VmfQ'0zr?N>שfRؒUOB]Q)0zr?NOt)~꟣_TIlS0*U9 "'s7͗nO^e FM'6/TGRg#=Fk""33#""w1)yKM[-L;ge難ǧ|bTR$ ͅ>MM6)B!22Փ.V*C3iD^qG֠i?8#CV5JJIE 27 $^1׽FNGxz|4У#菪%6FNGYU+|5?H}Q%0zr?Nã8_i9e$_*!,y8NNjڢ V݊t_dNvSѣ$*|JwddRPcXQN$Ob!ħxF).E)^]S[N%;µˬ(g%"C6R$q\РW>]kZƥuLy.O2ABҕ$FgU;" w`+D(QAtDHˉ> UϤW|~ś#Zrp%o<2]~d}qd∖"3:H Mp)Gfm$U;"-25Av|J~]A%TS9+LeN$MNAf{94UϤW|x33;t(0?TSYlتwHE)xzt(T|Ve=SB/N *<1-,$*|Jw%zCh)d$EhҿIڤʗJ25=wVyy}2a%(ygA( IFP*QHs3בze GVO tˡ1##">5XǑ Lt*!DmŮt^$EkZ7L5ܯ+ʵyIQ(i#4Ӽ2k'mJ"޼,d9P͵e'Q :ި>t^RN=pյysZ/LӺd̋ys~,d#&ʎuQАqa ]s&Cz D|WJVe2ZLCu^g!efTuƸҌD>i:;#Odɏ#儩oGА\tJϾY<#/Lᐌò1DbO^E|2Iq :ҷBI9h?ԿNNUhZ]"};1pbj_3@>6 RҋPE^u%5OGxUy~e=e8S۲v?z_M? yrK5ZyYNo:ۭtGğ0uҷ6'NiS@,ihR%_Gxkdd23V2 **"27FG!PԳΝOS.F T-,b|Y~qydywl'#qiz?'8ŧ׼4T媣8{ZuGū8|(#`ZxپoZC;TGFNFxnsb&1dw-C͏acX: Jrj5wATZz:4e9h*_O#OTGF%cf#vCcc͏bq2N*ޅѧ0$/ӴoP~=NpE)*3TGa3X=G換xny(rC5h-pZLvFң!eeՓ %D8+c E{8ӵŧU:_J5M掕3Q И8ŧHejS#Iz? 8űvZ Ј֞2o֏пuDti:EAF]MYGB2EUG? I}*<"ԃ%HL#v(!\n%2lFuDŹqṫ#E66&nYQM:NC viXv9Dt(l$fV-!ϛ1S ^9[u ZZ"3";ګzf*9JƚrXQ/9KI'GѹP_#oxhy`R)9<2KRFcKkNё\1lOt%xoҫTVvT&[v7U?6brej Фw.F\ūl%Uz(ȪE+|~^gcJ2=vVzU<%*A)ėP}%*d?O;8mV t.uDDDgTFWVq :rWsmG.O}f)G{fes k~m^ë~JIiM YZ k~mdE,81L4i;&4UjR)HW3'UvbrLJ}q%FxTvJi᤹عh k~m [ J}thS'hDMي?f*{++|~Zj%W-U?vbrIaD$3|cjtj#Q&i7)!6I-'ğ0C ~OҼU~;Q\bMmzDT$k+"[I~!;Mʭ&&YҴ42[GaȚҠRddI( Jzf[ky$22ѕll's! :<&ddtq'VZJg$h+Gy j!Zh$"tDꈋbr]N뫌FJ;3!l's!-򳩱")$Bw= c;Tie0$?ӿk\F}7Y MLR{^b=\adONs1עˇɄ؏9FA鿌OdyH1]TCAvy#2C[DJn2VT 1Yv+eFghk+Q1}15?Ptx&8 yf=D|S|ōߕ*kw1"2WcJ}w~j3ܛ0܆z&8BG>c;S&&O#(hһ1&#)ia Ӫ&Ds4iU?8wx+Drj'Wti#<ޝL|%A>2JLySkp̕!xB&zdi(K;! ZZF{C&34{\UYm5!i###퍗_K/L?LE"j:Q2e'NKQsWs.Ù;2Cuͩj2;J$LHQAs|bRo\4afg>yFg =˸V؆NeE-d$AcrYNV2|qOgT='c __>tD]QRiAL;h昘׿k\JF}7 o@;@>%>bOʄ>:`T~6oOg.&b?xadݭlEbLbU97/1ȸڕн>x隷0$vc<;cQCF5p\ܠJ)茉K&"g?L7y.^N\'74"r~{!(*O[(r&.o;?7r?I:!gw;.s|)ʕ#HK9jã-ѿc>\Կ87_c|9a2+_M^!j:U*eoA+Y[eUK6 ɽP}0S6F+bkhk$F7 OnBrƛ%HɶbvS)IdC3RUr!T{, ^U1U~_⹣Ҭq`ղkUߑfFw#L iٙFC*q: *-$ciY!JF.USW%9Cmg3C yZ-JiS'fv9KLz[U6)]h)kEm0$Q9AYTƬ-L_HARYeuFGXVm Л^8W:"iռ B%r%;5w3PD,`Կ7pIrGCR#ϲ<ۗ]~q8kV9`zGD墙(NDM Lz.'iGC#pd9w럜xO.sWyyAw"8))ja90`̾gPkעB'_1vs 0D|S|ѿ>ct7uvXq>yg _('uPퟎGdxHvLyG{e!ugɧy-0ֿ2m@ɫUjh6\$܏5k ꇵsVk~?Q32MAs6*BјjU˰h1\ۨw Db< SOԪ2" x#";5Ok ꇵs^PT='ϩyB}P`^P^{_W0EB}P`^P^E>),.Q- v2Ql\ۨw xv̭+UBiQY$z>Hm! $΂/Xr֪h jQGR33O?=+'gR3?B}Q~?QAW;$6N]Sld\ۨw h,JNMFk'eIpuzK9Fw3&9yAzojm*Qb"jJ Uw{'v׺QEy-ITHw= >'v ETj2%)$^"h$k ꍛ d#=Pi֓SkA͋u?odaʌCfN6j@_O/(/T=*u/(O k KꇵrG^c}Q~?Q\(ci~O?='3i:*{&e׫!V>uع;P3EyWZibCcMOWB #܊&Ƒ~?>.Gr:k ~Dw#_?`;ԯ GrG?;ԌPT~{_O/(OϩyB}P`^P^ KꇵrCR?ꇵrFp;Q.kmPUs"#b пѿҿӿԿտֿ׿пѿҿӿԿտֿ׿nyquist-3.05/demos/probability_distributions.htm0000644000175000000620000001303611466723256021325 0ustar stevestaff Probability Distributions

    Probability Distribution Generators

    Andreas Pfenning and Roger B. Dannenberg

    This page describes some uses of probability distribution functions that are defined in lib/distributions.lsp, so be sure to (load "distributions") before trying these examples. See the manual for more details.

    A probability distribution generator outputs a single number based the particular distribution and the input parameters. These functions were created to supplement the uniform random generator (real-random). There are two types of distributions: continuous and discrete. For either distribution, looking at the diagrams will show you the likely range of outputs. In a continuous distribution, the likelihood of returning a value between two points on the x-axis is equal to the area under the curve between those two points. Every continuous distribution has the property that the total area under the curve = 1. In a discrete distribution, only integers >= 0 are allowed as output. Each one of these numbers has a probability of being returned which is equal to the height of the bar in the diagram. For the user's convenience, many distributions have optional bounds that come in useful for certain applications.

    Example 1 Varying time with a continuous distribution generator

    One of the most common distributions found in algorithmic composition is known as the Poisson process. This consists of a sequence of notes or events separated by an amount of time determined by an exponential distribution. The resulting sequence of events has the following property: every point in time is equally likely to be that start of a note. Another property is that, the probability of an event happening in the next unit of time is completely independent of how long it has been since the previous event. These distributions are naturally occuring when events happen randomly without any coordination.

    The following is just one example how to use the exponential distribution. The first input parameter, .25, spreads the distribution out so that higher values are more likely. The second input is optional and is an upper bound on the output.

    (play (seqrep (i 20)
            (pluck c4 (* 0.5 (exponential-dist .25 2.0)))))
    

    Example 2 Varying pitch with a discrete distribution generator

    Discrete distribution generators are useful for changing pitch (to integer values). Constraining the output to a whole number means that every pitch is going to be in the chromatic scale. In the case of the binomial distribution, both parameters together determine the mean. One way to get feel for how the different parameters affect the distribution is to print values as you generate them. Distribution parameters may require some tweaking to produce a desired affect. In some cases, altering the parameters can yield unexpected and interesting sounds.

    (defun try-binomial ()
      (play (seqrep (i 20)
              (pluck (+ (binomial-dist 6 .5) c4) 0.1))))
    

    Example 3 Using granular synthesis with pitch distribution

    In granular synthesis, interesting sounds can be made by having a pitch vary according to some distribution other than the simple uniform distribution. In lib/dist-test.lsp, there is a a granular synthesis function that can take in any distribution (within the bounds of granular synthesis) and vary the pitch of the tone based on that distribution. To do this, you pass in a parameterless function as a parameter. Since most distribution functions take parameters, it is necessary to create a continuation as shown below using a lambda expression.

    (defun make-gamma (nu high)
      (lambda () (gamma-dist nu high)))
    

    Here, make-gamma takes two parameters and returns a function with no parameters. This no-parameter function remembers the values of nu and high and will call gamma-dist with these. For example, try

    (apply (make-gamma 2 5.0) nil)
    (The apply function applies a function to a list of arguments; in this case the list is nil, so there are no arguments.) This example just makes the function and uses it once, so there's not much point, but in the granular synthesis example, the function will be called many times. Unlike passing a number as a parameter, passing a function means that the granular synthesis function can call the function for every grain, resulting in a new value for each grain. (Be sure to load dist-test.lsp before running this example.)
    (defun try-pitch-dist ()
      (play (stretch 4 
              (simrep (i 4)
                (pitch-dist-granulate "demos/demo-snd.aiff" 0.04 0.0 0.02 0.001
                                      (make-gamma 2 5.0) 0 0)))))
    

    Example 4 Using granular synthesis with grain length distribution

    The length of grains can also be made to vary by a distribution passed in as a continuation. Here is an example.

    (defun make-gauss (xmu sigma low high)
      (lambda ()(gaussian-dist xmu sigma low high)))
    
    (defun try-len-dist ()
      (play (stretch 4
              (simrep (i 2)
    	    (len-dist-granulate "demos/demo-snd.aiff"
    	      (make-gauss 0.0 1.0 0.1 .5) 0.02 0.001 2.0 0 0)))))
    

    A Challenge

    Can you come up with a set of examples that clearly illustrates different distributions through sound? (I would love to add more examples here. -RBD) nyquist-3.05/demos/midi_tutorial.htm0000644000175000000620000002376411466723256016701 0ustar stevestaff Midi Tutorial

    Midi Tutorial

    Nyquist can read and write midi files. Midi files are read into and written from a special XLisp data type called a SEQ, which is short for "sequence". (This is not part of standard XLisp, but rather part of Nyquist.) Nyquist can examine the contents of a SEQ type, modify the SEQ by adding or deleting Midi notes and other messages. Finally, and perhaps most importantly, Nyquist can use the data in a SEQ type along with a sound behavior to generate sound. In other words, Nyquist can become a Midi synthesizer.

    The SEQ Type

    To create a SEQ data object:

    > (setf my-seq (seq-create))
    #<SEQ:0x7a6f60>
    > (type-of my-seq)
    SEQ
    >

    Reading a Midi File

    Once you have a sequence, you can read Midi data into it from a file. You do this in three steps. First, you open the file in binary mode (using open-binary, a Nyquist extension to XLisp). Then you read from the file. Finally, you (normally) close the file.

    (setf midi-file (open-binary "demo.mid"))
    (seq-read-smf my-seq midi-file)
    (close midi-file)

    Writing a Midi File

    A sequence can be written to a file. First you open the file as a binary output file; then you write it; then you close it.

    (setf midi-file (open-binary "copy.mid" :direction :output))
    (seq-write-smf my-seq midi-file t)
    (close midi-file)

    The result will not be a bit-for-bit copy of the original Midi file because the SEQ representation is not a complete representation of the Midi data. For example, the Midi file can contain headers and meta-data that is not captured by Nyquist. Nevertheless, the resulting Midi file should sound the same if you play it with a sequencer or Midi file player.

    Writing a Text Representation

    One very handy feature of the SEQ datatype is that it was originally developed for a text-based representation of files called the Adagio Score Language, or just "Adagio." You can write an Adagio file from a sequence by opening a text file and calling seq-write.

    (setf gio-file (open "copy.gio" :direction :output))
    (seq-write my-seq gio-file)
    (close gio-file)

    The basic format of the Adagio file is pretty intuitive, but you can find the full description in the CMU Midi Toolkit manual or in a chapter of the Nyquist manual, including the online version in HTML.

    Reading an Adagio File

    Because Adagio is text, you can easily edit them or compose your own Adagio file. You should be aware that Adagio supports numerical parameters, where pitch and duration are just numbers, and symbolic parameter, where a pitch might be Bf4 (for B-flat above middle-C) and a duration might be QT (for a quarter note triplet). Symbolic parameters are especially convenient for manual entry of data. Once you have an Adagio file, you can create a sequence from it in Nyquist:

    (setf seq-2 (seq-create))
    (setf gio-file (open "demo.gio"))
    (seq-read seq-2 gio-file)
    (close gio-file)

    Adding Notes to a SEQ Type

    Although not originally intended for this purpose, XLisp and Nyquist form a powerful language for generating Midi files. These can then be played using a Midi synthesizer or using Nyquist, as will be illustrated later.

    To add notes to a sequence, you call seq-insert-note as illustrated in this routine, called midinote. Since seq-insert-note requires integer parameters, with time in milliseconds, midinote performes some conversions and limiting to keep data in range:

    (defun midinote (seq time dur voice pitch vel)
      (setf time (round (* time 1000)))
      (setf dur (round (* dur 1000)))
      (setf pitch (round pitch))
      (setf vel (round vel))
      (seq-insert-note seq time 0 (1+ voice) pitch dur vel))

    Now, let's add some notes to a sequence:

    (defun test ()
      (setf *seq* (seq-create))
      (midinote *seq* 0.0 1.0 1 c4 100)
      (midinote *seq* 1.0 0.5 1 d4 100)
      (midinote *seq* 2.0 0.8 1 a4 100)
      (setf seqfile (open-binary "test.mid" :direction :output))
      (seq-write-smf *seq* seqfile)
      (close seqfile))

    A Larger Example

    This example illustrates the creation of random note onset times using the Poisson distribution. One way to generate this distribution, as seen here, is to create uniformly distributed random times, and then sort these. The function that creates times and then quantizes them to 24ths of a beat is shown here. The len parameter is the number of times, and the average-ioi parameter is the average inter-onset-interval, the average time interval between two adjacent times:

    ;; create list of random times and sort it
    ;; dur in ms.
    (defun poisson-gen (len average-ioi)
      (let ((dur (* len average-ioi)) poisson-list)
        (dotimes (i len)
    	     (push (* dur (random 10000) 0.0001) 
                       poisson-list))
        (setf poisson-list (sort poisson-list #'<))
        (display "initial list" poisson-list)
        ;; map list to 24ths:
        (setf poisson-list
              (quantize-times-to-24ths poisson-list)) ))

    We add a few functions to help express time in terms of beats:

    (defun set-tempo (tempo)
      (setf qtr (/ 60.0 tempo))
      (setf 8th (* qtr 0.5))
      (setf half (* qtr 2))
      (setf whole (* qtr 4))
      (setf 16th (* qtr 0.25)))
    
    (if (not (boundp 'qtr)) (set-tempo 100))
    
    (defun quantize-times-to-24ths (list)
      (mapcar #'quantize-time-to-24ths list))
    
    (defun quantize-time-to-24ths (time)
      (* (/ qtr 24.0)
         (round (* 24 (/ time qtr)))))

    Now, let's create Midi notes using Poisson-based onset times:

    (defun melody (seq onsets)
      (dolist (onset onsets)
        (midinote seq onset 16th 1 (+ 48 (random 24)) 100)))
    
    (defun poisson-melody ()
      (setf *seq* (seq-create))
      (melody *seq* (poisson-gen 50 8th)) ;; adds notes to *seq*
      (setf seqfile (open-binary "pois.mid" :direction :output))
      (seq-write-smf *seq* seqfile)
      (close seqfile))

    After evaluating (poisson-melody), you can play the file "pois.mid" to hear the result. The times are quantized to 24th notes at a tempo of 100, so you can even use a notation editor to display the result in common music notation.

    Synthesizing a Midi File

    To synthesize sound from a Midi file, use the seq-midi control construct. This behavior reads the data in the seq object and for each note, creates an instance of the behavior you provide. You will need an instrument, so let's define a simple FM instrument to play the notes of the Midi data:

    (defun fm-note (p)
      (mult (pwl 0.01 1 .5 1 1)
            (fmosc p
                   (mult (step-to-hz p)
                         (pwl 0.01 6 0.5 4 1)
                         (osc p)))))
    

    Now let's use fm-note to play the previously defined poisson-melody, which was saved in the variable *seq*:

    (play (seq-midi *seq* (note (chan pitch vel) (a-note pitch))))

    The seq-midi construct automatically uses time transformations to place notes at the proper time and to stretch them to the indicated duration. In addition, it sets the chan, pitch, and vel parameters according to the Midi data before invoking your behavior. In this simple example, we ignored chan and vel, but we used pitch to get the right pitch. You might write a more complicated behavior that uses chan to select different synthesis algorithms according to the Midi channel.

    The syntax for the seq-midi construct may be a little confusing. The symbol note appears to be a function call, but it is not. It is really there to say that the following parameter list and behavior expression apply to Midi notes. There can be other terms for other Midi messages, e.g.

    (seq-midi my-seq
       (note (chan pitch velocity) (my-note pitch velocity))
       (ctrl (chan control value) (...))
       (bend (chan value) (...))
       (touch (chan value) (...))
       (prgm (chan value) (setf (aref my-prgm chan) value))

    Examining SEQ Data

    In the lib folder of the standard Nyquist installation, there is a file called midishow.lsp. If you load this, you can call some functions that help you examine SEQ data. Try the following (after running poisson-melody above).

    (load "midishow")
    (midi-show *seq*)

    You will see a printout of the data inside the SEQ data object. Unlike Midi, which stores note-on and note-off messages separately, the SEQ structure saves notes as a single message that includes a duration. This is translated to and from Midi format when you write and read Midi files.

    You can also examine a Midi file by calling:

    (midi-show-file "demo.mid")

    This function can take an optional second argument specifying an opened text file if you want to write the data to a file rather than standard (console) output:

    (midi-show-file "demo.mid" (open "dump.txt" :direction :output))
    (gc)

    What is going on here? I did not save the opened file, but rather passed it directly to midi-show-file. Therefore, I did not have a value to pass to the close function. However, I know that files are closed by the garbage collector when there are no more references to them, so I simply called the garbage collector (gc) to run and close the file.



    nyquist-3.05/demos/warble_tutorial.htm0000644000175000000620000000530210144436365017211 0ustar stevestaff Warble Tutorial

    Warble Tutorial

    The warble function by Alex illustrates the use of AM and FM oscillators to create an "analog" electronic synthesizer sound.

    (defun warble (&optional (dur 1) (pch 60))
      (stretch dur 
        (sum (mult
               (env 0.017 0.1 0.004 1 0.7 0.8 1)
               (amosc pch (fmosc (hz-to-step 8) 
                                 (pwl 0 4 0.2 -4 0.56 9 0.7 0 1 -8 1))))
             (mult (stretch 0.96 (env 0.2 0.09 0.07 0.92 0.8 0.6 1))
                   (amosc pch (fmosc (* pch 1.414) 
                                     (pwl 0.2 80 0.5 4 0.9 1120 1 200 1)))))))

    This sound is the sum of two components. To find the two components, look for (mult ...). Each of these components is the product of an envelope and an AM oscillator. The first one modulates the AM oscillator with a low frequency (about 8 Hz) sinusoid produced by an FM oscillator. The modulator varies in frequency according to a piece-wise linear envelope.

    The second component is similar, but uses a much higher modulating frequency in the audio range, producing a ring-modulation effect. Another piece-wise linear envelope sweeps the modulator frequency by as much as 1120 Hz.

    Thicker Texture

    A thicker texture can be obtained by playing copies of warble together with slight parameter changes. Here is an example:

    (defun thicker ()
      (sim (scale 0.5 (at 0.00 (warble 8 48)))
           (scale 0.3 (at 0.05 (warble 8.05 47.9)))))


    Another FM Sound

    The following produces another analog-sounding FM texture:

    (defun mod (dur) 
      (stretch dur
        (mult (pwl 0 1000 .2 200 .5 8000 1 100 1)
    	  (fmosc c4 (pwl 0 1 .5 3.25 1 .74 1)))))
    
    (defun blurp (dur)
      (fmosc c3 (mult (osc 07 dur) (mod dur))))

    This example relies on a combination of AM and FM: the output is from an FM oscillator, but its modulator is formed by multiplying (AM) two oscillators. The first is low frequency (about 12 Hz), giving a warbling sound, and the second, generated by (mod dur), is another FM oscillator. It appears that the modulation generated by the piece-wise linear function is almost insignificant. You might try scaling the expression (pwl 0 1 .5 3.25 1 .74 1) in mod by varying amounts to see what happens.

    The original duration of blurp was 3.1 (seconds), but longer versions are interesting and reveal more detail.

    Yet Another Sound

    See Other Sounds Using Ring in Vinal Scratch Tutorial for another example.

    
    /body>
    
    nyquist-3.05/demos/examples.sal0000644000175000000620000003275711466723256015643 0ustar  stevestaff;; examples.lsp -- these are from the Nyquist Manual examples
    
    define function ex1()
      play osc(60)
    
    define function ex2()
      play 0.5 * osc(60)
    
    ; build-harmonic is already defined in nyquist.lsp
    ;
    ;(defun build-harmonic (n) (snd-sine 0 n tablesize 1))
    
    define function mkwave()
      begin
        set *table* = 0.5 * build-harmonic(1.0, 2048) +
                      0.25 * build-harmonic(2.0, 2048) +
                      0.125 * build-harmonic(3.0, 2048) +
                      0.0625 * build-harmonic(4.0, 2048)
        set *table* = list(*table*, hz-to-step(1.0), #t)
      end
    
    
    if ! boundp(quote(*mkwave*)) then
      begin
        exec mkwave()
        set *mkwave* = #t
      end
    
    
    define function my-note(pitch, dur)
      return osc(pitch, dur, *table*)
    
    
    define function ex3()
      play seq(my-note(c4, i), my-note(d4, i), my-note(f4, i), 
               my-note(g4, i), my-note(d4, q))
    
    
    define function env-note(p)
      return my-note(p, 1.0) *
             env(0.05, 0.1, 0.5, 1.0, 0.5, 0.4)
    
    
    define function ex4()
      play env-note(c4)
    
    
    define function ex5()
      play seq(seq(env-note(c4), env-note(d4)) ~ 0.25,
               seq(env-note(f4), env-note(g4)) ~ 0.5,
               env-note(c4))
    
    
    define function ex6()
      play seq(my-note(c4, q), my-note(d4, i))
    
    
    define function ex7()
      play 0.5 * sim(my-note(c4, q), my-note(d4, i))
    
    ;; previous versions could not get current-path to locate demo-snd.aiff...
    ;(format t "~%examples.lsp tries to load demo-snd.aiff from the~%")
    ;(format t "default sound file directory, which is stored in~%")
    ;(format t "the variable *default-sf-dir*. The current value is:~%")
    ;(format t "\"~A\". If you get an error immediately, you should~%"
    ;        *default-sf-dir*)
    ;(format t "either set *default-sf-dir* or copy demo-snd.aiff~%")
    ;(format t "where Nyquist will find it.~%")
    
    set a-snd = s-read(strcat(current-path(), "demo-snd.aiff"))
    
    
    define function ex8()
      play a-snd
    
    
    define function ex9()
      play seq(cue(a-snd), cue(a-snd))
    
    
    define function ex10()
      play sim(cue(a-snd) @ 0.0,
               cue(a-snd) @ 0.7,
               cue(a-snd) @ 1.0,
               cue(a-snd) @ 1.2)
    
    
    define function ex11()
      play sim(cue(a-snd),
               loud(6.0, cue(a-snd) @ 3))
    
    
    define function ex12()
      play loud(6.0, sim(cue(a-snd) @ 0.0,
                         cue(a-snd) @ 0.7))
    
    
    define function snds(dly)
      return sim(cue(a-snd) @ 0.0,
                 cue(a-snd) @ 0.7,
                 cue(a-snd) @ 1.0,
                 cue(a-snd) @ (1.2 + dly))
    
    
    define function ex13()
      play snds(0.1)
    
    
    define function ex14()
      play loud(0.25, snds(0.3) ~ 0.9)
    
    
    define function ex15()
      play sound-srate-abs(44100.0, osc(c4))
    
    
    define function tone-seq()
      return seqrep(i, 16,
                    osc-note(c4) ~ 0.25)
    
    
    define function pitch-rise()
      ; pitch-rise turns tone-seq into a chromatic scale 
      ; through transposition
      ; override sustain to avoid changing ramp duration
      return sustain-abs(1.0, 16 * ramp() ~ 4)
    
    
    define function chromatic-scale()
      return transpose(pitch-rise(), tone-seq())
    
    
    define function ex16()
      play chromatic-scale()
    
    
    define function ex17()
      play sustain((0.2 + ramp()) ~ 4,
                   chromatic-scale())
    
    
    define function warper()
      ; between 0 and 1, warper goes slow/fast/slow, then
      ; it adds extra 1-to-1 mapping from 1 to 2, which is
      ; just "padding" to avoid numerical problems near 1.0
      return pwl(0.25, .4, .75, .6, 1.0, 1.0, 2.0, 2.0, 2.0)
    
    
    define function warp4()
      ; stretch by 4 and scale by 4: now we're warping
      ; a 4 second sequence within a 4 second duration
      return 4 * warper() ~ 4
    
    
    define function ex18()
      play warp(warp4(), tone-seq())
    
    
    ; note: as explained in the manual, the following is NOT
    ; the solution to a fixed duration/variable tempo sequence:
    ;
    define function tone-seq-2 ()
      return seqrep(i, 16,
                    osc-note(c4) ~~ 0.25)
    
    
    define function ex19()
      play warp(warp4(), tone-seq-2())
    
    ; here is the proper solution (vs. ex19):
    ;
    define function tone-seq-3()
      return seqrep(i, 16,
                    set-logical-stop(osc-note(c4) ~~ 0.25, 0.25))
    
    
    define function ex20()
      play warp(warp4(), tone-seq-3())
    
    
    define function ex21()
      play warp(warp4(),
                transpose(pitch-rise(), tone-seq()))
    
    
    define function ex22()
      play warp(warp4(),
                transpose(control-warp(get-warp(),
                                       warp-abs(nil, pitch-rise())),
                          tone-seq()))
    
    
    if not(boundp(quote(a-snd))) then
      set a-snd = s-read("demo-snd.aiff")
    
    
    define function ex23()
      play force-srate(*default-sound-srate*,  sound(a-snd) ~ 3.0)
    
    define function down()
      return force-srate(*default-sound-srate*, 
                         seq(sound(a-snd) ~ 0.2,
                             sound(a-snd) ~ 0.3,
                             sound(a-snd) ~ 0.4,
                             sound(a-snd) ~ 0.6))
    
    
    define function ex24()
      play down()
    
    define function up()
      return force-srate(*default-sound-srate*,
                         seq(sound(a-snd) ~ 0.5,
                             sound(a-snd) ~ 0.4,
                             sound(a-snd) ~ 0.3,
                             sound(a-snd) ~ 0.2))
    
    
    define function ex25()
      play seq(down(), up(), down())
    
    
    define function ex26()
      begin
        exec s-save(a-snd, 1000000000, "./a-snd-file.snd")
        play "./a-snd-file.snd"
        exec system("rm ./a-snd-file.snd")
      end
    
    
    define function ex27()
      begin
        set my-sound-file = "./a-snd-file.snd"
        exec s-save(a-snd, 1000000000, my-sound-file)
        exec play-file(my-sound-file)
        exec system(strcat("rm ", my-sound-file))
      end
    
    
    ; note that Nyquist's "Autonorm" facility probably makes this example
    ; superfluous
    define function ex28()
      begin
        ; normalize in memory.  First, assign the sound to a variable so 
        ; it will be retained:
        set mysound = sim(osc(c4), osc(c5))
        ; now compute the maximum value (ny:all is a 1 giga-samples, you may want a
        ; smaller constant if you have less than 4GB of memory :-):
        set mymax = snd-max(mysound, NY:ALL)
        display "Computed max", mymax
        ; now write out and play the sound from memory with a scale factor:
        play mysound * (0.9 / mymax)
      end
    
    
    define function myscore()
      return sim(osc(c4), osc(c5))
    
    
    define function ex29()
      begin
        ; if you don't have space in memory, here's how to do it:
        ; Compute the maximum. This is a bit tricky in SAL because snd-max
        ; is looking for an expression (in LISP) to evaluate, not a sound.
        ; Use list and quote to create the LISP expression '(myscore):
        set mymax = snd-max(list(quote(myscore)), NY:ALL)
        display "Computed max", mymax
        ; now we know the max, but we don't have a the sound (it was garbage
        ; collected and never existed all at once in memory).  Compute the sound
        ; again, this time with a scale factor:]
        play myscore() * (0.9 / mymax)
      end
    
    
    define function ex30()
      play fmosc(c4, pwl(0.1))
    
    
    define function ex31()
      play fmosc(c4, pwl(0.5))
    
    
    define function ex32()
      play fmosc(c4, pwl(0.5, step-to-hz(c4),  0.501))
    
    
    define function ex33()
      begin
        set *fm-voice* = list(extract(0.110204, 0.13932, cue(a-snd)),
                              24.848422,
                              #T)
        play fmosc(cs2, pwl(0.5, step-to-hz(cs2), 0.501),
                   *fm-voice*, 0.0)
      end
    
    
    define function sweep(delay, pitch-1, sweep-time, pitch-2, hold-time)
      begin
        with interval = step-to-hz(pitch-2) - step-to-hz(pitch-1)
        return pwl(delay, 0.0,
                   ; sweep from pitch 1 to pitch 2
                   delay + sweep-time, interval,
                   ; hold until about 1 sample from the end
                   delay + sweep-time + hold-time - 0.0005, interval,
                   ; quickly ramp to zero (pwl always does this,
                   ;    so make it short)
                   delay + sweep-time + hold-time)
      end
    
    
    define function ex34()
      play fmosc(cs2, sweep(0.1, cs2, 0.6, gs2, 0.5),
                 *fm-voice*, 0.0)
    
    
    define function ex35() 
      play fmosc(cs2, 10.0 * lfo(6.0), *fm-voice*, 0.0)
    
    
    define function ex36()
      begin
        with modulator
        set modulator = pwl(1.0, 1000.0, 1.0005) * 
                        osc(c4)
        play fmosc(c4, modulator)
      end
    
    
    ;;; FINDING ZERO CROSSINGS, SND-SAMPLES
    
    set max-samples-for-zeros = 1000
    
    define function zeros(snd)
      begin
        ; start by getting the samples, only take 1000 samples max
        with s = snd-samples(snd, max-samples-for-zeros),
             newsign, sign, n, len, result, result2, starttime, srate
        ; go through the array looking for zero crossings
        set len = length(s)
        ; stop if there are no samples
        if len = 0 then return nil
        set sign = 0.0 > s[0]
        ; get the start time and sample rate of the sound for use below
        set starttime = car(snd-extent(snd, max-samples-for-zeros))
        set srate = snd-srate(snd)
        set n = 1
        loop
          until n >= len
          set newsign = 0.0 > s[n]
          if not(eq(sign, newsign)) then
            set result = cons(n, result)
          set sign = newsign
          set n += 1
        end
        ; now we have the zero crossings, convert them to times
        loop
          with result2 = nil
          for num in result
          ; return the time of the zero crossing, which is the start time
          ; of the snd plus the sample number / srate
          set result2 = cons(starttime + num / srate, result2)
          finally return result2
        end
      end
    
    
    define function ex37()
      begin
        ; extract a short piece of this sample
        set short = extract(0.1, 0.14, cue(a-snd))
        set z = zeros(short)
        exec format(t, "Zero crossings from a-snd: ~A~%", z)
      end
    
    
    ; find the differences between zero crossings reported by zeros
    ; print the result in terms of samples for readability
    ;
    define function periods(lis, short)
      begin
        with result, prev, srate
        if null(lis) then return nil
        set srate = snd-srate(short)
        loop
          set prev = car(lis)
          set lis = cdr(lis)
          if null(lis) then return reverse(result)
          set result = cons(srate * car(lis) - prev, result)
        end
      end
    
    define function ex38()
      ; ex38 depends upon z, set by (ex37)
      begin
        if not(boundp(quote(z))) then exec ex37()
        set p = periods(z, short)
        exec format(t, 
                    "The intervals (in samples) between zero crossings are: ~%~A~%",
                    p)
      end
    
    
    ; build a wavetable using zero crossing information
    ;
    ; I interactively played with the data and decided to extract from the
    ; 5th period to the 21st period (these had 86 and 87 samples each and
    ; seem to indicate some kind of periodicity).  The 1st period measures
    ; from the zeroth zero crossing to the first, so the 5th period measures
    ; from the 4th zero crossing to the 5th.  I'll arbitrarily take
    ; the 4th and 20th zero crossing times (the 5th and 20th should work as
    ; well), and from the data, this looks like 2 waveform periods.
    ; This is very clear if you plot the data.
    ;
    ; arguments are:
    ;  snd - the sound to extract from
    ;  zeros - the result of (zeros snd)
    ;  start - the number of the starting zero crossing
    ;  stop - the number of the ending zero crossing
    ;  n - number of periods contained in the extracted sound
    ;
    define function extract-table(snd, zeros, start, stop, n)
      begin
        with starttime, extent, hz
        ; Start by shifting snd to time zero:
        set starttime = car(snd-extent(snd, max-samples-for-zeros))
        set snd = cue(snd) @  - starttime
    
        exec format(t, "~A~%", snd)
        ; also get the start and stop times and shift them:
        set start = nth(start, zeros) - starttime
        set stop = nth(stop, zeros) - starttime
    
        exec format(t, "table ~A start ~A stop ~A~%", snd, start, stop)
    
        ; now extract the samples of interest, note that we are
        ; overwriting our pointer to the snd argument
        set snd = extract(start, stop, cue(snd))
        exec format(t, "table now ~A~%", snd)
    
        ; now we need to figure out the pitch this sound would represent
        ; when played at its samplerate.  The pitch in hz is 1 / duration,
        ; and duration is the extent of the sound / n.  Therefore, take
        ; n/extent
        set extent = snd-extent(snd, max-samples-for-zeros)
        set hz = n / (cadr(extent) - car(extent))
        ; an osc table is a list of the sound, pitch number, and T (periodic)
        return list(snd, hz-to-step(hz), #t)
      end
    
    
    define function ex39()
      begin
        ; try it out
        set *a-voice* = extract-table(short, z, 4, 20, 2)
        ; now use the table with an oscillator
        play osc(c3, 1.0, *a-voice*)
      end
    
    
    define function ex40()
      ; play it at its normal pitch
      play osc(cadr(*a-voice*), 1.0, *a-voice*)
    
    
    define function ex41()
      play noise()
    
    
    define function ex42()
      play lp(noise(), 1000.0)
    
    
    define function ex43()
      play hp(noise(), 1000.0) * 0.5
    
    
    ; low pass sweep from 100 hz to 2000 hz
    define function ex44()
      play lp(noise(), pwl(0.0, 100.0, 1.0, 2000.0, 1.0))
    
    
    ; high pass sweep from 50 hz to 4000 hz
    define function ex45()
      play hp(noise(), pwl(0.0, 50.0, 1.0, 4000.0, 1.0)) * 0.5
    
    
    ; band pass at 500 hz, 20 hz bandwidth
    define function ex46()
      play reson(10.0 * noise(), 500.0, 20.0, 1)
    
    
    ; band pass sweep from 100 to 1000 hz, 20 hz bandwidth
    define function ex47()
      play reson(0.04 * noise(),
                 pwl(0.0, 200.0, 1.0, 1000.0, 1.0),
                 20.0)
    
    
    exec format(t, "\nType (ex1) through (ex47) to run these examples.\n")
    exec format(t, "See demos/stktest.lsp for more simple sound examples.\n")
    exec format(t, "\nI'm turning off Auto-normalization.  See AUTONORM-ON\n")
    exec format(t, "in the documentation for an explanation:\n\n")
    exec autonorm-off()
    
    define function ex-all ()
      begin
        exec format(t, "Warning: turning automatic normalization feature off~%")
        exec autonorm-off()
        loop
          for i from 1 to 47
          for fn = list(intern(format(nil, "EX~A", i)))
          exec format(t, "~A~%", fn)
          exec eval(fn)
        end
      end
    
    
    exec format(t, "\n\"exec ex-all()\" in SAL or (ex-all) in Lisp will compute and play all examples for testing purposes.\n")
    nyquist-3.05/demos/rhythm_tutorial.htm0000644000175000000620000001003510144436365017247 0ustar  stevestaff
    
    
    
    Rhythmic Pattern Tutorial
    
    
    
    
    

    Rhythmic Pattern Tutorial

    This example illustrates a very simple percussion sound created with noise and using the sound to generate a rhythm.

    The sound is created by filtering noise. The filter is controlled using the piece-wise linear function (pwl):

    (defun pulse (dur)
      (stretch dur (hp (noise) (pwl 0 15 0.2 6000 0.6 15000 0.75 7))))

    A sequence of sounds is constructed and repeated in the following code. Notice that each time through the pattern,
    the scale factor is increased by 0.1, giving the whole sequence a crescendo:

    (defun pulsepat (&optional (rep 16)) 
      (seqrep (i rep)
        (stretch 0.2
          (scale (* i 0.1)
            (seq (pulse 1) (pulse 1) (pulse 2) (pulse 2))))))
    
    (play (pulsepat 17))

    Pitched Patterns

    This example uses the ring function from the Vinal Scratch Tutorial. When the pitch parameter is increased, we hear a kind of electronic bass sound. Try this:

    (play (ring 0.4 30 1.2))

    These notes can be combined to create a pattern. The techno function creates a short pattern of 3 notes repeated any number of times:

    (defun techno (rep)
      (seqrep (i rep) 
        (scale 0.8
          (sim
    	(scale 0.8 (at 0.0 (ring 0.4 30 1.2)))
    	(scale 0.6 (at 0.2 (ring 0.2 30 0.9)))
    	(scale 0.7 (at 0.3 (ring 0.1 30 1.1))) ))))

    Try this:

    (play (techno 3))

    The following combines and transposes rhythmic segments to create a bass line:

    (play (seqrep (i 2)
            (seq (techno 2)
                 (transpose 5 (techno 2))
                 (transpose -2 (techno 1))
                 (transpose 3 (techno 1))
                 (techno 2))))

    Layers for Richer Texture

    Sounds can often be combined with time and pitch offsets to create richer textures. The following layers two sequences based on the same techno function:

    (play (sim
            (scale 0.4
              (at 0.0
                (seqrep (i 2)
                  (seq (techno 2)
                       (transpose 5 (techno 2))
                       (transpose -2 (techno 1))
                       (transpose 3 (techno 1))
                       (techno 2)))))
    	(scale 0.2
              (at 0.1
                (seqrep (i 2)
                  (seq (transpose 2 (techno 2))
                       (transpose 7 (techno 2))
                       (transpose -4 (techno 1))
                       (transpose 5 (techno 1))
                       (transpose -2 (techno 2)))) ))))

    Note that the second layer is almost but not exactly a transposition of the first layer. If it were an exact transposition, it would make sense to encapsulate the first layer in a function and call it twice. The following variation is much more concise, but it does not compute exactly the same sound:

    (defun bass-line ()
      (seqrep (i 2)
        (seq (techno 2)
             (transpose 5 (techno 2))
             (transpose -2 (techno 1))
             (transpose 3 (techno 1))
             (techno 2))))
    (play (sim (scale 0.4 (bass-line))
               (scale 0.2 
                 (at 0.1 (transpose 2 (bass-line))))))

    Another Example

    This example also uses the ring function from the Vinal Scratch Tutorial.

    (play (seqrep (i 17) 
            (lp (scale (+ (* i 0.05 ) 0.3) 
                  (seq (transpose -4 (ring 0.1 32 0.6)) 
                       (transpose -5 (ring 0.05 20 0.2)) 
                       (transpose (* 2 i) (ring 0.1 27 0.5)) 
                       (transpose -3 (ring 0.05 22 0.1)) 
                       (transpose (* i 3) (ring 0.1 28 0.4)) 
                       (ring 0.05 31 0.7)))
                (* 100 i))))

    This play 17 repetitions of a sound. Each time, the sound is a bit louder, the low-pass frequency is raised by 100 Hz, and two of the transpositions are increased. This creates a rhythmic and evolving sound.


     

    nyquist-3.05/demos/mateos/0002755000175000000620000000000011537433124014567 5ustar stevestaffnyquist-3.05/demos/mateos/organ.lsp0000644000175000000620000000247611466723256016435 0ustar stevestaff;; Daniel Mateos - danielma@andrew.cmu.edu ;; Instrument by Hans Mikelson, ;; imported from CSOUND ;; Website: http://www.adp-gmbh.ch/csound/instruments/organ01.html ;; This instrument really sounds as a real organ!! ;; Modified by Roger Dannenberg, Nov. 2005 ;; Sound overtones (defun dmhm-overtones (freq) (sim (scale 0.8 (hzosc freq)) (scale 0.8 (hzosc (* freq 2))) (scale 0.8 (hzosc (* freq 2.9966))) (scale 0.8 (hzosc (* freq 4))) (scale 0.3 (hzosc (* freq 5.9932))) (scale 0.2 (hzosc (* freq 8))) (scale 0.1 (hzosc (* freq 10.0794))) (scale 0.1 (hzosc (* freq 11.9864))) (scale 0.4 (hzosc (* freq 16))))) (defun dmhm-organ (pitch) (mult 0.1 ;; normalize to about 1 (env 0.1 0 0.1 1 1 1) (dmhm-overtones (step-to-hz pitch)))) ;; DMHM-ORGAN-TEST -- a small test program/demo ;; ;; The same score used by the CSOUND example. ;; (defun dmhm-organ-test () (autonorm-off) (play (sim (at 0 (stretch 1.98 (sim (dmhm-organ c3) (dmhm-organ e3) (dmhm-organ g3) (dmhm-organ as3)))) (at 2 (stretch 1.98 (sim (dmhm-organ c3) (dmhm-organ ds3) (dmhm-organ f3) (dmhm-organ a3)))) (at 4 (stretch 1.98 (dmhm-organ c3))) (at 4 (stretch 0.1 (dmhm-organ ds3))) (at 4.1 (stretch 1.88 (dmhm-organ e3))) (at 4 (stretch 1.98 (dmhm-organ g3)))))) nyquist-3.05/demos/mateos/gong.lsp0000644000175000000620000000315011466723256016247 0ustar stevestaff;; GONG INSTRUMENT (TAM TAM) ;; Daniel Mateos - danielma@andrew.cmu.edu ;; Instrument by Hans Mikelson, imported from CSOUND ;; Website: http://www.adp-gmbh.ch/csound/instruments/ ;; Modified by Roger Dannenberg, Nov. 2005 ;; See also: demos/pmorales/b1.lsp ;; DMHM-GONG -- an additive synthesis gong sound ;; ;; so named to avoid naming conflicts with other gongs ;; (defun dmhm-gong (pitch) (let* ((ifrq (step-to-hz pitch)) ;; frequencies of partials (ifrq1 (* 1.0000 ifrq)) (ifrq2 (* 1.1541 ifrq)) (ifrq3 (* 1.6041 ifrq)) (ifrq4 (* 1.5208 ifrq)) (ifrq5 (* 1.4166 ifrq)) (ifrq6 (* 2.7916 ifrq)) (ifrq7 (* 3.3833 ifrq)) ;; amplitude of partials (iamp1 1.0000) (iamp2 0.8333) (iamp3 0.6667) (iamp4 1.0000) (iamp5 0.3333) (iamp6 0.3333) (iamp7 0.3333) ;; main envelope (envelope (pwevr 1 1 0.001)) ;; partial envelopes (aenv1 (mult iamp1 envelope)) (aenv2 (mult iamp2 envelope)) (aenv3 (mult iamp3 envelope)) (aenv4 (mult iamp4 envelope)) (aenv5 (mult iamp5 envelope)) (aenv6 (mult iamp6 envelope)) (aenv7 (mult iamp7 envelope))) ;; sum the partials (scale 0.25 ; normalize to about 1.0 (sim (partial (hz-to-step ifrq1) aenv1) (partial (hz-to-step ifrq2) aenv2) (partial (hz-to-step ifrq3) aenv3) (partial (hz-to-step ifrq4) aenv4) (partial (hz-to-step ifrq5) aenv5) (partial (hz-to-step ifrq6) aenv6) (partial (hz-to-step ifrq7) aenv7) )))) ;; Let's play something! ;; ;; type (dmhm-gong-test) to play an example ;; (defun dmhm-gong-test (autonorm-off) (play (stretch 10 (dmhm-gong a3)))) nyquist-3.05/demos/mateos/tuba.lsp0000644000175000000620000000475511466723256016264 0ustar stevestaff;; By Daniel Mateos - Feb 2005 ;; This FM sound is similar to that of the tuba. ;; Therefore, intended mainly for low register. ;; It is built upon a FM 8 parallel oscillator circuit. ;; The attack will remain constant whatever the enviroment. ;; Also, it is properly prepared for transposition. ;; Modified by Roger Dannenberg, Nov 2005 ;; Variable amplitude & frequency oscillator (defun tuba-osc (amp freq) (mult amp (hzosc freq))) ;; Parallel 8 oscillators FM (defun tuba-eight-osc (acar fcar amod1 fmod1 amod2 fmod2 amod3 fmod3 amod4 fmod4 amod5 fmod5 amod6 fmod6 amod7 fmod7 amod8 fmod8) (tuba-osc acar (sim fcar (tuba-osc amod1 fmod1) (tuba-osc amod2 fmod2) (tuba-osc amod3 fmod3) (tuba-osc amod4 fmod4) (tuba-osc amod5 fmod5) (tuba-osc amod6 fmod6) (tuba-osc amod7 fmod7) (tuba-osc amod8 fmod8)))) ;; Define amplitude envelope of each modulator (defun tuba-amod (numb) (seq (stretch-abs 1 (pwl (/ numb 10) 100)) (pwl 0 100 (- 1 (/ numb 10))))) ;; Defines Amplitud envelope of carrier (defun tuba-acar () (seq (stretch-abs 1 (pwl 0.1 0.8)) (pwl 0 0.8 0.7 0.8 0.9))) ;; Defines frequency of each modulator (defun tuba-fmod (numb fcar) (case numb (1 (- fcar 2)) (2 (- (* fcar 4) 3)) (3 (- (* fcar 3) 2)) (4 (- (* fcar 5) 2)) (5 (- (* fcar 6) 2)) (6 (- (* fcar 7) 2)) (7 (- (* fcar 8) 2)) (8 (- (* fcar 9) 2)))) ;; DMHM-TUBA -- a tuba-like FM sound ;; ;; named dmhm-tuba to avoid name conflicts with other (possible) tubas ;; (defun dmhm-tuba (fcar) (setf transp (float (get-transpose))) (cond ((> transp 0.0) (setf fcar (float fcar)) (setf fcar (* fcar (expt 2.0 (/ transp 12.0)))) )) (cond ((< transp 0.0) (setf transp (* -1.0 transp)) (setf fcar (float fcar)) (setf fcar (/ fcar (expt 2.0 (/ transp 12.0)))) )) (scale 0.8 ; normalize (lp (hp (transpose-abs 0 (tuba-eight-osc (tuba-acar) fcar (tuba-amod 1) (tuba-fmod 1 fcar) (tuba-amod 2) (tuba-fmod 2 fcar) (tuba-amod 3) (tuba-fmod 3 fcar) (tuba-amod 4) (tuba-fmod 4 fcar) (tuba-amod 5) (tuba-fmod 5 fcar) (tuba-amod 6) (tuba-fmod 6 fcar) (tuba-amod 7) (tuba-fmod 7 fcar) (tuba-amod 8) (tuba-fmod 8 fcar)) ) 10) 22000))) ;; DMHM-TUBA-TEST -- play a sample of dm-tuba instrument ;; (defun dmhm-tuba-test () (autonorm-off) (play (seq (dm-tuba 70 ) (stretch 5 (dm-tuba 70)) (loud -10 (dm-tuba 70)) (transpose -10 (stretch 3 (dm-tuba 70)))))) nyquist-3.05/demos/mateos/bell.lsp0000644000175000000620000000206511466723256016237 0ustar stevestaff;; BELL INSTRUMENT ;; Daniel Mateos - danielma@andrew.cmu.edu ;; Instrument by Hans Mikelson, imported from CSOUND ;; Website: http://www.adp-gmbh.ch/csound/instruments/ ;; Modified by Roger Dannenberg, Nov. 2005 ;; see also: demos/pmorales/b3.lsp, ;; demos/pmorales/e2.lsp, and ;; demos/pmoraels/partial.lsp ;; This bell is closely related to FM-BELL in e2.lsp ;; DMHM-BELL -- an FM bell sound ;; ;; so named to avoid naming conflicts with other bells ;; (defun dmhm-bell (pitch) (let ((imax 10) ; max amplitude (ifq1 (hz-to-step (* (step-to-hz pitch) 5))) ; partials (ifq2 (hz-to-step (* (step-to-hz pitch) 7))) (aenv (pwevr 1 1 0.0001)) ; amplitude envelope (adyn (mult (* imax ifq2) (pwevr 1 1 0.001)))) ; dynamics envelope (mult aenv ; create a carrier modulated signal (fmosc ifq1 (mult adyn (osc ifq2)))))) ;; Let's play this bell!! ;; ;; type (dmhm-bell-test) to play an example ;; (defun dmhm-bell-test () (play (stretch 10 (dmhm-bell g1)))) nyquist-3.05/demos/shepard.ny0000644000175000000620000001130710144436365015300 0ustar stevestaff;nyquist plug-in ;version 1 ;type generate ;name "Shephard glissando" ;action"Creating Shephard glissando" ;info "Shephard-Risset glissando\nwritten by Erich Neuwirth" ;control pitch1 "Start pitch" real "MIDInote" 60 24 96 ;control pitch2 "End pitch" real "MIDInote" 72 24 96 ;control cpitch1 "Start filter pitch" real "MIDInote" 60 24 96 ;control cpitch2 "End filter pitch" real "MIDInote" 60 24 96 ;control overtonesemi "Overtone interval" real "MIDInote" 12 3 24 ;control overtones "Overtones" int "" 4 1 8 ;control duration "Duration" real "seconds" 1.5 0.3 30 ;control skew "Tone skewness" real "" 0.0 0.0 0.99 (setf overtones (truncate overtones)) (setf *onepi* 3.141592654) (setf *twopi* (* 2 pi)) (setf *halfpi* (/ pi 2)) (defun make-table (func-exp points) (let ((table (make-array points))) (dotimes (i points) (setf (aref table i) (funcall func-exp (/ (float i) (float points))))) (list (snd-from-array 0.0 points table) (hz-to-step 1) T) )) (defun erich-wave (skew) (make-table (lambda (x) (if (< (abs skew) 0.000001) (sin (* *twopi* x)) (* (/ (sin (* *twopi* x)) (- (/ 1.0 skew) (cos (* *twopi* x)))) (/ ( sqrt (- 1.0 (* skew skew))) skew)))) 2048)) (defun pitchenv (pitch centerpitch halfwidth) (let ((xarg (abs (/ (- (float pitch) centerpitch) halfwidth)))) (if (> xarg 1) 0 (/ (+ (cos (* *onepi* xarg)) 1.0) 2.0)) )) ; envshaper is shifted from 0 to 2 ; it transforms (0 2) into 0 1 ; to use it as envelope distorter, it has to be used like ; (shape s (envshaper) 1) (defun envshaper () (mult (sum 1 (hzosc (const (/ 1.0 2.0) 2) *table* 270)) 0.5)) ; some utility functions (defun normalize (s &optional (maxvol 0.8) (maxlen 44100)) (let* ((mysound s) (vol (peak mysound maxlen))) (scale (/ (float maxvol) vol) mysound))) (defun buffer (s t1 duration t2) (let ((timebase (hzosc (pwl (+ duration t1 t2))))) (sim timebase (at t1 (cue s))))) (defun iseq-helper (a b) (let ((mylist '())) (dotimes (i (1+ (- b a)) (reverse mylist)) (setf mylist (cons (+ a i) mylist))))) (defun iseq (a b) (if (> a b) (reverse (iseq-helper b a)) (iseq-helper a b))) (defun floor (x) (if (< x 0) (1- (truncate x)) (truncate x))) (defun realrem (x mod) (- (float x) (* (floor (/ (float x) (float mod))) (float mod)))) (defun sheptone-sweep-helper (pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 overtonesemi overtones &optional (wavetable *sine-table*)) (let ((mytone (const 0 duration)) (maxovertones (+ (floor (/ (float (max (abs (- pitch-1 centerpitch-2)) (abs (- pitch-1 centerpitch-2)))) overtonesemi)) overtones 2)) (ampshaper (envshaper)) ) (dolist (i (iseq (- maxovertones) maxovertones) mytone) (progn (setf startpitch (+ pitch-1 (* i overtonesemi))) (setf endpitch (+ pitch-2 (* i overtonesemi))) (setf f (pwe 0 (step-to-hz startpitch) duration (step-to-hz endpitch))) (setf p (pwl 0 startpitch duration endpitch)) (setf c (pwl 0 centerpitch-1 duration centerpitch-2)) (setf normwidthfactor (/ 1.0 (* overtones overtonesemi))) (setf a (shape (mult (diff p c) normwidthfactor) ampshaper 1)) (setf voice (mult a (hzosc f wavetable))) (setf mytone (sum mytone voice)) ) ))) (defun sheptone-sweep (pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 overtonesemi overtones &optional (wavetable *sine-table*)) (normalize (mult (sheptone-sweep-helper pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 overtonesemi overtones wavetable) (env 0.05 0 0.05 1 1 1 duration))) ) (setf result (buffer (sheptone-sweep pitch1 cpitch1 duration pitch2 cpitch2 overtonesemi overtones) 0.1 duration 0.2)) result nyquist-3.05/demos/demo-snd.aiff0000644000175000000620000001756610144436365015654 0ustar stevestaffFORMnAIFFCOMM@ DSSNDH=6 8p)]N=(30\(nYIs; #\yqLqNxx{(.y(x^ I)Q {"%l'* ,&./0L0K/.$+)A&@"]8f  [f lO[y<-vcI[cm3;mU ] [F D& ,9q 3 #]AnKi+ O)~| < . Y i 4 D = n K @ dSQVahV3tisLN.SH A3x)v\?8 Dl<[a T F3<(jsA X C&s @hL9DQ)N$S c vq< #qBD[k x 1 @  !A~^DCDqmtTCA6+y,i;ut3@@lYQNy.]3,[_6`~,]8?],[isl8KQ$SyhC5iTi,9cyn N!$.&(+,-0_2n34X320-*i&_":{ \Ihyt + 8 , x8KN(yx~>@>>@>>@>5>@>>@A5A@>>@>P>@>>@>>@::@?5?@>>@> >@>>@>>@>>@>5>@>>@A5A@>>@>P>@>>@>>@>>@?5?@>>@>>@AA@A5A@AA@A5A@AA@?5?@<<@>P>@>>@>>@::@?5?@>>@> >@/MTrk~::@::@99@:5:@::@<5<@::@9P9@::@99@77@757@66@7 7@::@::@99@:5:@::@<5<@::@9P9@::@99@77@757@66@::@::@959@::@<5<@>>@<5<@77@9P9@::@99@77@757@66@7 7@/MTrk~77@77@22@757@77@555@77@2P2@77@22@33@050@22@+ +@77@77@22@757@77@555@77@2P2@77@66@77@050@22@77@..@555@22@555@..@050@33@2P2@77@22@33@050@22@+ +@/nyquist-3.05/demos/pmorales/0002755000175000000620000000000011537433124015121 5ustar stevestaffnyquist-3.05/demos/pmorales/b1.lsp0000644000175000000620000000316211466723256016154 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Gong like sounds ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun add-partial (dur frq scal) (amosc (hz-to-step frq) (pwev scal dur (* scal 1e-2)))) (defun gong-1 () (sim (add-partial 4 240 3.0) (add-partial 4 277 2.5) (add-partial 4 385 2.0) (add-partial 4 605 3.0) (add-partial 4 340 1.0) (add-partial 4 670 1.0) (add-partial 4 812 1.0))) (defun add-partial-2 (frq scal) (amosc (hz-to-step frq) (pwev scal (/ (* 6 240) frq) (* scal 1e-2)))) (defun gong-2 () (sim (add-partial-2 240 3.0) (add-partial-2 277 2.5) (add-partial-2 385 2.0) (add-partial-2 605 3.0) (add-partial-2 340 1.0) (add-partial-2 670 1.0) (add-partial-2 812 1.0))) (defun add-partial-3 (frq fratio dur amp) (amosc (hz-to-step (* frq fratio)) (pwev amp (/ dur fratio) (* amp 1e-2)))) (defun gong-3 (frq dur) (sim (add-partial-3 frq 1.0 dur 2.0) (add-partial-3 frq 2.0 dur 2.0) (add-partial-3 frq 2.4 dur 2.0) (add-partial-3 frq 3.0 dur 2.0) (add-partial-3 frq 4.5 dur 3.0) (add-partial-3 frq 5.33 dur 3.0) (add-partial-3 frq 6.0 dur 3.0))) (defun gong-3-melody () (sim (at 0.0 (gong-3 329 5)) (at 0.2 (gong-3 360 6)) (at 0.4 (gong-3 380 5)) (at 0.6 (gong-3 300 8)) (at 0.8 (gong-3 430 4)) (at 2.0 (gong-3 640 4)) (at 2.2 (gong-3 610 5)) (at 2.4 (gong-3 580 4)) (at 2.6 (gong-3 660 5)))) (defun gong-3-demo () (ss (gong-3-melody))) nyquist-3.05/demos/pmorales/b10.lsp0000644000175000000620000000345311466723256016237 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Sinus Chaos ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun env31 () (pwlv 0.99 25e-3 0.99 225e-3 0.318 275e-3 0.318 475e-3 0.99 500e-3 0.99)) (defun env32 () (pwlv 0.377 250e-3 0.99 500e-3 0.377)) (defun env33 () (pwlv 0.5 20e-3 0.5 225e-3 0.99 250e-3 0.99 480e-3 0.5 500e-3 0.5)) (defun env34 () (pwlv 0.333 25e-3 0.333 225e-3 0.999 275e-3 0.999 475e-3 0.333 500e-3 0.333)) (defun make-env31 () (setf *env31* (list (env31) (hz-to-step 2) T))) (defun make-env32 () (setf *env32* (list (env32) (hz-to-step 2) T))) (defun make-env33 () (setf *env33* (list (env33) (hz-to-step 2) T))) (defun make-env34 () (setf *env34* (list (env34) (hz-to-step 2) T))) (if (not (boundp '*env31*)) (make-env31)) (if (not (boundp '*env32*)) (make-env32)) (if (not (boundp '*env33*)) (make-env33)) (if (not (boundp '*env34*)) (make-env34)) (defun make-table12 () (setf *table12* (sim (build-harmonic 21.0 2048) (build-harmonic 29.0 2048) (build-harmonic 39.0 2048))) (setf *table12* (list *table12* (hz-to-step 1) T))) (if (not (boundp '*table12*)) (make-table12)) (defun chaos-partial (amp rate frq dur env &optional (table *table*)) (scale amp (fmosc (hz-to-step 1e-3) (scale frq (osc (hz-to-step rate) dur env)) table))) (defun partial2 (amp frandi rate frq dur env) (mult (randi1 frandi dur) (scale amp (fmosc (hz-to-step 1e-3) (scale frq (osc (hz-to-step rate) dur env)))))) (ss (sim (chaos-partial 4.5 0.12 880.0 24 *env31*) (partial2 4.0 200.0 0.17 1660.0 24 *env32*) (chaos-partial 1.2 0.05 200.0 24 *env33*) (chaos-partial 0.7 0.33 2400.0 24 *env34*) )) nyquist-3.05/demos/pmorales/a5.lsp0000644000175000000620000000122611466723256016156 0ustar stevestaff;;; SIMPLE SYNTHESIS ;;; Waveform + Envelope. Modulating the frequency ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun whiny (dur frq) (let ((lfo-f (step-to-hz frq))) (mult (pwl 0.1 1 (- dur 0.1) 1 dur) (fmosc frq (pwl (* 0.1 dur) (/ lfo-f -2.0) (* 0.25 dur) (* lfo-f 2.0) (* 0.3 dur) (* lfo-f 1.5) (* 0.7 dur) (* lfo-f -7.0 (/ 8.0)) dur (* lfo-f -15.0 (/ 16.0)) ))))) (defun whiny-demo () (ss (whiny 10 a5))) nyquist-3.05/demos/pmorales/e2.lsp0000644000175000000620000001310211466723256016153 0ustar stevestaff;;; FM ;;; Chowning Dynamic Spectral Evolution ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es ;;; WARNING: needs REVERB.LSP (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (if (not (fboundp 'reverb)) (load "reverb")) ; Chowning BELL ----------------------------------------------------- (defun exp-env (amp dur) (scale amp (pwe dur 64e-4))) (defun fm-bell (frq cm-ratio imax dur amp) (mult (exp-env amp dur) (fmosc (hz-to-step frq) (mult (exp-env (* imax (/ frq cm-ratio)) dur) (osc (hz-to-step (/ frq cm-ratio)) dur))))) ; Chowning WOOD-DRUM ------------------------------------------------ (defun wood-env (amp dur) (scale amp (pwev 0.8 (* dur 0.2) 1.0 (* dur 0.25) 1.0 dur 64e-4))) (defun wood-mod-env (amp dur) (scale amp (pwlv 1.0 (* 0.2 dur) 0.0 dur))) (defun fm-wood-drum (frq cm-ratio imax dur amp) (mult (wood-env amp dur) (fmosc (hz-to-step frq) (mult (wood-mod-env (* imax (/ frq cm-ratio)) dur) (osc (hz-to-step (/ frq cm-ratio)) dur))))) ; Chowning BRASS ---------------------------------------------------- (defun brass-env (amp dur) (scale amp (pwl 0.1 1.0 0.2 0.8 (- dur 0.1) 0.7 dur))) (defun fm-brass (pitch cm-ratio imax dur amp) (let ((frq (step-to-hz pitch))) (mult (brass-env amp dur) (fmosc pitch (mult (brass-env (* imax (/ frq cm-ratio)) dur) (osc (hz-to-step (/ frq cm-ratio)) dur)))))) ; Chowning CLARINET ------------------------------------------------- (defun clar-env (amp dur) (scale amp (pwev 64e-4 0.1 1.0 (- dur 0.1) 1.0 dur 64e-4))) (defun clar-mod-env (vmax vmin dur) (pwev vmax (* dur 0.3) vmin dur vmin)) (defun fm-clar (pitch cm-ratio imax imin dur amp) (let ((frq (step-to-hz pitch))) (mult (clar-env amp dur) (fmosc pitch (mult (scale (/ frq cm-ratio) (clar-mod-env imax imin dur)) (osc (hz-to-step (/ frq cm-ratio)) dur)))))) ; Chowning VARIABLE FM INSTRUMENT ----------------------------------- ; este instrumento hay que mejorarlo (defun variable-fm-env (amp break mid dur) (scale amp (pwev (* mid 64e-4) break mid dur (* mid 64e-4)))) (defun variable-mod-osc (index frq kdyn mid break dur) (amosc (hz-to-step frq) (scale (* index frq) (pwlv kdyn break mid dur)))) (defun variable-fm-inst (amp break mid dur kdyn index frq cm-ratio) (mult (variable-fm-env amp break mid dur) (fmosc (hz-to-step frq) (variable-mod-osc index (/ frq cm-ratio) kdyn mid break dur)))) (defun variable-fm-rev-st (amp break mid dur kdyn index frq cm-ratio coefrev) (let ((snd (variable-fm-inst amp break mid dur kdyn index frq cm-ratio))) (sim (cue snd) (scale coefrev (reverb snd dur))))) ;(ss (seq (fm-bell 100.0 (/ 5.0 7.0) 10 10 1.0) ; (fm-bell 150.0 (/ 5.0 7.0) 7 10 1.0) ; (fm-bell 200.0 (/ 5.0 7.0) 15 7 1.0))) (defun fm-w-d (pitch) (fm-wood-drum (step-to-hz pitch) (/ 16.0 11.0) 25 0.2 1.0)) ;(ss (seq (fm-w-d a2) (fm-w-d b2) (fm-w-d c3) (fm-w-d d3) (fm-w-d e3) ; (fm-w-d f3) (fm-w-d g3) (fm-w-d a3) ; (fm-w-d a1) (fm-w-d b1) (fm-w-d c2) (fm-w-d d2) (fm-w-d e2) ; (fm-w-d f2) (fm-w-d g2) (fm-w-d a2))) (defun fm-br (pitch) (fm-brass pitch 1.0 5 0.6 1.0)) ;(ss (seq (fm-br c4) (fm-br d4) (fm-br e4) (fm-br f4) (fm-br g4) ; (fm-br a4) (fm-br b4) (fm-br c5))) (defun fm-c (pitch) (fm-clar pitch (/ 3.0 2.0) 5 2 0.5 1.0)) ;(ss (seq (fm-c c5) (fm-c d5) (fm-c e5) (fm-c f5) (fm-c g5) ; (fm-c a5) (fm-c b5) (fm-c c6))) (defun v-fm (pitch break mid dur rev) (variable-fm-rev-st 1.0 break mid dur 0.8 20.0 (step-to-hz pitch) (/ 7.0 5.0) rev)) ;(ss (sim (at 0.0 (v-fm a4 0.7 0.2 3.0 0.5)) ; (at 1.5 (v-fm e6 0.2 0.3 3.0 0.4)) ; (at 3.0 (v-fm d5 2.0 0.6 4.0 0.4)) ; (at 6.0 (v-fm d6 0.01 0.7 3.0 0.5)))) ; Double Carrier Brass ---------------------------------------------- (defun dc-env (dur) (pwl (* dur 0.1) 1.0 (* dur 0.2) 0.8 (* dur 0.9) 0.7 dur)) (defun dc-modulator (frq dur imax imin) (amosc (hz-to-step frq) (sim (scale (* frq (- imax imin)) (dc-env dur)) (const (* frq imin) dur)))) (defun dc-fm1 (frq1 dur amp modulator) (scale amp (mult (dc-env dur) (fmosc (hz-to-step frq1) modulator)))) (defun dc-fm2 (frq1 dur cm-ratio index-ratio amp amp-ratio modulator) (scale (* amp amp-ratio) (mult (dc-env dur) (fmosc (hz-to-step (/ frq1 cm-ratio)) (scale index-ratio modulator))))) (defun double-carrier (dur frq cm-ratio amp amp-ratio imax imin index-ratio) (let ((modulator (dc-modulator (/ frq cm-ratio) dur imax imin))) (sim (dc-fm1 frq dur amp modulator) (dc-fm2 frq dur cm-ratio index-ratio amp amp-ratio modulator)))) ;(ss (double-carrier 0.6 440.0 1.0 1.0 0.5 3 1 (/ 3.0 1.5))) ; Double Carrier Trumpet -------------------------------------------- (defun port-env (dur) (pwlv -1.0 (* 0.25 dur) 0.1 (* 0.5 dur) 0.0 dur)) (defun chowning-fm-demo () (ss (seq (fm-bell 100.0 (/ 5.0 7.0) 10 10 1.0) (fm-bell 150.0 (/ 5.0 7.0) 7 10 1.0) (fm-bell 200.0 (/ 5.0 7.0) 15 7 1.0) (fm-w-d a2) (fm-w-d b2) (fm-w-d c3) (fm-w-d d3) (fm-w-d e3) (fm-w-d f3) (fm-w-d g3) (fm-w-d a3) (fm-w-d a1) (fm-w-d b1) (fm-w-d c2) (fm-w-d d2) (fm-w-d e2) (fm-w-d f2) (fm-w-d g2) (fm-w-d a2) (fm-br c4) (fm-br d4) (fm-br e4) (fm-br f4) (fm-br g4) (fm-br a4) (fm-br b4) (fm-br c5) (double-carrier 0.6 440.0 1.0 1.0 0.5 3 1 (/ 3.0 1.5))))) nyquist-3.05/demos/pmorales/c1.lsp0000644000175000000620000000133111466723256016151 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Random Signals ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun simple-noise () (mult (noise 4.0) (pwl 0.4 1.0 3.6 1.0 4.0))) (defun simple-randi (frandi) (mult (randi1 frandi 4.0) (pwl 0.4 1.0 3.6 1.0 4.0))) (defun tenney (frandi frq dur) (amosc (hz-to-step frq) (mult (randi1 frandi dur) (pwl 0.4 1.0 (- dur 0.4) 1.0 dur)))) ;(ss (seq (simple-noise) (simple-randi 200) (simple-randi 400))) (defun tenny-sequence () (seq (tenney 200.0 400.0 4.0) (tenney 800.0 300.0 2.0) (tenney 400.0 1600.0 4.0))) (defun tenny-demo () (ss (tenny-sequence))) nyquist-3.05/demos/pmorales/b7.lsp0000644000175000000620000000301011466723256016152 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Risset Tibetan ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun tibetan-wave () (setf *tibetan-table* (sim (scale 0.3 (build-harmonic 1 2048)) (scale 0.1 (build-harmonic 5 2048)) (scale 0.1 (build-harmonic 6 2048)) (scale 0.1 (build-harmonic 7 2048)) (scale 0.1 (build-harmonic 6 2048)) (scale 0.1 (build-harmonic 8 2048)) (scale 0.1 (build-harmonic 9 2048)))) (setf *tibetan-table* (list *tibetan-table* (hz-to-step 1) T))) (if (not (boundp '*tibetan-table*)) (tibetan-wave)) (defun tibetan (frq offset dur rise dec) (mult (pwl rise 1.0 (- dur dec) 1.0 dur) (apply #'sim (mapcar #'(lambda (off) (osc (hz-to-step (+ frq (* off offset))) dur *tibetan-table*)) '(0 1 2 3 4 -1 -2 -3 -4))))) (defun tibetan-sequence () (scale 0.1 (vector (sim (at 0.0 (tibetan 110 0.03 35 0.07 21)) (at 20.0 (tibetan 110 0.04 20 2 4)) (at 28.0 (tibetan 220 0.04 30 3 6)) (at 32.1 (tibetan 110 0.03 23 2.3 4.6))) (sim (at 5.0 (tibetan 55 0.02 20 0.04 12)) (at 20.0 (tibetan 220 0.05 15 1.5 3)) (at 32.0 (tibetan 110 0.025 26 2.6 5.2)) (at 36.0 (tibetan 55 0.01 22 0.04 13)))))) (defun tibetan-demo () (play (tibetan-sequence))) nyquist-3.05/demos/pmorales/phm.lsp0000644000175000000620000000507710144436365016437 0ustar stevestaff;;; DSP in Nyquist ;;; Flute Physical Modelling ;;; Based on Nicky Hind CLM Tutorial ;;; (Based on Perry Cook Flute Physical Modelling) ;;; Coded by Pedro J. Morales ;;; e-mail: pmorales @iele-ab.uclm.es (load "pjmg.lsp") ;; DELAY LINE (setf dl-class (send class :new '(cnt line len output))) (send dl-class :answer :isnew '(init-len) '((setf cnt 0) (setf len init-len) (setf line (make-array len)) (dotimes (i len) (setf (aref line i) 0.0)))) (send dl-class :answer :next '(val) '((setf output (aref line cnt)) (setf (aref line cnt) val) (setf cnt (if (= cnt (1- len)) 0 (1+ cnt))) output)) (defun make-delay-line (len) (send dl-class :new len)) (defun delay-line (dl-obj val) (send dl-obj :next val)) ; UNA EXCITACION (defun flute-exc (noise-lev vib-amount vib-rate atk dec dur) (let ((current-flow (sim (pwl atk 0.55 (- dur dec) 0.55 dur) ;puede variar 0.5 .. 0.8 (scale vib-amount (lfo vib-rate dur))))) (sim current-flow (scale noise-lev (mult current-flow (lp (noise dur) (/ *sound-srate* 2.0))))))) ;; FLUTE PHYSICAL MODELLING (setf flute-class (send class :new '(sum1 sum1-output freq dur bore-delay emb-delay period-samples out-sig last-sig current-bore))) (defun cubic-polynomial (x) (- x (expt x 3.0))) (send flute-class :answer :isnew '(exc emb-size ifreq idur) '((setf sum1 exc) (setf freq (step-to-hz ifreq)) (setf period-samples (round (/ *sound-srate* freq))) (setf bore-delay (make-delay-line period-samples)) (setf emb-delay (make-delay-line (round (* emb-size period-samples)))) (setf last-sig 0.0))) (send flute-class :answer :next '() '((setf sum1-output (snd-fetch sum1)) (when sum1-output (progn (setf current-bore (delay-line bore-delay last-sig)) (setf out-sig (+ (* 0.7 (+ (* 0.55 current-bore) (cubic-polynomial (delay-line emb-delay (+ sum1-output (* 0.5 current-bore)))))) (* 0.3 last-sig))) (setf last-sig out-sig))))) (defun flute (freq dur &key (noise-lev 0.0356) (atk 0.05) (dec 0.1) (emb-size 0.5) (vib-amount 0.015) (vib-rate 5)) (let (obj) (setf obj (send flute-class :new (flute-exc noise-lev vib-amount vib-rate atk dec dur) emb-size freq dur)) (hp (snd-fromobject 0.0 *sound-srate* obj) 20.0))) (ss (seq (flute a4 0.5 :dec 0.01) (flute b4 0.5 :dec 0.01) (flute c5 0.5 :dec 0.01) (flute gs4 1.0))) nyquist-3.05/demos/pmorales/b8.lsp0000644000175000000620000000272511466723256016167 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Risset Drum ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun drum-env (amp dur) (pwev amp dur (* 12e-5 amp))) (defun noise-component (amp dur central-frq noise-frq) (amosc (hz-to-step central-frq) (mult (drum-env (/ amp 2) dur) (randi1 noise-frq dur)))) (defun fund-component (amp dur frq) (amosc (hz-to-step frq) (drum-env (/ amp 2.5) dur))) (defun drum-inh-wave () (setf *drum-inh-table* (sim (build-harmonic 10 2048) (scale 1.5 (build-harmonic 16 2048)) (scale 2.0 (build-harmonic 22 2048)) (scale 1.5 (build-harmonic 23 2048)))) (setf *drum-inh-table* (list *drum-inh-table* (hz-to-step 1) T))) (if (not (boundp '*drum-inh-table*)) (drum-inh-wave)) (defun inh-component (amp dur frq) (amosc (hz-to-step (/ frq 10)) (drum-env (/ amp 6.0) dur) *drum-inh-table*)) (defun risset-drum (amp dur frq) (sim (noise-component amp dur 500 400) (inh-component amp dur frq) (fund-component amp dur frq))) (defun risset-drum-sequence () (sim (at 0.0 (risset-drum 1.0 3.0 100.0)) (at 0.5 (risset-drum 1.0 1.0 50.0)) (at 1.0 (risset-drum 1.0 1.0 75.0)) (at 1.2 (risset-drum 1.0 1.0 200.0)) (at 1.4 (risset-drum 1.0 3.0 300.0)) (at 1.8 (risset-drum 1.0 6.0 500.0)))) (defun risset-drum-demo () (ss (risset-drum-sequence))) nyquist-3.05/demos/pmorales/ks.lsp0000644000175000000620000000207210144436365016260 0ustar stevestaff;;; DSP in Nyquist ;;; Karplus-Strong Algorithm ;;; Coded by Pedro J. Morales. ;;; e-mail: pmorales@iele-ab.uclm.es (load "pjmg.lsp") (setf ks-class (send class :new '(cnt total-cnt last-output current-output string len total-len))) (send ks-class :answer :isnew '(pitch dur) '((setf len (round (/ *sound-srate* (step-to-hz pitch)))) (setf total-len (* *sound-srate* dur)) (setf string (snd-samples (noise (/ (step-to-hz pitch))) len)) (setf cnt 0) (setf total-cnt 0) (setf last-output 0.0) (setf current-output 0.0))) (send ks-class :answer :next '() '((setf current-output (aref string cnt)) (setf (aref string cnt) (/ (+ current-output last-output) 2.0)) (setf last-output current-output) (setf cnt (if (= (1- len) cnt) 0 (1+ cnt))) (setf total-cnt (1+ total-cnt)) (if (= total-cnt total-len) NIL current-output))) (defun ks (pitch dur) (let (obj) (setf obj (send ks-class :new pitch dur)) (snd-fromobject 0.0 *sound-srate* obj))) (ss (seq (ks e2 2)(ks a2 2)(ks d3 2)(ks g3 2)(ks b3 2)(ks e4 2))) nyquist-3.05/demos/pmorales/b9.lsp0000644000175000000620000000227211466723256016165 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Risset Endless ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (setf *twopi* (* 2 pi)) (defun bell-table () (setf *bell-table* (make-array 512)) (dotimes (i 512) (setf (aref *bell-table* i) (exp (* -4.8283 (- 1 (cos (* *twopi* (- i 255.5) (/ 511.0)))))))) (setf *bell-table* (snd-from-array 0.0 512 *bell-table*)) (setf *bell-table* (list *bell-table* (hz-to-step 1.0) T))) (if (not (boundp '*bell-table*)) (bell-table)) (defun frq-table () (setf *frq-table* (list (sim (pwe 1.0 16e-4) (const -1.0 1.0)) (hz-to-step 1.0) T))) (if (not (boundp '*frq-table*)) (frq-table)) (defun endless-partial () (mult (osc (hz-to-step 0.025) 40 *bell-table*) (fmosc (hz-to-step 16000) (scale 16000 (osc (hz-to-step 0.025) 40 *frq-table*))))) (setf *endless-partial* (endless-partial)) (defun risset-endless () (scale 0.25 (apply #'sim (mapcar #'(lambda (x) (at x (cue *endless-partial*))) '(0.0 2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0))))) (defun risset-endless-demo () (ss (risset-endless))) nyquist-3.05/demos/pmorales/b3.lsp0000644000175000000620000000251611466723256016160 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Risset Bell ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun bell-partial (amp dur frq) (amosc (hz-to-step frq) (pwev amp dur (* amp 12e-5)))) (defun risset-bell (amp dur frq) (sim (bell-partial amp dur (* frq .56)) (bell-partial (* amp .67) (* dur .9) (+ (* frq .56) 1)) (bell-partial (* amp 1.35) (* dur .65) (* frq .92)) (bell-partial (* amp 1.8) (* dur .55) (+ (* frq .92) 1.7)) (bell-partial (* amp 2.67) (* dur .325) (* frq 1.19)) (bell-partial (* amp 1.67) (* dur .35) (* frq 1.7)) (bell-partial (* amp 1.46) (* dur .25) (* frq 2.0)) (bell-partial (* amp 1.33) (* dur .2) (* frq 2.74)) (bell-partial (* amp 1.33) (* dur .15) (* frq 3.0)) (bell-partial amp (* dur .1) (* frq 3.76)) (bell-partial (* amp 1.33) (* dur .075) (* frq 4.07)))) (defun risset-bell-sequence () (sim (at 0.0 (risset-bell 1.0 4.0 999.0)) (at 2.0 (risset-bell 1.0 4.0 633.0)) (at 4.0 (risset-bell 1.0 4.0 211.0)) (at 6.0 (risset-bell 1.0 4.0 999.0)) (at 8.0 (risset-bell 0.7 20.0 633.0)) (at 10.0 (risset-bell 0.7 20.0 211.0)) (at 12.0 (risset-bell 0.7 20.0 999.0)) (at 14.0 (risset-bell 0.7 20.0 80.0)))) (defun risset-bell-demo () (ss (m))) nyquist-3.05/demos/pmorales/b5.lsp0000644000175000000620000000114111466723256016153 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Continuous pitch control by LFO ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun lfo-pitch-control () (pwlv 0.25 0.6 0.25 1.4 0.5 2.0 0.25 2.2 0.25 3.4 0.5 3.8 0.75 7.0 -0.2)) (defun starship (frq scl) (apply #'sim (mapcar #'(lambda (offset) (fmosc (hz-to-step (+ frq offset)) (scale scl (lfo-pitch-control)))) '(0.0 4.5 9.4 23.0 39.0 84.0)))) (defun starship-demo () (ss (starship 200.0 1000.0)) ) nyquist-3.05/demos/pmorales/pjmg.lsp0000644000175000000620000000231210144436365016575 0ustar stevestaff;;; PJMG.LSP ;;; Rutinas para Nyquist ; Some utilities and functions not defined in ; the released version of Nyquist (defun set-current-file (cf) (setf *CURRENT-FILE* cf)) (defun l () (load *CURRENT-FILE*)) ;; A comment by Dannenberg on the following function: ;; This function takes an expression for a sound and ;; finds its peak value. This forces a computation of all ;; samples, which are saved in memory (4 bytes per sample). ;; The samples are then normalized and written to a file. ;; This should be fine for short examples, but is not ;; recommended for general use because you may run out ;; of memory. See the manual for more notes on normalization. ;; (defun ss (m) (let ((m-max (peak m NY:ALL))) (s-save (scale (/ 1.0 m-max) m) NY:ALL *default-sound-file* :play *soundenable*))) (defun randi1 (fr dur) (let ((d (get-duration dur))) (snd-white *rslt* fr d))) (defun randi2 (fr dur) (at 0.0 (snd-white 0.0 fr dur))) (defun randh1 (fr dur) (let ((d (get-duration dur))) (snd-compose (noise d) (quantize (ramp d) (round (* fr d)))))) (defun rndh2 (fr dur) (at 0.0 (snd-compose (noise dur) (quantize (ramp dur) (round (* fr dur)))))) nyquist-3.05/demos/pmorales/d1.lsp0000644000175000000620000000232711466723256016160 0ustar stevestaff;;; Simple KARPLUS-STRONG ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es ; NYQUIST code for simple Karplus-Strong algorithm (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (setf ks-class (send class :new '(cnt total-cnt z-1output output delay-line len total-len))) (send ks-class :answer :isnew '(pitch dur) '((setf len (round (/ *sound-srate* (step-to-hz pitch)))) (setf total-len (* *sound-srate* dur)) (setf delay-line (snd-samples (noise (/ (step-to-hz pitch))) len)) (setf cnt 0) (setf total-cnt 0) (setf z-1output 0.0) (setf output 0.0))) (send ks-class :answer :next '() '((setf output (aref delay-line cnt)) (setf (aref delay-line cnt) (/ (+ output z-1output) 2.0)) (setf z-1output output) (setf cnt (if (= (1- len) cnt) 0 (1+ cnt))) (setf total-cnt (1+ total-cnt)) (if (= total-cnt total-len) NIL output))) (defun ks (pitch dur) (let (obj (d (get-duration dur))) (setf obj (send ks-class :new pitch d)) (snd-fromobject *rslt* *sound-srate* obj))) (defun ks-env (pitch dur) (mult (pwe dur 0.064) (ks pitch dur))) ;(ss (seq (ks a4 1.0) (ks b4 1.0) (ks c5 3.0))) (ss (seq (ks-env a3 1.0) (ks-env b3 1.0))) nyquist-3.05/demos/pmorales/buzz.lsp0000644000175000000620000000543611466723256016652 0ustar stevestaff;;; BUZZ generator for Nyquist ;;; Pedro J. Morales. Albacete, Spain. Jule, 2001 ;;; pmorales@iele-ab.uclm.es ; tested on Nyquist IDE 3.0 under Windows ; Summation formula taken from F. Richard Moore "Elements of Computer Music" ; section 3.4 page 273 (defun buzz-aux (harm len) (let ((frq (/ *sound-srate* len))) (scale (/ 1.0 harm) (mult (osc (hz-to-step (* (+ 1 harm) 0.5 frq)) (/ 1.0 frq)) (osc (hz-to-step (* harm 0.5 frq))(/ 1.0 frq)) (clip (recip (osc (hz-to-step (* 0.5 frq)) (/ 1.0 frq))) 10000))))) ; A table implies a constant spectrum. ; If you need another spectrum try to change the number of harmonics (defun make-buzz-table (harm &optional (len 2047)) (list (buzz-aux harm len) (hz-to-step (/ *sound-srate* len)) T)) ; This function calculates de maximun number of harmonics ; without aliasing (defun num-harm (pitch) (truncate (/ *sound-srate* 2.0 (step-to-hz pitch)))) ; Constant frequency buzz oscillator ; Number of harmonics is optional. If it is not ; specified then the waveform is calculated with maximum ; number of harmonics without aliasing (defun buzz (pitch dur &optional harm) (unless harm (setf harm (num-harm pitch))) (osc pitch dur (make-buzz-table harm))) ; vibrato buzz (defun vib-buzz (pitch dur &optional harm) (unless harm (setf harm (num-harm pitch))) (fmosc pitch (scale 10 (lfo 6 dur)) (make-buzz-table harm))) ; buzz in fm oscillator form (defun fmbuzz (pitch modulator harm) (fmosc pitch modulator (make-buzz-table harm))) ; filter with three formants intended for vowel synthesis ; (this synthesis algorithm may be improved by means of finer ; control of parameters) (defun formants (beh f1 f2 f3) (sim (reson beh f1 100 2) (reson beh f2 100 2) (reson beh f3 100 2))) ; vowels formants data taken from John R. Pierce "Los sonidos de la Musica" ; (Scientific American, spanish edition) (defun ah (pitch dur) ; Hawed foneme (mult (pwl 0.2 1 (- dur 0.4) 1 dur) (formants (vib-buzz pitch dur) 570 840 2410))) (defun eh (pitch dur) ; Head foneme (mult (pwl 0.2 1 (- dur 0.4) 1 dur) (formants (vib-buzz pitch dur) 530 1840 2480))) (defun eeh (pitch dur) ; Heed foneme (mult (pwl 0.2 1 (- dur 0.4) 1 dur) (formants (vib-buzz pitch dur) 270 2290 3010))) (defun ooh (pitch dur) ; Who'd foneme (mult (pwl 0.2 1 (- dur 0.4) 1 dur) (formants (vib-buzz pitch dur) 300 870 2240))) (defun buzz-demo () (seq (ah c3 1)(eeh c3 1)(ooh c3 1) (ah c2 1)(eeh c2 1)(ooh c2 1) (ah c4 1)(eeh c4 1)(ooh c4 1) (ah d4 1)(eeh d4 1)(ooh d4 1) (ah g4 1)(eeh g4 1)(ooh g4 1) (ah c5 1)(eeh c5 1)(ooh c5 1) (ah c4 1)(eh b3 0.5)(ah c4 0.5) (eeh e4 1)(eeh d4 1)(ah c4 3))) ; TEST (defun buzz-test () (play (buzz-demo))) ; (buzz-test) nyquist-3.05/demos/pmorales/a4.lsp0000644000175000000620000000154611466723256016162 0ustar stevestaff;;; SIMPLE SYNTHESIS ;;; Waveform + Envelope. Modulating the envelope with noise ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun shiver (dur frq noise-percent noise-frq) (mult (osc frq dur) (sum (pwlv 5e-2 300e-3 1.0 (- dur 300e-3) 1.0 dur 2e-3) (mult (/ noise-percent 100.0) (randi1 noise-frq dur))))) ; when noise-percent is too big (> 40), there is a click risk at the ; beginning and the end of the note ; this would be avoided if randi function were multiplied by a smooth envelope ; WARNING: randi1 is defined in PJMG.LSP (defun shiver-demo () (ss (seq (shiver 1 c5 20 40) (shiver 1 b4 50 40) (shiver 1 a4 80 40) (shiver 1 g4 20 300) (shiver 1 f4 50 300) (shiver 1 d4 80 300)))) nyquist-3.05/demos/pmorales/partial.lsp0000644000175000000620000000226311466723256017307 0ustar stevestaff;;; PARTIAL (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun klin (fr coef) (mult (sine (hz-to-step (* 300.0 fr coef)) 2.0) (pwev 3.0 3.0 1e-2))) (defun klines (coef) (sim (at 0.0 (klin 6.0 coef)) (at 0.3 (klin 7.0 coef)) (at 0.5 (klin 5.5 coef)) (at 0.7 (klin 6.5 coef)))) (defun bell-sequence () (sim (mult (sine (hz-to-step (* 300.0 (/ 3.14 5))) 6.0) (scale 4.0 (pwe 6.0 1e-2))) (mult (sine (hz-to-step 300.0) 6.0) (pwl 2.0 0.75 3.0 1.0 4.0 0.75 5.0 0.2 6.0)) (mult (sine (hz-to-step (* 300.0 1.57)) 6.0) (pwl 3.0 0.75 4.0 0.5 5.0)) (mult (sine (hz-to-step (* 300.0 3.14)) 6.0) (pwl 2.5 0.5 4.0)) (at 0.5 (scale 2.0 (mult (sine (hz-to-step (* 300.0 6.3)) 6.0) (pwe 3.0 5e-3)))) (at 2.0 (scale 2.0 (mult (sine (hz-to-step (* 300.0 9.12)) 6.0) (pwe 3.0 1e-2)))) (at 0.7 (scale 2.0 (mult (sine (hz-to-step (* 300.0 15.7)) 6.0) (pwe 4.0 2e-2)))) (at 3.0 (klines 1.0)) (at 4.0 (klines 1.5)) (at 1.0 (mult (sine (hz-to-step (+ (* 300.0 6.3) 20.0)) 6.0) (scale 5e-3 (pwe 2.0 1000.0 4.0)))) )) (defun bell-demo () (ss (scale 0.1 (bell-sequence)))) nyquist-3.05/demos/pmorales/b2.lsp0000644000175000000620000000306211466723256016154 0ustar stevestaff;;; ADDITIVE SYNTHESIS ;;; Risset's Spectral Analysis of a Chord ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) ; Probar con las dos envolventes ;(defun sac-env (dur) ; (let ((xx (pwl (/ dur 2) 1.0 dur))) ; (mult xx xx))) (defun sac-env (dur) (pwev 1.0 dur 5e-2)) (defun attk-list (offset num-harms &optional (out-list (list 0.0))) (if (= num-harms 0) (reverse out-list) (attk-list offset (1- num-harms) (cons (+ offset (car out-list)) out-list)))) (defun sac (frq dur offset-entry num-harm) (mapcar #'(lambda (xhrm xoff) (at xoff (amosc (hz-to-step (* (step-to-hz frq) xhrm)) (sac-env dur)))) (attk-list -1 (1- num-harm) (list num-harm)) (attk-list offset-entry (1- num-harm)))) (defun sac-left-right (l) (do* ((i 0 (1+ i)) (left () (if (evenp i) (cons (nth i l) left) left)) (right () (if (oddp i) (cons (nth i l) right) right))) ((= i (1- (length l))) (vector (apply #'sim left) (apply #'sim right))))) (defun st-sac (frq dur offset-entry num-harm) (sac-left-right (sac frq dur offset-entry (1+ num-harm)))) (defun st-sac-sequence () (scale 0.17 (sim (at 0.0 (st-sac as6 7.5 2.5 5)) (at 0.01 (st-sac b5 7.5 2.5 5)) (at 3.75 (st-sac e5 3.75 1.25 9)) (at 3.76 (st-sac g5 3.75 1.25 9)) (at 5.5 (st-sac d4 2 1.0 11)) (at 5.51 (st-sac gs3 2 1.0 11))))) (defun st-sac-demo () (ss (st-sac-sequence))) nyquist-3.05/demos/pmorales/readme.txt0000644000175000000620000000124610144436365017123 0ustar stevestaffHere there are a few sounds for Nyquist that I have coded for learning. Mostly are based on examples from Amsterdam Catalogue of CSound Computer Instruments,and some others are based on Computer Music Journal articles, Dodge & Jerse and F. R. Moore books. Karplus-Strong and Physical Modelling are implemented in Lisp. Albacete, Spain, 2 June 2.000 Pedro J. Morales. pmorales@iele-ab.uclm.es ---------------------------------------- Please see examples_home.htm in the parent folder for an index to these files. Note that there are "helper" functions in pjmg.lsp that you may need to load before you run the code in these other files. Roger B. Dannenberg rbd@cs.cmu.edu nyquist-3.05/demos/pmorales/a6.lsp0000644000175000000620000000212311466723256016154 0ustar stevestaff;;; SIMPLE SYNTHESIS ;;; Waveform + Envelope. Modulating the frequency, 2 ;;; coded by Pedro Jose Morales ;;; pmorales@iele-ab.uclm.es (setf *pmorales-path* (current-path)) (load (strcat *pmorales-path* "pjmg.lsp")) (defun saw-table () (setf *saw-table* (pwlv 1.0 1.0 0.0)) (setf *saw-table* (list *saw-table* (hz-to-step 1) T))) (if (not (boundp '*saw-table*)) (saw-table)) (defun cheap (frq-randi frq dur lfor lfoi) (mult (randi1 frq-randi dur) (fmosc frq (mult (const lfoi dur) (osc (hz-to-step lfor) dur *saw-table*))))) (defun callas (dur frq vib-r vib-w) (mult (pwl 0.1 1.0 (- dur 0.1) 1.0 dur) (fmosc frq (mult (const vib-w dur) (sine (hz-to-step vib-r) dur))))) (defun callas-demo () (ss (seq (sim (at 0.0 (cheap 80 a4 6.5 3 1000)) (at 2.5 (cheap 150 a5 6.5 3 750))) (callas 1 a4 5 24) (callas 0.5 e5 5 24) (callas 0.5 f5 5 24) (callas 1 a5 5 24) (callas 1 c6 5 24) (callas 1 e6 5 24) (callas 1 g4 5 24) (callas 1 f4 5 24) (callas 3 e4 5 24)))) nyquist-3.05/demos/largeclip.jpg0000644000175000000620000006457610144436365015766 0ustar stevestaffJFIFC     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(MsJ7JӼCj閗wPBqX,2P1\R\wK㯉TejR앶ViY]utWhzWbTLཅ,G0c+(Ue(8[GmFGנPĪҕ7FN;6(;MsJ7JӼCj閗wPBqX,2P1Fx+Xi!uH˻KN Yi9[4qH8b)3{9roͥ浵xKe/g7k5m~ۡtQEzgQ^ōދB ٮ -"rHcӭrկ줠ݕV.㯉38M7emiuG^^wt]R-2S{xZvD RFk]U%m{=]^CJTe];lgtڳP+ +5?|C]a{5#=ŤST6nT),zuCҼ l,4躤ZeƧ,-`81_יgN\ݻۚ_U){;_ݵKkۡtQEzgQ^ōދB ٮ -"rHcӭrկ줠ݕV.㯉38M7emiuG^^wt]R-2S{xZvD RFk]U%m{=]^CJTe];lgtڳP+ +5?|C]a{5#=ŤST6nT),zu@ ˋ M:}iOA:+K:Af1pïZ>mk{ۚy_uc.K^ֽ}s袊`(_ ; :\AA3ZE;Cf@22ǧZ_IAEɻ+l}]Q_gqn+];@ ˋ M:}iOA:+K:Af1pïZ)Wpqqj;fF1>r(8$(;MO7,l._oX^qqi @h4xEve7NΡY`L@0ּϯ~{)rZvW</}c˒׿{s_mmk\(3 (DxNEvek@NPٹP ֹjRPQrn+_vTqƜ`&zD4xEve7NΡY`L@0ּU\Zٵх O2I;;lgk (_ ; :\AA3ZE;Cf@22ǧZ4 ?,|Cݦ{ dhX :3߻\ݷK_X2mk[ZW<(L((#weC*# xrpN \=v_?xQ%pN\p<ʗ.ܓҩ|Լk5]hPGm2*I$/%҄6_?aN_ےU@+Mi4ŹM&I pr Ip3 5/iiWw.0@L I :%҉(/%҄eO_gYn|C+>+֖]6YgGE3vڻ гz4bJl?Qwҩ|}Klj CL-iV!$X\E {tQ2X /%҄6_?aN_ےU@+Z[KtYe=;m4b3+j3`3BOg> Z>hޡjv4y."=B:(,CK=Q_K?=a ^ ,m3f+'~EW}0WqXZE,VD $t-UقCvp|h_D5Mv2o?*7GԼx|-4N&bO5PǹP^GE#%/X a(JhS0!T (L>6 HH=>A$q%0Uabݎ٣ൺjƹMZIpVs[j*pqCK=Q_K?=a ^ "˿[d\˟8(邻 'şmvth!,BAj#,pI<:W]Ə,^;I\_g*/Oҩ|MC1ZIZ_i6kxCmV %@N3/X a(JhlaMwҪQ]wO>'+KM26BX hFYLy9W#>g8+g/zJ,ӚTTO9QNj4~m5ƛ{=MRHNYO  C^iMI]l|h_D,K;MOS H$T@8c5||R_ FD3g/zJ b'?+og[[y) I+)A }rkEגTh_:=%xOJ!EikqyYrH Uj9UMڝGJuSo]%҉(/%҄ gumn"Sd9v $ I> b'?+̫NTrSOȭJT2RQS^\i]-ݼN$ᕔ LT5릚=ԕ]Ə,^;IP|$Ծ+x2.5(t#NA\^xYu }q%Bس62I8 w1[JjC o[wGM_K?=a \mv_xP\i]-ݼN$ᕔ LQ5s m}~*d4Q],^%tW)NʛάMoНk_7nWXwa(X a(Jon5+FirHry$I'k/%҄ T`f"3iFEM{eqiwv4SA:7SVS =1PתjRW[YY\jWZZA-ċ0@UTrI$\YK=Q_K?=a \mpy~|OXBW]_K}7ⷃ.Zip,Y $`kZ=u+P7ZC6IH-,dWic'-]_w)Gai;[xw#U\d2HN/X a(JUѡ:)\V Rw[_%rwoOեƵ{,3Diܫ+ 뚟/zJ^ww[|1u5Veծg1 73*rp8K0vݗŚ>\v_K8z(L4bJk%҉+/G$v_xPqB$ዩb.ƭs %eHMjo"1$q="ea PIݞإ;`?b./%=Q]v_?xQ%q|h_Dҗc#h? (H>8=;4RGwo,,CG"0z,c`Mv_ѿG/$w^]E,Bd^KM[Rpx']o *?S__!T >8=;4RGwo,,CG"0z,c`MvN\p .ܓҩmw^]E,Bd^KM[Rpx']o_Yv_ s`+YEzgq~0x٢;Nky`eI`Ȭ9?5egFk62N?<̮P}#-p;=MIխ✰C=HD\=v_ ihlaM܇P+h<`Iާ5JNhdVRA ß#Mt_5;rg*_rOJq|}7ljB?LhQ\K X%$DapTO#Mu5Q$uY~L3DܒYEzgq~0x٢;Nky`eI`Ȭ9?5egFk62N?<̮P}#5{qkI嵻ua)$neVVeF_k6%ʏWגU@㍣`E$wz*ʒ;YI4r#k6?kD?*eF_k6/4Z]<ock_8(H>9\isH&B΍ٕ#\=v_iZk/c# ߒ?J;/4Z]q|':1~~uvWu6y(I(3`ee`{]şl֔TvLkO#Mu5W]o?ҷe15/ɜmQ]Ǥw49 mmjP!RQgF/?4E]qtoew %o}`kMwUӇOU?:];+??b[iZ$TyѰ{2=pk6?kJw?_rOJq|':?7ֿuO[2?6(;vWu6y(I(3`ee`{]şlָ:7XH2B(;/?4E]q|Y:/k/G$v_ ikO#Mu5WD??Ÿ_C|Y:/k6?kD/Oq|':?7ֿuF?ҷe0k_8(H,c`MvegFk6pn[C|':?7ֿu\m{s ΠWegFk6/?4E]{p Կ?ΙeF_k6/4Z]J3q ~Lh=##Mt_5]şlָR $yoGGeF_k6/4Z]qCc)U?:]şlָ,c`MvOg*R:g]o}`kMwTc+_ ƿ%3+6?k\mv_iZkK14?o}`kMwU0Wv_iZk#Mt_5?Kmv_ ikO#Mu5Qt~L3?6(;/?4E]q|Y:/k/G$v_ ikO#Mu5WD??Ÿ_C|Y:/k6?kD/Oq|':?7ֿuF?ҷe0k_8(H,c`MvegFk6pn[CQEzGegFk6/?4E]qÀtHr?7ֿu\mv_ ihOS~~u/?4E]q|Y:/h?T~ t6/4Z]q|':V &KgEWqşlָ,c`Mvҗc#h?;/4Z]q|&,0K4veB$:ub>=WJORbUK! ,c`MvegFk?~ t6/4Z]q|&,0K4veB$:ub>=RǴofp5I~L袊=3#Mt_5]şlָR $yoGGeF_k6v&ޖ;K\K4A%񏘍Ŧ$ 2Iqpu-1_;M?&nn޶i5+#Mt_5]şl֜S'8}`kMwUqֵGiaZKfc$1āFI.8ia*Ze52_6z/3+6?k\mv_iZkK14?o>[w$'Lx$Py3]D9$S|تtQ_;iЩ>lmfQn޶iWegFk6/?4E]9 8/Oq|':5GMR{4O)1.gE 5C2Iv]Kի%nݰUWjzGEWy靗şlָ,c`Mvҗc#h?;/4Z]q|*K{I|W]K*Gxv9TXh xOҶ]_GxLʲ|k]pcB.v;{N-'J?V6EeAB$טe_:_үB1FI[g'1VPӵ\V}ޱsL_zkVoៈ$hr%VK8ұ99d7+|E _tMj(u19iQqO]cB.?.iV5#OONN jqi:U>H=ڴfE2/+-*9&4uǫg+|: t604"(wd^Yק$N8%w՞j3N@DsV#32A soXй˯=[>[/bӥqc+j%$|DŽ̫*ؗ f???.iWk^WЯ\涝.fpʖOIa2 |w"ïKU57ٮnⅉkB55lޱsL_zkVoៈ$hr%VK8ұ99d7+|E _tMj(u19iQqO]cB.?.iV5#OONNmoWBҮmus[N38eKHu'र >s_?.iVώVu`\mp`hPQmhײ<1 $)rܼ^-|HFfF M"UdÏ+ 9A?\?ȭ1¸xz1>cfUlK决_M4uǫ{t͘K,DgB%2dg A1+|: tZa4޼\xbUQ>NKm񿷬\?՛g 48U?Ffgz3])Vqx6JN%@:mrk{qxoķSs"u3!QD\ʪ` UR^hOݷXʼ1*^hT_?[oXй˯=]574 9hq%iXx2eO"/:XSQ:珘ʴ8.tޱsL_z4uǫ'g_a|S֬5mNG;Ktb89$!cB.oJ}KE{:n,ı7Vn9$ 5~>|yx`q?M/ goXй˯=XWw?=O:O;/ȭ2w"ïKk 2O.GeO"/:XW]?V`a\m"Ob?ƿv^;[eӥqxEo_Nb?GOHb&qxEoNeO"/:XQ?a++|: t6/ȭ2 \7/ SKxEoNeO"/:XWFĿ؏"]Vu`\mv^;[eӥ&amv^[/bӥqxEoNc.!?h=#//덮+|: t6p#/v^[/bӥqxEoNч-o/"!6#kHWe_:_]Vu`F#/"g]?V`a\mv^[/bӥ/CKfq8(Hw"ïKk//덮ru??V`a\mv^[/bӥqa[KHa? xEo_Ne_:_ш-?"a6oHeO"/:XW]?V`aF7KPc:\N6(;/ȭ2w"ïKk')r<ܿ2O.GeO"/:XW]?V`a\m"Ob?ƿv^;[eӥqxEo_Nb?GOHb&qxEoNeO"/:XQ?a++|: t6/ȭ2 \7/ SKQEzGe_:_]Vu`\mp?.G_ "_K k5?ڃQ 2KV1baoMkҿO5e?'i.#?qQEwx.|<๊X㴼fE_ n V]((B;z]Ct%C#Q\=vZ {V}:_;4f]c+=O9#ҿO5e?'k-o/"#5@+//덮\1YֵxI :{P~؞з?"baMҿO5e?'i.#?qQEwxEo_Nq>-XK=OUQs,evǘz_;4f]c+=O9 +U;jOW]$wտN6p#/vZW{I}F촯#'qa[KHa? jG|1a[Ikcڷb?GOHb&qi_G|Oa'IkҿO4c.!?h=#cڷeo'ӫru?$wQ6-+H=>\m"Ob?ƿvZ {V}:_#u&amvZW{I}F촯#'/CKfq8(H_#uqjG|1a[Ik')r<ܿ2O.Ge?'kJ;i?OFĿ؏"]$wտN6-WH?=>F#/"g]$wQ6-+H=>F7KPc:\N6(;-WH?=>\mvZ {V}: \7/ SKi_G|Oa'IkҿO5ч-o/"!6#kHWeo'ӫU;jOQ-?"a6oHe?'kJ;i?Oэ?a+U;jOW]$wտN6p#/vZW{I}F촯#'qa[KHa? jG|1a[Ikcڷb?GOHb&qi_G|Oa'IkҿO4c.!?h=#cڷeo'ӫru?Q]Ǥw|+O؆wm۴0`z촯#'q\>N4?`$R'o#D~,wxqٷ}% ylI cڷуWrW`RzsN+% /muE$v"DDg0݇4lcL3ҿO4bN2_/1׊Uo&|kkD~,wxqٷ}% ylI cڷb4C9/ ƮyЦގje%EmQ]wğ|;vJ֑xSIm`QKt9C\=vZW{I}F^>қ25s[yfo&k|woY !Y[6/$-<\=vZ {V}:0jR* *ToYNwIA]$wտN66O>"ikHEKDwzb砣x:׏ceU}9qonIx-c!ә@n'-kU;jOQ\Ε>J$cW<Ҿ#+U;jOW]ŕ|meXV2[1|Ȍb`f+~N3\=pa/R2/07I&|O-O#41 5o[ d"s3hdpjG|1a[Ih{R*"aWJ)%|+cڷqopeɤAa vӉH?a# (>WJE%q_1TjH_N 񒿑qonIx-c!ә@n'-kU;jOQ\Ε>J$cW<Ҿ#+U;jOW]=FUhKHcH6HͽJm*t `G\7hu)~/~ f)g;Y#M?$ռEn1KiNݠ@͓5eo'ӫQ)K|^5*//+pU;jOW]åF&YeKN$6H˱*tmRQ|7E~-/c_$M짯2=w[2im9۴r`fz_#uSNK5sʍ+)۩~1W8(L_#uq\[Fhb2i>"KbHݴngGkM?Fy{NwɵgqehuZ(ve_2S٘'`cQ]$wտN6%T{R*#Uj9䯑~MvZ {V}:/muE$v"DDg0݇4lcL31-F$oP5v4^n]ŕnhV1)|Lfb;i-~Fs\=vZ {V}:]ST|y4Jjs◥6(;-WH?=>\mwuGF;_GrU"3ZIL|61pkuRgMuS?ɧ;|mW7 j} Ubu99M s/Y[;zo'뎳,1N0vWR_9#B7 rmJ;M/ҿO5qG> hK=OJ#*I;Aǘz ӫ^̿au)tp;-WH?=>\mw&M77-^)..=XAl{d,Jɒ~8z0N2z2O9 J;i?O]ƇequcGmiau }ѹr{HҤQeo'ӫ&E%ާ# solP2YO'qQvCOHbݫa(;-+H=>\mwK K;ƅHa3FEu"z4׷/"iĥkM_#uqx I%SoJ!+!PIPdF38NOKeJzrA]$wQ6-+H=>O%(qaU;jOW]LjmO?ഝY/5=V ²Kyn>[cXZgLXl2}f(;-+H=>\mvZW{I}F5@_#uqx I%SoJ!+!PIPdF38 IYsR&We?'kJ;i?O \G?kcڷqY\Z|A,1Z\mvZW{I}F5@_#uqkW<,K w:֯,"OBO#`t\5*2kvZW{I}F촯#'\mvZ {V}:Gh _D6(;-+H=>\mvZW{I}F5@;zo'Ha޾^*+_?xJ,gD~PEoNυJ[M#Ē<2 >WKz_5jQ_k7j#$(!a#4   zNiQm&Zܫ鶺sbV*cޒm.6M(H7+U*K$Gt1^wk xRmn")cM~xсAQ[?5_#ך(թ*qRi&sȍ,U eJjrOY4TxEo_NϊaRYT($QA c qTdԒq|-9ҥjmjmW:tF-[s7&4Je~+5?{RZ2$+;hEb7)μ!5φ<]xB{tֶL^YCw&֎du?!E,qYK "+ȭԌ0g0=T\=lcڗ'Mko>q7qKmhGSƌ2 XRK$WX3Gi{R'3/ȭ2[g ]/.Լ_=[[x존(Ǔj "GbqX.)ʤb]okW~;*ZRE "Ƣ+=c44RPO\ RN~F c&zNj/Oy.}+(n?1$̎d c[ +=y"ZԚzɯ+#OBYRd$OvZrzj}~Vk'彗~+44RPO\ RN~F c&zNj/Oy.}+(n?1$̎dTZ,7N/WoI۰g^-;]J/VdO{vf5w>_ myZ-X.J#z 'AP?JX'vԚge QGv %Z2Eye R$Z9lk%tG5CJIB)4Vb_k#OBYSe5y4׻oS\ +]cF}iZ >XwT` aX> o\uj^/]I-VvPE~cɵcG#8,kPn(7&Oy7Ḭ^AE9I&QEzǸQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEnyquist-3.05/demos/shepard.lsp0000644000175000000620000001532010144436365015447 0ustar stevestaff; Shepard tones and paradoxes ; to use try ; (playscale (majorscale 60)) ; (playscale (minorscale 60)) ; (playscale (chromascale 60)) ; (playparadoxscale (chromascale 60)) ; for shepard sweeps, try ; (play (sheptone-sweep 60 60 2 72 60 12 4)) ; the signature of sheptone-sweep should tell what the parameters do ; (defun sheptone-sweep (pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 ; overtonesemi overtones ; &optional (wavetable *sine-table*)) ; Some notes about how this works: ; Shepard tones consist of harmonics that are an octave apart, thus ; the ratios are 1, 2, 4, 8, 16, etc. Note that the pitch is ambiguous ; in the sense that there could be a missing fundamental at 0.5, 0.25, etc. ; The other trick is that the spectral shape is constant. The amplitude ; of each harmonic is a function of its absolute frequency. Here, the ; shape is triangular so that as the frequency sweeps upward, harmonics ; (which are ramping up in frequency) fade in, reach a maximum, and fade out. ; ; In this implementation, each harmonic is generated using an FM oscillator ; controlled by a frequency ramp. The harmonic is multiplied by an envelope ; to implement the spectral shape function. The envelope is computed by ; running the frequency control (with some scaling) into a SHAPE function ; that uses a triangular table to implement the spectral shape. ; ; Warning: Although I have not analyzed this code too carefully, I (RBD) ; believe that the oscillators keep sweeping up to higher and higher ; frequencies even after the amplitude drops to zero. This is not only ; wasteful, but when oscillators start to alias, they run slower. If you ; generate a very long Shepard tone with harmonics spanning many octaves, ; the run time could get to be very large. A better implementation would ; start the harmonics when they enter the non-zero part of the spectral ; envelope and end them when they leave it. (setf *onepi* 3.141592654) (setf *twopi* (* 2 pi)) (setf *halfpi* (/ pi 2)) ; envshaper is a raised cosine curve used to control ; the spectral shape. Its domain is 0 to 2 ; it transforms (0 2) into 0 1 ; it has to be used like ; (shape s (envshaper) 1) (defun envshaper () (mult (sum 1 (hzosc (const (/ 1.0 2.0) 2) *table* 270)) 0.5)) ; some utility functions ;; ISEQ-HELPER -- generates an integer sequence (defun iseq-helper (a b) (let ((mylist '())) (dotimes (i (1+ (- b a)) (reverse mylist)) (setf mylist (cons (+ a i) mylist))))) ;; ISEQ -- sequence of integers from a to b (defun iseq (a b) (if (> a b) (reverse (iseq-helper b a)) (iseq-helper a b))) (defun floor (x) (if (< x 0) (1- (truncate x)) (truncate x))) ; the main part (defun sheptone-sweep-helper (pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 overtonesemi overtones &optional (wavetable *sine-table*)) (let ((mytone (const 0 duration)) (maxovertones (+ (floor (/ (float (max (abs (- pitch-1 centerpitch-2)) (abs (- pitch-1 centerpitch-2)))) overtonesemi)) overtones 2)) (ampshaper (envshaper))) ;; synthesize and sum maxovertones partials (dolist (i (iseq (- maxovertones) maxovertones) mytone) (progn ;; partials start at pitch-1, spaced by overtonesemi (normally 12) (setf startpitch (+ pitch-1 (* i overtonesemi))) ;; partials end at pitch-2 + offset (setf endpitch (+ pitch-2 (* i overtonesemi))) ;; f is the frequency modulation (in hz) (setf f (pwe 0 (step-to-hz startpitch) duration (step-to-hz endpitch))) ;; p is the pitch in steps (setf p (pwl 0 startpitch duration endpitch)) ;; c is the centerpitch curve ;; (probably we could compute this outside the loop) (setf c (pwl 0 centerpitch-1 duration centerpitch-2)) ;; normwidthfactor is used to map pitch curves into the spectral shape ;; function (range 0 to 2) (setf normwidthfactor (/ 1.0 (* overtones overtonesemi))) ;; a is the amplitude envelope: f(p - c) (setf a (shape (mult (diff p c) normwidthfactor) ampshaper 1)) ;; voice is one partial (setf voice (mult a (hzosc f wavetable))) ;; sum the partials into mytone (setf mytone (sum mytone voice)) ) ))) (defun sheptone-sweep (pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 overtonesemi overtones &optional (wavetable *sine-table*)) (normalize ;; note: you might not want to normalize as is done here ;; use an envelope to get a smooth start and stop (mult (sheptone-sweep-helper pitch-1 centerpitch-1 duration pitch-2 centerpitch-2 overtonesemi overtones wavetable) (env 0.05 0 0.05 1 1 1 duration)))) ;; SHEPTONE is a special case of sheptone-sweep. ;; The spectral centroid and pitch is constant. (defun sheptone (pitch centerpitch duration overtonesemi overtones &optional (wavetable *sine-table*)) (sheptone-sweep pitch centerpitch duration pitch centerpitch overtonesemi overtones wavetable)) (defun majorscale (basepitch) (mapcar (lambda (x) (+ basepitch x)) '(0 2 4 5 7 9 11 12))) (defun minorscale (basepitch) (mapcar (lambda (x) (+ basepitch x)) '(0 2 3 5 7 8 10 12))) (defun chromascale (basepitch) (mapcar (lambda (x) (+ basepitch x)) (iseq 0 12))) ;; MAKE-TABLE turns a function of 0-1 into a lookup table (defun make-table (func-exp points) (let ((table (make-array points))) (dotimes (i points) (setf (aref table i) (funcall func-exp (/ (float i) (float points))))) (list (snd-from-array 0.0 points table) (hz-to-step 1) T) )) (defun erich-wave (skew) (make-table (lambda (x) (if (< (abs skew) 0.000001) (sin (* *twopi* x)) (* (/ (sin (* *twopi* x)) (- (/ 1.0 skew) (cos (* *twopi* x)))) (/ (sqrt (- 1.0 (* skew skew))) skew)))) 2048)) ;; NORMALIZE -- normalize a sound ;; (defun normalize (s &optional (maxvol 0.8) (maxlen 44100)) (let* ((mysound s) (vol (peak mysound maxlen))) (scale (/ (float maxvol) vol) mysound))) (defun playsafe (s) (play (normalize s))) ;; PLAYSCALE uses SHEPTONE to synthesize a scale that goes up on every ;; step, but never actually ends up an octave higher ;; (defun playscale (scaleseq &optional (duration 1) (wavetable *sine-table*)) (mapcar (lambda (x) (play (sheptone x 60 duration 12 4 wavetable))) scaleseq)) ;; PLAYPARADOXSCALE uses sheptone to go up by half steps, yet end up ;; an octave lower than it starts ;; (defun playparadoxscale (scaleseq &optional (duration 1) (wavetable *sine-table*)) (mapcar (lambda (x y) (play (sheptone x y duration 12 4 wavetable))) scaleseq (reverse scaleseq))) nyquist-3.05/demos/wind_tutorial.htm0000644000175000000620000000271710144436365016705 0ustar stevestaff Wind Tutorial

    Wind Tutorial

    This page describes a "wind" effect created by Alex. The basic function is as follows:

    (defun wind (&optional (dur 3) (scal 3) (cps 590) (bw 40))
      (stretch dur
        (mult (env 0.07 0.08 0.1 1 0.6 0.8 1)
    	  (sum 
    	    (reson (scale scal (noise)) cps bw 2)
    	    (reson (scale (mult scal 1.13) (noise)) 
                       (mult cps (pwl 0 0.74 0.2 0.96 0.5 0.8 0.75 1.16 0.9 0.97 1 0.74 1))
                       (mult bw 1.042)
                       2)))))

    The basic idea is to use bandpassed noise to create the sound of wind. In this example, two bandpass filters are added together. The first uses a fixed center frequency and bandwidth, and the second uses a piece-wise linear function to control the center frequency. The entire sound is multiplied by an envelope and stretched to the desired duration. Note how several optional parameters can be used to change the default behavior.

    A slight elaboration of the wind function uses several copies of wind in sequence with slight overlap:

    (defun multiwind ()
      (simrep (i 4) (at (* i 2.9) (wind))))

    One problem with this approach is that the wind sound becomes periodic. This could be solved by using noise or random numbers to generate the center frequency variation rather than a fixed envelope.

     

    nyquist-3.05/demos/osc-test.lsp0000644000175000000620000000645411466723256015600 0ustar stevestaff(load "nyinit.lsp") (osc-enable t) (autonorm-off) (snd-set-latency 0.1) ;; TEST 1 -- using hzosc (defun hzosc-osc () (hzosc (sum 500 (mult 500 (lp (snd-slider 0 (local-to-global 0) *default-sound-srate* 10) 2.0))))) ; (play (hzosc-osc)) ;; TEST 2 -- using granular synthesis (if (not (boundp '*granfile*)) (load "gran.lsp")) ;; this is modified from gran.lsp to allow pitch-dev to be continuous ;; (defun sf-granulate (filename grain-dur grain-dev ioi ioi-dev pitch-dev-factor &optional (file-start 0) (file-end 0)) (let (orig n env actual-grain-dur step-size (avg-ioi (+ ioi (/ ioi-dev 2.0))) (file-dur (sf-dur filename)) (dur (get-duration 1))) (setf n (truncate (/ dur avg-ioi))) (cond ((< file-dur file-start) (error "sf-granulate: file-start is after end of file!")) ((< file-dur file-end) (error "sf-granulate: file-end (offset) exceeds file duration!")) ((< file-dur (+ file-start file-end)) (error "sf-granulate: file-start + file-end > file duration!"))) (setf file-dur (- file-dur file-start file-end)) (setf step-size (/ file-dur n)) ;(display "sf-granulate" step-size file-dur n) (stretch-abs 1.0 (let () (seqrep (i n) (let () (setf actual-grain-dur (real-random grain-dur (+ grain-dur grain-dev))) (setf env (stretch actual-grain-dur (one-minus-cosine))) (force-srate *sound-srate* (stretch (real-random (+ 0.1 (* pitch-dev-factor (get-slider-value 0))) 1) (sound2 (set-logical-stop (mult (cue env) (s-read filename :time-offset (+ file-start (* step-size i)) :dur actual-grain-dur)) (real-random ioi (+ ioi ioi-dev)))))))))))) (defun gran-osc () (scale 0.8 (stretch 4 ; total is stretch * 10 seconds, i.e. 4 -> 40s (simrep (i 4) (sf-granulate *granfile* 0.04 0.0 0.02 0.001 10 0 0))))) ;(play (gran-osc)) ;; TEST 3 - piano sequence (defun piano-osc () (if (not (fboundp 'piano-note)) (load "pianosyn")) (seqrep (i 200) (piano-note (+ 0.05 (* 0.2 (get-slider-value 1))) (round (+ (real-random c1 c2) (* (get-slider-value 0) 60))) 100))) ;; TEST 4 - minimoog filter sweep (defun moog-osc () (setf *moog-dur* 10) (let ((cutoff (lp (snd-slider 0 (local-to-global 0) *default-sound-srate* *moog-dur*) 2.0)) bandwidth) (setf cutoff (scale 2000 cutoff)) (setf cutoff (snd-maxv cutoff (const 20 *moog-dur*))) (mult (pwl 1 1 (- *moog-dur* 1) 1 *moog-dur*) (scale 2 (reson (stretch *moog-dur* (osc-saw 50)) cutoff (mult cutoff 0.1) 2))))) ; (scale 1000 (ramp 5)))) ; (* 1000.0 (get-slider-value 0)))) (format t "(play (hzosc-osc)) -- play oscillator controlled by slider 0\n") (format t "(play (gran-osc)) -- play granular synthesis controlled by slider 0\n") (format t "(play (piano-osc)) -- play piano sequence controlled by slider 0, duration by slider 1\n") (format t "(play (moog-osc)) -- play minimoog with filter controlled by slider 0\n")nyquist-3.05/demos/arp.sal0000644000175000000620000000603311536000246014554 0ustar stevestaff;; arpeggiation examples ;; Roger B. Dannenberg ;; An arpeggiator is a function that plays sequences of pitches in a pattern ;; The typical patterns are very much like the palindrome pattern generator ;; in Nyquist, so this example shows how to make arpeggiation patterns. ;; A simple arpeggiation of a major-7th chord ;; define function arp1() begin with pat = make-palindrome(list(c4, e4, g4, b4)) exec score-play(score-gen(score-len: 17, ioi: 0.2, pitch: next(pat))) end ;; This will play the simple arpeggio: ;exec arp1() ;; We can make an upward only arpeggiator using the cycle pattern: ;; define function arp2() begin with pat = make-cycle(list(c4, e4, g4, b4)) exec score-play(score-gen(score-len: 17, ioi: 0.2, pitch: next(pat))) end ;; This will play it: ;exec arp2() ;; Arpeggios might sound a bit nicer with some legato or overlap, which ;; is easy to do by changing the duration (dur:) parameter: ;; define function arp3() begin with pat = make-cycle(list(c4, e4, g4, b4)) exec score-play(score-gen(score-len: 17, ioi: 0.2, dur: 0.4, pitch: next(pat))) end ;; This will play it: ;exec arp3() ;; It might be more useful to add some parameters. They are: ;; ;; pitches -- a list of pitches to arpeggiate ;; reps -- how many notes to generate ;; ioi -- inter-onset interval ;; dur -- a keyword parameter (optional), an ioi multiplier. Use 1 ;; to make the duration equal the ioi, use 2 for double the ioi ;; instr -- a keyword parameter (must be quoted), naming an instrument ;; ;; Any parameter may be a pattern. ;; Returns a score ;; define function arp4(pitches, len, ioi, dur: 1, instr: quote(note)) begin with n = next(len), pat = make-cycle(next(pitches)) return score-gen(score-len: n, ioi: next(ioi), dur: next(dur), name: next(instr), pitch: next(pat)) end ;; Since arp4 returns a score, you can play it like this: ; exec score-play(arp4(list(c4, e4, g4, b4, c5), 20, 0.15, 3)) ;; This will play the simple arpeggio: ;exec arp4() ;; Note: it might be nice to extend the parameters to let the user select ;; the arpeggiation style (up, down, up-down, up-down with elision), but ;; these can be specified just by writing out the full pattern, e.g. to ;; get up-down with elision, write list(c4, e4, g4, b4, c5, b4, g4, e4), ;; so I won't add that feature. ;; Makeing sequences of arpeggios ;; First define some pitch patterns: define variable c7 = list(c4, e4, g4, bf4, c5, bf4, g4, e4), bf7 = list(bf3, d4, f4, af4, bf4, af4, f4, d4), af7 = list(af3, c4, ef4, gf4, af4, gf4, ef4, c4), g7 = list(g3, b3, d4, f4, g4, f4, d4, b3) ;; now call arp4 to make some scores and splice them together define function arp-seq() begin with score = nil loop for pitches in list(c7, bf7, af7, g7, c7) for len in list(16, 16, 16, 16, 33) set score = score-append(score, arp4(pitches, len, 0.13, 3)) end return score end ;; make the score and play it exec score-play(arp-seq()) nyquist-3.05/demos/voice_synthesis.htm0000644000175000000620000002433110144436365017233 0ustar stevestaff Voice Synthesis Tutorial

    Voice Synthesis Tutorial

    Nyquist voice synthesis instrument by Eduardo Reck Miranda.

    ;---------------------------------------------------------------------------
    ; Nyquist voice synthesis instrument by Eduardo Reck Miranda
    ;
    ; Implements a geometrical articulator for tongue position (h p) and 
    ; lips rouding (r) 
    ;
    ;---------------------------------------------------------------------------
    ; Geometrical articulator: the following FORMx functions estimates the formant
    ; values from the positions of the three articulators p h and r, where:
    ; p = horizontal position of the tongue: 0.0 = front and 1.0 = back 
    ; h = vertical position of the tongue: 0.0 = low and 1.0 = high
    ; r = rounding of the lips: 0.0 = spread -> 1.0 rounded
    ;---------------------------------------------------------------------------
    ; FORM1: converts p-h-r articulators to first formant frequency
    ;---------------------------------------------------------------------------
    (defmacro form1 (p h r)
      `(+ (* (+ (* (+ (- 392) (* 392 ,r)) (expt ,h 2))
                (* (- 596 (* 668 ,r)) ,h) 
                (+ (- 146) (* 166 ,r))) 
             (expt ,p 2))
     
          (* (+ (* (- 348    (* 348 ,r)) (expt ,h 2)) 
                (* (+ (- 494) (* 606 ,r)) ,h) 
                (- 141 (* 175 ,r)))
             ,p)
     
          (+ (* (- 340 (* 72 ,r)) (expt ,h 2)) 
             (* (+ (- 796) (* 108 ,r)) ,h)
             (- 708 (* 38 ,r)))
          ))
    
    ;---------------------------------------------------------------------------
    ; FORM2: converts p-h-r articulators to second formant frequency
    ;---------------------------------------------------------------------------
    (defmacro form2 (p h r)
      `(+ (* (+ (* (+ (- 1200) (* 1208 ,r)) (expt ,h 2))
                (* (- 1320 (* 1328 ,r)) ,h) 
                (- 118 (* 158 ,r))) 
             (expt ,p 2))
     
          (* (+ (* (- 1864 (* 1488 ,r)) (expt ,h 2)) 
                (* (+ (- 2644) (* 1510 ,r)) ,h) 
                (+ (- 561) (* 221 ,r)))
             ,p)
     
          (+ (* (+ (- 670) (* 490 ,r)) (expt ,h 2)) 
             (* (- 1355  (* 697 ,r)) ,h)
             (- 1517 (* 117 ,r)))
          ))
    
    ;---------------------------------------------------------------------------
    ; FORM3: converts p-h-r articulators to third formant frequency
    ;---------------------------------------------------------------------------
    (defmacro form3 (p h r)
      `(+ (* (+ (* (- 604 (* 604 ,r)) (expt ,h 2))
                (* (- 1038 (* 1178 ,r)) ,h) 
                (+ 246 (* 566 ,r))) 
             (expt ,p 2))
     
          (* (+ (* (+  (- 1150) (* 1262 ,r)) (expt ,h 2)) 
                (* (+ (- 1443) (* 1313 ,r)) ,h) 
                (- (- 317) (* 483 ,r)))
             ,p)
     
          (+ (* (- 1130 (* 836 ,r)) (expt ,h 2)) 
             (* (+ (- 315)  (* 44 ,r)) ,h)
             (- 2427 (* 127 ,r)))
          ))
    
    
    ;---------------------------------------------------------------------------
    ; FORM4: converts p-h-r articulators to fourth formant frequency
    ;---------------------------------------------------------------------------
    (defmacro form4 (p h r)
      `(+ (* (+ (* (+ (- 1120) (* 16 ,r)) (expt ,h 2))
                (* (- 1696 (* 180 ,r)) ,h) 
                (+ 500 (* 522 ,r))) 
             (expt ,p 2))
     
          (* (+ (* (+  (- 140) (* 240 ,r)) (expt ,h 2)) 
                (* (+ (- 578) (* 214 ,r)) ,h) 
                (- (- 692) (* 419 ,r)))
             ,p)
     
          (+ (* (- 1480 (* 602 ,r)) (expt ,h 2)) 
             (* (+ (- 1220)  (* 289 ,r)) ,h)
             (- 3678 (* 178 ,r)))
          ))
    
    ;---------------------------------------------------------------------------
    ; ADSR-SMOOTH: a standard ADSR envelope
    ;---------------------------------------------------------------------------
    (defun adsr-smooth (signal dur)
    	 (mult signal (env 0.1 0.2 0.5  1.0  0.8  0.4 dur)))
    ;---------------------------------------------------------------------------
    ; VIBRATO: generates vibrato
    ; vib-rate = vibrato rate in Hz
    ; dur = duration in seconds
    ;---------------------------------------------------------------------------
    (defun vibrato (vib-rate dur)
    	(osc (hz-to-step vib-rate) dur))
    
    ;---------------------------------------------------------------------------
    ; PULSE-TABLE: build table for generating a pulse signal
    ; harm = number of harmonics
    ;---------------------------------------------------------------------------
    (defun pulse-table (harm)
      (abs-env ;prevent any timewarping in the following
        (let ((table (build-harmonic 1 2048)))
          (cond ((> harm 1) ;sum remaining harmonics
    		 (setf harm (- harm 1))
                 (dotimes (i harm)
                   (setf table (sum table (build-harmonic (1+ i) 2048))))))
          table)))
    
    ;---------------------------------------------------------------------------
    ; PULSE-WITH-VIBRATO: generate pulse with vibrato
    ; step = pitch in steps
    ; duration = duration in seconds
    ; vib-rate = vibrato rate in Hz
    ;---------------------------------------------------------------------------
    (defun pulse-with-vibrato (step duration vib-rate)
      (let (harm freq)
        (setf freq (step-to-hz step))
        (setf harm (truncate (/ 22050 (* 2 freq))))
        (setf table (scale (/ 1.0 harm) (pulse-table harm)))
        (fmosc step (vibrato vib-rate duration) (list table (hz-to-step 1) t))))
    
    ;---------------------------------------------------------------------------
    ; VOICING-SOURCE: generate voicing source: pulse with vibrato + LPFs
    ; step = pitch in steps
    ; duration = duration in seconds
    ; vib-rate = vibrato rate in Hz
    ;---------------------------------------------------------------------------
    (defun voicing-source (step duration vib-rate)
    	(lp
    	  (lp 
    	    (pulse-with-vibrato step duration vib-rate) 
    		(*  1.414 (* 2 (step-to-hz step)))) 
    		(*  1.414 (* 4 (step-to-hz step)))))
    	
    ;---------------------------------------------------------------------------
    ; NOISE-SOURCE: generate noise source: noise + offset oscillator + LPF
    ; step = pitch in steps
    ; duration = duration in seconds
    ; vib-rate = vibrato rate in Hz
    ;---------------------------------------------------------------------------
    (defun noise-source (step duration vib-rate)
    	(lp 
    	  (sum 
    		(noise duration)
    		(fmosc step (vibrato vib-rate duration))) 8000))
    
    ;---------------------------------------------------------------------------
    ; SOURCE: generate source signal: voicing + noise sources
    ; freq = fundamental frequency in Hz
    ; duration = duration in seconds
    ; vib-rate = vibrato rate in Hz
    ; voicing-scale = percentage of voicing in the resulting signal (0.0 -> 1.0)
    ; noise-scale = percentage of noise in the resulting signal (0.0 -> 1.0)
    ;---------------------------------------------------------------------------
    (defun source (freq duration vib-rate voicing-scale noise-scale)
    	(sum
    		(scale voicing-scale (voicing-source (hz-to-step freq) duration vib-rate))
    		(scale noise-scale (noise-source (hz-to-step freq) duration vib-rate))))
    
    
    ;---------------------------------------------------------------------------
    ; MAKE-SPECTRUM: formant filters
    ; freq = fundamental frequency in Hz
    ; dur = duration in seconds
    ; vib-rate = vibrato rate in Hz
    ; v-scale = amplitude scaling for the voicing source
    ; n-scale = amplitude scaling for the noise source 
    ; p = horizontal position of the tongue (0.0 = front -> 1.0 = back) 
    ; h = vertical position of the tongue (0.0 = low -> 1.0 = high)
    ; r = rouding of the lips (0.0 = spread -> 1.0 = rounded)
    ;---------------------------------------------------------------------------
    (defun make-spectrum (freq dur vib-rate v-scale n-scale p h r)
    	(let ((src (source freq dur vib-rate v-scale n-scale)))
     		(setf spectrum
      			(sim	
       				(reson src (form1 p h r) 50 1)
       				(reson (scale-db (- 10) src) (form2 p h r) 70 1)
       				(reson (scale-db (- 14) src) (form3 p h r) 110 1)
       				(reson (scale-db (- 20) src) (form4 p h r) 250 1)))))
    			
    ;---------------------------------------------------------------------------
    ; SYNTHESISE: the synthesise function
    ; Simplified version of the instrument used by the agents discussed in Chapter 6.
    ; f0 = pitch frequency
    ; w1 = amplitude of voicing source (min = 0.0 max = 1.0)
    ; w2 = amplitude of noise source (min = 0.0 max = 1.0)
    ; a = horizontal position of the tongue (0.0 = front -> 1.0 = back) 
    ; b = vertical position of the tongue (0.0 = low -> 1.0 = high)
    ; c = rouding of the lips (0.0 = spread -> 1.0 = rounded)
    ; fm = vibrato rate (in Hz)
    ; h = duration in seconds
    ;---------------------------------------------------------------------------
    (defun synthesise (f0 w1 w2 a b c fm h)
    	(adsr-smooth (make-spectrum f0 h fm w1 w2 a b c) h))
    		
    ;=== The code for the instrument ends here ===
    
    ;---------------------------------------------------------------------------
    ; Test the SYNTHESISE function with different positions of the articulators
    ;
    ; Running steps:
    ; 1 - run Nyquist
    ; 2 - load "articulator.lsp"
    ; 3 - type (play (vowel-1)) to synthesise the first test, and so on
    ;---------------------------------------------------------------------------
    (defun vowel-1 ()
    	(synthesise 220 1.0 0.005 0.0 0.0 0.0 5.6 1.0))
    
    (defun vowel-2 ()
    	(synthesise 220 1.0 0.005 0.0 0.0 1.0 5.6 1.0))
    
    (defun vowel-3 ()
    	(synthesise 220 1.0 0.005 0.5 0.0 0.0 5.6 1.0))
    
    (defun vowel-4 ()
    	(synthesise 220 1.0 0.005 0.5 0.0 1.0 5.6 1.0))
    
    (defun vowel-5 ()
    	(synthesise 220 1.0 0.005 1.0 0.0 0.0 5.6 1.0))
    
    (defun vowel-6 ()
    	(synthesise 220 1.0 0.005 1.0 0.0 1.0 5.6 1.0))
    
    (defun vowel-7 ()
    	(synthesise 220 1.0 0.005 0.0 0.5 0.0 5.6 1.0))
    
    (defun vowel-8 ()
    	(synthesise 220 1.0 0.005 0.0 0.5 1.0 5.6 1.0))
    
    (defun vowel-9 ()
    	(synthesise 220 1.0 0.005 0.5 0.5 0.0 5.6 1.0))
    
    (defun vowel-10 ()
    	(synthesise 220 1.0 0.005 0.5 0.5 1.0 5.6 1.0))
    
    (defun vowel-11 ()
    	(synthesise 220 1.0 0.005 1.0 0.5 0.0 5.6 1.0))
    
    (defun vowel-12 ()
    	(synthesise 220 1.0 0.005 1.0 0.5 1.0 5.6 1.0))
    
    (defun vowel-13 ()
    	(synthesise 220 1.0 0.005 0.0 1.0 0.0 5.6 1.0))
    
    (defun vowel-14 ()
    	(synthesise 220 1.0 0.005 0.0 1.0 1.0 5.6 1.0))
    
    (defun vowel-15 ()
    	(synthesise 220 1.0 0.005 0.5 1.0 0.0 5.6 1.0))
    
    (defun vowel-16 ()
    	(synthesise 220 1.0 0.005 0.5 1.0 1.0 5.6 1.0))
    
    (defun vowel-17 ()
    	(synthesise 220 1.0 0.005 1.0 1.0 0.0 5.6 1.0))
    
    (defun vowel-18 ()
    	(synthesise 220 1.0 0.005 1.0 1.0 1.0 5.6 1.0))
     
    ;; play everything
    (defun vowel-n (n) (funcall (intern (format nil "VOWEL-~A" n))))
    
    (defun play-all-vowels ()
      (autonorm-off)
      (dotimes (i 18) (play (scale 20 (vowel-n (1+ i)))))
      (autonorm-on))
    
    ; (play-all-vowels) will play everything in sequence
    
    nyquist-3.05/demos/piano.htm0000644000175000000620000000523410144436365015124 0ustar stevestaff Untitled Document

    Piano Synthesizer Tutorial

    This page describes how to use the piano synthesizer in Nyquist.

    First, load the file "pianosyn.lsp" to initialize the synthesizer. The file is in the "lib" directory.

    >(load "pianosyn")

    After the piano synthesizer has been initialized and returns, you can use the functions provided by the synthesizer program to generate piano sounds.

    The functions are shown as below:

    Generate a single note

    Use the function:

    (piano_note duration step dynamic)

    • duration represents the duration of the note in seconds.
    • step represents the pitch of note, and uses step values as in all Nyquist functions. For example, value 60 is middle C (C4).
    • dynamic means the dynamics of the note, and it ranges from 0 to 127. In a midi file, it is used as the velocity of the note.
    This behavior returns a sound. You can use (play (piano_note...)) or (s_save (piano_note...)...) to play or save the sound.

    Examples:

    > (play (piano_note 4 60 100))
    The command above will generate and immediately play a C4 note that lasts 4 seconds, velocity at 100.

    Synthesize piano music according to a midi file

    To convert a midi file to sound, use the function:

    (piano_midi midi_file_name)

    • midi_file_name is a string representing the name of the midi file.
    This behavior will generate sound according to the score of the midi file. It generates stereo sound, and the sample rate is the default sound sample rate.

    Convert midi file to sound file

    To convert a midi file to a sound file using the piano synthesizer, use the function:

    (piano_midi2file midi_file_name sound_file_ name)

    • midi_file_name is a string representing the name of the midi file.
    • sound_file_name is a string representing the name of the sound file.
    This command will generate a sound file according to the score of the midi file and play it at the same time. It generates stereo sound, and the sample rate is the default sound sample rate.

    Example:

    >(piano_midi2file "demo.mid" "demo.wav")
    "demo.mid" is the name of the midi file. It saves the output sound into "demo.wav", and plays it when generating the output.

    Generated by Ning Hu(ning_hu@cmu.edu) Mar.22, 2001 nyquist-3.05/demos/beginclip.jpg0000644000175000000620000002420410144436365015740 0ustar stevestaffJFIFC     C   " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((xOW[ֱmi(Ԧm>7Wnr県u ΝXUMӒvG}LiVY7JJI;hm:QZ5ƥ{]HC^IUG$@uz^sKĚVصOv6M"V7bg3JU2ʬ/[Z.U G1D)UL eG y&$o^ݴfXL0}Z.մk/Li:t87;hqInOFyAgHW\/+q'[R!)"oA޿%Ml^uouߚtxo_ kmmϒtX͜_1_G/x}Tx4{x5Ie]D$kFt.tѣ(ScFŒV|$~5WH P:e087`+Ǒ?~+b9^Kxޡ0XmȜ96E,FRpnJ3\-+$Tҕ$ FWKehG]tQEzz'i'gv(`u [R%*: E<6ߞ(<)V *O.NY0Wi FU]_ÿ |q[$*ҵ$Ep!Kg ϝב JVqoz7/zDž bZl#xѾi: bIxdot g:,>DR ;w]< x'ڣc]?߿/gy+GzvvQ#1<~}pWmvkwo" 9I#u9VV|syՕ`Ry>+ȁ Az?σ^ o;D.%oވdշrywêB`TQJ&n%-,] ̞ࢷZy4QEzGw Svk[,߽0Ǜ.0ce  qa/>-XKSy<9 X, @| ·Ԙi,ay0bd61W\QYˠYIά&cEC9Vo-([oT~9TþF0"zF)mmR_MBeÚ.<[6&%/9'`wg cDKxVrMumUT))N6&z/2km)4 a4+"`_L˹1<Oz3]ƢI4_߾oWbpzpQ;oͷRmmz>'h:mhtI,oDhYTK< />lh|?ןK<34k=ݵԖ?1 l7dPд7š^˝oVy--`o5+V,p@b)xKoF- K*9n|HKdyۓ oH=7RUg;gvq6]F2>_n\U, Ww_ RQy;쬴][5uq_]Ɵ4SPbX$-S}cB.w |gk6~״3OеI ͥV:~yrp>VV,<^QEt0T6[5uPtfM5NjQiūGKG$}62wYҵ i7ZC\g 2 FŇ.X[-2^̖V!yeeII8qW#vj=MxNZ J<kwWT(HFx}bswjy\i2Hbr<5i*Ww|bWgֵ%Ta G/eI=Կ^+|DcKqjtHJk1 FG pY$5cB.cQ^,%*NV<a:m+j[omz]񞟩>J5OE0NU2CW{æiw[)ݤ2 LVz<>>:*xO2051yhL%h !n\Ԅ05IOwwhun).4"y\:PTj&ӴfW-E+%}eQ׀-|u3D]GBn/gRRLۮa#Wr7 >%XAZ"4Ҡ载Cdlf=I5 Wz[7:T*$L۷|6i#`S!(S.&ZK]i$V2;⯴hgwUr̖ғĎC$-"OZ( TWZ֒WnVK2ԃQkI^6dRթ˹xI-6ѵjqC"iҖRp"nHiϕy9*_xdIi2ۼ/V@?sS) "(J5sn\..[V3R";^MJw\vQK. g|=x{Ey,f=.l˕0m#<mVVM 2u܇8WR;-WZ]+/eiFЦ(5(vrIIlѲ4uǫO u*ZpI$[W|DRC+KKu[|6b>aׯzğ>#ڐ:Uӯ8ZrJ)\_Vv%wK~XcxZi*tZEhRjilޱsL_z/ +Oq}q>u*ZpI$X֏yfJ!=Ė DbRAd+%i' iՅֶ~7 g컰[7MlUpzm+yٻi[% $4M-tݽԽ{%'&&Zu\gX .Z[܆I{'cB.cQ[B(M-EnPi?5 JAn*|I'koם^D0Ss4ܔmҶ[$*ycdKҌ m'{}bn1-yEW{^> tIlGyh"_* })! ם|wx2-F.%cH,bм2!**r2pFNxq4NPF{7dѦ~MhHq*Tam'i?)-^Y/~ XRIu{pFAl l4a[05敥_1ׯuj]CT̞c`pO BT`Mg&+w}IE;+x<۪Ӝ۔EIE;+WQEz'|fG/2;6Kn}6x1ib30~PO&d|'WVn`.Ww`fIgn=ԉ2<@ıe T-<5{OKq#YD{^U#TIdYJ/kH]Znmp wcUS$4敆HS[8;tq󽓺2dҡ_( r7Gӊ[]m 4[(ꂊ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((nyquist-3.05/demos/pitch_change.htm0000644000175000000620000000653510144436365016437 0ustar stevestaff Pitch Change by Resampling Tutorial

    Pitch Change by Resampling Tutorial

    Roger Dannenberg

    This tutorial shows how to change the pitch of a sound using resampling. In this example, a source sound is resampled to effectively play the sound faster and/or slower. This changes the perceived pitch. It also makes the sound play faster and/or slower, so the original duration is not preserved.

    To control the playback speed, a control function is used. The function specifies the pitch shift in steps, so if the function is zero, there is no change. If the signal is 1, the signal is shifted up one half-step. If the signal is -2, the signal is shifted down a whole-step, etc.

    The control signal can of course change over time. The control signal time corresponds to time in the resulting sound. Thus, if the control signal jumps from 0 to 5 at time 3, the resulting sound will jump up a musical fourth (5 half-steps) at time 3. This may or may not be time 3 in the source sound.

    The code implements VARIABLE-RESAMPLE which takes two parameters:

    • steps -- the pitch control function
    • snd -- the source sound to be resampled
    The function works as follows: First, steps is converted to ratio, which is the speed change expressed as a ratio. E.g. when steps is 12 (an octave), ratio will be 2 (a 2:1 ratio) Second, ratio is integrated to get map. The map is a function from real time to the score. Note that the slope of the map at any time determines the amount of speedup. Finally, SND-COMPOSE is used to map the source sound according to the tempo map. Because SND-COMPOSE is defined to output the sample rate of the map, we coerce the sample rate of map to *sound-srate*.

    This function could be improved by adding code to handle stereo inputs. Also, this function should really be implemented using snd-resamplev, which uses a high-quality resampling algorithm. Unfortunately, there a bug in snd-resamplev, so until the bug is fixed, snd-compose actually sounds better.

    The resulting sound ends whenever either steps or snd come to an end. To control duration, you may want to make sure that the source sound is much longer than the control function. That way, even if you speed it up, it will still last long enough to exhaust the control function, and you know by design how long that is. You can also apply an envelope to the result to trim it to a known length.

    So, here finally is the implementation:

    (defun variable-resample (steps snd)
      (let ((p1 (/ (log 2.0) 12))  ; p1 helps convert steps to a ratio
            ratio map)
        (setf ratio (s-exp (mult steps p1))) ; pitch ratio
        (setf map (integrate ratio)) ; map from real-time to sound time
        (snd-compose snd (force-srate *sound-srate* map))))
    
    Here is an example: the PWL control function is initially zero (no transposition), but starting at time 1.0, it rises to 2.0 in 0.1s where it remains until time 3.0. The function ends at time 3.0. The sound to be modified in this case is a simple sinusoid with a duration of 8. In this case, the PWL function finishes at 3.0s, well before the OSC sound comes to an end.
    (play
           (variable-resample (pwl 1.0 0.0 1.1 2.0 3.0 2.0 3.0) (osc c4 8.0)))
    
    Note that you can replace (osc c4 8.0) with any sound, including one read from a sound file using S-READ. nyquist-3.05/demos/softclip.gif0000644000175000000620000004035210144436365015616 0ustar stevestaffGIF87a3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3f!, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɒ$ZʜI͛813ϟ@ j'ѣH*]j(ӧPJz)OTB׮` KvٲhϪMv۶pʍK,0;/߿~,0YX)^̸ǐ#KL˘3k rb/7MӨI[QhU׮cÞ-6۶sޭ7߾.8Ίi'gsПKN}_BGqӫ_ꄭaǞr߯_h}y'b.(Xfva%THhb,g^c5-Ҹ6X~!|)䐣)"hL"B#۔Q)eX^[f%`zeE rxݚٵn k=fcyy& {`c5)餔JAQx~m꩞v *J꩟ꨩfʪg2H8X뭴jkut@) Ɗ9,6KBVˬ%jn ކܖ ݢkۮ\jТ#.Jh 쾪/"oyd*F ;l1?,qs_1+ĕ: +Ӻ3\3+Ϭ) ]<'m4H/MkZ/5_kuWWZwMנz6؂|26l3p+ttWc]|-xl#~xng1ȑWN"Kqs׋U'8sM骣^"lܷ-N^X&xh6O/}8=(&oA=ʝ-=_6 ;7@pvc z&1=/zAQςSʐЀ _GB-9Q[է2a ?/l! CK4E__77D1DL? &x1[U* S8%b?FPD}مc6nэpF:qu?Y1p#4a(H@6PȏAё>DGJ^t%sFL\b芈DQ2Le(%K_U!ʬ?,֖K5kS ILBL7re~w =UOD`sɫӳ]GN{d4ud$6?^giz2aDf1z@tjK5Yo\+;x*]6O}>w5JA JґlW+-q h&_:ɔ_J\IePM)TH]"ɚ,Fa6$86BNuc9-걓IVÕ(W %WUb[)Z4AdiZX* oѫ³͙m.IKUEhCKڣP5L.O7wWցR]$Ta%LT,p{Lˣ.a9z_g8BT5Ti Zv.*:Ҍf%gtҭz8)m6awƝ WQXEdME0~":…0׉)ִZ| /-J6UڌLēvO]WE{CUMEsiT=cDϛ ߲p5L̎.'Ǡċe0ӋB7 ۛNsp&P3 4]s٬-g&D{O3; .u}L[-Oڼ+JD=|-7(ZѦ.ϜvI٥ӶĨl3kA%,7'C:q}c h.vN7A5{Lff졨eS{ʋFgV@hy9"MoF 1HzFQar[M6~^ CƭC|ǎ+z{:~Yx7Vf>]X2 VIs vl V17G5weL*<(VquZbb\ W =xq~9.u) jW[<6U7 38e~.$ZPӆEu=ll η4n{/wi7y2rb=NlإlRל2=w{t>gwOx;&I^w[iǾф2U3}iGTm]w找zץXK~Š}N8v*9W^5wͦo_$ZEFWggg=y=Z4lHȁ!ȁ؁#( h(8)(+H#HBz\W=]⢃Ov-egK7wr#V W2e9,x -l 'HVS[~c0EkIQlNi6b_6]7w(t -XTȅy؇Uh)/8|) 4XgUKeD8kQytvFGKI{xdw|U_I8`4fͷb1AmwzCyȌϘX(HxQ8D*0QuH{c}Gvri4h[F*vtcpeTH، Yِy؆aPoF|hq8flLVgwkvmJ#GpgH8޸>99(8x9iE94yX^5V1pk0SrMQfI'r 6@1 88ٖkIj9֨3ِI<j6ɔ6 ;9(!;Õ9h̅r7Vjftŏ]'Tt'H{HӈDi錭9HqNbc:$=Ub!tnb ee'[冷elᙋ1FٗɔyɗIi9Y YtxEmpaTS M6x %dnSH\B(ɓYYa1oY>nٓF=uq՛es3eh4vc)qKJS %ȁ '7o9=t;;幖؉G9xu3ohk4l7Eg-&T-STOP J{ɗsx Hj9 )I{ zVgiʙ|s=f^y BӁ 86K988m::pɚzʦl2I78ey#w^i`gv" d'~#1Y>5@ʧZz"Z)((}U&yB{9w蛏] qb3Vyg4,b9@i jAI穤̪z&EikgjxWGi/Gv91I|ܩ *њ)J9d%?&q|3Ԃ9jٙ)K|ڗٲIa yjɵN O:f'űaǮ!˷'t?xtCwݪˤ)~I 隵Gٚ>∩kJJczxy7t%uSբ&ZGUӜk?o\Id{n yjR\;; n|RKj\bKvTƉ9rx=軜Y(kݩjZ{8'*׋6lz46/ԧfI3HMWE_sS3fbZj<#ҩ: mKFjy֣?7UMVpK,@DEyqrψ+ )R|Ȋ\۝U j3y6KRe;\(PGE\ZWZf+L;*[ SHypl- [yfnSd f,;u!2C{8{̣*ZsK:oڣW8JjVM϶g=`n-G#B9=Խ\6-{UdX^#:[Пq/ɍLٿ )mxhCn'ءONlW.:wsԡ~H6\\l㹣Ci-|Ca,JK ڄ+c~'/M7\؝$ny=l.Bϻ>֯B:;wJ` "* K9\* "hB#$(5%M 1%Ȏ-/4RŐ+a$h3gL; O7U-K5]M FwAD9~40bƋ`v2bÉ~q[\Wn|iקoX`܈-+\M>fe)қ;*Ө{5qϽA9:,HŬ4X.׃\ޛszlA܅ <7ԧ7Ow׵y_zO;;G#!,z6lK_{NT٫U<O?W?웪*ҪÍ"ȫHJ-(P P4Z.+Ң@+ %DMp?ztS @'1@,bʩlC; c o.0~ NZkԐq,:-/s1r<ӓL4+H#oG "t}HdE6YI2}+#BN*E6YL9 eZN/7S5E/RC;`OųAh$2Cul=48KRQh-4P̱He P m C耍nK|Mq7cKMSꥳ02ڕVBJ1zmLEB6 Sl>IREe=$4Nr8|Al :w[ 5NcQ-^l\-KށgDhQF) PnE&x-H6+}/Ô29uYH_+prMm/˝TM]uXR?ϳ4%Ƹi+.<ȏC*M @מ;6%kӢ QYB kUae1qV#itZP=34IZ-͊pÓZ帆Ytd$%9IJVҒd&5INvғ'E9JRҔD%&JVҕ'KZҖ*E^җ&0OLbӘ0. c6ә409Mj*tMnnӛ7}bpSD6ǘP cO}4f5:e ٹS4 QBs"<9!յ-rb]G7: HE*tzhȉ`/4EDȐz4Jxjmt; Rҏtz8ižB27%a@Ռզz5PHBD 2LOJq\֖&7oa"=~T9,"Y&q1M!#I5RXd7e}l))l9ihدxjp" 4+$r;㱐2xӑ-YVSCub͊\z[..D) j[ SrqD|*-_DbVC5 .} =(:Eq`X7`;֐d+- aφ*Tr<[cs}h&k֠X&i,8RjTS*ݰ y.6̪Ytv] J"G>{E6'tc5˗zܨ'.I5a8j5q:1fT8[mro&s\ȸ=PmfELWVH;Zebc3\!%,Uj7O%+#Z\([(89k[05dJ9C"<~TS"X;O%/ ^Z=T.(DX$11 ~g&jvw]Xѱsۅj/s*<أwO-řKȂl~p)t= ֳ?ʡV%oW3|rP]]fΝ(sDxNRozYdt+VE6xqz46:CbwҬo䭯lT٫ x·^.5 8%dwytr?>Du3cvSx鳦Le0&KXغF`r8Hj"]4坣[wx]: *&-j'Nx~MWBJ?Gb6σ8!҃ em2[Q$c=)4x >;:R"4z*!mj XXȾ?!#o!8"+1d9@Z!VX|@Av8);1 <81Q %q<[;ʙ'>0dY(h73#RK?Ҩ7!,p/1A\êbC ,442 J82ZC/0-GAADףK ƗP("E$/1ى <|8kY'DD\/tX#Dy@n$E6 B;tm,@4aY ْ\kY:!0"_ۡ^IW9σ$ +666 ; JBH:#ߚF0|8`jO,0Bڍ䉶ӲH= FǴtZ=r=rHˊ#+DbHpH]lI^2"Ē\ ){IjJYFB;2;[ ! z.|00C(,a,iSϰƑ)zdZd?Τ*M@KHmk6 $H/Ú:E="/c J t7ԈZIC#/a!,-yCl7rT!;ךD$A+.h$IӠj;K[-;EKO2ˌ*(Q@YC4B5j9ͣ5B/9RE{2#ĵ{{LC4=`6NP ŸI-ڞE.3Z#ı2ęLS#-p/<қE|-" |ͷPBڴdPt+"/7=dL7=t+SiEYO3EtBd̅)kPbJ B9!R8R>Q H*TI ̚"i<űQTq2wD,4QIGIc|Q\ Tݙ#@+ Xel˚_J3^B5~\Kb4j 0*{1Wd ba 8uF;S-=*,#>X ԋӘg -DU@6Y$٩O e}0%OIdѼU{5>T `&À7X M!$lQ|ju8UU`92w! r b( RYls8F 4U0rlX4 7M"9U570*ZEu?96+9X>}N^q^N>5{Y[UeM֡2K=.MfUWV:a7ʩ \]IP\NA΢BҬ)IeXD*] ^!W+yZ1OO\ͫTޓRY s]Z8U= d| "]\(WF8͗J=Ѹe$R 8%T!Tl_u.\8.zeR:̻l( vGTV&Jn+nJ$'#.݇81%a:ʥ˝]M=IVХcl^2xaK Dڹbsp9 u)աUD>*C)Y ^bm,7; nUnۊr eH4JO$:X/! .MT4d5S,0@{P%yu{(51H{bb^ !1<-D#- ҅_V7ʵc@h^Mq}!UXPƙ_Ul,&+=Z i^Ya!$I`0]HSTd}V[>55tj2ZdfVWnܔÕ~.s`{/4`׶R24tJd݂3nI "KOU8ekA2QQL,,u L)hx0WgQTek1ߥcЭI+LfR ZLXtܗsE Vo!% 0߉2Q鮗lfà~Իt)^ٜ M+Ҿ9~˱V2OԢ S^deM Hj-1B쏢}n$qnAHҴ1L'L5SU$7Yo7G5XufڋCUh́Ζ[5W<RX$`)\ <bCYMdu0"" nL1$Gv%ņQl(&E=j3f*DS͘w4PhH%H!f$}6!fFZy5Ny'd-(X"uDUjxa}Tw{9kS|}2aU˥SbH-H]JRRк]$^ʩK\yg9z*05*Sz)Wn穷j1luNʥT(hnYYطͻgvdZ r~\GR{O`IJF"^zk%PzKO@rEpӴ쨗VM-2Jd! K0Jt)^ƗvJn$6j҆>nnNdB*CNj&0s;Α:ekPjY2) E/uӥ=bی&1-!Ptcj C]R8SE%Ttg^S[I4qK(zZ,E6cQ;*]sdRmTԆ11%ŦeʒK"#tty&!B L'R*yܢj%*VOZYM3Oh$;z+TW 4ⶉNʼK5ţyj7Wf|mR?cT<\eWl [l׳ziͧx>mϵK̠馶M.<8YVI} x*X̒wī:tO[lv[u%^m“1U*Lp0 U$uRʘ_#F6ABVnt3yh=/6T]۹,{氤cRf߾<LN=rG1Zu$B`X\ֻM/?Һ^ [7:e/< 5S@>Ujj;sNGqBᨭ<͒UDDOσɋz3s{ cڮLj%md<!)1X=':HqwS7 " Yz\%3?^/VTY#sL((WXn8>2`Q^$s)(oğN2OyF?q=eǍM!#E^ۤZF֍~ܹ1Gc۩Hk`[4rH `ɐ| _ѐ}Yɸh UDٮ a̍(hOP]YOe㱱d1VJDjAܙ5$+*j%NG41 LayVu5`t8ڋcI8Bb*fiEr- щӡKEt[LÓ@HT_@8FʍicqQX=as=)| e^^uty\x́Ֆܓ|G#م)ՖeW7 -FљΈN #VD .6T]S!ƃUIe٬nY`f Y LE|f͞Fm⦅V~[Wе!8Eag O:8RT i`Gyo)f|%&51 TL p"K Iu˽醩aXvli\~8!.<+>QsB*i,1]0y%P&5#( Œp<ɛtAz n xo*iY]jmzxmBWi~Y@]*MV&c`őm=qDNH,OP2a`bƍe 2{1H΂ɦ_E]Mh +¢p1Њ_ʒAlY$SqI٨G5 b}]pigV[r9_)#;jcCLmD`]egJڰ}5Fo2mJs$V@=2ݔ߁}JmP@lqnOYY~N^9eYX8x2!~럍o+,H3Y]t]? PL}p>yppH 0G44Ru|Vjz+5!lcjb^WU_9Y.YoQb6[5" XhecFF6Ǝ37)2ύ)R5h=,iȲ/0&Ja#UmG끁 ttA#C+'8G;xCs{o8S8x8끊?8W8k8#8x@yKx7y+xgOwySx?'縕W9;9y'K{Ð99: ?s/:7?:GO:Wy_o:w:K::zǺ:׺:纮::;;;nyquist-3.05/demos/lpc_tutorial.htm0000644000175000000620000002604710144436365016524 0ustar stevestaff Nyquist FFT and Inverse FFT Tutorial

    Nyquist LPC Analysis and Synthesis

    Nyquist provides functions for LPC analysis and synthesis on streams of audio data. For analysis, the audio stream is broken into successive frames, each of which is analyzed, resulting in a small set of coefficients. For synthesis, these frames control a time-varying filter which can be applied to an audio signal.

    As with FFT frames, Nyquist does not have a special data type corresponding to a sequence of LPC frames. Instead, a sequence of frames is represented by an XLISP object. Whenever you send the selector :next to the object, you get back either NIL, indicating the end of the sequence, or you get an LPC frame. (Note that FFT frames and LPC frames are not compatible.)

    This tutorial is based on the file lpcdemo.lsp in the demos folder fo the Nyquist release. Not every line is covered, but this tutorial should give you a pretty full explanation of how to use LPC in Nyquist.

    Preliminaries

    Before using LPC functions, you must load the LPC library:
    (load "lpc")
    At the top of lpcdemo.lsp, you see the following lines:
    (setf *lpc-path* (current-path))
    (setf *lpc-data* (strcat *lpc-path* "lpc-exmpl.dat"))
    The (current-path) function call returns the full file system path to the file being loaded (lpcdemo.lsp). We save this into *lpc-path* so we can find other related files later, even if the current directory is changed. *lpc-data* is one of the file names we will use later.

    LPC Analysis

    Another file we want is a-snd-file.snd, a very short vocal sound that is part of the Nyquist release (it is also used by examples.lsp). To get this file, we concatenate it with the path we obtained above. The resulting full path can be passed to s-read to read the sound. Find the expressions in the following function that build a file name and read the file as a sound:
    (defun do-lpc-analysis ()
      (let ((myfile (strcat *lpc-path* "a-snd-file.snd")))
        (save-lpc-file (make-lpanal-iterator (s-read *myfile*) 0.08 0.04 50)
                       "temp.dat")))
    You can analyze a sound using make-lpanal-iterator. This function takes a sound, a frame size, a step size, and the number of poles. In do-lpc-analysis (above), we used 0.08 seconds, 0.04 seconds, and 50 poles for these parameters. The result of make-lpanal-iterator is an object that will deliver LPC frames on demand. In this function, we will grab all of the frames and write them to a file using save-lpc-file. The data is written to "temp.dat". You should run this function and look at the file, which contains ASCII data. Later, we will use this data to filter a sound.

    Since a-snd-file.snd is a very short and uninteresting sound, we will use a different set of LPC frames in the following synthesis examples. The data is in lpc-exmpl.dat, and the full path for this file was computed earlier and stored in *lpc-data*.

    The first example will just show how to read the LPC data file using make-lpc-file-iterator, which takes the file name as a parameter. You can print some frame data using show-lpc-data as shown in the following:

    (defun ex-1 () 
      (show-lpc-data (make-lpc-file-iterator *lpc-data*) 100 120 NIL))
    The additional parameters to show-lpc-data are the starting frame (100), the ending frame (120), and a flag (NIL)  indicating whether to print filter coefficients. If you want to look a little closer at the inner workings of this code, you can send a :next message to an LPC iterator object as follows:
    (setf iterator (make-lpc-file-iterator *lpc-data*))
    (send iterator :next)
    This will return the first frame of the LPC analysis. Send :next again  to get the next frame.

    LPC Synthesis With Fixed All-Pole Filter

    The next example creates a sequence of vowel sounds. The vowel filters are based on the
    30th, 60th, and 100th frames taken from the file lpc-exmpl.dat. We use make-lpc-file-iterator as before to read the LPC frames from the file, but we use nth-frame to get the desired frames.

    The function allpoles-from-lpc constructs a filter from the frame and applies it to a sound. In this case, the source sound is created by buzz with a little vibrato provided by lfo:
     

    (defun ex-4 () 
      (play (seq
              (allpoles-from-lpc (buzz 12 f2 (lfo 5.0 4.0)) 
                                 (nth-frame (make-lpc-file-iterator *lpc-data*)
                                            30))
              (allpoles-from-lpc (buzz 12 f2 (lfo 5.1 4.0)) 
                                 (nth-frame (make-lpc-file-iterator *lpc-data*)
                                            60))
              (allpoles-from-lpc (buzz 12 g2 (lfo 5.3 4.0))  
                                 (nth-frame (make-lpc-file-iterator *lpc-data*)
                                            100)) )))
    Rather than iterate through a file to find the desired frame, you can also just store the desired frames as in the following:
    (setf a-lpcdata
      '(63.2144 0.674387 0.103287
        #(-0.0381026 0.00804115 0.0109905 0.0145117 0.00199174 
          -0.00129314 0.0171826 0.0181176 0.00179391 -0.0114089 
          -0.0120949 -0.000410595 -0.0122539 -0.0209354 -0.00804976 
          -0.00345041 -0.00409532 -0.00227011 0.014224 0.0135451
          0.0056023 -0.00651142 -0.00564953 -0.0168921 -0.0377939
          -0.0449506 -0.0355592 -0.0339316 -0.0454434 1.19336)))
    (setf e-lpcdata
      '(40.7157 0.149753 0.0606467
        #(0.0244574 -0.0225545 -0.0172724 -0.0122709 -0.0042946
          0.00886974 0.0121516 0.0120936 0.00197545 -0.00582163
          -0.018367 -0.0201546 -0.00440599 0.00638936 0.0166275
          0.0185066 0.00890464 -0.00158013 -0.00494974 -0.00479037
          0.0130814 0.0138648 -0.0022018 -0.021368 -0.0343532 
          -0.0312712 -0.0574975 -0.0918824 -0.112016 1.31398)))
    (setf i-lpcdata
      '(5.5391 0.0321825 0.0762238 
        #(-0.0341124 -0.0149688 -0.00585657 -0.0111572 0.00769712
          0.0190367 0.00885366 0.0112762 0.0118286 -0.00059044 
          -0.0140864 -0.0123688 -0.0151128 0.00214354 -0.00810219 
          -0.00538188 0.00631382 0.020771 0.0356498 0.0295531
          0.0242797 0.0124296 0.00445127 -0.013062 -0.0387178 
          -0.0527783 -0.0685511 -0.076575 -0.0846335 1.24521)))
    The following function applies a filter to noise:
    (defun noise-vocal (lpcdata dur)
      (allpoles-from-lpc (noise dur) lpcdata))
    Combining this with our definitions of different frames, we can write a little sequence
    of vowel sounds:
    (defun ex-5 ()
      (play
        (seq (noise-vocal a-lpcdata 1)
             (noise-vocal e-lpcdata 1)
             (noise-vocal i-lpcdata 1))))
    We can do the same thing using a buzz sound rather than noise:
    (defun buzz-vocal (lpcdata dur)
      (allpoles-from-lpc (buzz 16 e2 (const 0.0 dur))
                         lpcdata))
    (defun ex-6 ()
      (play
         (seq (buzz-vocal a-lpcdata 1)
              (buzz-vocal e-lpcdata 1)
              (buzz-vocal i-lpcdata 1))))

    Time-Varying LPC Filter

    The most interesting LPC effect is to use a sequence of frames to drive a time-varying all-pole filter. If the frames were analyzed from a vocal source, then the resulting filter will transfer the speech articulation (or at least some of it) to another sound. The time-varying LPC filter is called lpreson.

    Here, the LPC data from *lpc-data* is used to modulate noise:

    (defun ex-7a ()
      ;; parameters are sound, lpc-iterator, skiptime
      (lpreson (noise 6.5) (make-lpc-file-iterator *lpc-data*) 0.04))
    (defun ex-7 ()
      (play (ex-7a)))
    The same thing can be done to filter a buzz sound. This example generates some vocal-like sounds in two-part harmony:
    (defun ex-8a (p dur)
      (lpreson (buzz 16 p (scale 1.5 (lfo 3.0 dur))) 
               (make-lpc-file-iterator *lpc-data*)
               0.04))

    (defun ex-8 ()
      (play
        (sim (seq (ex-8a c4 1) (ex-8a g3 1) (ex-8a a3 1) (ex-8a b3 1) (ex-8a c4 1))
             (seq (ex-8a c2 2) (ex-8a f2 1) (ex-8a g2 1) (ex-8a e2 1)))))

    Note that you can change the skiptime parameter to lpreson to change the rate at which the filter moves through the frames. The result is to caues the speech articulations to go faster or slower.

    More examples can be found in lpcdemo.lsp.

    Acknowledgments

    Pedro J. Morales created the LPC functions for Nyquist and wrote lpcdemo.lsp on which this tutorial is based. nyquist-3.05/demos/examples_home.htm0000644000175000000620000000633411536000246016635 0ustar stevestaff Nyquist Examples and Tutorials

    Nyquist Examples and Tutorials

    nyquist-3.05/demos/fft_tutorial.htm0000644000175000000620000007323211466723256016531 0ustar stevestaff Nyquist FFT and Inverse FFT Tutorial

    Nyquist FFT and Inverse FFT Tutorial

    Nyquist provides functions for FFT and inverse FFT operations on streams of audio data. Because sounds can be of any length, but an FFT operates on a fixed amount of data, FFT processing is typically done in short blocks or windows that move through the audio. Thus, a stream of samples is converted in to a sequence of FFT frames representing short-term spectra.

    Nyquist does not have a special data type corresponding to a sequence of FFT frames. This would be nice, but it would mean creating a large set of operations suitable for processing frame sequences. Another approach, and perhaps the most "pure" would be to convert a single sound into a multichannel sound, with one channel per bin of the FFT.

    Instead, Nyquist violates its "pure" functional model and resorts to objects for FFT processing. A sequence of frames is represented by an XLISP object. Whenever you send the selector :next to the object, you get back either NIL, indicating the end of the sequence, or you get an array of FFT coefficients.

    The Nyquist function FFT (mnemonic, isn't it?) returns one of the frame sequence generating objects. You can pass any frame sequence generating object to another function, IFFT, and turn the sequence back into audio.

    With  FFT and IFFT, you can create all sorts of interesting processes. The main idea is to create intermediate objects that both accept and generate sequences of frames. These objects can operate on the frames to implement the desired spectral-domain processes. Examples of this will follow, but first, let's try something simpler.

    Simple FFT Example

    [Special thanks to James Valenti for detailed comments and explanations about this code. -RBD]

    Just to convince ourselves that this works and to explore the FFT function, let's perform an FFT on a sinusoid. To make the outcome predictable, we will use 32 samples of sinusoid with a period of 8 samples. If we take a 32-point FFT, the spectrum should show a strong 4th harmonic (there are 4 8-sample periods) and zero everywhere else.

    Before the test, we will introduce a simple function to create an FFT sequence generating object, which is called an iterator: The function is called make-fft1-iterator, and creates an object of class fft1-class (I am using fft1 rather than fft because this is a simplified version that will be improved later). Objects of this class will have the fields sound, length, and skip. Create the class by sending class (the super class of all classes) a :new message to create a new class that will be a sub-class of class:

    (setf fft1-class (send class :new '(sound length skip)))
    
    Add a method named :next to the fft1-class. The method will have a formal argument list of () and the code body of (snd-fft sound length skip nil), so this is simply a wrapper for calling snd-fft which has takes as parameters: the source sound, the fft length, the number of samples to advance for each fft, and the sound to use as a window function (in this case, no windowing is indicated by nil.) Each time snd-fft is called, it will advance by skip to the next set of samples. The function (and thus the :next method) will return an array containing the results of the next short-time fft:
    (send fft1-class :answer :next '() '(
        (snd-fft sound length skip nil)))
    
    Add a method named :isnew to the fft1-class. This is a "standard" method that is called automatically to initialize a new object of the class when the :new method is sent to the class. Any parameters sent to :new are passed on to :isnew, and in this case the formal parameter list is (snd len skp) and the body of the function is three setf's that copy the parameters into the fields (or instance variables) of the new object, which are named sound, length, and skip:
    (send fft1-class :answer :isnew '(snd len skp) '(
        (setf sound snd)
        (setf length len)
        (setf skip skp)))
    
    Make a new function named make-fft1-iterator to create an fft1-iterator with the parameters sound, length, and skip. The function makes a new object by sending the :new message to the fft1-class. Because fft1-class consumes the sound (by calling snd-fft), this function copies the sound with snd-copy to avoid any unexpected side effects on the sound parameter.
    (defun make-fft1-iterator (sound length skip)
      (send fft1-class :new (snd-copy sound) length skip))

    For test data, create a sinusoid. lfo generates a one second sinusoid. The control-srate-abs transformation changes the sample rate generated by the lfo to points and since the duration is one second, there will be exactly points samples generated. The cycles parameter is the frequency of the sinusoid, so a value of 1 will generate one cycle (in one second) and a value of 2 will generate 2 cycles in one second, etc.

    ;; create a 1-second sinusoid with points samples at cycles hz:
    (defun short-sine (points cycles)
      (control-srate-abs points (lfo cycles)))
    
    In the fft-test function, the let introduces a list of local variables (just fft-iterfft-iter, it will be ignored by this function. Inside the let, fft-iter is set to a newly created instance of fft1-iterator, initialized with a signal that has 4 cycles of a sinusoid in 32 points, with an fft length of 32 samples and a skip of 32 samples (zero overlap):
    (defun fft-test ()
      (let (fft-iter)
        ;; signal will have 4 cycles in 32 points:
        (setf fft-iter (make-fft1-iterator (short-sine 32 4) 32 32))
        (display "fft-test" (send fft-iter :next))))

    Running this prints an array of nearly-zero values except for the 9th element (index 8), which is -1. The layout is as follows:

    • the DC component goes in array element 0
    • the Cosine part is in elements 2i - 1
    • the Sine part is in elements 2i
    • the Nyquist frequency component is in the last element
    The output should look like this:
    > (load "fft1.lsp")
    ;loading "fft1.lsp"
    ;[ gc: total 20640, 3360 free; samples 12 KB, 7KB free ]
    ;fft-test : (SEND FFT-ITER :NEXT) = #(1.53076e-017 0 0 0 0 0 0 -3.06152e-017
    ; -1 0 0 0 0 0 0 3.06152e-017
    ; 0 0 0 0 0 0 0 -3.06152e-017
    ; 8.9407e-008 0 0 0 0 0 0 1.53076e-017)
    ;T
    ;>
    

    Thus, the element at index 8 is the 4th Sine component, indicating a 4th harmonic as expected.

    Simple Inverse FFT Example

    Now, let's try to reverse the FFT and recover the sinusoid. We will use the snd-ifft function, which takes five parameters:

    • the starting time of the resulting sound
    • the sample rate of the resulting sound
    • the iterator object, which will be called to obtain short term spectra (frames)
    • the step-size, how many samples to advance for each frame
    • the window (or NIL), by which each frame is multiplied after the IFFT

    The result returned from snd-ifft is a sound which is assigned here to local variable ifft-snd. In this case, the sound will have a start time of 0, a sample rate of 32, the spectral frames (actually just one frame) will be obtained by sending the :next message to fft-iter, the skip between successive frames is 32, and no windowing is applied.

    (defun ifft-test ()
      (let (fft-iter ifft-snd)
        (setf fft-iter (make-fft1-iterator (short-sine 32 4) 32 32))
        (setf ifft-snd (snd-ifft 0 32 fft-iter 32 NIL))
        (display "fft-ifft" (snd-length ifft-snd 200))
        (display "fft-ifft" (snd-samples ifft-snd 200))
        ifft-snd )) ; return the sound

    Now call the function:

    (ifft-test)

    Looking at the printed samples, you can see that the result is a close approximation to the expected sinusoid. Since ifft-test returns a sound, you can call (play (ifft-test)), but in this case you won't hear much because the sound is only 32 samples, and there may also be problems trying to play a sound that is only sampled at 32 samples per second.

    Exercise: Modify short-sine to produce a cosine and observe the difference in the FFT. Confirm that the IFFT reproduces the original cosine. (Hint: the parameters to LFO should be: (lfo cycles 1.0 *sine-table* 90.0), indicating frequency, duration, the waveform, and the initial phase, respectively.)
     

    Sequence of FFT Frames

    Let's create an FFT iterator that reads sounds from a file. This is similar to what was done before, but here, s-read is used to read samples instead of using lfo to compute samples:

    (defun file-fft1 (filename frame-length skip)
      (make-fft1-iterator (s-read filename) frame-length skip))

    And here is a function to recover the sound file from spectral frames and play it. The sound will start at time 0, at the sample rate *sound-srate*, using iterator to generate successive spectral frames, advancing skip samples between fft's, and no windowing. Note: *sound-srate* is a global variable from Nyquist that is the default sample rate for sounds. It can be read directly, but you should only modify it by calling sound-srate-abs:

    (defun play-fft1 (iterator skip)
      (play (snd-ifft 0 *sound-srate* iterator skip NIL)))

    Define a filename for testing. Remember that the backslash (\) character is the escape character for XLisp strings, so you need to type two backslashes to denote one backslash character. Windows will also accept forward slashes (/) as a separator, and the forward slash does not need to be escaped. Be sure to test this with a mono file at the default sample rate of 44100:

    ;; a convenient sound file name (change this to one of your mono soundfiles):
    (setf sfn "D:\\brain\\outro\\soup.wav")
    
    Define a function to call play-fft1 using sfn as the input function for analysis, a frame length (fft size) of 512, and a skip size of 512 (no overlap). The start time (0), sample rate (*sound-srate*) and windowing function (none) are hard-coded in play-fft1.
    (defun file-test () (play-fft1 (file-fft1 sfn 512 512) 512))

    If you do not hear your original file, try playing the original file by typing (play-file sfn), and make sure the file is a mono file at 44,100 Hz sample rate (to match *sound-srate* used in play-fft1). Check out the file by typing (sf-info sfn).

    You can try different skip parameters, e.g. to play the sound at double speed, try this:

    (play-fft1 (file-fft1 sfn 512 512) 256)

    XLisp and Garbage Collection

    In the previous example, you may have noticed a lot of messages that look something like the following:

    [ gc: total 18640, 3114 free; samples 49KB, 39KB free ]

    What the gc: Messages Mean

    These messages are printed whenever the garbage collector runs to reclaim memory that was allocated but is no longer in use by the program. The memory found by the garbage collector is reused in future computation to avoid allocating more memory than is necessary. The particular message here says that 18640 "cells" have been allocated. Each cell is 10 bytes, so there are 186,400 bytes, or about 186KB used to store XLisp programs and data. This does not include the XLisp interpreter, Nyquist functions, and system libraries, that take an additional 500KB or so. It also does not include audio samples, which are stored separately. Of the 18640 cells, 3114 were free after garbage collection. Of the 49KB of audio data (samples) allocated by Nyquist, 39KB were free for reuse after after garbage collection.

    Making GC More Effective

    Nyquist and XLisp do a pretty good job of effective, automatic garbage collection, but since XLisp was designed to run on small machines, it favors using a minimal amount of memory, and this may result in frequent garbage collections. FFT processing, in particular, makes heavy use of XLisp, since every floating point number in every FFT frame requires the allocation of a 10-byte cell. When you are processing with FFTs, you can often gain some speed by telling XLisp to allocate more memory cells. Do this by calling expand:

    (expand 100)

    The parameter tells how many additional internal blocks of memory to allocate. Each block is 2000 cells, or about 20KB, so if the parameter is 100, you will allocate about 2MB. After allocating memory, the next garbage collection might look like:

    [ gc: total 218640, 204298 free; samples 49KB, 44KB free ]

    Notice that now, garbage collection frees a higher proportion of memory than before   (204298 out of 218640 cells). Garbage collection is more efficient when there is a higher proportion of memory to free.

    On the other hand, you should not allocate more memory than necessary. If you allocate too much, parts of Nyquist and other programs will be paged out of RAM and onto your disk drive. Since Nyquist must access all of its memory for every garbage collection, it is very inefficient to have any of that memory reside on disk.

    Should you always expand memory? Almost all non-FFT audio processing uses special data structures that are outside of XLisp and are managed without the use of the garbage collector. Since audio processing normally takes over 95% of the execution time, you normally do not have to worry much about the efficiency of XLisp.

    Simple Spectral Processing

    The main purpose of FFT and IFFT functions is to enable processing in the spectral domain. Let's create a very simple example in which certain frequencies are set to zero, creating a filter effect. (Note that this is not a very good way to create filters because of boundary effects.) We need to create an object that will access an FFT iterator to get frames, and that will serve as an iterator to deliver frames. The code is as follows:

    (setf fft-hp-class (send class :new '(source bins)))
    
    (send fft-hp-class :answer :next '() '(
      ; get a new frame of fft coefficients from source
      (let ((frame (send source :next))) ; creates local variable - frame
        ; a note about let:
        ; the first list after let names new local variables
        ; the following lists (below) are expressions to be evaluated
        ;
        ; if frame is nil, there are no more frames to process
        (cond (frame
               ; if frame is not nil, then do the following
               (dotimes (i bins)
                 ; set all the bins from 0 to bins-1 (these are low frequency bins) to zero
                 ; the order of coefficients is:
                 ;    DC coefficient
                 ;    first real
                 ;    first imaginary
                 ;    second real
                 ;    second imaginary
                 ;    ...
                 ;    if the length is even, then last is the real
                 ;       coefficient of the Nyquist frequency
                 ;
                 ; (Note: aref gets the ith element of the array)
                 (setf (aref frame i) 0.0)))) ; end of cond
        frame))) ; frame is the last expression of the let, so it is the return value
    
    Create an fft-hp-class method called :isnew to initialize the fft-hp-class class variables source and bins. The source will be a file-fft.

    A refresher as to what goes on with file-fft: file-fft1 reads a file into a sound variable and calls make-fft1-iterator. Then make-fft1-iterator returns an fft-1 class by sending fft1-class :new with a copy of the sound. It makes this copy because it will have skip samples removed every invocation of fft1-class:next because this method calls snd-fft which removes the samples every time a new fft frame is calculated.

    (send fft-hp-class :answer :isnew '(s b) '(
        (setf source s)
        (setf bins b)))
    
    This is a function to make and return an instance of the fft-hp-class class.
    (defun make-fft-hp (source bins)
      ; Send the fft-hp-calss a :new message to create a new instance of the class
      ; and to initialize the instance with the values of source and bins
      ; Returns an object that responds to the :next message by getting the next
      ; fft frame, zeroing the low frequencies, and returning the frame.
      (send fft-hp-class :new source bins))
    
    In play-fft1, fft frames from make-fft-hp are converted back into audio. The audio is reconstructed using a skip of 512.
    (defun hp-test ()
      (play-fft1 (make-fft-hp (file-fft1 sfn 512 512) 11) 512))

    Note that make-fft-hp takes a parameter, bins, that tells how many coefficients of the FFT to zero. At 44,100 Hz, the frame rate is 44100/512 = 86.13 Hz, and this corresponds to the first bin (coefficients at locations 1 and 2). Since we specified 11 for the bins parameter, this will zero the DC component and 5 complex pairs, representing frequencies up to 86.12 * 5 = 430.7 Hz. (If you are trying this on a laptop computer with small speakers, or if you are using a sound without low frequencies, you may want to increase the number of bins in hp-test from 11 to 30 to make the effect really obvious.)

    You will notice some raspy sounds in the output. Since the FFT frames are not smoothed by any window or overlapped, there are serious windowing artifacts that are easily heard. We will look at ways to reduce this problem later.

    Spectral Modulation

    An interesting effect is to let one spectrum modulate another one. By multiplying the amplitude spectrum of one signal onto that of another, one can superimpose the two signals. (Note that adding spectra is simply a way to mix them and is equivalent to addition in the time domain.)

    Let's create a bright FM sound to serve as a spectral modulation "carrier". First, create the FM sound. This sound has an initial, middle, and fiinal modulation index as well as a (constant) pitch:

    (defun fm-tone (step mi1 mi2 mi3)
      (let ((hz (step-to-hz step)))
        (setf mi1 (* mi1 hz))
        (setf mi2 (* mi2 hz))
        (setf mi3 (* mi3 hz))
        (fmosc c4 (partial step 
                           (control-srate-abs *sound-srate* 
                             (pwl 0 mi1 0.5 mi2 1 mi3 1))))))

    The modulated sound will be a cluster of three FM tones. You could use just one tone, but I have had better luck with chords or noise. You want to make sure the signal has plenty of amplitude at many frequencies; otherwise, the spectral modulation will not have anything to modulate.

    (defun mod-snd ()
      (sum
        (fm-tone c3 15 20 15)   ;; adjust FM parameters here
        (fm-tone d3 15 20 15)   ;; adjust FM parameters here
        (fm-tone e3 15 20 15))) ;; adjust FM parameters here

    Next, we need a class to do the modulation. As before, objects of this class respond to the :next message. In this case, the :next method sends  :next to both sources. It then multiplies the coefficients of one by the computed amplitude spectrum of the other.

    (setf fft-modulator-class (send class :new '(src1 src2)))
    
    (send fft-modulator-class :answer :isnew '(s1 s2) '(
        (setf src1 s1)
        (setf src2 s2)))
    
    (send fft-modulator-class :answer :next '() '(
      (let ((frame1 (send src1 :next))
            (frame2 (send src2 :next))
            n half_n)
        (cond ((and frame1 frame2)
               ; multiply frame2 by the amplitude coefficients of frame1
               (setf (aref frame2 0) (* (aref frame2 0) (aref frame1 0))) ;; DC
               (setf n (- (length frame1) 1))
               ; Subtracted 1 because we already took care of DC component
               (setf half_n (/ n 2)) ; integer divide
               (dotimes (i half_n)
                 (let* ((i2 (+ i i 2))
                        (i2m1 (- i2 1))
                        (amp (sqrt (+ (* (aref frame1 i2m1) (aref frame1 i2m1))
                                      (* (aref frame1 i2)   (aref frame1 i2))))))
                    (setf (aref frame2 i2m1) (* (aref frame2 i2m1) amp))
                    (setf (aref frame2 i2) (* (aref frame2 i2) amp))))
               (cond ((= n (+ half_n half_n 2)) ;; n is even -> nyquist component
                      (setf (aref frame2 n) (* (aref frame2 n) (aref frame1 n)))))
               frame2)
              (t nil)))))
    
    (defun make-fft-modulator (src1 src2)
      (send fft-modulator-class :new src1 src2))

    The code for  :next is longer than you might expect, but it is basically just a vector multiplication. Lisp is not ideal for numerical algorithms like this. The following code will test the new class:

    (defun mod-test ()
      (let ((fs 512)) ;; frame size
        (play-fft1 (make-fft-modulator 
                     (file-fft1 sfn fs fs)
                     (make-fft1-iterator (mod-snd) fs fs))
                   fs)))

    Here, we pass in iterators for the sound stored in a file and for the modulated sound. This example seems to work best if the sound in the file is a voice. You can also try stretching the speech by reducing the step parameter to file-fft and by making the modulated sound longer. You might also try different sizes of FFTs using the frame size (fs) parameter. If the FFT frame size is too big, you will resolve individual harmonics of the voice, and if it is too small, you will not resolve formants. 256 and 512 seem to be good numbers when working at 44,100 Hz sampling rates.

    Smoothing Windows

    In the previous examples, and especially in the last one, a lot of buzzing and noise is created because the boundaries of the FFT frames are no longer continuous when the spectrum is altered. To reduce the buzzing effect, we can multiply the frame by a smoothing window before reconstructing the time domain signal. We can also use a smoothing window on the input side, before taking the FFT. For now, we will try just a smoothing window on the IFFT side.

    The smoothing window will be a raised cosine pulse, although other window shapes could be used. The following code implements a raised cosine. (A raised cosine is a smooth bell-shaped curve that rises from zero to 1 and back again. The curve is one period of a sinusoid or cosine, but "raised" so that its minimum value is at zero.) The lfo function computes a sine curve, so we use an initial phase of 270 degrees to get the proper shape:

    (defun raised-cosine ()
      (scale 0.5 
        (sum (const 1) 
             (lfo (/ 1.0 (get-duration 1)) 1 *sine-table* 270))))

    Next, we need a function to create a window of the proper length. The sample rate of the window does not matter because the FFT and IFFT functions will simply take the proper number of samples (without any interpolation or resampling). Therefore, we will use the frame-size as the sample rate, insuring that there are frame-size samples:

    (defun fft-window (frame-size)
      (control-srate-abs frame-size (raised-cosine)))

    Now we can pass in a window to the IFFT. Let's redo the spectral modulation example with smoothing windows on the IFFT side. First, we will rewrite play-fft to use windowing:

    (defun play-fft (iterator frame-size skip)
      (play (snd-ifft 0 *sound-srate* iterator 
                      skip (fft-window frame-size))))

    Now, we can rewrite mod-test:

    (defun mod-test-w ()
      (let ((fs 512)) ;; frame size
        (play-fft (make-fft-modulator 
                    (file-fft1 sfn fs (/ fs 2))
                    (make-fft1-iterator (mod-snd) fs (/ fs 2)))
                  fs (/ fs 2))))

    Notice that we reduced the step size to half the frame size. This is because we want the windows to overlap by 50%, creating a nice cross-fade from one frame to the next.

    You might guess that the square windowing on the analysis (FFT) side is injecting high frequencies into the spectrum. We can introduce windowing there too. We can modify make-fft-iterator to use a window. This will require changes to fft1-class, so we will use the name fft-class:

    (setf fft-class (send class :new '(sound length skip window)))
    
    (send fft-class :answer :next '() '(
        (snd-fft sound length skip window)))
    
    (send fft-class :answer :isnew '(snd len skp) '(
        (setf sound snd)
        (setf length len)
        (setf skip skp)
        (setf window (fft-window len)) ))
    
    (defun make-fft-iterator (sound length skip)
      (send fft-class :new (snd-copy sound) length skip))

    Now, we can rewrite file-fft to use windowing:

    (defun file-fft (filename frame-length skip)
      (make-fft-iterator (s-read filename) frame-length skip))

    Now, we can rewrite mod-test yet again:

    (defun mod-test-ww ()
      (let ((fs 512)) ;; frame size
        (play-fft (make-fft-modulator 
                    (file-fft sfn fs (/ fs 2))
                    (make-fft-iterator (mod-snd) fs (/ fs 2)))
                  fs (/ fs 2))))

    This version seems to have less definition for speech input than the previous one. It might be that some windowing artifacts in the right places are actually beneficial! In fact, some simple experiments indicate that, in this example, the speech sounds better when the (mod-snd) sound is analyzed without windowing. This probably creates more noise to be modulated by the speech signal, so more speech information gets through.

    We can also stretch the result by taking smaller steps during the analysis (FFT) stage so that more frames are generated. I will also increase the frame size to obtain fewer frames/second.

    (defun mod-test-wws ()
      (let ((fs 1024)) ;; frame size
        (play-fft (make-fft-modulator 
                    (file-fft sfn fs (/ fs 16))
                    (make-fft1-iterator (mod-snd) fs (/ fs 16)))
                  fs (/ fs 2))))

    Acknowledgments

    Cort Lippe and Zack Settel have explored cross synthesis and other effects with FFTs extensively, and their work inspired these examples.

    nyquist-3.05/demos/distortion.htm0000644000175000000620000001461510144436365016217 0ustar stevestaff Untitled Document

    Distortion Tutorial

    This page describes how to use the Nyquist shape function to achieve distortion.

    Terminology

    First, some terminology:
    Clipping means that you limit the amplitude of samples, e.g.

    sample_out = min(sample_in, 1.0),

    or, observing that you might want to limit negative excursions as well as positive ones:
    sample_out = max(min(sample_in, 1.0), -1.0).
    This type of clipping is called hard clipping because the transition from an undistorted one to a maximum or minimum value is instantaneous, as if the signal hit a brick wall and can go no more.

    As you might guess, you can also have soft clipping where the transition is more gradual, and that's what this tutorial is about.

    Before discussing soft clipping, let's introduce a few other terms. Since clipping seems to be a way of limiting the values of the signal or compressing the range of the signal, you might think that clipping is a form of compressing or limiting; however, these terms have special meanings in the audio processing world.

    Compression, or dynamics compression (not to be confused with data compression) is a way of reducing the overall range of soft to loud.
    To do dynamics compression, you generally detect the intensity or peak level of a sound over a time scale of a few milliseconds, and then construct a relatively smooth amplitude control that you apply to the signal. For compression, the amplification goes down as the intensity of the input goes up, so loud passages get (relatively) softer and soft passages get (relatively) louder. (Dynamics expansion does just the opposite.) Limiters work like compressors, but are designed to eliminate peaks -- conceptually, there is no real difference, and products are often sold as "compressor/limiters". See nyquist/lib/compress.lsp for an implementation.

    In some ways, soft clipping is like dynamics compression. Both reduce the gain at high levels, but dynamics compression operates relatively slowly, effectively turning the volume knob up and down, whereas clipping operates on a sample-by-sample basis. The effect of clipping is to distort the input.

    In Nyquist, you use the shape function to implement clipping. shape applies a function to each sample, where the function is specified by a sound. The following is a typical function for soft clipping:

    Notice how the function is essentially y=x at small amplitudes, so there is no distortion for small signals, but at large input values, the function becomes very non-linear. Also, notice that this is similar to the behavior of real-life amplifiers, where small signals are undistorted, but at some point, the power limits of the amplifier clip the output signal.

    The Nyquist shape function is allows you to specify any function you like using a sound. Therefore you can use any of the Nyquist primitives to construct the function. Since a sound is a function of time, where time must be non-negative, how do you specify a shape function over a range that includes negative values? The trick is that shape takes an offset parameter that shifts the whole function to the left (in the -y direction). Note also that whereas a Nyquist sound is generally regarded as a function of time, shape treats the sound as just a real-valued function.

    The typical way to use shape is to create some increasing signal over the interval [0,2] that crosses zero at 1.0. Then you give 1.0 as the offset (3rd parameter). The result will look something like the graph above.

    Implementation

    In the figure above, I used a sine function to generate the smooth curve. Here is an implementation of distortion in Nyquist using the sine curve:
    (setf distortion 
          (osc (hz-to-step 0.25) 2.01 *SINE-TABLE* -90.0))
    (defun distort (snd)
        (shape snd distortion 1.0)) 
    
    (play (distort (mult 15.0 (ramp 4) (osc c4 4))))
    

    Even though I am an expert, and I have done this before, it still took me a few tries to get right. Here's a step-by-step explanation:

    • I used osc to generate a sinusoid so I could control the initial phase.
    • I set the osc duration to 2 because I want the table to go from 0 to 2 (after which we'll shift it back to [-1, +1]), but 2 is not enough because the interval [0,2] is closed, which means I need one extra sample. I used 2.01 to be conservative.
    • I specified *SINE-TABLE*, the default value, because the table parameter comes before the phase parameter.
    • I specified the phase to get the sine curve to go through zero in the middle of the generated function.
    • I assigned this to the variable distortion so I could plot it; try:
      (s-plot (force-srate 100 distortion))
    • Finally, I put in a tone that ramps up from zero to 15 in amplitude to cause some serious clipping. The output amplitude is limited to 1.

    Note that the input to shape is pre-clipped to the range [-1, +1] so you only need to specify the table from [0, 2] if the origin (third parameter to shape) is 1.0. If you specify a little extra, as in this example, it will be ignored.

    The Output

    Look at the generated waveform to observe the soft clipping effect. Here we see the beginning of the output, where the input amplitude is low and there is very little distortion:

    But when the input amplitude becomes large, the clipping becomes substantial. This plot is at the same scale, but taken from a later portion of the generated output. Remember that the input at this point is a high-amplitude sinusoid:

    Also notice that the distortion is symetrical, so it generates even harmonics. If you put in an asymetric function, you'll get odd harmonics too. Note that at soft levels, I actually get some gain from this function.

    Generated by Roger Dannenberg (roger.dannenberg@cs.cmu.edu) Feb, 2004. nyquist-3.05/nyqide/0002755000175000000620000000000011537433127013464 5ustar stevestaffnyquist-3.05/nyqide/nyqide_src.zip0000644000175000000620000063765010144436365016367 0ustar stevestaffPKU[-&BcRb About.dcuWo09 X ( -|a0rwƘoa;wf{36DJJDBRP&$AڤQKVjDI=m,74UJJTfyo}>3{ !n"sl-y+Oh#1X mdc MWi*.jL!vϨa7ϟD֝h 4i zas!][A6TF65)LU>E&`v3)o?$8lһt2tc&T%5M%ˬp#][zR9^;3zC* tk1١\p`vr 4oZhTŸz4V'K{܃MRt'&FO jύdV07ʳNpXtrJS$ l'ɬ~^6&-sc 4ZK;dVd3ġ74s5:vWQ'Ҷ!flm9̍a{8U]-ӥcIb]h{9-rX!½evgnOex&Tb HȊ2ң0Ϊ/WN Ha_vT}ݺ1D_^\y*cndVqC[i7+Go]#hfGW{Q,wwhb5K㦊z%h!I h qb坒`w%M9{uQfr'Y}I%3eKY*6̘fE$D9i"[8 h>t.S{l/GVf'}Ž`uǗq+O)}RbɞS{<^U=k1c<笵gp(iNi&+$5*Uўx։֥[]l5 X1QhiPԬ{GקNbNo;y,(yR_*vw*?l{H{L[hvoԓ .˩E_·NCeOS漫Q|h YE%XFLc?S -ZQDMb_q T JmDe`^xhtmT3WQqo}R3E^J-[d3ԶtƹOu&Sᨶ[0USVI׿N}|o7ʖ3B/R.{g[[&aEPyұɇk$@[LM7I?4ArHW@gXtabX[9a kGO4K|t6lvJZ LvmoWޭkS*/IBp 2-f/u Be]*B}>iq*CH1 i ;d~~Tʺ^Rƿ@ț?@. fB;@ܕ-qm)՚TB_Eզ6\.@B;**j=sKCđ5!!ɳ[dA,?2#d<3p<8zv-7Um"g;6m떫'Ygk7_޿4n@y_ C<|q?L6>Mj)w?7(bH"K:IPK Sio)Wnk:c:Yv3^ksDi7qRj}_gh_e}yv'8੣,meӀv[Z 5qGէjFo/w55O{9Wt1ک\umOcC!z[XA]&D{9[>}{U>l3{vJUNl{W7ֹO;?6ϝ_;mVmmpbgVX(5F-I{s(MӺuons58+jٻY9zkrZw,Qjz\ā(xOU;m.i\-C:9.&%rb E p|(tkfVQ10iGj=~h58p3oՐ[Ck:\o=%hhHwuKVv6Ն;ny۔A_rѐ\vhCR [ gQ4x6&f٭c&E=i!aUFׯ_9ydqA,Pz9@yϹщm&l@gٳ3Tw 43%3s֜#w?_Zl_n]ְÉ\lth|:2z -?CBhgc:cLR}i5B;w.ObxwNJ@lk/ӨPl܉n FatЃ}{ӤDY ƅ=-^D9{UL@(r BFSuhK'jSϑ 8N06 4_sG{ VpEִZװgC<يa/ЅѸBq ʥ-ޅDlV>s| Bb\2]ӮB#q3ѵBSL /_% f}{i. P="|فBm=1P c<7B_ZϥE<3K.8E`fmi3,]65P FŰ0p c!,tVnB>q ?rBaʞ4;Fx4VM sLJBR#٧[D'9\$v!?BѾ"ԨY8Pꅠ󊰚( `@% fG3 %oo][-^N9GG(8;w( \y#BIFz K[⁠a:UPDf@(\}BGpHuPZcC,޼ ~(搔+УZ>HY'񐔘(4Nl,LO9H9API2swUV|50wBaH*+V 'oWu@S&^ _^*KVg %Dfx 1!3'"T u+ |* L}` %ܟK?8AD#:,FLrr%K7e/#/7JARTH盹 wXVB7W<$ ɵXAwDc1RLtARP\l>Lks%(dHF@b磌.(VBL̛X`:F!I. QNa5̅( -H !+F*<ܿe(">FSbPFEaۏlEDa'#>(t;ǵ>TKP[(LӶF^2C)u6.rnB{0s38խP7krP*Ff~!5v{3U k)CUY!JEjec7ԯK笨k\9OXY!\M13M"nAzwԿD(V:jU SnI͆"?gG5vb8?W`k K>SIhBwD9#_'pl%{<,??=K$jDVi3<=n(%xEJ?\fx̂@p-+GA5@#ft~@m wӒdck_m4=Q1R+*pr #|^$`Gt=i$dU*_T:Wt~$ǟ"L !9=P,=#+AHa'{dsq 23?֝2-q?( 7jFg|G| ڏKgA"zֵG*W젼I{/xQ"y~FW}|"jw>}Wz| 0~q]3/a{R`;_/٩_BbdQMqX}blݻX4!xk;7Vi$Kpv6!U@yT-W`Q׏)eKw緯)QpZʯDr'LyzJί`|KnmKWS0IHd`%^; |9@-]:Gb^Ib"=wg1@xZ+5z)G5ӥf[~M^zpN)`z}#:/x Cbj͌v`!U]&8{\$EZRnyxA&i~ `תI*3OAe5x`U:/'5k4qҶ7lt1vv4*̓Fq|.8au!?~R}5$-OОͨB5Ă4ؤЫ&VZW"X<5at%f!لH.-< ^Pynao #u|_Cfڹ j0r`^!iK& :O\rAO'wJgͨ=Mu Wt ޖ(X`nKgc[w\p7[A]|1.IGP=gd1 RI1iu_!~̽򚍙zS+:AD;d&StivbU'$,& tD,@r3swH ⩻'kϤpdg,dM)TɫT`ykrZ%GGˬCp"nN}d;|rlE?!8ܰǾRz#d"ġh?abc(Llk F juͲuy~](u<-E) VAHN]kr a^Ҭ&}aۢKQgjpE]1g[ңL=ufl¸uq8p籿}a9dIB&9iaڻ!0 p,28{.U*j:ڳkeNm -3G] ߢ!Ə@V>W?"?Qo˕rU/Tv Kΰoh @LeǪ#[<̋CjMJsћN+} # cjNzL֎JK7V|e;R8+.sN@Jb--c9npVwvƩoAݱI,N;9z= ^ᰚ(6 O; 1 "TQfu3$UiWK֎x`S^]uSS[C$iKDdWxS$ 4ts I?޲Uqtbxٟ}0Vo]^OE%A*ܻ.D\yFŞK;SǶiU5ܾv\`lݾN1K2&68}ւ#U-/qrfb]C=j F]1dc=*f.."|i59SH8Wl+d&&/oq?E b/=9c,;ay"۳z nϰP2a}gKJۮk#{:f]M%E||ɷ,0ri_yҭ>[D 7}'dl-c`uȇpo潌zFIy [StwW.2Y#o}g=}AAŔ"'I_sv_ +%|җH3{ysgX Y V%7% ~e'l_Y4 6غ,W>" gRzssqgU_' &. ~@$L[:$&o?1y`-\_q{~|pE3Sl| gB\[9!1X֔O\nƜI<'Iй]i ֐%8E_1BMiyׄ sme]myc8YRAWV͓MH.cD3nMlj^DLo&u)r~Ov|g OP2`ChgV>Ќt$=_πפԸ z|w8Y5 ^y;($HC\yI=3r]0iאz~ j&vz0O} ym/AGBQoЦ3%aoUӈwA`EI!׮{4C^ wEfd Z}mg}&w߯l%;l 1h~XNؽ'6ȄH&|ŻX#y.8άx@d@UF9&V<%5J$٧59; N_1"|1 5\N'\l-'+üw%Kq.> -|O/FuPuf>S'S.K;a\[5.l;nu'Mɯ&v|Gf"w.p;[TQbM3~<B<Wސky񬤈5=qQbPL ڞ/!;s9\DjI< c݌g=g_0/KۄrޥşaIBvwU iy Eoy8x</ĺJ 9Cph5ᕉB[[2lE[r 7S%j|3w"='xU 6buiFf᦬%ۥ5.U f0j\ >KIiIwA̸gjKe­Iw! +fN`=W]{L]&e")wH0o.zwlulsdW)O6==D:/pe_~ybh/xP|2xy[s`)&4/~[pi8ac[]v>)LF~ښaC Z`wZ` >V @vv GZ<ýWQ|Wٱ^`>=F f}#)IW-1H$F opb"xUkVPZ|&q'? ~,kA!9l)<й~Esz1< 1a;zeO2o 5-?PKPY-j  NyqIDE.cfg_O0Mum8/ 1 -˲oo{01̈́>z Mu4IZ}8gpStz+%+p n0CA{`ZcZM=dukx[M8/SuZd O6mi[™nr"lHV,9\hsYT7}iˉӔ<3Itƭ>HHTYa"qٞl܀qWRʤEoIޒ}%}PKPY-ҥ#l NyqIDE.resœN0 Eo_XP$ԁ#c7f11O 򂔥_ۦ}nrbDZ($v 0#fa,YA&lk/hY*䭸cH ]=m 8AKRd)KL!),4R2%)__Fx|}CxN y' %X.ϐ _yV0^sΰu}&0a$ޑf4+$aYn*xxFgu cVIlӟFTyi K PG} Rw8DyѸoz[Y^%̵({TnlrԎ{ 4`W%NYNnSf37pk=AL/1x!S|؎=1X*9\k1_؍`YOT+T w[avWo|У?~Wzbf|Mru/"xGMؗFlDd]+oY PKrY-2# PlotWin.pasYmoH)a>)PIz; D k(MRU'c/KF77mh?^γ3ҵ%L!?ru~\0kx}yyU^GCfjn`wػ??{ bgg됅g0[lXKowu3 im`+nѐd HH#a&vW[f+pIhpcEMTbE,>55[Jt`9?|F6S ew`ʔ VI* S2זw4cC0Rx'M;f=q7l32|)LB9㏃Y`yVb ܺ|Jpq= (%GۡF'M PBzOvlJځב0X߉G%-Ϧc*~ʝ"a@E /N$@ʂ@*)Y$o3 #e1{0t݀Ugx7,Yֹ:ȰCtR  qS=9X kЄ!rV;ZZ[d =;,qH®i0+̱{yD!][_l ,B M^%I"8*MPpZgN88Y8㓑*NLb /9{ВS-κS$9ըuDbu=\["T:+=T>*6|ֆ>f؀&Ræ&hDWϭMYz.s]dl@)M P~P],>餔p4݌q;ѭ+ÞC@cK=^;} ҹrV%He?m|BoP?3Տ)$p|Yttt~~lLV6oTsg 5;tT2050,:׹r.` Wz)\}?Bç@YZ[Cs5"75;I[AaQ[1XG(l1b# ܲڎ5<0h~_EԚ*ěն6 ^#JߗxBVhd[Dٺɭ\1/=#7i", ̽ ީe+ㅲ٦-05lQo[J0x]]ZoG0Ol**hTկ- D4@zHB. S5An-ѲNdKy@cifiShX, aΥk )N334%jI& q iݹ ȝ ] RdkOr6oS6d*/ΕDVo4o(F"F桉߰55q^UaC]H ǚrKsgF2e9h'F#҈'oM'd~~ 7Wud/S1v @m.1i.RQ*t^%i"$;]Gt%'DQɎNQe ,|!%Rhө!F^5+f}eZKm_70g_W [ϧLG |Y,=3g9TxpʯCs.9-ead Ȋ䚺Tg(\R)NGJ+TۚGyQaKQ'bV4NKh4~s^)A=roWqſx0f0f0fDepQCvcAɟ*@?41 դ W VZαbҟ_|J7狋VJigveA}Hn<|ux:UQ6ZD-D㔙"ev*ޓ*)MPK[>-d! PlotDlg.pasRN@s0iQ@8HEc4Hm;vNBwwP+B8̛f^[)I0 z̖nۑ,DT%)UZ|}oLԇg#J&6z*LΕB)gNiHn`\tXt #Hԏe7c"k|J7gauLB J0;Sp| '}kS$Vp%9_P_?\ Э+փ;)h1 34}.;f5ka8m Z< e*9K%MjDqKr1 TKN,{ j (= ue d-AfSXqCNG-6LV-K;ODdJG !rs hHQ# ĵx}=8R&=!K"1׏Adܗ"r?]{BE!٠Q=FGi(g ze OU'FVӖqM *čg#ʥ>F;{gԒIJkY1Mswf~7{ӜeTA +lqEۈ0  ٰ~fD d. Êӻ}ĴՏL Ĝ9NJ-5*O{ލVsڙMYL&vCƈdѩ͞ۋl>@wa<#q=滀zA? wA>=߁{feJpE~|⤧9jɹidNg-t]"nSݤ35~&fx8m-Jlځb:쑓)%rdvXCv">]|^̶&X1>p5!YbM|8$Zbf0ic9Yk8 [kt4"fûQ^M;󱺭G%-ŢI"z`KnqT=1FMM}d~o(fgUug힒r0C2xۂu$.>FBS/i8E] RXx" ,Jfw6d ^A(Hm2Ž?5?=~#}#k}lr+ )*1Bȋ 4&' .T$`so@ t $_n;!b,^ dWc5l2jxڀ'{GB~8V }T?JG28'=Ogr{Wi) K$#RVj2Ӓ+\]3LC:˩WThf2xyjK;~u͜?BL*J^X2řӘ{Vw ic\caJbnϦsZk$.IAP(L',K׉ ɺE kbV AVy)qD ]W\/c [NWI1}U2+)\HBVәvG" &5ݘ(.7[-#v '%r$6쾎(0,+ʜvcsj7(+#`aƜ낭`_>UjE}Gs2 z''wLla]z³E=苰Z !9@ ʐSP68He1KG \7jcs`7Vw6;rMDARh KkB2(O6˹j)Ze/aŶ{&!O@ =/QZNN /g8/g;1ao0 L9 5RGCS'i4$?8&Adu% _QleYTij#}ҙZӚca R ߣKAc~ +=CiHB.5 =8Uԥ+m վHr(9h_\"VI ɋ &o'L;}+uv^:d7$u2U:,FL1cmBR!tKɍ/,elEls9۷o7]#C" L:K2hL`쮰aC Y#k 4/ǹ0K#AS?>e_iṀk!osbINR/pszKA x"XG& b=. x5>#I+@8 @*qخQ w8V2..;d]k)MM+$YI aρa^ho@TOCYg_$m޺pgB^Y*EյhXVminׂkd?4}#wa|+l=Rͮamv$B#3bzZ7ͱCD@ֵܻ2P)|4٤*LnX.ׯPKt- I_MAIN.PAS=s6w^:.dǽ'ǹg+M3 -A6_(RGRNv@C;uH`X, b0ggA}矅qy0xg]Wye}:g=<, n9<FAwi y<>IAu>;SDv$\&x%.n_Yx/ۻ:)x?_{exA>k!빾Q4<^ )#1C}=%%Ǭ r ySl}wo=fA^1x9=yd/2:un"s/SIgof5WKF G1(sNˆi+s~_m=`#+Ka8ԟ~ K.JO?~+JWss_νu>a᪆dν }#^=k2T ]2`PP,褺 Zq$U |+^L]r>A#%I3@L# í LJ՜MR%:}Cu66yDJ5z3$\$h3ߊo.V|%s2 sP2(`ޢ}Q]\fj)$4 Z$yŋ3!O=9\e4e=y0ا9.KfG |5 &2^ I #4[za #m |, ezE?AÂNc ^%Jhho*/BWphʬ {\BjKߚ#5 f FM1Yō@<\Vͤѫ:I:+8siRR+f x;>iCA >H8xjPX_EiU"X߼"߼kK^Z_L]RC9hۭ ,'Q"~@KK7|AJ-٪]ne[Vc9[)v:\ᱲ&{&NJk5 J8vKG馅nMDph-z46|e)aQJ-#B`gݛ]iۆ;58 SM@ 3xe0?# LB~)}%#vcWj!D">e %;hȃ0Kms5"Ew{Y5 \%i-<^W) *]| ^ ݤ-]1⍁c1$՘I M tFJ wQ:>R?ȑ}z0n>IU+,2WYK,d,LDUm0M{F5E UCT7Qad`zN&,7FQnh4^8RRb%[GXvvQ5fP㐔AV?t ,Atmʷ%L'cdr}6قKAF.\+1΂xЖw #$O߷u_ƒSepXIX\C_ T%L3`8$&XPsC t{0vQHŰq$ x`|_&ķq"U$ iD"aĬrXO|`}>וJ^Bc[dHN$ 2*ȖѳDKF2M~l("t Aٌ*Ѐ'WԣS e c1h} x$KYQaQd@b!:sڽծv& (9IB8m_r3ZҌ|="LCdbZ@91'_YxYm݅3V@_`Pu5>)#ý0;9=d`ɜeQ9nTU!WO#c, MPQB [:Q9(ZQF2IMEcCc5^;0!֏szSgڲQnоP9Ykrj%Ay48,TR8u[[%``!J*9<[Nz˲m2 bH䴢,_rF6vbEᴖ+ZAL.K`h-$n8pޫ4dM&`y fn\qop6̺XR%9t+3A },64eߠ;]C*%_򖹟SZ*n_WQ ]QcJgJÉ c~M) s=+=ZipW+ۻM2Wݣ '2L-]|.7}L.BKFhE)KꘓnS$2e鳷&լ~L0iVE *]YrS_ķ+3eg35gLR)WD5#jEZ"-CG iEXcXmZnߴ>j,CdhGPس)s:Z3ufpLW\)){6 jWimSHF?4٨!}Ѓ8޹Xj@[@y1;ft1=a=XyMrjdq 7]=͵e1H}ܕËfvHx2.8LI.N7 xl bO*?0FPX&2O'%G#^lOw`4xˇ'(kkR]z(ӕV9OpɽtOUBH3ʪy/#-y5QN0Y18x1Ule[8lmd.fڶ =++3ݵ颲kPR&h~)UYF&WZ hof6p+Y_.*zrjv<:u+,(+Fr; ed9Oaٙ B%6$mfmL23=**'NjS1lw[SJ ձ/X*nlYA۳Ϝ ҪU Ӎ w;؈^t#k/_-pxpu<_/W ܚ4CX3_VT13q ZI{jgW<[E;٣cۍFY~V(JiU~F 7E9P OphV5@ XhF5ӣ>Wۼ`8{W+hXw ]ϑZB)5P+t8CcS پ4D͠y y^iWoXnu< -;;Oxrzq.*I+.D) EqzYx=6e^TRIv:\hwƪ+l_SWj{7x#`,IԍgVDʝ^7jMބ8%Eک8{+PU}'fWn76nQ!qdFG5MDF~'YFvsJ`S+]}dϻdw"_\>ǹ%aS>]/G` 0f6Jl&IYBuXPdPݺseݤHtq{nG Yўcw>=:fO4Н^e# {2 D rXjPBMWȔA*䢑Ļu&<]1dg_4#lңG_HQݍ-#BIϹl8e ]AGƕOOryF_n|Ǵv,m9%u4F[p.ckUWH%-Ϟ c2 $SHGk0c&(I ިMN;K B\X4r~jhk0˰v0" -8k+k`p㞆(5|E"r %D1Me1pOh{+pVQ@ H7 Sa+ ({6ˌȂC?0v-3SdC\Uc-L}D#`z*c/Uq&="[L SI;O! !Agǝ>aN"b΂h ОF[3 @(,]coPKD*cS- GotoLN.pasRN0 W?E Cs:UB'Ŀ0<=qZ$4H#{ zq$D?+(7{ ''HΆ^LUNŗܺMƾ*ܒ;N ŶIə)Xmg-ʼn(0\s<~@[PG4*Z_|s6)+pAZ?dl#H@ HEfNiv1_(6ln@1sH#$^!%f%t/v88PK+Y-sYM ChildWin.pasNHE8[6mZˊ袖P=I8gP}ϙ=!kxfeg%tIH͍͍$4͌SAc}rF9GVI nrG_p:N"Ql}d[dq"LFu9 $\tEk2 |,B *SώNdD(wV\!z[kfRrq9h<˩Ԣ2Nbo]0 C.GZ5&ZŌwa6S4(0W;CQcƖb5­O7$J|a,a2n5ѿ}':q27ڀ6=Ơ][AMM0ͥ%3T[SRumܒH#[m)1x<)=ɣ-n2blV X 2k =fCI1)f\nk/@eLS:A"G'g?qWLQPVd]6&bL%yJĸ@$1S"\d4$D 0)kt.H47ZF0LyĒf,+pNJN+M J 8QxSkuKe{Q7̩%IfZ(S6F4-& RšGaPɊf/C6z>JG  |r'9w)Vox20O&> dhe׉B KI:fQdCϙs )t!2 ”qC z-w@-Cf1)s3| bdrWb0AA'NE'E?V?fGk\4q`v@@:;'ܗOr K -I6݇3l2Pa\Ʉ;G :X>DQ$f Lkǡz"b}@q/eJi6c;S&[.eYie3^rJ!{}k[9T^I. +TDZstW@8) N;m7|eRK8F%~(`WKG3ddq6f7>0lCUc(s57|LSheQy5E?9PLG c~+ٕe+ YiOt΋vRƭUޛz/}5%H"™K~w4z?ȱXptǹ\spwUzFof Ik2nޥ7޵uo8]kǘScAo_ ߝݕ>{ hʱZ.0‚j8 j,$RO ]\ls4=R鬞L_W .Dk;{CJ6gS:v\ j=a@qSY/ҠF]U=O;W,*cSi5A+ _WrI=˫0媀߈67PKJ-gHNAxisPrptsDlg.pasVQo8~G?mWUv$-Tn=L2lCIphH=$Ńj<#w|'k-Dk"*WvTx{#8'!_DFBʙǶT&s3d+Hp6 eb} 8֔vŻ36alf(Ŵ~vͪ";bvNݴΦm73id$ P4:?aXN&.aij-zGz0Ŋk#+SvTibGvfhj}6([4d)lkKHJ׷; V`@~LmH"H!̫swn/Uو gy` $5,h-LE a4~ r*̕]1*nr0}~j $ad7~_"11$i:^aϜΏƯeI@&_Z u?>H-+6D;{i0s-!; M?_^wA>|0&GV zOpa_>T JLv%VuIcP47e%TaKt.RG!V6㗧6r:l뼵S]&o_mjZsYZ ZNԎ:l~:l"^_?^OVo-O=!>S6 G<`aA̰Waj--'AxisLmtsDlg.pasTo0~GIKƤB +*l OIjqTUH:Z}ww$7pp1Xu׆3q&ļ5>o_L#1|M>gB5(  5\KD!K_=0} .h5,$Fkj"J,gjѴj61J*6•qIĀˮU3OZlX,jUh[gҰ8`CQmVQW12pN`pst,Ѯ|n 5: `N1[ (9_mЏ4ݷ(}ĽYCϴk@f0u|I5360E]4y`n)RBۥJS5ʌj:0sN|ܠ4<rxH \qr?;֨'hKh t0k4$='^_9 HeI#gKcY@(_ͮ+oDvz*~,n޼{3ߴ;龢Aԋun>t(Nco˅;~v!L/i"(No#[gیEI\R \nOq[{d, l32.(GåMqp_IwzRf<{[ޞ)տܪÔ܊4PK*B About.pasRKO1`"&^5p}Q9nwjm 1wF/E4h(rC` GG34s\(fVvn.W(kcFl;ИuheK;LnF1?Nn76N` PKPY-E= NyqIDE.DPRe_K0 y2>uZK79s$&06l %*-;MzTz&i2jԽYXU&x*/k mf#P8K)o&n=L&UQēANy̫e3L;?n̢hu]3_k: Whg]q];Ў B8 `g?tjπS2XiJ N(ĘQqi PKft-vU PlotWin.dfm\}lq[.yw$/ɊFjRqU:i]Ȇ%\^` A!RmQj4j5@Uam,jPjhיoF*ѿ}3f̾}= s3s#p윛xdKyugN:nL\Xn3O{x猎q[\9qE+τH4cs+.)} V#v9 |R>a88dCaYg{G ;12>\'1EsN]`ʳ{65kAŚu"gӾ(l[(Q;;22cY"e'^#4L Θvgp \t .}p^*Eu"\DBP"QEBE:p*z*E@4@EeTU]a:!QE U( P}A:pD_"\Dʀ*E@֑"\DF#Q@#B:pv#Q@tD" "CЏ( UGU( P9tD" 4 QE!HGT.*EdYM'W-ṟ*r1@1BEݘpQX[[c{B(ܼS?xe|`znY'^k ^IkJ5z3Ww۴ٓnh-+Zkp9hfK}ܵ\v,- $Ml:)GYkҥƷ:[׳}vwV:?8ڿ[ڨյ'} 6g*l@M3F"ǎDLX^-Xr +̲r8gyowP1Nl7mTo:Êe(vC3d4vm;'Kg;i&6j۠cnb^tÇٕmN [ӗ@lMݹ8u3^1^Q8a/^O'LY{ گ\xT(G>ܺu }]xwp.c _C^{ACc:x}~|2pf.?]37N['D񭒺g2/Sb?W>t5%wm{ Ͽ'&Dz[R)e1h\]+s8&ilg{{ٵG;clx_{ #ז0>arfx{T|na7D 6\ccQB7`jgsxӽEbOs)nE"o' si<i'4nQ;xOW+ p]PcVg^xNTG` A&}RCr/7 5Ҕ#TiԘl,э)rS&S 4SYnQjv*G%W|NjICqRe;ѫ7ZLDJ'*&3 4"rs9SN\Q 2ɸT"jɃ΋dRRfA DUVL_R+@y(NTL4(0a+ӣɰl!ưyBF4Nhs4oĞ)U2bSqNA>LTSo<'J!$L}$#s<Ԋ l*׉QQHpAԌ{Ҧ"MO:#N7V2ܲiU5D@\IpY/udd i< R&d0M/9\c΃M 0[dt @O#)_ %CY0DTM9dtLPj1e*ڡAqy D >Ʉ t[MT,* (P [S4rqH,Z2EL^%/bd"4epCrZ Wn)%/V $P$zXLQL]OGQVNP(V@3{ΤAyu odj}nB Z!EdA"<=&#S H:ΐѢ$$Y=0bҺp'ԛ!|MUEP$g[5aHESXb͐^m6R:^L¶3pQUSQv@u!`z3U2 U35 hJGOz< SАN*S2o)o84R!N(<^OB-O%2)Y$XESb@.ZRobU8gJЦ&IVՠiFh疹 R+U'{mC/_m`1ҬԠ^3REݓW$&Z0dY9P供Iz$2kH1H{,e4a\aR4{iGuvZA]c#X)Ș/tz+easw|<}'/!g=~<7e'_?^ R-ٜM_~a4ּ{D̳8η~[>yχxqq)閏H\ԗ]3v19!_rC¹~?Qrn^`62`*\8Gm<FAi&ıS^-zק(AǼE1Alt|HQ'!>Ó#Y?D%^{vܑ߷o/!^} 2V2ϷufjϝvXr_O T;|J+`;=v;] y }6!LEpdp 18X SVIIF-k0$\^68WR4T5gbekO+-}zUTS޲]'֕i^׿Ҭ¾h ઩sWd0-jNI\'*Ӻv5emW*[(O)B.c-9 %5*Ǐ*'Ʊuf;ëDNiԫ}4 Uҫ%WF|׬e{9OsS/h=~k2'bgcea$,Vdz?F]M{gtb]߈H*٣/VBhG%!ɾ5Čgu.ŝ:lql#SNl(}ba5c@ʬOz+^\QBHl̋3Ɓw;V ߭7Q^pDhֈn% emY+7 v4l2~$uN/лL/ě.YR^_J[+vDDjl-3&:g.l ZCiƶxqHA{Лirfn+%|F?gXpXEØj 4BQyXJe˂¤7 hVbR)XEж##atDPrNbۍK)bzO%/yj4 U'i#Y ⾲§#X|u쏷Lj/pB>vF\RktcUz>MZڲIg JN1 J= oU|7Okzmvz2~֓p>lVm80kaꁄ_)zIfwi6P ͢$^%.8'F:_d&v0>yfx1B+'~ lնVj[mmնVj[mmkoo]k"`}/.vVʹ7]S zZy ܸQXOa yf("(q8H1qlvX 2z v:lY5xgc@fj+X1b@1u|^qF,5buQj |a-4+b7_?/~=9]\hhQ}7O"s.N8~h3Ơܟr/|6O ~b>=r~/j O=!>5 Կ/mԤ z!~M_ϴϮzC'^;M}`I~=#ٞʰ㆑CSEatXDK(ɿ…^18vZ 6Gz~&9z̗:iJLk>[] IXtĨG[ܥ~lH}:©L;p_q6LsL褳 :~:eCN:tv> Qק<PK[>-$+ PlotDlg.dfmu͎0]6I4,f1AXijڤaF-JD-`69T6H#4iG#6}s IW fd>szLR.uD5ntvcyћ2;C(V"gr4*?8ަr熴L%V473خ)?\_%3>" S}lliPՐXKKeŬ;-:S"4ZPDiR}kIԝ uH`FY p^V#M_h>蚼ZX@S- \Cs<M}p˧XUBëž<"=ETAU>)ߟ-a 2n1? d4= p ʁ4&(/$UBibn咕~*k&HBAH-VtjXE,Y*iȌrvw]LW:z N=W x=)IzU.^QΜC9h= ]u䖝2鮒LT]_2aI7`kWc֏DCƒVv5 !x&it}o&8N|U- FB[';+-q✐n>p&}sxc+ 5PK؞t-l".MAIN.dfm\[sGv$ ċ$Kb}z6HU"ARxJ_V#`HNi0 AL>m )J[{^]w,Owt\@VfLw>ӧm+s˫KkWץ4)dٵw3xMt)%V=/ ԫvUMv #sW-ӵ-C-혋U-ZjVZwuLeWw>k莛[^X*Zeˣc^iwJu.hjpW,SwQp8OU\ylaqinZūsKay7uj5=73gplUiRN&)_rw -+e@32Šf6d]3E[S]mͮjv&]ڶWu7tGmh,AQrm:+=UIf8]&Er`oOФ#8F<3Ⱥ~O3u^6+ۉ[à)S. u5{͜VNI#'6*6li7]"^=rlr]vUdJL]CJp`I g^5xrzZ.4ze~Zq'UVwԦ3oU)FCj躦Vw(@װt(]MUh-wӒ-鵺a G+8pl 5Vͪhꝙyf,f˩wW-S#Ik %"`UtWK .H H2bI7R]ӪDL _0StA"^҉2@]WfV/VR!q&NN͙Z3W* h%Cu3WĂ3(I33f=)G2h>:/_?!|9s\W>S^Ǖw ~?<+wd";ƸfJWu[ ]A;Aw̓284RO]1Y*{{Ty4=GQ~?qJouԻt>u-rr I߁ɋ\ _5*/n{ĕ?(t+/z}xڟly[޻ :Od|t.ل~g{y^Skĭa\\+*hi^X,Ea뚝CLRz]w+۲Y_iUaP^nȬ[F/ޱ[6f<- k`x\mbfb(F=O_iDW;{|"e5T (MWX t! #k[w4gt@VSZV`Qv 7ejsYV)ia]-Cy# Vd23| Hk9wC仁ܴj?YD7_Ԥ"A<,$q8TDQ&PuB4ɷz dx|F!2P b)ބ~.h)(wKjsNHa;7aقw EuKZ4 ۡJIoDIDLo"֖XUPlE|KWV/e'8!Ŀ~/?<=%ӱ_qtars0!ӚG;h$DAs䈺-мaU,UdDV.BI:˲h f5@C4#jφmc$n\e65F >6O:b֊jIF4K4ňbt,ˆXs\,yFt>hQ!#Kt] XNIs C;Ww 8^q4hxU𚎣G뙧AղkA ׏ThDڨAb@~h4py07] ɉ8VT431 u0gޒ[@ ͳn&`q2CxR;oe?F= &◦@X/?|۶tw],O$oyjdYa/n# &D%:-I HV m7p[74K4x{$.x3;ѐYmpc8CCt?h9/ZZ o}ZPwZB)ʒ)v"ě^]&]?+@ JAl'AaQ8GFrSDm9v9}?Flڈݞrſě(Bwڳd>)5Qʞ2y_<aJQc|{uC#MLqrese1 l!פ&m|z3 it#e w3x}$7Y:$)/o|ś{}d+P fǾz4w `lgϞ>mxTf 8<.zP|mkM!(pI@Q.cU'r2sK2!'_rL@[,L&ɸn~.Oyn3rI{8 qq˻aAVIB;I4'i 2W" ^#>zڨG5ju'waC˵9O6f#Qh[+1BfL_s$62~˸ݍQmn5?}Dt=jfj& 쏰nx'E7SfJQ4hבԴO1R) ogEf 8zl.x{ɔbfGP@rz4i!$5`rl+ |[R(IQ5-r HKQ5ΊG?RR|:P_e;[7htհ٭ K %p5;G%6uCsr?a8_5g,}H}_^ɎZD4t9xV,pFrI`&]FЌ$.01'၏{7嚺9 re/wq93u7)<9d9[CT9Y:AΣ2D;-tulAh:I3/e&p bSŔ/kyݭu?U;o5]E-_( [W 88NBW^)ra|o4kR+,!F9G0,s 55uwa&G0qaD N'b-s9"w#*Ss(9P U`1w: cOIȅG F! |w_{z L0:$ꎅFyh‘9$nS CYT., ݜy7Qfz2ذn.b."Ẓ$<>j.QZ#i*6#kuN倽2 p>C2;cgCV 1W8xKn[EPSTŴ!p~2fZٍ@bLrp5'y26>j|eF`*讅>,WaC27B&]mv58q.$3pB_vX1x^NO%~[h#rCVF,[=:u+;F/95ϋfD$"@­ 8"P"q-rK镉K FCR&$ַUM\43%QI!jEPdIjHҷ5 y VM MHc2T/V,3+VltnQaXFP›#Wݓ‘'dG$(yyrq[Ѫ͂"5Z_a fǮB>=98!N.$t}qp>r9dGy(CΓD"?1/e&:w5 8P>J|Rr@ `CoPr䁼l0 '8M~IA2t['$k  $" ]C: 'WWfȾ[Ⱥ?I?I8pq88pq!rw4v`~?>ѹb>^E :`)^{{:#ht"η9As^OCv;"^l{ѧu"HxF/?8--Q`K ֭qw4ЭR;B Qk{wWMlLJʕb[S)%mQnؒ!@ȵLڥɕ-!Fzzz魇|T ڜ@2 GK5)rv8d73ftr=|?'2a qx ~\}a__SjqyZ$ Ʒ~/:Z8CR}Dy|<{w0$=_F8[vwu|46OjFY?""]cv;''.v޽;z?k09)D@aқO;[/; $9L py$~koxb 4$>D04xkik-:q~{뉞_5D_lwo#G߮~~&B o">8tmG'|ˀ&܃H z+QD0Yk<@ "ټ0;=zW~]IO?kN3H\=?G wB=4, LX/~`9VKIkD2΍zMaCqL\ a| \v6zc_ >3Ye?`@5vf@z_ "~{_C~q|X$X?>@k 0`@?w >'~f {;O\V{1uvn Z[Zy@/G.֓" M"i>~H"Ғ||= ¼~- @5\8:p8#AI6loQM̼җtY{c.[Bb2e~esotgH?ZA76ؾMR)Nl<ϡו 9b,݉\CK?5(sLVH ; _˒!GF z%߂?;Zz󑽫ۯu͗ioc"gH;Rd)} l?6m8u3w70 ۏZ~}?ZyHbJyjM!948^ya>ۣ>sS[O'[s8~?G_|`wL_ݥ}5\˙tW4tu}rDeP><VO,sH|~p>_̾ڂMMPf4(jR(**YW-3]+k%圫F4M9t]mAҳzo yc^]PőFIҬ2h SK87M%bτ.d +W Ukv[PYkꝡ˚;jP Z(9uWR=lܱZMWuTBoS_Sf\]4nQ W+ gZÿe J p{+?Kiv'^cuűR!R:Oi5ht*6&Zs45A3T6 lSTu:Y؟x־&f3jVgcmȯup\6cRJv,kwuκjS@]1ZkzMWTU<+Tʥ92{ʴZzFX[:3ʬZ\\Skv\QOgn?+%rd' 0C۵y*{9`{lvkz?͗oiJ7hefqnX$=g&3UU;{BAZX<].k2|~O>[˼ݘgS]Kw^cjKcg,Lួn:ɉӬu93gƅv݌VfvF7+1Oȃӛ*O;3=n]DS@ӹ ݐ AeyF}TCWeY3|aIx:5ʉAx[rQi|Ƚ4zgEmWeKnɘ9Y`4,B$@dE9^v|*"'dYڵjLoJĄ^GXu[*8?=V"ŎymXPP攥6ۋDAA\+q?gqp .V:tY"_ckOPKWY-( ChildWin.dfmAs6F{hƀNL0Ӑ: 1j-6D2ٴl?K+who_~j]G໢B>Yɍ/PHd'*Aۅ3.tɆ2%ᄧ,Q@Ɠ˻oO(OYϲT )dK&[sf9cT垁_Hl1aوH4 tԧ ԖqR%ƬsFAF=#ZcZNQe(o(QUX[}L&7 >JNb)w9qkL)%tYWzps#% \4S Smf]liT4w[zG>Jթ#(xS[[_kD/QIdZ#KJ/I$e` bAdkyLOUk'K'jcm&IU^ͺc}e4"YrHS`ׯ*)6&&u}^Qb3<^<{DQp .aXP"XQ&eEx˳d;>$gErs%ENyay^.e pJlU+c3)kr*u]!(n|,b.!Y-deb遈yOǫD|ٜiNML#3U$E3\1RK-,D:o6sy.5R]Sf}D[jp͑݌HˆB>`! c|Rq*;R[(=WHwJWTC.[<~`u|xrðb_UqSGu/^'Tg@:?LӲV+tka ݒt Һ|ÅsK/bNSy@QPK. 7/"Ek Q@X8ҋ 잋}`H} 6\OU,5;p^q8\7H9 yK;}{׈SnܐKɷNr``q }k/zx`{Uiu B*I\[L宑*xp.ӌ{@ǕpsGS^OR%zkFg|EƘ-ɤM1eTRH}ą,\f]~z.l+&} %O^ejo~ɘea :Dž4]#ZD;ṾZPiQ!"N,n!r>KF/"{_T-R@z7W^؇mo 3"|Dθ"v%X{^"nt+b%x%ҁqAEx"F>"gx%bƐM!o?%1f)`fɦx vW)lb)XcP GM tG q+5[tJCb%,ߦ6 NrnGC n̈\n,on9\$] I>UMPޓahC5 1wtj<;KzX=ߦTz)U&\еy% (5fd5o8sKRpɂηThc6lU#[` '<]%}vgފvj_FKPKV>-)AxisPrptsDlg.dfmˎD4i ` $ґ fvۮ$Tr;`#OĂ P_Ҹ[b]wtfo0/fgoNX(d.Ft::]#s@cu 0 ۣHGk ^L0Nt~Yƹuzv㮟4C)x d:v7e59$BP?|&#L$E 7&_cRV,[Jܫ[SħcyZăfnO=Vފ 7лu_"9v@<\8p"@+tl T-hX;UB`[gJW>oI(%^% )sGLjIQ#tL1Ցt.Y,/Н_AIV?hKMz$`zo]yD6 ^4(/&@x)d5MufdyJnP!pAW$1;Rq~7Y[RrDV-15!h@z$nY)`Cٻ;KMvޔ.$p6GB*" nj4*=k<5jq0ܚ6Tey,?T52kuY=j7̞;^<*P2p+S$)$ས/S[6aW5JKre/xrݶD`_?o[sFc[L=}|`tc9{.p!@ />%#nV}c-.9Ls|7'`FiK2s1ЊO6bp̐ʙVC]!PKV>-(0S.AxisLmtsDlg.dfmR͒0􃂻8eP,n ِ`f [8>5MKqq\7@vA ]3 pvZ`3oɳ>7GqkM J}Sz,MP4cH\wcFq;G^b5\ b _N0R݌ISƨ2_8 f's :ݫˬP+?Jzp+A!JS*vӁ4FRrV4+r@DىE֫۴&m')bBGUzS_q Uu*:'[VEhL<@I?v\mrKN˝OEBHN`y.,":[O q5$kCD.+Z:zʎzQOE~*B诊=LU"DPKZY-rj@ About.dfmUOoDmlͲ.9pvS*QM,gX83a T+F}*:̟?++ *y}hXKBUS7Jߠr^Ұ ":N_beڣ._RAN-4"9R/Ty,56{-j[Xa%/cA-"Iy@hS!RW0.`x>Dj}O]ߴk}tPLnnn`TonnoA]Ԝ͝Dm1@;è8IWQbcQ[\׹V:ײv\աp`@];ʹ u:{kdh 'i1 w`Xx$`TyqmcHvd3?lVJXDP6_!}Wx&rQ՟U:֟e0(9)rZԲeTNsyF,%gV,Z,ޙ٢v1 4P,Mag7WPK ft-O33 PlotWin.ddpDELPHI.DIAGRAM.PORTFOLIO@  Untitled1PK [>-O33 PlotDlg.ddpDELPHI.DIAGRAM.PORTFOLIO@  Untitled1PK t-O33 Output.ddpDELPHI.DIAGRAM.PORTFOLIO@  Untitled1PK ؞t-O33MAIN.ddpDELPHI.DIAGRAM.PORTFOLIO@  Untitled1PK Z7-:k!! GotoLN.ddpDELPHI.DIAGRAM.PORTFOLIO@PK -O33AxisLmtsDlg.ddpDELPHI.DIAGRAM.PORTFOLIO@  Untitled1PK ZY-O33 About.ddpDELPHI.DIAGRAM.PORTFOLIO@  Untitled1PKbhd- @/ PlotWin.dcuZ}|ս?/OCHKZB,`Ѯ@Q@.*r.նE@PC$ ILRL1^SйMv)W6|a'Lt'M?s~z )!"c;_M:\\M)ISKuSi{|kv~Qט$<ꞐbkpqyTwv7/er8ZmPuVQZ:)B8WAO(puǧD ޹q5mO&T~ho ,ieD:/Z=&-=mA`%j۳F}vuou>O܉ 9ڞ4`T)s?"R0.@Bj5,9cՕ9a/Sh]՞Pe{SG<4C=Fo:հ洜~]'<`\V3 jУp-M˄5&OPu=~_O_[pv}]?uv"Q {vbC?ܿ Q {h TuP=x~y/w}7Sn2'q3Uryu8=G;{ԝW1^péê׌C_'5~,tq*`e{mI7畼'u&LUǵ׿YFhGph`agjPdMNp:ɹZ#Uh3a3U&3`ᨡqhq^E&69 YF~mQn!88/܂sF[~{s(S;UgIN:a@U~nNN(I,Tv VpD!7 ; BK=RqQ~TNnCդ,8S3yMLdj[jx bikQ4d%9ԥgZ@vФtIPQW9Kʙ^oegB62P P ΐUE* f,.H +ϳd߁q=肉[zֿݖQKS{U|lGۘď Ut{\ayyx0 >nHCp()S+sJ3TvhP[PL^6!h`rۜWP7PɭG,ۺ+5’Khiwu?>ӧ?T 9/_yWn5MAs5^; ͥ Îɿ .!;&l9/QaN*\8h\0W0.C/InQ\7>]PZZdq{{[} ɛD~yHmy٭k{COjJOpP)?ox G *#E753yP D^ba:k?:pdɝo[e%"y]Fƿp=L3E|31)jfHՄm vSEx'ECҭz]2}sAKsTpBGD.ʥ8E>to *#p,kŪ)Eӊi&+êTiy#va zh!?#15_ח+mUel5Tj2`eC@8dmpT䬲ţz8rdwdeꭺK;-S`%d~4\v 9#`,"{q0r>Yl PJ[qy@*zU֘aUf_. kxMrTڠZ̜ @kխyZ4RGOs׺g8ep}]?JҮᆰ.L'#79p4kVFe:oc̭,\Bo@syp\. yk]#1 "F[^,zG9#QA*m_ZAVh"c$nuRt1|܆bBvK)6ΈvGwkkuRK_]> =sinQ{f=?755߼$?d4S}JdI<ī,⬓yvEH$2WTj]ZyjyS6=mNԯD닾}-4E,vGMgkhp߸ve0hkfm.:6݄,{^MqO`~p벹OikZ_Ro>~yk2N֍lVli|].~ԭ /[;F>DV% u6ڞ\+KHB$f$2J~tiwd-45MͣҔiqڴxTS2-MjLKhW2RYIvsW~㡱+H!LZISv1B1+1|‚O*d [е^̭&~&h5?fA eA 'A7ÂAt-轂mA]A+AW AW F}U}F/AAo-AMЧ =A z 4.6cR^E4mN^Ctw9cПLTC |.U^GtmNt}~!YP 1*f4`> l?,tLd03YuĆ:q l.-dm`1 u^^.S$f3 l kbeM7[tw6۠dAfx1]V1ͭadKXy.`%\ٔilQGb`t *+WfiJ5@;km^aIi])J1}Ѯ`L.EިR6~ m0=1^vQ9XÊ:HZLڨXYPlq6(RX)$E0f12cooS SXA^ xJbzc\E 0֥;J f$N ek9:.N&"'VR~'xΠ$-<Ř'͜?NBtJ^b|F>#c1b1̏La2 U1,[ VKjb#2#ΞR%c ^ `edn A.A%yp1iAISU1̑14ji1x舱t`l""}1v!#bl#Kbl>#KcbqrM NYc-8cI⊱K鏱6FVcD}c(+X'#!֬X^d׮5w"Y{>FnGv}@vz%߉-& / {-^-1do ku"|l+orFnGOdds[8 ;(wo~FNPE`w ([; }`[cFXGb, IL틱 UZޠ w;.h3C-=h r,d/yX|)K| @ҚG*_W3q;? ;:쥞l /"7>?~8axs$zi9Nux[D$`+4v*S؋X"^Xq풘4?PKU[-C.L PlotDlg.dcuW ogx1YcLXKU(J*X qk ʰsww`=U`(4Mi+j>`kZ7J-FҢVyTE*{z=z|{yݻb3XL<ٖ\EwVbt4'62QR}FR[-K'[Jedm1OtGxG[SDZoTTy™{w4]uHOQUhϞj!˭fc9JQ&ljZK^FZe -.pW,CV58+R]B1ld7-9K~uh&7 A\bnk?>GS~,nlZ*׬]VX Z39P\(uݓxF?^^6 gU[zxh-f?έ_S̐PoN ;zI7:L}7tG-qcm|$˕sY]T-ӓ[i>-hǙ9AĪO ?Xf!@ǿ1ԢTa()eECn<8Q_KP_.nsM*vs/!Ƌ//w;}B[`ķOQ`ݻeC3+*qgKgC8P@n(Sպ =G;E"XUpvk JHFg^0D@%qOOZa/tJ`.+\$KԔEVxLv DR5n]h$_剤Jܢ #Z醨'>LC.Ryl:vvxרčS]~ 'eﳞ9:FǓU UT<7(cΩo=-8KV&+$zTZN'NJm7VJa{ xB+ULzziY5CC]'HrTҜNDzéH>lۡV jD ”:lanE'+}w 028r9-bM=\0sݳ)G??򗃣d$E٘#":0AxmVN },0%aoE 0Ft#\A—^G8BB h- E"B5Ba3Z#O < |a V&!CDhGh@"<EZn!D FXpaW.!\F8p0pYs#\o& T"їg_+#0ZiGXz-5[JoH}J@d%LV$}w n/T6DivIC򫒴(U165WU^X(_&p/ܺIm`KHiej<}YC{#LaV!$\Dd$BR ;x(+ɯ<,3XXR)=~iZ`{$MHI _CFO U˔nVvi7ʃ/f ҹQ R|C%!m $擺~sy[b6RzaNyCD܂|-IVQ%_]U= yR|jijF^2-!݄QM,x,Y3Z)8S;s-ZBtYՇ2dC>`@=o)g,Xǧ +787_ zXo%ǃo(.uxrm]Us j]a cPmAxT9yYv'䪑PLB{rzў=ݽ\ly{Y"/f EksCi{+{yPBfC !D, 1:IP؊HXZBoCs$YPٖ7߂u {eg'roVDRF|H 1IJS&jFÒ7ҵrP ǥG> \ ]hS 7t-W) nJ%UY7g0VfejjRңb0ño\5b@ჿ8k qRVJM(97 Q0*=:<)4<&3SQ\f5- ݻÔvԫoԀ:c|S$8\C.aCH$֋(]:$`͌_ n:4d,-G|3Í%WTA;ZǟPKt@#dOhHZqeUɏ|l}h PX\*uw9PUpvBA_qJcG'm ܂ n>h3Lcyfil02D?XSMi3iMJ'vز.FkjM\UX'Lgs1LpKဵ+ӻ_Y+|R_ܗ_Pwk)˰or}_[rіyEOOg_<-6GVj/`=ogm9Dl(?i3JTՒCڲ0ooW8qO(wFX`ç|Yp6r*PlZlJgNXkl#DBZN\yXz.p*#kPcx/B. l@0>2qYvw uMf[@Zy}[vQE[> .9=oR@@TL{2ꓻw `30elG`y&NoRZ+DG]+@ʦբ,}AoK>]:|U{4-n,YZir'j3]v6, [Ef?|gBgK=F~UL~YP> J%m[SfkUI/2ss \T95^&"\~{+j,j5m^Yz˙B˥r5~a:39hY|/̝q\ܙ3X gs Ms÷`@CruJ Fs<'.*fao p)AY)uPَ鴺̫Ch3K{N]>5Z8ų܄\p;Zw$Sߍ[UK%9(m}|77MNMWVc:ϥ:Vww`j6CQ&z3hy51z?`\: إr F$v pN t)䛀`9X1 PZ{Co\Cl&~[$*d+,ϯGZ3rNpiu 8)rp4%N]EifBL%ĭ/lm|)}WL>K?jLxν!;9Uw`퍇j8̶A={e9؀)vg&@PXqxEqd,>n[1buj鳡ǕnzuB!48;4]N.ÑO8σ [4`D&?TZS)oY5M׶N |!8}uCn"^}pL)-/aIU]g%ќUz+BCc\hb3 Q%eB_Mft\5ﱸagǬʱl>V1[BXy8bdٟcVM8%#T8%tNNxWKF`Q8}[ B>mYC84P+'F43&Tg%+^I5A9K*iK!ck;4Aέ2QQ'VKr⺠~LR[Ϧ%KmE6|³7P"DFnNrQB/T/Cqpb9MFn@ѽ .K鄛Z-p\#3_HdH։/05"(%"/8DB$"D&U"$[ErHM$E(;ErHIH.<,K$"yL$@$]"[$$"$EH$"ɿdHU$_I@$"dHIH\"^$E2 A*<}_BNG|Ebuyg`}@iNZ cXZ"6ZL->MT) F!_:ri^ d7*dIY64ߔa9zDkDJL=RU0V12QAXǙENw*J{yn`b[8'4sul/8'8Z?DZ0p,Ʊ4BvQ/F-:%e(d O yO\lj |5y8 lǎ8v}t}38p1ȍ8{( ( *^eډnpz>N8=5 K4:Lq"t2)NpTw>9Bx^b# N/i#?t8ϲ>y^8t[l7rq ӽetlp:d[ίw+Nv>D';ah?9##w3/iaF].n:?肋[e:>G+'dOmpf=|N{㓆#Ks8M8|_qW˹#D]/_=(Ya:pgAPuUҐF#:'fFl 4n&.F&_LvĤ3ց6?B(/G-t.겱'‰zP}"iB/kh.F֑9t!a$}x1S@)Kp5_m#R<:uVD *qFe 'p@UY oM,h,Ñ _}ƗY0I肶*҄td}d˷)`7.WPDE~tZ/ڇ`G:y_J x)49<~"j_\nɃlO/}F'#K|# o4F !IņMIt4N6MBILoQUE=x! Cf]l8^zqi˂'1,@(TĠ ʼL"<ֿh dH{LIs~,j*G8?}R).^ )òSl7v&szLi Җ6(3Mփ[iTn&;Lrlz~ꂣlMA0:bT&"\QhHLF5ݎ ^Iı@mR̤@Q :H1֨Y;oLK785np YJ;r WcNERw:!GdE DڑDm|g줛06ćvY X3Ý"ϱCOh 9z2DplD| 9nz'X8   sVi$ǗJ(qK(bH`Sp"S?'wKgTh4+,cHGl]HZC3`SJBm)m6`G?"=H2)#ʨOe ms1nX#ug?* @eǶrԬTܻgkO,R!hkް: B ]mxxS o/]%'}U?}<~6);TlZt+"'g!iLpv$ABӈ ,.-%FnH83ahΝHTc'݇T"tO !x/}IgȐzuџ1$:9Kz WeA},?0nCTpZ5*(#pFNm9V6siKWeǙuvU#NiHVhy9\5-hG`&GUXLIaeT%ڎH*BL&͐ҪLu o:j~=]u0rV;24|/Ld7DNxul#x~'f{%,h z^}M`,S 'c\!+`CCptB啸15

    %=-T4%n}ڣĨ&llB0Ͼ[le$-SiLR}+`֮X=vrfc3)BKXN56IM!Hdr_Ш̠=ĻBJԗw= 8 㧎 ^mSԐή~G.k*QB Mь-A2ڀ>qgkg;LFM%M`/w+8حQYO E- oz>\xdz2缯 Ӧu59\6nR<5(1L Dˑ;CpTan@㒸5A]阡F+AWC7@#p"=+p획`II!I0 P.ًoUi 6%%Ŋ,4,ch8pFÿ>ԵwX%a3xOԚ[2|]7 tӞu=Ҝn~ *5﨡~ 0;|8M5Y?%@[9_'wчh{I,0 '[ggGB4hد0*.bPbKMK{[Ox^;Uxw]\0|l믮w W|奝}nk>wwn"iBƇ!%B fI"Udl},cEW\0(1a`c ;(\cw2]0bgSֺWf!ƛA@/]f>*$I66TWor+ #/; w3"XsZxxS!G%p"HyGE}{s %n!~ʥJaj#A[#]!g }:Hh$^IQPP|>ѡ:K44vݎmN_t]}6NMs l|5+HesR+߶*gH#]u9֨n2S6dtQ6N-d8Cd+QɁFd X|~|)rjtwPąw+hb2d-(We 6ɓP|{: 9!y2MylG(aS!Go}mTϷi#6 ƟhHٟOW(!9٧ * %5+u+ƺ IR N 5 M9x/cҫ6+rםzӺ3Gar>yn[25y *4UJl̘MO.@+pE՜+`y綖j8o(*OP+mbjNP\+ؗ܍7܃={v6çK.ĵ2`[f!y/Jaנ%$'{әiƾ8;13QzqU6]ܓ`9![eNI{6xJbXR)8~CT]̮mv#&*(tl860 ۄnkXowB6Ww84]3Jϓ+O!.e\jt|.6'lt eQ|lƸs0d>q\f q9.w*doA7f >k\v|1$,F M$d4)/h֫ Ry'H5s\>/r ٍG36OXW>XڒR\gߦKvːz;ᝉX?pak8;E / ^7pcya|0=#i.yOdq+wyQ>ii2F^cs;} (y'kY[~kD@z}ӛ5~$BZ pw=r{B|Ǎv4?kJCGX܆D**"N!<BXٽ,b5^ۑ՚bFuZPgEvf+,005PTaj4[ǽܾ:nզty};bnXbP"oރPgh|QWOv8 һgYkJBG*{`6ݴ։0ThD%M7(^v`+F-^ v|38pZxw/IuLm^nա58C/Ձ)xɋw/iv`ǯ=3JY!}9>>DػB!>Q͌ x 2* 95a/U Z|FcM}g?3J;۷ѹ}bXdUE ;` Sn 6u6Vex|Rח>Zu@ʍm-C.7JT.8 LtA=(_ rz:6-/ lܨHmFa@Qb)7ha(H~ز5ZrrWlN\R4oA+v8]@t S^BGUʔiGWk~oTdp&c!^ wL`(׉:Zbi莀Rtڼ,`Fl2V@XkfXID_՛b>ObvmnzD.Jt@s?6^uhIx5`T\UTme.h >+2QJ9rQ2 w ^aOFP@l__C} E94(+*,b](b581'U vxTR{(ͬcB{!:8e\Q4oYRO'AeFSVhƙ,*[B/L*[8*b+'RM@gF dyPT(J[dy8dY/L(e: V "ER%s@3ͥG2F\(q2ұY!~9h|.p:Qfb=5c:A:BRɎNfFVc بNcn,\tV:07c1ShPI{,e{rݘA}f}eE~hbJc#7Z 1V%NT[B$HXƂ<@y΃<5LT_8DT&dXi؏?$@,3bKYQ%RJ9!`S&B3QOQ-Λ:WV9j]Vs'A~$-0&h2elɄ@?%<@Ummkμ2Ya+3%N 2%$Zf$*T4Id4pbԥKBD.uL#Bg a> l!&L7Q\`Ej {Ѿs`Tgmݳ_UuL o[Ř iFb5)]$"a}ZKEVI J ;5kնg%/lytFZ3{mw[E/vL)yub{~kP9Ó#M_U:1_毈ϴ9.vD(F@OW76CZhHeC[mվ+5_|v`aj g.pƻ^Ds'e?ɳea`>]7aQi!V/=üŜ\8T\GNTLy7'1 )Cm2?ҪE)1]2zRdkd{O2z\ +g,]j&â3)p Ȉ--R9UY@G9{ م5n}Ӧͱк.!uEVڮ\wMB:k(%qlg F`L+guٍدUCf/>rbx!6UTf59Ī!4FyXXDS~,4g/H.T?6 &,<$ 2#ɖ g%D/@g&p@C| >~| aǓ'{bK񹥠?S(.nboaRsIhcnb<_FLs|(TQּcF?[$]{\… -2o\t `}} gQm >~5bLht2wE9kfrb^1K)D#QUl}^x ̈[xQ dת`O0C0]F; ѹMCw-fm` kl lGOT%8fe<8yvMO4k&[镓lsg帳qpޝ-R2v5>i"I ;A'ː]-|XOI 1GX=;/Jzu|&q;=ľm%b߯ұȅ9<LE >u ʶMD?q칏jSSǭd)>nFvYĀqdݟ|nm߿g"r];۝w^npf %WM :r4m l`d{6LJQa!P6 obr;۱U=Xѩ ٛi ' ,Y%[pUUˑ=tY1-Bݱ81ŋL6;zº|4F|&3xLݣJ4$ں\CNh5CsJ0ehc+E,Ȇ a'l<dU`tQ/tq;_*iG$z&m# #N.6|0.FܳQ ==VQ\i_]Oxۮ̢8Kok6nn D$e}S}!] Qu9oELY'I%󹌁1f͵um.c}3V!*1-vmk<-A[=N!pgfԡ>!ڇKvȻ]kutN-{=_O mt6Z{|K =rs9M}Mϡ2S`|F{6?5'0"v=ؖf~Gfulp|VWg|m:gCٛ6ovM;?y0]oc tz1WG/G<~迯u:xx'xmAr#q3'lz`]_%osW3CF}񍝫Ovf/ 6= TԺ%._"wI6ǵi}ʿ[oﭕs5z'_䃭;ZY~Mj%nnە=/dKl >xMCV=pӷ>(= >nk?EZSEa7yvǺ+Zr\IϽ{ ołϥָ:Y|gWc{<9p䬑_S}޽UGm]?՛7rOVX3MM"/0/Pkq㏃y=PaMo_Zhe-5H2dFk&M.B14‘gQy~Ðᦥ\p|ɛ{?Wלk<;C3iE kR8b\_Wc5h3}js/Բ|=dxVqh 7Vp.7󳛾  |dejˠO/;>`gA!Aᾂ| v}#BpOK돿Z7䛃2fX-W?Ci-y)ONj>݊oay6Z~ǣ\;%RHܗٛٗ|&e:=XY%7xh7=J#ࣥΥ\v7&deJŊ7o++7򗒩niI|+ʇ'hu<_g^:~mR ה+q/JalX$I[%.u,(+E [e_8ܱR{ 9 5 ,#5%$mvCjm N賐8Uk @Z9E<,X Xr!M [ @IdBK4H:$rrYr yCaH4C: =~Pv+\Un"D[U*ת@:kχ>T[iȜnf+/TjUZMVGheB0d r": UZLotբ.]m">XCz5 ;EYdMrk vQﴤ[n[<ڪq+w\rmքŚ4HwinVZ [֛=miAmJ[=ڢڦڡzmmں][[[whNX.m]7u~<42ߟ^BF4rf --%r,ebM&g;8w˥66`)1eڝu8UeXNYhG鲽=?1㟣r&ɠIFd:i [)X>.3]V-e >ᗍ2-̖%42NYYWsHd(m;Nx̙%됮NmE\5V: e[;3F}~lQ빐S>$[aK˶fVdԁ e-pee~ qbt(!'pHvJފa;>;)TW[̒a܀ݴE)E:[]gk$l-Oy8jdȬmN"L*[)0t-y夊`}Z+IQ ~aӪ&m7P].TuKz`e(z[A]v"P(/%BJ=%%ڥKXRX-ಀogɪPz,P+e_O*@)}+Z8̀%/Cp[)m-^TrXoƚJG)+bɐ dI'BΩЊ;agCXjWeIƳ表\/ P1x#D9$=A`5IgӁ8L Ee؟ʰ=b=ó nB%w7}G>GfsTfcvY%}L'fY< 3 & lҹ^pach.I'![нК.tsQf:$l GRcA¼MOyI;]pD@z]!{z}ȠnY* ,=>r誴&|n|X\+˗d]K5n.}) 6̃`ش4M Aa3kT)>,55RLJ]3u@ig4UJ)͉a?N ȳh/댿?Ar?cc $Pʦ/|>%nO"~M k&PJ nr")(RJ4jvO Ӏ!p8\PIJ>aY~o9=na<.@F'$%[)L(Șu^i Si9$.̟͐3f0LcϺ&q+?Gs/qư.0Vڂ#Ta: pY4<,&c\tq#QL0(; C `Y' d8ɫCv2bM.ok?1εXckf3 U/ƭƮ>1} n.'a^8 'V+')^=una_C\ ڂ<F+ݥ|c',z vI:w6g'W1:iT֗R&Ts|zv>UKjT1(߂ךt!?lz$lva ߩSy9ƘmBwuEE7}*:Q,>؉va)Vq8baT<6jYΡX==_AoV$OHR&l9EMEhecXAJ,r:AcQ&x# fE":Lt6]|9z\fAdh޳o\uTT:+cᯌzݚ Aa0H"Q`CHEHMbFFHa&㣨42N,&`[ b$Y@bE$ iYJv#I2n#7JwYM.#7-$=Fn#qI|$3F$H<`$ăF&;H QFge$6>$QD #Q ꀼ".l`lہDNB9]IWr.Jn: T7U1K=tT czq2nP5T?Q4Tu05@h )Cd)#A SdPM 15DT  25LC M05B 0M25J# M35iPFiI 2kh@uo걧{6lZ,SvJ곯25` \P =` mcJepΞa8ocg.s s%y*%vjL' RNÿ^md<0|ܮe<40F/:M sN3ü`UGv2|Du1y0 !M-2P2F1‡ $c:7i~u SjaZ \.2̨y%ߢX  Y!@Ze\Ncl  Ap* `c5 kktCn1fЩh.t7ø 7&I=ϩ!FaУ~'8sO2ФdwOfpO3L3 à{aؽpjj{)]fwQ}52Ԅ7274pz Z… N#&u26/kg_pi]g OH]g 2 FƉȘըq "O2kL3\f9ð9suif.IKhU -`xrΦ 1,e2 g0D -p(Ӯb<eBug _8mfme7Cm :28YPAq_10X'^d(SnO16N3ࠀ-vnyƾج_E_Lla06%ʢ忾Is]ta{zCGzϕp؟^0W1̤~8!ՓJ*x:,:]EÙjJWGLU/MQ{c2#Omޢ A/O'D'L)UT}eԨFWg5ܬ&jVy5qРJlEnUM6{UڑP?9B:mIUjnm{jA0;ռ8zm}7Q!!YPÇQUщ 9&9Z)N8i 8>~ͨ}Y%=ȓ"vP\ }K%l]V^ vot3WXkBp }k f-Ts^GoUg(C xk^w(<`(;. áz UгXh/GUDxh!@'CJ *B%CT]4 vbo݅āHJݧS/)OZ+ʬ[ݪF?Bjt VzFApF;#N!:ܠjЃi@ Qݢm;Tޡ ^']ڪ]wa 7} `4&5we)EOjZ/w:Gmh7 Y$9$"PguNzsڷPweUQ :cdQ b{[\Lz.w4#/j\ZBպO{ 'Vީ7c|`g\~kuus:] v:ݟ$z\)DMۼ~w=|qwqe{Qw%q&ܽmNQuҍO'9tٰpro:Y'88>ιg9λwq%wJznmՠ0xQnwRXᨖᨲMIlp ‰Uo _m w1d Nc]md+ܹ,.$;{MZԊ^Y=bip8;[4L'EkV>qF2-+O: ĝȱUĸenF·ye˦P9=SI4qk|8W u!ELMriۉ!->''.RHH|JIToWiB&tyqmuy0{%nGG.+}>˒b'mܦH:mNeOzx)[]U;mП,M'AØXŮ/g1^eC}:^B|ؼD*nYSy;ViG.IX~F@k 'vR J]\7E^e4vu:7#_ĵ &ruAzIŎj/ViL-"BF<]Ai5>asHOnpc%j-ptR:q]" {!=EunJh!QM9=*gS`^ ;}PFR9ٲz-XL>D*:3S3 ~'_BuʆR>[. HSF) iSZBY%hzn:ӤuODg*{Mr9"3A<[`|"|rq$|l_ցn03zU^`p!y _DH"Gx a+Bg <4Y! lF! #'&gb!<0B^DB&·ЇP0B#DL0Qfo t"# =jTViBe5ߕ6-kF&K+(Qb ,PkܔXm%mhHK2mJ/Ͷ]_6d\r蚸3PKbhd-i]% ChildWin.dcuY}xSU$=- %DL;Эdԝ&")M EMHT3;80": >#lwAQeL}Mߛ>| B=G#]߽t9W:G-Yk9=)XvᑥP}t}'XrF7{[`\|{]nf(!Hͻv5v/, GP+|'סN{siIA |] Dlg_r!T8R[י/w;S#.wgsM#9k=Sp$;HJ/ZTz i ,q$y/ffU8j"a9ؙbY,i启Zn n NGFPxoDѺ@X KP,]I^_).ϖW9K0w Hڗ;2ck]\c9A/o] ^ݟLr^8]#Gw5tʾ`Փ$Z$Jߜ*5΀K/4b35\YNi¾M`8R/mpe;KjX WA"Y$y!sPHiçH vk& Ͽ 2\ڐ$};T FG:p#a@!PپM6a%=Ќ dVHv! _#g\5^ +FgK6>ȔN֭yľ*.?d^8.IǑXnKiz!1YyMM.,TSxvCJ1)i2*ek0d9up"65Kj=䓥3#ё&>f!x*Ƕ3Rgކ!w{#к, RtW&3P5Cή+&Uk|y?s9X]PrЍr w| J ^*N %u|!EA (Y7ojGwC-Wϛs~MpK&7lCK?@8eM*jۃ!yU;oCʥY[mMX~ҫ/ߋ#Vg- 3Fc K _e|%o\nmX޾_J̋=9A osѬ E w9eW_L^\H-FB" @<:'׏~ɫ}csKO_=V-)sLP^UJaQNq"?~O%x6<蝌"PN6*)_%38IՁh*80 esG_n7hIܑ艘 9$fol]‚ q{¸2\4O]?};%ڡ?#Dr b^dip$s 7364`֕UgqWVqr"7힫}PafAōaJ~A\wvTM,B)b*(fBa ˻OȌ]Bصf $]¼ps@ɠuƞ2ܓ{TtpML\,٪S0oR>. f.DZ#.+vy|lZ>2S)OMӂ5W6_Eh$T!蚤[ hN)&U>clw+4E>1F4F%9IyEW)S<bl _ cw݄Y)N)13 H.,U~YNIm6#y[ŵ<ZΔP\bǒ{gֈ2f16dYfMhQϬA<şu>B)>c΅ze_){S&TBcT99_IsrSf<Ι:Asl<όQt 3 6{xZ1mo<_')gPVe* @X]*_Li๑(sFa GB0`F`ӏGOS9ܛ!K+M D4dZc\@Rs}ö >GUz⓻"_AMdj|}H˻3*3{6$%T 9à_g+U+ONfeXupVD:<}rd.ُOߦxB&։&8&[llGll'5ꚸū.E~^ %Rqv]U}뾂72]<*l/ö/<d~pWI_Yo??4[|J}vsw]s `|Gc WF~} >FQHxL#5#Ӓ,=#QȐ&/mC`?h>8S ޛfbtnR0`LHAcoNͳ< ۙ7/OS */T`sL̓X )+\*%mD.{FXZhcɞFr9[Z^ځ+Y8ZL+ʄPOx ;ڢW}-{>2Lw'Wqd/UU m)3s>g?g쳟C %&36o>-QYn?7@J`epp"AE9w}#=_ԏa"d6]>o]l h[ .qD2چ&ڇtj{{ p12 vo!Y2T -9S/90)(Yndx߰6`V9e@/nrs(h#T R=>,ed͌ɈH.tȣ87F0H#y.FN0a2Fgd#dVF~^Fy}AFe#!F2"#c`d#O0RH#b04#2f7led'#3"3ՌH{v=h ACrӴ|EɵbU"31ml3=jK[`:´}JXTgn7e>>hsi'ͧi/B;J4jJO9=cP:3A z^EƳi8OHWcOEs1<-X%BD?1J>]8頑3R]* y[DLzNsjK=!_"E-#Dl'hYh3AWm|efr#cҊYrB?+FZaE9UkE/ߕR"j"a#oHq>] 1~CF%|=b>@ -z#TIb+הS*:}kKYTI.OsVvfsM.LliNTSEAu4kPSL͸:#T2=] g)uW A̼<N1r'Y+?@i(go?1[vykC-)˱loK=7Wb{~vla'QSN[t'>MẟW2 £Jwj:ߧ&Ncڢ;K[琛紇&Wicz&r='Imt߹{>20t/fl~5îQ%ٓVh7,%?QbkĖu*+R4Im_aG%' уO'³ 9Y3&Y: + >uxVׇUi:oO..EfOVHYm|ʃd$+$ia{ 9k붞h\u%~iKȜ "-Ұc"f"&[#123%%"Jlʃ!~TmQQS@_t8p#ij8O GuJr􇱟=.{K-rpos|Zh/~⟉ đ)h\ ևaJrmş.<4+8L; p]-D\_WK_S2Db\\33-RiD)&rn+'z9CMHJL*ϑJEJBTy ER;TCMQ\W{,)'f9O/(ē ETnV˸]_aD9nL(+ )菘E[R2EjiQЬ]ܟ;g̜;pniHU`Y+d(H̼=ـ~w\j)Z넉oėGiGᵧq{CxbH/~kKϿJ{mOd~@OZ5 %wJL^%=RBJ&vQ! 7ЉJ2S~9ړc)rXi)sesㆁ9D{zZN<:`DθCꎫJX J&{,$LncXWB}*nCB3N2y3*K תڂum1^9_G3qE;v{_-$J| X0Pޛ1Ѷ fAW JyxR"0XQi$깗P ^p$9rh2ka\TƈIт\K-J4t<6F@_DѧWghf{t"7VPҽE>ZZ. m ixP b$| c\bjrDX%U }WOq-Ue"Gvz4=r"HEC|ktKnVhfAzet4ȆH8q`=mxWÒ佒 ʟ Y0id¶>5}ba{S,dqIJ~TQ^(o&8|kUb뱭@((Ϣ{h2(Eem<6^3wc&[RYQ0? f!1z;XnRՄvCV fKe|o z2g(߭%n^~@O.{]Q[m铣"XWJsmL1o8ɺYm5),X7?*~ 5Y'Bru 6#52("x? }Ӵ"PZ-7` ;ċ77A_C@ a`h|JD2#Wߩ][l2-;DFOu;YK;wYkm^)({9Z\eMoikkw$wUژ} zuˏ9^}v;N0pgගq۳G{=UwOE-s-ޞ-NT?6U{j&|q CMm /ɉ{j$9ŔJ6OSB`mt&e2UA?f[0oՈџ,d?:^V ~Jj5SBHTuqfҧ%6dAPČjQD'NUD2UJJ<0-IೕUUƲeE\uՀLUv9 j2eW&0 L5 r̘\e\2QYuic~FfJn9ےUX :Zwۅo&XF R)$(MRbY,fnw<5a1ED=% a>B|+h9'hFk!B&o_b|%niTjB#PLNv|ZA~2u僺aWUWe#u=RpySGm7މtCG?5wo:EpO5Uj?sISG׬P,_#`J7 xOSTtY-=7s4g)ބW]Ӫۀ=[S+24rnfca.eN[5Ll&`''CciA4sѿo O/ ? ͂BNa/YJVo|@^ Ea|P=G ]#xB ױ| ~XSnGU ~V_  ǂ"i!k^ 5jZXƻG<KA~.A?I ~RUC5Vp!]X90tYˬ%Yep}\_­P;ԃ*+ZֵȭprkԀ 9iRi=Hi=zNb+.%xn N~*,2<.U\,pخƒ|k `6 [@*TfÝQ3m{mZ?6hYV*am's8*;s=檱Cvao[f#fWkP~?`4&~_^S[XDžE<j8n-V1Ce$r( 8 lEVr[ujX֭y`k 5{C-uk 57^E|2`Zst?: z`džj 6#q;[u َpK{GX9=s`!k{_%%`gwsh# Xɇ{u b/ -ťt+Կږn&jzjlҞ7S{M!S>jg'F{x舦RWX8m})yPgO>8Omj;}w.Swv3ր)%ls-JqTz.5NJ#~*:Ǔׇ-aqjx%ΦB` eM5w]4sR6t%!CCЛ>G> :|Й>INv :< syT>K/1PKU[-#ڄ" AxisLmtsDlg.dcuX}lܭ'Ź89C9"E?.6r9Cٝ;o=v׎V4ZB) J[@-("5P*J9(@4,pݽ^Ρ=9̎BՈDҋZFsېeFT$-6FF7ھލ9K+ڎ+LΏ&Y*US3VS7p{/ef#$UnG6@A0o}$&kHč{, KG(UdS`PIB3'޹bj󐘢-b4qJ .Z`Lh*vF9_Q2xXa̛SQUXGC.+ 5PY ;_$ucٌ8k/~C)>bݟhg>#!|퓗H@hTbTMB|LP%wȄ~mdΛr>sYP]ZjX͊}KDP{I6L,J=jjiysA6VQ6qa(]bxB,0)\5 k HBZ ;op Ĭy*kf7™#:(j$d|̡`34a*P5حnW ;gL9R۳Z:6Fb>Մٌ"9y <T`EXBbyq삪yъ<ZbHZE.G\ŇL1UG=Pw7y!L)f~Ծ~g˔eY"\M U2yâۛp~*@#:at4O"<Y'/~o["8BAJ8wO_|^K#$. 6q{ N |[F'x*i^OE Q YNQG%$Q$)Sx yWl=[vRMj9ۋ*`'hFysi4Ϡ#,:ϡ|798l,<j>fyCWf9"P}C Yj dCZ]6 _5Z7x'jeZ qOBs@9&M'0GP $}|);} GNrg|7}ϝ|ϝ{]_jK0rv_0r ƒ~PKX-cb /60SynHighlighterNyquist.pasms6{vԻݹnǍf %B7ee %t(]Ccpiw|0֘ b+y5|j9tX 7}|߱#[7ޘ1=>'biT>n=;{aš;++`}0`ybK/ܲ4,6J.ppv#e9,I‹ϗesɢw7Ϗ$Yj^DhPZ.r)^N`={yo]?FNG\?Ã_>|]Y/o?Z]߾:(O>9D۴)6atM8V gJ){QS+3>NZ7'rٛYPDh@#GTD_ohLt9PWBht$[tVnVd^xy(υɋTɺsFϵlK>ڽ~r3i.y/EQ3j8i3xDR鿿D > q??^Tx&$~LY\(x-wb~\_z}eryego"')~}sZ M-t뫿e!V!M Zd. n?$_W~N5J^[FR{]m~#u}|fgX]9YX0U?y~lɚ:SODGUo>4xq&ѼAQ̻ԘH@Lz$rRy|Lҹ*'"ڭAy#gcax"N\k3F#x.gNB6хu|J76.9O?n(wZG6ȅ0ٝ ^Ly&kInhPIJnw,WyXץe5: dF2ŽMQW//8VTNpj XMw*ގ/N'iSW-th~fAQGS 6N]`d:.Bf[&!F e#e2}!`FiFpn#8m6sAp 8w;sAp"8w].sEp"8w{=sCp!8{=>sGp#8}>sy<@p 8y<@p"8C!yl2Be}nzaeǢFtꄻO-qUmLوX.benuyaW:ZW\뉢a%W,}11]gPrfU^^ O'_Nέ'Z]D .4Y~"3a:╤[]5N^Sw͔?A^]@ & D )aKm-OD//(YExH% L2̴a}Ŵ3+}i_1LifWL0Ӿbڇ>̴at3(@1Lf:PL0Ӂb:t`t3(P1Lf:TL0ӡb:!taCt3*CP1LfJZl&s%-[ɒV[ْt ^wKs[d`~5d`5d PK!10$b%DKLq i21$DcH [chj1DBD !"Z0D !bCDDb"<-!ha1=D k!!Z`C BbmCdB"{- h1DD /! ZA B b1dCA0 i- Xh1DD 7! ZA Bb90C@b9͡'h;1xDs&;M 4jbROM4w]9%oh$1Ds$G O56|ؚ`|[_@3 d2ml cنm [ AlC bknڽZU,szzȶl ֻ|ݬOD)L!US﷕4s}}>zs@ ԛEiS yo _xCZ(V ^ŋ9Mf"3UdFn5"Rd:S^??[~QD9R0o5p݀g-SN|W /ܔWzݦ'?9roω[>7B^9N%T=Z^B~E[usevN ?XXC Q> ›Xy] . `+8lkO<z:Ie( 0vj鷪Q\}ԛnٔ_ls`),@Ե9dPEbV|rj7;k{`O!];J@V삡CW8Y S>0G B>b1[.] ƢbA .j@ ?."3+W-x)EWsAIl45T3&r `e߱vOwkEfŮ\< F lZaD]cJkub?AE:_D^*3ξ8wLw!I=&PM^?]t\S2Xnd,6s⭥(|Uu":& c>_ }x z߁0t+Ν V\ko8Kjyѩ:*u6/ہ+@>Шn>g]z_H,7$3-e]q@e{`!|yRqcccI 03ʯ|bPuVc໔4qvS.W`&VFjˀFcL J *!Ͼwj*h: d%rVE#ɱxCc4d&>(W'YTz5"xp> 5,ּ]'ɕ*- E;[&;;aNU}BΜuęT sml\CxF5"qޫj\P(Q1xkkrC'JxݱFo?7 xlPhN!bǒ0oTV=AJǚk}i} D~2tp+rȫNkJ|h^7E =ʗRC8_` {ZcGG1LL(uGkuPjbFiSP._غlZ`7 EIpoz=#dζ7 iPho)krTyUތTLa sȨNwذj]N7TwIC;]=O"/sFRԓFb͏ [ȅ]'_  CG׌h3X2k5j=ľ5;3%;C>4-bN;V~ą&NzcK 55AWyHҢ.160&MDx^aͺةу"W4/\-4*|zT 364kLCEWxv YƑlVb9ĎSw\ؾ8sS9,-R+2!)?;o2Ai:M hFt?RxpzV^ `w56-IC>1\~6epzRDrEfIqwW*{ms|NJ}]*/}D@ѲGr3TF;b8NYe-t %˵D˲+.e3GTMQF".H&NJS5ONڙscGamOx޲.i"̷[-^O4FtofɺQ[ywuu н7%ߍ7s.*(>35 rع߇-gO?R;uά̳oyC>7M}ɲZ*l|נuљN{؀qt KɛVW>K&>zy{,0uް'Y1vFy^qF#]`LU\t[=9ѢڴC>]ib3!5:5&Key둯J^gpVd]p:'羚gg)Tڬ& ޿=u||sΩep H1Si"g42__SA*.z_Ʀ M鰌âϳ#_W]z_Tn߷ie|فa "^C8)+aE+CUfŕe*^ٛ~n^EufeZgMkDp v\Hzp~MmqO[K^)\£+*=fkH={-,gYٴvh)F",+v*$]n8]6T'$ k0Y"I'uSڦ!J{k& wBN7EEl9XC):L+ݴ.2G;+'VaaZ6[UwKykR֧+Mԛo'gUnC|- 6٣)FdǽβiB+ 40RW #oq3#Ly~M 6Zt&SH^O6!.G|h9v6Ciw; ĩRo/-zR8tNN͢JbkI/a-k:c N=vSt-ʡߢfx=^eh}Vгg/SDɱQ{5ը x/8{Â),gXHXq|a7z%m&U ^P[ Q j0՚0hj0uA 6J8Zq#Y1Th/&qjp'gA HƗD<f/a x)n_5%;>%zҐ'ACs0ě$1ٸ Gϛ?alnQSӴL{M":ći*kJdąݔ|3Z⭕jHU&gvZs ?Sɹe"m`q⢀Trye59N$'4Ov/}z \($[YqZI[ܨ Pz9uv4|fSPdviqGCm&<M6}pMz81?L#&I]0dh`9XH4vCNc¯(NByVhs7RPE5AD8ԿG&, v,-RD߀ѯ@VdgًY_◬zuz $g)m',(pKU)ΎIRvo-s6AbsGU8O "4R$d(Dr<$Y]syhSdz5YNvƂ eD`qqKVD3)@'zͣy=_ 8ty \9_S !QTR5Jy sXX,ThʨSgl,ŀ4ŬIVnqWiX[o 5Dw&m~j#ޘ7a2G4Y'ģd"3|K W4 l7C2PAyp8<# jFB)(4O$|0cޖŇapVs|={p"@{WN}S_{LMb&l&4dÆTO9ϞW{:'5B +kazbo:,wp %6YFuW֭ֈn>E#H} Mqb:I K겚.e;@iku<@"}Gq~#K[;J:I%R-f+ej* a'$Xk0w7?~$8t9]_4n3-AO$41,+ gb]Vn[_^}ui NKbUۚ9׊縃:+3z4o휯% &PV4_}7߿;Hq{{a-8:D&ĕ.qD6y Em R^xחg-^qp8΢`Ǣ$XB8Yul;`L 0%8r(*]]T8[Lk_ZVvو 2 <`}/Hv+QJA9*@"_R g0VJF2n ٛ]0I  b~g`YYgǵ@|y ( 1LRSyw lkZx{76; ]`2h'N3 {czCЏ0aĘ#fR@P<DDkx|v5 t?Q5ˍ<:6ǔ_[F0_ll#Ƞ|US0WQ?&˲@i̖v=+we;x1rVȫ,Hײxfp"|b|9,ARflR쓃?!hx]1sQxGfylSl+~"-|h:‘exA[B,7s RF%i1d)N9Â:NpS~29 G~-GUf9x j?n}+~R_\[V'm9QL?chD&Ew͘'a Vԓ$FmR)߄uJZ\!e^) /$P~/ķ\C8%怲VOՎ&6IT2f!a|b?1"OPfEe_b;X#RRȡfG>[[J4g:[FG1hql!RV(1ь zEw|-HIX~ RUu3M]7Wz6*AS`g1Ʀܲ_#*m}hDZETa)KƔ7lyZߗ5֠o*Ne]pzieƤ@uE%E9v+Lg<&"&ěQ%uLɁgta73;x`3߀:a>ܱO|ԧ)G}czCg-y\ ([B֡nC vT[zA9VUwQb&[/mxjڪcioħeW+R։W+'['NJwCN:j=EݮUf)uMz}VOhKkݧt[60 fys9E٢ *)?jc %{ 4LP [:Zc#=.|Q)0j[Aqwxټk]Ik'jF9΄yOtNr7AɗXLˍ6s-,cev3:@]AGMon rKfN҄VR.:=WU?E,l\ZT⹽oScُ?PKU[-Q ZSynHighlighterNyquist.dcu[ t[ŕ~eYI,c%c[ I iHO,$qI-%[ZRHMkJPB7 %Ҹ.) {i~,g'޹|ܙFgIAXX%l kF=8Sc7gcLh0c[¨ڻ±Lk,|x" g)@agEhȦ3ɑ+80Y(fidRٌC矈ZBoՑeZ׉d6Y{EOV)Fx; },3p{J w Wѱ+ѷyV_pd4.TH\5+ c ]/+)3X 4wiKcф=./KovC֮9ڔ%5s KW";R{`;Pkww$n;`2豴u |YsB^8 ]9_w2%FSP_ʝpX])m# M}fcBD@k@`h{ƾ/.N}]CO`C}C:^Cu?(cs/hz{k_ާ$ͬCbpG\,wCa]n i51[_XLdj]}PX. tOM;ɱ=:eXኳKP?kDUt{2YaJipX"ʹx0YGrd4>~y',RQ1 ;3p͗X$ fbD `؟:a˂@0e.mFrH:͋ 7b.EfԘ/ ܃MbX沷xkOHElT+\,w?ޔI녱h^ߜ2@/H=D:Lw8·*ḧ#tjxᡛ"TL=pג^X"CVO"e鈦-d\ &C/Fj1j 7!<&(#9o6Xz4 *=]zp\L ~q764(%1>h#J5:xϣ@*+~z"7QTmVoLqE{%)|Tb"굽0*`طAOQ0K{HLKcNDuk麑6ro(- uS?Rݱؖ@8`팱\ۣZ  S]4tvwz֖޷{h1<|ڈ& OӳFF1XېІP(Bī>t3t-h!ߐ؅?6#m6<1K mM}P*Im?;#? QJ(Gj ҘX~Aͺp> dV4׃0KesMf1&K63LX"Yͪp6X*4j4`J&]63<L&ɪǾhbIJiM,L IrԈmJ 'FfX da1vg|TzSb{O@Jo%F7RYěIZg-3?}덫x Ca|ú<|:لԄ¸:W^(ֱ]٬ ̯ʕ'(黯'8W&_G -" b۰BZe(x#=YtzӘT$t ,ll#muցڤ BۂF 7(h0j2 tNcIoX Ҏ}e32HQB:5rN~t񃼤A/lVf#=t\(;!j AKer z "z &}CTU}6/=v @*. h!ďj.uN?@Am|TnQA/qd;;\z &AZ|Iy F)>ۅF"ᴓ(d'r-Gĸ"7MCyH<_Z^2½]-$ld.;Qr$=.'I#h>װ\$?Y.7rCy.%m!{m%ce#A "t[".\|.BTu{^9XgukKX縋c#_;8u$sϱEƹWMO5C&7jL\/syNZ\䵑/NAOrn; 3>ɿpCOK *AV;Vf%JwYG ϿN¿Y Pnj(U(/oDBpu5m:? EV pL0╒ JryIoxOL͗4Nu%Y3צy1k U8,6d1D=szvSsTYg}+ bb"eһXG_IЪ%eF1w"Nk+]Z#LbʠQ,%DR=@OeRƳbpJ0Kd4SʢK'1H/r.3)[躿:6vtuǃшA0wFP1f+yĜS JO"F*+$/acBafeQ)_;g|JY]`693Kw'g"J8HƓ(,-.MR辳}al{2D~OW:w a2TK=x72JƉl(`iR`Q^{#@QBڲ0WL3 }Dg{gG+C*Kg>Ԉmfs$ӤNzdi29OKH9d*xd--я6Oɗ.3ɔ&";ȏAU/fQ \ϨWS14z\--(?jsXQ %GAx|,2MEvF_AB( {/ ulRFAy]OK%?Z3PX,)(VËk jduJ=O:EM+>m$Z4z9\բдaSKP6!47E%OZԑ@6EXq 崑.0a-L[Er/t1 ÐX$8g=Ӳ0Rt=p8aȩ=3TZt)ǜe698^3X'eQK!\,L *׋\iZ1YEh d0u7L Sr*LbM:d0ukL~N3%LM3-L]`G('!6d2x LmL7dd3';~&LރLg G 2xO1x2x3xkL˘ W1xL6&ow+Wd2d5'&>&~&Lާ /0x3xO2x0xd7Vdd]dmf2Z 0x}LML w$'{ 1xf2>d=d=d=d=d}{:'{w{[kb2 ^&owMeEj☬sVVz ?,+@yPVYYңLUYSYҭͲ !+)5HQYex^9.+IsFVs)T͓m@ͲQ[exHm6 eHGd6Yy@VE tpXV cטiYe¹ +i]]NUHVc\;z++ذe&+ e ^`)+)8%3S8hN[Wez;UgWt՘;̓\;CX&a4fM( o ի1+:”\>BgU(jY_|NΛ?NP ~9mf_bRVr u`Ihjs:*KDcVI? ,7$( HG".3, ȩrĸMk/9YӚ'#+VѤaPCA՚}Ҷ_kO wB+; LӚ9&O6<3拉FkeS S9e֚ksו?ҕ?[ J#-]l}lcC"+ՑX(ԑ\0RYvwYX$>G VT! ]iDW(q*8TQhK%GE Wqw}ͼZ5|;}}}ycs܅Kmuf?7>zw|fBUWkiu^_|PxP6@]ǭ7k>~;k|fٺ5/ߨ{iwM+>źo3Yx]Q3Y'k5r VwBp=@O ć ' m@\ O#>E,3#>G" /#D*+!"⛄o#~]wG|C3!#cuMM7#n q+-7ކx+Dp]{!܇~‡ l >L88IEl>x7'|)g!|9_ |%W_!| w$|"C>{"!'[f 7!n%fo%vwBp=@O ć ' m@\ O#>E,3#>G" /#D*+!"⛄o#~}?DL88IEl>xӈO> ᫈x]w?DC" {ZZ X>-@_VqϮÈqU@ډ?+|H0s?9ɟ믾2ic ,_\񯀭xËUެ)? ;~}+7 Al/uV`ZSeyĔ[wi(mvtS%J%=]z(K%Z[&JTspZE@kFv-y[xv <3z4 |C|ϨT+O+Ҙn V*ϰ4AaW%zVȓn/*d(##<"; lUs ~wB2@=I۫+ [?)ښ,S>g Hm7 Bqk{ tQru{u`%06Hggu^O(;tW+|H‡mXBr=9pl_78Iۢs- Ce=Rk.4Y$mG@XG%Jmoɐh%W&$Z[ک%ufa3;\-\gu>;&K^økD۫?Kw$Z{iFUc瞒-z646F #2Y`h TZ$Z"i/ݗhm /VfP=0Bv3m|,ݍ^P锢MXd ϻ摴ؿ&k(Q0}9v};ƱOj m=^NsiA2,oh T&Ty-L)3otyxڦoWX5.y\[as9YT eix:Eurq^층M߹T&?kg9.F}QAoϾO!<4dXۀ Vvf) l>Kd iu6Ǔ/I~m>erxXF9VqxތWUhe[ a,e?6(YLv:=xA4s-^b??O~,cݩwd`^6job >6xy/O|b%0,|ӭoMb ĴA^L E`q&z5jzfQקoE}y"ʊ#iZ?,anzA{fٮ6EA3k}ENh n(dPƍ~7lqSzY;.E7vL023+pC 54,u`G?ma٥~cclN=:|-0\.fyا 3/[ڄ*@gKk;*ᩌcڂ0e++,!%`ri,C¯.]w88 2 m8v Ӗ k>륝t=? M#[ž՞vn>"KCf6w4`{\v_V(d<Y" gbgbgb+؊31 W|4![ǵTb\>f(3d1qlM:ݷ_a9~Tayw(A_*)MGS 4k@*wJeV+8wKo%{&9I潊|[^'@R:Yq}&Y|&+m*;lKsy}\Z(`ՆӜӶ+|\ox|lFs믬H= x_(8ƃv_G)Wka&bE3/6 PdzGo%t%#oے>:NSnݑ˛{y(o8'ŝhG*|SƆ=sԥS=`^t`emh zzZ)yѳ9;8c oH[,P}(m $O*+#?T6FqDٓcРR{`>6blel*.Kv'Gx?z1WlYΰ^սU8}@mxK I2͏]xlQ5wrɶʴo:wt1? CQ؇x>P|)v3sW XƴXк0Jx30.pAEym[ڮXK,ŋXb,퓡lxYB9iXX*J.}y0|G9*{*VE+5ơ16a)p9A%8-bB~\[AkWϸ}d0Sa2_e`̂-+s)oi_?Q|ksEβUS" L̋)>zz-o+G[xj[̭yW?,z=PO6b7~јjƪ_eU!zz)lVG1\4Px,9|v$`8gVlTGZ"J|jLvUԵ]U'',UGykyg4Vq%3Umh\S[b#)V+˺Y;wc~UʻUƈ?ĔkA[8 pyi .֐UJn+?ij\3c|WHqO??h9yyJe:nu~j5v?ƺu[[WYشiX;XeAg6=`aY}Z_ŷ>=sӽsT ~YEج"VS]E'SG 1]r@$Q:%ʳ5Jĭ f֟,?NljFVgƿ^_)#YŲ jƒFw]*wFiwVMOy%o8sǁT/+H,QN`gb̻EQ._+]\.Qhi{UG{̽abw}a;"(s|;< 2K"ٟZBw8h7?3]Rg~ ߛ$_k.Nrߙּa.Weo&?))~ MS'_LvLM/{ŕ=}'9LȦ@PL18s#-3{Ki̅HF"=$stDuqHkTQDsm!*N I?,kPlg>yv͏yyq{/sK\Yz}IO{S؂=C{~Y) E~;]l$cg?ᲕccKDJb#DhelΏ062;<ᩣOzkP׍'5@:~WUdğK5 >!1Q`15:_ֿ.-#PdջƨoO Uoy?5ZPpa$XeʜaYo:z-[;垜_ ?<)ut!=.緦RuLφգA})pkzr1z=XqrP>zra`L{dAI4=mDt+Ǭy1i`?&[Zgɣ9<)5&+ hA;[o^ܳ0gfŞi9AW¥3cO _WO")%BY2\#MDi/{W#<$ 9QTf2rsBL2y8qIjQrj.Gz! ÉǡXᣗ *5ycIC* X%rCD2==%bN%϶#΂G2+SrsqfOF<1vDO#9#iA n4U:cd07O 'TDR&HB%'2dQRzVz 3$l+D'<-/M'"}wO)3-R?K!G]yOw/\-;If;&w k-r%8m'5"PAΔ rIϨ&ȑLH:ƘʔĴ䍡'y*[x I] =,"H >1o:"X.B 3ScnOi鮏4Gn)&I癔xUhv^D &qΌla7C$Ͼ#*C2S3ɰ=FX δ0rmSSƐ8d*t9MtDr^f;Kz{j9MS%oQjY ղN-w^AoGl&'f]ar#蘆3e)ds;9a%])+Ln9I̸xYOnrQb=9Y~MDj'Bn b_gl@GN6!qB:b<(d:X5m"ϚLkIN&5L䙊@:t;^vIeJ~CIl[F%8SY۔MP$&vZ*";W %@Ix秷)=vay/9Y2']u@[u Ϡd6U<^R9tTL,5mAYrB^Np!;αQOI/义nT}Nm*O"5HȤ<)3>b!O| ?yaGpxÎNo8%wKcRAB?c_{>~V$;tJdHjQ‹[=qgA9lד76)Ac:Y9H%%ݤEw_{g_9WO7q(b@: OD2;%")1< t QL]5x!d)|Ǐb_}PfVk_ȗ'(hڀQ GZ-b~yO2?ͼYy Ǜ?8 8-< 0-鿻=*WB\WY6"5>[S#]kK~TG[/c89r"$Qob2[몾Cč4F)ҌEث4[f"F2s 2-,2^7,ei,#l/ZFelYFd/[Vf-ʶ i7AٖQaQ X˘j-(P@02u p6`eZ,˘=Wda}̇Xf1?5SFp\esU"ίY@MLشs>Qn2hQ$ %`ܖ^hE@1P TU@5P D N]@ Wk-@ @0X f ǀN4p\!s(*5@ hZv(pz0\n (RZ m@pz~`\nb(r`5 4a 0p0,l?0e@%vM@+N@/0\m E@1P TU@5P D N]@ WB S2Ws(N&MfYc'%ZGvl}퓰Or;?oݨf^ؽ\ ({k^' u]gMFqmW-Z7yhǚuZk F(F,R-eWZk7DV6>f?Z-k'hAe/m۸^F5?'Pw|Pt|Ho?kykЮ[-vf@k ɬvo<&Yr61JFլi(B[q)6,1E78>ớ5?Pw|\aR)q >XKE'|:YAquYӼQv e^fmb|C 0kn6>_Ybmb<"tb|61%hSxDMk7JhX5Moam|>+vwkE&hE',yhG];kyqGYKIdMs]8!]tn|P5'ȡbj>%3묥S6|nv| n#Z/"QϚA 9,@škZj>+nkcܰI3E?Q7y~Ñ=Űs;aQ5?#Vn5k}>kͰ7}vC͚hX3{PwbSCc;١W4Ӭ8s qa_=M7ٖ KyȂk9\y(VšD2XV|JԠv M5vBkeףZ;Q?mNB;IֺuZ/^gۗ`_R:1{밯}m ez<`gj>(tRإ[*UlWîfv-QQ[EE6 'ا v=g{ whWݵPP U"˞ed@BȞor`:4-@;tڳn8 e`Ȟ!O";W̳%(";,_r{YiJ~^TKw*{977_mwSls~!$ۤBsAhnyb,ݚ}+sLylsQYnfYv'zo4?|og5jOrFT`fv`[v IN <*1BbaWcȊnM@5MW=Yj8&}*q ^jgc7@jl"ciLΰ?) 2gEqF(433"#WT ۨ j#h4#1CT(&ZV LцcΌl& sEWF\|F-V7ڧTn4skVgXi|`,hw Z1~Ԝ9 ;"30 b0ͯͩ6|l3h>GQpfR=+KeU XyU^N, ~k@{K#oͧoG]6|ϳ9WuwiOr%^OYl}Ύ˺sw)7v~+ C@ٷS4ihǂ,[keەE I4z|g ~}wqjjk xzJ]>^Oe*bv:X|Ꮊ%Y}߳K<{z=ix&VwnWRo=)|`[:sNn^s^>O4eo'գqG䱮FwY6# մF#0tqUj^#15D5wNs9{f ok{s|}#5e7> ky~Z<=?y{[e+ ^ZnQfs=v+betWe*}-P? ^Kef{Ot -A/[GaKo;eL9sU]%f~Y<ƞe7+sʋ?O㦹{kIvgʭ0o-~Ğ ^O@{qb^O2o^cz-2&,V ezZܳ?*]q]?eeZueY4S{~Χ˸@Ʋ@/,Ftn{_v)[\|}N9z]cO(~l?Cl/7j.1 HCקޢP_C}Q_ sߡr{Ԝ ɿ@hdlEM9EfI)`F2#XbF̌by*3 ("n2͌2b:3Ge1fTQCgF.f4xMZ2xM%-^y-^&m>Af>.pi5:Fǻ<]$=y=!s<fỳ,1 `fƀɌa~C>%sG^f)1?Cgq/L`~c~EO%1̔s߲8~23>11!2'|0gƌo9'󣸡x?qs8s~Əa~ 7O|~7ϐ< A܀^D^L`>g_LEA\|ˀ)\7EqF,Jbױ8K2Q0uB,p=Q%Ē!L2bO4`~9b;XHDLUSOcM25Q .#S5 Y4"A!" {XtDLS4DsXDLK4E Q -ч?L#b X>dGDWah鋞H !s("XD@6#db 0#dFb(0GL4S2cq$b0_#.LXda,̱=f*E`3p0_DeGT_as&NEb s.D+Xp\sQynIKq!`n7u̕W6YWb5?`\mG6x$[0Gɘ#0c=2>iױ=o`Gd/0G ʀ<&yB&$rX9 soas22,̀ɾSْr;XpZܒ)!aeD`mY'?&& Xm7$80#w$d\XXdLR&%H*ޞ5qzaRi!(TJڕi{uR$ ڕ-RY(?TFvIdV֠PYyH*tP99"Uy9 ATQ 3*aƗPPEyF,Ksd%yI"2*چHԾܓ (Ԟ :]/ä{P;P2B&T&FGPILjʆA2K%rj6n],ȶ@am>T#kzYTW6IeOP=!u( U>*m"ԡʁ@rLj$rU)#N*PX9ԑ 5ciM5WA@M5r u,fr*P5 :}CSy"KP %u&OTTIniBdԅ<=6Թ̐rՁyRsSS.ԥ,syՃ=R J dW *u<-WmR!GHP#(S HO塎|T@Uj WǤ*jP:!RAՁ: *B2*ʤ6UXfPaGjKmKMU#Q[*NTԶ"TDuIEն::V}R1U[4TT HJB]BԈT\39ԎJ3T\J A-~J(JSRiRP:+j+aBgԮjy~A9U5Q~2iʪw`ʪʩ&T* **P!$UTՃ CTTIjʪΠJjTEU./(FjOUTj2Pj_ cWyRUubPDjR4VCcšjjcjj$TKUIuT[RPmU'UKjk U꫞@ԡ+OT_mCTsP*Kc @p*HGPpTjH%P#'5VGU:R)R5V]2Xj1 DaBNy"O5ѵ}(S65lQuRN<6tpD[;8^:8L:xfOcKʕ ndchRV('+!Ô+[F(C1_eΗr0MYeR}y Ǿeʅ=)ëUkV6)m;{=ՁCꑃcN)'R;xA>w2ssu~!M(Ϯo;q0Nt0E`p#`~`F=ٍ`rrMw':8Gٟ?q> e晃;7/Sn.r頏3`rz3&Vm୘;[ RoeUpHٸUvB9ɭuJ-펃]yo=vpBٺ=upF9} /)/n_9 ihRF~/(ҁ+a|`˦"@Ԧc@ܦo$(:i;fy^/P%ke smbW*_(bk ܤ]kjboҧ (>|5Q]ckxɬP>wz9=;s2t+z?;A;Km|o_ )wvmP}r'gC;ED[m{<(jOdN2x2ޢo6eykwQ][?a@ug}d.?<^Q|ʳ3s{f6y<9M QD"R$azk2P|sr0F?w(;')[4XPYŗ]9ʣ`n+R= mP}ܧx'gFqw]uFբlt]}燔C{F?%&{SS{r/(+T7(/r)7< ; Yulq)6JR-Ӕ/Y}ݜ=FRDrU}>:ƛ񱶎!ׇx<;~O(}ߞR{bO֧|NᏈ+oZ{?¤S P0mccb2u?AX)/Rg)/P/SPk  G7)oS"t(w)Zf/Q!bFYVE>j+˝$[ v%{$JmJQxW,͔7V.E+F2l-9<[غ(aEʱG)>)8V%R@)gh&Dՙ|X5u`]`b5:8#kquq֩3x D W,FhkVHcvu\֖8BG51ט&99 N^2,k, GVIcXvaiXU5` }&>F[cP=}`881#cCk8щS)Z5^/0\ m-iW0Լ(oXI)`՘fܸr<]\0XEpu u `]=`}5LdxM43'|3s81s!825>ָ DkD6pӸ$0_w881a",k+cUXqtSc ⏬.5yqacgT <`πg8ՅK%Z4.pQ\6qz>481#cxq bSk^sW+K=|i[mQ`T>v4Ɓq Ԙ#kWcAߜ<0,j,Kq+5+fVd/^{q/t[ }(!x jx_vgd]'ϊYUE}r/P|*k>k WUcT#|EyS.gSl_&x?atjz+.em5c AkbwF[5k;5X#v((kL#v*([aAi\}f R_/l_ ں\y߶ oXSa?JТ/]whik%;c+dEu:͠,[)͠,Y-޵s8sieZ{hꡰAYgƠmM7QZ(lqP]J#PKX-߳ &SynHighlighterNyquist.msgZms8Z> Ɓ]K-E᪖;ƶ[$aWuFjZV~kLjjKN*~Mf#9SgMjx%Ĕ$Ed RYFԱ rOe|=7&gӉKFׅKlSҩwnqgݟۣp#G@~w^<<~xҬՉ[i̦ϿJ[(}f<:Y|荆G+v<:'+8YhS,Η:Mfx\h/rq) [+i.5V ^2&3HѴ#M;)ƣPG Luz<xdʌD 2t< v. l <)MnN$Yd`CYb5:3&7vi>H=0-&oXLZFsU %{Cʈls Ε-fڡԜݜ+B =cij5MWD1GD'02it$a)ݜDbN/(S錫y &e }O2CVi]r7s$-}O". p&-fF 2)%Yhcx R]*Wrsd}mb(5:jlЕ(A8ԋ nn&(p CG8mR6 ) :qWCsNApyJ.=m=? >#?xO%Yf 5S7puB1 F.'ZqzA=y `Ix$;ԐQDŽ"΂Tt zкy;YZAdcC@1Q:tTBMwm?iz~ը3Y>vCz,<˄_*97EˌP $VF,<*()$o5řPhD 2G@X?Qɫ4ST 3װVi)\J*L,``݃.L` vj 0ޜ%\a]]TF,Pŕt8R"RʔCXax9s57wFԠRYETFvdcdLDp>?[I ;bȄAh׋2p$a,9F3qrjUoҶCkEBڡKZE;! ^ҔVJNE 7RsLE:JiN8@d6O[G$:kV"X7!t|^# &E\UDВеsyV^ (WPie VILw71T:ܭcY)CRŭ1@KA,;L)GQKhaZ#lLShJy'=ҳP,94~iS11=C)Kʗ dsƠK}5׬0A~>ȸюQ="x9<)(eN!jn)ha7{^:~L< B!I_ys΂3CK% {R( _jd&>:WYn-,u,{QHU_$p*ւ2#PȜ^*_% 6R0uF),DqGYt AIE!Gy#3=oP wDԫ*@A"Y%O L_Bi?"sة05ȏz&鑆[ʖi3VC ,RO]XXMv&P$4hzqo)zI7=jzPLa&}Lmm 4ydOReCZ!v?6{3pKVlm At2UlZN ~7w$ޢflHd\X\Cj*u] ޽opˊdೳ.en_HZ''> m(]Kłzk~P50!xbtb`]n~$gx俶~m骏s/(_&y^Hpc[MOԑG"#₽qEo5nbun5 @ǧqWK /;0tcחfKD6mYyKs/\wšcF%&.)u~p#++t-j{o`}{k)Oyy@6Oύ+mto!_l |n|5#d_R=.~elҡMvS3oa\\+] a24 j\\[M,-x=wiB'{-qzZ]8&6a\˛{T"0o5CO2o5Xu~t?Ӽ\;J+zq_D۾z0_B _PK<}Y-wMf0.bmpsv@ P @6a؟ǃC0V9?d/PKt-G0Tips.htmXmoF.@aN;ب,YJ+ٸ7F)0aE.ŭ\Ҫo@3CR63ϼl|۷\_h:{u>^,/暾hUL4Tv:}~t6,xjhMc))].tˈ\±:ܕGmG4oS>5%Ajj6KZ'::s&XؼT2HWo}XbM'VF1iOGՈrm9*Et}ݚ鮭M kZ[ͺ<PhT]sM(Tҵ)5ݙ2u1A׳76WZLWgB )yu8h-iqIaBWUJS+n0+9vO}-.ö^z3XseMU+.#SVu\SQh*eᄾ/Fu|Np1R0>_:k_j?xA uV^Ě1A[DQ5?WhQӭjU 8*JT tIl)`:BE( L{sA&+@>X1P w_LʔcXN%sA\*$vYIr~mN:0..i?"_޳ ]4j"SܾNN"h /j7j+aݭDET2p}8" 6I25F@>շ͢}ƃ>J2kR L6@lg&w̻c^:a #3VLOw@foKMwuq-/vl49^Z#$/ل7Ws\i}p$r2Ox:J [PULc&r+V(sN011^ML ڣ6= 8AvBb^ȑEDǺjyogſj T_ADВ276emڭ;TBxU>cRs63'Bn2S7l׬~r5KGo?zWppbtδ7??Z弫8k8@nE.ڼ́/߹ EUSꉎ} '&}PeYr(<$@Q[XKl-u5vZRӮt.aE4!-L: q?(n>|<୫m^K9&lZmi7Saor Dד%x y\lgjuYe :n˸u zpS%37nM;pm45ʺ5zƭDf ?*mWX1ddxÞu E$\~<~Ba 8ЏI,]e '64;IJAs Ȫ0焸σ>@"Q<l-p(S1f쉚P/eܤHsf͛ۍ nDVTH7p:b+ld_.w`FwdĔMr~F޿2L.Kwi'> ; &5Q%qk#vƛTzvM9rPy˗V4ܽ 2jOxneD1_X#X;h-7[%W\%~I$E=i}rJz&93g2ϐa⹘ b.C-PK)t-}uyWOXNyqIDE_Plot.GIFXWEnX@:IAni\Fi)O3ս͜YyE9A!˷#Fg|񿳿?g B6ߤ @0_B@ /7 AFȆ!d@0,CC!!l8/ol9 e@0o_AAo0e@ X61-! x6 _a17o뿽l; ɆAE7ˆ`/B8 X?6(m_R{)/kl?!;euK/l8,'@OAo Buo'p@5oE!3ߍ/cz.2`+$k'4?)OQ,W /ק{@~zwO 1Tt:ڷ`N} `X5@7fzK̴@2(Z(J>3Kj>LdL,/ylE5y"5[)fѩYO\Ekvoc:,\$W`c>sU'躽oT 5N,fϷ=OTSNotBaxRϓ|SnZAȐKKQ(Fš ~[ˀACs4l&%$d MrMHKQ5ȯPڤ+ dgS `>ؤj ٤`Tn_˴KY~qqdv$wZ`]"S:)(=I 23{+)^IY&"Ö{R e4-NkK&Ė*5j$:F@dMWS F6ΦlSJk5 NmkrS 6{4Ozםud~^ԩ|rkQjxZ XLlj@=䯸o\1 v%ãzۓ%R0'RhR?+vĆji1q6Rlm)Hp'έ`@=$ JZg;12iDl@ <[cB]Z$^` #z..2:7US% ZQ^$@Ej} vCFD"o׻1ꥍÅ~er2){Eʬo0'dcfl-p&2浂Z=}F>`&R.1>̜Xg1Vs*0Kֵrȶ",sg'eC?*@DA=C`:E(_'Y1U1ZX>uCl4To>b8 LgSkV:kjCUI&NX1J!KRN5꿢& EܥO pJ2uS5AQ W&,yECVrv"Xe.-p-j 1WGd9D!% ^Jܣ#G["ҡZ6s&sabW~c{S !w^ͼ`ryCeƠm),FCEEs4Zk:Nz✈ZSѓjqtZ[F}`-mF.9[;A}B:lj.>[W̜~dG,|/"c(pqܘgZk$%iySdW?Z?f4t'UlШS3xRR߷6QQ-U%ɒgy6c瞑H"9U"b,3 9cKα{K~ ')޼J.ftó[lXL?ٍ%D J }k>I 9Y.8侷2j{O1CUvDEnwE[S76gcSX$f9Loq4Qڨ' {KuoC{P D%^-La 3>I9˜R;Q rc|tCeb/t8(s:B,UbJljWy0bSKwqvq`Ŕj*a Nf4JcOq,fUOVbTdT8cy9J{(y W:~>U.1B>J:U:UiXF%]U~~U JPe̪,̊4%Eqah$fE5d#9xu0oykNL.rߕ uC\.7dƣe @5c1%j^F W 7F wA%9AqE䡵]M?B(&R~.'sh>9RɡL[@Y{/ fMprt$"oޙP 7 .܌9z˟RnBql!mah5|> "V-.+ejOC4SvaQ.Q(-cǧ}E̟I}zENg!S%7nHXDԚ*zfG`n Kpn๮2cre'pIZSnS橮c'r&RIV.iWqWen+VOs(W]Mo&C簑1,5AA.^N!!`ܠPd}`_vd3(2lba$#`1Vs1188 Y<s.~wl=}|{804j ky3苊E5%lĒ)ȖvIÛn p,/xҊM FB lTO;;gWl;KF>840..4/ Ϯ6aTtZmt)Y k368@ hvj,2Ǒ9N֦$M/;R[LG䧙6,ZOg|X ꂳ<Г=F1gyc~[$Wo+L+T+SOEXN-U_m}N" RvȣB!\{PMGkxt[\Ls ~FFi]~jx71 ;0<0&~cn#s}e6`w%a1ᆟF&Цt7 UWqD;ق9G)`H֕ Cd=rHB? G>">L}'<*8uM~x.HIFOzJs־irl&gLkr)g ks[f;}Ѝ ^ŷf3us> %ͬ^D# Z[ORkJʢ=yFA2k~ya9/L`)gU|Kb`[}9Kg#m{/nL!h%03~>S{y_#D~9uiqe~I>խ9N@:oƣ:ql~5fimi3e[g.L\<}OOMEz~86Q M74.Gn/؎׺|mA/s{QܬĵD$SA|e Ҽ#%ƑT&!le尋kwnzVZ=P-<ܩc!J]:|Ҟ`hjc_30R)ʻ~$@Ёu(&BF;Fֽ EKޫR7pϺK|cyCZf_a_dŽSȅ:uDb0L}q&1Ӊq?i}2JdR3 ױmO'=kwfspmi=r<(#zׯwyEUh+5…jtXUs(:q5$(VspQ 3>?o B>h n"HT$Ζ7/b rp.,qbT'Nՙ6fjUr$UVCdvMn5Ag[$4:Vt`!l.v E)fc/,+}w)o& ?6pJЛr#N(XOQ[t[.m_3j϶?ec?겝Ғ|atDJn4eMDbŎ҄G̅Rh^9G> l"޹nU˟ Pmpg.mdP]rrq~z Luɲ2c$pC!Aw+Ep蝺zj:V TE5~@XI%^zҪ4{mw_E gw.<#'X"8SwE@8fMCW(P2߱}E}6G.o~52cDpcjOWJZw;w7Q^~]߇HqʾtygMĨ1w^(1j"<ϝy#`\˗4O?P_~g(8 81q!wEo/Rpz`2-%~G`:4x\Y.-r61?}/Sq"j!mRTḃz(#^tFEBjS~S=$`?_V0 Z҇?J;x| 86Ӂ/}Cz?ʗ;\:Jw҃\.OBH*K#vk@CݕyPB$8eP<+ЮIuLWJ ٢~6,z4fSLԉN,x>:'-L9.RM,c &0v _KLxy&%ŭR^wM)ُt 3b`IbiDoh&kFţ )QjZotש!&8qPV.Og#qa؃wFI0^܂6 Ī6bèmwd6 AxʼnTujB|];`rU9F(2^J kx5N5m^UBjߥ][m)0z\V$q Cb&&=i Qw,P<0lvIK;q- 9ܴ1P 55&b%bb\t,Tt &i!z?߾،(CXn b3j ^kŬ?p䠰4L!sX3I~Ѻ%zl;W:Z0\nf+L |ۍi3)/mS!M (:)b^d͓Q28 ޢ/"#Lo I/S{ {x륢:Yvu4 J0 5Jkq;,x^M.p>T5_i1N"/8*rUIٺe3|wB@4!˓uҿ}\"E3+7,k&ck}7N$`%Q[Qѡ|#*ۗzb2Ԃ#[eX[AuS? /SGu'$69g$FzWh u!uM{0# eCnWdzynPM=g¨EVd<^{F0f+FW]|d9u`'OӔLpB1#S3~0b}{/K9A:Oav_[JfNd(s7CZUF Buq.RIGQ8 F ^ PJDK{۔9jYrOf//4 Y {1TUfIL`]H%x70w~8fTNF8<ǾO:/8_W]z5!NcjV+G(3D;BQ#2:3-E䗯g[̠֕Fy`.v| +Ϙ = ^h ^9yˏ}~YS?x7c 1DtlcQ(Q_Z>V.)ŴLc&qiJFR\M*9$VL|~8YxeGKf9^t}]@:Ԕ`dD Y!0=%AaA`2_iD#z}YTx.zuZ^t.Hj0iX>.0Jjg^BZ-e<㴀cb *oswI~~6ڨEL2>^nGo\['U_MѢRIY%M'9t2ϝb>W!O$|AY&+_6PeoS^{R.CK5~ӭ6ުF\T Ֆ&2 {8| Wk'^,ybp DSOs ?].S1^;%|:e{&] |`3. ZD>!_XkF KԾkF|(#L(/o?ōm43p-G@Z,$/7fDBamMQjzpAd_J'r+FT =;OkQ|t'?y"hqr/[{ˌdO2(DhVqxS(~WJ<;_<:r--.C^=/ CXub on1sd>,F<U]]R@ך^<1V. $yJIeHP)8n&UʵApʞ.Cp&RIu1o ؘٲQp 4פ>gt9\Z8[f}r;h/Z#̦ |p?YrxoҎġv;ɫeëZG:j9WSP dDoޤ~J\OtFڰ`5.~Sz0/X?< 5Tץܘ2mg3vMUW:M/"M.,WEmA;OV=ޛ((hYP>Ф:U2J*lj"XNFt(W*-0khQgiUl3n3u K?6BtLdO6$ ']:y[DYS܏1ϧ4({s-k5kSQxC^j MC㺲X8;UIv-z_VDSC]ۯW$illGg C;SFjuw _[~)>sPb;>L-0do"SkaH -wπuL`-JjU`l.AĤz}r5LF_ =M8RsS;nxbn^ׄBlGyQ~ {ֹ]BȠ[&V@ADυ"iHD༅,i{Bc֑gY̡aI2po˛hPk$bD1JjώX5.G3n. ´sR)I6͉'DvTx]ֱ2޸n'1{ =DkF=وrdRNu뵡%V(qKCv9zV YX/q 2r+T aՔBs5P"{BH]ZR3]m1l$J,EXd_1q EsBӛRIjA`t\bo"c(PH'eEC*}W<wJό1<g6wFzaA ]Su¢2d7MvsTc4 L0R!WoZgxh%;Sh#u2Rzv ) (@e0k!?CrFvbV|6b%sgr(I)҉%.Rh=)h>zXVp+)3YM:'".a#ۉ<ˣ6h5ӗWf{@[M%m6]OI]m͡4G5{!* mMShr߬{^IuS*^y_,8 =s {)0՚aMC]I:kUZt03#~,(n%rBbvGrIre;0bWenR I6w1:3dC%fӇGAߡ+ɒ۴(}ҩAgӵf7j O~mi|>]NgFFtJ6,중gbS=:\fsA`. Ń1x*^4↉C47L۴P! 7ͽȦB.M>s28CҺ) |ZO'n.,}/Ǩ'7+46eRlcX3cbt)VGtL'(&׮@qM8:[S5SnGLњeuu|K*fZy"!p{uUCuL->X0lTaW2/j€>lY*PW13x hE0U gvVKm9-`'HoМ䡻 3H+ Ƚ+bd+v [P!& MGWu@Uη Lj `TJQY¨6Z<'e#6aTν=H."pjL ~HCA=L*I~D}}j&(&>$rPYľq!F’Ԗ#2c.f؛҈ #D&j|9a7Ma/[5 ; V7,7.9ЯgO`_{R̟q۳Dt<Ɵ+I2ϗ~ŧ|ji9Aبis0dv`U:o\pdVRldkz2\[VP<6/38Xp4<1O۠k wuIs⥧MXz'y~֑ >\qL=@iͪ/#4Rץiº҅!,았[[ 8CWEtW%X 1udzIرa뗒%D{U (dŢ"TiĄ-X1cZt*~Hf: gMg|DŽVWchem[!g2qC AQ3ыL6eD~ڛ"o!%̰/ɿ 5e?AÖ 3n2BӾ2<1Zf-'%ǣf;<:,g&J4aB]']"G بm,ME]C?M:v?N9av;C#ʙ͜rڪsڹGi;ޕdd{̢hGT FզǏd h*iۇ(r~9ƍ` )>;GJKQw ōyW;f̝KbOJ"5:_GFO_vP뀌Ս2XM]ֲF\Zیz8]4U.ìَiQ8|diUcvɣ~\5 W̃`A.H3Ô95n$ḁ׶fJ-M|kO 4tN74;LDaoɖFBVʴ!ţm%u4<2 ǶHFZXtM` ((@~NXSsqKB2pyr_lDGhpRFr&ʸ@o=5‘٬,ߨ*e^鷻gdcGQ^Qy^5p;ty"δ#z|Plf uh1SoV|76k-$=+t5Ņ@EVݜiVN 6>\W}atװi{픎P~|WZ!œ#C#iD*ߔg%V-2y,I6)]k<3Q)[8zA ;o$9 bkкd呸`U)V<۪,֊{ Sҏ%BBل ;'0 |b;x[lyE֘L&mKy~\ˑ"'t*9WTS ͉)`'榁d^]*dҤj *8( GUOTTD2#>㪣|ާ*T^B΄DOJvxkPt[ܡǻ+Q52he$Y M{ "LQØSRbnz6)ԬK8WrVeγ*|⫛I VXr/ YMr| nX"26!ܵ6 ͥsSB^\˦.qV%CzYKmUJsr5y= .05oG"/܇WR6WGm5 vF U:NNL/%zs; .i~'Usug Cſ%7D^sc>4&;P#(W;n!4_y-_<ƥbDkv U3thU}`xʍu4{) ˨F{3찮B"Ϻtr3AKỖlͫXVҮB!B]Wb"?⼮"hi+ +{jϨ~_=k4Q?k=xvJXFgr\\jp}OWqq\9LjMWzqVl)/[>r;vЦDEC&7>x7Btx} Ǿ?Ò7ؘԨ`Ǵ0*q^R` k~o6;:kB_-L@HY< }po#MUN]ɢ na@X~?Qu UTZ]l6O̞ʶL_f79 >3gy``gjwD0Mi~XN##&F*^%|G^۾w5kJ9~p䏌am?OLYK|FPM$A]wp $R~R33ͷת]q{|gb;@J)’$)_\a[sNT,[TQxL,9'%+sST;OTX~=ӑM'k&΅2P}1ɼac9@EoˑS4a+,LUU>~(kfk>dCP>5\[W-w@҅ghK=vxrNoIT~ Q?ͷZzY4X8;fٓI|w9Ì "iec}y!vY8C Z;R9' dAK:rsM'i,0CbhϿc-^bbF5+.FZ+?z>{.FN$ SyeS>LoR1VJ kĸ=,sqx?+\qG6rsΟ` N_cN|؎[m/e&o Hg> v~1.Wyd؛)TM~qX|}" %/as7]7C*:]M&k}bWz}f#x8k7HzFR3t1BdecL=7@d0wW k00~ TL,E`~Xnsp}tzvW(XCUAu孔#篐.Z vꦘL h%@[:gF8Qp9"6$h5vHxLs$mDdbc$WJ]h= XMWKPGR\gҾ*SS+!Xpl rZ08ut&BeHʫ*`:&TRͰf!PCp"g{:* cI\UwC#Xz;5E#~6%CY͛=Y,$g4^0glTYeO,lXBjR{fp7)KqO^F-NԆHRtDž#5edqE\1<-(JAUrHM5ʐHxiU晘ex5{E (F[T_L؀W3'ٹ$t0b^qz\1NG8ֽ:d` ea x-Gy` ~Hc/O?{m qBvO^X2 ~ON툜 h)yVK{4{hX恼_@q)ga||; [uef} >b{L-faD ٫Csrfw_h`j$.TGT~̞7A〱~u HB)nXjAS7ԳGHCj=Ls޿U5$@Cce,r)f=cەA1g@I\X 9n0CiB{iufPFLEKO7ɸPE=d] 6=|gސVuJ*ɎD.e85w8dHqPS"69J9E"rYQyÞf6Ӛ;zL+lZ)-yZ;qD M |HnIX_+R4<)ʹr5=(d_9Z׵0&cTTTrA(9 ta*:bLpgtq[\ވ˜G"HL}79j6?aI~(ϸcڍ36j;!Cubsq+I2x%nh󮇍[ubĝCcR*bkn|Sz1(3:à:FvvkpRgحb#Q]\ub?N@Z#T+2cK3F ecxbhl,\ʅ\4|,"xG_ /WP4;E,;OjDOlf>%~sVZ)%*}A0cKrCfPPiBօoD75c,&-t,ZmW-|9#fIJ=uʆ }qDYE\T]Uݗ! &UUb бpפ aՄ^w O%'Iȫ;X1إٶ80ccrBt} -9g qi6PfDmPA"{&@m%H!pwr!t(s0rYLKe=@qʒLƺ7[?%`mHλxtv>{ۜ{CL;.,b 1::$K?'G%>G@|7ŝjyqkyUh1?xy$U3R"O*|jMmo0L ^auL+$@av4\PX%/dԠW@J)1Ɵ rKӀrgןP/~M%ZأEFs# vhy D#vy󑫇J5G"RYЧb6rwfEASͣwz( Qk*d@{4*7p%DQ KbW$u,2!<(RC~AV'? @]pO XE _eX+ѿPMne:;*fuQHIg ӊ-~& \dY =X =/C貰qbkeA1i ӵ#ff$7)X35WXЀ2T&F!mej[ Q둩0yoy}v V8dLaHܼ(LJYM`@?s}n7=)K]:dE4D!6RSêۚ1y!@8cs\6(1~1p$Y4B԰Q# [Fޕzi2 Ґr_g?^CGQG:Wstɴ٬!x[a,ƇHpKwje=ns_&)jۓiDF7y -{Q(־)ׂ&U'}UU> |[e<O4`94@#-h"q }ϔhe6FidZv;N`Lu偵LU޴S&dW? fB^ЅEֿ<tp\ϕ<%r4Lr(BFɜAdrL`x[/ CTn#PKGt- NyquistIDE.gifWw%]M2Nnl۶m۶m۶mĶ&uWwSk]W4D /[Aw_A@@@2A@f/bfa6aaai bfb b6b/7$ $3$s$_ 3ȌL& LA @3`&p_6>-3fLfffmEffff3fX4cdΜaG_L& @3f`&3p- ֿbL333efeΘeſ͙L?H5fg̀Ϭ7I??9ߚg?}ff2g|'L ? 3?; ?f!GLaF_}[g?}fwȀ?o 1g4Vgv'?I18("gI` h(eCP('vHGbP6GD2*7dSDDst*SOl<[,CX]RdҙT6G&4Jh%[ݻn$ x)Gd6BJ;JjX'ƭB'tjZyVZ5f*JOﶓYy`ߧ7әli=r/Za׋"9 nvVYg72`tY-AMs,V>A:iГG㊡]l.veWacգ#9hQiO#i9ښ*k3;2^Zv% 6]%ZmNۖ=݀$X_0WFv` cNUCwh[yj'uGȘ?*,U=G1U,ϫ=ERU2e S,ܴne]M^w[͹ZJ`늜2{-zDa.ۺ陮ێF̮[zϟ5;;#'l;a=SN?~rKm_q~ǭw+}w@~ >n-o]3?v%o*>W1|m=zv};+=sު?^"8c_!zǕ#rX(Jb~D Co'!$pc_a@ %jDUIX pߛkͬ){Sm~[U\Ն:;E}A!;XcV W+~/ln2|:Bp #~Tk3 >~$}x51baɲM,ݧĒe>&՘Kif&Y9qE%|6?bhol)+GPjC Ô4lsL!'dZ< 9dYݤ{}͡LnZ;%אs_j-! U-zB9ʣ[cxY*? [^gt:a%QjIgMȬ&WW[ +ڕWaT91_,*v1^G-UVqTjN6|(SolU-5=V]T(bm>ԑ^KѹVTޣ+k`ZnN_|ԢՑRuKl6gVfј[n Kli&˹YҬ[++hTD7е]V94J`6`°*{v&V_kJDYR'pc5oMc-_~.+s!X}b#sSojmÉ~?˴XkzL ȭDa]0ubH1ZB&mG!O Mj 7d"B߉X6`@̻ 9$vDyi4vnL :0N5I3zwrf"y?ᚓc|eÝJc~QF.g){zi!c Pwؑέ3U6:}$oF[ yJAȘfQR:v.)\dVr~>qV\koK.O~;SD_;k-%z@dm{zgXP/;<;"ʸ߆2„G<POh )UD @*@^@ڌ@(h_G g $ $os?t ? ^?DزOB%O k%%5Ts@9 ?a0A?#7F’6]&+@yw'jm3J%_lU<" yE {1Ei[G.A̝م y5E$CDDEjRBQZO8UE)kD6Oxyґ+SO%Cǎy͹ET1G%ds8*Q PR{o&dG5cFmh8s79rĝB`?/"h*c%(,"+0Vc@8:cߠ `(%!)  ܍qgL62^ȑ1>A>2 \ 10ˉ^G`pgJԂ?7]hki(#46i> މ1oɆFF4kgeQIL~Ji TFimBi/ YEɋGX> G)`ԕDS<ɜ,T֜nߘtTA&ٷio)+J L19YYXԳ*Ff-1uobP'"=D €ZBx@JȆWfD왏oؗ:exhSJtFYXXR~eT$F|#O4D{X(qL4{!%%LyTTGwۄ8x{J.2.grpʵpbh7򬒤h-OԨ(){wb" ☩P1)J+Tq|0OJ¢Ȟ"|N! ^ ڼ&oK vj,Fd$J=GENcen\7Ɍ-[^Q}DEz;YI2YyzQYY^E3$[2ƪ.TDT]fGegjѧkfc>UK!W9DA5$5A?QAiZ'W3sQiGFG7{.xåG{Ճ\V<AaSj4҉|~Ny@{<(bxJygz5Pr7*5MxFy0a*<J VꂁۍJ AЀǦ7Y ++!4D!?@TjvcH :캑l`03 ~ì|찠 b>d)J/"IʖR)!x!ǦJ)!uMߏ~rIf묄+mJw Ls5@u!,ht:'hs,{bTgP9PzQzthlzk(pf(w+O Ωŭqș֍Iڜ љȊ5M[CT "~@П1N*a4͗/lƫ*ݯQd5^= 5K)33zn/'"Q3GFS'Uc=K0[Ի]g^ ^=>u50V'Kffp;5cY*{gzތk?{!v\;rA6ǶONL,̗o! JSnLo, ][]Y[uYrĻ"Ż.UrS"j{&sbHwwH~KpMQ)!fK}ae Ab#a2k`jwkhp9prlvzO7J5drotSjBG%{SS|_of_G*\P6'vSlNNCd5XP}:vF[dwsmɀ6<*ȐPL9eD.l4}5<%}4tݡvݽdMM>_@r,J{fdo#YV!,MCz#򜣏#YMI^־Ü[Gx'!M[ttziyv~(Vud%wĒ[攽oۜITսRbAB(wfYn v3 =)j΀RvUX'gQ};.ܼbᘅzYrvճ~uC"/B'6oZT)H`3]ca̰:\iWYRI+NT2cs=8J%bxj7luҰ|nfF>x/; &P{᫼{·E[fgnz?_ i;=P Ձho{dBKK\G;3d aJRGrÏ A"ß) |nVRpFBL䉑\#(hRdaWD ^_Yb(!sÝNr#Dz3X 7yHiךy>09&[gsp-E'< jHV"1dBKN1EERuI%Y`[J%%IsH`) Cz:&^g(-'v`y79E u~p1{`>}e<8}{$7-%*ӋZuԳAUTc?[#Yir;ѐk.䔥TjTf9kKiުf}OB6xF,fCcrb́~G@1q-ۨօkȠ1#Vl#9;xsn9(ƐrZ71^Σ'P9؜Nc.>\"h1{ξ_,s4~>Wg[ſ"r}PL9By!Nt?1>.D>}-Hѣ{>ſ{WLRٯXIu9FPOqBWX~(=^X׻6uP"ǿ:]ߙ:wOWTIuϠ3ߺ6@rߦ2v4{|yHxADxO~^h B $ |m,\^#+}i==p-3aU"e܅F_D૏ePfw`I,ghwo'8EbNU$]i v)8=1%2 Q0*a22n+#2#A:y,~D\~?,e!?2[ ӈ/?y[ _|, 7ȂȈ5eE5$TX*3,<0u0P [ ܊*ש~ yGIEjce2m&e*f }rqbwepQfʈqYpz0e(yez$DZxF;'E(FDʟ3yFjq~~y%:GzG821p==#;"38#03k"4"#'9$V3N#}3{3=rRx<;f*w5[2|2;r?7 >?*3#)2ߥ3߳22""eP[޷ c$훼;%Hg6f@9p{޹`QwXcaj=Þ;fZ Y&N6(PdhlW܆P"+";۔`7rs:!<ƁROgӺ26*lR|,⪶쪐ϲ βo9̪ u\Qq%uEUKմE%ۅ*M5pJv|mr;v.jm :؍͒L~h 6ڵ\QdD>J袂(F4ū"ny|-1X(>o>#Z=C)YXء7LG{r!XɻT>?wl`urGHfrw40i;AG(gx3h;w3X{c`7h)DҰeSdG3j@ GKP't\7'N} 0'1 +T};G2g2w'^'_KG6O h ud0Ϗ2OOIpxX9_J+ L H)0R/0+w {{y{$j~{}߽g>GI,= ΙZF~珰t4) 鰷9w3)0ւXi{` _T r9=ý8|YqP5Ⱦ^V} K ONlf(B_c΋gbԞnV=#:{ 7*Gn]p UQ&kgAuV]Q:C>{4؂~_Odhƣ_0R6I߃f&E#VF6 d[4 RY% XG BxU Cxa"I'JI;=^'oCQ@T)xQ>mTf{* UC}!($g5N5ʡ( /O5!lF~*2G3,W۩lmM i*&7Z}Û$`p''B|'єxU5%膰z܇GjygXحo{"*Zx7;|1S20;H B4e9TB = @1B#Ỉ j }Hܙċ9"3Ï2u!ItGlJ^溙E ۭ+EIe"+2z~+!;.Dl?J.JpeB*)UQ~&gRe)j{.y`>`VV-ZVMYqu%yǝ,WކȖj Cjcb5uzz!$صƯW;nyS<'.Fe)t[vkRK>K)nMղIA^vӕ("cQIק\мǎhxlﻈ)(³Fh//C4v0͓4 q26@6go)3ϫS;Nk_6o,bnb"tjt46rכ%Gb`foc'ųqFqv9ypВLɠhl__MZy jv׏rBGG0t)S( 9SIZ>>|;x.ǫ%oK|#N =@"u1#ݝ(QH?H)mkw*p5/;qa0! HF.a\v!h6YP&} |(Fτ.2S^KQ˜ 1%2dQIY9Ի O"S@`j[99_"}!tEp31Ҥ !M\;&Z *%6DcI5R IПBy%Dc9FdLRr1%qۇzc NN-h}^D%@_brӱ -O)KҒ#ڟ260ɩ>âa:ņSSEO);3vcJybi)3wrFqTbh/Ѥ֤S K C"$вYEpFԩSjW&EN0} I!^wSRZii{9AX8O4(:<*ό>QxiS0eVKj !1^jY8BԗfLbwJZZĥBJ/zKKl.V#kHY諵c"*b̟`LH{K13CA{5^ڟ .βG]&4=f!~Hd'?W͢[>cq^S?_H_cnā_bz}1cx߷u_[_y:sȷY}7/*Pcc8 Hd:1i ">*J/ʣ*Ake903]@U%5OtkB QP"pC 9C:KB(x.yUԽ1԰ɟ`G!nDDN)lPiD%LP-hCX/CHEB#BT15M-CDtb 1\B0C,"$ lHb_İCyK~X{) I ɍ Ǝ< ъIȋHيHXĊYHXՊYH̊H݊H8Š9H8ӊ9HʊHۊHxƀe?A"Lf<ﲼ2lɪ&˪,L|ƩѪ.6rSZ6ШV]?hj nЪn*lVnU^6V!땬;.;^Myk]r֕kcփV^WfCԝ՝BWmՃCu5-MQC\5WR4Ea4]MGcVeU+Ƃ1[YGӜn$*%RR9lf:AʝY@Q#4)Vm љQF1©uڳcqATqp rU\RnCY^^U˩폪gi%%&gbt;5g?[Y nmo}]8lx[P^D'm~rԊcڴg*Q$V{+σ&JV TeFՉE;ܟؑΛȬILG I1i+\9ȕ ڮqN|++^{L{6RdOœ Wު?7޳3G||$BË\<=w)b9<K7ΉτN JnT@~Kg7 e6~Y.T9fysn9 uwUtkr#bM(f?DL ^T > '6s+}b&Pa6a 5͝$ qծlƄ^>eB(N<3N},h1MChRGoqj=wߞ[=G|IZBOF5q{Y=wqfu%܋#݋P|w=Ò60EL>f;& `&O5sXs@o}iPaB~&3IL2a _Uxm׋;@L3O:'c`oT(y86~EHK(Ȥ Qmi[l 00>[Y!>_DU9|r,C%76g$Ah1_,淅m- Yr P>Vh 3b֯ PC'S+ǹjTMЋdp0GPp4'Ot2Ng4_t6^{7Un=R[Y-CH!@%b* 00錭;tFcMj'sԪvFJvFk‘xK3X8iRW,ExARb<7tgyh  ˈE㨿PqlL'q۶QW;i|yМfi$QFirHG#QT0 W{q> @YU♏E:mkFC!D_UǕXBgh^$c9T9Z]WsHt/(4d*ƶi= B)۲=WPamsŤ| ҄#?&nbjaaږe,c I㤊[,rJ]~eaQEKUԧ3YWj˰!/FQ5]$]}Vu1hOvِaeerߞ c* 0䱻*9b+Ŝg&n`ɐ0n|Y"+"F6bҩ'JҊGZ$ca9":.Ⲻڸ1.]菿W!r̖'k_olw*v$nxҳWqFi*xA"pWp4QpNW_D CTcYŸmõ z D{'fgμHJe\qD%_hdҬ_GrMy׫->/Kv/ruU>qFJm+!'%(dc^VDJ BĶĮ?~ O!S?Lnaw!D}|AljHs^#e* M+Q1&$F"g5AaE_"w eM2%hS}\9@8yc]_i]􊈿\G;i|q˭ȡV!ud53ҧxe ˱m%i픪bbRf{Ь s6@B_أYHEe|+g3J*?@F̭&QBF4 e֩O&)5u$e.Y€RC'GϓY%;Աڱ`>BHfVA:O%#צ!P,&;X`:u19m-qv)n{? F3Vi]oUb/_$1ҀfR) **"ˉfL~0me :Xkd9e-"f]1Ͻ*FBooj` [E~s6{LR,4}'dVi{7kj$8\J!Jm$iWQtZHU"^>Cx6#E~[ɍ(I\&*pm]\"QQƃy.dMQKH9JdJuĊ$&5QVFDZ P3acBbZ0&U"w @ʤX,g WH!! !k֩a_#jNGMKBHjF 9SP/juǎ/&.k⢆A`DGFdߣe4ADJ!XLNSvYW"[AdM ?h1 Q_pZډ\?D`BH,r'B +j.m~PӕcBΐB eLmNa(F(&'(N\(*PD(1-hiR"X"KHd<R (FB_ID$ YJNh)x'gz(q9b/"-:&Q^h#^ZV^8Ek]p (X(G(Xt53yK0tb"Rj {eHe/g$BB[EԎC:t5a0*|QBQPY} ^jOo0*lѵK60,P9&vR̞ۻt FmBgRCѐ Ӊ턚05]DMa@ Z3nRO0oJ4OYM vǡb!ﱸ:$h*7jу*ᢊL Qw5̨@Ŝ(Q)5H-:d $m3/PԟMe ϲt [iANڵ?ЎSq~Q}Dhͭ0OF"A,N`7~P-S\U(R]E7S Ve 2AߓSq=Cy#o6ewxc}PyeHj@|R!a i?u@BXa瀢4G>΁S?>Xw ܪX.oZ[)w]©qI)"jƒ]c9N +ʐ{3+Iy: b00Ɯb"04(7[A(*:+Wk3QrE%LŁE2 P$t\Rtly™(/ꖵ 2J(#Q8b \Εٻ))b8$g76_x1 cԖ.vU uz 93V<'bZˎ y KQNS&3Jn8hۃeG^NׄN+*V< /åHݬ%x;ȢeoUjμߓ;Mn]~%m4FUQR*ҩ}YR " u|PvS%łpq&EK Bjp.mAbJdhVٚSK362v8}?J49) }jI[CIJ >bוXyM%!4A#̒Mw2dg"YgH( .;*r"_u diC4$GZ-΄Dђʓ/E *KؕɗNs- 4rU[*Qp0w=gK6hzuZcTHIqjMA,8˟'g guEFj-ۧ]f}QD,b44C9O[*-\mX$**[S}` H[䟌5z'1[[ 8>m_-:/e7ieldSc4&B][^qaE 8ߖL*[CR܃h9%c2Y8%^tt ,ObOm!zvmp ԚKD0D/֎0^can&ZWj/<+ڱsvJN>7h,g~=ӡUaIR3Zee,E`3G=dg36lbCtH~GI5rONh}2[nnBc$וtgbOx"K|;u+wuZIGAK8v|IXي i˂r><jN7dNXDW}y׭EyxGYw5tU$ʢa WŞ%UA,.)ц"ՄGW櫤h 1-3Kv) 㼍Jsœ7~`eh4P ˇ|lI<E>&(=cs/[P^{Pw]rnfw<>YAlo_VkГcܺ5`T=K >T X֞^ho=7ǙoNU)/0p"E gQ1Z#z9錱n- l`X5\5UגuW5vZ>)DQ u9/V,48 0¯Hßá&_~_AdSd=)`( `XyTuf[>eY+NVجpkE.lWf:)YS$p܏5iMl/Y"i$ZͶe?v:]zz}|h8[2(-}v$jX£T5V#n|*ˌ h!el=B*˙b!u,T\e^+l͗҉, |[tq-=NsTwY&ϥ949 J A/ @H ~Wrj23ӇDH"oIfnȲ!$V +AR ʾRHvf R#[FNAQ _kQ8j oU‹s4c<(#,yJXkGze.@A^ydy1ɒڬ+&$Kɑ%Ti fKrzt\ YoKblHdƮR9ۼȨ I\ )gSDTZwJ,[j4O;R(eh*VmӃSɘ\)K)E7/ڮnڮ.۳ Ǻs$6Z+#;UZD{JE /edvXqQFm};EQtou@C:%C+֪;O4F8eiA'CE]&+wW\3,v*e!ߋ,lKa܉4%ʜf-@\$U}Xв ׾(eIapަb{}pgc׾׼"3uOB,pIzy {i1#8޸r74u;~VCWxI_u\N}iU~4c[>s?ʉsҟyG+incJya1Iȿ" TЃAs,Q͓La,EV%aIeHw0;Ud4k߮+0NO-(p|J,N4*14ZUE0H@ QQˈQhXM2(r4N;xGs⃌|»aom}6.<_'pYƇY5I1P'N%0p!c+KYǣlf(9ژSPqdH;!.HOD"#Q^H!ÿА;|6)䛔VDvJ,5{G߻In(9fNxI9aMϜoK!™rCq  Ŭ|ct[iHZEG 7B{`Bj(K(JFE:%.HvFC*9/d*"bjC%*MLcI*%J&R0vIu1ƖZ042퇴m11Gk-G{c-&ԅ!T2KY9>\|sFGN9)X7{u)ED kq9Tz稵WDy;ctUħ$f|S)'F-[b荍bZRK. rok{|TsyHkpZV-n<^;U$dQP^u $#́㇏2\XXHnD:2z{< DkPv5+Rߡb%/F(1*; /,uHZ.T+aJ1b\ALR B3tYQzq(1q3/VoܦȨZj gd,S2]* 'smZq yj3驴[-ٚ&/qUS37`O_wΖtVN1_3 l,0|-e:tԟ~,o6VHL;UH2*HŖ!~֯x)8ԓW"8 迯RD iUcBԌ A'Ą~<z 1Hzd)"f9*-7Z9∙Ne"N1p}iO^^ӌjȎ5XM*?$T0UG"ښz;uRtsM8]nDXβ.ikV.z;.Je拗 (uƘ󤔉4xQ =7潬(м IMF~ߵ459!O,4?e[aIpd+?$Ixζ^Tm{D3 (Q &6) `W72kf u=D 2T`PvrxD.$RB`b|Lpvv 9f |Wgw 1 !&#&f j.&c )՜b@&^MnrdV.NE(hv žt7&¤1b"`/"+F(كA+::LYD{GѬ :S8uh 26rFcu7<;e@eT $2 :U#!wL~gr}bѠӄe^JpP܉f+ 48?MD@-&? ru5m0p+SY% d(<-e*e;eWL>4**^8j#[ϢN|T~rwJW]qĎYj7+.ݨ<9@ݢTeFT݆Ueٛ'D냧hFR"(dr\Y'b(/'Jt)Rxuo#YBrDtp( C#{*daZ@C@gvbIf U ?6]Jw"L!ajSit*6XܪT| IL-YMWPfXMWdT gy/lzCvI΄+U9y!a;Ye]G[8)e.G=ګI`O╅lF4AU4%Dƈ"dFri{qQxȞbfa A Cjxy.lHIhv!!F{bBd,65yCܢ, wȴY&^A[8\Tdu7'BRٓ-uѰ'䐄܉6U^]n][Fk80ܦUˆ;r뙰YmS3%fJp2FfxSwgfd] n,>Y?gDcfX]WZfTfDgجgd}H`5 Bx+X0Q+ɰxc61]dibNBz pE]7ЖD-*QG -8snb92g.PseZYyymgގJ ^JE`vQXPHt;mH>&wK\XJbұ(>۰lsn)t;wͦwầk/ Uȳ΂hΜOGD,ĸU/3[93q,º2r>{VV9c=7պ[U#4Rۯ:;V[mۤ;]ybRh1sܾrȓa0! 0 E0R$׼{"CȇP{g(MtƩH bR,IF!CЈ+E*02cxS@#.K'M" FF 8Q33 ڦr&f%\ny|j"k n'nWrVn՛ r-*_&S Gy\h-󔿲T%׳IkZO[㤻-wpLsl-Sǁri9VTjU()9:V]\FLX!A{ QXPAL;Ӂ2&/#5|+}L&/ _bh:]0W`.+Sa?D?)Q]a?|2JȈf8tCVxEMPϾ*g )vHMt}7F=Q. '˳ٴf*g[Fe`WrʹdF\X&UuWdGRf(F  V[ V2fgtUQ$R֤uUYOET6VidDy7#2\4ik/,]oʛY6"EvTew$}tGSxEnF 'TLd!p_ONixl"G$;Bhf48I U D"(ȴ`c (cIȓߦ)L2E:Ӿ 玘n΢O;2KNKC?m۶vNv]yZ~,4 t`w+c\e|i%r"UvUw`v1AQ;1L)AlO3[r8F rFh?ı+[n좭̣uIU]H,QUT9`~YD`l-}8QJ}%矢` hO NB/ߢ#R 2R'0[wA@_D}h_DG}η!Q*|Hz7ۓ{o0]YDdHGK*C ~#l*g>xRbC G7E7XeB4xq`B CtGM̷TLʚYEpm:hojcuΥֺ7^='?;,8edKk2%7*0vpKֲQӘM/м eIa>*[~,Оk!7uiU'X&ԉJ5͢6S6ѣAկKK6c1٬k[mm /:{{FF;ci :m+)N67M"8k}7xC 鈷Hц<[mu9@sp''385ؽ_NvﭵV fSDH%$&u~%OB6t饈 (Qgj]J1KIk;KN+NƱf\"rKcΘ[}s]S<ܘuDWNM\,蠼X2c+ͅ;msf9ӳfjT2 _$SxkM%[S[odQ@նZk}ozˊeJ[?e&WE._cd,9sk\;eKW-9c-vNȓ`g\^9̼R&oj:7;T&D~]Ű(X B>?k( ffUJQn̄BsGOq9DŽ s.N;GH{p-9i{ι g\DA"5qdr^\:1xܹ,w bNW A+! T{ A=>z_:V4S~!Z {-:\Σ=a{-U/^$Gd'EHnd$iTO\̿T,E!L\U\#|Q8b&=KK>ıNшBNS"\knQцߢb*."*p-B2P;~⁸A46 ?Q&'}X$j$KJޡǸ.W;G *+a< '';K$.P[?zq#0SȄ04%ѼrS% e&9p4,b\YR:S69 R%SJGPRI!؅SE#0i4X9mI,4sG6;9pS.0 0=332)ՉIMĂGdi`HnH 6ԲNJ"'A6`K3"-+#dyF1fQYcN j-܁ Kl2"cDhwETlG|?(gS<%9,}1& L38 S ҜS==-M]x=8s䂊Z bd,9XX\l@fڴG#L[^Y5 |:noX輵7gb*ܻd#e0h&씌OIhvDcMGG[f~@GWvs"t$".Uj%TAEՈXuE5قߍ &bU# f͋2nU"d8̦*tyqMzsVw9swwwwZU/ʧ@2}mr 18E}$!Q>cCyn4ww , mw Lw5'xu_~dɻһ$i@뱀h@I/i>qfw^wh\w'Uݫ32GG[{v"yFM.zJР C$W}%k.|yw{{{gwyW/}a 5x$Pɧ/kZ]S@k{Ӈ}׏{}}zuwgvwG7g'mzqqA (8 :|Q!D,Ҙ/cÍf<( Ƈ~ؒcČi1aȑ }xĝ ]sϦNB*u*URV^j-Uӭb%شn~z[hmm^t ];xna+fLnWU/cάy3gQM?m/4mudϒBGNd1"ouMpL=S9C'[}}tб?i]f?=/R3_~?7Z5? 5LU{ !]r1RtQ@aI1]E$bv]T)p bo2T !;y^awgYY#^A2٤6Z5 Om ?wۇ}8yT17tlƈf+&PMdMՠ"2gZFM5%H62AbIp(݆'*JyxIm‰kt("2iQi?2+IS͔pGzETQ4RP4[()NYҼMKQ8$Ӯ 7h:W`Qؒ[\UɷdHNeD.mRa\$ܰT)8 5:O4ڤB63-hMXhauĄQ92\sV5SLcZ#v`3oӐ}u] uSxg")5f]x.m8լ7dserX]}ms\[Ƿ^g }+N6ϳ.gA(abh|[=iy&u1\_/ߗ~IO5[詇[`ݖgZ[?ן|}K{{TkY0Mb#+׼7:rtr*]Mkݛ6/}T#[f>3[0>ڥv)` Fq41B4l:pd hB"}On;Is^}-|VX&½d +)4yhbW;Mh̀?:e(`:,"䋡DZjU,nВn U7> &p4$(I5u_Ci%-BА\'>'No%\8]j<(hIѱ/etGeraj(a? \g 1McU_A?j2b)!"XI4s ΏދIY̟4 к [8qH;٭Rd'IK4 TTH7uATi`,LΣCF*F1H5̺HA|Yl`Ŭp۴т6FPUDb,N ROeG]G5/8D_1Wth\ SWP%,؎%ubSٕ#ez.na2K50ޕ&5g򤵜=WkZqD]Jw6fN_);Мhv2t#SxF$m*tdi3:U&6!gYPQKۀiv) ڥW66(YĵK%ji;k }k`A.*|/+$d߽w(U}9Z XnT$rԅSL䊁mT;4S+c)DˌL8l<[Lڟ%Y q ^د55ȼ2g4- '0~9PyQ~d GVF2+ZIhG#ѕ-ޜ KPjZq}1#)0ٌFm򺓝skl.DC><{hR3GJ 5uW{~"HEV3tOSzL2xtk3&w/{`CFގ!X5.hE(~5&>'L$;3C!+IIzn"3>͋zfw MfWm%ARCB<^9qu{omn#os/6)렛LAKR)@~"G7;#w?A@ O?_r)A?_A`z9T\xWyYwQEԓ M_AFΩeߣBp! _A(S\S`Re?D`\`9)abFDR`P ~ 7a"ّ`QN>, "! "b"*"A8a9_NH_BbN!%n"'R)&B!e^"J+J) +D_ BA")D`:E$.abT&#,b), ӑ Ma˵S(\N !!b= !>6%1c)_:!f! `C`0D/D!?bBfA:`FZ#IޢT Ol@Vd%~d5*KD$;͡E[$P6ڢQjRmZu =q5ASS4\H\=##H!Z&bfE )42 2&+Bj"H>V#_jdHJJb0a4H8/'cSD$6b$3 &_6E$FI5&Ap0K)y2 @aS1۬P.ƽĜVR넓NE- Y?>*'[ef #LL&G& NC* 2H@FdLu4eMBcF"t:d%>AG.yF'9%RR]SlnN]mNjSSR%͜#@6Zg?zf teIJbgI2\uBtgff`hyҨg U0A)N¨:2>BJ'j'yB)n ]#Ea4[5hvZyͮ5NHדN`!~"r."֩?0ugE1b^2FRJb'GbtZd^jF_B_("_Fd$ 6]Rbrd}ara]*fF佗ӡ镎i&-] Z1[ީmZMvhZaRtqiXa*N|BF21Tu-ԟѝQiωT)f+R(NȣHJsS4!6IȾ< ]Nli%x46 Ϣ5 =H O2- iq89,N3Nb-t6fmФH Teעmg^i +ȘY 'ݲW>, gO]Kn{d7ơ7BZv.f:ZݡGFX(N1  ,榌`:ޭ嶡i\8}lAnbOV%jѲRNk%ZTN%]o>F=Yl +*mTf@ƚbBeL*/f/'(*, ᓲuj雕y\#Pn:+Mֹ>[.㹚2 k< 70F߿zQu)+OJ҃ak*.MJD7=\\t(?"G$#0>`&.-r!qV6`W!''bd*BwqE1J%i3EBg_J:q"OZr?i\Q/ )Y+OfBh2QU^q#[srhr+pyJ'.Bگ,gV>3eoqrߪ*`n30Fhs:i 32ʤ68C(it(/kJpO$j/h:)FO5*/Y1g41+玎`$zg2hVj*3(KgI `dt楩6%FsuLn$*H¤OP#~diVo 1u!8+B.LTUyqn(צF/[|aOfy_RHgf27O^Ӵ5bs'K'2^Gf&2~fMS'Ur/ZXl;UaN,A,z&UBf6 6{wpCgןfS1)_#nuuijȅϞLI{ k׺V3x/w('[p ҴfuiWk.qK蚒mc[:s^55QVS5uUܛGE >hc˦>)30*@BU<+(,_0#e.F7Òz5$jg elr/o!keTg~y6k^f>8>6 @GkfrsYi՞M˶m\Dֵ{KpjS5*dɯBuQs8en)K΢/M%GP| k +(PcϔVA[5l} 4Zv|ƽ M 0Z*Qyi.%ICw{ wa OH,sLT >6Zˊ(H< M֬kN{q,F=.LH%J ӊ2KBRi,mMCkTRI>0r-9c(YNnF!57 BH[oYJ%3h6Z4/0ҿTi,1\R);=q+tYm>qOL9WuuWH"M4_ O-m}Ư+O*0UdjSմM+UFdk7VfyWٰkmh~ZY sۍ#ܰBrvkH y%!f jT3lB(¢"$ϯ#m;V6-oUXW]\hֳtq5k]( mhSn;\x)$)ortR9K4n e7Ku|rL#o$;OZՙݗOU(ӟz|z=)Mh7?oK^2!/\C b}JRE!rJ)1(sMz9aL(;{aQk a!("HKҌT\ DDHTLcUHʘq) Rlǹ$$ 'xQ+7Ό֗f#^,G9Q*HbAY&DlbRA1XTT`A:΅?&9y5%]Ӗﺄ)r!B|E32xDq5"+ǾF^c;V5Ut%MrDIΧ Rȯa'ϒQٔ0e+?#xA ʠc)Vcx"PUΝ=mOg>I"XK\ cBPHa/<@br1(0Mrcψ$#L|3TQ4 =Q#Ҟcc$JK(v9+6*ڰW`_B@>ffs2!U![=)$cJzR>G%LɦE$5.%R47!2êԝ1:&8lCƘ0HJ_06b)"Z1h_"ё=iKZi ں;"sbH+rjkK:6Cڍ~xOBOANr2G)a>XF UzK, ǒױMy%T ^V& ,:0iv)9˥q9#W᳷q۰vovAd3w*1WRERcd{n+\!|]O)ncF} @# eEQ.R0c//$2"N.lFtь^ A!MXuPխT]K+xfO(6?YIKۧuc jr #y/dJrcv0h $䍘TAVL WMPnSUpU\gOk_08\aPaWKpp] ]i0З8ϚKԚk #F*i\*O/P/N)xo i|#B @ʂ1Z ;q̯?G"$rxP£R (Kw.Ӥ6.hCm|D >QR|ȃt+dQ=v%<̐qq@wڭ`1,MCOXbtH#B@KEWEQ!FuOjLDK >TTELUh(r G?TIEE}(䒗2""~I/,-fP‹LbVP P pTG"l6F,-nBўЮo>V=-Dno8MB [/ AY \DI%0م%Ne8j0 9%ת/"w"*Kun$V\( *!biug)26{%M2^vM+hG>p?Ø2F#<>xNV|ޔHNw]OxM_q$cx}ńO1i3#lahKLĵY/ʺzGTL+0$]q# *y)Ö)F3L0!i~WX8dFp8:Z7f!cXd9Ϭ M w!+wYՠZ1tZV1ݴ?TUjN :˪ӗ`kT45m`! m`r'7QKcVB|Op0o*"TAԣiX)@,6hvqiuy7]D2n$YvVmӚ7PmxK͎, Z 餇꩎4qT-^aAdzn"`7C{f^q{ /s=V/vcck#;()ET|Gz4-L^vez]bgW ئm7W_NQ:zv>Jn԰Ȗ FCUkvcn_mZh[_A{ ky'xvϖkJ`GWz+jIBF<MX鯇Q}64՚[&D[b h17# X̒G9F-f7d7IeE{ܔ ڗ7Wv [Ƶ̭6[zuV̋w0>SJԽ+ij;Z@ <(DByqTu$i`VמRV(>lfWf[2G`a.z:oayGXyy\ wMr|d}89‚8^<_f ogQl^lP$s6mx=^򈹭sz}ZjK@i-ǯހ:HU%-0Ѵk Ռп*\Ȑ!(BPĉ 3jȱǏ CfA+(RcTmkI͛8mjsG$ɓI ]IϟE"ӧPJJ՜۶#^RaͥG/&]z[p&K-T^Q{˷ojʂDЕM(#]#KLS0oof>KE4*خUEu˗ͨhQ Nq;ܭn6R /}iW2[R#̧M_fMtuP3ƙ u6^f[h̤ ^L  *dbw v,nYv~YtvƊh+ls*43:s*ͳ)B3=Bߌt*0}tTKsS=R!_o*:A\Ӳೌ'n [|"ń5gP[A䅄oժ vr29cT>Pŭd딘6sE;LQʱú)FovıM%ר=jLQ9К4 RŔ( ԟrEqFyy)4)(Gĥ1*Y mӖ&6 M(RQ.C$#_S@G!= =R^ب<5G#)'#JM.,b~iSOYhb'-5Jٹw2LH'S)φ^g2 Fs--=B|EcOLI%KY#VwD)_/Hu9R-Eʭj4HZҚ:(iƔy&*l.ҫvu$%UƄu4*fYFլQ,d>FtOtJSRfb=[SX{s 6b؆Ylц0NـuTIN~ܬ)ZφG'sI<tRTuem"FFzer1g sЕT0hUrW huߖVFnTlf(ԐSbEۚ62ELէo~"pgK|+?ccH e5cRsu;xnOv٩lcʖ*a%/%ݧOifx1 B/f]>6<~u;JyT+LKv6Òqt_`g6t%\#.ڮis(L5զ+sbf!4FP J͘^HV2N MQWUYvh@j:H+FEVt$9\#:8 Ns;ȴ+Pp9 _ŀRj, 1.%,@إA9nw!/ VQ3wp7I;@762('RP͠o@r:-^;)Y 9ISYsU63< )DC& mӒ؏>%9 46=FAt ϔQZE36*}wuuȆܕa~t 1H.#Ka/>e,C @ Ԡ I IP@iyq9ڐCiiI)٘Yn$y )٘y隴y9ɚaFFltFfuXfj9q8yWUm&v~~nv*6:3XC=d#v&:ִ+!w!fR: Z# @*@-ci=JE49!J#&+ Zo*GWT:H/#`sr{.V}a&\q/!SU-GפJ3(O*$&eRFP DS78_ ՘p2y !?}(ۦ5IMjtZq{:f>zqMqؗ`r7rp,N!yaK=ҧo1*FqL aaS02`,<-m.d&<ߒ- m3u#3AmrsFed')djy*ש"KD$y9yڪڪY&\ij3*B.#A(J0;'2+s#?,۰6>8熩mqq隲:/MT9Lʪ8;Ǻ0[<,k7>V9CAZ'jgsn:s=7*zݨ^{C3 w2[:K9K6lWNJepl*y*sP;\!ci; Q D\O_-Q!Nbt#׃)k[n;ڶW8Sr81D疰+}dVF;\s7 eKuMg";K9 -? , *Du =S('PA0=c.B&-E= ?b?vk7md{C.39 0`Q}lgm)ZMj42Ey ]"n-SC4O*"m(>˧ 6"LbqEݤðgyyB|Az!ؤ!bΡ:|@\w%2ztDK b\ƁzUn>tf|So A\$zl&BE)%A{fI.lž1SyMfȵHכ;ѻ!ʐ{k.ӥz@ bj$ܹaMl۶,}! ,Wȍ{?Dl˿ٌ̹۬ͺ*W)w* =ZήM˶)\2PQ M,QН<"L]˼߼!<'MjEt|^vH MϠS)c !);MFk\F=$=- Gu"}% $=,ⵍ)r#}n+Ϭ2(>L|0&3O7" mm܍E-^>}O"(GS拍~e ک Ҷplu&mH[TU:.lڀ>'t8,}ܐ u-hG {WD3 u9_~CN*n@BD~命*D໢<lwQVj^}Kխ nprt*.Gk=}mG>]=..١(԰9#o4C@Q^t}Lx>o#@Mb=~0"I*\DϽ-%{ڣo==#/_˙~w"4[z07BzZD&nҝ}wfIwb~ao#}wQ 5luFOaާsOIe?wiAMږq`O1+燚KA]aWcEQgY[UofQ)F,gKGuJ#**"W֞yߖ`/]WIf(bTb?~?a󨯲rH:zo5}^QoQfy򻿣߁$d_+*3j1o{UTU^ZUۿ|mo`㚪P>56\p6bޒc/Kn+r0nI4)qaB)whYnK%j֭][lĢU602me.>;ɣ.oK?0@' , -g,Po@ 'P B 7C*,C =dE'4gFjpj!QRAF#D*`Y1I'? Q*"K//$̪lC0£R9*̤N N=Bp!+UDi)>e:mɳQI'q6U2WPQRO?*LPG%uCJɊSR_5(-eV[}HVaIaE|K7íd6[qȪf,8G9T[s\u-tR-Rvџr[Kus!j2EF\MZ3K u8c Vc)]l_!dc_6SDOew6.ft9h' Dفx<it:(s++R!Scv5hfFBR#;nZn4|7D nWZxp)̧|WB14pɅz4t/ujG!-n.=u" ]%4NU?-d! 3PlotDlg.pasPKt-6첛 *  65Output.pasPKt- I_ AMAIN.PASPKD*cS- 0`GotoLN.pasPK+Y-sYM aChildWin.pasPKJ-gHNhAxisPrptsDlg.pasPKG6>-'mAxisLmtsDlg.pasPK*B pAbout.pasPKPY-E= qNyqIDE.DPRPKft-vU rPlotWin.dfmPK[>-$+ PlotDlg.dfmPKjY-ѣ.  Output.dfmPK؞t-l". MAIN.dfmPKr*H}L GotoLN.dfmPKWY-( ChildWin.dfmPKV>-)AxisPrptsDlg.dfmPKV>-(0S.ԹAxisLmtsDlg.dfmPKZY-rj@ TAbout.dfmPK ft-O33  zPlotWin.ddpPK [>-O33 PlotDlg.ddpPK t-O33  2Output.ddpPK ؞t-O33 MAIN.ddpPK Z7-:k!! GotoLN.ddpPK -O33AxisLmtsDlg.ddpPK ZY-O33 ;About.ddpPKbhd- @/ PlotWin.dcuPKU[-C.L KPlotDlg.dcuPKt-?&d5+ Output.dcuPKt-Ŏ(fH; mMAIN.dcuPKbhd-%m MDGotoLN.dcuPKbhd-i]% 6LChildWin.dcuPKU[-4U_AxisPrptsDlg.dcuPKU[-#ڄ" nAxisLmtsDlg.dcuPKX-cb /60ySynHighlighterNyquist.pasPKU[-Q ZSynHighlighterNyquist.dcuPKX-߳ & 0SynHighlighterNyquist.msgPK<}Y-wMaf0.bmpPKt-G0 Tips.htmPK)t-}uyWOX NyqIDE_Plot.GIFPKGt-  oNyquistIDE.gifPK00 4nyquist-3.05/nyqide/doc/0002755000175000000620000000000011537433127014231 5ustar stevestaffnyquist-3.05/nyqide/doc/nyqide_plot.gif0000644000175000000620000005411710144436365017255 0ustar stevestaffGIF89a73f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f!,7S LO!UTMSBg-L *,6Q:6V3I*<Ë_ld* avZB Ŝ9r)bI)!NceF3ęqgϟ :qQzdzqSNWjtI̫Zatӫ*G2 (EH7XПTG˘3k̹ϠCMӨS'>QF 6|Q6ٿQV 7]7jˮl̅Wk^\6ї.8n؍Ӷ[7˓?N]{ϽK'^:qw x Gzɶm֛s'r1pWuvym `m7a|YH_rp p P3d9dFV43G.IM$5WVi3FIRB"YdJ:dX~饖_9L d]R9dYv&Kgw~ NReu~Gz(kcnDjf?~8#G#tJISK'jJ+8S&YDQGWaiQ\aLNMXTZ*kQ2ʗ ҰZdl]I)ˑJ n$k,FqPd*׽&lTE9EzDLboR JvUJ* tb*1_bU& ANGq%Ʌq lQ |SIuE3B6gLs/j|TW q-Q8\`E]nBwf*ΜQ_+ss9qӞظ]O%*v$0*\)8 "qRkd,3Cc(WRG[_|1t\~`I,*]ҙBT2 'i[AĪ4%nj_&$nt_ju%) N*VC.W,ȓ#|g(VʢX$A $CJRR I1SR%,|()H~?, MrB C?&ҋxeJ RO⟊DK[ ,x)*_pDe\Tc!,LN}ej9#OBBDcQj8hTXI'Qw ɚ( ㊴OğzF@DP GK(/ Gs}͜DBe` FR~r!Huy 4$Tc$Y0Mp^CUbi` p$).h TXn(pTIFj$V*$ & ܺVѮ|U)%`Gش&u}c3ٔP#d:IV2( R0L )˝n{N6Nm0&u\5*Cnk*IOC&)wY(? mu (fպWBSJMm.[,JS}oV_,H SWuF 䩖RT^j.!n%%="J6@:/eK$4GzLk&9j70,PXw $II6 e$'W RS$ U p^gl$׫v8TX! .5pn j`s`[*ɰ%.%[RŒ;W(R5gƂҴu=ZrUra@Wx!-e:N^"ǷG^ld쌶w{r*;n6;=i'X@?P`(xlzXvW/wsS$ogک_m3d()\ š~vdw5lں՗FTE.U#1l\17Ϟx)&d;936̉#q(kMeO)<95Ȩ$oX}H5 ~a}A΄g@\%Mdùpl]p=Wػayiwb ]7qݰZM8=,\Mg)i8o://tdjR5[G7*t}A 0H|[\ޕu[i&cbiQgz~*"x&2Qс r "hkBkTUCJ5ToR|L~ 7n6bp^RXh\(o6qW0r Rg(U p#VC&c~*O~|'I"HkuX!q[ @q¡"hT8Ց!B ob؉`ꘉ!8~ & N%gpE!Tp^-H͑aL>q#qT7uhnϨ 7U# !! bT 2ikP 5iwggpeP*WiH"1i+Y1Б1aH ,ِڀIf jɑGֱIk X{7~!FBɑX 9 EIz W˜flYIlb { k 5Y%Y$9%!9ap]@a7Yi!HɖǩYəoZkI!HyɚYTg ɠH7N{yjI) j%jѠJ1٢*fաN>Z"ڣ.j(Iʠʤ@:#zّz( OCYz-, NPڣI 9Z8ʖA ʤ/jq*!mTʧ ꦗMTl sjCqJt:)*Tzujm9uJCT:T Z+_zjzj#JK JI>: F.ʨs%Ȫ:xjTjIa$ Jͺz$*jJCɪZΚ:Z~p8~YQɛ߁z ɒ*RlћQj 2zۛ Y I!;7t:k˰.{03Kj#<[ 8[ҝYI7(W^KicT&ߥGqICDcmum<5^{%Jwcbcs[>u[`}kb⤷a·˶_ofHt?ec.M2=ې 0 P0 к[; [K@ۺ+{˺[~кKK@+뺣[ {+ۺ Kߋ;[䋻kۺۻ[⋾kk۾˛ ;[Ջ˽+K2 5 `Q"3.,2-L1*9q*,2(\5<-0\3A8Y)& 4,'\4H;G Q,=ld\XCj`h,¯|~ǀ z<#زq!1q lA >ŸnIQAȶnȏ: #JH رX! #%QʆܘHʑ" a˚<ɺ|Ŭʌ̏! .;z0uəQ!A "aa9j)|2!LG;m |-}MG"́!+Ix͛)B|Щx 1ϱ1= !R!B (qi *Q#hj!}٬hlx`͈\^]\c͖e gݏm  WMפׇ-gخ%IOˇT:ˆaԪැ ~KiЦq͆QˮϮlQ衵}7 !kG۬x q}٭ܖ-mȵԽ KYz9|9Q]ͽt9©"yݗ]➙8(h$B(سX R|!ny/Rx^#k$--^+1MnӒ:gIj~=7晜JV~]6"7 a(is{~tv5~en 鬎֩Ȉޏ1a= 1۲oX(Wq绞мt7n)hΚ͡6.Ԏ)֞߾&^⾇ܖ.Ϯ#X[>%{+Ϯ6"T횷̒.#GMn/Ƽ~ii_#W(/ʶ.._a~48<"U'ݬYߡ 8،ȐLz9ɾBrzЗc_qxOz iɒ KL#u=B {I flHzoro%2v? ~CL/- 9 mn#U"O- (qي-a7.#.l aȃ]ݑҍ!tϐ/nA 6jQ#/mU{oj jӆOU4hPc~_>t钩̎ҭJ6ny \xk\͏S u?Ζx&ޛ)+QO{=B.߮o.+gR,ΚHsۺsLSJ:ˬ߸bD,Jh j2Z.zI¨L,,7Z "~Fr NaoաTUV_Th)R\ ha51B\QkkZXSB#34*_9o |^k_MnVG~+9섊1'6ޢ0(ܖ--V0(w+*Ume_)f.f~qؠ_",3LMXX<8kQmJcbݺ yjlvm1K- ;-{of,p&\Fd#޻G_ և8LxA:A!x'xG>ygy矇>z駧CG*r[*29_jZ|ַ['鏁[sWA "LJjp!`><} B A <`C\$h4$D>Tv dL?ABGO}K8z! =X057@iq|_ 8q U(4ġC2q2l 88|E(Mc#!I0QH)WrAH @!D7)G~d!#L,᎒? ь?E9L-,,%LBr4hi"bY@;b>\f>ML1$pV՞|0"PE!QwΕDԇ=( *l 8(Gў mf$Z@{|dÏҚ|\Q*2.SlyGp]21@>b~j dT@j0$< @ RTp Kz|&kk[w"0J@qb5pTDTiLE!HrS"'! m#ׇuz H–O`i΀p3(NƂ2md$N)5& :㬽mk))(]>oMH>Fv*Kb.;y$3Y0jVUfZAyÚs@rZB2~էMwѺZ {Hd*r~ܥ3jkIF$1(_EJֳIXL^˳"= r!HQx`7|08Juݣ3ueNќ?e Rm1!\֬1Sa['jPOgFiOAa +Em<)0 R{;`;;z+P ƶf&I;~(-8OZaD9PԚqm.'F2uq'jTϚx$?dQ9Uf[AQhėhn/8lt5 Gm]\>77 g8ΠF#O XLc(#?%w3ujG=5>xXPo}9?yg0-xK|Qy{>.r<_]o{(}3U{e7 Wp~{_ΐWTC)/B~YM["< _ZE+h÷KFdjBK%R"Z;:}@:PsZj#v k?擻&hRzi-ɋP\,%#c_S 838qꩄ$rC~3 Fȸ3r6~y;-jg3@4'"CGl_!.63K,+#oS ͈%PPɋ@ҨWd6ğS5U{wӲ#-~$D"Y|;dTe&Bڵ 2,3gFȔ 9_ \0@\#5<" PT R %J*|x dGDh,C!BC*:Ii|/#S(2@dJA;.X뭄Ļ",, z0<:3d®Ѽ#2A(ֺ9A%Ó\)CR.hj`R1"G<-4")P"ϭ$w B B,MS)B4 BMHH3A1%QxΜZwk,BJ\R;<ÝZ3M) BjtL9HT k{. ,2"I`kq{;́,)Fj"n1%O9QNB$!㺸AD:bDB9d0 h31$Z8eQȇSH0,i.}1<K$T8;4j Ј`) ˍv<l|6΁\ߤ»4|KiC)4H SA[TdT@& #ڨ$9ܱ 0Ҫ Z;BJq\q `G9tL|@7 ķ,?,Kcڵa0{Ұ,TSh2$ʊ-HJ*Ym*Y*CiS,!<:/52S@G*Ŭ bYY^%m#ۆ1TOr.p艭/!N:eaqe!tRz⫕*β0TYe~ӄ!:R: DS2-brahNa B&nA-/ZWP&Vg^$<*OfQb*Π z0RL䇶 ^'Yum `='HL>q@F']Jɍx xB##m_LbjĦ \5*E,,bm2~PlrhA6Q]\)N &NYBz=6JPxdcH]>ZВcnԪF+oh_īNBUَd6:ٟ%̈́q6,lw:VnF C UĈZ lwE/yB>[ebQ`3R'`$_8<^o|;)_N-V8\J8FخZaҼ$ ]2 ڈ4!1҆ j[Dw~HQ* 1Zˢr^j.ӓ+Xp W3H m`m /0#łj)ӆ5|çMKmhnǒZ3Qsyqg5 k|J?Zh1>+^D+,KgVFf z *\AS}V5/T76d\e).8mWh[l #U9i4涠ۨVfϔ6yl:{AiÇ"Sr oꜬ@ U$W֭M[rŒ*tJEe)5ES;oi))ٝcjl.^կY]Z$i |-v#w!II, v瓞Y+G`YtRp"m6喩N ӣ@Rm ᷢ Aw̝U7iY*+u~}ūuuWh$Ihpb+lYU}P8U?>()>>Vo' 푥6f=)cc+װr_ 5 ? E{uq{:zld=hPx9hk'|9{Zy茡":QLHPCԉ-?Q,ن_#UBH BЁ S 6l? gx"`)a K,Kdle2IXdBAL`kAg4BKBD1=l0sU!X\lQHb? RKܶD%0n|#(DzBVr4=h xV9$'V&φd-cçHf; s I!#I7u(5E?s>yTPd0bU]ҍlR*YKfEL"t(ь(`e9fz. .T6֔hP̀ʢb. QtJA#@Bh\'@uYGҠIrGbmp&.C}͉z"& đ͜&ʴe,AҷP(P@3Lpғ@m 1q Qh9/Q53Y (RZ8Oy#)=C,X :0kq ~\^S*e:LJS)guej?, wXf]QX:&FcO=Hb6Tg2`,:\Z09l N̦]n89hL!T 5V?4SśJcז7EZ+J>,=& M|h9@$l#*?lcsKs3ݩ̍eʢ72hC~"Ocͬyj9}Y:iN65P|Օ(m=4>:kPaKWd݅eϢRʚ,F2m1p؂2!}asy2E3"u8T`,9_3?X.g eq$ӣ O]l%&y#4J6.9L/:_s\/ a1:3W";Cbҍh uk*ܿvg.wD6Ԫ/ݧPScE9NNze(jWHTؑT\=V3+ı TP_lJ]$EU$TuBL^}ʬD9OڅMYOMNČL+LlEŗ]:qX*4z5`Љ$G´OT&hG4KQEDw,وpuQ^Pѝ "o4p!?E*RW**U-Ldʜ}8GTK9 ې`TV $ɖW%τROp`i ZrLEc3.e=*3 ]4 5CMcm#YP5PQ644#;r8P6z=#=965Aܠk LAޥDo8 %wqr4ǡ4c36FvG~$$!l3JMiK`͝`a Eq$HNO$PNơlH4C\= ԄeJ0ػƆmGs*83LCW‚*43Xn%,L*+x3,X[%5%,4Xޥ3e^[eYfdPaf*@SE9=m_9NYmPd$5]%5[,N"Y¥[W&W%WҦW&m&5fjap*qO:VMh \UmL-˗PQ_i%Y[&jn[W~goo&Y~e]p֧}BP@ډNP5E1IHĆ UXFmv%Who:Cf{ w'yRkW2}[hM %b a=`HeJ`Z̄=ReeA&i3[6 e{&m$kNjfPqez9 )eMÚx+EP\NZ`Z!& `HE`$($v% |'ڦWngjbhefz&abXmjfMC͆NsZ+iD$XL<Y楺%{擒2iPe% 屺V{jXnrhM൚q}j3FYNAlҸ\N eQS|ܬQrn'4.i>&kzB%^k._> v*jDE^ LSNDfnKL@0&Fjzl[BiPAi|gj6*Wj؄g mIk۷v,3R:?ȡOP^]&efbJf,РN!xjigR{*$>+y(\Zj{n#F#bژZ*.j-RE$V-nQM(j 4EdžlgƧz.&Bi.-ffi%&g"i^meiN>R9J`ٝa)))%A1L0bA%ϲ&Ϛ'F)kojf{~n'|f1n"/ J?Ea]Y+=TNaƞċLJܔK I6Qxfnnj&^{Zg2:pGrfITpqpioΰŨ`]^hmf`ή^'wz%0C(f5,΢mPPO_%rF?pĭZbjk n%ziq_2q,PH]1Nof@>[1ɭf6j*zx~)Rx%c21?(LIৡRm ;"̭V*Fpw:j_%68+Bjsmn`2;Gji%\e8h1F_\p-LA_=xu+0fD3E*X6s]L$CN|L KX5L4V4L;冯OX"ˡ:- NĻX@tP_L7?}lEQ"K|tяKV/.ZőP+S+ f:9auN JJ$q[HC}hlp3DgԦuI#((-`=,yDR[X-`h2]4zoIӈѧٝ=ClOE6d*b"7bF&_"U 0u[js$]Ac&dƶeQƞ>MNR)F\$60t?9sC/uG-Ol87ŲvAus^qtNy3 5؃mGQ[eh늙}S,~w ow/wSGuo.J]PH*2eNYiHU{`$x0 ƛ 8t7o tx$N iLG(L* Pԋ)yDsAeRE8Ǟ)DybCn9[9 M=;ߌs p $i:BN"zrQRs@Ect8rW+slG31иj+!qr Y0oq뜁o&_4foeX z5wvz " D"X1 PR+ `Z2dlH(?U{_4VA:!G `p 6|Y~5r廣^^7M`4=1AL-fffqe: A$=)(*!( D?B?!`O?C?>P627f7ʣ6cM;6Jc3cc;b@JJ`B8-T lFm[>~_5jiWMW>m![nm$LڴIe5'tMC1m+A٫W^zeP T~U̡**RhMLb*fmUT >lo_ɴPFL) J}T @<*قR+L@-MrmT|Q9鬳T if?lIFRm$$5zL.aM2\a5+-@LO뿦N;aUTAE!G0%X4^G;3 { i<*7jSN=V=Q+U0'?%QWfMWuzWP3Tc4%L3,L_׈<2pz}q#(m%S|⽴\˳PJ-m 5du"Ek̏>+ >|0#Lh*eUJB3.O3~j.孹.F.hWP&f tגB`R44}=GZUmZReI*XVYMumGZ1J>ukȜUG[Gu"%/ &=0qRa 1&KrTptZoiSqP(~]Doxo^)KeDi^$΀2OB=5$ըqTh]e*SM]!m,bp1m96<;)p]{^<10Ecgd8IgwCd8f~+,"kaRXHaiq `4D/:*B0s(":C)8'%Rˈ΋ `8WBF+" F3sO,CT ~c84-\UaĘvP1E-юT'7Aj-l 9+T #aG0CuD0)U}\4q *"%)}} C^Mk\d_*MGVRҴٕIgFVN3!gF ANNn@ BjbE*c&dk'~fЬCGMIN biMzR^ cfWYĚ-|+M"m@I_ߨjaW P"{\I,VԎ5)JDYERE sshEEKZRރ') 93U@ᘴ&iLy 86 ZMuUo*JszNHU:QE!E R<"w˕)Dpzd^8yxa&?Mn{ 911g3*D,Pt,DCk 88E%s; O≖r+$)^Jc1OhB#E~O.S*Ţ4F\FCf1Z8SsB3NbrށB VKZ#)QGɯh_^}k_M1s6vݹ;tNΣmB*X JM5^`9 %[bK*oRbm޴d66uV%)R>״H;]YS4xH :J(8W1ve.HYTm]*K~kap& pꚨO.*kB3^,gLGT=%(:l\hejаF2f"/p*)z"ypB)1jnl m#=ЌجrD|Monnp"wU>Fv| %J)/ptP1rD#RRd|%lhILdu> I(&hʺ"ဧtN$: Kj ><()&:m&BW~F#'@N#'n4R'&彾MFdO^u퐰>&/oz A'=H TT@Z89yTfxj>k"22Fg&L{ yxsr'%mV~OxW\t#te 9B%sP%j&؃?Jb3 gXM.̧2&ʔvĎ:~n\].fd{'fvsPhKr7ч$iˏ`hɬxSjF p;U;S!qD5\Yt4OAsLW$SZspl'UczI[4Gg{ ]~$(Y o>ȫ&>N5s)?c 5czݜTHC3ƻ|~& &UhFU}0jh[ć^4@z*/"!B! ⧇Z"- b!*|Z!§,"§Zڧbf"lrAmnYY/#4'vVy*#L*16jopJHQg(A*D\B$u4SK'eP8%ۇ?̄B_EhxL f<# $'E_PdbS2\K3fD Ƹ#nfͲG]ꤏ23/A9(_4nz*;[bNN d[q6b դIA IJ 0O}Ԯ3@$%ܫߊy)pAja"CGrD#ICfpfGŎ{ٛ4URN)cf:u,$)KvN3 BZhDUkz]%N;Co$/Y,2>K1c~*KyMʲxMM%DNĊbu!$3>Nd l2T|@?\?q*w%3}gVc)ZccP | }PTcctΨ~ 2'\-i"߿36:7sJY2*H:Q!Ȁ;nyquist-3.05/nyqide/doc/nyquistide.gif0000644000175000000620000014262710144436365017130 0ustar stevestaffGIF89a3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f!,G0!ƒtPB BFxH;>$IȊ*7dYeʐO\lj;YScM7]Ds$ML$jTԛW{Ċš/rX͈J2jZ1;=TuUyP.}˕֧80ٮ Yj˷ơK{&z4gԭCgu΢9';7i͵Ms>vnܦWMZ8jYs<6nڶ_[Y.>y3/aO^nǾm}ԋ_{U_7rϣ7!{HE0Z;M#`W- M:pyla?P|0(@DA(H)8FoZ(}퀼kٚqoe[ǵ~ u/ڪ(:a\ܢ8тqƵ5jЍ]B+1r#50qo.\ ׆}t"9Va$Embd74m(IG=2x$X>ƒ3#' 8ry)CT3te1a?d0}d[3qF]N-l$*Iary<& 5Zzҙ95^jxd%%fn-h7s~&;W΁Z>6эzt| 6rOj_F yNjS!GCj 5옻5rtƓTn+ZKWLՓWiBS=n$O!T ur3S4~0}Lҩ:[հQD +ڪҲM4ޔQVVۧu%-^JV6.utSXiU֮$+.Hٳ,giVm,PQUNv+lӺY֦hS`]mZTb2gظ2js#W}ҏWv0; g6-[q<"x,5j.%p++ڴeZ^ E5TL5p2P&kDG_ ߗt&\ ] K1k< œۊ%=&ja1x!܈ӫ`78l$tl؞(crǭ챕diKc1{a8ݙfLym׶g$cޘ? KbQ/6y3< Do w:PGCQSu*06KV-][/ jWm~M_R^mbk^Z[iVlmeԲ'zPn3뒊*ۊE#+oVƯmdLN;ֵ}`m˻aqwVφTcnjij.xp.w>pƛep2/U>rߕ5ʭwzAp}8W7s۞ˇ.$Gu>ԔŽ:gLثVR}_ a)@A) " ^q'Qcc P@3.4Pǻx_&DiM Yg@ m= RP~ᅟqw;[ʦp \ʏ^;8wOc-.&bc,5l*MyCQ׼3PsY{wQ?<>dz|\ߝ r~w5x({WmyW|#FB}7)7,{~gSYp 8fx`g|€~ {JUph_7)X=x-} 8'FnGxg~8A~/=~ D R ` ^kR.V(g*g**W{ _`/͂|J8~yx.41{{~M@(׆wr"~Ŷ`’-&yR(Lj) *zz3 Yhb"|ny" C }XU(v'mkrSXzx.&S+WBzv膤2b|׊_8saR+-C(+xƆ؍]̘d&wψXsǍ8pu8* ,먆wH(iϨ9` (kI PQ(wcx('2lLz8|ǂ|L:x@y` ӑz1 }}R+A ++u--(c.Xه*W|{Ǖabb1C-G,(ihG2~R8=Y)bBSxx0xgɓⓏ-+|I`C08+p!y*94)Ik9v.)`EC@/dsRy2YxIh+͙*)uY"+Q o'H^ր|4gyMЇxchz9و|R`}W(GŲfiʉ* J,g؋|K)"7( x&x{zw)]9gΧ|(և))vW&‹yKxwI ڢS|"ʷFJ(j(GyWy( 򉼷Ju{yx-{^ |+1I.Ԡ()/"e霱R*gY*3H-(™y-ɩ驌ڝ)Hb'%Ӫ;c:*ꚗZ/YI s )Yh /3:(7~[xx} W"z ) X*"| x{*x()=A|Jxoez簬';Rfyx* y7*ஃG(۱R*L0);~9sɰ27z隱zX^ډgzF{),3 ɬ ->(k۰"h/ӶʶY*cۀng.04+Iyՠ yP闾] * } --i( 򊠷.Ӑ ]쟈p2W쌇ƾ{0۝qNzy'鄸{mN޵[yN2yo&O (/!^ .26?8:O>ԷPMD'H-N3/~9o^뱞E*g_ /?O5TvZ?r,_FEQ| M}ꝁNdx,ڊXQi0يُ 7xRT8OT_~ڞWp_]ĭ&ʤ[yۼx;`JSixy@eF |xx_y G @y()Ami j(\Tc6(^0&P rLA@Ψ5AQ CqEJ,S(0_ h_DiXaȌ(b/jno?m! |dRǰ+Yھ֌Ug]c AVm\Wn6,`~Ֆ-Xrī`g7&qYR qRXUQk.^ov^Ե iY\iG̶qjCm@o=s TyP5qۣj&6øz8)0vA g.nǎֹlK:B"o.1plˮhnS0ç݆\oީ-G!m޻s?|&:DnUiuanl\ot'=xf|YLqOr.Ƕf}C=1:iǽw>٧׬':o~mv4Vw0 Apo¯pVE}va@X6ɝЄ4]Ns  'B($q&DC!QLa e'a>vxjJ bHB2&:Ġ3J%!E0zqw@8Fqs2D 5ч<$Z-ֳiɁB )G64g%?GQ|ShJA"{&j0<)BВӡ7i=)*όTGFaYS~T:ӓ:hqƃґRT/EjFT6太Vk%h!Y:ԯr,%GoYМ4[ԁpm-cXJXU}"[{xUEzW6֦}_I X ֲgA5kW2k&jle;[ֶmnu[ַnp;\׸Enr\6׹υnt;!eI˂~F=۹vXY:aq[2جMJuȂhFknW &-x;#-%zb9o`ꋕbwnQkꋁ`() bߵH11i~/zWDƋ+x.Չwp-+֊6osr̕W$zQ3Io-dh8 |'8MVa0SXL֯kK9\7oE0Ș2<^@ljq,gDˋsǜ2G:tٌiAI#%ARu1DױΪ#ţ[؇zP|lZJ/`-kZIMuy]_'[czh}l%y{ٺ67N[M>mf=x[Yw r{D5smz7kkN]Q[}mkhc\w;'&9m}޸Al]>o:v'Nn{&g˛ ׹ɣ.qc[Vo6֍/!w;؟((^B!.?{/?>Hďw<*?yS/.W޺׼;Q~kw᳾'Ooyw'||o}ww|_>>W~嫼s>[?S<ۋ?ރ>K?=#=D=?{[@=@<@@<@ AԻk[A |K4At?,ADA tQ , @%=&>|>߻< Ic7!Ai P D̸ȊD ؠ( 昚75Đ)8 :d;CC H A @@DG\[iD4|CID:<̮]э ? @āC.STCT7lV9yJtKZ?EQ4`EF6tULDQFJ< KCZ[D]P,DR F4-2`3\ә)]]!ʹ`5h@-] \Pݜ0^Tx]˝]-),Н޵^l^^]ގm^ʡ^T^ו_̵՜ܤGEu_`].XI^=Lۅ_ҍe`%` _EU`aU_45v]]aV{VZ:ʟp=a|lٴ@_.IzTR צ 0I 8ަEX,l0̰zEr 5;5).2*+ݎac |%2YHcYB 71Ȉ*fW@I/>垝eN.dĸ&E&e^>GN;.WecWήbdEf4^fQFeiejfkd01M&dp^Cffcr0hޓ cIN afbnyzf|6h_ɥ-ҩ:V-S3/.\;0$}]G.f`!h3 Ѡ eee7:~e DW%VO0ijf F DN]jꞎC8.j k1fŨiC ƈ뭦>i6 ni峆jl8쎶 bki"k~봦id~k ]ivU5kVmخm|=I̶ߦE6RPXxVNiXbɈԟ\*!؋-X'I]ϭ" d@>^ o -^Aoэ vcv@&B >ĊI67oNfN,pa9S j1A&`̅qݕWGqM1`O_oO!"wK G1%V'q)ir,g-#r 91r4 ?78,s%QKOŃU_ L1ⶃA*hZdž$! 1sfdj-blG%E,0JX0GH B ?DHIRſzQ{ŠQpJ E>3D)LըUCEsV9V(Š Q4Hz0hň1C`bn?|WLfmu'XE PQTdZq# ;ɹSB>('O a ^;m=Va獇kDeTZ}5kw^}RO b$YM8TaxSaVA$g" }.#w2nGw8^?g]IU].韍6 Rzg]۵Ԣ}_ga`3]9D"3LsX^~gGԑtg!6@izLC'UC bლle'~R$[x dyDTCVb蝪i~jb:f{"өDMaZTL[CV-{zđ~l ngqv{)T ӿ抚Pj4oY(/IJQʭ6~K깣.Q+Kt{/,)|K H!P~\n@M`< 0;`@ NMȿƥ͓^ ‡Y/^ |mn|9H&rޅty"?Sj%"JL42 !e*.+v&b>8/j fF$BF܈l`H-BHEAQ#"XS1#G=6~!WƩMb(%2J8Nё*'Jl9Nr((^Α]*>Qd- JhR) Ll |1e3A\aI8u$inR=F}Ք5Nbw)F$k$7qʵҐD#-M? b$E+*>2QGRA'JLC=we$-KoӊIj 91.<)LJ>EUKeS[ɴL5}Xp:UZ "HLաFGPh̦TV\ZPJTi]L:IFbk%M֞f'* '5S5Vٜbvj\Xt-c׭5-`Zzv+cjZFeڶĹ9q -%4[`np*$i*qڐ#>٦RdE齯?;I)}{(;ޮ F  Q1)ה2a˜oۻa79z`# h;\ރؘ8NG`W. 2 \d73Y2 gSɉbfY/p'9c07"v+_C2x_[y2/>,^2%Fs9\F|h&'DITF3]2+"ҫ‚AuXU٬z[˗_uKݞ6 .oZe^n[ⷦx}^c;@vIf씀<Hmfyz{]r#Tn rÜ2GfA2"F6",E]iR>*RvC'"vF;A{g=:o'bk[#4F4N#5V5^#6f6n#7v7~#88#99#::#;;#<<2*̣7@L <=d^‰X x݊EBNyD!߈t?Jee!EutCZJDDR]MFFVQ8MˊQJJ2J"YXQ̤$ݤUGdvF,DPdAJaK"DRZdSMr$`QTU"VjVW6$KKLaEMST$[U"I2\VeQ~e1%X$Y_j$`z`$aa~b?b%X%E2dfNTZ^fUf&P^*V*W6l)%deYe~`[PfmeceLe*Xo"Pj2@*"5B*v‚v~*wn+|yxgyjxB3lzgzj{wg*'x'w~wxz'zhg}灚(~'§gw瀒'Zv>v({':(}b(槇~n}Bg}}^6(irƨ.~b(鈞|(?C*|mAvtV Yq˕%ݗ!xsOY`D3Dv agFC^\@s$ e ?hC3A(hjnjjj|!!d*f**|*ꧦz(jjBҪrjA"+fvR뭂*V*j"kjZ~RkjV*kRkr*z겞+Nkkjzfk+&kB뷶«&k:J,,kj?cAsXaxMX9v#TH&XJJ6<ށH@`E:wus `U-UTіNTzAH-BRς|B5c~pIvHF٭4$*.&#.cE|f3\m5-ASH-1LEbJ5[n ^F PG*`JaäNt]LޗV `[QrIeϟ.d^ d@ln*C*Jt]4f./:2ѨلQIH]l×Ĩ$z]VKR4py]Qra~ jD^Wt]h*)Bv^%dIDH$0✥'Jj*P^ASn~&> /11MFNޭ wQCl_>朆킄WeuHcxVL5߭C LUHǦ G@܆>jYEVGTPDc15TjLUɦ6mpg&o2'w8ʱnEFJv)p#_ANR)IM\ANb 3L310ͩ a/ırfӖGL*DZR} EH0G[R`d ,/FSfGDbFYTv+'>3?3NEB)?LRo1.L^prD?2$ u0 ZȐ CEaPF)Q'̄[[j~D:ROtVD"0Lu4\6 *s?gVo5Wm/)|q/t>8mq=EȁmumIZ2l2LrGVO<OT5%wU3m\ ϭHCeV LLH׉GBJF\u3~XQtBpN t5m׶mv9lP/S"EyfoN.Oy+ ?CWu653/cnU T GtgQcpEH7eTEĠ7F-P;OF W䀝.`83>[*nGO83cFDMáPD.zK3z˛D.rC^=ss߅QwvJ0d'De.)`|SmlԾ8FdmleЬ_x#eyu6UOMc z|B$\0Lb>z9<0ߐFYJo`q{c+W,w49yWU/>#2VYޚEaf;O=(ĻS>=@p7/oIl Y12拗H|fd'P7edS{_KD(C 92m4fd>ߓC%7C}UW[uO|o㗿72\m)`/7Il~ik@7=@$PmQ6mC  Q"C|ښ- 5|51!5'Up4qF&cng1& gѣ?m -Edj:B(ŋVkEOd3_mV %VO|U^7paÇ'VqcǏ!G4I0+6Ȭ ' S!8Q *UB/>:.og2LiV»r E/b$ʓ m7hC2iMB mpϷT,2F ]`oq1b?#VYaVi1#TvSVԮꡨLbs%.4|$na=$DB4mM>5э{ݷ>Qa(!5{o% ʛ6*TRxڅImMZ3^e\6Gjg03硉.Th2fDr5Y(jkDTD4-A$3 3"(F%{dɟ蒘'# arv F Tz2$HΒ:L@ ;W@JOrJIR2ۘ'l\{NЕƒh;wx.GL94BBA!R35hnQά&{7hM'μD'IpRv2s!܂^IzRs/ͣ؉2 c IƲُ|Fb /B*;ZLT>LEӛz<V-Ta}H,34L@$F\.AK蛹y._4)mJr{1'}(0q Dtu6.7}*\2(t!A Ԅmƪ|ZD*夬}V+p"# -^:7m&I!vџԦ>})LMӝBj'k Mv=eLK+ɓjYmiM S3rsD0˕0S"̀t fۅw ^Jw}v+b׺اľc~ XW)=iLIzcmÒ'}׹KFJJDAa 0J"[Uq$Gc+[򖶳 n} \يW{J731yjIE~Lr:C0UAd\g֥#dJTm*N+<lj_8&ۄL%W[0.GvD%A.qj_׎t1 OhJ*-Sc A)Aj iR:/Nzk)Mbt'OS _ۘ3Yz$yqؐhkR֚RS#yjsX;Q8QvJj>P5qk 8fIkr_o4g}tm耳Vq+c*>ohJGPC1IP ?y#Wa6'\?#B:gMyy40|&*"?L%~\jjh3눓5T5;|._zLHXLСi!H2ta߽qMtC{Ɇk?bfAߦHƴ`tKUOE4JRP[9nTS&:jmΈ6zq=`hkLL`;ޕOv##n?k`h=&^&4~SDR4;Y~Ofm}^:)uk#í.E,cɾi&j:(fJBR(jDprHl*G!ǃ=J&Le WJLKp1q&-bx!$q+`b ¦s bP))QQ@-b0*DdcF DFPEa55VrMBVbPmVqd t֥GEaH'!-b%_o,p!Ra2&er&WnIxEKHD'ڂS%1P` -B:FaQ@R %!ױRtc+Ez #hOȅ שPol).c$c^šel_ (BIJ'@( +%Bt()¨D(i2-21;C,p4vK#^Ma(C,Rmx/'đ A#"ٱ7/q|*R]*$''nHs+-*a'DJ}"*hBc&/2J4K bj0DfWd(%>j fOdi|4" !$+A70ꄩF Q[D2FL4)E*Т¦^.U {@@)E̴+DضL\-NS*{RJ6MK5Xuxhyb'Ra6r.b(+ 5@dVPB%;JLC=<]Q5}GI,)UpBU TLl")]ycF{^+L@f!$+m%W!NlXEvdI6Z3/,4 _M."&P(ږ5r[V+_*\fOkZ@** 6D++/^ VRfTJ+>kQE7;:bl*C$!:l%'d7p3JMT0*WT-Xte(FZjvg*o]+\kOM Tj]ghj.Q&$ V;|t<ILR*B+1Ɠu_qCS}L%w{1 SvJT!yep7|21-0^lQ7_if,<$QFPs]WSd? |~cPAu Z`QA qZVr()I~D+>FO dS\5]CFt}1HS(d\rBUΦovR4%78Gcdj'b1[M¨AZ{uQr*Vs05*p;Bb1 =BjV* yrd㘤9v-/M>>^&C2OBxaÇK$"vkIbQf=%sMBTB{Adt D6D|tb(_ (Q.Vi)F~Bb%ოl,t+O)\FɶDOB@[\8*B*FOOS"SR%@/j-+6)b+2.b6n9w%t"HrSBZKk5A߮jĢt"+|`G&Ta:e{#TTʾ ڈ* 1WOa$QX^hEKڋ$PA|Aa\_a 6H%em,d B(((ȷQz8MࢰiU2TAJg;ȤIL1ÚwMz.S.04[£y5AB7Fh4Ć.5%7;2-BNKÅ7(9kġ4-~u˅hHiJZ4oxpS%lۨ6F.~Ⓗ9X pnC&o-|QHcR]GFꋤ㺧i®O5#f́R=S]\MV~OkhVZMJF%#o42j({zC!QFk^^@bH̯/UJ;z!Qpw8v>EI-?R9KƋZ TjƫZ?ΫjkkY_?F=e'iHJ,9=ڍ hr~_8pO_0CdG3G= K_Dٿ <0… :|80տ|iSEq[5jij壦6j˗o[jDZ>m>̹3(5+QIqcNwY-Q;e>mc*HDqSc#Zmc{1ܹtڽ7޽| 8xqL|NVHl[R 4r,T,Zq3 XXQ[4ƈig+ Y%&2 Ö9n qgaLG1>C}9 &l1tHmx%XL{d>KQrfJG퓰3/iːh򏜔5_ΐD%)q.rF1vьȖ5 5,c (E/j%M'E1 R,6)$GCz%'3\$I BdJFeud ZE5B",i JE%D% Ouш m3+A$4#iKmf"$Y=x*-\.+w~4lj332ܪX*BFѴ 5 ~k$++ D%D-UVb`FB Df#$Ԥaz^0J]ax7QrR$e7fjFpUFg6,^V$ 2T48|46Yg,[Mmd4knS<2sĉ\]֑?we9tE34jk?-;g7rLϣӡ'\3"JS"Yz)=9Ch'Y/+%/u?F_"NZĐ*6I\2 v/I6 x1VG ~W6@V&d_0,a:qUup,wm7T5+x9Korg ,nX*DV87SppyY!Rx4X5HiysswL6!Si_7t\es XIvF\K6Ht3WVfumIpLeJ]tdp%Jt&fft8GXud8Z]Jw!́30X9!b dV ёE :"1;S(Fj&BL(.x7hLMMdYj"*z*byZ9T:&8(u]& ɑv'ڪjwٺۊ݊.*Jj HzV9y_ERbzFpr6E ɖ}rQrlp$QGC}9QP|+|b &Qao)bT-v?as7/"ISHU?0p3{@nR; 2K) "m'H*d mQ>P=*"T=W2#A}֑PZVal])gBC eL`YGD1ٗگLqYՊwۂ3 ƈk(ύ{aڼZ_]ň ڪ ,ۯJ\jڶ $ FJ͑ E_7q;}G`NAɆ @0 P OJ8#9=ߨ PF<2 u3#1 `"$ᣋLI1%B:Q\|%) *q^4!l#ؒ)/T,!"68VH=4I^ٞ Ϝ=USO W^n\M6[~Kn^lk !wq!ټey;<*^^`=-8R`3c'u"m~*@ oCn/˵UbؚmwM>^!8X:4)/By3nEHOPmLM L>A#=&(%Q.$凾g %qs\V^瞋Mځڌ ~ ^^.g.ڬ (ﲍ  m腂2BP? P߇1`Ad1))AG"+uC~, +/7E&ȌCa:FJf֤a% ɨ[G8}`#"y'q4P )GCQrtN-8ڃaTn}Oíoڙ x+mȍf^Ǡ/y *QMA&1- RT;&rN$88BX㺑@V -9S`DBV?N&^RҌ/1ү"f=C5$4Uc,Ԫiۦ-A|US/|iS_fRiTqcFU囖jI5T,TTMo[B7 ķ۪͟=8aMm=mۖfDm@6]:ԦӠ6GS+C>y\Zӟ<4gС#+|PW&ڬBvZؿȢ=4ڝn %:уw數*嫓0}}-Op+U4^ x+ᯇm&^lZב{:r]Kqw*. vx? yl W -tDZ퟿TPRsp`_Ū j"z'Ai,) csO.1?RǠL CYr$3<S)_R)%_蕌`1I\LEdp$>y '.韛)3k‡Lr*6#J̺DZ)*Bɧ6[.̨!sʹsM ΃Ԝ:LNBs3t;B5]LڔJ'S0S1;Ӵ@+0rP0SF]UVIѢK]STS5w?ETB,VLE=SوuY-iuڧ 4REUMH}V][1ŕIFoZ$*j樛0tֈ3|tBהyrv2 ]fDkԦdth.z҃4gC[ls%9.)&RU;zFHK:ӷs=eHkהMkVӦv}0&LgC:3@7M DMNhW9Ϭuk Mۥ;iw8iqk&B uG }oz~ߞ/>_g/;Հ9V*NP JIJ9LT ja VY l! 4 t+IA, !@,<+A B)$jsx) P 8B@ @lq Bd D܊ ,|DI$JC CLOQD3GUXD7Ďģ2DL\^\DiDƹ`EDd|9e\kFEhEEFTtDT HByLQ@?G~G$GH,HlS ȃ?|4HH1:QչĖ y Ȓρɹ #xtH%BYIzI@ a*d I,4I@F:;Jk\ʙlؑJRIJʢ ,˶ɳ4˧,HlKܜ ʓtH  ÏQx?G}HL͔(('I&99"A≧%8'v7l3?+MrR_DK&qMkl]̑D%bMߌfMeMp*9NԴ<+(l|l4 N23M21{GBhʜ͌OO O>|9DGzLYWMbu*^،5Y&^ חٟXebmXa- >u'Yyc)R qE-c )cĜQ A *C%eA G8 a*J%,˱ %d:Hd$FGNea VƭJ~宁DM BePQRN_Fef )kV tʥo:Ms#(t&:MpҧH՝4knf~oгnk~݋p/W(C?fm/qq{4q_qt ;6kqq+ҸhA_rGq&r(p9uːETHTr/mxOGGEs%247567ssvzSxO tG>_x/xwyxtϛa쁅+rGHxj|'uwggwj/vv}ooyugw8=GOu}/tXjh ܕǥí|pO7_vK9owvYx;Wzyigo{wwQ+gF,,Wwcl3W}%k.|yw{{{gwyW/}a 5x$Pɧ/kZ]S@k{Ӈ}׏{}}zuwgvwG7g'mzqqA (8 :|Q!D,Ҙ/cÍf<( Ƈ~ؒcČi1aȑ }xĝ ]sϦNB*u*URV^j-Uӭb%شn~z[hmm^t ];xna+fLnWU/cάy3gQM?m/4mudϒBGNd1"ouMpL=S9C'[}}tб?i]f?=/R3_~?7Z5? 5LU{ !]r1RtQ@aI1]E$bv]T)p bo2T !;y^awgYY#^A2٤6Z5 Om ?wۇ}8yT17tlƈf+&PMdMՠ"2gZFM5%H62AbIp(݆'*JyxIm‰kt("2iQi?2+IS͔pGzETQ4RP4[()NYҼMKQ8$Ӯ 7h:W`Qؒ[\UɷdHNeD.mRa\$ܰT)8 5:O4ڤB63-hMXhauĄQ92\sV5SLcZ#v`3oӐ}u] uSxg")5f]x.m8լ7dserX]}ms\[Ƿ^g }+N6ϳ.gA(abh|[=iy&u1\_/ߗ~IO5[詇[`ݖgZ[?ן|}K{{TkY0Mb#+׼7:rtr*]Mkݛ6/}T#[f>3[0>ڥv)` Fq41B4l:pd hB"}On;Is^}-|VX&½d +)4yhbW;Mh̀?:e(`:,"䋡DZjU,nВn U7> &p4$(I5u_Ci%-BА\'>'No%\8]j<(hIѱ/etGeraj(a? \g 1McU_A?j2b)!"XI4s ΏދIY̟4 к [8qH;٭Rd'IK4 TTH7uATi`,LΣCF*F1H5̺HA|Yl`Ŭp۴т6FPUDb,N ROeG]G5/8D_1Wth\ SWP%,؎%ubSٕ#ez.na2K50ޕ&5g򤵜=WkZqD]Jw6fN_);Мhv2t#SxF$m*tdi3:U&6!gYPQKۀiv) ڥW66(YĵK%ji;k }k`A.*|/+$d߽w(U}9Z XnT$rԅSL䊁mT;4S+c)DˌL8l<[Lڟ%Y q ^د55ȼ2g4- '0~9PyQ~d GVF2+ZIhG#ѕ-ޜ KPjZq}1#)0ٌFm򺓝skl.DC><{hR3GJ 5uW{~"HEV3tOSzL2xtk3&w/{`CFގ!X5.hE(~5&>'L$;3C!+IIzn"3>͋zfw MfWm%ARCB<^9qu{omn#os/6)렛LAKR)@~"G7;#w?A@ O?_r)A?_A`z9T\xWyYwQEԓ M_AFΩeߣBp! _A(S\S`Re?D`\`9)abFDR`P ~ 7a"ّ`QN>, "! "b"*"A8a9_NH_BbN!%n"'R)&B!e^"J+J) +D_ BA")D`:E$.abT&#,b), ӑ Ma˵S(\N !!b= !>6%1c)_:!f! `C`0D/D!?bBfA:`FZ#IޢT Ol@Vd%~d5*KD$;͡E[$P6ڢQjRmZu =q5ASS4\H\=##H!Z&bfE )42 2&+Bj"H>V#_jdHJJb0a4H8/'cSD$6b$3 &_6E$FI5&Ap0K)y2 @aS1۬P.ƽĜVR넓NE- Y?>*'[ef #LL&G& NC* 2H@FdLu4eMBcF"t:d%>AG.yF'9%RR]SlnN]mNjSSR%͜#@6Zg?zf teIJbgI2\uBtgff`hyҨg U0A)N¨:2>BJ'j'yB)n ]#Ea4[5hvZyͮ5NHדN`!~"r."֩?0ugE1b^2FRJb'GbtZd^jF_B_("_Fd$ 6]Rbrd}ara]*fF佗ӡ镎i&-] Z1[ީmZMvhZaRtqiXa*N|BF21Tu-ԟѝQiωT)f+R(NȣHJsS4!6IȾ< ]Nli%x46 Ϣ5 =H O2- iq89,N3Nb-t6fmФH Teעmg^i +ȘY 'ݲW>, gO]Kn{d7ơ7BZv.f:ZݡGFX(N1  ,榌`:ޭ嶡i\8}lAnbOV%jѲRNk%ZTN%]o>F=Yl +*mTf@ƚbBeL*/f/'(*, ᓲuj雕y\#Pn:+Mֹ>[.㹚2 k< 70F߿zQu)+OJ҃ak*.MJD7=\\t(?"G$#0>`&.-r!qV6`W!''bd*BwqE1J%i3EBg_J:q"OZr?i\Q/ )Y+OfBh2QU^q#[srhr+pyJ'.Bگ,gV>3eoqrߪ*`n30Fhs:i 32ʤ68C(it(/kJpO$j/h:)FO5*/Y1g41+玎`$zg2hVj*3(KgI `dt楩6%FsuLn$*H¤OP#~diVo 1u!8+B.LTUyqn(צF/[|aOfy_RHgf27O^Ӵ5bs'K'2^Gf&2~fMS'Ur/ZXl;UaN,A,z&UBf6 6{wpCgןfS1)_#nuuijȅϞLI{ k׺V3x/w('[p ҴfuiWk.qK蚒mc[:s^55QVS5uUܛGE >hc˦>)30*@BU<+(,_0#e.F7Òz5$jg elr/o!keTg~y6k^f>8>6 @GkfrsYi՞M˶m\Dֵ{KpjS5*dɯBuQs8en)K΢/M%GP| k +(PcϔVA[5l} 4Zv|ƽ M 0Z*Qyi.%ICw{ wa OH,sLT >6Zˊ(H< M֬kN{q,F=.LH%J ӊ2KBRi,mMCkTRI>0r-9c(YNnF!57 BH[oYJ%3h6Z4/0ҿTi,1\R);=q+tYm>qOL9WuuWH"M4_ O-m}Ư+O*0UdjSմM+UFdk7VfyWٰkmh~ZY sۍ#ܰBrvkH y%!f jT3lB(¢"$ϯ#m;V6-oUXW]\hֳtq5k]( mhSn;\x)$)ortR9K4n e7Ku|rL#o$;OZՙݗOU(ӟz|z=)Mh7?oK^2!/\C b}JRE!rJ)1(sMz9aL(;{aQk a!("HKҌT\ DDHTLcUHʘq) Rlǹ$$ 'xQ+7Ό֗f#^,G9Q*HbAY&DlbRA1XTT`A:΅?&9y5%]Ӗﺄ)r!B|E32xDq5"+ǾF^c;V5Ut%MrDIΧ Rȯa'ϒQٔ0e+?#xA ʠc)Vcx"PUΝ=mOg>I"XK\ cBPHa/<@br1(0Mrcψ$#L|3TQ4 =Q#Ҟcc$JK(v9+6*ڰW`_B@>ffs2!U![=)$cJzR>G%LɦE$5.%R47!2êԝ1:&8lCƘ0HJ_06b)"Z1h_"ё=iKZi ں;"sbH+rjkK:6Cڍ~xOBOANr2G)a>XF UzK, ǒױMy%T ^V& ,:0iv)9˥q9#W᳷q۰vovAd3w*1WRERcd{n+\!|]O)ncF} @# eEQ.R0c//$2"N.lFtь^ A!MXuPխT]K+xfO(6?YIKۧuc jr #y/dJrcv0h $䍘TAVL WMPnSUpU\gOk_08\aPaWKpp] ]i0З8ϚKԚk #F*i\*O/P/N)xo i|#B @ʂ1Z ;q̯?G"$rxP£R (Kw.Ӥ6.hCm|D >QR|ȃt+dQ=v%<̐qq@wڭ`1,MCOXbtH#B@KEWEQ!FuOjLDK >TTELUh(r G?TIEE}(䒗2""~I/,-fP‹LbVP P pTG"l6F,-nBўЮo>V=-Dno8MB [/ AY \DI%0م%Ne8j0 9%ת/"w"*Kun$V\( *!biug)26{%M2^vM+hG>p?Ø2F#<>xNV|ޔHNw]OxM_q$cx}ńO1i3#lahKLĵY/ʺzGTL+0$]q# *y)Ö)F3L0!i~WX8dFp8:Z7f!cXd9Ϭ M w!+wYՠZ1tZV1ݴ?TUjN :˪ӗ`kT45m`! m`r'7QKcVB|Op0o*"TAԣiX)@,6hvqiuy7]D2n$YvVmӚ7PmxK͎, Z 餇꩎4qT-^aAdzn"`7C{f^q{ /s=V/vcck#;()ET|Gz4-L^vez]bgW ئm7W_NQ:zv>Jn԰Ȗ FCUkvcn_mZh[_A{ ky'xvϖkJ`GWz+jIBF<MX鯇Q}64՚[&D[b h17# X̒G9F-f7d7IeE{ܔ ڗ7Wv [Ƶ̭6[zuV̋w0>SJԽ+ij;Z@ <(DByqTu$i`VמRV(>lfWf[2G`a.z:oayGXyy\ wMr|d}89‚8^<_f ogQl^lP$s6mx=^򈹭sz}ZjK@i-ǯހ:HU%-0Ѵk Ռп*\Ȑ!(BPĉ 3jȱǏ CfA+(RcTmkI͛8mjsG$ɓI ]IϟE"ӧPJJ՜۶#^RaͥG/&]z[p&K-T^Q{˷ojʂDЕM(#]#KLS0oof>KE4*خUEu˗ͨhQ Nq;ܭn6R /}iW2[R#̧M_fMtuP3ƙ u6^f[h̤ ^L  *dbw v,nYv~YtvƊh+ls*43:s*ͳ)B3=Bߌt*0}tTKsS=R!_o*:A\Ӳೌ'n [|"ń5gP[A䅄oժ vr29cT>Pŭd딘6sE;LQʱú)FovıM%ר=jLQ9К4 RŔ( ԟrEqFyy)4)(Gĥ1*Y mӖ&6 M(RQ.C$#_S@G!= =R^ب<5G#)'#JM.,b~iSOYhb'-5Jٹw2LH'S)φ^g2 Fs--=B|EcOLI%KY#VwD)_/Hu9R-Eʭj4HZҚ:(iƔy&*l.ҫvu$%UƄu4*fYFլQ,d>FtOtJSRfb=[SX{s 6b؆Ylц0NـuTIN~ܬ)ZφG'sI<tRTuem"FFzer1g sЕT0hUrW huߖVFnTlf(ԐSbEۚ62ELէo~"pgK|+?ccH e5cRsu;xnOv٩lcʖ*a%/%ݧOifx1 B/f]>6<~u;JyT+LKv6Òqt_`g6t%\#.ڮis(L5զ+sbf!4FP J͘^HV2N MQWUYvh@j:H+FEVt$9\#:8 Ns;ȴ+Pp9 _ŀRj, 1.%,@إA9nw!/ VQ3wp7I;@762('RP͠o@r:-^;)Y 9ISYsU63< )DC& mӒ؏>%9 46=FAt ϔQZE36*}wuuȆܕa~t 1H.#Ka/>e,C @ Ԡ I IP@iyq9ڐCiiI)٘Yn$y )٘y隴y9ɚaFFltFfuXfj9q8yWUm&v~~nv*6:3XC=d#v&:ִ+!w!fR: Z# @*@-ci=JE49!J#&+ Zo*GWT:H/#`sr{.V}a&\q/!SU-GפJ3(O*$&eRFP DS78_ ՘p2y !?}(ۦ5IMjtZq{:f>zqMqؗ`r7rp,N!yaK=ҧo1*FqL aaS02`,<-m.d&<ߒ- m3u#3AmrsFed')djy*ש"KD$y9yڪڪY&\ij3*B.#A(J0;'2+s#?,۰6>8熩mqq隲:/MT9Lʪ8;Ǻ0[<,k7>V9CAZ'jgsn:s=7*zݨ^{C3 w2[:K9K6lWNJepl*y*sP;\!ci; Q D\O_-Q!Nbt#׃)k[n;ڶW8Sr81D疰+}dVF;\s7 eKuMg";K9 -? , *Du =S('PA0=c.B&-E= ?b?vk7md{C.39 0`Q}lgm)ZMj42Ey ]"n-SC4O*"m(>˧ 6"LbqEݤðgyyB|Az!ؤ!bΡ:|@\w%2ztDK b\ƁzUn>tf|So A\$zl&BE)%A{fI.lž1SyMfȵHכ;ѻ!ʐ{k.ӥz@ bj$ܹaMl۶,}! ,Wȍ{?Dl˿ٌ̹۬ͺ*W)w* =ZήM˶)\2PQ M,QН<"L]˼߼!<'MjEt|^vH MϠS)c !);MFk\F=$=- Gu"}% $=,ⵍ)r#}n+Ϭ2(>L|0&3O7" mm܍E-^>}O"(GS拍~e ک Ҷplu&mH[TU:.lڀ>'t8,}ܐ u-hG {WD3 u9_~CN*n@BD~命*D໢<lwQVj^}Kխ nprt*.Gk=}mG>]=..١(԰9#o4C@Q^t}Lx>o#@Mb=~0"I*\DϽ-%{ڣo==#/_˙~w"4[z07BzZD&nҝ}wfIwb~ao#}wQ 5luFOaާsOIe?wiAMږq`O1+燚KA]aWcEQgY[UofQ)F,gKGuJ#**"W֞yߖ`/]WIf(bTb?~?a󨯲rH:zo5}^QoQfy򻿣߁$d_+*3j1o{UTU^ZUۿ|mo`㚪P>56\p6bޒc/Kn+r0nI4)qaB)whYnK%j֭][lĢU602me.>;ɣ.oK?0@' , -g,Po@ 'P B 7C*,C =dE'4gFjpj!QRAF#D*`Y1I'? Q*"K//$̪lC0£R9*̤N N=Bp!+UDi)>e:mɳQI'q6U2WPQRO?*LPG%uCJɊSR_5(-eV[}HVaIaE|K7íd6[qȪf,8G9T[s\u-tR-Rvџr[Kus!j2EF\MZ3K u8c Vc)]l_!dc_6SDOew6.ft9h' Dفx<it:(s++R!Scv5hfFBR#;nZn4|7D nWZxp)̧|WB14pɅz4t/ujG!-n.=u" ]%4NU? Untitled Document

    Tips for Nyquist IDE

    NyqIDE Interface

    • In the Command Line Window, use Alt + Up and Alt + Down to retrieve recently entered commands. It can be retrieved up to last ten commands.

    • In the Command Line Window, use Alt + Enter to begin a new line (for the purpose of inputting multiple lines). Only press Enter will send the input to the Nyquist kernel.

    • In the Command Line Window or Document Window, double click or select the "Select Complete Paragraph" Item in the popup menu right before an open paren, the system will automatically select the text that begins with this open paren and ends with the corresponding close paren. This will be helpful for checking the matching parens or loading a complete function.

    • In the Command Window or Document Window, select the "Load Selected Text" Item in the popup menu to load the selected text.

    • The way the Paren Matching works: When type in a close paren, the cursor jumps to the corresponding open paren and blinks, then it returns to the close paren. The function can be disabled from the main menu.

    • NyqIDE Plot Window To plot sounds in a window, either type (s-plot ...) function in the Command Line Window/document to be loaded, or click the speed button S-Plot/through the menu Process-->S-Plot, a Plot Window will pop up and show the plots. Multiple Plot Windows can be displayed at the same time as the children windows of the program. There are some shortcut keys for the Plot Window: Shift + Mouse Drag to zoom in; Ctrl + Mouse Drag to pan (move the center of the view); Shift + Mouse Left Click to restore the original view of the plot; Mouse Right Click to pop up the menu. Advanced functions are listed in the pop up menu, including figure copy, view options, and zoom options.

    • The program keeps the history of up to five most recently used (MRU) documents. And you can speedily reopen those MRU documents by getting through the menu File-->Reopen-->MRU List.

    • The system working directory will be always set to the directory of the most recently opened document, no matter whether the document is opened from the open dialog or from the MRU List. It means that the temporary sound file and the plot file (if created) will be also created in that working directory.

    • "Help Contents", "Topic Search" and "NyqIDE Tips" are local or online documentations. The program will first try to locate the documentations locally. If failed, the program will try to locate the online documentations.

    • Function keys F2-F12 are related to the functions with the same key names. E.g. Press F2 (or click the speed button F2 or go through the menu Process-->Function Keys-->Function F2) is equivalent to typing "(F2)" in the Command Line Window. However, pressing F1 will display the "Topic Search" documentation.

    • We welcome your suggestion to improve this program. This program was made in order to let Nyquist easier to use and friendlier to the programmers.

      Written by Ning Hu(ninghu@cs.cmu.edu)
      Last update: Nov.2002


    nyquist-3.05/nyqide/readme-vcl.txt0000644000175000000620000000052010144436365016237 0ustar stevestaffNyqIDE is using some free and open source VCL components listed as below: VCL Name URL ==================== ================================ dfsMRUFileList v2.66 http://www.delphifreestuff.com SGraph v2.4 http://pod0.chat.ru/prg_staf.htm SimpleThread v1.0 eugene@actcom.co.il SynEdit v1.1 http://synedit.sourceforge.net/ nyquist-3.05/jnyqide.bat0000644000175000000620000000003711466723256014332 0ustar stevestaffjava -jar jnyqide/jNyqIDE.jar nyquist-3.05/init.lsp~0000644000175000000620000000010411466723256014053 0ustar stevestaff(load "misc/makefile.lsp") (setf sys-type 'linux) (makefile) (exit) nyquist-3.05/nyqwin.vcproj0000644000175000000620000031444611512143043014743 0ustar stevestaff nyquist-3.05/nyquist.sln0000644000175000000620000003111611512143043014411 0ustar stevestaff Microsoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filelist", "misc\filelist.vcproj", "{DA1A1539-671B-4E70-BF6E-10EC6887FAF4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "intgen", "misc\intgen_win32\intgen.vcproj", "{378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nyquist", "nyquist.vcproj", "{208E5158-7B25-4185-8D8E-5E5BFC2153EC}" ProjectSection(ProjectDependencies) = postProject {A02E8EC5-317C-42CD-9425-60BDDE09D833} = {A02E8EC5-317C-42CD-9425-60BDDE09D833} {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} = {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nyqwin", "nyqwin.vcproj", "{19DEEB57-B0BB-476A-9960-CE360A884906}" ProjectSection(ProjectDependencies) = postProject {A02E8EC5-317C-42CD-9425-60BDDE09D833} = {A02E8EC5-317C-42CD-9425-60BDDE09D833} {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} = {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "packer", "misc\packer.vcproj", "{F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unpacker", "misc\unpacker.vcproj", "{E09240DC-CFBD-46BE-A6EA-2379C7502230}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osc-test-client", "liblo\test-client\osc-test-client.vcproj", "{22B02EA5-24F7-4F8D-8D8F-E066D80A0957}" ProjectSection(ProjectDependencies) = postProject {A02E8EC5-317C-42CD-9425-60BDDE09D833} = {A02E8EC5-317C-42CD-9425-60BDDE09D833} {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} = {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ser-to-osc", "liblo\ser-to-osc\ser-to-osc.vcproj", "{44736D55-68C4-496D-B08A-9C66844AE857}" ProjectSection(ProjectDependencies) = postProject {A02E8EC5-317C-42CD-9425-60BDDE09D833} = {A02E8EC5-317C-42CD-9425-60BDDE09D833} {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} = {FEA9D5D3-46BD-594F-85C6-F1380FD994A6} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthread", "liblo\pthreads.2\pthread.vcproj", "{A02E8EC5-317C-42CD-9425-60BDDE09D833}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblo", "liblo\build\vs2008\liblo.vcproj", "{FEA9D5D3-46BD-594F-85C6-F1380FD994A6}" ProjectSection(ProjectDependencies) = postProject {A02E8EC5-317C-42CD-9425-60BDDE09D833} = {A02E8EC5-317C-42CD-9425-60BDDE09D833} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 DebugDLL|Win32 = DebugDLL|Win32 DebugLib|Win32 = DebugLib|Win32 Release|Win32 = Release|Win32 ReleaseDLL|Win32 = ReleaseDLL|Win32 ReleaseLib|Win32 = ReleaseLib|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.Debug|Win32.ActiveCfg = Debug|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.Debug|Win32.Build.0 = Debug|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.DebugDLL|Win32.Build.0 = Debug|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.DebugLib|Win32.ActiveCfg = Debug|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.DebugLib|Win32.Build.0 = Debug|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.Release|Win32.ActiveCfg = Release|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.Release|Win32.Build.0 = Release|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.ReleaseDLL|Win32.Build.0 = Release|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {DA1A1539-671B-4E70-BF6E-10EC6887FAF4}.ReleaseLib|Win32.Build.0 = Release|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.Debug|Win32.ActiveCfg = Debug|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.Debug|Win32.Build.0 = Debug|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.DebugDLL|Win32.Build.0 = Debug|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.DebugLib|Win32.ActiveCfg = Debug|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.DebugLib|Win32.Build.0 = Debug|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.Release|Win32.ActiveCfg = Release|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.Release|Win32.Build.0 = Release|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.ReleaseDLL|Win32.Build.0 = Release|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {378FBAED-0CA5-4CFB-ACF4-CCEDF8A4596E}.ReleaseLib|Win32.Build.0 = Release|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.Debug|Win32.ActiveCfg = Debug|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.Debug|Win32.Build.0 = Debug|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.DebugDLL|Win32.Build.0 = Debug|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.DebugLib|Win32.ActiveCfg = Debug|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.DebugLib|Win32.Build.0 = Debug|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.Release|Win32.ActiveCfg = Release|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.Release|Win32.Build.0 = Release|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.ReleaseDLL|Win32.Build.0 = Release|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {208E5158-7B25-4185-8D8E-5E5BFC2153EC}.ReleaseLib|Win32.Build.0 = Release|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.Debug|Win32.ActiveCfg = Debug|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.Debug|Win32.Build.0 = Debug|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.DebugDLL|Win32.Build.0 = Debug|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.DebugLib|Win32.ActiveCfg = Debug|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.DebugLib|Win32.Build.0 = Debug|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.Release|Win32.ActiveCfg = Release|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.Release|Win32.Build.0 = Release|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.ReleaseDLL|Win32.Build.0 = Release|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {19DEEB57-B0BB-476A-9960-CE360A884906}.ReleaseLib|Win32.Build.0 = Release|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.Debug|Win32.ActiveCfg = Debug|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.Debug|Win32.Build.0 = Debug|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.DebugDLL|Win32.Build.0 = Debug|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.DebugLib|Win32.ActiveCfg = Debug|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.DebugLib|Win32.Build.0 = Debug|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.Release|Win32.ActiveCfg = Release|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.Release|Win32.Build.0 = Release|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.ReleaseDLL|Win32.Build.0 = Release|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {F40BCDEF-F66F-4FEB-9513-F7EFF29BFC93}.ReleaseLib|Win32.Build.0 = Release|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.Debug|Win32.ActiveCfg = Debug|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.Debug|Win32.Build.0 = Debug|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.DebugDLL|Win32.Build.0 = Debug|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.DebugLib|Win32.ActiveCfg = Debug|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.DebugLib|Win32.Build.0 = Debug|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.Release|Win32.ActiveCfg = Release|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.Release|Win32.Build.0 = Release|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.ReleaseDLL|Win32.Build.0 = Release|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {E09240DC-CFBD-46BE-A6EA-2379C7502230}.ReleaseLib|Win32.Build.0 = Release|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.Debug|Win32.ActiveCfg = Debug|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.Debug|Win32.Build.0 = Debug|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.DebugDLL|Win32.Build.0 = Debug|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.DebugLib|Win32.ActiveCfg = Debug|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.DebugLib|Win32.Build.0 = Debug|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.Release|Win32.ActiveCfg = Release|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.Release|Win32.Build.0 = Release|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.ReleaseDLL|Win32.Build.0 = Release|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {22B02EA5-24F7-4F8D-8D8F-E066D80A0957}.ReleaseLib|Win32.Build.0 = Release|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.Debug|Win32.ActiveCfg = Debug|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.Debug|Win32.Build.0 = Debug|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.DebugDLL|Win32.Build.0 = Debug|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.DebugLib|Win32.ActiveCfg = Debug|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.DebugLib|Win32.Build.0 = Debug|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.Release|Win32.ActiveCfg = Release|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.Release|Win32.Build.0 = Release|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.ReleaseDLL|Win32.Build.0 = Release|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {44736D55-68C4-496D-B08A-9C66844AE857}.ReleaseLib|Win32.Build.0 = Release|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.Debug|Win32.ActiveCfg = Debug|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.Debug|Win32.Build.0 = Debug|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.DebugDLL|Win32.Build.0 = Debug|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.DebugLib|Win32.ActiveCfg = Debug|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.DebugLib|Win32.Build.0 = Debug|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.Release|Win32.ActiveCfg = Release|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.Release|Win32.Build.0 = Release|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.ReleaseDLL|Win32.Build.0 = Release|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {A02E8EC5-317C-42CD-9425-60BDDE09D833}.ReleaseLib|Win32.Build.0 = Release|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.Debug|Win32.ActiveCfg = Debug|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.Debug|Win32.Build.0 = Debug|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugDLL|Win32.ActiveCfg = Debug|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugDLL|Win32.Build.0 = Debug|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugLib|Win32.ActiveCfg = Debug|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.DebugLib|Win32.Build.0 = Debug|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.Release|Win32.ActiveCfg = Release|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.Release|Win32.Build.0 = Release|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseDLL|Win32.ActiveCfg = Release|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseDLL|Win32.Build.0 = Release|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseLib|Win32.ActiveCfg = Release|Win32 {FEA9D5D3-46BD-594F-85C6-F1380FD994A6}.ReleaseLib|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal nyquist-3.05/todo.txt0000644000175000000620000002076711514640104013701 0ustar stevestaffdefault sound file directory seems to be install directory -- bad idea on Windows 7 preferences does not properly handle "\" in "set default sound file directory" under Windows Check if drums in browser tells you where to get and how/where to install. Nyquist should exit on (EXIT) without waiting for a return -- test on windows. Works on Mac. indentation is wrong after: (let ((var value) -- FIXED, but check (let (foo -- FIXED typing (top should not insert the return (when autoparens is on and parens are balanced) -- FIXED ==== check if this is still so: s-plot differs betweein Linux and Windows ====== Results from ICM2006 class: integrate asung's ide code - DONE integrate and improve prahava's browser - COULD USE MORE WORK write up plight's drum machine for demo section look into open source drum machine software -- maybe share file format? integrate dfontain's upic code -- IN C, NEEDS WORK integrate sliders from kmsun_bgoodric: Needs: more compact slider layout, editable range values, support for continuous control, elimination of the text echoing in the console window streamline find/replace execute selected code select expression when you double-click paren cyearly's envelope editor plan for integration with score editor dmakuck's graphic EQ editor and interface need to design strategy for saving data/code integrate jgrafton's GUS reader turn tgovani bird songs into demo Here's how envelopes should work: When the user opens a .pwl file, the envelope editor reads it. Using the envelope editor, envelopes are edited, loaded into nyquist, and saved. The user can also open the file as text (from within the env editor). IDE should prevent both from being open at same time. ===== Debian command line script to invoke nyquist omits parameters ===== Typo: space after pluck in manual. There are some minor bugs that I have found: 1. The function snd-lpanal is not recognized by Nyquist. I have fixed that in my own compiled version of Nyquist by means of MSVC 6.0 adding "by hand" some code. 3. There is a mistake in the name of gaussian distribution: the name in the manual is gauss-dist while the name in the source code is gaussian-dist. If I found any problem more I will comunicate it to you. Finally, sorry for my very basic english. I can not express the nuances as I would do in spanish. Best regards, Pedro J. Morales. This is the code that I have added to include snd-lpanal. /// SOURCE CODE FOR sndfnint.c #include "lpanal.h" /* xlc_snd_lpanal -- interface to C routine snd_lpanal */ /**/ LVAL xlc_snd_lpanal(void) { LVAL arg1 = xlgetarg(); long arg2 = getfixnum(xlgafixnum()); LVAL result; xllastarg(); result = snd_lpanal(arg1,arg2); return (result); } /// SOURCE CODE FOR sndfintptrs.h { "SND-LPANAL", S, xlc_snd_lpanal}, /// SOURCE CODE FOR sndfintdefs.h extern LVAL xlc_snd_lpanal(void); ================================ Check echoenabled in documentation -- maybe the preceding @index command is messing up the indentation. =========================== Roger I found a minor bug in full-name-p in system.lps The function does not test for the UNIX file separator / This causes s-save to only work with filenames relative to *sf-default-dir* --Steve ===================== test (SCORE-BEGIN) and (SCORE-END) implement score manipulation routines in xm.lsp (see manual) document, implement workspaces ====== big test of markov analysis for xm.lsp for order 1 and order 2 ======== (dotimes (i 10) (print (next (make-copier (make-cycle '(a b c)) :repeat 2) t))) prints nil period after 2 repeats ========== See cmsip hierarchy.lsp -- fix sustain It appears that sustain is not correctly implemented Check every use of get-duration, document get-duration correctly after fixing the code. ========= SourceForge credits on web site Create SourceForge project web page Put releases on SourceForge Create Nyquist mailing list on Sourceforge ========== Integrate new debian changes. -DONE ========== macosxproject/nyquistproject.pbproj/project.pbxproj is not on cvs -DONE =========== detect newline problems, e.g. a stray ^M at end of file seems to cause read error, but the char does not show up in most editors including jnyqide. -- tested under Win32, but not Linux ================= Documentation for Adagio should go somewhere. It's mentioned in the nyquist manual, but there's no reference or URL for CMT. -DONE ================= Thanks for the prompt response. it may help if I give you the preference file (OS9) that I created for v 2.29 that caused(?) the error message: PREF File in OS9 prefs folder: > XLISPPATH=Macintosh HD:Users:robwilkinson:SUBJECT > index:PROJECTS:Nyquist/Audacity Plugins:nyquist.229:runtime Resulting error message: XLISP version 2.0, Copyright (c) 1986, by David Betz > CMU MIDI Toolkit, Copyright (c) 1993,1994, by Roger B. Dannenberg > Macintosh interface by Brian Kendig, Erik A. Dahl, and Dominic > Mazzoni. > error: file name too long - NIL Regards Rob No matter what I do to the file name by altering the preferences file I get the same message. I thought it might have something to do with the extended(>32) filename length in OSX but even very short names do not work. Otherwise 2.29 works fine. 2) Version 2.30 unpacked ok but there was no file named Nyquist and no icon. Could not persuade it to run. Altho very late at night I tried to invoke "ny" using Terminal and remember getting the above error message. Could not repeat the experience tho'. I downloaded Nyquist to experiment with making a Declipper Effect for Audacity. In the learning process I found that none of the Nyquist effects actually work in Audacity. In particular the lp and hp effects. Wrote a simple clipper effect & it did not work either. Is this of interest to you? Finally have you any suggestions which Nyquist functions I should focus on to find flat topped peaks in a sound file. ie to find 3 or more adjacent identical samples not just test for equality to +/- maximum value. The maths for splining in sine or parabolic cap are straight forward if I can extract the flat section and the 3 samples that precede and follow it. I'm a semi-retired EE not experienced in Lisp or C Regards Rob Wilkinson. ================================================================ fix, test seqmidi to take note, ctrl, prgm, etc. ----- multiseq.c assumes all signals have same sample rate. I think this could be fixed merely by saving an array of sample rates so that zero signals of the proper rate could be generated later. Also be sure to free the array of sample rates when the multiseq struct is freed. bvg================ Each chapter requires: * Programming Instructions (this is done) * Programming Tips (this need more work) * Programming Misconceptions (this you do at times) * Conceptual overview 1. details for particular cases 2. generalization of the particular cases 3. summary notes for each chapter The idea of a user manual in addition to a documentation manual for nyquist is in order. Something with more step by step instructions. You may not have a graphic interface but the manual could have a more graphic approach to nyquist. The issue of analysis/resynthesis within nyquist is not spelled out. Since the technique of analysis/resynthesis was such a force in the creation of Nyquist you could think of gearing your presentation of Nyquist in those terms within a User's Manual for Nyquist. The point of which is to give a better presentation of Nyquist as a tool for analysis/resynthesis rather than a theory on analysis/resynthesis. An example of the problem with the manual is evident in the \ like of treatment of say recorded samples (soundfiles and sound synthesis): 1. mono 2. stereo 3. mixing There is the additional question of using a soundfile to go between one of these 3 cases. All of this would fill a section on Multichannels. There are sets of terminology which could be listed at the start of each chapter which could be organized in some kind of concept graph. \ Warping Behavior Abstract Behavior: * Parameterization of Behaviors * Flexibility of Parameterization \ Transformation Transformation Environment These ideas are very dense and need more development within a user's manual. In part the matter of warping in nyquist and time-warping Practices could also be discussed (discrete and continuous). ================ nyquist-3.05/files.txt0000644000175000000620000005505610144436365014047 0ustar stevestaffb .DS_Store a nyquist.dsp a nyquist.dsw a todo.txt a nyqwin.dsp a convert.dsp a advantages.txt a convert.dsw a jnyqide.bat a Readme.txt a files.txt a releasenyqide.bat a release.bat a releasenyqwin.bat a license.txt a howtorelease.txt a cmt/seqmwrite.h a cmt/cext.c a cmt/seqread.c a cmt/seqread.h a cmt/cext.h a cmt/userio.c a cmt/userio.h a cmt/cleanup.c a cmt/seqwrite.c a cmt/seqwrite.h a cmt/swlogic.h a cmt/cleanup.h a cmt/tempomap.c a cmt/tempomap.h a cmt/timebase.c a cmt/cmdline.c a cmt/timebase.h a cmt/cmdline.h a cmt/cmtcmd.c a cmt/cmtcmd.h a cmt/cmtio.c a cmt/cmtio.h a cmt/hash.h a cmt/hashrout.h a cmt/mem.c a cmt/mem.h a cmt/mfmidi.h a cmt/midibuff.h a cmt/midicode.h a cmt/midierr.h a cmt/midifile.c a cmt/midifile.h a cmt/midifns.c a cmt/midifns.h a cmt/midimgr.c a cmt/midimgr.h a cmt/moxc.c a cmt/moxc.h a cmt/musiprog.h a cmt/pitch.h a cmt/record.c a cmt/record.h a cmt/seq.c a cmt/seq.h a cmt/seqdecls.h a cmt/seqmread.c a cmt/seqmread.h a cmt/seqmwrite.c b demos/a-snd-file.snd a demos/allewis/cell_aut.lsp a demos/allewis/cellularautomata.htm b demos/allewis/cmusic_pres.ppt b demos/allewis/rule30.jpg a demos/bandfx.htm b demos/beginclip.jpg b demos/demo-snd.aiff b demos/demo.mid a demos/distortion.htm a demos/examples.lsp a demos/fft_tutorial.htm b demos/largeclip.jpg a demos/lpc-exmpl.dat a demos/lpc_tutorial.htm a demos/lpcdemo.lsp a demos/midi_tutorial.htm a demos/pitch_change.htm a demos/rhythm_tutorial.htm a demos/scratch_tutorial.htm a demos/sequence_example.htm a demos/shepard.lsp a demos/shepard.ny b demos/softclip.gif b demos/softclip.jpg a demos/stktest.lsp a demos/warble_tutorial.htm a demos/wind_tutorial.htm a demos/piano.htm a demos/fft_demo.lsp a demos/examples_home.htm a demos/voice_synthesis.htm a demos/pmorales/pjmg.lsp a demos/pmorales/readme.txt a demos/pmorales/a4.lsp a demos/pmorales/a5.lsp a demos/pmorales/a6.lsp a demos/pmorales/b1.lsp a demos/pmorales/b10.lsp a demos/pmorales/b2.lsp a demos/pmorales/b3.lsp a demos/pmorales/b5.lsp a demos/pmorales/b7.lsp a demos/pmorales/b8.lsp a demos/pmorales/b9.lsp a demos/pmorales/c1.lsp a demos/pmorales/d1.lsp a demos/pmorales/e2.lsp a demos/pmorales/ks.lsp a demos/pmorales/partial.lsp a demos/pmorales/phm.lsp a demos/pmorales/buzz.lsp b doc/fig1.gif b doc/fig2.gif b doc/fig3.gif b doc/fig4.gif b doc/fig5.gif b doc/fig6.gif a doc/foot.html a doc/home.html a doc/part1.html a doc/part2.html a doc/part3.html a doc/part4.html a doc/part5.html a doc/part6.html a doc/part7.html a doc/part8.html a doc/part9.html a doc/part10.html a doc/part11.html a doc/part12.html a doc/indx.html a fft/fftn.c a fft/fftn.h a jnyqide/README.txt b jnyqide/closefile.gif a jnyqide/finddialog.java b jnyqide/help.gif a jnyqide/keywords.txt a jnyqide/lispfilefilter.java a jnyqide/main.java a jnyqide/mainframe.java a jnyqide/mainframe_aboutbox.java a jnyqide/notfounddialog.java a jnyqide/nyqplot.java a jnyqide/nyquistfile.java a jnyqide/nyquistthread.java b jnyqide/openfile.gif a jnyqide/pair.java a jnyqide/plotframe.java a jnyqide/plotmouseadapter.java a jnyqide/replacedialog.java a jnyqide/syntaxthread.java a jnyqide/textcolor.java a lib/bandfx.lsp a lib/compress.lsp a lib/dtmf.lsp a lib/gran.lsp a lib/grapheq.lsp a lib/lpc.lsp a lib/midishow.lsp a lib/pianosyn.lsp a lib/reverb.lsp a lib/soften.lsp a lib/time-delay-fns.lsp b lib/piano/rls44100.pcm b lib/piano/dur.tab b lib/piano/gmax.tab b lib/piano/demo.mid b lib/piano/rls48000.pcm b lib/piano/pn00.cod b lib/piano/pn01.cod b lib/piano/pn02.cod b lib/piano/pn03.cod b lib/piano/pn04.cod b lib/piano/pn05.cod b lib/piano/pn06.cod b lib/piano/pn07.cod b lib/piano/pn08.cod b lib/piano/pn09.cod b lib/piano/pn10.cod b lib/piano/pn11.cod b lib/piano/pn12.cod b lib/piano/pn13.cod b lib/piano/pn14.cod b lib/piano/pn15.cod b lib/piano/pn16.cod b lib/piano/pn17.cod b lib/piano/pn18.cod b lib/piano/pn19.cod b lib/piano/pn20.cod b lib/piano/pn21.cod b lib/piano/pn22.cod b lib/piano/rlsrate.tab b lib/piano/rls8000.pcm b lib/piano/demo.mp3 b lib/piano/att11025.pcm b lib/piano/att16000.pcm b lib/piano/att22050.pcm b lib/piano/att32000.pcm b lib/piano/att44100.pcm b lib/piano/att48000.pcm b lib/piano/att8000.pcm b lib/piano/rls11025.pcm b lib/piano/rls16000.pcm b lib/piano/rls22050.pcm b lib/piano/rls32000.pcm a lpc/compile.txt a lpc/lpc-example.dat a lpc/lpc-exmpl.dat a lpc/lpc-orig.lsp a lpc/lpc.lsp a lpc/lpcdemo-orig.lsp a lpc/lpcdemo.lsp a lpc/prims-ref.txt a lpc/readme.txt a lpc/src/allpoles.alg a lpc/src/lpreson.alg a lpc/src/lpanal.c a lpc/src/lpanal.h b macosxproject/build/.DS_store b macosxproject/build/nyquist.build/.DS_store b macosxproject/build/nyquist.build/Interface Generator.build/Interface Generator.hmap b macosxproject/build/nyquist.build/nyquist.pbxindex/strings.pbxstrings/control b macosxproject/build/nyquist.build/nyquist.pbxindex/strings.pbxstrings/strings b macosxproject/build/nyquist.build/nyquist.pbxindex/categories.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/decls.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/files.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/imports.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/nyquist.indexed-headers b macosxproject/build/nyquist.build/nyquist.pbxindex/nyquist.indexed-precomps b macosxproject/build/nyquist.build/nyquist.pbxindex/pbxindex.header b macosxproject/build/nyquist.build/nyquist.pbxindex/protocols.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/refs.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/subclasses.pbxbtree b macosxproject/build/nyquist.build/nyquist.pbxindex/symbols0.pbxsymbols b macosxproject/nyquistproject.pbproj/project.pbxproj b macosxproject/.DS_Store b macosxproject/Nyquist.icns b macosxproject/README b macproject/nyquistdata/CWSettingsMacOS.stg b macproject/packer/packerdata/.DS_Store b macproject/packer/packerdata/.CWSettingsMacOS.stg b macproject/packer/packer.mcp b macproject/unpacker/unpackerdata/.DS_Store b macproject/unpacker/unpackerdata/CWSettingsMacOS.stg b macproject/unpacker/unpackerdata/unpacker/TargetDataMacOS.tdt b macproject/unpacker/unpacker.mcp a macproject/mac_port_changes.txt b macproject/nyquist.mcp b macproject/nyquist.rsrc b macproject/NyquistIcon b macproject/NyquistIcon.sit a misc/Makefile a misc/args.h a misc/cext.h a misc/cmdline.c a misc/cmdline.h a misc/convert.c a misc/convert.h a misc/mac-to-win.lsp a misc/filelist.c a misc/filelist.dsp a misc/intgen.c a misc/packer.c a misc/packer.dsp a misc/play.c a misc/plot.c a misc/sampleprint.c a misc/sine.c a misc/stdefs2.h a misc/unpacker.c a misc/unpacker.dsp a misc/makefile.lsp a misc/transfiles.lsp a misc/intgen2.c a misc/intgen_win32/intgen.dsp a misc/cmu/cmuinstall.bat a misc/cmu/cmuinstall2.bat a misc/cmu/cmu-linux-install.lsp a misc/cmu/init.lsp a misc/cmu/cleanup.bat a misc/cmu/music.software.html a misc/cmu/new.html a misc/cmu/restore.bat b nyqide/doc/nyqide_plot.gif b nyqide/doc/nyquistide.gif a nyqide/doc/tips.htm b nyqide/nyqide.exe b nyqide/nyqide_src.zip a nyqide/readme-vcl.txt a nyqsrc/nfilterkit.c a nyqsrc/add.c a nyqsrc/nfilterkit.h a nyqsrc/add.h a nyqsrc/resampv.c a nyqsrc/resampv.h a nyqsrc/avg.c a nyqsrc/resamp.c a nyqsrc/avg.h a nyqsrc/resamp.h a nyqsrc/samples.c a nyqsrc/samples.h a nyqsrc/compose.c a nyqsrc/rfftw.h a nyqsrc/seqfn.wcl a nyqsrc/seqfnint.c a nyqsrc/compose.h a nyqsrc/convolve.c a nyqsrc/convolve.h a nyqsrc/seqext.c a nyqsrc/seqext.h a nyqsrc/cque.h a nyqsrc/seqfn.cl a nyqsrc/seqfnint.lsp a nyqsrc/debug.c a nyqsrc/seqinterf.c a nyqsrc/debug.h a nyqsrc/seqfnintdefs.h a nyqsrc/downsample.c a nyqsrc/seqfnintptrs.h a nyqsrc/downsample.h a nyqsrc/seqinterf.h a nyqsrc/falloc.c a nyqsrc/sndfn.wcl a nyqsrc/sndfnint.c a nyqsrc/sndfnintptrs.h a nyqsrc/ffilterkit.c a nyqsrc/sndfn.cl a nyqsrc/sndfnint.lsp a nyqsrc/f0.cpp a nyqsrc/f0.h a nyqsrc/fftw.h a nyqsrc/ffilterkit.h a nyqsrc/sndseq.c a nyqsrc/sndwrite.c a nyqsrc/sndwritepa.c a nyqsrc/fft.c a nyqsrc/fft-rbd.c a nyqsrc/sndread.c a nyqsrc/sndread.h a nyqsrc/falloc.h a nyqsrc/sndmax.c a nyqsrc/sndmax.h a nyqsrc/fft.h a nyqsrc/sndwrite.h a nyqsrc/sound.c a nyqsrc/fftr4.c a nyqsrc/sndseq.h a nyqsrc/stats.c a nyqsrc/sndfail.c a nyqsrc/exitpa.h a nyqsrc/fresample.h a nyqsrc/fsmallfilter.h a nyqsrc/sound.h a nyqsrc/stdefs.h a nyqsrc/handlers.c a nyqsrc/inverse.c a nyqsrc/inverse.h a nyqsrc/local.c a nyqsrc/sndfnintdefs.h a nyqsrc/localdefs.h a nyqsrc/localptrs.h a nyqsrc/lpanal.c a nyqsrc/lpanal.h a nyqsrc/multiread.c a nyqsrc/multiread.h a nyqsrc/multiseq.c a nyqsrc/multiseq.h a nyqsrc/nyx.c a nyqsrc/nyx.h a nyqsrc/oldyin.c a nyqsrc/oldyin.h a nyqsrc/probe.c a nyqsrc/probe.h a nyqsrc/yin.c a nyqsrc/yin.h a nyqstk/globals.h a nyqstk/instr.cpp a nyqstk/instr.h a nyqstk/stkinit.cpp a nyqstk/stkinit.h a nyqstk/include/Clarinet.h a nyqstk/include/Delay.h a nyqstk/include/DelayL.h a nyqstk/include/Envelope.h a nyqstk/include/Filter.h a nyqstk/include/Instrmnt.h a nyqstk/include/Noise.h a nyqstk/include/OneZero.h a nyqstk/include/ReedTabl.h a nyqstk/include/Saxofony.h a nyqstk/include/SKINI.msg a nyqstk/include/Stk.h a nyqstk/include/WaveLoop.h a nyqstk/include/WvIn.h a nyqstk/src/Clarinet.cpp a nyqstk/src/Delay.cpp a nyqstk/src/DelayL.cpp a nyqstk/src/Envelope.cpp a nyqstk/src/Filter.cpp a nyqstk/src/Instrmnt.cpp a nyqstk/src/Noise.cpp a nyqstk/src/OneZero.cpp a nyqstk/src/ReedTabl.cpp a nyqstk/src/Saxofony.cpp a nyqstk/src/Stk.cpp a nyqstk/src/WaveLoop.cpp a nyqstk/src/WvIn.cpp a portaudio/aclocal.m4 a portaudio/config.doxy a portaudio/config.guess a portaudio/config.sub a portaudio/configure a portaudio/configure.in a portaudio/fixdir.bat a portaudio/fixfile.bat a portaudio/index.html a portaudio/install-sh a portaudio/LICENSE.txt a portaudio/Makefile.in a portaudio/rbdnotes.txt a portaudio/README.txt a portaudio/V19-devel-readme.txt a portaudio/docs/index.html a portaudio/docs/latency.html a portaudio/docs/pa_impl_guide.html a portaudio/docs/pa_impl_startstop.html a portaudio/docs/pa_tutorial.html a portaudio/docs/pa_tut_asio.html a portaudio/docs/pa_tut_callback.html a portaudio/docs/pa_tut_devs.html a portaudio/docs/pa_tut_explore.html a portaudio/docs/pa_tut_init.html a portaudio/docs/pa_tut_mac.html a portaudio/docs/pa_tut_mac_osx.html a portaudio/docs/pa_tut_open.html a portaudio/docs/pa_tut_oss.html a portaudio/docs/pa_tut_over.html a portaudio/docs/pa_tut_pc.html a portaudio/docs/pa_tut_run.html a portaudio/docs/pa_tut_rw.html a portaudio/docs/pa_tut_term.html a portaudio/docs/pa_tut_util.html a portaudio/docs/portaudio_h.txt b portaudio/docs/portaudio_icmc2001.pdf a portaudio/docs/proposals.html a portaudio/docs/releases.html a portaudio/pablio/pablio.c a portaudio/pablio/pablio.def a portaudio/pablio/pablio.h a portaudio/pablio/README.txt a portaudio/pablio/ringbuffer.c a portaudio/pablio/ringbuffer.h a portaudio/pablio/test_rw.c a portaudio/pablio/test_rw_echo.c a portaudio/pablio/test_w_saw.c a portaudio/pablio/test_w_saw8.c a portaudio/pa_asio/ASIO-README.txt b portaudio/pa_asio/Callback_adaptation_.pdf a portaudio/pa_asio/iasiothiscallresolver.cpp a portaudio/pa_asio/iasiothiscallresolver.h a portaudio/pa_asio/pa_asio.cpp a portaudio/pa_asio/pa_asio.h b portaudio/pa_asio/Pa_ASIO.pdf a portaudio/pa_beos/pa_beos_mk.cc a portaudio/pa_beos/PlaybackNode.cc a portaudio/pa_beos/PlaybackNode.h a portaudio/pa_common/pa_allocation.c a portaudio/pa_common/pa_allocation.h a portaudio/pa_common/pa_converters.c a portaudio/pa_common/pa_converters.h a portaudio/pa_common/pa_cpuload.c a portaudio/pa_common/pa_cpuload.h a portaudio/pa_common/pa_dither.c a portaudio/pa_common/pa_dither.h a portaudio/pa_common/pa_endianness.h a portaudio/pa_common/pa_front.c a portaudio/pa_common/pa_hostapi.h a portaudio/pa_common/pa_process.c a portaudio/pa_common/pa_process.h a portaudio/pa_common/pa_skeleton.c a portaudio/pa_common/pa_stream.c a portaudio/pa_common/pa_stream.h a portaudio/pa_common/pa_trace.c a portaudio/pa_common/pa_trace.h a portaudio/pa_common/pa_util.h a portaudio/pa_common/portaudio.h a portaudio/pa_dll_switch/letter_from_tim_010817.txt a portaudio/pa_dll_switch/loadPA_DLL.cpp a portaudio/pa_dll_switch/PaDllEntry.h a portaudio/pa_dll_switch/pa_lib.c a portaudio/pa_dll_switch/portaudio.h a portaudio/pa_jack/pa_jack.c a portaudio/pa_linux_alsa/pa_linux_alsa.c a portaudio/pa_linux_alsa/pa_linux_alsa.h a portaudio/pa_mac_core/notes.txt a portaudio/pa_mac_core/pa_mac_core.c a portaudio/pa_mac_sm/pa_mac_sm.c a portaudio/pa_sgi/pa_sgi.c a portaudio/pa_tests/debug_convert.c a portaudio/pa_tests/debug_dither_calc.c a portaudio/pa_tests/debug_dual.c a portaudio/pa_tests/debug_multi_in.c a portaudio/pa_tests/debug_multi_out.c a portaudio/pa_tests/debug_record.c a portaudio/pa_tests/debug_record_reuse.c a portaudio/pa_tests/debug_sine.c a portaudio/pa_tests/debug_sine_amp.c a portaudio/pa_tests/debug_sine_formats.c a portaudio/pa_tests/debug_srate.c a portaudio/pa_tests/debug_test1.c a portaudio/pa_tests/paqa_devs.c a portaudio/pa_tests/paqa_errs.c a portaudio/pa_tests/patest1.c a portaudio/pa_tests/patest_buffer.c a portaudio/pa_tests/patest_callbackstop.c a portaudio/pa_tests/patest_clip.c a portaudio/pa_tests/patest_dither.c a portaudio/pa_tests/patest_hang.c a portaudio/pa_tests/patest_in_overflow.c a portaudio/pa_tests/patest_latency.c a portaudio/pa_tests/patest_leftright.c a portaudio/pa_tests/patest_longsine.c a portaudio/pa_tests/patest_many.c a portaudio/pa_tests/patest_maxsines.c a portaudio/pa_tests/patest_multi_sine.c a portaudio/pa_tests/patest_out_underflow.c a portaudio/pa_tests/patest_pink.c a portaudio/pa_tests/patest_prime.c a portaudio/pa_tests/patest_read_record.c a portaudio/pa_tests/patest_record.c a portaudio/pa_tests/patest_ringmix.c a portaudio/pa_tests/patest_saw.c a portaudio/pa_tests/patest_sine.c a portaudio/pa_tests/patest_sine8.c a portaudio/pa_tests/patest_sine_formats.c a portaudio/pa_tests/patest_sine_time.c a portaudio/pa_tests/patest_start_stop.c a portaudio/pa_tests/patest_stop.c a portaudio/pa_tests/patest_sync.c a portaudio/pa_tests/patest_toomanysines.c a portaudio/pa_tests/patest_underflow.c a portaudio/pa_tests/patest_wire.c a portaudio/pa_tests/patest_write_sine.c a portaudio/pa_tests/pa_devs.c a portaudio/pa_tests/pa_fuzz.c a portaudio/pa_tests/pa_minlat.c a portaudio/pa_tests/README.txt a portaudio/pa_unix/pa_unix_hostapis.c a portaudio/pa_unix/pa_unix_util.c b portaudio/pa_unix_oss/low_latency_tip.txt a portaudio/pa_unix_oss/pa_unix_oss.c a portaudio/pa_unix_oss/recplay.c a portaudio/pa_win/pa_win_hostapis.c a portaudio/pa_win/pa_win_util.c a portaudio/pa_win/pa_x86_plain_converters.c a portaudio/pa_win/pa_x86_plain_converters.h a portaudio/pa_win/dev-cpp/Makefile-dll a portaudio/pa_win/dev-cpp/Makefile-static a portaudio/pa_win/dev-cpp/portaudio-dll.dev a portaudio/pa_win/dev-cpp/portaudio-static.dev a portaudio/pa_win/dev-cpp/readme.txt a portaudio/pa_win/msvc/clean.bat a portaudio/pa_win/msvc/make.bat a portaudio/pa_win/msvc/Makefile.msvc a portaudio/pa_win/msvc/portaudio.def a portaudio/pa_win/msvc/readme.txt a portaudio/pa_win/msvc/setenv.bat a portaudio/pa_win_ds/dsound_wrapper.c a portaudio/pa_win_ds/dsound_wrapper.h a portaudio/pa_win_ds/pa_win_ds.c a portaudio/pa_win_wmme/pa_win_wmme.c a portaudio/pa_win_wmme/pa_win_wmme.h a portaudio/testcvs/changeme.txt b portaudio_test/portaudio_test.dsp a runtime/bug.lsp a runtime/evalenv.lsp a runtime/follow.lsp a runtime/init.lsp a runtime/nyqmisc.lsp a runtime/printrec.lsp a runtime/profile.lsp a runtime/seq.lsp a runtime/seqfnint.lsp a runtime/sndfnint.lsp a runtime/stk.lsp a runtime/test.lsp a runtime/xlinit.lsp a runtime/fileio.lsp a runtime/nyinit.lsp a runtime/nyquist.lsp a runtime/dspprims.lsp a runtime/misc.lsp a runtime/seqmidi.lsp a runtime/nyquist-plot.txt b runtime/rawwaves/sinewave.raw a snd/sndnt.h a snd/sndrs6k.h a snd/audio.c a snd/sndsystemmac.h a snd/audiolinux.c a snd/sndsystem.c a snd/sndwin32.c a snd/audiomac.c a snd/sndsystem.h a snd/sndwin32.h a snd/audiomac.h a snd/audiopa.c a snd/sndlinux.c a snd/sndcvt.c a snd/wxsnd.h a snd/audionone.c a snd/sndwrite.h a snd/wxsnd.cpp a snd/audiooss.c a snd/sndfaillinux.c a snd/audiors6k.c a snd/audiosgi.c a snd/audiowin32.c a snd/audiowin32.h a snd/ieeecvt.c a snd/ieeecvt.h a snd/rs6kplaydemo.c a snd/snd.c a snd/snd.txt a snd/sndconfig.h a snd/sndfileio.h a snd/sndfreebsd.h a snd/sndhead.h a snd/sndheader.h a snd/sndio.c a snd/sndlinux.h a snd/sndmac.c a snd/sndmac.h a snd/sndfailwin32.c a snd/convert.c a snd/sndheader.c a snd/snd.h a snd/snd.htm a sys/switches.h.template a sys/unix/io.c a sys/unix/io.h a sys/unix/pl a sys/unix/setup a sys/unix/sndsystem.h a sys/unix/switches.h a sys/unix/term.c a sys/unix/term.h a sys/unix/termtest.c a sys/unix/osstuff.c a sys/unix/cmu/backup.script a sys/unix/cmu/tar.script a sys/unix/cmu/update.lsp a sys/unix/linux/system.lsp a sys/unix/linux/Makefile a sys/unix/next/Makefile a sys/unix/next/system.lsp a sys/unix/pmax/Makefile a sys/unix/pmax/system.lsp a sys/unix/rs6k/Makefile a sys/unix/rs6k/plotscript a sys/unix/rs6k/system.lsp a sys/unix/sgi/Makefile a sys/unix/sgi/system.lsp a sys/unix/sparc/Makefile a sys/unix/sparc/system.lsp a sys/win/msvc/sndsystem.h a sys/win/msvc/switches.h a sys/win/msvc/system.lsp a sys/win/msvc/winfun.c a sys/win/msvc/winfun.h a sys/win/msvc/winstuff.c a sys/win/wingui/winmain.h a sys/win/wingui/textio.h a sys/win/wingui/button.h a sys/win/wingui/winmain.cpp a sys/win/wingui/winmain.rc a sys/win/wingui/cppext.h a sys/win/wingui/textio.cpp a sys/win/wingui/longque.cpp a sys/win/wingui/longque.h a sys/win/wingui/winguistuff.c b sys/win/wingui/nycon.ico a sys/win/wingui/resource.h a sys/win/wingui/slider.h b sys/win/wingui/winmain.aps a sys/win/wingui/winmain2.h a sys/win/wingui/xlextstart.c a sys/win/wingui/xlispfns.c a sys/win/wingui/xlispfns.h a sys/win/wingui/typein.h a sys/mac/xlextstart.c a sys/mac/system.lsp a sys/mac/switches.h a sys/mac/sndsystem.h a sys/mac/macdrag.c a sys/mac/macstuff.h a sys/mac/macstuff.c a sys/mac/macptrs.h a sys/mac/macint.h a sys/mac/macint.c a sys/mac/MacHandleEv.h a sys/mac/MacHandleEv.c a sys/mac/MacGlobals.h a sys/mac/macfun.c a sys/mac/MacFileUtils.h a sys/mac/MacFileUtils.c a sys/mac/MacDrag.h a sys/mac/MacCommandWin.h a sys/mac/MacCommandWin.c a sys/mac/MacAE.c a sys/mac/macaboutbox.h a sys/mac/macaboutbox.c a test/alex.lsp a test/alpass.lsp a test/arraystream.lsp a test/articulator1.txt a test/audio.lsp a test/cnvl.lsp a test/comb.lsp a test/convolve.lsp a test/delaytest.lsp a test/eq.lsp a test/fft.lsp a test/gab.lsp a test/gatetest.lsp a test/gr.lsp a test/ifft.lsp a test/ifftnt.lsp a test/init.lsp a test/linux-segfault.lsp a test/midi2.lsp a test/ms2.lsp a test/multiseq.lsp a test/natbug.lsp a test/nonewline.lsp a test/overwrite.lsp a test/product.lsp a test/rbd.lsp a test/readme a test/seqmiditest.lsp a test/shape.lsp a test/sr.lsp a test/stktest.lsp a test/str.lsp a test/temp.gio a test/temp2.gio a test/temp3.gio a test/test.gio a test/tp.lsp a test/variable-resample.lsp a test/warp.lsp a tran/abs.alg a tran/abs.c a tran/abs.h a tran/allpoles.alg a tran/allpoles.c a tran/allpoles.h a tran/buzz.alg a tran/buzz.c a tran/buzz.h a tran/pluck.alg a tran/pluck.c a tran/pluck.h a tran/alpass.alg a tran/alpass.c a tran/alpass.h a tran/alpasscv.alg a tran/alpasscv.c a tran/alpasscv.h a tran/alpassvc.alg a tran/alpassvc.c a tran/alpassvc.h a tran/alpassvv.alg a tran/alpassvv.c a tran/alpassvv.h a tran/amosc.alg a tran/amosc.c a tran/amosc.h a tran/areson.alg a tran/areson.c a tran/areson.h a tran/aresoncv.alg a tran/aresoncv.c a tran/aresoncv.h a tran/aresonvc.alg a tran/aresonvc.c a tran/aresonvc.h a tran/aresonvv.alg a tran/aresonvv.c a tran/aresonvv.h a tran/atone.alg a tran/atone.c a tran/atone.h a tran/atonev.alg a tran/atonev.c a tran/atonev.h a tran/biquad.alg a tran/biquad.c a tran/biquad.h a tran/convolve.alg a tran/coterm.alg a tran/coterm.c a tran/coterm.h a tran/delay.alg a tran/delaycc.c a tran/delaycc.h a tran/delaycv.alg a tran/delaycv.c a tran/delaycv.h a tran/downproto.alg a tran/eqbandv.alg a tran/eqbandvvv.alg a tran/eqbandvvv.c a tran/eqbandvvv.h a tran/exprel.alg a tran/exp.alg a tran/exp.c a tran/exp.h a tran/follow.alg a tran/follow.c a tran/fmosc.c a tran/fmosc.h a tran/follow.h a tran/fromarraystream.alg a tran/fromarraystream.c a tran/fromarraystream.h a tran/fromobject.alg a tran/ifft-old.alg a tran/ifft.alg a tran/gate.alg a tran/fromobject.c a tran/gate.c a tran/fromobject.h a tran/gate.h a tran/innerloop.lsp a tran/ifft.c a tran/ifft.h a tran/init.lsp a tran/instrclar.alg a tran/instrclar.c a tran/instrclar.h a tran/instrclarall.alg a tran/instrclarall.c a tran/instrclarall.h a tran/instrclarfreq.alg a tran/instrclarfreq.c a tran/instrclarfreq.h a tran/instrsax.alg a tran/instrsax.c a tran/instrsax.h a tran/instrsaxall.alg a tran/instrsaxall.c a tran/instrsaxall.h a tran/instrsaxfreq.alg a tran/instrsaxfreq.c a tran/instrsaxfreq.h a tran/integrate.alg a tran/integrate.c a tran/log.alg a tran/log.c a tran/log.h a tran/lpreson.alg a tran/lpreson.c a tran/lpreson.h a tran/offset.alg a tran/integrate.h a tran/maxv.alg a tran/maxv.c a tran/maxv.h a tran/offset.c a tran/chase.alg a tran/oneshot.alg a tran/oneshot.c a tran/chase.c a tran/offset.h a tran/oneshot.h a tran/chase.h a tran/partial.alg a tran/partial.c a tran/clip.alg a tran/osc.alg a tran/osc.c a tran/clip.c a tran/osc.h a tran/partial.h a tran/clip.h a tran/siosc.h a tran/slope.alg a tran/prod.alg a tran/congen.alg a tran/prod.c a tran/prod.h a tran/congen.c a tran/pwl.alg a tran/pwl.c a tran/congen.h a tran/pwl.h a tran/tonev.alg a tran/tonev.c a tran/const.alg a tran/slope.c a tran/slope.h a tran/sqrt.alg a tran/sqrt.c a tran/sqrt.h a tran/tapf.alg a tran/tapf.c a tran/tapf.h a tran/const.c a tran/tapv.alg a tran/tapv.c a tran/const.h a tran/tapv.h a tran/tone.alg a tran/tone.c a tran/tone.h a tran/tonev.h a tran/upsample.alg a tran/upsample.c a tran/quantize.alg a tran/writemake.lsp a tran/white.c a tran/quantize.c a tran/upsample.h a tran/white.alg a tran/white.h a tran/quantize.h a tran/fmosc.alg a tran/recip.alg a tran/writesusp.lsp a tran/recip.c a tran/writetoss.lsp a tran/recip.h a tran/translate.lsp a tran/shape.alg a tran/reson.alg a tran/reson.c a tran/reson.h a tran/resoncv.alg a tran/resoncv.c a tran/resoncv.h a tran/resonvc.alg a tran/resonvc.c a tran/resonvc.h a tran/resonvv.alg a tran/resonvv.c a tran/resonvv.h a tran/sampler.alg a tran/sampler.c a tran/sampler.h a tran/scale.alg a tran/scale.c a tran/scale.h a tran/shape.c a tran/shape.h a tran/sine.alg a tran/sine.c a tran/sine.h a tran/siosc.alg a tran/siosc.c a xlisp/extern.c a xlisp/extern.h a xlisp/osdefs.h a xlisp/osptrs.h a xlisp/path.c a xlisp/xlbfun.c a xlisp/xlcont.c a xlisp/xldmem.h a xlisp/xlfio.c a xlisp/xlglob.c a xlisp/xlimage.c a xlisp/xlinit.c a xlisp/xlio.c a xlisp/xlisp.c a xlisp/xljump.c a xlisp/xllist.c a xlisp/xlmath.c a xlisp/xlpp.c a xlisp/xlprin.c a xlisp/xlstr.c a xlisp/xlsubr.c a xlisp/xlsym.c a xlisp/xlsys.c a xlisp/xlobj.c a xlisp/xlread.c a xlisp/xldbug.c a xlisp/xleval.c a xlisp/xldmem.c a xlisp/xlisp.h a xlisp/xlftab.c nyquist-3.05/convert.dsw0000644000175000000620000000077410144436365014400 0ustar stevestaffMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "convert"=.\convert.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### nyquist-3.05/nyquist.dsp0000644000175000000620000005664511466723256014443 0ustar stevestaff# Microsoft Developer Studio Project File - Name="nyquist" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=nyquist - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "nyquist.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "nyquist.mak" CFG="nyquist - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "nyquist - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "nyquist - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "nyquist - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir ".\WinRel" # PROP BASE Intermediate_Dir ".\WinRel" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\WinRel" # PROP Intermediate_Dir ".\WinRel" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /YX /c # ADD CPP /nologo /MT /W3 /GX /O2 /I ".\xlisp" /I ".\snd" /I ".\nyqsrc" /I ".\tran" /I ".\cmt" /I ".\nyqstk" /I ".\nyqstk\include" /I ".\sys\win\msvc" /I ".\fft" /I ".\portaudio\pa_common" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "CMTSTUFF" /D "PA_NO_ASIO" /D "PA_NO_DS" /D "STK_NYQUIST" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 wsock32.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "nyquist - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir ".\WinDebug" # PROP BASE Intermediate_Dir ".\WinDebug" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\WinDebug" # PROP Intermediate_Dir ".\WinDebug" # PROP Ignore_Export_Lib 0 # ADD BASE CPP /nologo /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /YX /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".\xlisp" /I ".\snd" /I ".\nyqsrc" /I ".\tran" /I ".\cmt" /I ".\nyqstk" /I ".\nyqstk\include" /I ".\sys\win\msvc" /I ".\fft" /I ".\portaudio\pa_common" /D "STK_NYQUIST" /D "__LITTLE_ENDIAN__" /D "_CONSOLE" /D "CMTSTUFF" /D "PA_NO_ASIO" /D "PA_NO_DS" /D "WIN32" /D "_DEBUG" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 # ADD LINK32 wsock32.lib winmm.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib /nologo /subsystem:console /debug /machine:I386 !ENDIF # Begin Target # Name "nyquist - Win32 Release" # Name "nyquist - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" # Begin Source File SOURCE=.\tran\abs.c # End Source File # Begin Source File SOURCE=.\nyqsrc\add.c # End Source File # Begin Source File SOURCE=.\tran\allpoles.c # End Source File # Begin Source File SOURCE=.\tran\alpass.c # End Source File # Begin Source File SOURCE=.\tran\alpasscv.c # End Source File # Begin Source File SOURCE=.\tran\alpassvv.c # End Source File # Begin Source File SOURCE=.\tran\amosc.c # End Source File # Begin Source File SOURCE=.\tran\areson.c # End Source File # Begin Source File SOURCE=.\tran\aresoncv.c # End Source File # Begin Source File SOURCE=.\tran\aresonvc.c # End Source File # Begin Source File SOURCE=.\tran\aresonvv.c # End Source File # Begin Source File SOURCE=.\tran\atone.c # End Source File # Begin Source File SOURCE=.\tran\atonev.c # End Source File # Begin Source File SOURCE=.\snd\audiopa.c # End Source File # Begin Source File SOURCE=.\nyqsrc\avg.c # End Source File # Begin Source File SOURCE=.\tran\biquad.c # End Source File # Begin Source File SOURCE=.\tran\buzz.c # End Source File # Begin Source File SOURCE=.\cmt\cext.c # End Source File # Begin Source File SOURCE=.\tran\chase.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Clarinet.cpp # End Source File # Begin Source File SOURCE=.\cmt\cleanup.c # End Source File # Begin Source File SOURCE=.\tran\clip.c # End Source File # Begin Source File SOURCE=.\cmt\cmdline.c # End Source File # Begin Source File SOURCE=.\cmt\cmtcmd.c # End Source File # Begin Source File SOURCE=.\nyqsrc\compose.c # End Source File # Begin Source File SOURCE=.\tran\congen.c # End Source File # Begin Source File SOURCE=.\tran\const.c # End Source File # Begin Source File SOURCE=.\nyqsrc\convolve.c # End Source File # Begin Source File SOURCE=.\tran\coterm.c # End Source File # Begin Source File SOURCE=.\nyqsrc\debug.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Delay.cpp # End Source File # Begin Source File SOURCE=.\tran\delaycc.c # End Source File # Begin Source File SOURCE=.\tran\delaycv.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\DelayL.cpp # End Source File # Begin Source File SOURCE=.\nyqsrc\downsample.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Envelope.cpp # End Source File # Begin Source File SOURCE=.\tran\eqbandvvv.c # End Source File # Begin Source File SOURCE=.\tran\exp.c # End Source File # Begin Source File SOURCE=.\xlisp\extern.c # End Source File # Begin Source File SOURCE=.\nyqsrc\falloc.c # End Source File # Begin Source File SOURCE=.\nyqsrc\ffilterkit.c # End Source File # Begin Source File SOURCE=.\nyqsrc\fft.c # End Source File # Begin Source File SOURCE=.\fft\fftn.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Filter.cpp # End Source File # Begin Source File SOURCE=.\tran\fmosc.c # End Source File # Begin Source File SOURCE=.\tran\follow.c # End Source File # Begin Source File SOURCE=.\tran\fromarraystream.c # End Source File # Begin Source File SOURCE=.\tran\fromobject.c # End Source File # Begin Source File SOURCE=.\tran\gate.c # End Source File # Begin Source File SOURCE=.\nyqsrc\handlers.c # End Source File # Begin Source File SOURCE=.\snd\ieeecvt.c # End Source File # Begin Source File SOURCE=.\tran\ifft.c # End Source File # Begin Source File SOURCE=.\nyqstk\instr.cpp # End Source File # Begin Source File SOURCE=.\tran\instrclar.c # End Source File # Begin Source File SOURCE=.\tran\instrclarall.c # End Source File # Begin Source File SOURCE=.\tran\instrclarfreq.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Instrmnt.cpp # End Source File # Begin Source File SOURCE=.\tran\instrsax.c # End Source File # Begin Source File SOURCE=.\tran\instrsaxall.c # End Source File # Begin Source File SOURCE=.\tran\instrsaxfreq.c # End Source File # Begin Source File SOURCE=.\tran\integrate.c # End Source File # Begin Source File SOURCE=.\nyqsrc\inverse.c # End Source File # Begin Source File SOURCE=.\nyqsrc\local.c # End Source File # Begin Source File SOURCE=.\tran\log.c # End Source File # Begin Source File SOURCE=.\nyqsrc\lpanal.c # End Source File # Begin Source File SOURCE=.\tran\lpreson.c # End Source File # Begin Source File SOURCE=.\tran\maxv.c # End Source File # Begin Source File SOURCE=.\cmt\mem.c # End Source File # Begin Source File SOURCE=.\cmt\midifile.c # End Source File # Begin Source File SOURCE=.\cmt\midifns.c # End Source File # Begin Source File SOURCE=.\cmt\moxc.c # End Source File # Begin Source File SOURCE=.\nyqsrc\multiread.c # End Source File # Begin Source File SOURCE=.\nyqsrc\multiseq.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Noise.cpp # End Source File # Begin Source File SOURCE=.\tran\offset.c # End Source File # Begin Source File SOURCE=.\tran\oneshot.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\OneZero.cpp # End Source File # Begin Source File SOURCE=.\tran\osc.c # End Source File # Begin Source File SOURCE=.\tran\partial.c # End Source File # Begin Source File SOURCE=.\xlisp\path.c # End Source File # Begin Source File SOURCE=.\tran\pluck.c # End Source File # Begin Source File SOURCE=.\tran\prod.c # End Source File # Begin Source File SOURCE=.\tran\pwl.c # End Source File # Begin Source File SOURCE=.\tran\quantize.c # End Source File # Begin Source File SOURCE=.\tran\recip.c # End Source File # Begin Source File SOURCE=.\cmt\record.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\ReedTabl.cpp # End Source File # Begin Source File SOURCE=.\nyqsrc\resamp.c # End Source File # Begin Source File SOURCE=.\nyqsrc\resampv.c # End Source File # Begin Source File SOURCE=.\tran\reson.c # End Source File # Begin Source File SOURCE=.\tran\resoncv.c # End Source File # Begin Source File SOURCE=.\tran\resonvc.c # End Source File # Begin Source File SOURCE=.\tran\resonvv.c # End Source File # Begin Source File SOURCE=.\tran\sampler.c # End Source File # Begin Source File SOURCE=.\nyqsrc\samples.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Saxofony.cpp # End Source File # Begin Source File SOURCE=.\tran\scale.c # End Source File # Begin Source File SOURCE=.\cmt\seq.c # End Source File # Begin Source File SOURCE=.\nyqsrc\seqext.c # End Source File # Begin Source File SOURCE=.\nyqsrc\seqfnint.c # End Source File # Begin Source File SOURCE=.\nyqsrc\seqinterf.c # End Source File # Begin Source File SOURCE=.\cmt\seqmread.c # End Source File # Begin Source File SOURCE=.\cmt\seqmwrite.c # End Source File # Begin Source File SOURCE=.\cmt\seqread.c # End Source File # Begin Source File SOURCE=.\cmt\seqwrite.c # End Source File # Begin Source File SOURCE=.\tran\shape.c # End Source File # Begin Source File SOURCE=.\tran\sine.c # End Source File # Begin Source File SOURCE=.\tran\siosc.c # End Source File # Begin Source File SOURCE=.\tran\slope.c # End Source File # Begin Source File SOURCE=.\snd\snd.c # End Source File # Begin Source File SOURCE=.\snd\sndcvt.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndfail.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndfnint.c # End Source File # Begin Source File SOURCE=.\snd\sndheader.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndmax.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndread.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndseq.c # End Source File # Begin Source File SOURCE=.\snd\sndwin32.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndwritepa.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sound.c # End Source File # Begin Source File SOURCE=.\tran\sqrt.c # End Source File # Begin Source File SOURCE=.\nyqsrc\stats.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Stk.cpp # End Source File # Begin Source File SOURCE=.\nyqstk\stkinit.cpp # End Source File # Begin Source File SOURCE=.\tran\tapf.c # End Source File # Begin Source File SOURCE=.\tran\tapv.c # End Source File # Begin Source File SOURCE=.\cmt\tempomap.c # End Source File # Begin Source File SOURCE=.\cmt\timebase.c # End Source File # Begin Source File SOURCE=.\tran\tone.c # End Source File # Begin Source File SOURCE=.\tran\tonev.c # End Source File # Begin Source File SOURCE=.\tran\upsample.c # End Source File # Begin Source File SOURCE=.\cmt\userio.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\WaveLoop.cpp # End Source File # Begin Source File SOURCE=.\tran\white.c # End Source File # Begin Source File SOURCE=.\sys\win\msvc\winfun.c # End Source File # Begin Source File SOURCE=.\sys\win\msvc\winstuff.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\WvIn.cpp # End Source File # Begin Source File SOURCE=.\xlisp\xlbfun.c # End Source File # Begin Source File SOURCE=.\xlisp\xlcont.c # End Source File # Begin Source File SOURCE=.\xlisp\xldbug.c # End Source File # Begin Source File SOURCE=.\xlisp\xldmem.c # End Source File # Begin Source File SOURCE=.\xlisp\xleval.c # End Source File # Begin Source File SOURCE=.\xlisp\xlfio.c # End Source File # Begin Source File SOURCE=.\xlisp\xlftab.c # End Source File # Begin Source File SOURCE=.\xlisp\xlglob.c # End Source File # Begin Source File SOURCE=.\xlisp\xlimage.c # End Source File # Begin Source File SOURCE=.\xlisp\xlinit.c # End Source File # Begin Source File SOURCE=.\xlisp\xlio.c # End Source File # Begin Source File SOURCE=.\xlisp\xlisp.c # End Source File # Begin Source File SOURCE=.\xlisp\xljump.c # End Source File # Begin Source File SOURCE=.\xlisp\xllist.c # End Source File # Begin Source File SOURCE=.\xlisp\xlmath.c # End Source File # Begin Source File SOURCE=.\xlisp\xlobj.c # End Source File # Begin Source File SOURCE=.\xlisp\xlpp.c # End Source File # Begin Source File SOURCE=.\xlisp\xlprin.c # End Source File # Begin Source File SOURCE=.\xlisp\xlread.c # End Source File # Begin Source File SOURCE=.\xlisp\xlstr.c # End Source File # Begin Source File SOURCE=.\xlisp\xlsubr.c # End Source File # Begin Source File SOURCE=.\xlisp\xlsym.c # End Source File # Begin Source File SOURCE=.\xlisp\xlsys.c # End Source File # Begin Source File SOURCE=.\nyqsrc\yin.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" # Begin Source File SOURCE=.\tran\abs.h # End Source File # Begin Source File SOURCE=.\nyqsrc\add.h # End Source File # Begin Source File SOURCE=.\tran\allpoles.h # End Source File # Begin Source File SOURCE=.\tran\alpass.h # End Source File # Begin Source File SOURCE=.\tran\alpassvv.h # End Source File # Begin Source File SOURCE=.\tran\amosc.h # End Source File # Begin Source File SOURCE=.\tran\areson.h # End Source File # Begin Source File SOURCE=.\tran\aresoncv.h # End Source File # Begin Source File SOURCE=.\tran\aresonvc.h # End Source File # Begin Source File SOURCE=.\tran\aresonvv.h # End Source File # Begin Source File SOURCE=.\tran\atone.h # End Source File # Begin Source File SOURCE=.\tran\atonev.h # End Source File # Begin Source File SOURCE=.\snd\audiont.h # End Source File # Begin Source File SOURCE=.\snd\audiowin32.h # End Source File # Begin Source File SOURCE=.\nyqsrc\avg.h # End Source File # Begin Source File SOURCE=.\tran\biquad.h # End Source File # Begin Source File SOURCE=.\tran\buzz.h # End Source File # Begin Source File SOURCE=.\cmt\cext.h # End Source File # Begin Source File SOURCE=.\tran\chase.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Clarinet.h # End Source File # Begin Source File SOURCE=.\cmt\cleanup.h # End Source File # Begin Source File SOURCE=.\tran\clip.h # End Source File # Begin Source File SOURCE=.\cmt\cmdline.h # End Source File # Begin Source File SOURCE=.\cmt\cmtcmd.h # End Source File # Begin Source File SOURCE=.\nyqsrc\compose.h # End Source File # Begin Source File SOURCE=.\tran\congen.h # End Source File # Begin Source File SOURCE=.\tran\const.h # End Source File # Begin Source File SOURCE=.\nyqsrc\convolve.h # End Source File # Begin Source File SOURCE=.\tran\coterm.h # End Source File # Begin Source File SOURCE=.\nyqsrc\debug.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Delay.h # End Source File # Begin Source File SOURCE=.\tran\delay.h # End Source File # Begin Source File SOURCE=.\tran\delaycc.h # End Source File # Begin Source File SOURCE=.\tran\delaycv.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\DelayL.h # End Source File # Begin Source File SOURCE=.\nyqsrc\downsample.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Envelope.h # End Source File # Begin Source File SOURCE=.\tran\exp.h # End Source File # Begin Source File SOURCE=.\xlisp\extern.h # End Source File # Begin Source File SOURCE=.\nyqsrc\falloc.h # End Source File # Begin Source File SOURCE=.\nyqsrc\ffilterkit.h # End Source File # Begin Source File SOURCE=.\nyqsrc\fft.h # End Source File # Begin Source File SOURCE=.\fft\fftn.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Filter.h # End Source File # Begin Source File SOURCE=.\tran\fmosc.h # End Source File # Begin Source File SOURCE=.\tran\follow.h # End Source File # Begin Source File SOURCE=.\tran\fromarraystream.h # End Source File # Begin Source File SOURCE=.\tran\fromobject.h # End Source File # Begin Source File SOURCE=.\tran\gate.h # End Source File # Begin Source File SOURCE=.\nyqstk\globals.h # End Source File # Begin Source File SOURCE=.\snd\ieeecvt.h # End Source File # Begin Source File SOURCE=.\tran\ifft.h # End Source File # Begin Source File SOURCE=.\nyqstk\instr.h # End Source File # Begin Source File SOURCE=.\tran\instrclar.h # End Source File # Begin Source File SOURCE=.\tran\instrclarfreq.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Instrmnt.h # End Source File # Begin Source File SOURCE=.\tran\instrsax.h # End Source File # Begin Source File SOURCE=.\tran\instrsaxfreq.h # End Source File # Begin Source File SOURCE=.\tran\integrate.h # End Source File # Begin Source File SOURCE=.\nyqsrc\inverse.h # End Source File # Begin Source File SOURCE=.\tran\log.h # End Source File # Begin Source File SOURCE=.\tran\lpanal.h # End Source File # Begin Source File SOURCE=.\tran\lpreson.h # End Source File # Begin Source File SOURCE=.\tran\maxv.h # End Source File # Begin Source File SOURCE=.\cmt\mem.h # End Source File # Begin Source File SOURCE=.\cmt\midifile.h # End Source File # Begin Source File SOURCE=.\cmt\midifns.h # End Source File # Begin Source File SOURCE=.\cmt\moxc.h # End Source File # Begin Source File SOURCE=.\nyqsrc\multiread.h # End Source File # Begin Source File SOURCE=.\nyqsrc\multiseq.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Noise.h # End Source File # Begin Source File SOURCE=.\tran\offset.h # End Source File # Begin Source File SOURCE=.\tran\oneshot.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\OneZero.h # End Source File # Begin Source File SOURCE=.\tran\osc.h # End Source File # Begin Source File SOURCE=.\tran\partial.h # End Source File # Begin Source File SOURCE=.\tran\prod.h # End Source File # Begin Source File SOURCE=.\tran\pwl.h # End Source File # Begin Source File SOURCE=.\tran\quantize.h # End Source File # Begin Source File SOURCE=.\tran\recip.h # End Source File # Begin Source File SOURCE=.\cmt\record.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\ReedTabl.h # End Source File # Begin Source File SOURCE=.\nyqsrc\resamp.h # End Source File # Begin Source File SOURCE=.\nyqsrc\resampv.h # End Source File # Begin Source File SOURCE=.\tran\reson.h # End Source File # Begin Source File SOURCE=.\tran\resoncv.h # End Source File # Begin Source File SOURCE=.\tran\resonvc.h # End Source File # Begin Source File SOURCE=.\tran\resonvv.h # End Source File # Begin Source File SOURCE=.\tran\sampler.h # End Source File # Begin Source File SOURCE=.\nyqsrc\samples.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Saxofony.h # End Source File # Begin Source File SOURCE=.\tran\scale.h # End Source File # Begin Source File SOURCE=.\cmt\seq.h # End Source File # Begin Source File SOURCE=.\nyqsrc\seqext.h # End Source File # Begin Source File SOURCE=.\nyqsrc\seqinterf.h # End Source File # Begin Source File SOURCE=.\cmt\seqmread.h # End Source File # Begin Source File SOURCE=.\cmt\seqmwrite.h # End Source File # Begin Source File SOURCE=.\cmt\seqread.h # End Source File # Begin Source File SOURCE=.\cmt\seqwrite.h # End Source File # Begin Source File SOURCE=.\tran\shape.h # End Source File # Begin Source File SOURCE=.\tran\sine.h # End Source File # Begin Source File SOURCE=.\tran\siosc.h # End Source File # Begin Source File SOURCE=.\tran\slope.h # End Source File # Begin Source File SOURCE=.\snd\snd.h # End Source File # Begin Source File SOURCE=.\snd\sndheader.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndmax.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndread.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndseq.h # End Source File # Begin Source File SOURCE=.\snd\sndwin32.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndwrite.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sound.h # End Source File # Begin Source File SOURCE=.\tran\sqrt.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\Stk.h # End Source File # Begin Source File SOURCE=.\nyqstk\stkinit.h # End Source File # Begin Source File SOURCE=.\tran\tapv.h # End Source File # Begin Source File SOURCE=.\cmt\tempomap.h # End Source File # Begin Source File SOURCE=.\cmt\timebase.h # End Source File # Begin Source File SOURCE=.\tran\tone.h # End Source File # Begin Source File SOURCE=.\tran\tonev.h # End Source File # Begin Source File SOURCE=.\tran\upsample.h # End Source File # Begin Source File SOURCE=.\cmt\userio.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\WaveLoop.h # End Source File # Begin Source File SOURCE=.\tran\white.h # End Source File # Begin Source File SOURCE=.\sys\win\msvc\winfun.h # End Source File # Begin Source File SOURCE=.\nyqstk\include\WvIn.h # End Source File # Begin Source File SOURCE=.\xlisp\xldmem.h # End Source File # Begin Source File SOURCE=.\xlisp\xlisp.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" # End Group # Begin Group "portaudio-c" # PROP Default_Filter "c" # Begin Source File SOURCE=.\portaudio\pa_common\pa_allocation.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_converters.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_cpuload.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_dither.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_front.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_process.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_skeleton.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_stream.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_win\pa_win_hostapis.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_win\pa_win_util.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_win_wmme\pa_win_wmme.c # End Source File # End Group # Begin Group "portaudio-h" # PROP Default_Filter "h" # Begin Source File SOURCE=.\portaudio\pa_common\pa_allocation.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_converters.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_cpuload.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_dither.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_process.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_stream.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_util.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_win_wmme\pa_win_wmme.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\portaudio.h # End Source File # End Group # End Target # End Project nyquist-3.05/sys/0002755000175000000620000000000011537433131013004 5ustar stevestaffnyquist-3.05/sys/unix/0002755000175000000620000000000011537433131013767 5ustar stevestaffnyquist-3.05/sys/unix/switches.h0000644000175000000620000001120011466723256015774 0ustar stevestaff/* see sys/switches.h.template */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm major reorganization of conditional compilation in Nyquist */ #define HAS_STDLIB_H 1 #define HAS_SYS_TYPES_H 1 #define HAS_SYS_STAT_H 1 #undef HAS_STAT_H #undef HAS_MALLOC_H #define HAS_GETTIMEOFDAY 1 // I think that READ_LINE prevents user from typing control characters to // get info during lisp execution. This needs to be tested. Using READ_LINE // is preventing any character echoing now, maybe due to new "improved" // command line handling added recently. -RBD // #define READ_LINE 1 /* this is defined in xlisp.h - RBD #if i386 #define XL_LITTLE_ENDIAN 1 #elif __i386__ #define XL_LITTLE_ENDIAN 1 #else #define XL_BIG_ENDIAN 1 #endif */ #undef USE_RANDOM #define USE_RAND 1 /* define this to be printf, or define your own fn of the form void nyquist_printf(char *format, ...); (for a GUI) */ #define nyquist_printf printf #if __APPLE__ && __GNUC__ /* Mac OS X */ #define NEED_ULONG 1 #else #include #undef NEED_ULONG #endif #undef NEED_USHORT #define NEED_BYTE 1 #define NEED_ROUND 1 #undef NEED_DEFINE_MALLOC /* definitions for libsndfile */ /* Target processor clips on negative float to int conversion */ /* (true on i386 and PPC) */ #define CPU_CLIPS_NEGATIVE 1 /* Target processor clips on positive float to int conversion */ /* (true on i386 and PPC) */ #define CPU_CLIPS_POSITIVE 1 #ifdef __APPLE__ #if defined (__LITTLE_ENDIAN__) /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 1 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 0 #else /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 0 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 1 #endif #else #if defined(__linux__) || defined(__GLIBC__) #include #if __BYTE_ORDER == __LITTLE_ENDIAN /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 1 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 0 #else /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 0 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 1 #endif #else /* default is little endian */ /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 1 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 0 #endif #endif /* Set to 1 if S_IRGRP is defined */ #define HAVE_DECL_S_IRGRP 1 /* Set to 1 if the compiler supports the struct hack. */ #define HAVE_FLEXIBLE_ARRAY 1 /* Define to 1 if you have the `fsync' function. */ #define HAVE_FSYNC 1 /* Define to 1 if you have the `gmtime' function. */ #define HAVE_GMTIME 1 /* Define to 1 if you have the `gmtime_r' function. */ #define HAVE_GMTIME_R 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define if you have C99's lrint function. */ #define HAVE_LRINT 1 /* Define if you have C99's lrintf function. */ #define HAVE_LRINTF 1 /* Define to 1 if you have the `snprintf' function. */ #define HAVE_SNPRINTF 1 /* Define to 1 if the system has the type `ssize_t'. */ #define HAVE_SSIZE_T 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 /* Set to 1 if compiling for MacOSX */ #ifdef __APPLE__ #define OS_IS_MACOSX 1 #else #define OS_IS_MACOSX 0 #endif /* Set to 1 if compiling for Win32 */ #define OS_IS_WIN32 0 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Set to 1 to use the native windows API */ #define USE_WINDOWS_API 0 #ifdef __GNUC__ #define SIZEOF_LONG_LONG 8 #endif /* The size of `int64_t', as computed by sizeof. */ #define SIZEOF_INT64_T 8 /* The size of long as computed by sizeof. */ #define SIZEOF_LONG 4 /* Set to long if unknown */ #define SIZEOF_SF_COUNT_T 8 /* explicitly choose a platform */ #define UNIX 1 #undef WINDOWS #undef MICROSOFT #undef DOS #undef MACINTOSH #define BUFFERED_SYNCHRONOUS_INPUT 1 #define SPACE_FOR_PLAY 10000 #define MAX_CHANNELS 16 /* this will enable code to read midi files, etc. */ #define CMTSTUFF 1 /* NYQUIST tells some CMT code that we're really in * XLISP and NYQUIST */ #define NYQUIST 1 #include "swlogic.h" nyquist-3.05/sys/unix/term.c0000644000175000000620000000565411471407277015123 0ustar stevestaff/* term.c -- Routines for managing terminal I/O settings by Alan Cox. * From LJ 17 */ /* Thanks to Dave Cook for rescuing it */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm include ioctl.h and declare void ctcinit(); */ #include #ifndef __APPLE__ #include #endif #include #include #include #include #include void ctcinit(); /* This will be used for new terminal settings. */ static struct termios current; /* This will hold the initial state so that we can restor it later. */ static struct termios initial; /* Restor the termianl settings to those saved when term_init was called. */ void term_restore(void) { tcsetattr(0, TCSANOW, &initial); } /* Clean up termianl; called on exit. */ void term_exit() { term_restore(); } /* Will be called when contrl-Z is pressed; * this correctly handles the terminal. */ void term_ctrlz() { signal(SIGTSTP, term_ctrlz); term_restore(); kill(getpid(), SIGSTOP); } /* Will be called when the application is continued * after having been stopped. */ void term_cont() { signal(SIGCONT, term_cont); tcsetattr(0, TCSANOW, ¤t); } /* Needs to be called to initialize the terminal. */ void term_init(void) { /* If stdin isn't a terminal this fails. But then so does tcsetattr(), so it doesn't matter. */ tcgetattr(0, &initial); /* Save a copy to work with later. */ current = initial; /* We _must_ clean up when we exit. */ /* signal(SIGINT, term_exit); */ ctcinit(); /* XLisp wants to catch ctrl C */ signal(SIGQUIT, term_exit); /* Control-Z must also be handled. */ signal(SIGTSTP, term_ctrlz); signal(SIGCONT, term_cont); atexit(term_exit); } /* Set character-by-character input mode. */ void term_character(void) { /* One or more characters are sufficient to cause a read return. */ current.c_cc[VMIN] = 1; /* No timeout; read waits forever until ready. */ current.c_cc[VTIME] = 0; /* Line-by-line mode off */ current.c_lflag &= ~ICANON; #ifndef READ_LINE current.c_lflag &= ~ECHO; #endif tcsetattr(0, TCSANOW, ¤t); } /* Return to line-by-line input mode. */ void term_line(void) { current.c_lflag |= ICANON; tcsetattr(0, TCSANOW, ¤t); } #define ERROR(s) return (perror(s), -1) /* term_testchar -- tell whether character is ready or not, * * if ready, return it, otherwise return -2 */ int term_testchar() { int n; char c; if (ioctl(0, FIONREAD, &n) < 0) ERROR("IOgetchar"); if (n == 0) return -2; switch(read(0, &c, 1)) { case 1: return c; case 0: return EOF; default: ERROR("IOgetchar-read"); } } /* term_getchar -- get a character (block if necessary) */ /**/ int term_getchar() { char c; int rslt = read(0, &c, 1); return (rslt == 1 ? c : EOF); } nyquist-3.05/sys/unix/README.txt0000644000175000000620000001412011512414056015457 0ustar stevestaffREADME.txt -- Nyquist information for Unix systems UNIX INSTALLATION ================= For Unix systems, Nyquist is distributed as a compressed file of sources named nyqsrc3.zip, where is the version number (e.g. v3.01 was in nyqsrc301.zip). To install Nyquist, copy nyqsrc3.zip) to the directory on your machine where you would like to install Nyquist. Note 1: you will need the "normal tool chain" consisting of the Gnu C/C++ compiler, linker, C/C++ runtime libraries, autoconf, libtool, automake, etc. Most linux installations already have this, but some more recent trimmed-down installations for netbooks and consumer-oriented computers do not have compilers installed by default. Note 2: There are two main unix versions of Nyquist: alsa and nonalsa. The alsa version is probably what you want. This version uses ALSA, the Linux audio system. This has also become standard, but your machine might not have the ALSA development package (probably named libasound2-dev), so you might have to install it. If you find you are missing "asound", you are missing and need to install the ALSA developmnent package. The nonalsa version is a special version for Debian linux. The ONLY difference is that it omits -lasound from the link step, so it does not try to link with ALSA. I assume this works because the PortAudio library which is included in the Nyquist sources configures itself differently on Debian and doesn't need ALSA. After unzipping sources, type: gunzip nyqsrc3.zip cd nyquist # In the following line, Debian linux users should # type "nonalsa" in place of "alsa": ln -s sys/unix/alsa/Makefile Makefile setenv XLISPPATH `pwd`/runtime:`pwd`/lib make (For bash shell users, instead of the setenv command, use this: export XLISPPATH=`pwd`/runtime:`pwd`/lib ) The first line creates a nyquist directory and some subdirectories. The second line (cd) changes directories to the new nyquist directory. The third line (ln) makes a link from the top-level directory to the Makefile for your system. In place of "alsa" in sys/unix/alsa/Makefile, you should substitute your system type. Current systems are alsa, nonalsa, next, pmax, rs6k, sgi, and sparc, but since only the alsa and nonalsa versions have been tested in recent years, do not expect anything else to work. The setenv (or export) command tells Nyquist where to search for lisp files to be loaded when a file is not found in the current directory. See SHELL STARTUP below for information about how to automate this. RUNNING NYQUIST FROM THE COMMAND LINE ===================================== Assuming the make completes successfully, you can run Nyquist as follows: ./ny When you get the prompt, you may begin typing expressions such as the ones in the following "Examples" section in the Nyquist manual. (See doc/nyquistman.pdf or doc/home.html). RUNNING NYQUIST USING NyquistIDE ===================================== One you establish that Nyquist (ny) is working from the command line, you should try using NyquistIDE, the Java-based Nyquist development environment. First, make jny executable (do this only once when you install Nyquist): chmod +x jny Then try running jNyqIDE by typing: ./jny If the NyquistIDE window does not appear, make sure you have Java installed (if not, you probably already encountered errors when you ran the make command.) You can also try recompiling the Java files. Note that jnyqide/SpecialMacHandler.java will NOT compile under non-OS X systems. The Makefile renames this file to "hide" it from the Java compiler, compiles all the remaining java files, and then restores jnyqide/SpecialMacHandler.java: make jnyqide/jNyqIDE.jar NYQUIST SEARCH PATH UNDER NyquistIDE ==================================== Note: With Linux and Mac OS X, jNyqIDE defines the environment passed to Nyquist. If you set XLISPPATH as shown above, it will be passed along to Nyquist under jNyqIDE. If not, a default XLISPPATH will have the lib and runtime directories only. This does not apply to Windows because even though the environment is there, the Windows version of Nyquist reads the XLISPPATH from the Registry. You can also specify the search path by creating the file nyquist/xlisppath, which should have colon-separated paths on a single (long) line of text. This file will override the environment variable XLISPPATH. MORE DETAILS ============ It is good to have USER in the environment with your user ID. This string is used to construct some file names. NyquistIDE will look for it in the environment. You can also specify your user ID using the file nyquist/user, but if you have a shared installation of Nyquist, this will not be very useful. Note: Nyquist looks for the file init.lsp in the current directory. If you look in the init.lsp in runtime, you will notice two things. First, init.lsp loads nyquist.lsp from the Nyquist directory, and second, init.lsp loads system.lsp which in turn defines the macro play. Normally, Nyquist plays audio through the PortAudio library, which should work on any system. An alternative is to save audio to a file and invoke a local non-Nyquist program to play the sound file. You can modify system.lsp to accomplish this. SHELL STARTUP ============= The (runtime directory should always be on your XLISPPATH when you run Nyquist, so you may want to set XLISPPATH in your shell startup file, e.g. .cshrc. Which shell are you using? echo $SHELL will tell you. If you use /bin/bash, your startup file is probably ~/.profile. (Remember that "~/" means your home directory, so the file will be something like /home/rbd/.profile). In this file, you can add a line such as: export XLISPPATH="/home/rbd/nyquist/runtime:/home/rbd/nyquist/lib" Do not use the shorthand `pwd`/runtime, because `pwd` returns the current working directory, which is not going to be your Nyquist directory when .profile is loaded. If you use /bin/csh (the C Shell), your startup file is probably ~/.cshrc. (Remember that "~/" means your home directory, so the file will be something like /home/rbd/.profile). In this file, you can add a line such as: setenv XLISPPATH "/home/rbd/nyquist/runtime:/home/rbd/nyquist/lib" nyquist-3.05/sys/unix/nonalsa/0002755000175000000620000000000011537433131015422 5ustar stevestaffnyquist-3.05/sys/unix/nonalsa/Makefile0000644000175000000620000012722111512414056017063 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is NONALSA # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny OPT = -O2 -m32 # OPT = -g -m32 EVERYTHING = $(NY) runtime/system.lsp jnyqide/jNyqIDE.jar \ bin/ser-to-osc bin/test-client CURRENT = $(EVERYTHING) current: $(CURRENT) onlyny: $(NY) runtime/system.lsp JAVASRC = jnyqide/browser.java jnyqide/NyquistThread.java \ jnyqide/Pair.java jnyqide/BareBonesBrowserLaunch.java \ jnyqide/EnvelopeFrame.java jnyqide/Piano_Roll.java \ jnyqide/FindDialog.java jnyqide/PlotFrame.java \ jnyqide/InstrumentCharacteristics.java \ jnyqide/PlotMouseAdapter.java \ jnyqide/Jslide.java jnyqide/PopupListener.java \ jnyqide/LispFileFilter.java jnyqide/PreferencesDialog.java \ jnyqide/MainFrame_AboutBox.java jnyqide/ReplaceDialog.java \ jnyqide/MainFrame.java jnyqide/SpringUtilities.java \ jnyqide/Main.java \ jnyqide/NotFoundDialog.java jnyqide/TextColor.java \ jnyqide/NyqPlot.java jnyqide/Trie.java \ jnyqide/NyquistFile.java jnyqide/WordList.java jnyqide/jNyqIDE.jar: $(JAVASRC) if [ -r jnyqide/SpecialMacHandler.java ] ; then \ mv jnyqide/SpecialMacHandler.java jnyqide/SpecialMacHandler.hidden ;\ fi cd jnyqide; javac *.java mv jnyqide/SpecialMacHandler.hidden jnyqide/SpecialMacHandler.java rm -rf jnyqide/jNyqIDE.jar jar -cfm jnyqide/jNyqIDE.jar jnyqide/manifest.txt jnyqide/*.class # Standard list of includes (common to all unix versions) # Keeping portaudio and libsndfile sources local to nyquist INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Iffts/src \ -Inyqstk/include -Inyqstk -Iportaudio/include -Iportaudio/src/common \ -Iportaudio/src/os/unix \ -Iliblo -Inylsf # system dependent stuff for nonalsa: AUDIOLIBS = CC = gcc LIBPA_PATH = portaudio/lib/.libs LIBLO_PATH = liblo/src/.libs # to enable command line editing, use -DREADLINE. WARNING: THIS WILL # DISABLE THE ABILITY TO INTERRUPT LISP AND USE SOME OTHER HANDY # CONTROL CHARACTERS (You will also need the readline and curses libraries) CFLAGS = -DOSC -DCMTSTUFF $(OPT) $(INCL) \ -DHAVE_LIBPTHREAD=1 -D_FILE_OFFSET_BITS=64 \ -DSTK_NYQUIST -DUSE_VSPRINTF \ -DHAVE_CONFIG_H LN = g++ -m32 AR = ar # to enable command line editing, insert -lreadline -lcurses LFLAGS = $(LIBPA_PATH)/libportaudio.a $(LIBLO_PATH)/liblo.a $(AUDIOLIBS) -lm -lpthread -lrt TAGS: find . ( -name INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o \ xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o \ xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o \ xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o \ xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o \ xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o \ xlisp/xlsym.o xlisp/xlsys.o \ xlisp/path.o tran/abs.o \ tran/allpoles.o tran/alpass.o \ tran/alpasscv.o tran/alpassvv.o \ tran/amosc.o tran/areson.o \ tran/aresonvc.o tran/aresoncv.o \ tran/aresonvv.o tran/atone.o \ tran/atonev.o tran/biquadfilt.o \ tran/buzz.o tran/chase.o \ tran/clip.o tran/congen.o \ tran/const.o tran/coterm.o \ tran/delaycc.o tran/delaycv.o \ tran/eqbandvvv.o tran/exp.o \ tran/follow.o tran/fmosc.o \ tran/fromobject.o tran/fromarraystream.o \ tran/gate.o tran/ifft.o \ tran/instrclar.o tran/instrclarall.o \ tran/instrclarfreq.o tran/instrsax.o \ tran/instrsaxall.o tran/instrsaxfreq.o \ tran/integrate.o tran/log.o \ tran/lpreson.o tran/maxv.o \ tran/offset.o tran/oneshot.o \ tran/osc.o tran/partial.o \ tran/pluck.o tran/prod.o \ tran/pwl.o tran/quantize.o \ tran/recip.o tran/reson.o \ tran/resonvc.o tran/resoncv.o \ tran/resonvv.o tran/sampler.o \ tran/scale.o tran/shape.o \ tran/sine.o tran/siosc.o \ tran/slope.o tran/sqrt.o \ tran/tapf.o tran/tapv.o \ tran/tone.o tran/tonev.o \ tran/upsample.o tran/white.o \ tran/stkrev.o tran/stkpitshift.o \ tran/stkchorus.o tran/instrbow.o \ tran/instrbowedfreq.o tran/instrbanded.o \ tran/instrmandolin.o tran/instrsitar.o \ tran/instrmodalbar.o tran/instrflute.o \ tran/instrflutefreq.o tran/instrfluteall.o \ tran/fmfb.o tran/fmfbv.o \ cmt/cext.o cmt/cleanup.o \ cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o \ cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o \ cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o \ cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nylsf/aiff.o \ nylsf/alaw.o nylsf/au.o \ nylsf/avr.o nylsf/broadcast.o \ nylsf/caf.o nylsf/command.o \ nylsf/common.o nylsf/dither.o \ nylsf/double64.o nylsf/dwd.o \ nylsf/dwvw.o nylsf/file_io.o \ nylsf/flac.o nylsf/float32.o \ nylsf/gsm610.o nylsf/htk.o \ nylsf/ima_adpcm.o nylsf/interleave.o \ nylsf/ircam.o nylsf/macbinary3.o \ nylsf/macos.o nylsf/mat4.o \ nylsf/mat5.o nylsf/ms_adpcm.o \ nylsf/nist.o nylsf/ogg.o \ nylsf/paf.o nylsf/pcm.o \ nylsf/pvf.o nylsf/raw.o \ nylsf/rx2.o nylsf/sd2.o \ nylsf/sds.o nylsf/sndfile.o \ nylsf/strings.o nylsf/svx.o \ nylsf/txw.o nylsf/ulaw.o \ nylsf/voc.o nylsf/vox_adpcm.o \ nylsf/w64.o nylsf/wav.o \ nylsf/wav_w64.o nylsf/wve.o \ nylsf/xi.o nylsf/g72x.o \ nylsf/GSM610/add.o nylsf/GSM610/code.o \ nylsf/GSM610/decode.o nylsf/GSM610/gsm_create.o \ nylsf/GSM610/gsm_decode.o nylsf/GSM610/gsm_destroy.o \ nylsf/GSM610/gsm_encode.o nylsf/GSM610/gsm_option.o \ nylsf/GSM610/long_term.o nylsf/GSM610/lpc.o \ nylsf/GSM610/preprocess.o nylsf/GSM610/rpe.o \ nylsf/GSM610/short_term.o nylsf/GSM610/table.o \ nylsf/G72x/g721.o nylsf/G72x/g723_16.o \ nylsf/G72x/g723_24.o nylsf/G72x/g723_40.o \ nylsf/G72x/g72x.o nyqsrc/debug.o \ nyqsrc/falloc.o nyqsrc/local.o \ nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/stats.o nyqsrc/ffilterkit.o \ nyqsrc/sliders.o nyqsrc/sound.o \ nyqsrc/add.o nyqsrc/avg.o \ nyqsrc/compose.o nyqsrc/convolve.o \ nyqsrc/downsample.o nyqsrc/fft.o \ nyqsrc/inverse.o nyqsrc/multiseq.o \ nyqsrc/resamp.o nyqsrc/resampv.o \ nyqsrc/samples.o nyqsrc/sndmax.o \ nyqsrc/sndread.o nyqsrc/sndseq.o \ nyqsrc/sndwritepa.o nyqsrc/yin.o \ nyqsrc/nyq-osc-server.o nyqsrc/trigger.o \ nyqsrc/lpanal.o nyqsrc/phasevocoder.o \ nyqsrc/pvshell.o nyqstk/src/Generator.o \ nyqstk/src/SineWave.o nyqstk/src/Function.o \ nyqstk/src/FileRead.o nyqstk/src/FileWvIn.o \ nyqstk/src/Effect.o nyqstk/src/Clarinet.o \ nyqstk/src/Delay.o nyqstk/src/DelayL.o \ nyqstk/src/Envelope.o nyqstk/src/Filter.o \ nyqstk/src/Instrmnt.o nyqstk/src/Noise.o \ nyqstk/src/OneZero.o nyqstk/src/ReedTable.o \ nyqstk/src/Saxofony.o nyqstk/src/Stk.o \ nyqstk/src/WaveLoop.o nyqstk/src/WvIn.o \ nyqstk/src/NRev.o nyqstk/src/JCRev.o \ nyqstk/src/PRCRev.o nyqstk/src/PitShift.o \ nyqstk/src/Chorus.o nyqstk/src/Bowed.o \ nyqstk/src/BowTable.o nyqstk/src/ADSR.o \ nyqstk/src/OnePole.o nyqstk/src/BiQuad.o \ nyqstk/src/BandedWG.o nyqstk/src/DelayA.o \ nyqstk/src/Mandolin.o nyqstk/src/PluckTwo.o \ nyqstk/src/Sitar.o nyqstk/src/ModalBar.o \ nyqstk/src/Modal.o nyqstk/src/Flute.o \ nyqstk/src/JetTable.o nyqstk/src/PoleZero.o \ nyqstk/stkinit.o nyqstk/instr.o \ nyqstk/stkint.o ffts/src/fftext.o \ ffts/src/fftlib.o ffts/src/matlib.o \ nyqsrc/sndfnint.o nyqsrc/seqfnint.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = nyqsrc/sndfmt.h nylsf/sndfile.h \ nyqsrc/sound.h nyqsrc/add.h \ nyqsrc/avg.h nyqsrc/compose.h \ nyqsrc/convolve.h nyqsrc/downsample.h \ nyqsrc/fft.h nyqsrc/inverse.h \ nyqsrc/multiseq.h nyqsrc/resamp.h \ nyqsrc/resampv.h nyqsrc/samples.h \ nyqsrc/sndmax.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/sndsliders.h \ nyqsrc/sndwrite.h nyqsrc/yin.h \ nyqsrc/nyq-osc-server.h nyqsrc/trigger.h \ nyqsrc/lpanal.h nyqsrc/phasevocoder.h \ nyqsrc/pvshell.h tran/abs.h \ tran/allpoles.h tran/alpass.h \ tran/alpasscv.h tran/alpassvv.h \ tran/amosc.h tran/areson.h \ tran/aresonvc.h tran/aresoncv.h \ tran/aresonvv.h tran/atone.h \ tran/atonev.h tran/biquadfilt.h \ tran/buzz.h tran/chase.h \ tran/clip.h tran/congen.h \ tran/const.h tran/coterm.h \ tran/delaycc.h tran/delaycv.h \ tran/eqbandvvv.h tran/exp.h \ tran/follow.h tran/fmosc.h \ tran/fromobject.h tran/fromarraystream.h \ tran/gate.h tran/ifft.h \ tran/instrclar.h tran/instrclarall.h \ tran/instrclarfreq.h tran/instrsax.h \ tran/instrsaxall.h tran/instrsaxfreq.h \ tran/integrate.h tran/log.h \ tran/lpreson.h tran/maxv.h \ tran/offset.h tran/oneshot.h \ tran/osc.h tran/partial.h \ tran/pluck.h tran/prod.h \ tran/pwl.h tran/quantize.h \ tran/recip.h tran/reson.h \ tran/resonvc.h tran/resoncv.h \ tran/resonvv.h tran/sampler.h \ tran/scale.h tran/shape.h \ tran/sine.h tran/siosc.h \ tran/slope.h tran/sqrt.h \ tran/tapf.h tran/tapv.h \ tran/tone.h tran/tonev.h \ tran/upsample.h tran/white.h \ tran/stkrev.h tran/stkpitshift.h \ tran/stkchorus.h tran/instrbow.h \ tran/instrbowedfreq.h tran/instrbanded.h \ tran/instrmandolin.h tran/instrsitar.h \ tran/instrmodalbar.h tran/instrflute.h \ tran/instrflutefreq.h tran/instrfluteall.h \ tran/fmfb.h tran/fmfbv.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h \ cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h \ cmt/seqwrite.h cmt/seqmwrite.h bin: mkdir bin liblo/Makefile: cd liblo; ./configure CFLAGS=-m32 LDFLAGS=-m32 CXXFLAGS=-m32 --enable-static --disable-shared # sometimes, residual files cause problems cd liblo; make clean $(LIBLO_PATH)/liblo.a: liblo/Makefile cd liblo; make bin/ser-to-osc: bin $(LIBLO_PATH)/liblo.a $(CC) -c $(CFLAGS) liblo/ser-to-osc/ser-to-osc.cpp \ -o liblo/ser-to-osc/ser-to-osc.o $(LN) liblo/ser-to-osc/ser-to-osc.o -o bin/ser-to-osc $(LFLAGS) bin/test-client: bin $(LIBLO_PATH)/liblo.a $(CC) -c $(CFLAGS) liblo/test-client/test-client.c \ -o liblo/test-client/test-client.o $(LN) liblo/test-client/test-client.o -o bin/test-client $(LFLAGS) portaudio/Makefile: # note: without-jack avoids 32/64-bit link error on Debian cd portaudio; ./configure CFLAGS=-m32 LDFLAGS=-m32 CXXFLAGS=-m32 --enable-static --disable-shared --without-jack # sometimes, residual files cause problems cd portaudio; make clean $(LIBPA_PATH)/libportaudio.a: portaudio/Makefile cd portaudio; make $(NY): $(OBJECTS) $(LIBPA_PATH)/libportaudio.a $(LIBLO_PATH)/liblo.a $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/nonalsa/system.lsp # make sure it's there before you make it writeable touch runtime/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/nonalsa/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/convolve.o: nyqsrc/convolve.c nyqsrc/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/convolve.c -o nyqsrc/convolve.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndsliders.o: nyqsrc/sndsliders.c nyqsrc/sndsliders.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndsliders.c -o nyqsrc/sndsliders.o $(CFLAGS) nyqsrc/sndwritepa.o: nyqsrc/sndwritepa.c nyqsrc/sndwrite.h $(CC) -c nyqsrc/sndwritepa.c -o nyqsrc/sndwritepa.o $(CFLAGS) nyqsrc/yin.o: nyqsrc/yin.c nyqsrc/yin.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/yin.c -o nyqsrc/yin.o $(CFLAGS) nyqsrc/nyq-osc-server.o: nyqsrc/nyq-osc-server.c nyqsrc/nyq-osc-server.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/nyq-osc-server.c -o nyqsrc/nyq-osc-server.o $(CFLAGS) nyqsrc/trigger.o: nyqsrc/trigger.c nyqsrc/trigger.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/trigger.c -o nyqsrc/trigger.o $(CFLAGS) nyqsrc/lpanal.o: nyqsrc/lpanal.c nyqsrc/lpanal.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/lpanal.c -o nyqsrc/lpanal.o $(CFLAGS) nyqsrc/phasevocoder.o: nyqsrc/phasevocoder.c nyqsrc/phasevocoder.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/phasevocoder.c -o nyqsrc/phasevocoder.o $(CFLAGS) nyqsrc/pvshell.o: nyqsrc/pvshell.c nyqsrc/pvshell.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/pvshell.c -o nyqsrc/pvshell.o $(CFLAGS) nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h $(CC) -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c $(CC) -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/sliders.o: nyqsrc/sliders.c nyqsrc/sliders.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sliders.c -o nyqsrc/sliders.o $(CFLAGS) ffts/src/fftext.o: ffts/src/fftext.c ffts/src/fftext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c ffts/src/fftext.c -o ffts/src/fftext.o $(CFLAGS) ffts/src/fftlib.o: ffts/src/fftlib.c ffts/src/fftlib.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c ffts/src/fftlib.c -o ffts/src/fftlib.o $(CFLAGS) ffts/src/matlib.o: ffts/src/matlib.c ffts/src/matlib.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c ffts/src/matlib.c -o ffts/src/matlib.o $(CFLAGS) tran/abs.o: tran/abs.c tran/abs.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/abs.c -o tran/abs.o $(CFLAGS) tran/allpoles.o: tran/allpoles.c tran/allpoles.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/allpoles.c -o tran/allpoles.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/alpasscv.o: tran/alpasscv.c tran/alpasscv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/alpasscv.c -o tran/alpasscv.o $(CFLAGS) tran/alpassvv.o: tran/alpassvv.c tran/alpassvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/alpassvv.c -o tran/alpassvv.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/biquadfilt.o: tran/biquadfilt.c tran/biquadfilt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/biquadfilt.c -o tran/biquadfilt.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/const.c -o tran/const.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/eqbandvvv.o: tran/eqbandvvv.c tran/eqbandvvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/eqbandvvv.c -o tran/eqbandvvv.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/instrclar.o: tran/instrclar.c tran/instrclar.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrclar.c -o tran/instrclar.o $(CFLAGS) tran/instrclarall.o: tran/instrclarall.c tran/instrclarall.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrclarall.c -o tran/instrclarall.o $(CFLAGS) tran/instrclarfreq.o: tran/instrclarfreq.c tran/instrclarfreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrclarfreq.c -o tran/instrclarfreq.o $(CFLAGS) tran/instrsax.o: tran/instrsax.c tran/instrsax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsax.c -o tran/instrsax.o $(CFLAGS) tran/instrsaxall.o: tran/instrsaxall.c tran/instrsaxall.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsaxall.c -o tran/instrsaxall.o $(CFLAGS) tran/instrsaxfreq.o: tran/instrsaxfreq.c tran/instrsaxfreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsaxfreq.c -o tran/instrsaxfreq.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/log.c -o tran/log.o $(CFLAGS) tran/lpreson.o: tran/lpreson.c tran/lpreson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/lpreson.c -o tran/lpreson.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/pluck.c -o tran/pluck.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/sqrt.o: tran/sqrt.c tran/sqrt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/sqrt.c -o tran/sqrt.o $(CFLAGS) tran/tapf.o: tran/tapf.c tran/tapf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tapf.c -o tran/tapf.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/white.c -o tran/white.o $(CFLAGS) tran/stkrev.o: tran/stkrev.c tran/stkrev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/stkrev.c -o tran/stkrev.o $(CFLAGS) tran/stkpitshift.o: tran/stkpitshift.c tran/stkpitshift.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/stkpitshift.c -o tran/stkpitshift.o $(CFLAGS) tran/stkchorus.o: tran/stkchorus.c tran/stkchorus.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/stkchorus.c -o tran/stkchorus.o $(CFLAGS) tran/instrbow.o: tran/instrbow.c tran/instrbow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrbow.c -o tran/instrbow.o $(CFLAGS) tran/instrbowedfreq.o: tran/instrbowedfreq.c tran/instrbowedfreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrbowedfreq.c -o tran/instrbowedfreq.o $(CFLAGS) tran/instrbanded.o: tran/instrbanded.c tran/instrbanded.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrbanded.c -o tran/instrbanded.o $(CFLAGS) tran/instrmandolin.o: tran/instrmandolin.c tran/instrmandolin.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrmandolin.c -o tran/instrmandolin.o $(CFLAGS) tran/instrsitar.o: tran/instrsitar.c tran/instrsitar.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsitar.c -o tran/instrsitar.o $(CFLAGS) tran/instrmodalbar.o: tran/instrmodalbar.c tran/instrmodalbar.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrmodalbar.c -o tran/instrmodalbar.o $(CFLAGS) tran/instrflute.o: tran/instrflute.c tran/instrflute.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrflute.c -o tran/instrflute.o $(CFLAGS) tran/instrflutefreq.o: tran/instrflutefreq.c tran/instrflutefreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrflutefreq.c -o tran/instrflutefreq.o $(CFLAGS) tran/instrfluteall.o: tran/instrfluteall.c tran/instrfluteall.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrfluteall.c -o tran/instrfluteall.o $(CFLAGS) tran/fmfb.o: tran/fmfb.c tran/fmfb.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fmfb.c -o tran/fmfb.o $(CFLAGS) tran/fmfbv.o: tran/fmfbv.c tran/fmfbv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fmfbv.c -o tran/fmfbv.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c $(CC) -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c $(CC) -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) nyqstk/stkinit.o: nyqstk/stkinit.cpp nyqstk/stkinit.h g++ -c nyqstk/stkinit.cpp -o nyqstk/stkinit.o $(CFLAGS) nyqstk/instr.o: nyqstk/instr.cpp nyqstk/instr.h g++ -c nyqstk/instr.cpp -o nyqstk/instr.o $(CFLAGS) nyqstk/stkint.o: nyqstk/stkint.cpp nyqstk/stkint.h g++ -c nyqstk/stkint.cpp -o nyqstk/stkint.o $(CFLAGS) nyqstk/src/Generator.o: nyqstk/src/Generator.cpp nyqstk/include/Generator.h g++ -c nyqstk/src/Generator.cpp -o nyqstk/src/Generator.o $(CFLAGS) nyqstk/src/SineWave.o: nyqstk/src/SineWave.cpp nyqstk/include/SineWave.h g++ -c nyqstk/src/SineWave.cpp -o nyqstk/src/SineWave.o $(CFLAGS) nyqstk/src/Function.o: nyqstk/src/Function.cpp nyqstk/include/Function.h g++ -c nyqstk/src/Function.cpp -o nyqstk/src/Function.o $(CFLAGS) nyqstk/src/FileRead.o: nyqstk/src/FileRead.cpp nyqstk/include/FileRead.h g++ -c nyqstk/src/FileRead.cpp -o nyqstk/src/FileRead.o $(CFLAGS) nyqstk/src/FileWvIn.o: nyqstk/src/FileWvIn.cpp nyqstk/include/FileWvIn.h g++ -c nyqstk/src/FileWvIn.cpp -o nyqstk/src/FileWvIn.o $(CFLAGS) nyqstk/src/Effect.o: nyqstk/src/Effect.cpp nyqstk/include/Effect.h g++ -c nyqstk/src/Effect.cpp -o nyqstk/src/Effect.o $(CFLAGS) nyqstk/src/Clarinet.o: nyqstk/src/Clarinet.cpp nyqstk/include/Clarinet.h g++ -c nyqstk/src/Clarinet.cpp -o nyqstk/src/Clarinet.o $(CFLAGS) nyqstk/src/Delay.o: nyqstk/src/Delay.cpp nyqstk/include/Delay.h g++ -c nyqstk/src/Delay.cpp -o nyqstk/src/Delay.o $(CFLAGS) nyqstk/src/DelayL.o: nyqstk/src/DelayL.cpp nyqstk/include/DelayL.h g++ -c nyqstk/src/DelayL.cpp -o nyqstk/src/DelayL.o $(CFLAGS) nyqstk/src/Envelope.o: nyqstk/src/Envelope.cpp nyqstk/include/Envelope.h g++ -c nyqstk/src/Envelope.cpp -o nyqstk/src/Envelope.o $(CFLAGS) nyqstk/src/Filter.o: nyqstk/src/Filter.cpp nyqstk/include/Filter.h g++ -c nyqstk/src/Filter.cpp -o nyqstk/src/Filter.o $(CFLAGS) nyqstk/src/Instrmnt.o: nyqstk/src/Instrmnt.cpp nyqstk/include/Instrmnt.h g++ -c nyqstk/src/Instrmnt.cpp -o nyqstk/src/Instrmnt.o $(CFLAGS) nyqstk/src/Noise.o: nyqstk/src/Noise.cpp nyqstk/include/Noise.h g++ -c nyqstk/src/Noise.cpp -o nyqstk/src/Noise.o $(CFLAGS) nyqstk/src/OneZero.o: nyqstk/src/OneZero.cpp nyqstk/include/OneZero.h g++ -c nyqstk/src/OneZero.cpp -o nyqstk/src/OneZero.o $(CFLAGS) nyqstk/src/ReedTable.o: nyqstk/src/ReedTable.cpp nyqstk/include/ReedTable.h g++ -c nyqstk/src/ReedTable.cpp -o nyqstk/src/ReedTable.o $(CFLAGS) nyqstk/src/Saxofony.o: nyqstk/src/Saxofony.cpp nyqstk/include/Saxofony.h g++ -c nyqstk/src/Saxofony.cpp -o nyqstk/src/Saxofony.o $(CFLAGS) nyqstk/src/Stk.o: nyqstk/src/Stk.cpp nyqstk/include/Stk.h g++ -c nyqstk/src/Stk.cpp -o nyqstk/src/Stk.o $(CFLAGS) nyqstk/src/WaveLoop.o: nyqstk/src/WaveLoop.cpp nyqstk/include/WaveLoop.h g++ -c nyqstk/src/WaveLoop.cpp -o nyqstk/src/WaveLoop.o $(CFLAGS) nyqstk/src/WvIn.o: nyqstk/src/WvIn.cpp nyqstk/include/WvIn.h g++ -c nyqstk/src/WvIn.cpp -o nyqstk/src/WvIn.o $(CFLAGS) nyqstk/src/NRev.o: nyqstk/src/NRev.cpp nyqstk/include/NRev.h g++ -c nyqstk/src/NRev.cpp -o nyqstk/src/NRev.o $(CFLAGS) nyqstk/src/JCRev.o: nyqstk/src/JCRev.cpp nyqstk/include/JCRev.h g++ -c nyqstk/src/JCRev.cpp -o nyqstk/src/JCRev.o $(CFLAGS) nyqstk/src/PRCRev.o: nyqstk/src/PRCRev.cpp nyqstk/include/PRCRev.h g++ -c nyqstk/src/PRCRev.cpp -o nyqstk/src/PRCRev.o $(CFLAGS) nyqstk/src/PitShift.o: nyqstk/src/PitShift.cpp nyqstk/include/PitShift.h g++ -c nyqstk/src/PitShift.cpp -o nyqstk/src/PitShift.o $(CFLAGS) nyqstk/src/Chorus.o: nyqstk/src/Chorus.cpp nyqstk/include/Chorus.h g++ -c nyqstk/src/Chorus.cpp -o nyqstk/src/Chorus.o $(CFLAGS) nyqstk/src/Bowed.o: nyqstk/src/Bowed.cpp nyqstk/include/Bowed.h g++ -c nyqstk/src/Bowed.cpp -o nyqstk/src/Bowed.o $(CFLAGS) nyqstk/src/BowTable.o: nyqstk/src/BowTable.cpp nyqstk/include/BowTable.h g++ -c nyqstk/src/BowTable.cpp -o nyqstk/src/BowTable.o $(CFLAGS) nyqstk/src/ADSR.o: nyqstk/src/ADSR.cpp nyqstk/include/ADSR.h g++ -c nyqstk/src/ADSR.cpp -o nyqstk/src/ADSR.o $(CFLAGS) nyqstk/src/OnePole.o: nyqstk/src/OnePole.cpp nyqstk/include/OnePole.h g++ -c nyqstk/src/OnePole.cpp -o nyqstk/src/OnePole.o $(CFLAGS) nyqstk/src/BiQuad.o: nyqstk/src/BiQuad.cpp nyqstk/include/BiQuad.h g++ -c nyqstk/src/BiQuad.cpp -o nyqstk/src/BiQuad.o $(CFLAGS) nyqstk/src/BandedWG.o: nyqstk/src/BandedWG.cpp nyqstk/include/BandedWG.h g++ -c nyqstk/src/BandedWG.cpp -o nyqstk/src/BandedWG.o $(CFLAGS) nyqstk/src/DelayA.o: nyqstk/src/DelayA.cpp nyqstk/include/DelayA.h g++ -c nyqstk/src/DelayA.cpp -o nyqstk/src/DelayA.o $(CFLAGS) nyqstk/src/Mandolin.o: nyqstk/src/Mandolin.cpp nyqstk/include/Mandolin.h g++ -c nyqstk/src/Mandolin.cpp -o nyqstk/src/Mandolin.o $(CFLAGS) nyqstk/src/PluckTwo.o: nyqstk/src/PluckTwo.cpp nyqstk/include/PluckTwo.h g++ -c nyqstk/src/PluckTwo.cpp -o nyqstk/src/PluckTwo.o $(CFLAGS) nyqstk/src/Sitar.o: nyqstk/src/Sitar.cpp nyqstk/include/Sitar.h g++ -c nyqstk/src/Sitar.cpp -o nyqstk/src/Sitar.o $(CFLAGS) nyqstk/src/ModalBar.o: nyqstk/src/ModalBar.cpp nyqstk/include/ModalBar.h g++ -c nyqstk/src/ModalBar.cpp -o nyqstk/src/ModalBar.o $(CFLAGS) nyqstk/src/Modal.o: nyqstk/src/Modal.cpp nyqstk/include/Modal.h g++ -c nyqstk/src/Modal.cpp -o nyqstk/src/Modal.o $(CFLAGS) nyqstk/src/Flute.o: nyqstk/src/Flute.cpp nyqstk/include/Flute.h g++ -c nyqstk/src/Flute.cpp -o nyqstk/src/Flute.o $(CFLAGS) nyqstk/src/JetTable.o: nyqstk/src/JetTable.cpp nyqstk/include/JetTable.h g++ -c nyqstk/src/JetTable.cpp -o nyqstk/src/JetTable.o $(CFLAGS) nyqstk/src/PoleZero.o: nyqstk/src/PoleZero.cpp nyqstk/include/PoleZero.h g++ -c nyqstk/src/PoleZero.cpp -o nyqstk/src/PoleZero.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h $(CC) -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c $(CC) -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c $(CC) -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c $(CC) -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c $(CC) -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c $(CC) -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c $(CC) -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c $(CC) -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c $(CC) -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c $(CC) -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c $(CC) -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c $(CC) -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c $(CC) -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xljump.o: xlisp/xljump.c $(CC) -c xlisp/xljump.c -o xlisp/xljump.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c $(CC) -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c $(CC) -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c $(CC) -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c $(CC) -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c $(CC) -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c $(CC) -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c $(CC) -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c $(CC) -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c $(CC) -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c $(CC) -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) xlisp/path.o: xlisp/path.c $(CC) -c xlisp/path.c -o xlisp/path.o $(CFLAGS) cmt/cext.o: cmt/cext.c $(CC) -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c $(CC) -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c $(CC) -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c $(CC) -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c $(CC) -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c $(CC) -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c $(CC) -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c $(CC) -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c $(CC) -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c $(CC) -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c $(CC) -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c $(CC) -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c $(CC) -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c $(CC) -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c $(CC) -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c $(CC) -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c $(CC) -c cmt/userio.c -o cmt/userio.o $(CFLAGS) nylsf/aiff.o: nylsf/aiff.c $(CC) -c nylsf/aiff.c -o nylsf/aiff.o $(CFLAGS) nylsf/alaw.o: nylsf/alaw.c $(CC) -c nylsf/alaw.c -o nylsf/alaw.o $(CFLAGS) nylsf/au.o: nylsf/au.c $(CC) -c nylsf/au.c -o nylsf/au.o $(CFLAGS) nylsf/avr.o: nylsf/avr.c $(CC) -c nylsf/avr.c -o nylsf/avr.o $(CFLAGS) nylsf/broadcast.o: nylsf/broadcast.c $(CC) -c nylsf/broadcast.c -o nylsf/broadcast.o $(CFLAGS) nylsf/caf.o: nylsf/caf.c $(CC) -c nylsf/caf.c -o nylsf/caf.o $(CFLAGS) nylsf/command.o: nylsf/command.c $(CC) -c nylsf/command.c -o nylsf/command.o $(CFLAGS) nylsf/common.o: nylsf/common.c $(CC) -c nylsf/common.c -o nylsf/common.o $(CFLAGS) nylsf/dither.o: nylsf/dither.c $(CC) -c nylsf/dither.c -o nylsf/dither.o $(CFLAGS) nylsf/double64.o: nylsf/double64.c $(CC) -c nylsf/double64.c -o nylsf/double64.o $(CFLAGS) nylsf/dwd.o: nylsf/dwd.c $(CC) -c nylsf/dwd.c -o nylsf/dwd.o $(CFLAGS) nylsf/dwvw.o: nylsf/dwvw.c $(CC) -c nylsf/dwvw.c -o nylsf/dwvw.o $(CFLAGS) nylsf/file_io.o: nylsf/file_io.c $(CC) -c nylsf/file_io.c -o nylsf/file_io.o $(CFLAGS) nylsf/flac.o: nylsf/flac.c $(CC) -c nylsf/flac.c -o nylsf/flac.o $(CFLAGS) nylsf/float32.o: nylsf/float32.c $(CC) -c nylsf/float32.c -o nylsf/float32.o $(CFLAGS) nylsf/gsm610.o: nylsf/gsm610.c $(CC) -c nylsf/gsm610.c -o nylsf/gsm610.o $(CFLAGS) nylsf/htk.o: nylsf/htk.c $(CC) -c nylsf/htk.c -o nylsf/htk.o $(CFLAGS) nylsf/ima_adpcm.o: nylsf/ima_adpcm.c $(CC) -c nylsf/ima_adpcm.c -o nylsf/ima_adpcm.o $(CFLAGS) nylsf/interleave.o: nylsf/interleave.c $(CC) -c nylsf/interleave.c -o nylsf/interleave.o $(CFLAGS) nylsf/ircam.o: nylsf/ircam.c $(CC) -c nylsf/ircam.c -o nylsf/ircam.o $(CFLAGS) nylsf/macbinary3.o: nylsf/macbinary3.c $(CC) -c nylsf/macbinary3.c -o nylsf/macbinary3.o $(CFLAGS) nylsf/macos.o: nylsf/macos.c $(CC) -c nylsf/macos.c -o nylsf/macos.o $(CFLAGS) nylsf/mat4.o: nylsf/mat4.c $(CC) -c nylsf/mat4.c -o nylsf/mat4.o $(CFLAGS) nylsf/mat5.o: nylsf/mat5.c $(CC) -c nylsf/mat5.c -o nylsf/mat5.o $(CFLAGS) nylsf/ms_adpcm.o: nylsf/ms_adpcm.c $(CC) -c nylsf/ms_adpcm.c -o nylsf/ms_adpcm.o $(CFLAGS) nylsf/nist.o: nylsf/nist.c $(CC) -c nylsf/nist.c -o nylsf/nist.o $(CFLAGS) nylsf/ogg.o: nylsf/ogg.c $(CC) -c nylsf/ogg.c -o nylsf/ogg.o $(CFLAGS) nylsf/paf.o: nylsf/paf.c $(CC) -c nylsf/paf.c -o nylsf/paf.o $(CFLAGS) nylsf/pcm.o: nylsf/pcm.c $(CC) -c nylsf/pcm.c -o nylsf/pcm.o $(CFLAGS) nylsf/pvf.o: nylsf/pvf.c $(CC) -c nylsf/pvf.c -o nylsf/pvf.o $(CFLAGS) nylsf/raw.o: nylsf/raw.c $(CC) -c nylsf/raw.c -o nylsf/raw.o $(CFLAGS) nylsf/rx2.o: nylsf/rx2.c $(CC) -c nylsf/rx2.c -o nylsf/rx2.o $(CFLAGS) nylsf/sd2.o: nylsf/sd2.c $(CC) -c nylsf/sd2.c -o nylsf/sd2.o $(CFLAGS) nylsf/sds.o: nylsf/sds.c $(CC) -c nylsf/sds.c -o nylsf/sds.o $(CFLAGS) nylsf/sndfile.o: nylsf/sndfile.c $(CC) -c nylsf/sndfile.c -o nylsf/sndfile.o $(CFLAGS) nylsf/strings.o: nylsf/strings.c $(CC) -c nylsf/strings.c -o nylsf/strings.o $(CFLAGS) nylsf/svx.o: nylsf/svx.c $(CC) -c nylsf/svx.c -o nylsf/svx.o $(CFLAGS) nylsf/txw.o: nylsf/txw.c $(CC) -c nylsf/txw.c -o nylsf/txw.o $(CFLAGS) nylsf/ulaw.o: nylsf/ulaw.c $(CC) -c nylsf/ulaw.c -o nylsf/ulaw.o $(CFLAGS) nylsf/voc.o: nylsf/voc.c $(CC) -c nylsf/voc.c -o nylsf/voc.o $(CFLAGS) nylsf/vox_adpcm.o: nylsf/vox_adpcm.c $(CC) -c nylsf/vox_adpcm.c -o nylsf/vox_adpcm.o $(CFLAGS) nylsf/w64.o: nylsf/w64.c $(CC) -c nylsf/w64.c -o nylsf/w64.o $(CFLAGS) nylsf/wav.o: nylsf/wav.c $(CC) -c nylsf/wav.c -o nylsf/wav.o $(CFLAGS) nylsf/wav_w64.o: nylsf/wav_w64.c $(CC) -c nylsf/wav_w64.c -o nylsf/wav_w64.o $(CFLAGS) nylsf/wve.o: nylsf/wve.c $(CC) -c nylsf/wve.c -o nylsf/wve.o $(CFLAGS) nylsf/xi.o: nylsf/xi.c $(CC) -c nylsf/xi.c -o nylsf/xi.o $(CFLAGS) nylsf/g72x.o: nylsf/g72x.c $(CC) -c nylsf/g72x.c -o nylsf/g72x.o $(CFLAGS) nylsf/GSM610/add.o: nylsf/GSM610/add.c $(CC) -c nylsf/GSM610/add.c -o nylsf/GSM610/add.o $(CFLAGS) nylsf/GSM610/code.o: nylsf/GSM610/code.c $(CC) -c nylsf/GSM610/code.c -o nylsf/GSM610/code.o $(CFLAGS) nylsf/GSM610/decode.o: nylsf/GSM610/decode.c $(CC) -c nylsf/GSM610/decode.c -o nylsf/GSM610/decode.o $(CFLAGS) nylsf/GSM610/gsm_create.o: nylsf/GSM610/gsm_create.c $(CC) -c nylsf/GSM610/gsm_create.c -o nylsf/GSM610/gsm_create.o $(CFLAGS) nylsf/GSM610/gsm_decode.o: nylsf/GSM610/gsm_decode.c $(CC) -c nylsf/GSM610/gsm_decode.c -o nylsf/GSM610/gsm_decode.o $(CFLAGS) nylsf/GSM610/gsm_destroy.o: nylsf/GSM610/gsm_destroy.c $(CC) -c nylsf/GSM610/gsm_destroy.c -o nylsf/GSM610/gsm_destroy.o $(CFLAGS) nylsf/GSM610/gsm_encode.o: nylsf/GSM610/gsm_encode.c $(CC) -c nylsf/GSM610/gsm_encode.c -o nylsf/GSM610/gsm_encode.o $(CFLAGS) nylsf/GSM610/gsm_option.o: nylsf/GSM610/gsm_option.c $(CC) -c nylsf/GSM610/gsm_option.c -o nylsf/GSM610/gsm_option.o $(CFLAGS) nylsf/GSM610/long_term.o: nylsf/GSM610/long_term.c $(CC) -c nylsf/GSM610/long_term.c -o nylsf/GSM610/long_term.o $(CFLAGS) nylsf/GSM610/lpc.o: nylsf/GSM610/lpc.c $(CC) -c nylsf/GSM610/lpc.c -o nylsf/GSM610/lpc.o $(CFLAGS) nylsf/GSM610/preprocess.o: nylsf/GSM610/preprocess.c $(CC) -c nylsf/GSM610/preprocess.c -o nylsf/GSM610/preprocess.o $(CFLAGS) nylsf/GSM610/rpe.o: nylsf/GSM610/rpe.c $(CC) -c nylsf/GSM610/rpe.c -o nylsf/GSM610/rpe.o $(CFLAGS) nylsf/GSM610/short_term.o: nylsf/GSM610/short_term.c $(CC) -c nylsf/GSM610/short_term.c -o nylsf/GSM610/short_term.o $(CFLAGS) nylsf/GSM610/table.o: nylsf/GSM610/table.c $(CC) -c nylsf/GSM610/table.c -o nylsf/GSM610/table.o $(CFLAGS) nylsf/G72x/g721.o: nylsf/G72x/g721.c $(CC) -c nylsf/G72x/g721.c -o nylsf/G72x/g721.o $(CFLAGS) nylsf/G72x/g723_16.o: nylsf/G72x/g723_16.c $(CC) -c nylsf/G72x/g723_16.c -o nylsf/G72x/g723_16.o $(CFLAGS) nylsf/G72x/g723_24.o: nylsf/G72x/g723_24.c $(CC) -c nylsf/G72x/g723_24.c -o nylsf/G72x/g723_24.o $(CFLAGS) nylsf/G72x/g723_40.o: nylsf/G72x/g723_40.c $(CC) -c nylsf/G72x/g723_40.c -o nylsf/G72x/g723_40.o $(CFLAGS) nylsf/G72x/g72x.o: nylsf/G72x/g72x.c $(CC) -c nylsf/G72x/g72x.c -o nylsf/G72x/g72x.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c $(CC) -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean cd liblo; test -f Makefile && make clean || true cd portaudio; test -f Makefile && make clean || true rm -f $(OBJECTS) # These could be deleted, but they're part of the release, so we won't # Note that these files are machine-generated: # rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h # rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f #*# */#*# rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat rm -f core.* core rm -f $(NY) release: cleaner cd misc; make packer misc/packer files.txt release.pac rm -f *.wav mv ny .. mv -f *.pac .. rm -f unpacker rm -f packer cd ..; zip -r nyquist.zip nyquist ../ny misc/cmu/cmu-linux-install.lsp mv ../ny ./ny nyquist-3.05/sys/unix/nonalsa/system.lsp0000644000175000000620000000623011512414056017463 0ustar stevestaff;; system.lsp -- system-dependent lisp code ; local definition for play ; this one is for Linux: (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-wave)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "./")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* (strcat (get-user) "-points.dat"))) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (or (eq (char filename 0) #\/) (eq (char filename 0) #\.))) ; RELATIVE-PATH-P -- test if filename or path is a relative path ; (defun relative-path-p (filename) (not (eq (char filename 0) #\/))) (setf *file-separator* #\/) ;; PLAY-FILE - play a sound file ;; (defun play-file (name) ;; ;; WARNING: if you invoke an external program to play files, ;; but Nyquist uses internal (portaudio) interface to ;; play synthesized sound, Nyquist may fail to open the ;; sound device while it is playing a sound file and then ;; refuse to play anything. -RBD dec05 ;; (system (strcat "sndplay " (soundfilename name)))) ;; (system (strcat "play " (soundfilename name) ))) ;; (play (s-read (soundfilename name)))) ;; R - replay last file written with PLAY (defun r () (play-file *default-sound-file*)) ;;;; use this old version if you want to use sndplay to play ;;;; the result file rather than play the samples as they ;;;; are computed. This version does not autonormalize. ;; PLAY - write value of an expression to file and play it ;; ;(defmacro play (expr) ; `(prog (specs) ; (setf specs (s-save (force-srate *sound-srate* ,expr) ; 1000000000 *default-sound-file*)) ; (r))) ;;;; ; local definition for play (defmacro play (expr) `(s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*)) ;; for Linux, modify s-plot (defined in nyquist.lsp) by saving s-plot ;; in standard-s-plot, then call gnuplot to display the points. ;; ;; we also need to save the location of this file so we can find ;; nyquist-plot.txt, the command file for gnuplot ;; ;; This code is broken in the following ways: ;; it tries to run gnuplot even when plotting can be done by NyquistIDE ;; it plots "points.dat", but "points.dat" may not be correct ;; (see *default-plot-file*) ;; it assumes the plot file is in the current directory, but it ;; by default goes to the sound file directory ;; ;; Fix this code or complain if you want to plot with gnuplot while ;; running ny (or even NyquistIDE (jny) if you want). Otherwise, use ;; NyquistIDE to get s-plot to work. ;; ;(setf *runtime-path* (current-path)) ;(display "system.lsp" *runtime-path*) ; ;(setfn standard-s-plot s-plot) ; ;(defun s-plot (s &optional (dur 2.0) (n 1000)) ; (let (plot-file) ; (standard-s-plot s dur n) ;; this calculates the data points ; (setf plot-file (strcat *runtime-path* "nyquist-plot.txt")) ; (system (strcat "gnuplot -persist " plot-file)))) nyquist-3.05/sys/unix/sndsystem.h0000644000175000000620000000213410144436365016174 0ustar stevestaff/* sndsystem.h -- system-specific definitions */ /* NOTES: you need a different sndswitches.h for each implementation, so this is a separate file. Things you need to define here: 1) Either UNIX, WIN32, or MACINTOSH should be defined. 2) Either the following function declaration: void snd_fail(char *msg); or #define snd_fail(msg) ... 3) typedef FASTFLOAT to be either a double or a float, whichever computes faster (PowerPCs are faster at double math than float math) 4) typedef MEMFLOAT to be how you would store a sample in memory (this should normally be float) 5) min() must be defined (either a macro or a function) 6) max() must be defined (either a macro or a function) */ #define UNIX #define snd_fail(msg) xlfail(msg) #define snd_warn(msg) errputstr(msg) typedef double FASTFLOAT; typedef float MEMFLOAT; /* avoid conflict with Windows */ #ifndef max /* min(n, sizeof(long)) doesn't work on RS6K without this: * (I never tracked down what min() was called and what was wrong.) */ #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) #endif nyquist-3.05/sys/unix/next/0002755000175000000620000000000011537433131014745 5ustar stevestaffnyquist-3.05/sys/unix/next/Makefile0000644000175000000620000004762210144436365016423 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is NEXT # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny # Standard list of includes (common to all unix versions) INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Isnd -Ifft # system dependent stuff for next: CC = cc CFLAGS = -DCMTSTUFF -O $(INCL) LN = cc LFLAGS = -lm INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o xlisp/xlsym.o xlisp/xlsys.o \ tran/amosc.o tran/clip.o tran/const.o tran/fmosc.o \ tran/integrate.o tran/log.o tran/maxv.o tran/osc.o \ tran/prod.o tran/buzz.o tran/pwl.o tran/recip.o \ tran/upsample.o tran/scale.o tran/sine.o tran/partial.o \ tran/white.o tran/tone.o tran/tonev.o tran/atonev.o \ tran/atone.o tran/reson.o tran/areson.o tran/resonvc.o \ tran/resoncv.o tran/aresonvc.o tran/aresoncv.o tran/resonvv.o \ tran/aresonvv.o tran/offset.o tran/slope.o tran/delay.o \ tran/delaycv.o tran/shape.o tran/sampler.o tran/exp.o \ tran/siosc.o tran/follow.o tran/gate.o tran/quantize.o \ tran/ifft.o tran/congen.o tran/fromobject.o tran/fromarraystream.o \ tran/coterm.o tran/convolve.o tran/alpass.o tran/oneshot.o \ tran/chase.o tran/tapv.o tran/biquad.o tran/pluck.o \ cmt/cext.o cmt/cleanup.o cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nyqsrc/debug.o nyqsrc/falloc.o nyqsrc/add.o \ nyqsrc/local.o nyqsrc/downsample.o nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/multiseq.o nyqsrc/samples.o nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/sndread.o nyqsrc/sndseq.o nyqsrc/sndwrite.o nyqsrc/sndmax.o \ nyqsrc/sound.o nyqsrc/stats.o nyqsrc/compose.o nyqsrc/inverse.o \ nyqsrc/resamp.o nyqsrc/resampv.o nyqsrc/ffilterkit.o nyqsrc/avg.o \ nyqsrc/fft.o nyqsrc/sndfail.o fft/fftn.o nyqsrc/sndfnint.o \ nyqsrc/seqfnint.o snd/audionext.o snd/sndnext.o snd/ieeecvt.o \ snd/snd.o snd/sndcvt.o snd/sndio.o snd/sndheader.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = snd/snd.h nyqsrc/sound.h nyqsrc/downsample.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/add.h nyqsrc/multiseq.h nyqsrc/samples.h \ nyqsrc/sndwrite.h nyqsrc/sndmax.h nyqsrc/compose.h nyqsrc/inverse.h \ nyqsrc/resamp.h nyqsrc/resampv.h nyqsrc/fft.h nyqsrc/avg.h \ tran/amosc.h tran/clip.h tran/const.h tran/fmosc.h \ tran/integrate.h tran/log.h tran/maxv.h tran/osc.h \ tran/prod.h tran/buzz.h tran/pwl.h tran/recip.h \ tran/upsample.h tran/scale.h tran/sine.h tran/partial.h \ tran/white.h tran/tone.h tran/tonev.h tran/atonev.h \ tran/atone.h tran/reson.h tran/areson.h tran/resonvc.h \ tran/resoncv.h tran/aresonvc.h tran/aresoncv.h tran/resonvv.h \ tran/aresonvv.h tran/offset.h tran/slope.h tran/delaycc.h \ tran/delaycv.h tran/shape.h tran/sampler.h tran/exp.h \ tran/siosc.h tran/follow.h tran/gate.h tran/quantize.h \ tran/ifft.h tran/congen.h tran/fromobject.h tran/fromarraystream.h \ tran/coterm.h tran/convolve.h tran/alpass.h tran/oneshot.h \ tran/chase.h tran/tapv.h tran/biquad.h tran/pluck.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h cmt/seqwrite.h cmt/seqmwrite.h EVERYTHING = $(NY) runtime/system.lsp CURRENT = $(EVERYTHING) current: $(CURRENT) $(NY): $(OBJECTS) $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/next/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/next/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h cc -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c cc -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndwrite.o: nyqsrc/sndwrite.c nyqsrc/sndwrite.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndwrite.c -o nyqsrc/sndwrite.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/sndfail.o: nyqsrc/sndfail.c cc -c nyqsrc/sndfail.c -o nyqsrc/sndfail.o $(CFLAGS) snd/audionext.o: snd/audionext.c snd/snd.h cc -c snd/audionext.c -o snd/audionext.o $(CFLAGS) snd/sndnext.o: snd/sndnext.c snd/sndnext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndnext.c -o snd/sndnext.o $(CFLAGS) snd/ieeecvt.o: snd/ieeecvt.c snd/ieeecvt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/ieeecvt.c -o snd/ieeecvt.o $(CFLAGS) snd/snd.o: snd/snd.c snd/snd.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/snd.c -o snd/snd.o $(CFLAGS) snd/sndcvt.o: snd/sndcvt.c snd/snd.h cc -c snd/sndcvt.c -o snd/sndcvt.o $(CFLAGS) snd/sndio.o: snd/sndio.c snd/snd.h cc -c snd/sndio.c -o snd/sndio.o $(CFLAGS) snd/sndheader.o: snd/sndheader.c snd/sndheader.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndheader.c -o snd/sndheader.o $(CFLAGS) fft/fftn.o: fft/fftn.c fft/fftn.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c fft/fftn.c -o fft/fftn.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/const.c -o tran/const.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/log.c -o tran/log.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/white.c -o tran/white.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/convolve.o: tran/convolve.c tran/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/convolve.c -o tran/convolve.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/biquad.o: tran/biquad.c tran/biquad.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/biquad.c -o tran/biquad.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pluck.c -o tran/pluck.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c cc -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c cc -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h cc -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c cc -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c cc -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c cc -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c cc -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c cc -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c cc -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c cc -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c cc -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c cc -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c cc -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c cc -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c cc -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c cc -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c cc -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c cc -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c cc -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c cc -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c cc -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c cc -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c cc -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c cc -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c cc -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) cmt/cext.o: cmt/cext.c cc -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c cc -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c cc -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c cc -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c cc -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c cc -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c cc -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c cc -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c cc -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c cc -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c cc -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c cc -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c cc -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c cc -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c cc -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c cc -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c cc -c cmt/userio.c -o cmt/userio.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c cc -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) # this doesn't compile with the -O switch (a NeXT compiler bug?) xlisp/xljump.o : xlisp/xljump.c xlisp/xlisp.h $(CC) -DCMTSTUFF -c xlisp/xljump.c -o xlisp/xljump.o misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) snd/snd.h misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean rm -f $(OBJECTS) # Note that these files are machine-generated: rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat nyquist-3.05/sys/unix/next/system.lsp0000644000175000000620000000172510144436365017021 0ustar stevestaff; local definition for play ; this one is for NeXT: (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-NeXT)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "./")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-head-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* "points.dat")) ;; PLAY-FILE - play a sound file ;; (defun play-file (name) (system (strcat "sndplay " (soundfilename name)))) ;; R - replay last file written with PLAY (defun r () (play-file *default-sound-file*)) ;; PLAY - write value of an expression to file and play it ;; (defmacro play (expr) `(prog (specs) (setf specs (s-save (force-srate *sound-srate* ,expr) 1000000000 *default-sound-file*)) (r))) nyquist-3.05/sys/unix/alsa/0002755000175000000620000000000011537433131014707 5ustar stevestaffnyquist-3.05/sys/unix/alsa/Makefile0000644000175000000620000012721611512414056016354 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is ALSA # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny OPT = -O2 -m32 # OPT = -g -m32 EVERYTHING = $(NY) runtime/system.lsp jnyqide/jNyqIDE.jar \ bin/ser-to-osc bin/test-client CURRENT = $(EVERYTHING) current: $(CURRENT) onlyny: $(NY) runtime/system.lsp JAVASRC = jnyqide/browser.java jnyqide/NyquistThread.java \ jnyqide/Pair.java jnyqide/BareBonesBrowserLaunch.java \ jnyqide/EnvelopeFrame.java jnyqide/Piano_Roll.java \ jnyqide/FindDialog.java jnyqide/PlotFrame.java \ jnyqide/InstrumentCharacteristics.java \ jnyqide/PlotMouseAdapter.java \ jnyqide/Jslide.java jnyqide/PopupListener.java \ jnyqide/LispFileFilter.java jnyqide/PreferencesDialog.java \ jnyqide/MainFrame_AboutBox.java jnyqide/ReplaceDialog.java \ jnyqide/MainFrame.java jnyqide/SpringUtilities.java \ jnyqide/Main.java \ jnyqide/NotFoundDialog.java jnyqide/TextColor.java \ jnyqide/NyqPlot.java jnyqide/Trie.java \ jnyqide/NyquistFile.java jnyqide/WordList.java jnyqide/jNyqIDE.jar: $(JAVASRC) if [ -r jnyqide/SpecialMacHandler.java ] ; then \ mv jnyqide/SpecialMacHandler.java jnyqide/SpecialMacHandler.hidden ;\ fi cd jnyqide; javac *.java mv jnyqide/SpecialMacHandler.hidden jnyqide/SpecialMacHandler.java rm -rf jnyqide/jNyqIDE.jar jar -cfm jnyqide/jNyqIDE.jar jnyqide/manifest.txt jnyqide/*.class # Standard list of includes (common to all unix versions) # Keeping portaudio and libsndfile sources local to nyquist INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Iffts/src \ -Inyqstk/include -Inyqstk -Iportaudio/include -Iportaudio/src/common \ -Iportaudio/src/os/unix \ -Iliblo -Inylsf # system dependent stuff for alsa: AUDIOLIBS = -lasound CC = gcc LIBPA_PATH = portaudio/lib/.libs LIBLO_PATH = liblo/src/.libs # to enable command line editing, use -DREADLINE. WARNING: THIS WILL # DISABLE THE ABILITY TO INTERRUPT LISP AND USE SOME OTHER HANDY # CONTROL CHARACTERS (You will also need the readline and curses libraries) CFLAGS = -DOSC -DCMTSTUFF $(OPT) $(INCL) \ -DHAVE_LIBPTHREAD=1 -D_FILE_OFFSET_BITS=64 \ -DSTK_NYQUIST -DUSE_VSPRINTF \ -DHAVE_CONFIG_H LN = g++ -m32 AR = ar # to enable command line editing, insert -lreadline -lcurses LFLAGS = $(LIBPA_PATH)/libportaudio.a $(LIBLO_PATH)/liblo.a $(AUDIOLIBS) -lm -lpthread -lrt TAGS: find . ( -name INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o \ xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o \ xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o \ xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o \ xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o \ xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o \ xlisp/xlsym.o xlisp/xlsys.o \ xlisp/path.o tran/abs.o \ tran/allpoles.o tran/alpass.o \ tran/alpasscv.o tran/alpassvv.o \ tran/amosc.o tran/areson.o \ tran/aresonvc.o tran/aresoncv.o \ tran/aresonvv.o tran/atone.o \ tran/atonev.o tran/biquadfilt.o \ tran/buzz.o tran/chase.o \ tran/clip.o tran/congen.o \ tran/const.o tran/coterm.o \ tran/delaycc.o tran/delaycv.o \ tran/eqbandvvv.o tran/exp.o \ tran/follow.o tran/fmosc.o \ tran/fromobject.o tran/fromarraystream.o \ tran/gate.o tran/ifft.o \ tran/instrclar.o tran/instrclarall.o \ tran/instrclarfreq.o tran/instrsax.o \ tran/instrsaxall.o tran/instrsaxfreq.o \ tran/integrate.o tran/log.o \ tran/lpreson.o tran/maxv.o \ tran/offset.o tran/oneshot.o \ tran/osc.o tran/partial.o \ tran/pluck.o tran/prod.o \ tran/pwl.o tran/quantize.o \ tran/recip.o tran/reson.o \ tran/resonvc.o tran/resoncv.o \ tran/resonvv.o tran/sampler.o \ tran/scale.o tran/shape.o \ tran/sine.o tran/siosc.o \ tran/slope.o tran/sqrt.o \ tran/tapf.o tran/tapv.o \ tran/tone.o tran/tonev.o \ tran/upsample.o tran/white.o \ tran/stkrev.o tran/stkpitshift.o \ tran/stkchorus.o tran/instrbow.o \ tran/instrbowedfreq.o tran/instrbanded.o \ tran/instrmandolin.o tran/instrsitar.o \ tran/instrmodalbar.o tran/instrflute.o \ tran/instrflutefreq.o tran/instrfluteall.o \ tran/fmfb.o tran/fmfbv.o \ cmt/cext.o cmt/cleanup.o \ cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o \ cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o \ cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o \ cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nylsf/aiff.o \ nylsf/alaw.o nylsf/au.o \ nylsf/avr.o nylsf/broadcast.o \ nylsf/caf.o nylsf/command.o \ nylsf/common.o nylsf/dither.o \ nylsf/double64.o nylsf/dwd.o \ nylsf/dwvw.o nylsf/file_io.o \ nylsf/flac.o nylsf/float32.o \ nylsf/gsm610.o nylsf/htk.o \ nylsf/ima_adpcm.o nylsf/interleave.o \ nylsf/ircam.o nylsf/macbinary3.o \ nylsf/macos.o nylsf/mat4.o \ nylsf/mat5.o nylsf/ms_adpcm.o \ nylsf/nist.o nylsf/ogg.o \ nylsf/paf.o nylsf/pcm.o \ nylsf/pvf.o nylsf/raw.o \ nylsf/rx2.o nylsf/sd2.o \ nylsf/sds.o nylsf/sndfile.o \ nylsf/strings.o nylsf/svx.o \ nylsf/txw.o nylsf/ulaw.o \ nylsf/voc.o nylsf/vox_adpcm.o \ nylsf/w64.o nylsf/wav.o \ nylsf/wav_w64.o nylsf/wve.o \ nylsf/xi.o nylsf/g72x.o \ nylsf/GSM610/add.o nylsf/GSM610/code.o \ nylsf/GSM610/decode.o nylsf/GSM610/gsm_create.o \ nylsf/GSM610/gsm_decode.o nylsf/GSM610/gsm_destroy.o \ nylsf/GSM610/gsm_encode.o nylsf/GSM610/gsm_option.o \ nylsf/GSM610/long_term.o nylsf/GSM610/lpc.o \ nylsf/GSM610/preprocess.o nylsf/GSM610/rpe.o \ nylsf/GSM610/short_term.o nylsf/GSM610/table.o \ nylsf/G72x/g721.o nylsf/G72x/g723_16.o \ nylsf/G72x/g723_24.o nylsf/G72x/g723_40.o \ nylsf/G72x/g72x.o nyqsrc/debug.o \ nyqsrc/falloc.o nyqsrc/local.o \ nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/stats.o nyqsrc/ffilterkit.o \ nyqsrc/sliders.o nyqsrc/sound.o \ nyqsrc/add.o nyqsrc/avg.o \ nyqsrc/compose.o nyqsrc/convolve.o \ nyqsrc/downsample.o nyqsrc/fft.o \ nyqsrc/inverse.o nyqsrc/multiseq.o \ nyqsrc/resamp.o nyqsrc/resampv.o \ nyqsrc/samples.o nyqsrc/sndmax.o \ nyqsrc/sndread.o nyqsrc/sndseq.o \ nyqsrc/sndwritepa.o nyqsrc/yin.o \ nyqsrc/nyq-osc-server.o nyqsrc/trigger.o \ nyqsrc/lpanal.o nyqsrc/phasevocoder.o \ nyqsrc/pvshell.o nyqstk/src/Generator.o \ nyqstk/src/SineWave.o nyqstk/src/Function.o \ nyqstk/src/FileRead.o nyqstk/src/FileWvIn.o \ nyqstk/src/Effect.o nyqstk/src/Clarinet.o \ nyqstk/src/Delay.o nyqstk/src/DelayL.o \ nyqstk/src/Envelope.o nyqstk/src/Filter.o \ nyqstk/src/Instrmnt.o nyqstk/src/Noise.o \ nyqstk/src/OneZero.o nyqstk/src/ReedTable.o \ nyqstk/src/Saxofony.o nyqstk/src/Stk.o \ nyqstk/src/WaveLoop.o nyqstk/src/WvIn.o \ nyqstk/src/NRev.o nyqstk/src/JCRev.o \ nyqstk/src/PRCRev.o nyqstk/src/PitShift.o \ nyqstk/src/Chorus.o nyqstk/src/Bowed.o \ nyqstk/src/BowTable.o nyqstk/src/ADSR.o \ nyqstk/src/OnePole.o nyqstk/src/BiQuad.o \ nyqstk/src/BandedWG.o nyqstk/src/DelayA.o \ nyqstk/src/Mandolin.o nyqstk/src/PluckTwo.o \ nyqstk/src/Sitar.o nyqstk/src/ModalBar.o \ nyqstk/src/Modal.o nyqstk/src/Flute.o \ nyqstk/src/JetTable.o nyqstk/src/PoleZero.o \ nyqstk/stkinit.o nyqstk/instr.o \ nyqstk/stkint.o ffts/src/fftext.o \ ffts/src/fftlib.o ffts/src/matlib.o \ nyqsrc/sndfnint.o nyqsrc/seqfnint.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = nyqsrc/sndfmt.h nylsf/sndfile.h \ nyqsrc/sound.h nyqsrc/add.h \ nyqsrc/avg.h nyqsrc/compose.h \ nyqsrc/convolve.h nyqsrc/downsample.h \ nyqsrc/fft.h nyqsrc/inverse.h \ nyqsrc/multiseq.h nyqsrc/resamp.h \ nyqsrc/resampv.h nyqsrc/samples.h \ nyqsrc/sndmax.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/sndsliders.h \ nyqsrc/sndwrite.h nyqsrc/yin.h \ nyqsrc/nyq-osc-server.h nyqsrc/trigger.h \ nyqsrc/lpanal.h nyqsrc/phasevocoder.h \ nyqsrc/pvshell.h tran/abs.h \ tran/allpoles.h tran/alpass.h \ tran/alpasscv.h tran/alpassvv.h \ tran/amosc.h tran/areson.h \ tran/aresonvc.h tran/aresoncv.h \ tran/aresonvv.h tran/atone.h \ tran/atonev.h tran/biquadfilt.h \ tran/buzz.h tran/chase.h \ tran/clip.h tran/congen.h \ tran/const.h tran/coterm.h \ tran/delaycc.h tran/delaycv.h \ tran/eqbandvvv.h tran/exp.h \ tran/follow.h tran/fmosc.h \ tran/fromobject.h tran/fromarraystream.h \ tran/gate.h tran/ifft.h \ tran/instrclar.h tran/instrclarall.h \ tran/instrclarfreq.h tran/instrsax.h \ tran/instrsaxall.h tran/instrsaxfreq.h \ tran/integrate.h tran/log.h \ tran/lpreson.h tran/maxv.h \ tran/offset.h tran/oneshot.h \ tran/osc.h tran/partial.h \ tran/pluck.h tran/prod.h \ tran/pwl.h tran/quantize.h \ tran/recip.h tran/reson.h \ tran/resonvc.h tran/resoncv.h \ tran/resonvv.h tran/sampler.h \ tran/scale.h tran/shape.h \ tran/sine.h tran/siosc.h \ tran/slope.h tran/sqrt.h \ tran/tapf.h tran/tapv.h \ tran/tone.h tran/tonev.h \ tran/upsample.h tran/white.h \ tran/stkrev.h tran/stkpitshift.h \ tran/stkchorus.h tran/instrbow.h \ tran/instrbowedfreq.h tran/instrbanded.h \ tran/instrmandolin.h tran/instrsitar.h \ tran/instrmodalbar.h tran/instrflute.h \ tran/instrflutefreq.h tran/instrfluteall.h \ tran/fmfb.h tran/fmfbv.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h \ cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h \ cmt/seqwrite.h cmt/seqmwrite.h bin: mkdir bin liblo/Makefile: cd liblo; ./configure CFLAGS=-m32 LDFLAGS=-m32 CXXFLAGS=-m32 --enable-static --disable-shared # sometimes, residual files cause problems cd liblo; make clean $(LIBLO_PATH)/liblo.a: liblo/Makefile cd liblo; make bin/ser-to-osc: bin $(LIBLO_PATH)/liblo.a $(CC) -c $(CFLAGS) liblo/ser-to-osc/ser-to-osc.cpp \ -o liblo/ser-to-osc/ser-to-osc.o $(LN) liblo/ser-to-osc/ser-to-osc.o -o bin/ser-to-osc $(LFLAGS) bin/test-client: bin $(LIBLO_PATH)/liblo.a $(CC) -c $(CFLAGS) liblo/test-client/test-client.c \ -o liblo/test-client/test-client.o $(LN) liblo/test-client/test-client.o -o bin/test-client $(LFLAGS) portaudio/Makefile: # note: without-jack avoids 32/64-bit link error on Debian cd portaudio; ./configure CFLAGS=-m32 LDFLAGS=-m32 CXXFLAGS=-m32 --enable-static --disable-shared --without-jack # sometimes, residual files cause problems cd portaudio; make clean $(LIBPA_PATH)/libportaudio.a: portaudio/Makefile cd portaudio; make $(NY): $(OBJECTS) $(LIBPA_PATH)/libportaudio.a $(LIBLO_PATH)/liblo.a $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/alsa/system.lsp # make sure it's there before you make it writeable touch runtime/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/alsa/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/convolve.o: nyqsrc/convolve.c nyqsrc/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/convolve.c -o nyqsrc/convolve.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndsliders.o: nyqsrc/sndsliders.c nyqsrc/sndsliders.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sndsliders.c -o nyqsrc/sndsliders.o $(CFLAGS) nyqsrc/sndwritepa.o: nyqsrc/sndwritepa.c nyqsrc/sndwrite.h $(CC) -c nyqsrc/sndwritepa.c -o nyqsrc/sndwritepa.o $(CFLAGS) nyqsrc/yin.o: nyqsrc/yin.c nyqsrc/yin.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/yin.c -o nyqsrc/yin.o $(CFLAGS) nyqsrc/nyq-osc-server.o: nyqsrc/nyq-osc-server.c nyqsrc/nyq-osc-server.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/nyq-osc-server.c -o nyqsrc/nyq-osc-server.o $(CFLAGS) nyqsrc/trigger.o: nyqsrc/trigger.c nyqsrc/trigger.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/trigger.c -o nyqsrc/trigger.o $(CFLAGS) nyqsrc/lpanal.o: nyqsrc/lpanal.c nyqsrc/lpanal.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/lpanal.c -o nyqsrc/lpanal.o $(CFLAGS) nyqsrc/phasevocoder.o: nyqsrc/phasevocoder.c nyqsrc/phasevocoder.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/phasevocoder.c -o nyqsrc/phasevocoder.o $(CFLAGS) nyqsrc/pvshell.o: nyqsrc/pvshell.c nyqsrc/pvshell.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/pvshell.c -o nyqsrc/pvshell.o $(CFLAGS) nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h $(CC) -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c $(CC) -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/sliders.o: nyqsrc/sliders.c nyqsrc/sliders.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c nyqsrc/sliders.c -o nyqsrc/sliders.o $(CFLAGS) ffts/src/fftext.o: ffts/src/fftext.c ffts/src/fftext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c ffts/src/fftext.c -o ffts/src/fftext.o $(CFLAGS) ffts/src/fftlib.o: ffts/src/fftlib.c ffts/src/fftlib.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c ffts/src/fftlib.c -o ffts/src/fftlib.o $(CFLAGS) ffts/src/matlib.o: ffts/src/matlib.c ffts/src/matlib.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c ffts/src/matlib.c -o ffts/src/matlib.o $(CFLAGS) tran/abs.o: tran/abs.c tran/abs.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/abs.c -o tran/abs.o $(CFLAGS) tran/allpoles.o: tran/allpoles.c tran/allpoles.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/allpoles.c -o tran/allpoles.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/alpasscv.o: tran/alpasscv.c tran/alpasscv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/alpasscv.c -o tran/alpasscv.o $(CFLAGS) tran/alpassvv.o: tran/alpassvv.c tran/alpassvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/alpassvv.c -o tran/alpassvv.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/biquadfilt.o: tran/biquadfilt.c tran/biquadfilt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/biquadfilt.c -o tran/biquadfilt.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/const.c -o tran/const.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/eqbandvvv.o: tran/eqbandvvv.c tran/eqbandvvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/eqbandvvv.c -o tran/eqbandvvv.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/instrclar.o: tran/instrclar.c tran/instrclar.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrclar.c -o tran/instrclar.o $(CFLAGS) tran/instrclarall.o: tran/instrclarall.c tran/instrclarall.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrclarall.c -o tran/instrclarall.o $(CFLAGS) tran/instrclarfreq.o: tran/instrclarfreq.c tran/instrclarfreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrclarfreq.c -o tran/instrclarfreq.o $(CFLAGS) tran/instrsax.o: tran/instrsax.c tran/instrsax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsax.c -o tran/instrsax.o $(CFLAGS) tran/instrsaxall.o: tran/instrsaxall.c tran/instrsaxall.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsaxall.c -o tran/instrsaxall.o $(CFLAGS) tran/instrsaxfreq.o: tran/instrsaxfreq.c tran/instrsaxfreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsaxfreq.c -o tran/instrsaxfreq.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/log.c -o tran/log.o $(CFLAGS) tran/lpreson.o: tran/lpreson.c tran/lpreson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/lpreson.c -o tran/lpreson.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/pluck.c -o tran/pluck.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/sqrt.o: tran/sqrt.c tran/sqrt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/sqrt.c -o tran/sqrt.o $(CFLAGS) tran/tapf.o: tran/tapf.c tran/tapf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tapf.c -o tran/tapf.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/white.c -o tran/white.o $(CFLAGS) tran/stkrev.o: tran/stkrev.c tran/stkrev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/stkrev.c -o tran/stkrev.o $(CFLAGS) tran/stkpitshift.o: tran/stkpitshift.c tran/stkpitshift.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/stkpitshift.c -o tran/stkpitshift.o $(CFLAGS) tran/stkchorus.o: tran/stkchorus.c tran/stkchorus.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/stkchorus.c -o tran/stkchorus.o $(CFLAGS) tran/instrbow.o: tran/instrbow.c tran/instrbow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrbow.c -o tran/instrbow.o $(CFLAGS) tran/instrbowedfreq.o: tran/instrbowedfreq.c tran/instrbowedfreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrbowedfreq.c -o tran/instrbowedfreq.o $(CFLAGS) tran/instrbanded.o: tran/instrbanded.c tran/instrbanded.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrbanded.c -o tran/instrbanded.o $(CFLAGS) tran/instrmandolin.o: tran/instrmandolin.c tran/instrmandolin.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrmandolin.c -o tran/instrmandolin.o $(CFLAGS) tran/instrsitar.o: tran/instrsitar.c tran/instrsitar.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrsitar.c -o tran/instrsitar.o $(CFLAGS) tran/instrmodalbar.o: tran/instrmodalbar.c tran/instrmodalbar.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrmodalbar.c -o tran/instrmodalbar.o $(CFLAGS) tran/instrflute.o: tran/instrflute.c tran/instrflute.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrflute.c -o tran/instrflute.o $(CFLAGS) tran/instrflutefreq.o: tran/instrflutefreq.c tran/instrflutefreq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrflutefreq.c -o tran/instrflutefreq.o $(CFLAGS) tran/instrfluteall.o: tran/instrfluteall.c tran/instrfluteall.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/instrfluteall.c -o tran/instrfluteall.o $(CFLAGS) tran/fmfb.o: tran/fmfb.c tran/fmfb.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fmfb.c -o tran/fmfb.o $(CFLAGS) tran/fmfbv.o: tran/fmfbv.c tran/fmfbv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h $(CC) -c tran/fmfbv.c -o tran/fmfbv.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c $(CC) -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c $(CC) -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) nyqstk/stkinit.o: nyqstk/stkinit.cpp nyqstk/stkinit.h g++ -c nyqstk/stkinit.cpp -o nyqstk/stkinit.o $(CFLAGS) nyqstk/instr.o: nyqstk/instr.cpp nyqstk/instr.h g++ -c nyqstk/instr.cpp -o nyqstk/instr.o $(CFLAGS) nyqstk/stkint.o: nyqstk/stkint.cpp nyqstk/stkint.h g++ -c nyqstk/stkint.cpp -o nyqstk/stkint.o $(CFLAGS) nyqstk/src/Generator.o: nyqstk/src/Generator.cpp nyqstk/include/Generator.h g++ -c nyqstk/src/Generator.cpp -o nyqstk/src/Generator.o $(CFLAGS) nyqstk/src/SineWave.o: nyqstk/src/SineWave.cpp nyqstk/include/SineWave.h g++ -c nyqstk/src/SineWave.cpp -o nyqstk/src/SineWave.o $(CFLAGS) nyqstk/src/Function.o: nyqstk/src/Function.cpp nyqstk/include/Function.h g++ -c nyqstk/src/Function.cpp -o nyqstk/src/Function.o $(CFLAGS) nyqstk/src/FileRead.o: nyqstk/src/FileRead.cpp nyqstk/include/FileRead.h g++ -c nyqstk/src/FileRead.cpp -o nyqstk/src/FileRead.o $(CFLAGS) nyqstk/src/FileWvIn.o: nyqstk/src/FileWvIn.cpp nyqstk/include/FileWvIn.h g++ -c nyqstk/src/FileWvIn.cpp -o nyqstk/src/FileWvIn.o $(CFLAGS) nyqstk/src/Effect.o: nyqstk/src/Effect.cpp nyqstk/include/Effect.h g++ -c nyqstk/src/Effect.cpp -o nyqstk/src/Effect.o $(CFLAGS) nyqstk/src/Clarinet.o: nyqstk/src/Clarinet.cpp nyqstk/include/Clarinet.h g++ -c nyqstk/src/Clarinet.cpp -o nyqstk/src/Clarinet.o $(CFLAGS) nyqstk/src/Delay.o: nyqstk/src/Delay.cpp nyqstk/include/Delay.h g++ -c nyqstk/src/Delay.cpp -o nyqstk/src/Delay.o $(CFLAGS) nyqstk/src/DelayL.o: nyqstk/src/DelayL.cpp nyqstk/include/DelayL.h g++ -c nyqstk/src/DelayL.cpp -o nyqstk/src/DelayL.o $(CFLAGS) nyqstk/src/Envelope.o: nyqstk/src/Envelope.cpp nyqstk/include/Envelope.h g++ -c nyqstk/src/Envelope.cpp -o nyqstk/src/Envelope.o $(CFLAGS) nyqstk/src/Filter.o: nyqstk/src/Filter.cpp nyqstk/include/Filter.h g++ -c nyqstk/src/Filter.cpp -o nyqstk/src/Filter.o $(CFLAGS) nyqstk/src/Instrmnt.o: nyqstk/src/Instrmnt.cpp nyqstk/include/Instrmnt.h g++ -c nyqstk/src/Instrmnt.cpp -o nyqstk/src/Instrmnt.o $(CFLAGS) nyqstk/src/Noise.o: nyqstk/src/Noise.cpp nyqstk/include/Noise.h g++ -c nyqstk/src/Noise.cpp -o nyqstk/src/Noise.o $(CFLAGS) nyqstk/src/OneZero.o: nyqstk/src/OneZero.cpp nyqstk/include/OneZero.h g++ -c nyqstk/src/OneZero.cpp -o nyqstk/src/OneZero.o $(CFLAGS) nyqstk/src/ReedTable.o: nyqstk/src/ReedTable.cpp nyqstk/include/ReedTable.h g++ -c nyqstk/src/ReedTable.cpp -o nyqstk/src/ReedTable.o $(CFLAGS) nyqstk/src/Saxofony.o: nyqstk/src/Saxofony.cpp nyqstk/include/Saxofony.h g++ -c nyqstk/src/Saxofony.cpp -o nyqstk/src/Saxofony.o $(CFLAGS) nyqstk/src/Stk.o: nyqstk/src/Stk.cpp nyqstk/include/Stk.h g++ -c nyqstk/src/Stk.cpp -o nyqstk/src/Stk.o $(CFLAGS) nyqstk/src/WaveLoop.o: nyqstk/src/WaveLoop.cpp nyqstk/include/WaveLoop.h g++ -c nyqstk/src/WaveLoop.cpp -o nyqstk/src/WaveLoop.o $(CFLAGS) nyqstk/src/WvIn.o: nyqstk/src/WvIn.cpp nyqstk/include/WvIn.h g++ -c nyqstk/src/WvIn.cpp -o nyqstk/src/WvIn.o $(CFLAGS) nyqstk/src/NRev.o: nyqstk/src/NRev.cpp nyqstk/include/NRev.h g++ -c nyqstk/src/NRev.cpp -o nyqstk/src/NRev.o $(CFLAGS) nyqstk/src/JCRev.o: nyqstk/src/JCRev.cpp nyqstk/include/JCRev.h g++ -c nyqstk/src/JCRev.cpp -o nyqstk/src/JCRev.o $(CFLAGS) nyqstk/src/PRCRev.o: nyqstk/src/PRCRev.cpp nyqstk/include/PRCRev.h g++ -c nyqstk/src/PRCRev.cpp -o nyqstk/src/PRCRev.o $(CFLAGS) nyqstk/src/PitShift.o: nyqstk/src/PitShift.cpp nyqstk/include/PitShift.h g++ -c nyqstk/src/PitShift.cpp -o nyqstk/src/PitShift.o $(CFLAGS) nyqstk/src/Chorus.o: nyqstk/src/Chorus.cpp nyqstk/include/Chorus.h g++ -c nyqstk/src/Chorus.cpp -o nyqstk/src/Chorus.o $(CFLAGS) nyqstk/src/Bowed.o: nyqstk/src/Bowed.cpp nyqstk/include/Bowed.h g++ -c nyqstk/src/Bowed.cpp -o nyqstk/src/Bowed.o $(CFLAGS) nyqstk/src/BowTable.o: nyqstk/src/BowTable.cpp nyqstk/include/BowTable.h g++ -c nyqstk/src/BowTable.cpp -o nyqstk/src/BowTable.o $(CFLAGS) nyqstk/src/ADSR.o: nyqstk/src/ADSR.cpp nyqstk/include/ADSR.h g++ -c nyqstk/src/ADSR.cpp -o nyqstk/src/ADSR.o $(CFLAGS) nyqstk/src/OnePole.o: nyqstk/src/OnePole.cpp nyqstk/include/OnePole.h g++ -c nyqstk/src/OnePole.cpp -o nyqstk/src/OnePole.o $(CFLAGS) nyqstk/src/BiQuad.o: nyqstk/src/BiQuad.cpp nyqstk/include/BiQuad.h g++ -c nyqstk/src/BiQuad.cpp -o nyqstk/src/BiQuad.o $(CFLAGS) nyqstk/src/BandedWG.o: nyqstk/src/BandedWG.cpp nyqstk/include/BandedWG.h g++ -c nyqstk/src/BandedWG.cpp -o nyqstk/src/BandedWG.o $(CFLAGS) nyqstk/src/DelayA.o: nyqstk/src/DelayA.cpp nyqstk/include/DelayA.h g++ -c nyqstk/src/DelayA.cpp -o nyqstk/src/DelayA.o $(CFLAGS) nyqstk/src/Mandolin.o: nyqstk/src/Mandolin.cpp nyqstk/include/Mandolin.h g++ -c nyqstk/src/Mandolin.cpp -o nyqstk/src/Mandolin.o $(CFLAGS) nyqstk/src/PluckTwo.o: nyqstk/src/PluckTwo.cpp nyqstk/include/PluckTwo.h g++ -c nyqstk/src/PluckTwo.cpp -o nyqstk/src/PluckTwo.o $(CFLAGS) nyqstk/src/Sitar.o: nyqstk/src/Sitar.cpp nyqstk/include/Sitar.h g++ -c nyqstk/src/Sitar.cpp -o nyqstk/src/Sitar.o $(CFLAGS) nyqstk/src/ModalBar.o: nyqstk/src/ModalBar.cpp nyqstk/include/ModalBar.h g++ -c nyqstk/src/ModalBar.cpp -o nyqstk/src/ModalBar.o $(CFLAGS) nyqstk/src/Modal.o: nyqstk/src/Modal.cpp nyqstk/include/Modal.h g++ -c nyqstk/src/Modal.cpp -o nyqstk/src/Modal.o $(CFLAGS) nyqstk/src/Flute.o: nyqstk/src/Flute.cpp nyqstk/include/Flute.h g++ -c nyqstk/src/Flute.cpp -o nyqstk/src/Flute.o $(CFLAGS) nyqstk/src/JetTable.o: nyqstk/src/JetTable.cpp nyqstk/include/JetTable.h g++ -c nyqstk/src/JetTable.cpp -o nyqstk/src/JetTable.o $(CFLAGS) nyqstk/src/PoleZero.o: nyqstk/src/PoleZero.cpp nyqstk/include/PoleZero.h g++ -c nyqstk/src/PoleZero.cpp -o nyqstk/src/PoleZero.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h $(CC) -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c $(CC) -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c $(CC) -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c $(CC) -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c $(CC) -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c $(CC) -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c $(CC) -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c $(CC) -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c $(CC) -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c $(CC) -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c $(CC) -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c $(CC) -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c $(CC) -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xljump.o: xlisp/xljump.c $(CC) -c xlisp/xljump.c -o xlisp/xljump.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c $(CC) -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c $(CC) -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c $(CC) -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c $(CC) -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c $(CC) -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c $(CC) -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c $(CC) -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c $(CC) -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c $(CC) -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c $(CC) -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) xlisp/path.o: xlisp/path.c $(CC) -c xlisp/path.c -o xlisp/path.o $(CFLAGS) cmt/cext.o: cmt/cext.c $(CC) -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c $(CC) -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c $(CC) -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c $(CC) -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c $(CC) -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c $(CC) -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c $(CC) -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c $(CC) -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c $(CC) -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c $(CC) -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c $(CC) -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c $(CC) -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c $(CC) -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c $(CC) -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c $(CC) -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c $(CC) -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c $(CC) -c cmt/userio.c -o cmt/userio.o $(CFLAGS) nylsf/aiff.o: nylsf/aiff.c $(CC) -c nylsf/aiff.c -o nylsf/aiff.o $(CFLAGS) nylsf/alaw.o: nylsf/alaw.c $(CC) -c nylsf/alaw.c -o nylsf/alaw.o $(CFLAGS) nylsf/au.o: nylsf/au.c $(CC) -c nylsf/au.c -o nylsf/au.o $(CFLAGS) nylsf/avr.o: nylsf/avr.c $(CC) -c nylsf/avr.c -o nylsf/avr.o $(CFLAGS) nylsf/broadcast.o: nylsf/broadcast.c $(CC) -c nylsf/broadcast.c -o nylsf/broadcast.o $(CFLAGS) nylsf/caf.o: nylsf/caf.c $(CC) -c nylsf/caf.c -o nylsf/caf.o $(CFLAGS) nylsf/command.o: nylsf/command.c $(CC) -c nylsf/command.c -o nylsf/command.o $(CFLAGS) nylsf/common.o: nylsf/common.c $(CC) -c nylsf/common.c -o nylsf/common.o $(CFLAGS) nylsf/dither.o: nylsf/dither.c $(CC) -c nylsf/dither.c -o nylsf/dither.o $(CFLAGS) nylsf/double64.o: nylsf/double64.c $(CC) -c nylsf/double64.c -o nylsf/double64.o $(CFLAGS) nylsf/dwd.o: nylsf/dwd.c $(CC) -c nylsf/dwd.c -o nylsf/dwd.o $(CFLAGS) nylsf/dwvw.o: nylsf/dwvw.c $(CC) -c nylsf/dwvw.c -o nylsf/dwvw.o $(CFLAGS) nylsf/file_io.o: nylsf/file_io.c $(CC) -c nylsf/file_io.c -o nylsf/file_io.o $(CFLAGS) nylsf/flac.o: nylsf/flac.c $(CC) -c nylsf/flac.c -o nylsf/flac.o $(CFLAGS) nylsf/float32.o: nylsf/float32.c $(CC) -c nylsf/float32.c -o nylsf/float32.o $(CFLAGS) nylsf/gsm610.o: nylsf/gsm610.c $(CC) -c nylsf/gsm610.c -o nylsf/gsm610.o $(CFLAGS) nylsf/htk.o: nylsf/htk.c $(CC) -c nylsf/htk.c -o nylsf/htk.o $(CFLAGS) nylsf/ima_adpcm.o: nylsf/ima_adpcm.c $(CC) -c nylsf/ima_adpcm.c -o nylsf/ima_adpcm.o $(CFLAGS) nylsf/interleave.o: nylsf/interleave.c $(CC) -c nylsf/interleave.c -o nylsf/interleave.o $(CFLAGS) nylsf/ircam.o: nylsf/ircam.c $(CC) -c nylsf/ircam.c -o nylsf/ircam.o $(CFLAGS) nylsf/macbinary3.o: nylsf/macbinary3.c $(CC) -c nylsf/macbinary3.c -o nylsf/macbinary3.o $(CFLAGS) nylsf/macos.o: nylsf/macos.c $(CC) -c nylsf/macos.c -o nylsf/macos.o $(CFLAGS) nylsf/mat4.o: nylsf/mat4.c $(CC) -c nylsf/mat4.c -o nylsf/mat4.o $(CFLAGS) nylsf/mat5.o: nylsf/mat5.c $(CC) -c nylsf/mat5.c -o nylsf/mat5.o $(CFLAGS) nylsf/ms_adpcm.o: nylsf/ms_adpcm.c $(CC) -c nylsf/ms_adpcm.c -o nylsf/ms_adpcm.o $(CFLAGS) nylsf/nist.o: nylsf/nist.c $(CC) -c nylsf/nist.c -o nylsf/nist.o $(CFLAGS) nylsf/ogg.o: nylsf/ogg.c $(CC) -c nylsf/ogg.c -o nylsf/ogg.o $(CFLAGS) nylsf/paf.o: nylsf/paf.c $(CC) -c nylsf/paf.c -o nylsf/paf.o $(CFLAGS) nylsf/pcm.o: nylsf/pcm.c $(CC) -c nylsf/pcm.c -o nylsf/pcm.o $(CFLAGS) nylsf/pvf.o: nylsf/pvf.c $(CC) -c nylsf/pvf.c -o nylsf/pvf.o $(CFLAGS) nylsf/raw.o: nylsf/raw.c $(CC) -c nylsf/raw.c -o nylsf/raw.o $(CFLAGS) nylsf/rx2.o: nylsf/rx2.c $(CC) -c nylsf/rx2.c -o nylsf/rx2.o $(CFLAGS) nylsf/sd2.o: nylsf/sd2.c $(CC) -c nylsf/sd2.c -o nylsf/sd2.o $(CFLAGS) nylsf/sds.o: nylsf/sds.c $(CC) -c nylsf/sds.c -o nylsf/sds.o $(CFLAGS) nylsf/sndfile.o: nylsf/sndfile.c $(CC) -c nylsf/sndfile.c -o nylsf/sndfile.o $(CFLAGS) nylsf/strings.o: nylsf/strings.c $(CC) -c nylsf/strings.c -o nylsf/strings.o $(CFLAGS) nylsf/svx.o: nylsf/svx.c $(CC) -c nylsf/svx.c -o nylsf/svx.o $(CFLAGS) nylsf/txw.o: nylsf/txw.c $(CC) -c nylsf/txw.c -o nylsf/txw.o $(CFLAGS) nylsf/ulaw.o: nylsf/ulaw.c $(CC) -c nylsf/ulaw.c -o nylsf/ulaw.o $(CFLAGS) nylsf/voc.o: nylsf/voc.c $(CC) -c nylsf/voc.c -o nylsf/voc.o $(CFLAGS) nylsf/vox_adpcm.o: nylsf/vox_adpcm.c $(CC) -c nylsf/vox_adpcm.c -o nylsf/vox_adpcm.o $(CFLAGS) nylsf/w64.o: nylsf/w64.c $(CC) -c nylsf/w64.c -o nylsf/w64.o $(CFLAGS) nylsf/wav.o: nylsf/wav.c $(CC) -c nylsf/wav.c -o nylsf/wav.o $(CFLAGS) nylsf/wav_w64.o: nylsf/wav_w64.c $(CC) -c nylsf/wav_w64.c -o nylsf/wav_w64.o $(CFLAGS) nylsf/wve.o: nylsf/wve.c $(CC) -c nylsf/wve.c -o nylsf/wve.o $(CFLAGS) nylsf/xi.o: nylsf/xi.c $(CC) -c nylsf/xi.c -o nylsf/xi.o $(CFLAGS) nylsf/g72x.o: nylsf/g72x.c $(CC) -c nylsf/g72x.c -o nylsf/g72x.o $(CFLAGS) nylsf/GSM610/add.o: nylsf/GSM610/add.c $(CC) -c nylsf/GSM610/add.c -o nylsf/GSM610/add.o $(CFLAGS) nylsf/GSM610/code.o: nylsf/GSM610/code.c $(CC) -c nylsf/GSM610/code.c -o nylsf/GSM610/code.o $(CFLAGS) nylsf/GSM610/decode.o: nylsf/GSM610/decode.c $(CC) -c nylsf/GSM610/decode.c -o nylsf/GSM610/decode.o $(CFLAGS) nylsf/GSM610/gsm_create.o: nylsf/GSM610/gsm_create.c $(CC) -c nylsf/GSM610/gsm_create.c -o nylsf/GSM610/gsm_create.o $(CFLAGS) nylsf/GSM610/gsm_decode.o: nylsf/GSM610/gsm_decode.c $(CC) -c nylsf/GSM610/gsm_decode.c -o nylsf/GSM610/gsm_decode.o $(CFLAGS) nylsf/GSM610/gsm_destroy.o: nylsf/GSM610/gsm_destroy.c $(CC) -c nylsf/GSM610/gsm_destroy.c -o nylsf/GSM610/gsm_destroy.o $(CFLAGS) nylsf/GSM610/gsm_encode.o: nylsf/GSM610/gsm_encode.c $(CC) -c nylsf/GSM610/gsm_encode.c -o nylsf/GSM610/gsm_encode.o $(CFLAGS) nylsf/GSM610/gsm_option.o: nylsf/GSM610/gsm_option.c $(CC) -c nylsf/GSM610/gsm_option.c -o nylsf/GSM610/gsm_option.o $(CFLAGS) nylsf/GSM610/long_term.o: nylsf/GSM610/long_term.c $(CC) -c nylsf/GSM610/long_term.c -o nylsf/GSM610/long_term.o $(CFLAGS) nylsf/GSM610/lpc.o: nylsf/GSM610/lpc.c $(CC) -c nylsf/GSM610/lpc.c -o nylsf/GSM610/lpc.o $(CFLAGS) nylsf/GSM610/preprocess.o: nylsf/GSM610/preprocess.c $(CC) -c nylsf/GSM610/preprocess.c -o nylsf/GSM610/preprocess.o $(CFLAGS) nylsf/GSM610/rpe.o: nylsf/GSM610/rpe.c $(CC) -c nylsf/GSM610/rpe.c -o nylsf/GSM610/rpe.o $(CFLAGS) nylsf/GSM610/short_term.o: nylsf/GSM610/short_term.c $(CC) -c nylsf/GSM610/short_term.c -o nylsf/GSM610/short_term.o $(CFLAGS) nylsf/GSM610/table.o: nylsf/GSM610/table.c $(CC) -c nylsf/GSM610/table.c -o nylsf/GSM610/table.o $(CFLAGS) nylsf/G72x/g721.o: nylsf/G72x/g721.c $(CC) -c nylsf/G72x/g721.c -o nylsf/G72x/g721.o $(CFLAGS) nylsf/G72x/g723_16.o: nylsf/G72x/g723_16.c $(CC) -c nylsf/G72x/g723_16.c -o nylsf/G72x/g723_16.o $(CFLAGS) nylsf/G72x/g723_24.o: nylsf/G72x/g723_24.c $(CC) -c nylsf/G72x/g723_24.c -o nylsf/G72x/g723_24.o $(CFLAGS) nylsf/G72x/g723_40.o: nylsf/G72x/g723_40.c $(CC) -c nylsf/G72x/g723_40.c -o nylsf/G72x/g723_40.o $(CFLAGS) nylsf/G72x/g72x.o: nylsf/G72x/g72x.c $(CC) -c nylsf/G72x/g72x.c -o nylsf/G72x/g72x.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c $(CC) -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean cd liblo; test -f Makefile && make clean || true cd portaudio; test -f Makefile && make clean || true rm -f $(OBJECTS) # These could be deleted, but they're part of the release, so we won't # Note that these files are machine-generated: # rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h # rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f #*# */#*# rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat rm -f core.* core rm -f $(NY) release: cleaner cd misc; make packer misc/packer files.txt release.pac rm -f *.wav mv ny .. mv -f *.pac .. rm -f unpacker rm -f packer cd ..; zip -r nyquist.zip nyquist ../ny misc/cmu/cmu-linux-install.lsp mv ../ny ./ny nyquist-3.05/sys/unix/alsa/system.lsp0000644000175000000620000000623011512414056016750 0ustar stevestaff;; system.lsp -- system-dependent lisp code ; local definition for play ; this one is for Linux: (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-wave)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "./")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* (strcat (get-user) "-points.dat"))) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (or (eq (char filename 0) #\/) (eq (char filename 0) #\.))) ; RELATIVE-PATH-P -- test if filename or path is a relative path ; (defun relative-path-p (filename) (not (eq (char filename 0) #\/))) (setf *file-separator* #\/) ;; PLAY-FILE - play a sound file ;; (defun play-file (name) ;; ;; WARNING: if you invoke an external program to play files, ;; but Nyquist uses internal (portaudio) interface to ;; play synthesized sound, Nyquist may fail to open the ;; sound device while it is playing a sound file and then ;; refuse to play anything. -RBD dec05 ;; (system (strcat "sndplay " (soundfilename name)))) ;; (system (strcat "play " (soundfilename name) ))) ;; (play (s-read (soundfilename name)))) ;; R - replay last file written with PLAY (defun r () (play-file *default-sound-file*)) ;;;; use this old version if you want to use sndplay to play ;;;; the result file rather than play the samples as they ;;;; are computed. This version does not autonormalize. ;; PLAY - write value of an expression to file and play it ;; ;(defmacro play (expr) ; `(prog (specs) ; (setf specs (s-save (force-srate *sound-srate* ,expr) ; 1000000000 *default-sound-file*)) ; (r))) ;;;; ; local definition for play (defmacro play (expr) `(s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*)) ;; for Linux, modify s-plot (defined in nyquist.lsp) by saving s-plot ;; in standard-s-plot, then call gnuplot to display the points. ;; ;; we also need to save the location of this file so we can find ;; nyquist-plot.txt, the command file for gnuplot ;; ;; This code is broken in the following ways: ;; it tries to run gnuplot even when plotting can be done by NyquistIDE ;; it plots "points.dat", but "points.dat" may not be correct ;; (see *default-plot-file*) ;; it assumes the plot file is in the current directory, but it ;; by default goes to the sound file directory ;; ;; Fix this code or complain if you want to plot with gnuplot while ;; running ny (or even NyquistIDE (jny) if you want). Otherwise, use ;; NyquistIDE to get s-plot to work. ;; ;(setf *runtime-path* (current-path)) ;(display "system.lsp" *runtime-path*) ; ;(setfn standard-s-plot s-plot) ; ;(defun s-plot (s &optional (dur 2.0) (n 1000)) ; (let (plot-file) ; (standard-s-plot s dur n) ;; this calculates the data points ; (setf plot-file (strcat *runtime-path* "nyquist-plot.txt")) ; (system (strcat "gnuplot -persist " plot-file)))) nyquist-3.05/sys/unix/pl0000644000175000000620000000004110144436365014323 0ustar stevestaffgraph < points.dat | plot -Ttek nyquist-3.05/sys/unix/rs6k/0002755000175000000620000000000011537433131014654 5ustar stevestaffnyquist-3.05/sys/unix/rs6k/plotscript0000644000175000000620000000007010144436365017002 0ustar stevestaffcat $1 | graph | tplot -Ttek echo "Type ^D to exit" cat nyquist-3.05/sys/unix/rs6k/Makefile0000644000175000000620000005010510144436365016320 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is RS6K # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny # Standard list of includes (common to all unix versions) INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Isnd -Ifft # system dependent stuff for rs6k: MIDI = /afs/cs/project/music/rs6k/midilib CC = cc # change -g to -O for optimization CFLAGS = -DCMTSTUFF -g $(INCL) -I$(MIDI) XFLAGS = $(CFLAGS) -qlanglvl=extended LN = xlc -qattr -qlist LFLAGS = -lm -L$(MIDI) -lmidi -lbsd -lg INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o xlisp/xlsym.o xlisp/xlsys.o \ tran/amosc.o tran/clip.o tran/const.o tran/fmosc.o \ tran/integrate.o tran/log.o tran/maxv.o tran/osc.o \ tran/prod.o tran/buzz.o tran/pwl.o tran/recip.o \ tran/upsample.o tran/scale.o tran/sine.o tran/partial.o \ tran/white.o tran/tone.o tran/tonev.o tran/atonev.o \ tran/atone.o tran/reson.o tran/areson.o tran/resonvc.o \ tran/resoncv.o tran/aresonvc.o tran/aresoncv.o tran/resonvv.o \ tran/aresonvv.o tran/offset.o tran/slope.o tran/delay.o \ tran/delaycv.o tran/shape.o tran/sampler.o tran/exp.o \ tran/siosc.o tran/follow.o tran/gate.o tran/quantize.o \ tran/ifft.o tran/congen.o tran/fromobject.o tran/fromarraystream.o \ tran/coterm.o tran/convolve.o tran/alpass.o tran/oneshot.o \ tran/chase.o tran/tapv.o tran/biquad.o tran/pluck.o \ cmt/cext.o cmt/cleanup.o cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nyqsrc/debug.o nyqsrc/falloc.o nyqsrc/add.o \ nyqsrc/local.o nyqsrc/downsample.o nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/multiseq.o nyqsrc/samples.o nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/sndread.o nyqsrc/sndseq.o nyqsrc/sndwrite.o nyqsrc/sndmax.o \ nyqsrc/sound.o nyqsrc/stats.o nyqsrc/compose.o nyqsrc/inverse.o \ nyqsrc/resamp.o nyqsrc/resampv.o nyqsrc/ffilterkit.o nyqsrc/avg.o \ nyqsrc/fft.o nyqsrc/sndfail.o fft/fftn.o nyqsrc/sndfnint.o \ nyqsrc/seqfnint.o snd/audiors6k.o snd/sndrs6k.o snd/ieeecvt.o \ snd/snd.o snd/sndcvt.o snd/sndio.o snd/sndheader.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = snd/snd.h nyqsrc/sound.h nyqsrc/downsample.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/add.h nyqsrc/multiseq.h nyqsrc/samples.h \ nyqsrc/sndwrite.h nyqsrc/sndmax.h nyqsrc/compose.h nyqsrc/inverse.h \ nyqsrc/resamp.h nyqsrc/resampv.h nyqsrc/fft.h nyqsrc/avg.h \ tran/amosc.h tran/clip.h tran/const.h tran/fmosc.h \ tran/integrate.h tran/log.h tran/maxv.h tran/osc.h \ tran/prod.h tran/buzz.h tran/pwl.h tran/recip.h \ tran/upsample.h tran/scale.h tran/sine.h tran/partial.h \ tran/white.h tran/tone.h tran/tonev.h tran/atonev.h \ tran/atone.h tran/reson.h tran/areson.h tran/resonvc.h \ tran/resoncv.h tran/aresonvc.h tran/aresoncv.h tran/resonvv.h \ tran/aresonvv.h tran/offset.h tran/slope.h tran/delaycc.h \ tran/delaycv.h tran/shape.h tran/sampler.h tran/exp.h \ tran/siosc.h tran/follow.h tran/gate.h tran/quantize.h \ tran/ifft.h tran/congen.h tran/fromobject.h tran/fromarraystream.h \ tran/coterm.h tran/convolve.h tran/alpass.h tran/oneshot.h \ tran/chase.h tran/tapv.h tran/biquad.h tran/pluck.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h cmt/seqwrite.h cmt/seqmwrite.h EVERYTHING = $(NY) runtime/system.lsp CURRENT = $(EVERYTHING) current: $(CURRENT) $(NY): $(OBJECTS) $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/rs6k/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/rs6k/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h cc -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c cc -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndwrite.o: nyqsrc/sndwrite.c nyqsrc/sndwrite.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndwrite.c -o nyqsrc/sndwrite.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/sndfail.o: nyqsrc/sndfail.c cc -c nyqsrc/sndfail.c -o nyqsrc/sndfail.o $(CFLAGS) snd/audiors6k.o: snd/audiors6k.c snd/snd.h cc -c snd/audiors6k.c -o snd/audiors6k.o $(CFLAGS) snd/sndrs6k.o: snd/sndrs6k.c snd/sndrs6k.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndrs6k.c -o snd/sndrs6k.o $(CFLAGS) snd/ieeecvt.o: snd/ieeecvt.c snd/ieeecvt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/ieeecvt.c -o snd/ieeecvt.o $(CFLAGS) snd/snd.o: snd/snd.c snd/snd.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/snd.c -o snd/snd.o $(CFLAGS) snd/sndcvt.o: snd/sndcvt.c snd/snd.h cc -c snd/sndcvt.c -o snd/sndcvt.o $(CFLAGS) snd/sndio.o: snd/sndio.c snd/snd.h cc -c snd/sndio.c -o snd/sndio.o $(CFLAGS) snd/sndheader.o: snd/sndheader.c snd/sndheader.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndheader.c -o snd/sndheader.o $(CFLAGS) fft/fftn.o: fft/fftn.c fft/fftn.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c fft/fftn.c -o fft/fftn.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/const.c -o tran/const.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/log.c -o tran/log.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/white.c -o tran/white.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/convolve.o: tran/convolve.c tran/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/convolve.c -o tran/convolve.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/biquad.o: tran/biquad.c tran/biquad.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/biquad.c -o tran/biquad.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pluck.c -o tran/pluck.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c cc -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c cc -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h cc -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c cc -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c cc -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c cc -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c cc -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c cc -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c cc -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c cc -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c cc -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c cc -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c cc -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c cc -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c cc -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xljump.o: xlisp/xljump.c cc -c xlisp/xljump.c -o xlisp/xljump.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c cc -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c cc -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c cc -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c cc -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c cc -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c cc -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c cc -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c cc -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c cc -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c cc -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) cmt/cext.o: cmt/cext.c cc -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c cc -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c cc -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c cc -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c cc -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c cc -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c cc -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c cc -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c cc -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c cc -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c cc -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c cc -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c cc -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c cc -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c cc -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c cc -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c cc -c cmt/userio.c -o cmt/userio.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c cc -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) snd/snd.h misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean rm -f $(OBJECTS) # Note that these files are machine-generated: rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat tar: cleaner sh -v sys/unix/cmu/tar.script backup: cleaner sh -v sys/unix/cmu/backup.script nyquist-3.05/sys/unix/rs6k/system.lsp0000644000175000000620000000404111466723256016730 0ustar stevestaff; machine.lsp -- machine/system-dependent definitions ; rs6000 (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-NeXT)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "/tmp/")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* "points.dat")) ; turn off switch to play sound as it is computed (setf *soundenable* nil) ; local definition for play (defmacro play (expr) `(let () (s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*) (r))) (defun r () (play-file *default-sound-file*)) ; PLAY-FILE -- play a file (defun play-file (name) (system (format nil "acpaplay ~A" (soundfilename name)))) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (or (eq (char filename 0) #\/) (eq (char filename 0) #\.))) (setf *file-separator* #\/) ; save the standard function to write points to a file ; (setfn s-plot-points s-plot) ; S-PLOT - plot a small number of points ; (defun s-plot (&rest args) (let ((n (soundfilename *default-plot-file*))) (apply #'s-plot-points args) (cond ((boundp '*plotscript-file*)) (t (format t "*plotscript-file* is unbound, setting it to: \n") (format t " sys/unix/rs6k/plotscript\n") (format t "You may need to set it to a full path\n") (setf *plotscript-file* "sys/unix/rs6k/plotscript"))) (system (format nil "xterm -t -e ~A ~A" *plotscript-file* n)))) ; S-EDIT - run the audio editor on a sound ; (defmacro s-edit (&optional expr) `(prog () (if ,expr (s-save ,expr 1000000000 *default-sound-file*)) (system (format nil "audio_editor ~A &" (soundfilename *default-sound-file*))))) nyquist-3.05/sys/unix/osx/0002755000175000000620000000000011537433131014600 5ustar stevestaffnyquist-3.05/sys/unix/osx/run0000755000175000000620000000025711466723256015347 0ustar stevestaff#csh # INSTRUCTIONS: for developers, in the top nyquist directory: # ln -l sys/unix/osx/run # ln -s macosxproject/build/ny java -cp jnyqide/NyquistIDE.jar jnyqide.Main nyquist-3.05/sys/unix/osx/system.lsp0000644000175000000620000000344511466723256016663 0ustar stevestaff;; system.lsp -- system-dependent lisp code ; local definition for play ; this one is for Mac OS-X: (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-wave)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "/tmp")) (format t "*default-sf-dir* (default sound file directory) is ~A~%" *default-sf-dir*) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* (strcat (get-user) "-points.dat"))) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (or (eq (char filename 0) #\/) (eq (char filename 0) #\.))) ; RELATIVE-PATH-P -- test if filename or path is a relative path ; (defun relative-path-p (filename) (not (eq (char filename 0) #\/))) (setf *file-separator* #\/) ;; PLAY-FILE - play a sound file ;; (defun play-file (name) (s-save (s-read name) NY:ALL "" :play t)) ;; R - replay last file written with PLAY (defun r () (play-file *default-sound-file*)) ;;;; use this old version if you want to use sndplay to play ;;;; the result file rather than play the samples as they ;;;; are computed. This version does not autonormalize. ;; PLAY - write value of an expression to file and play it ;; ;(defmacro play (expr) ; `(prog (specs) ; (setf specs (s-save (force-srate *sound-srate* ,expr) ; 1000000000 *default-sound-file*)) ; (r))) ;;;; ; local definition for play (defmacro play (expr) `(s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*)) ;; use standard s-plot nyquist-3.05/sys/unix/sparc/0002755000175000000620000000000011537433131015077 5ustar stevestaffnyquist-3.05/sys/unix/sparc/Makefile0000644000175000000620000004752110144436365016553 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is SPARC # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny # Standard list of includes (common to all unix versions) INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Isnd -Ifft # system dependent stuff for sparc: CC = gcc CFLAGS = -DCMTSTUFF -g $(INCL) LN = $(CC) LFLAGS = -lm INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o xlisp/xlsym.o xlisp/xlsys.o \ tran/amosc.o tran/clip.o tran/const.o tran/fmosc.o \ tran/integrate.o tran/log.o tran/maxv.o tran/osc.o \ tran/prod.o tran/buzz.o tran/pwl.o tran/recip.o \ tran/upsample.o tran/scale.o tran/sine.o tran/partial.o \ tran/white.o tran/tone.o tran/tonev.o tran/atonev.o \ tran/atone.o tran/reson.o tran/areson.o tran/resonvc.o \ tran/resoncv.o tran/aresonvc.o tran/aresoncv.o tran/resonvv.o \ tran/aresonvv.o tran/offset.o tran/slope.o tran/delay.o \ tran/delaycv.o tran/shape.o tran/sampler.o tran/exp.o \ tran/siosc.o tran/follow.o tran/gate.o tran/quantize.o \ tran/ifft.o tran/congen.o tran/fromobject.o tran/fromarraystream.o \ tran/coterm.o tran/convolve.o tran/alpass.o tran/oneshot.o \ tran/chase.o tran/tapv.o tran/biquad.o tran/pluck.o \ cmt/cext.o cmt/cleanup.o cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nyqsrc/debug.o nyqsrc/falloc.o nyqsrc/add.o \ nyqsrc/local.o nyqsrc/downsample.o nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/multiseq.o nyqsrc/samples.o nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/sndread.o nyqsrc/sndseq.o nyqsrc/sndwrite.o nyqsrc/sndmax.o \ nyqsrc/sound.o nyqsrc/stats.o nyqsrc/compose.o nyqsrc/inverse.o \ nyqsrc/resamp.o nyqsrc/resampv.o nyqsrc/ffilterkit.o nyqsrc/avg.o \ nyqsrc/fft.o nyqsrc/sndfail.o fft/fftn.o nyqsrc/sndfnint.o \ nyqsrc/seqfnint.o snd/audiosparc.o snd/sndsparc.o snd/ieeecvt.o \ snd/snd.o snd/sndcvt.o snd/sndio.o snd/sndheader.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = snd/snd.h nyqsrc/sound.h nyqsrc/downsample.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/add.h nyqsrc/multiseq.h nyqsrc/samples.h \ nyqsrc/sndwrite.h nyqsrc/sndmax.h nyqsrc/compose.h nyqsrc/inverse.h \ nyqsrc/resamp.h nyqsrc/resampv.h nyqsrc/fft.h nyqsrc/avg.h \ tran/amosc.h tran/clip.h tran/const.h tran/fmosc.h \ tran/integrate.h tran/log.h tran/maxv.h tran/osc.h \ tran/prod.h tran/buzz.h tran/pwl.h tran/recip.h \ tran/upsample.h tran/scale.h tran/sine.h tran/partial.h \ tran/white.h tran/tone.h tran/tonev.h tran/atonev.h \ tran/atone.h tran/reson.h tran/areson.h tran/resonvc.h \ tran/resoncv.h tran/aresonvc.h tran/aresoncv.h tran/resonvv.h \ tran/aresonvv.h tran/offset.h tran/slope.h tran/delaycc.h \ tran/delaycv.h tran/shape.h tran/sampler.h tran/exp.h \ tran/siosc.h tran/follow.h tran/gate.h tran/quantize.h \ tran/ifft.h tran/congen.h tran/fromobject.h tran/fromarraystream.h \ tran/coterm.h tran/convolve.h tran/alpass.h tran/oneshot.h \ tran/chase.h tran/tapv.h tran/biquad.h tran/pluck.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h cmt/seqwrite.h cmt/seqmwrite.h EVERYTHING = $(NY) runtime/system.lsp CURRENT = $(EVERYTHING) current: $(CURRENT) $(NY): $(OBJECTS) $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/sparc/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/sparc/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h cc -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c cc -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndwrite.o: nyqsrc/sndwrite.c nyqsrc/sndwrite.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndwrite.c -o nyqsrc/sndwrite.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/sndfail.o: nyqsrc/sndfail.c cc -c nyqsrc/sndfail.c -o nyqsrc/sndfail.o $(CFLAGS) snd/audiosparc.o: snd/audiosparc.c snd/snd.h cc -c snd/audiosparc.c -o snd/audiosparc.o $(CFLAGS) snd/sndsparc.o: snd/sndsparc.c snd/sndsparc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndsparc.c -o snd/sndsparc.o $(CFLAGS) snd/ieeecvt.o: snd/ieeecvt.c snd/ieeecvt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/ieeecvt.c -o snd/ieeecvt.o $(CFLAGS) snd/snd.o: snd/snd.c snd/snd.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/snd.c -o snd/snd.o $(CFLAGS) snd/sndcvt.o: snd/sndcvt.c snd/snd.h cc -c snd/sndcvt.c -o snd/sndcvt.o $(CFLAGS) snd/sndio.o: snd/sndio.c snd/snd.h cc -c snd/sndio.c -o snd/sndio.o $(CFLAGS) snd/sndheader.o: snd/sndheader.c snd/sndheader.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndheader.c -o snd/sndheader.o $(CFLAGS) fft/fftn.o: fft/fftn.c fft/fftn.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c fft/fftn.c -o fft/fftn.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/const.c -o tran/const.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/log.c -o tran/log.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/white.c -o tran/white.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/convolve.o: tran/convolve.c tran/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/convolve.c -o tran/convolve.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/biquad.o: tran/biquad.c tran/biquad.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/biquad.c -o tran/biquad.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pluck.c -o tran/pluck.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c cc -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c cc -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h cc -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c cc -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c cc -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c cc -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c cc -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c cc -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c cc -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c cc -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c cc -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c cc -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c cc -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c cc -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c cc -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xljump.o: xlisp/xljump.c cc -c xlisp/xljump.c -o xlisp/xljump.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c cc -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c cc -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c cc -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c cc -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c cc -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c cc -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c cc -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c cc -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c cc -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c cc -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) cmt/cext.o: cmt/cext.c cc -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c cc -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c cc -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c cc -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c cc -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c cc -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c cc -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c cc -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c cc -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c cc -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c cc -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c cc -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c cc -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c cc -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c cc -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c cc -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c cc -c cmt/userio.c -o cmt/userio.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c cc -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) snd/snd.h misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean rm -f $(OBJECTS) # Note that these files are machine-generated: rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat nyquist-3.05/sys/unix/sparc/system.lsp0000644000175000000620000000135111466723256017154 0ustar stevestaff; machine.lsp -- machine/system-dependent definitions ; sparc (setf *default-sound-srate* 8192) (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-NeXT)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "/tmp")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) ; local definition for play (defun r () (system (format nil "play ~A" *default-sound-file*))) (defmacro play (expr) `(prog (specs) (setf specs (s-save ,expr NY:ALL *default-sound-file*)) (r))) nyquist-3.05/sys/unix/osstuff.c0000644000175000000620000005110611524074337015632 0ustar stevestaff/* unixtuff.c - unix interface routines for xlisp * HISTORY * 5-Mar-07 Dannenberg * worked on hidden_msg() and hidden message handling * * 23-Dec-05 Dannenberg * still more hacks: Mac and Linux don't disable character echo like * windows does using a pipe to an IDE. To make UNIX versions match * the Windows behavior (which is preferable), added * echo_enabled flag and a function to set/clear it from XLisp. * This will give unix-specific behavior to compensate for the * unix-specific character echo. This worked, but printed * (echoenabled nil) on the console, which was pretty ugly, so I * added ctrl-e and ctrl-f handlers to turn echo on and off. Now * Java can just send ctrl-f before anything else. Windows must * ignore ctrl-f. * * 28-Apr-03 Mazzoni * many changes for new conditional compilation organization * * 28-Jun-95 Dannenberg * removed buffering (which could overflow) from ostgetc. * * 2-Aprl-88 Dale Amon at CMU-CSD * Upgraded to xlisp 2.0. Used msstuff.c as a template. * * 20-Apr-87 Dale Amon at CMU-CSD * Added control-c interrupt handler. Puts user in breakloop and allows * continue. Prints line at which the interrupt occured. Interrupt * occurs at first eval after ^C has been typed. * * 19-APR-87 Dale Amon at CMU-CSD * switched from rand to random package. Corrected bug in osrand(). It * did not use the argument n to calculate a rand in range 0 to n-1 as * advertised. * 28-OCT-05 Roger Dannenberg at CMU-SCS * added directory listing functions */ #include "switches.h" #include #include #include #include #include #include #include "xlisp.h" #include "term.h" #include "cext.h" #include "userio.h" #include "exitpa.h" #include "sliders.h" /* define sliders -- not just for OSC */ #if OSC #include "sound.h" /* define nosc_enabled */ #endif #define LBSIZE 200 /* external variables */ extern LVAL s_unbound,s_true; extern FILE *tfp; /* local variables */ static int lindex; static int lcount = 0; static int lposition; static int line_edit = TRUE; #ifndef READ_LINE #define typeahead_max 128 static char typeahead[typeahead_max]; static int typeahead_tail = 0; static int typeahead_head = 0; static char lbuf[LBSIZE]; static int lpos[LBSIZE]; #endif static int echo_enabled = 1; /* forward declarations */ FORWARD LOCAL void xflush(); FORWARD LOCAL int xcheck(); FORWARD LOCAL void hidden_msg(); /*==========================================================================*/ /* control-c interrupt handling routines and variables. Uses B4.2 signal handling. Previous SIGINT handler is saved just in case someday we want to play with turning control c on and off. */ #include static int ctc = FALSE; static void control_c(int x) {ctc = TRUE;} void ctcinit() {signal ( SIGINT, control_c );} static void ctcreset() {signal ( SIGINT, control_c );} /*==========================================================================*/ const char os_pathchar = '/'; const char os_sepchar = ':'; /* osinit - initialize */ void osinit(char *banner) { printf("%s\n",banner); /* start the random number generator. Older version was srand(1) seed of 1 makes the sequence repeatable. Random gives better pseudo randomness than does rand(). */ #if USE_RAND srand(1); #endif #if USE_RANDOM srandom(1); #endif #ifndef UNIX /* set control c trap to local routine */ ctcinit(); #else /* sets terminal for raw input and calls ctcinit too */ term_init(); term_character(); #endif lposition = 0; lindex = 0; lcount = 0; } /* osfinish - clean up before returning to the operating system */ void osfinish(void) { term_exit(); portaudio_exit(); } /* oserror - print an error message */ void oserror(char *msg) {printf("error: %s\n",msg);} /* osaopen - open an ascii file */ FILE *osaopen(name,mode) char *name,*mode; { FILE *fp; fp = fopen(name,mode); #ifdef DEBUG_INPUT printf("osaopen on %s yields %x\n", name, fp); if (strcmp(name, "/home/rbd/nyquist/lib/xm-test.lsp") == 0) { // when DEBUG_INPUT is set, this generates a compiler error // on linux -RBD debug_input_fp = fp; printf("osaopen: debug_input_fp gets %x\n", debug_input_fp); } #endif return fp; } /* osbopen - open a binary file */ FILE *osbopen(name,mode) char *name,*mode; { char bmode[10]; FILE *fp; strcpy(bmode,mode); strcat(bmode,"b"); fp = fopen(name,bmode); return fp; } /* osclose - close a file */ int osclose(fp) FILE *fp; { #ifdef DEBUG_INPUT if (debug_input_fp == fp) { debug_input_fp = NULL; printf("osclose: debug_input_fp gets %x\n", debug_input_fp); } #endif /* when XLISP is loading files and an error is encountered, the files * are automatically closed so that the OS will not lock them, confusing * the user. So we could get here and the file could already be closed */ return (fp ? fclose(fp) : 0); } /* osagetc - get a character from an ascii file */ int osagetc(fp) FILE *fp; { #ifdef DEBUG_INPUT int c = getc(fp); ungetc(c, fp); #endif return (getc(fp)); } /* osaputc - put a character to an ascii file */ int osaputc(int ch, FILE *fp) { return (putc(ch,fp)); } /* osoutflush - flush output to a file */ void osoutflush(FILE *fp) { fflush(fp); } extern int dbgflg; /* osbgetc - get a character from a binary file */ /* int osbgetc(fp) FILE *fp; {return (getc(fp));} */ int osbgetc(FILE *fp) { int c = (getc(fp)); /* if (dbgflg) printf("osbgetc: got %d from FILE %x\n", c, fp); */ return c; } /* osbputc - put a character to a binary file */ int osbputc(ch,fp) int ch; FILE *fp; {return (putc(ch,fp));} #ifdef OLDEST_OSTGETC /* ostgetc - get a character from the terminal */ int ostgetc() { int ch; switch (ch = term_getchar()) { case '\n': lbuf[lcount++] = '\n'; lposition = 0; if (tfp) for (lindex = 0; lindex < lcount; ++lindex) osaputc(lbuf[lindex],tfp); lindex = 0; lcount = 0; return (ch); case '\010': case '\177': if (lcount) { lcount--; while (lposition > lpos[lcount]) { lposition--; } } break; case '\032': xflush(); return (EOF); default: if (ch == '\t' || (ch >= 0x20 && ch < 0x7F)) { lbuf[lcount] = ch; lpos[lcount] = lposition; if (ch == '\t') do {} while (++lposition & 7); else {lposition++;} lcount++; return (ch); } else { xflush(); switch (ch) { case '\003': xltoplevel(); /* control-c */ case '\007': xlcleanup(); /* control-g */ case '\020': xlcontinue(); /* control-p */ case '\032': return (EOF); /* control-z */ /* moved from oscheck until I figure out how to set up interrupt to handle these two */ case '\002': xflush(); xlbreak("BREAK",s_unbound); break; /* control-b */ case '\024': xinfo(); break; /* control-t */ default: return (ch); } } } } #else #if OLD_OSTGETC /* ostgetc - get a character from the terminal */ int ostgetc() { int ch; for (;;) { ch = term_getchar(); oscheck(); switch (ch) { case '\003': xltoplevel(); /* control-c */ case '\007': xlcleanup(); /* control-g */ case '\020': xlcontinue(); /* control-p */ case '\032': return EOF; /* control-z */ case '\002': xflush(); xlbreak("BREAK",s_unbound); break; /* control-b */ case '\024': xinfo(); break; /* control-t */ case '\t': case '\n': default: if (tfp) osaputc(ch, tfp); return ch; } } } #else #ifdef READLINE #include #include char *readline_line = NULL; int readline_pos = 0; int readline_len = 0; int readline_first = 1; extern int xldebug; int ostgetc() { int rval; if (readline_first) using_history(); if (!readline_line) { char prompt[10]; if (xldebug==0) sprintf(prompt, "> "); else sprintf(prompt, "%d> ", xldebug); readline_line = readline(prompt); if (readline_line == NULL) return EOF; add_history(readline_line); readline_len = strlen(readline_line); readline_pos = 0; } rval = readline_line[readline_pos]; if (readline_pos == readline_len) { free(readline_line); readline_line = NULL; return '\n'; } readline_pos++; return rval; } #else /* no readline */ void end_of_line_edit() { line_edit = FALSE; if (tfp) { for (lindex = 0; lindex < lcount; ++lindex) osaputc(lbuf[lindex], tfp); } lindex = 0; } /* THIS IS THE "REAL" ostgetc(): */ LOCAL int rawtchar() { int ch; if (typeahead_tail != typeahead_head) { ch = typeahead[typeahead_head++]; typeahead_head &= (typeahead_max - 1); /* printf("[%c]", ch); */ if (ch == 0xFF) ch = -1; /* char to int conversion of EOF */ } else { fflush(stdout); /* necessary on OS X with Java IDE - I don't know why. */ /* don't use getchar() or buffering will cause out-of-order input */ ch = term_getchar(); /* printf("{%c}", ch); */ } return ch; } int ostgetc() { /* * NOTE: lbuf[] accumulates characters as they are typed * lpos[] is the column position of the characters * lcount is the number of characters in lbuf * lposition is current position * lindex is index of next char to output * line_edit is true iff we're inputing characters * */ int ch; while (line_edit) { ch = rawtchar(); if (ch == EOF) xlisp_wrapup(); oscheck(); /* in case user typed ^C */ /* assume for now we should add the character */ lbuf[lcount] = ch; lpos[lcount] = lposition; lcount++; lposition++; /* now do all the special character processing */ switch (ch) { case '\001': /* take out non-printing character */ lcount--; lposition--; mark_audio_time(); break; case '\n': lposition = 0; end_of_line_edit(); if (echo_enabled) { osaputc('\r', stdout); osaputc(ch, stdout); } break; /* delete key generates: 1b, 5b, 33, 7E which is: ESC, [, 3, ~ */ case '\010': /* backspace */ case '\177': /* delete */ lcount--; /* take out backspace or delete char */ lposition--; if (lcount) { lcount--; while (lposition > lpos[lcount]) { if (echo_enabled) { putchar('\010'); putchar(' '); putchar('\010'); } lposition--; } } break; case '\025': /* control-u */ lcount--; lposition--; if (lcount) { while (lposition > lpos[0]) { if (echo_enabled) { putchar('\010'); putchar(' '); putchar('\010'); } lposition--; } lcount = 0; } break; /* note that control-z never reaches here */ case '\003': /* control-c */ xltoplevel(); lcount = 0; break; case '\007': /* control-g */ lcount--; /* take out non-printing char */ lposition--; xlcleanup(); lcount = 0; break; case '\016': lcount--; /* take out non-printing char */ lposition--; hidden_msg(); /* process hidden msg chars */ break; case '\020': /* control-p */ lcount--; /* take out non-printing char */ lposition--; xlcontinue(); lcount = 0; break; case '\002': lcount--; /* take out non-printing char */ lposition--; xflush(); /* control-b */ xlbreak("BREAK",s_unbound); break; case '\005': /* control-e */ lcount--; /* take out non-printing char */ lposition--; echo_enabled = TRUE; break; case '\006': /* control-f */ lcount--; /* take out non-printing char */ lposition--; echo_enabled = FALSE; break; case '\024': /* control-t */ lcount--; /* take out non-printing char */ lposition--; xinfo(); lcount = 0; break; case '\t': /* TAB */ lposition--; /* undo the increment above */ do { lposition++; if (echo_enabled) osaputc(' ', stdout); } while (lposition & 7); break; default: if (echo_enabled) osaputc(ch, stdout); break; } // avoid line buffer overflow here: if (lposition > LBSIZE - 10) { // buffer is about to overflow, so write newline and // feed chars to XLISP if (echo_enabled) { osaputc('\r', stdout); osaputc('\n', stdout); } lposition = 0; end_of_line_edit(); } } if (lindex + 1 >= lcount) { lcount = 0; line_edit = TRUE; } ch = lbuf[lindex++]; /* printf("-%c-", ch); */ if (echo_enabled) fflush(stdout); return ch; } #endif #endif #endif /* ostputc - put a character to the terminal */ void ostputc(int ch) { oscheck(); /* check for control characters */ /* output the character */ if (ch == '\n') {lposition = 0;} else {lposition++;} /* output the character to the transcript file */ if (tfp) osaputc(ch,tfp); putchar(((char) ch)); } /* ostoutflush - flush output buffer */ void ostoutflush() { if (tfp) fflush(tfp); fflush(stdout); } /* osflush - flush the terminal input buffer */ void osflush(void) { lindex = lcount = lposition = 0; line_edit = TRUE; } /* hidden_msg - process a "hidden message" /* * NOTE: a "hidden message" is a sequence of characters starting * with '\016' and ending with '\021'. These are designed to allow * a graphical interface, namely jNyqIDE, to control sliders in * real-time (during synthesis). The character sequences are hidden * meaning they are not echoed and they are not interpreted as LISP. * * This function assumes that '\016' has been received already. */ LOCAL void hidden_msg() { #define MSGBUF_MAX 64 char msgbuf[MSGBUF_MAX]; int msgbufx = 0; char type_char = rawtchar(); char ch; // message is terminated by '\021' while ((ch = term_getchar()) != '\021' && ch != EOF && msgbufx < MSGBUF_MAX - 1) { msgbuf[msgbufx++] = ch; } msgbuf[msgbufx++] = 0; // printf("hidden message: %s, len %ld\n", msgbuf, (long) strlen(msgbuf)); if (msgbufx < MSGBUF_MAX) { if (type_char == 'S') { // slider change message int index; float value; if (sscanf(msgbuf, "%d %g", &index, &value) == 2) { set_slider(index, value); } } } /* other hidden messages could be parsed here */ } /* oscheck - check for control characters during execution */ /* * NOTE: to support type-ahead, unused characters are put * into a queue to be removed by ostgetc */ void oscheck(void) { int ch; int k, v, n; static int count = 0; #if OSC if (nosc_enabled) nosc_poll(); #endif if (ctc) { /* control-c */ /* printf("[oscheck: control-c detected]"); */ ctc=FALSE; ctcreset(); xflush(); xltoplevel(); return; } if ((ch = xcheck())) { switch (ch) { case BREAK_CHAR: /* control-b */ /* printf("BREAK_CHAR\n"); */ xflush(); xlbreak("BREAK",s_unbound); break; case '\024': /* control-t */ /* printf("control-t\n"); */ xinfo(); break; case '\025': /* control-u */ /* printf("control-u\n"); */ xcleanup(); case '\016': { /* begin hidden message */ /* printf("hidden msg\n"); */ hidden_msg(); break; } case '\001': /* control-a -- mark audio time */ mark_audio_time(); break; case -1: /* EOF - lost connection, so die */ xlisp_wrapup(); break; case -2: /* no character was ready */ break; default: /* printf("Got %d\n", ch); */ #ifndef READ_LINE /* printf("+%c+", ch); */ typeahead[typeahead_tail++] = ch; typeahead_tail &= (typeahead_max - 1); if (typeahead_tail == typeahead_head) { oserror("Input buffer overflow\n"); } #endif break; } } count++; // when compute-bound, count is incremented by 10000 in about 15s, so // that's about 700 Hz. We want to flush any output at about 2Hz, so // we'll pick 400 as a round number. if (count % 400 == 0) { fflush(stdout); } } /* xflush - flush the input line buffer and start a new line */ LOCAL void xflush() { osflush(); ostputc('\n'); } /* xsystem - execute a system command */ LVAL xsystem() { /*LVAL strval;*/ unsigned char *cmd = NULL; if (moreargs()) cmd = (unsigned char *)getstring(xlgastring()); xllastarg(); return (system((char *) cmd) == -1 ? cvfixnum((FIXTYPE)errno) : s_true); } /* xsetdir -- set current directory of the process */ LVAL xsetdir() { char *dir = (char *)getstring(xlgastring()); int result; LVAL cwd = NULL; int verbose = TRUE; if (moreargs()) { verbose = (xlgetarg() != NIL); } xllastarg(); result = chdir(dir); if (result) { /* perror("SETDIR"); -- Nyquist uses SETDIR to search for directories * at startup, so failures are normal, and seeing error messages * could be confusing, so don't print them. The NULL return indicates * an error, but doesn't tell which one it is. * But now, SETDIR has a second verbose parameter that is nil when * searching for directories. -RBD */ if (verbose) perror("Directory Setting Error"); return NULL; } dir = getcwd(NULL, 1000); if (dir) { cwd = cvstring(dir); free(dir); } return cwd; } /* xget_temp_path -- get a path to create temp files */ LVAL xget_temp_path() { return cvstring("/tmp/"); } /* xget_user -- get a string identifying the user, for use in file names */ LVAL xget_user() { char *user = getenv("USER"); if (!user || !*user) { errputstr("Warning: could not get user ID, using 'nyquist'\n"); user = "nyquist"; } return cvstring(user); } /* xechoenabled -- set/clear echo_enabled flag (unix only) */ LVAL xechoenabled() { int flag = (xlgetarg() != NULL); xllastarg(); echo_enabled = flag; return NULL; } #define OSDIR_LIST_READY 0 #define OSDIR_LIST_STARTED 1 #define OSDIR_LIST_DONE 2 static int osdir_list_status = OSDIR_LIST_READY; static DIR *osdir_dir; /* osdir_list_start -- open a directory listing */ int osdir_list_start(char *path) { if (osdir_list_status != OSDIR_LIST_READY) { osdir_list_finish(); /* close current listing */ } osdir_dir = opendir(path); if (!osdir_dir) { return FALSE; } osdir_list_status = OSDIR_LIST_STARTED; return TRUE; } /* osdir_list_next -- read the next entry from a directory */ char *osdir_list_next() { if (osdir_list_status != OSDIR_LIST_STARTED) { return NULL; } struct dirent *entry = readdir(osdir_dir); if (!entry) { osdir_list_status = OSDIR_LIST_DONE; return NULL; } else { return entry->d_name; } } /* osdir_list_finish -- close an open directory */ void osdir_list_finish() { if (osdir_list_status != OSDIR_LIST_READY) { closedir(osdir_dir); } osdir_list_status = OSDIR_LIST_READY; } /* xcheck -- return a character if one is present */ LOCAL int xcheck() { int ch = term_testchar(); return ch; } /* xgetkey - get a key from the keyboard */ LVAL xgetkey() {xllastarg(); return (cvfixnum((FIXTYPE)term_getchar()));} /* ossymbols - enter os specific symbols */ void ossymbols(void) {} /* xsetupconsole -- used to configure window in Win32 version */ LVAL xsetupconsole() { return NIL; } nyquist-3.05/sys/unix/io.h0000644000175000000620000000021310144436365014546 0ustar stevestaff#define NOCHAR -2 int IOinputfd; int IOnochar; int IOsetup(int inputfd); int IOcleanup(void); int IOgetchar(void); int IOwaitchar(void); nyquist-3.05/sys/unix/termtest.c0000644000175000000620000000101110144436365015776 0ustar stevestaff/* this was written to test the term.c code, which was found on the web for use in XLisp to enable ^C and other character-by-character handling */ #include "term.h" #include void ctcinit() { signal(SIGINT, term_exit); } main() { int c; int count = 0; term_init(); term_character(); while ((c = term_testchar()) == -2) count++; printf("got %c after %d\n", c, count); while ((c = getchar()) != 'x') { printf("got '%c' = %x\n", c, c); } term_exit(); } nyquist-3.05/sys/unix/term.h0000644000175000000620000000022411466723256015116 0ustar stevestaffvoid term_init(); void term_exit(); void ctcinit(); /* not implemented in term.h */ int term_testchar(); int term_getchar(); void term_character(); nyquist-3.05/sys/unix/setup0000644000175000000620000000024510144436365015056 0ustar stevestaffmkdir cmt demos lib misc nyqsrc runtime sys test tran xlisp cd sys mkdir unix mac win cd unix mkdir cmu next pmax rs6k sgi sparc cd .. cd win mkdir msvc cd .. cd .. nyquist-3.05/sys/unix/io.c0000644000175000000620000000707610144436365014557 0ustar stevestaff/* ********************************************************************** * File io.c ********************************************************************** * * Non blocking input routine * Works by puttng the terminal in CBREAK mode and using the FIONREAD * ioctl call to determine the number of characters in the input queue */ #include "stdio.h" #include "io.h" #include #include #include #include #include "cext.h" int IOinputfd; /* input file descriptor (usually 0) */ int IOnochar; /* Value to be returned by IOgetchar() where there is no input to be had */ static struct sgttyb IOoldmodes, IOcurrentmodes; /* Initial and current tty modes */ /* * IOsetup(inputfd) * Args: * inputfd - input file descriptor (should be zero for standard input) * Returns: * 0 - if all goes well * -1 - if an ioctl fails (also calls perror) * Side Effects: * Puts the terminal in CBREAK mode - before process termination * IOcleanup() should be called to restore old terminal modes * Catch's interrupts (if they are not already being caught) and * calls IOcleanup before exiting * */ #define ERROR(s) return (perror(s), -1) IOsetup(inputfd) { static IOdiegracefully(); int (*interrupt_handler)(); IOinputfd = inputfd; IOnochar = NOCHAR; if(ioctl(IOinputfd, TIOCGETP, &IOoldmodes) < 0) ERROR("IOsetup"); IOcurrentmodes = IOoldmodes; IOcurrentmodes.sg_flags |= CBREAK; IOcurrentmodes.sg_flags &= ~ECHO; if(ioctl(IOinputfd, TIOCSETP, &IOcurrentmodes)) ERROR("IOsetup-2"); if( (interrupt_handler = signal(SIGINT, IOdiegracefully)) != 0) signal(SIGINT, interrupt_handler); return 0; } static IOdiegracefully() { write(2, "\nBye\n", 5); IOcleanup(); EXIT(2); } /* * IOcleanup() * Returns: * 0 - if all goes well * -1 - if an ioctl fails (also calls perror) * Side Effects: * Restores initial terminal modes */ IOcleanup() { if(ioctl(IOinputfd, TIOCSETP, &IOoldmodes) < 0) ERROR("IOclean"); return 0; } /* * IOgetchar() * Returns: * A character off the input queue if there is one, * IOnochar if there is no character waiting to be read, * -1 if an ioctl fails (shouldn't happen if IOsetup went OK) */ #ifndef UNIX_MACH IOgetchar() { int n; char c; if(ioctl(IOinputfd, FIONREAD, &n) < 0) ERROR("IOgetchar"); if(n <= 0) return IOnochar; switch(read(IOinputfd, &c, 1)) { case 1: return c; case 0: return EOF; default: ERROR("IOgetchar-read"); } } IOgetchar2() { int nfds, readfds = 1 << IOinputfd; char c; static struct timeval zero; if(IOinputfd < 0 || IOinputfd >= 32) { printf("IOgetchar2: bad IOinputfd (%d)%s\n", IOinputfd, IOinputfd == -1 ? "Did you call IOsetup(fd)?" : ""); } nfds = select(32, &readfds, 0, 0, &zero); if(nfds > 0) { switch(read(IOinputfd, &c, 1)) { case 0: return EOF; case 1: return c; default: printf("IOgetchar2: read failed!\n"); return NOCHAR; } } else if(nfds < 0) printf("IOgetchar2: select failed!\n"); return NOCHAR; } /* * IOwaitchar() * Returns: * A character off the input queue. Waits if necessary. */ int IOwaitchar() { char c; if (read(IOinputfd, &c, 1) == 1) return c; else return EOF; } #endif /* UNIX_MACH */ nyquist-3.05/sys/unix/sgi/0002755000175000000620000000000011537433131014551 5ustar stevestaffnyquist-3.05/sys/unix/sgi/Makefile0000644000175000000620000004756410144436365016234 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is SGI # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny # Standard list of includes (common to all unix versions) INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Isnd -Ifft # system dependent stuff for sgi: CC = cc CFLAGS = -DCMTSTUFF -g $(INCL) LN = cc LFLAGS = -lm # you would need -lmd if UNIX_IRIX_MIDIFNS were defined in midifns.c INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o xlisp/xlsym.o xlisp/xlsys.o \ tran/amosc.o tran/clip.o tran/const.o tran/fmosc.o \ tran/integrate.o tran/log.o tran/maxv.o tran/osc.o \ tran/prod.o tran/buzz.o tran/pwl.o tran/recip.o \ tran/upsample.o tran/scale.o tran/sine.o tran/partial.o \ tran/white.o tran/tone.o tran/tonev.o tran/atonev.o \ tran/atone.o tran/reson.o tran/areson.o tran/resonvc.o \ tran/resoncv.o tran/aresonvc.o tran/aresoncv.o tran/resonvv.o \ tran/aresonvv.o tran/offset.o tran/slope.o tran/delay.o \ tran/delaycv.o tran/shape.o tran/sampler.o tran/exp.o \ tran/siosc.o tran/follow.o tran/gate.o tran/quantize.o \ tran/ifft.o tran/congen.o tran/fromobject.o tran/fromarraystream.o \ tran/coterm.o tran/convolve.o tran/alpass.o tran/oneshot.o \ tran/chase.o tran/tapv.o tran/biquad.o tran/pluck.o \ cmt/cext.o cmt/cleanup.o cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nyqsrc/debug.o nyqsrc/falloc.o nyqsrc/add.o \ nyqsrc/local.o nyqsrc/downsample.o nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/multiseq.o nyqsrc/samples.o nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/sndread.o nyqsrc/sndseq.o nyqsrc/sndwrite.o nyqsrc/sndmax.o \ nyqsrc/sound.o nyqsrc/stats.o nyqsrc/compose.o nyqsrc/inverse.o \ nyqsrc/resamp.o nyqsrc/resampv.o nyqsrc/ffilterkit.o nyqsrc/avg.o \ nyqsrc/fft.o nyqsrc/sndfail.o fft/fftn.o nyqsrc/sndfnint.o \ nyqsrc/seqfnint.o snd/audiosgi.o snd/sndsgi.o snd/ieeecvt.o \ snd/snd.o snd/sndcvt.o snd/sndio.o snd/sndheader.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = snd/snd.h nyqsrc/sound.h nyqsrc/downsample.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/add.h nyqsrc/multiseq.h nyqsrc/samples.h \ nyqsrc/sndwrite.h nyqsrc/sndmax.h nyqsrc/compose.h nyqsrc/inverse.h \ nyqsrc/resamp.h nyqsrc/resampv.h nyqsrc/fft.h nyqsrc/avg.h \ tran/amosc.h tran/clip.h tran/const.h tran/fmosc.h \ tran/integrate.h tran/log.h tran/maxv.h tran/osc.h \ tran/prod.h tran/buzz.h tran/pwl.h tran/recip.h \ tran/upsample.h tran/scale.h tran/sine.h tran/partial.h \ tran/white.h tran/tone.h tran/tonev.h tran/atonev.h \ tran/atone.h tran/reson.h tran/areson.h tran/resonvc.h \ tran/resoncv.h tran/aresonvc.h tran/aresoncv.h tran/resonvv.h \ tran/aresonvv.h tran/offset.h tran/slope.h tran/delaycc.h \ tran/delaycv.h tran/shape.h tran/sampler.h tran/exp.h \ tran/siosc.h tran/follow.h tran/gate.h tran/quantize.h \ tran/ifft.h tran/congen.h tran/fromobject.h tran/fromarraystream.h \ tran/coterm.h tran/convolve.h tran/alpass.h tran/oneshot.h \ tran/chase.h tran/tapv.h tran/biquad.h tran/pluck.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h cmt/seqwrite.h cmt/seqmwrite.h EVERYTHING = $(NY) runtime/system.lsp CURRENT = $(EVERYTHING) current: $(CURRENT) $(NY): $(OBJECTS) $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/sgi/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/sgi/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h cc -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c cc -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndwrite.o: nyqsrc/sndwrite.c nyqsrc/sndwrite.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndwrite.c -o nyqsrc/sndwrite.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/sndfail.o: nyqsrc/sndfail.c cc -c nyqsrc/sndfail.c -o nyqsrc/sndfail.o $(CFLAGS) snd/audiosgi.o: snd/audiosgi.c snd/snd.h cc -c snd/audiosgi.c -o snd/audiosgi.o $(CFLAGS) snd/sndsgi.o: snd/sndsgi.c snd/sndsgi.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndsgi.c -o snd/sndsgi.o $(CFLAGS) snd/ieeecvt.o: snd/ieeecvt.c snd/ieeecvt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/ieeecvt.c -o snd/ieeecvt.o $(CFLAGS) snd/snd.o: snd/snd.c snd/snd.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/snd.c -o snd/snd.o $(CFLAGS) snd/sndcvt.o: snd/sndcvt.c snd/snd.h cc -c snd/sndcvt.c -o snd/sndcvt.o $(CFLAGS) snd/sndio.o: snd/sndio.c snd/snd.h cc -c snd/sndio.c -o snd/sndio.o $(CFLAGS) snd/sndheader.o: snd/sndheader.c snd/sndheader.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndheader.c -o snd/sndheader.o $(CFLAGS) fft/fftn.o: fft/fftn.c fft/fftn.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c fft/fftn.c -o fft/fftn.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/const.c -o tran/const.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/log.c -o tran/log.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/white.c -o tran/white.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/convolve.o: tran/convolve.c tran/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/convolve.c -o tran/convolve.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/biquad.o: tran/biquad.c tran/biquad.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/biquad.c -o tran/biquad.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pluck.c -o tran/pluck.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c cc -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c cc -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h cc -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c cc -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c cc -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c cc -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c cc -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c cc -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c cc -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c cc -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c cc -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c cc -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c cc -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c cc -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c cc -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xljump.o: xlisp/xljump.c cc -c xlisp/xljump.c -o xlisp/xljump.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c cc -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c cc -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c cc -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c cc -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c cc -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c cc -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c cc -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c cc -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c cc -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c cc -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) cmt/cext.o: cmt/cext.c cc -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c cc -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c cc -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c cc -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c cc -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c cc -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c cc -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c cc -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c cc -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c cc -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c cc -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c cc -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c cc -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c cc -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c cc -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c cc -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c cc -c cmt/userio.c -o cmt/userio.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c cc -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) snd/snd.h misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean rm -f $(OBJECTS) # Note that these files are machine-generated: rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat nyquist-3.05/sys/unix/sgi/system.lsp0000644000175000000620000000217711466723256016635 0ustar stevestaff; machine.lsp -- machine/system-dependent definitions ; SGI/IRIX (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-AIFF)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "/tmp/")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* "points.dat")) (defmacro play (expr) `(let () (s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*) (r))) (defun r () (play-file *default-sound-file*)) ; PLAY-FILE -- play a file (defun play-file (name) (system (strcat "sfplay " (soundfilename name)))) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (or (eq (char filename 0) #\/) (eq (char filename 0) #\.))) (setf *file-separator* #\/) (sound-off) ; sgi implementation does not support real-time audio output yet nyquist-3.05/sys/unix/cmu/0002755000175000000620000000000011537433131014553 5ustar stevestaffnyquist-3.05/sys/unix/cmu/update.lsp0000644000175000000620000000414110144436365016560 0ustar stevestaff;; update.lsp -- script to push changes into source directories (load "makefile.lsp") ; just to make sure we got the latest bindings ;; UPDATE-SOURCES -- makes a script to push changes into source directories ;; (defun update-sources () (let (outf) (load "transfiles.lsp") ; just to make sure we're current (setf outf (open "script" :direction :output)) (format outf "# # source this script file # Source Paths: nyqsrc, cmtsrc, xlsrc, trnsrc ") (format outf " # # XLISP SOURCES # ") (file-update outf xlfiles ".c" "xlsrc") (file-update outf xlfiles-h ".h" "xlsrc") (file-update outf xlfiles-lsp ".lsp" "xlsrc") (format outf " # # NYQUIST SOURCES # ") (file-update outf nyqfiles ".c" "nyqsrc") (file-update outf (exceptions-filter nyqfiles) ".h" "nyqsrc") (file-update outf nyqfiles-h ".h" "nyqsrc") (file-update outf nyqfiles-lsp ".lsp" "nyqsrc") (file-update outf makefiles "" "nyqsrc") (format outf " # # CMT SOURCES # ") (file-update outf cmtfiles ".c" "cmtsrc") (file-update outf (exceptions-filter cmtfiles) ".h" "cmtsrc") (file-update outf cmtfiles-h ".h" "cmtsrc") ; don't write back machine generated trnsrc files ; (file-update outf transfiles ".c" "trnsrc") ; (file-update outf transfiles ".h" "trnsrc") (close outf) (format t "DONE writing script, 'source script' to copy files from~%") (format t "this directory to the source directories~%") )) ;; EXCEPTIONS-FILTER - remove .h files from list ; the depends-exceptions tells whether a .h file exists for a .c file ;; (defun exceptions-filter (files) (let (result) (dolist (f files) (let ((ex (assoc f depends-exceptions :test #'equal))) (cond (ex (if (and (cdr ex) (string-search (strcat f ".h") (cadr ex))) (push f result))) (t (push f result))))) result)) ;; FILE-UPDATE -- write dependency for source files ;; (defun file-update (outf files ext dir) (dolist (f files) (let ((fname (strcat f ext))) (format outf "cp -p ~A ~A/~A~%" fname dir fname)))) nyquist-3.05/sys/unix/cmu/backup.script0000644000175000000620000000007710144436365017255 0ustar stevestaffcp -Rp ../current/* /afs/cs/project/music/proj/nyquist/current nyquist-3.05/sys/unix/cmu/tar.script0000644000175000000620000000042410144436365016572 0ustar stevestaffmkdir ../TMP mv ny ../TMP mv runtime/system.lsp ../TMP mv Makefile ../TMP mv test ../TMP set NYQDIR=`pwd` cd .. ln -fs $NYQDIR nyquist tar -cvhf - nyquist | compress > nyquist.tar.Z cd $NYQDIR mv ../TMP/test . mv ../TMP/Makefile . mv ../TMP/system.lsp runtime mv ../TMP/ny . nyquist-3.05/sys/unix/pmax/0002755000175000000620000000000011537433131014734 5ustar stevestaffnyquist-3.05/sys/unix/pmax/Makefile0000644000175000000620000004747610144436365016421 0ustar stevestaff# # Makefile for Nyquist, SYSTEM-TYPE is PMAX # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally "ny"): NY = ny # Standard list of includes (common to all unix versions) INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Isnd -Ifft # system dependent stuff for pmax: CC = cc CFLAGS = -DCMTSTUFF -g $(INCL) LN = cc LFLAGS = -lm INTGEN = misc/intgen # Object files for Nyquist: OBJECTS = xlisp/extern.o xlisp/xldmem.o xlisp/xlbfun.o xlisp/xlcont.o \ xlisp/xldbug.o xlisp/xleval.o xlisp/xlfio.o xlisp/xlftab.o \ xlisp/xlglob.o xlisp/xlimage.o xlisp/xlinit.o xlisp/xlio.o \ xlisp/xlisp.o xlisp/xljump.o xlisp/xllist.o xlisp/xlmath.o \ xlisp/xlobj.o xlisp/xlpp.o xlisp/xlprin.o xlisp/xlread.o \ xlisp/xlstr.o xlisp/xlsubr.o xlisp/xlsym.o xlisp/xlsys.o \ tran/amosc.o tran/clip.o tran/const.o tran/fmosc.o \ tran/integrate.o tran/log.o tran/maxv.o tran/osc.o \ tran/prod.o tran/buzz.o tran/pwl.o tran/recip.o \ tran/upsample.o tran/scale.o tran/sine.o tran/partial.o \ tran/white.o tran/tone.o tran/tonev.o tran/atonev.o \ tran/atone.o tran/reson.o tran/areson.o tran/resonvc.o \ tran/resoncv.o tran/aresonvc.o tran/aresoncv.o tran/resonvv.o \ tran/aresonvv.o tran/offset.o tran/slope.o tran/delay.o \ tran/delaycv.o tran/shape.o tran/sampler.o tran/exp.o \ tran/siosc.o tran/follow.o tran/gate.o tran/quantize.o \ tran/ifft.o tran/congen.o tran/fromobject.o tran/fromarraystream.o \ tran/coterm.o tran/convolve.o tran/alpass.o tran/oneshot.o \ tran/chase.o tran/tapv.o tran/biquad.o tran/pluck.o \ cmt/cext.o cmt/cleanup.o cmt/cmdline.o cmt/cmtcmd.o \ cmt/moxc.o cmt/mem.o cmt/midifile.o cmt/midifns.o \ cmt/record.o cmt/seq.o cmt/seqmread.o cmt/seqmwrite.o \ cmt/seqread.o cmt/seqwrite.o cmt/tempomap.o cmt/timebase.o \ cmt/userio.o nyqsrc/debug.o nyqsrc/falloc.o nyqsrc/add.o \ nyqsrc/local.o nyqsrc/downsample.o nyqsrc/handlers.o nyqsrc/multiread.o \ nyqsrc/multiseq.o nyqsrc/samples.o nyqsrc/seqext.o nyqsrc/seqinterf.o \ nyqsrc/sndread.o nyqsrc/sndseq.o nyqsrc/sndwrite.o nyqsrc/sndmax.o \ nyqsrc/sound.o nyqsrc/stats.o nyqsrc/compose.o nyqsrc/inverse.o \ nyqsrc/resamp.o nyqsrc/resampv.o nyqsrc/ffilterkit.o nyqsrc/avg.o \ nyqsrc/fft.o nyqsrc/sndfail.o fft/fftn.o nyqsrc/sndfnint.o \ nyqsrc/seqfnint.o snd/audiopmax.o snd/sndpmax.o snd/ieeecvt.o \ snd/snd.o snd/sndcvt.o snd/sndio.o snd/sndheader.o \ sys/unix/osstuff.o sys/unix/term.o # Sound functions to add to xlisp NYQHDRS = snd/snd.h nyqsrc/sound.h nyqsrc/downsample.h nyqsrc/sndread.h \ nyqsrc/sndseq.h nyqsrc/add.h nyqsrc/multiseq.h nyqsrc/samples.h \ nyqsrc/sndwrite.h nyqsrc/sndmax.h nyqsrc/compose.h nyqsrc/inverse.h \ nyqsrc/resamp.h nyqsrc/resampv.h nyqsrc/fft.h nyqsrc/avg.h \ tran/amosc.h tran/clip.h tran/const.h tran/fmosc.h \ tran/integrate.h tran/log.h tran/maxv.h tran/osc.h \ tran/prod.h tran/buzz.h tran/pwl.h tran/recip.h \ tran/upsample.h tran/scale.h tran/sine.h tran/partial.h \ tran/white.h tran/tone.h tran/tonev.h tran/atonev.h \ tran/atone.h tran/reson.h tran/areson.h tran/resonvc.h \ tran/resoncv.h tran/aresonvc.h tran/aresoncv.h tran/resonvv.h \ tran/aresonvv.h tran/offset.h tran/slope.h tran/delaycc.h \ tran/delaycv.h tran/shape.h tran/sampler.h tran/exp.h \ tran/siosc.h tran/follow.h tran/gate.h tran/quantize.h \ tran/ifft.h tran/congen.h tran/fromobject.h tran/fromarraystream.h \ tran/coterm.h tran/convolve.h tran/alpass.h tran/oneshot.h \ tran/chase.h tran/tapv.h tran/biquad.h tran/pluck.h CMTHDRS = cmt/seqdecls.h nyqsrc/seqext.h cmt/seq.h nyqsrc/seqinterf.h \ cmt/seqread.h cmt/seqmread.h cmt/seqwrite.h cmt/seqmwrite.h EVERYTHING = $(NY) runtime/system.lsp CURRENT = $(EVERYTHING) current: $(CURRENT) $(NY): $(OBJECTS) $(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/pmax/system.lsp chmod +w runtime/system.lsp cp -p sys/unix/pmax/system.lsp runtime/system.lsp chmod -w runtime/system.lsp nyqsrc/debug.o: nyqsrc/debug.c nyqsrc/debug.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/debug.c -o nyqsrc/debug.o $(CFLAGS) nyqsrc/falloc.o: nyqsrc/falloc.c nyqsrc/falloc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/falloc.c -o nyqsrc/falloc.o $(CFLAGS) nyqsrc/add.o: nyqsrc/add.c nyqsrc/add.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/add.c -o nyqsrc/add.o $(CFLAGS) nyqsrc/local.o: nyqsrc/local.c xlisp/xlisp.h nyqsrc/sound.h cc -c nyqsrc/local.c -o nyqsrc/local.o $(CFLAGS) nyqsrc/downsample.o: nyqsrc/downsample.c nyqsrc/downsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/downsample.c -o nyqsrc/downsample.o $(CFLAGS) nyqsrc/handlers.o: nyqsrc/handlers.c cc -c nyqsrc/handlers.c -o nyqsrc/handlers.o $(CFLAGS) nyqsrc/multiread.o: nyqsrc/multiread.c nyqsrc/multiread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiread.c -o nyqsrc/multiread.o $(CFLAGS) nyqsrc/multiseq.o: nyqsrc/multiseq.c nyqsrc/multiseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/multiseq.c -o nyqsrc/multiseq.o $(CFLAGS) nyqsrc/samples.o: nyqsrc/samples.c nyqsrc/samples.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/samples.c -o nyqsrc/samples.o $(CFLAGS) nyqsrc/seqext.o: nyqsrc/seqext.c nyqsrc/seqext.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqext.c -o nyqsrc/seqext.o $(CFLAGS) nyqsrc/seqinterf.o: nyqsrc/seqinterf.c nyqsrc/seqinterf.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/seqinterf.c -o nyqsrc/seqinterf.o $(CFLAGS) nyqsrc/sndread.o: nyqsrc/sndread.c nyqsrc/sndread.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndread.c -o nyqsrc/sndread.o $(CFLAGS) nyqsrc/sndseq.o: nyqsrc/sndseq.c nyqsrc/sndseq.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndseq.c -o nyqsrc/sndseq.o $(CFLAGS) nyqsrc/sndwrite.o: nyqsrc/sndwrite.c nyqsrc/sndwrite.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndwrite.c -o nyqsrc/sndwrite.o $(CFLAGS) nyqsrc/sndmax.o: nyqsrc/sndmax.c nyqsrc/sndmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sndmax.c -o nyqsrc/sndmax.o $(CFLAGS) nyqsrc/sound.o: nyqsrc/sound.c nyqsrc/sound.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/sound.c -o nyqsrc/sound.o $(CFLAGS) nyqsrc/stats.o: nyqsrc/stats.c nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/stats.c -o nyqsrc/stats.o $(CFLAGS) nyqsrc/compose.o: nyqsrc/compose.c nyqsrc/compose.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/compose.c -o nyqsrc/compose.o $(CFLAGS) nyqsrc/inverse.o: nyqsrc/inverse.c nyqsrc/inverse.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/inverse.c -o nyqsrc/inverse.o $(CFLAGS) nyqsrc/resamp.o: nyqsrc/resamp.c nyqsrc/resamp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resamp.c -o nyqsrc/resamp.o $(CFLAGS) nyqsrc/resampv.o: nyqsrc/resampv.c nyqsrc/resampv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/resampv.c -o nyqsrc/resampv.o $(CFLAGS) nyqsrc/ffilterkit.o: nyqsrc/ffilterkit.c nyqsrc/ffilterkit.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/ffilterkit.c -o nyqsrc/ffilterkit.o $(CFLAGS) nyqsrc/avg.o: nyqsrc/avg.c nyqsrc/avg.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/avg.c -o nyqsrc/avg.o $(CFLAGS) nyqsrc/fft.o: nyqsrc/fft.c nyqsrc/fft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c nyqsrc/fft.c -o nyqsrc/fft.o $(CFLAGS) nyqsrc/sndfail.o: nyqsrc/sndfail.c cc -c nyqsrc/sndfail.c -o nyqsrc/sndfail.o $(CFLAGS) snd/audiopmax.o: snd/audiopmax.c snd/snd.h cc -c snd/audiopmax.c -o snd/audiopmax.o $(CFLAGS) snd/sndpmax.o: snd/sndpmax.c snd/sndpmax.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndpmax.c -o snd/sndpmax.o $(CFLAGS) snd/ieeecvt.o: snd/ieeecvt.c snd/ieeecvt.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/ieeecvt.c -o snd/ieeecvt.o $(CFLAGS) snd/snd.o: snd/snd.c snd/snd.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/snd.c -o snd/snd.o $(CFLAGS) snd/sndcvt.o: snd/sndcvt.c snd/snd.h cc -c snd/sndcvt.c -o snd/sndcvt.o $(CFLAGS) snd/sndio.o: snd/sndio.c snd/snd.h cc -c snd/sndio.c -o snd/sndio.o $(CFLAGS) snd/sndheader.o: snd/sndheader.c snd/sndheader.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c snd/sndheader.c -o snd/sndheader.o $(CFLAGS) fft/fftn.o: fft/fftn.c fft/fftn.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c fft/fftn.c -o fft/fftn.o $(CFLAGS) tran/amosc.o: tran/amosc.c tran/amosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/amosc.c -o tran/amosc.o $(CFLAGS) tran/clip.o: tran/clip.c tran/clip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/clip.c -o tran/clip.o $(CFLAGS) tran/const.o: tran/const.c tran/const.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/const.c -o tran/const.o $(CFLAGS) tran/fmosc.o: tran/fmosc.c tran/fmosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fmosc.c -o tran/fmosc.o $(CFLAGS) tran/integrate.o: tran/integrate.c tran/integrate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/integrate.c -o tran/integrate.o $(CFLAGS) tran/log.o: tran/log.c tran/log.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/log.c -o tran/log.o $(CFLAGS) tran/maxv.o: tran/maxv.c tran/maxv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/maxv.c -o tran/maxv.o $(CFLAGS) tran/osc.o: tran/osc.c tran/osc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/osc.c -o tran/osc.o $(CFLAGS) tran/prod.o: tran/prod.c tran/prod.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/prod.c -o tran/prod.o $(CFLAGS) tran/buzz.o: tran/buzz.c tran/buzz.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/buzz.c -o tran/buzz.o $(CFLAGS) tran/pwl.o: tran/pwl.c tran/pwl.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pwl.c -o tran/pwl.o $(CFLAGS) tran/recip.o: tran/recip.c tran/recip.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/recip.c -o tran/recip.o $(CFLAGS) tran/upsample.o: tran/upsample.c tran/upsample.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/upsample.c -o tran/upsample.o $(CFLAGS) tran/scale.o: tran/scale.c tran/scale.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/scale.c -o tran/scale.o $(CFLAGS) tran/sine.o: tran/sine.c tran/sine.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sine.c -o tran/sine.o $(CFLAGS) tran/partial.o: tran/partial.c tran/partial.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/partial.c -o tran/partial.o $(CFLAGS) tran/white.o: tran/white.c tran/white.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/white.c -o tran/white.o $(CFLAGS) tran/tone.o: tran/tone.c tran/tone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tone.c -o tran/tone.o $(CFLAGS) tran/tonev.o: tran/tonev.c tran/tonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tonev.c -o tran/tonev.o $(CFLAGS) tran/atonev.o: tran/atonev.c tran/atonev.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atonev.c -o tran/atonev.o $(CFLAGS) tran/atone.o: tran/atone.c tran/atone.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/atone.c -o tran/atone.o $(CFLAGS) tran/reson.o: tran/reson.c tran/reson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/reson.c -o tran/reson.o $(CFLAGS) tran/areson.o: tran/areson.c tran/areson.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/areson.c -o tran/areson.o $(CFLAGS) tran/resonvc.o: tran/resonvc.c tran/resonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvc.c -o tran/resonvc.o $(CFLAGS) tran/resoncv.o: tran/resoncv.c tran/resoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resoncv.c -o tran/resoncv.o $(CFLAGS) tran/aresonvc.o: tran/aresonvc.c tran/aresonvc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvc.c -o tran/aresonvc.o $(CFLAGS) tran/aresoncv.o: tran/aresoncv.c tran/aresoncv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresoncv.c -o tran/aresoncv.o $(CFLAGS) tran/resonvv.o: tran/resonvv.c tran/resonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/resonvv.c -o tran/resonvv.o $(CFLAGS) tran/aresonvv.o: tran/aresonvv.c tran/aresonvv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/aresonvv.c -o tran/aresonvv.o $(CFLAGS) tran/offset.o: tran/offset.c tran/offset.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/offset.c -o tran/offset.o $(CFLAGS) tran/slope.o: tran/slope.c tran/slope.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/slope.c -o tran/slope.o $(CFLAGS) tran/delaycc.o: tran/delaycc.c tran/delaycc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycc.c -o tran/delaycc.o $(CFLAGS) tran/delaycv.o: tran/delaycv.c tran/delaycv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/delaycv.c -o tran/delaycv.o $(CFLAGS) tran/shape.o: tran/shape.c tran/shape.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/shape.c -o tran/shape.o $(CFLAGS) tran/sampler.o: tran/sampler.c tran/sampler.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/sampler.c -o tran/sampler.o $(CFLAGS) tran/exp.o: tran/exp.c tran/exp.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/exp.c -o tran/exp.o $(CFLAGS) tran/siosc.o: tran/siosc.c tran/siosc.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/siosc.c -o tran/siosc.o $(CFLAGS) tran/follow.o: tran/follow.c tran/follow.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/follow.c -o tran/follow.o $(CFLAGS) tran/gate.o: tran/gate.c tran/gate.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/gate.c -o tran/gate.o $(CFLAGS) tran/quantize.o: tran/quantize.c tran/quantize.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/quantize.c -o tran/quantize.o $(CFLAGS) tran/ifft.o: tran/ifft.c tran/ifft.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/ifft.c -o tran/ifft.o $(CFLAGS) tran/congen.o: tran/congen.c tran/congen.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/congen.c -o tran/congen.o $(CFLAGS) tran/fromobject.o: tran/fromobject.c tran/fromobject.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromobject.c -o tran/fromobject.o $(CFLAGS) tran/fromarraystream.o: tran/fromarraystream.c tran/fromarraystream.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/fromarraystream.c -o tran/fromarraystream.o $(CFLAGS) tran/coterm.o: tran/coterm.c tran/coterm.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/coterm.c -o tran/coterm.o $(CFLAGS) tran/convolve.o: tran/convolve.c tran/convolve.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/convolve.c -o tran/convolve.o $(CFLAGS) tran/alpass.o: tran/alpass.c tran/alpass.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/alpass.c -o tran/alpass.o $(CFLAGS) tran/oneshot.o: tran/oneshot.c tran/oneshot.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/oneshot.c -o tran/oneshot.o $(CFLAGS) tran/chase.o: tran/chase.c tran/chase.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/chase.c -o tran/chase.o $(CFLAGS) tran/tapv.o: tran/tapv.c tran/tapv.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/tapv.c -o tran/tapv.o $(CFLAGS) tran/biquad.o: tran/biquad.c tran/biquad.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/biquad.c -o tran/biquad.o $(CFLAGS) tran/pluck.o: tran/pluck.c tran/pluck.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h cc -c tran/pluck.c -o tran/pluck.o $(CFLAGS) nyqsrc/sndfnint.o: nyqsrc/sndfnint.c cc -c nyqsrc/sndfnint.c -o nyqsrc/sndfnint.o $(CFLAGS) nyqsrc/seqfnint.o: nyqsrc/seqfnint.c cc -c nyqsrc/seqfnint.c -o nyqsrc/seqfnint.o $(CFLAGS) xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h cc -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS) xlisp/extern.o: xlisp/extern.c cc -c xlisp/extern.c -o xlisp/extern.o $(CFLAGS) xlisp/xldmem.o: xlisp/xldmem.c cc -c xlisp/xldmem.c -o xlisp/xldmem.o $(CFLAGS) xlisp/xlbfun.o: xlisp/xlbfun.c cc -c xlisp/xlbfun.c -o xlisp/xlbfun.o $(CFLAGS) xlisp/xlcont.o: xlisp/xlcont.c cc -c xlisp/xlcont.c -o xlisp/xlcont.o $(CFLAGS) xlisp/xldbug.o: xlisp/xldbug.c cc -c xlisp/xldbug.c -o xlisp/xldbug.o $(CFLAGS) xlisp/xleval.o: xlisp/xleval.c cc -c xlisp/xleval.c -o xlisp/xleval.o $(CFLAGS) xlisp/xlfio.o: xlisp/xlfio.c cc -c xlisp/xlfio.c -o xlisp/xlfio.o $(CFLAGS) xlisp/xlglob.o: xlisp/xlglob.c cc -c xlisp/xlglob.c -o xlisp/xlglob.o $(CFLAGS) xlisp/xlimage.o: xlisp/xlimage.c cc -c xlisp/xlimage.c -o xlisp/xlimage.o $(CFLAGS) xlisp/xlinit.o: xlisp/xlinit.c cc -c xlisp/xlinit.c -o xlisp/xlinit.o $(CFLAGS) xlisp/xlio.o: xlisp/xlio.c cc -c xlisp/xlio.c -o xlisp/xlio.o $(CFLAGS) xlisp/xlisp.o: xlisp/xlisp.c cc -c xlisp/xlisp.c -o xlisp/xlisp.o $(CFLAGS) xlisp/xljump.o: xlisp/xljump.c cc -c xlisp/xljump.c -o xlisp/xljump.o $(CFLAGS) xlisp/xllist.o: xlisp/xllist.c cc -c xlisp/xllist.c -o xlisp/xllist.o $(CFLAGS) xlisp/xlmath.o: xlisp/xlmath.c cc -c xlisp/xlmath.c -o xlisp/xlmath.o $(CFLAGS) xlisp/xlobj.o: xlisp/xlobj.c cc -c xlisp/xlobj.c -o xlisp/xlobj.o $(CFLAGS) xlisp/xlpp.o: xlisp/xlpp.c cc -c xlisp/xlpp.c -o xlisp/xlpp.o $(CFLAGS) xlisp/xlprin.o: xlisp/xlprin.c cc -c xlisp/xlprin.c -o xlisp/xlprin.o $(CFLAGS) xlisp/xlread.o: xlisp/xlread.c cc -c xlisp/xlread.c -o xlisp/xlread.o $(CFLAGS) xlisp/xlstr.o: xlisp/xlstr.c cc -c xlisp/xlstr.c -o xlisp/xlstr.o $(CFLAGS) xlisp/xlsubr.o: xlisp/xlsubr.c cc -c xlisp/xlsubr.c -o xlisp/xlsubr.o $(CFLAGS) xlisp/xlsym.o: xlisp/xlsym.c cc -c xlisp/xlsym.c -o xlisp/xlsym.o $(CFLAGS) xlisp/xlsys.o: xlisp/xlsys.c cc -c xlisp/xlsys.c -o xlisp/xlsys.o $(CFLAGS) cmt/cext.o: cmt/cext.c cc -c cmt/cext.c -o cmt/cext.o $(CFLAGS) cmt/cleanup.o: cmt/cleanup.c cc -c cmt/cleanup.c -o cmt/cleanup.o $(CFLAGS) cmt/cmdline.o: cmt/cmdline.c cc -c cmt/cmdline.c -o cmt/cmdline.o $(CFLAGS) cmt/cmtcmd.o: cmt/cmtcmd.c cc -c cmt/cmtcmd.c -o cmt/cmtcmd.o $(CFLAGS) cmt/moxc.o: cmt/moxc.c cc -c cmt/moxc.c -o cmt/moxc.o $(CFLAGS) cmt/mem.o: cmt/mem.c cc -c cmt/mem.c -o cmt/mem.o $(CFLAGS) cmt/midifile.o: cmt/midifile.c cc -c cmt/midifile.c -o cmt/midifile.o $(CFLAGS) cmt/midifns.o: cmt/midifns.c cc -c cmt/midifns.c -o cmt/midifns.o $(CFLAGS) cmt/record.o: cmt/record.c cc -c cmt/record.c -o cmt/record.o $(CFLAGS) cmt/seq.o: cmt/seq.c cc -c cmt/seq.c -o cmt/seq.o $(CFLAGS) cmt/seqmread.o: cmt/seqmread.c cc -c cmt/seqmread.c -o cmt/seqmread.o $(CFLAGS) cmt/seqmwrite.o: cmt/seqmwrite.c cc -c cmt/seqmwrite.c -o cmt/seqmwrite.o $(CFLAGS) cmt/seqread.o: cmt/seqread.c cc -c cmt/seqread.c -o cmt/seqread.o $(CFLAGS) cmt/seqwrite.o: cmt/seqwrite.c cc -c cmt/seqwrite.c -o cmt/seqwrite.o $(CFLAGS) cmt/tempomap.o: cmt/tempomap.c cc -c cmt/tempomap.c -o cmt/tempomap.o $(CFLAGS) cmt/timebase.o: cmt/timebase.c cc -c cmt/timebase.c -o cmt/timebase.o $(CFLAGS) cmt/userio.o: cmt/userio.c cc -c cmt/userio.c -o cmt/userio.o $(CFLAGS) sys/unix/osstuff.o: sys/unix/osstuff.c cc -c sys/unix/osstuff.c -o sys/unix/osstuff.o $(CFLAGS) misc/intgen: misc/intgen.c cd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c cd misc; make unpacker misc/packer: misc/packer.c misc/convert.c cd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) snd/snd.h misc/intgen $(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen $(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: cd misc; make clean rm -f $(OBJECTS) # Note that these files are machine-generated: rm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h rm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean cd misc; make cleaner rm -f *.backup */*.backup rm -f *~ */*.*~ rm -f *.save */*.save rm -f *.CKP */*.CKP rm -f *.BAK */*.BAK rm -f *.old */*.old rm -f *.gold */*.gold rm -f playparms rm -f points.dat nyquist-3.05/sys/unix/pmax/system.lsp0000644000175000000620000000170311466723256017012 0ustar stevestaff; machine.lsp -- machine/system-dependent definitions ; rs6000 (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-none)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "/tmp/")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) ; local definition for play (defun p6k () (system (format nil "/usr/itc/projects/depot/tactus/bin/acpaplay ~A/~A < playparms" *default-sf-dir* *default-sound-file*))) (defmacro play (expr) `(prog (specs playparms) (setf specs (s-save ',expr 1000000000 *default-sound-file*)) (setf playparms (open "playparms" :direction :output)) (format playparms "~A~%16~%2~%~A~%" (car specs) (cadr specs)) (close playparms) (p6k))) nyquist-3.05/sys/mac/0002755000175000000620000000000011537433131013544 5ustar stevestaffnyquist-3.05/sys/mac/switches.h0000644000175000000620000000213210144436365015547 0ustar stevestaff/* switches.h for Macintosh */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm major reorganization of conditional compilation in Nyquist */ #define HAS_STDLIB_H 1 #undef HAS_SYS_TYPES_H #undef HAS_SYS_STAT_H #define HAS_STAT_H 1 #undef HAS_MALLOC_H #define HAS_GETTIMEOFDAY 1 #undef READ_LINE #define XL_BIG_ENDIAN 1 #undef XL_LITTLE_ENDIAN #define USE_RAND 1 #undef USE_RANDOM /* define this to be printf, or define your own fn of the form void nyquist_printf(char *format, ...); (for a GUI) */ void nyquist_printf(char *format, ...); #define NEED_ULONG 1 #define NEED_USHORT 1 #define NEED_BYTE 1 #define NEED_ROUND 1 #undef NEED_DEFINE_MALLOC /* explicitly choose a platform */ #undef UNIX #undef WINDOWS #undef MICROSOFT #undef DOS #define MACINTOSH 1 #define BUFFERED_SYNCHRONOUS_INPUT 1 #define SPACE_FOR_PLAY 10000 #define MAX_CHANNELS 16 /* this will enable code to read midi files, etc. */ #define CMTSTUFF 1 /* NYQUIST tells some CMT code that we're really in * XLISP and NYQUIST */ #define NYQUIST 1 #include "swlogic.h" nyquist-3.05/sys/mac/macstuff.c0000644000175000000620000001445111466723256015536 0ustar stevestaff/* macstuff.c - macintosh interface routines for xlisp */ /* Written by Brian Kendig. */ /* This file contains the stuff that the other xlisp files call directly. */ #include "cext.h" #include #include #include /* for Random */ #include /* for DisposePtr */ #include /* for ExitToShell */ #include "xlisp.h" #include #include "macint.h" #include "MacCommandWin.h" #define DELETE 0x08 /* externals */ extern FILE *tfp; /* transcript file pointer */ extern int cursorPos; extern char *macgets (void); /* local variables */ int lposition; static char *linebuf = NULL, *lineptr; static int numChars; /* system-dependent variable definitions */ static const char os_pathchar = ':'; static const char os_sepchar = ','; int isascii (char c) { return 1; } /* every char is an ascii char, isn't it? */ void osinit (char *banner) { int i; char version[] = "\nMacintosh interface by Brian Kendig, Erik A. Dahl, and Dominic Mazzoni.\n"; InitMac (); /* initialize the mac interface routines */ lposition = 0; /* initialize the line editor */ for (i = 0; banner[i] != '\0'; i++) macputc (banner[i]); for (i = 0; version[i] != '\0'; i++) macputc (version[i]); } FILE *osaopen (char *name, char *mode) { return fopen (name, mode); } FILE *osbopen (char *name, char *mode) { FILE *f; char nmode[4]; strcpy (nmode, mode); strcat (nmode, "b"); f = fopen(name, nmode); return f; } int osclose (FILE *fp) { return (fclose (fp)); } int osaputc (int ch, FILE *fp) { return (putc (ch, fp)); } int osbputc (int ch, FILE *fp) { return (putc (ch, fp)); } /* osagetc - get a character from an ascii file */ int osagetc(fp) FILE *fp; { return (getc(fp)); } int ostgetc (void) { int i; if (numChars <= 0) { /* get some more */ if (linebuf) DisposePtr (linebuf); linebuf = macgets (); i = 0; while (linebuf[i] != '\0') i++; numChars = i; if (tfp) for (i = 0; i < numChars; i++) osaputc (linebuf[i], tfp); lineptr = linebuf; } numChars--; if (*lineptr == '\r') { lineptr++; return '\n'; } else return (*lineptr++); } void ostputc (int ch) { macputc (ch); if (tfp) osaputc (ch, tfp); } void osflush (void) { lineptr = linebuf; numChars = 0; lposition = 0; } void oscheck (void) { DoEvent (); } void oserror (char *msg) { char line[100], *p; sprintf (line,"error: %s\n",msg); for (p = line; *p != '\0'; ++p) ostputc (*p); } void osfinish(void) { /* dispose of everything... */ if (linebuf) DisposePtr(linebuf); portaudio_exit(); MacWrapUp (); ExitToShell (); } #define GPRINTF_MESSAGE_LEN 500 /* nyquist_printf -- system independent version of printf */ /* * this function prints to console like printf, but using GUI * rather than stdio when appropriate. * */ void nyquist_printf(char *format, ...) { char temp[GPRINTF_MESSAGE_LEN]; va_list pvar; char *p = temp; va_start(pvar, format); vsnprintf(temp, GPRINTF_MESSAGE_LEN, format, pvar); va_end(pvar); while (*p) ostputc(*p++); } int renamebackup (char *filename) { return 0; } static FSSpec prefsFSSpec; static int need_preferences_file = false; static char xlisp_path[1024]; /* cache for the path */ static int valid_xlisp_path = false; /* xsetupconsole -- used to configure window in Win32 version */ LVAL xsetupconsole() { return NIL; } /* this should really be in a header for MacFileUtils.c */ void GetFullPath(FSSpec *theSpec, StringPtr theName); void get_xlisp_path(char *p, long p_max, int *prefs_found) { Str63 fileName = "\pXLisp Preferences"; SInt16 foundPrefVRefNum = 0; SInt32 foundPrefDirID = 0; OSErr err = noErr; *p = 0; /* initialize to empty string */ *prefs_found = false; /* if we find path in the cache, copy and return */ if (valid_xlisp_path) { *prefs_found = true; strcpy(p, xlisp_path + 10); /* remember, path has XLISPPATH= at head */ return; } /* if we've been here before, do not try opening again */ if (need_preferences_file) return; err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &foundPrefVRefNum, &foundPrefDirID); if (err == noErr) { err = FSMakeFSSpec(foundPrefVRefNum, foundPrefDirID, fileName, &prefsFSSpec); *prefs_found = (err == noErr); need_preferences_file = !*prefs_found; } if (*prefs_found) { FILE *pf; GetFullPath(&prefsFSSpec, (StringPtr) xlisp_path); P2CStr((StringPtr) xlisp_path); pf = fopen(xlisp_path, "r"); if (!pf) { return; /* problem opening the path */ } while (fgets(xlisp_path, 1023, pf)) { if (strncmp(xlisp_path, "XLISPPATH=", 10) == 0) { valid_xlisp_path = true; xlisp_path[strlen(xlisp_path) - 1] = 0; /* trim newline */ strcpy(p, xlisp_path + 10); break; } } fclose(pf); } } /* this is called when we load a file -- if need_preference_file, * we will build a preference file and insert the path of the file * we just opened, assuming it will tell us where to find init.lsp */ void setup_preferences(char *filename) { if (need_preferences_file) { unsigned char prefname[256]; FILE *pf; char *cp; int len = 0; GetFullPath(&prefsFSSpec, prefname); need_preferences_file = false; P2CStr(prefname); /* we expect file-not-found error, path is valid */ pf = fopen((char *) prefname, "w"); if (pf == NULL) return; cp = strrchr((char *) filename, ':'); if (cp == NULL) return; cp[1] = 0; /* now, filename is the path. If filename ends in runtime, this * is probably the standard nyquist runtime folder. We should put * the nyquist lib folder on the path too. */ len = cp + 1 - filename; if (len >= 9 && strcmp(filename + len - 9, ":runtime:") == 0) { filename[len - 8] = 0; fprintf(pf, "XLISPPATH=%sruntime:,%slib:\n", filename, filename); } else { fprintf(pf, "XLISPPATH=%s\n", filename); } fclose(pf); } } nyquist-3.05/sys/mac/macaboutbox.h0000644000175000000620000000012310144436365016220 0ustar stevestaff/* macaboutbox.h -- header for about box implementation */ void DoAboutBox(void); nyquist-3.05/sys/mac/README.txt0000644000175000000620000000361111510141774015241 0ustar stevestaffREADME.txt -- information on Nyquist for Mac OS X Installation ------------ The simplest way to install and run Nyquist is to get the pre-compiled NyquistIDE application, which includes executables, documentation, and libraries all in one package. You will probably run Nyquist using the NyquistIDE application, but you can also run nyquist from the command line. The executable is located in NyquistIDE.app/Contents/Resources/Java/ny To run from the command line, you will need to set the XLISPPATH environment variable using this command line (if you use the C shell, e.g. csh): setenv XLISPPATH `pwd`/runtime:`pwd`/lib If you use the bash shell, use: export XLISPPATH=`pwd`/runtime:`pwd`/lib Note that this sets XLISPPATH in the environment of the current command line shell. If you exit the shell or switch to another shell, the XLISPPATH variable will not be set. Your shell reads an initialization file when it starts. You can add the XLISPPATH initialization command to this file if you want the variable to be set automatically in every instance of your command line shell. On the topic of the XLISPPATH, note that this variable is set by NyquistIDE when running with that application, overriding any other value. You can extend the search path by creating the file xlisppath in the same directory as the nyquist executable ny. The xlisppath file should have colon-separated paths on a single line of text. You can also build Nyquist from sources, as described below. How To Build Nyquist on Mac OS X -------------------------------- You need to install Xcode, Apple's free software development system for OS X. The project file is in nyquist/macosxproject/nyquist.xcodeproj To build Nyquist or NyquistIDE: - Open nyquist.xcodeproj in Xcode - Set the active target to "Nyquist" or "NyquistIDE" - Click on "build active target" - ny or NyquistIDE will be produced in MacOSXProject/build/ nyquist-3.05/sys/mac/MacFileUtils.h0000644000175000000620000000013610144436365016241 0ustar stevestaff/* MacFileUtils.h -- more mac stuff */ void GetFullPath(FSSpec *theSpec, StringPtr theName); nyquist-3.05/sys/mac/MacGlobals.h0000644000175000000620000000146510144436365015732 0ustar stevestaff// Window pointers extern WindowPtr gCommandWin, gGraphicsWin; extern Boolean gCommandWinResized; // Menu Handles extern MenuHandle appleMenu, fileMenu, editMenu, controlMenu; // The command window text handle extern TEHandle hTERec; #define TEXTREC (*hTERec) #define TEXTCHAR(i) ((*(TEXTREC->hText))[i]) // more comand window text stuff extern CharsHandle pastedTextH; /* a handle to pasted text */ extern int pastedLength; /* how many chars there are in the paste buffer */ extern int outputBufferLength; extern Rect dragRect, sizeRect; extern int flashTime, cursorBeforeFlash; extern char recentChar; /* the last character typed */ // Allocate space for UPPs extern ControlActionUPP uppScrollProc; extern TEClickLoopUPP uppScrollClickLoop; extern Boolean gInBackground; nyquist-3.05/sys/mac/MacFileUtils.c0000644000175000000620000000631410144436365016240 0ustar stevestaff// Routines that deal with some mac file system stuff -EAD #include #include #include //#include "MiscellaneousUtilities.h" //========================================================================= // Function prototypes //========================================================================= void set_mac_file_type(char *filename); void GetFullPath(FSSpec *theSpec, StringPtr theName); void PathNameFromDirID(long dirID, short vRefNum, StringPtr fullPathName); //========================================================================= // Set the output soundfile type and creator //========================================================================= void set_mac_file_type(char *filename) { Str255 fName; FSSpec fSpec; FInfo fFInfo; fFInfo.fdType = 'AIFF'; fFInfo.fdCreator = 'Sd2a'; BlockMoveData(filename, &fName[1], 256); fName[0] = strlen(filename); FSMakeFSSpec(0, 0, fName, &fSpec); FSpSetFInfo(&fSpec, &fFInfo); } //================================================================================================================================== // void GetFullPath(FSSpec *theSpec, StringPtr theName) //================================================================================================================================== // Extracts the full pathname for the file pointed to by theSpec and returns it in theName. //================================================================================================================================== void GetFullPath(FSSpec *theSpec, StringPtr theName) { *theName = 0; if (theSpec->parID != 1) PathNameFromDirID(theSpec->parID, theSpec->vRefNum, theName); // was: pstrcat(theName, theSpec->name); strcat(P2CStr(theName), P2CStr(theSpec->name)); C2PStr((char *) theName); C2PStr((char *) theSpec->name); //pstrcat(theName, "\p:"); theName[*theName + 1] = 0; } //================================================================================================================================== // void PathNameFromDirID(long dirID, short vRefNum, StringPtr fullPathName) //================================================================================================================================== // Given a vRefNum and a directory ID, creates a full path specification. //================================================================================================================================== void PathNameFromDirID(long dirID, short vRefNum, StringPtr fullPathName) { Str255 directoryName; DirInfo block; OSErr err; fullPathName[0] = 0; block.ioDrDirID = block.ioDrParID = dirID; block.ioNamePtr = directoryName; do { block.ioVRefNum = vRefNum; block.ioFDirIndex = -1; block.ioDrDirID = block.ioDrParID; err = PBGetCatInfo((CInfoPBPtr)&block, false); //pstrcat(directoryName, (StringPtr)"\p:"); //pstrinsert(fullPathName, directoryName); strcat(P2CStr(directoryName), ":"); strcat((char *) directoryName, (char *) fullPathName); strcpy((char *)fullPathName, (char *) directoryName); } while (block.ioDrDirID != 2); C2PStr((char *) fullPathName); } nyquist-3.05/sys/mac/MacCommandWin.h0000644000175000000620000000077210144436365016403 0ustar stevestaff/* MacCommandWin.h -- headers for more mac stuff */ void SetSelection (short start, short end); void macputc(int ch); void macputs(char *s); void PrepareForInput(void); void InitalizeCmdWindow(void); void UpdateCmdWindow(void); void StopPasting(void); void DeleteRange(void); void scrflush(void); void SetScrollRect(void); void AdjustCursor(Point theLoc, RgnHandle theRgn); void DoKeyPress(EventRecord *theEvent); void ActivateCmdWindow(void); void DeactivateCmdWindow(void); void CleanupCmdWindow(void); nyquist-3.05/sys/mac/sndsystem.h0000644000175000000620000000002510144436365015746 0ustar stevestaff#include "sndmac.h" nyquist-3.05/sys/mac/macfun.c0000644000175000000620000001453410144436365015173 0ustar stevestaff/* macfun.c - macintosh user interface functions for xlisp */ /* Written by Brian Kendig. */ #include #include #include #include "xlisp.h" #include "macint.h" /* externals */ extern WindowPtr gCommandWin, gGraphicsWin; extern Boolean hasColorQD; extern unsigned long startupTicks; extern void ShowGrafWin (void); unsigned long ticks_per_second (void) { return 60; } unsigned long run_tick_count (void) { return ((unsigned long) TickCount ()) - startupTicks; } unsigned long real_tick_count (void) { return (unsigned long) TickCount (); } LVAL xrealtime (void) { return cvfixnum ((FIXTYPE)real_tick_count()); } /* get-internal-real-time */ LVAL xruntime (void) { return cvfixnum ((FIXTYPE)run_tick_count()); } /* get-internal-run-time */ LVAL xtime (void) { return cvfixnum ((FIXTYPE)real_tick_count()); } /* time */ /* get an integer parameter */ LOCAL int getNumber () { LVAL num = xlgafixnum (); return ((int) getfixnum (num)); } /* handle commands that require integer arguments */ LOCAL LVAL GrafCmd (char funct, int nArgs) { short x, y, z; if (nArgs > 0) x = getNumber (); if (nArgs > 1) y = getNumber (); if (nArgs > 2) z = getNumber (); xllastarg (); SetPort (gGraphicsWin); switch (funct) { case 'G': ShowGrafWin (); break; case 'g': HideGrafWin (); break; case 'x': EraseRect (&gGraphicsWin->portRect); break; case 's': ShowPen (); break; case 'h': HidePen (); break; case 'd': PenMode (x); break; case 'M': Move (x, y); break; case 'm': MoveTo (x, y); break; case 'L': Line (x, y); break; case 'l': LineTo (x, y); break; case 'S': PenSize (x, y); break; case 'p': PenNormal (); break; case 'c': if (hasColorQD) { RGBColor col; col.red = x; col.green = y; col.blue = z; RGBForeColor (&col); } break; } SetPort (gCommandWin); return NIL; } LVAL xshowgraphics (void) { return GrafCmd ('G', 0); } /* show graphics win */ LVAL xhidegraphics (void) { return GrafCmd ('g', 0); } /* hide graphics win */ LVAL xcleargraphics (void) { return GrafCmd ('x', 0); } /* clear graphics win */ LVAL xshowpen (void) { return GrafCmd ('s', 0); } /* show the pen */ LVAL xhidepen (void) { return GrafCmd ('h', 0); } /* hide the pen */ LVAL xpenmode (void) { return GrafCmd ('d', 1); } /* set the pen mode */ LVAL xmove (void) { return GrafCmd ('M', 2); } /* move pen in a specified direction */ LVAL xmoveto (void) { return GrafCmd ('m', 2); } /* move pen to a screen location */ LVAL xdraw (void) { return GrafCmd ('L', 2); } /* draw a line in a specified direction */ LVAL xdrawto (void) { return GrafCmd ('l', 2); } /* draw a line to a screen location */ LVAL xpensize (void) { return GrafCmd ('S', 2); } /* set the pen size */ LVAL xpennormal (void) { return GrafCmd ('p', 0); } /* set the pen to normal */ LVAL xcolor (void) { return GrafCmd ('c', 3); } /* set RGB color of pen */ LVAL xgetpen (void) { /* get the pen position */ LVAL val; Point p; xllastarg (); SetPort ((GrafPtr)gGraphicsWin); GetPen (&p); SetPort (gCommandWin); xlsave1 (val); val = consa (NIL); rplaca (val,cvfixnum ((FIXTYPE)p.h)); rplacd (val,cvfixnum ((FIXTYPE)p.v)); xlpop (); return val; } LVAL xpenpat (void) { /* set the pen pattern */ LVAL plist; Pattern pat; int i; plist = xlgalist (); xllastarg (); for (i = 0; i < 8 && consp (plist); ++i, plist = cdr (plist)) // if (fixp (car (plist))) pat[i] = getfixnum (car (plist)); SetPort ((GrafPtr)gGraphicsWin); PenPat (&pat); SetPort (gCommandWin); return NIL; } /* The functions below are not yet implemented. */ LVAL xtool (void) { /* call the toolbox */ int trap = getNumber (); LVAL val; /* asm { move.l args(A6),D0 beq L2 L1: move.l D0,A0 move.l 2(A0),A1 move.w 4(A1),-(A7) move.l 6(A0),D0 bne L1 L2: lea L3,A0 move.w trap(A6),(A0) L3: dc.w 0xA000 clr.l val(A6) } return val; */ return cvfixnum ((FIXTYPE) trap); } LVAL xtool16 (void) { /* call the toolbox with a 16 bit result */ int trap = getNumber (); int val; /* asm { clr.w -(A7) move.l args(A6), D0 beq L2 L1: move.l D0, A0 move.l 2(A0), A1 move.w 4(A1), -(A7) move.l 6(A0), D0 bne L1 L2: lea L3, A0 move.w trap(A6), (A0) L3: dc.w 0xA000 move.w (A7)+, val(A6) } return cvfixnum ((FIXTYPE) val); */ return cvfixnum ((FIXTYPE) trap); } LVAL xtool32 (void) { /* call the toolbox with a 32 bit result */ int trap = getNumber (); long val; /* asm { clr.l -(A7) move.l args(A6),D0 beq L2 L1: move.l D0,A0 move.l 2(A0),A1 move.w 4(A1),-(A7) move.l 6(A0),D0 bne L1 L2: lea L3,A0 move.w trap(A6),(A0) L3: dc.w 0xA000 move.l (A7)+,val(A6) } return cvfixnum ((FIXTYPE) val); */ return cvfixnum ((FIXTYPE) trap); } LVAL xnewhandle (void) { /* allocate a new handle */ LVAL num = xlgafixnum (); long size = getfixnum (num); xllastarg (); return cvfixnum ((FIXTYPE) NewHandle (size)); } LVAL xnewptr (void) { /* allocate memory */ LVAL num = xlgafixnum (); long size = getfixnum (num); xllastarg (); return cvfixnum ((FIXTYPE) NewPtr (size)); } LVAL xhiword (void) { /* return the high order 16 bits of an integer */ unsigned int val = (unsigned int) (getNumber () >> 16); xllastarg (); return cvfixnum ((FIXTYPE) val); } LVAL xloword (void) { /* return the low order 16 bits of an integer */ unsigned int val = (unsigned int) getNumber (); xllastarg (); return cvfixnum ((FIXTYPE) val); } LVAL xrdnohang (void) { /* get the next character in the look-ahead buffer */ int ch = 0; xllastarg (); /* if ((ch = scrnextc ()) == EOF) return NIL; */ return cvfixnum ((FIXTYPE) ch); } void ossymbols (void) { /* ossymbols - enter important symbols */ LVAL sym; /* setup globals for the window handles */ sym = xlenter ("*COMMAND-WINDOW*"); setvalue (sym, cvfixnum ((FIXTYPE) gCommandWin)); sym = xlenter ("*GRAPHICS-WINDOW*"); setvalue (sym, cvfixnum ((FIXTYPE) gGraphicsWin)); } void xoserror (char *msg) { /* do nothing */ } LVAL xsystem (V) { return NIL; } LVAL xgetkey (V) { return NIL; } nyquist-3.05/sys/mac/MacAE.c0000644000175000000620000000336710144436365014632 0ustar stevestaff/* Handle required apple events -EAD */ #include #include #include #include "macstuff.h" #include "MacCommandWin.h" #include "MacFileUtils.h" //#include "MiscellaneousUtilities.h" #define TEXTREC (*hTERec) // the command extern TEHandle hTERec; // window text record //========================================================================= // Handle quit apple event //========================================================================= pascal OSErr AEQuit (AppleEvent *theAppleEvent, AppleEvent *theReply, long Refcon) { osfinish(); } //========================================================================= // Handle Open Document apple event by trying to load it. //========================================================================= extern xlload (char *, int, int); extern xlabort(char *); pascal OSErr AEOpenFiles(AppleEvent *theAppleEvent, AppleEvent *theReply, long Refcon) { AEDescList docList; AEKeyword keywd; DescType returnedType; Size actualSize; long itemsInList; FSSpec theSpec; CInfoPBRec pb; Str255 name; short i; if (AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList) != noErr) return; if (AECountItems (&docList, &itemsInList) != noErr) return; SetSelection (TEXTREC->teLength, TEXTREC->teLength); for (i = 1; i <= itemsInList; i++) { AEGetNthPtr (&docList, i, typeFSS, &keywd, &returnedType, (Ptr) &theSpec, sizeof(theSpec), &actualSize); GetFullPath(&theSpec, name); P2CStr(name); // was: pstrterm(name); if (xlload ((char *)name + 1, 1, 0) == 0) xlabort ("load error"); } macputs ("> "); PrepareForInput (); } nyquist-3.05/sys/mac/MacHandleEv.h0000644000175000000620000000012010144436365016020 0ustar stevestaff/* MacHandelEv.h -- event handlers */ void DoMouseDown(EventRecord *theEvent); nyquist-3.05/sys/mac/xlextstart.c0000644000175000000620000000002410144436365016131 0ustar stevestaff/* nothing to do */ nyquist-3.05/sys/mac/macaboutbox.c0000644000175000000620000000601010144436365016214 0ustar stevestaff/* macaboutbox.c - Display the "about box" of the application. */ /* Written by Brian Kendig. */ /* The functions here are only used by macint.c. */ //#include #include #include #include #include #include #include #include #include #include "macint.h" #define NIL ((void *) 0) static DialogPtr aboutBox; extern Boolean hasColorQD; static enum { theOKButton = 1, theOKOutline = 2, theIcon = 3, theName = 4, theAboutText = 5, theCopyright = 6 } ; pascal void DrawOKOutline (WindowPtr dialogWindow, short theItem) { PenState oldPen; short iType; Handle iHandle; Rect iRect; GetPenState (&oldPen); PenNormal (); PenSize (3,3); GetDialogItem (aboutBox, theOKButton, &iType, &iHandle, &iRect); InsetRect (&iRect, -4, -4); FrameRoundRect (&iRect, 16, 16); SetPenState (&oldPen); } pascal void DrawIcon (WindowPtr dialogWindow, short theItem) { short iType; Handle iHandle; Rect iRect; GetDialogItem (aboutBox, theIcon, &iType, &iHandle, &iRect); PlotIcon (&iRect, GetResource ('ICN#', 128)); } pascal void DrawName (WindowPtr dialogWindow, short theItem) { short iType; Handle iHandle; Rect iRect; Str255 string; TextFont (kFontIDHelvetica); TextSize (24); TextFace (0); GetDialogItem (aboutBox, theName, &iType, &iHandle, &iRect); GetIndString (string, STRINGS_RES, 1); TETextBox (string+1, string[0], &iRect, teFlushLeft); } pascal void DrawAboutText (WindowPtr dialogWindow, short theItem) { short iType; Handle iHandle; Rect iRect; Str255 string; TextFont (kFontIDMonaco); TextSize (9); TextFace (0); GetDialogItem (aboutBox, theAboutText, &iType, &iHandle, &iRect); GetIndString (string, STRINGS_RES, 2); TETextBox (string+1, string[0], &iRect, teFlushLeft); } pascal void DrawCopyright (WindowPtr dialogWindow, short theItem) { short iType; Handle iHandle; Rect iRect; Str255 string; TextFont (systemFont); TextSize (12); TextFace (0); GetDialogItem (aboutBox, theCopyright, &iType, &iHandle, &iRect); GetIndString (string, STRINGS_RES, 3); TETextBox (string+1, string[0], &iRect, teFlushLeft); } void DoAboutBox (void) { short itemType, itemHit = 0; Handle itemHandle; Rect aboutRect; short width, hight; PicHandle aboutPict; aboutPict = GetPicture(ABOUT_PICT); aboutRect = (*aboutPict)->picFrame; width = aboutRect.right - aboutRect.left; hight = aboutRect.bottom - aboutRect.top; aboutBox = GetNewDialog (ABOUT_BOX, NIL, (WindowPtr) -1); SizeWindow(aboutBox, width, hight, false); ShowWindow (aboutBox); SetPort(aboutBox); DrawPicture(aboutPict, &(*aboutPict)->picFrame); //itemHit = 0; //while (itemHit != ok) ModalDialog (NIL, &itemHit); while (!Button()); DisposeDialog (aboutBox); FlushEvents(everyEvent, 0); // dmazzoni } nyquist-3.05/sys/mac/macdrag.c0000644000175000000620000001054510144436365015316 0ustar stevestaff#include #include #include #include extern TEHandle hTERec; // Handle drag from newswatcher -EAD /*---------------------------------------------------------------------------- DragText Drag selected text. Entry: ev = pointer to mouse down event record. where = location of mouse down event in local coords. theTE = handle to TextEdit record. Exit: function result = error code. *dragged = true if text was dragged. false if mouse down was not over text selection, or user did not move the mouse before releasing the mouse button. *trashed = true if text was dragged to trash. ----------------------------------------------------------------------------*/ extern RgnHandle rgn; //extern EventRecord theEvent; Boolean DragText (EventRecord *ev) { DragReference dragRef; OSErr err = noErr; Boolean haveDragRef = false; Handle hText; RgnHandle dragRgn, tempRgn; short selStart, selEnd; char state; Point theLoc; GrafPtr curPort; // if (!PtInTEHiliteRgn(where, hTERec)) return noErr; if (!WaitMouseMoved(ev->where)) return noErr; GetPort(&curPort); CopyRgn(rgn, dragRgn = NewRgn()); SetPt(&theLoc, 0, 0); LocalToGlobal(&theLoc); OffsetRgn(dragRgn, theLoc.h, theLoc.v); hText = (**hTERec).hText; selStart = (**hTERec).selStart; selEnd = (**hTERec).selEnd; err = NewDrag(&dragRef); if (err != noErr) goto exit; haveDragRef = true; state = HGetState(hText); HLock(hText); err = AddDragItemFlavor(dragRef, 1, 'TEXT', *hText + selStart, selEnd - selStart, 0); HSetState(hText, state); if (err != noErr) goto exit; // dragRgn = NewRgn(); // err = TEGetHiliteRgn(dragRgn, hTERec); // if (err != noErr) goto exit; // LocalToGlobalRgn(dragRgn); // OutlineRegion(dragRgn); SetDragItemBounds(dragRef, 1, &(**dragRgn).rgnBBox); tempRgn = NewRgn(); CopyRgn(dragRgn, tempRgn); InsetRgn(tempRgn, 1, 1); DiffRgn(dragRgn, tempRgn, dragRgn); DisposeRgn(tempRgn); err = TrackDrag(dragRef, ev, dragRgn); if (err != noErr && err != userCanceledErr) goto exit; //*trashed = DragTargetWasTrash(dragRef); // DisposeRgn(dragRgn); DisposeDrag(dragRef); return true; exit: if (haveDragRef) DisposeDrag(dragRef); // if (dragRgn != nil) DisposeRgn(dragRgn); return false; } /*---------------------------------------------------------------------------- LocalToGlobalRgn Convert a region from local to global coordinates. Entry: rgn = handle to region. ----------------------------------------------------------------------------*/ void LocalToGlobalRgn (RgnHandle rgn) { Point where; SetPt(&where, 0, 0); LocalToGlobal(&where); OffsetRgn(rgn, where.h, where.v); } /*---------------------------------------------------------------------------- OutlineRegion Change a region into a tracing of its border which is appropriate for normal dragging. Entry: theRgn = handle to region. Exit: Region changed to outline of region. From Apple "HFS Drag Sample" sample code. ----------------------------------------------------------------------------*/ void OutlineRegion (RgnHandle theRgn) { RgnHandle tempRgn; tempRgn = NewRgn(); CopyRgn(theRgn, tempRgn); InsetRgn(tempRgn, 1, 1); DiffRgn(theRgn, tempRgn, theRgn); DisposeRgn(tempRgn); } /*---------------------------------------------------------------------------- PtInTEHiliteRgn Determine whether or not a point is in the current TextEdit hilite region. Entry: where = point in local coords. theTE = handle to TextEdit record. Exit: function result = true if point is in the hilite region. ----------------------------------------------------------------------------*/ Boolean PtInTEHiliteRgn (Point where, TEHandle theTE) { Boolean result = false; RgnHandle rgn = nil; OSErr err = noErr; //if (!HaveTEGetHiliteRgn()) return false; rgn = NewRgn(); err = TEGetHiliteRgn(rgn, theTE); if (err != noErr) goto exit; result = PtInRgn(where, rgn); exit: if (rgn != nil) DisposeRgn(rgn); return result; } nyquist-3.05/sys/mac/MacDrag.h0000644000175000000620000000010110144436365015206 0ustar stevestaff/* MacDrag.h -- drag text */ Boolean DragText(EventRecord *ev); nyquist-3.05/sys/mac/macint.h0000644000175000000620000000404210144436365015173 0ustar stevestaff#define INT_MAX +32767 #define INT_MIN -32767 /* resource id's */ #define CWINRES 400 #define GWINRES 401 #define MBAR_RES 400 #define APPLE_MENU_RES 400 #define FILE_MENU_RES 401 #define EDIT_MENU_RES 402 #define CONTROL_MENU_RES 403 #define STRINGS_RES 400 /* Apple menu */ #define ABOUT_ITEM 1 #define ABOUT_BOX 400 #define ABOUT_PICT 400 /* File menu */ #define LOAD 1 #define LOAD_NOISILY 2 #define QUIT 4 /* Edit menu */ #define UNDO 1 #define CUT 3 #define COPY 4 #define PASTE 5 #define CLEAR 6 /* Control menu */ #define BREAK 1 #define CONTINUE 2 #define CLEAN_UP 3 #define CANCEL_INPUT 4 #define TOP_LEVEL 5 #define SHOW_GRAPHICS 7 #define SPLIT_SCREEN 8 /* window sizing/dragging stuff */ #define DRAG_THRESHOLD 8 #define MIN_WIN_HEIGHT 80 #define MIN_WIN_WIDTH 120 #define MAX_BUF 250 /* max chars in output buffer */ #define SCROLLBACK_THRESHHOLD 30000 /* max chars kept in window */ #define DELETE_BLOCK 10000 /* how many chars to delete when threshhold reached */ #define LINEHEIGHT 11 /* height in pixels of 9-point Geneva, the font used */ #define STACKMIN 400000 /* amout of memory for application stack */ #define MASTERS 3 /* arbitrary -- how many times to call MoreMasters() */ /* key codes */ #define RETURN 0x0d #define ENTER 0x03 #define DELETE 0x08 #define FWDDEL 0x7F #define CLRKEY 0x1b #define PAGEUP 0x0b #define PAGEDN 0x0c #define HOMEKEY 0x01 #define ENDKEY 0x04 #define HELPKEY 0x05 #define FNKEY 0x10 #define LEFTARROW 0x1c #define RIGHTARROW 0x1d #define UPARROW 0x1e #define DOWNARROW 0x1f #define DBLQUOTE '\"' /* useful definitions */ #define MBAR_HEIGHT 20 #define TITLEBAR_HEIGHT 20 #define SCROLLER_WIDTH 15 #define SCREEN_MARGIN 2 #define TEXT_MARGIN 4 #define GRAFWIN_HEIGHT 232 void AdjustMenus(void); void DoMenu(long choice); void HideGrafWin(void); void DoContent(EventRecord *theEvent); void InitMac(void); void MacWrapUp(void); void DoEvent (void); nyquist-3.05/sys/mac/macstuff.h0000644000175000000620000000037210144436365015532 0ustar stevestaff/* macstuff.h -- header for mac-specific functions */ void osfinish(void); /* put searchpath into p, prefs_found tells if preference file exists */ void get_xlisp_path(char *p, long p_max, int *prefs_found); void setup_preferences(char *filename); nyquist-3.05/sys/mac/macint.c0000644000175000000620000004170610144436365015176 0ustar stevestaff/* macint.c - macintosh interface routines for xlisp 2.1e */ /* Written by Brian Kendig. */ /* The functions here are only called by macstuff.c. */ #include #include #include #include #include #include #include #include #include #include #include #include /* #include */ #include #include #include "macint.h" /* #define FALSE 0 #define TRUE 1 */ #define NIL ((void *) 0) #include "MacCommandWin.h" #include "macaboutbox.h" #include "MacDrag.h" #include "MacHandleEv.h" #include "macstuff.h" #include "stdio.h" #define TEXTREC (*hTERec) /* the command window text record */ #define TEXTCHAR(i) ((*(TEXTREC->hText))[i]) // Struct for apple event handling typedef struct AEventList { AEEventClass evclass; AEEventID evid; void *handler; long refcon; } AEventList, *AEventListPtr; //=========================================================================== // GLOBALS DEFINED HERE USE MacGlobals.h FOR ACCESS //=========================================================================== // Menu handles MenuHandle appleMenu, fileMenu, editMenu, controlMenu; /* command and graphics windows */ WindowPtr gCommandWin, gGraphicsWin; WindowRecord commandWinRec, bwGraphicsWinRec; CWindowRecord colorGraphicsWinRec; Boolean gGraphicsShown, gCommandWinResized = false; // Screen size stuff Rect dragRect, sizeRect; int screenWidth, screenHeight; /* screen dimensions */ int sHorizontal, sVertical, sWidth, sHeight; /* command win, split screen */ int gHorizontal, gVertical, gWidth, gHeight; /* graphics win, split screen */ // The Text handle TEHandle hTERec; /* output is buffered */ //Handle hOutputBuffer = NULL; int outputBufferLength = 0; // Allocate space for UPPs ControlActionUPP uppScrollProc; TEClickLoopUPP uppScrollClickLoop; //AEEventHandlerUPP uppAEOpenFiles, uppAEQuit; // Text related globals CharsHandle pastedTextH = NULL; /* a handle to pasted text */ int pastedLength = 0; /* how many chars there are in the paste buffer */ int flashTime = 0, cursorBeforeFlash; /* for flashing cursor when parens match */ char recentChar; /* the last character typed */ RgnHandle gMouseRgn; // holds current mouse regin /* miscellaneous stuff */ Boolean gInBackground; /* are we in background or not */ int wneImplemented; unsigned long startupTicks; Boolean hasColorQD; short howManyFiles = 0, whichFile = 0; /* keep track of files opened from Finder */ // Prototypes static pascal OSErr AEQuit (AppleEvent *theAppleEvent, AppleEvent *theReply, long Refcon); static pascal OSErr AEOpenFiles (AppleEvent *theAppleEvent, AppleEvent *theReply, long Refcon); pascal Boolean ScrollClickLoop (void); pascal void ScrollProc (ControlHandle control, short thePart); Rect SetTERect (void); void FlushOutput (void); void ShowGrafWin (void) { /* make the graphics window visible */ ShowWindow (gGraphicsWin); SelectWindow (gGraphicsWin); SetMenuItemText (controlMenu, SHOW_GRAPHICS, "\pHide Graphics"); //AdjustCursor (); gGraphicsShown = true; } void HideGrafWin (void) { /* hide the graphics window */ HideWindow (gGraphicsWin); SetMenuItemText (controlMenu, SHOW_GRAPHICS, "\pShow Graphics"); gGraphicsShown = false; } static void UpdateGraphWindow () { BeginUpdate (gGraphicsWin); EndUpdate (gGraphicsWin); } void InitMac (void) { // { /* set up memory properly */ // int i; // fix this later. -EAD //if (DefltStack < STACKMIN) SetApplLimit (CurStackBase - STACKMIN); // MaxApplZone (); // for (i = 0; i < MASTERS; i++) MoreMasters (); // } AEventListPtr theAppleEvent; AEventList theEventList[] = { { kCoreEventClass, kAEOpenDocuments, AEOpenFiles, 0 }, { kCoreEventClass, kAEQuitApplication, AEQuit, 0 }, { 0, 0, nil, 0 } }; int i; /* do all the necessary initialization mumbo-jumbo */ if (StackSpace() < STACKMIN) SetApplLimit(GetApplLimit() - STACKMIN); MaxApplZone(); /* printf("New StackSpace %lx GetApplLimit %lx\n", StackSpace(), GetApplLimit()); */ for (i = 0; i < MASTERS; i++) MoreMasters (); /* getchar(); */ /* initialize the toolbox */ InitGraf (&qd.thePort); InitFonts (); FlushEvents (everyEvent, 0); InitWindows (); InitMenus (); TEInit (); InitDialogs (NIL); InitCursor (); // Setup Callbacks uppScrollClickLoop = NewTEClickLoopProc(ScrollClickLoop); uppScrollProc = NewControlActionProc(ScrollProc); // Handlers for core apple events for (theAppleEvent = theEventList; theAppleEvent->handler; theAppleEvent++) if (AEInstallEventHandler(theAppleEvent->evclass, theAppleEvent->evid, NewAEEventHandlerProc((ProcPtr)theAppleEvent->handler), theAppleEvent->refcon, 0) != noErr); // Set up the SIOUX window SIOUXSettings.initializeTB = FALSE; //Toolbox is alread inited SIOUXSettings.setupmenus = FALSE; //keep the csound menus SIOUXSettings.autocloseonquit = TRUE; //close sioux without asking for save SIOUXSettings.showstatusline = FALSE; //no status line SIOUXSettings.asktosaveonclose = FALSE; //don't ask to save SIOUXSettings.toppixel = 40; SIOUXSettings.leftpixel = 5; /* see if we have WaitNextEvent and Color Quickdraw */ wneImplemented = (NGetTrapAddress (_WaitNextEvent, ToolTrap) != NGetTrapAddress (_Unimplemented, ToolTrap)); if (NGetTrapAddress ((short) Gestalt, ToolTrap) != NGetTrapAddress (_Unimplemented, ToolTrap)) { long returnCode; OSErr err = Gestalt (gestaltQuickdrawVersion, &returnCode); hasColorQD = ((err == noErr) && (returnCode >= gestalt8BitQD)); } else hasColorQD = false; { /* set up menus */ Handle theMenuBar = GetNewMBar (MBAR_RES); SetMenuBar (theMenuBar); appleMenu = (MenuHandle)GetMenuHandle (APPLE_MENU_RES); fileMenu = (MenuHandle)GetMenuHandle (FILE_MENU_RES); editMenu = (MenuHandle)GetMenuHandle (EDIT_MENU_RES); controlMenu = (MenuHandle)GetMenuHandle (CONTROL_MENU_RES); AppendResMenu (appleMenu, 'DRVR'); DrawMenuBar (); } /* get the size of the main screen */ screenWidth = qd.screenBits.bounds.right - qd.screenBits.bounds.left; screenHeight = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top; /* compute the size of the graphics window in split-screen mode */ gHorizontal = SCREEN_MARGIN; gVertical = MBAR_HEIGHT + TITLEBAR_HEIGHT - 1; gWidth = screenWidth - (SCREEN_MARGIN * 2); gHeight = GRAFWIN_HEIGHT; /* compute the size of the command window in split-screen mode */ sHorizontal = SCREEN_MARGIN; sVertical = MBAR_HEIGHT + TITLEBAR_HEIGHT - 1 + SCREEN_MARGIN + GRAFWIN_HEIGHT; sWidth = screenWidth - (SCREEN_MARGIN * 2); sHeight = screenHeight - MBAR_HEIGHT - TITLEBAR_HEIGHT - (SCREEN_MARGIN * 2) - GRAFWIN_HEIGHT - 1; /* set up size and drag rects */ dragRect = (*GetGrayRgn ())->rgnBBox; // dragRect.left += DRAG_THRESHOLD; // dragRect.right -= DRAG_THRESHOLD; // dragRect.bottom -= DRAG_THRESHOLD; sizeRect.top = MIN_WIN_HEIGHT; sizeRect.left = MIN_WIN_WIDTH; sizeRect.bottom = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top; sizeRect.right = qd.screenBits.bounds.right - qd.screenBits.bounds.left; /* create the command window */ gCommandWin = GetNewWindow (CWINRES, &commandWinRec, (WindowPtr) -1L); SetPort (gCommandWin); /* create the graphics window */ if (hasColorQD) gGraphicsWin = GetNewCWindow (GWINRES, &colorGraphicsWinRec, (WindowPtr) -1L); else gGraphicsWin = GetNewWindow (GWINRES, &bwGraphicsWinRec, (WindowPtr) -1L); startupTicks = TickCount (); /* take note of what time we're starting up */ // Create mouse regin gMouseRgn = NewRgn(); // Initalize some command window stuff InitalizeCmdWindow(); // Turn on text outlineing TEFeatureFlag(teFOutlineHilite, teBitSet, hTERec); HideGrafWin (); { /* see if the user launched the app by opening text files from the Finder */ short doWhat;\ // call to CountAppFiles was commented out, but that left doWhat uninitialized // RBD added this ifdef, I wonder where CountAppFiles came from? #ifdef CountAppFilesDefined CountAppFiles (&doWhat, &howManyFiles); if (doWhat != appOpen) howManyFiles = 0; #else howManyFiles = 0; #endif } UpdateCmdWindow (); } static void DoAppleMenu (int theItem) { switch (theItem) { case ABOUT_ITEM: DoAboutBox (); break; default: { Str255 name; GetMenuItemText (appleMenu, theItem, name); OpenDeskAcc (name); break; } } } /* this should really be in a header for MacFileUtils.c */ void GetFullPath(FSSpec *theSpec, StringPtr theName); static void DoFileMenu (int theItem) { extern xlload (char *, int, int); extern xlabort(char *); extern xlisp_wrapup (void); StandardFileReply theFile; SFTypeList fileTypes; Point pt = { 100, 100 }; fileTypes[0] = 'TEXT'; switch (theItem) { case LOAD: case LOAD_NOISILY: StopPasting (); StandardGetFile(NIL, 1, fileTypes, &theFile); if (theFile.sfGood) { Str255 theFullPath; short wdRefNum; OSErr err; HiliteMenu (0); err = OpenWD(theFile.sfFile.vRefNum, theFile.sfFile.parID, 'Nyqu', &wdRefNum); err = SetVol(NIL, wdRefNum); SetSelection (TEXTREC->teLength, TEXTREC->teLength); /* send cursor to end */ GetFullPath(&theFile.sfFile, theFullPath); P2CStr(theFullPath); if ((xlload((char *) theFullPath, 1, (theItem == LOAD_NOISILY))) == 0) { xlabort("load error"); } macputs ("> "); PrepareForInput (); } break; case QUIT: xlisp_wrapup (); } } static void DoEditMenu (int theItem) { if (SystemEdit (theItem-1) == false) switch (theItem) { case CUT: case COPY: if (ZeroScrap () == noErr) { TECopy (hTERec); /* after copying, export the TE scrap */ if (TEToScrap () != noErr) ZeroScrap (); } if (theItem == CUT) DeleteRange (); break; case PASTE: { long scrapOffset; if (pastedTextH) DisposeHandle (pastedTextH); pastedTextH = (CharsHandle) NewHandle (0); pastedLength = GetScrap (pastedTextH, 'TEXT', &scrapOffset); if (pastedLength < 0) pastedLength = 0; /* error */ else { SetHandleSize (pastedTextH, pastedLength + 1); HLock (pastedTextH); ((char *)(*pastedTextH))[pastedLength] = '\0'; HUnlock (pastedTextH); } } /* and fall through ... */ case CLEAR: DeleteRange (); break; } } static void DoControlMenu (int theItem) { extern xlbreak (char *, char *); extern char *s_unbound; extern xlcontinue (void); extern xlcleanup (void); extern xlabort (char *); extern xltoplevel (void); scrflush (); HiliteMenu (0); switch (theItem) { case BREAK: StopPasting (); xlbreak ("user break", s_unbound); PrepareForInput (); break; case CONTINUE: StopPasting (); xlcontinue (); PrepareForInput (); break; case CLEAN_UP: StopPasting (); xlcleanup (); PrepareForInput (); break; case CANCEL_INPUT: StopPasting (); xlabort ("input canceled"); PrepareForInput (); break; case TOP_LEVEL: StopPasting (); xltoplevel (); PrepareForInput (); break; case SHOW_GRAPHICS: if (gGraphicsShown) HideGrafWin (); else ShowGrafWin (); break; case SPLIT_SCREEN: MoveWindow (gCommandWin, sHorizontal, sVertical, -1); SizeWindow (gCommandWin, sWidth, sHeight, -1); InvalRect (&gCommandWin->portRect); SetTERect (); SetScrollRect (); ShowGrafWin (); MoveWindow (gGraphicsWin, gHorizontal, gVertical, -1); SizeWindow (gGraphicsWin, gWidth, gHeight, -1); break; } } void DoMenu (long choice) { int theMenu = HiWord (choice), theItem = LoWord (choice); HiliteMenu (theMenu); switch (theMenu) { case APPLE_MENU_RES: DoAppleMenu (theItem); break; case FILE_MENU_RES: DoFileMenu (theItem); break; case EDIT_MENU_RES: DoEditMenu (theItem); break; case CONTROL_MENU_RES: DoControlMenu (theItem); break; } HiliteMenu (0); } void AdjustMenus (void) { /* turn the stuff in the Edit menu on and off as necessary */ long temp; DisableItem (editMenu, UNDO); if (TEXTREC->selStart != TEXTREC->selEnd) { EnableItem (editMenu, CUT); EnableItem (editMenu, COPY); EnableItem (editMenu, CLEAR); } else { DisableItem (editMenu, CUT); DisableItem (editMenu, COPY); DisableItem (editMenu, CLEAR); } if (GetScrap (NIL, 'TEXT', &temp) > 0) EnableItem (editMenu, PASTE); else DisableItem (editMenu, PASTE); } RgnHandle rgn = nil; void DoContent (EventRecord *theEvent) { /* handle a click in a window's content region */ ControlHandle theScrollBar; GrafPtr oldPort; int scrollValue; Point mouse = theEvent->where; int thePart; // RgnHandle rgn = nil; GetPort (&oldPort); SetPort (gCommandWin); GlobalToLocal (&mouse); // Get Selected text rgn = NewRgn(); TEGetHiliteRgn(rgn, hTERec); if (thePart = FindControl (mouse, gCommandWin, &theScrollBar)) { switch (thePart) { case kControlUpButtonPart: case kControlDownButtonPart: case kControlPageUpPart: case kControlPageDownPart: scrollValue = TrackControl (theScrollBar, mouse, uppScrollProc); break; case kControlIndicatorPart: scrollValue = GetControlValue (theScrollBar); thePart = TrackControl (theScrollBar, mouse, NIL); if (thePart) { scrollValue -= GetControlValue (theScrollBar); if (scrollValue) TEScroll (0, scrollValue * LINEHEIGHT, hTERec); } break; } } else if (PtInRgn(mouse, rgn)) { if (!DragText(theEvent)) { TEClick(mouse, false, hTERec); } } else if (PtInRect (mouse, &(TEXTREC->viewRect))) { TEClick (mouse, (theEvent->modifiers & shiftKey) != 0, hTERec); } SetPort (oldPort); DisposeRgn(rgn); } void DoEvent (void) { EventRecord theEvent; if ((flashTime) && (--flashTime == 0)) SetSelection (cursorBeforeFlash, cursorBeforeFlash); if (outputBufferLength) FlushOutput (); if (FrontWindow () == gCommandWin) TEIdle (hTERec); recentChar = '\0'; if (WaitNextEvent (everyEvent, &theEvent, 0, gMouseRgn)) { AdjustCursor (theEvent.where, gMouseRgn); switch (theEvent.what) { case kHighLevelEvent: AEProcessAppleEvent(&theEvent); break; case mouseDown: DoMouseDown (&theEvent); break; case keyDown: case autoKey: DoKeyPress (&theEvent); break; case activateEvt: { WindowPtr whichWindow = (WindowPtr)theEvent.message; SetPort (whichWindow); if (whichWindow == gCommandWin) { if ((theEvent.modifiers & activeFlag) == 1) { ActivateCmdWindow(); } else { DeactivateCmdWindow(); } } break; } case updateEvt: { if ((WindowPtr)theEvent.message == gCommandWin) UpdateCmdWindow (); if ((WindowPtr)theEvent.message == gGraphicsWin) UpdateGraphWindow (); break; } case osEvt: if (((theEvent.message >> 24) & 0xff) == suspendResumeMessage) { if (theEvent.message & resumeFlag) { gInBackground = false; if (FrontWindow () == gCommandWin) { ActivateCmdWindow(); } } else { gInBackground = true; if (FrontWindow () == gCommandWin) { SetPort (gCommandWin); DeactivateCmdWindow(); } } } break; } } AdjustCursor (theEvent.where, gMouseRgn); } void MacWrapUp (void) { /* take everything down in preparation for quitting */ CleanupCmdWindow(); CloseWindow (gGraphicsWin); } nyquist-3.05/sys/mac/system.lsp0000644000175000000620000000605111466723256015623 0ustar stevestaff; system.lsp -- machine/system-dependent definitions ; Macintosh (setf ny:bigendianp t) ;; note that *default-sf-format* is used below by ;; compute-default-sound-file (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-AIFF)) ;; note that compute-default-sound-file uses *default-sf-format*, ;; so be sure to set *default-sf-format* first (this was just done) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* "points.dat")) ; turn off switch to play sound as it is computed (setf *soundenable* T) ; local definition for play (defmacro play (expr) `(s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*)) (defun r () (s-save (s-read *default-sound-file*) NY:ALL "" :play t) ) ; PLAY-FILE -- play a file (defun play-file (name) (s-save (s-read name) NY:ALL "" :play t)) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (eq (char filename 0) #\:)) (setf *file-separator* #\:) ; save the standard function to write points to a file ; ;(setfn s-plot-points s-plot) (defun array-max-abs (points) (let ((m 0.0)) (dotimes (i (length points)) (setf m (max m (abs (aref points i))))) m)) (setf graph-width 800) (setf graph-height 220) (defun s-plot (snd &optional (n 800)) (show-graphics) (clear-graphics) (cond ((soundp snd) (s-plot-2 snd n (/ graph-height 2) graph-height nil)) (t (let ((gh (/ graph-height (length snd))) hs) (dotimes (i (length snd)) (setf hs (s-plot-2 (aref snd i) n (+ (/ gh 2) (* i gh)) gh hs))))))) (defun s-plot-2 (snd n y-offset graph-height horizontal-scale) (prog ((points (snd-samples snd n)) maxpoint horizontal-scale vertical-scale) (setf maxpoint (array-max-abs points)) (moveto 0 y-offset) (lineto graph-width y-offset) (moveto 0 y-offset) (cond ((null horizontal-scale) (setf horizontal-scale (/ (float graph-width) (length points))))) (setf vertical-scale (- (/ (float graph-height) 2 maxpoint))) (dotimes (i (length points)) (lineto (truncate (* horizontal-scale i)) (+ y-offset (truncate (* vertical-scale (aref points i)))))) (format t "X Axis: ~A to ~A (seconds)\n" (snd-t0 snd) (/ (length points) (snd-srate snd))) (format t "Y Axis: ~A to ~A\n" (- maxpoint) maxpoint) (format t "~A samples plotted.\n" (length points)) (return horizontal-scale) )) ; S-EDIT - run the audio editor on a sound ; ;(defmacro s-edit (&optional expr) ; `(prog () ; (if ,expr (s-save ,expr 1000000000 *default-sound-file*)) ; (system (format nil "audio_editor ~A &" ; (soundfilename *default-sound-file*))))) nyquist-3.05/sys/mac/macptrs.h0000644000175000000620000000206310144436365015372 0ustar stevestaff{ "HIDEPEN", S, xhidepen }, /* 300 */ { "SHOWPEN", S, xshowpen }, /* 301 */ { "GETPEN", S, xgetpen }, /* 302 */ { "PENSIZE", S, xpensize }, /* 303 */ { "PENMODE", S, xpenmode }, /* 304 */ { "PENPAT", S, xpenpat }, /* 305 */ { "PENNORMAL", S, xpennormal }, /* 306 */ { "MOVETO", S, xmoveto }, /* 307 */ { "MOVE", S, xmove }, /* 308 */ { "LINETO", S, xdrawto }, /* 309 */ { "LINE", S, xdraw }, /* 310 */ { "SHOW-GRAPHICS", S, xshowgraphics }, /* 311 */ { "HIDE-GRAPHICS", S, xhidegraphics }, /* 312 */ { "CLEAR-GRAPHICS", S, xcleargraphics }, /* 313 */ { "TOOLBOX", S, xtool }, /* 314 */ { "TOOLBOX-16", S, xtool16 }, /* 315 */ { "TOOLBOX-32", S, xtool32 }, /* 316 */ { "NEWHANDLE", S, xnewhandle }, /* 317 */ { "NEWPTR", S, xnewptr }, /* 318 */ { "HIWORD", S, xhiword }, /* 319 */ { "LOWORD", S, xloword }, /* 320 */ { "READ-CHAR-NO-HANG", S, xrdnohang }, /* 321 */ /* not implemented - take a look at code in directory "sys:mac:old" */ /*{ "COMMAND-POINT-SIZE", S, xptsize }, 322 */ nyquist-3.05/sys/mac/MacCommandWin.c0000644000175000000620000007124310144436365016377 0ustar stevestaff//============================================================================= // All command window updates, input, etc happen here -EAD //============================================================================= #include /* #include */ #include #include #include #include "MacGlobals.h" #include "macint.h" #include #define NIL ((void *) 0) //============================================================================= // local variables //============================================================================= ControlHandle vScroll; int cursorPos; /* the cursor's position on the line */ short linesInView; /* how many lines are in the window */ int cmdStart; /* where (in text record) the current command starts */ TextStyle textStyle[2]; /* styles: bold for user input, plain for output */ /* output is buffered */ Handle hOutputBuffer = NULL; enum currentStyle { plainStyle, boldStyle } currentStyle; static void GoStartOfLine (void); static void GoEndOfLine (void); static void GoBackOneWord (void); static void GoForwardOneWord (void); //============================================================================= // static void DoScrollBar (ControlHandle control, short change) //============================================================================= /* keep track of the user as he fiddles with the scroll bar */ /* This routine is called while the user has the mouse down. */ /* It makes sure the thumb isn't dragged out-of-bounds. */ //============================================================================= static void DoScrollBar (ControlHandle control, short change) { short value = GetControlValue (control), max = GetControlMaximum (control); long newval = value + change; /* this is a long in case we try to go past MAX_INT */ if (newval < 0) newval = 0; else if (newval > max) newval = max; SetControlValue (control, (short) newval); if (newval != value) TEScroll (0, (short) (value - newval) * LINEHEIGHT, hTERec); } //============================================================================= // pascal Boolean ScrollClickLoop (void) //============================================================================= // //============================================================================= pascal Boolean ScrollClickLoop (void) { Rect tempRect; Point mouse; GrafPtr oldPort; RgnHandle oldClip; short amount = 0; if (FrontWindow () != gCommandWin) return false; GetPort (&oldPort); SetPort (gCommandWin); GetClip (oldClip = NewRgn ()); SetRect (&tempRect, INT_MIN, INT_MIN, INT_MAX, INT_MAX); ClipRect (&tempRect); GetMouse (&mouse); if (mouse.v < TEXTREC->viewRect.top) DoScrollBar (vScroll, -1); else if (mouse.v > TEXTREC->viewRect.bottom) DoScrollBar (vScroll, 1); SetClip (oldClip); DisposeRgn (oldClip); SetPort (oldPort); return true; } //============================================================================= // static pascal void ScrollProc (ControlHandle control, short thePart) //============================================================================= // for clicks in the scroll bar or arrows; update the window properly //============================================================================= pascal void ScrollProc (ControlHandle control, short thePart) { short amount; WindowPtr window; if (!thePart) return; window = (*control)->contrlOwner; switch (thePart) { case kControlUpButtonPart: amount = -1; break; case kControlDownButtonPart: amount = 1; break; case kControlPageUpPart: amount = -linesInView; break; case kControlPageDownPart: amount = linesInView; break; } DoScrollBar (control, amount); } //============================================================================= // Rect SetTERect (void) //============================================================================= // set the dimensions of the text record in its window //============================================================================= Rect SetTERect (void) { Rect teRect = gCommandWin->portRect; teRect.right -= SCROLLER_WIDTH; InsetRect (&teRect, TEXT_MARGIN, TEXT_MARGIN); linesInView = (teRect.bottom - teRect.top) / LINEHEIGHT; teRect.bottom = teRect.top + linesInView * LINEHEIGHT; /* round off */ return teRect; } //============================================================================= // static void AdjustCursor (EventRecord *theEvent) //============================================================================= // make the pointer an I-beam iff it's in the text window //============================================================================= void AdjustCursor (Point theLoc, RgnHandle theRgn) { RgnHandle arrowRgn, iBeamRgn, hiliteRgn, tempRgn; Rect theRect; Point thePoint; if (gInBackground) return; arrowRgn = NewRgn(); SetRectRgn(arrowRgn, -32767, -32767, 32767, 32767); // GlobalToLocal ((theLoc); ??? if (gCommandWin == FrontWindow () ) { SetPort(gCommandWin); iBeamRgn = NewRgn(); hiliteRgn = NewRgn(); theRect = TEXTREC->viewRect; LocalToGlobal((Point *)&(theRect.top)); LocalToGlobal((Point *)&(theRect.bottom)); RectRgn(iBeamRgn, &theRect); TEGetHiliteRgn(hiliteRgn, hTERec); thePoint.h = thePoint.v = 0; LocalToGlobal(&thePoint); OffsetRgn(hiliteRgn, thePoint.h, thePoint.v); DiffRgn(arrowRgn, hiliteRgn, arrowRgn); DiffRgn(arrowRgn, iBeamRgn, arrowRgn); DiffRgn(iBeamRgn, hiliteRgn, iBeamRgn); if (PtInRgn(theLoc, iBeamRgn)) { SetCursor(*GetCursor(iBeamCursor)); CopyRgn(iBeamRgn, theRgn); } else if (PtInRgn(theLoc, hiliteRgn)) { SetCursor(&qd.arrow); CopyRgn(hiliteRgn, theRgn); } else { SetCursor(&qd.arrow); CopyRgn(arrowRgn, theRgn); } DisposeRgn(iBeamRgn); DisposeRgn(hiliteRgn); } else { SetCursor(&qd.arrow); CopyRgn(arrowRgn, theRgn); } DisposeRgn(arrowRgn); } //============================================================================= // static void SetScrollRect (void) //============================================================================= // Set Scroll bar rec size //============================================================================= void SetScrollRect (void) { /* set the dimensions of the scroll bar in its window */ // This change fixes the double flash on window resize -EAD // MoveControl (vScroll, commandWin->portRect.right - SCROLLER_WIDTH, -1); // SizeControl (vScroll, SCROLLER_WIDTH + 1, // (commandWin->portRect.bottom - commandWin->portRect.top) - (SCROLLER_WIDTH - 2)); (*vScroll)->contrlRect.left = gCommandWin->portRect.right - SCROLLER_WIDTH; (*vScroll)->contrlRect.top = -1; (*vScroll)->contrlRect.right = gCommandWin->portRect.right + 1; (*vScroll)->contrlRect.bottom = gCommandWin->portRect.bottom - (SCROLLER_WIDTH - 1); } //============================================================================= // static void AdjustScrollBar (void) //============================================================================= // Set the thumb on scrollbar //============================================================================= static void AdjustScrollBar (void) { /* adjust the scroll bar to match the position of the text view */ short oldval = GetControlValue (vScroll), oldmax = GetControlMaximum (vScroll); short value, max; short test; max = TEXTREC->nLines - linesInView; if ((TEXTREC->teLength > 0) && (*(*TEXTREC->hText + TEXTREC->teLength - 1) == '\r')) max++; if (max < 0) max = 0; if (max != oldmax) SetControlMaximum (vScroll, max); value = (short)((TEXTREC->viewRect.top - TEXTREC->destRect.top) / LINEHEIGHT); // value = roundup ((TEXTREC->viewRect.top - TEXTREC->destRect.top) / LINEHEIGHT); if (value < 0) value = 0; else if (value > max) value = max; if (value != oldval) SetControlValue (vScroll, value); } static short roundup (float x) { /* a kludge to round up a float to an int */ if (((int) x) != ((int) (x += 0.5))) x += 0.5; return (int) x; } //============================================================================= // void DoKeyPress (EventRecord *theEvent) //============================================================================= // Hanlde Keyboard Input //============================================================================= void DoKeyPress (EventRecord *theEvent) { short whatKey = theEvent->message & charCodeMask; if (theEvent->modifiers & cmdKey) { long choice; AdjustMenus (); if (choice = MenuKey (theEvent->message)) DoMenu (choice); else if (((whatKey == 'w') || (whatKey == 'W')) && (FrontWindow () == gGraphicsWin)) HideGrafWin (); else if (whatKey == LEFTARROW) GoStartOfLine (); else if (whatKey == RIGHTARROW) GoEndOfLine (); else if (whatKey == UPARROW) DoScrollBar (vScroll, - linesInView); else if (whatKey == DOWNARROW) DoScrollBar (vScroll, linesInView); } else if (theEvent->modifiers & optionKey) { if (whatKey == LEFTARROW) GoBackOneWord (); else if (whatKey == RIGHTARROW) GoForwardOneWord (); } else switch (whatKey) { case PAGEUP: DoScrollBar (vScroll, -linesInView); break; case PAGEDN: DoScrollBar (vScroll, linesInView); break; case HOMEKEY: DoScrollBar (vScroll, INT_MIN); break; case ENDKEY: DoScrollBar (vScroll, INT_MAX); break; case FNKEY: break; case HELPKEY: break; default: recentChar = theEvent->message & charCodeMask; } } //============================================================================= // static void DrawOnlyGrowIcon (WindowPtr window) //============================================================================= // draw growbox on command window with no scoll bars //============================================================================= static void DrawOnlyGrowIcon (WindowPtr window) { RgnHandle saveRgn; Rect growRect; growRect = window->portRect; growRect.top = growRect.bottom - SCROLLER_WIDTH; growRect.left = growRect.right - SCROLLER_WIDTH; GetClip (saveRgn = NewRgn ()); ClipRect (&growRect); DrawGrowIcon (window); SetClip (saveRgn); DisposeRgn (saveRgn); } //============================================================================= // void SetSelection (short start, short end) //============================================================================= // set text selection in the command window //============================================================================= void SetSelection (short start, short end) { TEXTREC->clikStuff = 255; /* to make sure the caret appears at the start of a line when it should */ /* see tech note "TextEdit EOL Ambiguity" for more information */ TESetSelect (start, end, hTERec); } //============================================================================= // static void CancelFlash (void) //============================================================================= // cancel the matching-paren flashing //============================================================================= static void CancelFlash (void) { if (flashTime) { flashTime = 0; SetSelection (cursorBeforeFlash, cursorBeforeFlash); } } //============================================================================= // static void StopPasting (void) //============================================================================= // clean up after finishing a paste //============================================================================= void StopPasting (void) { pastedLength = 0; if (pastedTextH) { DisposeHandle (pastedTextH); pastedTextH = NULL; } } //============================================================================= // static void DoStyle (int whatStyle) //============================================================================= // set the text to a certain style //============================================================================= static void DoStyle (int whatStyle) { TESetStyle (doFace, &(textStyle[whatStyle]), false, hTERec); } //============================================================================= // static void FlushOutput (void) //============================================================================= // clear out the output buffer, dumping its contents to the window //============================================================================= void FlushOutput (void) { short totalLines, scrollAmount, max; if (outputBufferLength == 0) return; CancelFlash (); DoStyle (plainStyle); HLock (hOutputBuffer); TEInsert (*hOutputBuffer, outputBufferLength, hTERec); HUnlock (hOutputBuffer); outputBufferLength = 0; if (TEXTREC->teLength > SCROLLBACK_THRESHHOLD) { /* make sure TE record isn't too long */ #ifdef ORIGINALCODE /* I replaced this because Nyquist was crashing after the buffer got filled. The replacement below is simpler and eliminates the crashes, although it probably could cause problems by clearing the selection. */ int i = 1, newLength; TEPtr textPtr; while ((TEXTREC->teLength - TEXTREC->lineStarts[i]) > (SCROLLBACK_THRESHHOLD - DELETE_BLOCK)) i++; i = TEXTREC->lineStarts[i]; newLength = TEXTREC->teLength - i; textPtr = (TEPtr)(*(TEXTREC->hText)); BlockMoveData ((Ptr)((long)textPtr + i), textPtr, newLength); SetHandleSize (TEXTREC->hText, newLength); TEXTREC->destRect.top += LINEHEIGHT; TECalText (hTERec); TEUpdate (&(TEXTREC->viewRect), hTERec); #else /* find the line start after DELETE_BLOCK */ int i = 1; while (TEXTREC->lineStarts[i] < DELETE_BLOCK) i++; TESetSelect(0, TEXTREC->lineStarts[i], hTERec); TEDelete(hTERec); /* after deletion, put cursor back at end of buffer */ TESetSelect(TEXTREC->teLength, TEXTREC->teLength, hTERec); #endif } TESelView (hTERec); AdjustScrollBar (); } //============================================================================= // void PrepareForInput (void) //============================================================================= // get ready to take input //============================================================================= void PrepareForInput (void) { FlushOutput (); cmdStart = TEXTREC->selStart; } //============================================================================= // static void DeleteRange (void) //============================================================================= // delete the selected range of text, updating cmdStart as necessary //============================================================================= void DeleteRange (void) { if (TEXTREC->selEnd <= cmdStart) return; if (TEXTREC->selStart < cmdStart) SetSelection (cmdStart, TEXTREC->selEnd); TEDelete (hTERec); } //============================================================================= // static void CopyThisLineToEnd (void) //============================================================================= // copy the line the caret is on to the end //============================================================================= static void CopyThisLineToEnd (void) { char *buffer; short b, i, caretOffset; /* first find out exactly where it starts */ i = TEXTREC->nLines-1; /* first find which line */ while (TEXTREC->selStart < TEXTREC->lineStarts[i]) i--; while ((i > 0) && ((*(TEXTREC->hText))[TEXTREC->lineStarts[i]-1] != '\r')) i--; /* for wrapped lines */ i = TEXTREC->lineStarts[i]; /* now zero in on the exact character where it begins */ while ((TEXTCHAR(i) >= '0') && (TEXTCHAR(i) <= '9')) i++; /* skip error level */ if ((TEXTCHAR(i) == '>') && (TEXTCHAR(i+1) == ' ')) i+=2; /* get rid of leading prompt */ caretOffset = TEXTREC->selStart - i; /* how many characters in is the caret? */ /* now put the line into the buffer */ b = 0; while ((TEXTCHAR(i+b) != '\r') && (i+b < TEXTREC->teLength)) b++; /* find the end of the line */ buffer = (char *) NewPtr (b); BlockMoveData (*TEXTREC->hText + i, buffer, b); buffer[b] = '\0'; /* delete whatever's already on the last line */ SetSelection (cmdStart, TEXTREC->teLength); TEDelete (hTERec); DoStyle (boldStyle); TEInsert (buffer, b, hTERec); DisposePtr (buffer); if (caretOffset < 0) caretOffset = b; SetSelection (cmdStart + caretOffset, cmdStart + caretOffset); } //============================================================================= // Next four functions possition cursor in text //============================================================================= static void GoStartOfLine (void) { short whichLine = TEXTREC->nLines - 1; /* look for the caret; start at the end and go up */ while (TEXTREC->lineStarts[whichLine] > TEXTREC->selStart) whichLine--; SetSelection (TEXTREC->lineStarts[whichLine], TEXTREC->lineStarts[whichLine]); AdjustScrollBar (); } static void GoEndOfLine (void) { short whichLine = TEXTREC->nLines - 1; /* look for the caret; start at the end and go up */ while (TEXTREC->lineStarts[whichLine] > TEXTREC->selStart) whichLine--; if (whichLine == TEXTREC->nLines - 1) SetSelection (TEXTREC->teLength, TEXTREC->teLength); else SetSelection (TEXTREC->lineStarts[whichLine+1] - 1, TEXTREC->lineStarts[whichLine+1] - 1); AdjustScrollBar (); } static void GoBackOneWord (void) { short i = TEXTREC->selStart; while ((i > 0) && !isalnum (TEXTCHAR(i-1))) i--; while ((i > 0) && isalnum (TEXTCHAR(i-1))) i--; SetSelection (i, i); } static void GoForwardOneWord (void) { short i = TEXTREC->selStart; while ((i < TEXTREC->teLength) && !isalnum (TEXTCHAR(i))) i++; while ((i < TEXTREC->teLength) && isalnum (TEXTCHAR(i))) i++; SetSelection (i, i); } //============================================================================= // static void EditFreely (void) //============================================================================= // Enter text into the command windows //============================================================================= static void EditFreely (void) { Boolean done; do { done = false; DoEvent (); if (pastedLength > 0) { /* if there is still text to paste, paste it */ int i = 0; CancelFlash (); if (TEXTREC->selStart < cmdStart) StopPasting (); else { while ((i < pastedLength) && (((char *)(*pastedTextH))[i] != '\r')) i++; DoStyle (boldStyle); TEInsert (*pastedTextH, i, hTERec); AdjustScrollBar (); if (i < pastedLength) { /* we were stopped by a carriage return, so eat it */ i++; done = true; } pastedLength -= i; if (pastedLength > 0) { BlockMoveData ((Ptr)((long)(*pastedTextH) + i), *pastedTextH, pastedLength); SetHandleSize (pastedTextH, pastedLength); } else StopPasting (); } } else if (recentChar) { /* if the last event got us a character, process it */ int i; Boolean wasOnLastLine; CancelFlash (); if ((TEXTREC->selEnd <= cmdStart) && (TEXTREC->selStart != TEXTREC->selEnd)) continue; if (TEXTREC->selStart < cmdStart) SetSelection (cmdStart, TEXTREC->selEnd); wasOnLastLine = (TEXTREC->selStart >= cmdStart); if ((recentChar & 0xfc) == 0x1c) { /* was this an arrow key? */ TEXTREC->clikStuff = 255; /* to make sure the caret appears where it should */ TEKey (recentChar, hTERec); AdjustScrollBar (); continue; } if (!wasOnLastLine) CopyThisLineToEnd (); switch (recentChar) { case FWDDEL: if (TEXTREC->selStart != TEXTREC->selEnd) DeleteRange (); else if ((TEXTREC->selStart >= cmdStart) && (TEXTREC->selStart < TEXTREC->teLength)) { TEDeactivate (hTERec); SetSelection (TEXTREC->selStart, TEXTREC->selStart + 1); TEDelete (hTERec); if (FrontWindow () == gCommandWin) TEActivate (hTERec); } break; case CLRKEY: if (TEXTREC->selStart != TEXTREC->selEnd) DeleteRange (); break; case DELETE: if (TEXTREC->selStart != TEXTREC->selEnd) DeleteRange (); else if (TEXTREC->selStart > cmdStart) { TEXTREC->clikStuff = 255; /* to make sure the caret appears where it should */ TEKey (DELETE, hTERec); } break; case RETURN: if (wasOnLastLine) done = true; break; case ENTER: /* ENTER ends command no matter what */ done = true; break; default: DoStyle (boldStyle); TEXTREC->clikStuff = 255; /* to make sure the caret appears where it should */ TEKey (recentChar, hTERec); if ((recentChar == ')') && (TEXTREC->selStart > cmdStart)) { short parenCount = -1; Boolean inQuotes = false; i = TEXTREC->selStart - 1; while ((--i >= cmdStart) && (parenCount != 0)) switch ((*TEXTREC->hText)[i]) { case DBLQUOTE: inQuotes = !inQuotes; break; case '(': if (!inQuotes) parenCount++; break; case ')': if (!inQuotes) parenCount--; break; } if (parenCount == 0) { cursorBeforeFlash = TEXTREC->selStart; SetSelection (i+1, i+2); /* flash the matching open-paren */ flashTime = 10; } } else if ((recentChar == DBLQUOTE) && (TEXTREC->selStart > cmdStart)) { i = TEXTREC->selStart - 1; while ((--i >= cmdStart) && ((*TEXTREC->hText)[i] != DBLQUOTE)) ; if ((*TEXTREC->hText)[i] == DBLQUOTE) { cursorBeforeFlash = TEXTREC->selStart; SetSelection (i, i+1); /* flash the matching double-quote */ flashTime = 10; } } } AdjustScrollBar (); } } while (!done); } char *macgets (void) { /* retrieve a typed character */ /* Note that this uses some extensive (and clever, if I may say so myself) buffering. */ int i, b, bufSize; char *ptr, *buffer; Boolean done, onLastLine; PrepareForInput (); do { /* repeat until a full expression has been typed */ EditFreely (); /* allow free editing for a while */ /* Now, we have a complete command to parse, if and only if: */ /* - the cursor was on the last line when the user pressed Return or Enter, and */ /* - the user either pressed Enter, or else every '(' since the beginning */ /* of the command is matched by a ')'. */ /* Quoting is watched for. ( ") is not a complete expression. */ done = true; if (TEXTREC->selStart != TEXTREC->teLength) /* if we're not at the end already */ SetSelection (TEXTREC->teLength, TEXTREC->teLength); /* send cursor to end */ TEXTREC->clikStuff = 255; /* to make sure the caret appears where it should */ TEKey ('\r', hTERec); /* check and see if we've completed the command yet */ if (recentChar != ENTER) { Boolean inQuotes = false; short parenCount = 0; for (i = cmdStart; i < TEXTREC->teLength; i++) switch ((*TEXTREC->hText)[i]) { case DBLQUOTE: inQuotes = !inQuotes; break; case '(': if (!inQuotes) parenCount++; break; case ')': if (!inQuotes) parenCount--; break; } if ((parenCount > 0) || inQuotes) done = false; } AdjustScrollBar (); } while (!done); /* put the entire command into the buffer, and return it */ bufSize = TEXTREC->teLength - cmdStart; buffer = (char *) NewPtr (bufSize + 1); BlockMoveData (*TEXTREC->hText + cmdStart, buffer, bufSize); buffer[bufSize] = '\0'; return buffer; } void macputc (int ch) { /* put a char into the output buffer, and flush the buffer if necessary */ switch (ch) { case '\t': do { macputc (' '); } while (cursorPos & 7); break; case DELETE: if (cursorPos) cursorPos--; /* and fall through to default */ default: if (outputBufferLength == MAX_BUF) FlushOutput (); if (ch == '\n') { cursorPos = 0; (*hOutputBuffer)[outputBufferLength++] = '\r'; } else { cursorPos++; (*hOutputBuffer)[outputBufferLength++] = ch; } } } void macputs (char *s) { /* for completeness */ while (*s) macputc (*s++); } void scrflush (void) { extern void osflush (void); /* clear out everything */ FlushOutput (); osflush (); } void scrclear (void) { /* clear text window -- not implemented */ } //============================================================================= // static void UpdateCmdWindow (void) //============================================================================= // main command window update procedure //============================================================================= void UpdateCmdWindow (void) { long textBottom; Rect tempRect; InvalRect (&(gCommandWin->portRect)); BeginUpdate (gCommandWin); BlockMoveData(&(gCommandWin->portRect), &tempRect, sizeof(Rect)); tempRect.right -= SCROLLER_WIDTH; EraseRect (&tempRect); if (gCommandWinResized) { TEXTREC->viewRect = SetTERect (); TEXTREC->destRect.right = TEXTREC->viewRect.right; TECalText (hTERec); SetScrollRect (); gCommandWinResized = false; } DrawOnlyGrowIcon (gCommandWin); FlushOutput (); TEXTREC->viewRect = SetTERect (); /* adjust for possible change in height of status line */ textBottom = TEXTREC->destRect.top + (TEXTREC->nLines * LINEHEIGHT); if (TEXTREC->destRect.top > TEXTREC->viewRect.top) TEScroll (0, (TEXTREC->viewRect.top - TEXTREC->destRect.top), hTERec); if (TEXTREC->destRect.top < TEXTREC->viewRect.top) { /* make sure we don't get fractions of lineheights */ int amountOffTheTop = TEXTREC->viewRect.top - TEXTREC->destRect.top; if (amountOffTheTop % LINEHEIGHT) TEScroll (0, amountOffTheTop % LINEHEIGHT, hTERec); } TEUpdate (&(TEXTREC->viewRect), hTERec); AdjustScrollBar (); UpdateControls (gCommandWin, gCommandWin->visRgn); EndUpdate (gCommandWin); } void ActivateCmdWindow(void) { TEActivate (hTERec); HiliteControl (vScroll, 0); DrawOnlyGrowIcon (gCommandWin); } void DeactivateCmdWindow(void) { TEDeactivate (hTERec); HiliteControl (vScroll, 255); DrawOnlyGrowIcon (gCommandWin); } void InitalizeCmdWindow(void) { /* setup the font, size and writing mode for the command window */ TextFont (kFontIDMonaco); TextSize (9); TextFace (0); TextMode (srcCopy); textStyle[plainStyle].tsFace = 0; textStyle[boldStyle].tsFace = bold; currentStyle = plainStyle; { /* set up scroll bar */ Rect scrollRect; vScroll = NewControl (gCommandWin, &scrollRect, "\p", 0, 0, 0, 0, scrollBarProc, 0L); SetScrollRect (); ShowControl (vScroll); } { /* set up command text record */ Rect teRect = SetTERect (); hTERec = (TEHandle)TEStyleNew (&teRect, &teRect); TECalText (hTERec); TEAutoView (true, hTERec); TESetClickLoop (uppScrollClickLoop, hTERec); TEActivate (hTERec); } hOutputBuffer = NewHandle (MAX_BUF); /* a handle to a buffer for text to be displayed */ } void CleanupCmdWindow(void) { StopPasting (); CloseWindow (gCommandWin); TEDispose (hTERec); DisposeHandle (hOutputBuffer); } nyquist-3.05/sys/mac/MacHandleEv.c0000644000175000000620000000427010144436365016025 0ustar stevestaff#include #include #include #include #include #include "macint.h" extern WindowPtr gCommandWin, gGraphicsWin; extern Boolean gCommandWinResized; extern Rect dragRect, sizeRect; //============================================================================= // Hanlde Mouse Down Events //============================================================================= void DoMouseDown (EventRecord *theEvent) { WindowPtr whichWindow; short int thePart = FindWindow (theEvent->where, &whichWindow); switch (thePart) { case inSysWindow: SystemClick (theEvent, whichWindow); break; case inDrag: DragWindow (whichWindow, theEvent->where, &dragRect); break; case inMenuBar: { long choice; AdjustMenus (); choice = MenuSelect (theEvent->where); if (choice) DoMenu (choice); break; } case inGoAway: if ((whichWindow == gGraphicsWin) && (TrackGoAway (whichWindow, theEvent->where))) HideGrafWin (); break; case inContent: if ((FrontWindow () == gCommandWin) && (whichWindow == gCommandWin)) DoContent (theEvent); else SelectWindow (whichWindow); break; case inGrow: case inZoomIn: case inZoomOut: { long newSize; GrafPtr oldPort; if (thePart == inGrow) newSize = GrowWindow (whichWindow, theEvent->where, &sizeRect); if (((thePart == inGrow) && newSize) || ((thePart != inGrow) && TrackBox (whichWindow, theEvent->where, thePart))) { GetPort (&oldPort); SetPort (whichWindow); EraseRect (&whichWindow->portRect); if (thePart == inGrow) SizeWindow (whichWindow, LoWord (newSize), HiWord (newSize), -1); else ZoomWindow (whichWindow, thePart, 0); gCommandWinResized = true; InvalRect (&whichWindow->portRect); SetPort (oldPort); } break; } } } nyquist-3.05/sys/win/0002755000175000000620000000000011537433132013602 5ustar stevestaffnyquist-3.05/sys/win/README.txt0000644000175000000620000001411511514640104015272 0ustar stevestaffREADME.txt -- Nyquist information for Windows Installation ------------ The Win32 version of Nyquist is packaged as a compiled (runtime) system in an executable installer. For most users, the runtime version contain everything you need to run Nyquist, including the executable, examples, and documentation, packaged as an executable installer program. After executing the installer, just find Nyquist in your Start menu to run it. You may begin typing expressions such as the ones in the following "Examples" section of the Nyquist manual (in doc/nyquistman.pdf or doc/home.html). (See "The 'java is not recognized' Error" below if you get this error message.) A source version is also available (the same source download is for Win32, Mac OS X, and Linux). The source version is intended for developers who want to recompile Nyquist. The contents of the source archive are extracted to the C:\nyquist directory, but you can put it anywhere you like. You can then open the workspace file, nyquist.sln, using Microsoft Visual C++. You can build and run the command line version of Nyquist from within Visual C++. There is a batch file, comp-ide.bat, for bulding the Nyquist IDE. This requires the Java SDK from Sun Microsystems. Optional -------- Nyquist needs to know where to find the standard runtime files. The location of runtime files must be stored in the Registry. The installers create a registry entry, but if you move Nyquist or deal with different versions, you can edit the Registry manually as follows: Run the Registry editor (e.g. type regedit into the Start Search box of the Start menu and type the Enter key). Find and highlight the SOFTWARE key under HKEY_LOCAL_MACHINE. Open the CMU key (if it is not there, use the Edit:New:Key menu item to create a CMU key. CMU is case sensitive.) Highlight the new CMU key. Open the Nyquist key (if it is not there, use the Edit:New:Key menu item to create a Nyquist key. Nyquist is case sensitive.) Highlight the new Nyquist key. Find the XLISPPATH string (if it is not there, use the Edit:New:String menu item to create a new string and change the name by typing XLISPPATH). Select XLISPPATH and choose the Edit:Modify... menu item. In the String Edit box, type a list of paths you want Nyquist to search for lisp files. For example, if you installed Nyquist as C:\nyquist, then type: C:\nyquist\runtime,C:\nyquist\lib The paths should be separated by a comma or semicolon and no space. The runtime path is essential, and the lib path may become essential in a future release. You can also add paths to personal libraries of Lisp and Nyquist code. Click the OK button of the string box and exit from the Registry Editor application. What if Nyquist functions are undefined? ---------------------------------------- If you do not have administrative privileges for your machine, the installer may fail to set up the Registry entry that Nyquist uses to find initialization files. In this case, Nyquist will run a lisp interpreter, but many Nyquist functions will not be defined. If you can log in as administrator, do it and reinstall Nyquist. If you do not have permission, you can still run Nyquist as follows: Create a file named init.lsp in the same directory as Nyquist.exe (the default location is C:\Program Files\Nyquist, but you may have installed it in some other location.) Put the following text in init.lsp: (setf *search-path* "C:/Program Files/Nyquist/runtime,C:/Program Files/Nyquist/lib") (load "C:/Program Files/Nyquist/runtime/init.lsp") Note: in the three places where you see C:/Program Files/Nyquist, insert the full path where Nyquist is actually installed. Use forward slashes (/) rather than back slashes (\) to separate directories. For example, if Nyquist is installed at D:\rbd\nyquist, then init.lsp should contain: (setf *search-path* "D:/rbd/nyquist/runtime,D:/rbd/nyquist/lib") (load "d:/rbd/nyquist/runtime/init.lsp") The variable *search-path*, if defined, is used in place of the registry to determine search paths for files. SystemRoot ---------- (Ignore this paragraph if you are not planning to use Open Sound Control under Windows.) If Nyquist prints an error message and quits when you enable Open Sound Control (using osc-enable), check to see if you have an environment variable SystemRoot, e.g. type set to a command prompt and look for the value of SystemRoot. The normal value is C:\windows. If the value is something else, you should put the environment entry, for example: SystemRoot="D:\windows" into a file named systemroot (no extension). Put this file in your nyquist directory. When you run jNyqIDE, it will look for this file and pass the contents as an environment variable to Nyquist. The Nyquist process needs this to open a UDP socket, which is needed for Open Sound Control. The "java is not recognized" Error ---------------------------------- Sometimes, Nyquist will run directly from the installer, but then it will not start from the Windows Start menu. You can try running the nyquist/jnyqide.bat program from a Windows shell. If that fails, and you see an error similar to "java is not recognized as in internal or external command error", the problem may be that paths are not set up properly to allow the Windows shell to find java. Right click on "My Computer" on the Windows desktop and select "Properties." Under the "Advanced" tab, press the "Environment Variables" button, and look for PATH under "System Variables." Make sure the Java bin directory is on the path. If it is not, you will have to find your installation of Java and add the appropriate directory to the PATH variable, e.g. "C:\Program Files\Java\jdk1.6.0\bin." Right click on "My Computer" on the Windows desktop and select "Properties." Under the "Advanced" tap, press the "Environment Variables" button, and look for PATH under "System Variables." Make sure the Java bin directory is on the path. If it is not, you will have to find your installation of Java and add the appropriate directory to the PATH variable, e.g. "C:\Program Files\Java\jdk1.6.0\bin." nyquist-3.05/sys/win/nyqrelide.iss0000644000175000000620000000346711512143043016316 0ustar stevestaff; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! [Setup] ; NOTE: The value of AppId uniquely identifies this application. ; Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{3E29123D-0726-441C-8A38-42836B05F74C} AppName=NyquistIDE AppVerName=NyquistIDE 3.04 AppPublisher=Roger B. Dannenberg AppPublisherURL=http://www.cs.cmu.edu/~music/nyquist AppSupportURL=http://www.cs.cmu.edu/~music/nyquist AppUpdatesURL=http://www.cs.cmu.edu/~music/nyquist DefaultDirName={pf}\Nyquist DefaultGroupName=Nyquist LicenseFile=C:\Users\rbd\nyquist\nyqrelide\license.txt InfoAfterFile=C:\Users\rbd\nyquist\nyqrelide\Readme.txt OutputDir=setup OutputBaseFilename=setupnyqiderun SetupIconFile=C:\Users\rbd\nyquist\sys\win\wingui\nycon.ico Compression=lzma SolidCompression=yes [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Tasks] Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked [Files] Source: "C:\Users\rbd\nyquist\nyqrelide\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Registry] Root: HKLM32; Subkey: "Software\CMU\Nyquist"; ValueType: string; ValueName: "XLISPPATH"; ValueData: "{app}\runtime,{app}\lib" [Icons] Name: "{group}\NyquistIDE"; Filename: "{app}\jnyqide.bat"; WorkingDir: "{app}" Name: "{commondesktop}\NyquistIDE"; Filename: "{app}\jnyqide.bat"; WorkingDir: "{app}"; Tasks: desktopicon [Run] Filename: "{app}\jnyqide.bat"; WorkingDir: "{app}"; Description: "{cm:LaunchProgram,NyquistIDE}"; Flags: shellexec postinstall skipifsilent nyquist-3.05/sys/win/msvc/0002755000175000000620000000000011537433132014552 5ustar stevestaffnyquist-3.05/sys/win/msvc/switches.h0000644000175000000620000001006411466723256016565 0ustar stevestaff/* switches.h -- conditional compilation features for WIN32 systems */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm major reorganization of conditional compilation in Nyquist */ #ifdef SWITCHES Error: switches.h included more than once. #endif #define HAS_STDLIB_H 1 #define HAS_SYS_TYPES_H 1 #define HAS_SYS_STAT_H 1 #undef HAS_STAT_H #undef HAS_MALLOC_H /* define one of HAS_GETTIMEOFDAY, HAS_FTIME, */ #undef HAS_GETTIMEOFDAY #undef HAS_FTIME #undef READ_LINE #undef USE_RANDOM #define USE_RAND 1 /* since there are 2 versions Nyquist for windows: nyquist and nyqwin, we use WINGUI to decide which to compile */ #ifndef WINGUI /* use C library printf as nyquist_printf() */ #define USE_PRINTF 1 #endif /* define this to be printf, or define your own fn of the form void nyquist_printf(char *format, ...); (for a GUI) */ void nyquist_printf(char *format, ...); #define NEED_ULONG 1 #define NEED_USHORT 1 #define NEED_BYTE 1 #define NEED_ROUND 1 #undef NEED_DEFINE_MALLOC /* definitions for libsndfile */ /* Target processor clips on negative float to int conversion */ /* (true on i386) */ #define CPU_CLIPS_NEGATIVE 1 /* Target processor clips on positive float to int conversion */ /* (true on i386) */ #define CPU_CLIPS_POSITIVE 1 /* Target processor is little endian. */ #define CPU_IS_LITTLE_ENDIAN 1 /* Target processor is big endian. */ #define CPU_IS_BIG_ENDIAN 0 /* Set to 1 if S_IRGRP is defined */ #define HAVE_DECL_S_IRGRP 0 /* Set to 1 if the compiler supports the struct hack. */ #define HAVE_FLEXIBLE_ARRAY 1 /* Define to 1 if you have the `fsync' function. */ #define HAVE_FSYNC 1 /* Define to 1 if you have the `gmtime' function. */ #define HAVE_GMTIME 1 /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 0 /* Define if you have C99's lrint function. */ #define HAVE_LRINT 0 /* Define if you have C99's lrintf function. */ #define HAVE_LRINTF 0 /* Define to 1 if you have the `snprintf' function. */ #define snprintf _snprintf #define HAVE_SNPRINTF 1 /* Define to 1 if the system has the type `ssize_t'. */ #define ssize_t SSIZE_T #define HAVE_SSIZE_T 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 0 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 0 /* Define to 1 if you have the `vsnprintf' function. */ #define HAVE_VSNPRINTF 1 /* Set to 1 if compiling for MacOSX */ #define OS_IS_MACOSX 0 /* Set to 1 if compiling for Win32 */ #define OS_IS_WIN32 1 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Set to 1 to use the native windows API */ #define USE_WINDOWS_API 1 /* The size of `int64_t', as computed by sizeof. */ /* Omit this if int64_t is not a type */ #undef SIZEOF_INT64_T /* The size of long as computed by sizeof. */ #define SIZEOF_LONG 4 /* Set to long if unknown */ #define SIZEOF_SF_COUNT_T 8 /* explicitly choose a platform */ #undef UNIX #ifndef WINDOWS #define WINDOWS 1 #endif #ifndef WIN32 #define WIN32 1 #endif #ifndef MICROSOFT #define MICROSOFT 1 #endif #ifndef DOS #define DOS 1 #endif #undef MACINTOSH // Under Windows, we do not want synchronous input because then we do not // get the break character (^G) while XLISP is busy. Actually, there is a // way to send a message to the process, but the Java IDE cannot send // Windows messages, so we have to check for console character input // using the _kbhit function. //#define BUFFERED_SYNCHRONOUS_INPUT 1 #define SPACE_FOR_PLAY 10000 #define MAX_CHANNELS 16 /* this will enable code to read midi files, etc. */ #define CMTSTUFF 1 /* NYQUIST tells some CMT code that we're really in * XLISP and NYQUIST */ #define NYQUIST 1 #include "swlogic.h" nyquist-3.05/sys/win/msvc/sndsystem.h0000644000175000000620000000002610144436365016754 0ustar stevestaff#include "sndwin32.h" nyquist-3.05/sys/win/msvc/winfun.h0000644000175000000620000000040410144436365016231 0ustar stevestaff#ifdef __cplusplus extern "C" { #endif void get_xlisp_path(char *p, long p_max); char *getfilename(char *deflt, char *extension, char *mode, char *prompt); FILE *fileopen(char *deflt, char *extension, char *mode, char *prompt); #ifdef __cplusplus } #endif nyquist-3.05/sys/win/msvc/stdint.h0000644000175000000620000001651611466723256016251 0ustar stevestaff// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2008 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// // since this is an addition to the liblo library, I'm adding another // change (not normally part of stdint.h for VC++ compatibility: #ifndef inline #define inline __inline #endif typedef long ssize_t; #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif #include // For Visual Studio 6 in C++ mode wrap include with 'extern "C++" {}' // or compiler give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #if (_MSC_VER < 1300) && defined(__cplusplus) extern "C++" { #endif # include #if (_MSC_VER < 1300) && defined(__cplusplus) } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_STDINT_H_ ] nyquist-3.05/sys/win/msvc/winfun.c0000644000175000000620000002010611524074337016225 0ustar stevestaff/* winfun.c - windows user interface functions for xlisp */ /* Written by Brian Kendig. */ /*Windows Console and DirectSound code added by Morgan Green and Chris Tchou*/ //#include //#include //#include #include #include #include "xlisp.h" #include "sound.h" /* Added by Ning Hu May.2001 xsetdir - set current directory of the process */ LVAL xsetdir() { TCHAR ssCurDir[MAX_PATH], szCurDir[MAX_PATH]; int verbose = TRUE; strcpy(ssCurDir, getstring(xlgastring())); if (moreargs()) { verbose = (xlgetarg() != NIL); } xllastarg(); if (SetCurrentDirectory(ssCurDir)) { if (GetCurrentDirectory( sizeof(szCurDir)/sizeof(TCHAR), szCurDir)) { return cvstring(szCurDir); /* create the result string stdputstr("Current Directory: "); stdputstr(szCurDir); stdputstr("\n"); */ } } if (verbose) stdputstr("Directory Setting Error\n"); /* return nil on error*/ return NIL; } /* xget_temp_path -- get a path to create temp files */ LVAL xget_temp_path() { char *p; char szDir[MAX_PATH]; char szDirLC[MAX_PATH]; int rslt = GetTempPath(MAX_PATH, szDir); if (rslt > MAX_PATH || rslt <= 0) { return cvstring(""); } else { /* Vista apparently treats c:\windows with * special semantics, so just don't allow * GetTempPath to put us in c:\windows... */ strcpy(szDirLC, szDir); /* convert to lower case */ for (p = szDirLC; *p; p++) { *p = tolower(*p); } if (strstr(szDirLC, "c:\\windows")) { /* c:\windows is bad. */ return cvstring(""); } return cvstring(szDir); } } //Updated End /* osbgetc - get a character from a binary file ====== added for console*/ /* int osbgetc(fp) FILE *fp; {return (getc(fp));} */ int osbgetc(FILE *fp) { int c; c = (getc(fp)); /* if (dbgflg) printf("osbgetc: got %d from FILE %x\n", c, fp); */ return c; } LVAL xsystem (V) { return NIL; } LVAL xgetkey (V) { return NIL; } void ossymbols() { HWND mywin; #ifdef WIN32_SNAZZY_CONSOLE HANDLE myhandle; COORD winsize, origin; WORD textattrib; DWORD n; #endif mywin = GetForegroundWindow(); SetConsoleTitle("Nyquist"); #ifdef WIN32_SNAZZY_CONSOLE // -eub myhandle = GetStdHandle(STD_OUTPUT_HANDLE); origin.X = 0; origin.Y = 0; winsize.X = 100; winsize.Y = 40; textattrib = BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY; FillConsoleOutputAttribute(myhandle, textattrib, winsize.X * winsize.Y, origin, &n); SetConsoleScreenBufferSize(myhandle, winsize); FillConsoleOutputAttribute(myhandle, textattrib, winsize.X * winsize.Y, origin, &n); SetConsoleTextAttribute(myhandle, textattrib); #endif setvbuf(stdout, NULL, _IONBF, 0); // makes it work under NT emacs 20.3 -eub } LVAL xsetupconsole() { HWND mywin; HANDLE myhandle; COORD winsize, origin; WORD textattrib; DWORD n; mywin = GetForegroundWindow(); SetConsoleTitle("Nyquist"); myhandle = GetStdHandle(STD_OUTPUT_HANDLE); origin.X = 0; origin.Y = 0; winsize.X = 100; winsize.Y = 40; textattrib = BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY; FillConsoleOutputAttribute(myhandle, textattrib, winsize.X * winsize.Y, origin, &n); SetConsoleScreenBufferSize(myhandle, winsize); FillConsoleOutputAttribute(myhandle, textattrib, winsize.X * winsize.Y, origin, &n); SetConsoleTextAttribute(myhandle, textattrib); return NIL; } void get_xlisp_path(char *p, long p_max) { HKEY hkey; DWORD dwType; LVAL lval; extern LVAL s_search_path; *p = 0; /* for simplicity, we assume if !*p that path was not found */ /* therefore, no path is equivalent to an empty string path */ /* first, look for path in global variable *SEARCH-PATH* */ lval = getvalue(s_search_path); if (lval && stringp(lval)) { strncpy(p, getstring(lval), p_max); p[p_max - 1] = 0; /* make sure string is terminated, even if truncated */ } if (*p) return; /* we got search path, so don't look in registry */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return; } if (RegOpenKeyEx(hkey, "CMU", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return; } if (RegOpenKeyEx(hkey, "Nyquist", 0, KEY_READ, &hkey) != ERROR_SUCCESS) { return; } if (RegQueryValueEx(hkey, "XLISPPATH", NULL, &dwType, p, &p_max) != ERROR_SUCCESS) { *p = 0; return; } } LVAL xget_user() { // not implemented for Windows, just use "nyquist" return cvstring("nyquist"); } #ifdef WINGUI /* NOTE: define WINGUI in the Project Settings for the NyqWin projects. * Do not define WINGUI for console versions of Nyquist */ /**************************************************************************** * fileopen * Inputs: * char *deflt: the default file name (e.g. from command line) * char *extension: default extension * char *mode: read ("r") or write ("w") * char *prompt: prompt for user * Returns: * opened file pointer * Effect: * opens file, prompts for user input if necessary and warns about * possible confusion. If deflt is a null string or NULL, the user will * be prompted for a name. The routine loops until a file is opened. * If the mode is "r", a check is made to see if the file exists * with and without the extension. If both exist a warning is given. * For mode "w", a check is made to see if the file will be overwritten. * The extension is automatically added if the default or user-typed * file has no "." At the bottom of the loop body, if no file has * been opened, the user is prompted for another file name. ****************************************************************************/ char fileopen_name[100]; /* name of the opened file */ HINSTANCE hInst; /* current instance */ HWND hMainWindow; /* main window handle */ char *getfilename(char *deflt, char *extension, char *mode, char *prompt) { char filter[64]; char *filter_ptr = NULL; OPENFILENAME open_file_name; if (extension && extension[0] == 0) extension = NULL; if (strcmp(extension, "lsp") == 0) { strcpy(filter, "Lisp files"); } else if (extension) { sprintf(filter, "%s files", extension); } if (extension) { sprintf(filter + strlen(filter), "%c*.%s%cAll files%c*.*%c", 0, extension, 0, 0, 0); filter_ptr = filter; } if (!deflt) deflt = ""; /* treat NULL as the empty string */ strcpy(fileopen_name, deflt); open_file_name.lStructSize = sizeof(OPENFILENAME); open_file_name.hwndOwner = hMainWindow; open_file_name.hInstance = hInst; open_file_name.lpstrFilter = filter_ptr; open_file_name.lpstrCustomFilter = NULL; open_file_name.nMaxCustFilter = 0; open_file_name.nFilterIndex = 0; open_file_name.lpstrFile = fileopen_name; open_file_name.nMaxFile = 100; open_file_name.lpstrFileTitle = NULL; open_file_name.nMaxFileTitle = 0; open_file_name.lpstrInitialDir = NULL; open_file_name.lpstrTitle = prompt; open_file_name.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; open_file_name.nFileOffset = 0; open_file_name.nFileExtension = 0; open_file_name.lpstrDefExt = extension; open_file_name.lCustData = 0; open_file_name.lpfnHook = 0; open_file_name.lpTemplateName = 0; if (((*mode == 'r') && GetOpenFileName(&open_file_name)) || ((*mode == 'w') && GetSaveFileName(&open_file_name))) { return open_file_name.lpstrFile; } return NULL; } FILE *fileopen(char *deflt, char *extension, char *mode, char *prompt) { FILE *fp = NULL; /* file corresponding to filename */ if (getfilename(deflt, extension, mode, prompt)) { fp = fopen(fileopen_name, mode); } return fp; } #endif nyquist-3.05/sys/win/msvc/winstuff.c0000644000175000000620000003030711524074337016570 0ustar stevestaff/* winstuff.c - windows interface routines for xlisp */ /* Written by Chris Tchou. */ /* This file contains the stuff that the other xlisp files call directly. */ /* Changes by Roger Dannenberg, Jan 2006: Previously, the input thread would block on input, so if a command line instantiation of Nyquist called (EXIT), the process would still block in getchar() until the user typed a newline. Now, I only start the input thread if ostgetc is called (input is really needed). This will still read ahead and block, but only in cases where you are already interactive. /* Changes by Roger Dannenberg, April 2004: To support interrupts to Lisp processing, XLISP call oscheck frequently to test for an abort or break condition. This condition can be activated by special handlers, e.g. if a software interrupt is generated by Ctrl-C. Alternatively, the application can read ahead and look for break characters in the input stream. A third approach, implemented by Ning Hu for her Delphi-based IDE, is to send a Windows message to the process. Unfortunately, the Java IDE does not support sending a Windows message, nor can console IO be used to read ahead (console IO does not work because, when started by Java, Nyquist standard IO is redirected through pipes). The two solutions to enable break character prcessing seem to be: 1) extend Java with C code to find the process and send Windows messages 2) add a thread to perform read ahead and break character processing Option 2 contains the ugliness to Nyquist IO, which is already big and ugly, and leaves Java alone, which is something I don't know much about anyway, so I have chosen option 2: create a thread and read ahead. This uses only about 50 lines of code. A shortcoming of this approach is that, except for Ctrl-C, break characters like ^P, ^B, and ^U require the user to type RETURN to end the input line and allow the character to be processed. The thread will set a signal whenever a line of input is delivered so that Nyquist can block waiting for input. The signal will also be set when a ^C or ^G is detected. For flexibility, compatibility with the Delphi IDE (NyqIDE) is retained by continuing to check for Windows process messages. */ #include /* Added by Ning Hu Apr.2001 */ #include /* Added by Dannenberg Apr 2004 */ #include /* Added by Dannneberg, Apr 2004 */ #include "exitpa.h" /* Added by Dannneberg, Apr 2004 */ const char os_pathchar = '\\'; const char os_sepchar = ','; #undef ERROR #include //#include /* for Random */ #include /* for DisposPtr */ #include //#include /* for ExitToShell */ #include "xlisp.h" #include "cext.h" #include "userio.h" #include "sliders.h" #include "sound.h" /* define nosc_enabled */ /* externals */ extern FILE *tfp; /* transcript file pointer */ extern int cursorPos; extern char *macgets (void); //Added by Ning Hu Apr.2001 extern int _isatty(int); extern int redirect_flag; //Add end /* local variables */ int lposition; static char *linebuf = NULL, *lineptr; static int numChars; /* input thread */ unsigned long input_thread_handle = -1; #define NEED_INPUT if (input_thread_handle == -1) start_input_thread(); #define input_buffer_max 1024 #define input_buffer_mask (input_buffer_max - 1) char input_buffer[1024]; volatile int input_buffer_head = 0; volatile int input_buffer_tail = 0; volatile int buffer_eof = 0; HANDLE input_buffer_ready = NULL; BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType) { if (dwCtrlType == CTRL_C_EVENT) { abort_flag = ABORT_LEVEL; return TRUE; } return FALSE; } #ifdef DEBUG_INPUT extern FILE *to_input_buffer; #endif void input_thread_run(void *args) { int c; /* this gets called, possible later, in io_init() in userio.c, but * that doesn't seem to prevent this thread from being killed by * CTRL-C, so call it here to be safe. */ SetConsoleCtrlHandler(ctrl_c_handler, TRUE); /* printf("input_thread_run\n"); */ while (!buffer_eof) { int head; c = getchar(); if (c == EOF && abort_flag) { // when user types ^C, an EOF is generated for some reason. // Ignore it... if (abort_flag == ABORT_LEVEL) c = ABORT_CHAR; else c = BREAK_CHAR; } else if (c == ABORT_CHAR) { abort_flag = ABORT_LEVEL; } else if (!abort_flag && c == BREAK_CHAR) { // notice that a break will be ignored until XLISP // handles the ABORT_LEVEL abort_flag = BREAK_LEVEL; } else if (c == BREAK_CHAR) { ; // ignore this because abort_flag is set to ABORT_LEVEL } else if (c == '\005' || c == '\006') { // control-e or control-f ; // ignore these. IDE will send control-f to turn off echo, but // under Windows, echo is already turned off. We filter control-f // here to avoid generating an error message. Maybe the IDE should // not send control-f in the first place, but the IDE is cross-platform // and does not know it's running under Windows, whereas this file // is platform dependent. } else if (c == '\016') { // begin hidden message #define MSGBUF_MAX 64 char msgbuf[MSGBUF_MAX]; int msgbufx = 0; char type_char = getchar(); // read message type character printf("begin hidden message: %c\n", type_char); if (type_char == EOF) buffer_eof = TRUE; else { // message is terminated by '\021' while ((c = getchar()) != '\021' && c != EOF && msgbufx < MSGBUF_MAX - 1) { msgbuf[msgbufx++] = c; } msgbuf[msgbufx++] = 0; printf("message: %s\n", msgbuf); if (c == EOF) buffer_eof = TRUE; else if (msgbufx < MSGBUF_MAX) { if (type_char == 'S') { // slider change message // message format is indexvalue int index; float value; if (sscanf(msgbuf, "%d %g", &index, &value) == 2) { set_slider(index, value); printf("set_slider %d %g\n", index, value); } } } } } else if (c == EOF) { buffer_eof = TRUE; } else { // insert character into the FIFO head = (input_buffer_head + 1) & input_buffer_mask; while (head == input_buffer_tail) Sleep(100); input_buffer[input_buffer_head] = c; #ifdef DEBUG_INPUT if (to_input_buffer) putc(c, to_input_buffer); #endif input_buffer_head = head; } if (c == '\n' || abort_flag || buffer_eof) { SetEvent(input_buffer_ready); // wake up Nyquist if it is waiting for input } } // printf("Input thread exiting\n"); } //int isascii (char c) { return 1; } /* every char is an ascii char, isn't it? */ void start_input_thread() { // create thread to process input input_thread_handle = _beginthread(input_thread_run, 0, NULL); if (input_thread_handle == -1) { printf("Unable to create input thread, errno = %d\n", errno); EXIT(1); } } void osinit (char *banner) { printf("%s\n", banner); if (_isatty( _fileno( stdin ) ) ){ redirect_flag = 0; #ifdef DEBUG printf( "stdout has not been redirected to a file\n" ); //for debugging use #endif } else { redirect_flag = 1; #ifdef DEBUG printf( "stdout has been redirected to a file\n"); //for debugging use #endif } // signal when input is ready input_buffer_ready = CreateEvent(NULL, FALSE, FALSE, NULL); if (input_buffer_ready == NULL) { printf("Unable to create Event object\n"); EXIT(1); } } FILE *osaopen (char *name, char *mode) { return fopen (name, mode); } FILE *osbopen (char *name, char *mode) { char nmode[4]; strcpy (nmode, mode); strcat (nmode, "b"); return (fopen (name, nmode)); } int osclose (FILE *fp) { return (fclose (fp)); } int osaputc (int ch, FILE *fp) { return (putc (ch, fp)); } int osbputc (int ch, FILE *fp) { return (putc (ch, fp)); } void osoutflush(FILE *fp) { fflush(fp); } /* osagetc - get a character from an ascii file */ int osagetc(fp) FILE *fp; { return (getc(fp)); } extern int abort_flag; extern int redirect_flag; //Added by Ning Hu Apr.2001 int ostgetc (void) { int c; NEED_INPUT; while (!buffer_eof && (input_buffer_tail == input_buffer_head)) { oscheck(); WaitForSingleObject(input_buffer_ready, INFINITE); } if (buffer_eof) c = EOF; else { c = input_buffer[input_buffer_tail]; input_buffer_tail = (input_buffer_tail + 1) & input_buffer_mask; } if (c == '\025') { // control-u xlcleanup(); } else if (c == '\020') { // control-p xlcontinue(); } else if (c == '\024') { // control-t xinfo(); } return c; } void ostputc (int ch) { // macputc (ch); putchar(ch); // console if (tfp) osaputc (ch, tfp); } void ostoutflush() { if (tfp) fflush(tfp); fflush(stdout); } void osflush (void) { lineptr = linebuf; numChars = 0; lposition = 0; } void oscheck (void) { MSG lpMsg; #if OSC if (nosc_enabled) nosc_poll(); #endif // check_aborted(); -- call to userio.c superceded by code here in winstuff.c // printf("Current Thread: %d\n", GetCurrentThreadId()); //for debugging use // look for Windows messages from NyqIDE (a Delphi program) if ((redirect_flag) && (PeekMessage(&lpMsg, NULL, 0, 0, PM_REMOVE)!=0)) { if (lpMsg.message == WM_CHAR) { switch (lpMsg.wParam) { case ABORT_CHAR: abort_flag = ABORT_LEVEL; break; case BREAK_CHAR: // for nyquist, defined to be 2 case 7: // NyqIDE sends 7 (BEL) as break character abort_flag = BREAK_LEVEL; break; } // printf("Get message: %d %d %d\n", lpMsg.wParam, BREAK_CHAR, abort_flag); //for debugging use } } if (abort_flag == ABORT_LEVEL) { abort_flag = 0; osflush(); xltoplevel(); } else if (abort_flag == BREAK_LEVEL) { abort_flag = 0; osflush(); xlbreak("BREAK", s_unbound); } } //Update end void oserror (char *msg) { char line[100], *p; sprintf (line,"error: %s\n",msg); for (p = line; *p != '\0'; ++p) ostputc (*p); } void osfinish(void) { portaudio_exit(); /* dispose of everything... */ // if (linebuf) DisposPtr (linebuf); // MacWrapUp (); // ExitToShell (); } int renamebackup (char *filename) { return 0; } static WIN32_FIND_DATA FindFileData; static HANDLE hFind = INVALID_HANDLE_VALUE; #define OSDIR_LIST_READY 0 #define OSDIR_LIST_STARTED 1 #define OSDIR_LIST_DONE 2 static int osdir_list_status = OSDIR_LIST_READY; #define OSDIR_MAX_PATH 256 static char osdir_path[OSDIR_MAX_PATH]; // osdir_list_start -- prepare to list a directory int osdir_list_start(char *path) { if (strlen(path) >= OSDIR_MAX_PATH - 2) { xlcerror("LISTDIR path too big", "return nil", NULL); return FALSE; } strcpy(osdir_path, path); strcat(osdir_path, "/*"); // make a pattern to match all files if (osdir_list_status != OSDIR_LIST_READY) { osdir_list_finish(); // close previously interrupted listing } hFind = FindFirstFile(osdir_path, &FindFileData); // get the "." if (hFind == INVALID_HANDLE_VALUE) return FALSE; if (FindNextFile(hFind, &FindFileData) == 0) return FALSE; // get the ".." osdir_list_status = OSDIR_LIST_STARTED; return TRUE; } char *osdir_list_next() { if (FindNextFile(hFind, &FindFileData) == 0) { osdir_list_status = OSDIR_LIST_DONE; return NULL; } return FindFileData.cFileName; } void osdir_list_finish() { if (osdir_list_status != OSDIR_LIST_READY) { FindClose(hFind); } osdir_list_status = OSDIR_LIST_READY; } /* xechoenabled -- set/clear echo_enabled flag (unix only) */ LVAL xechoenabled() { int flag = (xlgetarg() != NULL); xllastarg(); // echo_enabled = flag; -- do nothing in Windows return NULL; } nyquist-3.05/sys/win/msvc/system.lsp0000644000175000000620000001003711466723256016627 0ustar stevestaff; machine.lsp -- machine/system-dependent definitions ; Windows ;; default behavior is to call SETUP-CONSOLE to get large white typescript ;; ;; set *setup-console* to nil in your personal init.lsp to override this behavior ;; (this may be necessary to work with emacs) ;; (if (not (boundp '*setup-console*)) (setf *setup-console* t)) (if *setup-console* (setup-console)) (if (not (boundp '*default-sf-format*)) (setf *default-sf-format* snd-head-Wave)) (if (not (boundp '*default-sound-file*)) (compute-default-sound-file)) (if (not (boundp '*default-sf-dir*)) (setf *default-sf-dir* "")) (if (not (boundp '*default-sf-mode*)) (setf *default-sf-mode* snd-mode-pcm)) (if (not (boundp '*default-sf-bits*)) (setf *default-sf-bits* 16)) (if (not (boundp '*default-plot-file*)) (setf *default-plot-file* "points.dat")) ;(if (not (boundp '*plotscript-file*)) ; (setf *plotscript-file* "sys/unix/rs6k/plotscript")) ; local definition for play (defmacro play (expr) `(s-save-autonorm ,expr NY:ALL *default-sound-file* :play *soundenable*)) (defun r () (s-save (s-read *default-sound-file*) NY:ALL "" :play t) ) ; PLAY-FILE -- play a file (defun play-file (name) (s-save (s-read name) NY:ALL "" :play t)) ; FULL-NAME-P -- test if file name is a full path or relative path ; ; (otherwise the *default-sf-dir* will be prepended ; (defun full-name-p (filename) (or (eq (char filename 0) #\\) (eq (char filename 0) #\/) (eq (char filename 0) #\.) (and (> (length filename) 2) (both-case-p (char filename 0)) (equal (char filename 1) #\:)))) ; RELATIVE-PATH-P -- test if filename or path is a relative path ; ; note that properly converting a Windows path from relative to ; absolute is complicated by paths like: E:MYFILE.LSP ; Nyquist assumes that if there is a drive letter, the path is ; absolute, e.g. E:\TMP\MYFILE.LSP and if there is no drive, ; the path is relative, e.g. you cannot have \TMP\MYFILE.LSP ; (defun relative-path-p (filename) (or (< (length filename) 2) (not (both-case-p (char filename 0))) (not (equal (char filename 1) #\:)))) (setf *file-separator* #\\) (defun ny:load-file () (load "*.*")) (defun ny:reload-file () (load "*")) ; save the standard function to write points to a file ; ;(setfn s-plot-points s-plot) ;(defun array-max-abs (points) ; (let ((m 0.0)) ; (dotimes (i (length points)) ; (setf m (max m (abs (aref points i))))) ; m)) ;(setf graph-width 600) ;(setf graph-height 220) ;(defun s-plot (snd &optional (n 600)) ; (show-graphics) ; (clear-graphics) ; (cond ((soundp snd) ; (s-plot-2 snd n (/ graph-height 2) graph-height)) ; (t ; (let ((gh (/ graph-height (length snd))) ; hs) ; (dotimes (i (length snd)) ; (setf hs (s-plot-2 (aref snd i) n (+ (/ gh 2) (* i gh)) gh hs))))))) ; ; ;(defun s-plot-2 (snd n y-offset graph-height horizontal-scale) ; (prog ((points (snd-samples snd n)) ; maxpoint horizontal-scale vertical-scale) ; (setf maxpoint (array-max-abs points)) ; (moveto 0 y-offset) ; (lineto graph-width y-offset) ; (moveto 0 y-offset) ; (cond ((null horizontal-scale) ; (setf horizontal-scale (/ (float graph-width) (length points))))) ; (setf vertical-scale (- (/ (float graph-height) 2 maxpoint))) ; (dotimes (i (length points)) ; (lineto (truncate (* horizontal-scale i)) ; (+ y-offset (truncate (* vertical-scale (aref points i)))))) ; (format t "X Axis: ~A to ~A (seconds)\n" (snd-t0 snd) (/ (length points) (snd-srate snd))) ; (format t "Y Axis: ~A to ~A\n" (- maxpoint) maxpoint) ; (format t "~A samples plotted.\n" (length points)) ; (return horizontal-scale) ; )) ; ; S-EDIT - run the audio editor on a sound ; ;(defmacro s-edit (&optional expr) ; `(prog () ; (if ,expr (s-save ,expr 1000000000 *default-sound-file*)) ; (system (format nil "audio_editor ~A &" ; (soundfilename *default-sound-file*))))) nyquist-3.05/sys/win/wingui/0002755000175000000620000000000011537433131015103 5ustar stevestaffnyquist-3.05/sys/win/wingui/resource.h0000644000175000000620000000122110144436365017102 0ustar stevestaff//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by winmain.rc // #define IDM_ABOUT 100 #define IDI_NYCON 101 #define ID_FILE_LOAD 101 #define ID_FILE_RELOAD 102 #define ID_FILE_EXIT 103 #define IDC_STATIC -1 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 104 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif nyquist-3.05/sys/win/wingui/longque.cpp0000644000175000000620000000071110144436365017263 0ustar stevestaff#include "stddef.h" #include "cppext.h" #include "longque.h" #include "stdlib.h" void longque::init(int size) { head = 0; tail = 0; count = 0; max = size; buff = (long *) malloc(sizeof(long) * size); } void longque::finish() { free(buff); } //1 producer-consumer safe long longque::remove() { long l; if (count <= 0) return 0; count--; l = buff[head++]; if (head == max) head = 0; return l; } nyquist-3.05/sys/win/wingui/xlispfns.c0000644000175000000620000000022610144436365017120 0ustar stevestaff#include "xlisp.h" #include "xlispfns.h" void run_xlisp() { xlisp_main_init(0,NULL); xlisp_main(); /* clean up */ xlisp_wrapup(); } nyquist-3.05/sys/win/wingui/cppext.h0000644000175000000620000000156010144436365016564 0ustar stevestaff#pragma warning( disable: 4237 ) // eub: temporary kludge // RBD -- this will define true, false, bool #include "yvals.h" //these preprocessor checks seem to get rid of compiler // error (redecl boolean) // typedef int bool; //#ifndef TRUE #define TRUE 1 #define FALSE 0 //#endif #define EOS '\000' // now defined by yvals.h: //#define true 1 //#define false 0 #define MALLOC ::malloc // note -- these macros are not consistently used #define FREE ::free void *MEMGET(long n); void *MEMFREE(void *data, long n); #define STREQ(a, b) (strcmp((a), (b)) == 0) typedef unsigned long uint32; typedef long int32; typedef unsigned short uint16; typedef short int16; typedef unsigned char uint8; //istvan 082197 // RBD commented out the following, instead, we're including yvals.h, // a microsoft-dependent file // #ifndef bool // typedef unsigned char bool; // #endif nyquist-3.05/sys/win/wingui/textio.cpp0000644000175000000620000001312210144436365017125 0ustar stevestaff// textio.cpp -- handles text input and output to edit control /* Overview of character input: ostgetc is called to get characters from stdin for XLisp ostgetc gets characters using ggetchar() and performs line editing ggetchar gets characters using wait_ascii() wait_ascii() get characters from typein:queue; it calls process_win_events if there are no characters, and it returns ABORT_CHAR or BREAK_CHAR if abort_flag is set characters get into typein::queue when the key handler is called get_ascii is similar to wait_ascii, but it doesn't wait: it just checks for input with process_win_events and returns a character if there is one, otherwise, it returns false */ #include #include #include #include #include "cppext.h" #include "longque.h" #include "textio.h" #include "typein.h" #include "button.h" #include "slider.h" #include "winmain.h" #include "assert.h" extern "C" { #include "xlisp.h" } #define GPRINTF_MESSAGE_LEN 500 //istvanmerge //int abort_flag = 0; longque typein::queue; void typein::init() { queue.init(100); } void typein::finish() { queue.finish(); } void typein::handler(char *inp) { if (!queue.fullp()) { if (*inp == ABORT_CHAR) { abort_flag = ABORT_LEVEL; free(inp); } else if (!abort_flag && *inp == BREAK_CHAR) { abort_flag = BREAK_LEVEL; free(inp); } else if (!abort_flag && *inp == INFO_CHAR) { xinfo(); free(inp); } else queue.insert((long) inp); } } extern char *next_ascii; int get_ascii(char *c) { check_aborted(); /* input buffer check */ if (!next_ascii && typein::queue.emptyp()) return false; *c = wait_ascii(); return true; // recurse with new string } /* check_aborted -- see if any characters are available, check for ctrl C */ int check_aborted() { process_win_events(USE_PEEK); /* handle input messages, if ^C, handler will set abort flag */ return abort_flag; } /* define with va_alist and use vsprintf to get temp */ void gprintf(long where, char *format, ...) { char temp[GPRINTF_MESSAGE_LEN]; va_list pvar; va_start(pvar, format); _vsnprintf(temp, GPRINTF_MESSAGE_LEN, format, pvar); va_end(pvar); switch((long) where) { case GTRANS: break; case GERROR: break; case GFATAL: edit_append("FATAL: "); edit_append(temp); break; case GDEBUG: edit_append("DEBUG: "); edit_append(temp); break; default: edit_append("UNKNOWN: "); edit_append(temp); break; } edit_append(temp); } void nyquist_printf(char *format, ...) { char temp[GPRINTF_MESSAGE_LEN]; va_list pvar; va_start(pvar, format); _vsnprintf(temp, GPRINTF_MESSAGE_LEN, format, pvar); va_end(pvar); edit_append(temp); } /************************************************************************** * gputchar * General putchar **************************************************************************/ void gputchar(int c) { char tmp[4]; tmp[0] = c; tmp[1] = 0; edit_append(tmp); } /************************************************************************** * ggetchar * General getchar **************************************************************************/ int ggetchar() { return wait_ascii(); } /************************************************************************** * ggets * General gets **************************************************************************/ char *ggets(char *str) { char *s = str; int c; do { c = ggetchar(); if (c == '\b' /* backspace */) { if (s != str) { gputchar('\b'); gputchar((int)' '); gputchar('\b'); s--; } else { gputchar((int)0x07); } } else *s++ = (char) c; } while (c != (int) '\n' && !abort_flag); *(s-1) = EOS; if (abort_flag) *str = EOS; return str; } /**************************************************************************** * askbool * Inputs: * char *prompt: string to prompt for user input * int deflt: true or false default * Returns: * boolean: true or false as entered by user * Effect: * prompts user for yes or no input, returns result ****************************************************************************/ int askbool(char *prompt, int deflt) { #define undefined -1 char defchar; /* the default answer */ char c; /* user input */ char in_string[100]; int result = -1; /* the result: -1 = undefined, 0 = false, 1 = true */ if (deflt) defchar = 'y'; else defchar = 'n'; while (result == undefined) { gprintf(GTRANS, "%s? [%c]: ", prompt, defchar); ggets(in_string); c = in_string[0]; if (islower(c)) c = toupper(c); if (c == 'Y') result = true; else if (c == 'N') result = false; else if (c == EOS) result = deflt; else if (abort_flag) result = deflt; /* space before Please to separate from user's type-in: */ else gprintf(GTRANS, " Please type Y or N.\n"); } if (abort_flag == BREAK_LEVEL) { abort_flag = 0; result = deflt; gprintf(GTRANS, "\n"); } return result; } void io_init() { } nyquist-3.05/sys/win/wingui/xlispfns.h0000644000175000000620000000012710144436365017125 0ustar stevestaff#ifdef __cplusplus extern "C" { #endif void run_xlisp(); #ifdef __cplusplus } #endif nyquist-3.05/sys/win/wingui/button.h0000644000175000000620000000004410144436365016570 0ustar stevestaff// button.h -- simple slider input nyquist-3.05/sys/win/wingui/nycon.ico0000644000175000000620000000137610144436365016737 0ustar stevestaff ( @ 0 ; ;;  0 0 ; 0  0 ;    3 0 ;0 0  0 0;00 ;00 0 0 0;0;0  ; 3 nyquist-3.05/sys/win/wingui/typein.h0000644000175000000620000000022310144436365016564 0ustar stevestaffclass typein { public: static longque queue; static void init(void); static void finish(void); static void handler(char *inp); }; nyquist-3.05/sys/win/wingui/longque.h0000644000175000000620000000071710144436365016736 0ustar stevestaffclass longque { public: void init(int size); void finish(); //1 producer-consumer safe void insert(long l) { buff[tail] = l; count++; tail++; if (tail == max) tail = 0; } long remove(); bool fullp() { return count >= max; } bool emptyp() { return count <= 0; } protected: int max; long *buff; int head; int tail; int count; }; nyquist-3.05/sys/win/wingui/slider.h0000644000175000000620000000020510144436365016536 0ustar stevestaff// slider.h -- simple slider input #define NUMSLIDERS 9 extern HWND sliders[NUMSLIDERS]; void set_slider_pos(HWND hwnd, int ival); nyquist-3.05/sys/win/wingui/winguistuff.c0000644000175000000620000002027411466723256017637 0ustar stevestaff/* winstuff.c - windows interface routines for xlisp */ /* Written by Chris Tchou. */ /* This file contains the stuff that the other xlisp files call directly. */ #include "windows.h" #include //#include /* for Random */ #include /* for DisposPtr */ #include //#include /* for ExitToShell */ #include "xlisp.h" #include "textio.h" #if OSC #include "sliders.h" /* define sliders */ #include "sound.h" /* define nosc_enabled */ #endif const char os_pathchar = '\\'; const char os_sepchar = ','; /* externals */ extern FILE *tfp; /* transcript file pointer */ extern int cursorPos; extern char *macgets (void); #define LBSIZE 200 /* local variables */ static char lbuf[LBSIZE]; static int lpos[LBSIZE]; static int lindex; static int lcount = 0; static int lposition; static int line_edit = TRUE; //int isascii (char c) { return 1; } /* every char is an ascii char, isn't it? */ void osinit (char *banner) { // int i; char version[] = "\nWindows console interface by Roger Dannenberg.\n"; // InitMac (); /* initialize the mac interface routines */ // lposition = 0; /* initialize the line editor */ // for (i = 0; banner[i] != '\0'; i++) macputc (banner[i]); // for (i = 0; version[i] != '\0'; i++) macputc (version[i]); nyquist_printf(banner); nyquist_printf(version); } FILE *osaopen (char *name, char *mode) { return fopen (name, mode); } FILE *osbopen (char *name, char *mode) { char nmode[4]; strcpy (nmode, mode); strcat (nmode, "b"); return (fopen (name, nmode)); } int osclose (FILE *fp) { return (fclose (fp)); } int osaputc (int ch, FILE *fp) { return (putc (ch, fp)); } int osbputc (int ch, FILE *fp) { return (putc (ch, fp)); } void osoutflush(FILE *fp) { fflush(fp); } /* osagetc - get a character from an ascii file */ int osagetc(fp) FILE *fp; { return (getc(fp)); } extern int abort_flag; #define OLDGETC #ifdef OLDGETC int ostgetc (void) { /* int i; if (numChars <= 0) { /* get some more */ /* if (linebuf) DisposPtr (linebuf); linebuf = macgets (); i = 0; while (linebuf[i] != '\0') i++; numChars = i; if (tfp) for (i = 0; i < numChars; i++) osaputc (linebuf[i], tfp); lineptr = linebuf; } numChars--; if (*lineptr == '\r') { lineptr++; return '\n'; } else return (*lineptr++);*/ int ch = ggetchar(); oscheck(); /* in case user typed ^C */ if (ch == BREAK_CHAR && abort_flag == BREAK_LEVEL) { abort_flag = 0; } return ch; } #else void end_of_line_edit() { line_edit = FALSE; if (tfp) { for (lindex = 0; lindex < lcount; ++lindex) osaputc(lbuf[lindex], tfp); } lindex = 0; } int ostgetc() { /* * NOTE: lbuf[] accumulates characters as they are typed * lpos[] is the column position of the characters * lcount is the number of characters in lbuf * lposition is current position * lindex is index of next char to output * line_edit is true iff we're inputing characters * */ int ch; while (line_edit) { ch = ggetchar(); oscheck(); /* in case user typed ^C */ if (ch == BREAK_CHAR && abort_flag == BREAK_LEVEL) { abort_flag = 0; } /* assume for now we should add the character */ lbuf[lcount] = ch; lpos[lcount] = lposition; lcount++; lposition++; /* now do all the special character processing */ switch (ch) { case '\n': lposition = 0; end_of_line_edit(); gputchar('\r'); gputchar(ch); break; /* delete key generates: 1b, 5b, 33, 7E which is: ESC, [, 3, ~ */ case '\010': /* backspace */ case '\177': /* delete */ lcount--; /* take out backspace or delete char */ lposition--; if (lcount) { lcount--; while (lposition > lpos[lcount]) { gputchar('\010'); gputchar(' '); gputchar('\010'); lposition--; } } break; case '\025': /* control-u */ lcount--; lposition--; if (lcount) { while (lposition > lpos[0]) { gputchar('\010'); gputchar(' '); gputchar('\010'); lposition--; } lcount = 0; } break; /* note that control-z never reaches here */ case '\003': /* control-c */ xltoplevel(); lcount = 0; break; case '\007': /* control-g */ xlcleanup(); lcount = 0; break; case '\020': /* control-p */ xlcontinue(); lcount = 0; break; case '\002': ostputc('\n'); /* control-b */ xlbreak("BREAK",s_unbound); break; case '\024': /* control-t */ xinfo(); lcount = 0; break; case '\t': /* TAB */ lposition--; /* undo the increment above */ do { lposition++; gputchar(' '); } while (lposition & 7); break; default: gputchar(ch); break; } } if (lindex + 1 >= lcount) { lcount = 0; line_edit = TRUE; } ch = lbuf[lindex++]; /* printf("[%c]", ch); */ fflush(stdout); return ch; } #endif void ostputc (int ch) { // macputc (ch); gputchar(ch); // console if (tfp) osaputc (ch, tfp); } void ostoutflush() { if (tfp) fflush(tfp); /* since ostputc calls gputchar which just calls putchar, I'm going to flush stdout rather than extending the "g" abstraction with a gflush() call. -RBD */ fflush(stdout); } void osflush (void) { lindex = lcount = lposition = 0; line_edit = TRUE; } extern int abort_flag; void oscheck (void) { #if OSC if (nosc_enabled) nosc_poll(); #endif check_aborted(); if (abort_flag == ABORT_LEVEL) { abort_flag = 0; osflush(); xltoplevel(); } else if (abort_flag == BREAK_LEVEL) { abort_flag = 0; osflush(); xlbreak("BREAK",s_unbound); } } void oserror (char *msg) { char line[100], *p; sprintf (line,"error: %s\n",msg); for (p = line; *p != '\0'; ++p) ostputc (*p); } void osfinish (void) { portaudio_exit(); /* dispose of everything... */ // if (linebuf) DisposPtr (linebuf); // MacWrapUp (); // ExitToShell (); } int renamebackup (char *filename) { return 0; } static WIN32_FIND_DATA FindFileData; static HANDLE hFind = INVALID_HANDLE_VALUE; #define OSDIR_LIST_READY 0 #define OSDIR_LIST_STARTED 1 #define OSDIR_LIST_DONE 2 static osdir_list_status = OSDIR_LIST_READY; #define OSDIR_MAX_PATH 256 static char osdir_path[OSDIR_MAX_PATH]; // osdir_list_start -- prepare to list a directory int osdir_list_start(char *path) { if (strlen(path) >= OSDIR_MAX_PATH - 2) { xlcerror("LISTDIR path too big", "return nil", NULL); return FALSE; } strcpy(osdir_path, path); strcat(osdir_path, "/*"); // make a pattern to match all files if (osdir_list_status != OSDIR_LIST_READY) { osdir_list_finish(); // close previously interrupted listing } hFind = FindFirstFile(osdir_path, &FindFileData); // get the "." if (hFind == INVALID_HANDLE_VALUE) return FALSE; if (FindNextFile(hFind, &FindFileData) == 0) return FALSE; // get the ".." osdir_list_status = OSDIR_LIST_STARTED; return TRUE; } char *osdir_list_next() { if (FindNextFile(hFind, &FindFileData) == 0) { osdir_list_status = OSDIR_LIST_DONE; return NULL; } return FindFileData.cFileName; } void osdir_list_finish() { if (osdir_list_status != OSDIR_LIST_READY) { FindClose(hFind); } osdir_list_status = OSDIR_LIST_READY; } /* xechoenabled -- set/clear echo_enabled flag (unix only) */ LVAL xechoenabled() { int flag = (xlgetarg() != NULL); xllastarg(); // echo_enabled = flag; -- do nothing in Windows return NULL; } nyquist-3.05/sys/win/wingui/winmain2.h0000644000175000000620000000176210144436365017011 0ustar stevestaffextern int quit_flag; extern int waiting_flag; extern long start_time; // initial system time in ms extern long the_time; // current time - updated by periodic interrupt extern HWND hMainWindow; /* main window handle */ void edit_append(char *txt); void debugeventwait(); bool get_mouse(int &x, int &y); void wait_mouse(int &x, int &y); void pause(long ms); // parameters to process_win_events() #define USE_GET 0 #define USE_PEEK 1 void process_win_events(int method); #define CTRLEVENT(a, b) (((long) (a))<<16 | (b)) #define WM_USER_TIMEOUT (WM_USER + 0) #define WM_USER_TIMESHOW (WM_USER + 1) #define WM_USER_TIMESHOW1 (WM_USER + 2) #define WM_USER_MIDI_INPUT (WM_USER + 10) #define WM_USER_MIDISHOW (WM_USER + 11) #define WM_USER_MIDISHOW1 (WM_USER + 12) #define WM_USER_MIDI_IN_ERROR (WM_USER + 20) #define WM_USER_MIDI_OUT_ERROR (WM_USER + 21) #define TIMERCB 1 #define MIDIINCB 2 #define FROMTIMERCB(x) ((x) == TIMERCB) #define FROMMIDIINCB(x) ((x) == MIDIINCB) #define TEXT_WIN_HT 200 nyquist-3.05/sys/win/wingui/winmain.aps0000644000175000000620000000642010144436365017257 0ustar stevestaff -$HWB  C:\rbd\nyquist\sys\win\wingui\winmain.rc0MAINMENU0 &Filee&Load...f&ReloadgE&xit&Helpd&About Nyquist...H0ABOUTBOX0 bAbout NyquistMS Sans SerifPNyquist, a language for music compositionP and sound synthesis.PLVersion 2.16PT OKPBCopyright (c) 2001, by Roger B. DannenbergPhttp://www.cs.cmu.edu/~rbd/nyquistPO&e 4TEXTINCLUDE0 resource.hX4TEXTINCLUDE0 #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS 4TEXTINCLUDE0   0 ( @ 0 ; ;;  0 0 ; 0  0 ;    3 0 ;0 0  0 0;00 ;00 0 0 0;0;0  ; 3  e0  $HWB0 !!resource.hIDM_ABOUT100IDI_NYCON101ID_FILE_LOAD101ID_FILE_RELOAD102ID_FILE_EXIT103 IDC_STATIC-1 _APS_NEXT_RESOURCE_VALUE103_APS_NEXT_COMMAND_VALUE104_APS_NEXT_CONTROL_VALUE1000_APS_NEXT_SYMED_VALUE101!!z$HWB0  C:\rbd\nyquist\sys\win\wingui\resource.he nycon.ico?$HWB0 4MAINMENUID_FILE_LOADeID_FILE_RELOADfID_FILE_EXITgIDM_ABOUTd$5ABOUTBOXIDC_STATICIDC_STATICIDC_STATICIDOKIDC_STATICIDC_STATICIDC_STATIC$TEXTINCLUDE1$TEXTINCLUDE2$TEXTINCLUDE3$14101IDI_NYCONC:\rbd\nyquist\sys\win\wingui\winmain.rci$$$HWB0 -DHWB MAINMENU0 H\ABOUTBOX0  TEXTINCLUDE0 XTEXTINCLUDE0 TEXTINCLUDE0 0 e0 HWB0 z@ HWB0 ? HWB0 nyquist-3.05/sys/win/wingui/winmain.rc0000644000175000000620000000575310144436365017110 0ustar stevestaff//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Menu // MAINMENU MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Load...", ID_FILE_LOAD MENUITEM "&Reload", ID_FILE_RELOAD MENUITEM SEPARATOR MENUITEM "E&xit", ID_FILE_EXIT END POPUP "&Help" BEGIN MENUITEM "&About Nyquist...", IDM_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // ABOUTBOX DIALOG DISCARDABLE 22, 17, 177, 98 STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU CAPTION "About Nyquist" FONT 8, "MS Sans Serif" BEGIN CTEXT "Nyquist, a language for music composition",IDC_STATIC,0, 5,177,8 CTEXT " and sound synthesis.",IDC_STATIC,0,14,177,8 CTEXT "Version 2.16",IDC_STATIC,0,76,177,8 DEFPUSHBUTTON "OK",IDOK,145,84,32,14,WS_GROUP CTEXT "Copyright (c) 2001, by Roger B. Dannenberg",IDC_STATIC, 0,66,177,8 CTEXT "http://www.cs.cmu.edu/~rbd/nyquist",IDC_STATIC,0,26,177, 8 ICON IDI_NYCON,IDC_STATIC,79,38,21,20 END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_NYCON ICON DISCARDABLE "nycon.ico" #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED nyquist-3.05/sys/win/wingui/xlextstart.c0000644000175000000620000000002410144436365017470 0ustar stevestaff/* nothing to do */ nyquist-3.05/sys/win/wingui/winmain.h0000644000175000000620000000077210144436365016727 0ustar stevestaff#include "resource.h" #ifdef __cplusplus extern "C" { #endif BOOL InitApplication(HANDLE); BOOL InitInstance(HANDLE, int); long CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK About(HWND, unsigned, WORD, LONG); void RegisterWindow(HWND, WNDPROC); #define IDC_EDIT 300 #define IDC_EDIT_INPUT 301 #define IDC_BUTTON 400 #define IDC_SLIDER 500 #define NUMBUTTONS 11 // 7 buttons high: #define NUMBUTTONS_VERT 7 extern int abort_flag; #ifdef __cplusplus } #endif #include "winmain2.h" nyquist-3.05/sys/win/wingui/winmain.cpp0000644000175000000620000005710611466723256017273 0ustar stevestaff#include "windows.h" /* required for all Windows applications */ #include "cppext.h" #include "longque.h" #include "button.h" #include "slider.h" #include "winmain.h" /* specific to this program */ #include "stdlib.h" #include "string.h" #include "stdio.h" #include "textio.h" #include "mmsystem.h" #include #include // for Sleep() #include "stdio.h" #include "resource.h" #include "typein.h" #include "xlispfns.h" #include "winfun.h" //#define THUMBTRACK // tries to get continuous scrollbars with SB_THUMBTRACK messages. // doesn't work -- zone 1 doesn't seem to wake up until the button-up. //#include "saudio.h" //#define D if(0) HWND buttons[NUMBUTTONS]; HWND sliders[NUMSLIDERS]; HWND textinput; HWND textoutput; HFONT hfont; HWND alt_win; WNDPROC alt_proc; extern "C" { HINSTANCE hInst; /* current instance */ HWND hMainWindow; /* main window handle */ } /* HINSTANCE hInst; /* current instance */ /* HWND hMainWindow; /* main window handle */ int quit_value; // return value from WinMain int abort_flag = 0; // there's some state here: // when we get a message from the input queue, it is an entire // string. We save the string and a pointer to the next char // char *get_ascii_string = NULL; char *next_ascii = NULL; //asciiwait -- wait for ascii input char wait_ascii() { if (next_ascii && *next_ascii) { char c = *next_ascii++; if (c == '\r') c = '\n'; _RPT1(_CRT_WARN, "|%c|", c); return c; } if (get_ascii_string) { _RPT2(_CRT_WARN, "free get_ascii_string %x %s\n", get_ascii_string, get_ascii_string); free(get_ascii_string); get_ascii_string = NULL; next_ascii = NULL; } // no input, so look for Windows messages while (typein::queue.emptyp() && !abort_flag) { process_win_events(USE_GET); } if (abort_flag == ABORT_LEVEL) return ABORT_CHAR; if (abort_flag == BREAK_LEVEL) return BREAK_CHAR; get_ascii_string = (char *) typein::queue.remove(); _RPT2(_CRT_WARN, "removed %x: %s\n", get_ascii_string, get_ascii_string); edit_append(get_ascii_string); next_ascii = get_ascii_string; return wait_ascii(); } //process_win_events -- receive and handle windows by either: // USE_PEEK: non-blocking // USE_GET: blocks void process_win_events(int method) { MSG msg; edit_append(""); // flush the output if (method == USE_GET) { //blocks until at least a message arrives if (GetMessage(&msg, //msg stored here NULL, //receive ALL application messages NULL,NULL)) //no msg filtering { //standard windows loop TranslateMessage(&msg); //posts another msg if there is a virtual to WM_CHAR mapping DispatchMessage(&msg); //calls object's receive function } else { //is this ever entered??? quit_value = msg.wParam; abort_flag = ABORT_CHAR; exit(0); } } else { //default: process all messges that already exist (non-blocking) while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE | PM_NOYIELD)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } //STUFF TO PROVIDE CONSOLE------------------------------------------------- //terminate strings and strip out LF int lf2crlf(char *dest, char *src) { char *d = dest; while (*src) { if (*src == '\n') { *dest++ = '\r'; } *dest++ = *src++; } *dest = EOS; return dest - d; /* string length */ } #define EDIT_HIGH_WATER 10000 #define EDIT_LOW_WATER 9000 #define EABUFFMAX 110 static char eabuff[EABUFFMAX]; /* edit_append buffer */ static char eabuffx = 0; static void edit_append2(char *txt2); /* edit_append -- optimizes output by buffering * * call with empty string to flush buffer */ void edit_append(char *txt) { /* new algorithm to deal with long strings on input: * if input is longer than 50, insert a zero and * call recursively; then undo the zero and continue. */ char txt2[100]; while (strlen(txt) > 50) { char temp = txt[50]; txt[50] = 0; edit_append(txt); /* strlen(txt) == 50 */ txt = txt + 50; txt[0] = temp; } int len = lf2crlf(txt2, txt); if ((eabuffx + len + 1 > EABUFFMAX) || ((len == 0) && eabuffx)) { edit_append2(eabuff); eabuffx = 0; } strcpy(eabuff + eabuffx, txt2); eabuffx += len; } static void edit_append2(char *txt2) { int len; int lines; if (*txt2 == '\b') { // special case: erase last character long len = SendMessage(textoutput, WM_GETTEXTLENGTH, (WPARAM) 0, (LPARAM) 0); if (len > 0) { // select the last character: SendMessage(textoutput, EM_SETSEL, (WPARAM) len - 1, (LPARAM) -1); // delete the last character: SendMessage(textoutput, EM_REPLACESEL, (WPARAM) 0, (LPARAM) ((LPSTR) "")); } return; } // to put insertion point at the end, first select // everything ... //wparam is UINT ; lparam is LONG SendMessage(textoutput, EM_SETSEL, (WPARAM) 0, (LPARAM) -1); // then remove selection, leaving cursor at the end: SendMessage(textoutput, EM_SETSEL, (WPARAM) -1, (LPARAM) -1); // now, replacement actually appends to the buffer: SendMessage(textoutput, EM_REPLACESEL, (WPARAM) 0, (LPARAM) ((LPSTR) txt2)); // if the number of characters exceeds EDIT_HIGH_WATER, then // trim the number of characters to EDIT_LOW_WATER by deleting // all lines up to the one containing total-EDIT_LOW_WATER lines = (int) SendMessage(textoutput, EM_GETLINECOUNT, (WPARAM) 0, (LPARAM) 0); len = (int) SendMessage(textoutput, EM_LINEINDEX, (WPARAM)(lines - 1), (LPARAM) 0); len += (int) SendMessage(textoutput, EM_LINELENGTH, (WPARAM)(lines - 1), (LPARAM) 0); if (len > EDIT_HIGH_WATER) { //these SendMessages operate to completion lines = (int) SendMessage(textoutput, EM_LINEFROMCHAR, (WPARAM)(len - EDIT_LOW_WATER), (LPARAM) 0); len = (int) SendMessage(textoutput, EM_LINEINDEX, (WPARAM)(lines), (LPARAM) 0); SendMessage(textoutput, EM_SETSEL, (WPARAM) 0, (LPARAM)(len)); SendMessage(textoutput, EM_REPLACESEL, (WPARAM) 0, (LPARAM) ((LPSTR) "")); } } //THE STUFF REQUIRED BY WINDOWS APPLICATIONS---------------------------------- // we will subclass the textinput window with a window procedure that detects // the Enter key (hex 0x0d) and sets a flag. Then in the main window proc, // when an EN_CHANGE message is received, we will know the user typed Enter, // so we can transfer the text to XLISP. // // This would be a good place also to add editing characters to scroll through // previous entries. // WNDPROC DefaultEditWndProc = NULL; #define ENTER_KEY 0x0d bool enter_flag = false; long CALLBACK EditWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_CHAR) { if (wParam == ENTER_KEY) enter_flag = true; _RPT1(_CRT_WARN, "wm_char is %x\n", wParam); } return CallWindowProc(DefaultEditWndProc, hWnd, message, wParam, lParam); } //All applications need to register BOOL InitApplication(HINSTANCE hInstance /* current instance */) { WNDCLASS wc; /* Fill in window class structure with parameters that describe the */ /* main window. */ wc.style = NULL; /* Class style(s). */ wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */ /* windows of this class. */ wc.cbClsExtra = 0; /* No per-class extra data. */ wc.cbWndExtra = 0; /* No per-window extra data. */ wc.hInstance = hInstance; /* Application that owns the class. */ wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NYCON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MAINMENU"; /* Name of menu resource in .RC file. */ wc.lpszClassName = "CMTWClass"; /* Name used in call to CreateWindow. */ /* Register the window class and return success/failure code. */ return (RegisterClass(&wc)); } static char *button_names[NUMBUTTONS] = { "Load File", "Reload File", "Replay Sound", "Break", "Top", "Up", "Info", "F1", "F2", "F3", "F4" }; //each time this application is run, the following program must be run BOOL InitInstance( HINSTANCE hInstance, /* Current instance identifier. */ int nCmdShow) /* Param for first ShowWindow() call. */ { int i; RECT rect; LRESULT rslt; /* Save the instance handle in static variable, which will be used in */ /* many subsequent calls from this application to Windows. */ hInst = hInstance; /* Create a main window for this application instance. */ hMainWindow = CreateWindow( "CMTWClass", /* See RegisterClass() call. */ "Nyquist", /* Text for window title bar. */ WS_OVERLAPPEDWINDOW, /* Window style. */ CW_USEDEFAULT, /* Default horizontal position. */ CW_USEDEFAULT, /* Default vertical position. */ CW_USEDEFAULT, /* Default width. */ CW_USEDEFAULT, /* Default height. */ NULL, /* Overlapped windows have no parent. */ NULL, /* Use the window class menu. */ hInstance, /* This instance owns this window. */ NULL /* Pointer not needed. */ ); /* If window could not be created, return "failure" */ if (!hMainWindow) return (FALSE); GetClientRect(hMainWindow, (LPRECT) &rect); /* Make the window visible; update its client area; and return "success" */ const int button_y = 25; // size in pixels const int slider_x = 20; const int slider_gap = 1; const int input_height = 48; // how high is input type-in edit control int slider_xsum = slider_x * NUMSLIDERS; int button_ysum = button_y * NUMBUTTONS_VERT; ShowWindow(hMainWindow, nCmdShow); /* Show the window */ UpdateWindow(hMainWindow); /* Sends WM_PAINT message */ for (i = 0; i < NUMBUTTONS; i++) { int x = 0; int y = i * button_y; int width = slider_xsum; if (i > 2) { y = (3 + (i - 3) / 2) * button_y; width = width / 2; if ((i & 1) == 0) x = width; } buttons[i] = CreateWindow("Button", //lpszClassName button_names[i],//windowName BS_PUSHBUTTON | //Style: 1) PB WS_CHILD | // 2) must reside w/in parent WS_VISIBLE, // 3) initially visible x, y, width, button_y, hMainWindow, //owner window (HMENU)(IDC_BUTTON+i), //&buttonsH[i], //child window Id hInstance, //application instance NULL); //WM_CREATE argument //activate current window & display w/current size and position ShowWindow(buttons[i], SW_SHOW); //update (nonempty) client area via WM_PAINT UpdateWindow(buttons[i]); } for (i=0; i= IDC_BUTTON && wid < IDC_BUTTON + NUMBUTTONS) { SetFocus(textinput); /* get focus back */ type_this(button_msgs[wid - IDC_BUTTON]); } else if (wid == IDC_EDIT_INPUT) { if (code == EN_CHANGE) { if (enter_flag) { enter_flag = false; long len = SendMessage(hwndCtrl, WM_GETTEXTLENGTH, 0, 0); len++; // allow for terminating null character char *buffer = (char *) malloc(len); SendMessage(hwndCtrl, WM_GETTEXT, (WPARAM) len, (LPARAM) buffer); _RPT2(_CRT_WARN, "inserting %x: %s\n", buffer, buffer); typein::handler(buffer); SendMessage(hwndCtrl, WM_SETTEXT, (WPARAM) 0, (LPARAM) ""); } } } else if (wid == IDC_EDIT) { if (code == EN_CHANGE) { } else { } } else { /*Let Windows process it*/ printf("unhandled: message %d\n", message); return (DefWindowProc(hWnd, message, wParam, lParam)); } break; } case WM_DESTROY: //message: window being destroyed PostQuitMessage(0); break; #ifdef MOUSEBUTTON_INPUT case WM_LBUTTONDOWN: { //message: left mouse button pressed while cursor in client area //never used, need SetCaputure??? int /*???*/ xPos LOWORD(lParam); int /*???*/ yPos HIWORD(lParam); //int /*???*/ fwKeys; virtual keys not used!!! buffer[0] = '<'; _itoa(xPos,buffer+1,10/*radix*/); i = strlen(buffer); buffer[i++] = ','; _itoa(yPos,buffer+i,10/*radix*/); i = strlen(buffer); buffer[i++] = '>'; buffer[i] = 0; edit_append(buffer); break; #endif #ifdef DEBUGINPUT //WM_USER msg codes are from the callbacks------------------------- case WM_USER_TIMEOUT: { //dummy message just unblocks GetMessage break; } //remaining wMsg codes generated elsewhere------------------------------------ case WM_KILLFOCUS: { //message: this window's loosing focus, focus must be set to new window HWND newFocus = (HWND) wParam; if (newFocus == textoutput) { //why not also set buttons, sliders...??? SetFocus(hWnd); } break; } case WM_VSCROLL: { //message: control bar scroll I/O //where is window scroll bar handled??? //why is this not also a WM_COMMAND??? HWND hwndCtrl = (HWND) lParam; short int nPos = HIWORD(wParam); int code = LOWORD(wParam); int i; for (i = 0; i < NUMSLIDERS; i++) { if (sliders[i] == hwndCtrl) { int pos = GetScrollPos(hwndCtrl /*parent*/, SB_CTL /*control*/); switch (code) { case SB_LINEUP: pos--; break; case SB_LINEDOWN: pos++; break; case SB_PAGEUP: pos -= 10; break; case SB_PAGEDOWN: pos += 10; break; case SB_ENDSCROLL: break; //why not continue??? case SB_THUMBTRACK: #ifdef THUMBTRACK pos = nPos; break; #else continue; // no silly multiple messages #endif //break; case SB_THUMBPOSITION: #ifndef THUMBTRACK pos = nPos; #endif break; case SB_TOP: pos = 0; break; case SB_BOTTOM: pos = 127; break; default: continue; //avoid SetScrollPos } // SetScrollRange() set the range to 0-127, but clip just to make sure: if (pos < 0) pos = 0; if (pos > 127) pos = 127; if (code != SB_ENDSCROLL #ifdef THUMBTRACK && code != SB_THUMBTRACK #endif ) { //ctrlevents.insert(CTRLEVENT(IDC_SLIDER + i, 127 - pos)); } SetScrollPos(hwndCtrl /*parent*/, SB_CTL /*control sb*/, pos /*new position*/, TRUE /*redraw*/); break; } } break; } #endif default: //Pass on all unproccessed messages return (DefWindowProc(hWnd, message, wParam, lParam)); } return (NULL); //all messages currently return this... } /**************************************************************************** FUNCTION: About(HWND, unsigned, WORD, LONG) PURPOSE: Processes messages for "About" dialog box MESSAGES: WM_INITDIALOG - initialize dialog box WM_COMMAND - Input received COMMENTS: No initialization is needed for this particular dialog box, but TRUE must be returned to Windows. Wait for user to click on "Ok" button, then close the dialog box. ****************************************************************************/ extern "C" BOOL CALLBACK About( HWND hDlg, /* window handle of the dialog box */ unsigned message, /* type of message */ WORD wParam, /* message-specific information */ LONG lParam) { switch (message) { case WM_INITDIALOG: /* message: initialize dialog box */ return (TRUE); case WM_COMMAND: /* message: received a command */ if (wParam == IDOK /* "OK" box selected? */ || wParam == IDCANCEL) /* System menu close command? */ { EndDialog(hDlg, TRUE); /* Exits the dialog box */ return TRUE; } break; } return FALSE; /* Didn't process a message */ } /* Load File support */ extern "C" void RegisterWindow(HWND w, WNDPROC p) { alt_win = w; alt_proc = p; } nyquist-3.05/sys/win/wingui/textio.h0000644000175000000620000000142010144436365016570 0ustar stevestaff#define CR '\n' #define ABORT_CHAR 0x03 #define BREAK_CHAR 0x02 #define CLEANUP_CHAR 0x07 #define INFO_CHAR '\024' #define BREAK_LEVEL 1 #define ABORT_LEVEL 2 #ifdef __cplusplus extern "C" { #endif int ggetchar(void); void gprintf(long where, char *format, ...); void gputchar(int c); int get_ascii(char *c); char *ggets(char *str); int check_aborted(); int askbool(char *prompt, int deflt); char wait_ascii(); void io_init(); /* this is not entirely kosher: nyquist_printf is also declared in sound.h so that all C programs will see it. Perhaps it should go into cext.h, but I'm not sure I want to drag all that into here. */ void nyquist_printf(char *format, ...); #ifdef __cplusplus } #endif #define GTRANS 0 #define GERROR 1 #define GFATAL 2 #define GDEBUG 3 nyquist-3.05/test/0002755000175000000620000000000011537433126013151 5ustar stevestaffnyquist-3.05/test/audio.lsp0000644000175000000620000000026310144436365014772 0ustar stevestaff;; audio.lsp ;; ;; simple audio output debugging test ;; (defun test () (stretch (/ 3.0 44100) (control-srate-abs 44100.0 (ramp))))) (play (vector (test) (test))) (play (test)) nyquist-3.05/test/fft.lsp0000644000175000000620000001421010144436365014445 0ustar stevestaff;; this sample code is described in fft_tutorial.htm (setf fft1-class (send class :new '(sound length skip))) (send fft1-class :answer :next '() '( (snd-fft sound length skip nil))) (send fft1-class :answer :isnew '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp))) (defun make-fft1-iterator (sound length skip) (send fft1-class :new (snd-copy sound) length skip)) ;; create a 1-second sinusoid with points samples at cycles hz: (defun short-sine (points cycles) (control-srate-abs points (lfo cycles))) (defun fft-test () (let (fft-iter) ;; signal will have 4 cycles in 32 points: (setf fft-iter (make-fft1-iterator (short-sine 32 4) 32 32)) (display "fft-test" (send fft-iter :next)))) (defun ifft-test () (let (fft-iter ifft-snd) (setf fft-iter (make-fft1-iterator (short-sine 32 4) 32 32)) (setf ifft-snd (snd-ifft 0 32 fft-iter 32 NIL)) (display "fft-ifft" (snd-length ifft-snd 200)) (display "fft-ifft" (snd-samples ifft-snd 200)) )) ; Test fft-test and ifft-test on a cosine using this redefinition: ; ; (defun short-sine (points cycles) ; (control-srate-abs points (lfo cycles 1.0 *sine-table* 90.0))) (defun file-fft1 (filename frame-length skip) (make-fft1-iterator (s-read filename) frame-length skip)) (defun play-fft1 (iterator skip) (play (snd-ifft 0 *sound-srate* iterator skip NIL))) ;; a convenient sound file name (change this to one of your soundfiles): (setf sfn "D:\\brain\\outro\\soup.wav") (defun file-test () (play-fft1 (file-fft1 sfn 512 512) 512)) (setf fft-hp-class (send class :new '(source bins))) (send fft-hp-class :answer :next '() '( (let ((frame (send source :next))) (cond (frame (dotimes (i bins) (setf (aref frame i) 0.0)))) frame))) (send fft-hp-class :answer :isnew '(s b) '( (setf source s) (setf bins b))) (defun make-fft-hp (source bins) (send fft-hp-class :new source bins)) (defun hp-test () (play-fft1 (make-fft-hp (file-fft sfn 512 512) 11) 512)) (defun fm-tone (step mi1 mi2 mi3) (let ((hz (step-to-hz step))) (setf mi1 (* mi1 hz)) (setf mi2 (* mi2 hz)) (setf mi3 (* mi3 hz)) (fmosc c4 (partial step (control-srate-abs *sound-srate* (pwl 0 mi1 0.5 mi2 1 mi3 1)))))) (defun mod-snd () (fm-tone c3 5 7 5)) ;; adjust FM parameters here (setf fft-modulator-class (send class :new '(src1 src2))) (send fft-modulator-class :answer :isnew '(s1 s2) '( (setf src1 s1) (setf src2 s2))) (send fft-modulator-class :answer :next '() '( (let ((frame1 (send src1 :next)) (frame2 (send src2 :next)) n half_n) (cond ((and frame1 frame2) ; multiply frame2 by the amplitude coefficients of frame1 (setf (aref frame2 0) (* (aref frame2 0) (aref frame1 0))) ;; DC (setf n (- (length frame1) 1)) ; Subtracted 1 because we already took care of DC component (setf half_n (/ n 2)) ; integer divide (dotimes (i half_n) (let* ((i2 (+ i i 2)) (i2m1 (- i2 1)) (amp (sqrt (+ (* (aref frame1 i2m1) (aref frame1 i2m1)) (* (aref frame1 i2) (aref frame1 i2)))))) (setf (aref frame2 i2m1) (* (aref frame2 i2m1) amp)) (setf (aref frame2 i2) (* (aref frame2 i2) amp)))) (cond ((= n (+ half_n half_n 2)) ;; n is even -> nyquist component (setf (aref frame2 n) (* (aref frame2 n) (aref frame1 n))))) frame2) (t nil))))) (defun make-fft-modulator (src1 src2) (send fft-modulator-class :new src1 src2)) (defun mod-test () (let ((fs 512)) ;; frame size (play-fft1 (make-fft-modulator (make-fft1-iterator (mod-snd) fs fs) (file-fft1 sfn fs fs)) fs))) (defun raised-cosine () (scale 0.5 (sum (const 1) (lfo (/ 1.0 (get-duration 1)) 1 *sine-table* 270)))) (defun fft-window (frame-size) (control-srate-abs frame-size (raised-cosine))) (defun play-fft (iterator frame-size skip) (play (snd-ifft 0 *sound-srate* iterator skip (fft-window frame-size)))) (defun mod-test-w () (let ((fs 512)) ;; frame size (play-fft (make-fft-modulator (make-fft1-iterator (mod-snd) fs (/ fs 2)) (file-fft1 sfn fs (/ fs 2))) fs (/ fs 2)))) (setf fft-class (send class :new '(sound length skip window))) (send fft-class :answer :next '() '( (snd-fft sound length skip window))) (send fft-class :answer :isnew '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp) (setf window (fft-window len)) )) (defun make-fft-iterator (sound length skip) (send fft-class :new (snd-copy sound) length skip)) (defun file-fft (filename frame-length skip) (make-fft-iterator (s-read filename) frame-length skip)) (defun mod-test-ww () (let ((fs 512)) ;; frame size (play-fft (make-fft-modulator (make-fft-iterator (mod-snd) fs (/ fs 2)) (file-fft sfn fs (/ fs 2))) fs (/ fs 2)))) (defun fft-test-w () (let (fft-iter) ;; signal will have 4 cycles in 32 points: (setf fft-iter (make-fft-iterator (short-sine 32 4) 32 32)) (display "fft-test-w" (send fft-iter :next)))) (defun ifft-test-w () (let (fft-iter ifft-snd) ;; this will generate two frames rather than one as before, and ;; with a higher harmonic to help detect the window: (setf fft-iter (make-fft1-iterator (short-sine 64 8) 32 32)) ;; window the result: (setf ifft-snd (snd-ifft 0 32 fft-iter 24 (fft-window 32))) (display "fft-ifft" (snd-length ifft-snd 200)) (display "fft-ifft" (snd-samples ifft-snd 200)) ifft-snd )) (defun mod-snd-2 () (fm-tone d3 15 27 15)) ;; adjust FM parameters here (defun mod-test-wwst () (let ((fs 1024)) ;; frame size (play-fft (make-fft-modulator (file-fft sfn fs (/ fs 8)) (make-fft1-iterator (transpose 2 (mod-snd-2)) fs (/ fs 8))) fs (/ fs 2)))) ;; do analysis synthesis ;; (defun fft-ifft (sound) (play-fft (make-fft-iterator sound 1024 512) 1024 512)) nyquist-3.05/test/overwrite.lsp0000644000175000000620000001015511466723256015726 0ustar stevestaff;; overwrite test ;; 1) add sine to existing sine ;; (defun ow-test-1 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite1.wav" :format snd-head-wave :mode snd-mode-pcm :bits 16) (print "called s-save with overwrite1.wav") (s-add-to (scale 0.5 (osc bf4)) ny:all "overwrite1.wav") (print "called s-add-to with overwrite1.wav") (play-file "overwrite1.wav") ) ;; 2) add sine to existing sine, extend beyond previous duration ;; (defun ow-test-2 () (print "calling s-save with overwrite2.wav") (s-save (scale 0.5 (osc c4)) ny:all "overwrite2.wav" :format snd-head-wave :mode snd-mode-pcm :bits 16) (print "called s-save with overwrite2.wav") (s-add-to (scale 0.5 (osc bf4 2)) ny:all "overwrite2.wav") (play-file "overwrite2.wav") ) ;; 3) add sine to existing sine, end within existing sound (defun ow-test-3 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite3.wav" :format snd-head-wave :mode snd-mode-pcm :bits 16) (s-add-to (mult (pwl 0 1 0.5 1 0.51) 0.5 (osc bf4)) ny:all "overwrite3.wav" 0.25) (play-file "overwrite3.wav") ) ;; 4) add sine beyond previous duration (extend by adding zeros first) (defun ow-test-4 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite4.wav" :format snd-head-wave :mode snd-mode-pcm :bits 16) (s-add-to (s-rest 3) ny:all "overwrite4.wav") (s-add-to (mult (pwl 0 0.5 0.5 0.5 0.51) (osc bf4)) ny:all "overwrite4.wav" 2) (play-file "overwrite4.wav") ) ;; 5) (1) with offset, and extend beyond previous duration (defun ow-test-5 () (s-save (mult (pwl 0 0.5 0.99 0.5 1.0) (osc c4)) ny:all "overwrite5.wav" :format snd-head-wave :mode snd-mode-pcm :bits 16) (s-add-to (mult (pwl 0.01 0.5 0.99 0.5 1) (osc bf4)) ny:all "overwrite5.wav" 0.5) (play-file "overwrite5.wav") ) ;; 6) (1) with floats (defun ow-test-6 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite6.wav" :format snd-head-wave :mode snd-mode-float) (s-add-to (scale 0.5 (osc bf4)) ny:all "overwrite6.wav") (play-file "overwrite6.wav") ) ;; 7) (2) with floats ;; add sine to existing sine, extend beyond previous duration ;; (defun ow-test-7 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite7.wav" :format snd-head-wave :mode snd-mode-float) (s-add-to (scale 0.5 (osc bf4 2)) ny:all "overwrite7.wav") (play-file "overwrite7.wav") ) ;; 8) (3) with raw floats ;; add sine to existing sine, end within existing sound (defun ow-test-8() (s-save (scale 0.5 (osc c4)) ny:all "overwrite8.wav" :format snd-head-wave :mode snd-mode-float) (s-add-to (mult (pwl 0 1 0.5 1 0.51) 0.5 (osc bf4)) ny:all "overwrite8.wav" 0.25) (play-file "overwrite8.wav") ) ;; 9) (4) with floats ;; add sine beyond previous duration (extend by adding zeros first) (defun ow-test-9 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite9.wav" :format snd-head-wave :mode snd-mode-float) (s-add-to (s-rest 3) ny:all "overwrite9.wav") (s-add-to (mult (pwl 0 0.5 0.5 0.5 0.51) (osc bf4)) ny:all "overwrite9.wav" 2) (play-file "overwrite9.wav") ) ;; 10) (5) wtih floats ;; overwrite with offset, and extend beyond previous duration (defun ow-test-10 () (s-save (mult (pwl 0 0.5 0.99 0.5 1.0) (osc c4)) ny:all "overwrite10.wav" :format snd-head-wave :mode snd-mode-float) (s-add-to (mult (pwl 0.01 0.5 0.99 0.5 1) (osc bf4)) ny:all "overwrite10.wav" 0.5) (play-file "overwrite10.wav") ) ;; 11) overwrite to a raw file of floats (defun ow-test-11 () (s-save (scale 0.5 (osc c4)) ny:all "overwrite11.raw" :format snd-head-raw :mode snd-mode-float :bits 32) (print (snd-overwrite '(scale 0.5 (osc bf4 0.4)) ny:all "/tmp/overwrite11.raw" 0.3 SND-HEAD-RAW SND-MODE-FLOAT 32 0)) (display "ow-test-11" *rslt*) (play (s-read "overwrite11.raw" :format snd-head-raw :mode snd-mode-float :bits 32))) nyquist-3.05/test/temp2.gio0000644000175000000620000000031510144436365014676 0ustar stevestaff!msec V3 c4 U600 N600 d4 U600 N600 e4 U600 N600 Z3 N0 f4 U300 N300 V4 g4 U300 N300 ~10(15) N300 ~10(20) N300 ~10(30) N300 Y100 N300 Y200 N300 Y0 N300 Y128 N300 Y16 N300 O0 N150 O20 N150 O50 N150 c0 U2400 nyquist-3.05/test/save-float.lsp0000644000175000000620000000072011511415575015727 0ustar stevestaff;; save-float.lsp -- a test program to explore a bug report (print "loading save-float.lsp") (load "/Users/rbd/nyquist/sys/unix/osx/system.lsp") (autonorm-off) ; write file (s-save (mult (osc c4) 10) ny:all "/Users/rbd/tmp/deleteme.rawfloat" :mode snd-mode-float :bits 32 :format snd-head-raw :play nil) ; read file (play (mult 0.1 (s-read "/Users/rbd/tmp/deleteme.rawfloat" :mode snd-mode-float :bits 32 :format snd-head-raw :nchans 1))) nyquist-3.05/test/alpass.lsp0000644000175000000620000000424210144436365015155 0ustar stevestaff;; tests for alpass filters (autonorm-off) ;; create a sum of sine tones signal, every 3rd harmonic to get some bw (defun sine-src () (scale 0.1 (simrep (i 5) (let () ;(display "simrep" *warp*) (osc (hz-to-step (* (1+ i) (step-to-hz c4)))))))) (defun osc-src () (scale 0.5 (osc c4))) (defun s-rest-d () (let () ; (display "s-rest-d" *warp*) (setf *srest* (s-rest)))) ; (play (sine-src)) (defun source () (seq (stretch 2 (sine-src)) (s-rest-d))) ; (play (source)) ;(play (seq (source) (source) (source) (source))) ; play sound followed by alpassed sound with different parameters (defun test1 () (seq (source) (alpass (source) 0.05 100) (alpass (source) 0.5 100) (alpass (source) 0.05 1000) (alpass (source) 0.5 1000))) ;(play (test1)) (defun test2 () (seq (source) (alpass (source) 0.05 (pwlv 50 3 200) 50) (alpass (source) 0.5 (pwlv 50 3 200) 50) (alpass (source) 0.05 (pwlv 250 3 1000) 250) (alpass (source) 0.5 (pwlv 250 3 1000) 250))) ;(play (test2)) (defun test2b () (seq (source) (setf xxx (comb (source) (pwlv 0.02 3 0.1) 100)) (setf yyy (comb (source) (pwlv 0.2 3 1.0) 100)) (setf zzz (comb (setf www (source)) (setf vvv (pwlv 0.02 3 0.1)) 1000)) (alpass (source) (pwlv 0.2 3 1.0) 1000))) ;(play (test2b)) (defun test3 () (seq (source) (setf xxx (alpass (source) (pwlv 0.02 3 0.1) 100)) (setf yyy (alpass (source) (pwlv 0.2 3 1.0) 100)) (setf zzz (alpass (setf www (source)) (setf vvv (pwlv 0.02 3 0.1)) 1000)) (alpass (source) (pwlv 0.2 3 1.0) 1000))) ;(play (test3)) (defun test4 () (seq (source) (alpass (source) (pwlv 0.02 3 0.1) (pwlv 50 3 200) 50) (alpass (source) (pwlv 0.2 3 1.0) (pwlv 50 3 200) 50) (alpass (source) (pwlv 0.02 3 0.1) (pwlv 500 3 2000) 500) (alpass (source) (pwlv 0.2 3 1.0) (pwlv 500 3 2000) 500))) (play (test4)) (defun pulses () (scale 0.5 (stretch 3 (buzz 400 (hz-to-step 2) (pwl 1))))) ;(play (pulses)) (defun test4 () (comb (pulses) (pwlv 0.6 3 0.1) 1000)) ;(play (test4)) nyquist-3.05/test/stktest.lsp0000644000175000000620000000570210144436365015375 0ustar stevestaff;; stktest.lsp -- test the STK instruments, currently clarinet and saxophony (autonorm-off) ;; simple clarinet sound (defun clarinet-example-1 () (clarinet bf3 (clarinet-breath-env 1 0.2 0.1))) ;; clarinet sound with frequency sweep (glissando) (defun clarinet-example-2 () (clarinet-freq bf3 (clarinet-breath-env 3 0.2 0.1) (pwl 1.5 80 3 80 3))) ;; clarinet sound with change in breath pressure (defun clarinet-example-3 () (clarinet bf3 (prod (pwl 0 1 1.5 0.9 3 1 3) (clarinet-breath-env 3 0.2 0.1)))) ;; clarinet sound using initial frequency sweep and built-in vibrato effect (defun clarinet-example-4 () (clarinet-all bf3 (clarinet-breath-env 3 0.5 0.05) (pwl 0.3 80 3 80 3) 5.7 0.5 0 0)) ;; clarinet sound with increasing then decreasing reed stiffness (defun clarinet-example-5 () (clarinet-all bf3 (clarinet-breath-env 3 0.5 0.05) 0 0 0 (pwl 1.5 0.75 3) 0)) ;; clarinet sound with increasing noise, with vibrato (defun clarinet-example-6 () (clarinet-all bf3 (clarinet-breath-env 3 0.5 0.05) 0 5.7 0.5 0 (pwl 3 1 3))) (print "clarinet-example-1") (play (clarinet-example-1)) (print "clarinet-example-2") (play (clarinet-example-2)) (print "clarinet-example-3") (play (clarinet-example-3)) (print "clarinet-example-4") (play (clarinet-example-4)) (print "clarinet-example-5") (play (clarinet-example-5)) (print "clarinet-example-6") (play (clarinet-example-6)) (defun sax-example-1 () (scale 0.5 (timed-seq '( (0.0 1 (sax g3 (sax-breath-env 2 0.2 0.2 0.6))) (2.0 1 (sax-freq c4 (sax-breath-env 4 0.6 0.6) (scale 100 (mult (pwl 0 0.95 4 1.3 4))))) ))) ) (defun sax-example-2 () (let (fade stacenv genenv) (defun fade (dur env) (prod (pwl 0 0 0.005 1 (- dur 0.005) 1 dur 0 dur) env)) (defun stacenv (dur amp) (scale (* 0.8 amp) (fade (* 0.9 dur) (sax-breath-env (* 0.9 dur) 1.0 0.9)))) (defun genenv (dur amp) (scale amp (sax-breath-env dur 1.0 1.0 0.75))) (scale 0.5 (timed-seq '( (0.0 1 (sax-freq bf3 (mult (envbreaks 1 (list 0.125 0.25 0.375 0.5 0.625 0.75 0.875)) (genenv 1 1)) (freqenv 1 bf3 (list 0 bf3 0.125 af4 0.25 g4 0.375 d4 0.5 f4 0.625 ef4 0.75 d4 0.875 ef4)) )) (1.0 1 (sax-freq e4 (mult (envbreaks 1 (list 0.125 0.25 0.375 0.5 0.625 0.75 0.875)) (genenv 1 1)) (freqenv 1 e4 (list 0 e4 0.125 c4 0.25 a3 0.375 e3 0.5 fs3 0.625 e3 0.75 fs3 0.875 e4)) )) (2.0 1 (sax-freq d4 (mult (envbreaks 1 (list 0.125 0.25 0.375 0.5 0.625 0.75 0.875)) (genenv 1 1)) (freqenv 1 d4 (list 0 d4 0.125 c4 0.25 b3 0.375 a3 0.5 g3 0.625 a3 0.75 b3 0.875 d4)) )) (3.0 1 (sax-freq ef4 (mult (envbreaks 1 (list 0.125 0.25 0.375 0.5 0.625 0.75 0.875)) (genenv 1 1)) (freqenv 1 ef4 (list 0 ef4 0.125 cs4 0.25 b3 0.375 bf3 0.625 gf3 0.75 af3 0.875 bf4)) )) ) )) ) ) (print "sax-example-1") (play (sax-example-1)) (print "sax-example-2") (play (sax-example-2)) nyquist-3.05/test/test.gio0000644000175000000620000000000610144436365014623 0ustar stevestaffa b c nyquist-3.05/test/tp.lsp0000644000175000000620000000550010144436365014313 0ustar stevestaff;;; Single Carriar Trumpet Algorithm based on a design by Dexter Morrill ;;; Computer Music Journal, February 1997, pgs 46-52 ;;; ;;; Naming changes: (Morill's name = my name) ;;; u.g.1 = envelope p2 -> ignored p13 = *** ;;; u.g.2 = cf_deviation p3 -> ignored p14 = *** ;;; u.g.3 = vibrato p4 = freq (pitch) p15 = modIndex1 ;;; u.g.4 = fm_env p5 = peak_amp (scaled) p16 = modIndex2 ;;; u.g.5 = random p6 -> ignored p17 = *** ;;; u.g.6 = fmod p7 = amp_rise p18 = *** ;;; u.g.7 = main p8 = amp_decay p19 = fm_rise ;;; p9 = *** p20 = fm_decay ;;; p10 = cfd_rise p21 = *** ;;; p11 = cfd_decay p22 = *** ;;; p12 -> ignored p23 -> ignored ;;; NOTES: ;;; P9 has been completely ignored!!! ;;; Look at p13 and p14 (defun trumpet (pitch &key (peak_amp (/ 500.0 2048.0)) (amp_rise .02) (amp_decay .15) (cfd_rise .06) (cfd_decay .06) (modIndex1 3.523) (modIndex2 0.0) (vib_dev .33) (fm_rise .02) (fm_decay .01)) (let* ((freq (float (step-to-hz pitch))) (p4 freq) (p13 freq) (p14 1.0) (p18 (hz-to-step 7)) (p21 0.5) (p22 (/ freq 4)) ;; main envelope (envelope (mult peak_amp (env amp_rise 0 amp_decay 1 1 .9))) ; 1,1,.9 need to be parameters? ;; center frequency deviation (my_dur (local-to-global 1)) (cf_deviation (stretch-abs 1 (pwl 0 -1 cfd_rise .1 (+ cfd_rise cfd_decay) 0 my_dur 0))) (m1_f (sum p4 cf_deviation)) ;; vibrato generator (vibrato (mult (mult m1_f (* vib_dev .01)) (osc p18))) (n1 (sum (* p13 p14) cf_deviation)) ;; envelope for fmod ;;; WARNING: This generator needs to be scaled by 1/2048 ??? (fm_env (mult (sum (mult modIndex1 n1) (mult modIndex2 n1)) (env fm_rise 0 fm_decay 1 1 .9))) ;; random frequency modulation (random (mult (mult (sum m1_f vibrato) (* p21 .01)) (sound-srate-abs p22 (noise)))) ;; frequency modulation (fmod_pitch (hz-to-step (* p13 p14))) (fmod_mod (sum (sum cf_deviation vibrato) random)) (fmod_amp (sum (sum (sum fm_env (mult n1 modIndex2)) vibrato) random)) (fmod (mult fmod_amp (fmosc fmod_pitch fmod_mod))) ;; main generator (main_mod (sum(sum (sum cf_deviation vibrato) random) fmod)) (main (mult envelope (fmosc pitch main_mod)))) main)) nyquist-3.05/test/ifft.lsp0000644000175000000620000001076610144436365014632 0ustar stevestaff;; test code for ifft framework ; The interface to SND-IFFT is: ; (snd-ifft t0 sr iterator) ; where t0 is the starting time, ; sr is the sample rate, and ; iterator is an XLisp object ; the iterator object must return an array of samples when :next is sent ; or return NIL to end the sound ; The sound returned by SND-IFFT (for now) is simply the concatenation ; of all samples returned in arrays returned from :next. ; TEST IT.... ; first, make a class: (setf iter-class (send class :new '(count len))) ; now define some methods ; for this test, we'll return "count" arrays of length "len" and ; we'll fill the arrays with a ramp from -1 to +1 so that the final ; result will be a sawtooth wave (send iter-class :answer :set-count '(c) '((setf count c))) (send iter-class :answer :set-len '(l) '((setf len l))) (send iter-class :answer :next '() '( (format t "iter-class got :next\n") (cond ((<= count 0) nil) (t (setf count (- count 1)) (make-ramp-array len))))) (defun make-ramp-array (len) (let (ar) (setf ar (make-array len)) (dotimes (i len) (setf (aref ar i) (+ -1 (* i (/ 2.0 len))))) ar)) ; now try calling SND-IFFT with an object (setf iter (send iter-class :new)) (send iter :set-count 10) (send iter :set-len 20) (print "Select SPLIT SCREEN item in CONTROL menu on Macs for good screen layout") (defun ifft-test () ;(s-plot (snd-ifft 0.0 100 iter nil))) (play (snd-ifft 0.0 44100.0 iter 20 nil))) ;; fft code: make an object that returns ffts when called with :NEXT ;; (setf fft-class (send class :new '(sound length skip))) (send fft-class :answer :next '() '((snd-fft sound length skip nil))) ; there's a way to do this with new, but I forgot how... (send fft-class :answer :init '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp))) (defun make-fft-iterator (sound length skip) (let (iter) (setf iter (send fft-class :new)) ; make a copy because the snd-fft will modify the sound: (send iter :init (snd-copy sound) length skip) iter)) ;; print ffts of a short ramp: (defun fft-test () (let (fft-iter) (setf fft-iter (control-srate-abs 100 (make-fft-iterator (pwl 1 1 1 0) 32 32))) (dotimes (i 5) (print (list 'fft (send fft-iter :next)))))) ;; now try running the ffts through the ifft: (defun fft-ifft-test () (let (fft-iter ifft-snd) (setf fft-iter (control-srate-abs 100 (make-fft-iterator (pwl 1 1 1 0) 32 32))) (setf ifft-snd (snd-ifft 0 100 fft-iter)) (display "fft-ifft" (snd-length ifft-snd 200)) (display "fft-ifft" (snd-samples ifft-snd 200)) (s-plot ifft-snd))) ;(fft-ifft-test) (defun square (x) (* x x)) (defun amplitude-spectrum (spectrum) (let ((result (make-array (+ 1 (/ (length spectrum) 2))))) (setf (aref result 0) (aref spectrum 0)) (dotimes (i (/ (- (length spectrum) 1) 2)) (setf (aref result (1+ i)) (sqrt (+ (square (aref spectrum (+ 1 (* 2 i)))) (square (aref spectrum (+ 2 (* 2 i)))) )))) (cond ((evenp (length spectrum)) (setf (aref result (/ (length spectrum) 2)) (aref spectrum (- (length spectrum) 1))))) result)) ;; test fft on sinusoids ;; ;; length 32 ffts, lfo has period 16 ;; should show as 2nd harmonic ;; (defun sin-test () (let (fft-iter) (setf fft-iter (control-srate-abs 32 (make-fft-iterator (stretch 4 (lfo 2)) 32 32))) (dotimes (i 5) (print (list 'fft-sin-test-amplitude-spectrum (amplitude-spectrum (cadr (print (list 'sin-test-spectrum (send fft-iter :next)))))))))) (setf spectrum (vector 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)) (dotimes (i 32) (setf (aref spectrum i) (float (aref spectrum i)))) (setf sine-class (send class :new '(count len))) ; now define some methods ; for this test, we'll return "count" arrays of length "len" (send sine-class :answer :set-count '(c) '((setf count c))) (send sine-class :answer :set-len '(l) '((setf len l))) (send sine-class :answer :next '() '( (format t "sine-class got :next\n") (cond ((<= count 0) nil) (t (setf count (- count 1)) spectrum)))) (setf sin-iter (send sine-class :new)) (send sin-iter :set-count 10) (send sin-iter :set-len 20) (defun sin-gen-test () (play (snd-ifft 0.0 44100.0 sin-iter 20 nil))) ;;TODO: (sin-gen-test) should generate a sinusoid tone with a period of 16 samples nyquist-3.05/test/ms2.lsp0000644000175000000620000000044610144436365014375 0ustar stevestaff;This causes a memory allocate/free bug, possibly related to multiseq: (load "rbd") (load "alex") (play (seqrep (i 10) (scale 0.5 (ster (osc 46 0.5) (* i 0.1))))) (play (seqrep (i 10) (scale 0.5 (ster (osc 46 0.5) (* i 0.1))))) (play (seqrep (i 10) (scale 0.5 (ster (osc 46 0.5) (* i 0.1))))) nyquist-3.05/test/articulator1.txt0000644000175000000620000002401610144436365016326 0ustar stevestaff;--------------------------------------------------------------------------- ; Nyquist voice synthesis instrument by Eduardo Reck Miranda ; ; Implements a geometrical articulator for tongue position (h p) and ; lips rouding (r) ; ;--------------------------------------------------------------------------- ; Geometrical articulator: the following FORMx functions estimates the formant ; values from the positions of the three articulators p h and r, where: ; p = horizontal position of the tongue: 0.0 = front and 1.0 = back ; h = vertical position of the tongue: 0.0 = low and 1.0 = high ; r = rounding of the lips: 0.0 = spread -> 1.0 rounded ;--------------------------------------------------------------------------- ; FORM1: converts p-h-r articulators to first formant frequency ;--------------------------------------------------------------------------- (defmacro form1 (p h r) `(+ (* (+ (* (+ (- 392) (* 392 ,r)) (expt ,h 2)) (* (- 596 (* 668 ,r)) ,h) (+ (- 146) (* 166 ,r))) (expt ,p 2)) (* (+ (* (- 348 (* 348 ,r)) (expt ,h 2)) (* (+ (- 494) (* 606 ,r)) ,h) (- 141 (* 175 ,r))) ,p) (+ (* (- 340 (* 72 ,r)) (expt ,h 2)) (* (+ (- 796) (* 108 ,r)) ,h) (- 708 (* 38 ,r))) )) ;--------------------------------------------------------------------------- ; FORM2: converts p-h-r articulators to second formant frequency ;--------------------------------------------------------------------------- (defmacro form2 (p h r) `(+ (* (+ (* (+ (- 1200) (* 1208 ,r)) (expt ,h 2)) (* (- 1320 (* 1328 ,r)) ,h) (- 118 (* 158 ,r))) (expt ,p 2)) (* (+ (* (- 1864 (* 1488 ,r)) (expt ,h 2)) (* (+ (- 2644) (* 1510 ,r)) ,h) (+ (- 561) (* 221 ,r))) ,p) (+ (* (+ (- 670) (* 490 ,r)) (expt ,h 2)) (* (- 1355 (* 697 ,r)) ,h) (- 1517 (* 117 ,r))) )) ;--------------------------------------------------------------------------- ; FORM3: converts p-h-r articulators to third formant frequency ;--------------------------------------------------------------------------- (defmacro form3 (p h r) `(+ (* (+ (* (- 604 (* 604 ,r)) (expt ,h 2)) (* (- 1038 (* 1178 ,r)) ,h) (+ 246 (* 566 ,r))) (expt ,p 2)) (* (+ (* (+ (- 1150) (* 1262 ,r)) (expt ,h 2)) (* (+ (- 1443) (* 1313 ,r)) ,h) (- (- 317) (* 483 ,r))) ,p) (+ (* (- 1130 (* 836 ,r)) (expt ,h 2)) (* (+ (- 315) (* 44 ,r)) ,h) (- 2427 (* 127 ,r))) )) ;--------------------------------------------------------------------------- ; FORM4: converts p-h-r articulators to fourth formant frequency ;--------------------------------------------------------------------------- (defmacro form4 (p h r) `(+ (* (+ (* (+ (- 1120) (* 16 ,r)) (expt ,h 2)) (* (- 1696 (* 180 ,r)) ,h) (+ 500 (* 522 ,r))) (expt ,p 2)) (* (+ (* (+ (- 140) (* 240 ,r)) (expt ,h 2)) (* (+ (- 578) (* 214 ,r)) ,h) (- (- 692) (* 419 ,r))) ,p) (+ (* (- 1480 (* 602 ,r)) (expt ,h 2)) (* (+ (- 1220) (* 289 ,r)) ,h) (- 3678 (* 178 ,r))) )) ;--------------------------------------------------------------------------- ; ADSR-SMOOTH: a standard ADSR envelope ;--------------------------------------------------------------------------- (defun adsr-smooth (signal dur) (mult signal (env 0.1 0.2 0.5 1.0 0.8 0.4 dur))) ;--------------------------------------------------------------------------- ; VIBRATO: generates vibrato ; vib-rate = vibrato rate in Hz ; dur = duration in seconds ;--------------------------------------------------------------------------- (defun vibrato (vib-rate dur) (osc (hz-to-step vib-rate) dur)) ;--------------------------------------------------------------------------- ; PULSE-TABLE: build table for generating a pulse signal ; harm = number of harmonics ;--------------------------------------------------------------------------- (defun pulse-table (harm) (abs-env ;prevent any timewarping in the following (let ((table (build-harmonic 1 2048))) (cond ((> harm 1) ;sum remaining harmonics (setf harm (- harm 1)) (dotimes (i harm) (setf table (sum table (build-harmonic (1+ i) 2048)))))) table))) ;--------------------------------------------------------------------------- ; PULSE-WITH-VIBRATO: generate pulse with vibrato ; step = pitch in steps ; duration = duration in seconds ; vib-rate = vibrato rate in Hz ;--------------------------------------------------------------------------- (defun pulse-with-vibrato (step duration vib-rate) (let (harm freq) (setf freq (step-to-hz step)) (setf harm (truncate (/ 22050 (* 2 freq)))) (setf table (scale (/ 1.0 harm) (pulse-table harm))) (fmosc step (vibrato vib-rate duration) (list table (hz-to-step 1) t)))) ;--------------------------------------------------------------------------- ; VOICING-SOURCE: generate voicing source: pulse with vibrato + LPFs ; step = pitch in steps ; duration = duration in seconds ; vib-rate = vibrato rate in Hz ;--------------------------------------------------------------------------- (defun voicing-source (step duration vib-rate) (lp (lp (pulse-with-vibrato step duration vib-rate) (* 1.414 (* 2 (step-to-hz step)))) (* 1.414 (* 4 (step-to-hz step))))) ;--------------------------------------------------------------------------- ; NOISE-SOURCE: generate noise source: noise + offset oscillator + LPF ; step = pitch in steps ; duration = duration in seconds ; vib-rate = vibrato rate in Hz ;--------------------------------------------------------------------------- (defun noise-source (step duration vib-rate) (lp (sum (noise duration) (fmosc step (vibrato vib-rate duration))) 8000)) ;--------------------------------------------------------------------------- ; SOURCE: generate source signal: voicing + noise sources ; freq = fundamental frequency in Hz ; duration = duration in seconds ; vib-rate = vibrato rate in Hz ; voicing-scale = percentage of voicing in the resulting signal (0.0 -> 1.0) ; noise-scale = percentage of noise in the resulting signal (0.0 -> 1.0) ;--------------------------------------------------------------------------- (defun source (freq duration vib-rate voicing-scale noise-scale) (sum (scale voicing-scale (voicing-source (hz-to-step freq) duration vib-rate)) (scale noise-scale (noise-source (hz-to-step freq) duration vib-rate)))) ;--------------------------------------------------------------------------- ; MAKE-SPECTRUM: formant filters ; freq = fundamental frequency in Hz ; dur = duration in seconds ; vib-rate = vibrato rate in Hz ; v-scale = amplitude scaling for the voicing source ; n-scale = amplitude scaling for the noise source ; p = horizontal position of the tongue (0.0 = front -> 1.0 = back) ; h = vertical position of the tongue (0.0 = low -> 1.0 = high) ; r = rouding of the lips (0.0 = spread -> 1.0 = rounded) ;--------------------------------------------------------------------------- (defun make-spectrum (freq dur vib-rate v-scale n-scale p h r) (let ((src (source freq dur vib-rate v-scale n-scale))) (setf spectrum (sim (reson src (form1 p h r) 50 1) (reson (scale-db (- 10) src) (form2 p h r) 70 1) (reson (scale-db (- 14) src) (form3 p h r) 110 1) (reson (scale-db (- 20) src) (form4 p h r) 250 1))))) ;--------------------------------------------------------------------------- ; SYNTHESISE: the synthesise function ; Simplified version of the instrument used by the agents discussed in Chapter 6. ; f0 = pitch frequency ; w1 = amplitude of voicing source (min = 0.0 max = 1.0) ; w2 = amplitude of noise source (min = 0.0 max = 1.0) ; a = horizontal position of the tongue (0.0 = front -> 1.0 = back) ; b = vertical position of the tongue (0.0 = low -> 1.0 = high) ; c = rouding of the lips (0.0 = spread -> 1.0 = rounded) ; fm = vibrato rate (in Hz) ; h = duration in seconds ;--------------------------------------------------------------------------- (defun synthesise (f0 w1 w2 a b c fm h) (adsr-smooth (make-spectrum f0 h fm w1 w2 a b c) h)) ;=== The code for the instrument ends here === ;--------------------------------------------------------------------------- ; Test the SYNTHESISE function with different positions of the articulators ; ; Running steps: ; 1 - run Nyquist ; 2 - load "articulator.lsp" ; 3 - type (play (vowel-1)) to synthesise the first test, and so on ;--------------------------------------------------------------------------- (defun vowel-1 () (synthesise 220 1.0 0.005 0.0 0.0 0.0 5.6 1.0)) (defun vowel-2 () (synthesise 220 1.0 0.005 0.0 0.0 1.0 5.6 1.0)) (defun vowel-3 () (synthesise 220 1.0 0.005 0.5 0.0 0.0 5.6 1.0)) (defun vowel-4 () (synthesise 220 1.0 0.005 0.5 0.0 1.0 5.6 1.0)) (defun vowel-5 () (synthesise 220 1.0 0.005 1.0 0.0 0.0 5.6 1.0)) (defun vowel-6 () (synthesise 220 1.0 0.005 1.0 0.0 1.0 5.6 1.0)) (defun vowel-7 () (synthesise 220 1.0 0.005 0.0 0.5 0.0 5.6 1.0)) (defun vowel-8 () (synthesise 220 1.0 0.005 0.0 0.5 1.0 5.6 1.0)) (defun vowel-9 () (synthesise 220 1.0 0.005 0.5 0.5 0.0 5.6 1.0)) (defun vowel-10 () (synthesise 220 1.0 0.005 0.5 0.5 1.0 5.6 1.0)) (defun vowel-11 () (synthesise 220 1.0 0.005 1.0 0.5 0.0 5.6 1.0)) (defun vowel-12 () (synthesise 220 1.0 0.005 1.0 0.5 1.0 5.6 1.0)) (defun vowel-13 () (synthesise 220 1.0 0.005 0.0 1.0 0.0 5.6 1.0)) (defun vowel-14 () (synthesise 220 1.0 0.005 0.0 1.0 1.0 5.6 1.0)) (defun vowel-15 () (synthesise 220 1.0 0.005 0.5 1.0 0.0 5.6 1.0)) (defun vowel-16 () (synthesise 220 1.0 0.005 0.5 1.0 1.0 5.6 1.0)) (defun vowel-17 () (synthesise 220 1.0 0.005 1.0 1.0 0.0 5.6 1.0)) (defun vowel-18 () (synthesise 220 1.0 0.005 1.0 1.0 1.0 5.6 1.0)) ;; play everything (defun vowel-n (n) (funcall (intern (format nil "VOWEL-~A" n)))) (defun play-all-vowels () (autonorm-off) (dotimes (i 18) (play (scale 20 (vowel-n (1+ i))))) (autonorm-on)) ; (play-all-vowels) will play everything in sequence nyquist-3.05/test/fmfb-test.lsp0000644000175000000620000000041311466723256015563 0ustar stevestaff; SND-FMFB ARGS: t0 hz sr index dur (defun feedback-fm (pitch index d) (let ((hz (step-to-hz (+ pitch (get-transpose)))) (dur (get-duration d))) (snd-fmfb (local-to-global 0) hz *sound-srate* index dur))) (play (feedback-fm a4 1.1 1)) (exit) nyquist-3.05/test/alex.lsp0000644000175000000620000003151410144436365014625 0ustar stevestaff; SOUNDS (defun mkwave () (setf *s-table* (scale 0.5 (sim (scale 1 (build-harmonic 1.41 2048)) (scale 0.7 (build-harmonic 3.1 2048)) (scale 0.9 (build-harmonic 6.3 2048)) (scale 0.4 (build-harmonic 9.12 2048))))) (setf *s-table* (list *s-table* (hz-to-step 1) T))) (if (not (boundp '*s-table*)) (mkwave)) (defun mk-voc1-table() (if (not (boundp 'voc-snd1)) (setf voc-snd1 (s-read "./test/voc1.snd"))) (setf *voc-table1* (list voc-snd1 16 T))) (defun mod(dur) (mult (stretch dur (pwl 0 1000 .2 200 .5 8000 1 100 1)) (fmosc c4 (stretch dur (pwl 0 1 .5 3.25 1 .74 1))))) (defun mod2(dur) (mult (stretch dur (pwl 0 5000 0.6 3000 1 50 1)) (fmosc c4 (stretch dur (pwl 0 10 0.5 50 0.65 1060 0.75 200 0.8 8400 1 5 1))))) (defun envl(dur) (stretch dur (env 0.15 0.15 0.2 1 .6 .5 1))) (defun blurp(dur) (fmosc c3 (mult (osc 07 dur) (mod dur)))) (defun bleerp(&optional (dur 4)) (fmosc 02 (mult (fmosc 23 (stretch dur (pwl 0 15000 .3 5600 .8 1500 1 380 1))) (mod dur)))) (defun ther(freq amp &optional (vib 6)) (mult (sum amp (lfo vib)) (fmosc 0 (sum freq (lfo (* vib 0.7)))) )) (defun fizz(scl &optional (dur 2) (pch 40)) (scale scl ( mult (stretch dur (env 0.02 0.08 0.01 1 0.6 0.8 1)) (fmosc pch (mod2 dur)) ( at 0.1 ( mult (envl dur) (fmosc (* pch 1.414) (mod2 dur)))) ( at 0.2 (mult (envl dur) (fmosc (* pch 0.57) (mod2 dur)))) ))) (defun warble(&optional (dur 1) (pch 60)) (sum (mult (stretch dur (env 0.017 0.1 0.004 1 0.7 0.8 1)) (amosc pch (fmosc (hz-to-step 8) (stretch dur (pwl 0 4 0.2 -4 0.56 9 0.7 0 1 -8 1)))) (mult (stretch (* dur 0.96) (env 0.2 0.09 0.07 0.92 0.8 0.6 1)) (amosc pch (fmosc (* pch 1.414) (stretch dur (pwl 0.2 80 0.5 4 0.9 1120 1 200 1)) ) ) )) )) (defun bell(dur pch) (mult (stretch dur (env 0.01 0.1 0.2 1 0.6 0.24 1)) (fmosc pch (sum (mult (stretch dur (pwl 0.07 1800 0.15 1000 0.4 680 0.8 240 1 100 1)) (osc (hz-to-step (* (step-to-hz pch) (sqrt 2.0))) dur)) (scale 1.57 (mult (stretch dur (pwl 0.001 1000 0.007 450 0.01)) (osc (hz-to-step (* (step-to-hz pch) (sqrt 11.0)))))) (scale 1.3 (mult (stretch dur (pwl 0.002 921 0.009 600 0.012)) (osc (hz-to-step (* (step-to-hz pch) (sqrt 71.0))))))) ))) (defun ring(dur pch scl) (mult (stretch dur (env 0.05 0.1 0.2 1 0.6 0.24 1)) (fmosc pch (mult (stretch dur (pwl 0.07 1800 0.15 1000 0.4 680 0.8 240 1 100 1)) (mult (osc (hz-to-step (* (step-to-hz pch) (sqrt 2.0))) dur) (scale scl (osc (hz-to-step (* (step-to-hz pch) (sqrt 11.0))) dur)) ))))) (defun wind(&optional (dur 3) (scal 3) (cps 590) (bw 40)) (mult (stretch dur (env 0.07 0.08 0.1 1 0.6 0.8 1)) (sum (stretch dur (reson (scale scal (noise)) cps bw 2)) (stretch dur (reson (scale (mult scal 1.13) (noise)) (mult cps (pwl 0 0.74 0.2 0.96 0.5 0.8 0.75 1.16 0.9 0.97 1 0.74 1)) (mult bw 1.042) 2)))) ) (defun suck(dur) (stretch dur (hp (noise) (pwl 0 15 0.2 6000 0.6 15000 0.75 7)))) (defun vocrap(&optional (pch 16) (dur 1)) (if (not (boundp '*voc-table1*)) (mk-voc1-table)) (fmosc pch (stretch dur(pwl 0 3 0.1 -20 0.2 20 0.3 30 0.4 -10 0.5 15 0.6 0 0.8 -30 1 60 1)) *voc-table1*)) (defun voc1(baspch varpch &optional (dur 1)) (display "duration" dur) (if (not (boundp '*voc-table1*)) (mk-voc1-table)) (fmosc baspch (stretch dur varpch) *voc-table1*)) (defun sparkle() ) ;______________________________________________________________________________________ ;UTILITIES (defun pl(exp) (setf the_max (snd-max exp 10000000)) (display "Max" the_max) (play (scale (/ 1.0 the_max) exp))) (defun ster(sound pan) (vector (mult sound pan) (mult sound (sum 1 (mult -1 pan))))) (defun echo (sound &optional (delay 0.2) (reps 12)) (seqrep (i reps) (scale (- 1 (* (+ i 1) (/ 1.0 reps))) (seq sound (s-rest delay)) ))) ;------------------------------------------------------------ (defun ster-echo (sound &optional (delay 0.2) (reps 12)) (vector (seqrep (i reps) (scale (- 0.95 (* (+ i 1) (/ 1.0 reps))) (seq (aref (cond ((oddp i) (ster sound 0.1)) (T (ster sound 0.9))) 0) (s-rest delay)))) (seqrep (i reps) (scale (- 1.0 (* (+ i 1) (/ 1.0 reps))) (seq (aref (cond ((oddp i) (ster sound 0.1)) (T (ster sound 0.9))) 1) (s-rest delay)))) )) (defun ster-echo (sound &optional (delay 0.2) (reps 12)) (vector (seqrep (i reps) (scale (- 0.95 (* (+ i 1) (/ 1.0 reps))) (seq (cond ((oddp i) sound) (T (scale 0 sound))) (s-rest delay)))) (seqrep (i reps) (scale (- 1.0 (* (+ i 1) (/ 1.0 reps))) (seq (cond ((not (oddp i)) sound) (T (scale 0 sound))) (s-rest delay)))) )) ;------------------------------------------------------------ (defun loop(exp &optional (rep 5)) (simrep (i rep) (at (- (* i (snd-stop-time exp)) 0.15) exp ))) ;______________________________________________________________________________________ ;RANDOM LOOKUP (defun pch-table(oct) (setf pch-t (vector (+ 12 (* oct 12)) (+ 13 (* oct 12)) (+ 14 (* oct 12)) (+ 15 (* oct 12)) (+ 16 (* oct 12)) (+ 17 (* oct 12)) (+ 18 (* oct 12)) (+ 19 (* oct 12)) (+ 20 (* oct 12)) (+ 21 (* oct 12)) (+ 22 (* oct 12)) (+ 23 (* oct 12)) ))) (defun dur-table() (setf dur-t (vector 1 1.5 1.25 1.75 2 3))) (defun time-table() (setf time-t (vector 0.1 0.2 0.4 0.8))) (defun rand-sel(v) ;;;(if (not (boundp v)) (pch-table oct)) (setf v (symbol-value v)) (aref v (random (- (length v) 1)))) (pch-table 5) (dur-table) (time-table) (defun chimes (n) (simrep (i n) (at (* i (rand-sel time-t)) (bell (rand-sel dur-t) (step-to-hz (rand-sel 'pch-t)))))) ;_______________________________________________________________________________________ ; SCORE SECTIONS (defun bellpat1() (scale 0.6 (sim (scale 0.7 (at 0.0 (bell 1 90))) (scale 0.6 (at 0.25 (bell 1.2 78))) (scale 0.7 (at 0.5 (bell 0.8 85))) (scale 0.55 (at 0.675 (bell 0.7 87))) (scale 0.6 (at 0.75 (bell 0.6 88))) (scale 0.7 (at 1 (bell 1 86))) ))) (defun bellpat2() (scale 0.6 (sim (scale 0.7 (at 0.0 (bell 1.2 67))) (scale 0.55 (at 0.125 (bell 0.8 74))) (scale 0.65 (at 0.25 (bell 1.3 67))) (scale 0.5 (at 0.5 (bell 0.5 79))) (scale 0.7 (at 0.75 (bell 1.5 74))) ))) (defun ringpat1() (scale 0.8 (sim (scale 0.6 (at 0.0 (ring 0.6 45 2))) (scale 0.5 (at 0.2 (ring 0.8 40 1.5))) (scale 0.8 (at 0.6 (ring 1 44 1))) (scale 0.7 (at 0.8 (ring 1.2 32 0.8))) ))) (defun ringpat2() (scale 0.65 (sim (scale 0.8 (at 0.0 (ring 1 39 1.95))) (scale 0.7 (at 0.45 (ring 0.7 27 1.7))) (scale 0.9 (at 0.6 (ring 0.9 32 1.88))) (scale 0.75 (at 1.05 (ring 0.7 36 1.6))) (scale 0.8 (at 1.2 (ring 0.8 37 1.78))) (scale 0.7 (at 1.5 (ring 0.8 34 1.8))) (scale 0.75 (at 1.8 (ring 2 32 2.6))) ))) (defun techno(rep) (seqrep (i rep) (scale 0.8 (sim (scale 0.8 (at 0.0 (ring 0.4 30 1.2))) (scale 0.6 (at 0.2 (ring 0.2 30 0.9))) (scale 0.7 (at 0.3 (ring 0.1 30 1.1))) )))) (defun suckpat(&optional (rep 16)) (seqrep (i rep) (stretch 0.2 (scale (* i 0.1) (seq (suck 1) (suck 1) (suck 2) (suck 2)))))) (defun tribal(rep) (scale 0.8 (simrep (i rep) (at (* i 0.9) (sim (at 0.0 (bell 0.2 72)) (scale 0.7 (at 0.15 (bell 0.2 72))) (scale 0.8 (at 0.3 (bell 0.2 60))) (scale 0.6 (at 0.45 (bell 0.2 65))) (scale 0.9 (at 0.6 (bell 0.2 69))) (scale 0.7 (at 0.75 (bell 0.2 60))) ))))) (defun bells(rep) (scale 0.4 (sim (bell 0.9 72) (at 0.3 (simrep (i rep) (at (* i 0.9 ) (sim (scale 0.7 (at 0.0 (bell 0.85 67))) (scale 0.8 (at 0.15 (bell 0.85 69))) (scale 0.9 (at 0.3 (bell 0.8 71))) (scale 0.8 (at 0.45 (bell 1.2 67))) (at 0.6 (bell 1.2 72 )) ))))))) (defun rings (&optional (rep 12) (init_del 0.1) (sep 0.12) (lenfac 0.2)) (scale 0.12 (simrep (i rep) (at (- 4 (+ init_del (* sep i))) (ring (* i lenfac) 24 (+ 1 (* i 0.4)) ))))) (defun rings2 (&optional (rep 8)) (simrep (i rep) (at (* 0.02 i) (vocrap)))) (defun bleerps (&optional (rep 12) (init_del 0.1) (sep 0.12) (lenfac 0.2)) (scale 0.12 (simrep (i rep) (at (- 4 (+ init_del (* sep i))) (bleerp (* i lenfac)))))) (defun accel_bleerps() (sim (scale 0.4 (at 0.0 (bleerp 4.5))) (scale 0.1 (at 0.6 (bleerp 1))) (scale 0.12 (at 1.3 (bleerp 0.8))) (scale 0.16 (at 1.9 (bleerp 0.7))) (scale 0.20 (at 2.3 (bleerp 0.6))) (scale 0.24 (at 2.7 (bleerp 0.5))) (scale 0.28 (at 3.0 (bleerp 0.4))) (scale 0.32 (at 3.2 (bleerp 0.3))) (scale 0.25 (at 3.4 (bleerp 0.2))) (scale 0.14 (at 3.55 (bleerp 0.2))) (scale 0.10 (at 3.7 (bleerp 0.2))) (scale 0.06 (at 3.8 (bleerp 0.2))) (scale 0.03 (at 3.9 (bleerp 0.2))) )) (defun sect1() (sim (scale 3 (at 0.0 (simrep(i 4) (at (* i 2.9) (wind))))) (scale 0.5 (at 2 (warble 8 48))) (scale 0.3 (at 2.05 (warble 8.05 47.9))) (scale 0.15 (at 2.9 (ring 7.1 (hz-to-step 1) 1.2))) (scale 0.175 (at 4.9 (ring 5.1 (hz-to-step 2) 1.414))) (scale 0.2 (at 6.9 (ring 3.1 (hz-to-step 4) 1.8))) (scale 0.7 (at 9.9 (suck 3.5))) (scale 0.28 (at 9.9 (blurp 3.1))) (scale 0.7 (at 12.4 (stretch 0.5 (suckpat 17)))) (scale 0.4 (at 13.8 (seqrep (i 2) (seq (techno 2) (transpose 5 (techno 2)) (transpose -2 (techno 1)) (transpose 3 (techno 1)) (techno 2))))) (scale 0.2 (at 13.9 (seqrep (i 2) (seq (transpose 2 (techno 2)) (transpose 7 (techno 2)) (transpose -4 (techno 1)) (transpose 5 (techno 1)) (transpose -2 (techno 2)))))) (scale 0.5 (at 15.75 (seqrep (i 4) (vocrap)) )) (scale 0.35 (at 21.5 (ring 4 1 1))) (scale 0.325 (at 24 (ring 4 4 2))) (scale 0.3 (at 27.5 (ring 4 10 4))) (scale 0.85 (at 23 (seqrep (i 17) (lp (scale (+ (* i 0.05 ) 0.3) (seq (transpose -4 (ring 0.1 32 0.6)) (transpose -5 (ring 0.05 20 0.2)) (transpose (* 2 i) (ring 0.1 27 0.5)) (transpose -3 (ring 0.05 22 0.1)) (transpose (* i 3) (ring 0.1 28 0.4)) (ring 0.05 31 0.7))) (* 100 i))))) (scale 0.75 (at 23.025 (seqrep (i 17) (scale (+ (* i 0.05 ) 0.3) (seq (ring 0.1 32 1.2) (transpose -10 (ring 0.05 20 0.4)) (transpose (* 0.66 i) (ring 0.1 27 1)) (transpose -13 (ring 0.05 22 0.2)) (transpose (* i 1.5) (ring 0.1 28 0.7)) (transpose -2 (ring 0.05 31 0.9))))))) (scale 1.0 (at 20.0 (ringpat1))) (scale 0.7 (at 20.05 (stretch 1.5 (ringpat1)))) )) (defun segfault () (seqrep (i 17) (scale (+ (* i 0.05 ) 0.3) (seq (ring 0.1 32 1.2) (transpose -10 (ring 0.05 20 0.4)) (transpose (* 0.66 i) (ring 0.1 27 1)) (transpose -13 (ring 0.05 22 0.2)) (transpose (* i 1.5) (ring 0.1 28 0.7)) (transpose -2 (ring 0.05 31 0.9)))))) ; the following does clicks (defun sect1() (sim (scale 3 (at 0.0 (simrep(i 4) (at (* i 2.9) (wind))))) (scale 0.5 (at 2 (warble 8 48))) (scale 0.3 (at 2.05 (warble 8.05 47.9))) (scale 0.15 (at 2.9 (ring 7.1 (hz-to-step 1) 1.2))) (scale 0.175 (at 4.9 (ring 5.1 (hz-to-step 2) 1.414))) (scale 0.2 (at 6.9 (ring 3.1 (hz-to-step 4) 1.8))) (scale 0.7 (at 9.9 (suck 3.5))) (scale 0.28 (at 9.9 (blurp 3.1))) (scale 0.7 (at 12.4 (stretch 0.5 (suckpat 17)))) (scale 0.4 (at 13.8 (seqrep (i 2) (seq (techno 2) (transpose 5 (techno 2)) (transpose -2 (techno 1)) (transpose 3 (techno 1)) (techno 2))))) (scale 0.2 (at 13.9 (seqrep (i 2) (seq (transpose 2 (techno 2)) (transpose 7 (techno 2)) (transpose -4 (techno 1)) (transpose 5 (techno 1)) (transpose -2 (techno 2)))))) (scale 0.5 (at 15.75 (seqrep (i 4) (vocrap)) )) (scale 0.35 (at 21.5 (ring 4 1 1))) (scale 0.325 (at 24 (ring 4 4 2))) (scale 0.3 (at 27.5 (ring 4 10 4))) (scale 0.85 (at 23 (seqrep (i 17) (lp (scale (+ (* i 0.05 ) 0.3) (seq (transpose -4 (ring 0.1 32 0.6)) (transpose -5 (ring 0.05 20 0.2)) (transpose (* 2 i) (ring 0.1 27 0.5)) (transpose -3 (ring 0.05 22 0.1)) (transpose (* i 3) (ring 0.1 28 0.4)) (ring 0.05 31 0.7))) (* 100 i))))) (scale 0.75 (at 23.025 (seqrep (i 17) (scale (+ (* i 0.05 ) 0.3) (seq (ring 0.1 32 1.2) (transpose -10 (ring 0.05 20 0.4)) (transpose (* 0.66 i) (ring 0.1 27 1)) (transpose -13 (ring 0.05 22 0.2)) (transpose (* i 1.5) (ring 0.1 28 0.7)) (transpose -2 (ring 0.05 31 0.9))))))) (scale 1.0 (at 20.0 (ringpat1))) (scale 0.7 (at 20.05 (stretch 1.5 (ringpat1)))) )) nyquist-3.05/test/arraystream.lsp0000644000175000000620000000000010144436365016210 0ustar stevestaffnyquist-3.05/test/delaytest.lsp0000644000175000000620000000043210144436365015665 0ustar stevestaff; test delay using seq and s-rest (setf *vc-score* '((0 1 (pluck c4)))) (defun long-delay (in) (sum in (seq (s-rest 0.3) (cue in)))) ;(play (timed-seq *vc-score*)) ;(play (long-delay (timed-seq *vc-score*))) ;(play (sim (timed-seq *vc-score*) (at 2 (timed-seq *vc-score*)))) nyquist-3.05/test/convolve.lsp0000644000175000000620000000207210144436365015524 0ustar stevestaff; Here is some LISP code that was used to test the function: (setf testArray (make-array 10)) ; an array with 10 elements (dotimes (i 10) (setf (aref testArray i) (float i))) ; fill array with i (display "convolve test" testArray) (setf h (snd-from-array 0.0 100.0 testArray)) ; make a sound x from testArray (setf xArray (make-array 20)) ; an array with 10 elements (dotimes (i 20) (setf (aref xArray i) 0.0)) ; fill array with 0.0 (setf (aref xArray 0) 1.0) ; set first element to 1 (setf (aref xArray 15) 1.0) (display "convolve test" xArray) (setf x (snd-from-array 0.0 100.0 xArray)) ; make a sound h from xArray (setf output (snd-convolve x h)) ; perform convolution ; convert output to an array and print: (display "convolve test" (snd-samples output 100)) (print "Verify proper logical stop time using seq to add samples") (setf yArray (make-array 10)) (dotimes (i 10) (setf (aref yArray i) 10.0)) (setf y (snd-from-array 0.0 100.0 yArray)) (display "test" (snd-samples (seq (cue output) (cue y)) 100)) nyquist-3.05/test/gab.lsp0000644000175000000620000011417610144436365014433 0ustar stevestaff(setf ts (/ s 2.0)) (defun trumpet (p) (double-carrier 0.6 (step-to-hz p) 1.0 1.0 0.5 3 1 (/ 3.0 1.5)) (defun tI_1 () (transpose -2 (seq (loud lmf (seq ;; measure 1 (s-rest h) (sustain 1.3 (stretch i (trumpet d5))) (stretch i (trumpet g4)) (stretch i (trumpet d5)) (stretch i (trumpet e5)) ;; measure 2 (sustain .9 (stretch qd (trumpet f5))) (stretch i (trumpet f5)) (sustain 1.4 (stretch s (trumpet e5))) (stretch s (trumpet d5)) (stretch s (trumpet c5)) (stretch s (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet a5)) ;; measure 3 (stretch i (trumpet g5)) (stretch i (trumpet f5)) (sustain 1.1 (stretch q (trumpet e5))) (stretch h (trumpet d5)) ;; measure 4 (s-rest w) ;; measure 5 (s-rest w) ;; measure 6 (s-rest w))) (loud lf (seq ;; measure 7 (sustain 1.3 (stretch i (trumpet d5))) (stretch i (trumpet g4)) (stretch i (trumpet d5)) (stretch i (trumpet e5)) (sustain .9 (stretch qd (trumpet f5))) (stretch i (trumpet f5)) ;; measure 8 (sustain 1.4 (stretch s (trumpet e5))) (stretch s (trumpet d5)) (stretch s (trumpet c5)) (stretch s (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet a5)) (stretch i (trumpet g5)) (stretch i (trumpet f5)) (sustain 1.1 (stretch q (trumpet e5))) ;; measure 9 (stretch w (trumpet d5)) ;; measure 10 (s-rest w) ;; measure 11 (sustain 1.3 (stretch i (trumpet d5))) (stretch i (trumpet g4)) (stretch i (trumpet d5)) (stretch i (trumpet e5)) (sustain .9 (stretch qd (trumpet f5))) (stretch i (trumpet f5)) ;; measure 12 (sustain 1.4 (stretch s (trumpet e5))) (stretch s (trumpet d5)) (stretch s (trumpet c5)) (stretch s (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet a5)) (stretch i (trumpet g5)) (stretch i (trumpet f5)) (sustain 1.1 (stretch q (trumpet e5))) ;; measure 13 (sustain .9 (stretch qd (trumpet d5))) (stretch i (trumpet d5)) (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (sustain 1.1 (stretch q (trumpet a4))) ;; measure 14 (stretch w (trumpet g4))))))) (defun tII_1 () (transpose -2 (seq (loud lmf (seq ;; measure 1 (sustain 1.3 (stretch i (trumpet g4))) (stretch i (trumpet d4)) (stretch i (trumpet g4)) (stretch i (trumpet a4)) (sustain .9 (stretch qd (trumpet bf4))) (stretch i (trumpet bf4)) ;; measure 2 (sustain 1.4 (stretch s (trumpet a4))) (stretch s (trumpet g4)) (stretch s (trumpet f4)) (stretch s (trumpet e4)) (stretch i (trumpet d4)) (stretch i (trumpet d5)) (sustain 1.4 (stretch s (trumpet c5))) (stretch s (trumpet bf4)) (stretch s (trumpet a4)) (stretch s (trumpet g4)) (stretch q (trumpet f4)) ;; measure 3 (stretch s (trumpet bf4)) (stretch s (trumpet c5)) (stretch q (trumpet d5)) (stretch i (trumpet cs5)) (stretch h (trumpet d5)) ;; measure 4 (s-rest w))) (loud lf (seq ;; measure 5 (sustain 1.3 (stretch i (trumpet g4))) (stretch i (trumpet d4)) (stretch i (trumpet g4)) (stretch i (trumpet a4)) (sustain .9 (stretch qd (trumpet bf4))) (stretch i (trumpet bf4)) ;; measure 6 (sustain 1.4 (stretch s (trumpet a4))) (stretch s (trumpet g4)) (stretch s (trumpet f4)) (stretch s (trumpet e4)) (stretch i (trumpet d4)) (stretch i (trumpet d5)) (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (stretch q (trumpet a4)) ;; meaure 7 (stretch qd (trumpet bf4)) (stretch s (trumpet a4)) (stretch s (trumpet g4)) (sustain 1.4 (stretch s (trumpet a4))) (stretch s (trumpet g4)) (stretch s (trumpet f4)) (stretch s (trumpet e4)) (stretch i (trumpet d4)) (stretch i (trumpet d5)) ;; measure 8 (sustain 1.4 (stretch s (trumpet c5))) (stretch s (trumpet bf4)) (stretch s (trumpet a4)) (stretch s (trumpet g4)) (stretch i (trumpet f4)) (stretch i (trumpet a4)) (stretch s (trumpet b4)) (stretch s (trumpet cs5)) (stretch q (trumpet d5)) (stretch i (trumpet c5)) ;; measure 9 (stretch h (trumpet d5)) (s-rest h) ;; measure 10 (s-rest h) (sustain 1.3 (stretch i (trumpet g4))) (stretch i (trumpet d4)) (stretch i (trumpet g4)) (stretch i (trumpet a4)) ;; measure 11 (sustain .9 (stretch qd (trumpet bf4))) (stretch i (trumpet bf4)) (sustain 1.4 (stretch s (trumpet a4))) (stretch s (trumpet g4)) (stretch s (trumpet f4)) (stretch s (trumpet e4)) (stretch i (trumpet d4)) (stretch i (trumpet d5)) ;; measure 12 (sustain 1.4 (stretch s (trumpet c5))) (stretch s (trumpet bf4)) (stretch s (trumpet a4)) (stretch s (trumpet g4)) (stretch i (trumpet f4)) (stretch i (trumpet a4)) (stretch s (trumpet b4)) (stretch s (trumpet cs5)) (stretch q (trumpet d5)) (stretch i (trumpet c5)) ;; measure 13 (sustain .9 (stretch qd (trumpet d5))) (stretch i (trumpet bf4)) (stretch i (trumpet a4)) (stretch q (trumpet g4)) (stretch i (trumpet fs4)) ;; measure 14 (stretch w (trumpet g4))))))) (defun h_1 () (transpose -7 (seq (loud lmf (seq ;; measure 1 (s-rest w) ;; measure 2 (s-rest w) ;; measure 3 (s-rest h) (sustain 1.3 (stretch i (trumpet g4))) (stretch i (trumpet c4)) (stretch i (trumpet g4)) (stretch i (trumpet a4)) ;; measure 4 (sustain .9 (stretch qd (trumpet bf4))) (stretch i (trumpet bf4)) (sustain 1.4 (stretch s (trumpet a4))) (stretch s (trumpet g4)) (stretch s (trumpet f4)) (stretch s (trumpet ef4)) (stretch i (trumpet d4)) (stretch i (trumpet g4)) ;; measure 5 (stretch i (trumpet fs4)) (stretch q (trumpet g4)) (stretch i (trumpet fs4)) (sustain .9 (stretch qd (trumpet g4))) (stretch i (trumpet ef4)) ;; measure 6 (stretch q (trumpet f4)) (stretch i (trumpet ef4)) (stretch i (trumpet g4)) (stretch s (trumpet a4)) (stretch s (trumpet b4)) (stretch q (trumpet c5)) (stretch i (trumpet b4)) ;; measure 7 (sustain 1.1 (stretch qd (trumpet c5))) (sustain 1.4 (stretch s (trumpet bf4))) (sustain 1.4 (stretch s (trumpet a4))) (stretch h (trumpet g4)) ;; measure 8 (s-rest qd) (stretch i (trumpet bf4)) (stretch s (trumpet c5)) (stretch s (trumpet d5)) (stretch i (trumpet ef5)) (stretch i (trumpet c5)) (stretch i (trumpet d5)) ;; measure 9 (stretch h (trumpet g4)))) (loud lf (seq (sustain 1.3 (stretch i (trumpet g4))) (stretch i (trumpet c4)) (stretch i (trumpet g4)) (stretch i (trumpet a4)) ;; measure 10 (sustain .9 (stretch qd (trumpet bf4))) (stretch i (trumpet bf4)) (sustain 1.1 (stretch qd (trumpet a4))) (sustain 1.4 (stretch s (trumpet g4))) (sustain 1.4 (stretch s (trumpet f4))) ;; measure 11 (stretch h (trumpet g4)) (stretch h (trumpet g4)) ;; measure 12 (s-rest qd) (stretch i (trumpet bf4)) (stretch s (trumpet c5)) (stretch s (trumpet d5)) (stretch i (trumpet ef5)) (stretch i (trumpet c5)) (stretch i (trumpet d5)) ;; measure 13 (sustain .9 (stretch qd (trumpet g4))) (stretch i (trumpet bf4)) (stretch i (trumpet af4)) (stretch q (trumpet af4)) (stretch i (trumpet g4)) ;; measure 14 (stretch w (trumpet e4))))))) (defun b_1 () (seq (loud lmf (seq ;; measure 1 (s-rest w) ;; measure 2 (s-rest w) ;; measure 3 (sustain 1.3 (stretch i (trumpet f3))) (stretch i (trumpet c3)) (stretch i (trumpet f3)) (stretch i (trumpet g3)) (sustain .9 (stretch qd (trumpet af3))) (stretch i (trumpet af3)) ;; measure 4 (sustain 1.4 (stretch s (trumpet g3))) (stretch s (trumpet f3)) (stretch s (trumpet ef3)) (stretch s (trumpet d3)) (stretch i (trumpet c3)) (stretch i (trumpet c4)) (sustain 1.4 (stretch s (trumpet bf3))) (stretch s (trumpet af3)) (stretch s (trumpet g3)) (stretch s (trumpet f3)) (stretch i (trumpet ef3)) (stretch s (trumpet d3)) (stretch s (trumpet c3)) ;; measure 5 (stretch i (trumpet d3)) (stretch i (trumpet ef3)) (stretch q (trumpet d3)) (sustain 1.4 (stretch s (trumpet c3))) (stretch s (trumpet bf2)) (stretch s (trumpet af2)) (stretch s (trumpet g2)) (stretch i (trumpet f2)) (stretch i (trumpet f3)) ;; measure 6 (stretch q (trumpet ef3)) (stretch i (trumpet f3)) (stretch i (trumpet af3)) (stretch s (trumpet bf3)) (stretch s (trumpet c4)) (stretch i (trumpet df4)) (stretch i (trumpet bf3)) (stretch i (trumpet c4)) ;; measure 7 (stretch h (trumpet f3)) (s-rest h) ;; measure 8 (s-rest w))) ;; measure 9 (loud lf (seq (sustain 1.3 (stretch i (trumpet f3))) (stretch i (trumpet c3)) (stretch i (trumpet f3)) (stretch i (trumpet g3)) (sustain .9 (stretch qd (trumpet af3))) (stretch i (trumpet af3)) ;; measure 10 (sustain 1.4 (stretch s (trumpet g3))) (stretch s (trumpet f3)) (stretch s (trumpet ef3)) (stretch s (trumpet d3)) (stretch i (trumpet c3)) (stretch i (trumpet c4)) (sustain 1.1 (stretch qd (trumpet bf3))) (sustain 1.4 (stretch s (trumpet af3))) (sustain 1.4 (stretch s (trumpet g3))) ;; measure 11 (stretch h (trumpet f3)) (s-rest h) ;; meausre 12 (s-rest w) ;; measure 13 (s-rest qd) (stretch i (trumpet af2)) (stretch s (trumpet bf2)) (stretch s (trumpet c3)) (stretch i (trumpet df3)) (stretch i (trumpet bf2)) (stretch i (trumpet c3)) ;; measure 14 (stretch w (trumpet f2)))))) (defun tI_2 () (transpose -2 (loud lp (seq ;; measure 15 (sustain 1.1 (stretch qd (trumpet bf4))) (sustain 1.3 (stretch i (trumpet c5))) (stretch q (trumpet d5)) (stretch q (trumpet bf4)) (stretch q (trumpet g4)) (stretch q (trumpet bf4)) ;; measure 16 (sustain 1.1 (stretch qd (trumpet a4))) (sustain 1.3 (stretch i (trumpet bf4))) (stretch q (trumpet c5)) (stretch h (trumpet d5)) (stretch q (trumpet cs5)) ;; measure 17 (stretch wd (trumpet d5)) ;; measure 18 (s-rest wd) ;; measure 19 (s-rest wd) ;; measure 20 (s-rest wd) ;; measure 21 (sustain 1.1 (stretch qd (trumpet bf4))) (sustain 1.3 (stretch i (trumpet c5))) (stretch q (trumpet d5)) (stretch q (trumpet bf4)) (stretch q (trumpet g4)) (stretch q (trumpet bf4)) ;; meausre 22 (sustain 1.1 (stretch qd (trumpet a4))) (sustain 1.3 (stretch i (trumpet bf4))) (stretch q (trumpet c5)) (stretch h (trumpet d5)) (stretch q (trumpet cs5)))))) (defun tII_2 () (transpose -2 (loud lp (seq ;; measure 15 (stretch w (trumpet g4)) (stretch h (trumpet g4)) ;; measure 16 (stretch hd (trumpet f4)) (stretch q (trumpet d4)) (stretch h (trumpet e4)) ;; measure 17 (stretch wd (trumpet d4)) ;; measure 18 (s-rest wd) ;; meausre 19 (sustain 1.1 (stretch qd (trumpet f4))) (sustain 1.3 (stretch i (trumpet g4))) (stretch q (trumpet a4)) (stretch q (trumpet f4)) (stretch q (trumpet d4)) (stretch q (trumpet f4)) ;; measure 20 (sustain 1.1 (stretch qd (trumpet e4))) (sustain 1.3 (stretch i (trumpet d4))) (stretch q (trumpet e4)) (stretch h (trumpet g4)) (stretch q (trumpet fs4)) ;; measure 21 (sustain 1.1 (stretch qd (trumpet g4))) (sustain 1.3 (stretch i (trumpet a4))) (stretch q (trumpet bf4)) (stretch q (trumpet g4)) (stretch q (trumpet d4)) (stretch q (trumpet ef4)) ;; measure 22 (sustain 1.1 (stretch qd (trumpet f4))) (sustain 1.3 (stretch i (trumpet g4))) (stretch q (trumpet a4)) (stretch q (trumpet a4)) (sustain 1.1 (stretch h (trumpet a4))))))) (defun h_2 () (transpose -7 (loud lp (seq ;; measure 15 (s-rest wd) ;; measure 16 (s-rest wd) ;; measure 17 (sustain 1.1 (stretch qd (trumpet ef4))) (sustain 1.3 (stretch i (trumpet f4))) (stretch q (trumpet g4)) (stretch q (trumpet ef4)) (stretch q (trumpet c4)) (stretch q (trumpet ef4)) ;; measure 18 (sustain 1.1 (stretch qd (trumpet d4))) (sustain 1.3 (stretch i (trumpet ef4))) (stretch q (trumpet f4)) (stretch h (trumpet g4)) (stretch q (trumpet fs4)) ;; measure 19 (stretch wd (trumpet g4)) ;; measure 20 (stretch hd (trumpet f4)) (stretch q (trumpet ef4)) (stretch h (trumpet d4)) ;; measure 21 (stretch w (trumpet g4)) (stretch h (trumpet ef4)) ;; measure 22 (stretch hd (trumpet f4)) (stretch q (trumpet bf4)) (sustain 1.1 (stretch h (trumpet a4))))))) (defun b_2 () (loud lp (seq ;; measure 15 (s-rest wd) ;; measure 16 (s-rest wd) ;; measure 17 (stretch w (trumpet f3)) (stretch h (trumpet f3)) ;; meausre 18 (stretch hd (trumpet ef3)) (stretch q (trumpet c3)) (stretch h (trumpet d3)) ;; measure 19 (stretch wd (trumpet c3)) ;; measure 20 (s-rest wd) ;; measure 21 (stretch w (trumpet f3)) (stretch h (trumpet f3)) ;; measure 22 (stretch hd (trumpet ef3)) (stretch q (trumpet c3)) (stretch h (trumpet g3))))) (defun tI_3 () (transpose -2 (loud lmf (seq ;; measure 23 (stretch i (trumpet d5)) (stretch i (trumpet a4)) (sustain 1.4 (stretch s (trumpet bf4))) (stretch s (trumpet c5)) (stretch s (trumpet d5)) (stretch s (trumpet f5)) (stretch i (trumpet e5)) (stretch i (trumpet d5)) (stretch i (trumpet c5)) (stretch i (trumpet bf4)) ;; measure 24 (stretch i (trumpet a4)) (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (stretch i (trumpet a4)) (stretch q (trumpet g4)) (s-rest q) ;; measure 25 (s-rest qd) (stretch i (trumpet a4)) (sustain 1.4 (stretch s (trumpet bf4))) (stretch s (trumpet c5)) (stretch s (trumpet d5)) (stretch s (trumpet f5)) (stretch i (trumpet e5)) (stretch i (trumpet d5)) ;; measure 26 (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (stretch q (trumpet a4)) (stretch q (trumpet g4)) (s-rest q) ;; measure 27 [C] (s-rest i) (stretch i (trumpet c5)) (sustain 1.4 (stretch s (trumpet c5))) (stretch s (trumpet e5)) (stretch s (trumpet f5)) (stretch s (trumpet a5)) (stretch i (trumpet g5)) (stretch i (trumpet f5)) (stretch i (trumpet e5)) (stretch q (trumpet d5)) ;; meausre 28 (stretch i (trumpet cs5)) (stretch id (trumpet d5)) (stretch s (trumpet a4)) (sustain 1.4 (stretch s (trumpet bf4))) (stretch s (trumpet c5)) (stretch s (trumpet d5)) (stretch s (trumpet f5)) (stretch i (trumpet ef5)) (stretch i (trumpet d5)) ;; measure 29 (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet g4)) (stretch i (trumpet fs4)) (stretch q (trumpet g4)) (stretch i (trumpet fs4)))))) (defun tII_3 () (transpose -2 (loud lmf (seq ;; measure 23 (stretch q (trumpet f4)) (s-rest i) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet e4))) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet g4)) ;; measure 24 (stretch i (trumpet f4)) (stretch i (trumpet e4)) (stretch q (trumpet d4)) (s-rest i) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet e4))) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) ;; measure 25 (stretch i (trumpet a4)) (stretch q (trumpet g4)) (stretch i (trumpet fs4)) (stretch i (trumpet g4)) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet e4))) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) ;; measure 26 (stretch i (trumpet a4)) (stretch q (trumpet g4)) (stretch i (trumpet fs4)) (stretch i (trumpet g4)) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet e4))) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) ;; measure 27 [C] (stretch i (trumpet a4)) (stretch q (trumpet g4)) (stretch s (trumpet f4)) (stretch s (trumpet f4)) (sustain 1.4 (stretch s (trumpet bf4))) (stretch s (trumpet c5)) (stretch s (trumpet d5)) (stretch s (trumpet a4)) (stretch i (trumpet c5)) (stretch i (trumpet g4)) ;; measure 28 (stretch id (trumpet a4)) (stretch s (trumpet e4)) (sustain 1.4 (stretch s (trumpet f4))) (stretch s (trumpet g4)) (stretch s (trumpet a4)) (stretch s (trumpet c5)) (stretch i (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet g4)) (stretch i (trumpet bf4)) ;; measure 29 (stretch i (trumpet a4)) (stretch i (trumpet g4)) (stretch i (trumpet ef4)) (stretch i (trumpet d4)) (sustain 1.1 (stretch h (trumpet d4))))))) (defun h_3 () (transpose -7 (loud lmf (seq ;; measure 23 (stretch q (trumpet g4)) (s-rest hd) ;; measure 24 (s-rest i) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet ef4))) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) (stretch i (trumpet a4)) (stretch i (trumpet g4)) (stretch i (trumpet f4)) (stretch i (trumpet ef4)) ;; measure 25 (stretch id (trumpet f4)) (stretch s (trumpet c4)) (stretch i (trumpet ef4)) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet c4))) (stretch s (trumpet d4)) (stretch s (trumpet ef4)) (stretch s (trumpet g4)) (stretch i (trumpet f4)) (stretch i (trumpet ef4)) ;; measure 26 (stretch q (trumpet f4)) (stretch i (trumpet g4)) (stretch i (trumpet g4)) (sustain 1.4 (stretch s (trumpet c4))) (stretch s (trumpet d4)) (stretch s (trumpet ef4)) (stretch s (trumpet g4)) (stretch i (trumpet f4)) (stretch i (trumpet ef4)) ;; measure 27 [C] (stretch id (trumpet f4)) (stretch s (trumpet c4)) (stretch i (trumpet ef4)) (stretch s (trumpet d4)) (stretch s (trumpet g4)) (stretch i (trumpet c4)) (s-rest s) (stretch s (trumpet g4)) (sustain 1.4 (stretch s (trumpet a4))) (stretch s (trumpet bf4)) (stretch s (trumpet c5)) (stretch s (trumpet g4)) ;; measure 28 (stretch i (trumpet bf4)) (stretch i (trumpet a4)) (stretch q (trumpet g4)) (s-rest i) (stretch i (trumpet d4)) (sustain 1.4 (stretch s (trumpet ef4))) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) ;; meausre 29 (stretch i (trumpet af4)) (stretch i (trumpet g4)) (stretch i (trumpet f4)) (stretch i (trumpet ef4)) (stretch i (trumpet d4)) (stretch i (trumpet c4)) (sustain 1.1 (stretch q (trumpet d4))))))) (defun b_3 () (loud lmf (seq ;; measure 23 (stretch h (trumpet c3)) (s-rest h) ;; measure 24 (s-rest qd) (stretch i (trumpet c3)) (sustain 1.4 (stretch s (trumpet d3))) (stretch s (trumpet ef3)) (stretch s (trumpet f3)) (stretch s (trumpet af3)) (stretch i (trumpet g3)) (stretch i (trumpet f3)) ;; measure 25 (stretch i (trumpet ef3)) (stretch i (trumpet d3)) (stretch q (trumpet c3)) (stretch q (trumpet f3)) (s-rest q) ;; measure 26 (s-rest qd) (stretch i (trumpet c3)) (sustain 1.4 (stretch s (trumpet d3))) (stretch s (trumpet ef3)) (stretch s (trumpet f3)) (stretch s (trumpet af3)) (stretch i (trumpet g3)) (stretch i (trumpet f3)) ;; measure 27 [C] (stretch i (trumpet ef3)) (stretch i (trumpet d3)) (stretch i (trumpet c3)) (stretch i (trumpet c3)) (sustain 1.4 (stretch s (trumpet f3))) (stretch s (trumpet g3)) (stretch s (trumpet af3)) (stretch s (trumpet c4)) (stretch i (trumpet bf3)) (stretch i (trumpet af3)) ;; measure 28 (stretch q (trumpet g3)) (stretch i (trumpet c3)) (stretch i (trumpet e3)) (stretch i (trumpet f3)) (stretch i (trumpet ef3)) (stretch q (trumpet f3)) ;; measure 29 (stretch h (trumpet bf2)) (stretch h (trumpet c3))))) (defun tI_4 () (transpose -2 (seqrep (i 1) (seq (loud lpp (seq ;; measure 30 (stretch s (trumpet g4)) (stretch s (trumpet g4)) (stretch s (trumpet bf4)) (stretch s (trumpet c5)) (sustain 1.1 (stretch q (trumpet d5))) (stretch i (trumpet d5)) (stretch i (trumpet bf4)) (sustain 1.1 (stretch q (trumpet c5))) ;; measure 31 (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (stretch i (trumpet bf4)) (sustain 1.4 (stretch s (trumpet a4))) (sustain 1.4 (stretch s (trumpet g4))) (stretch i (trumpet a4)) (stretch q (trumpet bf4)) (stretch i (trumpet a4)) ;; measure 32 (stretch q (trumpet bf4)) (sustain 1.1 (stretch q (trumpet d5))) (stretch i (trumpet d5)) (stretch i (trumpet d5)) (sustain 1.1 (stretch q (trumpet d5))) ;; measure 33 (stretch i (trumpet d5)) (stretch i (trumpet d5)) (stretch i (trumpet d5)) (stretch i (trumpet f5)) (sustain 1.3 (stretch i (trumpet ef4))) (stretch i (trumpet d4)) (stretch i (trumpet c5)) (stretch i (trumpet bf4)) ;; measure 34 [D] (stretch i (trumpet a4)) (stretch i (trumpet d5)) (stretch i (trumpet a4)) (stretch i (trumpet bf4)) (stretch qd (trumpet fs4)) (stretch i (trumpet d5)) ;; measure 35 (stretch i (trumpet a4)) (stretch i (trumpet bf4)) (stretch i (trumpet fs4)) (stretch i (trumpet g4)) (sustain 1.3 (stretch i (trumpet a4))) (stretch i (trumpet bf4)) (stretch i (trumpet c5)) (stretch i (trumpet d5)) ;; meausre 36 (stretch i (trumpet e5)) (stretch i (trumpet f5)) (stretch s (trumpet e5)) (stretch i (trumpet d5)) (stretch s (trumpet cs5)) (stretch s (trumpet d5)) (stretch s (trumpet a4)) (stretch s (trumpet f4)) (stretch s (trumpet g4)) (stretch i (trumpet a4)) (stretch i (trumpet bf4)) ;; measure 37 (stretch i (trumpet a4)) (stretch i (trumpet g4)) (stretch s (trumpet fs4)) (stretch i (trumpet g4)) (stretch s (trumpet fs4)) (stretch s (trumpet g4)) (stretch s (trumpet d5)) (stretch s (trumpet bf4)) (stretch s (trumpet c5)) (stretch i (trumpet d5)) (stretch i (trumpet ef5)) ;; measure 38 (stretch i (trumpet d5)) (stretch i (trumpet c5)) (stretch s (trumpet b4)) (stretch i (trumpet c5)) (stretch s (trumpet b4)) (stretch s (trumpet c5)) (stretch s (trumpet g5)) (stretch s (trumpet e5)) (stretch s (trumpet f5)) (stretch i (trumpet g5)) (stretch i (trumpet a5)) ;; measure 39 (stretch i (trumpet g5)) (stretch i (trumpet f5)) (stretch s (trumpet e5)) (stretch i (trumpet f5)) (stretch s (trumpet e5)) (stretch s (trumpet f5)) (stretch s (trumpet c5)) (stretch s (trumpet a4)) (stretch s (trumpet bf4)) (stretch i (trumpet c5)) (stretch i (trumpet d5)) ;; measure 40 (stretch i (trumpet c5)) (stretch i (trumpet bf4)) (stretch s (trumpet a4)) (stretch i (trumpet bf4)) (stretch s (trumpet a4)) (stretch s (trumpet bf4)) (stretch s (trumpet f4)) (stretch s (trumpet d4)) (stretch s (trumpet e4)) (stretch i (trumpet f4)) (stretch i (trumpet g4)) ;; measure 41.1 (stretch i (trumpet a4)) (stretch i (trumpet bf4)) (stretch s (trumpet a4)) (stretch i (trumpet g4)) (stretch s (trumpet fs4)) ;; measure 41.2 (stretch i (trumpet a4)) (stretch i (trumpet bf4)) (stretch s (trumpet a4)) (stretch i (trumpet g4)) (stretch s (trumpet fs4)) (stretch q (trumpet g4)) (s-rest s) (stretch s (trumpet d5)) (stretch s (trumpet b4)) (stretch s (trumpet c5)) ;; measure 42 (stretch i (trumpet d5)) (stretch i (trumpet ef5)) (stretch i (trumpet d5)) (stretch i (trumpet c5)) (stretch i (trumpet b4)) (stretch i (trumpet c5)) (s-rest ts) (sustain 1.1 (stretch ts (trumpet g5))) (sustain 1.1 (stretch ts (trumpet f5))) (stretch s (trumpet ef5)) (stretch s (trumpet c5)) ;; measure 43 (stretch i (trumpet b4)) (stretch i (trumpet c5)) (s-rest ts) (sustain 1.1 (stretch ts (trumpet g5))) (sustain 1.1 (stretch ts (trumpet f5))) (stretch s (trumpet ef5)) (stretch s (trumpet c5)) (stretch i (trumpet b4)) (stretch i (trumpet c5)) (stretch q (trumpet e5)) ;; measure 44 (stretch w (trumpet d5)))))))) ;; stretch .75 because q = 60 corresponds to a stretch of 1, so ;; q = 80 corresponds to 60/80 = .75 (defun gabrieli () (loud lp (sim (seq (stretch .75 (tI_1)) (stretch .25 (tI_2)) (stretch .75 (tI_3))) (seq (stretch .75 (tII_1)) (stretch .25 (tII_2)) (stretch .75 (tII_3))) (seq (stretch .75 (h_1)) (stretch .25 (h_2)) (stretch .75 (h_3))) (seq (stretch .75 (b_1)) (stretch .25 (b_2)) (stretch .75 (b_3))) ))) nyquist-3.05/test/shape.lsp0000644000175000000620000000157010144436365014773 0ustar stevestaff;; there was a reported problem with shape reading 1 beyond the ;; end of the table -- this is a test to check it out ;; 20-Jun-97 ; make sample rates low enough to look at by hand (set-sound-srate 10) (set-control-srate 10) ; make a table (setf shape-signal (scale 2 (ramp 2))) (print (snd-samples shape-signal 25)) ; try it out (setf input (scale 1.2 (stretch 3 (lfo .1)))) ;(s-plot input) (setf result (shape input shape-signal 1.0)) (print (snd-samples result 50)) ;(s-plot result) ; conclusion : ; The shape must be defined all the way to the origin + 1.0, ; in this case, the origin is 1, so the shape must go to 2.0. ; Initially, I used (pwl 2 2 2 0) for the shape and had ; problems because this function is zero at 2.0! I assume ; this is the source of the reported problem. By using ramp, ; which actually extends to it's duration + 1 sample, we ; get the right result. nyquist-3.05/test/str.lsp0000644000175000000620000000111510144436365014476 0ustar stevestaff(defun test () (stretch 3 (sim (at 0 (mynote)) (at 1 (mynote)) (at 2 (mynote))))) (defun mynote () (display "mynote" (local-to-global 0)) (stretch-abs 1 (snd-compose (s-read "tri.snd") (ramp)))) (set-sound-srate 100) (set-control-srate 100) (setf *plotscript-file* "../sys/unix/rs6k/plotscript") (defun kuu-up (dur rate) (stretch-abs 1 (snd-compose (kuu dur) (scale (* 0.5 rate) (sum (pwe 7 7 7) (control-srate-abs 22050 (pwl 7 7 7))))))) nyquist-3.05/test/s-add-to.lsp0000644000175000000620000000064511511415575015304 0ustar stevestaff;; s-add-to.lsp -- a test program to explore a bug report (print "loading s-add-to.lsp") (load "/Users/rbd/nyquist/sys/unix/osx/system.lsp") ; make a file to add to (s-save (mult 0.1 (vector (osc c4) (osc g4))) ny:all "deleteme.wav") ; play it to make sure (play-file "deleteme.wav") ; add to it (s-add-to (mult 0.1 (vector (osc e4) (osc b4))) ny:all "deleteme.wav") ; play the result (play-file "deleteme.wav") nyquist-3.05/test/gatetest.lsp0000644000175000000620000000155610144436365015517 0ustar stevestaff(defun gate-test () (setf yy (gate xx 1.0 0.1 2.0 0.1 0.5)) (s-plot yy)) (set-control-srate 100) (set-sound-srate 100) (setf xx (pwl 0 1 0.1 0 3 0 3 1 4 0 5)) (setf zz (pwl 0 1 0.02 0 1.99 0 2.0 1 2.01 0 2.09 0 2.1 1 2.11 0 2.99 0 3 1 3.01 0 3.09 0 3.1 1 3.11 0 3.19 0 3.2 1 3.21 0 5)) (defun noise-gate (snd &optional (lookahead 0.5) (risetime 0.02) (falltime 0.5) (floor 0.01) (threshold 0.01)) (let ((rms (lp (mult snd snd) (/ *control-srate* 10.0)))) (setf save-rms rms) (setf threshold (* threshold threshold)) (mult snd (gate rms lookahead risetime falltime floor threshold)))) (defun ngtest () (setf xx (mult (stretch 5 (lfo 40)) (pwl 0 1 0.5 0 2 0 2 1 2.5 1 2.5 0 5))) (setf xx (sum xx (scale 0.01 (stretch 5 (noise))))) (setf yy (noise-gate xx)) (s-plot (vector xx yy))) nyquist-3.05/test/snd-fetch-array.lsp0000644000175000000620000000065511511415575016664 0ustar stevestaff;; snd-fetch-array.lsp -- a test program to explore a new feature (print "loading snd-fetch-array.lsp") (load "/Users/rbd/nyquist/sys/unix/osx/system.lsp") (autonorm-off) ;; make short sound (setf s (osc c4 0.001)) ; about 44 samples (dotimes (i 100) ; limited iterations in case of problems (setf samps (snd-fetch-array s 10 10)) (display "after snd-fetch-array" i samps *rslt*) (if (null samps) (return 'done))) nyquist-3.05/test/ifftnt.lsp0000644000175000000620000000536710144436365015175 0ustar stevestaff;; test code for ifft framework ; The interface to SND-IFFT is: ; (snd-ifft t0 sr iterator) ; where t0 is the starting time, ; sr is the sample rate, and ; iterator is an XLisp object ; the iterator object must return an array of samples when :next is sent ; or return NIL to end the sound ; The sound returned by SND-IFFT (for now) is simply the concatenation ; of all samples returned in arrays returned from :next. ; TEST IT.... ; first, make a class: (setf iter-class (send class :new '(count len))) ; now define some methods ; for this test, we'll return "count" arrays of length "len" and ; we'll fill the arrays with a ramp from -1 to +1 so that the final ; result will be a sawtooth wave (send iter-class :answer :set-count '(c) '((setf count c))) (send iter-class :answer :set-len '(l) '((setf len l))) (send iter-class :answer :next '() '( (format t "iter-class got :next\n") (cond ((<= count 0) nil) (t (let (res) (setf count (- count 1)) (setf res (make-ramp-array len)) (display "iter-class returns" res) res))))) (defun make-ramp-array (len) (let (ar) (setf ar (make-array len)) (dotimes (i len) (setf (aref ar i) (+ -1 (* i (/ 2.0 len))))) ar)) ; now try calling SND-IFFT with an object (setf iter (send iter-class :new)) (send iter :set-count 10) (send iter :set-len 20) (print "Select SPLIT SCREEN item in CONTROL menu on Macs for good screen layout") (defun ifft-test () (s-save (snd-ifft 0.0 100 iter) ny:all "test.wav")) ;; fft code: make an object that returns ffts when called with :NEXT ;; (setf fft-class (send class :new '(sound length skip))) (send fft-class :answer :next '() '((snd-fft sound length skip))) ; there's a way to do this with new, but I forgot how... (send fft-class :answer :init '(snd len skp) '( (setf sound snd) (setf length len) (setf skip skp))) (defun make-fft-iterator (sound length skip) (let (iter) (setf iter (send fft-class :new)) ; make a copy because the snd-fft will modify the sound: (send iter :init (snd-copy sound) length skip) iter)) ;; print ffts of a short ramp: (defun fft-test () (let (fft-iter) (setf fft-iter (control-srate-abs 100 (make-fft-iterator (pwl 1 1 1 0) 32 32))) (dotimes (i 5) (print (send fft-iter :next))))) ;; now try running the ffts through the ifft: (defun fft-ifft-test () (let (fft-iter ifft-snd) (setf fft-iter (control-srate-abs 100 (make-fft-iterator (pwl 1 1 1 0) 32 32))) (setf ifft-snd (snd-ifft 0 100 fft-iter)) (display "fft-ifft" (snd-length ifft-snd 200)) (display "fft-ifft" (snd-samples ifft-snd 200)) (s-save ifft-snd ny:all "test.wav"))) nyquist-3.05/test/sr.lsp0000644000175000000620000000055710144436365014323 0ustar stevestaff;; scott raymond's midi code (set-sound-srate 22050.0) (setf my-seq (seq-create)) (setf midifile (open "/afs/andrew.cmu.edu/usr15/sr4r/public/testmidi.mid")) (seq-read-smf my-seq midifile) (close midifile) (defun my-note (p) (scale 0.2(osc p))) (play (seq-midi my-seq (note (chan pitch velocity) (my-note pitch)))) (defun (srl) () (load "test/sr")) nyquist-3.05/test/product.lsp0000644000175000000620000000127610144436365015356 0ustar stevestaff; this test should display a plot of x^2 ; it gives an example of constructing a DSP primitive ; (in this case, product) using Lisp rather than C ; for the computation (setf product-class (send class :new '(s1 s2))) (send product-class :answer :next '() '((let ((f1 (snd-fetch s1)) (f2 (snd-fetch s2))) (cond ((and f1 f2) (* f1 f2)) (t nil))))) (send product-class :answer :isnew '(p1 p2) '((setf s1 (snd-copy p1)) (setf s2 (snd-copy p2)))) (defun snd-product (s1 s2) (let (obj) (setf obj (send product-class :new s1 s2)) (snd-fromobject (snd-t0 s1) (snd-srate s1) obj))) (set-control-srate 100) (s-plot (snd-product (ramp) (ramp))) nyquist-3.05/test/temp3.gio0000644000175000000620000000000010144436365014666 0ustar stevestaffnyquist-3.05/test/comb.lsp0000644000175000000620000000414110144436365014610 0ustar stevestaff(load "rbd") (defun comb-test () ;(comb (seq (noise) (s-rest 10)) 500 5)) (sim (setf dur 5) (comb (seq (noise) (s-rest dur)) (step-to-hz c4) dur) (comb (seq (noise) (s-rest dur)) (step-to-hz e4) dur) (comb (seq (noise) (s-rest dur)) (step-to-hz d5) dur))) (setf bf3hz (step-to-hz bf3)) (setf c4hz (step-to-hz c4)) (setf bf4hz (step-to-hz bf4)) (setf c5hz (step-to-hz c5)) (setf d5hz (step-to-hz d5)) (setf f5hz (step-to-hz f5)) (setf g5hz (step-to-hz g5)) (setf a5hz (step-to-hz a5)) (setf b5hz (step-to-hz b5)) (defun pwl-step (fr to) (pwl 0 fr 15 fr 16 to 35 to 35)) (defun reson-test () (setf dur 4) (let (center (snd (s-read "./test/snd/test2.snd"))) (setf snd (seq (cue snd) (s-rest 5))) (setf center (scale 0.01 (at 0.05 (cue snd)))) (vector (sim (scale 0.01 snd) center (reson snd (pwl-step b5hz a5hz) 1) (reson snd (pwl-step c5hz bf4hz) 1)) (sim (scale 0.01 (at 0.11 (cue snd))) center (scale 0.1 (reson snd (pwl-step c4hz bf3hz) 0.5)) (reson snd (pwl-step g5hz f5hz) 1) (reson snd (pwl-step d5hz c5hz) 1))))) (defun reson-test-1 () (setf dur 4) (sim (reson (seq (noise) (s-rest dur)) (step-to-hz c5) 1) (reson (seq (noise) (s-rest dur)) (step-to-hz g5) 1) (reson (seq (noise) (s-rest dur)) (step-to-hz d5) 1))) (defun convert-file () (s-save (force-srate 22050 (jam-srate (aref (s-read "./test/snd/test1.snd") 0) 48000)) 1000000 "./test/snd/test2.snd")) (defun jam-srate (snd rate) (snd-xform snd rate (snd-time snd) MIN-START-TIME MAX-STOP-TIME 1.0)) ;(setf xxx (comb-test)) (defun g () (setf xxx (reson-test)) (play-xxx)) (defun play-xxx () (cond ((soundp xxx) (setf scale-factor (s-max xxx 1000000))) ((arrayp xxx) (setf scale-factor 0) (dotimes (i (length xxx)) (setf scale-factor (max scale-factor (s-max (aref xxx i) 1000000))))) (t (error "bad type" xxx))) (format t "Maximum amplitude before scaling: ~A~%" scale-factor) (play (scale (/ scale-factor) xxx))) (g) nyquist-3.05/test/trigger.lsp0000644000175000000620000000035711466723256015346 0ustar stevestaff'(print (control-srate-abs 20 (snd-samples (snd-trigger (lfo 2) '(lambda (t0) (at-abs t0 (const 0.5 0.2)))) 100))) (print (control-srate-abs 20 (snd-samples (trigger (lfo 2) (const 0.5 0.2)) 100))) nyquist-3.05/test/readme0000644000175000000620000000057110144436365014333 0ustar stevestaffrunning ../ny from test causes a 0 block length error. fix: I'm not sure how this is supposed to work. I'm recompiling with small block size. Make a sample that terminates and/or logical stops on a block boundary (1 input) and see how this is handled. It looks like prod has a special "break" command to get out of the inner loop and terminate the signal when this happens. nyquist-3.05/test/warp.lsp0000644000175000000620000000037610144436365014647 0ustar stevestaff(defun line () (seqrep (i 20) (pluck1 (+ 24 (random 12))))) (defun pluck1 (p) (display "pluck1" (local-to-global 0) (local-to-global 1)) (pluck p)) (play (warp (mult (pwl 21 2.5) (pwl 21 2.5)) (line))) (s-plot (mult (pwl 11 2.5) (pwl 11 2.5))) nyquist-3.05/test/rbd.lsp0000644000175000000620000000120010144436365014430 0ustar stevestaff;(setf *default-plot-file* "/afs/cs/usr/rbd/tmp/points.dat") ;(setf *default-sf-dir* "/afs/cs.cmu.edu/user/rbd/tmp/") ;(setf *default-sound-file* "test") (setf *default-plot-file* "/space/rbd/tmp/points.dat") (setf *default-sf-dir* "/space/rbd/tmp/") (setf *default-sound-file* "rbd-temp.snd") (set-sound-srate 22050) (set-control-srate 2205) (defun ask (string default) (let (inp) (format t "~A: [~A]" string default) (setf inp (read-line)) (cond ((equal inp "") default) (t (intern inp))))) (if (ask "turn off audio?" t) (defun r () t) ; turn off audio output (print "!!!AUDIO OUTPUT TURNED OFF!!!")) nyquist-3.05/test/gr.lsp0000644000175000000620000000215010144436365014276 0ustar stevestaff(defun gr () (show-graphics) (showpen) (moveto 0 0) (lineto 20 20)) (setf graph-width 600) (setf graph-height 220) (defun array-max-abs (points) (let ((m 0.0)) (dotimes (i (length points)) (setf m (max m (abs (aref points i))))) m)) (defun s-plot (snd &optional (n 1000)) (prog ((points (snd-samples snd n)) maxpoint y-offset horizontal-scale vertical-scale) (show-graphics) (clear-graphics) (setf maxpoint (array-max-abs points)) (setf y-offset (/ graph-height 2)) (moveto 0 y-offset) (lineto graph-width y-offset) (moveto 0 y-offset) (setf horizontal-scale (/ (float graph-width) (length points))) (setf vertical-scale (- (/ (float y-offset) maxpoint))) (dotimes (i (length points)) (lineto (truncate (* horizontal-scale i)) (+ y-offset (truncate (* vertical-scale (aref points i)))))) (format t "X Axis: ~A to ~A (seconds)\n" (snd-t0 snd) (/ (length points) (snd-srate snd))) (format t "Y Axis: ~A to ~A\n" (- maxpoint) maxpoint) (format t "~A samples plotted.\n" (length points)) )) nyquist-3.05/test/eq.lsp0000644000175000000620000000226610144436365014303 0ustar stevestaff;; test file for eq-band function ;; NOTE: eq-band is happy if you give it all numerical arguments or if you give ;; it a set of time-varying arguments. It will not run with a mixture of scalar ;; and SOUND arguments. Use the Nyquist function CONST to coerce a scalar into ;; a constant-valued SOUND. Be careful to note that CONST returns to zero at the ;; default stop time, e.g. (const 5) lasts 1 second, (stretch 2 (const 5)) lasts ;; 2 seconds, etc. (play (eq-band (scale 0.1 (noise)) 1000 30 0.3)) ;; 20 dB gain (play (eq-band (scale 0.1 (noise)) (const 1000) (const 30) (const 0.3))) ; different code is executed if the source has no scale factor... (play (scale 0.1 (eq-band (noise) (const 1000) (const 30) (const 0.3)))) (play (eq-band (scale 0.1 (noise)) (pwlv 800 1 1200) ; center frequency (const 30) (const 0.3))) (play (stretch 5 (eq-band (scale 0.1 (noise)) (const 1000) (pwlv -30 1 30) ; gain (const 0.3)))) (play (stretch 5 (eq-band (scale 0.1 (noise)) (const 1000) (const 30) (pwev 2 1 0.1)))) ; bandwidth in octaves nyquist-3.05/test/nonewline.lsp0000644000175000000620000000006710144436365015671 0ustar stevestaff;no newline at end of file test (print "hello world") nyquist-3.05/test/midi2.lsp0000644000175000000620000000515010144436365014675 0ustar stevestaff(defun midi2 () ; this was original test file, here wrapped in ; defun so that it doesn't execute ;(set-sound-srate 22050.0) (setf *default-plot-file* "/tmp/points.dat") (setf my-seq (seq-create)) (setf midifile (open "/afs/andrew.cmu.edu/usr15/sr4r/public/testmidi.mid")) (seq-read-smf my-seq midifile) (close midifile) ) (defun my-note-2 (p) (display "my-note-2" p (get-duration 1.0) (local-to-global 0.0)) (scale 0.2 (osc p))) (defun my-note (p) (display "my-note" p (get-duration 1.0) (local-to-global 0.0)) (scale 0.2 (mult (pwl 0.1 1 0.9 1 1) (osc p)))) (defun ss () (seq-midi my-seq (note (chan pitch velocity) (my-note pitch)))) (defun ss1 () (seq-midi my-seq (note (chan pitch velocity) (my-note-2 (- pitch 84))))) (defun ss2 () (sim (at .75 (Stretch .333 (my-note-2 -19))) (at 1.0 (stretch .333 (my-note-2 -15))) (at 1.5 (stretch .333 (my-note-2 -12))) (at 2.0 (stretch .333 (my-note-2 -12))) (at 2.75 (stretch .333 (my-note-2 -10))) (at 3.625 (stretch .333 (my-note-2 -7))))) (defun ss3 () (sim (at .75 (Stretch .333 (my-note-2 -19))) (at 1.0 (stretch .333 (my-note-2 -15))))) (defun ss4 () (sim (at .75 (Stretch .333 (my-note 65))) (at 1.0 (stretch .333 (my-note 69))) (at 1.5 (stretch .333 (my-note 72))) (at 2.0 (stretch .333 (my-note 72))) (at 2.75 (stretch .333 (my-note 74))) (at 3.625 (stretch .333 (my-note 77))))) (defun ss5 () (seq (set-logical-stop (stretch .333 (my-note 65)) .25) (set-logical-stop (stretch .333 (my-note 69)) .5) (set-logical-stop (stretch .333 (my-note 72)) .5) (set-logical-stop (stretch .333 (my-note 72)) .75) (set-logical-stop (stretch .333 (my-note 74)) .875) (stretch .333 (my-note 77)))) (defun ss6 () (seq (set-logical-stop (stretch .333 (my-note 65)) .5) (stretch .333 (my-note 77)))) (defun ss7 () (seq (set-logical-stop (stretch .333 (my-note -19)) .5) (stretch .333 (my-note -7)))) (defun lowrates () (set-sound-srate 100) (set-control-srate 100) ) (defun pulse () (display "pulse" (local-to-global 0.0) (get-duration 1.0)) (pwl 0 1 1)) (defun t1 () (seq-midi my-seq (note (chan pitch velocity) (pulse)))) ;=============================new test for Windows================== (defun wt () (setf my-seq (seq-create)) (setf midifile (open "..\\test\\test.gio")) (seq-read my-seq midifile) (close midifile) (seq-midi my-seq (note (chan pitch vel) (my-note pitch))) ) nyquist-3.05/test/init.lsp0000644000175000000620000000130510144436365014632 0ustar stevestaff; init.lsp -- default Nyquist startup file (load "nyinit.lsp") ; add your customizations here: ; e.g. (setf *default-sf-dir* "...") (setf *default-sf-dir* "/space/rbd/tmp/") ;(load "tp") ;(load "gab") ; here's where the error occurs: ;(play (trumpet c4)) (set-sound-srate 4) (set-control-srate 4) (Defun xx () (snd-samples (sum (set-logical-stop (osc c4 3) 2) (const 10)) 20)) (defun yy () (snd-samples (sum (osc c4 2) (const 10)) 20)) (defun zz () (snd-samples (snd-prod (set-logical-stop (osc c4 3) 2) (stretch 3 (const 10))) 20)) (defun ww () (snd-samples (snd-prod (osc c4 3) (stretch 3 (const 10))) 20)) ; here's where the error occurs (at sample rate of 4) ;(play (trumpet c4)) (load "natbug") nyquist-3.05/test/fmfbv-test.lsp0000644000175000000620000000062611466723256015757 0ustar stevestaff; SND-FMFBV ARGS: t0 hz sr index-sound ; index > 1.1 gets noisy (defun feedbackv-fm (pitch index-sound) (let ((hz (step-to-hz (+ pitch (get-transpose))))) (snd-fmfbv (local-to-global 0) hz *sound-srate* index-sound))) (play (seq (mult (pwl 5.0 1.0 10.0) (feedbackv-fm a4 (pwl 10 1.1 10.01))) (mult (pwl 5.0 1.0 10.0) (feedbackv-fm a3 (pwlv 1.1 10 0.0))))) (exit) nyquist-3.05/test/multiseq.lsp0000644000175000000620000000417710144436365015544 0ustar stevestaff (defun mst () (setf xxx (seq (vector (osc c4) (osc g4)) (vector (osc c3) (osc e4)))) (play xxx)) (defun mst1 () (setf xxx (seq (vector (const 1) (const 2)) (vector (const 3) (const 4)))) (play xxx)) (defun mst2 () (setf xxx (seq (vector (ramp) (ramp)) (vector (ramp) (ramp)))) (play xxx)) (defun mst3 () (setf xxx (seq (vector (ramp) (at 0.5 (const 1))) (vector (ramp) (at 0.8 (const 2)))))) (defun mst4 () (setf xxx (seq (vector (ramp) (ramp)) (vector (at 0.5 (const 1)) (at 0.8 (const 2))) (vector (ramp) (ramp)) ))) (defun sh () (dotimes (i 2) (print (snd-samples (aref xxx i) 100)))) (defun lsr () (set-sound-srate 10) (set-control-srate 10)) (defun hsr () (set-sound-srate 22050) (set-control-srate 2205)) ;crash: (load "test/rbd") (lsr) (mst1) (defun msr1 () (seqrep (i 3) (vector (osc (+ c4 i)) (osc (+ e4 i))))) (defun ster (sound pan) (vector (mult sound pan) (mult sound (sum 1 (mult -1 pan))))) (defun ster (sound pan) (vector (snd-normalize (mult sound pan)) (snd-normalize (mult sound (sum 1 (mult -1 pan)))))) (defun msr2 () (seqrep (i 10) (ster (osc 46 0.2) (* i 0.1)))) ; The next 4 lines crash nyquist if sound_types are allocated from the ; freelist. They just don't work if sound_types are always allocated ; from the pool. I guess something is getting on the freelist early. ; bad ref count? (lsr) (play (msr2)) (play (msr2)) ;(play (msr2)) ;(play (msr2)) ;(play (msr2)) ;(play (stretch 0.2 (ster (osc c4) 0.1))) '( (hsr) (play (stretch 0.2 (seq (ster (osc c4) 0.9) (ster (osc c4) 0.1)))) (lsr) (setf xxx (stretch 0.2 (ster (const 1) 0.9))) (setf xxx (stretch 0.2 (seq (ster (const 1) 0.9) (ster (const 2) 0.1)))) (setf xxx (seq (ster (const 1) 0.9) (ster (const 2) 0.1))) (sx) ) (defun sx () (list (snd-samples (aref xxx 0) 100) (snd-samples (aref xxx 1) 100))) ;(lsr) ;(msr1) ;(mst1) ;(sh) ;(mst4) ;(sh) ;(snd-print (seq (vector (ramp) (ramp)) ; (vector (at 0.5 (const 1)) (at 0.8 (const 2))) ; (vector (ramp) (ramp)) ) ; 100) nyquist-3.05/test/envtest.lsp0000644000175000000620000000054211466723256015367 0ustar stevestaff(defun pwltest () (define-env 'bar (make-big-envelope))) (defun make-big-envelope () (let (tim val lis (n 500)) (dotimes (i n) (setf tim (* (1+ i) 0.01)) (setf val (rrandom)) (setf lis (cons val (cons tim lis)))) (setf lis (cons (* (1+ n) 0.01) lis)) (cons 'pwl (reverse lis)))) ;(print (make-big-envelope)) (pwltest)nyquist-3.05/test/variable-resample.lsp0000644000175000000620000000021610144436365017262 0ustar stevestaff;; variable resample test (set-sound-srate 200.0) (defun test () (sound-warp (pwl 10 10 10) (stretch 10 (hzosc 5)) 10.0)) (play (test)) nyquist-3.05/test/linux-segfault.lsp0000644000175000000620000000226010144436365016637 0ustar stevestaff (setf *maintable* (sim (scale 0.9 (build-harmonic 1 2048)) (scale 0.2 (build-harmonic 2 2048)) (scale 0.3 (build-harmonic 3 2048)) (scale 0.3 (build-harmonic 4 2048)) (scale 0.2 (build-harmonic 5 2048)) (scale 0.2 (build-harmonic 6 2048)))) (setf *maintable* (list *maintable* (hz-to-step 1.0) T)) (setf *overtable* (sim (scale 1 (build-harmonic 1 2048)))) (setf *overtable* (list *overtable* (hz-to-step 1.0) T)) (defun maintone (note vibe) (fmosc note (scale 0.3 (lfo vibe)) *maintable* 0.0) ) (defun overtone (note vibe vol) (scale vol (mult (fmosc note (scale 0.2 (lfo 16)) *overtable* 0.1) (sum (const 1) (scale 0.2 (lfo vibe)))))) (defun bandsweep (low hi) (hp (lp (noise) (pwev (+ low 5) 1 (+ hi 5))) (pwev low 1 hi))) (play (timed-seq `( (0 30 (overtone ef7 .75 0.4)) (1 30 (overtone ds7 1.3 .3)) (1 30 (overtone cs7 .36 .3)) (1 30 (overtone gs7 .8 .5)) (1.5 5 (scale 0.7 (bandsweep 200 2000))) (1 7 (scale 0.7 (bandsweep 500 8000))) (2 2 (pluck c4)) (5 5 (pluck e4)) (7 10 (pluck g4)) ) ) ) nyquist-3.05/test/seqmiditest.lsp0000644000175000000620000000000010144436365016211 0ustar stevestaffnyquist-3.05/test/temp.gio0000644000175000000620000000034110144436365014613 0ustar stevestaff!msec V3 c4 U600 T0 d4 U600 T600 e4 U600 T1200 Z3 T1800 f4 U300 T1800 V4 g4 U300 T2100 ~10(15) T2400 ~10(20) T2700 ~10(30) T3000 Y100 T3300 Y200 T3600 Y0 T3900 Y128 T4200 Y16 T4500 O0 T4800 O20 T4950 O50 T5100 c0 U2400 T5250 nyquist-3.05/test/cnvl.lsp0000644000175000000620000000076110144436365014636 0ustar stevestaff;; cnvl.lsp -- convolve test ;; original bug: convolve truncated the result to the duration of the ;; first parameter. ;; the fix: convolve.c was hand-modified to set the logical stop to ;; the end of the first parameter but the terminate time to the sum ;; of durations. (set-sound-srate 10.0) (set-control-srate 10.0) (defun impulse () (snd-from-array 0.0 *default-sound-srate* (vector 1.0))) (defun train () (sim (impulse) (at 1.0 (impulse)) (at 2.0 (impulse)))) (s-plot (train)) nyquist-3.05/test/natbug.lsp0000644000175000000620000000534210144436365015154 0ustar stevestaff(defun n2b2 () (scale 2 (sim (at .3 (stretch .2 (osc (hz-to-step 1616)))) (at .5 (stretch .3 (osc (hz-to-step 1611)))) (at .6 (stretch .2 (osc (hz-to-step 1605)))) (at .8 (stretch .5 (osc (hz-to-step 1600))))))) (defun n2b2R () (scale 2 (sim (at .3 (stretch .2 (osc (hz-to-step 1600)))) (at .5 (stretch .3 (osc (hz-to-step 1605)))) (at .6 (stretch .2 (osc (hz-to-step 1611)))) (at .8 (stretch .5 (osc (hz-to-step 1616))))))) (defun hph1b () (seq (n2b2) (s-rest .02) (stretch .2 (at .5 (sim (osc (hz-to-step 200)) (osc (hz-to-step 206)) (s-rest .1)))))) (defun ply () (scale .1 (sim (hph1b) (at .9 (n2b2R))))) (defun Plystrm () (scale .1 (sim (seqrep (i 10) (ply)) (seq (stretch 2 (hph1b)) (s-rest .01) (stretch 2 (n2b2)) (stretch 3 (n2b2)))))) (defun drum () (scale .2 (stretch .5 (sim (pan (Plystrm)1) (at .4 (pan(Plystrm)0)) (at 1.5 (pan (Plystrm)1)) (at 3.5 (pan (Plystrm)0)))))) (play (scale 10.5 (drum))) (defun n2b2 () (scale 2 (sim (at .3 (stretch .2 (osc (hz-to-step 1616)))) (at .5 (stretch .3 (osc (hz-to-step 1611)))) (at .6 (stretch .2 (osc (hz-to-step 1605)))) (at .8 (stretch .5 (osc (hz-to-step 1600))))))) (defun n2b2R () (scale 2 (sim (at .3 (stretch .2 (osc (hz-to-step 1600)))) (at .5 (stretch .3 (osc (hz-to-step 1605)))) (at .6 (stretch .2 (osc (hz-to-step 1611)))) (at .8 (stretch .5 (osc (hz-to-step 1616))))))) (defun hph1b () (seq (n2b2) (s-rest .02) (stretch .2 (at .5 (sim (osc (hz-to-step 200)) (osc (hz-to-step 206)) (s-rest .1)))))) (defun ply () (scale .1 (sim (hph1b) (at .9 (n2b2R))))) (defun Plystrm () (scale .1 (sim (seqrep (i 10) (ply)) (seq (stretch 2 (hph1b)) (s-rest .01) (stretch 2 (n2b2)) (stretch 3 (n2b2)))))) (defun drum () (scale .2 (stretch .5 (sim (pan (Plystrm)1) (at .4 (pan(Plystrm)0)) (at 1.5 (pan (Plystrm)1)) (at 3.5 (pan (Plystrm)0)))))) (play (scale 10.5 (drum))) nyquist-3.05/docsrc/0002755000175000000620000000000011537433126013447 5ustar stevestaffnyquist-3.05/docsrc/sdl/0002755000175000000620000000000011537433126014231 5ustar stevestaffnyquist-3.05/docsrc/sdl/part1.tex0000755000175000000620000007030111466723256016013 0ustar stevestaff% Manual de SDL % part1.tex % pmorales. Junio, 2007 \section{Introduction} Usually, Computer Music compositions are formally specified by means of programming language algorithms. Owing to the fact that {\it Nyquist} is actually an extension of Lisp, this language can be used for both sound synthesis and algorithmic composition. In addition, Nyquist can be also employed for rendering music that is described as a note sequence, for instance, a score in traditional music notation. However, in this case, every note parameter has to be specified which makes difficult to compose music confortably. The {\it Score Description Library} (SDL) is aimed at facilitating the translation from traditional score notation to {\it Nyquist} source code and also allowing a fine control over the performance and synthesis parameters. \section{Description} \subsection{\textit{SDL} score example} A SDL score is a quoted list in which the notes along with the pitch, duration attributes and other arguments related to timing and synthesis parameters, are specified. \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm] ; Begin of BWV 1069 (setf *my-sdl-score* '((TF 1) (INIT-INSTR "i1" sinte) (INSTRUMENT "i1") (PWL-POINT :mm 100) (ATTR :idur 0.1) 2 (:c4 1) :d4 (:e4 2) :c4 :g4 :e4 :a4 (:g4 1) :f4 (:g4 4) (:a4 1) :c5 :f4 :a4 :g4 :f4 :e4 :g4 :f4 :a4 :d4 :f4 :e4 :d4 :c4 :d4 :e4 :f4 (:g4 2) :a3 :c4 :d4 :f4 :g3 :b3 :c4 :e4 (:f3 1) :e4 :d4 :c4 :g3 :d4 :c4 :b3 (ATTR :idur 1) (LABEL :t1) (:c4 4))) \end{Verbatim} \begin{itemize} \item \texttt{TF} stands for \textit{Time Factor}. All the durations will be multiplied by this factor (default value is 1). \item \texttt{INIT-INSTR} declares an instrument to be used in synthesis. The first argument \textit{``i1''} is the instrument name in the SDL score. The second one is the {\it Nyquist} function name which defines the instrument. This function must be defined independently from the score by means of an expression \mbox{\texttt{(defun sinte \ldots)}} \item \texttt{INSTRUMENT} causes that all the notes from now on are synthesized by the instrument \textit{``i1''} until a new instrument is specified. \item \texttt{PWL-POINT} defines a piece wise linear function in order to set the time-variable parameters. For instance, \texttt{:mm} takes a value of \texttt{100} when the instruction is called. \item \texttt{ATTR} sets the value of a constant parameter. The parameter value is not changed until a new \texttt{ATTR} instruction is reached. For example, the \texttt{:idur} parameter takes a value of {\it 0.1} in every note until a new value is specified by a new \texttt{ATTR}. \item \texttt{2} defines a 2 beat rest. Two different time types can be considered: a {\it score time} measured in beat and a {\it physical time} measured in second. A quarter has a duration of 4 beats. The physical time is computed according to the score time, {\it tempo} and Time Factor {\tt TF}. \item \texttt{(:c4 1)} represents a note given by a C4 pitch and a 1 beat duration.(i.e, a sixteenth). Only pitch and duration are specified. Pitch can be specified by using an alternative syntax. Duration can be any {\it Lisp } expression. The rest of attributes the needed for synthesis are provided by \texttt{ATTR} y \texttt{PWL-POINT} instructions. \item \texttt{:d4} is a D4 pitch note and inherited duration of 1 beat. Rests do not alter the default duration. Changes in duration are explicitly set by a note attribute. \item \texttt{LABEL} sets a time label aimed at synchronizing score sections. {\tt LABEL} is related to the score time. Coincidence among {\tt LABEL} references depends on the score {\it tempi} map. Therefore, the user is responsible for controlling this issue. \end{itemize} \subsection{\textit{SDL} score processing} A \textit{SDL} score is processed by using the \texttt{sdl->score} function. For example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (load ``sdl'') (sdl->score *my-sdl-score*) => ((0.3 0.15 (SINTE :PITCH 60 :MM 100 :IDUR 0.1)) (0.45 0.15 (SINTE :PITCH 62 :MM 100 :IDUR 0.1)) (0.6 0.3 (SINTE :PITCH 64 :MM 100 :IDUR 0.1)) (0.9 0.3 (SINTE :PITCH 60 :MM 100 :IDUR 0.1)) (1.2 0.3 (SINTE :PITCH 67 :MM 100 :IDUR 0.1)) +ldots ) \end{Verbatim} As can be noticed, an {\it Xmusic} score is obtained as a result. Every {\it Xmusic} score event has three elements. The first one indicates the note starting time. The second one is the stretching factor and the third one is a call to the synthesis function. For instance, the first event: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm] (0.3 0.15 (SINTE :PITCH 60 :MM 100 :IDUR 0.1)) \end{Verbatim} starts at {\tt 0.3} seconds; the stretching factor is {\tt 0.15} and the synthesis function call is \texttt{(sinte :pitch 60 :idur 0.1)}.\par \texttt{:mm} argument is not a synthesis parameter but a control for {\it tempo}. Thus, {\tt sinte} implementation must not include any argument with this name. The strecthing factor multiplies the note duration by the stretching value. For instance, for a sytnthesis function call returning a 1 second note and a stretching factor equals to {\tt 0.15} the overall note duration would be {\tt 0.15}. One of the most remarkable features of Nyquist is the \textit{Behavioral Abstraction} which constitutes a framework for addressing context-dependent transformations that includes stretching. Every synthesis function has a default behavior that properly works in most of the situations. Nevertheless, this default behavior may not be appropriated in some cases. Therefore, for instance, the amplitude envelope attack of a sound may be changed by different strecthing factor values which can be unsuitable for a harpsichord-like sound. To fix this problem, the synthesis function can be defined so that the attack time is constant and independent form the stretching factor \footnote{Extensive knowledge of Behavioral Abstraction is required to perform this task}. Alternatively, all the stretching factors can be set to \texttt{1} and a specific parameter can be used to indicate the specific duration of any event. \texttt{:idur} parameter is used for this purpose. This way, sound duration can be higher or lower allowing for several articulation modes from {\it legato} to {\it stacatto}. The time-control parameters can not be called \texttt{:dur} since this name is a {\it Xmusic} reserved keyword. \texttt{sdl:normalize-score-duration} is used to set the stretching factors to 1 as is shown in the following example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (sdl:normalize-score-duration (sdl->score *my-sdl-score*)) => ((0.3 1 (SINTE :PITCH 60 :MM 100 :IDUR 0.1)) (0.45 1 (SINTE :PITCH 62 :MM 100 :IDUR 0.1)) (0.6 1 (SINTE :PITCH 64 :MM 100 :IDUR 0.1)) (0.9 1 (SINTE :PITCH 60 :MM 100 :IDUR 0.1)) (1.2 1 (SINTE :PITCH 67 :MM 100 :IDUR 0.1)) +ldots ) \end{Verbatim} \subsection{\textit{SDL} score rendering} Once a \textit{SDL} score has been translated to \textit{Xmusic} format, a {\it Nyquist} {\it behavior} can be obtained by using the \texttt{timed-seq} function \footnote{It is also possible to use the \texttt{score-play} function in order to directly render the score} \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm] (play (timed-seq (sdl:normalize-score-duration (sdl->score *my-sdl-score*)))) \end{Verbatim} \subsection{Synchronization} When dealing with complex scores it is suitable to split them into smaller parts. Temporal references must be established in order to synchronize all the parts involved. These temporal reference can be set by using a \texttt{LABEL} instruction. \texttt{sdl->timelabels} function is used to obtain the temporal references list. This data is registered as a property list of a symbol created on-the-fly. For example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *my-time-labels* (sdl->timelabels *my-sdl-score*)) (print (symbol-plist *my-time-labels*)) => (:T1 64) \end{Verbatim} \texttt{AT-LABEL} instruction allow us to match the temporal label which has been previously specified by \texttt{LABEL} and another time value from a different score. The temporal references list must be sent, as an argument, to the \texttt{sdl->score} function as can be seen in the following example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm] (setf *my-time-labels* (sdl->timelabels *my-sdl-score*)) (setf *voz-2* '((TF 1) (INIT-INSTR "i1" sinte) (INSTRUMENT "i1") (PWL-POINT :mm 100) (ATTR :idur 0.1) (AT-LABEL :t1) 2 (:g4 1) :a4 (:b4 2) :g4)) (sdl->score *voz-2* *my-time-labels*) => ((9.9 0.15 (SINTE :PITCH 67 :MM 100 :IDUR 0.1)) (10.05 0.15 (SINTE :PITCH 69 :MM 100 :IDUR 0.1)) (10.2 0.3 (SINTE :PITCH 71 :MM 100 :IDUR 0.1)) (10.5 0.3 (SINTE :PITCH 67 :MM 100 :IDUR 0.1))) \end{Verbatim} \subsubsection*{Warnings} Users should notice that time labels are actually score times (measured in beats), whereas in \textit{Xmusic} scores the time is specified in seconds, which in turn are mapped from the score time, the \texttt{TF} parameter and the \textit{tempi} map. For that reason, time labels always coincide in score time, but they have to use the same \texttt{TF} parameter and \textit{tempi} map to achieve a coincidence in physical time. \section{Reference guide} % Incluir ejemplos en los apartados que interese \subsection{Overall \textit{SDL} score structure} A \textit{SDL} score is a quoted list containing notes, rests or other elements related to synthesis and performance. The following elements have to be present in any \textit{SDL} score: \begin{itemize} \item One instrument initialization \texttt{INIT-INSTR}. \item One instrument assignment \texttt{INSTRUMENT}. \item One tempo specification \texttt{:mm}, by means of either \texttt{PWL-POINT} or \texttt{ATTR}. \item One note, at least. \end{itemize} Examples: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm] (setf *minimal-sco-1* '((INIT-INSTR "i1" xx) (INSTRUMENT "i1") (PWL-POINT :mm 100) (:c4 2))) (setf *minimal-sco-2* '((INIT-INSTR "i2" yy) (INSTRUMENT "i2") (ATTR :mm 100) :c4)) \end{Verbatim} Function \texttt{sdl->score} returns an error if the score does not have this basic data. \subsection{Pitch specification} Pitches can be given by using: \begin{itemize} \item A number. The standard MIDI pitch scale has been adopted here (60 = C4). No tempered pitches are allowed when using floating point numbers (FLONUM). \item The standard \textit{Nyquist} symbols. Example: \texttt{cs4} = C4 sharp = 61. \item The standard \textit{lambda~Music} symbols\footnote{A library for music composition developed by Pedro Morales in \textit{Common Lisp}} Pitches are represented by symbols starting with a colon. Sharps and flats are notated by \texttt{\#} and \texttt{b}. Examples: \texttt{:c4 :C4 :c\#4 :C\#4 :cb4 :Cb4} \item Quoted symbols. Examples: \texttt{'c4 'cs4 'c\#4 'cb4} \item Strings. Examples: \texttt{``c4'' ``cs4'' ``c\#4'' ``cb4''} \end{itemize} Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm] (setf *pitches* (list 60 60.0 c4 'c4 C4 'C4 cs4 df4 :c4 :c#4 :cb4 :df4 "c4" "cs4" "cb4" "c#4")) (mapcar #'sdl:pitch-lex *pitches*) => (60 60 60 60 60 60 61 61 60 61 59 62 60 61 59 61) \end{Verbatim} \subsection{Durations}\label{duraciones} Durations are measured in beats. A quarter worth 4~beats; a half, 8~beats, and so on. Fractional durations are allowed.\par Durations can be given by: \begin{itemize} \item A number. \item A \textit{Lisp} expression. Example: \texttt{(/ 4.0 3.0)} represents a third of a quarter, that is, an eighth triplet. \end{itemize} \subsubsection*{Physical time and score time} Physical time (measured in seconds) is computed after score time (measured in beats), the \textit{time factor}, \texttt{TF} and the \textit{tempi} map (given by the parameter \texttt{:mm}). \subsubsection*{Global Time Factor} It is given by the score instruction \texttt{TF}. Example: \texttt{(TF 2.0)} multiplies by 2.0 all the durations in the score, whereas \texttt{(TF 0.5)} does it by 0.5. \par This instruction must appear only once in the score. Its default value is 1.0. \subsubsection*{\textit{Tempi}} \textit{Tempi} values are given by the parameter \texttt{:mm} whose value is set by means of the instructions \texttt{ATTR} or \texttt{PWL-POINT}. \subsection{Notes} There are two alternatives for specifying notes: \begin{itemize} \item By using a two-element list (pitch and duration). Example: \texttt{(:c4 4)} is a quarter \texttt{C4}. \item By the pitch only. Duration is taken from the last note. \end{itemize} The default duration can be changed by means of the \texttt{DUR} instruction. \subsection{Rests} Can be noted by: \begin{itemize} \item A number representing the amount of beats. \item \texttt{DELTA} or \texttt{PAU} instructions\footnote{Both instructions are equivalent.}, indicating the duration by a number or by a \textit{Lisp} expression. \end{itemize} Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *sco3* '((TF 1.0) ; Overall Time Factor (INIT-INSTR ``i1'' xx) ; Preamble. instr. init. (INSTRUMENT ``i1'') ; instr. assign. (ATTR :mm 60) ; metronome MM=60. 1 quarter = 1 sec. (:c4 4) ; c4 quarter 4 ; quarter rest :d4 ; d4. duration = quarter (inherited) (PAU 8) ; half rest (:e4 (/ 4.0 3.0)) ; e4. eighth triplet :e4 ; :e4 ; (DELTA (* 2 4)) ; half rest (:f4 (* 2 1.5)) ; f4 duration = 3 = dotted eighth (DUR 4) ; current duration = 4 (quarter) :g4 ; g4 duration = quarter (DUR (/ 4.0 3.0)) ; current duration = triplet eighth :a4 :a4 :a4 ; a4 triplets )) \end{Verbatim} \subsection{Chords} Polyphonic music can be achieved in \textit{SDL} by gathering several scores. Nevertheless, \textit{SDL} predefined instructions can be more appropriated in simple cases. \par \texttt{CH} produces simultaneous notes, having the current duration. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *sco4* '((TF 1.0) ; Overall Time Factor (INIT-INSTR ``i1'' xx) ; preamble. init. instr. (INSTRUMENT ``i1'') ; assign. instr. (ATTR :mm 60) ; metronome MM=60. 1 quarter = 1 sec. (:c4 4) ; c4 quarter 4 ; quarter rest (DUR 8) ; current duration = 8 = half (CH :c4 :e4 :g4) ; three-note chord. duration = half ; \end{Verbatim} \texttt{CH1} produces one note without increasing the time. Time increments can be indicated by the \texttt{DELTA} instruction. This way independent duration chords can be built for each note. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *sco5* '((TF 1.0) ; Overall Time Factor (INIT-INSTR ``i1'' xx) ; preamble. Init. instr. (INSTRUMENT ``i1'') ; assign. instr. (ATTR :mm 60) ; metronome MM=60. 1 quarter = 1 sec. (:c4 4) ; c4 quarter 4 ; quarter rest (CH1 :c4 4) ; CHORD BEGINNING. c4 quarter (CH1 :e4 8) ; e4 half. SIMULTANEOUS BEGINNING c4 (:g4 4) ; g4 quarter. SIMULTANEOUS BEGINNING. c4, e4 (:c5 4) ; c5 quarter. Starts when g4 ends ; e4 keeps playing because of the half ; duration (CH1 :c4 8) ; Arpeggiated chord BEGINNING (DELTA 0.2) ; time increases 0.2 beats (CH1 :e4 (- 8 0.2)) ; e4 starts 0.2 beats after c4 ; ends at the same time (DELTA 0.2) ; time increases 0.2 beats (CH1 :g4 (- 8 0.2 0.2)) ; g4. another arpeggio note (:c5 (- 8 0.2 0.2 0.2)) ; c5 final arpeggio note (:g3 4) ; g3 quarter after arpeggio )) ; (total arpeggio duration = 8) \end{Verbatim} \subsection{Instruments} In every score notes must be tied to a synthesis instrument. \texttt{INIT-INSTR} is the instruction used for mapping the score instrument name to a \textit{Nyquist} function that implements the instrument itself.\par The \texttt{INSTRUMENT} instruction assigns the instrument name to the notes. The current instrument can be set by a new \texttt{INSTRUMENT} instruction. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *sco6* '((TF 1.0) (INIT-INSTR ``i1'' flute) ; assign i1 instrument score name ; to the +textbf[flute] function (INSTRUMENT ``i1'') ; current instr. = i1 (ATTR :mm 60) (:c4 4) ; rendered by +textbf[flute] 4 (INIT-INSTR ``i2'' clarinet) ; assign i2 instrument score name ; to the +textbf[clarinet] function :d4 ; rendered by +textbf[flute] (INSTRUMENT ``i2) ; current instr. = i2 :e4 ; rendered by +textbf[clarinet] )) \end{Verbatim} \subsection{Attributes} In \textit{SDL} scores, parameters for synthesis functions in \textit{Nyquist} are defined by \texttt{ATTR} and \texttt{PWL-POINT} instructions.\par \begin{itemize} \item \texttt{ATTR} has two arguments. The first one is the parameter name (starting with a colon). The second one is used just to set the parameter value. The current parameter value can be changed by another \texttt{ATTR} instruction. \item \texttt{PWL-POINT} behaves like the \texttt{ATTR} instruction. The only difference is that a linear interpolation is performed between two consecutive \texttt{PWL-POINT} instructions. \end{itemize} It is not allowed to define the same attribute value by using both \texttt{ATTR} and \texttt{PWL-POINT} instructions. \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *sco7* '((TF 1.0) (INIT-INSTR ``i1'' flute) ; maps i1 to +textbf[flute] (INSTRUMENT ``i1'') ; current instr. i1 (flute) (:c4 4) ; mm = 100; rel = 4; decay = 3.2 (ATTR :decay 3.2) ; (:d4 4) ; mm = 100; rel = 4; decay = 5.1 (ATTR :decay 5.1) (:e4 4) ; mm = 100; rel = 4; decay = 5.1 (PWL-POINT :rel 4.0) (PWL-POINT :mm 100) (:f4 4) ; mm = 100; rel = 4; decay = 5.1 (:g4 4) ; mm = 100; rel = 5; decay = 5.1 (:a4 4) ; mm = 100; rel = 6; decay = 5.1 (PWL-POINT :rel 7.0) (:b4 4) ; mm = 100; rel = 7; decay = 5.1 (:c5 4) ; mm = 100; rel = 7; decay = 5.1 (:d5 4) ; mm = 100; rel = 7; decay = 5.1 (PWL-POINT :rel 7.0) (:e5 4) ; mm = 100; rel = 7; decay = 5.1 )) \end{Verbatim} \subsection{Tempi} \texttt{ATTR} can be used in case of sharp tempo changes, whereas \texttt{PWL-POINT} performs gradual tempo changes. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (setf *sco-8* '((TF 1) (INIT-INSTR "i1" flute) (INSTRUMENT "i1") (:c4 4) (PWL-POINT :mm 60) :d4 :e4 :f4 :g4 (PWL-POINT :mm 60) :e5 :d5 :c5 :b4 :c5 (PWL-POINT :mm 30))) (score-print (sdl->score *voz-8*)) => ((0 1 (FLUTE :PITCH 60 :MM 60)) (1 1 (FLUTE :PITCH 62 :MM 60)) (2 1 (FLUTE :PITCH 64 :MM 60)) (3 1 (FLUTE :PITCH 65 :MM 60)) (4 1 (FLUTE :PITCH 67 :MM 60)) (5 1 (FLUTE :PITCH 76 :MM 60)) (6 1.11111 (FLUTE :PITCH 74 :MM 54)) ; ritardando (7.11111 1.25 (FLUTE :PITCH 72 :MM 48)) (8.36111 1.42857 (FLUTE :PITCH 71 :MM 42)) (9.78968 1.66667 (FLUTE :PITCH 72 :MM 36)) ) \end{Verbatim} \subsection{Macros} A basic macro implementation is available in \textit{SDL} which allows for a specification of repetitive structures such as tremeloes, etc. The \texttt{MAC} instruction is used for this purpose. The first argument is the name of a \textit{Lisp} function and the rest ones represents the arguments for this function. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] ; +textit[Nyquist] function that repeats an event n times (defun sdl-repeat (n quoted-event) (let (result) (dotimes (i n (apply #'append result)) (push quoted-event result)))) ; macro +textit[sdl-repeat] called from a score ; the sequence :f4 :g4 is repeated 4 times (setf *score* '((TF 1.0) (INIT-INSTR "i1" flute2)(INSTRUMENT "i1")(ATTR :mm 60) (:e4 4) (MAC sdl-repeat 4 (:f4 :g4)))) (sdl->score *score*)) => ((0 1 (FLUTE2 :PITCH 64 :MM 60)) (1 1 (FLUTE2 :PITCH 65 :MM 60)) ; f4 repite 4 veces f4 g4 (2 1 (FLUTE2 :PITCH 67 :MM 60)) ; g4 (3 1 (FLUTE2 :PITCH 65 :MM 60)) ; f4 (4 1 (FLUTE2 :PITCH 67 :MM 60)) ; g4 (5 1 (FLUTE2 :PITCH 65 :MM 60)) ; f4 (6 1 (FLUTE2 :PITCH 67 :MM 60)) ; g4 (7 1 (FLUTE2 :PITCH 65 :MM 60)) ; f4 (8 1 (FLUTE2 :PITCH 67 :MM 60)) ; g4 ) \end{Verbatim} Macros can be also used to control the parameter values through a \textit{Lisp} function instead of specifying them note by note. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] ; pitches controlled by logistic equation (setf *logistica* 0.3) (setf *k* 3.97) (defun logistica () (setf *logistica* (* *k* (- 1.0 *logistica*) *logistica*))) (defun call-logistica (n dur pitch-min pitch-interval) (let (result) (dotimes (i n (reverse result)) (push (list (+ pitch-min (round (* (logistica) pitch-interval))) dur) result)))) (setf *score2* '((TF 1.0) (INIT-INSTR "i1" flute2)(INSTRUMENT "i1")(ATTR :mm 60) (:e4 4) (MAC call-logistica 5 4 30 15))) (score-print (sdl->score *score2*)) => ((0 1 (FLUTE2 :PITCH 64 :MM 60)) (1 1 (FLUTE2 :PITCH 43 :MM 60)) (2 1 (FLUTE2 :PITCH 38 :MM 60)) (3 1 (FLUTE2 :PITCH 45 :MM 60)) (4 1 (FLUTE2 :PITCH 31 :MM 60)) (5 1 (FLUTE2 :PITCH 34 :MM 60)) ) \end{Verbatim} \subsection{\textit{SDL} Functions} \texttt{FUN} instruction allows for defining score events through \textit{Lisp} functions. \par \textbf{Warning:} The inclusion of attribute \texttt{:mm} is mandatory if the event to be generated is a note. Example: \begin{Verbatim}[frame=single,fontsize=\small,numbers=left,numbersep=2mm, commandchars=+\[\]] (load "xm") (setf *my-durations* (make-heap (list 4 6 8))) (defun heap-durations (inicio pitch) (let ((dur (next *my-durations*))) (list inicio dur (list 'sinte-fun :pitch pitch :mm 60 :idur dur)))) (setf *score3* '((TF 1.0) (INIT-INSTR "i1" flute2)(INSTRUMENT "i1")(ATTR :mm 60) (:e4 4) (FUN #'heap-durations 1 :c4) (FUN #'heap-durations 2 :d4) (FUN #'heap-durations 3 :e4) (FUN #'heap-durations 4 :c4) (FUN #'heap-durations 7 :d4))) (sdl->score *score3*) => ((0 1 (FLUTE2 :PITCH 64 :MM 60)) (0.25 1.5 (SINTE-FUN :PITCH :C4 :MM 60 :IDUR 6)) (0.5 1 (SINTE-FUN :PITCH :D4 :MM 60 :IDUR 4)) (0.75 2 (SINTE-FUN :PITCH :E4 :MM 60 :IDUR 8)) (1 1.5 (SINTE-FUN :PITCH :C4 :MM 60 :IDUR 6)) (1.75 1 (SINTE-FUN :PITCH :D4 :MM 60 :IDUR 4)) ) \end{Verbatim} \section{Reference summary} \subsection{\textit{SDL} format for score instructions} \noindent\texttt{(TF args: time-factor)} \par Overall Time Factor. All the durations in the score are multiplied by this factor.\\ \noindent\texttt{(TIME-IN-SECONDS)}\par No arguments needed. Durations are measured in seconds when tempo is set to~60.\\ \noindent\texttt{(DUR lisp-expr)}\par Sets the value of the current duration. Any \textit{Lisp} expression can be used as argument.\\ \noindent\texttt{(DELTA lisp-expr)}\par Increases the time value.\\ \noindent\texttt{(PAU lisp-expr)}\par The same as \texttt{DELTA}.\\ \noindent\texttt{(INIT-INSTR string function-name)}\par Initializes an instrument. It maps the score name instrument \texttt{string} to the synthesis function \texttt{function-name}.\\ \noindent\texttt{(INSTRUMENT string)}\par Sets the current instrument to \texttt{string}. The notes following this instruction are rendered by the instrument \texttt{string} until a new instrument is set.\\ \noindent\texttt{(ATTR :symbol lisp-expr)} \par Sets \texttt{:symbol} value to \texttt{lisp-expr}. The first argument must start with a colon. The value for this attribute is kept until a new \texttt{ATTR} instruction is reached.\\ \noindent\texttt{(PWL-POINT :symbol lisp-expr)}\par Behaves like \texttt{ATTR}. The only difference is that a linear interpolation is performed between two consecutive \texttt{PWL-POINT} instructions.\\ \noindent\texttt{(CH \&rest pitches)} \par Produces a chord containing the pitches given by its argument and the current duration.\\ \noindent\texttt{(CH1 pitch duration)} \par Produces a note whose pitch and duration are given by the arguments. Time is not increased, so that the next event starts at the same time.\\ \noindent\texttt{(FUN \#'function-name \&rest args)} \par Calls the function \texttt{function-name} sending the arguments in the \texttt{args} list. The returning value must be an event to be added to an Xmusic score. This event has to be processed by the \textit{Nyquist} function \texttt{timed-seq}. Hence, the event must follow the format \texttt{(start-time stretching-factor synthesis-function-call)}\\ \noindent\texttt{(MAC macro-name \&rest args)} \par Calls the function \texttt{macro-name} sending the arguments in the \texttt{args} list. The returning value must be \textit{SDL} code which replaces the call to the macro. \\ \noindent\texttt{number}\par This is actually a rest of \texttt{number} beat duration.\\ \noindent\texttt{symbol}\par A note whose pitch is given by \texttt{symbol} and with the current duration.\\ \noindent\texttt{(pitch dur)} \par Note specified by pitch and dur arguments. \subsection{\textit{SDL} library functions} \noindent\texttt{(sdl->score score-data \&optional time-marks)}\par Produces an \textit{Xmusic} score consisting of a \mbox{\texttt{(onset-time stretch-factor synthesis-function)}} format event list.\par \noindent\texttt{score-data} is a \textit{SDL} score. \texttt{time-marks} is a symbol whose property list contains the time labels to be referenced from \texttt{score-data}.\\ \noindent\texttt{(sdl->timelabels score-data \&optional time-marks)}\par Returns a symbol whose property-list contains the time labels in \texttt{time-marks} added to \texttt{score-data} time labels. Sinchronicity can be ensured by using time labels. \noindent\texttt{(sdl:normalize-score-duration score)}\par \texttt{score} is an \textit{Xmusic} score. This function sets all the event stretching factors to 1.0. This is intended for making synthesis parameters independent from notes duration. \section{\textit{lambda~Music} compatibility} \textit{lambda Music} is a library developed in Common~Lisp and intended for MIDI rendering. Many scores from \textit{lambda~Music} can be converted to \textit{SDL} by introducing just minor changes. \section{Final remarks} This library is just an attempt to facilitate the music transcription from traditional notation to synthesis in \textit{Nyquist}. Currently it is under development and therefore some features have to be improved. For instance, the inconsistency between physical and score time. In addition, an extended implementation of the macros should be considered. nyquist-3.05/docsrc/sdl/pjmcfg.sty0000755000175000000620000000643511466723256016260 0ustar stevestaff% ------------------------ % PAQUETE DE CONFIGURACION % EJERCICIO FINAL de LaTeX % pjm. Junio, 2007 % ------------------------ \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{pjmcfg}[2007/06/07 pjm] % Estilo de pagina \newcommand{\ps@pjmx}{% \renewcommand{\@oddhead}{\sffamily \rightmark \hfill \thepage} \renewcommand{\@evenhead}{\sffamily \thepage \hfill Score Description Library} \renewcommand{\@oddfoot}{} \renewcommand{\@evenfoot}{} \renewcommand{\sectionmark}[1]{% \markright{\MakeUppercase{\thesection.\quad ##1}}}} % Dimensiones \setlength{\hoffset}{-1in} \setlength{\oddsidemargin}{2cm} \setlength{\evensidemargin}{2.5cm} \setlength{\textwidth}{\paperwidth} \addtolength{\textwidth}{-\oddsidemargin} \addtolength{\textwidth}{-\evensidemargin} \setlength{\voffset}{-1in} \setlength{\topmargin}{2cm} \setlength{\headsep}{0.5cm} \setlength{\footskip}{1.5cm} \setlength{\textheight}{\paperheight} \addtolength{\textheight}{-2\topmargin} \addtolength{\textheight}{-\footskip} % Titulos de secciones \renewcommand{\section}{\@startsection{section}{1}{0ex}% {-3.5ex plus -1ex minus -0.2ex}% {2.3ex plus 0.2ex}% {\normalfont\Large\bfseries\sffamily}} \renewcommand{\subsection}{\@startsection{subsection}{2}{0ex}% {-3.25ex plus -1ex minus -0.2ex}% {1.5ex plus 0.2ex}% {\normalfont\large\bfseries\sffamily}} \renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{0ex}% {-3.25ex plus -1ex minus -0.2ex}% {1.5ex plus 0.2ex}% {\normalfont\normalsize\bfseries\itshape}} % estos mantienen su configuracion por defecto % \newcommand{\paragraph}{\@startsection{paragraph}{4}{0ex}% % {3.25ex plus 1ex minus 0.2ex}% % {-1em}% % {\normalfont\normalsize\bfseries}} % \newcommand{\subparagraph}{\@startsection{subparagraph}{5}{\parindent}% % {3.25ex plus 1ex minus 0.2ex}% % {-1em}% % {\normalfont\normalsize\bfseries}} % Leyenda de figuras y cuadros \renewcommand{\@makecaption}[2]{% \vspace{\abovecaptionskip} \sbox{\@tempboxa}{\textbf{#1}. #2}% \ifdim \wd\@tempboxa >\linewidth \textbf{#1}. #2\par \else \global\@minipagefalse \makebox[\linewidth]{\hfil\usebox{\@tempboxa}\hfil}% \fi \vspace{\belowcaptionskip}} % Definicion de ordenes % flecha para resaltar el inicio de un parrafo \newcommand{\flecha}{\noindent\ding{'324}} % ----------------------------------------------------------- % \figura{nombre-fichero}{argumentos}{titulo}{etiqueta} % Resultado: % Inserta una figura. ``La figura~\ref{etiqueta} muestra...'' % permite referenciar la figura desde el texto. % Argumentos: width=Xcm,height=Ycm,angle=Z % ------------------------------------------------------------ \newcommand{\figura}[4]{% \begin{figure}[ht] \begin{center} \includegraphics[#2]{#1} \caption{#3} \label{#4} \end{center} \end{figure} } % Entornos % ----------------------------------------------------------- % \begin{tabla}{titulo}{etiqueta} % ... (contenido tabla) % \end{tabla} % Resultado: % Inserta una tabla. % Contenido de la tabla se define mediante el entorno 'tabular' % ``Tabla~\ref{etiqueta}'' permite referenciar la tabla. % ----------------------------------------------------------- \newenvironment{tabla}[2]{% \begin{table}[ht] \caption{#1} \label{#2} \begin{center}} {\end{center} \end{table}} % fin del paquete \endinput nyquist-3.05/docsrc/sdl/sdl-man.tex0000755000175000000620000000341311466723256016317 0ustar stevestaff\documentclass[a4paper,11pt,twoside,titlepage]{article} %\usepackage[T1]{fontenc} %\usepackage[spanish]{babel} \usepackage{graphicx} \usepackage{makeidx} \usepackage{amsmath} \usepackage{pifont} \usepackage{fancyvrb} \usepackage{pjmcfg} % subordinacion de contadores \numberwithin{figure}{section} \numberwithin{table}{section} \numberwithin{equation}{section} % AVISO: no hay ecuaciones numeradas en el texto \makeindex \pagestyle{pjmx} \begin{document} % TITULO ----------------------------------------------------------------------- \begin{titlepage} % titulo {\ \vfill \Huge\bfseries\sffamily \hfill Score Description Library\\[0.5cm] \mdseries \mbox{} \hfill Reference Manual\\ \rule{\textwidth}{1mm}} \\[0.2cm] % autor {\sffamily \mbox{} \hfill Pedro J. Morales.} \\ {\sffamily \mbox{} \hfill English translation by Luis Rodr\'iguez and Pedro J. Morales.} \\ % fecha {\sffamily \hfill \today} \\[1cm] \end{titlepage} % REVERSO DEL TITULO EN BLANCO ------------------------------------------------ \thispagestyle{empty} \mbox{} \pagebreak % TABLA DE CONTENIDOS, FIGURAS, CUADROS --------------------------------------- % inicia contador de paginas (MANEJO DE CONTADORES) \setcounter{page}{1} % numeracion de paginas en roman \renewcommand{\thepage}{\roman{page}} % comando equivalente % \pagenumbering{roman} \tableofcontents %\listoffigures %\listoftables \newpage % INICIO DEL TEXTO ------------------------------------------------------------ % inicia contador de paginas \setcounter{page}{1} % las paginas se numeran en arabic \renewcommand{\thepage}{\arabic{page}} % comando equivalente % \pagenumbering{arabic} \input{part1} % referencias % \bibliographystyle{alpha} % \bibliography{ejfinal} % indice alfabetico % \printindex \end{document}nyquist-3.05/docsrc/template/0002755000175000000620000000000011537433126015262 5ustar stevestaffnyquist-3.05/docsrc/template/filcap.mss0000644000175000000620000000044011466723256017247 0ustar stevestaff@textform[FillCaption="@begin(transparent)@modify(captionenv,fill,indent 0, leftmargin +0.5 inch,rightmargin +0.5 inch)@modify(figurecounter, numbered <@@b[Figure@@ @#@:-@1:@@ @@ ]>)@modify(tablecounter, numbered <@@b[Figure@@ @#@:-@1:@@ @@ ]>)@caption<@parm>@~ @end(transparent)"] nyquist-3.05/docsrc/nyquist/0002755000175000000620000000000011537433126015163 5ustar stevestaffnyquist-3.05/docsrc/nyquist/shifttimefig.ps0000644000175000000620000002363611466723256020230 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 35 522 418 752 %%Title: (shifttimefig-Layer#1) %%Creator: (MacDraw II 1.1v2: LaserWriter 8 8.1.1) %%CreationDate: (10:26 PM Sunday, January 24, 1904) %%For: (Dannenberg) %%Pages: 1 %%DocumentFonts: Courier %%DocumentNeededFonts: Courier %%DocumentSuppliedFonts: %%DocumentData: Clean7Bit %%PageOrder: Ascend %%Orientation: Portrait %ADO_PaperArea: -129 -125 3171 2425 %ADO_ImageableArea: 0 0 3042 2300 %%EndComments /md 148 dict def md begin /currentpacking where {pop /sc_oldpacking currentpacking def true setpacking}if %%BeginFile: adobe_psp_basic %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /bd{bind def}bind def /xdf{exch def}bd /xs{exch store}bd /ld{load def}bd /Z{0 def}bd /T/true /F/false /:L/lineto /lw/setlinewidth /:M/moveto /rl/rlineto /rm/rmoveto /:C/curveto /:T/translate /:K/closepath /:mf/makefont /gS/gsave /gR/grestore /np/newpath 14{ld}repeat /$m matrix def /av 81 def /por true def /normland false def /psb-nosave{}bd /pse-nosave{}bd /us Z /psb{/us save store}bd /pse{us restore}bd /level2 /languagelevel where { pop languagelevel 2 ge }{ false }ifelse def /featurecleanup { stopped cleartomark countdictstack exch sub dup 0 gt { {end}repeat }{ pop }ifelse }bd /noload Z /startnoload { {/noload save store}if }bd /endnoload { {noload restore}if }bd level2 startnoload /setjob { statusdict/jobname 3 -1 roll put }bd /setcopies { userdict/#copies 3 -1 roll put }bd level2 endnoload level2 not startnoload /setjob { 1 dict begin/JobName xdf currentdict end setuserparams }bd /setcopies { 1 dict begin/NumCopies xdf currentdict end setpagedevice }bd level2 not endnoload /pm Z /mT Z /sD Z /realshowpage Z /initializepage { /pm save store mT concat }bd /endp { pm restore showpage }def /$c/DeviceRGB def /rectclip where { pop/rC/rectclip ld }{ /rC { np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K clip np }bd }ifelse /rectfill where { pop/rF/rectfill ld }{ /rF { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl fill gR }bd }ifelse /rectstroke where { pop/rS/rectstroke ld }{ /rS { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K stroke gR }bd }ifelse %%EndFile %%BeginFile: adobe_psp_colorspace_level1 %%Copyright: Copyright 1991-1993 Adobe Systems Incorporated. All Rights Reserved. /G/setgray ld /:F/setrgbcolor ld %%EndFile %%BeginFile: adobe_psp_uniform_graphics %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /@a { np :M 0 rl :L 0 exch rl 0 rl :L fill }bd /@b { np :M 0 rl 0 exch rl :L 0 rl 0 exch rl fill }bd /arct where { pop }{ /arct { arcto pop pop pop pop }bd }ifelse /x1 Z /x2 Z /y1 Z /y2 Z /rad Z /@q { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct fill }bd /@s { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct :K stroke }bd /@i { np 0 360 arc fill }bd /@j { gS np :T scale 0 0 .5 0 360 arc fill gR }bd /@e { np 0 360 arc :K stroke }bd /@f { np $m currentmatrix pop :T scale 0 0 .5 0 360 arc :K $m setmatrix stroke }bd /@k { gS np :T 0 0 :M 0 0 5 2 roll arc fill gR }bd /@l { gS np :T 0 0 :M scale 0 0 .5 5 -2 roll arc fill gR }bd /@m { np arc stroke }bd /@n { np $m currentmatrix pop :T scale 0 0 .5 5 -2 roll arc $m setmatrix stroke }bd %%EndFile %%BeginFile: adobe_psp_customps %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /$t Z /$p Z /$s Z /$o 1. def /2state? false def /ps Z level2 startnoload /pushcolor/currentrgbcolor ld /popcolor/setrgbcolor ld /setcmykcolor where { pop/currentcmykcolor where { pop/pushcolor/currentcmykcolor ld /popcolor/setcmykcolor ld }if }if level2 endnoload level2 not startnoload /pushcolor { currentcolorspace $c eq { currentcolor currentcolorspace true }{ currentcmykcolor false }ifelse }bd /popcolor { { setcolorspace setcolor }{ setcmykcolor }ifelse }bd level2 not endnoload /pushstatic { ps 2state? $o $t $p $s }bd /popstatic { /$s xs /$p xs /$t xs /$o xs /2state? xs /ps xs }bd /pushgstate { save errordict/nocurrentpoint{pop 0 0}put currentpoint 3 -1 roll restore pushcolor currentlinewidth currentlinecap currentlinejoin currentdash exch aload length np clippath pathbbox $m currentmatrix aload pop }bd /popgstate { $m astore setmatrix 2 index sub exch 3 index sub exch rC array astore exch setdash setlinejoin setlinecap lw popcolor np :M }bd /bu { pushgstate gR pushgstate 2state? { gR pushgstate }if pushstatic pm restore mT concat }bd /bn { /pm save store popstatic popgstate gS popgstate 2state? { gS popgstate }if }bd /cpat{pop 64 div G 8{pop}repeat}bd %%EndFile %%BeginFile: adobe_psp_basic_text %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /S/show ld /A{ 0.0 exch ashow }bd /R{ 0.0 exch 32 exch widthshow }bd /W{ 0.0 3 1 roll widthshow }bd /J{ 0.0 32 4 2 roll 0.0 exch awidthshow }bd /V{ 0.0 4 1 roll 0.0 exch awidthshow }bd /fcflg true def /fc{ fcflg{ vmstatus exch sub 50000 lt{ (%%[ Warning: Running out of memory ]%%\r)print flush/fcflg false store }if pop }if }bd /$f[1 0 0 -1 0 0]def /:ff{$f :mf}bd /MacEncoding StandardEncoding 256 array copy def MacEncoding 39/quotesingle put MacEncoding 96/grave put /Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute /agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave /ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute /ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls /registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash /infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation /product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft /guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe /endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge /ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl /daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand /Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave /Oacute/Ocircumflex/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde /macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron MacEncoding 128 128 getinterval astore pop level2 startnoload /copyfontdict { findfont dup length dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall }bd level2 endnoload level2 not startnoload /copyfontdict { findfont dup length dict copy begin }bd level2 not endnoload md/fontname known not{ /fontname/customfont def }if /Encoding Z /:mre { copyfontdict /Encoding MacEncoding def fontname currentdict end definefont :ff def }bd /:bsr { copyfontdict /Encoding Encoding 256 array copy def Encoding dup }bd /pd{put dup}bd /:esr { pop pop fontname currentdict end definefont :ff def }bd /scf { scalefont def }bd /scf-non { $m scale :mf setfont }bd /ps Z /fz{/ps xs}bd /sf/setfont ld /cF/currentfont ld /mbf { /makeblendedfont where { pop makeblendedfont /ABlend exch definefont }{ pop }ifelse def }def %%EndFile /currentpacking where {pop sc_oldpacking setpacking}if end % md %%EndProlog %%BeginSetup md begin /pT[1 0 0 -1 29.999 761.009]def/mT[.24 0 0 -.24 29.999 761.009]def /sD 16 dict def %%IncludeFont: Courier /f0_1/Courier :mre /f0_58 f0_1 58 scf /Courier findfont[10 0 0 -10 0 0]:mf setfont %%EndSetup %%Page: 1 1 %%BeginPageSetup initializepage %%EndPageSetup gS 0 0 2300 3042 rC 0 0 :M 0 setlinecap currentscreen 3 1 roll pop pop 60 45 3 -1 roll setscreen np 38 38 :M 52 96 :L 38 96 :L 23 96 :L 38 38 :L eofill -4 -4 40 265 4 4 36 94 @b np 1613 263 :M 1554 277 :L 1554 263 :L 1554 248 :L 1613 263 :L 4 lw eofill 36 265 -4 4 1556 261 4 36 261 @a 36 261 :M 2 setlinecap 8 lw 44 263 :M 71.332 234.996 97.498 217.497 122.5 210.5 :C 147.498 203.497 167.664 202.83 183 208.5 :C 198.331 214.164 216.496 209.33 237.5 194 :C 258.497 178.664 277.995 165.498 296 154.5 :C 313.996 143.498 331.995 140.664 350 146 :C 367.995 151.331 382.494 157.497 393.5 164.5 :C 404.494 171.498 419.16 173.664 437.5 171 :C 455.827 168.331 471.826 173.83 485.5 187.5 :C 499.159 201.164 519.991 210.83 548 216.5 :C 575.992 222.163 595.491 222.997 606.5 219 :C 617.491 214.997 640.323 226.163 675 252.5 :C 709.657 278.83 735.655 296.495 753 305.5 :C 770.322 314.495 791.821 321.328 817.5 326 :C 843.154 330.662 866.486 324.995 887.5 309 :C 908.487 292.995 928.985 287.829 949 293.5 :C 968.986 299.162 985.318 300.329 998 297 :C 1010.652 293.662 1027.984 289.162 1050 283.5 :C 1071.984 277.829 1110.316 270.996 1165 263 :C stroke 1083 275 :M 0 setlinecap np 38 638 :M 52 696 :L 38 696 :L 23 696 :L 38 638 :L eofill -4 -4 40 865 4 4 36 694 @b np 1613 863 :M 1554 877 :L 1554 863 :L 1554 848 :L 1613 863 :L 4 lw eofill 36 865 -4 4 1556 861 4 36 861 @a 36 861 :M 2 setlinecap 8 lw 344 863 :M 371.328 834.987 397.493 817.488 422.5 810.5 :C 447.494 803.488 467.659 802.821 483 808.5 :C 498.326 814.154 516.492 809.321 537.5 794 :C 558.492 778.654 577.991 765.489 596 754.5 :C 613.991 743.488 631.99 740.655 650 746 :C 667.99 751.322 682.489 757.488 693.5 764.5 :C 704.489 771.488 719.155 773.655 737.5 771 :C 755.822 768.322 771.821 773.821 785.5 787.5 :C 799.155 801.155 819.987 810.821 848 816.5 :C 875.987 822.154 895.486 822.988 906.5 819 :C 917.486 814.987 940.318 826.153 975 852.5 :C 1009.652 878.821 1035.65 896.486 1053 905.5 :C 1070.317 914.486 1091.816 921.319 1117.5 926 :C 1143.15 930.653 1166.482 924.986 1187.5 909 :C 1208.482 892.986 1228.981 887.82 1249 893.5 :C 1268.981 899.153 1285.313 900.32 1298 897 :C 1310.647 893.653 1327.979 889.153 1350 883.5 :C 1371.98 877.82 1410.312 870.987 1465 863 :C stroke 1383 875 :M 0 setlinecap np 338 525 :M 268 542 :L 268 525 :L 268 508 :L 338 525 :L eofill 37 529 -8 8 272 521 8 37 521 @a -4 -4 40 565 4 4 36 486 @b -4 -4 340 565 4 4 336 486 @b 39 375 :M f0_58 sf -.187(snd)A 1 G 71 492 171 62 rF 72 538 :M 0 G (shift)S 30 975 :M -.019(\(shift-time snd shift\))A endp %%Trailer end % md %%EOF nyquist-3.05/docsrc/nyquist/gaussian-fig.ps0000644000175000000620000000664011466723256020117 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: gaussian-fig.ps %%CreationDate: Wed Jul 13 12:15:59 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2773 ASCII Bytes image nG`Lfn,MtY!r)]nn,MtY!pfd`n,MtY!pf^^n,MtY"7,`05Oe^Drr_Tdn3?FBo)Agd]PcWrs7$$h cKF]snG`O'qsaXTrrKk2nGi"X!Ik":s7--hrW)ods7--hrW%E:s7-*jrVlfcs7-*krVlhHnc/.Z "8i)tJ+o)Amls8INJJ+EX1rrrB$rr<"Jo)J:\"o\K#s8RT>s760nqu?Zqs1e.)o)Amj s8N&u^[hEqrrr#mrr<#5o)J:\"loIYs8V!Is760nj8T&Xs53DIo)AmRrVf%]ht$grr`#qs8N#t!:TOZoD\p]s8W)trrDNZ s7?6qn,NFeJ,fQ;oDeF^"7Q9irr2otp[eFVrr_0Ys8N#t!;H*boD\pMs8W)trrDfbs7?6mhuE`U rr2umoDeF^"5ikOrr2otqt'jZrr^%%qYpKo!;lBfoD\p-li$h^rrDrfs7?6q^[(jt5QCc^oDeF^ "+TY6rr2otrU^'\rr[cF\GlL-!<)NhoD\oBs8W)trrE#hs7?6mJ,fQJrr2utoDeI_!<2ut!<2ut !<2Tio`"pjrr2utrr2utoDeI_!<2ut!WITJrr@Q@s7H$jrVllsrVllso`+Ua!<)lr!<2rs!<2Wjp&>$hrVllsr;QbHp&F^b!;l`p !<2or!.X\Ap&>3ms8VihrqucrJ+`j7rrr/ss6KX_r;Qc3p&F^b"o&&sli$h\rrBh,s7QBrp](9Z rVf%[rrBh,s7QBqn,NFRrVl`p!8mJLp&>3as8VhtIf03Ght@$BrrCsTrrE&rrrDN\s7QBlhu3QT rqucrn+H_RrrCsTrrE&rrrDfds7QBl^]"04rqucrp\"RZrrBh4rrE&rrrDrhs7QBl^]"05rdXnH !;lHhp&>#ArVllsr;Qcqp&F^b!.XtI!<2or!<)TjpAY-lr;Qcrr;Qcrp&Fac!<2or!<2or!<2Zk pAY-kr;Qcrqu6YGpAajd!<)iq!<2lq!.X_BpAY-ir;Qcrqu6Z2pAajd!;l]o!WITHrrBh-s7ZHm p\b$krql]qhtI*DrrDNcrrE&qrrCsMs7ZHmn,31crql]qn+QeTrrCsSrrE&qrrDN]s7ZHmhu*KS rql]qp\+X\rrBh3rrE&qrrDris7ZHmJ,K1*krqZQo^\Ij(rrD6YrrE&orrCC?s7lTo+8Z!;rqZQonbE.[rrDumrrE&orrN*`q>^Bm#(Q[Q KE(u?r;Qcrqu6lhs8Tn7s8Dlq,QI`Bn,In7J7&9Tn,In7s53hUp]&#,s6ou;pBSJ3s6ou;rrE&U !!*&grrE&es7$$grpTmVrrE&es7$$grpTmCs8;lshu*KSp\"Odhu*KSrVZ]nrrA\hrrDBXrrB8# rrDlms8;ls?i9p(p\"Odhu*KSp&+jgrrM-jrVlorGP1t9hu*KSnGN=arrCsSrrDN\rrBh3rrE#q s8;lsO8T"Xj7WEPO8T"Xq#(0Js*t~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/adagio.mss0000644000175000000620000011673111466723256017151 0ustar stevestaffAdagio @Index(Adagio) is an easy-to-use, non-procedural notation for scores. In Adagio, text commands are used to specify each note. If you are new to Adagio, you may want to glance at the examples in Section @ref(adag-examples-sec) starting on page @pageref(adag-examples-sec) before reading any further. A note is described in Adagio by a set of attributes@Index(attributes), and any attribute not specified is ``inherited'' from the previous line. Attributes may appear in any order and must be separated by one or more blanks. An attribute may not contain any blanks. The attributes are: time@Index(time), pitch@Index(pitch), loudness@Index(loudness), voice@Index(voice) number, duration@Index(duration), and articulation@Index(articulation). Adagio has been used to program a variety of hardware and software synthesizers, and the Adagio compiler can be easily adapted to new environments. Although not originally intended for MIDI, Adagio works quite well as a representation for MIDI scores. Adagio has been extended to allow MIDI controller data such as modulation wheels, pitch bend, and volume, MIDI program commands to change timbre, and System Exclusive messages. A note command in Adagio must be separated from other notes. Usually, notes are distinguished by writing each one on a separate line. Notes can also be separated by using a comma or semicolon as will be described below. Besides notes, there are several other types of commands: @begin(enumerate) An asterisk@Index(asterisk) (@code(*)) in column one (or immediately after a comma, semicolon, or space) indicates that the rest of the line is a comment@Index(comment). The line is ignored by Adagio, and is therefore a good way to insert text to be read by people. Here are some examples: @begin(programexample) * This is a comment. T150 G4 * This is a comment too! T150 G4 ;* So is this. @end(programexample) An empty command (a blank@Index(blank) line, for example) is ignored as if it were a comment@Index(comment)@foot(To be consistent, a blank line ought to specify zero attributes and generate a note that inherits all of its attributes from the previous one. Adagio is intentionally inconsistent in this respect.). An exclamation point@Index(exclamation point)@index(!) (!) in column one (or immediately after a comma or semicolon) indicates a special command@Index(special command). A special command does not generate a note. Special commands follow the ``!'' with no intervening spaces and extend to the end of the line, for example: @begin(programexample) !TEMPO 100 @end(programexample) Control change commands are used to control parameters like pitch bend, modulation, and program (timbre). Control change commands can be specified along with notes or by themselves. A command that specifies control changes without specifying a pitch will not produce a note. @end(enumerate) Adagio is insensitive to case@Index(case), thus ``A'' is equivalent to ``a'', and you can mix upper and lower case letters freely. @section[Specifying Attributes] A note is indicated by a set of attributes. Attributes are indicated by a string of characters with no intervening spaces because spaces separate attributes. The attributes are described below. The default unit of time is a centisecond (100@+[th]'s), but this can be changed to a millisecond (1000@+[th]'s) using the @code(!MSEC) command and reset to centiseconds with @code(!CSEC) (see Section @ref(millisec-sec)). In the descriptions below, the term ``time unit'' will be used to mean whichever convention is currently in effect. @subsection[Time] The time@Index(time) attribute specifies when to start the note. A time is specified by a ``T@Index(T)'' followed by a number representing time units or by a duration (durations are described below). Examples: @begin(programexample) T150 ** 1.5 sec (or .15 sec) TQ3 ** 3 quarter note's duration @end(programexample) If no time is specified, the default time@Index(default time) is the sum of the time and duration attributes of the previous note. (But see Section @ref(next-time-sec).) Time is measured relative to the time of the most recent Tempo@Index(Tempo) or Rate@Index(Rate) command. (See the examples in Section @ref(adag-examples-sec) for some clarification of this point.) @subsection[Pitch] The pitch@Index(pitch) attribute specifies what frequency to produce. Standard scale pitches are named by name, using @code(S) for sharp@Index(sharp), @code(F) for flat@Index(flat), and (optionally) @code(N) for natural@Index(natural). For example, @code(C) and @code(CN) represent the same pitch, as do @code(FS) and @code(GF) (F sharp and G flat). Note that there are no bar lines, and accidentals to not carry forward to any other notes as in common practice notation. Octaves@Index(octave specification) are specified by number. @code(C4) is middle C, and @code(B3) is a half step lower. @code(F5) is the top line of the treble clef, etc. (Adagio octave numbering follows the ISO standard, but note that this is not universal. In particular, Yamaha refers to middle C as C3.) Accidentals@Index(accidentals)@index[S (Adagio Sharp)]@index[F (Adagio Flat)] can go before or after the octave number, so @code(FS3) and @code(F3S) have the same meaning. An alternate notation for pitch is @code(P)@i(n), where @i(n) is an integer representing the pitch.@index[P (Adagio Pitch)] Middle C@index(Middle C) (C4) is equivalent to @code(P60), @code(CS4) is @code(P61), etc. If you do not specify an octave@Index(octave specification), Adagio will choose one for you. This is done by picking the octave that will make the current pitch as close to the previous pitch as possible. In the case of augmented fourths or diminished fifths, there are two equally good choices. Adagio chooses the lower octave. @subsection[Duration] Duration@Index(duration) is specified by a letter indicating a number of beats, followed by one or several modifiers. The basic duration codes are: @begin(display) @code(W)@Index[W (Adagio Whole note)] (whole@index(whole note), 4 beats), @code(H)@Index[H (Adagio Half note)] (half@index(half note), 2 beats), @code(Q)@Index[Q (Adagio Quarter note)] (quarter@index(quarter note), 1 beat), @code(I)@Index[I (Adagio eIght note)] (eighth@Index(eighth note), 1/2 beat), @code(S)@Index[S (Adagio Sixteenth note)] (sixteenth@Index(sixteenth note), 1/4 beat), @code(%)@Index[% (Adagio thirtysecond note)] (thirtysecond@index(thirtysecond note), 1/8 beat), and @code(^)@index[^ (Adagio sixtyfourth note)] (sixtyfourth@index(sixtyfourth note), 1/16 beat). @end(display) Note that @code(E) is a pitch, so eighth-notes use the duration code @code(I). The default tempo is 100 beats per minute (see Section @ref(tempo-sec)). These codes may be followed by a @code(T) (triplet@Index(triplet)@index[T (Adagio Triplet)]), indicating a duration of 2/3 the normal. A dot@Index(dot)@index[. (Adagio)] (@code(.)) after a duration code extends it by half to 3/2 the normal. An integer after a note multiplies its duration by the indicated value (the result is still just one note). Finally, a slash followed by an integer divides the duration by the integer. Like all attributes, duration attributes may not have embedded spaces. Examples: @begin(display) @tabclear @tabset(.5 inches) @code(Q)@\1 beat (quarter note) @code(QT)@\2/3 beat (quarter triplet) @code(W.)@\6 beats(dotted whole note) @code(ST6)@\1 beat (6 sixteenth triplets) @code(H5)@\10 beats(5 half notes) @code(Q3/7)@\3/7 beats @end(display) A duration may be noted by @code(U)@i(n)@Index(U), where @i(n) is an integer indicating 100@+[th]'s of a second (or 1000@+[th]'s), see Section @ref(millisec-sec). For example, @code(U25) is twenty-five time units. Durations may be combined using a plus sign: @begin(programexample) Q+IT ** a quarter tied to an eighth triplet Q/7+W+Q2/7 ** a 7th beat tied to a whole tied to 2/7th beat Q+U10 ** a quarter plus 10 time units @end(programexample) @subsection(Next Time) @label(next-time-sec) The time of the next@Index(next)@index[N (Adagio Next)] command (the next command in the Adagio program text) is normally the time of the current note command plus the duration of the current note. This can be overridden by a field consisting of the letter @code(N) followed by a number indicating time units, or followed by a duration as described above. The next note will then start at the time of the current note plus the duration specified after @code(N). If the next note has an explicit time attribute (@code(T)), then the specified time will override the one based on the previous note. Examples: @begin(programexample) N0 ** start the next note at the same time as this one N50 ** start the next note 0.5 seconds after this one NQT ** start the next note 2/3 beat after the current one NU10+Q ** start after 0.1 seconds plus a quarter @end(programexample) A comma has an effect similar to @code(N0) and is explained in Section @ref(comma-sec). Articulation effects such as @i(staccato) can be produced using @code(N), but it is more convenient to use the articulation attribute described in Section @ref(articulation-sec). @subsection(Rest) Rests@Index(rests)@index[R (Adagio Rest)] are obtained by including the field @code(R) in a note command. The effect of an @code(R) field is to omit the note that would otherwise occur as the result of the current note command. In all other respects, the command is processed just like any other line. This means that attributes such as duration, loudness, and pitch can be specified, and anything specified will be inherited by the note in the next command. Normally, a rest will include just @code(R) and a duration. The fact that a note command specifies a rest is not inherited. For example: @begin(programexample) R H ** a half (two beat) rest RH ** illegal, R must be separated from H by space(s) @end(programexample) Because some synthesizers (e.g. a DX7@Index(DX7)) cannot change programs @Index(program change) (presets) rapidly, it may be desirable to change programs in a rest so that the synthesizer will be ready to play by the end of the rest. See Section @ref(adag-timbre-sec) for an example. @subsection[Articulation] @label(articulation-sec) Articulation@Index(articulation)@index(staccato)@index(legato) in Adagio refers to the percentage of time a note is on relative to the indicated duration. For example, to play a note @i(staccato), you would normally play the note about half of its indicated duration. In Adagio, articulation is indicated by @code(#)@index[# (Adagio articulation)] followed by an integer number indicating a percentage. The articulation attribute does not affect the time of the next command. This example plays two @i(staccato) quarter notes: @begin(programexample) C Q #50 D @end(programexample) To produce overlapping notes, the articulation may be greater than 100. @begin(detail) Be aware that overlapping notes on the same pitch can be a problem for some synthesizers. The following example illustrates this potential problem: @begin(programexample) !TEMPO 60 C Q #160 * starts at time 0, ends at 1.6 sec D I * starts at time 1, ends at 1.8 sec C Q * starts at time 1.5, ends at 3.1 sec? @end(programexample) At one beat per second (tempo 60), these three notes will start at times 0, 1, and 1.5 seconds, respectively. Since these notes have an articulation of 160, each will be on 160% of its nominal duration, so the first note (C) will remain on until 1.6 seconds. But the third note (another C) will start at time 1.5 seconds. Thus, the second C will be started before the first one ends. Depending on the synthesizer, this may cancel the first C or play a second C in unison. In either case, a note-off message will be sent at time 1.6 seconds. If this cancels the second C, its actual duration will be 0.1 rather than 1.6 seconds as intended. A final note-off will be sent at time 3.1 seconds. @end(detail) @subsection[Loudness] Loudness@Index(loudness)@index(velocity) is indicated by an @code(L) followed by a dynamic marking from the following: @code(PPP)@Index[PPP (Adagio dynamic)]@Index[LPPP (Adagio dynamic)], @code(PP)@Index[PP (Adagio dynamic)]@Index[LPP (Adagio dynamic)], @code(P)@Index[P (Adagio dynamic)]@Index[LP (Adagio dynamic)], @code(MP)@Index[MP (Adagio dynamic)]@Index[LMP (Adagio dynamic)], @code(MF)@Index[MF (Adagio dynamic)]@Index[LMF (Adagio dynamic)], @code(F)@Index[F (Adagio dynamic)]@Index[LF (Adagio dynamic)], @code(FF)@Index[FF (Adagio dynamic)]@Index[LFF (Adagio dynamic)], @code(FFF)@Index[FFF (Adagio dynamic)]@Index[LFFF (Adagio dynamic)]. Alternatively, a number from 1 to 127 may be used. The loudness attribute is the MIDI note velocity. (Note that a MIDI velocity of 0 means ``note-off,'' so the minimum loudness is 1.) The dynamic@Index(dynamic markings) markings are translated into numbers as follows: @begin(display) @tabclear @tabset(0.8 in, 3 in, 3.8 in) @code(Lppp)@\20@\@code(Lmf)@\58 @code(Lpp)@\26@\@code(Lf)@\75 @code(Lp)@\34@\@code(Lff)@\98 @code(Lmp)@\44@\@code(Lfff)@\127 @end(display) @subsection[Voice] The voice@Index(voice)@index[V (Adagio Voice)] attribute tells which of the 16 MIDI channels to use for the note. The voice attribute consists of a @code(V) followed by an integer from 1 (the default) to 16. @begin(detail) There is a limit to how many notes can be played at the same time on a given voice (MIDI channel). Since the limit depends upon the synthesizer, Adagio cannot tell you when you exceed the limit. Similarly, Adagio cannot tell whether your synthesizer is set up to respond to a given channel, so there is no guarantee that what you write will actually be heard. @end(detail) @subsection[Timbre (MIDI Program)] @label(adag-timbre-sec) A MIDI program@Index(MIDI program)@index[Z (Adagio program)] (synthesizer preset@Index(preset)) can be selected using the attribute @code(Z)@i(n), where @i(n) is the program number (from 1 to 128). Notice that in MIDI, changing the program on a given channel will affect @i(all) notes on that channel and possibly others. Adagio treats MIDI program changes as a form of control change. @begin(detail) For many synthesizers, you will not be able to change programs at the start of a note or during a note. Change the program during a rest instead. For example: @begin(programexample) R I Z23 V4 ** change MIDI channel 4 to program 23 during rest A4 ** play a note on channel 4 @end(programexample) Check how your synthesizer interprets program numbers. For example, the cartridge programs on a DX7 can be accessed by adding 32 to the cartridge program number. Cartridge program number 10 is specified by @code(Z42). @end(detail) As in MIDI, the Adagio timbre is a property of the voice (MIDI channel), so the timbre will not be inherited by notes on a different channel; to change the timbre on multiple voices (channels), you must explicitly notate each change. @subsection[Tempo] @label(tempo-sec) The length of a beat may be changed using a Tempo@Index(Tempo) command@index(!Tempo): @begin(programexample) !TEMPO @i(n) @end(programexample) where @i(n) indicates beats per minute. The exclamation mark tells Adagio that this is a special command line rather than a note definition. A special command takes the place of a note specification. No other attributes should be written on a line with a special command. The @code(!TEMPO) command is associated with a time, computed as if the @code(!TEMPO) command were a note. The time@Index(time) attribute (@code(T)) of all succeeding notes is now measured relative to the time of the @code(!TEMPO) command. The new tempo starts at the @code(!TEMPO) command time and affects all succeeding notes. Durations specified in time units (for example @code(U58), @code(N15)) are not affected by the @code(!TEMPO) command, and numerical times (for example @code(T851)) are computed relative to the time of the last @code(!TEMPO) command. The @code(!TEMPO) command is fairly clever about default durations@Index(default durations). If the last duration specified before the @code(!TEMPO) command is symbolic (using one of @code(^),@code(%), @code(S), @code(I), @code(Q), @code(H), or @code(W) ), then the default duration for the node after the @code(!TEMPO) command will be modified according to the tempo change. Consider the following tempo change: @begin(programexample) !TEMPO 60 A4 H !TEMPO 120 G @end(programexample) In this example, the first note will last 2 seconds (2 beats at 60 beats per minute). The second note inherits the duration (H) from the first note, but at 120 beats per minute, the second note will last only 1 second. If the duration had been specified @code(U200) (also a duration of 2 seconds), the second note would also last 2 seconds because the @code(!TEMPO) command does not affect times or durations specified numerically in time units. If the duration is the sum of a symbolic and a numeric specification, the inherited duration after a @code(!TEMPO) command is undefined. @subsection(Rate) The @code(!RATE)@Index(rate)@index(!Rate) command scales all times including those specified in hundredths of seconds. A rate of 100 means no change, 200 means twice as fast, and 50 means half as fast. For example, to make a piece play 10% faster, you can add the following command at the beginning of the score: @begin(programexample) !RATE 110 @end(programexample) @code(!RATE) and @code(!TEMPO) commands combine, so @begin(programexample) !RATE 200 !TEMPO 70 @end(programexample) will play 70 beats per minute at double the normal speed, or 140 beats per minute. Like @code(!TEMPO), the time of the @code(!RATE) command is added to the time attribute of all following notes up to the next @code(!TEMPO) or @code(!RATE) command. Two @code(!RATE) commands do not combine, so a @code(!RATE) command only affects the rate until the next @code(!RATE) command. Although @code(!TEMPO) and @code(!RATE) can occur in the middle of a note (using @code(N), @code(T), etc.) they do not affect a note already specified. This property allows multiple tempi to exist simultaneously (see Section @ref(multipletempi-sec)). @section[Default Attributes] @label(default-sec) If an attribute is omitted, the previous one is used by default@Index(default) (with the exception of the time attribute). The default values for the first note, which are inherited by succeeding notes until something else is specified, are given below in Adagio notation: @begin(display) @tabclear @tabset(1.5 inch) Time@\@code(T0) Pitch@\@code(C4) Duration@\@code(Q) Articulation@\@code(#100) Loudness@\@code(LFFF) Voice@\@code(V1) Tempo@\@code(!TEMPO 100) Rate@\@code(!RATE 100) @end(display) Control changes (including timbre or MIDI program, specified by @code(Z)) have no default value and are only sent as specified in the score. @p(Important:) the rules for determining when a command will play a note are as follows (and this has changed slightly from previous versions): @begin(enumerate) If a special (@code(!)) command or nothing is specified, e.g. a blank line, do @i(not) play a note. If @code(R) (for ``rest'') is specified, do @i(not) play a note. Otherwise, if a pitch is specified, @i(do) play a note. Otherwise, if no control changes (or program changes) are specified (so this is a command with non-pitch attributes and no control changes), @i(do) play a note. @end(enumerate) Another way to say this is ``Special commands and commands with rests (@code(R)) do not play notes. Otherwise, play a note if a pitch is specified or if no control is specified.'' @section[Examples] @label(adag-examples-sec) The following plays the first two bars of ``Happy Birthday''. Note that Adagio knows nothing of bar lines, so the fact that the first note occurs on beat 3 or that the meter is three-four is of no consequence: @begin(programexample) *Example 1 ** Happy Birthday tune (C major) !TEMPO 120 G4 I. LF G4 S A4 Q G4 C5 B4 H @end(programexample) The time attribute for the first note is zero (@code(0)). The second note will occur a dotted eighth later, etc. Notice that no timbre or rate was specified. Adagio will provide reasonable default values of 1 and 100, respectively. The following example plays the first four bars of an exercise from Bartok@Index(Bartok)'s Mikrokosmos@Index(Mikrokosmos) (Vol. 1, No. 12). An extra quarter note is inserted at the beginning of each voice in order to allow time to change MIDI programs. The right hand part is played on voice (MIDI channel) 1 and the left hand part on voice 2. Notice the specification of the time attribute to indicate that voice 2 starts at time 0. Also, default octaves are used to reduce typing. @begin(programexample) *Example 2 ** Bartok *voice 1, right hand R Q Z10 V1 ** extra rest for program change A4 H B Q C D H C D Q C B A B C D R *voice 2, left hand T0 R Q Z15 V2 ** extra rest for program change G3 H F Q E D H E D Q E F G F E D R @end(programexample) The next example is the same piece expressed in a different manner, illustrating the interaction between the @code(!TEMPO) command and the time attribute. Recall that the time attribute is measured relative to the time of the last @code(!TEMPO) command: @begin(programexample) *Example 3 ** 4 measures in 2 sections !Tempo 100 *Voice 1, Measures 1 & 2 R Q Z10 V1 A4 H B Q C D H C *Voice 2, Measures 1 & 2 T0 R Q Z15 V2 G3 H F Q E D H E H !TEMPO 100 *Voice 1, Measures 3 & 4 * note that Z10 is still in effect for V1 V1 D4 Q C B A B C D R *Voice 2, Measures 3 & 4 T0 V2 D3 Q E F G F E D R @end(programexample) The piece is written in 4 sections. The first plays a rest followed by two measures, starting at time 0. The next section changes the time back to zero and plays two measures of the left hand part (voice 2). The next command (!TEMPO 100) sets the tempo to 100 (it already is) @i(and) sets the reference time to be two measures into the piece. Therefore, the next note @code((D4)) will begin measure 3. The @code(D3) that begins the last group of notes has a @code(T0) attribute, so it will also start at measure 3. Notice how the @code(!TEMPO) command can serve to divide a piece into sections@Index(sections, Adagio). The last example will show yet another way to express the same piece of music using the ``Next'' attribute. Only the first bar of music is given. @begin(programexample) *Example 4 ** use of the Next attribute !Tempo 100 R Q Z10 V1 N0 R Q Z15 V2 A4 H V1 N0 G3 V2 B4 Q V1 N0 F3 V2 C4 Q V1 N0 E3 V2 @end(programexample) Here, each pair of lines represents two simultaneous notes. The @code(N0) attribute forces the second line to start at the same time as the first line of each pair. Because of the large intervals, octave numbers (3 and 4) are necessary to override the default octave for these pitches. @section(Advanced Features) Beyond the simple notation described above, Adagio supports a number of features. (See also the next chapter.) @subsection(Time Units and Resolution) @label(millisec-sec)@index(time units)@index(resolution) The default time unit is 10ms (ten milliseconds or one centisecond or 100@+(th) of a second), but it is possible to change the basic unit to 1ms, or 1000@+(th) of a second. The time unit can be specified by: @begin(display) @tabclear @tabset(0.8 inches) @t(!CSEC)@index(!csec)@\centisecond time units = 100@+(th) @t(!MSEC)@index(!msec)@\millisecond time units = 1000@+(th) @end(display) The time unit remains in effect until the next @code(!CSEC) or @code(!MSEC) command. @subsection(Multiple Notes Per Line) @label(comma-sec) @index(multiple commands) Notes can be separated by commas@Index(commas)@index[, (Adagio)] or semicolons@Index(semicolon, Adagio)@index[; (Adagio)] as well as by starting a new line. A comma is equivalent to typing @code(N0) and starting a new line. In other words, the next note after a comma will start at the same time as the note before the comma. In general, @i(use commas to separate the notes of a chord.) A semicolon is equivalent to starting a new line. In general, @i(use semicolons to group notes in a melody). Here is yet another rendition of the Bartok: @begin(programexample) *Example 5 ** use of semicolons !Tempo 100 R Q Z10 V1 A4 H; B Q; C; D H; C; D Q; C; B; A; B; C; D; R T0 R Q Z15 V2 G3 H; F Q; E; D H; E; D Q; E; F; G; F; E; D; R @end(programexample) This example is similar to Example 2, except semicolons are used. Note how semicolons make the two lines of music stand out. The next example is similar to Example 4, except commas are used and four bars are notated. The music below is treated as a sequence of 2-note chords, with each chord on a separate line: @begin(programexample) *Example 6 ** use of commas !Tempo 100 R Q Z10 V1, R Q Z15 V2 A4 H V1, G3 V2 B4 Q V1, F3 V2 C4 V1, E3 V2 D4 H V1, D3 V2 C4 V1, E3 V2 D4 Q V1, D3 V2 C4 V1, E3 V2 B4 V1, F3 V2 A4 V1, G3 V2 B4 V1, F3 V2 C4 V1, E3 V2 D4 V1, D3 V2 R @end(programexample) @subsection(Control Change Commands) @index(Control change)@index[~ (Adagio)] Any control change can be specified using the syntax ``@t[~@i(n)(@i(v))]'', where @i(n) is the controller number (0 - 127), and @i(v) is the value. In addition, Adagio has some special syntax for some of the commonly used control changes (note that Pitch bend, Aftertouch, and MIDI Program Change are technically not MIDI control changes but have their own special message format and status bytes): @begin(display) @tabclear @tabset(0.5 inch) K@\Portamento switch@Index(Portamento switch)@Index[K (Adagio control)] M@\Modulation wheel@Index(Modulation wheel)@Index[M (Adagio control)] O@\Aftertouch@Index(Aftertouch)@Index[O (Adagio control)] X@\Volume@Index(Volume)@Index[X (Adagio control)] Y@\Pitch bend@Index(Pitch bend)@Index[Y (Adagio control)] Z@\Program Change@Index(Program)@Index[Z (Adagio program)] @end(display) The letter listed beside each control function is the Adagio command letter. For example, @code(M23) is the command for setting the modulation wheel to 23. Except for pitch bend, the portamento switch, and MIDI Program Change, all values range from 0 to 127. Pitch bend is ``off'' or centered at 128, and has a range from 0 to 255 (MIDI allows for more precision, but Adagio does not). Turn on portamento with @code(K127) and off with @code(K0). Programs are numbered 1 to 128 to correspond to synthesizer displays. @p(About volume:) Midi volume is just a control, and the Midi standard does not say what it means. Typically it does what the volume pedal does; that is, it scales the amplitude in a continuously changeable fashion. In contrast, Midi velocity, which is controlled by the @code(L) (loudness) attribute, is part of a Midi note-on command and is fixed for the duration of the note. Typically, these two ways of controlling loudness and amplitude operate independently. In some low-cost synthesizers the numbers seem to be added together internally and volume changes are ignored after the note starts. @p(About pitch bend:) Midi pitch bend is a number from 0 to 16383, where 8192 is the center position. To convert to Midi, Adagio simply multiplies your number by 64, giving values from 0 to 16320. Note that @code(Y128) translates exactly to 8192. The @i(meaning) of pitch bend depends upon your synthesizer and its setting. Most synthesizers let you specify a ``pitch bend range.'' A range of one semitone means that @code(Y255) will produce a bend of approximately one semitone up, and @code(Y0) will bend one semitone down. If the range is 12 semitones, then the same @code(Y255) will bend an octave. Typically, pitch bend is exponential, so each increment in the pitch bend value will bend an equal number of cents in pitch. Control changes can be part of a note specification or independent. In the following example, a middle C is played with a modulation wheel setting of 50 and a pitch bend of 120. Then, at 10 unit intervals, the pitch bend is decreased by 10. The last line sets the portamento time (controller 5) to 80: @begin(programexample) *Example 7 C4 LMF M50 Y120 U100 N10 Y110 N10; Y100 N10; Y90 N10; Y80 N10; Y70 N10; Y60 N10; Y50 N10 ~5(80) @end(programexample) See Section @ref(default-sec) on page @pageref(default-sec) for rules on whether or not a command will play a note. @subsection(Multiple Tempi)@Index(multiple tempi) @label(multipletempi-sec) @Index(polyrhythm) Writing a piece with multiple tempi requires no new commands; you just have to be clever in the use of Tempo and Time. The following plays a 7 note diatonic scale on voice 1, and a 12 note chromatic scale on voice 2: @begin(programexample) *Example 8 ** multiple tempi !TEMPO 70 V1 C4; D; E; F; G; A; B T0 R N0 !TEMPO 120 V2 C4; CS; D; DS; E; F; FS; G; GS; A; AS; B !TEMPO 100 V1 C5, V2 C5 @end(programexample) The third line plays the 7-note diatonic scale on voice 1. The next line contains the tricky part: notice that the time is set back to zero, there is a rest, and a next (@code(N)) attribute is used to specify that the next default time will be at the same time as the current one. This is tricky because a @code(!TEMPO) command cannot have a time (@code(T0)) attribute, and a @code(T0) by itself would create a note with a duration. @code(T0 R N0) says: ``go to time 0, do not play a note, and do not advance the time before the next command''. Thus, the time of the @code(!TEMPO 120) command is zero. After the 12 note scale, the tempo is changed to 100 and a final note is played on each voice. A little arithmetic will show that 7 notes at tempo 70 and 12 notes at tempo 120 each take 6 seconds, so the final notes (@code(C5)) of each scale will happen at the same time. @subsection(MIDI Synchronization) @index(synchronization)@index(clock)@index(MIDI Clock)@index(clock command) The Adagio program can synchronize with external devices using MIDI real time messages. Adagio can act as either a master or slave. As a master, Midi real time messages are generated according to the score. As a slave, the program uses incoming Midi messages to control the timebase against which notes and other events are scheduled. In this way, an external device such as a drum machine or other sequencer can start, stop, and control the tempo of Adagio scores. @p(Note:) the current implementation of synchronization to an external source is very simplistic; it effectively quantizes the score to units of 1/24 of a beat. Since Adagio supports multiple tempi, and Midi clock is based on beats, it is necessary to be explicit in the score about where the clock should start and what is the duration of a quarter note. The @code(!CLOCK) command@index(!Clock) in Adagio turns on a 24 pulse-per-quarter (PPQ) clock at the current tempo and time: @begin(programExample) !TEMPO 100 !CLOCK @end(programexample) A @code(!CLOCK) command must also be inserted for each tempo change that is to be reflected in the Midi clock. Typically, each !TEMPO command will be followed by a !CLOCK command. @begin(detail) Clock commands and thus tempo changes can take place at arbitrary times. It is assumed that tempo changes on an exact 24@+(th) of a beat subdivision (for example, exactly on a beat). If not, the tempo change will take place on the nearest exact 24@+(th) of a beat subdivision. This may be earlier or later than the requested time. @end(detail) To synchronize other systems, e.g. a drum machine, to Adagio, you should make the device a ``slave'' and start Adagio. Adagio will sent a MIDI Start message and 24 Timing Clock messages per quarter note. When you stop Adagio by typing either the space bar or by reaching the end of the score, Adagio will send a MIDI Stop message, which should stop the slave device. To synchronize Adagio to another system, type @code(c) to enable external clock synchronization (see Section @ref(adag-resp-sec)), and type @c(RETURN) as if to start the Adagio score. Adagio will wait for a MIDI Start message and will then synchronize to MIDI Clock messages. A MIDI Stop message will stop the playback as if the space bar were typed. To synchronize one Adagio to another, be sure the ``slave'' is ready and waiting before starting the ``master''. @subsection[System Exclusive Messages] @label(macro-sec) Adagio has a definition facility that makes it possible to send system exclusive parameters. Often, there are parameters on Midi synthesizers that can only be controlled by system exclusive messages. Examples include the FM ratio and LFO rate on a DX7 synthesizer. The following example defines a macro for the DX7 LFO rate and then shows how the macro is used to set the LFO rate for a B-flat whole note in the score. The macro definition is given in hexadecimal, except @t(v) is replaced by the channel (voice) and @t(%1) is replaced by the first parameter. A macro is invoked by writing ``~'' followed by the macro name and a list of parameters@index(!Def): @begin(programexample) !DEF LFO F0 43 0v 01 09 %1 F7 Bf5 W ~LFO(25) @end(programexample) In general, the @t(!DEF) command can define any single MIDI message including a system exclusive message. The message must be complete (including the status byte), and each @t(!DEF) must correspond to just one message. The symbol following @t(!DEF) can be any name consisting of alphanumeric characters. Following the name is a hexadecimal string (with optional spaces), all on one line. Embedded in the string may be the following special characters: @begin(description) @t(v)@\Insert the 4-bit voice (MIDI channel) number. If @t(v) occurs in the place of a high-order hexadecimal digit, replace @t(v) with @t(0v) so that the channel number is always placed in the low-order 4 bits of a data byte. In other words, @t(v) is padded if necessary to fall into the low-order bits. @t(%)@i(n)@\Insert a data byte with the low-order 7 bits of parameter number @i(n). Parameters are numbered 1 through 9. If the parameter value is greater than 127, the high-order bits are discarded. @t(^)@i(n)@\Insert a data byte with bits 7 through 13 of parameter number @i(n). In other words, shift the value right 7 places then clear all but the first 7 bits. Note that 14-bit numbers can be encoded by referencing the same parameter twice; for example, @t(%4^4) will insert the low-order followed by the high-order parts of parameter 4 into two successive data bytes. @end(description) Parameters are separated by commas, but there may be no spaces. The maximum number of parameters allowed is 9. Here is an example of definitions to send a full-resolution pitch bend command and to send a system exclusive command to change a DX7 parameter@foot[My TX816 Owner's Manual gives an incorrect format for the change parameter sysex command (according to the manual, there is no data in the message!) I am assuming that the data should be the last byte before the EOX and that there is no byte count. If you are reading this, assume that I have not tested this guess, nor have I tested this example.]. @begin(programexample) * Define macro for pitch bend commands: !DEF bend Ev %1 ^1 A ~bend(8192) ** 8192 is "pitch bend off" * Change the LFO SPEED: * SYSEX = F0, Yamaha = 43, Substatus/Channel = 1v, * Group# = 01, Parameter# = 9, Data = 0-99, EOX = F7 !DEF lfospeed F0 43 1v 01 09 %1 F7 * now use the definitions: G4 ~bend(7567) N40 ~lfospeed(30) N35 @end(programexample) @subsection(Control Ramps) @label(macroramp-sec) The @t(!RAMP) command@index(!Ramp) can specify a smooth control change from one value to another. It consists of a specification of the starting and ending values of some control change, a duration specifying how often to send a new value, and a duration specifying the total length of the ramp. @begin(programexample) !RAMP X10 X100 Q W2 !RAMP ~23(10) ~23(50) U20 W !RAMP ~lfo(15) ~lfo(35) U10 @end(programexample) The first line says to ramp the volume control (controller number 7) from 10 to 100, changing at each quarter note for the duration of two whole notes. The second line says to ramp controller number 23 from value 10 to value 50, sending a new control change message every 20 time units. The overall duration of the ramp should be equivalent to a whole note (@t(W)). As shown in the third line, even system exclusive messages controlled by parameters can be specified. If the system exclusive message has more than one parameter, only one parameter may be ``ramped''; the others must remain the same. For example, the following would ramp the second parameter: @begin(programexample) !RAMP ~mysysex(4,23,75) ~mysysex(4,100,75) U10 W @end(programexample) @begin(detail) A rather curious and extreme use of macros and ramps is illustrated in the following example. The @t(noteon) macro starts a note, and @t(noteoff) ends it. Ramps can now be used to emit a series of notes with changing pitches or velocities. Since Adagio has no idea that these macros are turning on notes, it is up to the programmer to turn them off! @begin(programexample) !DEF noteon 9v %1 %2 !DEF noteoff 8v %1 %2 ~noteon(48,125) ~noteoff(48,126) * turn on some notes !RAMP ~noteon(36,125) ~noteon(60,125) Q W NW * turn them off !RAMP ~noteoff(60,50) ~noteoff(36,50) Q W NW @end(programexample) @end(detail) @subsection(The !End Command) @label(end-sec)@index(!End)@index(end command) The special command @code(!END) marks the end of a score. Everything beyond that is ignored, for example: @begin(programexample) * this is a score C; D; E; F; G W !END since the score has ended, this text will be ignored @end(programexample) See Section @ref(seqread-sec) for a further discussion. @subsection(Calling C Routines) @label(call-sec) It is possible to call C routines from within Adagio scores. The routine must be written in C, the name must be entered into a special table, and the compiled routine must be linked into Adagio or some application that uses Adagio sequences. Only the command syntax will be described here. (See Section @ref(call-impl-sec) for more information.) The @code(!CALL) command@index(!Call)@index(Call command) calls a C routine that can in turn invoke a complex sequence of operations. Below is a call to a trill@index(trill) routine, which is a standard routine in Adagio. The parameters are the base pitch of the trill, the total duration of the trill, the interval in semitones, the duration of each note of the trill, and the loudness. Notice that both numbers and Adagio notation can be used as parameters: @begin(programexample) !CALL trill(A5,W,2,S,Lmf) T278 V1 @end(programexample) @i(The parameter list should have no spaces), and parameters are separated by commas. Following the close parenthesis, you may specify other attributes such as the starting time and voice as shown in the example above. A parameter may be an Adagio pitch specification, an Adagio duration, an Adagio loudness, a number, or an ASCII character within single quotes, e.g. @t('a') is equivalent to @t(97) because 97 is the decimal encoding of ``a'' in ASCII. The @code(!CALL) may be followed by a limited set of attributes. These are time (@t(T)), voice (@t(V)), and next time (@t(N)). The @code(!CALL) is made at the current time if no time is specified, and the time of the next adagio command is the time of the @code(!CALL) unless a next time is specified. In other words, the default is @t(N0). @subsection(Setting C Variables) In addition to calling C routines, there is another way in which scores can communicate with C. As with @code(!CALL), specific C code must be linked before these commands can be used. (See Section @ref(set-sec) for details.) The @code(!SETI) command@index(!Seti)@index(seti commnad) sets an integer variable to a value, and the @code(!SETV) command@index(!Setv)@index(setv command) sets an element of an integer array. For example, the next line sets the variable @t(delay) to 200 and sets @t(transposition[5]) to -4 at time 200: @begin(programexample) !SETI delay 200 !SETV transposition 5 -4 T200 @end(programexample) As with the @code(!CALL) command, these commands perform their operations at particular times according to their place in the Adagio score. This makes it very easy to implement time-varying parameters that control various aspects of an interactive music system. nyquist-3.05/docsrc/nyquist/hyperbolic-fig.ps0000644000175000000620000000700111466723256020435 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: hyperbolic-fig.ps %%CreationDate: Wed Jul 13 12:16:30 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2868 ASCII Bytes image nG`Lfn,MnW!<2HenG`Lfn,MnW!WITs760nrVukHs*sV>o)Amls8N&u ^[hErs8W$#EW6"<^[hErs8Vou\,QF-^[hErrs&>sF8l4>ht$g=rs&>sIJuJ2ht$g=rs&>np&>!k ht$g=rs&Ga49#9[n+-MLrrqlkrr<#eo)J:\"n2Kjs8VQYs760nn,NB:s7c*ao)AmNs8N&up[\@T rrq<[rr<#mo)J:\"lK@Zs8Vues760n^]4<5s82Beo)Am.s8INJqssdXrrp1;rr<#so)J:\"b6RO s8W&gs760nJ,fNJs8DNgo)AlCs8N&urUU![rs&K&s8INJrpp*\rs&K&s8N&urpp*\rs&K&s8N&u rpp*\rr`6"s8N#t!.XV?oD\pks8W)trr@Q?s7?6qrVuosJ,fOuoDeF^"8i,urr2ot^[qKsrr`/m rVlfr!5J.*oD\pilh^V[rrBh*s7?6mpZqeWrr2uUoDeF^#P[Q_r]gG_ht-m>rr`#]qu6Tp!8mDJ oD\p]pUL5%rrDNZs7?6mn,NFerr2ueoDeF^"7Q9irr2otn+6SNrs.H]s8INJs6oRZoD\pMs8W)t rrDfbs7?6mhuE`Urr2umoDeF^"2Fm9rr2otp[eFVrr^%9s8N#t!;lBfoD]'1s8W(Js8Vufs7?6m J,fQJrr2uqoDeF^"+U@Nrr2otrU^'\rr[cNs8N#t!<)Nho`"pjrr2utrr2usoDeI_!<2ut"TEoN s8MWio`"pjrr2utrr2utoDeI_!<)os!<2rs!.XY@o`"pirr2utrVlkIo`+R`!<)os!<2rs!5J1+ o`"pgrr3#uJ,]HJ^\%Qurri5trc.r9rrCsKs7H$jrVllsr;QbH p&F^b!;l`p!<2or!5J4,p&>$hrVllsr;Qc3p&F^b!;HHl!<2or!5J4,p&>$drVlotJ,TBIht@$B rrDNdrrE&rrrCsLs7QBln,<7drqucrn+H_RrrCsTrrE&rrrDN\s7QBlhu3QTrqucrp\"RZrrBh4 rrN+KrVlllp&F^b!5JL4!<2or!;lHhp&>2Fs8Vihrqucrqt:!^rrmoPs6KX_r;Qcqp&Fac!<2ut !pfgar;Qcqp&Fac!<2ut"7,pb5Q1T^rq6UHlq#C-h!.XkF!<2fo!<)]mq>UHoq>UKpJ,90FrqQNhrrDlj rrE&nrr@QEs7uZpp\FghrqQKnTDAN_rrDN`rrE&nrrD6Xs7uZpTDAKerqQKnq>('errN+Kq>UKp J,0*ErqZTjrrDlirrE&mrr>:[s8)`qkP5&WrqHEmchd\$Mr;Z`q!/'tE!WITArr<<&s8N$!i.(G"!<2Wj!Vdc9s8W*"!$Ck5!<2Ti "5k:$rriAss8W)qrrDNcrrE&qrrDNcrrrE%s56-A,QIZ@huRQs7cQ.rrE&U!!*&grrE&es7$$grpTmVrrE&es7$$grpTmCs8;ls^\n*3p\"Odhu*KSrqufo rr>:]rrDBXrrB8#rrDups8DrurkJC2!;H0d!8m_S!;cWnrVlo<+8u3?r-.i6!8m_S!Vh0Cs8;ls ^\n*3n+H\\^\n*3rquforr=/=rrD*PrrA,XrrN%IrVt^RJ,~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/beta-fig.ps0000644000175000000620000000603711466723256017220 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: beta-fig.ps %%CreationDate: Wed Jul 13 12:13:53 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline -40 760 translate %0 176 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2392 ASCII Bytes image h>[QVIt-MY!ri6"!rfraj8T2[s8N0#It-MY!ri6"!rfqVj8T2[s8N0"^OP;D!ri6"!rmb"j8T2[ s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[ s8W-!!.X&/!ri6"s8N'`j8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[ s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N'`j8T2[ s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[ s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N'`j8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[ s8W-!!.X&/!ri6"s8N(Kj8T2[s8W-!!.X&/!ri6"s8N(Kj8T2[s8N0#5C__n!ri6"!ri4Lj8T2[ s8N0"It-MY!ri6"!rfqVj8T2[s8N0"^OP;D!r`0!!rd\!j8T2Zs8W-!!.X&/!r`0!s8N(Kj8T2Z s8W-!!.X&/!r`0!s8N(Kj8T2Zs8W-!!.X&/!r`0!s8N(Kj8T2Zs8W-!!.X&/!r`0!s8N'`j8T2Z s8W-!!.X&/!r`0!s8N(Kj8T2Zs8W-!!.X&/!r`0!s8N(Kj8T2Zs8W-!!.X&/!r`0!s8N(Kj8T2Z s8W-!!.X&/!r`0!s8N(Kj8T2Zs8W-!!.X&/!r`0!s8N'`j8T2Zs8W-!!.X&/!r`0!s8N(Kj8T2Z s8W-!!.X&/!r`0!s8N(Kj8T2Zs8W-!!.X&/!r`0!s8N(Kj8T2Xs8W-!!.X&/!rN#ts8N(Kj8T2X s8W-!!.X&/!rN#ts8N'`j8T2Xs8W-!!.X&/!rN#ts8N(Kj8T2Xs8W-!!.X&/!rN#ts8N(Kj8T2X s8W-!!.X&/!rN#ts8N(Kj8T2Xs8N0#^OP;D!rN#t!rkK7j8T2Xs8N0"^OP;D!rN#t!ra8`j8T2X s8N0#^OP;D!rN#t!rj?lj8T2Xs8W-!!.X&/!rN#ts8N(Kj8T2Xs8W-!!.X&/!r)`ps8N(Kj8T2T s8W-!!.X&/!r)`ps8N(Kj8T2Ts8W-!!'fND!r)`ps8N'`j8T2Ts8W-!!'fND!r)`ps8N'`j8T2T s8W-!!'fND!r)`ps8N'`j8T2Ls8W-!!'fND!q60hs8N'`j8T2Ls8W-!!'fND!q60hs8N'`j8T2L s8W-!!'fND!q60hs8N'`j8T2Ls8W-!!'fND!oO%Xs8N'`j8T2[rVuot!.3i-!<)lrs8N(Gjo5>XrVuot!.3i-!;HHls8N(Ijo5>L rVuot!.Eu/!2'5is8N(Jjo5=1rVuots*s53!;ucps8N+L^ZYUsoDJXgrrG@!kPkOCr;Zfs!Is"j rrN+Kr;Zfs!Is:rrrDTds8W*"J,/=.!0@$Ws8N.Mr]f]J!Vh0As8W*#J,dRSrr<<#s8W*$J,f:n m/I($q>^Kp"+U@NKC/[>n3?aKs8N4Os8W!-n,EFX&,?2)rr@QJrrVZi5P4sXrVup/p](9n!'gD] !Pea1rrTt9!VHElrr@QGrrE&m!!#7Ss8W*!J)LA,rr@Q,s8W*!J)LA,rr@Q,s8W*!J)LA,rr@Q, s8W*!J,K %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/warponsetfig.ps0000644000175000000620000003133711466723256020253 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 31 670 426 755 %%Title: (warponsetfig-Layer#1) %%Creator: (MacDraw II 1.1v2: LaserWriter 8 8.1.1) %%CreationDate: (10:28 PM Sunday, January 24, 1904) %%For: (Dannenberg) %%Pages: 1 %%DocumentFonts: Helvetica %%DocumentNeededFonts: Helvetica %%DocumentSuppliedFonts: %%DocumentData: Clean7Bit %%PageOrder: Ascend %%Orientation: Portrait %ADO_PaperArea: -129 -125 3171 2425 %ADO_ImageableArea: 0 0 3042 2300 %%EndComments /md 149 dict def md begin /currentpacking where {pop /sc_oldpacking currentpacking def true setpacking}if %%BeginFile: adobe_psp_basic %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /bd{bind def}bind def /xdf{exch def}bd /xs{exch store}bd /ld{load def}bd /Z{0 def}bd /T/true /F/false /:L/lineto /lw/setlinewidth /:M/moveto /rl/rlineto /rm/rmoveto /:C/curveto /:T/translate /:K/closepath /:mf/makefont /gS/gsave /gR/grestore /np/newpath 14{ld}repeat /$m matrix def /av 81 def /por true def /normland false def /psb-nosave{}bd /pse-nosave{}bd /us Z /psb{/us save store}bd /pse{us restore}bd /level2 /languagelevel where { pop languagelevel 2 ge }{ false }ifelse def /featurecleanup { stopped cleartomark countdictstack exch sub dup 0 gt { {end}repeat }{ pop }ifelse }bd /noload Z /startnoload { {/noload save store}if }bd /endnoload { {noload restore}if }bd level2 startnoload /setjob { statusdict/jobname 3 -1 roll put }bd /setcopies { userdict/#copies 3 -1 roll put }bd level2 endnoload level2 not startnoload /setjob { 1 dict begin/JobName xdf currentdict end setuserparams }bd /setcopies { 1 dict begin/NumCopies xdf currentdict end setpagedevice }bd level2 not endnoload /pm Z /mT Z /sD Z /realshowpage Z /initializepage { /pm save store mT concat }bd /endp { pm restore showpage }def /$c/DeviceRGB def /rectclip where { pop/rC/rectclip ld }{ /rC { np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K clip np }bd }ifelse /rectfill where { pop/rF/rectfill ld }{ /rF { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl fill gR }bd }ifelse /rectstroke where { pop/rS/rectstroke ld }{ /rS { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K stroke gR }bd }ifelse %%EndFile %%BeginFile: adobe_psp_colorspace_level1 %%Copyright: Copyright 1991-1993 Adobe Systems Incorporated. All Rights Reserved. /G/setgray ld /:F/setrgbcolor ld %%EndFile %%BeginFile: adobe_psp_uniform_graphics %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /@a { np :M 0 rl :L 0 exch rl 0 rl :L fill }bd /@b { np :M 0 rl 0 exch rl :L 0 rl 0 exch rl fill }bd /arct where { pop }{ /arct { arcto pop pop pop pop }bd }ifelse /x1 Z /x2 Z /y1 Z /y2 Z /rad Z /@q { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct fill }bd /@s { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct :K stroke }bd /@i { np 0 360 arc fill }bd /@j { gS np :T scale 0 0 .5 0 360 arc fill gR }bd /@e { np 0 360 arc :K stroke }bd /@f { np $m currentmatrix pop :T scale 0 0 .5 0 360 arc :K $m setmatrix stroke }bd /@k { gS np :T 0 0 :M 0 0 5 2 roll arc fill gR }bd /@l { gS np :T 0 0 :M scale 0 0 .5 5 -2 roll arc fill gR }bd /@m { np arc stroke }bd /@n { np $m currentmatrix pop :T scale 0 0 .5 5 -2 roll arc $m setmatrix stroke }bd %%EndFile %%BeginFile: adobe_psp_customps %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /$t Z /$p Z /$s Z /$o 1. def /2state? false def /ps Z level2 startnoload /pushcolor/currentrgbcolor ld /popcolor/setrgbcolor ld /setcmykcolor where { pop/currentcmykcolor where { pop/pushcolor/currentcmykcolor ld /popcolor/setcmykcolor ld }if }if level2 endnoload level2 not startnoload /pushcolor { currentcolorspace $c eq { currentcolor currentcolorspace true }{ currentcmykcolor false }ifelse }bd /popcolor { { setcolorspace setcolor }{ setcmykcolor }ifelse }bd level2 not endnoload /pushstatic { ps 2state? $o $t $p $s }bd /popstatic { /$s xs /$p xs /$t xs /$o xs /2state? xs /ps xs }bd /pushgstate { save errordict/nocurrentpoint{pop 0 0}put currentpoint 3 -1 roll restore pushcolor currentlinewidth currentlinecap currentlinejoin currentdash exch aload length np clippath pathbbox $m currentmatrix aload pop }bd /popgstate { $m astore setmatrix 2 index sub exch 3 index sub exch rC array astore exch setdash setlinejoin setlinecap lw popcolor np :M }bd /bu { pushgstate gR pushgstate 2state? { gR pushgstate }if pushstatic pm restore mT concat }bd /bn { /pm save store popstatic popgstate gS popgstate 2state? { gS popgstate }if }bd /cpat{pop 64 div G 8{pop}repeat}bd %%EndFile %%BeginFile: adobe_psp_basic_text %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /S/show ld /A{ 0.0 exch ashow }bd /R{ 0.0 exch 32 exch widthshow }bd /W{ 0.0 3 1 roll widthshow }bd /J{ 0.0 32 4 2 roll 0.0 exch awidthshow }bd /V{ 0.0 4 1 roll 0.0 exch awidthshow }bd /fcflg true def /fc{ fcflg{ vmstatus exch sub 50000 lt{ (%%[ Warning: Running out of memory ]%%\r)print flush/fcflg false store }if pop }if }bd /$f[1 0 0 -1 0 0]def /:ff{$f :mf}bd /MacEncoding StandardEncoding 256 array copy def MacEncoding 39/quotesingle put MacEncoding 96/grave put /Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute /agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave /ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute /ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls /registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash /infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation /product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft /guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe /endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge /ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl /daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand /Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave /Oacute/Ocircumflex/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde /macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron MacEncoding 128 128 getinterval astore pop level2 startnoload /copyfontdict { findfont dup length dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall }bd level2 endnoload level2 not startnoload /copyfontdict { findfont dup length dict copy begin }bd level2 not endnoload md/fontname known not{ /fontname/customfont def }if /Encoding Z /:mre { copyfontdict /Encoding MacEncoding def fontname currentdict end definefont :ff def }bd /:bsr { copyfontdict /Encoding Encoding 256 array copy def Encoding dup }bd /pd{put dup}bd /:esr { pop pop fontname currentdict end definefont :ff def }bd /scf { scalefont def }bd /scf-non { $m scale :mf setfont }bd /ps Z /fz{/ps xs}bd /sf/setfont ld /cF/currentfont ld /mbf { /makeblendedfont where { pop makeblendedfont /ABlend exch definefont }{ pop }ifelse def }def %%EndFile /currentpacking where {pop sc_oldpacking setpacking}if end % md %%EndProlog %%BeginSetup md begin /pT[1 0 0 -1 29.999 761.009]def/mT[.24 0 0 -.24 29.999 761.009]def /sD 16 dict def %%IncludeFont: Helvetica /f0_1/Helvetica :mre /f1_1 f0_1 1.04 scf /f1_50 f1_1 50 scf /Courier findfont[10 0 0 -10 0 0]:mf setfont %%EndSetup %%Page: 1 1 %%BeginPageSetup initializepage %%EndPageSetup gS 0 0 2300 3042 rC 0 0 :M 0 setlinecap currentscreen 3 1 roll pop pop 60 45 3 -1 roll setscreen np 1650 263 :M 1591 277 :L 1591 263 :L 1591 248 :L 1650 263 :L eofill 36 265 -4 4 1593 261 4 36 261 @a -4 -4 415 302 4 4 411 261 @b -4 -4 602 302 4 4 598 261 @b -4 -4 790 302 4 4 786 261 @b -4 -4 977 302 4 4 973 261 @b -4 -4 1165 302 4 4 1161 261 @b -4 -4 1352 302 4 4 1348 261 @b -4 -4 1540 302 4 4 1536 261 @b 18 358 :M f1_50 sf (0)S 393 358 :M (1)S 768 358 :M (2)S 1143 358 :M (3)S 1518 358 :M (4)S 4 lw 1551 358 :M 2 setlinecap .75 G 82.5 52.5 :M 112.166 68.166 127 76 127 76 :C 127 76 112.166 83.832 82.5 99.5 :C 52.832 115.165 38 123 38 123 :C 38 123 38 107.332 38 76 :C 38 44.665 38 29 38 29 :C 38 29 52.832 36.832 82.5 52.5 :C 8 lw :K gS eofill gR 0 G stroke 38 29 :M 0 setlinecap 2 setlinecap .75 G 232.5 52.5 :M 262.163 68.166 277 76 277 76 :C 277 76 262.163 83.832 232.5 99.5 :C 202.83 115.165 188 123 188 123 :C 188 123 188 107.332 188 76 :C 188 44.665 188 29 188 29 :C 188 29 202.83 36.832 232.5 52.5 :C :K gS eofill gR 0 G stroke 188 29 :M 0 setlinecap 2 setlinecap .75 G 382.5 52.5 :M 412.161 68.166 427 76 427 76 :C 427 76 412.161 83.832 382.5 99.5 :C 352.827 115.165 338 123 338 123 :C 338 123 338 107.332 338 76 :C 338 44.665 338 29 338 29 :C 338 29 352.827 36.832 382.5 52.5 :C :K gS eofill gR 0 G stroke 338 29 :M 0 setlinecap 2 setlinecap .75 G 532.5 52.5 :M 562.159 68.166 577 76 577 76 :C 577 76 562.159 83.832 532.5 99.5 :C 502.825 115.165 488 123 488 123 :C 488 123 488 107.332 488 76 :C 488 44.665 488 29 488 29 :C 488 29 502.825 36.832 532.5 52.5 :C :K gS eofill gR 0 G stroke 488 29 :M 0 setlinecap 2 setlinecap .75 G 682.5 52.5 :M 712.156 68.166 727 76 727 76 :C 727 76 712.156 83.832 682.5 99.5 :C 652.823 115.165 638 123 638 123 :C 638 123 638 107.332 638 76 :C 638 44.665 638 29 638 29 :C 638 29 652.823 36.832 682.5 52.5 :C :K gS eofill gR 0 G stroke 638 29 :M 0 setlinecap 2 setlinecap .75 G 720 52.5 :M 749.989 68.166 765 76 765 76 :C 765 76 749.989 83.832 720 99.5 :C 689.989 115.165 675 123 675 123 :C 675 123 675 107.332 675 76 :C 675 44.665 675 29 675 29 :C 675 29 689.989 36.832 720 52.5 :C :K gS eofill gR 0 G stroke 675 29 :M 0 setlinecap 2 setlinecap .75 G 757.5 52.5 :M 787.155 68.166 802 76 802 76 :C 802 76 787.155 83.832 757.5 99.5 :C 727.822 115.165 713 123 713 123 :C 713 123 713 107.332 713 76 :C 713 44.665 713 29 713 29 :C 713 29 727.822 36.832 757.5 52.5 :C :K gS eofill gR 0 G stroke 713 29 :M 0 setlinecap 2 setlinecap .75 G 795 52.5 :M 824.988 68.166 840 76 840 76 :C 840 76 824.988 83.832 795 99.5 :C 764.988 115.165 750 123 750 123 :C 750 123 750 107.332 750 76 :C 750 44.665 750 29 750 29 :C 750 29 764.988 36.832 795 52.5 :C :K gS eofill gR 0 G stroke 750 29 :M 0 setlinecap 2 setlinecap .75 G 832.5 52.5 :M 862.154 68.166 877 76 877 76 :C 877 76 862.154 83.832 832.5 99.5 :C 802.82 115.165 788 123 788 123 :C 788 123 788 107.332 788 76 :C 788 44.665 788 29 788 29 :C 788 29 802.82 36.832 832.5 52.5 :C :K gS eofill gR 0 G stroke 788 29 :M 0 setlinecap 2 setlinecap .75 G 870 52.5 :M 899.987 68.166 915 76 915 76 :C 915 76 899.987 83.832 870 99.5 :C 839.986 115.165 825 123 825 123 :C 825 123 825 107.332 825 76 :C 825 44.665 825 29 825 29 :C 825 29 839.986 36.832 870 52.5 :C :K gS eofill gR 0 G stroke 825 29 :M 0 setlinecap 2 setlinecap .75 G 907.5 52.5 :M 937.153 68.166 952 76 952 76 :C 952 76 937.153 83.832 907.5 99.5 :C 877.819 115.165 863 123 863 123 :C 863 123 863 107.332 863 76 :C 863 44.665 863 29 863 29 :C 863 29 877.819 36.832 907.5 52.5 :C :K gS eofill gR 0 G stroke 863 29 :M 0 setlinecap 2 setlinecap .75 G 945 52.5 :M 974.986 68.166 990 76 990 76 :C 990 76 974.986 83.832 945 99.5 :C 914.985 115.165 900 123 900 123 :C 900 123 900 107.332 900 76 :C 900 44.665 900 29 900 29 :C 900 29 914.985 36.832 945 52.5 :C :K gS eofill gR 0 G stroke 900 29 :M 0 setlinecap 2 setlinecap .75 G 982.5 52.5 :M 1012.152 68.166 1027 76 1027 76 :C 1027 76 1012.152 83.832 982.5 99.5 :C 952.818 115.165 938 123 938 123 :C 938 123 938 107.332 938 76 :C 938 44.665 938 29 938 29 :C 938 29 952.818 36.832 982.5 52.5 :C :K gS eofill gR 0 G stroke 938 29 :M 0 setlinecap 2 setlinecap .75 G 1132.5 52.5 :M 1162.15 68.166 1177 76 1177 76 :C 1177 76 1162.15 83.832 1132.5 99.5 :C 1102.816 115.165 1088 123 1088 123 :C 1088 123 1088 107.332 1088 76 :C 1088 44.665 1088 29 1088 29 :C 1088 29 1102.816 36.832 1132.5 52.5 :C :K gS eofill gR 0 G stroke 1088 29 :M 0 setlinecap 2 setlinecap .75 G 1282.5 52.5 :M 1312.147 68.166 1327 76 1327 76 :C 1327 76 1312.147 83.832 1282.5 99.5 :C 1252.814 115.165 1238 123 1238 123 :C 1238 123 1238 107.332 1238 76 :C 1238 44.665 1238 29 1238 29 :C 1238 29 1252.814 36.832 1282.5 52.5 :C :K gS eofill gR 0 G stroke 1238 29 :M 0 setlinecap 2 setlinecap .75 G 1432.5 52.5 :M 1462.145 68.166 1477 76 1477 76 :C 1477 76 1462.145 83.832 1432.5 99.5 :C 1402.811 115.165 1388 123 1388 123 :C 1388 123 1388 107.332 1388 76 :C 1388 44.665 1388 29 1388 29 :C 1388 29 1402.811 36.832 1432.5 52.5 :C :K gS eofill gR 0 G stroke 1388 29 :M 0 setlinecap 2 setlinecap .75 G 1432.5 52.5 :M 1462.145 68.166 1477 76 1477 76 :C 1477 76 1462.145 83.832 1432.5 99.5 :C 1402.811 115.165 1388 123 1388 123 :C 1388 123 1388 107.332 1388 76 :C 1388 44.665 1388 29 1388 29 :C 1388 29 1402.811 36.832 1432.5 52.5 :C :K gS eofill gR 0 G stroke 1388 29 :M 0 setlinecap -4 -4 227 302 4 4 223 261 @b -4 -4 40 302 4 4 36 261 @b endp %%Trailer end % md %%EOF nyquist-3.05/docsrc/nyquist/gamma-fig.ps0000644000175000000620000000712411466723256017365 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: gamma-fig.ps %%CreationDate: Wed Jul 13 12:15:43 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2956 ASCII Bytes image h>c=2rr2ueiW&oW!:SnHrr2ueiW&oW!:Ta`!;u-^rr2ueq>UK3#ODEhrrDN`rrKn1li6ta!9a4Y "9*fLJ*d47rrDNarr`6"s1dq#rr2ueqYpZps8V!Cs8N#un,!%dp](9^m/R(b!:Tda"7Q9ip[%qZ rrDNarr_0Ys820_rr2ueqYpZ4s8W&as8N#ukPG2\^]4?5m/R(b!:Tda!.Y"J!.XD9rr2uequ6Zq rVll4mJm1c!:Tgb!<)lr!8m2D"93l.n,*+brVc`rn*U,WrkGZ*qu6ZnrVlllmJd:f^YeMWrrDfl rrDr`rr`88hrjn:!;HHl!;l0`"9-'Mn,*+bn,<7drU'Ues*Kgqqu6ZbrVllsmJm1c!:Tgb!8m_S !.XG:rr2uequ6ZRr;QbHmf3:d!:Tgb!5JI3!5It%rr2uequ6Z2r;QcSmf3:d!9a7Z!.XqH!:T@U rr2uequ6YGr;Qckmf3:d!:Tgb!.XqH!;Gp]rr2uer;Qcrqu6Znmf3:d!:Tjc!<2lq!<)?crr2ue r;Qcqqu6Zqmf3:d!:Tjc!<)fp!<2Edrr2u]r;QcqqYpPFn,NCe!:Tjc!;lWm!.XJ;rr2uer;Qco qYpQ1n,NCe!:Tjc!;lWm!8m8Frr2uer;QckqYpQQn,NCe!:Tjc!;H?i!:TCVrr2uer;QccqYpQi n,NCe!9a:[!:Tda!;Gs^rr2uer;QccqYpQmn,NCe!:Tjc!8mYQ!;l6brr2uer;QcSqYpQon,NCe !:Tjc!5JC1!<2Herr2uer;Qc3qYpQpn,NCe!:Tjc!5J@0!.XMUH0nGiLf!:Tjc !.XhE!5J%'rr2uer;QbHq>UHPnGiLf!:Tmd!<2cn!8m;G"5i8`n,<7drqQKnn*p>ZYP3P8rVllr q#:?gnG`TopHS-FrrE#mrrDf_rr]J!hrjtrr2uerVll4pAY--o)J^h!:Tmd!.X_B !8mAIrr2uerVlkIpAY-Mo)J^h!9a=\!.X_B!:TLYrr2uerVlkIpAY-eo)J^h!:Tpe!<2Zk!;H'a rr2uerr2utp&>$ho)J^h!:Tpe!<2Zk!<)Kgrr2uerr2utp&>$ko)J^h!9a@]!<)Tj!<2Qhrr2ue rr2uso`"o@oDegi!:Tpe!<)Qi!5J.*rr2uerr2uqo`"pKoD\pmJ"Q3/rrDrgrrCsJrr`88hs^RE !;lEg!:TOZ"9-'mn,E=eqt0mgp[eCerkI@Rrr2umo`"pgoD\pl^YeMZrrDfcrrDrfrr`:J#OhZl !;H-c!<)Nhrr2uerr2umo`"pjoDegi!:Tpe!:TOZ!.XY@rr2uerr2ueoD\g*o`+pj!:Tpe!:TOZ !5J1+rr2u]rr2uUoD\gJo`+pj!:Tpe!8mDJ!:TR[rr2uerr2uUoD\gbo`+pj!:Tpe!5J.*!;H-c rr2uerr2u5oD\gfo`+pj!:Tpe!5J.*!<)Qirr2uerr2tJoD\gio`+pj!9a@]!.XS>!.X\Arr2ue rr2tJo)A]>p&G$k!:Tpe!.XS>!5J4,rr3)hs8W)grrCsLs8N$#n,NFenc&UXp&G$k"7Q9irpg!g p\"Rcrr_`is8DKf!;lHhrr3)`s8W&frrE#js8N$#n,NFdnc&XhJ+ipArr_`is82Wn,NFFn,ECbp\tH$legn*s53;F!<)Zl#-[?"n,NF&n,ECep\tHSpV61ss1e"% !'g8Yrr3)hs8Tk%rrCsOs8N$#n,NE;mf*:Uq#C?n"7Q9iJ+!=:oD&@brr_`is*sJ:!<)]mrr3&_ s8MEc!<2cnrr3&gs8MBb!'g;Zrr3&gs8MBb!8mVPrr3&gs8Drr3&gs*s53!9*qW rr3#froX4_rWiK'rr3#^roO.]pcnfXrrMTejSo7us8N$!n,)2G!W7HHrrMT_irB#X!UodBs8N$! n'Ct4!;lZn!.XqH!:Tjc!;lZn!.Y"J+R_Mop]&#*s53hUn,In7s1eO4n,E@]s1eI2hud9M!;HBj!.XqH!71TC!;HEk!U%5mrrDB_rrN+K r;Qc3r;Qc_r;Qfl?hjX$p\b$lrI=bF!2'2h!;HEk!V]srrrDfkrrN$^r;Qc#r;Qc_r;Qfl?hjX$ n,*+bJ,Kc=2h>`!~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/envfig.ps0000644000175000000620000000440311466723256017013 0ustar stevestaff%!PS-Adobe-2.0 %%Title: env-Layer#1 %%Creator: MacDraw II 1.1v2 %%CreationDate: Friday, July 19, 1991 %%Pages: (atend) %%BoundingBox: ? ? ? ? %%PageBoundingBox: 125 130 2425 3170 %%For: ' %%IncludeProcSet: "(AppleDict md)" 68 0 %%EndComments %%EndProlog %%BeginDocumentSetup md begin T T -130 -125 3170 2425 100 300 300 1 F F F F T T T psu (' ; document: env-Layer#1)jn 0 mf od %%EndDocumentSetup %%Page: ? 1 op 0 0 xl 1 1 pen 0 0 gm (nc 0 0 3040 2300 6 rc)kp 0 setlinecap currentscreen 3 1 roll pop pop 60 45 3 -1 roll setscreen 4 4 pen 73 36 gm 411 36 lin 411 1161 lin 2 setlinecap 0 0 pen 113 225 gm 113 225 lin nc ct 39 0 put 8 8 pen 413 38 gm bp 113 225 F qi 113 225 qc 263 338 qc 263 338 qc 300 975 qc 300 975 qc 413 1125 qc 413 1125 F qq ef 9 ec (nc 0 0 3040 2300 6 rc)kp 0 setlinecap 523 114 gm 1 setTxMode 0 fs bu fc {}mark T /Times-Roman /|______Times-Roman 0 rf bn 42 fz bu fc 2 F /|______Times-Roman fnt bn (t1)show 523 264 gm (t2)show 523 1051 gm (t4)show 4 4 pen 411 223 gm 0 gr 486 223 lin 411 36 gm 598 36 lin 411 336 gm 486 336 lin 411 973 gm 486 973 lin 411 1123 gm 598 1123 lin 111 186 gm 111 223 lin 111 114 gm 1 setTxMode (L1)show 261 336 gm 0 gr 261 298 lin 261 226 gm 1 setTxMode (L2)show 298 973 gm 0 gr 298 1011 lin 298 1051 gm 1 setTxMode (L3)show 450 38 gm 0 gr pr 450 38 pl 433 79 pl 450 79 pl 467 79 pl 450 38 pl 1 ep 450 225 gm pr 450 225 pl 467 183 pl 450 183 pl 433 183 pl 450 225 pl 1 ep 448 77 gm 448 181 lin 450 225 gm pr 450 225 pl 433 267 pl 450 267 pl 467 267 pl 450 225 pl 1 ep 450 338 gm pr 450 338 pl 467 296 pl 450 296 pl 433 296 pl 450 338 pl 1 ep 448 265 gm 448 294 lin 450 975 gm pr 450 975 pl 433 1017 pl 450 1017 pl 467 1017 pl 450 975 pl 1 ep 450 1125 gm pr 450 1125 pl 467 1083 pl 450 1083 pl 433 1083 pl 450 1125 pl 1 ep 448 1015 gm 448 1081 lin 563 38 gm pr 563 38 pl 545 79 pl 563 79 pl 580 79 pl 563 38 pl 1 ep 563 1125 gm pr 563 1125 pl 580 1083 pl 563 1083 pl 545 1083 pl 563 1125 pl 1 ep 561 77 gm 561 1081 lin 601 526 gm 1 setTxMode (dur)show 44 114 gm 1 fs bu fc {}mark T /Courier-Bold /|______Courier-Bold 0 rf bn 50 fz bu fc 2 F /|______Courier-Bold fnt bn (\(env )show 0 fs bu fc 2 F /|______Times-Roman fnt bn (t1 t2 t4 l1 l2 l3 dur)show 1 fs bu fc 2 F /|______Courier-Bold fnt bn (\))show F T cp %%Trailer cd end %%Pages: 1 0 %%EOF nyquist-3.05/docsrc/nyquist/linear-fig.ps.ORIGINAL0000644000175000000620000000570711466723256020765 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: linear-fig.ps %%CreationDate: Wed Jul 13 12:16:49 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline 0 176 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2321 ASCII Bytes image s8N)ri;WlYrVPOQ!rr,oi;WlYrVPOQ!rr5oi;WlYqtT+L"98/n5N2YBrrN#SiW&rX!W2'=s8W*" qt]4Ns8N,sro*nWrrW)t5N;_CrrW#rhr=\9rrW)tkMlOArrW)tqr7YUrrW)tr8RbVrr`/us*s)/ s8N2us8S_Os8W*$qu?]bj8]/Z"8i,uoAflNrr`)ss8:pWs8N)rrr2s_jT#8[!;lcq!70a+s8N)r rr2uijT#8[!;lcq!<)!Ys8N)rrr3#uJ*$_1rrDrprrBgqs8W*!qu-NpcfP3,rrDlnrrDfTs8W*! qu-NpqrRkXrrDrprrDuYs8W*!qu$HoJ*-e2rrDrorrA\Rs8W*!qu$HokN;gErrDrorrDlWs8W*! qu$HprdX,2s8N)pqu6YgkPtS^!;lZn!:T+Ns8N)rqu6ZfkPtS^!;lZn!<)*\s8N)rqu6]rJ*?n6 TB#hFrrA\TrrV*HqtgUH@l2Ue`!;lTl!;#ITs8N)rq>UHnl2Ue`!;lTl!WIT6s8W*!qtU0k^Ztk!rrDlirrCC1 s8W*!qtU0kpZheYrrDrkrrDl[s8W*!qtU0lrdX86s8N)rp\t6.li7"b!;lNj!71!2s8N)rp\t6f li7"b!;lNj!;Ys\s8N)pp\t9nJ*d48rrDrirrBh#s8W*!qtC$icg:]3rrDrirrDZWs8W*!qtC$i rTsRarrDrirrN+KmJm4d!;lHh!5Iq$s8N)rp&>$$jmJm4d!;lHh !WIT:s8W*!qt0mg^[D.%rrDrgrrCC5s8W*!qt0mgp[8(]rrDrgrrDl_s8W*!qt0mhrdXD:s8N)p oD\g*n,NFf!;lBf!71-6s8N)roD\gbn,NFf!;lBf!;Z*`s8N)roD\jjJ+3I>s7uQ_rrBh'rrW6! qssaecg^r9s8DicrrDZ[rrW6!q""FbrUBggs8DicrrN+Knc&[jn9a^*!2&f]s8N)rnc&UPnc/Xh !;lrrDrcrrBh)s8W*!q=+Cacgq,9rrDrcrrDZ]s8W*!qsaUcr:9mf rrDrbrr>:Ts8W*!qsXObch%2:rrDrbrrDfbs8W*!qsXObq=FXdrrDrbrrE&is8W*!q:Vs8W*!qsFC`ht@$L rrDr`rrD6Ts8W*!q:Xs8W*!qrrDr^rrDffs8W*!qs47^q=jph rrDr^rrE&ms8W*!qs+1]5PY6[hrFV!rrCC?rrTCmqs+1]p\=aiYNPfJrrDlirrTD$q!.kZrqQKp YNu)Mrr>:ZrrV'Oqs"+\htd('jrrDr\rrE&os8W*!qrn%[5PkE[ rrDr[rrCsQs8W*!q<7hYkPG5YrrDr[rrDrms8W*!qrn%[r;-HnrrDrZrr>:\s8W*!qrdtZhu!HR rrDrZrrD6Zs8W*!qrdtZqtpEnrrDrZrrDuos8W*!q<%\W5Q(Q]rrDrYrrCCCs8W*!qr[nYoDJXg rrDrYrrDups8W*!qrRhXJ,TEIrrDrXrrA\is8W*!qrRhXn,<:drrDrXrrDZhs8W*!q;qVVr;HZq rrDrWrr@QJs8W*!qrIbWTDnljrrDrWrrDNes8W*!qrIbWoD\dirrDrWrrE#ss8W*!qrIbZrdXtJ s8N)rj8T1Qs8W-!!;Y[T!q60hs8N)rj8T2Ps8W-!!;kgV!r`0!s8N)rj8T2[J,fQK!;kdU!MBDl rrDrUrrMTgs8N)rqu6Z2r;Qcoqu6YGr;Qckr;QfhJ,fNlqu>RQs7cQ.rVu?dJ,B9'rVu?dJ,B9' rr;`m^]"3$r-nbIrnmbV!WW0"qr%MSrrDrSs8W*!qr%MSrrDrSs5!_NrrM$OrVlrts1eO4!Pdgr rrN#rr;Qfqs7uZqYNu/e!rDp]rVln*hu3QVp&0C=rrN-!q>UK!p\k*nqYn8.rrHKQrVlokrqucs rr;fo!O)7rrrW&r+8u3??e>8V!qlMArVlots7uZqYODGi!rDr3rVln*fDY^Np&0C=rrN-!q>UKP j8JuZrU1j,rrKgZrVloqhYdBSpcmU7J,~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/logistic-fig.ps0000644000175000000620000000663211466723256020123 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: logistic-fig.ps %%CreationDate: Wed Jul 13 12:17:06 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2767 ASCII Bytes image li-tZo`+@Z"7Q,Jp[nLRrr^mG^\@C#mf*C@qk*WTs7$$lpcmC-n+$&MnG`[`T@`h@p[nLTs8MHg ESpN_s7$$hhtR-M!;H-cnG`O(p\t0mp[nLTrrIWHrr2umo`+F\!It(IrrDZ_s7-*jrr;rrrrDfc s7-*jrr;usrrDfcs7-*nrVunIs8Vics7-*nrVunIs8Vics7-*nqu?]2s8Vics7-*nqu?]2s8Vic s7-*np](9Ns8V]_s7-*np](9Ns8Vics7-*nn,NFFs8Vics7-*nn,NFVs8Vics7-*nn,NFVs8Vic s7-*nhuE`Fs8Vics7-*nhuE`Ns8V]_s7-*nhuE`Ns8Vics7-*n^]4?2s8Vics7-*n^]4?2s8Vic s7-*nJ,fQGs8Vics7-*nJ,fQIs8Vics7-*nJ,fQIs8Vics760irr2p"rVuoho`+L^!<2ut"9/?# p[nLVrrE&trr`9#s7c0co)A^grr3*"^[Lphs760irVc`t?e>&Es760irVc`t?gma]s760iqu-Nr +7Jals760iqu-Nr+5chbs760ip\k*n]uTm>s760ip\k*nhuEHCs760ip\k*nhuEHCs760in,<7f huEHCs760in,<7fn,N"Os760in,<7fn,N.Ss760ihu3QVn,N.Ss760ihu3QVp](![s760ihu3QV p](![s760i^]"06qu?E_s760i^]"06qu?E_s760i^]"06qu?9[s760i^]"06rVuWas760iJ,TBK rVuWas760iJ,TBKrVuWas760iJ,TBKrr;`bs7?6jrquctrr;`bs7?6jrquctrr;T^s7?6jrquct rr;`bs7?6jrVQTqJ+rU8oD\ghqu6\Hp[nLWrrE#prrIWDo`+O_!<)fp!PeC$s7?6jqtpBo^\@C# oD\gfqu6]3oCW(SrrDrnrrM$Oo`+O_!;HBj!T3YDs7?6jp\k*on+2V7o`+O_!;HHl"5!FBp[nLW rrDflrr^mMO8&;HoD\gZrVluOqsX(Is7?6jn,<7gfDDcGo`+O_!:Tmd"7KXLp[nLWrrCsRs8Vic s7?6jhu!HRp[nLWrrCsRs8Vics7?6j^\e$3qt'I[oD\g*qu6]op[nLWrrBh2rrN#ko`+O_!5JF2 !WDcbs7?6jJ,B6HrV,saoD\f?qu6]qp[nLWrr@QGrrN,no`+R`!<2ip!WM]_s7H$jq#:Bh^\.X"rrDrkrrMl/p&F^b!;lQk!VbLEs7QBlp\=ahpYYZD p&>$dq#:Bhn+H_RrrDN_rrM`[p&F^b!:T^_!Vc'Us7QBlht[6Op\"RZrrCsOs8Vids7QBl^\Ig0 p\XX`p&>$,q#:Bhqt:!^rr@QDrrM`ip&F^b!.XeD!VcQcs7ZHmrqHEnp\sjcpAY-lp\t9grq6$drr2u5q#C-h!:TU\!;HKm!8mSOq#:?Op&>$drr2u]q#C-h !5J4,!;HKm!;lQkq>UKpJ+`gAoD\airV6EgrrDlerrDfmrrN+Kq>^9j!;H-c!;HHl!2')eq>UH@ o`"pcrVll\q>^9j!'g,U!;HHl!;ZHjqYpQnoD\gbrVlotJ,93ArrDZ^rrDfkrrA,Vs82fsrX\W# !;$-g!:]jbqu6ZTo)A^aqu6X\qu?Qn!2&i^!;HBj!5\R4r;QfeJ+EU>p\XskrX\r,rVm!#&-)\, rVllTrr2utrVlllrVm#8s8VQhrVn,Bqu?_H^[LporVqA^hs^I@rr7J_n+Z_Xs*qf@n,*"_!.Y"K rnd\Us6K[bp[nLOrrDfcs6K[bp[nLOrrDfcs5!_RrrBh5rrDuqrrDflrr@QErr@QJrrE#rs8Drt ?iL'*qu-NpkPkJ^rkJ=0!WKk5rrDlns8Drt^]+65q>LUHorVllrrVuir!5JO5!;ZTn!9=(Y !WG=[rrN*`rr2unrVt^RJ,~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/binomial-fig.ps0000644000175000000620000015375111466723256020105 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: binomial-fig.ps %%CreationDate: Wed Jul 13 12:14:23 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 312 364 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 348.98334526366023 translate -20 775 translate 296.98582677165354 -348.98334526366023 scale % Image geometry 297 349 8 % Transformation matrix [ 297 0 0 349 0 0 ] % Strings to hold RGB-samples per scanline /rstr 297 string def /gstr 297 string def /bstr 297 string def {currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} true 3 %%BeginData: 54218 ASCII Bytes colorimage JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> r;V r;V r;V r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sc2[\A"FTJ6!!)3^rrDlprrE#tr;["7d/X+G!;ZX#iJdg:!!*$!!;6?qiJdg:!!(^P!:]md j8T,KquFt@!!)orJ,~> r;Q`sc2[\A"FTJ6!!)3^rrDlprrE#tr;["7d/X+G!;ZX#iJdg:!!*$!!;6?qiJdg:!!(^P!:]md j8T,KquFt@!!)orJ,~> r;Q`sc2[\A"FTJ6!!)3^rrDlprrE#tr;["7d/X+G!;ZX#iJdg:!!*$!!;6?qiJdg:!!(^P!:]md j8T,KquFt@!!)orJ,~> r;Q`sc2[eDs8N/Z!,1*drrE#trrE*!!h',JpAb-mr;Zcsp&G$lec,^(!1MjG!ndRBao;>@qu;0~> r;Q`sc2[eDs8N/Z!,1*drrE#trrE*!!h',JpAb-mr;Zcsp&G$lec,^(!1MjG!ndRBao;>@qu;0~> r;Q`sc2[eDs8N/Z!,1*drrE#trrE*!!h',JpAb-mr;Zcsp&G$lec,^(!1MjG!ndRBao;>@qu;0~> r;Q`sc2[eDrr;uu./s8Irr<&GHqhufs0>?!ZN'q)!76*f]uNiAd/O(Gs65IB!,1'c!!)utrrE*!% -[b\rr<'!l$NI2N9U9@%fZM/rr<&49oT,P!!*'!qZ%0,!!*'!Z:t>)rr<&GHqhuas8N'$d!SR7o D\m*!6=j6rr<,I9mlF0!keTSao;>@qu;0~> r;Q`sc2[eDrr;uu./s8Irr<&GHqhufs0>?!ZN'q)!76*f]uNiAd/O(Gs65IB!,1'c!!)utrrE*!% -[b\rr<'!l$NI2N9U9@%fZM/rr<&49oT,P!!*'!qZ%0,!!*'!Z:t>)rr<&GHqhuas8N'$d!SR7o D\m*!6=j6rr<,I9mlF0!keTSao;>@qu;0~> r;Q`sc2[eDrr;uu./s8Irr<&GHqhufs0>?!ZN'q)!76*f]uNiAd/O(Gs65IB!,1'c!!)utrrE*!% -[b\rr<'!l$NI2N9U9@%fZM/rr<&49oT,P!!*'!qZ%0,!!*'!Z:t>)rr<&GHqhuas8N'$d!SR7o D\m*!6=j6rr<,I9mlF0!keTSao;>@qu;0~> r;Q`sc2[eDs8OV.!4)V)!<3$!^$,Mks1JEQ`rNgQ!!'_%!!'=h!,2B4!<7H"s60MXrr<&ts8N)u s8N'Srr<'!BE8(s!.=eH!<<'!!<3$!VoJe8rr<'!rr<'!!!*'!!!*&4!6<+[]`8&Gkl=HSs8N'$ ^$,MkrVu`prVm"Z!)3HPq>^Hp"/j0>Vu?Ym!;c]uMuZQPN6D5$!;leH~> r;Q`sc2[eDs8OV.!4)V)!<3$!^$,Mks1JEQ`rNgQ!!'_%!!'=h!,2B4!<7H"s60MXrr<&ts8N)u s8N'Srr<'!BE8(s!.=eH!<<'!!<3$!VoJe8rr<'!rr<'!!!*'!!!*&4!6<+[]`8&Gkl=HSs8N'$ ^$,MkrVu`prVm"Z!)3HPq>^Hp"/j0>Vu?Ym!;c]uMuZQPN6D5$!;leH~> r;Q`sc2[eDs8OV.!4)V)!<3$!^$,Mks1JEQ`rNgQ!!'_%!!'=h!,2B4!<7H"s60MXrr<&ts8N)u s8N'Srr<'!BE8(s!.=eH!<<'!!<3$!VoJe8rr<'!rr<'!!!*'!!!*&4!6<+[]`8&Gkl=HSs8N'$ ^$,MkrVu`prVm"Z!)3HPq>^Hp"/j0>Vu?Ym!;c]uMuZQPN6D5$!;leH~> r;Q`sc2[\A.X^ac!!*$!!<<'!!<6^4s8N(4rr<'!rr<'!rr<'!!!*'!iNdh2!<3$!rVultrr;uu #QFc(s%NK@d/O(F!<<*!!$V@B!<<'!:&b1ns8N'!rr<'!rr<'!BE8)4!,)?4s8N'!qZ$Qqs8W*! oD\uQ:$K[uRem'a!<<'"!);t_"cQ1?`rMRPrr<&rs*t~> r;Q`sc2[\A.X^ac!!*$!!<<'!!<6^4s8N(4rr<'!rr<'!rr<'!!!*'!iNdh2!<3$!rVultrr;uu #QFc(s%NK@d/O(F!<<*!!$V@B!<<'!:&b1ns8N'!rr<'!rr<'!BE8)4!,)?4s8N'!qZ$Qqs8W*! oD\uQ:$K[uRem'a!<<'"!);t_"cQ1?`rMRPrr<&rs*t~> r;Q`sc2[\A.X^ac!!*$!!<<'!!<6^4s8N(4rr<'!rr<'!rr<'!!!*'!iNdh2!<3$!rVultrr;uu #QFc(s%NK@d/O(F!<<*!!$V@B!<<'!:&b1ns8N'!rr<'!rr<'!BE8)4!,)?4s8N'!qZ$Qqs8W*! oD\uQ:$K[uRem'a!<<'"!);t_"cQ1?`rMRPrr<&rs*t~> r;Q`sc2[eDs8OV&!,2B4!<3$!s8N'!rr<'!rr<'!!!*'!!!*'!!!*$!!<:CGRcsePrr<&ts8N)u s8N'Krr<'!cqOK?:!in?!<<'!!<3$!s8N'!rr<'!rr<'!!!*'!!!*$!!<<)t!<<*!!;c`q!<<*! !<)rp!;ZZp!;c`q!<<*!!<)rp!;?Hm!6kHC!;leH~> r;Q`sc2[eDs8OV&!,2B4!<3$!s8N'!rr<'!rr<'!!!*'!!!*'!!!*$!!<:CGRcsePrr<&ts8N)u s8N'Krr<'!cqOK?:!in?!<<'!!<3$!s8N'!rr<'!rr<'!!!*'!!!*$!!<<)t!<<*!!;c`q!<<*! !<)rp!;ZZp!;c`q!<<*!!<)rp!;?Hm!6kHC!;leH~> r;Q`sc2[eDs8OV&!,2B4!<3$!s8N'!rr<'!rr<'!!!*'!!!*'!!!*$!!<:CGRcsePrr<&ts8N)u s8N'Krr<'!cqOK?:!in?!<<'!!<3$!s8N'!rr<'!rr<'!!!*'!!!*$!!<<)t!<<*!!;c`q!<<*! !<)rp!;ZZp!;c`q!<<*!!<)rp!;?Hm!6kHC!;leH~> r;Q`sc2[eDrr;uu./s8Irr<'!rr<'!BE8)4!,2B4!<<'!!<<'!!<3$!rr<'!rr<'!!!)utrrE*! "mH#Urr<&us")j$!) r;Q`sc2[eDrr;uu./s8Irr<'!rr<'!BE8)4!,2B4!<<'!!<<'!!<3$!rr<'!rr<'!!!)utrrE*! "mH#Urr<&us")j$!) r;Q`sc2[eDrr;uu./s8Irr<'!rr<'!BE8)4!,2B4!<<'!!<<'!!<3$!rr<'!rr<'!!!)utrrE*! "mH#Urr<&us")j$!) r;Q`sc2[eDs8OV.!0$pX!<3$!s8N'!s1JEQ`rNgQ!!*'!!!*'!!!*$!!<5anl,Nc(rr<&ts8N*! s#?GIg&D$Ps*Oh2n,R/%!!*'!!!*$!!2n0DVuLE1l+I&srr<'!rr<'!]`?*n!5/@4s8N'!rr<&t s8N*!s8N)jrs3uPl-KF9rr<&ts8N'$VpGFAoDegj#60&Nl-KF9bl7YCqu;0~> r;Q`sc2[eDs8OV.!0$pX!<3$!s8N'!s1JEQ`rNgQ!!*'!!!*'!!!*$!!<5anl,Nc(rr<&ts8N*! s#?GIg&D$Ps*Oh2n,R/%!!*'!!!*$!!2n0DVuLE1l+I&srr<'!rr<'!]`?*n!5/@4s8N'!rr<&t s8N*!s8N)jrs3uPl-KF9rr<&ts8N'$VpGFAoDegj#60&Nl-KF9bl7YCqu;0~> r;Q`sc2[eDs8OV.!0$pX!<3$!s8N'!s1JEQ`rNgQ!!*'!!!*'!!!*$!!<5anl,Nc(rr<&ts8N*! s#?GIg&D$Ps*Oh2n,R/%!!*'!!!*$!!2n0DVuLE1l+I&srr<'!rr<'!]`?*n!5/@4s8N'!rr<&t s8N*!s8N)jrs3uPl-KF9rr<&ts8N'$VpGFAoDegj#60&Nl-KF9bl7YCqu;0~> r;Q`sc2[\A.ZEWl!!*$!!<<'!!<<))9hhqnrr<'!rr<'!rr<'!!!*&G9hhnn!<3$!rVufr3,%"F rr<'!n r;Q`sc2[\A.ZEWl!!*$!!<<'!!<<))9hhqnrr<'!rr<'!rr<'!!!*&G9hhnn!<3$!rVufr3,%"F rr<'!n r;Q`sc2[\A.ZEWl!!*$!!<<'!!<<))9hhqnrr<'!rr<'!rr<'!!!*&G9hhnn!<3$!rVufr3,%"F rr<'!n r;Q`sJcFU,!U4:WrrM@trVultZ2Xe(qu;0~> r;Q`sJcFU,!U4:WrrM@trVultZ2Xe(qu;0~> r;Q`sJcFU,!U4:WrrM@trVultZ2Xe(qu;0~> r;Q`sJcFU,!K?!srrJ);rVultZ2Xe(qu;0~> r;Q`sJcFU,!K?!srrJ);rVultZ2Xe(qu;0~> r;Q`sJcFU,!K?!srrJ);rVultZ2Xe(qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`soD\djrr;rtJcC<$qYpNqqu;0~> r;Q`soD\djrr;rtJcC<$qYpNqqu;0~> r;Q`soD\djrr;rtJcC<$qYpNqqu;0~> r;Q`so`+pks8N'!rr2ruJcC<$qu6Wrqu;0~> r;Q`so`+pks8N'!rr2ruJcC<$qu6Wrqu;0~> r;Q`so`+pks8N'!rr2ruJcC<$qu6Wrqu;0~> r;Q`sp&>0qrrE*!!<2uu!.k0$s82fr!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s82fr!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s82fr!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s82fr!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s82fr!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s82fr!;leH~> r;Q`spAY r;Q`spAY r;Q`spAY r;Q`spAb$j!WN0!rr<&orr<%M^lH21JGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<%M^lH21JGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<%M^lH21JGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^lH21JGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^lH21JGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^lH21JGK3F!;leH~> r;Q`soD\djrr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYS\XjtJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\XjtJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\XjtJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;osq#: r;Q`sp&G!krr;osq#: r;Q`sp&G!krr;osq#: r;Q`spAY*mrr3'#s8N)lrr<%i^]4B.R/d5<_#M1MJGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<%i^]4B.R/d5<_#M1MJGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<%i^]4B.rr<%M_#M1MJGK3F!;leH~> r;Q`so)AakrrD]k!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrD]k!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrD]k!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so`+pks8W#tp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`so`+pks8W#tp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`so`+pks8W#tp\t3nS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`so)A[ir;Q`squ?NnT>1F,p6bm\J\_<$!.anF!!)orJ,~> r;Q`so)A[ir;Q`squ?NnT>1F,p6bm\J\_<$!.anF!!)orJ,~> r;Q`so)A[ir;Q`squ?NnT>1F,pAY*mJ\_<$!.anF!!)orJ,~> r;Q`so)A[ir;Q`sq#: r;Q`so)A[ir;Q`sq#: r;Q`so)A[ir;Q`sq#: r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`so)AakrrE&u!!)orqZ*8(!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ*8(!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ*8(!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;osq#: r;Q`sp&G!krr;osq#: r;Q`sp&G!krr;osq#: r;Q`spAY*mrr3'#s8N)lrr<%i^]4B.R/d5<_#M1MJGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<%i^]4B.R/d5<_#M1MJGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<%i^]4B.rr<%M_#M1MJGK3F!;leH~> r;Q`so)AakrrD]k!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrD]k!!&S*!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrD]k!!&S*!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so)A^js8;rlrr<%i^]4B.R/d5<_#M1MJGK3F!;leH~> r;Q`so)A^js8;rlrr<%i^]4B.R/d5<_#M1MJGK3F!;leH~> r;Q`so)A^js8;rlrr<%i^]4B.rr<%M_#M1MJGK3F!;leH~> r;Q`soD\djqu6Wrqu?NnT>1F,p6bm\J\_<$!.anF!!)orJ,~> r;Q`soD\djqu6Wrqu?NnT>1F,p6bm\J\_<$!.anF!!)orJ,~> r;Q`soD\djqu6Wrqu?NnT>1F,pAY*mJ\_<$!.anF!!)orJ,~> r;Q`so`"mkqYpNqq#: r;Q`so`"mkqYpNqq#: r;Q`so`"mkqYpNqq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`spAb$js8W&up\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uYS\P4*pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YO.>n%\o'p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YO.>n%\o'p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YO.>n%\o'pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]YFLIopGd[nA##(p6bm\J\_<$!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]YFLIp&>!lnA##(pAY*mJ\_<$!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'[I!!)\[!!)N(!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'[I!!)\[!!)N(!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'[I!!)]l!!)N(!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'[I!!)\[!!)N(!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'[I!!)\[!!)N(!!)_\!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'[I!!)]l!!)N(!!)`m!!%Scs1eVbq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ+@G!!)\[!!)N(!!)_\!!)K'o`1Pu!.anF!!)orJ,~> r;Q`so)AakrrE&u!!)orqZ+@G!!)\[!!)N(!!)_\!!)K'o`1Pu!.anF!!)orJ,~> r;Q`so)AakrrE&u!!)orqZ+@G!!)]l!!)N(!!)`m!!)K'o`1Pu!.anF!!)orJ,~> r;Q`soD\mms8N)urr<&orr<&3^]4B-R/d6V^]4B.R/d6V^]4B.R/d5X^]8o\rr<&rs*t~> r;Q`soD\mms8N)urr<&orr<&3^]4B-R/d6V^]4B.R/d6V^]4B.R/d5X^]8o\rr<&rs*t~> r;Q`soD\mms8N)urr<&orr<&3^]4B-rr<&g^]4B.rr<&g^]4B.rr<%i^]8o\rr<&rs*t~> r;Q`so`"mkrr2rurr2ruq#:UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sp&>!lrVlitrr2ruq#:UEpqu;0~> r;Q`sp&>!lrVlitrr2ruq#:UEpqu;0~> r;Q`sp&>!lrVlitrr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`spAb$js8W&up\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`spAb$js8W&up\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`spAb$js8W&up\t3n]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkrVufrq#:UEpqu;0~> r;Q`so`"mkrVufrq#:UEpqu;0~> r;Q`so`"mkrVufrq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sp&G$lrVlitp&>!l]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sp&G$lrVlitp&>!l]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sp&G$lrVlitp&>!l]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`spAY0orrE&u!!)Zk!!'[I!!)\[!!)N(!!)_\!!)N(!!)_\!!&S*!.anF!!)orJ,~> r;Q`spAY0orrE&u!!)Zk!!'[I!!)\[!!)N(!!)_\!!)N(!!)_\!!&S*!.anF!!)orJ,~> r;Q`spAY0orrE&u!!)Zk!!'[I!!)]l!!)N(!!)`m!!)N(!!)`m!!&S*!.anF!!)orJ,~> r;Q`so`"mkrr;osp\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrr;osp\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrr;osp\t3n]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqqu?Nn^;'^KopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqqu?Nn^;'^KopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqqu?Nn^;'^Kp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqq#:UEpqu;0~> r;Q`so`"mkqYpNqq#:UEpqu;0~> r;Q`so`"mkqYpNqq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3n]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uY]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3n]YFLIopGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3n]YFLIp&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sp&G$lrr2rurr2ruq#:UEpqu;0~> r;Q`sp&G$lrr2rurr2ruq#:UEpqu;0~> r;Q`sp&G$lrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`spAY0orrE&u!!*#u!!)fo!!'[I!!)\[!!)N(!!)_\!!)N(!!)_\!!&S*!.anF!!)orJ,~> r;Q`spAY0orrE&u!!*#u!!)fo!!'[I!!)\[!!)N(!!)_\!!)N(!!)_\!!&S*!.anF!!)orJ,~> r;Q`spAY0orrE&u!!*#u!!)fo!!'[I!!)]l!!)N(!!)`m!!)N(!!)`m!!&S*!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruq#:UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruqu?Nngq`R_n%\o'opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruqu?Nngq`R_n%\o'opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruqu?Nngq`R_n%\o'p&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEp qu;0~> r;Q`so`"mkrVuisp\t3ng;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\n%ePq]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\n%ePq]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mn%ePq]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sn,N=dq#:UEp qu;0~> r;Q`sn,N=dq#:UEp qu;0~> r;Q`sn,N=dq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sn,E@fp&>!lg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,E@fp&>!lg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,E@fp&>!lg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`snG`Igo`"mkg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snG`Igo`"mkg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snG`Igo`"mkg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`snGiFep\t3ng;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snGiFep\t3ng;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snGiFep\t3ng;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sm/I%cqu?NngqWmip6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sm/I%cqu?NngqWmip6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sm/I%cqu?NngqWmipAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sm/I%cq#:UEp qu;0~> r;Q`sm/I%cq#:UEp qu;0~> r;Q`sm/I%cq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sn,N@ep\t3ng;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,N@ep\t3ng;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,N@ep\t3ng;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gpAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYq7uS%nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sir8uYq7uS%nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sir8uYq7uS%nA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[]YFMt q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[ ]YFMtq>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1opGd[nA##(p6bm\nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[ ]YFMtq>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1p&>!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!l ]YFMtq>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lnA##(pAY*mnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##( p&>!l]YFMtq>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lq7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1q7lt1pAY*m q7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1jM1`qj1kWpq>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lq7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1q7lt1pAY*m q7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1jM1`qj1kWpq>UEpqu;0~> r;Q`snG`Igrr2ruqu;3IM#dAO!!)orJ,~> r;Q`snG`Igrr2ruqu;3IM#dAO!!)orJ,~> r;Q`snG`Igrr2ruqu;3IM#dAO!!)orJ,~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`sn,N@ep\t3nj8T)ZjSo2[j8T)ZjSo2[jSo2[j8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sn,N@ep\t3nj8T)ZjSo2[j8T)ZjSo2[jSo2[j8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sn,N@ep\t3nj8T)ZjSo2[j8T)ZjSo2[jSo2[j8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sec5UKjSo2[jT#2Zk5YD\jSo2[k5YA[k5YD\bPqPBqu;0~> r;Q`sec5UKjSo2[jT#2Zk5YD\jSo2[k5YA[k5YD\bPqPBqu;0~> r;Q`sec5UKjSo2[jT#2Zk5YD\jSo2[k5YA[k5YD\bPqPBqu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukl1V_rr2ruk5YG]k5PD]jSo2[rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukl1V_rr2ruk5YG]k5PD]jSo2[rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukl1V_rr2ruk5YG]k5PD]jSo2[rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)*[!!)3^!W`6#kPkM^j8T)ZaSu5?qu;0~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)*[!!)3^!W`6#kPkM^j8T)ZaSu5?qu;0~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)*[!!)3^!W`6#kPkM^j8T)ZaSu5?qu;0~> r;Q`sf)G^Mrr2rujo5;\iVrlXk5YG]k5PJ_rrD6^r;c![r;b%@!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\iVrlXk5YG]k5PJ_rrD6^r;c![r;b%@!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\iVrlXk5YG]k5PJ_rrD6^r;c![r;b%@!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\ir8uYj8T)Zkl1_bs8N)Zrr<&^rr<&urr<&Crr<&rs*t~> r;Q`sf)G^Mrr2rujo5;\ir8uYj8T)Zkl1_bs8N)Zrr<&^rr<&urr<&Crr<&rs*t~> r;Q`sf)G^Mrr2rujo5;\ir8uYj8T)Zkl1_bs8N)Zrr<&^rr<&urr<&Crr<&rs*t~> r;Q`sf)G^Mrr2rujo5;\j8T)Zir8uYkl:P\jSo2[kPkM^rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2rujo5;\j8T)Zir8uYkl:P\jSo2[kPkM^rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2rujo5;\j8T)Zir8uYkl:P\jSo2[kPkM^rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2rujo5;\jSo2[jo5;\rr2rujo5;\kPkM^rr2rukPkM^rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2rujo5;\jSo2[jo5;\rr2rujo5;\kPkM^rr2rukPkM^rr2rubl7YCqu;0~> r;Q`sf)G^Mrr2rujo5;\jSo2[jo5;\rr2rujo5;\kPkM^rr2rukPkM^rr2rubl7YCqu;0~> r;Q`sec5UKjSo2[jo>5YkPtM]jSo2[k5YD\jo>;[bPqPBqu;0~> r;Q`sec5UKjSo2[jo>5YkPtM]jSo2[k5YD\jo>;[bPqPBqu;0~> r;Q`sec5UKjSo2[jo>5YkPtM]jSo2[k5YD\jo>;[bPqPBqu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;V r;V r;V JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/bilateral-fig.ps0000644000175000000620000000615311466723256020243 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: bilateral-fig.ps %%CreationDate: Wed Jul 13 12:14:08 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2463 ASCII Bytes image nG`Lfn,MtY!r)Khn,MtY!pfa_n,MtY!pf[]n,MtY"7,sc5Oe^DrrVN_rpTmXrrVr.rpTmVrrDuc s7$$hr."59nG`OeJ+3L-rrN%InGi"X!W7H:s7$$hr."59nG`Oc^[V9mrrMu2nGi"X!W'S#s7$$h qS2P"nG`Oc5Oe^BrrMu2nGi"X!VYF?s7$$hp>>B>nG`O_hsg[8rrMiNnGi"X!VTmis7$$hp@%MN nG`O_n*pAHrrMQVnGi"X!UfFGs7$$hme?5NnG`OWp[J4PrrLu#nGi"X!T*S?s7$$hhY6O>o)Agd rndPAs760llhnKonGi(Z"7,ftqsaXVrr_T^5!/96o)AgXrkA:!s760lpUi]enGi"X!Ik":s7$$h If8d9nG`Ns760nrr;uts*sV>o)Aml s8INJJ+EX1rrrB$rr<#5o)J:\"oJ?!s8Tk)s760nqu?Zqs1e.)o)Amjs8N&uht$grr`#qs8N#t!8mDJoD\pe s8W)trrDNZs7?6mn,NFerr2ueoDeF^"7Q9irr2otn+6SNrr_0Ys8N#t!;H*boD\pMs8W)trrDfb s7?6q^]4?5J,fQGoDeF^"2Fm9rr2otqt'jZrr[cNs8N#t!<)NhoD\oBs8W)trrE#hs7H6js8VE`r]gA]!5J4,p&>3is8VE`rqucrht@$B rrqlks7`aHr;Qccp&F^b!8mbT!<2or!:TU\p&>$,rVllsr;Qckp&F^b!.XtI!<2or!;lHhp&>#A rVlotJ,TBIrUp3arrE&rrrE&rrrE&ks7ZHmrVZZqrql]qJ+ip9rrDrorrE&qrrBh-s7ZHmp\b$k rql]qhtI*DrrDNcrrE&qrrDN]s7ZHmhu*KSrql]qoCi4Xrr>:]rrN+Kr;QcqpAame!;u`o!<2lq !WITCs7cNnoDAOfrqcWpTD/B[rrDNbrrE&prrDN^s7cNnTDSWgrqcWpoCr:[rrN+Kqu6ZqqYpQo p]($g!;ZKk!WITGrrN+Kq#C-h!6=s9!<2fo!2'&dq#:=YqYpQpq>UHXq#C0i!;QBi!<2fo!;ZEi q>UH8q>UHoq>UKp5Pb?Trr>:ZrrE&nrrC+8s8)`qnG*"`rqQKopj`/?qu6]r&,?/*rdX_C!/(.J qu6YIp\t6mp\t9l&,ZD)rrMV=p\t6mpAY0_J,K?FrrN*0pAY-lp&>&C&,lP.rr`0!!It%I!:Tjc !<2lq!:Tjc"o[ojJ,fNns82ufs*sqG^]"3$s*sqGhu$Lr;Qcqr;Z]p!2'2h!:0=X!3c>#!;ZQm r;Qb(r;Qckp&>$Lr;Qcir;Z`q!TO^hrrN%Ap&>$Lr;Qcdr;Z]p!8m_S!:TU\!5JI3!<)iqr;QbX r;QcWp&>#Qr;Qclr;YUQJ,~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/nyquistman-sal-only.mss0000644000175000000620000162551411510141774021663 0ustar stevestaff@device(mac52postscript) @make(manual) @libraryfile(mathematics10) @libraryfile(picture) @libraryfile(multilevelindex) @style(font timesroman) @style(fontscale 11) @commandstring(dash @Y[M]) @commandstring(subtract @Y[N]) @commandstring(itemsep @Y[M]) @Modify(indexenv, above=2 lines, leftmargin 8, columns=3, boxed) @define(prg=i) @define(detail=text, size 9, spacing 1.2, indent 0) @define(code, FaceCode T, size 11) @comment{codef is used to define a lisp function or variable -- a processor uses this to extract completion hint info for jNyqIDE.} @define(codef, FaceCode T, size 11) @comment{pragma(define) is used to mark a term's point of definition -- I tried to define(defn=index), but that didn't work in Scribe, so the approach now is to mark definitions. In s2h, the define pragma sets a flag that the NEXT index term is a definition. The s2h.lsp processor uses this to map terms defined within codef (which go into the completion list) to URLs for the help system.} @define(smallcode, FaceCode T, size 8, spacing 0.8) @comment(was 10) @define(rbdisplay = display, group) @define(fndefs = description, leftmargin 0.5in, indent -0.5in) @define(fdescription = text, leftmargin +0.5in, indent -0.5in, spread 1) @define(pdescription = text, leftmargin +0.5in, indent -0.5in, spread 0) @define(fgroup = text, indent -0.5in, spread 0) @textform(html = []) @textform(htmltitle = []) @textform(pragma = []) @use(bibliography = "../bib/music.bib") @style(references ClosedAlphabetic) @counter(dummy-counter) @modify(FigureCounter,Within=dummy-counter, Numbered <@@b[Figure@@ @1:@@ @@ ]@@$>, Referenced "@1",Init 0) @modify(TableCounter,Within=dummy-counter, Numbered <@@b[Table@@ @1:@@ @@ ]@@$>, Referenced "@1",Init 0) @pageheading(left "", center "@value(page)", right "") @include(../template/filcap.mss) @begin(comment) @begin(figure) @blankspace(0.3 inches) @comment(scribe doesn't leave enough space) @center(@graphic((height = *** in, width = *** in, magnify = ***, postscript = "***.ps")) @fillcaption(***) @tag(***) @end(figure) @end(comment) @html(Nyquist Reference Manual) @htmltitle(Nyquist Reference Manual) @begin(titlepage) @begin(titlebox) @blankspace(0.5 inch) @majorheading(Nyquist Reference Manual) @b(Version 3.04) @blankspace(0.3 inch) @b(Copyright 2011 by Roger B. Dannenberg) @value(date) @end(titlebox) @pragma(startscribe) @center(Carnegie Mellon University) @center(School of Computer Science) @center(Pittsburgh, PA 15213, U.S.A.) @pragma(endscribe) @html(
    Carnegie Mellon University
    School of Computer Science
    Pittsburgh, PA 15213, U.S.A.
    ) @blankspace(1 inch) @end(titlepage) @pragma(startscribe) . @pragma(endscribe) @newpage @pageheading(even, left "Page @Value(Page)", right "@c(Nyquist Manual)") @pageheading(odd, left "@c[@title(chapter)]", right "Page @Value(page)") @style(pagenumbers="@i") @set(page=3) @Unnumbered(Preface) This manual is a guide for users of Nyquist, a language for composition and sound synthesis. Nyquist grew out of a series of research projects, notably the languages Arctic and Canon. Along with Nyquist, these languages promote a functional style of programming and incorporate time into the language semantics. Please help by noting any errors@Index(errors), omissions@Index(omissions), or suggestions@Index(suggestions) you may have. You can send your suggestions to Dannenberg@@CS.CMU.EDU (internet) via computer mail, or by campus mail to Roger B. Dannenberg, School of Computer Science, or by ordinary mail to Roger B. Dannenberg, School of Computer Science, Carnegie Mellon University, 5000 Forbes Ave., Pittsburgh, PA 15213-3890, USA. Nyquist is a successor to Fugue, a language originally implemented by Chris Fraley, and extended by George Polly and Roger Dannenberg. Peter Velikonja and Dean Rubine were early users, and they proved the value as well as discovered some early problems of the system. This led to Nyquist, a reimplementation of Fugue by Roger Dannenberg with help from Joe Newcomer and Cliff Mercer. Ning Hu ported Zheng (Geoffrey) Hua and Jim Beauchamp's piano synthesizer to Nyquist and also built NyqIDE, the Nyquist Integrated Development Environment for Windows. Dave Mowatt contributed the original version of jNyqIDE, the cross-platform interactive development environment. Dominic Mazzoni made a special version of Nyquist that runs within the Audacity audio editor, giving Nyquist a new interface and introducing Nyquist to many new users. Many others have since contributed to Nyquist. Chris Tchou and Morgan Green worked on the Windows port. Eli Brandt contributed a number of filters and other synthesis functions. Pedro J. Morales, Eduardo Reck Miranda, Ann Lewis, and Erich Neuwirth have all contributed nyquist examples found in the demos folder of the Nyquist distribution. Philip Yam ported some synthesis functions from Perry Cook and Gary Scavone's STK to Nyquist. Pedro Morales ported many more STK instruments to Nyquist. Dave Borel wrote the Dolby Pro-Logic encoding library and Adam Hartman wrote stereo and spatialization effects. Stephen Mangiat wrote the MiniMoog emulator. Phil Light recorded the drum samples and wrote drum machine software. The Xmusic library, particularly the pattern specification, was inspired by Rick Taube's Common Music. The functions for generating probability distributions were implemented by Andreas Pfenning. Starting with Version 3, Nyquist supports a version of SAL, providing an alternative to Lisp syntax. SAL was designed by Rick Taube, and the SAL implementation in Nyquist is based on Taube's original implementation as part of his Common Music system. The current jNyqIDE includes contributions from many. Chris Yealy and Derek D'Souza implemented early versions of the envelope editor. Daren Makuck and Michael Rivera wrote the original equalizer editor. Priyanka Raghavan implemented the sound browser. Many others have made contributions, offered suggestions, and found bugs. If you were expecting to find your name here, I apologize for the omission, and please let me know. I also wish to acknowledge support from CMU, Yamaha, and IBM for this work. @newpage @blankspace(5 inches) @pragma(startscribe) . @pragma(endscribe) @newpage @set(page=1) @style(pagenumbers="@1") @chapter(Introduction and Overview) Nyquist is a language for sound synthesis and music composition. Unlike score languages that tend to deal only with events, or signal processing languages that tend to deal only with signals and synthesis, Nyquist handles both in a single integrated system. Nyquist is also flexible and easy to use because it is based on an interactive Lisp interpreter. With Nyquist, you can design instruments by combining functions (much as you would using the orchestra languages of Music V, cmusic, or Csound). You can call upon these instruments and generate a sound just by typing a simple expression. You can combine simple expressions into complex ones to create a whole composition. Nyquist runs under Linux, Apple Mac OS X, Microsoft Windows NT, 2000, XP, and Vista, and it produces sound files or directly generates audio. Recent versions have also run on AIX, NeXT, SGI, DEC pmax, and Sun Sparc machines. (Makefiles for many of these are included, but out-of-date). Let me know if you have problems with any of these machines. To use Nyquist, you should have a basic knowledge of Lisp. An excellent text by Touretzky is recommended @cite(Touretzky). Appendix @ref(xlisp-app) is the reference manual for XLISP, of which Nyquist is a superset. Starting with Version 3, Nyquist supports a variant of SAL, which is also available in Common Music. Since there are some differences, one should generally call this implementation ``Nyquist SAL;'' however, in this manual, I will just call it ``SAL.'' SAL offers most of the capabilities of Lisp, but it uses an Algol-like syntax that may be more familiar to programmers with experience in Java, C, Basic, etc. @label(install-sec) @section(Installation) @index(installation)@index(configure nyquist)@index(setup nyquist) Nyquist is a C program intended to run under various operating systems including Unix, MacOS, and Windows. @subsection(Unix Installation) For Unix systems, Nyquist is distributed as a compressed tar file named @code(nyqsrc3@i(nn).zip), where @i(nn) is the version number (e.g. v3.01 was in @code(nyqsrc301.zip)). To install Nyquist, copy @code(nyqsrc3@i(nn).zip) to the directory on your machine where you would like to install Nyquist, and type: @begin(example) gunzip nyqsrc3@i(nn).zip cd nyquist ln -s sys/unix/linux/Makefile Makefile setenv XLISPPATH `pwd`/runtime:`pwd`/lib make @end(example) The first line creates a @code(nyquist) directory and some subdirectories. The second line (cd) changes directories to the new nyquist directory. The third line makes a link from the top-level directory to the Makefile for your system. In place of @code(linux) in @code(sys/unix/linux/Makefile), you should substitute your system type. Current systems are @code(next), @code(pmax), @code(rs6k), @code(sgi), @code(linux), and @code(sparc). The @code(setenv) command tells Nyquist where to search for lisp files to be loaded when a file is not found in the current directory. The @code(runtime) directory should always be on your @code(XLISPPATH) when you run Nyquist, so you may want to set @code(XLISPPATH) in your shell startup file, e.g. @code(.cshrc). Assuming the make completes successfully, you can run Nyquist as follows: @begin(example) ./ny @end(example) When you get the prompt, you may begin typing expressions such as the ones in the following ``Examples'' section. One you establish that Nyquist (ny) is working from the command line, you should try using jNyqIDE, the Java-based Nyquist development environment. First, make @code(jny) executable (do this only once when you install Nyquist): @begin(example) chmod +x jny @end(example) Then try running jNyqIDE by typing: @begin(example) ./jny @end(example) If the jNyqIDE window does not appear, make sure you have Java installed (if not, you probably already encountered errors when you ran @code(make)). You can also try recompiling the Java files: @begin(example) cd jnyqide javac *.java cd .. @end(example) @p(Note:) With Linux and the Macintosh OS X, jNyqIDE defines the environment passed to Nyquist. If you set @code(XLISPPATH)@index(XLISPPATH)@index(search path) as shown above, it will be passed along to Nyquist under jNyqIDE. If not, a default XLISPPATH will have the @code(lib) and @code(runtime) directories only. This does not apply to Windows because even though the environment is there, the Windows version of Nyquist reads the @code(XLISPPATH) from the Registry. You can also specify the search path by creating the file @code(nyquist/xlisppath), which should have colon-separated paths on a single line of text. This file will override the environment variable @code(XLISPPATH). It is good to have @code(USER) in the environment with your user ID. This string is used to construct some file names. jNyqIDE will look for it in the environment. You can also specify your user ID using the file @code(nyquist/user), but if you have a shared installation of Nyquist, this will not be very useful. @p(Note:) Nyquist looks for the file @code(init.lsp) in the current directory. If you look in the @code(init.lsp) in @code(runtime), you will notice two things. First, @code(init.lsp) loads @code(nyquist.lsp) from the Nyquist directory, and second, @code(init.lsp) loads @code(system.lsp) which in turn defines the macro @code(play). You may have to modify @code(system.lsp) to invoke the right programs on your machine. @subsection(Win32 Installation) The Win32 version of Nyquist is packaged as a compiled (runtime) system in an executable installer. A source version is also available (the same source download is for Win32, Mac OS X, and Linux). The source version is intended for developers who want to recompile Nyquist. The contents of the source archive are extracted to the @code(C:\nyquist) directory, but you can put it anywhere you like. You can then open the workspace file, nyquist.sln, using Microsoft Visual C++. You can build and run the command line version of Nyquist from within Visual C++. There is a batch file, @code(comp-ide.bat), for bulding the Nyquist IDE. This requires the Java SDK from Sun Microsystems. The runtime version contain everything you need to run Nyquist, including the executable, examples, and documentation, packaged as an executable installer program. After executing the installer, just find Nyquist in your Start menu to run it. You may begin typing expressions such as the ones in the following ``Examples'' section. @begin(comment) THIS STUFF IS OUT OF DATE The Win32 version of Nyquist is packaged as n three versions: the source version and two runtime versions. The source version is a superset of the runtime version intended for developers who want to recompile Nyquist. The source version exists as a @code(.zip) file, so you need a utility like WinZip to unpack them. The URL @code(http://www.winzip.com/) has information on this product. Typically, the contents of the zip file are extracted to the @code(C:\nyquist) directory, but you can put it anywhere you like. You can then open the workspace file, nyquist.sln, using Microsoft Visual C++. You can build and run the command line and the NyqWin versions of Nyquist from within Visual C++. The runtime versions contain everything you need to run Nyquist, including the executable, examples, and documentation. Each runtime version is packaged as an executable installer program. I recommend @code(setupnyqiderun2xx.exe) (``2xx'' refers to the current version number), a graphical interface written in Java that runs nyquist.exe as a separate process. This IDE has a simple lisp editor built in. Alternatively, you can install @code(setupnyqwinrun2xx.exe), a different graphical interface written in C++. Just copy the installer you want to your system and run it. Then find Nyquist in your Start menu to run it. You may begin typing expressions such as the ones in the following ``Examples'' section. @end(comment) @p(Optional:)@index(Registry)@index(xlisppath)@index(search path) Nyquist needs to know where to find the standard runtime files. The location of runtime files must be stored in the Registry. The installers create a registry entry, but if you move Nyquist or deal with different versions, you can edit the Registry manually as follows: @begin(itemize) Run the Registry editor. Under Windows NT, run @code(C:\WINNT\system32\regedt32.exe). Under Windows95, run @code(C:\WINDOWS\regedit.exe). Find and highlight the @code(SOFTWARE) key under @code(HKEY_LOCAL_MACHINE). Choose @code(Add key ...) from the @code(Edit) menu, type @code(CMU), and click the @code(OK) button. Highlight the new @code(CMU) key. Choose @code(Add key ...) from the @code(Edit) menu, type @code(Nyquist), and click the @code(OK) button. (Note that @code(CMU) and @code(Nyquist) are case sensitive.) Highlight the new @code(Nyquist) key. Choose @code(Add value ...) from the @code(Edit) menu, type @code(XLISPPATH), and click the @code(OK) button. (Under WinXP the menu item is @code(Edit:New:String Value), after which you need to select the new string name that appears in the right panel, select @code(Edit:Rename), and type @code(XLISPPATH).) In the String Edit box (select the @code(Edit:Modify) menu item in WinXP), type a list of paths you want Nyquist to search for lisp files. For example, if you installed Nyquist as @code(C:\nyquist), then type: @begin(example) C:\nyquist\runtime,C:\nyquist\lib @end(example) The paths should be separated by a comma or semicolon and no space. The @code(runtime) path is essential, and the @code(lib) path may become essential in a future release. You can also add paths to personal libraries of Lisp and Nyquist code. Click the @code(OK) button of the string box and exit from the Registry Editor application. @end(itemize) @paragraph(What if Nyquist functions are undefined?) If you do not have administrative privileges for your machine, the installer may fail to set up the Registry entry that Nyquist uses to find initialization files. In this case, Nyquist will run a lisp interpreter, but many Nyquist functions will not be defined. If you can log in as administrator, do it and reinstall Nyquist. If you do not have permission, you can still run Nyquist as follows: Create a file named @code(init.lsp) in the same directory as Nyquist.exe (the default location is @code(C:\Program Files\Nyquist), but you may have installed it in some other location.) Put the following text in @code(init.lsp): @begin(example) @begin(smallcode) (setf *search-path* "C:/Program Files/Nyquist/runtime,C:/Program Files/Nyquist/lib") (load "C:/Program Files/Nyquist/runtime/init.lsp") @end(smallcode) @end(example) @p(Note:) in the three places where you see @code(C:/Program Files/Nyquist), insert the full path where Nyquist is actually installed. Use forward slashes (@code(/)) rather than back slashes (@code(\)) to separate directories. For example, if Nyquist is installed at @code(D:\rbd\nyquist), then @code(init.lsp) should contain: @begin(example) @begin(smallcode) (setf *search-path* "D:/rbd/nyquist/runtime,D:/rbd/nyquist/lib") (load "d:/rbd/nyquist/runtime/init.lsp") @end(smallcode) @end(example) The variable @code(*search-path*), if defined, is used in place of the registry to determine search paths for files. @paragraph(SystemRoot) @index(SystemRoot) (Ignore this paragraph if you are not planning to use Open Sound Control under Windows.) If Nyquist prints an error message and quits when you enable Open Sound Control (using @code(osc-enable)), check to see if you have an environment variable @code(SystemRoot), e.g. type @code(set) to a command prompt and look for the value of @code(SystemRoot). The normal value is @code(C:\windows). If the value is something else, you should put the environment entry, for example: @begin(example) SystemRoot="D:\windows" @end(example) into a file named @code(systemroot) (no extension). Put this file in your @code(nyquist) directory. When you run @code(jNyqIDE), it will look for this file and pass the contents as an environment variable to Nyquist. The Nyquist process needs this to open a UDP socket, which is needed for Open Sound Control. @paragraph(The "java is not recognized" Error) Sometimes, Nyquist will run directly from the installer, but then it will not start from the Windows Start menu. You can try running the @code(nyquist/jnyqide.bat) program from a Windows shell. If that fails, and you see an error similar to "java is not recognized as in internal or external command error", the problem may be that paths are not set up properly to allow the Windows shell to find java. Right click on ``My Computer'' on the Windows desktop and select ``Properties.'' Under the ``Advanced'' tap, press the ``Environment Variables'' button, and look for PATH under ``System Variables.'' Make sure the Java bin directory is on the path. If it is not, you will have to find your installation of Java and add the appropriate directory to the PATH variable, e.g. ``C:\Program Files\Java\jdk1.6.0\bin.'' @subsection(MacOS X Installation) The OS X version of Nyquist is very similar to the Linux version, but it is developed using Xcode, Apple's programming environment. With a little work, you can use the Linux installation instructions to compile Nyquist, but it might be simpler to just open the Xcode project that is included in the Nyquist sources. You can also download a pre-compiled version of Nyquist for the Mac. Just download @code(nyqosx2xx.tgz) to the desktop and open it to extract the folder nyqosx2xx. (Again, "2xx" refers to the current version number, e.g. v2.31 would be named with "231".) Open the folder to find a Mac Application named jNyqIDE and a directory named nyquist/doc. Documentation is in the nyquist/doc directory. The file jNyqIDE.app/Contents/Resources/Java/ny is the command line executable (if you should need it). To run from the command line, you will need to set the XLISPPATH environment variable as with Linux. On the topic of the @code(XLISPPATH), note that this variable is set by jNyqIDE when running with that application, overriding any other value. You can extend the search path by creating the file @code(xlisppath) in the same directory as the nyquist executable @code(ny). The @code(xlisppath) file should have colon-separated paths on a single line of text. @section(Using jNyqIDE)@index(jNyqIDE)@index(IDE)@index(Integrated Development Environment) The program named jNyqIDE is an ``integrated development environment'' for Nyquist. When you run jNyqIDE, it starts the Nyquist program and displays all Nyquist output in a window. jNyqIDE helps you by providing a Lisp and SAL editor, hints for command completion and function parameters, some graphical interfaces for editing envelopes and graphical equalizers, and a panel of buttons for common operations. A more complete description of jNyqIDE is in Chapter @ref(jnyqide-chapter). For now, all you really need to know is that you can enter Nyquist commands by typing into the upper left window. When you type return, the expression you typed is sent to Nyquist, and the results appear in the window below. You can edit files by clicking on the New File or Open File buttons. After editing some text, you can load the text into Nyquist by clicking the Load button. jNyqIDE always saves the file first; then it tells Nyquist to load the file. You will be prompted for a file name the first time you load a new file. @section(Using SAL) SAL mode means that Nyquist reads and evaluates SAL commands rather than Lisp. The SAL mode prompt is "@code(SAL> )" while the Lisp mode prompt is "@code(> )". When Nyquist starts it normally enters SAL mode automatically, but certain errors may exit SAL mode. You can reenter SAL mode by typing the Lisp expression @code[(sal)]. In SAL mode, you type commands in the SAL programming language. Nyquist reads the commands, compiles them into Lisp, and evaluates the commands. Commands can be entered manually by typing into the upper left text box in jNyqIDE. @section(Helpful Hints) Under Win95 and Win98, the console sometimes locks up. Activating another window and then reactivating the Nyquist window should unlock the output. (We suggest you use JNyqIDE, the interactive development environment rather than a console window.) You can cut and paste text into Nyquist, but for serious work, you will want to use the Lisp @code(load) command. To save even more time, write a function to load your working file, e.g. @code[(defun l () (load "myfile.lsp"))]. Then you can type @code[(l)] to (re)load your file. Using SAL, you can type @begin(example) define function l () load "myfile.lsp" @end(example) and then @begin(example) exec l() @end(example) to (re)load the file. The Emacs editor is free GNU software and will help you balance parentheses if you use Lisp mode. In fact, you can run nyquist (without the IDE) as a subprocess to Emacs. A helful discussion is at //http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/examples/emacs/main.html. If you use Emacs, there is also a SAL mode (the file is @code(sal-mode.el)) included with the Common Music distribution, which you can find on the Web at @code(sourceforge.net). The jNyqIDE also runs Nyquist as a subprocess and has built-in Lisp and SAL editors. If your editor does not help you balance parentheses, you may find yourself counting parens and searching for unbalanced expressions. If you are confused or desperate, try the @code(:print t) option o fthe @code(load) command. By looking at the expressions printed, you should be able to tell where the last unbalanced expression starts. Alternatively, type @code[(file-sexprs)] and type the lisp file name at the prompt. This function will read and print expressions from the file, reporting an error when an extra paren or end-of-file is reached unexpectedly. @section(Using Lisp) Lisp mode means that Nyquist reads and evaluates Nyquist expressions in Lisp syntax. Since Nyquist is build on a Lisp interpreter, this is the ``native'' or machine language of Nyquist, and certain errors and functions may break out of the SAL interpreter, leaving you with a prompt for a Lisp expression. Alternatively, you can exit SAL simply by typing @code(exit) to get a Lisp prompt (@code(> )). Commands can be entered manually by typing into the upper left text box in jNyqIDE. @section(Examples) We will begin with some simple Nyquist programs. Throughout the manual, we will assume SAL mode and give examples in SAL, but it should be emphasized that all of these examples can be performed using Lisp syntax. See Section @ref(sal-vs-lisp-section) on the relationship between SAL and Lisp. Detailed explanations of the functions used in these examples will be presented in later chapters, so at this point, you should just read these examples to get a sense of how Nyquist is used and what it can do. The details will come later. Most of these examples can be found in the file @code(nyquist/demos/examples.sal). Corresponding Lisp syntax examples are in the file @code(nyquist/demos/examples.lsp). Our first example makes and plays a sound:@index(osc)@index(play) @begin(example) @i(;; Making a sound.) play osc(60) ; generate a loud sine wave @comment{(play (osc 60)) @i(; generate a loud sine wave)} @end(example) This example is about the simplest way to create a sound with Nyquist. The @code(osc) function generates a sound using a table-lookup oscillator. There are a number of optional parameters, but the default is to compute a sinusoid with an amplitude of 1.0. The parameter @code(60) designates a pitch of middle C. (Pitch specification will be described in greater detail later.) The result of the @code(osc) function is a sound. To hear a sound, you must use the @code(play) command, which plays the file through the machine's D/A converters. It also writes a soundfile in case the computation cannot keep up with real time. You can then (re)play the file by typing: @begin(example) exec r() @end(example) This @code[(r)] function is a general way to ``replay'' the last thing written by @code(play). Note: when Nyquist plays a sound, it scales the signal by 2@+(15)-1 and (by default) converts to a 16-bit integer format. A signal like @code[(osc 60)], which ranges from +1 to -1, will play as a full-scale 16-bit audio signal. @subsection(Waveforms) @label(waveform-sec) Our next example will be presented in several steps. The goal is to create a sound using a wavetable consisting of several harmonics as opposed to a simple sinusoid. In order to build a table, we will use a function that computes a single harmonic and add harmonics to form a wavetable. An oscillator will be used to compute the harmonics. @begin(comment) Ordinarily, Nyquist programs are sample-rate independent, and time (in seconds) is used rather than sample numbers to indicate regions of signals. Since we want a wave-table with a certain integer number of samples, we need to do some extra calculations to convert from time to samples. The @code(build-harmonic) function (see Figure @ref(build-harmonic-fig)) produces a signal with @code(n) periods in the course of 2048 samples using the @code(snd-sine) function. @begin(figure) @begin(example) (defun build-harmonic (n tablesize) (snd-sine 0 n tablesize 1)) @end(example) @fillcaption(@code(build-harmonic) uses a low-level function, @code(snd-sine), to construct a harmonic. The function parameters denote: ``compute a sinusoid starting at time zero, with frequency @i(n), a sample rate of @i(tablesize) samples per second and a duration of 1 second.'' This signal becomes a periodic waveform to be resampled by a table lookup oscillator, so the choice of sample rate and duration is a matter of convenience. @tag(build-harmonic-fig) @end(figure) @end(comment) The function @code(mkwave@index(mkwave)) calls upon @code(build-harmonic@index(build-harmonic)) to generate a total of four harmonics with amplitudes 0.5, 0.25, 0.125, and 0.0625. These are scaled and added (using @code(+@index(sim))) to create a waveform which is bound temporarily to @code(*table*). A complete Nyquist waveform is a list consisting of a sound, a pitch, and @code(T), indicating a periodic waveform. The pitch gives the nominal pitch of the sound. (This is implicit in a single cycle wave table, but a sampled sound may have many periods of the fundamental.) Pitch is expressed in half-steps, where middle C is 60 steps, as in MIDI pitch numbers. The list of sound, pitch, and @code(T) is formed in the last line of @code(mkwave): since @code(build-harmonic) computes signals with a duration of one second, the fundamental is 1 Hz, and the @code(hz-to-step) function converts to pitch (in units of steps) as required. @begin(example)@label(build-harmonic-example) define function mkwave() begin set *table* = 0.5 * build-harmonic(1.0, 2048) + 0.25 * build-harmonic(2.0, 2048) + 0.125 * build-harmonic(3.0, 2048) + 0.0625 * build-harmonic(4.0, 2048) set *table* = list(*table*, hz-to-step(1.0), #t) end @end(example) Now that we have defined a function, the last step of this example is to build the wave. The following code calls @code(mkwave) the first time the code is executed (loaded from a file). The second time, the variable @code(*mkwave*) will be true, so @code(mkwave) will not be invoked: @begin(example) if ! fboundp(quote(*mkwave*)) then begin exec mkwave() set *mkwave* = #t end @end(example) @subsection(Wavetables)@index(wavetables)@index(waveforms)@index(triangle wave)@index(sawtooth wave) When Nyquist starts, several waveforms are created and stored in global variables for convenience. They are: @code(*sine-table*), @code(*saw-table*), and @code(*tri-table*), implementing sinusoid, sawtooth, and triangle waves, respectively. The variable @code(*table*) is initialized to @code(*sine-table*), and it is @code(*table*) that forms the default wave table for many Nyquist oscillator behaviors. If you want a proper, band-limited waveform, you should construct it yourself, but if you do not understand this sentence and/or you do not mind a bit of aliasing, give @code(*saw-table*) and @code(*tri-table*) a try. Note that in Lisp and SAL, global variables often start and end with asterisks (*). These are not special syntax, they just happen to be legal characters for names, and their use is purely a convention. @subsection(Sequences)@index(Sequences) Finally, we define @code(my-note@index(my-note)) to use the waveform, and play several notes in a simple score. Note that the function @code(my-note) has only one command (a @code(return) command), so it is not necessary to use @code(begin) and @code(end). These are only necessary when the function body consists of a sequence of statements: @begin(example) define function my-note(pitch, dur) return osc(pitch, dur, *table*) play seq(my-note(c4, i), my-note(d4, i), my-note(f4, i), my-note(g4, i), my-note(d4, q)) @end(example) Here, @code(my-note) is defined to take pitch and duration as parameters; it calls @code(osc) to do the work of generating a waveform, using @code(*table*) as a wave table. The @code(seq) function is used to invoke a sequence of behaviors. Each note is started at the time the previous note finishes. The parameters to @code(my-note) are predefined in Nyquist: @code(c4) is middle C, @code(i) (for eIghth note) is 0.5, and @code(q) (for Quarter note) is 1.0. See Section @ref(constants-sec) for a complete description. The result is the sum of all the computed sounds. Sequences can also be constructed using the @code(at) transformation to specify time offsets. See @code(sequence_example.htm)@index(sequence_example.htm)@index(score, musical) @code(demos, sequence) for more examples and explanation. @subsection(Envelopes)@index(Envelopes) The next example will illustrate the use of envelopes. In Nyquist, envelopes are just ordinary sounds (although they normally have a low sample rate). An envelope@index(envelope) is applied to another sound by multiplication using the @code(mult@index(mult)) function. The code shows the definition of @code(env-note@index(env-note)), defined in terms of the @code(note) function in the previous example. In @code(env-note), a 4-phase envelope is generated using the @code(env@index(env)) function, which is illustrated in Figure @ref(env-fig). @begin(figure) @center(@graphic((height = 2 in, width = 3.75 in, magnify = 1, postscript = "envfig.ps")) @html(

    ) @fillcaption(An envelope generated by the @code(env) function.) @tag(env-fig) @end(figure) @begin(Example) @i[; env-note produces an enveloped note. The duration ; defaults to 1.0, but stretch can be used to change ; the duration. ; Uses my-note, defined above. ;] define function env-note(p) return my-note(p, 1.0) * env(0.05, 0.1, 0.5, 1.0, 0.5, 0.4) @i[; try it out: ;] play env-note(c4) @end(example) While this example shows a smooth envelope multiplied by an audio signal, you can also multiply audio signals to achieve what is often called @i(ring modulation)@index(ring modulation). See the code and description in @code(demos/scratch_tutorial.htm)@index(demos, ring modulation) for an interesting use of ring modulation to create ``scratch'' sounds. In the next example, The @i(stretch) operator (@code(~))@index(stretch) is used to modify durations: @begin(example) @i[; now use stretch to play different durations ;] play seq(seq(env-note(c4), env-note(d4)) ~ 0.25, seq(env-note(f4), env-note(g4)) ~ 0.5, env-note(c4)) @end(example) In addition to @i(stretch), there are a number of transformations supported by Nyquist, and transformations of abstract behaviors is perhaps @i(the) fundamental idea behind Nyquist. Chapter @ref(behavioral-abstraction-sec) is devoted to explaining this concept, and further elaboration can be found elsewhere @cite(icmcfugue). @subsection(Piece-wise Linear Functions) It is often convenient to construct signals in Nyquist using a list of (time, value) breakpoints which are linearly interpolated to form a smooth signal. Envelopes created by @code(env) are a special case of the more general piece-wise linear functions created by @code(pwl). Since @code(pwl) is used in some examples later on, we will take a look at @code(pwl) now. The @code(pwl) function takes a list of parameters which denote (time, value) pairs. There is an implicit initial (time, value) pair of (0, 0), and an implicit final value of 0. There should always be an odd number of parameters, since the final value (but not the final time) is implicit. Here are some examples: @begin(Example) @i[; symetric rise to 10 (at time 1) and fall back to 0 (at time 2): ;] pwl(1, 10, 2) @i[; a square pulse of height 10 and duration 5. ; Note that the first pair (0, 10) overrides the default initial ; point of (0, 0). Also, there are two points specified at time 5: ; (5, 10) and (5, 0). (The last 0 is implicit). The conflict is ; automatically resolved by pushing the (5, 10) breakpoint back to ; the previous sample, so the actual time will be 5 - 1/sr, where ; sr is the sample rate. ;] pwl(0, 10, 5, 10, 5) @i[; a constant function with the value zero over the time interval ; 0 to 3.5. This is a very degenerate form of pwl. Recall that there ; is an implicit initial point at (0, 0) and a final implicit value of ; 0, so this is really specifying two breakpoints: (0, 0) and (3.5, 0): ;] pwl(3.5) @i[; a linear ramp from 0 to 10 and duration 1. ; Note the ramp returns to zero at time 1. As with the square pulse ; above, the breakpoint (1, 10) is pushed back to the previous sample. ;] pwl(1, 10, 1) @i[; If you really want a linear ramp to reach its final value at the ; specified time, you need to make a signal that is one sample longer. ; The RAMP function does this: ;] ramp(10) @i[; ramp from 0 to 10 with duration 1 + one sample period ; ; RAMP is based on PWL; it is defined in @p(nyquist.lsp). ;] @end(example) @section(Predefined Constants) @label(constants-sec) For convenience and readability, Nyquist pre-defines some constants, mostly based on the notation of the Adagio score language, as follows: @begin(itemize) @b(Dynamics) Note: these dynamics values are subject to change. @begin(display) @t(lppp@index(lppp)) = -12.0 (dB) @t(lpp@index(lpp)) = -9.0 @t(lp@index(lp)) = -6.0 @t(lmp@index(lmp)) = -3.0 @t(lmf@index(lmf)) = 3.0 @t(lf@index(lf)) = 6.0 @t(lff@index(lff)) = 9.0 @t(lfff@index(lfff)) = 12.0 @t(dB0@index(dB0)) = 1.00 @t(dB1@index(dB1)) = 1.122 @t(dB10@index(dB10)) = 3.1623 @end(display) @b(Durations@index(duration notation)) @begin(display) @t(s@index(s)) = Sixteenth@index(Sixteenth note) = 0.25 @t(i@index(i)) = eIghth@index(eIghth note) = 0.5 @t(q@index(q)) = Quarter@index(quarter note) = 1.0 @t(h@index(h)) = Half@index(half note) = 2.0 @t(w@index(w)) = Whole@index(whole note) = 4.0 @t(sd@index(sd), id@index(id), qd@index(qd), hd@index(hd), wd@index(wd)) = dotted durations@index(dotted durations). @t(st@index(st), it@index(it), qt@index(qt), ht@index(ht), wt@index(wt)) = triplet@index(triplet durations) durations. @end(display) @b(Pitches@index(pitch notation)) Pitches are based on an A4 of 440Hz. To achieve a different tuning, set @code(*A4-Hertz*) to the desired frequency for A4, and call @code[(set-pitch-names)]. This will recompute the names listed below with a different tuning. In all cases, the pitch value 69.0 corresponds exactly to 440Hz, but fractional values are allowed, so for example, if you set @code(*A4-Hertz*) to 444 (Hz), then the symbol @code(A4) will be bound to 69.1567, and @code(C4) (middle C), which is normally 60.0, will be 60.1567. @begin(display) @t(c0) = 12.0 @t(cs0, df0) = 13.0 @t(d0) = 14.0 @t(ds0, ef0) = 15.0 @t(e0) = 16.0 @t(f0) = 17.0 @t(fs0, gf0) = 18.0 @t(g0) = 19.0 @t(gs0, af0) = 20.0 @t(a0) = 21.0 @t(as0, bf0) = 22.0 @t(b0) = 23.0 @t(c1) ... @t(b1) = 24.0 ... 35.0 @t(c2) ... @t(b2) = 36.0 ... 47.0 @t(c3) ... @t(b3) = 48.0 ... 59.0 @t(c4) ... @t(b4) = 60.0 ... 71.0 @t(c5) ... @t(b5) = 72.0 ... 83.0 @t(c6) ... @t(b6) = 84.0 ... 95.0 @t(c7) ... @t(b7) = 96.0 ... 107.0 @t(c8) ... @t(b8) = 108.0 ... 119.0 @end(display) @b(Miscellaneous) @begin(display) @codef(ny:all)@pragma(defn)@index(ny:all) = ``all the samples'' (i.e. a big number) = 1000000000 @end(display) @end(itemize) @section(More Examples) More examples can be found in the directory @code(demos), part of the standard Nyquist release. In this directory, you will find the following and more: @begin(itemize) Gong sounds by additive synthesis@index(additive synthesis, gongs) (@code(demos/pmorales/b1.lsp) and @code(demos/mateos/gong.lsp)@index(Gong sounds)@index(demos, gong sound) Risset's spectral analysis of a chord (@code(demos/pmorales/b2.lsp))@index(Risset)@index(demos, spectral analysis of a chord) Bell sounds (@code(demos/pmorales/b3.lsp), @code(demos/pmorales/e2.lsp), @code(demos/pmorales/partial.lsp), and @code(demos/mateos/bell.lsp))@index(demos, bell sound)@index(bell sound) Drum sounds by Risset (@code(demos/pmorales/b8.lsp)@index(demos, drum sound)@index(drum sound) Shepard tones (@code(demos/shepard.lsp) and @code(demos/pmorales/b9.lsp))@index(Shepard tones)@index(endless tones) Random signals (@code(demos/pmorales/c1.lsp)) Buzz with formant filters (@code(demos/pmorales/buzz.lsp)@index(vocal sound)@index(demos, formants) Computing samples directly in Lisp (using Karplus-Strong and physical modelling as examples) (@code(demos/pmorales/d1.lsp)@index(demos, sample-by-sample)@index(DSP in Lisp)@index(Lisp DSP)@index(Karplus-Strong synthesis)@index(physical model)@index(flute sound) FM Synthesis examples, including bell@index(bell sound), wood drum@index(wood drum sound), brass sounds@index(brass sound), tuba sound @index(tuba) (@code(demos/mateos/tuba.lsp) and clarinet sounds@index(clarinet sound) (@code(demos/pmorales/e2.lsp)@index(demos, FM synthesis) Rhythmic patterns (@code(demos/rhythm_tutorial.htm)@index(demos, rhythmic pattern) Drum Samples and Drum Machine (@code(demos/plight/drum.lsp)@index(demos, drum machine)@index(drum samples)@index(drum machine). @end(itemize) @chapter(The jNyqIDE Program) @label(jnyqide-chapter) The jNyqIDE program combines many helpful functions and interfaces to help you get the most out of Nyquist. jNyqIDE is implemented in Java, and you will need the Java runtime system or development system installed on your computer to use jNyqIDE. The best way to learn about jNyqIDE is to just use it. This chapter introduces some of the less obvious features. If you are confused by something and you do not find the information you need here, please contact the author. @section(jNyqIDE Overview) The jNyqIDE runs the command-line version of Nyquist as a subtask, so everything that works in Nyquist should work when using the jNyqIDE and vice-versa. Input to Nyquist is usually entered in the top left window of the jNyqIDE. When you type return, if the expression or statement appears to be complete, the expression you typed is sent to Nyquist. Output from Nyquist appears in a window below. You cannot type into or edit the output window text. The normal way to use the jNyqIDE is to create or open one or more files. You edit these files and then click the Load button. To load a file, jNyqIDE saves the file, sets the current directory of Nyquist to that of the file, then issues a @code(load) command to Nyquist. In this case and several others, you may notice that jNyqIDE sends expressions to Nyquist automatically for evaluation. You can always see the commands and their results in the output window. Notice that when you load a selected file window, jNyqIDE uses @code(setdir) to change Nyquist's current directory. This helps to keep the two programs in sync. Normally, you should keep all the files of a project in the same directory and avoid manually changing Nyquist's current directory (i.e. avoid calling @code(setdir) in your code). Arranging windows in the jNyqIDE can be time-consuming, and depending on the operating system, it is possible for a window to get into a position where you cannot drag it to a new position. The Window:Tile menu command can be used to automatically lay out windows in a rational way. There is a preference setting to determine the height of the completion list relative to the height of the output window. @section(The Button Bar) @index(button bar) There are a number of buttons with frequently-used operations. These are: @begin(itemize) Info @itemsep @index(info button)Print information about Nyquist memory utilization, including the number of free cons cells, the number of garbage collections, the total number of cons cells, the total amount of sample buffer memory, and the amount of memory in free sample buffers. Break @itemsep @index(break button)Send a break character to XLISP. This can be used to enter the debugger (the break loop) while a program is running. Resume by typing @code[(co)]. SAL/Lisp @itemsep @index(SAL button)@index(Lisp button)Switch modes. The button names the mode (SAL or Lisp) you will switch to, not the current mode. For example, if you are in Lisp mode and want to type a SAL command, click the SAL button first. Top @itemsep @index(top button)Enters @code[(top)] into Nyquist. If the XLISP prompt is @code(1>) or some other integer followed by ``@code(>)'', clicking the Top button will exit the debug loop and return to the top-level prompt. Replay @itemsep @index(replay button)Enters @code[(r)] into Nyquist. This command replays the last computed sound. F2-F12 @itemsep @index(Fn button)Enters @code[(f2)] etc. into Nyquist. These commands are not built-in, and allow users to define their own custom actions. Browse @itemsep @index(browse button)Equivalent to the Window:Browse menu item. (See Section @ref(browser).) EQ @itemsep @index(eq button)Equivalent to the Window:EQ menu item. (See Section @ref(eq-window-sec).) EnvEdit @itemsep @index(envedit button)Equivalent to the Window:Envelope Edit menu item. (See Section @ref(envelope-editor-sec).) NewFile @itemsep @index(newfile button)Equivalent to the File:New menu item. Opens a new file editing window for creating and loading a Lisp or SAL program file. OpenFile @itemsep @index(openfile button)Equivalent to the File:Open menu item. Opens an existing Lisp or SAL program file for editing and loading. SaveFile @itemsep @index(savefile button)Equivalent to the File:Save menu item (found on the editing window's menu bar). Saves the contents of an editing window to its associated file. Load @itemsep @index(load button)Equivalent to the File:Load menu item (found on the editing window's menu bar). Performs a Save operation, then sends a command to Nyquist that loads the file as a program. Mark @itemsep @index(mark button)Sends a Control-A to Nyquist. While playing a sound, this displays and records the approximate time in the audio stream. (See Section @ref(play-sec) for more detail.) @end(itemize) @section(Command Completion) To help with programming, jNyqIDE maintains a command-completion window. As you type the first letters of function names, jNyqIDE lists matching functions and their parameters in the Completion List window. If you click on an entry in this window, the displayed expression will replace the incompletely typed function name. A preference allows you to match initial letters or any substring of the complete function name. This is controlled by the ``Use full search for code completion'' preference. In addition, if you right click (or under Mac OS X, hold down the Alt/Option key and click) on an entry, jNyqIDE will display documentation for the function. Documentation can come from a local copy or from the online copy (determined by the ``Use online manual instead of local copy'' preference). Documentation can be displayed within the jNyqIDE window or in an external browser (determined by the ``Use window in jNyqIDE for help browser'' preference.) Currently, the external browser option does not seem to locate documentation properly, but this should be fixed in the future. @section(Browser) @label(browser) @index(browser, jnyqide)@index(sound browser, jnyqide) If you click on the Browse button or use the Window:Browse menu command, jNyqIDE will display a browser window that is pre-loaded with a number of Nyquist commands to create sounds. You can adjust parameters, audition the sounds, and capture the expression that creates the sound. In many cases, the expression checks to see if necessary functions are defined, loading files if necessary before playing the sound. If you want to use a sound in your own program, you can often simplify things by explicitly loading the required file just once at the beginning of your file. Since Nyquist now supports a mix of Lisp and SAL, you may find yourself in the position of having code from the browser in one language while you are working in the other. The best way to handle this is to put the code for the sound you want into a function defined in a Lisp (@code(.lsp)) or SAL (@code(.sal)) file. Load the file (from Lisp, use the @code(sal-load) command to load a SAL file), and call the function from the language of your choice. @section(Envelope Editor) @label(envelope-editor-sec) @index(envelope editor) @index(editor for envelopes) @index(graphical envelope editor) The envelope editor allows you graphically to design and edit piece-wise linear and exponential envelopes. The editor maintains a list of envelopes and you select the one to edit or delete using the drop down list in the Saved Envelopes List area. The current envelope appears in the Graphical Envelope Editor area. You can click to add or drag points. Alternatively, you can use the Envelope Points window to select and edit any breakpoint by typing coordinates. The duration of the envelope is controlled by the Stop field in the Range area, and the vertical axis is controlled by the Min and Max fields. When you click the Save button, @i(all) envelopes are written to Nyquist. You can then use the envelope by treating the envelope name as a function. For example, if you define an envelope named ``fast-attack,'' then you can create the envelope within a Nyquist SAL program by writing the expression @code[fast-attack()]. These edited envelopes are saved to a file named @code(workspace.lsp) @index(workspace) in the current directory. The workspace is Nyquist's mechanism for saving data of all kinds (see Section @ref(workspaces-sec)). The normal way to work with workspaces is to (1) load the workspace, i.e. @code[load "workspace"], as soon as you start Nyquist; (2) invoke the envelope editor to change values in the workspace; and (3) save the workspace at any time, especially before you exit jNyqIDE. If you follow these steps, envelopes will be preserved from session to session, and the entire collection of envelopes will appear in the editor. Be sure to make backups of your @code(workspace.lsp) file along with your other project files. The envelope editor can create linear and exponential envelopes. Use the Type pull-down menu to select the type you want. Envelopes can be created using default starting and ending values using @code(pwl) or @code(pwe), or you can specify the initial values using @code(pwlv) or @code(pwev). The envelope editor uses @code(pwl) or @code(pwe) if no point is explicitly entered as the initial or final point. To create a @code(pwlv) or @code(pwev) function, create a point and drag it to the leftmost or rightmost edge of the graphical editing window. You will see the automatically generated default starting or ending point disappear from the graph. Exponential envelopes should never decay to zero. If you enter a zero amplitude, you will see that the envelope remains at zero to the next breakpoint. To get an exponential decay to ``silence,'' try using an amplitude of about 0.001 (about -60dB). To enter small values like this, you can type them into the Amplitude box and click ``Update Point.'' The Load button refreshes the editor from data saved in the Nyquist process. Normally, there is no need to use this because the editor automatically loads data when you open it. @section(Equalizer Editor) @label(eq-window-sec)@index(equalization editor)@index(graphical equalization) The Equalizer Editor provides a graphical EQ interface for creating and adjusting equalizers. Unlike the envelope editor, where you can type any envelope name, equalizers are named @code(eq-0), @code(eq-1), etc., and you select the equalizer to edit using a pull-down menu. The @code(Set) button should be use to record changes. @chapter(Behavioral Abstraction)@index(behavioral abstraction) @label(behavioral-abstraction-sec) In Nyquist, all functions are subject to transformations@index(transformations). You can think of transformations as additional parameters to every function, and functions are free to use these additional parameters in any way. The set of transformation parameters is captured in what is referred to as the @i(transformation environment@index(transformation environment)). (Note that the term @i(environment) is heavily overloaded in computer science. This is yet another usage of the term.) Behavioral abstraction is the ability of functions to adapt their behavior to the transformation environment. This environment may contain certain abstract notions, such as loudness, stretching a sound in time, etc. These notions will mean different things to different functions. For example, an oscillator should produce more periods of oscillation in order to stretch its output. An envelope, on the other hand, might only change the duration of the sustain portion of the envelope in order to stretch. Stretching a sample could mean resampling it to change its duration by the appropriate amount. Thus, transformations in Nyquist are not simply operations on signals. For example, if I want to stretch a note, it does not make sense to compute the note first and then stretch the signal. Doing so would cause a drop in the pitch. Instead, a transformation modifies the @i(transformation environment) in which the note is computed. Think of transformations as making requests to functions. It is up to the function to carry out the request. Since the function is always in complete control, it is possible to perform transformations with ``intelligence;'' that is, the function can perform an appropriate transformation, such as maintaining the desired pitch and stretching only the ''sustain'' portion of an envelope to obtain a longer note. @section(The Environment)@index(environment) @label(environment-sec) The transformation environment consists of a set of special variables. These variables should not be read directly and should @i(never) be set directly by the programmer. Instead, there are functions to read them, and they are automatically set and restored by transformation operators, which will be described below. The transformation environment consists of the following elements. Although each element has a ``standard interpretation,'' the designer of an instrument or the composer of a complex behavior is free to interpret the environment in any way. For example, a change in @code(*loud*) may change timbre more than amplitude, and @code(*transpose*) may be ignored by percussion instruments: @begin(description) @codef(*warp*@pragma(defn)@index(*warp*))@\Time transformation, including time shift, time stretch, and continuous time warp. The value of @code[*warp*] is interpreted as a function from logical (local score) time to physical (global real) time. Do not access @code(*warp*) directly. Instead, use @code[local-to-global(@i(t))] to convert from a logical (local) time to real (global) time. Most often, you will call @code[local-to-global(0)]. Several transformation operators operate on @code[*warp*], including @i(at) (@code(@@)), @i(stretch) (@code(~)), and @code(warp). @codef(*loud*@pragma(defn)@index(*loud*))@\Loudness, expressed in decibels. The default (nominal) loudness is 0.0 dB (no change). Do not access @code(*loud*) directly. Instead, use @code[get-loud()] to get the current value of @code(*loud*) and either @code(loud) or @code(loud-abs) to modify it. @codef(*transpose*@pragma(defn)@index(*transpose*))@\Pitch transposition, expressed in semitones. (Default: 0.0). Do not access @code(*transpose*) directly. Instead, use @code[get-transpose()] to get the current value of @code(*transpose*) and either @code(transpose) or @code(transpose-abs) to modify it. @codef(*sustain*@pragma(defn)@index(*sustain*))@\The ``sustain,'' ``articulation,'' ``duty factor,'' or amount by which to separate or overlap sequential notes. For example, staccato might be expressed with a @code(*sustain*) of 0.5, while very legato playing might be expressed with a @code(*sustain*) of 1.2. Specifically, @code(*sustain*) stretches the duration of notes (sustain) without affecting the inter-onset time (the rhythm). Do not access @code(*sustain*) directly. Instead, use @code[get-sustain()] to get the current value of @code(*sustain*) and either @code(sustain) or @code(sustain-abs) to modify it. @codef(*start*@pragma(defn)@index(*start*))@\Start time of a clipping region. @i(Note:) unlike the previous elements of the environment, @code(*start*) has a precise interpretation: no sound should be generated before @code(*start*). This is implemented in all the low-level sound functions, so it can generally be ignored. You can read @code(*start*) directly, but use @code(extract) or @code(extract-abs) to modify it. @p(Note 2:) Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, @code(*start*) is not fully implemented. @codef(*stop*@pragma(defn)@index(*stop*))@\Stop time of clipping region. By analogy to @code(*start*), no sound should be generated after this time. @code(*start*) and @code(*stop*) allow a composer to preview a small section of a work without computing it from beginning to end. You can read @code(*stop*) directly, but use @code(extract) or @code(extract-abs) to modify it. @p(Note:) Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, @code(*stop*) is not fully implemented. @codef(*control-srate*@pragma(defn)@index(*control-srate*))@\Sample rate of control signals. This environment element provides the default sample rate for control signals. There is no formal distinction between a control signal and an audio signal. You can read @code(*control-srate*) directly, but use @code(control-srate) or @code(control-srate-abs) to modify it. @codef(*sound-srate*@pragma(defn)@index(*sound-srate*))@\Sample rate of musical sounds. This environment element provides the default sample rate for musical sounds. You can read @code(*sound-srate*) directly, but use @code(sound-srate) or @code(sound-srate-abs) to modify it. @end(description) @section(Sequential Behavior)@index(sequential behavior) Previous examples have shown the use of @code(seq), the sequential behavior operator. We can now explain @code(seq) in terms of transformations. Consider the simple expression: @begin(Example) play seq(my-note(c4, q), my-note(d4, i)) @end(example) The idea is to create the first note at time 0, and to start the next note when the first one finishes. This is all accomplished by manipulating the environment. In particular, @code[*warp*] is modified so that what is locally time 0 for the second note is transformed, or warped, to the logical stop time of the first note. One way to understand this in detail is to imagine how it might be executed: first, @code(*warp*) is set to an initial value that has no effect on time, and @code[my-note(c4, q)] is evaluated. A sound is returned and saved. The sound has an ending time, which in this case will be @code(1.0) because the duration @code(q) is @code(1.0). This ending time, @code(1.0), is used to construct a new @code[*warp*] that has the effect of shifting time by 1.0. The second note is evaluated, and will start at time 1. The sound that is returned is now added to the first sound to form a composite sound, whose duration will be @code(2.0). @code(*warp*) is restored to its initial value. Notice that the semantics of @code(seq) can be expressed in terms of transformations. To generalize, the operational rule for @code(seq) is: evaluate the first behavior according to the current @code(*warp*). Evaluate each successive behavior with @code(*warp*) modified to shift the new note's starting time to the ending time of the previous behavior. Restore @code(*warp*) to its original value and return a sound which is the sum of the results. In the Nyquist implementation, audio samples are only computed when they are needed, and the second part of the @code(seq) is not evaluated until the ending time (called the logical stop time) of the first part. It is still the case that when the second part is evaluated, it will see @code(*warp*) bound to the ending time of the first part. A language detail: Even though Nyquist defers evaluation of the second part of the @code(seq), the expression can reference variables according to ordinary Lisp/SAL scope rules. This is because the @code(seq) captures the expression in a closure, which retains all of the variable bindings. @section(Simultaneous Behavior)@index(Simultaneous Behavior) Another operator is @code(sim), which invokes multiple behaviors at the same time. For example, @begin(example) play 0.5 * sim(my-note(c4, q), my-note(d4, i)) @end(example) will play both notes starting at the same time. The operational rule for @code(sim) is: evaluate each behavior at the current @code(*warp*) and return the sum of the results. (In SAL, the @code(sim) function applied to sounds is equivalent to adding them with the infix @code(+) operator. The following section illustrates two concepts: first, a @i(sound) is not a @i(behavior), and second, the @code(sim) operator and and the @code(at) transformation can be used to place sounds in time. @section(Sounds vs. Behaviors)@index(Sounds vs. Behaviors) The following example loads a sound from a file in the current directory and stores it in @code(a-snd): @begin(example) @i[; load a sound ;] set a-snd = s-read(strcat(current-path(), "demo-snd.aiff")) @i[; play it ;] play a-snd @end(example) One might then be tempted to write the following: @begin(example) play seq(a-snd, a-snd) @i(;WRONG!) @end(example) Why is this wrong? Recall that @code(seq) works by modifying @code(*warp*), not by operating on sounds. So, @code(seq) will proceed by evaluating @code(a-snd) with different values of @code(*warp*). However, the result of evaluating @code(a-snd) (a variable) is always the same sound, regardless of the environment; in this case, the second @code(a-snd) @i(should) start at time @code(0.0), just like the first. In this case, after the first sound ends, Nyquist is unable to ``back up'' to time zero, so in fact, this @i(will) play two sounds in sequence, but that is a result of an implementation detail rather than correct program execution. In fact, a future version of Nyquist might (correctly) stop and report an error when it detects that the second sound in the sequence has a real start time that is before the requested one. How then do we obtain a sequence of two sounds properly? What we really need here is a behavior that transforms a given sound according to the current transformation environment. That job is performed by @code(cue). For example, the following will behave as expected, producing a sequence of two sounds: @begin(example) play seq(cue(a-snd), cue(a-snd)) @end(example) This example is correct because the second expression will shift the sound stored in @code(a-snd) to start at the end time of the first expression. The lesson here is very important: @p(sounds are not behaviors!) Behaviors are computations that generate sounds according to the transformation environment. Once a sound has been generated, it can be stored, copied, added to other sounds, and used in many other operations, but sounds are @i(not) subject to transformations. To transform a sound, use @code(cue), @code(sound), or @code(control). The differences between these operations are discussed later. For now, here is a ``cue sheet'' style score that plays 4 copies of @code(a-snd): @begin(example) @i[; use sim and at to place sounds in time ;] play sim(cue(a-snd) @@ 0.0, cue(a-snd) @@ 0.7, cue(a-snd) @@ 1.0, cue(a-snd) @@ 1.2) @end(example) @section(The At Transformation)@index(At Transformation) The second concept introduced by the previous example is the @code(@@) operation, which shifts the @code(*warp*) component of the environment. For example, @begin(example) cue(a-snd) @@ 0.7 @end(example) can be explained operationally as follows: modify @code[*warp*] by shifting it by @code(0.7) and evaluate @code[cue(a-snd)]. Return the resulting sound after restoring @code(*warp*) to its original value. Notice how @code(@@) is used inside a @code(sim) construct to locate copies of @code(a-snd) in time. This is the standard way to represent a note-list or a cue-sheet in Nyquist. This also explains why sounds need to be @code(cue)'d in order to be shifted in time or arranged in sequence. If this were not the case, then @code(sim) would take all of its parameters (a set of sounds) and line them up to start at the same time. But @code[cue(a-snd) @@ 0.7] is just a sound, so @code(sim) would ``undo'' the effect of @code(@@), making all of the sounds in the previous example start simultaneously, in spite of the @code(@@)! Since @code(sim) respects the intrinsic starting times of sounds, a special operation, @code(cue), is needed to create a new sound with a new starting time. @section(The Stretch Transformation)@index(Stretch Transformation) In addition to At (denoted in SAL by the @code(@@) operator, the Stretch transformation is very important. It appeared in the introduction, and it is denoted in SAL by the @code(~) operator (or in LISP by the @code(stretch) special form). Stretch also operates on the @code(*warp*) component of the environment. For example, @begin(example) osc(c4) ~ 3 @end(example) does the following: modify @code(*warp*), scaling the degree of "stretch" by 3, and evaluate @code[osc(c4)]. The @code(osc) behavior uses the stretch factor to determime the duration, so it will return a sound that is 3 seconds long. Restore @code(*warp*) to its original value. Like At, Stretch only affects behaviors. @code(a-snd ~ 10) is equivalent to @code(a-snd) because @code(a-snd) is a sound, not a behavior. Behaviors are functions that compute sounds according to the environment and return a sound. @section(Nested Transformations)@index(Nested Transformations) Transformations can be combined using nested expressions. For example, @begin(example) sim(cue(a-snd), loud(6.0, cue(a-snd) @@ 3)) @end(example) scales the amplitude as well as shifts the second entrance of @code(a-snd). Why use @code(loud) instead of simply multiplying @code(a-snd) by some scale factor? Using @code(loud) gives the behavior the chance to implement the abstract property @i(loudness) in an appropriate way, e.g. by including timbral changes. In this case, the behavior is @code(cue), which implements @i(loudness) by simple amplitude scaling, so the result is equivalent to multiplication by @code(db-to-linear(6.0)). Transformations can also be applied to groups of behaviors: @begin(example) loud(6.0, sim(cue(a-snd) @@ 0.0, cue(a-snd) @@ 0.7)) @end(example) @section(Defining Behaviors)@index(Defining Behaviors) Groups of behaviors can be named using @code(define) (we already saw this in the definitions of @code(my-note) and @code(env-note)). Here is another example of a behavior definition and its use. The definition has one parameter: @begin(example) define function snds(dly) return sim(cue(a-snd) @@ 0.0, cue(a-snd) @@ 0.7, cue(a-snd) @@ 1.0, cue(a-snd) @@ (1.2 + dly)) play snds(0.1) play loud(0.25, snds(0.3) ~ 0.9) @end(example) In the last line, @code(snds) is transformed: the transformations will apply to the @code(cue) behaviors within @code(snds). The @code(loud) transformation will scale the sounds by @code(0.25), and the @i(stretch) (@code(~)) will apply to the shift (@code(@@)) amounts @code(0.0), @code(0.7), @code(1.0), and @code[1.2 + dly]. The sounds themselves (copies of @code(a-snd)) will not be stretched because @code(cue) never stretches sounds. Section @ref(transformations-sec) describes the full set of transformations. @section(Overriding Default Transformations) In Nyquist, behaviors are @i(the) important abstraction mechanism. A behavior represents a class of related functions or sounds. For example, a behavior can represent a musical note. When a note is stretched, it usually means that the tone sustains for more oscillations, but if the ``note'' is a drum roll, the note sustains by more repetitions of the component drum strokes. The concept of sustain is so fundamental that we do not really think of different note durations as being different instances of an abstract behavior, but in a music programming language, we need a way to model these abtract behaviors. As the tone and drum roll examples show, there is no one right way to ``stretch,'' so the language must allow users to define exactly what it means to stretch. By extension, the Nyquist programmer can define how all of the transformations affect different behaviors. To make programming easier, almost all Nyquist sounds are constructed from primitive behaviors that obey the environment in obvious ways: Stretch transformations make things longer and At transformations shift things in time. But sometimes you have to override the default behaviors. Maybe the attack phase of an envelope should not stretch when the note is stretched, or maybe when you stretch a trill, you should get more notes rather than a slower trill. To override default behaviors, you almost always follow the same programming pattern: first, capture the environment in a local variable; then, use one of the absolute transformations to ``turn off'' the environment's effect and compute the sound as desired. The following example creates a very simple envelope with a fixed rise time to illustrate the technique. @begin(example) define function two-phase-env(rise-time) begin with dur = get-duration(1) return pwl(rise-time, 1, dur) ~~ 1.0 end @end(example) To ``capture the environment in a local variable,'' a @code(with) construct is used to create the local variable @code(dur) and set it to the value of @code[get-duration(1)], which answers the question: ``If I apply use the environment to stretch something whose nominal duration is 1, what is the resulting duration?'' (Since time transformations can involve continuous time deformations, this question is not as simple as it may sound, so please use the provided function rather than peeking inside the @code(*warp*) structure and trying to do it yourself.) Next, we ``turn off'' stretching using the @code(stretch-abs) form, which in SAL is denoted by the @code(~~) operator. Finally, we are ready to compute the envelope using @code(pwl). Here, we use absolute durations. The first breakpoint is at @code(rise-time), so the attack time is given by the @code(rise-time) parameter. The @code(pwl) decays back to zero at time @code(dur), so the overall duration matches the duration expected from the environment encountered by this instance of @code(two-phase-env). Note, however, that since the @code(pwl) is evaluated in a different environment established by @code(~~), it is not stretched (or perhaps more accurately, it is stretched by 1.0). This is good because it means @code(rise-time) will not be stretched, but we must be careful to extend the envelope to @code(dur) so that it has the expected duration. @section(Sample Rates) @index(sample rates) The global environment contains @code(*sound-srate*) and @code(*control-srate*), which determine the sample rates of sounds and control signals. These can be overridden at any point by the transformations @code(sound-srate-abs) and @code(control-srate-abs); for example, @begin(example) sound-srate-abs(44100.0, osc(c4) @end(example) will compute a tone using a 44.1Khz sample rate even if the default rate is set to something different. @index(default sample rate) As with other components of the environment, you should @i(never) change @code(*sound-srate*) or @code(*control-srate*) directly. The global environment is determined by two additional variables: @code(*default-sound-srate*) and @code(*default-control-srate*). You can add lines like the following to your @code(init.lsp) file to change the default global environment: @begin(example) (setf *default-sound-srate* 44100.0) (setf *default-control-srate* 1102.5) @end(example) You can also do this using preferences in jNyqIDE. If you have already started Nyquist and want to change the defaults, the preferences or the following functions can be used: @begin(example) exec set-control-srate(1102.5)@index(set-control-srate) exec set-sound-srate(22050.0)@index(set-sound-srate) @end(example) These modify the default values and reinitialize the Nyquist environment. @chapter(Continuous Transformations and Time Warps) @label(warp-chap) Nyquist transformations were discussed in the previous chapter, but all of the examples used scalar values. For example, we saw the @code[loud] transformation used to change loudness by a fixed amount. What if we want to specify a crescendo, where the loudness changes gradually over time? It turns out that all transformations can accept signals as well as numbers, so transformations can be continuous over time. This raises some interesting questions about how to interpret continuous transformations. Should a loudness transformation apply to the internal details of a note or only affect the initial loudness? It might seem unnatural for a decaying piano note to perform a crescendo. On the other hand, a sustained trumpet sound should probably crescendo continuously. In the case of time warping (tempo changes), it might be best for a drum roll to maintain a steady rate, a trill may or may not change rates with tempo, and a run of sixteenth notes will surely change its rate. These issues are complex, and Nyquist cannot hope to automatically do the right thing in all cases. However, the concept of behavioral abstraction provides an elegant solution. Since transformations merely modify the environment, behaviors are not forced to implement any particular style of transformation. Nyquist is designed so that the default transformation is usually the right one, but it is always possible to override the default transformation to achieve a particular effect. @section(Simple Transformations) The ``simple'' transformations affect some parameter, but have no effect on time itself. The simple transformations that support continuously changing parameters are: @code(sustain), @code(loud), and @code(transpose). As a first example, Let us use @code(transpose) to create a chromatic scale. First define a sequence of tones at a steady pitch. The @code(seqrep) ``function'' works like @code(seq) except that it creates copies of a sound by evaluating an expression multiple times. Here, @code(i) takes on 16 values from 0 to 15, and the expression for the sound could potentially use @code(i). Technically, @code(seqrep) is not really a function but an abbreviation for a special kind of loop construct. @begin(example) define function tone-seq() return seqrep(i, 16, osc-note(c4) ~ 0.25) @end(example) Now define a linearly increasing ramp to serve as a transposition function: @begin(code) define function pitch-rise() return sustain-abs(1.0, 16 * ramp() ~ 4) @end(code) This ramp has a duration of 4 seconds, and over that interval it rises from 0 to 16 (corresponding to the 16 semitones we want to transpose). The ramp is inside a @code(sustain-abs) transformation, which prevents a @code(sustain) transformation from having any effect on the ramp. (One of the drawbacks of behavioral abstraction is that built-in behaviors sometimes do the wrong thing implicitly, requiring some explicit correction to turn off the unwanted transformation.) Now, @code(pitch-rise) is used to transpose @code(tone-seq): @begin(code) define function chromatic-scale() return transpose(pitch-rise(), tone-seq()) @end(code) Similar transformations can be constructed to change the sustain or ``duty factor'' of notes and their loudness. The following expression plays the @code(chromatic-scale) behavior with increasing note durations. The rhythm is unchanged, but the note length changes from staccato to legato: @begin(code) play sustain((0.2 + ramp()) ~ 4, chromatic-scale()) @end(code) The resulting sustain function will ramp from 0.2 to 1.2. A sustain of 1.2 denotes a 20 percent overlap between notes. The @code(sum) has a stretch factor of 4, so it will extend over the 4 second duration of @code(chromatic-scale). If you try this, you will discover that the @code(chromatic-scale) no longer plays a chromatic scale. You will hear the first 4 notes going up in intervals of 5 semitones (perfect fourths) followed by repeated pitches. What is happening is that the @code(sustain) operation applies to @code(pitch-rise) in addition to @code(tone-seq), so now the 4s ramp from 0 to 16 becomes a 0.8s ramp. To fix this problem, we need to shield @code(pitch-rise) from the effect of @code(sustain) using the @code(sustain-abs) transformation. Here is a corrected version of @code(chromatic-scale): @begin(code) define function chromatic-scale() return transpose(sustain-abs(1, pitch-rise()), tone-seq()) @end(code) What do these transformations mean? How did the system know to produce a pitch rise rather than a continuous glissando? This all relates to the idea of behavioral abstraction. It is possible to design sounds that @i(do) glissando under the transpose transform, and you can even make sounds that @i(ignore) transpose altogether. As explained in Chapter @ref(behavioral-abstraction-sec), the transformations modify the environment, and behaviors can reference the environment to determine what signals to generate. All built-in functions, such as @code(osc), have a default behavior. The default behavior for sound primitives under @code(transpose), @code(sustain), and @code(loud) transformations is to sample the environment at the beginning of the note. Transposition is not quantized to semitones or any other scale, but in our example, we arranged for the transposition to work out to integer numbers of semitones, so we obtained a chromatic scale anyway. Transposition only applies to the oscillator and sampling primitives @code(osc), @code(partial), @code(sampler), @code(sine), @code(fmosc), and @code(amosc). Sustain applies to @code(osc), @code(env), @code(ramp), and @code(pwl). (Note that @code(partial), @code(amosc), and @code(fmosc) get their durations from the modulation signal, so they may indirectly depend upon the sustain.) Loud applies to @code(osc), @code(sampler), @code(cue), @code(sound), @code(fmosc), and @code(amosc). (But not @code(pwl) or @code(env).) @section(Time Warps) The most interesting transformations have to do with transforming time itself. The @code(warp) transformation provides a mapping function from logical (score) time to real time. The slope of this function tells us how many units of real time are covered by one unit of score time. This is proportional to 1/tempo. A higher slope corresponds to a slower tempo. To demonstrate @code(warp), we will define a time warp function using @code(pwl): @begin(example) define function warper() return pwl(0.25, .4, .75, .6, 1.0, 1.0, 2.0, 2.0, 2.0) @end(example) This function has an initial slope of .4/.25 = 1.6. It may be easier to think in reciprocal terms: the initial tempo is .25/.4 = .625. Between 0.25 and 0.75, the tempo is .5/.2 = 2.5, and from 0.75 to 1.0, the tempo is again .625. It is important for warp functions to completely span the interval of interest (in our case it will be 0 to 1), and it is safest to extend a bit beyond the interval, so we extend the function on to 2.0 with a tempo of 1.0. Next, we stretch and scale the @code(warper) function to cover 4 seconds of score time and 4 seconds of real time: @begin(example) define function warp4() return 4 * warper() ~ 4 @end(example) @begin(figure) @center(@graphic((height = 3.25 in, width = 3.5 in, magnify = 0.5, postscript = "warpfig.ps")) @html(

    ) @fillcaption{The result of @code[(warp4)], intended to map 4 seconds of score time into 4 seconds of real time. The function extends beyond 4 seconds (the dashed lines) to make sure the function is well-defined at location (4, 4). Nyquist sounds are ordinarily open on the right.} @tag(warp-fig) @end(figure) Figure @ref(warp-fig) shows a plot of this warp function. Now, we can warp the tempo of the @code(tone-seq) defined above using @code(warp4): @begin(example) play warp(warp4(), tone-seq()) @end(example) Figure @ref(warp-notes-fig) shows the result graphically. Notice that the durations of the tones are warped as well as their onsets. Envelopes are not shown in detail in the figure. Because of the way @code(env) is defined, the tones will have constant attack and decay times, and the sustain will be adjusted to fit the available time. @begin(figure) @center(@graphic((height = 1.75 in, width = 6.75 in, magnify = 1.0, postscript = "warpnotesfig.ps")) @html(

    ) @fillcaption[When @code{(warp4)} is applied to @code{(tone-seq-2)}, the note onsets and durations are warped.] @tag(warp-notes-fig) @end(figure) @section(Abstract Time Warps) We have seen a number of examples where the default behavior did the ``right thing,'' making the code straightforward. This is not always the case. Suppose we want to warp the note onsets but not the durations. We will first look at an incorrect solution and discuss the error. Then we will look at a slightly more complex (but correct) solution. The default behavior for most Nyquist built-in functions is to sample the time warp function at the nominal starting and ending score times of the primitive. For many built-in functions, including @code(osc), the starting logical time is 0 and the ending logical time is 1, so the time warp function is evaluated at these points to yield real starting and stopping times, say 15.23 and 16.79. The difference (e.g. 1.56) becomes the signal duration, and there is no internal time warping. The @code(pwl) function behaves a little differently. Here, each breakpoint is warped individually, but the resulting function is linear between the breakpoints. A consequence of the default behavior is that notes stretch when the tempo slows down. Returning to our example, recall that we want to warp only the note onset times and not the duration. One would think that the following would work: @begin(example) define function tone-seq-2 () return seqrep(i, 16, osc-note(c4) ~~ 0.25) play warp(warp4(), tone-seq-2()) @end(example) Here, we have redefined @code(tone-seq), renaming it to @code(tone-seq-2) and changing the stretch (@code(~)) to absolute stretch (@code(~~)). The absolute stretch should override the warp function and produce a fixed duration. If you play the example, you will hear steady sixteenths and no tempo changes. What is wrong? In a sense, the ``fix'' works too well. Recall that sequences (including @code(seqrep)) determine the starting time of the next note from the logical stop time of the previous sound in the sequence. When we forced the stretch to 0.25, we also forced the logical stop time to 0.25 real seconds from the beginning, so every note starts 0.25 seconds after the previous one, resulting in a constant tempo. Now let us design a proper solution. The trick is to use absolute stretch (@code(~~)) as before to control the duration, but to restore the logical stop time to a value that results in the proper inter-onset time interval: @begin(example) define function tone-seq-3() return seqrep(i, 16, set-logical-stop(osc-note(c4) ~~ 0.25, 0.25)) play warp(warp4(), tone-seq-3()) @end(example) Notice the addition of @code(set-logical-stop) enclosing the absolute stretch (@code(~~)) expression to set the logical stop time. A possible point of confusion here is that the logical stop time is set to 0.25, the same number given to @code(~~)! How does setting the logical stop time to 0.25 result in a tempo change? When used within a @code(warp) transformation, the second argument to @code(set-logical-stop) refers to @i(score) time rather than @i(real) time. Therefore, the score duration of 0.25 is warped into real time, producing tempo changes according to the enviroment. Figure @ref(warp-onset-fig) illustrates the result graphically. @begin(figure) @center(@graphic((height = 1.75 in, width = 6.75 in, magnify = 1.0, postscript = "warponsetfig.ps")) @html(

    ) @fillcaption[When @code[(warp4)] is applied to @code[(tone-seq-3)], the note onsets are warped, but not the duration, which remains a constant 0.25 seconds. In the fast middle section, this causes notes to overlap. Nyquist will sum (mix) them.] @tag(warp-onset-fig) @end(figure) @section(Nested Transformations) Transformations can be nested. In particular, a simple transformation such as transpose can be nested within a time warp transformation. Suppose we want to warp our chromatic scale example with the @code(warp4) time warp function. As in the previous section, we will show an erroneous simple solution followed by a correct one. The simplest approach to a nested transformation is to simply combine them and hope for the best: @begin(example) play warp(warp4(), transpose(pitch-rise(), tone-seq())) @end(example) This example will not work the way you might expect. Here is why: the warp transformation applies to the @code[(pitch-rise)] expression, which is implemented using the @code(ramp) function. The default behavior of @code(ramp) is to interpolate linearly (in real time) between two points. Thus, the ``warped'' @code(ramp) function will not truly reflect the internal details of the intended time warp. When the notes are moving faster, they will be closer together in pitch, and the result is not chromatic. What we need is a way to properly compose the warp and ramp functions. If we continuously warp the ramp function in the same way as the note sequence, a chromatic scale should be obtained. This will lead to a correct solution. Here is the modified code to properly warp a transposed sequence. Note that the original sequence is used without modification. The only complication is producing a properly warped transposition function: @begin(example) play warp(warp4(), transpose( control-warp(get-warp(), warp-abs(nil, pitch-rise())), tone-seq())) @end(example) To properly warp the @code(pitch-rise) transposition function, we use @code(control-warp), which applies a warp function to a function of score time, yielding a function of real time. We need to pass the desired function to @code(control-warp), so we fetch it from the environment with @code[get-warp()]. Finally, since the warping is done here, we want to shield the @code(pitch-rise) expression from further warping, so we enclose it in @code[warp-abs(nil, ...)]. @i(An aside:) This last example illustrates a difficulty in the design of Nyquist. To support behavioral abstraction universally, we must rely upon behaviors to ``do the right thing.'' In this case, we would like the @code(ramp) function to warp continuously according to the environment. But this is inefficient and unnecessary in many other cases where @code(ramp) and especially @code(pwl) are used. (@code(pwl) warps its breakpoints, but still interpolates linearly between them.) Also, if the default behavior of primitives is to warp in a continuous manner, this makes it difficult to build custom abstract behaviors. The final vote is not in. @chapter(More Examples) This chapter explores Nyquist through additional examples. The reader may wish to browse through these and move on to Chapter @ref(lisp-chap), which is a reference section describing Nyquist functions. @section(Stretching Sampled Sounds)@index(Stretching Sampled Sounds) This example illustrates how to stretch a sound, resampling it in the process. Because sounds in Nyquist are @i(values) that contain the sample rate, start time, etc., use @code(sound) to convert a sound into a behavior that can be stretched, e.g. @code[sound(a-snd)]. This behavior stretches a sound according to the stretch factor in the environment, set using @code(stretch). For accuracy and efficiency, Nyquist does not resample a stretched sound until absolutely necessary. The @code(force-srate) function is used to resample the result so that we end up with a ``normal'' sample rate that is playable on ordinary sound cards. @begin(example) @i[; if a-snd is not loaded, load sound sample: ;] if not(boundp(quote(a-snd))) then set a-snd = s-read("demo-snd.aiff") @i[; the SOUND operator shifts, stretches, clips and scales ; a sound according to the current environment ;] define function ex23() play force-srate(*default-sound-srate*, sound(a-snd) ~ 3.0) define function down() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.2, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.6)) play down() @i[; that was so much fun, let's go back up: ;] define function up() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.5, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.2)) @i[; and write a sequence ;] play seq(down(), up(), down()) @end(example) Notice the use of the @code(sound) behavior as opposed to @code(cue). The @code(cue) behavior shifts and scales its sound according to @code(*warp*) and @code(*loud*), but it does not change the duration or resample the sound. In contrast, @code(sound) not only shifts and scales its sound, but it also stretches it by resampling or changing the effective sample rate according to @code(*warp*). If @code[*warp*] is a continuous warping function, then the sound will be stretched by time-varying amounts. (The @code(*transpose*) element of the environment is ignored by both @code(cue) and @code(sound).) @p(Note:) @code(sound) may use linear interpolation rather than a high-quality resampling algorithm. In some cases, this may introduce errors audible as noise. Use @code(resample) (see Section @ref(resample-sec)) for high-quality interpolation. In the functions @code(up) and @code(down), the @code(*warp*) is set by @i(stretch) (@code(~)), which simply scales time by a constant scale factor. In this case, @code(sound) can ``stretch'' the signal simply by changing the sample rate without any further computation. When @code(seq) tries to add the signals together, it discovers the sample rates do not match and uses linear interpolation to adjust all sample rates to match that of the first sound in the sequence. The result of @code(seq) is then converted using @code(force-srate) to convert the sample rate, again using linear interpolation. It would be slightly better, from a computational standpoint, to apply @code(force-srate) individually to each stretched sound rather than applying @code(force-srate) after @code(seq). Notice that the overall duration of @code[sound(a-snd) ~ 0.5] will be half the duration of @code(a-snd). @section(Saving Sound Files)@index(Saving Sound Files) So far, we have used the @code(play) command to play a sound. The @code(play) command works by writing a sound to a file while simultaneously playing it. This can be done one step at a time, and it is often convenient to save a sound to a particular file for later use: @begin(example) @i[; write the sample to a file, ; the file name can be any Unix filename. Prepending a "./" tells ; s-save to not prepend *default-sf-dir* ;] exec s-save(a-snd, 1000000000, "./a-snd-file.snd") @i[; play a file ; play command normally expects an expression for a sound ; but if you pass it a string, it will open and play a ; sound file] play "./a-snd-file.snd" @i[; delete the file (do this with care!) ; only works under Unix (not Windows)] exec system("rm ./a-snd-file.snd") @i[; now let's do it using a variable as the file name ;] set my-sound-file = "./a-snd-file.snd" exec s-save(a-snd, 1000000000, my-sound-file) @i[; play-file is a function to open and play a sound file] exec play-file(my-sound-file) exec system(strcat("rm ", my-sound-file)) @end(example) This example shows how @code(s-save) can be used to save a sound to a file. This example also shows how the @code(system) function can be used to invoke Unix shell commands, such as a command to play a file or remove it. Finally, notice that @code(strcat) can be used to concatenate a command name to a file name to create a complete command that is then passed to @code(system). (This is convenient if the sound file name is stored in a parameter or variable.) @section(Memory Space and Normalization) @label(normalization-sec) @index(normalization)@index(peak amplitude)@index(maximum amplitude)@index(clip)@index(s-max)@index(s-min)@index(rescaling)@index(not enough memory for normalization) Sound samples take up lots of memory, and often, there is not enough primary (RAM) memory to hold a complete composition. For this reason, Nyquist can compute sounds incrementally, saving the final result on disk. @i(However,) Nyquist can also save sounds in memory so that they can be reused efficiently. In general, if a sound is saved in a global variable, memory will be allocated as needed to save and reuse it. The standard way to compute a sound and write it to disk is to pass an expression to the @code(play) command: @begin(example) play my-composition() @end(example) @label(peak-ex-sec) Often it is nice to @i(normalize) sounds so that they use the full available dynamic range of 16 bits. Nyquist has an automated facility to help with normalization. By default, Nyquist computes up to 1 million samples (using about 4MB of memory) looking for the peak. The entire sound is normalized so that this peak will not cause clipping. If the sound has less than 1 million samples, or if the first million samples are a good indication of the overall peak, then the signal will not clip. With this automated normalization technique, you can choose the desired peak value by setting @code(*autonorm-target*), which is initialized to 0.9. The number of samples examined is @code(*autonorm-max-samples*), initially 1 million. You can turn this feature off by executing: @begin(example) exec autonorm-off()@index(autonorm-off) @end(example) and turn it back on by typing: @begin(example) exec autonorm-on()@index(autonorm-on) @end(example) This normalization technique is in effect when @code(*autonorm-type*) is @code(quote(lookahead)), which is the default. An alternative normalization method uses the peak value from the previous call to @code(play). After playing a file, Nyquist can adjust an internal scale factor so that if you play the same file again, the peak amplitude will be @code(*autonorm-target*), which is initialized to 0.9. This can be useful if you want to carefully normalize a big sound that does not have its peak near the beginning. To select this style of normalization, set @code(*autonorm-type*) to the (quoted) atom @code(quote(previous)). You can also create your own normalization method in Nyquist. The @code(peak) function computes the maximum value of a sound. The peak value is also returned from the @code(play) macro. You can normalize in memory if you have enough memory; otherwise you can compute the sound twice. The two techniques are illustrated here: @begin(example) @i[; normalize in memory. First, assign the sound to a variable so ; it will be retained:] set mysound = sim(osc(c4), osc(c5)) @i[; now compute the maximum value (ny:all is 1 giga-samples, you may want a ; smaller constant if you have less than 4GB of memory:] set mymax = snd-max(mysound, NY:ALL) display "Computed max", mymax @i[; now write out and play the sound from memory with a scale factor:] play mysound * (0.9 / mymax) @i[; if you don't have space in memory, here's how to do it:] define function myscore() return sim(osc(c4), osc(c5)) @i[; compute the maximum:] set mymax = snd-max(list(quote(myscore)), NY:ALL) display "Computed max", mymax @i[; now we know the max, but we don't have a the sound (it was garbage ; collected and never existed all at once in memory). Compute the sound ; again, this time with a scale factor:] play myscore() * (0.9 / mymax) @end(example) You can also write a sound as a floating point file. This file can then be converted to 16-bit integer with the proper scaling applied. If a long computation was involved, it should be much faster to scale the saved sound file than to recompute the sound from scratch. Although not implemented yet in Nyquist, some header formats can store maximum amplitudes, and some soundfile player programs can rescale floating point files on the fly, allowing normalized soundfile playback without an extra normalization pass (but at a cost of twice the disk space of 16-bit samples). You can use Nyquist to rescale a floating point file and convert it to 16-bit samples for playback. @section(Frequency Modulation)@index(Frequency Modulation) The next example uses the Nyquist frequency modulation behavior @code(fmosc) to generate various sounds. The parameters to @code(fmosc) are: @begin(example) fmosc(@i(pitch) @i(modulator) @i(table) @i(phase)) @end(example) Note that pitch is the number of half-steps, e.g. @code(c4) has the value of 60 which is middle-C, and phase is in degrees. Only the first two parameters are required: @begin(example) @i[; make a short sine tone with no frequency modulation ;] play fmosc(c4, pwl(0.1)) @i[; make a longer sine tone -- note that the duration of ; the modulator determines the duration of the tone ;] play fmosc(c4, pwl(0.5)) @end(example) In the example above, @code(pwl) (for Piece-Wise Linear) is used to generate sounds that are zero for the durations of @code(0.1) and @code(0.5) seconds, respectively. In effect, we are using an FM oscillator with no modulation input, and the result is a sine tone. The duration of the modulation determines the duration of the generated tone (when the modulation signal ends, the oscillator stops). The next example uses a more interesting modulation function, a ramp from zero to C@-(4), expressed in hz. More explanation of @code(pwl) is in order. This operation constructs a piece-wise linear function sampled at the @code(*control-srate*). The first breakpoint is always at @code[(0, 0)], so the first two parameters give the time and value of the second breakpoint, the second two parameters give the time and value of the third breakpoint, and so on. The last breakpoint has a value of @code(0), so only the time of the last breakpoint is given. In this case, we want the ramp to end at C@-(4), so we cheat a bit by having the ramp return to zero ``almost'' instantaneously between times @code(0.5) and @code(0.501). The @code(pwl) behavior always expects an odd number of parameters. The resulting function is shifted and stretched linearly according to @code[*warp*] in the environment. Now, here is the example: @begin(example) @i[; make a frequency sweep of one octave; the piece-wise linear function ; sweeps from 0 to (step-to-hz c4) because, when added to the c4 ; fundamental, this will double the frequency and cause an octave sweep. ;] play fmosc(c4, pwl(0.5, step-to-hz(c4), 0.501)) @end(Example) The same idea can be applied to a non-sinusoidal carrier. Here, we assume that @code(*fm-voice*) is predefined (the next section shows how to define it): @begin(example) @i[; do the same thing with a non-sine table ;] play fmosc(cs2, pwl(0.5, step-to-hz(cs2), 0.501), *fm-voice*, 0.0) @end(example) The next example shows how a function can be used to make a special frequency modulation contour. In this case the contour generates a sweep from a starting pitch to a destination pitch: @begin(example) @i[; make a function to give a frequency sweep, starting ; after seconds, then sweeping from ; to in seconds and then ; holding at for seconds. ;] define function sweep(delay, pitch-1, sweep-time, pitch-2, hold-time) begin with interval = step-to-hz(pitch-2) - step-to-hz(pitch-1) return pwl(delay, 0.0, @i[; sweep from pitch 1 to pitch 2] delay + sweep-time, interval, @i[; hold until about 1 sample from the end] delay + sweep-time + hold-time - 0.0005, interval, @i[; quickly ramp to zero (pwl always does this,] @i[; so make it short)] delay + sweep-time + hold-time) end @i[; now try it out ;] play fmosc(cs2, sweep(0.1, cs2, 0.6, gs2, 0.5), *fm-voice*, 0.0) @end(example) FM can be used for vibrato as well as frequency sweeps. Here, we use the @code(lfo) function to generate vibrato. The @code(lfo) operation is similar to @code(osc), except it generates sounds at the @code(*control-srate*), and the parameter is hz rather than a pitch: @begin(example) play fmosc(cs2, 10.0 * lfo(6.0), *fm-voice*, 0.0) @end(Example) What kind of manual would this be without the obligatory FM sound? Here, a sinusoidal modulator (frequency C@-(4)) is multiplied by a slowly increasing ramp from zero to @code(1000.0). @begin(example) set modulator = pwl(1.0, 1000.0, 1.0005) * osc(c4) @i[; make the sound] play fmosc(c4, modulator) @end(example) For more simple examples of FM in Nyquist, see @index(warble)@index(FM synthesis)@index(demos, FM)@index(tutorial, FM) @code(demos/warble_tutorial.htm). Another interesting FM sound reminiscent of ``scratching'' can be found with a detailed explanation in @code(demos/scratch_tutorial.htm).@index(demos, scratch tutorial) @index(vinal scratch)@index(scratch sound). @section(Building a Wavetable) In Section @ref(waveform-sec), we saw how to synthesize a wavetable. A wavetable for @code(osc) also can be extracted from any sound. This is especially interesting if the sound is digitized from some external sound source and loaded using the @code(s-read) function. Recall that a table is a list consisting of a sound, the pitch of that sound, and T (meaning the sound is periodic). In the following, a sound is first read from the file @code(demo-snd.nh). Then, the @code(extract) function is used to extract the portion of the sound between 0.110204 and 0.13932 seconds. (These numbers might be obtained by first plotting the sound and estimating the beginning and end of a period, or by using some software to look for good zero crossings.) The result of @code(extract) becomes the first element of a list. The next element is the pitch (24.848422), and the last element is @code(T). The list is assigned to @code(*fm-voice*). @begin(example) if not(boundp(quote(a-snd))) then set a-snd = s-read("demo-snd.aiff") set *fm-voice* = list(extract(0.110204, 0.13932, cue(a-snd)), 24.848422, #T) @end(example) The file @i(demos/examples.sal) contains an extensive example of how to locate zero-crossings, extract a period, build a waveform, and generate a tone from it. (See @code(ex37) through @code(ex40) in the file.) @begin(comment) The @code(maketable) command is also useful and is documented on page @ref(maketable). If @code(sample) is the source sound, then the following will extract 0.01 seconds (starting at time 0.2s) of audio and convert it into a waveform named @code(mytable): @begin(example) (setf mytable (maketable (extract -abs 0.2 0.21 sample))) @end(example) Nyquist does not provide any pitch analysis or other help finding good splice points, so it is up to you to make sure the table you extract is a reasonable one. @end(comment) @section(Filter Examples) Nyquist provides a variety of filters. All of these filters take either real numbers or signals as parameters. If you pass a signal as a filter parameter, the filter coefficients are recomputed at the sample rate of the @i(control) signal. Since filter coefficients are generally expensive to compute, you may want to select filter control rates carefully. Use @code(control-srate-abs) (Section @ref(control-srate-abs-sec)) to specify the default control sample rate, or use @code(force-srate) (Section @ref(force-srate-sec)) to resample a signal before passing it to a filter. Before presenting examples, let's generate some unfiltered white noise: @begin(example) play noise() @end(example) Now low-pass filter the noise with a 1000Hz cutoff: @begin(example) play lp(noise(), 1000.0) @end(example) The high-pass filter is the inverse of the low-pass: @begin(example) play hp(noise(), 1000.0) @end(example) Here is a low-pass filter sweep from 100Hz to 2000Hz: @begin(example) play lp(noise(), pwl(0.0, 100.0, 1.0, 2000.0, 1.0)) @end(example) And a high-pass sweep from 50Hz to 4000Hz: @begin(example) play hp(noise(), pwl(0.0, 50.0, 1.0, 4000.0, 1.0)) @end(example) The band-pass filter takes a center frequency and a bandwidth parameter. This example has a 500Hz center frequency with a 20Hz bandwidth. The scale factor is necessary because, due to the resonant peak of the filter, the signal amplitude exceeds 1.0: @begin(example) play reson(10.0 * noise(), 500.0, 20.0, 1) @end(example) In the next example, the center frequency is swept from 100 to 1000Hz, using a constant 20Hz bandwidth: @begin(example) play reson(0.04 * noise(), pwl(0.0, 200.0, 1.0, 1000.0, 1.0), 20.0) @end(example) For another example with explanations, see @index(wind_tutorial.htm)@index(wind sound)@index(filter example) @index(demos, wind sound) @code(demos/wind_tutorial.htm). @section(DSP in Lisp) @index(DSP in Lisp)@index(Lisp DSP)In almost any signal processing system, the vast majority of computation takes place in the inner loops of DSP algorithms, and Nyquist is designed so that these time-consuming inner loops are in highly-optimized machine code rather than relatively slow interpreted lisp code. As a result, Nyquist typically spends 95% of its time in these inner loops; the overhead of using a Lisp interpreter is negligible. The drawback is that Nyquist must provide the DSP operations you need, or you are out of luck. When Nyquist is found lacking, you can either write a new primitive signal operation, or you can perform DSP in Lisp code. Neither option is recommended for inexperienced programmers. Instructions for extending Nyquist are given in Appendix @ref(extending-app). This section describes the process of writing a new signal processing function in Lisp. Before implementing a new DSP function, you should decide which approach is best. First, figure out how much of the new function can be implemented using existing Nyquist functions. For example, you might think that a tapped-delay line would require a new function, but in fact, it can be implemented by composing sound transformations to accomplish delays, scale factors for attenuation, and additions to combine the intermediate results. This can all be packaged into a new Lisp function, making it easy to use. If the function relies on built-in DSP primitives, it will execute very efficiently. Assuming that built-in functions cannot be used, try to define a new operation that will be both simple and general. Usually, it makes sense to implement only the kernel of what you need, combining it with existing functions to build a complete instrument or operation. For example, if you want to implement a physical model that requires a varying breath pressure with noise and vibrato, plan to use Nyquist functions to add a basic pressure envelope to noise and vibrato signals to come up with a composite pressure signal. Pass that signal into the physical model rather than synthesizing the envelope, noise, and vibrato within the model. This not only simplifies the model, but gives you the flexibility to use all of Nyquist's operations to synthesize a suitable breath pressure signal. Having designed the new ``kernel'' DSP operation that must be implemented, decide whether to use C or Lisp. (At present, SAL is not a good option because it has no support for object-oriented programming.) To use C, you must have a C compiler, the full source code for Nyquist, and you must learn about extending Nyquist by reading Appendix @ref(extending-app). This is the more complex approach, but the result will be very efficient. A C implementation will deal properly with sounds that are not time-aligned or matched in sample rates. To use Lisp, you must learn something about the XLISP object system, and the result will be about 50 times slower than C. Also, it is more difficult to deal with time alignment and differences in sample rates. The remainder of this section gives an example of a Lisp version of @code(snd-prod) to illustrate how to write DSP functions for Nyquist in Lisp. The @code(snd-prod) function is the low-level multiply routine. It has two sound parameters and returns a sound which is the product of the two. To keep things simple, we will assume that two sounds to be multiplied have a matched sample rate and matching start times. The DSP algorithm for each output sample is simply to fetch a sample from each sound, multiply them, and return the product. To implement @code(snd-prod) in Lisp, three components are required: @begin(enumerate) An object is used to store the two parameter sounds. This object will be called upon to yield samples of the result sound; Within the object, the @code(snd-fetch) routine is used to fetch samples from the two input sounds as needed; The result must be of type @code(SOUND), so @code(snd-fromobject) is used to create the result sound. @end(enumerate) The combined solution will work as follows: The result is a value of type @code(sound) that retains a reference to the object. When Nyquist needs samples from the sound, it invokes the sound's ``fetch'' function, which in turn sends an XLISP message to the object. The object will use @code(snd-fetch) to get a sample from each stored sound, multiply the samples, and return a result. Thus the goal is to design an XLISP object that, in response to a @code(:next) message will return a proper sequence of samples. When the sound reaches the termination time, simply return @code(NIL). The XLISP manual (see Appendix @ref(XLISP-app) describes the object system, but in a very terse style, so this example will include some explanation of how the object system is used. First, we need to define a class for the objects that will compute sound products. Every class is a subclass of class @code(class), and you create a subclass by sending @code(:new) to a class. @begin(example) (setf product-class (send class :new '(s1 s2))) @end(example) The parameter @code['(s1 s2)] says that the new class will have two instance variables, @code(s1) and @code(s2). In other words, every object which is an instance of class @code(product-class) will have its own copy of these two variables. Next, we will define the @code(:next) method for @code(product-class): @begin(example) (send product-class :answer :next '() '((let ((f1 (snd-fetch s1)) (f2 (snd-fetch s2))) (cond ((and f1 f2) (* f1 f2)) (t nil))))) @end(example) The @code(:answer) message is used to insert a new method into our new @code(product-class). The method is described in three parts: the name (@code(:next)), a parameter list (empty in this case), and a list of expressions to be evaluated. In this case, we fetch samples from @code(s1) and @code(s2). If both are numbers, we return their product. If either is @code(NIL), we terminate the sound by returning @code(nil). The @code(:next) method assumes that @code(s1) and @code(s2) hold the sounds to be multiplied. These must be installed when the object is created. Objects are created by sending @code(:new) to a class. A new object is created, and any parameters passed to @code(:new) are then sent in a @code(:isnew) message to the new object. Here is the @code(:isnew) definition for @code(product-class): @begin(example) (send product-class :answer :isnew '(p1 p2) '((setf s1 (snd-copy p1)) (setf s2 (snd-copy p2)))) @end(example) Take careful note of the use of @code(snd-copy) in this initialization. The sounds @code(s1) and @code(s2) are modified when accessed by @code(snd-fetch) in the @code(:next) method defined above, but this destroys the illusion that sounds are immutable values. The solution is to copy the sounds before accessing them; the original sounds are therefore unchanged. (This copy also takes place implicitly in most Nyquist sound functions.) To make this code safer for general use, we should add checks that @code(s1) and @code(s2) are sounds with identical starting times and sample rates; otherwise, an incorrect result might be computed. Now we are ready to write @code(snd-product), an approximate replacement for @code(snd-prod): @begin(example) (defun snd-product (s1 s2) (let (obj) (setf obj (send product-class :new s1 s2)) (snd-fromobject (snd-t0 s1) (snd-srate s1) obj))) @end(example) This code first creates @code(obj), an instance of @code(product-class), to hold @code(s1) and @code(s2). Then, it uses @code(obj) to create a sound using @code(snd-fromobject). This sound is returned from @code(snd-product). Note that in @code(snd-fromobject), you must also specify the starting time and sample rate as the first two parameters. These are copied from @code(s1), again assuming that @code(s1) and @code(s2) have matching starting times and sample rates. Note that in more elaborate DSP algorithms we could expect the object to have a number of instance variables to hold things such as previous samples, waveform tables, and other parameters. @chapter(SAL) @label(SAL-chap) Nyquist supports two languages: XLISP and SAL. In some sense, XLISP and SAL are the same language, but with differing syntax. This chapter describes SAL: how it works, SAL syntax and semantics, and the relationship between SAL and XLISP, and differences between Nyquist SAL and Common Music SAL. Nyquist SAL is based on Rick Taube's SAL language, which is part of Common Music. SAL offers the power of Lisp but features a simple, Algol-like syntax. SAL is implemented in Lisp: Lisp code translates SAL into a Lisp program and uses the underlying Lisp engine to evaluate the program. Aside from the translation time, which is quite fast, SAL programs execute at about the same speed as the corresponding Lisp program. (Nyquist SAL programs run just slightly slower than XLISP because of some runtime debugging support automatically added to user programs by the SAL compiler.) From the user's perspective, these implementation details are hidden. You can enter SAL mode from XLISP by typing @code[(SAL)] to the XLISP prompt. The SAL input prompt (@code(SAL> )) will be displayed. From that point on, you simply type SAL commands, and they will be executed. By setting a preference in the jNyqIDE program, SAL mode will be entered automatically. It is possible to encounter errors that will take you from the SAL interpreter to an XLISP prompt. In general, the way to get back to SAL is by typing @code[(top)] to get back to the top level XLISP interpreter and reset the Nyquist environment. Then type @code[(sal)] to restart the SAL interpreter. @section(SAL Syntax and Semantics) @index(SAL) The most unusual feature of SAL syntax is that identifiers are Lisp-like, including names such as ``play-file'' and even ``*warp*.'' In SAL, most operators must be separated from identifiers by white space. For example, @code(play-file) is one identifier, but @code(play - file) is an expression for ``play minus file,'' where @code(play) and @code(file) are two separate identifiers. Fortunately, no spaces are needed around commas and parentheses. In SAL, whitespace (any sequence of space, newline, or tab characters) is sometimes necessary to separate lexical tokens, but otherwise, spaces and indentation are ignored. To make SAL readable, it is @i(strongly) advised that you indent SAL programs as in the examples here. The jNyqIDE program is purposely insistent about SAL indentation, so if you use it to edit SAL programs, your indentation should be both beautiful and consistent. As in Lisp (but very unlike C or Java), comments @index(comments) are indicated by semicolons. Any text from an unquoted semicolon to the end of the line is ignored. @begin(example) @i(; this is a comment) @i(; comments are ignored by the compiler) print "Hello World" @i(; this is a SAL statement) @end(example) As in Lisp, identifiers are translated to upper-case, making SAL case-insensitive@index(case-insensitive). For example, the function name @code(autonorm) can be typed in lower case or as @code(AUTONORM), @code(AutoNorm), or even @code(AuToNoRm). All forms denote the same function. The recommended approach is to write programs in all lower case. SAL is organized around statements, most of which contain expressions. We will begin with expressions and then look at statements. @subsection(Expressions) @index(sal expressions)@index(expressions, sal) @paragraph(Simple Expressions) As in XLISP, simple expressions include: @begin(itemize) integers (FIXNUM's), such as @code(1215), floats (FLONUM's) such as @code(12.15), strings (STRING's) such as @code("Magna Carta"), and symbols (SYMBOL's) such as @code(magna-carta). A symbol with a leading colon (@code(:)) evaluates to itself as in Lisp. Otherwise, a symbol denotes either a local variable, a formal parameter, or a global variable. As in Lisp, variables do not have data types or type declarations. The type of a variable is determined at runtime by its value. @end(itemize) Additional simple expressions in SAL are: @begin(itemize) lists such as @code[{c 60 e 64}]. Note that there are no commas to separate list elements, and symbols in lists are not evaluated as variables but stand for themselves. Lists may contain numbers, booleans, symbols, strings, and other lists. Booleans: SAL interprets @code(#t)@index(#t) as true and @code(#f)@index(#f) as false. (As far as the SAL compiler is concerned, @code(t) and @code(nil) are just variables. Since these are the Lisp versions of true and false, they are interchangeable with @code(#t) and @code(#f), respectively.) @end(itemize) A curious property of Lisp and Sal is that @i(false) and the empty list are the same value. Since SAL is based on Lisp, @code(#f) and @code({}) (the empty list)@index(empty list) are equal. @paragraph(Operators) Expressions can be formed with unary and binary operators using infix notation. The operators are: @begin(itemize) @index(+)@code(+) - addition, including sounds @index(-)@code(-) - subtraction, including sounds @index(*)@code(*) - multiplication, including sounds @index(/)@code(/) - division (due to divide-by-zero problems, does not operate on sounds) @index(%)@code(%) - modulus (remainder after division) @index(^)@code(^) - exponentiation @index(=)@code(=) - equal (using Lisp @code(eql)) @index(!=)@code(!=) - not equal @index(>)@code(>) - greater than @index(<)@code(<) - less than @index(>=)@code(>=) - greater than or equal @index(<=)@code(<=) - less than or equal @index(~=)@code(~=) - general equality (using Lisp @code(equal)) @index(&)@code(&) - logical and @index(|)@code(|) - logical or @index(!)@code(!) - logical not (unary) @index(@@)@index(time shift, sal)@index(at, sal)@code(@@) - time shift @index(@@@@)@index(absolute time shift, sal)@index(at-abs, sal)@code(@@@@) - time shift to absolute time @index(~)@index(stretch, sal)@code(~) - time stretch @index(~~)@index(absolute stretch, sal)@code(~~) - time stretch to absolute stretch factor @end(itemize) Again, remember that operators @i(must) be delimited from their operands using spaces or parentheses. Operator precedence is based on the following levels of precedence: @begin(example) @@ @@@@ ~ ~~ ^ / * % - + ~= <= >= > ~= = ! & | @end(example) @paragraph(Function Calls) @index(function calls, sal) A function call is a function name followed by zero or more comma-delimited argument expressions enclosed within parentheses: @begin(example) list() piano-note(2.0, c4 + interval, 100) @end(example) Some functions use named parameters, in which case the name of the argument with a colon precedes the argument expression. @begin(example) s-save(my-snd(), ny:all, "tmp.wav", play: #t, bits: 16) @end(example) @paragraph(Array Notation) @index(array notation, sal) An array reference is a variable identifier followed by an index expression in square brackets, e.g.: @begin(example) x[23] + y[i] @end(example) @paragraph(Conditional Values) @index(conditional expression, sal) @index(#?, sal) The special operator @code(#?) evaluates the first argument expression. If the result is @i(true), the second expression is evaluated and its value is returned. If @i(false), the third expression is evaluated and returned (or @i(false) is returned if there is no third expression): @begin(example) #?(random(2) = 0, unison, major-third) #?(pitch >= c4, pitch - c4) ; returns false if pitch < c4 @end(example) @subsection(SAL Statements) @index(statements, sal) SAL compiles and evaluates @i(statements) one at a time. You can type statements at the SAL prompt or load a file containing SAL statements. SAL statements are described below. The syntax is indicated at the beginning of each statement type description: @code(this font) indicates literal terms such as keywords, @i(the italic font) indicates a place-holder for some other statement or expression. Bracket [like this] indicate optional (zero or one) syntax elements, while braces with a plus {like this}+ indicate one or more occurrences of a syntax element. Braces with a star {like this}* indicate zero or more occurrences of a syntax element: { @i(non-terminal) }* is equivalent to [ {@i(non-terminal)}+ ]. @paragraph(begin and end) @index(begin)@index(end) @code(begin) [@i(with-stmt)] {@i(statement)}+ @code(end) A @code(begin)-@code(end) statement consists of a sequence of statements surrounded by the @code(begin) and @code(end) keywords. This form is often used for function definitions and after @code(then) or @code(else) where the syntax demands a single statement but you want to perform more than one action. Variables may be declared using an optional @code(with) statement immediately after @code(begin). For example: @begin(example) begin with db = 12.0, linear = db-to-linear(db) print db, "dB represents a factor of", linear set scale-factor = linear end @end(example) @paragraph(chdir) @index(chdir, sal) @code(chdir) @i(expression) The @code(chdir) statement changes the working directory. This statement is provided for compatibility with Common Music SAL, but it really should be avoided if you use jNyqIDE. The @i(expression) following the @code(chdir) keyword should evaluate to a string that is a directory path name. Note that literal strings themselves are valid expressions. @begin(example) chdir "/Users/rbd/tmp" @end(example) @paragraph(define variable) @index(global variables, sal)@index(define variable) [@code(define)] @code(variable) @i(name) [= @i(expression)] {, @i(name) [= @i(expression)]}* Global variables can be declared and initialized. A list of variable names, each with an optional initialization follows the @code(define variable) keywords. (Since @code(variable) is a keyword, @code(define) is redundant and optional in Nyquist SAL, but required in Common Music SAL.) If the initialization part is omitted, the variable is initialized to false. Global variables do not really need to be declared: just using the name implicitly creates the corresponding variable. However, it is an error to use a global variable that has not been initialized; @code(define variable) is a good way to introduce a variable (or constant) with an initial value into your program. @begin(example) define variable transposition = 2, print-debugging-info, @i(; initially false) output-file-name = "salmon.wav" @end(example) @paragraph(define function) @index(function, sal)@index(define function) [@code(define)] @code(function) @i(name) @code[(] [@i(parameter)], {, @i(parameter)}* @code[)] @i(statement) Before a function be called from an expression (as described above), it must be defined. A function definition gives the function @i(name), a list of @i(parameters), and a @i(statement). When a function is called, the actual parameter expressions are evaluated from left to right and the formal parameters of the function definition are set to these values. Then, @i(statement) is evaluated. The formal parameters may be positional parameters that are matched with actual parameters by position from left to right. Syntactically, these are symbols and these symbols are essentially local variables that exist only until @i(statement) completes or a @code(return) statement causes the function evaluation to end. As in Lisp, parameters are passed by value, so assigning a new value to a formal parameter has no effect on the actual value. However, lists and arrays are not copied, so internal changes to a list or array produce observable side effects. Alternatively, formal parameters may be keyword parameters. Here the @i(parameter) is actually a pair: a keyword parameter, which is a symbol followed by a colon, and a default value, given by any expression. Within the body of the function, the keyword parameter is named by a symbol whose name matches the keyword parameter except there is no final colon. @begin(example) define function foo(x: 1, y: bar(2, 3)) display "foo", x, y exec foo(x: 6, y: 7) @end(example) In this example, @code(x) is bound to the value 6 and @code(y) is bound to the value 7, so the example prints ``@code(foo : X = 6, Y = 7)''. Note that while the keyword parameters are @code(x:) and @code(y:), the corresponding variable names in the function body are @code(x) and @code(y), respectively. The @i(parameters) are meaningful only within the lexical (static) scope of @i(statement). They are not accessible from within other functions even if they are called by this function. Use a @code(begin)-@code(end) statement if the body of the function should contain more than one statement or you need to define local variables. Use a @code(return) statement to return a value from the function. If @i(statement) completes without a @code(return), the value false is returned. @paragraph(display) @index(display statement, sal) @code(display) @i(string) {, @i(expression)}* The @code(display) statement is handy for debugging. At present, it is only implemented in Nyquist SAL. When executed, @code(display) prints the @i(string) followed by a colon and then, for each @i(expression), the expression and its value are printed, after the last expression, a newline is printed. For example, @begin(example) display "In function foo", bar, baz @end(example) prints @begin(example) In function foo : bar = 23, baz = 5.3 @end(example) SAL may print the expressions using Lisp syntax, e.g. if the expression is ``bar + baz,'' do not be surprised if the output is ``@code[(sum bar baz) = 28.3].'' @paragraph(exec) @index(exec statement, sal) @code(exec) @i(expression) Unlike most other programming languages, you cannot simply type an expression as a statement. If you want to evaluate an expression, e.g. call a function, you must use an @code(exec) statement. The statement simply evaluates the @i(expression). For example, @begin(example) exec set-sound-srate(22050.0) @i(; change default sample rate) @end(example) @paragraph(if) @index(if statement, sal) @code(if) @i(test-expr) @code(then) @i(true-stmt) [@code(else) @i(false-stmt)] An @code(if) statement evaluates the expression @i(test-expr). If it is true, it evaluates the statement @i(true-stmt). If false, the statement @i(false-stmt) is evaluated. Use a @code(begin)-@code(end) statement to evaluate more than one statement in then @code(then) or @code(else) parts. @begin(example) if x < 0 then x = -x @i(; x gets its absoute value) if x > upper-bound then begin print "x too big, setting to", upper-bound x = upper-bound end else if x < lower-bound then begin print "x too small, setting to", lower-bound x = lower-bound end @end(example) Notice in this example that the @code(else) part is another @code(if) statement. An @code(if) may also be the @code(then) part of another @code(if), so there could be two possible @code(if)'s with which to associate an @code(else). An @code(else) clause always associates with the closest previous @code(if) that does not already have an @code(else) clause. @paragraph(when) @code(when) @i(test) @i(statement) The @code(when) statement is similar to @code(if), but there is no @code(else) clause. @begin(example) when *debug-flag* print "you are here" @end(example) @paragraph(unless) @code(unless) @i(test) @i(statement) The @code(unless) statement is similar to @code(when) (and @code(if)) but the @i(statement) is executed when the @i(test) expression is @i(false). @begin(example) unless count = 0 set average = sum / count @end(example) @paragraph(load) @index(load statement, sal) @code(load) @i(expression) The @code(load) command loads a file named by @i(expression), which must evauate to a string path name for the file. To load a file, SAL interprets each statement in the file, stopping when the end of the file or an error is encountered. If the file ends in @code(.lsp), the file is assumed to contain Lisp expressions, which are evaluated by the XLISP interpreter. In general, SAL files should end with the extension @code(.sal). @paragraph(loop) @index(loop statement, sal) @code(loop) [@i(with-stmt)] {@i(stepping)}* {@i(stopping)* @i(action)+ [@i(finally)] @code(end) The @code(loop) statement is by far the most complex statement in SAL, but it offers great flexibility for just about any kind of iteration. The basic function of a loop is to repeatedly evaluate a sequence of @i(action)'s which are statements. Before the loop begins, local variables may be declared in @i(with-stmt), a @code(with) statement. The @i(stepping) clauses do several things. They introduce and initialize additional local variables similar to the @i(with-stmt). However, these local variables are updated to new values after the @i(action)'s. In addition, some @i(stepping) clauses have associated stopping conditions, which are tested on each iteration @i(before) evaluating the @i(action)'s. There are also @i(stopping) clauses that provide additional tests to stop the iteration. These are also evaluated and tested on each iteration before evaluating the @i(action)'s. When some @i(stepping) or @i(stopping) condition causes the iteration to stop, the @i(finally) clause is evaluated (if present). Local variables and their values can still be accessed in the @i(finally) clause. After the @i(finally) clause, the @code(loop) statement completes. The @i(stepping) clauses are the following: @begin(description) @code(repeat) @i(expression)@\Sets the number of iterations to the value of @i(expression), which should be an integer (FIXNUM). @code(for) @i(var) = @i(expression) [ @code(then) @i(expr2) ]@\Introduces a new local variable named @i(var) and initializes it to @i(expression). Before each subsequent iteration, @i(var) is set to the value of @i(expr2). If the @code(then) part is omitted, @i(expression) is re-evaluated and assigned to @i(var) on each subsequent iteration. Note that this differs from a @i(with-stmt) where expressions are evaluated and variables are only assigned their values once. @code(for) @i(var) @code(in) @i(expression)@\Evaluates @i(expression) to obtain a list and creates a new local variable initialized to the first element of the list. After each iteration, @i(var) is assigned the next element of the list. Iteration stops when @i(var) has assumed all values from the list. If the list is initially empty, the loop @i(action)'s are not evaluated (there are zero iterations). @code(for) @i(var) [@code(from) @i(from-expr)] [[@code(to) | @code(below) | @code(downto) | @code(above)] @i(to-expr)] [@code(by) @i(step-expr)]@\Introduces a new local variable named @i(var) and intialized to the value of the expression @i(from-expr) (with a default value of 0). After each iteration of the loop, @i(var) is incremented by the value of @i(step-expr) (with a default value of 1). The iteration ends when @i(var) is greater than the value of @i(to-expr) if there is a @code(to) clause, greater than or equal to the value of @i(to-expr) if there is a @code(below) clause, less than the value of @i(to-expr) if there is a @code(downto) clause, or less than or equal to the value of @i(to-expr) if there is a @code(above) clause. (In the cases of @i(downto) and @i(above), the default increment value is -1. If there is no @code(to), @code(below), @code(downto), @code(above), or @code(below) clause, no interation stop test is created for this stepping clause. @end(description) The @i(stopping) clauses are the following: @begin(description) @code(while) @i(expression)@\The iterations are stopped when @i(expression) evaluates to @i(false). Anything not false is considered to mean true. @code(until) @i(expression)@\The iterations are stopped when @i(expression) evaluates to @i(true). @end(description) The @i(finally) clause is defined as follows: @index(finally clause, sal) @begin(description) @code(finally) @i(statement)@\The @i(statement) is evaluated when one of the @i(stepping) or @i(stopping) clauses ends the loop. As always, @i(statement) may be a @code(begin)-@code(end) statement. If an @i(action) evaluates a @code(return) statement, the @code(finally) statement is not executed. @end(description) @index(loop examples, sal)Loops often fall into common patterns, such as iteratiing a fixed number of times, performing an operation on some range of integers, collecting results in a list, and linearly searching for a solution. These forms are illustrated in the examples below. @begin(example) @i(; iterate 10 times) loop repeat 10 print random(100) end @i(; print even numbers from 10 to 20 ; note that 20 is printed. On the next iteration, ; i = 22, so i >= 22, so the loop exits.) loop for i from 10 to 22 by 2 print i end @i(; collect even numbers in a list) loop with lis for i = 0 to 10 by 2 set lis @@= i @i(; push integers on front of list,) @i(; which is much faster than append,) @i(; but list is built in reverse) finally result = reverse(lis) end @i(; now, the variable result has a list of evens) @i(; find the first even number in a list) result = #f @i(; #f means "false") loop for elem in lis until evenp(elem) finally result = elem end @i[; result has first even value in lis (or it is #f)] @end(example) @paragraph(print) @index(print statement, sal) @code(print) @i(expr) {, @i(expr)}* The @code(print) statement prints the values separated by spaces and followed by a newline. [Note that in the original SAL, the newline is printed @i(before) the values, not after.] @begin(example) print "The value of x is", x @end(example) @paragraph(return) @index(return statement, sal) @code(return) @i(expression) The @code(return) statement can only be used inside a function. It evaluates @i(expression) and then the function returns the value of the expression to its caller. @paragraph(set) @index(set statement, sal) @code(set) @i(var) @i(op) @i(expression) {, @i(var) @i(op) @i(expression)}* The @code(set) statement changes the value of a variable @i(var) according to the operator @i(op) and the value of the @i(expression). The operators are: @begin(description) @code(=)@\The value of @i(expression) is assigned to @i(var). @index(+=)@code(+=)@\The value of @i(expression) is added to @i(var). @index(*=)@code(*=)@\The value of @i(var) is multiplied by the value of the expression. @index(&=)@code(&=)@\The value of @i(expression) is inserted as the last element of the list referenced by @i(var). If @i(var) is the empty list (denoted by @code(#f)), then @i(var) is assigned a newly constructed list of one element, the value of @i(expression). @index(^=)@code(^=)@\The value of @i(expression), a list, is appended to the list referenced by @i(var). If @i(var) is the empty list (denoted by @code(#f)), then @i(var) is assigned the (list) value of @i(expression). @index(@@=)@code(@@=)@\Pushes the value of @i(expression) onto the front of the list referenced by @i(var). If @i(var) is empty (denoted by @code(#f)), then @i(var) is assigned a newly constructed list of one element, the value of @i(expression). @index(<=)@code(<=)@\Sets the new value of @i(var) to the minimum of the old value of @i(var) and the value of @i(expression). @index(>=)@code(>=)@\Sets the new value of @i(var) to the maximum of the old value of @i(var) and the value of @i(expression). @end(description) @begin(example) @i(; example from Rick Taube's SAL description) loop with a, b = 0, c = 1, d = {}, e = {}, f = -1, g = 0 for i below 5 set a = i, b += 1, c *= 2, d &= i, e @@= i, f <= i, g >= i finally display "results", a, b, c, d, e, f, g end @end(example) @paragraph(with) @index(with statement, sal) @code(with) @i(var) [= @i(expression)] {, @i(var) [= @i(expression)]}* The @code(with) statement declares and initializes local variables. It can appear only after @code(begin) or @code(loop). If the @i(expression) is omitted, the initial value is @i(false). The variables are visible only inside the @code(begin)-@code(end) or @code(loop) statement where the @code(with) statement appears. Even in @code(loop)'s the variables are intialized only when the loop is entered, not on each iteration. @paragraph(exit) @index(exit statement, sal) @code(exit) [@code(nyquist)] The @code(exit) statement is unique to Nyquist SAL. It returns from SAL mode to the XLISP interpreter. (Return to SAL mode by typing ``@code[(sal)]''). If @code(nyquist) is included in the statement, then the entire Nyquist process will exit. @section(Interoperability of SAL and XLISP) @index(sal and lisp)@index(interoperability, sal and lisp) @label(sal-vs-lisp-section) When SAL evaluatas command or loads files, it translates SAL into XLISP. You can think of SAL as a program that translates everything you write into XLISP and entering it for you. Thus, when you define a SAL function, the function actually exists as an XLISP function (created using Lisp's @code(defun) special form). When you set or evaluate global variables in SAL, these are exactly the same Lisp global variables. Thus, XLISP functions can call SAL functions and vice-versa. At run time, everything is Lisp. @subsection(Function Calls) In general, there is a very simple translation from SAL to Lisp syntax and back. A function call is SAL, for example, @begin(example) osc(g4, 2.0) @end(example) is translated to Lisp by moving the open parenthesis in front of the function name and removing the commas: @begin(example) (osc g4 2.0) @end(example) Similarly, if you want to translate a Lisp function call to SAL, just reverse the translation. @subsection(Symbols and Functions) SAL translates keywords with trailing colons (such as @code(foo:)) into Lisp keywords with leading colons (such as @code(:foo)), but SAL keywords are not treated as expressions as they are in Lisp. You cannot write @code[open("myfile.txt", direction: output:)] because SAL expects an expression after direction. A special form @code(keyword) is defined to generate a Lisp keyword as an expression. The argument is the keyword @i(without) a colon, e.g. @code[open("myfile.txt", direction: keyword(output))]. Alternatively, you can write the Lisp-style keyword with the leading colon, e.g. @code[open("myfile.txt", direction: :output)]. In Nyquist SAL, the hash character (#), can be used as a prefix to a Lisp function name. For example, the following command is not legal because @code(print) is a SAL command name, not a legal function name: @code[set v = append(print(a), print(b))]. (Here the intent is to print arguments to append). However, you can use the hash character to access the Lisp @code(print) function: @code[set v = append(#print(a), #print(b))]. @subsection(Playing Tricks On the SAL Compiler) In many cases, the close coupling between SAL and XLISP gives SAL unexpected expressive power. A good example is @code(seqrep). This is a special looping construct in Nyquist, implemented as a macro in XLISP. In Lisp, you would write something like: @begin(example) (seqrep (i 10) (pluck c4)) @end(example) One might expect SAL would have to define a special @code(seqrep) statement to express this, but since statements do not return values, this approach would be problematic. The solution (which is already fully implemented in Nyquist) is to define a new macro @code(sal-seqrep) that is equivalent to @code(seqrep) except that it is called as follows: @begin(example) (sal-seqrep i 10 (pluck c4)) @end(example) The SAL compiler automatically translates the identifier @code(seqrep) to @code(sal-seqrep). Now, in SAL, you can just write @begin(example) seqrep(i, 10, pluck(c4)) @end(example) which is translated in a pretty much semantics-unaware fashion to @begin(example) (sal-seqrep i 10 (pluck c4)) @end(example) and viola!, we have Nyquist control constructs in SAL even though SAL is completely unaware that @code(seqrep) is actually a special form. @chapter(Nyquist Functions) @label(lisp-chap) This chapter provides a language reference for Nyquist. Operations are categorized by functionality and abstraction level. Nyquist is implemented in two important levels: the ``high level'' supports behavioral abstraction, which means that operations like @code(stretch) and @code(at) can be applied. These functions are the ones that typical users are expected to use, and most of these functions are written in XLISP. The ``low-level'' primitives directly operate on sounds, but know nothing of environmental variables (such as @code(*warp*), etc.). The names of most of these low-level functions start with ``@code(snd-)''. In general, programmers should avoid any function with the ``@code(snd-)'' prefix. Instead, use the ``high-level'' functions, which know about the environment and react appropriately. The names of high-level functions do not have prefixes like the low-level functions. There are certain low-level operations that apply directly to sounds (as opposed to behaviors) and are relatively ``safe'' for ordinary use. These are marked as such. Nyquist uses both linear frequency and equal-temperament pitch numbers to specify repetition rates. Frequency is always specified in either cycles per second (hz), or pitch numbers, also referred to as ``steps,'' as in steps of the chromatic scale. Steps are floating point numbers such that 60 = Middle C, 61 = C#, 61.23 is C# plus 23 cents, etc. The mapping from pitch number to frequency is the standard exponential conversion, and fractional pitch numbers are allowed: @pragma(startscribe) @math[frequency = 440 @mult 2@+{(pitch - 69)/12}]. @pragma(endscribe) @html[@center{frequency = 440 * 2^((pitch - 69)/12)}] There are many predefined pitch names. By default these are tuned in equal temperament, with A4 = 440Hz, but these may be changed. (See Section @ref(constants-sec)). @section(Sounds)@index(Sounds) A sound is a primitive data type in Nyquist. Sounds can be created, passed as parameters, garbage collected, printed, and set to variables just like strings, atoms, numbers, and other data types. @subsection(What is a Sound?) Sounds have 5 components: @begin(itemize) @code(srate@index(srate)) @itemsep the sample rate of the sound. @code(samples@index(samples)) @itemsep the samples. @code(signal-start@index(signal-start)) @itemsep the time of the first sample. @code(signal-stop@index(signal-stop)) @itemsep the time of one past the last sample. @code(logical-stop@index(logical-stop)) @itemsep the time at which the sound logically ends, e.g. a sound may end at the beginning of a decay. This value defaults to @code(signal-stop), but may be set to any value. @end(itemize) It may seem that there should be @code(logical-start) to indicate the logical or perceptual beginning of a sound as well as a @code(logical-stop) to indicate the logical ending of a sound. In practice, only @code(logical-stop) is needed; this attribute tells when the next sound should begin to form a sequence of sounds. In this respect, Nyquist sounds are asymmetric: it is possible to compute sequences forward in time by aligning the logical start of each sound with the @code(logical-stop) of the previous one, but one cannot compute ``backwards'', aligning the logical end of each sound with the logical start of its successor. The root of this asymmetry is the fact that when we invoke a behavior, we say when to start, and the result of the behavior tells us its logical duration. There is no way to invoke a behavior with a direct specification of when to stop@foot(Most behaviors will stop at time 1, warped according to @code(*warp*) to some real time, but this is by convention and is not a direct specification.). @p(Note:) there is no way to enforce the intended ``perceptual'' interpretation of @code(logical-stop). As far as Nyquist is concerned, these are just numbers to guide the alignment of sounds within various control constructs. @subsection(Multichannel Sounds) @index(Multichannel Sounds) Multichannel sounds are represented by Lisp arrays of sounds. To create an array of sounds the XLISP @code(vector) function is useful. Most low-level Nyquist functions (the ones starting with @code(snd-)) do not operate on multichannel sounds. Most high-level functions do operate on multichannel sounds. @subsection(Accessing and Creating Sound) @label(flatten-sec) @label(snd-srate-sec) Several functions display information concerning a sound and can be used to query the components of a sound. There are functions that access samples in a sound and functions that construct sounds from samples. @begin(fndefs) @codef[sref(@pragma(defn)@index(sref)@indexSecondary(primary="sound", secondary="accessing point")@i(sound), @i(time))]@\Accesses @i(sound) at the point @i(time), which is a local time. If @i(time) does not correspond to a sample time, then the nearest samples are linearly interpolated to form the result. To access a particular sample, either convert the sound to an array (see @code(snd-samples) below), or use @code(snd-srate) and @code(snd-t0) (see below) to find the sample rate and starting time, and compute a time (@i(t)) from the sample number (@i(n)): @pragma(startscribe) @begin(math) t = (n / srate) + t0 @end(math) @pragma(endscribe) @html[
    t = (n / srate) + t0
    ] Thus, the lisp code to access the n@+(th) sample of a sound would look like: @begin(code) (sref sound (global-to-local (+ (/ n (snd-srate sound)) (snd-t0 sound)))) @end(code) Here is why @code(sref) interprets its time argument as a local time: @begin(example) > (sref (ramp 1) 0.5) @i(; evaluate a ramp at time 0.5) 0.5 > (at 2.0 (sref (ramp 1) 0.5)) @i(; ramp is shifted to start at 2.0) @i(; the time, 0.5, is shifted to 2.5) 0.5 @end(example) If you were to use @code(snd-sref), which treats time as global, instead of @code(sref), which treats time as local, then the first example above would return the same answer (0.5), but the second example would return 0. Why? Because the @code[(ramp 1)] behavior would be shifted to start at time 2.0, but the resulting sound would be evaluated at global time 0.5. By definition, sounds have a value of zero before their start time. @codef[sref-inverse(@pragma(defn)@index(sref-inverse)@i(sound), @i(value))]@\Search @i(sound) for the first point at which it achieves @i(value) and return the corresponding (linearly interpolated) time. If no inverse exists, an error is raised. This function is used by Nyquist in the implementation of time warping. @label(snd-from-array-sec) @codef[snd-from-array(@IndexSecondary(primary="sound", secondary = "creating from array")@pragma(defn)@index(snd-from-array)@i(t0), @i(sr), @i(array))]@\Converts a lisp array of @code(FLONUM)s into a sound with starting time @i(t0) and sample rate @i(sr). Safe for ordinary use. Be aware that arrays of floating-point samples use 14 bytes per sample, and an additional 4 bytes per sample are allocated by this function to create a sound type. @codef[snd-fromarraystream(@pragma(defn)@index(snd-fromarraystream)@i(t0), @i(sr), @i(object))]@\Creates a sound for which samples come from @i(object). The starting time is @i(t0) (a @code(FLONUM)), and the sample rate is @i(sr). The @i(object) is an XLISP object (see Section @ref(objects-sec) for information on objects.) A sound is returned. When the sound needs samples, they are generated by sending the message @code(:next) to @i(object). If @i(object) returns @code(NIL), the sound terminates. Otherwise, @i(object) must return an array of @code(FLONUM)s. The values in these arrays are concatenated to form the samples of the resulting sound. There is no provision for @i(object) to specify the logical stop time of the sound, so the logical stop time is the termination time. @codef[snd-fromobject(@pragma(defn)@index(snd-fromobject)@index(sound from Lisp data)@i(t0), @i(sr), @i(object))]@\Creates a sound for which samples come from @i(object). The starting time is @i(t0) (a @code(FLONUM)), and the sample rate is @i(sr). The @i(object) is an XLISP object (see Section @ref(objects-sec) for information on objects. A sound is returned. When the sound needs samples, they are generated by sending the message @code(:next) to @i(object). If @i(object) returns @code(NIL), the sound terminates. Otherwise, @i(object) must return a @code(FLONUM). There is no provision for @i(object) to specify the logical stop time of the sound, so the logical stop time is the termination time. @codef[snd-extent(@pragma(defn)@index(snd-extent)@i(sound), @i(maxsamples))]@\Returns a list of two numbers: the starting time of @i(sound) and the terminate time of @i(sound). Finding the terminate time requires that samples be computed. Like most Nyquist functions, this is non-destructive, so memory will be allocated to preserve the sound samples. If the sound is very long or infinite, this may exhaust all memory, so the @i(maxsamples) parameter specifies a limit on how many samples to compute. If this limit is reached, the terminate time will be (incorrectly) based on the sound having @i(maxsamples) samples. This function is safe for ordinary use. @codef[snd-fetch(@index(access samples)@index(samples, reading)@pragma(defn)@index(snd-fetch)@index(read samples)@i(sound))]@\Reads samples sequentially from @i(sound). This returns a @code(FLONUM) after each call, or @code(NIL) when @i(sound) terminates. @p(Note:) @code(snd-fetch) modifies @i(sound); it is strongly recommended to copy @i(sound) using @code(snd-copy) and access only the copy with @code(snd-fetch). @codef[snd-fetch-array(@pragma(defn)@index(snd-fetch-array)@i(sound), @i(len), @i(step))]@\Reads sequential arrays of samples from @i(sound), returning either an array of @code(FLONUM)s or @code(NIL) when the sound terminates. The @i(len) parameter, a @code(FIXNUM), indicates how many samples should be returned in the result array. After the array is returned, @i(sound) is modified by skipping over @i(step) (a @code(FIXNUM)) samples. If @i(step) equals @i(len), then every sample is returned once. If @i(step) is less than @i(len), each returned array will overlap the previous one, so some samples will be returned more than once. If @i(step) is greater than @i(len), then some samples will be skipped and not returned in any array. The @i(step) and @i(len) may change at each call, but in the current implementation, an internal buffer is allocated for @i(sound) on the first call, so subsequent calls may not specify a greater @i(len) than the first. @p(Note:) @code(snd-fetch-array) modifies @i(sound); it is strongly recommended to copy @i(sound) using @code(snd-copy) and access only the copy with @code(snd-fetch-array). @codef[snd-flatten(@pragma(defn)@index(snd-flatten)@i(sound), @i(maxlen))]@\This function is identical to @code(snd-length). You would use this function to force samples to be computed in memory. Normally, this is not a good thing to do, but here is one appropriate use: In the case of sounds intended for wavetables, the unevaluated sound may be larger than the evaluated (and typically short) one. Calling @code(snd-flatten) will compute the samples and allow the unit generators to be freed in the next garbage collection. @p(Note:) If a sound is computed from many instances of table-lookup oscillators, calling @code(snd-flatten) will free the oscillators and their tables. Calling @code[(stats)] will print how many total bytes have been allocated to tables. @codef[snd-length(@pragma(defn)@index(snd-length)@i(sound), @i(maxlen))]@\Counts the number of samples in @i(sound) up to the physical stop time. If the sound has more than @i(maxlen) samples, @i(maxlen) is returned. Calling this function will cause all samples of the sound to be computed and saved in memory (about 4 bytes per sample). Otherwise, this function is safe for ordinary use. @codef[snd-maxsamp(@pragma(defn)@index(snd-maxsamp)@i(sound))]@\Computes the maximum of the absolute value of the samples in @i(sound). Calling this function will cause samples to be computed and saved in memory. (This function should have a @i(maxlen) parameter to allow self-defense against sounds that would exhaust available memory.) Otherwise, this function is safe for ordinary use. This function will probably be removed in a future version. See @code(peak), a replacement (@pragma(startref) page @pageref(peak-sec)). @codef[snd-play(@pragma(defn)@index(snd-play)@i(expression))]@\Evaluates @i(expression) to obtain a sound or array of sounds, computes all of the samples (without retaining them in memory), and returns. Originally, this was a placeholder for a facility to play samples directly to an audio output device, but playback is now accomplished by @code(s-save). Meanwhile, since this function does not save samples in memory or write them to a disk, it is useful in determining how much time is spent calculating samples. See @code(s-save) (Section @ref(s-save-sec)) for saving samples to a file, and @code(play) (Section @ref(play-sec)) to play a sound. This function is safe for ordinary use. @codef[snd-print-tree(@pragma(defn)@index(snd-print-tree)@i(sound))]@\Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. This function is safe for ordinary use. @codef[snd-samples(@index(samples)@pragma(defn)@index(snd-samples)@index(array from sound)@index(convert sound to array)@i(sound), @i(limit))]@\Converts the samples into a lisp array. The data is taken directly from the samples, ignoring shifts. For example, if the sound starts at 3.0 seconds, the first sample will refer to time 3.0, not time 0.0. A maximum of @i(limit) samples is returned. This function is safe for ordinary use, but like @code(snd-from-array), it requires a total of slightly over 18 bytes per sample. @codef[snd-srate(@pragma(defn)@index(snd-srate)@i(sound))]@\Returns the sample rate of the sound. Safe for ordinary use. @begin(comment) @codef[snd-show(@pragma(defn)@index(snd-show)@i(sound))]@\Print the entire (internal) structure of the sound for debugging. Safe for ordinary use. @end(comment) @codef[snd-time(@pragma(defn)@index(snd-time)@i(sound))]@\Returns the start time of the sound. This will probably go away in a future version, so use @code(snd-t0) instead. @codef[snd-t0(@pragma(defn)@index(snd-t0)@i(sound))]@\Returns the time of the first sample of the sound. Note that Nyquist operators such as add always copy the sound and are allowed to shift the copy up to one half sample period in either direction to align the samples of two operands. Safe for ordinary use. @codef[snd-print(@pragma(defn)@index(snd-print)@i(expression), @i(maxlen))]@\Evaluates @i(expression) to yield a sound or an array of sounds, then prints up to @i(maxlen) samples to the screen (stdout). This is similar to @code(snd-save), but samples appear in text on the screen instead of in binary in a file. This function is intended for debugging@index(debugging). Safe for ordinary use. @codef[snd-set-logical-stop(@pragma(defn)@index(snd-set-logical-stop)@i(sound), @i(time))]@\Returns a sound which is @i(sound), except that the logical stop of the sound occurs at @i(time). @p(Note:) do not call this function. When defining a behavior, use @code(set-logical-stop) or @code(set-logical-stop-abs) instead. @codef[snd-sref(@pragma(defn)@index(snd-sref)@i(sound), @i(time))]@\Evaluates @i(sound) at the global time given by @i(time). Safe for ordinary use, but normally, you should call @code(sref) instead. @codef[snd-stop-time(@pragma(defn)@index(snd-stop-time)@i(sound))]@\Returns the stop time of @i(sound). Sounds can be ``clipped'' or truncated at a particular time. This function returns that time or MAX-STOP-TIME if he programmer has not specified a stop time for the sound. Safe for ordinary use. @codef[soundp(@pragma(defn)@index(soundp)@i(sound))]@\Returns true iff @i(sound) is a SOUND. Safe for ordinary use. @codef[stats(@pragma(defn)@index(stats)@index(memory usage)@index(table memory))]@\Prints the memory usage status. See also the XLISP @code(mem) function. Safe for ordinary use. This is the only way to find out how much memory is being used by table-lookup oscillator instances. @end(fndefs) @subsection(Miscellaneous Functions) These are all safe and recommended for ordinary use. @begin(fndefs) @codef[db-to-linear(@pragma(defn)@index(db-to-linear)@i(x))]@\Returns the conversion of @i(x) from decibels to linear. 0dB is converted to 1. 20dB represents a linear factor of 10. If @i(x) is a sound, each sample is converted and a sound is returned. If @i(x) is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. @p(Note:) With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Sample rates, start times, etc. are taken from @i(x). @codef[follow(@pragma(defn)@index(follow)@index(envelope follower)@index(compressor)@index(limiter)@i(sound), @i(floor), @i(risetime), @i(falltime), @i(lookahead))]@\An envelope follower intended as a commponent for compressor and limiter functions. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The @i(floor) is the minimum output value. The @i(risetime) is the time (in seconds) it takes for the output to rise (exponentially) from @i(floor) to unity (1.0) and the @i(falltime) is the time it takes for the output to fall (exponentially) from unity to @i(floor). The algorithm looks ahead for peaks and will begin to increase the output signal according to @i(risetime) in anticipation of a peak. The amount of anticipation (in seconds) is given by @i(lookahead). The algorithm is as follows: the output value is allowed to increase according to @i(risetime) or decrease according to @i(falltime). If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to @i(risetime) to meet the new value. The algorithm will only work backward as far as @i(lookahead). If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by @i(falltime), the output fall rate will be limited by @i(falltime), and the fall in output will stop when the output reaches @i(floor). This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See @code(snd-avg) for a function that can help to generate a low-sample-rate input for @code(follow). See @code(snd-chase) in Section @ref(snd-chase-sec) for a related filter. @label(gate-sec) @codef[gate(@pragma(defn)@index(gate)@index(noise-gate)@i(sound), @i(lookahead), @i(risetime), @i(falltime), @i(floor), @i(threshold))]@\Generate an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below @i(threshold) and stays there for longer than @i(lookahead) (a @code(FLONUM) in seconds). (The signal begins to drop when the signal crosses @i(threshold), not after @i(lookahead).) Decay continues until the value reaches @i(floor) (a @code(FLONUM)), at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above @i(threshold), then the ouptut value will rise to unity (1.0) at the point the signal crosses the threshold. Because of internal lookahead, the signal actually begins to rise before the signal crosses @i(threshold). The rise is a constant-rate exponential and set so that a rise from @i(floor) to unity occurs in @i(risetime). Similary, the fall is a constant-rate exponential such that a fall from unity to @i(floor) takes @i(falltime). @codef[hz-to-step(@pragma(defn)@index(hz-to-step)@i(freq))]@\Returns a step number for @i(freq) (in hz), which can be either a number of a @code(SOUND). The result has the same type as the argument. See also @code(step-to-hz) (below). @codef[linear-to-db(@pragma(defn)@index(linear-to-db)@i(x))]@\Returns the conversion of @i(x) from linear to decibels. 1 is converted to 0. 0 is converted to -INF (a special IEEE floating point value.) A factor of 10 represents a 20dB change. If @i(x) is a sound, each sample is converted and a sound is returned. If @i(x) is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. @p(Note:) With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Start times, sample rates, etc. are taken from @i(x). @codef[log(@index(log function)@pragma(defn)@index(log)@i(x))]@\Calculates the natural log of @i(x) (a @code(FLONUM)). (See @code(s-log) for a version that operates on signals.) @codef[set-control-srate(@pragma(defn)@index(set-control-srate)@index(sampling rate)@i(rate))]@\Sets the default sampling rate for control signals to @i(rate) by setting @code(*default-control-srate*) and reinitializing the environment. Do not call this within any synthesis function (see the @code(control-srate-abs) transformation, Section @ref(control-srate-abs-sec)). @codef[set-sound-srate(@pragma(defn)@index(set-sound-srate)@index(sampling rate)@i(rate))]@\Sets the default sampling rate for audio signals to @i(rate) by setting @code(*default-sound-srate*) and reinitializing the environment. Do not call this within any synthesis function (see the @code(sound-srate-abs) transformation, Section @ref(sound-srate-abs-sec)). @codef[set-pitch-names(@pragma(defn)@index(set-pitch-names))]@\Initializes pitch variables (@code(c0), @code(cs0), @code(df0), @code(d0), ... @code(b0), @code(c1), ... @code(b7)). A440 (the default tuning) is represented by the step 69.0, so the variable @code(a4) (fourth octave A) is set to 69.0. You can change the tuning by setting @code(*A4-Hertz*)@index(tuning)@index(A440)@index(*A4-Hertz*) to a value (in Hertz) and calling @code(set-pitch-names) to reinitialize the pitch variables. Note that this will result in non-integer step values. It does not alter the mapping from step values to frequency. There is no built-in provision for stretched scales or non-equal temperament, although users can write or compute any desired fractional step values. @codef[step-to-hz(@pragma(defn)@index(step-to-hz)@i(pitch))]@\Returns a frequency in hz for @i(pitch), a step number or a @code(SOUND) type representing a time-varying step number. The result is a @code(FLONUM) if @i(pitch) is a number, and a @code(SOUND) if @i(pitch) is a @code(SOUND). See also @code(hz-to-step) (above). @codef{get-duration(@pragma(defn)@index(get-duration)@i(dur))}@\Gets the actual duration of of something starting at a local time of 0 and ending at a local time of @i(dur) times the current sustain. For convenience, @code(*rslt*) is set to the global time corresponding to local time zero. @codef{get-loud(@pragma(defn)@index(get-loud))}@\Gets the current value of the @code(*loud*) environment variable. If @code(*loud*) is a signal, it is evaluated at local time 0 and a number (@code(FLONUM)) is returned. @codef{get-sustain(@pragma(defn)@index(get-sustain))}@\Gets the current value of the @code(*sustain*) environment variable. If @code(*sustain*) is a signal, it is evaluated at local time 0 and a number (@code(FLONUM)) is returned. @codef{get-transpose(@pragma(defn)@index(get-transpose))}@\Gets the current value of the @code(*transpose*) environment variable. If @code(*transpose*) is a signal, it is evaluated at local time 0 and a number (@code(FLONUM)) is returned. @codef{get-warp(@pragma(defn)@index(get-warp))}@\Gets a function corresponding to the current value of the @code(*warp*) environment variable. For efficiency, @code(*warp*) is stored in three parts representing a shift, a scale factor, and a continuous warp function. @code(Get-warp) is used to retrieve a signal that maps logical time to real time. This signal combines the information of all three components of @code(*warp*) into a single signal. If the continuous warp function component is not present (indicating that the time warp is a simple combination of @code(at) and @code(stretch) transformations), an error is raised. This function is mainly for internal system use. In the future, @code(get-warp) will probably be reimplemented to always return a signal and never raise an error. @codef{local-to-global(@pragma(defn)@index(local-to-global)@i(local-time))}@\Converts a score (local) time to a real (global) time according to the current environment. @codef{osc-enable(@pragma(defn)@index(osc-enable)@index(osc)@index(open sound control)@i(flag))}@\Enable or disable Open Sound Control. (See Appendix @ref(osc-app).) Enabling creates a socket and a service that listens for UDP packets on port 7770. Currently, only two messages are accepted by Nyquist. The first is of the form @code(/slider) with an integer index and a floating point value. These set internal slider values accessed by the @code(snd-slider) function. The second is of the form @code(/wii/orientation) with two floating point values. This message is a special case to support the DarwiinRemoteOsc@index(DarwiinRemoteOsc) program which can relay data from a Nintendo@index(Nintendo WiiMote) WiiMote@index(Wii Controller) device to Nyquist via OSC. The two orientation values control sliders 0 and 1. Disabling terminates the service (polling for messages) and closes the socket. The @i(previous) state of enablement is returned, e.g. if OSC is enabled and @i(flag) is @i(nil), OSC is disabled and @code(T) (true) is returned because OSC was enabled at the time of the call. This function only exists if Nyquist is compiled with the compiler flag @code(OSC). Otherwise, the function exists but always returns the symbol @code(DISABLED). Consider lowering the audio latency using @code(snd-set-latency). @i(Warning:) there is the potential for network-based attacks using OSC. It is tempting to add the ability to evaluate XLISP expressions sent via OSC, but this would create unlimited and unprotected access to OSC clients. For now, it is unlikely that an attacker could do more than manipulate slider values. @codef{snd-set-latency(@index(latency)@pragma(defn)@index(snd-set-latency)@i(latency))}@\Set the latency requested when Nyquist plays sound to @i(latency), a @code(FLONUM). The previous value is returned. The default is 0.3 seconds. To avoid glitches, the latency should be greater than the time required for garbage collection and message printing and any other system activity external to Nyquist. @end(fndefs) @section(Behaviors)@index(Behaviors) @label(behavior-sec) @subsection(Using Previously Created Sounds) @label(use-sounds-sec) These behaviors take a sound and transform that sound according to the environment. These are useful when writing code to make a high-level function from a low-level function, or when cuing sounds which were previously created: @begin(fndefs) @codef[cue(@pragma(defn)@index(cue)@i(sound))]@\Applies @code(*loud*), the starting time from @code(*warp*), @code(*start*), and @code(*stop*) to @i(sound). @codef[cue-file(@pragma(defn)@index(cue-file)@i(filename))]@\Same as @code(cue), except the sound comes from the named file, samples from which are coerced to the current default @code(*sound-srate*) sample rate. @codef[sound(@pragma(defn)@index(sound)@i(sound))]@\Applies @code(*loud*), @code(*warp*), @code(*start*), and @code(*stop*) to @i(sound). @codef[control(@pragma(defn)@index(control)@i(sound))]@\This function is identical to @code(sound), but by convention is used when @i(sound) is a control signal rather than an audio signal. @end(fndefs) @subsection(Sound Synthesis) These functions provide musically interesting creation behaviors that react to their environment; these are the ``unit generators'' of Nyquist: @begin(fndefs) @codef{const(@pragma(defn)@index(const)@index(constant function)@i(value)[ ,@i(duration)])}@\Creates a constant function at the @code(*control-srate*). Every sample has the given @i(value), and the default @i(duration) is 1.0. See also @code(s-rest), which is equivalent to calling @code(const) with zero, and note that you can pass scalar constants (numbers) to @code(sim), @code(sum), and @code(mult) where they are handled more efficiently than constant functions. @codef{env(@pragma(defn)@index(env)@i(t@-[1]), @i(t@-[2]), @i(t@-[4]), @i(l@-[1]), @i(l@-[2]), @i(l@-[3]), [@i(dur)])}@\Creates a 4-phase envelope. @i(t@-[@i(i)]) is the duration of phase @i(i), and @i(l@-[@i(i)]) is the final level of phase @i(i). @i(t@-[3]) is implied by the duration @i(dur), and @i(l@-[4]) is @code(0.0). If @i(dur) is not supplied, then @code(1.0) is assumed. The envelope duration is the product of @i(dur), @code(*stretch*), and @code(*sustain*). If @i(t@-[1]) + @i(t@-[2]) + 2ms + @i(t@-[4]) is greater than the envelope duration, then a two-phase envelope is substituted that has an attack/release time ratio of @i(t@-[1])/@i(t@-[4]). The sample rate of the returned sound is @code(*control-srate*). (See @code(pwl) for a more general piece-wise linear function generator.) The effect of time warping is to warp the starting time and ending time. The intermediate breakpoints are then computed as described above. @codef{exp-dec(@pragma(defn)@index(exp-dec)@index(exponential envelope)@i(hold), @i(halfdec), @i(length))}@\This convenient envelope shape is a special case of @code(pwev) (see Section @ref(pwev-sec)). The envelope starts at 1 and is constant for @i(hold) seconds. It then decays with a half life of @i(halfdec) seconds until @i(length). (The total duration is @i(length).) In other words, the amplitude falls by half each @i(halfdec) seconds. When stretched, this envelope scales linearly, which means the hold time increases and the half decay time increases. @label(force-srate-sec) @codef{force-srate(@pragma(defn)@index(force-srate)@index(sample rate, forcing)@index(resampling)@i(srate), @i(sound))}@\Returns a sound which is up- or down-sampled to @i(srate). Interpolation is linear, and no prefiltering is applied in the down-sample case, so aliasing may occur. See also @code(resample). @codef{lfo(@pragma(defn)@index(lfo)@index(low-frequency oscillator)@i(freq)[ ,@i(duration), @i(table), @i(phase)])}@\Just like @code(osc) (below) except this computes at the @code(*control-srate*) and frequency is specified in Hz. Phase is specified in degrees. The @code(*transpose*) and @code(*sustain*) is not applied. The effect of time warping is to warp the starting and ending times. The signal itself will have a constant unwarped frequency. @codef{fmlfo(@pragma(defn)@index(fmlfo)@i(freq)[ ,@i(table), @i(phase)])}@\A low-frequency oscillator that computes at the @code(*control-srate*) using a sound to specify a time-varying frequency in Hz. Phase is a @code(FLONUM) in degrees. The duration of the result is determined by @i(freq). @codef{maketable(@pragma(defn)@index(maketable)@label(maketable)@i(sound))}@\Assumes that the samples in @i(sound) constitute one period of a wavetable, and returns a wavetable suitable for use as the @i(table) argument to the @code(osc) function (see below). Currently, tables are limited to 1,000,000 samples. This limit is the compile-time constant @code(max_table_len) set in @code(sound.h). @codef{build-harmonic(@pragma(defn)@index(build-harmonic)@index(harmonic)@i(n), @i(table-size))}@\Intended for constructing wavetables@index(wavetables)@index(waveforms), this function returns a sound of length @i(table-size) samples containing @i(n) periods of a sinusoid. These can be scaled and summed to form a waveform with the desired harmonic content. See @pragma(startref) page @pageref(build-harmonic-example) for an example. @codef{control-warp(@pragma(defn)@index(control-warp)@i(warp-fn), @i(signal), [@i(wrate)])}@\Applies a warp function @i(warp-fn) to @i(signal) using function composition. If @i(wrate) is omitted, linear interpolation is used. @i(warp-fn) is a mapping from score (logical) time to real time, and @i(signal) is a function from score time to real values. The result is a function from real time to real values at a sample rate of @code(*control-srate*). See @code(sound-warp) for an explanation of @i(wrate) and high-quality warping. @label(mult-sec) @codef{mult(@pragma(defn)@index(mult)@i(beh@-[1]), @i(beh@-[2]), ...)}@\Returns the product of behaviors. The arguments may also be numbers, in which case simple multiplication is performed. If a number and sound are mixed, the @code(scale) function is used to scale the sound by the number. When sounds are multiplied, the resulting sample rate is the maximum sample rate of the factors. @codef{prod(@pragma(defn)@index(prod)@i(beh@-[1]), @i(beh@-[2]), ...)}@\Same as @code(mult). @label(pan-sec) @codef{pan(@pragma(defn)@index(pan)@index(stereo panning)@i(sound), @i(where))}@\Pans @i(sound) (a behavior) according to @i(where) (another behavior or a number). @i(Sound) must be monophonic. @i(Where) may be a monophonic sound (e.g. @code[(ramp)] or simply a number (e.g. @code(0.5)). In either case, @i(where) should range from 0 to 1, where 0 means pan completely left, and 1 means pan completely right. For intermediate values, the sound to each channel is scaled linearly. Presently, @code(pan) does not check its arguments carefully. @codef{prod(@pragma(defn)@index(prod)@i(beh@-[1]), @i(beh@-[2]), ...)}@\Same as @code(mult). @label(resample-sec) @codef{resample(@pragma(defn)@index(resample)@i(sound), @i(srate))}@\Similar to @code(force-srate), except high-quality interpolation is used to prefilter and reconstruct the signal at the new sample rate. Also, the result is scaled by 0.95 to reduce problems with clipping. (See also @code(sound-warp).) @label(scale-sec) @codef{scale(@pragma(defn)@index(scale)@i(scale), @i(sound))}@\Scales the amplitude of @i(sound) by the factor @i(scale). Identical function to @code(snd-scale), except that it handles multichannel sounds. Sample rates, start times, etc. are taken from @i(sound). @codef{scale-db(@pragma(defn)@index(scale-db)@i(db), @i(sound))}@\Scales the amplitude of @i(sound) by the factor @i(db), expressed in decibels. Sample rates, start times, etc. are taken from @i(sound). @codef[scale-srate(@pragma(defn)@index(scale-srate)@i(sound), @i(scale))]@\Scales the sample rate of @i(sound) by @i(scale) factor. This has the effect of linearly shrinking or stretching time (the sound is not upsampled or downsampled). This is a special case of @code(snd-xform) (see Section @ref(snd-xform-sec)). @codef[shift-time(@pragma(defn)@index(shift-time)@i(sound), @i(shift))]@\Shift @i(sound) by @i(shift) seconds. If the sound is @pragma(startscribe) @math[f(t)], then the result is @pragma(endscribe) @html[f(t), then the result is] @pragma(startscribe) @math[f(t - shift)]. @pragma(endscribe) @html[f(t - shift).] See Figure @ref(shift-time-fig). This is a special case of @code(snd-xform) (see Section @ref(snd-xform-sec)). @end(fndefs) @begin(figure) @center(@graphic((height = 3 in, width = 4.5 in, magnify = 0.75, postscript = "shifttimefig.ps")) @html(

    ) @fillcaption(The @code(shift-time) function shifts a sound in time according to its @i(shift) argument.) @tag(shift-time-fig) @end(figure) @begin(fndefs) @codef{sound-warp(@pragma(defn)@index(sound-warp)@i(warp-fn), @i(signal)[ ,@i(wrate)])}@\Applies a warp function @i(warp-fn) to @i(signal) using function composition. If the optional parameter @i(wrate) is omitted or NIL, linear interpolation is used. Otherwise, high-quality sample interpolation is used, and the result is scaled by 0.95 to reduce problems with clipping (interpolated samples can exceed the peak values of the input samples.) @i(warp-fn) is a mapping from score (logical) time to real time, and @i(signal) is a function from score time to real values. The result is a function from real time to real values at a sample rate of @code(*sound-srate*). See also @code(control-warp). @blankspace(1) If @i(wrate) is not NIL, it must be a number. The parameter indicates that high-quality resampling should be used and specifies the sample rate for the inverse of @i(warp-fn). Use the lowest number you can. (See below for details.) Note that high-quality resampling is much slower than linear interpolation. @blankspace(1) To perform high-quality resampling by a fixed ratio, as opposed to a variable ratio allowed in @code(sound-warp), use @code(scale-srate) to stretch or shrink the sound, and then @code(resample) to restore the original sample rate. @blankspace(1) @code(Sound-warp) and @code(control-warp) both take the inverse of @i(warp-fn) to get a function from real time to score time. Each sample of this inverse is thus a score time; @i(signal) is evaluated at each of these score times to yield a value, which is the desired result. The sample rate of the inverse warp function is somewhat arbitrary. With linear interpolation, the inverse warp function sample rate is taken to be the output sample rate. Note, however, that the samples of the inverse warp function are stored as 32-bit floats, so they have limited precision. Since these floats represent sample times, rounding can be a problem. Rounding in this case is equivalent to adding jitter to the sample times. Nyquist ignores this problem for ordinary warping, but for high-quality warping, the jitter cannot be ignored. @blankspace(1) The solution is to use a rather low sample rate for the inverse warp function. @code(Sound-warp) can then linearly interpolate this signal using double-precision floats to minimize jitter between samples. The sample rate is a compromise: a low sample rate minimizes jitter, while a high sample rate does a better job of capturing detail (e.g. rapid fluctuations) in the warp function. A good rule of thumb is to use at most 1,000 to 10,000 samples for the inverse warp function. For example, if the result will be 1 minute of sound, use a sample rate of 3000 samples / 60 seconds = 50 samples/second. Because Nyquist has no advance information about the warp function, the inverse warp function sample rate must be provided as a parameter. When in doubt, just try something and let your ears be the judge. @codef[integrate(@pragma(defn)@index(integrate)@index(smooth)@i(signal))]@\Computes the integral of @i(signal). The start time, sample rate, etc. are taken from @i(signal). @codef[slope(@pragma(defn)@index(slope)@index(derivative)@index(first derivative)@i(signal))]@\Computes the first derivative (slope) of @i(signal). The start time, sample rate, etc. are taken from @i(signal). @end(fndefs) @paragraph(Oscillators) @label(osc-sec) @begin(fndefs) @codef{osc(@pragma(defn)@index(osc)@i(pitch)[, @i(duration), @i(table), @i(phase)])}@\Returns a sound which is the @i(table) oscillated at @i(pitch) for the given @i(duration), starting with the @i(phase) (in degrees). Defaults are: @i(duration) @code(1.0) (second), @i(table) @code(*table*), @i(phase) @code(0.0). The default value of @code(*table*) is a sinusoid. Duration is stretched by @code(*warp*) and @code(*sustain*), amplitude is nominally 1, but scaled by @code(*loudness*), the start time is logical time 0, transformed by @code(*warp*), and the sample rate is @code(*sound-srate*). The effect of time-warping is to warp the starting and ending times only; the signal has a constant unwarped frequency. @p(Note 1:) @i(table) is a list of the form @begin(display) (@i(sound) @i(pitch-number) @i(periodic)) @end(display) where the first element is a sound, the second is the pitch of the sound (this is not redundant, because the sound may represent any number of periods), and the third element is @code(T) if the sound is one period of a periodic signal, or @code(nil) if the sound is a sample that should not be looped. The maximum table size is set by @code(max_table_len) in @code(sound.h), and is currently set to 1,000,000. @p(Note 2:) in the current implementation, it is assumed that the output should be periodic. See @code(snd-down) and @code(snd-up) for resampling one-shot sounds to a desired sample rate. A future version of @code(osc) will handle both cases. @p(Note 3:) When @code(osc) is called, memory is allocated for the table, and samples are copied from the sound (the first element of the list which is the @i(table) parameter) to the memory. Every instance of @code(osc) has a private copy of the table, so the total storage can become large in some cases, for example in granular synthesis with many instances of @code(osc). In some cases, it may make sense to use @code(snd-flatten) (see Section @ref(flatten-sec)) to cause the sound to be fully realized, after which the @code(osc) and its table memory can be reclaimed by garbage collection. The @code(partial) function (see below) does not need a private table and does not use much space. @label(partial-sec) @codef{partial(@pragma(defn)@index(partial)@i(pitch), @i(env))}@\Returns a sinusoid at the indicated pitch; the sound is multiplied by @i(env). The start time and duration are taken from @i(env), which is of course subject to transformations. The sample rate is @code(*sound-srate*). The @code(partial) function is faster than @code(osc). @label(sine-sec) @codef{sine(@pragma(defn)@index(sine)@i(pitch)[ ,@i(duration)])}@\Returns a sinusoid at the indicated pitch. The sample rate is @code(*sound-srate*). This function is like @code(osc) with respect to transformations. The @code(sine) function is faster than @code(osc). @codef{hzosc(@pragma(defn)@index(hzosc)@i(hz)[ ,@i(table), @i(phase)])}@\Returns a sound which is the @i(table) oscillated at @i(hz) starting at @i(phase) degrees. The default @i(table) is @code(*table*) and the default @i(phase) is @i(0.0). The default duration is @code(1.0), but this is stretched as in @code(osc) (see above). The @i(hz) parameter may be a @code(SOUND), in which case the duration of the result is the duration of @i(hz). The sample rate is @code(*sound-srate*). @codef{osc-saw(@pragma(defn)@index(osc-saw)@index(sawtooth oscillator)@i(hz))}@\Returns a sawtooth waveshape at the indicated frequency (in Hertz). The sample rate is @code(*sound-srate*). The @i(hz) parameter may be a sound as in @i(hzosc) (see above). @codef{osc-tri(@pragma(defn)@index(osc-tri)@index(triangle oscillator)@i(hz))}@\Returns a triangle waveshape at the indicated frequency (in Hertz). The sample rate is @code(*sound-srate*). The @i(hz) parameter may be a sound as in @i(hzosc) (see above). @codef{osc-pulse(@pragma(defn)@index(osc-pulse)@index(square oscillator)@index(pulse oscillator)@index(pulse-width modulation)@i(hz), @i(bias)[ ,@i(compare-shape)])}@\Returns a square pulse with variable width at the indicated frequency (in Hertz). The @i(bias) parameter controls the pulse width and should be between @code(-1) and @code(+1), giving a pulse width from 0% (always at @code(-1)) to 100% (always at @code(+1)). When bias is zero, a square wave is generated. Bias may be a @code(SOUND) to create varying pulse width. If bias changes rapidly, strange effects may occur. The optional @i(compare-shape) defaults to a hard step at zero, but other shapes may be used to achieve non-square pulses. The @code(osc-pulse) behavior is written in terms of other behaviors and defined in the file @code(nyquist.lsp) using just a few lines of code. Read the code for the complete story. @label(amosc-sec) @codef{amosc(@pragma(defn)@index(amosc)@i(pitch), @i(modulation)[ ,@i(table), @i(phase)])}@\Returns a sound which is @i(table) oscillated at @i(pitch). The output is multiplied by @i(modulation) for the duration of the sound @i(modulation). @i(osc-table) defaults to @code(*table*), and @i(phase) is the starting phase (default 0.0 degrees) within @i(osc-table). The sample rate is @code(*sound-srate*). @label(fmosc-sec) @codef{fmosc(@pragma(defn)@index(fmosc)@i(pitch), @i(modulation)[, @i(table), @i(phase)])}@\Returns a sound which is @i(table) oscillated at @i(pitch) plus @i(modulation) for the duration of the sound @i(modulation). @i(osc-table) defaults to @code(*table*), and @i(phase) is the starting phase (default 0.0 degrees) within @i(osc-table). The @i(modulation) is expressed in hz, e.g. a sinusoid modulation signal with an amplitude of 1.0 (2.0 peak to peak), will cause a +/@subtract 1.0 hz frequency deviation in @i(sound). Negative frequencies are correctly handled. The sample rate is @code(*sound-srate*). @label(fmfb-sec) @codef{fmfb(@pragma(defn)@index(fmfb)@index(Feedback FM Oscillator)@i(pitch), @i(index)[ ,@i(dur)])}@\Returns a sound generated by feedback FM synthesis. The @i(pitch) parameter (given in the usual half-step units) controls the fundamental frequency. The @i(index) is the amount of feedback, which may be a @code(SOUND) or a @code(FLONUM). If @i(index) is a @code(FLONUM), @i(dur) must be provided (a @code(FLONUM)) to specify the duration. Otherwise, @i(dur) is ignored if present and the duration is determined by that of @i(index). The sample rate is @code(*sound-srate*). A sinusoid table is used. If @i(index) is below 1.1, this generates a sawtooth-like waveform. @label(buzz-sec) @codef{buzz(@pragma(defn)@index(buzz)@i(n), @i(pitch), @i(modulation))}@\Returns a sound with @i(n) harmonics of equal amplitude and a total amplitude of 1.0, using a well-known function of two cosines. If @i(n) (an integer) is less than 1, it is set to 1. Aliasing will occur if @i(n) is too large. The duration is determined by the duration of the sound @i(modulation), which is a frequency modulation term expressed in Hz (see Section @ref(fmosc-sec)). Negative frequencies are correctly handled. The sample rate is @code(*sound-srate*). @label(pluck-sec) @codef{pluck(@pragma(defn)@index(pluck)@index(Karplus-Strong)@index(string synthesis) @index(plucked string)@i(pitch)[ ,@i(duration)] [, @i(final-amplitude)])}@\Returns a sound at the given @i(pitch) created using a modified Karplus-Strong plucked string algorithm. The tone decays from an amplitude of about 1.0 to about @i(final-amplitude) in @i(duration) seconds. The default values are to decay to 0.001 (-60dB) in 1 second. The sample rate is @code(*sound-srate*). @label(siosc-sec) @codef{siosc(@pragma(defn)@index(siosc)@index(spectral interpolation)@i(pitch), @i(modulation), @i(tables))}@\Returns a sound constructed by interpolating through a succession of periodic waveforms. The frequency is given (in half steps) by @i(pitch) to which a @i(modulation) signal (in hz) is added, exactly as in @code(fmosc). The @i(tables) specify a list of waveforms as follows: (@i(table0) @i(time1) @i(table2) ... @i(timeN) @i(tableN)), where each @i(table) is a sound representing one period. Each @i(time) is a time interval measured from the starting time. The time is scaled by the nominal duration (computed using @code[(local-to-global (get-sustain))]) to get the actual time. Note that this implies linear stretching rather than continuous timewarping of the interpolation or the breakpoints. The waveform is @i(table0) at the starting time, @i(table1) after @i(time1) (scaled as described), and so on. The duration and logical stop time is given by @i(modulation). If @i(modulation) is shorter than @i(timeN), then the full sequence of waveforms is not used. If @i(modulation) is longer than @i(timeN), @i(tableN) is used after @i(timeN) without further interpolation. @label(sampler-sec) @codef{sampler(@pragma(defn)@index(sampler)@i(pitch), @i(modulation)[ ,@i(sample), @i(npoints)])}@\Returns a sound constructed by reading a sample from beginning to end and then splicing on copies of the same sound from a loop point to the end. The @i(pitch) and @i(modulation) parameters are used as in @code(fmosc) described above. The optional @i(sample) (which defaults to the global variable @code(*table*) is a list of the form @begin(display) (@i(sound) @i(pitch-number) @i(loop-start)) @end(display) where the first element is a sound containing the sample, the second is the pitch of the sample, and the third element is the time of the loop point. If the loop point is not in the bounds of the sound, it is set to zero. The optional @i(npoints) specifies how many points should be used for sample interpolation. Currently this parameter defaults to 2 and only 2-point (linear) interpolation is implemented. It is an error to modulate such that the frequency is negative. Note also that the loop point may be fractional. The sample rate is @code(*sound-srate*). @end(fndefs) @paragraph(Piece-wise Approximations) @index(piece-wise)@index(approximation)@index(splines) There are a number of related behaviors for piece-wise approximations to functions. The simplest of these, @code(pwl) was mentioned earlier in the manual. It takes a list of breakpoints, assuming an initial point at (0, 0), and a final value of 0. An analogous piece-wise exponential function, @code(pwe), is provided. Its implicit starting and stopping values are 1 rather than 0. Each of these has variants. You can specify the initial and final values (instead of taking the default). You can specify time in intervals rather than cummulative time. Finally, you can pass a list rather than an argument list. This leads to 16 versions: @pragma(startscribe) @begin(display) @tabclear @tabset(0.4 inches, 0.8 inches, 1.2 inches) Piece-wise Linear Functions: @\Cummulative Time: @\@\Default initial point at (0, 0), final value at 0: @\@\@\@code(pwl) @\@\@\@code(pwl-list) @\@\Explicit initial value: @\@\@\@code(pwlv) @\@\@\@code(pwlv-list) @\Relative Time: @\@\Default initial point at (0, 0), final value at 0: @\@\@\@code(pwlr) @\@\@\@code(pwlr-list) @\@\Explicit initial value: @\@\@\@code(pwlvr) @\@\@\@code(pwlvr-list) Piece-wise Exponential Functions: @\Cummulative Time: @\@\Default initial point at (0, 1), final value at 1: @\@\@\@code(pwe) @\@\@\@code(pwe-list) @\@\Explicit initial value: @\@\@\@code(pwev) @\@\@\@code(pwev-list) @\Relative Time: @\@\Default initial point at (0, 1), final value at 1: @\@\@\@code(pwer) @\@\@\@code(pwer-list) @\@\Explicit initial value: @\@\@\@code(pwevr) @\@\@\@code(pwevr-list) @end(display) @pragma(endscribe) @html[
    Piece-wise Linear Functions:
    	Cummulative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwl
    			pwl-list
    		Explicit initial value:
    			pwlv
    			pwlv-list
    	Relative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwlr
    			pwlr-list
    		Explicit initial value:
    			pwlvr
    			pwlvr-list
    
    Piece-wise Exponential Functions:
    	Cummulative Time:
    		Default initial point at (0, 1), final value at 1:
    			pwe
    			pwe-list
    		Explicit initial value:
    			pwev
    			pwev-list
    	Relative Time:
    		Default initial point at (0, 1), final value at 1:
    			pwer
    			pwer-list
    		Explicit initial value:
    			pwevr
    			pwevr-list
    
    ] All of these functions are implemented in terms of @code(pwl) (see @code(nyquist.lsp) for the implementations. There are infinite opportunities for errors in these functions: if you leave off a data point, try to specify points in reverse order, try to create an exponential that goes to zero or negative values, or many other bad things, the behavior is not well-defined. Nyquist should not crash, but Nyquist does not necessarily attempt to report errors at this time. @begin(fndefs) @label(pwl-sec) @codef{pwl(@pragma(defn)@index(pwl)@i(t@-[1]), @i(l@-[1]), @i(t@-[2]), @i(l@-[2]), ... @i(t@-[n]))}@\Creates a piece-wise linear envelope with breakpoints at (0, 0), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 0). The breakpoint times are scaled linearly by the value of @code(*sustain*) (if @code(*sustain*) is a @code(SOUND), it is evaluated once at the starting time of the envelope). Each breakpoint time is then mapped according to @code(*warp*). The result is a linear interpolation (unwarped) between the breakpoints. The sample rate is @code(*control-srate*). Breakpoint times are quantized to the nearest sample time. If you specify one or more breakpoints withing one sample period, @code(pwl) attempts to give a good approximation to the specified function. In particular, if two breakpoints are simultaneous, @code(pwl) will move one of them to an adjacent sample, producing a steepest possible step in the signal. The exact details of this ``breakpoint munging'' is subject to change in future versions. Please report any cases where breakpoint lists give unexpected behaviors. The author will try to apply the ``principle of least surprise'' to the design. Note that the times are relative to 0; they are not durations of each envelope segment. @codef{pwl-list(@pragma(defn)@index(pwl-list)@i(breakpoints))}@\If you have a list of breakpoints, you can use @code(apply) to apply the @code(pwl) function to the breakpoints, but if the list is very long (hundreds or thousands of points), you might get a stack overflow because XLISP has a fixed-size argument stack. Instead, call @code(pwl-list), passing one argument, the list of breakpoints. @codef{pwlv(@pragma(defn)@index(pwlv)@i(l@-[1]), @i(t@-[2]), @i(l@-[2]), @i(t@-[3]), @i(t@-[3]), ... @i(t@-[n]), @i(l@-[n]))}@\Creates a piece-wise linear envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])). Otherwise, the behavior is like that of @code(pwl). @codef{pwlv-list(@pragma(defn)@index(pwlv-list)@i(breakpoints))}@\A version of @code(pwlv) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwlr(@pragma(defn)@index(pwlr)@i(i@-[1]), @i(l@-[1]), @i(i@-[2]), @i(l@-[2]), ... @i(i@-[n]))}@\Creates a piece-wise linear envelope with breakpoints at (0, 0), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 0), where @i(t@-[j]) is the sum of @i(i@-[1]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwl). @codef{pwlr-list(@pragma(defn)@index(pwlr-list)@i(breakpoints))}@\A version of @code(pwlr) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwlvr(@pragma(defn)@index(pwlvr)@i(l@-[1]), @i(i@-[2]), @i(l@-[2]), @i(i@-[3]), @i(i@-[3]), ... @i(i@-[n]), @i(l@-[n]))}@\Creates a piece-wise linear envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])), where @i(t@-[j]) is the sum of @i(i@-[2]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwlv). @codef{pwlvr-list(@pragma(defn)@index(pwlvr-list)@i(breakpoints))}@\A version of @code(pwlvr) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwe(@pragma(defn)@index(pwe)@i(t@-[1]), @i(l@-[1]), @i(t@-[2]), @i(l@-[2]), ... @i(t@-[n]))}@\Creates a piece-wise exponential envelope with breakpoints at (0, 1), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 1). Exponential segments means that the ratio of values from sample to sample is constant within the segment. (The current implementation actually takes the log of each value, computes a piece-wise exponential from the points using @code(pwl), then exponentiates each resulting sample. A faster implementation is certainly possible!) Breakpoint values (@i(l@-[j])) must be greater than zero. Otherwise, this function is similar to @code(pwl), including stretch by @code(*sustain*), mapping according to @code(*warp*), sample rate based on @code(*control-srate*), and "breakpoint munging" (see @code(pwl) described above). @i(Default initial and final values are of dubious value with exponentials. See @code(pwev) below for the function you are probably looking for.) @codef{pwe-list(@pragma(defn)@index(pwe-list)@i(breakpoints))}@\A version of @code(pwe) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @label(pwev-sec) @codef{pwev(@pragma(defn)@index(pwev)@i(l@-[1]), @i(t@-[2]), @i(l@-[2]), @i(t@-[3]), @i(t@-[3]), ... @i(t@-[n]), @i(l@-[n]))}@\Creates a piece-wise exponential envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])). Otherwise, the behavior is like that of @code(pwe). @codef{pwev-list(@pragma(defn)@index(pwev-list)@i(breakpoints))}@\A version of @code(pwev) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwer(@pragma(defn)@index(pwer)@i(i@-[1]), @i(l@-[1]), @i(i@-[2]), @i(l@-[2]), ... @i(i@-[n]))}@\Creates a piece-wise exponential envelope with breakpoints at (0, 1), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 1), where @i(t@-[j]) is the sum of @i(i@-[1]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwe). Consider using @code(pwerv) instead of this one. @codef{pwer-list(@pragma(defn)@index(pwer-list)@i(breakpoints))}@\A version of @code(pwer) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwevr(@index(GEN05)@pragma(defn)@index(pwevr)@i(l@-[1]), @i(i@-[2]), @i(l@-[2]), @i(i@-[3]), @i(i@-[3]), ... @i(i@-[n]), @i(l@-[n]))}@\Creates a piece-wise exponential envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])), where @i(t@-[j]) is the sum of @i(i@-[2]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwev). Note that this is similar to the csound GEN05 generator. Which is uglier, @i(GEN05) or @i(pwevr)? @codef{pwevr-list(@pragma(defn)@index(pwevr-list)@i(breakpoints))}@\A version of @code(pwevr) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @end(fndefs) @paragraph(Filter Behaviors) @begin(fndefs) @label(alpass-sec) @codef{alpass(@index(all pass filter)@index(alpass filter)@pragma(defn)@index(alpass)@i(sound), @i(decay), @i(hz)[ ,@i(minhz)])}@\Applies an all-pass filter to @i(sound). This all-pass filter creates a delay effect without the resonances of a comb filter. The decay time of the filter is given by @i(decay). The @i(hz) parameter must be a number or sound greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The @i(decay) may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert @i(decay) into the @i(feedback) parameter, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide @i(decay) at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of @i(sound). If @i(hz) is of type @code(SOUND), the delay may be time-varying. Linear interpolation is then used for fractional sample delay, but it should be noted that linear interpolation implies a low-pass transfer function. Thus, this filter may behave differently with a constant @code(SOUND) than it does with a @code(FLONUM) value for @i(hz). In addition, if @i(hz) is of type @code(SOUND), then @i(minhz) is required. The @i(hz) parameter will be clipped to be greater than @i(minhz), placing an upper bound on the delay buffer length. @label(comb-sec) @codef{comb(@pragma(defn)@index(comb)@index(comb filter)@i(sound), @i(decay), @i(hz))}@\Applies a comb filter to @i(sound). A comb filter emphasizes (resonates at) frequencies that are multiples of a @i(hz). The decay time of the resonance is given by @i(decay). This is a variation on @code(feedback-delay) (see below). The @i(hz) parameter must be a number greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The @i(decay) may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert @i(decay) into the @i(feedback) parameter for @code(feedback-delay), and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide @i(decay) at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of @i(sound). @label(congen-sec) @codef{congen(@pragma(defn)@index(congen)@index(contour generator)@index(envelope generator)@i(gate), @i(risetime), @i(falltime))}@\Implements an analog synthesizer-style contour generator. The input @i(gate) normally goes from 0.0 to 1.0 to create an attack and from 1.0 to 0.0 to start a release. During the attack (output is increasing), the output converges half-way to @i(gate) in @i(risetime) (a @code(FLONUM)) seconds. During the decay, the half-time is @i(falltime) seconds. The sample rate, start time, logical stop, and terminate time all come from @i(gate). If you want a nice decay, be sure that the @i(gate) goes to zero and stays there for awhile before @i(gate) terminates, because @code(congen) (and all Nyquist sounds) go immediately to zero at termination time. For example, you can use @code(pwl) to build a pulse followed by some zero time: @begin(example) (pwl 0 1 duty 1 duty 0 1) @end(example) Assuming @i(duty) is less than 1.0, this will be a pulse of duration @i(duty) followed by zero for a total duration of 1.0. @begin(example) (congen (pwl 0 1 duty 1 duty 0 1) 0.01 0.05) @end(example) will have a duration of 1.0 because that is the termination time of the @code(pwl) input. The decaying release of the resulting envelope will be truncated to zero at time 1.0. (Since the decay is theoretically infinite, there is no way to avoid truncation, although you could multiply by another envelope that smoothly truncates to zero in the last millisecond or two to get both an exponential decay and a smooth final transition to zero.) @label(convolve-sec) @codef{convolve(@pragma(defn)@index(convolve)@index(convolution)@index(FIR filter)@i(sound), @i(response))}@\Convolves two signals. The first can be any length, but the computation time per sample and the total space required are proportional to the length of @i(response). @label(feedback-delay-sec) @codef{feedback-delay(@pragma(defn)@index(feedback-delay)@index(delay)@index(echo)@i(sound), @i(delay), @i(feedback))}@\Applies feedback delay to @i(sound). The @i(delay) must be a number (in seconds). It is rounded to the nearest sample to determine the length of the delay. The sample rate is the maximum from @i(sound) and @i(feedback) (if feedback is also a sound). The amound of @i(feedback) should be less than one to avoid an exponential increase in amplitude. The start time and stop time, and logical stop time are taken from @i(sound). Since output is truncated at the stop time of @i(sound), you may want to append some silence to @i(sound) to give the filter time to decay. @label(lp-sec) @codef{lp(@pragma(defn)@index(lp)@index(low-pass filter)@i(sound), @i(cutoff))}@\Filters @i(sound) using a first-order Butterworth low-pass filter. @i(Cutoff) may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of @i(cutoff). The resulting sample rate, start time, etc. are taken from @i(sound). @codef{tone(@pragma(defn)@index(tone)@i(sound), @i(cutoff))}@\No longer defined; use @code(lp) instead, or define it by adding @code[(setfn tone lp)] to your program. @label(hp-sec) @codef{hp(@pragma(defn)@index(hp)@index(high-pass filter)@i(sound), @i(cutoff))}@\Filters @i(sound) using a first-order Butterworth high-pass filter. @i(Cutoff) may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of @i(cutoff). This filter is an exact complement of @code(lp). @codef{atone(@pragma(defn)@index(atone)@i(sound), @i(cutoff))}@\No longer defined; use @code(hp) instead, or define it by adding @code[(setfn atone hp)] to your program. @label(reson-sec) @codef{reson(@pragma(defn)@index(reson)@index(bandpass filter)@i(sound), @i(center), @i(bandwidth), @i(n))}@\Apply a resonating filter to @i(sound) with center frequency @i(center) (in hertz), which may be a float or a signal. @i(Bandwidth) is the filter bandwidth (in hertz), which may also be a signal. Filter coefficients (requiring trig functions) are recomputed at each new sample of either @i(center) or @i(bandwidth), and coefficients are @i(not) interpolated. The last parameter @i(n) specifies the type of normalization as in Csound: A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than @i(hz) are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The resulting sample rate, start time, etc. are taken from @i(sound). One application of @code(reson) is to simulate resonances in the human vocal tract. See @code(demos/voice_synthesis.htm)@index(voice synthesis)@index(demos, voice synthesis) for sample code and documentation. @label(areson-sec) @codef{areson(@pragma(defn)@index(areson)@index(notch filter)@i(sound), @i(center), @i(bandwidth), @i(n))}@\The @code(areson) filter is an exact complement of @code(reson) such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. @label(shape-sec) @codef{shape(@pragma(defn)@index(shape)@index(waveshaping)@index(table)@i(signal), @i(table), @i(origin))}@\A waveshaping function. Use @i(table) as a function; apply the function to each sample of @i(signal) to yield a new sound. @i(Signal) should range from -1 to +1. Anything beyond these bounds is clipped. @i(Table) is also a sound, but it is converted into a lookup table (similar to table-lookup oscillators). The @i(origin) is a @code(FLONUM) and gives the time which should be considered the origin of @i(table). (This is important because @i(table) cannot have values at negative times, but @i(signal) will often have negative values. The @i(origin) gives an offset so that you can produce suitable tables.) The output at time @i(t) is: @begin(display) @i(table)(@i(origin) + clip(@i(signal)(@i(t))) @end(display) where clip(@i(x)) = @i(max)(1, @i(min)(-1, @i(x))). (E.g. if @i(table) is a signal defined over the interval [0, 2], then @i(origin) should be 1.0. The value of @i(table) at time 1.0 will be output when the input signal is zero.) The output has the same start time, sample rate, etc. as @i(signal). The @code(shape) function will also accept multichannel @i(signal)s and @i(table)s. Further discussion and examples can be found in @code(demos/distortion.htm)@index(distortion tutorial)@index(demos, distortion). The @code(shape) function is also used to map frequency to amplitude to achieve a spectral envelope for Shepard tones in @code(demos/shepard.lsp).@index(Shepard tones)@index(demos, Shepard tones) @label(biquad-sec) @codef{biquad(@pragma(defn)@index(biquad)@i(signal), @i(b0), @i(b1), @i(b2), @i(a0), @i(a1), @i(a2))}@\A fixed-parameter biquad filter. All filter coefficients are @code(FLONUM)s. See also @code(lowpass2), @code(highpass2), @code(bandpass2), @code(notch2), @code(allpass2), @code(eq-lowshelf), @code(eq-highshelf), @code(eq-band), @code(lowpass4), @code(lowpass6), @code(highpass4), and @code(highpass8) in this section for convenient variations based on the same filter. The equations for the filter are: z@-[n] = s@-[n] + a1 * z@-[n-1] + a2 * z@-[n-2], and y@-[n] = z@-[n] * b0 + z@-[n-1] * b1 + z@-[n-2] * b2. @label(biquad-m-sec) @codef{biquad-m(@pragma(defn)@index(biquad-m)@i(signal), @i(b0), @i(b1), @i(b2), @i(a0), @i(a1), @i(a2))}@\A fixed-parameter biquad filter with Matlab sign conventions for @i(a0), @i(a1), and @i(a2). All filter coefficients are @code(FLONUM)s. @label(lowpass2-sec) @codef{lowpass2(@pragma(defn)@index(lowpass2)@i(signal), @i(hz)[ ,@i(q)])}@\A fixed-parameter, second-order lowpass filter based on @code(snd-biquad). The cutoff frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(highpass2-sec) @codef{highpass2(@pragma(defn)@index(highpass2)@i(signal), @i(hz)[ ,@i(q)])}@\A fixed-parameter, second-order highpass filter based on @code(snd-biquad). The cutoff frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(bandpass2-sec) @codef{bandpass2(@pragma(defn)@index(bandpass2)@i(signal), @i(hz)[ ,@i(q)])}@\A fixed-parameter, second-order bandpass filter based on @code(snd-biquad). The center frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(notch2-sec) @codef{notch2(@pragma(defn)@index(notch2)@i(signal), @i(hz)[ ,@i(q)])}@\A fixed-parameter, second-order notch filter based on @code(snd-biquad). The center frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(allpass2-sec) @codef{allpass2(@pragma(defn)@index(allpass2)@i(signal), @i(hz)[ ,@i(q)])}@\A fixed-parameter, second-order allpass filter based on @code(snd-biquad). The frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(eq-lowshelf-sec) @codef{eq-lowshelf(@pragma(defn)@index(eq-lowshelf)@index(equalization)@i(signal), @i(hz), @i(gain)[ ,@i(slope)])}@\A fixed-parameter, second-order bass shelving equalization (EQ) filter based on @code(snd-biquad). The @i(hz) parameter (a @code(FLONUM))is the halfway point in the transition, and @i(gain) (a @code(FLONUM)) is the bass boost (or cut) in dB. The optional @i(slope) (a @code(FLONUM)) is 1.0 by default, and response becomes peaky at values greater than 1.0. @label(eq-highshelf-sec) @codef{eq-highshelf(@pragma(defn)@index(eq-highshelf)@index(equalization)@i(signal), @i(hz), @i(gain)[ ,@i(slope)])}@\A fixed-parameter, second-order treble shelving equalization (EQ) filter based on @code(snd-biquad). The @i(hz) parameter (a @code(FLONUM))is the halfway point in the transition, and @i(gain) (a @code(FLONUM)) is the treble boost (or cut) in dB. The optional @i(slope) (a @code(FLONUM)) is 1.0 by default, and response becomes peaky at values greater than 1.0. @label(eq-band-sec) @codef{eq-band(@pragma(defn)@index(eq-band)@index(equalization)@i(signal), @i(hz), @i(gain), @i(width))}@\A fixed- or variable-parameter, second-order midrange equalization (EQ) filter based on @code(snd-biquad), @code(snd-eqbandcv) and @code(snd-eqbandvvv). The @i(hz) parameter (a @code(FLONUM)) is the center frequency, @i(gain) (a @code(FLONUM)) is the boost (or cut) in dB, and @i(width) (a @code(FLONUM)) is the half-gain width in octaves. Alternatively, @i(hz), @i(gain), and @i(width) may be @code(SOUND)s, but they must all have the same sample rate, e.g. they should all run at the control rate or at the sample rate. @label(lowpass4-sec) @codef{lowpass4(@pragma(defn)@index(lowpass4)@i(signal), @i(hz))}@\A four-pole Butterworth lowpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(lowpass6-sec) @codef{lowpass6(@pragma(defn)@index(lowpass6)@i(signal), @i(hz))}@\A six-pole Butterworth lowpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(lowpass8-sec) @codef{lowpass8(@pragma(defn)@index(lowpass8)@i(signal), @i(hz))}@\An eight-pole Butterworth lowpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(highpass4-sec) @codef{highpass4(@pragma(defn)@index(highpass4)@i(signal), @i(hz))}@\A four-pole Butterworth highpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(highpass6-sec) @codef{highpass6(@pragma(defn)@index(highpass6)@i(signal), @i(hz))}@\A six-pole Butterworth highpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(highpass8-sec) @codef{highpass8(@pragma(defn)@index(highpass8)@i(signal), @i(hz))}@\An eight-pole Butterworth highpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(tapv-sec) @codef{tapv(@pragma(defn)@index(tapv)@index(variable delay)@index(tapped delay)@i(sound), @i(offset), @i(vardelay), @i(maxdelay))}@\A delay line with a variable position tap. Identical to @code(snd-tapv). See it for details (@ref(snd-tapv-sec)). @end(fndefs) @paragraph(Effects) @begin(fndefs) @label(stkrev-sec) @codef{nrev(@pragma(defn)@index(nrev)@index(reverb)@index(effect, reverberation)@index(STK nreverb)@i(sound), @i(decay), @i(mix))} @codef{jcrev(@pragma(defn)@index(jcrev)@index(reverb)@index(effect, reverberation)@index(STK jcreverb)@i(sound), @i(decay), @i(mix))} @codef{prcrev(@pragma(defn)@index(prcrev)@index(reverb)@index(effect, reverberation)@index(STK prcreverb)@i(sound), @i(decay), @i(mix))} These reverbs (@code(nrev), @code(jcrev), and @code(prcrev)) are implemented in STK (running within Nyquist). @code(nrev) derives from Common Music's NRev, which consists of 6 comb filters followed by 3 allpass filters, a lowpass filter, and another allpass in series followed by two allpass filters in parallel. @code(jcrev) is the John Chowning reverberator which is based on the use of networks of simple allpass and comb delay filters. This reverb implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. @code(prcrev) is a Perry Cook's reverberator which is based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This one implements two series allpass units and two parallel comb filters. The @i(sound) input may be single or multi-channel. The @i(decay) time is in seconds, and @i(mix) sets the mixture of input sound reverb sound, where 0.0 means input only (dry) and 1.0 means reverb only (wet). @label(stkchorus-sec) @codef{stkchorus(@pragma(defn)@index(stkchorus)@index(chorus)@index(effect, chorus)@index(STK chorus)@i(sound), @i(depth), @i(freq), @i(mix)[ ,@i(delay)])}@\Chorus implemented in STK. The input @i(sound) can be single or multi-channel. The @code(FLONUM) parameters @i(depth) and @i(freq) set the modulation depth from 0 to 1 and modulation frequency (in Hz), and @i(mix) sets the mixture of input sound and chorused sound, where 0.0 means input sound only (dry) and 1.0 means chorused sound only (wet). The parameter @i(delay) is a @code(FIXNUM) representing the median desired delay length in samples. @label(stkpitshift-sec) @codef{pitshift(@pragma(defn)@index(pitshift)@index(pitch shift)@index(effect, pitch shift)@index(STK pitch shift)@i(sound), @i(shift), @i(mix))}@\A pitch shifter implemented in STK. The input @i(sound), a single-channel or multi-channel @code(SOUND) is pitch-shifted by @i(shift), a @code(FLONUM) ratio. A value of 1.0 means no shift. The parameter @i(mix) sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). @end(fndefs) @paragraph(Physical Models) @begin(fndefs) @label(clarinet-sec) @codef{clarinet(@pragma(defn)@index(clarinet)@index(stk clarinet)@i(step), @i(breath-env))}@\A physical model of a clarinet from STK. The @i(step) parameter is a @code(FLONUM) that controls the tube length, and the @i(breath-env) (a @code(SOUND)) controls the air pressure and also determines the length of the resulting sound. The @i(breath-env) signal should range from zero to one. @codef{clarinet-freq(@index(clarinet)@pragma(defn)@index(clarinet-freq)@index(stk clarinet)@i(step), @i(breath-env), @i(freq-env))}@\A variation of @code(clarinet) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(breath-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into @code(SOUND)s with a nominal duration arbitrarily set to 30. @codef{clarinet-all(@index(clarinet)@pragma(defn)@index(clarinet-all)@index(stk clarinet)@i(step), @i(breath-env), @i(freq-env), @i(vibrato-freq), @i(vibrato-gain), @i(reed-stiffness), @i(noise))}@\A variation of @code(clarinet-freq) that includes controls @i(vibrato-freq) (a @code(FLONUM) for vibrato frequency in Hertz), @i(vibrato-gain) (a @code(FLONUM) for the amount of amplitude vibrato), @i(reed-stiffness) (a @code(FLONUM) or @code(SOUND) controlling reed stiffness in the clarinet model), and @i(noise) (a @code(FLONUM) or @code(SOUND) controlling noise amplitude in the input air pressure). The @i(vibrato-gain) is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the @i(noise) parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the @i(breath-env). The @i(reed-stiffness) parameter varies from zero to one. The duration of the resulting sound is the minimum duration of @i(breath-env), @i(freq-env), @i(reed-stiffness), and @i(noise). As with @code(clarinet-freq), these parameters may be either @code(FLONUM)s or @code(SOUND)s, and @code(FLONUM)s are coerced to sounds with a nominal duration of 30. @label(sax-sec) @codef{sax(@pragma(defn)@index(sax)@index(stk sax)@i(step), @i(breath-env))}@\A physical model of a sax from STK. The @i(step) parameter is a @code(FLONUM) that controls the tube length, and the @i(breath-env) controls the air pressure and also determines the length of the resulting sound. The @i(breath-env) signal should range from zero to one. @codef{sax-freq(@pragma(defn)@index(sax)@index(sax-freq)@index(stk sax)@i(step), @i(breath-env), @i(freq-env))}@\A variation of @code(sax) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(breath-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into @code(SOUND)s with a nominal duration arbitrarily set to 30. @codef{sax-all(@pragma(defn)@index(sax)@index(sax-all)@index(stk sax)@i(step), @i(breath-env), @i(freq-env), @i(vibrato-freq), @i(vibrato-gain), @i(reed-stiffness), @i(noise), @i(blow-pos), @i(reed-table-offset))}@\A variation of @code(sax-freq) that includes controls @i(vibrato-freq) (a @code(FLONUM) for vibrato frequency in Hertz), @i(vibrato-gain) (a @code(FLONUM) for the amount of amplitude vibrato), @i(reed-stiffness) (a @code(SOUND) controlling reed stiffness in the sax model), @i(noise) (a @code(SOUND) controlling noise amplitude in the input air pressure), @i(blow-pos) (a @code(SOUND) controlling the point of excitation of the air column), and @i(reed-table-offset) (a @code(SOUND) controlling a parameter of the reed model). The @i(vibrato-gain) is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the @i(noise) parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the @i(breath-env). The @i(reed-stiffness), @i(blow-pos), and @i(reed-table-offset) parameters all vary from zero to one. The duration of the resulting sound is the minimum duration of @i(breath-env), @i(freq-env), @i(reed-stiffness), @i(noise), @i(breath-env), @i(blow-pos), and @i(reed-table-offset). As with @code(sax-freq), these parameters may be either @code(FLONUM)s or @code(SOUND)s, and @code(FLONUM)s are coerced to sounds with a nominal duration of 30. @label(flute-sec) @codef{flute(@pragma(defn)@index(flute)@index(STK flute)@i(step), @i(breath-env))}@\A physical model of a flute from STK. The @i(step) parameter is a @code(FLONUM) that controls the tube length, and the @i(breath-env) controls the air pressure and also determines the starting time and length of the resulting sound. The @i(breath-env) signal should range from zero to one. @codef{flute-freq(@pragma(defn)@index(flute-freq)@index(STK flute)@i(step), @i(breath-env), @i(freq-env))}@\A variation of @code(flute) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(breath-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into SOUNDs with a nominal duration arbitrary set to 30. @codef{flute-all(@pragma(defn)@index(flute-all)@index(STK flute)@i(step), @i(breath-env), @i(freq-env), @i(vibrato-freq), @i(vibrato-gain), @i(jet-delay), @i(noise))}@\A variation of @code(clarinet-freq) that includes controls @i(vibrato-freq) (a @code(FLONUM) for vibrato frequency in Hz), @i(vibrato-gain) (a @code(FLONUM) for the amount of amplitude vibrato), @i(jet-delay) (a @code(FLONUM) or @code(SOUND) controlling jet delay in the flute model), and noise (a @code(FLONUM) or @code(SOUND) controlling noise amplitude in the input air pressure). The @i(vibrato-gain) is a number from zero to one where zero means no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the @i(noise) parameter ranges from zero to one, where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the @i(breath-env). The @i(jet-delay) is a ratio that controls a delay length from the flute model, and therefore it changes the pitch of the resulting sound. A value of 0.5 will maintain the pitch indicated by the step parameter. The duration of the resulting sound is the minimum duration of @i(breath-env), @i(freq-env), @i(jet-delay), and @i(noise). These parameters may be either @code(FLONUM)s or @code(SOUND)s, and @code(FLONUM)s are coerced to sounds with a nominal duration of 30. @label(bowed-sec) @codef{bowed(@pragma(defn)@index(bowed)@index(STK bowed string)@i(step), @i(bowpress-env))}@\A physical model of a bowed string instrument from STK. The @i(step) parameter is a @code(FLONUM) that controls the string length, and the @i(bowpress-env) controls the bow pressure and also determines the duration of the resulting sound. The @i(bowpress-env) signal should range from zero to one. @codef{bowed-freq(@pragma(defn)@index(bowed-freq)@index(STK bowed-freq)@i(step), @i(bowpress-env), @i(freq-env))}@\A variation of @code(bowed) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(bowpress-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into @code(SOUND)s with a nominal duration arbitrarily set to 30s. @label(mandolin-sec) @codef{mandolin(@pragma(defn)@index(mandolin)@index(STK mandolon)@i(step), @i(dur), &optional @i(detune))}@\A physical model of a plucked double-string instrument from STK. The @i(step) parameter is a @code(FLONUM) wich specifies the desired pitch, @i(dur) means the duration of the resulting sound and detune is a @code(FLONUM) that controls the relative detune of the two strings. A value of 1.0 means unison. The default value is 4.0. Note: @i(body-size) (see @code(snd-mandolin) does not seem to work correctly, so a default value is always used by @code(mandolin). @label(bandedwg-sec) @codef{wg-uniform-bar(@pragma(defn)@index(wg-uniform-bar)@index(STK uniform bar)@i(step), @i(bowpress-env))} @codef{wg-tuned-bar(@pragma(defn)@index(wg-tuned-bar)@index(STK tuned bar)@i(step), @i(bowpress-env))} @codef{wg-glass-harm(@pragma(defn)@index(wg-glass-harm)@index(STK glass harmonica)@i(step), @i(bowpress-env))} @codef{wg-tibetan-bowl(@pragma(defn)@index(wg-tibetan-bowl)@index(STK tibetan bowl)@i(step), @i(bowpress-env))}@\These sounds are presets for a Banded Wave Guide Percussion instrument implemented in STK. The parameter @i(step) is a @code(FLONUM) that controls the resultant pitch, and @i(bowpress-env) is a @code(SOUND) ranging from zero to one that controls a parameter of the model. In addition, @i(bowpress-env) determines the duration of the resulting sound. (Note: The @i(bowpress-env) does not seems influence the timbral quality of the resulting sound). @label(modalbar-sec) @codef{modalbar(@pragma(defn)@index(modalbar)@index(STK modal bar)@i(preset), @i(step), @i(dur))}@\A physical model of a struck bar instrument implemented in STK. The parameter @i(preset) is one of the symbols @code(MARIMBA), @code(VIBRAPHONE), @code(AGOGO), @code(WOOD1), @code(RESO), @code(WOOD2), @code(BEATS), @code(TWO-FIXED), or @code(CLUMP). The symbol must be quoted, e.g. for SAL syntax use @code[quote(marimba)], and for Lisp syntax use @code('marimba). The parameter @i(step) is a @code(FLONUM) that sets the pitch (in steps), and @i(dur) is the duration in seconds. @label(sitar-sec) @codef{sitar(@pragma(defn)@index(sitar)@index(STK sitar)@i(step), @i(dur))}@\A sitar physical model implemented in STK. The parameter @i(step) is a @code(FLONUM) that sets the pitch, and @i(dur) is the duration. @end(fndefs) @paragraph(More Behaviors) @begin(fndefs) @label(clip-sec) @codef{clip(@pragma(defn)@index(clip)@index(limit)@i(sound), @i(peak))}@\Hard limit @i(sound) to the given @i(peak), a positive number. The samples of @i(sound) are constrained between an upper value of @i(peak) and a lower value of @subtract()@i(peak). If @i(sound) is a number, @code(clip) will return @i(sound) limited by @i(peak). If @i(sound) is a multichannel sound, @code(clip) returns a multichannel sound where each channel is clipped. The result has the type, sample rate, starting time, etc. of @i(sound). @label(s-abs-sec) @codef{s-abs(@pragma(defn)@index(s-abs)@index(absolute value)@i(sound))}@\A generalized absolute value function. If @i(sound) is a @code(SOUND), compute the absolute value of each sample. If @i(sound) is a number, just compute the absolute value. If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-abs) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). @label(s-sqrt-sec) @codef{s-sqrt(@pragma(defn)@index(s-sqrt)@index(square root)@i(sound))}@\A generalized square root function. If @i(sound) is a @code(SOUND), compute the square root of each sample. If @i(sound) is a number, just compute the square root. If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-sqrt) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). In taking square roots, if an input sample is less than zero, the corresponding output sample is zero. This is done because the square root of a negative number is undefined. @label(s-exp-sec) @codef{s-exp(@pragma(defn)@index(s-exp)@index(exponential)@i(sound))}@\A generalized exponential function. If @i(sound) is a @code(SOUND), compute @i(e)@+(@i(x)) for each sample @i(x). If @i(sound) is a number @i(x), just compute @i(e)@+(@i(x)). If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-exp) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). @label(s-log-sec) @codef{s-log(@pragma(defn)@index(s-log)@index(logorithm)@index(natural log)@i(sound))}@\A generalized natural log function. If @i(sound) is a @code(SOUND), compute @i(ln)(@i(x)) for each sample @i(x). If @i(sound) is a number @i(x), just compute @i(ln)(@i(x)). If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-log) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). Note that the @i(ln) of 0 is undefined (some implementations return negative infinity), so use this function with care. @label(s-max-sec) @codef{s-max(@pragma(defn)@index(s-max)@index(maximum)@i(sound1), @i(sound2))}@\Compute the maximum of two functions, @i(sound1) and @i(sound2). This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of @i(sound1) and @i(sound2). The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of @i(sound1) and @i(sound2). Note, therefore, that the result value is zero except within the bounds of @i(both) input sounds. @codef{s-min(@pragma(defn)@index(s-min)@index(minimum)@i(sound1), @i(sound2))}@\Compute the minimum of two functions, @i(sound1) and @i(sound2). This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of @i(sound1) and @i(sound2). The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of @i(sound1) and @i(sound2). Note, therefore, that the result value is zero except within the bounds of @i(both) input sounds. @codef{osc-note(@pragma(defn)@index(osc-note)@i(pitch)[ ,@i(duration), @i(env), @i(loud), @i(table)])}@\Same as @code(osc), but @code(osc-note) multiplies the result by @i(env). The @i(env) may be a sound, or a list supplying (@i(t@-[1]) @i(t@-[2]) @i(t@-[4]) @i(l@-[1]) @i(l@-[2]) @i(l@-[3])). The result has a sample rate of @code(*sound-srate*). @label(quantize-sec) @codef{quantize(@pragma(defn)@index(quantize)@i(sound), @i(steps))}@\Quantizes @i(sound) as follows: @i(sound) is multiplied by @i(steps) and rounded to the nearest integer. The result is then divided by @i(steps). For example, if @i(steps) is 127, then a signal that ranges from -1 to +1 will be quantized to 255 levels (127 less than zero, 127 greater than zero, and zero itself). This would match the quantization Nyquist performs when writing a signal to an 8-bit audio file. The @i(sound) may be multi-channel. @codef{ramp(@pragma(defn)@index(ramp) [@i(duration)])}@\Returns a linear ramp from 0 to 1 over @i(duration) (default is 1). The function actually reaches 1 at @i(duration), and therefore has one extra sample, making the total duration be @i(duration) + 1/@code(*Control-srate*). See Figure @ref(ramp-fig) for more detail. Ramp is unaffected by the @code(sustain) transformation. The effect of time warping is to warp the starting and ending times only. The ramp itself is unwarped (linear). The sample rate is @code(*control-srate*). @label(rms-sec) @codef{rms(@pragma(defn)@index(rms)@i(sound)[ ,@i(rate), @i(window-size)])}@\Computes the RMS of @i(sound) using a square window of size @i(window-size). The result has a sample rate of @i(rate). The default value of @i(rate) is 100 Hz, and the default window size is 1/rate seconds (converted to samples). The @i(rate) is a @code(FLONUM) and @i(window-size) is a @code(FIXNUM). @end(fndefs) @begin(figure) @center(@graphic((height = 2.37 in, width = 4.5 in, magnify = 0.75, postscript = "rampfig.ps")) @html(

    ) @fillcaption[Ramps generated by @code(pwl) and @code(ramp) functions. The @code(pwl) version ramps toward the breakpoint (1, 1), but in order to ramp back to zero at breakpoint (1, 0), the function never reaches an amplitude of 1. If used at the beginning of a @code(seq) construct, the next sound will begin at time 1. The @code(ramp) version actually reaches breakpoint (1, 1); notice that it is one sample longer than the @code(pwl) version. If used in a sequence, the next sound after @code(ramp) would start at time 1 + @i(P), where @i(P) is the sample period.] @tag(ramp-fig) @end(figure) @begin(fndefs) @label(recip-sec) @codef{recip(@pragma(defn)@index(recip)@index(reciprocal)@index(division)@i(sound))}@\A generalized reciprocal function. If @i(sound) is a @code(SOUND), compute 1/@i(x) for each sample @i(x). If @i(sound) is a number @i(x), just compute 1/@i(x). If @i(sound) is a multichannel sound, return a multichannel sound with @code(recip) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). Note that the reciprocal of 0 is undefined (some implementations return infinity), so use this function with care on sounds. Division of sounds is accomplished by multiplying by the reciprocal. Again, be careful not to divide by zero. @codef{s-rest(@index(rest)@pragma(defn)@index(s-rest) [@i(duration)])}@\Create silence (zero samples) for the given @i(duration) at the sample rate @code(*sound-srate*). Default duration is 1.0 sec, and the sound is transformed in time according to @code[*warp*]. @p(Note:) @code(rest) is a Lisp function that is equivalent to @code(cdr). Be careful to use @code(s-rest) when you need a sound! @label(noise-sec) @codef{noise(@pragma(defn)@index(noise) [@i(duration)])}@\Generate noise with the given @i(duration). Duration (default is 1.0) is transformed according to @code[*warp*]. The sample rate is @code(*sound-srate*) and the amplitude is +/- @code(*loud*). @label(yin-sec) @codef{yin(@pragma(defn)@index(yin)@index(pitch detection)@index(fundamenal frequency estimation)@index(estimate frequency)@index(frequency analysis)@index(period estimation)@i(sound), @i(minstep), @i(maxstep), @i(stepsize))}@\Fundamental frequency estimation (pitch detection. Use the YIN algorithm to estimate the fundamental frequency of @i(sound), which must be a @code(SOUND). The @i(minstep), a @code(FLONUM), is the minimum frequency considered (in steps), @i(maxstep), a @code(FLONUM), is the maximum frequency considered (in steps), and @i(stepsize), a @code(FIXNUM), is the desired hop size. The result is a ``stereo'' signal, i.e. an array of two @code(SOUND)s, both at the same sample rate, which is approximately the sample rate of @i(sound) divided by @i(stepsize). The first @code(SOUND) consists of frequency estimates. The second sound consists of values that measure the confidence or reliability of the frequency estimate. A small value (less than 0.1) indicates fairly high confidence. A larger value indicates lower confidence. This number can also be thought of as a ratio of non-periodic power to periodic power. When the number is low, it means the signal is highly periodic at that point in time, so the period estimate will be reliable. Hint #1: See Alain de Cheveigne and Hideki Kawahara's article "YIN, a Fundamental Frequency Estimator for Speech and Music" in the Journal of the Acoustic Society of America, April 2002 for details on the yin algorithm. Hint #2: Typically, the @i(stepsize) should be at least the expected number of samples in one period so that the fundamental frequency estimates are calculated at a rate far below the sample rate of the signal. Frequency does not change rapidly and the yin algorithm is fairly slow. To optimize speed, you may want to use less than 44.1 kHz sample rates for input sounds. Yin uses interpolation to achieve potentially fractional-sample-accurate estimates, so higher sample rates do not necessarily help the algorithm and definitely slow it down. The computation time is O(@i(n)@+(2)) per estimate, where @i(n) is the number of samples in the longest period considered. Therefore, each increase of @i(minstep) by 12 (an octave) gives you a factor of 4 speedup, and each decrease of the sample rate of @i(sound) by a factor of two gives you another factor of 4 speedup. Finally, the number of estimates is inversely proportional to @i(stepsize). Hint #3: Use @code(snd-srate) (see Section @ref(snd-srate-sec)) to get the exact sample rate of the result, which will be the sample rate of @i(sound) divided by @i(stepsize). E.g. @code{(snd-srate (aref yin-output 0))}, where @code(yin-output) is a result returned by @code(yin), will be the sample rate of the estimates. @end(fndefs) @section(Transformations)@index(Transformations) @label(transformations-sec) These functions change the environment that is seen by other high-level functions. Note that these changes are usually relative to the current environment. There are also ``absolute'' versions of each transformation function, with the exception of @code(seq), @code(seqrep), @code(sim), and @code(simrep). The ``absolute'' versions (starting or ending with ``abs'') do not look at the current environment, but rather set an environment variable to a specific value. In this way, sections of code can be insulated from external transformations. @begin(fndefs) @codef{abs-env(@pragma(defn)@index(abs-env)@i(beh))}@\Compute @i(beh) in the default environment. This is useful for computing waveform tables and signals that are ``outside'' of time. For example, @code[(at 10.0 (abs-env (my-beh)))] is equivalent to @code[(abs-env (my-beh))] because @code(abs-env) forces the default environment. Or in SAL, we would say @code[abs-env(my-beh()) @@ 10] is equivalent to @code[abs-env(my-beh())]. @codef{at(@pragma(defn)@index(at)@i(time), @i(beh))}@\Evaluate @i(beh) with @code(*warp*@index(*warp*)) shifted by @i(time). In SAL, you can use the infix operator @code(@@) as in @code[@i(beh) @@ @i(time)]. To discover how the environment is shifting time, use @code[local-to-global(@i(time))]. Most commonly, you call @code[local-to-global(0)] to find when a sound created in the current environment will start, expressed in absolute (global) terms. This can be regarded as the ``current time.'' @codef{at-abs(@pragma(defn)@index(at-abs)@i(time), @i(beh))}@\Evaluate @i(beh) with @code(*warp*@index(*warp*)) shifted so that local time 0 maps to @i(time). In SAL, you can use the infix operator @code[@@@@] as in @code[@i(beh) @@@@ @i(time)]. @label(continuous-control-warp) @codef{continuous-control-warp(@pragma(defn)@index(continuous-control-warp)@i(beh))}@\Applies the current warp environment to the signal returned by @i(beh). The result has the default control sample rate @code(*control-srate*). Linear interpolation is currently used. Implementation: @i(beh) is first evaluated without any shifting, stretching, or warping. The result is functionally composed with the inverse of the environment's warp function. @label(continuous-sound-warp) @codef{continuous-sound-warp(@pragma(defn)@index(continuous-sound-warp)@i(beh))}@\Applies the current warp environment to the signal returned by @i(beh). The result has the default sound sample rate @code(*sound-srate*). Linear interpolation is currently used. See @code(continuous-control-warp) for implementation notes. @label(control-srate-abs-sec) @codef{control-srate-abs(@pragma(defn)@index(control-srate-abs)@i(srate), @i(beh))}@\Evaluate @i(beh) with @code(*control-srate*@index(*control-srate*)) set to sample rate @i(srate). @p(Note:) there is no ``relative'' version of this function. @codef{extract(@pragma(defn)@index(extract)@i(start), @i(stop), @i(beh))}@\Returns a sound which is the portion of @i(beh) between @i(start) and @i(stop). Note that this is done relative to the current @code(*warp*). The result is shifted to start according to @code(*warp*), so normally the result will start without a delay of @i(start). @codef{extract-abs(@pragma(defn)@index(extract-abs)@i(start), @i(stop), @i(beh))}@\Returns a sound which is the portion of @i(beh) between @i(start) and @i(stop), independent of the current @code(*warp*). The result is shifted to start according to @code(*warp*). @codef{loud(@pragma(defn)@index(loud)@i(volume), @i(beh))}@\Evaluates @i(beh) with @code(*loud*) incremented by @i(volume). (Recall that @code(*loud*) is in decibels, so increment is the proper operation.) @codef{loud-abs(@pragma(defn)@index(loud-abs)@i(volume), @i(beh))}@\Evaluates @i(beh) with @code(*loud*) set to @i(volume). @label(sound-srate-abs-sec) @codef{sound-srate-abs(@pragma(defn)@index(sound-srate-abs)@i(srate), @i(beh))}@\Evaluate @i(beh) with @code(*sound-srate*@index(*sound-srate*)) set to sample rate @i(srate). @p(Note:) there is no ``relative'' version of this function. @codef{stretch(@pragma(defn)@index(stretch)@i(factor), @i(beh))}@\Evaluates @i(beh) with @code(*warp*) scaled by @i(factor). The effect is to ``stretch'' the result of @i(beh) (under the current environment) by @i(factor). See Chapter @ref(warp-chap) for more information. Use @code[get-duration(@i(dur))] to get the nominal actual duration of a behavior that locally has a duration of @i(dur). Here, ``nominal'' means what would be expected if the behavior obeys the shift, stretch, and warp components of the environment. (Any behavior is free to deviate from the nominal timing. For example, a percussion sound might have a fixed duration independent of the stretch factor.) Also, ``actual'' means global or absolute time, and ``locally'' means within the environment where @code[get-duration] is called. @code[get-duration] works by mapping the current time (local time 0) using @code[local-to-global] to obtain an actual start time, and mapping @i(dur) to obtain an actual end time. The difference is returned. @codef{stretch-abs(@pragma(defn)@index(stretch-abs)@i(factor), @i(beh))}@\Evaluates @i(beh) with @code(*warp*) set to a linear time transformation where each unit of logical time maps to @i(factor) units of real time. The effect is to stretch the nominal behavior of @i(beh) (under the default global environment) by @i(factor). See Chapter @ref(warp-chap) for more information. @codef{sustain(@pragma(defn)@index(sustain)@index(legato)@index(overlap)@index(stacatto)@i(factor), @i(beh))}@\Evaluates @i(beh) with @code(*sustain*) scaled by @i(factor). The effect is to ``stretch'' the result of @i(beh) (under the current environment) by @i(factor); however, the logical stop times are not stretched. Therefore, the overall duration of a sequence is not changed, and sounds will tend to overlap if @code(*sustain*) is greater than one (legato) and be separated by silence if @code(*sustain*) is less than one. @codef{sustain-abs(@pragma(defn)@index(sustain-abs)@i(factor), @i(beh))}@\Evaluates @i(beh) with @code(*sustain*) set to @i(factor). (See @code(sustain), above.) @codef{transpose(@pragma(defn)@index(transpose)@i(amount), @i(beh))}@\Evaluates @i(beh) with @code(*transpose*) shifted by @i(amount). The effect is relative transposition by @i(amount) semitones. @codef{transpose-abs(@pragma(defn)@index(transpose-abs)@i(amount), @i(beh))}@\Evaluates @i(beh) with @code(*transpose*) set to @i(amount). The effect is the transposition of the nominal pitches in @i(beh) (under the default global environment) by @i(amount). @codef{warp(@pragma(defn)@index(warp)@i(fn), @i(beh))}@\Evaluates @i(beh) with @code(*warp*) modified by @i(fn). The idea is that @i(beh) and @i(fn) are written in the same time system, and @i(fn) warps that time system to local time. The current environment already contains a mapping from local time to global (real) time. The value of @code(*warp*) in effect when @i(beh) is evaluated is the functional composition of the initial @code(*warp*) with @i(fn). @codef{warp-abs(@pragma(defn)@index(warp-abs)@i(fn), @i(beh))}@\Evaluates @i(beh) with @code(*warp*) set to @i(fn). In other words, the current @code(*warp*) is ignored and not composed with @i(fn) to form the new @code(*warp*). @end(fndefs) @section(Combination and Time Structure)@index(Combination)@index(Time Structure) These behaviors combine component behaviors into structures, including sequences (melodies), simultaneous sounds (chords), and structures based on iteration. @begin(fndefs) @label(seq-sec) @codef{seq(@pragma(defn)@index(seq)@i(beh@-[1])[ ,@i(beh@-[2]), ...])}@\Evaluates the first behavior @i(beh@-[1]) according to @code(*time*) and each successive behavior at the @code(logical-stop) time of the previous one. The results are summed to form a sound whose @code(logical-stop) is the @code(logical-stop) of the last behavior in the sequence. Each behavior can result in a multichannel sound, in which case, the logical stop time is considered to be the maximum logical stop time of any channel. The number of channels in the result is the number of channels of the first behavior. If other behaviors return fewer channels, new channels are created containing constant zero signals until the required number of channels is obtained. If other behaviors return a simple sound rather than multichannel sounds, the sound is automatically assigned to the first channel of a multichannel sound that is then filled out with zero signals. If another behavior returns more channels than the first behavior, the error is reported and the computation is stopped. Sample rates are converted up or down to match the sample rate of the first sound in a sequence. @codef{seqrep(@pragma(defn)@index(seqrep)@i(var), @i(limit), @i(beh))}@\Iteratively evaluates @i(beh) with the atom @i(var) set with values from 0 to @i(limit)-1, inclusive. These sounds are placed sequentially in time as if by @code(seq). The symbol @i(var) is a @i(read-only) local variable to @i(beh). Assignments are not restricted or detected, but may cause a run-time error or crash. In LISP, the syntax is @code[(seqrep (@i(var) @i(limit)) @i(beh))]. @label(sim-sec) @codef{sim(@pragma(defn)@index(sim)[@i(beh@-[1]), @i(beh@-[2]), ...])}@\Returns a sound which is the sum of the given behaviors evaluated with current value of @code(*warp*). If behaviors return multiple channel sounds, the corresponding channels are added. If the number of channels does not match, the result has the maximum. For example, if a two-channel sound [L, R] is added to a four-channel sound [C1, C2, C3, C4], the result is [L + C1, R + C2, C3, C4]. Arguments to @code(sim) may also be numbers. If all arguments are numbers, @code(sim) is equivalent (although slower than) the @code(+) function. If a number is added to a sound, @code(snd-offset) is used to add the number to each sample of the sound. The result of adding a number to two or more sounds with different durations is not defined. Use @code(const) to coerce a number to a sound of a specified duration. An important limitation of @code(sim) is that it cannot handle hundreds of behaviors due to a stack size limitation in XLISP. To compute hundreds of sounds (e.g. notes) at specified times, see @code(timed-seq), below. See also @code(sum) below. @codef{simrep(@pragma(defn)@index(simrep)@i(var), @i(limit), @i(beh))}@\Iteratively evaluates @i(beh) with the atom @i(var) set with values from 0 to @i(limit)-1, inclusive. These sounds are then placed simultaneously in time as if by @code(sim). In LISP, the syntax is @code[(seqrep (@i(var) @i(limit)) @i(beh))]. @label(trigger-sec) @codef[trigger(@pragma(defn)@index(trigger)@i(s), @i(beh))]@\Returns a sound which is the sum of instances of the behavior @i(beh). One instance is created each time @code(SOUND) @i(s) makes a transition from less than or equal to zero to greater than zero. (If the first sample of @i(s) is greater than zero, an instance is created immediately.) The sample rate of @i(s) and all behaviors must be the same, and the behaviors must be (monophonic) @code(SOUND)s. This function is particularly designed to allow behaviors to be invoked in real time by making @i(s) a function of a Nyquist slider, which can be controlled by a graphical interface or by OSC messages. See @code(snd-slider) in Section @ref(snd-slider-sec). @codef[set-logical-stop(@pragma(defn)@index(set-logical-stop)@i(beh), @i(time))]@\Returns a sound with @i(time) as the logical stop time. @codef{sum(@pragma(defn)@index(sum)@index(mix)@i(a)[ ,@i(b), @i(c), ...])}@\Returns the sum of @i(a), @i(b), @i(c), ..., allowing mixed addition of sounds, multichannel sounds and numbers. Identical to @i(sim). @codef{mult(@pragma(defn)@index(mult)@index(product)@index(multiply signals)@i(a)[ ,@i(b), @i(c), ...])}@\Returns the product of @i(a), @i(b), @i(c), ..., allowing mixed multiplication of sounds, multichannel sounds and numbers. @codef{diff(@pragma(defn)@index(diff)@index(difference of sounds)@i(a), @i(b))}@\Returns the difference between @i(a) and @i(b). This function is defined as @code[(sum a (prod -1 b))]. @label(timed-seq-sec) @codef{timed-seq(@pragma(defn)@index(timed-seq)@index(score)@index(note list)@i(score))}@\Computes sounds from a note list or ``score.'' The @i(score) is of the form: @code[`((@i(time1) @i(stretch1) @i(beh1)) (@i(time2) @i(stretch2) @i(beh2)) ...)], where @i(timeN) is the starting time, @i(stretchN) is the stretch factor, and @i(behN) is the behavior. Note that @i(score) is normally a @i(quoted list)! The times must be in increasing order, and each @i(behN) is evaluated using lisp's @code(eval), so the @i(behN) behaviors cannot refer to local parameters or local variables. The advantage of this form over @code(seq) is that the behaviors are evaluated one-at-a-time which can take much less stack space and overall memory. One special ``behavior'' expression is interpreted directly by @code(timed-seq): @code[(SCORE-BEGIN-END)] is ignored, not evaluated as a function. Normally, this special behavior is placed at time 0 and has two parameters: the score start time and the score end time. These are used in Xmusic functions. If the behavior has a @code(:pitch) keyword parameter which is a list, the list represents a chord, and the expression is replaced by a set of behaviors, one for each note in the chord. It follows that if @code(:pitch) is @code(nil), the behavior represents a rest and is ignored. @end(fndefs) @section(Sound File Input and Output) @index(sound file I/O) @begin(fndefs) @label(play-sec) @codef[play @pragma(defn)@index(play)@i(sound)]@\Play the sound through the DAC. Note that @code(play) is a command in SAL. In XLISP, it is a function, so the syntax is @code[(play @i(sound))], and in SAL, you can call the XLISP function as @code[#play(@i(sound))]. The @code(play) command or function writes a file and plays it. The details of this are system-dependent, but @code(play) is defined in the file @code(system.lsp). The variable @code(*default-sf-dir*)@index(sound file directory default)@index(directory, default sound file)@index(default sound file directory)@index(temporary sound files directory) @index(*default-sf-dir*) names a directory into which to save a sound file. Be careful not to call @code(play) or @code(sound-play) within a function and then invoke that function from another @code(play) command. By default, Nyquist will try to normalize sounds using the method named by @code(*autonorm-type*), which is @code('lookahead) by default. The @i(lookahead) method precomputes and buffers @code(*autonorm-max-samples*) samples, finds the peak value, and normalizes accordingly. The @code('previous) method bases the normalization of the current sound on the peak value of the (entire) previous sound. This might be good if you are working with long sounds that start rather softly. See Section @ref(peak-ex-sec) for more details. If you want precise control over output levels, you should turn this feature off by typing: @begin(example) autonorm-off()@index(autonorm-off) @end(example) Reenable the automatic normalization feature by typing: @begin(example)@index(autonorm-on) autonorm-on() @end(example) Play normally produces real-time output. The default is to send audio data to the DAC as it is computed in addition to saving samples in a file. If computation is slower than real-time, output will be choppy, but since the samples end up in a file, you can type @code[(r)] to replay the stored sound. Real-time playback can be disabled by: @begin(example) sound-off()@index(sound-off) @end(example) and reenabled by: @begin(example) sound-on()@index(sound-on) @end(example) Disabling real-time playback has no effect on @code[(play-file)] or @code[(r)]. While sounds are playing, typing control-A@index(control-A) to Nyquist will push the estimated elapsed@index(elapsed audio time) audio time onto the head of the list stored in @code(*audio-markers*). @index(*audio-markers*)@index(audio markers)@index(markers, audio) Because samples are computed in blocks and because there is latency between sample computation and sample playback, the elapsed time may not be too accurate, and the computed elapsed time may not advance after all samples have been computed but the sound is still playing. @codef[play-file(@pragma(defn)@index(play-file)@i(filename))]@\Play the contents of a sound file named by @i(filename). The @code(s-read) function is used to read the file, and unless @i(filename) specifies an absolute path or starts with ``.'', it will be read from @code(*default-sf-dir*). @codef[autonorm-on(@pragma(defn)@index(autonorm-on))]@\Enable automatic adjustment of a scale factor applied to sounds computed using the @code(play) command. @codef[autonorm-off(@pragma(defn)@index(autonorm-off))]@\Disable automatic adjustment of a scale factor applied to sounds computed using the @code(play) command. @codef[sound-on(@pragma(defn)@index(sound-on))]@\Enable real-time audio output when sound is computed by the the @code(play) command. @codef[sound-off(@pragma(defn)@index(sound-off))]@\Disable real-time audio output when sound is computed by the the @code(play) command. @label(s-save-sec) @codef{s-save(@pragma(defn)@index(s-save)@index(save samples to file)@index(write samples to file)@index(output samples to file)@i(expression), @i(maxlen), @i(filename)[ ,format: @i(format)] [, mode: @i(mode)] [, bits: @i(bits)] [, swap: @i(flag)] [, play: @i(play)])}@\@label(s-save)Evaluates the @i(expression), which should result in a sound or an array of sounds, and writes the result to the given @i(filename). A @code(FLONUM) is returned giving the maximum absolute value of all samples written. (This is useful for normalizing sounds and detecting sample overflow.) If @i(play) is not @code(NIL), the sound will be output through the computer's audio output system. (@i(:play) is not implemented on all systems; if it is implemented, and @i(filename) is @code(NIL), then this will play the file without also writing a file.) The latency (length of audio buffering) used to play the sound is 0.3s by default, but see @code(snd-set-latency). If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. A header is written according to @i(format), samples are encoded according to @i(mode), using @i(bits) bits/sample, and bytes are swapped if @i(swap) is not NIL. Defaults for these are @code(*default-sf-format*), @code(*default-sf-mode*), and @code(*default-sf-bits*). The default for @i(swap) is NIL. The @i(bits) parameter may be 8, 16, or 32. The values for the @i(format) and @i(mode) options are described below: @end(fndefs) @b(Format) @begin(description, leftmargin +2 in, indent -2 in) @code(snd-head-none)@\The format is unknown and should be determined by reading the file. @code(snd-head-raw)@\A raw format file has no header. @code(snd-head-AIFF)@\AIFF format header. @code(snd-head-IRCAM)@\IRCAM format header. @code(snd-head-NeXT)@\1024-byte NeXT/SUN format header followed by IRCAM header ala CMIX. Note that the NeXT/SUN format has a header-length field, so it really is legal to have a large header, even though the normal minimal header is only 24 bytes. The additional space leaves room for maximum amplitudes, which can be used for normalizing floating-point soundfiles, and for other data. Nyquist follows the CMIX convention of placing an IRCAM format header immediately after the NeXT-style header. @code(snd-head-Wave)@\Microsoft Wave format header. @code(snd-head-*)@\See sndfnint.lsp for more formats. @end(description) @b(Mode) @begin(description, leftmargin +2 in, indent -2 in) @code(snd-mode-adpcm)@\ADPCM mode (not supported). @code(snd-mode-pcm)@\signed binary PCM mode. @code(snd-mode-ulaw)@\8-bit U-Law mode. @code(snd-mode-alaw)@\8-bit A-Law mode (not supported). @code(snd-mode-float)@\32-bit floating point mode. @code(snd-mode-upcm)@\unsigned binary PCM mode. @code(snd-mode-*)@\See sndfnint.lsp for more modes. @end(description) The defaults for format, mode, and bits are as follows: @begin(description, leftmargin +2 in, indent -2 in) NeXT and Sun machines:@\@code(snd-head-NeXT), @code(snd-mode-pcm), @code(16) SGI and Macintosh machines:@\@code(snd-head-AIFF), @code(snd-mode-pcm), @code(16) @end(description) @begin(fndefs) @label(s-read-sec) @codef{s-read(@pragma(defn)@index(s-read)@index(read samples from file)@i(filename)[ ,time-offset: @i(offset)] [, srate: @i(sr)] [, dur: @i(dur)] [, nchans: @i(chans)] [, format: @i(format)] [, mode: @i(mode),] [bits: @i(n)] [, swap: @i(flag)])}@\Reads a sound from @i(filename). The global @code(*default-sf-dir*) applies. If a header is detected, the header is used to determine the format of the file, and header information overrides format information provided by keywords (except for @code(:time-offset) and @code(:dur)). @begin(example) s-read("mysound.snd", srate: 44100) @end(example) specifies a sample rate of 44100 hz, but if the file has a header specifying 22050 hz, the resulting sample rate will be 22050. The parameters are: @begin(itemize) @code(:time-offset) @itemsep the amount of time (in seconds) to skip from the beginning of the file. The default is 0.0. @code(:srate) @itemsep the sample rate of the samples in the file. Default is @code(*default-sf-srate*) @index(*default-sf-srate*), which is normally 44100. @code(:dur) @itemsep the maximum duration in seconds to read. Default is 10000. @code(:nchans) @itemsep the number of channels to read. It is assumed that samples from each channel are interleaved. Default is 1. @code(:format) @itemsep the header format. See @code(s-save) for details. Default is @code(*default-sf-format*), although this parameter is currently ignored. @code(:mode) @itemsep the sample representation, e.g. PCM or float. See @code(s-save) for details. Default is @code(*default-sf-format*). @code(:bits) @itemsep the number of bits per sample. See @code(s-save) for details. Default is @code(*default-sf-bits*). @code(:swap) @itemsep (T or NIL) swap byte order of each sample. Default is NIL. @end(itemize) If there is an error, for example if @code(:time-offset) is greater than the length of the file, then @code(NIL) is returned rather than a sound. Information about the sound is also returned by @code(s-read) through @code(*rslt*)@foot(Since XLISP does not support multiple value returns, multiple value returns are simulated by having the function assign additional return values in a list to the global variable @code(*rslt*). Since this is a global, it should be inspected or copied immediately after the function return to insure that return values are not overwritten by another function.). The list assigned to @code(*rslt*) is of the form: (@i(format) @i(channels) @i(mode) @i(bits) @i(samplerate) @i(duration) @i(flags) @i(byte-offset)), which are defined as follows: @begin(itemize) @i(format) @itemsep the header format. See @code(s-save) for details. @i(channels) @itemsep the number of channels. @i(mode) @itemsep the sample representation, e.g. PCM or float. See @code(s-save) for details. @i(bits) @itemsep the number of bits per sample. @i(samplerate) @itemsep the sample rate, expressed as a @code(FLONUM). @i(duration) @itemsep the duration of the sound, in seconds. @i(flags) @itemsep The values for @i(format), @i(channels), @i(mode), @i(bits), @i(samplerate), and @i(duration) are initially just the values passed in as parameters or default values to @code(s-read). If a value is actually read from the sound file header, a flag is set. The flags are: @code(snd-head-format), @code(snd-head-channels), @code(snd-head-mode), @code(snd-head-bits), @code(snd-head-srate), and @code(snd-head-dur). For example, @begin(example) (let ((flags (caddr (cddddr *rslt*)))) (not (zerop (logand flags snd-head-srate)))) @end(example) tells whether the sample rate was specified in the file. See also @code(sf-info) below. @i(byte-offset) @itemsep the byte offset into the file of the first sample to be read (this is used by the @code(s-overwrite) and @code(s-add-to) functions). @end(itemize) @codef{s-add-to(@pragma(defn)@index(s-add-to)@index(add to file samples)@index(mix to file)@i(expression), @i(maxlen), @i(filename)[ ,@i(offset)])}@\@label(s-add-to-sec)Evaluates the @i(expression), which should result in a sound or an array of sounds, and adds the result to the given @i(filename). The global @code(*default-sf-dir*) applies. A @code(FLONUM) is returned, giving the maximum absolute value of all samples written. The sample rate(s) of @i(expression) must match those of the file. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. If @i(offset) is specified, the new sound is added to the file beginning at an @i(offset) from the beginning (in seconds). The file is extended if necessary to accommodate the new addition, but if @i(offset) falls outside of the original file, the file is not modified. (If necessary, use @code(s-add-to) to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file). @codef{s-overwrite(@pragma(defn)@index(s-overwrite)@index(replace file samples)@index(overwrite samples)@i(expression), @i(maxlen), @i(filename)[ ,@i(offset)])}@\@label(s-overwrite-sec)Evaluates the @i(expression), which should result in a sound or an array of sounds, and replaces samples in the given @i(filename). The global @code(*default-sf-dir*) applies. A @code(FLONUM) is returned, giving the maximum absolute value of all samples written. The sample rate(s) of @i(expression) must match those of the file. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. If @i(offset) is specified, the new sound is written to the file beginning at an @i(offset) from the beginning (in seconds). The file is extended if necessary to accommodate the new insert, but if @i(offset) falls outside of the original file, the file is not modified. (If necessary, use @code(s-add-to) to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file). @codef{sf-info(@pragma(defn)@index(sf-info)@index(sound file info)@i(filename))}@\Prints information about a sound file. The parameter @i(filename) is a string. The file is assumed to be in *default-sf-dir* (see @code(soundfilename) below) unless the filename begins with ``.'' or ``/''. The source for this function is in the @code(runtime) and provides an example of how to determine sound file parameters. @codef{soundfilename(@pragma(defn)@index(soundfilename)@i(name))}@\Converts a string @i(name) to a soundfile name. If @i(name) begins with ``.'' or ``/'', the name is returned without alteration. Otherwise, a path taken from @code(*default-sf-dir*) is prepended to @i(name). The @code(s-plot), @code(s-read), and @code(s-save) functions all use @code(soundfilename) translate filenames. @codef{s-plot(@pragma(defn)@index(s-plot)@i(sound)[, @i(n), @i(dur)])}@\Plots sound in a window. This function was designed to run a @code(plot) program on a Unix workstation, but now is primarily used with @code(jNyqIDE), which has self-contained plotting. Normally, time/value pairs in ascii are written to @code(points.dat) and system-dependent code (or the @code(jNyqIDE) program) takes it from there. If the @i(sound) is longer than the optional @i(dur) (default is 2 seconds), only the first @i(dur) seconds are plotted. If there are more than @i(n) samples to be plotted, the signal is interpolated to have @i(n) samples before plotting. The data file used is: @begin(description, leftmargin +2 in, indent -2 in) @codef(*default-plot-file*)@pragma(defn)@index(*default-plot-file*)@\The file containing the data points, defaults to "points.dat". @end(description) @codef{s-print-tree(@pragma(defn)@index(s-print-tree)@index(snd-print-tree)@i(sound))}@\Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging@index(debugging) Nyquist. Identical to @code(snd-print-tree). @end(fndefs) @section(Low-level Functions) Nyquist includes many low-level functions that are used to implement the functions and behaviors described in previous sections. For completeness, these functions are described here. Remember that these are low-level functions that are not intended for normal use. Unless you are trying to understand the inner workings of Nyquist, you can skip this section. @subsection(Creating Sounds) The basic operations that create sounds are described here. @begin(fndefs) @codef[snd-const(@pragma(defn)@index(snd-const)@i(value), @i(t0), @i(srate), @i(duration))]@\Returns a sound with constant @i(value), starting at @i(t0) with the given @i(duration), at the sample rate @i(srate). You might want to use @code(pwl) (see Section @ref(pwl-sec)) instead. @codef[snd-read(@pragma(defn)@index(snd-read)@i(filename), @i(offset), @i(t0), @i(format), @i(channels), @i(mode), @i(bits), @i(swap), @i(sr), @i(dur))]@\Loads a sound from a file with name @i(filename). Files are assumed to consist of a header followed by frames consisting of one sample from each channel. The @i(format) specifies the type of header, but this information is currently ignored. Nyquist looks for a number of header formats and automatically figures out which format to read. If a header can be identified, the header is first read from the file. Then, the file pointer is advanced by the indicated @i(offset) (in seconds). If there is an unrecognized header, Nyquist will assume the file has no header. If the header size is a multiple of the frame size (bytes/sample * number-of-channels), you can use @i(offset) to skip over the header. To skip N bytes, use an @i(offset) of: @begin(example) (/ (float N) @i(sr) (/ @i(bits) 8) @i(channels)) @end(example) If the header is not a multiple of the frame size, either write a header or contact the author (dannenberg@@cs.cmu.edu) for assistance. Nyquist will round @i(offset) to the nearest sample. The resulting sound will start at time @i(t0). If a header is found, the file will be interpreted according to the header information. If no header was found, @i(channels) tells how many channels there are, the samples are encoded according to @i(mode), the sample length is @i(bits), and @i(sr) is the sample rate. The @i(swap) flag is 0 or 1, where 1 means to swap sample bytes. The duration to be read (in seconds) is given by @i(dur). If @i(dur) is longer than the data in the file, then a shorter duration will be returned. If the file contains one channel, a sound is returned. If the file contains 2 or more channels, an array of sounds is returned. @p(Note:) you probably want to call @code(s-read) (see Section @ref(s-read-sec)) instead of @code(snd-read). Also, see Section @ref(s-read-sec) for information on the @i(mode) and @i(format) parameters. @codef[snd-save(@pragma(defn)@index(snd-save)@i(expression), @i(maxlen), @i(filename), @i(format), @i(mode), @i(bits), @i(swap), @i(play))]@\@label(snd-save)Evaluates the @i(expression), which should result in a sound or an array of sounds, and writes the result to the given @i(filename). If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. A header is written according to @i(format), samples are encoded according to @i(mode), using @i(bits) bits/sample, and swapping bytes if @i(swap) is 1 (otherwise it should be 0). If @i(play) is not null, the audio is played in real time (to the extent possible) as it is computed. The peak value of the sound is returned. In addition, the symbol @code(*RSLT*) is bound to a list containing the sample rate, number of channels, and duration (in that order) of the saved sound. @p(Note:) you probably want to call @code(s-save) (see Section @ref(s-save-sec)) instead. The @i(format) and @i(mode) parameters are described in Section @ref(s-save-sec). @codef[snd-overwrite(@pragma(defn)@index(snd-overwrite)@i(expression), @i(maxlen), @i(filename), @i(offset), @i(format), @i(mode), @i(bits), @i(swap))]@\@label(snd-overwrite-sec)Evaluates the @i(expression), which should result in a sound or an array of sounds, and replaces samples in the given @i(filename), writing the first frame at a time of @i(offset) seconds. The @i(offset) must be less than or equal to the duration of the existing file. The duration of the written samples may be greater than that of the file, in which case the file is extended as necessary. The sample rate(s) of @i(expression) and the number of channels must match those of the file. If @i(format) is @code(SND-HEAD-RAW), then the file format is given by @i(mode) (see @code(snd-save), @i(bits) (per channel), @i(swap) (1 means to swap bytes and 0 means write them in the native byte order), and the number of channels and sample rate of the sound returned by evaluating @i(expression). If the file is a known audio file format, @i(format) should be @code(SND-HEAD-NONE), and the other parameters are ignored. Up to a maximum of @i(maxlen) samples will be written per channel. The peak value of the sound is returned. In addition, the symbol @code(*RSLT*) is bound to a list containing the duration of the written sound (which may not be the duration of the sound file). Use @code(s-add-to) (in Section @ref(s-add-to-sec) or @code(s-overwrite) (in Section @ref(s-overwrite-sec) instead of this function. @codef[snd-coterm(@pragma(defn)@index(snd-coterm)@index(co-termination)@index(duration of another sound)@i(s1), @i(s2))]@\Returns a copy of @i(s1), except the start time is the maximum of the start times of @i(s1) and @i(s2), and the termination time is the minimum of @i(s1) and @i(s2). (After the termination time, the sound is zero as if @i(s1) is gated by @i(s2).) Some rationale follows: In order to implement @code(s-add-to), we need to read from the target sound file, add the sounds to a new sound, and overwrite the result back into the file. We only want to write as many samples into the file as there are samples in the new sound. However, if we are adding in samples read from the file, the result of a @code(snd-add) in Nyquist will have the maximum duration of either sound. Therefore, we may read to the end of the file. What we need is a way to truncate the read, but we cannot easily do that, because we do not know in advance how long the new sound will be. The solution is to use @code(snd-coterm), which will allow us to truncate the sound that is read from the file (@i(s1)) according to the duration of the new sound (@i(s2)). When this truncated sound is added to the new sound, the result will have only the duration of the new sound, and this can be used to overwrite the file. This function is used in the implementation of @code(s-add-to), which is defined in @code(runtime/fileio.lsp). @codef[(snd-from-array @i(...))]@\See @pragma(startref) page @pageref(snd-from-array-sec). @codef[snd-white(@pragma(defn)@index(snd-white)@i(t0), @i(sr), @i(d))]@\Generate white noise, starting at @i(t0), with sample rate @i(sr), and duration @i(d). You probably want to use @code(noise) (see Section @ref(noise-sec)). @codef[snd-zero(@pragma(defn)@index(snd-zero)@i(t0), @i(srate))]@\Creates a sound that is zero everywhere, starts at @i(t0), and has sample rate @i(srate). The logical stop time is immediate, i.e. also at @i(t0). You probably want to use @code(pwl) (see Section @ref(pwl-sec)) instead. @codef[get-slider-value(@pragma(defn)@index(get-slider-value)@i(index))]@\@label(get-slider-value-sec)Return the current value of the slider named by @i(index) (an integer index into the array of sliders). Note that this ``slider'' is just a floating point value in an array. Sliders can be changed by OSC messages (see @code(osc-enable)) and by sending character sequences to Nyquist's standard input. (Normally, these character sequences would not be typed but generated by the jNyqIDE interactive development environment, which runs Nyquist as a sub-process, and which present the user with graphical sliders.) @codef[snd-slider(@pragma(defn)@index(snd-slider)@i(index), @i(t0), @i(srate), @i(duration))]@\@label(snd-slider-sec)Create a sound controlled by the slider named by @i(index) (an integer index into the array of sliders; see @code(get-slider-value) for more information). The function returns a sound. Since Nyquist sounds are computed in blocks of samples, and each block is computed at once, each block will contain copies of the current slider value. To obtain reasonable responsiveness, slider sounds should have high (audio) sample rates so that the block rate will be reasonably high. Also, consider lowering the audio latency using @code(snd-set-latency). To ``trigger'' a Nyquist behavior using slider input, see the @code(trigger) function in Section @ref(trigger-sec). @end(fndefs) @subsection(Signal Operations) This next set of functions take sounds as arguments, operate on them, and return a sound. @begin(fndefs) @codef[snd-abs(@pragma(defn)@index(snd-abs)@index(absolute value)@i(sound))]@\Computes a new sound where each sample is the absolute value of the corresponding sample in @i(sound). You should probably use @code(s-abs) instead. (See Section @ref(s-abs-sec).) @codef[snd-sqrt(@pragma(defn)@index(snd-sqrt)@index(square root)@i(sound))]@\Computes a new sound where each sample is the square root of the corresponding sample in @i(sound). If a sample is negative, it is taken to be zero to avoid raising a floating point error. You should probably use @code(s-sqrt) instead. (See Section @ref(s-sqrt-sec).) @codef[snd-add(@pragma(defn)@index(snd-add)@i(sound1), @i(sound))]@\Adds two sounds. The resulting start time is the minimum of the two parameter start times, the logical stop time is the maximum of the two parameter stop times, and the sample rate is the maximum of the two parameter sample rates. Use @code(sim) or @code(sum) instead of @code(snd-add) (see Section @ref(sim-sec)). @codef[snd-offset(@pragma(defn)@index(snd-offset)@index(offset to a sound)@index(add offset to sound)@i(sound), @i(offset))]@\Add an offset to a sound. The resulting start time, logical stop time, stop time, and sample rate are those of @i(sound). Use @code(sum) instead (see Section @ref(sim-sec)). @codef[snd-avg(@pragma(defn)@index(snd-avg)@index(moving average)@index(RMS)@index(average)@i(sound), @i(blocksize), @i(stepsize), @i(operation))]@\Computes the averages or peak values of blocks of samples. Each output sample is an average or peak of @i(blocksize) (a fixnum) adjacent samples from the input @i(sound). After each average or peak is taken, the input is advanced by @i(stepsize), a fixnum which may be greater or less than @i(blocksize). The output sample rate is the @i(sound) (input) sample rate divided by @i(stepsize). This function is useful for computing low-sample-rate rms or peak amplitude signals for input to @code(snd-gate) or @code(snd-follow). To select the operation, @i(operation) should be one of @code(OP-AVERAGE) or @code(OP-PEAK). (These are global lisp variables; the actual @i(operation) parameter is an integer.) For RMS computation, see @code(rms) in Section @ref(rms-sec). @codef[snd-clip(@index(clip)@pragma(defn)@index(snd-clip)@i(sound), @i(peak))]@\Hard limit @i(sound) to the given @i(peak), a positive number. The samples of @i(sound) are constrained between an upper value of @i(peak) and a lower value of @subtract()@i(peak). Use @code(clip) instead (see Section @ref(clip-sec)). @codef[snd-compose(@index(compose)@index(signal composition)@pragma(defn)@index(snd-compose)@i(f), @i(g))]@\Compose two signals, i.e. compute @i(f)(@i(g)(@i(t))), where @i(f) and @i(g) are sounds. This function is used primarily to implement time warping, but it can be used in other applications such as frequency modulation. For each sample @i(x) in @i(g), @i(snd-compose) looks up the value of @i(f)(@i(x)) using linear interpolation. The resulting sample rate, start time, etc. are taken from @i(g). The sound @i(f) is used in effect as a lookup table, but it is assumed that @i(g) is non-decreasing, so that @i(f) is accessed in time order. This allows samples of @i(f) to be computed and discarded incrementally. If in fact @i(g) decreases, the current sample of @i(g) is replaced by the previous one, forcing @i(g) into compliance with the non-decreasing restriction. See also @code(sref), @code(shape), and @code(snd-resample). For an extended example that uses @code(snd-compose) for variable pitch shifting, see @code(demos/pitch_change.htm).@index(demos, pitch change)@index(pitch shifting) @index(variable-resample function)@index(resampling) @label(snd-tapv-sec) @codef[snd-tapv(@pragma(defn)@index(snd-tapv)@index(tap)@index(variable delay)@index(delay, variable)@index(chorus)@i(sound), @i(offset), @i(vardelay), @i(maxdelay))]@\A variable delay: @i(sound) is delayed by the sum of @i(offset) (a @code(FIXNUM) or @code(FLONUM)) and @i(vardelay) (a @code(SOUND)). The specified delay is adjusted to lie in the range of zero to @i(maxdelay) seconds to yield the actual delay, and the delay is implemented using linear interpolation. This function was designed specifically for use in a chorus effect: the @i(offset) is set to half of @i(maxdelay), and the @i(vardelay) input is a slow sinusoid. The maximum delay is limited to @i(maxdelay), which determines the length of a fixed-sized buffer. The function @code(tapv) is equivalent and preferred (see Section @ref(tapv-sec)). @codef[snd-tapf(@pragma(defn)@index(snd-tapf)@index(variable delay)@index(delay, variable)@i(sound), @i(offset), @i(vardelay), @i(maxdelay))]@\A variable delay like @code(snd-tapv) except there is no linear interpolation. By eliminating interpolation, the output is an exact copy of the input with no filtering or distortion. On the other hand, delays jump by samples causing samples to double or skip even when the delay is changed smoothly. @codef[snd-copy(@pragma(defn)@index(snd-copy)@i(sound))]@\Makes a copy of @i(sound). Since operators always make (logical) copies of their sound parameters, this function should never be needed. This function is here for debugging@index(dubugging). @codef[snd-down(@pragma(defn)@index(snd-down)@i(srate), @i(sound))]@\Linear interpolation of samples down to the given sample rate @i(srate), which must be lower than the sample rate of @i(sound). Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call @code(force-srate) (see Section @ref(force-srate-sec)). @codef[snd-exp(@pragma(defn)@index(snd-exp)@i(sound))]@\Compute the exponential of each sample of @i(sound). Use @code(s-exp) instead (see Section @ref(s-exp-sec)). @label(snd-follow-sec) @codef[snd-follow(@pragma(defn)@index(snd-follow)@index(follower)@index(envelope follower)@i(sound), @i(floor), @i(risetime), @i(falltime), @i(lookahead))]@\An envelope follower. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The @i(floor) is the minimum output value. The @i(risetime) is the time (in seconds) it takes for the output to rise (exponentially) from @i(floor) to unity (1.0) and the @i(falltime) is the time it takes for the output to fall (exponentially) from unity to @i(floor). The algorithm looks ahead for peaks and will begin to increase the output signal according to @i(risetime) in anticipation of a peak. The amount of anticipation (in sampless) is given by @i(lookahead). The algorithm is as follows: the output value is allowed to increase according to @i(risetime) or decrease according to @i(falltime). If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to @i(risetime) to meet the new value. The algorithm will only work backward as far as @i(lookahead). If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by @i(falltime), the output fall rate will be limited by @i(falltime), and the fall in output will stop when the output reaches @i(floor). This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See @code(snd-avg) above for a function that can help to generate a low-sample-rate input for @code(snd-follow). See @code(snd-chase) in Section @ref(snd-chase-sec) for a related filter. @codef[snd-gate(@pragma(defn)@index(snd-gate)@index(noise gate)@index(gate)@i(sound), @i(lookahead), @i(risetime), @i(falltime), @i(floor), @i(threshold))]@\This function generates an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to unity (1.0) at the point the signal crosses the threshold. Again, look-ahead is used, so the rise actually starts before the signal crosses the threshold. The rise is a constant-rate exponential and set so that a rise from @i(floor) to unity occurs in @i(risetime). Similarly, the fall is a constant-rate exponential such that a fall from unity to @i(floor) takes @i(falltime). The result is delayed by @i(lookahead), so the output is not actually synchronized with the input. To compensate, you should drop the initial @i(lookahead) of samples. Thus, @code(snd-gate) is not recommended for direct use. Use @code(gate) instead (see Section @ref(gate-sec)). @codef[snd-inverse(@index(inverse)@pragma(defn)@index(snd-inverse)@i(signal), @i(start), @i(srate))]@\Compute the function inverse of @i(signal), that is, compute @i(g)(@i(t)) such that @i(signal)(@i(g)(@i(t))) = @i(t). This function assumes that @i(signal) is non-decreasing, it uses linear interpolation, the resulting sample rate is @i(srate), and the result is shifted to have a starting time of @i(start). If @i(signal) decreases, the true inverse may be undefined, so we define @code(snd-inverse) operationally as follows: for each output time point @i(t), scan ahead in @i(signal) until the value of signal exceeds @i(t). Interpolate to find an exact time point @i(x) from @i(signal) and output @i(x) at time @i(t). This function is intended for internal system use in implementing time warps. @codef[snd-log(@pragma(defn)@index(snd-log)@i(sound))]@\Compute the natural logorithm of each sample of @i(sound). Use @code(s-log) instead (see Section @ref(s-log-sec)). @label(peak-sec) @codef[peak(@index(peak, maximum amplitude)@pragma(defn)@index(peak)@i(expression), @i(maxlen))]@\Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating @i(expression) (as in @code(s-save)). Only the first @i(maxlen) samples are evaluated. The @i(expression) is automatically quoted (@code(peak) is a macro), so do not quote this parameter. If @i(expression) is a variable, then the @i(global binding) of that variable will be used. Also, since the variable retains a reference to the sound, the sound will be evaluated and left in memory. See Section @ref(peak-ex-sec) on @pragma(startref) page @pageref(peak-ex-sec) for examples. @label(snd-max-sec) @codef[snd-max(@pragma(defn)@index(snd-max)@index(maximum amplitude)@i(expression), @i(maxlen))]@\Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating @i(expression) (as in @code(snd-save)), which is therefore normally quoted by the caller. At most @i(maxlen) samples are computed. The result is the maximum of the absolute values of the samples. @p(Notes:) It is recommended to use @code(peak) (see above) instead. If you want to find the maximum of a sound bound to a local variable and it is acceptable to save the samples in memory, then this is probably the function to call. Otherwise, use @code(peak). @codef[snd-maxv(@pragma(defn)@index(snd-maxv)@index(maximum of two sounds)@i(sound1), @i(sound2))]@\Compute the maximum of @i(sound1) and @i(sound2) on a sample-by-sample basis. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. The physical stop time is the minimum of the physical stop times of the two sounds. @i(Note that this violates the ``normal'' interpretation that sounds are zero outside their start and stop times. For example, even if) sound1 @i(extends beyond) sound2 @i(and is greater than zero, the result value in this extension will be zero because it will be after the physical stop time, whereas if we simply treated) sound2 @i(as zero in this region and took the maximum, we would get a non-zero result.) Use @code(s-max) instead (see Section @ref(s-max-sec)). @codef[snd-normalize(@pragma(defn)@index(snd-normalize)@i(sound))]@\Internally, sounds are stored with a scale factor that applies to all samples of the sound. All operators that take sound arguments take this scale factor into account (although it is not always necessary to perform an actual multiply per sample), so you should never need to call this function. This function multiplies each sample of a sound by its scale factor, returning a sound that represents the same signal, but whose scale factor is 1.0. @codef[snd-oneshot(@pragma(defn)@index(snd-oneshot)@index(oneshot)@index(threshold)@i(sound), @i(threshold), @i(ontime))]@\Computes a new sound that is zero except where @i(sound) exceeds threshold. From these points, the result is 1.0 until @i(sound) remains below @i(threshold) for @i(ontime) (in seconds). The result has the same sample rate, start time, logical stop time, and duration as @i(sound). @codef[snd-prod(@pragma(defn)@index(snd-prod)@index(signal multiplication)@index(multiplication)@i(sound1), @i(sound2))]@\Computes the product of @i(sound1) and @i(sound2). The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. Do not use this function. Use @code(mult) or @code(prod) instead (see Section @ref(mult-sec)). Sample rate, start time, etc. are taken from @i(sound). @codef[snd-pwl(@pragma(defn)@index(snd-pwl)@index(piece-wise linear)@i(t0), @i(sr), @i(lis))]@\Computes a piece-wise linear function according to the breakpoints in @i(lis). The starting time is @i(t0), and the sample rate is @i(sr). The breakpoints are passed in an XLISP list (of type @code(LVAL)) where the list alternates sample numbers (@code(FIXNUM)s, computed in samples from the beginning of the pwl function) and values (the value of the pwl function, given as a @code(FLONUM)). There is an implicit starting point of (0, 0). The list must contain an odd number of points, the omitted last value being implicitly zero (0). The list is assumed to be well-formed. Do not call this function. Use @code(pwl) instead (see Section @ref(pwl-sec)). @codef[snd-quantize(@pragma(defn)@index(snd-quantize)@i(sound), @i(steps))]@\Quantizes a sound. See Section @ref(quantize-sec) for details. @codef[snd-recip(@pragma(defn)@index(snd-recip)@i(sound))]@\Compute the reciprocal of each sample of @i(sound). Use @code(recip) instead (see Section @ref(recip-sec)). @codef[snd-resample(@pragma(defn)@index(snd-resample)@index(sample interpolation)@i(f), @i(rate))]@\Resample sound @i(f) using high-quality interpolation, yielding a new sound with the specified @i(rate). The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. The resulting start time, etc. are taken from @i(f). Use @code(resample) instead. @codef[snd-resamplev(@pragma(defn)@index(snd-resamplev)@index(sample interpolation)@index(signal composition)@i(f), @i(rate), @i(g))]@\Compose two signals, i.e. compute @i(f)(@i(g)(@i(t))), where @i(f) and @i(g) are sounds. The result has sample rate given by @i(rate). At each time @i(t) (according to the @i(rate)), @i(g) is linearly interpolated to yield an increasing sequence of high-precision score-time values. @i(f) is then interpolated at each value to yield a result sample. If in fact @i(g) decreases, the current sample of @i(g) is replaced by the previous one, forcing @i(g) into compliance with the non-decreasing restriction. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. Note that if @i(g) has a high sample rate, this may introduce unwanted jitter into sample times. See @code(sound-warp) for a detailed discussion. See @code(snd-compose) for a fast, low-quality alternative to this function. Normally, you should use @code(sound-warp) instead of this function. @codef[snd-scale(@pragma(defn)@index(snd-scale)@i(scale), @i(sound))]@\Scales the amplitude of @i(sound) by the factor @i(scale). Use @code(scale) instead (see Section @ref(scale-sec)). @codef{snd-shape(@pragma(defn)@index(snd-shape)@i(signal), @i(table), @i(origin))}@\A waveshaping function. This is the primitive upon which @code(shape) is based. The @code(snd-shape) function is like @code(shape) except that @i(signal) and @i(table) must be (single-channel) sounds. Use @code(shape) instead (see Section @ref(shape-sec)). @codef[snd-up(@pragma(defn)@index(snd-up)@i(srate), @i(sound))]@\Increases sample rate by linear interpolation. The @i(sound) is the signal to be up-sampled, and @i(srate) is the output sample rate. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call @code(force-srate) (see Section @ref(force-srate-sec)). @label(snd-xform-sec) @codef[snd-xform(@pragma(defn)@index(snd-xform)@i(sound), @i(sr), @i(time), @i(start), @i(stop), @i(scale))]@\Makes a copy of @i(sound) and then alters it in the following order: (1) the start time (@code(snd-t0)) of the sound is shifted to @i(time), (1) the sound is stretched as a result of setting the sample rate to @i(sr) (the start time is unchanged by this), (3) the sound is clipped from @i(start) to @i(stop), (4) if @i(start) is greater than @i(time), the sound is shifted shifted by @i(time) - @i(start), so that the start time is @i(time), (5) the sound is scaled by @i(scale). An empty (zero) sound at @i(time) will be returned if all samples are clipped. Normally, you should accomplish all this using transformations. A transformation applied to a sound has no effect, so use @code(cue) to create a transformable sound (see Section @ref(use-sounds-sec)). @label(snd-yin-sec) @codef{snd-yin(@pragma(defn)@index(snd-yin)@i(sound), @i(minstep), @i(maxstep), @i(rate))}@\Identical to @code[yin]. See Section @ref(yin-sec). @end(fndefs) @subsection(Filters) These are also ``Signal Operators,'' the subject of the previous section, but there are so many filter functions, they are documented in this special section. Some filters allow time-varying filter parameters. In these functions, filter coefficients are calculated at the sample rate of the filter parameter, and coefficients are not interpolated. @begin(fndefs) @codef[snd-alpass(@pragma(defn)@index(snd-alpass)@i(sound), @i(delay), @i(feedback))]@\An all-pass filter. This produces a repeating echo effect without the resonances of @code(snd-delay). The @i(feedback) should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use @code(alpass) instead (see Section @ref(alpass-sec)). @codef[snd-alpasscv(@pragma(defn)@index(snd-alpasscv)@i(sound), @i(delay), @i(feedback))]@\An all-pass filter with variable @i(feedback). This is just like @i(snd-alpass) except @i(feedback) is a sound. You should use @code(alpass) instead (see Section @ref(alpass-sec)). @codef[snd-alpassvv(@pragma(defn)@index(snd-alpassvv)@i(sound), @i(delay), @i(feedback), @i(maxdelay))]@\An all-pass filter with variable @i(feedback) and @i(delay). This is just like @i(snd-alpass) except @i(feedback) and @i(delay) are sounds, and there is an additional @code(FLONUM) parameter, @i(maxdelay), that gives an upper bound on the value of @i(delay). @p(Note:) @i(delay) must remain between zero and @i(maxdelay). If not, results are undefined, and Nyquist may crash. You should use @code(alpass) instead (see Section @ref(alpass-sec)). @codef[snd-areson(@pragma(defn)@index(snd-areson)@i(sound), @i(hz), @i(bw), @i(normalization))]@\A notch filter modeled after the @code(areson) unit generator in Csound. The @code(snd-areson) filter is an exact complement of @code(snd-reson) such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. Note that because of this complementary design, the power is not normalized as in @code(snd-reson). See @code(snd-reson) for details on @i(normalization). You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-aresoncv(@pragma(defn)@index(snd-aresoncv)@i(sound), @i(hz), @i(bw), @i(normalization))]@\This function is identical to @code(snd-areson) except the @i(bw) (bandwidth) parameter is a sound. Filter coefficients are updated at the sample rate of @i(bw). The ``@code(cv)'' suffix stands for Constant, Variable, indicating that @i(hz) and @i(bw) are constant (a number) and variable (a sound), respectively. This naming convention is used throughout. You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-aresonvc(@pragma(defn)@index(snd-aresonvc)@i(sound), @i(hz), @i(bw), @i(normalization))]@\This function is identical to @code(snd-areson) except the @i(hz) (center frequency) parameter is a sound. Filter coefficients are updated at the sample rate of @i(hz). You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-aresonvv(@pragma(defn)@index(snd-aresonvv)@i(sound), @i(hz), @i(bw), @i(normalization))]@\This function is identical to @code(snd-areson) except both @i(hz) (center frequency) and @i(bw) (bandwidth) are sounds. Filter coefficients are updated at the next sample of either @i(hz) or @i(bw). You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-atone(@pragma(defn)@index(snd-atone)@i(sound), @i(hz))]@\A high-pass filter modeled after the @code(atone) unit generator in Csound. The @code(snd-atone) filter is an exact complement of @code(snd-tone) such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. You should use @code(hp) instead (see Section @ref(hp-sec)). @codef[snd-atonev(@pragma(defn)@index(snd-atonev)@i(sound), @i(hz))]@\This is just like @code(snd-atone) except that the @i(hz) cutoff frequency is a sound. Filter coefficients are updated at the sample rate of @i(hz). You should use @code(hp) instead (see Section @ref(hp-sec)). @codef[snd-biquad(@pragma(defn)@index(snd-biquad)@i(sound), @i(b0), @i(b1), @i(b2), @i(a1), @i(a2), @i(z1init), @i(z2init))]@\A general second order IIR filter, where @i(a0) is assumed to be unity. For @i(a1) and @i(a2), the sign convention is opposite to that of Matlab. All parameters except the input @i(sound) are of type @code(FLONUM). You should probably use one of @code(lowpass2), @code(highpass2), @code(bandpass2), @code(notch2), @code(allpass2), @code(eq-lowshelf), @code(eq-highshelf), @code(eq-band), @code(lowpass4), @code(lowpass6), @code(lowpass8), @code(highpass4), @code(highpass6), or @code(highpass8), which are all based on @code(snd-biquad) and described in Section @ref(lowpass2-sec). For completeness, you will also find @code(biquad) and @code(biquad-m) described in that section. @label(snd-chase-sec) @codef[snd-chase(@pragma(defn)@index(snd-chase)@i(sound), @i(risetime), @i(falltime))]@\A slew rate limiter. The output ``chases'' the input at rates determined by @i(risetime) and @i(falltime). If the input changes too fast, the output will lag behind the input. This is a form of lowpass filter, but it was created to turn hard-switching square waves into smoother control signals that could be used for linear crossfades. If the input switches from 0 to 1, the output will linearly rise to 1 in @i(risetime) seconds. If the input switches from 1 to 0, the output will linearly fall to 0 in @i(falltime) seconds. The generated slope is constant; the transition is linear; this is not an exponential rise or fall. The @i(risetime) and @i(falltime) must be scalar constants; complain to the author if this is not adequate. The @code(snd-chase) function is safe for ordinary use. See @code(snd-follow) in Section @ref(snd-follow-sec) for a related function. @codef[snd-congen(@pragma(defn)@index(snd-congen)@i(gate), @i(risetime), @i(falltime))]@\A simple ``contour generator'' based on analog synthesizers. The @i(gate) is a sound that normally steps from 0.0 to 1.0 at the start of an envelop and goes from 1.0 back to 0.0 at the beginning of the release. At each sample, the output converges to the input exponentially. If @i(gate) is greater than the output, e.g. the attack, then the output converges half-way to the output in @i(risetime). If the @i(gate) is less than the output, the half-time is @i(falltime). The sample rate, starting time, logical-stop-time, and terminate time are taken from @i(gate). You should use @code(congen) instead (see Section @ref(congen-sec). @codef[snd-convolve(@pragma(defn)@index(snd-convolve)@i(sound), @i(response))]@\Convolves @i(sound) by @i(response) using a simple O(N x M) algorithm. The @i(sound) can be any length, but the @i(response) is computed and stored in a table. The required compuation time per sample and total space are proportional to the length of @i(response). Use @code(convolve) instead (see Section @ref(convolve-sec)). @codef[snd-delay(@pragma(defn)@index(snd-delay)@i(sound), @i(delay), @i(feedback))]@\Feedback delay. The output, initially @i(sound), is recursively delayed by @i(delay), scaled by @i(feedback), and added to itself, producing an repeating echo effect. The @i(feedback) should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use @code(feedback-delay) instead (see Section @ref(feedback-delay-sec)) @codef[snd-delaycv(@pragma(defn)@index(snd-delaycv)@i(sound), @i(delay), @i(feedback))]@\Feedback delay with variable @i(feedback). This is just like @i(snd-delay) except @i(feedback) is a sound. You should use @code(feedback-delay) instead (see Section @ref(feedback-delay-sec)). @codef[snd-reson(@pragma(defn)@index(snd-reson)@i(sound), @i(hz), @i(bw), @i(normalization))]@\A second-order resonating (bandpass) filter with center frequency @i(hz) and bandwidth @i(bw), modeled after the @code(reson) unit generator in Csound. The @i(normalization) parameter must be an integer and (like in Csound) specifies a scaling factor. A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than @i(hz) are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The result sample rate, start time, etc. are takend from @i(sound). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-resoncv(@pragma(defn)@index(snd-resoncv)@i(sound), @i(hz), @i(bw), @i(normalization))]@\This function is identical to @code(snd-reson) except @i(bw) (bandwidth) is a sound. Filter coefficients are updated at the sample rate of @i(bw). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-resonvc(@pragma(defn)@index(snd-resonvc)@i(sound), @i(hz), @i(bw), @i(normalization))]@\This function is identical to @code(snd-reson) except @i(hz) (center frequency) is a sound. Filter coefficients are updated at the sample rate of @i(hz). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-resonvv(@pragma(defn)@index(snd-resonvv)@i(sound), @i(hz), @i(bw), @i(normalization))]@\This function is identical to @code(snd-reson) except botth @i(hz) (center frequency) and @i(bw) (bandwidth) are sounds. Filter coefficients are updated at the next sample from either @i(hz) or @i(bw). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-stkchorus(@pragma(defn)@index(snd-stkchorus)@index(chorus)@index(effect, chorus)@index(STK chorus)@i(sound), @i(delay), @i(depth), @i(freq), @i(mix), @i(sr))]@\A chorus implemented in STK. The parameter @i(delay) is a @code(FIXNUM) representing the median desired delay length in samples. A typical value is 6000. The @code(FLONUM) parameters @i(depth) and @i(freq) set the modulation depth (from 0 to 1) and modulation frequency (in Hz), @i(mix) sets the mixture of input sound and chorused sound, where a value of 0.0 means input sound only (dry) and a value of 1.0 means chorused sound only (wet). The parameter @i(sr) is the desired sample rate of the resulting sound@foot(This is probably a mistake since sample rate is implied by @i(sound). This parameter may be removed in a future release.) You should use @code(pitshift) instead (see Section @ref(stkchorus-sec)). @codef[snd-stkpitshift(@pragma(defn)@index(snd-stkpitshift)@index(pitch shift)@index(effect, pitch shift)@index(STK pitch shift)@i(sound), @i(shift), @i(mix), @i(sr))]@\A pitch shifter implemented in STK. The @i(sound) is shifted in pitch by @i(shift), a @code(FLONUM) representing the shift factor. A value of 1.0 means no shift. The parameter @i(mix) sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). The @i(sr) is the desired sampling frequency.@foot(This is probably a mistake since sample rate is implied by @i(sound). This parameter may be removed in a future release.) You should use @code(pitshift) instead (see Section @ref(stkpitshift-sec)). @codef[snd-stkrev(@pragma(defn)@index(snd-stkrev)@index(reverb)@index(effect, reverberation)@index(STK reverb)@i(rev-type), @i(sound), @i(decay), @i(mix), @i(sr))]@\A reverb implemented in STK. The parameter rev-type is a @code(FIXNUM) ranging from zero to two and selects the type of reverb. Zero selects NRev type, one selects JCRev, and two selects PRCRev. The input @i(sound) is processed by the reverb with a @i(decay) time in seconds (a @code(FLONUM)). The @i(mix), a @code(FLONUM), sets the mixture of dry input and reverb output. A value of 0.0 means input only (dry) and a value of 1.0 means reverb only (wet). The sample rate is @i(sr)@foot(This is probably a mistake since sample rate is implied by @i(sound). This parameter may be removed in a future release.) You should use @code(nrev), @code(jcrev) or @code(prcrev) instead (see Section @ref(stkrev-sec)). @codef[snd-tone(@pragma(defn)@index(snd-tone)@index(low-pass filter)@i(sound), @i(hz))]@\A first-order recursive low-pass filter, based on the @i(tone) unit generator of Csound. The @i(hz) parameter is the cutoff frequency, the response curve's half-power point. The result sample rate, start time, etc. are takend from @i(sound). You should use @code(lp) instead (see Section @ref(lp-sec)). @codef[snd-tonev(@pragma(defn)@index(snd-tonev)@i(sound), @i(hz))]@\This function is identical to @code(snd-tone) except @i(hz) (cutoff frequency) is a sound. The filter coefficients are updated at the sample rate of @i(hz). You should use @code(lp) instead (see Section @ref(lp-sec)). @end(fndefs) @subsection(Table-Lookup Oscillator Functions) These functions all use a sound to describe one period of a periodic waveform. In the current implementation, the sound samples are copied to an array (the waveform table) when the function is called. To make a table-lookup oscillator generate a specific pitch, we need to have several pieces of information: @begin(itemize) A waveform to put into the table. This comes from the @i(sound) parameter. The length (in samples) of the waveform. This is obtained by reading samples (starting at the sound's start time, not necessarily at time zero) until the physical stop time of the sound. (If you read the waveform from a file or generate it with functions like @code(sim) and @code(sine), then the physical and logical stop times will be the same and will correspond to the duration you specified, rounded to the nearest sample.) The intrinsic sample rate of the waveform. This sample rate is simply the sample rate property of @i(sound). The pitch of the waveform. This is supplied by the @i(step) parameter and indicates the pitch (in steps) of @i(sound). You might expect that the pitch would be related to the period (length) of @i(sound), but there is the interesting case that synthesis based on sampling often loops over multiple periods. This means that the fundamental frequency of a generated tone may be some multiple of the looping rate. In Nyquist, you always specify the perceived pitch of the looped @i(sound) if the sound is played at the @i(sound)'s own sample rate. The desired pitch. This is specified by the @i(hz) parameter in Hertz (cycles per second) in these low-level functions. Note that this is not necessarily the ``loop'' rate at which the table is scanned. Instead, Nyquist figures what sample rate conversion would be necessary to ``transpose'' from the @i(step) which specifies the original pitch of @i(sound) to @i(hz), which gives the desired pitch. The mixed use of steps and Hertz came about because it seemed that sample tables would be tagged with steps (``I sampled a middle-C''), whereas frequency deviation in the @code(fmosc) function is linear, thus calling for a specification in Hertz. The desired sample rate. This is given by the @i(sr) parameter in Hertz. @end(itemize) Other parameters common to all of these oscillator functions are: @begin(itemize) @i(t0), the starting time, and @i(phase), the starting phase in degrees. Note that if the @i(step) parameter indicates that the table holds more than one fundamental period, then a starting phase of 360 will be different than a starting phase of 0. @end(itemize) @begin(fndefs) @codef[snd-amosc(@pragma(defn)@index(snd-amosc)@i(sound), @i(step), @i(sr), @i(hz), @i(t0), @i(am), @i(phase))]@\An oscillator with amplitude modulation. The sound @i(am) specifies the amplitude and the logical stop time. The physical stop time is also that of @i(am). You should use @code(amosc) instead (see Section @ref(amosc-sec)). @codef[snd-fmosc(@pragma(defn)@index(snd-fmosc)@i(s), @i(step), @i(sr), @i(hz), @i(t0), @i(fm), @i(phase))]@\A Frequency Modulation oscillator. The sound @i(fm) specifies frequency deviation (in Hertz) from @i(hz). You should use @code(fmosc) instead (see Section @ref(fmosc-sec)). @code[snd-fmfb(@pragma(defn)@index(snd-fmfb)@i(t0), @i(hz), @i(sr), @i(index), @i(dur))]@\A Feedback FM oscillator. The resulting sound starts at @i(t0), has a fundamental frequency of @i(hz), a sample rate of @i(sr), and a duration of @i(dur) seconds. The @i(index) is a @code(FLONUM) that specifies the amount of feedback. You should use @code(fmfb) instead (see Section @ref(fmfb-sec)). @code[snd-fmfbv(@pragma(defn)@index(snd-fmfb)@i(t0), @i(hz), @i(sr), @i(index))]@\A Feedback FM oscillator. The resulting sound starts at @i(t0), has a fundamental frequency of @i(hz), and a sample rate of @i(sr). The @i(index) is a @code(SOUND) that specifies the amount of feedback and determines the duration. You should use @code(fmfb) instead (see Section @ref(fmfb-sec)). @codef[snd-buzz(@pragma(defn)@index(snd-buzz)@i(n), @i(sr), @i(hz), @i(t0), @i(fm))]@\A buzz oscillator, which generates @i(n) harmonics of equal amplitude. The @i(fm) specifies frequency deviation (in Hertz) from @i(hz). You should use @code(buzz) instead (see Section @ref(buzz-sec)). @codef[snd-pluck(@pragma(defn)@index(snd-pluck)@i(sr), @i(hz), @i(t0), @i(d), @i(final-amp))]@\A Karplus-Strong plucked string oscillator with sample rate @i(sr), fundamental frequency @i(hz), starting time @i(t0), duration @i(d), initial amplitude approximately 1.0 (not exact because the string is initialized with random values) and final amplitude approximately @i(final-amp). You should use @code(pluck) instead (see Section @ref(pluck-sec)). @codef[snd-osc(@pragma(defn)@index(snd-osc)@i(s), @i(step), @i(sr), @i(hz), @i(t0), @i(d), @i(phase))]@\A simple table lookup oscillator with fixed frequency. The duration is @i(d) seconds. You should use @code(osc) instead (see Section @ref(osc-sec)). @codef[snd-partial(@pragma(defn)@index(snd-partial)@i(sr), @i(hz), @i(t0), @i(env))]@\This is a special case of @code(snd-amosc) that generates a sinusoid starting at phase 0 degrees. The @i(env) parameter gives the envelope or any other amplitude modulation. You should use @code(partial) instead (see Section @ref(partial-sec)). @codef[snd-sine(@pragma(defn)@index(snd-sine)@i(t0), @i(hz), @i(sr), @i(d))]@\This is a special case of @code(snd-osc) that always generates a sinusoid with initial phase of 0 degrees. You should use @code(sine) instead (see Section @ref(sine-sec)). @codef[snd-siosc(@pragma(defn)@index(snd-siosc)@i(tables), @i(sr), @i(hz), @i(t0), @i(fm))]@\A Spectral Interpolation Oscillator with frequency modulation. The @i(tables) is a list of sounds and sample counts as follows: (@i(table0) @i(count1) @i(table1) ... @i(countN) @i(tableN)). The initial waveform is given by @i(table0), which is interpolated linearly to @i(table1) over the first @i(count1) samples. From @i(count1) to @i(count2) samples, the waveform is interpolated from @i(table1) to @i(table2), and so on. If more than @i(countN) samples are generated, @i(tableN) is used for the remainder of the sound. The duration and logical stop time of the sound is taken from @i(fm), which specified frequency modulation (deviation) in Hertz. You should use @code(siosc) instead (see Section @ref(siosc-sec)). @end(fndefs) @subsection(Physical Model Functions) These functions perform some sort of physically-based modeling synthesis. @begin(fndefs) @code[(snd-bandedwg@pragma(defn)@index(snd-bandedwg)@index(STK banded waveguide) @i(freq) @i(bowpress-env) @i(preset) @i(sr))]@\A Banded Wave Guide Percussion instrument implemented in STK. The parameter @i(freq) is a @code(FLONUM) in Hz, @i(bowpress-env) is a @code(SOUND) that ranges from zero to one, @i(preset) is a @code(FIXNUM), and @i(sr) is the desired sample rate in Hz. Currently, there are four presets: uniform-bar (0), tuned-bar (1), glass-harmonica (2), and tibetan-bowl (3). You should use @code(wg-uniform-bar), @code(wg-tuned-bar), @code(wg-glass-harm), or @code(wg-tibetan-bowl) instead (see Section @ref(bandedwg-sec)). @codef[snd-bowed(@pragma(defn)@index(snd-bowed)@index(stk bowed)@i(freq), @i(bowpress-env), @i(sr))]@\A bowed string instrument implemented in STK. The freq is a @code(FLONUM) in Hertz, bowpress-env is a @code(SOUND) that ranges from z ero to one, and sr is the desired sample rate (a @code(FLONUM)). You should use bowed instead (see Section @ref(bowed-sec)). @codef[snd-bowed-freq(@pragma(defn)@index(snd-bowed-freq)@index(stk bowed)@i(freq), @i(bowpress-env), @i(freq-env), @i(sr))]@\A bowed model just like @code(snd-bowed) but with an additional parameter for continuous frequency control. You should use @code(bowed-freq) instead (see Section @ref(bowed-sec)). @codef[snd-clarinet(@pragma(defn)@index(snd-clarinet)@index(stk clarinet)@i(freq), @i(breath-env), @i(sr))]@\A clarinet model implemented in STK. The @i(freq) is a @code(FLONUM) in Hertz, @i(breath-env) is a @code(SOUND) that ranges from zero to one, and @i(sr) is the desired sample rate (a @code(FLONUM)). You should use @code(clarinet) instead (see Section @ref(clarinet-sec)). @codef[snd-clarinet-freq(@pragma(defn)@index(snd-clarinet-freq)@index(STK clarinet)@i(freq), @i(breath-env), @i(freq-env), @i(sr))]@\A clarinet model just like @code(snd-clarinet) but with an additional parameter for continuous frequency control. You should use @code(clarinet-freq) instead (see Section @ref(clarinet-sec)). @codef[snd-clarinet-all(@pragma(defn)@index(snd-clarinet-all)@i(freq), @i(vibrato-freq), @i(vibrato-gain), @i(freq-env), @i(breath-env), @i(reed-stiffness), @i(noise), @i(sr))]@\A clarinet model just like @code(snd-clarinet-freq) but with additional parameters for vibrato generation and continuous control of reed stiffness and breath noise. You should use @code(clarinet-all) instead (see Section @ref(clarinet-sec)). @codef[snd-flute(@pragma(defn)@index(snd-flute)@index(stk flute)@i(freq), @i(breath-env), @i(sr))]@\A flute implemented in STK. The @i(freq) is a @code(FLONUM) in Hertz, @i(breath-env) is a @code(SOUND) that ranges from zero to one, and @i(sr) is the desired sample rate (a @code(FLONUM)). You should use @code(flute) instead (see Section @ref(flute-sec)). @codef[snd-flute-freq(@pragma(defn)@index(snd-flute-freq)@index(stk flute)@i(freq), @i(breath-env), @i(freq-env), @i(sr))]@\A flute model just like @code(snd-flute) but with an additional parameter for continuous frequency control. You should use @code(flute-freq) instead (see Section @ref(flute-sec)). @codef[snd-flute-all(@pragma(defn)@index(snd-flute-all)@index(stk flute)@i(freq), @i(vibrato-freq), @i(vibrato-gain), @i(freq-env), @i(breath-env), @i(jet-delay), @i(noise), @i(sr))]@\A flute model just like @code(snd-flute-freq) but with additional parameters for vibrato generation and continuous control of breath noise. You should use @code(flute-all) instead (see Section @ref(flute-sec)). @codef[snd-mandolin(@pragma(defn)@index(snd-mandolin)@index(STK mandolin)@i(t0), @i(freq), @i(dur), @i(body-size), @i(detune), @i(sr))]@\A plucked double-string instrument model implemented in STK. The @i(t0) parameter is the starting time (in seconds), @i(freq) is a @code(FLONUM) in Hz, @i(body-size) and @i(detune) are @code(FLONUM)s, and @code(sr) is the desired sample rate. You should use @code(mandolin) instead (see Section @ref(mandolin-sec)). @codef[snd-modalbar(@pragma(defn)@index(snd-modalbar)@index(STK modal bar)@i(t0), @i(freq), @i(preset), @i(dur), @i(sr))]@\Struck bar instrument model implemented in STK. The parameter @i(t0) is the starting time (in seconds), @i(freq) is a @code(FLONUM) in Hz, @code(preset) is a @code(FIXNUM) ranging from 0 to 8, @i(dur) is a @code(FLONUM) that sets the duration (in seconds) and @i(sr) is the desired sample rate. You should use @code(modalbar) instead (see Section @ref(modalbar-sec)). @codef[snd-sax(@pragma(defn)@index(snd-sax)@index(STK sax)@i(freq), @i(breath-env), @i(sr))]@\A sax model implemented in STK. The @i(freq) is a @code(FLONUM) in Hertz, @i(breath-env) is a @code(SOUND) that ranges from zero to one, and @i(sr) is the desired sample rate (a @code(FLONUM)). You should use @code(sax) instead (see Section @ref(sax-sec)). @codef[snd-sax-freq(@pragma(defn)@index(snd-sax-freq)@i(freq), @i(freq-env), @i(breath-env), @i(sr))]@\A sax model just like @code(snd-sax) but with an additional parameter for continuous frequency control. You should use @code(sax-freq) instead (see Section @ref(sax-sec)). @codef[snd-sax-all(@pragma(defn)@index(snd-sax-all)@i(freq), @i(vibrato-freq), @i(vibrato-gain), @i(freq-env), @i(breath-env), @i(reed-stiffness), @i(noise), @i(blow-pos), @i(reed-table-offset), @i(sr))]@\A sax model just like @code(snd-sax-freq) but with additional parameters for vibrato generation and continuous control of reed stiffness, breath noise, excitation position, and reed table offset. You should use @code(sax-all) instead (see Section @ref(sax-sec)). @codef[snd-sitar(@pragma(defn)@index(snd-sitar)@index(STK sitar)@i(t0), @i(freq), @i(dur), @i(sr))]@\A sitar model implemented in STK. The parameter @i(t0) is the starting time, @i(freq) is a @code(FLONUM) (in Hz), E @i(dur) sets the duration and @i(sr) is the sample rate (in Hz) of the resulting sound. You should use @code(sitar) instead (see Section @ref(sitar-sec)). @end(fndefs) @subsection(Sequence Support Functions) The next two functions are used to implement Nyquist's @code(seq) construct. @begin(fndefs) @codef[snd-seq(@pragma(defn)@index(snd-seq)@i(sound), @i(closure))]@\This function returns @i(sound) until the logical stop time of @i(sound). Then, the XLISP @i(closure) is evaluated, passing it the logical stop time of @i(sound) as a parameter. The closure must return a sound, which is then added to @i(sound). (An add is used so that @i(sound) can continue past its logical stop if desired.) Do not call this function. See @code(seq) in Section @ref(seq-sec). @codef[snd-multiseq(@pragma(defn)@index(snd-multiseq)@i(array), @i(closure))]@\This function is similar to @code(snd-seq) except the first parameter is a multichannel sound rather than a single sound. A multichannel sound is simply an XLISP array of sounds. An array of sounds is returned which is the sum of @i(array) and another array of sounds returned by @i(closure). The @i(closure) is passed the logical stop time of the multichannel sound, which is the maximum logical stop time of any element of @i(array). Do not call this function. See @code(seq) in Section @ref(seq-sec). @end(fndefs) @codef[snd-trigger(@pragma(defn)@index(snd-trigger)@i(s), @i(closure))]@\This is one of the only ways in which a behavior instance can be created by changes in a signal. When @i(s) (a @code(SOUND)) makes a transition from less than or equal to zero to greater than zero, the closure, which takes a starting time parameter, is evaluated. The closure must return a @code(SOUND). The sum of all these sounds is returned. If there are no sounds, the result will be zero. The stop time of the result is the maximum stop time of @i(s) and all sounds returned by the closure. The sample rate of the return value is the sample rate of @i(s), and the sounds returned by the closure must all have that same sample rate. Do not call this function. See @code(trigger) in Section @ref(trigger-sec). An implementation note: There is no way to have @code(snd-trigger) return a multichannel sound. An alternative implementation would be a built-in function to scan ahead in a sound to find the time of the next zero crossing. This could be combined with some LISP code similar to @code(seq) to sum up instances of the closure. However, this would force arbitrary look-ahead and therefore would not work with real-time inputs, which was the motivation for @code(snd-trigger) in the first place. @chapter(Nyquist Globals) @index(Global Variables) There are many global variables in Nyquist. A convention in Lisp is to place asterisks (*) around global variables, e.g. @code(*table*). This is only a convention, and the asterisks are just like any other letter as far as variable names are concerned. Here are some globals users should know about: @begin(description, leftmargin +2 in, indent -2 in) @codef(*table*)@index(*table*)@\Default table used by @code(osc) and other oscillators. @codef(*A4-Hertz*)@pragma(defn)@index(*a4-hertz*)@\Frequency of A4 in Hertz.. Note: you must call @code[(set-pitch-names)] to recompute pitches after changing @code(*A4-Hertz*). @codef(*autonorm*)@pragma(defn)@index(*autonorm*)@\The normalization factor to be applied to the next sound when @code(*autonorm-type*) is @code('previous). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonormflag*)@pragma(defn)@index(*autonormflag*)@\Enables the automatic normalization feature of the @code(play) command. You should use @code[(autonorm-on)] and @code[(autonorm-off)] rather than setting @code(*autonormflag*) directly. See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-max-samples*)@pragma(defn)@index(*autonorm-max-samples*)@\Specifies how many samples will be computed searching for a peak value when @code(*autonorm-type*) is @code('lookahead). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-previous-peak*)@pragma(defn)@index(*autonorm-previous-peak*)@\The peak of the previous sound generated by @code(play). This is used to compute the scale factor for the next sound when @code(*autonorm-type*) is @code('previous). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-target*)@pragma(defn)@index(*autonorm-target*)@\The target peak amplitude for the autonorm feature. The default value is 0.9. See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-type*)@pragma(defn)@index(*autonorm-type*)@\Determines how the autonorm feature is implemented. Valid values are @code('lookahead) (the default) and @code('previous). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*breakenable*)@pragma(defn)@index(*breakenable*)@\Controls whether XLISP enters a break loop when an error is encountered. See Section @ref(symbols-sec). @codef(*control-srate*)@pragma(defn)@index(*control-srate*)@\Part of the environment, establishes the control sample rate. See Section @ref(environment-sec) for details. @codef(*default-sf-bits*)@pragma(defn)@index(*default-sf-bits*)@\The default bits-per-sample for sound files. Typically 16. @codef(*default-sf-dir*)@pragma(defn)@index(*default-sf-dir*)@\The default sound file directory. Unless you give a full path for a file, audio files are assumed to be in this directory. (Applies to many functions that deal with sound files. Check the function description to see if @code(*default-sf-dir*) applies.) @codef(*default-sf-format*)@pragma(defn)@index(*default-sf-format*)@\The default sound file format. When you write a file, this will be the default format: AIFF for Mac and most Unix systems, NeXT for NeXT systems, and WAV for Win32. @codef(*default-sf-srate*)@pragma(defn)@index(*default-sf-srate*)@\The default sample rate for sound files. Typically 44100.0, but often set to 22050.0 for speed in non-critical tasks. @codef(*default-control-srate*)@pragma(defn)@index(*default-control-srate*)@\Default value for @code(*control-srate*). This value is restored when you execute @code[(top)] to pop out of a debugging session. Change it by calling @code[(set-control-srate @i(value))]. @codef(*default-sound-srate*)@pragma(defn)@index(*default-sound-srate*)@\Default value for @code(*sound-srate*). This value is restored when you execute @code[(top)] to pop out of a debugging session. Change it by calling @code[(set-sound-srate @i(value))]. @codef(*file-separator*)@pragma(defn)@index(*file-separator*)@\The character that separates directories in a path, e.g. ``@code(/)'' for Unix, ``@code(:)'' for Mac, and ``@code(\)'' for Win32. This is normally set in @code(system.lsp). @codef(*rslt*)@pragma(defn)@index(*rslt*)@\When a function returns more than one value, @code(*rslt*) is set to a list of the ``extra'' values. This provides a make-shift version of the @code(multiple-value-return) facility in Common Lisp. @codef(*sound-srate*)@pragma(defn)@index(*sound-srate*)@\Part of the environment, establishes the audio sample rate. See Section @ref(environment-sec) for details. @codef(*soundenable*)@pragma(defn)@index(*soundenable*)@\Controls whether writes to a sound file will also be played as audio. Set this variable by calling @code{(sound-on)} or @code{(sound-off)}. @codef(*tracenable*)@pragma(defn)@index(*tracenable*)@\Controls whether XLISP prints a backtrace when an error is encountered. @b(XLISP variables)@\See Section @ref(symbols-sec) for a list of global variables defined by XLISP. @b(Environment variables)@\See Section @ref(environment-sec) for definitions of variables used in the environment for behaviors. In general, you should never set or access these variables directly. @b(Various constants)@\See Section @ref(constants-sec) for definitions of predefined constants for loudness, duration, and pitch. @end(description) @chapter(Time/Frequency Transformation) Nyquist provides functions for FFT and inverse FFT operations on streams of audio data. Because sounds can be of any length, but an FFT operates on a fixed amount of data, FFT processing is typically done in short blocks or windows that move through the audio. Thus, a stream of samples is converted in to a sequence of FFT frames representing short-term spectra. Nyquist does not have a special data type corresponding to a sequence of FFT frames. This would be nice, but it would require creating a large set of operations suitable for processing frame sequences. Another approach, and perhaps the most ``pure'' would be to convert a single sound into a multichannel sound, with one channel per bin of the FFT. Instead, Nyquist violates its ``pure'' functional model and resorts to objects for FFT processing. A sequence of frames is represented by an XLISP object. Whenever you send the selector @code[:next] to the object, you get back either NIL, indicating the end of the sequence, or you get an array of FFT coefficients. The Nyquist function @code[snd-fft] (mnemonic, isn't it?) returns one of the frame sequence generating objects. You can pass any frame sequence generating object to another function, @code[snd-ifft], and turn the sequence back into audio. With @code[snd-fft] and @code[snd-ifft], you can create all sorts of interesting processes. The main idea is to create intermediate objects that both accept and generate sequences of frames. These objects can operate on the frames to implement the desired spectral-domain processes. Examples of this can be found in the file @code[fft_tutorial.htm]@index(fft tutorial)@index(fast fourier transform tutorial)@index(demos, fft), which is part of the standard Nyquist release. The documentation for @code[snd-fft] and @code[snd-ifft] follows. @begin(fndefs) @codef[snd-fft(@pragma(defn)@index(snd-fft)@index(fft)@i(sound), @i(length), @i(skip), @i(window))]@\This function performs an FFT on the first samples in @i(sound) and returns a Lisp array of @code[FLONUM]s. The function modifies the @i(sound), violating the normal rule that sounds are immutable in Nyquist, so it is advised that you copy the sound using @code[snd-copy] if there are any other references to @i(sound). The length of the FFT is specified by @i(length), a @code[FIXNUM] (integer) which must be a power of 2. After each FFT, the sound is advanced by @i(skip) samples, also of type @code[FIXNUM]. Overlapping FFTs, where @i(skip) is less than @i(length), are allowed. If @i(window) is not @code[NIL], it must be a sound. The first @i(length) samples of @i(window) are multiplied by @i(length) samples of @i(sound) before performing the FFT. When there are no more samples in @i(sound) to transform, this function returns @code[NIL]. The coefficients in the returned array, in order, are the DC coefficient, the first real, the first imaginary, the second real, the second imaginary, etc. The last array element corresponds to the real coefficient at the Nyquist frequency. @codef[snd-ifft(@pragma(defn)@index(snd-ifft)@index(ifft)@index(inverse fft)@i(time), @i(srate), @i(iterator), @i(skip), @i(window))]@\This function performs an IFFT on a sequence of spectral frames obtained from @i(iterator) and returns a sound. The start time of the sound is given by @i(time). Typically, this would be computed by calling @code[(local-to-global 0)]. The sample rate is given by @i(srate). Typically, this would be @code[*sound-srate*], but it might also depend upon the sample rate of the sound from which the spectral frames were derived. To obtain each frame, the function sends the message @code[:next] to the @i(iterator) object, using XLISP's primitives for objects and message passing. The object should return an array in the same format as obtained from @code[snd-fft], and the object should return @code[NIL] when the end of the sound is reached. After each frame is inverse transformed into the time domain, it is added to the resulting sound. Each successive frame is added with a sample offset specified by @i(skip) relative to the previous frame. This must be an integer greater than zero. If @i(window) is not @code[NIL], it must be a sound. This window signal is multiplied by the inverse transformed frame before the frame is added to the output sound. The length of each frame should be the same power of 2. The length is implied by the array returned by @i(iterator), so it does not appear as a parameter. This length is also the number of samples used from @i(window). Extra samples are ignored, and window is padded with zeros if necessary, so be sure @i(window) is the right length. The resulting sound is computed on demand as with other Nyquist sounds, so @code[:next] messages are sent to @i(iterator) only when new frames are needed. One should be careful not to reuse or modify @i(iterator) once it is passed to @code[snd-ifft]. @end(fndefs) @chapter(MIDI, Adagio, and Sequences) @label(adagio-chap) @index(MIDI)@index(Sequences) Nyquist includes facilities to read and write MIDI files as well as an ASCII text-based score representation language, Adagio. XLISP and Nyquist can be used to generate MIDI files using compositional algorithms. (See also Section @ref(xmusic-sec).) A tutorial on using the Adadio representation and MIDI can be found in @code(demos/midi_tutorial.htm)@index(demos, midi). The Adagio language is described below. Adagio was originally developed as part of the CMU MIDI Toolkit, which included a program to record and play MIDI using the Adagio representation. Some of the MIDI features of Adagio may not be useful within Nyquist. Nyquist offers a number of different score representations, and you may find this confusing. In general, MIDI files are a common way to exchange music performance data, especially with sequencers and score notation systems. The @code(demos/midi_tutorial.htm) examples show how to get the most precise control when generating MIDI data. Adagio is most useful as a text-based score entry language, and it is certainly more compact than Lisp expressions for MIDI-like data. The Xmusic library (Chapter @ref(xmusic-sec)) is best for algorithmic generation of music and score manipulation. There are functions to convert between the Adagio, MIDI sequence data, and Xmusic score representations. @pragma(doinclude) @include(adagio-nyquist.mss) @chapter(Linear Prediction Analysis and Synthesis) @index(Linear Prediction)@index(LPC) Nyquist provides functions to perform Linear Prediction Coding (LPC) analysis and synthesis. In simple terms, LPC analysis assumes that a sound is the result of an all-pole filter applied to a source with a flat spectrum. LPC is good for characterizing the general spectral shape of a signal, which may be time-varying as in speech sounds. For synthesis, any source can be filtered, allowing the general spectral shape of one signal (used in analysis) to be applied to any source (used in synthesis). A popular effect is to give vowel-like spectra to musical tones, creating an artificial (or sometimes natural) singing voice. Examples of LPC analysis and synthesis can be found in the file @code[lpc_tutorial.htm]@index(lpc tutorial)@index(linear prediction tutorial)@index(demos, lpc), which is part of the standard Nyquist release. As with FFT processing, LPC analysis takes a sound as input and returns a stream of frames. Frames are returned from an object using the @code(:next) selector just as with FFT frames. An LPC frame is a list consisting of: @i(RMS1), the energy of the input signal, @i(RMS2), the energy of the residual signal, @i(ERR), the square root of @i(RMS1)/@i(RMS2), and @i(FILTER-COEFS), an array of filter coefficients. To make code more readable and to avoid code dependence on the exact format of a frame, the functions @code(lpc-frame-rms1)@index(lpc-frame-rms1), @code(lpc-frame-rms2)@index(lpc-frame-rms2), @code(lpc-frame-err)@index(lpc-frame-err), and @code(lpc-frame-filter-coefs)@index(lpc-frame-filter-coefs) can be applied to a frame to obtain the respective fields. The @i(z) transform of the filter is @i(H)(@i(z)) = 1/@i(A)(@i(z)), where @i(A)(@i(z)) is a polynomial of the form @i(A)(@i(z)) = 1 + @i(a@-[1])@i(z) + @i(a@-[2])@i(z) + ... + @i(a@-[p])@i(z). The @i(FILTER-COEFS) array has the form @code[#(]@i(a@-[p]) @i(a@-[p-1]) ... @i(a@-[3]) @i(a@-[2]) @i(a@-[1])@code[)]. The file @code(lpc.lsp) defines some useful classes and functions. The file is @i(not) automatically loaded with Nyquist, so you must execute @code[(load "lpc")] before using them. @section(LPC Classes and Functions) @begin(fndefs) @codef[make-lpanal-iterator(@pragma(defn)@index(make-lpanal-iterator)@i(sound), @i(framedur), @i(skiptime), @i(npoles))]@\Makes an iterator object, an instance of @code(lpanal-class), that returns LPC frames from successive frames of samples in @i(sound). The duration (in seconds) of each frame is given by @i(framedur), a @code(FLONUM). The skip size (in seconds) between successive frames is given by @i(skiptime), a @code(FLONUM). Typical values for @i(framedur) and @i(skiptime) are 0.08 and 0.04, giving 25 frames per second and a 50% frame overlap. The number of poles is given by @i(npoles), a @code(FIXNUM). The result is an object that responds to the @code(:next) selector by returning a frame as described above. @code(NIL) is returned when @i(sound) terminates. (Note that one or more of the last analysis windows may be padded with zeros. @code(NIL) is only returned when the corresponding window would begin after the termination time of the sound.) @codef[make-lpc-file-iterator(@pragma(defn)@index(make-lpc-file-iterator)@i(filename))]@\Another way to get LPC frames is to read them from a file. This function opens an ASCII file containing LPC frames and creates an iterator object, an instance of class @code(lpc-file-class) to access them. Create a file using @code(save-lpc-file) (see below). @codef[save-lpc-file(@pragma(defn)@index(save-lpc-file)@i(lpc-iterator), @i(filename))]@\Create a file containing LPC frames. This file can be read by @code[make-lpc-file-iterator] (see above). @codef{show-lpc-data(@pragma(defn)@index(show-lpc-data)@i(lpc-iterator), @i(iniframe), @i(endframe)[ ,@i(poles?)])}@\Print values of LPC frames from an LPC iterator object. The object is @i(lpc-iterator), which is typically an instance of @code(lpanal-class) or @code(lpc-file-class). Frames are numbered from zero, and only files starting at @i(iniframe) (a @code[FIXNUM]) and ending before @i(endframe) (also a @code[FIXNUM]) are printed. By default, only the values for @i(RMS1), @i(RMS2), and @i(ERR) are printed, but if optional parameter @i(poles?) is non-@code[NIL], then the LPC coefficients are also printed. @codef[allpoles-from-lpc(@pragma(defn)@index(allpoles-from-lpc)@i(snd), @i(lpc-frame))]@\A single LPC frame defines a filter. Use @code(allpoles-from-lpc) to apply this filter to @i(snd), a @code(SOUND). To obtain @i(lpc-frame), a @code(LIST) containing an LPC frame, either send @code(:next) to an LPC iterator, or use @code(nth-frame) (see below). The result is a @code(SOUND) whose duration is the same as that of @i(snd). @codef[lpreson(@pragma(defn)@index(lpreson)@i(snd), @i(lpc-iterator), @i(skiptime))]@\Implements a time-varying all-pole filter controlled by a sequence of LPC frames from an iterator. The @code(SOUND) to be filtered is @i(snd), and the source of LPC frames is @i(lpc-iterator), typically an instance of @code(lpanal-class) or @code(lpc-file-class). The frame period (in seconds) is given by @i(skiptime) (a @code(FLONUM)). This number does not have to agree with the @i(skiptime) used to analyze the frames. (Greater values will cause the filter evolution slow down, and smaller values will cause it to speed up.) The result is a @code(SOUND). The duration of the result is the minimum of the duration of @i(snd) and that of the sequence of frames. @codef[lpc-frame-rms1(@pragma(defn)@index(lpc-frame-rms1)@i(frame))]@\Get the energy of the input signal from a frame. @codef[lpc-frame-rms2(@pragma(defn)@index(lpc-frame-rms2)@i(frame))]@\Get the energy of the residual from a frame. @codef[lpc-frame-err(@pragma(defn)@index(lpc-frame-err)@i(frame))]@\Get the square root of @i(RMS1)/@i(RMS2) from a frame. @codef[lpc-frame-filter-coefs(@pragma(defn)@index(lpc-frame-filter-coefs)@i(frame))]@\Get the filter coefficients from a frame. @end(fndefs) @section(Low-level LPC Functions) The lowest-level Nyquist functions for LPC are @begin(itemize) @code(snd-lpanal) for analysis, @code(snd-allpoles), an all-pole filter with fixed coefficients, and @code(snd-lpreson), an all-pole filter that takes frames from an LPC iterator. @end(itemize) @begin(fndefs) @codef[snd-lpanal(@pragma(defn)@index(snd-lpanal)@i(samps), @i(npoles))]@\Compute an LPC frame with @i(npoles) (a @code(FIXNUM)) poles from an @code(ARRAY) of samples (@code(FLONUMS)). Note that @code(snd-fetch-array) can be used to fetch a sequence of frames from a sound. Ordinarily, you should not use this function. Use @code(make-lpanal-iterator) instead. @codef[snd-allpoles(@pragma(defn)@index(snd-allpoles)@i(snd), @i(lpc-coefs), @i(gain))]@\A fixed all-pole filter. The input is @i(snd), a @code(SOUND). The filter coefficients are given by @i(lpc-coefs) (an @code(ARRAY)), and the filter gain is given by @i(gain), a @code(FLONUM). The result is a @code(SOUND) whose duration matches that of @i(snd). Ordinarily, you should use @code(allpoles-from-lpc) instead (see above). @codef[snd-lpreson(@pragma(defn)@index(snd-lpreson)@i(snd), @i(lpc-iterator), @i(skiptime))]@\This function is identical to @code(lpreson) (see above). @end(fndefs) @chapter(Developing and Debugging in Nyquist) @index(debugging)@index(developing code) There are a number of tools, functions, and techniques that can help to debug Nyquist programs. Since these are described in many places throughout this manual, this chapter brings together many suggestions and techniques for developing code and debugging. You @i(really) should read this chapter before you spend too much time with Nyquist. Many problems that you will certainly run into are addressed here. @section(Debugging) Probably the most important debugging tool is the backtrace. When Nyquist encounters an error, it suspends execution and prints an error message. To find out where in the program the error occurred and how you got there, start by typing @code[(bt)]. This will print out the last several function calls and their arguments, which is usually sufficient to see what is going on. In order for @code[(bt)] to work, you must have a couple of global variables set: @code(*tracenable*) is ordinarily set to @code(NIL). If it is true, then a backtrace is automatically printed when an error occurs; @code(*breakenable*) must be set to @code(T), as it enables the execution to be suspended when an error is encountered. If @code(*breakenable*) is @code(NIL) (false), then execution stops when an error occurs but the stack is not saved and you cannot get a backtrace. Finally, @code(bt) is just a macro to save typing. The actual backtrace function is @code(baktrace), which takes an integer argument telling how many levels to print. All of these things are set up by default when you start Nyquist. Since Nyquist sounds are executed with a lazy evaluation scheme, some errors are encountered when samples are being generated. In this case, it may not be clear which expression is in error. Sometimes, it is best to explore a function or set of functions by examining intermediate results. Any expression that yields a sound can be assigned to a variable and examined using one or more of: @code(s-plot), @code(snd-print-tree), and of course @code(play). The @code(snd-print-tree) function prints a lot of detail about the inner representaion of the sound. Keep in mind that if you assign a sound to a global variable and then look at the samples (e.g. with @code(play) or @code(s-plot)), the samples will be retained in memory. At 4 bytes per sample, a big sound may use all of your memory and cause a crash. Another technique is to use low sample rates so that it is easier to plot results or look at samples directly. The calls: @begin(example) set-sound-srate(100) set-control-srate(100) @end(example) set the default sample rates to 100, which is too slow for audio, but useful for examining programs and results. The function @begin(example) snd-samples(@i(sound), @i(limit)) @end(example) will convert up to @i(limit) samples from @i(sound) into a Lisp array. This is another way to look at results in detail. The @code(trace) function is sometimes useful. It prints the name of a function and its arguments everytimg the function is called, and the result is printed when the function exits. To trace the osc function, type: @begin(example) trace(osc) @end(example) and to stop tracing, type @code[untrace(osc)]. If a variable needs a value or a function is undefined, and if @code(*breakenable*) was set, you will get a prompt where you can fix the error (by setting the variable or loading the function definition) and keep going. At the debug (or break) prompt, your input must be in XLISP, not SAL syntax. Use @code[(co)], short for @code[(continue)] to reevaluate the variable or function and continue execution. When you finish debugging a particular call, you can ``pop'' up to the top level by typing @code[(top)], a short name for @code[(top-level)]. There is a button named "Top" in the NyquistIDE that takes you back to the top level (ready to accept XLISP expressions), and another button named "SAL" that puts you back in SAL mode. @section(Useful Functions) @begin(fndefs) @codef[grindef(@pragma(defn)@index(grindef)@index(listing of lisp function)@i(name))]@\Prints a formatted listing of a lisp function. This is often useful to quickly inspect a function without searching for it in source files. Do not forget to quote the name, e.g. @code[(grindef 'prod)]. @codef[args(@pragma(defn)@index(args)@index(arguments to a lisp function)@i(name))]@\Similar to @code(grindef), this function prints the arguments to a function. This may be faster than looking up a function in the documentation if you just need a reminder. For example, @code[(args 'lp)] prints ``(LP S C),'' which may help you to remember that the arguments are a sound (S) followed by the cutoff (C) frequency. @end(fndefs) The following functions are useful short-cuts that might have been included in XLISP. They are so useful that they are defined as part of Nyquist. @begin(fndefs) @codef[incf(@pragma(defn)@index(incf)@index(increment)@i(symbol))]@\Increment @i(symbol) by one. This is a macro, and @i(symbol) can be anything that can be set by @code(setf). Typically, @i(symbol) is a variable: ``@code[(incf i)],'' but @i(symbol) can also be an array element: ``@code[(incf (aref myarray i))].'' @codef[decf(@pragma(defn)@index(decf)@index(decrement)@i(symbol))]@\Decrement @i(symbol) by one. (See @code(incf), above.) @codef[push(@pragma(defn)@index(push)@i(val), @i(lis))]@\Push @i(val) onto @i(lis) (a Lisp list). This is a macro that is equivalent to writing @code[(setf @i(lis) (cons @i(val) @i(lis)))]. @codef[pop(@pragma(defn)@index(pop)@i(lis))]@\Remove (pop) the first item from @i(lis) (a Lisp list). This is a macro that is equivalent to writing @code[(setf @i(lis) (cdr @i(lis)))]. Note that the remaining list is returned, not the head of the list that has been popped. Retrieve the head of the list (i.e. the top of the stack) using @code(first) or, equivalently, @code(car). @end(fndefs) The following macros are useful control constructs. @begin(fndefs) @codef[while(@pragma(defn)@index(while)@i(test), @i(stmt1), @i(stmt2), ...)]@\A conventional ``while'' loop. If @i(test) is true, perform the statements (@i(stmt1), @i(stmt2), etc.) and repeat. If @i(test) is false, return. This expression evaluates to NIL unless the expression @code[(return @i(expr))] is evaluated, in which case the value of @i(expr) is returned. @codef[when(@pragma(defn)@index(when)@i(test), @i(action))]@\A conventional ``if-then'' statement. If @i(test) is true, @i(action) is evaluated and returned. Otherwise, NIL is returned. (Use @code(if) or @code(cond) to implement ``if-then-else'' and more complex conditional forms. @end(fndefs) It is often necessary to load a file @i(only if) it has not already been loaded. For example, the @code(pianosyn) library loads very slowly, so if some other file already loaded it, it would be good to avoid loading it again. How can you load a file once? Nyquist does not keep track of files that are loaded, but you must be loading a file to define some function, so the idea is to tell Nyquist "I require @i(function) from @i(file)"; if the function does not yet exist, Nyquist satisfies the requirement by loading the file. @begin(fndefs) @codef{require-from(@pragma(defn)@index(require-from)@index(load file conditionally)@i(fnsymbol), @i(filename) [, @i(path)])}@\Tests whether @i(fnsymbol), an unquoted function name, is defined. If not, @i(filename), a @code(STRING), is loaded. Normally @i(fnsymbol) is a function that will be called from within the current file, and @i(filename) is the file that defines @i(fnsymbol). The @i(path), if a @code(STRING), is prepended to @i(filename). If @i(path) is @code(t) (true), then the directory of the current file is used as the path. @end(fndefs) Sometimes it is important to load files relative to the current file. For example, the @code(lib/piano.lsp) library loads data files from the @code(lib/piano) directory, but how can we find out the full path of @code(lib)? The solution is: @begin(fndefs) @codef[current-path(@pragma(defn)@index(current-path)@index(path, current)@index(full path name))]@\Returns the full path name of the file that is currently being loaded (see @code(load)). Returns NIL if no file is being loaded. @end(fndefs) Finally, there are some helpful math functions: @begin(fndefs) @codef[real-random(@index(random)@index(uniform random)@pragma(defn)@index(real-random)@i(from), @i(to))]@\Returns a random @code(FLONUM) between @i(from) and @i(to). (See also @code(rrandom), which is equivalent to @code((real-random 0 1))). @codef[power(@pragma(defn)@index(power)@index(exponent)@i(x), @i(y))]@\Returns @i(x) raised to the @i(y) power. @end(fndefs) @chapter(Xmusic and Algorithmic Composition) @label(xmusic-sec) @index(Xmusic)@index(Algorithmic Composition) Several Nyquist libraries offer support for algorithmic composition. Xmusic is a library for generating sequences and patterns of data. Included in Xmusic is the @code(score-gen) macro which helps to generate scores from patterns. Another important facility is the @code(distributions.lsp) library, containing many different random number generators. @section(Xmusic Basics) Xmusic is inspired by and based on Common Music by Rick Taube. Currently, Xmusic only implements patterns and some simple support for scores to be realized as sound by Nyquist. In contrast, Common Music supports MIDI and various other synthesis languages and includes a graphical interface, some visualization tools, and many other features. Common Music runs in Common Lisp and Scheme, but not XLISP, which is the base language for Nyquist. Xmusic patterns are objects that generate data streams. For example, the @code(cycle-class) of objects generate cyclical patterns such as "1 2 3 1 2 3 1 2 3 ...", or "1 2 3 4 3 2 1 2 3 4 ...". Patterns can be used to specify pitch sequences, rhythm, loudness, and other parameters. Xmusic functions are automatically loaded when you start Nyquist. To use a pattern object, you first create the pattern, e.g. @begin(example) set pitch-source = make-cycle(list(c4, d4, e4, f4)) @end(example) After creating the pattern, you can access it repeatedly with @code(next)@index(next in pattern) to generate data, e.g. @begin(example) play seqrep(i, 13, pluck(next(pitch-source), 0.2)) @end(example) This will create a sequence of notes with the following pitches: c, d, e, f, c, d, e, f, c, d, e, f, c. If you evaluate this again, the pitch sequence will continue, starting on "d". It is very important not to confuse the creation of a sequence with its access. Consider this example: @begin(example) play seqrep(i, 13, pluck(next(make-cycle(list(c4, d4, e4, f4))), 0.2)) @end(example) This looks very much like the previous example, but it only repeats notes on middle-C. The reason is that every time @code(pluck) is evaluated, @code(make-cycle) is called and creates a new pattern object. After the first item of the pattern is extracted with @code(next), the cycle is not used again, and no other items are generated. To summarize this important point, there are two steps to using a pattern. First, the pattern is created and stored in a variable using @code(setf). Second, the pattern is accessed (multiple times) using @code(next). Patterns can be nested, that is, you can write patterns of patterns. In general, the @code(next) function does not return patterns. Instead, if the next item in a pattern is a (nested) pattern, @code(next) recursively gets the next item of the nested pattern. While you might expect that each call to @code(next) would advance the top-level pattern to the next item, and descend recursively if necessary to the inner-most nesting level, this is not how @code(next) works. Instead, @code(next) remembers the last top-level item, and if it was a pattern, @code(next) continues to generate items from that same inner pattern until the end of the inner pattern's @i(period) is reached. The next paragraph explains the concept of the @i(period). The data returned by a pattern object is structured into logical groups called @i(periods). You can get an entire period (as a list) by calling @code[next(@i(pattern), t)]@index(next pattern). For example: @begin(example) set pitch-source = make-cycle(list(c4, d4, e4, f4)) print next(pitch-source, t) @end(example) This prints the list @code[(60 62 64 65)], which is one period of the cycle. You can also get explicit markers that delineate periods by calling @code[send(@i(pattern), :next)]. In this case, the value returned is either the next item of the pattern, or the symbol @code(+eop+) if the end of a period has been reached. What determines a period? This is up to the specific pattern class, so see the documentation for specifics. You can override the ``natural'' period using the keyword @code(:for), e.g. @begin(example) set pitch-source = make-cycle(list(c4, d4, e4, f4), for: 3) print next(pitch-source, t) print next(pitch-source, t) @end(example) This prints the lists @code[(60 62 64) (65 60 62)]. Notice that these periods just restructure the stream of items into groups of 3. Nested patterns are probably easier to understand by example than by specification. Here is a simple nested pattern of cycles: @begin(example) set cycle-1 = make-cycle({a b c}) set cycle-2 = make-cycle({x y z}) set cycle-3 = make-cycle(list(cycle-1, cycle-2)) exec dotimes(i, 9, format(t, "~A ", next(cycle-3))) @end(example) This will print "A B C X Y Z A B C". Notice that the inner-most cycles @code(cycle-1) and @code(cycle-2) generate a period of items before the top-level @code(cycle-3) advances to the next pattern. Before describing specific pattern classes, there are several optional parameters that apply in the creating of any pattern object. These are: @begin(description, leftmargin +2 in, indent -2 in) @code(:for)@\The length of a period. This overrides the default by providing a numerical length. The value of this optional parameter may be a pattern that generates a sequence of integers that determine the length of each successive period. A period length may not be negative, but it may be zero. @code(:name)@\A pattern object may be given a name. This is useful if the @code(:trace) option is used. @code(:trace)@\If non-null, this optional parameter causes information about the pattern to be printed each time an item is generated from the pattern. @end(description) The built-in pattern classes are described in the following section. @section(Pattern Classes) @subsection(cycle) The @code(cycle-class) iterates repeatedly through a list of items. For example, two periods of @code[make-cycle({a b c})] would be @code[(A B C) (A B C)]. @begin(fndefs) @codef{make-cycle(@pragma(defn)@index(make-cycle)@index(cycle pattern)@index(pattern, cycle)@i(items)[ ,for: @i(for)] [, name: @i(name),] [trace: @i(trace)])}@\Make a cycle pattern that iterates over @i(items). The default period length is the length of @i(items). (See above for a description of the optional parameters.) If @i(items) is a pattern, a period of the pattern becomes the list from which items are generated. The list is replaced every period of the cycle. @end(fndefs) @subsection(line) The @code(line-class) is similar to the cycle class, but when it reaches the end of the list of items, it simply repeats the last item in the list. For example, two periods of @code[make-line({a b c})] would be @code[(A B C) (C C C)]. @begin(fndefs) @codef{make-line(@pragma(defn)@index(make-line)@index(line pattern)@index(pattern, line)@i(items)[ ,for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Make a line pattern that iterates over @i(items). The default period length is the length of @i(items). As with @code(make-cycle), @i(items) may be a pattern. (See above for a description of the optional parameters.) @end(fndefs) @subsection(random) The @code(random-class) generates items at random from a list. The default selection is uniform random with replacement, but items may be further specified with a weight, a minimum repetition count, and a maximum repetition count. Weights give the relative probability of the selection of the item (with a default weight of one). The minimum count specifies how many times an item, once selected at random, will be repeated. The maximum count specifies the maximum number of times an item can be selected in a row. If an item has been generated @i(n) times in succession, and the maximum is equal to @i(n), then the item is disqualified in the next random selection. Weights (but not currently minima and maxima) can be patterns. The patterns (thus the weights) are recomputed every period. @begin(fndefs) @codef{make-random(@pragma(defn)@index(make-random)@index(random pattern)@index(pattern, random)@i(items)[ ,for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Make a random pattern that selects from @i(items). Any (or all) element(s) of @i(items) may be lists of the following form: @code{(@i(value) [:weight @i(weight)] [:min @i(mincount)] [:max @i(maxcount)]}, where @i(value) is the item (or pattern) to be generated, @i(weight) is the relative probability of selecting this item, @i(mincount) is the minimum number of repetitions when this item is selected, and @i(maxcount) is the maximum number of repetitions allowed before selecting some other item. The default period length is the length of @i(items). If @i(items) is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. @end(fndefs) @subsection(palindrome) The @code(palindrome-class) repeatedly traverses a list forwards and then backwards. For example, two periods of @code[make-palindrome({a b c})] would be @code[(A B C C B A) (A B C C B A)]. The @code(:elide) keyword parameter controls whether the first and/or last elements are repeated: @begin(example) make-palindrome({a b c}, elide: nil) ;; generates A B C C B A A B C C B A ... make-palindrome({a b c}, elide: t) ;; generates A B C B A B C B ... make-palindrome({a b c}, elide: :first) ;; generates A B C C B A B C C B ... make-palindrome({a b c}, elide: :last) ;; generates A B C B A A B C B A ... @end(example) @begin(fndefs) @codef{make-palindrome(@pragma(defn)@index(make-palindrome)@index(palindrome pattern)@index(pattern, palindrome)@i(items)[ ,elide: @i(elide),] [for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Generate items from list alternating in-order and reverse-order sequencing. The keyword parameter @i(elide) can have the values @code(:first), @code(:last), @code(t), or @code(nil) to control repetition of the first and last elements. The @i(elide) parameter can also be a pattern, in which case it is evaluated every period. One period is one complete forward and backward traversal of the list. If @i(items) is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. @end(fndefs) @subsection(heap) The @code(heap-class) selects items in random order from a list without replacement, which means that all items are generated once before any item is repeated. For example, two periods of @code[make-heap({a b c})] might be @code[(C A B) (B A C)]. Normally, repetitions can occur even if all list elements are distinct. This happens when the last element of a period is chosen first in the next period. To avoid repetitions, the @code(:max) keyword argument can be set to 1. The @code(:max) keyword only controls repetitions from the end of one period to the beginning of the next. If the list contains more than one copy of the same value, it may be repeated within a period regardless of the value of @code(:max). @begin(fndefs) @codef{make-heap(@pragma(defn)@index(make-heap)@index(heap pattern)@index(pattern, heap)@i(items), [for: @i(for)] [, max: @i(max)] [, name: @i(name)] [, trace: @i(trace)])}@\Generate items randomly from list without replacement. If @i(max) is 1, the first element of a new period will not be the same as the last element of the previous period, avoiding repetition. The default value of @i(max) is 2, meaning repetition is allowed. The period length is the length of @i(items). If @i(items) is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. @end(fndefs) @subsection(accumulation) The @code(accumulation-class) takes a list of values and returns the first, followed by the first two, followed by the first three, etc. In other words, for each list item, return all items from the first through the item. For example, if the list is (A B C), each generated period is (A A B A B C). @begin(fndefs) @codef{make-accumulation(@pragma(defn)@index(make-accumulation)@index(accumulation pattern)@index(pattern, accumulation)@i(items)[ ,name: @i(name),] [trace: @i(trace)])}@\For each item, generate items from the first to the item including the item. The period length is (@i(n)@+(2) + @i(n)) / 2 where @i(n) is the length of @i(items). If @i(items) is a pattern, a period from that pattern becomes the list from which items are generated, and a new list is generated every period. Note that this is similar in name but different from @code(make-accumulate). @subsection(copier) The @code(copier-class) makes copies of periods from a sub-pattern. For example, three periods of @code[make-copier(make-cycle({a b c}, for: 1), repeat: 2, merge: t)] would be @code[(A A) (B B) (C C)]. Note that entire periods (not individual items) are repeated, so in this example the @code(:for) keyword was used to force periods to be of length one so that each item is repeated by the @code(:repeat) count. @codef{make-copier(@pragma(defn)@index(make-copier)@index(copier pattern)@index(pattern, copier)@i(sub-pattern)[ ,repeat: @i(repeat)] [, merge: @i(merge),] [for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Generate a period from @i(sub-pattern) and repeat it @i(repeat) times. If @i(merge) is false (the default), each repetition of a period from @i(sub-pattern) results in a period by default. If @i(merge) is true (non-null), then all @i(repeat) repetitions of the period are merged into one result period by default. If the @code(:for) keyword is used, the same items are generated, but the items are grouped into periods determined by the @code(:for) parameter. If the @code(:for) parameter is a pattern, it is evaluated every result period. The @i(repeat) and @i(merge) values may be patterns that return a repeat count and a boolean value, respectively. If so, these patterns are evaluated initially and after each @i(repeat) copies are made (independent of the @code(:for) keyword parameter, if any). The @i(repeat) value returned by a pattern can also be negative. A negative number indicates how many periods of @i(sub-pattern) to skip. After skipping these patterns, new @i(repeat) and @i(merge) values are generated. @end(fndefs) @subsection(accumulate) The @code(accumulate-class) forms the sum of numbers returned by another pattern. For example, each period of @code[make-accumulate(make-cycle({1 2 -3}))] is @code[(1 3 0)]. The default output period length is the length of the input period. @begin(fndefs) @codef{make-accumulate(@pragma(defn)@index(make-accumulate)@index(accumulate pattern)@index(pattern, accumulate)@i(sub-pattern)[ ,for: @i(for)] [, max: @i(maximum)] [, min: @i(minimum)] [, name: @i(name)] [, trace: @i(trace)])}@\Keep a running sum of numbers generated by @i(sub-pattern). The default period lengths match the period lengths from @i(sub-pattern). If @i(maximum) (a pattern or a number) is specified, and the running sum exceeds @i(maximum), the running sum is reset to @i(maximum). If @i(minimum) (a pattern or a number) is specified, and the running sum falls below @i(minimum), the running sum is reset to @i(minimum). If @i(minimum) is greater than @i(maximum), the running sum will be set to one of the two values. Note that this is similar in name but not in function to @code(make-accumulation). @end(fndefs) @subsection(sum) The @code(sum-class) forms the sum of numbers, one from each of two other patterns. For example, each period of @code[make-sum(make-cycle({1 2 3}), make-cycle({4 5 6}))] is @code[(5 7 9)]. The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number. @begin(fndefs) @codef{make-sum(@pragma(defn)@index(make-sum)@index(sum pattern)@index(pattern, sum)@i(x), @i(y)[ ,for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Form sums of items (which must be numbers) from pattern @i(x) and pattern or number @i(y). The default period lengths match the period lengths from @i(x). @end(fndefs) @subsection(product) The @code(product-class) forms the product of numbers, one from each of two other patterns. For example, each period of @code[make-product(make-cycle({1 2 3}), make-cycle({4 5 6}))] is @code[(4 10 18)]. The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number. @begin(fndefs) @codef{make-product(@pragma(defn)@index(make-product)@index(product pattern)@index(pattern, product)@i(x), @i(y)[ ,for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Form products of items (which must be numbers) from pattern @i(x) and pattern or number @i(y). The default period lengths match the period lengths from @i(x). @end(fndefs) @subsection(eval) The @code(eval-class) evaluates an expression to produce each output item. The default output period length is 1. @begin(fndefs) @codef{make-eval(@pragma(defn)@index(make-eval)@index(eval pattern)@index(pattern, eval)@index(expression pattern)@index(pattern, expression)@i(expr)[ ,for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Evaluate @i(expr) to generate each item. If @i(expr) is a pattern, each item is generated by getting the next item from @i(expr) and evaluating it. @end(fndefs) @subsection(length) The @code(length-class) generates periods of a specified length from another pattern. This is similar to using the @code(:for) keyword, but for many patterns, the @code(:for) parameter alters the points at which other patterns are generated. For example, if the palindrome pattern has an @code(:elide) pattern parameter, the value will be computed every period. If there is also a @code(:for) parameter with a value of 2, then @code(:elide) will be recomputed every 2 items. In contrast, if the palindrome (without a @code(:for) parameter) is embedded in a @i(length) pattern with a lenght of 2, then the periods will all be of length 2, but the items will come from default periods of the palindrome, and therefore the @code(:elide) values will be recomputed at the beginnings of default palindrome periods. @begin(fndefs) @codef{make-length(@index(length pattern)@index(pattern, length)@pragma(defn)@index(make-length)@i(pattern), @i(length-pattern), [name: @i(name)] [, trace: @i(trace)])}@\Make a pattern of class @code(length-class) that regroups items generated by a @i(pattern) according to pattern lengths given by @i(length-pattern). Note that @i(length-pattern) is not optional: There is no default pattern length and no @code(:for) keyword. @end(fndefs) @subsection(window) The @code(window-class) groups items from another pattern by using a sliding window. If the @i(skip) value is 1, each output period is formed by dropping the first item of the previous perioda and appending the next item from the pattern. The @i(skip) value and the output period length can change every period. For a simple example, if the period length is 3 and the skip value is 1, and the input pattern generates the sequence A, B, C, ..., then the output periods will be (A B C), (B C D), (C D E), (D E F), .... @begin(fndefs) @codef{make-window(@index(window pattern)@index(pattern, window)@pragma(defn)@index(make-window)@i(pattern), @i(length-pattern), @i(skip-pattern)[ ,name: @i(name)] [, trace: @i(trace)])}@\Make a pattern of class @code(window-class) that regroups items generated by a @i(pattern) according to pattern lengths given by @i(length-pattern) and where the period advances by the number of items given by @i(skip-pattern). Note that @i(length-pattern) is not optional: There is no default pattern length and no @code(:for) keyword. @end(fndefs) @subsection(markov) The @code(markov-class) generates items from a Markov model. A Markov model generates a sequence of @i(states) according to rules which specify possible future states given the most recent states in the past. For example, states might be pitches, and each pitch might lead to a choice of pitches for the next state. In the @code(markov-class), states can be either symbols or numbers, but not arbitrary values or patterns. This makes it easier to specify rules. However, symbols can be mapped to arbitrary values including pattern objects, and these become the actual generated items. By default, all future states are weighted equally, but weights may be associated with future states. A Markov model must be initialized with a sequence of past states using the @code(:past) keyword. The most common form of Markov model is a "first order Markov model" in which the future item depends only upon one past item. However, higher order models where the future items depend on two or more past items are possible. A "zero-order" Markov model, which depends on no past states, is essentially equivalent to the random pattern. As an example of a first-order Markov pattern, two periods of @code[make-markov({{a -> b c} {b -> c} {c -> a}}, past: {a})] might be @code[(C A C) (A B C)]. @begin(fndefs) @codef{make-markov(@pragma(defn)@index(make-markov)@index(markov pattern)@index(pattern, markov)@i(rules)[ ,past: @i(past)] [, produces: @i(produces),] [for: @i(for)] [, name: @i(name)] [, trace: @i(trace)])}@\Generate a sequence of items from a Markov process. The @i(rules) parameter has the form: @code[(@i(prev1) @i(prev2) ... @i(prevn) -> @i(next1) @i(next2) ... @i(nextn))] where @i(prev1) through @i(prevn) represent a sequence of most recent (past) states. The symbol @code(*) is treated specially: it matches any previous state. If @i(prev1) through @i(prevn) (which may be just one state as in the example above) match the previously generated states, this rule applies. Note that every rule must specify the same number of previous states; this number is known as the order of the Markov model. The first rule in @i(rules) that applies is used to select the next state. If no rule applies, the next state is @code(NIL) (which is a valid state that can be used in rules). Assuming a rule applies, the list of possible next states is specified by @i(next1) through @i(nextn). Notice that these are alternative choices for the next state, not a sequence of future states, and each rule can have any number of choices. Each choice may be the state itself (a symbol or a number), or the choice may be a list consisting of the state and a weight. The weight may be given by a pattern, in which case the next item of the pattern is obtained every time the rule is applied. For example, this rules says that if the previous states were A and B, the next state can be A with a weight of 0.5 or C with an implied weight of 1: @code[(A B -> (A 0.5) C)]. The default length of the period is the length of @i(rules). The @i(past) parameter must be provided. It is a list of states whose length matches the order of the Markov model. The keyword parameter @i(produces) may be used to map from state symbols or numbers to other values or patterns. The parameter is a list of alternating symbols and values. For example, to map A to 69 and B to 71, use @code[list(quote(a), 69, quote(b), 71)]. You can also map symbols to patterns, for example @code[list(quote(a), make-cycle({57 69}), quote(b), make-random({59 71}))]. The next item of the pattern is is generated each time the Markov model generates the corresponding state. Finally, the @i(produces) keyword can be @code(:eval), which means to evaluate the Markov model state. This could be useful if states are Nyquist global variables such as @code(C4, CS4, D4, ]..., which evaluate to numerical values (60, 61, 62, ...). @codef{markov-create-rules(@pragma(defn)@index(markov-create-rules)@index(markov analysis)@i(sequence), @i(order)[ ,@i(generalize)])}@\Generate a set of rules suitable for the @code(make-markov) function. The @i(sequence) is a ``typical'' sequence of states, and @i(order) is the order of the Markov model. It is often the case that a sample sequence will not have a transition from the last state to any other state, so the generated Markov model can reach a ``dead end'' where no rule applies. This might lead to an infinite stream of NIL's. To avoid this, the optional parameter @i(generalize) can be set to @code(t) (true), indicating that there should be a fallback rule that matches any previous states and whose future states are weighted according to their frequency in @i(sequence). For example, if sequence contains 5 A's, 5 B's and 10 G's, the default rule will be @code[(* -> (A 5) (B 5) (G 10))]. This rule will be appended to the end so it will only apply if no other rule does. @end(fndefs) @section(Random Number Generators) @index(random)@index(probability distributions)@index(distributions, probability)@index(stochastic functions) The @code(distributions.lsp) library implements random number generators that return random values with various probability distributions. Without this library, you can generate random numbers with @i(uniform) distributions. In a uniform distribution, all values are equally likely. To generate a random integer in some range, use @code(random). To generate a real number (FLONUM) in some range, use @code(real-random) (or @code(rrandom) if the range is 0-1). But there are other interesting distributions. For example, the Gaussian distribution is often used to model real-world errors and fluctuations where values are clustered around some central value and large deviations are more unlikely than small ones. See Dennis Lorrain, "A Panoply of Stochastic 'Canons'," @i(Computer Music Journal) vol. 4, no. 1, 1980, pp. 53-81. In most of the random number generators described below, there are optional parameters to indicate a maximum and/or minimum value. These can be used to truncate the distribution. For example, if you basically want a Gaussian distribution, but you never want a value greater than 5, you can specify 5 as the maximum value. The upper and lower bounds are implemented simply by drawing a random number from the full distribution repeatedly until a number falling into the desired range is obtained. Therefore, if you select an acceptable range that is unlikely, it may take Nyquist a long time to find each acceptable random number. The intended use of the upper and lower bounds is to weed out values that are already fairly unlikely. @begin(fndefs) @codef[linear-dist(@pragma(defn)@index(linear-dist)@index(linear distribution)@i(g))]@\Return a @code(FLONUM) value from a linear distribution, where the probability of a value decreases linearly from zero to @i(g) which must be greater than zero. (See Figure @ref(linear-fig).) The linear distribution is useful for generating for generating time and pitch intervals. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "linear-fig.ps")) @html(

    ) @fillcaption(The Linear Distribution, @i(g) = 1.) @tag(linear-fig) @end(figure) @begin(fndefs) @codef{exponential-dist(@pragma(defn)@index(exponential-dist)@index(exponential distribution)@i(delta)[ ,@i(high)])}@\Return a @code(FLONUM) value from an exponential distribution. The initial downward slope is steeper with larger values of @i(delta), which must be greater than zero. (See Figure @ref(exponential-fig). The optional @i(high) parameter puts an artificial upper bound on the return value. The exponential distribution generates values greater than 0, and can be used to generate time intervals. Natural random intervals such as the time intervals between the release of atomic particles or the passing of yellow volkswagons in traffic have exponential distributions. The exponential distribution is memory-less: knowing that a random number from this distribution is greater than some value (e.g. a note duration is at least 1 second) tells you nothing new about how soon the note will end. This is a continuous distribution, but @code(geometric-dist) (described below) implements the discrete form. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "exponential-fig.ps")) @html(

    ) @fillcaption(The Exponential Distribution, @i(delta) = 1.) @tag(exponential-fig) @end(figure) @begin(fndefs) @codef{gamma-dist(@pragma(defn)@index(gamma-dist)@i(nu)[ ,@i(high)])}@\Return a @code(FLONUM) value from a Gamma distribution. The value is greater than zero, has a mean of @i(nu) (a @code(FIXNUM) greater than zero), and a mode (peak) of around @i(nu) - 1. The optional @i(high) parameter puts an artificial upper bound on the return value. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "gamma-fig.ps")) @html(

    ) @fillcaption(The Gamma Distribution, @i(nu) = 4.) @tag(gamma-fig) @end(figure) @begin(fndefs) @codef{bilateral-exponential-dist(@pragma(defn)@index(bilateral-exponential-dist)@index(bilateral exponential distribution)@i(xmu), @i(tau)[ ,@i(low)] [, @i(high)])}@\Returns a @code(FLONUM) value from a bilateral exponential distribution, where @i(xmu) is the center of the double exponential and @i(tau) controls the spread of the distribution. A larger @i(tau) gives a wider distribution (greater variance), and @i(tau) must be greater than zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. This distribution is similar to the exponential, except it is centered at 0 and can output negative values as well. Like the exponential, it can be used to generate time intervals; however, it might be necessary to add a lower bound so as not to compute a negative time interval. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "bilateral-fig.ps")) @html(

    ) @fillcaption(The Bilateral Exponential Distribution.) @tag(bilateral-fig) @end(figure) @begin(fndefs) @codef{cauchy-dist(@pragma(defn)@index(cauchy-dist)@index(cauchy distribution)@i(tau)[ ,@i(low)] [, @i(high)])}@\Returns a @code(FLONUM) from the Cauchy distribution, a symetric distribution with a high peak at zero and a width (variance) that increases with parameter @i(tau), which must be greater than zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "cauchy-fig.ps")) @html(

    ) @fillcaption(The Cauchy Distribution, @i(tau) = 1.) @tag(cauchy-fig) @end(figure) @begin(fndefs) @codef{hyperbolic-cosine-dist(@pragma(defn)@index(hyperbolic-cosine-dist) [@i(low)] [, @i(high)])}@\Returns a @code(FLONUM) value from the hyperbolic cosine distribution, a symetric distribution with its peak at zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "hyperbolic-fig.ps")) @html(

    ) @fillcaption(The Hyperbolic Cosine Distribution.) @tag(hyperbolic-fig) @end(figure) @begin(fndefs) @codef{logistic-dist(@pragma(defn)@index(logistic-dist)@index(logistic distribution)@i(alpha), @i(beta)[ ,@i(low)] [, @i(high)])}@\Returns a @code(FLONUM) value from the logistic distribution, which is symetric about the mean. The @i(alpha) parameter primarily affects dispersion (variance), with larger values resulting in values closer to the mean (less variance), and the @i(beta) parameter primarily influences the mean. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "logistic-fig.ps")) @html(

    ) @fillcaption(The Logistic Distribution, alpha = 1, beta = 2.) @tag(logistic-fig) @end(figure) @begin(fndefs) @codef{arc-sine-dist(@pragma(defn)@index(arc-sine-dist)@index(arcsine distribution))}@\Returns a @code(FLONUM) value from the arc sine distribution, which outputs values between 0 and 1. It is symetric about the mean of 1/2, but is more likely to generate values closer to 0 and 1. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "arcsine-fig.ps")) @html(

    ) @fillcaption(The Arc Sine Distribution.) @tag(arcsine-fig) @end(figure) @begin(fndefs) @codef{gaussian-dist(@index(Gaussian distribution)@pragma(defn)@index(gaussian-dist)@i(xmu), @i(sigma)[ ,@i(low)] [, @i(high)])}@\Returns a @code(FLONUM) value from the Gaussian or Gauss-Laplace distribution, a linear function of the normal distribution. It is symetric about the mean of @i(xmu), with a standard deviation of @i(sigma), which must be greater than zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "gaussian-fig.ps")) @html(

    ) @fillcaption{The Gauss-Laplace (Gaussian) Distribution, @i(xmu) = 0, @i(sigma) = 1.} @tag(gaussian-fig) @end(figure) @begin(fndefs) @codef{beta-dist(@index(beta distribution)@pragma(defn)@index(beta-dist)@i(a), @i(b))}@\Returns a @code(FLONUM) value from the Beta distribution. This distribution outputs values between 0 and 1, with outputs more likely to be close to 0 or 1. The parameter @i(a) controls the height (probability) of the right side of the distribution (at 1) and @i(b) controls the height of the left side (at 0). The distribution is symetric about 1/2 when @i(a) = @i(b). @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "beta-fig.ps")) @html(

    ) @fillcaption(The Beta Distribution, @i(alpha) = .5, @i(beta) = .25.) @tag(beta-fig) @end(figure) @begin(fndefs) @codef{bernoulli-dist(@index(Bernoulli distribution)@pragma(defn)@index(bernoulli-dist)@i(px1)[ ,@i(x1)] [, @i(x2)])}@\Returns either @i(x1) (default value is 1) with probability @i(px1) or @i(x2) (default value is 0) with probability 1 - @i(px1). The value of @i(px1) should be between 0 and 1. By convention, a result of @i(x1) is viewed as a success while @i(x2) is viewed as a failure. @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "bernoulli-fig.ps")) @html(

    ) @fillcaption(The Bernoulli Distribution, @i(px1) = .75.) @tag(bernoulli-fig) @end(figure) @begin(fndefs) @code{(binomial-dist@index(binomial distribution)@pragma(defn)@index(binomial-dist) @i(n) @i(p)}@\Returns a @code(FIXNUM) value from the binomial distribution, where @i(n) is the number of Bernoulli trials run (a @code(FIXNUM)) and @i(p) is the probability of success in the Bernoulli trial (a @code(FLONUM) from 0 to 1). The mean is the product of @i(n) and @i(p). @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "binomial-fig.ps")) @html(

    ) @fillcaption(The Binomial Distribution, @i(n) = 5, @i(p) = .5.) @tag(binomial-fig) @end(figure) @begin(fndefs) @codef{geometric-dist(@index(geometric distribution)@pragma(defn)@index(geometric-dist)@i(p))}@\Returns a @code(FIXNUM) value from the geometric distribution, which is defined as the number of failures before a success is achieved in a Bernoulli trial with probability of success @i(p) (a @code(FLONUM) from 0 to 1). @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "geometric-fig.ps")) @html(

    ) @fillcaption(The Geometric Distribution, @i(p) = .4.) @tag(geometric-fig) @end(figure) @begin(fndefs) @codef{poisson-dist(@index(Poisson distribution)@pragma(defn)@index(poisson-dist)@i(delta))}@\Returns a @code(FIXNUM) value from the Poisson distribution with a mean of @i(delta) (a @code(FIXNUM)). The Poisson distribution is often used to generate a sequence of time intervals, resulting in random but often pleasing rhythms. @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "poisson-fig.ps")) @html(

    ) @fillcaption(The Poisson Distribution, @i(delta) = 3.) @tag(poisson-fig) @end(figure) @begin(comment) ***************** Note: this should remain out of Nyquist until the granulate code is cleaned up (why are there separate functions for pitch-dist and len-dist instead of a single function where any parameter can be specified by a closure?) ***************** @begin(fndefs) @codef{pitch-dist-granulate(@pragma(defn)@index(pitch-dist-granulate)@index(granular synthesis)@i(filename), @i(grain-dur), @i(grain-dev), @i(ioi), @i(ioi-dev), @i(pitch-dist)[ ,@i(file-start)] [, @i(file-end)])}@\*** need to write this *** @i(filename) @dash name of the file @i(dist) @dash the distribution that determines the length of the grains @i(ioi) @dash the basic inter-onset-interval for grains @i(ioi-dev) @dash ioi is actually: ioi + random(0, ioi-dev) @i(pitch-dev) @dash grains are resampled at rate between 1 and pitch-dev @i(file-start) @dash when to start reading the file (an offset from start). The default is 0. @i(file-end) @dash when to stop reading the file (an offset from end) the default is 0 returns @dash a set of sound grains created from the input file This is a granular synthesis function based on the one by Roger B. Dannenberg. The pitch of the grains will be based on the distribution you give to it. The distribution must be passed in as a continuation. (len-dist-granulate @i(filename) @i(dist ioi ioi-dev) @i(pitch-dev) [@i(file-start)] [@i(file-end)]) @i(filename) @dash name of the file @i(grain-dur) the duration of a grain @i(grain-dev) grain dur is actually grain-dur + random(0, grain-dev) @i(ioi) the basic inter-onset-interval for grains @i(ioi-dev) ioi is actually: ioi + random(0, ioi-dev) @i(pitch-dist) the distribution of the alteration in pitch to the grains. The distribution values should be > 1. @i(file-start) when to start reading the file (an offset from start). The default is 0 @i(file-end) when to stop reading the file (an offset from end). The default is 0 returns a set of sound grains created from the input file This is a granular synthesis function based on the one by Roger B. Dannenberg. The length of the grains will be based on the distribution you give to it. The distribution must be passed in as a continuation. @end(fndefs) @end(comment) @section(Score Generation and Manipulation) A common application of pattern generators is to specify parameters for notes. (It should be understood that ``notes'' in this context means any Nyquist behavior, whether it represents a conventional note, an abstract sound object, or even some micro-sound event that is just a low-level component of a hierarchical sound organization. Similarly, ``score'' should be taken to mean a specification for a sequence of these ``notes.'') The @code(score-gen) macro (defined by loading @code(xm.lsp)) establishes a convention for representing scores and for generating them using patterns. The @code(timed-seq) macro, described in Section @ref(timed-seq-sec), already provides a way to represent a ``score'' as a list of expressions. The Xmusic representation goes a bit further by specifying that @i(all notes are specified by an alternation of keywords and values, where some keywords have specific meanings and interpretations.) The basic idea of @code(score-gen)@index(score-gen) is you provide a template for notes in a score as a set of keywords and values. For example, @begin(example) set pitch-pattern = make-cycle(list(c4, d4, e4, f4)) score-gen(dur: 0.4, name: quote(my-sound), pitch: next(pitch-pattern), score-len: 9) @end(example) generates a score of 9 notes as follows: @begin(example) ((0 0 (SCORE-BEGIN-END 0 3.6)) (0 0.4 (MY-SOUND :PITCH 60)) (0.4 0.4 (MY-SOUND :PITCH 62)) (0.8 0.4 (MY-SOUND :PITCH 64)) (1.2 0.4 (MY-SOUND :PITCH 65)) (1.6 0.4 (MY-SOUND :PITCH 60)) (2 0.4 (MY-SOUND :PITCH 62)) (2.4 0.4 (MY-SOUND :PITCH 64)) (2.8 0.4 (MY-SOUND :PITCH 65)) (3.2 0.4 (MY-SOUND :PITCH 60))) @end(example) The use of keywords like @code(:PITCH) helps to make scores readable and easy to process without specific knowledge of about the functions called in the score. For example, one could write a transpose operation to transform all the @code(:pitch) parameters in a score without having to know that pitch is the first parameter of @code(pluck) and the second parameter of @code(piano-note). Keyword parameters are also used to give flexibility to note specification with @code(score-gen). Since this approach requires the use of keywords, the next section is a brief explanation of how to define functions that use keyword parameters. @subsection(Keyword Parameters) @index(keyword parameters) @index(parameters, keyword) Keyword parameters are parameters whose presence is indicated by a special symbol, called a keyword, followed by the actual parameter. Keyword parameters in SAL have default values that are used if no actual parameter is provided by the caller of the function. (See Appendix @ref(xlisp-app) to learn about keywords in XLISP.) To specify that a parameter is a keyword parameter, use a keyword symbol (one that ends in a colon) followed by a default value. For example, here is a function that accepts keyword parameters and invokes the @code(pluck) function: @begin(example) define function k-pluck(pitch: 60, dur: 1) return pluck(pitch, dur) @end(example) Now, we can call k-pluck with keyword parameters. The keywords are simply the formal parameter names with a prepended colon character (@code(:pitch) and @code(:dur) in this example), so a function call would look like: @begin(example) pluck(pitch: c3, dur: 3) @end(example) Usually, it is best to give keyword parameters useful default values. That way, if a parameter such as @code(dur:) is missing, a reasonable default value (1) can be used automatically. It is never an error to omit a keyword parameter, but the called function can check to see if a keyword parameter was supplied or not. Because of default values, we can call @code[k-pluck(pitch: c3)] with no duration, @code[k-pluck(dur: 3)] with only a duration, or even @code[k-pluck()] with no parameters. In XLISP, there is additional syntax to specify an alternate symbol to be used as the keyword and to allow the called function to determine whether or not a keyword parameter was supplied, but these features are little-used. See the XLISP manual for details. @subsection(Using score-gen)@pragma(defn)@index(score-gen) The @code(score-gen) macro computes a score based on keyword parameters. Some keywords have a special meaning, while others are not interpreted but merely placed in the score. The resulting score can be synthesized using @code(timed-seq) (see Section @ref(timed-seq-sec)). The form of a call to @code(score-gen) is simply: @begin(fndefs) @codef[score-gen(@pragma(defn)@index(score-gen)@i(k1:) @i(e1), @i(k2:) @i(e2), ... )]@\where the @i(k)'s are keywords and the @i(e)'s are expressions. A score is generated by evaluating the expressions once for each note and constructing a list of keyword-value pairs. A number of keywords have special interpretations. The rules for interpreting these parameters will be explained through a set of "How do I ..." questions below. @end(fndefs) @i(How many notes will be generated?) The keyword parameter @code(:score-len) specifies an upper bound on the number of notes. The keyword @code(:score-dur) specifies an upper bound on the starting time of the last note in the score. (To be more precise, the @code(:score-dur) bound is reached when the default starting time of the next note is greater than or equal to the @code(:score-dur) value. This definition is necessary because note times are not strictly increasing.) When either bound is reached, score generation ends. At least one of these two parameters must be specified or an error is raised. These keyword parameters are evaluated just once and are not copied into the parameter lists of generated notes. @i(What is the duration of generated notes?) The keyword @code(:dur) defaults to 1 and specifies the nominal duration in seconds. Since the generated note list is compatible with @code(timed-seq), the starting time and duration (to be precise, the @i(stretch factor)) are not passed as parameters to the notes. Instead, they control the Nyquist environment in which the note will be evaluated. @i(What is the start time of a note?) The default start time of the first note is zero. Given a note, the default start time of the next note is the start time plus the inter-onset time, which is given by the @code(:ioi) parameter. If no @code(:ioi) parameter is specified, the inter-onset time defaults to the duration, given by @code(:dur). In all cases, the default start time of a note can be overridden by the keyword parameter @code(:time). @i(When does the score begin and end?) The behavior @code[SCORE-BEGIN-END] contains the beginning and ending of the score (these are used for score manipulations, e.g. when scores are merged, their begin times can be aligned.) When @code(timed-seq) is used to synthesize a score, the @code(SCORE-BEGIN-END) marker is not evaluated. The @code(score-gen) macro inserts a ``note'' of the form @code[(0 0 (SCORE-BEGIN-END @i(begin-time) @i(end-time)))] at the time given by the @code(:begin) keyword, with @i(begin-time) and @i(end-time) determined by the @code(:begin) and @code(:end) keyword parameters, respectively. If the @i(:begin) keyword is not provided, the score begins at zero. If the @code(:end) keyword is not provided, the score ends at the default start time of what would be the next note after the last note in the score (as described in the previous paragraph). Note: if @code(:time) is used to compute note starting times, and these times are not increasing, it is strongly advised to use @code(:end) to specify an end time for the score, because the default end time may be anywhere in the middle of the generated sequence. @i(What function is called to synthesize the note?) The @code(:name) parameter names the function. Like other parameters, the value can be any expression, including something like @code[next(fn-name-pattern)], allowing function names to be recomputed for each note. The default value is @code(note). @i(Can I make parameters depend upon the starting time or the duration of the note?) Parameter expressions can use the variable @code(sg:time) to access the start time of the note, @code(sg:ioi) to access the inter-onset time, and @code(sg:dur) to access the duration (stretch factor) of the note. Also, @code(sg:count) counts how many notes have been computed so far, starting at 0. The order of computation is: @code(sg:time) first, then @code(sg:ioi) and @code(sg:dur), so for example, an expression to compute @code(sg:dur) can depend on @code(sg:ioi). @i(Can parameters depend on each other?) The keyword @code(:pre) introduces an expression that is evaluated before each note, and @code(:post) provides an expression to be evaluated after each note. The @code(:pre) expression can assign one or more global variables which are then used in one or more expressions for parameters. @i(How do I debug @code(score-gen) expressions?) You can set the @code(:trace) parameter to true (@code(t)) to enable a print statement for each generated note. @i(How can I save scores generated by @code(score-gen) that I like?) If the keyword parameter @code(:save) is set to a symbol, the global variable named by the symbol is set to the value of the generated sequence. Of course, the value returned by @code(score-gen) is just an ordinary list that can be saved like any other value. In summary, the following keywords have special interpretations in @code(score-gen): @code(:begin), @code(:end), @code(:time), @code(:dur), @code(:name), @code(:ioi), @code(:trace), @code(:save), @code(:score-len), @code(:score-dur), @code(:pre), @code(:post). All other keyword parameters are expressions that are evaluated once for each note and become the parameters of the notes. @subsection(Score Manipulation) @index(score manipulation)@index(manipulation of scores) Nyquist encourages the representation of music as executable programs, or @i(behaviors), and there are various ways to modify behaviors, including time stretching, transposition, etc. An alternative to composing executable programs is to manipulate scores as editable data. Each approach has its strengths and weaknesses. This section describes functions intended to manipulate Xmusic scores as generated by, or at least in the form generated by, @code(score-gen). Recall that this means scores are lists of events (e.g. notes), where events are three-element lists of the form (@i(time) @i(duration) @i(expression), and where @i(expression) is a standard lisp function call where all parameters are keyword parameters. In addition, the first ``note'' may be the special @code(SCORE-BEGIN-END) expression. If this is missing, the score begins at zero and ends at the end of the last note. For convenience, a set of functions is offered to access properties of events (or notes) in scores. Although lisp functions such as @code(car), @code(cadr), and @code(caddr) can be used, code is more readable when more mnemonic functions are used to access events. @begin(fndefs) @codef[event-time(@pragma(defn)@index(event-time)@i(event))]@\Retrieve the time field from an event. @codef[event-set-time(@pragma(defn)@index(event-set-time)@i(event), @i(time))]@\Construct a new event where the time of @i(event) is replaced by @i(time). @codef[event-dur(@pragma(defn)@index(event-dur)@i(event))]@\Retrieve the duration (i.e. the stretch factor) field from an event. @codef[event-set-dur(@pragma(defn)@index(event-set-dur)@i(event), @i(dur))]@\Construct a new event where the duration (or stretch factor) of @i(event) is replaced by @i(dur). @codef[event-expression(@pragma(defn)@index(event-expression)@i(event))]@\Retrieve the expression field from an event. @codef[event-set-expression(@pragma(defn)@index(event-set-expression)@i(event), @i(dur))]@\Construct a new event where the expression of @i(event) is replaced by @i(expression). @codef[event-end(@pragma(defn)@index(event-end)@i(event))]@\Retrieve the end time of @i(event), its time plus its duration. @codef[expr-has-attr(@pragma(defn)@index(expr-has-attr)@i(expression), @i(attribute))]@\Test whether a score event @i(expression) has the given @i(attribute). @codef{expr-get-attr(@pragma(defn)@index(expr-get-attr)@i(expression), @i(attribute), [@i(default)])}@\Get the value of the given @i(attribute) from a score event @i(expression). If @i(attribute) is not present, return @i(default) if specified, and otherwise @code(nil). @codef{expr-set-attr(@pragma(defn)@index(expr-set-attr)@i(expr), @i(attribute), @i(value))}@\Construct a new expression identical to @i(expr) except that the @i(attribute) has @i(value). @codef[event-has-attr(@pragma(defn)@index(event-has-attr)@i(event), @i(attribute))]@\Test whether a given score @i(event)'s expression has the given @i(attribute). @codef{event-get-attr(@pragma(defn)@index(event-get-attr)@i(event), @i(attribute), [@i(default)])}@\Get the value of the given @i(attribute) from a score @i(event)'s expression. If @i(attribute) is not present, return @i(default) if specified, and otherwise @code(nil). @codef{event-set-attr(@pragma(defn)@index(event-set-attr)@i(event), @i(attribute), @i(value))}@\Construct a new event identical to @i(event) except that the @i(attribute) has @i(value). @end(fndefs) Functions are provided to shift the starting times of notes, stretch times and durations, stretch only durations, add an offset to a keyword parameter, scale a keyword parameter, and other manipulations. Functions are also provided to extract ranges of notes, notes that match criteria, and to combine scores. Most of these functions (listed below in detail) share a set of keyword parameters that optionally limit the range over which the transformation operates. The @code(:from-index) and @code(:to-index) parameters specify the index of the first note and the index of the last note to be changed. If these numbers are negative, they are offsets from the end of the score, e.g. -1 denotes the last note of the score. The @code(:from-time) and @code(:to-time) indicate a range of starting times of notes that will be affected by the manipulation. Only notes whose time is greater than or equal to the @i(from-time) and @i(strictly less than) the @i(to-time) are modified. If both index and time ranges are specified, only notes that satisfy @i(both) constraints are selected. @begin(fndefs) @codef[score-sorted(@pragma(defn)@index(score-sorted)@i(score))]@\Test if @i(score) is sorted. @codef{score-sort(@pragma(defn)@index(score-sort)@i(score)[ ,@i(copy-flag)])}@\Sort the notes in a score into start-time order. If copy-flag is nil, this is a destructive operation which should only be performed if the top-level score list is a fresh copy that is not shared by any other variables. (The @i(copy-flag) is intended for internal system use only.) For the following operations, it is assumed that scores are sorted, and all operations return a sorted score. @codef{score-shift(@pragma(defn)@index(score-shift)@i(score), @i(offset)[ ,from-index: @i(i),] [to-index: @i(j)] [, from-time: @i(x)] [, to-time: @i(y)])}@\Add a constant @i(offset) to the starting time of a set of notes in @i(score). By default, all notes are modified, but the range of notes can be limited with the keyword parameters. The begin time of the score is not changed, but the end time is increased by @i(offset). The original score is not modified, and a new score is returned. @codef{score-stretch(@pragma(defn)@index(score-stretch)@i(score), @i(factor), [dur: @i(dur-flag)] [, time: @i(time-flag)] [, from-index: @i(i),] [to-index: @i(j)] [, from-time: @i(x)] [, to-time: @i(y)])}@\Stretch note times and durations by @i(factor). The default @i(dur-flag) is non-null, but if @i(dur-flag) is null, the original durations are retained and only times are stretched. Similarly, the default @i(time-flag) is non-null, but if @i(time-flag) is null, the original times are retained and only durations are stretched. If both @i(dur-flag) and @i(time-flag) are null, the score is not changed. If a range of notes is specified, times are scaled within that range, and notes after the range are shifted so that the stretched region does not create a "hole" or overlap with notes that follow. If the range begins or ends with a time (via @code(:from-time) and @code(:to-time)), time stretching takes place over the indicated time interval independent of whether any notes are present or where they start. In other words, the ``rests'' are stretched along with the notes. The original score is not modified, and a new score is returned. @codef{score-transpose(@pragma(defn)@index(score-transpose)@i(score), @i(keyword), @i(amount)[ ,from-index: @i(i),] [to-index: @i(j)] [, from-time: @i(x)] [, to-time: @i(y)])}@\For each note in the score and in any indicated range, if there is a keyword parameter matching @i(keyword) and the parameter value is a number, increment the parameter value by @i(amount). For example, to tranpose up by a whole step, write @code[(score-transpose 2 :pitch @i(score))]. The original score is not modified, and a new score is returned. @codef{score-scale(@pragma(defn)@index(score-scale)@i(score), @i(keyword), @i(amount), [from-index: @i(i),] [to-index: @i(j)] [, from-time: @i(x)] [, to-time: @i(y)])}@\For each note in the score and in any indicated range, if there is a keyword parameter matching @i(keyword) and the parameter value is a number, multiply the parameter value by @i(amount). The original score is not modified, and a new score is returned. @codef{score-sustain(@pragma(defn)@index(score-sustain)@i(score), @i(factor), [from-index: @i(i),] [to-index: @i(j)] [, from-time: @i(x)] [, to-time: @i(y)])}@\For each note in the score and in any indicated range, multiply the duration (stretch factor) by @i(amount). This can be used to make notes sound more legato or staccato, and does not change their starting times. The original score is not modified, and a new score is returned. @codef{score-voice(@pragma(defn)@index(score-voice)@i(score), @i(replacement-list), [from-index: @i(i),] [to-index: @i(j)] [, from-time: @i(x)] [, to-time: @i(y)])}@\For each note in the score and in any indicated range, replace the behavior (function) name using @i(replacement-list), which has the format: @code[((@i(old1 new1)) (@i(old2 new2)) ...)], where @i(oldi) indicates a current behavior name and @i(newi) is the replacement. If @i(oldi) is @code(*), it matches anything. For example, to replace @code(my-note-1) by @code(trombone) and @code(my-note-2) by @code(horn), use @code[score-voice(@i(score), {{my-note-1 trombone} {my-note-2 horn}})]. To replace all instruments with @code(piano), use @code[score-voice(@i(score), {{* piano}})]. The original score is not modified, and a new score is returned. @codef{score-merge(@pragma(defn)@index(score-merge)@i(score1), @i(score2), ...)}@\Create a new score containing all the notes of the parameters, which are all scores. The resulting notes retain their original times and durations. The merged score begin time is the minimum of the begin times of the parameters and the merged score end time is the maximum of the end times of the parameters. The original scores are not modified, and a new score is returned. @codef{score-append(@pragma(defn)@index(score-append)@i(score1), @i(score2), ...)}@\Create a new score containing all the notes of the parameters, which are all scores. The begin time of the first score is unaltered. The begin time of each other score is aligned to the end time of the previous score; thus, scores are ``spliced'' in sequence. The original scores are not modified, and a new score is returned. @codef{score-select(@pragma(defn)@index(score-select)@index(score-filter)@i(score), @i(predicate), [from-index: @i(i)] [, to-index: @i(j),] [from-time: @i(x)] [, to-time: @i(y)] [, reject: @i(flag)])}@\Select (or reject) notes to form a new score. Notes are selected if they fall into the given ranges of index and time @i(and) they satisfy @i(predicate), a function of three parameters that is applied to the start time, duration, and the expression of the note. Alternatively, @i(predicate) may be @code(t), indicating that all notes in range are to be selected. The selected notes along with the existing score begin and end markers, are combined to form a new score. Alternatively, if the @code(:reject) parameter is non-null, the notes @i(not) selected form the new score (in other words the selected notes are rejected or removed to form the new score). The original score is not modified, and a new score is returned. @codef{score-set-begin(@pragma(defn)@index(score-set-begin)@i(score), @i(time))}@\The begin time from the @i(score)'s @code(SCORE-BEGIN-END) marker is set to @i(time). The original score is not modified, and a new score is returned. @codef{score-get-begin(@pragma(defn)@index(score-get-begin)@i(score))}@\Return the begin time of the @i(score). @codef{score-set-end(@pragma(defn)@index(score-set-end)@i(score), @i(time))}@\The end time from the @i(score)'s @code(SCORE-BEGIN-END) marker is set to @i(time). The original score is not modified, and a new score is returned. @codef{score-get-end(@pragma(defn)@index(score-get-end)@i(score))}@\Return the end time of the @i(score). @codef{score-must-have-begin-end(@pragma(defn)@index(score-must-have-begin-end)@i(score))}@\If @i(score) does not have a begin and end time, construct a score with a @code(SCORE-BEGIN-END) expression and return it. If score already has a begin and end time, just return the score. The orignal score is not modified. @codef{score-filter-length(@pragma(defn)@index(score-filter-length)@i(score), @i(cutoff))}@\Remove notes that extend beyond the @i(cutoff) time. This is similar to @code(score-select), but the here, events are removed when their nominal ending time (start time plus duration) exceeds the @i(cutoff), whereas the @code(:to-time) parameter is compared to the note's start time. The original score is not modified, and a new score is returned. @codef{score-repeat(@pragma(defn)@index(score-repeat)@i(score), @i(n))}@\Make a sequence of @i(n) copies of @i(score). Each copy is shifted to that it's begin time aligns with the end time of the previous copy, as in @code(score-append). The original score is not modified, and a new score is returned. @codef{score-stretch-to-length(@pragma(defn)@index(score-stretch-to-length)@i(score), @i(length))}@\Stretch the score so that the end time of the score is the score's begin time plus @i(length). The original score is not modified, and a new score is returned. @codef{score-filter-overlap(@pragma(defn)@index(score-filter-overlap)@i(score))}@\Remove overlapping notes (based on the note start time and duration), giving priority to the positional order within the note list (which is also time order). The original score is not modified, and a new score is returned. @codef{score-print(@pragma(defn)@index(score-print)@i(score))}@\Print a score with one note per line. Returns @code(nil). @codef{score-play(@pragma(defn)@index(score-play)@i(score))}@\Play @i(score) using @code(timed-seq) to convert the score to a sound, and @code(play) to play the sound. @codef{score-adjacent-events(@pragma(defn)@index(score-adjacent-events)@i(score), @i(function), [from-index: @i(i)] [, to-index: @i(j),] [from-time: @i(x)] [, to-time: @i(y)])}@\Call @code[(@i(function) @i(A) @i(B) @i(C))], where @i(A), @i(B), and @i(C) are consecutive notes in the score. The result replaces @i(B). If the result is @code(nil), @i(B) is deleted, and the next call will be @code[(@i(function A C D))], etc. The first call is to @code[(@i(function) nil @i(A B))] and the last is to @code[(@i(function) @i(Y Z) nil)]. If there is just one note in the score, @code[(@i(function) nil @i(A) nil)] is called. Function calls are not made if the note is outside of the indicated range. This function allows notes and their parameters to be adjusted according to their immediate context. The original score is not modified, and a new score is returned. @codef{score-apply(@pragma(defn)@index(score-apply)@i(score), @i(function), [from-index: @i(i)] [, to-index: @i(j),] [from-time: @i(x)] [, to-time: @i(y)])}@\Replace each note in the score with the result of @code[(@i(function time dur expression))], where @i(time), @i(dur), and @i(expression) are the time, duration, and expression of the note. If a range is indicated, only notes in the range are replaced. The original score is not modified, and a new score is returned. @codef{score-indexof(@pragma(defn)@index(score-indexof)@i(score), @i(function), [from-index: @i(i)] [, to-index: @i(j),] [from-time: @i(x)] [, to-time: @i(y)])}@\Return the index (position) of the first score event (in range) for which applying @i(function) using @code[(@i(function time dur expression))] returns true. @codef{score-last-indexof(@pragma(defn)@index(score-last-indexof)@i(score), @i(function), [from-index: @i(i)] [, to-index: @i(j),] [from-time: @i(x)] [, to-time: @i(y)])}@\Return the index (position) of the last score event (in range) for which applying @i(function) using @code[(@i(function time dur expression))] returns true. @codef{score-randomize-start(@pragma(defn)@index(score-randomize-start)@index(jitter)@index(feel factor)@index(offset)@i(score), @i(amt)[ ,from-index: @i(i)] [, to-index: @i(j),] [from-time: @i(x)] [, to-time: @i(y)])}@\Alter the start times of notes by a random amount up to plus or minus @i(amt). The original score is not modified, and a new score is returned. @end(fndefs) @subsection(Xmusic and Standard MIDI Files) @index(MIDI file)@index(Standard MIDI File) Nyquist has a general facility to read and write MIDI files. You can even translate to and from a text representation, as described in Chapter @ref(adagio-chap). It is also useful sometimes to read notes from Standard MIDI Files into Xmusic scores and vice versa. At present, Xmusic only translates notes, ignoring the various controls, program changes, pitch bends, and other messages. MIDI notes are translated to Xmusic score events as follows: @begin(display) @code[(@i(time) @i(dur) (NOTE :chan @i(channel) :pitch @i(keynum) :vel @i(velocity)))], @end(display) where @i(channel), @i(keynum), and @i(velocity) come directly from the MIDI message (channels are numbered starting from zero). Note also that note-off messages are implied by the stretch factor @i(dur) which is duration in seconds. @begin(fndefs) @codef{score-read-smf(@pragma(defn)@index(score-read-smf)@index(midi file)@i(filename))}@\Read a standard MIDI file from @i(filename). Return an Xmusic score, or @code(nil) if the file could not be opened. The start time is zero, and the end time is the maximum end time of all notes. A very limited interface is offered to extract MIDI program numbers from the file: The global variable @code(*rslt*) is set to a list of MIDI program numbers for each channel. E.g. if @code(*rslt*) is @code[(0 20 77)], then program for channel 0 is 0, for channel 1 is 20, and for channel 2 is 77. Program changes were not found on other channels. The default program number is 0, so in this example, it is not known whether the program 0 on channel 0 is the result of a real MIDI program change command or just a default value. If more than one program change exists on a channel, the @i[last] program number is recorded and returned, so this information will only be completely correct when the MIDI file sends single program change per channel before any notes are played. This, however, is a fairly common practice. Note that the list returned as @code(*rslt*) can be passed to @code(score-write-smf), described below. @codef{score-write-smf(@pragma(defn)@index(score-write-smf)@index(midi file)@i(score), @i(filename), [@i(programs)])}@\Write a standard MIDI file to @i(filename) with notes in @i(score). In this function, @i(every) event in the score with a @code(:pitch) attribute, regardless of the ``instrument'' (or function name), generates a MIDI note, using the @code(:chan) attribute for the channel (default 0) and the @code(:vel) attribute for velocity (default 100). There is no facility (in the current implementation) to issue control changes, but to allow different instruments, MIDI programs may be set in two ways. The simplest is to associate programs with channels using the optional @i[programs] parameter, which is simply a list of up to 16 MIDI program numbers. Corresponding program change commands are added to the beginning of the MIDI file. If @i[programs] has less than 16 elements, program change commands are only sent on the first @i[n] channels. The second way to issue MIDI program changes is to add a @code(:program) keyword parameter to a note in the score. Typically, the note will have a @code(:pitch) of @code(nil) so that no actual MIDI note-on message is generated. If program changes and notes have the same starting times, their relative playback order is undefined, and the note may be cut off by an immediately following program change. Therefore, program changes should occur slightly, e.g. 1 ms, before any notes. @i(Program numbers and channels are numbered starting at zero, matching the internal MIDI representation. This may be one less than displayed on MIDI hardware, sequencers, etc.) @end(fndefs) @subsection(Workspaces) @label(workspaces-sec) @index(workspace) When working with scores, you may find it necessary to save them in files between work sessions. This is not an issue with functions because they are normally edited in files and loaded from them. In contrast, scores are created as Lisp data, and unless you take care to save them, they will be destroyed when you exit the Nyquist program. A simple mechanism called a workspace has been created to manage scores (and any other Lisp data, for that matter). A workspace is just a set of lisp global variables. These variables are stored in the file @code(workspace.lsp). For simplicity, there is only one workspace, and no backups or versions are maintained, but the user is free to make backups and copies of @code(workspace.lsp). To help remember what each variable is for, you can also associate and retrieve a text string with each variable. The following functions manage workspaces. In addition, when a workspace is loaded, you can request that functions be called. For example, the workspace might store descriptions of a graphical interface. When the workspace is loaded, a function might run to convert saved data into a graphical interface. (This is how sliders are saved by the IDE.) @begin(fndefs) @codef[add-to-workspace(@pragma(defn)@index(add-to-workspace)@i(symbol))]@\Adds a global variable to the workspace. The @i(symbol) should be a (quoted) symbol. @codef[save-workspace(@pragma(defn)@index(save-workspace))]@\All global variables in the workspace are saved to @code(workspace.lsp) (in the current directory), overwriting the previous file. @codef{describe(@pragma(defn)@index(describe)@i(symbol), [@i(description)])}@\If @i(description), a text string, is present, associate @i(description) with the variable named by the @i(symbol). If @i(symbol) is not already in the workspace, it is added. If @i(description) is omitted, the function returns the current description (from a previous call) for @i(symbol). @codef{add-action-to-workspace(@pragma(defn)@index(add-action-to-workspace)@i(symbol))}@\Requests that the function named by @i(symbol) be called when the workspace is loaded (if the function is defined). @end(fndefs) To restore a workspace, use the command @code[load "workspace"]. This restores the values of the workspace variables to the values they had when @code(save-workspace) was last called. It also restores the documentation strings, if set, by @code(describe). If you load two or more @code(workspace.lsp) files, the variables will be merged into a single workspace. The current set of workspace variables are saved in the list @code(*workspace*). To clear the workspace, set @code(*workspace*) to @code(nil). This does not delete any variables, but means that no variables will be saved by @code(save-workspace) until variables are added again. Functions to be called are saved in the list @code(*workspace-actions*). to clear the functions, set @code(*workspace-actions*) to @code(nil). Restore functions to the list with @code(add-action-to-workspace). @subsection(Utility Functions) This chapter concludes with details of various utility functions for score manipulation. @begin(fndefs) @codef[patternp(@pragma(defn)@index(patternp)@i(expression))]@\Test if @i(expression) is an Xmusic pattern. @codef[params-transpose(@pragma(defn)@index(params-transpose)@i(params), @i(keyword), @i(amount))]@\Add a transposition amount to a score event parameter. The @i(params) parameter is a list of keyword/value pairs (not preceded by a function name). The @i(keyword) is the keyword of the value to be altered, and @i(amount) is a number to be added to the value. If no matching keyword is present in @i(params), then @i(params) is returned. Otherwise, a new parameter list is constructed and returned. The original @i(params) is not changed. @codef[params-scale(@pragma(defn)@index(params-scale)@i(params), @i(keyword), @i(amount))]@\Scale a score event parameter by some factor. This is like @code(params-transpose), only using multiplication. The @i(params) list is a list of keyword/value pairs, @i(keyword) is the parameter keyword, and @i(amount) is the scale factor. @codef[interpolate(@pragma(defn)@index(interpolate)@index(linear interpolation)@i(x), @i(x1), @i(y1), @i(x2), @i(y2))]@\Linearly interpolate (or extrapolate) between points (@i(x1), @i(y1)) and (@i(x2), @i(y2)) to compute the y value corresponding to @i(x). @codef[intersection(@pragma(defn)@index(intersection)@index(set intersection)@i(a), @i(b))]@\Compute the set intersection of lists @i(a) and @i(b). @codef[union(@pragma(defn)@index(union)@index(set union)@i(a), @i(b))]@\Compute the set union of lists @i(a) and @i(b). @codef[set-difference(@index(difference)@pragma(defn)@index(set-difference)@i(a), @i(b))]@\Compute the set of all elements that are in @i(a) but not in @i(b). @codef[subsetp(@pragma(defn)@index(subsetp)@index(subset)@i(a), @i(b))]@\Returns true iff @i(a) is a subset of @i(b), that is, each element of @i(a) is a member of @i(b). @end(fndefs) @chapter(Nyquist Libraries) @index(libraries) Nyquist is always growing with new functions. Functions that are most fundamental are added to the core language. These functions are automatically loaded when you start Nyquist, and they are documented in the preceding chapters. Other functions seem less central and are implemented as lisp files that you can load. These are called library functions, and they are described here. To use a library function, you must first load the library, e.g. @code[(load "pianosyn")] loads the piano synthesis library. The libraries are all located in the @code(lib) directory, and you should therefore include this directory on your @code(XLISPPATH) variable. (See Section @ref(install-sec).) Each library is documented in one of the following sections. When you load the library described by the section, all functions documented in that section become available. @section(Piano Synthesizer) The piano synthesizer (library name is @code(pianosyn.lsp)) generates realistic piano tones using a multiple wavetable implementation by Zheng (Geoffrey) Hua and Jim Beauchamp, University of Illinois. Please see the notice about acknowledgements that prints when you load the file. Further informations and example code can be found in @code(demos/piano.htm)@index(demos, piano)@index(piano synthesizer tutorial). There are several useful functions in this library: @begin(fndefs) @codef[piano-note(@pragma(defn)@index(piano-note)@index(piano synthesizer)@i(duration), @i(step), @i(dynamic))]@\Synthesizes a piano tone. @i(Duration) is the duration to the point of key release, after which there is a rapid decay. @i(Step) is the pitch in half steps, and @i(dynamic) is approximately equivalent to a MIDI key velocity parameter. Use a value near 100 for a loud sound and near 10 for a soft sound. @codef[piano-note-2(@pragma(defn)@index(piano-note-2)@i(step), @i(dynamic))]@\Similar to @code(piano-note) except the duration is nominally 1.0. @codef[piano-midi(@pragma(defn)@index(piano-midi)@i(midi-file-name))]@\Use the piano synthesizer to play a MIDI file. The file name (a string) is given by @i(midi-file-name). @codef[piano-midi2file(@pragma(defn)@index(piano-midi2file)@i(midi-file-name), @i(sound-file-name))]@\Use the piano synthesizer to play a MIDI file. The MIDI file is given by @i(midi-file-name) and the (monophonic) result is written to the file named @i(sound-file-name). @end(fndefs) @section(Dymanics Compression) To use these functions, load the file @code(compress.lsp). This library implements a compressor originally intended for noisy speech audio, but usable in a variety of situations. There are actually two compressors that can be used in series. The first, @code(compress), is a fairly standard one: it detects signal level with an RMS detector and uses table-lookup to determine how much gain to place on the original signal at that point. One bit of cleverness here is that the RMS envelope is ``followed'' or enveloped using @code(snd-follow), which does look-ahead to anticipate peaks before they happen. The other interesting feature is @code(compress-map), which builds a map in terms of compression and expansion. For speech, the recommended procedure is to figure out the noise floor on the signal you are compressing (for example, look at the signal where the speaker is not talking). Use a compression map that leaves the noise alone and boosts signals that are well above the noise floor. Alas, the @code(compress-map) function is not written in these terms, so some head-scratching is involved, but the results are quite good. The second compressor is called @code(agc), and it implements automatic gain control that keeps peaks at or below 1.0. By combining @code(compress) and @code(agc), you can process poorly recorded speech for playback on low-quality speakers in noisy environments. The @code(compress) function modulates the short-term gain to to minimize the total dynamic range, keeping the speech at a generally loud level, and the @code(agc) function rides the long-term gain to set the overall level without clipping. @begin(fndefs) @codef{compress-map(@pragma(defn)@index(compress-map)@i(compress-ratio), @i(compress-threshold), @i(expand-ratio), @i(expand-ratio)[ ,limit: @i(limit)] [, transition: @i(transition)])}@\Construct a map for the compress function. The map consists of two parts: a compression part and an expansion part. The intended use is to compress everything above compress-threshold by compress-ratio, and to downward expand everything below expand-ratio by expand-ratio. Thresholds are in dB and ratios are dB-per-dB. 0dB corresponds to a peak amplitude of 1.0 or rms amplitude of 0.7 If the input goes above 0dB, the output can optionally be limited by setting @code(:limit) (a keyword parameter) to @code(T). This effectively changes the compression ratio to infinity at 0dB. If @code(:limit) is @code(nil) (the default), then the compression-ratio continues to apply above 0dB. Another keyword parameter, @code(:transition), sets the amount below the thresholds (in dB) that a smooth transition starts. The default is 0, meaning that there is no smooth transition. The smooth transition is a 2nd-order polynomial that matches the slopes of the straight-line compression curve and interpolates between them. It is assumed that expand-threshold <= compress-threshold <= 0 The gain is unity at 0dB so if compression-ratio > 1, then gain will be greater than unity below 0dB. The result returned by this function is a sound for use in the @code(shape) function. The sound maps input dB to gain. Time 1.0 corresponds to 0dB, time 0.0 corresponds to -100 dB, and time 2.0 corresponds to +100dB, so this is a 100hz ``sample rate'' sound. The sound gives gain in dB. @codef[db-average(@pragma(defn)@index(db-average)@i(input))]@\Compute the average amplitude of @i(input) in dB. @codef{compress(@pragma(defn)@index(compress)@i(input), @i(map), @i(rise-time), @i(fall-time), [@i(lookahead)])}@\Compress @i(input) using @i(map), a compression curve probably generated by @code(compress-map) (see above). Adjustments in gain have the given @i(rise-time) and @i(fall-time). Lookahead tells how far ahead to look at the signal, and is @i(rise-time) by default. @codef{agc(@index(automatic gain control)@pragma(defn)@index(agc)@index(gain)@i(input), @i(range), @i(rise-time), @i(fall-time)[ ,@i(lookahead)])}@\An automatic gain control applied to @i(input). The maximum gain in dB is @i(range). Peaks are attenuated to 1.0, and gain is controlled with the given @i(rise-time) and @i(fall-time). The look-ahead time default is @i(rise-time). @end(fndefs) @section(Clipping Softener) This library, in @code(soften.lsp), was written to improve the quality of poorly recorded speech. In recordings of speech, extreme clipping generates harsh high frequency noise. This can sound particulary bad on small speakers that will emphasize high frequencies. This problem can be ameliorated by low-pass filtering regions where clipping occurs. The effect is to dull the harsh clipping. Intelligibility is not affected by much, and the result can be much more pleasant on the ears. Clipping is detected simply by looking for large signal values. Assuming 8-bit recording, this level is set to 126/127. The function works by cross-fading between the normal signal and a filtered signal as opposed to changing filter coefficients. @begin(fndefs) @codef[soften-clipping(@pragma(defn)@index(soften-clipping)@index(clipping repair)@i(snd), @i(cutoff))]@\Filter the loud regions of a signal where clipping is likely to have generated additional high frequencies. The input signal is @i(snd) and @i(cutoff) is the filter cutoff frequency (4 kHz is recommended for speech). @end(fndefs) @section(Graphical Equalizer) There's nothing really ``graphical'' about this library (@code(grapheq.lsp)), but this is a common term for multi-band equalizers. This implementation uses Nyquist's @code(eq-band) function to split the incoming signal into different frequency bands. Bands are spaced geometrically, e.g. each band could be one octave, meaning that each successive band has twice the bandwidth. An interesting possibility is using computed control functions to make the equalization change over time. @begin(fndefs) @codef[nband-range(@pragma(defn)@index(nband-range)@index(graphical equalizer)@index(equalization)@i(input), @i(gains), @i(lowf), @i(highf))]@\A graphical equalizer applied to @i(input) (a @code(SOUND)). The gain controls and number of bands is given by @i(gains), an ARRAY of @code(SOUND)s (in other words, a Nyquist multichannel @code(SOUND)). Any sound in the array may be replaced by a @code(FLONUM). The bands are geometrically equally spaced from the lowest frequency @i(lowf) to the highest frequency @i(highf) (both are @code(FLONUM)s). @codef[nband(@pragma(defn)@index(nband)@i(input), @i(gains))]@\A graphical equalizer, identical to @code(nband-range) with a range of 20 to 20,000 Hz. @end(fndefs) @section(Sound Reversal) The @code(reverse.lsp) library implements functions to play sounds in reverse. @begin(fndefs) @codef[s-reverse(@index(reverse, sound)@pragma(defn)@index(s-reverse)@index(backward)@index(play in reverse)@i(snd))]@\Reverses @i(snd) (a @code(SOUND)). Sound must be shorter than @code(*max-reverse-samples*), which is currently initialized to 25 million samples. Reversal allocates about 4 bytes per sample. This function uses XLISP in the inner sample loop, so do not be surprised if it calls the garbage collector a lot and runs slowly. The result starts at the starting time given by the current environment (not necessarily the starting time of @i(snd)). If @i(snd) has multiple channels, a multiple channel, reversed sound is returned. @codef{s-read-reverse(@index(read samples in reverse)@pragma(defn)@index(s-read-reverse)@i(filename)[ ,time-offset: @i(offset)] [, srate: @i(sr)] [, dur: @i(dur)] [, nchans: @i(chans)] [, format: @i(format)] [, mode: @i(mode)] [, bits: @i(n)] [, swap: @i(flag)])}@\This function is identical to @code(s-read) (see @ref(s-read-sec)), except it reads the indicated samples in reverse. Like @code(s-reverse) (see above), it uses XLISP in the inner loop, so it is slow. Unlike @code(s-reverse), @code(s-read-reverse) uses a fixed amount of memory that is independent of how many samples are computed. Multiple channels are handled. @end(fndefs) @section(Time Delay Functions) The @code(time-delay-fns.lsp) library implements chorus, phaser, and flange effects. @begin(fndefs) @codef[phaser(@pragma(defn)@index(phaser)@index(effects, phaser)@i(snd))]@\A phaser effect applied to @i(snd) (a @code(SOUND)). There are no parameters, but feel free to modify the source code of this one-liner. @codef[flange(@pragma(defn)@index(flange)@index(flange effect)@index(effect, flange)@i(snd))]@\A flange effect applied to @i(snd). To vary the rate and other parameters, see the source code. @codef[stereo-chorus(@index(chorus)@pragma(defn)@index(stereo-chorus)@i(snd))]@\A chorus effect applied to @i(snd), a @code(SOUND) (monophonic). The output is a stereo sound. All parameters are built-in, but see the simple source code to make modifications. @codef[chorus(@pragma(defn)@index(chorus)@index(effect, chorus)@i(snd), @i(maxdepth), @i(depth), @i(rate), @i(saturation))]@\A chorus effect applied to @i(snd). All parameters may be arrays as usual. The @i(maxdepth) is a @code(FLONUM) giving twice the maximum value of @i(depth), which may be a @code(FLONUM) or a @code(SOUND). The chorus is implemented as a variable delay modulated by a sinusoid running at @i(rate) Hz (a @code(FLONUM)). The sinusoid is scaled by @i(depth) and offset by @i(maxdepth)/2. The delayed signal is mixed with the original, and @i(saturation) gives the fraction of the delayed signal (from 0 to 1) in the mix. A reasonable choice of parameter values is @i(maxdepth) = 0.05, @i(depth) = 0.025, @i(rate) = 0.5, and @i(saturation) = 0.5. @end(fndefs) @section(Multiple Band Effects) @index(multiple band effects)@index(bandfx.lsp) The @code(bandfx.lsp) library implements several effects based on multiple frequency bands. The idea is to separate a signal into different frequency bands, apply a slightly different effect to each band, and sum the effected bands back together to form the result. This file includes its own set of examples. After loading the file, try @code[f2()], @code[f3()], @code[f4()], and @code[f5()] to hear them. There is much room for expansion and experimentation with this library. Other effects might include distortion in certain bands (for example, there are commercial effects that add distortion to low frequencies to enhance the sound of the bass), separating bands into different channels for stereo or multi-channel effects, adding frequency-dependent reverb, and performing dynamic compression, limiting, or noise gate functions on each band. There are also opportunities for cross-synthesis: using the content of bands extracted from one signal to modify the bands of another. The simplest of these would be to apply amplitude envelopes of one sound to another. Please contact us (dannenberg@@cs.cmu.edu) if you are interested in working on this library. @begin(fndefs) @codef[apply-banded-delay( @index(banded delay)@pragma(defn)@index(apply-banded-delay)@i(s), @i(lowp), @i(highp), @i(num-bands), @i(lowd), @i(highd), @i(fb), @i(wet))]@\Separates input @code(SOUND) @i(s) into @code(FIXNUM) @i(num-bands) bands from a low frequency of @i(lowp) to a high frequency of @i(highp) (these are @code(FLONUMS) that specify steps, not Hz), and applies a delay to each band. The delay for the lowest band is given by the @code(FLONUM) @i(lowd) (in seconds) and the delay for the highest band is given by the @code(FLONUM) @i(highd). The delays for other bands are linearly interpolated between these values. Each delay has feedback gain controlled by @code(FLONUM) @i(fb). The delayed bands are scaled by @code(FLONUM) @i(wet), and the original sound is scaled by 1 - @i(wet). All are summed to form the result, a @code(SOUND). @codef[apply-banded-bass-boost(@index(banded bass boost)@pragma(defn)@index(apply-banded-bass-boost)@i(s), @i(lowp), @i(highp), @i(num-bands), @i(num-boost), @i(gain))]@\Applies a boost to low frequencies. Separates input @code(SOUND) @i(s) into @code(FIXNUM) @i(num-bands) bands from a low frequency of @i(lowp) to a high frequency of @i(highp) (these are @code(FLONUMS) that specify steps, not Hz), and scales the lowest @i(num-boost) (a @code(FIXNUM)) bands by @i(gain), a @code(FLONUM). The bands are summed to form the result, a @code(SOUND). @codef[apply-banded-treble-boost(@index(banded treble boost)@pragma(defn)@index(apply-banded-treble-boost)@i(s), @i(lowp), @i(highp), @i(num-bands), @i(num-boost), @i(gain))]@\Applies a boost to high frequencies. Separates input @code(SOUND) @i(s) into @code(FIXNUM) @i(num-bands) bands from a low frequency of @i(lowp) to a high frequency of @i(highp) (these are @code(FLONUMS) that specify steps, not Hz), and scales the highest @i(num-boost) (a @code(FIXNUM)) bands by @i(gain), a @code(FLONUM). The bands are summed to form the result, a @code(SOUND). @end(fndefs) @section(Granular Synthesis) Some granular synthesis functions are implemented in the @code(gran.lsp) library file. There are many variations and control schemes one could adopt for granular synthesis, so it is impossible to create a single universal granular synthesis function. One of the advantages of Nyquist is the integration of control and synthesis functions, and users are encouraged to build their own granular synthesis functions incorporating their own control schemes. The @code(gran.lsp) file includes many comments and is intended to be a useful starting point. Another possibility is to construct a score with an event for each grain. Estimate a few hundred bytes per score event (obviously, size depends on the number of parameters) and avoid using all of your computer's memory. @begin(fndefs) @codef{sf-granulate(@index(granular synthesis)@pragma(defn)@index(sf-granulate)@i(filename), @i(grain-dur), @i(grain-dev), @i(ioi), @i(ioi-dev), @i(pitch-dev), [@i(file-start)] [, @i(file-end)])}@\Granular synthesis using a sound file named @i(filename) as the source for grains. Grains are extracted from a sound file named by @i(filename) by stepping through the file in equal increments. Each grain duration is the sum of @i(grain-dur) and a random number from 0 to @i(grain-dev). Grains are then multiplied by a raised cosine smoothing window and resampled at a ratio between 1.0 and @i(pitch-dev). If @i(pitch-dev) is greater than one, grains are stretched and the pitch (if any) goes down. If @i(pitch-dev) is less than one, grains are shortened and the pitch goes up. Grains are then output with an inter-onset interval between successive grains (which may overlap) determined by the sum of @i(ioi) and a random number from 0 to @i(ioi-dev). The duration of the resulting sound is determined by the stretch factor (not by the sound file). The number of grains is the total sound duration (determined by the stretch factor) divided by the mean inter-onset interval, which is @i(ioi) + @i(ioi-dev) * 0.5. The grains are taken from equally-spaced starting points in @i(filename), and depending on grain size and number, the grains may or may not overlap. The output duration will simply be the sum of the inter-onset intervals and the duration of the last grain. If @i(ioi-dev) is non-zero, the output duration will vary, but the expected value of the duration is the stretch factor. To achieve a rich granular synthesis effect, it is often a good idea to sum four or more copies of @code(sf-granulate) together. (See the @code(gran-test) function in @code(gran.lsp).) @end(fndefs) @section(MIDI Utilities) The @code(midishow.lsp) library has functions that can print the contents fo MIDI files. This intended as a debugging aid. @begin(fndefs) @codef[midi-show-file(@pragma(defn)@index(midi-show-file)@index(print midi file)@index(show midi file)@i(file-name))]@\Print the contents of a MIDI file to the console. @codef{midi-show(@pragma(defn)@index(midi-show)@i(the-seq)[ ,@i(out-file)])}@\Print the contents of the sequence @i(the-seq) to the file @i(out-file) (whose default value is the console.) @end(fndefs) @section(Reverberation) The @code(reverb.lsp) library implements artificial reverberation. @begin(fndefs) @codef[reverb(@pragma(defn)@index(reverb)@index(effect, reverberation)@i(snd), @i(time))]@\Artificial reverberation applied to @i(snd) with a decay time of @i(time). @end(fndefs) @section(DTMF Encoding) @index(dtmf)@index(touch tone) The @code(dtmf.lsp) library implements DTMF encoding. DTMF is the ``touch tone'' code used by telephones. @begin(fndefs) @codef[dtmf-tone(@pragma(defn)@index(dtmf-tone)@i(key), @i(len), @i(space))]@\Generate a single DTMF tone. The @i(key) parameter is either a digit (a @code(FIXNUM) from 0 through 9) or the atom @code(STAR) or @code(POUND). The duration of the done is given by @i(len) (a @code(FLONUM)) and the tone is followed by silence of duration @i(space) (a @code(FLONUM)). @codef[speed-dial(@pragma(defn)@index(speed-dial)@i(thelist))]@\Generates a sequence of DTMF tones using the keys in @i(thelist) (a @code(LIST) of keys as described above under @code(dtmf-tone)). The duration of each tone is 0.2 seconds, and the space between tones is 0.1 second. Use @code(stretch) to change the ``dialing'' speed. @end(fndefs) @section[Dolby Surround(R), Stereo and Spatialization Effects] @index(spatialization)@index(stereo)@index(pan)@index(Dolby Surround) The @code(spatial.lsp) library implements various functions for stereo manipulation and spatialization. It also includes some functions for Dolby Pro-Logic panning, which encodes left, right, center, and surround channels into stereo. The stereo signal can then be played through a Dolby decoder to drive a surround speaker array. This library has a somewhat simplified encoder, so you should certainly test the output. Consider using a high-end encoder for critical work. There are a number of functions in @code(spatial.lsp) for testing. See the source code for comments about these. @begin(fndefs) @codef[stereoize(@pragma(defn)@index(stereoize)@index(mono to stereo)@index(effect, stereo)@i(snd))]@\Convert a mono sound, @i(snd), to stereo. Four bands of equalization and some delay are used to create a stereo effect. @codef[widen(@pragma(defn)@index(widen)@index(effect, widen)@i(snd), @i(amt))]@\Artificially widen the stereo field in @i(snd), a two-channel sound. The amount of widening is @i(amt), which varies from 0 (@i(snd) is unchanged) to 1 (maximum widening). The @i(amt) can be a @code(SOUND) or a number. @codef[span(@index(stereo pan)@index(pan, stereo)@index(effect, stereo pan)@pragma(defn)@index(span)@i(snd), @i(amt))]@\Pan the virtual center channel of a stereo sound, @i(snd), by @i(amt), where 0 pans all the way to the left, while 1 pans all the way to the right. The @i(amt) can be a @code(SOUND) or a number. @codef[swapchannels(@pragma(defn)@index(swapchannels)@index(swap channels)@index(effect, swap channels)@i(snd))]@\Swap left and right channels in @i(snd), a stereo sound. @codef[prologic(@pragma(defn)@index(prologic)@index(Dolby Pro-Logic)@index(Surround Sound)@i(l), @i(c), @i(r), @i(s))]@\Encode four monaural @code(SOUND)s representing the front-left, front-center, front-right, and rear channels, respectively. The return value is a stereo sound, which is a Dolby-encoded mix of the four input sounds. @codef[pl-left(@pragma(defn)@index(pl-left)@i(snd))]@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the front left channel. @codef[pl-center(@pragma(defn)@index(pl-center)@i(snd))]@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the front center channel. @codef[pl-right(@pragma(defn)@index(pl-right)@i(snd))]@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the front right channel. @codef[pl-rear(@pragma(defn)@index(pl-rear)@i(snd))]@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the rear, or surround, channel. @codef[pl-pan2d(@pragma(defn)@index(pl-pan2d)@i(snd), @i(x), @i(y))]@\Comparable to Nyquist's existing pan function, @code(pl-pan2d) provides not only left-to-right panning, but front-to-back panning as well. The function accepts three parameters: @i(snd) is the (monophonic) input @code(SOUND), @i(x) is a left-to-right position, and @i(y) is a front-to-back position. Both position parameters may be numbers or @code(SOUND)s. An @i(x) value of 0 means left, and 1 means right. Intermediate values map linearly between these extremes. Similarly, a @i(y) value of 0 causes the sound to play entirely through the front speakers(s), while 1 causes it to play entirely through the rear. Intermediate values map linearly. Note that, although there are usually two rear speakers in Pro-Logic systems, they are both driven by the same signal. Therefore any sound that is panned totally to the rear will be played over both rear speakers. For example, it is not possible to play a sound exclusively through the rear left speaker. @codef[pl-position(@pragma(defn)@index(pl-position)@i(snd), @i(x), @i(y), @i(config))]@\The position function builds upon speaker panning to allow more abstract placement of sounds. Like @code(pl-pan2d), it accepts a (monaural) input sound as well as left-to-right (@i(x)) and front-to-back (@i(y)) coordinates, which may be @code(FLONUM)s or @code(SOUND)s. A fourth parameter @i(config) specifies the distance from listeners to the speakers (in meters). Current settings assume this to be constant for all speakers, but this assumption can be changed easily (see comments in the code for more detail). There are several important differences between @code(pl-position) and @code(pl-pan2d). First, @code(pl-position) uses a Cartesian coordinate system that allows x and y coordinates outside of the range (0, 1). This model assumes a listener position of (0,0). Each speaker has a predefined position as well. The input sound's position, relative to the listener, is given by the vector (@i(x),@i(y)). @codef[pl-doppler(@pragma(defn)@index(pl-doppler)@index(Doppler effect)@i(snd), @i(r))]@\Pitch-shift moving sounds according to the equation: @i(fr) = @i(f0)((@i(c)+@i(vr))/@i(c)), where @i(fr) is the output frequency, @i(f0) is the emitted (source) frequency, @i(c) is the speed of sound (assumed to be 344.31 m/s), and @i(vr) is the speed at which the emitter approaches the receiver. (@i(vr) is the first derivative of parameter @i(r), the distance from the listener in meters. @end(fndefs) @section(Drum Machine) The drum machine software in @code(demos/plight) deserves further explanation. to use the software, load the code by evaluating: @begin(example) load "../demos/plight/drum.lsp" exec load-props-file(strcat(*plight-drum-path*, "beats.props")) exec create-drum-patches() exec create-patterns() @end(example) Drum sounds and patterns are specified in the @code(beats.props) file (or whatever name you give to @code(load-props-file)). This file contains two types of specifications. First, there are sound file specifications. Sound files are located by a line of the form: @begin(example) set sound-directory = "kit/" @end(example) This gives the name of the sound file directory, relative to the @code(beats.props) file. Then, for each sound file, there should be a line of the form: @begin(example) track.2.5 = big-tom-5.wav @end(example) This says that on track 2, a velocity value of 5 means to play the sound file @code(big-tom-5.wav). (Tracks and velocity values are described below.) The @code(beats.props) file contains specifications for all the sound files in @code(demos/plight/kit) using 8 tracks. If you make your own specifications file, tracks should be numbered consecutively from 1, and velocities should be in the range of 1 to 9. The second set of specifications is of beat patterns. A beat pattern is given by a line in the following form: @begin(example) beats.5 = 2--32--43-4-5--- @end(example) The number after @code(beats) is just a pattern number. Each pattern is given a unique number. After the equal sign, the digits and dashes are velocity values where a dash means ``no sound.'' Beat patterns should be numbered consecutively from 1. Once data is loaded, there are several functions to access drum patterns and create drum sounds (described below). The @code(demos/plight/drums.lsp) file contains an example function @code(plight-drum-example) to play some drums. There is also the file @code(demos/plight/beats.props) to serve as an example of how to specify sound files and beat patterns. @begin(fndefs) @codef{drum(@pragma(defn)@index(drum)@i(tracknum), @i(patternnum), @i(bpm))}@\Create a sound by playing drums sounds associated with track @i(tracknum) (a FIXNUM) using pattern @i(patternnum). The tempo is given by @i(bpm) in beats per minute. Normally patterns are a sequence of sixteenth notes, so the tempo is in @i(sixteenth notes per minute). For example, if @i(patternnum) is 10, then use the pattern specified for @code(beats.10). If the third character of this pattern is 3 and @i(tracknum) is 5, then on the third beat, play the soundfile assigned to @code(track.5.3). This function returns a @code(SOUND). @codef{drum-loop(@pragma(defn)@index(drum-loop)@i(snd), @i(duration), @i(numtimes))}@\Repeat the sound given by @i(snd) @i(numtimes) times. The repetitions occur at a time offset of @i(duration), regardless of the actual duration of @i(snd). A @code(SOUND) is returned. @codef{length-of-beat(@pragma(defn)@index(length-of-beat)@i(bpm))}@\Given a tempo of @i(bpm), return the duration of the beat in seconds. Note that this software has no real notion of beat. A ``beat'' is just the duration of each character in the beat pattern strings. This function returns a @code(FLONUM). @end(fndefs) @section(Minimoog-inspired Synthesis) @index(Moog)@index(Minimoog)@index(analog synthesizer) The @code(moog.lsp) library gives the Nyquist user easy access to ``classic'' synthesizer sounds through an emulation of the Minimoog Synthesizer. Unlike modular Moogs that were very large, the Minimoog was the first successful and commonly used portable synthesizer. The trademark filter attack was unique and easily recognizable. The goal of this Nyquist instrument is not only to provide the user with default sounds, but also to give control over many of the ``knobs'' found on the Minimoog. In this implementation, these parameters are controlled using keywords. The input to the @code(moog) instrument is a user-defined sequence of notes, durations, and articulations that simulate notes played on a keyboard. These are translated into control voltages that drive multiple oscillators, similar to the Voltage Controlled Oscillator or VCO found in the original analog Moog. The basic functionality of the Minimoog has been implemented, including the often-used "glide". The glide feature essentially low-pass filters the control voltage sequence in order to create sweeps between notes. Figure @ref(moog-fig) is a simplified schematic of the data flow in the Moog. The control lines have been omitted. @begin(figure) @center(@graphic((height = 2.514 in, width = 4.65 in, magnify = 0.3, postscript = "moog-fig.ps")) @html(

    ) @fillcaption(System diagram for Minimoog emulator.) @tag(moog-fig) @end(figure) The most recognizable feature of the Minimoog is its resonant filter, a Four-Pole Ladder Filter invented by Robert Moog. It is simply implemented in a circuit with four transistors and provides an outstanding 24 dB/octave rolloff. It is modeled here using the built-in Nyquist resonant filter. One of the Moog filter features is a constant Q, or center frequency to bandwidth ratio. This is implemented and the user can control the Q. The user can control many parameters using keywords. Their default values, acceptable ranges, and descriptions are shown below. The defaults were obtained by experimenting with the official Minimoog software synthesizer by Arturia. @subsection(Oscillator Parameters) @code(range-osc1) (2)@* @code(range-osc2) (1)@* @code(range-osc3) (3)@* These parameters control the octave of each oscillator. A value of 1 corresponds to the octave indicated by the input note. A value of 3 is two octaves above the fundamental. The allowable range is 1 to 7. @code(detun2) (-.035861)@* @code(detun3) (.0768)@* Detuning of two oscillators adds depth to the sound. A value of 1 corresponds to an increase of a single semitone and a -1 corresponds to a decrease in a semitone. The range is -1 to 1. @code(shape-osc1) (@code(*saw-table*))@* @code(shape-osc2) (@code(*saw-table*))@* @code(shape-osc3) (@code(*saw-table*))@* Oscilators can use any wave shape. The default sawtooth waveform is a built-in Nyquist variable. Other waveforms can be defined by the user. @code(volume-osc1) (1)@* @code(volume-osc2) (1)@* @code(volume-osc3) (1)@* These parameters control the relative volume of each oscillator. The range is any @code(FLONUM) greater than or equal to zero. @subsection(Noise Parameters) @code(noiselevel) (.05)@* This parameter controls the relative volume of the noise source. The range is any @code(FLONUM) greater than or equal to zero. @subsection(Filter Parameters) @code(filter-cutoff) (768)@* The cutoff frequency of the filter in given in Hz. The range is zero to 20,000 Hz. @code(Q) (2)@* Q is the ratio of center frequency to bandwidth. It is held constant by making the bandwidth a function of frequency. The range is any @code(FLONUM) greater than zero. @code(contour) (.65)@* Contour controls the range of the transient frequency sweep from a high to low cutoff frequency when a note is played. The high frequency is proportional to contour. A contour of 0 removes this sweep. The range is 0 to 1. @code(filter-attack) (.0001)@* Filter attack controls the attack time of the filter, i.e. the time to reach the high cutoff frequency. The range is any @code(FLONUM) greater than zero (seconds). @code(filter-decay) (.5)@* Filter decay controls the decay time of the filter, i.e. the time of the sweep from the high to low cutoff frequency. The range is any @code(FLONUM) greater than zero (seconds). @code(filter-sustain) (.8)@* Filter sustain controls the percentage of the filter cutoff frequency that the filter settles on following the sweep. The range is 0 to 1. @subsection(Amplitude Parameters) @code(amp-attack) (.01)@* This parameter controls the amplitude envelope attack time, i.e. the time to reach maximum amplitude. The range is any @code(FLONUM) greater than zero (seconds). @code(amp-decay) (1)@* This parameter controls the amplitude envelope decay time, i.e. the time between the maximum and sustain volumes. The range is any @code(FLONUM) greater than zero (seconds). @code(amp-sustain) (1)@* This parameter controls the amplitude envelope sustain volume, a fraction of the maximum. The range is 0 to 1. @code(amp-release) (0)@* This parameter controls the amplitude envelope release time, i.e. the time it takes between the sustain volume and 0 once the note ends. The duration controls the overall length of the sound. The range of @code(amp-release) is any @code(FLONUM) greater than zero (seconds). @subsection(Other Parameters) @code(glide) (0)@* Glide controls the low-pass filter on the control voltages. This models the glide knob on a Minimoog. A higher value corresponds to a lower cutoff frequency and hence a longer "glide" between notes. A value of 0 corresponds to no glide. The range is zero to 10. @subsection(Input Format) A single note or a series of notes can be input to the Moog instrument by defining a list with the following format: @begin(display) (list (list @i(frequency duration articulation)) ... ) @end(display) where @i(frequency) is a @code(FLONUM) in steps, @i(duration) is the duration of each note in seconds (regardless of the release time of the amplifier), and @i(articulation) is a percentage of the duration that a sound will be played, representing the amount of time that a key is pressed. The filter and amplitude envelopes are only triggered if a note is played when the articulation of the previous note is less than 1, or a key is not down at the same time. This Moog instrument is a monophonic instrument, so only one note can sound at a time. The release section of the amplifier is triggered when the articulation is less than 1 at the time (@i(duration) * @i(articulation)). @subsection(Sample Code/Sounds) @b[Sound 1 (default parameters):] @begin(display) @begin(code) set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99} {29 .5 .99} {31 2 1}} play moog(s) @end(code) @end(display) @b[Sound 2 (articulation, with amplitude release):] @begin(display) @begin(code) set s = {{24 .5 .5} {26 .5 1} {28 .5 .25} {29 .5 1} {31 1 .8}} play moog(s, amp-release: .2) @end(code) @end(display) @b[Sound 3 (glide):] @begin(display) @begin(code) set s = {{24 .5 .5} {38 .5 1} {40 .5 .25} {53 .5 1} {55 2 1} {31 2 .8} {36 2 .8}} play moog(s, amp-release: .2, glide: .5) @end(code) @end(display) @b[Sound 4 (keyword parameters):] Filter attack and decay are purposely longer than notes being played with articulation equal to 1. @begin(display) @begin(code) set s = {{20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1} {20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1}} play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*, filter-attack: 2, filter-decay: 2, filter-cutoff: 300, contour: .8, glide: .2, Q: 8) @end(code) @end(display) @b[Sound 5:] This example illustrates the ability to completely define a new synthesizer with different parameters creating a drastically different sound. Sine waves are used for wavetables. There is a high value for glide. @begin(display) @begin(code) define function my-moog(freq) return moog(freq, range-osc1: 3, range-osc2: 2, range-osc3: 4, detun2: -.043155, detun3: .015016, noiselevel: 0, filter-cutoff: 400, Q: .1, contour: .0000001, filter-attack: 0, filter-decay: .01, filter-sustain: 1, shape-osc1: *sine-table*, shape-osc2: *sine-table*, shape-osc3: *sine-table*, volume-osc1: 1, volume-osc2: 1, volume-osc3: .1, amp-attack: .1, amp-decay: 0, amp-sustain: 1, amp-release: .3, glide: 2) set s = {{80 .4 .75} {28 .2 1} {70 .5 1} {38 1 .5}} play my-moog(s) @end(code) @end(display) @b[Sound 6:] This example has another variation on the default parameters. @begin(display) @begin(code) set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99} {29 .5 .99} {31 2 1}} play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*, filter-attack: .5, contour: .5) @end(code) @end(display) @pragma(doinclude) @include(nymanimpl.mss) @appendix(Open Sound Control and Nyquist)@index(Open Sound Control) @label(osc-app) Open Sound Control (OSC) is a simple protocol for communicating music control parameters between software applications and across networks. For more information, see @html[
    ]@code(http://www.cnmat.berkeley.edu/OpenSoundControl/)@html[]. The Nyquist implementation of Open Sound Control is simple: an array of floats can be set by OSC messages and read by Nyquist functions. That is about all there is to it. Note: Open Sound Control must be enabled by calling @code[osc-enable(t)]. If this fails under Windows, see the installation instructions regarding @code(SystemRoot). To control something in (near) real-time, you need to access a slider value as if it a signal, or more properly, a Nyquist @code(SOUND) type. The function @code(snd-slider), described in Section @ref(snd-slider-sec), takes a slider number and returns a @code(SOUND) type representing the current value of the slider. To fully understand this function, you need to know something about how Nyquist is actually computing sounds. Sounds are normally computed on demand. So the result returned by @code(snd-slider) does not immediately compute any samples. Samples are only computed when something tries to use this signal. At that time, the slider value is read. Normally, if the slider is used to control a sound, you will hear changes in the sound pretty soon after the slider value changes. However, one thing that can interfere with this is that @code(SOUND) samples are computed in blocks of about 1000 samples. When the slider value is read, the same value is used to fill a block of 1000 samples, so even if the sample rate is 44,100 Hz, the effective slider sample rate is 44,100/1000, or 44.1 Hz. If you give the slider a very low sample rate, say 1000, then slider value changes will only be noticed by Nyquist approximately once per second. For this reason, you should normally use the audio sample rate (typically 44,100 Hz) for the rate of the @code(snd-slider) output @code(SOUND). (Yes, this is terribly wasteful to represent each slider value with 1000 samples, but Nyquist was not designed for low-latency computation, and this is an expedient work-around.) In addition to reading sliders as continually changing @code(SOUND)s, you can get the slider value as a Lisp @code(FLONUM) (a floating point number) using @code(get-slider-value), described in Section @ref(get-slider-value-sec). This might be useful if you are computing a sequence of many notes (or other sound events) and want to apply the current slider value to the whole note or sound event. Note that if you store the value returned by @code(snd-slider) in a variable, you will capture the history of the slider changes. This will take a lot of memory, so be careful. Suppose you write a simple expression such as @code[(hzosc (mult 1000 (snd-slider 0 ...)))] to control an oscillator frequency with a slider. How long does this sound last? The duration of @code[hzosc] is the duration of the frequency control, so what is the duration of a slider? To avoid infinitely long signals, you must specify a duration as one of the parameters of @code[snd-slider]. You might be thinking, what if I just want to tell the slider when to stop? At present, you cannot do that, but in the future there should be a function that stops when its input goes to zero. Then, moving a slider to zero could end the signal (and if you multiplied a complex sound by one of these ending functions, everything in the sound would end and be garbage collected). Another thing you might want to do with interactive control is start some sound. The @code(trigger) function computes an instance of a behavior each time an input @code(SOUND) goes from zero to greater-than-zero. This could be used, for example, to create a sequence of notes. The @code(snd-slider) function has some parameters that may be unfamiliar. The second parameter, @i(t0), is the starting time of the sound. This should normally be @code[local-to-global(0)], an expression that computes the instantiation time of the current expression. This will often be zero, but if you call @code[snd-slider] from inside a @code(seq) or @code(seq-rep), the starting time may not be zero. The @i(srate) parameter is the sample rate to return. This should normally be the audio sample rate you are working with, which is typically @code[*default-sound-srate*]. @section(Sending Open Sound Control Messages) A variety of programs support OSC. The only OSC message interpreted by Nyquist has an address of @code[/slider], and two parameters: an integer slider number and a float value, nominally from 0.0 to 1.0. Two small programs are included in the Nyquist distribution for sending OSC messages. (Both can be found in the same directory as the nyquist executable.) The first one, @code[osc-test-client] sends a sequence of messages that just cause slider 0 to ramp slowly up and down. If you run this on a command line, you can use "?" or "h" to get help information. There is an interactive mode that lets you send each OSC message by typing RETURN. @section(The ser-to-osc Program) The second program is @code[ser-to-osc], a program that reads serial input (for example from a PIC-based microcontroller) and sends OSC messages. Run this command-line program from a shell (a terminal window under OS X or Linux; use the CMD program under Windows). You must name the serial input device on the command line, e.g. under OS X, you might run: @begin(display) @code(./ser-to-osc /dev/tty.usbserial-0000103D) @end(display) (Note that the program name is preceded by ``@code(./)". This tells the shell exactly where to find the executable program in case the current directory is not on the search path for executable programs.) Under Windows, you might run: @begin(display) @code(ser-to-osc com4) @end(display) (Note that you do not type ``@code(./)'' in front of a windows program.) To use @code(ser-to-osc), you will have to find the serial device. On the Macintosh and Linux, try the following: @begin(display) @code(ls /dev/*usb*) @end(display) This will list all serial devices with ``usb'' in their names. Probably, one will be a name similar to @code(/dev/tty.usbserial-0000103D). The @code(ser-to-osc) program will echo data that it receives, so you should know if things are working correctly. Under Windows, open Control Panel from the Start menu, and open the System control panel. Select the Hardware tab and click the Device Manager button. Look in the device list under Ports (COM & LPT). When you plug in your serial or USB device, you should see a new entry appear, e.g. @code(COM4). This is the device name you need. The format for the serial input is: any non-whitespace character(s), a slider number, a slider value, and a newline (control-j or ASCII 0x0A). These fields need to be separated by tabs or spaces. An optional carriage return (control-m or ASCII 0x0D) preceding the ASCII 0x0A is ignored. The slider number should be in decimal, and theh slider value is a decimal number from 0 to 255. This is scaled to the range 0.0 to 1.0 (so an input of 255 translates to 1.0). There is a simple test program in @code[demos/osc-test.lsp] you can run to try out control with Open Sound Control. There are two examples in that file. One uses @code(snd-slider) to control the frequency of an oscillator. The other uses @code(get-slider-value) to control the pitch of grains in a granular synthesis process. @appendix(Intgen)@index(Intgen) @label(intgen-app) @pragma(doinclude) @include(../xlisp/intgen.mss) @appendix(XLISP: An Object-oriented Lisp) @label(xlisp-app) @begin(center) @b(Version 2.0) February 6, 1988 by @b(David Michael Betz) 127 Taylor Road Peterborough, NH 03458 Copyright (c) 1988, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use @end(center) @newpage @pragma(doinclude) @include(../xlisp/xlisp.mss) nyquist-3.05/docsrc/nyquist/nymanimpl.mss0000644000175000000620000006412411511415575017720 0ustar stevestaff@part(Implementation,root "nyquistman2.mss") @appendix(Extending Nyquist) @label(extending-app) @p(WARNING:) Nyquist sound functions look almost like a human wrote them; they even have a fair number of comments for human readers. Don't be fooled: virtually all Nyquist functions are written by a special translator. If you try to write a new function by hand, you will probably not succeed, and even if you do, you will waste a great deal of time. (End of Warning.) @section(Translating Descriptions to C Code) The translator code used to extend Nyquist resides in the @code(trnsrc) directory. This directory also contains a special @code(init.lsp), so if you start XLisp or Nyquist in this directory, it will automatically read @code(init.lsp), which in turn will load the translator code (which resides in several files). Also in the @code(trnsrc) directory are a number of @code(.alg) files, which contain the source code for the translator (more on these will follow), and a number of corresponding @code(.h) and @code(.c) files. To translate a @code(.alg) file to @code(.c) and @code(.h) files, you start XLisp or Nyquist in the @code(trnsrc) directory and type @begin(example) (translate "prod") @end(example) where @code("prod") should really be replaced by the filename (without a suffix) you want to translate. Be sure you have a saved, working copy of Nyquist or Xlisp before you recompile! @p(Note:) On the Macintosh, just run Nyquist out of the @code(runtime) directory and then use the @code(Load) menu command to load @code(init.lsp) from the @code(trnsrc) directory. This will load the translation code and change Nyquist's current directory to @code(trnsrc) so that commands like @code[(translate "prod")] will work. @section(Rebuilding Nyquist) After generating @code(prod.c) and @code(prod.h), you need to recompile Nyquist. For Unix systems, you will want to generate a new Makefile. Modify @code(transfiles.lsp) in your main Nyquist directory, run Xlisp or Nyquist and load @code(makefile.lsp). Follow the instructions to set your machine type, etc., and execute @code[(makesrc)] and @code[(makefile)]. @begin(comment) @subsection(Special Macintosh Instructions) For the Code Warrior/Macintosh implementation, you will need to generate new Lisp-to-C interface files and then modify your project file. To generate Lisp-to-C interface files, first modify the file @code(:nyqsrc:sndfn.cl) to include your newly generated @code(.h) file. If you are not familiar with naming Macintosh folders, this file may look a bit odd. The initial colon in a file name means to start in the current folder. After that, colons separate folder and file names. For example, @begin(example) :tran:osc.h @end(example) means to start from the current directory, go to the @code(tran) directory, and there find the @code(osc.h) file. After modifying @code(sndfn.cl), run the @code(intgen) program, which must be in the top-level Nyquist directory (the parent directory to @code(nyqsrc) and @code(tran). (If you build the @code(intgen) program in @code(misc), copy it to the parent directory.) After starting @code(intgen), to the command line, type: @begin(example) @@:nyqsrc:sndfn.cl @end(example) which tells @code(intgen) to use the contents of the @code(sndfn.cl) file as a command line. Read about @code(intgen) in Appendix @ref(intgen-app). Next, add the @code(.c) file generated by @code(translate) (e.g. @code(prod.c)) to your Nyquist project and recompile Nyquist. @end(comment) @section(Accessing the New Function) The new Lisp function will generally be named with a @code(snd-) prefix, e.g. @code(snd-prod). You can test this by running Nyquist. Debugging is usually a combination of calling the code from within the interpreter, reading the generated code when things go wrong, and using a C debugger to step through the inner loop of the generated code. An approach I like is to set the default sample rate to 10 hertz. Then, a one-second sound has only 10 samples, which are easy to print and study on a text console. For some functions, you must write some Lisp code to impose ordinary Nyquist behaviors such as stretching and time shifting. A good approach is to find some structurally similar functions and see how they are implemented. Most of the Lisp code for Nyquist is in @code(nyquist.lsp). Finally, do not forget to write up some documentation. Also, contributions are welcome. Send your @code(.alg) file, documentation, Lisp support functions for @code(nyquist.lsp), and examples or test programs to @code(rbd@@cs.cmu.edu). I will either put them in the next release or make them available at a public ftp site. @section(Why Translation?) Many of the Nyquist signal processing operations are similar in form, but they differ in details. This code is complicated by many factors: Nyquist uses lazy evaluation, so the operator must check to see that input samples are available before trying to access them. Nyquist signals can have different sample rates, different block sizes, different block boundaries, and different start times, all of which must be taken into account. The number of software tests is enormous. (This may sound like a lot of overhead, but the overhead is amortized over many iterations of the inner loop. Of course setting up the inner loop to run efficiently is one more programming task.) The main idea behind the translation is that all of the checks and setup code are similar and relatively easy to generate automatically. Programmers often use macros for this sort of task, but the C macro processor is too limited for the complex translation required here. To tell the translator how to generate code, you write @code(.alg) files, which provide many details about the operation in a declarative style. For example, the code generator can make some optimizations if you declare that two input signals are commutative (they can be exchanged with one another). The main part of the @code(.alg) file is the inner loop which is the heart of the signal processing code. @section(Writing a .alg File) @p(WARNING:) Translation relies heavily on string substitution, which is fragile. In particular, variables with names that are substrings of other variables will cause problems. For example if you declare STATE variables "phase" and "iphase", then the translator will globally substitute "phase_reg" for "phase", converting "phase" to "phase_reg" and iphase" to "iphase_reg". Then it will substitute "iphase_reg" for iphase" which will convert the existing "iphase_reg" to "iphase_reg_reg". This will be confusing and will not compile. (End of WARNING) To give you some idea how functions are specified, here is the specification for @code(snd-prod), which generates over 250 lines of C code: @begin(example) (PROD-ALG (NAME "prod") (ARGUMENTS ("sound_type" "s1") ("sound_type" "s2")) (START (MAX s1 s2)) (COMMUTATIVE (s1 s2)) (INNER-LOOP "output = s1 * s2") (LINEAR s1 s2) (TERMINATE (MIN s1 s2)) (LOGICAL-STOP (MIN s1 s2)) ) @end(example) A @code(.alg) file is always of the form: @begin(example) (@i(name) (@i(attribute) @i(value)) (@i(attribute) @i(value)) ... ) @end(example) There should be just one of these algorithms descriptions per file. The @i(name) field is arbitrary: it is a Lisp symbol whose property list is used to save the following attribute/value pairs. There are many attributes described below. For more examples, see the @code(.alg) files in the @code(trnsrc) directory. Understanding what the attributes do is not easy, so here are three recommendations for implementors. First, if there is an existing Nyquist operator that is structurally similar to something you want to implement, make a copy of the corresponding @code(.alg) file and work from there. In some cases, you can merely rename the parameters and substitute a new inner loop. Second, read the generated code, especially the generated inner loop. It may not all make sense, but sometimes you can spot obvious errors and work your way back to the error in the @code(.alg) file. Third, if you know where something bad is generated, see if you can find where the code is generated. (The code generator files are listed in @code(init.lsp).) This code is poorly written and poorly documented, but in some cases it is fairly straightforward to determine what attribute in the @code(.alg) file is responsible for the erroneous output. @section(Attributes) Here are the attributes used for code generation. Attributes and values may be specified in any order. @begin(description) @code[(NAME "@i(string)")]@\specifies a base name for many identifiers. In particular, the generated filenames will be @i(string)@code(.c) and @i(string)@code(.h), and the XLisp function generated will be @code(snd-)@i(string). @code[(ARGUMENTS @i(arglist))]@\describes the arguments to be passed from XLisp. @i(Arglist) has the form: @code[(@i(type1) @i(name1)) (@i(type2) @i(name2)) ...], where @i(type) and @i(name) are strings in double quotes, e.g. ("sound_type" "s") specifies a SOUND parameter named @code(s). Note that @i(arglist) is not surrounded by parentheses. As seen in this example, the type names and parameter names are C identifiers. Since the parameters are passed in from XLisp, they must be chosen from a restricted set. Valid type names are: @code("sound_type"), @code("rate_type"), @code("double"), @code("long"), @code("string"), and @code("LVAL"). @code[(STATE @i(statelist))]@\describes additional state (variables) needed to perform the computation. A @i(statelist) is similar to an @i(arglist) (see @code(ARGUMENTS) above), and has the form: @code{(@i(type1) @i(name1) @i(init1) [TEMP]) (@i(type2) @i(name2) @i(init2) [TEMP]) ...}. The types and names are as in @i(arglist), and the "inits" are double-quoted initial values. Initial values may be any C expression. State is initialized in the order implied by @i(statelist) when the operation is first called from XLisp. If @code(TEMP) is omitted the state is preserved in a structure until the sound computation completes. Otherwise, the state variable only exists at state initialization time. @code[(INNER-LOOP @i(innerloop-code))]@\describes the inner loop, written as C code. The @i(innerloop-code) is in double quotes, and may extend over multiple lines. To make generated code extra-beautiful, prefix each line of @i(innerloop-code) with 12 spaces. Temporary variables should not be declared at the beginning of @i(innerloop-code). Use the @code(INNER-LOOP-LOCALS) attribute instead. Within @i(innerloop-code), @i(each ARGUMENT of type sound_type) @p(must) @i(be referenced exactly one time.) If you need to use a signal value twice, assign it once to a temporary and use the temporary twice. The inner loop must also assign @i(one) time to the psuedo-variable @i(output). The model here is that the name of a sound argument denotes the value of the corresponding signal at the current output sample time. The inner loop code will be called once for each output sample. In practice, the code generator will substitute some expression for each signal name. For example, @code(prod.alg) specifies @display[@code[(INNER-LOOP "output = s1 * s2")]] (@code(s1) and @code(s2) are @code(ARGUMENTS).) This expands to the following inner loop in @code(prod.c): @display[@code[*out_ptr_reg++ = *s1_ptr_reg++ * *s2_ptr_reg++;]] In cases where arguments have different sample rates, sample interpolation is in-lined, and the expressions can get very complex. The translator is currently very simple-minded about substituting access code in the place of parameter names, and @i(this is a frequent source of bugs.) Simple string substitution is performed, so @i(you must not use a parameter or state name that is a substring of another). For example, if two sound parameters were named @code(s) and @code(s2), the translator might substitute for ``s'' in two places rather than one. If this problem occurs, you will almost certainly get a C compiler syntax error. The fix is to use ``more unique'' parameter and state variable names. @code[(INNER-LOOP-LOCALS "@i(innerloop-code)")]@\The @i(innerloop-code) contains C declarations of local variables set and referenced in the inner loop. @code[(SAMPLE-RATE "@i(expr)")]@\specifies the output sample rate; @i(expr) can be any C expression, including a parameter from the @code(ARGUMENTS) list. You can also write @code[(SAMPLE-RATE (MAX @i(name1) @i(name2) ...))] where names are unquoted names of arguments. @code[(SUPPORT-HEADER "@i(c-code)")]@\specifies arbitrary C code to be inserted in the generated @code(.h) file. The code typically contains auxiliarly function declarations and definitions of constants. @code[(SUPPORT-FUNCTIONS "@i(c-code)")]@\specifies arbitrary C code to be inserted in the generated @code(.c) file. The code typically contains auxiliarly functions and definitions of constants. @code[(FINALIZATION "@i(c-code)")]@\specifies code to execute when the sound has been fully computed and the state variables are about to be decallocated. This is the place to deallocate buffer memory, etc. @code[(CONSTANT "@i(name1)" "@i(name2)" ...)]@\specifies state variables that do not change value in the inner loop. The values of state variables are loaded into registers before entering the inner loop so that access will be fast within the loop. On exiting the inner loop, the final register values are preserved in a ``suspension'' structure. If state values do not change in the inner loop, this @code(CONSTANT) declaration can eliminate the overhead of storing these registers. @code[(START @i(spec))]@\specifies when the output sound should start (a sound is zero and no processing is done before the start time). The @i(spec) can take several forms: @code[(MIN @i(name1) @i(name2) ...)] means the start time is the minimum of the start times of input signals @i(name1), @i(name2), .... Note that these names are not quoted. @code[(TERMINATE @i(spec))]@\specifies when the output sound terminates (a sound is zero after this termination time and no more samples are computed). The @i(spec) can take several forms: @code[(MIN @i(name1) @i(name2) ...)] means the terminate time is the minimum of the terminate times of input arguments @i(name1), @i(name2), .... Note that these names are not quoted. To terminate at the time of a single argument @code(s1), specify @code[(MIN s1)]. To terminate after a specific duration, use @code[(AFTER "@i(c-expr)")], where @i(c-expr) is a C variable or expression. To terminate at a particular time, use @code[(AT "@i(c-expr)")]. @i(spec) may also be @code(COMPUTED), which means to use the maximum sample rate of any input signal. @code[(LOGICAL-STOP @i(spec))]@\specifies the logical stop time of the output sound. This @i(spec) is just like the one for @code(TERMINATE). If no @code(LOGICAL-STOP) attribute is present, the logical stop will coincide with the terminate time. @code[(ALWAYS-SCALE @i(name1) @i(name2) ...)]@\says that the named sound arguments (not in quotes) should always be multiplied by a scale factor. This is a space-time tradeoff. When Nyquist sounds are scaled, the scale factor is merely stored in a structure. It is the responsibility of the user of the samples to actually scale them (unless the scale factor is exactly 1.0). The default is to generate code with and without scaling and to select the appropriate code at run time. If there are N signal inputs, this will generate 2@+(N) versions of the code. To avoid this code explosion, use the @code(ALWAYS-SCALE) attribute. @code[(INLINE-INTERPOLATION T)]@\specifies that sample rate interpolation should be performed in-line in the inner loop. There are two forms of sample rate interpolation. One is intended for use when the rate change is large and many points will be interpolated. This form uses a divide instruction and some setup at the low sample rate, but the inner loop overhead is just an add. The other form, intended for less drastic sample rate changes, performs interpolation with 2 multiplies and several adds per sample at the high sample rate. Nyquist generates various inner loops and selects the appropriate one at run-time. If @code(INLINE-INTERPOLATION) is not set, then much less code is generated and interpolation is performed as necessary by instantiating a separate signal processing operation. @code[(STEP-FUNCTION @i(name1) @i(name2) ...)]@\Normally all argument signals are linearly interpolated to the output sample rate. The linear interpolation can be turned off with this attribute. This is used, for example, in Nyquist variable filters so that filter coefficients are computed at low sample rates. In fact, this attribute was added for the special case of filters. @code[(DEPENDS @i(spec1) @i(spec2) ...)]@\Specifies dependencies. This attribute was also introduced to handle the case of filter coefficients (but may have other applications.) Use it when a state variable is a function of a potentially low-sample-rate input where the input is in the @code(STEP-FUNCTION) list. Consider a filter coefficient that depends upon an input signal such as bandwidth. In this case, you want to compute the filter coefficient only when the input signal changes rather than every output sample, since output may occur at a much higher sample rate. A @i(spec) is of the form @display{@code{("@i(name)" "@i(arg)" "@i(expr)" [TEMP @i("type")])}} which is interpreted as follows: @I(name) depends upon @i(arg); when @i(arg) changes, recompute @i(expr) and assign it to @i(name). The @i(name) must be declared as a @code(STATE) variable unless @code(TEMP) is present, in which case @i(name) is not preserved and is used only to compute other state. Variables are updated in the order of the @code(DEPENDS) list. @code[(FORCE-INTO-REGISTER @i(name1) @i(name2) ...)]@\causes @i(name1), @i(name2), ... to be loaded into registers before entering the inner loop. If the inner loop references a state variable or argument, this happens automatically. Use this attribute only if references are ``hidden'' in a @code(#define)'d macro or referenced in a @code(DEPENDS) specification. @code[(NOT-REGISTER @i(name1) @i(name2) ...)]@\specifies state and arguments that should not be loaded into registers before entering an inner loop. This is sometimes an optimization for infrequently accessed state. @code[(NOT-IN-INNER-LOOP "@i(name1)" "@i(name2)" ...)]@\says that certain arguments are not used in the inner loop. Nyquist assumes all arguments are used in the inner loop, so specify them here if not. For example, tables are passed into functions as sounds, but these sounds are not read sample-by-sample in the inner loop, so they should be listed here. @code[(MAINTAIN ("@i(name1)" "@i(expr1)") ("@i(name2)" "@i(expr2)") ... )]@\Sometimes the IBM XLC compiler generates better loop code if a variable referenced in the loop is not referenced outside of the loop after the loop exit. Technically, optimization is better when variables are dead upon loop exit. Sometimes, there is an efficient way to compute the final value of a state variable without actually referencing it, in which case the variable and the computation method are given as a pair in the @code(MAINTAIN) attribute. This suppresses a store of the value of the named variable, making it a dead variable. Where the store would have been, the expression is computed and assigned to the named variable. See @code(partial.alg) for an example. This optimization is never necessary and is only for fine-tuning. @code[(LINEAR @i(name1) @i(name2) ...)]@\specifies that named arguments (without quotes) are linear with respect to the output. What this @i(really) means is that it is numerically OK to eliminate a scale factor from the named argument and store it in the output sound descriptor, avoiding a potential multiply in this inner loop. For example, both arguments to @code(snd-prod) (signal multiplication) are ``linear.'' The inner loop has a single multiplication operator to multiply samples vs. a potential 3 multiplies if each sample were also scaled. To handle scale factors on the input signals, the scale factors are automatically multiplied and the product becomes the scale factor of the resulting output. (This effectively ``passes the buck'' to some other, or perhaps more than one, signal processing function, which is not always optimal. On the other hand, it works great if you multiply a number of scaled signals together: all the scale factors are ultimately handled with a single multiply.) @code[(INTERNAL-SCALING @i(name1) @i(name2) ...)]@\indicates that scaling is handled in code that is hidden from the code generator for @i(name1), @i(name2), ..., which are sound arguments. Although it is the responsibility of the reader of samples to apply any given scale factor, sometimes scaling can be had for free. For example, the @code(snd-recip) operation computes the reciprocal of the input samples by peforming a division. The simple approach would be to specify an inner loop of @code[output = 1.0/s1], where @code(s1) is the input. With scaling, this would generate an inner loop something like this: @display(@code[*output++ = 1.0 / (s1_scale_factor * *s1++);]) but a much better approach would be the following: @display(@code[*output++ = my_scale_factor / *s1++]) where @code(my_scale_factor) is initialized to @code(1.0 / s1->scale). Working backward from the desired inner loop to the @code(.alg) inner loop specification, a first attempt might be to specify: @display(@code[(INNER-LOOP "output = my_scale_factor / s1")]) but this will generate the following: @display(@code[*output++=my_scale_factor/(s1_scale_factor * *s1++);]) Since the code generator does not know that scaling is handled elsewhere, the scaling is done twice! The solution is to put @code(s1) in the @code(INTERNAL-SCALING) list, which essentially means ``I've already incorporated scaling into the algorithm, so suppress the multiplication by a scale factor.'' @code[(COMMUTATIVE (@i(name1) @i(name2) ...))]@\specifies that the results will not be affected by interchanging any of the listed arguments. When arguments are commutative, Nyquist rearranges them at run-time into decreasing order of sample rates. If interpolation is in-line, this can dramatically reduce the amount of code generated to handle all the different cases. The prime example is @code(prod.alg). @code[(TYPE-CHECK "@i(code)")]@\specifies checking code to be inserted after argument type checking at initialization time. See @code(downproto.alg) for an example where a check is made to guarantee that the output sample rate is not greater than the input sample rate. Otherwise an error is raised. @end(description) @section(Generated Names) The resulting @code(.c) file defines a number of procedures. The procedures that do actual sample computation are named something like @i(name)@c(_)@i(interp-spec)@c(_fetch), where @i(name) is the @c(NAME) attribute from the @code(.alg) file, and @i(interp-spec) is an interpolation specification composed of a string of the following letters: n, s, i, and r. One letter corresponds to each sound argument, indicating no interpolation (r), scaling only (s), ordinary linear interpolation with scaling (i), and ramp (incremental) interpolation with scaling (r). The code generator determines all the combinations of n, s, i, and r that are necessary and generates a separate fetch function for each. Another function is @i(name)@code(_toss_fetch), which is called when sounds are not time-aligned and some initial samples must be discarded from one or more inputs. The function that creates a sound is @code(snd_make_)@i(name). This is where state allocation and initialization takes place. The proper fetch function is selected based on the sample rates and scale factors of the sound arguments, and a @code(sound_type) is returned. Since Nyquist is a functional language, sound operations are not normally allowed to modify their arguments through side effects, but even reading samples from a @code(sound_type) causes side effects. To hide these from the Nyquist programmer, @code(sound_type) arguments are first copied (this only copies a small structure. The samples themselves are on a shared list). The function @code(snd_)@i(name) performs the necessary copies and calls @code(snd_make_)@i(name). It is the @code(snd_)@i(name) function that is called by XLisp. The XLisp name for the function is @code(SND-)@i(NAME). Notice that the underscore in C is converted to a dash in XLisp. Also, XLisp converts identifiers to upper case when they are read, so normally, you would type @code(snd)-@i(name) to call the function. @section(Scalar Arguments) If you want the option of passing either a number (scalar) or a signal as one of the arguments, you have two choices, neither of which is automated. Choice 1 is to coerce the constant into a signal from within XLisp. The naming convention would be to @code(DEFUN) a new function named @i(NAME) or @code(S-)@i(NAME) for ordinary use. The @i(NAME) function tests the arguments using XLisp functions such as @code(TYPE-OF), @code(NUMBERP), and @code(SOUNDP). Any number is converted to a @code(SOUND), e.g. using @code(CONST). Then @code(SND-)@i(NAME) is called with all sound arguments. The disadvantage of this scheme is that scalars are expanded into a sample stream, which is slower than having a special inner loop where the scalar is simply kept in a register, avoiding loads, stores, and addressing overhead. Choice 2 is to generate a different sound operator for each case. The naming convention here is to append a string of c's and v's, indicating constant (scalar) or variable (signal) inputs. For example, the @code(reson) operator comes in four variations: @code(reson), @code(resoncv), @code(resonvc), and @code(resonvv). The @code(resonvc) version implements a resonating filter with a variable center frequency (a sound type) and a constant bandwidth (a @code(FLONUM)). The @code(RESON) function in Nyquist is an ordinary Lisp function that checks types and calls one of @code(SND-RESON), @code(SND-RESONCV), @code(SND-RESONVC), or @code(SND-RESONVV). Since each of these @code(SND-) functions performs further selection of implementation based on sample rates and the need for scaling, there are 25 different functions for computing RESON! So far, however, Nyquist is smaller than Common Lisp and it's about half the size of Microsoft Word. Hopefully, exponential growth in memory density will outpace linear (as a function of programming effort) growth of Nyquist. nyquist-3.05/docsrc/nyquist/geometric-fig.ps0000644000175000000620000014127511466723256020267 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: geometric-fig.ps %%CreationDate: Wed Jul 13 12:16:14 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 313 363 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 348 translate -20 775 translate 297.99999999999994 -348 scale % Image geometry 298 348 8 % Transformation matrix [ 298 0 0 348 0 0 ] % Strings to hold RGB-samples per scanline /rstr 298 string def /gstr 298 string def /bstr 298 string def {currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} true 3 %%BeginData: 48827 ASCII Bytes colorimage JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> r;V r;V r;V r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`s^]+JrHiO/8nDO r;Q`s^]+JrHiO/8nDO r;Q`s^]+JrHiO/8nDO r;Q`s_#FW'!1Nr@!.<`)rrDHdrrE*!!h',JpAb-mq#C?op&G$lec,]a!!'e6!!)orJ,~> r;Q`s_#FW'!1Nr@!.<`)rrDHdrrE*!!h',JpAb-mq#C?op&G$lec,]a!!'e6!!)orJ,~> r;Q`s_#FW'!1Nr@!.<`)rrDHdrrE*!!h',JpAb-mq#C?op&G$lec,]a!!'e6!!)orJ,~> r;Q`s_#FJ)!9sC\"0qn,ZMsk>Z:t>)s8N'!d!SR$a%]:Ts8TA)!4)Y'!"T#/!/u=*!!*'!Z:t=X l2CY^!<<'-kl@1P!!*&`HiO/*l2(GlN-tX*!<3$!]hOIcrr<'!s8)d-rr<'!s0>?!ZN'q)!76*f d/*eB!!:MAI.[F@n7Ve%^]+96qu;0~> r;Q`s_#FJ)!9sC\"0qn,ZMsk>Z:t>)s8N'!d!SR$a%]:Ts8TA)!4)Y'!"T#/!/u=*!!*'!Z:t=X l2CY^!<<'-kl@1P!!*&`HiO/*l2(GlN-tX*!<3$!]hOIcrr<'!s8)d-rr<'!s0>?!ZN'q)!76*f d/*eB!!:MAI.[F@n7Ve%^]+96qu;0~> r;Q`s_#FJ)!9sC\"0qn,ZMsk>Z:t>)s8N'!d!SR$a%]:Ts8TA)!4)Y'!"T#/!/u=*!!*'!Z:t=X l2CY^!<<'-kl@1P!!*&`HiO/*l2(GlN-tX*!<3$!]hOIcrr<'!s8)d-rr<'!s0>?!ZN'q)!76*f d/*eB!!:MAI.[F@n7Ve%^]+96qu;0~> r;Q`s_#FF0!;ldN]`?+"!58EG!6<+[^&J'4^$l"%ZKV@&s1JEQciCcZ!!*'!!!(^Prr<'!Z2hr0 !0$mVrrE&urr>"X!!*%4!<;9`I/a0Hrr<&Ps8N'!rr<%s`rN%;!!*'!!!*$!!<<'!!<9_4a2\1n rr<&4kl=HSs8N'%VoJe8s8)forr]1G!!'e6!!)orJ,~> r;Q`s_#FF0!;ldN]`?+"!58EG!6<+[^&J'4^$l"%ZKV@&s1JEQciCcZ!!*'!!!(^Prr<'!Z2hr0 !0$mVrrE&urr>"X!!*%4!<;9`I/a0Hrr<&Ps8N'!rr<%s`rN%;!!*'!!!*$!!<<'!!<9_4a2\1n rr<&4kl=HSs8N'%VoJe8s8)forr]1G!!'e6!!)orJ,~> r;Q`s_#FF0!;ldN]`?+"!58EG!6<+[^&J'4^$l"%ZKV@&s1JEQciCcZ!!*'!!!(^Prr<'!Z2hr0 !0$mVrrE&urr>"X!!*%4!<;9`I/a0Hrr<&Ps8N'!rr<%s`rN%;!!*'!!!*$!!<<'!!<9_4a2\1n rr<&4kl=HSs8N'%VoJe8s8)forr]1G!!'e6!!)orJ,~> r;Q`s_#OE7s8W&u-N?d?s8N(4s(DE4rr?a4!!*'!!!*'!!!*$n!<<'!B`A&4s8N'!rr;uu!rksp q>^Hprr;uu#QFc(s%NK@d/O(F!!<0#!<3#u!$_FC!<<'!:&b1ns8N'!rr<'!rr<'!BE8)4!,2B4 !<<'!!;c`q!<<'"!)<1e"R1=6!!'e6!!)orJ,~> r;Q`s_#OE7s8W&u-N?d?s8N(4s(DE4rr?a4!!*'!!!*'!!!*$n!<<'!B`A&4s8N'!rr;uu!rksp q>^Hprr;uu#QFc(s%NK@d/O(F!!<0#!<3#u!$_FC!<<'!:&b1ns8N'!rr<'!rr<'!BE8)4!,2B4 !<<'!!;c`q!<<'"!)<1e"R1=6!!'e6!!)orJ,~> r;Q`s_#OE7s8W&u-N?d?s8N(4s(DE4rr?a4!!*'!!!*'!!!*$n!<<'!B`A&4s8N'!rr;uu!rksp q>^Hprr;uu#QFc(s%NK@d/O(F!!<0#!<3#u!$_FC!<<'!:&b1ns8N'!rr<'!rr<'!BE8)4!,2B4 !<<'!!;c`q!<<'"!)<1e"R1=6!!'e6!!)orJ,~> r;Q`s_#FF0!<3#u!!*&r!##;3!<<'!!<3$!s8N'!s8N'!s8)d#rr<'!rr<&us8N'#rr<&ps8N)u s8N'0rr<'!cqOK?:!in?!<3$!rr;uu,6%WCs8N'!rr<'!rr<'!!!*'!!!*$!!<<'!!<3$!s8N'! qZ$Qqs8W*!!<;orrVm"ZiVrlX^]+96qu;0~> r;Q`s_#FF0!<3#u!!*&r!##;3!<<'!!<3$!s8N'!s8N'!s8)d#rr<'!rr<&us8N'#rr<&ps8N)u s8N'0rr<'!cqOK?:!in?!<3$!rr;uu,6%WCs8N'!rr<'!rr<'!!!*'!!!*$!!<<'!!<3$!s8N'! qZ$Qqs8W*!!<;orrVm"ZiVrlX^]+96qu;0~> r;Q`s_#FF0!<3#u!!*&r!##;3!<<'!!<3$!s8N'!s8N'!s8)d#rr<'!rr<&us8N'#rr<&ps8N)u s8N'0rr<'!cqOK?:!in?!<3$!rr;uu,6%WCs8N'!rr<'!rr<'!!!*'!!!*$!!<<'!!<3$!s8N'! qZ$Qqs8W*!!<;orrVm"ZiVrlX^]+96qu;0~> r;Q`s_#F_0!9*tX!!*$n!;uj1BE8)4!,2B4!<<'!!<<'!!<5anr;Zcss8W*!rr;uu!rkspq>^Hp s8N8e!1Nof!<3!)fr"gErr<'!!!*#urr=8C!!*'!!)jfs8)f3rr<&rs*t~> r;Q`s_#F_0!9*tX!!*$n!;uj1BE8)4!,2B4!<<'!!<<'!!<5anr;Zcss8W*!rr;uu!rkspq>^Hp s8N8e!1Nof!<3!)fr"gErr<'!!!*#urr=8C!!*'!!)jfs8)f3rr<&rs*t~> r;Q`s_#F_0!9*tX!!*$n!;uj1BE8)4!,2B4!<<'!!<<'!!<5anr;Zcss8W*!rr;uu!rkspq>^Hp s8N8e!1Nof!<3!)fr"gErr<'!!!*#urr=8C!!*'!!)jfs8)f3rr<&rs*t~> r;Q`s_#H"N!1Nr$!!*&)!6==(N;pQka2\1nrr<'!rr<'!rr<'!Z2hr0!0$pX!<<'!!<3#u!!`J/ !6==(I/X*F!<<'3RK2%@!!*%H!9rtQB`A&4rr<&us8N'Frr<%sciC!DBE7;1!!*$!!<<'!!<9_4 a2\1nrr<'!rr<'!!!)utrrs8N)ts8N)6rr<&rs*t~> r;Q`s_#H"N!1Nr$!!*&)!6==(N;pQka2\1nrr<'!rr<'!rr<'!Z2hr0!0$pX!<<'!!<3#u!!`J/ !6==(I/X*F!<<'3RK2%@!!*%H!9rtQB`A&4rr<&us8N'Frr<%sciC!DBE7;1!!*$!!<<'!!<9_4 a2\1nrr<'!rr<'!!!)utrrs8N)ts8N)6rr<&rs*t~> r;Q`s_#H"N!1Nr$!!*&)!6==(N;pQka2\1nrr<'!rr<'!rr<'!Z2hr0!0$pX!<<'!!<3#u!!`J/ !6==(I/X*F!<<'3RK2%@!!*%H!9rtQB`A&4rr<&us8N'Frr<%sciC!DBE7;1!!*$!!<<'!!<9_4 a2\1nrr<'!rr<'!!!)utrrs8N)ts8N)6rr<&rs*t~> r;Q`s^]+]#HiO/*d/X-O9`U.OruJC>9sXg!!!*'!!!*'!!!*'!Z:t=Xs8UFGI/a0Hrr;uus8N5- !!%uBrVufr¬urr<'!n r;Q`s^]+]#HiO/*d/X-O9`U.OruJC>9sXg!!!*'!!!*'!!!*'!Z:t=Xs8UFGI/a0Hrr;uus8N5- !!%uBrVufr¬urr<'!n r;Q`s^]+]#HiO/*d/X-O9`U.OruJC>9sXg!!!*'!!!*'!!!*'!Z:t=Xs8UFGI/a0Hrr;uus8N5- !!%uBrVufr¬urr<'!n r;Q`sJcEUe!U4:rs8N)"rr<&rs*t~> r;Q`sJcEUe!U4:rs8N)"rr<&rs*t~> r;Q`sJcEUe!U4:rs8N)"rr<&rs*t~> r;Q`sJcEUe!K?"9s8N)"rr<&rs*t~> r;Q`sJcEUe!K?"9s8N)"rr<&rs*t~> r;Q`sJcEUe!K?"9s8N)"rr<&rs*t~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sp&G!krr;rtJcC<$q>UEpqu;0~> r;Q`sp&G!krr;rtJcC<$q>UEpqu;0~> r;Q`sp&G!krr;rtJcC<$q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGTH!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGTH!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGTH!!)orJ,~> r;Q`spAY*mr;Q`srr2ruJcC<$qYpNqqu;0~> r;Q`spAY*mr;Q`srr2ruJcC<$qYpNqqu;0~> r;Q`spAY*mr;Q`srr2ruJcC<$qYpNqqu;0~> r;Q`spAb'ks8N'!rr2ruJcC<$qYpNqqu;0~> r;Q`spAb'ks8N'!rr2ruJcC<$qYpNqqu;0~> r;Q`spAb'ks8N'!rr2ruJcC<$qYpNqqu;0~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)1tNe$s*!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)1tNe$s*!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)1tNe$s*!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sp&Fsjs8W&up\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&Fsjs8W&up\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&Fsjs8W&up\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAb'ks8N'!rr2ruq#: r;Q`spAb'ks8N'!rr2ruq#: r;Q`spAb'ks8N'!rr2ruq#: r;Q`so)AakrrE&u!!)orqZ)2_O2(aGq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ)2_O2(aGq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ)2_O2(aGq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYq7uS%J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7uS%J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7uS%J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#:!lJ\\%r!.anF!!)orJ,~> r;Q`sp&>0qrrE*!!<2uu!;QQo!;XD1!;2`[!.hq\^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!;XD1!;2`[!.hq\^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!;XD1!;6?l!.hq\^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!;XD1!;2`[!.hq\^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!;XD1!;2`[!.hq\^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!;XD1!;6?l!.hq\^]8o\rr<&rs*t~> r;Q`spAYUEpqu;0~> r;Q`spAYUEpqu;0~> r;Q`spAYUEpqu;0~> r;Q`spAb$j!WN0!rr<&orr<&p^]4B-R/d5<^n\[FJGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<&p^]4B-R/d5<^n\[FJGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<&p^]4B-rr<%M^n\[FJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<&p^]4B-R/d5<^n\[FJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<&p^]4B-R/d5<^n\[FJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<&p^]4B-rr<%M^n\[FJGK3F!;leH~> r;Q`soD\djrr;rtp\t3nq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nq7lt1opGd[J\\%r!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nq7lt1p&>!lJ\\%r!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)]l!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)]l!!%ScUVHk[q>UEpqu;0~> r;Q`so`+pks8N'!rr2ruqu?NnqnN13opGd[J\\%r!.anF!!)orJ,~> r;Q`so`+pks8N'!rr2ruqu?NnqnN13opGd[J\\%r!.anF!!)orJ,~> r;Q`so`+pks8N'!rr2ruqu?NnqnN13p&>!lJ\\%r!.anF!!)orJ,~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)]l!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)]l!!%ScUVHk[q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)\[!!%ScUVHk[q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)]l!!%ScUVHk[q>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nq7lt1opGd[nA+YrJ\]+;!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nq7lt1opGd[nA+YrJ\]+;!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nq7lt1p&>!lnA+YrJ\]+;!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sp&G!krr;rtp\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`sp&G!krr;rtp\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`sp&G!krr;rtp\t3nq7lt1p&>!lnA##(p&>!lJ\]. r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)i1!!)]l!!)N(!!)]l!!%Sc_S?/%q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)]l!!)N(!!)]l!!%Sc_S?/%q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)i1!!)]l!!)N(!!)]l!!%Sc_S?/%q>UEpqu;0~> r;Q`soD\mms8N)urr<&rs8)fn^]4B-R/d6V^]4B-R/d5<^r!keJGK3F!;leH~> r;Q`soD\mms8N)urr<&rs8)fn^]4B-R/d6V^]4B-R/d5<^r!keJGK3F!;leH~> r;Q`soD\mms8N)urr<&rs8)fn^]4B-rr<&g^]4B-rr<%M^r!keJGK3F!;leH~> r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#:!lnA##(p&>!lJ\]. r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#:!lnA##(p&>!lJ\]. r;Q`spAb$js8W&up\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`spAb$js8W&up\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`spAb$js8W&up\t3nq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[J\]. r;Q`sir8uYq7lt1p&>!lnA##(p&>!lJ\]. r;Q`so`"mkrVuisp\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`so`"mkrVuisp\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`so`"mkrVuisp\t3nq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sp&G$lrr2rurr2ruq#: r;Q`sp&G$lrr2rurr2ruq#: r;Q`sp&G$lrr2rurr2ruq#:!lnA##(p&>!lJ\]. r;Q`spAY0orrE&u!!*#u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`spAY0orrE&u!!*#u!!)fo!!)i1!!)\[!!)N(!!)\[!!%Sc_S?/%q>UEpqu;0~> r;Q`spAY0orrE&u!!*#u!!)fo!!)i1!!)]l!!)N(!!)]l!!%Sc_S?/%q>UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#:!lnA##(p&>!lJ\]. r;Q`so`"mkrr2rurr2ruqu?NnqnN13opGd[nA##(opGd[J\]. r;Q`so`"mkrr2rurr2ruqu?NnqnN13opGd[nA##(opGd[J\]. r;Q`so`"mkrr2rurr2ruqu?NnqnN13p&>!lnA##(p&>!lJ\]. r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#:!lnA##(p&>!lJ\]. r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#:!lnA##(p&>!lJ\]. r;Q`so`"mkrVuisp\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`so`"mkrVuisp\t3nq7lt1opGd[nA##(opGd[J\]. r;Q`so`"mkrVuisp\t3nq7lt1p&>!lnA##(p&>!lJ\]. r;Q`sir8uYq7lt1opGd[nA##(opGd[nA+\sJ\^0Y!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA+\sJ\^0Y!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA+\sJ\^0Y!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA+Yrn%ePqS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA+Yrn%ePqS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA+Yrn%ePqS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA+VqnA+Yrg;!]= q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA+VqnA+Yrg;!]= q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA+VqnA+Yrg;!]= q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\g;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\g;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mg;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\g;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\g;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mg;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\g;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\g;!]=q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mg;!]=q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[ nA##(p6bm\nA+Vqq7lu\q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[ nA##(p6bm\nA+Vqq7lu\q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l nA##(pAY*mnA+Vqq7lu\q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##( p&>!lnA##(pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1pAY*m q7lt1q7lt1p&>!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1pAY*m q7lt1q7lt1p&>!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1q>UEpqu;0~> r;Q`snG`Igrr2ruqu;3IL]I8N!!)orJ,~> r;Q`snG`Igrr2ruqu;3IL]I8N!!)orJ,~> r;Q`snG`Igrr2ruqu;3IL]I8N!!)orJ,~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`sn,N@ep\t3nj8T)Zj8T)ZjSo2[jSo2[j8T)Zj8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sn,N@ep\t3nj8T)Zj8T)ZjSo2[jSo2[j8T)Zj8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sn,N@ep\t3nj8T)Zj8T)ZjSo2[jSo2[j8T)Zj8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sec5UKjSo2[jT#2Zjo>;[jo5;\jo>8Zk5YD\n,E@fr;Q`sjSo2[qu;0~> r;Q`sec5UKjSo2[jT#2Zjo>;[jo5;\jo>8Zk5YD\n,E@fr;Q`sjSo2[qu;0~> r;Q`sec5UKjSo2[jT#2Zjo>;[jo5;\jo>8Zk5YD\n,E@fr;Q`sjSo2[qu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukPkM^rr2rukPtP^jo5;\jSo2[rr2runGiLgrr;uujSo2[ qu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukPkM^rr2rukPtP^jo5;\jSo2[rr2runGiLgrr;uujSo2[ qu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukPkM^rr2rukPtP^jo5;\jSo2[rr2runGiLgrr;uujSo2[ qu;0~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)'Z!!)6_!W`6#k5PD]j8T)Zm/R(crr;uus8W&us8N3%rrE*! rW)Qi!!)orJ,~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)'Z!!)6_!W`6#k5PD]j8T)Zm/R(crr;uus8W&us8N3%rrE*! rW)Qi!!)orJ,~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)'Z!!)6_!W`6#k5PD]j8T)Zm/R(crr;uus8W&us8N3%rrE*! rW)Qi!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\iVrlXjo>>\kPkS`rrD3]r;c![r;c r;Q`sf)G^Mrr2rujo5;\iVrlXjo>>\kPkS`rrD3]r;c![r;c r;Q`sf)G^Mrr2rujo5;\iVrlXjo>>\kPkS`rrD3]r;c![r;c r;Q`sf)G^Mrr2rujo5;\ir8uYir8uYl2Lhcs8N)Yrr<&^rr<&urr<&grs/W)!<3'!!<3&urrN3# !<3#r!;-9k!;leH~> r;Q`sf)G^Mrr2rujo5;\ir8uYir8uYl2Lhcs8N)Yrr<&^rr<&urr<&grs/W)!<3'!!<3&urrN3# !<3#r!;-9k!;leH~> r;Q`sf)G^Mrr2rujo5;\ir8uYir8uYl2Lhcs8N)Yrr<&^rr<&urr<&grs/W)!<3'!!<3&urrN3# !<3#r!;-9k!;leH~> r;Q`sf)G^Mrr2rujo5;\j8T)ZiVrlXl2UY]j8T)ZkPkM^rr2runG`aorrE'!rrE'!rr3$"rrE&u !!)Ng!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\j8T)ZiVrlXl2UY]j8T)ZkPkM^rr2runG`aorrE'!rrE'!rr3$"rrE&u !!)Ng!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\j8T)ZiVrlXl2UY]j8T)ZkPkM^rr2runG`aorrE'!rrE'!rr3$"rrE&u !!)Ng!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\jSo2[jSo2[rr2ruk5PD]k5PD]rr2rukPkM^rr2runG`aos8N*!rrE'! rr3$"rrE&u!!*#u!!)Zk!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\jSo2[jSo2[rr2ruk5PD]k5PD]rr2rukPkM^rr2runG`aos8N*!rrE'! rr3$"rrE&u!!*#u!!)Zk!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\jSo2[jSo2[rr2ruk5PD]k5PD]rr2rukPkM^rr2runG`aos8N*!rrE'! rr3$"rrE&u!!*#u!!)Zk!!)orJ,~> r;Q`sec5UKjSo2[jo>5Yk5YD\jo5;\jo>;[jo>;[n,EXns8N*!rrE*!rW)uu!!)utrW)Qi!!)or J,~> r;Q`sec5UKjSo2[jo>5Yk5YD\jo5;\jo>;[jo>;[n,EXns8N*!rrE*!rW)uu!!)utrW)Qi!!)or J,~> r;Q`sec5UKjSo2[jo>5Yk5YD\jo5;\jo>;[jo>;[n,EXns8N*!rrE*!rW)uu!!)utrW)Qi!!)or J,~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;V r;V r;V JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/rampfig.ps0000644000175000000620000002363611466723256017173 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 36 573 444 752 %%Title: (rampfig-Layer#1) %%Creator: (MacDraw II 1.1v2: LaserWriter 8 8.1.1) %%CreationDate: (4:37 AM Sunday, January 24, 1904) %%For: (Dannenberg) %%Pages: 1 %%DocumentFonts: Helvetica Courier %%DocumentNeededFonts: Helvetica Courier %%DocumentSuppliedFonts: %%DocumentData: Clean7Bit %%PageOrder: Ascend %%Orientation: Portrait %ADO_PaperArea: -129 -125 3171 2425 %ADO_ImageableArea: 0 0 3042 2300 %%EndComments /md 154 dict def md begin /currentpacking where {pop /sc_oldpacking currentpacking def true setpacking}if %%BeginFile: adobe_psp_basic %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /bd{bind def}bind def /xdf{exch def}bd /xs{exch store}bd /ld{load def}bd /Z{0 def}bd /T/true /F/false /:L/lineto /lw/setlinewidth /:M/moveto /rl/rlineto /rm/rmoveto /:C/curveto /:T/translate /:K/closepath /:mf/makefont /gS/gsave /gR/grestore /np/newpath 14{ld}repeat /$m matrix def /av 81 def /por true def /normland false def /psb-nosave{}bd /pse-nosave{}bd /us Z /psb{/us save store}bd /pse{us restore}bd /level2 /languagelevel where { pop languagelevel 2 ge }{ false }ifelse def /featurecleanup { stopped cleartomark countdictstack exch sub dup 0 gt { {end}repeat }{ pop }ifelse }bd /noload Z /startnoload { {/noload save store}if }bd /endnoload { {noload restore}if }bd level2 startnoload /setjob { statusdict/jobname 3 -1 roll put }bd /setcopies { userdict/#copies 3 -1 roll put }bd level2 endnoload level2 not startnoload /setjob { 1 dict begin/JobName xdf currentdict end setuserparams }bd /setcopies { 1 dict begin/NumCopies xdf currentdict end setpagedevice }bd level2 not endnoload /pm Z /mT Z /sD Z /realshowpage Z /initializepage { /pm save store mT concat }bd /endp { pm restore showpage }def /$c/DeviceRGB def /rectclip where { pop/rC/rectclip ld }{ /rC { np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K clip np }bd }ifelse /rectfill where { pop/rF/rectfill ld }{ /rF { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl fill gR }bd }ifelse /rectstroke where { pop/rS/rectstroke ld }{ /rS { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K stroke gR }bd }ifelse %%EndFile %%BeginFile: adobe_psp_colorspace_level1 %%Copyright: Copyright 1991-1993 Adobe Systems Incorporated. All Rights Reserved. /G/setgray ld /:F/setrgbcolor ld %%EndFile %%BeginFile: adobe_psp_uniform_graphics %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /@a { np :M 0 rl :L 0 exch rl 0 rl :L fill }bd /@b { np :M 0 rl 0 exch rl :L 0 rl 0 exch rl fill }bd /arct where { pop }{ /arct { arcto pop pop pop pop }bd }ifelse /x1 Z /x2 Z /y1 Z /y2 Z /rad Z /@q { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct fill }bd /@s { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct :K stroke }bd /@i { np 0 360 arc fill }bd /@j { gS np :T scale 0 0 .5 0 360 arc fill gR }bd /@e { np 0 360 arc :K stroke }bd /@f { np $m currentmatrix pop :T scale 0 0 .5 0 360 arc :K $m setmatrix stroke }bd /@k { gS np :T 0 0 :M 0 0 5 2 roll arc fill gR }bd /@l { gS np :T 0 0 :M scale 0 0 .5 5 -2 roll arc fill gR }bd /@m { np arc stroke }bd /@n { np $m currentmatrix pop :T scale 0 0 .5 5 -2 roll arc $m setmatrix stroke }bd %%EndFile %%BeginFile: adobe_psp_customps %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /$t Z /$p Z /$s Z /$o 1. def /2state? false def /ps Z level2 startnoload /pushcolor/currentrgbcolor ld /popcolor/setrgbcolor ld /setcmykcolor where { pop/currentcmykcolor where { pop/pushcolor/currentcmykcolor ld /popcolor/setcmykcolor ld }if }if level2 endnoload level2 not startnoload /pushcolor { currentcolorspace $c eq { currentcolor currentcolorspace true }{ currentcmykcolor false }ifelse }bd /popcolor { { setcolorspace setcolor }{ setcmykcolor }ifelse }bd level2 not endnoload /pushstatic { ps 2state? $o $t $p $s }bd /popstatic { /$s xs /$p xs /$t xs /$o xs /2state? xs /ps xs }bd /pushgstate { save errordict/nocurrentpoint{pop 0 0}put currentpoint 3 -1 roll restore pushcolor currentlinewidth currentlinecap currentlinejoin currentdash exch aload length np clippath pathbbox $m currentmatrix aload pop }bd /popgstate { $m astore setmatrix 2 index sub exch 3 index sub exch rC array astore exch setdash setlinejoin setlinecap lw popcolor np :M }bd /bu { pushgstate gR pushgstate 2state? { gR pushgstate }if pushstatic pm restore mT concat }bd /bn { /pm save store popstatic popgstate gS popgstate 2state? { gS popgstate }if }bd /cpat{pop 64 div G 8{pop}repeat}bd %%EndFile %%BeginFile: adobe_psp_basic_text %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /S/show ld /A{ 0.0 exch ashow }bd /R{ 0.0 exch 32 exch widthshow }bd /W{ 0.0 3 1 roll widthshow }bd /J{ 0.0 32 4 2 roll 0.0 exch awidthshow }bd /V{ 0.0 4 1 roll 0.0 exch awidthshow }bd /fcflg true def /fc{ fcflg{ vmstatus exch sub 50000 lt{ (%%[ Warning: Running out of memory ]%%\r)print flush/fcflg false store }if pop }if }bd /$f[1 0 0 -1 0 0]def /:ff{$f :mf}bd /MacEncoding StandardEncoding 256 array copy def MacEncoding 39/quotesingle put MacEncoding 96/grave put /Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute /agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave /ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute /ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls /registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash /infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation /product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft /guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe /endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge /ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl /daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand /Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave /Oacute/Ocircumflex/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde /macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron MacEncoding 128 128 getinterval astore pop level2 startnoload /copyfontdict { findfont dup length dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall }bd level2 endnoload level2 not startnoload /copyfontdict { findfont dup length dict copy begin }bd level2 not endnoload md/fontname known not{ /fontname/customfont def }if /Encoding Z /:mre { copyfontdict /Encoding MacEncoding def fontname currentdict end definefont :ff def }bd /:bsr { copyfontdict /Encoding Encoding 256 array copy def Encoding dup }bd /pd{put dup}bd /:esr { pop pop fontname currentdict end definefont :ff def }bd /scf { scalefont def }bd /scf-non { $m scale :mf setfont }bd /ps Z /fz{/ps xs}bd /sf/setfont ld /cF/currentfont ld /mbf { /makeblendedfont where { pop makeblendedfont /ABlend exch definefont }{ pop }ifelse def }def %%EndFile %%BeginFile: adobe_psp_dashes %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /:q/setdash ld /:r{ np :M :L stroke }bd /nodash[]def /qdenddash { nodash 0 setdash }bd %%EndFile /currentpacking where {pop sc_oldpacking setpacking}if end % md %%EndProlog %%BeginSetup md begin /pT[1 0 0 -1 29.999 761.009]def/mT[.24 0 0 -.24 29.999 761.009]def /sD 16 dict def %%IncludeFont: Helvetica %%IncludeFont: Courier /f0_1/Helvetica :mre /f0_58 f0_1 58 scf /f1_1/Courier :mre /f1_58 f1_1 58 scf /Courier findfont[10 0 0 -10 0 0]:mf setfont %%EndSetup %%Page: 1 1 %%BeginPageSetup initializepage %%EndPageSetup gS 0 0 2300 3042 rC 0 0 :M 0 setlinecap currentscreen 3 1 roll pop pop 60 45 3 -1 roll setscreen np 150 38 :M 165 96 :L 150 96 :L 135 96 :L 150 38 :L eofill -4 -4 152 602 4 4 148 94 @b np 750 600 :M 691 615 :L 691 600 :L 691 585 :L 750 600 :L 4 lw eofill 148 602 -4 4 693 598 4 148 598 @a -8 -8 154 604 8 8 559 184 @b 559 192 -8 8 604 596 8 559 184 @a 111 152 -4 4 152 148 4 111 148 @a -4 -4 602 640 4 4 598 598 @b [20.833 16.667 ] 0 :q 675 150 150 150 :r 39 179 :M f0_58 sf (1)S 47 634 :M (0)S 572 709 :M (1)S [8.333 8.333 ] 0 :q 600 150 563 188 :r 600 600 600 150 :r np 1125 38 :M 1140 96 :L 1125 96 :L 1110 96 :L 1125 38 :L [] 0 :q eofill -4 -4 1127 602 4 4 1123 94 @b np 1725 600 :M 1666 615 :L 1666 600 :L 1666 585 :L 1725 600 :L eofill 1123 602 -4 4 1668 598 4 1123 598 @a -8 -8 1129 604 8 8 1571 146 @b 1571 154 -8 8 1617 596 8 1571 146 @a 1086 152 -4 4 1127 148 4 1086 148 @a -4 -4 1577 640 4 4 1573 598 @b [20.833 16.667 ] 0 :q 1650 150 1125 150 :r 1014 179 :M (1)S 1022 634 :M (0)S 1547 709 :M (1)S 151 763 :M f1_58 sf -.071(\(pwl 1 1 1\))A 1276 763 :M -.15(\(ramp\))A 29 30 450.5 300 @j [] 0 :q 29 30 450.5 300 @f 29 30 375.5 375 @j 29 30 375.5 375 @f 29 30 337.5 413 @j 29 30 337.5 413 @f 29 30 300.5 450 @j 29 30 300.5 450 @f 29 30 262.5 488 @j 29 30 262.5 488 @f 29 30 225.5 525 @j 29 30 225.5 525 @f 29 30 187.5 563 @j 29 30 187.5 563 @f 29 30 487.5 263 @j 29 30 487.5 263 @f 29 30 412.5 338 @j 29 30 412.5 338 @f 28 30 525 225 @j 28 30 525 225 @f 562.5 187.5 14.5 @i 562.5 187.5 14.5 @e 1 G 28 30 600 150 @j 0 G 8 lw 28 30 600 150 @f 1 G 28 30 600 600 @j 0 G 28 30 600 600 @f 28 30 150 600 @j 4 lw 28 30 150 600 @f 28 30 1125 600 @j 28 30 1125 600 @f 28 30 1200 525 @j 28 30 1200 525 @f 1162.5 562.5 14.5 @i 1162.5 562.5 14.5 @e 1237.5 487.5 14.5 @i 1237.5 487.5 14.5 @e 28 30 1275 450 @j 28 30 1275 450 @f 1312.5 412.5 14.5 @i 1312.5 412.5 14.5 @e 28 30 1350 375 @j 28 30 1350 375 @f 1387.5 337.5 14.5 @i 1387.5 337.5 14.5 @e 28 30 1425 300 @j 28 30 1425 300 @f 1462.5 262.5 14.5 @i 1462.5 262.5 14.5 @e 28 30 1500 225 @j 28 30 1500 225 @f 1537.5 187.5 14.5 @i 1537.5 187.5 14.5 @e 28 30 1575 150 @j 28 30 1575 150 @f 1 G 29 30 1612.5 600 @j 0 G 8 lw 29 30 1612.5 600 @f 4 lw [20.833 16.667 ] 0 :q 1575 600 1575 150 :r endp %%Trailer end % md %%EOF nyquist-3.05/docsrc/nyquist/moog-fig.ps0000644000175000000620000044657611466723256017266 0ustar stevestaff%!PS-Adobe-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: moog.ps %%CreationDate: Tue Oct 11 08:13:23 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 1131 618 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456693 14.173228346456693 translate % Translate to begin of first scanline %0 603 translate 0 725 translate 1116 -603 scale % Image geometry 1116 603 8 % Transformation matrix [ 1116 0 0 603 0 0 ] % Strings to hold RGB-samples per scanline /rstr 1116 string def /gstr 1116 string def /bstr 1116 string def {currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} true 3 %%BeginData: 149912 ASCII Bytes colorimage JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$VuHb#JUbC`_uG5~> JcC<$JcC<$JcC<$VuHb#JUbC`_uG5~> JcC<$JcC<$JcC<$VuHb#JUbC`_uG5~> JcC<$JcC<$JcC<$VuHa(JH3Ca_uG5~> JcC<$JcC<$JcC<$VuHa(JH3Ca_uG5~> JcC<$JcC<$JcC<$VuHa(JH3Ca_uG5~> JcC<$JcC<$JcC<$VuHg*!)S5r_LMRc_uG5~> JcC<$JcC<$JcC<$VuHg*!)S5r_LMRc_uG5~> JcC<$JcC<$JcC<$VuHg*!)S5r_LMRc_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> qZ$?kJcC<$JcC<$JcC<$[f6D9!2+oC_Z0W9_uG5~> qZ$?kJcC<$JcC<$JcC<$[f6D9!2+oC_Z0W9_uG5~> qZ$?kJcC<$JcC<$JcC<$[f6D9!2+oC_Z0W9_uG5~> q>UHJr;ZiNcMmllJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q>UHJr;ZiNcMmllJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q>UHJr;ZiNcMmllJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mcMmp(!.k0$s+13$s+13$s69Ob?N?aMs2+g9!5nhe~> q#C9mcMmp(!.k0$s+13$s+13$s69Ob?N?aMs2+g9!5nhe~> q#C9mcMmp(!.k0$s+13$s+13$s69Ob?N?aMs2+g9!5nhe~> q#C9mci4&o!!%TMJcC<$JcC<$JcG!7!abr#JcEUerrBt:J,~> q#C9mci4&o!!%TMJcC<$JcC<$JcG!7!abr#JcEUerrBt:J,~> q#C9mci4&o!!%TMJcC<$JcC<$JcG!7!abr#JcEUerrBt:J,~> q#C9mdJj7+BDqm^s+13$s+13$s+147rrQO-TRm-[s8N):s*t~> q#C9mdJj7+BDqm^s+13$s+13$s+147rrQO-TRm-[s8N):s*t~> q#C9mdJj7+BDqm^s+13$s+13$s+147rrQO-TRm-[s8N):s*t~> q#C9mrVucq"om8'!)1*)s82j"l"9uiZMjh$!<<)s!<<'!ReZr7s+13$s+13$s+14:rrQO-TRm-[ s8N):s*t~> q#C9mrVucq"om8'!)1*)s82j"l"9uiZMjh$!<<)s!<<'!ReZr7s+13$s+13$s+14:rrQO-TRm-[ s8N):s*t~> q#C9mrVucq"om8'!)1*)s82j"l"9uiZMjh$!<<)s!<<'!ReZr7s+13$s+13$s+14:rrQO-TRm-[ s8N):s*t~> q#C9mrVll^r;Zi'qu?`1rr2u_r;[#!s-`ofN;ihWl2:V^rrD<^!<)rr!.k0$s+13$s+13$s69Ob ?N?aMs2+g9!5nhe~> q#C9mrVll^r;Zi'qu?`1rr2u_r;[#!s-`ofN;ihWl2:V^rrD<^!<)rr!.k0$s+13$s+13$s69Ob ?N?aMs2+g9!5nhe~> q#C9mrVll^r;Zi'qu?`1rr2u_r;[#!s-`ofN;ihWl2:V^rrD<^!<)rr!.k0$s+13$s+13$s69Ob ?N?aMs2+g9!5nhe~> q#C9mr;Z]q!b_#]rVuq2rVufr!q?6CrVurOrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC _Z0W9_uG5~> q#C9mr;Z]q!b_#]rVuq2rVufr!q?6CrVurOrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC _Z0W9_uG5~> q#C9mr;Z]q!b_#]rVuq2rVufr!q?6CrVurOrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC _Z0W9_uG5~> q#C9mr;Z]q!oa1Zr;cfrr;clt!:]sf!1Noer;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUe rrBt:J,~> q#C9mr;Z]q!oa1Zr;cfrr;clt!:]sf!1Noer;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUe rrBt:J,~> q#C9mr;Z]q!oa1Zr;cfrr;clt!:]sf!1Noer;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUe rrBt:J,~> q#C9mr;Z]qrr;osrVufrrr;rt!,)<2r;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!,)<2r;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!,)<2r;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;osrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mr;Z]qrr;osrVufrrr;osrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mr;Z]qrr;osrVufrrr;osrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mr;Z]qrr;osrVufrrr;osrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mr;Z]qrr;osrVufrrr;osrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mr;Z]qrr;osrVufrrr;osrr;osrr;osrVufrJcC<$JcC<$JcC<$l2Lfl!2+oC_Z0W9_uG5~> q#C9mr;Z]qrr;osrVufrrr;rt!,)<2r;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!,)<2r;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!,)<2r;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!1Noer;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!1Noer;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrrr;rt!1Noer;cisr;cfrr;_EKJcC<$JcC<$JcG!7!abr#JcEUerrBt: J,~> q#C9mr;Z]qrr;osrVufrs8N)XrVurFrr2t2rW!#Ys*XbFrVljkrW!#ad# q#C9mr;Z]qrr;osrVufrs8N)XrVurFrr2t2rW!#Ys*XbFrVljkrW!#ad# q#C9mr;Z]qrr;osrVufrs8N)XrVurFrr2t2rW!#Ys*XbFrVljkrW!#ad# q>UHJr;ZiNrr2u_r;Zo`s8W#t!9sL_r;[#,s-`ofN;`bV^&.j1I/O$Fl2L\_ZMX\&fn'0Ss+13$ s+13$s6Tae?N?aMs2+g9!5nhe~> q>UHJr;ZiNrr2u_r;Zo`s8W#t!9sL_r;[#,s-`ofN;`bV^&.j1I/O$Fl2L\_ZMX\&fn'0Ss+13$ s+13$s6Tae?N?aMs2+g9!5nhe~> q>UHJr;ZiNrr2u_r;Zo`s8W#t!9sL_r;[#,s-`ofN;`bV^&.j1I/O$Fl2L\_ZMX\&fn'0Ss+13$ s+13$s6Tae?N?aMs2+g9!5nhe~> qZ$?ks8Vrrs8Vusrr;os"Rqi[9X=Qq"hdS0B;be-!<)p#]hAERfn'0Ss+13$s+13$s6K[d?N?aM s2+g9!5nhe~> qZ$?ks8Vrrs8Vusrr;os"Rqi[9X=Qq"hdS0B;be-!<)p#]hAERfn'0Ss+13$s+13$s6K[d?N?aM s2+g9!5nhe~> qZ$?ks8Vrrs8Vusrr;os"Rqi[9X=Qq"hdS0B;be-!<)p#]hAERfn'0Ss+13$s+13$s6K[d?N?aM s2+g9!5nhe~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> i;``UJcC<$JcC<$JcC<$bl7`O!2+oC_Z0W9_uG5~> iVroBr;Zi^JcC<$JcC<$JcC<$c2RiP!2+oC_Z0W9_uG5~> iVroBr;Zi^JcC<$JcC<$JcC<$c2RiP!2+oC_Z0W9_uG5~> iVroBr;Zi^JcC<$JcC<$JcC<$c2RiP!2+oC_Z0W9_uG5~> iW&cTJcC<$JcC<$JcC<$c2RiP!2+oC_Z0W9_uG5~> iW&cTJcC<$JcC<$JcC<$c2RiP!2+oC_Z0W9_uG5~> iW&cTJcC<$JcC<$JcC<$c2RiP!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcC<$VuHg*!2+oC_Z0W9_uG5~> JcC<$JcC<$JcFp5s*TCt_uBdF!2+oC_Z0W9_uG5~> JcC<$JcC<$JcFp5s*TCt_uBdF!2+oC_Z0W9_uG5~> JcC<$JcC<$JcFp5s*TCt_uBdF!2+oC_Z0W9_uG5~> JcC<$JcC<$MuNdjrVusml1tAW!:^$gI"D=8rrQO-TRm-[s8N):s*t~> JcC<$JcC<$MuNdjrVusml1tAW!:^$gI"D=8rrQO-TRm-[s8N):s*t~> JcC<$JcC<$MuNdjrVusml1tAW!:^$gI"D=8rrQO-TRm-[s8N):s*t~> JcC<$JcC<$M>m\:RK.a1rrUjRfn'1,rrQO-TRm-[s8N):s*t~> JcC<$JcC<$M>m\:RK.a1rrUjRfn'1,rrQO-TRm-[s8N):s*t~> JcC<$JcC<$M>m\:RK.a1rrUjRfn'1,rrQO-TRm-[s8N):s*t~> g]%9:JcC<$JcC<$Y5eM%!1N]_!!%TM^&J/[B>=->!abr#JcEUerrBt:J,~> g]%9:JcC<$JcC<$Y5eM%!1N]_!!%TM^&J/[B>=->!abr#JcEUerrBt:J,~> g]%9:JcC<$JcC<$Y5eM%!1N]_!!%TM^&J/[B>=->!abr#JcEUerrBt:J,~> h#@H=!*OmQJcC<$JcDqR!s"8[^%q[.!.k0`rrp.;!#9.]q#:D&!2+oC_Z0W9_uG5~> h#@H=!*OmQJcC<$JcDqR!s"8[^%q[.!.k0`rrp.;!#9.]q#:D&!2+oC_Z0W9_uG5~> h#@H=!*OmQJcC<$JcDqR!s"8[^%q[.!.k0`rrp.;!#9.]q#:D&!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR"9AIL!875K!!%TM^&J)Iqu?d5B>=?D!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcDqR"9AIL!875K!!%TM^&J)Iqu?d5B>=?D!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcDqR"9AIL!875K!!%TM^&J)Iqu?d5B>=?D!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcDqR"T\Se9MF^Jrr<&rrs%tj9E7banGW@hnAgstrVm&,9ME.a!;uj#l).2T B>&lrkPkOsq#CI2B>=HG!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcDqR"T\Se9MF^Jrr<&rrs%tj9E7banGW@hnAgstrVm&,9ME.a!;uj#l).2T B>&lrkPkOsq#CI2B>=HG!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcDqR"T\Se9MF^Jrr<&rrs%tj9E7banGW@hnAgstrVm&,9ME.a!;uj#l).2T B>&lrkPkOsq#CI2B>=HG!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcDqR"T\T&f`6Esrr<&srs7j_^&S,c9MF.=rr[X]!!*#u#-trBs2P*>rVm,L 9[NguHiSQ]rrMSDJUdZK!+5F""Vk[b?N?aMs2+g9!5nhe~> h#@Gj!'l,8JcC<$JcDqR"T\T&f`6Esrr<&srs7j_^&S,c9MF.=rr[X]!!*#u#-trBs2P*>rVm,L 9[NguHiSQ]rrMSDJUdZK!+5F""Vk[b?N?aMs2+g9!5nhe~> h#@Gj!'l,8JcC<$JcDqR"T\T&f`6Esrr<&srs7j_^&S,c9MF.=rr[X]!!*#u#-trBs2P*>rVm,L 9[NguHiSQ]rrMSDJUdZK!+5F""Vk[b?N?aMs2+g9!5nhe~> h#@Gj!'l,8JcC<$JcDqR!!*#u!lk;0r;Q`sr;Qe1^&@s5kl=EHrVultrr2slrVlo(!<3!"n4^n% rr^pS!57h#!0;[2mJm;'!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!*#u!lk;0r;Q`sr;Qe1^&@s5kl=EHrVultrr2slrVlo(!<3!"n4^n% rr^pS!57h#!0;[2mJm;'!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!*#u!lk;0r;Q`sr;Qe1^&@s5kl=EHrVultrr2slrVlo(!<3!"n4^n% rr^pS!57h#!0;[2mJm;'!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)ut!iH%3rVlitrVlr>!9sF]!iH%(rVultrr3!!VuH\sn,WIf!N,qq s8N'!I.%"8muN$LrdOoTp&G7DJ(J$-TRm-[s8N):s*t~> h#@Gj!'l,8JcC<$JcDqR!!)ut!iH%3rVlitrVlr>!9sF]!iH%(rVultrr3!!VuH\sn,WIf!N,qq s8N'!I.%"8muN$LrdOoTp&G7DJ(J$-TRm-[s8N):s*t~> h#@Gj!'l,8JcC<$JcDqR!!)ut!iH%3rVlitrVlr>!9sF]!iH%(rVultrr3!!VuH\sn,WIf!N,qq s8N'!I.%"8muN$LrdOoTp&G7DJ(J$-TRm-[s8N):s*t~> h#@Gj!'l,8JcC<$JcDqR!!)rs!dk"$rr2rurVlnG!;lcti;dNhs8N)urr\\i9YL?'!,)',JcG!7 !5J=0![iKLrr3%,!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)rs!dk"$rr2rurVlnG!;lcti;dNhs8N)urr\\i9YL?'!,)',JcG!7 !5J=0![iKLrr3%,!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)rs!dk"$rr2rurVlnG!;lcti;dNhs8N)urr\\i9YL?'!,)',JcG!7 !5J=0![iKLrr3%,!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)ors%EOZs8N)ts8N)qs8N)ts8N)trrebj!)0 h#@Gj!'l,8JcC<$JcDqR!!)ors%EOZs8N)ts8N)qs8N)ts8N)trrebj!)0 h#@Gj!'l,8JcC<$JcDqR!!)ors%EOZs8N)ts8N)qs8N)ts8N)trrebj!)0 h#@Gj!'l,8JcC<$JcDqR!!)or"mJ^.s8N)ts8N)qs8N)ts8N)srsI__!!#^Ws8N'!n:CW!rrp.; !%39Jq#:D&!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)or"mJ^.s8N)ts8N)qs8N)ts8N)srsI__!!#^Ws8N'!n:CW!rrp.; !%39Jq#:D&!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)or"mJ^.s8N)ts8N)qs8N)ts8N)srsI__!!#^Ws8N'!n:CW!rrp.; !%39Jq#:D&!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)lq"OI.;rrE#t!bVMdqu6ZsN;`eV!;c^$l$NJis8Q^3a8Gr h#@Gj!'l,8JcC<$JcDqR!!)lq"OI.;rrE#t!bVMdqu6ZsN;`eV!;c^$l$NJis8Q^3a8Gr h#@Gj!'l,8JcC<$JcDqR!!)lq"OI.;rrE#t!bVMdqu6ZsN;`eV!;c^$l$NJis8Q^3a8Gr h#@Gj!'l,8JcC<$JcDqR!!)ip"2+]J!<)p!Z2gg#rrVEbd/F"E!<3!!!:^!f#Oh]ns8Sts9`4nk ]o7OBgA_4]!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)ip"2+]J!<)p!Z2gg#rrVEbd/F"E!<3!!!:^!f#Oh]ns8Sts9`4nk ]o7OBgA_4]!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)ip"2+]J!<)p!Z2gg#rrVEbd/F"E!<3!!!:^!f#Oh]ns8Sts9`4nk ]o7OBgA_4]!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDqR!!)fo!h')hr;Qgl!9*nV!PN.Ds8N)urrE,*rVm<,BE/"r!!$Zbs8UG> d"25NrrQO-TRm-[s8N):s*t~> h#@Gj!'l,8JcC<$JcDqR!!)fo!h')hr;Qgl!9*nV!PN.Ds8N)urrE,*rVm<,BE/"r!!$Zbs8UG> d"25NrrQO-TRm-[s8N):s*t~> h#@Gj!'l,8JcC<$JcDqR!!)fo!h')hr;Qgl!9*nV!PN.Ds8N)urrE,*rVm<,BE/"r!!$Zbs8UG> d"25NrrQO-TRm-[s8N):s*t~> h#@Gj!'l,8JcC<$JcDtS!ndS,q#:AB!;uj&fh>)ds8U,5l2CVkci='ms8N'!ZN's&!7:`F!7:TC !2kDJg&D+\!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDtS!ndS,q#:AB!;uj&fh>)ds8U,5l2CVkci='ms8N'!ZN's&!7:`F!7:TC !2kDJg&D+\!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDtS!ndS,q#:AB!;uj&fh>)ds8U,5l2CVkci='ms8N'!ZN's&!7:`F!7:TC !2kDJg&D+\!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcE"TquHQm!Ure[rs%_V9E8_'nGWCa!!iN(l+L^0I+eGt"lYmM!.;J2s4I>Q ?N?aMs2+g9!5nhe~> h#@Gj!'l,8JcC<$JcE"TquHQm!Ure[rs%_V9E8_'nGWCa!!iN(l+L^0I+eGt"lYmM!.;J2s4I>Q ?N?aMs2+g9!5nhe~> h#@Gj!'l,8JcC<$JcE"TquHQm!Ure[rs%_V9E8_'nGWCa!!iN(l+L^0I+eGt"lYmM!.;J2s4I>Q ?N?aMs2+g9!5nhe~> h#@Gj!'l,8JcC<$JcDMF!:YR>Y5\Q1!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDMF!:YR>Y5\Q1!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcDMF!:YR>Y5\Q1!2+oC_Z0W9_uG5~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'l,8JcC<$JcC<$JcF'r!abr#JcEUerrBt:J,~> h#@Gj!'mpkJO&`j!4ROZJcC<$JcDkP!abr#JcEUerrBt:J,~> h#@Gj!'mpkJO&`j!4ROZJcC<$JcDkP!abr#JcEUerrBt:J,~> h#@Gj!'mpkJO&`j!4ROZJcC<$JcDkP!abr#JcEUerrBt:J,~> h#@Gj!'mpkJH53?!2+oCJcC<$JcDkP!abr#JcEUerrBt:J,~> h#@Gj!'mpkJH53?!2+oCJcC<$JcDkP!abr#JcEUerrBt:J,~> h#@Gj!'mpkJH53?!2+oCJcC<$JcDkP!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<C?N?aMs+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<C?N?aMs+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<C?N?aMs+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=nh/c\.fs+13DrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=nh/c\.fs+13DrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=nh/c\.fs+13DrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=n^ApNMs+13DrrQO-TRm-[ s8N):s*t~> h#@Gj!'mpk!<=n^ApNMs+13DrrQO-TRm-[ s8N):s*t~> h#@Gj!'mpk!<=n^ApNMs+13DrrQO-TRm-[ s8N):s*t~> h#@Gj!'mpk!<=i!'l,8JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=F"H96k!!(dR !l"_#JcC<$U&P1$!2+oC_Z0W9_uG5~> h#@Gj!'mpk!<=F"H96k!!(dR !l"_#JcC<$U&P1$!2+oC_Z0W9_uG5~> h#@Gj!'mpk!<=F"H96k!!(dR !l"_#JcC<$U&P1$!2+oC_Z0W9_uG5~> h#@Gj!'mpk!<=i!'l,8 JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8 JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8 JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8 JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8 JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<=i!'l,8 JcDGD!abr#JcEUerrBt:J,~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=Aq[9W.CZrs8,7RK3B.B)o70s8N)RrrTq85_8rd s.TGo?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=Aq[9W.CZrs8,7RK3B.B)o70s8N)RrrTq85_8rd s.TGo?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=Aq[9W.CZrs8,7RK3B.B)o70s8N)RrrTq85_8rd s.TGo?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=->l$NK:rVultr;RGp9YLK+fh>)ms8Q_E!!'=hiFdQ1s8N)R rrTq85_8rds02M*TMV h#@Gj!'mpk!<=->l$NK:rVultr;RGp9YLK+fh>)ms8Q_E!!'=hiFdQ1s8N)R rrTq85_8rds02M*TMV h#@Gj!'mpk!<=->l$NK:rVultr;RGp9YLK+fh>)ms8Q_E!!'=hiFdQ1s8N)R rrTq85_8rds02M*TMV h#@Gj!'nF$!9!ML!<=%k!q61`rVultr;Qe1^&@s5kl=EHrr;uu!7:68rrCgR!l"_# JcC<$Yl=]rrW!!rT^V^V!abr#JcEUerrBt:J,~> h#@Gj!'nF$!9!ML!<=%k!q61`rVultr;Qe1^&@s5kl=EHrr;uu!7:68rrCgR!l"_# JcC<$Yl=]rrW!!rT^V^V!abr#JcEUerrBt:J,~> h#@Gj!'nF$!9!ML!<=%k!q61`rVultr;Qe1^&@s5kl=EHrr;uu!7:68rrCgR!l"_# JcC<$Yl=]rrW!!rT^V^V!abr#JcEUerrBt:J,~> h#@Gj!'nF$"$e&LchIG?!$[!op&>)C!2/9M!+5U'!^N+8qZ$QqhuE]Vo`+pks8N*"VuH\sn,WIf !keTurVlr`9RQj>rrDusrrDusrrE#ts*XbErrE#trrE#t!lk<*r;Qhr!4)V(rrDNfrrCgR!l"_# JcC<$Yl=]rqZ$[oT^VgY!abr#JcEUerrBt:J,~> h#@Gj!'nF$"$e&LchIG?!$[!op&>)C!2/9M!+5U'!^N+8qZ$QqhuE]Vo`+pks8N*"VuH\sn,WIf !keTurVlr`9RQj>rrDusrrDusrrE#ts*XbErrE#trrE#t!lk<*r;Qhr!4)V(rrDNfrrCgR!l"_# JcC<$Yl=]rqZ$[oT^VgY!abr#JcEUerrBt:J,~> h#@Gj!'nF$"$e&LchIG?!$[!op&>)C!2/9M!+5U'!^N+8qZ$QqhuE]Vo`+pks8N*"VuH\sn,WIf !keTurVlr`9RQj>rrDusrrDusrrE#ts*XbErrE#trrE#t!lk<*r;Qhr!4)V(rrDNfrrCgR!l"_# JcC<$Yl=]rqZ$[oT^VgY!abr#JcEUerrBt:J,~> h#@Gj!'nF$!'pM`![;U0qYpQr,(]derrRZMT]#hM?haU&5aU[4s8N)Vs8N)ks8N*!rr\\i9YL?' !IOn@s8N)ss8N)ss8N)prrhi3HiO0Fs8N)trrIKIqu6`V!,)<2rrDNfrrCgR!l"_#JcC<$Yl=]r p](OqT^Vp\?N?aMs2+g9!5nhe~> h#@Gj!'nF$!'pM`![;U0qYpQr,(]derrRZMT]#hM?haU&5aU[4s8N)Vs8N)ks8N*!rr\\i9YL?' !IOn@s8N)ss8N)ss8N)prrhi3HiO0Fs8N)trrIKIqu6`V!,)<2rrDNfrrCgR!l"_#JcC<$Yl=]r p](OqT^Vp\?N?aMs2+g9!5nhe~> h#@Gj!'nF$!'pM`![;U0qYpQr,(]derrRZMT]#hM?haU&5aU[4s8N)Vs8N)ks8N*!rr\\i9YL?' !IOn@s8N)ss8N)ss8N)prrhi3HiO0Fs8N)trrIKIqu6`V!,)<2rrDNfrrCgR!l"_#JcC<$Yl=]r p](OqT^Vp\?N?aMs2+g9!5nhe~> h#@Gj!'nF$!'pD]![;U0rVllu,(]derrRZM9&Mr7(%hP15aU[6!!(pV!fR-DpAY3`!0$pW"I];j 9W.jhrrDcmrrDusrrDusrrDrr#2u"EZKV>hrVultrVultqZ$Qqrr;uun,NCfg]%Aj!'kLS5_22* 5QE2)!!H,k=ob4Hs2+g9!5nhe~> h#@Gj!'nF$!'pD]![;U0rVllu,(]derrRZM9&Mr7(%hP15aU[6!!(pV!fR-DpAY3`!0$pW"I];j 9W.jhrrDcmrrDusrrDusrrDrr#2u"EZKV>hrVultrVultqZ$Qqrr;uun,NCfg]%Aj!'kLS5_22* 5QE2)!!H,k=ob4Hs2+g9!5nhe~> h#@Gj!'nF$!'pD]![;U0rVllu,(]derrRZM9&Mr7(%hP15aU[6!!(pV!fR-DpAY3`!0$pW"I];j 9W.jhrrDcmrrDusrrDusrrDrr#2u"EZKV>hrVultrVultqZ$Qqrr;uun,NCfg]%Aj!'kLS5_22* 5QE2)!!H,k=ob4Hs2+g9!5nhe~> h#@Gj!'nF$!'p;Z"X7p3rr=6os7QBnIfL53!!GQRpAb3NrrTJ+a7fN7f`9(krsI__!!#^Ws8N'! l1b5X!;uls!;uls!;uiuZ2hT;s8N)ts8N)ts8N)qs8N)us8N)fs8N)RrrTq84b3Ta!29Gq'd h#@Gj!'nF$!'p;Z"X7p3rr=6os7QBnIfL53!!GQRpAb3NrrTJ+a7fN7f`9(krsI__!!#^Ws8N'! l1b5X!;uls!;uls!;uiuZ2hT;s8N)ts8N)ts8N)qs8N)us8N)fs8N)RrrTq84b3Ta!29Gq'd h#@Gj!'nF$!'p;Z"X7p3rr=6os7QBnIfL53!!GQRpAb3NrrTJ+a7fN7f`9(krsI__!!#^Ws8N'! l1b5X!;uls!;uls!;uiuZ2hT;s8N)ts8N)ts8N)qs8N)us8N)fs8N)RrrTq84b3Ta!29Gq'd h#@Jk!%o"p!!4>E,(]derrRZMQ/KCW8G<)c5aU[5s8N)VrrVZiI.mR@VbHse#jH^:N;roj!6>$; !Usb$s8N)ss8N)ss8N)trrTJ+a8Q& h#@Jk!%o"p!!4>E,(]derrRZMQ/KCW8G<)c5aU[5s8N)VrrVZiI.mR@VbHse#jH^:N;roj!6>$; !Usb$s8N)ss8N)ss8N)trrTJ+a8Q& h#@Jk!%o"p!!4>E,(]derrRZMQ/KCW8G<)c5aU[5s8N)VrrVZiI.mR@VbHse#jH^:N;roj!6>$; !Usb$s8N)ss8N)ss8N)trrTJ+a8Q& h#@Jk!%o"p!!4>E,(]derrRZMT]#hM?hsa(5aU[2s8N)UrrTk6a8#Z9i;gptrrE,hrr35m!!*'! VZ9EgrrKEorr;uur;Zcsr;ZcsrVultr;ZcsrVultrVlr)!2obp!pK^3rr;uun,NCfg]%>i!'l,8 JcDtS!20/g!Yo(GrVlq+!2..-"2+[7^%VI.]`8&cQN-sb_uG5~> h#@Jk!%o"p!!4>E,(]derrRZMT]#hM?hsa(5aU[2s8N)UrrTk6a8#Z9i;gptrrE,hrr35m!!*'! VZ9EgrrKEorr;uur;Zcsr;ZcsrVultr;ZcsrVultrVlr)!2obp!pK^3rr;uun,NCfg]%>i!'l,8 JcDtS!20/g!Yo(GrVlq+!2..-"2+[7^%VI.]`8&cQN-sb_uG5~> h#@Jk!%o"p!!4>E,(]derrRZMT]#hM?hsa(5aU[2s8N)UrrTk6a8#Z9i;gptrrE,hrr35m!!*'! VZ9EgrrKEorr;uur;Zcsr;ZcsrVultr;ZcsrVultrVlr)!2obp!pK^3rr;uun,NCfg]%>i!'l,8 JcDtS!20/g!Yo(GrVlq+!2..-"2+[7^%VI.]`8&cQN-sb_uG5~> h#@Gj!'nF$!'p;Z"X7p3rr=6os7QBnIfQ/"rr?F)!!5EPkP5)W!8[YVVbH(GrrV.QVu?Vr!4)S'% 01&@s6p!gI-L\2f`:"1s8N)ss8N)ss8N)ts8N'!nGWCe!<)rt!;uiu9E=&MrrKfGrVultn,NCfg ]%>i!'l,8JcDtS!208j!Yo(GqYpV(!2.+,rr<$mpAY2,!!&;arrBt:J,~> h#@Gj!'nF$!'p;Z"X7p3rr=6os7QBnIfQ/"rr?F)!!5EPkP5)W!8[YVVbH(GrrV.QVu?Vr!4)S'% 01&@s6p!gI-L\2f`:"1s8N)ss8N)ss8N)ts8N'!nGWCe!<)rt!;uiu9E=&MrrKfGrVultn,NCfg ]%>i!'l,8JcDtS!208j!Yo(GqYpV(!2.+,rr<$mpAY2,!!&;arrBt:J,~> h#@Gj!'nF$!'p;Z"X7p3rr=6os7QBnIfQ/"rr?F)!!5EPkP5)W!8[YVVbH(GrrV.QVu?Vr!4)S'% 01&@s6p!gI-L\2f`:"1s8N)ss8N)ss8N)ts8N'!nGWCe!<)rt!;uiu9E=&MrrKfGrVultn,NCfg ]%>i!'l,8JcDtS!208j!Yo(GqYpV(!2.+,rr<$mpAY2,!!&;arrBt:J,~> h#@Gj!'nF$!'pD]!Yo\#rVllu,(]derrRZMT]#hQ?Na%Yasrr^:A!9*JJ"5s4[iS=G7^ApNMs+13Srretp'jn0=rrQO-TYLL/!2fh1q#:HCVZ6^^ s8N):s*t~> h#@Gj!'nF$!'pD]!Yo\#rVllu,(]derrRZMT]#hQ?Na%Yasrr^:A!9*JJ"5s4[iS=G7^ApNMs+13Srretp'jn0=rrQO-TYLL/!2fh1q#:HCVZ6^^ s8N):s*t~> h#@Gj!'nF$!'pD]!Yo\#rVllu,(]derrRZMT]#hQ?Na%Yasrr^:A!9*JJ"5s4[iS=G7^ApNMs+13Srretp'jn0=rrQO-TYLL/!2fh1q#:HCVZ6^^ s8N):s*t~> h#@Gj!'nF$!'pM`!Yo@_qYpQr,(]derrRZMT]#hNa63$nrrCgR!q h#@Gj!'nF$!'pM`!Yo@_qYpQr,(]derrRZMT]#hNa63$nrrCgR!q h#@Gj!'nF$!'pM`!Yo@_qYpQr,(]derrRZMT]#hNa63$nrrCgR!q h#@Gj!'nF$"$dT6^\@a/!$[!op&>)C!2.[+ h#@Gj!'nF$"$dT6^\@a/!$[!op&>)C!2.[+ h#@Gj!'nF$"$dT6^\@a/!$[!op&>)C!2.[+ h#@Gj!'nF$!8$lC!<= h#@Gj!'nF$!8$lC!<= h#@Gj!'nF$!8$lC!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=*Brr@HGs8N)r s8N)rrr[WKN2QRQ!,)',rr;uu]`8!3_uG5~> h#@Gj!'mpk!<=*Brr@HGs8N)r s8N)rrr[WKN2QRQ!,)',rr;uu]`8!3_uG5~> h#@Gj!'mpk!<=*Brr@HGs8N)r s8N)rrr[WKN2QRQ!,)',rr;uu]`8!3_uG5~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=GrrDrr rrDrr"H;Tc!.=_E!bVMRr;QfeBE%r2!5/@3!5nhe~> h#@Gj!'mpk!<=GrrDrr rrDrr"H;Tc!.=_E!bVMRr;QfeBE%r2!5/@3!5nhe~> h#@Gj!'mpk!<=GrrDrr rrDrr"H;Tc!.=_E!bVMRr;QfeBE%r2!5/@3!5nhe~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=8^&J'/!5AL5!5nhe~> h#@Gj!'mpk!<=8^&J'/!5AL5!5nhe~> h#@Gj!'mpk!<=8^&J'/!5AL5!5nhe~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=nh/c\.fs+13DrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=nh/c\.fs+13DrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=nh/c\.fs+13DrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=>1s8)fDs7lWrI&GrHrrRZMTRm,os+13$s/l;&?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=>1s8)fDs7lWrI&GrHrrRZMTRm,os+13$s/l;&?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=>1s8)fDs7lWrI&GrHrrRZMTRm,os+13$s/l;&?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=>0rr^pS!85]u$J>CZl2UeQcqFGdbl7`o!2+oCJcC<$JcDkP!abr#JcEUerrBt: J,~> h#@Gj!'mpk!<=>0rr^pS!85]u$J>CZl2UeQcqFGdbl7`o!2+oCJcC<$JcDkP!abr#JcEUerrBt: J,~> h#@Gj!'mpk!<=>0rr^pS!85]u$J>CZl2UeQcqFGdbl7`o!2+oCJcC<$JcDkP!abr#JcEUerrBt: J,~> h#@Gj!'mpk!<=>/s8N)Ds8N)rrrQg5g!0NuIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)Ds8N)rrrQg5g!0NuIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)Ds8N)rrrQg5g!0NuIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)Ds8N)rrrUOII*MZmIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)Ds8N)rrrUOII*MZmIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)Ds8N)rrrUOII*MZmIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)Ds8N)qs8N)DrrRZMTRm,os+13$s/l;&?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=>/s8N)Ds8N)qs8N)DrrRZMTRm,os+13$s/l;&?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=>/s8N)Ds8N)qs8N)DrrRZMTRm,os+13$s/l;&?N?aMs2+g9!5nhe~> h#@Gj!'mpk!<=>/s8N)krs%tj9E7banG`FfN;WbVrrA#V!!;-Zs8DuuN;*AP!;c`q!<3!&iL3F? !.;KXrro]%9YKZjrVm&,9ME.a!:9^eIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)krs%tj9E7banG`FfN;WbVrrA#V!!;-Zs8DuuN;*AP!;c`q!<3!&iL3F? !.;KXrro]%9YKZjrVm&,9ME.a!:9^eIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)krs%tj9E7banG`FfN;WbVrrA#V!!;-Zs8DuuN;*AP!;c`q!<3!&iL3F? !.;KXrro]%9YKZjrVm&,9ME.a!:9^eIfQ-ms+13$s+13PrrQO-TRm-[s8N):s*t~> h#@Gj!'mpk!<=>/s8N)lrs7j_^&S,c9MF.=rrT(u!<)p"i;`l:rVlluZM+=u!;ld*i;e9*s3Lbd s8V>2!4)V(#-trBs2P*>rr32.^&S,Q!!)Bc!e13CJcC<$JcC<$XoAH0!2+oC_Z.^X!>X#Zs*t~> h#@Gj!'mpk!<=>/s8N)lrs7j_^&S,c9MF.=rrT(u!<)p"i;`l:rVlluZM+=u!;ld*i;e9*s3Lbd s8V>2!4)V(#-trBs2P*>rr32.^&S,Q!!)Bc!e13CJcC<$JcC<$XoAH0!2+oC_Z.^X!>X#Zs*t~> h#@Gj!'mpk!<=>/s8N)lrs7j_^&S,c9MF.=rrT(u!<)p"i;`l:rVlluZM+=u!;ld*i;e9*s3Lbd s8V>2!4)V(#-trBs2P*>rr32.^&S,Q!!)Bc!e13CJcC<$JcC<$XoAH0!2+oC_Z.^X!>X#Zs*t~> h#@Gj!'mpk!<=>/s8N)lrrHcGrVlua!)2n]rrQg5l2CV`Mu_6(rrMV%p&G$lqu6kJ!87DP9E>%k !q61`rr2slrVlo(!<2uu9`=tlZ2j7k!e13CJcC<$JcC<$XoAH0!2+oC_Z.[W!3Q.uJ,~> h#@Gj!'mpk!<=>/s8N)lrrHcGrVlua!)2n]rrQg5l2CV`Mu_6(rrMV%p&G$lqu6kJ!87DP9E>%k !q61`rr2slrVlo(!<2uu9`=tlZ2j7k!e13CJcC<$JcC<$XoAH0!2+oC_Z.[W!3Q.uJ,~> h#@Gj!'mpk!<=>/s8N)lrrHcGrVlua!)2n]rrQg5l2CV`Mu_6(rrMV%p&G$lqu6kJ!87DP9E>%k !q61`rr2slrVlo(!<2uu9`=tlZ2j7k!e13CJcC<$JcC<$XoAH0!2+oC_Z.[W!3Q.uJ,~> h#@Gj!'mpk!<=>/s8N)mrrU4@l2:P_VZ=%%rrTJ+ZMje)9E:O\rrL0Gp&G$l!7:`F"5.<\d/O(F I/O$E!<3!!!2ohr!Up*grrE+trr3#g!:9^eIfQ-ms+13$s+13PrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=>/s8N)mrrU4@l2:P_VZ=%%rrTJ+ZMje)9E:O\rrL0Gp&G$l!7:`F"5.<\d/O(F I/O$E!<3!!!2ohr!Up*grrE+trr3#g!:9^eIfQ-ms+13$s+13PrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=>/s8N)mrrU4@l2:P_VZ=%%rrTJ+ZMje)9E:O\rrL0Gp&G$l!7:`F"5.<\d/O(F I/O$E!<3!!!2ohr!Up*grrE+trr3#g!:9^eIfQ-ms+13$s+13PrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=>/s8N)mrrIKIqu6`V!,)<2!pK\Yrr3)IZ2an(rrIN3p&Fmh!K>(orrhi3HiO0G rr\\i9YL?'".B3`^$5OuIfQ-ms+13$s+13PrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=>/s8N)mrrIKIqu6`V!,)<2!pK\Yrr3)IZ2an(rrIN3p&Fmh!K>(orrhi3HiO0G rr\\i9YL?'".B3`^$5OuIfQ-ms+13$s+13PrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=>/s8N)mrrIKIqu6`V!,)<2!pK\Yrr3)IZ2an(rrIN3p&Fmh!K>(orrhi3HiO0G rr\\i9YL?'".B3`^$5OuIfQ-ms+13$s+13PrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=>/s8N)ms8N)qs8N)trsX8Tg&M)"n h#@Gj!'mpk!<=>/s8N)ms8N)qs8N)trsX8Tg&M)"n h#@Gj!'mpk!<=>/s8N)ms8N)qs8N)trsX8Tg&M)"n h#@Gj!'mpk!<=>/s8N)ms8N)qs8N)trsZpJVuQ"Ms4IC@s2VG;s8N)lrrTJ+^&J'3!;uj#iMQYU 9^2NU"lZ?Z!)2YErrRZMTRm,os+13$s/l;&?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=>/s8N)ms8N)qs8N)trsZpJVuQ"Ms4IC@s2VG;s8N)lrrTJ+^&J'3!;uj#iMQYU 9^2NU"lZ?Z!)2YErrRZMTRm,os+13$s/l;&?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=>/s8N)ms8N)qs8N)trsZpJVuQ"Ms4IC@s2VG;s8N)lrrTJ+^&J'3!;uj#iMQYU 9^2NU"lZ?Z!)2YErrRZMTRm,os+13$s/l;&?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=>/s8N)qrs%sds8Q^3g&(dM!0$mV%.F6js/4QMs%EF^I-L;'rrDcm!jVgHrVult qYpZ^HiT-&rr_M5!0$=F!e13CJcC<$JcC<$XoAH0!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=>/s8N)qrs%sds8Q^3g&(dM!0$mV%.F6js/4QMs%EF^I-L;'rrDcm!jVgHrVult qYpZ^HiT-&rr_M5!0$=F!e13CJcC<$JcC<$XoAH0!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=>/s8N)qrs%sds8Q^3g&(dM!0$mV%.F6js/4QMs%EF^I-L;'rrDcm!jVgHrVult qYpZ^HiT-&rr_M5!0$=F!e13CJcC<$JcC<$XoAH0!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=>/s8N)qrs#cfs8TA)Vu6PrklB*.rr\\id!Yim"/c.)I.RC h#@Gj!'mpk!<=>/s8N)qrs#cfs8TA)Vu6PrklB*.rr\\id!Yim"/c.)I.RC h#@Gj!'mpk!<=>/s8N)qrs#cfs8TA)Vu6PrklB*.rr\\id!Yim"/c.)I.RC h#@Gj!'mpk!<=>/s8N)rrrV[`^&J$59E=&MrrKfGqu6cF!)1**rr^pS!6=^2rrDcmrr<&grVult rr3!!ZMje,!,)?3!4)S'! h#@Gj!'mpk!<=>/s8N)rrrV[`^&J$59E=&MrrKfGqu6cF!)1**rr^pS!6=^2rrDcmrr<&grVult rr3!!ZMje,!,)?3!4)S'! h#@Gj!'mpk!<=>/s8N)rrrV[`^&J$59E=&MrrKfGqu6cF!)1**rr^pS!6=^2rrDcmrr<&grVult rr3!!ZMje,!,)?3!4)S'! h#@Gj!'mpk!<=>0rr^pS!9*nV"5/&%g&D!Wfh>)ds8U,5l2(D]9E=S\rrPjonFZ__f`2$*p\u83 !.=;9d$aq7n?W&o!4)Y)VZ>*Drr<&)s8Stsd-^i7IfQ-ms+14#rr?DW!5JR7^RY<*?N?aMs2+g9 !6kHE?N@k h#@Gj!'mpk!<=>0rr^pS!9*nV"5/&%g&D!Wfh>)ds8U,5l2(D]9E=S\rrPjonFZ__f`2$*p\u83 !.=;9d$aq7n?W&o!4)Y)VZ>*Drr<&)s8Stsd-^i7IfQ-ms+14#rr?DW!5JR7^RY<*?N?aMs2+g9 !6kHE?N@k h#@Gj!'mpk!<=>0rr^pS!9*nV"5/&%g&D!Wfh>)ds8U,5l2(D]9E=S\rrPjonFZ__f`2$*p\u83 !.=;9d$aq7n?W&o!4)Y)VZ>*Drr<&)s8Stsd-^i7IfQ-ms+14#rr?DW!5JR7^RY<*?N?aMs2+g9 !6kHE?N@k h#@Gj!'mpk!<=>1s7H?lnGW@kl'b9GB;b7prrK$Vr;Qf'I.[I9!;HL*VZ6^Ed/TO7N9U?Bl+L^0 I+eN!"p!o$B)m>4m/I-:!2.[ h#@Gj!'mpk!<=>1s7H?lnGW@kl'b9GB;b7prrK$Vr;Qf'I.[I9!;HL*VZ6^Ed/TO7N9U?Bl+L^0 I+eN!"p!o$B)m>4m/I-:!2.[ h#@Gj!'mpk!<=>1s7H?lnGW@kl'b9GB;b7prrK$Vr;Qf'I.[I9!;HL*VZ6^Ed/TO7N9U?Bl+L^0 I+eN!"p!o$B)m>4m/I-:!2.[ h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=rrDoq"7U[ h#@Gj!'mpk!<=rrDoq"7U[ h#@Gj!'mpk!<=rrDoq"7U[ h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=rrDfn!_`UYoD\m=!!&8`!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=rrDfn!_`UYoD\m=!!&8`!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=rrDfn!_`UYoD\m=!!&8`!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<=rrDfn!oX-,rr35M9[NguHiSQms8N)trrVEb!<)p.i;`lXs*SGZ!56)Gs/,k1 rr3OWB)hr3s*SGZ!56)Gs/,k1rVm)k9RQ@0iCs1Mdf0A6!5G'(!abr#JcEUerrC:C!abrBqu;0~> h#@Gj!'mpk!<=rrDfn!oX-,rr35M9[NguHiSQms8N)trrVEb!<)p.i;`lXs*SGZ!56)Gs/,k1 rr3OWB)hr3s*SGZ!56)Gs/,k1rVm)k9RQ@0iCs1Mdf0A6!5G'(!abr#JcEUerrC:C!abrBqu;0~> h#@Gj!'mpk!<=rrDfn!oX-,rr35M9[NguHiSQms8N)trrVEb!<)p.i;`lXs*SGZ!56)Gs/,k1 rr3OWB)hr3s*SGZ!56)Gs/,k1rVm)k9RQ@0iCs1Mdf0A6!5G'(!abr#JcEUerrC:C!abrBqu;0~> h#@Gj!'mpk!<=!;?Hm!<<'#n4^n%rr^pS!58C3rrDusrrDusrrE#trr<&`rr3&h!,)60rrE#trr<&` rr3&h!,)91!h',Yrr3&H!2n3D!^Hb#XoAEpi:?mL?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=!;?Hm!<<'#n4^n%rr^pS!58C3rrDusrrDusrrE#trr<&`rr3&h!,)60rrE#trr<&` rr3&h!,)91!h',Yrr3&H!2n3D!^Hb#XoAEpi:?mL?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=!;?Hm!<<'#n4^n%rr^pS!58C3rrDusrrDusrrE#trr<&`rr3&h!,)60rrE#trr<&` rr3&h!,)91!h',Yrr3&H!2n3D!^Hb#XoAEpi:?mL?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=s(>sE!4(kJB70:M!pK^3h>[KU ,1cbr?VmEaq#:D&!2.a>rrDcmrrE*!!N,qqs8N'!I/a0G!;uls!;uls!<)rt!;uls!;uls!<)rt !;uls!<)rt!;uit!)1c>!^Hb#XoAMJ!%s>jp&>)#!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=s(>sE!4(kJB70:M!pK^3h>[KU ,1cbr?VmEaq#:D&!2.a>rrDcmrrE*!!N,qqs8N'!I/a0G!;uls!;uls!<)rt!;uls!;uls!<)rt !;uls!<)rt!;uit!)1c>!^Hb#XoAMJ!%s>jp&>)#!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=s(>sE!4(kJB70:M!pK^3h>[KU ,1cbr?VmEaq#:D&!2.a>rrDcmrrE*!!N,qqs8N'!I/a0G!;uls!;uls!<)rt!;uls!;uls!<)rt !;uls!<)rt!;uit!)1c>!^Hb#XoAMJ!%s>jp&>)#!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'mpk!<=%k!q61`rVultr;Qe1^&@s5kl=EHrr;uu!7:06!PN.$rrE*Df)G_WrW!!rT^VdX !abr#dJs4HpAb-ms8N(3p]1 h#@Gj!'mpk!<=%k!q61`rVultr;Qe1^&@s5kl=EHrr;uu!7:06!PN.$rrE*Df)G_WrW!!rT^VdX !abr#dJs4HpAb-ms8N(3p]1 h#@Gj!'mpk!<=%k!q61`rVultr;Qe1^&@s5kl=EHrr;uu!7:06!PN.$rrE*Df)G_WrW!!rT^VdX !abr#dJs4HpAb-ms8N(3p]1 h#@Gj!'mpk!<=!;HKti;ei:rr<&ms8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)trrT(ud/O%Hn,SEo rrPFc^TIM9,5M9@/s"rfrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=!;HKti;ei:rr<&ms8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)trrT(ud/O%Hn,SEo rrPFc^TIM9,5M9@/s"rfrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=!;HKti;ei:rr<&ms8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)trrT(ud/O%Hn,SEo rrPFc^TIM9,5M9@/s"rfrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<=^Ao#C!!4d6 i;W`X?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=^Ao#C!!4d6 i;W`X?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=^Ao#C!!4d6 i;W`X?N?aMs2+g9!6kHE?N@k h#@Gj!'mpk!<=>-es8Q^3 a8Gr h#@Gj!'mpk!<=>-es8Q^3 a8Gr h#@Gj!'mpk!<=>-es8Q^3 a8Gr h#@Gj!'nF$!O(GSrrE*DJcGEC!e13Ci;WhN^[hC++opQZrrTJ+a7fN7f`9(krsI__!!#^Ws8N'! l1b5X!;uls!;uls!;uiuZ2hT;s8N)ts8N)ts8N)qs8N)us8N)grrMAig&K"k!*%AGrrDio!dk!] rr3%t!)3=j!POHks8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)trrVFYiQM6'mhGgTX[)OZ #9n-5s8QF+TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!O(GSrrE*DJcGEC!e13Ci;WhN^[hC++opQZrrTJ+a7fN7f`9(krsI__!!#^Ws8N'! l1b5X!;uls!;uls!;uiuZ2hT;s8N)ts8N)ts8N)qs8N)us8N)grrMAig&K"k!*%AGrrDio!dk!] rr3%t!)3=j!POHks8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)trrVFYiQM6'mhGgTX[)OZ #9n-5s8QF+TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!O(GSrrE*DJcGEC!e13Ci;WhN^[hC++opQZrrTJ+a7fN7f`9(krsI__!!#^Ws8N'! l1b5X!;uls!;uls!;uiuZ2hT;s8N)ts8N)ts8N)qs8N)us8N)grrMAig&K"k!*%AGrrDio!dk!] rr3%t!)3=j!POHks8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)trrVFYiQM6'mhGgTX[)OZ #9n-5s8QF+TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$"@)r>O5Tg5!<=Pr;QfeBE%r2!;uls!;uls!<)p!Z2hrDs8N)ts8N)trrQg5g&(dM!0$pWrrDQg!6 h#@Gj!'nF$"@)r>O5Tg5!<=Pr;QfeBE%r2!;uls!;uls!<)p!Z2hrDs8N)ts8N)trrQg5g&(dM!0$pWrrDQg!6 h#@Gj!'nF$"@)r>O5Tg5!<=Pr;QfeBE%r2!;uls!;uls!<)p!Z2hrDs8N)ts8N)trrQg5g&(dM!0$pWrrDQg!6 h#@Gj!'nF$!'pJ_!\TPlqu6Zs,(]derrRZMT]#hM5lCZa'kb;VrrOAEi8=P9]`?+JrrV-Za8Z)> !:^!f#Oh]ns8Sts9`4nkZC:dmrrDusrrDusrrE#trrDusrrE#trrE#t!jVg(r;Qi_!7:`FrrDTh !6>!:!577h!<==prr?F&!!am$fDkkX!2.d?"PEbTiUHjH"PK[Q9YL?'!7:TC!2oeq(46,@fo5t2 ]`=u1s1QGQ!,$]Zci=(!rr3)i!!(CFrs@$P!7:cGci=(!rr3)i!!(CFrr>ag!!&qErrPFc^TIM9 ,5_EB,&km(rrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pJ_!\TPlqu6Zs,(]derrRZMT]#hM5lCZa'kb;VrrOAEi8=P9]`?+JrrV-Za8Z)> !:^!f#Oh]ns8Sts9`4nkZC:dmrrDusrrDusrrE#trrDusrrE#trrE#t!jVg(r;Qi_!7:`FrrDTh !6>!:!577h!<==prr?F&!!am$fDkkX!2.d?"PEbTiUHjH"PK[Q9YL?'!7:TC!2oeq(46,@fo5t2 ]`=u1s1QGQ!,$]Zci=(!rr3)i!!(CFrs@$P!7:cGci=(!rr3)i!!(CFrr>ag!!&qErrPFc^TIM9 ,5_EB,&km(rrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pJ_!\TPlqu6Zs,(]derrRZMT]#hM5lCZa'kb;VrrOAEi8=P9]`?+JrrV-Za8Z)> !:^!f#Oh]ns8Sts9`4nkZC:dmrrDusrrDusrrE#trrDusrrE#trrE#t!jVg(r;Qi_!7:`FrrDTh !6>!:!577h!<==prr?F&!!am$fDkkX!2.d?"PEbTiUHjH"PK[Q9YL?'!7:TC!2oeq(46,@fo5t2 ]`=u1s1QGQ!,$]Zci=(!rr3)i!!(CFrs@$P!7:cGci=(!rr3)i!!(CFrr>ag!!&qErrPFc^TIM9 ,5_EB,&km(rrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pA\!\TPlrr3!!,(]derrRZMT]#hM5l(H^'kb;YrrOAEi84J8VbH(GrrV.QVu?Vr !4)S'%01&@s6p!gI-L\2f`:"1s8N)ss8N)ss8N)ts8N'!nGWCe!<)rt!;uiu9E=&MrrKfGrVult o)A^1r;QifR[W+5!<==prr?F)!!4NtfDPXM?N?bJs7cQqB8jn+rrqAM!!%D[r;Ql`B)nk.rs>u) !1N0P!1LstqZ-Zrqu?`so`5$lquHcs!ROO9!!&qFrrPFc^TIM>+ohTeE6n7X!abr#JcEUerrC:C !abrBqu;0~> h#@Gj!'nF$!'pA\!\TPlrr3!!,(]derrRZMT]#hM5l(H^'kb;YrrOAEi84J8VbH(GrrV.QVu?Vr !4)S'%01&@s6p!gI-L\2f`:"1s8N)ss8N)ss8N)ts8N'!nGWCe!<)rt!;uiu9E=&MrrKfGrVult o)A^1r;QifR[W+5!<==prr?F)!!4NtfDPXM?N?bJs7cQqB8jn+rrqAM!!%D[r;Ql`B)nk.rs>u) !1N0P!1LstqZ-Zrqu?`so`5$lquHcs!ROO9!!&qFrrPFc^TIM>+ohTeE6n7X!abr#JcEUerrC:C !abrBqu;0~> h#@Gj!'nF$!'pA\!\TPlrr3!!,(]derrRZMT]#hM5l(H^'kb;YrrOAEi84J8VbH(GrrV.QVu?Vr !4)S'%01&@s6p!gI-L\2f`:"1s8N)ss8N)ss8N)ts8N'!nGWCe!<)rt!;uiu9E=&MrrKfGrVult o)A^1r;QifR[W+5!<==prr?F)!!4NtfDPXM?N?bJs7cQqB8jn+rrqAM!!%D[r;Ql`B)nk.rs>u) !1N0P!1LstqZ-Zrqu?`so`5$lquHcs!ROO9!!&qFrrPFc^TIM>+ohTeE6n7X!abr#JcEUerrC:C !abrBqu;0~> h#@Jk!'nlJ^Aon\!!Fp8huFsPs7QBnIfO]NIfL\e!!3mJ^]+67+opQWrr]q7Vr@XT"50SGd/)ds8U,5l2L\b`rH+uo`"o=q#CEAhZ!TV,1cbs?N;I'fD5FJ?N?aMs8N$!fr+`I!pQT_df0A6 !5GZ9!^L_NoD\l!!2+oC_Z0W9bl7`O!5JF2J,~> h#@Jk!'nlJ^Aon\!!Fp8huFsPs7QBnIfO]NIfL\e!!3mJ^]+67+opQWrr]q7Vr@XT"50SGd/)ds8U,5l2L\b`rH+uo`"o=q#CEAhZ!TV,1cbs?N;I'fD5FJ?N?aMs8N$!fr+`I!pQT_df0A6 !5GZ9!^L_NoD\l!!2+oC_Z0W9bl7`O!5JF2J,~> h#@Jk!'nlJ^Aon\!!Fp8huFsPs7QBnIfO]NIfL\e!!3mJ^]+67+opQWrr]q7Vr@XT"50SGd/)ds8U,5l2L\b`rH+uo`"o=q#CEAhZ!TV,1cbs?N;I'fD5FJ?N?aMs8N$!fr+`I!pQT_df0A6 !5GZ9!^L_NoD\l!!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!%5)Q!$[!op&>#Aci=4aO7sgui8">6n?S#P!!/&!qYpa"l+L^0I+eGt"lYmM!.[KU,1cbp\(C?R !abr#JcGcM!q8nJq>UEpdf0A6!5G'(!abr#JcEUerrC:C!abrBqu;0~> h#@Gj!%5)Q!$[!op&>#Aci=4aO7sgui8">6n?S#P!!/&!qYpa"l+L^0I+eGt"lYmM!.[KU,1cbp\(C?R !abr#JcGcM!q8nJq>UEpdf0A6!5G'(!abr#JcEUerrC:C!abrBqu;0~> h#@Gj!%5)Q!$[!op&>#Aci=4aO7sgui8">6n?S#P!!/&!qYpa"l+L^0I+eGt"lYmM!.[KU,1cbp\(C?R !abr#JcGcM!q8nJq>UEpdf0A6!5G'(!abr#JcEUerrC:C!abrBqu;0~> h#@Jk!&[Tj5QDPm!!)C!*S60!$_+:#:G#Qs8O8Ci.:pHrrE*Dao;EL!2+oCs8N+Y !;ZWqn>F_7!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Jk!&[Tj5QDPm!!)C!*S60!$_+:#:G#Qs8O8Ci.:pHrrE*Dao;EL!2+oCs8N+Y !;ZWqn>F_7!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Jk!&[Tj5QDPm!!)C!*S60!$_+:#:G#Qs8O8Ci.:pHrrE*Dao;EL!2+oCs8N+Y !;ZWqn>F_7!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'nF$!'p>["r1LKs8N'CJcGEC!e13Ci;WdBq#CIDJ(OVu![7X&JcE[g!<==crrQO-TRm.C s8N'!iVNQSVpYMG5QJQhrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'p>["r1LKs8N'CJcGEC!e13Ci;WdBq#CIDJ(OVu![7X&JcE[g!<==crrQO-TRm.C s8N'!iVNQSVpYMG5QJQhrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'p>["r1LKs8N'CJcGEC!e13Ci;WdBq#CIDJ(OVu![7X&JcE[g!<==crrQO-TRm.C s8N'!iVNQSVpYMG5QJQhrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pD]!ElW(rrE*DJcGEC!e13Ci;WdBqu?dBE7apc![7X&JcE[g!<==crrQO-TRm.C rrg[K!4(kgrrUlZl-]M45QJQhrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pD]!ElW(rrE*DJcGEC!e13Ci;WdBqu?dBE7apc![7X&JcE[g!<==crrQO-TRm.C rrg[K!4(kgrrUlZl-]M45QJQhrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pD]!ElW(rrE*DJcGEC!e13Ci;WdBqu?dBE7apc![7X&JcE[g!<==crrQO-TRm.C rrg[K!4(kgrrUlZl-]M45QJQhrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$!'pM`!a2GqqYpQr,(]derrRZMT]#hR5QCd.E6n7X![7X&JcE[g!<==crrQO-TRm.B rs/&!HiO.?RaBC\!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'nF$!'pM`!a2GqqYpQr,(]derrRZMT]#hR5QCd.E6n7X![7X&JcE[g!<==crrQO-TRm.B rs/&!HiO.?RaBC\!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'nF$!'pM`!a2GqqYpQr,(]derrRZMT]#hR5QCd.E6n7X![7X&JcE[g!<==crrQO-TRm.B rs/&!HiO.?RaBC\!^Hb#SGrXt!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!'nF$"%ZRmp\4[g!$[!op&>)C!2/9M!afomoD\k9!8rG.`;]i<,0Bid?N?aMs2=p=5QJQh rrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$"%ZRmp\4[g!$[!op&>)C!2/9M!afomoD\k9!8rG.`;]i<,0Bid?N?aMs2=p=5QJQh rrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nF$"%ZRmp\4[g!$[!op&>)C!2/9M!afomoD\k9!8rG.`;]i<,0Bid?N?aMs2=p=5QJQh rrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'mpk!<= h#@Gj!'nI%"2@*fkP"oV!$[!op&>)C!2/KrrUOI!0mKb+opPmrrQO-TRm-[s8N)CrrQO- ^\e%]~> h#@Gj!'nI%"2@*fkP"oV!$[!op&>)C!2/KrrUOI!0mKb+opPmrrQO-TRm-[s8N)CrrQO- ^\e%]~> h#@Gj!'nI%"2@*fkP"oV!$[!op&>)C!2/KrrUOI!0mKb+opPmrrQO-TRm-[s8N)CrrQO- ^\e%]~> h#@Gj!'nI%!5JL5!^N+8q>UHq,(]derrRZMT],nN^]"375aU[-rrOAEi8FV:Z2i8FrrUOIZMsk- Z:ms*klCV\$b^0Q!0#V2s7"'t!;uls!;uls!;uj$iL3F?!.;KZrrA#U!!%uWrs%tj9E7banG`Fn nAgsts2SaPZLe(tn,VG&rrE*Df)Gg7?a'/&!^Hb#dJs4Hp\t<#!4)S'"mMpY!,'"ErrA#U!!%uV !<3#s!<<'*nAgsts5BCH!4)S'&+IW.!<<)ga-m#.iL0`HZMOS)Ve6!'Vsr%4![7X&T)Sk!!2+oC _Z0W9bl7`O!5JF2J,~> h#@Gj!'nI%!5JL5!^N+8q>UHq,(]derrRZMT],nN^]"375aU[-rrOAEi8FV:Z2i8FrrUOIZMsk- Z:ms*klCV\$b^0Q!0#V2s7"'t!;uls!;uls!;uj$iL3F?!.;KZrrA#U!!%uWrs%tj9E7banG`Fn nAgsts2SaPZLe(tn,VG&rrE*Df)Gg7?a'/&!^Hb#dJs4Hp\t<#!4)S'"mMpY!,'"ErrA#U!!%uV !<3#s!<<'*nAgsts5BCH!4)S'&+IW.!<<)ga-m#.iL0`HZMOS)Ve6!'Vsr%4![7X&T)Sk!!2+oC _Z0W9bl7`O!5JF2J,~> h#@Gj!'nI%!5JL5!^N+8q>UHq,(]derrRZMT],nN^]"375aU[-rrOAEi8FV:Z2i8FrrUOIZMsk- Z:ms*klCV\$b^0Q!0#V2s7"'t!;uls!;uls!;uj$iL3F?!.;KZrrA#U!!%uWrs%tj9E7banG`Fn nAgsts2SaPZLe(tn,VG&rrE*Df)Gg7?a'/&!^Hb#dJs4Hp\t<#!4)S'"mMpY!,'"ErrA#U!!%uV !<3#s!<<'*nAgsts5BCH!4)S'&+IW.!<<)ga-m#.iL0`HZMOS)Ve6!'Vsr%4![7X&T)Sk!!2+oC _Z0W9bl7`O!5JF2J,~> h#@Gj!'nI%!5JC2!^N+8r;Qct,(]derrRZMT],nN^\\!45aU[0rrOAEi8FV:HiW[0rsS&kI/j5P ^&S,Q!!)ut%I$Qls8V$X!7:anB)hr0s8N)ss8N)trs6sOa8c2(HiUJNs8N)srtFWj^&S,c9MF.> s(>sE!4(kJB70=N!K=_HrrE*Df)Gp3!!!a@YPA,!5QJRHs8N)nrrV-ZI/a-NcqMgdiHtWQrVult rVlr`!!)ut&)dKgs8RIZ!!'^Gs8Sts^&J$CHtNEZs8RIZ!!'^Gs8Sts^&@s8n4\6!s5?ZM!7LlK +opPmrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nI%!5JC2!^N+8r;Qct,(]derrRZMT],nN^\\!45aU[0rrOAEi8FV:HiW[0rsS&kI/j5P ^&S,Q!!)ut%I$Qls8V$X!7:anB)hr0s8N)ss8N)trs6sOa8c2(HiUJNs8N)srtFWj^&S,c9MF.> s(>sE!4(kJB70=N!K=_HrrE*Df)Gp3!!!a@YPA,!5QJRHs8N)nrrV-ZI/a-NcqMgdiHtWQrVult rVlr`!!)ut&)dKgs8RIZ!!'^Gs8Sts^&J$CHtNEZs8RIZ!!'^Gs8Sts^&@s8n4\6!s5?ZM!7LlK +opPmrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nI%!5JC2!^N+8r;Qct,(]derrRZMT],nN^\\!45aU[0rrOAEi8FV:HiW[0rsS&kI/j5P ^&S,Q!!)ut%I$Qls8V$X!7:anB)hr0s8N)ss8N)trs6sOa8c2(HiUJNs8N)srtFWj^&S,c9MF.> s(>sE!4(kJB70=N!K=_HrrE*Df)Gp3!!!a@YPA,!5QJRHs8N)nrrV-ZI/a-NcqMgdiHtWQrVult rVlr`!!)ut&)dKgs8RIZ!!'^Gs8Sts^&J$CHtNEZs8RIZ!!'^Gs8Sts^&@s8n4\6!s5?ZM!7LlK +opPmrrQO-TRm-[s8N)CrrQO-^\e%]~> h#@Gj!'nI%!5J:/#!eO!$^"o!9!bT!Yo(Gqu6^_!5Hq]rrDcmrrE*!!q8n(rr3)R!!'_3s8N)ss8N)ss8N)t s8N'!l2L\an,R,!s8N)ts8N'!l2L\an,R,"rrSVhnG`FhciBujrrOAEi1BrM?N?aMs2+g9!6kHE ?N@k h#@Gj!'nI%!5J:/#!eO!$^"o!9!bT!Yo(Gqu6^_!5Hq]rrDcmrrE*!!q8n(rr3)R!!'_3s8N)ss8N)ss8N)t s8N'!l2L\an,R,!s8N)ts8N'!l2L\an,R,"rrSVhnG`FhciBujrrOAEi1BrM?N?aMs2+g9!6kHE ?N@k h#@Gj!'nI%!5J:/#!eO!$^"o!9!bT!Yo(Gqu6^_!5Hq]rrDcmrrE*!!q8n(rr3)R!!'_3s8N)ss8N)ss8N)t s8N'!l2L\an,R,!s8N)ts8N'!l2L\an,R,"rrSVhnG`FhciBujrrOAEi1BrM?N?aMs2+g9!6kHE ?N@k h#@Gj!%5ZL!&!pE"$i1Q,(]derrRZM0&]%q0(f2L5aU[6ruqI$i;`fWo`+pks8N*"VuH\sn,WIf !keTurVlr`9RQj>rrDusrrDusrrE#ts*XbErrE#trrE#t!lk<*r;Qhr!4)V(rrDThqu?aknD4*F !$^"o!9!YQ!Yo(Grr3$b!5Hq]rrDcmrrE*!!N,qqs8N'!I/a0G!;uls!;uls!<)rt!;uls!;uls !<)rt!;uls!<)rt!;uit!)1c>![7X&T)Sk!!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!%5ZL!&!pE"$i1Q,(]derrRZM0&]%q0(f2L5aU[6ruqI$i;`fWo`+pks8N*"VuH\sn,WIf !keTurVlr`9RQj>rrDusrrDusrrE#ts*XbErrE#trrE#t!lk<*r;Qhr!4)V(rrDThqu?aknD4*F !$^"o!9!YQ!Yo(Grr3$b!5Hq]rrDcmrrE*!!N,qqs8N'!I/a0G!;uls!;uls!<)rt!;uls!;uls !<)rt!;uls!<)rt!;uit!)1c>![7X&T)Sk!!2+oC_Z0W9bl7`O!5JF2J,~> h#@Gj!%5ZL!&!pE"$i1Q,(]derrRZM0&]%q0(f2L5aU[6ruqI$i;`fWo`+pks8N*"VuH\sn,WIf !keTurVlr`9RQj>rrDusrrDusrrE#ts*XbErrE#trrE#t!lk<*r;Qhr!4)V(rrDThqu?aknD4*F !$^"o!9!YQ!Yo(Grr3$b!5Hq]rrDcmrrE*!!N,qqs8N'!I/a0G!;uls!;uls!<)rt!;uls!;uls !<)rt!;uls!<)rt!;uit!)1c>![7X&T)Sk!!2+oC_Z0W9bl7`O!5JF2J,~> h#@ApYlFbJJcGEC!.W>q"^0d`+opQZs8N)ks8N*!rr\\i9YL?'!IOn@s8N)ss8N)ss8N)prrhi3 HiO0Fs8N)trrIKIqu6`V!,)<2rrDQg"n9QF!!&qQrrE*7epd[=p&G72?`u]p^X<)]!;?Hm!<<'! BD;K+s8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)ts8N)ss8N)GrrOAEi2lq[/mkgUrrQO- TRm-[s8N)CrrQO-^\e%]~> h#@ApYlFbJJcGEC!.W>q"^0d`+opQZs8N)ks8N*!rr\\i9YL?'!IOn@s8N)ss8N)ss8N)prrhi3 HiO0Fs8N)trrIKIqu6`V!,)<2rrDQg"n9QF!!&qQrrE*7epd[=p&G72?`u]p^X<)]!;?Hm!<<'! BD;K+s8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)ts8N)ss8N)GrrOAEi2lq[/mkgUrrQO- TRm-[s8N)CrrQO-^\e%]~> h#@ApYlFbJJcGEC!.W>q"^0d`+opQZs8N)ks8N*!rr\\i9YL?'!IOn@s8N)ss8N)ss8N)prrhi3 HiO0Fs8N)trrIKIqu6`V!,)<2rrDQg"n9QF!!&qQrrE*7epd[=p&G72?`u]p^X<)]!;?Hm!<<'! BD;K+s8N)ss8N)ss8N)ts8N)ss8N)ss8N)ts8N)ss8N)ts8N)ss8N)GrrOAEi2lq[/mkgUrrQO- TRm-[s8N)CrrQO-^\e%]~> g]%:]Qc$Q*CrrVZiN6qS++opQ& rrjSH!#8kEq>UM'!2+oC_Z0W9bl7`O!5JF2J,~> g]%:]Qc$Q*CrrVZiN6qS++opQ& rrjSH!#8kEq>UM'!2+oC_Z0W9bl7`O!5JF2J,~> g]%:]Qc$Q*CrrVZiN6qS++opQ& rrjSH!#8kEq>UM'!2+oC_Z0W9bl7`O!5JF2J,~> S,WK'q#CJ!Vt^2j!<= S,WK'q#CJ!Vt^2j!<= S,WK'q#CJ!Vt^2j!<= S,WK'qu?e$Vt^)g!<=$;!Usb$s8N)ss8N)ss8N)trrTJ+a8Q&>-es8Q^3a8Gr S,WK'qu?e$Vt^)g!<=$;!Usb$s8N)ss8N)ss8N)trrTJ+a8Q&>-es8Q^3a8Gr S,WK'qu?e$Vt^)g!<=$;!Usb$s8N)ss8N)ss8N)trrTJ+a8Q&>-es8Q^3a8Gr S,WZ,!!$0"p\=ah!$[!op&>)C!2/!:^!f#Oh]n s8Sts9`4nkZC:dmrrDusrrDusrrE#trrDusrrE#trrE#t!jVg(r;Qi_!7:`FrrDEc!=?D!^Hb#dJs4Hq#:DC!58C3!iH#lr;Qf2N;ikW!;uls!;uls!<)rt!;uls!;uls !<)rt!;uls!<)p!ktL'YrrO/?335C S,WZ,!!$0"p\=ah!$[!op&>)C!2/!:^!f#Oh]n s8Sts9`4nkZC:dmrrDusrrDusrrE#trrDusrrE#trrE#t!jVg(r;Qi_!7:`FrrDEc!=?D!^Hb#dJs4Hq#:DC!58C3!iH#lr;Qf2N;ikW!;uls!;uls!<)rt!;uls!;uls !<)rt!;uls!<)p!ktL'YrrO/?335C S,WZ,!!$0"p\=ah!$[!op&>)C!2/!:^!f#Oh]n s8Sts9`4nkZC:dmrrDusrrDusrrE#trrDusrrE#trrE#t!jVg(r;Qi_!7:`FrrDEc!=?D!^Hb#dJs4Hq#:DC!58C3!iH#lr;Qf2N;ikW!;uls!;uls!<)rt!;uls!;uls !<)rt!;uls!<)p!ktL'YrrO/?335C S,WQJVt]la!<= S,WQJVt]la!<= S,WQJVt]la!<= N;inY,(]derrRZMT[3W>+opQWrr]q7Vr@XT"50SGd/)ds8U,5l2L\b`rH+up&>;F9W..T s1NgEh#@BT,1cbqk@_R&rrPFc^XE,bf`2$2nG`Fjfr"gD^&.g0d/*eCVu?W2HiW-YN;rpk!2oks ]uL*QB70a+!!(^Orr_`j!7:`F$.&YPd/X-m!!(^Orr_`j!7:`F!)31g!2n6E![7WBXM4`MpAbA" VtXNuTRm-[s8N)CrrQO-^\e%]~> N;inY,(]derrRZMT[3W>+opQWrr]q7Vr@XT"50SGd/)ds8U,5l2L\b`rH+up&>;F9W..T s1NgEh#@BT,1cbqk@_R&rrPFc^XE,bf`2$2nG`Fjfr"gD^&.g0d/*eCVu?W2HiW-YN;rpk!2oks ]uL*QB70a+!!(^Orr_`j!7:`F$.&YPd/X-m!!(^Orr_`j!7:`F!)31g!2n6E![7WBXM4`MpAbA" VtXNuTRm-[s8N)CrrQO-^\e%]~> N;inY,(]derrRZMT[3W>+opQWrr]q7Vr@XT"50SGd/)ds8U,5l2L\b`rH+up&>;F9W..T s1NgEh#@BT,1cbqk@_R&rrPFc^XE,bf`2$2nG`Fjfr"gD^&.g0d/*eCVu?W2HiW-YN;rpk!2oks ]uL*QB70a+!!(^Orr_`j!7:`F$.&YPd/X-m!!(^Orr_`j!7:`F!)31g!2n6E![7WBXM4`MpAbA" VtXNuTRm-[s8N)CrrQO-^\e%]~> N;inY,(]derrRZMT[3W>+opQVrrV\qN;`eXN5tep"p!o$B)m>4r;QrZRK*>8d/O(B!!*&r!!*&r !<3!/VZ6^Ed/TO7N9UBBl":!orVm)dRS3]oVss]cqZ-?i#/+XL!)/j.gA_0R,00]b5QJRJs7cQq B8jn+rrqAM!!%D[r;Ql`B)nk.rs>u)!1N0P!1LstqZ-Zrqu?`so`5$lquHcs!ROO9!!&qFrrOAE i2lqY,5M9@=f;#nrrQO-TRm-[s8N)CrrQO-^\e%]~> N;inY,(]derrRZMT[3W>+opQVrrV\qN;`eXN5tep"p!o$B)m>4r;QrZRK*>8d/O(B!!*&r!!*&r !<3!/VZ6^Ed/TO7N9UBBl":!orVm)dRS3]oVss]cqZ-?i#/+XL!)/j.gA_0R,00]b5QJRJs7cQq B8jn+rrqAM!!%D[r;Ql`B)nk.rs>u)!1N0P!1LstqZ-Zrqu?`so`5$lquHcs!ROO9!!&qFrrOAE i2lqY,5M9@=f;#nrrQO-TRm-[s8N)CrrQO-^\e%]~> N;inY,(]derrRZMT[3W>+opQVrrV\qN;`eXN5tep"p!o$B)m>4r;QrZRK*>8d/O(B!!*&r!!*&r !<3!/VZ6^Ed/TO7N9UBBl":!orVm)dRS3]oVss]cqZ-?i#/+XL!)/j.gA_0R,00]b5QJRJs7cQq B8jn+rrqAM!!%D[r;Ql`B)nk.rs>u)!1N0P!1LstqZ-Zrqu?`so`5$lquHcs!ROO9!!&qFrrOAE i2lqY,5M9@=f;#nrrQO-TRm-[s8N)CrrQO-^\e%]~> N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=pUEpdf0@m!8ssY" N;inY,(]derrRZMT[3W>+opPPs2=pUEpdf0@m!8ssY" N;inY,(]derrRZMT[3W>+opPPs2=pUEpdf0@m!8ssY" N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+opPPs2=p N;inY,(]derrRZMT[3W>+olS5J&Hg;!$]J`!^H`mJUbUf!Yk^nT)SeGJO$q7bl7`O!5JF2J,~> N;inY,(]derrRZMT[3W>+olS5J&Hg;!$]J`!^H`mJUbUf!Yk^nT)SeGJO$q7bl7`O!5JF2J,~> N;inY,(]derrRZMT[3W>+olS5J&Hg;!$]J`!^H`mJUbUf!Yk^nT)SeGJO$q7bl7`O!5JF2J,~> N;inY,(]derrRZMT[3W<,(Ta1!!"4`rr><8!5JR7i.:oZs/#_s?N@k N;inY,(]derrRZMT[3W<,(Ta1!!"4`rr><8!5JR7i.:oZs/#_s?N@k N;inY,(]derrRZMT[3W<,(Ta1!!"4`rr><8!5JR7i.:oZs/#_s?N@k N;inY,(]derrRZMT[3W N;inY,(]derrRZMT[3W N;inY,(]derrRZMT[3W N;nG/nGiQ^JcC<$JcC<$JcC<$[/U27!5JF2J,~> N;nG/nGiQ^JcC<$JcC<$JcC<$[/U27!5JF2J,~> N;nG/nGiQ^JcC<$JcC<$JcC<$[/U27!5JF2J,~> N;nG/nGiQ^JcC<$JcC<$JcC<$[/U27!5JF2J,~> N;nG/nGiQ^JcC<$JcC<$JcC<$[/U27!5JF2J,~> N;nG/nGiQ^JcC<$JcC<$JcC<$[/U27!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> JcC<$JcC<$JcC<$JcC<$Y5\Q1!5JF2J,~> g]%?D:j7J?JU`6#JU`6#JU`6#JUc:$!\OJfqu;0~> g]%?D:j7J?JU`6#JU`6#JU`6#JUc:$!\OJfqu;0~> g]%?D:j7J?JU`6#JU`6#JU`6#JUc:$!\OJfqu;0~> g]%8%JH16$JH16$JH16$JH16$df9BBqu;0~> g]%8%JH16$JH16$JH16$JH16$df9BBqu;0~> g]%8%JH16$JH16$JH16$JH16$df9BBqu;0~> g]%>D!'l*bJU`6#JU`6#JU`6#JUc:$!I&_`s*t~> g]%>D!'l*bJU`6#JU`6#JU`6#JUc:$!I&_`s*t~> g]%>D!'l*bJU`6#JU`6#JU`6#JUc:$!I&_`s*t~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.TS"JcC<$JcC<$JcC<$JcF$qJ,~> g]%>J!.VEV!2+lCb5_NlMuNd g]%>J!.VEV!2+lCb5_NlMuNd g]%>J!.VEV!2+lCb5_NlMuNd g]%>J!.VEV!2+lCb5_NlMuNc$JH3jnJcC<$JcC<$s8RT~> g]%>J!.VEV!2+lCb5_NlMuNc$JH3jnJcC<$JcC<$s8RT~> g]%>J!.VEV!2+lCb5_NlMuNc$JH3jnJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!-!L=c[YrpJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!-!L=c[YrpJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!-!L=c[YrpJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#JcF'r!e13"MuNi&!8rG.ci="FJcC<$JcC<$s8RT~> g]%>J!.VEV!h]O#fDkXH!b[J=K`;+'!.Tq,![7X&XT&Cla-m#+s8RK,rr_c2RK1b8rr@WMJcC<$ JcGcMJ,~> g]%>J!.VEV!h]O#fDkXH!b[J=K`;+'!.Tq,![7X&XT&Cla-m#+s8RK,rr_c2RK1b8rr@WMJcC<$ JcGcMJ,~> g]%>J!.VEV!h]O#fDkXH!b[J=K`;+'!.Tq,![7X&XT&Cla-m#+s8RK,rr_c2RK1b8rr@WMJcC<$ JcGcMJ,~> g]%>J!.VEV!h]O#f)Gg)!!)ut"5/V5N3`Han,V&>!e13"MuNi&!8uQ1!N1n-rr\3m!!)rss*Wl, "+4_]!7CiH!.k0$s+13$s8W+L~> g]%>J!.VEV!h]O#f)Gg)!!)ut"5/V5N3`Han,V&>!e13"MuNi&!8uQ1!N1n-rr\3m!!)rss*Wl, "+4_]!7CiH!.k0$s+13$s8W+L~> g]%>J!.VEV!h]O#f)Gg)!!)ut"5/V5N3`Han,V&>!e13"MuNi&!8uQ1!N1n-rr\3m!!)rss*Wl, "+4_]!7CiH!.k0$s+13$s8W+L~> g]%>J!.VEV!h]O#ec5XLqu6_d!55`=!RLhtrrRZMIuF=.+opQSs8N'!nC@R=!;6?mn,V\PrrCIH rr@WMJcC<$JcGcMJ,~> g]%>J!.VEV!h]O#ec5XLqu6_d!55`=!RLhtrrRZMIuF=.+opQSs8N'!nC@R=!;6?mn,V\PrrCIH rr@WMJcC<$JcGcMJ,~> g]%>J!.VEV!h]O#ec5XLqu6_d!55`=!RLhtrrRZMIuF=.+opQSs8N'!nC@R=!;6?mn,V\PrrCIH rr@WMJcC<$JcGcMJ,~> g]%>J!.VEV!h]O#ec5XLqu6`e!)0a!!La#>rrRZMIuF=.+opQTrr^:A!4(/TrrD`l!RLi1s8N)H s8N(Ms+13$s+14Ms*t~> g]%>J!.VEV!h]O#ec5XLqu6`e!)0a!!La#>rrRZMIuF=.+opQTrr^:A!4(/TrrD`l!RLi1s8N)H s8N(Ms+13$s+14Ms*t~> g]%>J!.VEV!h]O#ec5XLqu6`e!)0a!!La#>rrRZMIuF=.+opQTrr^:A!4(/TrrD`l!RLi1s8N)H s8N(Ms+13$s+14Ms*t~> g]%>J!.VEV!h]O#ec5XLqZ$Qq[/U3S!!(UM!e13"MuNi&!8uT2")$Qm9\'1C!;6?mRK2ROrrCIH rr@WMJcC<$JcGcMJ,~> g]%>J!.VEV!h]O#ec5XLqZ$Qq[/U3S!!(UM!e13"MuNi&!8uT2")$Qm9\'1C!;6?mRK2ROrrCIH rr@WMJcC<$JcGcMJ,~> g]%>J!.VEV!h]O#ec5XLqZ$Qq[/U3S!!(UM!e13"MuNi&!8uT2")$Qm9\'1C!;6?mRK2ROrrCIH rr@WMJcC<$JcGcMJ,~> g]%>J!.VEV!h]O#ec5XLqu6`V!,)3/"mMpY!,'"Crro]%9YKZjr;QujVb@(aVss]c$1Q!(!<;#H !!'>&rs%GN9E5'?^&J$ g]%>J!.VEV!h]O#ec5XLqu6`V!,)3/"mMpY!,'"Crro]%9YKZjr;QujVb@(aVss]c$1Q!(!<;#H !!'>&rs%GN9E5'?^&J$ g]%>J!.VEV!h]O#ec5XLqu6`V!,)3/"mMpY!,'"Crro]%9YKZjr;QujVb@(aVss]c$1Q!(!<;#H !!'>&rs%GN9E5'?^&J$ g]%>J!.VEV!h]O#ec5XLqu6_F!87;M#LH/ks5A>*I/a-MZG$;<`rH,s*SGZ !56)Gs/,k1rr3_[!6>->l$NK:s8RIZ!!'^Gs8Sts^&A!2!7q/OIfOtVrrOAEi7n88VpPIj!0$dS &Fd`/!<;;P!!&Jfs5BCH9X=Zt$1Q!(!<:Dn!)1*'s8N)urr_c2RK3?e!0$gU!0$jVrr;osqu6ku 9E:%9!!)rs"mMpY!,'"#s8N(Ms+13$s+14Ms*t~> g]%>J!.VEV!h]O#ec5XLqu6_F!87;M#LH/ks5A>*I/a-MZG$;<`rH,s*SGZ !56)Gs/,k1rr3_[!6>->l$NK:s8RIZ!!'^Gs8Sts^&A!2!7q/OIfOtVrrOAEi7n88VpPIj!0$dS &Fd`/!<;;P!!&Jfs5BCH9X=Zt$1Q!(!<:Dn!)1*'s8N)urr_c2RK3?e!0$gU!0$jVrr;osqu6ku 9E:%9!!)rs"mMpY!,'"#s8N(Ms+13$s+14Ms*t~> g]%>J!.VEV!h]O#ec5XLqu6_F!87;M#LH/ks5A>*I/a-MZG$;<`rH,s*SGZ !56)Gs/,k1rr3_[!6>->l$NK:s8RIZ!!'^Gs8Sts^&A!2!7q/OIfOtVrrOAEi7n88VpPIj!0$dS &Fd`/!<;;P!!&Jfs5BCH9X=Zt$1Q!(!<:Dn!)1*'s8N)urr_c2RK3?e!0$gU!0$jVrr;osqu6ku 9E:%9!!)rs"mMpY!,'"#s8N(Ms+13$s+14Ms*t~> g]%>J!.VEV!h]O#ec5XLrr3,[Z:ms=r;Qif9ZR/4#2&tV^&S++rVlo(!<)ouB>+9D"6feZnG`If !!)9_rrVZiBE%o39E>%k!q61`rVult!9sL_!q62&rVultf)Gf$!.Tq,![7X&g]%7drr3$n!:]mc *dhT#!85'cs-`qH]tOIGVZ=F1s*SGZ!4'uOn g]%>J!.VEV!h]O#ec5XLrr3,[Z:ms=r;Qif9ZR/4#2&tV^&S++rVlo(!<)ouB>+9D"6feZnG`If !!)9_rrVZiBE%o39E>%k!q61`rVult!9sL_!q62&rVultf)Gf$!.Tq,![7X&g]%7drr3$n!:]mc *dhT#!85'cs-`qH]tOIGVZ=F1s*SGZ!4'uOn g]%>J!.VEV!h]O#ec5XLrr3,[Z:ms=r;Qif9ZR/4#2&tV^&S++rVlo(!<)ouB>+9D"6feZnG`If !!)9_rrVZiBE%o39E>%k!q61`rVult!9sL_!q62&rVultf)Gf$!.Tq,![7X&g]%7drr3$n!:]mc *dhT#!85'cs-`qH]tOIGVZ=F1s*SGZ!4'uOn g]%>J!.VEV!h]O#ec5LH!dr&Xqu6\p!;uls!!I]LrrAtrrrMThrr3&?!9sF]!iH%(rr;uur;Zcs rr<"Gr;ZcsrVultr;ZcsrVultf)Gf$!.Tq,![7X&h#@E%ZMsk*Z2h3+s8N'!l2L\bn,NIQrr3&h !,)91rr<&`rVlq3!7:]ErrDusrrDusrrDusrrDusrrE#ts*XeF!lk9@rr3&h9ZR/4"5*YS^#&eh !1 g]%>J!.VEV!h]O#ec5LH!dr&Xqu6\p!;uls!!I]LrrAtrrrMThrr3&?!9sF]!iH%(rr;uur;Zcs rr<"Gr;ZcsrVultr;ZcsrVultf)Gf$!.Tq,![7X&h#@E%ZMsk*Z2h3+s8N'!l2L\bn,NIQrr3&h !,)91rr<&`rVlq3!7:]ErrDusrrDusrrDusrrDusrrE#ts*XeF!lk9@rr3&h9ZR/4"5*YS^#&eh !1 g]%>J!.VEV!h]O#ec5LH!dr&Xqu6\p!;uls!!I]LrrAtrrrMThrr3&?!9sF]!iH%(rr;uur;Zcs rr<"Gr;ZcsrVultr;ZcsrVultf)Gf$!.Tq,![7X&h#@E%ZMsk*Z2h3+s8N'!l2L\bn,NIQrr3&h !,)91rr<&`rVlq3!7:]ErrDusrrDusrrDusrrDusrrE#ts*XeF!lk9@rr3&h9ZR/4"5*YS^#&eh !1 g]%>J!.VEV!h]O#ec5XLs8N/R!0$aR!,)',s8N1i!)1*'rrIKIqu6`V!,)<2rrDusrrDoq"RsHZ !!)utrrDusrrE#trrCXM!e13"RK!9=o`"t:!8uZ4!IXD9rrVZi9_n_g!;uls!;uls!<)rt!;uiu ciBO5s8N)ss8N)ss8N)ss8N)ss8N)urrUOIg&:pPn,NIfrrK"tr;Zcs!. g]%>J!.VEV!h]O#ec5XLs8N/R!0$aR!,)',s8N1i!)1*'rrIKIqu6`V!,)<2rrDusrrDoq"RsHZ !!)utrrDusrrE#trrCXM!e13"RK!9=o`"t:!8uZ4!IXD9rrVZi9_n_g!;uls!;uls!<)rt!;uiu ciBO5s8N)ss8N)ss8N)ss8N)ss8N)urrUOIg&:pPn,NIfrrK"tr;Zcs!. g]%>J!.VEV!h]O#ec5XLs8N/R!0$aR!,)',s8N1i!)1*'rrIKIqu6`V!,)<2rrDusrrDoq"RsHZ !!)utrrDusrrE#trrCXM!e13"RK!9=o`"t:!8uZ4!IXD9rrVZi9_n_g!;uls!;uls!<)rt!;uiu ciBO5s8N)ss8N)ss8N)ss8N)ss8N)urrUOIg&:pPn,NIfrrK"tr;Zcs!. g]%>J!.VEV!h]O#ec5XLrr3%t!587/rrDcm"I];j9W.jhrrDoqrrE&urrDusrrDus#2u"EZKV>h rVultr;ZcsrVultf)Gf$!.UF:"$dT6^\@a0+opQWrrMA3r;QhG!7:TBrrDusrrDusrrE#trrDus !q60irVultr;Zcsr;Zcsr;Zcsr;Zcsrr3"f!;lfr!<2uuBD;J`s8N(drr@QI!!4Ntf@U$1fh;C) g&M**MuZQ)l2La2h#@A%JcC<$jo9i~> g]%>J!.VEV!h]O#ec5XLrr3%t!587/rrDcm"I];j9W.jhrrDoqrrE&urrDusrrDus#2u"EZKV>h rVultr;ZcsrVultf)Gf$!.UF:"$dT6^\@a0+opQWrrMA3r;QhG!7:TBrrDusrrDusrrE#trrDus !q60irVultr;Zcsr;Zcsr;Zcsr;Zcsrr3"f!;lfr!<2uuBD;J`s8N(drr@QI!!4Ntf@U$1fh;C) g&M**MuZQ)l2La2h#@A%JcC<$jo9i~> g]%>J!.VEV!h]O#ec5XLrr3%t!587/rrDcm"I];j9W.jhrrDoqrrE&urrDusrrDus#2u"EZKV>h rVultr;ZcsrVultf)Gf$!.UF:"$dT6^\@a0+opQWrrMA3r;QhG!7:TBrrDusrrDusrrE#trrDus !q60irVultr;Zcsr;Zcsr;Zcsr;Zcsrr3"f!;lfr!<2uuBD;J`s8N(drr@QI!!4Ntf@U$1fh;C) g&M**MuZQ)l2La2h#@A%JcC<$jo9i~> g]%>J!.Vod"$f\Un+Zh`TE&?Ls8N)trrQg5iVWZT!!)N^rs@Y^!!#^Ws8N'!qZ$Qqrr;uur;Zcs rVlr)!58C3rrE#trrDusrrE#trrCXM!e13"RK!7PrW!!7B>=[JQq#CD`qZ$Qqr;Zcs r;ZcsrVultqu?ZrrVultr;Zcsr;Zcsr;Zcsr;Zcsrr;uuqu?Zrrr;uuf)PaMR/[/9q>^REO5Sdm "4.#JVu-JrRK*?7li.!E!8[YUMu\G/JcFj3J,~> g]%>J!.Vod"$f\Un+Zh`TE&?Ls8N)trrQg5iVWZT!!)N^rs@Y^!!#^Ws8N'!qZ$Qqrr;uur;Zcs rVlr)!58C3rrE#trrDusrrE#trrCXM!e13"RK!7PrW!!7B>=[JQq#CD`qZ$Qqr;Zcs r;ZcsrVultqu?ZrrVultr;Zcsr;Zcsr;Zcsr;Zcsrr;uuqu?Zrrr;uuf)PaMR/[/9q>^REO5Sdm "4.#JVu-JrRK*?7li.!E!8[YUMu\G/JcFj3J,~> g]%>J!.Vod"$f\Un+Zh`TE&?Ls8N)trrQg5iVWZT!!)N^rs@Y^!!#^Ws8N'!qZ$Qqrr;uur;Zcs rVlr)!58C3rrE#trrDusrrE#trrCXM!e13"RK!7PrW!!7B>=[JQq#CD`qZ$Qqr;Zcs r;ZcsrVultqu?ZrrVultr;Zcsr;Zcsr;Zcsr;Zcsrr;uuqu?Zrrr;uuf)PaMR/[/9q>^REO5Sdm "4.#JVu-JrRK*?7li.!E!8[YUMu\G/JcFj3J,~> g]%>J!.Vod!'pM`!`5QYqYpVi!+4:VrrE#t!oX,lqu6_1!6>$;!Usb!rs7k:!0$sXB)pW^rrE+Y rr;uur;Zcsrr3&*!6>'=EF![7X&h>[IfqYpUj !:]mcrrDusrrDusrrE#trrDrrrrE#trrDusrrDusrrDusrrDusrrE&urrDrrrrE&urr<&gfDkjN R(iW.pAb7IO5Spq"5*YS9_n\j9E5(GmJd68!!(mU!djtJJcC<$jo9i~> g]%>J!.Vod!'pM`!`5QYqYpVi!+4:VrrE#t!oX,lqu6_1!6>$;!Usb!rs7k:!0$sXB)pW^rrE+Y rr;uur;Zcsrr3&*!6>'=EF![7X&h>[IfqYpUj !:]mcrrDusrrDusrrE#trrDrrrrE#trrDusrrDusrrDusrrDusrrE&urrDrrrrE&urr<&gfDkjN R(iW.pAb7IO5Spq"5*YS9_n\j9E5(GmJd68!!(mU!djtJJcC<$jo9i~> g]%>J!.Vod!'pM`!`5QYqYpVi!+4:VrrE#t!oX,lqu6_1!6>$;!Usb!rs7k:!0$sXB)pW^rrE+Y rr;uur;Zcsrr3&*!6>'=EF![7X&h>[IfqYpUj !:]mcrrDusrrDusrrE#trrDrrrrE#trrDusrrDusrrDusrrDusrrE&urrDrrrrE&urr<&gfDkjN R(iW.pAb7IO5Spq"5*YS9_n\j9E5(GmJd68!!(mU!djtJJcC<$jo9i~> g]%>J!.Vod!'pD]!`5QYrVlql!+4:VrrDus!keT&r;Qhr!)3=j"hflprrDQfrs/#n!<<))!2obp !pK^3rr;uur;Zcsrr;uur;ZcsrVultr;ZcsrVultf)Gf$!.UF:!'p;Z"r1dcruqI$hZ!W'Vu$Dp VZ=F-s8N)ss8N)ss8N)ts8N)rrrE+YrVultr;Zcsr;Zcsr;Zcsr;Zcsrr3$n!9sF]rrE&u!bVMR r;QfeBA`^hpP8eN/s#bdrrYpp!4)G#"0qn,9^hu^iFi,ii;Wi:BDqm^s+143s*t~> g]%>J!.Vod!'pD]!`5QYrVlql!+4:VrrDus!keT&r;Qhr!)3=j"hflprrDQfrs/#n!<<))!2obp !pK^3rr;uur;Zcsrr;uur;ZcsrVultr;ZcsrVultf)Gf$!.UF:!'p;Z"r1dcruqI$hZ!W'Vu$Dp VZ=F-s8N)ss8N)ss8N)ts8N)rrrE+YrVultr;Zcsr;Zcsr;Zcsr;Zcsrr3$n!9sF]rrE&u!bVMR r;QfeBA`^hpP8eN/s#bdrrYpp!4)G#"0qn,9^hu^iFi,ii;Wi:BDqm^s+143s*t~> g]%>J!.Vod!'pD]!`5QYrVlql!+4:VrrDus!keT&r;Qhr!)3=j"hflprrDQfrs/#n!<<))!2obp !pK^3rr;uur;Zcsrr;uur;ZcsrVultr;ZcsrVultf)Gf$!.UF:!'p;Z"r1dcruqI$hZ!W'Vu$Dp VZ=F-s8N)ss8N)ss8N)ts8N)rrrE+YrVultr;Zcsr;Zcsr;Zcsr;Zcsrr3$n!9sF]rrE&u!bVMR r;QfeBA`^hpP8eN/s#bdrrYpp!4)G#"0qn,9^hu^iFi,ii;Wi:BDqm^s+143s*t~> g]%>J!.Vod!'p;Z##Lu]s.B@!ec5XLqu6_F!2oeq%I!imBA*=bcqMgdrrBA'rrE+4rr3$n!9*nV !PN.Es8N)ss8N)us8N'!nGWCe!<)rt!;uls!<)rt!8%5Ok7rjS!u1e9i84J7I-LM-!pK\tqu?Zr r;Zcsr;ZcsrVultr;QiO!6>' g]%>J!.Vod!'p;Z##Lu]s.B@!ec5XLqu6_F!2oeq%I!imBA*=bcqMgdrrBA'rrE+4rr3$n!9*nV !PN.Es8N)ss8N)us8N'!nGWCe!<)rt!;uls!<)rt!8%5Ok7rjS!u1e9i84J7I-LM-!pK\tqu?Zr r;Zcsr;ZcsrVultr;QiO!6>' g]%>J!.Vod!'p;Z##Lu]s.B@!ec5XLqu6_F!2oeq%I!imBA*=bcqMgdrrBA'rrE+4rr3$n!9*nV !PN.Es8N)ss8N)us8N'!nGWCe!<)rt!;uls!<)rt!8%5Ok7rjS!u1e9i84J7I-LM-!pK\tqu?Zr r;Zcsr;ZcsrVultr;QiO!6>' g]%>J!$]/,"&NJ-?e55Zf`2$*r;Qoa!!%E"rr2uFqZ$Vorr;uu"g\1.VZ>*Crs7:O9[Nh> a%Yasrr^UJ!87AO(%;2'd/X-D!.=;9d$aq7n?W)@!!(^Orr_`j!7:`F"FL4.fo4Yb!Tt2T!!=DF !8uc7!SNG,rrRQJa8Gu;!;uls!;uls!<)rt!!(^NrrJ'Pr;Zcsr;Zcsr;Zcsr;QhG!:^!f!oX+Z rr3&Y!)3@k!pK[brr3;h!!$Zbs8UG>d,+g&!1 g]%>J!$]/,"&NJ-?e55Zf`2$*r;Qoa!!%E"rr2uFqZ$Vorr;uu"g\1.VZ>*Crs7:O9[Nh> a%Yasrr^UJ!87AO(%;2'd/X-D!.=;9d$aq7n?W)@!!(^Orr_`j!7:`F"FL4.fo4Yb!Tt2T!!=DF !8uc7!SNG,rrRQJa8Gu;!;uls!;uls!<)rt!!(^NrrJ'Pr;Zcsr;Zcsr;Zcsr;QhG!:^!f!oX+Z rr3&Y!)3@k!pK[brr3;h!!$Zbs8UG>d,+g&!1 g]%>J!$]/,"&NJ-?e55Zf`2$*r;Qoa!!%E"rr2uFqZ$Vorr;uu"g\1.VZ>*Crs7:O9[Nh> a%Yasrr^UJ!87AO(%;2'd/X-D!.=;9d$aq7n?W)@!!(^Orr_`j!7:`F"FL4.fo4Yb!Tt2T!!=DF !8uc7!SNG,rrRQJa8Gu;!;uls!;uls!<)rt!!(^NrrJ'Pr;Zcsr;Zcsr;Zcsr;QhG!:^!f!oX+Z rr3&Y!)3@k!pK[brr3;h!!$Zbs8UG>d,+g&!1 g]%8_ZN(%_!+4@XqZ-Qo!6>$<#iYg`iL0`HI(fLY"p!o$B)m>4r;QucRS3]oVss]cqZ-ZrquHcs $)[b'I*hn^!0$1>!<<)s!<<'$l":!of`)#&!.UF:!'p;Z"sS$4ruqI$i;Wo49UbJHrr\2[!7:`F "4.#Jg&D!Rkl:_:rr3)b!!(CFs8N''BA*=bVbH@Rrr^UJ!7:`F"4.#Jd/EtfHiW-YN;rpk!2oks ]uL*QB70aZVZ:Ags5BjU!,#sEs3UWC!2nZQrrAGd!.XkG!^N+8h#@@JrW)]mr;cisr;cisr;cfr r;ccqr;Zogs4RAO!87AOr;cisr;cfrr;_EKJcFj3J,~> g]%8_ZN(%_!+4@XqZ-Qo!6>$<#iYg`iL0`HI(fLY"p!o$B)m>4r;QucRS3]oVss]cqZ-ZrquHcs $)[b'I*hn^!0$1>!<<)s!<<'$l":!of`)#&!.UF:!'p;Z"sS$4ruqI$i;Wo49UbJHrr\2[!7:`F "4.#Jg&D!Rkl:_:rr3)b!!(CFs8N''BA*=bVbH@Rrr^UJ!7:`F"4.#Jd/EtfHiW-YN;rpk!2oks ]uL*QB70aZVZ:Ags5BjU!,#sEs3UWC!2nZQrrAGd!.XkG!^N+8h#@@JrW)]mr;cisr;cisr;cfr r;ccqr;Zogs4RAO!87AOr;cisr;cfrr;_EKJcFj3J,~> g]%8_ZN(%_!+4@XqZ-Qo!6>$<#iYg`iL0`HI(fLY"p!o$B)m>4r;QucRS3]oVss]cqZ-ZrquHcs $)[b'I*hn^!0$1>!<<)s!<<'$l":!of`)#&!.UF:!'p;Z"sS$4ruqI$i;Wo49UbJHrr\2[!7:`F "4.#Jg&D!Rkl:_:rr3)b!!(CFs8N''BA*=bVbH@Rrr^UJ!7:`F"4.#Jd/EtfHiW-YN;rpk!2oks ]uL*QB70aZVZ:Ags5BjU!,#sEs3UWC!2nZQrrAGd!.XkG!^N+8h#@@JrW)]mr;cisr;cisr;cfr r;ccqr;Zogs4RAO!87AOr;cisr;cfrr;_EKJcFj3J,~> g]%?LVolol!&"!G"]1l\TE&>Ms3L]HIfOtdrr>=]!!4?`ci*kF+opQ[rrA#V!!'_1rrD$T!!*&r !<<)s!<<)s!<<*!!!VV7!!&JPrVu`p!<;orrr3)bB)nk.rs>u)!1N0P!1Lstrr3;OHiQj8rrAGd!.XtJ!^N+8g&M!Np](0lrr;osrr;osrVufrr;Z]qs8N)grVuqerr;os rr;osrVufrJcC<$jo9i~> g]%?LVolol!&"!G"]1l\TE&>Ms3L]HIfOtdrr>=]!!4?`ci*kF+opQ[rrA#V!!'_1rrD$T!!*&r !<<)s!<<)s!<<*!!!VV7!!&JPrVu`p!<;orrr3)bB)nk.rs>u)!1N0P!1Lstrr3;OHiQj8rrAGd!.XtJ!^N+8g&M!Np](0lrr;osrr;osrVufrr;Z]qs8N)grVuqerr;os rr;osrVufrJcC<$jo9i~> g]%?LVolol!&"!G"]1l\TE&>Ms3L]HIfOtdrr>=]!!4?`ci*kF+opQ[rrA#V!!'_1rrD$T!!*&r !<<)s!<<)s!<<*!!!VV7!!&JPrVu`p!<;orrr3)bB)nk.rs>u)!1N0P!1Lstrr3;OHiQj8rrAGd!.XtJ!^N+8g&M!Np](0lrr;osrr;osrVufrr;Z]qs8N)grVuqerr;os rr;osrVufrJcC<$jo9i~> Rf<@Qq>^RnT^Vm[!h]O#JcF'r!e13"RK!7PrW!!DE6nC\![7X&\GuR/RfEBfR/[8<5aUZbs8;rl s8;rss8;rss8;rrs8;rqs8;rss8DuuBE%r0!<3#s!<)rr!.k0$s5j92~> Rf<@Qq>^RnT^Vm[!h]O#JcF'r!e13"RK!7PrW!!DE6nC\![7X&\GuR/RfEBfR/[8<5aUZbs8;rl s8;rss8;rss8;rrs8;rqs8;rss8DuuBE%r0!<3#s!<)rr!.k0$s5j92~> Rf<@Qq>^RnT^Vm[!h]O#JcF'r!e13"RK!7PrW!!DE6nC\![7X&\GuR/RfEBfR/[8<5aUZbs8;rl s8;rss8;rss8;rrs8;rqs8;rss8DuuBE%r0!<3#s!<)rr!.k0$s5j92~> Rf<@Qr;ZmqT^VdX!h]O#JcF'r!e13"RK!@S,&km&rrOAEi4/ge!1Nrf!.k17rrA#W!!)NarrD<_ !!%uWs8;rss8;rrs8;rqs8;rss8;rss8;rss8;rrs8;qKs+143s*t~> Rf<@Qr;ZmqT^VdX!h]O#JcF'r!e13"RK!@S,&km&rrOAEi4/ge!1Nrf!.k17rrA#W!!)NarrD<_ !!%uWs8;rss8;rrs8;rqs8;rss8;rss8;rss8;rrs8;qKs+143s*t~> Rf<@Qr;ZmqT^VdX!h]O#JcF'r!e13"RK!@S,&km&rrOAEi4/ge!1Nrf!.k17rrA#W!!)NarrD<_ !!%uWs8;rss8;rrs8;rqs8;rss8;rss8;rss8;rrs8;qKs+143s*t~> Rf'=!9*bR!87>O!6>*= r;cisr;cfrr;ccqr;cisr;cisr;cisr;cfrr;_EKJcFj3J,~> Rf'=!9*bR!87>O!6>*= r;cisr;cfrr;ccqr;cisr;cisr;cisr;cfrr;_EKJcFj3J,~> Rf'=!9*bR!87>O!6>*= r;cisr;cfrr;ccqr;cisr;cisr;cisr;cfrr;_EKJcFj3J,~> RfMs3L]HIfOtVrrOAEi4/ge!1Nrf!.k16rrYpp!4)G#"0qn,9`>"i!<3#s!<)rr !;ulq!<3#t!!$[2s8;rss8;rrs8;qKs+143s*t~> RfMs3L]HIfOtVrrOAEi4/ge!1Nrf!.k16rrYpp!4)G#"0qn,9`>"i!<3#s!<)rr !;ulq!<3#t!!$[2s8;rss8;rrs8;qKs+143s*t~> RfMs3L]HIfOtVrrOAEi4/ge!1Nrf!.k16rrYpp!4)G#"0qn,9`>"i!<3#s!<)rr !;ulq!<3#t!!$[2s8;rss8;rrs8;qKs+143s*t~> N;isP!+1UOj!!(CEs8;rss8;rrs8;rq s8;rss8DuuRf N;isP!+1UOj!!(CEs8;rss8;rrs8;rq s8;rss8DuuRf N;isP!+1UOj!!(CEs8;rss8;rrs8;rq s8;rss8DuuRf N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1P!)1c:rrBb1!!%EF!!)9_rrBA& !!:jRs8;p$ZN$?n!0$mV!58:1!.=_F!9sL_!4)M&!82r'JcFs6J,~> N;isP!+1P!)1c:rrBb1!!%EF!!)9_rrBA& !!:jRs8;p$ZN$?n!0$mV!58:1!.=_F!9sL_!4)M&!82r'JcFs6J,~> N;isP!+1P!)1c:rrBb1!!%EF!!)9_rrBA& !!:jRs8;p$ZN$?n!0$mV!58:1!.=_F!9sL_!4)M&!82r'JcFs6J,~> N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+3)4s*XhG"7X@"!2fbtIfOtVrrOAEi.:pSs8N(Ms1JC1!.k0$s2b4j~> N;isP!+3)4s*XhG"7X@"!2fbtIfOtVrrOAEi.:pSs8N(Ms1JC1!.k0$s2b4j~> N;isP!+3)4s*XhG"7X@"!2fbtIfOtVrrOAEi.:pSs8N(Ms1JC1!.k0$s2b4j~> N;isP!+3YDoDnmjs*XhG",pjm!2fbtIfOtVrrOAEi2$ATnAgstYlF_'JcEC_r;_EKJcEgkJ,~> N;isP!+3YDoDnmjs*XhG",pjm!2fbtIfOtVrrOAEi2$ATnAgstYlF_'JcEC_r;_EKJcEgkJ,~> N;isP!+3YDoDnmjs*XhG",pjm!2fbtIfOtVrrOAEi2$ATnAgstYlF_'JcEC_r;_EKJcEgkJ,~> N;isP!+3VC!ndPRqu6`E9E=herrDus!Up)krrRZMIuF=.+opQSs7? N;isP!+3VC!ndPRqu6`E9E=herrDus!Up)krrRZMIuF=.+opQSs7? N;isP!+3VC!ndPRqu6`E9E=herrDus!Up)krrRZMIuF=.+opQSs7? N;isP!+3SBrrDoq!PJL-s8N)srrLIHXoAHP!.Tq,![7X&f`)$+!!)or!oZfQfDkjNYlF_'JcEF` qZ)3IJcEjlJ,~> N;isP!+3SBrrDoq!PJL-s8N)srrLIHXoAHP!.Tq,![7X&f`)$+!!)or!oZfQfDkjNYlF_'JcEF` qZ)3IJcEjlJ,~> N;isP!+3SBrrDoq!PJL-s8N)srrLIHXoAHP!.Tq,![7X&f`)$+!!)or!oZfQfDkjNYlF_'JcEF` qZ)3IJcEjlJ,~> N;isP!+3SBrrDoq!Up*`s8N)srrJPgXoAHP!.Tq,![7X&fDkjNqYpTC!8%8N!3lM'!.k0$s+13$ s8W+L~> N;isP!+3SBrrDoq!Up*`s8N)srrJPgXoAHP!.Tq,![7X&fDkjNqYpTC!8%8N!3lM'!.k0$s+13$ s8W+L~> N;isP!+3SBrrDoq!Up*`s8N)srrJPgXoAHP!.Tq,![7X&fDkjNqYpTC!8%8N!3lM'!.k0$s+13$ s8W+L~> N;isP!+3SBrrDKerrE#t!mgoIXoAHP!.Tq,![7X&fDkjNqYpTc!8%8N!3lM'!.k0$s+13$s8W+L~> N;isP!+3SBrrDKerrE#t!mgoIXoAHP!.Tq,![7X&fDkjNqYpTc!8%8N!3lM'!.k0$s+13$s8W+L~> N;isP!+3SBrrDKerrE#t!mgoIXoAHP!.Tq,![7X&fDkjNqYpTc!8%8N!3lM'!.k0$s+13$s8W+L~> N;isP!+3SBrrDfn"7X@"!;uls!<2uuN;NYUN;ih\l).2TB>+ N;isP!+3SBrrDfn"7X@"!;uls!<2uuN;NYUN;ih\l).2TB>+ N;isP!+3SBrrDfn"7X@"!;uls!<2uuN;NYUN;ih\l).2TB>+ N;isP!+3SBrrE#t!Up*frr[X]!!)rsrrDusrrDus'$s>!s5A>*I/j4ZB)hq;l/?9&`W$!h!.Tq, ![7X&fDkjNpAYHga-m#.iL0`HZMsk(iVWZWiW&rW!!nP`s66FT!,'"Bs8N)rrs%tj9E7banG`Fo nAgsts3Q,n9YL?'"mMpY!,'!rs8N(Ms+13$s+14Ms*t~> N;isP!+3SBrrE#t!Up*frr[X]!!)rsrrDusrrDus'$s>!s5A>*I/j4ZB)hq;l/?9&`W$!h!.Tq, ![7X&fDkjNpAYHga-m#.iL0`HZMsk(iVWZWiW&rW!!nP`s66FT!,'"Bs8N)rrs%tj9E7banG`Fo nAgsts3Q,n9YL?'"mMpY!,'!rs8N(Ms+13$s+14Ms*t~> N;isP!+3SBrrE#t!Up*frr[X]!!)rsrrDusrrDus'$s>!s5A>*I/j4ZB)hq;l/?9&`W$!h!.Tq, ![7X&fDkjNpAYHga-m#.iL0`HZMsk(iVWZWiW&rW!!nP`s66FT!,'"Bs8N)rrs%tj9E7banG`Fo nAgsts3Q,n9YL?'"mMpY!,'!rs8N(Ms+13$s+14Ms*t~> N;isP!+3SBrrE#t!La#cs8N)ss8N)ss8N)trrV[`a8Z)@f`2#crr;uu!78R^!e13"MuNi&!8uK/ rrDrr!!)ut$@HId!56)Gs/,k1rr3)iHiT-'rsO4Ps8UG>d/W'P!.=_ErrDus($SE*s8UbG9\KIG HtNEZZI&X@RK/fTrs-nEd/W'P!. N;isP!+3SBrrE#t!La#cs8N)ss8N)ss8N)trrV[`a8Z)@f`2#crr;uu!78R^!e13"MuNi&!8uK/ rrDrr!!)ut$@HId!56)Gs/,k1rr3)iHiT-'rsO4Ps8UG>d/W'P!.=_ErrDus($SE*s8UbG9\KIG HtNEZZI&X@RK/fTrs-nEd/W'P!. N;isP!+3SBrrE#t!La#cs8N)ss8N)ss8N)trrV[`a8Z)@f`2#crr;uu!78R^!e13"MuNi&!8uK/ rrDrr!!)ut$@HId!56)Gs/,k1rr3)iHiT-'rsO4Ps8UG>d/W'P!.=_ErrDus($SE*s8UbG9\KIG HtNEZZI&X@RK/fTrs-nEd/W'P!. N;isP!+3SBq#L N;isP!+3SBq#L N;isP!+3SBq#L N;isP!+3SBrrE#t!PJL1s8N)ss8N)ss8N)trr?^,!<3#u!5SU9IfOtVrrOAEi7J#(!;lfr!;uls !;uiuHiW.)rrq)Rs8Stsr;Zcs!.=bFrrE#t!lk<*r;Qhr!4)V(rrDus#1*@=s8Stsr;Zcs!. N;isP!+3SBrrE#t!PJL1s8N)ss8N)ss8N)trr?^,!<3#u!5SU9IfOtVrrOAEi7J#(!;lfr!;uls !;uiuHiW.)rrq)Rs8Stsr;Zcs!.=bFrrE#t!lk<*r;Qhr!4)V(rrDus#1*@=s8Stsr;Zcs!. N;isP!+3SBrrE#t!PJL1s8N)ss8N)ss8N)trr?^,!<3#u!5SU9IfOtVrrOAEi7J#(!;lfr!;uls !;uiuHiW.)rrq)Rs8Stsr;Zcs!.=bFrrE#t!lk<*r;Qhr!4)V(rrDus#1*@=s8Stsr;Zcs!. N;isP!+3SBrrDus!!)orrrDusrrDusrrE#trrDcmrrBk7!e13"MuNi&!8uK/rrDus!PJL1s8N)s s8N)srrUOIVuH]!Rb@`@BD;K*s8N)trrIKIqu6`V!,)<2rrDus"n2Kls8Qa,!8.>O!.k0$s+13$ s8W+L~> N;isP!+3SBrrDus!!)orrrDusrrDusrrE#trrDcmrrBk7!e13"MuNi&!8uK/rrDus!PJL1s8N)s s8N)srrUOIVuH]!Rb@`@BD;K*s8N)trrIKIqu6`V!,)<2rrDus"n2Kls8Qa,!8.>O!.k0$s+13$ s8W+L~> N;isP!+3SBrrDus!!)orrrDusrrDusrrE#trrDcmrrBk7!e13"MuNi&!8uK/rrDus!PJL1s8N)s s8N)srrUOIVuH]!Rb@`@BD;K*s8N)trrIKIqu6`V!,)<2rrDus"n2Kls8Qa,!8.>O!.k0$s+13$ s8W+L~> N;isP!+3SBrrD`lrrDusrrDusrrE#trr<&gp](6n_#FIc!.Tq,![7X&fDkjNqu6Wrqu?Zrr;Zcs qu6Zs9`G%lBE%r2!;6Bl!<)rt!;c`q!<3#u!;lfr!<<*!!7:cG!.k0$s+13$s8W+L~> N;isP!+3SBrrD`lrrDusrrDusrrE#trr<&gp](6n_#FIc!.Tq,![7X&fDkjNqu6Wrqu?Zrr;Zcs qu6Zs9`G%lBE%r2!;6Bl!<)rt!;c`q!<3#u!;lfr!<<*!!7:cG!.k0$s+13$s8W+L~> N;isP!+3SBrrD`lrrDusrrDusrrE#trr<&gp](6n_#FIc!.Tq,![7X&fDkjNqu6Wrqu?Zrr;Zcs qu6Zs9`G%lBE%r2!;6Bl!<)rt!;c`q!<3#u!;lfr!<<*!!7:cG!.k0$s+13$s8W+L~> N;isP!+3SBrrD`lrrDusrrDusrrE#t!bVMRr;QfeBE%r2!5SU9IfOtVrrOAEi7J#/!;-*Da0P^Err<&gpAb-mrVultqZ$Qqrr;uuqu?Zrs8W*!!:\D9rr@WMJcC<$JcGcMJ,~> N;isP!+3SBrrD`lrrDusrrDusrrE#t!bVMRr;QfeBE%r2!5SU9IfOtVrrOAEi7J#/!;-*Da0P^Err<&gpAb-mrVultqZ$Qqrr;uuqu?Zrs8W*!!:\D9rr@WMJcC<$JcGcMJ,~> N;isP!+3SBrrD`lrrDusrrDusrrE#t!bVMRr;QfeBE%r2!5SU9IfOtVrrOAEi7J#/!;-*Da0P^Err<&gpAb-mrVultqZ$Qqrr;uuqu?Zrs8W*!!:\D9rr@WMJcC<$JcGcMJ,~> N;isP!+3SBrrD`lrrDusrrDusrrE#t!iH#lr;Qf2N;ikW!5SU9IfOtVrrOAEi7J#/!;-$;!UsaSs8N(M s+13$s+14Ms*t~> N;isP!+3SBrrD`lrrDusrrDusrrE#t!iH#lr;Qf2N;ikW!5SU9IfOtVrrOAEi7J#/!;-$;!UsaSs8N(M s+13$s+14Ms*t~> N;isP!+3SBrrD`lrrDusrrDusrrE#t!iH#lr;Qf2N;ikW!5SU9IfOtVrrOAEi7J#/!;-$;!UsaSs8N(M s+13$s+14Ms*t~> N;isP!+3SBrrD`lrrDusrrDusrrE#t$0_EiBA*=bcqMgcs8N)7rrRZMIuF=.+opQQs8N)prrM)+ rr;uur;ZcsqYpY1!76,lrrT(u9`4nk]o;pirrE#t!jVg(r;Qi_!7:`FrrDus#MB*ts8Sts9`4nk ]o:VDrr@WMJcC<$JcGcMJ,~> N;isP!+3SBrrD`lrrDusrrDusrrE#t$0_EiBA*=bcqMgcs8N)7rrRZMIuF=.+opQQs8N)prrM)+ rr;uur;ZcsqYpY1!76,lrrT(u9`4nk]o;pirrE#t!jVg(r;Qi_!7:`FrrDus#MB*ts8Sts9`4nk ]o:VDrr@WMJcC<$JcGcMJ,~> N;isP!+3SBrrD`lrrDusrrDusrrE#t$0_EiBA*=bcqMgcs8N)7rrRZMIuF=.+opQQs8N)prrM)+ rr;uur;ZcsqYpY1!76,lrrT(u9`4nk]o;pirrE#t!jVg(r;Qi_!7:`FrrDus#MB*ts8Sts9`4nk ]o:VDrr@WMJcC<$JcGcMJ,~> N;isP!+3VC"5*YSg%YLKci='mrr3)I!!(CErs*oOiRs1is3UWC!2ohr"31BAiPGNqIfOtVrrOAE i7J#/!;ZWq9ZR/4rrDusrrDoq"2+[7d/EtNkl:]rg&M*!9[Nbd+JBu!.k0$s+13$s8W+L~> N;isP!+3VC"5*YSg%YLKci='mrr3)I!!(CErs*oOiRs1is3UWC!2ohr"31BAiPGNqIfOtVrrOAE i7J#/!;ZWq9ZR/4rrDusrrDoq"2+[7d/EtNkl:]rg&M*!9[Nbd+JBu!.k0$s+13$s8W+L~> N;isP!+3VC"5*YSg%YLKci='mrr3)I!!(CErs*oOiRs1is3UWC!2ohr"31BAiPGNqIfOtVrrOAE i7J#/!;ZWq9ZR/4rrDusrrDoq"2+[7d/EtNkl:]rg&M*!9[Nbd+JBu!.k0$s+13$s8W+L~> N;isP!+3YDqZ-HlqZ$WrqZ-Wq"6jFuVu?W!iL0`HI(fOZqZ+M5!e13"MuNi&!8uN0"5*YSl2:P_ fk1 N;isP!+3YDqZ-HlqZ$WrqZ-Wq"6jFuVu?W!iL0`HI(fOZqZ+M5!e13"MuNi&!8uN0"5*YSl2:P_ fk1 N;isP!+3YDqZ-HlqZ$WrqZ-Wq"6jFuVu?W!iL0`HI(fOZqZ+M5!e13"MuNi&!8uN0"5*YSl2:P_ fk1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!+1 N;isP!(_[UcbBNg!.Tq,![7X&JcF'rrr@WMJcC<$JcGcMJ,~> N;isP!(_[UcbBNg!.Tq,![7X&JcF'rrr@WMJcC<$JcGcMJ,~> N;isP!(_[UcbBNg!.Tq,![7X&JcF'rrr@WMJcC<$JcGcMJ,~> N;imNJH3jn!.Tq,![7V(JO%OHrr@WMJcC<$JcGcMJ,~> N;imNJH3jn!.Tq,![7V(JO%OHrr@WMJcC<$JcGcMJ,~> N;imNJH3jn!.Tq,![7V(JO%OHrr@WMJcC<$JcGcMJ,~> N;imeJO%CD!2,8M!$Zsob5d+nJcC<$JcGcMJ,~> N;imeJO%CD!2,8M!$Zsob5d+nJcC<$JcGcMJ,~> N;imeJO%CD!2,8M!$Zsob5d+nJcC<$JcGcMJ,~> JcC<$JcFU,!69Z*bJ/W.JcC<$JcGcMJ,~> JcC<$JcFU,!69Z*bJ/W.JcC<$JcGcMJ,~> JcC<$JcFU,!69Z*bJ/W.JcC<$JcGcMJ,~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> JcC<$JcC<$JcC<$JcC<$V>l&~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/warpnotesfig.ps0000644000175000000620000003064011466723256020247 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 31 670 426 755 %%Title: (warpnotesfig-Layer#1) %%Creator: (MacDraw II 1.1v2: LaserWriter 8 8.1.1) %%CreationDate: (10:27 PM Sunday, January 24, 1904) %%For: (Dannenberg) %%Pages: 1 %%DocumentFonts: Helvetica %%DocumentNeededFonts: Helvetica %%DocumentSuppliedFonts: %%DocumentData: Clean7Bit %%PageOrder: Ascend %%Orientation: Portrait %ADO_PaperArea: -129 -125 3171 2425 %ADO_ImageableArea: 0 0 3042 2300 %%EndComments /md 149 dict def md begin /currentpacking where {pop /sc_oldpacking currentpacking def true setpacking}if %%BeginFile: adobe_psp_basic %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /bd{bind def}bind def /xdf{exch def}bd /xs{exch store}bd /ld{load def}bd /Z{0 def}bd /T/true /F/false /:L/lineto /lw/setlinewidth /:M/moveto /rl/rlineto /rm/rmoveto /:C/curveto /:T/translate /:K/closepath /:mf/makefont /gS/gsave /gR/grestore /np/newpath 14{ld}repeat /$m matrix def /av 81 def /por true def /normland false def /psb-nosave{}bd /pse-nosave{}bd /us Z /psb{/us save store}bd /pse{us restore}bd /level2 /languagelevel where { pop languagelevel 2 ge }{ false }ifelse def /featurecleanup { stopped cleartomark countdictstack exch sub dup 0 gt { {end}repeat }{ pop }ifelse }bd /noload Z /startnoload { {/noload save store}if }bd /endnoload { {noload restore}if }bd level2 startnoload /setjob { statusdict/jobname 3 -1 roll put }bd /setcopies { userdict/#copies 3 -1 roll put }bd level2 endnoload level2 not startnoload /setjob { 1 dict begin/JobName xdf currentdict end setuserparams }bd /setcopies { 1 dict begin/NumCopies xdf currentdict end setpagedevice }bd level2 not endnoload /pm Z /mT Z /sD Z /realshowpage Z /initializepage { /pm save store mT concat }bd /endp { pm restore showpage }def /$c/DeviceRGB def /rectclip where { pop/rC/rectclip ld }{ /rC { np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K clip np }bd }ifelse /rectfill where { pop/rF/rectfill ld }{ /rF { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl fill gR }bd }ifelse /rectstroke where { pop/rS/rectstroke ld }{ /rS { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K stroke gR }bd }ifelse %%EndFile %%BeginFile: adobe_psp_colorspace_level1 %%Copyright: Copyright 1991-1993 Adobe Systems Incorporated. All Rights Reserved. /G/setgray ld /:F/setrgbcolor ld %%EndFile %%BeginFile: adobe_psp_uniform_graphics %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /@a { np :M 0 rl :L 0 exch rl 0 rl :L fill }bd /@b { np :M 0 rl 0 exch rl :L 0 rl 0 exch rl fill }bd /arct where { pop }{ /arct { arcto pop pop pop pop }bd }ifelse /x1 Z /x2 Z /y1 Z /y2 Z /rad Z /@q { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct fill }bd /@s { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct :K stroke }bd /@i { np 0 360 arc fill }bd /@j { gS np :T scale 0 0 .5 0 360 arc fill gR }bd /@e { np 0 360 arc :K stroke }bd /@f { np $m currentmatrix pop :T scale 0 0 .5 0 360 arc :K $m setmatrix stroke }bd /@k { gS np :T 0 0 :M 0 0 5 2 roll arc fill gR }bd /@l { gS np :T 0 0 :M scale 0 0 .5 5 -2 roll arc fill gR }bd /@m { np arc stroke }bd /@n { np $m currentmatrix pop :T scale 0 0 .5 5 -2 roll arc $m setmatrix stroke }bd %%EndFile %%BeginFile: adobe_psp_customps %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /$t Z /$p Z /$s Z /$o 1. def /2state? false def /ps Z level2 startnoload /pushcolor/currentrgbcolor ld /popcolor/setrgbcolor ld /setcmykcolor where { pop/currentcmykcolor where { pop/pushcolor/currentcmykcolor ld /popcolor/setcmykcolor ld }if }if level2 endnoload level2 not startnoload /pushcolor { currentcolorspace $c eq { currentcolor currentcolorspace true }{ currentcmykcolor false }ifelse }bd /popcolor { { setcolorspace setcolor }{ setcmykcolor }ifelse }bd level2 not endnoload /pushstatic { ps 2state? $o $t $p $s }bd /popstatic { /$s xs /$p xs /$t xs /$o xs /2state? xs /ps xs }bd /pushgstate { save errordict/nocurrentpoint{pop 0 0}put currentpoint 3 -1 roll restore pushcolor currentlinewidth currentlinecap currentlinejoin currentdash exch aload length np clippath pathbbox $m currentmatrix aload pop }bd /popgstate { $m astore setmatrix 2 index sub exch 3 index sub exch rC array astore exch setdash setlinejoin setlinecap lw popcolor np :M }bd /bu { pushgstate gR pushgstate 2state? { gR pushgstate }if pushstatic pm restore mT concat }bd /bn { /pm save store popstatic popgstate gS popgstate 2state? { gS popgstate }if }bd /cpat{pop 64 div G 8{pop}repeat}bd %%EndFile %%BeginFile: adobe_psp_basic_text %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /S/show ld /A{ 0.0 exch ashow }bd /R{ 0.0 exch 32 exch widthshow }bd /W{ 0.0 3 1 roll widthshow }bd /J{ 0.0 32 4 2 roll 0.0 exch awidthshow }bd /V{ 0.0 4 1 roll 0.0 exch awidthshow }bd /fcflg true def /fc{ fcflg{ vmstatus exch sub 50000 lt{ (%%[ Warning: Running out of memory ]%%\r)print flush/fcflg false store }if pop }if }bd /$f[1 0 0 -1 0 0]def /:ff{$f :mf}bd /MacEncoding StandardEncoding 256 array copy def MacEncoding 39/quotesingle put MacEncoding 96/grave put /Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute /agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave /ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute /ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls /registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash /infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation /product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft /guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe /endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge /ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl /daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand /Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave /Oacute/Ocircumflex/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde /macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron MacEncoding 128 128 getinterval astore pop level2 startnoload /copyfontdict { findfont dup length dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall }bd level2 endnoload level2 not startnoload /copyfontdict { findfont dup length dict copy begin }bd level2 not endnoload md/fontname known not{ /fontname/customfont def }if /Encoding Z /:mre { copyfontdict /Encoding MacEncoding def fontname currentdict end definefont :ff def }bd /:bsr { copyfontdict /Encoding Encoding 256 array copy def Encoding dup }bd /pd{put dup}bd /:esr { pop pop fontname currentdict end definefont :ff def }bd /scf { scalefont def }bd /scf-non { $m scale :mf setfont }bd /ps Z /fz{/ps xs}bd /sf/setfont ld /cF/currentfont ld /mbf { /makeblendedfont where { pop makeblendedfont /ABlend exch definefont }{ pop }ifelse def }def %%EndFile /currentpacking where {pop sc_oldpacking setpacking}if end % md %%EndProlog %%BeginSetup md begin /pT[1 0 0 -1 29.999 761.009]def/mT[.24 0 0 -.24 29.999 761.009]def /sD 16 dict def %%IncludeFont: Helvetica /f0_1/Helvetica :mre /f1_1 f0_1 1.04 scf /f1_50 f1_1 50 scf /Courier findfont[10 0 0 -10 0 0]:mf setfont %%EndSetup %%Page: 1 1 %%BeginPageSetup initializepage %%EndPageSetup gS 0 0 2300 3042 rC 0 0 :M 0 setlinecap currentscreen 3 1 roll pop pop 60 45 3 -1 roll setscreen 2 setlinecap .75 G 1013 52.5 :M 1062.985 68.166 1088 76 1088 76 :C 1088 76 1062.985 83.832 1013 99.5 :C 962.984 115.165 938 123 938 123 :C 938 123 938 107.332 938 76 :C 938 44.665 938 29 938 29 :C 938 29 962.984 36.832 1013 52.5 :C 8 lw :K gS eofill gR 0 G stroke 938 29 :M 0 setlinecap 2 setlinecap .75 G 1163 52.5 :M 1212.983 68.166 1238 76 1238 76 :C 1238 76 1212.983 83.832 1163 99.5 :C 1112.982 115.165 1088 123 1088 123 :C 1088 123 1088 107.332 1088 76 :C 1088 44.665 1088 29 1088 29 :C 1088 29 1112.982 36.832 1163 52.5 :C :K gS eofill gR 0 G stroke 1088 29 :M 0 setlinecap 2 setlinecap .75 G 1313 52.5 :M 1362.98 68.166 1388 76 1388 76 :C 1388 76 1362.98 83.832 1313 99.5 :C 1262.98 115.165 1238 123 1238 123 :C 1238 123 1238 107.332 1238 76 :C 1238 44.665 1238 29 1238 29 :C 1238 29 1262.98 36.832 1313 52.5 :C :K gS eofill gR 0 G stroke 1238 29 :M 0 setlinecap 2 setlinecap .75 G 1463 52.5 :M 1512.978 68.166 1538 76 1538 76 :C 1538 76 1512.978 83.832 1463 99.5 :C 1412.977 115.165 1388 123 1388 123 :C 1388 123 1388 107.332 1388 76 :C 1388 44.665 1388 29 1388 29 :C 1388 29 1412.977 36.832 1463 52.5 :C :K gS eofill gR 0 G stroke 1388 29 :M 0 setlinecap np 1650 263 :M 1591 277 :L 1591 263 :L 1591 248 :L 1650 263 :L eofill 36 265 -4 4 1593 261 4 36 261 @a -4 -4 415 302 4 4 411 261 @b -4 -4 602 302 4 4 598 261 @b -4 -4 790 302 4 4 786 261 @b -4 -4 977 302 4 4 973 261 @b -4 -4 1165 302 4 4 1161 261 @b -4 -4 1352 302 4 4 1348 261 @b -4 -4 1540 302 4 4 1536 261 @b 18 358 :M f1_50 sf (0)S 393 358 :M (1)S 768 358 :M (2)S 1143 358 :M (3)S 1518 358 :M (4)S 4 lw 1551 358 :M 2 setlinecap .75 G 919 52.5 :M 931.653 68.166 938 76 938 76 :C 938 76 931.653 83.832 919 99.5 :C 906.319 115.165 900 123 900 123 :C 900 123 900 107.332 900 76 :C 900 44.665 900 29 900 29 :C 900 29 906.319 36.832 919 52.5 :C 8 lw :K gS eofill gR 0 G stroke 900 29 :M 0 setlinecap -4 -4 227 302 4 4 223 261 @b -4 -4 40 302 4 4 36 261 @b 4 lw 36 261 :M 2 setlinecap .75 G 881.5 52.5 :M 893.82 68.166 900 76 900 76 :C 900 76 893.82 83.832 881.5 99.5 :C 869.153 115.165 863 123 863 123 :C 863 123 863 107.332 863 76 :C 863 44.665 863 29 863 29 :C 863 29 869.153 36.832 881.5 52.5 :C 8 lw :K gS eofill gR 0 G stroke 863 29 :M 0 setlinecap 2 setlinecap .75 G 844 52.5 :M 856.654 68.166 863 76 863 76 :C 863 76 856.654 83.832 844 99.5 :C 831.32 115.165 825 123 825 123 :C 825 123 825 107.332 825 76 :C 825 44.665 825 29 825 29 :C 825 29 831.32 36.832 844 52.5 :C :K gS eofill gR 0 G stroke 825 29 :M 0 setlinecap 2 setlinecap .75 G 806.5 52.5 :M 818.821 68.166 825 76 825 76 :C 825 76 818.821 83.832 806.5 99.5 :C 794.154 115.165 788 123 788 123 :C 788 123 788 107.332 788 76 :C 788 44.665 788 29 788 29 :C 788 29 794.154 36.832 806.5 52.5 :C :K gS eofill gR 0 G stroke 788 29 :M 0 setlinecap 2 setlinecap .75 G 769 52.5 :M 781.655 68.166 788 76 788 76 :C 788 76 781.655 83.832 769 99.5 :C 756.321 115.165 750 123 750 123 :C 750 123 750 107.332 750 76 :C 750 44.665 750 29 750 29 :C 750 29 756.321 36.832 769 52.5 :C :K gS eofill gR 0 G stroke 750 29 :M 0 setlinecap 2 setlinecap .75 G 731.5 52.5 :M 743.822 68.166 750 76 750 76 :C 750 76 743.822 83.832 731.5 99.5 :C 719.155 115.165 713 123 713 123 :C 713 123 713 107.332 713 76 :C 713 44.665 713 29 713 29 :C 713 29 719.155 36.832 731.5 52.5 :C :K gS eofill gR 0 G stroke 713 29 :M 0 setlinecap 2 setlinecap .75 G 694 52.5 :M 706.656 68.166 713 76 713 76 :C 713 76 706.656 83.832 694 99.5 :C 681.323 115.165 675 123 675 123 :C 675 123 675 107.332 675 76 :C 675 44.665 675 29 675 29 :C 675 29 681.323 36.832 694 52.5 :C :K gS eofill gR 0 G stroke 675 29 :M 0 setlinecap 2 setlinecap .75 G 656.5 52.5 :M 668.823 68.166 675 76 675 76 :C 675 76 668.823 83.832 656.5 99.5 :C 644.157 115.165 638 123 638 123 :C 638 123 638 107.332 638 76 :C 638 44.665 638 29 638 29 :C 638 29 644.157 36.832 656.5 52.5 :C :K gS eofill gR 0 G stroke 638 29 :M 0 setlinecap 2 setlinecap .75 G 113 52.5 :M 162.999 68.166 188 76 188 76 :C 188 76 162.999 83.832 113 99.5 :C 62.998 115.165 38 123 38 123 :C 38 123 38 107.332 38 76 :C 38 44.665 38 29 38 29 :C 38 29 62.998 36.832 113 52.5 :C :K gS eofill gR 0 G stroke 38 29 :M 0 setlinecap 2 setlinecap .75 G 263 52.5 :M 312.996 68.166 338 76 338 76 :C 338 76 312.996 83.832 263 99.5 :C 212.996 115.165 188 123 188 123 :C 188 123 188 107.332 188 76 :C 188 44.665 188 29 188 29 :C 188 29 212.996 36.832 263 52.5 :C :K gS eofill gR 0 G stroke 188 29 :M 0 setlinecap 2 setlinecap .75 G 413 52.5 :M 462.994 68.166 488 76 488 76 :C 488 76 462.994 83.832 413 99.5 :C 362.993 115.165 338 123 338 123 :C 338 123 338 107.332 338 76 :C 338 44.665 338 29 338 29 :C 338 29 362.993 36.832 413 52.5 :C :K gS eofill gR 0 G stroke 338 29 :M 0 setlinecap 2 setlinecap .75 G 563 52.5 :M 612.992 68.166 638 76 638 76 :C 638 76 612.992 83.832 563 99.5 :C 512.991 115.165 488 123 488 123 :C 488 123 488 107.332 488 76 :C 488 44.665 488 29 488 29 :C 488 29 512.991 36.832 563 52.5 :C :K gS eofill gR 0 G stroke 488 29 :M 0 setlinecap endp %%Trailer end % md %%EOF nyquist-3.05/docsrc/nyquist/linear-fig.ps0000644000175000000620000000573311466723256017561 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: linear-fig.ps %%CreationDate: Wed Jul 13 12:16:49 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2321 ASCII Bytes image s8N)ri;WlYrVPOQ!rr,oi;WlYrVPOQ!rr5oi;WlYqtT+L"98/n5N2YBrrN#SiW&rX!W2'=s8W*" qt]4Ns8N,sro*nWrrW)t5N;_CrrW#rhr=\9rrW)tkMlOArrW)tqr7YUrrW)tr8RbVrr`/us*s)/ s8N2us8S_Os8W*$qu?]bj8]/Z"8i,uoAflNrr`)ss8:pWs8N)rrr2s_jT#8[!;lcq!70a+s8N)r rr2uijT#8[!;lcq!<)!Ys8N)rrr3#uJ*$_1rrDrprrBgqs8W*!qu-NpcfP3,rrDlnrrDfTs8W*! qu-NpqrRkXrrDrprrDuYs8W*!qu$HoJ*-e2rrDrorrA\Rs8W*!qu$HokN;gErrDrorrDlWs8W*! qu$HprdX,2s8N)pqu6YgkPtS^!;lZn!:T+Ns8N)rqu6ZfkPtS^!;lZn!<)*\s8N)rqu6]rJ*?n6 TB#hFrrA\TrrV*HqtgUH@l2Ue`!;lTl!;#ITs8N)rq>UHnl2Ue`!;lTl!WIT6s8W*!qtU0k^Ztk!rrDlirrCC1 s8W*!qtU0kpZheYrrDrkrrDl[s8W*!qtU0lrdX86s8N)rp\t6.li7"b!;lNj!71!2s8N)rp\t6f li7"b!;lNj!;Ys\s8N)pp\t9nJ*d48rrDrirrBh#s8W*!qtC$icg:]3rrDrirrDZWs8W*!qtC$i rTsRarrDrirrN+KmJm4d!;lHh!5Iq$s8N)rp&>$$jmJm4d!;lHh !WIT:s8W*!qt0mg^[D.%rrDrgrrCC5s8W*!qt0mgp[8(]rrDrgrrDl_s8W*!qt0mhrdXD:s8N)p oD\g*n,NFf!;lBf!71-6s8N)roD\gbn,NFf!;lBf!;Z*`s8N)roD\jjJ+3I>s7uQ_rrBh'rrW6! qssaecg^r9s8DicrrDZ[rrW6!q""FbrUBggs8DicrrN+Knc&[jn9a^*!2&f]s8N)rnc&UPnc/Xh !;lrrDrcrrBh)s8W*!q=+Cacgq,9rrDrcrrDZ]s8W*!qsaUcr:9mf rrDrbrr>:Ts8W*!qsXObch%2:rrDrbrrDfbs8W*!qsXObq=FXdrrDrbrrE&is8W*!q:Vs8W*!qsFC`ht@$L rrDr`rrD6Ts8W*!q:Xs8W*!qrrDr^rrDffs8W*!qs47^q=jph rrDr^rrE&ms8W*!qs+1]5PY6[hrFV!rrCC?rrTCmqs+1]p\=aiYNPfJrrDlirrTD$q!.kZrqQKp YNu)Mrr>:ZrrV'Oqs"+\htd('jrrDr\rrE&os8W*!qrn%[5PkE[ rrDr[rrCsQs8W*!q<7hYkPG5YrrDr[rrDrms8W*!qrn%[r;-HnrrDrZrr>:\s8W*!qrdtZhu!HR rrDrZrrD6Zs8W*!qrdtZqtpEnrrDrZrrDuos8W*!q<%\W5Q(Q]rrDrYrrCCCs8W*!qr[nYoDJXg rrDrYrrDups8W*!qrRhXJ,TEIrrDrXrrA\is8W*!qrRhXn,<:drrDrXrrDZhs8W*!q;qVVr;HZq rrDrWrr@QJs8W*!qrIbWTDnljrrDrWrrDNes8W*!qrIbWoD\dirrDrWrrE#ss8W*!qrIbZrdXtJ s8N)rj8T1Qs8W-!!;Y[T!q60hs8N)rj8T2Ps8W-!!;kgV!r`0!s8N)rj8T2[J,fQK!;kdU!MBDl rrDrUrrMTgs8N)rqu6Z2r;Qcoqu6YGr;Qckr;QfhJ,fNlqu>RQs7cQ.rVu?dJ,B9'rVu?dJ,B9' rr;`m^]"3$r-nbIrnmbV!WW0"qr%MSrrDrSs8W*!qr%MSrrDrSs5!_NrrM$OrVlrts1eO4!Pdgr rrN#rr;Qfqs7uZqYNu/e!rDp]rVln*hu3QVp&0C=rrN-!q>UK!p\k*nqYn8.rrHKQrVlokrqucs rr;fo!O)7rrrW&r+8u3??e>8V!qlMArVlots7uZqYODGi!rDr3rVln*fDY^Np&0C=rrN-!q>UKP j8JuZrU1j,rrKgZrVloqhYdBSpcmU7J,~> %%EndData %showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/bernoulli-fig.ps0000644000175000000620000013353411466723256020303 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: bernoulli-fig.ps %%CreationDate: Wed Jul 13 12:13:35 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 312 364 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 348.98334526366023 translate -20 775 translate 296.98582677165354 -348.98334526366023 scale % Image geometry 297 349 8 % Transformation matrix [ 297 0 0 349 0 0 ] % Strings to hold RGB-samples per scanline /rstr 297 string def /gstr 297 string def /bstr 297 string def {currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} true 3 %%BeginData: 45884 ASCII Bytes colorimage JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> r;V r;V r;V r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`s_uKW7!IX.hs8N'&rr<'!!!)utr;["7d/X+G!;ZWqiJdX5rr<-#!!)`m"lYF?rr<&Ls8)cs s7#pd_Z'T9qu;0~> r;Q`s_uKW7!IX.hs8N'&rr<'!!!)utr;["7d/X+G!;ZWqiJdX5rr<-#!!)`m"lYF?rr<&Ls8)cs s7#pd_Z'T9qu;0~> r;Q`s_uKW7!IX.hs8N'&rr<'!!!)utr;["7d/X+G!;ZWqiJdX5rr<-#!!)`m"lYF?rr<&Ls8)cs s7#pd_Z'T9qu;0~> r;Q`s_uK`:s8N/Z!,19irr<-#!!)lqrrE*!!h',JpAb-mp](6npAb-mcMn+%!0$s2!1L\&!!)or J,~> r;Q`s_uK`:s8N/Z!,19irr<-#!!)lqrrE*!!h',JpAb-mp](6npAb-mcMn+%!0$s2!1L\&!!)or J,~> r;Q`s_uK`:s8N/Z!,19irr<-#!!)lqrrE*!!h',JpAb-mp](6npAb-mcMn+%!0$s2!1L\&!!)or J,~> r;Q`s_uK`:rr;uus8OIP!!'>)rr<%XI/a0Hd!SR7s8TB!!4)Y)!!*'!!!*$!!<3$!rr<&ts8N*! rs\,lRf?!ZN'q)!76*fd/*eB !!:MAI-gk;BE7;s]`?*frr<&rs*t~> r;Q`s_uK`:rr;uus8OIP!!'>)rr<%XI/a0Hd!SR7s8TB!!4)Y)!!*'!!!*$!!<3$!rr<&ts8N*! rs\,lRf?!ZN'q)!76*fd/*eB !!:MAI-gk;BE7;s]`?*frr<&rs*t~> r;Q`s_uK`:rr;uus8OIP!!'>)rr<%XI/a0Hd!SR7s8TB!!4)Y)!!*'!!!*$!!<3$!rr<&ts8N*! rs\,lRf?!ZN'q)!76*fd/*eB !!:MAI-gk;BE7;s]`?*frr<&rs*t~> r;Q`s_uK`:s8OY/!4)X!2oeqqZ-Ek$,$>Ps8S#X9`U-grr<&rs*t~> r;Q`s_uK`:s8OY/!4)X!2oeqqZ-Ek$,$>Ps8S#X9`U-grr<&rs*t~> r;Q`s_uK`:s8OY/!4)X!2oeqqZ-Ek$,$>Ps8S#X9`U-grr<&rs*t~> r;Q`s_uKW7$[hID9`Y4n!,2B4!<3#u!<<*!!#GTJ!<<'!B`A&4s8N'!rr<'!!!*$!!<)rt!<3#u !!iN(!<5anI*hlmrrE*!rrE&urr=5B!!*'!!)3Fns8N'!rr<'!rr<'!BE8)4!,2B4!<<'!!;c`q !<<'"!);n]s%WLm"cQ1?`rMRFrr<&rs*t~> r;Q`s_uKW7$[hID9`Y4n!,2B4!<3#u!<<*!!#GTJ!<<'!B`A&4s8N'!rr<'!!!*$!!<)rt!<3#u !!iN(!<5anI*hlmrrE*!rrE&urr=5B!!*'!!)3Fns8N'!rr<'!rr<'!BE8)4!,2B4!<<'!!;c`q !<<'"!);n]s%WLm"cQ1?`rMRFrr<&rs*t~> r;Q`s_uKW7$[hID9`Y4n!,2B4!<3#u!<<*!!#GTJ!<<'!B`A&4s8N'!rr<'!!!*$!!<)rt!<3#u !!iN(!<5anI*hlmrrE*!rrE&urr=5B!!*'!!)3Fns8N'!rr<'!rr<'!BE8)4!,2B4!<<'!!;c`q !<<'"!);n]s%WLm"cQ1?`rMRFrr<&rs*t~> r;Q`s_uK`:s8N2S!,2E0!!<0#!<3#u!<<*!!#GS7!<<'!!<3$!s8N'!rr<'!!!*$!!<)rt!<3#u !"f/1!<:D?!!#a?rr<'!rr<&us8N'%rr<'!s8;rts8N'5rr<'!rr<'!!!*'!!!*$!!<<'!!;c`q !<<*!!<)rp!;ZWrf`8>Ss8N)9rr<&rs*t~> r;Q`s_uK`:s8N2S!,2E0!!<0#!<3#u!<<*!!#GS7!<<'!!<3$!s8N'!rr<'!!!*$!!<)rt!<3#u !"f/1!<:D?!!#a?rr<'!rr<&us8N'%rr<'!s8;rts8N'5rr<'!rr<'!!!*'!!!*$!!<<'!!;c`q !<<*!!<)rp!;ZWrf`8>Ss8N)9rr<&rs*t~> r;Q`s_uK`:s8N2S!,2E0!!<0#!<3#u!<<*!!#GS7!<<'!!<3$!s8N'!rr<'!!!*$!!<)rt!<3#u !"f/1!<:D?!!#a?rr<'!rr<&us8N'%rr<'!s8;rts8N'5rr<'!rr<'!!!*'!!!*$!!<<'!!;c`q !<<*!!<)rp!;ZWrf`8>Ss8N)9rr<&rs*t~> r;Q`s_uK`:rr;uu!rkspr;Zcsrr;uus8W*!(B8%Js8N(4rr<'!rr<'!!!*$!!<3$!rVults8N8e !1Nof!<3!*fr"gErr<'!rr<&us8N'Brr<'!rr>an!<<'!!<3$!s8N'!s(DE4rr?a4!!*'!!!)lq rrE*!!<>j_rrT(ug%t^L!):?1!!)orJ,~> r;Q`s_uK`:rr;uu!rkspr;Zcsrr;uus8W*!(B8%Js8N(4rr<'!rr<'!!!*$!!<3$!rVults8N8e !1Nof!<3!*fr"gErr<'!rr<&us8N'Brr<'!rr>an!<<'!!<3$!s8N'!s(DE4rr?a4!!*'!!!)lq rrE*!!<>j_rrT(ug%t^L!):?1!!)orJ,~> r;Q`s_uK`:rr;uu!rkspr;Zcsrr;uus8W*!(B8%Js8N(4rr<'!rr<'!!!*$!!<3$!rVults8N8e !1Nof!<3!*fr"gErr<'!rr<&us8N'Brr<'!rr>an!<<'!!<3$!s8N'!s(DE4rr?a4!!*'!!!)lq rrE*!!<>j_rrT(ug%t^L!):?1!!)orJ,~> r;Q`s_uK`:s8NMd!0$r`!6==(N;ikXrr;uus8W*!(B;&Ja2\1ns(DDs]`8'4!!*$!!<3$!rVult s8Nb$!87AP!<7EHl0n[drr<'!rr<&us8N'Err<%sciBtW!9q/s!<3$!s8N'!s1JEQ`rNgQ!!*'! !!*$!!<)rt!!B.G!2oGgrrE*!!b_T'rr3.L!9qi1ZGQVA!;leH~> r;Q`s_uK`:s8NMd!0$r`!6==(N;ikXrr;uus8W*!(B;&Ja2\1ns(DDs]`8'4!!*$!!<3$!rVult s8Nb$!87AP!<7EHl0n[drr<'!rr<&us8N'Err<%sciBtW!9q/s!<3$!s8N'!s1JEQ`rNgQ!!*'! !!*$!!<)rt!!B.G!2oGgrrE*!!b_T'rr3.L!9qi1ZGQVA!;leH~> r;Q`s_uK`:s8NMd!0$r`!6==(N;ikXrr;uus8W*!(B;&Ja2\1ns(DDs]`8'4!!*$!!<3$!rVult s8Nb$!87AP!<7EHl0n[drr<'!rr<&us8N'Err<%sciBtW!9q/s!<3$!s8N'!s1JEQ`rNgQ!!*'! !!*$!!<)rt!!B.G!2oGgrrE*!!b_T'rr3.L!9qi1ZGQVA!;leH~> r;Q`s_uKW7$]O?Ms0>?!N;rnX!<3#u!<<*!!<<'5Z;"'!s8UG?B^#Ksrr<'!!!*$!!<)rr!#'&! s8N'!s6uHW!.=&2ciAIn!!*#urr=>E!!(A?I/hPfB^#Kss3Lanrr<'!s0>?nZN'q)!<<'!!<3$! rVult!lk;"o)J^is8W*!rVm#bMuWj`_>aK8qu;0~> r;Q`s_uKW7$]O?Ms0>?!N;rnX!<3#u!<<*!!<<'5Z;"'!s8UG?B^#Ksrr<'!!!*$!!<)rr!#'&! s8N'!s6uHW!.=&2ciAIn!!*#urr=>E!!(A?I/hPfB^#Kss3Lanrr<'!s0>?nZN'q)!<<'!!<3$! rVult!lk;"o)J^is8W*!rVm#bMuWj`_>aK8qu;0~> r;Q`s_uKW7$]O?Ms0>?!N;rnX!<3#u!<<*!!<<'5Z;"'!s8UG?B^#Ksrr<'!!!*$!!<)rr!#'&! s8N'!s6uHW!.=&2ciAIn!!*#urr=>E!!(A?I/hPfB^#Kss3Lanrr<'!s0>?nZN'q)!<<'!!<3$! rVult!lk;"o)J^is8W*!rVm#bMuWj`_>aK8qu;0~> r;Q`sJcF$q!U4:rs8N(lrr<&rs*t~> r;Q`sJcF$q!U4:rs8N(lrr<&rs*t~> r;Q`sJcF$q!U4:rs8N(lrr<&rs*t~> r;Q`sJcF$q!K?"9s8N(lrr<&rs*t~> r;Q`sJcF$q!K?"9s8N(lrr<&rs*t~> r;Q`sJcF$q!K?"9s8N(lrr<&rs*t~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sp&G!krr;rtJcC<$qYpNqqu;0~> r;Q`sp&G!krr;rtJcC<$qYpNqqu;0~> r;Q`sp&G!krr;rtJcC<$qYpNqqu;0~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!%TMJcGWI!!)orJ,~> r;Q`sp&Fsj!WN0!rr<&rs8)eIJ<,6Vrr<&rs*t~> r;Q`sp&Fsj!WN0!rr<&rs8)eIJ<,6Vrr<&rs*t~> r;Q`sp&Fsj!WN0!rr<&rs8)eIJ<,6Vrr<&rs*t~> r;Q`so)AakrrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`sp&G!ks8N'!rr2ruq#: r;Q`sp&G!ks8N'!rr2ruq#: r;Q`sp&G!ks8N'!rr2ruq#: r;Q`spAY*mrr3$"rrE&u!!)orqZ)2_OMCjHq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)2_OMCjHq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)2_OMCjHq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNkbXFq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\[;]!.anF!!)orJ,~> r;Q`sir8uYJ\\P+pAjEm!.anF!!)orJ,~> r;Q`sir8uYJ\\P+pAjEm!.anF!!)orJ,~> r;Q`sir8uYJ\\P+pAjEm!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;ZWp!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;ZWp!9h2uJGK3F!;leH~> r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruqu?NnJ\\V-!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruqu?NnJ\\V-!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruqu?NnJ\\V-!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lr;Z`rp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&>!lr;Z`rp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&>!lr;Z`rp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAb'ks8N'!rr2ruq#: r;Q`spAb'ks8N'!rr2ruq#: r;Q`spAb'ks8N'!rr2ruq#: r;Q`spAY*mrr3$"rrE&u!!)orqZ)2_ZbQP@q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)2_ZbQP@q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)orqZ)2_ZbQP@q>UEpkeI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&Fsjs8W&up\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&Fsjs8W&up\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&Fsjs8W&up\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAY*mr;Q`srr2ruq#: r;Q`spAb'ks8N'!rr2ruqu?NnJ\\V-!!)h_!!)5u!.anF!!)orJ,~> r;Q`spAb'ks8N'!rr2ruqu?NnJ\\V-!!)h_!!)5u!.anF!!)orJ,~> r;Q`spAb'ks8N'!rr2ruqu?NnJ\\V-!!)ip!!)5u!.anF!!)orJ,~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`sp&>0qrrE*!!<2uu!;QQo!.hqj^]4B1R/d6N^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!.hqj^]4B1R/d6N^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!.hqj^]4B1rr<&_^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!.hqj^]4B1R/d6N^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!.hqj^]4B1R/d6N^]8o\rr<&rs*t~> r;Q`sp&>0qrrE*!!<2uu!;QQo!.hqj^]4B1rr<&_^]8o\rr<&rs*t~> r;Q`spAYUEpqu;0~> r;Q`spAYUEpqu;0~> r;Q`spAYUEpkeI1Kq>UEpqu;0~> r;Q`spAb$j!WN0!rr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<%M^p1ZT!;ZWp!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^p1ZT!;ZWp!9h2uJGK3F!;leH~> r;Q`soD\djrr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`so`+pks8N'!rr2ruq#: r;Q`so)AakrrE&u!!)orqZ)2_ZbQP@q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ)2_ZbQP@q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ)2_ZbQP@q>UEpkeI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScZ+p>>q>UEpkeI1Kq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYJ\\P+!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4r+.J\]"8!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4r+.J\]"8!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4r+.J\]"8!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!)r4!!)lq!!%Sc^VBgLq>UEpkeI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)r4!!)lq!!%Sc^VBgLq>UEpkeI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!)r4!!)lq!!%Sc^VBgLq>UEpkeI1Kq>UEpqu;0~> r;Q`soD\mms8N)urr<&rs8)fq^]4B2R/d5<^q[Yb!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&rs8)fq^]4B2R/d5<^q[Yb!;W#_!9h2uJGK3F!;leH~> r;Q`soD\mms8N)urr<&rs8)fq^]4B2rr<%M^q[Yb!;ZWp!9h2uJGK3F!;leH~> r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`sp&>!lrVlitrr2ruq#: r;Q`spAb$js8W&up\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3nr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`so`"mkrVuisp\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrVuisp\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrVuisp\t3nr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sp&G$lrr2rurr2ruq#: r;Q`sp&G$lrr2rurr2ruq#: r;Q`sp&G$lrr2rurr2ruq#: r;Q`spAY0orrE&u!!*#u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`spAY0orrE&u!!*#u!!)fo!!)r4!!)k`!!%Sc^VBgLq3_3_keI1Kq>UEpqu;0~> r;Q`spAY0orrE&u!!*#u!!)fo!!)r4!!)lq!!%Sc^VBgLq>UEpkeI1Kq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruqu?NnrkJL6qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruqu?NnrkJL6qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruqu?NnrkJL6qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrr2rurr2ruq#: r;Q`so`"mkrVuisp\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrVuisp\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`so`"mkrVuisp\t3nr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sir8uYr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`sn,N@ep\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sn,N@ep\t3nr4i:4qO%<`J\]%9!!)h_!!)5u!.anF!!)orJ,~> r;Q`sn,N@ep\t3nr4i:4qYpNqJ\]%9!!)ip!!)5u!.anF!!)orJ,~> r;Q`snG`Igrr2ruq#: r;Q`snG`Igrr2ruq#: r;Q`snG`Igrr2ruq#: r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpr4i:4m_Af&q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpr4i:4m_Af&q>UEpqu;0~> r;Q`snG`Igrr2ruqu;3IM#dAO!!)orJ,~> r;Q`snG`Igrr2ruqu;3IM#dAO!!)orJ,~> r;Q`snG`Igrr2ruqu;3IM#dAO!!)orJ,~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`sn,N@ep\t3nmf*7emJd.dmf*7emJd.dmf*7emf*7emf*7emf*7emJd.dmf*7emJd.dmf*7e q>UEpqu;0~> r;Q`sn,N@ep\t3nmf*7emJd.dmf*7emJd.dmf*7emf*7emf*7emf*7emJd.dmf*7emJd.dmf*7e q>UEpqu;0~> r;Q`sn,N@ep\t3nmf*7emJd.dmf*7emJd.dmf*7emf*7emf*7emf*7emJd.dmf*7emJd.dmf*7e q>UEpqu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`s])Vd1gA_-QgAh0QgAh0QW;chtqu;0~> r;Q`s])Vd1gA_-QgAh0QgAh0QW;chtqu;0~> r;Q`s])Vd1gA_-QgAh0QgAh0QW;chtqu;0~> r;Q`sjT#5[gA_6Ts8N)Rs8N)SrrW9$rrCjS!s&B$!8RSS!71ZF!;leH~> r;Q`sjT#5[gA_6Ts8N)Rs8N)SrrW9$rrCjS!s&B$!8RSS!71ZF!;leH~> r;Q`sjT#5[gA_6Ts8N)Rs8N)SrrW9$rrCjS!s&B$!8RSS!71ZF!;leH~> r;Q`sjo5G`s8N'!h#@?Srr2ruh#@EUrrCmT"9AK%!!(jT!s&B$!8RSS!71ZF!;leH~> r;Q`sjo5G`s8N'!h#@?Srr2ruh#@EUrrCmT"9AK%!!(jT!s&B$!8RSS!71ZF!;leH~> r;Q`sjo5G`s8N'!h#@?Srr2ruh#@EUrrCmT"9AK%!!(jT!s&B$!8RSS!71ZF!;leH~> r;Q`sjo5;\rr;uuh>[HTrr2ruh#@EUs8W&ui;Wu]rrE*!!!(pV!W`9#r;baTrrCFG!!)orJ,~> r;Q`sjo5;\rr;uuh>[HTrr2ruh#@EUs8W&ui;Wu]rrE*!!!(pV!W`9#r;baTrrCFG!!)orJ,~> r;Q`sjo5;\rr;uuh>[HTrr2ruh#@EUs8W&ui;Wu]rrE*!!!(pV!W`9#r;baTrrCFG!!)orJ,~> r;Q`sjo5;\rVlith>[HTrr3'#s8N)Vrr`?%rr<&Vs8E#trr<&Us8N)urr<&VrrN3#!7CfH!;leH~> r;Q`sjo5;\rVlith>[HTrr3'#s8N)Vrr`?%rr<&Vs8E#trr<&Us8N)urr<&VrrN3#!7CfH!;leH~> r;Q`sjo5;\rVlith>[HTrr3'#s8N)Vrr`?%rr<&Vs8E#trr<&Us8N)urr<&VrrN3#!7CfH!;leH~> r;Q`sjo>>\rVlitgA_6Trr<&Us8E!!rrCsVrrE&u!!(jT!!*#u!!(gS!!(II!!)orJ,~> r;Q`sjo>>\rVlitgA_6Trr<&Us8E!!rrCsVrrE&u!!(jT!!*#u!!(gS!!(II!!)orJ,~> r;Q`sjo>>\rVlitgA_6Trr<&Us8E!!rrCsVrrE&u!!(jT!!*#u!!(gS!!(II!!)orJ,~> r;Q`sjT#5[rr2rug]%?Urr<&Ts8N)Rs8N'#rr<&Ts8N*!rr<&Rrr<&Jrr<&rs*t~> r;Q`sjT#5[rr2rug]%?Urr<&Ts8N)Rs8N'#rr<&Ts8N*!rr<&Rrr<&Jrr<&rs*t~> r;Q`sjT#5[rr2rug]%?Urr<&Ts8N)Rs8N'#rr<&Ts8N*!rr<&Rrr<&Jrr<&rs*t~> r;Q`sj8],Z!ri6#jT#5[q>^HpjT#5[qu6WriW&oXqYpNqirB#Yqu?Wqg&D$PeGfLKqu;0~> r;Q`sj8],Z!ri6#jT#5[q>^HpjT#5[qu6WriW&oXqYpNqirB#Yqu?Wqg&D$PeGfLKqu;0~> r;Q`sj8],Z!ri6#jT#5[q>^HpjT#5[qu6WriW&oXqYpNqirB#Yqu?Wqg&D$PeGfLKqu;0~> r;Q`siVrlXj8T5^s8N'!qu6WrjSo>_s8N'!h>[TXs8N'!h>[TXs8N'!V#LDpqu;0~> r;Q`siVrlXj8T5^s8N'!qu6WrjSo>_s8N'!h>[TXs8N'!h>[TXs8N'!V#LDpqu;0~> r;Q`siVrlXj8T5^s8N'!qu6WrjSo>_s8N'!h>[TXs8N'!h>[TXs8N'!V#LDpqu;0~> r;Q`s_Z'T9rr;uurr;uuj8T)Zrr;uus8W*!ir8uYrr;uus8W*!ir8uYrr;uus8W*!WW)ququ;0~> r;Q`s_Z'T9rr;uurr;uuj8T)Zrr;uus8W*!ir8uYrr;uus8W*!ir8uYrr;uus8W*!WW)ququ;0~> r;Q`s_Z'T9rr;uurr;uuj8T)Zrr;uus8W*!ir8uYrr;uus8W*!ir8uYrr;uus8W*!WW)ququ;0~> r;Q`s_Z'T9rVlithZ!QUrVlithZ!QUrVlithZ!QUrVlitV>gMqqu;0~> r;Q`s_Z'T9rVlithZ!QUrVlithZ!QUrVlithZ!QUrVlitV>gMqqu;0~> r;Q`s_Z'T9rVlithZ!QUrVlithZ!QUrVlithZ!QUrVlitV>gMqqu;0~> r;Q`s_Z0W9rVlithuE]VrVlithuE]VrVlithuE]VrVlitVZ-Vrqu;0~> r;Q`s_Z0W9rVlithuE]VrVlithuE]VrVlithuE]VrVlitVZ-Vrqu;0~> r;Q`s_Z0W9rVlithuE]VrVlithuE]VrVlithuE]VrVlitVZ-Vrqu;0~> r;Q`s_>jN8rr2ruhZ*TUrr2ruhZ*TUrr2ruhZ*TUrr2ruVZ-Vrqu;0~> r;Q`s_>jN8rr2ruhZ*TUrr2ruhZ*TUrr2ruhZ*TUrr2ruVZ-Vrqu;0~> r;Q`s_>jN8rr2ruhZ*TUrr2ruhZ*TUrr2ruhZ*TUrr2ruVZ-Vrqu;0~> r;Q`s_#OE7!ri6#h>dKT!ri6#h>dKT!ri6#h>dKT!ri6#VZ-Vrqu;0~> r;Q`s_#OE7!ri6#h>dKT!ri6#h>dKT!ri6#h>dKT!ri6#VZ-Vrqu;0~> r;Q`s_#OE7!ri6#h>dKT!ri6#h>dKT!ri6#h>dKT!ri6#VZ-Vrqu;0~> r;Q`s^Ae05g&D$Pg&D$Pg&D$PV#LDpqu;0~> r;Q`s^Ae05g&D$Pg&D$Pg&D$PV#LDpqu;0~> r;Q`s^Ae05g&D$Pg&D$Pg&D$PV#LDpqu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;Q`sJcC<$jo5;\qu;0~> r;V r;V r;V JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> JcC<$f`-I~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/arcsine-fig.ps0000644000175000000620000000606711466723256017734 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: arcsine-fig.ps %%CreationDate: Wed Jul 13 12:12:47 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2413 ASCII Bytes image h>[NUO5Ks[!rq_]j8T2[s8N0#hiHgt!ri6"!rq/Mj8T2[s8N0#hk/s/!ri6"s8N(kj8T2[ s8W-!!2&CrJ,fQKrrKmljo5>[rr<#u!PdORrrE#ss8W*"^Ye/Q!<)oss8N,7n)aQLrVlis rrJbdjo5>Xrr<#u!PeBjrrDrqs8W*"^\d-m!;HKms8N,7rT4%Zn,E@errJbkjo5>1F* J*?n4ci*kIs51Tks.AQU!WG=^rrrG[^]4>ol2LbZr;Qs#hiIg;r9=4]a8Gr=s51Tjrr=/,rrN$^ r;Qiu#J^94-2rrBh2rrKn9oD\m]!'g;Zs8N)6qYpWr!'g2W!It^Ts8W*!^\Ig/_#495s82isJ+ipBrrA\_ s8N)gs8W*!^Yo.lrrBgls8W*!^Yo.lrrBgls8W*!TA]bLrrBgls8W*!^Yo.lrrBgls8W*!^Yo.l rrA\Ls8W*!^Yo.lrrBh3rrDfkrrE&qrrCsSrrDrnrrIWLs8O7WrVtdSs7cQ.qu>RQs7cPCqu>RQ s6ou;qu>RPs6ou;rrN/Xi;`lZs8W*!^Yo.lrrBgls8W*!^Yo.lrrBgls5!_OrrN#rr;QeIn,<7e n+lq^!r`.KrVlrss8Vrq!qlMArr3'!^X)lY!S@)ErrW&r^]"06rr<#prrMflrVlru^T[V9!S?rA rrW&sJ,TBKrr<#prrMflrVlru^PDdf!S@#CrrW&r^]"06rr<#prrMfkrVlru^[M.$!S@#CrrW&r ^]"06rr<#prrW)QJ,TBJHcQ*b!Uk+.rrW/fJ,TBKpcnf7s*t~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/warpfig.ps0000644000175000000620000002245211466723256017200 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 31 334 444 752 %%Title: (warpfig-Layer#1) %%Creator: (MacDraw II 1.1v2: LaserWriter 8 8.1.1) %%CreationDate: (10:26 PM Sunday, January 24, 1904) %%For: (Dannenberg) %%Pages: 1 %%DocumentFonts: Helvetica %%DocumentNeededFonts: Helvetica %%DocumentSuppliedFonts: %%DocumentData: Clean7Bit %%PageOrder: Ascend %%Orientation: Portrait %ADO_PaperArea: -129 -125 3171 2425 %ADO_ImageableArea: 0 0 3042 2300 %%EndComments /md 153 dict def md begin /currentpacking where {pop /sc_oldpacking currentpacking def true setpacking}if %%BeginFile: adobe_psp_basic %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /bd{bind def}bind def /xdf{exch def}bd /xs{exch store}bd /ld{load def}bd /Z{0 def}bd /T/true /F/false /:L/lineto /lw/setlinewidth /:M/moveto /rl/rlineto /rm/rmoveto /:C/curveto /:T/translate /:K/closepath /:mf/makefont /gS/gsave /gR/grestore /np/newpath 14{ld}repeat /$m matrix def /av 81 def /por true def /normland false def /psb-nosave{}bd /pse-nosave{}bd /us Z /psb{/us save store}bd /pse{us restore}bd /level2 /languagelevel where { pop languagelevel 2 ge }{ false }ifelse def /featurecleanup { stopped cleartomark countdictstack exch sub dup 0 gt { {end}repeat }{ pop }ifelse }bd /noload Z /startnoload { {/noload save store}if }bd /endnoload { {noload restore}if }bd level2 startnoload /setjob { statusdict/jobname 3 -1 roll put }bd /setcopies { userdict/#copies 3 -1 roll put }bd level2 endnoload level2 not startnoload /setjob { 1 dict begin/JobName xdf currentdict end setuserparams }bd /setcopies { 1 dict begin/NumCopies xdf currentdict end setpagedevice }bd level2 not endnoload /pm Z /mT Z /sD Z /realshowpage Z /initializepage { /pm save store mT concat }bd /endp { pm restore showpage }def /$c/DeviceRGB def /rectclip where { pop/rC/rectclip ld }{ /rC { np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K clip np }bd }ifelse /rectfill where { pop/rF/rectfill ld }{ /rF { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl fill gR }bd }ifelse /rectstroke where { pop/rS/rectstroke ld }{ /rS { gS np 4 2 roll :M 1 index 0 rl 0 exch rl neg 0 rl :K stroke gR }bd }ifelse %%EndFile %%BeginFile: adobe_psp_colorspace_level1 %%Copyright: Copyright 1991-1993 Adobe Systems Incorporated. All Rights Reserved. /G/setgray ld /:F/setrgbcolor ld %%EndFile %%BeginFile: adobe_psp_uniform_graphics %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /@a { np :M 0 rl :L 0 exch rl 0 rl :L fill }bd /@b { np :M 0 rl 0 exch rl :L 0 rl 0 exch rl fill }bd /arct where { pop }{ /arct { arcto pop pop pop pop }bd }ifelse /x1 Z /x2 Z /y1 Z /y2 Z /rad Z /@q { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct fill }bd /@s { /rad xs /y2 xs /x2 xs /y1 xs /x1 xs np x2 x1 add 2 div y1 :M x2 y1 x2 y2 rad arct x2 y2 x1 y2 rad arct x1 y2 x1 y1 rad arct x1 y1 x2 y1 rad arct :K stroke }bd /@i { np 0 360 arc fill }bd /@j { gS np :T scale 0 0 .5 0 360 arc fill gR }bd /@e { np 0 360 arc :K stroke }bd /@f { np $m currentmatrix pop :T scale 0 0 .5 0 360 arc :K $m setmatrix stroke }bd /@k { gS np :T 0 0 :M 0 0 5 2 roll arc fill gR }bd /@l { gS np :T 0 0 :M scale 0 0 .5 5 -2 roll arc fill gR }bd /@m { np arc stroke }bd /@n { np $m currentmatrix pop :T scale 0 0 .5 5 -2 roll arc $m setmatrix stroke }bd %%EndFile %%BeginFile: adobe_psp_customps %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /$t Z /$p Z /$s Z /$o 1. def /2state? false def /ps Z level2 startnoload /pushcolor/currentrgbcolor ld /popcolor/setrgbcolor ld /setcmykcolor where { pop/currentcmykcolor where { pop/pushcolor/currentcmykcolor ld /popcolor/setcmykcolor ld }if }if level2 endnoload level2 not startnoload /pushcolor { currentcolorspace $c eq { currentcolor currentcolorspace true }{ currentcmykcolor false }ifelse }bd /popcolor { { setcolorspace setcolor }{ setcmykcolor }ifelse }bd level2 not endnoload /pushstatic { ps 2state? $o $t $p $s }bd /popstatic { /$s xs /$p xs /$t xs /$o xs /2state? xs /ps xs }bd /pushgstate { save errordict/nocurrentpoint{pop 0 0}put currentpoint 3 -1 roll restore pushcolor currentlinewidth currentlinecap currentlinejoin currentdash exch aload length np clippath pathbbox $m currentmatrix aload pop }bd /popgstate { $m astore setmatrix 2 index sub exch 3 index sub exch rC array astore exch setdash setlinejoin setlinecap lw popcolor np :M }bd /bu { pushgstate gR pushgstate 2state? { gR pushgstate }if pushstatic pm restore mT concat }bd /bn { /pm save store popstatic popgstate gS popgstate 2state? { gS popgstate }if }bd /cpat{pop 64 div G 8{pop}repeat}bd %%EndFile %%BeginFile: adobe_psp_basic_text %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /S/show ld /A{ 0.0 exch ashow }bd /R{ 0.0 exch 32 exch widthshow }bd /W{ 0.0 3 1 roll widthshow }bd /J{ 0.0 32 4 2 roll 0.0 exch awidthshow }bd /V{ 0.0 4 1 roll 0.0 exch awidthshow }bd /fcflg true def /fc{ fcflg{ vmstatus exch sub 50000 lt{ (%%[ Warning: Running out of memory ]%%\r)print flush/fcflg false store }if pop }if }bd /$f[1 0 0 -1 0 0]def /:ff{$f :mf}bd /MacEncoding StandardEncoding 256 array copy def MacEncoding 39/quotesingle put MacEncoding 96/grave put /Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute /agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave /ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute /ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls /registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash /infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation /product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft /guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe /endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge /ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl /daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand /Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave /Oacute/Ocircumflex/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde /macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron MacEncoding 128 128 getinterval astore pop level2 startnoload /copyfontdict { findfont dup length dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall }bd level2 endnoload level2 not startnoload /copyfontdict { findfont dup length dict copy begin }bd level2 not endnoload md/fontname known not{ /fontname/customfont def }if /Encoding Z /:mre { copyfontdict /Encoding MacEncoding def fontname currentdict end definefont :ff def }bd /:bsr { copyfontdict /Encoding Encoding 256 array copy def Encoding dup }bd /pd{put dup}bd /:esr { pop pop fontname currentdict end definefont :ff def }bd /scf { scalefont def }bd /scf-non { $m scale :mf setfont }bd /ps Z /fz{/ps xs}bd /sf/setfont ld /cF/currentfont ld /mbf { /makeblendedfont where { pop makeblendedfont /ABlend exch definefont }{ pop }ifelse def }def %%EndFile %%BeginFile: adobe_psp_dashes %%Copyright: Copyright 1990-1993 Adobe Systems Incorporated. All Rights Reserved. /:q/setdash ld /:r{ np :M :L stroke }bd /nodash[]def /qdenddash { nodash 0 setdash }bd %%EndFile /currentpacking where {pop sc_oldpacking setpacking}if end % md %%EndProlog %%BeginSetup md begin /pT[1 0 0 -1 29.999 761.009]def/mT[.24 0 0 -.24 29.999 761.009]def /sD 16 dict def %%IncludeFont: Helvetica /f0_1/Helvetica :mre /f1_1 f0_1 1.04 scf /f1_58 f1_1 58 scf /Courier findfont[10 0 0 -10 0 0]:mf setfont %%EndSetup %%Page: 1 1 %%BeginPageSetup initializepage %%EndPageSetup gS 0 0 2300 3042 rC 0 0 :M 0 setlinecap currentscreen 3 1 roll pop pop 60 45 3 -1 roll setscreen np 113 38 :M 127 96 :L 113 96 :L 98 96 :L 113 38 :L eofill -4 -4 115 1652 4 4 111 94 @b np 1725 1650 :M 1666 1665 :L 1666 1650 :L 1666 1635 :L 1725 1650 :L 4 lw eofill 111 1652 -4 4 1668 1648 4 111 1648 @a 111 1648 :M 2 setlinecap 8 lw 113 1650 :M 237.663 1449.978 300 1350 300 1350 :C 300 1350 362.492 1324.981 487.5 1275 :C 612.494 1224.98 675 1200 675 1200 :C 675 1200 706.321 1149.985 769 1050 :C 831.655 949.983 863 900 863 900 :C 863 900 987.979 774.994 1238 525 :C 1487.983 274.99 1613 150 1613 150 :C 1613 150 1613 399.982 1613 900 :C 1613 1399.99 1613 1650 1613 1650 :C stroke 1613 1650 :M 0 setlinecap -4 -4 302 1690 4 4 298 1648 @b -4 -4 490 1690 4 4 486 1648 @b -4 -4 677 1690 4 4 673 1648 @b -4 -4 865 1690 4 4 861 1648 @b -4 -4 1052 1690 4 4 1048 1648 @b -4 -4 1240 1690 4 4 1236 1648 @b -4 -4 1427 1690 4 4 1423 1648 @b -4 -4 1615 1690 4 4 1611 1648 @b -4 -4 115 1690 4 4 111 1648 @b 93 1754 :M f1_58 sf (0)S 280 1754 :M (1)S 468 1754 :M (2)S 655 1754 :M (3)S 843 1754 :M (4)S 1030 1754 :M (5)S 1218 1754 :M (6)S 1405 1754 :M (7)S 1593 1754 :M (8)S 73 152 -4 4 115 148 4 73 148 @a 73 340 -4 4 115 336 4 73 336 @a 73 527 -4 4 115 523 4 73 523 @a 73 715 -4 4 115 711 4 73 711 @a 73 902 -4 4 115 898 4 73 898 @a 73 1090 -4 4 115 1086 4 73 1086 @a 73 1277 -4 4 115 1273 4 73 1273 @a 73 1465 -4 4 115 1461 4 73 1461 @a 73 1652 -4 4 115 1648 4 73 1648 @a 18 1679 :M (0)S 18 1491 :M (1)S 18 1304 :M (2)S 18 1116 :M (3)S 18 929 :M (4)S 18 741 :M (5)S 18 554 :M (6)S 18 366 :M (7)S 18 179 :M (8)S 4 lw [16.667 12.5 ] 0 :q 863 900 113 900 :r 863 1650 863 900 :r endp %%Trailer end % md %%EOF nyquist-3.05/docsrc/nyquist/test.ps0000644000175000000620000010236311466723256016520 0ustar stevestaff%!PS-Adobe-2.0 %%Title: test.mss %%DocumentFonts: (atend) %%Creator: Roger Dannenberg and Scribe 7(1700) %%CreationDate: 18 December 1996 16:16 %%Pages: (atend) %%EndComments % PostScript Prelude for Scribe. /BS {/SV save def 0.0 792.0 translate .01 -.01 scale} bind def /ES {showpage SV restore} bind def /SC {setrgbcolor} bind def /FMTX matrix def /RDF {WFT SLT 0.0 eq {SSZ 0.0 0.0 SSZ neg 0.0 0.0 FMTX astore} {SSZ 0.0 SLT neg sin SLT cos div SSZ mul SSZ neg 0.0 0.0 FMTX astore} ifelse makefont setfont} bind def /SLT 0.0 def /SI { /SLT exch cvr def RDF} bind def /WFT /Courier findfont def /SF { /WFT exch findfont def RDF} bind def /SSZ 1000.0 def /SS { /SSZ exch 100.0 mul def RDF} bind def /AF { /WFT exch findfont def /SSZ exch 100.0 mul def RDF} bind def /MT /moveto load def /XM {currentpoint exch pop moveto} bind def /UL {gsave newpath moveto dup 2.0 div 0.0 exch rmoveto setlinewidth 0.0 rlineto stroke grestore} bind def /LH {gsave newpath moveto setlinewidth 0.0 rlineto gsave stroke grestore} bind def /LV {gsave newpath moveto setlinewidth 0.0 exch rlineto gsave stroke grestore} bind def /BX {gsave newpath moveto setlinewidth exch dup 0.0 rlineto exch 0.0 exch neg rlineto neg 0.0 rlineto closepath gsave stroke grestore} bind def /BX1 {grestore} bind def /BX2 {setlinewidth 1 setgray stroke grestore} bind def /PB {/PV save def newpath 3 -1 roll sub translate 100.0 -100.0 scale /showpage {} def} bind def /PE {PV restore} bind def /GB {/PV save def newpath translate rotate div dup scale 100.0 -100.0 scale /showpage {} def /letter {} def /lettersmall {} def /note {} def } bind def /GE {PV restore} bind def /FB {dict dup /FontMapDict exch def begin} bind def /FM {cvn exch cvn exch def} bind def /FE {end /original-findfont /findfont load def /findfont {dup FontMapDict exch known{FontMapDict exch get} if original-findfont} def} bind def /BC {gsave moveto dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath clip} bind def /EC /grestore load def /SH /show load def /MX {exch show 0.0 rmoveto} bind def /W {0 32 4 -1 roll widthshow} bind def /WX {0 32 5 -1 roll widthshow 0.0 rmoveto} bind def /RC {100.0 -100.0 scale 612.0 0.0 translate -90.0 rotate .01 -.01 scale} bind def /URC {100.0 -100.0 scale 90.0 rotate -612.0 0.0 translate .01 -.01 scale} bind def /RCC {100.0 -100.0 scale 0.0 -792.0 translate 90.0 rotate .01 -.01 scale} bind def /URCC {100.0 -100.0 scale -90.0 rotate 0.0 792.0 translate .01 -.01 scale} bind def % Scribe Systems version of LaserPrep v5.2 % All lines added/changed by Scribe Systems contain "%UNI" % %{appledict version #65 % CopyRight Apple Computer, Inc. 1984,1985,1986,1987 All Rights Reserved. systemdict/currentpacking known{currentpacking true setpacking}if /LW{save statusdict/product get(LaserWriter)anchorsearch exch pop{length 0 eq{1}{2}ifelse}{0}ifelse exch restore}bind def /LW+{LW 2 eq}bind def /ok{systemdict/statusdict known dup{LW 0 gt and}if}bind def %UNI ok{statusdict begin 9 sccinteractive 3 ne exch 0 ne or{9 0 3 setsccinteractive}if end}if /md 250 dict def md begin /av 65 def /T true def /F false def /mtx matrix def /s75 75 string def /s8 8 string def /s1 ( ) def /pxs 1 def /pys 1 def 1 0 mtx defaultmatrix dtransform exch atan/pa exch def /nlw .24 def /ppr [-32 -29.52 762 582.48] def % default printable page rectangle /pgs 1 def /por true def /xb 500 array def /so true def /fillflag false def /pnm 1 def /fmv true def /sfl false def /ma 0 def /invertflag false def /xflip false def /yflip false def /noflips true def /scaleby96 false def /fNote true def /fBitStretch true def /fg (Rvd\001\001\000\000\177) def /bdf{bind def}bind def /xdf{exch def}bdf /xl{neg exch neg translate}bdf /fp{pnsh 0 ne pnsv 0 ne and}bdf /nop{}bdf/lnop[/nop load]cvx bdf /vrb[ {fp{gsave 1 setlinewidth pnsh pnsv scale stroke grestore}if newpath}bind /eofill load dup /newpath load 2 index dup {clip newpath}bind {}bind dup 2 copy ]def currentscreen/spf xdf/rot xdf/freq xdf /doop{vrb exch get exec}bdf % psu - page setup called at begining of page % args: smooth, por, bbs1, bbs2, bbey, bbex, scale, dpix, dpiy, pgs, % invert, xflip, yflip, scaleby96, fBitStretch, fNote % % smooth is T if smoothing was selected in page setup, else F % por is T for portrait orientation, F for landscape % bbs2 seems to be offset for start of image area (in 72nds of an inch) % bbs1 seems to be offset for start of image area (in 72nds of an inch) % bbey is length (or end?) of printable area in 72nd of an inch % bbex is width (or end?) of printable area in 72nd of an inch % dpix is dots per inch of coordinate system % dpiy is dots per inch of coordinate system % scale is scale factor selected in page setup % pgs is a small integer denoting paper cassette type (legal, a4, etc.) % invert is T to reverse black/white % xflip is T to rotate image horizontally % yflip is T to rotate image vertically % scaleby96 is T if "Precision Bitmap Graphics" requested % fBitStretch is T if "Faster Bitmap Printing" requested % fNote is T to use small imageable region, F to use large /psu{ pop /fNote xdf /fBitStretch xdf /scaleby96 xdf pop F %UNI force yflip off /yflip xdf pop F %UNI force xflip off /xflip xdf pop F %UNI force black/white reversing off /invertflag xdf xflip yflip or{/noflips false def}if /pgs xdf % set pgs 2 index % get copy of scale .72 mul exch div /pys xdf % pys = (.72 * scale) / dpiy % S: smooth por bbs1 bbs2 bbey bbex scale dpix div .72 mul /pxs xdf % pxs = .72 * (scale / dpix) 2 index pxs mul 4 index pys mul neg translate %UNI xlate for scribe ppr astore pop % put "bbs1 bbs2 bbey bbex" into ppr pop T %UNI force portrait on /por xdf % set por pop F %UNI force smooth request off sn and /so xdf % set "so" T if smooth req'd AND avail in LW }bdf /txpose{ %UNI don't change paper type %UNI fNote{smalls}{bigs}ifelse pgs get exec pxs pys scale ppr aload pop por { noflips{pop exch neg exch translate pop 1 -1 scale}if xflip yflip and{ pop exch neg exch translate 180 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate }if xflip yflip not and{ pop exch neg exch translate pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 translate }if yflip xflip not and{ ppr 1 get neg ppr 0 get neg translate }if } { noflips{translate pop pop 270 rotate 1 -1 scale}if xflip yflip and{ translate pop pop 90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate }if xflip yflip not and{ translate pop pop 90 rotate ppr 3 get ppr 1 get neg sub neg 0 translate }if yflip xflip not and{ translate pop pop 270 rotate ppr 2 get ppr 0 get neg sub neg 0 exch translate }if } ifelse %UNI statusdict begin waittimeout 300 lt{/waittimeout 300 def}if end scaleby96{ ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy translate .96 dup scale neg exch neg exch translate }if }bdf /fr{3 index 3 index xl ppr aload pop 3 -1 roll 2 mul add 3 1 roll exch 2 mul add 6 2 roll 3 -1 roll sub 3 1 roll exch sub 3 1 roll exch 3 -1 roll div 3 1 roll div exch scale}bdf /lws{show}bdf /tv{show pop pop}bdf /obl{{0.212557 mul}{pop 0}ifelse}bdf /sfd{ps fg 5 -1 roll get mul 100 div 0 ps 5 -1 roll obl ps neg 0 0 6a astore makefont setfont}bdf /fnt{findfont sfd}bdf /bt{sa 3 1 roll 3 index and put}bdf /sa(\000\000\000\000\000\000\000\000\000\000)def /fs{0 1 bt 1 2 bt 2 4 bt 3 8 bt 4 16 bt 5 32 bt 6 64 bt 7 128 bt sa exch 8 exch put}bdf /mx1 matrix def /mx2 matrix def /mx3 matrix def /bu{currentpoint currentgray currentlinewidth currentlinecap currentlinejoin currentdash exch aload length fg 5 sfl{1}{0}ifelse put pnsv pnsh 2t aload pop 3a aload pop mx2 aload pop mx1 aload pop mtx currentmatrix aload pop mx3 aload pop ps pm restore/ps xdf mx3 astore pop}bdf /bn{/pm save def mx3 setmatrix newpath 0 0 moveto ct dup 39 get 0 exch getinterval cvx exec mtx astore setmatrix mx1 astore pop mx2 astore pop 3a astore pop 2t astore pop/pnsh xdf/pnsv xdf gw /sfl fg 5 get 0 ne def array astore exch setdash setlinejoin setlinecap setlinewidth setgray moveto}bdf /fc{save vmstatus exch sub 50000 lt {(%%[|0|]%%)=print flush}if pop restore}bdf /tc{32768 div add 3 1 roll 32768 div add 2t astore pop}bdf /3a [0 0 0] def /2t 2 array def /tp{3a astore pop}bdf /tt{mx2 currentmatrix pop currentpoint 2 copy 2t aload pop qa 2 copy translate 3a aload pop exch dup 0 eq {pop}{1 eq{-1 1}{1 -1}ifelse scale}ifelse rotate pop neg exch neg exch translate moveto}bdf /te{mx2 setmatrix}bdf /th{3 -1 roll div 3 1 roll exch div 2 copy mx1 scale pop scale/sfl true def}bdf /tu{1 1 mx1 itransform scale/sfl false def}bdf /ts{1 1 mx1 transform scale/sfl true def}bdf /fz{/ps xdf}bdf /dv{dup 0 ne{div}{pop}ifelse}bdf /pop4{pop pop pop pop}bdf /it{sfl{mx1 itransform}if}bdf /gm{exch it moveto}bdf/rm{it rmoveto}bdf /lm{currentpoint sfl{mx1 transform}if exch pop sub 0 exch it rmoveto}bdf /fm{statusdict/manualfeed known}bdf /se{statusdict exch/manualfeed exch put}bdf /mf{ pop %UNI never allow manual feed %UNI dup/ma exch def 0 gt{fm se/t1 5 st ok ma 1 gt and{/t2 0 st/t3 0 st statusdict/manualfeedtimeout 3600 put}if}if }bdf /jn{ pop %UNI don't set job name %UNI /statusdict where exch pop{statusdict exch/jobname exch put}if }bdf /pen{pnm mul/pnsh xdf pnm mul/pnsv xdf pnsh setlinewidth}bdf /min{2 copy gt{exch}if pop}bdf /max{2 copy lt{exch}if pop}bdf /dh{fg 6 1 put array astore exch pop exch pop exch setdash}bdf /ih[currentdash]def /rh{fg 6 0 put ih aload pop setdash}bdf /dl{gsave nlw pys div setlinewidth 0 setgray}bdf /dlin{exch currentpoint currentlinewidth 2 div dup translate newpath moveto lineto currentpoint stroke grestore moveto}bdf /lin{fg 6 get 0 ne{exch lineto currentpoint 0 doop moveto} {exch currentpoint/pnlv xdf/pnlh xdf gsave newpath/@1 xdf/@2 xdf fp{pnlh @2 lt{pnlv @1 ge {pnlh pnlv moveto @2 @1 lineto pnsh 0 rlineto 0 pnsv rlineto pnlh pnsh add pnlv pnsv add lineto pnsh neg 0 rlineto} {pnlh pnlv moveto pnsh 0 rlineto @2 pnsh add @1 lineto 0 pnsv rlineto pnsh neg 0 rlineto pnlh pnlv pnsv add lineto}ifelse}{pnlv @1 gt {@2 @1 moveto pnsh 0 rlineto pnlh pnsh add pnlv lineto 0 pnsv rlineto pnsh neg 0 rlineto @2 @1 pnsv add lineto}{pnlh pnlv moveto pnsh 0 rlineto 0 pnsv rlineto @2 pnsh add @1 pnsv add lineto pnsh neg 0 rlineto 0 pnsv neg rlineto}ifelse}ifelse closepath fill}if @2 @1 grestore moveto}ifelse}bdf /gw{/pnm fg 3 get fg 4 get div def}bdf /lw{fg exch 4 exch put fg exch 3 exch put gw pnsv pnsh pen}bdf /barc{/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf /@6 xdf/@7 xdf/@8 xdf gsave @5 @7 add 2 div @6 @8 add 2 div translate newpath 0 0 moveto @5 @7 sub @6 @8 sub mtx currentmatrix pop scale @1{newpath}if 0 0 0.5 @4 @3 arc @4 @3 sub abs 360 ge{closepath}if mtx setmatrix @2 doop grestore}bdf /ar{dup 0 eq barc}bdf /ov{0 exch 360 exch true barc}bdf /rc{/@t xdf currentpoint 6 2 roll newpath 4 copy 4 2 roll exch moveto 6 -1 roll lineto lineto lineto closepath @t doop moveto}bdf /mup{dup pnsh 2 div le exch pnsv 2 div le or}bdf /rr{/@1 xdf 2. div/@2 xdf 2. div/@3 xdf /@4 xdf/@5 xdf/@6 xdf/@7 xdf @7 @5 eq @6 @4 eq @2 mup or or{@7 @6 @5 @4 @1 rc} {@4 @6 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse @5 @7 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse @1 0 eq{/@2 @2 pnsh 2 div 2 copy gt{sub def}{0 pop4}ifelse}if currentpoint newpath @4 @6 add 2. div @7 moveto @4 @7 @4 @5 @2 arcto pop4 @4 @5 @6 @5 @2 arcto pop4 @6 @5 @6 @7 @2 arcto pop4 @6 @7 @4 @7 @2 arcto pop4 closepath @1 doop moveto}ifelse}bdf /pr{gsave newpath/pl{exch moveto/pl{exch lineto}def}def}bdf /pl{exch lineto}bdf /ep{dup 0 eq{{moveto}{exch lin}{}{(%%[|1|]%%)= flush}pathforall pop grestore}{doop grestore}ifelse currentpoint newpath moveto}bdf /gr{64. div setgray}bdf /pat{s8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi s8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}setscreen gr}bdf /sg{freq rot/spf load setscreen gr}bdf /dc{transform round .5 sub exch round .5 sub exch itransform}bdf /sn{userdict/smooth4 known}bdf /x8{3 bitshift}bdf /x4{2 bitshift}bdf /d4{-2 bitshift}bdf /d8{-3 bitshift}bdf /rb{15 add -4 bitshift 1 bitshift}bdf /db{/@7 save def/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf/@6 @5 @3 4 add mul def dc translate scale/xdbit 1 1 idtransform abs/ydbit exch def abs def{0 0 1 ydbit add 1 10 rc clip}if @1 0 eq @1 4 eq or{1 setgray ydbit 0 1 ydbit add 1 2 rc}if @1 3 eq @1 7 eq or{1}{0}ifelse setgray/@9 @1 0 eq @1 1 eq @1 3 eq or or invertflag xor def/@13 @6 def @2 fBitStretch or{/@10 @4 x4 def/@11 @3 x4 def/@12 @10 rb def/@13 @12 @11 mul def/@15 1 1 dtransform abs/calcY 1 index def round cvi/@14 exch def abs/calcX 1 index def round cvi scaleby96 not{1 add}if def/@16 @15 rb def/@17 @16 @14 mul def}if sn @13 60000 lt and @2 fBitStretch or and{mtx currentmatrix dup 1 get exch 2 get 0. eq exch 0. eq and @17 60000 lt and fBitStretch and{@16 3 bitshift @14 @9 [calcX 0 0 calcY 0 0]{@17 string @13 string currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4 @10 @11 @12 dup string 5 index @15 @14 @16 dup string stretch}imagemask}{@12 x8 @11 @9 [@10 0 0 @11 0 0]{@13 string currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4}imagemask}ifelse}{@5 3 bitshift @3 4 add @9 [@4 0 0 @3 0 2]{currentfile @6 string readhexstring pop}imagemask}ifelse @7 restore}bdf /wd 16 dict def /mfont 14 dict def /mdf{mfont wcheck not{/mfont 14 dict def}if mfont begin xdf end}bdf /cf{{1 index/FID ne{def}{pop pop}ifelse}forall}bdf /rf{/@1 exch def/@2 exch def FontDirectory @2 known{cleartomark pop}{findfont dup begin dup length @1 add dict begin cf {/Encoding macvec def}{Encoding dup length array copy/Encoding exch def counttomark 2 idiv{Encoding 3 1 roll put}repeat}ifelse pop exec currentdict end end @2 exch definefont pop}ifelse}bdf /bmbc{exch begin wd begin /cr xdf save CharTable cr 6 mul 6 getinterval{}forall /bitheight xdf/bitwidth xdf .96 div/width xdf Gkernmax add/XOffset xdf Gdescent add/YOffset xdf/rowbytes xdf rowbytes 255 eq{0 0 0 0 0 0 setcachedevice} {Gnormsize dup scale width 0 XOffset YOffset bitwidth XOffset add bitheight YOffset add setcachedevice rowbytes 0 ne{ XOffset YOffset translate newpath 0 0 moveto bitwidth bitheight scale sn{ /xSmt bitwidth x4 def /ySmt bitheight x4 def /rSmt xSmt rb def rSmt x8 ySmt true [xSmt 0 0 ySmt neg 0 ySmt] {rSmt ySmt mul string CharData cr get 1 index bitwidth bitheight rowbytes rSmt so smooth4} }{rowbytes 3 bitshift bitheight 4 add true [bitwidth 0 0 bitheight neg 0 bitheight 2 add] {CharData cr get} }ifelse imagemask }if }ifelse restore end end }bdf /bb{.96 exch div/Gnormsize mdf 2 index /Gkernmax mdf 1 index/Gdescent mdf 3 index div 4 1 roll 2 index div 1. 5 2 roll exch div 4 1 roll 4 array astore/FontBBox mdf }bdf /cdf{mfont/CharData get 3 1 roll put}bdf /bf{ mfont begin /FontType 3 def /FontMatrix [1 0 0 1 0 0] def /Encoding macvec def /BuildChar/bmbc load def end mfont definefont pop }bdf /wi LW 1 eq{{gsave 0 0 0 0 0 0 0 0 moveto lineto lineto lineto closepath clip stringwidth grestore}bind}{/stringwidth load}ifelse def /aps{0 get 124 eq}bdf /xc{s75 cvs dup}bdf /xp{put cvn}bdf /scs{xc 3 67 put dup 0 95 xp}bdf /sos{xc 3 79 xp}bdf /sbs{xc 1 66 xp}bdf /sis{xc 2 73 xp}bdf /sob{xc 2 79 xp}bdf /sss{xc 4 83 xp}bdf /dd{exch 1 index add 3 1 roll add exch}bdf /smc{moveto dup lws}bdf /kwn{FontDirectory 1 index known{findfont exch pop}}bdf /gl{1 currentgray sub setgray}bdf /mm{/mfont 10 dict def mfont begin /FontMatrix [1 0 0 1 0 0] def /FontType 3 def /Encoding macvec def /df 4 index findfont def /FontBBox [0 0 1 1] def /xda xdf/mbc xdf /BuildChar{wd begin/cr xdf/fd xdf/cs s1 dup 0 cr put def fd/mbc get exec end}def exec end mfont definefont}bdf /ac{dup scs kwn{exch findfont dup length 1 add dict begin cf fmv{/Encoding macvec def}if/StrokeWidth nlw 1000 mul pys div ps div dup 12 lt{pop 12}if def /PaintType 2 def currentdict /UniqueID known{/UniqueID UniqueID 16#A80000 xor def}if currentdict end definefont}ifelse}bdf /mb{dup sbs kwn{exch{pop}{bbc}{}mm}ifelse sfd}bdf /mo{dup sos kwn{exch{pop}{boc}{}mm}ifelse sfd}bdf /ms{dup sss kwn{exch{pop}{bsc}{}mm}ifelse sfd}bdf /ou{dup sos kwn{exch dup ac pop{scs findfont /df2 xdf}{aoc}{}mm}ifelse sfd}bdf /su{dup sss kwn{exch dup ac pop{scs findfont /df2 xdf}{asc}{}mm}ifelse sfd}bdf /ao{/fmv true def ou}bdf/as{/fmv true def su}bdf /vo{/fmv false def ou}bdf/vs{/fmv false def su}bdf /bbc{/da .03 def fd/df get setfont gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth cs 0 0 smc da 0 smc da da smc 0 da moveto lws}bdf /boc{/da 1 ps div def fd/df get setfont gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth cs 0 0 smc da 0 smc da da smc 0 da smc gl da 2. div dup moveto lws}bdf /bsc{/da 1 ps div def /ds .05 def/da2 da 2. div def fd/df get setfont gsave cs wi 1 index 0 ne{exch ds add da2 add exch}if grestore setcharwidth cs ds da2 add .01 add 0 smc 0 ds da2 sub translate 0 0 smc da 0 smc da da smc 0 da smc gl da 2. div dup moveto lws}bdf /aoc{fd/df get setfont gsave cs wi grestore setcharwidth gl cs 0 0 smc fd/df2 get setfont gl 0 0 moveto lws}bdf /asc{/da .05 def fd/df get setfont gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth cs da .01 add 0 smc 0 da translate gl 0 0 smc gl fd/df2 get setfont 0 0 moveto lws}bdf /st{1000 mul usertime add dup 2147483647 gt{2147483647 sub}if def}bdf /the{usertime sub dup 0 lt exch -2147483648 gt and}bdf /6a 6 array def /2a 2 array def /3q 3 array def /qs{3 -1 roll sub exch 3 -1 roll sub exch}bdf /qa{3 -1 roll add exch 3 -1 roll add exch}bdf /qm{3 -1 roll 1 index mul 3 1 roll mul}bdf /qn{6a exch get mul}bdf /qA .166667 def/qB .833333 def/qC .5 def /qx{6a astore pop qA 0 qn qB 2 qn add qA 1 qn qB 3 qn add qB 2 qn qA 4 qn add qB 3 qn qA 5 qn add qC 2 qn qC 4 qn add qC 3 qn qC 5 qn add}bdf /qp{6 copy 12 -2 roll pop pop}bdf /qc{exch qp qx curveto}bdf /qi{{exch 4 copy 2a astore aload pop qa .5 qm newpath moveto}{exch 2 copy 6 -2 roll 2 qm qs 4 2 roll}ifelse}bdf /qq{{qc 2a aload pop qx curveto}{exch 4 copy qs qa qx curveto}ifelse}bdf /pt{currentpoint newpath moveto}bdf /qf{/fillflag true def}bdf /ec{1 and 0 ne{0 doop}if grestore currentpoint newpath moveto/fillflag false def}bdf /eu{currentpoint fp{0 ep}{grestore newpath}ifelse moveto/fillflag false def}bdf /bp{currentpoint newpath 2 copy moveto}bdf /ef{gsave fillflag{gsave eofill grestore}if}bdf /sm{0 exch{@1 eq{1 add}if}forall}bdf /lshow{4 1 roll exch/@1 exch def{1 index wi pop sub 1 index sm dv 0 @1 4 -1 roll widthshow}{1 index wi pop sub 1 index dup sm 10 mul exch length 1 sub add dv dup 10. mul 0 @1 4 -1 roll 0 6 -1 roll awidthshow}ifelse}bdf /setTxMode{sa 9 2 index put 3 eq{1}{0}ifelse setgray}bdf /SwToSym{{}mark false/Symbol/|______Symbol 0 rf 0 sa 6 get 0 ne{pop 1}{sa 7 get 0 eq{pop 2}if}ifelse sa 1 get 0 ne/|______Symbol sa 4 get 0 ne{vs}{sa 3 get 0 ne{vo}{fnt}ifelse}ifelse}bdf /mc{0 3 1 roll transform neg exch pop}bdf /ul{dup 0 ne sa 2 get 0 ne and{gsave 0 0 /UnderlinePosition kif{mc}{ps -10 div}ifelse/UnderlineThickness kif{mc}{ps 15 div}ifelse abs setlinewidth neg rmoveto sa 4 get 0 ne{gsave currentlinewidth 2. div dup rmoveto currentpoint newpath moveto 2 copy rlineto stroke grestore}if sa 3 get sa 4 get or 0 ne{gsave gl 2 copy rlineto stroke grestore rlineto strokepath nlw pys div setlinewidth}{rlineto}ifelse stroke grestore}{pop}ifelse}bdf /sgt{2 copy known{get true}{pop pop false}ifelse}bdf /kif{currentfont dup/FontMatrix get exch/FontInfo sgt{true}{currentfont/df sgt {dup/FontInfo sgt{3 1 roll/FontMatrix get mtx concatmatrix exch true}{pop pop pop false} ifelse}{pop pop false}ifelse}ifelse{3 -1 roll sgt{exch true}{pop false}ifelse}{false}ifelse}bdf /blank/Times-Roman findfont/CharStrings get/space get def /macvec 256 array def /NUL/SOH/STX/ETX/EOT/ENQ/ACK/BEL/BS/HT/LF/VT/FF/CR/SO/SI /DLE/DC1/DC2/DC3/DC4/NAK/SYN/ETB/CAN/EM/SUB/ESC/FS/GS/RS/US macvec 0 32 getinterval astore pop macvec 32/Times-Roman findfont/Encoding get 32 96 getinterval putinterval macvec dup 39/quotesingle put 96/grave put /Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute /agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave /ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute /ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls /registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash /infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation /product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft /guillemotright/ellipsis/blank/Agrave/Atilde/Otilde/OE/oe /endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge /ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl /daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand/Acircumflex/Ecircumflex/Aacute /Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave/Oacute/Ocircumflex /apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde /macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron macvec 128 128 getinterval astore pop {}mark true/Courier/|______Courier 0 rf {/Metrics 21 dict begin/zero 600 def/one 600 def/two 600 def/three 600 def/four 600 def/five 600 def/six 600 def/seven 600 def/eight 600 def /nine 600 def/comma 600 def/period 600 def/dollar 600 def/numbersign 600 def/percent 600 def/plus 600 def/hyphen 600 def/E 600 def/parenleft 600 def/parenright 600 def/space 600 def currentdict end def currentdict/UniqueID known{/UniqueID 16#800000 def}if/FontBBox FontBBox 4 array astore def}mark true/Helvetica/|______Seattle 1 rf /oldsettransfer/settransfer load def /concatprocs{/proc2 exch cvlit def/proc1 exch cvlit def/newproc proc1 length proc2 length add array def newproc 0 proc1 putinterval newproc proc1 length proc2 putinterval newproc cvx}def /settransfer{currenttransfer concatprocs oldsettransfer}def /PaintBlack{{1 exch sub}settransfer gsave newpath clippath 1 setgray fill grestore}def /od{(Rvd\001\001\000\000\177) fg copy pop txpose 1 0 mtx defaultmatrix dtransform exch atan/pa exch def newpath clippath mark {transform{itransform moveto}}{transform{itransform lineto}} {6 -2 roll transform 6 -2 roll transform 6 -2 roll transform {itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}} {{closepath}}pathforall newpath counttomark array astore/gc xdf pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if}bdf /cd{}bdf /op{/sfl false def/pm save def}bdf % two args, booleans /cp{ %UNI don't actually print page pop pop %UNI ignore two args %UNI not{userdict/#copies 0 put}if %UNI ma 0 gt{{t1 the{exit}if}loop}if %UNI {copypage}{showpage}ifelse pm restore }bdf /px{0 3 1 roll tp tt}bdf /psb{/us save def}bdf /pse{us restore}bdf /ct 40 string def /nc{currentpoint initclip newpath gc{dup type dup/arraytype eq exch/packedarraytype eq or{exec}if} forall clip newpath moveto}bdf /kp{ct 0 2 index length 2 index 39 2 index put getinterval copy cvx exec mx3 currentmatrix pop}bdf end % dict "md" %UNI don't initialize LaserWriter %UNI LW 1 eq userdict/a4small known not and{/a4small %UNI [[300 72 div 0 0 -300 72 div -120 3381] %UNI 280 3255 %UNI {statusdict/jobstate (printing) put 0 setblink %UNI margins %UNI exch 196 add exch 304 add 8 div round cvi frametoroket %UNI statusdict/jobstate (busy) put %UNI 1 setblink} %UNI /framedevice load %UNI 60 45{dup mul exch dup mul add 1.0 exch sub}/setscreen load %UNI {}/settransfer load/initgraphics load/erasepage load]cvx %UNI statusdict begin bind end readonly def}if %UNI md begin/bigs[lnop lnop/legal load userdict/a4 known{/a4 load}{lnop}ifelse lnop lnop lnop lnop lnop]def %UNI /smalls[lnop userdict/note known{/note load}{dup}ifelse lnop userdict/a4small known{/a4small load}{lnop}ifelse 2 index lnop lnop lnop lnop ]def end systemdict/currentpacking known{setpacking}if %UNI currentfile ok userdict/stretch known not and{eexec}{flushfile}ifelse %%EndProlog %%Page: 0 1 BS 0 SI 16 /Times-Bold AF 22526 20648 MT (Nyquist Reference Manual)SH 11 SS 29022 22993 MT (Version 2.0)SH 26562 26761 MT (Roger B. Dannenberg)SH /Times-Roman SF 27496 28138 MT (18 December 1996)SH 25509 39635 MT (Carnegie Mellon University)SH 25371 41387 MT (School of Computer Science)SH 25140 43139 MT (Pittsburgh, PA 15213, U.S.A.)SH ES %%Page: 1 2 BS 0 SI 10 /Times-Roman AF 31430 4286 MT (1)SH 11 SS 9280 7955 MT (.)SH ES %%Page: iii 3 BS 0 SI 8 /Times-Roman AF 8280 4286 MT (PREFACE)SH 10 SS 52052 XM (Page iii)SH 16 /Times-Bold AF 8280 8272 MT (Preface)SH 11 /Times-Roman AF 9280 9649 MT (This manual is a guide for users of Nyquist, a) 51 W( language for composition and sound synthesis. Nyquist)50 W 8280 11026 MT (grew out of a series) 75 W( of research projects, notably the languages Arctic and Canon. Along with Nyquist,)76 W 8280 12403 MT (these languages promote a functional style of programming and incorporate time into the language)261 W 8280 13780 MT (semantics.)SH 9280 16259 MT (Please help by noting any errors,) 267 W( omissions, or suggestions you may have. You can send your)268 W 8280 17636 MT (suggestions to Dannenberg@CS.CMU.EDU \050internet\051 via computer mail, or by campus mail to Roger)147 W 8280 19013 MT (B. Dannenberg, School of Computer Science, or by) 138 W( ordinary mail to Roger B. Dannenberg, School of)139 W 8280 20390 MT (Computer Science, Carnegie Mellon University, 5000 Forbes Ave., Pittsburgh, PA 15213-3890, USA.)SH 9280 22869 MT (Nyquist is a successor to Fugue, a language originally implemented by Chris Fraley,) 78 W( and extended by)77 W 8280 24246 MT (George Polly and Roger Dannenberg. Peter Velikonja and Dean Rubine) 210 W( were early users, and they)211 W 8280 25623 MT (proved the value as well as discovered some early problems of the system.) 221 W( This) 715 W( led to Nyquist, a)220 W 8280 27000 MT (reimplementation of Fugue by Roger Dannenberg with help from Joe Newcomer and Cliff Mercer.)SH 9280 29479 MT (I also wish to acknowledge support from CMU, Yamaha, and IBM for this work.)SH ES %%Page: iv 4 BS 0 SI 10 /Times-Roman AF 6120 4286 MT (Page iv)SH 8 SS 45696 XM (NYQUIST MANUAL)SH 11 SS 6120 44577 MT (.)SH ES %%Page: 1 5 BS 0 SI 8 /Times-Roman AF 8280 4286 MT (NYQUIST FUNCTIONS)SH 10 SS 52386 XM (Page 1)SH 16 /Times-Bold AF 8280 8272 MT (1. Nyquist Functions)SH 14 SS 8280 12090 MT (1.1. Behaviors)SH 12 SS 8280 15774 MT (1.1.1. Sound Synthesis)SH 11 /Times-Roman AF 9280 17151 MT (These functions provide musically interesting) 74 W( creation behaviors that react to their environment; these)75 W 8280 18528 MT (are the ``unit generators'' of Nyquist:)SH /Courier SF 8280 20476 MT (\050sound-warp)SH /Times-Italic SF 16200 XM (warp-fn signal)385 W /Courier SF 23694 XM ([)SH /Times-Italic SF (wrate)SH /Courier SF (]\051)SH /Times-Roman SF 11880 21672 MT (Applies a warp function)50 W /Times-Italic SF 22954 XM (warp-fn)SH /Times-Roman SF 26763 XM (to)SH /Times-Italic SF 27944 XM (signal)SH /Times-Roman SF 30959 XM (using function composition. If) 50 W( the optional parameter)51 W /Times-Italic SF 11880 22868 MT (wrate)SH /Times-Roman SF 14742 XM (is omitted or NIL,) 81 W( linear interpolation is used.)80 W /Times-Italic SF 36210 XM (warp-fn)SH /Times-Roman SF 40049 XM (is a mapping from score \050logical\051)80 W 11880 24064 MT (time to real) 39 W( time, and)40 W /Times-Italic SF 21732 XM (signal)SH /Times-Roman SF 24737 XM (is a function from score time to real values. The result is a function)40 W 11880 25260 MT (from real time to real values at a sample rate of)SH /Courier SF 32923 XM (*sound-srate*)SH /Times-Roman SF (. See) 275 W( also)SH /Courier SF 46238 XM (control-warp)SH /Times-Roman SF (.)SH 11880 26456 MT (If)SH /Times-Italic SF 13004 XM (wrate)SH /Times-Roman SF 15902 XM (is not NIL, it) 117 W( must be a number. The parameter indicates that high-quality resampling)116 W 11880 27652 MT (should be used and specifies the sample rate for the inverse of)94 W /Times-Italic SF 40558 XM (warp-fn)SH /Times-Roman SF (. Use the lowest) 94 W( number)95 W 11880 28848 MT (you can. \050See below for) 109 W( details.\051 Note that high-quality resampling is much slower than linear)108 W 11880 30044 MT (interpolation.)SH 11880 31240 MT (To perform) 138 W( high-quality resampling by a fixed ratio, as opposed to a variable ratio allowed in)139 W /Courier SF 11880 32436 MT (sound-warp)SH /Times-Roman SF (, use)249 W /Courier SF 21269 XM (scale-srate)SH /Times-Roman SF 29053 XM (to stretch) 249 W( or shrink the sound, and then)248 W /Courier SF 48421 XM (resample)SH /Times-Roman SF 54224 XM (to)SH 11880 33632 MT (restore the original sample rate.)SH /Courier SF 11880 36265 MT (Sound-warp)SH /Times-Roman SF 18783 XM (and)SH /Courier SF 20674 XM (control-warp)SH /Times-Roman SF 28897 XM (both take the inverse of)28 W /Times-Italic SF 39636 XM (warp-fn)SH /Times-Roman SF 43423 XM (to get a function) 28 W( from real)29 W 11880 37461 MT (time to score time. Each sample of this inverse) 33 W( is thus a score time;)32 W /Times-Italic SF 42183 XM (signal)SH /Times-Roman SF 45180 XM (is evaluated at each of)32 W 11880 38657 MT (these score times to yield a value, which is) 17 W( the desired result. The sample rate of the inverse warp)18 W 11880 39853 MT (function is somewhat arbitrary. With linear interpolation, the inverse warp function sample rate is)17 W 11880 41049 MT (taken to be the output sample rate. Note,) 63 W( however, that the samples of the inverse warp function)64 W 11880 42245 MT (are stored as 32-bit floats, so they have limited precision. Since) 171 W( these floats represent sample)170 W 11880 43441 MT (times, rounding can) 190 W( be a problem. Rounding in this case is equivalent to adding jitter to the)191 W 11880 44637 MT (sample times. Nyquist ignores this problem for ordinary) 110 W( warping, but for high-quality warping,)109 W 11880 45833 MT (the jitter cannot be ignored.)SH 11880 47029 MT (The solution is to use a) 59 W( rather low sample rate for the inverse warp function.)60 W /Courier SF 46619 XM (Sound-warp)SH /Times-Roman SF 53554 XM (can)SH 11880 48225 MT (then linearly interpolate this signal using double-precision floats to minimize jitter between)275 W 11880 49421 MT (samples. The) 205 W( sample rate is a compromise: a low sample rate minimizes jitter, while a high)206 W 11880 50617 MT (sample rate) 76 W( does a better job of capturing detail \050e.g. rapid fluctuations\051 in the warp function. A)75 W 11880 51813 MT (good rule of thumb is to use at) 69 W( most 1,000 to 10,000 samples for the inverse warp function. For)70 W 11880 53009 MT (example, if the result will be 1 minute of sound, use a sample rate of 3000 samples / 60) 9 W( seconds =)8 W 11880 54205 MT (50 samples/second. Because Nyquist has no advance information about) 153 W( the warp function, the)154 W 11880 55401 MT (inverse warp function sample rate must be) 173 W( provided as a parameter. When in doubt, just try)172 W 11880 56597 MT (something and let your ears be the judge.)SH /Courier SF 8280 58292 MT (\050slope)SH /Times-Italic SF 12900 XM (signal)SH /Courier SF (\051)SH /Times-Roman SF 11880 59488 MT (Computes the first derivative \050slope\051 of)100 W /Times-Italic SF 30076 XM (signal)SH /Times-Roman SF (. The) 475 W( start time, sample rate,) 100 W( etc. are taken from)99 W /Times-Italic SF 11880 60684 MT (signal)SH /Times-Roman SF (.)SH ES %%Page: 2 6 BS 0 SI 10 /Times-Roman AF 6120 4286 MT (Page 2)SH 8 SS 45696 XM (NYQUIST MANUAL)SH ES %%Page: 3 7 BS 0 SI 8 /Times-Roman AF 8280 4286 MT (INDEX)SH 10 SS 52386 XM (Page 3)SH 16 /Times-Bold AF 8280 8272 MT (Index)SH 8 /Times-Roman AF 8280 10469 MT (Behaviors 1)400 W 8280 12317 MT (Errors iii)400 W 8280 14165 MT (Omissions iii)400 W 8280 16013 MT (Slope, derivative, first derivative) SH( 1)400 W 8280 16937 MT (Sound-warp 1)400 W 8280 17861 MT (Suggestions iii)400 W ES %%Page: 4 8 BS 0 SI 10 /Times-Roman AF 6120 4286 MT (Page 4)SH 8 SS 45696 XM (NYQUIST MANUAL)SH ES %%Page: i 9 BS 0 SI 8 /Times-Roman AF 8280 4286 MT (TABLE OF CONTENTS)SH 10 SS 52608 XM (Page i)SH 16 /Times-Bold AF 25591 8272 MT (Table of Contents)SH 12 SS 8280 9796 MT (Preface)SH 54078 XM (iii)SH 8280 11320 MT (1. Nyquist Functions)SH 54480 XM (1)SH 10 SS 9780 12710 MT (1.1. Behaviors)SH 54580 XM (1)SH 11780 13790 MT (1.1.1. Sound Synthesis)SH 54580 XM (1)SH 12 SS 8280 15314 MT (Index)SH 54480 XM (3)SH ES %%Trailer %%Pages: 9 %%DocumentFonts: Times-Roman Times-Bold Courier Times-Italic nyquist-3.05/docsrc/nyquist/nyquistman.mss0000644000175000000620000175620611537432671020142 0ustar stevestaff@device(mac52postscript) @make(manual) @libraryfile(mathematics10) @libraryfile(picture) @libraryfile(multilevelindex) @style(font timesroman) @style(fontscale 11) @commandstring(dash @Y[M]) @commandstring(subtract @Y[N]) @commandstring(itemsep @Y[M]) @Modify(indexenv, above=2 lines, leftmargin 8, columns=3, boxed) @define(prg=i) @define(detail=text, size 9, spacing 1.2, indent 0) @define(code, FaceCode T, size 11) @comment{codef is used to define a lisp function or variable -- a processor uses this to extract completion hint info for NyquistIDE.} @define(codef, FaceCode T, size 11) @comment{pragma(define) is used to mark a term's point of definition -- I tried to define(defn=index), but that didn't work in Scribe, so the approach now is to mark definitions. In s2h, the define pragma sets a flag that the NEXT index term is a definition. The s2h.lsp processor uses this to map terms defined within codef (which go into the completion list) to URLs for the help system.} @define(smallcode, FaceCode T, size 8, spacing 0.8) @comment(was 10) @define(rbdisplay = display, group) @define(fndefs = description, leftmargin 0.5in, indent -0.5in) @define(fdescription = text, leftmargin +0.5in, indent -0.5in, spread 1) @define(pdescription = text, leftmargin +0.5in, indent -0.5in, spread 0) @define(fgroup = text, indent -0.5in, spread 0) @define(altdef = text, leftmargin +0.0in, indent -0.5in) @textform(html = []) @textform(htmltitle = []) @textform(pragma = []) @use(bibliography = "../bib/music.bib") @style(references ClosedAlphabetic) @counter(dummy-counter) @modify(FigureCounter,Within=dummy-counter, Numbered <@@b[Figure@@ @1:@@ @@ ]@@$>, Referenced "@1",Init 0) @modify(TableCounter,Within=dummy-counter, Numbered <@@b[Table@@ @1:@@ @@ ]@@$>, Referenced "@1",Init 0) @pageheading(left "", center "@value(page)", right "") @include(../template/filcap.mss) @begin(comment) @begin(figure) @blankspace(0.3 inches) @comment(scribe doesn't leave enough space) @center(@graphic((height = *** in, width = *** in, magnify = ***, postscript = "***.ps")) @fillcaption(***) @tag(***) @end(figure) @end(comment) @html(Nyquist Reference Manual) @htmltitle(Nyquist Reference Manual) @begin(titlepage) @begin(titlebox) @blankspace(0.5 inch) @majorheading(Nyquist Reference Manual) @b(Version 3.05) @blankspace(0.3 inch) @b(Copyright 2011 by Roger B. Dannenberg) @value(date) @end(titlebox) @pragma(startscribe) @center(Carnegie Mellon University) @center(School of Computer Science) @center(Pittsburgh, PA 15213, U.S.A.) @pragma(endscribe) @html(
    Carnegie Mellon University
    School of Computer Science
    Pittsburgh, PA 15213, U.S.A.
    ) @blankspace(1 inch) @end(titlepage) @pragma(startscribe) . @pragma(endscribe) @newpage @pageheading(even, left "Page @Value(Page)", right "@c(Nyquist Manual)") @pageheading(odd, left "@c[@title(chapter)]", right "Page @Value(page)") @style(pagenumbers="@i") @set(page=3) @Unnumbered(Preface) This manual is a guide for users of Nyquist, a language for composition and sound synthesis. Nyquist grew out of a series of research projects, notably the languages Arctic and Canon. Along with Nyquist, these languages promote a functional style of programming and incorporate time into the language semantics. Please help by noting any errors@Index(errors), omissions@Index(omissions), or suggestions@Index(suggestions) you may have. You can send your suggestions to Dannenberg@@CS.CMU.EDU (internet) via computer mail, or by campus mail to Roger B. Dannenberg, School of Computer Science, or by ordinary mail to Roger B. Dannenberg, School of Computer Science, Carnegie Mellon University, 5000 Forbes Ave., Pittsburgh, PA 15213-3890, USA. Nyquist is a successor to Fugue, a language originally implemented by Chris Fraley, and extended by George Polly and Roger Dannenberg. Peter Velikonja and Dean Rubine were early users, and they proved the value as well as discovered some early problems of the system. This led to Nyquist, a reimplementation of Fugue by Roger Dannenberg with help from Joe Newcomer and Cliff Mercer. Ning Hu ported Zheng (Geoffrey) Hua and Jim Beauchamp's piano synthesizer to Nyquist and also built NyqIDE, the Nyquist Integrated Development Environment for Windows. Dave Mowatt contributed the original version of NyquistIDE, the cross-platform interactive development environment. Dominic Mazzoni made a special version of Nyquist that runs within the Audacity audio editor, giving Nyquist a new interface and introducing Nyquist to many new users. Many others have since contributed to Nyquist. Chris Tchou and Morgan Green worked on the Windows port. Eli Brandt contributed a number of filters and other synthesis functions. Pedro J. Morales, Eduardo Reck Miranda, Ann Lewis, and Erich Neuwirth have all contributed nyquist examples found in the demos folder of the Nyquist distribution. Philip Yam ported some synthesis functions from Perry Cook and Gary Scavone's STK to Nyquist. Pedro Morales ported many more STK instruments to Nyquist. Dave Borel wrote the Dolby Pro-Logic encoding library and Adam Hartman wrote stereo and spatialization effects. Stephen Mangiat wrote the MiniMoog emulator. Phil Light recorded the drum samples and wrote drum machine software. The Xmusic library, particularly the pattern specification, was inspired by Rick Taube's Common Music. The functions for generating probability distributions were implemented by Andreas Pfenning. Starting with Version 3, Nyquist supports a version of SAL, providing an alternative to Lisp syntax. SAL was designed by Rick Taube, and the SAL implementation in Nyquist is based on Taube's original implementation as part of his Common Music system. The current NyquistIDE includes contributions from many. Chris Yealy and Derek D'Souza implemented early versions of the envelope editor. Daren Makuck and Michael Rivera wrote the original equalizer editor. Priyanka Raghavan implemented the sound browser. Dmitry Portnoy wrote the original "UPIC" editor. Many others have made contributions, offered suggestions, and found bugs. If you were expecting to find your name here, I apologize for the omission, and please let me know. I also wish to acknowledge support from CMU, Yamaha, and IBM for this work. @newpage @blankspace(5 inches) @pragma(startscribe) . @pragma(endscribe) @newpage @set(page=1) @style(pagenumbers="@1") @chapter(Introduction and Overview) Nyquist is a language for sound synthesis and music composition. Unlike score languages that tend to deal only with events, or signal processing languages that tend to deal only with signals and synthesis, Nyquist handles both in a single integrated system. Nyquist is also flexible and easy to use because it is based on an interactive Lisp interpreter. With Nyquist, you can design instruments by combining functions (much as you would using the orchestra languages of Music V, cmusic, or Csound). You can call upon these instruments and generate a sound just by typing a simple expression. You can combine simple expressions into complex ones to create a whole composition. Nyquist runs under Linux, Apple Mac OS X, Microsoft Windows NT, 2000, XP, and Vista, and it produces sound files or directly generates audio. Recent versions have also run on AIX, NeXT, SGI, DEC pmax, and Sun Sparc machines. (Makefiles for many of these are included, but out-of-date). Let me know if you have problems with any of these machines. To use Nyquist, you should have a basic knowledge of Lisp. An excellent text by Touretzky is recommended @cite(Touretzky). Appendix @ref(xlisp-app) is the reference manual for XLISP, of which Nyquist is a superset. Starting with Version 3, Nyquist supports a variant of SAL, which is also available in Common Music. Since there are some differences, one should generally call this implementation ``Nyquist SAL;'' however, in this manual, I will just call it ``SAL.'' SAL offers most of the capabilities of Lisp, but it uses an Algol-like syntax that may be more familiar to programmers with experience in Java, C, Basic, etc. @label(install-sec) @section(Installation) @index(installation)@index(configure nyquist)@index(setup nyquist) Nyquist is a C++ program intended to run under various operating systems including Unix, Mac OS X, and Windows. Nyquist is based on Lisp, but it includes its own Lisp interpreter (a modified version of XLISP), so you do not need to install some other Lisp to run Nyquist. Other Lisp systems are not compatible with Nyquist. Most Nyquist users run Nyquist under the Nyquist IDE, which is written in Java and depends on the Java runtime system. Most systems already have Java, but if you do not, you will need to install it. When you install the Nyquist IDE, you will automatically get Nyquist and a set of runtime libraries. There are generally two ways to install Nyquist: @begin(itemize) Get a pre-compiled version of the Nyquist IDE for Windows or Mac OS X. The Windows version comes packaged in an installer that installs and configures the Nyquist IDE. The Mac OS X version unpacks to a complete OS X application. Compile from sources. There is one set of sources for Mac, Windows, and Unix. Instructions for building applications from the sources are provided in the files @code(sys/win/README.txt), @code(sys/mac/README.txt), and @code(sys/unix/README.txt). @end(itemize) You can download source code and precompiled versions from the Nyquist project on SourceForge (@code(http://sourceforge.net/projects/nyquist)). The latest source code can be obtained via Subversion (svn) using the following: @begin(example) svn co https://nyquist.svn.sourceforge.net/svnroot/nyquist/trunk nyquist @end(example) or by checking out nyquist using a graphical interface svn client such as TortoiseSVN for Windows. @begin(comment) @subsection(Unix Installation) For Unix systems, Nyquist is distributed as a compressed tar file named @code(nyqsrc3@i(nn).zip), where @i(nn) is the version number (e.g. v3.01 was in @code(nyqsrc301.zip)). To install Nyquist, copy @code(nyqsrc3@i(nn).zip) to the directory on your machine where you would like to install Nyquist, and type: @begin(example) gunzip nyqsrc3@i(nn).zip cd nyquist ln -s sys/unix/linux/Makefile Makefile setenv XLISPPATH `pwd`/runtime:`pwd`/lib make @end(example) The first line creates a @code(nyquist) directory and some subdirectories. The second line (cd) changes directories to the new nyquist directory. The third line makes a link from the top-level directory to the Makefile for your system. In place of @code(linux) in @code(sys/unix/linux/Makefile), you should substitute your system type. Current systems are @code(next), @code(pmax), @code(rs6k), @code(sgi), @code(linux), and @code(sparc). The @code(setenv) command tells Nyquist where to search for lisp files to be loaded when a file is not found in the current directory. The @code(runtime) directory should always be on your @code(XLISPPATH) when you run Nyquist, so you may want to set @code(XLISPPATH) in your shell startup file, e.g. @code(.cshrc). Assuming the make completes successfully, you can run Nyquist as follows: @begin(example) ./ny @end(example) When you get the prompt, you may begin typing expressions such as the ones in the following ``Examples'' section. One you establish that Nyquist (ny) is working from the command line, you should try using NyquistIDE, the Java-based Nyquist development environment. First, make @code(jny) executable (do this only once when you install Nyquist): @begin(example) chmod +x jny @end(example) Then try running NyquistIDE by typing: @begin(example) ./jny @end(example) If the NyquistIDE window does not appear, make sure you have Java installed (if not, you probably already encountered errors when you ran @code(make)). You can also try recompiling the Java files: @begin(example) cd jnyqide javac *.java cd .. @end(example) @p(Note:) With Linux and the Macintosh OS X, NyquistIDE defines the environment passed to Nyquist. If you set @code(XLISPPATH)@index(XLISPPATH)@index(search path) as shown above, it will be passed along to Nyquist under NyquistIDE. If not, a default XLISPPATH will have the @code(lib) and @code(runtime) directories only. This does not apply to Windows because even though the environment is there, the Windows version of Nyquist reads the @code(XLISPPATH) from the Registry. You can also specify the search path by creating the file @code(nyquist/xlisppath), which should have colon-separated paths on a single line of text. This file will override the environment variable @code(XLISPPATH). It is good to have @code(USER) in the environment with your user ID. This string is used to construct some file names. NyquistIDE will look for it in the environment. You can also specify your user ID using the file @code(nyquist/user), but if you have a shared installation of Nyquist, this will not be very useful. @p(Note:) Nyquist looks for the file @code(init.lsp) in the current directory. If you look in the @code(init.lsp) in @code(runtime), you will notice two things. First, @code(init.lsp) loads @code(nyquist.lsp) from the Nyquist directory, and second, @code(init.lsp) loads @code(system.lsp) which in turn defines the macro @code(play). You may have to modify @code(system.lsp) to invoke the right programs on your machine. @subsection(Win32 Installation) The Win32 version of Nyquist is packaged as a compiled (runtime) system in an executable installer. A source version is also available (the same source download is for Win32, Mac OS X, and Linux). The source version is intended for developers who want to recompile Nyquist. The contents of the source archive are extracted to the @code(C:\nyquist) directory, but you can put it anywhere you like. You can then open the workspace file, nyquist.sln, using Microsoft Visual C++. You can build and run the command line version of Nyquist from within Visual C++. There is a batch file, @code(comp-ide.bat), for bulding the Nyquist IDE. This requires the Java SDK from Sun Microsystems. The runtime version contain everything you need to run Nyquist, including the executable, examples, and documentation, packaged as an executable installer program. After executing the installer, just find Nyquist in your Start menu to run it. You may begin typing expressions such as the ones in the following ``Examples'' section. @p(Optional:)@index(Registry)@index(xlisppath)@index(search path) Nyquist needs to know where to find the standard runtime files. The location of runtime files must be stored in the Registry. The installers create a registry entry, but if you move Nyquist or deal with different versions, you can edit the Registry manually as follows: @begin(itemize) Run the Registry editor. Under Windows NT, run @code(C:\WINNT\system32\regedt32.exe). Under Windows95, run @code(C:\WINDOWS\regedit.exe). Find and highlight the @code(SOFTWARE) key under @code(HKEY_LOCAL_MACHINE). Choose @code(Add key ...) from the @code(Edit) menu, type @code(CMU), and click the @code(OK) button. Highlight the new @code(CMU) key. Choose @code(Add key ...) from the @code(Edit) menu, type @code(Nyquist), and click the @code(OK) button. (Note that @code(CMU) and @code(Nyquist) are case sensitive.) Highlight the new @code(Nyquist) key. Choose @code(Add value ...) from the @code(Edit) menu, type @code(XLISPPATH), and click the @code(OK) button. (Under WinXP the menu item is @code(Edit:New:String Value), after which you need to select the new string name that appears in the right panel, select @code(Edit:Rename), and type @code(XLISPPATH).) In the String Edit box (select the @code(Edit:Modify) menu item in WinXP), type a list of paths you want Nyquist to search for lisp files. For example, if you installed Nyquist as @code(C:\nyquist), then type: @begin(example) C:\nyquist\runtime,C:\nyquist\lib @end(example) The paths should be separated by a comma or semicolon and no space. The @code(runtime) path is essential, and the @code(lib) path may become essential in a future release. You can also add paths to personal libraries of Lisp and Nyquist code. Click the @code(OK) button of the string box and exit from the Registry Editor application. @end(itemize) @paragraph(What if Nyquist functions are undefined?) If you do not have administrative privileges for your machine, the installer may fail to set up the Registry entry that Nyquist uses to find initialization files. In this case, Nyquist will run a lisp interpreter, but many Nyquist functions will not be defined. If you can log in as administrator, do it and reinstall Nyquist. If you do not have permission, you can still run Nyquist as follows: Create a file named @code(init.lsp) in the same directory as Nyquist.exe (the default location is @code(C:\Program Files\Nyquist), but you may have installed it in some other location.) Put the following text in @code(init.lsp): @begin(example) @begin(smallcode) (setf *search-path* "C:/Program Files/Nyquist/runtime,C:/Program Files/Nyquist/lib") (load "C:/Program Files/Nyquist/runtime/init.lsp") @end(smallcode) @end(example) @p(Note:) in the three places where you see @code(C:/Program Files/Nyquist), insert the full path where Nyquist is actually installed. Use forward slashes (@code(/)) rather than back slashes (@code(\)) to separate directories. For example, if Nyquist is installed at @code(D:\rbd\nyquist), then @code(init.lsp) should contain: @begin(example) @begin(smallcode) (setf *search-path* "D:/rbd/nyquist/runtime,D:/rbd/nyquist/lib") (load "d:/rbd/nyquist/runtime/init.lsp") @end(smallcode) @end(example) The variable @code(*search-path*), if defined, is used in place of the registry to determine search paths for files. @paragraph(SystemRoot) @index(SystemRoot) (Ignore this paragraph if you are not planning to use Open Sound Control under Windows.) If Nyquist prints an error message and quits when you enable Open Sound Control (using @code(osc-enable)), check to see if you have an environment variable @code(SystemRoot), e.g. type @code(set) to a command prompt and look for the value of @code(SystemRoot). The normal value is @code(C:\windows). If the value is something else, you should put the environment entry, for example: @begin(example) SystemRoot="D:\windows" @end(example) into a file named @code(systemroot) (no extension). Put this file in your @code(nyquist) directory. When you run @code(NyquistIDE), it will look for this file and pass the contents as an environment variable to Nyquist. The Nyquist process needs this to open a UDP socket, which is needed for Open Sound Control. @paragraph(The "java is not recognized" Error) Sometimes, Nyquist will run directly from the installer, but then it will not start from the Windows Start menu. You can try running the @code(nyquist/jnyqide.bat) program from a Windows shell. If that fails, and you see an error similar to "java is not recognized as in internal or external command error", the problem may be that paths are not set up properly to allow the Windows shell to find java. Right click on ``My Computer'' on the Windows desktop and select ``Properties.'' Under the ``Advanced'' tap, press the ``Environment Variables'' button, and look for PATH under ``System Variables.'' Make sure the Java bin directory is on the path. If it is not, you will have to find your installation of Java and add the appropriate directory to the PATH variable, e.g. ``C:\Program Files\Java\jdk1.6.0\bin.'' @subsection(MacOS X Installation) The OS X version of Nyquist is very similar to the Linux version, but it is developed using Xcode, Apple's programming environment. With a little work, you can use the Linux installation instructions to compile Nyquist, but it might be simpler to just open the Xcode project that is included in the Nyquist sources. You can also download a pre-compiled version of Nyquist for the Mac. Just download @code(nyqosx2xx.tgz) to the desktop and open it to extract the folder nyqosx2xx. (Again, "2xx" refers to the current version number, e.g. v2.31 would be named with "231".) Open the folder to find a Mac Application named NyquistIDE and a directory named nyquist/doc. Documentation is in the nyquist/doc directory. The file @code(NyquistIDE.app/Contents/Resources/Java/ny) is the command line executable (if you should need it). To run from the command line, you will need to set the XLISPPATH environment variable as with Linux. On the topic of the @code(XLISPPATH), note that this variable is set by NyquistIDE when running with that application, overriding any other value. You can extend the search path by creating the file @code(xlisppath) in the same directory as the nyquist executable @code(ny). The @code(xlisppath) file should have colon-separated paths on a single line of text. @end(comment) @section(Using NyquistIDE)@index(NyquistIDE)@index(IDE)@index(Integrated Development Environment) The program named NyquistIDE is an ``integrated development environment'' for Nyquist. When you run NyquistIDE, it starts the Nyquist program and displays all Nyquist output in a window. NyquistIDE helps you by providing a Lisp and SAL editor, hints for command completion and function parameters, some graphical interfaces for editing envelopes and graphical equalizers, and a panel of buttons for common operations. A more complete description of NyquistIDE is in Chapter @ref(jnyqide-chapter). For now, all you really need to know is that you can enter Nyquist commands by typing into the upper left window. When you type return, the expression you typed is sent to Nyquist, and the results appear in the window below. You can edit files by clicking on the New File or Open File buttons. After editing some text, you can load the text into Nyquist by clicking the Load button. NyquistIDE always saves the file first; then it tells Nyquist to load the file. You will be prompted for a file name the first time you load a new file. @section(Using SAL) SAL mode means that Nyquist reads and evaluates SAL commands rather than Lisp. The SAL mode prompt is "@code(SAL> )" while the Lisp mode prompt is "@code(> )". When Nyquist starts it normally enters SAL mode automatically, but certain errors may exit SAL mode. You can reenter SAL mode by typing the Lisp expression @code[(sal)]. In SAL mode, you type commands in the SAL programming language. Nyquist reads the commands, compiles them into Lisp, and evaluates the commands. Commands can be entered manually by typing into the upper left text box in NyquistIDE. @section(Helpful Hints) Under Win95 and Win98, the console sometimes locks up. Activating another window and then reactivating the Nyquist window should unlock the output. (We suggest you use JNyqIDE, the interactive development environment rather than a console window.) You can cut and paste text into Nyquist, but for serious work, you will want to use the Lisp @code(load) command. To save even more time, write a function to load your working file, e.g. @code[(defun l () (load "myfile.lsp"))]. Then you can type @code[(l)] to (re)load your file. Using SAL, you can type @begin(example) define function l () load "myfile.lsp" @end(example) and then @begin(example) exec l() @end(example) to (re)load the file. The Emacs editor is free GNU software and will help you balance parentheses if you use Lisp mode. In fact, you can run nyquist (without the IDE) as a subprocess to Emacs. A helful discussion is at //http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/examples/emacs/main.html. If you use Emacs, there is also a SAL mode (the file is @code(sal-mode.el)) included with the Common Music distribution, which you can find on the Web at @code(sourceforge.net). The NyquistIDE also runs Nyquist as a subprocess and has built-in Lisp and SAL editors. If your editor does not help you balance parentheses, you may find yourself counting parens and searching for unbalanced expressions. If you are confused or desperate and using Lisp syntax, try the @code(:print t) option of the @code(load) function. By looking at the expressions printed, you should be able to tell where the last unbalanced expression starts. Alternatively, type @code[(file-sexprs)] and type the lisp file name at the prompt. This function will read and print expressions from the file, reporting an error when an extra paren or end-of-file is reached unexpectedly. @section(Using Lisp) Lisp mode means that Nyquist reads and evaluates Nyquist expressions in Lisp syntax. Since Nyquist is build on a Lisp interpreter, this is the ``native'' or machine language of Nyquist, and certain errors and functions may break out of the SAL interpreter, leaving you with a prompt for a Lisp expression. Alternatively, you can exit SAL simply by typing @code(exit) to get a Lisp prompt (@code(> )). Commands can be entered manually by typing into the upper left text box in NyquistIDE. @section(Examples) We will begin with some simple Nyquist programs. Throughout the manual, we will assume SAL mode and give examples in SAL, but it should be emphasized that all of these examples can be performed using Lisp syntax. See Section @ref(sal-vs-lisp-section) on the relationship between SAL and Lisp. Detailed explanations of the functions used in these examples will be presented in later chapters, so at this point, you should just read these examples to get a sense of how Nyquist is used and what it can do. The details will come later. Most of these examples can be found in the file @code(nyquist/demos/examples.sal). Corresponding Lisp syntax examples are in the file @code(nyquist/demos/examples.lsp). Our first example makes and plays a sound:@index(osc)@index(play) @begin(example) @i(;; Making a sound.) play osc(60) ; generate a loud sine wave @comment{(play (osc 60)) @i(; generate a loud sine wave)} @end(example) This example is about the simplest way to create a sound with Nyquist. The @code(osc) function generates a sound using a table-lookup oscillator. There are a number of optional parameters, but the default is to compute a sinusoid with an amplitude of 1.0. The parameter @code(60) designates a pitch of middle C. (Pitch specification will be described in greater detail later.) The result of the @code(osc) function is a sound. To hear a sound, you must use the @code(play) command, which plays the file through the machine's D/A converters. It also writes a soundfile in case the computation cannot keep up with real time. You can then (re)play the file by typing: @begin(example) exec r() @end(example) This @code[(r)] function is a general way to ``replay'' the last thing written by @code(play). Note: when Nyquist plays a sound, it scales the signal by 2@+(15)-1 and (by default) converts to a 16-bit integer format. A signal like @code[(osc 60)], which ranges from +1 to -1, will play as a full-scale 16-bit audio signal. @subsection(Waveforms) @label(waveform-sec) Our next example will be presented in several steps. The goal is to create a sound using a wavetable consisting of several harmonics as opposed to a simple sinusoid. In order to build a table, we will use a function that computes a single harmonic and add harmonics to form a wavetable. An oscillator will be used to compute the harmonics. @begin(comment) Ordinarily, Nyquist programs are sample-rate independent, and time (in seconds) is used rather than sample numbers to indicate regions of signals. Since we want a wave-table with a certain integer number of samples, we need to do some extra calculations to convert from time to samples. The @code(build-harmonic) function (see Figure @ref(build-harmonic-fig)) produces a signal with @code(n) periods in the course of 2048 samples using the @code(snd-sine) function. @begin(figure) @begin(example) (defun build-harmonic (n tablesize) (snd-sine 0 n tablesize 1)) @end(example) @fillcaption(@code(build-harmonic) uses a low-level function, @code(snd-sine), to construct a harmonic. The function parameters denote: ``compute a sinusoid starting at time zero, with frequency @i(n), a sample rate of @i(tablesize) samples per second and a duration of 1 second.'' This signal becomes a periodic waveform to be resampled by a table lookup oscillator, so the choice of sample rate and duration is a matter of convenience. @tag(build-harmonic-fig) @end(figure) @end(comment) The function @code(mkwave@index(mkwave)) calls upon @code(build-harmonic@index(build-harmonic)) to generate a total of four harmonics with amplitudes 0.5, 0.25, 0.125, and 0.0625. These are scaled and added (using @code(+@index(sim))) to create a waveform which is bound temporarily to @code(*table*). A complete Nyquist waveform is a list consisting of a sound, a pitch, and @code(T), indicating a periodic waveform. The pitch gives the nominal pitch of the sound. (This is implicit in a single cycle wave table, but a sampled sound may have many periods of the fundamental.) Pitch is expressed in half-steps, where middle C is 60 steps, as in MIDI pitch numbers. The list of sound, pitch, and @code(T) is formed in the last line of @code(mkwave): since @code(build-harmonic) computes signals with a duration of one second, the fundamental is 1 Hz, and the @code(hz-to-step) function converts to pitch (in units of steps) as required. @begin(example)@label(build-harmonic-example) define function mkwave() begin set *table* = 0.5 * build-harmonic(1.0, 2048) + 0.25 * build-harmonic(2.0, 2048) + 0.125 * build-harmonic(3.0, 2048) + 0.0625 * build-harmonic(4.0, 2048) set *table* = list(*table*, hz-to-step(1.0), #t) end @end(example) Now that we have defined a function, the last step of this example is to build the wave. The following code calls @code(mkwave) the first time the code is executed (loaded from a file). The second time, the variable @code(*mkwave*) will be true, so @code(mkwave) will not be invoked: @begin(example) if ! fboundp(quote(*mkwave*)) then begin exec mkwave() set *mkwave* = #t end @end(example) @subsection(Wavetables)@index(wavetables)@index(waveforms)@index(triangle wave)@index(sawtooth wave) When Nyquist starts, several waveforms are created and stored in global variables for convenience. They are: @code(*sine-table*), @code(*saw-table*), and @code(*tri-table*), implementing sinusoid, sawtooth, and triangle waves, respectively. The variable @code(*table*) is initialized to @code(*sine-table*), and it is @code(*table*) that forms the default wave table for many Nyquist oscillator behaviors. If you want a proper, band-limited waveform, you should construct it yourself, but if you do not understand this sentence and/or you do not mind a bit of aliasing, give @code(*saw-table*) and @code(*tri-table*) a try. Note that in Lisp and SAL, global variables often start and end with asterisks (*). These are not special syntax, they just happen to be legal characters for names, and their use is purely a convention. @subsection(Sequences)@index(Sequences) Finally, we define @code(my-note@index(my-note)) to use the waveform, and play several notes in a simple score. Note that the function @code(my-note) has only one command (a @code(return) command), so it is not necessary to use @code(begin) and @code(end). These are only necessary when the function body consists of a sequence of statements: @begin(example) define function my-note(pitch, dur) return osc(pitch, dur, *table*) play seq(my-note(c4, i), my-note(d4, i), my-note(f4, i), my-note(g4, i), my-note(d4, q)) @end(example) Here, @code(my-note) is defined to take pitch and duration as parameters; it calls @code(osc) to do the work of generating a waveform, using @code(*table*) as a wave table. The @code(seq) function is used to invoke a sequence of behaviors. Each note is started at the time the previous note finishes. The parameters to @code(my-note) are predefined in Nyquist: @code(c4) is middle C, @code(i) (for eIghth note) is 0.5, and @code(q) (for Quarter note) is 1.0. See Section @ref(constants-sec) for a complete description. The result is the sum of all the computed sounds. Sequences can also be constructed using the @code(at) transformation to specify time offsets. See @code(sequence_example.htm)@index(sequence_example.htm)@index(score, musical) @code(demos, sequence) for more examples and explanation. @subsection(Envelopes)@index(Envelopes) The next example will illustrate the use of envelopes. In Nyquist, envelopes are just ordinary sounds (although they normally have a low sample rate). An envelope@index(envelope) is applied to another sound by multiplication using the @code(mult@index(mult)) function. The code shows the definition of @code(env-note@index(env-note)), defined in terms of the @code(note) function in the previous example. In @code(env-note), a 4-phase envelope is generated using the @code(env@index(env)) function, which is illustrated in Figure @ref(env-fig). @begin(figure) @center(@graphic((height = 2 in, width = 3.75 in, magnify = 1, postscript = "envfig.ps")) @html(

    ) @fillcaption(An envelope generated by the @code(env) function.) @tag(env-fig) @end(figure) @begin(Example) @i[; env-note produces an enveloped note. The duration ; defaults to 1.0, but stretch can be used to change ; the duration. ; Uses my-note, defined above. ;] define function env-note(p) return my-note(p, 1.0) * env(0.05, 0.1, 0.5, 1.0, 0.5, 0.4) @i[; try it out: ;] play env-note(c4) @end(example) While this example shows a smooth envelope multiplied by an audio signal, you can also multiply audio signals to achieve what is often called @i(ring modulation)@index(ring modulation). See the code and description in @code(demos/scratch_tutorial.htm)@index(demos, ring modulation) for an interesting use of ring modulation to create ``scratch'' sounds. In the next example, The @i(stretch) operator (@code(~))@index(stretch) is used to modify durations: @begin(example) @i[; now use stretch to play different durations ;] play seq(seq(env-note(c4), env-note(d4)) ~ 0.25, seq(env-note(f4), env-note(g4)) ~ 0.5, env-note(c4)) @end(example) In addition to @i(stretch), there are a number of transformations supported by Nyquist, and transformations of abstract behaviors is perhaps @i(the) fundamental idea behind Nyquist. Chapter @ref(behavioral-abstraction-sec) is devoted to explaining this concept, and further elaboration can be found elsewhere @cite(icmcfugue). @subsection(Piece-wise Linear Functions) It is often convenient to construct signals in Nyquist using a list of (time, value) breakpoints which are linearly interpolated to form a smooth signal. Envelopes created by @code(env) are a special case of the more general piece-wise linear functions created by @code(pwl). Since @code(pwl) is used in some examples later on, we will take a look at @code(pwl) now. The @code(pwl) function takes a list of parameters which denote (time, value) pairs. There is an implicit initial (time, value) pair of (0, 0), and an implicit final value of 0. There should always be an odd number of parameters, since the final value (but not the final time) is implicit. Here are some examples: @begin(Example) @i[; symetric rise to 10 (at time 1) and fall back to 0 (at time 2): ;] pwl(1, 10, 2) @i[; a square pulse of height 10 and duration 5. ; Note that the first pair (0, 10) overrides the default initial ; point of (0, 0). Also, there are two points specified at time 5: ; (5, 10) and (5, 0). (The last 0 is implicit). The conflict is ; automatically resolved by pushing the (5, 10) breakpoint back to ; the previous sample, so the actual time will be 5 - 1/sr, where ; sr is the sample rate. ;] pwl(0, 10, 5, 10, 5) @i[; a constant function with the value zero over the time interval ; 0 to 3.5. This is a very degenerate form of pwl. Recall that there ; is an implicit initial point at (0, 0) and a final implicit value of ; 0, so this is really specifying two breakpoints: (0, 0) and (3.5, 0): ;] pwl(3.5) @i[; a linear ramp from 0 to 10 and duration 1. ; Note the ramp returns to zero at time 1. As with the square pulse ; above, the breakpoint (1, 10) is pushed back to the previous sample. ;] pwl(1, 10, 1) @i[; If you really want a linear ramp to reach its final value at the ; specified time, you need to make a signal that is one sample longer. ; The RAMP function does this: ;] ramp(10) @i[; ramp from 0 to 10 with duration 1 + one sample period ; ; RAMP is based on PWL; it is defined in @p(nyquist.lsp). ;] @end(example) @section(Predefined Constants) @label(constants-sec) For convenience and readability, Nyquist pre-defines some constants, mostly based on the notation of the Adagio score language, as follows: @begin(itemize) @b(Dynamics) Note: these dynamics values are subject to change. @begin(display) @t(lppp@index(lppp)) = -12.0 (dB) @t(lpp@index(lpp)) = -9.0 @t(lp@index(lp)) = -6.0 @t(lmp@index(lmp)) = -3.0 @t(lmf@index(lmf)) = 3.0 @t(lf@index(lf)) = 6.0 @t(lff@index(lff)) = 9.0 @t(lfff@index(lfff)) = 12.0 @t(dB0@index(dB0)) = 1.00 @t(dB1@index(dB1)) = 1.122 @t(dB10@index(dB10)) = 3.1623 @end(display) @b(Durations@index(duration notation)) @begin(display) @t(s@index(s)) = Sixteenth@index(Sixteenth note) = 0.25 @t(i@index(i)) = eIghth@index(eIghth note) = 0.5 @t(q@index(q)) = Quarter@index(quarter note) = 1.0 @t(h@index(h)) = Half@index(half note) = 2.0 @t(w@index(w)) = Whole@index(whole note) = 4.0 @t(sd@index(sd), id@index(id), qd@index(qd), hd@index(hd), wd@index(wd)) = dotted durations@index(dotted durations). @t(st@index(st), it@index(it), qt@index(qt), ht@index(ht), wt@index(wt)) = triplet@index(triplet durations) durations. @end(display) @b(Pitches@index(pitch notation)) Pitches are based on an A4 of 440Hz. To achieve a different tuning, set @code(*A4-Hertz*) to the desired frequency for A4, and call @code[(set-pitch-names)]. This will recompute the names listed below with a different tuning. In all cases, the pitch value 69.0 corresponds exactly to 440Hz, but fractional values are allowed, so for example, if you set @code(*A4-Hertz*) to 444 (Hz), then the symbol @code(A4) will be bound to 69.1567, and @code(C4) (middle C), which is normally 60.0, will be 60.1567. @begin(display) @t(c0) = 12.0 @t(cs0, df0) = 13.0 @t(d0) = 14.0 @t(ds0, ef0) = 15.0 @t(e0) = 16.0 @t(f0) = 17.0 @t(fs0, gf0) = 18.0 @t(g0) = 19.0 @t(gs0, af0) = 20.0 @t(a0) = 21.0 @t(as0, bf0) = 22.0 @t(b0) = 23.0 @t(c1) ... @t(b1) = 24.0 ... 35.0 @t(c2) ... @t(b2) = 36.0 ... 47.0 @t(c3) ... @t(b3) = 48.0 ... 59.0 @t(c4) ... @t(b4) = 60.0 ... 71.0 @t(c5) ... @t(b5) = 72.0 ... 83.0 @t(c6) ... @t(b6) = 84.0 ... 95.0 @t(c7) ... @t(b7) = 96.0 ... 107.0 @t(c8) ... @t(b8) = 108.0 ... 119.0 @end(display) @b(Miscellaneous) @begin(display) @codef(ny:all)@pragma(defn)@index(ny:all) = ``all the samples'' (i.e. a big number) = 1000000000 @end(display) @end(itemize) @section(More Examples) More examples can be found in the directory @code(demos), part of the standard Nyquist release. The file @code(demos/examples_home.htm) is an index to all the demo descriptions. In this directory, you will find the following and more: @begin(itemize) How to make arpeggios (@code(demos/arpeggiator.htm) and @code(arp.sal)@index(arpeggiator) Gong sounds by additive synthesis@index(additive synthesis, gongs) (@code(demos/pmorales/b1.lsp) and @code(demos/mateos/gong.lsp)@index(Gong sounds)@index(demos, gong sound) Risset's spectral analysis of a chord (@code(demos/pmorales/b2.lsp))@index(Risset)@index(demos, spectral analysis of a chord) Bell sounds (@code(demos/pmorales/b3.lsp), @code(demos/pmorales/e2.lsp), @code(demos/pmorales/partial.lsp), and @code(demos/mateos/bell.lsp))@index(demos, bell sound)@index(bell sound) Drum sounds by Risset (@code(demos/pmorales/b8.lsp)@index(demos, drum sound)@index(drum sound) Shepard tones (@code(demos/shepard.lsp) and @code(demos/pmorales/b9.lsp))@index(Shepard tones)@index(endless tones) Random signals (@code(demos/pmorales/c1.lsp)) Buzz with formant filters (@code(demos/pmorales/buzz.lsp)@index(vocal sound)@index(demos, formants) Computing samples directly in Lisp (using Karplus-Strong and physical modelling as examples) (@code(demos/pmorales/d1.lsp)@index(demos, sample-by-sample)@index(DSP in Lisp)@index(Lisp DSP)@index(Karplus-Strong synthesis)@index(physical model)@index(flute sound) FM Synthesis examples, including bell@index(bell sound), wood drum@index(wood drum sound), brass sounds@index(brass sound), tuba sound @index(tuba) (@code(demos/mateos/tuba.lsp) and clarinet sounds@index(clarinet sound) (@code(demos/pmorales/e2.lsp)@index(demos, FM synthesis) Rhythmic patterns (@code(demos/rhythm_tutorial.htm)@index(demos, rhythmic pattern) Drum Samples and Drum Machine (@code(demos/plight/drum.lsp)@index(demos, drum machine)@index(drum samples)@index(drum machine). (See Section @ref(drum-machine-sec)). @end(itemize) @chapter(The NyquistIDE Program) @label(jnyqide-chapter) The NyquistIDE program combines many helpful functions and interfaces to help you get the most out of Nyquist. NyquistIDE is implemented in Java, and you will need the Java runtime system or development system installed on your computer to use NyquistIDE. The best way to learn about NyquistIDE is to just use it. This chapter introduces some of the less obvious features. If you are confused by something and you do not find the information you need here, please contact the author. @section(NyquistIDE Overview) The NyquistIDE runs the command-line version of Nyquist as a subtask, so everything that works in Nyquist should work when using the NyquistIDE and vice-versa. Input to Nyquist is usually entered in the top left window of the NyquistIDE. When you type return, if the expression or statement appears to be complete, the expression you typed is sent to Nyquist. Output from Nyquist appears in a window below. You cannot type into or edit the output window text. The normal way to use the NyquistIDE is to create or open one or more files. You edit these files and then click the Load button. To load a file, NyquistIDE saves the file, sets the current directory of Nyquist to that of the file, then issues a @code(load) command to Nyquist. In this case and several others, you may notice that NyquistIDE sends expressions to Nyquist automatically for evaluation. You can always see the commands and their results in the output window. Notice that when you load a selected file window, NyquistIDE uses @code(setdir) to change Nyquist's current directory. This helps to keep the two programs in sync. Normally, you should keep all the files of a project in the same directory and avoid manually changing Nyquist's current directory (i.e. avoid calling @code(setdir) in your code). Arranging windows in the NyquistIDE can be time-consuming, and depending on the operating system, it is possible for a window to get into a position where you cannot drag it to a new position. The Window:Tile menu command can be used to automatically lay out windows in a rational way. There is a preference setting to determine the height of the completion list relative to the height of the output window. @section(The Button Bar) @index(button bar) There are a number of buttons with frequently-used operations. These are: @begin(itemize) Info @itemsep @index(info button)Print information about Nyquist memory utilization, including the number of free cons cells, the number of garbage collections, the total number of cons cells, the total amount of sample buffer memory, and the amount of memory in free sample buffers. Break @itemsep @index(break button)Send a break character to XLISP. This can be used to enter the debugger (the break loop) while a program is running. Resume by typing @code[(co)]. SAL/Lisp @itemsep @index(SAL button)@index(Lisp button)Switch modes. The button names the mode (SAL or Lisp) you will switch to, not the current mode. For example, if you are in Lisp mode and want to type a SAL command, click the SAL button first. Top @itemsep @index(top button)Enters @code[(top)] into Nyquist. If the XLISP prompt is @code(1>) or some other integer followed by ``@code(>)'', clicking the Top button will exit the debug loop and return to the top-level prompt. Replay @itemsep @index(replay button)Enters @code[(r)] into Nyquist. This command replays the last computed sound. F2-F12 @itemsep @index(Fn button)Enters @code[(f2)] etc. into Nyquist. These commands are not built-in, and allow users to define their own custom actions. Browse @itemsep @index(browse button)Equivalent to the Window:Browse menu item. (See Section @ref(browser).) EQ @itemsep @index(eq button)Equivalent to the Window:EQ menu item. (See Section @ref(eq-window-sec).) EnvEdit @itemsep @index(envedit button)Equivalent to the Window:Envelope Edit menu item. (See Section @ref(envelope-editor-sec).) NewFile @itemsep @index(newfile button)Equivalent to the File:New menu item. Opens a new file editing window for creating and loading a Lisp or SAL program file. OpenFile @itemsep @index(openfile button)Equivalent to the File:Open menu item. Opens an existing Lisp or SAL program file for editing and loading. SaveFile @itemsep @index(savefile button)Equivalent to the File:Save menu item (found on the editing window's menu bar). Saves the contents of an editing window to its associated file. Load @itemsep @index(load button)Equivalent to the File:Load menu item (found on the editing window's menu bar). Performs a Save operation, then sends a command to Nyquist that loads the file as a program. Mark @itemsep @index(mark button)Sends a Control-A to Nyquist. While playing a sound, this displays and records the approximate time in the audio stream. (See Section @ref(play-sec) for more detail.) @end(itemize) @section(Command Completion) To help with programming, NyquistIDE maintains a command-completion window. As you type the first letters of function names, NyquistIDE lists matching functions and their parameters in the Completion List window. If you click on an entry in this window, the displayed expression will replace the incompletely typed function name. A preference allows you to match initial letters or any substring of the complete function name. This is controlled by the ``Use full search for code completion'' preference. In addition, if you right click (or under Mac OS X, hold down the Alt/Option key and click) on an entry, NyquistIDE will display documentation for the function. Documentation can come from a local copy or from the online copy (determined by the ``Use online manual instead of local copy'' preference). Documentation can be displayed within the NyquistIDE window or in an external browser (determined by the ``Use window in NyquistIDE for help browser'' preference.) Currently, the external browser option does not seem to locate documentation properly, but this should be fixed in the future. @section(Browser) @label(browser) @index(browser, jnyqide)@index(sound browser, jnyqide) If you click on the Browse button or use the Window:Browse menu command, NyquistIDE will display a browser window that is pre-loaded with a number of Nyquist commands to create sounds. You can adjust parameters, audition the sounds, and capture the expression that creates the sound. In many cases, the expression checks to see if necessary functions are defined, loading files if necessary before playing the sound. If you want to use a sound in your own program, you can often simplify things by explicitly loading the required file just once at the beginning of your file. Since Nyquist now supports a mix of Lisp and SAL, you may find yourself in the position of having code from the browser in one language while you are working in the other. The best way to handle this is to put the code for the sound you want into a function defined in a Lisp (@code(.lsp)) or SAL (@code(.sal)) file. Load the file (from Lisp, use the @code(sal-load) command to load a SAL file), and call the function from the language of your choice. @section(Envelope Editor) @label(envelope-editor-sec) @index(envelope editor) @index(editor for envelopes) @index(graphical envelope editor) The envelope editor allows you graphically to design and edit piece-wise linear and exponential envelopes. The editor maintains a list of envelopes and you select the one to edit or delete using the drop down list in the Saved Envelopes List area. The current envelope appears in the Graphical Envelope Editor area. You can click to add or drag points. Alternatively, you can use the Envelope Points window to select and edit any breakpoint by typing coordinates. The duration of the envelope is controlled by the Stop field in the Range area, and the vertical axis is controlled by the Min and Max fields. When you click the Save button, @i(all) envelopes are written to Nyquist. You can then use the envelope by treating the envelope name as a function. For example, if you define an envelope named ``fast-attack,'' then you can create the envelope within a Nyquist SAL program by writing the expression @code[fast-attack()]. These edited envelopes are saved to a file named @code(workspace.lsp) @index(workspace) in the current directory. The workspace is Nyquist's mechanism for saving data of all kinds (see Section @ref(workspaces-sec)). The normal way to work with workspaces is to (1) load the workspace, i.e. @code[load "workspace"], as soon as you start Nyquist; (2) invoke the envelope editor to change values in the workspace; and (3) save the workspace at any time, especially before you exit NyquistIDE. If you follow these steps, envelopes will be preserved from session to session, and the entire collection of envelopes will appear in the editor. Be sure to make backups of your @code(workspace.lsp) file along with your other project files. The envelope editor can create linear and exponential envelopes. Use the Type pull-down menu to select the type you want. Envelopes can be created using default starting and ending values using @code(pwl) or @code(pwe), or you can specify the initial values using @code(pwlv) or @code(pwev). The envelope editor uses @code(pwl) or @code(pwe) if no point is explicitly entered as the initial or final point. To create a @code(pwlv) or @code(pwev) function, create a point and drag it to the leftmost or rightmost edge of the graphical editing window. You will see the automatically generated default starting or ending point disappear from the graph. Exponential envelopes should never decay to zero. If you enter a zero amplitude, you will see that the envelope remains at zero to the next breakpoint. To get an exponential decay to ``silence,'' try using an amplitude of about 0.001 (about -60dB). To enter small values like this, you can type them into the Amplitude box and click ``Update Point.'' The Load button refreshes the editor from data saved in the Nyquist process. Normally, there is no need to use this because the editor automatically loads data when you open it. @section(Equalizer Editor) @label(eq-window-sec)@index(equalization editor)@index(graphical equalization) The Equalizer Editor provides a graphical EQ interface for creating and adjusting equalizers. Unlike the envelope editor, where you can type any envelope name, equalizers are named @code(eq-0), @code(eq-1), etc., and you select the equalizer to edit using a pull-down menu. The @code(Set) button should be use to record changes. @section(UPIC Editor) @label(upic-editor-sec)@index(UPIC)@index(Xenakis)@index(Iannis Xenakis)The UPIC Editor is inspired by the UPIC system by Iannis Xenakis at the Centre d'Edudes de Mathematique et Automatique Musicales (CEMaMu). The UPIC Editor is accessed by the ``Upic Edit'' menu item in the ``Window'' menu of the NyquistIDE. Once opened, you can draw pitch contours in the main panel by pressing the left mouse button and dragging with the mouse down. Contours represent tones in a frequency vs. time coordinate system. Any contour can be deleted by right-clicking (or shift-clicking on an Apple computer) to select the contour (indicated by the color red), and typing the Delete key. A collection of contours can be saved to a file and later retrieved using the items in the File menu (use the File menu in the UPIC Editor window, not in the main NyquistIDE window.) The file is a SAL program in a special format that can be parsed by the UPIC Editor. The file can also be loaded into Nyquist using the File:Load menu item, or by executing a load command in Nyquist. The panel at the top of the editor offers control over various parameters. The Name box is a Nyquist variable name. This name takes effect when you save a file from the UPIC Editor. The variable name is stored in the file so that when a UPIC Editor-generated file is loaded into Nyquist, the data is assigned to this variable name. The data is a list of contours, where each contour specifies a waveform, an envelope, and a list of time-frequency coordinates. The next item in the panel is the Waveform box. The Waveform box names a waveform for a contour. Default waveforms are sinusoid, triangle, and sawtooth, but you can type in your own names. The currently selected waveform is stored with the contour when it is created (entered by drawing). You cannot change or edit the waveform name associated with a contour once the contour is created, but you can always delete the contour and replace it. The Envelope box names an envelope for a contour. The envelope names a Nyquist function. The default, @code(upic-env) is a trapezoid shape with an onset time and offset time of 10ms. As with waveforms, the envelope is stored with each contour when the contour is created and cannot be edited. The Stop Time box gives the duration of the drawing area in seconds. The Min Freq box gives the minimum frequency (at the bottom of the drawing area), and the Max Freq box gives the maximum frequency (at the top of the drawing area). The vertical frequency axis can use a linear scale corresponding to frequency in Hertz or a logarithmic scale corresponding to semitones. The ``linear'' checkbox selects the linear scale. When @i(any) of these parameters (described in this paragraph and delimited by the border labeled ``Range'' on the control panel) is changed, you must press the Update Range button for the change to take effect. The Background menu lets you display a grid that indicates pitch locations. The ``C's'' item draws a line at C in every visible octave. E.g. middle C is about 260 Hz, so a reference line will be drawn near 260 Hz. Lines will be drawn around 130 Hz (an octave below middle C), and around 520 Hz (an octave above middle C), etc. The ``GrandStaff'' menu item draws reference lines for each line of the grand staff commonly used for piano music. The pitches are G2, B2, D3, F3, A3, E4, G4, B4, D5, and F5. Finally, you can load a picture using the Background:Load Picture... menu item. Then, the Background:Show Picture menu item toggles whether the picture is displayed or not. This feature allows you to trace an image. (For example, see the Sonic Self-Portrait at @code(http://www.cs.cmu.edu/~rbd).) You may wish to use an image editor to lighten the image so that superimposed contours will be more visible. Each change to the Range data, background choice, and each entry of a contour is an action that you can undo or redo with the Undo and Redo buttons. To convert UPIC data into sound, first load @code(upic.sal) and load a file generated by the UPIC Editor. Now, suppose the variable name used is @code(upicdata). You can play the data by writing @begin(example) play upic(upicdata) @end(example) If you created your own names for waveforms or envelopes, you must be sure that these exist before calling the @code(upic) function. Each waveform must be the name of a variable which is set to a Nyquist wave table. (See Section @ref(waveform-sec) for information on how to create a wave table.) Also, each envelope must name a function with no parameters that will return an amplitude envelope. The following is the built-in definition for @code(upic-env): @begin(example) define function upic-env() return env(0.01, 0.01, 0.01, 1, 1, 1) @end(example) To make a custom envelope function named @code(upic-smooth) with a 0.2 second attack and a 0.3 second decay, you could write: @begin(example) define function upic-smooth() return env(0.2, 0.01, 0.3, 1, 1, 1) @end(example) @chapter(Behavioral Abstraction)@index(behavioral abstraction) @label(behavioral-abstraction-sec) In Nyquist, all functions are subject to transformations@index(transformations). You can think of transformations as additional parameters to every function, and functions are free to use these additional parameters in any way. The set of transformation parameters is captured in what is referred to as the @i(transformation environment@index(transformation environment)). (Note that the term @i(environment) is heavily overloaded in computer science. This is yet another usage of the term.) Behavioral abstraction is the ability of functions to adapt their behavior to the transformation environment. This environment may contain certain abstract notions, such as loudness, stretching a sound in time, etc. These notions will mean different things to different functions. For example, an oscillator should produce more periods of oscillation in order to stretch its output. An envelope, on the other hand, might only change the duration of the sustain portion of the envelope in order to stretch. Stretching a sample could mean resampling it to change its duration by the appropriate amount. Thus, transformations in Nyquist are not simply operations on signals. For example, if I want to stretch a note, it does not make sense to compute the note first and then stretch the signal. Doing so would cause a drop in the pitch. Instead, a transformation modifies the @i(transformation environment) in which the note is computed. Think of transformations as making requests to functions. It is up to the function to carry out the request. Since the function is always in complete control, it is possible to perform transformations with ``intelligence;'' that is, the function can perform an appropriate transformation, such as maintaining the desired pitch and stretching only the ''sustain'' portion of an envelope to obtain a longer note. @section(The Environment)@index(environment) @label(environment-sec) The transformation environment consists of a set of special variables. These variables should not be read directly and should @i(never) be set directly by the programmer. Instead, there are functions to read them, and they are automatically set and restored by transformation operators, which will be described below. The transformation environment consists of the following elements. Although each element has a ``standard interpretation,'' the designer of an instrument or the composer of a complex behavior is free to interpret the environment in any way. For example, a change in @code(*loud*) may change timbre more than amplitude, and @code(*transpose*) may be ignored by percussion instruments: @begin(description) @codef(*warp*@pragma(defn)@index(*warp*))@\Time transformation, including time shift, time stretch, and continuous time warp. The value of @code[*warp*] is interpreted as a function from logical (local score) time to physical (global real) time. Do not access @code(*warp*) directly. Instead, use @code[local-to-global(@i(t))] to convert from a logical (local) time to real (global) time. Most often, you will call @code[local-to-global(0)]. Several transformation operators operate on @code[*warp*], including @i(at) (@code(@@)), @i(stretch) (@code(~)), and @code(warp). See also @code[get-duration()] and @code[get-warp()]. @codef(*loud*@pragma(defn)@index(*loud*))@\Loudness, expressed in decibels. The default (nominal) loudness is 0.0 dB (no change). Do not access @code(*loud*) directly. Instead, use @code[get-loud()] to get the current value of @code(*loud*) and either @code(loud) or @code(loud-abs) to modify it. @codef(*transpose*@pragma(defn)@index(*transpose*))@\Pitch transposition, expressed in semitones. (Default: 0.0). Do not access @code(*transpose*) directly. Instead, use @code[get-transpose()] to get the current value of @code(*transpose*) and either @code(transpose) or @code(transpose-abs) to modify it. @codef(*sustain*@pragma(defn)@index(*sustain*))@\The ``sustain,'' ``articulation,'' ``duty factor,'' or amount by which to separate or overlap sequential notes. For example, staccato might be expressed with a @code(*sustain*) of 0.5, while very legato playing might be expressed with a @code(*sustain*) of 1.2. Specifically, @code(*sustain*) stretches the duration of notes (sustain) without affecting the inter-onset time (the rhythm). Do not access @code(*sustain*) directly. Instead, use @code[get-sustain()] to get the current value of @code(*sustain*) and either @code(sustain) or @code(sustain-abs) to modify it. @codef(*start*@pragma(defn)@index(*start*))@\Start time of a clipping region. @i(Note:) unlike the previous elements of the environment, @code(*start*) has a precise interpretation: no sound should be generated before @code(*start*). This is implemented in all the low-level sound functions, so it can generally be ignored. You can read @code(*start*) directly, but use @code(extract) or @code(extract-abs) to modify it. @p(Note 2:) Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, @code(*start*) is not fully implemented. @codef(*stop*@pragma(defn)@index(*stop*))@\Stop time of clipping region. By analogy to @code(*start*), no sound should be generated after this time. @code(*start*) and @code(*stop*) allow a composer to preview a small section of a work without computing it from beginning to end. You can read @code(*stop*) directly, but use @code(extract) or @code(extract-abs) to modify it. @p(Note:) Due to some internal confusion between the specified starting time and the actual starting time of a signal after clipping, @code(*stop*) is not fully implemented. @codef(*control-srate*@pragma(defn)@index(*control-srate*))@\Sample rate of control signals. This environment element provides the default sample rate for control signals. There is no formal distinction between a control signal and an audio signal. You can read @code(*control-srate*) directly, but use @code(control-srate) or @code(control-srate-abs) to modify it. @codef(*sound-srate*@pragma(defn)@index(*sound-srate*))@\Sample rate of musical sounds. This environment element provides the default sample rate for musical sounds. You can read @code(*sound-srate*) directly, but use @code(sound-srate) or @code(sound-srate-abs) to modify it. @end(description) @section(Sequential Behavior)@index(sequential behavior) Previous examples have shown the use of @code(seq), the sequential behavior operator. We can now explain @code(seq) in terms of transformations. Consider the simple expression: @begin(Example) play seq(my-note(c4, q), my-note(d4, i)) @end(example) The idea is to create the first note at time 0, and to start the next note when the first one finishes. This is all accomplished by manipulating the environment. In particular, @code[*warp*] is modified so that what is locally time 0 for the second note is transformed, or warped, to the logical stop time of the first note. One way to understand this in detail is to imagine how it might be executed: first, @code(*warp*) is set to an initial value that has no effect on time, and @code[my-note(c4, q)] is evaluated. A sound is returned and saved. The sound has an ending time, which in this case will be @code(1.0) because the duration @code(q) is @code(1.0). This ending time, @code(1.0), is used to construct a new @code[*warp*] that has the effect of shifting time by 1.0. The second note is evaluated, and will start at time 1. The sound that is returned is now added to the first sound to form a composite sound, whose duration will be @code(2.0). @code(*warp*) is restored to its initial value. Notice that the semantics of @code(seq) can be expressed in terms of transformations. To generalize, the operational rule for @code(seq) is: evaluate the first behavior according to the current @code(*warp*). Evaluate each successive behavior with @code(*warp*) modified to shift the new note's starting time to the ending time of the previous behavior. Restore @code(*warp*) to its original value and return a sound which is the sum of the results. In the Nyquist implementation, audio samples are only computed when they are needed, and the second part of the @code(seq) is not evaluated until the ending time (called the logical stop time) of the first part. It is still the case that when the second part is evaluated, it will see @code(*warp*) bound to the ending time of the first part. A language detail: Even though Nyquist defers evaluation of the second part of the @code(seq), the expression can reference variables according to ordinary Lisp/SAL scope rules. This is because the @code(seq) captures the expression in a closure, which retains all of the variable bindings. @section(Simultaneous Behavior)@index(Simultaneous Behavior) Another operator is @code(sim), which invokes multiple behaviors at the same time. For example, @begin(example) play 0.5 * sim(my-note(c4, q), my-note(d4, i)) @end(example) will play both notes starting at the same time. The operational rule for @code(sim) is: evaluate each behavior at the current @code(*warp*) and return the sum of the results. (In SAL, the @code(sim) function applied to sounds is equivalent to adding them with the infix @code(+) operator. The following section illustrates two concepts: first, a @i(sound) is not a @i(behavior), and second, the @code(sim) operator and and the @code(at) transformation can be used to place sounds in time. @section(Sounds vs. Behaviors)@index(Sounds vs. Behaviors) The following example loads a sound from a file in the current directory and stores it in @code(a-snd): @begin(example) @i[; load a sound ;] set a-snd = s-read(strcat(current-path(), "demo-snd.aiff")) @i[; play it ;] play a-snd @end(example) One might then be tempted to write the following: @begin(example) play seq(a-snd, a-snd) @i(;WRONG!) @end(example) Why is this wrong? Recall that @code(seq) works by modifying @code(*warp*), not by operating on sounds. So, @code(seq) will proceed by evaluating @code(a-snd) with different values of @code(*warp*). However, the result of evaluating @code(a-snd) (a variable) is always the same sound, regardless of the environment; in this case, the second @code(a-snd) @i(should) start at time @code(0.0), just like the first. In this case, after the first sound ends, Nyquist is unable to ``back up'' to time zero, so in fact, this @i(will) play two sounds in sequence, but that is a result of an implementation detail rather than correct program execution. In fact, a future version of Nyquist might (correctly) stop and report an error when it detects that the second sound in the sequence has a real start time that is before the requested one. How then do we obtain a sequence of two sounds properly? What we really need here is a behavior that transforms a given sound according to the current transformation environment. That job is performed by @code(cue). For example, the following will behave as expected, producing a sequence of two sounds: @begin(example) play seq(cue(a-snd), cue(a-snd)) @end(example) This example is correct because the second expression will shift the sound stored in @code(a-snd) to start at the end time of the first expression. The lesson here is very important: @p(sounds are not behaviors!) Behaviors are computations that generate sounds according to the transformation environment. Once a sound has been generated, it can be stored, copied, added to other sounds, and used in many other operations, but sounds are @i(not) subject to transformations. To transform a sound, use @code(cue), @code(sound), or @code(control). The differences between these operations are discussed later. For now, here is a ``cue sheet'' style score that plays 4 copies of @code(a-snd): @begin(example) @i[; use sim and at to place sounds in time ;] play sim(cue(a-snd) @@ 0.0, cue(a-snd) @@ 0.7, cue(a-snd) @@ 1.0, cue(a-snd) @@ 1.2) @end(example) @section(The At Transformation)@index(At Transformation) The second concept introduced by the previous example is the @code(@@) operation, which shifts the @code(*warp*) component of the environment. For example, @begin(example) cue(a-snd) @@ 0.7 @end(example) can be explained operationally as follows: modify @code[*warp*] by shifting it by @code(0.7) and evaluate @code[cue(a-snd)]. Return the resulting sound after restoring @code(*warp*) to its original value. Notice how @code(@@) is used inside a @code(sim) construct to locate copies of @code(a-snd) in time. This is the standard way to represent a note-list or a cue-sheet in Nyquist. This also explains why sounds need to be @code(cue)'d in order to be shifted in time or arranged in sequence. If this were not the case, then @code(sim) would take all of its parameters (a set of sounds) and line them up to start at the same time. But @code[cue(a-snd) @@ 0.7] is just a sound, so @code(sim) would ``undo'' the effect of @code(@@), making all of the sounds in the previous example start simultaneously, in spite of the @code(@@)! Since @code(sim) respects the intrinsic starting times of sounds, a special operation, @code(cue), is needed to create a new sound with a new starting time. @section(The Stretch Transformation)@index(Stretch Transformation) In addition to At (denoted in SAL by the @code(@@) operator, the Stretch transformation is very important. It appeared in the introduction, and it is denoted in SAL by the @code(~) operator (or in LISP by the @code(stretch) special form). Stretch also operates on the @code(*warp*) component of the environment. For example, @begin(example) osc(c4) ~ 3 @end(example) does the following: modify @code(*warp*), scaling the degree of "stretch" by 3, and evaluate @code[osc(c4)]. The @code(osc) behavior uses the stretch factor to determime the duration, so it will return a sound that is 3 seconds long. Restore @code(*warp*) to its original value. Like At, Stretch only affects behaviors. @code(a-snd ~ 10) is equivalent to @code(a-snd) because @code(a-snd) is a sound, not a behavior. Behaviors are functions that compute sounds according to the environment and return a sound. @section(Nested Transformations)@index(Nested Transformations) Transformations can be combined using nested expressions. For example, @begin(example) sim(cue(a-snd), loud(6.0, cue(a-snd) @@ 3)) @end(example) scales the amplitude as well as shifts the second entrance of @code(a-snd). Why use @code(loud) instead of simply multiplying @code(a-snd) by some scale factor? Using @code(loud) gives the behavior the chance to implement the abstract property @i(loudness) in an appropriate way, e.g. by including timbral changes. In this case, the behavior is @code(cue), which implements @i(loudness) by simple amplitude scaling, so the result is equivalent to multiplication by @code(db-to-linear(6.0)). Transformations can also be applied to groups of behaviors: @begin(example) loud(6.0, sim(cue(a-snd) @@ 0.0, cue(a-snd) @@ 0.7)) @end(example) @section(Defining Behaviors)@index(Defining Behaviors) Groups of behaviors can be named using @code(define) (we already saw this in the definitions of @code(my-note) and @code(env-note)). Here is another example of a behavior definition and its use. The definition has one parameter: @begin(example) define function snds(dly) return sim(cue(a-snd) @@ 0.0, cue(a-snd) @@ 0.7, cue(a-snd) @@ 1.0, cue(a-snd) @@ (1.2 + dly)) play snds(0.1) play loud(0.25, snds(0.3) ~ 0.9) @end(example) In the last line, @code(snds) is transformed: the transformations will apply to the @code(cue) behaviors within @code(snds). The @code(loud) transformation will scale the sounds by @code(0.25), and the @i(stretch) (@code(~)) will apply to the shift (@code(@@)) amounts @code(0.0), @code(0.7), @code(1.0), and @code[1.2 + dly]. The sounds themselves (copies of @code(a-snd)) will not be stretched because @code(cue) never stretches sounds. Section @ref(transformations-sec) describes the full set of transformations. @section(Overriding Default Transformations) In Nyquist, behaviors are @i(the) important abstraction mechanism. A behavior represents a class of related functions or sounds. For example, a behavior can represent a musical note. When a note is stretched, it usually means that the tone sustains for more oscillations, but if the ``note'' is a drum roll, the note sustains by more repetitions of the component drum strokes. The concept of sustain is so fundamental that we do not really think of different note durations as being different instances of an abstract behavior, but in a music programming language, we need a way to model these abtract behaviors. As the tone and drum roll examples show, there is no one right way to ``stretch,'' so the language must allow users to define exactly what it means to stretch. By extension, the Nyquist programmer can define how all of the transformations affect different behaviors. To make programming easier, almost all Nyquist sounds are constructed from primitive behaviors that obey the environment in obvious ways: Stretch transformations make things longer and At transformations shift things in time. But sometimes you have to override the default behaviors. Maybe the attack phase of an envelope should not stretch when the note is stretched, or maybe when you stretch a trill, you should get more notes rather than a slower trill. To override default behaviors, you almost always follow the same programming pattern: first, capture the environment in a local variable; then, use one of the absolute transformations to ``turn off'' the environment's effect and compute the sound as desired. The following example creates a very simple envelope with a fixed rise time to illustrate the technique. @begin(example) define function two-phase-env(rise-time) begin with dur = get-duration(1) return pwl(rise-time, 1, dur) ~~ 1.0 end @end(example) To ``capture the environment in a local variable,'' a @code(with) construct is used to create the local variable @code(dur) and set it to the value of @code[get-duration(1)], which answers the question: ``If I apply use the environment to stretch something whose nominal duration is 1, what is the resulting duration?'' (Since time transformations can involve continuous time deformations, this question is not as simple as it may sound, so please use the provided function rather than peeking inside the @code(*warp*) structure and trying to do it yourself.) Next, we ``turn off'' stretching using the @code(stretch-abs) form, which in SAL is denoted by the @code(~~) operator. Finally, we are ready to compute the envelope using @code(pwl). Here, we use absolute durations. The first breakpoint is at @code(rise-time), so the attack time is given by the @code(rise-time) parameter. The @code(pwl) decays back to zero at time @code(dur), so the overall duration matches the duration expected from the environment encountered by this instance of @code(two-phase-env). Note, however, that since the @code(pwl) is evaluated in a different environment established by @code(~~), it is not stretched (or perhaps more accurately, it is stretched by 1.0). This is good because it means @code(rise-time) will not be stretched, but we must be careful to extend the envelope to @code(dur) so that it has the expected duration. @section(Sample Rates) @index(sample rates) The global environment contains @code(*sound-srate*) and @code(*control-srate*), which determine the sample rates of sounds and control signals. These can be overridden at any point by the transformations @code(sound-srate-abs) and @code(control-srate-abs); for example, @begin(example) sound-srate-abs(44100.0, osc(c4) @end(example) will compute a tone using a 44.1Khz sample rate even if the default rate is set to something different. @index(default sample rate) As with other components of the environment, you should @i(never) change @code(*sound-srate*) or @code(*control-srate*) directly. The global environment is determined by two additional variables: @code(*default-sound-srate*) and @code(*default-control-srate*). You can add lines like the following to your @code(init.lsp) file to change the default global environment: @begin(example) (setf *default-sound-srate* 44100.0) (setf *default-control-srate* 1102.5) @end(example) You can also do this using preferences in NyquistIDE. If you have already started Nyquist and want to change the defaults, the preferences or the following functions can be used: @begin(example) exec set-control-srate(1102.5)@index(set-control-srate) exec set-sound-srate(22050.0)@index(set-sound-srate) @end(example) These modify the default values and reinitialize the Nyquist environment. @chapter(Continuous Transformations and Time Warps) @label(warp-chap) Nyquist transformations were discussed in the previous chapter, but all of the examples used scalar values. For example, we saw the @code[loud] transformation used to change loudness by a fixed amount. What if we want to specify a crescendo, where the loudness changes gradually over time? It turns out that all transformations can accept signals as well as numbers, so transformations can be continuous over time. This raises some interesting questions about how to interpret continuous transformations. Should a loudness transformation apply to the internal details of a note or only affect the initial loudness? It might seem unnatural for a decaying piano note to perform a crescendo. On the other hand, a sustained trumpet sound should probably crescendo continuously. In the case of time warping (tempo changes), it might be best for a drum roll to maintain a steady rate, a trill may or may not change rates with tempo, and a run of sixteenth notes will surely change its rate. These issues are complex, and Nyquist cannot hope to automatically do the right thing in all cases. However, the concept of behavioral abstraction provides an elegant solution. Since transformations merely modify the environment, behaviors are not forced to implement any particular style of transformation. Nyquist is designed so that the default transformation is usually the right one, but it is always possible to override the default transformation to achieve a particular effect. @section(Simple Transformations) The ``simple'' transformations affect some parameter, but have no effect on time itself. The simple transformations that support continuously changing parameters are: @code(sustain), @code(loud), and @code(transpose). As a first example, Let us use @code(transpose) to create a chromatic scale. First define a sequence of tones at a steady pitch. The @code(seqrep) ``function'' works like @code(seq) except that it creates copies of a sound by evaluating an expression multiple times. Here, @code(i) takes on 16 values from 0 to 15, and the expression for the sound could potentially use @code(i). Technically, @code(seqrep) is not really a function but an abbreviation for a special kind of loop construct. @begin(example) define function tone-seq() return seqrep(i, 16, osc-note(c4) ~ 0.25) @end(example) Now define a linearly increasing ramp to serve as a transposition function: @begin(code) define function pitch-rise() return sustain-abs(1.0, 16 * ramp() ~ 4) @end(code) This ramp has a duration of 4 seconds, and over that interval it rises from 0 to 16 (corresponding to the 16 semitones we want to transpose). The ramp is inside a @code(sustain-abs) transformation, which prevents a @code(sustain) transformation from having any effect on the ramp. (One of the drawbacks of behavioral abstraction is that built-in behaviors sometimes do the wrong thing implicitly, requiring some explicit correction to turn off the unwanted transformation.) Now, @code(pitch-rise) is used to transpose @code(tone-seq): @begin(code) define function chromatic-scale() return transpose(pitch-rise(), tone-seq()) @end(code) Similar transformations can be constructed to change the sustain or ``duty factor'' of notes and their loudness. The following expression plays the @code(chromatic-scale) behavior with increasing note durations. The rhythm is unchanged, but the note length changes from staccato to legato: @begin(code) play sustain((0.2 + ramp()) ~ 4, chromatic-scale()) @end(code) The resulting sustain function will ramp from 0.2 to 1.2. A sustain of 1.2 denotes a 20 percent overlap between notes. The @code(sum) has a stretch factor of 4, so it will extend over the 4 second duration of @code(chromatic-scale). If you try this, you will discover that the @code(chromatic-scale) no longer plays a chromatic scale. You will hear the first 4 notes going up in intervals of 5 semitones (perfect fourths) followed by repeated pitches. What is happening is that the @code(sustain) operation applies to @code(pitch-rise) in addition to @code(tone-seq), so now the 4s ramp from 0 to 16 becomes a 0.8s ramp. To fix this problem, we need to shield @code(pitch-rise) from the effect of @code(sustain) using the @code(sustain-abs) transformation. Here is a corrected version of @code(chromatic-scale): @begin(code) define function chromatic-scale() return transpose(sustain-abs(1, pitch-rise()), tone-seq()) @end(code) What do these transformations mean? How did the system know to produce a pitch rise rather than a continuous glissando? This all relates to the idea of behavioral abstraction. It is possible to design sounds that @i(do) glissando under the transpose transform, and you can even make sounds that @i(ignore) transpose altogether. As explained in Chapter @ref(behavioral-abstraction-sec), the transformations modify the environment, and behaviors can reference the environment to determine what signals to generate. All built-in functions, such as @code(osc), have a default behavior. The default behavior for sound primitives under @code(transpose), @code(sustain), and @code(loud) transformations is to sample the environment at the beginning of the note. Transposition is not quantized to semitones or any other scale, but in our example, we arranged for the transposition to work out to integer numbers of semitones, so we obtained a chromatic scale anyway. Transposition only applies to the oscillator and sampling primitives @code(osc), @code(partial), @code(sampler), @code(sine), @code(fmosc), and @code(amosc). Sustain applies to @code(osc), @code(env), @code(ramp), and @code(pwl). (Note that @code(partial), @code(amosc), and @code(fmosc) get their durations from the modulation signal, so they may indirectly depend upon the sustain.) Loud applies to @code(osc), @code(sampler), @code(cue), @code(sound), @code(fmosc), and @code(amosc). (But not @code(pwl) or @code(env).) @section(Time Warps) The most interesting transformations have to do with transforming time itself. The @code(warp) transformation provides a mapping function from logical (score) time to real time. The slope of this function tells us how many units of real time are covered by one unit of score time. This is proportional to 1/tempo. A higher slope corresponds to a slower tempo. To demonstrate @code(warp), we will define a time warp function using @code(pwl): @begin(example) define function warper() return pwl(0.25, .4, .75, .6, 1.0, 1.0, 2.0, 2.0, 2.0) @end(example) This function has an initial slope of .4/.25 = 1.6. It may be easier to think in reciprocal terms: the initial tempo is .25/.4 = .625. Between 0.25 and 0.75, the tempo is .5/.2 = 2.5, and from 0.75 to 1.0, the tempo is again .625. It is important for warp functions to completely span the interval of interest (in our case it will be 0 to 1), and it is safest to extend a bit beyond the interval, so we extend the function on to 2.0 with a tempo of 1.0. Next, we stretch and scale the @code(warper) function to cover 4 seconds of score time and 4 seconds of real time: @begin(example) define function warp4() return 4 * warper() ~ 4 @end(example) @begin(figure) @center(@graphic((height = 3.25 in, width = 3.5 in, magnify = 0.5, postscript = "warpfig.ps")) @html(

    ) @fillcaption{The result of @code[(warp4)], intended to map 4 seconds of score time into 4 seconds of real time. The function extends beyond 4 seconds (the dashed lines) to make sure the function is well-defined at location (4, 4). Nyquist sounds are ordinarily open on the right.} @tag(warp-fig) @end(figure) Figure @ref(warp-fig) shows a plot of this warp function. Now, we can warp the tempo of the @code(tone-seq) defined above using @code(warp4): @begin(example) play warp(warp4(), tone-seq()) @end(example) Figure @ref(warp-notes-fig) shows the result graphically. Notice that the durations of the tones are warped as well as their onsets. Envelopes are not shown in detail in the figure. Because of the way @code(env) is defined, the tones will have constant attack and decay times, and the sustain will be adjusted to fit the available time. @begin(figure) @center(@graphic((height = 1.75 in, width = 6.75 in, magnify = 1.0, postscript = "warpnotesfig.ps")) @html(

    ) @fillcaption[When @code{(warp4)} is applied to @code{(tone-seq-2)}, the note onsets and durations are warped.] @tag(warp-notes-fig) @end(figure) @section(Abstract Time Warps) We have seen a number of examples where the default behavior did the ``right thing,'' making the code straightforward. This is not always the case. Suppose we want to warp the note onsets but not the durations. We will first look at an incorrect solution and discuss the error. Then we will look at a slightly more complex (but correct) solution. The default behavior for most Nyquist built-in functions is to sample the time warp function at the nominal starting and ending score times of the primitive. For many built-in functions, including @code(osc), the starting logical time is 0 and the ending logical time is 1, so the time warp function is evaluated at these points to yield real starting and stopping times, say 15.23 and 16.79. The difference (e.g. 1.56) becomes the signal duration, and there is no internal time warping. The @code(pwl) function behaves a little differently. Here, each breakpoint is warped individually, but the resulting function is linear between the breakpoints. A consequence of the default behavior is that notes stretch when the tempo slows down. Returning to our example, recall that we want to warp only the note onset times and not the duration. One would think that the following would work: @begin(example) define function tone-seq-2 () return seqrep(i, 16, osc-note(c4) ~~ 0.25) play warp(warp4(), tone-seq-2()) @end(example) Here, we have redefined @code(tone-seq), renaming it to @code(tone-seq-2) and changing the stretch (@code(~)) to absolute stretch (@code(~~)). The absolute stretch should override the warp function and produce a fixed duration. If you play the example, you will hear steady sixteenths and no tempo changes. What is wrong? In a sense, the ``fix'' works too well. Recall that sequences (including @code(seqrep)) determine the starting time of the next note from the logical stop time of the previous sound in the sequence. When we forced the stretch to 0.25, we also forced the logical stop time to 0.25 real seconds from the beginning, so every note starts 0.25 seconds after the previous one, resulting in a constant tempo. Now let us design a proper solution. The trick is to use absolute stretch (@code(~~)) as before to control the duration, but to restore the logical stop time to a value that results in the proper inter-onset time interval: @begin(example) define function tone-seq-3() return seqrep(i, 16, set-logical-stop(osc-note(c4) ~~ 0.25, 0.25)) play warp(warp4(), tone-seq-3()) @end(example) Notice the addition of @code(set-logical-stop) enclosing the absolute stretch (@code(~~)) expression to set the logical stop time. A possible point of confusion here is that the logical stop time is set to 0.25, the same number given to @code(~~)! How does setting the logical stop time to 0.25 result in a tempo change? When used within a @code(warp) transformation, the second argument to @code(set-logical-stop) refers to @i(score) time rather than @i(real) time. Therefore, the score duration of 0.25 is warped into real time, producing tempo changes according to the enviroment. Figure @ref(warp-onset-fig) illustrates the result graphically. @begin(figure) @center(@graphic((height = 1.75 in, width = 6.75 in, magnify = 1.0, postscript = "warponsetfig.ps")) @html(

    ) @fillcaption[When @code[(warp4)] is applied to @code[(tone-seq-3)], the note onsets are warped, but not the duration, which remains a constant 0.25 seconds. In the fast middle section, this causes notes to overlap. Nyquist will sum (mix) them.] @tag(warp-onset-fig) @end(figure) @section(Nested Transformations) Transformations can be nested. In particular, a simple transformation such as transpose can be nested within a time warp transformation. Suppose we want to warp our chromatic scale example with the @code(warp4) time warp function. As in the previous section, we will show an erroneous simple solution followed by a correct one. The simplest approach to a nested transformation is to simply combine them and hope for the best: @begin(example) play warp(warp4(), transpose(pitch-rise(), tone-seq())) @end(example) This example will not work the way you might expect. Here is why: the warp transformation applies to the @code[(pitch-rise)] expression, which is implemented using the @code(ramp) function. The default behavior of @code(ramp) is to interpolate linearly (in real time) between two points. Thus, the ``warped'' @code(ramp) function will not truly reflect the internal details of the intended time warp. When the notes are moving faster, they will be closer together in pitch, and the result is not chromatic. What we need is a way to properly compose the warp and ramp functions. If we continuously warp the ramp function in the same way as the note sequence, a chromatic scale should be obtained. This will lead to a correct solution. Here is the modified code to properly warp a transposed sequence. Note that the original sequence is used without modification. The only complication is producing a properly warped transposition function: @begin(example) play warp(warp4(), transpose( control-warp(get-warp(), warp-abs(nil, pitch-rise())), tone-seq())) @end(example) To properly warp the @code(pitch-rise) transposition function, we use @code(control-warp), which applies a warp function to a function of score time, yielding a function of real time. We need to pass the desired function to @code(control-warp), so we fetch it from the environment with @code[get-warp()]. Finally, since the warping is done here, we want to shield the @code(pitch-rise) expression from further warping, so we enclose it in @code[warp-abs(nil, ...)]. @i(An aside:) This last example illustrates a difficulty in the design of Nyquist. To support behavioral abstraction universally, we must rely upon behaviors to ``do the right thing.'' In this case, we would like the @code(ramp) function to warp continuously according to the environment. But this is inefficient and unnecessary in many other cases where @code(ramp) and especially @code(pwl) are used. (@code(pwl) warps its breakpoints, but still interpolates linearly between them.) Also, if the default behavior of primitives is to warp in a continuous manner, this makes it difficult to build custom abstract behaviors. The final vote is not in. @chapter(More Examples) This chapter explores Nyquist through additional examples. The reader may wish to browse through these and move on to Chapter @ref(lisp-chap), which is a reference section describing Nyquist functions. @section(Stretching Sampled Sounds)@index(Stretching Sampled Sounds) This example illustrates how to stretch a sound, resampling it in the process. Because sounds in Nyquist are @i(values) that contain the sample rate, start time, etc., use @code(sound) to convert a sound into a behavior that can be stretched, e.g. @code[sound(a-snd)]. This behavior stretches a sound according to the stretch factor in the environment, set using @code(stretch). For accuracy and efficiency, Nyquist does not resample a stretched sound until absolutely necessary. The @code(force-srate) function is used to resample the result so that we end up with a ``normal'' sample rate that is playable on ordinary sound cards. @begin(example) @i[; if a-snd is not loaded, load sound sample: ;] if not(boundp(quote(a-snd))) then set a-snd = s-read("demo-snd.aiff") @i[; the SOUND operator shifts, stretches, clips and scales ; a sound according to the current environment ;] define function ex23() play force-srate(*default-sound-srate*, sound(a-snd) ~ 3.0) define function down() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.2, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.6)) play down() @i[; that was so much fun, let's go back up: ;] define function up() return force-srate(*default-sound-srate*, seq(sound(a-snd) ~ 0.5, sound(a-snd) ~ 0.4, sound(a-snd) ~ 0.3, sound(a-snd) ~ 0.2)) @i[; and write a sequence ;] play seq(down(), up(), down()) @end(example) Notice the use of the @code(sound) behavior as opposed to @code(cue). The @code(cue) behavior shifts and scales its sound according to @code(*warp*) and @code(*loud*), but it does not change the duration or resample the sound. In contrast, @code(sound) not only shifts and scales its sound, but it also stretches it by resampling or changing the effective sample rate according to @code(*warp*). If @code[*warp*] is a continuous warping function, then the sound will be stretched by time-varying amounts. (The @code(*transpose*) element of the environment is ignored by both @code(cue) and @code(sound).) @p(Note:) @code(sound) may use linear interpolation rather than a high-quality resampling algorithm. In some cases, this may introduce errors audible as noise. Use @code(resample) (see Section @ref(resample-sec)) for high-quality interpolation. In the functions @code(up) and @code(down), the @code(*warp*) is set by @i(stretch) (@code(~)), which simply scales time by a constant scale factor. In this case, @code(sound) can ``stretch'' the signal simply by changing the sample rate without any further computation. When @code(seq) tries to add the signals together, it discovers the sample rates do not match and uses linear interpolation to adjust all sample rates to match that of the first sound in the sequence. The result of @code(seq) is then converted using @code(force-srate) to convert the sample rate, again using linear interpolation. It would be slightly better, from a computational standpoint, to apply @code(force-srate) individually to each stretched sound rather than applying @code(force-srate) after @code(seq). Notice that the overall duration of @code[sound(a-snd) ~ 0.5] will be half the duration of @code(a-snd). @section(Saving Sound Files)@index(Saving Sound Files) So far, we have used the @code(play) command to play a sound. The @code(play) command works by writing a sound to a file while simultaneously playing it. This can be done one step at a time, and it is often convenient to save a sound to a particular file for later use: @begin(example) @i[; write the sample to a file, ; the file name can be any Unix filename. Prepending a "./" tells ; s-save to not prepend *default-sf-dir* ;] exec s-save(a-snd, 1000000000, "./a-snd-file.snd") @i[; play a file ; play command normally expects an expression for a sound ; but if you pass it a string, it will open and play a ; sound file] play "./a-snd-file.snd" @i[; delete the file (do this with care!) ; only works under Unix (not Windows)] exec system("rm ./a-snd-file.snd") @i[; now let's do it using a variable as the file name ;] set my-sound-file = "./a-snd-file.snd" exec s-save(a-snd, 1000000000, my-sound-file) @i[; play-file is a function to open and play a sound file] exec play-file(my-sound-file) exec system(strcat("rm ", my-sound-file)) @end(example) This example shows how @code(s-save) can be used to save a sound to a file. This example also shows how the @code(system) function can be used to invoke Unix shell commands, such as a command to play a file or remove it. Finally, notice that @code(strcat) can be used to concatenate a command name to a file name to create a complete command that is then passed to @code(system). (This is convenient if the sound file name is stored in a parameter or variable.) @section(Memory Space and Normalization) @label(normalization-sec) @index(normalization)@index(peak amplitude)@index(maximum amplitude)@index(clip)@index(s-max)@index(s-min)@index(rescaling)@index(not enough memory for normalization) Sound samples take up lots of memory, and often, there is not enough primary (RAM) memory to hold a complete composition. For this reason, Nyquist can compute sounds incrementally, saving the final result on disk. @i(However,) Nyquist can also save sounds in memory so that they can be reused efficiently. In general, if a sound is saved in a global variable, memory will be allocated as needed to save and reuse it. The standard way to compute a sound and write it to disk is to pass an expression to the @code(play) command: @begin(example) play my-composition() @end(example) @label(peak-ex-sec) Often it is nice to @i(normalize) sounds so that they use the full available dynamic range of 16 bits. Nyquist has an automated facility to help with normalization. By default, Nyquist computes up to 1 million samples (using about 4MB of memory) looking for the peak. The entire sound is normalized so that this peak will not cause clipping. If the sound has less than 1 million samples, or if the first million samples are a good indication of the overall peak, then the signal will not clip. With this automated normalization technique, you can choose the desired peak value by setting @code(*autonorm-target*), which is initialized to 0.9. The number of samples examined is @code(*autonorm-max-samples*), initially 1 million. You can turn this feature off by executing: @begin(example) exec autonorm-off()@index(autonorm-off) @end(example) and turn it back on by typing: @begin(example) exec autonorm-on()@index(autonorm-on) @end(example) This normalization technique is in effect when @code(*autonorm-type*) is @code(quote(lookahead)), which is the default. An alternative normalization method uses the peak value from the previous call to @code(play). After playing a file, Nyquist can adjust an internal scale factor so that if you play the same file again, the peak amplitude will be @code(*autonorm-target*), which is initialized to 0.9. This can be useful if you want to carefully normalize a big sound that does not have its peak near the beginning. To select this style of normalization, set @code(*autonorm-type*) to the (quoted) atom @code(quote(previous)). You can also create your own normalization method in Nyquist. The @code(peak) function computes the maximum value of a sound. The peak value is also returned from the @code(play) macro. You can normalize in memory if you have enough memory; otherwise you can compute the sound twice. The two techniques are illustrated here: @begin(example) @i[; normalize in memory. First, assign the sound to a variable so ; it will be retained:] set mysound = sim(osc(c4), osc(c5)) @i[; now compute the maximum value (ny:all is 1 giga-samples, you may want a ; smaller constant if you have less than 4GB of memory:] set mymax = snd-max(mysound, NY:ALL) display "Computed max", mymax @i[; now write out and play the sound from memory with a scale factor:] play mysound * (0.9 / mymax) @i[; if you don't have space in memory, here's how to do it:] define function myscore() return sim(osc(c4), osc(c5)) @i[; compute the maximum:] set mymax = snd-max(list(quote(myscore)), NY:ALL) display "Computed max", mymax @i[; now we know the max, but we don't have a the sound (it was garbage ; collected and never existed all at once in memory). Compute the sound ; again, this time with a scale factor:] play myscore() * (0.9 / mymax) @end(example) You can also write a sound as a floating point file. This file can then be converted to 16-bit integer with the proper scaling applied. If a long computation was involved, it should be much faster to scale the saved sound file than to recompute the sound from scratch. Although not implemented yet in Nyquist, some header formats can store maximum amplitudes, and some soundfile player programs can rescale floating point files on the fly, allowing normalized soundfile playback without an extra normalization pass (but at a cost of twice the disk space of 16-bit samples). You can use Nyquist to rescale a floating point file and convert it to 16-bit samples for playback. @section(Frequency Modulation)@index(Frequency Modulation) The next example uses the Nyquist frequency modulation behavior @code(fmosc) to generate various sounds. The parameters to @code(fmosc) are: @begin(example) fmosc(@i(pitch) @i(modulator) @i(table) @i(phase)) @end(example) Note that pitch is the number of half-steps, e.g. @code(c4) has the value of 60 which is middle-C, and phase is in degrees. Only the first two parameters are required: @begin(example) @i[; make a short sine tone with no frequency modulation ;] play fmosc(c4, pwl(0.1)) @i[; make a longer sine tone -- note that the duration of ; the modulator determines the duration of the tone ;] play fmosc(c4, pwl(0.5)) @end(example) In the example above, @code(pwl) (for Piece-Wise Linear) is used to generate sounds that are zero for the durations of @code(0.1) and @code(0.5) seconds, respectively. In effect, we are using an FM oscillator with no modulation input, and the result is a sine tone. The duration of the modulation determines the duration of the generated tone (when the modulation signal ends, the oscillator stops). The next example uses a more interesting modulation function, a ramp from zero to C@-(4), expressed in hz. More explanation of @code(pwl) is in order. This operation constructs a piece-wise linear function sampled at the @code(*control-srate*). The first breakpoint is always at @code[(0, 0)], so the first two parameters give the time and value of the second breakpoint, the second two parameters give the time and value of the third breakpoint, and so on. The last breakpoint has a value of @code(0), so only the time of the last breakpoint is given. In this case, we want the ramp to end at C@-(4), so we cheat a bit by having the ramp return to zero ``almost'' instantaneously between times @code(0.5) and @code(0.501). The @code(pwl) behavior always expects an odd number of parameters. The resulting function is shifted and stretched linearly according to @code[*warp*] in the environment. Now, here is the example: @begin(example) @i[; make a frequency sweep of one octave; the piece-wise linear function ; sweeps from 0 to (step-to-hz c4) because, when added to the c4 ; fundamental, this will double the frequency and cause an octave sweep. ;] play fmosc(c4, pwl(0.5, step-to-hz(c4), 0.501)) @end(Example) The same idea can be applied to a non-sinusoidal carrier. Here, we assume that @code(*fm-voice*) is predefined (the next section shows how to define it): @begin(example) @i[; do the same thing with a non-sine table ;] play fmosc(cs2, pwl(0.5, step-to-hz(cs2), 0.501), *fm-voice*, 0.0) @end(example) The next example shows how a function can be used to make a special frequency modulation contour. In this case the contour generates a sweep from a starting pitch to a destination pitch: @begin(example) @i[; make a function to give a frequency sweep, starting ; after seconds, then sweeping from ; to in seconds and then ; holding at for seconds. ;] define function sweep(delay, pitch-1, sweep-time, pitch-2, hold-time) begin with interval = step-to-hz(pitch-2) - step-to-hz(pitch-1) return pwl(delay, 0.0, @i[; sweep from pitch 1 to pitch 2] delay + sweep-time, interval, @i[; hold until about 1 sample from the end] delay + sweep-time + hold-time - 0.0005, interval, @i[; quickly ramp to zero (pwl always does this,] @i[; so make it short)] delay + sweep-time + hold-time) end @i[; now try it out ;] play fmosc(cs2, sweep(0.1, cs2, 0.6, gs2, 0.5), *fm-voice*, 0.0) @end(example) FM can be used for vibrato as well as frequency sweeps. Here, we use the @code(lfo) function to generate vibrato. The @code(lfo) operation is similar to @code(osc), except it generates sounds at the @code(*control-srate*), and the parameter is hz rather than a pitch: @begin(example) play fmosc(cs2, 10.0 * lfo(6.0), *fm-voice*, 0.0) @end(Example) What kind of manual would this be without the obligatory FM sound? Here, a sinusoidal modulator (frequency C@-(4)) is multiplied by a slowly increasing ramp from zero to @code(1000.0). @begin(example) set modulator = pwl(1.0, 1000.0, 1.0005) * osc(c4) @i[; make the sound] play fmosc(c4, modulator) @end(example) For more simple examples of FM in Nyquist, see @index(warble)@index(FM synthesis)@index(demos, FM)@index(tutorial, FM) @code(demos/warble_tutorial.htm). Another interesting FM sound reminiscent of ``scratching'' can be found with a detailed explanation in @code(demos/scratch_tutorial.htm).@index(demos, scratch tutorial) @index(vinal scratch)@index(scratch sound). @section(Building a Wavetable) In Section @ref(waveform-sec), we saw how to synthesize a wavetable. A wavetable for @code(osc) also can be extracted from any sound. This is especially interesting if the sound is digitized from some external sound source and loaded using the @code(s-read) function. Recall that a table is a list consisting of a sound, the pitch of that sound, and T (meaning the sound is periodic). In the following, a sound is first read from the file @code(demo-snd.nh). Then, the @code(extract) function is used to extract the portion of the sound between 0.110204 and 0.13932 seconds. (These numbers might be obtained by first plotting the sound and estimating the beginning and end of a period, or by using some software to look for good zero crossings.) The result of @code(extract) becomes the first element of a list. The next element is the pitch (24.848422), and the last element is @code(T). The list is assigned to @code(*fm-voice*). @begin(example) if not(boundp(quote(a-snd))) then set a-snd = s-read("demo-snd.aiff") set *fm-voice* = list(extract(0.110204, 0.13932, cue(a-snd)), 24.848422, #T) @end(example) The file @i(demos/examples.sal) contains an extensive example of how to locate zero-crossings, extract a period, build a waveform, and generate a tone from it. (See @code(ex37) through @code(ex40) in the file.) @begin(comment) The @code(maketable) command is also useful and is documented on page @ref(maketable). If @code(sample) is the source sound, then the following will extract 0.01 seconds (starting at time 0.2s) of audio and convert it into a waveform named @code(mytable): @begin(example) (setf mytable (maketable (extract -abs 0.2 0.21 sample))) @end(example) Nyquist does not provide any pitch analysis or other help finding good splice points, so it is up to you to make sure the table you extract is a reasonable one. @end(comment) @section(Filter Examples) Nyquist provides a variety of filters. All of these filters take either real numbers or signals as parameters. If you pass a signal as a filter parameter, the filter coefficients are recomputed at the sample rate of the @i(control) signal. Since filter coefficients are generally expensive to compute, you may want to select filter control rates carefully. Use @code(control-srate-abs) (Section @ref(control-srate-abs-sec)) to specify the default control sample rate, or use @code(force-srate) (Section @ref(force-srate-sec)) to resample a signal before passing it to a filter. Before presenting examples, let's generate some unfiltered white noise: @begin(example) play noise() @end(example) Now low-pass filter the noise with a 1000Hz cutoff: @begin(example) play lp(noise(), 1000.0) @end(example) The high-pass filter is the inverse of the low-pass: @begin(example) play hp(noise(), 1000.0) @end(example) Here is a low-pass filter sweep from 100Hz to 2000Hz: @begin(example) play lp(noise(), pwl(0.0, 100.0, 1.0, 2000.0, 1.0)) @end(example) And a high-pass sweep from 50Hz to 4000Hz: @begin(example) play hp(noise(), pwl(0.0, 50.0, 1.0, 4000.0, 1.0)) @end(example) The band-pass filter takes a center frequency and a bandwidth parameter. This example has a 500Hz center frequency with a 20Hz bandwidth. The scale factor is necessary because, due to the resonant peak of the filter, the signal amplitude exceeds 1.0: @begin(example) play reson(10.0 * noise(), 500.0, 20.0, 1) @end(example) In the next example, the center frequency is swept from 100 to 1000Hz, using a constant 20Hz bandwidth: @begin(example) play reson(0.04 * noise(), pwl(0.0, 200.0, 1.0, 1000.0, 1.0), 20.0) @end(example) For another example with explanations, see @index(wind_tutorial.htm)@index(wind sound)@index(filter example) @index(demos, wind sound) @code(demos/wind_tutorial.htm). @section(DSP in Lisp) @index(DSP in Lisp)@index(Lisp DSP)In almost any signal processing system, the vast majority of computation takes place in the inner loops of DSP algorithms, and Nyquist is designed so that these time-consuming inner loops are in highly-optimized machine code rather than relatively slow interpreted lisp code. As a result, Nyquist typically spends 95% of its time in these inner loops; the overhead of using a Lisp interpreter is negligible. The drawback is that Nyquist must provide the DSP operations you need, or you are out of luck. When Nyquist is found lacking, you can either write a new primitive signal operation, or you can perform DSP in Lisp code. Neither option is recommended for inexperienced programmers. Instructions for extending Nyquist are given in Appendix @ref(extending-app). This section describes the process of writing a new signal processing function in Lisp. Before implementing a new DSP function, you should decide which approach is best. First, figure out how much of the new function can be implemented using existing Nyquist functions. For example, you might think that a tapped-delay line would require a new function, but in fact, it can be implemented by composing sound transformations to accomplish delays, scale factors for attenuation, and additions to combine the intermediate results. This can all be packaged into a new Lisp function, making it easy to use. If the function relies on built-in DSP primitives, it will execute very efficiently. Assuming that built-in functions cannot be used, try to define a new operation that will be both simple and general. Usually, it makes sense to implement only the kernel of what you need, combining it with existing functions to build a complete instrument or operation. For example, if you want to implement a physical model that requires a varying breath pressure with noise and vibrato, plan to use Nyquist functions to add a basic pressure envelope to noise and vibrato signals to come up with a composite pressure signal. Pass that signal into the physical model rather than synthesizing the envelope, noise, and vibrato within the model. This not only simplifies the model, but gives you the flexibility to use all of Nyquist's operations to synthesize a suitable breath pressure signal. Having designed the new ``kernel'' DSP operation that must be implemented, decide whether to use C or Lisp. (At present, SAL is not a good option because it has no support for object-oriented programming.) To use C, you must have a C compiler, the full source code for Nyquist, and you must learn about extending Nyquist by reading Appendix @ref(extending-app). This is the more complex approach, but the result will be very efficient. A C implementation will deal properly with sounds that are not time-aligned or matched in sample rates. To use Lisp, you must learn something about the XLISP object system, and the result will be about 50 times slower than C. Also, it is more difficult to deal with time alignment and differences in sample rates. The remainder of this section gives an example of a Lisp version of @code(snd-prod) to illustrate how to write DSP functions for Nyquist in Lisp. The @code(snd-prod) function is the low-level multiply routine. It has two sound parameters and returns a sound which is the product of the two. To keep things simple, we will assume that two sounds to be multiplied have a matched sample rate and matching start times. The DSP algorithm for each output sample is simply to fetch a sample from each sound, multiply them, and return the product. To implement @code(snd-prod) in Lisp, three components are required: @begin(enumerate) An object is used to store the two parameter sounds. This object will be called upon to yield samples of the result sound; Within the object, the @code(snd-fetch) routine is used to fetch samples from the two input sounds as needed; The result must be of type @code(SOUND), so @code(snd-fromobject) is used to create the result sound. @end(enumerate) The combined solution will work as follows: The result is a value of type @code(sound) that retains a reference to the object. When Nyquist needs samples from the sound, it invokes the sound's ``fetch'' function, which in turn sends an XLISP message to the object. The object will use @code(snd-fetch) to get a sample from each stored sound, multiply the samples, and return a result. Thus the goal is to design an XLISP object that, in response to a @code(:next) message will return a proper sequence of samples. When the sound reaches the termination time, simply return @code(NIL). The XLISP manual (see Appendix @ref(XLISP-app) describes the object system, but in a very terse style, so this example will include some explanation of how the object system is used. First, we need to define a class for the objects that will compute sound products. Every class is a subclass of class @code(class), and you create a subclass by sending @code(:new) to a class. @begin(example) (setf product-class (send class :new '(s1 s2))) @end(example) The parameter @code['(s1 s2)] says that the new class will have two instance variables, @code(s1) and @code(s2). In other words, every object which is an instance of class @code(product-class) will have its own copy of these two variables. Next, we will define the @code(:next) method for @code(product-class): @begin(example) (send product-class :answer :next '() '((let ((f1 (snd-fetch s1)) (f2 (snd-fetch s2))) (cond ((and f1 f2) (* f1 f2)) (t nil))))) @end(example) The @code(:answer) message is used to insert a new method into our new @code(product-class). The method is described in three parts: the name (@code(:next)), a parameter list (empty in this case), and a list of expressions to be evaluated. In this case, we fetch samples from @code(s1) and @code(s2). If both are numbers, we return their product. If either is @code(NIL), we terminate the sound by returning @code(nil). The @code(:next) method assumes that @code(s1) and @code(s2) hold the sounds to be multiplied. These must be installed when the object is created. Objects are created by sending @code(:new) to a class. A new object is created, and any parameters passed to @code(:new) are then sent in a @code(:isnew) message to the new object. Here is the @code(:isnew) definition for @code(product-class): @begin(example) (send product-class :answer :isnew '(p1 p2) '((setf s1 (snd-copy p1)) (setf s2 (snd-copy p2)))) @end(example) Take careful note of the use of @code(snd-copy) in this initialization. The sounds @code(s1) and @code(s2) are modified when accessed by @code(snd-fetch) in the @code(:next) method defined above, but this destroys the illusion that sounds are immutable values. The solution is to copy the sounds before accessing them; the original sounds are therefore unchanged. (This copy also takes place implicitly in most Nyquist sound functions.) To make this code safer for general use, we should add checks that @code(s1) and @code(s2) are sounds with identical starting times and sample rates; otherwise, an incorrect result might be computed. Now we are ready to write @code(snd-product), an approximate replacement for @code(snd-prod): @begin(example) (defun snd-product (s1 s2) (let (obj) (setf obj (send product-class :new s1 s2)) (snd-fromobject (snd-t0 s1) (snd-srate s1) obj))) @end(example) This code first creates @code(obj), an instance of @code(product-class), to hold @code(s1) and @code(s2). Then, it uses @code(obj) to create a sound using @code(snd-fromobject). This sound is returned from @code(snd-product). Note that in @code(snd-fromobject), you must also specify the starting time and sample rate as the first two parameters. These are copied from @code(s1), again assuming that @code(s1) and @code(s2) have matching starting times and sample rates. Note that in more elaborate DSP algorithms we could expect the object to have a number of instance variables to hold things such as previous samples, waveform tables, and other parameters. @chapter(SAL) @label(SAL-chap) Nyquist supports two languages: XLISP and SAL. In some sense, XLISP and SAL are the same language, but with differing syntax. This chapter describes SAL: how it works, SAL syntax and semantics, and the relationship between SAL and XLISP, and differences between Nyquist SAL and Common Music SAL. Nyquist SAL is based on Rick Taube's SAL language, which is part of Common Music. SAL offers the power of Lisp but features a simple, Algol-like syntax. SAL is implemented in Lisp: Lisp code translates SAL into a Lisp program and uses the underlying Lisp engine to evaluate the program. Aside from the translation time, which is quite fast, SAL programs execute at about the same speed as the corresponding Lisp program. (Nyquist SAL programs run just slightly slower than XLISP because of some runtime debugging support automatically added to user programs by the SAL compiler.) From the user's perspective, these implementation details are hidden. You can enter SAL mode from XLISP by typing @code[(SAL)] to the XLISP prompt. The SAL input prompt (@code(SAL> )) will be displayed. From that point on, you simply type SAL commands, and they will be executed. By setting a preference in the NyquistIDE program, SAL mode will be entered automatically. It is possible to encounter errors that will take you from the SAL interpreter to an XLISP prompt. In general, the way to get back to SAL is by typing @code[(top)] to get back to the top level XLISP interpreter and reset the Nyquist environment. Then type @code[(sal)] to restart the SAL interpreter. @section(SAL Syntax and Semantics) @index(SAL) The most unusual feature of SAL syntax is that identifiers are Lisp-like, including names such as ``play-file'' and even ``*warp*.'' In SAL, most operators must be separated from identifiers by white space. For example, @code(play-file) is one identifier, but @code(play - file) is an expression for ``play minus file,'' where @code(play) and @code(file) are two separate identifiers. Fortunately, no spaces are needed around commas and parentheses. In SAL, whitespace (any sequence of space, newline, or tab characters) is sometimes necessary to separate lexical tokens, but otherwise, spaces and indentation are ignored. To make SAL readable, it is @i(strongly) advised that you indent SAL programs as in the examples here. The NyquistIDE program is purposely insistent about SAL indentation, so if you use it to edit SAL programs, your indentation should be both beautiful and consistent. As in Lisp (but very unlike C or Java), comments @index(comments) are indicated by semicolons. Any text from an unquoted semicolon to the end of the line is ignored. @begin(example) @i(; this is a comment) @i(; comments are ignored by the compiler) print "Hello World" @i(; this is a SAL statement) @end(example) As in Lisp, identifiers are translated to upper-case, making SAL case-insensitive@index(case-insensitive). For example, the function name @code(autonorm) can be typed in lower case or as @code(AUTONORM), @code(AutoNorm), or even @code(AuToNoRm). All forms denote the same function. The recommended approach is to write programs in all lower case. SAL is organized around statements, most of which contain expressions. We will begin with expressions and then look at statements. @subsection(Expressions) @index(sal expressions)@index(expressions, sal) @paragraph(Simple Expressions) As in XLISP, simple expressions include: @begin(itemize) integers (FIXNUM's), such as @code(1215), floats (FLONUM's) such as @code(12.15), strings (STRING's) such as @code("Magna Carta"), and symbols (SYMBOL's) such as @code(magna-carta). A symbol with a leading colon (@code(:)) evaluates to itself as in Lisp. Otherwise, a symbol denotes either a local variable, a formal parameter, or a global variable. As in Lisp, variables do not have data types or type declarations. The type of a variable is determined at runtime by its value. @end(itemize) Additional simple expressions in SAL are: @begin(itemize) lists such as @code[{c 60 e 64}]. Note that there are no commas to separate list elements, and symbols in lists are not evaluated as variables but stand for themselves. Lists may contain numbers, booleans, symbols, strings, and other lists. Booleans: SAL interprets @code(#t)@index(#t) as true and @code(#f)@index(#f) as false. (As far as the SAL compiler is concerned, @code(t) and @code(nil) are just variables. Since these are the Lisp versions of true and false, they are interchangeable with @code(#t) and @code(#f), respectively.) @end(itemize) A curious property of Lisp and Sal is that @i(false) and the empty list are the same value. Since SAL is based on Lisp, @code(#f) and @code({}) (the empty list)@index(empty list) are equal. @paragraph(Operators) Expressions can be formed with unary and binary operators using infix notation. The operators are: @begin(itemize) @index(+)@code(+) - addition, including sounds @index(-)@code(-) - subtraction, including sounds @index(*)@code(*) - multiplication, including sounds @index(/)@code(/) - division (due to divide-by-zero problems, does not operate on sounds) @index(%)@code(%) - modulus (remainder after division) @index(^)@code(^) - exponentiation @index(=)@code(=) - equal (using Lisp @code(eql)) @index(!=)@code(!=) - not equal @index(>)@code(>) - greater than @index(<)@code(<) - less than @index(>=)@code(>=) - greater than or equal @index(<=)@code(<=) - less than or equal @index(~=)@code(~=) - general equality (using Lisp @code(equal)) @index(&)@code(&) - logical and @index(|)@code(|) - logical or @index(!)@code(!) - logical not (unary) @index(@@)@index(time shift, sal)@index(at, sal)@code(@@) - time shift @index(@@@@)@index(absolute time shift, sal)@index(at-abs, sal)@code(@@@@) - time shift to absolute time @index(~)@index(stretch, sal)@code(~) - time stretch @index(~~)@index(absolute stretch, sal)@code(~~) - time stretch to absolute stretch factor @end(itemize) Again, remember that operators @i(must) be delimited from their operands using spaces or parentheses. Operator precedence is based on the following levels of precedence: @begin(example) @@ @@@@ ~ ~~ ^ / * % - + ~= <= >= > ~= = ! & | @end(example) @paragraph(Function Calls) @index(function calls, sal) A function call is a function name followed by zero or more comma-delimited argument expressions enclosed within parentheses: @begin(example) list() piano-note(2.0, c4 + interval, 100) @end(example) Some functions use named parameters, in which case the name of the argument with a colon precedes the argument expression. @begin(example) s-save(my-snd(), ny:all, "tmp.wav", play: #t, bits: 16) @end(example) @paragraph(Array Notation) @index(array notation, sal) An array reference is a variable identifier followed by an index expression in square brackets, e.g.: @begin(example) x[23] + y[i] @end(example) @paragraph(Conditional Values) @index(conditional expression, sal) @index(#?, sal) The special operator @code(#?) evaluates the first argument expression. If the result is @i(true), the second expression is evaluated and its value is returned. If @i(false), the third expression is evaluated and returned (or @i(false) is returned if there is no third expression): @begin(example) #?(random(2) = 0, unison, major-third) #?(pitch >= c4, pitch - c4) ; returns false if pitch < c4 @end(example) @subsection(SAL Statements) @index(statements, sal) SAL compiles and evaluates @i(statements) one at a time. You can type statements at the SAL prompt or load a file containing SAL statements. SAL statements are described below. The syntax is indicated at the beginning of each statement type description: @code(this font) indicates literal terms such as keywords, @i(the italic font) indicates a place-holder for some other statement or expression. Bracket [like this] indicate optional (zero or one) syntax elements, while braces with a plus {like this}+ indicate one or more occurrences of a syntax element. Braces with a star {like this}* indicate zero or more occurrences of a syntax element: { @i(non-terminal) }* is equivalent to [ {@i(non-terminal)}+ ]. @paragraph(begin and end) @index(begin)@index(end) @code(begin) [@i(with-stmt)] {@i(statement)}+ @code(end) A @code(begin)-@code(end) statement consists of a sequence of statements surrounded by the @code(begin) and @code(end) keywords. This form is often used for function definitions and after @code(then) or @code(else) where the syntax demands a single statement but you want to perform more than one action. Variables may be declared using an optional @code(with) statement immediately after @code(begin). For example: @begin(example) begin with db = 12.0, linear = db-to-linear(db) print db, "dB represents a factor of", linear set scale-factor = linear end @end(example) @paragraph(chdir) @index(chdir, sal) @code(chdir) @i(expression) The @code(chdir) statement changes the working directory. This statement is provided for compatibility with Common Music SAL, but it really should be avoided if you use NyquistIDE. The @i(expression) following the @code(chdir) keyword should evaluate to a string that is a directory path name. Note that literal strings themselves are valid expressions. @begin(example) chdir "/Users/rbd/tmp" @end(example) @paragraph(define variable) @index(global variables, sal)@index(define variable) [@code(define)] @code(variable) @i(name) [= @i(expression)] {, @i(name) [= @i(expression)]}* Global variables can be declared and initialized. A list of variable names, each with an optional initialization follows the @code(define variable) keywords. (Since @code(variable) is a keyword, @code(define) is redundant and optional in Nyquist SAL, but required in Common Music SAL.) If the initialization part is omitted, the variable is initialized to false. Global variables do not really need to be declared: just using the name implicitly creates the corresponding variable. However, it is an error to use a global variable that has not been initialized; @code(define variable) is a good way to introduce a variable (or constant) with an initial value into your program. @begin(example) define variable transposition = 2, print-debugging-info, @i(; initially false) output-file-name = "salmon.wav" @end(example) @paragraph(define function) @index(function, sal)@index(define function) [@code(define)] @code(function) @i(name) @code[(] [@i(parameter)], {, @i(parameter)}* @code[)] @i(statement) Before a function be called from an expression (as described above), it must be defined. A function definition gives the function @i(name), a list of @i(parameters), and a @i(statement). When a function is called, the actual parameter expressions are evaluated from left to right and the formal parameters of the function definition are set to these values. Then, @i(statement) is evaluated. The formal parameters may be positional parameters that are matched with actual parameters by position from left to right. Syntactically, these are symbols and these symbols are essentially local variables that exist only until @i(statement) completes or a @code(return) statement causes the function evaluation to end. As in Lisp, parameters are passed by value, so assigning a new value to a formal parameter has no effect on the actual value. However, lists and arrays are not copied, so internal changes to a list or array produce observable side effects. Alternatively, formal parameters may be keyword parameters. Here the @i(parameter) is actually a pair: a keyword parameter, which is a symbol followed by a colon, and a default value, given by any expression. Within the body of the function, the keyword parameter is named by a symbol whose name matches the keyword parameter except there is no final colon. @begin(example) define function foo(x: 1, y: bar(2, 3)) display "foo", x, y exec foo(x: 6, y: 7) @end(example) In this example, @code(x) is bound to the value 6 and @code(y) is bound to the value 7, so the example prints ``@code(foo : X = 6, Y = 7)''. Note that while the keyword parameters are @code(x:) and @code(y:), the corresponding variable names in the function body are @code(x) and @code(y), respectively. The @i(parameters) are meaningful only within the lexical (static) scope of @i(statement). They are not accessible from within other functions even if they are called by this function. Use a @code(begin)-@code(end) statement if the body of the function should contain more than one statement or you need to define local variables. Use a @code(return) statement to return a value from the function. If @i(statement) completes without a @code(return), the value false is returned. @paragraph(display) @index(display statement, sal) @code(display) @i(string) {, @i(expression)}* The @code(display) statement is handy for debugging. At present, it is only implemented in Nyquist SAL. When executed, @code(display) prints the @i(string) followed by a colon and then, for each @i(expression), the expression and its value are printed, after the last expression, a newline is printed. For example, @begin(example) display "In function foo", bar, baz @end(example) prints @begin(example) In function foo : bar = 23, baz = 5.3 @end(example) SAL may print the expressions using Lisp syntax, e.g. if the expression is ``bar + baz,'' do not be surprised if the output is ``@code[(sum bar baz) = 28.3].'' @paragraph(exec) @index(exec statement, sal) @code(exec) @i(expression) Unlike most other programming languages, you cannot simply type an expression as a statement. If you want to evaluate an expression, e.g. call a function, you must use an @code(exec) statement. The statement simply evaluates the @i(expression). For example, @begin(example) exec set-sound-srate(22050.0) @i(; change default sample rate) @end(example) @paragraph(if) @index(if statement, sal) @code(if) @i(test-expr) @code(then) @i(true-stmt) [@code(else) @i(false-stmt)] An @code(if) statement evaluates the expression @i(test-expr). If it is true, it evaluates the statement @i(true-stmt). If false, the statement @i(false-stmt) is evaluated. Use a @code(begin)-@code(end) statement to evaluate more than one statement in then @code(then) or @code(else) parts. @begin(example) if x < 0 then x = -x @i(; x gets its absoute value) if x > upper-bound then begin print "x too big, setting to", upper-bound x = upper-bound end else if x < lower-bound then begin print "x too small, setting to", lower-bound x = lower-bound end @end(example) Notice in this example that the @code(else) part is another @code(if) statement. An @code(if) may also be the @code(then) part of another @code(if), so there could be two possible @code(if)'s with which to associate an @code(else). An @code(else) clause always associates with the closest previous @code(if) that does not already have an @code(else) clause. @paragraph(when) @code(when) @i(test) @i(statement) The @code(when) statement is similar to @code(if), but there is no @code(else) clause. @begin(example) when *debug-flag* print "you are here" @end(example) @paragraph(unless) @code(unless) @i(test) @i(statement) The @code(unless) statement is similar to @code(when) (and @code(if)) but the @i(statement) is executed when the @i(test) expression is @i(false). @begin(example) unless count = 0 set average = sum / count @end(example) @paragraph(load) @index(load statement, sal) @code(load) @i(expression) The @code(load) command loads a file named by @i(expression), which must evauate to a string path name for the file. To load a file, SAL interprets each statement in the file, stopping when the end of the file or an error is encountered. If the file ends in @code(.lsp), the file is assumed to contain Lisp expressions, which are evaluated by the XLISP interpreter. In general, SAL files should end with the extension @code(.sal). @paragraph(loop) @index(loop statement, sal) @code(loop) [@i(with-stmt)] {@i(stepping)}* {@i(stopping)* @i(action)+ [@i(finally)] @code(end) The @code(loop) statement is by far the most complex statement in SAL, but it offers great flexibility for just about any kind of iteration. The basic function of a loop is to repeatedly evaluate a sequence of @i(action)'s which are statements. Before the loop begins, local variables may be declared in @i(with-stmt), a @code(with) statement. The @i(stepping) clauses do several things. They introduce and initialize additional local variables similar to the @i(with-stmt). However, these local variables are updated to new values after the @i(action)'s. In addition, some @i(stepping) clauses have associated stopping conditions, which are tested on each iteration @i(before) evaluating the @i(action)'s. There are also @i(stopping) clauses that provide additional tests to stop the iteration. These are also evaluated and tested on each iteration before evaluating the @i(action)'s. When some @i(stepping) or @i(stopping) condition causes the iteration to stop, the @i(finally) clause is evaluated (if present). Local variables and their values can still be accessed in the @i(finally) clause. After the @i(finally) clause, the @code(loop) statement completes. The @i(stepping) clauses are the following: @begin(description) @code(repeat) @i(expression)@\Sets the number of iterations to the value of @i(expression), which should be an integer (FIXNUM). @code(for) @i(var) = @i(expression) [ @code(then) @i(expr2) ]@\Introduces a new local variable named @i(var) and initializes it to @i(expression). Before each subsequent iteration, @i(var) is set to the value of @i(expr2). If the @code(then) part is omitted, @i(expression) is re-evaluated and assigned to @i(var) on each subsequent iteration. Note that this differs from a @i(with-stmt) where expressions are evaluated and variables are only assigned their values once. @code(for) @i(var) @code(in) @i(expression)@\Evaluates @i(expression) to obtain a list and creates a new local variable initialized to the first element of the list. After each iteration, @i(var) is assigned the next element of the list. Iteration stops when @i(var) has assumed all values from the list. If the list is initially empty, the loop @i(action)'s are not evaluated (there are zero iterations). @code(for) @i(var) [@code(from) @i(from-expr)] [[@code(to) | @code(below) | @code(downto) | @code(above)] @i(to-expr)] [@code(by) @i(step-expr)]@\Introduces a new local variable named @i(var) and intialized to the value of the expression @i(from-expr) (with a default value of 0). After each iteration of the loop, @i(var) is incremented by the value of @i(step-expr) (with a default value of 1). The iteration ends when @i(var) is greater than the value of @i(to-expr) if there is a @code(to) clause, greater than or equal to the value of @i(to-expr) if there is a @code(below) clause, less than the value of @i(to-expr) if there is a @code(downto) clause, or less than or equal to the value of @i(to-expr) if there is a @code(above) clause. (In the cases of @i(downto) and @i(above), the default increment value is -1. If there is no @code(to), @code(below), @code(downto), @code(above), or @code(below) clause, no interation stop test is created for this stepping clause. @end(description) The @i(stopping) clauses are the following: @begin(description) @code(while) @i(expression)@\The iterations are stopped when @i(expression) evaluates to @i(false). Anything not false is considered to mean true. @code(until) @i(expression)@\The iterations are stopped when @i(expression) evaluates to @i(true). @end(description) The @i(finally) clause is defined as follows: @index(finally clause, sal) @begin(description) @code(finally) @i(statement)@\The @i(statement) is evaluated when one of the @i(stepping) or @i(stopping) clauses ends the loop. As always, @i(statement) may be a @code(begin)-@code(end) statement. If an @i(action) evaluates a @code(return) statement, the @code(finally) statement is not executed. @end(description) @index(loop examples, sal)Loops often fall into common patterns, such as iteratiing a fixed number of times, performing an operation on some range of integers, collecting results in a list, and linearly searching for a solution. These forms are illustrated in the examples below. @begin(example) @i(; iterate 10 times) loop repeat 10 print random(100) end @i(; print even numbers from 10 to 20 ; note that 20 is printed. On the next iteration, ; i = 22, so i >= 22, so the loop exits.) loop for i from 10 to 22 by 2 print i end @i(; collect even numbers in a list) loop with lis for i = 0 to 10 by 2 set lis @@= i @i(; push integers on front of list,) @i(; which is much faster than append,) @i(; but list is built in reverse) finally result = reverse(lis) end @i(; now, the variable result has a list of evens) @i(; find the first even number in a list) result = #f @i(; #f means "false") loop for elem in lis until evenp(elem) finally result = elem end @i[; result has first even value in lis (or it is #f)] @end(example) @paragraph(print) @index(print statement, sal) @code(print) @i(expr) {, @i(expr)}* The @code(print) statement prints the values separated by spaces and followed by a newline. [Note that in the original SAL, the newline is printed @i(before) the values, not after.] @begin(example) print "The value of x is", x @end(example) @paragraph(return) @index(return statement, sal) @code(return) @i(expression) The @code(return) statement can only be used inside a function. It evaluates @i(expression) and then the function returns the value of the expression to its caller. @paragraph(set) @index(set statement, sal) @code(set) @i(var) @i(op) @i(expression) {, @i(var) @i(op) @i(expression)}* The @code(set) statement changes the value of a variable @i(var) according to the operator @i(op) and the value of the @i(expression). The operators are: @begin(description) @code(=)@\The value of @i(expression) is assigned to @i(var). @index(+=)@code(+=)@\The value of @i(expression) is added to @i(var). @index(*=)@code(*=)@\The value of @i(var) is multiplied by the value of the expression. @index(&=)@code(&=)@\The value of @i(expression) is inserted as the last element of the list referenced by @i(var). If @i(var) is the empty list (denoted by @code(#f)), then @i(var) is assigned a newly constructed list of one element, the value of @i(expression). @index(^=)@code(^=)@\The value of @i(expression), a list, is appended to the list referenced by @i(var). If @i(var) is the empty list (denoted by @code(#f)), then @i(var) is assigned the (list) value of @i(expression). @index(@@=)@code(@@=)@\Pushes the value of @i(expression) onto the front of the list referenced by @i(var). If @i(var) is empty (denoted by @code(#f)), then @i(var) is assigned a newly constructed list of one element, the value of @i(expression). @index(<=)@code(<=)@\Sets the new value of @i(var) to the minimum of the old value of @i(var) and the value of @i(expression). @index(>=)@code(>=)@\Sets the new value of @i(var) to the maximum of the old value of @i(var) and the value of @i(expression). @end(description) @begin(example) @i(; example from Rick Taube's SAL description) loop with a, b = 0, c = 1, d = {}, e = {}, f = -1, g = 0 for i below 5 set a = i, b += 1, c *= 2, d &= i, e @@= i, f <= i, g >= i finally display "results", a, b, c, d, e, f, g end @end(example) @paragraph(with) @index(with statement, sal) @code(with) @i(var) [= @i(expression)] {, @i(var) [= @i(expression)]}* The @code(with) statement declares and initializes local variables. It can appear only after @code(begin) or @code(loop). If the @i(expression) is omitted, the initial value is @i(false). The variables are visible only inside the @code(begin)-@code(end) or @code(loop) statement where the @code(with) statement appears. Even in @code(loop)'s the variables are intialized only when the loop is entered, not on each iteration. @paragraph(exit) @index(exit statement, sal) @code(exit) [@code(nyquist)] The @code(exit) statement is unique to Nyquist SAL. It returns from SAL mode to the XLISP interpreter. (Return to SAL mode by typing ``@code[(sal)]''). If @code(nyquist) is included in the statement, then the entire Nyquist process will exit. @section(Interoperability of SAL and XLISP) @index(sal and lisp)@index(interoperability, sal and lisp) @label(sal-vs-lisp-section) When SAL evaluatas command or loads files, it translates SAL into XLISP. You can think of SAL as a program that translates everything you write into XLISP and entering it for you. Thus, when you define a SAL function, the function actually exists as an XLISP function (created using Lisp's @code(defun) special form). When you set or evaluate global variables in SAL, these are exactly the same Lisp global variables. Thus, XLISP functions can call SAL functions and vice-versa. At run time, everything is Lisp. @subsection(Function Calls) In general, there is a very simple translation from SAL to Lisp syntax and back. A function call is SAL, for example, @begin(example) osc(g4, 2.0) @end(example) is translated to Lisp by moving the open parenthesis in front of the function name and removing the commas: @begin(example) (osc g4 2.0) @end(example) Similarly, if you want to translate a Lisp function call to SAL, just reverse the translation. @subsection(Symbols and Functions) SAL translates keywords with trailing colons (such as @code(foo:)) into Lisp keywords with leading colons (such as @code(:foo)), but SAL keywords are not treated as expressions as they are in Lisp. You cannot write @code[open("myfile.txt", direction: output:)] because SAL expects an expression after direction. A special form @code(keyword) is defined to generate a Lisp keyword as an expression. The argument is the keyword @i(without) a colon, e.g. @code[open("myfile.txt", direction: keyword(output))]. Alternatively, you can write the Lisp-style keyword with the leading colon, e.g. @code[open("myfile.txt", direction: :output)]. In Nyquist SAL, the hash character (#), can be used as a prefix to a Lisp function name. For example, the following command is not legal because @code(print) is a SAL command name, not a legal function name: @code[set v = append(print(a), print(b))]. (Here the intent is to print arguments to append). However, you can use the hash character to access the Lisp @code(print) function: @code[set v = append(#print(a), #print(b))]. @subsection(Playing Tricks On the SAL Compiler) In many cases, the close coupling between SAL and XLISP gives SAL unexpected expressive power. A good example is @code(seqrep). This is a special looping construct in Nyquist, implemented as a macro in XLISP. In Lisp, you would write something like: @begin(example) (seqrep (i 10) (pluck c4)) @end(example) One might expect SAL would have to define a special @code(seqrep) statement to express this, but since statements do not return values, this approach would be problematic. The solution (which is already fully implemented in Nyquist) is to define a new macro @code(sal-seqrep) that is equivalent to @code(seqrep) except that it is called as follows: @begin(example) (sal-seqrep i 10 (pluck c4)) @end(example) The SAL compiler automatically translates the identifier @code(seqrep) to @code(sal-seqrep). Now, in SAL, you can just write @begin(example) seqrep(i, 10, pluck(c4)) @end(example) which is translated in a pretty much semantics-unaware fashion to @begin(example) (sal-seqrep i 10 (pluck c4)) @end(example) and viola!, we have Nyquist control constructs in SAL even though SAL is completely unaware that @code(seqrep) is actually a special form. @chapter(Nyquist Functions) @label(lisp-chap) This chapter provides a language reference for Nyquist. Operations are categorized by functionality and abstraction level. Nyquist is implemented in two important levels: the ``high level'' supports behavioral abstraction, which means that operations like @code(stretch) and @code(at) can be applied. These functions are the ones that typical users are expected to use, and most of these functions are written in XLISP. The ``low-level'' primitives directly operate on sounds, but know nothing of environmental variables (such as @code(*warp*), etc.). The names of most of these low-level functions start with ``@code(snd-)''. In general, programmers should avoid any function with the ``@code(snd-)'' prefix. Instead, use the ``high-level'' functions, which know about the environment and react appropriately. The names of high-level functions do not have prefixes like the low-level functions. There are certain low-level operations that apply directly to sounds (as opposed to behaviors) and are relatively ``safe'' for ordinary use. These are marked as such. Nyquist uses both linear frequency and equal-temperament pitch numbers to specify repetition rates. Frequency is always specified in either cycles per second (hz), or pitch numbers, also referred to as ``steps,'' as in steps of the chromatic scale. Steps are floating point numbers such that 60 = Middle C, 61 = C#, 61.23 is C# plus 23 cents, etc. The mapping from pitch number to frequency is the standard exponential conversion, and fractional pitch numbers are allowed: @pragma(startscribe) @math[frequency = 440 @mult 2@+{(pitch - 69)/12}]. @pragma(endscribe) @html[@center{frequency = 440 * 2^((pitch - 69)/12)}] There are many predefined pitch names. By default these are tuned in equal temperament, with A4 = 440Hz, but these may be changed. (See Section @ref(constants-sec)). @section(Sounds)@index(Sounds) A sound is a primitive data type in Nyquist. Sounds can be created, passed as parameters, garbage collected, printed, and set to variables just like strings, atoms, numbers, and other data types. @subsection(What is a Sound?) Sounds have 5 components: @begin(itemize) @code(srate@index(srate)) @itemsep the sample rate of the sound. @code(samples@index(samples)) @itemsep the samples. @code(signal-start@index(signal-start)) @itemsep the time of the first sample. @code(signal-stop@index(signal-stop)) @itemsep the time of one past the last sample. @code(logical-stop@index(logical-stop)) @itemsep the time at which the sound logically ends, e.g. a sound may end at the beginning of a decay. This value defaults to @code(signal-stop), but may be set to any value. @end(itemize) It may seem that there should be @code(logical-start) to indicate the logical or perceptual beginning of a sound as well as a @code(logical-stop) to indicate the logical ending of a sound. In practice, only @code(logical-stop) is needed; this attribute tells when the next sound should begin to form a sequence of sounds. In this respect, Nyquist sounds are asymmetric: it is possible to compute sequences forward in time by aligning the logical start of each sound with the @code(logical-stop) of the previous one, but one cannot compute ``backwards'', aligning the logical end of each sound with the logical start of its successor. The root of this asymmetry is the fact that when we invoke a behavior, we say when to start, and the result of the behavior tells us its logical duration. There is no way to invoke a behavior with a direct specification of when to stop@foot(Most behaviors will stop at time 1, warped according to @code(*warp*) to some real time, but this is by convention and is not a direct specification.). @p(Note:) there is no way to enforce the intended ``perceptual'' interpretation of @code(logical-stop). As far as Nyquist is concerned, these are just numbers to guide the alignment of sounds within various control constructs. @subsection(Multichannel Sounds) @index(Multichannel Sounds) Multichannel sounds are represented by Lisp arrays of sounds. To create an array of sounds the XLISP @code(vector) function is useful. Most low-level Nyquist functions (the ones starting with @code(snd-)) do not operate on multichannel sounds. Most high-level functions do operate on multichannel sounds. @subsection(Accessing and Creating Sound) @label(flatten-sec) @label(snd-srate-sec) Several functions display information concerning a sound and can be used to query the components of a sound. There are functions that access samples in a sound and functions that construct sounds from samples. @begin(fndefs) @codef[sref(@pragma(defn)@index(sref)@indexSecondary(primary="sound", secondary="accessing point")@i(sound), @i(time))] @c{[sal]}@* @altdef{@code[(sref @i(sound) @i(time))] @c{[lisp]}}@\Accesses @i(sound) at the point @i(time), which is a local time. If @i(time) does not correspond to a sample time, then the nearest samples are linearly interpolated to form the result. To access a particular sample, either convert the sound to an array (see @code(snd-samples) below), or use @code(snd-srate) and @code(snd-t0) (see below) to find the sample rate and starting time, and compute a time (@i(t)) from the sample number (@i(n)): @pragma(startscribe) @begin(math) t = (n / srate) + t0 @end(math) @pragma(endscribe) @html[
    t = (n / srate) + t0
    ] Thus, the lisp code to access the n@+(th) sample of a sound would look like: @begin(code) (sref sound (global-to-local (+ (/ n (snd-srate sound)) (snd-t0 sound)))) @end(code) Here is why @code(sref) interprets its time argument as a local time: @begin(example) > (sref (ramp 1) 0.5) @i(; evaluate a ramp at time 0.5) 0.5 > (at 2.0 (sref (ramp 1) 0.5)) @i(; ramp is shifted to start at 2.0) @i(; the time, 0.5, is shifted to 2.5) 0.5 @end(example) If you were to use @code(snd-sref), which treats time as global, instead of @code(sref), which treats time as local, then the first example above would return the same answer (0.5), but the second example would return 0. Why? Because the @code[(ramp 1)] behavior would be shifted to start at time 2.0, but the resulting sound would be evaluated at global time 0.5. By definition, sounds have a value of zero before their start time. @codef[sref-inverse(@pragma(defn)@index(sref-inverse)@i(sound), @i(value))] @c{[sal]}@* @altdef{@code[(sref-inverse @i(sound) @i(value))] @c{[lisp]}}@\Search @i(sound) for the first point at which it achieves @i(value) and return the corresponding (linearly interpolated) time. If no inverse exists, an error is raised. This function is used by Nyquist in the implementation of time warping. @label(snd-from-array-sec) @codef[snd-from-array(@IndexSecondary(primary="sound", secondary = "creating from array")@pragma(defn)@index(snd-from-array)@i(t0), @i(sr), @i(array))] @c{[sal]}@* @altdef{@code[(snd-from-array @i(t0) @i(sr) @i(array))] @c{[lisp]}}@\Converts a lisp array of @code(FLONUM)s into a sound with starting time @i(t0) and sample rate @i(sr). Safe for ordinary use. Be aware that arrays of floating-point samples use 14 bytes per sample, and an additional 4 bytes per sample are allocated by this function to create a sound type. @codef[snd-fromarraystream(@pragma(defn)@index(snd-fromarraystream)@i(t0), @i(sr), @i(object))] @c{[sal]}@* @altdef{@code[(snd-fromarraystream @i(t0) @i(sr) @i(object))] @c{[lisp]}}@\Creates a sound for which samples come from @i(object). The starting time is @i(t0) (a @code(FLONUM)), and the sample rate is @i(sr). The @i(object) is an XLISP object (see Section @ref(objects-sec) for information on objects.) A sound is returned. When the sound needs samples, they are generated by sending the message @code(:next) to @i(object). If @i(object) returns @code(NIL), the sound terminates. Otherwise, @i(object) must return an array of @code(FLONUM)s. The values in these arrays are concatenated to form the samples of the resulting sound. There is no provision for @i(object) to specify the logical stop time of the sound, so the logical stop time is the termination time. @codef[snd-fromobject(@pragma(defn)@index(snd-fromobject)@index(sound from Lisp data)@i(t0), @i(sr), @i(object))] @c{[sal]}@* @altdef{@code[(snd-fromobject @i(t0) @i(sr) @i(object))] @c{[lisp]}}@\Creates a sound for which samples come from @i(object). The starting time is @i(t0) (a @code(FLONUM)), and the sample rate is @i(sr). The @i(object) is an XLISP object (see Section @ref(objects-sec) for information on objects. A sound is returned. When the sound needs samples, they are generated by sending the message @code(:next) to @i(object). If @i(object) returns @code(NIL), the sound terminates. Otherwise, @i(object) must return a @code(FLONUM). There is no provision for @i(object) to specify the logical stop time of the sound, so the logical stop time is the termination time. @codef[snd-extent(@pragma(defn)@index(snd-extent)@i(sound), @i(maxsamples))] @c{[sal]}@* @altdef{@code[(snd-extent @i(sound) @i(maxsamples))] @c{[lisp]}}@\Returns a list of two numbers: the starting time of @i(sound) and the terminate time of @i(sound). Finding the terminate time requires that samples be computed. Like most Nyquist functions, this is non-destructive, so memory will be allocated to preserve the sound samples. If the sound is very long or infinite, this may exhaust all memory, so the @i(maxsamples) parameter specifies a limit on how many samples to compute. If this limit is reached, the terminate time will be (incorrectly) based on the sound having @i(maxsamples) samples. This function is safe for ordinary use. @codef[snd-fetch(@index(access samples)@index(samples, reading)@pragma(defn)@index(snd-fetch)@index(read samples)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-fetch @i(sound))] @c{[lisp]}}@\Reads samples sequentially from @i(sound). This returns a @code(FLONUM) after each call, or @code(NIL) when @i(sound) terminates. @p(Note:) @code(snd-fetch) modifies @i(sound); it is strongly recommended to copy @i(sound) using @code(snd-copy) and access only the copy with @code(snd-fetch). @codef[snd-fetch-array(@pragma(defn)@index(snd-fetch-array)@i(sound), @i(len), @i(step))] @c{[sal]}@* @altdef{@code[(snd-fetch-array @i(sound) @i(len) @i(step))] @c{[lisp]}}@\Reads sequential arrays of samples from @i(sound), returning either an array of @code(FLONUM)s or @code(NIL) when the sound terminates. The @i(len) parameter, a @code(FIXNUM), indicates how many samples should be returned in the result array. After the array is returned, @i(sound) is modified by skipping over @i(step) (a @code(FIXNUM)) samples. If @i(step) equals @i(len), then every sample is returned once. If @i(step) is less than @i(len), each returned array will overlap the previous one, so some samples will be returned more than once. If @i(step) is greater than @i(len), then some samples will be skipped and not returned in any array. The @i(step) and @i(len) may change at each call, but in the current implementation, an internal buffer is allocated for @i(sound) on the first call, so subsequent calls may not specify a greater @i(len) than the first. When an array is returned, it will have @i(len) samples. If necessary, @code(snd-fetch-array) will read zeros beyond the end of the sound to fill the array. When this happens, @code(*rslt*) is set to a FIXNUM number of samples in the array that were read from the sound before the physical stop time of the sound. If all samples in the array are ``valid'' samples from the sound (coming from the sound before the sound terminates), @code(*rslt*) is set to @code(NIL). The @code(*rslt*) variable is global and used to return extra results from other functions, so programs should not assume @code(*rslt*) is valid after subsequent function calls. @p(Note:) @code(snd-fetch-array) modifies @i(sound); it is strongly recommended to copy @i(sound) using @code(snd-copy) and access only the copy with @code(snd-fetch-array). @codef[snd-flatten(@pragma(defn)@index(snd-flatten)@i(sound), @i(maxlen))] @c{[sal]}@* @altdef{@code[(snd-flatten @i(sound) @i(maxlen))] @c{[lisp]}}@\This function is identical to @code(snd-length). You would use this function to force samples to be computed in memory. Normally, this is not a good thing to do, but here is one appropriate use: In the case of sounds intended for wavetables, the unevaluated sound may be larger than the evaluated (and typically short) one. Calling @code(snd-flatten) will compute the samples and allow the unit generators to be freed in the next garbage collection. @p(Note:) If a sound is computed from many instances of table-lookup oscillators, calling @code(snd-flatten) will free the oscillators and their tables. Calling @code[(stats)] will print how many total bytes have been allocated to tables. @codef[snd-length(@pragma(defn)@index(snd-length)@i(sound), @i(maxlen))] @c{[sal]}@* @altdef{@code[(snd-length @i(sound) @i(maxlen))] @c{[lisp]}}@\Counts the number of samples in @i(sound) up to the physical stop time. If the sound has more than @i(maxlen) samples, @i(maxlen) is returned. Calling this function will cause all samples of the sound to be computed and saved in memory (about 4 bytes per sample). Otherwise, this function is safe for ordinary use. @codef[snd-maxsamp(@pragma(defn)@index(snd-maxsamp)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-maxsamp @i(sound))] @c{[lisp]}}@\Computes the maximum of the absolute value of the samples in @i(sound). Calling this function will cause samples to be computed and saved in memory. (This function should have a @i(maxlen) parameter to allow self-defense against sounds that would exhaust available memory.) Otherwise, this function is safe for ordinary use. This function will probably be removed in a future version. See @code(peak), a replacement (@pragma(startref) page @pageref(peak-sec)). @codef[snd-play(@pragma(defn)@index(snd-play)@i(expression))] @c{[sal]}@* @altdef{@code[(snd-play @i(expression))] @c{[lisp]}}@\Evaluates @i(expression) to obtain a sound or array of sounds, computes all of the samples (without retaining them in memory), and returns. Originally, this was a placeholder for a facility to play samples directly to an audio output device, but playback is now accomplished by @code(s-save). Meanwhile, since this function does not save samples in memory or write them to a disk, it is useful in determining how much time is spent calculating samples. See @code(s-save) (Section @ref(s-save-sec)) for saving samples to a file, and @code(play) (Section @ref(play-sec)) to play a sound. This function is safe for ordinary use. @codef[snd-print-tree(@pragma(defn)@index(snd-print-tree)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-print-tree @i(sound))] @c{[lisp]}}@\Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging Nyquist. This function is safe for ordinary use. @codef[snd-samples(@index(samples)@pragma(defn)@index(snd-samples)@index(array from sound)@index(convert sound to array)@i(sound), @i(limit))] @c{[sal]}@* @altdef{@code[(snd-samples @i(sound) @i(limit))] @c{[lisp]}}@\Converts the samples into a lisp array. The data is taken directly from the samples, ignoring shifts. For example, if the sound starts at 3.0 seconds, the first sample will refer to time 3.0, not time 0.0. A maximum of @i(limit) samples is returned. This function is safe for ordinary use, but like @code(snd-from-array), it requires a total of slightly over 18 bytes per sample. @codef[snd-srate(@pragma(defn)@index(snd-srate)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-srate @i(sound))] @c{[lisp]}}@\Returns the sample rate of the sound. Safe for ordinary use. @begin(comment) @codef[snd-show(@pragma(defn)@index(snd-show)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-show @i(sound))] @c{[lisp]}}@\Print the entire (internal) structure of the sound for debugging. Safe for ordinary use. @end(comment) @codef[snd-time(@pragma(defn)@index(snd-time)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-time @i(sound))] @c{[lisp]}}@\Returns the start time of the sound. This will probably go away in a future version, so use @code(snd-t0) instead. @codef[snd-t0(@pragma(defn)@index(snd-t0)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-t0 @i(sound))] @c{[lisp]}}@\Returns the time of the first sample of the sound. Note that Nyquist operators such as add always copy the sound and are allowed to shift the copy up to one half sample period in either direction to align the samples of two operands. Safe for ordinary use. @codef[snd-print(@pragma(defn)@index(snd-print)@i(expression), @i(maxlen))] @c{[sal]}@* @altdef{@code[(snd-print @i(expression) @i(maxlen))] @c{[lisp]}}@\Evaluates @i(expression) to yield a sound or an array of sounds, then prints up to @i(maxlen) samples to the screen (stdout). This is similar to @code(snd-save), but samples appear in text on the screen instead of in binary in a file. This function is intended for debugging@index(debugging). Safe for ordinary use. @codef[snd-set-logical-stop(@pragma(defn)@index(snd-set-logical-stop)@i(sound), @i(time))] @c{[sal]}@* @altdef{@code[(snd-set-logical-stop @i(sound) @i(time))] @c{[lisp]}}@\Returns a sound which is @i(sound), except that the logical stop of the sound occurs at @i(time). @p(Note:) do not call this function. When defining a behavior, use @code(set-logical-stop) or @code(set-logical-stop-abs) instead. @codef[snd-sref(@pragma(defn)@index(snd-sref)@i(sound), @i(time))] @c{[sal]}@* @altdef{@code[(snd-sref @i(sound) @i(time))] @c{[lisp]}}@\Evaluates @i(sound) at the global time given by @i(time). Safe for ordinary use, but normally, you should call @code(sref) instead. @codef[snd-stop-time(@pragma(defn)@index(snd-stop-time)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-stop-time @i(sound))] @c{[lisp]}}@\Returns the stop time of @i(sound). Sounds can be ``clipped'' or truncated at a particular time. This function returns that time or MAX-STOP-TIME if he programmer has not specified a stop time for the sound. Safe for ordinary use. @codef[soundp(@pragma(defn)@index(soundp)@i(sound))] @c{[sal]}@* @altdef{@code[(soundp @i(sound))] @c{[lisp]}}@\Returns true iff @i(sound) is a SOUND. Safe for ordinary use. @codef[stats(@pragma(defn)@index(stats)@index(memory usage)@index(table memory))] @c{[sal]}@* @altdef{@code[(stats)] @c{[lisp]}}@\Prints the memory usage status. See also the XLISP @code(mem) function. Safe for ordinary use. This is the only way to find out how much memory is being used by table-lookup oscillator instances. @end(fndefs) @subsection(Miscellaneous Functions) These are all safe and recommended for ordinary use. @begin(fndefs) @codef[db-to-linear(@pragma(defn)@index(db-to-linear)@i(x))] @c{[sal]}@* @altdef{@code[(db-to-linear @i(x))] @c{[lisp]}}@\Returns the conversion of @i(x) from decibels to linear. 0dB is converted to 1. 20dB represents a linear factor of 10. If @i(x) is a sound, each sample is converted and a sound is returned. If @i(x) is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. @p(Note:) With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Sample rates, start times, etc. are taken from @i(x). @codef[follow(@pragma(defn)@index(follow)@index(envelope follower)@index(compressor)@index(limiter)@i(sound), @i(floor), @i(risetime), @i(falltime), @i(lookahead))] @c{[sal]}@* @altdef{@code[(follow @i(sound) @i(floor) @i(risetime) @i(falltime) @i(lookahead))] @c{[lisp]}}@\An envelope follower intended as a commponent for compressor and limiter functions. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The @i(floor) is the minimum output value. The @i(risetime) is the time (in seconds) it takes for the output to rise (exponentially) from @i(floor) to unity (1.0) and the @i(falltime) is the time it takes for the output to fall (exponentially) from unity to @i(floor). The algorithm looks ahead for peaks and will begin to increase the output signal according to @i(risetime) in anticipation of a peak. The amount of anticipation (in seconds) is given by @i(lookahead). The algorithm is as follows: the output value is allowed to increase according to @i(risetime) or decrease according to @i(falltime). If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to @i(risetime) to meet the new value. The algorithm will only work backward as far as @i(lookahead). If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by @i(falltime), the output fall rate will be limited by @i(falltime), and the fall in output will stop when the output reaches @i(floor). This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See @code(snd-avg) for a function that can help to generate a low-sample-rate input for @code(follow). See @code(snd-chase) in Section @ref(snd-chase-sec) for a related filter. @label(gate-sec) @codef[gate(@pragma(defn)@index(gate)@index(noise-gate)@i(sound), @i(lookahead), @i(risetime), @i(falltime), @i(floor), @i(threshold))] @c{[sal]}@* @altdef{@code[(gate @i(sound) @i(lookahead) @i(risetime) @i(falltime) @i(floor) @i(threshold))] @c{[lisp]}}@\Generate an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below @i(threshold) and stays there for longer than @i(lookahead) (a @code(FLONUM) in seconds). (The signal begins to drop when the signal crosses @i(threshold), not after @i(lookahead).) Decay continues until the value reaches @i(floor) (a @code(FLONUM)), at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above @i(threshold), then the ouptut value will rise to unity (1.0) at the point the signal crosses the threshold. Because of internal lookahead, the signal actually begins to rise before the signal crosses @i(threshold). The rise is a constant-rate exponential and set so that a rise from @i(floor) to unity occurs in @i(risetime). Similary, the fall is a constant-rate exponential such that a fall from unity to @i(floor) takes @i(falltime). @codef[hz-to-step(@pragma(defn)@index(hz-to-step)@i(freq))] @c{[sal]}@* @altdef{@code[(hz-to-step @i(freq))] @c{[lisp]}}@\Returns a step number for @i(freq) (in hz), which can be either a number of a @code(SOUND). The result has the same type as the argument. See also @code(step-to-hz) (below). @codef[linear-to-db(@pragma(defn)@index(linear-to-db)@i(x))] @c{[sal]}@* @altdef{@code[(linear-to-db @i(x))] @c{[lisp]}}@\Returns the conversion of @i(x) from linear to decibels. 1 is converted to 0. 0 is converted to -INF (a special IEEE floating point value.) A factor of 10 represents a 20dB change. If @i(x) is a sound, each sample is converted and a sound is returned. If @i(x) is a multichannel sound, each channel is converted and a multichannel sound (array) is returned. @p(Note:) With sounds, conversion is only performed on actual samples, not on the implicit zeros before the beginning and after the termination of the sound. Start times, sample rates, etc. are taken from @i(x). @codef[log(@index(log function)@pragma(defn)@index(log)@i(x))] @c{[sal]}@* @altdef{@code[(log @i(x))] @c{[lisp]}}@\Calculates the natural log of @i(x) (a @code(FLONUM)). (See @code(s-log) for a version that operates on signals.) @codef[set-control-srate(@pragma(defn)@index(set-control-srate)@index(sampling rate)@i(rate))] @c{[sal]}@* @altdef{@code[(set-control-srate @i(rate))] @c{[lisp]}}@\Sets the default sampling rate for control signals to @i(rate) by setting @code(*default-control-srate*) and reinitializing the environment. Do not call this within any synthesis function (see the @code(control-srate-abs) transformation, Section @ref(control-srate-abs-sec)). @codef[set-sound-srate(@pragma(defn)@index(set-sound-srate)@index(sampling rate)@i(rate))] @c{[sal]}@* @altdef{@code[(set-sound-srate @i(rate))] @c{[lisp]}}@\Sets the default sampling rate for audio signals to @i(rate) by setting @code(*default-sound-srate*) and reinitializing the environment. Do not call this within any synthesis function (see the @code(sound-srate-abs) transformation, Section @ref(sound-srate-abs-sec)). @codef[set-pitch-names(@pragma(defn)@index(set-pitch-names))] @c{[sal]}@* @altdef{@code[(set-pitch-names)] @c{[lis]}}@\Initializes pitch variables (@code(c0), @code(cs0), @code(df0), @code(d0), ... @code(b0), @code(c1), ... @code(b7)). A440 (the default tuning) is represented by the step 69.0, so the variable @code(a4) (fourth octave A) is set to 69.0. You can change the tuning by setting @code(*A4-Hertz*)@index(tuning)@index(A440)@index(*A4-Hertz*) to a value (in Hertz) and calling @code(set-pitch-names) to reinitialize the pitch variables. Note that this will result in non-integer step values. It does not alter the mapping from step values to frequency. There is no built-in provision for stretched scales or non-equal temperament, although users can write or compute any desired fractional step values. @codef[step-to-hz(@pragma(defn)@index(step-to-hz)@i(pitch))] @c{[sal]}@* @altdef{@code[(step-to-hz @i(pitch))] @c{[lisp]}}@\Returns a frequency in hz for @i(pitch), a step number or a @code(SOUND) type representing a time-varying step number. The result is a @code(FLONUM) if @i(pitch) is a number, and a @code(SOUND) if @i(pitch) is a @code(SOUND). See also @code(hz-to-step) (above). @codef{get-duration(@pragma(defn)@index(get-duration)@i(dur))} @c{[sal]}@* @altdef{@code[(get-duration @i(dur))] @c{[lisp]}}@\Gets the actual duration of of something starting at a local time of 0 and ending at a local time of @i(dur) times the current sustain. For convenience, @code(*rslt*) is set to the global time corresponding to local time zero. @codef{get-loud(@pragma(defn)@index(get-loud))} @c{[sal]}@* @altdef{@code[(get-loud)] @c{[lisp]}}@\Gets the current value of the @code(*loud*) environment variable. If @code(*loud*) is a signal, it is evaluated at local time 0 and a number (@code(FLONUM)) is returned. @codef{get-sustain(@pragma(defn)@index(get-sustain))} @c{[sal]}@* @altdef{@code[(get-sustain)] @c{[lisp]}}@\Gets the current value of the @code(*sustain*) environment variable. If @code(*sustain*) is a signal, it is evaluated at local time 0 and a number (@code(FLONUM)) is returned. @codef{get-transpose(@pragma(defn)@index(get-transpose))} @c{[sal]}@* @altdef{@code[(get-transpose)] @c{[lisp]}}@\Gets the current value of the @code(*transpose*) environment variable. If @code(*transpose*) is a signal, it is evaluated at local time 0 and a number (@code(FLONUM)) is returned. @codef{get-warp(@pragma(defn)@index(get-warp))} @c{[sal]}@* @altdef{@code[(get-warp)] @c{[lisp]}}@\Gets a function corresponding to the current value of the @code(*warp*) environment variable. For efficiency, @code(*warp*) is stored in three parts representing a shift, a scale factor, and a continuous warp function. @code(Get-warp) is used to retrieve a signal that maps logical time to real time. This signal combines the information of all three components of @code(*warp*) into a single signal. If the continuous warp function component is not present (indicating that the time warp is a simple combination of @code(at) and @code(stretch) transformations), an error is raised. This function is mainly for internal system use. In the future, @code(get-warp) will probably be reimplemented to always return a signal and never raise an error. @CODEF{LOCAL-to-global(@pragma(defn)@index(local-to-global)@i(local-time))} @c{[sal]}@* @altdef{@code[(local-to-global @i(local-time))] @c{[lisp]}}@\Converts a score (local) time to a real (global) time according to the current environment. @codef{osc-enable(@pragma(defn)@index(osc-enable)@index(osc)@index(open sound control)@i(flag))} @c{[sal]}@* @altdef{@code[(osc-enable @i(flag))] @c{[lisp]}}@\Enable or disable Open Sound Control. (See Appendix @ref(osc-app).) Enabling creates a socket and a service that listens for UDP packets on port 7770. Currently, only two messages are accepted by Nyquist. The first is of the form @code(/slider) with an integer index and a floating point value. These set internal slider values accessed by the @code(snd-slider) function. The second is of the form @code(/wii/orientation) with two floating point values. This message is a special case to support the DarwiinRemoteOsc@index(DarwiinRemoteOsc) program which can relay data from a Nintendo@index(Nintendo WiiMote) WiiMote@index(Wii Controller) device to Nyquist via OSC. The two orientation values control sliders 0 and 1. Disabling terminates the service (polling for messages) and closes the socket. The @i(previous) state of enablement is returned, e.g. if OSC is enabled and @i(flag) is @i(nil), OSC is disabled and @code(T) (true) is returned because OSC was enabled at the time of the call. This function only exists if Nyquist is compiled with the compiler flag @code(OSC). Otherwise, the function exists but always returns the symbol @code(DISABLED). Consider lowering the audio latency using @code(snd-set-latency). @i(Warning:) there is the potential for network-based attacks using OSC. It is tempting to add the ability to evaluate XLISP expressions sent via OSC, but this would create unlimited and unprotected access to OSC clients. For now, it is unlikely that an attacker could do more than manipulate slider values. @codef{snd-set-latency(@index(latency)@pragma(defn)@index(snd-set-latency)@i(latency))} @c{[sal]}@* @altdef{@code[(snd-set-latency @i(latency))] @c{[lisp]}}@\Set the latency requested when Nyquist plays sound to @i(latency), a @code(FLONUM). The previous value is returned. The default is 0.3 seconds. To avoid glitches, the latency should be greater than the time required for garbage collection and message printing and any other system activity external to Nyquist. @end(fndefs) @section(Behaviors)@index(Behaviors) @label(behavior-sec) @subsection(Using Previously Created Sounds) @label(use-sounds-sec) These behaviors take a sound and transform that sound according to the environment. These are useful when writing code to make a high-level function from a low-level function, or when cuing sounds which were previously created: @begin(fndefs) @codef[cue(@pragma(defn)@index(cue)@i(sound))] @c{[sal]}@* @altdef{@code[(cue @i(sound))] @c{[lisp]}}@\Applies @code(*loud*), the starting time from @code(*warp*), @code(*start*), and @code(*stop*) to @i(sound). @codef[cue-file(@pragma(defn)@index(cue-file)@i(filename))] @c{[sal]}@* @altdef{@code[(cue-file @i(filename))] @c{[lisp]}}@\Same as @code(cue), except the sound comes from the named file, samples from which are coerced to the current default @code(*sound-srate*) sample rate. @codef[sound(@pragma(defn)@index(sound)@i(sound))] @c{[sal]}@* @altdef{@code[(sound @i(sound))] @c{[lisp]}}@\Applies @code(*loud*), @code(*warp*), @code(*start*), and @code(*stop*) to @i(sound). @codef[control(@pragma(defn)@index(control)@i(sound))] @c{[sal]}@* @altdef{@code[(control @i(sound))] @c{[lisp]}}@\This function is identical to @code(sound), but by convention is used when @i(sound) is a control signal rather than an audio signal. @end(fndefs) @subsection(Sound Synthesis) These functions provide musically interesting creation behaviors that react to their environment; these are the ``unit generators'' of Nyquist: @begin(fndefs) @codef{const(@pragma(defn)@index(const)@index(constant function)@i(value) [, @i(duration)])} @c{[sal]}@* @altdef{@code{(const @i(value) [@i(duration)])} @c{[lisp]}}@\Creates a constant function at the @code(*control-srate*). Every sample has the given @i(value), and the default @i(duration) is 1.0. See also @code(s-rest), which is equivalent to calling @code(const) with zero, and note that you can pass scalar constants (numbers) to @code(sim), @code(sum), and @code(mult) where they are handled more efficiently than constant functions. @codef{env(@pragma(defn)@index(env)@i(t@-[1]), @i(t@-[2]), @i(t@-[4]), @i(l@-[1]), @i(l@-[2]), @i(l@-[3]), [@i(dur)])} @c{[sal]}@* @altdef{@code[(env @i(t@-[1]) @i(t@-[2]) @i(t@-[4]) @i(l@-[1]) @i(l@-[2]) @i(l@-[3]) @i(dur))] @c{[lisp]}}@\Creates a 4-phase envelope. @i(t@-[@i(i)]) is the duration of phase @i(i), and @i(l@-[@i(i)]) is the final level of phase @i(i). @i(t@-[3]) is implied by the duration @i(dur), and @i(l@-[4]) is @code(0.0). If @i(dur) is not supplied, then @code(1.0) is assumed. The envelope duration is the product of @i(dur), @code(*stretch*), and @code(*sustain*). If @i(t@-[1]) + @i(t@-[2]) + 2ms + @i(t@-[4]) is greater than the envelope duration, then a two-phase envelope is substituted that has an attack/release time ratio of @i(t@-[1])/@i(t@-[4]). The sample rate of the returned sound is @code(*control-srate*). (See @code(pwl) for a more general piece-wise linear function generator.) The effect of time warping is to warp the starting time and ending time. The intermediate breakpoints are then computed as described above. @codef{exp-dec(@pragma(defn)@index(exp-dec)@index(exponential envelope)@i(hold), @i(halfdec), @i(length))} @c{[sal]}@* @altdef{@code[(exp-dec @i(hold) @i(halfdec) @i(length))] @c{[lisp]}}@\This convenient envelope shape is a special case of @code(pwev) (see Section @ref(pwev-sec)). The envelope starts at 1 and is constant for @i(hold) seconds. It then decays with a half life of @i(halfdec) seconds until @i(length). (The total duration is @i(length).) In other words, the amplitude falls by half each @i(halfdec) seconds. When stretched, this envelope scales linearly, which means the hold time increases and the half decay time increases. @label(force-srate-sec) @codef{force-srate(@pragma(defn)@index(force-srate)@index(sample rate, forcing)@index(resampling)@i(srate), @i(sound))} @c{[sal]}@* @altdef{@code[(force-srate @i(srate) @i(sound))] @c{[lisp]}}@\Returns a sound which is up- or down-sampled to @i(srate). Interpolation is linear, and no prefiltering is applied in the down-sample case, so aliasing may occur. See also @code(resample). @codef{lfo(@pragma(defn)@index(lfo)@index(low-frequency oscillator)@i(freq) [, @i(duration), @i(table), @i(phase)])} @c{[sal]}@* @altdef{@code[(lfo @i(freq) @i(duration) @i(table) @i(phase))] @c{[lisp]}}@\Just like @code(osc) (below) except this computes at the @code(*control-srate*) and frequency is specified in Hz. Phase is specified in degrees. The @code(*transpose*) and @code(*sustain*) is not applied. The effect of time warping is to warp the starting and ending times. The signal itself will have a constant unwarped frequency. @codef{fmlfo(@pragma(defn)@index(fmlfo)@i(freq) [, @i(table), @i(phase)])} @c{[sal]}@* @altdef{@code{(fmlfo @i(freq) [@i(table) @i(phase)])} @c{[lisp]}}@\A low-frequency oscillator that computes at the @code(*control-srate*) using a sound to specify a time-varying frequency in Hz. Phase is a @code(FLONUM) in degrees. The duration of the result is determined by @i(freq). @codef{maketable(@pragma(defn)@index(maketable)@label(maketable)@i(sound))} @c{[sal]}@* @altdef{@code[(maketable @i(sound))] @c{[lisp]}}@\Assumes that the samples in @i(sound) constitute one period of a wavetable, and returns a wavetable suitable for use as the @i(table) argument to the @code(osc) function (see below). Currently, tables are limited to 1,000,000 samples. This limit is the compile-time constant @code(max_table_len) set in @code(sound.h). @codef{build-harmonic(@pragma(defn)@index(build-harmonic)@index(harmonic)@i(n), @i(table-size))} @c{[sal]}@* @altdef{@code[(build-harmonic @i(n) @i(table-size))] @c{[lisp]}}@\Intended for constructing wavetables@index(wavetables)@index(waveforms), this function returns a sound of length @i(table-size) samples containing @i(n) periods of a sinusoid. These can be scaled and summed to form a waveform with the desired harmonic content. See @pragma(startref) page @pageref(build-harmonic-example) for an example. @codef{control-warp(@pragma(defn)@index(control-warp)@i(warp-fn), @i(signal), [@i(wrate)])} @c{[sal]}@* @altdef{@code[(control-warp @i(warp-fn) @i(signal) @i(wrate))] @c{[lisp]}}@\Applies a warp function @i(warp-fn) to @i(signal) using function composition. If @i(wrate) is omitted, linear interpolation is used. @i(warp-fn) is a mapping from score (logical) time to real time, and @i(signal) is a function from score time to real values. The result is a function from real time to real values at a sample rate of @code(*control-srate*). See @code(sound-warp) for an explanation of @i(wrate) and high-quality warping. @label(mult-sec) @codef{mult(@pragma(defn)@index(mult)@i(beh@-[1]), @i(beh@-[2]), @r(...))} @c{[sal]}@* @altdef{@code[(mult @i(beh@-[1]) @i(beh@-[2] @r(...)))] @c{[lisp]}}@\Returns the product of behaviors. The arguments may also be numbers, in which case simple multiplication is performed. If a number and sound are mixed, the @code(scale) function is used to scale the sound by the number. When sounds are multiplied, the resulting sample rate is the maximum sample rate of the factors. @codef{prod(@pragma(defn)@index(prod)@i(beh@-[1]), @i(beh@-[2]), @r(...))} @c{[sal]}@* @altdef{@code[(prod @i(beh@-[1]) @i(beh@-[2]) @r(...))] @c{[lisp]}}@\Same as @code(mult). @label(pan-sec) @codef{pan(@pragma(defn)@index(pan)@index(stereo panning)@i(sound), @i(where))} @c{[sal]}@* @altdef{@code[(pan @i(sound) @i(where))] @c{[lisp]}}@\Pans @i(sound) (a behavior) according to @i(where) (another behavior or a number). @i(Sound) must be monophonic. @i(Where) may be a monophonic sound (e.g. @code[(ramp)] or simply a number (e.g. @code(0.5)). In either case, @i(where) should range from 0 to 1, where 0 means pan completely left, and 1 means pan completely right. For intermediate values, the sound to each channel is scaled linearly. Presently, @code(pan) does not check its arguments carefully. @codef{prod(@pragma(defn)@index(prod)@i(beh@-[1]), @i(beh@-[2]), @r(...))} @c{[sal]}@* @altdef{@code[(prod @i(beh@-[1]) @i(beh@-[2]) @r(...))] @c{[lisp]}}@\Same as @code(mult). @label(resample-sec) @codef{resample(@pragma(defn)@index(resample)@i(sound), @i(srate))} @c{[sal]}@* @altdef{@code[(resample @i(sound) @i(srate))] @c{[lisp]}}@\Similar to @code(force-srate), except high-quality interpolation is used to prefilter and reconstruct the signal at the new sample rate. Also, the result is scaled by 0.95 to reduce problems with clipping. (See also @code(sound-warp).) @label(scale-sec) @codef{scale(@pragma(defn)@index(scale)@i(scale), @i(sound))} @c{[sal]}@* @altdef{@code[(scale @i(scale) @i(sound))] @c{[lisp]}}@\Scales the amplitude of @i(sound) by the factor @i(scale). Identical function to @code(snd-scale), except that it handles multichannel sounds. Sample rates, start times, etc. are taken from @i(sound). @codef{scale-db(@pragma(defn)@index(scale-db)@i(db), @i(sound))} @c{[sal]}@* @altdef{@code[(scale-db @i(db) @i(sound))] @c{[lisp]}}@\Scales the amplitude of @i(sound) by the factor @i(db), expressed in decibels. Sample rates, start times, etc. are taken from @i(sound). @codef[scale-srate(@pragma(defn)@index(scale-srate)@i(sound), @i(scale))] @c{[sal]}@* @altdef{@code[(scale-srate @i(sound) @i(scale))] @c{[lisp]}}@\Scales the sample rate of @i(sound) by @i(scale) factor. This has the effect of linearly shrinking or stretching time (the sound is not upsampled or downsampled). This is a special case of @code(snd-xform) (see Section @ref(snd-xform-sec)). @codef[shift-time(@pragma(defn)@index(shift-time)@i(sound), @i(shift))] @c{[sal]}@* @altdef{@code[(shift-time @i(sound) @i(shift))] @c{[lisp]}}@\Shift @i(sound) by @i(shift) seconds. If the sound is @pragma(startscribe) @math[f(t)], then the result is @pragma(endscribe) @html[f(t), then the result is] @pragma(startscribe) @math[f(t - shift)]. @pragma(endscribe) @html[f(t - shift).] See Figure @ref(shift-time-fig). This is a special case of @code(snd-xform) (see Section @ref(snd-xform-sec)). @end(fndefs) @begin(figure) @center(@graphic((height = 3 in, width = 4.5 in, magnify = 0.75, postscript = "shifttimefig.ps")) @html(

    ) @fillcaption(The @code(shift-time) function shifts a sound in time according to its @i(shift) argument.) @tag(shift-time-fig) @end(figure) @begin(fndefs) @codef{sound-warp(@pragma(defn)@index(sound-warp)@i(warp-fn), @i(signal) [, @i(wrate)])} @c{[sal]}@* @altdef{@code{(sound-warp @i(warp-fn) @i(signal) [@i(wrate)])} @c{[lisp]}}@\Applies a warp function @i(warp-fn) to @i(signal) using function composition. If the optional parameter @i(wrate) is omitted or NIL, linear interpolation is used. Otherwise, high-quality sample interpolation is used, and the result is scaled by 0.95 to reduce problems with clipping (interpolated samples can exceed the peak values of the input samples.) @i(warp-fn) is a mapping from score (logical) time to real time, and @i(signal) is a function from score time to real values. The result is a function from real time to real values at a sample rate of @code(*sound-srate*). See also @code(control-warp). @blankspace(1) If @i(wrate) is not NIL, it must be a number. The parameter indicates that high-quality resampling should be used and specifies the sample rate for the inverse of @i(warp-fn). Use the lowest number you can. (See below for details.) Note that high-quality resampling is much slower than linear interpolation. @blankspace(1) To perform high-quality resampling by a fixed ratio, as opposed to a variable ratio allowed in @code(sound-warp), use @code(scale-srate) to stretch or shrink the sound, and then @code(resample) to restore the original sample rate. @blankspace(1) @code(Sound-warp) and @code(control-warp) both take the inverse of @i(warp-fn) to get a function from real time to score time. Each sample of this inverse is thus a score time; @i(signal) is evaluated at each of these score times to yield a value, which is the desired result. The sample rate of the inverse warp function is somewhat arbitrary. With linear interpolation, the inverse warp function sample rate is taken to be the output sample rate. Note, however, that the samples of the inverse warp function are stored as 32-bit floats, so they have limited precision. Since these floats represent sample times, rounding can be a problem. Rounding in this case is equivalent to adding jitter to the sample times. Nyquist ignores this problem for ordinary warping, but for high-quality warping, the jitter cannot be ignored. @blankspace(1) The solution is to use a rather low sample rate for the inverse warp function. @code(Sound-warp) can then linearly interpolate this signal using double-precision floats to minimize jitter between samples. The sample rate is a compromise: a low sample rate minimizes jitter, while a high sample rate does a better job of capturing detail (e.g. rapid fluctuations) in the warp function. A good rule of thumb is to use at most 1,000 to 10,000 samples for the inverse warp function. For example, if the result will be 1 minute of sound, use a sample rate of 3000 samples / 60 seconds = 50 samples/second. Because Nyquist has no advance information about the warp function, the inverse warp function sample rate must be provided as a parameter. When in doubt, just try something and let your ears be the judge. @codef[integrate(@pragma(defn)@index(integrate)@index(smooth)@i(signal))] @c{[sal]}@* @altdef{@code[(integrate @i(signal))] @c{[lisp]}}@\Computes the integral of @i(signal). The start time, sample rate, etc. are taken from @i(signal). @codef[slope(@pragma(defn)@index(slope)@index(derivative)@index(first derivative)@i(signal))] @c{[sal]}@* @altdef{@code[(slope @i(signal))] @c{[lisp]}}@\Computes the first derivative (slope) of @i(signal). The start time, sample rate, etc. are taken from @i(signal). @end(fndefs) @paragraph(Oscillators) @label(osc-sec) @begin(fndefs) @codef{osc(@pragma(defn)@index(osc)@i(pitch) [, @i(duration), @i(table), @i(phase)])} @c{[sal]}@* @altdef{@code{(osc @i(pitch) [@i(duration) @i(table) @i(phase)])} @c{[lisp]}}@\Returns a sound which is the @i(table) oscillated at @i(pitch) for the given @i(duration), starting with the @i(phase) (in degrees). Defaults are: @i(duration) @code(1.0) (second), @i(table) @code(*table*), @i(phase) @code(0.0). The default value of @code(*table*) is a sinusoid. Duration is stretched by @code(*warp*) and @code(*sustain*), amplitude is nominally 1, but scaled by @code(*loudness*), the start time is logical time 0, transformed by @code(*warp*), and the sample rate is @code(*sound-srate*). The effect of time-warping is to warp the starting and ending times only; the signal has a constant unwarped frequency. @p(Note 1:) @i(table) is a list of the form @begin(display) (@i(sound) @i(pitch-number) @i(periodic)) @end(display) where the first element is a sound, the second is the pitch of the sound (this is not redundant, because the sound may represent any number of periods), and the third element is @code(T) if the sound is one period of a periodic signal, or @code(nil) if the sound is a sample that should not be looped. The maximum table size is set by @code(max_table_len) in @code(sound.h), and is currently set to 1,000,000. @p(Note 2:) in the current implementation, it is assumed that the output should be periodic. See @code(snd-down) and @code(snd-up) for resampling one-shot sounds to a desired sample rate. A future version of @code(osc) will handle both cases. @p(Note 3:) When @code(osc) is called, memory is allocated for the table, and samples are copied from the sound (the first element of the list which is the @i(table) parameter) to the memory. Every instance of @code(osc) has a private copy of the table, so the total storage can become large in some cases, for example in granular synthesis with many instances of @code(osc). In some cases, it may make sense to use @code(snd-flatten) (see Section @ref(flatten-sec)) to cause the sound to be fully realized, after which the @code(osc) and its table memory can be reclaimed by garbage collection. The @code(partial) function (see below) does not need a private table and does not use much space. @label(partial-sec) @codef{partial(@pragma(defn)@index(partial)@i(pitch), @i(env))} @c{[sal]}@* @altdef{@code[(partial @i(pitch) @i(env))] @c{[lisp]}}@\Returns a sinusoid at the indicated pitch; the sound is multiplied by @i(env). The start time and duration are taken from @i(env), which is of course subject to transformations. The sample rate is @code(*sound-srate*). The @code(partial) function is faster than @code(osc). @label(sine-sec) @codef{sine(@pragma(defn)@index(sine)@i(pitch) [, @i(duration)])} @c{[sal]}@* @altdef{@code{(sine @i(pitch) [@i(duration)])} @c{[lisp]}}@\Returns a sinusoid at the indicated pitch. The sample rate is @code(*sound-srate*). This function is like @code(osc) with respect to transformations. The @code(sine) function is faster than @code(osc). @codef{hzosc(@pragma(defn)@index(hzosc)@i(hz) [, @i(table), @i(phase)])} @c{[sal]}@* @altdef{@code{(hzosc @i(hz) [@i(table) @i(phase)])} @c{[lisp]}}@\Returns a sound which is the @i(table) oscillated at @i(hz) starting at @i(phase) degrees. The default @i(table) is @code(*table*) and the default @i(phase) is @i(0.0). The default duration is @code(1.0), but this is stretched as in @code(osc) (see above). The @i(hz) parameter may be a @code(SOUND), in which case the duration of the result is the duration of @i(hz). The sample rate is @code(*sound-srate*). @codef{osc-saw(@pragma(defn)@index(osc-saw)@index(sawtooth oscillator)@i(hz))} @c{[sal]}@* @altdef{@code[(osc-saw @i(hz))] @c{[lisp]}}@\Returns a sawtooth waveshape at the indicated frequency (in Hertz). The sample rate is @code(*sound-srate*). The @i(hz) parameter may be a sound as in @i(hzosc) (see above). @codef{osc-tri(@pragma(defn)@index(osc-tri)@index(triangle oscillator)@i(hz))} @c{[sal]}@* @altdef{@code[(osc-tri @i(hz))] @c{[lisp]}}@\Returns a triangle waveshape at the indicated frequency (in Hertz). The sample rate is @code(*sound-srate*). The @i(hz) parameter may be a sound as in @i(hzosc) (see above). @codef{osc-pulse(@pragma(defn)@index(osc-pulse)@index(square oscillator)@index(pulse oscillator)@index(pulse-width modulation)@i(hz), @i(bias) [, @i(compare-shape)])} @c{[sal]}@* @altdef{@code{(osc-pulse @i(hz) @i(bias) [@i(compare-shape)])} @c{[lisp]}}@\Returns a square pulse with variable width at the indicated frequency (in Hertz). The @i(bias) parameter controls the pulse width and should be between @code(-1) and @code(+1), giving a pulse width from 0% (always at @code(-1)) to 100% (always at @code(+1)). When bias is zero, a square wave is generated. Bias may be a @code(SOUND) to create varying pulse width. If bias changes rapidly, strange effects may occur. The optional @i(compare-shape) defaults to a hard step at zero, but other shapes may be used to achieve non-square pulses. The @code(osc-pulse) behavior is written in terms of other behaviors and defined in the file @code(nyquist.lsp) using just a few lines of code. Read the code for the complete story. @label(amosc-sec) @codef{amosc(@pragma(defn)@index(amosc)@i(pitch), @i(modulation) [, @i(table), @i(phase)])} @c{[sal]}@* @altdef{@code{(amosc @i(pitch) @i(modulation) [@i(table) @i(phase)])} @c{[lisp]}}@\Returns a sound which is @i(table) oscillated at @i(pitch). The output is multiplied by @i(modulation) for the duration of the sound @i(modulation). @i(osc-table) defaults to @code(*table*), and @i(phase) is the starting phase (default 0.0 degrees) within @i(osc-table). The sample rate is @code(*sound-srate*). @label(fmosc-sec) @codef{fmosc(@pragma(defn)@index(fmosc)@i(pitch), @i(modulation) [, @i(table), @i(phase)])} @c{[sal]}@* @altdef{@code{(fmosc @i(pitch) @i(modulation) [@i(table) @i(phase)])} @c{[lisp]}}@\Returns a sound which is @i(table) oscillated at @i(pitch) plus @i(modulation) for the duration of the sound @i(modulation). @i(osc-table) defaults to @code(*table*), and @i(phase) is the starting phase (default 0.0 degrees) within @i(osc-table). The @i(modulation) is expressed in hz, e.g. a sinusoid modulation signal with an amplitude of 1.0 (2.0 peak to peak), will cause a +/@subtract 1.0 hz frequency deviation in @i(sound). Negative frequencies are correctly handled. The sample rate is @code(*sound-srate*). @label(fmfb-sec) @codef{fmfb(@pragma(defn)@index(fmfb)@index(Feedback FM Oscillator)@i(pitch), @i(index) [, @i(dur)])} @c{[sal]}@* @altdef{@code{(fmfb @i(pitch) @i(index) [@i(dur)])} @c{[lisp]}}@\Returns a sound generated by feedback FM synthesis. The @i(pitch) parameter (given in the usual half-step units) controls the fundamental frequency. The @i(index) is the amount of feedback, which may be a @code(SOUND) or a @code(FLONUM). If @i(index) is a @code(FLONUM), @i(dur) must be provided (a @code(FLONUM)) to specify the duration. Otherwise, @i(dur) is ignored if present and the duration is determined by that of @i(index). The sample rate is @code(*sound-srate*). A sinusoid table is used. If @i(index) is below 1.1, this generates a sawtooth-like waveform. @label(buzz-sec) @codef{buzz(@pragma(defn)@index(buzz)@i(n), @i(pitch), @i(modulation))} @c{[sal]}@* @altdef{@code[(buzz @i(n) @i(pitch) @i(modulation))] @c{[lisp]}}@\Returns a sound with @i(n) harmonics of equal amplitude and a total amplitude of 1.0, using a well-known function of two cosines. If @i(n) (an integer) is less than 1, it is set to 1. Aliasing will occur if @i(n) is too large. The duration is determined by the duration of the sound @i(modulation), which is a frequency modulation term expressed in Hz (see Section @ref(fmosc-sec)). Negative frequencies are correctly handled. The sample rate is @code(*sound-srate*). @label(pluck-sec) @codef{pluck(@pragma(defn)@index(pluck)@index(Karplus-Strong)@index(string synthesis)@index(plucked string)@i(pitch) [, @i(duration), @i(final-amplitude)])} @c{[sal]}@* @altdef{@code{(pluck @i(pitch) [@i(duration) @i(final-amplitude)])} @c{[lisp]}}@\Returns a sound at the given @i(pitch) created using a modified Karplus-Strong plucked string algorithm. The tone decays from an amplitude of about 1.0 to about @i(final-amplitude) in @i(duration) seconds. The default values are to decay to 0.001 (-60dB) in 1 second. The sample rate is @code(*sound-srate*). @label(siosc-sec) @codef{siosc(@pragma(defn)@index(siosc)@index(spectral interpolation)@i(pitch), @i(modulation), @i(tables))} @c{[sal]}@* @altdef{@code[(siosc @i(pitch) @i(modulation) @i(tables))] @c{[lisp]}}@\Returns a sound constructed by interpolating through a succession of periodic waveforms. The frequency is given (in half steps) by @i(pitch) to which a @i(modulation) signal (in hz) is added, exactly as in @code(fmosc). The @i(tables) specify a list of waveforms as follows: (@i(table0) @i(time1) @i(table2) ... @i(timeN) @i(tableN)), where each @i(table) is a sound representing one period. Each @i(time) is a time interval measured from the starting time. The time is scaled by the nominal duration (computed using @code[(local-to-global (get-sustain))]) to get the actual time. Note that this implies linear stretching rather than continuous timewarping of the interpolation or the breakpoints. The waveform is @i(table0) at the starting time, @i(table1) after @i(time1) (scaled as described), and so on. The duration and logical stop time is given by @i(modulation). If @i(modulation) is shorter than @i(timeN), then the full sequence of waveforms is not used. If @i(modulation) is longer than @i(timeN), @i(tableN) is used after @i(timeN) without further interpolation. @label(sampler-sec) @codef{sampler(@pragma(defn)@index(sampler)@i(pitch), @i(modulation) [, @i(sample), @i(npoints)])} @c{[sal]}@* @altdef{@code{(sampler @i(pitch) @i(modulation) [@i(sample) @i(npoints)])} @c{[lisp]}}@\Returns a sound constructed by reading a sample from beginning to end and then splicing on copies of the same sound from a loop point to the end. The @i(pitch) and @i(modulation) parameters are used as in @code(fmosc) described above. The optional @i(sample) (which defaults to the global variable @code(*table*) is a list of the form @begin(display) (@i(sound) @i(pitch-number) @i(loop-start)) @end(display) where the first element is a sound containing the sample, the second is the pitch of the sample, and the third element is the time of the loop point. If the loop point is not in the bounds of the sound, it is set to zero. The optional @i(npoints) specifies how many points should be used for sample interpolation. Currently this parameter defaults to 2 and only 2-point (linear) interpolation is implemented. It is an error to modulate such that the frequency is negative. Note also that the loop point may be fractional. The sample rate is @code(*sound-srate*). @end(fndefs) @paragraph(Piece-wise Approximations) @index(piece-wise)@index(approximation)@index(splines) There are a number of related behaviors for piece-wise approximations to functions. The simplest of these, @code(pwl) was mentioned earlier in the manual. It takes a list of breakpoints, assuming an initial point at (0, 0), and a final value of 0. An analogous piece-wise exponential function, @code(pwe), is provided. Its implicit starting and stopping values are 1 rather than 0. Each of these has variants. You can specify the initial and final values (instead of taking the default). You can specify time in intervals rather than cummulative time. Finally, you can pass a list rather than an argument list. This leads to 16 versions: @pragma(startscribe) @begin(display) @tabclear @tabset(0.4 inches, 0.8 inches, 1.2 inches) Piece-wise Linear Functions: @\Cummulative Time: @\@\Default initial point at (0, 0), final value at 0: @\@\@\@code(pwl) @\@\@\@code(pwl-list) @\@\Explicit initial value: @\@\@\@code(pwlv) @\@\@\@code(pwlv-list) @\Relative Time: @\@\Default initial point at (0, 0), final value at 0: @\@\@\@code(pwlr) @\@\@\@code(pwlr-list) @\@\Explicit initial value: @\@\@\@code(pwlvr) @\@\@\@code(pwlvr-list) Piece-wise Exponential Functions: @\Cummulative Time: @\@\Default initial point at (0, 1), final value at 1: @\@\@\@code(pwe) @\@\@\@code(pwe-list) @\@\Explicit initial value: @\@\@\@code(pwev) @\@\@\@code(pwev-list) @\Relative Time: @\@\Default initial point at (0, 1), final value at 1: @\@\@\@code(pwer) @\@\@\@code(pwer-list) @\@\Explicit initial value: @\@\@\@code(pwevr) @\@\@\@code(pwevr-list) @end(display) @pragma(endscribe) @html[
    Piece-wise Linear Functions:
    	Cummulative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwl
    			pwl-list
    		Explicit initial value:
    			pwlv
    			pwlv-list
    	Relative Time:
    		Default initial point at (0, 0), final value at 0:
    			pwlr
    			pwlr-list
    		Explicit initial value:
    			pwlvr
    			pwlvr-list
    
    Piece-wise Exponential Functions:
    	Cummulative Time:
    		Default initial point at (0, 1), final value at 1:
    			pwe
    			pwe-list
    		Explicit initial value:
    			pwev
    			pwev-list
    	Relative Time:
    		Default initial point at (0, 1), final value at 1:
    			pwer
    			pwer-list
    		Explicit initial value:
    			pwevr
    			pwevr-list
    
    ] All of these functions are implemented in terms of @code(pwl) (see @code(nyquist.lsp) for the implementations. There are infinite opportunities for errors in these functions: if you leave off a data point, try to specify points in reverse order, try to create an exponential that goes to zero or negative values, or many other bad things, the behavior is not well-defined. Nyquist should not crash, but Nyquist does not necessarily attempt to report errors at this time. @begin(fndefs) @label(pwl-sec) @codef{pwl(@pragma(defn)@index(pwl)@i(t@-[1]), @i(l@-[1]), @i(t@-[2]), @i(l@-[2]), @r(...) @i(t@-[n]))} @c{[sal]}@* @altdef{@code[(pwl @i(t@-[1]) @i(l@-[1]) @i(t@-[2]) @i(l@-[2]) @r(...) @i(t@-[n]))] @c{[lisp]}}@\Creates a piece-wise linear envelope with breakpoints at (0, 0), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 0). The breakpoint times are scaled linearly by the value of @code(*sustain*) (if @code(*sustain*) is a @code(SOUND), it is evaluated once at the starting time of the envelope). Each breakpoint time is then mapped according to @code(*warp*). The result is a linear interpolation (unwarped) between the breakpoints. The sample rate is @code(*control-srate*). Breakpoint times are quantized to the nearest sample time. If you specify one or more breakpoints withing one sample period, @code(pwl) attempts to give a good approximation to the specified function. In particular, if two breakpoints are simultaneous, @code(pwl) will move one of them to an adjacent sample, producing a steepest possible step in the signal. The exact details of this ``breakpoint munging'' is subject to change in future versions. Please report any cases where breakpoint lists give unexpected behaviors. The author will try to apply the ``principle of least surprise'' to the design. Note that the times are relative to 0; they are not durations of each envelope segment. @codef{pwl-list(@pragma(defn)@index(pwl-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwl-list @i(breakpoints))] @c{[lisp]}}@\If you have a list of breakpoints, you can use @code(apply) to apply the @code(pwl) function to the breakpoints, but if the list is very long (hundreds or thousands of points), you might get a stack overflow because XLISP has a fixed-size argument stack. Instead, call @code(pwl-list), passing one argument, the list of breakpoints. @codef{pwlv(@pragma(defn)@index(pwlv)@i(l@-[1]), @i(t@-[2]), @i(l@-[2]), @i(t@-[3]), @i(t@-[3]), ... @i(t@-[n]), @i(l@-[n]))} @c{[sal]}@* @altdef{@code[(pwlv @i(l@-[1]) @i(t@-[2]) @i(l@-[2]) @i(t@-[3]) @i(t@-[3]) @r(...) @i(t@-[n]) @i(l@-[n]))] @c{[lisp]}}@\Creates a piece-wise linear envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])). Otherwise, the behavior is like that of @code(pwl). @codef{pwlv-list(@pragma(defn)@index(pwlv-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwlv-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwlv) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwlr(@pragma(defn)@index(pwlr)@i(i@-[1]), @i(l@-[1]), @i(i@-[2]), @i(l@-[2]), ... @i(i@-[n]))} @c{[sal]}@* @altdef{@code[(pwlr @i(i@-[1]) @i(l@-[1]) @i(i@-[2]) @i(l@-[2]) @r(...) @i(i@-[n]))] @c{[lisp]}}@\Creates a piece-wise linear envelope with breakpoints at (0, 0), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 0), where @i(t@-[j]) is the sum of @i(i@-[1]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwl). @codef{pwlr-list(@pragma(defn)@index(pwlr-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwlr-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwlr) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwlvr(@pragma(defn)@index(pwlvr)@i(l@-[1]), @i(i@-[2]), @i(l@-[2]), @i(i@-[3]), @i(i@-[3]), ... @i(i@-[n]), @i(l@-[n]))} @c{[sal]}@* @altdef{@code[(pwlvr @i(l@-[1]) @i(i@-[2]) @i(l@-[2]) @i(i@-[3]) @i(i@-[3]) @r(...) @i(i@-[n]) @i(l@-[n]))] @c{[lisp]}}@\Creates a piece-wise linear envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])), where @i(t@-[j]) is the sum of @i(i@-[2]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwlv). @codef{pwlvr-list(@pragma(defn)@index(pwlvr-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwlvr-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwlvr) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwe(@pragma(defn)@index(pwe)@i(t@-[1]), @i(l@-[1]), @i(t@-[2]), @i(l@-[2]), @r(...) @i(t@-[n]))} @c{[sal]}@* @altdef{@code[(pwe @i(t@-[1]) @i(l@-[1]) @i(t@-[2]) @i(l@-[2]) @r(...) @i(t@-[n]))] @c{[lisp]}}@\Creates a piece-wise exponential envelope with breakpoints at (0, 1), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 1). Exponential segments means that the ratio of values from sample to sample is constant within the segment. (The current implementation actually takes the log of each value, computes a piece-wise exponential from the points using @code(pwl), then exponentiates each resulting sample. A faster implementation is certainly possible!) Breakpoint values (@i(l@-[j])) must be greater than zero. Otherwise, this function is similar to @code(pwl), including stretch by @code(*sustain*), mapping according to @code(*warp*), sample rate based on @code(*control-srate*), and "breakpoint munging" (see @code(pwl) described above). @i(Default initial and final values are of dubious value with exponentials. See @code(pwev) below for the function you are probably looking for.) @codef{pwe-list(@pragma(defn)@index(pwe-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwe-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwe) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @label(pwev-sec) @codef{pwev(@pragma(defn)@index(pwev)@i(l@-[1]), @i(t@-[2]), @i(l@-[2]), @i(t@-[3]), @i(t@-[3]), @r(...) @i(t@-[n]), @i(l@-[n]))} @c{[sal]}@* @altdef{@code[(pwev @i(l@-[1]) @i(t@-[2]) @i(l@-[2]) @i(t@-[3]) @i(t@-[3]) @r(...) @i(t@-[n]) @i(l@-[n]))] @c{[lisp]}}@\Creates a piece-wise exponential envelope with breakpoints at (0, @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n]), @i(l@-[n])). Otherwise, the behavior is like that of @code(pwe). @codef{pwev-list(@pragma(defn)@index(pwev-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwev-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwev) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwer(@pragma(defn)@index(pwer)@i(i@-[1]), @i(l@-[1]), @i(i@-[2]), @i(l@-[2]), @r(...) @i(i@-[n]))} @c{[sal]}@* @altdef{@code[(pwer @i(i@-[1]) @i(l@-[1]) @i(i@-[2]) @i(l@-[2]) @r(...) @i(i@-[n]))] @c{[lisp]}}@\Creates a piece-wise exponential envelope with breakpoints at (0, 1), (@i(t@-[1]), @i(l@-[1])), (@i(t@-[2]), @i(l@-[2])), ... (@i(t@-[n]), 1), where @i(t@-[j]) is the sum of @i(i@-[1]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwe). Consider using @code(pwerv) instead of this one. @codef{pwer-list(@pragma(defn)@index(pwer-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwer-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwer) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @codef{pwevr(@index(GEN05)@pragma(defn)@index(pwevr)@i(l@-[1]), @i(i@-[2]), @i(l@-[2]), @i(i@-[3]), @i(i@-[3]), @r(...) @i(i@-[n]), @i(l@-[n]))} @c{[sal]}@* @altdef{@code[(pwevr @i(l@-[1]) @i(i@-[2]) @i(l@-[2]) @i(i@-[3]) @i(i@-[3]) @r(...) @i(i@-[n]) @i(l@-[n]))] @c{[lisp]}}@\Creates a piece-wise exponential envelope with breakpoints at (0, l@-[1]), (@i(t@-[2]), @i(l@-[2])), etc., ending with (@i(t@-[n], @i(l@-[n])), where @i(t@-[j]) is the sum of @i(i@-[2]) through @i(i@-[j]). In other words, the breakpoint times are specified in terms of intervals rather than cummulative time. Otherwise, the behavior is like that of @code(pwev). Note that this is similar to the csound GEN05 generator. Which is uglier, @i(GEN05) or @i(pwevr)? @codef{pwevr-list(@pragma(defn)@index(pwevr-list)@i(breakpoints))} @c{[sal]}@* @altdef{@code[(pwevr-list @i(breakpoints))] @c{[lisp]}}@\A version of @code(pwevr) that takes a single list of breakpoints as its argument. See @code(pwl-list) above for the rationale. @end(fndefs) @paragraph(Filter Behaviors) @begin(fndefs) @label(alpass-sec) @codef{alpass(@index(all pass filter)@index(alpass filter)@pragma(defn)@index(alpass)@i(sound), @i(decay), @i(hz) [, @i(minhz)])} @c{[sal]}@* @altdef{@code{(alpass @i(sound) @i(decay) @i(hz) [@i(minhz)])} @c{[lisp]}}@\Applies an all-pass filter to @i(sound). This all-pass filter creates a delay effect without the resonances of a comb filter. The decay time of the filter is given by @i(decay). The @i(hz) parameter must be a number or sound greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The @i(decay) may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert @i(decay) into the @i(feedback) parameter, and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide @i(decay) at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of @i(sound). If @i(hz) is of type @code(SOUND), the delay may be time-varying. Linear interpolation is then used for fractional sample delay, but it should be noted that linear interpolation implies a low-pass transfer function. Thus, this filter may behave differently with a constant @code(SOUND) than it does with a @code(FLONUM) value for @i(hz). In addition, if @i(hz) is of type @code(SOUND), then @i(minhz) is required. The @i(hz) parameter will be clipped to be greater than @i(minhz), placing an upper bound on the delay buffer length. @label(comb-sec) @codef{comb(@pragma(defn)@index(comb)@index(comb filter)@i(sound), @i(decay), @i(hz))} @c{[sal]}@* @altdef{@code[(comb @i(sound) @i(decay) @i(hz))] @c{[lisp]}}@\Applies a comb filter to @i(sound). A comb filter emphasizes (resonates at) frequencies that are multiples of a @i(hz). The decay time of the resonance is given by @i(decay). This is a variation on @code(feedback-delay) (see below). The @i(hz) parameter must be a number greater than zero. It is used to compute delay, which is then rounded to the nearest integer number of samples (so the frequency is not always exact. Higher sampling rates yield better delay resolution.) The @i(decay) may be a sound or a number. In either case, it must also be positive. (Implementation note: an exponentiation is needed to convert @i(decay) into the @i(feedback) parameter for @code(feedback-delay), and exponentiation is typically more time-consuming than the filter operation itself. To get high performance, provide @i(decay) at a low sample rate.) The resulting sound will have the start time, sample rate, etc. of @i(sound). @label(congen-sec) @codef{congen(@pragma(defn)@index(congen)@index(contour generator)@index(envelope generator)@i(gate), @i(risetime), @i(falltime))} @c{[sal]}@* @altdef{@code[(congen @i(gate) @i(risetime) @i(falltime))] @c{[lisp]}}@\Implements an analog synthesizer-style contour generator. The input @i(gate) normally goes from 0.0 to 1.0 to create an attack and from 1.0 to 0.0 to start a release. During the attack (output is increasing), the output converges half-way to @i(gate) in @i(risetime) (a @code(FLONUM)) seconds. During the decay, the half-time is @i(falltime) seconds. The sample rate, start time, logical stop, and terminate time all come from @i(gate). If you want a nice decay, be sure that the @i(gate) goes to zero and stays there for awhile before @i(gate) terminates, because @code(congen) (and all Nyquist sounds) go immediately to zero at termination time. For example, you can use @code(pwl) to build a pulse followed by some zero time: @begin(example) (pwl 0 1 duty 1 duty 0 1) @end(example) Assuming @i(duty) is less than 1.0, this will be a pulse of duration @i(duty) followed by zero for a total duration of 1.0. @begin(example) (congen (pwl 0 1 duty 1 duty 0 1) 0.01 0.05) @end(example) will have a duration of 1.0 because that is the termination time of the @code(pwl) input. The decaying release of the resulting envelope will be truncated to zero at time 1.0. (Since the decay is theoretically infinite, there is no way to avoid truncation, although you could multiply by another envelope that smoothly truncates to zero in the last millisecond or two to get both an exponential decay and a smooth final transition to zero.) @label(convolve-sec) @codef{convolve(@pragma(defn)@index(convolve)@index(convolution)@index(FIR filter)@i(sound), @i(response))} @c{[sal]}@* @altdef{@code[(convolve @i(sound) @i(response))] @c{[lisp]}}@\Convolves two signals. The first can be any length, but the computation time per sample and the total space required are proportional to the length of @i(response). @label(feedback-delay-sec) @codef{feedback-delay(@pragma(defn)@index(feedback-delay)@index(delay)@index(echo)@i(sound), @i(delay), @i(feedback))} @c{[sal]}@* @altdef{@code[(feedback-delay @i(sound) @i(delay) @i(feedback))] @c{[lisp]}}@\Applies feedback delay to @i(sound). The @i(delay) must be a number (in seconds). It is rounded to the nearest sample to determine the length of the delay. The sample rate is the maximum from @i(sound) and @i(feedback) (if feedback is also a sound). The amound of @i(feedback) should be less than one to avoid an exponential increase in amplitude. The start time and stop time, and logical stop time are taken from @i(sound). Since output is truncated at the stop time of @i(sound), you may want to append some silence to @i(sound) to give the filter time to decay. @label(lp-sec) @codef{lp(@pragma(defn)@index(lp)@index(low-pass filter)@i(sound), @i(cutoff))} @c{[sal]}@* @altdef{@code[(lp @i(sound) @i(cutoff))] @c{[lisp]}}@\Filters @i(sound) using a first-order Butterworth low-pass filter. @i(Cutoff) may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of @i(cutoff). The resulting sample rate, start time, etc. are taken from @i(sound). @codef{tone(@pragma(defn)@index(tone)@i(sound), @i(cutoff))} @c{[sal]}@* @altdef{@code[(tone @i(sound) @i(cutoff))] @c{[lisp]}}@\No longer defined; use @code(lp) instead, or define it by adding @code[(setfn tone lp)] to your program. @label(hp-sec) @codef{hp(@pragma(defn)@index(hp)@index(high-pass filter)@i(sound), @i(cutoff))} @c{[sal]}@* @altdef{@code[(hp @i(sound) @i(cutoff))] @c{[lisp]}}@\Filters @i(sound) using a first-order Butterworth high-pass filter. @i(Cutoff) may be a float or a signal (for time-varying filtering) and expresses hertz. Filter coefficients (requiring trig functions) are recomputed at the sample rate of @i(cutoff). This filter is an exact complement of @code(lp). @codef{atone(@pragma(defn)@index(atone)@i(sound), @i(cutoff))} @c{[sal]}@* @altdef{@code[(atone @i(sound) @i(cutoff))] @c{[lisp]}}@\No longer defined; use @code(hp) instead, or define it by adding @code[(setfn atone hp)] to your program. @label(reson-sec) @codef{reson(@pragma(defn)@index(reson)@index(bandpass filter)@i(sound), @i(center), @i(bandwidth), @i(n))} @c{[sal]}@* @altdef{@code[(reson @i(sound) @i(center) @i(bandwidth) @i(n))] @c{[lisp]}}@\Apply a resonating filter to @i(sound) with center frequency @i(center) (in hertz), which may be a float or a signal. @i(Bandwidth) is the filter bandwidth (in hertz), which may also be a signal. Filter coefficients (requiring trig functions) are recomputed at each new sample of either @i(center) or @i(bandwidth), and coefficients are @i(not) interpolated. The last parameter @i(n) specifies the type of normalization as in Csound: A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than @i(hz) are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The resulting sample rate, start time, etc. are taken from @i(sound). One application of @code(reson) is to simulate resonances in the human vocal tract. See @code(demos/voice_synthesis.htm)@index(voice synthesis)@index(demos, voice synthesis) for sample code and documentation. @label(areson-sec) @codef{areson(@pragma(defn)@index(areson)@index(notch filter)@i(sound), @i(center), @i(bandwidth), @i(n))} @c{[sal]}@* @altdef{@code[(areson @i(sound) @i(center) @i(bandwidth) @i(n))] @c{[lisp]}}@\The @code(areson) filter is an exact complement of @code(reson) such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. @label(shape-sec) @codef{shape(@pragma(defn)@index(shape)@index(waveshaping)@index(table)@i(signal), @i(table), @i(origin))} @c{[sal]}@* @altdef{@code[(shape @i(signal) @i(table) @i(origin))] @c{[lisp]}}@\A waveshaping function. Use @i(table) as a function; apply the function to each sample of @i(signal) to yield a new sound. @i(Signal) should range from -1 to +1. Anything beyond these bounds is clipped. @i(Table) is also a sound, but it is converted into a lookup table (similar to table-lookup oscillators). The @i(origin) is a @code(FLONUM) and gives the time which should be considered the origin of @i(table). (This is important because @i(table) cannot have values at negative times, but @i(signal) will often have negative values. The @i(origin) gives an offset so that you can produce suitable tables.) The output at time @i(t) is: @begin(display) @i(table)(@i(origin) + clip(@i(signal)(@i(t))) @end(display) where clip(@i(x)) = @i(max)(1, @i(min)(-1, @i(x))). (E.g. if @i(table) is a signal defined over the interval [0, 2], then @i(origin) should be 1.0. The value of @i(table) at time 1.0 will be output when the input signal is zero.) The output has the same start time, sample rate, etc. as @i(signal). The @code(shape) function will also accept multichannel @i(signal)s and @i(table)s. Further discussion and examples can be found in @code(demos/distortion.htm)@index(distortion tutorial)@index(demos, distortion). The @code(shape) function is also used to map frequency to amplitude to achieve a spectral envelope for Shepard tones in @code(demos/shepard.lsp).@index(Shepard tones)@index(demos, Shepard tones) @label(biquad-sec) @codef{biquad(@pragma(defn)@index(biquad)@i(signal), @i(b0), @i(b1), @i(b2), @i(a0), @i(a1), @i(a2))} @c{[sal]}@* @altdef{@code[(biquad @i(signal) @i(b0) @i(b1) @i(b2) @i(a0) @i(a1) @i(a2))] @c{[lisp]}}@\A fixed-parameter biquad filter. All filter coefficients are @code(FLONUM)s. See also @code(lowpass2), @code(highpass2), @code(bandpass2), @code(notch2), @code(allpass2), @code(eq-lowshelf), @code(eq-highshelf), @code(eq-band), @code(lowpass4), @code(lowpass6), @code(highpass4), and @code(highpass8) in this section for convenient variations based on the same filter. The equations for the filter are: z@-[n] = s@-[n] + a1 * z@-[n-1] + a2 * z@-[n-2], and y@-[n] = z@-[n] * b0 + z@-[n-1] * b1 + z@-[n-2] * b2. @label(biquad-m-sec) @codef{biquad-m(@pragma(defn)@index(biquad-m)@i(signal), @i(b0), @i(b1), @i(b2), @i(a0), @i(a1), @i(a2))} @c{[sal]}@* @altdef{@code[(biquad-m @i(signal) @i(b0) @i(b1) @i(b2) @i(a0) @i(a1) @i(a2))] @c{[lisp]}}@\A fixed-parameter biquad filter with Matlab sign conventions for @i(a0), @i(a1), and @i(a2). All filter coefficients are @code(FLONUM)s. @label(lowpass2-sec) @codef{lowpass2(@pragma(defn)@index(lowpass2)@i(signal), @i(hz) [, @i(q)])} @c{[sal]}@* @altdef{@code{(lowpass2 @i(signal) @i(hz) [@i(q)])} @c{[lisp]}}@\A fixed-parameter, second-order lowpass filter based on @code(snd-biquad). The cutoff frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(highpass2-sec) @codef{highpass2(@pragma(defn)@index(highpass2)@i(signal), @i(hz) [, @i(q)])} @c{[sal]}@* @altdef{@code{(highpass2 @i(signal) @i(hz) [@i(q)])} @c{[lisp]}}@\A fixed-parameter, second-order highpass filter based on @code(snd-biquad). The cutoff frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(bandpass2-sec) @codef{bandpass2(@pragma(defn)@index(bandpass2)@i(signal), @i(hz) [, @i(q)])} @c{[sal]}@* @altdef{@code{(bandpass2 @i(signal) @i(hz) [@i(q)])} @c{[lisp]}}@\A fixed-parameter, second-order bandpass filter based on @code(snd-biquad). The center frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(notch2-sec) @codef{notch2(@pragma(defn)@index(notch2)@i(signal), @i(hz) [, @i(q)])} @c{[sal]}@* @altdef{@code{(notch2 @i(signal) @i(hz) [@i(q)])} @c{[lisp]}}@\A fixed-parameter, second-order notch filter based on @code(snd-biquad). The center frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(allpass2-sec) @codef{allpass2(@pragma(defn)@index(allpass2)@i(signal), @i(hz) [, @i(q)])} @c{[sal]}@* @altdef{@code{(allpass2 @i(signal) @i(hz) [@i(q)])} @c{[lisp]}}@\A fixed-parameter, second-order allpass filter based on @code(snd-biquad). The frequency is given by @i(hz) (a @code(FLONUM)) and an optional Q factor is given by @i(q) (a @code(FLONUM)). @label(eq-lowshelf-sec) @codef{eq-lowshelf(@pragma(defn)@index(eq-lowshelf)@index(equalization)@i(signal), @i(hz), @i(gain) [, @i(slope)])} @c{[sal]}@* @altdef{@code{(eq-lowshelf @i(signal) @i(hz) @i(gain) [@i(slope)])} @c{[lisp]}}@\A fixed-parameter, second-order bass shelving equalization (EQ) filter based on @code(snd-biquad). The @i(hz) parameter (a @code(FLONUM))is the halfway point in the transition, and @i(gain) (a @code(FLONUM)) is the bass boost (or cut) in dB. The optional @i(slope) (a @code(FLONUM)) is 1.0 by default, and response becomes peaky at values greater than 1.0. @label(eq-highshelf-sec) @codef{eq-highshelf(@pragma(defn)@index(eq-highshelf)@index(equalization)@i(signal), @i(hz), @i(gain) [, @i(slope)])} @c{[sal]}@* @altdef{@code{(eq-highshelf @i(signal) @i(hz) @i(gain) [@i(slope)])} @c{[lisp]}}@\A fixed-parameter, second-order treble shelving equalization (EQ) filter based on @code(snd-biquad). The @i(hz) parameter (a @code(FLONUM))is the halfway point in the transition, and @i(gain) (a @code(FLONUM)) is the treble boost (or cut) in dB. The optional @i(slope) (a @code(FLONUM)) is 1.0 by default, and response becomes peaky at values greater than 1.0. @label(eq-band-sec) @codef{eq-band(@pragma(defn)@index(eq-band)@index(equalization)@i(signal), @i(hz), @i(gain), @i(width))} @c{[sal]}@* @altdef{@code[(eq-band @i(signal) @i(hz) @i(gain) @i(width))] @c{[lisp]}}@\A fixed- or variable-parameter, second-order midrange equalization (EQ) filter based on @code(snd-biquad), @code(snd-eqbandcv) and @code(snd-eqbandvvv). The @i(hz) parameter (a @code(FLONUM)) is the center frequency, @i(gain) (a @code(FLONUM)) is the boost (or cut) in dB, and @i(width) (a @code(FLONUM)) is the half-gain width in octaves. Alternatively, @i(hz), @i(gain), and @i(width) may be @code(SOUND)s, but they must all have the same sample rate, e.g. they should all run at the control rate or at the sample rate. @label(lowpass4-sec) @codef{lowpass4(@pragma(defn)@index(lowpass4)@i(signal), @i(hz))} @c{[sal]}@* @altdef{@code[(lowpass4 @i(signal) @i(hz))] @c{[lisp]}}@\A four-pole Butterworth lowpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(lowpass6-sec) @codef{lowpass6(@pragma(defn)@index(lowpass6)@i(signal), @i(hz))} @c{[sal]}@* @altdef{@code[(lowpass6 @i(signal) @i(hz))] @c{[lisp]}}@\A six-pole Butterworth lowpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(lowpass8-sec) @codef{lowpass8(@pragma(defn)@index(lowpass8)@i(signal), @i(hz))} @c{[sal]}@* @altdef{@code[(lowpass8 @i(signal) @i(hz))] @c{[lisp]}}@\An eight-pole Butterworth lowpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(highpass4-sec) @codef{highpass4(@pragma(defn)@index(highpass4)@i(signal), @i(hz))} @c{[sal]}@* @altdef{@code[(highpass4 @i(signal) @i(hz))] @c{[lisp]}}@\A four-pole Butterworth highpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(highpass6-sec) @codef{highpass6(@pragma(defn)@index(highpass6)@i(signal), @i(hz))} @c{[sal]}@* @altdef{@code[(highpass6 @i(signal) @i(hz))] @c{[lisp]}}@\A six-pole Butterworth highpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(highpass8-sec) @codef{highpass8(@pragma(defn)@index(highpass8)@i(signal), @i(hz))} @c{[sal]}@* @altdef{@code[(highpass8 @i(signal) @i(hz))] @c{[lisp]}}@\An eight-pole Butterworth highpass filter. The cutoff frequency is @i(hz) (a @code(FLONUM)). @label(tapv-sec) @codef{tapv(@pragma(defn)@index(tapv)@index(variable delay)@index(tapped delay)@i(sound), @i(offset), @i(vardelay), @i(maxdelay))} @c{[sal]}@* @altdef{@code[(tapv @i(sound) @i(offset) @i(vardelay) @i(maxdelay))] @c{[lisp]}}@\A delay line with a variable position tap. Identical to @code(snd-tapv). See it for details (@ref(snd-tapv-sec)). @end(fndefs) @paragraph(Effects) @begin(fndefs) @label(stkrev-sec) @codef{nrev(@pragma(defn)@index(nrev)@index(reverb)@index(effect, reverberation)@index(STK nreverb)@i(sound), @i(decay), @i(mix))} @c{[sal]}@* @altdef{@code[(nrev @i(sound) @i(decay) @i(mix))] @c{[lisp]}} @codef{jcrev(@pragma(defn)@index(jcrev)@index(reverb)@index(effect, reverberation)@index(STK jcreverb)@i(sound), @i(decay), @i(mix))} @c{[sal]}@* @altdef{@code[(jcrev @i(sound) @i(decay) @i(mix))] @c{[lisp]}} @codef{prcrev(@pragma(defn)@index(prcrev)@index(reverb)@index(effect, reverberation)@index(STK prcreverb)@i(sound), @i(decay), @i(mix))} @c{[sal]}@* @altdef{@code[(prcrev @i(sound) @i(decay) @i(mix))] @c{[lisp]}} These reverbs (@code(nrev), @code(jcrev), and @code(prcrev)) are implemented in STK (running within Nyquist). @code(nrev) derives from Common Music's NRev, which consists of 6 comb filters followed by 3 allpass filters, a lowpass filter, and another allpass in series followed by two allpass filters in parallel. @code(jcrev) is the John Chowning reverberator which is based on the use of networks of simple allpass and comb delay filters. This reverb implements three series allpass units, followed by four parallel comb filters, and two decorrelation delay lines in parallel at the output. @code(prcrev) is a Perry Cook's reverberator which is based on the Chowning/Moorer/Schroeder reverberators using networks of simple allpass and comb delay filters. This one implements two series allpass units and two parallel comb filters. The @i(sound) input may be single or multi-channel. The @i(decay) time is in seconds, and @i(mix) sets the mixture of input sound reverb sound, where 0.0 means input only (dry) and 1.0 means reverb only (wet). @label(stkchorus-sec) @codef{stkchorus(@pragma(defn)@index(stkchorus)@index(chorus)@index(effect, chorus)@index(STK chorus)@i(sound), @i(depth), @i(freq), @i(mix) [, @i(delay)])} @c{[sal]}@* @altdef{@code{(stkchorus @i(sound) @i(depth) @i(freq) @i(mix) [@i(delay)])} @c{[lisp]}}@\Chorus implemented in STK. The input @i(sound) can be single or multi-channel. The @code(FLONUM) parameters @i(depth) and @i(freq) set the modulation depth from 0 to 1 and modulation frequency (in Hz), and @i(mix) sets the mixture of input sound and chorused sound, where 0.0 means input sound only (dry) and 1.0 means chorused sound only (wet). The parameter @i(delay) is a @code(FIXNUM) representing the median desired delay length in samples. @label(stkpitshift-sec) @codef{pitshift(@pragma(defn)@index(pitshift)@index(pitch shift)@index(effect, pitch shift)@index(STK pitch shift)@i(sound), @i(shift), @i(mix))} @c{[sal]}@* @altdef{@code[(pitshift @i(sound) @i(shift) @i(mix))] @c{[lisp]}}@\A pitch shifter implemented in STK. The input @i(sound), a single-channel or multi-channel @code(SOUND) is pitch-shifted by @i(shift), a @code(FLONUM) ratio. A value of 1.0 means no shift. The parameter @i(mix) sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). @end(fndefs) @paragraph(Physical Models) @begin(fndefs) @label(clarinet-sec) @codef{clarinet(@pragma(defn)@index(clarinet)@index(stk clarinet)@i(step), @i(breath-env))} @c{[sal]}@* @altdef{@code[(clarinet @i(step) @i(breath-env))] @c{[lisp]}}@\A physical model of a clarinet from STK. The @i(step) parameter is a @code(FLONUM) that controls the tube length, and the @i(breath-env) (a @code(SOUND)) controls the air pressure and also determines the length of the resulting sound. The @i(breath-env) signal should range from zero to one. @codef{clarinet-freq(@index(clarinet)@pragma(defn)@index(clarinet-freq)@index(stk clarinet)@i(step), @i(breath-env), @i(freq-env))} @c{[sal]}@* @altdef{@code[(clarinet-freq @i(step) @i(breath-env) @i(freq-env))] @c{[lisp]}}@\A variation of @code(clarinet) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(breath-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into @code(SOUND)s with a nominal duration arbitrarily set to 30. @codef{clarinet-all(@index(clarinet)@pragma(defn)@index(clarinet-all)@index(stk clarinet)@i(step), @i(breath-env), @i(freq-env), @i(vibrato-freq), @i(vibrato-gain), @i(reed-stiffness), @i(noise))} @c{[sal]}@* @altdef{@code[(clarinet-all @i(step) @i(breath-env) @i(freq-env) @i(vibrato-freq) @i(vibrato-gain) @i(reed-stiffness) @i(noise))] @c{[lisp]}}@\A variation of @code(clarinet-freq) that includes controls @i(vibrato-freq) (a @code(FLONUM) for vibrato frequency in Hertz), @i(vibrato-gain) (a @code(FLONUM) for the amount of amplitude vibrato), @i(reed-stiffness) (a @code(FLONUM) or @code(SOUND) controlling reed stiffness in the clarinet model), and @i(noise) (a @code(FLONUM) or @code(SOUND) controlling noise amplitude in the input air pressure). The @i(vibrato-gain) is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the @i(noise) parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the @i(breath-env). The @i(reed-stiffness) parameter varies from zero to one. The duration of the resulting sound is the minimum duration of @i(breath-env), @i(freq-env), @i(reed-stiffness), and @i(noise). As with @code(clarinet-freq), these parameters may be either @code(FLONUM)s or @code(SOUND)s, and @code(FLONUM)s are coerced to sounds with a nominal duration of 30. @label(sax-sec) @codef{sax(@pragma(defn)@index(sax)@index(stk sax)@i(step), @i(breath-env))} @c{[sal]}@* @altdef{@code[(sax @i(step) @i(breath-env))] @c{[lisp]}}@\A physical model of a sax from STK. The @i(step) parameter is a @code(FLONUM) that controls the tube length, and the @i(breath-env) controls the air pressure and also determines the length of the resulting sound. The @i(breath-env) signal should range from zero to one. @codef{sax-freq(@pragma(defn)@index(sax)@index(sax-freq)@index(stk sax)@i(step), @i(breath-env), @i(freq-env))} @c{[sal]}@* @altdef{@code[(sax-freq @i(step) @i(breath-env) @i(freq-env))] @c{[lisp]}}@\A variation of @code(sax) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(breath-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into @code(SOUND)s with a nominal duration arbitrarily set to 30. @codef{sax-all(@pragma(defn)@index(sax)@index(sax-all)@index(stk sax)@i(step), @i(breath-env), @i(freq-env), @i(vibrato-freq), @i(vibrato-gain), @i(reed-stiffness), @i(noise), @i(blow-pos), @i(reed-table-offset))} @c{[sal]}@* @altdef{@code[(sax-all @i(step) @i(breath-env) @i(freq-env) @i(vibrato-freq) @i(vibrato-gain) @i(reed-stiffness) @i(noise) @i(blow-pos) @i(reed-table-offset))] @c{[lisp]}}@\A variation of @code(sax-freq) that includes controls @i(vibrato-freq) (a @code(FLONUM) for vibrato frequency in Hertz), @i(vibrato-gain) (a @code(FLONUM) for the amount of amplitude vibrato), @i(reed-stiffness) (a @code(SOUND) controlling reed stiffness in the sax model), @i(noise) (a @code(SOUND) controlling noise amplitude in the input air pressure), @i(blow-pos) (a @code(SOUND) controlling the point of excitation of the air column), and @i(reed-table-offset) (a @code(SOUND) controlling a parameter of the reed model). The @i(vibrato-gain) is a number from zero to one, where zero indicates no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the @i(noise) parameter ranges from zero to one where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the @i(breath-env). The @i(reed-stiffness), @i(blow-pos), and @i(reed-table-offset) parameters all vary from zero to one. The duration of the resulting sound is the minimum duration of @i(breath-env), @i(freq-env), @i(reed-stiffness), @i(noise), @i(breath-env), @i(blow-pos), and @i(reed-table-offset). As with @code(sax-freq), these parameters may be either @code(FLONUM)s or @code(SOUND)s, and @code(FLONUM)s are coerced to sounds with a nominal duration of 30. @label(flute-sec) @codef{flute(@pragma(defn)@index(flute)@index(STK flute)@i(step), @i(breath-env))} @c{[sal]}@* @altdef{@code[(flute @i(step) @i(breath-env))] @c{[lisp]}}@\A physical model of a flute from STK. The @i(step) parameter is a @code(FLONUM) that controls the tube length, and the @i(breath-env) controls the air pressure and also determines the starting time and length of the resulting sound. The @i(breath-env) signal should range from zero to one. @codef{flute-freq(@pragma(defn)@index(flute-freq)@index(STK flute)@i(step), @i(breath-env), @i(freq-env))} @c{[sal]}@* @altdef{@code[(flute-freq @i(step) @i(breath-env) @i(freq-env))] @c{[lisp]}}@\A variation of @code(flute) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(breath-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into SOUNDs with a nominal duration arbitrary set to 30. @codef{flute-all(@pragma(defn)@index(flute-all)@index(STK flute)@i(step), @i(breath-env), @i(freq-env), @i(vibrato-freq), @i(vibrato-gain), @i(jet-delay), @i(noise))} @c{[sal]}@* @altdef{@code[(flute-all @i(step) @i(breath-env) @i(freq-env) @i(vibrato-freq) @i(vibrato-gain) @i(jet-delay) @i(noise))] @c{[lisp]}}@\A variation of @code(clarinet-freq) that includes controls @i(vibrato-freq) (a @code(FLONUM) for vibrato frequency in Hz), @i(vibrato-gain) (a @code(FLONUM) for the amount of amplitude vibrato), @i(jet-delay) (a @code(FLONUM) or @code(SOUND) controlling jet delay in the flute model), and noise (a @code(FLONUM) or @code(SOUND) controlling noise amplitude in the input air pressure). The @i(vibrato-gain) is a number from zero to one where zero means no vibrato, and one indicates a plus/minus 50% change in breath envelope values. Similarly, the @i(noise) parameter ranges from zero to one, where zero means no noise and one means white noise with a peak amplitude of plus/minus 40% of the @i(breath-env). The @i(jet-delay) is a ratio that controls a delay length from the flute model, and therefore it changes the pitch of the resulting sound. A value of 0.5 will maintain the pitch indicated by the step parameter. The duration of the resulting sound is the minimum duration of @i(breath-env), @i(freq-env), @i(jet-delay), and @i(noise). These parameters may be either @code(FLONUM)s or @code(SOUND)s, and @code(FLONUM)s are coerced to sounds with a nominal duration of 30. @label(bowed-sec) @codef{bowed(@pragma(defn)@index(bowed)@index(STK bowed string)@i(step), @i(bowpress-env))} @c{[sal]}@* @altdef{@code[(bowed @i(step) @i(bowpress-env))] @c{[lisp]}}@\A physical model of a bowed string instrument from STK. The @i(step) parameter is a @code(FLONUM) that controls the string length, and the @i(bowpress-env) controls the bow pressure and also determines the duration of the resulting sound. The @i(bowpress-env) signal should range from zero to one. @codef{bowed-freq(@pragma(defn)@index(bowed-freq)@index(STK bowed-freq)@i(step), @i(bowpress-env), @i(freq-env))} @c{[sal]}@* @altdef{@code[(bowed-freq @i(step) @i(bowpress-env) @i(freq-env))] @c{[lisp]}}@\A variation of @code(bowed) that includes a variable frequency control, @i(freq-env), which specifies frequency deviation in Hz. The duration of the resulting sound is the minimum duration of @i(bowpress-env) and @i(freq-env). These parameters may be of type @code(FLONUM) or @code(SOUND). @code(FLONUM)s are coerced into @code(SOUND)s with a nominal duration arbitrarily set to 30s. @label(mandolin-sec) @codef{mandolin(@pragma(defn)@index(mandolin)@index(STK mandolon)@i(step), @i(dur), &optional @i(detune))} @c{[sal]}@* @altdef{@code[(mandolin @i(step) @i(dur) @i(detune))] @c{[lisp]}}@\A physical model of a plucked double-string instrument from STK. The @i(step) parameter is a @code(FLONUM) wich specifies the desired pitch, @i(dur) means the duration of the resulting sound and detune is a @code(FLONUM) that controls the relative detune of the two strings. A value of 1.0 means unison. The default value is 4.0. Note: @i(body-size) (see @code(snd-mandolin) does not seem to work correctly, so a default value is always used by @code(mandolin). @label(bandedwg-sec) @codef{wg-uniform-bar(@pragma(defn)@index(wg-uniform-bar)@index(STK uniform bar)@i(step), @i(bowpress-env))} @c{[sal]}@* @altdef{@code[(wg-uniform-bar @i(step) @i(bowpress-env))] @c{[lisp]}} @codef{wg-tuned-bar(@pragma(defn)@index(wg-tuned-bar)@index(STK tuned bar)@i(step), @i(bowpress-env))} @c{[sal]}@* @altdef{@code[(wg-tuned-bar @i(step) @i(bowpress-env))] @c{[lisp]}} @codef{wg-glass-harm(@pragma(defn)@index(wg-glass-harm)@index(STK glass harmonica)@i(step), @i(bowpress-env))} @c{[sal]}@* @altdef{@code[(wg-glass-harm @i(step) @i(bowpress-env))] @c{[lisp]}} @codef{wg-tibetan-bowl(@pragma(defn)@index(wg-tibetan-bowl)@index(STK tibetan bowl)@i(step), @i(bowpress-env))} @c{[sal]}@* @altdef{@code[(wg-tibetan-bowl @i(step) @i(bowpress-env))] @c{[lisp]}}@\These sounds are presets for a Banded Wave Guide Percussion instrument implemented in STK. The parameter @i(step) is a @code(FLONUM) that controls the resultant pitch, and @i(bowpress-env) is a @code(SOUND) ranging from zero to one that controls a parameter of the model. In addition, @i(bowpress-env) determines the duration of the resulting sound. (Note: The @i(bowpress-env) does not seems influence the timbral quality of the resulting sound). @label(modalbar-sec) @codef{modalbar(@pragma(defn)@index(modalbar)@index(STK modal bar)@i(preset), @i(step), @i(dur))} @c{[sal]}@* @altdef{@code[(modalbar @i(preset) @i(step) @i(dur))] @c{[lisp]}}@\A physical model of a struck bar instrument implemented in STK. The parameter @i(preset) is one of the symbols @code(MARIMBA), @code(VIBRAPHONE), @code(AGOGO), @code(WOOD1), @code(RESO), @code(WOOD2), @code(BEATS), @code(TWO-FIXED), or @code(CLUMP). The symbol must be quoted, e.g. for SAL syntax use @code[quote(marimba)], and for Lisp syntax use @code('marimba). The parameter @i(step) is a @code(FLONUM) that sets the pitch (in steps), and @i(dur) is the duration in seconds. @label(sitar-sec) @codef{sitar(@pragma(defn)@index(sitar)@index(STK sitar)@i(step), @i(dur))} @c{[sal]}@* @altdef{@code[(sitar @i(step) @i(dur))] @c{[lisp]}}@\A sitar physical model implemented in STK. The parameter @i(step) is a @code(FLONUM) that sets the pitch, and @i(dur) is the duration. @end(fndefs) @paragraph(More Behaviors) @begin(fndefs) @label(clip-sec) @codef{clip(@pragma(defn)@index(clip)@index(limit)@i(sound), @i(peak))} @c{[sal]}@* @altdef{@code[(clip @i(sound) @i(peak))] @c{[lisp]}}@\Hard limit @i(sound) to the given @i(peak), a positive number. The samples of @i(sound) are constrained between an upper value of @i(peak) and a lower value of @subtract()@i(peak). If @i(sound) is a number, @code(clip) will return @i(sound) limited by @i(peak). If @i(sound) is a multichannel sound, @code(clip) returns a multichannel sound where each channel is clipped. The result has the type, sample rate, starting time, etc. of @i(sound). @label(s-abs-sec) @codef{s-abs(@pragma(defn)@index(s-abs)@index(absolute value)@i(sound))} @c{[sal]}@* @altdef{@code[(s-abs @i(sound))] @c{[lisp]}}@\A generalized absolute value function. If @i(sound) is a @code(SOUND), compute the absolute value of each sample. If @i(sound) is a number, just compute the absolute value. If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-abs) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). @label(s-sqrt-sec) @codef{s-sqrt(@pragma(defn)@index(s-sqrt)@index(square root)@i(sound))} @c{[sal]}@* @altdef{@code[(s-sqrt @i(sound))] @c{[lisp]}}@\A generalized square root function. If @i(sound) is a @code(SOUND), compute the square root of each sample. If @i(sound) is a number, just compute the square root. If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-sqrt) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). In taking square roots, if an input sample is less than zero, the corresponding output sample is zero. This is done because the square root of a negative number is undefined. @label(s-exp-sec) @codef{s-exp(@pragma(defn)@index(s-exp)@index(exponential)@i(sound))} @c{[sal]}@* @altdef{@code[(s-exp @i(sound))] @c{[lisp]}}@\A generalized exponential function. If @i(sound) is a @code(SOUND), compute @i(e)@+(@i(x)) for each sample @i(x). If @i(sound) is a number @i(x), just compute @i(e)@+(@i(x)). If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-exp) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). @label(s-log-sec) @codef{s-log(@pragma(defn)@index(s-log)@index(logorithm)@index(natural log)@i(sound))} @c{[sal]}@* @altdef{@code[(s-log @i(sound))] @c{[lisp]}}@\A generalized natural log function. If @i(sound) is a @code(SOUND), compute @i(ln)(@i(x)) for each sample @i(x). If @i(sound) is a number @i(x), just compute @i(ln)(@i(x)). If @i(sound) is a multichannel sound, return a multichannel sound with @code(s-log) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). Note that the @i(ln) of 0 is undefined (some implementations return negative infinity), so use this function with care. @label(s-max-sec) @codef{s-max(@pragma(defn)@index(s-max)@index(maximum)@i(sound1), @i(sound2))} @c{[sal]}@* @altdef{@code[(s-max @i(sound1) @i(sound2))] @c{[lisp]}}@\Compute the maximum of two functions, @i(sound1) and @i(sound2). This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of @i(sound1) and @i(sound2). The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of @i(sound1) and @i(sound2). Note, therefore, that the result value is zero except within the bounds of @i(both) input sounds. @codef{s-min(@pragma(defn)@index(s-min)@index(minimum)@i(sound1), @i(sound2))} @c{[sal]}@* @altdef{@code[(s-min @i(sound1) @i(sound2))] @c{[lisp]}}@\Compute the minimum of two functions, @i(sound1) and @i(sound2). This function also accepts numbers and multichannel sounds and returns the corresponding data type. The start time of the result is the maximum of the start times of @i(sound1) and @i(sound2). The logical stop time and physical stop time of the result is the minimum of the logical stop and physical stop times respectively of @i(sound1) and @i(sound2). Note, therefore, that the result value is zero except within the bounds of @i(both) input sounds. @codef{osc-note(@pragma(defn)@index(osc-note)@i(pitch) [, @i(duration), @i(env), @i(loud), @i(table)])} @c{[sal]}@* @altdef{@code{(osc-note @i(pitch) [@i(duration) @i(env) @i(loud) @i(table)])} @c{[lisp]}}@\Same as @code(osc), but @code(osc-note) multiplies the result by @i(env). The @i(env) may be a sound, or a list supplying (@i(t@-[1]) @i(t@-[2]) @i(t@-[4]) @i(l@-[1]) @i(l@-[2]) @i(l@-[3])). The result has a sample rate of @code(*sound-srate*). @label(quantize-sec) @codef{quantize(@pragma(defn)@index(quantize)@i(sound), @i(steps))} @c{[sal]}@* @altdef{@code[(quantize @i(sound) @i(steps))] @c{[lisp]}}@\Quantizes @i(sound) as follows: @i(sound) is multiplied by @i(steps) and rounded to the nearest integer. The result is then divided by @i(steps). For example, if @i(steps) is 127, then a signal that ranges from -1 to +1 will be quantized to 255 levels (127 less than zero, 127 greater than zero, and zero itself). This would match the quantization Nyquist performs when writing a signal to an 8-bit audio file. The @i(sound) may be multi-channel. @codef{ramp(@pragma(defn)@index(ramp)[@i(duration)])} @c{[sal]}@* @altdef{@code{(ramp [@i(duration)])} @c{[lisp]}}@\Returns a linear ramp from 0 to 1 over @i(duration) (default is 1). The function actually reaches 1 at @i(duration), and therefore has one extra sample, making the total duration be @i(duration) + 1/@code(*Control-srate*). See Figure @ref(ramp-fig) for more detail. Ramp is unaffected by the @code(sustain) transformation. The effect of time warping is to warp the starting and ending times only. The ramp itself is unwarped (linear). The sample rate is @code(*control-srate*). @label(rms-sec) @codef{rms(@pragma(defn)@index(rms)@i(sound) [, @i(rate), @i(window-size)])} @c{[sal]}@* @altdef{@code{(rms @i(sound) [@i(rate) @i(window-size)])} @c{[lisp]}}@\Computes the RMS of @i(sound) using a square window of size @i(window-size). The result has a sample rate of @i(rate). The default value of @i(rate) is 100 Hz, and the default window size is 1/rate seconds (converted to samples). The @i(rate) is a @code(FLONUM) and @i(window-size) is a @code(FIXNUM). @end(fndefs) @begin(figure) @center(@graphic((height = 2.37 in, width = 4.5 in, magnify = 0.75, postscript = "rampfig.ps")) @html(

    ) @fillcaption[Ramps generated by @code(pwl) and @code(ramp) functions. The @code(pwl) version ramps toward the breakpoint (1, 1), but in order to ramp back to zero at breakpoint (1, 0), the function never reaches an amplitude of 1. If used at the beginning of a @code(seq) construct, the next sound will begin at time 1. The @code(ramp) version actually reaches breakpoint (1, 1); notice that it is one sample longer than the @code(pwl) version. If used in a sequence, the next sound after @code(ramp) would start at time 1 + @i(P), where @i(P) is the sample period.] @tag(ramp-fig) @end(figure) @begin(fndefs) @label(recip-sec) @codef{recip(@pragma(defn)@index(recip)@index(reciprocal)@index(division)@i(sound))} @c{[sal]}@* @altdef{@code[(recip @i(sound))] @c{[lisp]}}@\A generalized reciprocal function. If @i(sound) is a @code(SOUND), compute 1/@i(x) for each sample @i(x). If @i(sound) is a number @i(x), just compute 1/@i(x). If @i(sound) is a multichannel sound, return a multichannel sound with @code(recip) applied to each element. The result has the type, sample rate, starting time, etc. of @i(sound). Note that the reciprocal of 0 is undefined (some implementations return infinity), so use this function with care on sounds. Division of sounds is accomplished by multiplying by the reciprocal. Again, be careful not to divide by zero. @codef{s-rest(@index(rest)@pragma(defn)@index(s-rest)[@i(duration)])} @c{[sal]}@* @altdef{@code{(s-rest [@i(duration)])} @c{[lisp]}}@\Create silence (zero samples) for the given @i(duration) at the sample rate @code(*sound-srate*). Default duration is 1.0 sec, and the sound is transformed in time according to @code[*warp*]. @p(Note:) @code(rest) is a Lisp function that is equivalent to @code(cdr). Be careful to use @code(s-rest) when you need a sound! @label(noise-sec) @codef{noise(@pragma(defn)@index(noise)[@i(duration)])} @c{[sal]}@* @altdef{@code[(noise @i(duration))] @c{[lisp]}}@\Generate noise with the given @i(duration). Duration (default is 1.0) is transformed according to @code[*warp*]. The sample rate is @code(*sound-srate*) and the amplitude is +/- @code(*loud*). @label(yin-sec) @codef{yin(@pragma(defn)@index(yin)@index(pitch detection)@index(fundamenal frequency estimation)@index(estimate frequency)@index(frequency analysis)@index(period estimation)@i(sound), @i(minstep), @i(maxstep), @i(stepsize))} @c{[sal]}@* @altdef{@code[(yin @i(sound) @i(minstep) @i(maxstep) @i(stepsize))] @c{[lisp]}}@\Fundamental frequency estimation (pitch detection. Use the YIN algorithm to estimate the fundamental frequency of @i(sound), which must be a @code(SOUND). The @i(minstep), a @code(FLONUM), is the minimum frequency considered (in steps), @i(maxstep), a @code(FLONUM), is the maximum frequency considered (in steps), and @i(stepsize), a @code(FIXNUM), is the desired hop size. The result is a ``stereo'' signal, i.e. an array of two @code(SOUND)s, both at the same sample rate, which is approximately the sample rate of @i(sound) divided by @i(stepsize). The first @code(SOUND) consists of frequency estimates. The second sound consists of values that measure the confidence or reliability of the frequency estimate. A small value (less than 0.1) indicates fairly high confidence. A larger value indicates lower confidence. This number can also be thought of as a ratio of non-periodic power to periodic power. When the number is low, it means the signal is highly periodic at that point in time, so the period estimate will be reliable. Hint #1: See Alain de Cheveigne and Hideki Kawahara's article "YIN, a Fundamental Frequency Estimator for Speech and Music" in the Journal of the Acoustic Society of America, April 2002 for details on the yin algorithm. Hint #2: Typically, the @i(stepsize) should be at least the expected number of samples in one period so that the fundamental frequency estimates are calculated at a rate far below the sample rate of the signal. Frequency does not change rapidly and the yin algorithm is fairly slow. To optimize speed, you may want to use less than 44.1 kHz sample rates for input sounds. Yin uses interpolation to achieve potentially fractional-sample-accurate estimates, so higher sample rates do not necessarily help the algorithm and definitely slow it down. The computation time is O(@i(n)@+(2)) per estimate, where @i(n) is the number of samples in the longest period considered. Therefore, each increase of @i(minstep) by 12 (an octave) gives you a factor of 4 speedup, and each decrease of the sample rate of @i(sound) by a factor of two gives you another factor of 4 speedup. Finally, the number of estimates is inversely proportional to @i(stepsize). Hint #3: Use @code(snd-srate) (see Section @ref(snd-srate-sec)) to get the exact sample rate of the result, which will be the sample rate of @i(sound) divided by @i(stepsize). E.g. @code{(snd-srate (aref yin-output 0))}, where @code(yin-output) is a result returned by @code(yin), will be the sample rate of the estimates. @end(fndefs) @section(Transformations)@index(Transformations) @label(transformations-sec) These functions change the environment that is seen by other high-level functions. Note that these changes are usually relative to the current environment. There are also ``absolute'' versions of each transformation function, with the exception of @code(seq), @code(seqrep), @code(sim), and @code(simrep). The ``absolute'' versions (starting or ending with ``abs'') do not look at the current environment, but rather set an environment variable to a specific value. In this way, sections of code can be insulated from external transformations. @begin(fndefs) @codef{abs-env(@pragma(defn)@index(abs-env)@i(beh))} @c{[sal]}@* @altdef{@code[(abs-env @i(beh))] @c{[lisp]}}@\Compute @i(beh) in the default environment. This is useful for computing waveform tables and signals that are ``outside'' of time. For example, @code[(at 10.0 (abs-env (my-beh)))] is equivalent to @code[(abs-env (my-beh))] because @code(abs-env) forces the default environment. Or in SAL, we would say @code[abs-env(my-beh()) @@ 10] is equivalent to @code[abs-env(my-beh())]. @codef{at(@pragma(defn)@index(at)@i(time), @i(beh))} @c{[sal]}@* @altdef{@code[(at @i(time) @i(beh))] @c{[lisp]}}@\Evaluate @i(beh) with @code(*warp*@index(*warp*)) shifted by @i(time). In SAL, you can use the infix operator @code(@@) as in @code[@i(beh) @@ @i(time)]. To discover how the environment is shifting time, use @code[local-to-global(@i(time))]. Most commonly, you call @code[local-to-global(0)] to find when a sound created in the current environment will start, expressed in absolute (global) terms. This can be regarded as the ``current time.'' @codef{at-abs(@pragma(defn)@index(at-abs)@i(time), @i(beh))} @c{[sal]}@* @altdef{@code[(at-abs @i(time) @i(beh))] @c{[lisp]}}@\Evaluate @i(beh) with @code(*warp*@index(*warp*)) shifted so that local time 0 maps to @i(time). In SAL, you can use the infix operator @code[@@@@] as in @code[@i(beh) @@@@ @i(time)]. @label(continuous-control-warp) @codef{continuous-control-warp(@pragma(defn)@index(continuous-control-warp)@i(beh))} @c{[sal]}@* @altdef{@code[(continuous-control-warp @i(beh))] @c{[lisp]}}@\Applies the current warp environment to the signal returned by @i(beh). The result has the default control sample rate @code(*control-srate*). Linear interpolation is currently used. Implementation: @i(beh) is first evaluated without any shifting, stretching, or warping. The result is functionally composed with the inverse of the environment's warp function. @label(continuous-sound-warp) @codef{continuous-sound-warp(@pragma(defn)@index(continuous-sound-warp)@i(beh))} @c{[sal]}@* @altdef{@code[(continuous-sound-warp @i(beh))] @c{[lisp]}}@\Applies the current warp environment to the signal returned by @i(beh). The result has the default sound sample rate @code(*sound-srate*). Linear interpolation is currently used. See @code(continuous-control-warp) for implementation notes. @label(control-srate-abs-sec) @codef{control-srate-abs(@pragma(defn)@index(control-srate-abs)@i(srate), @i(beh))} @c{[sal]}@* @altdef{@code[(control-srate-abs @i(srate) @i(beh))] @c{[lisp]}}@\Evaluate @i(beh) with @code(*control-srate*@index(*control-srate*)) set to sample rate @i(srate). @p(Note:) there is no ``relative'' version of this function. @codef{extract(@pragma(defn)@index(extract)@i(start), @i(stop), @i(beh))} @c{[sal]}@* @altdef{@code[(extract @i(start) @i(stop) @i(beh))] @c{[lisp]}}@\Returns a sound which is the portion of @i(beh) between @i(start) and @i(stop). Note that this is done relative to the current @code(*warp*). The result is shifted to start according to @code(*warp*), so normally the result will start without a delay of @i(start). @codef{extract-abs(@pragma(defn)@index(extract-abs)@i(start), @i(stop), @i(beh))} @c{[sal]}@* @altdef{@code[(extract-abs @i(start) @i(stop) @i(beh))] @c{[lisp]}}@\Returns a sound which is the portion of @i(beh) between @i(start) and @i(stop), independent of the current @code(*warp*). The result is shifted to start according to @code(*warp*). @codef{loud(@pragma(defn)@index(loud)@i(volume), @i(beh))} @c{[sal]}@* @altdef{@code[(loud @i(volume) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*loud*) incremented by @i(volume). (Recall that @code(*loud*) is in decibels, so increment is the proper operation.) @codef{loud-abs(@pragma(defn)@index(loud-abs)@i(volume), @i(beh))} @c{[sal]}@* @altdef{@code[(loud-abs @i(volume) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*loud*) set to @i(volume). @label(sound-srate-abs-sec) @codef{sound-srate-abs(@pragma(defn)@index(sound-srate-abs)@i(srate), @i(beh))} @c{[sal]}@* @altdef{@code[(sound-srate-abs @i(srate) @i(beh))] @c{[lisp]}}@\Evaluate @i(beh) with @code(*sound-srate*@index(*sound-srate*)) set to sample rate @i(srate). @p(Note:) there is no ``relative'' version of this function. @codef{stretch(@pragma(defn)@index(stretch)@i(factor), @i(beh))} @c{[sal]}@* @altdef{@code[(stretch @i(factor) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*warp*) scaled by @i(factor). The effect is to ``stretch'' the result of @i(beh) (under the current environment) by @i(factor). See Chapter @ref(warp-chap) for more information. Use @code[get-duration(@i(dur))] to get the nominal actual duration of a behavior that locally has a duration of @i(dur). Here, ``nominal'' means what would be expected if the behavior obeys the shift, stretch, and warp components of the environment. (Any behavior is free to deviate from the nominal timing. For example, a percussion sound might have a fixed duration independent of the stretch factor.) Also, ``actual'' means global or absolute time, and ``locally'' means within the environment where @code[get-duration] is called. @code[get-duration] works by mapping the current time (local time 0) using @code[local-to-global] to obtain an actual start time, and mapping @i(dur) to obtain an actual end time. The difference is returned. @codef{stretch-abs(@pragma(defn)@index(stretch-abs)@i(factor), @i(beh))} @c{[sal]}@* @altdef{@code[(stretch-abs @i(factor) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*warp*) set to a linear time transformation where each unit of logical time maps to @i(factor) units of real time. The effect is to stretch the nominal behavior of @i(beh) (under the default global environment) by @i(factor). See Chapter @ref(warp-chap) for more information. @codef{sustain(@pragma(defn)@index(sustain)@index(legato)@index(overlap)@index(stacatto)@i(factor), @i(beh))} @c{[sal]}@* @altdef{@code[(sustain @i(factor) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*sustain*) scaled by @i(factor). The effect is to ``stretch'' the result of @i(beh) (under the current environment) by @i(factor); however, the logical stop times are not stretched. Therefore, the overall duration of a sequence is not changed, and sounds will tend to overlap if @code(*sustain*) is greater than one (legato) and be separated by silence if @code(*sustain*) is less than one. @codef{sustain-abs(@pragma(defn)@index(sustain-abs)@i(factor), @i(beh))} @c{[sal]}@* @altdef{@code[(sustain-abs @i(factor) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*sustain*) set to @i(factor). (See @code(sustain), above.) @codef{transpose(@pragma(defn)@index(transpose)@i(amount), @i(beh))} @c{[sal]}@* @altdef{@code[(transpose @i(amount) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*transpose*) shifted by @i(amount). The effect is relative transposition by @i(amount) semitones. @codef{transpose-abs(@pragma(defn)@index(transpose-abs)@i(amount), @i(beh))} @c{[sal]}@* @altdef{@code[(transpose-abs @i(amount) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*transpose*) set to @i(amount). The effect is the transposition of the nominal pitches in @i(beh) (under the default global environment) by @i(amount). @codef{warp(@pragma(defn)@index(warp)@i(fn), @i(beh))} @c{[sal]}@* @altdef{@code[(warp @i(fn) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*warp*) modified by @i(fn). The idea is that @i(beh) and @i(fn) are written in the same time system, and @i(fn) warps that time system to local time. The current environment already contains a mapping from local time to global (real) time. The value of @code(*warp*) in effect when @i(beh) is evaluated is the functional composition of the initial @code(*warp*) with @i(fn). @codef{warp-abs(@pragma(defn)@index(warp-abs)@i(fn), @i(beh))} @c{[sal]}@* @altdef{@code[(warp-abs @i(fn) @i(beh))] @c{[lisp]}}@\Evaluates @i(beh) with @code(*warp*) set to @i(fn). In other words, the current @code(*warp*) is ignored and not composed with @i(fn) to form the new @code(*warp*). @end(fndefs) @section(Combination and Time Structure)@index(Combination)@index(Time Structure) These behaviors combine component behaviors into structures, including sequences (melodies), simultaneous sounds (chords), and structures based on iteration. @begin(fndefs) @label(seq-sec) @codef{seq(@pragma(defn)@index(seq)@i(beh@-[1]) [, @i(beh@-[2]), @r(...)])} @c{[sal]}@* @altdef{@code{(seq @i(beh@-[1]) [@i(beh@-[2]) @r(...)])} @c{[lisp]}}@\Evaluates the first behavior @i(beh@-[1]) according to @code(*time*) and each successive behavior at the @code(logical-stop) time of the previous one. The results are summed to form a sound whose @code(logical-stop) is the @code(logical-stop) of the last behavior in the sequence. Each behavior can result in a multichannel sound, in which case, the logical stop time is considered to be the maximum logical stop time of any channel. The number of channels in the result is the number of channels of the first behavior. If other behaviors return fewer channels, new channels are created containing constant zero signals until the required number of channels is obtained. If other behaviors return a simple sound rather than multichannel sounds, the sound is automatically assigned to the first channel of a multichannel sound that is then filled out with zero signals. If another behavior returns more channels than the first behavior, the error is reported and the computation is stopped. Sample rates are converted up or down to match the sample rate of the first sound in a sequence. @codef{seqrep(@pragma(defn)@index(seqrep)@i(var), @i(limit), @i(beh))} @c{[sal]}@* @altdef{@code[(seqrep @i(var) @i(limit) @i(beh))] @c{[lisp]}}@\Iteratively evaluates @i(beh) with the atom @i(var) set with values from 0 to @i(limit)-1, inclusive. These sounds are placed sequentially in time as if by @code(seq). The symbol @i(var) is a @i(read-only) local variable to @i(beh). Assignments are not restricted or detected, but may cause a run-time error or crash. In LISP, the syntax is @code[(seqrep (@i(var) @i(limit)) @i(beh))]. @label(sim-sec) @codef{sim(@pragma(defn)@index(sim)[@i(beh@-[1]), @i(beh@-[2]), @r(...)])} @c{[sal]}@* @altdef{@code{(sim [@i(beh@-[1]) @i(beh@-[2]) @r(...)])} @c{[lisp]}}@\Returns a sound which is the sum of the given behaviors evaluated with current value of @code(*warp*). If behaviors return multiple channel sounds, the corresponding channels are added. If the number of channels does not match, the result has the maximum. For example, if a two-channel sound [L, R] is added to a four-channel sound [C1, C2, C3, C4], the result is [L + C1, R + C2, C3, C4]. Arguments to @code(sim) may also be numbers. If all arguments are numbers, @code(sim) is equivalent (although slower than) the @code(+) function. If a number is added to a sound, @code(snd-offset) is used to add the number to each sample of the sound. The result of adding a number to two or more sounds with different durations is not defined. Use @code(const) to coerce a number to a sound of a specified duration. An important limitation of @code(sim) is that it cannot handle hundreds of behaviors due to a stack size limitation in XLISP. To compute hundreds of sounds (e.g. notes) at specified times, see @code(timed-seq), below. See also @code(sum) below. @codef{simrep(@pragma(defn)@index(simrep)@i(var), @i(limit), @i(beh))} @c{[sal]}@* @altdef{@code[(simrep @i(var) @i(limit) @i(beh))] @c{[lisp]}}@\Iteratively evaluates @i(beh) with the atom @i(var) set with values from 0 to @i(limit)-1, inclusive. These sounds are then placed simultaneously in time as if by @code(sim). In LISP, the syntax is @code[(seqrep (@i(var) @i(limit)) @i(beh))]. @label(trigger-sec) @codef[trigger(@pragma(defn)@index(trigger)@i(s), @i(beh))] @c{[sal]}@* @altdef{@code[(trigger @i(s) @i(beh))] @c{[lisp]}}@\Returns a sound which is the sum of instances of the behavior @i(beh). One instance is created each time @code(SOUND) @i(s) makes a transition from less than or equal to zero to greater than zero. (If the first sample of @i(s) is greater than zero, an instance is created immediately.) The sample rate of @i(s) and all behaviors must be the same, and the behaviors must be (monophonic) @code(SOUND)s. This function is particularly designed to allow behaviors to be invoked in real time by making @i(s) a function of a Nyquist slider, which can be controlled by a graphical interface or by OSC messages. See @code(snd-slider) in Section @ref(snd-slider-sec). @codef[set-logical-stop(@pragma(defn)@index(set-logical-stop)@i(beh), @i(time))] @c{[sal]}@* @altdef{@code[(set-logical-stop @i(beh) @i(time))] @c{[lisp]}}@\Returns a sound with @i(time) as the logical stop time. @codef{sum(@pragma(defn)@index(sum)@index(mix)@i(a) [, @i(b), @r(...)])} @c{[sal]}@* @altdef{@code{(sum @i(a) [@i(b) @r(...)])} @c{[lisp]}}@\Returns the sum of @i(a), @i(b), ..., allowing mixed addition of sounds, multichannel sounds and numbers. Identical to @i(sim). In SAL, use the infix ``+'' operator. @codef{mult(@pragma(defn)@index(mult)@index(product)@index(multiply signals)@i(a) [, @i(b), @r(...)])} @c{[sal]}@* @altdef{@code{(mult @i(a) [@i(b) @r(...)])} @c{[lisp]}}@\Returns the product of @i(a), @i(b), ..., allowing mixed multiplication of sounds, multichannel sounds and numbers. @codef{diff(@pragma(defn)@index(diff)@index(difference of sounds)@i(a), @i(b))} @c{[sal]}@* @altdef{@code[(diff @i(a) @i(b))] @c{[lisp]}}@\Returns the difference between @i(a) and @i(b). This function is defined as @code[(sum a (prod -1 b))]. @label(timed-seq-sec) @codef{timed-seq(@pragma(defn)@index(timed-seq)@index(score)@index(note list)@i(score))} @c{[sal]}@* @altdef{@code[(timed-seq @i(score))] @c{[lisp]}}@\Computes sounds from a note list or ``score.'' The @i(score) is of the form: @code[`((@i(time1) @i(stretch1) @i(beh1)) (@i(time2) @i(stretch2) @i(beh2)) @r(...))], where @i(timeN) is the starting time, @i(stretchN) is the stretch factor, and @i(behN) is the behavior. Note that @i(score) is normally a @i(quoted list)! The times must be in increasing order, and each @i(behN) is evaluated using lisp's @code(eval), so the @i(behN) behaviors cannot refer to local parameters or local variables. The advantage of this form over @code(seq) is that the behaviors are evaluated one-at-a-time which can take much less stack space and overall memory. One special ``behavior'' expression is interpreted directly by @code(timed-seq): @code[(SCORE-BEGIN-END)] is ignored, not evaluated as a function. Normally, this special behavior is placed at time 0 and has two parameters: the score start time and the score end time. These are used in Xmusic functions. If the behavior has a @code(:pitch) keyword parameter which is a list, the list represents a chord, and the expression is replaced by a set of behaviors, one for each note in the chord. It follows that if @code(:pitch) is @code(nil), the behavior represents a rest and is ignored. @end(fndefs) @section(Sound File Input and Output) @index(sound file I/O) @begin(fndefs) @label(play-sec) @codef[play @pragma(defn)@index(play)@i(sound)] @c{[sal]}@* @altdef{@code[(play @i(sound))] @c{[lisp]}}@\Play the sound through the DAC. Note that @code(play) is a command in SAL. In XLISP, it is a function, so the syntax is @code[(play @i(sound))], and in SAL, you can call the XLISP function as @code[#play(@i(sound))]. The @code(play) command or function writes a file and plays it. The details of this are system-dependent, but @code(play) is defined in the file @code(system.lsp). The variable @code(*default-sf-dir*)@index(sound file directory default)@index(directory, default sound file)@index(default sound file directory)@index(temporary sound files directory) @index(*default-sf-dir*) names a directory into which to save a sound file. Be careful not to call @code(play) or @code(sound-play) within a function and then invoke that function from another @code(play) command. By default, Nyquist will try to normalize sounds using the method named by @code(*autonorm-type*), which is @code('lookahead) by default. The @i(lookahead) method precomputes and buffers @code(*autonorm-max-samples*) samples, finds the peak value, and normalizes accordingly. The @code('previous) method bases the normalization of the current sound on the peak value of the (entire) previous sound. This might be good if you are working with long sounds that start rather softly. See Section @ref(peak-ex-sec) for more details. If you want precise control over output levels, you should turn this feature off by typing (using SAL syntax): @begin(example) autonorm-off()@index(autonorm-off) @end(example) Reenable the automatic normalization feature by typing: @begin(example) autonorm-on()@index(autonorm-on) @end(example) Play normally produces real-time output. The default is to send audio data to the DAC as it is computed in addition to saving samples in a file. If computation is slower than real-time, output will be choppy, but since the samples end up in a file, you can type @code[(r)] to replay the stored sound. Real-time playback can be disabled by (using SAL syntax): @begin(example) sound-off()@index(sound-off) @end(example) and reenabled by: @begin(example) sound-on()@index(sound-on) @end(example) Disabling real-time playback has no effect on @code[(play-file)] or @code[(r)]. While sounds are playing, typing control-A@index(control-A) to Nyquist will push the estimated elapsed@index(elapsed audio time) audio time onto the head of the list stored in @code(*audio-markers*). @index(*audio-markers*)@index(audio markers)@index(markers, audio) Because samples are computed in blocks and because there is latency between sample computation and sample playback, the elapsed time may not be too accurate, and the computed elapsed time may not advance after all samples have been computed but the sound is still playing. @codef[play-file(@pragma(defn)@index(play-file)@i(filename))] @c{[sal]}@* @altdef{@code[(play-file @i(filename))] @c{[lisp]}}@\Play the contents of a sound file named by @i(filename). The @code(s-read) function is used to read the file, and unless @i(filename) specifies an absolute path or starts with ``.'', it will be read from @code(*default-sf-dir*). @codef[autonorm-on(@pragma(defn)@index(autonorm-on))] @c{[sal]}@* @altdef{@code[(autonorm-on)] @c{[lisp]}}@\Enable automatic adjustment of a scale factor applied to sounds computed using the @code(play) command. @codef[autonorm-off(@pragma(defn)@index(autonorm-off))] @c{[sal]}@* @altdef{@code[(autonorm-off)] @c{[lisp]}}@\Disable automatic adjustment of a scale factor applied to sounds computed using the @code(play) command. @codef[sound-on(@pragma(defn)@index(sound-on))] @c{[sal]}@* @altdef{@code[(sound-on)] @c{[lisp]}}@\Enable real-time audio output when sound is computed by the the @code(play) command. @codef[sound-off(@pragma(defn)@index(sound-off))] @c{[sal]}@* @altdef{@code[(sound-off)] @c{[lisp]}}@\Disable real-time audio output when sound is computed by the the @code(play) command. @label(s-save-sec) @codef{s-save(@pragma(defn)@index(s-save)@index(save samples to file)@index(write samples to file)@index(output samples to file)@i(expression), @i(maxlen), @i(filename), format: @i(format), mode: @i(mode), bits: @i(bits), swap: @i(flag), play: @i(play))} @c{[sal]}@* @altdef{@code{(s-save @i(expression) @i(maxlen) @i(filename) :format @i(format) :mode @i(mode) :bits @i(bits) :swap @i(flag) :play @i(play))} @c{[lisp]}}@\@label(s-save)Evaluates the @i(expression), which should result in a sound or an array of sounds, and writes the result to the given @i(filename). A @code(FLONUM) is returned giving the maximum absolute value of all samples written. (This is useful for normalizing sounds and detecting sample overflow.) If @i(play) is not @code(NIL), the sound will be output through the computer's audio output system. (@i(play:) @c{[sal]} or @i(:play) @c{[lisp]} is not implemented on all systems; if it is implemented, and @i(filename) is @code(NIL), then this will play the file without also writing a file.) The latency (length of audio buffering) used to play the sound is 0.3s by default, but see @code(snd-set-latency). If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. A header is written according to @i(format), samples are encoded according to @i(mode), using @i(bits) bits/sample, and bytes are swapped if @i(flag) is not NIL. Defaults for these are @code(*default-sf-format*), @code(*default-sf-mode*), and @code(*default-sf-bits*). The default for @i(flag) is NIL. The @i(bits) parameter may be 8, 16, or 32. The values for the @i(format) and @i(mode) options are described below: @end(fndefs) @b(Format) @begin(description, leftmargin +2 in, indent -2 in) @code(snd-head-none)@\The format is unknown and should be determined by reading the file. @code(snd-head-raw)@\A raw format file has no header. @code(snd-head-AIFF)@\AIFF format header. @code(snd-head-IRCAM)@\IRCAM format header. @code(snd-head-NeXT)@\1024-byte NeXT/SUN format header followed by IRCAM header ala CMIX. Note that the NeXT/SUN format has a header-length field, so it really is legal to have a large header, even though the normal minimal header is only 24 bytes. The additional space leaves room for maximum amplitudes, which can be used for normalizing floating-point soundfiles, and for other data. Nyquist follows the CMIX convention of placing an IRCAM format header immediately after the NeXT-style header. @code(snd-head-Wave)@\Microsoft Wave format header. @code(snd-head-*)@\See sndfnint.lsp for more formats. @end(description) @b(Mode) @begin(description, leftmargin +2 in, indent -2 in) @code(snd-mode-adpcm)@\ADPCM mode (not supported). @code(snd-mode-pcm)@\signed binary PCM mode. @code(snd-mode-ulaw)@\8-bit U-Law mode. @code(snd-mode-alaw)@\8-bit A-Law mode (not supported). @code(snd-mode-float)@\32-bit floating point mode. @code(snd-mode-upcm)@\unsigned binary PCM mode. @code(snd-mode-*)@\See sndfnint.lsp for more modes. @end(description) The defaults for format, mode, and bits are as follows: @begin(description, leftmargin +2 in, indent -2 in) NeXT and Sun machines:@\@code(snd-head-NeXT), @code(snd-mode-pcm), @code(16) SGI and Macintosh machines:@\@code(snd-head-AIFF), @code(snd-mode-pcm), @code(16) @end(description) @begin(fndefs) @label(s-read-sec) @codef{s-read(@pragma(defn)@index(s-read)@index(read samples from file)@i(filename), time-offset: @i(offset), srate: @i(sr), dur: @i(dur), nchans: @i(chans), format: @i(format), mode: @i(mode), bits: @i(n), swap: @i(flag))} @c{[sal]}@* @altdef{@code{(s-read @i(filename) :time-offset @i(offset) :srate @i(sr) :dur @i(dur) :nchans @i(chans) :format @i(format) :mode @i(mode) :bits @i(n) :swap @i(flag))} @c{[lisp]}}@\Reads a sound from @i(filename). The global @code(*default-sf-dir*) applies. If a header is detected, the header is used to determine the format of the file, and header information overrides format information provided by keywords (except for @code(time-offset:) and @code(dur:)). @begin(example) s-read("mysound.snd", srate: 44100) @end(example) specifies a sample rate of 44100 hz, but if the file has a header specifying 22050 hz, the resulting sample rate will be 22050. The parameters are: @begin(itemize) @i(offset) @itemsep the amount of time (in seconds) to skip from the beginning of the file. The default is 0.0. @i(sr) @itemsep the sample rate of the samples in the file. Default is @code(*default-sf-srate*) @index(*default-sf-srate*), which is normally 44100. @i(dur) @itemsep the maximum duration in seconds to read. Default is 10000. @i(chans) @itemsep the number of channels to read. It is assumed that samples from each channel are interleaved. Default is 1. @i(format) @itemsep the header format. See @code(s-save) for details. Default is @code(*default-sf-format*), although this parameter is currently ignored. @i(mode) @itemsep the sample representation, e.g. PCM or float. See @code(s-save) for details. Default is @code(*default-sf-format*). @i(n) @itemsep the number of bits per sample. See @code(s-save) for details. Default is @code(*default-sf-bits*). @i(flag) @itemsep (T or NIL) swap byte order of each sample. Default is NIL. @end(itemize) If there is an error, for example if @i(offset) is greater than the length of the file, then @code(NIL) is returned rather than a sound. Information about the sound is also returned by @code(s-read) through @code(*rslt*)@foot(Since XLISP does not support multiple value returns, multiple value returns are simulated by having the function assign additional return values in a list to the global variable @code(*rslt*). Since this is a global, it should be inspected or copied immediately after the function return to insure that return values are not overwritten by another function.). The list assigned to @code(*rslt*) is of the form: (@i(format) @i(channels) @i(mode) @i(bits) @i(samplerate) @i(duration) @i(flags) @i(byte-offset)), which are defined as follows: @begin(itemize) @i(format) @itemsep the header format. See @code(s-save) for details. @i(channels) @itemsep the number of channels. @i(mode) @itemsep the sample representation, e.g. PCM or float. See @code(s-save) for details. @i(bits) @itemsep the number of bits per sample. @i(samplerate) @itemsep the sample rate, expressed as a @code(FLONUM). @i(duration) @itemsep the duration of the sound, in seconds. @i(flags) @itemsep The values for @i(format), @i(channels), @i(mode), @i(bits), @i(samplerate), and @i(duration) are initially just the values passed in as parameters or default values to @code(s-read). If a value is actually read from the sound file header, a flag is set. The flags are: @code(snd-head-format), @code(snd-head-channels), @code(snd-head-mode), @code(snd-head-bits), @code(snd-head-srate), and @code(snd-head-dur). For example, @begin(example) (let ((flags (caddr (cddddr *rslt*)))) (not (zerop (logand flags snd-head-srate)))) @end(example) tells whether the sample rate was specified in the file. See also @code(sf-info) below. @i(byte-offset) @itemsep the byte offset into the file of the first sample to be read (this is used by the @code(s-overwrite) and @code(s-add-to) functions). @end(itemize) @codef{s-add-to(@pragma(defn)@index(s-add-to)@index(add to file samples)@index(mix to file)@i(expression), @i(maxlen), @i(filename) [, @i(offset)])} @c{[sal]}@* @altdef{@code{(s-add-to @i(expression) @i(maxlen) @i(filename) [@i(offset)])} @c{[lisp]}}@\@label(s-add-to-sec)Evaluates the @i(expression), which should result in a sound or an array of sounds, and adds the result to the given @i(filename). The global @code(*default-sf-dir*) applies. A @code(FLONUM) is returned, giving the maximum absolute value of all samples written. The sample rate(s) of @i(expression) must match those of the file. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. If @i(offset) is specified, the new sound is added to the file beginning at an @i(offset) from the beginning (in seconds). The file is extended if necessary to accommodate the new addition, but if @i(offset) falls outside of the original file, the file is not modified. (If necessary, use @code(s-add-to) to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file). @codef{s-overwrite(@pragma(defn)@index(s-overwrite)@index(replace file samples)@index(overwrite samples)@i(expression), @i(maxlen), @i(filename) [, @i(offset)])} @c{[sal]}@* @altdef{@code{(s-overwrite @i(expression) @i(maxlen) @i(filename) [@i(offset)])} @c{[lisp]}}@\@label(s-overwrite-sec)Evaluates the @i(expression), which should result in a sound or an array of sounds, and replaces samples in the given @i(filename). The global @code(*default-sf-dir*) applies. A @code(FLONUM) is returned, giving the maximum absolute value of all samples written. The sample rate(s) of @i(expression) must match those of the file. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. If @i(offset) is specified, the new sound is written to the file beginning at an @i(offset) from the beginning (in seconds). The file is extended if necessary to accommodate the new insert, but if @i(offset) falls outside of the original file, the file is not modified. (If necessary, use @code(s-add-to) to extend the file with zeros.) The file must be a recognized sound file with a header (not a raw sound file). @codef{sf-info(@pragma(defn)@index(sf-info)@index(sound file info)@i(filename))} @c{[sal]}@* @altdef{@code[(sf-info @i(filename))] @c{[lisp]}}@\Prints information about a sound file. The parameter @i(filename) is a string. The file is assumed to be in *default-sf-dir* (see @code(soundfilename) below) unless the filename begins with ``.'' or ``/''. The source for this function is in the @code(runtime) and provides an example of how to determine sound file parameters. @codef{soundfilename(@pragma(defn)@index(soundfilename)@i(name))} @c{[sal]}@* @altdef{@code[(soundfilename @i(name))] @c{[lisp]}}@\Converts a string @i(name) to a soundfile name. If @i(name) begins with ``.'' or ``/'', the name is returned without alteration. Otherwise, a path taken from @code(*default-sf-dir*) is prepended to @i(name). The @code(s-plot), @code(s-read), and @code(s-save) functions all use @code(soundfilename) translate filenames. @codef{s-plot(@pragma(defn)@index(s-plot)@index(plot)@i(sound) [, @i(dur), @i(n)])} @c{[sal]}@* @altdef{@code{(s-plot @i(sound) [@i(dur) @i(n)])} @c{[lisp]}}@\Plots sound in a window. This function was designed to run a @code(plot) program on a Unix workstation, but now is primarily used with @code(NyquistIDE), which has self-contained plotting. Normally, time/value pairs in ascii are written to @code(points.dat) and system-dependent code (or the @code(NyquistIDE) program) takes it from there. If the @i(sound) is longer than the optional @i(dur) (default is 2 seconds), only the first @i(dur) seconds are plotted. If there are more than @i(n) samples to be plotted, the signal is interpolated to have @i(n) samples before plotting. The data file used is @code(*default-plot-file*): @codef(*default-plot-file*)@pragma(defn)@index(*default-plot-file*)@\The file containing the data points, defaults to "points.dat". @codef{s-print-tree(@pragma(defn)@index(s-print-tree)@index(snd-print-tree)@i(sound))} @c{[sal]}@* @altdef{@code[(s-print-tree @i(sound))] @c{[lisp]}}@\Prints an ascii representation of the internal data structures representing a sound. This is useful for debugging@index(debugging) Nyquist. Identical to @code(snd-print-tree). @end(fndefs) @section(Low-level Functions) Nyquist includes many low-level functions that are used to implement the functions and behaviors described in previous sections. For completeness, these functions are described here. Remember that these are low-level functions that are not intended for normal use. Unless you are trying to understand the inner workings of Nyquist, you can skip this section. @subsection(Creating Sounds) The basic operations that create sounds are described here. @begin(fndefs) @codef[snd-const(@pragma(defn)@index(snd-const)@i(value), @i(t0), @i(srate), @i(duration))] @c{[sal]}@* @altdef{@code[(snd-const @i(value) @i(t0) @i(srate) @i(duration))] @c{[lisp]}}@\Returns a sound with constant @i(value), starting at @i(t0) with the given @i(duration), at the sample rate @i(srate). You might want to use @code(pwl) (see Section @ref(pwl-sec)) instead. @codef[snd-read(@pragma(defn)@index(snd-read)@i(filename), @i(offset), @i(t0), @i(format), @i(channels), @i(mode), @i(bits), @i(swap), @i(sr), @i(dur))] @c{[sal]}@* @altdef{@code[(snd-read @i(filename) @i(offset) @i(t0) @i(format) @i(channels) @i(mode) @i(bits) @i(swap) @i(sr) @i(dur))] @c{[lisp]}}@\Loads a sound from a file with name @i(filename). Files are assumed to consist of a header followed by frames consisting of one sample from each channel. The @i(format) specifies the type of header, but this information is currently ignored. Nyquist looks for a number of header formats and automatically figures out which format to read. If a header can be identified, the header is first read from the file. Then, the file pointer is advanced by the indicated @i(offset) (in seconds). If there is an unrecognized header, Nyquist will assume the file has no header. If the header size is a multiple of the frame size (bytes/sample * number-of-channels), you can use @i(offset) to skip over the header. To skip N bytes, use an @i(offset) of: @begin(example) (/ (float N) @i(sr) (/ @i(bits) 8) @i(channels)) @end(example) If the header is not a multiple of the frame size, either write a header or contact the author (dannenberg@@cs.cmu.edu) for assistance. Nyquist will round @i(offset) to the nearest sample. The resulting sound will start at time @i(t0). If a header is found, the file will be interpreted according to the header information. If no header was found, @i(channels) tells how many channels there are, the samples are encoded according to @i(mode), the sample length is @i(bits), and @i(sr) is the sample rate. The @i(swap) flag is 0 or 1, where 1 means to swap sample bytes. The duration to be read (in seconds) is given by @i(dur). If @i(dur) is longer than the data in the file, then a shorter duration will be returned. If the file contains one channel, a sound is returned. If the file contains 2 or more channels, an array of sounds is returned. @p(Note:) you probably want to call @code(s-read) (see Section @ref(s-read-sec)) instead of @code(snd-read). Also, see Section @ref(s-read-sec) for information on the @i(mode) and @i(format) parameters. @codef[snd-save(@pragma(defn)@index(snd-save)@i(expression), @i(maxlen), @i(filename), @i(format), @i(mode), @i(bits), @i(swap), @i(play))] @c{[sal]}@* @altdef{@code[(snd-save @i(expression) @i(maxlen) @i(filename) @i(format) @i(mode) @i(bits) @i(swap) @i(play))] @c{[lisp]}}@\@label(snd-save)Evaluates the @i(expression), which should result in a sound or an array of sounds, and writes the result to the given @i(filename). If a multichannel sound (array) is written, the channels are up-sampled to the highest rate in any channel so that all channels have the same sample rate. The maximum number of samples written per channel is given by @i(maxlen), which allows writing the initial part of a very long or infinite sound. A header is written according to @i(format), samples are encoded according to @i(mode), using @i(bits) bits/sample, and swapping bytes if @i(swap) is 1 (otherwise it should be 0). If @i(play) is not null, the audio is played in real time (to the extent possible) as it is computed. The peak value of the sound is returned. In addition, the symbol @code(*RSLT*) is bound to a list containing the sample rate, number of channels, and duration (in that order) of the saved sound. @p(Note:) you probably want to call @code(s-save) (see Section @ref(s-save-sec)) instead. The @i(format) and @i(mode) parameters are described in Section @ref(s-save-sec). @codef[snd-overwrite(@pragma(defn)@index(snd-overwrite)@i(expression), @i(maxlen), @i(filename), @i(offset), @i(format), @i(mode), @i(bits), @i(swap))] @c{[sal]}@* @altdef{@code[(snd-overwrite @i(expression) @i(maxlen) @i(filename) @i(offset) @i(format) @i(mode) @i(bits) @i(swap))] @c{[lisp]}}@\@label(snd-overwrite-sec)Evaluates the @i(expression), which should result in a sound or an array of sounds, and replaces samples in the given @i(filename), writing the first frame at a time of @i(offset) seconds. The @i(offset) must be less than or equal to the duration of the existing file. The duration of the written samples may be greater than that of the file, in which case the file is extended as necessary. The sample rate(s) of @i(expression) and the number of channels must match those of the file. If @i(format) is @code(SND-HEAD-RAW), then the file format is given by @i(mode) (see @code(snd-save), @i(bits) (per channel), @i(swap) (1 means to swap bytes and 0 means write them in the native byte order), and the number of channels and sample rate of the sound returned by evaluating @i(expression). If the file is a known audio file format, @i(format) should be @code(SND-HEAD-NONE), and the other parameters are ignored. Up to a maximum of @i(maxlen) samples will be written per channel. The peak value of the sound is returned. In addition, the symbol @code(*RSLT*) is bound to a list containing the duration of the written sound (which may not be the duration of the sound file). Use @code(s-add-to) (in Section @ref(s-add-to-sec) or @code(s-overwrite) (in Section @ref(s-overwrite-sec) instead of this function. @codef[snd-coterm(@pragma(defn)@index(snd-coterm)@index(co-termination)@index(duration of another sound)@i(s1), @i(s2))] @c{[sal]}@* @altdef{@code[(snd-coterm @i(s1) @i(s2))] @c{[lisp]}}@\Returns a copy of @i(s1), except the start time is the maximum of the start times of @i(s1) and @i(s2), and the termination time is the minimum of @i(s1) and @i(s2). (After the termination time, the sound is zero as if @i(s1) is gated by @i(s2).) Some rationale follows: In order to implement @code(s-add-to), we need to read from the target sound file, add the sounds to a new sound, and overwrite the result back into the file. We only want to write as many samples into the file as there are samples in the new sound. However, if we are adding in samples read from the file, the result of a @code(snd-add) in Nyquist will have the maximum duration of either sound. Therefore, we may read to the end of the file. What we need is a way to truncate the read, but we cannot easily do that, because we do not know in advance how long the new sound will be. The solution is to use @code(snd-coterm), which will allow us to truncate the sound that is read from the file (@i(s1)) according to the duration of the new sound (@i(s2)). When this truncated sound is added to the new sound, the result will have only the duration of the new sound, and this can be used to overwrite the file. This function is used in the implementation of @code(s-add-to), which is defined in @code(runtime/fileio.lsp). @code[(snd-from-array @r(...))] @c{[sal]}@* @altdef{@code[(snd-from-array @r(...))] @c{[lisp]}}@\See @pragma(startref) page @pageref(snd-from-array-sec). @codef[snd-white(@pragma(defn)@index(snd-white)@i(t0), @i(sr), @i(d))] @c{[sal]}@* @altdef{@code[(snd-white @i(t0) @i(sr) @i(d))] @c{[lisp]}}@\Generate white noise, starting at @i(t0), with sample rate @i(sr), and duration @i(d). You probably want to use @code(noise) (see Section @ref(noise-sec)). @codef[snd-zero(@pragma(defn)@index(snd-zero)@i(t0), @i(srate))] @c{[sal]}@* @altdef{@code[(snd-zero @i(t0) @i(srate))] @c{[lisp]}}@\Creates a sound that is zero everywhere, starts at @i(t0), and has sample rate @i(srate). The logical stop time is immediate, i.e. also at @i(t0). You probably want to use @code(pwl) (see Section @ref(pwl-sec)) instead. @codef[get-slider-value(@pragma(defn)@index(get-slider-value)@i(index))] @c{[sal]}@* @altdef{@code[(get-slider-value @i(index))] @c{[lisp]}}@\@label(get-slider-value-sec)Return the current value of the slider named by @i(index) (an integer index into the array of sliders). Note that this ``slider'' is just a floating point value in an array. Sliders can be changed by OSC messages (see @code(osc-enable)) and by sending character sequences to Nyquist's standard input. (Normally, these character sequences would not be typed but generated by the NyquistIDE interactive development environment, which runs Nyquist as a sub-process, and which present the user with graphical sliders.) @codef[snd-slider(@pragma(defn)@index(snd-slider)@i(index), @i(t0), @i(srate), @i(duration))] @c{[sal]}@* @altdef{@code[(snd-slider @i(index) @i(t0) @i(srate) @i(duration))] @c{[lisp]}}@\@label(snd-slider-sec)Create a sound controlled by the slider named by @i(index) (an integer index into the array of sliders; see @code(get-slider-value) for more information). The function returns a sound. Since Nyquist sounds are computed in blocks of samples, and each block is computed at once, each block will contain copies of the current slider value. To obtain reasonable responsiveness, slider sounds should have high (audio) sample rates so that the block rate will be reasonably high. Also, consider lowering the audio latency using @code(snd-set-latency). To ``trigger'' a Nyquist behavior using slider input, see the @code(trigger) function in Section @ref(trigger-sec). @end(fndefs) @subsection(Signal Operations) This next set of functions take sounds as arguments, operate on them, and return a sound. @begin(fndefs) @codef[snd-abs(@pragma(defn)@index(snd-abs)@index(absolute value)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-abs @i(sound))] @c{[lisp]}}@\Computes a new sound where each sample is the absolute value of the corresponding sample in @i(sound). You should probably use @code(s-abs) instead. (See Section @ref(s-abs-sec).) @codef[snd-sqrt(@pragma(defn)@index(snd-sqrt)@index(square root)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-sqrt @i(sound))] @c{[lisp]}}@\Computes a new sound where each sample is the square root of the corresponding sample in @i(sound). If a sample is negative, it is taken to be zero to avoid raising a floating point error. You should probably use @code(s-sqrt) instead. (See Section @ref(s-sqrt-sec).) @codef[snd-add(@pragma(defn)@index(snd-add)@i(sound1), @i(sound))] @c{[sal]}@* @altdef{@code[(snd-add @i(sound1) @i(sound))] @c{[lisp]}}@\Adds two sounds. The resulting start time is the minimum of the two parameter start times, the logical stop time is the maximum of the two parameter stop times, and the sample rate is the maximum of the two parameter sample rates. Use @code(sim) or @code(sum) instead of @code(snd-add) (see Section @ref(sim-sec)). @codef[snd-offset(@pragma(defn)@index(snd-offset)@index(offset to a sound)@index(add offset to sound)@i(sound), @i(offset))] @c{[sal]}@* @altdef{@code[(snd-offset @i(sound) @i(offset))] @c{[lisp]}}@\Add an offset to a sound. The resulting start time, logical stop time, stop time, and sample rate are those of @i(sound). Use @code(sum) instead (see Section @ref(sim-sec)). @codef[snd-avg(@pragma(defn)@index(snd-avg)@index(moving average)@index(RMS)@index(average)@i(sound), @i(blocksize), @i(stepsize), @i(operation))] @c{[sal]}@* @altdef{@code[(snd-avg @i(sound) @i(blocksize) @i(stepsize) @i(operation))] @c{[lisp]}}@\Computes the averages or peak values of blocks of samples. Each output sample is an average or peak of @i(blocksize) (a fixnum) adjacent samples from the input @i(sound). After each average or peak is taken, the input is advanced by @i(stepsize), a fixnum which may be greater or less than @i(blocksize). The output sample rate is the @i(sound) (input) sample rate divided by @i(stepsize). This function is useful for computing low-sample-rate rms or peak amplitude signals for input to @code(snd-gate) or @code(snd-follow). To select the operation, @i(operation) should be one of @code(OP-AVERAGE) or @code(OP-PEAK). (These are global lisp variables; the actual @i(operation) parameter is an integer.) For RMS computation, see @code(rms) in Section @ref(rms-sec). @codef[snd-clip(@index(clip)@pragma(defn)@index(snd-clip)@i(sound), @i(peak))] @c{[sal]}@* @altdef{@code[(snd-clip @i(sound) @i(peak))] @c{[lisp]}}@\Hard limit @i(sound) to the given @i(peak), a positive number. The samples of @i(sound) are constrained between an upper value of @i(peak) and a lower value of @subtract()@i(peak). Use @code(clip) instead (see Section @ref(clip-sec)). @codef[snd-compose(@index(compose)@index(signal composition)@pragma(defn)@index(snd-compose)@i(f), @i(g))] @c{[sal]}@* @altdef{@code[(snd-compose @i(f) @i(g))] @c{[lisp]}}@\Compose two signals, i.e. compute @i(f)(@i(g)(@i(t))), where @i(f) and @i(g) are sounds. This function is used primarily to implement time warping, but it can be used in other applications such as frequency modulation. For each sample @i(x) in @i(g), @i(snd-compose) looks up the value of @i(f)(@i(x)) using linear interpolation. The resulting sample rate, start time, etc. are taken from @i(g). The sound @i(f) is used in effect as a lookup table, but it is assumed that @i(g) is non-decreasing, so that @i(f) is accessed in time order. This allows samples of @i(f) to be computed and discarded incrementally. If in fact @i(g) decreases, the current sample of @i(g) is replaced by the previous one, forcing @i(g) into compliance with the non-decreasing restriction. See also @code(sref), @code(shape), and @code(snd-resample). For an extended example that uses @code(snd-compose) for variable pitch shifting, see @code(demos/pitch_change.htm).@index(demos, pitch change)@index(pitch shifting) @index(variable-resample function)@index(resampling) @label(snd-tapv-sec) @codef[snd-tapv(@pragma(defn)@index(snd-tapv)@index(tap)@index(variable delay)@index(delay, variable)@index(chorus)@i(sound), @i(offset), @i(vardelay), @i(maxdelay))] @c{[sal]}@* @altdef{@code[(snd-tapv @i(sound) @i(offset) @i(vardelay) @i(maxdelay))] @c{[lisp]}}@\A variable delay: @i(sound) is delayed by the sum of @i(offset) (a @code(FIXNUM) or @code(FLONUM)) and @i(vardelay) (a @code(SOUND)). The specified delay is adjusted to lie in the range of zero to @i(maxdelay) seconds to yield the actual delay, and the delay is implemented using linear interpolation. This function was designed specifically for use in a chorus effect: the @i(offset) is set to half of @i(maxdelay), and the @i(vardelay) input is a slow sinusoid. The maximum delay is limited to @i(maxdelay), which determines the length of a fixed-sized buffer. The function @code(tapv) is equivalent and preferred (see Section @ref(tapv-sec)). @codef[snd-tapf(@pragma(defn)@index(snd-tapf)@index(variable delay)@index(delay, variable)@i(sound), @i(offset), @i(vardelay), @i(maxdelay))] @c{[sal]}@* @altdef{@code[(snd-tapf @i(sound) @i(offset) @i(vardelay) @i(maxdelay))] @c{[lisp]}}@\A variable delay like @code(snd-tapv) except there is no linear interpolation. By eliminating interpolation, the output is an exact copy of the input with no filtering or distortion. On the other hand, delays jump by samples causing samples to double or skip even when the delay is changed smoothly. @codef[snd-copy(@pragma(defn)@index(snd-copy)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-copy @i(sound))] @c{[lisp]}}@\Makes a copy of @i(sound). Since operators always make (logical) copies of their sound parameters, this function should never be needed. This function is here for debugging@index(dubugging). @codef[snd-down(@pragma(defn)@index(snd-down)@i(srate), @i(sound))] @c{[sal]}@* @altdef{@code[(snd-down @i(srate) @i(sound))] @c{[lisp]}}@\Linear interpolation of samples down to the given sample rate @i(srate), which must be lower than the sample rate of @i(sound). Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call @code(force-srate) (see Section @ref(force-srate-sec)). @codef[snd-exp(@pragma(defn)@index(snd-exp)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-exp @i(sound))] @c{[lisp]}}@\Compute the exponential of each sample of @i(sound). Use @code(s-exp) instead (see Section @ref(s-exp-sec)). @label(snd-follow-sec) @codef[snd-follow(@pragma(defn)@index(snd-follow)@index(follower)@index(envelope follower)@i(sound), @i(floor), @i(risetime), @i(falltime), @i(lookahead))] @c{[sal]}@* @altdef{@code[(snd-follow @i(sound) @i(floor) @i(risetime) @i(falltime) @i(lookahead))] @c{[lisp]}}@\An envelope follower. The basic goal of this function is to generate a smooth signal that rides on the peaks of the input signal. The usual objective is to produce an amplitude envelope given a low-sample rate (control rate) signal representing local RMS measurements. The first argument is the input signal. The @i(floor) is the minimum output value. The @i(risetime) is the time (in seconds) it takes for the output to rise (exponentially) from @i(floor) to unity (1.0) and the @i(falltime) is the time it takes for the output to fall (exponentially) from unity to @i(floor). The algorithm looks ahead for peaks and will begin to increase the output signal according to @i(risetime) in anticipation of a peak. The amount of anticipation (in sampless) is given by @i(lookahead). The algorithm is as follows: the output value is allowed to increase according to @i(risetime) or decrease according to @i(falltime). If the next input sample is in this range, that sample is simply output as the next output sample. If the next input sample is too large, the algorithm goes back in time as far as necessary to compute an envelope that rises according to @i(risetime) to meet the new value. The algorithm will only work backward as far as @i(lookahead). If that is not far enough, then there is a final forward pass computing a rising signal from the earliest output sample. In this case, the output signal will be at least momentarily less than the input signal and will continue to rise exponentially until it intersects the input signal. If the input signal falls faster than indicated by @i(falltime), the output fall rate will be limited by @i(falltime), and the fall in output will stop when the output reaches @i(floor). This algorithm can make two passes througth the buffer on sharply rising inputs, so it is not particularly fast. With short buffers and low sample rates this should not matter. See @code(snd-avg) above for a function that can help to generate a low-sample-rate input for @code(snd-follow). See @code(snd-chase) in Section @ref(snd-chase-sec) for a related filter. @codef[snd-gate(@pragma(defn)@index(snd-gate)@index(noise gate)@index(gate)@i(sound), @i(lookahead), @i(risetime), @i(falltime), @i(floor), @i(threshold))] @c{[sal]}@* @altdef{@code[(snd-gate @i(sound) @i(lookahead) @i(risetime) @i(falltime) @i(floor) @i(threshold))] @c{[lisp]}}@\This function generates an exponential rise and decay intended for noise gate implementation. The decay starts when the signal drops below threshold and stays there for longer than lookahead. Decay continues until the value reaches floor, at which point the decay stops and the output value is held constant. Either during the decay or after the floor is reached, if the signal goes above threshold, then the output value will rise to unity (1.0) at the point the signal crosses the threshold. Again, look-ahead is used, so the rise actually starts before the signal crosses the threshold. The rise is a constant-rate exponential and set so that a rise from @i(floor) to unity occurs in @i(risetime). Similarly, the fall is a constant-rate exponential such that a fall from unity to @i(floor) takes @i(falltime). The result is delayed by @i(lookahead), so the output is not actually synchronized with the input. To compensate, you should drop the initial @i(lookahead) of samples. Thus, @code(snd-gate) is not recommended for direct use. Use @code(gate) instead (see Section @ref(gate-sec)). @codef[snd-inverse(@index(inverse)@pragma(defn)@index(snd-inverse)@i(signal), @i(start), @i(srate))] @c{[sal]}@* @altdef{@code[(snd-inverse @i(signal) @i(start) @i(srate))] @c{[lisp]}}@\Compute the function inverse of @i(signal), that is, compute @i(g)(@i(t)) such that @i(signal)(@i(g)(@i(t))) = @i(t). This function assumes that @i(signal) is non-decreasing, it uses linear interpolation, the resulting sample rate is @i(srate), and the result is shifted to have a starting time of @i(start). If @i(signal) decreases, the true inverse may be undefined, so we define @code(snd-inverse) operationally as follows: for each output time point @i(t), scan ahead in @i(signal) until the value of signal exceeds @i(t). Interpolate to find an exact time point @i(x) from @i(signal) and output @i(x) at time @i(t). This function is intended for internal system use in implementing time warps. @codef[snd-log(@pragma(defn)@index(snd-log)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-log @i(sound))] @c{[lisp]}}@\Compute the natural logorithm of each sample of @i(sound). Use @code(s-log) instead (see Section @ref(s-log-sec)). @label(peak-sec) @codef[peak(@index(peak, maximum amplitude)@pragma(defn)@index(peak)@i(expression), @i(maxlen))] @c{[sal]}@* @altdef{@code[(peak @i(expression) @i(maxlen))] @c{[lisp]}}@\Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating @i(expression) (as in @code(s-save)). Only the first @i(maxlen) samples are evaluated. The @i(expression) is automatically quoted (@code(peak) is a macro), so do not quote this parameter. If @i(expression) is a variable, then the @i(global binding) of that variable will be used. Also, since the variable retains a reference to the sound, the sound will be evaluated and left in memory. See Section @ref(peak-ex-sec) on @pragma(startref) page @pageref(peak-ex-sec) for examples. @label(snd-max-sec) @codef[snd-max(@pragma(defn)@index(snd-max)@index(maximum amplitude)@i(expression), @i(maxlen))] @c{[sal]}@* @altdef{@code[(snd-max @i(expression) @i(maxlen))] @c{[lisp]}}@\Compute the maximum absolute value of the amplitude of a sound. The sound is created by evaluating @i(expression) (as in @code(snd-save)), which is therefore normally quoted by the caller. At most @i(maxlen) samples are computed. The result is the maximum of the absolute values of the samples. @p(Notes:) It is recommended to use @code(peak) (see above) instead. If you want to find the maximum of a sound bound to a local variable and it is acceptable to save the samples in memory, then this is probably the function to call. Otherwise, use @code(peak). @codef[snd-maxv(@pragma(defn)@index(snd-maxv)@index(maximum of two sounds)@i(sound1), @i(sound2))] @c{[sal]}@* @altdef{@code[(snd-maxv @i(sound1) @i(sound2))] @c{[lisp]}}@\Compute the maximum of @i(sound1) and @i(sound2) on a sample-by-sample basis. The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. The physical stop time is the minimum of the physical stop times of the two sounds. @i(Note that this violates the ``normal'' interpretation that sounds are zero outside their start and stop times. For example, even if) sound1 @i(extends beyond) sound2 @i(and is greater than zero, the result value in this extension will be zero because it will be after the physical stop time, whereas if we simply treated) sound2 @i(as zero in this region and took the maximum, we would get a non-zero result.) Use @code(s-max) instead (see Section @ref(s-max-sec)). @codef[snd-normalize(@pragma(defn)@index(snd-normalize)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-normalize @i(sound))] @c{[lisp]}}@\Internally, sounds are stored with a scale factor that applies to all samples of the sound. All operators that take sound arguments take this scale factor into account (although it is not always necessary to perform an actual multiply per sample), so you should never need to call this function. This function multiplies each sample of a sound by its scale factor, returning a sound that represents the same signal, but whose scale factor is 1.0. @codef[snd-oneshot(@pragma(defn)@index(snd-oneshot)@index(oneshot)@index(threshold)@i(sound), @i(threshold), @i(ontime))] @c{[sal]}@* @altdef{@code[(snd-oneshot @i(sound) @i(threshold) @i(ontime))] @c{[lisp]}}@\Computes a new sound that is zero except where @i(sound) exceeds threshold. From these points, the result is 1.0 until @i(sound) remains below @i(threshold) for @i(ontime) (in seconds). The result has the same sample rate, start time, logical stop time, and duration as @i(sound). @codef[snd-prod(@pragma(defn)@index(snd-prod)@index(signal multiplication)@index(multiplication)@i(sound1), @i(sound2))] @c{[sal]}@* @altdef{@code[(snd-prod @i(sound1) @i(sound2))] @c{[lisp]}}@\Computes the product of @i(sound1) and @i(sound2). The resulting sound has its start time at the maximum of the input start times and a logical stop at the minimum logical stop of the inputs. Do not use this function. Use @code(mult) or @code(prod) instead (see Section @ref(mult-sec)). Sample rate, start time, etc. are taken from @i(sound). @codef[snd-pwl(@pragma(defn)@index(snd-pwl)@index(piece-wise linear)@i(t0), @i(sr), @i(lis))] @c{[sal]}@* @altdef{@code[(snd-pwl @i(t0) @i(sr) @i(lis))] @c{[lisp]}}@\Computes a piece-wise linear function according to the breakpoints in @i(lis). The starting time is @i(t0), and the sample rate is @i(sr). The breakpoints are passed in an XLISP list (of type @code(LVAL)) where the list alternates sample numbers (@code(FIXNUM)s, computed in samples from the beginning of the pwl function) and values (the value of the pwl function, given as a @code(FLONUM)). There is an implicit starting point of (0, 0). The list must contain an odd number of points, the omitted last value being implicitly zero (0). The list is assumed to be well-formed. Do not call this function. Use @code(pwl) instead (see Section @ref(pwl-sec)). @codef[snd-quantize(@pragma(defn)@index(snd-quantize)@i(sound), @i(steps))] @c{[sal]}@* @altdef{@code[(snd-quantize @i(sound) @i(steps))] @c{[lisp]}}@\Quantizes a sound. See Section @ref(quantize-sec) for details. @codef[snd-recip(@pragma(defn)@index(snd-recip)@i(sound))] @c{[sal]}@* @altdef{@code[(snd-recip @i(sound))] @c{[lisp]}}@\Compute the reciprocal of each sample of @i(sound). Use @code(recip) instead (see Section @ref(recip-sec)). @codef[snd-resample(@pragma(defn)@index(snd-resample)@index(sample interpolation)@i(f), @i(rate))] @c{[sal]}@* @altdef{@code[(snd-resample @i(f) @i(rate))] @c{[lisp]}}@\Resample sound @i(f) using high-quality interpolation, yielding a new sound with the specified @i(rate). The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. The resulting start time, etc. are taken from @i(f). Use @code(resample) instead. @codef[snd-resamplev(@pragma(defn)@index(snd-resamplev)@index(sample interpolation)@index(signal composition)@i(f), @i(rate), @i(g))] @c{[sal]}@* @altdef{@code[(snd-resamplev @i(f) @i(rate) @i(g))] @c{[lisp]}}@\Compose two signals, i.e. compute @i(f)(@i(g)(@i(t))), where @i(f) and @i(g) are sounds. The result has sample rate given by @i(rate). At each time @i(t) (according to the @i(rate)), @i(g) is linearly interpolated to yield an increasing sequence of high-precision score-time values. @i(f) is then interpolated at each value to yield a result sample. If in fact @i(g) decreases, the current sample of @i(g) is replaced by the previous one, forcing @i(g) into compliance with the non-decreasing restriction. The result is scaled by 0.95 because often, in resampling, interpolated values exceed the original sample values, and this could lead to clipping. Note that if @i(g) has a high sample rate, this may introduce unwanted jitter into sample times. See @code(sound-warp) for a detailed discussion. See @code(snd-compose) for a fast, low-quality alternative to this function. Normally, you should use @code(sound-warp) instead of this function. @codef[snd-scale(@pragma(defn)@index(snd-scale)@i(scale), @i(sound))] @c{[sal]}@* @altdef{@code[(snd-scale @i(scale) @i(sound))] @c{[lisp]}}@\Scales the amplitude of @i(sound) by the factor @i(scale). Use @code(scale) instead (see Section @ref(scale-sec)). @codef{snd-shape(@pragma(defn)@index(snd-shape)@i(signal), @i(table), @i(origin))} @c{[sal]}@* @altdef{@code[(snd-shape @i(signal) @i(table) @i(origin))] @c{[lisp]}}@\A waveshaping function. This is the primitive upon which @code(shape) is based. The @code(snd-shape) function is like @code(shape) except that @i(signal) and @i(table) must be (single-channel) sounds. Use @code(shape) instead (see Section @ref(shape-sec)). @codef[snd-up(@pragma(defn)@index(snd-up)@i(srate), @i(sound))] @c{[sal]}@* @altdef{@code[(snd-up @i(srate) @i(sound))] @c{[lisp]}}@\Increases sample rate by linear interpolation. The @i(sound) is the signal to be up-sampled, and @i(srate) is the output sample rate. Do not call this function. Nyquist performs sample-rate conversion automatically as needed. If you want to force a conversion, call @code(force-srate) (see Section @ref(force-srate-sec)). @label(snd-xform-sec) @codef[snd-xform(@pragma(defn)@index(snd-xform)@i(sound), @i(sr), @i(time), @i(start), @i(stop), @i(scale))] @c{[sal]}@* @altdef{@code[(snd-xform @i(sound) @i(sr) @i(time) @i(start) @i(stop) @i(scale))] @c{[lisp]}}@\Makes a copy of @i(sound) and then alters it in the following order: (1) the start time (@code(snd-t0)) of the sound is shifted to @i(time), (1) the sound is stretched as a result of setting the sample rate to @i(sr) (the start time is unchanged by this), (3) the sound is clipped from @i(start) to @i(stop), (4) if @i(start) is greater than @i(time), the sound is shifted shifted by @i(time) - @i(start), so that the start time is @i(time), (5) the sound is scaled by @i(scale). An empty (zero) sound at @i(time) will be returned if all samples are clipped. Normally, you should accomplish all this using transformations. A transformation applied to a sound has no effect, so use @code(cue) to create a transformable sound (see Section @ref(use-sounds-sec)). @label(snd-yin-sec) @codef{snd-yin(@pragma(defn)@index(snd-yin)@i(sound), @i(minstep), @i(maxstep), @i(rate))} @c{[sal]}@* @altdef{@code[(snd-yin @i(sound) @i(minstep) @i(maxstep) @i(rate))] @c{[lisp]}}@\Identical to @code[yin]. See Section @ref(yin-sec). @end(fndefs) @subsection(Filters) These are also ``Signal Operators,'' the subject of the previous section, but there are so many filter functions, they are documented in this special section. Some filters allow time-varying filter parameters. In these functions, filter coefficients are calculated at the sample rate of the filter parameter, and coefficients are not interpolated. @begin(fndefs) @codef[snd-alpass(@pragma(defn)@index(snd-alpass)@i(sound), @i(delay), @i(feedback))] @c{[sal]}@* @altdef{@code[(snd-alpass @i(sound) @i(delay) @i(feedback))] @c{[lisp]}}@\An all-pass filter. This produces a repeating echo effect without the resonances of @code(snd-delay). The @i(feedback) should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use @code(alpass) instead (see Section @ref(alpass-sec)). @codef[snd-alpasscv(@pragma(defn)@index(snd-alpasscv)@i(sound), @i(delay), @i(feedback))] @c{[sal]}@* @altdef{@code[(snd-alpasscv @i(sound) @i(delay) @i(feedback))] @c{[lisp]}}@\An all-pass filter with variable @i(feedback). This is just like @i(snd-alpass) except @i(feedback) is a sound. You should use @code(alpass) instead (see Section @ref(alpass-sec)). @codef[snd-alpassvv(@pragma(defn)@index(snd-alpassvv)@i(sound), @i(delay), @i(feedback), @i(maxdelay))] @c{[sal]}@* @altdef{@code[(snd-alpassvv @i(sound) @i(delay) @i(feedback) @i(maxdelay))] @c{[lisp]}}@\An all-pass filter with variable @i(feedback) and @i(delay). This is just like @i(snd-alpass) except @i(feedback) and @i(delay) are sounds, and there is an additional @code(FLONUM) parameter, @i(maxdelay), that gives an upper bound on the value of @i(delay). @p(Note:) @i(delay) must remain between zero and @i(maxdelay). If not, results are undefined, and Nyquist may crash. You should use @code(alpass) instead (see Section @ref(alpass-sec)). @codef[snd-areson(@pragma(defn)@index(snd-areson)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-areson @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\A notch filter modeled after the @code(areson) unit generator in Csound. The @code(snd-areson) filter is an exact complement of @code(snd-reson) such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. Note that because of this complementary design, the power is not normalized as in @code(snd-reson). See @code(snd-reson) for details on @i(normalization). You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-aresoncv(@pragma(defn)@index(snd-aresoncv)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-aresoncv @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\This function is identical to @code(snd-areson) except the @i(bw) (bandwidth) parameter is a sound. Filter coefficients are updated at the sample rate of @i(bw). The ``@code(cv)'' suffix stands for Constant, Variable, indicating that @i(hz) and @i(bw) are constant (a number) and variable (a sound), respectively. This naming convention is used throughout. You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-aresonvc(@pragma(defn)@index(snd-aresonvc)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-aresonvc @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\This function is identical to @code(snd-areson) except the @i(hz) (center frequency) parameter is a sound. Filter coefficients are updated at the sample rate of @i(hz). You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-aresonvv(@pragma(defn)@index(snd-aresonvv)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-aresonvv @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\This function is identical to @code(snd-areson) except both @i(hz) (center frequency) and @i(bw) (bandwidth) are sounds. Filter coefficients are updated at the next sample of either @i(hz) or @i(bw). You should use @code(areson) instead (see Section @ref(areson-sec)). @codef[snd-atone(@pragma(defn)@index(snd-atone)@i(sound), @i(hz))] @c{[sal]}@* @altdef{@code[(snd-atone @i(sound) @i(hz))] @c{[lisp]}}@\A high-pass filter modeled after the @code(atone) unit generator in Csound. The @code(snd-atone) filter is an exact complement of @code(snd-tone) such that if both are applied to the same signal with the same parameters, the sum of the results yeilds the original signal. You should use @code(hp) instead (see Section @ref(hp-sec)). @codef[snd-atonev(@pragma(defn)@index(snd-atonev)@i(sound), @i(hz))] @c{[sal]}@* @altdef{@code[(snd-atonev @i(sound) @i(hz))] @c{[lisp]}}@\This is just like @code(snd-atone) except that the @i(hz) cutoff frequency is a sound. Filter coefficients are updated at the sample rate of @i(hz). You should use @code(hp) instead (see Section @ref(hp-sec)). @codef[snd-biquad(@pragma(defn)@index(snd-biquad)@i(sound), @i(b0), @i(b1), @i(b2), @i(a1), @i(a2), @i(z1init), @i(z2init))] @c{[sal]}@* @altdef{@code[(snd-biquad @i(sound) @i(b0) @i(b1) @i(b2) @i(a1) @i(a2) @i(z1init) @i(z2init))] @c{[lisp]}}@\A general second order IIR filter, where @i(a0) is assumed to be unity. For @i(a1) and @i(a2), the sign convention is opposite to that of Matlab. All parameters except the input @i(sound) are of type @code(FLONUM). You should probably use one of @code(lowpass2), @code(highpass2), @code(bandpass2), @code(notch2), @code(allpass2), @code(eq-lowshelf), @code(eq-highshelf), @code(eq-band), @code(lowpass4), @code(lowpass6), @code(lowpass8), @code(highpass4), @code(highpass6), or @code(highpass8), which are all based on @code(snd-biquad) and described in Section @ref(lowpass2-sec). For completeness, you will also find @code(biquad) and @code(biquad-m) described in that section. @label(snd-chase-sec) @codef[snd-chase(@pragma(defn)@index(snd-chase)@i(sound), @i(risetime), @i(falltime))] @c{[sal]}@* @altdef{@code[(snd-chase @i(sound) @i(risetime) @i(falltime))] @c{[lisp]}}@\A slew rate limiter. The output ``chases'' the input at rates determined by @i(risetime) and @i(falltime). If the input changes too fast, the output will lag behind the input. This is a form of lowpass filter, but it was created to turn hard-switching square waves into smoother control signals that could be used for linear crossfades. If the input switches from 0 to 1, the output will linearly rise to 1 in @i(risetime) seconds. If the input switches from 1 to 0, the output will linearly fall to 0 in @i(falltime) seconds. The generated slope is constant; the transition is linear; this is not an exponential rise or fall. The @i(risetime) and @i(falltime) must be scalar constants; complain to the author if this is not adequate. The @code(snd-chase) function is safe for ordinary use. See @code(snd-follow) in Section @ref(snd-follow-sec) for a related function. @codef[snd-congen(@pragma(defn)@index(snd-congen)@i(gate), @i(risetime), @i(falltime))] @c{[sal]}@* @altdef{@code[(snd-congen @i(gate) @i(risetime) @i(falltime))] @c{[lisp]}}@\A simple ``contour generator'' based on analog synthesizers. The @i(gate) is a sound that normally steps from 0.0 to 1.0 at the start of an envelop and goes from 1.0 back to 0.0 at the beginning of the release. At each sample, the output converges to the input exponentially. If @i(gate) is greater than the output, e.g. the attack, then the output converges half-way to the output in @i(risetime). If the @i(gate) is less than the output, the half-time is @i(falltime). The sample rate, starting time, logical-stop-time, and terminate time are taken from @i(gate). You should use @code(congen) instead (see Section @ref(congen-sec). @codef[snd-convolve(@pragma(defn)@index(snd-convolve)@i(sound), @i(response))] @c{[sal]}@* @altdef{@code[(snd-convolve @i(sound) @i(response))] @c{[lisp]}}@\Convolves @i(sound) by @i(response) using a simple O(N x M) algorithm. The @i(sound) can be any length, but the @i(response) is computed and stored in a table. The required compuation time per sample and total space are proportional to the length of @i(response). Use @code(convolve) instead (see Section @ref(convolve-sec)). @codef[snd-delay(@pragma(defn)@index(snd-delay)@i(sound), @i(delay), @i(feedback))] @c{[sal]}@* @altdef{@code[(snd-delay @i(sound) @i(delay) @i(feedback))] @c{[lisp]}}@\Feedback delay. The output, initially @i(sound), is recursively delayed by @i(delay), scaled by @i(feedback), and added to itself, producing an repeating echo effect. The @i(feedback) should be less than one to avoid exponential amplitude blowup. Delay is rounded to the nearest sample. You should use @code(feedback-delay) instead (see Section @ref(feedback-delay-sec)) @codef[snd-delaycv(@pragma(defn)@index(snd-delaycv)@i(sound), @i(delay), @i(feedback))] @c{[sal]}@* @altdef{@code[(snd-delaycv @i(sound) @i(delay) @i(feedback))] @c{[lisp]}}@\Feedback delay with variable @i(feedback). This is just like @i(snd-delay) except @i(feedback) is a sound. You should use @code(feedback-delay) instead (see Section @ref(feedback-delay-sec)). @codef[snd-reson(@pragma(defn)@index(snd-reson)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-reson @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\A second-order resonating (bandpass) filter with center frequency @i(hz) and bandwidth @i(bw), modeled after the @code(reson) unit generator in Csound. The @i(normalization) parameter must be an integer and (like in Csound) specifies a scaling factor. A value of 1 specifies a peak amplitude response of 1.0; all frequencies other than @i(hz) are attenuated. A value of 2 specifies the overall RMS value of the amplitude response is 1.0; thus filtered white noise would retain the same power. A value of zero specifies no scaling. The result sample rate, start time, etc. are takend from @i(sound). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-resoncv(@pragma(defn)@index(snd-resoncv)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-resoncv @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\This function is identical to @code(snd-reson) except @i(bw) (bandwidth) is a sound. Filter coefficients are updated at the sample rate of @i(bw). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-resonvc(@pragma(defn)@index(snd-resonvc)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-resonvc @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\This function is identical to @code(snd-reson) except @i(hz) (center frequency) is a sound. Filter coefficients are updated at the sample rate of @i(hz). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-resonvv(@pragma(defn)@index(snd-resonvv)@i(sound), @i(hz), @i(bw), @i(normalization))] @c{[sal]}@* @altdef{@code[(snd-resonvv @i(sound) @i(hz) @i(bw) @i(normalization))] @c{[lisp]}}@\This function is identical to @code(snd-reson) except botth @i(hz) (center frequency) and @i(bw) (bandwidth) are sounds. Filter coefficients are updated at the next sample from either @i(hz) or @i(bw). You should use @code(reson) instead (see Section @ref(reson-sec)). @codef[snd-stkchorus(@pragma(defn)@index(snd-stkchorus)@index(chorus)@index(effect, chorus)@index(STK chorus)@i(sound), @i(delay), @i(depth), @i(freq), @i(mix), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-stkchorus @i(sound) @i(delay) @i(depth) @i(freq) @i(mix) @i(sr))] @c{[lisp]}}@\A chorus implemented in STK. The parameter @i(delay) is a @code(FIXNUM) representing the median desired delay length in samples. A typical value is 6000. The @code(FLONUM) parameters @i(depth) and @i(freq) set the modulation depth (from 0 to 1) and modulation frequency (in Hz), @i(mix) sets the mixture of input sound and chorused sound, where a value of 0.0 means input sound only (dry) and a value of 1.0 means chorused sound only (wet). The parameter @i(sr) is the desired sample rate of the resulting sound@foot(This is probably a mistake since sample rate is implied by @i(sound). This parameter may be removed in a future release.) You should use @code(pitshift) instead (see Section @ref(stkchorus-sec)). @codef[snd-stkpitshift(@pragma(defn)@index(snd-stkpitshift)@index(pitch shift)@index(effect, pitch shift)@index(STK pitch shift)@i(sound), @i(shift), @i(mix), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-stkpitshift @i(sound) @i(shift) @i(mix) @i(sr))] @c{[lisp]}}@\A pitch shifter implemented in STK. The @i(sound) is shifted in pitch by @i(shift), a @code(FLONUM) representing the shift factor. A value of 1.0 means no shift. The parameter @i(mix) sets the mixture of input and shifted sounds. A value of 0.0 means input only (dry) and a value of 1.0 means shifted sound only (wet). The @i(sr) is the desired sampling frequency.@foot(This is probably a mistake since sample rate is implied by @i(sound). This parameter may be removed in a future release.) You should use @code(pitshift) instead (see Section @ref(stkpitshift-sec)). @codef[snd-stkrev(@pragma(defn)@index(snd-stkrev)@index(reverb)@index(effect, reverberation)@index(STK reverb)@i(rev-type), @i(sound), @i(decay), @i(mix), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-stkrev @i(rev-type) @i(sound) @i(decay) @i(mix) @i(sr))] @c{[lisp]}}@\A reverb implemented in STK. The parameter rev-type is a @code(FIXNUM) ranging from zero to two and selects the type of reverb. Zero selects NRev type, one selects JCRev, and two selects PRCRev. The input @i(sound) is processed by the reverb with a @i(decay) time in seconds (a @code(FLONUM)). The @i(mix), a @code(FLONUM), sets the mixture of dry input and reverb output. A value of 0.0 means input only (dry) and a value of 1.0 means reverb only (wet). The sample rate is @i(sr)@foot(This is probably a mistake since sample rate is implied by @i(sound). This parameter may be removed in a future release.) You should use @code(nrev), @code(jcrev) or @code(prcrev) instead (see Section @ref(stkrev-sec)). @codef[snd-tone(@pragma(defn)@index(snd-tone)@index(low-pass filter)@i(sound), @i(hz))] @c{[sal]}@* @altdef{@code[(snd-tone @i(sound) @i(hz))] @c{[lisp]}}@\A first-order recursive low-pass filter, based on the @i(tone) unit generator of Csound. The @i(hz) parameter is the cutoff frequency, the response curve's half-power point. The result sample rate, start time, etc. are takend from @i(sound). You should use @code(lp) instead (see Section @ref(lp-sec)). @codef[snd-tonev(@pragma(defn)@index(snd-tonev)@i(sound), @i(hz))] @c{[sal]}@* @altdef{@code[(snd-tonev @i(sound) @i(hz))] @c{[lisp]}}@\This function is identical to @code(snd-tone) except @i(hz) (cutoff frequency) is a sound. The filter coefficients are updated at the sample rate of @i(hz). You should use @code(lp) instead (see Section @ref(lp-sec)). @end(fndefs) @subsection(Table-Lookup Oscillator Functions) These functions all use a sound to describe one period of a periodic waveform. In the current implementation, the sound samples are copied to an array (the waveform table) when the function is called. To make a table-lookup oscillator generate a specific pitch, we need to have several pieces of information: @begin(itemize) A waveform to put into the table. This comes from the @i(sound) parameter. The length (in samples) of the waveform. This is obtained by reading samples (starting at the sound's start time, not necessarily at time zero) until the physical stop time of the sound. (If you read the waveform from a file or generate it with functions like @code(sim) and @code(sine), then the physical and logical stop times will be the same and will correspond to the duration you specified, rounded to the nearest sample.) The intrinsic sample rate of the waveform. This sample rate is simply the sample rate property of @i(sound). The pitch of the waveform. This is supplied by the @i(step) parameter and indicates the pitch (in steps) of @i(sound). You might expect that the pitch would be related to the period (length) of @i(sound), but there is the interesting case that synthesis based on sampling often loops over multiple periods. This means that the fundamental frequency of a generated tone may be some multiple of the looping rate. In Nyquist, you always specify the perceived pitch of the looped @i(sound) if the sound is played at the @i(sound)'s own sample rate. The desired pitch. This is specified by the @i(hz) parameter in Hertz (cycles per second) in these low-level functions. Note that this is not necessarily the ``loop'' rate at which the table is scanned. Instead, Nyquist figures what sample rate conversion would be necessary to ``transpose'' from the @i(step) which specifies the original pitch of @i(sound) to @i(hz), which gives the desired pitch. The mixed use of steps and Hertz came about because it seemed that sample tables would be tagged with steps (``I sampled a middle-C''), whereas frequency deviation in the @code(fmosc) function is linear, thus calling for a specification in Hertz. The desired sample rate. This is given by the @i(sr) parameter in Hertz. @end(itemize) Other parameters common to all of these oscillator functions are: @begin(itemize) @i(t0), the starting time, and @i(phase), the starting phase in degrees. Note that if the @i(step) parameter indicates that the table holds more than one fundamental period, then a starting phase of 360 will be different than a starting phase of 0. @end(itemize) @begin(fndefs) @codef[snd-amosc(@pragma(defn)@index(snd-amosc)@i(sound), @i(step), @i(sr), @i(hz), @i(t0), @i(am), @i(phase))] @c{[sal]}@* @altdef{@code[(snd-amosc @i(sound) @i(step) @i(sr) @i(hz) @i(t0) @i(am) @i(phase))] @c{[lisp]}}@\An oscillator with amplitude modulation. The sound @i(am) specifies the amplitude and the logical stop time. The physical stop time is also that of @i(am). You should use @code(amosc) instead (see Section @ref(amosc-sec)). @codef[snd-fmosc(@pragma(defn)@index(snd-fmosc)@i(s), @i(step), @i(sr), @i(hz), @i(t0), @i(fm), @i(phase))] @c{[sal]}@* @altdef{@code[(snd-fmosc @i(s) @i(step) @i(sr) @i(hz) @i(t0) @i(fm) @i(phase))] @c{[lisp]}}@\A Frequency Modulation oscillator. The sound @i(fm) specifies frequency deviation (in Hertz) from @i(hz). You should use @code(fmosc) instead (see Section @ref(fmosc-sec)). @codef[snd-fmfb(@pragma(defn)@index(snd-fmfb)@i(t0), @i(hz), @i(sr), @i(index), @i(dur))] @c{[sal]}@* @altdef{@code[(snd-fmfb @i(t0) @i(hz) @i(sr) @i(index) @i(dur))] @c{[lisp]}}@\A Feedback FM oscillator. The resulting sound starts at @i(t0), has a fundamental frequency of @i(hz), a sample rate of @i(sr), and a duration of @i(dur) seconds. The @i(index) is a @code(FLONUM) that specifies the amount of feedback. You should use @code(fmfb) instead (see Section @ref(fmfb-sec)). @codef[snd-fmfbv(@pragma(defn)@index(snd-fmfbv)@i(t0), @i(hz), @i(sr), @i(index))]@* @altdef{@code[(snd-fmfv @i(t0) @i(hz) @i(sr) @i(index))] @c{[lisp]}}@\A Feedback FM oscillator. The resulting sound starts at @i(t0), has a fundamental frequency of @i(hz), and a sample rate of @i(sr). The @i(index) is a @code(SOUND) that specifies the amount of feedback and determines the duration. You should use @code(fmfb) instead (see Section @ref(fmfb-sec)). @codef[snd-buzz(@pragma(defn)@index(snd-buzz)@i(n), @i(sr), @i(hz), @i(t0), @i(fm))] @c{[sal]}@* @altdef{@code[(snd-buzz @i(n) @i(sr) @i(hz) @i(t0) @i(fm))] @c{[lisp]}}@\A buzz oscillator, which generates @i(n) harmonics of equal amplitude. The @i(fm) specifies frequency deviation (in Hertz) from @i(hz). You should use @code(buzz) instead (see Section @ref(buzz-sec)). @codef[snd-pluck(@pragma(defn)@index(snd-pluck)@i(sr), @i(hz), @i(t0), @i(d), @i(final-amp))] @c{[sal]}@* @altdef{@code[(snd-pluck @i(sr) @i(hz) @i(t0) @i(d) @i(final-amp))] @c{[lisp]}}@\A Karplus-Strong plucked string oscillator with sample rate @i(sr), fundamental frequency @i(hz), starting time @i(t0), duration @i(d), initial amplitude approximately 1.0 (not exact because the string is initialized with random values) and final amplitude approximately @i(final-amp). You should use @code(pluck) instead (see Section @ref(pluck-sec)). @codef[snd-osc(@pragma(defn)@index(snd-osc)@i(s), @i(step), @i(sr), @i(hz), @i(t0), @i(d), @i(phase))] @c{[sal]}@* @altdef{@code[(snd-osc @i(s) @i(step) @i(sr) @i(hz) @i(t0) @i(d) @i(phase))] @c{[lisp]}}@\A simple table lookup oscillator with fixed frequency. The duration is @i(d) seconds. You should use @code(osc) instead (see Section @ref(osc-sec)). @codef[snd-partial(@pragma(defn)@index(snd-partial)@i(sr), @i(hz), @i(t0), @i(env))] @c{[sal]}@* @altdef{@code[(snd-partial @i(sr) @i(hz) @i(t0) @i(env))] @c{[lisp]}}@\This is a special case of @code(snd-amosc) that generates a sinusoid starting at phase 0 degrees. The @i(env) parameter gives the envelope or any other amplitude modulation. You should use @code(partial) instead (see Section @ref(partial-sec)). @codef[snd-sine(@pragma(defn)@index(snd-sine)@i(t0), @i(hz), @i(sr), @i(d))] @c{[sal]}@* @altdef{@code[(snd-sine @i(t0) @i(hz) @i(sr) @i(d))] @c{[lisp]}}@\This is a special case of @code(snd-osc) that always generates a sinusoid with initial phase of 0 degrees. You should use @code(sine) instead (see Section @ref(sine-sec)). @codef[snd-siosc(@pragma(defn)@index(snd-siosc)@i(tables), @i(sr), @i(hz), @i(t0), @i(fm))] @c{[sal]}@* @altdef{@code[(snd-siosc @i(tables) @i(sr) @i(hz) @i(t0) @i(fm))] @c{[lisp]}}@\A Spectral Interpolation Oscillator with frequency modulation. The @i(tables) is a list of sounds and sample counts as follows: (@i(table0) @i(count1) @i(table1) ... @i(countN) @i(tableN)). The initial waveform is given by @i(table0), which is interpolated linearly to @i(table1) over the first @i(count1) samples. From @i(count1) to @i(count2) samples, the waveform is interpolated from @i(table1) to @i(table2), and so on. If more than @i(countN) samples are generated, @i(tableN) is used for the remainder of the sound. The duration and logical stop time of the sound is taken from @i(fm), which specified frequency modulation (deviation) in Hertz. You should use @code(siosc) instead (see Section @ref(siosc-sec)). @end(fndefs) @subsection(Physical Model Functions) These functions perform some sort of physically-based modeling synthesis. @begin(fndefs) @codef[(snd-bandedwg@pragma(defn)@index(snd-bandedwg)@index(STK banded waveguide) @i(freq) @i(bowpress-env) @i(preset) @i(sr))]@* @altdef{@code[(snd-bandedwg @i(freq) @i(bowpress-env) @i(preset) @i(sr))] @c{[lisp]}}@\A Banded Wave Guide Percussion instrument implemented in STK. The parameter @i(freq) is a @code(FLONUM) in Hz, @i(bowpress-env) is a @code(SOUND) that ranges from zero to one, @i(preset) is a @code(FIXNUM), and @i(sr) is the desired sample rate in Hz. Currently, there are four presets: uniform-bar (0), tuned-bar (1), glass-harmonica (2), and tibetan-bowl (3). You should use @code(wg-uniform-bar), @code(wg-tuned-bar), @code(wg-glass-harm), or @code(wg-tibetan-bowl) instead (see Section @ref(bandedwg-sec)). @codef[snd-bowed(@pragma(defn)@index(snd-bowed)@index(stk bowed)@i(freq), @i(bowpress-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-bowed @i(freq) @i(bowpress-env) @i(sr))] @c{[lisp]}}@\A bowed string instrument implemented in STK. The freq is a @code(FLONUM) in Hertz, bowpress-env is a @code(SOUND) that ranges from z ero to one, and sr is the desired sample rate (a @code(FLONUM)). You should use bowed instead (see Section @ref(bowed-sec)). @codef[snd-bowed-freq(@pragma(defn)@index(snd-bowed-freq)@index(stk bowed)@i(freq), @i(bowpress-env), @i(freq-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-bowed-freq @i(freq) @i(bowpress-env) @i(freq-env) @i(sr))] @c{[lisp]}}@\A bowed model just like @code(snd-bowed) but with an additional parameter for continuous frequency control. You should use @code(bowed-freq) instead (see Section @ref(bowed-sec)). @codef[snd-clarinet(@pragma(defn)@index(snd-clarinet)@index(stk clarinet)@i(freq), @i(breath-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-clarinet @i(freq) @i(breath-env) @i(sr))] @c{[lisp]}}@\A clarinet model implemented in STK. The @i(freq) is a @code(FLONUM) in Hertz, @i(breath-env) is a @code(SOUND) that ranges from zero to one, and @i(sr) is the desired sample rate (a @code(FLONUM)). You should use @code(clarinet) instead (see Section @ref(clarinet-sec)). @codef[snd-clarinet-freq(@pragma(defn)@index(snd-clarinet-freq)@index(STK clarinet)@i(freq), @i(breath-env), @i(freq-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-clarinet-freq @i(freq) @i(breath-env) @i(freq-env) @i(sr))] @c{[lisp]}}@\A clarinet model just like @code(snd-clarinet) but with an additional parameter for continuous frequency control. You should use @code(clarinet-freq) instead (see Section @ref(clarinet-sec)). @codef[snd-clarinet-all(@pragma(defn)@index(snd-clarinet-all)@i(freq), @i(vibrato-freq), @i(vibrato-gain), @i(freq-env), @i(breath-env), @i(reed-stiffness), @i(noise), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-clarinet-all @i(freq) @i(vibrato-freq) @i(vibrato-gain) @i(freq-env) @i(breath-env) @i(reed-stiffness) @i(noise) @i(sr))] @c{[lisp]}}@\A clarinet model just like @code(snd-clarinet-freq) but with additional parameters for vibrato generation and continuous control of reed stiffness and breath noise. You should use @code(clarinet-all) instead (see Section @ref(clarinet-sec)). @codef[snd-flute(@pragma(defn)@index(snd-flute)@index(stk flute)@i(freq), @i(breath-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-flute @i(freq) @i(breath-env) @i(sr))] @c{[lisp]}}@\A flute implemented in STK. The @i(freq) is a @code(FLONUM) in Hertz, @i(breath-env) is a @code(SOUND) that ranges from zero to one, and @i(sr) is the desired sample rate (a @code(FLONUM)). You should use @code(flute) instead (see Section @ref(flute-sec)). @codef[snd-flute-freq(@pragma(defn)@index(snd-flute-freq)@index(stk flute)@i(freq), @i(breath-env), @i(freq-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-flute-freq @i(freq) @i(breath-env) @i(freq-env) @i(sr))] @c{[lisp]}}@\A flute model just like @code(snd-flute) but with an additional parameter for continuous frequency control. You should use @code(flute-freq) instead (see Section @ref(flute-sec)). @codef[snd-flute-all(@pragma(defn)@index(snd-flute-all)@index(stk flute)@i(freq), @i(vibrato-freq), @i(vibrato-gain), @i(freq-env), @i(breath-env), @i(jet-delay), @i(noise), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-flute-all @i(freq) @i(vibrato-freq) @i(vibrato-gain) @i(freq-env) @i(breath-env) @i(jet-delay) @i(noise) @i(sr))] @c{[lisp]}}@\A flute model just like @code(snd-flute-freq) but with additional parameters for vibrato generation and continuous control of breath noise. You should use @code(flute-all) instead (see Section @ref(flute-sec)). @codef[snd-mandolin(@pragma(defn)@index(snd-mandolin)@index(STK mandolin)@i(t0), @i(freq), @i(dur), @i(body-size), @i(detune), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-mandolin @i(t0) @i(freq) @i(dur) @i(body-size) @i(detune) @i(sr))] @c{[lisp]}}@\A plucked double-string instrument model implemented in STK. The @i(t0) parameter is the starting time (in seconds), @i(freq) is a @code(FLONUM) in Hz, @i(body-size) and @i(detune) are @code(FLONUM)s, and @code(sr) is the desired sample rate. You should use @code(mandolin) instead (see Section @ref(mandolin-sec)). @codef[snd-modalbar(@pragma(defn)@index(snd-modalbar)@index(STK modal bar)@i(t0), @i(freq), @i(preset), @i(dur), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-modalbar @i(t0) @i(freq) @i(preset) @i(dur) @i(sr))] @c{[lisp]}}@\Struck bar instrument model implemented in STK. The parameter @i(t0) is the starting time (in seconds), @i(freq) is a @code(FLONUM) in Hz, @code(preset) is a @code(FIXNUM) ranging from 0 to 8, @i(dur) is a @code(FLONUM) that sets the duration (in seconds) and @i(sr) is the desired sample rate. You should use @code(modalbar) instead (see Section @ref(modalbar-sec)). @codef[snd-sax(@pragma(defn)@index(snd-sax)@index(STK sax)@i(freq), @i(breath-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-sax @i(freq) @i(breath-env) @i(sr))] @c{[lisp]}}@\A sax model implemented in STK. The @i(freq) is a @code(FLONUM) in Hertz, @i(breath-env) is a @code(SOUND) that ranges from zero to one, and @i(sr) is the desired sample rate (a @code(FLONUM)). You should use @code(sax) instead (see Section @ref(sax-sec)). @codef[snd-sax-freq(@pragma(defn)@index(snd-sax-freq)@i(freq), @i(freq-env), @i(breath-env), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-sax-freq @i(freq) @i(freq-env) @i(breath-env) @i(sr))] @c{[lisp]}}@\A sax model just like @code(snd-sax) but with an additional parameter for continuous frequency control. You should use @code(sax-freq) instead (see Section @ref(sax-sec)). @codef[snd-sax-all(@pragma(defn)@index(snd-sax-all)@i(freq), @i(vibrato-freq), @i(vibrato-gain), @i(freq-env), @i(breath-env), @i(reed-stiffness), @i(noise), @i(blow-pos), @i(reed-table-offset), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-sax-all @i(freq) @i(vibrato-freq) @i(vibrato-gain) @i(freq-env) @i(breath-env) @i(reed-stiffness) @i(noise) @i(blow-pos) @i(reed-table-offset) @i(sr))] @c{[lisp]}}@\A sax model just like @code(snd-sax-freq) but with additional parameters for vibrato generation and continuous control of reed stiffness, breath noise, excitation position, and reed table offset. You should use @code(sax-all) instead (see Section @ref(sax-sec)). @codef[snd-sitar(@pragma(defn)@index(snd-sitar)@index(STK sitar)@i(t0), @i(freq), @i(dur), @i(sr))] @c{[sal]}@* @altdef{@code[(snd-sitar @i(t0) @i(freq) @i(dur) @i(sr))] @c{[lisp]}}@\A sitar model implemented in STK. The parameter @i(t0) is the starting time, @i(freq) is a @code(FLONUM) (in Hz), E @i(dur) sets the duration and @i(sr) is the sample rate (in Hz) of the resulting sound. You should use @code(sitar) instead (see Section @ref(sitar-sec)). @end(fndefs) @subsection(Sequence Support Functions) The next two functions are used to implement Nyquist's @code(seq) construct. @begin(fndefs) @codef[snd-seq(@pragma(defn)@index(snd-seq)@i(sound), @i(closure))] @c{[sal]}@* @altdef{@code[(snd-seq @i(sound) @i(closure))] @c{[lisp]}}@\This function returns @i(sound) until the logical stop time of @i(sound). Then, the XLISP @i(closure) is evaluated, passing it the logical stop time of @i(sound) as a parameter. The closure must return a sound, which is then added to @i(sound). (An add is used so that @i(sound) can continue past its logical stop if desired.) Do not call this function. See @code(seq) in Section @ref(seq-sec). @codef[snd-multiseq(@pragma(defn)@index(snd-multiseq)@i(array), @i(closure))] @c{[sal]}@* @altdef{@code[(snd-multiseq @i(array) @i(closure))] @c{[lisp]}}@\This function is similar to @code(snd-seq) except the first parameter is a multichannel sound rather than a single sound. A multichannel sound is simply an XLISP array of sounds. An array of sounds is returned which is the sum of @i(array) and another array of sounds returned by @i(closure). The @i(closure) is passed the logical stop time of the multichannel sound, which is the maximum logical stop time of any element of @i(array). Do not call this function. See @code(seq) in Section @ref(seq-sec). @end(fndefs) @begin(fndefs) @codef[snd-trigger(@pragma(defn)@index(snd-trigger)@i(s), @i(closure))] @c{[sal]}@* @altdef{@code[(snd-trigger @i(s) @i(closure))] @c{[lisp]}}@\This is one of the only ways in which a behavior instance can be created by changes in a signal. When @i(s) (a @code(SOUND)) makes a transition from less than or equal to zero to greater than zero, the closure, which takes a starting time parameter, is evaluated. The closure must return a @code(SOUND). The sum of all these sounds is returned. If there are no sounds, the result will be zero. The stop time of the result is the maximum stop time of @i(s) and all sounds returned by the closure. The sample rate of the return value is the sample rate of @i(s), and the sounds returned by the closure must all have that same sample rate. Do not call this function. See @code(trigger) in Section @ref(trigger-sec). An implementation note: There is no way to have @code(snd-trigger) return a multichannel sound. An alternative implementation would be a built-in function to scan ahead in a sound to find the time of the next zero crossing. This could be combined with some LISP code similar to @code(seq) to sum up instances of the closure. However, this would force arbitrary look-ahead and therefore would not work with real-time inputs, which was the motivation for @code(snd-trigger) in the first place. @end(fndefs) @chapter(Nyquist Globals) @index(Global Variables) There are many global variables in Nyquist. A convention in Lisp is to place asterisks (*) around global variables, e.g. @code(*table*). This is only a convention, and the asterisks are just like any other letter as far as variable names are concerned. Here are some globals users should know about: @begin(description, leftmargin +2 in, indent -2 in) @codef(*table*)@index(*table*)@\Default table used by @code(osc) and other oscillators. @codef(*A4-Hertz*)@pragma(defn)@index(*a4-hertz*)@\Frequency of A4 in Hertz.. Note: you must call @code[(set-pitch-names)] to recompute pitches after changing @code(*A4-Hertz*). @codef(*autonorm*)@pragma(defn)@index(*autonorm*)@\The normalization factor to be applied to the next sound when @code(*autonorm-type*) is @code('previous). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonormflag*)@pragma(defn)@index(*autonormflag*)@\Enables the automatic normalization feature of the @code(play) command. You should use @code[(autonorm-on)] and @code[(autonorm-off)] rather than setting @code(*autonormflag*) directly. See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-max-samples*)@pragma(defn)@index(*autonorm-max-samples*)@\Specifies how many samples will be computed searching for a peak value when @code(*autonorm-type*) is @code('lookahead). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-previous-peak*)@pragma(defn)@index(*autonorm-previous-peak*)@\The peak of the previous sound generated by @code(play). This is used to compute the scale factor for the next sound when @code(*autonorm-type*) is @code('previous). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-target*)@pragma(defn)@index(*autonorm-target*)@\The target peak amplitude for the autonorm feature. The default value is 0.9. See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*autonorm-type*)@pragma(defn)@index(*autonorm-type*)@\Determines how the autonorm feature is implemented. Valid values are @code('lookahead) (the default) and @code('previous). See Sections @ref(peak-ex-sec) and @ref(play-sec). @codef(*breakenable*)@pragma(defn)@index(*breakenable*)@\Controls whether XLISP enters a break loop when an error is encountered. See Section @ref(symbols-sec). @codef(*control-srate*)@pragma(defn)@index(*control-srate*)@\Part of the environment, establishes the control sample rate. See Section @ref(environment-sec) for details. @codef(*default-sf-bits*)@pragma(defn)@index(*default-sf-bits*)@\The default bits-per-sample for sound files. Typically 16. @codef(*default-sf-dir*)@pragma(defn)@index(*default-sf-dir*)@\The default sound file directory. Unless you give a full path for a file, audio files are assumed to be in this directory. (Applies to many functions that deal with sound files. Check the function description to see if @code(*default-sf-dir*) applies.) @codef(*default-sf-format*)@pragma(defn)@index(*default-sf-format*)@\The default sound file format. When you write a file, this will be the default format: AIFF for Mac and most Unix systems, NeXT for NeXT systems, and WAV for Win32. @codef(*default-sf-srate*)@pragma(defn)@index(*default-sf-srate*)@\The default sample rate for sound files. Typically 44100.0, but often set to 22050.0 for speed in non-critical tasks. @codef(*default-control-srate*)@pragma(defn)@index(*default-control-srate*)@\Default value for @code(*control-srate*). This value is restored when you execute @code[(top)] to pop out of a debugging session. Change it by calling @code[(set-control-srate @i(value))]. @codef(*default-sound-srate*)@pragma(defn)@index(*default-sound-srate*)@\Default value for @code(*sound-srate*). This value is restored when you execute @code[(top)] to pop out of a debugging session. Change it by calling @code[(set-sound-srate @i(value))]. @codef(*file-separator*)@pragma(defn)@index(*file-separator*)@\The character that separates directories in a path, e.g. ``@code(/)'' for Unix, ``@code(:)'' for Mac, and ``@code(\)'' for Win32. This is normally set in @code(system.lsp). @codef(*rslt*)@pragma(defn)@index(*rslt*)@\When a function returns more than one value, @code(*rslt*) is set to a list of the ``extra'' values. This provides a make-shift version of the @code(multiple-value-return) facility in Common Lisp. @codef(*sound-srate*)@pragma(defn)@index(*sound-srate*)@\Part of the environment, establishes the audio sample rate. See Section @ref(environment-sec) for details. @codef(*soundenable*)@pragma(defn)@index(*soundenable*)@\Controls whether writes to a sound file will also be played as audio. Set this variable by calling @code{(sound-on)} or @code{(sound-off)}. @codef(*tracenable*)@pragma(defn)@index(*tracenable*)@\Controls whether XLISP prints a backtrace when an error is encountered. @b(XLISP variables)@\See Section @ref(symbols-sec) for a list of global variables defined by XLISP. @b(Environment variables)@\See Section @ref(environment-sec) for definitions of variables used in the environment for behaviors. In general, you should never set or access these variables directly. @b(Various constants)@\See Section @ref(constants-sec) for definitions of predefined constants for loudness, duration, and pitch. @end(description) @chapter(Time/Frequency Transformation) Nyquist provides functions for FFT and inverse FFT operations on streams of audio data. Because sounds can be of any length, but an FFT operates on a fixed amount of data, FFT processing is typically done in short blocks or windows that move through the audio. Thus, a stream of samples is converted in to a sequence of FFT frames representing short-term spectra. Nyquist does not have a special data type corresponding to a sequence of FFT frames. This would be nice, but it would require creating a large set of operations suitable for processing frame sequences. Another approach, and perhaps the most ``pure'' would be to convert a single sound into a multichannel sound, with one channel per bin of the FFT. Instead, Nyquist violates its ``pure'' functional model and resorts to objects for FFT processing. A sequence of frames is represented by an XLISP object. Whenever you send the selector @code[:next] to the object, you get back either NIL, indicating the end of the sequence, or you get an array of FFT coefficients. The Nyquist function @code[snd-fft] (mnemonic, isn't it?) returns one of the frame sequence generating objects. You can pass any frame sequence generating object to another function, @code[snd-ifft], and turn the sequence back into audio. With @code[snd-fft] and @code[snd-ifft], you can create all sorts of interesting processes. The main idea is to create intermediate objects that both accept and generate sequences of frames. These objects can operate on the frames to implement the desired spectral-domain processes. Examples of this can be found in the file @code[fft_tutorial.htm]@index(fft tutorial)@index(fast fourier transform tutorial)@index(demos, fft), which is part of the standard Nyquist release. The documentation for @code[snd-fft] and @code[snd-ifft] follows. @begin(fndefs) @codef[snd-fft(@pragma(defn)@index(snd-fft)@index(fft)@i(sound), @i(length), @i(skip), @i(window))] @c{[sal]}@* @altdef{@code[(snd-fft @i(sound) @i(length) @i(skip) @i(window))] @c{[lisp]}}@\This function performs an FFT on the first samples in @i(sound) and returns a Lisp array of @code[FLONUM]s. The function modifies the @i(sound), violating the normal rule that sounds are immutable in Nyquist, so it is advised that you copy the sound using @code[snd-copy] if there are any other references to @i(sound). The length of the FFT is specified by @i(length), a @code[FIXNUM] (integer) which must be a power of 2. After each FFT, the sound is advanced by @i(skip) samples, also of type @code[FIXNUM]. Overlapping FFTs, where @i(skip) is less than @i(length), are allowed. If @i(window) is not @code[NIL], it must be a sound. The first @i(length) samples of @i(window) are multiplied by @i(length) samples of @i(sound) before performing the FFT. When there are no more samples in @i(sound) to transform, this function returns @code[NIL]. The coefficients in the returned array, in order, are the DC coefficient, the first real, the first imaginary, the second real, the second imaginary, etc. The last array element corresponds to the real coefficient at the Nyquist frequency. @codef[snd-ifft(@pragma(defn)@index(snd-ifft)@index(ifft)@index(inverse fft)@i(time), @i(srate), @i(iterator), @i(skip), @i(window))] @c{[sal]}@* @altdef{@code[(snd-ifft @i(time) @i(srate) @i(iterator) @i(skip) @i(window))] @c{[lisp]}}@\This function performs an IFFT on a sequence of spectral frames obtained from @i(iterator) and returns a sound. The start time of the sound is given by @i(time). Typically, this would be computed by calling @code[(local-to-global 0)]. The sample rate is given by @i(srate). Typically, this would be @code[*sound-srate*], but it might also depend upon the sample rate of the sound from which the spectral frames were derived. To obtain each frame, the function sends the message @code[:next] to the @i(iterator) object, using XLISP's primitives for objects and message passing. The object should return an array in the same format as obtained from @code[snd-fft], and the object should return @code[NIL] when the end of the sound is reached. After each frame is inverse transformed into the time domain, it is added to the resulting sound. Each successive frame is added with a sample offset specified by @i(skip) relative to the previous frame. This must be an integer greater than zero. If @i(window) is not @code[NIL], it must be a sound. This window signal is multiplied by the inverse transformed frame before the frame is added to the output sound. The length of each frame should be the same power of 2. The length is implied by the array returned by @i(iterator), so it does not appear as a parameter. This length is also the number of samples used from @i(window). Extra samples are ignored, and window is padded with zeros if necessary, so be sure @i(window) is the right length. The resulting sound is computed on demand as with other Nyquist sounds, so @code[:next] messages are sent to @i(iterator) only when new frames are needed. One should be careful not to reuse or modify @i(iterator) once it is passed to @code[snd-ifft]. @end(fndefs) @chapter(MIDI, Adagio, and Sequences) @label(adagio-chap) @index(MIDI)@index(Sequences) Nyquist includes facilities to read and write MIDI files as well as an ASCII text-based score representation language, Adagio. XLISP and Nyquist can be used to generate MIDI files using compositional algorithms. (See also Section @ref(xmusic-sec).) A tutorial on using the Adadio representation and MIDI can be found in @code(demos/midi_tutorial.htm)@index(demos, midi). The Adagio language is described below. Adagio was originally developed as part of the CMU MIDI Toolkit, which included a program to record and play MIDI using the Adagio representation. Some of the MIDI features of Adagio may not be useful within Nyquist. Nyquist offers a number of different score representations, and you may find this confusing. In general, MIDI files are a common way to exchange music performance data, especially with sequencers and score notation systems. The @code(demos/midi_tutorial.htm) examples show how to get the most precise control when generating MIDI data. Adagio is most useful as a text-based score entry language, and it is certainly more compact than Lisp expressions for MIDI-like data. The Xmusic library (Chapter @ref(xmusic-sec)) is best for algorithmic generation of music and score manipulation. There are functions to convert between the Adagio, MIDI sequence data, and Xmusic score representations. @pragma(doinclude) @include(adagio-nyquist.mss) @chapter(Linear Prediction Analysis and Synthesis) @index(Linear Prediction)@index(LPC) Nyquist provides functions to perform Linear Prediction Coding (LPC) analysis and synthesis. In simple terms, LPC analysis assumes that a sound is the result of an all-pole filter applied to a source with a flat spectrum. LPC is good for characterizing the general spectral shape of a signal, which may be time-varying as in speech sounds. For synthesis, any source can be filtered, allowing the general spectral shape of one signal (used in analysis) to be applied to any source (used in synthesis). A popular effect is to give vowel-like spectra to musical tones, creating an artificial (or sometimes natural) singing voice. Examples of LPC analysis and synthesis can be found in the file @code[lpc_tutorial.htm]@index(lpc tutorial)@index(linear prediction tutorial)@index(demos, lpc), which is part of the standard Nyquist release. As with FFT processing, LPC analysis takes a sound as input and returns a stream of frames. Frames are returned from an object using the @code(:next) selector just as with FFT frames. An LPC frame is a list consisting of: @i(RMS1), the energy of the input signal, @i(RMS2), the energy of the residual signal, @i(ERR), the square root of @i(RMS1)/@i(RMS2), and @i(FILTER-COEFS), an array of filter coefficients. To make code more readable and to avoid code dependence on the exact format of a frame, the functions @code(lpc-frame-rms1)@index(lpc-frame-rms1), @code(lpc-frame-rms2)@index(lpc-frame-rms2), @code(lpc-frame-err)@index(lpc-frame-err), and @code(lpc-frame-filter-coefs)@index(lpc-frame-filter-coefs) can be applied to a frame to obtain the respective fields. The @i(z) transform of the filter is @i(H)(@i(z)) = 1/@i(A)(@i(z)), where @i(A)(@i(z)) is a polynomial of the form @i(A)(@i(z)) = 1 + @i(a@-[1])@i(z) + @i(a@-[2])@i(z) + ... + @i(a@-[p])@i(z). The @i(FILTER-COEFS) array has the form @code[#(]@i(a@-[p]) @i(a@-[p-1]) ... @i(a@-[3]) @i(a@-[2]) @i(a@-[1])@code[)]. The file @code(lpc.lsp) defines some useful classes and functions. The file is @i(not) automatically loaded with Nyquist, so you must execute @code[(load "lpc")] before using them. @section(LPC Classes and Functions) @begin(fndefs) @codef[make-lpanal-iterator(@pragma(defn)@index(make-lpanal-iterator)@i(sound), @i(framedur), @i(skiptime), @i(npoles))] @c{[sal]}@* @altdef{@code[(make-lpanal-iterator @i(sound) @i(framedur) @i(skiptime) @i(npoles))] @c{[lisp]}}@\Makes an iterator object, an instance of @code(lpanal-class), that returns LPC frames from successive frames of samples in @i(sound). The duration (in seconds) of each frame is given by @i(framedur), a @code(FLONUM). The skip size (in seconds) between successive frames is given by @i(skiptime), a @code(FLONUM). Typical values for @i(framedur) and @i(skiptime) are 0.08 and 0.04, giving 25 frames per second and a 50% frame overlap. The number of poles is given by @i(npoles), a @code(FIXNUM). The result is an object that responds to the @code(:next) selector by returning a frame as described above. @code(NIL) is returned when @i(sound) terminates. (Note that one or more of the last analysis windows may be padded with zeros. @code(NIL) is only returned when the corresponding window would begin after the termination time of the sound.) @codef[make-lpc-file-iterator(@pragma(defn)@index(make-lpc-file-iterator)@i(filename))] @c{[sal]}@* @altdef{@code[(make-lpc-file-iterator @i(filename))] @c{[lisp]}}@\Another way to get LPC frames is to read them from a file. This function opens an ASCII file containing LPC frames and creates an iterator object, an instance of class @code(lpc-file-class) to access them. Create a file using @code(save-lpc-file) (see below). @codef[save-lpc-file(@pragma(defn)@index(save-lpc-file)@i(lpc-iterator), @i(filename))] @c{[sal]}@* @altdef{@code[(save-lpc-file @i(lpc-iterator) @i(filename))] @c{[lisp]}}@\Create a file containing LPC frames. This file can be read by @code[make-lpc-file-iterator] (see above). @codef{show-lpc-data(@pragma(defn)@index(show-lpc-data)@i(lpc-iterator), @i(iniframe), @i(endframe) [, @i(poles?)])} @c{[sal]}@* @altdef{@code{(show-lpc-data @i(lpc-iterator) @i(iniframe) @i(endframe) [@i(poles?)])} @c{[lisp]}}@\Print values of LPC frames from an LPC iterator object. The object is @i(lpc-iterator), which is typically an instance of @code(lpanal-class) or @code(lpc-file-class). Frames are numbered from zero, and only files starting at @i(iniframe) (a @code[FIXNUM]) and ending before @i(endframe) (also a @code[FIXNUM]) are printed. By default, only the values for @i(RMS1), @i(RMS2), and @i(ERR) are printed, but if optional parameter @i(poles?) is non-@code[NIL], then the LPC coefficients are also printed. @codef[allpoles-from-lpc(@pragma(defn)@index(allpoles-from-lpc)@i(snd), @i(lpc-frame))] @c{[sal]}@* @altdef{@code[(allpoles-from-lpc @i(snd) @i(lpc-frame))] @c{[lisp]}}@\A single LPC frame defines a filter. Use @code(allpoles-from-lpc) to apply this filter to @i(snd), a @code(SOUND). To obtain @i(lpc-frame), a @code(LIST) containing an LPC frame, either send @code(:next) to an LPC iterator, or use @code(nth-frame) (see below). The result is a @code(SOUND) whose duration is the same as that of @i(snd). @codef[lpreson(@pragma(defn)@index(lpreson)@i(snd), @i(lpc-iterator), @i(skiptime))] @c{[sal]}@* @altdef{@code[(lpreson @i(snd) @i(lpc-iterator) @i(skiptime))] @c{[lisp]}}@\Implements a time-varying all-pole filter controlled by a sequence of LPC frames from an iterator. The @code(SOUND) to be filtered is @i(snd), and the source of LPC frames is @i(lpc-iterator), typically an instance of @code(lpanal-class) or @code(lpc-file-class). The frame period (in seconds) is given by @i(skiptime) (a @code(FLONUM)). This number does not have to agree with the @i(skiptime) used to analyze the frames. (Greater values will cause the filter evolution slow down, and smaller values will cause it to speed up.) The result is a @code(SOUND). The duration of the result is the minimum of the duration of @i(snd) and that of the sequence of frames. @codef[lpc-frame-rms1(@pragma(defn)@index(lpc-frame-rms1)@i(frame))] @c{[sal]}@* @altdef{@code[(lpc-frame-rms1 @i(frame))] @c{[lisp]}}@\Get the energy of the input signal from a frame. @codef[lpc-frame-rms2(@pragma(defn)@index(lpc-frame-rms2)@i(frame))] @c{[sal]}@* @altdef{@code[(lpc-frame-rms2 @i(frame))] @c{[lisp]}}@\Get the energy of the residual from a frame. @codef[lpc-frame-err(@pragma(defn)@index(lpc-frame-err)@i(frame))] @c{[sal]}@* @altdef{@code[(lpc-frame-err @i(frame))] @c{[lisp]}}@\Get the square root of @i(RMS1)/@i(RMS2) from a frame. @codef[lpc-frame-filter-coefs(@pragma(defn)@index(lpc-frame-filter-coefs)@i(frame))] @c{[sal]}@* @altdef{@code[(lpc-frame-filter-coefs @i(frame))] @c{[lisp]}}@\Get the filter coefficients from a frame. @end(fndefs) @section(Low-level LPC Functions) The lowest-level Nyquist functions for LPC are @begin(itemize) @code(snd-lpanal) for analysis, @code(snd-allpoles), an all-pole filter with fixed coefficients, and @code(snd-lpreson), an all-pole filter that takes frames from an LPC iterator. @end(itemize) @begin(fndefs) @codef[snd-lpanal(@pragma(defn)@index(snd-lpanal)@i(samps), @i(npoles))] @c{[sal]}@* @altdef{@code[(snd-lpanal @i(samps) @i(npoles))] @c{[lisp]}}@\Compute an LPC frame with @i(npoles) (a @code(FIXNUM)) poles from an @code(ARRAY) of samples (@code(FLONUMS)). Note that @code(snd-fetch-array) can be used to fetch a sequence of frames from a sound. Ordinarily, you should not use this function. Use @code(make-lpanal-iterator) instead. @codef[snd-allpoles(@pragma(defn)@index(snd-allpoles)@i(snd), @i(lpc-coefs), @i(gain))] @c{[sal]}@* @altdef{@code[(snd-allpoles @i(snd) @i(lpc-coefs) @i(gain))] @c{[lisp]}}@\A fixed all-pole filter. The input is @i(snd), a @code(SOUND). The filter coefficients are given by @i(lpc-coefs) (an @code(ARRAY)), and the filter gain is given by @i(gain), a @code(FLONUM). The result is a @code(SOUND) whose duration matches that of @i(snd). Ordinarily, you should use @code(allpoles-from-lpc) instead (see above). @codef[snd-lpreson(@pragma(defn)@index(snd-lpreson)@i(snd), @i(lpc-iterator), @i(skiptime))] @c{[sal]}@* @altdef{@code[(snd-lpreson @i(snd) @i(lpc-iterator) @i(skiptime))] @c{[lisp]}}@\This function is identical to @code(lpreson) (see above). @end(fndefs) @chapter(Developing and Debugging in Nyquist) @index(debugging)@index(developing code) There are a number of tools, functions, and techniques that can help to debug Nyquist programs. Since these are described in many places throughout this manual, this chapter brings together many suggestions and techniques for developing code and debugging. You @i(really) should read this chapter before you spend too much time with Nyquist. Many problems that you will certainly run into are addressed here. @section(Debugging) Probably the most important debugging tool is the backtrace. There are two kinds of backtrace: one for SAL, and one for Lisp. SAL mode is actually just an XLISP function (@code(sal)) that reads input and evaluates it. When SAL encounters an error, it normally prints a trace of the SAL stack (all the active functions written in SAL), exists the current command, and reads the next command. If you call XLISP functions from SAL, including most Nyquist sound processing functions, and an error occurs within these XLISP functions, you will only see the SAL function that called the XLISP functions listed in the stack trace. Sometimes you need more details. When Nyquist encounters an error when it is not running SAL, it normally suspends execution and prints an error message. To find out where in the program the error occurred and how you got there, start by typing @code[(bt)]. This will print out the last several function calls and their arguments, which is usually sufficient to see what is going on. In order for @code[(bt)] to work, you must have a couple of global variables set: @code(*tracenable*) is ordinarily set to @code(NIL). If it is true, then a backtrace is automatically printed when an error occurs; @code(*breakenable*) must be set to @code(T), as it enables the execution to be suspended when an error is encountered. If @code(*breakenable*) is @code(NIL) (false), then execution stops when an error occurs but the stack is not saved and you cannot get a backtrace. Finally, @code(bt) is just a macro to save typing. The actual backtrace function is @code(baktrace), which takes an integer argument telling how many levels to print. All of these things are set up by default when you start Nyquist. To get this XLISP backtrace behavior when SAL encounters an error, you need to have @code(*breakenable*) set while SAL is running. The best way to do this is to run within the NyquistIDE program, open the Preferences dialog, and choose the desired settings, e.g. ``Enable XLISP break on SAL error.'' Since Nyquist sounds are executed with a lazy evaluation scheme, some errors are encountered when samples are being generated. In this case, it may not be clear which expression is in error. Sometimes, it is best to explore a function or set of functions by examining intermediate results. Any expression that yields a sound can be assigned to a variable and examined using one or more of: @code(s-plot), @code(snd-print-tree), and of course @code(play). The @code(snd-print-tree) function prints a lot of detail about the inner representaion of the sound. Keep in mind that if you assign a sound to a global variable and then look at the samples (e.g. with @code(play) or @code(s-plot)), the samples will be retained in memory. At 4 bytes per sample, a big sound may use all of your memory and cause a crash. Another technique is to use low sample rates so that it is easier to plot results or look at samples directly. The calls: @begin(example) set-sound-srate(100) set-control-srate(100) @end(example) set the default sample rates to 100, which is too slow for audio, but useful for examining programs and results. The function @begin(example) snd-samples(@i(sound), @i(limit)) @end(example) will convert up to @i(limit) samples from @i(sound) into a Lisp array. This is another way to look at results in detail. The @code(trace) function is sometimes useful. It prints the name of a function and its arguments everytimg the function is called, and the result is printed when the function exits. To trace the osc function, type: @begin(example) trace(osc) @end(example) and to stop tracing, type @code[untrace(osc)]. If a variable needs a value or a function is undefined, and if @code(*breakenable*) was set, you will get a prompt where you can fix the error (by setting the variable or loading the function definition) and keep going. At the debug (or break) prompt, your input must be in XLISP, not SAL syntax. Use @code[(co)], short for @code[(continue)] to reevaluate the variable or function and continue execution. When you finish debugging a particular call, you can ``pop'' up to the top level by typing @code[(top)], a short name for @code[(top-level)]. There is a button named "Top" in the NyquistIDE that takes you back to the top level (ready to accept XLISP expressions), and another button named "SAL" that puts you back in SAL mode. @section(Useful Functions) @begin(fndefs) @codef[grindef(@pragma(defn)@index(grindef)@index(listing of lisp function)@i(name))] @c{[sal]}@* @altdef{@code[(grindef @i(name))] @c{[lisp]}}@\Prints a formatted listing of a lisp function. This is often useful to quickly inspect a function without searching for it in source files. Do not forget to quote the name, e.g. @code[(grindef 'prod)]. @codef[args(@pragma(defn)@index(args)@index(arguments to a lisp function)@i(name))] @c{[sal]}@* @altdef{@code[(args @i(name))] @c{[lisp]}}@\Similar to @code(grindef), this function prints the arguments to a function. This may be faster than looking up a function in the documentation if you just need a reminder. For example, @code[(args 'lp)] prints ``(LP S C),'' which may help you to remember that the arguments are a sound (S) followed by the cutoff (C) frequency. @end(fndefs) The following functions are useful short-cuts that might have been included in XLISP. They are so useful that they are defined as part of Nyquist. @begin(fndefs) @codef[incf(@pragma(defn)@index(incf)@index(increment)@i(symbol))] @c{[sal]}@* @altdef{@code[(incf @i(symbol))] @c{[lisp]}}@\Increment @i(symbol) by one. This is a macro, and @i(symbol) can be anything that can be set by @code(setf). Typically, @i(symbol) is a variable: ``@code[(incf i)],'' but @i(symbol) can also be an array element: ``@code[(incf (aref myarray i))].'' @codef[decf(@pragma(defn)@index(decf)@index(decrement)@i(symbol))] @c{[sal]}@* @altdef{@code[(decf @i(symbol))] @c{[lisp]}}@\Decrement @i(symbol) by one. (See @code(incf), above.) @codef[push(@pragma(defn)@index(push)@i(val), @i(lis))] @c{[sal]}@* @altdef{@code[(push @i(val) @i(lis))] @c{[lisp]}}@\Push @i(val) onto @i(lis) (a Lisp list). This is a macro that is equivalent to writing (in Lisp) @code[(setf @i(lis) (cons @i(val) @i(lis)))]. @codef[pop(@pragma(defn)@index(pop)@i(lis))] @c{[sal]}@* @altdef{@code[(pop @i(lis))] @c{[lisp]}}@\Remove (pop) the first item from @i(lis) (a Lisp list). This is a macro that is equivalent to writing (in Lisp) @code[(setf @i(lis) (cdr @i(lis)))]. Note that the remaining list is returned, not the head of the list that has been popped. Retrieve the head of the list (i.e. the top of the stack) using @code(first) or, equivalently, @code(car). @end(fndefs) The following macros are useful control constructs. @begin(fndefs) @codef[while(@pragma(defn)@index(while)@i(test), @i(expr1), @i(expr2), @r(...))] @c{[sal]}@* @altdef{@code[(while @i(test) @i(expr1) @i(expr2) @r(...))] @c{[lisp]}}@\A conventional ``while'' loop. If @i(test) is true, evaluate expressions (@i(expr1), @i(expr2), etc.) and repeat. If @i(test) is false, return. This expression evaluates to NIL unless the expression @code[(return @i(expr))] is evaluated, in which case the value of @i(expr) is returned. In SAL, the loop statement is preferred. @codef[when(@pragma(defn)@index(when)@i(test), @i(action))] @c{[sal]}@* @altdef{@code[(when @i(test) @i(action))] @c{[lisp]}}@\A conventional ``if-then'' statement. If @i(test) is true, @i(action) is evaluated and returned. Otherwise, NIL is returned. (Use @code(if) or @code(cond) to implement ``if-then-else'' and more complex conditional forms. @end(fndefs) It is often necessary to load a file @i(only if) it has not already been loaded. For example, the @code(pianosyn) library loads very slowly, so if some other file already loaded it, it would be good to avoid loading it again. How can you load a file once? Nyquist does not keep track of files that are loaded, but you must be loading a file to define some function, so the idea is to tell Nyquist "I require @i(function) from @i(file)"; if the function does not yet exist, Nyquist satisfies the requirement by loading the file. @begin(fndefs) @codef{require-from(@pragma(defn)@index(require-from)@index(load file conditionally)@i(fnsymbol), @i(filename) [, @i(path)])} @c{[sal]}@* @altdef{@code{(require-from @i(fnsymbol) @i(filename) [@i(path)])} @c{[lisp]}}@\Tests whether @i(fnsymbol), an unquoted function name, is defined. If not, @i(filename), a @code(STRING), is loaded. Normally @i(fnsymbol) is a function that will be called from within the current file, and @i(filename) is the file that defines @i(fnsymbol). The @i(path), if a @code(STRING), is prepended to @i(filename). If @i(path) is @code(t) (true), then the directory of the current file is used as the path. @end(fndefs) Sometimes it is important to load files relative to the current file. For example, the @code(lib/piano.lsp) library loads data files from the @code(lib/piano) directory, but how can we find out the full path of @code(lib)? The solution is: @begin(fndefs) @codef[current-path(@pragma(defn)@index(current-path)@index(path, current)@index(full path name))] @c{[sal]}@* @altdef{@code[(current-path)] @c{[lisp]}}@\Returns the full path name of the file that is currently being loaded (see @code(load)). Returns NIL if no file is being loaded. @end(fndefs) Finally, there are some helpful math functions: @begin(fndefs) @codef[real-random(@index(random)@index(uniform random)@pragma(defn)@index(real-random)@i(from), @i(to))] @c{[sal]}@* @altdef{@code[(real-random @i(from) @i(to))] @c{[lisp]}}@\Returns a random @code(FLONUM) between @i(from) and @i(to). (See also @code(rrandom), which is equivalent to @code((real-random 0 1))). @codef[power(@pragma(defn)@index(power)@index(exponent)@i(x), @i(y))] @c{[sal]}@* @altdef{@code[(power @i(x) @i(y))] @c{[lisp]}}@\Returns @i(x) raised to the @i(y) power. @end(fndefs) @chapter(Xmusic and Algorithmic Composition) @label(xmusic-sec) @index(Xmusic)@index(Algorithmic Composition) Several Nyquist libraries offer support for algorithmic composition. Xmusic is a library for generating sequences and patterns of data. Included in Xmusic is the @code(score-gen) macro which helps to generate scores from patterns. Another important facility is the @code(distributions.lsp) library, containing many different random number generators. @section(Xmusic Basics) Xmusic is inspired by and based on Common Music by Rick Taube. Currently, Xmusic only implements patterns and some simple support for scores to be realized as sound by Nyquist. In contrast, Common Music supports MIDI and various other synthesis languages and includes a graphical interface, some visualization tools, and many other features. Common Music runs in Common Lisp and Scheme, but not XLISP, which is the base language for Nyquist. Xmusic patterns are objects that generate data streams. For example, the @code(cycle-class) of objects generate cyclical patterns such as "1 2 3 1 2 3 1 2 3 ...", or "1 2 3 4 3 2 1 2 3 4 ...". Patterns can be used to specify pitch sequences, rhythm, loudness, and other parameters. Xmusic functions are automatically loaded when you start Nyquist. To use a pattern object, you first create the pattern, e.g. @begin(example) set pitch-source = make-cycle(list(c4, d4, e4, f4)) @end(example) After creating the pattern, you can access it repeatedly with @code(next)@index(next in pattern) to generate data, e.g. @begin(example) play seqrep(i, 13, pluck(next(pitch-source), 0.2)) @end(example) This will create a sequence of notes with the following pitches: c, d, e, f, c, d, e, f, c, d, e, f, c. If you evaluate this again, the pitch sequence will continue, starting on "d". It is very important not to confuse the creation of a sequence with its access. Consider this example: @begin(example) play seqrep(i, 13, pluck(next(make-cycle(list(c4, d4, e4, f4))), 0.2)) @end(example) This looks very much like the previous example, but it only repeats notes on middle-C. The reason is that every time @code(pluck) is evaluated, @code(make-cycle) is called and creates a new pattern object. After the first item of the pattern is extracted with @code(next), the cycle is not used again, and no other items are generated. To summarize this important point, there are two steps to using a pattern. First, the pattern is created and stored in a variable using @code(setf). Second, the pattern is accessed (multiple times) using @code(next). Patterns can be nested, that is, you can write patterns of patterns. In general, the @code(next) function does not return patterns. Instead, if the next item in a pattern is a (nested) pattern, @code(next) recursively gets the next item of the nested pattern. While you might expect that each call to @code(next) would advance the top-level pattern to the next item, and descend recursively if necessary to the inner-most nesting level, this is not how @code(next) works. Instead, @code(next) remembers the last top-level item, and if it was a pattern, @code(next) continues to generate items from that same inner pattern until the end of the inner pattern's @i(period) is reached. The next paragraph explains the concept of the @i(period). The data returned by a pattern object is structured into logical groups called @i(periods). You can get an entire period (as a list) by calling @code[next(@i(pattern), t)]@index(next pattern). For example: @begin(example) set pitch-source = make-cycle(list(c4, d4, e4, f4)) print next(pitch-source, t) @end(example) This prints the list @code[(60 62 64 65)], which is one period of the cycle. You can also get explicit markers that delineate periods by calling @code[send(@i(pattern), :next)]. In this case, the value returned is either the next item of the pattern, or the symbol @code(+eop+) if the end of a period has been reached. What determines a period? This is up to the specific pattern class, so see the documentation for specifics. You can override the ``natural'' period using the keyword @code(for:), e.g. @begin(example) set pitch-source = make-cycle(list(c4, d4, e4, f4), for: 3) print next(pitch-source, t) print next(pitch-source, t) @end(example) This prints the lists @code[(60 62 64) (65 60 62)]. Notice that these periods just restructure the stream of items into groups of 3. Nested patterns are probably easier to understand by example than by specification. Here is a simple nested pattern of cycles: @begin(example) set cycle-1 = make-cycle({a b c}) set cycle-2 = make-cycle({x y z}) set cycle-3 = make-cycle(list(cycle-1, cycle-2)) exec dotimes(i, 9, format(t, "~A ", next(cycle-3))) @end(example) This will print "A B C X Y Z A B C". Notice that the inner-most cycles @code(cycle-1) and @code(cycle-2) generate a period of items before the top-level @code(cycle-3) advances to the next pattern. Before describing specific pattern classes, there are several optional parameters that apply in the creating of any pattern object. These are: @begin(description, leftmargin +2 in, indent -2 in) @code(for:)@\The length of a period. This overrides the default by providing a numerical length. The value of this optional parameter may be a pattern that generates a sequence of integers that determine the length of each successive period. A period length may not be negative, but it may be zero. @code(name:)@\A pattern object may be given a name. This is useful if the @code(trace:) option is used. @code(trace:)@\If non-null, this optional parameter causes information about the pattern to be printed each time an item is generated from the pattern. @end(description) The built-in pattern classes are described in the following section. @section(Pattern Classes) @subsection(cycle) The @code(cycle-class) iterates repeatedly through a list of items. For example, two periods of @code[make-cycle({a b c})] would be @code[(A B C) (A B C)]. @begin(fndefs) @codef{make-cycle(@pragma(defn)@index(make-cycle)@index(cycle pattern)@index(pattern, cycle)@i(items), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-cycle @i(items) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Make a cycle pattern that iterates over @i(items). The default period length is the length of @i(items). (See above for a description of the optional parameters.) If @i(items) is a pattern, a period of the pattern becomes the list from which items are generated. The list is replaced every period of the cycle. @end(fndefs) @subsection(line) The @code(line-class) is similar to the cycle class, but when it reaches the end of the list of items, it simply repeats the last item in the list. For example, two periods of @code[make-line({a b c})] would be @code[(A B C) (C C C)]. @begin(fndefs) @codef{make-line(@pragma(defn)@index(make-line)@index(line pattern)@index(pattern, line)@i(items), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-line @i(items) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Make a line pattern that iterates over @i(items). The default period length is the length of @i(items). As with @code(make-cycle), @i(items) may be a pattern. (See above for a description of the optional parameters.) @end(fndefs) @subsection(random) The @code(random-class) generates items at random from a list. The default selection is uniform random with replacement, but items may be further specified with a weight, a minimum repetition count, and a maximum repetition count. Weights give the relative probability of the selection of the item (with a default weight of one). The minimum count specifies how many times an item, once selected at random, will be repeated. The maximum count specifies the maximum number of times an item can be selected in a row. If an item has been generated @i(n) times in succession, and the maximum is equal to @i(n), then the item is disqualified in the next random selection. Weights (but not currently minima and maxima) can be patterns. The patterns (thus the weights) are recomputed every period. @begin(fndefs) @codef{make-random(@pragma(defn)@index(make-random)@index(random pattern)@index(pattern, random)@i(items), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-random @i(items) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Make a random pattern that selects from @i(items). Any (or all) element(s) of @i(items) may be lists of the following form: @code{(@i(value) :weight @i(weight) :min @i(mincount) :max @i(maxcount))}, where @i(value) is the item (or pattern) to be generated, @i(weight) is the (optional) relative probability of selecting this item, @i(mincount) is the (optional) minimum number of repetitions when this item is selected, and @i(maxcount) is the (optional) maximum number of repetitions allowed before selecting some other item. The default period length is the length of @i(items). If @i(items) is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. @end(fndefs) @subsection(palindrome) The @code(palindrome-class) repeatedly traverses a list forwards and then backwards. For example, two periods of @code[make-palindrome({a b c})] would be @code[(A B C C B A) (A B C C B A)]. The @code(elide:) keyword parameter controls whether the first and/or last elements are repeated: @begin(example) make-palindrome({a b c}, elide: nil) ;; generates A B C C B A A B C C B A ... make-palindrome({a b c}, elide: t) ;; generates A B C B A B C B ... make-palindrome({a b c}, elide: :first) ;; generates A B C C B A B C C B ... make-palindrome({a b c}, elide: :last) ;; generates A B C B A A B C B A ... @end(example) @begin(fndefs) @codef{make-palindrome(@pragma(defn)@index(make-palindrome)@index(palindrome pattern)@index(pattern, palindrome)@i(items), elide: @i(elide), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-palindrome @i(items) :elide @i(elide) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Generate items from list alternating in-order and reverse-order sequencing. The keyword parameter @i(elide) can have the values @code(:first), @code(:last), @code(t), or @code(nil) to control repetition of the first and last elements. The @i(elide) parameter can also be a pattern, in which case it is evaluated every period. One period is one complete forward and backward traversal of the list. If @i(items) is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. @end(fndefs) @subsection(heap) The @code(heap-class) selects items in random order from a list without replacement, which means that all items are generated once before any item is repeated. For example, two periods of @code[make-heap({a b c})] might be @code[(C A B) (B A C)]. Normally, repetitions can occur even if all list elements are distinct. This happens when the last element of a period is chosen first in the next period. To avoid repetitions, the @code(max:) keyword argument can be set to 1. The @code(max:) keyword only controls repetitions from the end of one period to the beginning of the next. If the list contains more than one copy of the same value, it may be repeated within a period regardless of the value of @code(max:). @begin(fndefs) @codef{make-heap(@pragma(defn)@index(make-heap)@index(heap pattern)@index(pattern, heap)@i(items), for: @i(for), max: @i(max), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-heap @i(items) :for @i(for) :max @i(max) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Generate items randomly from list without replacement. If @i(max) is 1, the first element of a new period will not be the same as the last element of the previous period, avoiding repetition. The default value of @i(max) is 2, meaning repetition is allowed. The period length is the length of @i(items). If @i(items) is a pattern, a period from that pattern becomes the list from which random selections are made, and a new list is generated every period. @end(fndefs) @subsection(accumulation) The @code(accumulation-class) takes a list of values and returns the first, followed by the first two, followed by the first three, etc. In other words, for each list item, return all items from the first through the item. For example, if the list is (A B C), each generated period is (A A B A B C). @begin(fndefs) @codef{make-accumulation(@pragma(defn)@index(make-accumulation)@index(accumulation pattern)@index(pattern, accumulation)@i(items), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-accumulation @i(items) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\For each item, generate items from the first to the item including the item. The period length is (@i(n)@+(2) + @i(n)) / 2 where @i(n) is the length of @i(items). If @i(items) is a pattern, a period from that pattern becomes the list from which items are generated, and a new list is generated every period. Note that this is similar in name but different from @code(make-accumulate). @subsection(copier) The @code(copier-class) makes copies of periods from a sub-pattern. For example, three periods of @code[make-copier(make-cycle({a b c}, for: 1), repeat: 2, merge: t)] would be @code[(A A) (B B) (C C)]. Note that entire periods (not individual items) are repeated, so in this example the @code(for:) keyword was used to force periods to be of length one so that each item is repeated by the @code(repeat:) count. @codef{make-copier(@pragma(defn)@index(make-copier)@index(copier pattern)@index(pattern, copier)@i(sub-pattern), repeat: @i(repeat), merge: @i(merge), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-copier @i(sub-pattern) :repeat @i(repeat) :merge @i(merge) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Generate a period from @i(sub-pattern) and repeat it @i(repeat) times. If @i(merge) is false (the default), each repetition of a period from @i(sub-pattern) results in a period by default. If @i(merge) is true (non-null), then all @i(repeat) repetitions of the period are merged into one result period by default. If the @code(for:) keyword is used, the same items are generated, but the items are grouped into periods determined by the @code(for:) parameter. If the @code(for:) parameter is a pattern, it is evaluated every result period. The @i(repeat) and @i(merge) values may be patterns that return a repeat count and a boolean value, respectively. If so, these patterns are evaluated initially and after each @i(repeat) copies are made (independent of the @code(for:) keyword parameter, if any). The @i(repeat) value returned by a pattern can also be negative. A negative number indicates how many periods of @i(sub-pattern) to skip. After skipping these patterns, new @i(repeat) and @i(merge) values are generated. @end(fndefs) @subsection(accumulate) The @code(accumulate-class) forms the sum of numbers returned by another pattern. For example, each period of @code[make-accumulate(make-cycle({1 2 -3}))] is @code[(1 3 0)]. The default output period length is the length of the input period. @begin(fndefs) @codef{make-accumulate(@pragma(defn)@index(make-accumulate)@index(accumulate pattern)@index(pattern, accumulate)@i(sub-pattern), for: @i(for), max: @i(maximum), min: @i(minimum), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-accumulate @i(sub-pattern) :for @i(for) :max @i(maximum) :min @i(minimum) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Keep a running sum of numbers generated by @i(sub-pattern). The default period lengths match the period lengths from @i(sub-pattern). If @i(maximum) (a pattern or a number) is specified, and the running sum exceeds @i(maximum), the running sum is reset to @i(maximum). If @i(minimum) (a pattern or a number) is specified, and the running sum falls below @i(minimum), the running sum is reset to @i(minimum). If @i(minimum) is greater than @i(maximum), the running sum will be set to one of the two values. Note that this is similar in name but not in function to @code(make-accumulation). @end(fndefs) @subsection(sum) The @code(sum-class) forms the sum of numbers, one from each of two other patterns. For example, each period of @code[make-sum(make-cycle({1 2 3}), make-cycle({4 5 6}))] is @code[(5 7 9)]. The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number. @begin(fndefs) @codef{make-sum(@pragma(defn)@index(make-sum)@index(sum pattern)@index(pattern, sum)@i(x), @i(y), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-sum @i(x) @i(y) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Form sums of items (which must be numbers) from pattern @i(x) and pattern or number @i(y). The default period lengths match the period lengths from @i(x). @end(fndefs) @subsection(product) The @code(product-class) forms the product of numbers, one from each of two other patterns. For example, each period of @code[make-product(make-cycle({1 2 3}), make-cycle({4 5 6}))] is @code[(4 10 18)]. The default output period length is the length of the input period of the first argument. Therefore, the first argument must be a pattern, but the second argument can be a pattern or a number. @begin(fndefs) @codef{make-product(@pragma(defn)@index(make-product)@index(product pattern)@index(pattern, product)@i(x), @i(y), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-product @i(x) @i(y) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Form products of items (which must be numbers) from pattern @i(x) and pattern or number @i(y). The default period lengths match the period lengths from @i(x). @end(fndefs) @subsection(eval) The @code(eval-class) evaluates an expression to produce each output item. The default output period length is 1. @begin(fndefs) @codef{make-eval(@pragma(defn)@index(make-eval)@index(eval pattern)@index(pattern, eval)@index(expression pattern)@index(pattern, expression)@i(expr), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-eval @i(expr) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Evaluate @i(expr) to generate each item. If @i(expr) is a pattern, each item is generated by getting the next item from @i(expr) and evaluating it. @end(fndefs) @subsection(length) The @code(length-class) generates periods of a specified length from another pattern. This is similar to using the @code(for:) keyword, but for many patterns, the @code(for:) parameter alters the points at which other patterns are generated. For example, if the palindrome pattern has an @code(elide:) pattern parameter, the value will be computed every period. If there is also a @code(for:) parameter with a value of 2, then @code(elide:) will be recomputed every 2 items. In contrast, if the palindrome (without a @code(for:) parameter) is embedded in a @i(length) pattern with a lenght of 2, then the periods will all be of length 2, but the items will come from default periods of the palindrome, and therefore the @code(elide:) values will be recomputed at the beginnings of default palindrome periods. @begin(fndefs) @codef{make-length(@index(length pattern)@index(pattern, length)@pragma(defn)@index(make-length)@i(pattern), @i(length-pattern), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-length @i(pattern) @i(length-pattern) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Make a pattern of class @code(length-class) that regroups items generated by a @i(pattern) according to pattern lengths given by @i(length-pattern). Note that @i(length-pattern) is not optional: There is no default pattern length and no @code(for:) keyword. @end(fndefs) @subsection(window) The @code(window-class) groups items from another pattern by using a sliding window. If the @i(skip) value is 1, each output period is formed by dropping the first item of the previous perioda and appending the next item from the pattern. The @i(skip) value and the output period length can change every period. For a simple example, if the period length is 3 and the skip value is 1, and the input pattern generates the sequence A, B, C, ..., then the output periods will be (A B C), (B C D), (C D E), (D E F), .... @begin(fndefs) @codef{make-window(@index(window pattern)@index(pattern, window)@pragma(defn)@index(make-window)@i(pattern), @i(length-pattern), @i(skip-pattern), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-window @i(pattern) @i(length-pattern) @i(skip-pattern) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Make a pattern of class @code(window-class) that regroups items generated by a @i(pattern) according to pattern lengths given by @i(length-pattern) and where the period advances by the number of items given by @i(skip-pattern). Note that @i(length-pattern) is not optional: There is no default pattern length and no @code(for:) keyword. @end(fndefs) @subsection(markov) The @code(markov-class) generates items from a Markov model. A Markov model generates a sequence of @i(states) according to rules which specify possible future states given the most recent states in the past. For example, states might be pitches, and each pitch might lead to a choice of pitches for the next state. In the @code(markov-class), states can be either symbols or numbers, but not arbitrary values or patterns. This makes it easier to specify rules. However, symbols can be mapped to arbitrary values including pattern objects, and these become the actual generated items. By default, all future states are weighted equally, but weights may be associated with future states. A Markov model must be initialized with a sequence of past states using the @code(past:) keyword. The most common form of Markov model is a "first order Markov model" in which the future item depends only upon one past item. However, higher order models where the future items depend on two or more past items are possible. A "zero-order" Markov model, which depends on no past states, is essentially equivalent to the random pattern. As an example of a first-order Markov pattern, two periods of @code[make-markov({{a -> b c} {b -> c} {c -> a}}, past: {a})] might be @code[(C A C) (A B C)]. @begin(fndefs) @codef{make-markov(@pragma(defn)@index(make-markov)@index(markov pattern)@index(pattern, markov)@i(rules), past: @i(past), produces: @i(produces), for: @i(for), name: @i(name), trace: @i(trace))} @c{[sal]}@* @altdef{@code{(make-markov @i(rules) @i(past) :produces @i(produces) :for @i(for) :name @i(name) :trace @i(trace))} @c{[lisp]}}@\Generate a sequence of items from a Markov process. The @i(rules) parameter has the form: @code[(@i(prev1) @i(prev2) ... @i(prevn) -> @i(next1) @i(next2) ... @i(nextn))] where @i(prev1) through @i(prevn) represent a sequence of most recent (past) states. The symbol @code(*) is treated specially: it matches any previous state. If @i(prev1) through @i(prevn) (which may be just one state as in the example above) match the previously generated states, this rule applies. Note that every rule must specify the same number of previous states; this number is known as the order of the Markov model. The first rule in @i(rules) that applies is used to select the next state. If no rule applies, the next state is @code(NIL) (which is a valid state that can be used in rules). Assuming a rule applies, the list of possible next states is specified by @i(next1) through @i(nextn). Notice that these are alternative choices for the next state, not a sequence of future states, and each rule can have any number of choices. Each choice may be the state itself (a symbol or a number), or the choice may be a list consisting of the state and a weight. The weight may be given by a pattern, in which case the next item of the pattern is obtained every time the rule is applied. For example, this rules says that if the previous states were A and B, the next state can be A with a weight of 0.5 or C with an implied weight of 1: @code[(A B -> (A 0.5) C)]. The default length of the period is the length of @i(rules). The @i(past) parameter must be provided. It is a list of states whose length matches the order of the Markov model. The keyword parameter @i(produces) may be used to map from state symbols or numbers to other values or patterns. The parameter is a list of alternating symbols and values. For example, to map A to 69 and B to 71, use @code[list(quote(a), 69, quote(b), 71)]. You can also map symbols to patterns, for example @code[list(quote(a), make-cycle({57 69}), quote(b), make-random({59 71}))]. The next item of the pattern is is generated each time the Markov model generates the corresponding state. Finally, the @i(produces) keyword can be @code(eval:), which means to evaluate the Markov model state. This could be useful if states are Nyquist global variables such as @code(C4, CS4, D4, ]..., which evaluate to numerical values (60, 61, 62, ...). @codef{markov-create-rules(@pragma(defn)@index(markov-create-rules)@index(markov analysis)@i(sequence), @i(order) [, @i(generalize)])} @c{[sal]}@* @altdef{@code{(markov-create-rules @i(sequence) @i(order) [@i(generalize)])} @c{[lisp]}}@\Generate a set of rules suitable for the @code(make-markov) function. The @i(sequence) is a ``typical'' sequence of states, and @i(order) is the order of the Markov model. It is often the case that a sample sequence will not have a transition from the last state to any other state, so the generated Markov model can reach a ``dead end'' where no rule applies. This might lead to an infinite stream of NIL's. To avoid this, the optional parameter @i(generalize) can be set to @code(t) (true), indicating that there should be a fallback rule that matches any previous states and whose future states are weighted according to their frequency in @i(sequence). For example, if sequence contains 5 A's, 5 B's and 10 G's, the default rule will be @code[(* -> (A 5) (B 5) (G 10))]. This rule will be appended to the end so it will only apply if no other rule does. @end(fndefs) @section(Random Number Generators) @index(random)@index(probability distributions)@index(distributions, probability)@index(stochastic functions) The @code(distributions.lsp) library implements random number generators that return random values with various probability distributions. Without this library, you can generate random numbers with @i(uniform) distributions. In a uniform distribution, all values are equally likely. To generate a random integer in some range, use @code(random). To generate a real number (FLONUM) in some range, use @code(real-random) (or @code(rrandom) if the range is 0-1). But there are other interesting distributions. For example, the Gaussian distribution is often used to model real-world errors and fluctuations where values are clustered around some central value and large deviations are more unlikely than small ones. See Dennis Lorrain, "A Panoply of Stochastic 'Canons'," @i(Computer Music Journal) vol. 4, no. 1, 1980, pp. 53-81. In most of the random number generators described below, there are optional parameters to indicate a maximum and/or minimum value. These can be used to truncate the distribution. For example, if you basically want a Gaussian distribution, but you never want a value greater than 5, you can specify 5 as the maximum value. The upper and lower bounds are implemented simply by drawing a random number from the full distribution repeatedly until a number falling into the desired range is obtained. Therefore, if you select an acceptable range that is unlikely, it may take Nyquist a long time to find each acceptable random number. The intended use of the upper and lower bounds is to weed out values that are already fairly unlikely. @begin(fndefs) @codef[linear-dist(@pragma(defn)@index(linear-dist)@index(linear distribution)@i(g))] @c{[sal]}@* @altdef{@code[(linear-dist @i(g))] @c{[lisp]}}@\Return a @code(FLONUM) value from a linear distribution, where the probability of a value decreases linearly from zero to @i(g) which must be greater than zero. (See Figure @ref(linear-fig).) The linear distribution is useful for generating for generating time and pitch intervals. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "linear-fig.ps")) @html(

    ) @fillcaption(The Linear Distribution, @i(g) = 1.) @tag(linear-fig) @end(figure) @begin(fndefs) @codef{exponential-dist(@pragma(defn)@index(exponential-dist)@index(exponential distribution)@i(delta) [, @i(high)])} @c{[sal]}@* @altdef{@code{(exponential-dist @i(delta) [@i(high)])} @c{[lisp]}}@\Return a @code(FLONUM) value from an exponential distribution. The initial downward slope is steeper with larger values of @i(delta), which must be greater than zero. (See Figure @ref(exponential-fig). The optional @i(high) parameter puts an artificial upper bound on the return value. The exponential distribution generates values greater than 0, and can be used to generate time intervals. Natural random intervals such as the time intervals between the release of atomic particles or the passing of yellow volkswagons in traffic have exponential distributions. The exponential distribution is memory-less: knowing that a random number from this distribution is greater than some value (e.g. a note duration is at least 1 second) tells you nothing new about how soon the note will end. This is a continuous distribution, but @code(geometric-dist) (described below) implements the discrete form. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "exponential-fig.ps")) @html(

    ) @fillcaption(The Exponential Distribution, @i(delta) = 1.) @tag(exponential-fig) @end(figure) @begin(fndefs) @codef{gamma-dist(@pragma(defn)@index(gamma-dist)@i(nu) [, @i(high)])} @c{[sal]}@* @altdef{@code{(gamma-dist @i(nu) [@i(high)])} @c{[lisp]}}@\Return a @code(FLONUM) value from a Gamma distribution. The value is greater than zero, has a mean of @i(nu) (a @code(FIXNUM) greater than zero), and a mode (peak) of around @i(nu) - 1. The optional @i(high) parameter puts an artificial upper bound on the return value. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "gamma-fig.ps")) @html(

    ) @fillcaption(The Gamma Distribution, @i(nu) = 4.) @tag(gamma-fig) @end(figure) @begin(fndefs) @codef{bilateral-exponential-dist(@pragma(defn)@index(bilateral-exponential-dist)@index(bilateral exponential distribution)@i(xmu), @i(tau) [, @i(low), @i(high)])} @c{[sal]}@* @altdef{@code{(bilateral-exponential-dist @i(xmu) @i(tau) [@i(low) @i(high)])} @c{[lisp]}}@\Returns a @code(FLONUM) value from a bilateral exponential distribution, where @i(xmu) is the center of the double exponential and @i(tau) controls the spread of the distribution. A larger @i(tau) gives a wider distribution (greater variance), and @i(tau) must be greater than zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. This distribution is similar to the exponential, except it is centered at 0 and can output negative values as well. Like the exponential, it can be used to generate time intervals; however, it might be necessary to add a lower bound so as not to compute a negative time interval. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "bilateral-fig.ps")) @html(

    ) @fillcaption(The Bilateral Exponential Distribution.) @tag(bilateral-fig) @end(figure) @begin(fndefs) @codef{cauchy-dist(@pragma(defn)@index(cauchy-dist)@index(cauchy distribution)@i(tau) [, @i(low), @i(high)])} @c{[sal]}@* @altdef{@code{(cauchy-dist @i(tau) [@i(low) @i(high)])} @c{[lisp]}}@\Returns a @code(FLONUM) from the Cauchy distribution, a symetric distribution with a high peak at zero and a width (variance) that increases with parameter @i(tau), which must be greater than zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "cauchy-fig.ps")) @html(

    ) @fillcaption(The Cauchy Distribution, @i(tau) = 1.) @tag(cauchy-fig) @end(figure) @begin(fndefs) @codef{hyperbolic-cosine-dist(@pragma(defn)@index(hyperbolic-cosine-dist)[@i(low), @i(high)])} @c{[sal]}@* @altdef{@code[(hyperbolic-cosine-dist [@i(low) @i(high)])] @c{[lisp]}}@\Returns a @code(FLONUM) value from the hyperbolic cosine distribution, a symetric distribution with its peak at zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "hyperbolic-fig.ps")) @html(

    ) @fillcaption(The Hyperbolic Cosine Distribution.) @tag(hyperbolic-fig) @end(figure) @begin(fndefs) @codef{logistic-dist(@pragma(defn)@index(logistic-dist)@index(logistic distribution)@i(alpha), @i(beta) [, @i(low), @i(high)])} @c{[sal]}@* @altdef{@code{(logistic-dist @i(alpha) @i(beta) [@i(low) @i(high)])} @c{[lisp]}}@\Returns a @code(FLONUM) value from the logistic distribution, which is symetric about the mean. The @i(alpha) parameter primarily affects dispersion (variance), with larger values resulting in values closer to the mean (less variance), and the @i(beta) parameter primarily influences the mean. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "logistic-fig.ps")) @html(

    ) @fillcaption(The Logistic Distribution, alpha = 1, beta = 2.) @tag(logistic-fig) @end(figure) @begin(fndefs) @codef{arc-sine-dist(@pragma(defn)@index(arc-sine-dist)@index(arcsine distribution))} @c{[sal]}@* @altdef{@code{(arc-sine-dist)} @c{[lisp]}}@\Returns a @code(FLONUM) value from the arc sine distribution, which outputs values between 0 and 1. It is symetric about the mean of 1/2, but is more likely to generate values closer to 0 and 1. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "arcsine-fig.ps")) @html(

    ) @fillcaption(The Arc Sine Distribution.) @tag(arcsine-fig) @end(figure) @begin(fndefs) @codef{gaussian-dist(@index(Gaussian distribution)@pragma(defn)@index(gaussian-dist)@i(xmu), @i(sigma) [, @i(low), @i(high)])} @c{[sal]}@* @altdef{@code{(gaussian-dist @i(xmu) @i(sigma) [@i(low) @i(high)])} @c{[lisp]}}@\Returns a @code(FLONUM) value from the Gaussian or Gauss-Laplace distribution, a linear function of the normal distribution. It is symetric about the mean of @i(xmu), with a standard deviation of @i(sigma), which must be greater than zero. The @i(low) and @i(high) parameters give optional artificial bounds on the minimum and maximum output values, respectively. @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "gaussian-fig.ps")) @html(

    ) @fillcaption{The Gauss-Laplace (Gaussian) Distribution, @i(xmu) = 0, @i(sigma) = 1.} @tag(gaussian-fig) @end(figure) @begin(fndefs) @codef{beta-dist(@index(beta distribution)@pragma(defn)@index(beta-dist)@i(a), @i(b))} @c{[sal]}@* @altdef{@code[(beta-dist @i(a) @i(b))] @c{[lisp]}}@\Returns a @code(FLONUM) value from the Beta distribution. This distribution outputs values between 0 and 1, with outputs more likely to be close to 0 or 1. The parameter @i(a) controls the height (probability) of the right side of the distribution (at 1) and @i(b) controls the height of the left side (at 0). The distribution is symetric about 1/2 when @i(a) = @i(b). @end(fndefs) @begin(figure) @center(@graphic((height = 2.5 in, width = 3.75 in, magnify = 1, postscript = "beta-fig.ps")) @html(

    ) @fillcaption(The Beta Distribution, @i(alpha) = .5, @i(beta) = .25.) @tag(beta-fig) @end(figure) @begin(fndefs) @codef{bernoulli-dist(@index(Bernoulli distribution)@pragma(defn)@index(bernoulli-dist)@i(px1) [, @i(x1), @i(x2)])} @c{[sal]}@* @altdef{@code{(bernoulli-dist @i(px1) [@i(x1) @i(x2)])} @c{[lisp]}}@\Returns either @i(x1) (default value is 1) with probability @i(px1) or @i(x2) (default value is 0) with probability 1 - @i(px1). The value of @i(px1) should be between 0 and 1. By convention, a result of @i(x1) is viewed as a success while @i(x2) is viewed as a failure. @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "bernoulli-fig.ps")) @html(

    ) @fillcaption(The Bernoulli Distribution, @i(px1) = .75.) @tag(bernoulli-fig) @end(figure) @begin(fndefs) @codef{binomial-dist(@index(binomial distribution)@pragma(defn)@index(binomial-dist)@i(n), @i(p))} @c{[sal]}@* @altdef{@code{(binomial-dist @i(n) @i(p))} @c{[lisp]}}@\Returns a @code(FIXNUM) value from the binomial distribution, where @i(n) is the number of Bernoulli trials run (a @code(FIXNUM)) and @i(p) is the probability of success in the Bernoulli trial (a @code(FLONUM) from 0 to 1). The mean is the product of @i(n) and @i(p). @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "binomial-fig.ps")) @html(

    ) @fillcaption(The Binomial Distribution, @i(n) = 5, @i(p) = .5.) @tag(binomial-fig) @end(figure) @begin(fndefs) @codef{geometric-dist(@index(geometric distribution)@pragma(defn)@index(geometric-dist)@i(p))} @c{[sal]}@* @altdef{@code[(geometric-dist @i(p))] @c{[lisp]}}@\Returns a @code(FIXNUM) value from the geometric distribution, which is defined as the number of failures before a success is achieved in a Bernoulli trial with probability of success @i(p) (a @code(FLONUM) from 0 to 1). @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "geometric-fig.ps")) @html(

    ) @fillcaption(The Geometric Distribution, @i(p) = .4.) @tag(geometric-fig) @end(figure) @begin(fndefs) @codef{poisson-dist(@index(Poisson distribution)@pragma(defn)@index(poisson-dist)@i(delta))} @c{[sal]}@* @altdef{@code[(poisson-dist @i(delta))] @c{[lisp]}}@\Returns a @code(FIXNUM) value from the Poisson distribution with a mean of @i(delta) (a @code(FIXNUM)). The Poisson distribution is often used to generate a sequence of time intervals, resulting in random but often pleasing rhythms. @end(fndefs) @begin(figure) @center(@graphic((height = 3.5 in, width = 3.75 in, magnify = 0.75, postscript = "poisson-fig.ps")) @html(

    ) @fillcaption(The Poisson Distribution, @i(delta) = 3.) @tag(poisson-fig) @end(figure) @begin(comment) ***************** Note: this should remain out of Nyquist until the granulate code is cleaned up (why are there separate functions for pitch-dist and len-dist instead of a single function where any parameter can be specified by a closure?) ***************** @begin(fndefs) @codef{pitch-dist-granulate(@pragma(defn)@index(pitch-dist-granulate)@index(granular synthesis)@i(filename), @i(grain-dur), @i(grain-dev), @i(ioi), @i(ioi-dev), @i(pitch-dist) [, @i(file-start), @i(file-end)])} @c{[sal]}@* @altdef{@code{(pitch-dist-granulate @i(filename) @i(grain-dur) @i(grain-dev) @i(ioi) @i(ioi-dev) @i(pitch-dist) [@i(file-start) @i(file-end)])} @c{[lisp]}}@\*** need to write this *** @i(filename) @dash name of the file @i(dist) @dash the distribution that determines the length of the grains @i(ioi) @dash the basic inter-onset-interval for grains @i(ioi-dev) @dash ioi is actually: ioi + random(0, ioi-dev) @i(pitch-dev) @dash grains are resampled at rate between 1 and pitch-dev @i(file-start) @dash when to start reading the file (an offset from start). The default is 0. @i(file-end) @dash when to stop reading the file (an offset from end) the default is 0 returns @dash a set of sound grains created from the input file This is a granular synthesis function based on the one by Roger B. Dannenberg. The pitch of the grains will be based on the distribution you give to it. The distribution must be passed in as a continuation. (len-dist-granulate @i(filename) @i(dist ioi ioi-dev) @i(pitch-dev) [@i(file-start)@i(file-end)]) @i(filename) @dash name of the file @i(grain-dur) @dash the duration of a grain @i(grain-dev) @dash grain dur is actually grain-dur + random(0, grain-dev) @i(ioi) @dash the basic inter-onset-interval for grains @i(ioi-dev) @dash ioi is actually: ioi + random(0, ioi-dev) @i(pitch-dist) @dash the distribution of the alteration in pitch to the grains. The distribution values should be > 1. @i(file-start) @dash when to start reading the file (an offset from start). The default is 0 @i(file-end) @dash when to stop reading the file (an offset from end). The default is 0 returns @dash a set of sound grains created from the input file This is a granular synthesis function based on the one by Roger B. Dannenberg. The length of the grains will be based on the distribution you give to it. The distribution must be passed in as a continuation. @end(fndefs) @end(comment) @section(Score Generation and Manipulation) A common application of pattern generators is to specify parameters for notes. (It should be understood that ``notes'' in this context means any Nyquist behavior, whether it represents a conventional note, an abstract sound object, or even some micro-sound event that is just a low-level component of a hierarchical sound organization. Similarly, ``score'' should be taken to mean a specification for a sequence of these ``notes.'') The @code(score-gen) macro (defined by loading @code(xm.lsp)) establishes a convention for representing scores and for generating them using patterns. The @code(timed-seq) macro, described in Section @ref(timed-seq-sec), already provides a way to represent a ``score'' as a list of expressions. The Xmusic representation goes a bit further by specifying that @i(all notes are specified by an alternation of keywords and values, where some keywords have specific meanings and interpretations.) The basic idea of @code(score-gen)@index(score-gen) is you provide a template for notes in a score as a set of keywords and values. For example, @begin(example) set pitch-pattern = make-cycle(list(c4, d4, e4, f4)) score-gen(dur: 0.4, name: quote(my-sound), pitch: next(pitch-pattern), score-len: 9) @end(example) generates a score of 9 notes as follows: @begin(example) ((0 0 (SCORE-BEGIN-END 0 3.6)) (0 0.4 (MY-SOUND :PITCH 60)) (0.4 0.4 (MY-SOUND :PITCH 62)) (0.8 0.4 (MY-SOUND :PITCH 64)) (1.2 0.4 (MY-SOUND :PITCH 65)) (1.6 0.4 (MY-SOUND :PITCH 60)) (2 0.4 (MY-SOUND :PITCH 62)) (2.4 0.4 (MY-SOUND :PITCH 64)) (2.8 0.4 (MY-SOUND :PITCH 65)) (3.2 0.4 (MY-SOUND :PITCH 60))) @end(example) The use of keywords like @code(:PITCH) helps to make scores readable and easy to process without specific knowledge of about the functions called in the score. For example, one could write a transpose operation to transform all the @code(:pitch) parameters in a score without having to know that pitch is the first parameter of @code(pluck) and the second parameter of @code(piano-note). Keyword parameters are also used to give flexibility to note specification with @code(score-gen). Since this approach requires the use of keywords, the next section is a brief explanation of how to define functions that use keyword parameters. @subsection(Keyword Parameters) @index(keyword parameters) @index(parameters, keyword) Keyword parameters are parameters whose presence is indicated by a special symbol, called a keyword, followed by the actual parameter. Keyword parameters in SAL have default values that are used if no actual parameter is provided by the caller of the function. (See Appendix @ref(xlisp-app) to learn about keywords in XLISP.) To specify that a parameter is a keyword parameter, use a keyword symbol (one that ends in a colon) followed by a default value. For example, here is a function that accepts keyword parameters and invokes the @code(pluck) function: @begin(example) define function k-pluck(pitch: 60, dur: 1) return pluck(pitch, dur) @end(example) Now, we can call k-pluck with keyword parameters. The keywords are simply the formal parameter names with a prepended colon character (@code(:pitch) and @code(:dur) in this example), so a function call would look like: @begin(example) pluck(pitch: c3, dur: 3) @end(example) Usually, it is best to give keyword parameters useful default values. That way, if a parameter such as @code(dur:) is missing, a reasonable default value (1) can be used automatically. It is never an error to omit a keyword parameter, but the called function can check to see if a keyword parameter was supplied or not. Because of default values, we can call @code[k-pluck(pitch: c3)] with no duration, @code[k-pluck(dur: 3)] with only a duration, or even @code[k-pluck()] with no parameters. In XLISP, there is additional syntax to specify an alternate symbol to be used as the keyword and to allow the called function to determine whether or not a keyword parameter was supplied, but these features are little-used. See the XLISP manual for details. @subsection(Using score-gen)@pragma(defn)@index(score-gen) The @code(score-gen) macro computes a score based on keyword parameters. Some keywords have a special meaning, while others are not interpreted but merely placed in the score. The resulting score can be synthesized using @code(timed-seq) (see Section @ref(timed-seq-sec)). The form of a call to @code(score-gen) is simply: @begin(fndefs) @codef[score-gen(@pragma(defn)@index(score-gen)@i(k1:) @i(e1), @i(k2:) @i(e2), @r(...))] @c{[sal]}@* @altdef{@code[(score-gen @i(:k1) @i(e1) @i(:k2) @i(e2) @r(...))] @c{[lisp]}}@\where the @i(k)'s are keywords and the @i(e)'s are expressions. A score is generated by evaluating the expressions once for each note and constructing a list of keyword-value pairs. A number of keywords have special interpretations. The rules for interpreting these parameters will be explained through a set of "How do I ..." questions below. @end(fndefs) @i(How many notes will be generated?) The keyword parameter @code(score-len:) specifies an upper bound on the number of notes. (Note: in LISP syntax, keywords are always @i(preceded) by colons, so you would write @code(:score-len) instead.) The keyword @code(score-dur:) specifies an upper bound on the starting time of the last note in the score. (To be more precise, the @code(score-dur:) bound is reached when the default starting time of the next note is greater than or equal to the @code(score-dur:) value. This definition is necessary because note times are not strictly increasing.) When either bound is reached, score generation ends. At least one of these two parameters must be specified or an error is raised. These keyword parameters are evaluated just once and are not copied into the parameter lists of generated notes. @i(What is the duration of generated notes?) The keyword @code(dur:) defaults to 1 and specifies the nominal duration in seconds. Since the generated note list is compatible with @code(timed-seq), the starting time and duration (to be precise, the @i(stretch factor)) are not passed as parameters to the notes. Instead, they control the Nyquist environment in which the note will be evaluated. @i(What is the start time of a note?) The default start time of the first note is zero. Given a note, the default start time of the next note is the start time plus the inter-onset time, which is given by the @code(ioi:) parameter. If no @code(ioi:) parameter is specified, the inter-onset time defaults to the duration, given by @code(dur:). In all cases, the default start time of a note can be overridden by the keyword parameter @code(time:). @i(When does the score begin and end?) The behavior @code[SCORE-BEGIN-END] contains the beginning and ending of the score (these are used for score manipulations, e.g. when scores are merged, their begin times can be aligned.) When @code(timed-seq) is used to synthesize a score, the @code(SCORE-BEGIN-END) marker is not evaluated. The @code(score-gen) macro inserts a ``note'' of the form @code[(0 0 (SCORE-BEGIN-END @i(begin-time) @i(end-time)))] at the time given by the @code(begin:) keyword, with @i(begin-time) and @i(end-time) determined by the @code(begin:) and @code(end:) keyword parameters, respectively. If the @i(begin:) keyword is not provided, the score begins at zero. If the @code(end:) keyword is not provided, the score ends at the default start time of what would be the next note after the last note in the score (as described in the previous paragraph). Note: if @code(time:) is used to compute note starting times, and these times are not increasing, it is strongly advised to use @code(end:) to specify an end time for the score, because the default end time may be anywhere in the middle of the generated sequence. @i(What function is called to synthesize the note?) The @code(name:) parameter names the function. Like other parameters, the value can be any expression, including something like @code[next(fn-name-pattern)], allowing function names to be recomputed for each note. The default value is @code(note). @i(Can I make parameters depend upon the starting time or the duration of the note?) Parameter expressions can use the variable @code(sg:time) to access the start time of the note, @code(sg:ioi) to access the inter-onset time, and @code(sg:dur) to access the duration (stretch factor) of the note. Also, @code(sg:count) counts how many notes have been computed so far, starting at 0. The order of computation is: @code(sg:time) first, then @code(sg:ioi) and @code(sg:dur), so for example, an expression to compute @code(sg:dur) can depend on @code(sg:ioi). @i(Can parameters depend on each other?) The keyword @code(pre:) introduces an expression that is evaluated before each note, and @code(post:) provides an expression to be evaluated after each note. The @code(pre:) expression can assign one or more global variables which are then used in one or more expressions for parameters. @i(How do I debug @code(score-gen) expressions?) You can set the @code(trace:) parameter to true (@code(t)) to enable a print statement for each generated note. @i(How can I save scores generated by @code(score-gen) that I like?) If the keyword parameter @code(save:) is set to a symbol, the global variable named by the symbol is set to the value of the generated sequence. Of course, the value returned by @code(score-gen) is just an ordinary list that can be saved like any other value. In summary, the following keywords have special interpretations in @code(score-gen): @code(begin:), @code(end:), @code(time:), @code(dur:), @code(name:), @code(ioi:), @code(trace:), @code(save:), @code(score-len:), @code(score-dur:), @code(pre:), @code(post:). All other keyword parameters are expressions that are evaluated once for each note and become the parameters of the notes. @subsection(Score Manipulation) @index(score manipulation)@index(manipulation of scores) Nyquist encourages the representation of music as executable programs, or @i(behaviors), and there are various ways to modify behaviors, including time stretching, transposition, etc. An alternative to composing executable programs is to manipulate scores as editable data. Each approach has its strengths and weaknesses. This section describes functions intended to manipulate Xmusic scores as generated by, or at least in the form generated by, @code(score-gen). Recall that this means scores are lists of events (e.g. notes), where events are three-element lists of the form (@i(time) @i(duration) @i(expression), and where @i(expression) is a standard lisp function call where all parameters are keyword parameters. In addition, the first ``note'' may be the special @code(SCORE-BEGIN-END) expression. If this is missing, the score begins at zero and ends at the end of the last note. For convenience, a set of functions is offered to access properties of events (or notes) in scores. Although lisp functions such as @code(car), @code(cadr), and @code(caddr) can be used, code is more readable when more mnemonic functions are used to access events. @begin(fndefs) @codef[event-time(@pragma(defn)@index(event-time)@i(event))] @c{[sal]}@* @altdef{@code[(event-time @i(event))] @c{[lisp]}}@\Retrieve the time field from an event. @codef[event-set-time(@pragma(defn)@index(event-set-time)@i(event), @i(time))] @c{[sal]}@* @altdef{@code[(event-set-time @i(event) @i(time))] @c{[lisp]}}@\Construct a new event where the time of @i(event) is replaced by @i(time). @codef[event-dur(@pragma(defn)@index(event-dur)@i(event))] @c{[sal]}@* @altdef{@code[(event-dur @i(event))] @c{[lisp]}}@\Retrieve the duration (i.e. the stretch factor) field from an event. @codef[event-set-dur(@pragma(defn)@index(event-set-dur)@i(event), @i(dur))] @c{[sal]}@* @altdef{@code[(event-set-dur @i(event) @i(dur))] @c{[lisp]}}@\Construct a new event where the duration (or stretch factor) of @i(event) is replaced by @i(dur). @codef[event-expression(@pragma(defn)@index(event-expression)@i(event))] @c{[sal]}@* @altdef{@code[(event-expression @i(event))] @c{[lisp]}}@\Retrieve the expression field from an event. @codef[event-set-expression(@pragma(defn)@index(event-set-expression)@i(event), @i(dur))] @c{[sal]}@* @altdef{@code[(event-set-expression @i(event) @i(dur))] @c{[lisp]}}@\Construct a new event where the expression of @i(event) is replaced by @i(expression). @codef[event-end(@pragma(defn)@index(event-end)@i(event))] @c{[sal]}@* @altdef{@code[(event-end @i(event))] @c{[lisp]}}@\Retrieve the end time of @i(event), its time plus its duration. @codef[expr-has-attr(@pragma(defn)@index(expr-has-attr)@i(expression), @i(attribute))] @c{[sal]}@* @altdef{@code[(expr-has-attr @i(expression) @i(attribute))] @c{[lisp]}}@\Test whether a score event @i(expression) has the given @i(attribute). @codef{expr-get-attr(@pragma(defn)@index(expr-get-attr)@i(expression), @i(attribute) [, @i(default)])} @c{[sal]}@* @altdef{@code{(expr-get-attr @i(expression) @i(attribute) [@i(default)])} @c{[lisp]}}@\Get the value of the given @i(attribute) from a score event @i(expression). If @i(attribute) is not present, return @i(default) if specified, and otherwise @code(nil). @codef{expr-set-attr(@pragma(defn)@index(expr-set-attr)@i(expr), @i(attribute), @i(value))} @c{[sal]}@* @altdef{@code[(expr-set-attr @i(expr) @i(attribute) @i(value))] @c{[lisp]}}@\Construct a new expression identical to @i(expr) except that the @i(attribute) has @i(value). @codef[event-has-attr(@pragma(defn)@index(event-has-attr)@i(event), @i(attribute))] @c{[sal]}@* @altdef{@code[(event-has-attr @i(event) @i(attribute))] @c{[lisp]}}@\Test whether a given score @i(event)'s expression has the given @i(attribute). @codef{event-get-attr(@pragma(defn)@index(event-get-attr)@i(event), @i(attribute), [@i(default)])} @c{[sal]}@* @altdef{@code{(event-get-attr @i(event) @i(attribute) [@i(default)])} @c{[lisp]}}@\Get the value of the given @i(attribute) from a score @i(event)'s expression. If @i(attribute) is not present, return @i(default) if specified, and otherwise @code(nil). @codef{event-set-attr(@pragma(defn)@index(event-set-attr)@i(event), @i(attribute), @i(value))} @c{[sal]}@* @altdef{@code[(event-set-attr @i(event) @i(attribute) @i(value))] @c{[lisp]}}@\Construct a new event identical to @i(event) except that the @i(attribute) has @i(value). @end(fndefs) Functions are provided to shift the starting times of notes, stretch times and durations, stretch only durations, add an offset to a keyword parameter, scale a keyword parameter, and other manipulations. Functions are also provided to extract ranges of notes, notes that match criteria, and to combine scores. Most of these functions (listed below in detail) share a set of keyword parameters that optionally limit the range over which the transformation operates. The @code(from-index:) and @code(to-index:) parameters specify the index of the first note and the index of the last note to be changed. If these numbers are negative, they are offsets from the end of the score, e.g. -1 denotes the last note of the score. The @code(from-time:) and @code(to-time:) indicate a range of starting times of notes that will be affected by the manipulation. Only notes whose time is greater than or equal to the @i(from-time) and @i(strictly less than) the @i(to-time) are modified. If both index and time ranges are specified, only notes that satisfy @i(both) constraints are selected. (Note: in LISP syntax, colons @i(precede) the keyword, so use @code(:from-index), @code(:to-index), @code(:from-time), and @code(:to-time).) @begin(fndefs) @codef[score-sorted(@pragma(defn)@index(score-sorted)@i(score))] @c{[sal]}@* @altdef{@code[(score-sorted @i(score))] @c{[lisp]}}@\Test if @i(score) is sorted. @codef{score-sort(@pragma(defn)@index(score-sort)@i(score) [, @i(copy-flag)])} @c{[sal]}@* @altdef{@code{(score-sort @i(score) [@i(copy-flag)])} @c{[lisp]}}@\Sort the notes in a score into start-time order. If copy-flag is nil, this is a destructive operation which should only be performed if the top-level score list is a fresh copy that is not shared by any other variables. (The @i(copy-flag) is intended for internal system use only.) For the following operations, it is assumed that scores are sorted, and all operations return a sorted score. @codef{score-shift(@pragma(defn)@index(score-shift)@i(score), @i(offset), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-shift @i(score) @i(offset) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Add a constant @i(offset) to the starting time of a set of notes in @i(score). By default, all notes are modified, but the range of notes can be limited with the keyword parameters. The begin time of the score is not changed, but the end time is increased by @i(offset). The original score is not modified, and a new score is returned. @codef{score-stretch(@pragma(defn)@index(score-stretch)@i(score), @i(factor), dur: @i(dur-flag), time: @i(time-flag), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-stretch @i(score) @i(factor) :dur @i(dur-flag) :time @i(time-flag) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Stretch note times and durations by @i(factor). The default @i(dur-flag) is non-null, but if @i(dur-flag) is null, the original durations are retained and only times are stretched. Similarly, the default @i(time-flag) is non-null, but if @i(time-flag) is null, the original times are retained and only durations are stretched. If both @i(dur-flag) and @i(time-flag) are null, the score is not changed. If a range of notes is specified, times are scaled within that range, and notes after the range are shifted so that the stretched region does not create a "hole" or overlap with notes that follow. If the range begins or ends with a time (via @code(from-time:) and @code(to-time:)), time stretching takes place over the indicated time interval independent of whether any notes are present or where they start. In other words, the ``rests'' are stretched along with the notes. The original score is not modified, and a new score is returned. @codef{score-transpose(@pragma(defn)@index(score-transpose)@i(score), @i(keyword), @i(amount), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-transpose @i(score) @i(keyword) @i(amount) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\For each note in the score and in any indicated range, if there is a keyword parameter matching @i(keyword) and the parameter value is a number, increment the parameter value by @i(amount). For example, to tranpose up by a whole step, write @code[(score-transpose 2 :pitch @i(score))]. The original score is not modified, and a new score is returned. @codef{score-scale(@pragma(defn)@index(score-scale)@i(score), @i(keyword), @i(amount), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-scale @i(score) @i(keyword) @i(amount) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\For each note in the score and in any indicated range, if there is a keyword parameter matching @i(keyword) and the parameter value is a number, multiply the parameter value by @i(amount). The original score is not modified, and a new score is returned. @codef{score-sustain(@pragma(defn)@index(score-sustain)@i(score), @i(factor), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-sustain @i(score) @i(factor) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\For each note in the score and in any indicated range, multiply the duration (stretch factor) by @i(amount). This can be used to make notes sound more legato or staccato, and does not change their starting times. The original score is not modified, and a new score is returned. @codef{score-voice(@pragma(defn)@index(score-voice)@i(score), @i(replacement-list), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-voice @i(score) @i(replacement-list) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\For each note in the score and in any indicated range, replace the behavior (function) name using @i(replacement-list), which has the format: @code[((@i(old1 new1)) (@i(old2 new2)) @r(...))], where @i(oldi) indicates a current behavior name and @i(newi) is the replacement. If @i(oldi) is @code(*), it matches anything. For example, to replace @code(my-note-1) by @code(trombone) and @code(my-note-2) by @code(horn), use @code[score-voice(@i(score), {{my-note-1 trombone} {my-note-2 horn}})]. To replace all instruments with @code(piano), use @code[score-voice(@i(score), {{* piano}})]. The original score is not modified, and a new score is returned. @codef{score-merge(@pragma(defn)@index(score-merge)@i(score1), @i(score2), @r(...))} @c{[sal]}@* @altdef{@code[(score-merge @i(score1) @i(score2) @r(...))] @c{[lisp]}}@\Create a new score containing all the notes of the parameters, which are all scores. The resulting notes retain their original times and durations. The merged score begin time is the minimum of the begin times of the parameters and the merged score end time is the maximum of the end times of the parameters. The original scores are not modified, and a new score is returned. @codef{score-append(@pragma(defn)@index(score-append)@i(score1), @i(score2), @r(...))} @c{[sal]}@* @altdef{@code[(score-append @i(score1) @i(score2) @r(...))] @c{[lisp]}}@\Create a new score containing all the notes of the parameters, which are all scores. The begin time of the first score is unaltered. The begin time of each other score is aligned to the end time of the previous score; thus, scores are ``spliced'' in sequence. The original scores are not modified, and a new score is returned. @codef{score-select(@pragma(defn)@index(score-select)@index(score-filter)@i(score), @i(predicate), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y), reject: @i(flag))} @c{[sal]}@* @altdef{@code{(score-select @i(score) @i(predicate) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y) :reject @i(flag))} @c{[lisp]}}@\Select (or reject) notes to form a new score. Notes are selected if they fall into the given ranges of index and time @i(and) they satisfy @i(predicate), a function of three parameters that is applied to the start time, duration, and the expression of the note. Alternatively, @i(predicate) may be @code(t), indicating that all notes in range are to be selected. The selected notes along with the existing score begin and end markers, are combined to form a new score. Alternatively, if the @code(reject:) parameter is non-null, the notes @i(not) selected form the new score (in other words the selected notes are rejected or removed to form the new score). The original score is not modified, and a new score is returned. @codef{score-set-begin(@pragma(defn)@index(score-set-begin)@i(score), @i(time))} @c{[sal]}@* @altdef{@code[(score-set-begin @i(score) @i(time))] @c{[lisp]}}@\The begin time from the @i(score)'s @code(SCORE-BEGIN-END) marker is set to @i(time). The original score is not modified, and a new score is returned. @codef{score-get-begin(@pragma(defn)@index(score-get-begin)@i(score))} @c{[sal]}@* @altdef{@code[(score-get-begin @i(score))] @c{[lisp]}}@\Return the begin time of the @i(score). @codef{score-set-end(@pragma(defn)@index(score-set-end)@i(score), @i(time))} @c{[sal]}@* @altdef{@code[(score-set-end @i(score) @i(time))] @c{[lisp]}}@\The end time from the @i(score)'s @code(SCORE-BEGIN-END) marker is set to @i(time). The original score is not modified, and a new score is returned. @codef{score-get-end(@pragma(defn)@index(score-get-end)@i(score))} @c{[sal]}@* @altdef{@code[(score-get-end @i(score))] @c{[lisp]}}@\Return the end time of the @i(score). @codef{score-must-have-begin-end(@pragma(defn)@index(score-must-have-begin-end)@i(score))} @c{[sal]}@* @altdef{@code[(score-must-have-begin-end @i(score))] @c{[lisp]}}@\If @i(score) does not have a begin and end time, construct a score with a @code(SCORE-BEGIN-END) expression and return it. If score already has a begin and end time, just return the score. The orignal score is not modified. @codef{score-filter-length(@pragma(defn)@index(score-filter-length)@i(score), @i(cutoff))} @c{[sal]}@* @altdef{@code[(score-filter-length @i(score) @i(cutoff))] @c{[lisp]}}@\Remove notes that extend beyond the @i(cutoff) time. This is similar to @code(score-select), but the here, events are removed when their nominal ending time (start time plus duration) exceeds the @i(cutoff), whereas the @code(to-time:) parameter is compared to the note's start time. The original score is not modified, and a new score is returned. @codef{score-repeat(@pragma(defn)@index(score-repeat)@i(score), @i(n))} @c{[sal]}@* @altdef{@code[(score-repeat @i(score) @i(n))] @c{[lisp]}}@\Make a sequence of @i(n) copies of @i(score). Each copy is shifted to that it's begin time aligns with the end time of the previous copy, as in @code(score-append). The original score is not modified, and a new score is returned. @codef{score-stretch-to-length(@pragma(defn)@index(score-stretch-to-length)@i(score), @i(length))} @c{[sal]}@* @altdef{@code[(score-stretch-to-length @i(score) @i(length))] @c{[lisp]}}@\Stretch the score so that the end time of the score is the score's begin time plus @i(length). The original score is not modified, and a new score is returned. @codef{score-filter-overlap(@pragma(defn)@index(score-filter-overlap)@i(score))} @c{[sal]}@* @altdef{@code[(score-filter-overlap @i(score))] @c{[lisp]}}@\Remove overlapping notes (based on the note start time and duration), giving priority to the positional order within the note list (which is also time order). The original score is not modified, and a new score is returned. @codef{score-print(@pragma(defn)@index(score-print)@i(score))} @c{[sal]}@* @altdef{@code[(score-print @i(score))] @c{[lisp]}}@\Print a score with one note per line. Returns @code(nil). @codef{score-play(@pragma(defn)@index(score-play)@i(score))} @c{[sal]}@* @altdef{@code[(score-play @i(score))] @c{[lisp]}}@\Play @i(score) using @code(timed-seq) to convert the score to a sound, and @code(play) to play the sound. @codef{score-adjacent-events(@pragma(defn)@index(score-adjacent-events)@i(score), @i(function), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-adjacent-events @i(score) @i(function) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Call @code[(@i(function) @i(A) @i(B) @i(C))], where @i(A), @i(B), and @i(C) are consecutive notes in the score. The result replaces @i(B). If the result is @code(nil), @i(B) is deleted, and the next call will be @code[(@i(function A C D))], etc. The first call is to @code[(@i(function) nil @i(A B))] and the last is to @code[(@i(function) @i(Y Z) nil)]. If there is just one note in the score, @code[(@i(function) nil @i(A) nil)] is called. Function calls are not made if the note is outside of the indicated range. This function allows notes and their parameters to be adjusted according to their immediate context. The original score is not modified, and a new score is returned. @codef{score-apply(@pragma(defn)@index(score-apply)@i(score), @i(function), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-apply @i(score) @i(function) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Replace each note in the score with the result of @code[(@i(function time dur expression))] (in Lisp) or @code[@i(function)(@i(time), @i(dur), @i(expression))] (in SAL), where @i(time), @i(dur), and @i(expression) are the time, duration, and expression of the note. If a range is indicated, only notes in the range are replaced. The original score is not modified, and a new score is returned. @codef{score-indexof(@pragma(defn)@index(score-indexof)@i(score), @i(function), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-indexof @i(score) @i(function) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Return the index (position) of the first score event (in range) for which applying @i(function) using @code[(@i(function time dur expression))] returns true. @codef{score-last-indexof(@pragma(defn)@index(score-last-indexof)@i(score), @i(function), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-last-indexof @i(score) @i(function) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Return the index (position) of the last score event (in range) for which applying @i(function) using @code[(@i(function time dur expression))] returns true. @codef{score-randomize-start(@pragma(defn)@index(score-randomize-start)@index(jitter)@index(feel factor)@index(offset)@i(score), @i(amt), from-index: @i(i), to-index: @i(j), from-time: @i(x), to-time: @i(y))} @c{[sal]}@* @altdef{@code{(score-randomize-start @i(score) @i(amt) :from-index @i(i) :to-index @i(j) :from-time @i(x) :to-time @i(y))} @c{[lisp]}}@\Alter the start times of notes by a random amount up to plus or minus @i(amt). The original score is not modified, and a new score is returned. @end(fndefs) @subsection(Xmusic and Standard MIDI Files) @index(MIDI file)@index(Standard MIDI File) Nyquist has a general facility to read and write MIDI files. You can even translate to and from a text representation, as described in Chapter @ref(adagio-chap). It is also useful sometimes to read notes from Standard MIDI Files into Xmusic scores and vice versa. At present, Xmusic only translates notes, ignoring the various controls, program changes, pitch bends, and other messages. MIDI notes are translated to Xmusic score events as follows: @begin(display) @code[(@i(time) @i(dur) (NOTE :chan @i(channel) :pitch @i(keynum) :vel @i(velocity)))], @end(display) where @i(channel), @i(keynum), and @i(velocity) come directly from the MIDI message (channels are numbered starting from zero). Note also that note-off messages are implied by the stretch factor @i(dur) which is duration in seconds. @begin(fndefs) @codef{score-read-smf(@pragma(defn)@index(score-read-smf)@index(midi file)@i(filename))} @c{[sal]}@* @altdef{@code[(score-read-smf @i(filename))] @c{[lisp]}}@\Read a standard MIDI file from @i(filename). Return an Xmusic score, or @code(nil) if the file could not be opened. The start time is zero, and the end time is the maximum end time of all notes. A very limited interface is offered to extract MIDI program numbers from the file: The global variable @code(*rslt*) is set to a list of MIDI program numbers for each channel. E.g. if @code(*rslt*) is @code[(0 20 77)], then program for channel 0 is 0, for channel 1 is 20, and for channel 2 is 77. Program changes were not found on other channels. The default program number is 0, so in this example, it is not known whether the program 0 on channel 0 is the result of a real MIDI program change command or just a default value. If more than one program change exists on a channel, the @i[last] program number is recorded and returned, so this information will only be completely correct when the MIDI file sends single program change per channel before any notes are played. This, however, is a fairly common practice. Note that the list returned as @code(*rslt*) can be passed to @code(score-write-smf), described below. @codef{score-write-smf(@pragma(defn)@index(score-write-smf)@index(midi file)@i(score), @i(filename), [@i(programs)])} @c{[sal]}@* @altdef{@code[(score-write-smf @i(score) @i(filename) @i(programs))] @c{[lisp]}}@\Write a standard MIDI file to @i(filename) with notes in @i(score). In this function, @i(every) event in the score with a @code(pitch:) attribute, regardless of the ``instrument'' (or function name), generates a MIDI note, using the @code(chan:) attribute for the channel (default 0) and the @code(vel:) attribute for velocity (default 100). There is no facility (in the current implementation) to issue control changes, but to allow different instruments, MIDI programs may be set in two ways. The simplest is to associate programs with channels using the optional @i[programs] parameter, which is simply a list of up to 16 MIDI program numbers. Corresponding program change commands are added to the beginning of the MIDI file. If @i[programs] has less than 16 elements, program change commands are only sent on the first @i[n] channels. The second way to issue MIDI program changes is to add a @code(program:) keyword parameter to a note in the score. Typically, the note will have a @code(pitch:) of @code(nil) so that no actual MIDI note-on message is generated. If program changes and notes have the same starting times, their relative playback order is undefined, and the note may be cut off by an immediately following program change. Therefore, program changes should occur slightly, e.g. 1 ms, before any notes. @i(Program numbers and channels are numbered starting at zero, matching the internal MIDI representation. This may be one less than displayed on MIDI hardware, sequencers, etc.) @end(fndefs) @subsection(Workspaces) @label(workspaces-sec) @index(workspace) When working with scores, you may find it necessary to save them in files between work sessions. This is not an issue with functions because they are normally edited in files and loaded from them. In contrast, scores are created as Lisp data, and unless you take care to save them, they will be destroyed when you exit the Nyquist program. A simple mechanism called a workspace has been created to manage scores (and any other Lisp data, for that matter). A workspace is just a set of lisp global variables. These variables are stored in the file @code(workspace.lsp). For simplicity, there is only one workspace, and no backups or versions are maintained, but the user is free to make backups and copies of @code(workspace.lsp). To help remember what each variable is for, you can also associate and retrieve a text string with each variable. The following functions manage workspaces. In addition, when a workspace is loaded, you can request that functions be called. For example, the workspace might store descriptions of a graphical interface. When the workspace is loaded, a function might run to convert saved data into a graphical interface. (This is how sliders are saved by the IDE.) @begin(fndefs) @codef[add-to-workspace(@pragma(defn)@index(add-to-workspace)@i(symbol))] @c{[sal]}@* @altdef{@code[(add-to-workspace @i(symbol))] @c{[lisp]}}@\Adds a global variable to the workspace. The @i(symbol) should be a (quoted) symbol. @codef[save-workspace(@pragma(defn)@index(save-workspace))] @c{[sal]}@* @altdef{@code{(save-workspace)} @c{[lisp]}}@\All global variables in the workspace are saved to @code(workspace.lsp) (in the current directory), overwriting the previous file. @codef{describe(@pragma(defn)@index(describe)@i(symbol) [, @i(description)])} @c{[sal]}@* @altdef{@code[(describe @i(symbol) [@i(description)])] @c{[lisp]}}@\If @i(description), a text string, is present, associate @i(description) with the variable named by the @i(symbol). If @i(symbol) is not already in the workspace, it is added. If @i(description) is omitted, the function returns the current description (from a previous call) for @i(symbol). @codef{add-action-to-workspace(@pragma(defn)@index(add-action-to-workspace)@i(symbol))} @c{[sal]}@* @altdef{@code[(add-action-to-workspace @i(symbol))] @c{[lisp]}}@\Requests that the function named by @i(symbol) be called when the workspace is loaded (if the function is defined). @end(fndefs) To restore a workspace, use the command @code[load "workspace"]. This restores the values of the workspace variables to the values they had when @code(save-workspace) was last called. It also restores the documentation strings, if set, by @code(describe). If you load two or more @code(workspace.lsp) files, the variables will be merged into a single workspace. The current set of workspace variables are saved in the list @code(*workspace*). To clear the workspace, set @code(*workspace*) to @code(nil). This does not delete any variables, but means that no variables will be saved by @code(save-workspace) until variables are added again. Functions to be called are saved in the list @code(*workspace-actions*). to clear the functions, set @code(*workspace-actions*) to @code(nil). Restore functions to the list with @code(add-action-to-workspace). @subsection(Utility Functions) This chapter concludes with details of various utility functions for score manipulation. @begin(fndefs) @codef[patternp(@pragma(defn)@index(patternp)@i(expression))] @c{[sal]}@* @altdef{@code[(patternp @i(expression))] @c{[lisp]}}@\Test if @i(expression) is an Xmusic pattern. @codef[params-transpose(@pragma(defn)@index(params-transpose)@i(params), @i(keyword), @i(amount))] @c{[sal]}@* @altdef{@code[(params-transpose @i(params) @i(keyword) @i(amount))] @c{[lisp]}}@\Add a transposition amount to a score event parameter. The @i(params) parameter is a list of keyword/value pairs (not preceded by a function name). The @i(keyword) is the keyword of the value to be altered, and @i(amount) is a number to be added to the value. If no matching keyword is present in @i(params), then @i(params) is returned. Otherwise, a new parameter list is constructed and returned. The original @i(params) is not changed. @codef[params-scale(@pragma(defn)@index(params-scale)@i(params), @i(keyword), @i(amount))] @c{[sal]}@* @altdef{@code[(params-scale @i(params) @i(keyword) @i(amount))] @c{[lisp]}}@\Scale a score event parameter by some factor. This is like @code(params-transpose), only using multiplication. The @i(params) list is a list of keyword/value pairs, @i(keyword) is the parameter keyword, and @i(amount) is the scale factor. @codef[interpolate(@pragma(defn)@index(interpolate)@index(linear interpolation)@i(x), @i(x1), @i(y1), @i(x2), @i(y2))] @c{[sal]}@* @altdef{@code[(interpolate @i(x) @i(x1) @i(y1) @i(x2) @i(y2))] @c{[lisp]}}@\Linearly interpolate (or extrapolate) between points (@i(x1), @i(y1)) and (@i(x2), @i(y2)) to compute the y value corresponding to @i(x). @codef[intersection(@pragma(defn)@index(intersection)@index(set intersection)@i(a), @i(b))] @c{[sal]}@* @altdef{@code[(intersection @i(a) @i(b))] @c{[lisp]}}@\Compute the set intersection of lists @i(a) and @i(b). @codef[union(@pragma(defn)@index(union)@index(set union)@i(a), @i(b))] @c{[sal]}@* @altdef{@code[(union @i(a) @i(b))] @c{[lisp]}}@\Compute the set union of lists @i(a) and @i(b). @codef[set-difference(@index(difference)@pragma(defn)@index(set-difference)@i(a), @i(b))] @c{[sal]}@* @altdef{@code[(set-difference @i(a) @i(b))] @c{[lisp]}}@\Compute the set of all elements that are in @i(a) but not in @i(b). @codef[subsetp(@pragma(defn)@index(subsetp)@index(subset)@i(a), @i(b))] @c{[sal]}@* @altdef{@code[(subsetp @i(a) @i(b))] @c{[lisp]}}@\Returns true iff @i(a) is a subset of @i(b), that is, each element of @i(a) is a member of @i(b). @end(fndefs) @chapter(Nyquist Libraries) @index(libraries) Nyquist is always growing with new functions. Functions that are most fundamental are added to the core language. These functions are automatically loaded when you start Nyquist, and they are documented in the preceding chapters. Other functions seem less central and are implemented as lisp files that you can load. These are called library functions, and they are described here. To use a library function, you must first load the library, e.g. @code[(load "pianosyn")] loads the piano synthesis library. The libraries are all located in the @code(lib) directory, and you should therefore include this directory on your @code(XLISPPATH) variable. (See Section @ref(install-sec).) Each library is documented in one of the following sections. When you load the library described by the section, all functions documented in that section become available. @section(Piano Synthesizer) The piano synthesizer (library name is @code(pianosyn.lsp)) generates realistic piano tones using a multiple wavetable implementation by Zheng (Geoffrey) Hua and Jim Beauchamp, University of Illinois. Please see the notice about acknowledgements that prints when you load the file. Further informations and example code can be found in @code(demos/piano.htm)@index(demos, piano)@index(piano synthesizer tutorial). There are several useful functions in this library: @begin(fndefs) @codef[piano-note(@pragma(defn)@index(piano-note)@index(piano synthesizer)@i(duration), @i(step), @i(dynamic))] @c{[sal]}@* @altdef{@code[(piano-note @i(duration) @i(step) @i(dynamic))] @c{[lisp]}}@\Synthesizes a piano tone. @i(Duration) is the duration to the point of key release, after which there is a rapid decay. @i(Step) is the pitch in half steps, and @i(dynamic) is approximately equivalent to a MIDI key velocity parameter. Use a value near 100 for a loud sound and near 10 for a soft sound. @codef[piano-note-2(@pragma(defn)@index(piano-note-2)@i(step), @i(dynamic))] @c{[sal]}@* @altdef{@code[(piano-note-2 @i(step) @i(dynamic))] @c{[lisp]}}@\Similar to @code(piano-note) except the duration is nominally 1.0. @codef[piano-midi(@pragma(defn)@index(piano-midi)@i(midi-file-name))] @c{[sal]}@* @altdef{@code[(piano-midi @i(midi-file-name))] @c{[lisp]}}@\Use the piano synthesizer to play a MIDI file. The file name (a string) is given by @i(midi-file-name). @codef[piano-midi2file(@pragma(defn)@index(piano-midi2file)@i(midi-file-name), @i(sound-file-name))] @c{[sal]}@* @altdef{@code[(piano-midi2file @i(midi-file-name) @i(sound-file-name))] @c{[lisp]}}@\Use the piano synthesizer to play a MIDI file. The MIDI file is given by @i(midi-file-name) and the (monophonic) result is written to the file named @i(sound-file-name). @end(fndefs) @section(Dymanics Compression) To use these functions, load the file @code(compress.lsp). This library implements a compressor originally intended for noisy speech audio, but usable in a variety of situations. There are actually two compressors that can be used in series. The first, @code(compress), is a fairly standard one: it detects signal level with an RMS detector and uses table-lookup to determine how much gain to place on the original signal at that point. One bit of cleverness here is that the RMS envelope is ``followed'' or enveloped using @code(snd-follow), which does look-ahead to anticipate peaks before they happen. The other interesting feature is @code(compress-map), which builds a map in terms of compression and expansion. For speech, the recommended procedure is to figure out the noise floor on the signal you are compressing (for example, look at the signal where the speaker is not talking). Use a compression map that leaves the noise alone and boosts signals that are well above the noise floor. Alas, the @code(compress-map) function is not written in these terms, so some head-scratching is involved, but the results are quite good. The second compressor is called @code(agc), and it implements automatic gain control that keeps peaks at or below 1.0. By combining @code(compress) and @code(agc), you can process poorly recorded speech for playback on low-quality speakers in noisy environments. The @code(compress) function modulates the short-term gain to to minimize the total dynamic range, keeping the speech at a generally loud level, and the @code(agc) function rides the long-term gain to set the overall level without clipping. @begin(fndefs) @codef{compress-map(@pragma(defn)@index(compress-map)@i(compress-ratio), @i(compress-threshold), @i(expand-ratio), @i(expand-ratio), limit: @i(limit), transition: @i(transition))} @c{[sal]}@* @altdef{@code{(compress-map @i(compress-ratio) @i(compress-threshold) @i(expand-ratio) @i(expand-ratio) :limit @i(limit) :transition @i(transition)])} @c{[lisp]}}@\Construct a map for the compress function. The map consists of two parts: a compression part and an expansion part. The intended use is to compress everything above compress-threshold by compress-ratio, and to downward expand everything below expand-ratio by expand-ratio. Thresholds are in dB and ratios are dB-per-dB. 0dB corresponds to a peak amplitude of 1.0 or rms amplitude of 0.7 If the input goes above 0dB, the output can optionally be limited by setting @code(limit:) (a keyword parameter) to @code(T). This effectively changes the compression ratio to infinity at 0dB. If @code(limit:) is @code(nil) (the default), then the compression-ratio continues to apply above 0dB. Another keyword parameter, @code(transition:), sets the amount below the thresholds (in dB) that a smooth transition starts. The default is 0, meaning that there is no smooth transition. The smooth transition is a 2nd-order polynomial that matches the slopes of the straight-line compression curve and interpolates between them. It is assumed that expand-threshold <= compress-threshold <= 0 The gain is unity at 0dB so if compression-ratio > 1, then gain will be greater than unity below 0dB. The result returned by this function is a sound for use in the @code(shape) function. The sound maps input dB to gain. Time 1.0 corresponds to 0dB, time 0.0 corresponds to -100 dB, and time 2.0 corresponds to +100dB, so this is a 100hz ``sample rate'' sound. The sound gives gain in dB. @codef[db-average(@pragma(defn)@index(db-average)@i(input))] @c{[sal]}@* @altdef{@code[(db-average @i(input))] @c{[lisp]}}@\Compute the average amplitude of @i(input) in dB. @codef{compress(@pragma(defn)@index(compress)@i(input), @i(map), @i(rise-time), @i(fall-time) [, @i(lookahead)])} @c{[sal]}@* @altdef{@code[(compress @i(input) @i(map) @i(rise-time) @i(fall-time) [@i(lookahead)])] @c{[lisp]}}@\Compress @i(input) using @i(map), a compression curve probably generated by @code(compress-map) (see above). Adjustments in gain have the given @i(rise-time) and @i(fall-time). Lookahead tells how far ahead to look at the signal, and is @i(rise-time) by default. @codef{agc(@index(automatic gain control)@pragma(defn)@index(agc)@index(gain)@i(input), @i(range), @i(rise-time), @i(fall-time) [, @i(lookahead)])} @c{[sal]}@* @altdef{@code{(agc @i(input) @i(range) @i(rise-time) @i(fall-time) [@i(lookahead)])} @c{[lisp]}}@\An automatic gain control applied to @i(input). The maximum gain in dB is @i(range). Peaks are attenuated to 1.0, and gain is controlled with the given @i(rise-time) and @i(fall-time). The look-ahead time default is @i(rise-time). @end(fndefs) @section(Clipping Softener) This library, in @code(soften.lsp), was written to improve the quality of poorly recorded speech. In recordings of speech, extreme clipping generates harsh high frequency noise. This can sound particulary bad on small speakers that will emphasize high frequencies. This problem can be ameliorated by low-pass filtering regions where clipping occurs. The effect is to dull the harsh clipping. Intelligibility is not affected by much, and the result can be much more pleasant on the ears. Clipping is detected simply by looking for large signal values. Assuming 8-bit recording, this level is set to 126/127. The function works by cross-fading between the normal signal and a filtered signal as opposed to changing filter coefficients. @begin(fndefs) @codef[soften-clipping(@pragma(defn)@index(soften-clipping)@index(clipping repair)@i(snd), @i(cutoff))] @c{[sal]}@* @altdef{@code[(soften-clipping @i(snd) @i(cutoff))] @c{[lisp]}}@\Filter the loud regions of a signal where clipping is likely to have generated additional high frequencies. The input signal is @i(snd) and @i(cutoff) is the filter cutoff frequency (4 kHz is recommended for speech). @end(fndefs) @section(Graphical Equalizer) There's nothing really ``graphical'' about this library (@code(grapheq.lsp)), but this is a common term for multi-band equalizers. This implementation uses Nyquist's @code(eq-band) function to split the incoming signal into different frequency bands. Bands are spaced geometrically, e.g. each band could be one octave, meaning that each successive band has twice the bandwidth. An interesting possibility is using computed control functions to make the equalization change over time. @begin(fndefs) @codef[nband-range(@pragma(defn)@index(nband-range)@index(graphical equalizer)@index(equalization)@i(input), @i(gains), @i(lowf), @i(highf))] @c{[sal]}@* @altdef{@code[(nband-range @i(input) @i(gains) @i(lowf) @i(highf))] @c{[lisp]}}@\A graphical equalizer applied to @i(input) (a @code(SOUND)). The gain controls and number of bands is given by @i(gains), an ARRAY of @code(SOUND)s (in other words, a Nyquist multichannel @code(SOUND)). Any sound in the array may be replaced by a @code(FLONUM). The bands are geometrically equally spaced from the lowest frequency @i(lowf) to the highest frequency @i(highf) (both are @code(FLONUM)s). @codef[nband(@pragma(defn)@index(nband)@i(input), @i(gains))] @c{[sal]}@* @altdef{@code[(nband @i(input) @i(gains))] @c{[lisp]}}@\A graphical equalizer, identical to @code(nband-range) with a range of 20 to 20,000 Hz. @end(fndefs) @section(Sound Reversal) The @code(reverse.lsp) library implements functions to play sounds in reverse. @begin(fndefs) @codef[s-reverse(@index(reverse, sound)@pragma(defn)@index(s-reverse)@index(backward)@index(play in reverse)@i(snd))] @c{[sal]}@* @altdef{@code[(s-reverse @i(snd))] @c{[lisp]}}@\Reverses @i(snd) (a @code(SOUND)). Sound must be shorter than @code(*max-reverse-samples*), which is currently initialized to 25 million samples. Reversal allocates about 4 bytes per sample. This function uses XLISP in the inner sample loop, so do not be surprised if it calls the garbage collector a lot and runs slowly. The result starts at the starting time given by the current environment (not necessarily the starting time of @i(snd)). If @i(snd) has multiple channels, a multiple channel, reversed sound is returned. @codef{s-read-reverse(@index(read samples in reverse)@pragma(defn)@index(s-read-reverse)@i(filename), time-offset: @i(offset), srate: @i(sr), dur: @i(dur), nchans: @i(chans), format: @i(format), mode: @i(mode), bits: @i(n), swap: @i(flag))} @c{[sal]}@* @altdef{@code{(s-read-reverse @i(filename) :time-offset @i(offset) :srate @i(sr) :dur @i(dur) :nchans @i(chans) :format @i(format) :mode @i(mode) :bits @i(n) :swap @i(flag))} @c{[lisp]}}@\This function is identical to @code(s-read) (see @ref(s-read-sec)), except it reads the indicated samples in reverse. Like @code(s-reverse) (see above), it uses XLISP in the inner loop, so it is slow. Unlike @code(s-reverse), @code(s-read-reverse) uses a fixed amount of memory that is independent of how many samples are computed. Multiple channels are handled. @end(fndefs) @section(Time Delay Functions) The @code(time-delay-fns.lsp) library implements chorus, phaser, and flange effects. @begin(fndefs) @codef[phaser(@pragma(defn)@index(phaser)@index(effects, phaser)@i(snd))] @c{[sal]}@* @altdef{@code[(phaser @i(snd))] @c{[lisp]}}@\A phaser effect applied to @i(snd) (a @code(SOUND)). There are no parameters, but feel free to modify the source code of this one-liner. @codef[flange(@pragma(defn)@index(flange)@index(flange effect)@index(effect, flange)@i(snd))] @c{[sal]}@* @altdef{@code[(flange @i(snd))] @c{[lisp]}}@\A flange effect applied to @i(snd). To vary the rate and other parameters, see the source code. @codef[stereo-chorus(@index(chorus)@pragma(defn)@index(stereo-chorus)@i(snd))] @c{[sal]}@* @altdef{@code[(stereo-chorus @i(snd))] @c{[lisp]}}@\A chorus effect applied to @i(snd), a @code(SOUND) (monophonic). The output is a stereo sound. All parameters are built-in, but see the simple source code to make modifications. @codef[chorus(@pragma(defn)@index(chorus)@index(effect, chorus)@i(snd), @i(maxdepth), @i(depth), @i(rate), @i(saturation))] @c{[sal]}@* @altdef{@code[(chorus @i(snd) @i(maxdepth) @i(depth) @i(rate) @i(saturation))] @c{[lisp]}}@\A chorus effect applied to @i(snd). All parameters may be arrays as usual. The @i(maxdepth) is a @code(FLONUM) giving twice the maximum value of @i(depth), which may be a @code(FLONUM) or a @code(SOUND). The chorus is implemented as a variable delay modulated by a sinusoid running at @i(rate) Hz (a @code(FLONUM)). The sinusoid is scaled by @i(depth) and offset by @i(maxdepth)/2. The delayed signal is mixed with the original, and @i(saturation) gives the fraction of the delayed signal (from 0 to 1) in the mix. A reasonable choice of parameter values is @i(maxdepth) = 0.05, @i(depth) = 0.025, @i(rate) = 0.5, and @i(saturation) = 0.5. @end(fndefs) @section(Multiple Band Effects) @index(multiple band effects)@index(bandfx.lsp) The @code(bandfx.lsp) library implements several effects based on multiple frequency bands. The idea is to separate a signal into different frequency bands, apply a slightly different effect to each band, and sum the effected bands back together to form the result. This file includes its own set of examples. After loading the file, try @code[f2()], @code[f3()], @code[f4()], and @code[f5()] to hear them. There is much room for expansion and experimentation with this library. Other effects might include distortion in certain bands (for example, there are commercial effects that add distortion to low frequencies to enhance the sound of the bass), separating bands into different channels for stereo or multi-channel effects, adding frequency-dependent reverb, and performing dynamic compression, limiting, or noise gate functions on each band. There are also opportunities for cross-synthesis: using the content of bands extracted from one signal to modify the bands of another. The simplest of these would be to apply amplitude envelopes of one sound to another. Please contact us (dannenberg@@cs.cmu.edu) if you are interested in working on this library. @begin(fndefs) @codef[apply-banded-delay(@index(banded delay)@pragma(defn)@index(apply-banded-delay)@i(s), @i(lowp), @i(highp), @i(num-bands), @i(lowd), @i(highd), @i(fb), @i(wet))] @c{[sal]}@* @altdef{@code[(apply-banded-delay @i(s) @i(lowp) @i(highp) @i(num-bands) @i(lowd) @i(highd) @i(fb) @i(wet))] @c{[lisp]}}@\Separates input @code(SOUND) @i(s) into @code(FIXNUM) @i(num-bands) bands from a low frequency of @i(lowp) to a high frequency of @i(highp) (these are @code(FLONUMS) that specify steps, not Hz), and applies a delay to each band. The delay for the lowest band is given by the @code(FLONUM) @i(lowd) (in seconds) and the delay for the highest band is given by the @code(FLONUM) @i(highd). The delays for other bands are linearly interpolated between these values. Each delay has feedback gain controlled by @code(FLONUM) @i(fb). The delayed bands are scaled by @code(FLONUM) @i(wet), and the original sound is scaled by 1 - @i(wet). All are summed to form the result, a @code(SOUND). @codef[apply-banded-bass-boost(@index(banded bass boost)@pragma(defn)@index(apply-banded-bass-boost)@i(s), @i(lowp), @i(highp), @i(num-bands), @i(num-boost), @i(gain))] @c{[sal]}@* @altdef{@code[(apply-banded-bass-boost @i(s) @i(lowp) @i(highp) @i(num-bands) @i(num-boost) @i(gain))] @c{[lisp]}}@\Applies a boost to low frequencies. Separates input @code(SOUND) @i(s) into @code(FIXNUM) @i(num-bands) bands from a low frequency of @i(lowp) to a high frequency of @i(highp) (these are @code(FLONUMS) that specify steps, not Hz), and scales the lowest @i(num-boost) (a @code(FIXNUM)) bands by @i(gain), a @code(FLONUM). The bands are summed to form the result, a @code(SOUND). @codef[apply-banded-treble-boost(@index(banded treble boost)@pragma(defn)@index(apply-banded-treble-boost)@i(s), @i(lowp), @i(highp), @i(num-bands), @i(num-boost), @i(gain))] @c{[sal]}@* @altdef{@code[(apply-banded-treble-boost @i(s) @i(lowp) @i(highp) @i(num-bands) @i(num-boost) @i(gain))] @c{[lisp]}}@\Applies a boost to high frequencies. Separates input @code(SOUND) @i(s) into @code(FIXNUM) @i(num-bands) bands from a low frequency of @i(lowp) to a high frequency of @i(highp) (these are @code(FLONUMS) that specify steps, not Hz), and scales the highest @i(num-boost) (a @code(FIXNUM)) bands by @i(gain), a @code(FLONUM). The bands are summed to form the result, a @code(SOUND). @end(fndefs) @section(Granular Synthesis) Some granular synthesis functions are implemented in the @code(gran.lsp) library file. There are many variations and control schemes one could adopt for granular synthesis, so it is impossible to create a single universal granular synthesis function. One of the advantages of Nyquist is the integration of control and synthesis functions, and users are encouraged to build their own granular synthesis functions incorporating their own control schemes. The @code(gran.lsp) file includes many comments and is intended to be a useful starting point. Another possibility is to construct a score with an event for each grain. Estimate a few hundred bytes per score event (obviously, size depends on the number of parameters) and avoid using all of your computer's memory. @begin(fndefs) @codef{sf-granulate(@index(granular synthesis)@pragma(defn)@index(sf-granulate)@i(filename), @i(grain-dur), @i(grain-dev), @i(ioi), @i(ioi-dev), @i(pitch-dev), [@i(file-start), @i(file-end)])} @c{[sal]}@* @altdef{@code{(sf-granulate @i(filename) @i(grain-dur) @i(grain-dev) @i(ioi) @i(ioi-dev) @i(pitch-dev) [@i(file-start) @i(file-end)])} @c{[lisp]}}@\Granular synthesis using a sound file named @i(filename) as the source for grains. Grains are extracted from a sound file named by @i(filename) by stepping through the file in equal increments. Each grain duration is the sum of @i(grain-dur) and a random number from 0 to @i(grain-dev). Grains are then multiplied by a raised cosine smoothing window and resampled at a ratio between 1.0 and @i(pitch-dev). If @i(pitch-dev) is greater than one, grains are stretched and the pitch (if any) goes down. If @i(pitch-dev) is less than one, grains are shortened and the pitch goes up. Grains are then output with an inter-onset interval between successive grains (which may overlap) determined by the sum of @i(ioi) and a random number from 0 to @i(ioi-dev). The duration of the resulting sound is determined by the stretch factor (not by the sound file). The number of grains is the total sound duration (determined by the stretch factor) divided by the mean inter-onset interval, which is @i(ioi) + @i(ioi-dev) * 0.5. The grains are taken from equally-spaced starting points in @i(filename), and depending on grain size and number, the grains may or may not overlap. The output duration will simply be the sum of the inter-onset intervals and the duration of the last grain. If @i(ioi-dev) is non-zero, the output duration will vary, but the expected value of the duration is the stretch factor. To achieve a rich granular synthesis effect, it is often a good idea to sum four or more copies of @code(sf-granulate) together. (See the @code(gran-test) function in @code(gran.lsp).) @end(fndefs) @section(MIDI Utilities) The @code(midishow.lsp) library has functions that can print the contents fo MIDI files. This intended as a debugging aid. @begin(fndefs) @codef[midi-show-file(@pragma(defn)@index(midi-show-file)@index(print midi file)@index(show midi file)@i(file-name))] @c{[sal]}@* @altdef{@code[(midi-show-file @i(file-name))] @c{[lisp]}}@\Print the contents of a MIDI file to the console. @codef{midi-show(@pragma(defn)@index(midi-show)@i(the-seq) [, @i(out-file)])} @c{[sal]}@* @altdef{@code{(midi-show @i(the-seq) [@i(out-file)])} @c{[lisp]}}@\Print the contents of the sequence @i(the-seq) to the file @i(out-file) (whose default value is the console.) @end(fndefs) @section(Reverberation) The @code(reverb.lsp) library implements artificial reverberation. @begin(fndefs) @codef[reverb(@pragma(defn)@index(reverb)@index(effect, reverberation)@i(snd), @i(time))] @c{[sal]}@* @altdef{@code[(reverb @i(snd) @i(time))] @c{[lisp]}}@\Artificial reverberation applied to @i(snd) with a decay time of @i(time). @end(fndefs) @section(DTMF Encoding) @index(dtmf)@index(touch tone) The @code(dtmf.lsp) library implements DTMF encoding. DTMF is the ``touch tone'' code used by telephones. @begin(fndefs) @codef[dtmf-tone(@pragma(defn)@index(dtmf-tone)@i(key), @i(len), @i(space))] @c{[sal]}@* @altdef{@code[(dtmf-tone @i(key) @i(len) @i(space))] @c{[lisp]}}@\Generate a single DTMF tone. The @i(key) parameter is either a digit (a @code(FIXNUM) from 0 through 9) or the atom @code(STAR) or @code(POUND). The duration of the done is given by @i(len) (a @code(FLONUM)) and the tone is followed by silence of duration @i(space) (a @code(FLONUM)). @codef[speed-dial(@pragma(defn)@index(speed-dial)@i(thelist))] @c{[sal]}@* @altdef{@code[(speed-dial @i(thelist))] @c{[lisp]}}@\Generates a sequence of DTMF tones using the keys in @i(thelist) (a @code(LIST) of keys as described above under @code(dtmf-tone)). The duration of each tone is 0.2 seconds, and the space between tones is 0.1 second. Use @code(stretch) to change the ``dialing'' speed. @end(fndefs) @section[Dolby Surround(R), Stereo and Spatialization Effects] @index(spatialization)@index(stereo)@index(pan)@index(Dolby Surround) The @code(spatial.lsp) library implements various functions for stereo manipulation and spatialization. It also includes some functions for Dolby Pro-Logic panning, which encodes left, right, center, and surround channels into stereo. The stereo signal can then be played through a Dolby decoder to drive a surround speaker array. This library has a somewhat simplified encoder, so you should certainly test the output. Consider using a high-end encoder for critical work. There are a number of functions in @code(spatial.lsp) for testing. See the source code for comments about these. @begin(fndefs) @codef[stereoize(@pragma(defn)@index(stereoize)@index(mono to stereo)@index(effect, stereo)@i(snd))] @c{[sal]}@* @altdef{@code[(stereoize @i(snd))] @c{[lisp]}}@\Convert a mono sound, @i(snd), to stereo. Four bands of equalization and some delay are used to create a stereo effect. @codef[widen(@pragma(defn)@index(widen)@index(effect, widen)@i(snd), @i(amt))] @c{[sal]}@* @altdef{@code[(widen @i(snd) @i(amt))] @c{[lisp]}}@\Artificially widen the stereo field in @i(snd), a two-channel sound. The amount of widening is @i(amt), which varies from 0 (@i(snd) is unchanged) to 1 (maximum widening). The @i(amt) can be a @code(SOUND) or a number. @codef[span(@index(stereo pan)@index(pan, stereo)@index(effect, stereo pan)@pragma(defn)@index(span)@i(snd), @i(amt))] @c{[sal]}@* @altdef{@code[(span @i(snd) @i(amt))] @c{[lisp]}}@\Pan the virtual center channel of a stereo sound, @i(snd), by @i(amt), where 0 pans all the way to the left, while 1 pans all the way to the right. The @i(amt) can be a @code(SOUND) or a number. @codef[swapchannels(@pragma(defn)@index(swapchannels)@index(swap channels)@index(effect, swap channels)@i(snd))] @c{[sal]}@* @altdef{@code[(swapchannels @i(snd))] @c{[lisp]}}@\Swap left and right channels in @i(snd), a stereo sound. @codef[prologic(@pragma(defn)@index(prologic)@index(Dolby Pro-Logic)@index(Surround Sound)@i(l), @i(c), @i(r), @i(s))] @c{[sal]}@* @altdef{@code[(prologic @i(l) @i(c) @i(r) @i(s))] @c{[lisp]}}@\Encode four monaural @code(SOUND)s representing the front-left, front-center, front-right, and rear channels, respectively. The return value is a stereo sound, which is a Dolby-encoded mix of the four input sounds. @codef[pl-left(@pragma(defn)@index(pl-left)@i(snd))] @c{[sal]}@* @altdef{@code[(pl-left @i(snd))] @c{[lisp]}}@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the front left channel. @codef[pl-center(@pragma(defn)@index(pl-center)@i(snd))] @c{[sal]}@* @altdef{@code[(pl-center @i(snd))] @c{[lisp]}}@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the front center channel. @codef[pl-right(@pragma(defn)@index(pl-right)@i(snd))] @c{[sal]}@* @altdef{@code[(pl-right @i(snd))] @c{[lisp]}}@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the front right channel. @codef[pl-rear(@pragma(defn)@index(pl-rear)@i(snd))] @c{[sal]}@* @altdef{@code[(pl-rear @i(snd))] @c{[lisp]}}@\Produce a Dolby-encoded (stereo) signal with @i(snd), a @code(SOUND), encoded as the rear, or surround, channel. @codef[pl-pan2d(@pragma(defn)@index(pl-pan2d)@i(snd), @i(x), @i(y))] @c{[sal]}@* @altdef{@code[(pl-pan2d @i(snd) @i(x) @i(y))] @c{[lisp]}}@\Comparable to Nyquist's existing pan function, @code(pl-pan2d) provides not only left-to-right panning, but front-to-back panning as well. The function accepts three parameters: @i(snd) is the (monophonic) input @code(SOUND), @i(x) is a left-to-right position, and @i(y) is a front-to-back position. Both position parameters may be numbers or @code(SOUND)s. An @i(x) value of 0 means left, and 1 means right. Intermediate values map linearly between these extremes. Similarly, a @i(y) value of 0 causes the sound to play entirely through the front speakers(s), while 1 causes it to play entirely through the rear. Intermediate values map linearly. Note that, although there are usually two rear speakers in Pro-Logic systems, they are both driven by the same signal. Therefore any sound that is panned totally to the rear will be played over both rear speakers. For example, it is not possible to play a sound exclusively through the rear left speaker. @codef[pl-position(@pragma(defn)@index(pl-position)@i(snd), @i(x), @i(y), @i(config))] @c{[sal]}@* @altdef{@code[(pl-position @i(snd) @i(x) @i(y) @i(config))] @c{[lisp]}}@\The position function builds upon speaker panning to allow more abstract placement of sounds. Like @code(pl-pan2d), it accepts a (monaural) input sound as well as left-to-right (@i(x)) and front-to-back (@i(y)) coordinates, which may be @code(FLONUM)s or @code(SOUND)s. A fourth parameter @i(config) specifies the distance from listeners to the speakers (in meters). Current settings assume this to be constant for all speakers, but this assumption can be changed easily (see comments in the code for more detail). There are several important differences between @code(pl-position) and @code(pl-pan2d). First, @code(pl-position) uses a Cartesian coordinate system that allows x and y coordinates outside of the range (0, 1). This model assumes a listener position of (0,0). Each speaker has a predefined position as well. The input sound's position, relative to the listener, is given by the vector (@i(x),@i(y)). @codef[pl-doppler(@pragma(defn)@index(pl-doppler)@index(Doppler effect)@i(snd), @i(r))] @c{[sal]}@* @altdef{@code[(pl-doppler @i(snd) @i(r))] @c{[lisp]}}@\Pitch-shift moving sounds according to the equation: @i(fr) = @i(f0)((@i(c)+@i(vr))/@i(c)), where @i(fr) is the output frequency, @i(f0) is the emitted (source) frequency, @i(c) is the speed of sound (assumed to be 344.31 m/s), and @i(vr) is the speed at which the emitter approaches the receiver. (@i(vr) is the first derivative of parameter @i(r), the distance from the listener in meters. @end(fndefs) @section(Drum Machine) @label(drum-machine-sec)@index(drum machine) The drum machine software in @code(demos/plight) deserves further explanation. to use the software, load the code by evaluating: @begin(example) load "../demos/plight/drum.lsp" exec load-props-file(strcat(*plight-drum-path*, "beats.props")) exec create-drum-patches() exec create-patterns() @end(example) Drum sounds and patterns are specified in the @code(beats.props) file (or whatever name you give to @code(load-props-file)). This file contains two types of specifications. First, there are sound file specifications. Sound files are located by a line of the form: @begin(example) set sound-directory = "kit/" @end(example) This gives the name of the sound file directory, relative to the @code(beats.props) file. Then, for each sound file, there should be a line of the form: @begin(example) track.2.5 = big-tom-5.wav @end(example) This says that on track 2, a velocity value of 5 means to play the sound file @code(big-tom-5.wav). (Tracks and velocity values are described below.) The @code(beats.props) file contains specifications for all the sound files in @code(demos/plight/kit) using 8 tracks. If you make your own specifications file, tracks should be numbered consecutively from 1, and velocities should be in the range of 1 to 9. The second set of specifications is of beat patterns. A beat pattern is given by a line in the following form: @begin(example) beats.5 = 2--32--43-4-5--- @end(example) The number after @code(beats) is just a pattern number. Each pattern is given a unique number. After the equal sign, the digits and dashes are velocity values where a dash means ``no sound.'' Beat patterns should be numbered consecutively from 1. Once data is loaded, there are several functions to access drum patterns and create drum sounds (described below). The @code(demos/plight/drums.lsp) file contains an example function @code(plight-drum-example) to play some drums. There is also the file @code(demos/plight/beats.props) to serve as an example of how to specify sound files and beat patterns. @begin(fndefs) @codef{drum(@pragma(defn)@index(drum)@i(tracknum), @i(patternnum), @i(bpm))} @c{[sal]}@* @altdef{@code[(drum @i(tracknum) @i(patternnum) @i(bpm))] @c{[lisp]}}@\Create a sound by playing drums sounds associated with track @i(tracknum) (a FIXNUM) using pattern @i(patternnum). The tempo is given by @i(bpm) in beats per minute. Normally patterns are a sequence of sixteenth notes, so the tempo is in @i(sixteenth notes per minute). For example, if @i(patternnum) is 10, then use the pattern specified for @code(beats.10). If the third character of this pattern is 3 and @i(tracknum) is 5, then on the third beat, play the soundfile assigned to @code(track.5.3). This function returns a @code(SOUND). @codef{drum-loop(@pragma(defn)@index(drum-loop)@i(snd), @i(duration), @i(numtimes))} @c{[sal]}@* @altdef{@code[(drum-loop @i(snd) @i(duration) @i(numtimes))] @c{[lisp]}}@\Repeat the sound given by @i(snd) @i(numtimes) times. The repetitions occur at a time offset of @i(duration), regardless of the actual duration of @i(snd). A @code(SOUND) is returned. @codef{length-of-beat(@pragma(defn)@index(length-of-beat)@i(bpm))} @c{[sal]}@* @altdef{@code[(length-of-beat @i(bpm))] @c{[lisp]}}@\Given a tempo of @i(bpm), return the duration of the beat in seconds. Note that this software has no real notion of beat. A ``beat'' is just the duration of each character in the beat pattern strings. This function returns a @code(FLONUM). @end(fndefs) @section(Minimoog-inspired Synthesis) @index(Moog)@index(Minimoog)@index(analog synthesizer) The @code(moog.lsp) library gives the Nyquist user easy access to ``classic'' synthesizer sounds through an emulation of the Minimoog Synthesizer. Unlike modular Moogs that were very large, the Minimoog was the first successful and commonly used portable synthesizer. The trademark filter attack was unique and easily recognizable. The goal of this Nyquist instrument is not only to provide the user with default sounds, but also to give control over many of the ``knobs'' found on the Minimoog. In this implementation, these parameters are controlled using keywords. The input to the @code(moog) instrument is a user-defined sequence of notes, durations, and articulations that simulate notes played on a keyboard. These are translated into control voltages that drive multiple oscillators, similar to the Voltage Controlled Oscillator or VCO found in the original analog Moog. The basic functionality of the Minimoog has been implemented, including the often-used "glide". The glide feature essentially low-pass filters the control voltage sequence in order to create sweeps between notes. Figure @ref(moog-fig) is a simplified schematic of the data flow in the Moog. The control lines have been omitted. @begin(figure) @center(@graphic((height = 2.514 in, width = 4.65 in, magnify = 0.3, postscript = "moog-fig.ps")) @html(

    ) @fillcaption(System diagram for Minimoog emulator.) @tag(moog-fig) @end(figure) The most recognizable feature of the Minimoog is its resonant filter, a Four-Pole Ladder Filter invented by Robert Moog. It is simply implemented in a circuit with four transistors and provides an outstanding 24 dB/octave rolloff. It is modeled here using the built-in Nyquist resonant filter. One of the Moog filter features is a constant Q, or center frequency to bandwidth ratio. This is implemented and the user can control the Q. The user can control many parameters using keywords. Their default values, acceptable ranges, and descriptions are shown below. The defaults were obtained by experimenting with the official Minimoog software synthesizer by Arturia. @subsection(Oscillator Parameters) @code(range-osc1) (2)@* @code(range-osc2) (1)@* @code(range-osc3) (3)@* These parameters control the octave of each oscillator. A value of 1 corresponds to the octave indicated by the input note. A value of 3 is two octaves above the fundamental. The allowable range is 1 to 7. @code(detun2) (-.035861)@* @code(detun3) (.0768)@* Detuning of two oscillators adds depth to the sound. A value of 1 corresponds to an increase of a single semitone and a -1 corresponds to a decrease in a semitone. The range is -1 to 1. @code(shape-osc1) (@code(*saw-table*))@* @code(shape-osc2) (@code(*saw-table*))@* @code(shape-osc3) (@code(*saw-table*))@* Oscilators can use any wave shape. The default sawtooth waveform is a built-in Nyquist variable. Other waveforms can be defined by the user. @code(volume-osc1) (1)@* @code(volume-osc2) (1)@* @code(volume-osc3) (1)@* These parameters control the relative volume of each oscillator. The range is any @code(FLONUM) greater than or equal to zero. @subsection(Noise Parameters) @code(noiselevel) (.05)@* This parameter controls the relative volume of the noise source. The range is any @code(FLONUM) greater than or equal to zero. @subsection(Filter Parameters) @code(filter-cutoff) (768)@* The cutoff frequency of the filter in given in Hz. The range is zero to 20,000 Hz. @code(Q) (2)@* Q is the ratio of center frequency to bandwidth. It is held constant by making the bandwidth a function of frequency. The range is any @code(FLONUM) greater than zero. @code(contour) (.65)@* Contour controls the range of the transient frequency sweep from a high to low cutoff frequency when a note is played. The high frequency is proportional to contour. A contour of 0 removes this sweep. The range is 0 to 1. @code(filter-attack) (.0001)@* Filter attack controls the attack time of the filter, i.e. the time to reach the high cutoff frequency. The range is any @code(FLONUM) greater than zero (seconds). @code(filter-decay) (.5)@* Filter decay controls the decay time of the filter, i.e. the time of the sweep from the high to low cutoff frequency. The range is any @code(FLONUM) greater than zero (seconds). @code(filter-sustain) (.8)@* Filter sustain controls the percentage of the filter cutoff frequency that the filter settles on following the sweep. The range is 0 to 1. @subsection(Amplitude Parameters) @code(amp-attack) (.01)@* This parameter controls the amplitude envelope attack time, i.e. the time to reach maximum amplitude. The range is any @code(FLONUM) greater than zero (seconds). @code(amp-decay) (1)@* This parameter controls the amplitude envelope decay time, i.e. the time between the maximum and sustain volumes. The range is any @code(FLONUM) greater than zero (seconds). @code(amp-sustain) (1)@* This parameter controls the amplitude envelope sustain volume, a fraction of the maximum. The range is 0 to 1. @code(amp-release) (0)@* This parameter controls the amplitude envelope release time, i.e. the time it takes between the sustain volume and 0 once the note ends. The duration controls the overall length of the sound. The range of @code(amp-release) is any @code(FLONUM) greater than zero (seconds). @subsection(Other Parameters) @code(glide) (0)@* Glide controls the low-pass filter on the control voltages. This models the glide knob on a Minimoog. A higher value corresponds to a lower cutoff frequency and hence a longer "glide" between notes. A value of 0 corresponds to no glide. The range is zero to 10. @subsection(Input Format) A single note or a series of notes can be input to the Moog instrument by defining a list with the following format: @begin(example) list(list(@i(frequency), @i(duration), @i(articulation)), @r(...) ) @end(example) where @i(frequency) is a @code(FLONUM) in steps, @i(duration) is the duration of each note in seconds (regardless of the release time of the amplifier), and @i(articulation) is a percentage of the duration that a sound will be played, representing the amount of time that a key is pressed. The filter and amplitude envelopes are only triggered if a note is played when the articulation of the previous note is less than 1, or a key is not down at the same time. This Moog instrument is a monophonic instrument, so only one note can sound at a time. The release section of the amplifier is triggered when the articulation is less than 1 at the time (@i(duration) * @i(articulation)). @subsection(Sample Code/Sounds) @b[Sound 1 (default parameters):] @begin(display) @begin(code) set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99} {29 .5 .99} {31 2 1}} play moog(s) @end(code) @end(display) @b[Sound 2 (articulation, with amplitude release):] @begin(display) @begin(code) set s = {{24 .5 .5} {26 .5 1} {28 .5 .25} {29 .5 1} {31 1 .8}} play moog(s, amp-release: .2) @end(code) @end(display) @b[Sound 3 (glide):] @begin(display) @begin(code) set s = {{24 .5 .5} {38 .5 1} {40 .5 .25} {53 .5 1} {55 2 1} {31 2 .8} {36 2 .8}} play moog(s, amp-release: .2, glide: .5) @end(code) @end(display) @b[Sound 4 (keyword parameters):] Filter attack and decay are purposely longer than notes being played with articulation equal to 1. @begin(display) @begin(code) set s = {{20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1} {20 .5 1} {27 .5 1} {26 .5 1} {21 .5 1}} play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*, filter-attack: 2, filter-decay: 2, filter-cutoff: 300, contour: .8, glide: .2, Q: 8) @end(code) @end(display) @b[Sound 5:] This example illustrates the ability to completely define a new synthesizer with different parameters creating a drastically different sound. Sine waves are used for wavetables. There is a high value for glide. @begin(display) @begin(code) define function my-moog(freq) return moog(freq, range-osc1: 3, range-osc2: 2, range-osc3: 4, detun2: -.043155, detun3: .015016, noiselevel: 0, filter-cutoff: 400, Q: .1, contour: .0000001, filter-attack: 0, filter-decay: .01, filter-sustain: 1, shape-osc1: *sine-table*, shape-osc2: *sine-table*, shape-osc3: *sine-table*, volume-osc1: 1, volume-osc2: 1, volume-osc3: .1, amp-attack: .1, amp-decay: 0, amp-sustain: 1, amp-release: .3, glide: 2) set s = {{80 .4 .75} {28 .2 1} {70 .5 1} {38 1 .5}} play my-moog(s) @end(code) @end(display) @b[Sound 6:] This example has another variation on the default parameters. @begin(display) @begin(code) set s = {{24 .5 .99} {26 .5 .99} {28 .5 .99} {29 .5 .99} {31 2 1}} play moog(s, shape-osc1: *tri-table*, shape-osc2: *tri-table*, filter-attack: .5, contour: .5) @end(code) @end(display) @pragma(doinclude) @include(nymanimpl.mss) @appendix(Open Sound Control and Nyquist)@index(Open Sound Control) @label(osc-app) Open Sound Control (OSC) is a simple protocol for communicating music control parameters between software applications and across networks. For more information, see @html[]@code(http://www.cnmat.berkeley.edu/OpenSoundControl/)@html[]. The Nyquist implementation of Open Sound Control is simple: an array of floats can be set by OSC messages and read by Nyquist functions. That is about all there is to it. Note: Open Sound Control must be enabled by calling @code[osc-enable(t)]. If this fails under Windows, see the installation instructions in @code(sys/win/README.txt) regarding @code(SystemRoot). To control something in (near) real-time, you need to access a slider value as if it a signal, or more properly, a Nyquist @code(SOUND) type. The function @code(snd-slider), described in Section @ref(snd-slider-sec), takes a slider number and returns a @code(SOUND) type representing the current value of the slider. To fully understand this function, you need to know something about how Nyquist is actually computing sounds. Sounds are normally computed on demand. So the result returned by @code(snd-slider) does not immediately compute any samples. Samples are only computed when something tries to use this signal. At that time, the slider value is read. Normally, if the slider is used to control a sound, you will hear changes in the sound pretty soon after the slider value changes. However, one thing that can interfere with this is that @code(SOUND) samples are computed in blocks of about 1000 samples. When the slider value is read, the same value is used to fill a block of 1000 samples, so even if the sample rate is 44,100 Hz, the effective slider sample rate is 44,100/1000, or 44.1 Hz. If you give the slider a very low sample rate, say 1000, then slider value changes will only be noticed by Nyquist approximately once per second. For this reason, you should normally use the audio sample rate (typically 44,100 Hz) for the rate of the @code(snd-slider) output @code(SOUND). (Yes, this is terribly wasteful to represent each slider value with 1000 samples, but Nyquist was not designed for low-latency computation, and this is an expedient work-around.) In addition to reading sliders as continually changing @code(SOUND)s, you can get the slider value as a Lisp @code(FLONUM) (a floating point number) using @code(get-slider-value), described in Section @ref(get-slider-value-sec). This might be useful if you are computing a sequence of many notes (or other sound events) and want to apply the current slider value to the whole note or sound event. Note that if you store the value returned by @code(snd-slider) in a variable, you will capture the history of the slider changes. This will take a lot of memory, so be careful. Suppose you write a simple expression such as @code[(hzosc (mult 1000 (snd-slider 0 @r(...))))] (or in SAL, @code[hzosc(1000 * snd-slider(0 @r(...)))]) to control an oscillator frequency with a slider. How long does this sound last? The duration of @code[hzosc] is the duration of the frequency control, so what is the duration of a slider? To avoid infinitely long signals, you must specify a duration as one of the parameters of @code[snd-slider]. You might be thinking, what if I just want to tell the slider when to stop? At present, you cannot do that, but in the future there should be a function that stops when its input goes to zero. Then, moving a slider to zero could end the signal (and if you multiplied a complex sound by one of these ending functions, everything in the sound would end and be garbage collected). Another thing you might want to do with interactive control is start some sound. The @code(trigger) function computes an instance of a behavior each time an input @code(SOUND) goes from zero to greater-than-zero. This could be used, for example, to create a sequence of notes. The @code(snd-slider) function has some parameters that may be unfamiliar. The second parameter, @i(t0), is the starting time of the sound. This should normally be @code[local-to-global(0)], an expression that computes the instantiation time of the current expression. This will often be zero, but if you call @code[snd-slider] from inside a @code(seq) or @code(seq-rep), the starting time may not be zero. The @i(srate) parameter is the sample rate to return. This should normally be the audio sample rate you are working with, which is typically @code[*default-sound-srate*]. @section(Sending Open Sound Control Messages) A variety of programs support OSC. The only OSC message interpreted by Nyquist has an address of @code[/slider], and two parameters: an integer slider number and a float value, nominally from 0.0 to 1.0. Two small programs are included in the Nyquist distribution for sending OSC messages. (Both can be found in the same directory as the nyquist executable.) The first one, @code[osc-test-client] sends a sequence of messages that just cause slider 0 to ramp slowly up and down. If you run this on a command line, you can use "?" or "h" to get help information. There is an interactive mode that lets you send each OSC message by typing RETURN. @section(The ser-to-osc Program) The second program is @code[ser-to-osc], a program that reads serial input (for example from a PIC-based microcontroller) and sends OSC messages. Run this command-line program from a shell (a terminal window under OS X or Linux; use the CMD program under Windows). You must name the serial input device on the command line, e.g. under OS X, you might run: @begin(display) @code(./ser-to-osc /dev/tty.usbserial-0000103D) @end(display) (Note that the program name is preceded by ``@code(./)". This tells the shell exactly where to find the executable program in case the current directory is not on the search path for executable programs.) Under Windows, you might run: @begin(display) @code(ser-to-osc com4) @end(display) (Note that you do not type ``@code(./)'' in front of a windows program.) To use @code(ser-to-osc), you will have to find the serial device. On the Macintosh and Linux, try the following: @begin(display) @code(ls /dev/*usb*) @end(display) This will list all serial devices with ``usb'' in their names. Probably, one will be a name similar to @code(/dev/tty.usbserial-0000103D). The @code(ser-to-osc) program will echo data that it receives, so you should know if things are working correctly. Under Windows, open Control Panel from the Start menu, and open the System control panel. Select the Hardware tab and click the Device Manager button. Look in the device list under Ports (COM & LPT). When you plug in your serial or USB device, you should see a new entry appear, e.g. @code(COM4). This is the device name you need. The format for the serial input is: any non-whitespace character(s), a slider number, a slider value, and a newline (control-j or ASCII 0x0A). These fields need to be separated by tabs or spaces. An optional carriage return (control-m or ASCII 0x0D) preceding the ASCII 0x0A is ignored. The slider number should be in decimal, and theh slider value is a decimal number from 0 to 255. This is scaled to the range 0.0 to 1.0 (so an input of 255 translates to 1.0). There is a simple test program in @code[demos/osc-test.lsp] you can run to try out control with Open Sound Control. There are two examples in that file. One uses @code(snd-slider) to control the frequency of an oscillator. The other uses @code(get-slider-value) to control the pitch of grains in a granular synthesis process. @appendix(Intgen)@index(Intgen) @label(intgen-app) @pragma(doinclude) @include(../xlisp/intgen.mss) @appendix(XLISP: An Object-oriented Lisp) @label(xlisp-app) @begin(center) @b(Version 2.0) February 6, 1988 by @b(David Michael Betz) 127 Taylor Road Peterborough, NH 03458 Copyright (c) 1988, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use @end(center) @newpage @pragma(doinclude) @include(../xlisp/xlisp.mss) nyquist-3.05/docsrc/nyquist/adagio-nyquist.mss0000644000175000000620000011423611466723256020661 0ustar stevestaffAdagio @Index(Adagio) is an easy-to-use, non-procedural notation for scores. In Adagio, text commands are used to specify each note. If you are new to Adagio, you may want to glance at the examples in Section @ref(adag-examples-sec) starting on page @pageref(adag-examples-sec) before reading any further. A note is described in Adagio by a set of attributes@Index(attributes), and any attribute not specified is ``inherited'' from the previous line. Attributes may appear in any order and must be separated by one or more blanks. An attribute may not contain any blanks. The attributes are: time@Index(time), pitch@Index(pitch), loudness@Index(loudness), voice@Index(voice) number, duration@Index(duration), and articulation@Index(articulation). Adagio has been used to program a variety of hardware and software synthesizers, and the Adagio compiler can be easily adapted to new environments. Although not originally intended for MIDI, Adagio works quite well as a representation for MIDI scores. Adagio has been extended to allow MIDI controller data such as modulation wheels, pitch bend, and volume, MIDI program commands to change timbre, and System Exclusive messages. A note command in Adagio must be separated from other notes. Usually, notes are distinguished by writing each one on a separate line. Notes can also be separated by using a comma or semicolon as will be described below. Besides notes, there are several other types of commands: @begin(enumerate) An asterisk@Index(asterisk) (@code(*)) in column one (or immediately after a comma, semicolon, or space) indicates that the rest of the line is a comment@Index(comment). The line is ignored by Adagio, and is therefore a good way to insert text to be read by people. Here are some examples: @begin(programexample) * This is a comment. T150 G4 * This is a comment too! T150 G4 ;* So is this. @end(programexample) An empty command (a blank@Index(blank) line, for example) is ignored as if it were a comment@Index(comment)@foot(To be consistent, a blank line ought to specify zero attributes and generate a note that inherits all of its attributes from the previous one. Adagio is intentionally inconsistent in this respect.). An exclamation point@Index(exclamation point)@index(!) (!) in column one (or immediately after a comma or semicolon) indicates a special command@Index(special command). A special command does not generate a note. Special commands follow the ``!'' with no intervening spaces and extend to the end of the line, for example: @begin(programexample) !TEMPO 100 @end(programexample) Control change commands are used to control parameters like pitch bend, modulation, and program (timbre). Control change commands can be specified along with notes or by themselves. A command that specifies control changes without specifying a pitch will not produce a note. @end(enumerate) Adagio is insensitive to case@Index(case), thus ``A'' is equivalent to ``a'', and you can mix upper and lower case letters freely. @section[Specifying Attributes] A note is indicated by a set of attributes. Attributes are indicated by a string of characters with no intervening spaces because spaces separate attributes. The attributes are described below. The default unit of time is a centisecond (100@+[th]'s), but this can be changed to a millisecond (1000@+[th]'s) using the @code(!MSEC) command and reset to centiseconds with @code(!CSEC) (see Section @ref(millisec-sec)). In the descriptions below, the term ``time unit'' will be used to mean whichever convention is currently in effect. @subsection[Time] The time@Index(time) attribute specifies when to start the note. A time is specified by a ``T@Index(T)'' followed by a number representing time units or by a duration (durations are described below). Examples: @begin(programexample) T150 ** 1.5 sec (or .15 sec) TQ3 ** 3 quarter note's duration @end(programexample) If no time is specified, the default time@Index(default time) is the sum of the time and duration attributes of the previous note. (But see Section @ref(next-time-sec).) Time is measured relative to the time of the most recent Tempo@Index(Tempo) or Rate@Index(Rate) command. (See the examples in Section @ref(adag-examples-sec) for some clarification of this point.) @subsection[Pitch] The pitch@Index(pitch) attribute specifies what frequency to produce. Standard scale pitches are named by name, using @code(S) for sharp@Index(sharp), @code(F) for flat@Index(flat), and (optionally) @code(N) for natural@Index(natural). For example, @code(C) and @code(CN) represent the same pitch, as do @code(FS) and @code(GF) (F sharp and G flat). Note that there are no bar lines, and accidentals to not carry forward to any other notes as in common practice notation. Octaves@Index(octave specification) are specified by number. @code(C4) is middle C, and @code(B3) is a half step lower. @code(F5) is the top line of the treble clef, etc. (Adagio octave numbering follows the ISO standard, but note that this is not universal. In particular, Yamaha refers to middle C as C3.) Accidentals@Index(accidentals)@index[S (Adagio Sharp)]@index[F (Adagio Flat)] can go before or after the octave number, so @code(FS3) and @code(F3S) have the same meaning. An alternate notation for pitch is @code(P)@i(n), where @i(n) is an integer representing the pitch.@index[P (Adagio Pitch)] Middle C@index(Middle C) (C4) is equivalent to @code(P60), @code(CS4) is @code(P61), etc. If you do not specify an octave@Index(octave specification), Adagio will choose one for you. This is done by picking the octave that will make the current pitch as close to the previous pitch as possible. In the case of augmented fourths or diminished fifths, there are two equally good choices. Adagio chooses the lower octave. @subsection[Duration] Duration@Index(duration) is specified by a letter indicating a number of beats, followed by one or several modifiers. The basic duration codes are: @begin(display) @code(W)@Index[W (Adagio Whole note)] (whole@index(whole note), 4 beats), @code(H)@Index[H (Adagio Half note)] (half@index(half note), 2 beats), @code(Q)@Index[Q (Adagio Quarter note)] (quarter@index(quarter note), 1 beat), @code(I)@Index[I (Adagio eIght note)] (eighth@Index(eighth note), 1/2 beat), @code(S)@Index[S (Adagio Sixteenth note)] (sixteenth@Index(sixteenth note), 1/4 beat), @code(%)@Index[% (Adagio thirtysecond note)] (thirtysecond@index(thirtysecond note), 1/8 beat), and @code(^)@index[^ (Adagio sixtyfourth note)] (sixtyfourth@index(sixtyfourth note), 1/16 beat). @end(display) Note that @code(E) is a pitch, so eighth-notes use the duration code @code(I). The default tempo is 100 beats per minute (see Section @ref(tempo-sec)). These codes may be followed by a @code(T) (triplet@Index(triplet)@index[T (Adagio Triplet)]), indicating a duration of 2/3 the normal. A dot@Index(dot)@index[. (Adagio)] (@code(.)) after a duration code extends it by half to 3/2 the normal. An integer after a note multiplies its duration by the indicated value (the result is still just one note). Finally, a slash followed by an integer divides the duration by the integer. Like all attributes, duration attributes may not have embedded spaces. Examples: @begin(display) @tabclear @tabset(.5 inches) @code(Q)@\1 beat (quarter note) @code(QT)@\2/3 beat (quarter triplet) @code(W.)@\6 beats(dotted whole note) @code(ST6)@\1 beat (6 sixteenth triplets) @code(H5)@\10 beats(5 half notes) @code(Q3/7)@\3/7 beats @end(display) A duration may be noted by @code(U)@i(n)@Index(U), where @i(n) is an integer indicating 100@+[th]'s of a second (or 1000@+[th]'s), see Section @ref(millisec-sec). For example, @code(U25) is twenty-five time units. Durations may be combined using a plus sign: @begin(programexample) Q+IT ** a quarter tied to an eighth triplet Q/7+W+Q2/7 ** a 7th beat tied to a whole tied to 2/7th beat Q+U10 ** a quarter plus 10 time units @end(programexample) @subsection(Next Time) @label(next-time-sec) The time of the next@Index(next Adagio command)@index[N (Adagio Next)] command (the next command in the Adagio program text) is normally the time of the current note command plus the duration of the current note. This can be overridden by a field consisting of the letter @code(N) followed by a number indicating time units, or followed by a duration as described above. The next note will then start at the time of the current note plus the duration specified after @code(N). If the next note has an explicit time attribute (@code(T)), then the specified time will override the one based on the previous note. Examples: @begin(programexample) N0 ** start the next note at the same time as this one N50 ** start the next note 0.5 seconds after this one NQT ** start the next note 2/3 beat after the current one NU10+Q ** start after 0.1 seconds plus a quarter @end(programexample) A comma has an effect similar to @code(N0) and is explained in Section @ref(comma-sec). Articulation effects such as @i(staccato) can be produced using @code(N), but it is more convenient to use the articulation attribute described in Section @ref(articulation-sec). @subsection(Rest) Rests@Index(rests)@index[R (Adagio Rest)] are obtained by including the field @code(R) in a note command. The effect of an @code(R) field is to omit the note that would otherwise occur as the result of the current note command. In all other respects, the command is processed just like any other line. This means that attributes such as duration, loudness, and pitch can be specified, and anything specified will be inherited by the note in the next command. Normally, a rest will include just @code(R) and a duration. The fact that a note command specifies a rest is not inherited. For example: @begin(programexample) R H ** a half (two beat) rest RH ** illegal, R must be separated from H by space(s) @end(programexample) Because some synthesizers (e.g. a DX7@Index(DX7)) cannot change programs @Index(program change) (presets) rapidly, it may be desirable to change programs in a rest so that the synthesizer will be ready to play by the end of the rest. See Section @ref(adag-timbre-sec) for an example. @subsection[Articulation] @label(articulation-sec) Articulation@Index(articulation)@index(staccato)@index(legato) in Adagio refers to the percentage of time a note is on relative to the indicated duration. For example, to play a note @i(staccato), you would normally play the note about half of its indicated duration. In Adagio, articulation is indicated by @code(#)@index[# (Adagio articulation)] followed by an integer number indicating a percentage. The articulation attribute does not affect the time of the next command. This example plays two @i(staccato) quarter notes: @begin(programexample) C Q #50 D @end(programexample) To produce overlapping notes, the articulation may be greater than 100. @begin(detail) Be aware that overlapping notes on the same pitch can be a problem for some synthesizers. The following example illustrates this potential problem: @begin(programexample) !TEMPO 60 C Q #160 * starts at time 0, ends at 1.6 sec D I * starts at time 1, ends at 1.8 sec C Q * starts at time 1.5, ends at 3.1 sec? @end(programexample) At one beat per second (tempo 60), these three notes will start at times 0, 1, and 1.5 seconds, respectively. Since these notes have an articulation of 160, each will be on 160% of its nominal duration, so the first note (C) will remain on until 1.6 seconds. But the third note (another C) will start at time 1.5 seconds. Thus, the second C will be started before the first one ends. Depending on the synthesizer, this may cancel the first C or play a second C in unison. In either case, a note-off message will be sent at time 1.6 seconds. If this cancels the second C, its actual duration will be 0.1 rather than 1.6 seconds as intended. A final note-off will be sent at time 3.1 seconds. @end(detail) @subsection[Loudness] Loudness@Index(loudness)@index(velocity) is indicated by an @code(L) followed by a dynamic marking from the following: @code(PPP)@Index[PPP (Adagio dynamic)]@Index[LPPP (Adagio dynamic)], @code(PP)@Index[PP (Adagio dynamic)]@Index[LPP (Adagio dynamic)], @code(P)@Index[P (Adagio dynamic)]@Index[LP (Adagio dynamic)], @code(MP)@Index[MP (Adagio dynamic)]@Index[LMP (Adagio dynamic)], @code(MF)@Index[MF (Adagio dynamic)]@Index[LMF (Adagio dynamic)], @code(F)@Index[F (Adagio dynamic)]@Index[LF (Adagio dynamic)], @code(FF)@Index[FF (Adagio dynamic)]@Index[LFF (Adagio dynamic)], @code(FFF)@Index[FFF (Adagio dynamic)]@Index[LFFF (Adagio dynamic)]. Alternatively, a number from 1 to 127 may be used. The loudness attribute is the MIDI note velocity. (Note that a MIDI velocity of 0 means ``note-off,'' so the minimum loudness is 1.) The dynamic@Index(dynamic markings) markings are translated into numbers as follows: @begin(display) @tabclear @tabset(0.8 in, 3 in, 3.8 in) @code(Lppp)@\20@\@code(Lmf)@\58 @code(Lpp)@\26@\@code(Lf)@\75 @code(Lp)@\34@\@code(Lff)@\98 @code(Lmp)@\44@\@code(Lfff)@\127 @end(display) @subsection[Voice] The voice@Index(voice)@index[V (Adagio Voice)] attribute tells which of the 16 MIDI channels to use for the note. The voice attribute consists of a @code(V) followed by an integer from 1 (the default) to 16. @begin(detail) There is a limit to how many notes can be played at the same time on a given voice (MIDI channel). Since the limit depends upon the synthesizer, Adagio cannot tell you when you exceed the limit. Similarly, Adagio cannot tell whether your synthesizer is set up to respond to a given channel, so there is no guarantee that what you write will actually be heard. @end(detail) @subsection[Timbre (MIDI Program)] @label(adag-timbre-sec) A MIDI program@Index(MIDI program)@index[Z (Adagio program)] (synthesizer preset@Index(preset)) can be selected using the attribute @code(Z)@i(n), where @i(n) is the program number (from 1 to 128). Notice that in MIDI, changing the program on a given channel will affect @i(all) notes on that channel and possibly others. Adagio treats MIDI program changes as a form of control change. @begin(detail) For many synthesizers, you will not be able to change programs at the start of a note or during a note. Change the program during a rest instead. For example: @begin(programexample) R I Z23 V4 ** change MIDI channel 4 to program 23 during rest A4 ** play a note on channel 4 @end(programexample) Check how your synthesizer interprets program numbers. For example, the cartridge programs on a DX7 can be accessed by adding 32 to the cartridge program number. Cartridge program number 10 is specified by @code(Z42). @end(detail) As in MIDI, the Adagio timbre is a property of the voice (MIDI channel), so the timbre will not be inherited by notes on a different channel; to change the timbre on multiple voices (channels), you must explicitly notate each change. @subsection[Tempo] @label(tempo-sec) The length of a beat may be changed using a Tempo@Index(Tempo) command@index(!Tempo): @begin(programexample) !TEMPO @i(n) @end(programexample) where @i(n) indicates beats per minute. The exclamation mark tells Adagio that this is a special command line rather than a note definition. A special command takes the place of a note specification. No other attributes should be written on a line with a special command. The @code(!TEMPO) command is associated with a time, computed as if the @code(!TEMPO) command were a note. The time@Index(time) attribute (@code(T)) of all succeeding notes is now measured relative to the time of the @code(!TEMPO) command. The new tempo starts at the @code(!TEMPO) command time and affects all succeeding notes. Durations specified in time units (for example @code(U58), @code(N15)) are not affected by the @code(!TEMPO) command, and numerical times (for example @code(T851)) are computed relative to the time of the last @code(!TEMPO) command. The @code(!TEMPO) command is fairly clever about default durations@Index(default durations). If the last duration specified before the @code(!TEMPO) command is symbolic (using one of @code(^),@code(%), @code(S), @code(I), @code(Q), @code(H), or @code(W) ), then the default duration for the node after the @code(!TEMPO) command will be modified according to the tempo change. Consider the following tempo change: @begin(programexample) !TEMPO 60 A4 H !TEMPO 120 G @end(programexample) In this example, the first note will last 2 seconds (2 beats at 60 beats per minute). The second note inherits the duration (H) from the first note, but at 120 beats per minute, the second note will last only 1 second. If the duration had been specified @code(U200) (also a duration of 2 seconds), the second note would also last 2 seconds because the @code(!TEMPO) command does not affect times or durations specified numerically in time units. If the duration is the sum of a symbolic and a numeric specification, the inherited duration after a @code(!TEMPO) command is undefined. @subsection(Rate) The @code(!RATE)@Index(rate)@index(!Rate) command scales all times including those specified in hundredths of seconds. A rate of 100 means no change, 200 means twice as fast, and 50 means half as fast. For example, to make a piece play 10% faster, you can add the following command at the beginning of the score: @begin(programexample) !RATE 110 @end(programexample) @code(!RATE) and @code(!TEMPO) commands combine, so @begin(programexample) !RATE 200 !TEMPO 70 @end(programexample) will play 70 beats per minute at double the normal speed, or 140 beats per minute. Like @code(!TEMPO), the time of the @code(!RATE) command is added to the time attribute of all following notes up to the next @code(!TEMPO) or @code(!RATE) command. Two @code(!RATE) commands do not combine, so a @code(!RATE) command only affects the rate until the next @code(!RATE) command. Although @code(!TEMPO) and @code(!RATE) can occur in the middle of a note (using @code(N), @code(T), etc.) they do not affect a note already specified. This property allows multiple tempi to exist simultaneously (see Section @ref(multipletempi-sec)). @section[Default Attributes] @label(default-sec) If an attribute is omitted, the previous one is used by default@Index(default) (with the exception of the time attribute). The default values for the first note, which are inherited by succeeding notes until something else is specified, are given below in Adagio notation: @begin(display) @tabclear @tabset(1.5 inch) Time @\@code(T0) Pitch @\@code(C4) Duration @\@code(Q) Articulation @\@code(#100) Loudness @\@code(LFFF) Voice @\@code(V1) Tempo @\@code(!TEMPO 100) Rate @\@code(!RATE 100) @end(display) Control changes (including timbre or MIDI program, specified by @code(Z)) have no default value and are only sent as specified in the score. @p(Important:) the rules for determining when a command will play a note are as follows (and this has changed slightly from previous versions): @begin(enumerate) If a special (@code(!)) command or nothing is specified, e.g. a blank line, do @i(not) play a note. If @code(R) (for ``rest'') is specified, do @i(not) play a note. Otherwise, if a pitch is specified, @i(do) play a note. Otherwise, if no control changes (or program changes) are specified (so this is a command with non-pitch attributes and no control changes), @i(do) play a note. @end(enumerate) Another way to say this is ``Special commands and commands with rests (@code(R)) do not play notes. Otherwise, play a note if a pitch is specified or if no control is specified.'' @section[Examples] @label(adag-examples-sec) The following plays the first two bars of ``Happy Birthday''. Note that Adagio knows nothing of bar lines, so the fact that the first note occurs on beat 3 or that the meter is three-four is of no consequence: @begin(programexample) *Example 1 ** Happy Birthday tune (C major) !TEMPO 120 G4 I. LF G4 S A4 Q G4 C5 B4 H @end(programexample) The time attribute for the first note is zero (@code(0)). The second note will occur a dotted eighth later, etc. Notice that no timbre or rate was specified. Adagio will provide reasonable default values of 1 and 100, respectively. The following example plays the first four bars of an exercise from Bartok@Index(Bartok)'s Mikrokosmos@Index(Mikrokosmos) (Vol. 1, No. 12). An extra quarter note is inserted at the beginning of each voice in order to allow time to change MIDI programs. The right hand part is played on voice (MIDI channel) 1 and the left hand part on voice 2. Notice the specification of the time attribute to indicate that voice 2 starts at time 0. Also, default octaves are used to reduce typing. @begin(programexample) *Example 2 ** Bartok *voice 1, right hand R Q Z10 V1 ** extra rest for program change A4 H B Q C D H C D Q C B A B C D R *voice 2, left hand T0 R Q Z15 V2 ** extra rest for program change G3 H F Q E D H E D Q E F G F E D R @end(programexample) The next example is the same piece expressed in a different manner, illustrating the interaction between the @code(!TEMPO) command and the time attribute. Recall that the time attribute is measured relative to the time of the last @code(!TEMPO) command: @begin(programexample) *Example 3 ** 4 measures in 2 sections !Tempo 100 *Voice 1, Measures 1 & 2 R Q Z10 V1 A4 H B Q C D H C *Voice 2, Measures 1 & 2 T0 R Q Z15 V2 G3 H F Q E D H E H !TEMPO 100 *Voice 1, Measures 3 & 4 * note that Z10 is still in effect for V1 V1 D4 Q C B A B C D R *Voice 2, Measures 3 & 4 T0 V2 D3 Q E F G F E D R @end(programexample) The piece is written in 4 sections. The first plays a rest followed by two measures, starting at time 0. The next section changes the time back to zero and plays two measures of the left hand part (voice 2). The next command (!TEMPO 100) sets the tempo to 100 (it already is) @i(and) sets the reference time to be two measures into the piece. Therefore, the next note @code((D4)) will begin measure 3. The @code(D3) that begins the last group of notes has a @code(T0) attribute, so it will also start at measure 3. Notice how the @code(!TEMPO) command can serve to divide a piece into sections@Index(sections, Adagio). The last example will show yet another way to express the same piece of music using the ``Next'' attribute. Only the first bar of music is given. @begin(programexample) *Example 4 ** use of the Next attribute !Tempo 100 R Q Z10 V1 N0 R Q Z15 V2 A4 H V1 N0 G3 V2 B4 Q V1 N0 F3 V2 C4 Q V1 N0 E3 V2 @end(programexample) Here, each pair of lines represents two simultaneous notes. The @code(N0) attribute forces the second line to start at the same time as the first line of each pair. Because of the large intervals, octave numbers (3 and 4) are necessary to override the default octave for these pitches. @section(Advanced Features) Beyond the simple notation described above, Adagio supports a number of features. (See also the next chapter.) @subsection(Time Units and Resolution) @label(millisec-sec)@index(time units)@index(resolution) The default time unit is 10ms (ten milliseconds or one centisecond or 100@+(th) of a second), but it is possible to change the basic unit to 1ms, or 1000@+(th) of a second. The time unit can be specified by: @begin(display) @tabclear @tabset(0.8 inches) @t(!CSEC)@index(!csec)@\centisecond time units = 100@+(th) @t(!MSEC)@index(!msec)@\millisecond time units = 1000@+(th) @end(display) The time unit remains in effect until the next @code(!CSEC) or @code(!MSEC) command. @subsection(Multiple Notes Per Line) @label(comma-sec) @index(multiple commands) Notes can be separated by commas@Index(commas)@index[, (Adagio)] or semicolons@Index(semicolon, Adagio)@index[; (Adagio)] as well as by starting a new line. A comma is equivalent to typing @code(N0) and starting a new line. In other words, the next note after a comma will start at the same time as the note before the comma. In general, @i(use commas to separate the notes of a chord.) A semicolon is equivalent to starting a new line. In general, @i(use semicolons to group notes in a melody). Here is yet another rendition of the Bartok: @begin(programexample) *Example 5 ** use of semicolons !Tempo 100 R Q Z10 V1 A4 H; B Q; C; D H; C; D Q; C; B; A; B; C; D; R T0 R Q Z15 V2 G3 H; F Q; E; D H; E; D Q; E; F; G; F; E; D; R @end(programexample) This example is similar to Example 2, except semicolons are used. Note how semicolons make the two lines of music stand out. The next example is similar to Example 4, except commas are used and four bars are notated. The music below is treated as a sequence of 2-note chords, with each chord on a separate line: @begin(programexample) *Example 6 ** use of commas !Tempo 100 R Q Z10 V1, R Q Z15 V2 A4 H V1, G3 V2 B4 Q V1, F3 V2 C4 V1, E3 V2 D4 H V1, D3 V2 C4 V1, E3 V2 D4 Q V1, D3 V2 C4 V1, E3 V2 B4 V1, F3 V2 A4 V1, G3 V2 B4 V1, F3 V2 C4 V1, E3 V2 D4 V1, D3 V2 R @end(programexample) @subsection(Control Change Commands) @index(Control change)@index[~ (Adagio)] Any control change can be specified using the syntax ``@t[~@i(n)(@i(v))]'', where @i(n) is the controller number (0 - 127), and @i(v) is the value. In addition, Adagio has some special syntax for some of the commonly used control changes (note that Pitch bend, Aftertouch, and MIDI Program Change are technically not MIDI control changes but have their own special message format and status bytes): @begin(display) @tabclear @tabset(0.5 inch) K@\Portamento switch@Index(Portamento switch)@Index[K (Adagio control)]@* M@\Modulation wheel@Index(Modulation wheel)@Index[M (Adagio control)]@* O@\Aftertouch@Index(Aftertouch)@Index[O (Adagio control)]@* X@\Volume@Index(Volume)@Index[X (Adagio control)]@* Y@\Pitch bend@Index(Pitch bend)@Index[Y (Adagio control)]@* Z@\Program Change@Index(Program)@Index[Z (Adagio program)]@* @end(display) The letter listed beside each control function is the Adagio command letter. For example, @code(M23) is the command for setting the modulation wheel to 23. Except for pitch bend, the portamento switch, and MIDI Program Change, all values range from 0 to 127. Pitch bend is ``off'' or centered at 128, and has a range from 0 to 255 (MIDI allows for more precision, but Adagio does not). Turn on portamento with @code(K127) and off with @code(K0). Programs are numbered 1 to 128 to correspond to synthesizer displays. @p(About volume:) Midi volume is just a control, and the Midi standard does not say what it means. Typically it does what the volume pedal does; that is, it scales the amplitude in a continuously changeable fashion. In contrast, Midi velocity, which is controlled by the @code(L) (loudness) attribute, is part of a Midi note-on command and is fixed for the duration of the note. Typically, these two ways of controlling loudness and amplitude operate independently. In some low-cost synthesizers the numbers seem to be added together internally and volume changes are ignored after the note starts. @p(About pitch bend:) Midi pitch bend is a number from 0 to 16383, where 8192 is the center position. To convert to Midi, Adagio simply multiplies your number by 64, giving values from 0 to 16320. Note that @code(Y128) translates exactly to 8192. The @i(meaning) of pitch bend depends upon your synthesizer and its setting. Most synthesizers let you specify a ``pitch bend range.'' A range of one semitone means that @code(Y255) will produce a bend of approximately one semitone up, and @code(Y0) will bend one semitone down. If the range is 12 semitones, then the same @code(Y255) will bend an octave. Typically, pitch bend is exponential, so each increment in the pitch bend value will bend an equal number of cents in pitch. Control changes can be part of a note specification or independent. In the following example, a middle C is played with a modulation wheel setting of 50 and a pitch bend of 120. Then, at 10 unit intervals, the pitch bend is decreased by 10. The last line sets the portamento time (controller 5) to 80: @begin(programexample) *Example 7 C4 LMF M50 Y120 U100 N10 Y110 N10; Y100 N10; Y90 N10; Y80 N10 Y70 N10; Y60 N10; Y50 N10 ~5(80) @end(programexample) See Section @ref(default-sec) on page @pageref(default-sec) for rules on whether or not a command will play a note. @subsection(Multiple Tempi)@Index(multiple tempi) @label(multipletempi-sec) @Index(polyrhythm) Writing a piece with multiple tempi requires no new commands; you just have to be clever in the use of Tempo and Time. The following plays a 7 note diatonic scale on voice 1, and a 12 note chromatic scale on voice 2: @begin(programexample) *Example 8 ** multiple tempi !TEMPO 70 V1 C4; D; E; F; G; A; B T0 R N0 !TEMPO 120 V2 C4; CS; D; DS; E; F; FS; G; GS; A; AS; B !TEMPO 100 V1 C5, V2 C5 @end(programexample) The third line plays the 7-note diatonic scale on voice 1. The next line contains the tricky part: notice that the time is set back to zero, there is a rest, and a next (@code(N)) attribute is used to specify that the next default time will be at the same time as the current one. This is tricky because a @code(!TEMPO) command cannot have a time (@code(T0)) attribute, and a @code(T0) by itself would create a note with a duration. @code(T0 R N0) says: ``go to time 0, do not play a note, and do not advance the time before the next command''. Thus, the time of the @code(!TEMPO 120) command is zero. After the 12 note scale, the tempo is changed to 100 and a final note is played on each voice. A little arithmetic will show that 7 notes at tempo 70 and 12 notes at tempo 120 each take 6 seconds, so the final notes (@code(C5)) of each scale will happen at the same time. @subsection(MIDI Synchronization) @index(synchronization)@index(clock)@index(MIDI Clock)@index(clock command) The Adagio program (but not Nyquist) can synchronize with external devices using MIDI real time messages. Thus, Adagio has a @code(!CLOCK) command. This command is currently of no use to Nyquist users but is documented here for completeness (it's part of the language syntax even if it does not do anything). Since Adagio supports multiple tempi, and Midi clock is based on beats, it is necessary to be explicit in the score about where the clock should start and what is the duration of a quarter note. The @code(!CLOCK) command@index(!Clock) in Adagio turns on a 24 pulse-per-quarter (PPQ) clock at the current tempo and time: @begin(programExample) !TEMPO 100 !CLOCK @end(programexample) A @code(!CLOCK) command must also be inserted for each tempo change that is to be reflected in the Midi clock. Typically, each !TEMPO command will be followed by a !CLOCK command. @begin(detail) Clock commands and thus tempo changes can take place at arbitrary times. It is assumed that tempo changes on an exact 24@+(th) of a beat subdivision (for example, exactly on a beat). If not, the tempo change will take place on the nearest exact 24@+(th) of a beat subdivision. This may be earlier or later than the requested time. @end(detail) @subsection[System Exclusive Messages] @label(macro-sec) Adagio has a definition facility that makes it possible to send system exclusive parameters. Often, there are parameters on Midi synthesizers that can only be controlled by system exclusive messages. Examples include the FM ratio and LFO rate on a DX7 synthesizer. The following example defines a macro for the DX7 LFO rate and then shows how the macro is used to set the LFO rate for a B-flat whole note in the score. The macro definition is given in hexadecimal, except @t(v) is replaced by the channel (voice) and @t(%1) is replaced by the first parameter. A macro is invoked by writing ``~'' followed by the macro name and a list of parameters@index(!Def): @begin(programexample) !DEF LFO F0 43 0v 01 09 %1 F7 Bf5 W ~LFO(25) @end(programexample) In general, the @t(!DEF) command can define any single MIDI message including a system exclusive message. The message must be complete (including the status byte), and each @t(!DEF) must correspond to just one message. The symbol following @t(!DEF) can be any name consisting of alphanumeric characters. Following the name is a hexadecimal string (with optional spaces), all on one line. Embedded in the string may be the following special characters: @begin(description) @t(v)@\Insert the 4-bit voice (MIDI channel) number. If @t(v) occurs in the place of a high-order hexadecimal digit, replace @t(v) with @t(0v) so that the channel number is always placed in the low-order 4 bits of a data byte. In other words, @t(v) is padded if necessary to fall into the low-order bits. @t(%)@i(n)@\Insert a data byte with the low-order 7 bits of parameter number @i(n). Parameters are numbered 1 through 9. If the parameter value is greater than 127, the high-order bits are discarded. @t(^)@i(n)@\Insert a data byte with bits 7 through 13 of parameter number @i(n). In other words, shift the value right 7 places then clear all but the first 7 bits. Note that 14-bit numbers can be encoded by referencing the same parameter twice; for example, @t(%4^4) will insert the low-order followed by the high-order parts of parameter 4 into two successive data bytes. @end(description) Parameters are separated by commas, but there may be no spaces. The maximum number of parameters allowed is 9. Here is an example of definitions to send a full-resolution pitch bend command and to send a system exclusive command to change a DX7 parameter@foot[My TX816 Owner's Manual gives an incorrect format for the change parameter sysex command (according to the manual, there is no data in the message!) I am assuming that the data should be the last byte before the EOX and that there is no byte count. If you are reading this, assume that I have not tested this guess, nor have I tested this example.]. @begin(programexample) * Define macro for pitch bend commands: !DEF bend Ev %1 ^1 A ~bend(8192) ** 8192 is "pitch bend off" * Change the LFO SPEED: * SYSEX = F0, Yamaha = 43, Substatus/Channel = 1v, * Group# = 01, Parameter# = 9, Data = 0-99, EOX = F7 !DEF lfospeed F0 43 1v 01 09 %1 F7 * now use the definitions: G4 ~bend(7567) N40 ~lfospeed(30) N35 @end(programexample) @subsection(Control Ramps) @label(macroramp-sec) The @t(!RAMP) command@index(!Ramp) can specify a smooth control change from one value to another. It consists of a specification of the starting and ending values of some control change, a duration specifying how often to send a new value, and a duration specifying the total length of the ramp. @begin(programexample) !RAMP X10 X100 Q W2 !RAMP ~23(10) ~23(50) U20 W !RAMP ~lfo(15) ~lfo(35) U10 @end(programexample) The first line says to ramp the volume control (controller number 7) from 10 to 100, changing at each quarter note for the duration of two whole notes. The second line says to ramp controller number 23 from value 10 to value 50, sending a new control change message every 20 time units. The overall duration of the ramp should be equivalent to a whole note (@t(W)). As shown in the third line, even system exclusive messages controlled by parameters can be specified. If the system exclusive message has more than one parameter, only one parameter may be ``ramped''; the others must remain the same. For example, the following would ramp the second parameter: @begin(programexample) !RAMP ~mysysex(4,23,75) ~mysysex(4,100,75) U10 W @end(programexample) @begin(detail) A rather curious and extreme use of macros and ramps is illustrated in the following example. The @t(noteon) macro starts a note, and @t(noteoff) ends it. Ramps can now be used to emit a series of notes with changing pitches or velocities. Since Adagio has no idea that these macros are turning on notes, it is up to the programmer to turn them off! @begin(programexample) !DEF noteon 9v %1 %2 !DEF noteoff 8v %1 %2 ~noteon(48,125) ~noteoff(48,126) * turn on some notes !RAMP ~noteon(36,125) ~noteon(60,125) Q W NW * turn them off !RAMP ~noteoff(60,50) ~noteoff(36,50) Q W NW @end(programexample) @end(detail) @subsection(The !End Command) @label(end-sec)@index(!End)@index(end command) The special command @code(!END) marks the end of a score. Everything beyond that is ignored, for example: @begin(programexample) * this is a score C; D; E; F; G W !END since the score has ended, this text will be ignored @end(programexample) @subsection(Calling C Routines) @label(call-sec) It is possible to call C routines from within Adagio scores when using specially linked versions, but this feature is disabled in Nyquist. The syntax is described here for completeness. The @code(!CALL) command@index(!Call)@index(Call command) calls a C routine that can in turn invoke a complex sequence of operations. Below is a call to a trill@index(trill) routine, which is a standard routine in Adagio. The parameters are the base pitch of the trill, the total duration of the trill, the interval in semitones, the duration of each note of the trill, and the loudness. Notice that both numbers and Adagio notation can be used as parameters: @begin(programexample) !CALL trill(A5,W,2,S,Lmf) T278 V1 @end(programexample) @i(The parameter list should have no spaces), and parameters are separated by commas. Following the close parenthesis, you may specify other attributes such as the starting time and voice as shown in the example above. A parameter may be an Adagio pitch specification, an Adagio duration, an Adagio loudness, a number, or an ASCII character within single quotes, e.g. @t('a') is equivalent to @t(97) because 97 is the decimal encoding of ``a'' in ASCII. The @code(!CALL) may be followed by a limited set of attributes. These are time (@t(T)), voice (@t(V)), and next time (@t(N)). The @code(!CALL) is made at the current time if no time is specified, and the time of the next adagio command is the time of the @code(!CALL) unless a next time is specified. In other words, the default is @t(N0). @subsection(Setting C Variables) In addition to calling C routines, there is another way in which scores can communicate with C. As with @code(!CALL), specific C code must be linked before these commands can be used, and this is not supported in Nyquist. The @code(!SETI) command@index(!Seti)@index(seti commnad) sets an integer variable to a value, and the @code(!SETV) command@index(!Setv)@index(setv command) sets an element of an integer array. For example, the next line sets the variable @t(delay) to 200 and sets @t(transposition[5]) to -4 at time 200: @begin(programexample) !SETI delay 200 !SETV transposition 5 -4 T200 @end(programexample) As with the @code(!CALL) command, these commands perform their operations at particular times according to their place in the Adagio score. This makes it very easy to implement time-varying parameters that control various aspects of an interactive music system. nyquist-3.05/docsrc/nyquist/poisson-fig.ps0000644000175000000620000015546011466723256020004 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: poisson-fig.ps %%CreationDate: Wed Jul 13 12:17:22 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 313 364 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 349 translate -20 775 translate 297.99999999999994 -349 scale % Image geometry 298 349 8 % Transformation matrix [ 298 0 0 349 0 0 ] % Strings to hold RGB-samples per scanline /rstr 298 string def /gstr 298 string def /bstr 298 string def {currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} {currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} true 3 %%BeginData: 55088 ASCII Bytes colorimage JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> r;V r;V r;V r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`s`rGr:!1N]_rrD$Xr;["7d/X+G!;ZWqiJdX5rr<-#!!)`m"lYF?rr<&_s8N)ps8N'#s5Aq& rrqYU!!%uB`W#o r;Q`s`rGr:!1N]_rrD$Xr;["7d/X+G!;ZWqiJdX5rr<-#!!)`m"lYF?rr<&_s8N)ps8N'#s5Aq& rrqYU!!%uB`W#o r;Q`s`rGr:!1N]_rrD$Xr;["7d/X+G!;ZWqiJdX5rr<-#!!)`m"lYF?rr<&_s8N)ps8N'#s5Aq& rrqYU!!%uB`W#o r;Q`s`rH&=s8N/@!1MO>rrE*!!h',JpAb-mp](6npAb-mjT#5[q>^Hp!ri6#li.-W!9r_J9u[,4 !;leH~> r;Q`s`rH&=s8N/@!1MO>rrE*!!h',JpAb-mp](6npAb-mjT#5[q>^Hp!ri6#li.-W!9r_J9u[,4 !;leH~> r;Q`s`rH&=s8N/@!1MO>rrE*!!h',JpAb-mp](6npAb-mjT#5[q>^Hp!ri6#li.-W!9r_J9u[,4 !;leH~> r;Q`s`rH&=rr;uus8O=L9`VL!rr<'!l$NI2N9UB,HiO/*l2Udh9`VL!rr<&GHqhuds8N*!rs\,l Rf?!ZN'q)!76*fd/!\MN+gQ< !<<))!!'>)s8)d#s65IB!,1'TrrV-ZI)Z*c!;leH~> r;Q`s`rH&=rr;uus8O=L9`VL!rr<'!l$NI2N9UB,HiO/*l2Udh9`VL!rr<&GHqhuds8N*!rs\,l Rf?!ZN'q)!76*fd/!\MN+gQ< !<<))!!'>)s8)d#s65IB!,1'TrrV-ZI)Z*c!;leH~> r;Q`s`rH&=rr;uus8O=L9`VL!rr<'!l$NI2N9UB,HiO/*l2Udh9`VL!rr<&GHqhuds8N*!rs\,l Rf?!ZN'q)!76*fd/!\MN+gQ< !<<))!!'>)s8)d#s65IB!,1'TrrV-ZI)Z*c!;leH~> r;Q`s`rH&=rr;uu-3(XYa2\1nrr<'!BE8(s!.=f[!<;9`I/gk[a2\1nrr<&4kl=HVs8N)us8N'X rr<'!BE8(s!.=eH!<<'!!87DP!!*$!!2mj;VZ6_srr<'!!!*'!!!*&4!6<+[^&J'4^$,MkqYqJ3 !6:u;!<9_4a3Xh"rr<'!!!*'!I+ePa!) r;Q`s`rH&=rr;uu-3(XYa2\1nrr<'!BE8(s!.=f[!<;9`I/gk[a2\1nrr<&4kl=HVs8N)us8N'X rr<'!BE8(s!.=eH!<<'!!87DP!!*$!!2mj;VZ6_srr<'!!!*'!!!*&4!6<+[^&J'4^$,MkqYqJ3 !6:u;!<9_4a3Xh"rr<'!!!*'!I+ePa!) r;Q`s`rH&=rr;uu-3(XYa2\1nrr<'!BE8(s!.=f[!<;9`I/gk[a2\1nrr<&4kl=HVs8N)us8N'X rr<'!BE8(s!.=eH!<<'!!87DP!!*$!!2mj;VZ6_srr<'!!!*'!!!*&4!6<+[^&J'4^$,MkqYqJ3 !6:u;!<9_4a3Xh"rr<'!!!*'!I+ePa!) r;Q`s`rH&=s8N\E!2oj1!<<'!B`A&4s%NK@d/O%I9`TRfrr3C?!<<'!B`A&4s8N'!rVultrr;uu #QFc(s%NK@d/O(F!<<*!!<3#u!$V@B!<<'!9`P1nrr<'!!!*'!!!*%4!<<'!B`A&4s8N'!qYq1& !<<'!!<5ans8N(4rr<'!!!*#u"Q?Y6!!)Ng!lk;0`W#o r;Q`s`rH&=s8N\E!2oj1!<<'!B`A&4s%NK@d/O%I9`TRfrr3C?!<<'!B`A&4s8N'!rVultrr;uu #QFc(s%NK@d/O(F!<<*!!<3#u!$V@B!<<'!9`P1nrr<'!!!*'!!!*%4!<<'!B`A&4s8N'!qYq1& !<<'!!<5ans8N(4rr<'!!!*#u"Q?Y6!!)Ng!lk;0`W#o r;Q`s`rH&=s8N\E!2oj1!<<'!B`A&4s%NK@d/O%I9`TRfrr3C?!<<'!B`A&4s8N'!rVultrr;uu #QFc(s%NK@d/O(F!<<*!!<3#u!$V@B!<<'!9`P1nrr<'!!!*'!!!*%4!<<'!B`A&4s8N'!qYq1& !<<'!!<5ans8N(4rr<'!!!*#u"Q?Y6!!)Ng!lk;0`W#o r;Q`s`rGr:-`@"E!!*'!!!*$!!<:D?!!#a?s3OI?!):i?!!*'!!!*$!!<<'!!<)rt!<3#u!"f/1 !<:D?!!#a?rr<'!rr<&us8N'%rr<'!s8;rts8N'5rr<'!rr<'!!!*'!!!*$!!<<'!!;c`q!<<*! !!*&r!"Jr.!<3$!s8UFGRcsePrVu`pq>^Hp`W#o r;Q`s`rGr:-`@"E!!*'!!!*$!!<:D?!!#a?s3OI?!):i?!!*'!!!*$!!<<'!!<)rt!<3#u!"f/1 !<:D?!!#a?rr<'!rr<&us8N'%rr<'!s8;rts8N'5rr<'!rr<'!!!*'!!!*$!!<<'!!;c`q!<<*! !!*&r!"Jr.!<3$!s8UFGRcsePrVu`pq>^Hp`W#o r;Q`s`rGr:-`@"E!!*'!!!*$!!<:D?!!#a?s3OI?!):i?!!*'!!!*$!!<<'!!<)rt!<3#u!"f/1 !<:D?!!#a?rr<'!rr<&us8N'%rr<'!s8;rts8N'5rr<'!rr<'!!!*'!!!*$!!<<'!!;c`q!<<*! !!*&r!"Jr.!<3$!s8UFGRcsePrVu`pq>^Hp`W#o r;Q`s`rH&=qu6q8!<<'!B`A&4rr3)RVZ9Hjrt3q^!)an!<<'!!<3$!s8N'!s(DE4rr?a4!!*'!!!)lq#Yb=! rr<'!9`Y+krrj5rr<&rs*t~> r;Q`s`rH&=qu6q8!<<'!B`A&4rr3)RVZ9Hjrt3q^!)an!<<'!!<3$!s8N'!s(DE4rr?a4!!*'!!!)lq#Yb=! rr<'!9`Y+krrj5rr<&rs*t~> r;Q`s`rH&=qu6q8!<<'!B`A&4rr3)RVZ9Hjrt3q^!)an!<<'!!<3$!s8N'!s(DE4rr?a4!!*'!!!)lq#Yb=! rr<'!9`Y+krrj5rr<&rs*t~> r;Q`s`rH&=qu7qT!6<+[^&J'4s*Oh2n,R/%HiWF#!,2DG!6<+[^&J'4s8N'!rVults8Nb$!87AP !<7EHl0n[drr<'!rr<&us8N'Err<%sciBtW!9q/s!<3$!s8N'!s1JEQ`rNgQ!!*'!!!*$!!<)p9 VZ=cN!!*&)!6==(N;ikXrr<'!s%NLX`rH,2rrn>]l,Ne0`W#o r;Q`s`rH&=qu7qT!6<+[^&J'4s*Oh2n,R/%HiWF#!,2DG!6<+[^&J'4s8N'!rVults8Nb$!87AP !<7EHl0n[drr<'!rr<&us8N'Err<%sciBtW!9q/s!<3$!s8N'!s1JEQ`rNgQ!!*'!!!*$!!<)p9 VZ=cN!!*&)!6==(N;ikXrr<'!s%NLX`rH,2rrn>]l,Ne0`W#o r;Q`s`rH&=qu7qT!6<+[^&J'4s*Oh2n,R/%HiWF#!,2DG!6<+[^&J'4s8N'!rVults8Nb$!87AP !<7EHl0n[drr<'!rr<&us8N'Err<%sciBtW!9q/s!<3$!s8N'!s1JEQ`rNgQ!!*'!!!*$!!<)p9 VZ=cN!!*&)!6==(N;ikXrr<'!s%NLX`rH,2rrn>]l,Ne0`W#o r;Q`s`rH&=qYqeG9hhqnrr<'!n8l2Udh9hhqnrr<'!rr<&ts8;p2B\EFc!!*&g RK*>8l2T*1I/a0Hrr;uu,l[iEcqSofcqS3 r;Q`s`rH&=qYqeG9hhqnrr<'!n8l2Udh9hhqnrr<'!rr<&ts8;p2B\EFc!!*&g RK*>8l2T*1I/a0Hrr;uu,l[iEcqSofcqS3 r;Q`s`rH&=qYqeG9hhqnrr<'!n8l2Udh9hhqnrr<'!rr<&ts8;p2B\EFc!!*&g RK*>8l2T*1I/a0Hrr;uu,l[iEcqSofcqS3 r;Q`sJcF:#!U49\rr<&rs*t~> r;Q`sJcF:#!U49\rr<&rs*t~> r;Q`sJcF:#!U49\rr<&rs*t~> r;Q`sJcF:#!K?!#rr<&rs*t~> r;Q`sJcF:#!K?!#rr<&rs*t~> r;Q`sJcF:#!K?!#rr<&rs*t~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`soD\djrr;rtJcC<$q>UEpqu;0~> r;Q`soD\djrr;rtJcC<$q>UEpqu;0~> r;Q`soD\djrr;rtJcC<$q>UEpqu;0~> r;Q`so`+pks8N'!rr2ruJcC<$qYpNqqu;0~> r;Q`so`+pks8N'!rr2ruJcC<$qYpNqqu;0~> r;Q`so`+pks8N'!rr2ruJcC<$qYpNqqu;0~> r;Q`sp&>0qrrE*!!<2uu!.k0$s8)`q!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s8)`q!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s8)`q!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s8)`q!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s8)`q!;leH~> r;Q`sp&>0qrrE*!!<2uu!.k0$s8)`q!;leH~> r;Q`spAY r;Q`spAY r;Q`spAY r;Q`spAb$j!WN0!rr<&orr<%M^l?,0JGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<%M^l?,0JGK3F!;leH~> r;Q`spAb$j!WN0!rr<&orr<%M^l?,0JGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^l?,0JGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^l?,0JGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<%M^l?,0JGK3F!;leH~> r;Q`soD\djrr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`soD\djrr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;osq#: r;Q`sp&G!krr;osq#: r;Q`sp&G!krr;osq#: r;Q`spAY*mrr3'#s8N)lrr<%M^l?,0JGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<%M^l?,0JGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<%M^l?,0JGK3F!;leH~> r;Q`so)AakrrD]k!!%ScNPGOEq>UEpqu;0~> r;Q`so)AakrrD]k!!%ScNPGOEq>UEpqu;0~> r;Q`so)AakrrD]k!!%ScNPGOEq>UEpqu;0~> r;Q`so`+pks8W#tp\t3nJ\[8\!.anF!!)orJ,~> r;Q`so`+pks8W#tp\t3nJ\[8\!.anF!!)orJ,~> r;Q`so`+pks8W#tp\t3nJ\[8\!.anF!!)orJ,~> r;Q`so)A[ir;Q`squ?NnJ\[>^!.anF!!)orJ,~> r;Q`so)A[ir;Q`squ?NnJ\[>^!.anF!!)orJ,~> r;Q`so)A[ir;Q`squ?NnJ\[>^!.anF!!)orJ,~> r;Q`so)A[ir;Q`sq#: r;Q`so)A[ir;Q`sq#: r;Q`so)A[ir;Q`sq#: r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!%ScNPGOEq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3nJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uYJ\[8\!.anF!!)orJ,~> r;Q`sir8uY]>4%=J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>4%=J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>4%=J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`so`+pks8N'!rr2ruq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`so`+pks8N'!rr2ruq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`so`+pks8N'!rr2ruq#:+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`so)AakrrE&u!!)orqZ+=F!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ+=F!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ+=F!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`sp&G!krr;rtp\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;osq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;osq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;osq#:+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`spAY*mrr3'#s8N)lrr<&2^]4B.R/d5<^u3!.JGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<&2^]4B.R/d5<^u3!.JGK3F!;leH~> r;Q`spAY*mrr3'#s8N)lrr<&2^]4B.rr<%M^u3!.JGK3F!;leH~> r;Q`so)AakrrD]k!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrD]k!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrD]k!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`so)A^js8;rlrr<&2^]4B.R/d5<^u3!.JGK3F!;leH~> r;Q`so)A^js8;rlrr<&2^]4B.R/d5<^u3!.JGK3F!;leH~> r;Q`so)A^js8;rlrr<&2^]4B.rr<%M^u3!.JGK3F!;leH~> r;Q`soD\djqu6Wrqu?Nn]taUJp6bm\J\^3Z!.anF!!)orJ,~> r;Q`soD\djqu6Wrqu?Nn]taUJp6bm\J\^3Z!.anF!!)orJ,~> r;Q`soD\djqu6Wrqu?Nn]taUJpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`so`"mkqYpNqq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`so`"mkqYpNqq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`so`"mkqYpNqq#:+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#:+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#:+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3n]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHp6bm\J\^3Z!.anF!!)orJ,~> r;Q`sp&G!krr;rtp\t3n]>+CHpAY*mJ\^3Z!.anF!!)orJ,~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`spAY*mrr3$"rrE&u!!)fo!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)_\!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)fo!!'XH!!)`m!!%Sci4o>Cq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ+=F!!)_\!!)N(oDjHXrkJMaq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ+=F!!)_\!!)N(oDjHXrkJMaq>UEpqu;0~> r;Q`so)AakrrE&u!!)orqZ+=F!!)`m!!)N(oDjHXrkJMaq>UEpqu;0~> r;Q`soD\mms8N)urr<&orr<&2^]4B.R/d6V^]4B.R/d5<_#D+LJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<&2^]4B.R/d6V^]4B.R/d5<_#D+LJGK3F!;leH~> r;Q`soD\mms8N)urr<&orr<&2^]4B.rr<&g^]4B.rr<%M_#D+LJGK3F!;leH~> r;Q`so`"mkrr2rurr2ruq#:+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruq#:+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`so`"mkrr2rurr2ruq#:+CHpAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#:+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#:+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sp&>!lrVlitrr2ruq#:+CHpAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3n]>+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3n]>+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`spAb$js8W&up\t3n]>+CHpAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uY]>+CHp6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uY]>+CHpAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;*=\n%\o'p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;*=\n%\o'p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;*=\n%\o'pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`so`"mkrVufrq#: r;Q`so`"mkrVufrq#: r;Q`so`"mkrVufrq#:!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`sp&G$lrVlitp&>!lg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sp&G$lrVlitp&>!lg;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`sp&G$lrVlitp&>!lg;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`spAY0orrE&u!!)Zk!!(`g!!)\[!!)N(!!)_\!!)N(!!)_\!!%ScrkJMaq>UEpqu;0~> r;Q`spAY0orrE&u!!)Zk!!(`g!!)\[!!)N(!!)_\!!)N(!!)_\!!%ScrkJMaq>UEpqu;0~> r;Q`spAY0orrE&u!!)Zk!!(`g!!)]l!!)N(!!)`m!!)N(!!)`m!!%ScrkJMaq>UEpqu;0~> r;Q`so`"mkrr;osp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`so`"mkrr;osp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\J\_9#!.anF!!)orJ,~> r;Q`so`"mkrr;osp\t3ng;![gp&>!lnA##(pAY*mnA##(pAY*mJ\_9#!.anF!!)orJ,~> r;Q`so`"mkqYpNqqu?NngqWmiopGd[nA##(p6bm\nA##(p6bm\n%ePqS\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqqu?NngqWmiopGd[nA##(p6bm\nA##(p6bm\n%ePqS\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqqu?NngqWmip&>!lnA##(pAY*mnA##(pAY*mn%ePqS\P5Uq>UEpqu;0~> r;Q`so`"mkqYpNqq#:UEpqu;0~> r;Q`so`"mkqYpNqq#:UEpqu;0~> r;Q`so`"mkqYpNqq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEp qu;0~> r;Q`so`"mkrVuisp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sp&G$lrr2rurr2ruq#:UEp qu;0~> r;Q`sp&G$lrr2rurr2ruq#:UEp qu;0~> r;Q`sp&G$lrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEp qu;0~> r;Q`spAY0orrE&u!!*#u!!)fo!!(`g!!)\[!!)N(!!)_\!!)N(!!)_\!!)N(!!)\[!!&S*!.anF !!)orJ,~> r;Q`spAY0orrE&u!!*#u!!)fo!!(`g!!)\[!!)N(!!)_\!!)N(!!)_\!!)N(!!)\[!!&S*!.anF !!)orJ,~> r;Q`spAY0orrE&u!!*#u!!)fo!!(`g!!)]l!!)N(!!)`m!!)N(!!)`m!!)N(!!)]l!!&S*!.anF !!)orJ,~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEp qu;0~> r;Q`so`"mkrr2rurr2ruqu?NngqWmiopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEp qu;0~> r;Q`so`"mkrr2rurr2ruqu?NngqWmiopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEp qu;0~> r;Q`so`"mkrr2rurr2ruqu?NngqWmip&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:UEp qu;0~> r;Q`so`"mkrr2rurr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEp qu;0~> r;Q`so`"mkrVuisp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`so`"mkrVuisp\t3ng;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[S\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lS\P5Uq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[n%ePq]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[n%ePq]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!ln%ePq]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sn,N=dq#:UEp qu;0~> r;Q`sn,N=dq#:UEp qu;0~> r;Q`sn,N=dq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sn,E@fp&>!lg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,E@fp&>!lg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,E@fp&>!lg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`snG`Igo`"mkg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snG`Igo`"mkg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snG`Igo`"mkg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`snGiFep\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snGiFep\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`snGiFep\t3ng;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sm/I%cqu?NngqWmiopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sm/I%cqu?NngqWmiopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sm/I%cqu?NngqWmip&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sm/I%cq#:UEp qu;0~> r;Q`sm/I%cq#:UEp qu;0~> r;Q`sm/I%cq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMt q>UEpqu;0~> r;Q`sn,N@ep\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,N@ep\t3ng;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEp qu;0~> r;Q`sn,N@ep\t3ng;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEp qu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gopGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[]YFMtq>UEpqu;0~> r;Q`sir8uYg;![gp&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l]YFMtq>UEpqu;0~> r;Q`sir8uYq7uS%nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA+YrnA+Vq q7lu\q>UEpqu;0~> r;Q`sir8uYq7uS%nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA+YrnA+Vq q7lu\q>UEpqu;0~> r;Q`sir8uYq7uS%nA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA+YrnA+Vq q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[nA##( p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sir8uYq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!lnA##( pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[ nA##(p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1opGd[nA##(opGd[nA##(p6bm\nA##(p6bm\nA##(opGd[nA##(opGd[ nA##(p6bm\nA##(opGd[q7lu\q>UEpqu;0~> r;Q`sn,N@ep\t3nq7lt1p&>!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##(p&>!l nA##(pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lnA##(p&>!lnA##(pAY*mnA##(pAY*mnA##(p&>!lnA##( p&>!lnA##(pAY*mnA##(p&>!lq7lu\q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1pAY*m q7lt1q7lt1p&>!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1q>UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1pAY*m q7lt1q7lt1p&>!lq7lt1q7lt1p&>!lq7lt1q7lt1pAY*mq7lt1q7lt1p&>!lq7lt1q>UEpqu;0~> r;Q`snG`Igrr2ruqu;3IL]I8N!!)orJ,~> r;Q`snG`Igrr2ruqu;3IL]I8N!!)orJ,~> r;Q`snG`Igrr2ruqu;3IL]I8N!!)orJ,~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`snG`Igrr2ruq#:UEpqu;0~> r;Q`sn,N@ep\t3nj8T)Zj8T)ZjSo2[jSo2[j8T)Zj8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sn,N@ep\t3nj8T)Zj8T)ZjSo2[jSo2[j8T)Zj8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sn,N@ep\t3nj8T)Zj8T)ZjSo2[jSo2[j8T)Zj8T)ZjSo2[j8T)Zq>UEpqu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sec5UKjSo2[jT#2Zjo>;[jo5;\jo>8Zk5YD\n,E@fr;Q`sjSo2[qu;0~> r;Q`sec5UKjSo2[jT#2Zjo>;[jo5;\jo>8Zk5YD\n,E@fr;Q`sjSo2[qu;0~> r;Q`sec5UKjSo2[jT#2Zjo>;[jo5;\jo>8Zk5YD\n,E@fr;Q`sjSo2[qu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukPkM^rr2rukPtP^jo5;\jSo2[rr2runGiLgrr;uujSo2[ qu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukPkM^rr2rukPtP^jo5;\jSo2[rr2runGiLgrr;uujSo2[ qu;0~> r;Q`sf)G^Mrr2ruk5YG]jo5;\rr2rukPkM^rr2rukPtP^jo5;\jSo2[rr2runGiLgrr;uujSo2[ qu;0~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)'Z!!)6_!W`6#k5PD]j8T)Zm/R(crr;uus8W&us8N3%rrE*! rW)Qi!!)orJ,~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)'Z!!)6_!W`6#k5PD]j8T)Zm/R(crr;uus8W&us8N3%rrE*! rW)Qi!!)orJ,~> r;Q`sf)G^Mrr2rukPkS`rrD$X!!)'Z!!)6_!W`6#k5PD]j8T)Zm/R(crr;uus8W&us8N3%rrE*! rW)Qi!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\iVrlXjo>>\kPkS`rrD3]r;c![r;c r;Q`sf)G^Mrr2rujo5;\iVrlXjo>>\kPkS`rrD3]r;c![r;c r;Q`sf)G^Mrr2rujo5;\iVrlXjo>>\kPkS`rrD3]r;c![r;c r;Q`sf)G^Mrr2rujo5;\ir8uYir8uYl2Lhcs8N)Yrr<&^rr<&urr<&grs/W)!<3'!!<3&urrN3# !<3#r!;-9k!;leH~> r;Q`sf)G^Mrr2rujo5;\ir8uYir8uYl2Lhcs8N)Yrr<&^rr<&urr<&grs/W)!<3'!!<3&urrN3# !<3#r!;-9k!;leH~> r;Q`sf)G^Mrr2rujo5;\ir8uYir8uYl2Lhcs8N)Yrr<&^rr<&urr<&grs/W)!<3'!!<3&urrN3# !<3#r!;-9k!;leH~> r;Q`sf)G^Mrr2rujo5;\j8T)ZiVrlXl2UY]j8T)ZkPkM^rr2runG`aorrE'!rrE'!rr3$"rrE&u !!)Ng!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\j8T)ZiVrlXl2UY]j8T)ZkPkM^rr2runG`aorrE'!rrE'!rr3$"rrE&u !!)Ng!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\j8T)ZiVrlXl2UY]j8T)ZkPkM^rr2runG`aorrE'!rrE'!rr3$"rrE&u !!)Ng!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\jSo2[jSo2[rr2ruk5PD]k5PD]rr2rukPkM^rr2runG`aos8N*!rrE'! rr3$"rrE&u!!*#u!!)Zk!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\jSo2[jSo2[rr2ruk5PD]k5PD]rr2rukPkM^rr2runG`aos8N*!rrE'! rr3$"rrE&u!!*#u!!)Zk!!)orJ,~> r;Q`sf)G^Mrr2rujo5;\jSo2[jSo2[rr2ruk5PD]k5PD]rr2rukPkM^rr2runG`aos8N*!rrE'! rr3$"rrE&u!!*#u!!)Zk!!)orJ,~> r;Q`sec5UKjSo2[jo>5Yk5YD\jo5;\jo>;[jo>;[n,EXns8N*!rrE*!rW)uu!!)utrW)Qi!!)or J,~> r;Q`sec5UKjSo2[jo>5Yk5YD\jo5;\jo>;[jo>;[n,EXns8N*!rrE*!rW)uu!!)utrW)Qi!!)or J,~> r;Q`sec5UKjSo2[jo>5Yk5YD\jo5;\jo>;[jo>;[n,EXns8N*!rrE*!rW)uu!!)utrW)Qi!!)or J,~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;Q`sJcC<$jSo2[qu;0~> r;V r;V r;V JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> JcC<$fDg@~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/exponential-fig.ps0000644000175000000620000000544611466723256020636 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: exponential-fig.ps %%CreationDate: Wed Jul 13 12:15:23 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2136 ASCII Bytes image s8N)ri;WlYq>9+M!rr5ri;WlYrVPOQ!rr5oi;WlYrVPOQ!rqb8i;`iW!;YRQs8N)pi;`iW!;bXR s8N)qi;`iW!;bXRs8N,qJ)UG-rrN"HiW&rX!W.B*s8W*"qnM+is8N,s^Z#4mrrN#3iW&rX!W1d5 s8W*"qqpB4s8N,qn)=L s8W*!q>:0ln)s`NrrDrnrrDfVs8W*!qtpBnqre"ZrrDrnrrE#\s8W*!qtpBnroa=]rrDrmrr>:I s8W*!qtg1*kpZVYWrrDrmrrDr[s8W*!qtg($jqs".\rrDrlrrDu] s8W*!qtU0kJ*R(6rrDrkrrBh!s8W*!qtU0kcg(N3htR$CrrDfYrrTCiqtU0kqli.%Cj88TN!;GgZs8N)rp\t6hli7"b!;lNj!WIT8s8W*!qtC$i ^[2"#rrDrirrCC3s8W*!qtC$ioBcMWrrDlgrrDu`s8W*!qt9sh+79+.rrDrhrrD6Ls8W*!qt9sh q!J+]rrDrgrr=//s8W*!qt0mgj6lsIrrDrgrrDubs8W*!qt'gf+7K70rrDldrrD*Js8W*!qt'gg r'0]Ns8N)ro)A^1nGiOg!;l?e!Vh07s8W*!qsj[dJard?rrDrdrrN*0o)Jai!;l9c!Ur>Fs8W*! qsXOb_=R^,rrDl`rrN*(o`+sk!;l3a!Vcoms8W*!qsFCap]1$fs8N)rli-tc5PY9YrrDr]rrKn? q>^Kp!;l$\!VcZks8W*!qtpBn^\n*3qtpBnJ,Kr;QcWr;Qcpqu6ZVr;Qfss5!^*~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/nyquist/cauchy-fig.ps0000644000175000000620000000647111466723256017563 0ustar stevestaff%!PS-Adobe-3.0 EPSF-3.0 %%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner %%Title: cauchy-fig.ps %%CreationDate: Wed Jul 13 12:15:04 2005 %%DocumentData: Clean7Bit %%LanguageLevel: 2 %%Pages: 1 %%BoundingBox: 14 14 303 191 %%EndComments %%BeginProlog % Use own dictionary to avoid conflicts 10 dict begin %%EndProlog %%Page: 1 1 % Translate for offset 14.173228346456694 14.173228346456694 translate % Translate to begin of first scanline %0 176 translate -40 760 translate 288 -176 scale % Image geometry 288 176 1 % Transformation matrix [ 288 0 0 176 0 0 ] currentfile /ASCII85Decode filter /RunLengthDecode filter %%BeginData: 2672 ASCII Bytes image nG`Lfn,MnW!<2HenG`Lfn,MnW!WITo)AgXqnDgos760llhS9lnGi(Z"7,f447N:@rr_T`If&X7o)Agd\UOMH s7--hrW)ods7--grp]sXs8W&uIdmC-s8N#es7-*jrVlfcs7-*krVlhHnc/.Z"9&6!J+s760nqu?YFs*sV>o)Amjs8N&u J+EX1rrr<"rr<#5o)J:\"oJ?!s8Tk)s760np](6ms1e.)o)Amfs8INJ^[hEqrrr/srr<#Uo)J:\ "o&#qs8V!Is760nlhpb^s53DIo)AmZqYpNpht$grs/#YrVf%]s6oRZoD\p]li-n_rrDNZs7?6mhtO\\rr2ueoDeF^"5j.Y rr2otp[eFVrr_0Ys8N#t!;H*boD]'1s8W(Js8Vufs7?6m^]4?5rr2uqoDeF^"2Fm9rr2otqt'jZ rr[cNs8N#t!<)NhoD\oBs8W)trrE#hs7H$j rVllsrVllso`+Ua!<)lr!<2or!.X\Ap&>$hrVlotJ,TBI^\.X"rrDrprrE&rrrBh,s7QBlp\k*l rqucrht@$BrrDNdrrE&rrrDN\s7QBlhu3QTrqucrn+H_RrrBh4rrN+KrVlllp&F^b!5JL4!<2or !;lHhp&>#ArVllsr;Qcqp&Fac!<2or!<2or!<)TjpAY-kr;Qcrr;Qcrp&Fac!;l]o!WITHrr@QB s7ZHmp\b$krql]q^\7^$rrDNcrrE&qrrCsMs7ZHmn,31crql]qn+QeTrrCsSrrE&qrrDfes7ZHm ^\n*4rdXkG!;Z?gpAY,Br;Qcrqu6ZqpAame!;ufq!r)NiqYpPFp](!f!;l`p!pfgaqYpPfp](!f !;HHl!pfgaqYpQap](!f!:Tmd"7,pb5PtH\p\4^^rrA\irrVNbrqcWpq=jparrN+KrVlrnY^ZHK !WITDs7lToq>1*krqZQoTD8H]rrD6YrrE&orrD6Ws7lToTDJQgrdXeE!;lQkq>UKpJ,90FrqZQo r:p:Zs7uZpa8,`8rqQKnch[V:rr>:ZrrE&nrrDTbs8)`qq"XjirdXbD!WITF s8)`qa8#Z7rqHEmO8AnRrrN$^q#:?np\t6_qZ$Hm!/(%G!<2]l!!E,ur;QfeJ+rsCrq??mr#bk: rVlor&,-#(rdXYA!9!eTrVlkMp&>$ko`"mnrVuls!T8J#rrE&jrrN$.rr<#u!T5'lrrE&irr_a$ s8N0#p`K,-!<2Qh!q8GSnG`OgJ+3L-rrE&es7$$grpTmcrrE&qrrDNcrrE&qrrDNcrrE&rs!.R@ s53hUp]&#,s6ou;qu>RQs7cQ.rVu?dJ,B9'rr;`m^]+<5hZ*ZVnG`Lfn,MnW!<2HenG`Lfn,MnW !<2Heh>dEQ!5JI3!;H0d!8m_S!<2orr;Qa]r;Qc_p&>#qr;Qcpr;Z`q!WKk3rrDfdrrCsSrrDon s8Dru`ZP0Z!W707rrCsSrrMnErVufq!5JI3!:TU\!5JI3!<2orr;Qa=r;QcWp&>#Qr;QfqJ,TE' s*t~> %%EndData showpage %%Trailer end %%EOF nyquist-3.05/docsrc/toafs.bat0000644000175000000620000000032111466723256015254 0ustar stevestaffcopy nyquist\*.mss p:\doc\man\nyquist copy nyquist\*.ps p:\doc\man\nyquist copy bib\music.bib p:\doc\man\bib\music.bib copy template\filcap.mss p:\doc\man\template\filcap.mss copy xlisp\*.mss p:\doc\man\xlisp nyquist-3.05/docsrc/bib/0002755000175000000620000000000011537433126014203 5ustar stevestaffnyquist-3.05/docsrc/bib/music.bib0000644000175000000620000025063411466723256016020 0ustar stevestaff@article(4CED ,key "Abbot" ,author "Abbot, Curtis" ,title "The 4CED Program" ,journal "Computer Music Journal" ,Volume 5 ,Number 1 ,Month "Spring" ,Year 1981 ,Pages "13-33" ) @book(surveys ,key "Abbot" ,editor "Abbot. C." ,publisher "ACM" ,title "Computing Surveys" ,year 1985 ,volume 17 ,note "No. 2 (June)" ) @book(abelson ,key "Abelson" ,author "Abelson, H. and G. J. Sussman, with J. Sussman" ,title "Structure and Interpretation of Computer Programs" ,publisher "MIT Press" ,year 1985 ) @inproceedings(Mach ,author "Accetta, M., R. Baron, W. Bolosky, D. Golub, R. Rashid, A. Tevanian, M. Young" ,title "Mach: A New Kernel Foundation for UNIX Development" ,organization "Usenix" ,booktitle "Proc. of Summer Usenix" ,year 1986 ,month July ) @article(ashton ,key "Ames" ,author "Ames, C." ,title "The ASHTON Score-Transcription Utility" ,journal "Interface" ,volume 14 ,pages "165-173" ,year 1985 ) @book(hypertext89 ,author "ACM" ,key "ACM" ,organization "ACM" ,title "Hypertext '89 Proceedings" ,publisher "ACM" ,year 1989 ) @inproceedings(rodet85 ,key "Adrien" ,author "Adrien, J-M, and X. Rodet" ,title "Physical Models of Instruments: A Modular Approach, Application to Strings" ,organization "Computer Music Association" ,booktitle "Proceedings of the 1985 International Computer Music Conference" ,year 1985 ,pages "85-96" ) @book(aho ,author="Aho, Hopcroft, and Ullman" ,title="The Design and Analysis of Computer Algorithms" ,publisher="Addison Wesley" ,key="Aho" ,year=1974 ) @inproceedings(Allen90 ,key "Allen" ,author "Allen, P. E. and R. B. Dannenberg" ,title "Tracking Musical Beats in Real Time" ,organization "International Computer Music Association" ,booktitle "ICMC Glasgow 1990 Proceedings" ,editor "S. Arnold and G. Hair" ,year 1990 ,pages "140-143" ) @unpublished(Anderson85b ,key "Anderson" ,author "Anderson, D. P. and R. Kuivila" ,title "Continuous Abstractions for Discrete Event Languages" ,year "1985" ) @article(Formula-TOCS ,key "Anderson" ,author "Anderson, D. P. and R. Kuivila" ,title "A System for Computer Music Performance" ,journal "ACM Transactions on Computer Systems" ,volume 8 ,number 1 ,pages 56-82 ,month February ,year 1990 ) @article(Formula ,key "Anderson" ,author "Anderson, D. P. and R. Kuivila" ,title "Accurately Timed Generation of Discrete Musical Events" ,journal "Computer Music Journal" ,volume 10 ,number 3 ,month "Fall" ,year 1986 ,pages "48-56" ) @techreport(acme ,key "Anderson" ,title "Abstractions for Continuous Media in a Network Window System" ,author "Anderson, D. P., R. Govindan, G. Homsy" ,institution "Computer Science Division (EECS), U.C. at Berkeley" ,number "UCB/CSD 90/596" ,year 1990 ) @article(acmecomputer ,key "Anderson" ,title "A Continuous Media I/O Server and Its Synchronization Mechanism" ,author "Anderson, D. P. and G. Homsy" ,journal "Computer" ,month "October" ,pages "51-57" ,year 1991 ) @article(andrews ,key Andrews ,author "Andrews, G. R." ,title "Concepts and Notations for Concurrent Programming" ,journal "ACM Computing Surveys" ,volume 15 ,number 1 ,month "March" ,year 1983 ,pages "3-43" ) @article(lisp-tutor ,key = Anderson ,author "Anderson, J. R., F. G. Conrad, and A. T. Corbett" ,title "Skill acquisition and the LISP TUTOR" ,journal "Cognitive Science" ,volume 13 ,number 4 ,month "Oct-Dec" ,year 1989 ,pages "467-505" ) @misc(smdl ,key="ANSI" ,author="ANSI" ,title="X3V1.8M/SD-7 Journal of Development, Standard Music Description Language, Part 2: Technical Description and Formal Definition" ,howpublished="International Computer Music Association, San Francisco" ) @article(Lucid ,key "Ashcroft" ,author "Ashcroft, E. A. and W. W. Wadge" ,title "Lucid, a Nonprocedural Language with Iteration" ,journal "Communications of the ACM" ,volume "20" ,number "7" ,month "July" ,year "1977" ,pages "519-526" ) @inproceedings(Assayag ,key "Assayag" ,author "Assayag, G., and D. Timis" ,title "A ToolBox for Music Notation" ,pages "173-178" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ) @article(Backus ,key "Backus" ,author "Backus, John" ,title "Can Programming Be Liberated from the von Neumann Style?" ,journal "Communications of the ACM" ,Volume 21 ,Number 8 ,Month "August" ,Year 1978 ,Pages "613-641" ) @article(Baird93 ,key "Baird" ,author "Baird, B., D. Blevins, N. Zahler" ,title "Artificial Intelligence and Music: Implementing an Interactive Computer Performer" ,journal "Computer Music Journal" ,volume 17 ,number 2 ,month "Summer" ,year 1993 ,pages "73-79" ) @techreport(balaban ,key "Balaban" ,title "Music Structures: A Temporal-Hierarchical Representation For Music" ,author "Balaban, Mira" ,institution "Ben Gurion University Department of Mathematics and Computer Science" ,number "FC-TR-021 MCS-313" ,year 1989 ) @article(Balzano80 ,key="Balzano" ,author="Balzano, G. J." ,title="The Group-theoretic Description of 12-Fold and Microtonal Pitch Systems" ,journal="Computer Music Journal" ,number="4" ,year="1980" ,volume="4" ,pages="66-84" ) @book(FMA ,key="Benade" ,author="Benade, A. H." ,title="Fundamentals of Musical Acoustics" ,publisher="Oxford University Press" ,year="1976" ) @inproceedings(berger ,key "Berger" ,author "Berger, Jonathan" ,title "Theory and Practice: Chicken and Egg" ,booktitle "The Arts and Technology II: A Symposium" ,pages "24-30" ,year 1989 ,organization "Connecticut College" ) @article(bentley, key="Bentley" ,author="Bentley, Jon" ,title="Programming Pearls" ,journal="Communications of the ACM" ,volume="28", number="3" ,pages="245-250" ,year=1985 ) @unpublished(Betz ,key "Betz" ,author "Betz, David" ,title "XLISP: An Experimental Object-oriented Language, Version 1.7" ,date "June 2" ,year 1986 ,note "(program documentation)" ) @Misc(Blackwood80 ,key="Blackwood" ,author="Blackwood, E." ,title="Twelve Microtonal Etudes for Electronic Music Media" ,howpublished="Stereo LP Recording available from Easley Blackwood, 5300 S. Shore Drive, Chicago, IL 60615" ,note="score published by G. Schirmer" ) @book(knowledgerep ,key "Brachman" ,author "Brachman, R. J., and H. J. Levesque, eds." ,title "Readings in Knowledge Representation" ,publisher "M. Kaufmann" ,year 1985 ,address "Los Altos, Calif." ) @book(MultimediaInterfaceDesign ,key "Blattner" ,editors "Blattner, M. M. and R. B. Dannenberg" ,title "Multimedia Interface Design" ,publisher "ACM Press" ,year 1992 ) @inproceedings(bilmes92 ,key "Bilmes" ,author "Bilmes, J." ,title "A Model for Musical Rhythm" ,organization "Computer Music Association" ,booktitle = "ICMC Proceedings" ,year = "1992" ,pages "207-210" ,organization = "International Computer Music Association" ,address "San Francisco" ) @article(Blesser ,key "Blesser" ,author "Blesser, B. A." ,title "Digitization of Audio: A Comprehensive Examination of Theory, Implementation, and Current Practice" ,journal "Journal of the Audio Engineering Society" ,volume 26 ,number 10 ,pages "739-771" ,year 1978 ,month "October" ) @inproceedings(Bloch ,key "Bloch" ,author "Bloch, J. J. and R. B. Dannenberg" ,title "Real-Time Computer Accompaniment of Keyboard Performances" ,organization "International Computer Music Association" ,booktitle "Proceedings of the International Computer Music Conference 1985" ,editor "B. Truax" ,year 1985 ,pages "279-290" ) @inproceedings(bloom, key = "Bloom", Author = "Bloom, P. J.", Publisher = "IEEE", year = "1984", title = "Use of Dynamic Programming for Automatic Synchronization of Two Similar Speech Signals", booktitle = "Proceedings of IEEE International Conference on Acoustics, Speech, and Signal Processing", Pages = "2.6.1-2.6.4") @inproceedings(BockerStructure ,key = "Bocker" ,Author = "Bocker, H.-D. and A. Mahling" ,title = "What's in a Note?" ,pages= "166-174" ,booktitle = "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,year = "1988" ,organization = "International Computer Music Association" ) @article(Constraints ,key = "Borning" ,Author = "Borning, A." ,Title = "The Programming Language Aspects of Thinglab: A Constraint-Oriented Simulation Laboratory" ,Journal = "ACM Transactions on Programming Languages and Systems" ,Volume 3 ,Number 4 ,month October ,year 1981 ,pages "353-387" ) @inproceedings(midilisp, key = "Boynton" ,Author = "Boynton, L., P. Lavoie, Y. Orlarey, C. Rueda and David Wessel" ,title = "MIDI-LISP: A Lisp Based Music Programming Environment for the Macintosh" ,pages= "183-186" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ) @inproceedings(preformes, key = "Boynton" ,Author = "L. Boynton, J. Duthen, Y. Potard, and X. Rodet" ,title = "Adding a Graphical Interface to FORMES." ,pages= "105-108" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ) @inproceedings(brinkmanstructure ,key = "Brinkman" ,author = "Brinkman, A." ,title = "A Data Structure for Computer Analysis of Musical Scores" ,organization "Computer Music Association" ,booktitle "Proceedings of the 1984 International Computer Music Conference" ,year 1985 ,pages "233-242" ) @inproceedings(brinkmanGraphs ,key = "Brinkman" ,author = "Brinkman, A." ,title = "Computer-Graphic Tools for Music Analysis" ,organization "Computer Music Association" ,booktitle = "ICMC Montreal 1991 Proceedings" ,year = "1991" ,pages "53-56" ,editor "B. Alphonse and B. Pennycook" ,organization = "International Computer Music Association" ,address "San Francisco" ) @article(Buxton, key = "Buxton", Author = "Buxton, W., Reeves, W., Fedorkow, G., Smith, K. C., and Baecker, R.", Journal = "Computer Music Journal", Title = "A Microcomputer-based Conducting System", Year = "1980", Month = "Spring", Number = "4", Pages = "8-21", Volume = "4") @inbook(BuxtonViews ,key = "Buxton", ,Author = "Buxton, W., R. Sniderman, W. Reeves, R. Patel, and R. Baecker" ,Title = "The Evolution of the SSSP Score-Editing Tools" ,Year = "1985" ,Booktitle "Foundations of Computer Music" ,Pages = "376-402" ,editor "C. Roads and J. Strawn" ,publisher "MIT Press" ) @inbook(BuxtonStructures ,key = "Buxton", ,Author = "Buxton, W., W. Reeves, R. Baecker, and L. Mezei" ,Title = "The Use of Hierarchy and Instance in a Data Structure for Computer Music" ,Year = "1985" ,Booktitle "Foundations of Computer Music" ,Pages = "443-466" ,editor "C. Roads and J. Strawn" ,publisher "MIT Press" ) @article(buxton-modeless ,key "Buxton" ,author "Buxton, William" ,title "Lexical and pragmatic considerations of input structures" ,journal "Computer Graphics" ,volume 17 ,number 1 ,pages "31-36" ,year 1983 ) @inproceedings(buxton85 ,key "Buxton" ,author "Kitamura, J., W. Buxton, M. Snelgrove and K. C. Smith" ,title "Music Synthesis by Simulation using a General-Purpose Signal Processing System" ,organization "Computer Music Association" ,booktitle "Proceedings of the 1985 International Computer Music Conference" ,year 1985 ,pages "155-158" ) @inproceedings(accompchi ,key "Buxton" ,author "Buxton, W., Dannenberg, Roger B., Vercoe, Barry" ,title "The Computer as Accompanist" ,organization "ACM" ,address "New York" ,booktitle "Proceedings of the CHI'86 Human Factors in Computing Systems" ,editor "M. Mantei and P. Orbeton" ,year 1986 ,pages "41-43" ) @inproceedings(mabel ,key = "Bartlett" ,author = "Bartlett, M." ,title="The Development of a Practical Live-Performance Music Language" ,pages= "297-302" ,booktitle = "Proceedings of the International Computer Music Conference 1985" ,editor "B. Truax" ,year = "1985" ,organization = "International Computer Music Association" ) @phdthesis(Byrd, ,key = "Byrd" ,author = "Byrd, Donald" ,Title = "Music Notation by Computer" ,school = "Computer Science Department, Indiana University" ,year = 1984 ,note = "Ann Arbor: University Microfilms (order no. DA8506091)" ) @book(cage ,key "Cage" ,author "Cage, John" ,title "Silence" ,publisher "MIT Press" ,address "Cambridge, MA" ,year "1969" ) @article(L0 ,key "Cameron" ,author "Cameron, E. J., D. M. Cohen, B. Gopinath, W. M. Keese II, L. Ness, P. Uppaluru, and J. R. Vollaro" ,title "The IC* Model of Parallel Computation and Programming Environment" ,journal "IEEE Transactions on Software Engineering" ,month "March" ,year 1988 ,pages "317-326" ) @book(campbell ,key "Campbell" ,author "Campbell, R. H. and Habermann, A. N." ,title "The Specification of Process Synchronization by Path Expressions" ,series "Lecture Notes in Computer Science" ,volume 16 ,publisher "Springer Verlag" ,address "New York" ,year "1974" ) @article(ptcurriculum ,key "Capell" ,author "Capell, P. and R. B. Dannenberg" ,title "Instructional Design and Intelligent Tutoring: Theory and the Precision of Design" ,journal "Journal of Artificial Intelligence in Education" ,year "1993" ,pages "95-121" ,volume 4 ,number 1 ) @inproceedings(jdb ,key = "Chabot" ,author = "Chabot, Xavier, Roger Dannenberg, and Georges Bloch" ,title="A Workstation in Live Performance: Composed Improvisation" ,pages= "57-59" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ) @article(chadabe, key "Chadabe" ,title "Interactive Composing: An Overview" ,journal "Computer Music Journal" ,author "Chadabe, Joel" ,year "1984" ,volume 8, number 1 ,pages "22-27" ) @article(play , key "Chadabe" ,title "An Introduction to the Play Program" ,author "Chadabe, J., and R. Meyers" ,journal "Computer Music Journal" ,year "1978" ,volume 2, number 1 ,pages "12-18" ) @article(Chafe, key = "Chafe", Author = "Chafe, Chris, Bernard Mont-Reynaud, and Loren Rush", Journal = "Computer Music Journal", Title = "Toward an Intelligent Editor of Digital Audio: Recognition of Musical Constructs", Year = "1982", Month = "Spring", Number = "1", Pages = "30-41", Volume = "6") @InProceedings(poly, key = "Chafe" ,Author = "Chafe, Chris, David Jaffe, Kyle Kashima, Bernard Mont-Reynaud, and Julius Smith" ,Organization = "International Computer Music Association", ,year = "1985" ,booktitle = "1985 Proceedings of the International Computer Music Conference", ,title = "Techniques for Note Identification in Polyphonic Music" ,pages "399-405" ) @article(chowning ,key "Chowning" ,author "Chowning, J. M." ,title "The Synthesis of Complex Audio Spectra by Means of Frequency Modulation" ,journal "Journal of the Audio Engineering Society" ,Volume 21 ,Number 7 ,Month "September" ,Year 1973 ) @inbook(clark ,key "Clark" ,author "Clark, E. F." ,title "Expression and communication in musical performance" ,booktitle "Music, Language, Speech and Brain" ,series "Wenner-Gren International Symposium Series, Vol. 59" ,year 1991 ,editor "J. Sundberg, L. Nord, and R. Carlson" ,pages "184-193" ,publisher "Macmillan" ,address "London" ) @InProceedings(Clendinning, key = "Clendinning", Author = "Clendinning, J. and Dworak, P. E.", Organization = "International Computer Music Association", year = "1983", booktitle = "1983 International Computer Music Conference Proceedings", title = "Computer Pitch Recognition: A New Approach") @inbook(clynes ,key = "Clynes" ,author "Clynes, M." ,booktitle "Action and Perception in Rhythm and Music" ,title "What Can a Musician Learn About Music Performance From Newly Discovered Microstructure Principles (PM and PAS)?" ,publisher "Royal Swedish Academy of Music No. 55" ,year 1987 ,pages "201-233" ) @inproceedings(FPFormes ,key "Cointe" ,author "Cointe, P. and X. Rodet" ,title "Formes: an Object & Time Oriented System for Music Composition and Synthesis" ,organization "ACM" ,booktitle "1984 ACM Symposium on LISP and Functional Programming" ,address "New York" ,year 1984 ,pages "85-95" ) @inproceedings(Moxie ,key = "Collinge" ,author = "Collinge, D. J." ,title = "MOXIE: A Language for Computer Music Performance" ,pages = "217-220" ,booktitle = "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,year = "1985" ,organization = "International Computer Music Association" ) @inproceedings(Moxie88collinge ,key = "Collinge" ,author = "Collinge, D. J. and Scheidt, D. J." ,title = "MOXIE for the Atari ST" ,pages = "231-238" ,booktitle = "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,year = "1988" ,organization = "International Computer Music Association" ) @inproceedings(Moxc88pennycook ,key = Pennycook ,author = "Pennycook, Bruce W." ,title = "PRAESCIO-II: AMNESIA Toward Dynamic Tapeless Performance" ,pages = "383-391" ,booktitle = "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,year = "1988" ,organization = "International Computer Music Association" ) @article(Bradford ,key = "Comerford" ,author = "Comerford, P. J." ,title = "Bradford musical instrument simulator" ,pages = "364-372" ,journal = "IEE Proc." ,volume = "128, Pt. A" ,number = 5 ,month = "July" ,year = 1981 ) @book(ObjectiveC ,key "Cox" ,author "Cox, B. J." ,title "Object-Oriented Programming: an evolutionary approach" ,publisher "Addison-Wesley" ,year 1987 ,address "Reading, Mass." ) @phdthesis(Dannenberg82 ,key "Dannenberg" ,author "Dannnenberg, Roger B." ,title "Resource Sharing in a Network of Personal Computers" ,school "Carnegie Mellon University" ,year 1982 ,note "School of Computer Science Report CMU-CS-82-152" ) @inproceedings(teaching ,key = "Dannenberg" ,author = "Dannenberg, F. K., R. B. Dannenberg, and P. Miller" ,title = "Teaching Programming to Musicians" ,pages = "114-122" ,booktitle = "Proceedings Fourth Symposium on Small Computers in the Arts" ,year = 1984 ,editor = "D. Mansfield" ,address = "Washington, D.C." ,month = "October" ,organization = "IEEE Computer Society" ) @inproceedings(ArcticLisp ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Arctic: A Functional Language for Real-Time Control" ,organization "ACM" ,booktitle "1984 ACM Symposium on LISP and Functional Programming" ,address "New York" ,year 1984 ,month "August" ,pages "96-103" ) @inproceedings(Dannenberg ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "An On-Line Algorithm for Real-Time Accompaniment" ,organization "International Computer Music Association" ,booktitle "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,pages "193-198" ,year 1984 ) @InProceedings(Studio84 ,author = "Dannenberg, Roger B., Paul McAvinney, and Marilyn T. Thomas" ,key = "Dannenberg" ,title = "Carnegie-Mellon University Studio Report" ,booktitle = "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,year = "1984" ,organization = "International Computer Music Association" ,pages = "281-286" ) @InProceedings(ArcticICMC ,author = "Dannenberg, R. B. and P. McAvinney" ,key = "Dannenberg" ,title = "A Functional Approach to Real-Time Control" ,booktitle = "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,year = "1984" ,organization = "International Computer Music Association" ,pages = "5-15" ) @inproceedings(Arctic86 ,key "Dannenberg" ,author "Dannenberg, Roger B." ,title "Arctic: Functional Programming for Real-Time Systems" ,organization "U. Hawaii/Western Periodicals" ,editor "B. Shriver" ,booktitle "Proceedings of the Nineteenth Hawaii International Conference on System Sciences" ,year 1986 ,pages "216-226" ) @article(ArcticIEEE ,key "Dannenberg" ,author "Dannenberg, Roger B." ,title "Arctic: A Functional Language for Real-Time Control" ,journal "IEEE Software" ,month January ,volume 3 ,number 1 ,year 1986 ,pages "70-71" ) @inproceedings(aep86 ,key = "Dannenberg" ,author = "Dannenberg, Roger B." ,title = "Workstations for Computer Music at Carnegie Mellon" ,pages = "109 - 117" ,volume = "II" ,booktitle = "1986 University AEP Conference" ,editor = "F. Dwyer" ,year = "1986" ,organization = "IBM Academic Information Systems" ,address = "472 Wheelers Farms Road, Milford, Connecticut 06460" ) @inproceedings(cmt ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "The CMU MIDI Toolkit" ,booktitle = "Proceedings of the 1986 International Computer Music Conference" ,year = "1986" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "53-56" ) @inproceedings(musicrep ,key = "Dannenberg" ,author = "Dannenberg, R. B." ,title = "A Structure for Representing, Displaying and Editing Music" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ,pages = "153-160" ) @manual(old-cmt-manual ,key = "Dannenberg" ,author "Dannenberg, R. B" ,title "The CMU MIDI Toolkit" ,year "1986" ,publisher "Studio for Creative Inquiry, Carnegie Mellon University" ) @manual(cmt-manual ,key = "Dannenberg" ,author "Dannenberg, R. B" ,title "The CMU MIDI Toolkit" ,year "1993" ,publisher "School of Computer Science, Carnegie Mellon University" ) @article(ArcticCMJ ,key = "Dannenberg" ,author = "Dannenberg, R. B., P. McAvinney, and D. Rubine" ,title = "Arctic: A Functional Language for Real-Time Systems" ,journal = "Computer Music Journal" ,volume = "10" ,number = "4" ,month = "Winter" ,year = "1986" ,pages = "67-78" ) @inproceedings(Dannenberg87 ,key "Dannenberg" ,title "Following an Improvisation in Real Time" ,author "Dannenberg, R. B. and B. Mont-Reynaud" ,booktitle "Proceedings of the 1987 International Computer Music Conference" ,editor "J. Beauchamp" ,pages 241-248 ,year 1987 ,organization "International Computer Music Association" ,address "San Francisco" ) @inproceedings(ircamWorkbench ,key "Dannenberg" ,author "Dannenberg, Roger B." ,title "Systemes pour Informatique Musicale a l'universite de Carnegie Mellon" ,editor "J.-B. Barriere, F. Armand, and C. Marquet" ,booktitle "Actes du Symposium Systemes Personnels et Informatique Musicale" ,year 1987 ,organization "IRCAM, Paris, France" ) @article(JASA87 ,key Dannenberg ,author "Dannenberg, Roger B., Serra, Marie-Helen, Rubine, Dean" ,title "Comprehensive study of analysis and synthesis of tones by spectral interpolation" ,journal "Journal of the Acoustical Society of America" ,volume "Supplement 1, Vol 82" ,month Fall ,year 1987 ,pages S69 ) @inbook(workbench ,key "Dannenberg" ,author "Dannenberg, Roger B." ,title "A Project in Computer Music: The Musician's Workbench" ,address "Oxford, England" ,pages "354-388" ,booktitle "From Information to Knowledge" ,publisher "Intellect Books, Publications from the Society of Conceptual and Content Analysis by Computer (SCCAC)" ,year 1994. ,editor "Ephraim Nissan and Klaus M. Schmidt" ) @inproceedings(Dannenberg88a ,key "Dannenberg" ,title "New Techniques for Enhanced Quality of Computer Accompaniment" ,author "Dannenberg, R. B. and H. Mukaino" ,booktitle = "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,year = "1988" ,pages "243-249" ,organization = "International Computer Music Association" ,address "San Francisco" ) @inproceedings(animation89 ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Real Time Control For Interactive Computer Music and Animation" ,booktitle "The Arts and Technology II: A Symposium" ,editor "N. Zahler" ,address "New London, Conn." ,organization "Connecticut College" ,pages "85-94" ,year 1989 ) @inproceedings(realtime91 ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Software Support for Interactive Multimedia Performance" ,booktitle "Proceedings of The Arts and Technology 3" ,editor "D. Smalley, N. Zahler, and C. Luce" ,organization "Connecticut College" ,address "New London, Conn." ,pages "85-94" ,year 1991 ) @article(animationInterface ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Software Support for Interactive Multimedia Performance" ,journal "Interface Journal of New Music Research" ,pages "213-228" ,month August ,Volume 22 ,Number 3 ,year 1993 ) @inbook(klangart ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Computerbegleitung und Musikverstehen" ,booktitle "Neue Musiktechnologie" ,editor "B. Enders" ,pages "241-252" ,publisher "Schott" ,year "1993" ,address "Mainz" ) @inbook(dannenberg91 ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Recent work in real-time music understanding by computer" ,booktitle "Music, Language, Speech and Brain" ,series "Wenner-Gren International Symposium Series, Vol. 59" ,year 1991 ,editor "J. Sundberg, L. Nord, and R. Carlson" ,pages "194-202" ,publisher "Macmillan" ,address "London" ) @inproceedings(cmt-technique ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Software Techniques for Interactive Performance Systems" ,booktitle "International Workshop on Man-Machine Interaction in Live Performance" ,editor "L. Tarabella" ,address "Pisa" ,organization "Scuola di Stude Superiori Universitari e di Perfezionamento" ,year "to appear") @inproceedings(conducting ,key "Dannenberg" ,title "Practical Aspects of a MIDI Conducting Program" ,author "Dannenberg, R. B. and K. Bookstein" ,booktitle = "ICMC Montreal 1991 Proceedings" ,year = "1991" ,pages "537-540" ,editor "B. Alphonse and B. Pennycook" ,organization = "International Computer Music Association" ,address "San Francisco" ) @inproceedings(resource-instance ,key "Dannenberg" ,title "The Resource-Instance Model of Music Representation" ,author "Dannenberg, R. B., D. Rubine, T. Neuendorffer" ,booktitle = "ICMC Montreal 1991 Proceedings" ,year = "1991" ,pages "428-432" ,editor "B. Alphonse and B. Pennycook" ,organization = "International Computer Music Association" ,address "San Francisco" ) @article(CanonCMJ ,key = "Dannenberg" ,author = "Dannenberg, R. B." ,title = "The Canon Score Language" ,journal = "Computer Music Journal" ,volume = "13" ,number = "1" ,month = "Spring" ,year = "1989" ,pages = "47-56" ) @inbook(schedulers ,key "Dannenberg" ,title "Real-Time Scheduling and Computer Accompaniment" ,author "Dannenberg, Roger B." ,booktitle "Current Directions in Computer Music Research" ,pages "225-262" ,series "System Development Foundation Benchmark Series" ,editor "Mathews, M. V. and J. R. Pierce" ,year 1989 ,publisher "MIT Press" ) @inbook(jdbC ,key "Dannenberg" ,title "@i(Jimmy Durante Boulevard)" ,author "Dannenberg, Roger B." ,booktitle "@r(Compact Disc accompanying) Current Directions in Computer Music Research" ,series "System Development Foundation Benchmark Series" ,editor "Mathews, M. V. and J. R. Pierce" ,year 1989 ,publisher "MIT Press" ) @inproceedings(ICMCFugue ,key "Dannenberg" ,author "Dannenberg, R. B. and C. L. Fraley" ,title "Fugue: Composition and Sound Synthesis With Lazy Evaluation and Behavioral Abstraction" ,booktitle = "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,year = "1989" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "76-79" ) @inproceedings(musrepissues ,key "Dannenberg" ,author "Dannenberg, Roger B." ,title "Music Representation Issues: A Position Paper" ,booktitle = "Proceedings of the 1989 International Computer Music Conference" ,year = "1989" ,editor "T. Wells and D. Butler" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "73-75" ) @inbook(musun89 ,key Dannenberg ,author "Dannenberg, Roger B." ,title "Music Understanding" ,booktitle "Computer Science Research Review 1987/1988" ,publisher "Carnegie Mellon School of Computer Science" ,editor "C. Copetas" ,address "Pittsburgh, PA 15213, USA" ,year 1989 ,pages 19-28 ) @inproceedings(uist89 ,key "Dannenberg" ,author "Dannenberg, Roger B. and D. Amon" ,title "A Gesture Based User Interface Prototyping System" ,booktitle "Proceedings of the ACM SIGGRAPH Symposium on User Interface Software and Technology" ,year 1989 ,address "New York" ,pages "127-132" ,organization "ACM" ) @inproceedings(icmcmusrep ,key "Dannenberg" ,author "Dannenberg, R." ,title "A Structure for Representing, Displaying, and Editing Music" ,pages "153-160" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ) @article(spemusrep ,key "Dannenberg" ,author "Dannenberg, Roger B." ,title "A Structure for Efficient Update, Incremental Redisplay and Undo in Display-Oriented Editors" ,journal "Software: Practice and Experience" ,year 1990 ,volume 20 ,number 2 ,month February ,pages "109-132" ) @article(tpl ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Extending Music Notation Through Programming" ,journal "Contemporary Music Review" ,year "to appear" ) @article(ptinterface ,key "Dannenberg" ,author "Dannenberg, R. B., M. Sanchez, A. Joseph, P. Capell, R. Joseph, and R. Saul" ,title "A Computer-Based Multi-Media Tutor for Beginning Piano Students" ,journal "Interface" ,volume 19 ,number "2-3" ,pages "155-73" ,year 1990 ) @inproceedings(icmcptutor ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "An Expert System for Teaching Piano to Novices" ,booktitle = "ICMC Glasgow 1990 Proceedings" ,year = "1990" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "20-23" ,editor "S. Arnold and G. Hair" ) @inbook(accompvideo ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Computer Accompaniment and Following an Improvisation" ,booktitle "The ICMA Video Review" ,year "1991" ,publisher "International Computer Music Association" ,address "San Francisco" ,volume 1 ,note "(Video)" ) @incollection(bash ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Expressing Temporal Behavior Declaratively" ,booktitle "CMU Computer Science: a 25th Anniversary Commemorative", ,year 1991 ,publisher "Addison Wesley" ,pages "47-68" ) @inproceedings(nyquist ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "Real-Time Software Synthesis on Superscalar Architectures" ,booktitle = "Proceedings of the 1992 ICMC" ,year = "1992" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "174-177" ) @article(IEEEFugue ,key "Dannenberg" ,author "Dannenberg, R. B., C. L. Fraley, and P. Velikonja" ,title "Fugue: A Functional Language for Sound Synthesis" ,journal "Computer" ,month "July" ,year "1991" ,volume 24 ,number 7 ,pages "36-42" ) @inbook(fuguechap ,key "Dannenberg" ,author "Dannenberg, R. B., C. L. Fraley, and P. Velikonja" ,title "A Functional Language for Sound Synthesis with Behavioral Abstraction and Lazy Evaluation" ,editors "Denis Baggi" ,booktitle "Readings in Computer-Generated Music" ,publisher "IEEE Computer Society Press" ,address "Los Alamitos, CA" ,year 1992 ) @inbook(ptdialog ,title "Human-Computer Interaction in the Piano Tutor" ,author "Dannenberg, R. B. and R. L. Joseph" ,pages "65-78" ,key "Dannenberg" ,editors "Blattner, M. M. and R. B. Dannenberg" ,booktitle "Multimedia Interface Design" ,publisher "ACM Press" ,year 1992 ) @inproceedings(PianoTutor93 ,key "Dannenberg" ,author "Dannenberg, R. B., M. Sanchez, A. Joseph, R. Joseph, R. Saul, and P. Capell" ,title "Results from the Piano Tutor Project" ,booktitle "The Fourth Biennial Arts and Technology Symposium" ,editor "D. Smalley, N. Zahler, and P. Galvani" ,organization "Connecticut College" ,address "New London, Conn." ,pages "143-150" ,year 1993 ) @inproceedings(nyquist93 ,key "Dannenberg" ,author "Dannenberg, R. B." ,title "The Implementation of Nyquist, A Sound Synthesis Language" ,booktitle = "Proceedings of the 1993 ICMC" ,year = "1993" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "168-171" ) @inproceedings(realtimemusic ,key "Dannenberg" ,author "Dannenberg, R. B., and D. Jameson" ,title "Real-Time Issues in Computer Music" ,booktitle = "Proceedings of the Real-Time Systems Symposium" ,year = "1993" ,organization = "IEEE Computer Society" ,pages "258-261" ) @inbook(CMUResearch ,key "Dannenberg" ,author "Dannenberg, R." ,title "Computer Music at Carnegie Mellon University" ,year 1993 ,booktitle "Music Processing" ,pages "303-333" ,publisher "AR Editions" ,address "Madison" ) @techreport(machmediatr ,key "Dannenberg" ,author "Roger B. Dannenberg, David B. Anderson, Tom Neuendorffer, Dean Rubine, Jim Zelenka" ,Title " Performance Measurements of the Multimedia Testbed on Mach 3.0: Experience Writing Real-Time Device Drivers, Servers, and Applications" ,Number "CMU-CS-93-205" ,Date "July 1993" ,Institution "School of Computer Science, Carnegie Mellon University" ) @book(date ,key "Date" ,author "Date, C. J." ,title "An Introduction to Database Systems" ,publisher "Addison-Wesley" ,address "Reading, Mass." ,edition "5th ed." ,year 1991 ) @inproceedings(Decker ,key "Decker" ,author "Decker, S. and G. Kendall" ,Organization = "International Computer Music Association" ,year = "1984" ,title = "A Modular Approach to Sound Synthesis Software" ,booktitle = "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,pages "243-250" ) @article(Dennis80 ,key "Dennis" ,author "Dennis, Jack B." ,title "Data flow supercomputers" ,journal "Computer" ,volume 13 ,number 11 ,month "November" ,year "1980" ,pages "48-56" ) @inproceedings(streams ,key "Dennis" ,author "Dennis, Jack B. and Weng, Ken K.-S." ,title "An Abstract Implementation For Concurrent Computation With Streams" ,organization "IEEE Computer Society" ,year "1979" ,booktitle "Proceedings of the 1979 International Conference on Parallel Processing" ) @book(depoli ,key "DePoli" ,title "Representations of Musical Signals" ,editor "G. De Poli, A. Piccialli, and C. Roads" ,publisher "MIT Press" ,address "Cambridge, Mass." ,year 1991 ) @inproceedings(DesainGraphics ,key "Desain" ,author "Desain, P." ,title "Graphical Programming in Computer Music, a Proposal" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ,pages = "161-166" ) @article(desain89 ,key "Desain" ,author "Desain, Peter and Henkjan Honing" ,title "Quantization of Musical Time: a connectionist approach" ,journal "Computer Music Journal" ,year 1989 ,pages="56-66" ,volume=13 ,number=3 ) @inproceedings(DesainTempo ,key "Desain" ,author "Desain, P. and H. Honing" ,title "Tempo Curves Considered Harmful" ,booktitle = "ICMC Montreal 1991 Proceedings" ,year = "1991" ,pages "143-149" ,editor "B. Alphonce and B. Pennycook" ,organization = "International Computer Music Association" ,address "San Francisco" ) @inbook(DesainTempoChapter ,key "Desain" ,author "Desain, P. and H. Honing" ,title "Tempo Curves Considered Harmful" ,year 1992 ,booktitle "Music, Mind, and Machine: Studies in Computer Music, Music Cognition, and Artificial Intelligence" ,pages 25-40 ,publisher "Thesis Publishers" ,address "Amsterdam" ) @techreport(DesainStructure ,key "Desain" ,author "Desain, P. and H. Honing" ,title "Towards a calculus for expressive timing in music" ,year = "1991" ,institution = "Center for Knowledge Technology" ,address = "Utrecht" ) @article(timefunctions ,key "Desain" ,author "Desain, P. and H. Honing" ,title "Time Functions Function Best as Functions of Multiple Times" ,Journal = "Computer Music Journal" ,Year = "1992" ,Month = "Summer" ,Number = "2" ,Pages = "17-34" ,Volume = "16") @book(ada ,key "DOD" ,title "The Programming Language Ada Reference Manual" ,author "American National Standards Institute, Inc." ,publisher "Springer-Verlag" ,volume 155 ,series "Lecture Notes in Computer Science" ,year 1983) @inproceedings(Donner ,key "Donner" ,author "Donner, Marc" ,title "The Design of OWL - A Language for Walking" ,organization "Sigplan" ,booktitle "Sigplan Symposium on Prog. Lang. Issues In Software Systems" ,year 1983 ) @inproceedings(gist ,key "Eckel" ,author "Eckel, G., M. R. Iturbide" ,title "The Development of GiST, a Granular Synthesis Toolkit Based on an Extension of the FOF Generator" ,booktitle "Proceedings of the 1995 International Computer Music Conference" ,publisher "International Computer Music Association" ,year 1995 ,pages "296-302" ) @manual(BarsAndPipes ,key "Fey" ,author "Fey, T. and M. J. Grey" ,title "Using Bars and Pipes" ,publisher "Blue Ribbon Bakery" ,address "Decatur, Georgia" ,year 1989 ) @book(Field, key = Field ,Author = "Field, A. J., and P. G. Harrison" ,Title = "Functional Programming" ,publisher = "Addison-Wesley" ,year 1988 ) @book(Foerster ,title = "Music By Computers" ,year = "1969" ,key = "Foerster" ,editors = "Foerster, H. V., and J. W. Beauchamp" ,publisher "John Wiley & Sons, Inc." ) @article(Foster, key = "Foster", ,Author = "Foster, Scott, Schloss, W. Andrew, and Rockmore, A. Joseph" ,Journal = "Computer Music Journal" ,Title = "Toward an Intelligent Editor of Digital Audio: Signal Processing Methods" ,Year = "1982" ,Month = "Spring" ,Number = "1" ,Pages = "42-51" ,Volume = "6") @inproceedings(htm ,key = "Freed" ,author = "Freed, A." ,title = "Codevelopment of User Interface, Control, and Digital Signal Processing with the HTM Environment" ,booktitle = "Proceedings of the International Conference on Signal Processing Applications and Technology" ,year 1994 ) @inproceedings(Gibbs ,key "Gibbs" ,author "Gibbs, S." ,title "Composite Multimedia and Active Objects" ,organization "ACM/SIGPLAN" ,booktitle "OOPSLA '91 Conference Proceedings" ,pages "97-112" ,year 1991 ,publisher "ACM Press" ,address "New York" ,editor "A. Paepcke" ) @article(Glass ,key "Glass" ,author "Glass, Robert L." ,title "Real-Time: The ``Lost World'' Of Software Debugging and Testing" ,journal "Communications of the ACM" ,volume 23 ,number 5 ,month "May" ,year 1980 ,pages "264-271" ) @book(Smalltalk ,key "Goldberg" ,author "Goldberg, A. and D. Robson" ,title "Smalltalk-80: the language and its implementation." ,publisher "Addison-Wesley" ,year 1983 ) @inproceedings(Greenberg ,key "Greenberg" ,author "Greenberg, Gary" ,title "Procedural Composition" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1987 International Computer Music Conference" ,editor "J. Beauchamp" ,year 1987 ,pages "25-32" ) @inproceedings(Greenberg88 ,key "Greenberg" ,author "Greenberg, Gary" ,title "Composing With Performer Objects" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,year 1988 ,pages "142-149" ) @phdthesis(Greytimbre ,key "Grey" ,author "Grey, J. M." ,year 1975 ,title "An Exploration of Musical Timbre" ,school "Department of Psychology, Stanford University" ,note "Department of Music Report STAN-M-2" ) @inproceedings(Gross ,key "Gross" ,author "Gross, Dorothy" ,Organization = "International Computer Music Association" ,year = "1984" ,title = "An Intelligent Ear-Training Lesson" ,booktitle = "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,pages "179-183" ) @InProceedings(sonar, key = "Haflich", Author = "Haflich, Steven M. and Burns, Mark A.", Organization = "International Computer Music Association", year = "1983", title = "Following a Conductor: The Engineering of an Input Device", booktitle = "1983 International Computer Music Conference Proceedings") @article(Hagerman80 ,key="Hagerman" ,author="Hagerman, B. and Sundberg, J." ,title="Fundamental Frequency Adjustment in Barbershop Singing" ,journal="Speech Transmission Laboratory Quarterly Progress and Status Report" ,year="1980" ,month="April" ,number="STL-QPSR 1/1980" ) @manual(hamel ,key Hamel ,author "Hamel, K." ,title "MusScribe Reference Manual" ,year 1988 ,organization "SoftCore Music Systems" ,address "Richmond, BC, Canada" ) @inproceedings(PATCHMIX ,key = "Helmuth" ,author = "Helmuth, M." ,title = "PATCHMIX: A C++ X Graphical Interface to Cmix" ,booktitle = "Proceedings of the 1990 International Computer Music Conference" ,pages = "273-275" ,publisher = "Computer Music Association" ,year 1990 ) @inproceedings (HILD92, key = "Hild", author = "Hild, Hermann and Feulner, Johannes and Menzel, Wolfgang", title = "HARMONET: A Neural Net for Harmonizing Chorales in the Style of J.S.Bach", booktitle = "Advances in Neural Network Information Processing Systems (NIPS-4-)", year = "1992", editor = "Moody, J.E. and Hanson, S.J. and Lippmann,R.P.", publisher = "Morgan Kaufmann" ) @book(Hiller59 ,key "Hiller" ,author "Hiller, L. and Isaacson, L." ,title "Experimental Music: Composition with an Electronic Computer" ,publisher "McGraw Hill" ,year 1959 ,address "New York, N. Y." ) @article(Hiller58 ,key "Hiller" ,author "Hiller, L. and Isaacson, L." ,title "Musical composition with a high-speed digital computer" ,journal "Journal of the Audio Engineering Society" ,volume 6 ,number 3 ,month July ,year 1958 ,pages 154-160 ) @book(Hindemith42 ,key="Hindemith" ,author="Hindemith, P." ,title="Craft of Musical Composition, Book 1, Theoretical Part" ,publisher="Schott" ,year="1942" ) @article(monitor ,key "Hoare" ,author "Hoare, C. A. R." ,title "Monitors: An Operating System Structuring Concept" ,journal "Communications of the ACM" ,volume 17 ,number 10 ,pages "549-557" ,month "October" ,year "1974" ,note "Erratum in @i(Communications of the ACM), 18(2) (Feb. 1975), p95" ) @article(csp ,key "Hoare" ,author "Hoare, C. A. R." ,title "Communicating Sequential Processes" ,journal "Communications of the ACM" ,volume 21 ,number 8 ,pages "666-677" ,month "August" ,year "1978" ) @book(hofstetter ,key "Hofstetter" ,author "Hofstetter, F. T." ,title "Computer Literacy for Musicians" ,publisher "Prentice Hall" ,address "Englewood Cliffs, NJ" ,year 1988 ) @article(CPR ,key "Hon" ,author "Hon, D." ,journal "Byte Magazine" ,volume 7 ,number 6 ,title "Interactive Training in Cardiopulmonary Resuscitation" ,month June ,year 1982 ) @inbook(honing90 ,key "Honing" ,author "Honing, H." ,title "Issues in the Representation of Time and Structure in Music" ,year 1992 ,booktitle "Music, Mind, and Machine: Studies in Computer Music, Music Cognition, and Artificial Intelligence" ,pages 25-40 ,publisher "Thesis Publishers" ,address "Amsterdam" ,note "Also in Proceedings of the 1990 Music and the Cognitive Sciences Conference, Harwood Academic Publishers GmbH, 1992" ) @book(horowitz ,key "Horowitz" ,author "Horowitz, E. and S. Sahni" ,title "Fundamentals of Data Structures in Pascal" ,publisher "Computer Science Press" ,year 1976 ) @book(MIDISPEC ,key = IMA ,author "IMA" ,title = "MIDI 1.0 Detailed Specification" ,publisher "International MIDI Association" ,address "Los Angeles, CA" ,year 1989 ) @book(APL ,key "Ivers" ,author "Iverson, K." ,title "A Programming Language" ,year 1962 ,address "New York" ,publisher "Wiley" ) @article(Jaffe , key "Jaffe" ,author "Jaffe, David" ,title "Ensemble Timing in Computer Music" ,journal "Computer Music Journal" ,pages "38-48" ,volume 9, number 4 ,year 1985 ) @article(SoundKit, key "Jaffe" ,author "Jaffe, D., and L. Boynton" ,title "An Overview of the Sound and Music Kit for the NeXT Computer" ,journal "Computer Music Journal" ,pages "48-55" ,volume 13, number 2 ,year 1989 ) @techreport(seqnet ,key "Jordan" ,author "Jordan, M. I." ,title "Serial Order: A Parallel Distributed Processing Approach" ,institution "Institute for Cognitive Science, UCSD" ,year 1986 ,number "8604" ) @techreport(Actors ,key "Kahn" ,author "Kahn, K." ,title "DIRECTOR Guide" ,institution "MIT" ,year 1979 ,month "December" ,number "MIT AI Laboratory Memo 482B" ) @inproceedings(Katayose89 ,key "Katayose" ,author "Katayose, H., H. Kato, M. Imai, and S. Inokuchi" ,title "An Approach to an Artificial Music Expert" ,booktitle = "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,year = "1989" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "139-146" ) @book(knuth ,key "Knuth" ,author "Knuth, D." ,title "The Art of Computer Programming" ,volume 1 ,publisher "Addison Wesley" ,year 1975 ) @article(ntp ,key "Kolstad" ,author "Kolstad, R." ,title "The Network Time Protocol" ,journal "UNIX Review" ,volume 8 ,pages "58-61" ,month "December" ,year 1990 ) @article(cmjlisp ,key "Kornfeld" ,author "Kornfeld, W." ,title "Machine Tongues VII: LISP" ,journal "Computer Music Journal" ,pages "6-12" ,volume 4 ,number 2 ,year 1980 ,month "Summer" ) @book(Kernighan ,key = "Kernighan" ,author = "Kernighan, Brian M. and Richie, Dennis M." ,title = "The C Programming Language" ,publisher "Prentice-Hall" ,address "Englewood Cliffs" ,year = 1978 ) @manual(krakowsky86 ,key "krakowsky" ,author "Krakowsky, Philippe, ed." ,title "Object LOGO Reference Manual" ,address "Cambridge Massachusetts" ,year 1986 ,organization "Coral Software" ) @article(krumhanslReview ,key "Krumhansl" ,author "Krumhansl, C. L." ,title "Music Psychology: Tonal Structures in Perception and Memory" ,journal "Annual Review of Psychology" ,year 1991 ,publisher "Annual Reviews Inc." ,pages "277-303" ) @book(Cmix ,key "Lansky" ,author "Lansky, P." ,title "CMIX" ,year 1987 ,publisher "Princeton Univ." ) @article(lansky ,key "Lansky" ,author "Lansky, P. and K. Steiglitz" ,title "The synthesis of timbral families by warped linear prediction" ,journal "Computer Music Journal" ,volume 5 ,number 3 ,pages "45-49" ,month "Fall" ,year 1981 ) @article(Levitt84 ,key "Levitt" ,author "Levitt, D." ,title "Machine Tongues X: Constraint Languages" ,journal "Computer Music Journal" ,pages "9-21" ,month Spring ,year 1984 ,volume 8 ,number 1 ) @article(little ,key "Little" ,author "Little, T. D. C. and A. Ghafoor" ,title "Spatio-Temporal Composition of Distributed Multimedia Objects for Value-Added Networks" ,journal "Computer" ,pages "42-50" ,month "October" ,year 1991 ) @article(dvi ,key "Ripley" ,author "Ripley, G. D." ,title "DVI - A Digital Multimedia Technology" ,journal "CACM" ,number 7 ,volume 32 ,month "July" ,year "1989" ,pages "811-822" ) @inbook(LewisInterview ,key "Roads" ,author "Roads, Curtis" ,title "Improvisation With George Lewis" ,booktitle "Composers and the Computer" ,editor "Roads, Curtis" ,publisher "William Kaufmann" ,address "Los Altos, CA" ,chapter "5" ,year 1985 ,pages "74-87" ,series "The Computer Music and Digital Audio Series" ) @inproceedings(Lifton85 ,key "Lifton" ,author "Lifton, J." ,title "Some Technical and Aesthetic Considerations in Software for Live Interactive Performance" ,organization "International Computer Music Association" ,booktitle "Proceedings of the International Computer Music Conference 1985" ,editor "B. Truax" ,year 1985 ,pages "303-306" ) @inproceedings(Lischka ,key "Lischka" ,author "Lischka, C." ,title "Connectionist Models of Musical Thinking" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1987 International Computer Music Conference" ,editor "J. Beauchamp" ,year 1987 ,pages "190-196" ) @book(lincoln ,title = "The Computer and Music" ,year = "1970" ,editor = "Lincoln, H. B." ,key = "Lincoln" ,publisher = "Cornell University Press" ,address = "Ithaca, N.Y." ) @article(IMWArchitecture ,key "Lindemann" ,author "Lindemann, E., F. Dechelle, B. Smith, and M. Starkier" ,title "The Architecture of the IRCAM Musical Workstation" ,journal "Computer Music Journal" ,volume "15" ,number "3" ,month "Fall" ,year "1991" ,pages "41-49" ) @inproceedings(logemann89 ,key "Logemann" ,year 1989 ,title "Experiments With a Gestural Controller" ,author "G. Logemann" ,booktitle "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,pages "184-185" ,year 1989 ,organization "International Computer Music Association" ) @article(longuet ,key "Longuet-Higgins" ,year 1982 ,title "The Perception of Musical Rhythms" ,author "Longuet-Higgins, H. C. and C. S. Lee" ,journal "Perception" ,volume 11 ,pages "115-128" ) @article(LH76, author"Longuet-Higgins, H. C.", title="Perception of Melodies", journal="Nature", pages="646-653", volume=263, year=1976) @article(LH78, author="Longuet-Higgins, H. C.", title="The Perception of Music", journal="Interdisciplinary Science Reviews", pages="148-156", volume=3, number=2, year=1978 ) @article(MIDI ,key = "Loy" ,author = "Loy, G." ,title = "Musicians Make a Standard: The MIDI Phenomenon" ,journal = "Computer Music Journal" ,volume = "9" ,number = "4" ,month = "Winter" ,year = "1985" ,pages = "8-26" ) @inproceedings(hyperinstruments ,key "Machover" ,author "Machover, T. and Chung, J." ,title "Hyperinstruments: Musically Intelligent and Interactive Performance and Creativity Systems" ,booktitle "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,pages "186-190" ,year 1989 ,organization "International Computer Music Association" ) @inproceedings(martens ,key "Martens" ,author "Martens, W. L." ,title "PALETTE: An Environment for developing an individualized set of psychophysically scaled timbres" ,booktitle "Proceedings of the 1985 International Computer Music Conference" ,editor "B. Truax" ,pages "355-365" ,year 1985 ,organization "International Computer Music Association" ) @inproceedings(sampling ,key "Massie" ,author "Massie, D. C." ,title "The Emulator II Computer Music Environment" ,booktitle "Proceedings of the 1985 International Computer Music Conference" ,editor "B. Truax" ,pages "111-118" ,year 1985 ,organization "International Computer Music Association" ) @Article(Mathews63 ,key = "Mathews" ,author = "Mathews, M. V." ,title = "The Digital Computer as a Musical Instrument" ,journal = "Science" ,volume = "142" ,pages = "553-557" ,year = "1963" ) @book(Music5 ,key "Mathews" ,author "Mathews, M. V." ,title "The Technology of Computer Music" ,publisher "MIT Press" ,year 1969 ,address "Boston" ) @article(groove ,key "Mathews" ,author "Mathews, M. V. and F. Richard Moore" ,title "A Program to Compose, Store, and Edit Functions of Time" ,journal "Communications of the ACM" ,year 1970 ,month December ,volume 13 ,number 12 ,pages "715-721" ) @article(seqdrum, key = "Mathews", Author = "Mathews, M. V. and C. Abbot", Journal = "Computer Music Journal", Title = "The Sequential Drum", Year = "1980", Month = "Winter", Number = "4", Pages = "45-59", Volume = "4") @book(MP ,key "Mathews" ,title "Current Directions in Computer Music Research" ,series "System Development Foundation Benchmark Series" ,editor "Mathews, M. V. and Pierce, J. R." ,year 1989 ,publisher "MIT Press" ) @article(mockingbird ,key "Maxwell" ,author "Maxwell, J. T., and S. M. Ornstein" ,title "Mockingbird: A Composer's Amanuensis" ,journal "Byte" ,volume 9 ,number 1 ,year 1984 ,pages "384-401" ) @article(OCCAM ,key "May" ,author "May, David" ,title "OCCAM" ,journal "Sigplan Notices" ,volume 18 ,number 4 ,month "April" ,year 1983 ,pages "69-79" ) @manual(MidiManager ,key "Apple" ,author "Apple Computer, Inc." ,title "MIDI Management Tools, Version 2.0" ,organization "Apple Programmers and Developers Association" ,year 1990 ) @book(McCarthy ,key "McCarthy" ,author "McCarthy, J." ,title "LISP 1.5 Programmer's Manual" ,publisher "M.I.T. Press" ,address "Cambridge, Mass" ,year "1965" ) @mastersthesis(Mecca ,key "Mecca" ,author "Michael T. Mecca" ,title "Tempo Following Behavior in Musical Accompaniment" ,School "Department of Logic and Philosophy, Carnegie Mellon University" ,Year 1993 ,address "Pittsburgh" ) @book(moorebook ,key = "Moore" ,author = "Moore, F. R." ,title = "Elements of Computer Music" ,year = "1990" ,publisher = "Prentice Hall" ,address = "New Jersey" ) @article(moorer ,key "Moorer" ,author "Moorer, J. A." ,title "Signal Processing Aspects of Computer Music - A Survey" ,journal "Proceedings of the IEEE" ,volume 65 ,number 8 ,pages "1108-1137" ,year 1977 ,month "July" ,note "A revised and updated version is included in @i(Digital Audio Signal Processing: An Anthology), ed. by John Strawn, William Kaufmann, Inc., 1985." ) @article(Val ,key "McGraw" ,author "McGraw, James R." ,title "The VAL Language: Description and Analysis" ,journal "ACM Transactions on Programming Languages and Systems" ,volume 4 ,number 1 ,month "January" ,year 1982 ,pages "44-82" ) @article(Cmusic, key = "Moore", Author = "Moore, F. R.", Journal = "Computer Music Journal", Title = "The Computer Audio Research Laboratory at UCSD", Year = "1982", Number = "6", Pages = "18-29", Volume = "1") @book(Cmusic90, key = "Moore", Author = "Moore, F. R.", Title = "Elements of Computer Music", Publisher = "Prentice-Hall", Year = "1990") @PhDThesis(Moorer75 ,key = "Moorer" ,Author = "Moorer, J. A." ,Year = 1975 ,School = "Stanford University Department of Computer Science" ,Title = "On the Segmentation and Analysis of Continuous Musical Sounds by Digital Computer" ) @article(Andrew ,key = "Morris" ,author = "Morris, James H., et. al." ,title = "Andrew: A Distributed Personal Computing Environment" ,journal = "Communications of the ACM" ,volume = "29" ,number = "3" ,month = "March" ,year = "1986" ,pages = "184-201" ) @Article(GarnetComputer Key="Myers", Author="Brad A. Myers, et al.", Title="Garnet: Comprehensive Support for Graphical, Highly Interactive User Interfaces", Journal="IEEE Computer", Volume=23, number=11, Month=Nov, year=1990, pages="71-85") @article(NelsonMPL ,key Nelson ,author "Nelson, G." ,title "MPL: A Program Library for Musical Data Processing" ,journal "Creative Computing" ,pages "76-81" ,year "1977" ,month "Mar.-Apr." ) @article(Hytime ,key "Newcomb" ,author "Newcomb, S. R., N. A. Kipp, and V. T. Newcomb" ,title "The HYTIME Multimedia/time-based document structuring language" ,journal "Communications of the ACM" ,volume 34 ,month "November" ,year 1991 ,pages "67-83" ) @article(SMDL-Computer ,key "Newcomb" ,author "Newcomb, S. R." ,title "Standard Music Description Language Complies With Hypermedia Standard" ,journal "Computer" ,volume 24 ,number 7 ,month "July" ,year 1991 ,pages "76-80" ) @manual(framekit ,key = "Nyberg" ,author = "Nyberg, Eric H." ,title = "The FRAMEKIT User's Guide Version 2.0" ,organization = "Computer Science Department, Carnegie Mellon University" ,year = 1988) @inproceedings(oppenheimNotation ,key "Oppenheim" ,title "The P-G-G Environment For Music Composition: A Proposal" ,author "Oppenheim, D. V." ,booktitle "Proceedings of the 1987 International Computer Music Conference" ,editor "J. Beauchamp" ,pages 40-48 ,year 1987 ,organization "International Computer Music Association" ,address "San Francisco" ) @inproceedings(MLOGO ,key "Orlarey" ,author "Orlarey, Y." ,title "MLOGO: A MIDI Composing Environment" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ,pages = "211-213" ) @inproceedings(midishare ,key "Orlarey" ,author "Orlarey, Y., H. Lequay" ,title "MidiShare, A Real Time Multi-tasks Software Module for Midi Applications" ,booktitle "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,pages "234-237" ,year 1989 ,organization "International Computer Music Association" ) @inproceedings(ATK ,key "Palay" ,author "Palay, A. J., F. Hansen, M. Kazar, M. Sherman, M. Wadlow, T. Neuendorffer, Z. Stern, M. Bader, T. Peters" ,title "The Andrew Toolkit - An Overview" ,booktitle "Proceedings USENIX Technical Conference" ,month "Winter" ,year 1988 ,pages "9-21" ,organization "USENIX" ) @article(palmer ,key "Palmer" ,author "Palmer, C." ,title "Mapping Musical Thought to Musical Performance" ,journal "Journal of Experimental Psychology" ,volume 15 ,number 12 ,month "Dec" ,year 1989 ) @inproceedings(fminverse ,key "Payne" ,author "Payne, R. G." ,title "A Microcomputer Based Analysis/Resynthesis Scheme for Processing Sampled Sounds Using FM" ,organization "Computer Music Association" ,booktitle "Proceedings of the 1987 International Computer Music Conference" ,year 1987 ,pages "282-289" ) @book(Papoulis ,key "Papoulis" ,author "Papoulis, Athanasios" ,title "The Fourier Integral And Its Applications" ,year 1962 ,publisher "McGraw-Hill" ,address "New York" ) @article(HMSL ,key "Polansky" ,author "Polansky, L., P. Burk, and D. Rosenboom" ,title "HMSL (Hierarchical Music Specification Language): A Theoretical Overview" ,journal "Perspectives of New Music" ,year 1990 ,volume 28 ,number 2 ,month summer ,pages "136-179" ) @book(OOPBook ,key "Pope" ,author "Pope, S. T., editor" ,title "The Well-Tempered Object: Musical Applications of Object-Oriented Software Technology" ,address "Boston" ,publisher "MIT Press" ,year "1991" ) @inbook(Mode ,author "Pope, S. T." ,key "Pope" ,title "Introduction to MODE: The Musical Object Development Environment" ,booktitle "The Well-Tempered Object: Musical Applications of Object-Oriented Software Technology" ,editor "S. T. Pope" ,address "Boston" ,publisher "MIT Press" ,pages "83-106" ,year "1991" ) @article(cmj-software-synthesis ,author "Pope, S. T." ,key "Pope" ,title "Machine Tongues XV: Three Packages for Software Sound Synthesis" ,journal "Computer Music Journal" ,Volume 17 ,Number 2 ,Month "Summer" ,Year "1993" ,Pages "23-54" ) @book(Pratt ,author "Pratt, Terrence W." ,key "Pratt" ,title "Programming Languages: Design and Implementation" ,year 1975 ,publisher "Prentice-Hall" ,address "Englewood Cliffs, N. J." ) @inproceedings(MAXandX ,key "Puckette" ,author "Puckette, M." ,title "Interprocess Communication and Timing in Real-time Computer Music Performance" ,pages "43-46" ,booktitle = "Proceedings of the International Computer Music Conference 1986" ,editor "P. Berg" ,year = "1986" ,organization = "International Computer Music Association" ) @inproceedings(Patcher ,key "Puckette" ,author "Puckette, M." ,title "The Patcher" ,booktitle "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,year 1988 ,pages "420-429" ,organization "International Computer Music Association" ) @inproceedings(Explode ,key "Puckette" ,author "Puckette, M." ,title "EXPLODE: a user interface for sequencing and score following" ,booktitle "ICMC Glasgow 1990 Proceedings" ,year = "1990" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "259-261" ,editor "S. Arnold and G. Hair" ) @manual(MaxManual ,key = "Puckette" ,author = "Puckette, M. and D. Zicarelli" ,title = "MAX Development Package" ,organization = "Opcode Systems, Inc." ,year = 1991) @article(maxcmj ,key "Puckette" ,author "Puckette, M." ,title "Combining Event and Signal Processing in the MAX Graphical Programming Environment" , ,journal "Computer Music Journal" ,year 1991 ,pages="68-77" ,volume=15 ,number=3 ,month "Fall" ) @book(polson ,key "Pohlmann" ,author "Pohlmann, K. C." ,title "The Compact Disc: a handbook of theory and use" ,publisher "A-R Editions" ,address "Madison, WI" ,year 1992 ) @article(fts-cmj ,key "Puckette" ,author "M. Puckette" ,title "FTS: A Real-Time Monitor for Multiprocessor Music Synthesis" ,journal "Computer Music Journal" ,year 1991 ,volume 15 ,number 3 ,month "Fall" ,pages "58-67" ) @inproceedings(fts ,key "Viara" ,author "Viara, E., and M. Puckette" ,title "A Real-Time Operating System for Computer Music" ,year 1990 ,booktitle "Proceedings of the 1990 International Computer Music Conference" ,pages "270-272" ,organization "International Computer Music Association" ) @inproceedings(reynaud85a ,key "Reynaud" ,title "Problem-solving Strategies in a Music Transcription System" ,author "Mont-Reynaud, Bernard" ,year 1985 ,booktitle "IJCAI Proceedings" ) @inproceedings(reynaud85b, ,key "Reynaud" ,title "On Finding Rhythmic Patterns in Musical Lines" ,author "Mont-Reynaud, Bernard and Mark Goldstein" ,organization "International Computer Music Association" ,booktitle "Proceedings of the International Computer Music Conference 1985" ,editor "B. Truax" ,year 1985 ,pages "391-397" ) @techreport(reynaud84 ,key "Chowning" ,author "Chowning, J., B. Mont-Reynaud, et. al." ,title "An Intelligent System for the Analysis of Digitized Acoustic Signals" ,institution "Stanford University" ,year 1984 ,number "STAN-M-15" ) @inproceedings(Rogers ,key "Rogers" ,author "Rogers, J., J. Rockstroh, and P. Batstone" ,title "Music-Time and Clock-Time Similarities Under Tempo Changes" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1980 International Computer Music Conference" ,year 1980 ,pages "404-442" ) @book(MIDIbook ,key "Rothstein" ,author "Rothstein, J." ,title "MIDI: A Comprehensive Introduction" ,publisher "A-R Editions" ,address "Madison, WI" ,year 1992 ) @book(Rowe ,key "Rowe" ,author "Rowe, R." ,title "Interactive Music Systems" ,publisher "MIT Press" ,year 1993 ) @inbook(ptvideo ,key "Sanchez" ,author "Sanchez, M., A. Joseph, R. B. Dannenberg, P. Capell, R. Saul, and R. Joseph" ,title "The Piano Tutor" ,series "ACM Siggraph Video Review" ,year "1990" ,publisher "ACM Siggraph" ,address "c/o 1st Priority, Box 576, Itasca, IL 60143-0576" ,booktitle " CHI '90 Technical Video Program - New Techniques" ,volume "55" ,note "(Video)" ) @book(sankoff ,key "Sankoff" ,author "Sankoff, David and Joseph B. Kruskal, editors" ,title "Time Warps, String Edits, and Macromolecules: The Theory and Practice of Sequence Comparison." ,publisher "Addison-Wesley" ,address "Reading, Mass." ,year 1983 ) @article(KymaCMJ ,key "Scaletti" ,title "The Kyma/Platypus Computer Music Workstation" ,author "Scaletti, C." ,journal "Computer Music Journal" ,volume 13 ,number 2 ,month "Summer" ,year 1989 ,pages "23-38" ) @inproceedings(KymaOOPSLA ,key "Scaletti" ,title "An Interactive Graphic Environment for Object-Oriented Music Composition and Sound Synthesis" ,author "Scaletti, C., and E. Johnson" ,booktitle "Proceedings of the 1988 Conference on Object-Oriented Languages and Systems" ,year 1988 ,pages "18-26" ,organization "ACM" ) @inbook(Kyma ,key "Scaletti" ,author "Scaletti, C., and K. Hebel" ,title "An Object-based Representation for Digital Audio Signals" ,booktitle "Representations of Musical Signals" ,editor "G. De Poli, A. Piccialli, and C. Roads" ,publisher "MIT Press" ,address "Cambridge, Mass." ,year 1991 ,pages "371-389" ,chapter 11 ) @inproceedings(scaletti92 ,key "Scaletti" ,author "Scaletti, C." ,title "Polymorphic transformations in Kyma" ,booktitle = "Proceedings of the 1992 ICMC" ,year = "1992" ,organization = "International Computer Music Association" ,address "San Francisco" ,pages "249-252" ) @phdthesis(Schloss ,key "Schloss" ,author "Schloss, A." ,title "On the Automatic Transcription of Percussive Music" ,school "Department of Speech and Hearing, Stanford University" ,year 1985 ,note "Department of Music Technical Report STAN-M-27" ,month June ) @techreport(sisTR ,key "Serra" ,author "Serra, M., D. Rubine, R. B. Dannenberg" ,title "A Comprehensive Study of the Analysis and Synthesis of Tones by Spectral Interpolation" ,institution "Carnegie Mellon" ,number "CMU-CS-88-146" ,year 1988 ,month June ) @inproceedings(sisicmc ,key "Serra" ,author "Serra, M., D. Rubine, R. B. Dannenberg" ,title "The Analysis and Resynthesis of Tones via Spectral Interpolation" ,booktitle "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,organization "International Computer Music Association" ,year 1988 ,pages "322-332" ) @article(sisJAES ,key Serra ,author "Serra, M., D. Rubine, R. B. Dannenberg" ,title "Analysis and Synthesis of Tones by Spectral Interpolation" ,journal "Journal of the Audio Engineering Society" ,year 1990 ,volume 38 ,number 3 ,month March ,year 1990 ,pages 111-128 ) @article(shepardspiral ,key "Shepard" ,author "Shepard, R. N." ,title "Geometrical approximations to the structure of musical pitch" ,journal "Psychological Review" ,volume 89 ,number 4 ,year 1982 ,pages "305-333" ) @inbook(simon ,key "Simon" ,author "Simon, H. A. and Sumner, R. K." ,title "Pattern in Music" ,booktitle "Formal Representation of Human Judgment" ,editor "B. Kleinmuntz" ,address "New York" ,publisher "Wiley" ,year 1968 ) @article(Auditeur ,key "Simon" ,author "Simon, H. A." ,title "Perception du Pattern Musical par AUDITEUR" ,Journal "Sciences de l'Art" ,volume 2 ,pages "28-34" ,year 1968 ) @book(slawson ,key "Slawson" ,author "Slawson, A. W." ,title "Sound Color" ,publisher "University of California Press" ,address "Berkeley" ,year 1985 ) @book(Sleeman-brown ,key = "Sleeman" ,author = "Sleeman, D. and J. S. Brown (eds.)" ,title = "Intelligent Tutoring Systems" ,address = "New York" ,publisher = "Academic Press" ,year = 1982 ) @inproceedings(smdl ,key "Sloan" ,author "D. Sloan" ,title "Precis of the Standard Music Description Language" ,organization "Computer Music Association" ,booktitle "Proceedings of the 1989 International Computer Music Conference" ,year 1989 ,pages "296-302" ) @inproceedings(arctic-runtime ,key Dannenberg ,author "Dannenberg, R. B." ,title "A Run-time System for Arctic" ,booktitle "ICMC Glasgow 1990 Proceedings" ,organization "International Computer Music Association" ,year 1990 ,pages "185-187" ) @inproceedings(cmt-mexico ,key Dannenberg ,author "Dannenberg, R. B." ,title "Recent Developments in the CMU MIDI Toolkit" ,booktitle "Proceedings of the International Seminar Ano 2000: Theoretical, Technological and Compositional Alternatives" ,organization "Universidad Nacional Autonoma de Mexico" ,address "Mexico City" ,editor "C. Sandoval" ,year 1990 ,pages "52-62" ) @inproceedings(optimizingdsp ,key "Thompson" ,author "Thompson, N. and R. B. Dannenberg" ,title "Optimizing Software Synthesis Performance" ,booktitle "Proceedings of the 1995 International Computer Music Conference" ,publisher "International Computer Music Association" ,year 1995 ,pages "235-6" ) @inproceedings(W ,key Dannenberg ,author "Dannenberg, R. B. and D. Rubine" ,title = "Toward Modular, Portable, Real-Time Software" ,booktitle = "Proceedings of the 1995 International Computer Music Conference" ,publisher "International Computer Music Association" ,year 1995 ,pages "65-72" ) @inproceedings(SampleRate ,key Smith ,author "Smith, Julius O. and Phil Gossett" ,title "A Flexible Sampling-Rate Conversion Method" ,booktitle "Proceedings of ICASSP, Vol. 2" ,pages "19.4.1-19.4.4" ,year 1984 ) @inproceedings(Parshl ,key "Smith" ,author "Smith, Julius O. and Xavier Serra" ,title "PARSHL: An Analysis/Synthesis Program for Non-Harmonic Sounds Based on a Sinusoidal Representation" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1987 International Computer Music Conference" ,editor "J. Beauchamp" ,year 1987 ,pages "290-297" ) @inproceedings(Spiegel ,key "Spiegel" ,author "Spiegel, L." ,title "Manipulations of Musical Patterns" ,organization "IEEE Computer Society" ,booktitle "Proceedings of the Symposium on Small Computers in the Arts" ,year "1981" ,pages "19-22" ) @inproceedings(Taube ,key "Taube" ,author "Taube, H." ,title "Common Music: A Compositional Language in Common Lisp and CLOS" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,year 1989 ,pages "316-319" ) @inproceedings(Vivace ,key "Thomas" ,author "Thomas, M. T." ,title "Vivace: a rule based AI system for composition" ,organization "International Computer Music Association" ,booktitle "Proceedings of the International Computer Music Conference 1985" ,editor "B. Truax" ,year 1985 ,pages "267-274" ) @misc(Voice, ,author "Thomas, Marilyn T. and Peter Monta" ,key "Thomas" ,title "MacVoice 1.0 User's Manual" ,year "1986" ,publisher "Kinko's Academic Courseware Exchange" ,address "4141 State Street, Santa Barbara, CA 93110, (800) 235-6919" ,note "published by Kinko's Academic Courseware Exchange" ) @inproceedings(cantabile ,key "Thomas" ,author "Thomas, M. T., S. Chatterjee, Mark W. M." ,title "Cantabile: A Rule-Based System For Composing Melody" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1989 International Computer Music Conference" ,editor "T. Wells and D. Butler" ,year 1989 ,pages "320-323" ) @inproceedings(Animation ,key "Reynolds" ,author "Reynolds, C. U." ,title "Computer Animation with Scripts and Actors" ,organization "ACM" ,booktitle "Proceedings of ACM SIGGRAPH Conference" ,year 1982 ,month "July" ) @article(CMJAda ,key "Roads" ,author "Roads, C." ,title "Machine Tongues VI: Ada" ,journal "Compter Music Journal" ,volume 3 ,number 4 ,month "Winter" ,year 1980 ,pages "6-8" ) @inproceedings(Formes83 ,key "Rodet" ,author "Rodet, Xavier, Pierre Cointe, Jean-Baptiste Barriere, Yves Potard, B. Serpette, and J. J. Briot" ,title "Applications and Developments of the FORMES programming environment" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 1983 International Computer Music Conference" ,year 1983 ) @article(Chant ,key "Rodet" ,author "Rodet, X., Y. Potard and Jean-Baptist Barriere" ,journal "Computer Music Journal" ,title "The CHANT Project: From Synthesis of the Singing Voice to Synthesis in General" ,year 1984 ,volume 8 ,number 3 ,month "Fall" ,pages "15-31" ) @article(Formes84 ,key "Rodet" ,author "Rodet, X. and P. Cointe" ,journal "Computer Music Journal" ,title "FORMES: Composition and Scheduling of Processes" ,year 1984 ,volume 8 ,number 3 ,month "Fall" ,pages "32-50" ) @inproceedings(mercury ,key "Rodet" ,author "Rodet, Xavier and Gerhard Eckel" ,year 1988 ,title "Dynamic Patches: Implementation and Control in the Sun-Mercury Workstation" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 14th International Computer Music Conference" ,editor "C. Lischka and J. Fritsch" ,pages "82-89" ) @phdthesis(rubenstein ,key "Rubenstein" ,author "Rubenstein, W. B." ,year 1987 ,Title "Data Management of Musical Information" ,school "U. C. Berkeley" ,note "Memorandom No. UCB/ERL M87/69" ,month June ) @techreport(arcticref ,key "Rubine" ,title "Arctic Programmer's Manual and Tutorial" ,author "Rubine, D. and R. B. Dannenberg" ,institution "Carnegie Mellon" ,number "CMU-CS-87-110" ,year 1987 ) @inproceedings(videoharp ,key "Rubine" ,title "The VideoHarp" ,author "Rubine, D. and P. McAvinney" ,organization "International Computer Music Association" ,booktitle "Proceedings of the 14th International Computer Music Conference" ,year 1988 ,pages "49-55" ) @article(videoharpcmj ,key "Rubine" ,title "Programmable Finger-tracking Instrument Controllers" ,author "Rubine, Dean and Paul McAvinney" ,journal "Computer Music Journal" ,year 1990 ,month Spring ,number 1 ,volume 14 ,pages "26-41" ) @phdthesis(rubinethesis ,key "Rubine" ,author "Rubine, D." ,title "The Automatic Recognition of Gestures" ,school "Carnegie Mellon University" ,year 1991 ) @incollection(rubine91c ,key "Rubine" ,author "Rubine, D." ,title "Criteria for Gesture Recognition Technologies" ,booktitle "Neural Networks and Pattern Recognition in Human Computer Interaction" ,publisher "Ellis Horwood" ,address "Chichester, UK" ,year "(to appear)" ,editor "R. Beale and J. Finlay" ) @inproceedings(rubine91b ,key "Rubine" ,author "Rubine, D." ,title "Integrating Gesture Recognition and Direct Manipulation" ,booktitle "Proceedings of the Summer 1991 Usenix Conference" ,editor "C. Carr" ,address "Berkeley, CA" ,organization "USENIX Association" ,year 1991 ) @article(rubine91a ,key "Rubine" ,author "Rubine, D." ,title "Specifying Gestures by Example" ,journal "Computer Graphics" ,volume 25 ,number 4 ,month July ,year 1991 ,note "(Proceedings of SIGGRAPH '91)" ,organization "ACM SIGGRAPH" ,address "New York" ,pages "329-37" ) @inCollection(Salamon ,key "Salamon" ,author "Salamon, F. P., Jr." ,title "Real-Time Electronic Engine Control (EEC) Microprocessor Software Productivity" ,booktitle "New Developments in Electronic Engine Management" ,publisher "Society of Automotive Engineers" ,address "400 Commonwealth Drive, Warrendale, PA 15096" ,year 1984 ,volume "SP-572" ,pages "45-55" ) @article(PianoTutor ,author "Sanchez, Marta and Annabelle Joseph" ,key "Sanchez" ,journal "Accent on Research" ,title "Piano Tutor" ,year 1986 ,month "Fall" ,pages "7" ,note "published by Carnegie Mellon University" ) @article(scarborough89 ,key "Scarborough" ,author "Scarborough, D., B. O. Miller, and J. A. Jones" ,title "Connectionist Models for Tonal Analysis" ,journal "Computer Music Journal" ,volume 13 ,number 3 ,month "Fall" ,year 1989 ,pages "49-55" ) @article(marksweep ,key "Schorr" ,author "Schorr, H. and W. Waite" ,year 1967 ,title "An Efficient and Machine Independent Procedure for Garbage Collection in Various List Structures" ,journal "Communications of the ACM" ,volume 10 ,number 8 ,pages 501-506 ) @article(PLA ,key "Schottstaedt" ,author "Schottstaedt, Bill" ,title "Pla: A Composer's Idea of a Language" ,journal "Computer Music Journal" ,volume 7 ,number 1 ,month "Spring" ,year 1983 ,pages "11-20" ) @article(Roads ,key "Roads" ,author "Roads, C." ,title "Artificial Intelligence and Music" ,journal "Computer Music Journal" ,volume 4 ,number 2 ,year 1980 ,month "Summer" ,pages "13-25" ) @techreport(nettalk ,key = "Sejnowski" ,Author = "Sejnowski, T. J. and C. R. Rosenberg" ,Journal = "Complex Systems" ,Title = "NETtalk: AParallel Network that Learns to Read Aloud" ,Institution "Johns Hopkins University" ,number "JHU/EECS-86/01" ,Year = "1986" ) @Article(snell, key = "Snell", Author = "Snell, John", Journal = "Computer Music Journal", Title = "The Lucasfilm Real-Time Console for Recording Studios and Performance of Computer Music", Year = "1982", Month = "Fall", Number = "3", Pages = "33-45", Volume = "6") @book(steele ,key "Steele" ,author "Steele, Guy L., Jr." ,title "Common Lisp" ,publisher "Digital Press" ,year "1984") @article(stevens ,key "Stevens" ,author "Stevens, S. M." ,title "Intelligent Interactive Video Simulation of a Code Inspection" ,journal "Communications of the ACM" ,volume 32 ,number 7 ,year 1989 ,month "July" ,pages "832-43" ) @misc(stone, key = "Stone", Title = "diffreg.c", HowPublished = "Source code for the 4.1BSD Berkeley Unix@+(TM) @i(diff) program.") @book(schrader ,key = "Schrader" ,author = "Schrader, B." ,title = "Introduction to Electro-Acoustic Music" ,year = "1982" ,publisher = "Prentice Hall" ,address = "New Jersey" ) @article(Sundberg82 ,key="Sundberg" ,author="Sundberg, J." ,title="In tune or not? A study of fundamental frequency in music practise" ,journal="Speech Transmission Laboratory Quarterly Progress and Status Report" ,year="1982" ,month="April" ,number="STL-QPSR 1/1982" ) @article(Sundberg83 ,key "Sundberg" ,author "Sundberg, J., A. Askenfelt, L. Fryden" ,title "Musical Performance: A Synthesis-by-Rule Approach" ,journal "Computer Music Journal" ,pages "37-43" ,year 1983 ,month "Spring" ,volume 7 ,number 1 ) @inproceedings(Teitelbaum ,key = "Teitelbaum" ,author = "Teitelbaum, R." ,title = "The Digital Piano and the Patch Control Language System" ,pages = "213-216" ,booktitle = "Proceedings of the International Computer Music Conference 1984" ,editor = "W. Buxton" ,year = "1985" ,organization = "International Computer Music Association" ) @article(Terhardt ,key="Terhardt" ,author="Terhardt, E." ,title="Pitch, consonance, and harmony" ,journal="Journal of the Acoustical Society of America" ,year="1974" ,number="55" ,page="1061-69" ) @article(Toddcmj ,key "Todd" ,author "Todd, P. M." ,title "A Connectionist Approach to Algorithmic Composition" ,journal "Computer Music Journal" ,volume 13 ,number 4 ,month "Winter" ,year 1989 ,pages "27-43" ) @InCollection(Koenig ,key "Koenig" ,author "Koenig, G. M." ,title "Project 1" ,BookTitle "Electronic Music Reports" ,publisher "Institute of Sonology, Utrecht University" ,month "July" ,year "1970" ,pages "32-44" ) @article(ISP ,key "Kopec" ,author "Kopec, Gary E." ,title "The Integrated Signal Processing System ISP" ,journal "IEEE Transactions on Acoustics, Speech and Signal Processing" ,month "August" ,volume "ASSP-32" ,number 4 ,year 1984 ,month "August" ,pages "842-850" ) @article(SRL, ,key "Kopec" ,author "Kopec, Gary E." ,title "The Signal Representation Language SRL" ,journal "IEEE Transactions on Acoustics, Speech and Signal Processing" ,volume "ASSP-33" ,number 4 ,month "August" ,year "1985" ,pages "921-932" ) @article(Ternstrom82 ,key="Ternstrom" ,author="Ternstrom, S. and J. Sundberg" ,title="Acoustical factors related to pitch precision in choir singing" ,journal="Speech Transmission Laboratory Quarterly Progress and Status Report" ,year="1982" ,month="October" ,number="STL-QPSR 2-3/1982" ) @book(Todd ,key "Todd" ,author "Todd, P. M. and D. G. Loy" ,title "Music and Connectionism" ,publisher "MIT Press" ,address "Boston" ,year 1991 ) @book(Touretzky ,key "Touretzky" ,author "Touretzky, David S." ,title "LISP: a gentle introduction to symbolic computation" ,address "New York" ,publisher "Harper & Row" ,year 1984 ) @article(vanska ,author "Vanska, L., R. J. Rosenberg and V. Pitkanen" ,key "Vanska" ,journal "Nuclear Instruments and Methods" ,title "An Automatic Gamma Spectrometer For Activation Analysis" ,year 1983 ,volume 213 ,pages "343-347" ) @unpublished(spomin ,author "Velikonja, P." ,title "Spomin" ,note "unpublished score." ,year 1990 ) @manual(Music11 ,key "vercoe" ,author "Vercoe, Barry" ,title "Reference Manual for the MUSIC 11 Sound Synthesis Language" ,year 1981 ,organization "MIT Experimental Music Studio" ) @inproceedings(Vercoe84 ,key "Vercoe" ,author "Vercoe, B." ,fullauthor "Barry Vercoe" ,title "The Synthetic Performer in the Context of Live Performance" ,organization "Computer Music Association" ,booktitle "Proceedings of the 1984 International Computer Music Conference" ,pages "199-200" ,year 1984 ) @inproceedings(Vercoe85 ,key "Vercoe" ,author "Vercoe, B. and M. Puckette" ,title "Synthetic Rehearsal: Training the Synthetic Performer" ,organization "International Computer Music Association" ,booktitle "Proceedings of the International Computer Music Conference 1985" ,editor "B. Truax" ,year 1985 ,pages "275-278" ) @manual(Csound ,key "vercoe" ,author "Vercoe, B." ,title "Csound: A Manual for the Audio Processing System and Supporting Programs" ,year 1986 ,organization "MIT Media Lab" ) @inproceedings(RTCsound ,key "Vercoe" ,author "Vercoe, B. and D. Ellis" ,title "Real-Time CSOUND: Software Synthesis with Sensing and Control" ,organization "International Computer Music Association" ,booktitle "ICMC Glasgow 1990 Proceedings" ,editor "S. Arnold and G. Hair" ,year 1990 ,pages "209-211" ) @TechReport(Waibel81a, key = "Waibel", Author = "Waibel, A., N. Krishnan, R. Reddy", Title = "Minimizing Computational Cost for Dynamic Programming Algorithms", Institution = "Carnegie-Mellon University Department of Computer Science", year = "1981", Month = "June", Number = "CMU-CS-81-124") @TechReport(Waibel81b, key = "Waibel", Author = "Waibel, A. and B. Yegnanarayana", Title = "Comparative Study of Nonlinear Time Warping Techniques in Isolated Word Speech Recognition Systems", Institution = "Carnegie-Mellon University Department of Computer Science", year = "1981", Month = "June", Number = "CMU-CS-81-125") @techreport(ward ,author = "Ward, Stephen A." ,institution = "MIT" ,key = "ward" ,title = "An Approach to Real Time Computation" ,year = "1978" ) @inproceedings(waters ,key "Waters" ,author "Waters, S. and T. Ungvary" ,title "The Sonogram: A Tool for Visual Documentation of Musical Structure" ,organization "International Computer Music Association" ,booktitle "ICMC Glasgow 1990 Proceedings" ,editor "S. Arnold and G. Hair" ,year 1990 ,pages "159-162" ) @techreport(Wawrzynek ,key = "Wawrzynek" ,author = "Wawrzynek, John and Tzu-Mu Lin" ,institution = "California Institute of Technology" ,title = "A Bit Serial Architecture for Multiplication and Interpolation" ,year = "1983" ,month = "January" ,number = "5067:DF:83" ) @article(Quicktime ,key "Wayner" ,author "Wayner, P." ,title "Inside QUICKTIME" ,journal "Byte" ,volume 16 ,year 1991 ,month December ,pages 189 ) @book(wenger ,Key = "Wenger" ,Author = "Wenger, E." ,Title = "Artificial Intelligence and Tutoring Systems" ,Publisher = "Morgan Kaufmann Publishers, Inc." ,Year = 1987 ) @inbook(wesseltimbre ,key "Wessel" ,author "Wessel, D. L." ,title "Timbre Space as a Musical Control Structure" ,booktitle "Foundations of Computer Music" ,editor "C. Roads and J. Strawn" ,pages "640-657" ,year 1985 ,publisher "MIT Press" ,address "Cambridge, MA" ,note "Originally published in @i(Computer Music Journal) 3(2):45-52, 1979" ) @article(ModulaDesign ,key "Wirth" ,author "Wirth, N." ,title "Design and implementation of Modula" ,journal "Software, Practice and Experience" ,volume 7 ,number 1 ,year 1977 ,pages "67-84" ) @article(MPC ,key "Yager" ,author "Yager, T." ,title "The Multimedia PC: High-powered Sight and Sound on Your Desk" ,journal "Byte" ,volume 17 ,year 1992 ,month Feb ,pages 217 ) @book(Xenakis ,key "Xenakis" ,author "Xenakis, I." ,title "Formalized Music" ,publisher "Indiana University Press" ,address "Bloomington" ,year 1971 ) @misc(Xmedia ,key = "DEC" ,Title = "XMedia Tools, Version 1.1A" ,Author = "Digital Equipment Corporation" ,HowPublished = "Software Product Description SPD 36.55.02" ,year 1992 ) @inproceedings(CEDS ,key "Zahler" ,author "Zahler, N." ,title "CEDS TO GROW A CAT: A Progress/Studio Report" ,organization "International Computer Music Association" ,booktitle "ICMC Montreal 1991 Proceedings" ,editor "B. Alphonce and B. Pennycook" ,year 1991 ,pages "455-458" ) nyquist-3.05/docsrc/convert/0002755000175000000620000000000011537433126015127 5ustar stevestaffnyquist-3.05/docsrc/convert/init.lsp0000644000175000000620000000030311510141774016600 0ustar stevestaff; init.lsp -- default Nyquist startup file (load "nyinit.lsp" :verbose nil) ; add your customizations here: ; e.g. (setf *default-sf-dir* "...") ;(load "convert.lsp") (load "convert2.lsp") nyquist-3.05/docsrc/convert/convert2.lsp0000644000175000000620000003050711510141774017410 0ustar stevestaff;; convert2.lsp -- insert XLISP syntax definitions to Nyquist manual AND SAL syntax ;; definitions into xlisp.mss (defun assert (co) (if co t (error "assertion error"))) (defun alpha-char-p (c) (let ((cc (char-code c))) (or (and (>= cc (char-code #\a)) (<= cc (char-code #\z))) (and (>= cc (char-code #\A)) (<= cc (char-code #\Z)))))) (defun get-begin-end-token (begin-end) (open-paren) (let ((env-name (get-token)) (close-tok (get-token))) (cond ((paren-match close-tok) (pop paren-stack) (return (strcat begin-end "(" env-name ")"))) (t (display "get-begin-end-token failed" begin-end env-name close-tok))))) (defun get-token () (prog ((token (read-char *inf*)) (next-char (peek-char nil *inf*))) (if (not token) (return token)) (if (and token (not (alpha-char-p token)) (not (eql token #\@))) (return (string token))) (setf token (string token)) (while (and next-char (alpha-char-p next-char)) (setf token (strcat token (string (read-char *inf*)))) (setf next-char (peek-char nil *inf*))) (if (or (string= token "@begin") (string= token "@end")) (return (get-begin-end-token token)) (return token)))) (defun convert (infile outfile) (setf *next-tokens* nil) (setf paren-stack nil) (let ((inf (open infile)) (outf (open outfile :direction :output))) (process inf outf) (close inf) (close outf))) ;; note: "<" has been omitted here to allow parsing of "<" as an operator ;; in XLISP documentation. "<" is not commonly used as scribe bracket, but ;; that could cause problems in some cases because this is not a full ;; scribe parser. (defun is-open-paren (tok) (member tok '("(" "{" "[") :test 'equal)) (defun open-paren () (let ((tok (get-token))) (cond ((is-open-paren tok) (push tok paren-stack)) (t (display "open-paren got a surprise" tok))))) ; (push tok *next-tokens*) ; ;; if no open paren, then fake open and close ; (push #\( paren-stack) ; (push #\) *next-tokens*))))) (defun close-paren-p (tok) (paren-match tok)) (defun paren-match (p2) (let ((p1 (car paren-stack))) (or (and (equal p2 ")") (equal p1 "(")) (and (equal p2 "]") (equal p1 "[")) (and (equal p2 "}") (equal p1 "{")) (and (equal p2 ">") (equal p1 "<"))))) (defun starts-with-symbol-char (tok) (let ((c (char tok 0))) (or (alpha-char-p c) (digit-char-p c) (eql c #\-) (eql c #\+) (eql c #\*) (eql c #\=) (eql c #\/) (eql c #\>) (eql c #\<)))) (defun get-fn-name () (setf *token-list* (cdr *token-list*)) (let ((fn-name "")) (while (and *token-list* (or (starts-with-symbol-char (car *token-list*)) (equal (car *token-list*) "@i") ; allow c@i(xx)r (equal (car *token-list*) "(") (equal (car *token-list*) ")"))) (setf fn-name (strcat fn-name (car *token-list*))) (setf *token-list* (cdr *token-list*))) fn-name)) (defun get-symbol() (let ((s "")) (while (and *token-list* (starts-with-symbol-char (car *token-list*))) (setf s (strcat s (car *token-list*))) (setf *token-list* (cdr *token-list*))) s)) ;; GET-ARG - *token-list* starts with open bracket (after @i). Get the ;; tokens between this and the close bracket. (defun get-arg () (let (arg) (push (car *token-list*) paren-stack) (setf *token-list* (cdr *token-list*)) ;; go to parameter name (while paren-stack (if (close-paren-p (car *token-list*)) (pop paren-stack)) (push (car *token-list*) arg) (setf *token-list* (cdr *token-list*))) ;; take cdr to drop the close bracket (reverse (cdr arg)))) (defun get-args () (prog (args arg) loop (cond ((and *token-list* (cdr *token-list*) (cddr *token-list*) (equal (car *token-list*) "@i")) (setf *token-list* (cdr *token-list*)) (push (get-arg) args)) ((and (equal (car *token-list*) ".") (equal (cadr *token-list*) ".") (equal (caddr *token-list*) ".")) (setf *token-list* (cdddr *token-list*)) (push '("...") args)) ((and *token-list* (cddr *token-list*) (equal (car *token-list*) "&") (equal (cadr *token-list*) "key") (equal (caddr *token-list*) " ")) (push '("&key ") args) (setf *token-list* (cdddr *token-list*))) ((and *token-list* (cdr *token-list*) (equal (car *token-list*) ":")) (setf arg '(":")) (setf *token-list* (cdr *token-list*)) ; skip ":" (push (get-symbol) arg) ;; keyword (setf arg (reverse arg)) (push arg args)) (*token-list* (push (list :meta (car *token-list*)) args) (setf *token-list* (cdr *token-list*))) ((null *token-list*) (return (reverse args)))) (go loop))) (defun write-list-of-args (args) (let (need-space) (dolist (arg args) (cond ((equal arg '("...")) (setf need-space t) (format *outf* "@r(...)")) ((and (consp arg) (equal (car arg) :meta)) (setf need-space nil) (format *outf* (cadr arg))) ((and (consp arg) (or (equal (car arg) ":") (equal (car arg) "&key "))) (setf need-space nil) (format *outf* "@t(") (write-list-of-tokens arg) (format *outf* ")")) (t ;; insert space between consecutive args (if need-space (format *outf* "@t( )")) (setf need-space t) (format *outf* "@t(@i(") (write-list-of-tokens arg) (format *outf* "))")))))) (defun write-sal-args (args) (let (need-comma) (dolist (arg args) (cond ((equal arg '("...")) (format *outf* "@r(...)")) ((and (consp arg) (equal (car arg) :meta) (or (equal (cadr arg) "[") (equal (cadr arg) "]"))) (format *outf* (cadr arg))) ((and (consp arg) (equal (car arg) :meta)) nil) ;; o.w. ignore meta ((and (consp arg) (equal (car arg) "&key "))) ((and (consp arg) (equal (car arg) ":")) ;; must be a keyword parm ;; assumes this is not the first parameter (format *outf* ", ~A: @i(~A)" (cadr arg) (cadr arg))) (t (format *outf* "~A@i(" (if need-comma ", " "")) (setf need-comma t) (write-list-of-tokens arg) (format *outf* ")")))))) (defun write-list-of-tokens (toks) (dolist (tok toks) (format *outf* "~A" tok))) ;; this is a variable if there are no args and if there is no ;; back-to-back open/close paren pair as in foo(). (defun is-variable-check (args) (prog () loop (cond ((null (cdr args)) (return t)) ((and (equal (car args) '(:meta "(")) (equal (cadr args) '(:meta ")"))) (return nil)) ((= (length (car args)) 1) (return nil))) (setf args (cdr args)) (go loop))) (defun get-balanced-token-list (tok) (let (token-list) (push tok paren-stack) (push tok token-list) (while (and tok paren-stack) (setf tok (get-token)) (if (is-open-paren tok) (push tok paren-stack) (if (close-paren-p tok) (pop paren-stack))) (push tok token-list)) (setf token-list (reverse token-list)))) (defun process-codef () (let (fn-name args save-tokens) (setf *token-list* (get-balanced-token-list (get-token))) ;; now we have a list of tokens including brackets (display "process-codef" *token-list*) (setf save-tokens *token-list*) (setf fn-name (get-fn-name)) (setf args (get-args)) (setf is-var (is-variable-check args)) (display "parse" fn-name args is-var) (cond (is-var (format *outf* "@codef") (write-list-of-tokens save-tokens)) (t (format *outf* "@codef") (write-list-of-tokens *token-list*) (format *outf* " @c{[sal]}@*\n@altdef{@code[(~A" fn-name) (write-list-of-args args) (format *outf* "] @c{[lisp]}}"))))) (defun exclude-from-sal (name) (or (equal name "*") (equal name "/") (equal name "+") (equal name "-") (equal name "cond") (equal name "case") (equal name "let") (equal name "let*") (equal name "prog") (equal name "prog*") (equal name "flet") (equal name "labels") (equal name "macrolet") (equal name "defun") (equal name "defmacro") (equal name "do") (equal name "do*") (equal name "dolist") (equal name "dotimes") (equal name "return") (equal name "loop") (equal name "progv") (equal name "clean-up") (equal name "top-level") (equal name "continue") (equal name "errset") (equal name "baktrace") (equal name "evalhook") (equal name "1+") (equal name "1-") (equal name "<") (equal name "<=") (equal name ">") (equal name ">=") (equal name "=") (equal name "/=") (equal name "print") (equal name "load"))) (defun process-fdescription () (let (function-name args save-tokens (tok (get-token)) has-sal) (format *outf* "@begin(fdescription)") (while (and tok (not (equal tok "@end(fdescription)"))) (cond ((equal tok "(") (setf *token-list* (get-balanced-token-list tok)) (assert (equal (first *token-list*) "(")) (setf function-name (get-fn-name)) (setf save-tokens *token-list*) (setf args (get-args)) (display "process-fdescription" save-tokens args) (setf has-sal (not (exclude-from-sal function-name))) (cond (has-sal (format *outf* "@begin(fgroup)@xlcode{~A(" function-name) (write-sal-args args) (format *outf* ")} @c{[sal]}\n\n "))) (format *outf* "@xlcode{(~A" function-name) ;(setf save-tokens (reverse save-tokens)) ;(cond ((equal (car save-tokens) ")") ; (setf save-tokens (cons "@xlcode{)}" (cdr save-tokens)))) ; (t ; (display "MISSING CLOSE PAREN" save-tokens))) ;(setf save-tokens (reverse save-tokens)) ;(write-list-of-tokens save-tokens) (write-list-of-args args) (format *outf* "} @c{[lisp]}") (setf tok (get-token)) (format *outf* tok) (display "process-fdescription" function-name args) (while (not (equal tok "\n")) (setf tok (get-token)) (format *outf* tok)) (cond (has-sal (format *outf* "@end(fgroup)\n") (setf has-sal nil))) (setf tok (get-token))) ((equal tok "@begin(pdescription)") (format *outf* tok) (scan-to "@end(pdescription)") (setf tok (get-token))) ((equal (char tok 0) #\@) (format *outf* tok) (cond ((equal (setf tok (get-token)) "(") (write-list-of-tokens (get-balanced-token-list tok)) (setf tok (get-token))))) (t (format *outf* tok) (setf tok (get-token))))) (if tok (format *outf* tok)))) (defun scan-to (stop-tok) (prog (tok) loop (setf tok (get-token)) (format *outf* "~A" tok) ;; handle nested pdescriptions (if (equal tok "@begin(pdescription)") (scan-to "@end(pdescription)")) (if (equal tok stop-tok) (return)) (go loop))) (defun process (inf outf) (setf *inf* inf) (setf *outf* outf) (prog (tok) loop (setf tok (get-token)) (cond ((null tok) (return 'done)) ((string= tok "@codef") (process-codef)) ((string= tok "@begin(fdescription)") (process-fdescription)) (t (format *outf* "~A" tok))) (go loop))) (defun l () (load "convert2.lsp")) ;(convert "xltest.mss" "xltest.out.mss") (convert "../../xlisp/xlisp-no-sal.mss" "xlisp-out.mss") nyquist-3.05/docsrc/convert/convert.lsp0000644000175000000620000001137711510141774017332 0ustar stevestaff;; convert.lsp -- insert XLISP syntax definitions (defun alpha-char-p (c) (let ((cc (char-code c))) (or (and (>= cc (char-code #\a)) (<= cc (char-code #\z))) (and (>= cc (char-code #\A)) (<= cc (char-code #\Z)))))) (defun get-token () (prog ((token (read-char *inf*)) (next-char (peek-char nil *inf*))) (if (not token) (return token)) (if (and token (not (alpha-char-p token)) (not (eql token #\@))) (return (string token))) (setf token (string token)) (while (and next-char (alpha-char-p next-char)) (setf token (strcat token (string (read-char *inf*)))) (setf next-char (peek-char nil *inf*))) (return token))) (defun convert (infile outfile) (setf *next-tokens* nil) (setf paren-stack nil) (let ((inf (open infile)) (outf (open outfile :direction :output))) (process inf outf) (close inf) (close outf))) (defun is-open-paren (tok) (member tok '("(" "{" "[" "<") :test 'equal)) (defun open-paren () (let ((tok (get-token))) (cond ((is-open-paren tok) (push tok paren-stack)) (t (display "open-paren got a surprise" tok))))) ; (push tok *next-tokens*) ; ;; if no open paren, then fake open and close ; (push #\( paren-stack) ; (push #\) *next-tokens*))))) (defun close-paren-p (tok) (paren-match tok)) (defun paren-match (p2) (let ((p1 (car paren-stack))) (or (and (equal p2 ")") (equal p1 "(")) (and (equal p2 "]") (equal p1 "[")) (and (equal p2 "}") (equal p1 "{")) (and (equal p2 ">") (equal p1 "<"))))) (defun starts-with-symbol-char (tok) (let ((c (char tok 0))) (or (alpha-char-p c) (digit-char-p c) (eql c #\-) (eql c #\*)))) (defun get-fn-name (token-list) (setf token-list (cdr token-list)) (let ((fn-name "")) (while (and token-list (starts-with-symbol-char (car token-list))) (setf fn-name (strcat fn-name (car token-list))) (setf token-list (cdr token-list))) fn-name)) (defun get-args (token-list) (prog (arg args) loop (setf token-list (cdr token-list)) (cond ((and token-list (cdr token-list) (cddr token-list) (equal (car token-list) "@i")) (push (cadr token-list) paren-stack) (setf token-list (cddr token-list)) ;; go to parameter name (while paren-stack (if (close-paren-p (car token-list)) (pop paren-stack) (push (car token-list) arg)) (setf token-list (cdr token-list))) (push (reverse arg) args) (setf arg nil)) ((null token-list) (return (reverse args)))) (go loop))) (defun write-list-of-args (args) (dolist (arg args) (format *outf* " @i(") (write-list-of-tokens arg) (format *outf* ")"))) (defun write-list-of-tokens (toks) (dolist (tok toks) (format *outf* "~A" tok))) ;; this is a variable if there are no args and if there is no ;; back-to-back open/close paren pair as in foo(). (defun is-variable-check (tokens) (prog () loop (cond ((null (cdr tokens)) (return t)) ((and (equal (car tokens) "(") (equal (cadr tokens) ")")) (return nil))) (setf tokens (cdr tokens)) (go loop))) (defun process-codef () (let ((tok (get-token)) token-list fn-name args) (push tok paren-stack) (push tok token-list) (while (and tok paren-stack) (setf tok (get-token)) (if (is-open-paren tok) (push tok paren-stack) (if (close-paren-p tok) (pop paren-stack))) (push tok token-list)) (setf token-list (reverse token-list)) ;; now we have a list of tokens including brackets (display "process-codef" token-list) (setf fn-name (get-fn-name token-list)) (setf args (get-args token-list)) (setf is-var (and (null args) (is-variable-check token-list))) (display "parse" fn-name args) (cond (is-var (format *outf* "@codef") (write-list-of-tokens token-list)) (t (format *outf* "@codef") (write-list-of-tokens token-list) (format *outf* " @c{[sal]}@*\n@altdef{@code[~A~A" (if is-var "" "(") fn-name) (write-list-of-args args) (format *outf* "~A] @c{[lisp]}}" (if is-var "" ")")))))) (defun process (inf outf) (setf *inf* inf) (setf *outf* outf) (prog (tok) loop (setf tok (get-token)) (cond ((null tok) (return 'done)) ((string= tok "@codef") (process-codef)) (t (format *outf* "~A" tok))) (go loop))) (defun l () (load "convert.lsp")) (convert "nyquistman.mss" "nyquistman-out.mss") ;(convert "short.txt" "short-out.txt") nyquist-3.05/docsrc/scribe.htm0000644000175000000620000017760011512512746015440 0ustar stevestaff Scribe

    Scribe


    • @@ - insert an '@' sign
    • @+ - superscript
    • @− - subscript
    • @~ - unknown meaning
    • @\ - horizontal tabulator
    • @* - force a line break
    • @appendix - start appendix chapter
    • @b - bold text
    • @begin - start a region
    • @blankspace - insert witepace with specific width
    • @c - small capitals
    • @caption - add text to an object
    • @chapter - start an numbered chapter
    • @center - centered text
    • @cite - cite an entry from the bibliograpy
    • @code - inline code example, use typewriter font
    • @codef - inline code example, use typewriter font
    • @commandstring - define printing commands [for CMU use only]
    • @comment - a comment, invisible in the final document
    • @dash - insert a horizontal dash with specific width
    • @define - define a command or a variable
    • @device - the printer device [for CMU use only]
    • @display - non-justified text
    • @end - end of a region
    • @fillcaption - add formatted text to an object
    • @foot - add a footnote
    • @graphic - insert a picture
    • @html - insert text in HTML only
    • @htmltitle - insert a HTML header with title (HTML only)
    • @i - italics
    • @include - read a different Scribe file
    • @index - index reference
    • @itemsep - insert a horizontal dash with specific width
    • @label - add a label to a section
    • @libraryfile - load Scribe library [for CMU use only]
    • @majorheading - document title
    • @make - printer output format [for CMU use only]
    • @math - render and insert a math formula
    • @mult - insert a multiplication sign
    • @modify - change internal Scribe settings [for CMU use only]
    • @newpage - force a page break
    • @p - bold italics
    • @pageheading - format of the page heading
    • @pageref - insert the page number of a @label
    • @paragraph - start a new paragraph
    • @parm - unknown meaning
    • @part - faciliates separate compilation of parts of a larger document
    • @pragma - control the 's2h.lsp' HTML converter
    • @ref - insert the section number of a @label
    • @section - start a section
    • @set - set a Scribe variable [for CMU use only]
    • @style - change a Scribe document preset [for CMU use only]
    • @subsection - start a sub-section
    • @subtract - insert a horizontal dash with specific width
    • @t - use typewriter font
    • @tabclear - reset tabulator settings
    • @tabset - define new tabulator settings
    • @tag - add a label to a figure or table
    • @textform - define a text-formatting Scribe command
    • @title - define the page heading title
    • @unnumbered - start an unnumbered chapter
    • @use - use a external database file
    • @value - insert the value of a command or a variable

    Table of Contents


    1. Scribe - basic Syntax rules
    2. General Settings - start of 'myquistman.mss'
    3. Command Definitions - Nyquist Scribe commands
    4. Inline Markup
    5. Regions
    6. Lists
    7. Comments
    8. Footnotes
    9. Indexing
    10. Headings
    11. Title Page
    12. Tab Stops and Whitespace
    13. Line and Page Breaks
    14. Cross References
    15. Bibliography and Citation
    16. Figures and Tables

    Scribe


    Scribe is a markup language and word processing system. It was designed and developed by Brian Reid of Carnegie Mellon University around 1980.

    A source file prepared for input to Scribe consists primarily of plain text. Paragraphs are separated by blank lines, and commands, if present, are flagged with '@' signs. If you want an '@' sign to appear within your output, you must type two of them '@@'. A file containing no commands at all will work just fine, it will yield simple justified paragraphed text. A Scribe source file should be given the extension '.mss'. Upper and lower case may be used interchangeably in any Scribe command.

    A perhaps confusing aspect of Scribe is that you get to use any bracket as long as you close it with a matching one, so for example:

    @i(This is italic.)
    @i[This is also italic]
    @i{This italic has (parentheses) but it's ok because there is no curly brace}
    @begin(i)This form is allows [any] (brackets) {in} the text, but "at" (@@) must be escaped@end(i)
    

    Legal delimiter pairs are:

       (...)  ,  [...]  ,  <...>  ,  "..."

    It doesn't really matter which delimiter is used as long as the closing delimiter matches the opening limiter.

      Back to top


    General Settings


    Most of the definitions in this section affect the Scribe system at the CMU only.

    @device(mac52postscript)          @comment(printer device)
    @make(manual)                     @comment(printer output format)
    @libraryfile(mathematics10)
    @libraryfile(picture)
    @libraryfile(multilevelindex)
    @style(font timesroman)           @comment(printer font)
    @style(fontscale 11)              @comment(printer font size)
    @commandstring(dash @Y[M])
    @commandstring(subtract @Y[N])
    @commandstring(itemsep @Y[M])
    @Modify(indexenv, above=2 lines, leftmargin 8, columns=3, boxed)
    @define(prg=i)
    

    The '@commandstring' lines define three formatting directices:

       @dash  ,  @subtract  ,  @itemsep   -  a minus sign in HTML, but different widths in PDF

    [A block with Command Definitions follows here in the original file, moved to a separate paragraph below.]

    @use(bibliography = "../bib/music.bib")
    @style(references ClosedAlphabetic)
    @counter(dummy-counter)
    @modify(FigureCounter,Within=dummy-counter,
            Numbered <@@b[Figure@@ @1:@@ @@ ]@@$>,
            Referenced "@1",Init 0)
    @modify(TableCounter,Within=dummy-counter,
            Numbered <@@b[Table@@ @1:@@ @@ ]@@$>,
            Referenced "@1",Init 0)
    @pageheading(left "", center "@value(page)", right "")
    @include(../template/filcap.mss)
    

    Scribe commands for producing large documents:

       @part(text)   -  faciliates separate compilation of parts of a larger document.
       @use(text)   -  tells Scribe to use a particular database file, used to include the bibliography file
       @include(text)   -  read another Scribe file

    The @style Command

    The database entry for a document type presets the value of all Scribe parameters. The '@style' command can be used to override these values. All '@style' commands used in a document must come at the beginning. Styles can't be changed in the middle of a document. Here is a list of '@style' commands used in the Nymqust manual:

    @style(font timesroman)
    @style(fontscale 11)
    @style(references ClosedAlphabetic)
    @style(pagenumbers="@i")
    @style(pagenumbers="@1")
    

    Numbering Pages and Page Headings

    The page heading and footing areas are divided into three parts. A 'left' part, a 'center' part, and a 'right' part:

    @pageheading(left "", center "@value(page)", right "")
    @pageheading(even, left "Page @Value(Page)", right "@c(Nyquist Manual)")
    @pageheading(odd, left "@c[@title(chapter)]", right "Page @Value(page)")
    

    The text fields inside the quotes can contain anything, including Scribe commands.

      Back to top


    Command Definitions


    The definitions in this section are used in the Scribe sources.

    @define(detail=text, size 9, spacing 1.2, indent 0)
    @define(code, FaceCode T, size 11)
    @define(codef, FaceCode T, size 11)
    @define(smallcode, FaceCode T, size 8, spacing 0.8) @comment(was 10)
    @define(rbdisplay = display, group)
    @define(fndefs = description, leftmargin 0.5in, indent -0.5in)
    @define(fdescription = text, leftmargin +0.5in, indent -0.5in, spread 1)
    @define(pdescription = text, leftmargin +0.5in, indent -0.5in, spread 0)
    @define(fgroup = text, indent -0.5in, spread 0)
    
    • detail defines text with a small font
    • code and codef define text with a typewriter font
    • smallcode defines text with typewriter font, with a small font in PDF
    • 'rbdisplay' seems nowhere else to be used in the Nyquist manual
    • fndefs and fgroup define special PDF formatting parameters for function definitions
    • fdesription and pdescription define a special definition list format

    '@codef' is used to define a lisp function or variable. A processor uses this to extract completion hint info for jNyqIDE.

    HTML Commands

    Three Scribe commands are added for the 's2h.lsp' HTML converter::

    @textform(html = [])
    @textform(htmltitle = [])
    @textform(pragma = [])
    

    The first two commands insert text in the HTML file only, but not in the PDF:

       @html(text)   -  insert HTML text
       @htmltitle(text)   -  insert a HTML header with title

    The '@pragma' command controls the 's2h.lsp' HTML converter:

       @pragma(defn)   -  the next @index marks a term's definition in the manual
       @pragma(startscribe)   -  ignore scribe file starting here
       @pragma(endscribe)   -  stop ignoring scribe file
       @pragma(startref)   -  use text between here and an @ref or @pageref as link text
       @pragma(doinclude)   -  process the next include file (default is to ignore)
       @pragma(endcodef)   -  end a code definition (used for completion list)

    RBD: '@pragma(defn)' is used to mark a term's point of definition. I tried to define(defn=index), but that didn't work in Scribe, so the approach now is to mark definitions. In s2h, the 'defn' pragma sets a flag that the NEXT index term is a definition. The 's2h.lsp' processor uses this to map terms defined within 'codef' (which go into the completion list) to URLs for the help system.

      Back to top


    Inline Markup


       Scribe  HTML 
       @b(text)  →  <b>text</b>   -  bold
       @i(text)  →  <i>text</i>   -  italics
       @p(text)  →  <b><i>text</i></b>   -  bold + italics
       @t(text)  →  <tt>text</tt>   -  typewriter font
       @c(text)  →  <small>text</small>   -  small capitals
       @+(text)  →  <sup>text</sup>   -  superscript
       @(text)  →  <sub>text</sub>   -  subscript
     
    User-defined Scribe commands:
      
       @code(text)  →  <code>text</code>   -  code example inside text
       @codef(text)  →  <code>text</code>   -  code example inside text
     
    Named entities:
     
       @mult  →  *   -  insert a multiplication sign

      Back to top


    Regions


    Text-formatting Scribe commands can be written as inline command or as a region command, delimited by '@begin' and '@end':

       @command(text)   -  inline command
     
       @begin(command)
    text
    @end(command)
      -  region command

    The most often used Scribe region commands in the Nyquist manual are:

       Scribe  HTML 
       @begin(programexample)
    text
    @end(programexample)
     →  <pre>
    text
    </pre>
      -  code example, typewriter font
     
       @begin(example)
    text
    @end(example)
     →  <pre>
    text
    </pre>
      -  code example, typewriter font
     
       @begin(display)
    text
    @end(display)
     →  <blockquote>
    text
    </blockquote>
      -  normal text, non-justified, each line separate
     
       @display(text)   -  same as above
     
    Scribe: The 'example' and 'display' inserts types are very similar, they differ only in the type face that will be used. In either 'example' or 'display' inserts, each line of the manuscript will produce one line in the document. Since 'example' is for showing examples of computer type-in and type-out, it will appear in a typeface that is designed to look like computer output. 'display' inserts will appear in the normal body typeface. If the document is printed on a device that cannot change fonts, then 'example' and 'display' will look nearly identical.
     
       @begin(center)
    text
    @end(center)
     →  <center>
    text
    </center>
      -  each line centered
     
       @center(text)   -  same as above
     
    Scribe: The 'center' insert is similar to 'display', except that it centers its lines rather than left-justifying them. Like 'display', 'center' produces one line in the document for each line of the manuscript file that is inside the 'center'. If there is more than one line in a 'center' insert, each line will be centered individually.
     
       @begin(detail)
    text
    @end(detail)
     →  <small>
    text
    </small>
      -  use small font
     
       @begin(code)
    text
    @end(code)
     →  <code>
    text
    </code>
      -  typewriter font
     
       @begin(smallcode)
    text
    @end(smallcode)
     →  <code>
    text
    </code>
      -  typewriter font, use small font in PDF

      Back to top


    Lists


       Scribe  HTML 
       @begin(itemize)
    item-1

    item-2

    item-3
    @end(itemize)
     →  <ul>
    <li>item-1
    <li>item-2
    <li>item-3
    </ul>
      -  unordered list
     
       @begin(enumerate)
    item-1

    item-2

    item-3
    @end(enumerate)
     →  <ol>
    <li>item-1
    <li>item-2
    <li>item-3
    </ol>
      -  ordered list
     
    Scribe: 'itemize' and 'enumerate' each expect a sequence of paragraphs, separated by blank lines, and each justifies those paragraphs into inset margins and puts a mark in front of each. 'itemize' puts a tick-mark or a bullet in front of each paragraph, while 'enumerate' puts a number in front of each.
     
       @begin(description)
    item-1@\text-1

    item-2@\text-2

    item-3@\text-3
    @end(description)
     →  <dl>
    <dt>item-1<dd>text-1
    <dt>item-2<dd>text-2
    <dt>item-3<dd>text-3
    </dl>
      -  definition list
     
    Scribe: A 'description' insert is designed for the 'command description' style that is very common in reference manuals. The first line of a 'description' insert will be at the left margin, and the second and remaining lines will be indented substantially, so that the word or phrase at the end of the head of the description stands out. If three or more blanks in a row are found in the first line of a 'description', they will be taken as a signal to tab to the left margin provided that the left margin has not been passed.
      
       @begin(fdescription)
    item
    @begin(pdescription)
    text-1

    text-2

    text-3
    @end(pdescription)
    @end(fdescription)
     →  <dl>
    <dt>
    item
    <dd>
    text-1<br>
    text-2<br>
    text-3<br>
    </dl>
      -  definition list

      Back to top


    Comments


    Comments produce no text in the final document and can be written as inline or as region command:

       @comment(text)   -  inline comment
     
       @begin(comment)
    text
    @end(comment)
      -  region comment

      Nach oben


    Footnotes


       @foot(text)   -  footnote

      Back to top


    Indexing


       @index(text)  →  <a name="indexXX">   -  nothing will appear in the printed text, but the 'text' will appear in the index together with the current page number.

      Back to top


    Headings


       Scribe  HTML 
       @majorheading(text)  →  <h1>text</h1>   -  document title
     
       @unnumbered(text)  →  <h2>text</h2>   -  unnumbered chapter (e.g. preface)
       @chapter(text)  →  <h2>text</h2>   -  numbered chapter
       @appendix(text)  →  <h2>text</h2>   -  appendix
     
    Scribe: Notice that 'unnumbered', 'chapter', and 'appendix' cause Scribe to start at the top of a new page.
     
       @section(text)  →  <h3>text</h3>   -  section
       @subsection(text)  →  <h4>text</h4>   -  subsection
       @paragraph(text)  →  <h5>text</h5>   -  paragraph

      Back to top


    Title Page


       @begin(titlepage)
    text
    @end(titlepage)
      -  this will cause the title page to be a page by itself, and text within the titlepage will be centered.
     
    Scribe: The title page for a technical report usually has the title, author, and date of publication visible within a box that will be reproduced on the cover of the report. The 'titlebox' command can be used to put text in this box:
     
       @begin(titlebox)
    text
    @end(titlebox)
      -  this will produce a titlebox.

      Back to top


    Tab Stops and Whitespace


       @tabclear   -  clear all tabs
       @tabset(number unit)   -  set tab width to 'number' of units, 'unit' should be 'inch' or 'inches'
       @\   -  go to the right until the next tab. If there is no tab stop to the right of the cursor position, then the cursor will be moved to the right margin.

    @tabset(.5 inches)
    @tabset(0.8 in, 3 in, 3.8 in)
    @tabset(1.5 inch)
    @tabset(0.8 inches)
    @tabset(0.5 inch)
    

       @blankspace(number)   -  forces a 'number' units of whitespace
       @blankspace(number unit)   -  forces a 'number' units of whitespace, 'unit' should be 'inch' or 'inches'

    @blankspace(0.3 inches)
    @blankspace(0.5 inch)
    @blankspace(0.3 inch)
    @blankspace(1 inch)
    @blankspace(5 inches)
    @blankspace(1)
    

      Back to top


    Line and Page Breaks


       @*   -  force a line break
       @newpage   -  force a page break

      Back to top


    Cross References


       @label(word)   -  define a label (text reference to a section or page number)
       @ref(word)   -  insert the section number of the label
       @pageref(word)   -  insert the page number of the label
       @tag(word)   -  define a tag (object reference to a figure or a table)

    Scribe: The difference between a 'label' and a tag is a bit subtle. A section document has many different sequences of numbers that identify the pieces of it. Pages are numbered sequentially, chapters and sections are usually numbered independently of the pages. Figures and tables are often numbered within a chapter, ignoring section numbers. If you want to attach a codeword to the section number of the section that contains a particular figure or table, then use '@label'. If you want to attach a codeword to the figure or table, rather than to the section that it is contained in, then use the '@tag' command.

      Back to top


    Bibliography and Citation


    A bibliography is a labeled list of books, articles, or papers. A citation is a marker in the text that refers to an entry in the bibliography. Because Scribe selects and prints only those entries in a bibliography that are actually cited in the text, a common bibliography file may be used for many different documents. The bibliography file consists of a series of entries, each with an identifier.

    @book(Touretzky
            ,key "Touretzky"
            ,author "Touretzky, David S."
            ,title "LISP: a gentle introduction to symbolic computation"
            ,address "New York"
            ,publisher "Harper & Row"
            ,year 1984
            )
    
    @inproceedings(ICMCFugue
            ,key "Dannenberg"
            ,author "Dannenberg, R. B. and C. L. Fraley"
            ,title "Fugue: Composition and Sound Synthesis With Lazy Evaluation
            and Behavioral Abstraction"
            ,booktitle = "Proceedings of the 1989
                    International Computer Music Conference"
            ,editor "T. Wells and D. Butler"
            ,year = "1989"
            ,organization = "International Computer Music Association"
            ,address "San Francisco"
            ,pages "76-79"
            )
    

    Then just put a '@cite' command into the text at the spot where the citation should appear:

    @cite(Touretzky)
    @cite(icmcfugue)
    

    RBD: HTML citations are translated by 's2h.lsp' to links according to data in 'docsrc/s2h/citations.lsp'. The actual bibliographic references must be hand-translated to HTML.

      Back to top


    Figures and Tables


       @begin(figure)
    text
    @end(figure)
      -  define a region to insert an object

       @graphic(text)   -  insert a picture
       @math(text)   -  insert a rendered math formula

       @caption(text)   -  add text to an object
       @fillcaption(text)   -  add formatted text to an object and modify object counters

    With the Scribe @tag command a label can be added to an object. The best place to put the @tag command is after the '@caption' or '@fillcaption' command. If the @tag command appears before the '@caption' or '@fillcaption' command, then the wrong figure number will get assigned to the tag, because the number will not yet have been incremented.

    The '@fillcaption' command is defined in the file 'docsrc/template/filcap.mss':

    @textform[FillCaption="@begin(transparent)@modify(captionenv,fill,indent 0,
    leftmargin +0.5 inch,rightmargin +0.5 inch)@modify(figurecounter,
    numbered <@@b[Figure@@ @#@:-@1:@@ @@ ]>)@modify(tablecounter,
    numbered <@@b[Figure@@ @#@:-@1:@@ @@ ]>)@caption<@parm<text>>@~
    @end(transparent)"]
    

    The exact meaning of the Scribe '@parm' and '@~' commands are currently unknown.

      Back to top


    Formatting of the Nyquist Manual


    The 's2h.lsp' HTML converter assumes a number of definitions in Scribe source, so for example, @dash is defined for Scribe by:

    @commandstring(dash @Y[M])
    

    In the Scribe output this will create an 'em-dash' (horizontal dash with a width of the letter 'm'), but the 's2h.lsp' HTML converter will always translate @dash to a hyphen character, regardless of the Scribe @commandstring definition, which 's2h.lsp' ignores. In other words, 's2h.lsp' is not written to handle any of the mechanisms provided by Scribe to extend the command set, but there are some built-in extensions such as @dash so that 's2h.lsp' can translate Nyquist manuals.

      
    @codef(name)
      -  @codef is used to define a lisp function or variable. A processor uses this to extract completion hint info for jNyqIDE.
     
      
    @pragma(defn)
      -  @pragma(defn) tells 's2h.lsp' that the next @index marks a term's definition in the manual.
     
      
    @index(term)
      -  @index is used to insert 'term' in the manual's index.

    Although Scribe has no support for marking up why a location is indexed, 's2h.lsp' uses @pragma(defn) before @index(term) to indicate that this location in the text provides the definition of 'term'. This information helps 's2h.lsp' give priority to this location in the text in cases where term may be indexed from multiple locations. In short, if you define a term, you should insert:

    @pragma(defn)@index(term)
    

    at the beginning of the definition.

    Function definitions in the Nyquist manual should be documented like this:

    @begin(fndefs)
    @codef[myfunction(@pragma(defn)@index(myfunction) ... parameters ...]@\Description of myfunction.
    
    @codef[myotherfn(@pragma(defn)@index(myotherfn) ... parameters ...]@\Description of myothernfn.
    @end(fndefs)
    

    Where one or more function definitions can be inside the @begin(fndefs) and @end(fndefs) brackets.

    Another style of documenting functions, used in the XLISP documentation is to document the function and provide indented detailed descriptions of each parameter and the return value. This style is shown here and uses @fdescription and @pdescription:

    @begin(fdescription)
            (eval@pragma(defn)@index(eval) @i<expr>) @itemsep evaluate an xlisp expression
    @begin(pdescription)
                @i<expr> @itemsep     the expression to be evaluated
    
                returns @itemsep     the result of evaluating the expression
    @end(pdescription)
    @blankspace(1)
    

      Back to top



    nyquist-3.05/docsrc/s2h/0002755000175000000620000000000011537433126014143 5ustar stevestaffnyquist-3.05/docsrc/s2h/s2h.lsp0000644000175000000620000013726311510141774015365 0ustar stevestaff; s2h -- scribe to html ; MajorHeading = H1 ; Chapter, Unnumbered, Appendix = H2 ; Section = Heading = H3 ; SubSection = SubHeading = H4 ; Paragraph = H5 ; Files: ; *dest* -- the title and table of contents ; part1.html -- for each unnumbered, chapter, appendix, ; at end of each part, link to: next part, ; index, and table of contents ; at beginning of each part, link to: prev part, ; next part, index, and table of contents ; indx.html -- the index (not "index", because that's a special name) ; title.html -- the title page and table of contents ; guide.html -- the table of contents and index for left frame ; home.html -- the top-level document with two frames, the actual name ; of this file is given by the dest parameter of (G ...) ; NyquistWords.txt -- completion list file ; Fancy control: ; add the following to Scribe file: ; @textform(html = []) ; @textform(htmltitle = []) ; @textform(pragma = []) ; To get a title, add this to the file: ; @html(Your Title Here) ; If you use frames, you should add this to the scribe document: ; @htmltitle(Your Title Here) ; This tells the translator the html title to use for the root ; html file. ; anything inside @html{...} is output directly to output html file ; anything in the @pragma{...} is executed as a command to this translator ; some pragma commands are: ; defn -- the next @index() marks a term's definition in the manual ; startscribe -- ignore scribe file starting here ; endscribe -- stop ignoring scribe file ; startref -- use text between here and an @ref or @pageref as link text ; doinclude -- process the next include file (default is to ignore) ; endcodef -- end a code definition (used for completion list) ; citations are translated to links according to data in citations.lsp ; (the actual bibliographic references must be hand-translated to HTML) ; alter *bgcolorinfo* to set background color of html documents ; set *8.3* to change from "indx.html" to "INDX.HTM" format for file names ;; label-list shall look like this: ;; ((label-symbol "label text" file-name number) ...) ;; where label-symbol is the scribe label, ;; and the rest is used like this: ;; label text (cond ((boundp '*label-list*) (setf *previous-label-list* *label-list*))) (setf *label-list* nil) ;; number of parts must be obtained from previous pass (cond ((boundp '*number-of-parts*) (setf *previous-number-of-parts* *number-of-parts*))) (setf *number-of-parts* nil) (cond ((not (boundp '*citations*)) (load (strcat (current-path) "/citations.lsp")))) ;; set this to trace parser input to help locate errors in input file (cond ((not (boundp '*token-trace*)) (setf *token-trace* nil))) (cond ((and (boundp '*inf*) *inf*) (format t "closing *inf*\n") (setf *inf* nil))) (cond ((and (boundp '*footnotefile*) *footnotefile*) (format t "closing *footnotefile*\n") (close *footnotefile*) (setf *footnotefile* nil))) (cond ((and (boundp '*outf*) *outf*) (setf *outf* nil))) ;; when @pragma(defn) is seen, this flag is set to t, when ;; the following @index(...) is seen, the flag is cleared and ;; the index is entered as a definition of the term, meaning ;; the referenced location will go to the head of the list. ;; Later, when we want to find help for a term, we know that ;; the help information is located by the first entry in the ;; index for this term. (setf definition-flag nil) (defun open-paren () (let ((tok (get-token))) (cond ((member tok '(#\( #\{ #\[ #\<)) (push tok paren-stack)) (t (push tok *next-tokens*) ;; if no open paren, then fake open and close (push #\( paren-stack) (push #\) *next-tokens*))))) ;; ((label-symbol "label text" file-name number) ...) (defun write-label () (let ((body (get-body "label" nil))) (push (list (list-to-symbol body) *name-reference* *file-name* *name-number*) *label-list*))) (defun do-make () (let ((what (get-body "make" nil))) (setf what (string-upcase (list-to-string what))) (setf what (intern what)) (cond ((member what '(manual article)) (setf *document-type* what)) (t (format t "Unknown document type: ~A, assuming ARTICLE~%" what) (setf *document-type* 'ARTICLE))))) (defun get-body (what spacesok) (prog (tok body) loop (setf tok (get-token)) (cond ((not (characterp tok)) (format t "expected characters in ~A: ~A\n" what tok)) ((paren-match tok) (pop paren-stack) (return (reverse body))) ((and (not spacesok) (eql #\Space tok))) ((null tok) (format t "early end of file\n") (break)) (t (push tok body))) (go loop))) (defun write-code () (if *omit* nil (format *outf* "")) (translate) (if *omit* nil (format *outf* ""))) (defun write-codef () (progv '(*codef*) '(t) (write-code) (codef-complete))) (defun write-quotation () (format *outf* "
    ") (translate) (format *outf* "
    ")) (defun write-normal () (format *outf* "") (translate) (format *outf* "")) (defun write-t () (let (paren) (format *outf* "") (translate) (format *outf* ""))) (defun list-to-string (body) (let ((str "")) (dolist (ch body) (setf str (strcat str (string ch)))) str)) (defun list-to-symbol (body) (setf cmd (intern (string-upcase (list-to-string body))))) ;; index-casify -- first letter upper, all others lower ;; (defun index-casify (item) (nstring-downcase item) (nstring-upcase item :start 0 :end 1)) (defun enter-index-item (item def-flag) (setf item (index-casify item)) (setf *index-number* (1+ *index-number*)) (let ((entry (assoc item *index-list* :test #'equal)) (ref (list *file-name* *index-number*)) front) (cond ((and entry def-flag) ;; put new reference at beginning of list (rplacd entry (cons ref (cdr entry)))) (entry (nconc entry (list ref))) (t (push (list item ref) *index-list*))) *index-number*)) (defun write-index (&optional def-flag) (let (body str n) (setf body (get-body "index" t)) (setf str (list-to-string body)) (if *token-trace* (format t "Index item: ~A~%" str)) (setf n (enter-index-item str def-flag)) (format *outf* "" n))) (defun index-sort-fn (a b) (string< (car a) (car b))) (defun mysort (list) (setf list (cons 'header list)) (prog (first ptr result) loop1 (cond ((null (cdr list)) (return result))) ; (display "loop1" list result) (setf first list) (setf ptr (cdr first)) loop (cond ((null (cdr ptr)) (go gotone)) ((index-sort-fn (cadr first) (cadr ptr)) (setf first ptr))) (setf ptr (cdr ptr)) (go loop) gotone (push (cadr first) result) (rplacd first (cddr first)) (go loop1))) (cond ((not (boundp '*bgcolorinfo*)) (setf *bgcolorinfo* " bgcolor=\"ffffff\""))) (cond ((not (boundp '*8.3*)) (setf *8.3* nil))) (defun html-file (namestring) (cond (*8.3* (setf namestring (string-upcase namestring)) (cond ((> (length namestring) 8) (setf namestring (subseq namestring 0 8)))) (strcat namestring ".HTM")) (t (strcat namestring ".html")))) (defun generate-index-entry (entry target) (let (n) ;; if only one target for index entry, make the word be a link (cond ((= 1 (length (cdr entry))) (format *outf* "~A
    ~%" (caadr entry) (cadadr entry) target (car entry))) (t (setf n 1) ; (car entry) may have formatting commands... (format *outf* "~A" (car entry)) (dolist (ref (cdr entry)) (format *outf* " ~A " (car ref) (cadr ref) target n) (setf n (1+ n))) (format *outf* "
    \n"))))) ;; HAS-ALPHA - trim non-alpha from beginning of key and capitalize ;; returns: nil if no alpha chars, *rslt* = key without non-alpha prefix ;; (defun has-alpha (key) (while (and (> (length key) 0) (not (both-case-p (char key 0)))) (setf key (subseq key 1))) (setf *rslt* key) ;(display "non-alpha" key) (cond ((> (length key) 0) (setf *rslt* (index-casify *rslt*)) t) (t nil))) ;; FIX-NON-ALPHA -- duplicate non-alpha entries that have an alpha char ;; and make all entries have sort keys (defun fix-non-alpha (lis) (let (rslt) (dolist (entry lis) (setf key (car entry)) (push (cons key entry) rslt) (cond ((both-case-p (char key 0)) nil) ;; normal alpha key ((has-alpha key) (push (cons *rslt* entry) rslt)))) rslt)) ;; GENERATE-INDEX -- generate the index and write to outf ;; ;; if frame-flag is provided, it signals that the output goes ;; to an already open file, which is in fact the value of frame-flag ;; This would be the second time generate-index is called, so the ;; preprocessing and sorting is not needed when frame-flag is a file ;; (defun generate-index (&optional frame-flag) (let (n target initial-char) (setf *outf* (if frame-flag frame-flag (open (strcat *dest-dir* (html-file "indx")) :direction :output))) (cond (frame-flag t) (t (incf *part-number*) (display "generate-index top" *part-number*) (write-chapter-links t t) (setf *index-list* (fix-non-alpha *index-list*)) (setf *index-list* (mysort *index-list*)) (generate-index-chars) (format *outf* "Index\n") (format *outf* "" *bgcolorinfo*))) (setf initial-char (car *index-chars*)) (format *outf* "

    Index

    ~%") (setf target (if frame-flag " target=m" "")) (format *outf* "

    ~A

    ~%" initial-char initial-char) (format *outf* "TOP
    ~%") ;; generate all non-alpha entries (dolist (entry *index-list*) (cond ((both-case-p (char (car entry) 0))) (t (generate-index-entry (cdr entry) target)))) ;; generate A - Z (dolist (entry *index-list*) ;; put headings for every new starting character (let ((c (char (car entry) 0))) (cond ((not (both-case-p c)) nil) ; ignore non-alphas here ((eql initial-char (char (car entry) 0))) ; no change (t (setf initial-char (char (car entry) 0)) (format *outf* "

    ~A

    ~%" initial-char initial-char) (format *outf* "TOP
    ~%"))) (if (both-case-p c) (generate-index-entry (cdr entry) target)))) (cond (frame-flag t) (t (display "generate-index bottom" *part-number*) (write-chapter-links nil t) (format t "closing indx.html\n") (close *outf*))))) ;; GENERATE-TOC-2 -- generate table of contents body ;; ;; if frame-flag is t, generate html for left frame ;; output to *outf* ;; (defun generate-toc-2 (lis &optional frame-flag) (format *outf* "
      \n") (dolist (lis1 lis) (let (lis2 target) (setf lis1 (reverse lis1)) (setf lis2 (car lis1)) ; (display "part1" lis2) (if frame-flag (setf target " target=\"m\"")) (format *outf* "
    • ~A\n" ;filename ;ref-number ;target ;name (car lis2) (cadr lis2) target (caddr lis2)) (setf lis2 (cdr lis1)) ; (display "part2" lis2) (cond (lis2 (generate-toc-2 lis2 frame-flag))))) (format *outf* "
    \n")) (defun generate-toc (&optional frame-flag) (format *outf* "\n") (format *outf* "

    Table of Contents

    \n") (generate-toc-2 (reverse *chapter-list*) frame-flag) (cond (frame-flag t) (t (format *outf* "
    " (html-file "indx"))))) (defun get-primary (str) (get-string-after "primary" str)) (defun get-secondary (str) (get-string-after "secondary" str)) (defun get-string-after (key str) (let ((n (string-search key str)) m) (cond ((null n) (format t "get-string-after could not find ~A in ~A~%" key str) (break))) (setf n (+ n (length key))) (display "a" n) (setf n (string-search "\"" str :start n)) (display "b" n) (cond ((null n) (format t "get-string-after: no quote after ~A in ~A~%" key str) (break))) (setf n (1+ n)) (setf m (string-search "\"" str :start n)) (display "c" m) (cond ((null m) (format t "get-string-after: no close quote after ~A in ~A~%" key str) (break))) (subseq str n m))) (defun write-indexsecondary () (let (body str n) (setf body (get-body "secondaryindex" t)) (setf str (list-to-string body)) (if *token-trace* (format t "SecondaryIndex item: ~A~%" str)) (setf str (strcat (get-primary str) ", " (get-secondary str))) (setf n (enter-index-item str nil)) (format *outf* "" str n))) (defun read-begin-command () (let (cmd n (body (get-body "begin" nil))) (setf cmd (list-to-string body)) (setf n (string-search "," cmd)) (cond (n (format t "warning: dropping parameters after comma in @begin(~A)~%" cmd) (setf cmd (subseq cmd 0 n)))) (setf cmd (intern (string-upcase cmd))) (push cmd paren-stack) cmd)) (defun read-end-command () (let (cmd (body (get-body "end" nil))) (setf cmd (list-to-symbol body)) (list 'end cmd))) (defun read-pragma-command () (let ((body (get-body "end" nil)) cmd) (setf cmd (list-to-symbol body)) cmd)) (defun write-style (style) (format *outf* "<~A>" style) (translate) (format *outf* "" style)) (defun write-bold-italic () (format *outf* "") (translate) (format *outf* "")) (defun write-superscript () (output-char #\^) (output-char #\() (translate) (output-char #\))) (defun write-subscript () ; (output-char #\[) (translate) ; (output-char #\]) ) (defun write-dd () (if (and *description* (not *omit*)) (format *outf* "
    "))) (defun write-description () (format *outf* "
    \n
    ") (progv '(*description*) '(t) (translate)) (format *outf* "
    ")) (defun write-fdescription () (format *outf* "
    \n
    ") (progv '(*fdescription*) '(t) (progv '(*codef*) '(t) (translate) (codef-complete))) (format *outf* "
    ")) (defun write-fgroup () (progv '(*fgroup*) '(t) ; (format *outf* " enter fgroup ") (translate))) ; (format *outf* " exit fgroup ") (defun write-pdescription () (let ((pdesc *pdescription*)) (if pdesc (format *outf* "
    ")) (format *outf* "
    ") (setf *pdescription* t) (codef-complete) ;; finish preceding function completion string (progv '(*codef*) '(nil) (translate)) (setf *codef* t) ;; turn back on for next definition (if pdesc (format *outf* "
    ")) (setf *pdescription* pdesc))) (defun close-paren-p (tok) (or (and (listp tok) (eq (car tok) 'end)) (paren-match tok))) (defun paren-match (p2) (let ((p1 (car paren-stack))) (or (and (eql p2 #\)) (eql p1 #\()) (and (eql p2 #\]) (eql p1 #\[)) (and (eql p2 #\}) (eql p1 #\{)) (and (eql p2 #\>) (eql p1 #\<)) (and (listp p2) (eq (car p2) 'end) (eq p1 (cadr p2)))))) (defun skip-it () (let ((omit *omit*)) (setf *omit* t) (translate) (setf *omit* omit))) (defun write-titlepage () (translate)) (defun write-titlebox () (translate)) (defun write-majorheading () (format *outf* "

    ") (translate) (format *outf* "

    ")) (defun write-h2 () (format *outf* "

    ") (translate) (format *outf* "

    ")) (defun write-h3 () (format *outf* "

    ") (translate) (format *outf* "

    ")) (defun write-h4 () (format *outf* "

    ") (translate) (format *outf* "

    ")) (defun write-paragraph () (let ((body (get-body "paragraph" t))) (setf body (list-to-string body)) (setf *name-reference* (format nil "\"~A\"" body)) (setf *name-number* (1+ *name-number*)) (push (list (list *file-name* *name-number* body)) *paragraph-list*) (format *outf* "
    ~A
    " *name-number* body))) (defun finish-subsection () (push *paragraph-list* *subsection-list*) (setf *paragraph-list* nil)) (defun write-subsection () (let ((body (get-body "subsection" t))) (setf body (list-to-string body)) (setf *name-reference* (format nil "\"~A\"" body)) (setf *name-number* (1+ *name-number*)) (cond (*paragraph-list* (finish-subsection))) (setf *paragraph-list* (list (list *file-name* *name-number* body))) (format *outf* "

    ~A

    " *name-number* body))) (defun finish-section () (cond (*paragraph-list* (finish-subsection))) (push *subsection-list* *section-list*) (setf *subsection-list* nil)) (defun write-section () (let ((body (get-body "section" t))) (setf body (list-to-string body)) (setf *name-reference* (format nil "\"~A\"" body)) (setf *name-number* (1+ *name-number*)) (cond (*subsection-list* (finish-section))) (setf *subsection-list* (list (list *file-name* *name-number* body))) (format *outf* "

    ~A

    " *name-number* body))) (defun previous-part-file-name () (cond ((> *part-number* 2) (html-file (format nil "part~A" (- *part-number* 2)))) (t *dest*))) ;; called when new chapter is encountered, ;; lastflag = nil means write a Next Section link (defun finish-chapter () (cond (*subsection-list* (finish-section))) (push *section-list* *chapter-list*) (setf *section-list* nil) ; *dest* links get added after table of contents (cond ((not (eq *outf* *rootf*)) (write-chapter-links) (format *outf* "\n") ))) (defun write-title-page-links () (format *outf* "
    \n") (let (name) (setf name (html-file "part1")) (format *outf* "Next Section | " name)) (format *outf* "Index | " (html-file "indx")) (format *outf* "
    \n")) (defun write-chapter-links (&optional top-flag index-flag title-flag) (display "write-chapter-links" *part-number* *previous-number-of-parts*) (let ((lastflag (eql *part-number* *previous-number-of-parts*))) (if top-flag t (format *outf* "
    \n")) (cond ((not title-flag) (format *outf* "Previous Section | " (previous-part-file-name)))) (cond (index-flag nil) ((not lastflag) (let (name) (setf name (html-file (if title-flag "part1" (format nil "part~A" *part-number*)))) (format *outf* "Next Section | " name))) (t (format *outf* "Next Section (Index) | " (html-file "indx")))) (format *outf* "Table of Contents | " *dest*) (cond ((and (not lastflag) (not index-flag)) (format *outf* "Index | " (html-file "indx")))) (format *outf* "Title Page\n" *dest*) (if top-flag (format *outf* "
    \n")))) (defun set-html-title () (setf *title* (get-body "htmltitle" t)) (setf *title* (list-to-string *title*))) (defun write-chapter () (let ((body (get-body "chapter" t))) ;(display "write-chapter" body) (setf body (list-to-string body)) (setf *name-reference* (format nil "\"~A\"" body)) (setf *name-number* (1+ *name-number*)) (cond (*section-list* (finish-chapter))) (cond ((eq *outf* *rootf*)) (t (format t "Closing ~A~%" *file-name*) (close *outf*))) (setf *file-name* (html-file (format nil "part~A" *part-number*))) (setf *section-list* (list (list *file-name* *name-number* body))) (setf *outf* (open (strcat *dest-dir* *file-name*) :direction :output)) (setf *part-number* (1+ *part-number*)) (format *outf* "~A\n\n" body *bgcolorinfo*) (write-chapter-links t) (format *outf* "

    ~A

    " *name-number* body))) (defun write-detail () (format *outf* "") (translate) (format *outf* "\n")) (defun write-appendix () (let ((body (get-body "appendix" t))) (setf body (list-to-string body)) (setf *name-reference* (format nil "\"~A\"" body)) (setf body (format nil "Appendix ~A: ~A" *appendix-number* body)) (setf *appendix-number* (1+ *appendix-number*)) (setf *name-number* (1+ *name-number*)) (cond (*section-list* (finish-chapter))) (cond ((eq *outf* *rootf*)) (t (format t "Closing ~A~%" *file-name*) (close *outf*))) (setf *file-name* (html-file (format nil "part~A" *part-number*))) (setf *section-list* (list (list *file-name* *name-number* body))) (setf *outf* (open (strcat *dest-dir* *file-name*) :direction :output)) (setf *part-number* (1+ *part-number*)) (write-chapter-links t) (format *outf* "~A\n" body) (format *outf* "

    ~A

    " *name-number* body))) (defun write-blankspace () (cond (*fdescription* ; what we want is

    after pdescription environment ; to set up the next fdescription, but we may have output one
    ; after the last pdescription. By using (linebreak) we avoid a ; third
    which would output too much space. (linebreak) (format *outf* "
    ")) (t (paragraph))) (get-body "blankspace" t)) ;(defun write-center () ; (linebreak) ; (translate) ; (linebreak)) (defun write-newpage () (translate)) ; ignore multiple calls in sequence ; (defun paragraph () (cond ((null *paragraph*) (cond (*itemize* (format *outf* "\n
  • ")) (*description* (format *outf* "

    \n
    ")) ((or *pdescription* *fgroup*) (linebreak)) (*fdescription*) ; and not *pdescription*: no paragraph (t (format *outf* "\n

    \n"))) (setf *paragraph* t)))) (defun linebreak () (cond ((and (null *paragraph*) (null *linebreak*)) (format *outf* "
    \n") (setf *linebreak* t)))) (defun write-smallcaps () (let ((sc *smallcap*)) (setf *smallcap* t) (translate) (setf *smallcap* sc))) (defun write-cite () (let (body link) (setf body (get-body "cite" nil)) (setf body (list-to-symbol body)) (format t "Citation: ~A ~%" body) (setf link (assoc body *citations*)) (cond ((null link) (format t "Undefined citation: ~A~%" body)) (t (format *outf* " ~A" (cadr link) (caddr link)))))) (defun write-ref () (let ((body (get-body "ref" nil)) ref (file "")) (cond (*startref* (setf *startref* nil) (setf *omit* nil))) (setf body (list-to-symbol body)) (setf ref (assoc body *previous-label-list*)) (cond ((null ref) (format t "warning: undefined label ~A~%" body)) (t (cond ((not (equal (caddr ref) *file-name*)) (setf file (caddr ref)))) (format *outf* "~A" file (cadddr ref) (cadr ref)))))) (defun write-example () (format *outf* "

    ")
      (translate)
      (format *outf* "
    \n")) (defun write-enumerate () (let ((itemize *itemize*)) (format *outf* "
      \n
    1. ") (setf *itemize* t) (translate) (format *outf* "
    ") (setf *itemize* itemize))) (defun write-itemize () (let ((itemize *itemize*)) (format *outf* "
      \n
    • ") (setf *itemize* t) (translate) (format *outf* "
    ") (setf *itemize* itemize))) (defun write-format () (let ((display *display*)) ; hopefully, we'll get a linebreak to separate the text as does scribe (setf *display* t) (translate) (format *outf* "

    ~%") ; separate the text from what follows (setf *display* display))) (defun write-display () (let ((display *display*)) (format *outf* "

    ") (setf *display* t) (setf *linebreak* t) ; it's automatic with blockquote, ; so we do this to suppress an extra
    (translate) (format *outf* "
    ") (setf *display* display))) (defun write-figure () (format *outf* "
    ") (translate) (format *outf* "
    ")) (defun write-dash () (get-body "dash" nil) (output-char #\-)) (defun write-html () (setf *html* t) (translate) (setf *html* nil)) (defun write-foot () (let ((outf *outf*) (name (html-file "foot"))) (format *outf* " (Footnote ~A) " name *footnote-number* *footnote-number*) (cond ((null *footnotefile*) (setf *footnotefile* (open (strcat *dest-dir* name) :direction :output)) (format *footnotefile* "Footnotes\n") (format *footnotefile* "\n

    Footnotes

    \n" *bgcolorinfo*) )) (setf *outf* *footnotefile*) (format *outf* " ~A. " *footnote-number* *footnote-number*) (setf *footnote-number* (1+ *footnote-number*)) (translate) (format *outf* "\n

    \n") (setf *outf* outf))) (defun write-fillcaption () (paragraph) (format *outf* "Figure ~A: " *figure-number*) (translate)) (defun do-include () (setf *include* t)) (defun write-include () (let ((body (get-body "include" nil)) file) (cond (*include* (setf *include* nil) (setf body (list-to-string body)) (setf file *inf*) (setf *inf* (open (strcat *include-prefix* body))) (cond ((null *inf*) (format t "Could not open include file ~A\n" body) (break)) (t (format t "Processing include file ~A\n" body) (translate) (format t "Closing include file ~A\n" body) (close *inf*) (setf *inf* file))) )))) (defun do-tag () (let ((body (get-body "tag" nil))) (push (list (list-to-symbol body) (format nil "~A" *figure-number*) *file-name* *name-number*) *label-list*) (setf *figure-number* (1+ *figure-number*)) )) (defun write-math () (translate)) (defun write-underline () (format *outf* "") (translate) (format *outf* "\n")) ; initiated by @startscribe() ; and ended by @endscribe() ; (defun do-startscribe () (setf *omit* t)) (defun do-endscribe () (setf *omit* nil)) (defun do-startref () (setf *omit* t) (setf *startref* t)) (defun write-title () (translate)) (defun do-comment () ; skip everything until matching paren (prog (tok) loop (setf tok (get-comment-token)) ; (display "do-comment" tok paren-stack) (cond ((and (close-paren-p tok) (paren-match tok)) ; (display "do-comment" paren-stack) (pop paren-stack) ; (format t "do-comment done\n") (return))) (go loop))) (defun output-char (c) (cond (*omit* t) (t (cond ((and *smallcap* (alpha-char-p c)) (setf c (char-upcase c)))) ; (display "output-char" *display*) (cond ((and *display* (eql c #\Newline)) (linebreak)) ((member c '(#\Space #\Newline))) (t (setf *paragraph* nil) (setf *linebreak* nil))) (cond (*html*) ; no translation if we're in an @html(...) section ((eq c #\<) (write-char #\& *outf*) (write-char #\l *outf*) (write-char #\t *outf*) (setf c #\;)) ((eq c #\>) (write-char #\& *outf*) (write-char #\g *outf*) (write-char #\t *outf*) (setf c #\;)) ((eq c #\&) (write-char #\& *outf*) (write-char #\a *outf*) (write-char #\m *outf*) (write-char #\p *outf*) (setf c #\;))) ; (display "output-char" c) (write-char c *outf*)))) (setf *translate-depth* 0) (defun translate () (setf *translate-depth* (1+ *translate-depth*)) (if *token-trace* (format t "(~A " *translate-depth*)) (prog (tok) loop (setf tok (get-token)) (cond ((and tok (symbolp tok) *token-trace*) (format t "[~A]" tok))) (cond ((null tok) (go ret)) ((close-paren-p tok) (cond ((paren-match tok) (pop paren-stack)) (t (format t "unmatched end: ~A~%" tok) (break))) (go ret)) ((eq tok 'altdef) (translate)) ((characterp tok) ;; output completion hints file (cond (*codef* (codef-char tok))) (output-char tok)) ((eq tok 'label) (write-label)) ((member tok '(code smallcode xlcode)) (write-code)) ((eq tok 'codef) (write-codef)) ((eq tok 'index) (write-index definition-flag) (setf definition-flag nil)) ((eq tok 'indexsecondary) (write-indexsecondary)) ((eq tok 'indexdef) ;; this is obsolete now (write-index t)) ((eq tok 'r) (write-normal)) ((eq tok 'i) (write-style "i")) ((eq tok 'b) (write-style "b")) ((eq tok 'titlepage) (write-titlepage)) ((eq tok 'titlebox) (write-titlebox)) ((member tok '(majorheading chapnum)) ; chapnum is for Tomayko (write-majorheading)) ((member tok '(skip blankspace)) ; skip is for Tomayko (write-blankspace)) ((member tok '(verse center)) (write-display)) ;; seems to be best substitute for center ((eq tok 'format) (write-format)) ((eq tok 'newpage) (write-newpage)) ((eq tok 'c) (write-smallcaps)) ((member tok '(text quotation)) (write-quotation)) ((eq tok 't) (write-t)) ((eq tok 'title) (write-title)) ((eq tok 'htmltitle) (set-html-title)) ((member tok '(chapter unnumbered)) (write-chapter)) ((eq tok 'appendix) (write-appendix)) ((eq tok 'detail) (write-detail)) ((eq tok 'section) (write-section)) ((eq tok 'heading) (write-h3)) ((eq tok 'subsection) (write-subsection)) ((eq tok 'subheading) (write-h4)) ((eq tok 'paragraph) (write-paragraph)) ((eq tok 'cite) (write-cite)) ((member tok '(ref pageref)) (write-ref)) ((eq tok 'startref) (do-startref)) ((eq tok 'p) (write-bold-italic)) ((eq tok 'plus) (write-superscript)) ((eq tok 'minus) (write-subscript)) ((eq tok 'html) ; special way to insert html (write-html)) ((member tok '(example programexample)) (write-example)) ((eq tok 'figure) (write-figure)) ((eq tok 'fillcaption) (write-fillcaption)) ((eq tok 'tag) (do-tag)) ((eq tok 'doinclude) (do-include)) ((eq tok 'include) (write-include)) ((eq tok 'backslash) (write-dd)) ((eq tok 'math) (write-math)) ((member tok '(foot note)) ; note is for Tomayko (codef-complete) (setf *codef* nil) (write-foot)) ((member tok '(description fndefs)) (write-description)) ((eq tok 'fdescription) (write-fdescription)) ((eq tok 'pdescription) (write-pdescription)) ((eq tok 'fgroup) (write-fgroup)) ((eq tok 'itemize) (write-itemize)) ((eq tok 'enumerate) (write-enumerate)) ((eq tok 'display) (write-display)) ((member tok '(subtract itemsep dash ndash)) (cond ((eq tok 'itemsep) (codef-complete) (setf *codef* nil))) ;; end completion string (write-dash)) ((eq tok 'star) (linebreak)) ((eq tok 'new-paragraph) (paragraph)) ((member tok '(y value definefont)) (format t "warning: omitting @~A[] text\n" tok) (skip-it)) ((member tok '(one colon shout slash bar bibliography)) (format t "ignoring ~A\n" tok)) ((eq tok 'make) (do-make)) ((member tok '(device libraryfile style commandstring modify define use counter pageheading set graphic mult tabset tabclear textform part)) (skip-it)) ((eq tok 'comment) (do-comment)) ((eq tok 'defn) (setf definition-flag t)) ((eq tok 'startscribe) (do-startscribe)) ((eq tok 'endscribe) (do-endscribe)) ((eq tok 'endcodef) (codef-complete)) ((eq tok 'stopcodef) (setf *codef* nil)) ((eq tok 'startcodef) (setf *codef* t)) ((member tok '(u ux)) (write-underline)) ((member tok '(group flushleft)) ; ignore it, flushleft is for Tomayko (translate)) (t (format t "unrecognized token: ~A~%" tok) (break))) (go loop) ret (if *token-trace* (format t ")")) (setf *translate-depth* (- *translate-depth* 1)) )) (defun manualp () (eq *document-type* 'manual)) (format t "To run, call:\n") (format t " (g \"scribe source directory\" ; omit the trailing slash\n") (format t " \"scribe file\" ; omit the .mss suffix\n") (format t " \"html directory\" ; omit the trailing slash\n") (format t " \"html root file\" ; omit the .html suffix\n") (format t " [t]) ; optional flag generates html with frames\n") (defun g (sourcedir source destdir dest &optional frame-flag) (setf *codef-capture* "") (setf *codef-list* nil) (setf *figure-number* 1) (setf *index-number* 1) (setf *appendix-number* 1) (setf *footnotefile* nil) (setf *footnote-number* 1) (setf *name-number* 0) (setf *name-reference* nil) (setf *omit* nil) (setf *html* nil) ; says we're in section to dump html literally (setf *include* nil) ; process include or not? (setf *next-tokens* nil) (setf *smallcap* nil) (setf *paragraph* t) (setf *linebreak* t) (setf *itemize* nil) (setf *display* nil) (setf *description* nil) (setf *fdescription* nil) (setf *fgroup* nil) (setf *pdescription* nil) (setf *codef* nil) ; says we're defining a function, add to completion list ;; paragraph-list is initialized to: ;; ((file number sectionname)) ;; and after each paragraph, expands, e.g.: ;; ((file number paragraphname) (file number sectionname)) (setf *paragraph-list* nil) ;; likewise, the subsection-list is initialized to: ;; ((file number sectionname)) ;; and after each subsection, expands, e.g.: ;; (((file number paragraphname) (file number subsectionname)) ;; (file number sectionname))) (setf *subsection-list* nil) ;; and so on... (setf *section-list* nil) (setf *chapter-list* nil) ; *dest* is the root HTML file (setf *dest* (if frame-flag (html-file "title") (html-file dest))) ; *file-name* is the current HTML file (setf *file-name* *dest*) (format t "Destination HTML file: ~A~%" *file-name*) (setf *part-number* 1) ; *startref* is set when @startref() is encountered, at which ; point text is omitted until a reference is encountered, at ; which point text is resumed. (setf *startref* nil) ;; index-list shall look like this: ;; (("key" "indexterm" (filename num) (filename num) ...) ;; ("key" "indexterm" (filename num) (filename num) ...) ...) ;; where key is the sortkey (usually indexterm) and indexterm is ;; what gets printed. This allows non-alphabetic items to be sorted ;; according to their first alphabetic character, e.g. *rslt* can ;; be sorted as "rslt" as well as "*rslt*" ;; (setf *index-list* nil) (setf paren-stack nil) ;; run this twice to get labels right ;; if *label-list* is NIL, it may be because we reloaded this file, ;; in which case *previous-label-list* has already been copied from ;; *label-list* (cond (*label-list* (setf *previous-label-list* *label-list*)) ((not (boundp '*previous-label-list*)) (setf *previous-label-list* nil))) (cond (*number-of-parts* (setf *previous-number-of-parts* *number-of-parts*))) (cond ((not (boundp '*previous-number-of-parts*)) (setf *previous-number-of-parts* 0))) (setf *inf* (open (strcat sourcedir "/" source ".mss"))) ; "test.mss")) ; "/afs/cs/user/rbd/doc/man/nyquist/nyquistman.mss")) (setf *include-prefix* (strcat sourcedir "/")) (setf *dest-dir* (strcat destdir "/")) (setf *outf* (open (strcat *dest-dir* *file-name*) :direction :output)) (setf *codef-file* (open (strcat *dest-dir* "NyquistWords.txt" ) :direction :output)) (setf *rootf* *outf*) (display "g-before translate" *outf* *rootf* *inf*) (translate) (display "g-after translate" *outf* *rootf* *inf*) (format t "g: closing *inf*\n") (close *inf*) (setf *inf* nil) (format t "g: closing *outf*\n") (finish-chapter) (cond ((not (eq *outf* *rootf*)) (close *outf*) (setf *outf* nil))) (cond (*footnotefile* (format *footnotefile* "\n") (close *footnotefile*))) (setf *footnotefile* nil) (setf *outf* *rootf*) (display "g-before toc" *outf* *rootf* *inf*) (setf *number-of-parts* *part-number*) (cond ((manualp) (setf *part-number* 1) ;; reset for title page (write-title-page-links) (generate-toc) (write-chapter-links nil nil t))) (format *rootf* "\n") (format t "g: closing *rootf*\n") (close *rootf*) (setf *outf* (setf *rootf* nil)) (cond ((manualp) (setf *part-number* *number-of-parts*) ;; restore from above (generate-index)) ; if this is not a manual, there are no chapters, so there are no ; links between chapters or table of contents, so index cannot be ; reached, so index is not generated. This is bad if there really ; are index terms!!!! (*index-list* (format t "WARNING: NO INDEX IS BEING GENERATED, THIS IS A BUG~%"))) (cond (frame-flag (if (not (manualp)) (error "frame option only works with manual document types")) (generate-home *title* (strcat *dest-dir* (html-file dest))) (generate-guide (strcat *dest-dir* (html-file "guide"))) )) (codef-close) ) (defun generate-home (title filename) (let ((outf (open filename :direction :output))) (format outf "~A~%" title) (format outf "~%") (format outf "~%") (format outf "~%") (format outf "<body><p>This browser does not support frames.~%") (format outf "<p><a href=title.html>The no-frames version is here.</a>~%") (format outf "</body>~%") (close outf))) ;; FIND-ALPHA-AND-NON-ALPHA -- sublist with only alpha chars ;; return the range of the rest in *rslt*, e.g. "!-~" ;; (defun find-alpha-and-non-alpha (lis) (let (prev first last rslt) (dolist (c lis) (cond ((eql prev c)) (t (setf prev c) (cond ((both-case-p prev) (push prev rslt)) ((null first) (setf first prev) (setf last prev)) (t (setf last prev)))))) (setf *rslt* (strcat (string first) "-" (string last))) rslt)) (defun generate-index-chars () (let (term initial prev) (setf *index-chars* nil) ;; compute the list of characters for index (dolist (entry *index-list*) (setf term (car entry)) (setf initial (char term 0)) (cond ((eql prev (char term 0))) (t (setf prev initial) (push prev *index-chars*)))) (setf *index-chars* (reverse *index-chars*)) (setf *index-chars* (find-alpha-and-non-alpha *index-chars*)) (setf *index-chars* (reverse *index-chars*)) (push *rslt* *index-chars*))) (defun generate-guide (dest) (let (term initial prev index-chars non-alpha) (setf *outf* (open dest :direction :output)) (format *outf* "Links~%") (format *outf* "

    ~%") (dotimes (n (length *index-chars*)) (setf c (nth n *index-chars*)) (format *outf* "~A~%" c c) (if (zerop (rem (1+ n) 9)) (format *outf* "
    ~%"))) (format *outf* "

    ~%") (generate-toc t) (generate-index *outf*) (format *outf* "~%") (close *outf*))) (defun alpha-char-p (c) (let ((cc (char-code c))) (or (and (>= cc (char-code #\a)) (<= cc (char-code #\z))) (and (>= cc (char-code #\A)) (<= cc (char-code #\Z)))))) (defun process-comment-at () (let (c cmd) (read-char *inf*) ; read the @ (setf c (peek-char nil *inf*)) (cond ((alpha-char-p c) (setf cmd (read-command)) (cond ((eq cmd 'end) (open-paren) (read-end-command)) (t #\z)))))) (defun process-at () (let (c cmd) (read-char *inf*) ; read the @ (setf c (peek-char nil *inf*)) (cond ((eql c #\@) (read-char *inf*)) ((eql c #\\) (read-char *inf*) 'backslash) ((eql c #\/) (read-char *inf*) 'slash) ((eql c #\1) (read-char *inf*) 'one) ((eql c #\+) (read-char *inf*) (open-paren) 'plus) ((eql c #\*) (read-char *inf*) 'star) ((eql c #\-) (read-char *inf*) (open-paren) 'minus) ((eql c #\:) (read-char *inf*) 'colon) ((eql c #\!) (read-char *inf*) 'shout) ((eql c #\|) (read-char *inf*) 'bar) ((alpha-char-p c) (setf cmd (read-command)) (cond ((eq cmd 'begin) (open-paren) (read-begin-command)) ((eq cmd 'end) (open-paren) (read-end-command)) ((eq cmd 'pragma) (open-paren) (read-pragma-command)) (t (open-paren) cmd))) (t (format t "unexpected char after @: ~A~%" c) (break))))) (defun process-newline () (let (c) (read-char *inf*) ; read the newline (setf c (peek-char nil *inf*)) (cond ((eql c #\Newline) (while (eql (peek-char nil *inf*) #\Newline) (read-char *inf*)) 'new-paragraph) (t #\Newline)))) ;; READ-COMMAND -- read command after an @ ; (defun read-command () (let ((command "")) (while (alpha-char-p (peek-char nil *inf*)) (setf command (strcat command (string (read-char *inf*))))) (intern (string-upcase command)))) ;; (read-char *inf*)) (defun get-token () (let ((c (peek-char nil *inf*)) result) ;; allow others to force next token: (cond (*next-tokens* (setf result (car *next-tokens*)) (setf *next-tokens* (cdr *next-tokens*))) (t (setf result (cond ((eql c #\@) (process-at)) ((eql c #\Newline) (process-newline)) ((eql c #\`) ;; double `` -> " (read-char *inf*) (setf c (peek-char nil *inf*)) (cond ((eql c #\`) (read-char *inf*) #\") (t #\`))) ((eql c #\') ;; double '' -> " (read-char *inf*) (setf c (peek-char nil *inf*)) (cond ((eql c #\') (read-char *inf*) #\") (t #\'))) (t (read-char *inf*)))))) (if *token-trace* (format t "->~A " result)) result )) (defun get-comment-token () (let ((c (peek-char nil *inf*)) result) (setf result (cond ((eql c #\@) (process-comment-at)) (t (read-char *inf*)))) (if *token-trace* (format t "->~A " result)) result )) (defun codef-char (c) (if (member c '(#\Newline #\Tab)) (setf c #\Space)) (setf *codef-capture* (strcat *codef-capture* (string c)))) (defun codef-complete () ; (write-char #\) *codef-file*) (let (index) ;; remove [lisp] and [sal] and everything after it (if (setf index (string-search "[lisp]" *codef-capture*)) (setf *codef-capture* (subseq *codef-capture* 0 index))) (if (setf index (string-search "[sal]" *codef-capture*)) (setf *codef-capture* (subseq *codef-capture* 0 index))) ;; trim extra blanks (while (setf index (string-search " " *codef-capture*)) (setf *codef-capture* (strcat (subseq *codef-capture* 0 index) (subseq *codef-capture* (1+ index))))) ;; replace "expr..." with "expr ..." Want to replace all occurences, ;; so scan string, starting at previous spot + 2 (to get beyond the ;; inserted space character) until nothing is found (setf index 0) (while (and (< (+ index 2) (length *codef-capture*)) (setf index (string-search "..." *codef-capture* :start (+ 2 index)))) (cond ((and index (> index 0) (not (eq (char *codef-capture* (1- index)) #\Space))) (setf *codef-capture* (strcat (subseq *codef-capture* 0 index) " " (subseq *codef-capture* index)))))) ;; trim blanks after open bracket/comma and before close paren (while (setf index (string-search "[, " *codef-capture*)) (setf index (+ 2 index)) (setf *codef-capture* (strcat (subseq *codef-capture* 0 index) (subseq *codef-capture* (1+ index))))) (while (setf index (string-search " )" *codef-capture*)) (setf *codef-capture* (strcat (subseq *codef-capture* 0 index) (subseq *codef-capture* (1+ index))))) ) ;; trim blanks (setf *codef-capture* (string-trim " " *codef-capture*)) ;; translate &key to example format (cond ((or (string-search "&key" *codef-capture*) (string-search "&optional" *codef-capture*)) (setf *codef-capture* (codef-expand *codef-capture*)))) (if (and (> (length *codef-capture*) 0) ; must be non-empty (not (eq (char *codef-capture* 0) #\:))) ; ignore messages (push (string-downcase (convert-sal-to-lisp *codef-capture*)) *codef-list*)) ;; trim leading open paren (if (and (> (length *codef-capture*) 0) (eq (char *codef-capture* 0) #\()) (setf *codef-capture* (subseq *codef-capture* 1))) (setf *codef-capture* "")) (defun convert-sal-to-lisp (codef) ;(format *codef-file* "sal-to-lisp |~A|~%" codef) ;; some of these strings are already lisp. The SAL strings have an ;; open paren after the function call (cond ((eq (char codef 0) #\() (setf codef (subseq codef 1))) ((string-search "(" codef) (setf codef (do-convert-sal-to-lisp codef)))) codef) (defun do-convert-sal-to-lisp (codef) ;; take out initial "(" and replace with space ;; delete each subsequent comma ;; for each colon, flip it to a keyword (key: -> :key) (let ((p (string-search "(" codef))) ;; replace "(" with " " (setf codef (strcat (subseq codef 0 p) " " (subseq codef (1+ p)))) ;; delete commas: (setf p (string-search "," codef)) (while p (setf codef (strcat (subseq codef 0 p) (subseq codef (1+ p)))) (setf p (string-search "," codef))) ;; for each colon, flip it to a keyword (setf p (string-search ":" codef)) (while p ;; back up (setf q (1- p)) (while (not (member (char codef q) '(#\Space #\[))) (setf q (1- q))) (incf q) (setf codef (strcat (subseq codef 0 q) ":" (subseq codef q p) (subseq codef (1+ p)))) (setf p (string-search ":" codef :start (1+ p))) '(display "do-cstl" p codef)) codef)) (defun split (s) (let (rslt (token "") c) (dotimes (i (length s)) (setf c (char s i)) (cond ((eq c #\Space) (cond ((> (length token) 0) (push token rslt) (setf token "")))) ((member c '(#\( #\))) (cond ((> (length token) 0) (push token rslt) (setf token ""))) (push (string c) rslt)) (t (setf token (strcat token (string c)))))) (cond ((> (length token) 0) (push token rslt))) (reverse rslt))) (defun colonize (word) (if (eq (char word 0) #\:) word (strcat ":" word))) (defun uncolonize (word) (if (eq (char word 0) #\:) (subseq word 1) word)) (defun codef-expand (s) (let (words (r "") mode (space "")) (setf words (split s)) (dolist (word words) (cond ((equal word "&key") (setf mode :key)) ((equal word "&optional") (setf mode :optional)) ((equal word "(") (setf r (strcat r space word)) (setf space "")) ((equal word ")") (setf r (strcat r word)) (setf space " ")) ((eq mode :key) (setf r (strcat r space "[" (colonize word) " " (uncolonize word) "]")) (setf space " ")) ((eq mode :optional) (setf r (strcat r space "[" word "]")) (setf space " ")) (t (setf r (strcat r space word)) (setf space " ")))) r)) (defun find-url-for (item) (let (i entry) ;; first, extract the initial symbol from item (setf i (string-search " " item)) (cond (i (setf item (subseq item 0 i)))) ;; trim trailing (or any) close parenthesis (setf i (string-search ")" item)) (cond (i (setf item (subseq item 0 i)))) ;; fix the case/capitalization to match what's in *index-list* (setf item (index-casify item)) ;; look it up (setf entry (assoc item *index-list* :test #'equal)) ;; return the URL (cond (entry ;; entry has (sort-key, name, ref1, ref2, ...) (setf entry (third entry)) ;; get first reference (format nil "~A#index~A" (first entry) (second entry))) (t (format t "WARNING: ~A IS NOT IN INDEX~%" item) "home.htm")))) (defun codef-close () ;; called to close file ;; nothing written yet (let (url) (setf *codef-list* (sort *codef-list* #'string<)) (dolist (item *codef-list*) (setf url (find-url-for item)) (format *codef-file* "~A~%~A~%" item url)) (close *codef-file*))) nyquist-3.05/docsrc/s2h/do-nyquist-manual.lsp0000644000175000000620000000031011510141774020236 0ustar stevestaff;; build html for nyquist manual (load "s2h") (expand 10) ;; sourcedir source destdir dest (g "../nyquist" "nyquistman" "../../doc" "home" t) (g "../nyquist" "nyquistman" "../../doc" "home" t) nyquist-3.05/docsrc/s2h/citations.lsp0000644000175000000620000000156511466723256016674 0ustar stevestaff(expand 100) (setf *citations* '( (Anderson "../JITLBIB.HTM#anderson" "(Anderson 1985)") (Beare "../JITLBIB.HTM#beare" "(Beare 1989)") (Bloom "../JITLBIB.HTM#bloom" "(Bloom 1956)") (Capell "../JITLBIB.HTM#capell" "(Capell 1995)") (ptinterface "../JITLBIB.HTM#dannenberg" "(Dannenberg 1990)") (Fletcher "../JITLBIB.HTM#fletcher" "(Fletcher 1990)") (Ford "../JITLBIB.HTM#ford" "(Ford 1959)") (Lehman "../JITLBIB.HTM#lehman" "(Lehman 1993)") (Moore "../JITLBIB.HTM#moore96" "(Moore 1996)") (Moore97 "../JITLBIB.HTM#moore97" "(Moore 1997)") (Pflieger "../JITLBIB.HTM#pflieger" "(Pflieger 1961)") (Russell "../JITLBIB.HTM#russel" "(Russell 1997)") (Whittington "../JITLBIB.HTM#whittington" "(Whittington 1989)") (touretzky "musicbib.html#touretzky" "(Touretzky 1984)") (icmcfugue "http://www.cs.cmu.edu/~rbd/bib-arctic.html#icmcfugue" "(Dannenberg and Frayley 1989)"))) nyquist-3.05/docsrc/toafs.sh0000644000175000000620000000046511466723256015131 0ustar stevestaffscp nyquist/*.mss rbd@linux.gp.cs.cmu.edu:doc/man/nyquist scp nyquist/*.ps rbd@linux.gp.cs.cmu.edu:doc/man/nyquist scp bib/music.bib rbd@linux.gp.cs.cmu.edu:doc/man/bib/music.bib scp template/filcap.mss rbd@linux.gp.cs.cmu.edu:doc/man/template/filcap.mss scp xlisp/*.mss rbd@linux.gp.cs.cmu.edu:doc/man/xlisp nyquist-3.05/docsrc/xlisp/0002755000175000000620000000000011537433126014606 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp.mss0000644000175000000620000044146511524074337016506 0ustar stevestaff@define(codef, FaceCode T, size 11) @comment{In my original scribe conversion of the ascii xlisp documentation, I used times roman fonts for xlisp function names and code text in general. To be consistent with Nyquist documentation, I have changed the code font to xlcode which is defined here. If this turns out to be a problem, redefine xlcode to use the regular FaceCode. -RBD} @define(xlcode, FaceCode T, size 11) @textform(pragma=[]) @section(Introduction) XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers. Implementations of XLISP run on virtually every operating system. XLISP is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users. Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects Object and Class as primitives. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances (it is the only object that is an instance of itself). This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming. I recommend the book @i(Lisp) by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp. You will probably also need a copy of @i(Common Lisp: The Language) by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document. @section(A Note From The Author) If you have any problems with XLISP, feel free to contact me [me being David Betz - RBD] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users [e.g. that Dannenberg fellow - RBD] have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me. If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it. Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However, PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!! I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run. @section(XLISP Command Loop)@index(XLISP Command Loop)@index(Command Loop) When XLISP is started, it first tries to load the workspace @code(xlisp.wks) from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols. Then XLISP attempts to load @code(init.lsp) from the current directory. It then loads any files named as parameters on the command line (after appending @code(.lsp) to their names). XLISP then issues the following prompt: @begin(example) > @end(example) This indicates that XLISP is waiting for an expression to be typed. When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed. @section(Special Characters)@index(control characters, XLISP) When XLISP is running from a console, some control characters invoke operations: @begin(itemize) Backspace and Delete characters erase the previous character on the input line (if any). Control-U erases the entire input line. Control-C executes the TOP-LEVEL function. Control-G executes the CLEAN-UP function. Control-P executes the CONTINUE function. Control-B stops execution and enters the break command loop. Execution can be continued by typing Control-P or (CONTINUE). Control-E turns on character echoing (Linux and Mac OS X only). Control-F turns off character echoing (Linux and Mac OS X only). Control-T evaluates the INFO function. @end(itemize) @section(Break Command Loop)@index(break) When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way: If the symbol @xlcode(*breakenable*@index(*breakenable*)) is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed. If the symbol @xlcode(*tracenable*@index(*tracenable*)) is true, a trace back is printed. The number of entries printed depends on the value of the symbol @xlcode(*tracelimit*@index(*tracelimit*)). If this symbol is set to something other than a number, the entire trace back stack is printed. XLISP then enters a read/eval/print loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level read/eval/print loop in that if the user invokes the function @xlcode(continue), XLISP will continue from a correctable error. If the user invokes the function @xlcode(clean-up), XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt. If the symbol @xlcode(*breakenable*@index(*breakenable*)) is @xlcode(nil), XLISP looks for a surrounding errset function. If one is found, XLISP examines the value of the print flag. If this flag is true, the error message is printed. In any case, XLISP causes the errset function call to return @xlcode(nil). If there is no surrounding errset function, XLISP prints the error message and returns to the top level. @section(Data Types)@index(XLISP Data Types)@index(Data Types) There are several different data types available to XLISP programmers. @begin(itemize) lists symbols strings integers characters floats objects arrays streams subrs (built-in functions) fsubrs (special forms) closures (user defined functions) @end(itemize) @section(The Evaluator)@index(evaluator)@index(XLISP evaluator) The process of evaluation in XLISP: @begin(itemize) Strings, integers, characters, floats, objects, arrays, streams, subrs, fsubrs and closures evaluate to themselves. Symbols act as variables and are evaluated by retrieving the value associated with their current binding. Lists are evaluated by examining the first element of the list and then taking one of the following actions: @begin(itemize) If it is a symbol, the functional binding of the symbol is retrieved. If it is a lambda expression, a closure is constructed for the function described by the lambda expression. If it is a subr, fsubr or closure, it stands for itself. Any other value is an error. @end(itemize) Then, the value produced by the previous step is examined: @begin(itemize) If it is a subr or closure, the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments. If it is an fsubr, the fsubr is called using the remaining list elements as arguments (unevaluated). If it is a macro, the macro is expanded using the remaining list elements as arguments (unevaluated). The macro expansion is then evaluated in place of the original macro call. @end(itemize) @end(itemize) @section(Lexical Conventions)@index(Lexical conventions)@index(XLISP Lexical Conventions) The following conventions must be followed when entering XLISP programs: Comments in XLISP code begin with a semi-colon character and continue to the end of the line. Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following: @begin(example) ( ) ' ` , " ; @end(example) Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input. Integer literals consist of a sequence of digits optionally beginning with a @code(+) or @code(-). The range of values an integer can represent is limited by the size of a C @code(long) on the machine on which XLISP is running. Floating point literals consist of a sequence of digits optionally beginning with a @code(+) or @code(-) and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C @code(float) (@code(double) on machines with 32 bit addresses) on the machine on which XLISP is running. Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the ``@code(\)'' character is used to allow non-printable characters to be included. The codes recognized are: @begin(itemize) @code(\\) means the character ``@code(\)'' @code(\n) means newline @code(\t) means tab @code(\r) means return @code(\f) means form feed @code(\nnn) means the character whose octal code is nnn @end(itemize) @section(Readtables)@index(Readtables) The behavior of the reader is controlled by a data structure called a @i(readtable). The reader uses the symbol @xlcode(*readtable*@index(*readtable*)) to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things: @begin(itemize) @xlcode(NIL) @itemsep Indicating an invalid character @xlcode(:CONSTITUENT) @itemsep Indicating a symbol constituent @xlcode(:WHITE-SPACE) @itemsep Indicating a whitespace character @xlcode[(:TMACRO . @i(fun))] @itemsep Terminating readmacro @xlcode[(:NMACRO . @i(fun))] @itemsep Non-terminating readmacro @xlcode(:SESCAPE) @itemsep Single escape character ('\') @xlcode(:MESCAPE) @itemsep Multiple escape character ('|') @end(itemize) In the case of @xlcode(:TMACRO) and @xlcode(:NMACRO), the @i(fun) component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return @xlcode(NIL) to indicate that the character should be treated as white space or a value consed with @xlcode(NIL) to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream. XLISP defines several useful read macros@index(read macros): @begin(itemize) @xlcode(')@i[] == @xlcode{(quote} @i[]@xlcode{)} @xlcode(#')@i[] == @xlcode{(function} @i[]@xlcode{)} @xlcode{#(}@i[]...@xlcode{)} == an array of the specified expressions @xlcode(#x)@i[] == a hexadecimal number (0-9,A-F) @xlcode(#o)@i[] == an octal number (0-7) @xlcode(#b)@i[] == a binary number (0-1) @xlcode(#\)@i[] == the ASCII code of the character @xlcode(#|) ... @xlcode(|#) == a comment @xlcode(#:)@i[] == an uninterned symbol @xlcode(`)@i[] == @xlcode{(backquote} @i[]@xlcode{)} @xlcode(,)@i[] == @xlcode{(comma} @i[]@xlcode{)} @xlcode(,@@)@i[] == @xlcode{(comma-at} @i[]@xlcode{)} @end(itemize) @section(Lambda Lists)@index(Lambda Lists) There are several forms in XLISP that require that a ``lambda list'' be specified. A lambda list is a definition of the arguments accepted by a function. There are four different types of arguments. The lambda list starts with required arguments. Required arguments must be specified in every call to the function. The required arguments are followed by the @xlcode(&optional) arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an @xlcode(&optional) argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to @xlcode(NIL). It is also possible to provide the name of a @xlcode(supplied-p) variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the supplied- p variable will be bound to T if a value was specified in the call and @xlcode(NIL) if the default value was used. The @xlcode(&optional) arguments are followed by the @xlcode(&rest) argument. The @xlcode(&rest) argument gets bound to the remainder of the argument list after the required and @xlcode(&optional) arguments have been removed. The @xlcode(&rest) argument is followed by the @xlcode(&key) arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol (a symbol that begins with a ``@code(:)''). The value of the second expression is the value of the keyword argument. Like @xlcode(&optional) arguments, @xlcode(&key) arguments can have initialization expressions and supplied-p variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a ``@code(:)'' to the beginning of the keyword argument symbol is used. In other words, if the keyword argument symbol is @xlcode(foo), the keyword will be @xlcode(:foo). The @xlcode(&key) arguments are followed by the @xlcode(&aux) variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the @xlcode(&aux) variables. Here is the complete syntax for lambda lists: @begin(display) (@i... [@xlcode(&optional) [@i | (@i [@i [@i]])]...] [@xlcode(&rest) @i] [@xlcode(&key) [@i | ([@i | (@i @i)] [@i [@i]])]... @xlcode(&allow)-other-keys] [@xlcode(&aux) [@i | (@i [@i])]...]) where: @i is a required argument symbol @i is an @xlcode(&optional) argument symbol @i is the @xlcode(&rest) argument symbol @i is a @xlcode(&key) argument symbol @i is a keyword symbol @i is an auxiliary variable symbol @i is an initialization expression @i is a supplied-p variable symbol @end(display) @section(Objects)@index(Objects)@label(objects-sec) Definitions: @begin(itemize) selector @itemsep a symbol used to select an appropriate method message @itemsep a selector and a list of actual arguments method @itemsep the code that implements a message @end(itemize) Since XLISP was created to provide a simple basis for experimenting with object-oriented programming, one of the primitive data types included is @i(object). In XLISP, an object consists of a data structure containing a pointer to the object's class as well as an array containing the values of the object's instance variables. Officially, there is no way to see inside an object (look at the values of its instance variables). The only way to communicate with an object is by sending it a message. You can send a message to an object using the @xlcode(send) function. This function takes the object as its first argument, the message selector as its second argument (which must be a symbol) and the message arguments as its remaining arguments. The @xlcode(send) function determines the class of the receiving object and attempts to find a method corresponding to the message selector in the set of messages defined for that class. If the message is not found in the object's class and the class has a super-class, the search continues by looking at the messages defined for the super-class. This process continues from one super-class to the next until a method for the message is found. If no method is found, an error occurs. @begin(comment) THIS IS WRONG -- I DON'T KNOW IF IT WAS CORRECT IN THE ORIGINAL XLISP. -RBD A message can also be sent from the body of a method by using the current object, but the method lookup starts with the object's superclass rather than its class. This allows a subclass to invoke a standard method in its parent class even though it overrides that method with its own specialized version. @end(comment) When a method is found, the evaluator binds the receiving object to the symbol @xlcode(self) and evaluates the method using the remaining elements of the original list as arguments to the method. These arguments are always evaluated prior to being bound to their corresponding formal arguments. The result of evaluating the method becomes the result of the expression. Within the body of a method, a message can be sent to the current object by calling the @xlcode[(send self ...)]. The method lookup starts with the object's class regardless of the class containing the current method. Sometimes it is desirable to invoke a general method in a superclass even when it is overridden by a more specific method in a subclass. This can be accomplished by calling @xlcode(send-super), which begins the method lookup in the superclass of the class defining the current method rather than in the class of the current object. The @xlcode(send-super) function takes a selector as its first argument (which must be a symbol) and the message arguments as its remaining arguments. Notice that @xlcode(send-super) can only be sent from within a method, and the target of the message is always the current object (@xlcode(self)). @xlcode[(send-super ...)] is similar to @xlcode[(send self ...)] except that method lookup begins in the superclass of the class containing the current method rather than the class of the current object. @section(The ``Object'' Class)@index(Object Class) @xlcode(Object)@index(Object) @itemsep the top of the class hierarchy. Messages: @begin(fdescription) @xlcode(:show@index(:show)) @itemsep show an object's instance variables. @begin(pdescription) returns @itemsep the object @end(pdescription) @blankspace(1) @xlcode{:class@index(:class)} @itemsep return the class of an object @begin(pdescription) returns @itemsep the class of the object @end(pdescription) @blankspace(1) @xlcode{:isa@index(:isa)} @i(class) @itemsep test if object inherits from class @begin(pdescription) returns @itemsep @xlcode(t) if object is an instance of @i(class) or a subclass of @i(class), otherwise @xlcode(nil) @end(pdescription) @blankspace(1) @xlcode(:isnew@index(:isnew)) @itemsep the default object initialization routine @begin(pdescription) returns @itemsep the object @end(pdescription) @end(fdescription) @section(The ``Class'' Class)@index(Class class) @xlcode(Class@index(Class)) @itemsep class of all object classes (including itself) Messages: @begin(fdescription) @xlcode(:new@index(:new)) @itemsep create a new instance of a class @begin(pdescription) returns @itemsep the new class object @end(pdescription) @blankspace(1) @xlcode(:isnew@index(:isnew)) @i [@i [@i]] @itemsep initialize a new class @begin(pdescription) @i @itemsep the list of instance variable symbols @i @itemsep the list of class variable symbols @i @itemsep the superclass (default is object) returns @itemsep the new class object @end(pdescription) @blankspace(1) @xlcode(:answer@index(:answer)) @i @i @i @itemsep add a message to a class @begin(pdescription) @i @itemsep the message symbol @i @itemsep the formal argument list (lambda list) @i @itemsep a list of executable expressions returns @itemsep the object @end(pdescription) @blankspace(1) @end(fdescription) When a new instance of a class is created by sending the message @xlcode(:new) to an existing class, the message @xlcode(:isnew) followed by whatever parameters were passed to the @xlcode(:new) message is sent to the newly created object. When a new class is created by sending the @xlcode(:new) message to the object @xlcode(Class), an optional parameter may be specified indicating the superclass of the new class. If this parameter is omitted, the new class will be a subclass of @xlcode(Object). A class inherits all instance variables, class variables, and methods from its super-class. @section(Profiling)@index(profiling) The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where @xlcode(eval) is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an @xlcode(eval) in the immediately (lexically) enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls. The list of all functions executed is maintained on the global @xlcode(*profile*) variable. These functions in turn have @xlcode(*profile*) properties, which maintain the counts. The profile system merely increments counters and puts symbols on the @xlcode(*profile*) list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the @xlcode(profile) function. Unfortunately, methods cannot be profiled with this facility. @label(symbols-sec) @section(Symbols)@index(symbols) @begin(itemize) @codef(self)@pragma(defn)@index(self) @dash the current object (within a method context) @codef(*obarray*@pragma(defn)@index(*obarray*)) @dash the object hash table @codef(*standard-input*@pragma(defn)@index(*standard-input*)) @dash the standard input stream @codef(*standard-output*@pragma(defn)@index(*standard-output*)) @dash the standard output stream @codef(*error-output*@pragma(defn)@index(*error-output*)) @dash the error output stream @codef(*trace-output*@pragma(defn)@index(*trace-output*)) @dash the trace output stream @codef(*debug-io*@pragma(defn)@index(*debug-io*)) @dash the debug i/o stream @codef(*breakenable*@pragma(defn)@index(*breakenable*)) @dash flag controlling entering break loop on errors @codef(*tracelist*@pragma(defn)@index(*tracelist*)) @dash list of names of functions to trace @codef(*tracenable*@pragma(defn)@index(*tracenable*)) @dash enable trace back printout on errors @codef(*tracelimit*@pragma(defn)@index(*tracelimit*)) @dash number of levels of trace back information @codef(*evalhook*@pragma(defn)@index(*evalhook*)) @dash user substitute for the evaluator function @codef(*applyhook*@pragma(defn)@index(*applyhook*)) @dash (not yet implemented) @codef(*readtable*@pragma(defn)@index(*readtable*)) @dash the current readtable @codef(*unbound*@pragma(defn)@index(*unbound*)) @dash indicator for unbound symbols @codef(*gc-flag*@pragma(defn)@index(*gc-flag*)) @dash controls the printing of gc messages @codef(*gc-hook*@pragma(defn)@index(*gc-hook*)) @dash function to call after garbage collection @codef(*integer-format*@pragma(defn)@index(*integer-format*)) @dash format for printing integers (``%d'' or ``%ld'') @codef(*float-format*@pragma(defn)@index(*float-format*)) @dash format for printing floats (``%g'') @codef(*print-case*@pragma(defn)@index(*print-case*)) @dash symbol output case (:upcase or :downcase) @end(itemize) There are several symbols maintained by the read/eval/print loop. The symbols @code(+), @code(++), and @code(+++) are bound to the most recent three input expressions. The symbols @code(*), @code(**) and @code(***) are bound to the most recent three results. The symbol @code(-) is bound to the expression currently being evaluated. It becomes the value of @code(+) at the end of the evaluation. @section(Evaluation Functions)@index(evaluation functions) @begin(fdescription) @begin(fgroup)@xlcode{eval(@i(expr))} @c{[sal]} @xlcode{(eval@pragma(defn)@index(eval) @t(@i(expr)))} @c{[lisp]} @itemsep evaluate an xlisp expression @end(fgroup) @begin(pdescription) @i @itemsep the expression to be evaluated returns @itemsep the result of evaluating the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{apply(@i(fun), @i(args))} @c{[sal]} @xlcode{(apply@pragma(defn)@index(apply) @t(@i(fun)) @t(@i(args)))} @c{[lisp]} @itemsep apply a function to a list of arguments @end(fgroup) @begin(pdescription) @i @itemsep the function to apply (or function symbol) @i @itemsep the argument list returns @itemsep the result of applying the function to the arguments @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{funcall(@i(fun), @i(arg)@r(...))} @c{[sal]} @xlcode{(funcall@pragma(defn)@index(funcall) @t(@i(fun)) @t(@i(arg))@r(...))} @c{[lisp]} @itemsep call a function with arguments @end(fgroup) @begin(pdescription) @i @itemsep the function to call (or function symbol) @i @itemsep arguments to pass to the function returns @itemsep the result of calling the function with the arguments @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{quote(@i(expr))} @c{[sal]} @xlcode{(quote@pragma(defn)@index(quote) @t(@i(expr)))} @c{[lisp]} @itemsep return an expression unevaluated @end(fgroup) @begin(pdescription) @i @itemsep the expression to be quoted (quoted) returns @itemsep @i unevaluated @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{function(@i(expr))} @c{[sal]} @xlcode{(function@pragma(defn)@index(function) @t(@i(expr)))} @c{[lisp]} @itemsep get the functional interpretation @end(fgroup) @begin(pdescription) @i @itemsep the symbol or lambda expression (quoted) returns @itemsep the functional interpretation @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{backquote(@i(expr))} @c{[sal]} @xlcode{(backquote@pragma(defn)@index(backquote) @t(@i(expr)))} @c{[lisp]} @itemsep fill in a template @end(fgroup) @begin(pdescription) @i @itemsep the template returns @itemsep a copy of the template with comma and comma-at expressions expanded @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{lambda(@i(args), @i(expr)@r(...))} @c{[sal]} @xlcode{(lambda@pragma(defn)@index(lambda) @t(@i(args)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep make a function closure @end(fgroup) @begin(pdescription) @i @itemsep formal argument list (lambda list) (quoted) @i @itemsep expressions of the function body returns @itemsep the function closure @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{get-lambda-expression(@i(closure))} @c{[sal]} @xlcode{(get-lambda-expression@pragma(defn)@index(get-lambda-expression) @t(@i(closure)))} @c{[lisp]} @itemsep get the lambda expression @end(fgroup) @begin(pdescription) @i @itemsep the closure returns @itemsep the original lambda expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{macroexpand(@i(form))} @c{[sal]} @xlcode{(macroexpand@pragma(defn)@index(macroexpand) @t(@i(form)))} @c{[lisp]} @itemsep recursively expand macro calls @end(fgroup) @begin(pdescription) @i
    @itemsep the form to expand returns @itemsep the macro expansion @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{macroexpand-1(@i(form))} @c{[sal]} @xlcode{(macroexpand-1@pragma(defn)@index(macroexpand-1) @t(@i(form)))} @c{[lisp]} @itemsep expand a macro call @end(fgroup) @begin(pdescription) @i @itemsep the macro call form returns @itemsep the macro expansion @end(pdescription) @blankspace(1) @end(fdescription) @section(Symbol Functions)@index(Symbol Functions) @begin(fdescription) @begin(fgroup)@xlcode{set(@i(sym), @i(expr))} @c{[sal]} @xlcode{(set@pragma(defn)@index(set) @t(@i(sym)) @t(@i(expr)))} @c{[lisp]} @itemsep set the value of a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol being set @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{setq([@i(sym), @i(expr)]@r(...))} @c{[sal]} @xlcode{(setq@pragma(defn)@index(setq) [@t(@i(sym)) @t(@i(expr))]@r(...))} @c{[lisp]} @itemsep set the value of a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol being set (quoted) @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{psetq([@i(sym), @i(expr)]@r(...))} @c{[sal]} @xlcode{(psetq@pragma(defn)@index(psetq) [@t(@i(sym)) @t(@i(expr))]@r(...))} @c{[lisp]} @itemsep parallel version of setq @end(fgroup) @begin(pdescription) @i @itemsep the symbol being set (quoted) @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{setf([@i(place), @i(expr)]@r(...))} @c{[sal]} @xlcode{(setf@pragma(defn)@index(setf) [@t(@i(place)) @t(@i(expr))]@r(...))} @c{[lisp]} @itemsep set the value of a field @end(fgroup) @begin(pdescription) @i @itemsep the field specifier (quoted): @begin(pdescription) @i @itemsep set value of a symbol (car @i) @itemsep set car of a cons node (cdr @i) @itemsep set cdr of a cons node (nth @i @i) @itemsep set nth car of a list (aref @i @i) @itemsep set nth element of an array (get @i @i) @itemsep set value of a property (symbol-value @i) @itemsep set value of a symbol (symbol-function @i) @itemsep set functional value of a symbol (symbol-plist @i) @itemsep set property list of a symbol @end(pdescription)@pragma(stopcodef) @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) @begin(fgroup) @xlcode{(defun@pragma(defn)@index(defun) @t(@i(sym)) @t(@i(fargs)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep define a function @pragma(startcodef) @xlcode{(defmacro@pragma(defn)@index(defmacro) @t(@i(sym)) @t(@i(fargs)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep define a macro @end(fgroup) @begin(pdescription) @i @itemsep symbol being defined (quoted) @i @itemsep formal argument list (lambda list) (quoted) @i @itemsep expressions constituting the body of the function (quoted) returns @itemsep the function symbol @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{gensym([@i(tag)])} @c{[sal]} @xlcode{(gensym@pragma(defn)@index(gensym) [@t(@i(tag))])} @c{[lisp]} @itemsep generate a symbol @end(fgroup) @begin(pdescription) @i @itemsep string or number returns @itemsep the new symbol @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{intern(@i(pname))} @c{[sal]} @xlcode{(intern@pragma(defn)@index(intern) @t(@i(pname)))} @c{[lisp]} @itemsep make an interned symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol's print name string returns @itemsep the new symbol @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{make-symbol(@i(pname))} @c{[sal]} @xlcode{(make-symbol@pragma(defn)@index(make-symbol) @t(@i(pname)))} @c{[lisp]} @itemsep make an uninterned symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol's print name string returns @itemsep the new symbol @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{symbol-name(@i(sym))} @c{[sal]} @xlcode{(symbol-name@pragma(defn)@index(symbol-name) @t(@i(sym)))} @c{[lisp]} @itemsep get the print name of a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's print name @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{symbol-value(@i(sym))} @c{[sal]} @xlcode{(symbol-value@pragma(defn)@index(symbol-value) @t(@i(sym)))} @c{[lisp]} @itemsep get the value of a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{symbol-function(@i(sym))} @c{[sal]} @xlcode{(symbol-function@pragma(defn)@index(symbol-function) @t(@i(sym)))} @c{[lisp]} @itemsep get the functional value of a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's functional value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{symbol-plist(@i(sym))} @c{[sal]} @xlcode{(symbol-plist@pragma(defn)@index(symbol-plist) @t(@i(sym)))} @c{[lisp]} @itemsep get the property list of a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's property list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{hash(@i(sym), @i(n))} @c{[sal]} @xlcode{(hash@pragma(defn)@index(hash) @t(@i(sym)) @t(@i(n)))} @c{[lisp]} @itemsep compute the hash index for a symbol @end(fgroup) @begin(pdescription) @i @itemsep the symbol or string @i @itemsep the table size (integer) returns @itemsep the hash index (integer) @end(pdescription) @blankspace(1) @end(fdescription) @section(Property List Functions)@index(Property List Functions) @begin(fdescription) @begin(fgroup)@xlcode{get(@i(sym), @i(prop))} @c{[sal]} @xlcode{(get@pragma(defn)@index(get) @t(@i(sym)) @t(@i(prop)))} @c{[lisp]} @itemsep get the value of a property @end(fgroup) @begin(pdescription) @i @itemsep the symbol @i @itemsep the property symbol returns @itemsep the property value or @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{putprop(@i(sym), @i(val), @i(prop))} @c{[sal]} @xlcode{(putprop@pragma(defn)@index(putprop) @t(@i(sym)) @t(@i(val)) @t(@i(prop)))} @c{[lisp]} @itemsep put a property onto a property list @end(fgroup) @begin(pdescription) @i @itemsep the symbol @i @itemsep the property value @i @itemsep the property symbol returns @itemsep the property value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{remprop(@i(sym), @i(prop))} @c{[sal]} @xlcode{(remprop@pragma(defn)@index(remprop) @t(@i(sym)) @t(@i(prop)))} @c{[lisp]} @itemsep remove a property @end(fgroup) @begin(pdescription) @i @itemsep the symbol @i @itemsep the property symbol returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @end(fdescription) @section(Array Functions)@index(Array Functions) @begin(fdescription) @begin(fgroup)@xlcode{aref(@i(array), @i(n))} @c{[sal]} @xlcode{(aref@pragma(defn)@index(aref) @t(@i(array)) @t(@i(n)))} @c{[lisp]} @itemsep get the nth element of an array @end(fgroup) @begin(pdescription) @i @itemsep the array @i @itemsep the array index (integer) returns @itemsep the value of the array element @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{make-array(@i(size))} @c{[sal]} @xlcode{(make-array@pragma(defn)@index(make-array) @t(@i(size)))} @c{[lisp]} @itemsep make a new array @end(fgroup) @begin(pdescription) @i @itemsep the size of the new array (integer) returns @itemsep the new array @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{vector(@i(expr)@r(...))} @c{[sal]} @xlcode{(vector@pragma(defn)@index(vector) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep make an initialized vector @end(fgroup) @begin(pdescription) @i @itemsep the vector elements returns @itemsep the new vector @end(pdescription) @blankspace(1) @end(fdescription) @section(List Functions)@index(List Functions) @begin(fdescription) @begin(fgroup)@xlcode{car(@i(expr))} @c{[sal]} @xlcode{(car@pragma(defn)@index(car) @t(@i(expr)))} @c{[lisp]} @itemsep return the car of a list node @end(fgroup) @begin(pdescription) @i @itemsep the list node returns @itemsep the car of the list node @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{cdr(@i(expr))} @c{[sal]} @xlcode{(cdr@pragma(defn)@index(cdr) @t(@i(expr)))} @c{[lisp]} @itemsep return the cdr of a list node @end(fgroup) @begin(pdescription) @i @itemsep the list node returns @itemsep the cdr of the list node @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{c@i(xx)r(@i(expr))} @c{[sal]} @xlcode{(c@i(xx)r@index(cxxr) @t(@i(expr)))} @c{[lisp]} @itemsep all c@i(xx)r combinations @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{c@i(xxx)r(@i(expr))} @c{[sal]} @xlcode{(c@i(xxx)r@index(cxxxr) @t(@i(expr)))} @c{[lisp]} @itemsep all c@i(xxx)r combinations @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{c@i(xxxx)r(@i(expr))} @c{[sal]} @xlcode{(c@i(xxxx)r@index(cxxxxr) @t(@i(expr)))} @c{[lisp]} @itemsep all c@i(xxxx)r combinations @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{first(@i(expr))} @c{[sal]} @xlcode{(first@pragma(defn)@index(first) @t(@i(expr)))} @c{[lisp]} @itemsep a synonym for car @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{second(@i(expr))} @c{[sal]} @xlcode{(second@pragma(defn)@index(second) @t(@i(expr)))} @c{[lisp]} @itemsep a synonym for cadr @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{third(@i(expr))} @c{[sal]} @xlcode{(third@pragma(defn)@index(third) @t(@i(expr)))} @c{[lisp]} @itemsep a synonym for caddr @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{fourth(@i(expr))} @c{[sal]} @xlcode{(fourth@pragma(defn)@index(fourth) @t(@i(expr)))} @c{[lisp]} @itemsep a synonym for cadddr @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{rest(@i(expr))} @c{[sal]} @xlcode{(rest@pragma(defn)@index(rest) @t(@i(expr)))} @c{[lisp]} @itemsep a synonym for cdr @end(fgroup) @begin(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{cons(@i(expr1), @i(expr2))} @c{[sal]} @xlcode{(cons@pragma(defn)@index(cons) @t(@i(expr1)) @t(@i(expr2)))} @c{[lisp]} @itemsep construct a new list node @end(fgroup) @begin(pdescription) @i @itemsep the car of the new list node @i @itemsep the cdr of the new list node returns @itemsep the new list node @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{list(@i(expr)@r(...))} @c{[sal]} @xlcode{(list@pragma(defn)@index(list) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep create a list of values @end(fgroup) @begin(pdescription) @i @itemsep expressions to be combined into a list returns @itemsep the new list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{append(@i(expr)@r(...))} @c{[sal]} @xlcode{(append@pragma(defn)@index(append) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep append lists @end(fgroup) @begin(pdescription) @i @itemsep lists whose elements are to be appended returns @itemsep the new list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{reverse(@i(expr))} @c{[sal]} @xlcode{(reverse@pragma(defn)@index(reverse) @t(@i(expr)))} @c{[lisp]} @itemsep reverse a list @end(fgroup) @begin(pdescription) @i @itemsep the list to reverse returns @itemsep a new list in the reverse order @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{last(@i(list))} @c{[sal]} @xlcode{(last@pragma(defn)@index(last) @t(@i(list)))} @c{[lisp]} @itemsep return the last list node of a list @end(fgroup) @begin(pdescription) @i @itemsep the list returns @itemsep the last list node in the list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{member(@i(expr), @i(list), test: @i(test), test-not: @i(test-not))} @c{[sal]} @xlcode{(member@pragma(defn)@index(member) @t(@i(expr)) @t(@i(list)) @t(&key )@t(:test) @t(:test-not))} @c{[lisp]} @itemsep find an expression in a list @end(fgroup) @begin(pdescription) @i @itemsep the expression to find @i @itemsep the list to search :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the remainder of the list starting with the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{assoc(@i(expr), @i(alist), test: @i(test), test-not: @i(test-not))} @c{[sal]} @xlcode{(assoc@pragma(defn)@index(assoc) @t(@i(expr)) @t(@i(alist)) @t(&key )@t(:test) @t(:test-not))} @c{[lisp]} @itemsep find an expression in an a-list @end(fgroup) @begin(pdescription) @i @itemsep the expression to find @i @itemsep the association list :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the alist entry or @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{remove(@i(expr), @i(list), test: @i(test), test-not: @i(test-not))} @c{[sal]} @xlcode{(remove@pragma(defn)@index(remove) @t(@i(expr)) @t(@i(list)) @t(&key )@t(:test) @t(:test-not))} @c{[lisp]} @itemsep remove elements from a list @end(fgroup) @begin(pdescription) @i @itemsep the element to remove @i @itemsep the list :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep copy of list with matching expressions removed @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{remove-if(@i(test), @i(list))} @c{[sal]} @xlcode{(remove-if@pragma(defn)@index(remove-if) @t(@i(test)) @t(@i(list)))} @c{[lisp]} @itemsep remove elements that pass test @end(fgroup) @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep copy of list with matching elements removed @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{remove-if-not(@i(test), @i(list))} @c{[sal]} @xlcode{(remove-if-not@pragma(defn)@index(remove-if-not) @t(@i(test)) @t(@i(list)))} @c{[lisp]} @itemsep remove elements that fail test @end(fgroup) @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep copy of list with non-matching elements removed @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{length(@i(expr))} @c{[sal]} @xlcode{(length@pragma(defn)@index(length) @t(@i(expr)))} @c{[lisp]} @itemsep find the length of a list, vector or string @end(fgroup) @begin(pdescription) @i @itemsep the list, vector or string returns @itemsep the length of the list, vector or string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{nth(@i(n), @i(list))} @c{[sal]} @xlcode{(nth@pragma(defn)@index(nth) @t(@i(n)) @t(@i(list)))} @c{[lisp]} @itemsep return the nth element of a list @end(fgroup) @begin(pdescription) @i @itemsep the number of the element to return (zero origin) @i @itemsep the list returns @itemsep the nth element or @xlcode(nil) if the list isn't that long @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{nthcdr(@i(n), @i(list))} @c{[sal]} @xlcode{(nthcdr@pragma(defn)@index(nthcdr) @t(@i(n)) @t(@i(list)))} @c{[lisp]} @itemsep return the nth cdr of a list @end(fgroup) @begin(pdescription) @i @itemsep the number of the element to return (zero origin) @i @itemsep the list returns @itemsep the nth cdr or @xlcode(nil) if the list isn't that long @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{mapc(@i(fcn), @i(list1), @i(list)@r(...))} @c{[sal]} @xlcode{(mapc@pragma(defn)@index(mapc) @t(@i(fcn)) @t(@i(list1)) @t(@i(list))@r(...))} @c{[lisp]} @itemsep apply function to successive cars @end(fgroup) @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep the first list of arguments @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{mapcar(@i(fcn), @i(list1), @i(list)@r(...))} @c{[sal]} @xlcode{(mapcar@pragma(defn)@index(mapcar) @t(@i(fcn)) @t(@i(list1)) @t(@i(list))@r(...))} @c{[lisp]} @itemsep apply function to successive cars @end(fgroup) @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep a list of the values returned @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{mapl(@i(fcn), @i(list1), @i(list)@r(...))} @c{[sal]} @xlcode{(mapl@pragma(defn)@index(mapl) @t(@i(fcn)) @t(@i(list1)) @t(@i(list))@r(...))} @c{[lisp]} @itemsep apply function to successive cdrs @end(fgroup) @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep the first list of arguments @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{maplist(@i(fcn), @i(list1), @i(list)@r(...))} @c{[sal]} @xlcode{(maplist@pragma(defn)@index(maplist) @t(@i(fcn)) @t(@i(list1)) @t(@i(list))@r(...))} @c{[lisp]} @itemsep apply function to successive cdrs @end(fgroup) @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep a list of the values returned @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{subst(@i(to), @i(from), @i(expr), test: @i(test), test-not: @i(test-not))} @c{[sal]} @xlcode{(subst@pragma(defn)@index(subst) @t(@i(to)) @t(@i(from)) @t(@i(expr)) @t(&key )@t(:test) @t(:test-not))} @c{[lisp]} @itemsep substitute expressions @end(fgroup) @begin(pdescription) @i @itemsep the new expression @i @itemsep the old expression @i @itemsep the expression in which to do the substitutions :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the expression with substitutions @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{sublis(@i(alist), @i(expr), test: @i(test), test-not: @i(test-not))} @c{[sal]} @xlcode{(sublis@pragma(defn)@index(sublis) @t(@i(alist)) @t(@i(expr)) @t(&key )@t(:test) @t(:test-not))} @c{[lisp]} @itemsep substitute with an a-list @end(fgroup) @begin(pdescription) @i @itemsep the association list @i @itemsep the expression in which to do the substitutions :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the expression with substitutions @end(pdescription) @blankspace(1) @end(fdescription) @section(Destructive List Functions)@index(Destructive List Functions) @begin(fdescription) @begin(fgroup)@xlcode{rplaca(@i(list), @i(expr))} @c{[sal]} @xlcode{(rplaca@pragma(defn)@index(rplaca) @t(@i(list)) @t(@i(expr)))} @c{[lisp]} @itemsep replace the car of a list node @end(fgroup) @begin(pdescription) @i @itemsep the list node @i @itemsep the new value for the car of the list node returns @itemsep the list node after updating the car @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{rplacd(@i(list), @i(expr))} @c{[sal]} @xlcode{(rplacd@pragma(defn)@index(rplacd) @t(@i(list)) @t(@i(expr)))} @c{[lisp]} @itemsep replace the cdr of a list node @end(fgroup) @begin(pdescription) @i @itemsep the list node @i @itemsep the new value for the cdr of the list node returns @itemsep the list node after updating the cdr @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{nconc(@i(list)@r(...))} @c{[sal]} @xlcode{(nconc@pragma(defn)@index(nconc) @t(@i(list))@r(...))} @c{[lisp]} @itemsep destructively concatenate lists @end(fgroup) @begin(pdescription) @i @itemsep lists to concatenate returns @itemsep the result of concatenating the lists @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{delete(@i(expr), test: @i(test), test-not: @i(test-not))} @c{[sal]} @xlcode{(delete@pragma(defn)@index(delete) @t(@i(expr)) @t(&key )@t(:test) @t(:test-not))} @c{[lisp]} @itemsep delete elements from a list @end(fgroup) @begin(pdescription) @i @itemsep the element to delete @i @itemsep the list :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the list with the matching expressions deleted @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{delete-if(@i(test), @i(list))} @c{[sal]} @xlcode{(delete-if@pragma(defn)@index(delete-if) @t(@i(test)) @t(@i(list)))} @c{[lisp]} @itemsep delete elements that pass test @end(fgroup) @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep the list with matching elements deleted @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{delete-if-not(@i(test), @i(list))} @c{[sal]} @xlcode{(delete-if-not@pragma(defn)@index(delete-if-not) @t(@i(test)) @t(@i(list)))} @c{[lisp]} @itemsep delete elements that fail test @end(fgroup) @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep the list with non-matching elements deleted @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{sort(@i(list), @i(test))} @c{[sal]} @xlcode{(sort@pragma(defn)@index(sort) @t(@i(list)) @t(@i(test)))} @c{[lisp]} @itemsep sort a list @end(fgroup) @begin(pdescription) @i @itemsep the list to sort @i @itemsep the comparison function returns @itemsep the sorted list @end(pdescription) @blankspace(1) @end(fdescription) @section(Predicate Functions)@index(Predicate Functions) @begin(fdescription) @begin(fgroup)@xlcode{atom(@i(expr))} @c{[sal]} @xlcode{(atom@pragma(defn)@index(atom) @t(@i(expr)))} @c{[lisp]} @itemsep is this an atom? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an atom, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{symbolp(@i(expr))} @c{[sal]} @xlcode{(symbolp@pragma(defn)@index(symbolp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a symbol? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the expression is a symbol, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{numberp(@i(expr))} @c{[sal]} @xlcode{(numberp@pragma(defn)@index(numberp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a number? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the expression is a number, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{null(@i(expr))} @c{[sal]} @xlcode{(null@pragma(defn)@index(null) @t(@i(expr)))} @c{[lisp]} @itemsep is this an empty list? @end(fgroup) @begin(pdescription) @i @itemsep the list to check returns @itemsep @xlcode(t) if the list is empty, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{not(@i(expr))} @c{[sal]} @xlcode{(not@pragma(defn)@index(not) @t(@i(expr)))} @c{[lisp]} @itemsep is this false? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check return @itemsep @xlcode(t) if the value is @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{listp(@i(expr))} @c{[sal]} @xlcode{(listp@pragma(defn)@index(listp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a list? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a cons or @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{endp(@i(list))} @c{[sal]} @xlcode{(endp@pragma(defn)@index(endp) @t(@i(list)))} @c{[lisp]} @itemsep is this the end of a list @end(fgroup) @begin(pdescription) @i @itemsep the list returns @itemsep @xlcode(t) if the value is @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{consp(@i(expr))} @c{[sal]} @xlcode{(consp@pragma(defn)@index(consp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a non-empty list? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a cons, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{integerp(@i(expr))} @c{[sal]} @xlcode{(integerp@pragma(defn)@index(integerp) @t(@i(expr)))} @c{[lisp]} @itemsep is this an integer? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an integer, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{floatp(@i(expr))} @c{[sal]} @xlcode{(floatp@pragma(defn)@index(floatp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a float? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a float, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{stringp(@i(expr))} @c{[sal]} @xlcode{(stringp@pragma(defn)@index(stringp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a string? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a string, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{characterp(@i(expr))} @c{[sal]} @xlcode{(characterp@pragma(defn)@index(characterp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a character? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a character, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{arrayp(@i(expr))} @c{[sal]} @xlcode{(arrayp@pragma(defn)@index(arrayp) @t(@i(expr)))} @c{[lisp]} @itemsep is this an array? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an array, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{streamp(@i(expr))} @c{[sal]} @xlcode{(streamp@pragma(defn)@index(streamp) @t(@i(expr)))} @c{[lisp]} @itemsep is this a stream? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a stream, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{objectp(@i(expr))} @c{[sal]} @xlcode{(objectp@pragma(defn)@index(objectp) @t(@i(expr)))} @c{[lisp]} @itemsep is this an object? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an object, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{filep(@i(expr))} @c{[sal]} @xlcode{(filep@pragma(defn)@index(filep) @t(@i(expr)))} @c{[lisp]}@foot(This is not part of standard XLISP nor is it built-in. Nyquist defines it though.) @itemsep is this a file? @end(fgroup) @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an object, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{boundp(@i(sym))} @c{[sal]} @xlcode{(boundp@pragma(defn)@index(boundp) @t(@i(sym)))} @c{[lisp]} @itemsep is a value bound to this symbol? @end(fgroup) @begin(pdescription) @i @itemsep the symbol returns @itemsep @xlcode(t) if a value is bound to the symbol, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{fboundp(@i(sym))} @c{[sal]} @xlcode{(fboundp@pragma(defn)@index(fboundp) @t(@i(sym)))} @c{[lisp]} @itemsep is a functional value bound to this symbol? @end(fgroup) @begin(pdescription) @i @itemsep the symbol returns @itemsep @xlcode(t) if a functional value is bound to the symbol, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{minusp(@i(expr))} @c{[sal]} @xlcode{(minusp@pragma(defn)@index(minusp) @t(@i(expr)))} @c{[lisp]} @itemsep is this number negative? @end(fgroup) @begin(pdescription) @i @itemsep the number to test returns @itemsep @xlcode(t) if the number is negative, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{zerop(@i(expr))} @c{[sal]} @xlcode{(zerop@pragma(defn)@index(zerop) @t(@i(expr)))} @c{[lisp]} @itemsep is this number zero? @end(fgroup) @begin(pdescription) @i @itemsep the number to test returns @itemsep @xlcode(t) if the number is zero, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{plusp(@i(expr))} @c{[sal]} @xlcode{(plusp@pragma(defn)@index(plusp) @t(@i(expr)))} @c{[lisp]} @itemsep is this number positive? @end(fgroup) @begin(pdescription) @i @itemsep the number to test returns @itemsep @xlcode(t) if the number is positive, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{evenp(@i(expr))} @c{[sal]} @xlcode{(evenp@pragma(defn)@index(evenp) @t(@i(expr)))} @c{[lisp]} @itemsep is this integer even? @end(fgroup) @begin(pdescription) @i @itemsep the integer to test returns @itemsep @xlcode(t) if the integer is even, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{oddp(@i(expr))} @c{[sal]} @xlcode{(oddp@pragma(defn)@index(oddp) @t(@i(expr)))} @c{[lisp]} @itemsep is this integer odd? @end(fgroup) @begin(pdescription) @i @itemsep the integer to test returns @itemsep @xlcode(t) if the integer is odd, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{eq(@i(expr1), @i(expr2))} @c{[sal]} @xlcode{(eq@pragma(defn)@index(eq) @t(@i(expr1)) @t(@i(expr2)))} @c{[lisp]} @itemsep are the expressions identical? @end(fgroup) @begin(pdescription) @i @itemsep the first expression @i @itemsep the second expression returns @itemsep @xlcode(t) if they are equal, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{eql(@i(expr1), @i(expr2))} @c{[sal]} @xlcode{(eql@pragma(defn)@index(eql) @t(@i(expr1)) @t(@i(expr2)))} @c{[lisp]} @itemsep are the expressions identical? (works with all numbers) @end(fgroup) @begin(pdescription) @i @itemsep the first expression @i @itemsep the second expression returns @itemsep @xlcode(t) if they are equal, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{equal(@i(expr1), @i(expr2))} @c{[sal]} @xlcode{(equal@pragma(defn)@index(equal) @t(@i(expr1)) @t(@i(expr2)))} @c{[lisp]} @itemsep are the expressions equal? @end(fgroup) @begin(pdescription) @i @itemsep the first expression @i @itemsep the second expression returns @itemsep @xlcode(t) if they are equal, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @end(fdescription) @section(Control Constructs)@index(Control Constructs) @begin(fdescription) @xlcode{(cond@pragma(defn)@index(cond) @t(@i(pair))@r(...))} @c{[lisp]} @itemsep evaluate conditionally @begin(pdescription) @i @itemsep pair consisting of: @begin(pdescription) (@i @i...) @end(pdescription)@pragma(stopcodef) where: @begin(pdescription) @i @itemsep is a predicate expression @i @itemsep evaluated if the predicate is not @xlcode(nil) @end(pdescription)@pragma(stopcodef) returns @itemsep the value of the first expression whose predicate is not @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{and(@i(expr)@r(...))} @c{[sal]} @xlcode{(and@pragma(defn)@index(and) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the logical and of a list of expressions @end(fgroup) @begin(pdescription) @i @itemsep the expressions to be anded returns @itemsep @xlcode(nil) if any expression evaluates to @xlcode(nil), otherwise the value of the last expression (evaluation of expressions stops after the first expression that evaluates to @xlcode(nil)) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{or(@i(expr)@r(...))} @c{[sal]} @xlcode{(or@pragma(defn)@index(or) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the logical or of a list of expressions @end(fgroup) @begin(pdescription) @i @itemsep the expressions to be ored returns @itemsep @xlcode(nil) if all expressions evaluate to @xlcode(nil), otherwise the value of the first non-@xlcode(nil) expression (evaluation of expressions stops after the first expression that does not evaluate to @xlcode(nil)) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{if(@i(texpr), @i(expr1)[, @i(expr2)])} @c{[sal]} @xlcode{(if@pragma(defn)@index(if) @t(@i(texpr)) @t(@i(expr1)) [@t(@i(expr2))])} @c{[lisp]} @itemsep evaluate expressions conditionally @end(fgroup) @begin(pdescription) @i @itemsep the test expression @i @itemsep the expression to be evaluated if texpr is non-@xlcode(nil) @i @itemsep the expression to be evaluated if texpr is @xlcode(nil) returns @itemsep the value of the selected expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{when(@i(texpr), @i(expr)@r(...))} @c{[sal]} @xlcode{(when@pragma(defn)@index(when) @t(@i(texpr)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep evaluate only when a condition is true @end(fgroup) @begin(pdescription) @i @itemsep the test expression @i @itemsep the expression(s) to be evaluated if texpr is non-@xlcode(nil) returns @itemsep the value of the last expression or @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{unless(@i(texpr), @i(expr)@r(...))} @c{[sal]} @xlcode{(unless@pragma(defn)@index(unless) @t(@i(texpr)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep evaluate only when a condition is false @end(fgroup) @begin(pdescription) @i @itemsep the test expression @i @itemsep the expression(s) to be evaluated if texpr is @xlcode(nil) returns @itemsep the value of the last expression or @xlcode(nil) @end(pdescription) @blankspace(1) @xlcode{(case@pragma(defn)@index(case) @t(@i(expr)) @t(@i(case))@r(...))} @c{[lisp]} @itemsep select by case @begin(pdescription) @i @itemsep the selection expression @i @itemsep pair consisting of: @begin(pdescription) (@i @i...) @end(pdescription)@pragma(stopcodef) where: @begin(pdescription) @i @itemsep is a single expression or a list of expressions (unevaluated) @i @itemsep are expressions to execute if the case matches @end(pdescription)@pragma(stopcodef) returns @itemsep the value of the last expression of the matching case @end(pdescription) @blankspace(1) @begin(fgroup) @xlcode{(let@pragma(defn)@index(let) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep create local bindings @pragma(startcodef) @xlcode{(let*@pragma(defn)@index(let*) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep let with sequential binding @end(fgroup) @begin(pdescription) @i @itemsep the variable bindings each of which is either: @begin(pdescription) 1) a symbol (which is initialized to @xlcode(nil)) 2) a list whose car is a symbol and whose cadr is an initialization expression @end(pdescription)@pragma(stopcodef) @i @itemsep the expressions to be evaluated returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) @begin(fgroup) @xlcode{(flet@pragma(defn)@index(flet) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep create local functions @pragma(startcodef) @xlcode{(labels@pragma(defn)@index(labels) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep flet with recursive functions @pragma(startcodef) @xlcode{(macrolet@pragma(defn)@index(macrolet) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep create local macros @end(fgroup) @begin(pdescription) @i @itemsep the function bindings each of which is: @begin(pdescription) (@i @i @i...) @end(pdescription)@pragma(stopcodef) where: @begin(pdescription) @i @itemsep the function/macro name @i @itemsep formal argument list (lambda list) @i @itemsep expressions constituting the body of the function/macro @end(pdescription)@pragma(stopcodef) @i @itemsep the expressions to be evaluated returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{catch(@i(sym), @i(expr)@r(...))} @c{[sal]} @xlcode{(catch@pragma(defn)@index(catch) @t(@i(sym)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep evaluate expressions and catch throws @end(fgroup) @begin(pdescription) @i @itemsep the catch tag @i @itemsep expressions to evaluate returns @itemsep the value of the last expression the throw expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{throw(@i(sym)[, @i(expr)])} @c{[sal]} @xlcode{(throw@pragma(defn)@index(throw) @t(@i(sym)) [@t(@i(expr))])} @c{[lisp]} @itemsep throw to a catch @end(fgroup) @begin(pdescription) @i @itemsep the catch tag @i @itemsep the value for the catch to return (defaults to @xlcode(nil)) returns @itemsep never returns @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{unwind-protect(@i(expr), @i(cexpr)@r(...))} @c{[sal]} @xlcode{(unwind-protect@pragma(defn)@index(unwind-protect) @t(@i(expr)) @t(@i(cexpr))@r(...))} @c{[lisp]} @itemsep protect evaluation of an expression @end(fgroup) @begin(pdescription) @i @itemsep the expression to protect @i @itemsep the cleanup expressions returns @itemsep the value of the expression@* Note: unwind-protect guarantees to execute the cleanup expressions even if a non-local exit terminates the evaluation of the protected expression @end(pdescription) @blankspace(1) @end(fdescription) @section(Looping Constructs)@index(Looping Constructs) @begin(fdescription) @xlcode{(loop@pragma(defn)@index(loop) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep basic looping form @begin(pdescription) @i @itemsep the body of the loop returns @itemsep never returns (must use non-local exit) @end(pdescription) @blankspace(1) @begin(fgroup) @xlcode{(do@pragma(defn)@index(do) (@t(@i(binding))@r(...)) (@t(@i(texpr)) @t(@i(rexpr))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @pragma(endcodef) @xlcode{(do*@pragma(defn)@index(do*) (@t(@i(binding))@r(...)) (@t(@i(texpr)) @t(@i(rexpr))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @end(fgroup) @begin(pdescription) @i @itemsep the variable bindings each of which is either: @begin(pdescription) 1) a symbol (which is initialized to @xlcode(nil)) 2) a list of the form: (@i @i [@i]) where: @begin(pdescription) @i @itemsep is the symbol to bind @i @itemsep is the initial value of the symbol @i @itemsep is a step expression @end(pdescription) @end(pdescription)@pragma(stopcodef) @i @itemsep the termination test expression @i @itemsep result expressions (the default is @xlcode(nil)) @i @itemsep the body of the loop (treated like an implicit prog) returns @itemsep the value of the last result expression @end(pdescription) @blankspace(1) @xlcode{(dolist@pragma(defn)@index(dolist) (@t(@i(sym)) @t(@i(expr)) [@t(@i(rexpr))]) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep loop through a list @begin(pdescription) @i @itemsep the symbol to bind to each list element @i @itemsep the list expression @i @itemsep the result expression (the default is @xlcode(nil)) @i @itemsep the body of the loop (treated like an implicit prog) @end(pdescription) @blankspace(1) @xlcode{(dotimes@pragma(defn)@index(dotimes) (@t(@i(sym)) @t(@i(expr)) [@t(@i(rexpr))]) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep loop from zero to n-1 @begin(pdescription) @i @itemsep the symbol to bind to each value from 0 to n-1 @i @itemsep the number of times to loop @i @itemsep the result expression (the default is @xlcode(nil)) @i @itemsep the body of the loop (treated like an implicit prog) @end(pdescription) @blankspace(1) @end(fdescription) @section(The Program Feature)@index(The Program Feature) @begin(fdescription) @begin(fgroup) @xlcode{(prog@pragma(defn)@index(prog) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the program feature @pragma(startcodef) @xlcode{(prog*@pragma(defn)@index(prog*) (@t(@i(binding))@r(...)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep prog with sequential binding @end(fgroup) @begin(pdescription) @i @itemsep the variable bindings each of which is either: @begin(pdescription) 1) a symbol (which is initialized to @xlcode(nil)) 2) a list whose car is a symbol and whose cadr is an initialization expression @end(pdescription)@pragma(stopcodef) @i @itemsep expressions to evaluate or tags (symbols) returns @itemsep @xlcode(nil) or the argument passed to the return function @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{block(@i(name), @i(expr)@r(...))} @c{[sal]} @xlcode{(block@pragma(defn)@index(block) @t(@i(name)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep named block @end(fgroup) @begin(pdescription) @i @itemsep the block name (symbol) @i @itemsep the block body returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) @xlcode{(return@pragma(defn)@index(return) [@t(@i(expr))])} @c{[lisp]} @itemsep cause a prog construct to return a value @begin(pdescription) @i @itemsep the value (defaults to @xlcode(nil)) returns @itemsep never returns @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{return-from(@i(name)[, @i(value)])} @c{[sal]} @xlcode{(return-from@pragma(defn)@index(return-from) @t(@i(name)) [@t(@i(value))])} @c{[lisp]} @itemsep return from a named block @end(fgroup) @begin(pdescription) @i @itemsep the block name (symbol) @i @itemsep the value to return (defaults to @xlcode(nil)) returns @itemsep never returns @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{tagbody(@i(expr)@r(...))} @c{[sal]} @xlcode{(tagbody@pragma(defn)@index(tagbody) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep block with labels @end(fgroup) @begin(pdescription) @i @itemsep expression(s) to evaluate or tags (symbols) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{go(@i(sym))} @c{[sal]} @xlcode{(go@pragma(defn)@index(go) @t(@i(sym)))} @c{[lisp]} @itemsep go to a tag within a tagbody or prog @end(fgroup) @begin(pdescription) @i @itemsep the tag (quoted) returns @itemsep never returns @end(pdescription) @blankspace(1) @xlcode{(progv@pragma(defn)@index(progv) @t(@i(slist)) @t(@i(vlist)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep dynamically bind symbols @begin(pdescription) @i @itemsep list of symbols @i @itemsep list of values to bind to the symbols @i @itemsep expression(s) to evaluate returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{prog1(@i(expr1), @i(expr)@r(...))} @c{[sal]} @xlcode{(prog1@pragma(defn)@index(prog1) @t(@i(expr1)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep execute expressions sequentially @end(fgroup) @begin(pdescription) @i @itemsep the first expression to evaluate @i @itemsep the remaining expressions to evaluate returns @itemsep the value of the first expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{prog2(@i(expr1), @i(expr2), @i(expr)@r(...))} @c{[sal]} @xlcode{(prog2@pragma(defn)@index(prog2) @t(@i(expr1)) @t(@i(expr2)) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep execute expressions sequentially @end(fgroup) @begin(pdescription) @i @itemsep the first expression to evaluate @i @itemsep the second expression to evaluate @i @itemsep the remaining expressions to evaluate returns @itemsep the value of the second expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{progn(@i(expr)@r(...))} @c{[sal]} @xlcode{(progn@pragma(defn)@index(progn) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep execute expressions sequentially @end(fgroup) @begin(pdescription) @i @itemsep the expressions to evaluate returns @itemsep the value of the last expression (or @xlcode(nil)) @end(pdescription) @blankspace(1) @end(fdescription) @section(Debugging and Error Handling)@index(Debugging)@index(Error Handling) @begin(fdescription) @begin(fgroup)@xlcode{trace(@i(sym))} @c{[sal]} @xlcode{(trace@pragma(defn)@index(trace) @t(@i(sym)))} @c{[lisp]} @itemsep add a function to the trace list @end(fgroup) @begin(pdescription) @i @itemsep the function to add (quoted) returns @itemsep the trace list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{untrace(@i(sym))} @c{[sal]} @xlcode{(untrace@pragma(defn)@index(untrace) @t(@i(sym)))} @c{[lisp]} @itemsep remove a function from the trace list @end(fgroup) @begin(pdescription) @i @itemsep the function to remove (quoted) returns @itemsep the trace list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{error(@i(emsg)[, @i(arg)])} @c{[sal]} @xlcode{(error@pragma(defn)@index(error) @t(@i(emsg)) [@t(@i(arg))])} @c{[lisp]} @itemsep signal a non-correctable error @end(fgroup) @begin(pdescription) @i @itemsep the error message string @i @itemsep the argument expression (printed after the message) returns @itemsep never returns @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{cerror(@i(cmsg), @i(emsg)[, @i(arg)])} @c{[sal]} @xlcode{(cerror@pragma(defn)@index(cerror) @t(@i(cmsg)) @t(@i(emsg)) [@t(@i(arg))])} @c{[lisp]} @itemsep signal a correctable error @end(fgroup) @begin(pdescription) @i @itemsep the continue message string @i @itemsep the error message string @i @itemsep the argument expression (printed after the message) returns @itemsep @xlcode(nil) when continued from the break loop @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{break([@i(bmsg)[, @i(arg)]])} @c{[sal]} @xlcode{(break@pragma(defn)@index(break) [@t(@i(bmsg)) [@t(@i(arg))]])} @c{[lisp]} @itemsep enter a break loop @end(fgroup) @begin(pdescription) @i @itemsep the break message string (defaults to @xlcode(**break**)) @i @itemsep the argument expression (printed after the message) returns @itemsep @xlcode(nil) when continued from the break loop @end(pdescription) @blankspace(1) @xlcode{(clean-up@pragma(defn)@index(clean-up))} @c{[lisp]} @itemsep clean-up after an error @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) @xlcode{(top-level@pragma(defn)@index(top-level))} @c{[lisp]} @itemsep clean-up after an error and return to the top level @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) @xlcode{(continue@pragma(defn)@index(continue))} @c{[lisp]} @itemsep continue from a correctable error @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) @xlcode{(errset@pragma(defn)@index(errset) @t(@i(expr)) [@t(@i(pflag))])} @c{[lisp]} @itemsep trap errors @begin(pdescription) @i @itemsep the expression to execute @i @itemsep flag to control printing of the error message returns @itemsep the value of the last expression consed with @xlcode(nil) or @xlcode(nil) on error @end(pdescription) @blankspace(1) @xlcode{(baktrace@pragma(defn)@index(baktrace)@index(debugging)@index(stack trace) [@t(@i(n))])} @c{[lisp]} @itemsep print n levels of trace back information @begin(pdescription) @i @itemsep the number of levels (defaults to all levels) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @xlcode{(evalhook@pragma(defn)@index(evalhook) @t(@i(expr)) @t(@i(ehook)) @t(@i(ahook)) [@t(@i(env))])} @c{[lisp]} @itemsep evaluate with hooks @begin(pdescription) @i @itemsep the expression to evaluate @i @itemsep the value for @xlcode(*evalhook*) @i @itemsep the value for @xlcode(*applyhook*) @i @itemsep the environment (default is @xlcode(nil)) returns @itemsep the result of evaluating the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{profile(@i(flag))} @c{[sal]} @xlcode{(profile@pragma(defn)@index(profile) @t(@i(flag)))} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep turn profiling on or off. @end(fgroup) @begin(pdescription) @i @itemsep @xlcode(nil) turns profiling off, otherwise on returns @itemsep the previous state of profiling. @end(pdescription) @blankspace(1) @end(fdescription) @section(Arithmetic Functions)@index(Arithmetic Functions) @begin(fdescription) @begin(fgroup)@xlcode{truncate(@i(expr))} @c{[sal]} @xlcode{(truncate@pragma(defn)@index(truncate) @t(@i(expr)))} @c{[lisp]} @itemsep truncates a floating point number to an integer @end(fgroup) @begin(pdescription) @i @itemsep the number returns @itemsep the result of truncating the number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{float(@i(expr))} @c{[sal]} @xlcode{(float@pragma(defn)@index(float) @t(@i(expr)))} @c{[lisp]} @itemsep converts an integer to a floating point number @end(fgroup) @begin(pdescription) @i @itemsep the number returns @itemsep the result of floating the integer @end(pdescription) @blankspace(1) @xlcode{(+@pragma(defn)@index(+) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep add a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the addition @end(pdescription) @blankspace(1) @xlcode{(-@pragma(defn)@index(-) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep subtract a list of numbers or negate a single number @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the subtraction @end(pdescription) @blankspace(1) @xlcode{(*@pragma(defn)@index(*) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep multiply a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the multiplication @end(pdescription) @blankspace(1) @xlcode{(/@pragma(defn)@index(/) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep divide a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the division @end(pdescription) @blankspace(1) @xlcode{(1+@pragma(defn)@index(1+) @t(@i(expr)))} @c{[lisp]} @itemsep add one to a number @begin(pdescription) @i @itemsep the number returns @itemsep the number plus one @end(pdescription) @blankspace(1) @xlcode{(1-@pragma(defn)@index(1-) @t(@i(expr)))} @c{[lisp]} @itemsep subtract one from a number @begin(pdescription) @i @itemsep the number returns @itemsep the number minus one @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{rem(@i(expr)@r(...))} @c{[sal]} @xlcode{(rem@pragma(defn)@index(rem)@index(remainder)@index(modulo (rem) function) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep remainder of a list of numbers @end(fgroup) @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the remainder operation @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{min(@i(expr)@r(...))} @c{[sal]} @xlcode{(min@pragma(defn)@index(min)@index(minimum) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the smallest of a list of numbers @end(fgroup) @begin(pdescription) @i @itemsep the expressions to be checked returns @itemsep the smallest number in the list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{max(@i(expr)@r(...))} @c{[sal]} @xlcode{(max@pragma(defn)@index(max)@index(maximum) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the largest of a list of numbers @end(fgroup) @begin(pdescription) @i @itemsep the expressions to be checked returns @itemsep the largest number in the list @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{abs(@i(expr))} @c{[sal]} @xlcode{(abs@pragma(defn)@index(abs) @t(@i(expr)))} @c{[lisp]} @itemsep the absolute value of a number @end(fgroup) @begin(pdescription) @i @itemsep the number returns @itemsep the absolute value of the number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{gcd(@i(n1), @i(n2)@r(...))} @c{[sal]} @xlcode{(gcd@pragma(defn)@index(gcd) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep compute the greatest common divisor @end(fgroup) @begin(pdescription) @i @itemsep the first number (integer) @i @itemsep the second number(s) (integer) returns @itemsep the greatest common divisor @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{random(@i(n))} @c{[sal]} @xlcode{(random@pragma(defn)@index(random) @t(@i(n)))} @c{[lisp]} @itemsep compute a random number between 0 and n-1 inclusive @end(fgroup) @begin(pdescription) @i @itemsep the upper bound (integer) returns @itemsep a random number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{rrandom()} @c{[sal]} @xlcode{(rrandom@pragma(defn)@index(rrandom)@index(uniform random))} @c{[lisp]} @itemsep compute a random real number between 0 and 1 inclusive @end(fgroup) @begin(pdescription) returns @itemsep a random floating point number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{sin(@i(expr))} @c{[sal]} @xlcode{(sin@pragma(defn)@index(sin) @t(@i(expr)))} @c{[lisp]} @itemsep compute the sine of a number @end(fgroup) @begin(pdescription) @i @itemsep the floating point number returns @itemsep the sine of the number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{cos(@i(expr))} @c{[sal]} @xlcode{(cos@pragma(defn)@index(cos) @t(@i(expr)))} @c{[lisp]} @itemsep compute the cosine of a number @end(fgroup) @begin(pdescription) @i @itemsep the floating point number returns @itemsep the cosine of the number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{tan(@i(expr))} @c{[sal]} @xlcode{(tan@pragma(defn)@index(tan) @t(@i(expr)))} @c{[lisp]} @itemsep compute the tangent of a number @end(fgroup) @begin(pdescription) @i @itemsep the floating point number returns @itemsep the tangent of the number @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{atan(@i(expr)[, @i(expr2)])} @c{[sal]} @xlcode{(atan@pragma(defn)@index(atan) @t(@i(expr)) [@t(@i(expr2))])} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep compute the arctangent @end(fgroup) @begin(pdescription) @i @itemsep the value of @i(x) @i @itemsep the value of @i(y) (default value is 1.0) returns @itemsep the arctangent of @i(x)/@i(y) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{expt(@i(x-expr), @i(y-expr))} @c{[sal]} @xlcode{(expt@pragma(defn)@index(expt) @t(@i(x-expr)) @t(@i(y-expr)))} @c{[lisp]} @itemsep compute x to the y power @end(fgroup) @begin(pdescription) @i @itemsep the floating point number @i @itemsep the floating point exponent returns @itemsep x to the y power @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{exp(@i(x-expr))} @c{[sal]} @xlcode{(exp@pragma(defn)@index(exp) @t(@i(x-expr)))} @c{[lisp]} @itemsep compute e to the x power @end(fgroup) @begin(pdescription) @i @itemsep the floating point number returns @itemsep e to the x power @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{sqrt(@i(expr))} @c{[sal]} @xlcode{(sqrt@pragma(defn)@index(sqrt) @t(@i(expr)))} @c{[lisp]} @itemsep compute the square root of a number @end(fgroup) @begin(pdescription) @i @itemsep the floating point number returns @itemsep the square root of the number @end(pdescription) @blankspace(1) @begin(fgroup) @xlcode{(<@pragma(defn)@index(<) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep test for less than @xlcode{(<=@pragma(defn)@index(<=) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep test for less than or equal to @xlcode{(=@pragma(defn)@index(=) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep test for equal to @xlcode{(/=@pragma(defn)@index(/=) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep test for not equal to @xlcode{(>=@pragma(defn)@index(>=) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep test for greater than or equal to @xlcode{(>@pragma(defn)@index(>) @t(@i(n1)) @t(@i(n2))@r(...))} @c{[lisp]} @itemsep test for greater than @end(fgroup) @begin(pdescription) @i @itemsep the first number to compare @i @itemsep the second number to compare returns @itemsep @xlcode(t) if the results of comparing @i with @i, @i with @i, etc., are all true. @end(pdescription) @blankspace(1) @end(fdescription) @section(Bitwise Logical Functions)@index(Bitwise Logical Functions) @begin(fdescription) @begin(fgroup)@xlcode{logand(@i(expr)@r(...))} @c{[sal]} @xlcode{(logand@pragma(defn)@index(logand) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the bitwise and of a list of numbers @end(fgroup) @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the and operation @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{logior(@i(expr)@r(...))} @c{[sal]} @xlcode{(logior@pragma(defn)@index(logior) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the bitwise inclusive or of a list of numbers @end(fgroup) @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the inclusive or operation @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{logxor(@i(expr)@r(...))} @c{[sal]} @xlcode{(logxor@pragma(defn)@index(logxor) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep the bitwise exclusive or of a list of numbers @end(fgroup) @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the exclusive or operation @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{lognot(@i(expr))} @c{[sal]} @xlcode{(lognot@pragma(defn)@index(lognot) @t(@i(expr)))} @c{[lisp]} @itemsep the bitwise not of a number @end(fgroup) @begin(pdescription) @i @itemsep the number returns @itemsep the bitwise inversion of number @end(pdescription) @blankspace(1) @end(fdescription) @section(String Functions)@index(String Functions) @begin(fdescription) @begin(fgroup)@xlcode{string(@i(expr))} @c{[sal]} @xlcode{(string@pragma(defn)@index(string) @t(@i(expr)))} @c{[lisp]} @itemsep make a string from a value @end(fgroup) @begin(pdescription) @i @itemsep an integer (which is first converted into its ASCII character value), string, character, or symbol returns @itemsep the string representation of the argument @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{string-search(@i(pat), @i(str), start: @i(start), end: @i(end))} @c{[sal]} @xlcode{(string-search@pragma(defn)@index(string-search)@index(find string) @t(@i(pat)) @t(@i(str)) @t(&key )@t(:start) @t(:end))} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep search for pattern in string @end(fgroup) @begin(pdescription) @i @itemsep a string to search for @i @itemsep the string to be searched :start @itemsep the starting offset in str :end @itemsep the ending offset + 1 returns @itemsep index of pat in str or NIL if not found @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{string-trim(@i(bag), @i(str))} @c{[sal]} @xlcode{(string-trim@pragma(defn)@index(string-trim) @t(@i(bag)) @t(@i(str)))} @c{[lisp]} @itemsep trim both ends of a string @end(fgroup) @begin(pdescription) @i @itemsep a string containing characters to trim @i @itemsep the string to trim returns @itemsep a trimed copy of the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{string-left-trim(@i(bag), @i(str))} @c{[sal]} @xlcode{(string-left-trim@pragma(defn)@index(string-left-trim) @t(@i(bag)) @t(@i(str)))} @c{[lisp]} @itemsep trim the left end of a string @end(fgroup) @begin(pdescription) @i @itemsep a string containing characters to trim @i @itemsep the string to trim returns @itemsep a trimed copy of the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{string-right-trim(@i(bag), @i(str))} @c{[sal]} @xlcode{(string-right-trim@pragma(defn)@index(string-right-trim) @t(@i(bag)) @t(@i(str)))} @c{[lisp]} @itemsep trim the right end of a string @end(fgroup) @begin(pdescription) @i @itemsep a string containing characters to trim @i @itemsep the string to trim returns @itemsep a trimed copy of the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{string-upcase(@i(str), start: @i(start), end: @i(end))} @c{[sal]} @xlcode{(string-upcase@pragma(defn)@index(string-upcase) @t(@i(str)) @t(&key )@t(:start) @t(:end))} @c{[lisp]} @itemsep convert to uppercase @end(fgroup) @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep a converted copy of the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{string-downcase(@i(str), start: @i(start), end: @i(end))} @c{[sal]} @xlcode{(string-downcase@pragma(defn)@index(string-downcase) @t(@i(str)) @t(&key )@t(:start) @t(:end))} @c{[lisp]} @itemsep convert to lowercase @end(fgroup) @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep a converted copy of the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{nstring-upcase(@i(str), start: @i(start), end: @i(end))} @c{[sal]} @xlcode{(nstring-upcase@pragma(defn)@index(nstring-upcase) @t(@i(str)) @t(&key )@t(:start) @t(:end))} @c{[lisp]} @itemsep convert to uppercase @end(fgroup) @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep the converted string (not a copy) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{nstring-downcase(@i(str), start: @i(start), end: @i(end))} @c{[sal]} @xlcode{(nstring-downcase@pragma(defn)@index(nstring-downcase) @t(@i(str)) @t(&key )@t(:start) @t(:end))} @c{[lisp]} @itemsep convert to lowercase @end(fgroup) @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep the converted string (not a copy) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{strcat(@i(expr)@r(...))} @c{[sal]} @xlcode{(strcat@pragma(defn)@index(strcat)@index(concatenate strings) @t(@i(expr))@r(...))} @c{[lisp]} @itemsep concatenate strings @end(fgroup) @begin(pdescription) @i @itemsep the strings to concatenate returns @itemsep the result of concatenating the strings @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{subseq(@i(string), @i(start)[, @i(end)])} @c{[sal]} @xlcode{(subseq@pragma(defn)@index(subseq) @t(@i(string)) @t(@i(start)) [@t(@i(end))])} @c{[lisp]} @itemsep extract a substring @end(fgroup) @begin(pdescription) @i @itemsep the string @i @itemsep the starting position (zero origin) @i @itemsep the ending position + 1 (defaults to end) returns @itemsep substring between @i and @i @end(pdescription) @blankspace(1) @begin(fgroup) @begin(fgroup)@xlcode{string<(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string<@pragma(defn)@index(string<) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string<=(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string<=@pragma(defn)@index(string<=) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string=(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string=@pragma(defn)@index(string=) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string/=(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string/=@pragma(defn)@index(string/=) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string>=(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string>=@pragma(defn)@index(string>=) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string>(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string>@pragma(defn)@index(string>) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @end(fgroup) @begin(pdescription) @i @itemsep the first string to compare @i @itemsep the second string to compare :start1 @itemsep first substring starting offset :end1 @itemsep first substring ending offset + 1 :start2 @itemsep second substring starting offset :end2 @itemsep second substring ending offset + 1 returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is significant with these comparison functions. @end(pdescription) @blankspace(1) @begin(fgroup) @begin(fgroup)@xlcode{string-lessp(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string-lessp@pragma(defn)@index(string-lessp) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string-not-greaterp(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string-not-greaterp@pragma(defn)@index(string-not-greaterp) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string-equalp(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string-equalp@pragma(defn)@index(string-equalp) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string-not-equalp(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string-not-equalp@pragma(defn)@index(string-not-equalp) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string-not-lessp(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string-not-lessp@pragma(defn)@index(string-not-lessp) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{string-greaterp(@i(str1), @i(str2), start1: @i(start1), end1: @i(end1), start2: @i(start2), end2: @i(end2))} @c{[sal]} @xlcode{(string-greaterp@pragma(defn)@index(string-greaterp) @t(@i(str1)) @t(@i(str2)) @t(&key )@t(:start1) @t(:end1) @t(:start2) @t(:end2))} @c{[lisp]} @end(fgroup) @end(fgroup) @begin(pdescription) @i @itemsep the first string to compare @i @itemsep the second string to compare :start1 @itemsep first substring starting offset :end1 @itemsep first substring ending offset + 1 :start2 @itemsep second substring starting offset :end2 @itemsep second substring ending offset + 1 returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is not significant with these comparison functions. @end(pdescription) @blankspace(1) @end(fdescription) @section(Character Functions)@index(Character Functions) @begin(fdescription) @begin(fgroup)@xlcode{char(@i(string), @i(index))} @c{[sal]} @xlcode{(char@pragma(defn)@index(char) @t(@i(string)) @t(@i(index)))} @c{[lisp]} @itemsep extract a character from a string @end(fgroup) @begin(pdescription) @i @itemsep the string @i @itemsep the string index (zero relative) returns @itemsep the ascii code of the character @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{upper-case-p(@i(chr))} @c{[sal]} @xlcode{(upper-case-p@pragma(defn)@index(upper-case-p) @t(@i(chr)))} @c{[lisp]} @itemsep is this an upper case character? @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep @xlcode(t) if the character is upper case, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{lower-case-p(@i(chr))} @c{[sal]} @xlcode{(lower-case-p@pragma(defn)@index(lower-case-p) @t(@i(chr)))} @c{[lisp]} @itemsep is this a lower case character? @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep @xlcode(t) if the character is lower case, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{both-case-p(@i(chr))} @c{[sal]} @xlcode{(both-case-p@pragma(defn)@index(both-case-p) @t(@i(chr)))} @c{[lisp]} @itemsep is this an alphabetic (either case) character? @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep @xlcode(t) if the character is alphabetic, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{digit-char-p(@i(chr))} @c{[sal]} @xlcode{(digit-char-p@pragma(defn)@index(digit-char-p) @t(@i(chr)))} @c{[lisp]} @itemsep is this a digit character? @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep the digit weight if character is a digit, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{char-code(@i(chr))} @c{[sal]} @xlcode{(char-code@pragma(defn)@index(char-code) @t(@i(chr)))} @c{[lisp]} @itemsep get the ascii code of a character @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep the ascii character code (integer) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{code-char(@i(code))} @c{[sal]} @xlcode{(code-char@pragma(defn)@index(code-char) @t(@i(code)))} @c{[lisp]} @itemsep get the character with a specified ascii code @end(fgroup) @begin(pdescription) @i @itemsep the ascii code (integer) returns @itemsep the character with that code or @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{char-upcase(@i(chr))} @c{[sal]} @xlcode{(char-upcase@pragma(defn)@index(char-upcase) @t(@i(chr)))} @c{[lisp]} @itemsep convert a character to upper case @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep the upper case character @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{char-downcase(@i(chr))} @c{[sal]} @xlcode{(char-downcase@pragma(defn)@index(char-downcase) @t(@i(chr)))} @c{[lisp]} @itemsep convert a character to lower case @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep the lower case character @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{digit-char(@i(n))} @c{[sal]} @xlcode{(digit-char@pragma(defn)@index(digit-char) @t(@i(n)))} @c{[lisp]} @itemsep convert a digit weight to a digit @end(fgroup) @begin(pdescription) @i @itemsep the digit weight (integer) returns @itemsep the digit character or @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{char-int(@i(chr))} @c{[sal]} @xlcode{(char-int@pragma(defn)@index(char-int) @t(@i(chr)))} @c{[lisp]} @itemsep convert a character to an integer @end(fgroup) @begin(pdescription) @i @itemsep the character returns @itemsep the ascii character code @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{int-char(@i(int))} @c{[sal]} @xlcode{(int-char@pragma(defn)@index(int-char) @t(@i(int)))} @c{[lisp]} @itemsep convert an integer to a character @end(fgroup) @begin(pdescription) @i @itemsep the ascii character code returns @itemsep the character with that code @end(pdescription) @blankspace(1) @begin(fgroup) @begin(fgroup)@xlcode{char<(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char<@pragma(defn)@index(char<) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char<=(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char<=@pragma(defn)@index(char<=) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char=(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char=@pragma(defn)@index(char=) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char/=(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char/=@pragma(defn)@index(char/=) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char>=(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char>=@pragma(defn)@index(char>=) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char>(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char>@pragma(defn)@index(char>) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @end(fgroup) @begin(pdescription) @i @itemsep the first character to compare @i @itemsep the second character(s) to compare returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is significant with these comparison functions. @end(pdescription) @blankspace(1) @begin(fgroup) @begin(fgroup)@xlcode{char-lessp(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char-lessp@pragma(defn)@index(char-lessp) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char-not-greaterp(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char-not-greaterp@pragma(defn)@index(char-not-greaterp) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char-equalp(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char-equalp@pragma(defn)@index(char-equalp) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char-not-equalp(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char-not-equalp@pragma(defn)@index(char-not-equalp) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char-not-lessp(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char-not-lessp@pragma(defn)@index(char-not-lessp) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @pragma(endcodef) @begin(fgroup)@xlcode{char-greaterp(@i(chr1), @i(chr2)@r(...))} @c{[sal]} @xlcode{(char-greaterp@pragma(defn)@index(char-greaterp) @t(@i(chr1)) @t(@i(chr2))@r(...))} @c{[lisp]} @end(fgroup) @end(fgroup) @begin(pdescription) @i @itemsep the first string to compare @i @itemsep the second string(s) to compare returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is not significant with these comparison functions. @end(pdescription) @blankspace(1) @end(fdescription) @section(Input/Output Functions)@index(Input/Output Functions) @begin(fdescription) @begin(fgroup)@xlcode{read([@i(stream)[, @i(eof)[, @i(rflag)]]])} @c{[sal]} @xlcode{(read@pragma(defn)@index(read) [@t(@i(stream)) [@t(@i(eof)) [@t(@i(rflag))]]])} @c{[lisp]} @itemsep read an expression @end(fgroup) @begin(pdescription) @i @itemsep the input stream (default is standard input) @i @itemsep the value to return on end of file (default is @xlcode(nil)) @i @itemsep recursive read flag (default is @xlcode(nil)) returns @itemsep the expression read @end(pdescription) @blankspace(1) @xlcode{(print@pragma(defn)@index(print) @t(@i(expr)) [@t(@i(stream))])} @c{[lisp]} @itemsep print an expression on a new line @begin(pdescription) @i @itemsep the expression to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{prin1(@i(expr)[, @i(stream)])} @c{[sal]} @xlcode{(prin1@pragma(defn)@index(prin1) @t(@i(expr)) [@t(@i(stream))])} @c{[lisp]} @itemsep print an expression @end(fgroup) @begin(pdescription) @i @itemsep the expression to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{princ(@i(expr)[, @i(stream)])} @c{[sal]} @xlcode{(princ@pragma(defn)@index(princ) @t(@i(expr)) [@t(@i(stream))])} @c{[lisp]} @itemsep print an expression without quoting @end(fgroup) @begin(pdescription) @i @itemsep the expressions to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{pprint(@i(expr)[, @i(stream)])} @c{[sal]} @xlcode{(pprint@pragma(defn)@index(pprint) @t(@i(expr)) [@t(@i(stream))])} @c{[lisp]} @itemsep pretty print an expression @end(fgroup) @begin(pdescription) @i @itemsep the expressions to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{terpri([@i(stream)])} @c{[sal]} @xlcode{(terpri@pragma(defn)@index(terpri) [@t(@i(stream))])} @c{[lisp]} @itemsep terminate the current print line @end(fgroup) @begin(pdescription) @i @itemsep the output stream (default is standard output) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{flatsize(@i(expr))} @c{[sal]} @xlcode{(flatsize@pragma(defn)@index(flatsize) @t(@i(expr)))} @c{[lisp]} @itemsep length of printed representation using prin1 @end(fgroup) @begin(pdescription) @i @itemsep the expression returns @itemsep the length @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{flatc(@i(expr))} @c{[sal]} @xlcode{(flatc@pragma(defn)@index(flatc) @t(@i(expr)))} @c{[lisp]} @itemsep length of printed representation using princ @end(fgroup) @begin(pdescription) @i @itemsep the expression returns @itemsep the length @end(pdescription) @blankspace(1) @end(fdescription) @section(The Format Function)@index(The Format Function) @begin(fdescription) @begin(fgroup)@xlcode{format(@i(stream), @i(fmt), @i(arg)@r(...))} @c{[sal]} @xlcode{(format@pragma(defn)@index(format) @t(@i(stream)) @t(@i(fmt)) @t(@i(arg))@r(...))} @c{[lisp]} @itemsep do formated @end(fgroup) output @begin(pdescription) @i @itemsep the output stream @i @itemsep the format string @i @itemsep the format arguments returns @itemsep output string if @i is @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @end(fdescription) The format string can contain characters that should be copied directly to the output and formatting directives. The formatting directives are: @begin(display) @xlcode(~A) @itemsep print next argument using princ @xlcode(~S) @itemsep print next argument using prin1 @xlcode(~%) @itemsep start a new line @xlcode(~~) @itemsep print a tilde character @xlcode(~) @itemsep ignore this one newline and white space on the next line up to the first non-white-space character or newline. This allows strings to continue across multiple lines @end(display) @section(File I/O Functions)@index(File I/O Functions) Note that files are ordinarily opened as text. Binary files (such as standard midi files) must be opened with @xlcode(open-binary) on non-unix systems. @begin(fdescription) @begin(fgroup)@xlcode{open(@i(fname), direction: @i(direction))} @c{[sal]} @xlcode{(open@pragma(defn)@index(open) @t(@i(fname)) @t(&key )@t(:direction))} @c{[lisp]} @itemsep open a file stream @end(fgroup) @begin(pdescription) @i @itemsep the file name string or symbol :direction @itemsep :input or :output (default is :input) returns @itemsep a stream @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{open-binary(@i(fname), direction: @i(direction))} @c{[sal]} @xlcode{(open-binary@pragma(defn)@index(open-binary)@index(open)@index(binary files) @t(@i(fname)) @t(&key )@t(:direction))} @c{[lisp]} @itemsep open a binary file stream @end(fgroup) @begin(pdescription) @i @itemsep the file name string or symbol :direction @itemsep :input or :output (default is :input) returns @itemsep a stream @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{close(@i(stream))} @c{[sal]} @xlcode{(close@pragma(defn)@index(close) @t(@i(stream)))} @c{[lisp]} @itemsep close a file stream @end(fgroup) @begin(pdescription) @i @itemsep the stream returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{setdir(@i(path)[, @i(verbose)])} @c{[sal]} @xlcode{(setdir@pragma(defn)@index(setdir)@index(change directory) @t(@i(path)) [@t(@i(verbose))])} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep set current directory @end(fgroup) @begin(pdescription) @i @itemsep the path of the new directory @i @itemsep print error message if current directory cannot be changed to @i(path) returns @itemsep the resulting full path, e.g. (setdir ".") gets the current working directory, or @xlcode(nil) if an error occurs @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{listdir(@i(path))} @c{[sal]} @xlcode{(listdir@pragma(defn)@index(listdir)@index(directory listing)@index(scan directory)@index(read directory)@index(list directory) @t(@i(path)))} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep get a directory listing @end(fgroup) @begin(pdescription) @i @itemsep the path of the directory to be listed returns @itemsep list of filenames in the directory @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{get-temp-path()} @c{[sal]} @xlcode{(get-temp-path@pragma(defn)@index(get-temp-path)@index(temporary files)@index(temp file))} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep get a path where a temporary file can be created. Under Windows, this is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice @xlcode(c:\windows\). @end(fgroup) @begin(pdescription) returns @itemsep the resulting full path as a string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{get-user()} @c{[sal]} @xlcode{(get-user@pragma(defn)@index(get-user)@index(user name)@index(temp file))} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep get the user ID. In Unix systems (including OS X and Linux), this is the value of the USER environment variable. In Windows, this is currently just ``nyquist'', which is also returned if the environment variable cannot be accessed. This function is used to avoid the case of two users creating files of the same name in the same temp directory. @end(fgroup) @begin(pdescription) returns @itemsep the string naming the user @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{find-in-xlisp-path(@i(filename))} @c{[sal]} @xlcode{(find-in-xlisp-path@pragma(defn)@index(find-in-xlisp-path) @t(@i(filename)))} @c{[lisp]}@foot(This is not a standard XLISP 2.0 function.) @itemsep search the XLISP search path (e.g. @xlcode(XLISPPATH) from the environment) for @i(filename). If @i(filename) is not found as is, and there is no file extension, append "@code(.lsp)" to @i(filename) and search again. The current directory is not searched. @end(fgroup) @begin(pdescription) @i @itemsep the name of the file to search for returns @itemsep a full path name to the first occurrence found @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{read-char([@i(stream)])} @c{[sal]} @xlcode{(read-char@pragma(defn)@index(read-char)@index(get char) [@t(@i(stream))])} @c{[lisp]} @itemsep read a character from a stream @end(fgroup) @begin(pdescription) @i @itemsep the input stream (default is standard input) returns @itemsep the character @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{peek-char([@i(flag)[, @i(stream)]])} @c{[sal]} @xlcode{(peek-char@pragma(defn)@index(peek-char) [@t(@i(flag)) [@t(@i(stream))]])} @c{[lisp]} @itemsep peek at the next character @end(fgroup) @begin(pdescription) @i @itemsep flag for skipping white space (default is @xlcode(nil)) @i @itemsep the input stream (default is standard input) returns @itemsep the character (integer) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{write-char(@i(ch)[, @i(stream)])} @c{[sal]} @xlcode{(write-char@pragma(defn)@index(write-char) @t(@i(ch)) [@t(@i(stream))])} @c{[lisp]} @itemsep write a character to a stream @end(fgroup) @begin(pdescription) @i @itemsep the character to write @i @itemsep the output stream (default is standard output) returns @itemsep the character @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{read-int([@i(stream)[, @i(length)]])} @c{[sal]} @xlcode{(read-int@pragma(defn)@index(read-int) [@t(@i(stream)) [@t(@i(length))]])} @c{[lisp]} @itemsep read a binary integer from a stream @end(fgroup) @begin(pdescription) @i @itemsep the input stream (default is standard input) @i @itemsep the length of the integer in bytes (default is 4) returns @itemsep the integer Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{write-int(@i(ch)[, @i(stream)[, @i(length)]])} @c{[sal]} @xlcode{(write-int@pragma(defn)@index(write-int) @t(@i(ch)) [@t(@i(stream)) [@t(@i(length))]])} @c{[lisp]} @itemsep write a binary integer to a stream @end(fgroup) @begin(pdescription) @i @itemsep the character to write @i @itemsep the output stream (default is standard output) @i @itemsep the length of the integer in bytes (default is 4) returns @itemsep the integer Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{read-float([@i(stream)[, @i(length)]])} @c{[sal]} @xlcode{(read-float@pragma(defn)@index(read-float) [@t(@i(stream)) [@t(@i(length))]])} @c{[lisp]} @itemsep read a binary floating-point number from a stream @end(fgroup) @begin(pdescription) @i @itemsep the input stream (default is standard input) @i @itemsep the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8) returns @itemsep the integer Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{write-float(@i(ch)[, @i(stream)[, @i(length)]])} @c{[sal]} @xlcode{(write-float@pragma(defn)@index(write-float) @t(@i(ch)) [@t(@i(stream)) [@t(@i(length))]])} @c{[lisp]} @itemsep write a binary floating-point number to a stream @end(fgroup) @begin(pdescription) @i @itemsep the character to write @i @itemsep the output stream (default is standard output) @i @itemsep the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8) returns @itemsep the integer Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{read-line([@i(stream)])} @c{[sal]} @xlcode{(read-line@pragma(defn)@index(read-line) [@t(@i(stream))])} @c{[lisp]} @itemsep read a line from a stream @end(fgroup) @begin(pdescription) @i @itemsep the input stream (default is standard input) returns @itemsep the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{read-byte([@i(stream)])} @c{[sal]} @xlcode{(read-byte@pragma(defn)@index(read-byte) [@t(@i(stream))])} @c{[lisp]} @itemsep read a byte from a stream @end(fgroup) @begin(pdescription) @i @itemsep the input stream (default is standard input) returns @itemsep the byte (integer) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{write-byte(@i(byte)[, @i(stream)])} @c{[sal]} @xlcode{(write-byte@pragma(defn)@index(write-byte) @t(@i(byte)) [@t(@i(stream))])} @c{[lisp]} @itemsep write a byte to a stream @end(fgroup) @begin(pdescription) @i @itemsep the byte to write (integer) @i @itemsep the output stream (default is standard output) returns @itemsep the byte (integer) @end(pdescription) @blankspace(1) @end(fdescription) @section(String Stream Functions)@index(String Stream Functions) These functions operate on unnamed streams. An unnamed output stream collects characters sent to it when it is used as the destination of any output function. The functions @xlcode(get-output-stream-string) and @xlcode(get-output-stream-list) return a string or a list of characters. An unnamed input stream is setup with the @xlcode(make-string-input-stream) function and returns each character of the string when it is used as the source of any input function. @begin(fdescription) @blankspace(1) @begin(fgroup)@xlcode{make-string-input-stream(@i(str)[, @i(start)[, @i(end)]])} @c{[sal]} @xlcode{(make-string-input-stream@pragma(defn)@index(make-string-input-stream) @t(@i(str)) [@t(@i(start)) [@t(@i(end))]])} @c{[lisp]} @end(fgroup) @begin(pdescription) @i @itemsep the string @i @itemsep the starting offset @i @itemsep the ending offset + 1 returns @itemsep an unnamed stream that reads from the string @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{make-string-output-stream)()} @c{[sal]} @xlcode{(make-string-output-stream)} @c{[lisp]}@pragma(defn)@index(make-string-output-stream) @end(fgroup) @begin(pdescription) returns @itemsep an unnamed output stream @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{get-output-stream-string(@i(stream))} @c{[sal]} @xlcode{(get-output-stream-string@pragma(defn)@index(get-output-stream-string) @t(@i(stream)))} @c{[lisp]} @end(fgroup) @begin(pdescription) @i @itemsep the output stream returns @itemsep the output so far as a string Note: the output stream is emptied by this function @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{get-output-stream-list(@i(stream))} @c{[sal]} @xlcode{(get-output-stream-list@pragma(defn)@index(get-output-stream-list) @t(@i(stream)))} @c{[lisp]} @end(fgroup) @begin(pdescription) @i @itemsep the output stream returns @itemsep the output so far as a list Note: the output stream is emptied by this function @end(pdescription) @blankspace(1) @end(fdescription) @section(System Functions)@index(System Functions) Note: the @xlcode(load) function first tries to load a file from the current directory. A @code(.lsp) extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. (The Macintosh version has no search path.) @begin(fdescription) @begin(fgroup)@xlcode{get-env(@i(name))} @c{[sal]} @xlcode{(get-env@pragma(defn)@index(get-env)@index(getenv)@index(environment variables) @t(@i(name)))} @c{[lisp]} @itemsep get from an environment variable @end(fgroup) @begin(pdescription) @i @itemsep the name of the environment variable returns @itemsep string value of the environment variable, @xlcode(nil) if variable does not exist @end(pdescription) @blankspace(1) @xlcode{(load@pragma(defn)@index(load) @t(@i(fname)) @t(&key )@t(:verbose) @t(:print))} @c{[lisp]} @itemsep load a source file @begin(pdescription) @i @itemsep the filename string or symbol :verbose @itemsep the verbose flag (default is t) :print @itemsep the print flag (default is @xlcode(nil)) returns @itemsep the filename @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{save(@i(fname))} @c{[sal]} @xlcode{(save@pragma(defn)@index(save) @t(@i(fname)))} @c{[lisp]} @itemsep save workspace to a file @end(fgroup) @begin(pdescription) @i @itemsep the filename string or symbol returns @itemsep @xlcode(t) if workspace was written, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{restore(@i(fname))} @c{[sal]} @xlcode{(restore@pragma(defn)@index(restore) @t(@i(fname)))} @c{[lisp]} @itemsep restore workspace from a file @end(fgroup) @begin(pdescription) @i @itemsep the filename string or symbol returns @itemsep @xlcode(nil) on failure, otherwise never returns @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{dribble([@i(fname)])} @c{[sal]} @xlcode{(dribble@pragma(defn)@index(dribble) [@t(@i(fname))])} @c{[lisp]} @itemsep create a file with a transcript of a session @end(fgroup) @begin(pdescription) @i @itemsep file name string or symbol (if missing, close current transcript) returns @itemsep @xlcode(t) if the transcript is opened, @xlcode(nil) if it is closed @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{gc()} @c{[sal]} @xlcode{(gc@pragma(defn)@index(gc))} @c{[lisp]} @itemsep force garbage collection @end(fgroup) @begin(pdescription) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{expand(@i(num))} @c{[sal]} @xlcode{(expand@pragma(defn)@index(expand) @t(@i(num)))} @c{[lisp]} @itemsep expand memory by adding segments @end(fgroup) @begin(pdescription) @i @itemsep the number of segments to add returns @itemsep the number of segments added @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{alloc(@i(num))} @c{[sal]} @xlcode{(alloc@pragma(defn)@index(alloc) @t(@i(num)))} @c{[lisp]} @itemsep change number of nodes to allocate in each segment @end(fgroup) @begin(pdescription) @i @itemsep the number of nodes to allocate returns @itemsep the old number of nodes to allocate @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{info()} @c{[sal]} @xlcode{(info@pragma(defn)@index(info))} @c{[lisp]} @itemsep show information about memory usage. @end(fgroup) @begin(pdescription) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{room()} @c{[sal]} @xlcode{(room@pragma(defn)@index(room))} @c{[lisp]} @itemsep show memory allocation statistics @end(fgroup) @begin(pdescription) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{type-of(@i(expr))} @c{[sal]} @xlcode{(type-of@pragma(defn)@index(type-of) @t(@i(expr)))} @c{[lisp]} @itemsep returns the type of the expression @end(fgroup) @begin(pdescription) @i @itemsep the expression to return the type of returns @itemsep @xlcode(nil) if the value is @xlcode(nil) otherwise one of the symbols: @begin(pdescription) SYMBOL @itemsep for symbols OBJECT @itemsep for objects CONS @itemsep for conses SUBR @itemsep for built-in functions FSUBR @itemsep for special forms CLOSURE @itemsep for defined functions STRING @itemsep for strings FIXNUM @itemsep for integers FLONUM @itemsep for floating point numbers CHARACTER @itemsep for characters FILE-STREAM @itemsep for file pointers UNNAMED-STREAM @itemsep for unnamed streams ARRAY @itemsep for arrays @end(pdescription) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{peek(@i(addrs))} @c{[sal]} @xlcode{(peek@pragma(defn)@index(peek) @t(@i(addrs)))} @c{[lisp]} @itemsep peek at a location in memory @end(fgroup) @begin(pdescription) @i @itemsep the address to peek at (integer) returns @itemsep the value at the specified address (integer) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{poke(@i(addrs), @i(value))} @c{[sal]} @xlcode{(poke@pragma(defn)@index(poke) @t(@i(addrs)) @t(@i(value)))} @c{[lisp]} @itemsep poke a value into memory @end(fgroup) @begin(pdescription) @i @itemsep the address to poke (integer) @i @itemsep the value to poke into the address (integer) returns @itemsep the value @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{bigendianp()} @c{[sal]} @xlcode{(bigendianp@pragma(defn)@index(bigendianp)@index(endian)@index(big endian)@index(little endian))} @c{[lisp]} @itemsep is this a big-endian machine? @end(fgroup) @begin(pdescription) returns @itemsep T if this a big-endian architecture, storing the high-order byte of an integer at the lowest byte address of the integer; otherwise, NIL. @foot(This is not a standard XLISP 2.0 function.) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{address-of(@i(expr))} @c{[sal]} @xlcode{(address-of@pragma(defn)@index(address-of) @t(@i(expr)))} @c{[lisp]} @itemsep get the address of an xlisp node @end(fgroup) @begin(pdescription) @i @itemsep the node returns @itemsep the address of the node (integer) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{exit()} @c{[sal]} @xlcode{(exit@pragma(defn)@index(exit))} @c{[lisp]} @itemsep exit xlisp @end(fgroup) @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{setup-console()} @c{[sal]} @xlcode{(setup-console@pragma(defn)@index(setup-console)@index(window initialization))} @c{[lisp]} @itemsep set default console attributes @end(fgroup) @begin(pdescription) returns @itemsep NIL Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of ``Nyquist.'' This is normally accomplished by calling @xlcode(setup-console) in @code(system.lsp). In Nyquist, you can avoid this behavior by setting @xlcode(*setup-console*) to NIL in your @code(init.lsp) file. If @xlcode(setup-console) is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.@index(emacs, using Nyquist with) @end(pdescription) @blankspace(1) @begin(fgroup)@xlcode{echoenabled(@i(flag))} @c{[sal]} @xlcode{(echoenabled@pragma(defn)@index(echoenabled)@index(console, XLISP) @t(@i(flag)))} @c{[lisp]} @itemsep turn console input echoing on or off @end(fgroup) @begin(pdescription) @i @itemsep T to enable echo, NIL to disable returns @itemsep NIL Note: This function is only implemented under Linux and Mac OS X. If Nyquist I/O is redirected through pipes, the Windows version does not echo the input, but the Linux and Mac versions do. You can turn off echoing with this function. Under windows it is defined to do nothing. @end(pdescription) @end(fdescription) @section(File I/O Functions)@index(File I/O Functions) @subsection(Input from a File)@index(Input from a File) To open a file for input, use the @xlcode(open) function with the keyword argument @xlcode(:direction) set to @xlcode(:input). To open a file for output, use the @xlcode(open) function with the keyword argument @xlcode(:direction) set to @xlcode(:output). The @xlcode(open) function takes a single required argument which is the name of the file to be opened. This name can be in the form of a string or a symbol. The @xlcode(open) function returns an object of type @xlcode(FILE-STREAM) if it succeeds in opening the specified file. It returns the value @xlcode(nil) if it fails. In order to manipulate the file, it is necessary to save the value returned by the @xlcode(open) function. This is usually done by assigning it to a variable with the @xlcode(setq) special form or by binding it using @xlcode(let) or @xlcode(let*). Here is an example: @begin(example) (setq fp (open "init.lsp" :direction :input)) @end(example) Evaluating this expression will result in the file @code(init.lsp) being opened. The file object that will be returned by the @xlcode(open) function will be assigned to the variable @xlcode(fp). It is now possible to use the file for input. To read an expression from the file, just supply the value of the @xlcode(fp) variable as the optional @i(stream) argument to @xlcode(read). @begin(example) (read fp) @end(example) Evaluating this expression will result in reading the first expression from the file @code(init.lsp). The expression will be returned as the result of the @xlcode(read) function. More expressions can be read from the file using further calls to the @xlcode(read) function. When there are no more expressions to read, the @xlcode(read) function will return @xlcode(nil) (or whatever value was supplied as the second argument to @xlcode(read)). Once you are done reading from the file, you should close it. To close the file, use the following expression: @begin(example) (close fp) @end(example) Evaluating this expression will cause the file to be closed. @subsection(Output to a File)@index(Output to a File) Writing to a file is pretty much the same as reading from one. You need to open the file first. This time you should use the @xlcode(open) function to indicate that you will do output to the file. For example: @begin(example) (setq fp (open "test.dat" :direction :output)) @end(example) Evaluating this expression will open the file @code(test.dat) for output. If the file already exists, its current contents will be discarded. If it doesn't already exist, it will be created. In any case, a @xlcode(FILE-STREAM) object will be returned by the @xlcode(OPEN) function. This file object will be assigned to the @xlcode(fp) variable. It is now possible to write to this file by supplying the value of the @xlcode(fp) variable as the optional @i(stream) parameter in the @xlcode(print) function. @begin(example) (print "Hello there" fp) @end(example) Evaluating this expression will result in the string ``Hello there'' being written to the file @code(test.dat). More data can be written to the file using the same technique. Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file. @begin(example) (close fp) @end(example) Evaluating this expression will close the output file and make it permanent. @subsection(A Slightly More Complicated File Example) This example shows how to open a file, read each Lisp expression from the file and print it. It demonstrates the use of files and the use of the optional @i(stream) argument to the @xlcode(read) function. @begin(programexample) (do* ((fp (open "test.dat" :direction :input)) (ex (read fp) (read fp))) ((null ex) nil) (print ex)) @end(programexample) nyquist-3.05/docsrc/xlisp/intgen.mss0000644000175000000620000002516611466723256016635 0ustar stevestaffThis documentation describes Intgen, a program for generating XLISP to C interfaces. Intgen works by scanning @code(.h) files with special comments in them. Intgen builds stubs that implement XLISP SUBR's. When the SUBR is called, arguments are type-checked and passed to the C routine declared in the @code(.h) file. Results are converted into the appropriate XLISP type and returned to the calling XLISP function. Intgen lets you add C functions into the XLISP environment with very little effort. The interface generator will take as command-line input: @begin(itemize) the name of the @code(.c) file to generate (do not include the @code(.c) extension; e.g. write @code(xlexten), not @code(xlexten.c)); a list of @code(.h) files. @end(itemize) Alternatively, the command line may specify a command file from which to read file names. The command file name should be preceded by "@@", for example: @begin(example) intgen @@sndfns.cl @end(example) reads sndfns.cl to get the command-line input. Only one level of indirection is allowed. The output is: @begin(itemize) a single @code(.c) file with one SUBR defined for each designated routine in a @code(.h) file. a @code(.h) file that declares each new C routine. E.g. if the @code(.c) file is named @code(xlexten.c), this file will be named @code(xlextendefs.h); a @code(.h) file that extends the SUBR table used by Xlisp. E.g. if the @code(.c) file is named @code(xlexten.c), then this file is named @code(xlextenptrs.h); a @code(.lsp) file with lisp initialization expressions copied from the @code(.h) files. This file is only generated if at least one initialization expression is encountered. @end(itemize) For example, the command line @begin(example) intgen seint ~setypes.h access.h @end(example) generates the file @code(seint.c), using declarations in @code(setypes.h) and @code(access.h). Normally, the @code(.h) files are included by the generated file using @code(#include) commands. A @code(~) before a file means do not include the @code(.h) file. (This may be useful if you extend @code(xlisp.h), which will be included anyway). Also generated will be @code(setintdefs.h) and @code(seintptrs.h). @subsection(Extending Xlisp)@index(Extending Xlisp) Any number of @code(.h) files may be named on the command line to Intgen, and Intgen will make a single @code(.c) file with interface routines for all of the @code(.h) files. On the other hand, it is not necessary to put all of the extensions to Xlisp into a single interface file. For example, you can run Intgen once to build interfaces to window manager routines, and again to build interfaces to a new data type. Both interfaces can be linked into Xlisp. To use the generated files, you must compile the @code(.c) files and link them with all of the standard Xlisp object files. In addition, you must edit the file @code(localdefs.h) to contain an @code(#include) for each @code(*defs.h) file, and edit the file @code(localptrs.h) to include each @code(*ptrs.h) file. For example, suppose you run Intgen to build @code(soundint.c), @code(fugueint.c), and @code(tableint.c). You would then edit @code(localdefs.h) to contain the following: @begin(example) #include "soundintdefs.h" #include "fugueintdefs.h" #include "tableintdefs.h" @end(example) and edit @code(localptrs.h) to contain: @begin(example) #include "soundintptrs.h" #include "fugueintptrs.h" #include "tableintptrs.h" @end(example) These @code(localdefs.h) and @code(localptrs.h) files are in turn included by @code(xlftab.c) which is where Xlisp builds a table of SUBRs. To summarize, building an interface requires just a few simple steps: @begin(itemize) Write C code to be called by Xlisp interface routines. This C code does the real work, and in most cases is completely independent of Xlisp. Add comments to @code(.h) files to tell Intgen which routines to build interfaces to, and to specify the types of the arguments. Run Intgen to build interface routines. Edit @code(localptrs.h) and @code(localdefs.h) to include generated @code(.h) files. Compile and link Xlisp, including the new C code. @end(itemize) @section(Header file format)@index(Header file format) Each routine to be interfaced with Xlisp must be declared as follows: @begin(example) @i(type-name) @i(routine-name)(); /* LISP: (@i(func-name) @i(type@-(1)) @i(type@-(2)) ...) */ @end(example) The comment may be on the line following the declaration, but the declaration and the comment must each be on no more than one line. The characters @code(LISP:) at the beginning of the comment mark routines to put in the interface. The comment also gives the type and number of arguments. The function, when accessed from lisp will be known as @I(func-name), which need not bear any relationship to @i(routine-name). By convention, underscores in the C @i(routine-name) should be converted to dashes in @i(func-name), and @i(func-name) should be in all capitals. None of this is enforced or automated though. Legal type_names are: @begin(description) @code(LVAL)@\returns an Xlisp datum. @code(atom_type)@\equivalent to @code(LVAL), but the result is expected to be an atom. @code(value_type)@\a value as used in Dannenberg's score editor. @code(event_type)@\an event as used in Dannenberg's score editor. @code(int)@\interface will convert int to Xlisp @code(FIXNUM). @code(boolean)@\interface will convert int to @code( T) or @code(nil). @code(float) or @code(double)@\interface converts to @code(FLONUM). @code(char *) or @code(string) or @code(string_type)@\interface converts to @code(STRING). The result string will be copied into the XLISP heap. void@\interface will return @code(nil). @end(description) It is easy to extend this list. Any unrecognized type will be coerced to an @code(int) and then returned as a @code(FIXNUM), and a warning will be issued. The ``@code(*)'' after char must be followed by @i(routine-name) with no intervening space. Parameter types may be any of the following: @begin(description) @code(FIXNUM)@\C routine expects an int. @code(FLONUM) or @code(FLOAT)@\C routine expects a @code(double). @code(STRING)@\C routine expects @code(char *), the string is not copied. @code(VALUE)@\C routine expects a @code(value_type). (Not applicable to Fugue.) @code(EVENT)@\C routine expects an @code(event_type). (Not applicable to Fugue.) @code(ANY)@\C routine expects @code(LVAL). @code(ATOM)@\C routine expects @code(LVAL) which is a lisp atom. @code(FILE)@\C routine expects @code(FILE *). @code(SOUND)@\C routine expects a @code(SoundPtr). @end(description) Any of these may be followed by ``@code(*)'': @code(FIXNUM*), @code(FLONUM*), @code(STRING*), @code(ANY*), @code(FILE*), indicating C routine expects @code(int *), @code(double *), @code(char **), @code(LVAL *), or @code(FILE **) . This is basically a mechanism for returning more than one value, @i(not) a mechanism for clobbering XLisp values. In this spirit, the interface copies the value (an @code(int), @code(double), @code(char *), @code(LVAL), or @code(FILE *)) to a local variable and passes the address of that variable to the C routine. On return, a list of resulting ``@code(*)'' parameters is constructed and bound to the global XLisp symbol @code(*RSLT*@index(*RSLT*)). (Strings are copied.) If the C routine is void, then the result list is also returned by the corresponding XLisp function. Note 1: this does not support C routines like strcpy that modify strings, because the C routine gets a pointer to the string in the XLisp heap. However, you can always add an intermediate routine that allocates space and then calls @code(strcpy), or whatever. Note 2: it follows that a new XLisp @code(STRING) will be created for each @code(STRING*) parameter. Note 3: putting results on a (global!) symbol seems a bit unstructured, but note that one could write a multiple-value binding macro that hides this ugliness from the user if desired. In practice, I find that pulling the extra result values from @code(*RSLT*) when needed is perfectly acceptable. For parameters that are result values only, the character ``@code(^)'' may be substituted for ``@code(*)''. In this case, the parameter is @i(not) to be passed in the XLisp calling site. However, the address of an initialized local variable of the given type is passed to the corresponding C function, and the resulting value is passed back through @code(*RSLT*) as ordinary result parameter as described above. The local variables are initialized to zero or @code(NULL). @section(Using #define'd macros)@index(#define'd macros) If a comment of the form: @begin(example) /* LISP: @i(type-name) (@i(routine-name-2) @i(type-1) @i(type-2) ...) */ @end(example) appears on a line by itself and there was a @code(#define) on the previous line, then the preceding @code(#define) is treated as a C routine, e.g. @begin(example) #define leftshift(val, count) ((val) << (count)) /* LISP: int (LOGSHIFT INT INT) */ @end(example) will implement the LeLisp function @code(LOGSHIFT). The @i(type-name) following ``@code(LISP:)'' should have no spaces, e.g. use @code(ANY*), not @code(ANY *). @section(Lisp Include Files)@index(Lisp Include Files) Include files often define constants that we would like to have around in the Lisp world, but which are easier to initialize just by loading a text file. Therefore, a comment of the form: @begin(example) /* LISP-SRC: (any lisp expression) */ @end(example) will cause Intgen to open a file @i(name)@code(.lsp) and append @begin(example) (any lisp expression) @end(example) to @i(name)@code(.lsp), where @i(name) is the interface name passed on the command line. If none of the include files examined have comments of this form, then no @i(name)@code(.lsp) file is generated. @p(Note:) @i(the LISP-SRC comment must be on a new line.) @section(Example) This file was used for testing Intgen. It uses a trick (ok, it's a hack) to interface to a standard library macro (tolower). Since tolower is already defined, the macro ToLower is defined just to give Intgen a name to call. Two other routines, strlen and tough, are interfaced as well. @begin(example) /* igtest.h -- test interface for intgen */ #define ToLower(c) tolower(c) /* LISP: int (TOLOWER FIXNUM) */ int strlen(); /* LISP: (STRLEN STRING) */ void tough(); /* LISP: (TOUGH FIXNUM* FLONUM* STRING ANY FIXNUM) */ @end(example) @section(More Details) Intgen has some compiler switches to enable/disable the use of certain types, including @code(VALUE) and @code(EVENT) types used by Dannenberg's score editing work, the @code(SOUND) type used by Fugue, and @code(DEXT) and @code(SEXT) types added for Dale Amon. Enabling all of these is not likely to cause problems, and the chances of an accidental use of these types getting through the compiler and linker seems very small. nyquist-3.05/docsrc/xlisp/xlisp-no-sal.mss0000644000175000000620000035467511510141774017676 0ustar stevestaff@define(codef, FaceCode T, size 11) @comment{In my original scribe conversion of the ascii xlisp documentation, I used times roman fonts for xlisp function names and code text in general. To be consistent with Nyquist documentation, I have changed the code font to xlcode which is defined here. If this turns out to be a problem, redefine xlcode to use the regular FaceCode. -RBD} @define(xlcode, FaceCode T, size 11) @textform(pragma=[]) @section(Introduction) XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers. Implementations of XLISP run on virtually every operating system. XLISP is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users. Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects Object and Class as primitives. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances (it is the only object that is an instance of itself). This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming. I recommend the book @i(Lisp) by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp. You will probably also need a copy of @i(Common Lisp: The Language) by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document. @section(A Note From The Author) If you have any problems with XLISP, feel free to contact me [me being David Betz - RBD] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users [e.g. that Dannenberg fellow - RBD] have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me. If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it. Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However, PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!! I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run. @section(XLISP Command Loop)@index(XLISP Command Loop)@index(Command Loop) When XLISP is started, it first tries to load the workspace @code(xlisp.wks) from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols. Then XLISP attempts to load @code(init.lsp) from the current directory. It then loads any files named as parameters on the command line (after appending @code(.lsp) to their names). XLISP then issues the following prompt: @begin(example) > @end(example) This indicates that XLISP is waiting for an expression to be typed. When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed. @section(Special Characters)@index(control characters, XLISP) When XLISP is running from a console, some control characters invoke operations: @begin(itemize) Backspace and Delete characters erase the previous character on the input line (if any). Control-U erases the entire input line. Control-C executes the TOP-LEVEL function. Control-G executes the CLEAN-UP function. Control-P executes the CONTINUE function. Control-B stops execution and enters the break command loop. Execution can be continued by typing Control-P or (CONTINUE). Control-E turns on character echoing (Linux and Mac OS X only). Control-F turns off character echoing (Linux and Mac OS X only). Control-T evaluates the INFO function. @end(itemize) @section(Break Command Loop)@index(break) When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way: If the symbol @xlcode(*breakenable*@index(*breakenable*)) is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed. If the symbol @xlcode(*tracenable*@index(*tracenable*)) is true, a trace back is printed. The number of entries printed depends on the value of the symbol @xlcode(*tracelimit*@index(*tracelimit*)). If this symbol is set to something other than a number, the entire trace back stack is printed. XLISP then enters a read/eval/print loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level read/eval/print loop in that if the user invokes the function @xlcode(continue), XLISP will continue from a correctable error. If the user invokes the function @xlcode(clean-up), XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt. If the symbol @xlcode(*breakenable*@index(*breakenable*)) is @xlcode(nil), XLISP looks for a surrounding errset function. If one is found, XLISP examines the value of the print flag. If this flag is true, the error message is printed. In any case, XLISP causes the errset function call to return @xlcode(nil). If there is no surrounding errset function, XLISP prints the error message and returns to the top level. @section(Data Types)@index(XLISP Data Types)@index(Data Types) There are several different data types available to XLISP programmers. @begin(itemize) lists symbols strings integers characters floats objects arrays streams subrs (built-in functions) fsubrs (special forms) closures (user defined functions) @end(itemize) @section(The Evaluator)@index(evaluator)@index(XLISP evaluator) The process of evaluation in XLISP: @begin(itemize) Strings, integers, characters, floats, objects, arrays, streams, subrs, fsubrs and closures evaluate to themselves. Symbols act as variables and are evaluated by retrieving the value associated with their current binding. Lists are evaluated by examining the first element of the list and then taking one of the following actions: @begin(itemize) If it is a symbol, the functional binding of the symbol is retrieved. If it is a lambda expression, a closure is constructed for the function described by the lambda expression. If it is a subr, fsubr or closure, it stands for itself. Any other value is an error. @end(itemize) Then, the value produced by the previous step is examined: @begin(itemize) If it is a subr or closure, the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments. If it is an fsubr, the fsubr is called using the remaining list elements as arguments (unevaluated). If it is a macro, the macro is expanded using the remaining list elements as arguments (unevaluated). The macro expansion is then evaluated in place of the original macro call. @end(itemize) @end(itemize) @section(Lexical Conventions)@index(Lexical conventions)@index(XLISP Lexical Conventions) The following conventions must be followed when entering XLISP programs: Comments in XLISP code begin with a semi-colon character and continue to the end of the line. Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following: @begin(example) ( ) ' ` , " ; @end(example) Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input. Integer literals consist of a sequence of digits optionally beginning with a @code(+) or @code(-). The range of values an integer can represent is limited by the size of a C @code(long) on the machine on which XLISP is running. Floating point literals consist of a sequence of digits optionally beginning with a @code(+) or @code(-) and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C @code(float) (@code(double) on machines with 32 bit addresses) on the machine on which XLISP is running. Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the ``@code(\)'' character is used to allow non-printable characters to be included. The codes recognized are: @begin(itemize) @code(\\) means the character ``@code(\)'' @code(\n) means newline @code(\t) means tab @code(\r) means return @code(\f) means form feed @code(\nnn) means the character whose octal code is nnn @end(itemize) @section(Readtables)@index(Readtables) The behavior of the reader is controlled by a data structure called a @i(readtable). The reader uses the symbol @xlcode(*readtable*@index(*readtable*)) to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things: @begin(itemize) @xlcode(NIL) @itemsep Indicating an invalid character @xlcode(:CONSTITUENT) @itemsep Indicating a symbol constituent @xlcode(:WHITE-SPACE) @itemsep Indicating a whitespace character @xlcode[(:TMACRO . @i(fun))] @itemsep Terminating readmacro @xlcode[(:NMACRO . @i(fun))] @itemsep Non-terminating readmacro @xlcode(:SESCAPE) @itemsep Single escape character ('\') @xlcode(:MESCAPE) @itemsep Multiple escape character ('|') @end(itemize) In the case of @xlcode(:TMACRO) and @xlcode(:NMACRO), the @i(fun) component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return @xlcode(NIL) to indicate that the character should be treated as white space or a value consed with @xlcode(NIL) to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream. XLISP defines several useful read macros@index(read macros): @begin(itemize) @xlcode(')@i[] == @xlcode{(quote} @i[]@xlcode{)} @xlcode(#')@i[] == @xlcode{(function} @i[]@xlcode{)} @xlcode{#(}@i[]...@xlcode{)} == an array of the specified expressions @xlcode(#x)@i[] == a hexadecimal number (0-9,A-F) @xlcode(#o)@i[] == an octal number (0-7) @xlcode(#b)@i[] == a binary number (0-1) @xlcode(#\)@i[] == the ASCII code of the character @xlcode(#|) ... @xlcode(|#) == a comment @xlcode(#:)@i[] == an uninterned symbol @xlcode(`)@i[] == @xlcode{(backquote} @i[]@xlcode{)} @xlcode(,)@i[] == @xlcode{(comma} @i[]@xlcode{)} @xlcode(,@@)@i[] == @xlcode{(comma-at} @i[]@xlcode{)} @end(itemize) @section(Lambda Lists)@index(Lambda Lists) There are several forms in XLISP that require that a ``lambda list'' be specified. A lambda list is a definition of the arguments accepted by a function. There are four different types of arguments. The lambda list starts with required arguments. Required arguments must be specified in every call to the function. The required arguments are followed by the @xlcode(&optional) arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an @xlcode(&optional) argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to @xlcode(NIL). It is also possible to provide the name of a @xlcode(supplied-p) variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the supplied- p variable will be bound to T if a value was specified in the call and @xlcode(NIL) if the default value was used. The @xlcode(&optional) arguments are followed by the @xlcode(&rest) argument. The @xlcode(&rest) argument gets bound to the remainder of the argument list after the required and @xlcode(&optional) arguments have been removed. The @xlcode(&rest) argument is followed by the @xlcode(&key) arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol (a symbol that begins with a ``@code(:)''). The value of the second expression is the value of the keyword argument. Like @xlcode(&optional) arguments, @xlcode(&key) arguments can have initialization expressions and supplied-p variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a ``@code(:)'' to the beginning of the keyword argument symbol is used. In other words, if the keyword argument symbol is @xlcode(foo), the keyword will be @xlcode(:foo). The @xlcode(&key) arguments are followed by the @xlcode(&aux) variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the @xlcode(&aux) variables. Here is the complete syntax for lambda lists: @begin(display) (@i... [@xlcode(&optional) [@i | (@i [@i [@i]])]...] [@xlcode(&rest) @i] [@xlcode(&key) [@i | ([@i | (@i @i)] [@i [@i]])]... @xlcode(&allow)-other-keys] [@xlcode(&aux) [@i | (@i [@i])]...]) where: @i is a required argument symbol @i is an @xlcode(&optional) argument symbol @i is the @xlcode(&rest) argument symbol @i is a @xlcode(&key) argument symbol @i is a keyword symbol @i is an auxiliary variable symbol @i is an initialization expression @i is a supplied-p variable symbol @end(display) @section(Objects)@index(Objects)@label(objects-sec) Definitions: @begin(itemize) selector @itemsep a symbol used to select an appropriate method message @itemsep a selector and a list of actual arguments method @itemsep the code that implements a message @end(itemize) Since XLISP was created to provide a simple basis for experimenting with object-oriented programming, one of the primitive data types included is @i(object). In XLISP, an object consists of a data structure containing a pointer to the object's class as well as an array containing the values of the object's instance variables. Officially, there is no way to see inside an object (look at the values of its instance variables). The only way to communicate with an object is by sending it a message. You can send a message to an object using the @xlcode(send) function. This function takes the object as its first argument, the message selector as its second argument (which must be a symbol) and the message arguments as its remaining arguments. The @xlcode(send) function determines the class of the receiving object and attempts to find a method corresponding to the message selector in the set of messages defined for that class. If the message is not found in the object's class and the class has a super-class, the search continues by looking at the messages defined for the super-class. This process continues from one super-class to the next until a method for the message is found. If no method is found, an error occurs. @begin(comment) THIS IS WRONG -- I DON'T KNOW IF IT WAS CORRECT IN THE ORIGINAL XLISP. -RBD A message can also be sent from the body of a method by using the current object, but the method lookup starts with the object's superclass rather than its class. This allows a subclass to invoke a standard method in its parent class even though it overrides that method with its own specialized version. @end(comment) When a method is found, the evaluator binds the receiving object to the symbol @xlcode(self) and evaluates the method using the remaining elements of the original list as arguments to the method. These arguments are always evaluated prior to being bound to their corresponding formal arguments. The result of evaluating the method becomes the result of the expression. Within the body of a method, a message can be sent to the current object by calling the @xlcode[(send self ...)]. The method lookup starts with the object's class regardless of the class containing the current method. Sometimes it is desirable to invoke a general method in a superclass even when it is overridden by a more specific method in a subclass. This can be accomplished by calling @xlcode(send-super), which begins the method lookup in the superclass of the class defining the current method rather than in the class of the current object. The @xlcode(send-super) function takes a selector as its first argument (which must be a symbol) and the message arguments as its remaining arguments. Notice that @xlcode(send-super) can only be sent from within a method, and the target of the message is always the current object (@xlcode(self)). @xlcode[(send-super ...)] is similar to @xlcode[(send self ...)] except that method lookup begins in the superclass of the class containing the current method rather than the class of the current object. @section(The ``Object'' Class)@index(Object Class) @xlcode(Object)@index(Object) @itemsep the top of the class hierarchy. Messages: @begin(fdescription) @xlcode(:show@index(:show)) @itemsep show an object's instance variables. @begin(pdescription) returns @itemsep the object @end(pdescription) @blankspace(1) @xlcode{:class@index(:class)} @itemsep return the class of an object @begin(pdescription) returns @itemsep the class of the object @end(pdescription) @blankspace(1) @xlcode{:isa@index(:isa)} @i(class) @itemsep test if object inherits from class @begin(pdescription) returns @itemsep @xlcode(t) if object is an instance of @i(class) or a subclass of @i(class), otherwise @xlcode(nil) @end(pdescription) @blankspace(1) @xlcode(:isnew@index(:isnew)) @itemsep the default object initialization routine @begin(pdescription) returns @itemsep the object @end(pdescription) @end(fdescription) @section(The ``Class'' Class)@index(Class class) @xlcode(Class@index(Class)) @itemsep class of all object classes (including itself) Messages: @begin(fdescription) @xlcode(:new@index(:new)) @itemsep create a new instance of a class @begin(pdescription) returns @itemsep the new class object @end(pdescription) @blankspace(1) @xlcode(:isnew@index(:isnew)) @i [@i [@i]] @itemsep initialize a new class @begin(pdescription) @i @itemsep the list of instance variable symbols @i @itemsep the list of class variable symbols @i @itemsep the superclass (default is object) returns @itemsep the new class object @end(pdescription) @blankspace(1) @xlcode(:answer@index(:answer)) @i @i @i @itemsep add a message to a class @begin(pdescription) @i @itemsep the message symbol @i @itemsep the formal argument list (lambda list) @i @itemsep a list of executable expressions returns @itemsep the object @end(pdescription) @blankspace(1) @end(fdescription) When a new instance of a class is created by sending the message @xlcode(:new) to an existing class, the message @xlcode(:isnew) followed by whatever parameters were passed to the @xlcode(:new) message is sent to the newly created object. When a new class is created by sending the @xlcode(:new) message to the object @xlcode(Class), an optional parameter may be specified indicating the superclass of the new class. If this parameter is omitted, the new class will be a subclass of @xlcode(Object). A class inherits all instance variables, class variables, and methods from its super-class. @section(Profiling)@index(profiling) The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where @xlcode(eval) is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an @xlcode(eval) in the immediately (lexically) enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls. The list of all functions executed is maintained on the global @xlcode(*profile*) variable. These functions in turn have @xlcode(*profile*) properties, which maintain the counts. The profile system merely increments counters and puts symbols on the @xlcode(*profile*) list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the @xlcode(profile) function. Unfortunately, methods cannot be profiled with this facility. @label(symbols-sec) @section(Symbols)@index(symbols) @begin(itemize) @codef(self)@pragma(defn)@index(self) @dash the current object (within a method context) @codef(*obarray*@pragma(defn)@index(*obarray*)) @dash the object hash table @codef(*standard-input*@pragma(defn)@index(*standard-input*)) @dash the standard input stream @codef(*standard-output*@pragma(defn)@index(*standard-output*)) @dash the standard output stream @codef(*error-output*@pragma(defn)@index(*error-output*)) @dash the error output stream @codef(*trace-output*@pragma(defn)@index(*trace-output*)) @dash the trace output stream @codef(*debug-io*@pragma(defn)@index(*debug-io*)) @dash the debug i/o stream @codef(*breakenable*@pragma(defn)@index(*breakenable*)) @dash flag controlling entering break loop on errors @codef(*tracelist*@pragma(defn)@index(*tracelist*)) @dash list of names of functions to trace @codef(*tracenable*@pragma(defn)@index(*tracenable*)) @dash enable trace back printout on errors @codef(*tracelimit*@pragma(defn)@index(*tracelimit*)) @dash number of levels of trace back information @codef(*evalhook*@pragma(defn)@index(*evalhook*)) @dash user substitute for the evaluator function @codef(*applyhook*@pragma(defn)@index(*applyhook*)) @dash (not yet implemented) @codef(*readtable*@pragma(defn)@index(*readtable*)) @dash the current readtable @codef(*unbound*@pragma(defn)@index(*unbound*)) @dash indicator for unbound symbols @codef(*gc-flag*@pragma(defn)@index(*gc-flag*)) @dash controls the printing of gc messages @codef(*gc-hook*@pragma(defn)@index(*gc-hook*)) @dash function to call after garbage collection @codef(*integer-format*@pragma(defn)@index(*integer-format*)) @dash format for printing integers (``%d'' or ``%ld'') @codef(*float-format*@pragma(defn)@index(*float-format*)) @dash format for printing floats (``%g'') @codef(*print-case*@pragma(defn)@index(*print-case*)) @dash symbol output case (:upcase or :downcase) @end(itemize) There are several symbols maintained by the read/eval/print loop. The symbols @code(+), @code(++), and @code(+++) are bound to the most recent three input expressions. The symbols @code(*), @code(**) and @code(***) are bound to the most recent three results. The symbol @code(-) is bound to the expression currently being evaluated. It becomes the value of @code(+) at the end of the evaluation. @section(Evaluation Functions)@index(evaluation functions) @begin(fdescription) (eval@pragma(defn)@index(eval) @i) @itemsep evaluate an xlisp expression @begin(pdescription) @i @itemsep the expression to be evaluated returns @itemsep the result of evaluating the expression @end(pdescription) @blankspace(1) (apply@pragma(defn)@index(apply) @i @i) @itemsep apply a function to a list of arguments @begin(pdescription) @i @itemsep the function to apply (or function symbol) @i @itemsep the argument list returns @itemsep the result of applying the function to the arguments @end(pdescription) @blankspace(1) (funcall@pragma(defn)@index(funcall) @i @i...) @itemsep call a function with arguments @begin(pdescription) @i @itemsep the function to call (or function symbol) @i @itemsep arguments to pass to the function returns @itemsep the result of calling the function with the arguments @end(pdescription) @blankspace(1) (quote@pragma(defn)@index(quote) @i) @itemsep return an expression unevaluated @begin(pdescription) @i @itemsep the expression to be quoted (quoted) returns @itemsep @i unevaluated @end(pdescription) @blankspace(1) (function@pragma(defn)@index(function) @i) @itemsep get the functional interpretation @begin(pdescription) @i @itemsep the symbol or lambda expression (quoted) returns @itemsep the functional interpretation @end(pdescription) @blankspace(1) (backquote@pragma(defn)@index(backquote) @i) @itemsep fill in a template @begin(pdescription) @i @itemsep the template returns @itemsep a copy of the template with comma and comma-at expressions expanded @end(pdescription) @blankspace(1) (lambda@pragma(defn)@index(lambda) @i @i...) @itemsep make a function closure @begin(pdescription) @i @itemsep formal argument list (lambda list) (quoted) @i @itemsep expressions of the function body returns @itemsep the function closure @end(pdescription) @blankspace(1) (get-lambda-expression@pragma(defn)@index(get-lambda-expression) @i) @itemsep get the lambda expression @begin(pdescription) @i @itemsep the closure returns @itemsep the original lambda expression @end(pdescription) @blankspace(1) (macroexpand@pragma(defn)@index(macroexpand) @i) @itemsep recursively expand macro calls @begin(pdescription) @i @itemsep the form to expand returns @itemsep the macro expansion @end(pdescription) @blankspace(1) (macroexpand-1@pragma(defn)@index(macroexpand-1) @i) @itemsep expand a macro call @begin(pdescription) @i @itemsep the macro call form returns @itemsep the macro expansion @end(pdescription) @blankspace(1) @end(fdescription) @section(Symbol Functions)@index(Symbol Functions) @begin(fdescription) (set@pragma(defn)@index(set) @i @i) @itemsep set the value of a symbol @begin(pdescription) @i @itemsep the symbol being set @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) (setq@pragma(defn)@index(setq) [@i @i]...) @itemsep set the value of a symbol @begin(pdescription) @i @itemsep the symbol being set (quoted) @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) (psetq@pragma(defn)@index(psetq) [@i @i]...) @itemsep parallel version of setq @begin(pdescription) @i @itemsep the symbol being set (quoted) @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) (setf@pragma(defn)@index(setf) [@i @i]...) @itemsep set the value of a field @begin(pdescription) @i @itemsep the field specifier (quoted): @begin(pdescription) @i @itemsep set value of a symbol (car @i) @itemsep set car of a cons node (cdr @i) @itemsep set cdr of a cons node (nth @i @i) @itemsep set nth car of a list (aref @i @i) @itemsep set nth element of an array (get @i @i) @itemsep set value of a property (symbol-value @i) @itemsep set value of a symbol (symbol-function @i) @itemsep set functional value of a symbol (symbol-plist @i) @itemsep set property list of a symbol @end(pdescription)@pragma(stopcodef) @i @itemsep the new value returns @itemsep the new value @end(pdescription) @blankspace(1) @begin(fgroup) (defun@pragma(defn)@index(defun) @i @i @i...) @itemsep define a function @pragma(startcodef) (defmacro@pragma(defn)@index(defmacro) @i @i @i...) @itemsep define a macro @end(fgroup) @begin(pdescription) @i @itemsep symbol being defined (quoted) @i @itemsep formal argument list (lambda list) (quoted) @i @itemsep expressions constituting the body of the function (quoted) returns @itemsep the function symbol @end(pdescription) @blankspace(1) (gensym@pragma(defn)@index(gensym) [@i]) @itemsep generate a symbol @begin(pdescription) @i @itemsep string or number returns @itemsep the new symbol @end(pdescription) @blankspace(1) (intern@pragma(defn)@index(intern) @i) @itemsep make an interned symbol @begin(pdescription) @i @itemsep the symbol's print name string returns @itemsep the new symbol @end(pdescription) @blankspace(1) (make-symbol@pragma(defn)@index(make-symbol) @i) @itemsep make an uninterned symbol @begin(pdescription) @i @itemsep the symbol's print name string returns @itemsep the new symbol @end(pdescription) @blankspace(1) (symbol-name@pragma(defn)@index(symbol-name) @i) @itemsep get the print name of a symbol @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's print name @end(pdescription) @blankspace(1) (symbol-value@pragma(defn)@index(symbol-value) @i) @itemsep get the value of a symbol @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's value @end(pdescription) @blankspace(1) (symbol-function@pragma(defn)@index(symbol-function) @i) @itemsep get the functional value of a symbol @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's functional value @end(pdescription) @blankspace(1) (symbol-plist@pragma(defn)@index(symbol-plist) @i) @itemsep get the property list of a symbol @begin(pdescription) @i @itemsep the symbol returns @itemsep the symbol's property list @end(pdescription) @blankspace(1) (hash@pragma(defn)@index(hash) @i @i) @itemsep compute the hash index for a symbol @begin(pdescription) @i @itemsep the symbol or string @i @itemsep the table size (integer) returns @itemsep the hash index (integer) @end(pdescription) @blankspace(1) @end(fdescription) @section(Property List Functions)@index(Property List Functions) @begin(fdescription) (get@pragma(defn)@index(get) @i @i) @itemsep get the value of a property @begin(pdescription) @i @itemsep the symbol @i @itemsep the property symbol returns @itemsep the property value or @xlcode(nil) @end(pdescription) @blankspace(1) (putprop@pragma(defn)@index(putprop) @i @i @i) @itemsep put a property onto a property list @begin(pdescription) @i @itemsep the symbol @i @itemsep the property value @i @itemsep the property symbol returns @itemsep the property value @end(pdescription) @blankspace(1) (remprop@pragma(defn)@index(remprop) @i @i) @itemsep remove a property @begin(pdescription) @i @itemsep the symbol @i @itemsep the property symbol returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) @end(fdescription) @section(Array Functions)@index(Array Functions) @begin(fdescription) (aref@pragma(defn)@index(aref) @i @i) @itemsep get the nth element of an array @begin(pdescription) @i @itemsep the array @i @itemsep the array index (integer) returns @itemsep the value of the array element @end(pdescription) @blankspace(1) (make-array@pragma(defn)@index(make-array) @i) @itemsep make a new array @begin(pdescription) @i @itemsep the size of the new array (integer) returns @itemsep the new array @end(pdescription) @blankspace(1) (vector@pragma(defn)@index(vector) @i...) @itemsep make an initialized vector @begin(pdescription) @i @itemsep the vector elements returns @itemsep the new vector @end(pdescription) @blankspace(1) @end(fdescription) @section(List Functions)@index(List Functions) @begin(fdescription) (car@pragma(defn)@index(car) @i) @itemsep return the car of a list node @begin(pdescription) @i @itemsep the list node returns @itemsep the car of the list node @end(pdescription) @blankspace(1) (cdr@pragma(defn)@index(cdr) @i) @itemsep return the cdr of a list node @begin(pdescription) @i @itemsep the list node returns @itemsep the cdr of the list node @end(pdescription) @blankspace(1) (c@i(xx)r@index(cxxr) @i) @itemsep all c@i(xx)r combinations @begin(pdescription) @end(pdescription) @blankspace(1) (c@i(xxx)r@index(cxxxr) @i) @itemsep all c@i(xxx)r combinations @begin(pdescription) @end(pdescription) @blankspace(1) (c@i(xxxx)r@index(cxxxxr) @i) @itemsep all c@i(xxxx)r combinations @begin(pdescription) @end(pdescription) @blankspace(1) (first@pragma(defn)@index(first) @i) @itemsep a synonym for car @begin(pdescription) @end(pdescription) @blankspace(1) (second@pragma(defn)@index(second) @i) @itemsep a synonym for cadr @begin(pdescription) @end(pdescription) @blankspace(1) (third@pragma(defn)@index(third) @i) @itemsep a synonym for caddr @begin(pdescription) @end(pdescription) @blankspace(1) (fourth@pragma(defn)@index(fourth) @i) @itemsep a synonym for cadddr @begin(pdescription) @end(pdescription) @blankspace(1) (rest@pragma(defn)@index(rest) @i) @itemsep a synonym for cdr @begin(pdescription) @end(pdescription) @blankspace(1) (cons@pragma(defn)@index(cons) @i @i) @itemsep construct a new list node @begin(pdescription) @i @itemsep the car of the new list node @i @itemsep the cdr of the new list node returns @itemsep the new list node @end(pdescription) @blankspace(1) (list@pragma(defn)@index(list) @i...) @itemsep create a list of values @begin(pdescription) @i @itemsep expressions to be combined into a list returns @itemsep the new list @end(pdescription) @blankspace(1) (append@pragma(defn)@index(append) @i...) @itemsep append lists @begin(pdescription) @i @itemsep lists whose elements are to be appended returns @itemsep the new list @end(pdescription) @blankspace(1) (reverse@pragma(defn)@index(reverse) @i) @itemsep reverse a list @begin(pdescription) @i @itemsep the list to reverse returns @itemsep a new list in the reverse order @end(pdescription) @blankspace(1) (last@pragma(defn)@index(last) @i) @itemsep return the last list node of a list @begin(pdescription) @i @itemsep the list returns @itemsep the last list node in the list @end(pdescription) @blankspace(1) (member@pragma(defn)@index(member) @i @i &key :test :test-not) @itemsep find an expression in a list @begin(pdescription) @i @itemsep the expression to find @i @itemsep the list to search :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the remainder of the list starting with the expression @end(pdescription) @blankspace(1) (assoc@pragma(defn)@index(assoc) @i @i &key :test :test-not) @itemsep find an expression in an a-list @begin(pdescription) @i @itemsep the expression to find @i @itemsep the association list :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the alist entry or @xlcode(nil) @end(pdescription) @blankspace(1) (remove@pragma(defn)@index(remove) @i @i &key :test :test-not) @itemsep remove elements from a list @begin(pdescription) @i @itemsep the element to remove @i @itemsep the list :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep copy of list with matching expressions removed @end(pdescription) @blankspace(1) (remove-if@pragma(defn)@index(remove-if) @i @i) @itemsep remove elements that pass test @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep copy of list with matching elements removed @end(pdescription) @blankspace(1) (remove-if-not@pragma(defn)@index(remove-if-not) @i @i) @itemsep remove elements that fail test @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep copy of list with non-matching elements removed @end(pdescription) @blankspace(1) (length@pragma(defn)@index(length) @i) @itemsep find the length of a list, vector or string @begin(pdescription) @i @itemsep the list, vector or string returns @itemsep the length of the list, vector or string @end(pdescription) @blankspace(1) (nth@pragma(defn)@index(nth) @i @i) @itemsep return the nth element of a list @begin(pdescription) @i @itemsep the number of the element to return (zero origin) @i @itemsep the list returns @itemsep the nth element or @xlcode(nil) if the list isn't that long @end(pdescription) @blankspace(1) (nthcdr@pragma(defn)@index(nthcdr) @i @i) @itemsep return the nth cdr of a list @begin(pdescription) @i @itemsep the number of the element to return (zero origin) @i @itemsep the list returns @itemsep the nth cdr or @xlcode(nil) if the list isn't that long @end(pdescription) @blankspace(1) (mapc@pragma(defn)@index(mapc) @i @i @i...) @itemsep apply function to successive cars @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep the first list of arguments @end(pdescription) @blankspace(1) (mapcar@pragma(defn)@index(mapcar) @i @i @i...) @itemsep apply function to successive cars @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep a list of the values returned @end(pdescription) @blankspace(1) (mapl@pragma(defn)@index(mapl) @i @i @i...) @itemsep apply function to successive cdrs @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep the first list of arguments @end(pdescription) @blankspace(1) (maplist@pragma(defn)@index(maplist) @i @i @i...) @itemsep apply function to successive cdrs @begin(pdescription) @i @itemsep the function or function name @i @itemsep a list for each argument of the function returns @itemsep a list of the values returned @end(pdescription) @blankspace(1) (subst@pragma(defn)@index(subst) @i @i @i &key :test :test-not) @itemsep substitute expressions @begin(pdescription) @i @itemsep the new expression @i @itemsep the old expression @i @itemsep the expression in which to do the substitutions :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the expression with substitutions @end(pdescription) @blankspace(1) (sublis@pragma(defn)@index(sublis) @i @i &key :test :test-not) @itemsep substitute with an a-list @begin(pdescription) @i @itemsep the association list @i @itemsep the expression in which to do the substitutions :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the expression with substitutions @end(pdescription) @blankspace(1) @end(fdescription) @section(Destructive List Functions)@index(Destructive List Functions) @begin(fdescription) (rplaca@pragma(defn)@index(rplaca) @i @i) @itemsep replace the car of a list node @begin(pdescription) @i @itemsep the list node @i @itemsep the new value for the car of the list node returns @itemsep the list node after updating the car @end(pdescription) @blankspace(1) (rplacd@pragma(defn)@index(rplacd) @i @i) @itemsep replace the cdr of a list node @begin(pdescription) @i @itemsep the list node @i @itemsep the new value for the cdr of the list node returns @itemsep the list node after updating the cdr @end(pdescription) @blankspace(1) (nconc@pragma(defn)@index(nconc) @i...) @itemsep destructively concatenate lists @begin(pdescription) @i @itemsep lists to concatenate returns @itemsep the result of concatenating the lists @end(pdescription) @blankspace(1) (delete@pragma(defn)@index(delete) @i &key :test :test-not) @itemsep delete elements from a list @begin(pdescription) @i @itemsep the element to delete @i @itemsep the list :test @itemsep the test function (defaults to eql) :test-not @itemsep the test function (sense inverted) returns @itemsep the list with the matching expressions deleted @end(pdescription) @blankspace(1) (delete-if@pragma(defn)@index(delete-if) @i @i) @itemsep delete elements that pass test @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep the list with matching elements deleted @end(pdescription) @blankspace(1) (delete-if-not@pragma(defn)@index(delete-if-not) @i @i) @itemsep delete elements that fail test @begin(pdescription) @i @itemsep the test predicate @i @itemsep the list returns @itemsep the list with non-matching elements deleted @end(pdescription) @blankspace(1) (sort@pragma(defn)@index(sort) @i @i) @itemsep sort a list @begin(pdescription) @i @itemsep the list to sort @i @itemsep the comparison function returns @itemsep the sorted list @end(pdescription) @blankspace(1) @end(fdescription) @section(Predicate Functions)@index(Predicate Functions) @begin(fdescription) (atom@pragma(defn)@index(atom) @i) @itemsep is this an atom? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an atom, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (symbolp@pragma(defn)@index(symbolp) @i) @itemsep is this a symbol? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the expression is a symbol, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (numberp@pragma(defn)@index(numberp) @i) @itemsep is this a number? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the expression is a number, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (null@pragma(defn)@index(null) @i) @itemsep is this an empty list? @begin(pdescription) @i @itemsep the list to check returns @itemsep @xlcode(t) if the list is empty, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (not@pragma(defn)@index(not) @i) @itemsep is this false? @begin(pdescription) @i @itemsep the expression to check return @itemsep @xlcode(t) if the value is @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (listp@pragma(defn)@index(listp) @i) @itemsep is this a list? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a cons or @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (endp@pragma(defn)@index(endp) @i) @itemsep is this the end of a list @begin(pdescription) @i @itemsep the list returns @itemsep @xlcode(t) if the value is @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (consp@pragma(defn)@index(consp) @i) @itemsep is this a non-empty list? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a cons, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (integerp@pragma(defn)@index(integerp) @i) @itemsep is this an integer? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an integer, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (floatp@pragma(defn)@index(floatp) @i) @itemsep is this a float? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a float, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (stringp@pragma(defn)@index(stringp) @i) @itemsep is this a string? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a string, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (characterp@pragma(defn)@index(characterp) @i) @itemsep is this a character? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a character, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (arrayp@pragma(defn)@index(arrayp) @i) @itemsep is this an array? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an array, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (streamp@pragma(defn)@index(streamp) @i) @itemsep is this a stream? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is a stream, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (objectp@pragma(defn)@index(objectp) @i) @itemsep is this an object? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an object, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (filep@pragma(defn)@index(filep) @i)@foot(This is not part of standard XLISP nor is it built-in. Nyquist defines it though.) @itemsep is this a file? @begin(pdescription) @i @itemsep the expression to check returns @itemsep @xlcode(t) if the value is an object, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (boundp@pragma(defn)@index(boundp) @i) @itemsep is a value bound to this symbol? @begin(pdescription) @i @itemsep the symbol returns @itemsep @xlcode(t) if a value is bound to the symbol, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (fboundp@pragma(defn)@index(fboundp) @i) @itemsep is a functional value bound to this symbol? @begin(pdescription) @i @itemsep the symbol returns @itemsep @xlcode(t) if a functional value is bound to the symbol, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (minusp@pragma(defn)@index(minusp) @i) @itemsep is this number negative? @begin(pdescription) @i @itemsep the number to test returns @itemsep @xlcode(t) if the number is negative, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (zerop@pragma(defn)@index(zerop) @i) @itemsep is this number zero? @begin(pdescription) @i @itemsep the number to test returns @itemsep @xlcode(t) if the number is zero, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (plusp@pragma(defn)@index(plusp) @i) @itemsep is this number positive? @begin(pdescription) @i @itemsep the number to test returns @itemsep @xlcode(t) if the number is positive, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (evenp@pragma(defn)@index(evenp) @i) @itemsep is this integer even? @begin(pdescription) @i @itemsep the integer to test returns @itemsep @xlcode(t) if the integer is even, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (oddp@pragma(defn)@index(oddp) @i) @itemsep is this integer odd? @begin(pdescription) @i @itemsep the integer to test returns @itemsep @xlcode(t) if the integer is odd, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (eq@pragma(defn)@index(eq) @i @i) @itemsep are the expressions identical? @begin(pdescription) @i @itemsep the first expression @i @itemsep the second expression returns @itemsep @xlcode(t) if they are equal, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (eql@pragma(defn)@index(eql) @i @i) @itemsep are the expressions identical? (works with all numbers) @begin(pdescription) @i @itemsep the first expression @i @itemsep the second expression returns @itemsep @xlcode(t) if they are equal, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (equal@pragma(defn)@index(equal) @i @i) @itemsep are the expressions equal? @begin(pdescription) @i @itemsep the first expression @i @itemsep the second expression returns @itemsep @xlcode(t) if they are equal, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @end(fdescription) @section(Control Constructs)@index(Control Constructs) @begin(fdescription) (cond@pragma(defn)@index(cond) @i...) @itemsep evaluate conditionally @begin(pdescription) @i @itemsep pair consisting of: @begin(pdescription) (@i @i...) @end(pdescription)@pragma(stopcodef) where: @begin(pdescription) @i @itemsep is a predicate expression @i @itemsep evaluated if the predicate is not @xlcode(nil) @end(pdescription)@pragma(stopcodef) returns @itemsep the value of the first expression whose predicate is not @xlcode(nil) @end(pdescription) @blankspace(1) (and@pragma(defn)@index(and) @i...) @itemsep the logical and of a list of expressions @begin(pdescription) @i @itemsep the expressions to be anded returns @itemsep @xlcode(nil) if any expression evaluates to @xlcode(nil), otherwise the value of the last expression (evaluation of expressions stops after the first expression that evaluates to @xlcode(nil)) @end(pdescription) @blankspace(1) (or@pragma(defn)@index(or) @i...) @itemsep the logical or of a list of expressions @begin(pdescription) @i @itemsep the expressions to be ored returns @itemsep @xlcode(nil) if all expressions evaluate to @xlcode(nil), otherwise the value of the first non-@xlcode(nil) expression (evaluation of expressions stops after the first expression that does not evaluate to @xlcode(nil)) @end(pdescription) @blankspace(1) (if@pragma(defn)@index(if) @i @i [@i]) @itemsep evaluate expressions conditionally @begin(pdescription) @i @itemsep the test expression @i @itemsep the expression to be evaluated if texpr is non-@xlcode(nil) @i @itemsep the expression to be evaluated if texpr is @xlcode(nil) returns @itemsep the value of the selected expression @end(pdescription) @blankspace(1) (when@pragma(defn)@index(when) @i @i...) @itemsep evaluate only when a condition is true @begin(pdescription) @i @itemsep the test expression @i @itemsep the expression(s) to be evaluated if texpr is non-@xlcode(nil) returns @itemsep the value of the last expression or @xlcode(nil) @end(pdescription) @blankspace(1) (unless@pragma(defn)@index(unless) @i @i...) @itemsep evaluate only when a condition is false @begin(pdescription) @i @itemsep the test expression @i @itemsep the expression(s) to be evaluated if texpr is @xlcode(nil) returns @itemsep the value of the last expression or @xlcode(nil) @end(pdescription) @blankspace(1) (case@pragma(defn)@index(case) @i @i...) @itemsep select by case @begin(pdescription) @i @itemsep the selection expression @i @itemsep pair consisting of: @begin(pdescription) (@i @i...) @end(pdescription)@pragma(stopcodef) where: @begin(pdescription) @i @itemsep is a single expression or a list of expressions (unevaluated) @i @itemsep are expressions to execute if the case matches @end(pdescription)@pragma(stopcodef) returns @itemsep the value of the last expression of the matching case @end(pdescription) @blankspace(1) @begin(fgroup) (let@pragma(defn)@index(let) (@i...) @i...) @itemsep create local bindings @pragma(startcodef) (let*@pragma(defn)@index(let*) (@i...) @i...) @itemsep let with sequential binding @end(fgroup) @begin(pdescription) @i @itemsep the variable bindings each of which is either: @begin(pdescription) 1) a symbol (which is initialized to @xlcode(nil)) 2) a list whose car is a symbol and whose cadr is an initialization expression @end(pdescription)@pragma(stopcodef) @i @itemsep the expressions to be evaluated returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) @begin(fgroup) (flet@pragma(defn)@index(flet) (@i...) @i...) @itemsep create local functions @pragma(startcodef) (labels@pragma(defn)@index(labels) (@i...) @i...) @itemsep flet with recursive functions @pragma(startcodef) (macrolet@pragma(defn)@index(macrolet) (@i...) @i...) @itemsep create local macros @end(fgroup) @begin(pdescription) @i @itemsep the function bindings each of which is: @begin(pdescription) (@i @i @i...) @end(pdescription)@pragma(stopcodef) where: @begin(pdescription) @i @itemsep the function/macro name @i @itemsep formal argument list (lambda list) @i @itemsep expressions constituting the body of the function/macro @end(pdescription)@pragma(stopcodef) @i @itemsep the expressions to be evaluated returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) (catch@pragma(defn)@index(catch) @i @i...) @itemsep evaluate expressions and catch throws @begin(pdescription) @i @itemsep the catch tag @i @itemsep expressions to evaluate returns @itemsep the value of the last expression the throw expression @end(pdescription) @blankspace(1) (throw@pragma(defn)@index(throw) @i [@i]) @itemsep throw to a catch @begin(pdescription) @i @itemsep the catch tag @i @itemsep the value for the catch to return (defaults to @xlcode(nil)) returns @itemsep never returns @end(pdescription) @blankspace(1) (unwind-protect@pragma(defn)@index(unwind-protect) @i @i...) @itemsep protect evaluation of an expression @begin(pdescription) @i @itemsep the expression to protect @i @itemsep the cleanup expressions returns @itemsep the value of the expression@* Note: unwind-protect guarantees to execute the cleanup expressions even if a non-local exit terminates the evaluation of the protected expression @end(pdescription) @blankspace(1) @end(fdescription) @section(Looping Constructs)@index(Looping Constructs) @begin(fdescription) (loop@pragma(defn)@index(loop) @i...) @itemsep basic looping form @begin(pdescription) @i @itemsep the body of the loop returns @itemsep never returns (must use non-local exit) @end(pdescription) @blankspace(1) @begin(fgroup) (do@pragma(defn)@index(do) (@i...) (@i @i...) @i...) @pragma(endcodef) (do*@pragma(defn)@index(do*) (@i...) (@i @i...) @i...) @end(fgroup) @begin(pdescription) @i @itemsep the variable bindings each of which is either: @begin(pdescription) 1) a symbol (which is initialized to @xlcode(nil)) 2) a list of the form: (@i @i [@i]) where: @begin(pdescription) @i @itemsep is the symbol to bind @i @itemsep is the initial value of the symbol @i @itemsep is a step expression @end(pdescription) @end(pdescription)@pragma(stopcodef) @i @itemsep the termination test expression @i @itemsep result expressions (the default is @xlcode(nil)) @i @itemsep the body of the loop (treated like an implicit prog) returns @itemsep the value of the last result expression @end(pdescription) @blankspace(1) (dolist@pragma(defn)@index(dolist) (@i @i [@i]) @i...) @itemsep loop through a list @begin(pdescription) @i @itemsep the symbol to bind to each list element @i @itemsep the list expression @i @itemsep the result expression (the default is @xlcode(nil)) @i @itemsep the body of the loop (treated like an implicit prog) @end(pdescription) @blankspace(1) (dotimes@pragma(defn)@index(dotimes) (@i @i [@i]) @i...) @itemsep loop from zero to n-1 @begin(pdescription) @i @itemsep the symbol to bind to each value from 0 to n-1 @i @itemsep the number of times to loop @i @itemsep the result expression (the default is @xlcode(nil)) @i @itemsep the body of the loop (treated like an implicit prog) @end(pdescription) @blankspace(1) @end(fdescription) @section(The Program Feature)@index(The Program Feature) @begin(fdescription) @begin(fgroup) (prog@pragma(defn)@index(prog) (@i...) @i...) @itemsep the program feature @pragma(startcodef) (prog*@pragma(defn)@index(prog*) (@i...) @i...) @itemsep prog with sequential binding @end(fgroup) @begin(pdescription) @i @itemsep the variable bindings each of which is either: @begin(pdescription) 1) a symbol (which is initialized to @xlcode(nil)) 2) a list whose car is a symbol and whose cadr is an initialization expression @end(pdescription)@pragma(stopcodef) @i @itemsep expressions to evaluate or tags (symbols) returns @itemsep @xlcode(nil) or the argument passed to the return function @end(pdescription) @blankspace(1) (block@pragma(defn)@index(block) @i @i...) @itemsep named block @begin(pdescription) @i @itemsep the block name (symbol) @i @itemsep the block body returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) (return@pragma(defn)@index(return) [@i]) @itemsep cause a prog construct to return a value @begin(pdescription) @i @itemsep the value (defaults to @xlcode(nil)) returns @itemsep never returns @end(pdescription) @blankspace(1) (return-from@pragma(defn)@index(return-from) @i [@i]) @itemsep return from a named block @begin(pdescription) @i @itemsep the block name (symbol) @i @itemsep the value to return (defaults to @xlcode(nil)) returns @itemsep never returns @end(pdescription) @blankspace(1) (tagbody@pragma(defn)@index(tagbody) @i...) @itemsep block with labels @begin(pdescription) @i @itemsep expression(s) to evaluate or tags (symbols) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (go@pragma(defn)@index(go) @i) @itemsep go to a tag within a tagbody or prog @begin(pdescription) @i @itemsep the tag (quoted) returns @itemsep never returns @end(pdescription) @blankspace(1) (progv@pragma(defn)@index(progv) @i @i @i...) @itemsep dynamically bind symbols @begin(pdescription) @i @itemsep list of symbols @i @itemsep list of values to bind to the symbols @i @itemsep expression(s) to evaluate returns @itemsep the value of the last expression @end(pdescription) @blankspace(1) (prog1@pragma(defn)@index(prog1) @i @i...) @itemsep execute expressions sequentially @begin(pdescription) @i @itemsep the first expression to evaluate @i @itemsep the remaining expressions to evaluate returns @itemsep the value of the first expression @end(pdescription) @blankspace(1) (prog2@pragma(defn)@index(prog2) @i @i @i...) @itemsep execute expressions sequentially @begin(pdescription) @i @itemsep the first expression to evaluate @i @itemsep the second expression to evaluate @i @itemsep the remaining expressions to evaluate returns @itemsep the value of the second expression @end(pdescription) @blankspace(1) (progn@pragma(defn)@index(progn) @i...) @itemsep execute expressions sequentially @begin(pdescription) @i @itemsep the expressions to evaluate returns @itemsep the value of the last expression (or @xlcode(nil)) @end(pdescription) @blankspace(1) @end(fdescription) @section(Debugging and Error Handling)@index(Debugging)@index(Error Handling) @begin(fdescription) (trace@pragma(defn)@index(trace) @i) @itemsep add a function to the trace list @begin(pdescription) @i @itemsep the function to add (quoted) returns @itemsep the trace list @end(pdescription) @blankspace(1) (untrace@pragma(defn)@index(untrace) @i) @itemsep remove a function from the trace list @begin(pdescription) @i @itemsep the function to remove (quoted) returns @itemsep the trace list @end(pdescription) @blankspace(1) (error@pragma(defn)@index(error) @i [@i]) @itemsep signal a non-correctable error @begin(pdescription) @i @itemsep the error message string @i @itemsep the argument expression (printed after the message) returns @itemsep never returns @end(pdescription) @blankspace(1) (cerror@pragma(defn)@index(cerror) @i @i [@i]) @itemsep signal a correctable error @begin(pdescription) @i @itemsep the continue message string @i @itemsep the error message string @i @itemsep the argument expression (printed after the message) returns @itemsep @xlcode(nil) when continued from the break loop @end(pdescription) @blankspace(1) (break@pragma(defn)@index(break) [@i [@i]]) @itemsep enter a break loop @begin(pdescription) @i @itemsep the break message string (defaults to @xlcode(**break**)) @i @itemsep the argument expression (printed after the message) returns @itemsep @xlcode(nil) when continued from the break loop @end(pdescription) @blankspace(1) (clean-up@pragma(defn)@index(clean-up)) @itemsep clean-up after an error @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) (top-level@pragma(defn)@index(top-level)) @itemsep clean-up after an error and return to the top level @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) (continue@pragma(defn)@index(continue)) @itemsep continue from a correctable error @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) (errset@pragma(defn)@index(errset) @i [@i]) @itemsep trap errors @begin(pdescription) @i @itemsep the expression to execute @i @itemsep flag to control printing of the error message returns @itemsep the value of the last expression consed with @xlcode(nil) or @xlcode(nil) on error @end(pdescription) @blankspace(1) (baktrace@pragma(defn)@index(baktrace)@index(debugging)@index(stack trace) [@i]) @itemsep print n levels of trace back information @begin(pdescription) @i @itemsep the number of levels (defaults to all levels) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (evalhook@pragma(defn)@index(evalhook) @i @i @i [@i]) @itemsep evaluate with hooks @begin(pdescription) @i @itemsep the expression to evaluate @i @itemsep the value for @xlcode(*evalhook*) @i @itemsep the value for @xlcode(*applyhook*) @i @itemsep the environment (default is @xlcode(nil)) returns @itemsep the result of evaluating the expression @end(pdescription) @blankspace(1) (profile@pragma(defn)@index(profile) @i(flag))@foot(This is not a standard XLISP 2.0 function.) @itemsep turn profiling on or off. @begin(pdescription) @i @itemsep @xlcode(nil) turns profiling off, otherwise on returns @itemsep the previous state of profiling. @end(pdescription) @blankspace(1) @end(fdescription) @section(Arithmetic Functions)@index(Arithmetic Functions) @begin(fdescription) (truncate@pragma(defn)@index(truncate) @i) @itemsep truncates a floating point number to an integer @begin(pdescription) @i @itemsep the number returns @itemsep the result of truncating the number @end(pdescription) @blankspace(1) (float@pragma(defn)@index(float) @i) @itemsep converts an integer to a floating point number @begin(pdescription) @i @itemsep the number returns @itemsep the result of floating the integer @end(pdescription) @blankspace(1) (+@pragma(defn)@index(+) @i...) @itemsep add a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the addition @end(pdescription) @blankspace(1) (-@pragma(defn)@index(-) @i...) @itemsep subtract a list of numbers or negate a single number @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the subtraction @end(pdescription) @blankspace(1) (*@pragma(defn)@index(*) @i...) @itemsep multiply a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the multiplication @end(pdescription) @blankspace(1) (/@pragma(defn)@index(/) @i...) @itemsep divide a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the division @end(pdescription) @blankspace(1) (1+@pragma(defn)@index(1+) @i) @itemsep add one to a number @begin(pdescription) @i @itemsep the number returns @itemsep the number plus one @end(pdescription) @blankspace(1) (1-@pragma(defn)@index(1-) @i) @itemsep subtract one from a number @begin(pdescription) @i @itemsep the number returns @itemsep the number minus one @end(pdescription) @blankspace(1) (rem@pragma(defn)@index(rem)@index(remainder)@index(modulo (rem) function) @i...) @itemsep remainder of a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the remainder operation @end(pdescription) @blankspace(1) (min@pragma(defn)@index(min)@index(minimum) @i...) @itemsep the smallest of a list of numbers @begin(pdescription) @i @itemsep the expressions to be checked returns @itemsep the smallest number in the list @end(pdescription) @blankspace(1) (max@pragma(defn)@index(max)@index(maximum) @i...) @itemsep the largest of a list of numbers @begin(pdescription) @i @itemsep the expressions to be checked returns @itemsep the largest number in the list @end(pdescription) @blankspace(1) (abs@pragma(defn)@index(abs) @i) @itemsep the absolute value of a number @begin(pdescription) @i @itemsep the number returns @itemsep the absolute value of the number @end(pdescription) @blankspace(1) (gcd@pragma(defn)@index(gcd) @i @i...) @itemsep compute the greatest common divisor @begin(pdescription) @i @itemsep the first number (integer) @i @itemsep the second number(s) (integer) returns @itemsep the greatest common divisor @end(pdescription) @blankspace(1) (random@pragma(defn)@index(random) @i) @itemsep compute a random number between 0 and n-1 inclusive @begin(pdescription) @i @itemsep the upper bound (integer) returns @itemsep a random number @end(pdescription) @blankspace(1) (rrandom@pragma(defn)@index(rrandom)@index(uniform random)) @itemsep compute a random real number between 0 and 1 inclusive @begin(pdescription) returns @itemsep a random floating point number @end(pdescription) @blankspace(1) (sin@pragma(defn)@index(sin) @i) @itemsep compute the sine of a number @begin(pdescription) @i @itemsep the floating point number returns @itemsep the sine of the number @end(pdescription) @blankspace(1) (cos@pragma(defn)@index(cos) @i) @itemsep compute the cosine of a number @begin(pdescription) @i @itemsep the floating point number returns @itemsep the cosine of the number @end(pdescription) @blankspace(1) (tan@pragma(defn)@index(tan) @i) @itemsep compute the tangent of a number @begin(pdescription) @i @itemsep the floating point number returns @itemsep the tangent of the number @end(pdescription) @blankspace(1) (atan@pragma(defn)@index(atan) @i [@i])@foot(This is not a standard XLISP 2.0 function.) @itemsep compute the arctangent @begin(pdescription) @i @itemsep the value of @i(x) @i @itemsep the value of @i(y) (default value is 1.0) returns @itemsep the arctangent of @i(x)/@i(y) @end(pdescription) @blankspace(1) (expt@pragma(defn)@index(expt) @i @i) @itemsep compute x to the y power @begin(pdescription) @i @itemsep the floating point number @i @itemsep the floating point exponent returns @itemsep x to the y power @end(pdescription) @blankspace(1) (exp@pragma(defn)@index(exp) @i) @itemsep compute e to the x power @begin(pdescription) @i @itemsep the floating point number returns @itemsep e to the x power @end(pdescription) @blankspace(1) (sqrt@pragma(defn)@index(sqrt) @i) @itemsep compute the square root of a number @begin(pdescription) @i @itemsep the floating point number returns @itemsep the square root of the number @end(pdescription) @blankspace(1) @begin(fgroup) (<@pragma(defn)@index(<) @i @i...) @itemsep test for less than (<=@pragma(defn)@index(<=) @i @i...) @itemsep test for less than or equal to (=@pragma(defn)@index(=) @i @i...) @itemsep test for equal to (/=@pragma(defn)@index(/=) @i @i...) @itemsep test for not equal to (>=@pragma(defn)@index(>=) @i @i...) @itemsep test for greater than or equal to (>@pragma(defn)@index(>) @i @i...) @itemsep test for greater than @end(fgroup) @begin(pdescription) @i @itemsep the first number to compare @i @itemsep the second number to compare returns @itemsep @xlcode(t) if the results of comparing @i with @i, @i with @i, etc., are all true. @end(pdescription) @blankspace(1) @end(fdescription) @section(Bitwise Logical Functions)@index(Bitwise Logical Functions) @begin(fdescription) (logand@pragma(defn)@index(logand) @i...) @itemsep the bitwise and of a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the and operation @end(pdescription) @blankspace(1) (logior@pragma(defn)@index(logior) @i...) @itemsep the bitwise inclusive or of a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the inclusive or operation @end(pdescription) @blankspace(1) (logxor@pragma(defn)@index(logxor) @i...) @itemsep the bitwise exclusive or of a list of numbers @begin(pdescription) @i @itemsep the numbers returns @itemsep the result of the exclusive or operation @end(pdescription) @blankspace(1) (lognot@pragma(defn)@index(lognot) @i) @itemsep the bitwise not of a number @begin(pdescription) @i @itemsep the number returns @itemsep the bitwise inversion of number @end(pdescription) @blankspace(1) @end(fdescription) @section(String Functions)@index(String Functions) @begin(fdescription) (string@pragma(defn)@index(string) @i) @itemsep make a string from a value @begin(pdescription) @i @itemsep an integer (which is first converted into its ASCII character value), string, character, or symbol returns @itemsep the string representation of the argument @end(pdescription) @blankspace(1) (string-search@pragma(defn)@index(string-search)@index(find string) @i @i &key :start :end)@foot(This is not a standard XLISP 2.0 function.) @itemsep search for pattern in string @begin(pdescription) @i @itemsep a string to search for @i @itemsep the string to be searched :start @itemsep the starting offset in str :end @itemsep the ending offset + 1 returns @itemsep index of pat in str or NIL if not found @end(pdescription) @blankspace(1) (string-trim@pragma(defn)@index(string-trim) @i @i) @itemsep trim both ends of a string @begin(pdescription) @i @itemsep a string containing characters to trim @i @itemsep the string to trim returns @itemsep a trimed copy of the string @end(pdescription) @blankspace(1) (string-left-trim@pragma(defn)@index(string-left-trim) @i @i) @itemsep trim the left end of a string @begin(pdescription) @i @itemsep a string containing characters to trim @i @itemsep the string to trim returns @itemsep a trimed copy of the string @end(pdescription) @blankspace(1) (string-right-trim@pragma(defn)@index(string-right-trim) @i @i) @itemsep trim the right end of a string @begin(pdescription) @i @itemsep a string containing characters to trim @i @itemsep the string to trim returns @itemsep a trimed copy of the string @end(pdescription) @blankspace(1) (string-upcase@pragma(defn)@index(string-upcase) @i &key :start :end) @itemsep convert to uppercase @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep a converted copy of the string @end(pdescription) @blankspace(1) (string-downcase@pragma(defn)@index(string-downcase) @i &key :start :end) @itemsep convert to lowercase @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep a converted copy of the string @end(pdescription) @blankspace(1) (nstring-upcase@pragma(defn)@index(nstring-upcase) @i &key :start :end) @itemsep convert to uppercase @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep the converted string (not a copy) @end(pdescription) @blankspace(1) (nstring-downcase@pragma(defn)@index(nstring-downcase) @i &key :start :end) @itemsep convert to lowercase @begin(pdescription) @i @itemsep the string :start @itemsep the starting offset :end @itemsep the ending offset + 1 returns @itemsep the converted string (not a copy) @end(pdescription) @blankspace(1) (strcat@pragma(defn)@index(strcat)@index(concatenate strings) @i...) @itemsep concatenate strings @begin(pdescription) @i @itemsep the strings to concatenate returns @itemsep the result of concatenating the strings @end(pdescription) @blankspace(1) (subseq@pragma(defn)@index(subseq) @i @i [@i]) @itemsep extract a substring @begin(pdescription) @i @itemsep the string @i @itemsep the starting position (zero origin) @i @itemsep the ending position + 1 (defaults to end) returns @itemsep substring between @i and @i @end(pdescription) @blankspace(1) @begin(fgroup) (string<@pragma(defn)@index(string<) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string<=@pragma(defn)@index(string<=) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string=@pragma(defn)@index(string=) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string/=@pragma(defn)@index(string/=) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string>=@pragma(defn)@index(string>=) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string>@pragma(defn)@index(string>) @i @i &key :start1 :end1 :start2 :end2) @end(fgroup) @begin(pdescription) @i @itemsep the first string to compare @i @itemsep the second string to compare :start1 @itemsep first substring starting offset :end1 @itemsep first substring ending offset + 1 :start2 @itemsep second substring starting offset :end2 @itemsep second substring ending offset + 1 returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is significant with these comparison functions. @end(pdescription) @blankspace(1) @begin(fgroup) (string-lessp@pragma(defn)@index(string-lessp) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string-not-greaterp@pragma(defn)@index(string-not-greaterp) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string-equalp@pragma(defn)@index(string-equalp) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string-not-equalp@pragma(defn)@index(string-not-equalp) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string-not-lessp@pragma(defn)@index(string-not-lessp) @i @i &key :start1 :end1 :start2 :end2) @pragma(endcodef) (string-greaterp@pragma(defn)@index(string-greaterp) @i @i &key :start1 :end1 :start2 :end2) @end(fgroup) @begin(pdescription) @i @itemsep the first string to compare @i @itemsep the second string to compare :start1 @itemsep first substring starting offset :end1 @itemsep first substring ending offset + 1 :start2 @itemsep second substring starting offset :end2 @itemsep second substring ending offset + 1 returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is not significant with these comparison functions. @end(pdescription) @blankspace(1) @end(fdescription) @section(Character Functions)@index(Character Functions) @begin(fdescription) (char@pragma(defn)@index(char) @i @i) @itemsep extract a character from a string @begin(pdescription) @i @itemsep the string @i @itemsep the string index (zero relative) returns @itemsep the ascii code of the character @end(pdescription) @blankspace(1) (upper-case-p@pragma(defn)@index(upper-case-p) @i) @itemsep is this an upper case character? @begin(pdescription) @i @itemsep the character returns @itemsep @xlcode(t) if the character is upper case, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (lower-case-p@pragma(defn)@index(lower-case-p) @i) @itemsep is this a lower case character? @begin(pdescription) @i @itemsep the character returns @itemsep @xlcode(t) if the character is lower case, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (both-case-p@pragma(defn)@index(both-case-p) @i) @itemsep is this an alphabetic (either case) character? @begin(pdescription) @i @itemsep the character returns @itemsep @xlcode(t) if the character is alphabetic, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (digit-char-p@pragma(defn)@index(digit-char-p) @i) @itemsep is this a digit character? @begin(pdescription) @i @itemsep the character returns @itemsep the digit weight if character is a digit, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (char-code@pragma(defn)@index(char-code) @i) @itemsep get the ascii code of a character @begin(pdescription) @i @itemsep the character returns @itemsep the ascii character code (integer) @end(pdescription) @blankspace(1) (code-char@pragma(defn)@index(code-char) @i) @itemsep get the character with a specified ascii code @begin(pdescription) @i @itemsep the ascii code (integer) returns @itemsep the character with that code or @xlcode(nil) @end(pdescription) @blankspace(1) (char-upcase@pragma(defn)@index(char-upcase) @i) @itemsep convert a character to upper case @begin(pdescription) @i @itemsep the character returns @itemsep the upper case character @end(pdescription) @blankspace(1) (char-downcase@pragma(defn)@index(char-downcase) @i) @itemsep convert a character to lower case @begin(pdescription) @i @itemsep the character returns @itemsep the lower case character @end(pdescription) @blankspace(1) (digit-char@pragma(defn)@index(digit-char) @i) @itemsep convert a digit weight to a digit @begin(pdescription) @i @itemsep the digit weight (integer) returns @itemsep the digit character or @xlcode(nil) @end(pdescription) @blankspace(1) (char-int@pragma(defn)@index(char-int) @i) @itemsep convert a character to an integer @begin(pdescription) @i @itemsep the character returns @itemsep the ascii character code @end(pdescription) @blankspace(1) (int-char@pragma(defn)@index(int-char) @i) @itemsep convert an integer to a character @begin(pdescription) @i @itemsep the ascii character code returns @itemsep the character with that code @end(pdescription) @blankspace(1) @begin(fgroup) (char<@pragma(defn)@index(char<) @i @i...) @pragma(endcodef) (char<=@pragma(defn)@index(char<=) @i @i...) @pragma(endcodef) (char=@pragma(defn)@index(char=) @i @i...) @pragma(endcodef) (char/=@pragma(defn)@index(char/=) @i @i...) @pragma(endcodef) (char>=@pragma(defn)@index(char>=) @i @i...) @pragma(endcodef) (char>@pragma(defn)@index(char>) @i @i...) @end(fgroup) @begin(pdescription) @i @itemsep the first character to compare @i @itemsep the second character(s) to compare returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is significant with these comparison functions. @end(pdescription) @blankspace(1) @begin(fgroup) (char-lessp@pragma(defn)@index(char-lessp) @i @i...) @pragma(endcodef) (char-not-greaterp@pragma(defn)@index(char-not-greaterp) @i @i...) @pragma(endcodef) (char-equalp@pragma(defn)@index(char-equalp) @i @i...) @pragma(endcodef) (char-not-equalp@pragma(defn)@index(char-not-equalp) @i @i...) @pragma(endcodef) (char-not-lessp@pragma(defn)@index(char-not-lessp) @i @i...) @pragma(endcodef) (char-greaterp@pragma(defn)@index(char-greaterp) @i @i...) @end(fgroup) @begin(pdescription) @i @itemsep the first string to compare @i @itemsep the second string(s) to compare returns @itemsep @xlcode(t) if predicate is true, @xlcode(nil) otherwise Note: case is not significant with these comparison functions. @end(pdescription) @blankspace(1) @end(fdescription) @section(Input/Output Functions)@index(Input/Output Functions) @begin(fdescription) (read@pragma(defn)@index(read) [@i [@i [@i]]]) @itemsep read an expression @begin(pdescription) @i @itemsep the input stream (default is standard input) @i @itemsep the value to return on end of file (default is @xlcode(nil)) @i @itemsep recursive read flag (default is @xlcode(nil)) returns @itemsep the expression read @end(pdescription) @blankspace(1) (print@pragma(defn)@index(print) @i [@i]) @itemsep print an expression on a new line @begin(pdescription) @i @itemsep the expression to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) (prin1@pragma(defn)@index(prin1) @i [@i]) @itemsep print an expression @begin(pdescription) @i @itemsep the expression to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) (princ@pragma(defn)@index(princ) @i [@i]) @itemsep print an expression without quoting @begin(pdescription) @i @itemsep the expressions to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) (pprint@pragma(defn)@index(pprint) @i [@i]) @itemsep pretty print an expression @begin(pdescription) @i @itemsep the expressions to be printed @i @itemsep the output stream (default is standard output) returns @itemsep the expression @end(pdescription) @blankspace(1) (terpri@pragma(defn)@index(terpri) [@i]) @itemsep terminate the current print line @begin(pdescription) @i @itemsep the output stream (default is standard output) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (flatsize@pragma(defn)@index(flatsize) @i) @itemsep length of printed representation using prin1 @begin(pdescription) @i @itemsep the expression returns @itemsep the length @end(pdescription) @blankspace(1) (flatc@pragma(defn)@index(flatc) @i) @itemsep length of printed representation using princ @begin(pdescription) @i @itemsep the expression returns @itemsep the length @end(pdescription) @blankspace(1) @end(fdescription) @section(The Format Function)@index(The Format Function) @begin(fdescription) (format@pragma(defn)@index(format) @i @i @i...) @itemsep do formated output @begin(pdescription) @i @itemsep the output stream @i @itemsep the format string @i @itemsep the format arguments returns @itemsep output string if @i is @xlcode(nil), @xlcode(nil) otherwise @end(pdescription) @blankspace(1) @end(fdescription) The format string can contain characters that should be copied directly to the output and formatting directives. The formatting directives are: @begin(display) @xlcode(~A) @itemsep print next argument using princ @xlcode(~S) @itemsep print next argument using prin1 @xlcode(~%) @itemsep start a new line @xlcode(~~) @itemsep print a tilde character @xlcode(~) @itemsep ignore this one newline and white space on the next line up to the first non-white-space character or newline. This allows strings to continue across multiple lines @end(display) @section(File I/O Functions)@index(File I/O Functions) Note that files are ordinarily opened as text. Binary files (such as standard midi files) must be opened with @xlcode(open-binary) on non-unix systems. @begin(fdescription) (open@pragma(defn)@index(open) @i &key :direction) @itemsep open a file stream @begin(pdescription) @i @itemsep the file name string or symbol :direction @itemsep :input or :output (default is :input) returns @itemsep a stream @end(pdescription) @blankspace(1) (open-binary@pragma(defn)@index(open-binary)@index(open)@index(binary files) @i &key :direction) @itemsep open a binary file stream @begin(pdescription) @i @itemsep the file name string or symbol :direction @itemsep :input or :output (default is :input) returns @itemsep a stream @end(pdescription) @blankspace(1) (close@pragma(defn)@index(close) @i) @itemsep close a file stream @begin(pdescription) @i @itemsep the stream returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (setdir@pragma(defn)@index(setdir)@index(change directory) @i)@foot(This is not a standard XLISP 2.0 function.) @itemsep set current directory @begin(pdescription) @i @itemsep the path of the new directory returns @itemsep the resulting full path, e.g. (setdir ".") gets the current working directory, or @xlcode(nil) if an error occurs @end(pdescription) @blankspace(1) (listdir@pragma(defn)@index(listdir)@index(directory listing)@index(scan directory)@index(read directory)@index(list directory) @i)@foot(This is not a standard XLISP 2.0 function.) @itemsep get a directory listing @begin(pdescription) @i @itemsep the path of the directory to be listed returns @itemsep list of filenames in the directory @end(pdescription) @blankspace(1) (get-temp-path@pragma(defn)@index(get-temp-path)@index(temporary files)@index(temp file))@foot(This is not a standard XLISP 2.0 function.) @itemsep get a path where a temporary file can be created. Under Windows, this is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice @xlcode(c:\windows\). @begin(pdescription) returns @itemsep the resulting full path as a string @end(pdescription) @blankspace(1) (get-user@pragma(defn)@index(get-user)@index(user name)@index(temp file))@foot(This is not a standard XLISP 2.0 function.) @itemsep get the user ID. In Unix systems (including OS X and Linux), this is the value of the USER environment variable. In Windows, this is currently just ``nyquist'', which is also returned if the environment variable cannot be accessed. This function is used to avoid the case of two users creating files of the same name in the same temp directory. @begin(pdescription) returns @itemsep the string naming the user @end(pdescription) @blankspace(1) (find-in-xlisp-path@pragma(defn)@index(find-in-xlisp-path) @i)@foot(This is not a standard XLISP 2.0 function.) @itemsep search the XLISP search path (e.g. @xlcode(XLISPPATH) from the environment) for @i(filename). If @i(filename) is not found as is, and there is no file extension, append "@code(.lsp)" to @i(filename) and search again. The current directory is not searched. @begin(pdescription) @i @itemsep the name of the file to search for returns @itemsep a full path name to the first occurrence found @end(pdescription) @blankspace(1) (read-char@pragma(defn)@index(read-char)@index(get char) [@i]) @itemsep read a character from a stream @begin(pdescription) @i @itemsep the input stream (default is standard input) returns @itemsep the character @end(pdescription) @blankspace(1) (peek-char@pragma(defn)@index(peek-char) [@i [@i]]) @itemsep peek at the next character @begin(pdescription) @i @itemsep flag for skipping white space (default is @xlcode(nil)) @i @itemsep the input stream (default is standard input) returns @itemsep the character (integer) @end(pdescription) @blankspace(1) (write-char@pragma(defn)@index(write-char) @i [@i]) @itemsep write a character to a stream @begin(pdescription) @i @itemsep the character to write @i @itemsep the output stream (default is standard output) returns @itemsep the character @end(pdescription) @blankspace(1) (read-int@pragma(defn)@index(read-int) [@i [@i]]) @itemsep read a binary integer from a stream @begin(pdescription) @i @itemsep the input stream (default is standard input) @i @itemsep the length of the integer in bytes (default is 4) returns @itemsep the integer Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) (write-int@pragma(defn)@index(write-int) @i [@i [@i]]) @itemsep write a binary integer to a stream @begin(pdescription) @i @itemsep the character to write @i @itemsep the output stream (default is standard output) @i @itemsep the length of the integer in bytes (default is 4) returns @itemsep the integer Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) (read-float@pragma(defn)@index(read-float) [@i [@i]]) @itemsep read a binary floating-point number from a stream @begin(pdescription) @i @itemsep the input stream (default is standard input) @i @itemsep the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8) returns @itemsep the integer Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) (write-float@pragma(defn)@index(write-float) @i [@i [@i]]) @itemsep write a binary floating-point number to a stream @begin(pdescription) @i @itemsep the character to write @i @itemsep the output stream (default is standard output) @i @itemsep the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8) returns @itemsep the integer Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode. @end(pdescription) @blankspace(1) (read-line@pragma(defn)@index(read-line) [@i]) @itemsep read a line from a stream @begin(pdescription) @i @itemsep the input stream (default is standard input) returns @itemsep the string @end(pdescription) @blankspace(1) (read-byte@pragma(defn)@index(read-byte) [@i]) @itemsep read a byte from a stream @begin(pdescription) @i @itemsep the input stream (default is standard input) returns @itemsep the byte (integer) @end(pdescription) @blankspace(1) (write-byte@pragma(defn)@index(write-byte) @i [@i]) @itemsep write a byte to a stream @begin(pdescription) @i @itemsep the byte to write (integer) @i @itemsep the output stream (default is standard output) returns @itemsep the byte (integer) @end(pdescription) @blankspace(1) @end(fdescription) @section(String Stream Functions)@index(String Stream Functions) These functions operate on unnamed streams. An unnamed output stream collects characters sent to it when it is used as the destination of any output function. The functions @xlcode(get-output-stream-string) and @xlcode(get-output-stream-list) return a string or a list of characters. An unnamed input stream is setup with the @xlcode(make-string-input-stream) function and returns each character of the string when it is used as the source of any input function. @begin(fdescription) @blankspace(1) (make-string-input-stream@pragma(defn)@index(make-string-input-stream) @i [@i [@i]]) @begin(pdescription) @i @itemsep the string @i @itemsep the starting offset @i @itemsep the ending offset + 1 returns @itemsep an unnamed stream that reads from the string @end(pdescription) @blankspace(1) (make-string-output-stream)@pragma(defn)@index(make-string-output-stream) @begin(pdescription) returns @itemsep an unnamed output stream @end(pdescription) @blankspace(1) (get-output-stream-string@pragma(defn)@index(get-output-stream-string) @i) @begin(pdescription) @i @itemsep the output stream returns @itemsep the output so far as a string Note: the output stream is emptied by this function @end(pdescription) @blankspace(1) (get-output-stream-list@pragma(defn)@index(get-output-stream-list) @i) @begin(pdescription) @i @itemsep the output stream returns @itemsep the output so far as a list Note: the output stream is emptied by this function @end(pdescription) @blankspace(1) @end(fdescription) @section(System Functions)@index(System Functions) Note: the @xlcode(load) function first tries to load a file from the current directory. A @code(.lsp) extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. (The Macintosh version has no search path.) @begin(fdescription) (get-env@pragma(defn)@index(get-env)@index(getenv)@index(environment variables) @i) @itemsep get from an environment variable @begin(pdescription) @i @itemsep the name of the environment variable returns @itemsep string value of the environment variable, @xlcode(nil) if variable does not exist @end(pdescription) @blankspace(1) (load@pragma(defn)@index(load) @i &key :verbose :print) @itemsep load a source file @begin(pdescription) @i @itemsep the filename string or symbol :verbose @itemsep the verbose flag (default is t) :print @itemsep the print flag (default is @xlcode(nil)) returns @itemsep the filename @end(pdescription) @blankspace(1) (save@pragma(defn)@index(save) @i) @itemsep save workspace to a file @begin(pdescription) @i @itemsep the filename string or symbol returns @itemsep @xlcode(t) if workspace was written, @xlcode(nil) otherwise @end(pdescription) @blankspace(1) (restore@pragma(defn)@index(restore) @i) @itemsep restore workspace from a file @begin(pdescription) @i @itemsep the filename string or symbol returns @itemsep @xlcode(nil) on failure, otherwise never returns @end(pdescription) @blankspace(1) (dribble@pragma(defn)@index(dribble) [@i]) @itemsep create a file with a transcript of a session @begin(pdescription) @i @itemsep file name string or symbol (if missing, close current transcript) returns @itemsep @xlcode(t) if the transcript is opened, @xlcode(nil) if it is closed @end(pdescription) @blankspace(1) (gc@pragma(defn)@index(gc)) @itemsep force garbage collection @begin(pdescription) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (expand@pragma(defn)@index(expand) @i) @itemsep expand memory by adding segments @begin(pdescription) @i @itemsep the number of segments to add returns @itemsep the number of segments added @end(pdescription) @blankspace(1) (alloc@pragma(defn)@index(alloc) @i) @itemsep change number of nodes to allocate in each segment @begin(pdescription) @i @itemsep the number of nodes to allocate returns @itemsep the old number of nodes to allocate @end(pdescription) @blankspace(1) (info@pragma(defn)@index(info)) @itemsep show information about memory usage. @begin(pdescription) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (room@pragma(defn)@index(room)) @itemsep show memory allocation statistics @begin(pdescription) returns @itemsep @xlcode(nil) @end(pdescription) @blankspace(1) (type-of@pragma(defn)@index(type-of) @i) @itemsep returns the type of the expression @begin(pdescription) @i @itemsep the expression to return the type of returns @itemsep @xlcode(nil) if the value is @xlcode(nil) otherwise one of the symbols: @begin(pdescription) SYMBOL @itemsep for symbols OBJECT @itemsep for objects CONS @itemsep for conses SUBR @itemsep for built-in functions FSUBR @itemsep for special forms CLOSURE @itemsep for defined functions STRING @itemsep for strings FIXNUM @itemsep for integers FLONUM @itemsep for floating point numbers CHARACTER @itemsep for characters FILE-STREAM @itemsep for file pointers UNNAMED-STREAM @itemsep for unnamed streams ARRAY @itemsep for arrays @end(pdescription) @end(pdescription) @blankspace(1) (peek@pragma(defn)@index(peek) @i) @itemsep peek at a location in memory @begin(pdescription) @i @itemsep the address to peek at (integer) returns @itemsep the value at the specified address (integer) @end(pdescription) @blankspace(1) (poke@pragma(defn)@index(poke) @i @i) @itemsep poke a value into memory @begin(pdescription) @i @itemsep the address to poke (integer) @i @itemsep the value to poke into the address (integer) returns @itemsep the value @end(pdescription) @blankspace(1) (bigendianp@pragma(defn)@index(bigendianp)@index(endian)@index(big endian)@index(little endian)) @itemsep is this a big-endian machine? @begin(pdescription) returns @itemsep T if this a big-endian architecture, storing the high-order byte of an integer at the lowest byte address of the integer; otherwise, NIL. @foot(This is not a standard XLISP 2.0 function.) @end(pdescription) @blankspace(1) (address-of@pragma(defn)@index(address-of) @i) @itemsep get the address of an xlisp node @begin(pdescription) @i @itemsep the node returns @itemsep the address of the node (integer) @end(pdescription) @blankspace(1) (exit@pragma(defn)@index(exit)) @itemsep exit xlisp @begin(pdescription) returns @itemsep never returns @end(pdescription) @blankspace(1) (setup-console@pragma(defn)@index(setup-console)@index(window initialization)) @itemsep set default console attributes @begin(pdescription) returns @itemsep NIL Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of ``Nyquist.'' This is normally accomplished by calling @xlcode(setup-console) in @code(system.lsp). In Nyquist, you can avoid this behavior by setting @xlcode(*setup-console*) to NIL in your @code(init.lsp) file. If @xlcode(setup-console) is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.@index(emacs, using Nyquist with) @end(pdescription) @blankspace(1) (echoenabled@pragma(defn)@index(echoenabled)@index(console, XLISP) @i) @itemsep turn console input echoing on or off @begin(pdescription) @i @itemsep T to enable echo, NIL to disable returns @itemsep NIL Note: This function is only implemented under Linux and Mac OS X. If Nyquist I/O is redirected through pipes, the Windows version does not echo the input, but the Linux and Mac versions do. You can turn off echoing with this function. Under windows it is defined to do nothing. @end(pdescription) @end(fdescription) @section(File I/O Functions)@index(File I/O Functions) @subsection(Input from a File)@index(Input from a File) To open a file for input, use the @xlcode(open) function with the keyword argument @xlcode(:direction) set to @xlcode(:input). To open a file for output, use the @xlcode(open) function with the keyword argument @xlcode(:direction) set to @xlcode(:output). The @xlcode(open) function takes a single required argument which is the name of the file to be opened. This name can be in the form of a string or a symbol. The @xlcode(open) function returns an object of type @xlcode(FILE-STREAM) if it succeeds in opening the specified file. It returns the value @xlcode(nil) if it fails. In order to manipulate the file, it is necessary to save the value returned by the @xlcode(open) function. This is usually done by assigning it to a variable with the @xlcode(setq) special form or by binding it using @xlcode(let) or @xlcode(let*). Here is an example: @begin(example) (setq fp (open "init.lsp" :direction :input)) @end(example) Evaluating this expression will result in the file @code(init.lsp) being opened. The file object that will be returned by the @xlcode(open) function will be assigned to the variable @xlcode(fp). It is now possible to use the file for input. To read an expression from the file, just supply the value of the @xlcode(fp) variable as the optional @i(stream) argument to @xlcode(read). @begin(example) (read fp) @end(example) Evaluating this expression will result in reading the first expression from the file @code(init.lsp). The expression will be returned as the result of the @xlcode(read) function. More expressions can be read from the file using further calls to the @xlcode(read) function. When there are no more expressions to read, the @xlcode(read) function will return @xlcode(nil) (or whatever value was supplied as the second argument to @xlcode(read)). Once you are done reading from the file, you should close it. To close the file, use the following expression: @begin(example) (close fp) @end(example) Evaluating this expression will cause the file to be closed. @subsection(Output to a File)@index(Output to a File) Writing to a file is pretty much the same as reading from one. You need to open the file first. This time you should use the @xlcode(open) function to indicate that you will do output to the file. For example: @begin(example) (setq fp (open "test.dat" :direction :output)) @end(example) Evaluating this expression will open the file @code(test.dat) for output. If the file already exists, its current contents will be discarded. If it doesn't already exist, it will be created. In any case, a @xlcode(FILE-STREAM) object will be returned by the @xlcode(OPEN) function. This file object will be assigned to the @xlcode(fp) variable. It is now possible to write to this file by supplying the value of the @xlcode(fp) variable as the optional @i(stream) parameter in the @xlcode(print) function. @begin(example) (print "Hello there" fp) @end(example) Evaluating this expression will result in the string ``Hello there'' being written to the file @code(test.dat). More data can be written to the file using the same technique. Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file. @begin(example) (close fp) @end(example) Evaluating this expression will close the output file and make it permanent. @subsection(A Slightly More Complicated File Example) This example shows how to open a file, read each Lisp expression from the file and print it. It demonstrates the use of files and the use of the optional @i(stream) argument to the @xlcode(read) function. @begin(programexample) (do* ((fp (open "test.dat" :direction :input)) (ex (read fp) (read fp))) ((null ex) nil) (print ex)) @end(programexample) nyquist-3.05/docsrc/xlisp/xlisp-doc/0002755000175000000620000000000011537433125016507 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/objects/0002755000175000000620000000000011537433125020140 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/objects/smalltalk.htm0000644000175000000620000003325711512762341022644 0ustar stevestaff Smalltalk Object Model Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    The Smalltalk Object Model


    This page is based on a document written by Glenn Hollowell:

    The original document has been adapted for use with the XLISP 2.0 object system.


    1  Basic Concepts


    Within the context of Smalltalk, objects are implemented in code through encapsulation and polymorphism.

    Encapsulation is the approach used in Smalltalk to bundle everything needed into an object to preserve the integrity of the enclosed data. The code within an object performs operations on the objects internal data. Operations in Smalltalk are performed as the result of a messages being sent to an object to execute a specific portion of its code, usually called a 'method'.

    Polymorphism is the way that the Smalltalk language allows methods of the same name to have predictable and meaningful results in related instances, yet perform the operations differently to achieve the results.

    Polymorphism is typically implemented in Smalltalk through the abstraction of the common properties of a group of objects into classes and hierarchically subclassing shared properties using inheritance, along with specialization of the subclass to define the differences.

    Classes serve as templates because they define the instance variables for all the class instance variables and methods. The instance of a class is created by sending a :new message to the class which uniquely identifies the object instance and allocates space for its variables.

      Back to top


    2  Objects


    An object is an encapsulated software component made up of memory and operations that creates a coherent programming entity. All objects are an instance of a class. Objects have public and private properties. An object's implementation details are private and are hidden from other objects.

    • An object's public properties are its messages that make up its interface.

    • The object's private properties are its variables.

    Interaction with an object only occurs via these messages to its interface. All object instances of a given class have a common message interface.

      Back to top


    2.1  Operations


    An operation is the action taken by an object instance as result of a message being received through the object's interface. Messages requesting operations are addressed to specific recipient object instances, thus Smalltalk uses the 'classical' object model and the method to execute in response to a message is determined by searching the object's class hierarchy.

      Back to top


    2.2  Requests


    A request is act of sending a message to an object's interface with the expectation that the object will perform a known operation that is associated with the message.

      Back to top


    2.3  Messages


    A message is a request to an object instance to perform an operation. A message expression consists of a receiver, selector [message name], and potentially some arguments. The selector must be mapped to a method of the same name, encapsulated in the receiver object's class hierarchy. The arguments, if any, are used by the method to perform its operation.

    (send receiver :selector [arguments])
    

    In Smalltalk there exist several message types, like unary, binary, and keyword messages. In XLISP there is only one message type, so the description of the Smalltalk message types has been omitted from this document.

      Back to top


    2.4  Specification of Behavioral Semantics


    Behavior is defined by methods specified in classes which are implemented as class instances and execution is triggered in those instances by message requests.

      Back to top


    2.5  Methods


    A method is the executable code rendered in the class and executed in the context of an object instance. It defines how to perform an operation in the object instance. It is made up of a message pattern that is used to match against incoming messages, temporary variables, and a sequence of instructions. A method execution is triggered when message is received that matches the methods' message pattern.

      Back to top


    2.6  State


    The state of an instance is represented by the values of its instance variables.

      Back to top


    2.7  Object Lifetime


    Object instances are created with the :new method. Each object instance is given a unique identifier called an object pointer or object reference.

    New classes are created by using the "subclass" method. The "new" and "subclass" methods are inheritedby almost all classes. Every instance object pointer is also associated with an object pointer of a class. Unlike the "new" and "subclass" methods, there are no specific methods that remove an object that is no longer useful. Smalltalk objects are deleted when they are no longer reachable (garbage collected).

      Back to top


    2.8  Behavior/State Grouping


    Smalltalk uses the 'classical' object model.

      Back to top


    2.9  Communication Model


    All communications within Smalltalk occur through messages between objects and most Smalltalk implementations support a form of concurrency. For example, Smalltalk-80 provides for multiple independent processes, and semaphores provide the common mechanism for synchronizing the independent processes.

      Back to top


    2.10  Events


    No specific mechanisms for handling events are built into the Smalltalk language, but "event handling" logic is commonly implemented in Smalltalk applications through its normal messaging techniques.

      Back to top


    4  Polymorphism


    Polymorphism is the way that the Smalltalk language allows methods of same name to have predictable and meaningful results in related instances, yet perform the operations differently to achieve similar results.

    Smalltalk supports polymorphism by allowing methods defined in classes to be overridden with methods of the same name, but different logic, in a subsequent subclass. In addition, methods of the same name can be defined in a total different subclass hierarchy.

    In the class hierarchy below, all of the lowest level classes are defined to accept the message 'moveForward' (mFabstract), but several different versions are implemented as indicated by (MFn) in the diagram. The message sent to the instances of 'Bus' or 'Auto' uses the method defined in the 'Motorized' class. The same method is inherited by 'Train' and 'Motorcycle', but both have overridden the inherited method by defining a method with different logic using the same message pattern. All the others instances in the diagram have the 'moveForward' message pattern in their interface, but are not in the 'Motorized' inheritance chain. All of the 'moveForward' (mFabstract) methods function as you intuitively expect.

                         Transport Mechanism  (mFabstract)
           /---------------       |        -------------------\
    Animal Powered          Human Powered                  Motorized
      /  (mF1)  \         /               \               /  (mF5)  \
    Buggy      Wagon  Land-based      Water-based    Public       Private
                       /     \         / (mF4) \     /    \        /   \
                     Bike  Skates  Row Boat  Canoe  Bus  Train  Auto  Motorcycle
                    (mF2)   (mF3)                        (mF6)          (mF7)
    

      Back to top


    5  Encapsulation


    The approach used in Smalltalk is to encapsulate all objects, whether a complex as a sorted list or as simple as a string, into a single programming entity that includes data and logic. Further, other objects can not invoke the encapsulated data or logic. In order to interact, other objects must send messages to an object's interface that will cause the object to perform a function that will have a known effect. See also entry under 2.3 Messages.

      Back to top


    6  Identity, Equality, Copy


    Smalltalk provides unique identity for all objects. Objects can be tested for equivalence (Are the objects being compared the same object?) and equality (every object may implement its own definition of equality).

    Copying of objects can be performed as a deep copy (object's structure and the objects pointed to by its variables are copied) or shallow copy (objects pointed to by variables, their variables are not copied, but are shared with the original object).

    XLISP does not provide build-in functions or methods to compare or to copy objects.

      Back to top


    7  Types and Classes


    Smalltalk does not have a separate notion of 'type' [message protocol shared by a group of objects] apart from 'class'.

    A class is a group of objects that represent the same type of entity and share the same methods. A class describes the implementation of a set of similar objects. Classes are themselves objects. All objects belong to some class and an object is an instance of the class of which it belongs.

    XLISP: If an object is a member of a class can be tested by sending an :isa message.

      Back to top


    8  Inheritance and Delegation


    Smalltalk class relationships are defined in terms of inheritance. The properties of one class are be inherited from another class in a hierarchical structure beginning with the upper-most class object. In inheritance, the inheriting class is called the 'subclass' and the class being inherited from is call the 'superclass'. A subclass inherits all of its superclass' variables and methods.

    Abstract classes are classes from which other classes are inherited (subclassed) only. Instances can be implemented any non-abstract class.

    Subclasses are specialization of their superclasses. A subclass may add variables, but it cannot delete those inherited from the superclass. A subclass may accept an inherited method or it may override the method by providing an new method with the same name (or message selector).

    Object instances are instances of a class. Smalltalk does not provide for delegation (defined as object instances being created from other object instances and not a class).

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/objects/advanced-objects.htm0000644000175000000620000004563311512762341024055 0ustar stevestaff Advanced XLISP Objects Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Advanced XLISP Objects


    1. Standard XLISP Objects
    2. Initializing Class Variables
    3. Accessing Class and Instance Variables

    Standard XLISP Objects


    Define a class with an instance variable and a class variable:

    (setq my-class (send class :new '(instance-var) '(class-var)))
    

    Look at the layout of the new class:

    > (send my-class :show)
    Object is #<Object...>, Class is #<Object...>
      MESSAGES = NIL
      IVARS = (INSTANCE-VAR)
      CVARS = (CLASS-VAR)
      CVALS = #(NIL) ; default init-value of class variables
      SUPERCLASS = #<Object...>
      IVARCNT = 1
      IVARTOTAL = 1
    #<Object...>
    

    Make an instance of 'my-class':

    (setq my-object (send my-class :new))
    

    Look at the layout of the new object:

    > (send my-object :show)
    Object is #<Object...>, Class is #<Object...>
      INSTANCE-VAR = NIL ; default init-value of instance variables
    #<Object...>
    

      Back to top


    Initializing Class Variables


    1. Add an :isnew init-method to 'my-class':

    (send my-class :answer :isnew nil '((setq class-var 1)))
    

    Now reset the class:

    (send my-class :isnew)  => error: too few arguments
    

    It turns out that :isnew needs at least a list of instance variables plus an optional list of class variables:

    (send my-class :isnew '(ivar))           ; overwrites INSTANCE-VAR, deletes CLASS-VAR
    (send my-class :isnew '(ivar) '(cvar)))  ; overwrites INSTANCE-VAR and CLASS-VAR
    

    2. Add an :init method to 'my-class':

    (send my-class :answer :init nil '((setq class-var 1)))
    

    Now call the :init method:

    (send my-class :init)  => error: no method for this message - :INIT
    

    This is not true, there is an :init method:

    > (send my-class :show)
    Object is #<Object...>, Class is #<Object...>
      MESSAGES = ((:INIT . #<Closure-:INIT:...>))
      IVARS = (INSTANCE-VAR)
      CVARS = (CLASS-VAR)
      CVALS = #(NIL)
      SUPERCLASS = #<Object...>
      IVARCNT = 1
      IVARTOTAL = 1
    #<Object...>
    

    The problem here is that in XLISP, methods cannot be called from the class they were defined in, methods only can be called from instances, and exactly the same happens with manipulating class variables. There seems to be no standard XLISP way to initialize class variables with values at the time when the class is defined.

    3. The only way I know in XLISP to initialize a class variable is to create an instance of the class and set the class variable e.g. from the :isnew method of the instance:

    (setq my-object (send my-class :new))
    

    The :isnew method of 'my-object', inherited from 'my-class', has set the class variable in 'my-class' to a new value:

    > (send my-class :show)
    Object is #<Object...>, Class is #<Object...>
      MESSAGES = ((:ISNEW . #<Closure-:ISNEW:...>))
      IVARS = (INSTANCE-VAR)
      CVARS = (CLASS-VAR)
      CVALS = #(1) ; new value of CLASS-VAR
      SUPERCLASS = #<Object...>
      IVARCNT = 1
      IVARTOTAL = 1
    #<Object...>
    

    This works, but now I have two problems:

    1. If a class variable is set from an instance's :isnew method, inherited from the superclass, then, whenever an instance is created, the class variable will be reset to its initial value. Note that in Lisp, instances can be created at arbitrary run-time, not only at the beginning of a program. Setting class variables from an :isnew method can produce unexpected side-effects if a class variable is used for object inter-communication.

    2. Because instances can be created at arbitrary runtime, a framework would need to be written when a class variable is allowed to be set or reset and when not. Ok, if class variables are used for object inter-communication, a framework needs to be witten anyway, but I do not want to be forced to think about this only because I want to initialize a single class variable.

    4. Here is a trick I use to initialize class variables.

    Create a class with class variables:

    (setq my-class (send class :new nil '(cvar-1 cvar-2)))
    

    Add an :isnew method to set the class variables:

    (send my-class :answer :isnew nil '((setq cvar-1 "a" cvar-2 "b")))
    

    Create a temporary dummy object to initialize the class variables:

    (let ((x (send my-class :new))))
    

    Replace the :isnew method with a dummy version [or a real version, initializing the instance variables]:

    (send my-class :answer :isnew nil nil)
    

    Now I have a class with initialized class variables:

    > (send my-class :show)
    Object is #<Object...>, Class is #<Object...>
      MESSAGES = ((:ISNEW . #<Closure-:ISNEW...>))  ; dummy method
      IVARS = NIL
      CVARS = (CVAR-1 CVAR-2)  ; class variables
      CVALS = #("a" "b")       ; init values
      SUPERCLASS = #<Object...>
      IVARCNT = 0
      IVARTOTAL = 0
    #<Object...>
    

    See defclass below how to make this work automatically.

      Back to top


    Accessing Class and Instance Variables


    (setq my-class (send class :new '(i-var) '(c-var)))
    (setq my-object (send my-class :new))
    

    A message to read internal class and instance variables:

    (send my-class :answer :internal-slot-get '(slot-name)
      '((eval slot-name)))
    

    A message to write internal class and instance variables:

    (send my-class :answer :internal-slot-set '(slot-name value)
      '((eval (list 'setq slot-name value))))
    

    Implementation Notes

    1. It's not really good Lisp style to explicitely call 'eval' in Lisp code at run-time, because 'eval' produces a lot of overhead, but here the only way to get access to the internal environment of an object is passing the message arguments to 'eval' inside the object itself.

    2. In the XLISP object system, an :answer message can only be accessed in an instance of a class [a sub-class or on object], but not in the class, where the :answer message has been defined, so the :internal-slot accessor will only work in 'my-object' but ont in 'my-class'.

    3. If a method had been changed in a superclass, the change will automatically be inherited by all instances of the class [sub-classes and objects], with no need to redefine them.

    Warning: If 'internal-slot-set' is given a slot-name that doesn't exist inside the object, a global variable will be created.

    Reading and writing an instance variable:

    > (send my-object :internal-slot-get 'i-var)     ; read
    NIL
    
    > (send my-object :internal-slot-set 'i-var 55)  ; write
    55
    
    > (send my-object :internal-slot-get 'i-var)     ; read
    55
    
    > (send my-object :show)
    Object is #<Object: #9b95998>, Class is #<Object: #9b95c50>
      I-VAR = 55 ; new value
    #<Object: #9b95998>
    

    Reading and writing a class variable:

    > (send my-object :internal-slot-get 'c-var)      ; read
    NIL
    
    > (send my-object :internal-slot-set 'c-var 123)  ; write
    123
    
    > (send my-object :internal-slot-get 'c-var)      ; read
    123
    
    > (send my-class :show)
    Object is #<Object: #9b95c50>, Class is #<Object: #9af7dd4>
      MESSAGES = ((:INTERNAL-SLOT-GET . #<Closure-:INTERNAL-SLOT-GET: #9b90080>)
                  (:INTERNAL-SLOT-SET . #<Closure-:INTERNAL-SLOT-SET: #9b900d4>))
      IVARS = (I-VAR)
      CVARS = (C-VAR)
      CVALS = #(123) ; new value
      SUPERCLASS = #<Object: #9af7dc8>
      IVARCNT = 1
      IVARTOTAL = 1
    #<Object: #9b95c50>
    

    See the 'slot-get' and 'slot-set' functions below how this can be generalized to access any class or instance variable in any class or object via only two functions.

      Back to top


    defclass


    The original RBD 'defclass' macro:

    (defmacro defclass (name super locals class-vars)
      (if (not (boundp name))
        (if super
            `(setq ,name (send class :new ',locals ',class-vars ,super))
            `(setq ,name (send class :new ',locals ',class-vars)))))
    

    In order to read or write XLISP class or object variables two slot-acessor messages need to be added to every new top-level class:

    (defmacro defclass (name super locals class-vars)
      (when (boundp name)
        (format t ";; WARNING: redefining ~a~%" name))
      (if super
          `(setq ,name (send class :new ',locals ',class-vars ,super))
          `(progn
             (setq ,name (send class :new ',locals ',class-vars))
             (send ,name :answer :internal-slot-set '(slot-name value)
               '((eval (list 'setq slot-name value))))
             (send ,name :answer :internal-slot-get '(slot-name)
               '((eval slot-name))))))
    

    The third version provides 'let'-syntax with instance and class variables. A list of symbols will create variables initialized to NIL. This is the XLISP default behaviour. If an element is a (symbol value) list, then the variable will be initialized with 'value', as soon as an instance of the class is created.

    (defclass class {superclass | NIL}
      ({ ivar  | ( ivar  init-form )} ... )   ; instance variables
      ({ cvar  | ( cvar  init-form )} ... ))   ; class variables

    (defmacro expand-init-values (vars var-list init-list)
      (let ((var (gensym)))
        `(dolist (,var ,vars (setq ,var-list  (reverse ,var-list)
                                   ,init-list (reverse ,init-list)))
           (cond ((symbolp ,var)
                  ;; if the element is a single symbol,
                  ;; then add it to the variable list
                  (push ,var ,var-list))
                 ((and (listp ,var) (symbolp (first ,var)))
                  ;; if the element is a (symbol value) list, then add
                  ;; an (setq symbol value) element to the init-list
                  (push (list 'setq (first ,var) (second ,var)) ,init-list)
                  ;; and add the symbol to the variable-list
                  (push (first ,var) ,var-list))
                 (t (error "bad argument type" ,var))))))
    
    (defmacro with-unique-names (symbols &rest body)
      `(let ,(mapcar #'(lambda (x) `(,x (gensym))) symbols) ,@body))
    
    (defmacro defclass (name super class-vars instance-vars)
      (with-unique-names (class-list class-init instance-list instance-init x)
        `(let (,instance-list ,instance-init ,class-list ,class-init)
           (expand-init-values ',class-vars ,class-list ,class-init)
           (expand-init-values ',instance-vars ,instance-list ,instance-init)
           (if (boundp ',name)
               (format t ";; Redefining ~a~%" ',name)
               (format t ";; CLASS ~a~%" ',name))
           (format t ";; CVARS ~a~%" ',class-vars)
           (format t ";; IVARS ~a~%" ',instance-vars)
           ,(if super
                `(setq ,name (send class :new ,instance-list ,class-list ,super))
                `(setq ,name (send class :new ,instance-list ,class-list)))
           ;; initialize class and instance variables
           (when ,class-list
             (send ,name :answer :isnew nil ,class-init)
             (let ((,x (send ,name :new)))))
           (when (or ,instance-list ,class-list)
             (send ,name :answer :isnew nil ,instance-init))
           ;; add slot-accessors to top-level classes
           ,(unless super
              `(progn
                 (send ,name :answer :internal-slot-set '(slot-name value)
                   '((eval (list 'setq slot-name value))))
                 (send ,name :answer :internal-slot-get '(slot-name)
                   '((eval slot-name))))))))
    

    Sub-classes and objects inherit their acessors from the super-class.

    Define a class with an instance-variable, a class-variable and slot acessors:

    > (defclass my-class nil 
        ((a 1) (b 2) (c 3))
        ((d 4) (e 5) (f 6)))
    
    > 
    

      Back to top


    Generalized Slot Accessors


    Now the slot accessors for internal class and instance variables can be defined as ordinary XLISP functions:

    (defun slot-set (object slot-name value)
      (send object :internal-slot-set slot-name value))
    
    (defun slot-get (object slot-name)
      (send object :internal-slot-get slot-name))
    

    Examples:

    > (slot-set my-object 'i-var 333)
    333
    
    > (slot-get my-object 'i-var)
    333
    

    Even typing the quote could be saved if 'slot-set' and 'slot-get' are defined as macros:

    (defmacro slot-set (object slot-name value)
      `(send ,object :internal-slot-set ',slot-name ,value))
    
    (defmacro slot-get (object slot-name)
      (send ,object :internal-slot-set ',slot-name ,value))
    

    Examples:

    > (slot-set my-object i-var 444)
    444
    
    > (slot-get my-object i-var)
    444
    

      Back to top


    Removing a Method from a Class or Instance


    In Smalltalk, if a method's body is unbound and no other object refernces the method, then the method is automatically garbage collected. Unfortunately in XLISP this doesn't work because the instance variables, including the list of methods, are not accessed by the garbage collector at all. This means that even if the message body is set to NIL, the message is not garbage collected, instead the 'no function' message returns NIL and blocks the built-in search for super-class messages.

    Because messages cannot be removed from XLISP objects, the only way to make a message 'disappear' is to replage it's body by a call to the super-class, passing the arguments of the original message:

    (defun remove-method (object message-selector &rest args)
      (send object message-selector
      (send-super message-selector args))
    

    Shit: this doesn't work if the metod is defined in a super-class.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/internals/0002755000175000000620000000000011537433125020506 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/internals/xlisp-internals.html0000644000175000000620000014403211512762341024530 0ustar stevestaffXLISP Internals Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    XLISP Internals


    92Jan14 jsp@glia.biostr.washington.edu [Jeff Prothero]. Public Domain.

                     +---------------------+
                     | xlisp 2.1 internals |
                     +---------------------+
    
             "Trust the Source, Luke, trust the Source!"
    

    Contents


    1. Who should read this?
    2. What is an LVAL?
    3. What is the obarray?
    4. The Interpreter Stacks
    5. What is a context?
    6. What is an environment?
    7. How are XLISP entities stored and identified?
    8. How are vectors implemented?
    9. How are strings implemented?
    10. How are symbols implemented?
    11. How are closures implemented?
    12. How are objects implemented?
    13. How are classes implemented?
    14. How is the class hierarchy laid out?
    15. How do we look up the value of a variable?
    16. How are function calls implemented?
    17. How are message-sends implemented?
    18. How is garbage collection implemented?
    19. How are the source files laid out?
    20. How do I add a new primitive fn to xlisp?
    21. Minor Observations.
    22. Acknowledgements. 

    Who should read this ?


    Anyone poking through the C implementation of XLISP for the first time. This is intended to provide a rough roadmap of the global XLISP structures and algorithms. If you just want to write lisp code in XLISP, you don't need to read this file. Go read the XLISP 2.0 Manual, the XLisp Objects Primer, and the XLisp Language Reference, in about that order. If you want to tinker with the XLISP implementation code, you should *still* read those three before reading this. The following isn't intended to be exhaustively precise, that's what the source code is for. It is intended only to allow you a fighting change of understanding the code the first time through [instead of the third time].

    At the bottom of the file you'll find an example of how to add new primitive functions to XLISP.

      Back to top


    What is an LVAL ?


    An LVAL is the C type for a generic pointer to an XLISP garbage-collectable something. [Cons cell, object, string, closure, symbol, vector, whatever.] Virtually every variable in the interpreter is an LVAL. Cons cells contain two LVAL slots, symbols contains four LVAL slots, etc.

      Back to top


    What is the obarray ?


    The obarray is the XLISP symbol table. More precisely, it is a hashtable mapping ASCII strings [symbol names] to symbols. [The name 'obarray' is traditional but a bit of a misnomer, since it contains only XLISP symbols, and in particular contains no XLISP objects.] It is used when converting Lisp expressions from text to internal form. Since it is a root for the garbage collector, it also serves to distinguish permanent global-variable symbols from other symbols. You can permanently protect a symbol from the garbage collector by entering it into the obarray. This is called 'interning' the symbol. The obarray is called 'obarray' in C and *obarray* in XLISP. It is physically implemented as a vector-valued symbol.

      Back to top


    The Interpreter Stacks


    XLISP uses two stacks, an 'evaluation stack' and an 'argument stack'. Both are roots for the garbage collector. The evaluation stack is largely private to the interpreter and protects internal values from garbage collection, while the argument stack holds the conventional user-visible stackframes.

    The evaluation stack is an 'edepth'-long array of LVAL allocated by 'xldmem.c:xlminit()'. It grows zeroward.

    'xlstkbase' points to the zero-near end of the evaluation stack.

    'xlstktop' points to the zero-far end of the evaluation stack, the occupied part of the stack lies between 'xlstack' and 'xlstktop'. Note that 'xlstktop' is *NOT* the top of the stack in the conventional sense of indicating the most recent entry on the stack. 'xlstktop' is a static bounds pointer which never changes once the stack is allocated.

    'xlstack' starts at the zero-far end of the evaluation stack. '*xlstack' is the most recent LVAL on the stack. The garbage collector marks everything reachable from the evaluation stack [among other things], so we frequently push things on this stack while C code is manipulating them. [Via 'xlsave()', 'xlprotect()', 'xlsave1()', 'xlprot1()'.]

    The argument stack is an 'adepth'-long array of LVAL. It also grows zeroward. The evaluator pushes arguments on the argument stack at the start of a function call [form evaluation]. Built-in functions usually eat them directly off the stack. For user-lisp functions 'xleval.c:evfun()' pops them off the stack and binds them to the appropriate symbols before beginning execution of the function body proper.

    xlargstkbase  -  is the zero-near end of argument stack.
     
    xlargstktop  -  is the zero-far end of argument stack. Like 'xlstktop', 'xlargstktop' is a static bounds pointer which never changes after the stack is allocated.
     
    *xlsp   [stack pointer]  -  is the most recent item on the argument stack.
     
    *xlfp   [frame pointer]  -  is the base of the current stackframe.

      Back to top


    What is a context ?


    A XLISP context is something like a checkpoint, recording a particular point buried in the execution history so that we can abort or return back to it. Contexts are used to implement call and return, catch and throw, signals, gotos, and breaks. 'xlcontext' points to the chain of active contexts, the top one being the second-newest active context. [The newest, that is, the current, active context is implemented by the variables 'xlstack', 'xlenv', 'xlfenv', 'xldenv', 'xlcontext', 'xlargv', 'xlargc', 'xlfp', and 'xlsp'.] Context records are written by 'xljump.c:xlbegin()' and read by 'xljump.c:xljump()'. Context records are C structures on the C program stack. They are not in the dynamic memory pool or on the Lisp execution or argument stacks.

      Back to top


    What is an environment ?


    An environment is basically a store of symbol-value pairs, used to resolve variable references by the Lisp program. XLISP maintains three environments, in the global variables 'xlenv', 'xlfenv' and 'xldenv'.

    Lisp supports two sorts of binding, 'lexical binding' and 'dynamic binding'. Lexically bound variables are visible only in code textually within their binding form. Dynamically bound variables are visible in any code *called* from the binding form. [Either kind of binding may be shadowed by other declarations, of course.] Historically, Lisp has been moving from dynamic binding [which is easy for interpreters to handle], to lexical binding [which is easy for humans and compilers to handle]. Almost all XLISP binding forms are lexically scoped. The most important exception is progv.

    'xlenv' and 'xlfenv' track lexical bindings. 'xlenv' and 'xlfenf' are conceptually a single environment, although they are implemented separately. They are linked-list stacks which are pushed when we enter a function and popped when we exit it. We also switch 'xlenv+xlfenf' environments entirely when we begin executing a new closure [user-function written in Lisp].

    The 'xlenv' environment is the most heavily used environment. It is used to resolve everyday data references to local variables. It consists of a list of frames [and objects]. Each frame is a list of symbol-value pairs. In the case of an object, we check all the instance and class variables of the object, then do the same for its superclass, until we run out of superclasses.

    The 'xlfenv' environment is maintained strictly parallel to 'xlenv', but is used to find function values instead of variable values. The separation may be partly for lookup speed and partly for historical reasons. Merging these two lists into a single list [while distinguishing function bindings from variable bindings, of course] would slightly decrease fn enter/exit overhead while increasing the overhead of looking up each variable or function binding.

    When we send a message, we set 'xlenv' to the value it had when the message closure was built, then push on (obj msg-class), where 'msg-class' is the [super]class defining the method. [We also set 'xlfenv' to the value 'xlfenv' had when the method was built.] This makes the object instance variables part of the environment, and saves the information needed to correctly resolve references to class variables, and to implement send-super.

    The 'xldenv' environment tracks dynamic bindings. It is a simple list of symbol-value pairs, treated as a stack. progv uses it to save the old values of symbols it binds, and it is also used to save old values of 's_evalhook' and 's_applyhook' [*evalhook* and *applyhook*]. These latter mostly support the debug facilities.

    These environments are manipulated in C via the 'xlisp.h' macros 'xlframe(e)', 'xlbind(s,v)', 'xlfbind(s,v)', 'xlpbind(s,v,e)', 'xldbind(s,v)', 'xlunbind(e)'.

      Back to top


    How are XLISP entities stored and identified ?


    Conceptually, XLISP manages memory as a single array of fixed-size objects. Keeping all objects the same size simplifies memory management enormously, since any object can be allocated anywhere, and complex compacting schemes aren't needed. Every LVAL pointer points somewhere in this array. Every XLISP object has the basic format 'xldmem.h:typdef struct node':

    struct node {
        char n_type;
        char n_flags;
        LVAL car;
        LVAL cdr;
    }
    

    where 'n_type' is one of:

    FREE   -  a node on the freelist.
    SUBR   -  a function implemented in C. [Needs evaluated arguments.]
    FSUBR   -  a 'special form' implemented in C. [Needs unevaluated arguments.]
    CONS   -  a regular lisp cons cell.
    SYMBOL   -  a symbol.
    FIXNUM   -  an integer.
    FLONUM   -  a floating-point number.
    STRING   -  a string.
    OBJECT   -  any object, including class objects.
    STREAM   -  an input or output file.
    VECTOR   -  a variable-size array of LVALs.
    CLOSURE   -  result of defun or lambda, a function written in Lisp.
    CHAR   -  an ASCII character.
    USTREAM   -  an internal stream.
    STRUCT   -  a structure.

    Messages may be sent only to nodes with a 'n_type' of OBJECT.

    Obviously, several of the above types won't fit in a fixed-size two-slot node. The escape is to have them 'malloc()' some memory and have one of the slots point to it. VECTOR is the archetype. For example, see 'xldmem.c:newvector()'. To some extent, this 'malloc()' hack simply exports the memory fragmentation problem to the C 'malloc()/free()' routines. However, it helps keep XLISP simple, and it has the happy side-effect of unpinning the body of the vector, so that vectors can easily be expanded and contracted.

    The garbage collector has special-case code for each of the above node types, so it can find all LVAL slots and recycle any 'malloc()'-ed ram when a node is garbage-collected.

    XLISP pre-allocates nodes for all ASCII characters, and for small integers. These nodes are never garbage-collected.

    As a practical matter, allocating all nodes in a single array is not very sensible. Instead, nodes are allocated as needed, in segments of one or two thousand nodes, and the segments linked by a pointer chain rooted at 'xldmem.c:segs'.

      Back to top


    How are vectors implemented ?


    An XLISP vector is a generic array of LVAL slots. Vectors are also the canonical illustration of XLISP's escape mechanism for node types which need more than two LVAL slots [the maximum possible in the fixed-size nodes in the dynamic memory pool]. The node CAR/CDR slots for a vector hold a size field plus a pointer to a 'malloc()'-ed ram chunk, which is automatically 'free()'-ed when the vector is garbage-collected.

    'xldmem.h' defines macros for reading and writing vector fields and slots, 'getsize()', 'getelement()' and 'setelement()'. It also defines macros for accessing each of the other types of XLISP nodes.

      Back to top


    How are strings implemented ?


    Strings work much like vectors. The node has a pointer to a 'malloc()'-ed ram chunk which is automatically 'free()'-ed when the string gets garbage-collected.

      Back to top


    How are symbols implemented ?


    A symbol is a generic user-visible Lisp variable, with separate slots for print name, value, function, and property list. Any or all of these slots [including name] may be NIL.

    You create an XLISP symbol from C by calling 'xlmakesym(name)' or 'xlenter(name)' [to make a symbol and enter it in the obarray].

    You may create symbols from XLISP by explicitly calling gensym, make-symbol [uninterned symbols], or intern [interned symbol]. However, the Lisp reader will create symbols on sight, so most Lisp symbols are created as side-effects of expressions like:

    'name
    

    A symbol is interned if it is listed in the *obarray*. Various parts of the system, like the Lisp reader, treat the *obarray* essentially as the list of all known symbols. It is unusual but occasionally useful to create uninterned symbols. You can make read create an uninterned symbol by preceding it with '#:'. In XLISP, a newly created symbol has no value unless its name begins with a ':', in which case it has itself for its value. Handy for keywords and message selectors.]

    Most of the symbol-specific code in the interpreter is in 'xlsym.c'.

    Physically, a symbol is implemented like a four-slot vector [print name, value, function, and property list].

    Random musing: Abstractly, the Lisp symbols plus cons cells [etc.] constitute a single directed graph, and the symbols mark spots where normal recursive evaluation should stop. Normal Lisp programming practice is to have a symbol in every cycle in the graph, so that recursive traversal can be done without mark bits.

      Back to top


    How are closures implemented ?


    A closure, the return value from a lambda, is a regular coded-in-lisp function. Physically, it is implemented like an eleven-slot vector, with the node 'n_type' field hacked to contain CLOSURE instead of VECTOR. The vector slots contain:

    name   -  a symbol, the first argument of defun. nil for lambda closures.
    type   -  's_lambda' or 's_macro'. Must be 's_lambda' to be executable.
    args   -  list of required formal arguments [as symbols].
    oargs   -  list of &optional arguments, each like (name (default specified-p)).
    rest   -  name of '&rest' formal arguments, else nil.
    kargs   -  &key-word arguments, each like ((':foo 'bar default specified-p))
    aargs   -  &aux variables, each like (('arg default)).
    body   -  actual code [as a Lisp list] for the function.
    env   -  value of 'xlenv' when the closure was built.
    fenv   -  value of 'xlfend' when the closure was built.
    lambda   -  the original formal args list in the defun or lambda.

    The lambda field is for printout purposes. The remaining fields store a predigested version of the formal arguments list. This is a limited form of compilation. By processing the arguments list at closure-creation time, we reduce the work needed during calls to the closure.

      Back to top


    How are objects implemented ?


    An object is implemented like a vector, with the size determined by the number of instance variables. The first slot in the vector points to the class of the object, the remaining slots hold the instance variables for the object. An object needs enough slots to hold all the instance variables defined by its class, *plus* all the instance variables defined by all of its superclasses.

      Back to top


    How are classes implemented ?


    A class is a specific kind of object, hence has a class pointer plus instance variables. All classes have the following instance variables:

      MESSAGES     a list of (interned-symbol method-closure) pairs.
      IVARS        instance variable names, a list of interned symbols.
      CVARS        class variable names, a list of interned symbols.
      CVALS        class variable values, a vector of values.
      SUPERCLASS   a pointer to the superclass.
      IVARCNT      the number of class instance variables, a fixnum.
      IVARTOTAL    the total number of instance variables, a fixnum.
    

    IVARCNT is the count of the number of instance variables defined by our class. IVARTOTAL is the total number of instance variables in an object of this class -- IVARCNT for this class plus the IVARCNTs from all of our superclasses.

        Back to Top

    How is the class hierarchy laid out ?

    The fundamental objects are the OBJECT and CLASS class objects. (Both are instances of class CLASS, and since CLASSes are a particular kind of OBJECT, both are also objects, with n_type==OBJECT. Bear with me!)

    OBJECT is the root of the class hierarchy: everything you can send a message to has OBJECT as its class or super*class. (Vectors, chars, integers and so forth stand outside the object hierarchy -- you can't send messages to them. I'm not sure why Dave did it this way.) OBJECT defines the messages:

      :isnew -- Does nothing but return the object.
      :class -- Returns contents of class-pointer slot.
      :show  -- Prints names of obj, obj->class and instance vars.
    

    Since a CLASS is a specialized type of OBJECT (with instance variables like MESSAGES which generic OBJECTs lack), class CLASS has class OBJECT as its superclass. The CLASS object defines the messages:

      :new    -- Create new object with self.IVARTOTAL LVAR slots, plus
                 one for the class pointer. Point class slot to self.
                 Set new.n_type char to OBJECT.
      :isnew  -- Fill in IVARS, CVARS, CVALS, SUPERCLASS, IVARCNT and
                 IVARTOTAL, using parameters from :new call.  (The
                 :isnew msg inherits the :new msg parameters because
                 the  :isnew msg is generated automatically after
                 each :new   msg, courtesy of a special hack in
                 xlobj.c:sendmsg().)
      :answer -- Add a (msg closure) pair to self.MESSAGES.
    

    Here's a figure to summarize the above, with a generic object thrown in for good measure. Note that all instances of CLASS will have a SUPERCLASS pointer, but no normal object will. Note also that the messages known to an object are those which can be reached by following exactly one Class Ptr and then zero or more Superclass Ptrs. For example, the generic object can respond to :ISNEW, :CLASS and :SHOW, but not to :NEW or :ANSWER. (The functions implementing the given messages are shown in parentheses.)

                                         NIL
                                          ^
                                          |
                                          |Superclass Ptr
                                          |
                                 Msg+--------+
      :isnew (xlobj.c:obisnew) <----|  class |Class Ptr
      :class (xlobj.c:obclass) <----| OBJECT |------------------------------>+
      :show  (xlobj.c:objshow) <----|        |                               |
                                    +--------+                               |
                                      ^  ^  ^                                |
            +---------+               |  |  |                                |
            | generic |Class Ptr      |  |  +<---------------+               |
            | object  |-------------->+  |Superclass Ptr     ^Superclass Ptr |
            +---------+                  |                   |               |
                                 Msg+--------+          +---------+          |
      :isnew (xlobj.c:clnew)   <----| class  |Class Ptr | generic |Class Ptr |
      :new   (xlobj.c:clisnew) <----| CLASS  |------->+ | CLASS   |------->+ |
      :answer(xlobj.c:clanswer)<----|        |        | |         |        | |
                                    +--------+        | +---------+        | |
                                       ^  ^           |                    | |
                                       |  |           v                    v |
                                       |  +-----------+ <------------------+ v
                                       +<------------------------------------+
    

    Thus, class CLASS inherits the :CLASS and :SHOW messages from class OBJECT, overrides the default :ISNEW message, and provides new messages :NEW and :ANSWER.

    New classes are created by (send CLASS :NEW ...) messages. Their Class Ptr will point to CLASS. By default, they will have OBJECT as their superclass, but this can be overridden by the second optional argument to :NEW.

    The above basic structure is set up by xlobj.c:xloinit().

        Back to Top

    How do we look up the value of a variable ?

    When we're cruising along evaluating an expression and encounter a symbol, the symbol might refer to a global variable, an instance variable, or a class variable in any of our superclasses. Figuring out which means digging through the environment. The canonical place this happens is in xleval.c:xleval(), which simply passes the buck to xlsym.c:xlgetvalue(), which in turn passes the buck to xlxsym.c:xlxgetvalue(), where the fun of scanning down xlenv begins. The xlenv environment looks something like

               Backbone    Environment frame contents
               --------    --------------------------
      xlenv --> frame      ((sym val) (sym val) (sym val) ... )
                frame      ...
                object     (obj msg-class)
                frame      ...
                object     ...
                frame      ...
                ...
    

    The "frame" lines are due to everyday nested constructs like LET expressions, while the "object" lines represent an object environment entered via a message send. xlxgetvalue scans the enviroment left to right, and then top to bottom. It scans down the regular environment frames itself, and calls xlobj.c:xlobjgetvalue() to search the object environment frames.

    xlobjgetvalue() first searches for the symbol in the msg-class, then in all the successive superclasses of msg-class. In each class, it first checks the list of instance-variable names in the IVARS slot, then the list of class-variables name in the CVARS slot.

        Back to Top

    How are function calls implemented ?

    xleval.c contains the central expression-evaluation code. xleval.c:xleval() is the standard top-level entrypoint. The two central functions are xleval.c:xlevform() and xleval.c:evfun(). xlevform() can evaluate four kinds of expression nodes:

    SUBR: A normal primitive fn coded in C. We call evpushargs() to evaluate and push the arguments, then call the primitive.

    FSUBR: A special primitive fn coded in C, which (like IF) wants its arguments unevaluated. We call pushargs() (instead of evpushargs()) and then the C fn.

    CLOSURE: A preprocessed written-in-lisp fn from a DEFUN or LAMBDA. We call evpushargs() and then evfun().

    CONS: We issue an error if CONS.car isn't a LAMBDA, otherwise we call xleval.c:xlclose() to build a CLOSURE from the LAMBDA, and fall into the CLOSURE code.

    The common thread in all the above cases is that we call evpushargs() or pushargs() to push all the arguments on the evaluation stack, leaving the number and location of the arguments in the global variables xlargc and xlargv. The primitive C functions consume their arguments directly from the argument stack.

    xleval.c:evfun() evaluates a CLOSURE by:

    (1) Switching xlenv and xlfenv to the values they had when the CLOSURE was built. (These values are recorded in the CLOSURE.)

    (2) Binding the arguments to the environment. This involves scanning through the section of the argument stack indicated by xlargc/xlargv, using information from the CLOSURE to resolve keyword arguments correctly and assign appropriate default values to optional arguments, among other things.

    (3) Evaluating the body of the function via xleval.c:xleval().

    (4) Cleaning up and restoring the original environment.

        Back to Top

    How are message-sends implemented ?

    We scan the MESSAGES list in the CLASS object of the recipient, looking for a (message-symbol method) pair that matches our message symbol. If necessary, we scan the MESSAGES lists of the recipient's superclasses too. (xlobj.c:sendmsg().) Once we find it, we basically do a normal function evaluation. (xlobjl.c:evmethod().)

    Two differences between message-send and normal function invocation:

    1) We need to replace the message-symbol by the recipient on the argument stack to make "self" available in the method closure.

    2) We need to push an 'object' stack entry on the xlenv environment to record which class is handling the message (so that, for example, SEND-SUPER can find our superclass).

        Back to Top

    How is garbage collection implemented ?

    The dynamic memory pool managed by xlisp consists of a chain of memory segments (xldmem.h:struct segment) rooted at global C variable "segs". Each segment contains an array of "struct node"s plus a pointer to the next segment. Each node contains a n_type field and a MARK bit, which is zero except during garbage collection.

    Xlisp uses a simple, classical mark-and-sweep garbage collector. When it runs out of memory (fnodes==NIL), it does a recursive traversal setting the MARK flag on all nodes reachable from the obarray, the three environments xlenv/xlfenv/xldenv, and the evaluation and argument stacks. (A "switch" on the n_type field tells us how to find all the LVAL slots in the node (plus associated storage), and a pointer-reversal trick lets us avoid using too much stack space during the traversal.) sweep() then adds all un-MARKed LVALs to fnodes, and clears the MARK bit on the remaining nodes. If this fails to produce enough free nodes, a new segment is malloc()ed.

    The code to do this stuff is mostly in xldmem.c.

        Back to Top

    How are the source files laid out ?

    To really understand the source, of course, you simply have to sit down and read it. There's no royal road to hacking! So this is a map of the source, not a picture of it.

    The core portable xlisp files have the prefix 'xl' (for 'xlisp').

    The best place to start reading the code is in the two main header files, xlisp.h and xldmem.h.

    The xldmem.h file ('dmem' for 'dynamic memory') defines the actual structure in memory of all the primitive xlisp data types. This is the file you will most likely refer to most often.

    The xlisp.h file defines essentially all global constants and macros which don't need to know about the structures in xldmem.h, mainly manifest constants sizing various arrays for different machines, and macros to test for the type of a list object and to help parse xlisp argument lists.

    The central code files to understand are xlmain.c, xleval.c, xlbfun.c, and xlsym.c.

    xlmain.c contains both main() and the central read-eval-print loop, so it is the place from which to begin tracing flow of control.

    xleval.c (with some support from xlbfun.) contains the heart of xlisp, the code to evaluate functions and macros.

    xlsym.c contains the code to find the value of a symbol.

    Once you understand the above three, you know where xlisp decides to evaluate an s-expression, how it evaluates it, and how it finds the values needed by the expression.

    A good file to tackle next is xlobj.c, which handles much of the object-oriented support, and has much of the flavor of xleval.c.

    Most of the other files are just libraries of functions to handle particular types of processing, and are easily understood once the central code is grokked.

    One of the charms of xlisp *is* that it is small enough to easily read and comprehend. I hope it stays that way!

    Here's a very brief file-by-file overview of the source. Your files will probably be laid out just a little differently. In particular, if you're not running on unix, instead of 'unixstuff.c' you'll have something like 'dosstuff.c'.

       Size Name        Contains
      ----- --------    --------
       2054 osdefs.h    System specific declarations.  Empty file in my case.
       2050 osptrs.h    System specific pointers.      Empty file in my case.
      14172 unixstuff.c Isolates I/O fns, which tend to be OS-specific. Unix version.
      19049 xlbfun.c    'Basic FUNctions': highlevel eval stuff + random support.
      30229 xlcont.c    'CONTrol': case, do, while, dotimes, other special forms.
       6380 xldbug.c    'DeBUG': break, abort, error, baktrace...
      18006 xldmem.c    'Dynamic MEMory': ram allocation, garbage collector.
       9431 xldmem.h    Declaration of LVAL, scads of useful macros.
      21220 xleval.c    'EVALuation': eval, apply, macroexpand and support for them.
      11935 xlfio.c     'File I/O': OPEN, READ-CHAR, WRITE-CHAR ...
      18481 xlftab.c    'Function TABle': Array of all xlisp primitives.
       4866 xlglob.c    'GLOBal variables':  Boring list of declarations.
      11048 xlimage.c   'memory IMAGE': Code to save/restore contents of xlisp.
      10579 xlinit.c    'INITialization': Start-of-the-world setup code.
       6016 xlio.c      'Input/Output': misc I/O stuff, some called by xlfio.c.
      12664 xlisp.h     consp() ..., xlgetarg() ..., misc types.
       5853 xljump.c    catch, throw, return ...
      20723 xllist.c    car, cdr, append, map ... basic list manipulation.
      11975 xlmath.c    Arithmetic functions -- addition, multiplication ...
      16425 xlobj.c     Object support -- create objects & classes, send msgs...
       4134 xlpp.c      A little prettyprinter.
       9487 xlprin.c    Print an arbitrary lisp value in ascii.
      19535 xlread.c    Read in an arbitrary ascii lisp expression.
      15062 xlstr.c     Manipulation of characters and strings.
      12889 xlstruct.c  Lisp structures -- defstruct and kin.
       5957 xlsubr.c    eq, equal, some internal utility fns.
       7019 xlsym.c     Symbols and obarrays ... maksym, getvalue, getprop...
       5566 xlsys.c     Misc stuff -- read file, print backtrace, peek/poke...
       3926 xmain.c     main(), with top read-eval-print loop.
    
        Back to Top

    How do I add a new primitive fn to xlisp ?

    A preliminary comment: You should have a copy of Guy L Steele's "Common Lisp: The Language" (2nd Edition), and make your new primitives compatible with the standard whenever practical.

    Add a line to the end of xlftab.c:funtab[]. This table contains a list of triples:

    The first element of each triple is the function name as it will appear to the programmer. Make it all upper case.

    The second element is S (for SUBR) if (like most fns) your function wants its arguments pre-evaluated, else F (for FSUBR).

    The third element is the name of the C function to call.

    Remember that your arguments arrive on the xlisp argument stack rather than via the usual C parameter mechanism.

    CAUTION: Try to keep your files separate from generic xlisp files, and to minimize the number of changes you make in the generic xlisp files. This way, you'll have an easier time re-installing your changes when new versions of xlisp come out. For example, if you are going to add many primitive functions to your xlisp, use an #include file rather than putting them all in xlftab.c. It's a good idea to put a marker (like a comment with your initials) on each line you change or insert in the generic xlisp fileset.

    CAUTION: Remember that you usually need to protect the LVAL variables in your function from the garbage-collector. It never hurts to do this, and often produces obscure bugs if you do not. You protect uninitialized local variables with xlsave1() and initialized local variables with xlprot1().

    BE CAREFUL NOT TO PROTECT UNINITIALIZED LOCAL VARIABLES WITH XLPROT1() OR XLPROTECT()! This will appear to work fine until garbage collection happens at an inconvenient moment, at which point the garbage collector will wind up following your uninitialized pointer off to never-never land.

    Note: If you have several pointers to protect, you can save a little runtime and codespace by using xlstkcheck(number-of-variables-to-protect) followed by xlsave()s and xlprotect()s instead of the more expensive xlsave1()s and xlprot1()s.

    Generic code for a new primitive fn:

      /* xlsamplefun - do useless stuff.        */
      /* Called like (samplefun '(a c b) 1 2.0) */
      LVAL xlsamplefun()
      {
          /* Variables to hold the arguments: */
          LVAL    list_arg, integer_arg, float_arg;
      
          /* Get the arguments, with appropriate errors */
          /* if any are of the wrong type.  Look in     */
          /* xlisp.h for macros to read other types of  */
          /* arguments.  Look in xlmath.c for examples  */
          /* of functions which can handle an argument  */
          /* which may be either int or float:          */
          list_arg    = xlgalist()  ;  /* "XLisp Get A LIST"   */
          integer_arg = xlgafixnum();  /* "XLisp Get A FIXNUM" */
          float_arg   = xlgaflonum();  /* "XLisp Get A FLONUM" */
      
          /* Issue an error message if there are any extra arguments: */
          xllastarg();
      
          /* Call a separate C function to do the actual  */
          /* work.  This way, the main function can       */
          /* be called from both xlisp code and C code.   */
          /* By convention, the name of the xlisp wrapper */
          /* starts with "xl", and the native C function  */
          /* has the same name minus the "xl" prefix:     */
          return samplefun( list_arg, integer_arg, float_arg );
      }
      LVAL samplefun( list_arg, integer_arg, float_arg )
      LVAL            list_arg, integer_arg, float_arg;
      {
          FIXTYPE val_of_integer_arg;
          FLOTYPE val_of_float_arg;
      
          /* Variables which will point to LISP objects: */
          LVAL result;
          LVAL list_ptr;
          LVAL float_ptr;
          LVAL int_ptr;
      
          /* Protect our internal pointers by */
          /* pushing them on the evaluation   */
          /* stack so the garbage collector   */
          /* can't recycle them in the middle */
          /* of the routine:                  */
          xlstkcheck(4);    /* Make sure following xlsave */
                            /* calls won't overrun stack. */
          xlsave(list_ptr); /* Use xlsave1() if you don't */
          xlsave(float_ptr);/* do an xlstkcheck().        */
          xlsave(int_ptr);
          xlsave(result);
      
          /* Semantic check, illustrating use of xlfail(): */
          if (list_ptr == NIL) {
              xlfail("null list");
              /* Won't return. */
          }
      
          /* Create an internal list structure, protected */
          /* against garbage collection until we exit fn: */
          list_ptr = cons(list_arg,list_arg);
      
          /* Get the actual values of our fixnum and flonum: */
          val_of_integer_arg = getfixnum( integer_arg );
          val_of_float_arg   = getflonum( float_arg   );
      
          /* Semantic check, illustrating use of xlerror(): */
          if (val_of_integer_arg < -2) {
              xlerror("bad integer",cvfixnum(val_of_integer_arg));
              /* Won't return. */
          }
      
          /*******************************************/
          /* You can have any amount of intermediate */
          /* computations at this point in the fn... */
          /*******************************************/
      
          /* Make new numeric values to return: */
          integer_ptr = cvfixnum( val_of_integer_arg * 3   );
          float_ptr   = cvflonum( val_of_float_arg   * 3.0 );
      
          /* Cons it all together to produce a return value: */
          result = cons( float_ptr,   NIL    );
          result = cons( integer_ptr, result );
          result = cons( list_ptr,    result );
      
          /* Restore the stack, canceling the xlsave()s: */
          xlpopn(4); /* Use xlpop() for a single argument.*/
      
          return result;
      }
    

    Example of what NOT to do:

    Here's a function I wrote which does *NOT* correctly prevent the garbage collector from stealing its dynamically allocated cells:

      LVAL incorrect_Point_To_List( p )/*DON'T USE THIS CODE! */
      geo_point*                    p;
      /*-
          Convert point to (x y z) list.
      -*/
      {
          LVAL result;
          xlsave1(result);
          result = cons(              /* THIS CODE IS BROKEN! */
              cvflonum(        p->x), /* THIS CODE IS BROKEN! */
              cons(                   /* THIS CODE IS BROKEN! */
                  cvflonum(    p->y), /* THIS CODE IS BROKEN! */
                  cons(               /* THIS CODE IS BROKEN! */
                      cvflonum(p->z), /* THIS CODE IS BROKEN! */
                      NIL             /* THIS CODE IS BROKEN! */
                  )                   /* THIS CODE IS BROKEN! */
              )                       /* THIS CODE IS BROKEN! */
          );                          /* THIS CODE IS BROKEN! */
          xlpop();
          return result;
      }
    

    The problem with the above function is that the "z" cell will be allocated first, and is not protected during the allocation of the "y" flonum (or vice versa, depending on the order the compiler chooses to evaluate these arguments). Similarly, the "y" cell is not protected during allocation of the "x" flonum. Here is a correct version, in which "result" always protects the list-to-date:

      LVAL correct_Point_To_List( p )
      geo_point*                  p;
      /*-
          Convert point to (x y z) list.
      -*/
      {
          LVAL result;
          xlsave1(result);
          result = cons( cvflonum(p->z), NIL          );
          result = cons( cvflonum(p->y), result       );
          result = cons( cvflonum(p->x), result       );
          xlpop();
          return result;
      }
    
        Back to Top

    Minor Observations:

    xlapply, xlevform and sendmsg will issue an error if they encounter a s_macro CLOSURE. You are not allowed to use APPLY or FUNCALL with macros in Common Lisp. There is no way provided to declare macro methods, nor do they make much sense...

    Neither xlapply nor sendmsg will handle FSUBRs. Common Lisp does not allow APPLYing a special form (FSUBR), and since SEND is a SUBR, all of its arguments are already evaluated, so it is not possible to have FSUBR methods.

    Since xlisp tracks the three most recent input expressions (in variables +, ++ and +++) and three most recent results (in variables *, ** and ***), things may occasionally not get garbage-collected as soon as you expect!

    Both xlobj.c:xloinit() and xlobj.c:obsymvols() initialize the "object" and "class" variables. This is neither redundant nor a bug:

    xloinit creates the classes class and object, as well as the symbols, but sets the C variables class and object to point to the class and object.

    obsymbols just sets the C variables by looking up the symbols. It is needed because when you restore a workspace you don't create new objects but still need to know where the existing objects are (they might be in a different location in the saved workspace). Notice that obsymbols is called by xlsymbols which is called both when initializing a new workspace and when restoring an old workspace.

        Back to Top

    Acknowledgements

    This document is considerably improved thanks to careful reading and thoughtful suggestions from Ken Whedbee (kcw@beach.cis.ufl.edu) and (especially) Tom Almy (toma@sail.labs.tek.com).

        Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/internals/c-printf.htm0000644000175000000620000004433711512762341022751 0ustar stevestaff ANSI C 'printf' Format Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    ANSI C 'printf' Format


    Nyquist/XLISP: The *float-format* and *integer-format* variables define format strings for the underlying 'sprintf' C function. In C, the same format string specification is used for 'fprint' [writes to a file], 'printf' [writes to standard output] and 'sprintf' [writes to another string]. These three functions are meant in the following text with 'the printf functions'.

    ANSI C: The printf functions write output under control of a format string that specifies how subsequent arguments are converted for output. If there are insufficient arguments for the format, the behavior is undefined. If the format is exhausted while arguments remain, the excess arguments are evaluated but are otherwise ignored. The printf functions return when the end of the format string is encountered.

      Back to top


    Format String


    The format string is composed of zero or more directives, which are ordinary characters [except "%"], which are copied unchanged to the output stream, and conversion specifications, each of which results in fetching zero or more subsequent arguments. Each conversion specification is introduced by the character "%":

    %[flags][field-with][precision][data-type]conversion-type
    

    After the "%", the following appear in sequence:

    • Flags - Zero or more flags that modify the meaning of the conversion specification.

    • Field Width - An optional decimal integer specifying a minimum field width. If the converted value has fewer characters than the field width, it will be padded with spaces on the left to the field width. The field is padded on the right if the  −  flag has been given, or padded with zeros if the  0  flag had been given. A negative integer, given as 'field width' argument, is interpreted as a  −  flag followed by a positive field width.

    • Precision - An optional decimal integer that gives the minimum number of digits to appear for integer conversions, the number of digits to appear after the decimal-point character for floating-point  e  and  f  conversions, or the maximum number of significant digits for the floating-point  g  conversion.

      The precision takes the form of a period character followed by an optional decimal integer:

      .[integer]
      

      If the integer is omitted, it is treated as zero, a negative precision argument is taken as if it were missing.

      Note: In C, the precision also specifies the maximum number of characters to be written from a string in 's' conversion, but "%s" should not be used in the XLISP *float-format* or *integer-format* variables, otherwise XLISP will crash.

    • Data Type - An optional character specifying a data type to be used for the conversion.

      XLISP: Nyquist/XLISP uses C 'long' signed integers and C 'double' floats only, so with floating-point numbers no special data type needs to be given, while integer conversions should always be prefixed by a 'l' [lowercase L], otherwise the printed representation of integer numbers may be differently than the behaviour of the Nyquist/XLISP functions.

    • Conversion Type - A character that specifies the conversion type to be applied.

    Not with Nyquist/XLISP: In C, a 'field width' or 'precision', or both, may be indicated by an asterisk * instead of a digit string. In this case, an int argument supplies the field width or precision. The arguments specifying field width or precision, or both, shall appear [in that order] before the argument [if any] to be converted.

      Back to top


    Flags


    The flag characters and their meanings are:

    −  [minus sign character]

    The result of the conversion will be left-justified within the field.

    +  [plus sign character]

    The result of a signed conversion will always begin with a plus or minus sign.

    space  [space character]

    If the first character of a signed conversion is not a sign, or if a signed conversion results in no characters, a space will be prepended to the result. If the 'space' and  +  flags both appear, the 'space' flag will be ignored.

    #  [hash character]

    The result is to be converted to an 'alternate form':

    Octal Numbers - For o conversion, it increases the precision to force the first digit of the result to be a zero.

    Hexadecimal Numbers - For x or X conversion, a nonzero result will have 0x or 0X prepended to it.

    Floating-point Numbers - For e, E, f, g, and G conversions, the result will always contain a decimal-point character, even if no digits follow it (normally, a decimal-point character appears in the result of these conversions only if a digit follows it). For g and G conversions, trailing zeros will not be removed from the result. For other conversions, the behavior is undefined.

    0  [number zero character]

    For integer d, i, o, u, x, X, and floating-point e, E, f, g, G conversions, leading zeros [following any indication of sign or base] are used to pad to the field width. No space padding is performed. If the '0' and  −  flags both appear, the '0' flag will be ignored. For integer d, i, o, u, x, X conversions, if a precision is specified, the '0' flag will be ignored. For other conversions, the behavior is undefined.

      Back to top


    Data Type


    h  [lowercase H character]

    A following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument [the argument will have been promoted according to the integral promotions, and its value shall be converted to short int or unsigned short int before printing].

    A following n conversion specifier applies to a pointer to a short int argument.

    l  [lowercase L character]

    A following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int argument.

    A following n conversion specifier applies to a pointer to a long int argument.

    L  [uppercase L character]

    A following e, E, f, g, or G conversion specifier applies to a long double argument.

    If an h, l, or L appears with any other conversion specifier, the behavior is undefined.

      Back to top


    Conversion Type


    Integer conversion:

    d, i, o, u, x, X

    The integer argument is converted to:

       d  →  signed decimal
       i  →  signed decimal
       o  →  unsigned octal
       u  →  unsigned decimal
       x  →  unsigned hexadecimal, using 'abcdef'
       X  →  unsigned hexadecimal, using 'ABCDEF'

    The precision specifies the minimum number of digits to appear. If the value being converted can be represented in fewer digits, it will be expanded with leading zeros. The default precision is 1. The result of converting a zero value with an explicit precision of zero results in no characters.

    XLISP: Nyquist/XLISP uses C 'long' signed integers, so the integer conversions should always be prefixed by a 'l' [lowercase L] indicating a 'long int' C data type, otherwise the printed representation of integer numbers may be differently than the behaviour of the Nyquist/XLISP functions.

    Floating-point conversion:

    f

    The floating-point argument of C data type 'double' is converted to decimal notation in the style:

    [-]ddd.ddd
    

    where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6. If the precision is explicitly zero, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.

    e, E

    The floating-point argument of C data type 'double' is converted in the style:

    [-]d.ddde+-dd
    

    where there is one digit before the decimal-point character [which is nonzero if the argument is nonzero] and the number of digits after it is equal to the precision. If the precision is missing, it is taken as 6. If the precision is zero, no decimal-point character appears. The value is rounded to the appropriate number of digits. The exponent always contains at least two digits. If the value is zero, the exponent is zero. The "E" conversion specifier will produce a number with 'E' instead of 'e' introducing the exponent.

    g, G

    The floating-point argument of C data type 'double' is converted in style  f  or  e  or in style  E  in the case of a "G" conversion specifier, with the precision specifying the number of significant digits. If an explicit precision is zero, it is taken as 1. The style used depends on the value converted. Style  e  will be used only if the exponent resulting from such a conversion is less than -4 or greater than or equal to the precision. Trailing zeros are removed from the fractional portion of the result. A decimal-point character appears only if it is followed by a digit.

    Other conversion types defined in ANSI C, but not to be used with the XLISP *float-format* and *integer-format* variables, because XLISP will produce nonsense or just simply will crash:

    c

    The integer argument is converted to an 'unsigned char', and the resulting character is written.

    XLISP: If the *float-format* or *integer-format* variable is set to "%c", then with integers or floating-point numbers, the lowest 8 bit of the internal binary representation will be interpreted as an ASCII character.

    s

    The argument shall be a pointer to an array of character type. Characters from the array are written up to [but not including] a terminating null character. If the precision is specified, no more than that many characters are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character.

    XLISP: If

    p

    The argument shall be a pointer to 'void'. The value of the pointer is converted to a sequence of printable characters, in an implementation-defined manner.

    n

    The argument shall be a pointer to an integer into which is written the number of characters written to the output stream so far by this call to the C 'fprintf' function. No argument is converted.

    %

    A "%" is written. No argument is converted. The complete conversion specification shall be "%%".

    If a conversion specification is invalid, the behavior is undefined. In no case does a nonexistent or small field width cause truncation of a field. If the result of a conversion is wider than the field width, the field is expanded to contain the conversion result.

    The minimum value for the maximum number of characters produced by any single conversion shall be 509.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/0002755000175000000620000000000011537433125020535 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/file-io.htm0000644000175000000620000002510011512762341022565 0ustar stevestaffXLISP: An Object-oriented Lisp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    File I/O


    1. File I/O Examples - from the XLISP 2.0 manual, by David Betz
    2. Files and Directories
    3. Testing Existence
    4. Text File I/O
    5. Binary File I/O

    1  File I/O Examples


    1.1  Input from a File


    The basics of file i/o with XLISP:

    • To open a file for input, use the open function with the keyword argument :direction set to :input.

    • To open a file for output, use the open function with the keyword argument :direction set to :output.

    • To close a file, use the close function.

    The open function takes a single required argument which is the name of the file to be opened. This name can be in the form of a string or a symbol. The open function returns an object of type 'file-stream' if it succeeds in opening the specified file. It returns the value NIL if it fails.

    In order to manipulate the file, it is necessary to save the value returned by the open function. This is usually done by assigning it to a variable with the setq special form or by binding it using let or let*. Here is an example:

    (setq file-stream (open "init.lsp" :direction :input))
    

    Evaluating this expression will result in the file 'init.lsp' being opened. The file object that will be returned by the open function will be assigned to the variable 'file-stream'.

    It is now possible to use the file for input. To read an expression from the file, just supply the value of the 'file-stream' variable as the optional 'stream' argument to the read function:

    (read file-stream)
    

    Evaluating this expression will result in reading the first expression from the file 'init.lsp'. The expression will be returned as the result of the read function. More expressions can be read from the file using further calls to the read function. When there are no more expressions to read, the read function will return NIL [or whatever value was supplied as the second argument to read].

    Once you are done reading from the file, you should close it. To close the file, use the close function:

    (close file-stream)
    

    Evaluating this expression will cause the file to be closed.

      Back to Top


    1.2  Output to a File


    Writing to a file is pretty much the same as reading from one. You need to open the file first. This time you should use the open function to indicate that you will do output to the file:

    (setq file-stream (open "test.dat" :direction :output))
    

    Evaluating this expression will open the file 'test.dat' for output. If the file already exists, its current contents will be discarded. If it doesn't already exist, it will be created. In any case, a 'file-stream' object will be returned by the open function. This file object will be assigned to the 'file-stream' variable.

    It is now possible to write to this file by supplying the value of the 'file-stream' variable as the optional 'stream' parameter in the print function.

    (print "Hello there" file-stream)
    

    Evaluating this expression will result in the string "Hello there" being written to the file "test.dat". More data can be written to the file using the same technique.

    Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file:

    (close file-stream)
    

    Evaluating this expression will close the output file and make it permanent.

      Back to Top


    1.3  A Slightly More Complicated File Example


    This example shows how to open a file, read each Lisp expression from the file and print it. It demonstrates the use of files and the use of the optional 'stream' argument to the read function.

    (do* ((file-stream (open "test.dat" :direction :input))
          (expression (read file-stream) (read file-stream)))
         ((null expression) nil)
      (print expression))
    

      Back to top


    1.4  Closing Files via 'unwind-protect'


    To make sure that the file gets closed in the end, the file i/o functions can be wrapped by an unwind-protect form:

    (let ((file-stream (open "test.dat" :direction :input)))
      (unwind-protect
        ;; protect-form
        (do ((expression (read file-stream) (read file-stream)))
            ((null expression) nil)
          (print expression))
        ;; clean-up form
        (when file-stream (close file-stream))))
    

    This pattern can be found in many file i/o functions:

    (let ((file-stream (open filename :direction direction)))
      (unwind-protect
        (progn
          ;; do something with the file-stream
          )
        (when file-stream (close file-stream))))
    

      Back to top


    3  Testing Existence


    Note that these function are meant to prevent accidents during basic file i/o, they may not be able to test if a file or directory physically exists or is a link to a different place.

    The Nyquist listdir function can be used to test if a directory exists:

    (defun directory-exists-p (string)
      (and (listdir string) t))
    

    Testing if a file exists is a bit more tricky because on Unix [including Linux and Mac OS X] a directory is a special kind of file, so the XLISP open function also can open directories. That's why we first must make sure that the filename string is not the name of an existing directory:

    (defun file-exists-p (string)
      (or (stringp string) (error "not a string" string))
      (unless (listdir string)
        (let ((file-stream (open string)))
          (when file-stream
            (close file-stream)
            string))))
    

    Before creating a new file it's always a good idea to check if a file or directory with the same name already exists:

    (defun file-or-directory-exists-p (string)
      (or (stringp string) (error "not a string" string))
      (when (or (listdir string)
                (let ((file-stream (open string)))
                  (when file-stream
                    (close file-stream)
                    t)))
        string))
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/xlisp-objects.htm0000644000175000000620000007417411512762341024046 0ustar stevestaffXLISP Objects Primer Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    XLISP Objects Primer


    1. Programming Styles
    2. Object Oriented Programming
    3. Xlisp Object Terminology
    4. Sending Messages
    5. Classes
    6. A Better Class Example
    7. Instances
    8. Methods
    9. Sending Messages To A Superclass
    10. Object And Class
    11. Objects Example

    This tutorial is adapted from a 'XLISPOOP.DOC' document with the following copyright:

    XLisp 2.0 Objects Primer by Tim I Mikkelsen - February 3, 1990

    Copyright (c) 1990 by Tim I. Mikkelsen. All Rights Reserved. No part of this document may be copied, reproduced or translated for commercial use without prior written consent of the author. Permission is granted for non-commercial use as long as this notice is left intact.

    One of the features in the design of XLISP is object-oriented programming. This primer is intended to serve as a very brief introduction to the object facilities of the XLISP 2.0 dialect of LISP. Note that the object features of XLISP are not based on other existing object definitions in other LISP dialects. If you find problems in the primer, I'd appreciate hearing.

    Tim Mikkelsen, (tim@hpfcbig.SDE.HP.COM), 4316 Picadilly Drive, Fort Collins, Colorado 80526


    1  Programming Styles


    There are many programming models, some of them are:

    • procedural
    • functional
    • rule-based
    • declarative
    • object-oriented

    A language can have aspects of one or many of these programming models.

    Procedure-Oriented

    The programming paradigm most people are familiar with is the procedural style. The primitives in procedural programming are subroutines and data structures. Through these primitives, programmers have some limited abilities to share programs and program fragments. C and Pascal are examples of procedural languages. Some procedural languages [such as Modula and ADA] have extensions that provide for better sharing of code.

    Object-Oriented

    Object-oriented programming is based on the primitives of objects, classes and messages. Objects are defined in terms of classes. Actions occur by sending a message to an object. An object's definition can be inherited from more general classes. Objective-C and C++ both are object-oriented dialects of the C language. Many dialects of Lisp have some object-oriented extension [Flavors, Common LOOPS, CLOS and others]. There currently is standards work proceeding to add object-oriented programming to Common Lisp.

      Back to top


    2  Object Oriented Programming


    The object-oriented programming model is based around the concepts of objects, classes and messages. An object is essentially a black box that contains internal state information. You send an object a message which causes the object to perform some operation. Objects are defined and described through classes.

    One aspect of an object is that you do not have to know what is inside or how it works to be able to use it. From a programming point of view, this is very handy. You can develop a series of objects for someone to use. If you need to change what goes on inside, the users of the objects should be unaware.

    Another aspect of objects is that of inheritance. You can build up new classes from existing classes by inheriting the existing class's functionality and then extending the new definition. For example, you can define a 'tool' class with various attributes and then go about creating object instances like 'tool-1', 'tool-2', and so on. You can also create new sub-classes of the 'tool' class like 'power-tool'. This is also very handy because you don't have to re-implement something if you can build it up from existing code.

      Back to top


    3  Xlisp Object Terminology


    There are many different languages with object-oriented extensions and facilities. The terminology, operations and styles of these are very different. Some of the main definitions for XLISP's object-oriented extensions are:

    object data type

    The object data type is a built-in data type of XLISP. Members of the object data type are object instances and classes.

    object instances

    An 'object instance' is a composite structure that contains internal state information, methods [the code which respond to messages], a pointer to the object instance's defining class and a pointer to the object's super-class. XLISP contains no built-in object instances.

    class objects

    A class object is, essentially, the template for defining the derived object instances. A class object, although used differently from a simple object instance, is structurally a member of the object data type. It also contains the linking mechanism that allows you to build class hierarchies [sub-classes and super-classes]. XLISP contains two built-in class objects, 'object' and 'class'.

    message selector

    The 'message selector' is the symbol that is used to select a particular action [method] from the object.

    message

    The 'message' is the combination of the message selector and the data [if any] to be sent to the object.

    method

    The 'method' is the actual code that gets executed when the object receives the message.

      Back to top


    4  Sending Messages


    The mechanism for sending messages to XLISP objects is via the send function. It takes an object, a message selector and various optional arguments [depending on the message selector].

    The way that a user creates a new object is to send a :new message to a previously defined class. The result of this send will return an object, so this is normally preceded by a setq.

    > (setq my-object (send object :new))
    #<Object: #2e100>
    

    The examples are similar to what you should see on your computer screen. The '>' is the normal XLISP prompt, the characters that follow the prompt is what you type in to try the examples. Note that XLISP prints objects together with their internal pointer, like #2e100 in the example above. These #ID numbers may not match with the numbers you see on the screen if you try the examples, but this is not an error.

    The object created above is of limited value. Most often, you create a 'class' object and then you create instances of that class. So in the following example, a class called 'my-class' is created that inherits its definition from the a built-in class definition. Then two instances are created of the new class:

    > (setq my-class (send class :new '()))
    #<Object: #27756>
    
    > (setq my-instance (send my-class :new))
    #<Object: #27652>
    
    > (setq another-instance (send my-class :new))
    #<Object: #275da>
    

      Back to top


    5  Classes


    In the examples above, a :new message was used to create an object. The message used to see what is in an object is the :show message:

    > (send my-class :show)
    Object is #<Object: #27756>, Class is #<Object: #23fe2>
      MESSAGES = NIL
      IVARS = NIL
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = #<Object: #23fd8>
      IVARCNT = 0
      IVARTOTAL = 0
    #<Object: #27756>
    

    From the display of the 'my-class' object you can see there are a variety of components. The components of a class are:

    class pointer

    This pointer shows to what class the object [instance or class] belongs. For a class, this always points to the built-in object class. This is also true of the class object, its class pointer points to itself.

    superclass pointer

    This pointer shows what the next class up the class hierarchy is. If the user does not specify what class is the superclass, it will point to the built-in class object.

    messages

    This component shows what messages are allowed for the class, and the description of the method that will be used. If the method is system-defined, it will show up in the form of:

    #<Subr-: #18b98>
    

    Remember that the class hierarchy [through the superclass pointer] is searched if the requested message is not found in the class.

    instance variables

    The IVARS component lists what instance variables will be created when an object instance is created. If no instances of the class exist, there are no instance variables. If there are 5 instances of a class, there are 5 complete and different groups of the instance variables.

    class variables and values

    The CVARS component lists what class variables exist within the class. The CVALS component shows what the current values of the variables are. Class variables are used to hold state information about a class. There will be one of each of the class variables, independent of the number of instances of the class created.

      Back to top


    6  A Better Class Example


    The example shown in the previous section does work, but the class and instances created don't really do anything of interest. The following example sets up a tool class and creates some tool instances:

    > (setq my-tools (send class :new '(power moveable operation)))
    #<Object: #277a6>
    
    > (send my-tools :answer :isnew '(pow mov op) 
        '((setq power pow moveable mov operation op))
    #<Object: #277a6>
    
    > (setq drill (send my-tools :new 'AC t 'holes))
    #<Object: #2ddbc>
    
    > (setq hand-saw (send my-tools :new 'none t 'cuts))
    #<Object: #2dc40>
    
    > (setq table-saw (send my-tools :new 'AC nil 'cuts))
    #<Object: #2db00>
    

    A class of objects called 'my-tools' and three instances were created:

      [Figure 1]

    First the class 'my-tools' was created by sending the :new message to the built-in class object. Then, within the 'my-tool' class, three instances called 'drill', 'hand-saw' and 'table-saw' were created by sending the :new message to the 'my-tools' class. Notice the three parameters following the message selector. The instance variables are initialized from these parameters by the :isnew method, inherited from the 'my-tools' class at the time when the instances were created.

      Back to top


    7  Instances


    The following is a display of the contents of some of the instances created above, where the XLISP object #ID numbers had been replaced by the respective class and instance names:

    > (send drill :show)
    Object is #<Object: #[drill]>, Class is #<Object: #[my-tools]>
      POWER = AC
      MOVEABLE = T
      OPERATION = HOLES
    #<Object: #[drill]>
    
    > (send hand-saw :show)
    Object is #<Object: #[hand-saw]>, Class is #<Object: #[my-tools]>
      POWER = NONE
      MOVEABLE = T
      OPERATION = CUTS
    #<Object: #[hand-saw]>
    

    From the display of these instances you can see there are some components and values. The components of an instance are:

    class pointer

    This pointer shows to which class the current object instance belongs. It is through this link that the system finds the methods to execute for the received messages.

    instance variables and values

    The variables existing within the instance are shown together with their values. Instance Variables are used to hold state information for each instance. There will be a group of instance variables for each instance.

      Back to top


    8  Methods


    There have been a few of the messages and methods in XLISP shown to this point like :new and :show. The following are the methods built into XLISP:

    :answer

    The :answer method allows you to define or change methods within a class.

    :class

    The :class method returns the class of an object.

    :isnew

    The :isnew method causes an instance to run its initialization code. When the :isnew method is run on a class, it resets the class state. This allows you to re-define instance variables, class variables, etc.

    :new

    The :new method allows you to create an instance when the :new message is sent to a user-defined class. The :new method allows you to create a new class when the :new message is sent to the built-in class.

    :show

    The :show method displays the instance or class.

    :isa

    The :isa method tests if an object inherits from a class.

      Back to top


    9  Sending Messages To A Superclass


    In addition to the send function, there is another function called send-super. The send-super function causes the specified message to be performed by the superclass method. This is a mechanism to allow chaining of methods in a class hierarchy. This chaining behavior can be achieved by creating a method for a class with the :answer message. Within the body of the method, you include a send-super form. This function is allowed only inside the execution of a method of an object.

      Back to top


    10  Object And Class


    The definition of the built-in class 'object' is:

    > (send object :show)
    Object is #<Object: #[built-in-object]>, Class is #<Object: #[built-in-class]>
      MESSAGES = ((:ISA   . #<Subr-: #[built-in-isa-method]>)
                  (:SHOW  . #<Subr-: #[built-in-show-method]>)
                  (:CLASS . #<Subr-: #[built-in-class-method]>)
                  (:ISNEW . #<Subr-: #[built-in-isnew-method]>))
      IVARS = NIL
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = NIL  ; no superclass
      IVARCNT = 0
      IVARTOTAL = 0
    #<Object: #[built-in-object]>
    

    Note that 'object' is a class, as opposed to an 'instance-style' object. 'object' has no superclass, it is the top or root of the class hierarchy. 'object's class is 'class'.

    > (send class :show)
    Object is #<Object: #[built-in-class]>, Class is #<Object: #[built-in-class]>
      MESSAGES = ((:ANSWER . #<Subr-: #[built-in-answer-method]>) 
                  (:ISNEW  . #<Subr-: #[built-in-isnew-method]>) 
                  (:NEW    . #<Subr-: #[built-in-new-method]>))
      IVARS = (MESSAGES IVARS CVARS CVALS SUPERCLASS IVARCNT IVARTOTAL)
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = #<Object: #[built-in-object]>
      IVARCNT = 7
      IVARTOTAL = 7
    #<Object: #[built-in-class]>
    

    'class' has a superclass of 'object'. It's class is itself, 'class'.

      Back to top


    11  Objects Example


    The following is an example, using the idea of tools again. It contains a hierarchy of tool classes. The top of the class hierarchy is 'tools'. 'hand-tools' and 'shop-tools' are sub-classes of 'tools'. The example creates instances of these sub-classes. It is possible to extend this example in various ways. One obvious extension would be to create a third tier of classes under 'hand-tools' that could contain classes like drills, screwdrivers, pliers and so on.

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;;       Define the superclasses and classes
    ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; make TOOLS superclass
    ;;
    ;;   with a different :ISNEW method
    ;;   added methods are :BORROW and :RETURN
    ;;
    ;;   class variables      NUMBER        contains # of tool instances
    ;;                        ACTIVE-LIST   contains list of current objects
    ;;
    ;;   instance variables   POWER         list - (AC BATTERY HAND)
    ;;                        MOVEABLE      CAN-CARRY or CAN-ROLL or FIXED
    ;;                        OPERATIONS    list
    ;;                        MATERIAL      list - (WOOD METAL PLASTIC ...)
    ;;                        PIECES        list
    ;;                        LOCATION      HOME or person's name
    ;;
    
    (setq tools (send class :new '(power moveable operations
                                   material pieces location) 
                                 '(number active-list)))
    
    (send tools :answer :isnew '() 
      '((setq number      (if (null number) 1 (1+ number))
              active-list (cons self active-list)
              location    'home)))
    
    (send tools :answer :borrow '(by-who)
      '((if (eq location 'home)
            (setq location by-who)
            (print "you can't"))))
    
    (send tools :answer :return '()
      '((if (eq location 'home)
            (print "got it already")
            (setq location 'home))))
    
    ;; make HAND-TOOLS class
    ;; - with a different :ISNEW method
    ;; - new instance variable WEIGHT = <number> of pounds
    ;; - the rest is inherited from TOOLS
     
    (setq hand-tools (send class :new '(weight) '() tools))
    
    (send hand-tools :answer :isnew '(pow op mat parts w-in)
      '((setq power       pow
              moveable    'can-carry
              operations  op
              material    mat
              pieces      parts
              weight      w-in)
        (send-super :isnew)))
    
    ;; make SHOP-TOOLS class
    ;; - with a different :ISNEW method
    ;; - no new instance variables
    ;; - the rest is inherited from TOOLS
    
    (setq shop-tools (send class :new '() '() tools))
    
    (send shop-tools :answer :isnew '(pow mov op mat parts)
      '((setq power       pow
              moveable    mov
              operations  op
              material    mat
              pieces      parts)
        (send-super :isnew)))
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;;       Create instances of various tool classes
    ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    (setq hand-drill (send hand-tools :new       ; make an instance - HAND-DRILL
                                      '(ac) 
                                      '(drill polish grind screw)
                                      '(wood metal plastic)
                                      '(drill drill-bits screw-bits buffer)
                                      '2.5))
    
    (setq table-saw  (send shop-tools :new       ; make an instance - TABLE-SAW
                                      '(ac)
                                      'fixed
                                      '(rip cross-cut)
                                      '(wood plastic)
                                      '(saw blades fence)))
    
    (setq radial-arm (send shop-tools :new       ; make an instance = RADIAL-ARM
                                      '(ac)
                                      'can-roll
                                      '(rip cross-cut)
                                      '(wood plastic)
                                      '(saw blades dust-bag)))
    

    The following session shows how to use the tool definitions from the code above:

    > (send hand-drill :borrow 'fred)
    FRED
    
    > (send table-saw :return)
    "got it already"
    "got it already"
    
    > (send hand-drill :borrow 'joe)
    "you can't"
    "you can't"
    
    > (send hand-drill :return)
    HOME
    

    Fred was able to borrow the 'hand-drill'. When an attempt was made to return the 'table-saw', it was already at home. A second attempt to borrow the 'hand-drill' indicated that "you can't" because it was already lent out. Lastly, the 'hand-drill' was returned successfully. [Note that the "got it already" and "you can't" strings show up twice in the display because the methods both print and return the string.)

    The following example shows the structure of the 'tools' object with the XLISP #ID numbers replaced by the related class and method names:

    > (send tools :show)
    Object is #<Object: #[tools]>, Class is #<Object: #[class]>
      MESSAGES = ((:RETURN . #<Closure-:RETURN: #[tools-return-method]>) 
                  (:BORROW . #<Closure-:BORROW: #[tools-borrow-method]>) 
                  (:ISNEW  . #<Closure-:ISNEW:  #[tools-isnew-method]>))
      IVARS = (POWER MOVEABLE OPERATIONS MATERIAL PIECES LOCATION)
      CVARS = (NUMBER ACTIVE-LIST)
      CVALS = #(3 (#<Object: #[radial-arm]> 
                   #<Object: #[table-saw]> 
                   #<Object: #[hand-drill]>))
      SUPERCLASS = #<Object: #[object]>
      IVARCNT = 6
      IVARTOTAL = 6
    #<Object: #[tools]>
    

    The two 'tools' sub-classes 'hand-tools' and 'shop-tools' structure looks like:

    > (send hand-tools :show)
    Object is #<Object: #[hand-tools]>, Class is #<Object: #[class]>
      MESSAGES = ((:ISNEW . #<Closure-:ISNEW: #[hand-tools-isnew-method]>))
      IVARS = (WEIGHT)
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = #<Object: #[tools]>
      IVARCNT = 1
      IVARTOTAL = 7
    #<Object: #[hand-tools]>
    
    > (send shop-tools :show)
    Object is #<Object: #[shop-tools]>, Class is #<Object: #[class]>
      MESSAGES = ((:ISNEW . #<Closure-:ISNEW: #[shop-tools-isnew-method]>))
      IVARS = NIL
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = #<Object: #[tools]>
      IVARCNT = 0
      IVARTOTAL = 6
    #<Object: #[shop-tools]>
    

    The class 'hand-tools' has an instance 'hand-drill' which looks like:

    > (send hand-drill :show)
    Object is #<Object: #[hand-drill]>, Class is #<Object: #[hand-tools]>
      WEIGHT = 2.5
      POWER = (AC)
      MOVEABLE = CAN-CARRY
      OPERATIONS = (DRILL POLISH GRIND SCREW)
      MATERIAL = (WOOD METAL PLASTIC)
      PIECES = (DRILL DRILL-BITS SCREW-BITS BUFFER)
      LOCATION = HOME
    #<Object: #[hand-drill]>
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/lisp-hints.htm0000644000175000000620000017564311512762341023355 0ustar stevestaff Lisp Hints Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Lisp Hints


    The original document was written by Geoffrey J. Gordon [ggordon@cs.cmu.edu], Friday, February 5, 1993, for CMUCL.

    Modified by:

    • Bruno Haible for CLISP.
    • Tom Almy in 1995 for XLISP Plus.
    • Edgar M. Franke [edgar-rft@web.de] in 2010 for Nyquist.

    All examples tested with Nyquist 3.03 in November 2010.


    Table of Contents


    1. Symbols
    2. Numbers
    3. Conses
    4. Lists
    5. Functions
    6. Printing
    7. Forms and the Top-Level Loop
    8. Special Forms
    9. Binding
    10. Dynamic Scoping
    11. Arrays
    12. Strings
    13. Setf
    14. Booleans and Conditionals
    15. Iteration
    16. Non-local Exits
    17. Funcall, Apply, and Mapcar
    18. Lambda
    19. Sorting
    20. Equality
    21. Some Useful List Functions

    1  Symbols


    A symbol is just a sequence of characters. There are restrictions on what you can include in a symbol and what the first character can be, but as long as you stick to letters, digits, and hyphens, you'll be safe. [Except that if you use only digits and possibly an initial hyphen, Lisp will think you typed an integer rather than a symbol.] Some examples of symbols:

    a
    b
    c1
    foo
    bar
    baaz-quux-garply
    

    Some things you can do with symbols follow. Things after a '>' prompt are what you type to the Lisp interpreter, while other things are what the Lisp interpreter prints back to you. The semicolon ';' is Lisp's comment character. Everything from a ';' to the end of line is ignored.

    > (setq a 5)        ; store a number as the value of a symbol
    5
    
    > a                 ; take the value of a symbol
    5
    
    > (let ((a 6))      ; bind the value of a symbol temporarily to 6
        a)
    6
    
    > a                 ; the value returns to 5 once the let is finished
    5
    
    > (+ a 6)           ; use the value of a symbol as an argument to a function
    11
    
    > b                 ; try to take the value of a symbol which has no value
    error: unbound variable - b
    

    There are two special symbols,  T  and NIL. The value of  T  is defined always to be  T , and the value of NIL is defined always to be NIL. Lisp uses  T  and NIL to represent true and false. An example of this use is in the if statement, described more fully later:

    > (if t 5 6)
    5
    
    > (if nil 5 6)
    6
    
    > (if 4 5 6)
    5
    

    The last example is odd but correct. NIL means false, and anything else means true. Unless we have a reason to do otherwise, we use  T  to mean true, just for the sake of clarity.

    Symbols like  T  and NIL are called 'self-evaluating' symbols, because they evaluate to themselves. There is a whole class of self-evaluating symbols called 'keywords'. Any symbol whose name starts with a colon is a keyword. [See below for some uses for keywords.] Some examples:

    > :this-is-a-keyword
    :THIS-IS-A-KEYWORD
    
    > :so-is-this
    :SO-IS-THIS
    
    > :me-too
    :ME-TOO
    

      Back to top


    2  Numbers


    An integer number [FIXNUM] is a sequence of digits optionally preceded by a plus sign '+' or a minus sign '-'. A floating point number [FLONUM] looks like an integer, except that it has a decimal point and optionally can be written in scientific notation. Here are some numbers:

    5
    17
    -34
    +6
    3.1415
    1.722e-15
    

    The standard arithmetic functions are all available:

       +   -  addition
       -   -  subtraction
       *   -  multiplication
       /   -  division
       truncate   -  truncate a float to an integer
       rem   -  remainder of a division
       sin   -  sine
       cos   -  cosine
       tan   -  tangent
       sqrt   -  square root
       exp   -  natural exponent
       expt   -  math exponent

     +  [addition],  -  [subtraction],  *  [multiplication], and  /  [division] accept any number of arguments and return a number according to type contagion. This means that as long as only integer numbers are given as arguments the result will always be an integer number, but as soon as at least one of the arguments is a floating number then the result will be a floating point number. Here are some examples:

    > (/ 3 2)               ; integer division causes rounding error
    1
    
    > (/ 3 2.0)             ; the 2.0 forces floating point computation
    1.5
    
    > (exp 1)               ; e
    2.71828
    
    > (exp 3)               ; e * e * e
    20.0855
    
    > (expt 3 4.2)          ; exponent with a base other than e
    100.904
    
    > (+ 5 6 7 (* 8 9 10))  ; the functions + - * / accept multiple arguments
    738
    

    In Nyquist the valid range of integer numbers is limited by the size of a C 'long' value on the machine on which Nyquist is running.

      Back to top


    3  Conses


    A cons is just a two-field record. The fields are called car and cdr, for historical reasons. On the first machine where Lisp was implemented, there were two assembly language instructions CAR and CDR which stood for 'contents of address register' and 'contents of decrement register'. Conses were implemented using these two registers.

    Conses are created by the cons function:

    > (cons 4 5)            ; Allocate a cons. Set the car to 4 and the cdr to 5
    (4 . 5)
    
    > (cons (cons 4 5) 6)
    ((4 . 5) . 6)
    
    > (car (cons 4 5))
    4
    
    > (cdr (cons 4 5))
    5
    

      Back to top


    4  Lists


    You can build many structures out of conses. Perhaps the simplest is a linked list. The car [the first element] of each cons points to one of the elements of the list, and the cdr [the rest of the elements] points either to another cons or to NIL. You can create such a linked list with the list function:

    > (list 4 5 6)
    (4 5 6)
    

    Notice that Lisp prints linked lists a special way. It omits some of the periods and parentheses. The rule is that if the cdr of a cons is NIL, Lisp doesn't bother to print the period or the NIL, and if the cdr of cons A is cons B, then Lisp doesn't bother to print the period for cons A or the parentheses for cons B. So:

    > (cons 4 nil)
    (4)             ; (4 . nil)
    
    > (cons 4 (cons 5 6))
    (4 5 . 6)       ; (4 . (5 . 6))
    
    > (cons 4 (cons 5 (cons 6 nil)))
    (4 5 6)         ; (4 . (5 . (6 . nil)))
    

    The last example is exactly equivalent to the call:

    (list 4 5 6)
    

    Note that NIL now means the list with no elements. The cdr of (a b), a list with 2 elements, is (b), a list with 1 element, and the cdr of (b), a list with 1 element, is NIL, which therefore must be a list with no elements.

    The car and cdr of NIL are defined to be NIL.

    If you store your list in a variable, you can make it act like a stack:

    > (setq a nil)
    NIL             ; A = ()
    
    > (push 4 a)
    (4)             ; A = (4)
    
    > (push 5 a)
    (5 4)           ; A = (5 4)
    
    > (pop a)
    5               ; A = (4)
    
    > (pop a)
    4               ; A = ()
    
    > (pop a)
    NIL             ; A = ()
    

    See pop, push, setq.

    List Accessors

    There are several different approaches to name the accessor functions for elements of conses and lists. The 'traditional' Lisp still uses function names like car and cdr while the 'modern' Lisp uses more descriptive names like first and rest. This leads to the situation that in most Lisps today the list accessor functions are available under different names for the same functions:

    modern  —  traditional equivalent to    (1 2 3 4 5 6 7 8)
    first  —  car    (nth 0 ... )   →   1
    second  —  cadr    (nth 1 ... )   →   2
    third  —  caddr    (nth 2 ... )   →   3
    fourth  —  cadddr    (nth 3 ... )   →   4
       (nth 4 ... )   →   5
         ...
    (nthcdr 0 ... )   →   (1 2 3 4 5 6 7 8)
    rest  —  cdr    (nthcdr 1 ... )   →   (2 3 4 5 6 7 8)
    cddr    (nthcdr 2 ... )   →   (3 4 5 6 7 8)
    cdddr    (nthcdr 3 ... )   →   (4 5 6 7 8)
    cddddr    (nthcdr 4 ... )   →   (5 6 7 8)
    (nthcdr 5 ... )   →   (6 7 8)
         ...
    last   →   (8)

    The traditional c..r-functions are available in even more variations, see car, cdr, cadr, cddr, caaar...caddr, cdaar...cdddr, caaaar...cadddr, and cdaaar...cddddr.

      Back to top


    5  Functions


    You saw one example of a function above. Here are some more:

    > (+ 3 4 5 6)                 ; this function takes any number of arguments
    18
    
    > (+ (+ 3 4) (+ (+ 4 5) 6))   ; isn't prefix notation fun?
    22
    
    > (defun foo (x y)            ; defining a function
        (+ x y 5))
    FOO
    
    > (foo 5 0)                   ; calling a function
    10
    
    > (defun fact (x)             ; a recursive function
        (if (> x 0)
            (* x (fact (- x 1)))
            1))
    FACT
    
    > (fact 5)
    120
    
    > (defun a (x)
        (if (= x 0)
            t
            (b (- x))))           ; mutually recursive functions
    A
    
    > (defun b (x)
        (if (> x 0)
            (a (- x 1))
            (a (+ x 1))))
    B
    
    > (a 5)
    T
    
    > (defun bar (x)              ; A function with multiple statements
        (setq x (* x 3))          ; in its body. It will return the value
        (setq x (/ x 2))          ; returned by its final statement
        (+ x 4))
    BAR
    
    > (bar 6)
    13
    

    See  + ,  − ,  * ,  / ,  = ,  > , defun,  if , setq. When we defined 'foo', we gave it two arguments, 'x' and 'y'. Now when we call 'foo', we are required to provide exactly two arguments. The first will become the value of 'x' for the duration of the call to 'foo', and the second will become the value of 'y' for the duration of the call. In Lisp, most variables are lexically scoped. That is, if 'foo' calls 'bar' and 'bar' tries to reference 'x', then 'bar' will not get 'foo's value for x.

    The process of assigning a symbol a value for the duration of some lexical scope is called 'binding'.

    You can specify optional arguments for your functions. Any argument after the symbol &optional is optional:

    > (defun bar (x &optional y)
        (if y
            x
            0))
    BAR
    
    > (defun baaz (&optional (x 3) (z 10))
        (+ x z))
    BAAZ
    
    > (bar 5)
    0
    
    > (bar 5 t)
    5
    
    > (baaz 5)
    15
    
    > (baaz 5 6)
    11
    
    > (baaz)
    13
    

    See  + , defun,  if . It is legal to call the function 'bar' with either one or two arguments. If it is called with one argument, 'x' will be bound to the value of that argument and 'y' will be bound to NIL. If it is called with two arguments, 'x' and 'y' will be bound to the values of the first and second argument, respectively.

    The function 'baaz' has two optional arguments. It specifies a default value for each of them. If the caller specifies only one argument, 'z' will be bound to 10 instead of to NIL, and if the caller specifies no arguments, 'x' will be bound to 3 and 'z' to 10.

    You can make your function accept any number of arguments by ending its argument list with an &rest parameter. Lisp will collect all arguments not otherwise accounted for into a list and bind the &rest parameter to that list. So:

    > (defun foo (x &rest y)
        y)
    FOO
    
    > (foo 3)
    NIL
    
    > (foo 4 5 6)
    (5 6)
    

    See defun. Finally, you can give your function another kind of optional argument called a &key 'keyword' argument. The caller can give these arguments in any order, because they're labelled with keywords:

    > (defun foo (&key x y)
        (cons x y))
    FOO
    
    > (foo :x 5 :y 3)
    (5 . 3)
    
    > (foo :y 3 :x 5)
    (5 . 3)
    
    > (foo :y 3)
    (NIL . 3)
    
    > (foo)
    (NIL)
    

    See defun. An &key parameter can have a default value too:

    > (defun foo (&key (x 5))
        x)
    FOO
    
    > (foo :x 7)
    7
    
    > (foo)
    5
    

      Back to top


    6  Printing


    Some functions can cause output. The simplest one is print, which prints its argument and then returns it:

    > (print 3)
    3            ; screen output
    3            ; return value
    

    The first 3 above was printed, the second was returned.

    If you want more complicated output, you will need to use format. Here's an example:

    > (format t "An atom: ~S~%and a list: ~S~%and an integer: ~A~%"
              nil (list 5) 6)
    An atom: NIL          ; screen output
    and a list: (5)       ; screen output
    and an integer: 6     ; screen output
    NIL                   ; return value
    

    See list. The first argument to format is either  T , NIL, or a stream.  T  specifies output to the terminal. NIL means not to print anything but to return a string containing the output instead. Streams are general places for output to go. They can specify a file, or the terminal, or a printer device. This tutorial will not describe streams in any further detail.

    The second argument is a formatting template, which is a string optionally containing formatting directives. All remaining arguments may be referred to by the formatting directives. Lisp will replace the directives with some appropriate characters based on the arguments to which they refer and then print the resulting string.

    The format function always returns NIL unless its first argument is NIL, in which case it prints nothing and returns a string.

    There are several different directives available:

      
    ~S
      -  [standard] - accepts any Lisp object and replaces it by the same printed representation which is produced by the print function.
     
      
    ~A
      -  [aestethic] - tries to 'pretty-print' its argument.
     
      
    ~%
      -  [linebreak] - is always replaced by a linebreak character or character sequence of the underlying operation system.
     
      
    ~~
      -  [tilde] - is replaced by a single '~' character.

    If the last character in a line in a format template is a tilde, then the linebreak is ignored and the template continues with the next non-whitespace character in the next line.

      Back to top


    7  Forms and the Top-Level Loop


    The things which you type to the Lisp interpreter are called 'forms'. The Lisp interpreter repeatedly reads a form, evaluates it, and prints the result. This procedure is therefore called the 'read-eval-print' loop, or REPL for short.

    Some forms will cause errors. After an error, Lisp will put you into the debugger so you can try to figure out what caused the error.

    In general, a form is either an atom, [for example a symbol, an integer, or a string] or a list. If the form is an atom, Lisp evaluates it immediately. Symbols evaluate to their value, integers and strings evaluate to themselves. If the form is a list, Lisp treats its first element as the name of a function. It evaluates the remaining elements recursively, and then calls the function with the values of the remaining elements as arguments.

    For example, if Lisp sees the form:

    (+ 3 4)
    

    then it treats  +  as the name of a function. It then evaluates 3 to get 3 and 4 to get 4, finally it calls  +  with 3 and 4 as the arguments. The  +  function returns 7, which Lisp prints.

    Nyquist: A description of the debugger can be found in the Break Command Loop section and a detailed description of the evaluation process can be found in the Evaluator section of the XLISP manual.

    The top-level loop provides some other conveniences. One particularly convenient convenience is the ability to talk about the results of previously typed forms. Lisp always saves its most recent three results, it stores them as the values of the symbols  * ,  ** , and  *** . For example:

    > 3
    3
    
    > 4
    4
    
    > 5
    5
    
    > ***
    3
    
    > ***
    4
    
    > ***
    5
    
    > **
    4
    
    > *
    4
    

    See  * ,  ** ,  *** ,  + ,  ++ ,  +++ ,  − .

      Back to top


    8  Special Forms


    There are a number of special forms which look like function calls but aren't. These include control constructs such as  if  statements and do loops, assignments like setq, setf, push, and pop, definitions such as defun, and binding constructs such as let. Not all of these special forms have been mentioned yet, see below for examples.

    One useful special form is the quote form. The quote function prevents its argument from being evaluated. For example:

    > (setq a 3)
    3
    
    > a
    3
    
    > (quote a)
    A
    
    > 'a            ; 'a is an abbreviation for (quote a)
    A
    

    Another similar special form is the function form, it causes its argument to be interpreted as a function rather than being evaluated. For example:

    > (setq + 3)
    3
    
    > +
    3
    
    > '+
    +
    
    > (function +)
    #<Subr-+: #88b44d5e>
    
    > #'+                   ; #'+ is an abbreviation for (function +)
    #<Subr-+: #88b44d5e>
    

    The function special form is useful when you want to pass a function as an argument to another function. See below for some examples of functions which take functions as arguments.

      Back to top


    9  Binding


    Binding is lexically scoped assignment. It happens to the variables in a function's parameter list whenever the function is called. The formal parameters are bound to the actual parameters for the duration of the function call. You can bind variables anywhere in a program with the let special form, which looks like this:

    (let ((variable-1 value-1)
          (variable-2 value-2)
           ... )
      body)
    

    The let function binds 'variable-1' to 'value-1', 'variable-2' to 'value-2', and so forth. Then it executes the statements in its body. The body of a let follows exactly the same rules that a function body does. Some examples:

    > (let ((a 3)) (+ a 1))
    4
    
    > (let ((a 2)
            (b 3)
            (c 0))
        (setq c (+ a b))
        c)
    5
    
    > (setq c 4)
    4
    
    > (let ((c 5))
        c)
    5
    
    > c
    4
    

    See  + , let, setq. Instead of:

    (let ((a nil)
          (b nil))
      ... )
    

    you can write:

    (let (a b)
      ... )
    

    The 'value-1', 'value-2', etc. inside a let form cannot reference the variables 'variable-1', 'variable-2', etc. that the let form is binding. For example:

    > (let ((x 1)
            (y (+ x 1)))  ; x is still unbound here
        y)
    error: unbound variable - x
    

    If the symbol 'x' already has a global value, stranger happenings will result:

    > (setq x 7)
    7
    
    > (let ((x 1)
            (y (+ x 1)))  ; references to the global x
        y)
    8
    

    The let* special form is just like let except that it allows values to reference variables defined earlier in the let* form. For example:

    > (setq x 7)
    7
    
    > (let* ((x 1)
             (y (+ x 1)))  ; references to x in the line before
        y)
    2
    

    The let* form:

    (let* ((x a)
           (y b))
      ... )
    

    is equivalent to the following let construct:

    (let ((x a))
      (let ((y b))
        ... ))
    

      Back to top


    10  Dynamic Scoping


    The let and let* forms provide lexical scoping, which is what you expect if you're used to programming in C or Pascal. Dynamic scoping is what you get in BASIC. If you assign a value to a dynamically scoped variable, every mention of that variable returns that value until you assign another value to the same variable.

    In Lisp, dynamically scoped variables are called 'special' variables. In Common Lisp special variables are declared with the 'defvar' special form. In Nyquist there is no 'defvar' form.

    Nyquist has no 'dynamic' scoping in the Common Lisp sense.

    In Nyquist every variable assigned with setq or setf at the top-level, outside of a function or a let binding, is a lexical scoped variable. Here is an example what this means:

    > (setq *variable* 5)         ; define a global variable
    5
    
    > (defun check-variable ()    ; define a function in global scope,
        *variable*)               ; returning the value of the variable
    CHECK-VARIABLE
    
    > (check-variable)            ; the CHECK-VARIABLE function returns
    5                             ; the global value of the variable
    
    > (let ((*variable* 10))      ; create a local binding for the variable
        (print (check-variable))  ; call CHECK-VARIABLE and print the return value
        (print *variable*))       ; print the local value of the variable
    5   ; return value of CHECK-VARIABLE
    10  ; variable value inside of LET
    10
    

    See defun, let, print, setq. Because the 'check-variable' function was defined in global scope and therefore is lexically outside of the let form, the 'check-variable' function returns the variable's global value of 5, even if called from inside the let form, where the variable has a value of 10.

    Important: In Nyquist there is no way to change the scoping behaviour of variables, so you must be careful where you define your variables. With Nyquist it's generally a good idea to prefer local let bindings over global variables.

    By convention, the name of a global Nyquist variable begins and ends with a star * to signal that the variable might behave differently than the programmer expects.

      Back to top


    11  Arrays


    The function make-array makes a 1-dimensional array. The aref function accesses its elements. All elements of an array are initially set to NIL. For example:

    > (make-array 4)        ; 1-D array with 4 elements
    #(NIL NIL NIL NIL)
    

    Array indices always start at 0. See below for how to set the elements of an array.

      Back to top


    12  Strings


    A string is a sequence of characters between double quotes. Nyquist represents a string internally as a variable-length array of characters. You can write a string containing a double quote by preceding the quote with a backslash. A double backslash stands for a single backslash. For example:

       "abcd"   -  has 4 characters
       "\""   -  has 1 character, a quote
       "\\"   -  has 1 character, a backslash

    Here are some functions for dealing with strings:

    > (strcat "abcd" "efg")
    "abcdefg"                ; STRCAT concatenates strings
    
    > (char "abc" 1)
    #\b                      ; Lisp writes characters preceded by #\
    
    > (subseq "abc" 0 2)
    "ab"                     ; SUBSEQ extracts substrings
    

    See char, strcat, subseq.

      Back to top


    13  Setf


    Certain forms in Lisp naturally define a memory location. For example, if the value of 'x' is a list, then (nth 4 x) defines the fifth element of the list. Or, if the value of 'y' is a one-dimensional array, (aref y 2) defines the third element of the array.

    The setf special form uses its first argument to define a place in memory, evaluates its second argument, and stores the resulting value in the resulting memory location. For example:

    > (setq a (make-array 3))
    #(NIL NIL NIL)
    
    > (aref a 1)
    NIL
    
    > (setf (aref a 1) 3)         ; store 3 in the second element of a
    3
    
    > a
    #(NIL 3 NIL)
    
    > (aref a 1)                  ; read the second element of a
    3
    
    > (setq b (list 1 2 3 4 5))
    (1 2 3 4 5)
    
    > (nth 4 b)
    5
    
    > (setf (nth 4 b) "five")     ; store "five" in the fifth element of b
    "five"
    
    > b
    (1 2 3 4 "five")
    
    > (nth 4 b)
    "five"
    

    The setf function is the only way to set the elements of a list or an array.

      Back to top


    14  Booleans and Conditionals


    Lisp uses the self-evaluating symbol NIL to mean false. Anything other than self-evaluating means true. Unless we have a reason not to, we usually use the self-evaluating symbol  T  to stand for true.

    Lisp provides a standard set of logical functions, for example and, or, and not. The and and or connectives are short-circuiting, and will not evaluate any arguments to the right of the first one which evaluates to NIL, while or will not evaluate any arguments to the right of the first one which evaluates to  T .

    Lisp also provides several special forms for conditional execution. The simplest of these is  if . The first argument of  if  determines whether the second or third argument will be executed:

    > (if t 5 6)
    5
    
    > (if nil 5 6)
    6
    
    > (if 4 5 6)
    5
    

    If you need to put more than one statement in the 'then' or 'else' clause of an  if  statement, you can use the progn special form. progn executes each statement in its body, then returns the value of the final one:

    > (setq a 7)
    7
    
    > (setq b 0)
    0
    
    > (setq c 5)
    5
    
    > (if (> a 5)
        (progn
          (setq a (+ b 7))
          (setq b (+ c 8)))
        (setq b 4))
    13
    

    An  if  statement which lacks either a 'then' or an 'else' clause can be written using the when or unless special form:

    > (when t 3)
    3
    
    > (when nil 3)
    NIL
    
    > (unless t 3)
    NIL
    
    > (unless nil 3)
    3
    

    when and unless, unlike  if , allow any number of statements in their bodies:

    (when x
      a
      b
      c)
    

    is equivalent to:

    (if x
        (progn
          a
          b
          c))
    

    For example:

    > (when t
        (setq a 5)
        (+ a 6))
    11
    

    More complicated conditionals can be defined using the cond special form. A cond form consists of the symbol cond followed by a number of cond clauses, each of which is a list. The first element of a cond clause is the condition, the remaining elements [if any] are the actions:

    (cond (condition-1 action-1)
          (condition-2 action-2)
            ...
          (t default-action))
    

    The cond form finds the first clause whose condition evaluates to true [does not evaluate to NIL]. It then executes the corresponding action and returns the resulting value. None of the remaining conditions are evaluated, nor are any actions except the one corresponding to the selected condition. For example:

    > (setq a 3)
    3
    
    > (cond
        ((evenp a) a)        ; if a is even return a
        ((> a 7) (/ a 2))    ; else if a is bigger than 7 return a/2
        ((< a 5) (- a 1))    ; else if a is smaller than 5 return a-1
        (t 17))              ; else return 17
    2
    

    If the action in the selected cond clause is missing, then cond returns what the condition evaluated to:

    > (cond ((+ 3 4)))
    7
    

    The Lisp case form is like a C 'switch' statement:

    > (setq x 'b)
    B
    
    > (case x
        (a 5)
        ((d e) 7)
        ((b f) 3)
        (t 9))
    3
    

    The  T  clause at the end means that if 'x' is not 'a', 'd or e', or 'b or f', then the case form will return 9.

      Back to top


    15  Iteration


    The simplest iteration construct in Lisp is loop. A loop construct repeatedly executes its body until it hits a return special form. For example:

    > (setq a 4)
    4
    
    > (loop
        (setq a (+ a 1))
        (when (> a 7) (return a)))
    8
    
    > (loop
        (setq a (- a 1))
        (when (< a 3) (return)))
    NIL
    

    The next simplest is dolist. It binds a variable to the elements of a list in order and stops when it hits the end of the list:

    > (dolist (x '(a b c))
        (print x))
    A
    B
    C
    NIL
    

    dolist always returns NIL. Note that the value of 'x' in the above example was never NIL. The NIL below the C was the value that dolist returned, printed by the read-eval-print loop.

    The most flexible, but also most complicated iteration form is called do. A do form looks like this:

    > (do ((x 1 (+ x 1))    ; variable x, initial value 1, update with (+ x 1)
           (y 1 (* y 2)))   ; variable y, initial value 1, update with (* y 2)
          ((> x 5) y)       ; terminate if (> x 5), return the value of y
        (print y)
        (print 'working))
    1
    WORKING
    2
    WORKING
    4
    WORKING
    8
    WORKING
    16
    WORKING
    32
    

    The first part of a do form specifies what variables to bind, what their initial values are, and how to update them. The second part specifies a termination condition and a return value. The last part is the body. A do form binds its variables to their initial values like a let, then checks the termination condition. As long as the condition is false, it executes the body repeatedly. When the condition becomes true, it returns the value of the return-value form.

    The do* form is to do as let* is to let.

      Back to top


    16  Non-local Exits


    The return special form is an example of a nonlocal return. Another example is return-from, which returns a value from the surrounding function:

    > (defun foo (x)
        (return-from foo 3)
        x)
    FOO
    
    > (foo 17)
    3
    

    Actually, the return-from form can return from any named block, it's just that functions are the only blocks which are named by default. You can create a named block with the block special form:

    > (block foo
        (return-from foo 7)
        3)
    7
    

    The return special form can return from any block named NIL. Loops are by default named NIL, but you can make your own NIL-named blocks:

    > (block nil
        (return 7)
        3)
    7
    

    Another form which causes a nonlocal exit is the error form:

    > (error "This is an error")
    error: This is an error
    

    The error form applies format to its arguments, then places you in the debugger.

      Back to top


    17  Funcall, Apply, and Mapcar


    Earlier I promised to give some functions which take functions as arguments. Here they are:

    > (funcall #'+ 3 4)
    7
    
    > (apply #'+ 3 4 '(3 4))
    14
    
    > (mapcar #'not '(t nil t nil t nil))
    (NIL T NIL T NIL T)
    

    funcall calls its first argument on its remaining arguments.

    apply is just like funcall, except that its final argument should be a list. The elements of that list are treated as if they were additional arguments to a funcall.

    The first argument to mapcar must be a function of one argument, mapcar applies this function to each element of a list and collects the results in another list.

    funcall and apply are chiefly useful when their first argument is a variable. For instance, a search engine could take a heuristic function as a parameter and use funcall or apply to call that function on a state description. The sorting functions described later use funcall to call their comparison functions.

    mapcar, along with nameless lambda functions, can replace many loops.

    Nyquist/XLISP: In XLISP, a 'special form' of type FSUBR is not a function. This means that apply, funcall and mapcar only work with functions of type SUBR [built-in function] or CLOSURE [function defined by defun, flet, labels, or lambda], but with special forms of type FSUBR a 'bad argument type' error is signalled.

      Back to top


    18  Lambda


    If you just want to create a temporary function and don't want to bother giving it a name, lambda is what you need.

    > #'(lambda (x)
          (+ x 3))
    #<Closure: #88b71ece>
    
    > (funcall * 5)
    8
    

    The combination of lambda and mapcar can replace many loops. For example, the following two forms are equivalent:

    > (do ((x '(1 2 3 4 5) (cdr x))
           (y nil))
          ((null x) (reverse y))
        (push (+ (car x) 2) y))
    (3 4 5 6 7)
    
    > (mapcar #'(lambda (x) (+ x 2)) '(1 2 3 4 5))
    (3 4 5 6 7)
    

      Back to top


    19  Sorting


    Lisp provides a primitive for sorting, sort:

    > (sort '(2 1 5 4 6) #'<)
    (1 2 4 5 6)
    
    > (sort '(2 1 5 4 6) #'>)
    (6 5 4 2 1)
    

    The first argument to sort is a list, the second is a comparison function. Be careful, because sort is allowed to destroy its argument, so if the original sequence is important to you, make a copy before sorting the list.

    Bug: In Nyquist 3.03 [November 2010] the XLISP sort function has a bug, so it's better to store the return value of sort in the original variable like this:

    (setq a '(3 1 4 1 5 9 6 7))  => (3 1 4 1 5 9 6 7)
    (setq a (sort a '<))         => (1 1 3 4 5 6 7 9)
    a                            => (1 1 3 4 5 6 7 9)
    

      Back to top


    20  Equality


    Lisp has many different ideas of equality. Numerical equality is denoted by =. Two symbols are eq if and only if they are identical. Two copies of the same list are not eq, but they are equal.

    > (eq 'a 'a)
    T
    
    > (eq 'a 'b)
    NIL
    
    > (= 3 4)
    T
    
    > (eq '(a b c) '(a b c))
    NIL
    
    > (equal '(a b c) '(a b c))
    T
    
    > (eql 'a 'a)
    T
    
    > (eql 3 3)
    T
    

    The eql predicate is equivalent to eq for symbols and to = for numbers.

    The equal predicate is equivalent to eql for symbols and numbers. It is true for two conses if and only if their cars are equal and their cdrs are equal.

      Back to top


    21  Some Useful List Functions


    These functions all manipulate lists:

    > (append '(1 2 3) '(4 5 6))    ;concatenate lists
    (1 2 3 4 5 6)
    
    > (reverse '(1 2 3))            ;reverse the elements of a list
    (3 2 1)
    
    > (member 'a '(b d a c))        ;set membership -- returns the first tail
    (A C)                           ;whose car is the desired element
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/tutorials.htm0000644000175000000620000000173511512762341023277 0ustar stevestaffTutorials Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Tutorials


    nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/lisp-faq.htm0000644000175000000620000001406111512762341022761 0ustar stevestaff Lisp FAQ Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Lisp FAQ


    1. Why do #'and and #'or not work with apply and funcall?
    2. Where can I find more Lisp FAQs in the Internet?

    Why do #'and and #'or not work with apply and funcall?


    From http://www.cs.cmu.edu/Groups/AI/html/faqs/lang/lisp/part3/faq-doc-3.html

    The short answer is that and and or are special operators, not functions, while apply and funcall can only be used to invoke functions, not macros and special operators.

    The reason why and and or are special operators is because they implement control structure in addition to computing a boolean value. They evaluate their subforms sequentially from left to right, and stop evaluating subforms as soon as the result can be determined. This is referred to as 'short circuiting'. apply and funcall, however, are ordinary functions. Therefore, their arguments are evaluated before they are called. Thus, were apply able to be used with #'and and or, the short-circuiting would be defeated.

    Perhaps you don't really care about the short-circuiting, and simply want the functional, boolean interpretation. While this may be a reasonable interpretation of trying to apply and or or, it doesn't generalize to other macros well, so there's no obvious way to have the Lisp system 'do the right thing' when trying to apply macros. The only function associated with a macro is its expander function. This function accepts and returns and form, so it cannot be used to compute the value.

    The Common Lisp functions EVERY, SOME and IDENTITY can be used to get the functionality you intend when trying to apply #'and and #'or:

       (apply #'and list)  →  (every #'identity list)
       (apply #'or  list)  →  (some  #'identity list)

    Defining and and or as functions using cons and eval:

    (defun and-fn (&rest args)
      (eval (cons 'and args)))
    
    (defun or-fn (&rest args)
      (eval (cons 'or args)))
    

    Defining and and or as functions using dolist:

    (defun and-fn (&rest args)
      (dolist (x args t)
        (and (not x) (return nil))))
    
    (defun or-fn (&rest args)
      (dolist (x args nil)
        (and x (return t))))
    
    (defun apply* (function args)
      (if (eq (type-of function) 'fsubr)
          (eval (cons function args))
          (apply function args)))
    
    
    

      Back to top


    Where can I find more Lisp FAQs in the Internet?


      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/shell-utilities.htm0000644000175000000620000005543511512762341024377 0ustar stevestaff Shell Utilities Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Shell Utilities


    • cd - display and change directories
    • ls - display files and sub-directories
    • hd - hexdump a file

    Nyquist is not a system programming language, so Nyquist/XLISP cannot create or remove files and directories, and the system function does not work on Windows. But sometimes it helps to know the name of the current working directory, the name of the directory where the soundfiles are stored, or the names of files and sub-directories.


    cd


    The 'cd' function displays or changes the current working directory, it also displays the name of the *default-sf-dir* directory, where Nyquist stores its sound files:

    > (cd)
    ;; *default-sf-dir*  = /tmp/
    ;; working directory = /home/edgar
    NIL
    
    > (cd "test")
    ;; directory changed to "test"
    ;; *default-sf-dir*  = /tmp/
    ;; working directory = /home/edgar/test
    T
    
    > (cd "..")
    ;; directory changed to "edgar"
    ;; *default-sf-dir*  = /tmp/
    ;; working directory = /home/edgar
    T
    
    > (cd "foo")
    ;; directory not changed, "foo" not found
    ;; *default-sf-dir*  = /tmp/
    ;; working directory = /home/edgar
    NIL
    
    > (cd 123)
    ;; directory not changed, 123 is not a string
    ;; *default-sf-dir*  = /tmp/
    ;; working directory = /home/edgar
    NIL
    

    The 'cd' function is intended for interactive use, in program code it's better to use the Nyquist setdir function.

    (defun cd (&optional dirname)
      (let ((old-dir (setdir "."))
            (new-dir (when (stringp dirname) (setdir dirname))))
        (when dirname
          (if new-dir
              (when (string/= old-dir new-dir)
                (let ((string-end (length new-dir))
                      (subseq-start 0))
                  (dotimes (index string-end)
                    (when (char= (char new-dir index) *file-separator*)
                      (setq subseq-start index)))
                  (incf subseq-start)
                  (format t ";; directory changed to ~s~%"
                            (if (< subseq-start string-end)
                                (subseq new-dir subseq-start)
                                (string *file-separator*)))))
              (format t ";; directory not changed, ~s ~a~%" dirname
                (if (stringp dirname) "not found" "is not a string"))))
        (format t ";; *default-sf-dir*  = ~a~%" *default-sf-dir*)
        (format t ";; working directory = ~a~%" (setdir "."))
        (when new-dir t)))
    

      Back to top


    ls


    The 'ls' function lists files and directories:

    > (ls)
    ;;; /home/edgar/Downloads/nyquist/svn/nyquist
    ;;  advantages.txt  cmt/               comp-ide.bat       convert.dsp
    ;;  convert.dsw     demos/             doc/               docsrc/
    ;;  fft/            ffts/              files.txt          howtorelease.txt
    ;;  jny             jnyqide.bat        jnyqide/           lib/
    ;;  liblo/          license.txt        lpc/               macosxproject/
    ;;  macproject/     Makefile           misc/              nylsf/
    ;;  nyqide/         nyqsrc/            nyqstk/            nyquist.dsp
    ;;  nyquist.dsw     nyquist.sln        nyquist.vcproj     nyqwin.dsp
    ;;  nyqwin.vcproj   portaudio-oldv19/  portaudio/         portaudio_test/
    ;;  Readme.txt      release.bat        releasenyqide.bat  releasenyqwin.bat
    ;;  runtime/        snd/               sys/               test/
    ;;  todo.txt        tran/              xlisp/             
    47
    

    The algorithm to find the number of colums is trial-and-error, for example it starts with one column:

    <- maximum-width ->|
    item-1 
    item-2
    item-3
    item-4
    item-5
    

    When no line was longer than the maximum-width the layout is saved and a new test is started with two columns:

    <- maximum-width ->|
    item-1  item-2
    item-3  item-4
    item-5
    

    When no line was longer than the maximum-width the layout is saved and a new test is started with three columns:

    <- maximum-width ->|
    item-1  item-2  item-3
    

    As soon as a line becomes longer than the maximum-width, the test is aborted and the saved layout from the previous run is used.

    The main reason why arrays are used instead of lists is that we need access to predefined numbers. With lists we always first need to test if an element exists because non-existent list elements are NIL and not numbers:

    (< (nth 3 '(1 2)) 0)  => error: bad argument type - NIL
    

    It's also no good idea to use setf with non-existent list elements:

    (setf (nth 2 nil) 'value)  => VALUE
    (nth 2 nil)                => error: bad argument type - NIL
    

    Caution: The XLISP setf special form does not signal an error if values are assigned to non-existent places.

    We use the Common Lisp 'incf' macro because the Nyquist incf macro has no 'increment' argument:

    (defmacro cl:incf (place &optional (increment 1))
      `(setf ,place (+ ,place ,increment)))
    
    (defun ls (&rest args)
      (let* ((dirname   (if (stringp (car args))
                            (prog1 (car args) (setq args (cdr args)))
                            (setdir ".")))
             (show-all (car args))
             (raw-list (listdir dirname)))
        (cond ((null raw-list)
               (format t ";; directory ~s not found~%" dirname))
              ((<= (length raw-list) 2)
               (format t ";;; ~a~%" dirname)
               (format t ";; [directory is empty]~%") 0)
              (t
               (format t ";;; ~a~%" dirname)
               (let ((file-separator (string *file-separator*))
                     (dir-list nil))
                 (dolist (item raw-list)
                   (when (or show-all (not (ls:hidden-p item)))
                     (if (listdir (strcat dirname file-separator item))
                         (push (strcat item "/") dir-list)
                         (push item dir-list))))
                 (ls:list-items (sort dir-list #'string-lessp)))))))
    
    (setq *ls-hidden-start* (list "." "#"))
    (setq *ls-hidden-end* (list "~" "#"))
    
    (defun ls:hidden-p (string)
      (let ((string-length (length string)))
        (or (dolist (item *ls-hidden-start* nil)
              (let ((subseq-end (length item)))
                (when (and (>= string-length subseq-end)
                           (string= item (subseq string 0 subseq-end)))
                  (return t))))
            (dolist (item *ls-hidden-end* nil)
              (let ((subseq-start (- string-length (length item))))
                (when (and (<= 0 subseq-start)
                           (string= item (subseq string subseq-start)))
                  (return t)))))))
    
    (defmacro ls:reset-array (array)
      (let ((index (gensym)))
        `(dotimes (,index (length ,array))
           (setf (aref ,array ,index) 0))))
    
    (defmacro ls:copy-array (from-array to-array end)
      (let ((index (gensym)))
        `(dotimes (,index ,end)
           (setf (aref ,to-array ,index)
                 (aref ,from-array ,index)))))
    
    (defun ls:fill-string (length)
      (let ((string ""))
        (dotimes (i length)
          (setq string (strcat string " ")))
        string))
    
    (defun ls:list-items (item-list &optional (terminal-width 80))
      (let* ((separator 2)
             (width (- terminal-width 4))
             (width-max (+ width separator))
             (num-items (length item-list))
             (num-columns 1)     ; number of columns
             (item-array   (make-array num-items))
             (length-array (make-array num-items))
             (length-min width)  ; shortest item
             (length-max 0)      ; longest item
             (length-all 0)      ; all items + separators
             ;; the maximum possible number of columns is
             ;; width-max / (1 char + separator)
             (max-columns (/ width-max (1+ separator)))
             (column-array (make-array max-columns)))
    
        ;; initialize the column-array
        (ls:reset-array column-array)
    
        ;; copy the items from the list into the item-array
        (let ((item-index 0))
          (dolist (item item-list)
            (setf (aref item-array item-index) item)
            (incf item-index)))
    
        ;; find the length of all items and store them in the length-array
        (dotimes (item-index num-items)
          (let ((length-item (length (aref item-array item-index))))
            (setf (aref length-array item-index) length-item
                  length-all (+ length-all length-item separator)
                  length-min (min length-min length-item)
                  length-max (max length-max length-item))))
    
        ;; find the number and widths of the columns
        (cond ((<= length-all width-max)
               ;; if all items together fit into a single line
               (setq num-columns num-items)
               (ls:copy-array length-array column-array num-items))
              ((and (> num-items 1)
                    (<= (+ length-min length-max separator) width))
               ;; if there is more than one item and the
               ;; longest + shortest item + separator fit into one line
               ;; we start with two columns, one column is the fallback
               (incf num-columns)
               ;; the test-array must be 1+ because we need 1 failure-run
               (do ((test-array (make-array (1+ max-columns)))
                    (item-index 0 0))
                   ((progn
                      (ls:reset-array test-array)
                      ;; loop until there are no more items in the list
                      (do ((line-length 0 0))
                          ((>= item-index num-items))
                        ;; compute a complete line
                        (dotimes (column-index num-columns)
                          ;; loop through all columns in the test-array
                          (when (and (< item-index num-items)
                                     (< (aref test-array column-index)
                                        (aref length-array item-index)))  
                            ;; if there are still items in the list and the
                            ;; item is wider than the column, update the array
                            (setf (aref test-array column-index)
                                  (aref length-array item-index)))
                          ;; compute the line-length from the value in the array
                          (cl:incf line-length
                                   (+ (aref test-array column-index) separator))
                          (incf item-index))
                        ;; analyze the result from computing the line
                        (cond ((> line-length width-max)
                               ;; if the line is too long, abort completely, use
                               ;; the column-array values from the previous run
                               (decf num-columns)
                               (return t))  ; abort both 'do' loops
                              ((>= item-index num-items)
                               ;; if no items is left and no line was too long
                               ;; first save the test-array in the column-array
                               (ls:copy-array test-array column-array num-columns)
                               ;; then try again with one more column
                               (incf num-columns)))))))))
    
        ;; print the items on the screen
        (do ((item-index 0)
             (last-item (1- num-items))
             (last-column (1- num-columns))
             (line ";;  " ";;  "))
            ((>= item-index num-items))
          (dotimes (column-index num-columns)
            ;; loop through all columns
            (when (< item-index num-items)
              ;; if there are still items in the list
              (setq line
                    (if (and (< column-index last-column)
                             (< item-index last-item))
                        ;; if not the last column and not the last item
                        (strcat line (aref item-array item-index)
                          ;; add a fill-string
                          (let ((column (aref column-array column-index))
                                (item   (aref length-array item-index)))
                            (ls:fill-string (+ (- column item) separator))))
                        ;; if the last column or the last item
                        (strcat line (aref item-array item-index))))
              (incf item-index)))
          ;; display the line on the screen
          (format t "~a~%" line))
    
        ;; return the number of items listed on the screen
        num-items))
    

    Note: The code works, but this section is still too much mess.

      Back to top


    hd


    The 'hd' function prints the hexdump of a file on the screen:

    > (hd "/tmp/edgar-temp.wav")
    0000000000  52 49 46 46 ac 58 01 00  57 41 56 45 66 6d 74 20  RIFF.X..WAVEfmt 
    0000000016  10 00 00 00 01 00 01 00  44 ac 00 00 88 58 01 00  ........D....X..
    0000000032  02 00 10 00 64 61 74 61  88 58 01 00 00 00 4a 04  ....data.X....J.
    0000000048  93 08 da 0c 1b 11 57 15  8b 19 b7 1d d7 21 ec 25  ......W......!.%
    0000000064  f3 29 eb 2d d3 31 a9 35  6c 39 1a 3d b3 40 35 44  .).-.1.5l9.=.@5D
    0000000080  9e 47 ee 4a 24 4e 3d 51  3a 54 19 57 d9 59 78 5c  .G.J$N=Q:T.W.Yx\
    0000000096  f7 5e 54 61 8f 63 a6 65  99 67 67 69 10 6b 92 6c  .^Ta.c.e.ggi.k.l
    0000000112  ee 6d 23 6f 31 70 16 71  d3 71 68 72 d4 72 17 73  .m#o1p.q.qhr.r.s
    0000000128  31 73 23 73 eb 72 8a 72  01 72 4f 71 75 70 73 6f  1s#s.r.r.rOqupso
    0000000144  49 6e f8 6c 80 6b e2 69  1f 68 36 66 29 64 f8 61  In.l.k.i.h6f)d.a
    0000000160  a5 5f 2f 5d 98 5a e2 57  0b 55 17 52 05 4f d8 4b  ._/].Z.W.U.R.O.K
    0000000176  8f 48 2c 45 b1 41 1f 3e  76 3a b9 36 e8 32 05 2f  .H,E.A.>v:.6.2./
    0000000192  11 2b 0e 27 fe 22 e0 1e  b8 1a 86 16 4c 12 0c 0e  .+.'."......L...
    0000000208  c7 09 7e 05 33 01 e9 fc  9f f8 57 f4 14 f0 d6 eb  ..~.3.....W.....
    0000000224  a0 e7 72 e3 4e df 36 db  2b d7 2f d3 42 cf 67 cb  ..r.N.6.+./.B.g.
    0000000240  9f c7 ea c3 4b c0 c3 bc  53 b9 fb b5 be b2 9d af  ....K...S.......
    ;; type "q" to quit or press Return to continue... 
    
    (defun hd (filename &key (start 0) end)
      (cond
        ((not (stringp filename))
         (format t ";; not a string ~s~%" filename))
        ((listdir filename)
         (format t ";; not a file ~s~%" string))
        ((or (not (integerp start)) (minusp start))
         (format t ";; not a non-negative integer ~s~%" start))
        ((and end (or (not (integerp end)) (minusp end)))
         (format t ";; not a non-negative integer ~s~%" end))
        ((and end (>= start end))
         (format t ";; :start ~s is greater then :end ~s~%" start end))
        (t (let ((file-stream (open-binary filename)))
             (if (null file-stream)
                 (format t ";; file not found ~s~%" filename)
                 (unwind-protect
                   (hd:dump file-stream start end)
                   (when file-stream (close file-stream))))))))
    
    (defun hd:dump (file-stream start end)
      (let ((file-position (hd:skip file-stream start))
            (break (+ start 255))
            (end-of-file nil)
            (end-of-dump nil))
        (if (< file-position start)
            (setq end-of-file t)
            (flet ((read-eight-bytes (start-position)
                     (let (byte-list)
                       (dotimes (offset 8)
                         (let* ((position (+ start-position offset))
                                (read-p (and (<= start position)
                                             (or (null end)
                                                 (>= end position))))
                                (byte (when read-p
                                        (read-byte file-stream))))
                           (push byte byte-list)
                           (when byte (incf file-position))
                           (when (and read-p (null byte))
                             (setq end-of-file t))))
                       (reverse byte-list))))
              (read-line)
              (do ((line-start (* (/ start 16) 16) (+ line-start 16)))
                  ((or end-of-file end-of-dump))
                (let* ((number  (hd:line-number line-start))
                       (list-1  (read-eight-bytes line-start))
                       (list-2  (read-eight-bytes (+ line-start 8)))
                       (bytes-1 (hd:byte-string list-1))
                       (bytes-2 (hd:byte-string list-2))
                       (chars   (hd:char-string (append list-1 list-2))))
                  (format t "~a  ~a  ~a  ~a~%" number bytes-1 bytes-2 chars)
                  (when (and end (> file-position end))
                    (setq end-of-dump t))
                  (when (> file-position break)
                    (format t ";; type \"q\" to quit or press Return to continue... ")
                    (if (string-equal "q" (read-line))
                        (setq end-of-dump t)
                        (setq break (+ break 256))))))))
        (when (and end (>= file-position end))
          (format t ";; reached specified :end at byte number ~a~%" end))
        (when end-of-file
          (format t ";; end of file at byte number ~a~%" file-position))))
    
    (defun hd:line-number (integer)
      (progv '(*integer-format*) '("%.10d")
        (format nil "~s" integer)))
    
    (defun hd:byte-string (byte-list)
      (let ((string ""))
        (dolist (byte byte-list)
          (setq string (strcat string (if byte
                                          (progv '(*integer-format*) '("%.2x")
                                            (format nil "~s " byte))
                                          "   "))))
        (subseq string 0 (1- (length string)))))
    
    (defun hd:char-string (byte-list)
      (let ((string ""))
        (dolist (byte byte-list)
          (setq string (strcat string (if byte
                                          (if (<= 32 byte 126)
                                              (string byte)
                                              ".")
                                          " "))))
        string))
    
    (defun hd:skip (file-stream offset)
      (if (= offset 0)
          offset
          (let ((count 0))
              (format t ";; skipping ~a bytes...~%" offset)
              (dotimes (ignore offset)
                (if (read-byte file-stream)
                    (incf count)
                    (return)))
            count)))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/xobj-1.png0000644000175000000620000000301711512762341022340 0ustar stevestaffPNG  IHDR|N)ZsRGBPLTEU~bKGDH pHYs  tIME  :lIDAThkFHmܒ){HԱfF 25" K^BZRz W=Ik}QwNL85iԈHvtGˎ8j)t6٤a Nv:$(O?朝J85JI*v*HE/` ̹k' R7R5t?ʤ?b5ʤ?bGH>FL-'DÕNUfSXЂ!^Vs>S;IYZN[C̽i&?H2wD ֨*4LPu$* nSuS"?j0T7B jR^ tdYq@txYjv&mK|LT]ӵ[P?c>p eLX\:dK^eZ@l q:&!Eok/qD7ѥ~kP7.)&#Zڲj\ƔV@"'5{`®E>^T]F)#Ĵ[nvеre[|~wLe^JYD iF+GԂp 7:rFUF;"Ze݂H 5b VnƝ]3n}EW&-#RSd"sm{"} !^~E1:CBw^H&5ש G58maT-]E3,vj'<|jWPtBԶiRX&8>I&җǠ'rs>II/E ~njQp\ L~΃i[h`%bJ]9.YOSSkLުy|$aHOQyp!Ek&=Z29΋4&(=Ю{_OTs^6Bn}X, $>|\;a91 ;S^W]mE;||SS%J^JZ@cuSzL_*.РS.TztrMDUdcڨ 4Ԫ %aTԈd)pة? w[.FFo*d7iRv;Tٞ)$ݪMjTctCuQ2a|IENDB`nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/binary-io.htm0000644000175000000620000000325311512762341023137 0ustar stevestaff Binary File I/O Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Binary File I/O


    (defun hexdump (filename &key (start 0) end)
      (if (and (integerp start) (not (minusp start)))
          (error "not a non-negative integer" start))
      (or (null end)
          (and (integerp end) (not (minusp end)))
          (error "not a non-negative integer" end))
      (let ((file (open-binary filename)))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/nyquist.htm0000644000175000000620000002341711512762341022766 0ustar stevestaff Nyquist Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Nyquist


    This page will not save you from reading the Nyquist manual, it's a list of things I find useful but frequently have to look them up in the manuals when I haven't worked with Nyquist for a while. Many more useful tricks can be found in the 'Developing and Debugging in Nyquist' chapter in the Nyquist manual.


    Debugger Shortcuts


    Some Nyquist/XLISP debugger shortcuts, defined in 'xlinit.lsp' and 'misc.lsp':

      
    (bt)
      →  baktrace
      
    (co)
      →  continue
      
    (top)
      →  top-level
     
      
    (res)
      →  clean-up
      
    (up)
      →  clean-up

    The debugger commands only work if *breakenable* is non-NIL:

      
    (bkon)
      →  (setq *breakenable* t)
      
    (bkoff)
      →  (setq *breakenable* nil)

    You can make your own *tracenable* shortcuts like shown here:

    (defun tron ()
      (setq *tracenable* t))
    
    (defun troff ()
      (setq *tracenable* nil))
    

    See also:

      Back to top


    grindef


    The 'grindef' function prints the Lisp code of a closure [user-defined function or macro]:

    (defun grindef (e)
      (pprint (get-lambda-expression (symbol-function e))))
    

    Example:

    > (grindef 'grindef)
    (LAMBDA (E)
            (PPRINT (GET-LAMBDA-EXPRESSION (SYMBOL-FUNCTION E))))
    NIL
    

      Back to top


    args


    The 'args' function prints the name and the argument variables of a closure [user-defined function or macro]:

    (defun args (e) 
      (pprint (cons e (second (get-lambda-expression (symbol-function e))))))
    

    Example:

    > (args 'args)
    (ARGS E)
    NIL
    

      Back to top


    setfn


    The 'setfn' macro defines 'alias' names for functions:

    (defmacro setfn (a b) 
      `(setf (symbol-function ',a) (symbol-function ',b)))
    

    Examples from 'xlinit.lsp':

    (setfn co  continue)
    (setfn top top-level)
    (setfn res clean-up)
    (setfn up  clean-up)
    

      Back to top


    display


    'display' is a debugging macro, defined in 'xlinit.lsp'.

    (defmacro display-macro (label &rest items)
      (let ($res$)
        (dolist ($item$ items)
                (setq $res$ (cons
                             `(format t "~A = ~A  " ',$item$ ,$item$)
                             $res$)))
        (append (list 'let nil `(format t "~A : " ,label))
                (reverse $res$)
                '((terpri)))))
    
    (defun display-on ()
      (setfn display display-macro) t)
    
    (defun display-off ()
      (setfn display or) nil)
    

    Usage:

    (display "heading" var1 var2 ...)
    

    expands into:

    (let ()
      (format t "~A: " "heading")
      (format t "~A = ~A  " ',var1 ,var1)
      (format t "~A = ~A  " ',var2 ,var2)
       ... )
    

    and then prints:

    heading : VAR1 = value1 VAR2 = value2 ...
    

    Using the 'display' macro in a function like shown here:

    (defun hello ()
      (let ((local-var 'hello))
        (display "debug message" local-var)
        local-var)) ; return value
    

    Now the 'debug message' can be switched on and off without changing the code:

    > (display-on)
    T
    
    > (hello)
    debug message : LOCAL-VAR = HELLO  
    HELLO
    
    > (display-off)
    NIL
    
    > (hello)
    HELLO
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/tutorials/environment.htm0000644000175000000620000003405111512762341023612 0ustar stevestaff Environment Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Environment



    Global and Lexical Binding


    From the XLISP perspective, there are two kinds of bindings:

    1. Global bindings are bindings to symbols in the *obarray*.

    2. Lexical bindings are bindings in a local association list

    There is a third kind of binding, 'dynamical binding', used by progv.

      Back to top


    Lexical Scope


    Have you ever wondered why this doesn't work:

    (defun print-x ()
      (print x))  ; unbound variable X
    
    (let ((x 'hello))
      (print-x))
    error: unbound variable - X
    

    The answer is twofold:

    1. The 'print-x' function is defined at the global top-level, where no lexical environment exists.

    2. The 'print-x' function is called inside a let form, where a lexical variable binding for 'x' exists, but 'print-x' is evaluated at the global top-level, where it was defined, so 'print-x' cannot see the lexical let binding of 'x' and signals an 'unbound variable' error.

    Here is a version that seems to work:

    (let ((x 'hello))
    
      (defun print-x ()
        (print x))
    
      (print-x))
    HELLO
    
    1. The 'print-x' function is defined inside a let form.

    2. The 'print-x' function is called inside the same let form as where it was defined, so 'print-x' prints the lexical let binding of 'x'.

    But here again a version that does not behave as wanted:

    (let ((x 'lexical))
      (defun print-x ()
        (print x)))
    
    (let ((x 'hello))
      (print-x))
    LEXICAL
    
    1. The 'print-x' function is defined inside a let form.

    2. The 'print-x' function is called inside a different let form as where it was defined, so 'print-x' prints the lexical let binding of 'x' from the place where it was defined.

    Somehow it seems to be important where a function was defined.


    Closures


    Here a Lisp function, defined inside a let form:

    (let ((a 'A) (b 'B) (c 'C))
    
      (defun print-abc ()
        (format t ";; a = ~s, b = ~s, c = ~s~%" a b c))
    
      )  ; end of LET
    

    Now 'print-abc' is called outside the let form:

    > (print-abc)
    ;; a = A, b = B, c = C
    NIL
    

    The lexical let variables 'a', 'b', and 'c' have become a permanent part of the 'print-abc' function.

      Back to top


    Lisp Objects


    The following examples are based on Chapter 13 of 'Paradigms of Artificial Intelligence Programming' by Peter Norvig. The code has been ported from Common Lisp to XLISP, all examples have been tested with Nyquist 3.03 in December 2010.

    The function 'new-account' creates account objects, which are implemented as closures encapsulating three variables 'name', 'balance', and 'interest-rate'. An account object also encapsulates functions to handle five messages ':withdraw', ':deposit', ':balance', ':name', and ':interest', to which the object can respond:

    (defun new-account (name &optional (balance 0.0) (interest-rate 0.06))
      #'(lambda (message)
          (case message
            (:withdraw #'(lambda (amount)
                           (if (<= amount balance)
                               (setq balance (- balance amount))
                               'insufficient-funds)))
            (:deposit  #'(lambda (amount)
                           (setq balance (+ balance amount))))
            (:balance  #'(lambda () balance))
            (:name     #'(lambda () name))
            (:interest #'(lambda ()
                           (setq balance (+ balance (* interest-rate balance))))))))
    

    An account object can only do one thing, receive a message and return the appropriate function to execute that message. This function is called the 'method' that implements the message.

    The function 'get-method' finds the method that implements a message for a given object:

    (defun get-method (object message)
      (funcall object message))
    

    The function 'send-message' gets the method and applies it to a list of arguments:

    (defun send-message (object message &rest args)
      (apply (get-method object message) args))
    

    Here are some examples how it works:

    > (setq a1 (new-account "My Name" 1000.0))
    #<Closure...>
    
    > (send-message a1 :name)
    "My Name"
    
    > (send-message a1 :balance)
    1000.0
    
    > (send-message a1 :withdraw 500.0)
    500
    
    > (send-message a1 :deposit 123.45)
    623.45
    
    > (send-message a1 :balance)
    623.45
    

      Back to top


    Generic Functions


    The 'send-message' syntax is awkward, as it is different from normal Lisp function calling syntax, and it doesn't fit in with the other Lisp tools.

    For example if we want to say:

    (mapcar :balance accounts)
    

    with 'send-message' we would have to write:

    (mapcar #'(lambda (acc)
                (send-message acc :balance))
            accounts)
    

    We could fix this problem by defining a generic function 'withdraw' like this:

    (defun withdraw (object &rest args)
      (apply (get-method object :withdraw) args))
    

    Now we can write:

    (withdraw account x)
    

    instead of:

    (send-message account :withdraw x)
    

      Back to top


    Classes


    The macro 'define-class' defines a class with its associated message handling methods. It also defines a generic function for each message. Finally, it allows the programmer to make a distinction between instance variables, associated with each object, and class variables, associated with a class and shared by all members of the class.

    (defmacro define-class (class ivars cvars &rest methods)
      `(let ,cvars
         (mapcar #'ensure-generic-function ',(mapcar #'first methods))
         (defun ,class ,ivars
           #'(lambda (message)
               (case message
                 ,@(mapcar #'make-clause methods))))))
    

    The 'make-clause' function translates a message from 'define-class' into a case clause.

    (defun make-clause (clause)
      `(,(car clause) #'(lambda ,(cadr clause) ,@(cddr clause))))
    

    The 'ensure-generic-function' function defines a dispatch function for a message, unless it already has been defined as one:

    (defun ensure-generic-function (message)
      (unless (generic-function-p message)
        (let ((fn #'(lambda (object &rest args)
                      (apply (get-method object message) args))))
          (setf (symbol-function message) fn)
          (putprop message fn 'generic-function))))
    

    The 'generic-function-p' function tests if a function has been defined as a generic function:

    (defun generic-function-p (name)
      (and (fboundp name)
           (eq (get name 'generic-function) (symbol-function name))))
    

    Now we can define the 'account' class with 'define-class'. We make 'interest-rate' a class variable, shared by all accounts:

    (define-class account (name &optional (balance 0.0)) ((interest-rate 0.06))
      (withdraw (amount)
        (if (<= amount balance)
            (setq balance (- balance amount))
            'insufficient-funds))
      (deposit (amount)
        (setq balance (+ balance amount)))
      (balance ()
        balance)
      (name ()
        name)
      (interest ()
        (setq balance (+ balance (* interest-rate balance)))))
    

    Macroexpansion:

    (let ((interest-rate 0.06))
      (mapcar (function ensure-generic-function)
              (quote (withdraw deposit balance name interest)))
      (defun account (name &optional (balance 0))
        (function (lambda (message)
          (case message
            (withdraw (function (lambda (amount)
                                  (if (<= amount balance)
                                      (setq balance (- balance amount))
                                      (quote insufficient-funds)))))
            (deposit  (function (lambda (amount)
                                  (setq balance (+ balance amount)))))
            (balance  (function (lambda nil balance)))
            (name     (function (lambda nil name)))
            (interest (function (lambda nil
                                  (setq balance (+ balance (* interest-rate balance)))))))))))
    

    Here is how it works:

    > (setq a2 (account "my-name" 2000.0)
    #<Closure...>
    
    > (balance a2)
    2000
    
    > (deposit a2 42.0)
    2042
    
    > (interest a2)
    2164.52
    

      Back to top


    Delegation


    Here is a 'password-account' class with two message clauses:

    (define-class password-account (password acc) ()
      (change-password (pass new-pass)
        (if (equal pass password)
            (setq password new-pass)
            'wrong-password))
      (t (pass &rest args)
        (if (equal pass password)
            (if args
                (apply message (cons acc args))
                (funcall message acc))
            'wrong-password)))
    

    The definition of 'password-account' depends on some internal details of 'define-class'. It uses 't' as a catch-all clause to case and uses the dispatch variable 'message'. Usually it is not a good idea to rely on details of other code, so this will be changed below.

    Here is how 'password-account' works:

    > (setq a3 (password-account "secret" a2))
    #<Closure...>
    
    > (balance a3 "secret")
    2164.52
    
    > (withdraw a3 "guess" 2000.0)
    WRONG-PASSWORD
    
    > (withdraw a3 "secret" 2000.0)
    164.52
    

    Here is a 'limited-account' class, where only a limited amount of money can be withdrawn at any time:

    (define-class limited-account (limit acc) ()
      (withdraw (amount)
        (if (<= amount limit)
            (withdraw acc amount)
            'over-limit))
      (t (&rest args)
        (if args
            (apply message (cons acc args))
            (funcall message acc))))
    

    The 'withdraw' message is redefined to check if the account limit is exceeded, while the 't' clause passes all other messages unchanged:

    > (setq a4 (password-account "pass"
                 (limited-account 100.0
                   (account "limited" 500.0)))
    #<Closure...>
    
    
    
    
    
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/start.htm0000644000175000000620000000536611512762341020364 0ustar stevestaff XLisp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Nyquist / XLISP 2.0



    If you find bugs in these documents please write to:

    If you send me email please write the words XLISP or NYQUIST as big as possible into the subject line in case you get catched by the spam filter. I usually sort out my emails by hand but often do not have the time to open them all during sorting.


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/0002755000175000000620000000000011537433125017764 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/manual/xlisp-man-033.htm0000644000175000000620000002712311512762341022712 0ustar stevestaffXLISP: An Object-oriented Lisp XLISP > XLISP 2.0  -  Contents  -  Reference  -  Previous | Next

    33  Nyquist Functions


    1. Predicate Functions
      • filep - is this a file ?
    2. Arithmetic Functions
      • rrandom - compute a random real number between 0 and 1 inclusive
    3. String Functions
    4. File I/O Functions
      • open-binary - open a binary file stream
      • setdir - set current directory
      • listdir - get a directory listing
      • get-temp-path - get a path where a temporary file can be created
      • read-int - read a binary integer from a stream
      • write-int - write a binary integer to a stream
      • read-float - read a binary floating-point number from a stream
      • write-float - write a binary floating-point number to a stream
    5. System Functions
      • info - show information about memory usage
      • bigendiap - is this a big-endian machine ?
      • setup-console - set default console attributes
      • echoenabled - turn console input echoing on or off
    6. Profiling
      • profile - turn profiling on or off

    Note: if you're interested in *all* functions added by Nyquist to the XLISP language, I suggest you download the Nyquist manual from:

    The following is a list of all Nyquist functions I have found in the XLISP section of the Nyquist 2.36 manual but I cannot even guarantee that the list is complete. I'm willing to add more functions here if you find that some are missing but the best information source is the Nyquist manual itself. Roger is always a step ahead and I do not want to spread obsolete or wrong information.


    Predicate Functions


    (filep expr) - is this a file ?
    expr - the expression to check
    returns - T if the value is an object, NIL otherwise

      Back to Top


    Arithmetic Functions


    (rrandom) - compute a random real number between 0 and 1 inclusive
    returns - a random floating point number

      Back to Top


    String Functions


    (string-search pat str &key :start :end) - search for pattern in string
    pat - a string to search for
    str - the string to be searched
    :start - the starting offset in str
    :end - the ending offset + 1
    returns - index of pat in str or NIL if not found

      Back to Top


    File I/O Functions


    Note: Files are ordinarily opened as text. Binary files [such as standard MIDI files] must be opened with 'open-binary' on non-unix systems.

    (open-binary fname &key :direction) - open a binary file stream
    fname - the file name string or symbol
    :direction - :input or :output [default is :input]
    returns - a stream

    (setdir path) - set current directory
    path - the path of the new directory
    returns - the resulting full path, e.g. (setdir ".") gets the current working directory, or NIL if an error occurs

    (listdir path) - get a directory listing
    path - the path of the directory to be listed
    returns - list of filenames in the directory

    (get-temp-path) - get a path where a temporary file can be created
    returns - the resulting full path as a string

    Note: Under Windows, the 'get-temp-path' function is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice 'c:\windows\'.

    (read-int [stream [length]]) - read a binary integer from a stream
    stream - the input stream [default is standard input]
    length - the length of the integer in bytes [default is 4]
    returns - the integer

    (write-int ch [stream [length]]) - write a binary integer to a stream
    ch - the character to write
    stream - the output stream [default is standard output]
    length - the length of the integer in bytes [default is 4]
    returns - the integer

    (read-float [stream [length]]) - read a binary floating-point number from a stream
    stream - the input stream (default is standard input)
    length - the length of the float in bytes [default is 4, legal values are -4, -8, 4, and 8]
    returns - the float

    (write-float ch [stream [length]]) - write a binary floating-point number to a stream
    ch - the character to write
    stream - the output stream [default is standard output]
    length - the length of the float in bytes [default is 4, legal values are -4, -8, 4, and 8]
    returns - the float

    Note: Integers and floats are assumed to be big-endian [high-order byte first] and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. '-4' indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

      Back to Top


    System Functions


    Note: in Nyquist, the XLISP load function first tries to load a file from the current directory. A '.lsp' extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. [The Macintosh version has no search path.]

    (info) - show information about memory usage.
    returns - NIL
    (bigendiap) - is this a big-endian machine ?
    returns - T if this a big-endian architecture, storing the high-order byte of an integer at the lowest byte address of the integer, otherwise NIL.

    Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of "Nyquist." This is normally accomplished by calling 'setup-console' in 'system.lsp'. In Nyquist, you can avoid this behavior by setting *setup-console* to NIL in your 'init.lsp' file. If 'setup-console' is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.

    (setup-console) - set default console attributes
    returns - NIL

    Note: The 'echoenabled' function is only implemented under Linux and Mac OS X. If Nyquist I/O is redirected through pipes, the Windows version does not echo the input, but the Linux and Mac versions do. You can turn off echoing with this function. Under windows it is defined to do nothing.

    (echoenabled flag) - turn console input echoing on or off
    flag - T to enable echo, NIL to disable
    returns - NIL

      Back to Top


    Profiling


    The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where eval is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an eval in the immediately [lexically] enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls.

    The list of all functions executed is maintained on the global *profile* variable. These functions in turn have *profile* properties, which maintain the counts. The profile system merely increments counters and puts symbols on the *profile* list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the 'profile' function.

    (profile flag) - turn profiling on or off
    flag - NIL turns profiling off, otherwise on
    returns - the previous state of profiling

    Unfortunately, methods cannot be profiled with this facility.

    [Nyquist sources: xlsys.c, xleval.c]

      Back to Top


    XLISP > XLISP 2.0  -  Contents  -  Reference  -  Previous | Next nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/xlisp.htm0000644000175000000620000012734211512762341021642 0ustar stevestaff XLISP 2.0 Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    XLISP 2.0


    XLISP: An Object-oriented Lisp  Version 2.0, February 6, 1988, by David Michael Betz, 127 Taylor Road, Peterborough, NH 03458

    Copyright (c) 1988, by David Michael Betz, All Rights Reserved, Permission is granted for unrestricted non-commercial use.


    1. Introduction
    2. A Note From The Author
    3. Command Loop
    4. Break Loop
    5. Data Types
    6. The Evaluator
    7. Lexical Conventions
    8. The Readtable
    9. Lambda Lists

    1  Introduction


    XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers. Implementations of XLISP run on virtually every operating system. XLISP is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users. Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects object and class as primitives. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances [it is the only object that is an instance of itself].

    This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming. I recommend the book 'Lisp' by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp. You will probably also need a copy of 'Common Lisp, The Language' by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document.

    A list with Lisp books and documents available for free in the internet can be found under Lisp Links.

      Back to Top


    2  A Note From The Author


    If you have any problems with XLISP, feel free to contact me [David Betz] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me.

    If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it.

    Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However,

    PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!!

    I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run.

    The official XLISP homepage is:

      Back to top


    3  Command Loop


    When XLISP is started, it first tries to load the workspace 'xlisp.wks' from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols. Then XLISP attempts to load 'init.lsp' from the current directory. It then loads any files named as parameters on the command line [after appending '.lsp' to their names].

    XLISP then issues the following prompt:

    >
    

    This indicates that XLISP is waiting for an expression to be typed. When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed.

    Interactive Programming

    There are several symbols maintained by the read-eval-print loop:

       *   -  the most recent result
       **   -  the second recent result
       ***   -  the third recent result
       +   -  the most recent input expression
       ++   -  the second recent input expression
       +++   -  the third recent input expression
         -  the expression currently being evaluated, becomes the value of + at the end of the evaluation

    These symbols are for interactive programming. It is not recommended to use them in program code.

    Special Characters

    When XLISP is running from a console [not in the Nyquist Java IDE], some control characters invoke operations:

       Control-c   -  executes the top-level function
       Control-g   -  executes the clean-up function
       Control-p   -  executes the continue function
       Control-b   -  stops execution and enters the break command loop, execution can be continued by typing Control-p or (continue)
       Control-e   -  turns on character echoing [Linux and Mac OS X only]
       Control-f   -  turns off character echoing [Linux and Mac OS X only]
       Control-t   -  evaluates the info function
       Control-u   -  erases the entire input line

    Backspace and Delete characters erase the previous character on the input line [if any].

      Back to top


    4  Break Loop


    When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way:

    1. If the symbol *breakenable* is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed.

    • If the symbol *tracenable* is true, a trace back is printed. The number of entries printed depends on the value of the symbol *tracelimit*. If this symbol is set to something other than a number, the entire trace back stack is printed.

    XLISP then enters a 'read-eval-print' loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level 'read-eval-print' loop in that if the user invokes the continue function:

    1> (continue)
    

    XLISP will continue from a correctable error. If the user invokes the clean-up function:

    1> (clean-up)
    

    XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt with a number.

    2. If the symbol *breakenable* is NIL, XLISP looks for a surrounding errset function:

    • If an error happened within the scope of an errset function, XLISP examines the value of the errset print flag. If this flag is true, the error message is printed. In case of an error, the errset function always returns NIL.

    • If there is no surrounding errset function, XLISP prints the error message and returns to the top level.

      Back to top


    5  Data Types


    There are several different data types available to XLISP programmers:

    See also the type-of function.

      Back to top


    6  The Evaluator


    The process of evaluation in XLISP:

    • The following Lisp objects evaluate to themselves:

    • Symbols act as variables and are evaluated by retrieving the value associated with their current binding.

    • Lists are evaluated by examining the first element of the list and then taking one of the following actions:

      • If it is a symbol, the functional binding of the symbol is retrieved.

      • If it is a lambda expression, a closure is constructed for the function described by the lambda expression.

      • If it is a subr [built-in function], fsubr [special form] or closure [user defined function], it stands for itself.

      • Any other value is an error.

      Then, the value produced by the previous step is examined:

      • If it is a subr [built-in function] or closure [user defined function], the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments.

      • If it is an fsubr [special form], the fsubr is called using the remaining list elements as arguments [unevaluated].

      • If it is a macro, the macro is expanded using the remaining list elements as arguments [unevaluated]. The macro expansion is then evaluated in place of the original macro call.

      Back to top


    7  Lexical Conventions


    The following conventions must be followed when entering XLISP programs:

    • Comments in XLISP code begin with a semicolon character and continue to the end of the line.

    • Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following:

    •    (   -  opening parenthesis
         )   -  closing parenthesis
         '   -  single-quote
         `   -  backquote
         ,   -  comma
         "   -  double-quote
         ;   -  semicolon

    • Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input.

    • Integer literals consist of a sequence of digits optionally beginning with a '+' [plus] or '-' [minus]. The range of values an integer can represent is limited by the size of a C 'long' value on the machine on which XLISP is running. Also be aware that Nyquist doesn't check for CPU register overflow with integer numbers, so for example if you add 1 to the biggest Nyquist integer number, the result will be a negative number.

    • Floating point literals consist of a sequence of digits optionally beginning with a '+' [plus] or '-' [minus] and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C 'float' [or 'double' on machines with 32 bit addresses] on the machine on which XLISP is running.

    • Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the '\' [backslash] character is used to allow non-printable characters to be included. The codes recognized are:

    •    \\   -  the character '\' [backslash]
         \n   -  newline
         \t   -  tab
         \r   -  return
         \f   -  form feed
         \nnn   -  the character whose octal code is 'nnn'

      An ASCII table is provided with this version of the XLISP manual with all octal, decimal and hexadecimal character values.

      Back to top


    8  The Readtable


    The behavior of the reader is controlled by a data structure called a 'readtable'. The reader uses the symbol *readtable* to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things:

        NIL   -   indicating an invalid character    [see nil]
       :CONSTITUENT   -   indicating a symbol constituent    [see :constituent]
       :WHITE-SPACE   -   indicating a whitespace character    [see :white-space]
       (:TMACRO . function)   -   terminating readmacro    [see :tmacro]
       (:NMACRO . function)   -   non-terminating readmacro    [see :nmacro]
       :SESCAPE   -   single escape character '\'    [see :sescape]
       :MESCAPE   -   multiple escape character '|'    [see :mescape]

    In the case of :tmacro and :nmacro, the 'fun' component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return NIL to indicate that the character should be treated as white space or a value consed with NIL to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream.

    XLISP defines several useful read macros:

       'expression   =   (quote expr)
       #'expression   =   (function expr)
       #(expression...)   =   an array of the specified expressions
       #xdigits   =   a hexadecimal number [0-9,A-F]
       #odigits   =   an octal number [0-7]
       #bdigits   =   a binary number [0-1]
       #\character   =   a single character
       #| ... |#   =   a comment
       #:symbol   =   an uninterned symbol
       `expression   =   (backquote expr)
       ,expression   =   (comma expr)
       ,@expression   =   (comma-at expr)

    Characters names handled by the reader:

       #\Tab   =   horiz. tab    [ASCII decimal value 9]
       #\Newline   =   newline    [ASCII decimal value 10]
       #\Space   =   space    [ASCII decimal value 32]

      Back to top


    9  Lambda Lists


    9.1  Arguments


    There are several forms in XLISP that require that a 'lambda list' be specified. A lambda list is a definition of the arguments accepted by a function.

      Back to top


    9.1.1  Required Arguments


    The lambda list starts with 'required' arguments. Required arguments must be specified in every call to the function.

    The function 'print-x' has exactly one required argument 'x':

    (defun print-x (x)
      (print x))
    
    (print-x 1)    => 1
    (print-x)      => error: too few arguments
    (print-x 1 2)  => error: too many arguments
    

      Back to top


    9.1.2  Optional Arguments


    The Required Arguments are followed by the &optional arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an &optional argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to NIL.

    It is also possible to provide the name of a 'supplied-p' variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the 'supplied-p' variable will be bound to  T  if a value was specified in the call and NIL if the default value was used.

      Back to top


    9.1.3  Rest Argument


    The Optional Arguments are followed by the &rest argument. The &rest argument gets bound to the remainder of the argument list after the required and &optional arguments have been removed.

    Known Problems with the Rest Argument

    A subtle problem arises if Optional Arguments are used together with a &rest argument:

    (defun test (&optional opt &rest rest)
      (format t "opt = ~a, rest = ~a~%" opt rest))
    
    (test 1)      => opt = 1, rest = NIL
    (test 1 2)    => opt = 1, rest = (2)
    (test 1 2 3)  => opt = 1, rest = (2 3)
    

    Now the &optional argument is not optional anymore, there is no way to make the first argument appear in the &rest list and not in the &optional variable. This is not a XLISP bug, this is a general Lisp phenomenon. In Lisp it's not a good idea to use Optional Arguments together with a &rest argument.

    If a &rest argument is used togethter with Keyword Arguments, then the keywords and their arguments appear in the list bound to the &rest argument. This is not neccessarily a XLISP bug, this also happens with other Lisps. In Lisp it's also not a good idea to use Keyword Arguments together with a &rest argument.

    XLISP Bug: If the number of elements in a &rest list is odd, then &key variables have wrong values:

    (defun test (&rest rest &key (key t))
      (format t "rest = ~a, key = ~a~%" rest key))
    
    (test 1     :key 'a)  => rest = (1 :KEY A),     key = T  ; wrong KEY value
    (test 1 2   :key 'a)  => rest = (1 2 :KEY A),   key = A  ; quirk, but correct KEY value
    (test 1 2 3 :key 'a)) => rest = (1 2 3 :KEY A), key = T  ; again wrong KEY value
    

      Back to top


    9.1.4  Keyword Arguments


    The Rest Argument is followed by the &key arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol [a symbol that begins with a colon ':']. The value of the second expression is the value of the keyword argument.

    Like &optional arguments, &key arguments can have initialization expressions and 'supplied-p' variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a colon ':' to the beginning of the keyword argument symbol is used.

    In other words, if the keyword argument symbol is:

    foo
    

    the keyword will be:

    :foo
    

      Back to top


    9.1.5  Auxiliary Variables


    The Keyword Arguments are followed by the &aux variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the &aux variables.

      Back to Top


    9.2  Lambda List Syntax


    Here is the complete syntax for lambda lists:

       (required-arg ...
          [&optional [optional-arg | (optional-arg [init-form [supplied-var]])] ... ]
          [&rest rest-arg]
          [&key [key-arg | ([key-arg | (keyword key-arg)] [init-form [supplied-var]]) ...] &allow-other-keys]
          [&aux [aux-var | (aux-var [init-form])] ... ])

    where:

       required-arg  —  is a required argument symbol
       optional-arg  —  is an &optional argument symbol
       rest-arg  —  is the &rest argument symbol
       key-arg  —  is a &key argument symbol
       keyword  —  is a keyword symbol
       aux-var  —  is an auxiliary variable symbol
       init-form  —  is an initialization expression
       supplied-var  —  is a supplied-p variable symbol

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/sal.htm0000644000175000000620000001165311512762341021257 0ustar stevestaff SAL XLISP

    SAL


    Data Types


    Data types used in SAL and XLISP:

       SAL XLISP
       integer:   1 1
       float:   1.0 1.0
       string:   "hello" "hello"
       symbol:   name name
       keyword:   symbol: :symbol
       list:   {item-1 item-2 ...} (item-1 item-2 ...)
       array:   array[index] (aref array index)
       boolean:   #t #f  t  nil

    Data types with different concepts:

    SAL:

    • expressions - evaluated to produce a return value
    • statements - evaluated for side-effects

    XLISP:

    • character - a single ASCII character
    • object - the XLISP object system
    • stream - data type of unknown length
    • subr - built-in function
    • fsubr - special form
    • closure - user defined function

    A function to print the Lisp code, produced by the SAL compiler, to the screen:

    (defun test (string)
      (if (not (stringp string))
          (error "not a string" string)
          (pprint (third (second (sal-compile string nil nil "<console>"))))))
    

      Back to top



    nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/contents.htm0000644000175000000620000013527211512762341022341 0ustar stevestaffTable of Contents Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Table of Contents


    1. Manuals
    2. Reference

    XLISP 2.0 Manual


      Back to top


    XLISP Object System


      Back to top


    Symbols


    •  +  - the most recent input expression
    •  ++  - the next to the last input expression
    •  +++  - the second to the last input expression
    •  *  - the result of the previously evaluated expression
    •  **  - the result of the next to the last evaluated expression
    •  ***  - the result of the second to the last evaluated expression
    •  -  - the expression currently being evaluated

      Back to top


    Evaluation Functions


      Back to top


    Symbol Functions


    • Constructors
    • Accessors
    • Assignment
      • set - set the value of a symbol
      • setq - set the [quoted] value of a symbol
      • psetq - parallel version of setq
      • setf - set the value of a field
    • Utilities
      • incf - increment a variable
      • decf - decrement a variable

      Back to top


    Array Functions


    • Constructors
    • Acessors
      • aref - get the nth element of an array
    • Predicate
    • Utilities
      • length - find the length of a list, vector or string
      • hash - compute the hash index for a symbol

      Back to top


    List Functions


    • Constructors
      • cons - construct a new list node
      • list - create a list of values
    • Accessors
    • Predicates
      • consp - is this a non-empty list?
      • listp - is this an empty or non-empty list?
      • null - is this an empty list?
    • List Functions
      • append - append lists
      • reverse - reverse a list
      • member - find an expression in a list
      • length - find the length of a list, vector or string
      • subst - substitute expressions
    • Association Lists
      • assoc - find an expression in an a-list
      • sublis - substitute with an a-list
    • Property Lists
      • get - get the value of a property
      • putprop - put a property onto a property list
      • remprop - remove a property from a property list
    • Mapping
      • mapc - apply function to successive cars
      • mapcar - apply function to successive cars
      • mapl - apply function to successive cdrs
      • maplist - apply function to successive cdrs
    • Lists as Stack
      • push - push a value to the front of a list
      • pop - pop a value from the front of a list
    • Lists as Sets
      • union - compute the union of two lists
      • intersection - compute the intersection of two lists
      • set-difference - compute the set-difference of two lists
      • subsetp - test if a list is a subset of another list
    • Non-destructive List Functions
    • Destructive List Functions
      • rplaca - replace the car of a list node
      • rplacd - replace the cdr of a list node
      • nconc - destructively concatenate lists
      • delete - delete elements from a list
      • delete-if - delete elements that pass test
      • delete-if-not - delete elements that fail test
      • sort - sort a list

      Back to top


    Predicate Functions


    • Predicates
    • Comparison
      • eq - are the expressions identical?
      • eql - are the expressions identical?
      • equal - are the expressions equal?
    • Boolean
      • not - is this false?

      Back to top


    Control Constructs


    • Logical
      • and - the logical AND of a list of expressions
      • or - the logical OR of a list of expressions
    • Conditional
      • if - evaluate expressions conditionally
      • when - evaluate only when a condition is true
      • unless - evaluate only when a condition is false
      • cond - evaluate conditionally
      • case - select by case
    • Binding
      • let - create local bindings
      • let* - let with sequential binding
      • flet - create local functions
      • labels - flet with recursive functions
      • macrolet - create local macros
    • Non-local Exits
    • Looping Constructs
      • loop - basic looping form
      • do - loop while the termination test is NIL
      • do* - 'do' loop with sequential binding
      • dolist - loop through a list
      • dotimes - loop from zero to n-1
      • while - standard 'while' loop
    • The Program Feature
      • prog - the program feature
      • prog* - 'prog' with sequential binding
      • block - named block
      • return - cause a prog construct to return a value
      • return-from - return from a named block
      • tagbody - block with labels
      • go - go to a tag within a tagbody or prog
      • progv - dynamically bind symbols
      • prog1 - return the value of the first expression
      • prog2 - return the value of the second expression
      • progn - return the value of the last expression

      Back to top


    Debugging and Error Handling


    • trace - add a function to the trace list
    • untrace - remove a function from the trace list
    • error - signal a non-correctable error
    • cerror - signal a correctable error
    • break - enter a break loop
    • clean-up - clean-up after an error
    • top-level - clean-up after an error and return to the top level
    • continue - continue from a correctable error
    • errset - trap errors
    • baktrace - print n levels of trace back information
    • evalhook - evaluate with hooks
    • profile - turn profiling on or off

      Back to top


    Arithmetic Functions


    • Integer and Floating Point - error if not a number
      • truncate - truncates a floating point number to an integer
      • float - converts an integer to a floating point number
      •  +  - add one or several numbers
      •  −  - negate a single number or subtract one or several numbers
      •  *  - multiply one or several numbers
      •  /  - get the reciprocal of a single number or divide several numbers
      • 1+ - increment a number by one
      • 1− - decrement a number by one
      • min - the smallest of one or several numbers
      • max - the largest of one or several numbers
      • abs - the absolute value of a number
      • asin - compute the arcsine of a number
      • acos - compute the arccosine of a number
      • atan - compute the arctangent of a number
      • power - compute 'x' to the 'y' power
      • interpolate - compute the 'y' coordinate corresponding to 'x'
    • Comparison - error if not a number
      •  <  - test for less than
      •  <=  - test for less than or equal to
      •  =  - test for equal to
      •  /=  - test for not equal to
      •  >=  - test for greater than or equal to
      •  >  - test for greater than
    • Floating Point - error if not a floating point number
      • sin - compute the sine of a floating-point number
      • cos - compute the cosine of a floating-point number
      • tan - compute the tangent of a floating-point number
      • expt - compute x to the y power
      • exp - compute e to the x power
      • exp - compute the natural logarithm of a floating-point number
      • sqrt - compute the square root of a floating-point number
    • Integer - error if not an integer number
      • gcd - compute the greatest common divisor
      • logand - compute the bitwise 'and' of one or several numbers
      • logior - compute the bitwise 'inclusive or' of one or several numbers
      • logxor - compute the bitwise 'exclusive or' of one or several numbers
      • lognot - compute the bitwise 'not' of an number
      • rem - remainder of one or several integer numbers
    • Random Numbers
      • random - compute an integer random number between 0 and n-1 inclusive
      • rrandom - compute a floating point random number between 0 and 1 inclusive
      • real-random - compute a floating point random number in an arbitrary range

      Back to top


    String Functions


      Back to top


    Character Functions


    • Character Functions
      • char - extract a character from a string
      • char-code - get the ASCII code of a character
      • code-char - get the character with a specified ASCII code
      • digit-char - convert a digit weight to a digit
      • char-int - convert a character to an integer
      • int-char - convert an integer to a character
    • General Predicate - all data types
    • Character Predicates - error if not a character
    • Case Conversion
    • Case-sensitive Comparison
      • char< - test for less than in ASCII ordering
      • char<= - test for less than or equal to in ASCII ordering
      • char= - test for equal to in ASCII ordering
      • char/= - test for not equal to in ASCII ordering
      • char>= - test for greater than or equal to in ASCII ordering
      • char> - test for greater than in ASCII ordering
    • Case-insensitive Comparison

      Back to top


    Input/Output Functions


    • get-key - get a single key stroke from the keyboard
    • read - read an expression
    • print - print an expression on a new line
    • prin1 - print an expression
    • princ - print an expression without quoting
    • pprint - pretty print an expression
    • terpri - terminate the current print line
    • flatsize - length of printed representation using prin1
    • flatc - length of printed representation using princ
    • format - do formated output

      Back to top


    File I/O Functions


    • Character I/O
    • Binary I/O
      • bigendianp - is this a bigendian machine?
      • open-binary - open a binary file stream
      • Bytes
      • Integer Numbers
        • read-int - read a binary integer number from a stream
        • write-int - write a binary integer number to a stream
      • Floating Point Numbers
        • read-float - read a binary floating point number from a stream
        • write-float - write a binary floating point number to a stream
    • Character and Bibary I/O
      • close - close a file stream
    • Operating System

      Back to top


    String Stream Functions


      Back to top


    System Functions


    • load - load a source file
    • save - save workspace to a file
    • restore - restore workspace from a file
    • dribble - create a file with a transcript of a session
    • gc - force garbage collection
    • expand - expand memory by adding segments
    • alloc - change number of nodes to allocate in each segment
    • info - show information about memory usage
    • room - show memory allocation statistics
    • type-of - returns the type of the expression
    • peek - peek at a location in memory
    • poke - poke a value into memory
    • bigendianp - is this a big-endian machine?
    • address-of - get the address of an xlisp node
    • get-env - get the value of an environment variable
    • system - execute a command of the operating system
    • quit - exit XLISP
    • exit - exit XLISP
    • setup-console - set default console attributes
    • echoenabled - turn console input echo on or off

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/links.htm0000644000175000000620000000006211512762341021610 0ustar stevestaff object nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/part15.html0000755000175000000620000031015711512762341021774 0ustar stevestaffAppendix 3: XLISP: An Object-oriented Lisp

    Appendix 3: XLISP: An Object-oriented Lisp

    Version 2.0

    February 6, 1988

    by
    David Michael Betz
    127 Taylor Road
    Peterborough, NH 03458

    (603) 924-6936 (home)

    Copyright (c) 1988, by David Michael Betz
    All Rights Reserved
    Permission is granted for unrestricted non-commercial use

    Introduction

    XLISP is an experimental programming language combining some of the features of Common Lisp with an object-oriented extension capability. It was implemented to allow experimentation with object-oriented programming on small computers.

    There are currently implementations of XLISP running on the IBM- PC and clones under MS-DOS, on the Macintosh, the Atari-ST and the Amiga. It is completely written in the programming language C and is easily extended with user written built-in functions and classes. It is available in source form to non-commercial users.

    Many Common Lisp functions are built into XLISP. In addition, XLISP defines the objects Object and Class as primitives. Object is the only class that has no superclass and hence is the root of the class hierarchy tree. Class is the class of which all classes are instances (it is the only object that is an instance of itself).

    This document is a brief description of XLISP. It assumes some knowledge of LISP and some understanding of the concepts of object-oriented programming.

    I recommend the book Lisp by Winston and Horn and published by Addison Wesley for learning Lisp. The first edition of this book is based on MacLisp and the second edition is based on Common Lisp. XLISP will continue to migrate towards compatibility with Common Lisp.

    You will probably also need a copy of Common Lisp: The Language by Guy L. Steele, Jr., published by Digital Press to use as a reference for some of the Common Lisp functions that are described only briefly in this document.

    A Note From The Author

    If you have any problems with XLISP, feel free to contact me [me being David Betz - RBD] for help or advice. Please remember that since XLISP is available in source form in a high level language, many users [e.g. that Dannenberg fellow - RBD] have been making versions available on a variety of machines. If you call to report a problem with a specific version, I may not be able to help you if that version runs on a machine to which I don't have access. Please have the version number of the version that you are running readily accessible before calling me.

    If you find a bug in XLISP, first try to fix the bug yourself using the source code provided. If you are successful in fixing the bug, send the bug report along with the fix to me. If you don't have access to a C compiler or are unable to fix a bug, please send the bug report to me and I'll try to fix it.

    Any suggestions for improvements will be welcomed. Feel free to extend the language in whatever way suits your needs. However, PLEASE DO NOT RELEASE ENHANCED VERSIONS WITHOUT CHECKING WITH ME FIRST!! I would like to be the clearing house for new features added to XLISP. If you want to add features for your own personal use, go ahead. But, if you want to distribute your enhanced version, contact me first. Please remember that the goal of XLISP is to provide a language to learn and experiment with LISP and object-oriented programming on small computers. I don't want it to get so big that it requires megabytes of memory to run.

    XLISP Command Loop

    When XLISP is started, it first tries to load the workspace xlisp.wks from the current directory. If that file doesn't exist, XLISP builds an initial workspace, empty except for the built-in functions and symbols.

    Then XLISP attempts to load init.lsp from the current directory. It then loads any files named as parameters on the command line (after appending .lsp to their names).

    XLISP then issues the following prompt:

            >
    
    This indicates that XLISP is waiting for an expression to be typed.

    When a complete expression has been entered, XLISP attempts to evaluate that expression. If the expression evaluates successfully, XLISP prints the result and then returns to the initial prompt waiting for another expression to be typed.

    Break Command Loop

    When XLISP encounters an error while evaluating an expression, it attempts to handle the error in the following way:

    If the symbol *breakenable* is true, the message corresponding to the error is printed. If the error is correctable, the correction message is printed.

    If the symbol *tracenable* is true, a trace back is printed. The number of entries printed depends on the value of the symbol *tracelimit*. If this symbol is set to something other than a number, the entire trace back stack is printed.

    XLISP then enters a read/eval/print loop to allow the user to examine the state of the interpreter in the context of the error. This loop differs from the normal top-level read/eval/print loop in that if the user invokes the function continue, XLISP will continue from a correctable error. If the user invokes the function clean-up, XLISP will abort the break loop and return to the top level or the next lower numbered break loop. When in a break loop, XLISP prefixes the break level to the normal prompt.

    If the symbol *breakenable* is nil, XLISP looks for a surrounding errset function. If one is found, XLISP examines the value of the print flag. If this flag is true, the error message is printed. In any case, XLISP causes the errset function call to return nil.

    If there is no surrounding errset function, XLISP prints the error message and returns to the top level.

    Data Types

    There are several different data types available to XLISP programmers.

    • lists
    • symbols
    • strings
    • integers
    • characters
    • floats
    • objects
    • arrays
    • streams
    • subrs (built-in functions)
    • fsubrs (special forms)
    • closures (user defined functions)

    The Evaluator

    The process of evaluation in XLISP:
    • Strings, integers, characters, floats, objects, arrays, streams, subrs, fsubrs and closures evaluate to themselves.
    • Symbols act as variables and are evaluated by retrieving the value associated with their current binding.
    • Lists are evaluated by examining the first element of the list and then taking one of the following actions:
      • If it is a symbol, the functional binding of the symbol is retrieved.
      • If it is a lambda expression, a closure is constructed for the function described by the lambda expression.
      • If it is a subr, fsubr or closure, it stands for itself.
      • Any other value is an error.
      Then, the value produced by the previous step is examined:
      • If it is a subr or closure, the remaining list elements are evaluated and the subr or closure is called with these evaluated expressions as arguments.
      • If it is an fsubr, the fsubr is called using the remaining list elements as arguments (unevaluated).
      • If it is a macro, the macro is expanded using the remaining list elements as arguments (unevaluated). The macro expansion is then evaluated in place of the original macro call.

    Lexical Conventions

    The following conventions must be followed when entering XLISP programs:

    Comments in XLISP code begin with a semi-colon character and continue to the end of the line.

    Symbol names in XLISP can consist of any sequence of non-blank printable characters except the following:

                    ( ) ' ` , " ;
    
    Uppercase and lowercase characters are not distinguished within symbol names. All lowercase characters are mapped to uppercase on input.

    Integer literals consist of a sequence of digits optionally beginning with a + or -. The range of values an integer can represent is limited by the size of a C long on the machine on which XLISP is running.

    Floating point literals consist of a sequence of digits optionally beginning with a + or - and including an embedded decimal point. The range of values a floating point number can represent is limited by the size of a C float (double on machines with 32 bit addresses) on the machine on which XLISP is running.

    Literal strings are sequences of characters surrounded by double quotes. Within quoted strings the ``\'' character is used to allow non-printable characters to be included. The codes recognized are:

    • \\ means the character ``\''
    • \n means newline
    • \t means tab
    • \r means return
    • \f means form feed
    • \nnn means the character whose octal code is nnn

    Readtables

    The behavior of the reader is controlled by a data structure called a readtable. The reader uses the symbol *readtable* to locate the current readtable. This table controls the interpretation of input characters. It is an array with 128 entries, one for each of the ASCII character codes. Each entry contains one of the following things:
    • NIL - Indicating an invalid character
    • :CONSTITUENT - Indicating a symbol constituent
    • :WHITE-SPACE - Indicating a whitespace character
    • (:TMACRO . fun) - Terminating readmacro
    • (:NMACRO . fun) - Non-terminating readmacro
    • :SESCAPE - Single escape character ('\')
    • :MESCAPE - Multiple escape character ('|')

    In the case of :TMACRO and :NMACRO, the fun component is a function. This can either be a built-in readmacro function or a lambda expression. The function should take two parameters. The first is the input stream and the second is the character that caused the invocation of the readmacro. The readmacro function should return NIL to indicate that the character should be treated as white space or a value consed with NIL to indicate that the readmacro should be treated as an occurence of the specified value. Of course, the readmacro code is free to read additional characters from the input stream.

    XLISP defines several useful read macros:

    • '<expr> == (quote <expr>)
    • #'<expr> == (function <expr>)
    • #(<expr>...) == an array of the specified expressions
    • #x<hdigits> == a hexadecimal number (0-9,A-F)
    • #o<odigits> == an octal number (0-7)
    • #b<bdigits> == a binary number (0-1)
    • #\<char> == the ASCII code of the character
    • #| ... |# == a comment
    • #:<symbol> == an uninterned symbol
    • `<expr> == (backquote <expr>)
    • ,<expr> == (comma <expr>)
    • ,@<expr> == (comma-at <expr>)

    Lambda Lists

    There are several forms in XLISP that require that a ``lambda list'' be specified. A lambda list is a definition of the arguments accepted by a function. There are four different types of arguments.

    The lambda list starts with required arguments. Required arguments must be specified in every call to the function.

    The required arguments are followed by the &optional arguments. Optional arguments may be provided or omitted in a call. An initialization expression may be specified to provide a default value for an &optional argument if it is omitted from a call. If no initialization expression is specified, an omitted argument is initialized to NIL. It is also possible to provide the name of a supplied-p variable that can be used to determine if a call provided a value for the argument or if the initialization expression was used. If specified, the supplied- p variable will be bound to T if a value was specified in the call and NIL if the default value was used.

    The &optional arguments are followed by the &rest argument. The &rest argument gets bound to the remainder of the argument list after the required and &optional arguments have been removed.

    The &rest argument is followed by the &key arguments. When a keyword argument is passed to a function, a pair of values appears in the argument list. The first expression in the pair should evaluate to a keyword symbol (a symbol that begins with a ``:''). The value of the second expression is the value of the keyword argument. Like &optional arguments, &key arguments can have initialization expressions and supplied-p variables. In addition, it is possible to specify the keyword to be used in a function call. If no keyword is specified, the keyword obtained by adding a ``:'' to the beginning of the keyword argument symbol is used. In other words, if the keyword argument symbol is foo, the keyword will be ':foo.

    The &key arguments are followed by the &aux variables. These are local variables that are bound during the evaluation of the function body. It is possible to have initialization expressions for the &aux variables.

    Here is the complete syntax for lambda lists:

    (rarg...
    [&optional [oarg | (oarg [init [svar]])]...]
    [&rest rarg]
    [&key
    [karg | ([karg | (key karg)] [init [svar]])]...
    &allow-other-keys]
    [&aux
    [aux | (aux [init])]...])

    where:

    rarg is a required argument symbol
    oarg is an &optional argument symbol
    rarg is the &rest argument symbol
    karg is a &key argument symbol
    key is a keyword symbol
    aux is an auxiliary variable symbol
    init is an initialization expression
    svar is a supplied-p variable symbol

    Objects

    Definitions:
    • selector - a symbol used to select an appropriate method
    • message - a selector and a list of actual arguments
    • method - the code that implements a message
    Since XLISP was created to provide a simple basis for experimenting with object-oriented programming, one of the primitive data types included is object. In XLISP, an object consists of a data structure containing a pointer to the object's class as well as an array containing the values of the object's instance variables.

    Officially, there is no way to see inside an object (look at the values of its instance variables). The only way to communicate with an object is by sending it a message.

    You can send a message to an object using the send function. This function takes the object as its first argument, the message selector as its second argument (which must be a symbol) and the message arguments as its remaining arguments.

    The send function determines the class of the receiving object and attempts to find a method corresponding to the message selector in the set of messages defined for that class. If the message is not found in the object's class and the class has a super-class, the search continues by looking at the messages defined for the super-class. This process continues from one super-class to the next until a method for the message is found. If no method is found, an error occurs.

    A message can also be sent from the body of a method by using the current object, but the method lookup starts with the object's superclass rather than its class. This allows a subclass to invoke a standard method in its parent class even though it overrides that method with its own specialized version.

    When a method is found, the evaluator binds the receiving object to the symbol self and evaluates the method using the remaining elements of the original list as arguments to the method. These arguments are always evaluated prior to being bound to their corresponding formal arguments. The result of evaluating the method becomes the result of the expression.

    The ``Object'' Class

    Object - the top of the class hierarchy.

    Messages:

    :show - show an object's instance variables.
    returns - the object

    :class - return the class of an object
    returns - the class of the object

    :isnew - the default object initialization routine
    returns - the object
    :sendsuper sel args... - send superclass a message
    sel - the message selector
    args - the message arguments
    returns - the result of sending the message

    The ``Class'' Class

    Class - class of all object classes (including itself)

    Messages:

    :new - create a new instance of a class
    returns - the new class object

    :isnew ivars [cvars [super]] - initialize a new class
    ivars - the list of instance variable symbols
    cvars - the list of class variable symbols
    super - the superclass (default is object)
    returns - the new class object

    :answer msg fargs code - add a message to a class
    msg - the message symbol
    fargs - the formal argument list (lambda list)
    code - a list of executable expressions
    returns - the object

    When a new instance of a class is created by sending the message :new to an existing class, the message :isnew followed by whatever parameters were passed to the :new message is sent to the newly created object.

    When a new class is created by sending the :new message to the object Class, an optional parameter may be specified indicating the superclass of the new class. If this parameter is omitted, the new class will be a subclass of Object. A class inherits all instance variables, class variables, and methods from its super-class.

    Profiling

    The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where eval is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an eval in the immediately (lexically) enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls. The list of all functions executed is maintained on the global *profile* variable. These functions in turn have *profile* properties, which maintain the counts. The profile system merely increments counters and puts symbols on the *profile* list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the profile function. Unfortunately, methods cannot be profiled with this facility.

    SYMBOLS

    There are several symbols maintained by the read/eval/print loop. The symbols +, ++, and +++ are bound to the most recent three input expressions. The symbols *, ** and *** are bound to the most recent three results. The symbol - is bound to the expression currently being evaluated. It becomes the value of + at the end of the evaluation.

    Evaluation Functions

    (eval expr) - evaluate an xlisp expression
    expr - the expression to be evaluated
    returns - the result of evaluating the expression

    (apply fun args) - apply a function to a list of arguments
    fun - the function to apply (or function symbol)
    args - the argument list
    returns - the result of applying the function to the arguments

    (funcall fun arg...) - call a function with arguments
    fun - the function to call (or function symbol)
    arg - arguments to pass to the function
    returns - the result of calling the function with the arguments

    (quote expr) - return an expression unevaluated
    expr - the expression to be quoted (quoted)
    returns - expr unevaluated

    (function expr) - get the functional interpretation
    expr - the symbol or lambda expression (quoted)
    returns - the functional interpretation

    (backquote expr) - fill in a template
    expr - the template
    returns - a copy of the template with comma and comma-at
    expressions expanded

    (lambda args expr...) - make a function closure
    args - formal argument list (lambda list) (quoted)
    expr - expressions of the function body
    returns - the function closure

    (get-lambda-expression closure) - get the lambda expression
    closure - the closure
    returns - the original lambda expression

    (macroexpand form) - recursively expand macro calls
    form - the form to expand
    returns - the macro expansion

    (macroexpand-1 form) - expand a macro call
    form - the macro call form
    returns - the macro expansion

    Symbol Functions

    (set sym expr) - set the value of a symbol
    sym - the symbol being set
    expr - the new value
    returns - the new value

    (setq [sym expr]...) - set the value of a symbol
    sym - the symbol being set (quoted)
    expr - the new value
    returns - the new value

    (psetq [sym expr]...) - parallel version of setq
    sym - the symbol being set (quoted)
    expr - the new value
    returns - the new value

    (setf [place expr]...) - set the value of a field
    place - the field specifier (quoted):
    sym - set value of a symbol
    (car expr) - set car of a cons node
    (cdr expr) - set cdr of a cons node
    (nth n expr) - set nth car of a list
    (aref expr n) - set nth element of an array
    (get sym prop) - set value of a property
    (symbol-value sym) - set value of a symbol
    (symbol-function sym) - set functional value of a symbol
    (symbol-plist sym) - set property list of a symbol
    expr - the new value
    returns - the new value

    (defun sym fargs expr...) - define a function
    (defmacro
    sym fargs expr...) - define a macro
    sym - symbol being defined (quoted)
    fargs - formal argument list (lambda list) (quoted)
    expr - expressions constituting the body of the
    function (quoted) returns - the function symbol

    (gensym [tag]) - generate a symbol
    tag - string or number
    returns - the new symbol

    (intern pname) - make an interned symbol
    pname - the symbol's print name string
    returns - the new symbol

    (make-symbol pname) - make an uninterned symbol
    pname - the symbol's print name string
    returns - the new symbol

    (symbol-name sym) - get the print name of a symbol
    sym - the symbol
    returns - the symbol's print name

    (symbol-value sym) - get the value of a symbol
    sym - the symbol
    returns - the symbol's value

    (symbol-function sym) - get the functional value of a symbol
    sym - the symbol
    returns - the symbol's functional value

    (symbol-plist sym) - get the property list of a symbol
    sym - the symbol
    returns - the symbol's property list

    (hash sym n) - compute the hash index for a symbol
    sym - the symbol or string
    n - the table size (integer)
    returns - the hash index (integer)

    Property List Functions

    (get sym prop) - get the value of a property
    sym - the symbol
    prop - the property symbol
    returns - the property value or nil

    (putprop sym val prop) - put a property onto a property list
    sym - the symbol
    val - the property value
    prop - the property symbol
    returns - the property value

    (remprop sym prop) - remove a property
    sym - the symbol
    prop - the property symbol
    returns - nil

    Array Functions

    (aref array n) - get the nth element of an array
    array - the array
    n - the array index (integer)
    returns - the value of the array element

    (make-array size) - make a new array
    size - the size of the new array (integer)
    returns - the new array

    (vector expr...) - make an initialized vector
    expr - the vector elements
    returns - the new vector

    List Functions

    (car expr) - return the car of a list node
    expr - the list node
    returns - the car of the list node

    (cdr expr) - return the cdr of a list node
    expr - the list node
    returns - the cdr of the list node

    (cxxr expr) - all cxxr combinations


    (cxxxr expr) - all cxxxr combinations


    (cxxxxr expr) - all cxxxxr combinations


    (first expr) - a synonym for car


    (second expr) - a synonym for cadr


    (third expr) - a synonym for caddr


    (fourth expr) - a synonym for cadddr


    (rest expr) - a synonym for cdr


    (cons expr1 expr2) - construct a new list node
    expr1 - the car of the new list node
    expr2 - the cdr of the new list node
    returns - the new list node

    (list expr...) - create a list of values
    expr - expressions to be combined into a list
    returns - the new list

    (append expr...) - append lists
    expr - lists whose elements are to be appended
    returns - the new list

    (reverse expr) - reverse a list
    expr - the list to reverse
    returns - a new list in the reverse order

    (last list) - return the last list node of a list
    list - the list
    returns - the last list node in the list

    (member expr list &key :test :test-not) - find an expression in a list
    expr - the expression to find
    list - the list to search
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the remainder of the list starting with the expression

    (assoc expr alist &key :test :test-not) - find an expression in an a-list
    expr - the expression to find
    alist - the association list
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the alist entry or nil

    (remove expr list &key :test :test-not) - remove elements from a list
    expr - the element to remove
    list - the list
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - copy of list with matching expressions removed

    (remove-if test list) - remove elements that pass test
    test - the test predicate
    list - the list
    returns - copy of list with matching elements removed

    (remove-if-not test list) - remove elements that fail test
    test - the test predicate
    list - the list
    returns - copy of list with non-matching elements removed

    (length expr) - find the length of a list, vector or string
    expr - the list, vector or string
    returns - the length of the list, vector or string

    (nth n list) - return the nth element of a list
    n - the number of the element to return (zero origin)
    list - the list
    returns - the nth element or nil if the list isn't that long

    (nthcdr n list) - return the nth cdr of a list
    n - the number of the element to return (zero origin)
    list - the list
    returns - the nth cdr or nil if the list isn't that long

    (mapc fcn list1 list...) - apply function to successive cars
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - the first list of arguments

    (mapcar fcn list1 list...) - apply function to successive cars
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - a list of the values returned

    (mapl fcn list1 list...) - apply function to successive cdrs
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - the first list of arguments

    (maplist fcn list1 list...) - apply function to successive cdrs
    fcn - the function or function name
    listn - a list for each argument of the function
    returns - a list of the values returned

    (subst to from expr &key :test :test-not) - substitute expressions
    to - the new expression
    from - the old expression
    expr - the expression in which to do the substitutions
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the expression with substitutions

    (sublis alist expr &key :test :test-not) - substitute with an a-list
    alist - the association list
    expr - the expression in which to do the substitutions
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the expression with substitutions

    Destructive List Functions

    (rplaca list expr) - replace the car of a list node
    list - the list node
    expr - the new value for the car of the list node
    returns - the list node after updating the car

    (rplacd list expr) - replace the cdr of a list node
    list - the list node
    expr - the new value for the cdr of the list node
    returns - the list node after updating the cdr

    (nconc list...) - destructively concatenate lists
    list - lists to concatenate
    returns - the result of concatenating the lists

    (delete expr &key :test :test-not) - delete elements from a list
    expr - the element to delete
    list - the list
    :test - the test function (defaults to eql)
    :test-not - the test function (sense inverted)
    returns - the list with the matching expressions deleted

    (delete-if test list) - delete elements that pass test
    test - the test predicate
    list - the list
    returns - the list with matching elements deleted

    (delete-if-not test list) - delete elements that fail test
    test - the test predicate
    list - the list
    returns - the list with non-matching elements deleted

    (sort list test) - sort a list
    list - the list to sort
    test - the comparison function
    returns - the sorted list

    Predicate Functions

    (atom expr) - is this an atom?
    expr - the expression to check
    returns - t if the value is an atom, nil otherwise

    (symbolp expr) - is this a symbol?
    expr - the expression to check
    returns - t if the expression is a symbol, nil otherwise

    (numberp expr) - is this a number?
    expr - the expression to check
    returns - t if the expression is a number, nil otherwise

    (null expr) - is this an empty list?
    expr - the list to check
    returns - t if the list is empty, nil otherwise

    (not expr) - is this false?
    expr - the expression to check
    return - t if the value is nil, nil otherwise

    (listp expr) - is this a list?
    expr - the expression to check
    returns - t if the value is a cons or nil, nil otherwise

    (endp list) - is this the end of a list
    list - the list
    returns - t if the value is nil, nil otherwise

    (consp expr) - is this a non-empty list?
    expr - the expression to check
    returns - t if the value is a cons, nil otherwise

    (integerp expr) - is this an integer?
    expr - the expression to check
    returns - t if the value is an integer, nil otherwise

    (floatp expr) - is this a float?
    expr - the expression to check
    returns - t if the value is a float, nil otherwise

    (stringp expr) - is this a string?
    expr - the expression to check
    returns - t if the value is a string, nil otherwise

    (characterp expr) - is this a character?
    expr - the expression to check
    returns - t if the value is a character, nil otherwise

    (arrayp expr) - is this an array?
    expr - the expression to check
    returns - t if the value is an array, nil otherwise

    (streamp expr) - is this a stream?
    expr - the expression to check
    returns - t if the value is a stream, nil otherwise

    (objectp expr) - is this an object?
    expr - the expression to check
    returns - t if the value is an object, nil otherwise

    (boundp sym) - is a value bound to this symbol?
    sym - the symbol
    returns - t if a value is bound to the symbol, nil otherwise

    (fboundp sym) - is a functional value bound to this symbol?
    sym - the symbol
    returns - t if a functional value is bound to the symbol,
    nil otherwise

    (minusp expr) - is this number negative?
    expr - the number to test
    returns - t if the number is negative, nil otherwise

    (zerop expr) - is this number zero?
    expr - the number to test
    returns - t if the number is zero, nil otherwise

    (plusp expr) - is this number positive?
    expr - the number to test
    returns - t if the number is positive, nil otherwise

    (evenp expr) - is this integer even?
    expr - the integer to test
    returns - t if the integer is even, nil otherwise

    (oddp expr) - is this integer odd?
    expr - the integer to test
    returns - t if the integer is odd, nil otherwise

    (eq expr1 expr2) - are the expressions identical?
    expr1 - the first expression
    expr2 - the second expression
    returns - t if they are equal, nil otherwise

    (eql expr1 expr2) - are the expressions identical? (works with all numbers)
    expr1 - the first expression
    expr2 - the second expression
    returns - t if they are equal, nil otherwise

    (equal expr1 expr2) - are the expressions equal?
    expr1 - the first expression
    expr2 - the second expression
    returns - t if they are equal, nil otherwise

    Control Constructs

    (cond pair...) - evaluate conditionally
    pair - pair consisting of:
    (pred expr...)
    where:
    pred - is a predicate expression
    expr - evaluated if the predicate is not nil
    returns - the value of the first expression whose predicate is not nil

    (and expr...) - the logical and of a list of expressions
    expr - the expressions to be anded
    returns - nil if any expression evaluates to nil, otherwise the value of the last expression (evaluation of expressions stops after the first expression that evaluates to nil)

    (or expr...) - the logical or of a list of expressions
    expr - the expressions to be ored
    returns - nil if all expressions evaluate to nil, otherwise the value of the first non-nil expression (evaluation of expressions stops after the first expression that does not evaluate to nil)

    (if texpr expr1 [expr2]) - evaluate expressions conditionally
    texpr - the test expression
    expr1 - the expression to be evaluated if texpr is non-nil
    expr2 - the expression to be evaluated if texpr is nil
    returns - the value of the selected expression

    (when texpr expr...) - evaluate only when a condition is true
    texpr - the test expression
    expr - the expression(s) to be evaluated if texpr is non-nil
    returns - the value of the last expression or nil

    (unless texpr expr...) - evaluate only when a condition is false
    texpr - the test expression
    expr - the expression(s) to be evaluated if texpr is nil
    returns - the value of the last expression or nil

    (case expr case...) - select by case
    expr - the selection expression
    case - pair consisting of:
    (value expr...)
    where:
    value - is a single expression or a list of expressions (unevaluated)
    expr - are expressions to execute if the case matches
    returns - the value of the last expression of the matching case

    (let (binding...) expr...) - create local bindings
    (let*
    (binding...) expr...) - let with sequential binding
    binding - the variable bindings each of which is either:
    1) a symbol (which is initialized to nil)
    2) a list whose car is a symbol and whose cadr is an initialization expression
    expr - the expressions to be evaluated
    returns - the value of the last expression

    (flet (binding...) expr...) - create local functions
    (labels
    (binding...) expr...) - flet with recursive functions
    (macrolet
    (binding...) expr...) - create local macros
    binding - the function bindings each of which is:
    (sym fargs expr...)
    where:
    sym - the function/macro name
    fargs - formal argument list (lambda list)
    expr - expressions constituting the body of the function/macro
    expr - the expressions to be evaluated
    returns - the value of the last expression

    (catch sym expr...) - evaluate expressions and catch throws
    sym - the catch tag
    expr - expressions to evaluate
    returns - the value of the last expression the throw expression

    (throw sym [expr]) - throw to a catch
    sym - the catch tag
    expr - the value for the catch to return (defaults to nil)
    returns - never returns

    (unwind-protect expr cexpr...) - protect evaluation of an expression
    expr - the expression to protect
    cexpr - the cleanup expressions
    returns - the value of the expression
    Note: unwind-protect guarantees to execute the cleanup expressions even if a non-local exit terminates the evaluation of the protected expression

    Looping Constructs

    (loop expr...) - basic looping form
    expr - the body of the loop
    returns - never returns (must use non-local exit)

    (do (binding...) (texpr rexpr...) expr...)
    (do*
    (binding...) (texpr rexpr...) expr...)
    binding - the variable bindings each of which is either:
    1) a symbol (which is initialized to nil)
    2) a list of the form: (sym init [step]) where:
    sym - is the symbol to bind
    init - is the initial value of the symbol
    step - is a step expression
    texpr - the termination test expression
    rexpr - result expressions (the default is nil)
    expr - the body of the loop (treated like an implicit prog)
    returns - the value of the last result expression

    (dolist (sym expr [rexpr]) expr...) - loop through a list
    sym - the symbol to bind to each list element
    expr - the list expression
    rexpr - the result expression (the default is nil)
    expr - the body of the loop (treated like an implicit prog)

    (dotimes (sym expr [rexpr]) expr...) - loop from zero to n-1
    sym - the symbol to bind to each value from 0 to n-1
    expr - the number of times to loop
    rexpr - the result expression (the default is nil)
    expr - the body of the loop (treated like an implicit prog)

    The Program Feature

    (prog (binding...) expr...) - the program feature
    (prog*
    (binding...) expr...) - prog with sequential binding
    binding - the variable bindings each of which is either:
    1) a symbol (which is initialized to nil)
    2) a list whose car is a symbol and whose cadr is an initialization expression
    expr - expressions to evaluate or tags (symbols)
    returns - nil or the argument passed to the return function

    (block name expr...) - named block
    name - the block name (symbol)
    expr - the block body
    returns - the value of the last expression

    (return [expr]) - cause a prog construct to return a value
    expr - the value (defaults to nil)
    returns - never returns

    (return-from name [value]) - return from a named block
    name - the block name (symbol)
    value - the value to return (defaults to nil)
    returns - never returns

    (tagbody expr...) - block with labels
    expr - expression(s) to evaluate or tags (symbols)
    returns - nil

    (go sym) - go to a tag within a tagbody or prog
    sym - the tag (quoted)
    returns - never returns

    (progv slist vlist expr...) - dynamically bind symbols
    slist - list of symbols
    vlist - list of values to bind to the symbols
    expr - expression(s) to evaluate
    returns - the value of the last expression

    (prog1 expr1 expr...) - execute expressions sequentially
    expr1 - the first expression to evaluate
    expr - the remaining expressions to evaluate
    returns - the value of the first expression

    (prog2 expr1 expr2 expr...) - execute expressions sequentially
    expr1 - the first expression to evaluate
    expr2 - the second expression to evaluate
    expr - the remaining expressions to evaluate
    returns - the value of the second expression

    (progn expr...) - execute expressions sequentially
    expr - the expressions to evaluate
    returns - the value of the last expression (or nil)

    Debugging and Error Handling

    (trace sym) - add a function to the trace list
    sym - the function to add (quoted)
    returns - the trace list

    (untrace sym) - remove a function from the trace list
    sym - the function to remove (quoted)
    returns - the trace list

    (error emsg [arg]) - signal a non-correctable error
    emsg - the error message string
    arg - the argument expression (printed after the message)
    returns - never returns

    (cerror cmsg emsg [arg]) - signal a correctable error
    cmsg - the continue message string
    emsg - the error message string
    arg - the argument expression (printed after the message)
    returns - nil when continued from the break loop

    (break [bmsg [arg]]) - enter a break loop
    bmsg - the break message string (defaults to **break**)
    arg - the argument expression (printed after the message)
    returns - nil when continued from the break loop

    (clean-up) - clean-up after an error
    returns - never returns

    (top-level) - clean-up after an error and return to the top level
    returns - never returns

    (continue) - continue from a correctable error
    returns - never returns

    (errset expr [pflag]) - trap errors
    expr - the expression to execute
    pflag - flag to control printing of the error message
    returns - the value of the last expression consed with nil
    or nil on error

    (baktrace [n]) - print n levels of trace back information
    n - the number of levels (defaults to all levels)
    returns - nil

    (evalhook expr ehook ahook [env]) - evaluate with hooks
    expr - the expression to evaluate
    ehook - the value for *evalhook*
    ahook - the value for *applyhook*
    env - the environment (default is nil)
    returns - the result of evaluating the expression

    (profile flag) (Footnote 3) - turn profiling on or off.
    flag - nil turns profiling off, otherwise on
    returns - the previous state of profiling.

    Arithmetic Functions

    (truncate expr) - truncates a floating point number to an integer
    expr - the number
    returns - the result of truncating the number

    (float expr) - converts an integer to a floating point number
    expr - the number
    returns - the result of floating the integer

    (+ expr...) - add a list of numbers
    expr - the numbers
    returns - the result of the addition

    (- expr...) - subtract a list of numbers or negate a single number
    expr - the numbers
    returns - the result of the subtraction

    (* expr...) - multiply a list of numbers
    expr - the numbers
    returns - the result of the multiplication

    (/ expr...) - divide a list of numbers
    expr - the numbers
    returns - the result of the division

    (1+ expr) - add one to a number
    expr - the number
    returns - the number plus one

    (1- expr) - subtract one from a number
    expr - the number
    returns - the number minus one

    (rem expr...) - remainder of a list of numbers
    expr - the numbers
    returns - the result of the remainder operation

    (min expr...) - the smallest of a list of numbers
    expr - the expressions to be checked
    returns - the smallest number in the list

    (max expr...) - the largest of a list of numbers
    expr - the expressions to be checked
    returns - the largest number in the list

    (abs expr) - the absolute value of a number
    expr - the number
    returns - the absolute value of the number

    (gcd n1 n2...) - compute the greatest common divisor
    n1 - the first number (integer)
    n2 - the second number(s) (integer)
    returns - the greatest common divisor

    (random n) - compute a random number between 1 and n-1
    n - the upper bound (integer)
    returns - a random number

    (sin expr) - compute the sine of a number
    expr - the floating point number
    returns - the sine of the number

    (cos expr) - compute the cosine of a number
    expr - the floating point number
    returns - the cosine of the number

    (tan expr) - compute the tangent of a number
    expr - the floating point number
    returns - the tangent of the number

    (expt x-expr y-expr) - compute x to the y power
    x-expr - the floating point number
    y-expr - the floating point exponent
    returns - x to the y power

    (exp x-expr) - compute e to the x power
    x-expr - the floating point number
    returns - e to the x power

    (sqrt expr) - compute the square root of a number
    expr - the floating point number
    returns - the square root of the number

    (< n1 n2...) - test for less than
    (<=
    n1 n2...) - test for less than or equal to
    (=
    n1 n2...) - test for equal to
    (/=
    n1 n2...) - test for not equal to
    (>=
    n1 n2...) - test for greater than or equal to
    (>
    n1 n2...) - test for greater than
    n1 - the first number to compare
    n2 - the second number to compare
    returns - t if the results of comparing n1 with n2, n2 with n3, etc., are all true.

    Bitwise Logical Functions

    (logand expr...) - the bitwise and of a list of numbers
    expr - the numbers
    returns - the result of the and operation

    (logior expr...) - the bitwise inclusive or of a list of numbers
    expr - the numbers
    returns - the result of the inclusive or operation

    (logxor expr...) - the bitwise exclusive or of a list of numbers
    expr - the numbers
    returns - the result of the exclusive or operation

    (lognot expr) - the bitwise not of a number
    expr - the number
    returns - the bitwise inversion of number

    String Functions

    (string expr) - make a string from an integer ascii value
    expr - the integer
    returns - a one character string

    (string-search pat str &key :start :end) (Footnote 4) - search for pattern in string
    pat - a string to search for
    str - the string to be searched
    :start - the starting offset in str
    :end - the ending offset + 1
    returns - index of pat in str or NIL if not found

    (string-trim bag str) - trim both ends of a string
    bag - a string containing characters to trim
    str - the string to trim
    returns - a trimed copy of the string

    (string-left-trim bag str) - trim the left end of a string
    bag - a string containing characters to trim
    str - the string to trim
    returns - a trimed copy of the string

    (string-right-trim bag str) - trim the right end of a string
    bag - a string containing characters to trim
    str - the string to trim
    returns - a trimed copy of the string

    (string-upcase str &key :start :end) - convert to uppercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - a converted copy of the string

    (string-downcase str &key :start :end) - convert to lowercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - a converted copy of the string

    (nstring-upcase str &key :start :end) - convert to uppercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - the converted string (not a copy)

    (nstring-downcase str &key :start :end) - convert to lowercase
    str - the string
    :start - the starting offset
    :end - the ending offset + 1
    returns - the converted string (not a copy)

    (strcat expr...) - concatenate strings
    expr - the strings to concatenate
    returns - the result of concatenating the strings

    (subseq string start [end]) - extract a substring
    string - the string
    start - the starting position (zero origin)
    end - the ending position + 1 (defaults to end)
    returns - substring between start and end

    (string< str1 str2 &key :start1 :end1 :start2 :end2)
    (string<=
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string=
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string/=
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string>=
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string>
    str1 str2 &key :start1 :end1 :start2 :end2)
    str1 - the first string to compare
    str2 - the second string to compare
    :start1 - first substring starting offset
    :end1 - first substring ending offset + 1
    :start2 - second substring starting offset
    :end2 - second substring ending offset + 1
    returns - t if predicate is true, nil otherwise
    Note: case is significant with these comparison functions.

    (string-lessp str1 str2 &key :start1 :end1 :start2 :end2)
    (string-not-greaterp
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string-equalp
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string-not-equalp
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string-not-lessp
    str1 str2 &key :start1 :end1 :start2 :end2)
    (string-greaterp str1 str2 &key :start1 :end1 :start2 :end2)
    str1 - the first string to compare
    str2 - the second string to compare
    :start1 - first substring starting offset
    :end1 - first substring ending offset + 1
    :start2 - second substring starting offset
    :end2 - second substring ending offset + 1
    returns - t if predicate is true, nil otherwise
    Note: case is not significant with these comparison functions.

    Character Functions

    (char string index) - extract a character from a string
    string - the string
    index - the string index (zero relative)
    returns - the ascii code of the character

    (upper-case-p chr) - is this an upper case character?
    chr - the character
    returns - t if the character is upper case, nil otherwise

    (lower-case-p chr) - is this a lower case character?
    chr - the character
    returns - t if the character is lower case, nil otherwise

    (both-case-p chr) - is this an alphabetic (either case) character?
    chr - the character
    returns - t if the character is alphabetic, nil otherwise

    (digit-char-p chr) - is this a digit character?
    chr - the character
    returns - the digit weight if character is a digit, nil otherwise

    (char-code chr) - get the ascii code of a character
    chr - the character
    returns - the ascii character code (integer)

    (code-char code) - get the character with a specified ascii code
    code - the ascii code (integer)
    returns - the character with that code or nil

    (char-upcase chr) - convert a character to upper case
    chr - the character
    returns - the upper case character

    (char-downcase chr) - convert a character to lower case
    chr - the character
    returns - the lower case character

    (digit-char n) - convert a digit weight to a digit
    n - the digit weight (integer)
    returns - the digit character or nil

    (char-int chr) - convert a character to an integer
    chr - the character
    returns - the ascii character code

    (int-char int) - convert an integer to a character
    int - the ascii character code
    returns - the character with that code

    (char< chr1 chr2...)
    (char<=
    chr1 chr2...)
    (char=
    chr1 chr2...)
    (char/=
    chr1 chr2...)
    (char>=
    chr1 chr2...)
    (char>
    chr1 chr2...)
    chr1 - the first character to compare
    chr2 - the second character(s) to compare
    returns - t if predicate is true, nil otherwise
    Note: case is significant with these comparison functions.

    (char-lessp chr1 chr2...)
    (char-not-greaterp
    chr1 chr2...)
    (char-equalp
    chr1 chr2...)
    (char-not-equalp
    chr1 chr2...)
    (char-not-lessp
    chr1 chr2...)
    (char-greaterp
    chr1 chr2...)
    chr1 - the first string to compare
    chr2 - the second string(s) to compare
    returns - t if predicate is true, nil otherwise

    Note: case is not significant with these comparison functions.

    Input/Output Functions

    (read [stream [eof [rflag]]]) - read an expression
    stream - the input stream (default is standard input)
    eof - the value to return on end of file (default is nil)
    rflag - recursive read flag (default is nil)
    returns - the expression read

    (print expr [stream]) - print an expression on a new line
    expr - the expression to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    (prin1 expr [stream]) - print an expression
    expr - the expression to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    (princ expr [stream]) - print an expression without quoting
    expr - the expressions to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    (pprint expr [stream]) - pretty print an expression
    expr - the expressions to be printed
    stream - the output stream (default is standard output)
    returns - the expression

    (terpri [stream]) - terminate the current print line
    stream - the output stream (default is standard output)
    returns - nil

    (flatsize expr) - length of printed representation using prin1
    expr - the expression
    returns - the length

    (flatc expr) - length of printed representation using princ
    expr - the expression
    returns - the length

    The Format Function

    (format stream fmt arg...) - do formated output
    stream - the output stream
    fmt - the format string
    arg - the format arguments
    returns - output string if stream is nil, nil otherwise

    The format string can contain characters that should be copied directly to the output and formatting directives. The formatting directives are:
    ~A - print next argument using princ
    ~S - print next argument using prin1
    ~% - start a new line
    ~~ - print a tilde character

    File I/O Functions

    Note that files are ordinarily opened as text. Binary files (such as standard midi files) must be opened with open-binary on non-unix systems.
    (open fname &key :direction) - open a file stream
    fname - the file name string or symbol
    :direction - :input or :output (default is :input)
    returns - a stream

    (open-binary fname &key :direction) - open a binary file stream
    fname - the file name string or symbol
    :direction - :input or :output (default is :input)
    returns - a stream

    (close stream) - close a file stream
    stream - the stream
    returns - nil

    (read-char [stream]) - read a character from a stream
    stream - the input stream (default is standard input)
    returns - the character

    (peek-char [flag [stream]]) - peek at the next character
    flag - flag for skipping white space (default is nil)
    stream - the input stream (default is standard input)
    returns - the character (integer)

    (write-char ch [stream]) - write a character to a stream
    ch - the character to write
    stream - the output stream (default is standard output)
    returns - the character

    (read-int [stream [length]]) - read a binary integer from a stream
    stream - the input stream (default is standard input)
    length - the length of the integer in bytes (default is 4)
    returns - the integer
    Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    (write-int ch [stream [length]]) - write a binary integer to a stream
    ch - the character to write
    stream - the output stream (default is standard output)
    length - the length of the integer in bytes (default is 4)
    returns - the integer
    Note: Integers are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    (read-float [stream [length]]) - read a binary floating-point number from a stream
    stream - the input stream (default is standard input)
    length - the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8)
    returns - the integer
    Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    (write-float ch [stream [length]]) - write a binary floating-point number to a stream
    ch - the character to write
    stream - the output stream (default is standard output)
    length - the length of the float in bytes (default is 4, legal values are -4, -8, 4, and 8)
    returns - the integer
    Note: Floats are assumed to be big-endian (high-order byte first) and signed, regardless of the platform. To write in little-endian format, use a negative number for the length, e.g. -4 indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    (read-line [stream]) - read a line from a stream
    stream - the input stream (default is standard input)
    returns - the string

    (read-byte [stream]) - read a byte from a stream
    stream - the input stream (default is standard input)
    returns - the byte (integer)

    (write-byte byte [stream]) - write a byte to a stream
    byte - the byte to write (integer)
    stream - the output stream (default is standard output)
    returns - the byte (integer)

    String Stream Functions

    These functions operate on unnamed streams. An unnamed output stream collects characters sent to it when it is used as the destination of any output function. The functions get-output-stream-string and string or a list of characters.

    An unnamed input stream is setup with the make-string-input-stream function and returns each character of the string when it is used as the source of any input function.


    (make-string-input-stream str [start [end]])
    str - the string
    start - the starting offset
    end - the ending offset + 1
    returns - an unnamed stream that reads from the string

    (make-string-output-stream)
    returns - an unnamed output stream

    (get-output-stream-string stream)
    stream - the output stream
    returns - the output so far as a string
    Note: the output stream is emptied by this function

    (get-output-stream-list stream)
    stream - the output stream
    returns - the output so far as a list
    Note: the output stream is emptied by this function

    System Functions

    Note: the load function first tries to load a file from the current directory. A .lsp extension is added if there is not already an alphanumeric extension following a period. If that fails, XLisp searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. (The Macintosh version has no search path.)

    (load fname &key :verbose :print) - load a source file
    fname - the filename string or symbol
    :verbose - the verbose flag (default is t)
    :print - the print flag (default is nil)
    returns - the filename

    (save fname) - save workspace to a file
    fname - the filename string or symbol
    returns - t if workspace was written, nil otherwise

    (restore fname) - restore workspace from a file
    fname - the filename string or symbol
    returns - nil on failure, otherwise never returns

    (dribble [fname]) - create a file with a transcript of a session
    fname - file name string or symbol (if missing, close current transcript)
    returns - t if the transcript is opened, nil if it is closed

    (gc) - force garbage collection
    returns - nil

    (expand num) - expand memory by adding segments
    num - the number of segments to add
    returns - the number of segments added

    (alloc num) - change number of nodes to allocate in each segment
    num - the number of nodes to allocate
    returns - the old number of nodes to allocate

    (room) - show memory allocation statistics
    returns - nil

    (type-of expr) - returns the type of the expression
    expr - the expression to return the type of
    returns - nil if the value is nil otherwise one of the symbols:
    SYMBOL - for symbols
    OBJECT - for objects
    CONS - for conses
    SUBR - for built-in functions
    FSUBR - for special forms
    CLOSURE - for defined functions
    STRING - for strings
    FIXNUM - for integers
    FLONUM - for floating point numbers
    CHARACTER - for characters
    FILE-STREAM - for file pointers
    UNNAMED-STREAM - for unnamed streams
    ARRAY - for arrays

    (peek addrs) - peek at a location in memory
    addrs - the address to peek at (integer)
    returns - the value at the specified address (integer)

    (poke addrs value) - poke a value into memory
    addrs - the address to poke (integer)
    value - the value to poke into the address (integer)
    returns - the value

    (address-of expr) - get the address of an xlisp node
    expr - the node
    returns - the address of the node (integer)

    (exit) - exit xlisp
    returns - never returns

    (setup-console) - set default console attributes
    returns - NIL
    Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of ``Nyquist.'' This is normally accomplished by calling setup-console in system.lsp. In Nyquist, you can avoid this behavior by setting *setup-console* to NIL in your init.lsp file. If setup-console is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.

    File I/O Functions

    Input from a File

    To open a file for input, use the open function with the keyword argument :direction set to :input. To open a file for output, use the open function with the keyword argument :direction set to :output. The open function takes a single required argument which is the name of the file to be opened. This name can be in the form of a string or a symbol. The open function returns an object of type FILE-STREAM if it succeeds in opening the specified file. It returns the value nil if it fails. In order to manipulate the file, it is necessary to save the value returned by the open function. This is usually done by assigning it to a variable with the setq special form or by binding it using let or let*. Here is an example:
    (setq fp (open "init.lsp" :direction :input))
    
    Evaluating this expression will result in the file init.lsp being opened. The file object that will be returned by the open function will be assigned to the variable fp.

    It is now possible to use the file for input. To read an expression from the file, just supply the value of the fp variable as the optional stream argument to read.

    (read fp)
    
    Evaluating this expression will result in reading the first expression from the file init.lsp. The expression will be returned as the result of the read function. More expressions can be read from the file using further calls to the read function. When there are no more expressions to read, the read function will return nil (or whatever value was supplied as the second argument to read).

    Once you are done reading from the file, you should close it. To close the file, use the following expression:

    (close fp)
    
    Evaluating this expression will cause the file to be closed.

    Output to a File

    Writing to a file is pretty much the same as reading from one. You need to open the file first. This time you should use the open function to indicate that you will do output to the file. For example:
    (setq fp (open "test.dat" :direction :output))
    
    Evaluating this expression will open the file test.dat for output. If the file already exists, its current contents will be discarded. If it doesn't already exist, it will be created. In any case, a FILE-STREAM object will be returned by the OPEN function. This file object will be assigned to the fp variable.

    It is now possible to write to this file by supplying the value of the fp variable as the optional stream parameter in the print function.

    (print "Hello there" fp)
    
    Evaluating this expression will result in the string ``Hello there'' being written to the file test.dat. More data can be written to the file using the same technique.

    Once you are done writing to the file, you should close it. Closing an output file is just like closing an input file.

    (close fp)
    
    Evaluating this expression will close the output file and make it permanent.

    A Slightly More Complicated File Example

    This example shows how to open a file, read each Lisp expression from the file and print it. It demonstrates the use of files and the use of the optional stream argument to the read function.
    (do* ((fp (open "test.dat" :direction :input))
          (ex (read fp) (read fp)))
         ((null ex) nil)
      (print ex))
    


    Previous Section | Next Section (Index) | Table of Contents | Title Page nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/manual.css0000644000175000000620000000112411512762341021745 0ustar stevestaff.example { color: #000000; background-color: #F5F5F5; padding: 8px; border: #808080; border-style: solid; border-width: 1px; width:auto; } .button { color: #000000; background-color: #F5F5F5; padding-top: 1px; padding-bottom: 1px; padding-left: 4px; padding-right: 8px; border: #808080; border-style: solid; border-width: 1px; white-space: pre; } .box { color: #000000; padding-top: 4px; padding-bottom: 4px; padding-left: 16px; padding-right: 16px; border: #808080; border-style: solid; border-width: 1px; } nyquist-3.05/docsrc/xlisp/xlisp-doc/manual/objects.htm0000644000175000000620000002722311512762341022131 0ustar stevestaffXLISP: An Object-oriented Lisp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    XLISP Object System


    1. Definitions
      • selector - a symbol used to select an appropriate method
      • message - a selector and a list of actual arguments
      • method - the code that implements a message
      • object - the top of the class hierarchy
      • class - the class of all object classes
    2. The 'send' Function
    3. The 'self' Symbol
    4. The 'send-super' Function
    5. The 'object' Class
      • object - the top of the class hierarchy
        • :show - show an object's instance variables
        • :class - return the class of an object
        • :isnew - the default object initialization routine
        • send-super - send superclass a message
    6. The 'class' Class
      • class - class of all object classes
        • :new - create a new instance of a class
        • :isnew - initialize a new class
        • :answer - add a message to a class

    1  Definitions


    selector  —  a symbol used to select an appropriate method, usually a keyword
    message  —  a selector symbol and a list of actual arguments
    method  —  the Lisp code that implements a message
    object  —  the top of the class hierarchy
    class  —  the class of all object classes [including itself]

    Since XLISP was created to provide a simple basis for experimenting with object-oriented programming, one of the primitive data types included is object. In XLISP, an object consists of a data structure containing a pointer to the object's class as well as an array containing the values of the object's instance variables.

    Officially, there is no way to see inside an object [look at the values of its instance variables]. The only way to communicate with an object is by sending it a message.

      Back to Top


    2  The 'send' Function


    You can send a message to an object using the send function:

    (send object selector [args])
    object - an object
    selector - message selector for object
    arg - parameter sent to object method
    returns - the object

    The send function takes the object as its first argument, the message selector as its second argument [which must be a symbol] and the message arguments as its remaining arguments. It determines the class of the receiving object and attempts to find a method corresponding to the message selector in the set of messages defined for that class. If the message is not found in the object's class and the class has a super-class, the search continues by looking at the messages defined for the super-class. This process continues from one super-class to the next until a method for the message is found. If no method is found, an error occurs.

      Back to Top


    3  The 'self' Symbol


    When a method is found, the evaluator binds the receiving object to the symbol self and evaluates the method using the remaining elements of the original list as arguments to the method. These arguments are always evaluated prior to being bound to their corresponding formal arguments. The result of evaluating the method becomes the result of the expression.

    Within the body of a method, a message can be sent to the current object by calling:

    (send self ... )
    

    The method lookup starts with the object's class regardless of the class containing the current method.

      Back to Top


    4  The 'send-super' Function


    Sometimes it is desirable to invoke a general method in a superclass even when it is overridden by a more specific method in a subclass. This can be accomplished by calling send-super, which begins the method lookup in the superclass of the class defining the current method rather than in the class of the current object:

    (send-super selector [args])
    selector - the message selector
    args - the optional message arguments
    returns - the result of sending the message

    The send-super function takes a selector as its first argument [which must be a symbol] and the message arguments as its remaining arguments. Notice that send-super can only be sent from within a method, and the target of the message is always the current object self.

    (send-super ... )
    

    is similar to:

    (send self ... )
    

    except that method lookup begins in the superclass of the class containing the current method rather than the class of the current object.

      Back to Top


    5  The 'object' Class


    object - the top of the class hierarchy.

    Messages:

    (send object :show) - show an object's instance variables.
    returns - the object

    (send object :class) - return the class of an object
    returns - the class of the object

    (send object :isnew args) - run the default object initialization routine
    returns - the object

    (send object :isa class) - test if object inherits from class
    returns -  T  if object is an instance of class or a subclass of class, otherwise NIL

      Back to Top


    6  The 'class' Class


    class - class of all object classes (including itself)

    Messages:

    (send class :new ivars [cvars [super]]) - create a new instance of a class
    returns - the new class object

    (send class :isnew ivars [cvars [super]]) - initialize a new class
    ivars - list of instance variable symbols
    cvars - list of class variable symbols
    super - the superclass, default is object
    returns - the new class object

    (send class :answer selector fargs body) - add a message to a class
    selector - a message selector symbol
    fargs - the formal argument list, a lambda list
    body - a list of executable expressions
    returns - the object

    When a new instance of a class is created by sending the message :new to an existing class, the message :isnew followed by whatever parameters were passed to the :new message is sent to the newly created object.

    When a new class is created by sending the :new message to the object class, an optional parameter may be specified indicating the superclass of the new class. If this parameter is omitted, the new class will be a subclass of object. A class inherits all instance variables, class variables, and methods from its superclass.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/0002755000175000000620000000000011537433125020325 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/examples/examples.htm0000644000175000000620000002252511512762341022657 0ustar stevestaffXLISP Examples Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    XLISP Examples


    Nyquist/XLISP

    • Lists
      • print-cons - print lists as dotted conses
      • dolist* - a dolist version that can iterate dotted lists
    • Arrays
      • make-array* - create multi-dimensional arrays
      • aref* - access multi-dimensional arrays
    • Circular Access
      • c-nth - circular list accessor
      • c-aref - circular array accessor
    • Hash Tables
      • make-hash-table - create a hash-table
      • puthash - store a key/value pair in a hash-table
      • gethash - get a value from a hash-table by using a key
      • remhash - remove a key/value pair from a hash-table
      • clrhash - remove all key/value pairs from a hash-table
      • hash-table-p - is this a hash-table?
      • hash-table-size - get the number of buckets
      • hash-table count - get the number of key/value pairs
      • hash-table-test - get the :test argument given to to make-hash-table
      • print-hash-table - print a hash-table in human-readable form
    • Strings and Characters
    • Sequences - lists, strings, and arrays
    • Predicates and Comparison
    • Files and Directories
    • Numbers
    • Reader
      • read-from-string
      • *readtable*
        • print-readtable - print the XLISP *readtable* in human-readable form
        • get-macro-character
        • set-macro-character

    Common Lisp - written in Nyquist/XLISP

    • Data and Control Flow
      • Comparison
        • eq - [Function] - test if arguments are identical
        • eql - [Function] - test if arguments are identical or same integer value
        • equal - [Function] - test if arguments are structurally equivalent
        • cl:equalp - [Function] - test arguments with 'equality' functions
      • Multiple Values
    • Numbers
    • Conses
      • List Membership
        • cl:member - [Function] - test for membership in lists and sub-elements
        • cl:member-if - [Function] - search for the first element matching a predicate
        • cl:member-if-not - [Function] - search for the first element not matching a predicate
      • Non-destructive Removal
        • cl:remove
        • cl:remove-if
        • cl:remove-if-not
      • Destructive Removal = Deletion
        • cl:delete
        • cl:delete-if
        • cl:delete-if-not
      • Lists as Sets
        • cl:pushnew - [Macro] -
        • cl:union - [Function]
        • cl:intersection - [Function]
        • cl:set-difference - [Function]
        • cl:set-exclusive-or - [Function]
        • cl:subsetp - [Function]
    • Sequences
      • Subsequences
        • cl:subseq - subsequences of lists, strings, or arrays
      • Properties of elements in sequences:
        • cl:find
        • cl:count
        • cl:position
      • Predicates for testing sequences:
        • cl:every
        • cl:some
        • cl:notevery
        • cl:notany
      • Functions to modify sequences:
        • cl:map
    nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/apropos.htm0000644000175000000620000002514411512762341022524 0ustar stevestaff apropos Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    apropos


    (apropos &optional pattern type)

    The 'apropos' function searches the Nyquist/XLISP *obarray* for matching symbol names containing 'pattern' and being of 'type'. It prints a list of the results in alphabetical order.

    'pattern and 'type' can be given as symbols or strings. If no 'pattern' is given, all symbol names are considered as matching. If no 'type' is given, all symbol types are considered as matching. With 'type', only the first letter is important. A type of 'f' searches for symbols with a valid function value, while a type of 'v' searches for symbols with a valid variable value.

    Examples:

      
    (apropos)
      -  all symbols known by Nyquist
      
    (apropos nil 'f)
      -  all bound functions known by Nyquist
      
    (apropos nil 'v)
      -  all bound variables known by Nyquist
      
    (apropos 'snd 'f)
      -  all function names containing 'snd'

    A method to introspect classes and objects:

    (setq instance-var '*wrong-variable*)                 ; value outside the object
    
    (setq my-class (send class :new '(instance-var)))                ; class with instance variable
    (send my-class :answer :isnew '() '((setq instance-var '*OK*)))  ; value inside an object
    (send my-class :answer :eval '(list) '((eval list)))             ; evaluation method
    
    (setq my-object (send my-class :new))                 ; instance of my-class
    (send my-object :eval 'instance-var)                  => *OK*
    (send my-object :eval '(apropos 'instance-var 'v t))  => *WRONG-VARIABLE*
    

    The first version works because the call to 'eval' happens inside the object:

    (send my-class :answer :eval '(list) '((eval list))) => *OK*
    

    The second version doesn't work because the call to 'eval' happens outside the object:

    (defun external-function (list)
      (eval list))
    
    (send my-class :answer :eval '(list) '((external-function list))) => *WRONG-VARIABLE*
    

    The call to 'apropos' doesn't work because 'apropos' is executed outside the object:

    (send my-object :eval '(apropos)) => *WRONG-VARIABLE*
    

    The trick is to pass the Lisp code of 'apropos' as a list into the inside of the object and 'apply' it there to the arguments:

    (send my-class :answer :apropos '(args)
      '((apply (get-lambda-expression #'apropos) args)))
    
    (send my-object :apropos '(instance-var v t)) => *OK*
    

    But this only works if all function that need access to internal instance or class variables are executed inside the object. For example, if 'apropos' calls a function that needs access to an internal instance variable, I would get a 'unbound variable' error.

    Here is the code of the 'apropos' function:

    (defun apropos (&optional pattern type)
      (let (result-list (*gc-flag* nil))
        ;; make sure 'pattern' is a string, either empty or upper-case
        (if pattern
            (setf pattern (string-upcase (string pattern)))
          (setf pattern ""))
        ;; take only the first letter of 'type' and make it an upper-case string
        (if type (setf type (string-upcase (subseq (string type) 0 1))))
        ;; go through all entries in the *obarray* symbol hash table
        (dotimes (i (length *obarray*))
          (let ((entry (aref *obarray* i)))  ; *obarray* is an array of lists
            ;; if the *obarray* entry is not an empty list
            (if entry
              ;; go through all elements of the *obarray* entry list
              ;; do not use 'dolist' because *obarray* contains *unbound*
              (dotimes (j (length entry))
                ;; convert the symbol to a string to enable pattern matching
                (let ((string (string (nth j entry))))
                  ;; if the symbol string matches the search pattern
                  (if (string-search pattern string)
                      ;; if a special symbol type to search for was given
                      (if type
                          ;; if a 'type' search was initiated and the current
                          ;; symbol has no 'type' value bound to it, do nothing
                          ;; and return from 'cond' without adding the symbol
                          ;; string to the result list
                          (cond ((and (string= type "F")  ; bound functions only
                                      (not (fboundp (nth j entry))))
                                 nil)
                                ((and (string= type "V")  ; bound variables only
                                      (not (boundp (nth j entry))))
                                 nil)
                                ;; if the symbol has passed all tests,
                                ;; add the symbol string to the result list
                                (t (setf result-list (cons string result-list))))
                        ;; if no special symbol type to search for had been given,
                        ;; but the symbol string had matched the search pattern,
                        ;; add the symbol string to the result list
                        (setf result-list (cons string result-list)))))))))
        ;; if the result list contains more than one element
        ;; make it become an alphabetically sorted list
        (if (> (length result-list) 1)
            (setf result-list (sort result-list 'string<)))
        ;; print a message according to the search type and pattern
        (cond ((and type (string= type "F")) (setf type "function"))
              ((and type (string= type "V")) (setf type "variable"))
              (t (setf type "symbol")))
        (if (string= pattern "")
            (format t "All ~a names known by Nyquist:~%" type)
            (format t "All ~a names containing pattern ~a:~%" type pattern))
        ;; print the search results
        (cond (result-list
               (let ((list-length (length result-list)))
                 (format t ";; number of symbols: ~a~%" list-length)
                 (dolist (i result-list) (format t "~a~%" i))
                 (if (> list-length 20)
                   (format t ";; number of symbols: ~a~%" list-length))))
              (t (format t "No matches found.")))))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/evaluation.htm0000644000175000000620000000734111512762341023207 0ustar stevestaff Evaluation Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Evaluation


    1. with-errset - evaluate expressions without entering the Break Loop
    2. apply* and funcall* - work also with macros and special forms

    with-errset


    Evaluate an expression without entering the Break Loop on error or cerror:

    (defmacro with-errset (expr &optional (print-flag nil))
      `(progv '(*breakenable*) '(nil)
         (errset ,expr ,print-flag)))
    

    See defmacro, errset, nil, &optional, progv.

    Note: errset does not protect against the break function.

      Back to top


    apply* and funcall*


    In Lisp, macros and special forms are no functions. This means that apply and funcall only work with functions of type SUBR [built-in function] or CLOSURE [functions defined by defun, flet, labels, or lambda], but with macros and special forms a 'bad function' error is signalled. Here are two examples how to work around this behaviour:

    (defun apply* (function args)
      (eval (cons function args)))
    
    (defun funcall* (function args)
      (eval (cons function args)))
    

    Warning: These functions can produce unwanted side-effects because macros and special forms do not need to conform to functional evaluation rules. Use them on your own risk.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/circular-lists.htm0000644000175000000620000000636211512762341024002 0ustar stevestaff Circular Lists Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Circular Lists



    Known XLISP Problems with Circular Lists


    Warning: do not try this with XLISP:

    > (setq my-list (cons 'item nil))  ; create a 1-item list
    (ITEM)
    
    > (setf (cdr my-list) my-list))    ; create the circle
    ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM
    ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM
    ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM
    ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ITEM ...
    

    If you're lucky you can break the loop. If not, then XLISP will print the ITEM forever.

      Back to top


    c-nth


    The 'c-nth' macro accesses a linear list as if it were circular:

    (defmacro c-nth (index list)
      `(nth ,(rem index (length list)) ,list))
    

    Note that with every call to 'c-nth', the length of the list will be computed again.

    Examples:

    (c-nth 0 '(1 2 3))  => 1
    (c-nth 1 '(1 2 3))  => 2
    (c-nth 2 '(1 2 3))  => 3
    (c-nth 3 '(1 2 3))  => 1
    (c-nth 4 '(1 2 3))  => 2
    (c-nth 5 '(1 2 3))  => 3
    (c-nth 6 '(1 2 3))  => 1
    (c-nth 7 '(1 2 3))  => 2
    
    Because 'c-nth' is a macro expanding into a regular nth form, 'c-nth' can be used with setf:
    (setq lst '(1 2 3))      => (1 2 3)
    lst                      => (1 2 3)
    (setf (c-nth 4 lst) 'x)  => X
    lst                      => (1 X 3)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/reader.htm0000644000175000000620000002617411512762341022307 0ustar stevestaff XLISP reader Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Reader



    read-from-string


    (defun read-from-string (string)
      (read (make-string-input-stream string)))
    

      Back to top


    *readtable*


    The *readtable* system variable contains the reader table array. The table is 128 entries [0..127] for each of the 7-bit ASCII characters that XLISP can read.

    See also the Lexical Conventions and Readtable sections in the XLISP 2.0 manual.


    print-readtable


    (defun print-readtable ()
      (dotimes (index 128)
        (format t "ASCII-~a ~a = ~a~%"
                  (cond ((<=  0 index  9) (format nil "00~a" index))
                        ((<= 10 index 99) (format nil "0~a"  index))
                        (t index))
                  (if (< 31 index 127)
                      (code-char index)
                      (case index
                        (0   "[null]                  ")
                        (1   "[start of heading]      ")
                        (2   "[start of text]         ")
                        (3   "[end of text]           ")
                        (4   "[end of transmission]   ")
                        (5   "[enquiry]               ")
                        (6   "[acknowledge]           ")
                        (7   "[terminal bell]         ")
                        (8   "[backspace]             ")
                        (9   "[horizontal tab]        ")
                        (10  "[line feed]             ")
                        (11  "[vertical tab]          ")
                        (12  "[form feed]             ")
                        (13  "[carriage return]       ")
                        (14  "[shift out]             ")
                        (15  "[shift in]              ")
                        (16  "[data link escape]      ")
                        (17  "[device control 1, xon] ")
                        (18  "[device control 2]      ")
                        (19  "[device control 3, xoff]")
                        (20  "[device control 4]      ")
                        (21  "[negative acknowledge]  ")
                        (22  "[synchronous idle]      ")
                        (23  "[end transmission block]")
                        (24  "[cancel line]           ")
                        (25  "[end of medium]         ")
                        (26  "[substitute]            ")
                        (27  "[escape]                ")
                        (28  "[file separator]        ")
                        (29  "[group separator]       ")
                        (30  "[record separator]      ")
                        (31  "[unit separator]        ")
                        (127 "[delete]")))
                  (aref *readtable* index))))
    

    get-macro-character


    (get-macro-character char)
    char - a character
    returns - the code associated with the *readtable* entry or NIL

    (defun get-macro-character (char)
      (if (consp (aref *readtable* (char-code char)))
          (cdr (aref *readtable* (char-int char)))
          nil))
    

    The 'get-macro-character' function returns the code that will be executed when the specified character 'char' is encountered by the XLISP reader.

    The 'get-macro-character' function will return a NIL value if the table entry is NIL , :constituent , :sescape , :mescape or :white-space. If the table entry is :tmacro or :nmacro , then the code associated with the entry is returned. :tmacro is used for a terminating read-macro. :nmacro is used for a non-terminating read-macro. 'get-macro-character' does not differentiate whether the code returned is a :tmacro or an :nmacro.

    The function returned may be a built-in read-macro function or a user defined lambda expression. The function takes two parameters, an input stream specification, and an integer that is the character value. The function should return NIL if the character is 'white-space' or a value consed with NIL to return the value.

    Examples:

    (get-macro-character #\()      => #<Subr-(null): #...>
    (get-macro-character #\#)      => #<Subr-(null): #...>
    (get-macro-character #\Space)  => NIL
    

      Back to Top


    set-macro-character


    (set-macro-character char function [termination-flag])
    char - a character expression
    function - a function definition
    termination-flag - an expression, NIL or non-NIL
    returns - always returns  T 

    (defun set-macro-character (char function &optional terminate-p)
      (setf (aref *readtable* (char-code char))
            (cons (if terminate-p :tmacro :nmacro) function))
      t)
    

    The 'set-macro-character' function installs the code that will be executed when the specified character 'char' is encountered by the XLISP reader.

    The 'set-macro-character' function only allows you to put in a terminating read-macro function :tmacro or a non-terminating read-macro-function :nmacro. If the 'termflag' is present and non-NIL , then the 'function' will be put in *readtable* as a :tmacro entry. If 'termflag' is not present or NIL , then 'function' will be put in *readtable* as a :nmacro entry. The 'function' can be a built-in read-macro function or a user defined defun symbol or a lambda expression.

    The 'function' takes two parameters, an input stream specification, and an integer that is the character value. The 'function' should return NIL if the character is 'white-space' or a value consed with NIL to return the value. The function 'set-macro-character' always returns  T .

    Examples:

    > (print "hi") % comment
    "hi"
    "hi"
    error: unbound variable - %       ; % is interpreted as a variable
    
    > (setq readtable-backup *readtable*)
    #( ... very-long-value ... )
    
    > (set-macro-character #\% (get-macro-character #\;) t)
    T
    
    > (print "hi") % comment
    "hi"                              ; no error because
    "hi"                              ; % is now a comment character
    
    > (setq *readtable* readtable-backup)
    #( ... very-long-value ... )
    

    Important: before manipulating the XLISP *readtable* it's always a good idea to store the original contents in some other variable.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/hexadecimal.htm0000644000175000000620000001107711512762341023305 0ustar stevestaff Hexadecimal Integer Numbers Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Hexadecimal Integer Numbers


    XLISP provides the #x read-macro for hexadecimal numbers:

    #x0  => 0        #x8  => 8         #x10  => 16
    #x1  => 1        #x9  => 9         #x11  => 17
    #x2  => 2        #xa  => 10        #x12  => 18
    #x3  => 3        #xb  => 11        #x13  => 19
    #x4  => 4        #xc  => 12        #x14  => 20
    #x5  => 5        #xd  => 13        #x15  => 21
    #x6  => 6        #xe  => 14        #x16  => 22
    #x7  => 7        #xf  => 15        #x17  => 23
    

    (hex-string integer [all])
    integer - an integer expression
    all - a boolean expression
    returns - the integer in hexadecimal form as string

    (defun hex-string (integer &optional all)
      (if (integerp integer)
          (let ((fmt (if all
                         (or (dolist (bits '(16 32 64 128) nil)
                               (let ((fixnum (round (expt 2.0 (1- bits)))))
                                 (and (plusp (1- fixnum))
                                      (minusp fixnum)
                                      (return (format nil "%.~ax" (/ bits 4))))))
                             (error "integer limit not found"))
                         "%x")))
            (progv '(*integer-format*) (list fmt)
              (format nil "~a" integer)))
          (error "not an integer" integer)))
    

    The 'hex-string' function converts the 'integer' argument into hexadecimal form and returns is as a string. If the optional 'all' argument is not given or NIL, leading zeros are not included in the string. If the optional 'all' argument is non-NIL, all digits of the internal representation of the 'integer' argument, including leading zeros, are contained in the string. This is useful for debugging integer overflow and bit-wise functions.

    (hex integer [all])
    integer - an integer expression
    all - a boolean expression
    prints - the integer in hexadecimal form
    returns - the integer argument

    (defun hex (integer &optional all)
      (if (integerp integer)
          (format t "#x~a~%" (hex-string integer all))
          (format t ";; not an integer~%"))
      integer)
    

    The 'hex' function prints the 'integer' argument in hexadecimal form on the screen. Together with the #x read-macro this can be used for interactive hexadecimal computations.

    > (hex 12345678)
    #xbc614e
    12345678
    
    > (hex (+ #x1f #xa3))
    #xc2
    194
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/0002755000175000000620000000000011537433125022562 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/exp.htm0000644000175000000620000000426711512762341024075 0ustar stevestaff cl:exp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:exp


    The cl:exp function does the same as the Nyquist/XLISP exp function, but also accepts integer numbers as argument:

    (cl:exp power)
    power - an integer or floating-point number
    returns - the result of 'e' [2.7128] to the power of power

    (defun cl:exp (x)
      (exp (float x)))
    

    See defun, exp, float.

    The cl:exp function computes 'e' [2.7128] raised to the specified 'power' and returns the result as a floating-point number.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/remainder-and-modulus.htm0000644000175000000620000000511111512762341027462 0ustar stevestaff Remainder and Modulus Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Remainder and Modulus


    The cl:mod and cl:rem function are generalizations of the modulus and remainder functions.

    • The cl:mod function performs the cl:floor operation on its arguments and returns the remainder of the cl:floor operation.

    • The cl:rem function performs the cl:truncate operation on its arguments and returns the remainder of the cl:truncate operation.

    The cl:mod and cl:rem functions are the modulus and remainder functions when the 'number' and 'divisor' arguments both are integers.

    (mod  13    4)  =>  1          (rem  13    4)  =>  1 
    (mod -13    4)  =>  3          (rem -13    4)  => -1 
    (mod  13   -4)  => -3          (rem  13   -4)  =>  1 
    (mod -13   -4)  => -1          (rem -13   -4)  => -1 
    (mod  13.4  1)  =>  0.4        (rem  13.4  1)  =>  0.4 
    (mod -13.4  1)  =>  0.6        (rem -13.4  1)  => -0.4
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/multiple-value-bind.htm0000644000175000000620000001411211512762341027146 0ustar stevestaff cl:multiple-value-bind Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:multiple-value-bind


    The cl:multiple-value-bind macro creates new bindings for a list of symbols and evaluates expressions that use these bindings:

    (cl:multiple-value-bind symbols values [expr1 ...])
    symbols - a list of symbols
    values - a Lisp expression returning one or more values
    exprN - arbitrary Lisp expressions
    returns - the value[s] returned by the last expression

    (defmacro cl:multiple-value-bind (symbols expr &rest body)
      (and (or (not (consp symbols))
               (eq 'quote (first symbols))
               (dolist (symbol symbols)
                 (or (symbolp symbol) (return t))))
           (error "not a list of symbols" symbols))
      (setq cl:*multiple-values* nil)
      (let* ((result (eval expr))
             (values (if cl:*multiple-values*
                         *rslt*
                         (list result)))
             (number-of-symbols (length symbols))
             (number-of-values  (length values))
             (bindings nil))
        (dotimes (index number-of-symbols)
          (push (if (< index number-of-values)
                    (list (nth index symbols)
                          (list 'quote (nth index values)))
                    (nth index symbols))
                bindings))
        (setq bindings (reverse bindings))
        `(let ,bindings ,@body)))
    

    The 'values' expression is evaluated, and each of the symbols is bound to the respective value returned by the evaluation. If there are more symbols than values returned, extra values of NIL are bound to the remaining symbols. If there are more values than symbols, the extra values are ignored. The symbols are bound to the values by let, behaving like an implicit progn.

    Before evaluating 'expr1', the cl:*multiple-values* variable is  T  if evaluating the 'values' expression returned multiple values and NIL with a normal return value.

    The cl:multiple-value-bind macro binds multiple values to local let variables::

    > (macroexpand-1 '(cl:multiple-value-bind (a b c)
                          (cl:values 1 2 3)
                        (list a b c)))
    (LET ((A (QUOTE 1))
          (B (QUOTE 2))
          (C (QUOTE 3)))
      (LIST A B C))
    

    The quotes are necessary to prevent 'unbound variable' and 'unbound function' errors with symbols and lists.

    Examples:

    1. The cl:multiple-value-bind macro binds values returned by the cl:values function:

    (defun multiple-value-function ()
      (cl:values 1 2 3))  ; multiple return values
    
    > (cl:multiple-value-bind (a b c)
          (multiple-value-function)
        (list a b c))
    (1 2 3)
    

    2. If there are no values returned in the Nyquist *rslt* variable, the normal function return value is bound to the first symbol and all remaining symbols are bound to NIL:

    (defun normal-lisp-function ()
      (+ 1 1))  ; normal return value
    
    > (cl:multiple-value-bind (a b c)
          (normal-lisp-function)
        (list a b c))
    (2 NIL NIL)
    

    3. If there are less values than symbols, the extra symbols are bound to NIL:

    (defun not-enough-values-function ()
      (cl:values 1 2))  ; multiple return values
    
    > (cl:multiple-value-bind (a b c)
          (not-enough-values-function)
        (list a b c))
    (1 2 NIL)
    

    4. If there are more values than symbols, the extra values are ignored:

    (defun too-many-values-function ()
      (cl:values 1 2 3 4 5))  ; multiple return values
    
    > (cl:multiple-value-bind (a b c)
          (too-many-values-function)
        (list a b c))
    (1 2 3)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/expt.htm0000644000175000000620000000546011512762341024255 0ustar stevestaff cl:expt Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:expt


    The cl:expt function computes the result of 'x' to the power of 'y':

    (cl:expt base power)
    base - the base
    power - the exponent
    returns - the result of base to the power of power

    (defun cl:expt (x y)
      (let ((power (expt (float x) y)))
        (if (and (integerp x) (integerp y))
            (round power)
            power)))
    

    See and, defun, expt, float,  if , integerp, let, power, round.

    The cl:expt function accepts integer and floating point numbers as arguments. If both arguments are integer numbers, the result will be an integer number, if one or both arguments are floating-point numbers, the result will be a floating-point number. In contrast to the Nyquist/XLISP expt function, the 'cl:expt' function accepts exactly two arguments.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/rounding-and-truncation.htm0000644000175000000620000001372611512762341030052 0ustar stevestaff Rounding and Truncation Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Rounding and Truncation


    The cl:round, cl:truncate, cl:ceiling and cl:floor functions divide a number by a divisor, returning a quotient and a remainder:

    (cl:round  number [divisor])   ⇒   quotient, remainder
    (cl:truncate  number [divisor])   ⇒   quotient, remainder
    (cl:ceiling  number [divisor])   ⇒   quotient, remainder
    (cl:floor  number [divisor])   ⇒   quotient, remainder

      quotient * divisor + remainder = number

    The 'quotient' always represents a mathematical integer. The 'remainder' is an integer if both 'number' and 'divisor' arguments are integers, and a floating-point number if either the 'number' or the 'divisor' or both are floating-point numbers.

    With Nyquist/XLISP, the 'quotient' is always directly returned by the function, while a list:

    (quotient remainder)
    

    is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to  T  to signal that Multiple Values are returned.

    Examples:
    (cl:round     3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:truncate  3.5)  =>  3  ; *rslt* = ( 3  0.5)
    (cl:ceiling   3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:floor     3.5)  =>  3  ; *rslt* = ( 3  0.5)
    
    (cl:round    -3.5)  => -4  ; *rslt* = (-4  0.5)
    (cl:truncate -3.5)  => -3  ; *rslt* = (-3 -0.5)
    (cl:ceiling  -3.5)  => -3  ; *rslt* = (-3 -0.5)
    (cl:floor    -3.5)  => -4  ; *rslt* = (-4  0.5)
    

    Force an integer division:

    (cl:truncate 3.0 2.0)              => 1  ; Common Lisp
    (/ (truncate 3.0) (truncate 2.0))  => 1  ; Nyquist/XLISP
    (/ 3 2)                            => 1  ; integer division
    

    Implementation Notes

    (defun name (number &optional (divisor (if (integerp number) 1 1.0)))
      ... )
    

    The integerp test in the parameter list signals an error if the 'number' argument is not a number, also the  /  [division] function signals errors if the 'divisor' argument is zero or not a number, so we do not explicitely need to test the arguments.

    The cl:ceiling and cl:floor functions test if 'number' is an integer multiple of 'divisor' by comparing the results of an integer division and a floating-point division:

    (let ((i-quotient (/ (truncate number) (truncate divisor)))
          (f-quotient (/ (float number) divisor)))
      (if (= i-quotient f-quotient)
            ...
    

    I'm not sure if this really catches all cases [e.g. regarding floating point precision], but have found no problems so far.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/mod.htm0000644000175000000620000000533711512762341024057 0ustar stevestaff cl:mod Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:mod


    (cl:mod number divisor)
    number - an integer or floating-point number
    divisor - an integer or floating-point number
    returns - the remainder of a cl:floor operation

    (defun cl:mod (number divisor)
      (if (= (abs number) (abs divisor))
          (if (and (integerp number) (integerp divisor)) 0 0.0)
          (let* ((i-quotient (/ (truncate number) (truncate divisor)))
                 (f-quotient (/ (float number) divisor))
                 (quotient (if (or (= i-quotient f-quotient)  ; integer result
                                   (not (minusp f-quotient)))
                               (truncate f-quotient)
                               (1- (truncate f-quotient)))))
            (- number (* quotient divisor)))))
    

    The cl:mod function performs the cl:floor operation on its arguments and returns the remainder of the cl:floor operation. The result is either zero or an integer or floating-point number with the same sign as the 'divisor' argument. If both arguments are integer numbers, the cl:mod function is equal to the mathematical modulus function.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/numbers.htm0000644000175000000620000000442011512762341024743 0ustar stevestaff Numbers Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Numbers


    1. Number Types
    2. Integer Limits

    Number Types


    In Nyquist/XLISP only two types of numers exist:

    • fixnum - integer numbers
    • flonum - floating-point numbers

    In Nyquist/XLISP, there are no ratios or complex numbers. Even if the math functions in this section are modelled after Common Lisp, no attempt is made to emulate these numbers.


    Integer Limits


    (setq *most-positive-fixnum*  2147483647)
    (setq *most-negative-fixnum* -2147483648)
    

    Note: these are the limits for 32-bit machines.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/global-multiple-values.htm0000644000175000000620000000750211512762341027662 0ustar stevestaff cl:*multiple-values* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:*multiple-values*


    The cl:*multiple-values* variable is used to signal if a function has returned multiple values:

    cl:*multiple-values*
    returns -  T  if a function returned multiple values

    Test if a function has returned multiple values:

    (setf cl:*multiple-values* nil)
    (let ((result (function ...)))
      (if cl:*multiple-values*
          (do-something-with *rslt* ...)
          (do-something-with result ...))
      ... )
    

    Do not use cl:*multiple-values* with let like this:

    (let ((cl:*multiple-values* nil)
          (result (function ...)))
      (if cl:*multiple-values*
          (do-something-with *rslt* ...)
          (do-something-with result ...))
      ... )
    

    This doesn't work because 'function' is evaluated in the global XLISP environment, where the lexical let binding of the cl:*multiple-values* variable does not exist, while the  if  form inside the let form cannot see a global change of the cl:*multiple-values* variable, because the global value is shadowed by the lexical let binding. See Environment for more details about variables.

    The XLISP progv special form can be used to encapsulate a multiple value call while automatically restoring the old values at the end like this:

    (values 1 2 3)        => 1
    
    cl:*multiple-values*  => T
    *rslt*                => (1 2 3)
    
    (progv '(cl:*multiple-values* *rslt*) '(nil nil)
      (let ((result (function ...)))
        (if cl:*multiple-values*
            (do-something-with *rslt* ...)
            (do-something-with result ...))))
    
    cl:*multiple-values*  => T
    *rslt*                => (1 2 3)
    

    Note: All functions returning multiple values set cl:*multiple-values* to  T , but it's up to the Lisp programmer to reset the variable to NIL.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/floor.htm0000644000175000000620000001137611512762341024421 0ustar stevestaff cl:floor Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:floor


    The cl:floor function truncates an integer or floating-point number toward negative infinity:

    (cl:floor number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of truncating the result of number divided by divisor
     -  the remainder of the truncate operation

    (defun cl:floor (number &optional (divisor
                                      (if (integerp number) 1 1.0)
                                      divisor-p))
      (let ((quotient
              (cond ((and (not divisor-p) (integerp number)) number)
                    ((= number divisor) 1)
                    (t (let ((i-quotient (/ (truncate number) (truncate divisor)))
                             (f-quotient (/ (float number) divisor)))
                         (if (or (= i-quotient f-quotient)  ; integer result
                                 (not (minusp f-quotient)))
                              (truncate f-quotient)
                              (1- (truncate f-quotient))))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The cl:floor function computes a quotient that has been truncated toward negative infinity. That is, the quotient represents the largest mathematical integer that is not larger than the mathematical quotient.

    The quotient is directly returned by the function, while a list:

    (quotient remainder)
    

    is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to  T  to signal that Multiple Values are returned.

    See Rounding and Truncation for more details.

    Examples:

    (cl:floor  3.5)  =>  3  ; *rslt* => ( 3 0.5)
    (cl:floor -3.5)  => -4  ; *rslt* => (-4 0.5)
    

    See also:

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/multiple-values.htm0000644000175000000620000001574211512762341026431 0ustar stevestaff Multiple Values Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Multiple Values


    1. Multiple Values

    Multiple Values


    This is a port of the Common List framework for passing multiple values from one place to another. It is most often used to return multiple values from a function with cl:values or to bind multiple values to multiple variables with cl:multiple-value-bind or cl:multiple-value-setq.

    The multiple value functions and macros use the Nyquist/XLISP *rslt* variable to store the values as a list, while the cl:*multiple-values* variable is used as a flag to indicate if a function has returned multiple values.

    What happens if a normal Lisp function are given multiple values?

    A normal Lisp function only sees the 'primary' return value, as returned by every Lisp function. The additional return values [including the primary return value] are stored in the *rslt* variable and are only read by the multiple value functions. This also means that with multiple values, the most important value should always be returned as the first value, because only the first value can be seen by a normal Lisp function. See cl:values for examples.

    What happens if a function expecting multiple values is given a normal Lisp return value?

    The first symbol will be set to the function's return value, while all other symbol will be set to NIL. No symbol will be left unset. All functions expecting multiple values are protected against a wrong number of values. If there are more symbols than values, then the extra symbols are set to NIL, if there are more values than symbols, the extra values will be ignored.

    Known Limitations

    1. In Nyquist/XLISP, cl:values cannot be used as argument to setf. But this is not a real problem, because the values are stored as a simple list in the *rslt* variable, where they can be manipulated with any arbitrary Lisp functions, not only with setf.

    2. In Common Lisp there exists the option to return 'no value' by calling the 'values' function with no arguments. In Nyquist/XLISP there is no built-in way to return 'no value' from a function. The symbol *unbound* cannot be used for this because in Common Lisp, if 'no value' is assigned to a symbol as variable value, the new value will be NIL and not *unbound*.

    In Nyquist/XLISP, the cl:values function, if called with no arguments, always returns NIL, and the *rslt* variable will be set to NIL, too:

    (cl:values)      => NIL  ; *rslt* = NIL
    (cl:values nil)  => NIL  ; *rslt* = (NIL)
    

    Maybe this observation helps to write a 'no values' test if anybody really needs it.

    3. Neither in Common Lisp nor in Nyquist/XLISP is it possibe to return nested multiple values:

    (cl:values (1 (cl:values 2 3) 4)  => 1  ; *rslt* = (1 2 4)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/equalp.htm0000644000175000000620000001261311512762341024562 0ustar stevestaff cl:equalp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:equalp


    (equalp expr1 expr2)
    exprN - arbitrary Lisp expressions
    returns -  T  if the expressions are structurally equal, NIL otherwise

    Two expressions are 'equalp':

    • If the expressions are equal.

    • If two numbers of arbitrary type are  = .

    • If two characters are char-equal.

    • If two strings are string-equal.

    • If the two cars in conses are 'equalp' and the two cdrs in conses are 'equalp'.

    • If two arrays have the same number of elements and dimensions, and the corresponding elements in all dimensions are 'equalp'.

    Note that only 'equalp' can compare arrays.

    (defun cl:equalp (expr-1 expr-2)
      (or (equal expr-1 expr-2)
          (and (numberp expr-1) (numberp expr-2) (= expr-1 expr-2))
          (let ((type (type-of expr-1)))
            (when (eq type (type-of expr-2))
              (case type
                (character (char-equal expr-1 expr-2))
                (string    (string-equal expr-1 expr-2))
                (cons      (do ((x (first expr-1)
                                   (if (consp expr-1) (first expr-1) expr-1))
                                (y (first expr-2)
                                   (if (consp expr-2) (first expr-2) expr-2)))
                               ((or (null expr-1)
                                    (null expr-2)
                                    (not (equalp x y)))
                                (and (null expr-1)
                                     (null expr-2)))
                             (setq expr-1 (and (consp expr-1) (rest expr-1))
                                   expr-2 (and (consp expr-2) (rest expr-2)))))
                (array     (let ((end (length expr-1)))
                             (when (eql end (length expr-2))
                               (dotimes (index end t)
                                 (and (not (equalp (aref expr-1 index)
                                                   (aref expr-2 index)))
                                      (return nil)))))))))))
    

    cons: do is used instead of recursion because XLISP has only two kilobytes stack size. The (consp expr) tests are necessary because in a dotted list the last rest element is not a cons.

    Examples:

    (cl:equalp 1 1.0)                            => T
    (cl:equalp #\a #\A)                          => T
    (cl:equalp "Abc" "aBc")                      => T
    (cl:equalp '(1 #\a "Abc") '(1.0 #\A "aBc"))  => T
    (cl:equalp #(1 #\a "Abc") #(1.0 #\A "aBc"))  => T
    

    Nested expressions only match if the nesting matches:

    (cl:equalp '(1 (2 3)) '(1.0 (2.0 3.0))  => T
    (cl:equalp '(1 (2 3)) '((1.0 2.0) 3.0)  => NIL
    (cl:equalp '((1 2) 3) '((1.0 2.0) 3.0)  => T
    (cl:equalp '((1 2) 3) '(1.0 (2.0 3.0))  => NIL
    

    A character does not match a string with the same character:

    (cl:equalp #\a "a")  => NIL
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/round.htm0000644000175000000620000001032311512762341024416 0ustar stevestaff cl:round Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:round


    The cl:round function truncates an integer or floating-point number toward the next integer:

    (cl:round number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of runding the result of number divided by divisor
     -  the remainder of the round operation

    (defun cl:round (number &optional (divisor
                                      (if (integerp number) 1 1.0)
                                      divisor-p))
      (let* ((x (/ (float number) divisor))
             (quotient (cond ((and (not divisor-p) (integerp number)) number)
                             ((= number divisor) 1)
                             ((plusp x) (truncate (+ x 0.5)))
                             ((= (- x 0.5) (truncate (- x 0.5)))
                              (if (minusp x)
                                  (1- (truncate x))
                                  (truncate x)))
                             (t (truncate (- x 0.5))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The cl:round function computes a quotient that has been rounded to the nearest mathematical integer. If the mathematical quotient is exactly halfway between two integers, [that is, it has the form 'integer+1/2'], then the quotient has been rounded to the even [divisible by two] integer.

    The quotient is directly returned by the function, while a list:

    (quotient remainder)
    

    is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to  T  to signal that Multiple Values are returned.

    See Rounding and Truncation for more details.

    Examples:

    (round  3.5)     =>  4
    (round -3.5)     => -3
    
    (cl:round  3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:round -3.5)  => -4  ; *rslt* = (-4  0.5)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/multiple-value-setq.htm0000644000175000000620000001640611512762341027216 0ustar stevestaff cl:multiple-value-setq Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:multiple-value-setq


    The cl:multiple-value-setq macro assigns multiple values to multiple variables:

    (cl:multiple-value-setq symbols expr)
    symbols - a list of symbols
    expr - a Lisp expression returning one or more values
    returns - the primary value returned by evaluating the expression

    (defmacro cl:multiple-value-setq (symbols expr)
      (and (or (not (consp symbols))
               (eq 'quote (first symbols))
               (dolist (symbol symbols)
                 (or (symbolp symbol) (return t))))
           (error "not a list of symbols" symbols))
      (setq cl:*multiple-values* nil)
      (let* ((result (eval expr))
             (values (if cl:*multiple-values*
                         *rslt*
                         (list result)))
             (number-of-symbols (length symbols))
             (number-of-values  (length values))
             (assignments (list 'setq)))
        (dotimes (index number-of-symbols)
          (push (nth index symbols) assignments)
          (push (when (< index number-of-values)
                  (list 'quote (nth index values)))
                assignments))
        (setq assignments (reverse assignments))
        `(progn ,assignments ',result)))
    

    The expression is evaluated, and each symbol is assigned to the corresponding value returned by the evaluation. If there are more symbols than values returned, NIL is assigned to the extra symbols. If there are more values than symbols, the extra values are discarded.

    The cl:*multiple-values* variable is  T  if evaluating the expression returns multiple values and NIL with a normal return value.

    The cl:multiple-value-setq macro assigns multiple values to multiple variables using setq:

    > (macroexpand-1 '(cl:multiple-value-setq (a b c)
                        (cl:values 1 2 3)))
    (PROGN (SETQ A (QUOTE 1)
                 B (QUOTE 2)
                 C (QUOTE 3))
           (QUOTE 1))
    

    The quotes are necessary to prevent 'unbound variable' and 'unbound function' errors with symbols and lists.

    Examples:

    1. The cl:multiple-value-setq macro assigns values returned by the cl:values function:

    (defun multiple-value-function ()
      (cl:values 1 2 3))  ; multiple return values
    
    > (let ((a 'A) (b 'B) (c 'C))
        (cl:multiple-value-setq (a b c)
          (multiple-value-function))
        (list a b c))
    (1 2 3)
    

    2. If there are no values returned in the Nyquist *rslt* variable, the normal function return value is assigned to the first symbol and all remaining symbols are assigned to NIL:

    (defun normal-lisp-function ()
      (+ 1 1))  ; normal return value
    
    > (let ((a 'A) (b 'B) (c 'C))
        (cl:multiple-value-setq (a b c)
          (normal-lisp-function))
        (list a b c))
    (2 NIL NIL)
    

    3. If there are less values than symbols, the extra symbols are assigned to NIL:

    (defun not-enough-values-function ()
      (cl:values 1 2))  ; multiple return values
    
    > (let ((a 'A) (b 'B) (c 'C))
        (cl:multiple-value-setq (a b c)
          (not-enough-values-function))
        (list a b c))
    (1 2 NIL)
    

    4. If there are more values than symbols, the extra values are ignored:

    (defun too-many-values-function ()
      (cl:values 1 2 3 4 5))  ; multiple return values
    
    > (let ((a 'A) (b 'B) (c 'C))
        (cl:multiple-value-setq (a b c)
          (too-many-values-function))
        (list a b c))
    (1 2 3)
    

    5. Symbols not contained in the cl:multiple-value-setq symbol-list are not changed:

    (defun multiple-value-function ()
      (cl:values 1 2 3))  ; multiple return values
    
    > (let ((a 'A) (b 'B) (c 'C) (d 'D) (e 'E))
        (cl:multiple-value-setq (a b c)
          (multiple-value-function))
        (list a b c d e))
    (1 2 3 D E)
    

    5. If no bindings exist, new variables will be created:

    (defun multiple-value-function ()
      (cl:values 1 2 3))  ; multiple return values
    
    > (let ((c 'C) (d 'D) (e 'E))
        (cl:multiple-value-setq (a b c)
          (multiple-value-function))
        (list a b c d e))
    (1 2 3 D E)
    

    Caution: In the last example, two global variables 'a' and 'b' were created, while the lexical let variable 'c' was assigned to the value 3:

    > (list a b)
    (1 2)
    
    > (list a b c)
    error: unbound variable - C
    

    The lexical let binding of 'c' does not exist in the global top-level. See Environment for more details about variables.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/multiple-value-call.htm0000644000175000000620000000635611512762341027160 0ustar stevestaff cl:multiple-value-call Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:multiple-value-call


    The cl:multiple-value-call macro applies a function to a list of return values:

    (cl:multiple-value-call function [expr1 ...])
    function - a Lisp expression evaluating to a function call
    exprN - arbitrary Lisp expressions
    returns - the values returned by the function

    (defmacro cl:multiple-value-call (function &rest exprs)
      (let (args)
        (dolist (expr exprs)
          (setq  cl:*multiple-values* nil)
          (let* ((result (eval expr)))
            (if cl:*multiple-values*
                (dolist (rslt *rslt*) (push rslt args))
                (push result args))))
        (setq args (reverse args))
        `(progn
           (setq cl:*multiple-values* nil)
           (apply ,function ',args)))
    

    The cl:multiple-value-call macro first evaluates the expressions and collects all return values in a single list, then the 'function' form is evaluated and the resulting function call is applied to the list of values.

    Before applying the function to the list of values the cl:*multiple-values* variable is set to NIL, the final value of cl:*multiple-values* depends on the 'function' argument.

    Examples:

    > (funcall #'+
        (cl:values 1 2)
        (cl:values 3 4))
    4  ; (apply #'+ (1 3))
    
    > (cl:multiple-value-call #'+
        (cl:values 1 2)
        (cl:values 3 4))
    10  ; (apply #'+ (1 2 3 4))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/values-list.htm0000644000175000000620000000654511512762341025552 0ustar stevestaff cl:values-list Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:values-list


    The cl:values-list function returns the elements of a list unevaluated as multiple values:

    (cl:values-list list)
    list - a list of values
    returns - the elements of the list as multiple values

    (defun cl:values-list (list)
      (or (listp list) (error "not a list" list))
      (or (null list) (consp (last list)) (error "not a proper list" list))
      (setq *rslt* list
            cl:*multiple-values* t)
      (first list))
    

    The unevaluated first value from the list is returned as the primary return value, and the list is assigned to the Nyquist *rslt* variable. If an an empty list is given, NIL is returned and the *rslt* variable is set to NIL. An error is signalled if the 'list' argument is not a list or if the list does not end with NIL.

    The cl:*multiple-values* variable is set to  T  to indicate that multiple values are returned.

    Examples:

    (cl:values-list nil)         => NIL  ; *rslt* = NIL
    (cl:values-list '(1))        => 1    ; *rslt* = (1)
    (cl:values-list '(1 2))      => 1    ; *rslt* = (1 2)
    (cl:values-list '(1 2 3))    => 1    ; *rslt* = (1 2 3)
    (cl:values-list '(1 2 . 3))  => error: not a proper list - (1 2 . 3)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/sqrt.htm0000644000175000000620000000420411512762341024261 0ustar stevestaff cl:sqrt Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:sqrt


    The cl:sqrt function does the same as the Nyquist/XLISP sqrt function, but also accepts integer numbers as argument:

    (cl:sqrt number)
    number - an integer or floating-point number
    returns - the square root of number

    (defun cl:sqrt (x)
      (sqrt (float x)))
    

    See defun, float, sqrt.

    The cl:sqrt function computes the square root of its argument and returns the result. as a floating-point number.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/values.htm0000644000175000000620000001225611512762341024575 0ustar stevestaff cl:values Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:values


    The cl:values function evaluates all given Lisp expressions and returns the results as multiple values:

    (cl:values [expr1 ...])
    exprN - an arbitrary Lisp expression
    returns - the results of evaluating the expressions, as multiple values

    (defun cl:values (&rest exprs)
      (setq *rslt* exprs
            cl:*multiple-values* t)
      (first exprs))
    

    The primary return value [the result from evaluating the first expression] is returned by the cl:values function and a list with the results of evaluating all expressions is assigned to the Nyquist *rslt* variable. If no expressions are given, NIL is returned and the *rslt* variable is set to NIL.

    The cl:*multiple-values* variable is set to  T  to indicate that multiple values are returned.

    Examples:

    (cl:values 1 2 3)  => 1        ; primary value
    *rslt*             => (1 2 3)  ; all values
    
    (cl:values 'a 'b)  => A        ; primary value
    *rslt*             => (A B)    ; all values
    
    > (cl:multiple-value-bind (a b c)
          (cl:values 1 2 3)
        (list a b c))
    (1 2 3)
    

    See cl:multiple-value-bind, list, *rslt*.

    Known Limitations

    1. In Nyquist/XLISP, cl:values cannot be used as argument to setf. But this is not a real problem, because the values are stored as a simple list in the *rslt* variable, where they can be manipulated with any arbitrary Lisp functions, not only with setf.

    2. In Common Lisp there exists the option to return 'no value' by calling the 'values' function with no arguments. In Nyquist/XLISP there is no built-in way to return 'no value' from a function. The symbol *unbound* cannot be used for this because in Common Lisp, if 'no value' is assigned to a symbol as variable value, the new value will be NIL and not *unbound*.

    In Nyquist/XLISP, the cl:values function, if called with no arguments, always returns NIL, and the *rslt* variable will be set to NIL, too:

    (cl:values)      => NIL    ; primary value
    *rslt*           => NIL    ; all values
    
    (cl:values nil)  => NIL    ; primary value
    *rslt*           => (NIL)  ; all values
    

    Maybe this observation helps to write a 'no values' test if anybody really needs it.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/ceiling.htm0000644000175000000620000001022311512762341024700 0ustar stevestaff cl:ceiling Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:ceiling


    The cl:ceiling function truncates an integer or floating-point number toward positive infinity:

    (cl:ceiling number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of truncating the result of number divided by divisor
     -  the remainder of the truncate operation

    (defun cl:ceiling (number &optional (divisor
                                        (if (integerp number) 1 1.0)
                                        divisor-p))
      (let ((quotient
              (cond ((and (not divisor-p) (integerp number)) number)
                    ((= number divisor) 1)
                    (t (let ((i-quotient (/ (truncate number) (truncate divisor)))
                             (f-quotient (/ (float number) divisor)))
                         (if (or (= i-quotient f-quotient)  ; integer result
                                 (not (plusp f-quotient)))
                              (truncate f-quotient)
                              (1+ (truncate f-quotient))))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The cl:ceiling function computes a quotient that has been truncated toward positive infinity. That is, the quotient represents the smallest mathematical integer that is not smaller than the mathematical result.

    The quotient is directly returned by the function, while a list:

    (quotient remainder)
    

    is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to  T  to signal that Multiple Values are returned.

    See Rounding and Truncation for more details.

    Examples:

    (cl:ceiling  3.5)  =>  4  ; *rslt* => ( 4 -0.5)
    (cl:ceiling -3.5)  => -3  ; *rslt* => (-3 -0.5)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/multiple-value-prog1.htm0000644000175000000620000000613611512762341027271 0ustar stevestaff cl:multiple-value-prog1 Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:multiple-value-prog1


    The cl:multiple-value-prog1 macro is like prog1, but it can handle multiple values:

    (cl:multiple-value-prog1 expr1 [expr2 ...])
    exprN - arbitrary Lisp expressions
    returns - the values returned by the first expression

    (defmacro cl:multiple-value-prog1 (expr &rest body)
      (setq cl:*multiple-values* nil)
      (let* ((result (eval expr)))
        (if cl:*multiple-values*
            `(progn ,@body
                    (setq *rslt* ',*rslt*
                          cl:*multiple-values* t)
                    ',result)
            `(progn ,@body ',result))))
    

    The cl:multiple-value-prog1 macro evaluates the first expression and saves all the values returned by the evaluation. It then evaluates each of the following expressions from left to right, discarding their values. After the evaluation is finished, the cl:*multiple-values* and *rslt* variables are restored and the primary value from evaluating the fist expression is returned.

    The cl:*multiple-values* variable is  T  if evaluating the first expression returns multiple values and NIL with a normal return value.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/debug-mv.htm0000644000175000000620000000574311512762341025007 0ustar stevestaff cl:debug:mv Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:debug:mv


    (cl:debug:mv expr
    expr - a Lisp expression, returning an arbitrary number of values
    returns - the normal Lisp return value from evaluating expr

    (defun cl:debug:mv (expr)
      (setq cl:*multiple-values* nil)
      (let ((result (eval expr)))
        (format t ";; cl:*multiple-values* => ~a~%" cl:*multiple-values*)
        (format t ";; *rslt* => ~a~a~%" *rslt*
                  (if cl:*multiple-values* "" " [invalid]"))
        result))
    

    The cl:debug:mv function first sets the cl:*multiple-values* variable to NIL, then it evaluates the expression. After evaluation it prints the values of the cl:*multiple-values* and *rslt* variables and returns the normal Lisp return value from the evaluation.

    Example:

    > (cl:debug:mv '(cl:values 1 2 3))
    ;; cl:*multiple-values* => T
    ;; *rslt* => (1 2 3)
    1
    
    > (cl:debug:mv 1)
    ;; cl:*multiple-values* => NIL
    ;; *rslt* => (1 2 3) [invalid]
    1
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/multiple-value-list.htm0000644000175000000620000000646311512762341027217 0ustar stevestaff cl:multiple-value-list Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:multiple-value-list


    The cl:multiple-value-list macro evaluates a Lisp expression and returns all values in a list:

    (cl:multiple-value-list expr)
    expr - an arbitrary Lisp expression
    returns - all values in a list

    (defmacro cl:multiple-value-list (expr)
      (setq cl:*multiple-values* nil)
      (let ((result (eval expr)))
        (if cl:*multiple-values*
            '*rslt*
            `(list ,result))))
    

    The cl:multiple-value-list macro first evaluates the expression. If the evaluation returned multiple values, the value of the *rslt* variable is returned, otherwise the normal Lisp return value is returned in a list of one element.

    The cl:*multiple-values* variable is  T  if evaluating the expression returns multiple values and NIL with a normal return value.

    Examples:

    (cl:multiple-value-list 1)  => (1)      ; cl:*multiple-values* => NIL
                                            ; *rslt* => [invalid]
    (cl:multiple-value-list
      (+ 1 1))                  => (2)      ; cl:*multiple-values* => NIL
                                            ; *rslt* => [invalid]
    (cl:multiple-value-list
      (cl:values 1 2 3))        => (1 2 3)  ; cl:*multiple-values* => T
                                            ; *rslt* => (1 2 3)
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/truncate.htm0000644000175000000620000000753611512762341025130 0ustar stevestaff cl:truncate Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:truncate


    The cl:truncate function truncates an integer or floating-point number toward zero:

    (cl:truncate number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of truncating the result of number divided by divisor
     -  the remainder of the truncate operation

    (defun cl:truncate (number &optional (divisor (if (integerp number) 1 1.0)))
      (let ((quotient (truncate (/ (float number) divisor))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The cl:truncate function computes a quotient that has been truncated towards zero. That is, the quotient represents the mathematical integer of the same sign as the mathematical quotient, and that has the greatest integral magnitude not greater than that of the mathematical quotient.

    The quotient is directly returned by the function, while a list:

    (quotient remainder)
    

    is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to  T  to signal that Multiple Values are returned.

    See Rounding and Truncation for more details.

    Examples:

    (cl:truncate  3.5)  =>  0  ; *rslt* => ( 3  0.5)
    (cl:truncate -3.5)  => -3  ; *rslt* => (-3 -0.5)
    

    Force an integer division:

    (cl:truncate 3.1 2.6)  => 1  ; *rslt* => (1 0.5)
    (/ 3 2)                => 1
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/log.htm0000644000175000000620000000464311512762341024060 0ustar stevestaff cl:log Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:log


    The cl:log function does the same as the Nyquist/XLISP log function, but also accepts integer numbers and has an optional 'base' argument:

    (cl:log number [base])
    number - an integer or floating-point number
    base - an integer or floating-point number
    returns - the the logarithm of number in base base

    (defun cl:log (number &optional base)
      (if base
          (if (zerop base)
              0.0
              (/ (log (float number)) (log (float base))))
          (log (float number))))
    

    The 'cl:log' function returns the logarithm of 'number' in base 'base'. If 'base' is not supplied its value is 'e', the base of the natural logarithms. If the 'base' argument is zero, then 'cl:log' returns zero. The result is always a floating-point number.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp/rem.htm0000644000175000000620000000464711512762341024066 0ustar stevestaff cl:rem Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cl:rem


    (cl:rem number divisor)
    number - an integer or floating-point number
    divisor - an integer or floating-point number
    returns - the remainder of a cl:truncate operation

    (defun cl:rem (number divisor)
      (if (= (abs number) (abs divisor))
          (if (and (integerp number) (integerp divisor)) 0 0.0)
          (let ((quotient (truncate (/ (float number) divisor))))
            (- number (* quotient divisor)))))
    

    The cl:rem function performs the cl:truncate operation on its arguments and returns the remainder of the cl:truncate operation. The result is either zero or an integer or floating-point number with the same sign as the 'number' argument. If both arguments are integer numbers, the cl:rem function is equal to the mathematical remainder function.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/posix-chars.htm0000644000175000000620000004014411512762341023276 0ustar stevestaff Characters and Strings Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    POSIX Character Classes


    1. POSIX Character Classes
    2. Internal Functions
    3. User Functions

    POSIX Character Classes


    The functions on this page implement tests for the standard POSIX character classes, where all functions return the tested character if the test succeeds, or NIL if the test fails.

    The built-in XLISP character test functions upper-case-p, lower-case-p, both-case-p, alphanumericp, return the boolean values  T  or NIL instead of the tested character, while digit-char-p returns an integer or NIL, what is handy if you want to convert arbitrary Lisp symbols into numbers without producing an error, but all this is impractical for writing a string parser.

    The Internal Functions do not check if the argument is a character and therefore are faster than the User Functions. Also note that XLISP is limited to ASCII characters, so there is no way to find out if an unicode character is upper- or lowercase if the character code is greater than ASCII 127.

       POSIX   -   Internal   -   User Function
       [: alnum :]   -   char:alnum-p   -   alnum-character-p   -  alphanumeric = [a-z], [A-Z], [0-9]
       [: alpha :]   -   char:alpha-p   -   alpha-character-p   -  alphabetic = [a-z], [A-Z]
       [: blank :]   -   char:blank-p   -   blank-character-p   -  space and horizontal-tab
       [: cntrl :]   -   char:cntrl-p   -   cntrl-character-p   -  code-chars 0-31 and 127
       [: digit :]   -   char:digit-p   -   digit-character-p   -  decimal = [0-9]
       [: graph :]   -   char:graph-p   -   graph-character-p   -  graphical = alnum + punct
       [: lower :]   -   char:lower-p   -   lower-character-p   -  lowercase = [a-z]
       [: print :]   -   char:print-p   -   print-character-p   -  printable = alnum + punct + space
       [: punct :]   -   char:punct-p   -   punct-character-p   -  punctuation marks
       [: space :]   -   char:space-p   -   space-character-p   -  characters producing whitespace
       [: upper :]   -   char:upper-p   -   upper-character-p   -  uppercase = [A-Z]
       [: xdigit :]   -   char:xdigit-p   -   xdigit-character-p   -  hexadecimal = [0-9], [a-f], [A-F]

    The main difference is:

    > (char:alnum-p 'nonsense-value)
    error: bad argument type - NONSENSE-VALUE
    
    > (alnum-character-p 'nonsense-value)
    NIL
    

      Back to top


    Internal Functions


    The internal functions are based on built-in XLISP functions, there are no external dependencies.

    ;; alphanumeric characters = a-z, A-z, 0-9
    
    (defun char:alnum-p (char)
      (and (alphanumericp char)
           char))
    
    ;; alphabetic characters = a-z, A-Z
    
    (defun char:alpha-p (char)
      (and (both-char-p char)
           char))
    
    ;; blanks = space and horizontal-tab
    
    (defun char:blank-p (char)
      (and (or (char= char #\Space)
               (char= char #\Tab))
           char))
    
    ;; control characters = code-chars 0-31 and 127
    
    (defun char:cntrl-p (char)
      (let ((code (char-code char)))
        (and (or (<= 0 code 31)
                 (= code 127))
             char)))
    
    ;; decimal digits = 0-9
    
    (defun char:digit-p (char)
      (and (digit-char-p char)
           char))
    
    ;; graphical characters = alnum + punct
    
    (defun char:graph-p (char)
      (and (<= 33 (char-code char) 126)
           char))
    
    ;; lowercase characters = a-z
    
    (defun char:lower-p (char)
      (and (lower-case-p char)
           char))
    
    ;; printable characters = alnum + punct + space
    
    (defun char:print-p (char)
      (and (<= 32 (char-code char) 126)
           char))
    
    ;; punctuation marks
    
    (defun char:punct-p (char)
      (let ((code (char-code char)))
        (and (or (<=  33 code  47)   ;  ! " # $ % & ' ( ) * + , - . /
                 (<=  58 code  64)   ;  : ; < = > ? @
                 (<=  91 code  96)   ;  [ \ ] ^ _ `
                 (<= 123 code 126))  ;  { | } ~
             char)))
    
    ;; characters producing whitespace
    ;;
    ;;  9 = horizontal tab   10 = line feed         11 = vertical tab
    ;; 12 = form feed        13 = carriage return   32 = space
    
    (defun char:space-p (char)
      (and (member (char-code char) '(9 10 11 12 13 32))
           char))
    
    ;; uppercase characters = A-Z
    
    (defun char:upper-p (char)
      (and (upper-case-p char)
           char))
    
    ;; hexadecimal digits = 0-9, a-f, A-F
    
    (defun char:xdigit-p (char)
      (and (or (digit-char-p char)
               (let ((code (char-code char)))
                 (or (<= 65 code  70)     ; A-Z
                     (<= 97 code 102))))  ; a-z
           char))
    

      Back to top


    User Functions


    The user functions are based on the Internal Functions above. There are no other dependencies.

    ;; alphanumeric characters = a-z, A-z, 0-9
    
    (defun alnum-character-p (char)
      (and (characterp char)
           (char:alnum-p char)))
    
    ;; alphabetic characters = a-z, A-Z
    
    (defun alpha-character-p (char)
      (and (characterp char)
           (char:alpha-p char)))
    
    ;; blanks = space and horizontal-tab
    
    (defun blank-character-p (char)
      (and (characterp char)
           (char:blank-p char)))
    
    ;; control characters = code-chars 0-31 and 127
    
    (defun cntrl-character-p (char)
      (and (characterp char)
           (char:cntrl-p char)))
    
    ;; decimal digits = 0-9
    
    (defun digit-character-p (char)
      (and (characterp char)
           (char:digit-p char)))
    
    ;; graphical characters = alnum + punct
    
    (defun graph-character-p (char)
      (and (characterp char)
           (char:graph-p char)))
    
    ;; lowercase characters = a-z
    
    (defun lower-character-p (char)
      (and (characterp char)
           (char:lower-p char)))
    
    ;; printable characters = alnum + punct + space
    
    (defun print-character-p (char)
      (and (characterp char)
           (char:print-p char)))
    
    ;; punctuation marks
    
    (defun punct-character-p (char)
      (and (characterp char)
           (char:punct-p char)))
    
    ;; characters producing whitespace
    
    (defun space-character-p (char)
      (and (characterp char)
           (char:space-p char)))
    
    ;; uppercase characters = A-Z
    
    (defun upper-character-p (char)
      (and (characterp char)
           (char:upper-p char)))
    
    ;; hexadecimal digits = 0-9, a-f, A-F
    
    (defun xdigit-character-p (char)
      (and (characterp char)
           (char:xdigit-p char)))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/binary.htm0000644000175000000620000001147311512762341022325 0ustar stevestaff Binary Integer Numbers Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Binary Integer Numbers


    XLISP provides the #b read-macro for binary numbers:

    #b0    => 0       #b1000  => 8        #b100000  => 16
    #b1    => 1       #b1001  => 9        #b100001  => 17
    #b10   => 2       #b1010  => 10       #b100010  => 18
    #b11   => 3       #b1011  => 11       #b100011  => 19
    #b100  => 4       #b1100  => 12       #b100100  => 20
    #b101  => 5       #b1101  => 13       #b100101  => 21
    #b110  => 6       #b1110  => 14       #b100110  => 22
    #b111  => 7       #b1111  => 15       #b100111  => 23
    

    (bin-string integer [all])
    integer - an integer expression
    all - a boolean expression
    returns - the integer in binary form as string

    (defun bin-string (integer &optional all)
      (if (integerp integer)
          (let ((digits (or (dolist (bits '(16 32 64 128) nil)
                              (let ((fixnum (round (expt 2.0 (1- bits)))))
                                (and (plusp (1- fixnum))
                                     (minusp fixnum)
                                     (return bits))))
                            (error "integer limit not found")))
                (string ""))
            (dotimes (x digits)
              (let ((digit (logand (round (expt 2.0 x)) integer)))
                (setq string (strcat (if (zerop digit) "0" "1") string))))
            (format nil "~a" (if all string (string-left-trim "0" string))))
          (error "not an integer" integer)))
    

    The 'bin-string' function converts the 'integer' argument into binary form and returns is as a string. If the optional 'all' argument is not given or NIL, leading zeros are not included in the string. If the optional 'all' argument is non-NIL, all digits of the internal representation of the 'integer' argument, including leading zeros, are contained in the string. This is useful for debugging integer overflow and bit-wise functions.

    (bin integer [all])
    integer - an integer expression
    all - a boolean expression
    prints - the integer in binary form
    returns - the integer argument

    (defun bin (integer &optional all)
      (if (integerp integer)
          (format t "#b~a~%" (bin-string integer all))
          (format t ";; not an integer~%"))
      integer)
    

    The 'bin' function prints the 'integer' argument in binary form on the screen. Together with the #b read-macro this can be used for interactive binary computations.

    > (bin 12345678)
    #b101111000110000101001110
    12345678
    
    > (bin 12345678 :all)
    #b00000000101111000110000101001110
    12345678
    
    > (bin 1.2345678)
    ;; not an integer
    1.2345678
    
    > (bin (logand #b1011 #b1101))
    #b1001
    9
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/predicates.htm0000644000175000000620000005212111512762341023157 0ustar stevestaff Predicates Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Predicates and Comparison


    Lisp has extensive support for run-time tests.

    Generalized Lisp Functions - slower than the build-ins, but no errors

    1. Built-in XLISP Functions
    2. Generalized Comparison - one or more arguments
      • equalp - compares expressions with 'equality' functions.
    3. Symbol Predicates - one argument
      • variablep - is this a symbol with a variable value bound to it?
      • functionp - is this a function or a symbol with a function value bound to it?
      • specialp - is this a special form or a symbol with a special form bound to it?
      • macrop - is this a Lisp macro or a symbol with a Lisp macro bound to it?
    4. Function Predicates - one argument
      • subrp - is this a build-in function?
      • fsubrp - is this a build-in special form?
      • closurep - is this a user-defined function?
    5. Character Predicates - one argument

      Back to top


    Built-in XLISP Functions


    1. Boolean Predicates - one argument [all types]
      • not - does this expression evaluate to false?
    2. Generalized Comparison - two arguments [all types]
      • eq - are the expressions identical?
      • eql - are the expressions identical or equal numbers?
      • equal - do the printed expressions look the same?
    3. Type Predicates - one argument [all types]
      • atom - is this an atom?
      • symbolp - is this a symbol?
        • Symbol Predicates - one argument [error if not a symbol]
          • boundp - has the symbol a variable value?
          • fboundp - has the symbol a function value?
      • numberp - is this a number?
        • Number Predicates - one argument [error if not a number]
          • plusp - is the number positive?
          • minusp - is the number negative?
          • zerop - is the number equal to zero?
          • integerp - is the number an integer?
            • Integer Predicates - one argument [error if not an integer]
              • evenp - is the integer even?
              • oddp - is the integer odd?
          • floatp - is the number a floating-point number?
        • Numerical Comparison - one or more arguments [error if not numbers only]
          •  <  - true if all numbers are monotonically increasing
          •  <=  - true if all numbers are monotonically nondecreasing
          •  =  - true if all all numbers are the same value
          •  /=  - true if no two numbers have the same value
          •  >=  - true if all numbers are monotonically nonincreasing
          •  >  - true if all numbers are monotonically decreasing
      • null - is this an empty list?
      • consp - is it a non-empty list?
      • listp - is this a list?
        • List Predicates - one argument [error if not a list]
          • endp - is this the end of a list?
      • stringp - is this a string?
        • String Comparison - one or more arguments [error if not strings only]
          • Case Sensitive
            • string< - test for less than in ASCII ordering
            • string<= - test for less than or equal to in ASCII ordering
            • string= - test for equal to in ASCII ordering
            • string/= - test for not equal to in ASCII ordering
            • string>= - test for greater than or equal to in ASCII ordering
            • string> - test for greater than in ASCII ordering
          • Case Insensitive
          • See also Unicode examples.
      • characterp - is this a character?
        • Character Predicates - one argument [error if not a character]
        • Character Comparison - one or more arguments [error if not characters only]
          • Case Sensitive
            • char< - test for less than in ASCII ordering
            • char<= - test for less than or equal to in ASCII ordering
            • char= - test for equal to in ASCII ordering
            • char/= - test for not equal to in ASCII ordering
            • char>= - test for greater than or equal to in ASCII ordering
            • char> - test for greater than in ASCII ordering
          • Case Insensitive
          • See also Unicode examples.
      • arrayp - is this an array?
      • streamp - is this a stream?
      • objectp - is this an object?
      • filep - is this a file?
      • soundp - is this a sound?

      Back to top


    equalp


    Two expressions are 'equalp':

    • If two numbers are  =  numerical equal.

    • If two characters are char-equal.

    • If two strings are string-equal.

    • If the two cars in conses are 'equalp' and the two cdrs in conses are 'equalp'.

    • If two arrays have the same number of elements and dimensions, and the corresponding elements in all dimensions are 'equalp'.

    (defun equalp (expr-1 expr-2)
      (or (equal expr-1 expr-2)
          (and (numberp expr-1) (numberp expr-2) (= expr-1 expr-2))
          (let ((type (type-of expr-1)))
            (when (eq type (type-of expr-2))
              (case type
                (character (char-equal expr-1 expr-2))
                (string    (string-equal expr-1 expr-2))
                (cons      (do ((x (first expr-1)
                                   (if (consp expr-1) (first expr-1) expr-1))
                                (y (first expr-2)
                                   (if (consp expr-2) (first expr-2) expr-2)))
                               ((or (null expr-1)
                                    (null expr-2)
                                    (not (equalp x y)))
                                (and (null expr-1)
                                     (null expr-2)))
                             (setq expr-1 (and (consp expr-1) (rest expr-1))
                                   expr-2 (and (consp expr-2) (rest expr-2)))))
                (array     (let ((end (length expr-1)))
                             (when (eql end (length expr-2))
                               (dotimes (index end t)
                                 (and (not (equalp (aref expr-1 index)
                                                   (aref expr-2 index)))
                                      (return nil)))))))))))
    

    cons: I used do instead of recursion because XLISP has only two kilobytes stack size. The (consp expr) tests are necessary because in a dotted list the last rest element is not a cons.

    Examples:

    (equalp 1 1.0)                            => T
    (equalp #\a #\A)                          => T
    (equalp "Abc" "aBc")                      => T
    (equalp '(1 #\a "Abc") '(1.0 #\A "aBc"))  => T
    (equalp #(1 #\a "Abc") #(1.0 #\A "aBc"))  => T
    

    Nested expressions only match if the nesting matches:

    (equalp '(1 (2 3)) '(1.0 (2.0 3.0))  => T
    (equalp '(1 (2 3)) '((1.0 2.0) 3.0)  => NIL
    (equalp '((1 2) 3) '((1.0 2.0) 3.0)  => T
    (equalp '((1 2) 3) '(1.0 (2.0 3.0))  => NIL
    

    A character does not match a string with the same character:

    (equalp #\a "a")  => NIL
    

      Back to top


    variablep


    The 'variablep' macro tests if a Lisp expression evaluates to a symbol with a valid variable value bound to it in the current global or lexical environment:

    (defmacro variablep (expr)
      `(and (symbolp ,expr)
            (valuep ,expr)))
    

    Depends on valuep, see and, defmacro, symbolp.

      Back to top


    functionp


    The 'functionp' macro tests if a Lisp expression eveluates to a function or a symbol with a valid function value bound to it in the current global or lexical environment:

    (defmacro functionp (expr)
      `(case (type-of ,expr)
         (closure (eq 'lambda (car (get-lambda-expression ,expr))))
         (subr    t)
         (symbol  (and (or (lfboundp ,expr) (fboundp ,expr))
                       (functionp (function ,(if (consp expr) (cadr expr) expr)))))
         (t       nil)))
    

    Depends on lfboundp, see and, cadr, car, case, closure, defmacro, eq, fboundp, function, get-lambda-expression, lambda, nil, or, subr, symbol,  t , type-of.

    The awkward (function ,(if (consp expr) (cadr expr) expr)) construct is necessary because the function special form needs a pre-evaluated argument, what must be done at macro-expansion time, so an additional consp test is needed if the 'expr' argument is a list at all, otherwise cadr will produce an error.

    Examples:
    (functionp #'car)  => T    ; subr = built-in function
    (functionp  'car)  => T    ; symbol with a function value
    
    (functionp #'and)  => NIL  ; fsubr = built-in special form
    (functionp "and")  => NIL  ; string
    
    (defun a () nil)   => A    ; closure = user-defined function
    (functionp #'a)    => T    ; closure
    (functionp  'a)    => T    ; symbol with a function value
    
    (setq b #'a)       => A    ; function A stored in variable B
    (fboundp 'b)       => NIL  ; no function B found
    (fboundp b)        => T    ; variable B evaluates to function A
    
    (functionp #'(lambda () nil))  => T    ; closure
    (functionp  '(lambda () nil))  => NIL  ; list
    (functionp   (lambda () nil))  => T    ; closure
    
    (functionp #'functionp)        => NIL  ; macro
    
    (let ((x nil))        ; lexical variable
      (functionp x))
    => NIL
    
    (flet ((y () nil))    ; lexical closure
      (functionp y))
    => T
    
    (labels ((z () nil))  ; lexical closure
      (functionp z))
    => T
    

      Back to top


    specialp


    (defmacro specialp (expr)
      `(case (type-of ,expr)
         (fsubr   t)
         (symbol  (and (or (lfboundp ,expr) (fboundp ,expr))
                       (functionp (function ,(if (consp expr) (cadr expr) expr)))))
         (t       nil)))
    

      Back to top


    macrop


    (defmacro macrop (expr)
      `(case (type-of ,expr)
         (closure (eq 'macro (car (get-lambda-expression ,expr))))
         (symbol  (and (or (lfboundp ,expr) (fboundp ,expr))
                       (macrop (function ,(if (consp expr) (cadr expr) expr)))))
         (t       nil)))
    

      Back to top


    subrp


    The 'subrp' function returns T if the symbol is a build-in function.

    (defun subrp (symbol)
      (eq 'subr (type-of symbol))) 
    

      Back to top


    fsubrp


    The 'fsubrp' function returns T if the symbol is a build-in special function.

    (defun fsubrp (symbol)
      (eq 'fsubr (type-of symbol))) 
    

      Back to top


    closurep


    The 'closurep' function returns T if the symbol is a user-defined function.

    (defun closurep (symbol)
      (eq 'closure (type-of symbol)))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/math.htm0000644000175000000620000006507411512762341022000 0ustar stevestaff Math Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Math


    1. Number Types
    2. Integer Limits
    3. Rounding and Truncation
    4. Remainder and Modulus
    5. Power and Roots

    Number Types


    Nyquist/XLISP only knows two types of numers:

    • fixnum - integer numbers
    • flonum - floating-point numbers

    In Nyquist/XLISP, there are no ratios or complex numbers. Even if the math functions on this page are modelled after Common Lisp, no attempt is made to emulate these numbers.


    Integer Limits


    (setq *most-positive-fixnum*  2147483647)
    (setq *most-negative-fixnum* -2147483648)
    

    Note: these are the limits for 32-bit machines.

    (defun fixnum-bits ()
      (dolist (bits '(15 31 63) nil)
        (let ((fixnum (round (expt 2.0 bits))))
          (and (plusp (1- fixnum))
               (minusp fixnum)
               (return (1+ bits))))))
    
    (defun fixnum-limits ()
      (if (dolist (bits '(15 31 63) nil)
            (let* ((negative (round (expt 2.0 bits)))
                   (positive (1- negative)))
               (when (and (plusp  positive)
                          (minusp negative))
                 (setq most-positive-fixnum positive
                       most-negative-fixnum negative)
                 (return t))))
          most-positive-fixnum
          (error "fixnum limit not found")))
    

      Back to top


    print-float


    The 'print-float' function prints floating-point numbers ending in '.0' as floating-point numbers and not as integers:

    (defun print-float (item)
      (if (not (floatp item))
          item
          (let ((string (format nil "~a" item)))
            (if (not (string-search "." string))
                (strcat string ".0")
                string))))
    

      Back to top


    divide-float


    An easy way to force a sequence of integers to be divided as floating point numbers is to insert the number 1.0 after the first argument in the list of arguments to the divider function or to explicitely convert the first argument into a floating point number by using the XLISP float function:

    (defun divide-float (&rest args)
      (if (null args)
          (error "too few arguments")
          (apply #'/ (cons (float (first args)) (rest args)))))
    

    See apply, cons, defun, error, first, float, if, null, rest, &rest.

    Examples:

    (divide-float 1)    => 1.0
    (divide-float 1 2)  => 0.5
    

      Back to top


    Rounding and Truncation


    The cl:round, cl:truncate, cl:ceiling and cl:floor functions divide a number by a divisor, returning a quotient and a remainder:

    (cl:round  number [divisor])   ⇒   quotient, remainder
    (cl:truncate  number [divisor])   ⇒   quotient, remainder
    (cl:ceiling  number [divisor])   ⇒   quotient, remainder
    (cl:floor  number [divisor])   ⇒   quotient, remainder

      quotient * divisor + remainder = number

    The 'quotient' always represents a mathematical integer. The 'remainder' is an integer if both 'number' and 'divisor' arguments are integers, and a floating-point number if either the 'number' or the 'divisor' or both are floating-point numbers.

    With Nyquist/XLISP, the 'quotient' is always directly returned by the function, while a list:

    (quotient remainder)
    

    is stored in the Nyquist/XLISP *rslt* variable and the cl:*multiple-values* is set to  T  to signal that Multiple Values are returned.

    Examples:
    (cl:round     3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:truncate  3.5)  =>  3  ; *rslt* = ( 3  0.5)
    (cl:ceiling   3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:floor     3.5)  =>  3  ; *rslt* = ( 3  0.5)
    
    (cl:round    -3.5)  => -4  ; *rslt* = (-4  0.5)
    (cl:truncate -3.5)  => -3  ; *rslt* = (-3 -0.5)
    (cl:ceiling  -3.5)  => -3  ; *rslt* = (-3 -0.5)
    (cl:floor    -3.5)  => -4  ; *rslt* = (-4  0.5)
    
    Force integer division:
    (cl:truncate 3.0 2.0)              => 1
    (/ (truncate 3.0) (truncate 2.0))  => 1
    (/ 3 4)                            => 1
    

    Implementation Notes

    (defun name (number &optional (divisor (if (integerp number) 1 1.0)))
      ... )
    

    The integerp test in the parameter list signals an error if the 'number' argument is not a number, also the  /  [division] function signals errors if the 'divisor' argument is zero or not a number, so we do not explicitely need to test the arguments.

    The cl:ceiling and cl:floor functions test if 'number' is an integer multiple of 'divisor' by comparing the results of an integer division and a floating-point division:

    (let ((i-quotient (/ (truncate number) (truncate divisor)))
          (f-quotient (/ (float number) divisor)))
      (if (= i-quotient f-quotient)
            ...
    

    I'm not sure if this really catches all cases [e.g. regarding floating point precision], but have found no problems so far.

      Back to top


    cl:round


    The 'cl:round' function truncates towards the next integer:

    (cl:round number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of runding the result of number divided by divisor
     -  the remainder of the round operation

    (defun cl:round (number &optional (divisor
                                      (if (integerp number) 1 1.0)
                                      divisor-p))
      (let* ((x (/ (float number) divisor))
             (quotient (cond ((and (not divisor-p) (integerp number)) number)
                             ((= number divisor) 1)
                             ((plusp x) (truncate (+ x 0.5)))
                             ((= (- x 0.5) (truncate (- x 0.5)))
                              (if (minusp x)
                                  (1- (truncate x))
                                  (truncate x)))
                             (t (truncate (- x 0.5))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The 'cl:round' function computes a quotient that has been rounded to the nearest mathematical integer. If the mathematical quotient is exactly halfway between two integers, [that is, it has the form 'integer+1/2'], then the quotient has been rounded to the even [divisible by two] integer. See Rounding and Truncation above for more details.

    (round  3.5)     =>  4
    (round -3.5)     => -3
    
    (cl:round  3.5)  =>  4  ; *rslt* = ( 4 -0.5)
    (cl:round -3.5)  => -4  ; *rslt* = (-4  0.5)
    

      Back to top


    cl:truncate


    The 'cl:truncate' function truncates towards zero:

    (cl:truncate number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of truncating the result of number divided by divisor
     -  the remainder of the truncate operation

    (defun cl:truncate (number &optional (divisor (if (integerp number) 1 1.0)))
      (let ((quotient (truncate (/ (float number) divisor))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The 'cl:truncate' function computes a quotient that has been truncated towards zero. That is, the quotient represents the mathematical integer of the same sign as the mathematical quotient, and that has the greatest integral magnitude not greater than that of the mathematical quotient. See Rounding and Truncation above for more details.

      Back to top


    cl:ceiling


    The 'cl:ceiling' function truncates towards positive infinity:

    (cl:ceiling number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of truncating the result of number divided by divisor
     -  the remainder of the truncate operation

    (defun cl:ceiling (number &optional (divisor
                                        (if (integerp number) 1 1.0)
                                        divisor-p))
      (let ((quotient
              (cond ((and (not divisor-p) (integerp number)) number)
                    ((= number divisor) 1)
                    (t (let ((i-quotient (/ (truncate number) (truncate divisor)))
                             (f-quotient (/ (float number) divisor)))
                         (if (or (= i-quotient f-quotient)  ; integer result
                                 (not (plusp f-quotient)))
                              (truncate f-quotient)
                              (1+ (truncate f-quotient))))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The 'cl:ceiling' function computes a quotient that has been truncated toward positive infinity. That is, the quotient represents the smallest mathematical integer that is not smaller than the mathematical result. See Rounding and Truncation above for more details.

      Back to top


    cl:floor


    The 'cl:floor' function truncates towards negative infinity:

    (cl:floor number [divisor])
    number - an integer or floating-point number
    divisor - an integer or floating-point number, except zero
    returns  -  the result of truncating the result of number divided by divisor
     -  the remainder of the truncate operation

    (defun cl:floor (number &optional (divisor
                                      (if (integerp number) 1 1.0)
                                      divisor-p))
      (let ((quotient
              (cond ((and (not divisor-p) (integerp number)) number)
                    ((= number divisor) 1)
                    (t (let ((i-quotient (/ (truncate number) (truncate divisor)))
                             (f-quotient (/ (float number) divisor)))
                         (if (or (= i-quotient f-quotient)  ; integer result
                                 (not (minusp f-quotient)))
                              (truncate f-quotient)
                              (1- (truncate f-quotient))))))))
        (setq *rslt* (list quotient (- number (* quotient divisor)))
              cl:*multiple-values* t)
        quotient))
    

    The 'cl:floor' function computes a quotient that has been truncated toward negative infinity. That is, the quotient represents the largest mathematical integer that is not larger than the mathematical quotient. See Rounding and Truncation above for more details.

      Back to top


    Remainder and Modulus


    The cl:mod and cl:rem function are generalizations of the modulus and remainder functions. The cl:mod function performs the cl:floor operation on its arguments and returns the remainder of the cl:floor operation. The cl:rem function performs the cl:truncate operation on its arguments and returns the remainder of the cl:truncate operation. The cl:mod and cl:rem functions are the modulus and remainder functions when the 'number' and 'divisor' arguments both are integers.

      Back to top


    cl:rem


    (cl:rem number divisor)
    number - an integer or floating-point number
    divisor - an integer or floating-point number
    returns - the remainder of a cl:truncate operation

    (defun cl:rem (number divisor)
      (if (= (abs number) (abs divisor))
          (if (and (integerp number) (integerp divisor)) 0 0.0)
          (let ((quotient (truncate (/ (float number) divisor))))
            (- number (* quotient divisor)))))
    

    The 'cl:rem' function performs the cl:truncate operation on its arguments and returns the remainder of the cl:truncate operation. The result is either zero or an integer or floating-point number with the same sign as the 'number' argument. If both arguments are integer numbers, the 'cl:rem' function is equal to the mathematical remainder function.

      Back to top


    cl:mod


    (cl:mod number divisor)
    number - an integer or floating-point number
    divisor - an integer or floating-point number
    returns - the remainder of a cl:floor operation

    (defun cl:mod (number divisor)
      (if (= (abs number) (abs divisor))
          (if (and (integerp number) (integerp divisor)) 0 0.0)
          (let* ((i-quotient (/ (truncate number) (truncate divisor)))
                 (f-quotient (/ (float number) divisor))
                 (quotient (if (or (= i-quotient f-quotient)  ; integer result
                                   (not (minusp f-quotient)))
                               (truncate f-quotient)
                               (1- (truncate f-quotient)))))
            (- number (* quotient divisor)))))
    

    The 'cl:mod' function performs the cl:floor operation on its arguments and returns the remainder of the cl:floor operation. The result is either zero or an integer or floating-point number with the same sign as the 'divisor' argument. If both arguments are integer numbers, the 'cl:rem' function is equal to the mathematical modulus function.

      Back to top


    cl:exp


    The 'cl:exp' function does the same as the Nyquist/XLISP exp function, but it also accepts integer numbers as argument:

    (cl:exp power)
    power - an integer or floating-point number
    returns - the result of 'e' [2.7128] to the power of power

    (defun cl:exp (x)
      (exp (float x)))
    

    The 'cl:exp' function computes 'e' [2.7128] raised to the specified 'power'. The result is always a floating-point number.

      Back to top


    cl:expt


    The 'cl:expt' function computes the result of 'x' to the power of 'y':

    (cl:expt base power)
    base - the base
    power - the exponent
    returns - the result of base to the power of power

    (defun cl:expt (x y)
      (let ((power (expt (float x) y)))
        (if (and (integerp x) (integerp y))
            (round power)
            power)))
    

    See and, defun, expt, float,  if , integerp, let, power, round.

    The 'cl:expt' function accepts integer and floating point numbers as arguments. If both arguments are integer numbers, the result will be an integer number, if one or both arguments are floating-point numbers, the result will be a floating-point number. In contrast to the Nyquist/XLISP expt function, the 'cl:expt' function specifies exactly two arguments.

      Back to top


    cl:log


    The 'cl:log' function does the same as the Nyquist/XLISP log function, but also accepts integer numbers and has an optional 'base' argument:

    (cl:log number [base])
    number - an integer or floating-point number
    base - an integer or floating-point number
    returns - the the logarithm of number in base base

    (defun cl:log (number &optional base)
      (if base
          (if (zerop base)
              0.0
              (/ (log (float number)) (log (float base))))
          (log (float number))))
    

    The 'cl:log' function returns the logarithm of 'number' in base 'base'. If 'base' is not supplied its value is 'e', the base of the natural logarithms. If the 'base' argument is zero, then 'cl:log' returns zero. The result is always a floating-point number.

      Back to top


    cl:sqrt


    The 'cl:sqrt' function does the same as the Nyquist/XLISP sqrt function, but it also accepts integer numbers as argument:

    (cl:sqrt number)
    number - an integer or floating-point number
    returns - the square root of number

    (defun cl:sqrt (x)
      (sqrt (float x)))
    

    The result is always a floating-point number.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/hash-tables.htm0000644000175000000620000004260011512762341023230 0ustar stevestaff Hash Tables Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Hash Tables


    The internal XLISP 'hash' function from 'xlsym.c':

    /* hash - hash a symbol name string */
    int hash(char *str, int len)
    {
        int i;
        for (i = 0; *str; )
            i = (i << 2) ^ *str++;
        i %= len;
        return (i < 0 ? -i : i);
    }
    

    In XLISP this would look like:

    (defun lisp-hash (string table-size)
      (let ((i 0))
        (dotimes (index (length string))
          (setq i (logxor (bsh i 2) (char-code (char string index)))))
        (setq i (rem i table-size))
        (if (minusp i) (- i) i)))
    

    A hash function is a kind of random number generator, where the same input always produces the same output number. The XLISP hash function computes equally distributed integer numbers in a given range from the characters of an input string.

    A very simple example:

    1. We want to store 4 strings in 2 lists, stored in 2 array elements:

      > (setq my-array (make-array 2))
      #(NIL NIL)  ; NIL NIL = two empty lists
      

      If the array index is computed by the hash function, then the equally distributed numbers make sure that every list will contain approximately the same number of strings:

      > (dolist (string '("a" "b" "c" "d") my-array)
          (push string (aref my-array (hash string (length my-array)))))
      #(("d" "b") ("c" "a"))
      

      The order of the strings in the array was computed by the hash function, it is not the same order as given to dolist.

    2. If we now search for a string in the lists then the hash function will tell us the number of the array element with the list containing the string because the same input string to the hash function always produces the same output number, as long as the same 'table-size' [the same number of array elements] is used:

      > (dolist (string '("a" "b" "c" "d"))
          (format t "~s = ~s~%" string
                    (aref my-array (hash string (length my-array)))))
      "a" = ("c" "a")
      "b" = ("d" "b")
      "c" = ("c" "a")
      "d" = ("d" "b")
      NIL
      

      The hash function will always find the correct list as long as the number of array elements has not changed.

    The two main tasks of the hash function are:

    1. Make sure that all lists contain approximately the same number of elements, independent from the characters in the input strings, no matter if the strings are very similar or completely different. With the hash function it will nearly never happen that one list contains all strings while all other lists are empty.

    2. With the same 'name' and 'table-size' arguments the hash function will always return exactly the same integer number, so a string can always be found no matter in what order the strings are stored in the lists of the array.

    Now we can find strings stored in lists, but we want to store and find arbitrary things. Therefore we replace the ordinary lists with association lists:

    > (setq my-array (make-array 2))
    #(() ())
    
    > (dolist (a-cons '(("a" . 1) ("b" . 2) ("c" . 3) ("d" . 4)) my-array)
        (push a-cons (aref my-array (hash (car a-cons) (length my-array)))))
    #((("d" . 4) ("b" . 2)) (("c" . 3) ("a" . 1)))
    

    We now have an array like this:

    Array 
      0  Association List 1  →  (("d" . 4) ("b" . 2))
      1  Association List 2  →  (("c" . 3) ("a" . 1))

    The association lists give the flexibility to store an arbitrary number of key/value pairs, we are not limited by the fixed number of array elements, while the array together with the hash function gives much more speed than a single association list if we want to manage a big number of key/value pairs.

    With a big number of key/value pairs it is faster to keep them in many small association lists than in one single big list. Arrays provide random access, where every element can be accessed in the same time, while a list can only be searched from the beginning up to the matching element. The longer the list, the slower the search becomes.

    With the hash function we find the association list containing the key:

    > (dolist (key '("a" "b" "c" "d"))
        (format t "~s = ~s~%" key
                  (aref my-array (hash key (length my-array)))))
    "a" = (("c" . 3) ("a" . 1))
    "b" = (("d" . 4) ("b" . 2))
    "c" = (("c" . 3) ("a" . 1))
    "d" = (("d" . 4) ("b" . 2))
    NIL
    

    With the assoc function we find the key/value pair:

    > (dolist (key '("a" "b" "c" "d"))
        (format t "~s = ~s~%" key
                  (assoc key (aref my-array (hash key (length my-array)))
                         :test #'equal)))
    "a" = ("a" . 1)
    "b" = ("b" . 2)
    "c" = ("c" . 3)
    "d" = ("d" . 4)
    NIL
    

    With the cdr function we get the value:

    > (dolist (key '("a" "b" "c" "d"))
        (format t "~s = ~s~%" key
                  (cdr (assoc key (aref my-array (hash key (length my-array)))
                              :test #'equal))))
    "a" = 1
    "b" = 2
    "c" = 3
    "d" = 4
    NIL
    

    And now we have our first working hash-table.

    But we still have one problem. The hash function works only with symbols or strings, while assoc can also work with numbers, strings and even lists as 'key' argument. To make our hash-table work with all types assoc can handle, we must make the hash function happy and convert the 'key' argument with format into a string before computing the hash index:

    > (setq my-array (make-array 2))
    #(() ())
    
    > (dolist (a-cons '((#\x . 1) ((y z) . 2) (12 . 3) (6.5 . 4)) my-array)
        (push a-cons (aref my-array (hash (format nil "~s" (car a-cons))
                                          (length my-array)))))
    #(((12 . 3) (#\x . 1)) ((6.5 . 4) ((Y Z) . 2)))
    
    > (dolist (key '(#\x (y z) 12 6.5))
        (format t "~s = ~s~%" key
                  (cdr (assoc key (aref my-array (hash (format nil "~s" key)
                                                       (length my-array)))
                              :test #'equal))))
    #\x = 1
    (Y Z) = 2
    12 = 3
    6.5 = 4
    NIL
    

    Wonderful.

    A final quirk still needs to be solved. Maybe you have noticed the :test argument to assoc. Like with all Lisp functions providing :test arguments, the assoc :test defaults to eql [because eq is unreliable with numbers, and eql is faster than equal], but eql doesn't work with floating-point numbers, strings and lists, so we had to use equal.

    The typical Lisp solution is to provide a :test argument to the 'make-hash-table' function, so the programmer can choose which function to use. The :test argument to 'make-hash-table' becomes a property of the hash-table itself, so the :test only needs to be given once, at the time when the hash-table is created, and not every time the hash-table is accessed afterwards.

    We have the problem that hash-tables are no built-in XLISP data type and we want use make-hash-table in the same way as make-array:

    (setq my-hash-table (make-hash-table size :test #'equal))
    

    Here the make-hash-table function has no access to the property list of the 'my-hash-table' symbol, so the only solution is to make the :test function become part of the hash-table itself:

    Array 
      0  Test Function  →  the :test argument to assoc
      1  Association List 1  →  ((key1 . value1) ... (keyN . valueN))
      2  Association List 2  →  ((key1 . value1) ... (keyN . valueN))
      3  Association List 3  →  ((key1 . value1) ... (keyN . valueN))
    ... 
      n  Association List n  →  ((key1 . value1) ... (keyN . valueN))

    This is the final layout of our hash-tables, so we can start to implement the hash-table functions.

      Back to top


    make-hash-table


    (defun make-hash-table (size &optional (test #'eql))
      (and (< size 1) (error "hash-table minimum size is 1" size))
      (let ((hash-table (make-array (1+ size))))
        (setf (aref hash-table 0) test)
        hash-table))
    
    (defun gethash (key hash-table)
      (let* ((size   (1- (length hash-table)))
             (index  (1+ (hash (format nil "~s" key) size)))
             (a-list (aref hash-table index))
             (test   (aref hash-table 0)))
        (cdr (assoc key a-list :test test))))
    
    (defun puthash (key value hash-table)
      (let* ((size   (1- (length hash-table)))
             (index  (1+ (hash (format nil "~s" key) size)))
             (a-list (aref hash-table index))
             (test   (aref hash-table 0))
             (a-cons (assoc key a-list :test test)))
        (setf (aref hash-table index)
              (cons (cons key value)
                    (if a-cons
                        (remove-if #'(lambda (x)
                                       (funcall test key (car x)))
                                   a-list)
                        a-list)))))
    
    (defun remhash (key hash-table)
      (let* ((size   (1- (length hash-table)))
             (index  (1+ (hash (format nil "~s" key) size)))
             (a-list (aref hash-table index))
             (test   (aref hash-table 0))
             (a-cons (assoc key a-list :test test)))
        (and a-cons
             (setf (aref hash-table index)
                   (remove-if #'(lambda (x)
                                  (funcall test key (car x)))
                              a-list)))
        a-cons))
    
    (defun clrhash (hash-table)
      (let ((size (1- (length hash-table))))
        (do ((index 1 (1+ index)))
            ((> index size))
          (setf (aref hash-table index) nil))
        hash-table))
    
    (defun hash-table-p (expr)
      (and (arrayp expr)             ; expression is an array
           (> (length expr) 1)       ; with more than one elements
           (fboundp (aref expr 0))   ; first element is a function
           (let ((size (1- (length expr))))   ; all other
             (do ((index 1 (1+ index)))       ; elements are lists
                 ((or (> index size)
                      (not (listp (aref expr index))))
                  (> index size))))))
    
    (defun hash-table-count (hash-table)
      (let ((size (1- (length hash-table)))
            (entries 0))
        (do ((index 1 (1+ index)))
            ((> index size))
          (setf entries (+ entries (length (aref hash-table index)))))
        entries))
    
    (defun hash-table-size (hash-table)
      (1- (length hash-table)))
    
    (defun hash-table-test (hash-table)
      (aref hash-table 0))
    
    (defun print-hash-table (hash-table)
      (if (not (arrayp hash-table))
          (format t ";; Not an array: ~s~%" hash-table)
          (dotimes (index (length hash-table))
            (let ((element (aref hash-table index)))
              (cond ((not (listp element))
                     (format t ";; array element ~a: ~s~%" index element))
                    ((null element)
                     (format t ";; bucket ~a: ()~%" index))
                    (t
                     (format t ";; bucket ~a:~%" index)
                     (let ((entry-counter 1))
                       (dolist (entry element)
                         (format t ";; ~a.~a: ~s~%" index entry-counter entry)
                         (incf entry-counter)))))))))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/strings.htm0000644000175000000620000007022411512762341022531 0ustar stevestaff Characters and Strings Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Characters and Strings


    Strings are also Sequences.


    make-string


    (defun make-string (length initial-element)
      (cond ((not (and (integerp length)
                       (plusp    length)))
             (error "not a positive integer" length))
            ((not (characterp initial-element))
             (error "not a character" initial-element))
            (t
             (let ((element (string initial-element))
                   (string ""))
               (dotimes (x length)
                 (setq string (strcat string element)))
               string))))
    

      Back to top


    string*


    (string* [expr1 ...])
    exprN - arbitrary Lisp expressions
    returns - the expression[s], converted and concatenated into a single string

    The 'string*' function tries to make a string out of everything:

    (defun string* (&rest items)
      (if (null items)
          ""
          (let ((end (length items))
                (result ""))
            (labels ((strcat-element (element)
                       (let ((string (if (or (consp element) (arrayp element))
                                         (string* element)
                                         (format nil "~a" element))))
                         (setq result (strcat result string)))))
              (dotimes (index end)
                (if (eq (nth index items) '*unbound*)
                    (strcat-element "*UNBOUND*")
                    (let ((item (nth index items)))
                      (case (type-of item)
                        (cons  (let ((end (length item)))
                                 (when (not (consp (last item))) (incf end))
                                 (dotimes (index end)
                                   (if (eq (nth index item) '*unbound*)
                                       (strcat-element "*UNBOUND*")
                                       (strcat-element (nth index item))))))
                        (array (let ((end (length item)))
                                 (dotimes (index end)
                                   (if (eq (aref item index) '*unbound*)
                                       (strcat-element "*UNBOUND*")
                                       (strcat-element (aref item index))))))
                        (t     (strcat-element item))))))
              result))))
    

    Examples:

    (string*)              => ""
    
    (string* #\A "B" 'c)   => "ABC"
    (string* 1 2 3)        => "123"
    
    (string* 1 "st")       => "1st"
    (string* "2" #\n #\d)  => "2nd"
    
    (setq a 3)             => 3
    (string* 'a "=" a)     => "A=3"
    

    Nested expressions will be flattened:

    (string* #(1 (#\2) "3"))  => "123"
    

    The result may contain nonsense:

    (string* #'car)                    => "#<Subr-CAR: #8645768>"
    (string* '(lambda (x) (print x)))  => "LAMBDAXPRINTX"
    

      Back to top


    POSIX Character Classes


    The built-in XLISP character test functions upper-case-p, lower-case-p, both-case-p, return the boolean values  T  or NIL instead of the tested character, while digit-char-p returns an integer or NIL, what is handy if you want to convert arbitrary Lisp symbols into numbers without producing an error, but all this is impractical for writing a string parser.

    The following functions implement tests for the standard POSIX character classes, where all functions return the tested character if the test succeeds, or NIL if the test fails. The 'internal' functions do not check if the argument is a character and therefore are faster than the 'user' functions. Also note that XLISP is limited to ASCII characters, so there is no way to find out if an unicode character is upper- or lowercase if the character code is greater than ASCII 127.

       POSIX   -   Internal   -   User Function
       [: alnum :]   -   char:alnum-p   -   alnum-character-p   -  alphanumeric = [a-z], [A-Z], [0-9]
       [: alpha :]   -   char:alpha-p   -   alpha-character-p   -  alphabetic = [a-z], [A-Z]
       [: blank :]   -   char:blank-p   -   blank-character-p   -  space and horizontal-tab
       [: cntrl :]   -   char:cntrl-p   -   cntrl-character-p   -  code-chars 0-31 and 127
       [: digit :]   -   char:digit-p   -   digit-character-p   -  decimal = [0-9]
       [: graph :]   -   char:graph-p   -   graph-character-p   -  graphical = alnum + punct
       [: lower :]   -   char:lower-p   -   lower-character-p   -  lowercase = [a-z]
       [: print :]   -   char:print-p   -   print-character-p   -  printable = alnum + punct + space
       [: punct :]   -   char:punct-p   -   punct-character-p   -  punctuation marks
       [: space :]   -   char:space-p   -   space-character-p   -  characters producing whitespace
       [: upper :]   -   char:upper-p   -   upper-character-p   -  uppercase = [A-Z]
       [: xdigit :]   -   char:xdigit-p   -   xdigit-character-p   -  hexadecimal = [0-9], [a-f], [A-F]

    Internal Functions for POSIX character classes:

    ;; alphanumeric characters = a-z, A-z, 0-9
    
    (defun char:alnum-p (char)
      (and (alphanumericp char)
           char))
    
    ;; alphabetic characters = a-z, A-Z
    
    (defun char:alpha-p (char)
      (and (both-char-p char)
           char))
    
    ;; blanks = space and horizontal-tab
    
    (defun char:blank-p (char)
      (and (or (char= char #\Space)
               (char= char #\Tab))
           char))
    
    ;; control characters = code-chars 0-31 and 127
    
    (defun char:cntrl-p (char)
      (let ((code (char-code char)))
        (and (or (<= 0 code 31)
                 (= code 127))
             char)))
    
    ;; decimal digits = 0-9
    
    (defun char:digit-p (char)
      (and (digit-char-p char)
           char))
    
    ;; graphical characters = alnum + punct
    
    (defun char:graph-p (char)
      (and (<= 33 (char-code char) 126)
           char))
    
    ;; lowercase characters = a-z
    
    (defun char:lower-p (char)
      (and (lower-case-p char)
           char))
    
    ;; printable characters = alnum + punct + space
    
    (defun char:print-p (char)
      (and (<= 32 (char-code char) 126)
           char))
    
    ;; punctuation marks
    
    (defun char:punct-p (char)
      (let ((code (char-code char)))
        (and (or (<=  33 code  47)   ;  ! " # $ % & ' ( ) * + , - . /
                 (<=  58 code  64)   ;  : ; < = > ? @
                 (<=  91 code  96)   ;  [ \ ] ^ _ `
                 (<= 123 code 126))  ;  { | } ~
             char)))
    
    ;; characters producing whitespace
    ;;
    ;;  9 = horizontal tab   10 = line feed         11 = vertical tab
    ;; 12 = form feed        13 = carriage return   32 = space
    
    (defun char:space-p (char)
      (and (member (char-code char) '(9 10 11 12 13 32))
           char))
    
    ;; uppercase characters = A-Z
    
    (defun char:upper-p (char)
      (and (upper-case-p char)
           char))
    
    ;; hexadecimal digits = 0-9, a-f, A-F
    
    (defun char:xdigit-p (char)
      (and (or (digit-char-p char)
               (let ((code (char-code char)))
                 (or (<= 65 code  70)     ; A-Z
                     (<= 97 code 102))))  ; a-z
           char))
    

    User Functions for POSIX character classes:

    ;; alphanumeric characters = a-z, A-z, 0-9
    
    (defun alnum-character-p (char)
      (and (characterp char)
           (char:alnum-p char)))
    
    ;; alphabetic characters = a-z, A-Z
    
    (defun alpha-character-p (char)
      (and (characterp char)
           (char:alpha-p char)))
    
    ;; blanks = space and horizontal-tab
    
    (defun blank-character-p (char)
      (and (characterp char)
           (char:blank-p char)))
    
    ;; control characters = code-chars 0-31 and 127
    
    (defun cntrl-character-p (char)
      (and (characterp char)
           (char:cntrl-p char)))
    
    ;; decimal digits = 0-9
    
    (defun digit-character-p (char)
      (and (characterp char)
           (char:digit-p char)))
    
    ;; graphical characters = alnum + punct
    
    (defun graph-character-p (char)
      (and (characterp char)
           (char:graph-p char)))
    
    ;; lowercase characters = a-z
    
    (defun lower-character-p (char)
      (and (characterp char)
           (char:lower-p char)))
    
    ;; printable characters = alnum + punct + space
    
    (defun print-character-p (char)
      (and (characterp char)
           (char:print-p char)))
    
    ;; punctuation marks
    
    (defun punct-character-p (char)
      (and (characterp char)
           (char:punct-p char)))
    
    ;; characters producing whitespace
    
    (defun space-character-p (char)
      (and (characterp char)
           (char:space-p char)))
    
    ;; uppercase characters = A-Z
    
    (defun upper-character-p (char)
      (and (characterp char)
           (char:upper-p char)))
    
    ;; hexadecimal digits = 0-9, a-f, A-F
    
    (defun xdigit-character-p (char)
      (and (characterp char)
           (char:xdigit-p char)))
    

      Back to top


    Unicode


    The UTF-8 functions may help to write custom UTF-8 string access functions like UTF-8-SUBSEQ or UTF-8-STRING-SEARCH with no need to care about the underlying low-level octal sequences.

    In the list of "string-characters" every ASCII or UTF-8 character from 1-byte to 4-byte is represented by its own list element:

    (utf-8-string-to-list "hll") => ("h" "\303\244" "l" "l" "\303\266")
                                        h             l   l       
    

    The list can be manipulated by standard Nyquist list functions and then re-converted into a string by UTF-8-LIST-TO-STRING.

    Practical examples

    In Nyquist code, non-ASCII characters are represented by their native bytes sequences, represented by escaped octal numbers:

    (print "")  => "\303\244"  ; on UTF-8 systems
    

    So for example matching the second "" from "hllo" in the list above, represented by the octal sequence "\303\244":

    (let ((string-list (utf-8-string-to-list "hll")))
      (string= "" (nth 1 string-list)))  ; 0 = first, 1 = second element
    => T                                  ; T = true = identified
    

    Advantage: The number of the element in the list is the same as the number of the character in the string, independent from the number of bytes in the underlying character encoding.

    ;; The UTF-8 toolbox is intended to manipulate UTF-8 encoded file- ;; or directory names, typed in by the user or read from environment ;; variables, before they are given to SETDIR or OPEN. ;; ;; Information from the environment ;; ;; Because the encoding of the non-ASCII characters depends on the ;; underlying operation system [with non-unicode operation systems ;; there will be no UTF-8 encoding available], it's always better ;; to refer to strings from environment variables, user input, or ;; strings returned from the underlying file system, instead of ;; hand-coded strings in the Nyquist source code, for example: ;; ;; GET-ENV - can read strings from environment variables: ;; ;; (defun user-home-directory () ;; (or (get-env "HOME") ; Unix ;; (get-env "UserProfile"))) ; Windows ;; ;; On Windows, there is no HOME variable defined by Windows itself, ;; but most programs will respect a HOME variable, if one has been ;; defined by the user. That's why the HOME variable is read first. ;; ;; SETDIR - can test if a directory exists and return its name: ;; ;; (defun directory-exists-p (string) ;; (let ((orig-dir (setdir ".")) ;; (new-dir (setdir string))) ;; (when (string/= orig-dir new-dir) ;; (setdir orig-dir) ;; new-dir))) ;; ;; SETDIR always returns abloute direcory names, even if STRING is a ;; relative direcory name. That's why DIRECTORY-EXISTS-P first stores ;; the absolute name of the current working directory in the ORIG-DIR ;; variable and compares it then against the absolute directory name ;; returned by SETDIR when it tries to change the directory to STRING. ;; ;; OPEN - can test if a file exists and return its name: ;; ;; (defun file-exists-p (string) ;; (unless (directory-exists-p string) ;; (let (file-stream) ;; (unwind-protect ;; (setq file-stream (open string)) ;; (when file-stream (close file-stream))) ;; (when file-stream string)))) ;; ;; On Unix, a directory is a special kind of file, so the Nyquist/XLISP ;; OPEN function opens directories, too. That's why FILE-EXISTS-P first ;; must test and make sure that STRING is not the name of a directory. ;; ;;; Known bugs and limitations of the UTF-8 toolbox: ;; ;; The UTF-8 toolbox does not provide support for UTF-8 case-detection ;; or UTF-8 case-conversion. It cannot be detected if a UTF-8 character ;; is upper- or lowercase, it's also not possible to convert characters ;; from upper- to lowercase or vice versa. ;; ;; The library does not provide functions to compare UTF-8 characters ;; or to sort UTF-8 characters. ;; ;; The XLISP character functions do not work with UTF-8 octal sequences, ;; so matching must be done via XLISP's STRING= and STRING/= functions. ;; ;; The XLISP string comparison functions like STRING<, STRING>, etc. ;; do not work reliably with multibyte characters. ;; ;; The string matching and sorting algorithms of the Unicode Consortium ;; are too complex to be implemented in XLISP with reasonable speed. ;; ;; See: http://www.unicode.org/reports/tr10/ - string comparison ;; ;; The library is implemented in interpreted Lisp, so please do not ;; expect high-speed performance with advanced list manipulations. ;; ;; The library still has not been tested with ISO encoded systems. ;;

    UTF-8 Encoding - see also http://en.wikipedia.org/wiki/UTF-8

    In an UTF-8 encoded character the first byte starts with:

    ;;    one-byte  0xxxxxxx -> legal char-codes   0 to 127  [UTF-8/ASCII]
    ;;    two-byte  110xxxxx -> legal char-codes 194 to 223  [UTF-8]
    ;;  three-byte  1110xxxx -> legal char-codes 224 to 239  [UTF-8]
    ;;   four-byte  11110xxx -> legal char-codes 240 to 244  [UTF-8]
    ;;
    ;; The second, third, and fourth characters start with:
    ;;
    ;;              10xxxxxx -> legal char-codes 128 to 191  [UTF-8]
    

    UTF-8-BYTE-P tests if a XLISP character is a valid UTF-8 byte

    (defun utf-8-byte-p (char)
      (when (characterp char)
        (let ((code (char-code char)))
          (when (or (<=   0 code 191)
                    (<= 194 code 244))  
            char))))
    

    UTF-8-BYTES tries to determine from the XLISP character code how many bytes the character has in UTF-8 encoding

    (defun utf-8-bytes (char)
      (cond ((not (characterp char))
             (error "not a character" char))
            ((not (utf-8-byte-p char))
             (error "invalid UTF-8 byte" char))
            (t
             (let ((code (char-code char)))
               (cond ((<=   0 code 127) 1)  ; one byte [= ASCII]
                     ((<= 194 code 223) 2)  ; two bytes
                     ((<= 224 code 239) 3)  ; three bytes
                     ((<= 240 code 244) 4)  ; four bytes
                     (t (error "utf-8-bytes: not an UTF-8 identifer" char)))))))
    

    UTF-8-STRING-TO-LIST converts a string containing ASCII or UTF-8 characters from one to four bytes into a list, where:

    • ASCII - ASCII string
    • UTF-8 - string of octal-sequences
    ;; Every character (single-byte or multi-byte) is represented ;; by its own list element: ;; ;; (utf-8-string-to-list "hll") => ("h" "\303\244" "l" "l" "\303\266") ;; h l l ;; ;; The list can be manipulated by standard XLISP list functions and ;; then re-converted into a string by UTF-8-LIST-TO-STRING below.
    (defun utf-8-string-to-list (string)
      (cond
        ((not (stringp string))
         (error "utf-8-string-to-list: not a string" string))
        ((string= "" string) nil)
        (t
         (let ((end (length string))
               (list nil))
           (do ((index 0 (1+ index)))
               ((>= index end))
             (let* ((char (char string index))
                    (bytes (1- (utf-8-bytes char)))
                    (utf-8 (string char)))
               (dotimes (rest-of bytes) ; runs only if bytes > 0
                 (incf index)
                 (if (> index end)
                     (error "utf-8-string-to-list: index out of range" index)
                     (let ((byte (char string index)))
                       (if (not (utf-8-byte-p byte))
                           (error "utf-8-string-to-list: invalid UTF-8 byte" byte)
                           (setq utf-8 (strcat utf-8 (string byte)))))))
               (push utf-8 list)))
           (reverse list)))))
    
    ;; UTF-8-LIST-TO-STRING re-converts a list containing ASCII and ;; UTF-8 "string-characters" back to a XLISP string, intended ;; to be given to SETDIR or OPEN for file or directory operations.
    (defun utf-8-list-to-string (list)
      (cond ((not (listp list))
             (error "utf-8-list-to-string: not a list" list))
            ((null list) "")
            (t
             (let ((result ""))
               (dolist (string list)
                 (if (not (stringp string))
                     (error "utf-8-list-to-string: not a string" string)
                     (setq result (strcat result string))))
               result))))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/arrays.htm0000644000175000000620000003610211512762341022336 0ustar stevestaff Arrays Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Arrays


    Arrays are also Sequences.

    • make-array* - create multi-dimensional arrays
    • aref* - access multi-dimensional-arrays
    • vector* - make a one-dimensional array out of arbitrary Lisp expressions
    • array* - make a multi-dimensional array out of arbitrary Lisp expressions

    make-array*


    XLISP already has the make-array function to create one-dimensional arrays:

    (make-array size)
    size - the size [integer] of the array to be created
    returns - the new array

    Here is a function to create multi-dimensional arrays:

    (make-array* size-1 [size-2 ...])
    sizeN - the size [integer] of the N-th dimension in the array to be created
    returns - the new array

    (defun make-array* (&rest dimensions-list)
      (cond ((null dimensions-list)
             (error "too few arguments"))
            ((and (null (rest dimensions-list))
                  (eql 0 (first dimensions-list)))
             (make-array 0))
            (t (labels ((multi-vector (dimensions-list)
                          (let ((count (first dimensions-list)))
                            (if (not (and (integerp count) (plusp count)))
                                (error "not a positive integer" count)
                                (let ((rest (rest dimensions-list))
                                      (elements-list nil))
                                  (dotimes (i count)
                                    (push (when rest
                                            (multi-vector rest))
                                          elements-list))
                                  (apply #'vector (reverse elements-list)))))))
                 (multi-vector dimensions-list)))))
    

    Examples:

    (make-array* 2 3)    => #(#(NIL NIL NIL) #(NIL NIL NIL)))
    (make-array* 2 2 1)  => #(#(#(NIL) #(NIL)) #(#(NIL) #(NIL)))
    

    Like make-array it is possible to create one-dimensional arrays with zero elements:

    (make-array* 0)  => #()
    (make-array  0)  => #()
    

    But it is not allowed to create multi-dimensional arrays with zero-size dimensions:

    (make-array* 1 0 1)  => error: not a positive integer - 0
    

    Rationale: Multi-dimensional arrays are implemented as nested vectors and a zero-element vector cannot hold the vector for the subsequent dimension. We would need some additional administration overhead to keep the subsequent dimensions accessible, but this would break the compatibility to the build-in XLISP aref function.

    More practical examples see 'aref*' below.

      Back to top


    aref*


    XLISP already has the aref function to access elements in one-dimensional arrays:

    (aref array dimension-1)
    array - one-dimensional array
    dimension-1 - element number in the first dimension
    returns - the value of the array element

    Here is a macro for accessing elements in multi-dimensional arrays:

    (aref* array dimension-1 [dimension-2 ...])
    array - any-dimensional array
    dimensionN - element number in the N-th dimension
    returns - the value of the array element

    (defmacro aref* (array &rest index-list)
      (labels ((multi-aref (array-name index-list)
                 (let ((index (first index-list)))
                   (if (not (integerp index))
                       (error "not an integer" index)
                       (let ((rest (rest index-list))
                             (expansion-list (list 'aref)))
                         (push (if rest
                                   (multi-aref array-name rest)
                                   array-name)
                               expansion-list)
                         (push index expansion-list)
                         (reverse expansion-list))))))
        (multi-aref `,array (reverse `,index-list))))
    

    The symbols inside the labels form do not leak into the expansion, so 'aref*' also works with array names like 'array', 'array-name' 'index', 'index-list' or 'expansion-list'. Also the values of local or global variables with these names are not changed.

    (macroexpand-1 '(aref* a 1 2 3))  => (aref (aref (aref a 1) 2) 3)
    

    Examples:

    > (setq a (make-array* 2 3))
    #(#(NIL NIL NIL) #(NIL NIL NIL)))
    
    > (setf (aref* a 0 1) "hello")
    "hello"
    
    > a
    #(#(NIL "hello" NIL) #(NIL NIL NIL))
    
    > (aref* a 0 1)
    "hello"
    

    'aref*' with only one 'dimension' argument behaves like aref:

    (aref* a 0)            => #(NIL "hello" NIL)
    (aref  a 0)            => #(NIL "hello" NIL)
    
    (aref* (aref* a 0) 1)  => "hello"
    (aref  (aref  a 0) 1)  => "hello"
    
    (aref* a 0 1)          => "hello"
    (aref  a 0 1)          => error: too many arguments
    

    'aref*' like aref also works with setf to store values in multi-dimensional arrays:

    (setf (aref* (aref* a 0) 1) "1")  => "1" ; a => #(#(NIL "1" NIL) #(NIL NIL NIL)))
    (setf (aref  (aref  a 0) 1) "2")  => "2" ; a => #(#(NIL "2" NIL) #(NIL NIL NIL)))
    
    (setf (aref* 0 1) "3")            => "3" ; a => #(#(NIL "3" NIL) #(NIL NIL NIL)))
    (setf (aref  0 1) "4")            => error: too many arguments
    

      Back to top


    vector*


    (defun vector* (&rest items)
      (if (null items)
          (make-array 0)
          (let* ((end (length items))
                 (result (make-array end)))
            (if (> end 1)
                (dotimes (index end)               ; more than one item
                  (setf (aref result index)
                        (if (eq (nth index items) '*unbound*)
                            '*unbound*
                            (nth index items))))
                (if (eq (first items) '*unbound*)  ; one item only
                    (setf (aref result 0) '*unbound*)
                    (let ((item (first items)))
                      (case (type-of item)
                        (cons   (let ((end (length item)))
                                  (setq result (make-array end))
                                  (dotimes (index end)
                                    (setf (aref result index)
                                          (if (eq (nth index item) '*unbound*)
                                              '*unbound*
                                              (nth index item))))))
                        (array  (let ((end (length item)))
                                  (setq result (make-array end))
                                  (dotimes (index end)
                                    (setf (aref result index)
                                          (if (eq (aref item index) '*unbound*)
                                              '*unbound*
                                              (aref item index))))))
                        (string (let ((end (length item)))
                                  (setq result (make-array end))
                                  (dotimes (index end)
                                    (setf (aref result index)
                                          (char item index)))))
                        (t      (setf (aref result 0) item))))))
            result)))
    
    (defun list* (&rest items)
      (if (null items)
          nil
          (let* ((end (length items))
                 (result nil))
            (labels ((push-element (element)
                       (if (member (type-of element) '(array cons string))
                           (setq result (append (reverse (list* element)) result))
                           (push element result))))
              (dotimes (index end)
                (if (eq (nth index items) '*unbound*)
                    (push '*unbound* result)
                    (let ((item (nth index items)))
                      (case (type-of item)
                        (nil    (push item result))
                        (cons   (let ((end (length item)))
                                  (when (not (consp (last item))) (incf end))
                                  (dotimes (index end)
                                    (if (eq (nth index item) '*unbound*)
                                        (push '*unbound* result)
                                        (push-element (nth index item))))))
                        (array  (let ((end (length item)))
                                  (dotimes (index end)
                                    (if (eq (aref item index) '*unbound*)
                                        (push '*unbound* result)
                                        (push-element (aref item index))))))
                        (string (let ((end (length item)))
                                  (dotimes (index end)
                                    (push (char item index) result))))
                        (t      (push item result))))))
              (reverse result)))))
    
    (defun tree* (&rest items)
      (if (null items)
          nil
          (let* ((end (length items))
                 (result nil))
            (labels ((push-element (element)
                       (if (member (type-of element) '(array cons string))
                           (push (reverse (list* element)) result)
                           (push element result))))
              (dotimes (index end)
                (if (eq (nth index items) '*unbound*)
                    (push '*unbound* result)
                    (let ((item (nth index items)))
                      (case (type-of item)
                        (nil    (push item result))
                        (cons   (let ((end (length item)))
                                  (when (not (consp (last item))) (incf end))
                                  (dotimes (index end)
                                    (if (eq (nth index item) '*unbound*)
                                        (push '*unbound* result)
                                        (push-element (nth index item))))))
                        (array  (let ((end (length item)))
                                  (dotimes (index end)
                                    (if (eq (aref item index) '*unbound*)
                                        (push '*unbound* result)
                                        (push-element (aref item index))))))
                        (string (let ((end (length item)))
                                  (dotimes (index end)
                                    (push (char item index) result))))
                        (t      (push item result))))))
              (reverse result)))))
    

      Back to top


    array*


    (defun array* (&rest items)
      (if (null items)
          (make-array 0)
          (let* ((end (length items))
                 (result (make-array end)))
            (labels ((vector-element (element index)
                       (setf (aref result index)
                             (if (member (type-of element) '(cons string array))
                                 (array* element)
                                 element))))
              (dotimes (index end)
                (if (eq (nth index items) '*unbound*)
                    (setf (aref result index) '*unbound*)
                    (let ((item (nth index items)))
                      (case (type-of item)
                        (cons  (let ((end (length item)))
                                 (dotimes (index end)
                                   (if (eq (nth index item) '*unbound*)
                                       (strcat-element "*UNBOUND*")
                                       (strcat-element (nth index item))))))
                        (array (let ((end (length item)))
                                 (dotimes (index end)
                                   (if (eq (aref item index) '*unbound*)
                                       (strcat-element "*UNBOUND*")
                                       (strcat-element (aref item index))))))
                        (t     (strcat-element item))))))
              result))))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/lists.htm0000644000175000000620000004314111512762341022174 0ustar stevestaff Lists Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Lists


    Lists are also Sequences.


    print-cons


    (defun print-cons (item)
      (labels ((cons-string (item)
                 (case (type-of item)
                   (array      (let ((end (length item))
                                     (result ""))
                                 (dotimes (index end)
                                   (let ((string (cons-string (aref item index))))
                                     (setq result 
                                       (if (eql 0 index)
                                           (format nil "#(~a" string)
                                           (format nil "~a ~a" result string)))))
                                 (format nil "~a)" result)))
                   (character  (format nil "~s" item))
                   (cons       (format nil "(~a . ~a)"
                                       (cons-string (car item))
                                       (cons-string (cdr item))))
                   (string     (format nil "\"~a\"" item))
                   (t          item))))
        (format t "~a~%" (cons-string item))
        item))
    

    Examples:

    > (print-cons '(1 2 3))
    (1 . (2 . (3 . NIL)))
    (1 2 3)
    

    The 'print-cons' function is useful for debugging association lists, where print often fails to display the correct layout:

    > (print-cons (cons '((1 . 2) (3 . 4)) '((a . b) (c . d))))
    (((1 . 2) . ((3 . 4) . NIL)) . ((A . B) . ((C . D) . NIL)))
    (((1 . 2) (3 . 4)) (A . B) (C . D))  ; <- output of PRINT
    

    Do not think that print is bad, it saves you from reading things like this:

    > (print-cons '(defun hello-world ()
                     (print "Hello World!")))
    (DEFUN . (HELLO-WORLD . (NIL . ((PRINT . ("Hello World!" . NIL)) . NIL))))
    (DEFUN HELLO-WORLD NIL (PRINT "Hello World!"))  ; <- output of PRINT
    

    Test this if you don't believe:

    > (DEFUN . (HELLO-WORLD . (NIL . ((PRINT . ("Hello World!" . NIL)) . NIL))))
    HELLO-WORLD
    
    > (hello-world)
    "Hello World!"
    

      Back to top


    dolist*


    A dolist version that can iterate dotted lists:

    (defmacro dolist* (fargs &rest body)
      (let ((list (gensym)))
        `(let ((,list ,(second fargs)))
           (if (not (listp ,list))
               (error "not a list" ,list)
               (do ((,(first fargs) (first ,list)
                                    (if (consp ,list) (first ,list) ,list)))
                   ((null ,list))
                 (setq ,list (and (consp ,list) (rest ,list)))
                 ,@body)))))
    
    (dolist  (i '(1 2 3)) (print i))    ; prints 1 2 3
    (dolist* (i '(1 2 3)) (print i))    ; prints 1 2 3
    
    (dolist  (i '(1 2 . 3)) (print i))  ; prints 1 2
    (dolist* (i '(1 2 . 3)) (print i))  ; prints 1 2 3
    

      Back to top


    cl:member


    XLISP already has the member function to for search elements in lists:

    (member expr list [{:test | :test-not} test])
    expr - the expression to find [an atom or a list]
    list - the list to search
    test - optional test function, default is eql
    returns - the remainder of the list starting with expr

    The 'cl:member' function provides an additional :key argument for accessing sub-elements in the list:

    (cl:member expr list [{:test | :test-not} test :key key])
    expr - the expression to find [an atom or a list]
    list - the list to search
    test - an optional test function, default is eql
    key - an optional accessor function for sub-elements in the list
    returns - the remainder of the list starting with expr

    (defun cl:member (expr list &key test test-not key)
      (and test test-not (error "both :TEST and :TEST-NOT specified"))
      (if key
          (cond (test
                 (member expr list
                   :test #'(lambda (x y)
                             (funcall test x (funcall key y)))))
                (test-not
                 (member expr list
                   :test-not #'(lambda (x y)
                                 (funcall test-not x (funcall key y)))))
                (t (member expr list
                     :test #'(lambda (x y)
                               (eql x (funcall key y))))))
          (cond (test     (member expr list :test test))
                (test-not (member expr list :test-not test-not))
                (t        (member expr list)))))
    

    Test if the number 4 matches the first or the second element in several sublists:

    (cl:member 4 '((1 2) (3 4) (5 6)) :key #'first)   => NIL            ; no match
    (cl:member 4 '((1 2) (3 4) (5 6)) :key #'second)  => ((3 4) (5 6))  ; number found
    

    Subtle differences between XLISP and Common Lisp:

    ;; Lisp Form              XLISP         Common Lisp
    (member 1 '(1 2 . 3))  => (1 2 . 3)  => (1 2 . 3)
    (member 2 '(1 2 . 3))  => (2 . 3)    => (2 . 3)
    (member 3 '(1 2 . 3))  => NIL        => error: not a proper list
    

    Here is a 'cl:member' version that behaves error-conform to Common Lisp but produces an unintelligible backtrace in case of Lisp errors. I also have found no way how to macroexpand macrolets, so debugging this function is a real pain.

    (defun cl:member (expr list &key test test-not key)
      (and test test-not (error "both :TEST and :TEST-NOT specified"))
      (macrolet ((internal-loop (list)
        `(do ()
             ;; termination test
             ((or (not (consp list))
                  ,(if key
                       (cond (test     `(funcall ,test ,expr (funcall ,key (car list))))
                             (test-not `(not (funcall ,test ,expr (funcall ,key (car list)))))
                             (t        `(eql ,expr (funcall ,key (car list)))))
                       (cond (test     `(funcall ,test ,expr (car list)))
                             (test-not `(not (funcall ,test ,expr (car list))))
                             (t        `(eql ,expr (car list))))))
              ;; return value
              (if (not (listp list))
                  (error "a proper list must not end with" list)
                  list))
            ;; body
            (setq list (cdr list)))))
         (internal-loop list)))
    

      Back to top


    cl:member-if


    Here are two functions to search for elements that satisfy a given predicate:

    (member-if predicate list [:key key])
    predicate - a test function with one argument
    list - the list to search
    key - optional accessor function for sub-elements in the list
    returns - the remainder of the list starting with the first matching element

    (defun cl:member-if-not (predicate list &key key)
      (member nil list :test (if key
                                 #'(lambda (x y)
                                     (funcall predicate (funcall key y)))
                                 #'(lambda (x y)
                                     (funcall predicate y)))))))
    

      Back to top


    cl:member-if-not


    (member-if-not predicate list [:key key])
    predicate - a test function with one argument
    list - the list to search
    key - optional accessor function for sub-elements in the list
    returns - the remainder of the list starting with the first non-matching element

    (defun cl:member-if-not (predicate list &key key)
      (member nil list :test-not (if key
                                     #'(lambda (x y)
                                         (funcall predicate (funcall key y)))
                                     #'(lambda (x y)
                                         (funcall predicate y)))))))
    

    Examples:

    (cl:member-if     #'plusp  '(-2 -1 0 1 2))  => (1 2)    ; 1 = first positive number
    (cl:member-if-not #'minusp '(-2 -1 0 1 2))  => (0 1 2)  ; 0 = first non-negative number
    

    More test functions see Predicates.

      Back to top


    cl:list:accessor


    The 'lists as sets' functions have common :test, :test-not and :key parameters:

    (defmacro cl:list:accessor (test test-not &optional key)
      (if (and test test-not)
          (error "both :TEST and :TEST-NOT specified"))
          (if key
              (cond (test     `(lambda (x y)
                                 (funcall ,test (funcall ,key x)
                                                (funcall ,key y))))
                    (test-not `(lambda (x y)
                                 (not (funcall ,test-not (funcall ,key x)
                                                         (funcall ,key y)))))
                    (t        `(lambda (x y)
                                 (eql (funcall ,key x) (funcall ,key y)))))
              (cond (test     `(lambda (x y)
                                 (funcall ,test x y)))
                    (test-not `(lambda (x y)
                                 (not (funcall ,test-not x y))))
                    (t        `(lambda (x y)
                                 (eql x y))))))
    

      Back to top


    cl:pushnew


      Back to top


    cl:union


    (union list1 list2 [{:test | :test-not} test :key key])
    listN - a list of symbols or numbers
    returns - the union of list1 and list2

    (defun union (a b)
      (let (result)
        (dolist (element a)
          (unless (member element result)
            (push element result)))
        (dolist (element b)
          (unless (member element result)
            (push element result)))
        result))
    

    The 'cl:union' function returns a list that contains every element that occurs in either 'list1' or 'list2'.

      Back to top


    cl:intersection


    (intersection list1 list2 [{:test | :test-not} test :key key])
    listN - a list of symbols or numbers
    returns - the intersection of list1 and list2

    (defun intersection (a b)
      (let (result)
        (dolist (element a)
          (when (member element b)
            (push element result)))
        result))
    

      Back to top


    cl:set-difference


    (set-difference list1 list2)
    listN - a list of symbols or numbers
    returns - the set-difference of list1 and list2

    (defun set-difference (a b)
      (remove-if #'(lambda (element)
                     (member element b))
                 a))
    

    An element of list1 appears in the result if and only if it does not match any element of list2.

    (set-difference '(1 2 3) '(2 3 4)) => (1)
    

      Back to top


    cl:set-exclusive-or


    The result contains precisely those elements of list1 and list2 that appear in no matching pair.

    (set-exclusive-or '(1 2 3) '(2 3 4)) => (1 4)
    

      Back to top


    cl:subsetp


    (subsetp list1 list2)
    listN - a list of symbols or numbers
    returns -  T  if list1 is a subset of list2, NIL otherwise

    (defun subsetp (a b)
      (let ((result t))
        (dolist (element a)
          (when (not (member element b)
            (setf result nil)
            (return))))
        result))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/sequences.htm0000644000175000000620000005310211512762341023027 0ustar stevestaff Sequences Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Sequences


    Sequences are Lists, Strings, or Arrays.

    • sequencep - test if a Lisp object is a sequence
    • length - the length of a sequence
    • identity - do nothing, just return the value
    • cl:subseq - subsequences of lists, strings, or arrays
    • Properties of elements in sequences:
      • find
      • count
      • position
    • Predicates for testing sequences:
      • every
      • some
      • notevery
      • notany
    • Functions to modify sequences:
      • map
      • flatten

    sequencep


    The following example demonstrates how a XLISP expression can be tested for being a sequence:

    (defun sequencep (x)
      (and (lboundp 'x)                ; not *unbound*
           (or (and (listp x)          ; a list or NIL
                    (consp (last x)))  ; but not a dotted list
               (stringp x)             ; or a string
               (arrayp x))))           ; or an array
    

    Depends on lboundp, see also and, arrayp, consp, defun, last, listp, or, stringp.

      Back to top


    length


    XLISP already knows sequences, even if the manual doesn't explicitely tell you:

    (length expr)
    expr - expression, evaluating to a list, string, or array
    returns - the length of the list, string, or array

      Back to top


    identity


    (defun identity (x)
      x)
    

    The 'identity' function is handy if a mapping function needs a 'do nothing, just return the value' function.

      Back to top


    cl:subseq


    XLISP already has a subseq function returning a subsequence of a string:

    (subseq string start [end])
    string - a string expression
    start - the position of the first element, an integer
    end - the position following last element, defaults to the end of the sequence
    returns - the substring between start and end

    The 'cl:subseq' function works like subseq, but returns subsequences of lists, strings, and arrays:

    (cl:subseq sequence start [end])
    sequence - a list, string, or array
    start - the position of the first element, an integer
    end - the position following last element, defaults to the end of the sequence
    returns - the subsequence in the same type as sequence

    The 'cl:subseq' function creates a sequence that is a copy of the subsequence of 'sequence' bounded by 'start' and 'end'. 'cl:subseq' always allocates a new sequence for a result, it never shares storage with an old sequence. The resulting subsequence is always of the same type as the input sequence.

    (defun cl:subseq (sequence start &optional (end nil end-p))
      (let ((type (type-of sequence)))
        (if (not (member type '(nil cons string array)))
            (error "not a sequence" sequence)
            (let* ((length (length sequence))
                   (end (or end length)))
              (cond ((or (> start length) (minusp start))
                     (error "start index out of bounds" start))
                    ((and end-p (or (> end length) (minusp end)))
                     (error "end index out of bounds" end))
                    ((> start end)
                     (error (format nil "bad range start ~a end ~a" start end)))
                    (t (case type
                         (nil    nil)
                         (cons   (if (not (consp (last sequence)))
                                     ;; a dotted list is not a sequence
                                     (error "not a proper sequence" sequence)
                                     (if (>= start end)
                                         nil
                                         (nthcdr start
                                                 (if end-p
                                                     (reverse
                                                       (nthcdr (- length end)
                                                         (reverse sequence)))
                                                     sequence)))))
                         (string (subseq sequence start end))
                         (array  (if (>= start end)
                                     (make-array 0)
                                     (let ((new-array (make-array (- end start))))
                                       (do ((n-index 0 (1+ n-index))
                                            (s-index start (1+ s-index)))
                                           ((>= s-index end))
                                         (setf (aref new-array n-index)
                                               (aref sequence s-index)))
                                       new-array))))))))))
    

    Examples:

    (cl:subseq "012345" 2)          => "2345"
    (cl:subseq "012345" 3 5)        => "34"
    
    (cl:subseq '(0 1 2 3 4 5) 2)    => (2 3 4 5)
    (cl:subseq '(0 1 2 3 4 5) 3 5)  => (3 4)
    
    (cl:subseq #(0 1 2 3 4 5) 2)    => #(2 3 4 5)
    (cl:subseq #(0 1 2 3 4 5) 3 5)  => #(3 4)
    

    In XLISP, neither subseq nor 'cl:subseq' can be used as arguments to setf. See cl:replace below how to replace subsequences.

      Back to top


    cl:replace


    (cl:replace sequence1 sequence2 &key start1 end1 start2 end2)
    sequenceN - a list, string, or array
    startN - the position of the first element in sequenceN, an integer
    endN - the position following last element in sequenceN, defaults to the end of sequenceN
    returns - the subsequence in the same type as sequence

      Back to top


    map


    map result-type function sequence-1 [sequence-2 ...]
    result-type - list, string, or array
    function - a function, applied to each element of each sequenceN
    sequenceN - a list, string, or array
    returns - a sequence where each element is the result of applying the function to each element of each sequenceN

    The 'sequence:string' function can handle lists and arrays containing not only characters but also strings, because XLISP Unicode characters are represented as strings.

    (defun sequence:string (sequence)
      (if (stringp sequence)
          sequence
          (let ((result ""))
            (flet ((strcat-element (element)
                     (let ((string (cond ((stringp element) element)
                                         ((characterp element) (string element))
                                         (t (error "not a character or string"
                                                   element)))))
                       (setq result (strcat result string)))))
              (case (type-of sequence)
                (array  (let ((end (length sequence)))
                          (dotimes (index end)
                            (if (eq (aref sequence index) '*unbound*)
                                (error "not a character or string" '*unbound*)
                                (strcat-element (aref sequence index))))))
                (cons   (let ((end (length sequence)))
                          (if (not (consp (last sequence)))
                              (error "not a proper sequence" sequence)
                              (dotimes (index end)
                                (if (eq (nth index sequence) '*unbound*)
                                    (error "not a character or string" '*unbound*)
                                    (strcat-element (nth index sequence)))))))
                (nil    nil)
                (t      (error "not a sequence" sequence)))
              result))))
    
    (defun list-to-string (list)
      (let ((string ""))
        (dolist (element list string)
          (setq string (strcat string (if (consp element)
                                          (list-to-string element)
                                          (format nil "~a" element)))))))
    
    (defun sequence:vector (sequence)
      (if (not (boundp 'sequence))
          (error "not a sequence" '*unbound*)
          (let ((type (type-of sequence)))
            (if (not (member type '(array cons nil string)))
                (error "not a sequence" sequence)
                (let* ((end (length sequence))
                       (result (make-array end)))
                  (unless (zerop end)
                    (case type
                      (array  (dotimes (index end)
                                (setf (aref result index)
                                      (if (eq (aref sequence index) '*unbound*)
                                          '*unbound*
                                          (aref sequence index)))))
                      (cons   (if (not (consp (last sequence)))
                                  (error "not a proper sequence" sequence)
                                  (dotimes (index end)
                                    (setf (aref result index)
                                          (if (eq (nth index sequence) '*unbound*)
                                              '*unbound*
                                              (nth index sequence))))))
                      (string (dotimes (index end)
                                (setf (aref result index)
                                      (char sequence index))))))
                  result)))))
    
    (defun sequence:array (sequence)
      (let ((type (type-of sequence)))
        (if (not (member type '(array cons nil string)))
            (error "not a sequence" sequence)
            (let* ((end (length sequence))
                   (result (make-array end)))
              (if (zerop end)
                  result
                  (labels ((array-element (element index)
                             (setf (aref result index)
                                   (if (or (consp element) (arrayp element))
                                       (sequence:array element)
                                       element))))
                    (case type
                      (array  (dotimes (index end)
                                (if (eq (aref sequence index) '*unbound*)
                                    (setf (aref result index) '*unbound*)
                                    (array-element (aref sequence index) index))))
                      (cons   (if (not (consp (last sequence)))
                                  (error "not a proper sequence" sequence)
                                  (dotimes (index end)
                                    (if (eq (nth index sequence) '*unbound*)
                                        (setf (aref result index) '*unbound*)
                                        (array-element (nth index sequence) index)))))
                      (string (dotimes (index end)
                                (setf (aref result index)
                                      (char sequence index)))))
                    result))))))
    
    
    (defun list-to-array (list)
      (let* ((end (length list))
             (array (make-array end)))
        (dotimes (index end array)
          (let ((element (nth index list)))
            (setf (aref array index) (if (consp element)
                                         (list-to-array element)
                                         element))))))
    
    (defun list-from-input (input)
      (let (result)
        (dolist (element input)  ; input is always a list
          (format t ";; ~s ~s~%" element (type-of element))
          (case (type-of element)
            (nil    (push element result))
            (cons   (if (consp (last element))
                        (push element result)
                        (error "not a proper list" element)))
            (array  (let (local (end (length element)))
                      (dotimes (index end)
                        (push (aref element index) local))
                      (push (reverse local) result)))
            (string (let (local (end (length element)))
                      (dotimes (index end)
                        (push (char element index) local))
                      (push (reverse local) result)))
            (t      (error "not a sequence" element))))
        (reverse result)))
    
    (defun list-from-input* (input &optional recursion-p)
      (let (result)
        (labels ((test (element)
                   (if (member (type-of element) '(array cons string))
                       (list-from-input* element t)
                       (if (or recursion-p (null element))
                           element
                           (error "not a sequence" element)))))
          (format t ";; ~s~%" input)
          (case (type-of input)
            (nil     (push input result))
            (cons    (if (consp (last input))
                         (dolist (element input)
                           (push (test element) result))
                         (error "not a proper list" input)))
            (array   (let ((end (length input)))
                       (dotimes (index end)
                         (push (test (aref input index)) result))))
            (string  (let ((end (length input)))
                       (dotimes (index end)
                         (push (test (char input index)) result))))
            (t       (error "not a sequence" input)))
          (reverse result))))
    
    (defun map (result-type function &rest sequences)
      (if (not (member result-type '(list string array)))
          (error "invalid result type" result-type)
          (let* ((input-list (list-from-input sequences))
                 (result (if function
                             (apply #'mapcar (cons function input-list))
                             (if (rest sequences)
                                 input-list
                                 (first input-list)))))
            (case result-type
              (list   result)
              (string (list-to-string result))
              (array  (list-to-array result))))))
    
    (defun mapcar* (function &rest lists)
      (unless (or (null lists)
                  (dolist (list lists nil)
                    (and (null list) (return t))))
        (let ((end (length lists))
              (result nil))
          (do ((stop nil) (recurse t t)) (stop)
            (let (local)
              (dotimes (index end)
                (let ((first (first (nth index lists)))
                      (rest  (rest  (nth index lists))))
                  (push first local)
                  (unless (consp first) (setq recurse nil))
                  (setf (nth index lists) rest)
                  (when (null rest) (setq stop t))))
              (setq local (reverse local))
              (format t ";; local: ~a~%" local)
              (format t ";; lists: ~a~%" lists)
              (format t ";; recurse: ~a~%" recurse)
              (if recurse
                  (push (apply #'mapcar* (cons function local)) result)
                  (push (apply function local) result))))
          (reverse result))))
    
    (defun map* (result-type function &rest sequences)
      (if (not (member result-type '(list string array)))
          (error "invalid result type" result-type)
          (let* ((input-list (list-from-input* sequences))
                 (result (if function
                             (apply #'mapcar* (cons function input-list))
                             (if (rest sequences)
                                 input-list
                                 (first input-list)))))
            (format t ";; ~s~%" input-list)
            (case result-type
              (list   result)
              (string (list-to-string result))
              (array  (list-to-array result))))))
    

      Back to top


    find item sequence &key from-end test test-not start end keyelement
    find-if predicate sequence &key from-end start end key ⇒ element
    find-if-not predicate sequence &key from-end start end key ⇒ element

    Search for an element of the sequence bounded by start and end that satisfies the predicate or that satisfies the test or test-not, as appropriate.

    count item sequence &key from-end start end key test test-not ⇒ n
    count-if predicate sequence &key from-end start end key ⇒ n
    count-if-not predicate sequence &key from-end start end key ⇒ n

    Count and return the number of elements in the sequence bounded by start and end that satisfy the test.

    position item sequence &key from-end test test-not start end key ⇒ position
    position-if predicate sequence &key from-end start end key ⇒ position
    position-if-not predicate sequence &key from-end start end key ⇒ position

    Search sequence for an element that satisfies the test. The position returned is the index within sequence of the leftmost (if from-end is true) or of the rightmost (if from-end is false) element that satisfies the test; otherwise nil is returned. The index returned is relative to the left-hand end of the entire sequence, regardless of the value of start, end, or from-end.

    (defun list-find (element list &key from-end test test-not start end)
      (when from-end (setq list (reverse-list)))
      (first (cond (test (member element list :test test))
                   (test-not (member element list :test-not test-not))
                   (t (member element list)))))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/common-lisp.htm0000644000175000000620000001206611512762341023275 0ustar stevestaff Common Lisp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Where is the Nyquist Common Lisp Library?


    Short answer - nowhere.

    Rationale:

    1. XLISP is a very simple Lisp. Many of the XLISP functions are just simple wrappers around the underlying C functions. This makes XLISP, as an interpreted language, run with reasonable speed. The main advantage of XLISP over Common Lisp is that XLISP is much smaller and therefore much easier to learn.

    2. The main trick of Nyquist is to use XLISP only in the initial setup phase, where the Lisp code is parsed, to set-up the low-level sound sample functions, written in C, not in Lisp.

      The Nyquist low-level 'snd-...' functions only look like Lisp functions, but they are direct wrappers around C functions and behave like that. They do not provide type contagion, instead they expect a correct number of arguments, given in correct order with correct data types, and if not given exactly as expected, chances are good that Nyquist will crash.

      In Nyquist, XLISP [slow] is used to make sure that the low-level functions will be given the correct arguments, while the low-level sound sample functions after the initial setup phase will run in high-speed C, and not in Lisp anymore.

    Because the Nyquist Common Lisp functions are running in interpreted XLISP, they run slower than the built-in XLISP functions. Because many Common Lisp functions do extensive parsing and/or type checking on their arguments, they run many times slower than XLISP. That's why overloading Nyquist with an extensive Common Lisp layer makes not much sense.

      Back to top


    But why did you write so many Common Lisp functions?


    I usually work with Common Lisp for prototyping, so if I'm porting code from Common Lisp to Nyquist:

    1. I first copy the Common Lisp code together with the respective Nyquist Common Lisp functions from screen into a Nyquist lisp file to see if the Common Lisp code works with Nyquist at all. Many of the Nyquist Common Lisp functions have argument tests to help with error tracking.

    2. When the Common Lisp code works with Nyquist I start to strip out everything I don't need for the particular problem at hand, making the Nyquist code run faster. Because this second step is highly depending on the particular problem at hand, there probably never will be a general solution for this.

    I have tried to keep the functions as self-contained as possible, any dependencies to non-Nyquist functions are noted directly below the code.

    There are many XLISP functions that behave exactly like their Common Lisp counterparts, so I haven't written extra functions for them.

    • If you already know Common Lisp then the Nyquist Common Lisp functions may help to understand how XLISP works.

    • If you still don't know Common Lisp and maybe one day you decide to learn more about it, then the Nyquist Common Lisp functions may save you from learning everything double.

    In either case you can use the Nyquist Common Lisp functions as a grab-bag for your own functions.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/octal.htm0000644000175000000620000001104211512762341022133 0ustar stevestaff Octal Integer Numbers Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Octal Integer Numbers


    XLISP provides the #o read-macro for octal numbers:

    #o0  => 0        #o10  => 8         #o20  => 16
    #o1  => 1        #o11  => 9         #o21  => 17
    #o2  => 2        #o12  => 10        #o22  => 18
    #o3  => 3        #o13  => 11        #o23  => 19
    #o4  => 4        #o14  => 12        #o24  => 20
    #o5  => 5        #o15  => 13        #o25  => 21
    #o6  => 6        #o16  => 14        #o26  => 22
    #o7  => 7        #o17  => 15        #o27  => 23
    

    (oct-string integer [all])
    integer - an integer expression
    all - a boolean expression
    returns - the integer in octal form as string

    (defun oct-string (integer &optional all)
      (if (integerp integer)
          (let ((fmt (if all
                         (or (dolist (bits '(16 32 64 128) nil)
                               (let ((fixnum (round (expt 2.0 (1- bits)))))
                                 (and (plusp (1- fixnum))
                                      (minusp fixnum)
                                      (return (format nil "%.~ao"
                                                          (1+ (/ bits 3)))))))
                             (error "integer limit not found"))
                         "%o")))
            (progv '(*integer-format*) (list fmt)
              (format nil "~a" integer)))
          (error "not an integer" integer)))
    

    The 'oct-string' function converts the 'integer' argument into octal form and returns is as a string. If the optional 'all' argument is not given or NIL, leading zeros are not included in the string. If the optional 'all' argument is non-NIL, all digits of the internal representation of the 'integer' argument, including leading zeros, are contained in the string. This is useful for debugging integer overflow and bit-wise functions.

    (oct integer [all])
    integer - an integer expression
    all - a boolean expression
    prints - the integer in octal form
    returns - the integer argument

    (defun oct (integer &optional all)
      (if (integerp integer)
          (format t "#o~a~%" (oct-string integer all))
          (format t ";; not an integer~%"))
      integer)
    

    The 'oct' function prints the 'integer' argument in octal form on the screen. Together with the #o read-macro this can be used for interactive octal computations.

    > (oct 12345678)
    #o57060516
    12345678
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/xlisp/0002755000175000000620000000000011537433125021464 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/examples/xlisp/floor.htm0000644000175000000620000000500411512762341023312 0ustar stevestaff floor Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    floor


    The 'floor' function truncates an integer or floating-point number toward negative infinity:

    (floor number)
    number - an integer or floating-point expression
    returns - the integer result of truncating number

    (defun floor (number)
      (let ((trunc (truncate number)))
        (if (or (plusp number) (= number trunc))
            trunc
            (1- trunc))))
    

    The 'floor' function computes an integer number that has been truncated toward negative infinity. That is, the result represents the largest mathematical integer that is not larger than the number given as argument.

    Examples:

    (floor 3)    => 3      (floor -3)    => -3
    (floor 3.0)  => 3      (floor -3.0)  => -3
    (floor 3.1)  => 3      (floor -3.1)  => -4
    (floor 3.5)  => 3      (floor -3.5)  => -4
    (floor 3.9)  => 3      (floor -3.9)  => -4
    (floor 4.0)  => 4      (floor -4.0)  => -4
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/xlisp/bsh.htm0000644000175000000620000000715611512762341022757 0ustar stevestaff bsh Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    bsh


    The 'bsh' functio performs an 'binary shift' operation:

    (bsh integer count)
    integer - an integer expression
    count - an integer expression
    returns - the number shifted by count

    (defun bsh (integer count)
      (or (integerp integer) (error "not an integer" integer))
      (or (integerp count)   (error "not an integer" count))
      (if (zerop count)
          integer
          (let ((digits (or (dolist (bits '(16 32 64 128) nil)
                              (let ((fixnum (round (expt 2.0 (1- bits)))))
                                (and (plusp (1- fixnum))
                                     (minusp fixnum)
                                     (return bits))))
                            (error "integer limit not found")))
                (list nil)
                (string "#b"))
            (dotimes (x digits)
              (let ((digit (logand (round (expt 2.0 x)) integer)))
                (push (if (zerop digit) "0" "1") list)))
            (dotimes (x digits)
              (let ((digit (if (< -1 count digits) (nth count list) "0")))
                (setq string (strcat string digit))
                (incf count)))
            (eval (read (make-string-input-stream string))))))
    

    The 'bsh' function performs a binary shift operation on the 'integer' argument. The bits of the 'integer' argument is shifted to the left by 'count' positions if 'count' is positive, or to the right by 'count' positions if 'count' is negative. The missing bits are filled with zeros.

    Examples:

    (bsh 16  1)  =>
    (bsh 16  0)  =>
    (bsh 16 -1)  =>
    
    (defun debug:bsh (integer count)
      (let ((shifted (bsh integer count)))
        (format t "integer: ~a~%" (bin-string integer :all))
        (format t "shifted: ~a~%" (bin-string shifted :all))
        shifted))
    

    See Binary Integer Numbers for the 'bin-string' function.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/xlisp/ceiling.htm0000644000175000000620000000505311512762341023607 0ustar stevestaff ceiling Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    ceiling


    The 'ceiling' function truncates an integer or floating-point number toward positive infinity:

    (ceiling number)
    number - an integer or floating-point expression
    returns - the integer result of truncating number

    (defun ceiling (number)
      (let ((trunc (truncate number)))
        (if (or (minusp number) (= number trunc))
            trunc
            (1+ trunc))))
    

    The 'ceiling' function computes an integer number that has been truncated toward positive infinity. That is, the result represents the smallest mathematical integer that is not smaller than the number given as argument.

    Examples:

    (ceiling 3)    => 3      (ceiling -3)    => -3
    (ceiling 3.0)  => 3      (ceiling -3.0)  => -3
    (ceiling 3.1)  => 4      (ceiling -3.1)  => -3
    (ceiling 3.5)  => 4      (ceiling -3.5)  => -3
    (ceiling 3.9)  => 4      (ceiling -3.9)  => -3
    (ceiling 4.0)  => 4      (ceiling -4.0)  => -4
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/xlisp/ash.htm0000644000175000000620000000710611512762341022751 0ustar stevestaff ash Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    ash


    The 'ash' functio performs an 'arithmetic shift' operation:

    (ash integer count)
    integer - an integer expression
    count - an integer expression
    returns - the number shifted by count

    (defun ash (integer count)
      (or (integerp integer) (error "not an integer" integer))
      (or (integerp count)   (error "not an integer" count))
      (let* ((shift (* integer (expt 2.0 count)))
             (trunc (truncate shift)))
        ;; XLISP implementation of (FLOOR SHIFT)
        (if (or (plusp shift) (= shift trunc))
            trunc
            (1- trunc))))
    

    The 'ash' functio performs an arithmetic shift operation on the binary representation of the 'integer' argument, which is treated as if it were binary. The 'integer' argument is shifted arithmetically to the left by 'count' bit positions if 'count' is positive, or to the right by 'count' bit positions if 'count' is negative. The shifted value of the same sign as 'integer' is returned.

    The 'ash' function performs the computation:

    floor (integer * 2^count)
    

    Logically, the 'ash' function moves all of the bits in integer to the left, adding zero-bits at the right, or moves them to the right, discarding bits.

    The 'ash' function is defined to behave as if integer were represented in two's complement form, regardless of how integers are represented internally.

    Examples:

    (ash 16  1)  => 32
    (ash 16  0)  => 16
    (ash 16 -1)  => 8
    
    (defun debug:ash (integer count)
      (let ((shifted (ash integer count)))
        (format t "integer: ~a~%" (bin-string integer :all))
        (format t "shifted: ~a~%" (bin-string shifted :all))
        shifted))
    

    See Binary Integer Numbers for the 'bin-string' function.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/files.htm0000644000175000000620000003444711512762341022151 0ustar stevestaff Files and Directories Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Files and Directories


    • Interactive Functions
      • pwd - returns the current working directory
      • cd - changes the current working directory
    • Testing Files and Directories
    • Testing Filenames
    • System Environment Variables

    pwd


    The 'pwd' function returns the current working directory:

    (defun pwd ()
      (setdir "."))
    

    Ok, this function does not belong to the masterpieces of computer science, but (pwd) is much easier to remember than (setdir ".").

      Back to top


    cd


    The 'cd' function changes the current working directory. The directory name must be given as a string:

    (defun cd (string)
      (cond ((not (stringp string))
             (error "argument must be a string" string))
            ((string= "." string)
             (setdir "."))
            (t
             (let ((orig-dir (setdir "."))
                   (new-dir  (setdir string)))
               (when (string/= orig-dir new-dir)
                 new-dir)))))
    

    Possible actions and return values are:

    • It the argument is not a string, then an error will be raised.

    • If the directory name is ".", then the name of the current working directory is returned as a string. This is the same effect as if the directory has been changed to itself.

    • If the directory has successfully been changed to the given directory, then the name of the new working directory is returned as a string.

    • If the given directory has not been found, then NIL [= false] is returned.

      Back to top


    directory-exists-p


    The 'directory-exists-p' function tests if a directory exists. The directory name must be given as a string:

    (defun directory-exists-p (string)
      (cond ((not (stringp string))
             (error "argument must be a string" string))
            ((string= "." string)
             (setdir "."))
            (t
             (let ((orig-dir (setdir "."))
                   (new-dir  (setdir string)))
               (when (string/= orig-dir new-dir)
                 (setdir orig-dir)
                 new-dir)))))
    

    Possible actions and return values are:

    • It the argument is not a string, then an error will be raised.

    • If the directory name is ".", then the absolute name of the current working directory is returned as a string. This is not a very useful test, but makes the return values consistent.

    • If the directory has been found, then the absolute name of the directory is returned as a string.

    • If the directory has not been found, then NIL [= false] is returned.

    The 'directory-exists-p' function is nearly the same as the cd function above. The only difference is that the working directory will automatically be changed back to the initial directory.

    On Unix, with soft-links, the absolute name of the target directory [i.e. not the name of the link-file itself, but the name of the directory the link points to] is returned.

    Implementation Notes

    The Nyquist 'setdir' function always returns absolute directory names, even if a relative directory name has been given as a string by the user. That's why it's not possible to reliably compare the return value of (setdir string) directly with 'string'. Instead the absolute name of the initial working directory, returned by (setdir "."), is compared to the absolute name, returned when (setdir string) tries to change the directory. If both return values are the same, then (setdir string) has failed because the directory has not been found.

    If the directory string is ".", then this trick doesn't work, because the initial directory is the same as the target directory, so even if the directory has 'successfully' been changed to itself, both return values still would be the same. This is one of the reasons why "." has a separate 'cond' clause. The other reason is of course that it makes not really much sense to change a directory to itself, that's why we save the work and just return the absolute name of the current working directory.

      Back to top


    file-exists-p


    The 'file-exists-p' function tests if a file exists. The file name must be given as a string:

    (defun file-exists-p (string)
      (if (not (stringp string))
          (error "argument must be a string" string)
          (unless (directory-exists-p string)
            (let (file-stream)
              (unwind-protect
                (setq file-stream (open string))
                (when file-stream (close file-stream)))
              (when file-stream string)))))
    

    On Unix systems a directory is a special kind of file, so on Unix the XLisp 'open' function can open directories, too. That's why we first must make sure that no directory exists with the same name as the file that we are looking for.

      Back to top


    filename-exists-p


    (defun filename-exists-p (string)
      (if (not (stringp string))
          (error "argument must be a string" string)
          (or (directory-exists-p string)
              (file-exists-p string)))
    

      Back to top


    absolute-filename-p


    The 'absolute-filename-p' function tests if a string is an absolute file or directory name:

    (defun absolute-filename-p (string)
      (if (not (stringp string))
          (error "argument must be a string" string)
          (let ((end (length string)))
            (when (or (and (>= end 1)  ; Unix "/..."
                           (char= #\/ (char string 0)))
                      (and (>= end 3)  ; Windows "[a-zA-Z]:[\/]..."
                           (let ((char (char string 0)))
                             ;; upper- or lowercase character a-z, A-Z
                             (and (> (char-code (char-downcase char)) 96)
                                  (< (char-code (char-downcase char)) 123)))
                           (char= #\: (char string 1))
                           (let ((char (char string 2)))
                             (or (char= #\\ char)
                                 (char= #\/ char)))))
              string))))
    

    Note that it is only tested whether the beginning of the string matches the beginning of an absolute file or directory name. It is not tested whether the string reperesents a meaningful name.

      Back to top


    System Environment Variables


    get-env


    [This function works only with Audacity 1.3.13 and above.]

    (get-env "environment-variable")

      Back to top


    windows-p


    [This function works only with Audacity 1.3.13 and above.]

    The 'windows-p' function tests if the underlying operation system is a Microsoft Windows[tm] system:

    (defun windows-p ()
      (let* ((home (let ((drive (get-env "HOMEDRIVE"))
                         (path  (get-env "HOMEPATH")))
                     (if (and drive path)
                         (strcat drive path)
                         (get-env "UserProfile"))))
             (path (get-env "PATH")))
        (when home  ; if HOMEDRIVE + HOMEPATH or UserProfile exist
          (if path  ; search for Windows :\ drive-letter patterns
              (string-search ":\\" path)  
              (error "no PATH environment variable found")))))
    

    Nquist has a *file-separator* variable, that could be used much easier to detect the operation system:

    (defun windows-p ()
      (char= *file-separator* #\\))
    

      Back to top


    user-home-directory


    [This function works only with Audacity 1.3.13 and above.]

    The 'user-home-directory' function returns the path to the user's home directory on Linux, Mac, and Windows:

    (defun user-home-directory ()
      (or (get-env "HOME")
          (let ((drive (get-env "HOMEDRIVE"))
                (path  (get-env "HOMEPATH")))
            (when (and drive path)
              (strcat drive path)))
          (get-env "UserProfile")))
    

    If the user's home directory could be identified, then the path to the home directory is returned as a string. If the user's home directory could not be identified, then NIL [= false] is returned.

    Examples:

    (user-home-directory)  => "/home/edgar"                        ; Linux
    (user-home-directory)  => "C:\\Documents and Settings\\Edgar"  ; Windows
    

    On Windows there is no HOME variable defined by Windows itself, but most programs will respect a HOME variable, if one had been defined by the user. This means that on Windows, if a HOME variable exists, the HOME variable will be used instead of HOMEDRIVE and HOMEPATH or 'UserProfile'.

      Back to top


    expand-tilde


    [This function works only with Audacity 1.3.13 and above.]

    (defun expand-filename (string)
      (cond ((not (stringp string))
             (error "argument must be a string" string))
            ((and (> (length string) 1)
                     (char= #\~ (char string 0))
                     (or (char= #\/ (char string 1))
                         (char= #\\ (char string 1))))
             (strcat (user-home-directory)
                     (subseq string 1)))
            (t string)))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/macros.htm0000644000175000000620000002571111512762341022325 0ustar stevestaff Macros Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Macro Programming


    Note: The best book for Lisp macro programming is Paul Graham's 'On Lisp', available for free under:


    with-unique-names


    See http://www.cliki.net/WITH-UNIQUE-NAMES. This macro also appears in Chapter 11 of Paul Graham's On Lisp under the name 'with-gensyms'.

    (with-unique-names (symbols) body)
    symbols - a list of Lisp symbols, representing variable names
    body - some Lisp code to execute
    returns - the body with all symbols bound to different gensyms

    The 'with-unique-names' macro helps to avoid name clashes in Lisp macros.

    (defmacro with-unique-names (symbols &rest body)
      `(let ,(mapcar #'(lambda (x) `(,x (gensym))) symbols) ,@body))
    

    The 'with-unique-names' macro belongs to the category of write-only code. No matter how you write it, it's nearly impossible to understand its meaning by reading the macro definition. It's easier to understand if you look at the macro expansion:

    > (macroexpand-1 '(with-unique-names (a b c)
                        `(let ((,a 1) (,b 2) (,c 3))
                           (list ,a ,b ,c))))
    
    (let ((a (gensym)) (b (gensym)) (c (gensym)))
      `(let ((,a 1) (,b 2) (,c 3))
         (list ,a ,b ,c)))
    

    This translates in practice to the following idea:

    (let ((a (gensym)) (b (gensym)) (c (gensym)))  ; outside the expansion
      `(let ((gensym1 1) (gensym2 2) (gensym3 3))  ; inside the expansion
         (list gensym1 gensym2 gensym3)))
    

    The variable names 'a', 'b', and 'c' have been replaced inside the macro expansion by three gensyms. This way a variable name inside the macro expansion cannot accidentally collide with a variable of the same name in the environment of the macro's expansion like shown here:

    (defmacro print-macro (x)         ; bad example
      `(let ((macro-var 'macro))
         (print ,x)))
    
    > (let ((local-var 'let))         ; this works
        (print local-var)
        (print-macro local-var))
    LET  ; printed by PRINT
    LET  ; printed by PRINT-MACRO
    
    > (let ((macro-var 'let))         ; this doesn't
        (print macro-var)
        (print-macro macro-var))
    LET    ; printed by PRINT
    MACRO  ; printed by PRINT-MACRO
    

    The reason for this behaviour is that the 'print-macro' expands to:

    > (let ((local-var 'let))         ; this works
        (print local-var)
        (let ((macro-var 'macro))
          (print local-var)))
    LET  ; LOCAL-VAR inside the first LET
    LET  ; LOCAL-VAR inside the second LET
    
    > (let ((macro-var 'let))         ; this doesn't
        (print macro-var)
        (let ((macro-var 'macro))
          (print macro-var)))
    LET    ; MACRO-VAR inside the first LET
    MACRO  ; MACRO-VAR inside the second LET
    

    Now the same example with unique names. Note the comma before the 'macro-var' inside the let form of the macro definition:

    (defmacro print-macro (x)         ; good example
      (with-unique-names (macro-var)
        `(let ((,macro-var 'macro))
           (print ,x))))
    
    > (let ((macro-var 'let))         ; now it works
        (print macro-var)
        (print-macro macro-var))
    LET  ; printed by PRINT
    LET  ; printed by PRINT-MACRO
    

    The reason why it works is that the 'print-macro' now expands to:

    > (let ((macro-var 'let))         ; works
        (print macro-var)
        (let ((gensym 'macro))
          (print macro-var)))
    LET  ; MACRO-VAR inside the first LET
    LET  ; MACRO-VAR inside the second LET
    
    Now 'macro-var' can even be used as a variable name inside the macro definition without colliding with the 'macro-var' bound by let:
    (defmacro print-macro (x)         ; good example
      (with-unique-names (macro-var)
        `(let ((,macro-var 'macro))
           (print ,macro-var)
           (print ,x))))
    
    > (let ((macro-var 'let))         ; works
        (print macro-var)
        (print-macro macro-var))
    LET     ; MACRO-VAR printed inside LET
    MACRO   ; GENSYMed MACRO-VAR, printed inside PRINT-MACRO
    LET     ; MACRO-VAR bound by LET, printed inside PRINT-MACRO
    

    The expansion of the 'print-macro' shows why this works:

    > (let ((macro-var 'let))         ; works
        (print macro-var)
        (let ((gensym 'macro))
          (print gensym)
          (print macro-var)))
    LET     ; MACRO-VAR printed inside LET
    MACRO   ; GENSYMed MACRO-VAR printed inside PRINT-MACRO
    LET     ; MACRO-VAR bound by LET, printed inside PRINT-MACRO
    

    You can give as many variable names as you like to 'with-unique-names', the gensym management is done automatically:

    (defmacro print-macro (x y z)
      (with-unique-names (a b c)
        `(let ((,a 1) (,b 2) (,c 3))
           (format t "outside: a: ~a  b: ~a  c: ~a~%" ,x ,y ,z)
           (format t " inside: a: ~a  b: ~a  c: ~a~%" ,a ,b ,c))))
    
    > (let ((a 'a) (b 'b) (c 'c))
        (print-macro a b c))
    outside: a: A  b: B  c: C
     inside: a: 1  b: 2  c: 3
    

    Two things you still have to care about:

    1. The 'unique names' should not use the same smbol names as the parameter variables of the macro, otherwise you will have the same 'shadowing' effect like in ordinary Lisp functions. This is not a real problem because when writing a macro you can see the parameter names before your eyes, while you usually cannot see the variable names of the environment, where the macro will be expanded. You also do not have to care which variable names had been used in a macro if you call the macro from arbitrary Lisp code, where you usually cannot see the code of the macro definition.

    2. The local gensymed variables now themselves must be expanded by writing a comma in front of each when they appear inside a backquote scope. This sometimes can lead to tricky situations, because the comma expansion of the symbol does not produce the variable's value, instead it produces the name of the gensym, which holds the value. But this is a general phenomenon of gensyms in Lisp macro programming and not a bug of the 'with-unique-names' macro.

    The alternative would be writing:

    (defmacro print-macro (x y z)
      (let ((a (gensym)) (b (gensym)) (c (gensym)))
        `(let ((,a 1) (,b 2) (,c 3))
           (format t "outside: a: ~a  b: ~a  c: ~a~%" ,x ,y ,z)
           (format t " inside: a: ~a  b: ~a  c: ~a~%" ,a ,b ,c))))
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/examples/environment.htm0000644000175000000620000012575511512762341023416 0ustar stevestaff Environment Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Environment


    1. *unbound*
    2. Lexical Environment
    3. lboundp - [Macro] - has this symbol a lexical variable value bound to it?
      • valuep - [Macro] - has this symbol a valid variable value bound to it?
    4. lfboundp - [Macro] - has this symbol a lexical function value bound to it?
    5. lsymbol-value - [Macro] - get the lexical variable value
    6. lsymbol-function - [Macro] - get the lexical flet, labels, or macrolet function value
    7. lmacroexpand-1 - [Macro] - expand the first level of a a macrolet form
    8. Known Problems

    *unbound*


    A tricky problem with XLISP is that the symbol *unbound* can be bound as a value to any Lisp symbol, also to a lexical parameter variable if passed as a value to a Lisp function:

    (defun test (x)
      (print x))
    
    (test '*unbound*)  => error: unbound variable
    

    The problem here is that the symbol *unbound* has been bound to the parameter variable 'x', so the expression (print x) instead of printing "*UNBOUND*" now causes an 'unbound variable' error. How can I test from inside of a function if the lexical parameter variable 'x' is bound to the symbol *unbound*? Unfortunately there is no standard Lisp way to solve this problem.

      Back to top


    *obarray*


    A symbol in the *obarray* is protected from garbage collection.

      Back to top


    Lexical Environment


    Lisp parameter variables together with local variables bound with let and let* and functions defined by flet and labels are not interned in the *obarray*, instead they are stored in the local lexical environment, maintained via an internal association list. The key for reading this list is the *evalhook* variable and the evalhook function.

    Here are two Nyquist macros from 'evalenv.lsp':

    (defmacro getenv ()        ; return the current environment
      '(progv '(*evalhook*) (list #'(lambda (exp env) env))
         (eval nil)))
    
    (defmacro eval-env (arg)   ; evaluate in the current environment
      `(evalhook ,arg nil nil (getenv)))
    

      Back to top


    getenv


    The 'getenv' macro returns the association list of the current lexical environment:

    (let ((v1 1)          ; first variable
          (v2 2))         ; second variable
      (flet ((f1 (a) a)   ; first function
             (f2 (b) b))  ; second function
        (getenv)))
    
    => ((((V2 . 1) (V1 . 2))) ((F2 . #<Closure...>) (F1 . #<Closure...>)))
    

    The asymmetric layout is produced by print, the real structure of the lexical environment is a cons of two association lists:

    (defmacro print-env ()
      (let ((env (gensym)))
        `(let ((,env (getenv)))
           (format t "(~s . ~s)~%" (car ,env) (cdr ,env)))))
    

    Note: You could also use print-cons instead of format to print really all the details of the list, but format is enough for the examples here.

    (let ((v1 1)          ; first variable
          (v2 2))         ; second variable
      (flet ((f1 (a) a)   ; first function
             (f2 (b) b))  ; second function
        (print-env)))
    
    ((((V2 . 2) (V1 . 1))) . (((F2 . #<Closure...>) (F1 . #<Closure...>))))
    

    The basic layout is:

    ((((V2 . value) (V1 . value))) . (((F2 . value) (F1 . value))))
    
    ((<----- variable-list ----->) . (<----- function-list ----->))
    
    (car (getenv))  => (variable-list)
    (cdr (getenv))  => (function-list)
    

    The different levels of bindings are maintained via multiple sublists:

    (let ((v1 1))             ; first level variable
      (let ((v2 2))           ; second level variable
        (flet ((f1 (a) a))    ; first level function
          (flet ((f2 (b) b))  ; second level function
            (print-env)))))
    
    ((((V2 . value)) ((V1 . value))) . (((F2 . value)) ((F1 . value))))
    
    (((<--level2-->) (<--level1-->)) . ((<--level2-->) (<--level1-->)))
    ((<------ variable-list ------>) . (<------ function-list ------>))
    

    Variables appear always in the variable list, functions always in the function list:

    (let ((v1 1))             ; first level variable
      (flet ((f1 (a) a))      ; first level function
        (let ((v2 2))         ; second level variable
          (flet ((f2 (b) b))  ; second level function
            (print-env)))))
    
    ((((V2 . value)) ((V1 . value))) . (((F2 . value)) ((F1 . value))))
    
    (((<--level2-->) (<--level1-->)) . ((<--level2-->) (<--level1-->)))
    ((<------ variable-list ------>) . (<------ function-list ------>))
    

    The inner-most bindings always appear at the front of the lists:

    (let ((v1 1))             ; first level variable
      (let ((v2 2))           ; second level variable
        (flet ((f1 (a) a))    ; first level function
          (flet ((f2 (b) b))  ; second level function
            (let ((v3 3))     ; third level variable
              (print-env))))))
    
    ((((V3 . value)) ((V2 . value)) ((V1 . value))) . (((F2 . value)) ((F1 . value))))
    
    (((<--level3-->) (<--level2-->) (<--level1-->)) . ((<--level2-->) (<--level1-->)))
    ((<------------- variable-list -------------->) . (<------ function-list ------>))
    

    There may appear several variable bindings in the same sublist:

    (let ((v1 1) (v2 2))      ; first level variables
      (flet ((f1 (a) a)       ; first level functions
             (f2 (b) b))
        (let ((v3 3))         ; second level variable
          (print-env))))
    
    ((((V3 . value)) ((V2 . value) (V1 . value))) . (((F2 . value) (F1 . value))))
    
    (((<--level2-->) (<--------level1--------->)) . ((<---------level1-------->)))
    ((<------------ variable-list ------------->) . (<----- function-list ----->))
    

    The basic principle is always the same:

    (((level n ...) ... (level 1 variables)) . ((level n ...) ... (level 1 functions)))
    
    (car (getenv))  => ((level n ...) (level n-1 ...) ... (level 1 variables))
    (cdr (getenv))  => ((level n ...) (level n-1 ...) ... (level 1 functions))
    

    Also the function parameter variables appear in the the lexical environment association list:

    (defun test (parameter-var)
      (let ((local-var 'value))
        (print-env)))
    
    ((((LOCAL-VAR . value)) ((PARAMETER-VAR . value))) . NIL)  ; NIL = no functions
    
    (((<-----level2------>) (<-------level1-------->)) . NIL)
    ((<--------------- variable-list --------------->) . NIL)
    

    The variables bound by let appear before the function's parameter variables, that's why let bindings 'shadow' parameter variables with the same name. The 'test' function name does not appear in the environment list because the function name was interned in the *obarray* by defun.

      Back to top


    eval-env


    This still doen't work:

    (setq x 'global)        ; define a global variable 'x'
    
    (defun print-x ()       ; define a function PRINT-X in the global environment
      (print (getenv))      ; always prints ((NIL)), also with EVAL-ENV or EVALHOOK
      (print x))            ; always prints GLOBAL, also with EVAL-ENV or EVALHOOK
    
    (let ((x 'local))       ; create a lexical variable 'x'
      (print-x))            ; evaluate PRINT-X
    => GLOBAL               ; value from the environment, where PRINT-X was defined
    
    (let ((x 'local))       ; create a lexical variable 'x'
      (eval-env (print-x))  ; evaluate PRINT-X in the current environment
    => GLOBAL  ;wrong       ; value from the environment, where PRINT-X was called
    
    (let ((x 'local))       ; create a lexical variable 'x'
      (eval-env (funcall 'print-x))  ; evaluate PRINT-X in the current environment
    => GLOBAL  ;wrong       ; value from the environment, where PRINT-X was called
    

      Back to top


    lboundp


    The 'lboundp' function tests if a valid variable value is bound to a symbol in the current lexical environment:

    (lboundp symbol)
    symbol - a quoted lisp symbol
    returns -  T  if a lexical variable value is bound to the symbol, NIL otherwise

    (defmacro lboundp (symbol)
      (cond ((not (or (symbolp symbol)
                      (and (consp symbol)
                           (eq 'quote (car symbol))
                           (symbolp (cadr symbol)))))
             (error "bad argument type" symbol))
            ((and (consp symbol) (cddr symbol))
             (error "too many arguments"))
            (t (let ((a-cons (gensym)) (level (gensym)) (binding (gensym)))
                 `(let ((,a-cons (dolist (,level (car (getenv)) nil)
                                   (let ((,binding (assoc ,symbol ,level)))
                                     (when ,binding (return ,binding))))))
                    (and ,a-cons (not (eq (cdr ,a-cons) '*unbound*))))))))
    

    The XLISP boundp function only can test global variables, interned in the *obarray*, so it cannot be used to test if a symbol has a variable value bound to it in the lexical environment:

    (defun test (x)    ; bad example
      (if (boundp 'x)  ; <- global test
          (print x)
          (print '*unbound*)))
    
    (test 'hello!)     => *UNBOUND*  ; bad result
    (test 123)         => *UNBOUND*  ; bad result
    
    (setq x t)         => T          ; create a global variable 'x'
    
    (test 'hello!)     => 'HELLO!    ; OK
    (test 123)         => 123        ; OK
    (test '*unbound*)  => error: unbound variable - X  ; bad result
    

    Here the same example with 'lboundp':

    (defun test (x)     ; good example
      (if (lboundp 'x)  ; <- local test
          (print x)
          (print '*unbound*)))
    
    (test 'hello!)     => 'HELLO!    ; OK
    (test 123)         => 123        ; OK
    (test '*unbound*)  => *UNBOUND*  ; OK
    

    The 'lboundp' function cannot test symbol values at the top-level, because there is no lexical environment:

    (setq x t)    => T   ; create a global variable 'x'
    (lboundp 'x)  => NIL ; lexical test fails
    (boundp 'x)   => T   ; global test succeeds
    

      Back to top


    valuep


    The 'valuep' function tests if a valid variable value is bound to a symbol at any level:

    (defmacro valuep (symbol)
      (cond ((not (or (symbolp symbol)
                      (and (consp symbol)
                           (eq 'quote (car symbol))
                           (symbolp (cadr symbol)))))
             (error "bad argument type" ,symbol))
            ((and (consp symbol) (cddr symbol))
             (error "too many arguments"))
            (t (let ((a-cons (gensym)) (level (gensym)) (binding (gensym)))
                 `(let ((,a-cons (dolist (,level (car (getenv)) nil)
                                   (let ((,binding (assoc ,symbol ,level)))
                                     (when ,binding (return ,binding))))))
                    (if ,a-cons
                        (not (eq (cdr ,a-cons) '*unbound*))
                        (boundp ,symbol)))))))
    

    It's tricky to test if a symbol has a valid variable value bound to it because if the symbol is bound to *unbound* in a lexical environment, it still shadows a symbol with the same name in the *obarray*, making a possibly existing global variable inaccessible, like shown in the examples below.

    Note: The lexical environment must be tested first, because this is the way how XLISP searches for symbol bindings.

    Examples:

    (when (valuep 'x) x)  => NIL  ; no global binding of 'x' found
    (setq x 'ok)          => OK   ; create a global variable 'x'
    (when (valuep 'x) x)  => OK   ; global binding of 'x' found
    
    (let ((x 'local))             ; create a lexical variable 'x'
      (when (valuep 'x) x))       ; try to access the lexical variable
    => LOCAL                      ; lexical binding of 'x' found
    

    XLISP problems with *unbound* lexical variables:

    (setq x 'ok)          => OK   ; create a global variable 'x'
    (when (valuep 'x) x)  => OK   ; global binding of 'x' found
    
    (let ((x '*unbound*))         ; create an unbound lexical variable 'x'
      (when (valuep 'x) x))       ; try to access the global variable
    => NIL                        ; global binding of 'x' NOT found
    
    (let ((x '*unbound*))         ; create an unbound lexical variable 'x'
      x)                          ; try to access the global variable
    error: unbound variable - X
    

    The 'valuep' function recognizes if a global variable value is shadowed by an *unbound* lexical variable and returns NIL if the global variable is inaccessible..

      Back to top


    lfboundp


    The 'lfboundp' function tests if a valid function value is bound to a symbol in the current lexical environment:

    (lfboundp symbol)
    symbol - a quoted lisp symbol
    returns -  T  if a lexical function value is bound to the symbol, NIL otherwise

    (defmacro lfboundp (symbol)
      (cond ((not (or (symbolp symbol)
                      (and (consp symbol)
                           (eq 'quote (car symbol))
                           (symbolp (cadr symbol)))))
             (error "bad argument type" symbol))
            ((and (consp symbol) (cddr symbol))
             (error "too many arguments"))
            (t (let ((a-cons (gensym)) (level (gensym)) (binding (gensym)))
                 `(let ((,a-cons (dolist (,level (cdr (getenv)) nil)
                                   (let ((,binding (assoc ,symbol ,level)))
                                     (when ,binding (return ,binding))))))
                    (and ,a-cons (not (eq (cdr ,a-cons) '*unbound*))))))))
    

    The XLISP fboundp function only works with symbols interned in the *obarray*, so it cannot be used to test if a symbol has a function value bound to it in the lexical environment:

    (flet ((my-function (x) 'hello))
      (fboundp 'my-function))   ; <- global test
    => NIL
    
    (flet ((my-function (x) 'hello))
      (lfboundp 'my-function))  ; <- local test
    => T
    

    The 'lfboundp' function cannot test symbol function values at the top-level, because there is no lexical environment:

    (lfboundp 'car)  => NIL ; lexical test fails
    (fboundp 'car)   => T   ; global test succeeds
    

    Problems with *unbound* lexical functions are less likely then with *unbound* parameter variables, because there is no buit-in way to bind a lexical function to *unbound*.

    See also:

    • suprp - is this a built-in function?
    • fsubrp - is this a built-in special form?
    • closurep - is this a user-defined function or macro?
    • functionp - is this a build-in or a user-defined function?
    • macrop - is this a user-defined macro?

      Back to top


    lsymbol-value


    The function 'lsymbol-value' returns a variable value from the lexical environment:

    (defmacro lsymbol-value (symbol)
      (cond ((not (or (symbolp symbol)
                      (and (consp symbol)
                           (eq 'quote (car symbol))
                           (symbolp (cadr symbol)))))
             (error "bad argument type" symbol))
            ((and (consp ,symbol) (cddr symbol))
             (error "too many arguments"))
            (t (let ((a-cons (gensym)) (level (gensym)) (binding (gensym)))
                 `(let ((,a-cons (dolist (,level (car (getenv)) nil)
                                   (let ((,binding (assoc ,symbol ,level)))
                                     (when ,binding (return ,binding))))))
                    (when ,a-cons
                        (if (eq (cdr ,a-cons) '*unbound*)
                            '*unbound*
                            (cdr ,a-cons))))))))
    

      Back to top


    lsymbol-function


    The function 'lsymbol-function' returns a function value from the lexical environment:

    (defmacro lsymbol-function (symbol)
      (cond ((not (or (symbolp symbol)
                      (and (consp symbol)
                           (eq 'quote (car symbol))
                           (symbolp (cadr symbol)))))
             (error "bad argument type" symbol))
            ((and (consp symbol) (cddr symbol))
             (error "too many arguments"))
            (t (let ((a-cons (gensym)) (level (gensym)) (binding (gensym)))
                 `(let ((,a-cons (dolist (,level (cdr (getenv)) nil)
                                   (let ((,binding (assoc ,symbol ,level)))
                                     (when ,binding (return ,binding))))))
                    (when ,a-cons
                      (if (eq (cdr ,a-cons) '*unbound*)
                          '*unbound*
                          (cdr ,a-cons))))))))
    

    The XLISP function symbol-function only works with symbols interned in the *obarray*, so it cannot return a function value, bound to a symbol in the lexical environment:

    (flet ((my-function (x) 'hello))
      (symbol-function 'my-function))  ; <- searches the *obarray*
    => error: unbound function - MY-FUNCTION
    
    (flet ((my-function (x) 'hello))
      (lsymbol-function 'my-function)) ; <- searches the lexical environment
    => #<Closure-MY-FUNCTION...>
    

      Back to top


    lmacroexpand-1


    (defmacro with-static-env (&rest body)
      (let ((env (gensym)) (rval (gensym)))
        `(let ((,env (getenv)))  ; environment snapshot
           (progv '(*evalhook*)
                  '((lambda (exp env)
                     (labels ((,rval (exp env) ; recursive eval
                                (format t "exp: ~a env: ~a ,env: ~a~%" exp env ,env)
                                (evalhook exp #',rval NIL ,env)))
                       (format t "exp: ~a env: ~a ,env: ~a~%" exp env ,env)
                       (evalhook exp #',rval NIL ,env))))
             ,@body))))
    
    (defmacro with-dynamic-env (&rest body)
      (let ((env (gensym)) (rval (gensym)))
        `(let ((,env (getenv)))  ; environment snapshot
           (progv '(*evalhook*)
                  '((lambda (exp env)
                     (labels ((,rval (exp env) ; recursive eval
                                (format t "inner exp: ~a env: ~a~%" exp env)
                                (evalhook exp #',rval NIL env)))
                       (format t "outer exp: ~a env: ~a~%" exp env)
                       (evalhook exp #',rval NIL env))))
             ,@body))))
    
    (defun display-env (env &optional (exp nil exp-p))
      (flet ((display-bindings (name bindings)
        (format t " ~a bindings: ~s~%" name bindings)
        (let ((frame-counter 1))
          (dolist (frame bindings)
            (format t "  ~a frame ~a: ~a~%" name frame-counter frame)
            (let ((binding-counter 1))
              (dolist (binding frame)
                (when (consp binding)
                  (format t "   ~a ~a: ~s - value: ~s~%"
                      name binding-counter (car binding) (cdr binding))
                  (incf binding-counter))))
            (incf frame-counter)))))
        (when exp-p (format t "eval: ~s~%" exp))
        (format t "environment: ~s~%" env)
        (display-bindings "variable" (car env))
        (display-bindings "function" (cdr env))))
    
    (defmacro debug:env ()
      '(progv '(*evalhook*) '(nil)
         (display-env (getenv))))
    
    (defmacro debug:env ()
      '(progv '(*evalhook*) '((lambda (exp env)
                                (display-env env)))
         (eval nil)))
    
    (defmacro debug:env (&rest body)
      (when *evalhook*
        (format t "DEBUG:ENV ")
        (format t "*evalhook* was already modified~%"))
      (if (null body)
          '(progv '(*evalhook*) '((lambda (exp env)
                                    (display-env env)))
             (eval nil))
          (let ((init (gensym)) (rval (gensym)))
            `(let ((,init (getenv)))  ; environment snapshot
               (progv '(*evalhook*)
                      '((lambda (exp env)
                         (labels ((,rval (exp env) ; recursive eval
                                    (display-env env exp)
                                    (evalhook exp #',rval nil env)))
                           (display-env ,init exp)
                           (evalhook exp #',rval nil ,init))))
                 ,@body)))))
    
    (defmacro with-evalhook (&rest body)
      (let ((init (gensym)) (rval (gensym)) (hook (gensym)) debug)
        `(let ((,init (getenv)))  ; environment snapshot
           (progv '(*evalhook*)
                  '((lambda (exp env)
                     (labels ((,rval (exp env)  ; recursive eval
                                ,(print *evalhook*)
                                ,(when T `(funcall ,*evalhook* exp env))
    
                                (evalhook exp #',rval nil env)))
                       (evalhook exp #',rval nil ,init))))
             ,@body))))
    
    (defmacro with-current-environment (&rest body)
      (when *evalhook* (error "*evalhook* already modified"))
      (let ((init (gensym)) (rval (gensym)) debug)
        (when (eq :debug (car body)) (setq debug t body (cdr body)))
        `(let ((,init (getenv)))  ; environment snapshot
           (progv '(*evalhook*)
                  '((lambda (exp env)
                     (labels ((,rval (exp env)  ; recursive eval
                                ;; append environment from snapshot
                                (setq env (cons (append (car env) (car ,init))
                                                (append (cdr env) (cdr ,init))))
                                ,(when debug '(display-env env exp))
                                (evalhook exp #',rval nil env)))
                       ;; start with environment snapshot
                       ,(when debug `(display-env ,init exp))
                       (evalhook exp #',rval nil ,init))))
             ,@body))))
    
    (defmacro with-env (&rest body)
      (let ((init (gensym)) (rval (gensym)))
        `(let ((,init (getenv)))  ; environment snapshot
           (progv '(*evalhook*)
                  '((lambda (exp env)
                     (labels ((,rval (exp env) ; recursive eval
                                (display-env env exp)
                                (evalhook exp #',rval nil env)))
                       (display-env ,init exp)
                       (evalhook exp #',rval nil ,init))))
             ,@body))))
    
    (with-current-environment
      (debug:env
        body))
    
    (progv '(*evalhook)
           '((lambda (exp env)
               (labels ((rval (exp env)
                          (append-current-environment)
                          (debug:env ...)
                          (evalhook exp #'rval nil env)))
                 (evalhook exp #'rval nil init)))))
    
    (debug:env
      (with-current-environment
        body))
    
    (progv '(*evalhook)
           '((lambda (exp env)
               (labels ((rval (exp env)
    
    (defmacro with-current-environment (&rest body)
      (when *evalhook* (error "*evalhook* already modified"))
      (let ((debug nil) (init (gensym)) (rval (gensym)))
        (when (eq :debug (car body)) (setq debug t body (cdr body)))
        `(let ((,init (getenv)))  ; environment snapshot
           (progv '(*evalhook*)
                  '((lambda (exp env)
                     (labels ((,rval (exp env)  ; recursive eval
                                ,(cond (debug
                                        `(setq env
                                           (cons (append (car env) (car ,init))
                                                 (append (cdr env) (cdr ,init))))
                                        '(display-env env exp)
                                        `(evalhook exp #',rval nil env))
                                       (t
                                        `(evalhook exp #',rval nil
                                           (cons (append (car env) (car ,init))
                                                 (append (cdr env) (cdr ,init))))))))
                       ,(when debug `(display-env ,init exp))
                       (evalhook exp #',rval nil ,init))))
             ,@body))))
    
    (setq *rvalhook* nil)
    
    (defmacro with-current-environment (&rest body)
      (let ((init (gensym)))
        `(let ((,init (getenv)))
           (rval-env #'(lambda (exp env)
                         (cons exp (cons (append (car env) (car ,init))
                                         (append (cdr env) (cdr ,init)))))
                     ,@body))))
    
    (defmacro debug:env (&rest body)
      (rval-env #'(lambda (exp env)
                    (display-env env exp)
                    (cons exp env))
                ,@body))
    
    (defmacro run-rvalhooks ()
      (let ((func (gensym)) (result (gensym)))
        `(dolist (,func *rvalhook*)
           (format t "func: ~a~%" ,func)
           (format t "exp: ~a~%" exp)
           (format t "env: ~a~%" env)
           (let ((,result (eval (list ,func 'exp 'env) )))
             (format t "result: ~a~%" ,result)
             (format t "exp: ~a~%" exp)
             (format t "car: ~a~%" (car ,result))
             (format t "env: ~a~%" env)
             (format t "cdr: ~a~%" (cdr ,result))
             (setq exp (car ,result) env (cdr ,result)) 
      ))))
    
    (defmacro rval-env (function &rest body)
      (format t "function: ~a~%" function)
      (format t "body: ~a~%" body)
      (or *evalhook* (setq *rvalhook* nil))
      (format t "*rvalhook*: ~a~%" *rvalhook*)
      (if *rvalhook*
          `(prog2
             (push ,function *rvalhook*)
             (progn ,@body)
             (setq *rvalhook* (remove ,function *rvalhook*)))
          (let ((rval (gensym)) (func (gensym)) (result (gensym)))
            `(prog2
               (push ,function *rvalhook*)
               (progv '(*evalhook*)
                      `((lambda (exp env)
                          (print 'hallo)
                          (labels ((,rval (exp env)
                                     (run-rvalhooks)
                                     (evalhook exp #',rval nil env)))
                            ; (run-rvalhooks)
                            (evalhook exp #',rval nil env))))
                 ,@body)
               (setq *rvalhook* (remove ,function *rvalhook*))))))
    

    *rvalhook* must be a list of functions, each taking two arguments 'exp' [the Lisp expressions to evaluate] and 'env' [the environment], returning a cons of the format (exp . env).

    In case of an error, the *evalhook* variable is automatically reset by the XLISP top-level function. This means that if *evalhook* is NIL and *rvalhook* is non-NIL, then *rvalhook* is invalid and must also be reset to NIL before pushing the next function on it.

    (defmacro lmacroexpand-1 (form)
      (if (not (and (consp form)
                    (eq 'quote (car form))
                    (symbolp (caadr form))))
          form  ; if the form isn't '(symbol ... )
          (let ((a-cons (gensym)) (l-expr (gensym)))
            `(let ((,a-cons (assoc ',(caadr form) (cadr (getenv)))))
               (if (null ,a-cons)  ; (caadr form) = macro-name
                   ,form  ; if no lexical binding was found
                   (let ((,l-expr (get-lambda-expression (cdr ,a-cons))))
                     (if (eq 'macro (car ,l-expr)) ; if l-expr is a macro
                         (with-current-environment
                           ;; create an *unbound* macro in the *obarray*
                           (eval (append '(defmacro *unbound*) (cdr ,l-expr)))
                           ;; expand the macro in the current environment
                           (eval (list 'macroexpand-1  ; (cdadr form) =
                                       (list 'quote    ; macro-arguments as list
                                             (cons '*unbound* ',(cdadr form))))))
                         ,form)))))))  ; if l-expr is not a macro
    
    (let ((x 1))
      (macrolet ((test (arg)
                   `(progn
                      (print ,arg)
                      (print ,(eval x)))))
        (lmacroexpand-1 '(test 'hallo))))
    =>
    

      Back to top


    Known Problems


    A lexical variable with the symbol *unbound* as a variable value bound to it will continue to shadow a global variable with the same name, even if the the lexical variable is 'unbound':

    (setq x t)  => T        ; create a global variable 'x'
    
    (let ((x '*unbound*))   ; create an unbound lexical variable 'x'
      (print x))            ; try to print the global variable
    error: unbound variable - X
    

    Tested with Nyquist 3.03 in December 2010.

    Nyquist Bug: let* causes infinite recursion problems with either progv, evalhook, or *evalhook* [still needs more investigation], so this doesnt work:

    (let* ((init (getenv)))
      (progv '(*evalhook*)
             '((lambda (exp env)
                 (labels ((rval (exp env)
                            (print init)  ; <- causes infinite recursion
                            (evalhook exp #'rval nil env)))
                   (evalhook exp #'rval nil init))))
        (eval nil)))
    => infinite recursion
    
    while exactly the same form using let instead of let* works:
    (let ((init (getenv)))
      (progv '(*evalhook*)
             '((lambda (exp env)
                 (labels ((rval (exp env)
                            (print init)  ; <- no infinite recursion
                            (evalhook exp #'rval nil env)))
                   (evalhook exp #'rval nil init))))
        (eval nil)))
    (NIL)  ; PRINT output
    => NIL
    

    Bug tested with Nyquist 3.03 in December 2010.

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/misc/0002755000175000000620000000000011537433125017442 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/misc/ascii-table.htm0000644000175000000620000012442111512762341022331 0ustar stevestaffASCII Character Set Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    The ASCII Character Set


    The standard ASCII character set uses only 7 bits of the 8 bit byte for each character. There are several larger character sets that use all 8 bits of the byte, which gives them an 128 additional characters in the set. The extra characters are used to represent characters not used in the English language, graphics characters or symbols, and mathematical representations or symbols.

    ASCII Control Characters

    ASCII control characters are actually commands for the terminal, monitor, computer, I/O devices, printer or other peripherals to do something. The first 32 values are non-printing control characters, such as 'carriage return' and 'line feed'. You generate these characters on the keyboard by holding down the 'control' key while you strike another key. These characters are also capable of being sent to the device by a software sequence, most often by a program. They are usually sent as a string of characters following an attention character, usually 'escape', but not always.

    ASCII Control Characters

    Char Oct Dec Hex Ctrl-key XLISP
    NUL 0 0 0 Ctrl+@   -  null character
    SOH 1 1 1 Ctrl+a   -  start of heading
    STX 2 2 2 Ctrl+b   -  start of text
    ETX 3 3 3 Ctrl+c   -  end of text
    EOT 4 4 4 Ctrl+d   -  end of transmission
    ENQ 5 5 5 Ctrl+e   -  enquiry
    ACK 6 6 6 Ctrl+f   -  acknowledge
    BEL 7 7 7 Ctrl+g   -  rings terminal bell
    Char Oct Dec Hex Ctrl-key XLISP
    BS 10 8 8 Ctrl+h   -  backspace (non-destructive)
    HT 11 9 9 Ctrl+i #\Tab   -  horizontal tab
    LF 12 10 A Ctrl+j #\Newline   -  line feed
    VT 13 11 B Ctrl+k   -  vertical tab
    FF 14 12 C Ctrl+l   -  form feed
    CR 15 13 D Ctrl+m   -  carriage return
    SO 16 14 E Ctrl+n   -  shift out
    SI 17 15 F Ctrl+o   -  shift in
    Char Oct Dec Hex Ctrl-key XLISP
    DLE 20 16 10 Ctrl+p   -  data link escape
    DC1 21 17 11 Ctrl+q   -  device control 1, normally 'xon'
    DC2 22 18 12 Ctrl+r   -  device control 2
    DC3 23 19 13 Ctrl+s   -  device control 3, normally 'xoff'
    DC4 24 20 14 Ctrl+t   -  device control 4
    NAK 25 21 15 Ctrl+u   -  negative acknowledge
    SYN 26 22 16 Ctrl+v   -  synchronous idle
    ETB 27 23 17 Ctrl+w   -  end transmission block
    Char Oct Dec Hex Ctrl-key XLISP
    CAN 30 24 17 Ctrl+x   -  cancel line
    EM 31 25 19 Ctrl+y   -  end of medium
    SUB 32 26 1A Ctrl+z   -  substitute
    ESC 33 27 1B Ctrl+[   -  escape
    FS 34 28 1C Ctrl+\   -  file separator
    GS 35 29 1D Ctrl+]   -  group separator
    RS 36 30 1E Ctrl+^   -  record separator
    US 37 31 1F Ctrl+_   -  unit separator
    Char Oct Dec Hex Ctrl-key XLISP

    ASCII Printing Characters

    Char Oct Dec Hex XLISP
      40 32 20 #\Space   -  space
    ! 41 33 21 #\!   -  exclamation mark
    " 42 34 22 #\"   -  quotation mark
    # 43 35 23 #\#   -  cross hatch, number sign
    $ 44 36 24 #\$   -  dollar sign
    % 45 37 25 #\%   -  percent sign
    & 46 38 26 #\&   -  ampersand
    ` 47 39 27 #\`   -  backquote, apostrophe
    Char Oct Dec Hex XLISP
    ( 50 40 28 #\(   -  opening parentheses
    ) 51 41 29 #\)   -  closing parentheses
    * 52 42 2A #\*   -  asterisk, star, multiply
    + 53 43 2B #\+   -  plus
    , 54 44 2C #\,   -  comma
    - 55 45 2D #\-   -  hyphen, dash, minus
    . 56 46 2E #\.   -  period
    / 57 47 2F #\/   -  slash forward, divide
    Char Oct Dec Hex XLISP
    0 60 48 30 #\0   -  zero
    1 61 49 31 #\1   -  one
    2 62 50 32 #\2   -  two
    3 63 51 33 #\3   -  three
    4 64 52 34 #\4   -  four
    5 65 53 35 #\5   -  five
    6 66 54 36 #\6   -  six
    7 67 55 37 #\7   -  seven
    Char Oct Dec Hex XLISP
    8 70 56 38 #\8   -  eight
    9 71 57 39 #\9   -  nine
    : 72 58 3A #\:   -  colon
    ; 73 59 3B #\;   -  semicolon
    < 74 60 3C #\<   -  less than sign
    = 75 61 3D #\=   -  equals sign
    > 76 62 3E #\>   -  greater than sign
    ? 77 63 3F #\?   -  question mark
    Char Oct Dec Hex XLISP
    @ 100 64 40 #\@   -  at-sign
    A 101 65 41 #\A   -  upper case A
    B 102 66 42 #\B   -  upper case B
    C 103 67 43 #\C   -  upper case C
    D 104 68 44 #\D   -  upper case D
    E 105 69 45 #\E   -  upper case E
    F 106 70 46 #\F   -  upper case F
    G 107 71 47 #\G   -  upper case G
    Char Oct Dec Hex XLISP
    H 110 72 48 #\H   -  upper case H
    I 111 73 49 #\I   -  upper case I
    J 112 74 4A #\J   -  upper case J
    K 113 75 4B #\K   -  upper case K
    L 114 76 4C #\L   -  upper case L
    M 115 77 4D #\M   -  upper case M
    N 116 78 4E #\N   -  upper case N
    O 117 79 4F #\O   -  upper case O
    Char Oct Dec Hex XLISP
    P 120 80 50 #\P   -  upper case P
    Q 121 81 51 #\Q   -  upper case Q
    R 122 82 52 #\R   -  upper case R
    S 123 83 53 #\S   -  upper case S
    T 124 84 54 #\T   -  upper case T
    U 125 85 55 #\U   -  upper case U
    V 126 86 56 #\V   -  upper case V
    W 127 87 57 #\W   -  upper case W
    Char Oct Dec Hex XLISP
    X 130 88 58 #\X   -  upper case X
    Y 131 89 59 #\Y   -  upper case Y
    Z 132 90 5A #\Z   -  upper case Z
    [ 133 91 5B #\[   -  opening square bracket
    \ 134 92 5C #\\   -  backslash, reverse slant
    ] 135 93 5D #\]   -  closing square bracket
    ^ 136 94 5E #\^   -  caret, circumflex
    _ 137 95 5F #\_   -  underscore
    Char Oct Dec Hex XLISP
    ` 140 96 60 #\`   -  opening single quote
    a 141 97 61 #\a   -  lower case a
    b 142 98 62 #\b   -  lower case b
    c 143 99 63 #\c   -  lower case c
    d 144 100 64 #\d   -  lower case d
    e 145 101 65 #\e   -  lower case e
    f 146 102 66 #\f   -  lower case f
    g 147 103 67 #\g   -  lower case g
    Char Oct Dec Hex XLISP
    h 150 104 68 #\h   -  lower case h
    i 151 105 69 #\i   -  lower case i
    j 152 106 6A #\j   -  lower case j
    k 153 107 6B #\k   -  lower case k
    l 154 108 6C #\l   -  lower case l
    m 155 109 6D #\m   -  lower case m
    n 156 110 6E #\n   -  lower case n
    o 157 111 6F #\o   -  lower case o
    Char Oct Dec Hex XLISP
    p 160 112 70 #\p   -  lower case p
    q 161 113 71 #\q   -  lower case q
    r 162 114 72 #\r   -  lower case r
    s 163 115 73 #\s   -  lower case s
    t 164 116 74 #\t   -  lower case t
    u 165 117 75 #\u   -  lower case u
    v 166 118 76 #\v   -  lower case v
    w 167 119 77 #\w   -  lower case w
    Char Oct Dec Hex XLISP
    x 170 120 78 #\x   -  lower case x
    y 171 121 79 #\y   -  lower case y
    z 172 122 7A #\z   -  lower case z
    { 173 123 7B #\{   -  opening curly brace
    | 174 124 7C #\|   -  vertical line
    } 175 125 7D #\}   -  closing curly brace
    ~ 176 126 7E #\~   -  tilde, approximate
    DEL 177 127 7F   -  delete, cross-hatch box
    Char Oct Dec Hex XLISP


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/misc/links.htm0000644000175000000620000000715511512762341021300 0ustar stevestaff Lisp Links Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Lisp Links


    The most helpful book to learn XLISP I found 'Common Lisp, A Gentle Introduction to Symbolic Computation' by David Touretzky, mentioned in the Nyquist manual by Roger Dannenberg. The book can be downloaded for free from:

    It's a book about Lisp in general, not only about Common Lisp, explaining and helping a lot to understand the the fundamental principles of Lisp programming.

    Unfortunately there seems to be no specific information source about XLISP programming in the internet [beside the David Betz manual and the Tim I Mikkelsen documents], probably because most Lisp dialects have been merged into the Common Lisp standard in the 1980s and 1990s.

    As a result of this I first had to learn Common Lisp to be able to re-construct how the examples in all the books could work with XLISP. This was a quite tedious way to learn and the main reason to start this document collection.


    XLISP links


    The official XLISP homepage is:

    The official Nyquist homepage is:


    Common Lisp links


    Copies of 'Common Lisp, the Language, 2nd Edition' by Guy Steele [known as 'CltL2'] can be downloaded in various formats for free from the CMU archives:

    It is a quite huge book explaining all details and discussions about the Common Lisp standard and is a real good Common Lisp information source. Unfortunately it is not very useful for learning XLISP out of it.

    The most recent document about the Common Lisp standard is the 'Common Lisp Hypespec' [re-worked in 2005]. It is available for online reading under:

    or as a 'tar.gz' package for offline reading from:

    If you have no idea how to deal with 'tar.gz' packages on Windows computers and the 'tar.gz' file doesn't open automatically by clicking on it, the probably most easiest way is using the '7-zip' program available for free from:



    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/misc/preface.htm0000644000175000000620000001210411512762341021553 0ustar stevestaff XLISP Preface Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Preface


    This is a collection of documents about 'XLISP 2.0' as a programming language in general. It is intended to be used together with Nyquist, a language for composition and sound synthesis. It includes the second re-work of the Tim I Mikkelsen 'XLISP Language Reference', linked against the original 'XLISP 2.0 Manual' by David Betz.

    Both manuals are linked against each other and intended to be used as 'one' manual. You can jump back and forth from a function description in the 'XLISP Manual' to the description in the 'Language Reference' and vice versa with ease.

    The navigation bar at the top and the bottom of each page need some explanation. From the left to right you will find the following links:

    • XLISP - always returns to the main page from everywhere, helping you to find your way back if you get lost in the information jungle.

    • XLISP 2.0 - opens the front page of the 'XLISP 2.0 Manual' by David Betz with links to all chapters so you can read it like a book.

    • Contents - opens the detailed contents page of the 'XLISP 2.0 Manual' with links to all functions and symbols sorted by topic.

    • Reference - opens the index page of the 'XLISP Language Reference' with links to all XLISP functions and symbols sorted in alphabetical order.

    • The Previous and Next links are a bit tricky. As expected they move to the previous and next pages, but in the 'XLISP 2.0 Manual' they move through the manual while in the 'XLISP Language Reference' they move through the reference. This needs some accustomisation but I have worked like this during the last few month and found it the best possible solution. You can always go back to the pages where you have been before by using the 'back' button of your browser.

    During the second re-work of the 'XLISP Language Reference' I have sorted out all functions that were related to 'XLISP 2.1' and 'XLISP Plus'. They can now be found on their own page under XLISP Plus Functions.

    I also have sorted out of the 'XLISP 2.0 Manual' all functions added by Nyquist to the XLISP interpreter to an extra page, for just the simple reason that unlike XLISP 2.0, Nyquist still evolves and it is easier to maintain a single page with Nyquist Functions than sixteen [or more] functions spread all over the manual.


    Things still to be done and how you can help:


    First of all, please note that this is a work in progress and not a final version. There probably still are bugs and quirks that need to be resolved and you can help by writing an e-mail to edgar-rft@web.de if you find some and I will try to fix it as soon as possible.

    This does not mean that these documents are 'overloaded with bugs' but XLISP was [and is] an experimental language that itself was re-worked several times and most of the time during the last months I was busy with sorting out what really matters out of the manuals I had collected over a period of two and a half years about several XLISP versions and mutations.

    In case of doubt I will prefer the Nyquist version of XLISP 2.0 because this is the version I work with most often and the original intention of this document collection was to support the Nyquist manual with better XLISP information.

    Also please note that I do not want to change the David Betz manual more than necessary, because I consider it as the most original information source. Instead I whould like to improve the 'XLISP Language Reference' by better explanations and source code examples. I also have not tested really *all* examples with Nyquist yet. If you find bugs please write me an email.

    If you have any further ideas or suggestions how these documents can be improved please write to edgar-rft@web.de.


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/misc/c-printf.htm0000644000175000000620000005031711512762341021700 0ustar stevestaff ANSI C 'printf' Format Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    ANSI C 'printf' Format


    Nyquist/XLISP: The *float-format* and *integer-format* variables define format strings for the underlying 'sprintf' C function. In C, the same format string specification is used for 'fprint' [writes to a file], 'printf' [writes to standard output] and 'sprintf' [writes to another string]. These three functions are meant in the following text with 'the printf functions'.

    ANSI C: The printf functions write output under control of a format string that specifies how subsequent arguments are converted for output. If there are insufficient arguments for the format, the behavior is undefined. If the format is exhausted while arguments remain, the excess arguments are evaluated but are otherwise ignored. The printf functions return when the end of the format string is encountered.

      Back to top


    Format String


    The format string is composed of zero or more directives, which are ordinary characters [except "%"], which are copied unchanged to the output stream, and conversion specifications, each of which results in fetching zero or more subsequent arguments. Each conversion specification is introduced by the character "%":

    %[flags][field-with][precision][data-type]conversion-type
    

    After the "%", the following appear in sequence:

    • Flags - Zero or more flags that modify the meaning of the conversion specification.

    • Field Width - An optional decimal integer specifying a minimum field width. If the converted value has fewer characters than the field width, it will be padded with spaces on the left to the field width. The field is padded on the right if the  −  flag has been given, or padded with zeros if the  0  flag had been given. A negative integer, given as 'field width' argument, is interpreted as a  −  flag followed by a positive field width.

    • Precision - An optional decimal integer that gives the minimum number of digits to appear for integer conversions, the number of digits to appear after the decimal-point character for floating-point  e  and  f  conversions, or the maximum number of significant digits for the floating-point  g  conversion.

      The precision takes the form of a period character followed by an optional decimal integer:

      .[integer]
      

      If the integer is omitted, it is treated as zero, a negative precision argument is taken as if it were missing.

      Note: In C, the precision also specifies the maximum number of characters to be written from a string in 's' conversion, but "%s" should not be used in the XLISP *float-format* or *integer-format* variables, otherwise XLISP will crash.

    • Data Type - An optional character specifying a data type to be used for the conversion.

      XLISP: Nyquist/XLISP uses C 'long' signed integers and C 'double' floats only, so with floating-point numbers no special data type needs to be given, while integer conversions should always be prefixed by a 'l' [lowercase L], otherwise the printed representation of integer numbers may be differently than the behaviour of the Nyquist/XLISP functions.

    • Conversion Type - A character that specifies the conversion type to be applied.

    Not with Nyquist/XLISP: In C, a 'field width' or 'precision', or both, may be indicated by an asterisk * instead of a digit string. In this case, an int argument supplies the field width or precision. The arguments specifying field width or precision, or both, shall appear [in that order] before the argument [if any] to be converted.

      Back to top


    Flags


    The flag characters and their meanings are:

    −  [minus sign character]

    The result of the conversion will be left-justified within the field.

    +  [plus sign character]

    The result of a signed conversion will always begin with a plus or minus sign.

    space  [space character]

    If the first character of a signed conversion is not a sign, or if a signed conversion results in no characters, a space will be prepended to the result. If the 'space' and  +  flags both appear, the 'space' flag will be ignored.

    #  [hash character]

    The result is to be converted to an 'alternate form':

    Octal Numbers - For o conversion, it increases the precision to force the first digit of the result to be a zero.

    Hexadecimal Numbers - For x or X conversion, a nonzero result will have 0x or 0X prepended to it.

    Floating-point Numbers - For e, E, f, g, and G conversions, the result will always contain a decimal-point character, even if no digits follow it (normally, a decimal-point character appears in the result of these conversions only if a digit follows it). For g and G conversions, trailing zeros will not be removed from the result. For other conversions, the behavior is undefined.

    0  [number zero character]

    For integer d, i, o, u, x, X, and floating-point e, E, f, g, G conversions, leading zeros [following any indication of sign or base] are used to pad to the field width. No space padding is performed. If the '0' and  −  flags both appear, the '0' flag will be ignored. For integer d, i, o, u, x, X conversions, if a precision is specified, the '0' flag will be ignored. For other conversions, the behavior is undefined.

      Back to top


    Data Type


    h  [lowercase H character]

    A following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument [the argument will have been promoted according to the integral promotions, and its value shall be converted to short int or unsigned short int before printing].

    A following n conversion specifier applies to a pointer to a short int argument.

    l  [lowercase L character]

    A following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int argument.

    A following n conversion specifier applies to a pointer to a long int argument.

    L  [uppercase L character]

    A following e, E, f, g, or G conversion specifier applies to a long double argument.

    If an h, l, or L appears with any other conversion specifier, the behavior is undefined.

      Back to top


    Conversion Type


    Integer conversion:

    d, i, o, u, x, X

    The integer argument is converted to:

       d  →  signed decimal
       i  →  signed decimal
       o  →  unsigned octal
       u  →  unsigned decimal
       x  →  unsigned hexadecimal, using 'abcdef'
       X  →  unsigned hexadecimal, using 'ABCDEF'

    The precision specifies the minimum number of digits to appear. If the value being converted can be represented in fewer digits, it will be expanded with leading zeros. The default precision is 1. The result of converting a zero value with an explicit precision of zero results in no characters.

    XLISP: Nyquist/XLISP uses C 'long' signed integers, so the integer conversions should always be prefixed by a 'l' [lowercase L] indicating a 'long int' C data type, otherwise the printed representation of integer numbers may be differently than the behaviour of the Nyquist/XLISP functions.

    Floating-point conversion:

    f

    The floating-point argument of C data type 'double' is converted to decimal notation in the style:

    [-]ddd.ddd
    

    The number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6. If the precision is explicitly zero, no decimal-point character appears. If a decimal-point character appears, at least one digit appears before it. The value is rounded to the appropriate number of digits.

    e, E

    The floating-point argument of C data type 'double' is converted in the style:

    [-]d.ddde+-dd
    

    There is one digit before the decimal-point character [which is nonzero if the argument is nonzero] and the number of digits after it is equal to the precision. If the precision is missing, it is taken as 6. If the precision is zero, no decimal-point character appears. The value is rounded to the appropriate number of digits. The exponent always contains at least two digits. If the value is zero, the exponent is zero. The "E" conversion specifier will produce a number with 'E' instead of 'e' introducing the exponent.

    g, G

    The floating-point argument of C data type 'double' is converted in style  f  or  e , or in style  E  in the case of a "G" conversion specifier, with the precision specifying the number of significant digits. If an explicit precision is zero, it is taken as 1. The style used depends on the value converted. Style  e  will be used only if the exponent resulting from such a conversion is less than -4 or greater than or equal to the precision. Trailing zeros are removed from the fractional portion of the result. A decimal-point character appears only if it is followed by a digit.

    If a conversion specification is invalid, the behavior is undefined. In no case does a nonexistent or small field width cause truncation of a field. If the result of a conversion is wider than the field width, the field is expanded to contain the conversion result.

    The minimum value for the maximum number of characters produced by any single conversion shall be 509.

      Back to top


    Other Conversion Types


    This section contains a list of all other conversion types defined in ANSI C.

    Warning: Do not use thse conversions with the XLISP *float-format* and *integer-format* variables, because XLISP will produce nonsense or just simply will crash. The XLISP behaviour described below was tested with Nyquist 3.03 in December 2010, compiled with GCC 4.3.2 and glibc 2.7 on Debian 5 [Lenny]. The behaviour may be different with different Nyquist or XLISP versions, different C compilers and/or libraries, or different operating systems.

    c

    ANSI C: The integer argument is converted to an 'unsigned char', and the resulting character is written.

    XLISP: If the *float-format* or *integer-format* is set to "%c", then the lowest 8 bit of the internal binary representation of the respective numbers will be printed as an ASCII character.

    s

    ANSI C: The argument shall be a pointer to an array of character type. Characters from the array are written up to [but not including] a terminating null character. If the precision is specified, no more than that many characters are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character.

    XLISP: If the *float-format* or *integer-format* is set to "%s" and XLISP tries to print a respective number, XLISP crashes.

    p

    ANSI C: The argument shall be a pointer to 'void'. The value of the pointer is converted to a sequence of printable characters, in an implementation-defined manner.

    XLISP: If the *float-format* is set to "%p", then floating-point numbers are printed as "(nil)". If the *integer-format* is set to "%p", the integer numbers are printed as hexadecimal numbers, prefixed with "0x".

    n

    ANSI C: The argument shall be a pointer to an integer into which is written the number of characters written to the output stream so far by this call to the C 'fprintf' function. No argument is converted.

    XLISP: If the *float-format* or *integer-format* is set to "%n" and XLISP tries to print a respective number, XLISP crashes.

    %

    ANSI C: A "%" is written. No argument is converted. The complete conversion specification shall be "%%".

    XLISP: If the *float-format* is set to "%g%%" or the *integer-format* is set to "%ld%%" then all respective numbers will be printed with a trailing "%".

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/0002755000175000000620000000000011537433126020446 5ustar stevestaffnyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-constituent.htm0000644000175000000620000000622211512762341025216 0ustar stevestaffXLISP :constituent Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :constituent


    Type:   -   keyword
    Source:   -   xlread.c

    Syntax

     :constituent

    Description

    ':constituent' is an entry that is used in the *readtable* system variable that contains XLISP's data structures relating to the processing of characters from the user [or files] and read-macro expansions. The existance of the ':constituent' keyword means that the specified character is to be used, as is, with no further processing. The system defines that the following characters are ':constituent' characters:

    0123456789
    !$%&*+-./:<=>?@[]^_{}~
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    abcdefghijklmnopqrstuvwxyz
    

    Examples

    (defun look-at (table)               ; define a function to
      (dotimes (ch 127)                  ;   look in a table
        (prog ((entry (aref table ch)))  ;   and print out any
          (case entry                    ;   entries with a function
            (:CONSTITUENT
              (princ (int-char ch)))
            (T NIL))))
      (terpri))
    
    (look-at *readtable*)                ; prints  !$%&*+-./0123456789
                                         ;         :<=>?@ABCDEFGHIJKLM
                                         ;         NOPQRSTUVWXYZ[]^_ab
                                         ;         cdefghijklmnopqrstu
                                         ;         vwxyz{}~
    

    Caution: If you experiment with *readtable* , it is useful to save the old value in a variable, so that you can restore the system state.

    See the :constituent keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/peek-char.htm0000644000175000000620000001011111512762341023004 0ustar stevestaffXLISP peek-char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    peek-char


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (peek-char [skip-flag [source]])
    skip-flag - an optional expression, default is NIL
    source - an optional source, must be a file pointer or stream, default is *standard-input*
    returns - the character

    Description

    The 'peek-char' function looks at a single character from the specified 'source'. The character looked-at is returned as an integer value for the result. If the 'skip-flag' expression is NIL , then the next character will be looked-at, without advancing the position within the file. If the 'skip-flag' expression is non-NIL , then the next non-white-space character will be looked-at. This skipping does advance the position within the file. White-space characters include 'blank', 'tab' and 'new-line' characters. If 'skip-flag' is not used, no skipping will occur. The 'source' may be a file pointer or a stream. If there is no 'source', *standard-input* is the default. If an end-of-file is encountered in the 'source', then NIL will be returned as the result.

    Examples

    (setq fp (open "f" :direction :output))  ; create file "f"
    (print 12 fp)
    (princ "  34" fp)
    (terpri fp)
    (close fp)
    
    (setq fp (open "f" :direction :input))   ; open "f" for reading
    (peek-char NIL fp)                       ; returns #\1
    (peek-char NIL fp)                       ; returns #\1 - didn't advance
    (read-char fp)                           ; returns #\1 - force advance
    (peek-char NIL fp)                       ; returns #\2
    (read-char fp)                           ; returns #\2 - force advance
    (peek-char NIL fp)                       ; returns #\Newline
    (peek-char T fp)                         ; returns #\3 - skipped blanks
    (read-line fp)                           ; returns "34"
    (close fp)
    

    Common Lisp: The XLISP and Common Lisp 'peek-char' functions are compatible for simple cases. They both allow for the optional 'skip-flag' and 'source'. However, in Common Lisp, there are additional parameters which occur right after 'source' that support various end-of-file operations and recursive calls. So, when porting from Common Lisp to XLISP, remember there are additional arguments in Common Lisp's 'peek-char' that are not supported in XLISP.

    See the peek-char function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/exp.htm0000644000175000000620000000423011512762341021746 0ustar stevestaffXLISP exp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    exp


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (exp power)
    power - floating point number/expression
    returns - e to the x power

    Description

    The 'exp' function calculates e [2.7128] raised to the specified 'power' and returns the result.

    Examples

    (exp 0.0)   ; returns 1
    (exp 1.0)   ; returns 2.71828 - e
    (exp 2.0)   ; returns 7.38906
    (exp 10.0)  ; returns 22026.5
    (exp 0)     ; error: bad integer operation
    

    Note: 'exp' with a large 'power' like 1000.0 causes an incorrect value to be generated, with no error. The returned value will be a very large floating point number near the computer's limit [something like 1.79000e+308].

    See the exp function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/number-greaterp.htm0000644000175000000620000000511611512762341024255 0ustar stevestaffXLISP > Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    >


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (> expr1 expr2 ...)
    exprN - a numeric expression
    returns -  T  if the results of comparing the expressions are all true, NIL otherwise

    Description

    The '>' [greater-than] function takes an arbitrary number of numeric arguments. It checks to see if all the numbers are monotonically decreasing.  T  is returned if the arguments are numerically, and monotonically decreasing, NIL is returned otherwise. For two arguments, this has the effect of testing if 'expr1' is greater than 'expr2'.

    Examples

    (> 1 1)             => NIL
    (> 1 2)             => NIL
    (> 2.0 1.99)        => T
    (> 3 2 1)           => T
    (> 3 2 2)           => NIL
    (> "aa" "aa")       => error: bad argument type
    (setq a 12 b 99.9)  => 99.9  ; set up A and B with values
    (> a b)             => NIL
    (> b a)             => T
    

    See setq.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/read-int.htm0000644000175000000620000000453111512762341022661 0ustar stevestaffXLISP read-int Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    read-int


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (read-int [stream [length]])
    stream - the input stream [default is standard input]
    length - the length of the integer in bytes [default is 4]
    returns - the integer

    Description

    The 'read-int' function reads an integer from a binary input stream, created by the open-binary function.

    Note: Integers and floats are assumed to be big-endian [high-order byte first] and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. '-4' indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    Examples

    
    

    See also write-int, read-float, write-float, bigendianp, open-binary.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/let-star.htm0000644000175000000620000000645311512762341022716 0ustar stevestaffXLISP let* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    let*


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (let* ([binding ... ]) expr ... )
    binding - a variable binding which is one of the forms:
    symbol
    (symbol init-expr)
    symbol - a symbol
    init-expr - an initialization expression for symbol
    expr - an expression
    returns - the value of the last expression

    Description

    The 'let*' special form is basically a local block construct that contains symbols [with optional initializations] and a block of code [expressions] to evaluate. The first form after the 'let*' is the 'binding' form. It contains a series of 'symbols' or 'bindings'. The 'binding' is a 'symbol' followed by an initialization expression 'init-expr'. If there is no 'init-expr', the 'symbol' will be initialized to NIL. The execution of the bindings will occur from the first to the last binding. The 'let*' form will go through and create and initialize the symbols and then sequentially execute the 'exprs'. The value of the last 'expr' evaluated is returned. When the 'let*' is finished execution, the 'symbols' that were defined will no longer exist or retain their values.

    Examples

    (let* (x y z)                     ; LET* with local vars
      (print x) (print y) (print z))  ;   prints   NIL NIL NIL
    
    (let* ((a 1) (b 2) (c 3))         ; LET* with local vars & init
      (print (+ a b c)))              ;   prints and returns 6
    
    (let* ((a 1) (b 2) (c (+ a b)))   ; LET* with local vars & init
      (print (+ a b c)))              ;   prints and returns 6
    

    Note:

    (let* (a b) ... )
    

    can be understood as:

    (let (a)
      (let (b)
        ... ))
    

    See the let* special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-greaterp-i.htm0000644000175000000620000000756111512762341024527 0ustar stevestaffXLISP string-greaterp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-greaterp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-greaterp string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is greater than string2 in ASCII ordering, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'string-greaterp' [string-greater-than] predicate function takes two string arguments. A non-NIL value is returned if 'string1' is greater than 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char-greaterp [char-greater-than] the corresponding character of 'string2'. This test is not case sensitive, the character '#\a' is considered to be the same as '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string-greaterp "a" "b")                   ; returns NIL
    (string-greaterp "a" "a")                   ; returns NIL
    (string-greaterp "a" "A")                   ; returns NIL
    (string-greaterp "A" "a")                   ; returns NIL
    (string-greaterp "abc" "abc ")              ; returns NIL
    (string-greaterp "1234qrst" "12345678")     ; returns 4
    
    (string-greaterp "J Smith" "K Jones" :start1 1 :start2 1)  ; strip off the first chars 
                                                               ; returns 2
    

    See the string-greaterp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/let.htm0000644000175000000620000000634311512762341021745 0ustar stevestaffXLISP let Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    let


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (let ([binding ... ]) expr ... )
    binding - a variable binding which is one of the forms:
    symbol
    (symbol init-expr)
    symbol - a symbol
    init-expr - an initialization expression for symbol
    expr - an expression
    returns - the value of the last expression

    Description

    The 'let' special form is basically a local block construct that contains symbols [with optional initializations] and a block of code [expressions] to evaluate. The first form after the 'let' is the 'binding' form. It contains a series of 'symbols' or 'bindings'. The 'binding' is a 'symbol' followed by an initialization expression 'init-expr'. If there is no 'init-expr', the 'symbol' will be initialized to NIL. There is no specification as to the order of execution of the bindings. The 'let' form will go through and create and initialize the symbols and then sequentially execute the 'exprs'. The value of the last 'expr' evaluated is returned. When the 'let' is finished execution, the 'symbols' that were defined will no longer exist or retain their values.

    Examples

    (let (x y z)                      ; LET with local vars
      (print x) (print y) (print z))  ;   prints   NIL NIL NIL
    
    (let ((a 1) (b 2) (c 3))          ; LET with local vars & init
      (print (+ a b c)))              ;   prints and returns 6
    
    (let ((a 1) (b 2) (c (+ a b)))    ; LET with local vars & init
      (print (+ a b c)))              ;   error: unbound variable - A
    

    Note: to make the last example work you need the let* special form.

    See the let special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/expand.htm0000644000175000000620000000611111512762341022431 0ustar stevestaffXLISP expand Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    expand


    Type:   -   function (subr)
    Source:   -   xlsys.c, xldmem.c

    Syntax

    (expand segments)
    segments - the number of segments to add as an integer expression
    returns - the number of segments added

    Description

    The 'expand' function expands memory by the specified number of 'segments'. The number of 'segments' added is returned as the result. The power up default is 1000 nodes per segment. Note that alloc allows you to change the number of nodes per segment.

    Examples

    (room)      ; prints  Nodes:       8000
                ;         Free nodes:  5622
                ;         Segments:    6
                ;         Allocate:    1000
                ;         Total:       92586
                ;         Collections: 8
                ; returns NIL
    
    (expand 2)  ; add more nodes
    
    (room)      ; prints  Nodes:       10000
                ;         Free nodes:  7608
                ;         Segments:    8
                ;         Allocate:    1000
                ;         Total:       112602
                ;         Collections: 8
                ; returns NIL
    

    Note: When gc is called or an automatic garbage collection occurs, if the amount of free memory is still low after the garbage collection, the system attempts to add more segments [an automatic 'expand'].

    See the expand function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/incf.htm0000644000175000000620000000433611512762341022100 0ustar stevestaffXLISP incf Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    incf


    Type:   -   Lisp macro (closure)
    Source:   -   misc.lsp

    Syntax

    (incf symbol)
    symbol - a symbol with numerical value bound to it
    returns - the new value of the symbol

    In Nyquist, 'incf' is implemented as a Lisp macro:

    (defmacro incf (symbol)
      `(setf ,symbol (1+ ,symbol)))
    

    Description

    The 'incf' macro is used for incrementing a numerical value of a variable. 1 is added to the number and the result is stored in the variable. An error is signalled if the variable doesn't hold a number.

    Examples

    (setq n 1)     => 1
    (incf n)       => 2
    n              => 2
    (incf n)       => 3
    
    (setq n -1.8)  => -1.8
    (incf n)       => -0.8
    (incf n)       => 0.2
    (incf n)       => 1.2
    n              => 1.2
    
    (setq n #\a)  => #\a
    (incf a)      => error: bad argument type - #\a
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/find-in-xlisp-path.htm0000644000175000000620000000347711512762341024601 0ustar stevestaffXLISP find-in-xlisp-path Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    find-in-xlisp-path


    Type:   -   function (subr)
    Source:   -   path.c

    Syntax

    (find-in-xlisp-path filename)
    filename - the name of the file to search for as string
    returns - a full path name to the first occurrence found

    Description

    The 'find-in-xlisp-path' function searches the XLISP search path [e.g. XLISPPATH from the environment] for 'filename'. If 'filename' is not found as is, and there is no file extension, '.lsp' is appended to filename and searched again. The current directory is not searched.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/remove.htm0000644000175000000620000000774411512762341022464 0ustar stevestaffXLISP remove Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    remove


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (remove expr list-expr [{:test | :test-not} test])
    expr - the expression to remove, an atom or list
    list-expr - the list to remove from
    test - optional test function, default is eql
    returns - a copy of list-expr with matching expressions removed

    Description

    The 'remove' function searches through 'list-expr' for 'expr'. If 'expr' is found, 'remove' returns the list with the 'expr' deleted. All occurances of 'expr' are deleted. If 'expr' is not found, then the 'list-expr' is returned unaltered. You may specify your own test with the ':test' and ':test-not' keywords followed by the test you which to perform. Note that this operation is non-destructive, it does not modify or affect 'list-expr' directly, it creates a modified copy.

    Examples

    (setq mylist '(a b c d it e f))       ; set up a list
    (remove 'it mylist)                   ; returns (A B C D E F)
    (print mylist)                        ; prints (A B C D IT E F)
                                          ;   note that MYLIST is not affected
    
    (setq mylist '(a b c b d b))          ; change list to include duplicates
    (remove 'b mylist)                    ; returns (A C D)
    
    (setq alist '( (a) (b) (it) (c)))     ; set up another list
    (remove '(it) alist)                  ; returns ((A) (B) (IT) (C))
                                          ;   the EQ test doesn't work for lists
    (remove '(it) alist :test 'equal)     ; returns ((A) (B) (C))
    
    (setq slist '( "a" "b" "it" "c"))     ; set up yet another list
    (remove "it" slist)                   ; returns ("a" "b" "c")
    (remove "it" slist :test-not 'equal)  ; returns ("it")
                                          ;   REMOVE takes away everything but IT
    

    Note: The 'remove' function can work with a list or string as the 'expr'. However, the default eql test does not work with lists or strings, only symbols and numbers. To make this work, you need to use the ':test' keyword along with equal for 'test'.

    Common Lisp: XLISP does not support the ':from-end', ':start', ':end', ':count' and ':key' keywords which Common Lisp does.

    See the remove function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-not-lessp-s.htm0000644000175000000620000000757511512762341024661 0ustar stevestaffXLISP string>= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string>=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string>= string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is greater than or equal to string2 in ASCII ordering, NIL otherwise
    Note: case is significant with this function

    Description

    The 'string>=' [string-greater-than-or-equal] function takes two string arguments. A non-NIL value is returned if 'string1' is greater than or equal to 'string2' in an ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char>= [char-greater-than-or-equal] to the corresponding character of 'string2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string>= "a" "b")                   ; returns NIL
    (string>= "a" "a")                   ; returns 1
    (string>= "a" "A")                   ; returns 0
    (string>= "A" "a")                   ; returns NIL
    (string>= "abc" "abc ")              ; returns NIL
    (string>= "1234qrst" "12345678")     ; returns 4
    
    (string>= "J Smith" "K Jones" :start1 1 :start2 1)  ; strip off the first chars
                                                        ; returns 2
    

    See the string>= function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-not-equal-s.htm0000644000175000000620000000554011512762341024237 0ustar stevestaffXLISP char/= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char/=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char/= char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are not equal, NIL otherwise
    Note: case is significant with this function

    Description

    The 'char/=' function tests if all character arguments are different values.  T  is returned if the arguments are of different ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is not equal to 'char2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than the character '#\A'.

    Examples

    (char/= #\a #\b)      => T
    (char/= #\a #\b #\c)  => T
    (char/= #\a #\a)      => NIL
    (char/= #\a #\b #\b)  => NIL
    (char/= #\A #\a)      => T
    (char/= #\a #\A)      => T
    

    Caution: If you type 'char\=' [with a backslash] instead of 'string/=' by mistake, no error will be signalled because backslash is the single escape character and the XLISP reader will evaluate 'char\=' as char=, but the meaning of the test is exactly reversed.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/stringp.htm0000644000175000000620000000474711512762341022655 0ustar stevestaffXLISP tringp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    stringp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (stringp expr)
    expr - the expression to check
    returns -  T  if the value is a string, NIL otherwise

    Description

    The 'stringp' predicate function checks if 'expr' is a string.  T  is returned if 'expr' is a string, NIL is returned otherwise.

    Examples

    (stringp "a")        ; returns T - string
    
    (setq a "hi there"
    (stringp a)          ; returns T - evaluates to string
    
    (stringp #\a)        ; returns NIL - character
    (stringp '(a b c))   ; returns NIL - list
    (stringp 1)          ; returns NIL - integer
    (stringp 1.2)        ; returns NIL - float
    (stringp 'a)         ; returns NIL - symbol
    (stringp #(0 1 2))   ; returns NIL - array
    (stringp nil)        ; returns NIL - nil
    

    See the stringp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-env.htm0000644000175000000620000000320411512762341022517 0ustar stevestaffXLISP get-env Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-env


    Type:   -   function (subr)
    Source:   -   xlsys.c

    Syntax

    (get-env string)
    string - environment variable name as string
    returns - the value of the environment variable as string, or NIL

    Description

    The 'get-user' function returns the value of an environment variable, or NIL if no variable had been found.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-downcase.htm0000644000175000000620000000520411512762341024263 0ustar stevestaffXLISP string-downcase Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-downcase


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-downcase string [{:start | :end} offset] ... )
    string - a string expression
    offset - an optional integer expression for a keyword
    returns - a converted copy of the string

    Description

    The 'string-downcase' function takes a string argument and returns a new string that has been made lower case.

    The keyword arguments allow for accessing substrings within 'string'. The keyword arguments require a keyword ':start' or ':end' first and a single integer expression second. The ':start' keyword specifies the starting offset for the 'string-downcase' operation on 'string'. A value of 0 starts the string at the beginning [no offset]. The ':end' keyword specifies the end offset for the operation on 'string'.

    Examples

    (string-downcase "ABcd+-12&[")                ; returns "abcd+-&["
    (string-downcase "ABCDEFGH" :start 2 :end 4)  ; returns "ABcdEFGH"
    
    (setq mystr "ABcdEFgh")      ; set up variable
    (string-downcase mystr)      ; returns "abcdefgh"
    (print mystr)                ; prints  "ABcdEFgh"
    

    See the string-downcase function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/return.htm0000644000175000000620000000556711512762341022507 0ustar stevestaffXLISP return Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    return


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (return [expr])
    expr - an expression
    returns - never returns

    Description

    The 'return' special form allows the return of an arbitrary value at arbitrary times within 'block' constructs like do , do* , dolist , dotimes , loop , prog and prog*. The 'expr' will be returned by the outer 'block' construct. A NIL will be returned by the outer 'block' construct if there is no 'expr' specified.

    If 'return' is used without being within a valid 'block' construct, an error is generated:

    error: no target for RETURN
    

    Examples

    (prog (i)                              ; PROG form
      (print i) (RETURN "foo") (print j))  ; prints NIL  returns "foo"
    
    (dotimes (i 10)
      (if (eql i 5) (RETURN 20)
                    (princ i)))            ; prints 01234  returns 20
    
    (prog1 (print "hi") (RETURN "foo"))    ; prints "hi"
                                           ; error: no target for RETURN
    
    (return 9)                             ; error: no target for RETURN
    

    See the return special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/self.htm0000644000175000000620000000504411512762341022107 0ustar stevestaffXLISP self Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    self


    Type:   -   symbol
    Source:   -   xlobj.c

    Syntax

     self

    Description

    The 'self' symbol evaluates to the current object when used within a message context.

    Examples

    (setq my-class (send class :new '(state)))               ; create MY-CLASS with STATE
    
    (send my-class :answer :isnew '()                        ; set up initialization
                                  '((setq state nil) SELF))  ;   returning SELF
    
    (send my-class :answer :set-it '(value)                  ; create :SET-IT message
                                   '((setq state value)))
    
    (setq my-obj (send my-class :new))                       ; create MY-OBJ of MY-CLASS
    (send my-obj :set-it 5)                                  ; STATE is set to 5
    

    Context: 'self' does not exist except within the context of a method and it's execution.

    Note: In the previous example, there is a 'self' in the line that creates the ':set-it' message. What this does is to return the object as the last operation when you do an :isnew.

    See the self symbol in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/fboundp.htm0000644000175000000620000000560711512762341022620 0ustar stevestaffXLISP fboundp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    fboundp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (fboundp symbol)
    symbol - the symbol expression to check for a value
    returns -  T  if a functional value is bound to the symbol, NIL otherwise

    Description

    The 'fboundp' predicate function checks to see if 'symbol' is a symbol with a function definition bound to it.  T  is returned if 'symbol' has a function value, NIL is returned otherwise. Note that 'symbol' is a symbol expression, it is evaluated and the resulting expression is the one that is checked.

    Examples

    (defun foo (x) (print x))       ; set up function FOO
    (fboundp 'foo)                  ; returns T - FOO is closure
    (fboundp 'car)                  ; returns T - CAR is subr
    
    (setq myvar 'goo)               ; set up MYVAR to have value GOO
    (fboundp myvar)                 ; returns NIL - because GOO has no value yet
    (defmacro goo () (print "hi"))  ; define GOO macro
    (fboundp myvar)                 ; returns T
    
    (fboundp 'a)                    ; returns NIL
    (fboundp '1)                    ; error: bad argument type - 1
    (fboundp "hi")                  ; error: bad argument type - "hi"
    

    See the fboundp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-class.htm0000644000175000000620000000505611512762341023750 0ustar stevestaffXLISP :class Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :class


    Type:   -   message selector
    Source:   -   xlobj.c

    Syntax

    (send object :class)
    object - an existing object
    returns the class object

    Description

    The ':class' message selector will cause a method to run that will return the object which is the class of the specified 'object'. Note that the returned value is an object which will look like:

    #<Object: #18d8c>
    

    The 'object' must exist or an error will be generated:

    error: bad argument type
    

    Examples

    (send object :class)                     ; returns the CLASS object
    (send class :class)                      ; returns the CLASS object
    (setq new-cls (send class :new '(var)))  ; create NEW-CLS
    (setq new-obj (send new-cls :new))       ; create NEW-OBJ of NEW-CLS
    (send new-obj :class)                    ; returns the NEW-CLS object
    (send new-cls :class)                    ; returns the CLASS object
    

    See the :class message selector in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/abs.htm0000644000175000000620000000374411512762341021730 0ustar stevestaffXLISP abs Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    abs


    Type:   -   function (subr)
    Source:   -   xlisp/xlmath.c

    Syntax

    (abs number)
    number - an integer or floating point expression
    returns - the absolute value of the number

    Description

    The 'abs' function computes the absolute value of a number and returns the result. A 'bad argument type' error is signalled if the argument is not a numebr.

    Examples

    (abs 1)       => 1
    (abs -99)     => 99
    (abs -99.9)   => 99.9
    (abs -32768)  => 32768
    (abs "123")   => error: bad argument type
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-mescape.htm0000644000175000000620000000472611512762341024263 0ustar stevestaffXLISP :mescape Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :mescape


    Type:   -   keyword
    Source:   -   xlread.c

    Syntax

     :mescape

    Description

    The ':mescape' keyword is an entry used in the *readtable* system variable that contains XLISP's data structures relating to the processing of characters from the user (or files) and read-macro expansions. The existance of the ':mescape' keyword means that the specified character is to be used as a multiple escape character. The system defines that the the vertical bar character '|' is the only ':mescape' character.

    Examples

    ;; define a function to look in a table
    ;; and print out any :mescape character
    
    (defun look-at (table)
      (dotimes (ch 127)
        (prog ((entry (aref table ch)))
          (case entry
            (:mescape (princ (int-char ch)))
            (t nil))))
      (terpri))
    
    (look-at *readtable*)     ; prints |
    

    Caution: If you experiment with *readtable* , it is useful to save the old value in a variable, so that you can restore the system state.

    See the :mescape keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/member.htm0000644000175000000620000000660211512762341022426 0ustar stevestaffXLISP member Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    member


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (member expr list-expr [{:test | :test-not} test])
    expr - the expression to find [an atom or a list]
    list-expr - the list to search
    test - optional test function, default is eql
    returns - the remainder of the list starting with expr

    Description

    The 'member' function searches through 'list-expr' for 'expr'. If found, 'member' returns the remainder of the 'list-expr' starting with 'expr'. If 'expr' is not found, a NIL is returned. You may specify your own test with the ':test' and ':test-not' keywords followed by the test you which to perform.

    Examples

    (member 'a '(1 2 3 4))                         ; returns NIL
    (member '2 '(1 2 3 4))                         ; returns (2 3 4)
    
    (setq mylist '(2 4 8 16 32 64 128 256))        ; make a numeric list
    (member 6 mylist :test '<)                     ; returns (8 16 32 64 128 256)
    (member 6 (reverse mylist) :test-not '<)       ; returns (4 2)
    (member '20 '(60 40 20 10) :test '> )          ; returns (10)
    
    (member '(a) '((see) (a) (cat)) :test 'equal)  ; returns ((A) (CAT)) with EQUAL as test
    (member "hi" '("a" "hi" "c") :test 'string= )  ; returns ("hi" "c") with STRING= as test
    
    

    Note: The 'member' function can work with a list or string as the 'expr'. However, the default eql test does not work with lists or strings, only symbols and numbers. To make this work, you need to use the ':test' keyword along with equal for 'test'.

    Common Lisp: Common Lisp supports the use of the ':key' keyword which specifies a function that is applied to each element of 'list-expr' before it is tested. XLISP does not support this.

    See the member function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/symbol-value.htm0000644000175000000620000000517011512762341023575 0ustar stevestaffXLISP symbol-value Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    symbol-value


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (symbol-value symbol)
    symbol - an expression that evaluates to a symbol name
    returns - the symbol's value

    Description

    The 'symbol-value' function takes the 'symbol' expression and returns the current value of the 'symbol'.

    If the 'symbol' had not existed, then it will be created and interned into the system symbol table *obarray* , but with it's value unbound and an empty property list. In this case of a previously non-existant 'symbol', since it has no bound value, the 'symbol-value' function will still report an error due to an unbound variable.

    Examples

    (setq myvar 55)                   ; set MYVAR to value 55
    (symbol-value 'myvar)             ; returns 55
    (symbol-value 'floop)             ; error: unbound variable
    
    (setq my-symbol 'a)               ; set MY-SYMBOL to A
    
    (setq a '(contents of symbol a))  ; set A to value (CONTENTS OF SYMBOL A)
    
    (symbol-value my-symbol)          ; returns (CONTENTS OF SYMBOL A)
    

    See the symbol-value function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/nstring-upcase.htm0000644000175000000620000000547011512762341024123 0ustar stevestaffXLISP nstring-upcase Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    nstring-upcase


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (nstring-upcase string [{:start | :end} offset] ... )
    string - a string expression
    offset - an optional integer expression for a keyword
    returns - the converted string, not a copy

    Description

    The 'nstring-upcase' function takes a string argument and makes it upper case. This function modifies the string or string variable itself, it does not just make a copy. The upper case string is returned.

    The keyword arguments allow for accessing substrings within 'string'. The keyword arguments require a keyword (':start' or ':end') first and a single integer expression second. The ':start' keyword specifies the starting offset for the 'nstring-upcase' operation on 'string'. A value of 0 starts the string at the beginning [no offset]. The ':end' keyword specifies the end offset for the operation on 'string'.

    Examples

    (nstring-upcase "ABcd+-12&[")                ; returns "ABCD+-&["
    (nstring-upcase "abcdefgh" :start 2 :end 4)  ; returns "abCDefgh"
    
    (setq mystr "ABcdEFgh")      ; set up variable
    (nstring-upcase mystr)       ; returns "ABCDEFGH"
    (print mystr)                ; prints  "ABCDEFGH"
                                 ; note that MYSTR is modified
    

    See the nstring-upcase function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/intern.htm0000644000175000000620000001160411512762341022454 0ustar stevestaffXLISP intern Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    intern


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (intern name-str)
    name-str - a string expression
    returns - the new symbol

    Description

    The 'intern' function takes a string name 'name-str' and creates a new interned symbol. What this means is that the symbol 'name-str' will be placed into the symbol hash table *obarray*. It's value will be unbound. It's property list will be NIL [empty]. If the symbol already exists, no error or action is taken and the old values and property lists remain intact. The 'intern' function returns the symbol as its result.

    Examples

    (defun lookin (sym)                  ; create a function to
      (aref *obarray*                    ;   look inside *OBARRAY* and
        (hash sym (length *obarray*))))  ;   look for a specific symbol
                                         ;   returns a list
    
    (lookin "FINGERS")                   ; see if "FINGERS" is a symbol
                                         ;   returns (:START1) - it isn't
    
    (intern "FINGERS")                   ; intern "FINGERS" as a symbol
                                         ;   returns FINGERS
    
    (lookin "FINGERS")                   ; returns (FINGERS :START1)
    
    (print fingers)                      ; error: unbound variable
                                         ;   it exists, but has no value
    
    (lookin "TOES")                      ; returns NIL - doesn't exist
    toes                                 ; error: unbound variable
    
    (lookin "TOES")                      ; returns (TOES)
                                         ;   the act of looking for a
                                         ;   value or using a symbol
                                         ;   causes it to be INTERNed
    
    (lookin "KNEECAPS")                  ; returns (MAX MAPLIST)
                                         ;   KNEECAPS doesn't exist
    
    (setq kneecaps 'a-bone)              ; create symbol with a value
    (lookin "KNEECAPS")                  ; returns (KNEECAPS MAX MAPLIST)
    

    Note: When you 'intern' a string symbol like "fingers" in lower case letters, this gets placed in the *obarray* symbol table as a lower case symbol. Note that this is different from doing an 'intern' on a string symbol "FINGERS" in upper case letters which will get placed in the *obarray* as a upper case symbol. "fingers" and "FINGERS" then are two different symbols in *obarray*. Remember also that normal symbols created by XLISP are automatically converted to upper case names. So, an intern of the lower case symbol name 'fingers and the upper case symbol name 'FINGERS will result in the effect that both symbol names get interned as the same upper-case symbol FINGERS.

    Common Lisp: Common LISP allows an optional package specification, which XLISP does not support.

    See the intern function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-breakenable.htm0000644000175000000620000000716011512762341024650 0ustar stevestaffXLISP *breakenable* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *breakenable*


    Type:   -   system variable
    Source:   -   xldbug.c

    Syntax

    (setq *breakenable* boolean)
    boolean - a generalized boolean value
    returns - non-NIL if errors shall be handled by the Break Loop, or NIL if not

    Description

    The *breakenable* system variable controls entry to the Break Loop and the trapping of errors. If *breakenable* is set to NIL , then no errors from the system or from the error or cerror functions will be trapped. If *breakenable* is non-NIL, the Break Loop will handle these errors. The break function is not affected by *breakenable* and will always force entry to the Break Loop. If the 'init.lsp' initialization file sets *breakenable* to  T , errors will be trapped by the Break Loop.

    Examples

    > (defun foo (x)            ; define function FOO
        (+ x x))
    FOO
    
    > (setq *breakenable* NIL)  ; disable break loop
    NIL
    
    > (foo "a")
    error: bad argument type    ; does NOT enter a break loop
    
    > (setq *breakenable* T)    ; enable break loop
    T
    
    > (foo "a")
    error: bad argument type
    
    1>                          ; entered a break loop
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/terpri.htm0000644000175000000620000000627411512762341022471 0ustar stevestaffXLISP terpri Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    terpri


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlprin.c

    Syntax

    (terpri [dest])
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - NIL

    Description

    The 'terpri' function prints a new-line to the specified 'destination' This will terminate the current print line for 'destination'. NIL is always returned as the result. The 'destination' may be a file pointer or a stream. If there is no 'destination', *standard-output* is the default.

    Examples

    (terpri)                                 ; prints  #\Newline
    
    (setq f (open "pr" :direction :output))  ; create a file
    (princ "hi" f)                           ; returns "hi"
    (princ 727 f)                            ; returns 727
    (princ "ho" f)                           ; returns "ho"
    (terpri f)                               ; returns NIL
    (close f)                                ; file contains hi727ho#\Newline
    

    Common Lisp: Common Lisp specifies that print operations with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the terpri function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/symbolp.htm0000644000175000000620000000604011512762341022640 0ustar stevestaffXLISP symbolp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    symbolp


    Type:   -   predicate function (subr)
    Source:   -   xllist.c

    Syntax

    (symbolp expr)
    expr - the expression to check
    returns -  T  if the expression is a symbol, NIL otherwise

    Description

    The 'symbolp' predicate function checks if an 'expr' is a valid symbol.  T  is returned if 'expr' is a symbol, NIL is returned otherwise. An 'expr' that evaluates to an integer, function [subr or otherwise], and so on is not a symbol. However, the quoted [un-evaluated] name of these objects [like 'myarray] is a valid symbol.

    Examples

    (symbolp (make-symbol "a"))       ; returns T - symbol
    (symbolp 'a)                      ; returns T - symbol
    
    (symbolp #(1 2 3))                ; returns NIL - array
    (symbolp (lambda (x) (print x)))  ; returns NIL - closure
    (symbolp *standard-output*)       ; returns NIL - stream
    (symbolp 1.2)                     ; returns NIL - float
    (symbolp 2)                       ; returns NIL - integer
    (symbolp object)                  ; returns NIL - object
    (symbolp "hi")                    ; returns NIL - string
    
    (symbolp #'car)                   ; returns NIL - subr
    (symbolp 'car)                    ; returns T - it is a symbol now
    (symbolp '2)                      ; returns NIL - not a symbol
    

    See the symbolp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/random.htm0000644000175000000620000000536511512762341022444 0ustar stevestaffXLISP random Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    random


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (random expr)
    expr - integer number or expression
    returns - a random number between 0 and expr - 1.

    Description

    The 'random' function generates and returns a random number between 0 and 'expr' - 1. If 'expr' is negative, the number range is forced to be positive.

    Examples

    (random 100)      ; returns 7
    (random 100)      ; returns 49
    (random 100)      ; returns 73
    (random -100)     ; returns 58
    (random 100.01)   ; error: bad floating point operation
    

    Common Lisp: Common Lisp allows an optional 'state' parameter, which is not supported in XLISP. Also, Common LISP allows floating point numbers, which XLISP does not support.

    Note: This function is an extension of the XLISP system. It is provided in the 'msstuff.c' source code file. If your XLISP system is built for an IBM PC and compatibles, this function will work. If your system is built on UNIX or some other operating system, it will need the code in the corresponding 'stuff.c' file.

    Nyquist: As far as I know the Nyquist 'random' function works on all systems. See also the Nyquist rrandom function.

    See the random function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/top-level.htm0000644000175000000620000000534211512762341023066 0ustar stevestaffXLISP top-level Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    top-level


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xldbug.c

    Syntax

    (top-level)
    returns - never returns

    Description

    The 'top-level' function aborts to the top level of XLISP. This may be from within several levels of the break loop. This is valid for breaks, errors and cerrors [continuable errors]. If 'top-level' is evaluated while not in a break loop , a message is printed:

    [ back to top level ]
    

    This message does not cause XLISP to go into a break loop. The 'top-level' function never actually returns a value.

    Examples

    (top-level)      ; [ back to top level ]
    
    (break "out")    ; break: out    (1st)
    (break "twice")  ; break: twice  (2nd)
    (top-level)      ; to exit out of the break loop
    

    Keyboard: In the IBM PC and MS-DOS versions of XLISP, a 'Ctrl+c' key sequence has the same effect as doing a (top-level). On a Macintosh, this can be accomplished by a pull-down menu or a 'Command+t'. [I haven't tested this with Nyquist.]

    See the top-level function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/reference.css0000644000175000000620000000112411512762341023107 0ustar stevestaff.example { color: #000000; background-color: #F5F5F5; padding: 8px; border: #808080; border-style: solid; border-width: 1px; width:auto; } .button { color: #000000; background-color: #F5F5F5; padding-top: 1px; padding-bottom: 1px; padding-left: 4px; padding-right: 8px; border: #808080; border-style: solid; border-width: 1px; white-space: pre; } .box { color: #000000; padding-top: 4px; padding-bottom: 4px; padding-left: 16px; padding-right: 16px; border: #808080; border-style: solid; border-width: 1px; } nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/write-char.htm0000644000175000000620000000635611512762341023232 0ustar stevestaffXLISP write-char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    write-char


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (write-char char-expr [dest])
    char-expr - a character expression
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - the character

    Description

    The 'write-char' function writes the 'char-expr' to the specified 'destination'. Only the 'char-expr' is written. The 'char-expr' must be a character expression. The 'char-expr' is returned as the result. The 'destination' may be a file pointer or a stream. If there is no 'destination', *standard-output* is the default.

    Examples

    (write-char #\C)                         ; prints  C
    
    (setq fp (open "t" :direction :output))  ; create file
    (write-char #\A fp)                      ; returns #\A
    (write-char #\B fp)                      ; returns #\B
    (write-char #\Newline fp)                ; returns #\Newline
    (close fp)                               ; returns NIL
    
    (read (open "t" :direction :input))      ; returns AB
    

    Common Lisp: Common Lisp specifies that print operations with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the write-char function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/number-equal.htm0000644000175000000620000000462111512762341023553 0ustar stevestaffXLISP = Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    =


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (= expr1 expr2 ...)
    exprN - a numeric expression
    returns -  T  if the results of comparing the expressions are all true, NIL otherwise

    Description

    The '=' [equality] function takes an arbitrary number of numeric arguments. It checks to see if all the numbers are equal.  T  is returned if all of the arguments are numerically equal to each other, NIL is returned otherwise.

    Examples

    (= 1 1)              => T
    (= 1 2)              => NIL
    (= 1 1.0)            => T
    (= 1 1.0 1 (+ 0 1))  => T
    (= 1 1.0 1.00001)    => NIL
    (= "a" "b")          => error: bad argument type
    (setq a 1 b 1.0)     => 1.0  ; set up A and B with values
    (= a b)              => T
    

    See setq.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/return-from.htm0000644000175000000620000000540311512762341023435 0ustar stevestaffXLISP return-from Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    return-from


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (return-from name [expr])
    name - an unevaluated symbol for the block name
    expr - an expression
    returns - never returns

    Description

    The 'return-from' special form allows the return of an arbitrary value at arbitrary times within a 'named-block' construct of the specified 'name'. The 'expr' will be returned by the block construct. A NIL will be returned by the block construct if there is no 'expr' specified.

    If 'return-from' is used without being within a valid block construct, an error is generated:

    error: no target for RETURN
    

    Examples

    (block out                        ; outer BLOCK
      (print "outer")
      (block in                       ; inner BLOCK
        (print "inner")
        (return-from out "all done")
        (print "won't get here")))    ; prints "outer"
                                      ; prints "inner"
                                      ; returns "all done"
    
    (return-from nobody 9)            ; error: no target for RETURN
    

    See the return-from special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/subseq.htm0000644000175000000620000000533011512762341022456 0ustar stevestaffXLISP subseq Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    subseq


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (subseq string start [end])
    string - a string expression
    start - an integer expression
    end - an integer expression
    returns - the substring between start and end

    Description

    The 'subseq' function extracts a substring from 'string' starting with the 'start' offset and ending with the 'end' offset. The 'start' offset has a origin or 0. The substring is returned.

    Examples

    (subseq "12345678" 0)     ; returns "12345678"
    (subseq "12345678" 2)     ; returns "345678"
    (subseq "12345678" 2 4)   ; returns "34"
    (subseq "1234" 3)         ; returns "4"
    
    (subseq "1234" 4)         ; returns ""
    (subseq "1234" 4 2)       ; returns ""
    (subseq "1234" 5)         ; error: string index out of bounds - 5
    

    Common Lisp: The 'subseq' function in Common Lisp is intended to return a portion of a sequence, a sub-sequence. This function operates on lists and vectors [one-dimensional arrays of data], basically ordered data. Strings are just one of the valid types operated on by 'subseq' in Common Lisp. The XLISP 'subseq' function only operates on strings.

    See the subseq function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/defun.htm0000644000175000000620000001343111512762341022256 0ustar stevestaffXLISP defun Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    defun


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (defun symbol arg-list body)
    symbol - the name of the function being defined
    arg-list - a list of the formal arguments to the function of the form:
    ([arg1 ... ]
     [&optional oarg1 ... ]
     [&rest rarg]
     [&key ... ]
     [&aux aux1 ... ])
    body - a series of LISP forms (expressions) that are executed in order.
    returns - the function symbol

    Description

    The 'defun' special form defines a new function or re-defines an exisiting function. The last form in 'body' that is evaluated is the value that is returned when the function is executed.

    All of the 'argN' formal arguments that are defined are required to appear in a call to the defined function.

    If there are any &optional arguments defined, they will be filled in order.

    If there is a &rest argument defined, and all the required formal arguments and &optional arguments are filled, any and all further parameters will be passed into the function via the 'rarg' argument. Note that there can be only one 'rarg' argument for &rest.

    If there are insufficient parameters for any of the &optional or &rest arguments, they will contain NIL.

    The &aux variables are a mechanism for you to define variables local to the function definition. At the end of the function execution, these local symbols and their values are are removed.

    Examples

    (defun my-add                          ; define function MY-ADD
      (num1 num2)                          ;   with 2 formal parameters
      (+ num1 num2))                       ;   that adds the two paramters
    
    (my-add 1 2)                           ; returns 3
    
    (defun foo                             ; define function FOO
      (a b &optional c d &rest e)          ;   with some of each argument
      (print a) (print b)
      (print c) (print d)                  ;   print out each
      (print e))
    
    (foo)                                  ; error: too few arguments
    (foo 1)                                ; error: too few arguments
    (foo 1 2)                              ; prints 1 2 NIL NIL NIL
    (foo 1 2 3)                            ; prints 1 2 3 NIL NIL
    (foo 1 2 3 4)                          ; prints 1 2 3 4 NIL
    (foo 1 2 3 4 5)                        ; prints 1 2 3 4 (5)
    (foo 1 2 3 4 5 6 7 8 9)                ; prints 1 2 3 4 (5 6 7 8 9)
    
    (defun my-add                          ; define function MY-ADD
      (num1 &rest num-list &aux sum)       ;   with 1 arg, rest, 1 aux var
      (setq sum num1)                      ;   clear SUM
      (dotimes (i (length num-list) )      ;   loop through rest list
        (setq sum (+ sum (car num-list)))  ;      add the number to sum
        (setq num-list (cdr num-list)))    ;      and remove num from list
      sum)                                 ;   return sum when finished
    
    (my-add 1 2 3 4)                       ; returns 10
    (my-add 5 5 5 5 5)                     ; returns 25
    

    Common Lisp: Common Lisp supports an optional documentation string as the first form in the 'body' of a defmacro or 'defun'. XLISP will accept this string as a valid form, but it will not do anything special with it.

    See the defun special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/length.htm0000644000175000000620000000445111512762341022440 0ustar stevestaffXLISP length Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    length


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (length expr)
    expr - a list expression or string expression
    returns - the length of the list, array or string

    Description

    The 'length' function returns the length of the 'expr'. If the 'expr' is a string, the number of characters is returned. If the 'expr' is a list, the number of top level elements [atoms or sublists] is returned. If the list is NIL , a '0' is returned.

    Examples

    (length NIL)                     ; returns 0
    (length 'a)                      ; error: bad argument type
    (length '(a))                    ; returns 1
    (length '(1 2 3 4 5 6))          ; returns 6
    (length '(a (b c) (d (e) f) g))  ; returns 4
    (length "12345")                 ; returns 5
    

    See the length function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-trim.htm0000644000175000000620000000514511512762341023437 0ustar stevestaffXLISP string-trim Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-trim


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-trim trim-stuff string)
    trim-stuff - a string expression
    string - a string expression
    returns - a trimed copy of the string

    Description

    The 'string-trim' function takes the 'trim-stuff' characters and removes them from both ends of the 'string'. The 'trim-stuff' characters are an un-ordered set of characters to be removed, so any character that occurs in 'trim-stuff' is removed if it appears in 'string'. A new string is created and returned as the result of this function.

    Examples

    (string-trim "." "....foo....")     ; returns "foo"
    (string-trim "<>" "<<<<bar>>>>")    ; returns "bar"
    (string-trim "(.)" "..(12.34)..")   ; returns "12.34"
    

    Common Lisp: Common LISP also supports a list of characters as a valid 'trim-stuff' argument. An example:

    (string-trim '(#\Tab #\Newline) mystring)
    

    XLISP does not support non-string parameters. Porting from XLISP will be no problem, but modifications will be necessary if porting from Common LISP code which uses a list of characters.

    See the string-trim function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/bigendianp.htm0000644000175000000620000000362711512762341023263 0ustar stevestaffXLISP bigendianp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    bigendianp


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (bigendiap)
    returns -  T  with a big-endian architecture, otherwise NIL.

    Description

    The 'bigendianp' function tests if Nyquist/XLISP runs on a bigendian machine, storing the high-order byte of an integer at the lowest byte address of the integer.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/room.htm0000644000175000000620000000550611512762341022135 0ustar stevestaffXLISP room Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    room


    Type:   -   function (subr)
    Source:   -   xldmem.c

    Syntax

    (room [info])
    info - an optional, unused expression
    returns - NIL

    Description

    The 'room' function prints the current memory statistics to *standard-output*. NIL is always returned. The message shows the statistics for:

    • total nodes
    • current free nodes
    • current number of allocated memory segments
    • node size of the allocated memory segments
    • total memory in bytes
    • total number of garbage collections that have occured since this session of XLISP started

    Examples

    (room)    ; prints  Nodes:       4000
              ;         Free nodes:  1723
              ;         Segments:    4
              ;         Allocate:    1000
              ;         Total:       52566
              ;         Collections: 8
              ; returns NIL
    

    Common Lisp: In Common LISP, the 'info' argument controls the amount of information that is printed. In Common Lisp, the form of and information provided by the 'room' output is implementation dependent. For portability, you should not count on this information or form.

    See the room function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char.htm0000644000175000000620000000415111512762341022071 0ustar stevestaffXLISP char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char string position)
    string - a string expression
    position - an integer expression
    returns - the ASCII code of the character

    Description

    The 'char' function returns the ASCII numeric value of the character at the specified 'position' in the 'string'. A position of '0' is the first character in the string.

    Examples

    (char "12345" 0)          => #\1
    (char "12 45" 2)          => #\Space
    (string (char "1234" 3))  => "4"
    (char "1234" 9)           => error: index out of range
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/setq.htm0000644000175000000620000000365511512762341022140 0ustar stevestaffXLISP setq Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    setq


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (setq [symbol1 expr1] ... )
    symbolN - un-evaluated symbol
    exprN - value for symbolN
    returns - the new value

    Description

    The 'setq' special form sets 'expr' as the value of 'symbol'. 'setq' returns the value from 'expr' as it's result.

    Examples

    (setq a 1)             ; symbol A gets value 1
    (setq b '(a b c))      ; symbol B gets value (A B C)
    (setq mynum (+ 3 4))   ; symbol MYNUM gets value 7
    

    See the setq special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/expt.htm0000644000175000000620000000462211512762341022137 0ustar stevestaffXLISP expt Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    expt


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (expt expr [power ... ])
    expr - floating point number/expression
    power - integer or floating point number/expression
    returns - x to the y power

    Description

    The 'expt' function raises the 'expr' to the specified 'power' and returns the result. If there is no 'power' specified, the 'expr' is returned. If there are multiple 'powers', they will be applied sequentially to 'expr'.

    Examples

    (expt 2.0 2)        ; returns 4
    (expt 2.0 10)       ; returns 1024
    (expt 2 2)          ; error: bad integer operation
    (expt 99.9)         ; returns 99.9
    (expt 2.0 2.0 2.0)  ; returns 16
    

    Note: 'expt' with a large values like (expt 999.9 999.9) causes an incorrect value to be generated, with no error. The returned value will be a very large floating point number near the computer's limit [something like 1.79000e+308].

    See the expt function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-obarray.htm0000644000175000000620000000512511512762341024053 0ustar stevestaffXLISP *obarray* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *obarray*


    Type:   -   system variable
    Source:   -   xlsym.c

    Syntax

     *obarray*

    Description

    The *obarray* system variable contains the system symbol table. This symbol table is an XLISP array that is constructed out of lists.

    Examples

    (defun lookin (sym)                  ; create a function to
      (aref *obarray*                    ;   look inside *OBARRAY*
        (hash sym (length *obarray*))))  ;   and look for a specific
                                         ;   symbol - returns a list
    
    (lookin "CAR")                       ; returns (TEST PEEK CAR)
    (lookin "car")                       ; returns NIL
    

    Note: When looking into *obarray* or interning symbols, remember that "car" and "CAR" written as strings [with quotation marks in front and behind] are two different symbols in *obarray*. Remember also that normal symbols created by XLISP are upper case names. So, if you type in 'car as a normal symbol [with a single quote in front of it], it will be the symbol CAR after this normal upper-casing operation.

    See the *obarray* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/when.htm0000644000175000000620000000465511512762341022126 0ustar stevestaffXLISP when Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    when


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (when test [expr ... ])
    test - an expression, NIL or non-NIL
    expr - expressions comprising a body of code
    returns - the value of the last expression or NIL

    Description

    The 'when' macro executes the 'expr' forms if 'test' evaluates to a non-NIL value. If 'test' is non-NIL , the value of the last 'expr' is returned as the result. If 'test' is NIL , NIL is returned with none of 'expr' evaluated.

    Examples

    (when NIL)                  ; returns NIL
    (when T)                    ; returns T
    
    (when T (print "hi") 'foo)  ; prints "hi"  returns FOO
    
    (when (listp '(a))
          (print "a list"))     ; prints  "a list"
                                ; returns "a list"
    

    See the when special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/code-char.htm0000644000175000000620000000632411512762341023005 0ustar stevestaffXLISP code-char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    code-char


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (code-char code)
    code - a numeric expression representing the ASCII code as an integer
    returns - the character with that code or NIL

    Description

    The 'code-char' function returns a character which is the result of turning 'code' expression into a character. If a 'code' cannot be made into a character, NIL is returned. The range that 'code' produces a valid character is 0 through 127.

    Examples

    (code-char 48)    ; returns #\0
    (code-char 65)    ; returns #\A
    (code-char 97)    ; returns #\a
    (code-char 91)    ; returns #\[
    (code-char 10)    ; returns #\Newline
    (code-char 128)   ; returns NIL
    (code-char 999)   ; returns NIL
    

    Common Lisp: Common Lisp allows for some optional arguments in 'code-char' because it supports the concept of a complex character that includes not only the ASCII code value, but also fonts and bits. The bits allow for more than 8 bits per character [16 bits is especially useful in oriental languages]. The fonts allow for up to 128 different fonts. XLISP does not support fonts and bits or the optional parameters associated with them.

    Note: Unlike the char-code and char-int functions, 'code-char' and int-char are not identical in use. 'code-char' accepts 0..127 for its range and then produces NIL results. int-char accepts 0..255 for its range and then produces errors.

    See the code-char function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-output-stream-string.htm0000644000175000000620000000532211512762341026067 0ustar stevestaffXLISP get-output-stream-string Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-output-stream-string


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (get-output-stream-string stream)
    stream - an output stream expression
    returns - the output so far as a string

    Description

    The 'get-output-stream-string' function empties the specified 'stream' and returns this data as a single string. The output stream is emptied by this operation.

    Examples

    (setq out (make-string-output-stream))  ; returns #<Unnamed-Stream: #...>
    
    (format out "fee fi fo fum ")           ; \
    (format out "I smell the blood of ")    ;  fill up output stream
    (format out "Elmer Fudd")               ; /
    (get-output-stream-string out)          ; returns "fee fi fo fum I smell the blood of Elmer Fudd"
    
    (format out "~%now what")               ; add more to output stream
    (get-output-stream-string out)          ; returns "\nnow what"
    (get-output-stream-string out)          ; returns ""
    
    (format out "hello")                    ; add more to output stream
    (read out)                              ; returns HELLO
    

    See the get-output-stream-string function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-equal-s.htm0000644000175000000620000000515711512762341023445 0ustar stevestaffXLISP char= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char= char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of the same ASCII value, NIL otherwise
    Note: case is significant with this function

    Description

    The 'char=' function tests if all the character arguments are equivalent.  T  is returned if the arguments are of the same ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is equal to 'char2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than the character '#\A'.

    Examples

    (char= #\a #\b)      => NIL
    (char= #\b #\a)      => NIL
    (char= #\a #\b #\c)  => NIL
    (char= #\a #\a)      => T
    (char= #\a #\a #\a)  => T
    (char= #\a #\a #\b)  => NIL
    (char= #\A #\a)      => NIL
    (char= #\a #\A)      => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/send.htm0000644000175000000620000000665411512762341022117 0ustar stevestaffXLISP send Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    send


    Type:   -   function (subr)
    Source:   -   xlobj.c

    Syntax

    (send object message [args])
    object - an object
    message - message selector for object
    arg - parameter sent to object method
    returns - the object

    Description

    The 'send' function is the mechanism used to send a 'message' to an object. The 'message' is the message selector symbol that is used to select a particular action [method] from the object.

    Examples

    (setq myclass (send class :new '(var)))              ; create MYCLASS with VAR
    
    (send myclass :answer :isnew '()                     ; set up initialization
                                 '((setq var nil) self))
    
    (send myclass :answer :set-it '(value)               ; create :SET-IT message
                                  '((setq var value)))
      
    (setq my-obj (send myclass :new))                    ; create MY-OBJ of MYCLASS
    (send my-obj :set-it 5)                              ; VAR is set to 5
    

    Built-in methods: The built in methods in XLISP include:

    • :answer - add a method to an object
    • :class - return the object's class
    • :isnew - run initialization code on object
    • :new - create a new object [instance or class]
    • :show - show the internal state of the object

    Message structure: The normal XLISP convention for a 'message' is to have a valid symbol preceeded by a colon like :isnew or ':my-message'. However, it is possible to define a 'message' that is a symbol without a colon, but this makes the code less readable.

    See the send function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/plus.htm0000644000175000000620000000362411512762341022143 0ustar stevestaffXLISP + (variable) Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    (variable)


    Type:   -   variable
    Source:   -   xlinit.c, xlisp.c

    Syntax

     +
    returns - the most recent input expression

    Description

    The '+' variable is set to the most recent input expression.

    Examples

    (setq hi 'there)  => THERE
    +                 => (SETQ HI (QUOTE THERE))
    +                 => +
    

    See setq.

    Note: The '+' variable is for interactive programming. It is not recommended to use the '+' variable in program code.

    See also the XLISP Command Loop.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/division.htm0000644000175000000620000000607511512762341023007 0ustar stevestaffXLISP / Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    /


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (/ expr1 ...)
    exprN - integer or floating point number/expression
    returns - the result of the division

    Description

    The '/' function divides the first number given by the rest of the numbers and returns the result. If all the expressions are integers, the division is integer division. If any expression is a floating point number, then the division will be floating point division.

    Examples

    (/ 1)               => 1
    (/ 1 2)             => 0          ; integer division
    (float (/ 1 2))     => 0          ; integer division
    (/ (float 1) 2)     => 0.5        ; type contagion
    (/ 1 1.0 2)         => 0.5        ; type contagion
    (/ (float 1) 2 3)   => 0.166667   ; type contagion
    (/ 1 1.0 2 3 4)     => 0.0416667  ; type contagion
    
    > (print (+ 1 2 (* 3.5 (/ 3.9 1.45))))
    12.4138
    12.4138
    

    See  + ,  * , float, print. XLISP first prints the value on the screen, the second number is the return value.

    In XLISP, the type contagion depends on the order of occurrence:

    (/ 1 2 1.0)  => 0    ; because (/ 1 2)   => 0   and (/ 0 1.0) => 0.0
    (/ 1.0 2 1)  => 0.5  ; because (/ 1.0 2) => 0.5 and (/ 0.5 1) => 0.5
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/restore.htm0000644000175000000620000000702011512762341022635 0ustar stevestaffXLISP restore Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    restore


    Type:   -   function (subr)
    Source:   -   xldmem.c, xlimage.c

    Syntax

    (restore file)
    file - a string or symbol for the name of the file
    returns - NIL on failure, otherwise never returns

    Description

    The 'restore' function restores the previously saved XLISP workspace [system state] from the specified file. The 'file' may be a string or a symbol. If the 'file' does not include a '.wks' suffix, it will be extended to be called 'file.wks'. If successful, 'restore' will print a message saying:

    [ returning to the top level ]
    

    and will not return any value. If 'restore' fails, it will return NIL. There can be several saved workspaces. These workspaces can be restored as often as desired.

    Examples

    (setq myvar 5)       ; set MYVAR to value 5
    myvar                ; returns 5
    
    (save 'farp)         ; save workspace in FARP.wks
    
    (setq myvar "garp")  ; change MYVAR to "garp"
    myvar                ; returns "garp"
    
    (restore 'farp)      ; restore workspace
    myvar                ; returns 5
    

    File names: In the PC and DOS world, all file names and extensions ["foo.bat"] are automatically made uppercase. In using XLISP, this means you don't have to worry about whether the name is "foo.bat", "FOO.BAT" or even "FoO.bAt", they will all work. However, in other file systems [UNIX in particular], uppercase and lowercase do make a difference:

    This will create a file named FOO-FILE in UNIX, because XLISP uppercases its symbols:

    (open 'foo-file :direction :output)
    

    This will create a file named 'foo-file' because UNIX doesn't uppercase its file names:

    (open "foo-file" :direction :output)
    

    So, if you are having trouble with opening and accessing files, check to make sure the file name is in the proper case.

    See the restore function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/progv.htm0000644000175000000620000001153011512762341022310 0ustar stevestaffXLISP progv Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    progv


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (progv symbols values [expr1 expr2 ... ])
    symbols - a list of symbols to be bound
    values - a list of values to be bound to symbols
    exprN - expressions for the body of the loop
    returns - the value of the last expression

    Description

    The 'progv' special form is basically a 'block' construct that contains a block of code [expressions] to evaluate. 'progv' is different from prog1, prog2 and progn in that it contains a pair of lists, 'symbols' and 'values'. Before evaluating the expressions, 'progv' will dynamically bind the 'values' to the corresponding 'symbols'. If there are too many 'symbols' for the 'values', the 'symbols' with no corresponding 'values' will be bound to NIL. The variables will be unbound after the execution of 'progv'. The value of the last 'expr' will be returned as the result of 'progv'. If there are no 'exprs', NIL is returned.

    Examples

    > (progv '(var) '(2)
        (print var)
        (print "two"))
    2      ; output of PRINT
    "two"  ; output of PRINT
    "two"  ; return value
    
    > (setq a "beginning")   ; initialize A
    "beginning"
    
    > (progv '(a) '(during)  ; bind A to a new value
        (print a))
    DURING  ; output of PRINT
    DURING  ; return value     restore A the original value
    
    > (print a)
    "beginning"              ; prints the original value
    "beginning"
    
    > (progv '(no-way) '(no-how))
    NIL
    
    > (progv)
    error: too few arguments
    

    Note: 'progv' is different from prog, which allows symbols and initialization forms, in that 'progv' allows its 'symbols' and 'values' to be evaluated. This allows you to pass in forms that generate the 'symbols' and their 'values'.

    Note: prog1, prog2, progn and 'progv' do not allow the use of return or go or tags for go.

    Important: In contrast to all other binding constructs, 'progv' binds global variables and not lexical variables, so 'progv' behaves like:

    (defun progv (symbols values &rest body)  ; this function does
      (push symbol-values *internal-stack*)   ; not really work,
      (setq symbols values)                   ; it only demonstates
      (prog1                                  ; the principle
        (eval body)
        (setq symbol-values (pop *internal-stack*))))
    

    Variables bound by 'progv' can be manipulated by global functions including symbol-value. All changes to the 'progv' variables by other functions, called in the 'progv' body, will be lost after 'progv' is finished, because the original value from the beginning of 'progv' will be restored. This can be good or bad, depending on the situation.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cddr.htm0000644000175000000620000000567611512762341022105 0ustar stevestaffXLISP cdar, cddr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cdar, cddr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (cdar expr)
    (cddr expr)
    expr - a list or list expression
    returns - the result of the last cdr function

    Description

    The 'cdar' and 'cddr' functions go through the list expression and perform a sequence of car or cdr operations. The sequence of operations is performed from right to left. So 'cdar' does a car on the expression, followed by a cdr. If at any point the list is NIL, then NIL is returned. If at any point a car operation is performed on an atom [as opposed to a list] an error is signalled:

    error: bad argument
    

    Examples

    (setq mylist '((1A 1B) (2A 2B) (3A 3B))) 
    
    (caar mylist)  => 1A
    (cadr mylist)  => (2A 2B)
    
    (cdar mylist)  => (1B)
    (cddr mylist)  => ((3A 3B))
    
    (cdar 'a)      => error: bad argument
    (cdar nil)     => NIL
    

    Note: The 'c...r' functions are part of the historical Lisp functions. You may find it easier to work with the modern lisp functions like nth and nthcdr.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-integer-format.htm0000644000175000000620000001156211512762341025341 0ustar stevestaffXLISP *integer-format* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *integer-format*


    Type:   -   system variable
    Source:   -   xlprin.c

    Syntax

     *integer-format*

    Description

    *integer-format* is a system variable that allows a user to specify how integer numbers are to be printed by XLISP. The value of *integer-format* should be set to one of the string expressions "%ld", "%lo" or "%lx" [the character after the percent character is the lower-case 'L' character]. These format strings are similar to C-language floating point specifications:

    "%ld"   -   decimal
    "%lu"   -   unsigned decimal
    "%lo"   -   unsigned octal
    "%lx"   -   unsigned hexadecimal

    The default value for *integer-format* is the string "%ld".

    Examples

    *integer-format*               ; returns "%ld"
    
    (setq *integer-format* "%ld")  ; signed decimal
    (print 1)                      ; prints 1
    (print 1234)                   ; prints 1234
    (print -1)                     ; prints -1
    (print -1234)                  ; prints -1234
    
    (setq *integer-format* "%lo")  ; octal notation
    (print 1)                      ; prints 1
    (print 1234)                   ; prints 2322
    (print -1)                     ; prints 37777777777
    (print -1234)                  ; prints 37777775456
    
    (setq *integer-format* "%lx")  ; hexadecimal notation
    (print 1)                      ; prints 1
    (print -1)                     ; prints ffffffff
    (print 1234)                   ; prints 4d2
    (print -1234)                  ; prints fffffb2e
    
    (setq *integer-format* "%u")   ; unsigned decimal
    (print 1)                      ; prints 1
    (print 1234)                   ; prints 1234
    (print -1)                     ; prints 4294967295
    (print -1234)                  ; prints 4294966062
    
    (setq *integer-format* "hi")   ; a bad notation
    (print 1)                      ; prints hi
    (print 9999)                   ; prints hi
    
    (setq *integer-format* "%ld")  ; reset to original "%ld"
    

    Note: There can be other characters put in the string, but in general, this will not produce particularly desirable behaviour. There is no error checking performed on the format string.

    See the *integer-format* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-not-equal-i.htm0000644000175000000620000000526511512762341024231 0ustar stevestaffXLISP char-not-equal Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-not-equal


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-not-equal char1 charN ... )
    char1 - a character expression
    charN - character expression(s) to compare
    returns -  T  if the characters are of different ASCII value, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'char-not-equal' function tests if all the character arguments are different values.  T  is returned if the arguments are of different ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is not equal to 'char2'. This test is case insensitive, the character '#\a' is considered to be the same ASCII value as the character '#\A'.

    Examples

    (char-not-equal #\a #\b)      => T
    (char-not-equal #\a #\b #\c)  => T
    (char-not-equal #\a #\a)      => NIL
    (char-not-equal #\a #\b #\b)  => NIL
    (char-not-equal #\A #\a)      => NIL
    (char-not-equal #\a #\A)      => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/integerp.htm0000644000175000000620000000525011512762341022772 0ustar stevestaffXLISP integerp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    integerp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (integerp expr)
    expr - the expression to check
    returns -  T  if the value is an integer, NIL otherwise

    Description

    The 'integerp' predicate function checks if an 'expr' is a integer number.  T  is returned if 'expr' is a integer number, NIL is returned otherwise.

    Examples

    (integerp 1)         ; returns T - integer
    (integerp #x034)     ; returns T - integer readmacro
    (integerp '1)        ; returns T - still an integer
    (setq a 14)
    (integerp a)         ; returns T - evaluates to int.
    (integerp 0)         ; returns T - integer zero
    
    (integerp 1.2)       ; returns NIL - float
    (integerp 0.0)       ; returns NIL - float zero
    (integerp 'a)        ; returns NIL - symbol
    (integerp #\a)       ; returns NIL - character
    (integerp NIL)       ; returns NIL - NIL
    (integerp #(0 1 2))  ; returns NIL - array
    

    See the integerp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/caaar.htm0000644000175000000620000000646011512762341022230 0ustar stevestaffXLISP caaar ... caddr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    caaar ... caddr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (caaar expr)
    (caadr expr)
    (cadar expr)
    (caddr expr)
    expr - a list expression
    returns - the result of the last car function

    Description

    The 'caaar', 'caadr', 'cadar' and 'caddr' functions go through the list expression and perform a sequence of car or cdr operations. The sequence of operations is performed from right to left. So 'caddr' does a cdr on the expression, followed by a cdr, followed by a car. If at any point the list is NIL, then NIL is returned. If at any point a car operation is performed on an atom [as opposed to a list] an error is signalled:

    error: bad argument
    

    The 'caddr' function returns the same result as the third function.

    Examples

    (setq mylist '(((11A 11B) (12A 12B) (13A 13B))
                   ((21A 21B) (22A 22B) (23A 23B))
                   ((31A 31B) (32A 32B) (33A 33B))
                   ((41A 41B) (42A 42B) (43A 43B))))
    
    (caaar mylist)  => 11A
    (caadr mylist)  => (21A 21B)
    (cadar mylist)  => (12A 12B)
    (caddr mylist)  => ((31A 31B) (32A 32B) (33A 33B))
    

    Note: The 'c...r' functions are part of the historical Lisp functions. You may find it easier to work with the modern lisp functions like nth and nthcdr.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-debug-io.htm0000644000175000000620000000376411512762341024116 0ustar stevestaffXLISP *debug-io* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *debug-io*


    Type:   -   system variable
    Source:   -   xlinit.c, xlio.c, xldbug.c

    Syntax

    *debug-io*

    Description

    *debug-io* is a system variable that contains a file pointer pointing to the stream where all debug input and output goes to and from. The default file for *debug-io* is the system standard error device, normally the keyboard and screen.

    Examples

    *debug-io*   ; returns #<File-Stream...>
    

    Note: *trace-output* , *debug-io* and *error-output* are normally all set to the same file stream 'stderr'.

    See the *debug-io* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-not-lessp-i.htm0000644000175000000620000000546711512762341024254 0ustar stevestaffXLISP char-not-lessp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-not-lessp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-not-lessp char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically non-increasing ASCII value, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'char-not-lessp' function tests if all character arguments are monotonically non-increasing.  T  is returned if the arguments are of monotonically non-increasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is greater than or equal to 'char2'. This test is case insensitive, the character '#\a' is considered to be the same ASCII value as the character '#\A'.

    Examples

    (char-not-lessp #\a #\b)      => NIL
    (char-not-lessp #\b #\a)      => T
    (char-not-lessp #\c #\b #\a)  => T
    (char-not-lessp #\a #\a)      => T
    (char-not-lessp #\c #\a #\b)  => NIL
    (char-not-lessp #\A #\a)      => T
    (char-not-lessp #\a #\A)      => T
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-not-lessp-i.htm0000644000175000000620000000757711512762341024651 0ustar stevestaffXLISP string-not-lessp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-not-lessp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-not-lessp string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is greater than or equal to string2 in ASCII ordering, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'string-not-lessp' [string-not-less-than] predicate function takes two string arguments. A non-NIL value is returned if 'string1' is greater than or equal to 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char-not-lessp [char-not-less-than] the corresponding character of 'string2'. This test is not case sensitive, the character '#\a' is considered to be the same as '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string-not-lessp "a" "b")                ; returns NIL
    (string-not-lessp "a" "a")                ; returns 1
    (string-not-lessp "a" "A")                ; returns 1
    (string-not-lessp "A" "a")                ; returns 1
    (string-not-lessp "abc" "abc ")           ; returns NIL
    (string-not-lessp "1234qr" "123456")      ; returns 4
    
    (string-not-lessp "J Smith" "K Jones" :start1 1 :start2 1)  ; strip off the first chars 
                                                                ; returns 2
    

    See the string-not-lessp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/digit-char-p.htm0000644000175000000620000000554511512762341023434 0ustar stevestaffXLISP digit-char-p Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    digit-char-p


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (digit-char-p char)
    char - a character expression
    returns - the digit weight if character is a digit, NIL otherwise

    Description

    The 'digit-char-p' predicate function checks if the 'char' expression is a numeric digit. If 'char' is numeric digit, the equivalent integer value is returned, otherwise a NIL is returned. Decimal digits are '0' [ASCII decimal value 48] through '9' [ASCII decimal value 57].

    Examples

    (digit-char-p #\0)   ; returns 0
    (digit-char-p #\9)   ; returns 9
    (digit-char-p #\A)   ; returns NIL
    (digit-char-p #\a)   ; returns NIL
    (digit-char-p #\.)   ; returns NIL
    (digit-char-p #\-)   ; returns NIL
    (digit-char-p #\+)   ; returns NIL
    

    Note: Other non-digit characters used in numbers are NOT included: plus [+], minus [-], exponent [e or E] and decimal point [.].

    Common Lisp: Common Lisp supports the use of an optional radix parameter. This option specifies numeric base. This allows the 'digit-char-p' to function properly for hexadecimal digits [for example]. Common LISP supports up to base 36 radix systems. XLISP does not support this radix parameter.

    See the digit-char-p predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string.htm0000644000175000000620000000557311512762341022473 0ustar stevestaffXLISP string Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string expr)
    expr - a symbol, character, integer or string expression
    returns - a string

    Description

    The 'string' function makes the 'expr' to be a string. If the 'expr' is a string, it is returned, as is. If the 'expr' is a character, a one-character string is returned. If the 'expr' is a symbol, the symbol is turned into a string. If the 'expr' is an integer, a string representing the character with an ASCII code of the lowest 8-bit of the intger will be returned:

       (string integer)   →   (code-char (rem integer 256))   →   string

    Examples

    (string 'foo)        ; returns "FOO"
    (string 'x)          ; returns "X"
    (string "abcdef")    ; returns "abcdef"
    (string #\a)         ; returns "a"
    (string #\A)         ; returns "A"
    (string #\Newline)   ; returns "\n"
    

    See the string function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/remove-if.htm0000644000175000000620000000512311512762341023045 0ustar stevestaffXLISP remove-if Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    remove-if


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (remove-if test list-expr)
    test - the test function to be performed
    list-expr - the list to remove from
    returns - copy of list with matching elements removed

    Description

    The 'remove-if' function searches through 'list-expr' and removes any elements that pass the 'test'. Note that this operation is non-destructive, it does not modify or affect 'list-expr' directly, it creates a modified copy.

    Examples

    (setq mylist '(1 2 3 4 5 6 7 8))   ; set up a list
    (remove-if 'oddp mylist)           ; returns (2 4 6 8)
    (remove-if 'evenp mylist)          ; returns (1 3 5 7)
    (print mylist)                     ; prints (1 2 3 4 5 6 7 8)
                                       ;   note that MYLIST is not affected
    
    (setq mylist '(a nil b nil c))     ; set up a list
    (remove-if 'null mylist)           ; returns (A B C)
    

    Common Lisp: XLISP does not support the ':from-end', ':start', ':end', ':count' and ':key' keywords which Common Lisp does.

    See the remove-if function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/do-star.htm0000644000175000000620000001457211512762341022535 0ustar stevestaffXLISP do* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    do*


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (do* ([binding ... ]) (test-expr [result]) [expr ... ])
    binding - a variable binding which is can take one of the following forms:
    symbol
    (symbol init-expr [step-expr])
    symbol - a symbol
    init-expr - an initialization expression for symbol
    step-expr - an expression with that symbol is updated at the end of each loop
    test-expr - iteration ends when this expression returns a non-NIL value
    result - an optional expression for the returned result
    expr - expressions comprising the body of the loop which may contain returns, gos or tags for go
    returns - the value of the last result expression

    Description

    The 'do*' special form is basically a 'while' looping construct that contains symbols [with optional initializations and updates], a loop test [with an optional return value] and a block of code [expressions] to evaluate. The 'do*' form evaluates its initializations and updates in sequential order [as opposed to do which doesn't]. The sequence of these events is:

      init-expr execution
      while test-expr do
        loop code execution
        step-expr execution
      end-while
      return result
    

    The first form after the 'do*' is the 'binding' form. It contains a series of 'symbols' or 'bindings'. The 'binding' is a 'symbol' followed by an initialization expression 'init-expr' and an optional 'step-expr'. If there is no 'init-expr', the 'symbol' will be initialized to NIL. There is no specification as to the order of execution of the bindings or the step expressions, except that they happen all together.

    The 'do*' form will go through and create and initialize the symbols. This is followed by evaluating the 'test-expr'. If 'test-expr' returns a non-NIL value, the loop will terminate. If 'test-expr' returns a NIL value then the 'do*' will sequentially execute the 'exprs'. After execution of the loop 'exprs', the 'symbols' are set to the step-exprs' [if the 'step-exprs' exist]. Then, the 'test-expr' is re-evaluated, and so on. The value of the 'result' expression is evaluated and returned. If no 'result' is specified, NIL is returned. When the 'do*' is finished execution, the 'symbols' that were defined will no longer exist or retain their values.

    Examples

    (do                                 ; DO example - won't work
      ((i 0)                            ;   var I=0
       (j i))                           ;   var J=I (won't work)
      ((eql i j) "done")                ;   test and result
      (print "looping"))                ; error: unbound variable - I
    
    (do*                                ; DO* example - will work
      ((i 0)                            ;   var I=0
       (j i))                           ;   var J=I (proper exec. order)
      ((eql i j) "done")                ;   test and result
      (print "looping"))                ;   returns "done"
    
    (do* (i)                            ; DO* loop with var I
      ((eql i 0) "done")                ;   test and result
      (print i) (setq i 0) (print i))   ;   prints NIL 0
                                        ;   returns "done"
    
    (do* (i)                            ; DO* loop with var I
      ((eql i 0))                       ;   test but no result
      (print i) (setq i 0) (print i))   ;   prints NIL 0
                                        ;   returns NIL
    
    (do*                                ; DO* loop
      ((i 0 (setq i (1+ i)))            ;   var I=0  increment by 1
       (j 10 (setq j (1- j))))          ;   var J=10 decrement by 1
      ((eql i j)  "met in the middle")  ;   test and result
      (princ i) (princ " ")             ;   prints  0 10
      (princ j) (terpri))               ;           1 9
                                        ;           2 8
                                        ;           3 7
                                        ;           4 6
                                        ;   returns "met in the middle"
    

    See the do* special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/funcall.htm0000644000175000000620000000741311512762341022604 0ustar stevestaffXLISP funcall Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    funcall


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (funcall function [arg1 ... ])
    function - the function or symbol to be called
    argN - an argument to be passed to function
    returns - the result of calling the function with the arguments

    Description

    The 'funcall' function calls a function with a series of arguments. It returns the result from calling the function with the arguments.

    Examples

    (funcall '+ 1 2 3 4)                 ; returns 10
    (funcall #'+ 1 2 3 4)                ; returns 10
    (funcall '+ '1 '2 '3)                ; returns 6
    
    (setq sys-add (function +))          ; returns #<Subr-+: #22c32>
    (setq a 99)
    (funcall sys-add 1 a)                ; 100
    (funcall sys-add 1 'a)               ; error: bad argument type
                                         ;   you can't add a symbol, only it's value
    
    (setq a 2)                           ; set A
    (setq b 3)                           ; and B values
    (funcall (if (< a b) (function +)    ; 'function' can be computed
                         (function -))
             a b)                        ; returns 5
    
    (defun add-to-list (arg list)        ; add a list or an atom
       (funcall (if (atom arg) 'cons     ;   to the front of a list
                               'append)
                arg list))
    (add-to-list 'a '(b c))              ; returns (A B C)
    (add-to-list '(a b) '(b c))          ; returns (A B B C)
    

    Notes

    In XLISP, a 'special form' of type FSUBR is not a function. This means that 'funcall' only works with functions of type SUBR [built-in function] or CLOSURE [function defined by defun, flet, labels, or lambda], but with special forms of type FSUBR a 'bad function' error is signalled. Here is an example how to work around this behaviour:

    (defun funcall* (function &rest args)
      (if (eq (type-of function) 'fsubr)
          (eval (cons function args))
          (apply function args)))
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-equal-i.htm0000644000175000000620000000514511512762341023430 0ustar stevestaffXLISP char-equal Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-equal


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-equal char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if all characters are equal, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'char-equal' function tests if all the character arguments are equivalent.  T  is returned if the arguments are of the same ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is equal to 'char2'. This test is case insensitive, the character '#\a' is considered to be the same ASCII value as the character '#\A'.

    Examples

    (char-equal #\a #\b)      => NIL
    (char-equal #\b #\a)      => NIL
    (char-equal #\a #\b #\c)  => NIL
    (char-equal #\a #\a)      => T
    (char-equal #\a #\a #\a)  => T
    (char-equal #\a #\a #\b)  => NIL
    (char-equal #\A #\a)      => T
    (char-equal #\a #\A)      => T
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/remprop.htm0000644000175000000620000000642411512762341022645 0ustar stevestaffXLISP remprop Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    remprop


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (remprop symbol property)
    symbol - the symbol with a property list
    property - the property name being removed
    returns - the property value

    Description

    The 'remprop' function removes the 'property' from the 'symbol'. The function returns a NIL. If the 'property' does not exist, there is no error generated. The 'symbol' must be an existing symbol. Property lists are lists attached to any user defined variables. The lists are in the form of:

    (name1 val1 name2 val2 ... )
    

    Any number of properties may be attached to a single variable.

    Examples

    (setq person 'bobby)                 ; create a var with a value
    (putprop person 'boogie 'last-name)  ; add a LAST-NAME property
    (putprop person 'disc-jockey 'job)   ; add a JOB property
    
    (get person 'last-name)              ; retrieve LAST-NAME - boogie
    (get person 'job)                    ; retrieve JOB - disc-jockey
    (get person 'height)                 ; non-existant - returns NIL
    
    (remprop person 'job)                ; remove JOB
    (remprop person 'height)             ; remove non-existant
    

    Common Lisp: Common Lisp does not have a 'remprop' function. It uses setf to achieve this functionality. Porting from Common Lisp to XLISP will work fine since XLISP supports the setf modifications of property lists and the get function to retrieve property values from symbol names. Porting from XLISP to Common LISP will require translating 'remprop' into setf forms.

    See the remprop function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-downcase.htm0000644000175000000620000000401611512762341023672 0ustar stevestaffXLISP char-downcase Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-downcase


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-downcase char)
    char - a character expression
    returns - the lower case character

    Description

    The 'char-downcase' function converts the 'char' expression to lower case. The lower case equivalent of 'char' is returned. If 'char' is not alphabetic [a-z or A-Z], then the character is returned unchanged.

    Examples

    (char-downcase #\0)  => #\0
    (char-downcase #\A)  => #\a
    (char-downcase #\a)  => #\a
    (char-downcase #\[)  => #\[
    (char-downcase #\+)  => #\+
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-show.htm0000644000175000000620000000532311512762341023620 0ustar stevestaffXLISP :show Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :show


    Type:   -   message selector
    Source:   -   xlobj.c

    Syntax

    (send object :show)
    object - an existing object
    returns - the object

    Description

    The ':show' message selector attempts to find the 'show' method in the specified objects class. Since the ':show' message selector is built-in in the root class, this is always a valid message selector. The object must already exist.

    Examples

    (setq my-class (send class :new '(state)))              ; create MY-CLASS with STATE
    
    (send my-class :answer :isnew '()                       ; set up initialization
                                  '((setq state nil) self))
    
    (send my-class :answer :set-it '(value)                 ; create :SET-IT message
                                   '((setq state value)))  
    
    (setq my-obj (send my-class :new))         ; create MY-OBJ of MY-CLASS
    (send my-obj :show)                        ; returns object state including STATE = NIL
    (send my-obj :set-it 5)                    ; STATE is set to 5
    (send new-obj :show)                       ; error: unbound variable
    

    See the :show message selector in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/break.htm0000644000175000000620000000572311512762341022246 0ustar stevestaffXLISP break Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    break


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xldbug.c

    Syntax

    (break [err-msg [arg]])
    err-msg - a string expression for the error message
    arg - an optional argument expression
    returns - NIL when continued from the break loop

    Description

    The 'break' function allows the entry into the Break Loop with a continuable error. The continuable error generated by 'break' does not require any corrective action. The form of the message generated is:

    break: err-msg - arg
    if continued: return from BREAK
    

    The default for 'err-msg' is:

    **BREAK**
    

    From within the Break Loop, if a continue form is evaluated then NIL is returned from 'break'. If desired, the clean-up or top-level functions may be evaluated to abort the Break Loop.

    Examples

    > (break)
    break: **BREAK**
    if continued: return from BREAK
    
    > (break "out")
    break: out
    if continued: return from BREAK
    
    > (break "it" "up")
    break: it - "up"
    if continued: return from BREAK
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-sescape.htm0000644000175000000620000000464611512762341024272 0ustar stevestaffXLISP :sescape Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :sescape


    Type:   -   keyword
    Source:   -   xlread.c

    Syntax

     :sescape

    Description

    The ':sescape' keyword is an entry used in the *readtable* system variable that contains XLISP's data structures relating to the processing of characters from the user [or files] and read-macro expansions. The existance of the ':sescape' keyword means that the specified character is to be used as a single escape character. The system defines that the the backslash character '\' is the only defined ':sescape' character.

    Examples

    ;; define a function to look in a table
    ;; and print out any :SESCAPE character
    
    (defun look-at (table)
      (dotimes (ch 127)
        (prog ((entry (aref table ch)))
          (case entry
            (:SESCAPE (princ (int-char ch)))
            (t nil))))
      (terpri))
    
    (look-at *readtable*)    ; prints  \
    

    Caution: If you experiment with *readtable*, it is useful to save the old value in a variable, so that you can restore the system state.

    See the :sescape keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-temp-path.htm0000644000175000000620000000351311512762341023631 0ustar stevestaffXLISP get-temp-path Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-temp-path


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/win/msvc/winfun.c

    Syntax

    (get-temp-path)
    returns - the resulting full path as a string

    Description

    The 'get-temp-path' function tries to get a path where a temporary file can be created.

    Note: Under Windows, the 'get-temp-path' function is based on environment variables. If XLISP is running as a sub-process to Java, the environment may not exist, in which case the default result is the unfortunate choice 'c:\windows\'.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/print.htm0000644000175000000620000000723411512762341022315 0ustar stevestaffXLISP print Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    print


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlprin.c

    Syntax

    (print expr [dest])
    expr - an expression
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - the expression

    Description

    The 'print' function prints the 'expr' to the specified 'destination'. The 'expr' is printed followed by a 'newline' character. If 'expr' is a string, it will be printed with quotes around the string. The 'expr' is returned as the result. The 'destination' may be a file pointer or a stream. If there is no 'destination', *standard-output* is the default.

    Examples

    (print 'a)                              ; prints A     with #\Newline
    (print '(a b))                          ; prints (A B) with #\Newline
    (print 99)                              ; prints 99    with #\Newline
    (print "hi")                            ; prints "hi"  with #\Newline
    
    (setq f (open "f" :direction :output))  ; create file
    (print "hi" f)                          ; returns "hi"
    (print 727 f)                           ; returns 727
    (print "ho" f)                          ; returns "ho"
    (close f)                               ; file contains "hi"#\Newline
                                            ;               727#\Newline
                                            ;               "ho"#\Newline
    

    Common Lisp: Common Lisp specifies that 'pprint' with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the print function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/macrolet.htm0000644000175000000620000001107611512762341022766 0ustar stevestaffXLISP macrolet Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    macrolet


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (macrolet ([macro ... ]) expr ... )
    macro - a macro definition binding which is of the form:
    (symbol arg-list body)
    symbol - the symbol specifying the macro name
    arg-list - the argument list for the macro
    body - the body of the macro
    expr - an expression
    returns - the value of the last expression

    Description

    The 'macrolet' special form is basically a local block construct that allows local 'macro' definitions followed by a block of code to evaluate. The first form after the macrolet is the 'binding' form. It contains a series of 'macros'. The 'macrolet' form will sequentially execute the 'exprs' after defining the 'macros'. The value of the last 'expr' evaluated is returned. When the 'macrolet' is finished execution, the 'symbols' that were defined will no longer exist.

    Examples

    > (macrolet ((pls (n1 n2)     ; MACROLET defining a PLS macro
                   `(+ ,n1 ,n2)))
        (pls 4 5))
    9
    
    > (pls 4 5)                   ; the PLS macro no longer exists
    error: unbound function - PLS
    
    > (macrolet ()                ; an empty MACROLET
        (print 'a))
    A  ; screen output of PRINT
    A  ; return value
    

    Known Problems

    1. In XLISP, only macros defined by defmacro [interned in the *obarray*] can be used with setf:

    (setq a #(1 2 3))
    
    (defmacro second-array-element (array)
      `(aref ,array 1))
    
    (second-array-element a)            => 2
    (setf (second-array-element a) 'x)  => X
    a                                   => #(1 X 3)
    

    With macros defined by 'macrolet' [stored in the lexical environment], setf signals a 'bad place form' error:

    (macrolet ((second-element (array)
                 `(aref ,array 1)))
      (second-element a))               => X
    
    (macrolet ((second-element (array)
                 `(aref ,array 1)))
      (setf (second-element a) 'y))     => error: bad place form
    

    2. In XLISP, the macroexpand and macroexpand-1 functions can only expand macros defined by defmacro:

    > (macroexpand-1 '(second-array-element a))
    (AREF A 1)
    

    With macros defined by 'macrolet', the macro form is returned unexpanded:

    > (macrolet ((second-element (array)
                   `(aref ,array 1)))
        (macroexpand-1 '(second-element a)))
    (SECOND-ELEMENT A)
    

    In XLISP, the macroexpand and macroexpand-1 functions only search in the *obarray* for defined macros, but not in the lexical environment.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/eq.htm0000644000175000000620000000564211512762341021567 0ustar stevestaffXLISP eq Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    eq


    Type:   -   predicate function (subr)
    Source:   -   xllist.c, xlsubr.c

    Syntax

    (eq expr1 expr2)
    exprN - arbitrary Lisp expressions
    returns -  T  if the expressions eveluate to the same internal value, NIL otherwise

    Description

    Two expressions are 'eq' if the expressions are identical. The 'eq' function tests if the results of the evaluated expressions point to the same memory location.  T  is returned if both expressions evaluate to exactly the same internal value, NIL is returned otherwise.

    Integer numbers being  =  are 'eq' as long as not stored in a CPU register, so the eql function is recommended for testing integers. Also note that arrays, floating-point numbers, lists, and strings are only 'eq' if they are bound as variable values to the same symbol.

    Examples

    (eq 'a 'a)          => T
    (eq 1 1)            => T or NIL
    (eq 1 1.0)          => NIL
    (eq 1.0 1.0)        => NIL
    (eq "a" "a")        => NIL
    (eq '(a b) '(a b))  => NIL
    (eq 'a 34)          => NIL
    
    (setq a '(a b))     ; set value of A to (A B)
    (setq b a)          ; set B to point to A's value
    (setq c '(a b))     ; set value of C to different (A B)
    (eq a b)            => T
    (eq a c)            => NIL
    

    See also eql, equal, cl:equalp.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/reference-index.htm0000644000175000000620000027313611512762341024232 0ustar stevestaffLanguage Reference Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Nyquist / XLISP 2.0 Language Reference


       #  |  a  |  b  |  c  |  d  |  e  |  f  |  g  |  h  |  i  |  k  |  l  |  m  |  n  |  o  |  p  |  q  |  r  |  s  |  t  |  u  |  v  |  w  |  z 

     *    -  variable - most recent result
     **    -  variable - second recent result
     ***    -  variable - third recent result
     +    -  variable - most recent input expression
     ++    -  variable - second recent input expression
     +++    -  variable - third recent input expression
     −    -  variable - the expression currently being evaluated
     [ Back to Top ]       
     +    -  function - add one or several numbers
     −    -  function - negate one number or subtract several numbers
     *    -  function - multiply one or several numbers
     /    -  function - divide one or several numbers
     <    -  function - test if numbers are monotonically increasing
     <=    -  function - test if numbers are monotonically non-decreasing
     =    -  function - test numbers for equality
     /=    -  function - test numbers for non-equality
     >    -  function - test if numbers are monotonically decreasing
     >=    -  function - test if numbers are monotonically non-increasing
     1+    -  function - increment a number by one
     1−    -  function - decrement a number by one
     [ Back to Top ]       
    abs   -  function - compute the absolute value of a number
    acos   -  function - compute the arccosine of a floating point number
    address-of   -  function - get the address of an xlisp node
    alloc   -  function - change the number of nodes to allocate in each segment
    alphanumericp   -  function - is this an alphabetic or a digit character?
    and   -  special form - the logical 'and' of an arbitrary number of expressions
    :answer   -  message selector - add a message to a class
    append   -  function - append lists
    apply   -  function - apply a function to a list of arguments
    *applyhook*   -  system variable - returns NIL [hook not implemented]
    aref   -  function - array accessor for the nth element of an array
    arrayp   -  predicate function - is this an array?
    asin   -  function - compute the arcsine of a floating point number
    assoc   -  function - find an expression in an association list
    atan   -  function - compute the arctangent of a floating point number
    atom   -  predicate function - is this an atom?
    &aux   -  keyword - define auxiliary variables
     [ Back to Top ]       
    backquote   -  special form - fill in a template
    baktrace   -  function - print n levels of trace back information
    bigendianp   -  function - is this a bigendian machine?
    block   -  special form - define a named block
    both-case-p   -  predicate function - is this an uppercase or lowercase alphabetic character?
    boundp   -  predicate function - is a variable value bound to this symbol in the *obarray*?
    break   -  function - enter a Break Loop
    *breakenable*   -  system variable - define if the Break Loop shall be entered on errors
     [ Back to Top ]       
    car   -  function - list accessor for the first element of a list
    caar cadr   -  function - list accessors for a sequence of car and cdr operations
    caaar...caddr   -  function - list accessors for a sequence of car and cdr operations
    caaaar...cadddr   -  function - list accessors for a sequence of car and cdr operations
    case   -  special form - select by case
    catch   -  special form - evaluate expressions and catch throws
    cdr   -  function - list accessor for the tail of a list with the first element removed
    cdar cddr   -  function - list accessors for a sequence of car and cdr operations
    cdaar...cdddr   -  function - list accessors for a sequence of car and cdr operations
    cdaaar...cddddr   -  function - list accessors for a sequence of car and cdr operations
    cerror   -  function - signal a correctable error
    char   -  function - extract a character from a string
    char/=   -  function - test if characters are not equal, case is significant
    char<   -  function - test if characters are monotonically increasing, case is significant
    char<=   -  function - test if characters are monotonically non-decreasing, case is significant
    char=   -  function - test if characters are equivalent, case is significant
    char>   -  function - test if characters are monotonically decreasing, case is significant
    char>=   -  function - test if characters are monotonically non-increasing, case is significant
    characterp   -  predicate function - is this a character?
    char-code   -  function - get the ASCII code of a character
    char-downcase   -  function - convert a character to lower case
    char-equal   -  function - test if characters are equivalent, case is not significant
    char-greaterp   -  predicate function - test if characters are monotonically decreasing, case is not significant
    char-int   -  function - convert a character to an integer
    char-lessp   -  predicate function - test if characters are monotonically increasing, case is not significant
    char-not-equal   -  function - test if characters are different values, case is not significant
    char-not-greaterp   -  predicate function - test if characters are monotonically non-decreasing, case is not significant
    char-not-lessp   -  predicate function - test if characters are monotonically non-increasing, case is not significant
    char-upcase   -  function - convert a character to upper case
    class   -  object - the built-in object class
    :class   -  message selector - return the class of an object
    clean-up   -  function - clean-up after an error
    close   -  function - close a file stream
    code-char   -  function - get the character with a specified ASCII code
    comma   -  reader expansion - comma evaluates expressions in a backquote form
    comma-at   -  reader expansion - splices a list into a expression in a backquote form
    cond   -  special form - evaluate conditionally
    cons   -  function - construct a new list node
    consp   -  predicate function - is this a non-empty list?
    :constituent   -  keyword - readtable entry to specify a character to be used as is
    continue   -  function - continue from a correctable error
    cos   -  function - compute the cosine of a floating point number
     [ Back to Top ]       
    *debug-io*   -  system variable - file pointer for debug input and output
    decf   -  macro - decrement a variable
    defmacro   -  special form - define a Lisp macro
    defun   -  special form - define a Lisp function
    delete   -  function - delete elements from a list
    delete-if   -  function - delete elements from a list that pass a test
    delete-if-not   -  function - delete elements from a list that fail a test
    digit-char   -  function - convert a decimal digit to a character
    digit-char-p   -  predicate function - convert a character to a decimal digit, if possible
    do   -  special form - loop with local 'let' bindings
    do*   -  special form - loop with local 'let*' bindings
    dolist   -  special form - loop through a list
    dotimes   -  special form - loop a given number of times
    dribble   -  function - create a file with a transcript of a Nyquist/ XLISP session
     [ Back to Top ]       
    echoenabled   -  function - turn the console input echo on or off
    endp   -  predicate function - is this the end of a list?
    eq   -  predicate function - equality test comparing memory pointers, may fail on numbers
    eql   -  predicate function - same as 'eq', but works with all symbols and numbers
    equal   -  predicate function - equality test by comparing printed values
    error   -  function - signal a non-correctable error
    *error-output*   -  system variable - file pointer for error input and output
    errset   -  special form - trapping errors
    eval   -  function - evaluate a Lisp expression
    evalhook   -  function - evaluate with hooks
    *evalhook*   -  system variable - user substitute for the evaluator function
    evenp   -  predicate function - is this integer even?
    exit   -  function - exit XLISP
    exp   -  function - compute 'e' to the 'x' power
    expand   -  function - expand memory by adding segments
    expt   -  function - compute 'x' to the 'y' power
     [ Back to Top ]       
    fboundp   -  predicate function - is a function value bound to this symbol in the *obarray*??
    filep   -  function - is this a file?
    find-in-xlisp-path   -  function - searches the XLISP path for a filename
    *file-separator*   -  variable - the operating system's file separator character
    first   -  function - list accessor for the first element of a list
    flatc   -  function - length of printed representation using princ
    flatsize   -  function - length of printed representation using prin1
    flet   -  special form - define local Lisp functions
    float   -  function - convert an integer to a floating point number
    *float-format*   -  system variable - format for printing floating point numbers
    floatp   -  predicate function - is this number a floating point number?
    format   -  function - do formatted output
    fourth   -  function - list accessor for the fourth element of a list
    funcall   -  function - call a function with arguments
    function   -  special form - get the functional value of a symbol or lambda expression
     [ Back to Top ]       
    gc   -  function - call the garbage collector
    gcd   -  function - compute the greatest common divisor
    *gc-flag*   -  system variable - controls the printing of 'gc' messages
    *gc-hook*   -  system variable - function to call after garbage collection
    gensym   -  function - generate an unique Lisp symbol
    get   -  function - list accessor for property lists
    get-env   -  function - get the value of an environment variable
    get-key   -  function - get a single key stroke from the keyboard
    get-lambda-expression   -  function - get the Lisp code of a lambda or macro expression as a list
    get-output-stream-list   -  function - empty a stream and return it's data as a list
    get-output-stream-string   -  function - empty a stream and return it's data as a single string
    get-temp-path   -  function - get a path where a temporary file can be created
    get-user   -  function - get the current user name
    go   -  special form - go to a tag within a 'tagbody' or 'prog'
     [ Back to Top ]       
    hash   -  function - compute the hash index for a symbol
     [ Back to Top ]       
     if    -  special form - evaluate expressions conditionally
    incf   -  macro - increment a variable
    info   -  function - show information about memory usage
    int-char   -  function - convert an integer to a character
    *integer-format*   -  system variable - format for printing integer numbers
    integerp   -  predicate function - is this number an integer?
    intern   -  function - create a new interned symbol
    interpolate   -  function - compute the 'y' coordinate value corresponding to 'x'
    intersection   -  function - compute the intersection of two lists
    :isa   -  message selector - test if object inherits from class
    :isnew   -  message selector - cause an instance to run its initialization method
     [ Back to Top ]       
    keywordp   -  function - is this a keyword?
    &key   -  lambda list keyword - define keyword arguments
     [ Back to Top ]       
    labels   -  special form - define local Lisp functions in a mutually recursive manner
    lambda   -  special form - define a unnamed function
    last   -  function - list accessor for the last element of a list
    length   -  function - returns the length of a list, vector or string
    let   -  special form - define local bindings, evaluated in no specific order
    let*   -  special form - define local bindings, evaluated in sequencial order
    list   -  function - create a list of values
    listdir   -  function - get a list of all filenames in a directory
    listp   -  predicate function - is this a list?
    load   -  function - load a source file
    log   -  function - the natural logarithm of a floating-point number
    logand   -  function - the bitwise 'and' of one or several numbers
    logior   -  function - the bitwise 'inclusive or' of one or several numbers
    lognot   -  function - the bitwise 'exclusive or' of one or several numbers
    logxor   -  function - the bitwise 'not' of a number
    loop   -  special form - basic looping form
    lower-case-p   -  predicate function - is this a lowercase character?
     [ Back to Top ]       
    macroexpand   -  function - expand macro definitions recursively
    macroexpand-1   -  function - expand the first level of a macro definition
    macrolet   -  special form - define a local macro
    make-array   -  function - create an array of specified size
    make-string-input-stream   -  function - create an unnamed stream from a string expression
    make-string-output-stream   -  function - create and return an unnamed output stream
    make-symbol   -  function - create a temporary, uninterned symbol
    mapc   -  function - apply a function to successive 'car's, return the first list of arguments
    mapcar   -  function - apply a function to successive 'car's, return a list of the values
    mapl   -  function - apply a function to successive 'cdr's, return the first list of arguments
    maplist   -  function - apply a function to successive 'cdr's, return a list of the values
    max   -  function - return the largest of one or several numbers
    member   -  function - test if an expression is contained in a list
    :mescape   -  keyword - readtable entry specifying a character to be used as a multiple escape character
    min   -  function - return the smallest of one or several numbers
    minusp   -  predicate function - is this number negative?
     [ Back to Top ]       
    nconc   -  function - destructively concatenate lists
    :new   -  message selector - create a new instance of a class
    nil   -  system constant - representing the empty list as well as the false value
    :nmacro   -  keyword - readtable entry to specify a character to be used as the start of a non-terminating read macro
    not   -  predicate function - is this expression false?
    nstring-downcase   -  function - destructively convert a string or a part of it to lower case
    nstring-upcase   -  function - destructively convert a string or a part of it to upper case
    nth   -  function - list accessor for the nth element of a list
    nthcdr   -  function - list accessor for the nth tail of a list
    null   -  predicate function - is this an empty list?
    numberp   -  predicate function - is this a number?
     [ Back to Top ]       
    *obarray*   -  system variable - the system symbol table
    object   -  object - the build-in object class
    objectp   -  predicate function - is this an object?
    oddp   -  predicate function - is this integer number odd?
    open   -  function - open a file for character or byte i/o
    open-binary   -  function - open a file for multi-byte i/o
    &optional   -  lambda list keyword - define optional arguments
    or   -  special form - the logical 'or' of an arbitrary number of expressions
     [ Back to Top ]       
    peek   -  function - accessor for an internal computer memory value
    peek-char   -  function - look at a single character from a specified source
    pi   -  variable - floating point approximation of the number 'pi'
    plusp   -  predicate function - is this number positive?
    poke   -  function - write a value to the internal computer memory
    pop   -  macro - pop a value from a list
    power   -  function - compute 'x' raised to the 'y' power
    pprint   -  function - print a pretty looking version of an expression
    prin1   -  function - print an expression without a newline
    princ   -  function - print an expression without quoting and without a newline
    print   -  function - print an expression on a new line
    *print-case*   -  system variable - specifies how symbols are printed
    profile   -  function - turn profiling on or off
    prog   -  special form - a 'block' with local 'let' bindings
    prog*   -  special form - a 'block' with local 'let*' bindings
    prog1   -  special form - a 'block' returning the value of the first expression
    prog2   -  special form - a 'block' returning the value of the second expression
    progn   -  special form - a 'block' returning the value of the last expression
    progv   -  special form - a 'block' with local bindings, created out of two lists
    psetq   -  special form - perform 'setq' assignments in parallel
    push   -  macro - push a value to the front of a list
    putprop   -  function - put a property onto a symbol's property list
     [ Back to Top ]       
    quit   -  function - quit XLISP
    quote   -  special form - return an expression unevaluated
     [ Back to Top ]       
    random   -  function - compute an integer random number between 0 and n-1 inclusive
    read   -  function - read a Lisp expression
    read-byte   -  function - read a byte from a stream
    read-char   -  function - read a character from a stream
    read-float   -  function - read a binary floating point number from a stream
    read-int   -  function - read a binary integer number from a stream
    read-line   -  function - read a line from a stream, returned as a string
    *readtable*   -  system variable - contains data structures relating to the processing of characters
    real-random   -  function - compute a floating point random number in an arbitrary range
    rem   -  function - compute the remainder of one or several numbers
    remove   -  function - remove elements from a list
    remove-if   -  function - remove elements from a list that pass a test
    remove-if-not   -  function - remove elements from a list that fail a test
    remprop   -  function - remove a property from a symbol's property list
    rest   -  function - list accessor for the tail of a list, identical to 'cdr'
    &rest   -  lambda list keyword - define 'rest' arguments, to be collected in a list
    restore   -  function - restore a XLISP workspace from a file
    return   -  special form - return from a 'block' construct
    return-from   -  special form - return from a named block
    reverse   -  function - reverse a list
    room   -  function - show memory allocation statistics
    round   -  function - round a number to the next integer value
    rplaca   -  function - replace the first element of a list
    rplacd   -  function - replace the tail of a list
    rrandom   -  function - compute a random floating point number between 0 and 1 inclusive
    *rslt*   -  system variable - used to store multiple return values
     [ Back to Top ]       
    save   -  function - save a XLISP workspace to a file
    second   -  function - list accessor for the second element of a list
    self   -  symbol - evaluates to the current object when used within a message context
    send   -  function - send a message to an object
    send-super   -  function - send a message to the superclass of an object
    :sescape   -  keyword - readtable entry specifying a character to be used as a single escape character
    set   -  function - set the value of a symbol
    set-difference   -  function - compute the set-difference of two lists
    setdir   -  function - set a new working directory
    setf   -  special form - set the value of a place
    setq   -  special form - set the value of a quoted symbol
    setup-console   -  function - set default console attributes
    :show   -  message selector - show an object's instance variables
    sin   -  function - compute the sine of a floating point number
    sort   -  function - destructively sort a list
    soundp   -  function - is this a sound?
    sqrt   -  function - compute the square root of a floating point number
    *standard-input*   -  system variable - file pointer for standard input
    *standard-output*   -  system variable - file pointer for standard output
    strcat   -  function - concatenate strings
    streamp   -  predicate function - is this a stream?
    string   -  function - make a string from a symbol, character or string
    string/=   -  function - test if string1 is not equal to string2, case is significant
    string<   -  function - test if string1 is less than string2, case is significant
    string<=   -  function - test if string1 is less than or equal to string2, case is significant
    string=   -  function - test if the string arguments have the same values, case is significant
    string>   -  function - test if string1 is greater than string2, case is significant
    string>=   -  function - test if string1 is greater than or equal to string2, case is significant
    stringp   -  predicate function - is this a string?
    string-downcase   -  function - convert a string to lower case
    string-equal   -  function - test if string1 equal to string2, case is not significant
    string-greaterp   -  predicate function - test if string1 is greater than string2, case is not significant
    string-left-trim   -  function - trim the left end of a string
    string-lessp   -  predicate function - test if string1 is less than string2, case is not significant
    string-not-equal   -  function - test if string1 is not equal to string2, case is not significant
    string-not-greaterp   -  predicate function - test if string1 is less than or equal to string2, case is not significant
    string-not-lessp   -  predicate function - test if string1 is greater than or equal to string2, case is not significant
    string-right-trim   -  function - trim the right end of a string
    string-search   -  function - search for a pattern in a string
    string-trim   -  function - trim both ends of a string
    string-upcase   -  function - convert a string to upper case
    sublis   -  function - substitute expressions by using an association list
    subseq   -  function - extract a substring
    subsetp   -  function - test if a list is a subset of another list
    subst   -  function - substitute expressions
    symbol-function   -  function - get the functional value of a symbol
    symbol-name   -  function - get the print name of a symbol
    symbol-plist   -  function - get the property list of a symbol
    symbol-value   -  function - get the value of a symbol
    symbolp   -  predicate function - is this a symbol?
    system   -  function - execute a command of the operating system
     [ Back to Top ]       
     t    -  system constant - represents 'true'
    tagbody   -  special form - a 'block' form with labels
    tan   -  function - compute the tangent of a floating point number
    terpri   -  function - terminate printing, prints a newline character
    third   -  function - list accessor for the third element of a list
    throw   -  special form - throw to a 'catch', allows non-local exits and traps
    :tmacro   -  keyword - readtable entry to specify a character to be used as the start of a terminating read macro
    top-level   -  function - clean-up after an error and return to the top level
    trace   -  function - add a function to the trace list
    *tracelimit*   -  system variable - the number of forms printed on entry to the Break Loop
    *tracelist*   -  system variable - a list of the current functions being traced
    *tracenable*   -  system variable - controls whether or not the Break Loop prints any back trace information on entry
    *trace-output*   -  system variable - file pointer for trace output
    truncate   -  function - truncates a number to an integer
    type-of   -  function - compute the type of a Lisp expression
     [ Back to Top ]       
    *unbound*   -  system constant - used to indicate when a symbol has no value
    union   -  function - compute the union of two lists
    unless   -  special form - evaluate only when a condition is false
    untrace   -  function - remove a function from the trace list
    unwind-protect   -  special form - allows the trapping of all forms of exit from a protected form
    upper-case-p   -  predicate function - is this an uppercase character?
     [ Back to Top ]       
    vector   -  function - create an initialized vector [one-dimensional array]
     [ Back to Top ]       
    when   -  special form - evaluate only when a condition is true
    while   -  macro - loop while a condition is met
    :white-space   -  keyword - readtable entry to specifying a character that may be skipped over
    write-byte   -  function - write a byte to a stream
    write-char   -  function - write a character to a stream
    write-float   -  function - write a binary floating point number to a stream
    write-int   -  function - write a binary integer number to a stream
     [ Back to Top ]       
    zerop   -  predicate function - is this number zero?

    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-output-stream-list.htm0000644000175000000620000000456211512762341025541 0ustar stevestaffXLISP get-output-stream-list Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-output-stream-list


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (get-output-stream-list stream)
    stream - an output stream expression
    returns - the output so far as a list

    Description

    The 'get-output-stream-list' function empties the specified 'stream' and returns this data as a list. The output stream is emptied by this operation.

    Examples

    (setq out (make-string-output-stream))  ; returns #<Unnamed-Stream: #...>
    
    (format out "123")                      ; add some data to output stream
    (get-output-stream-list out)            ; returns (#\1 #\2 #\3)
    
    (format out "123")                      ; add some data to output stream
    (read out)                              ; returns 123
    (get-output-stream-list out)            ; returns NIL, the string was emptied by 'read'
    

    See the get-output-stream-list function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/addition.htm0000644000175000000620000000430611512762341022751 0ustar stevestaffXLISP + Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    +


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (+ expr1 ...)
    exprN - integer or floating point number/expression
    returns - the result of adding the expressions

    Description

    The '+' function adds a list of numbers together and returns the result.

    Examples

    (+ 1)         => 1
    (+ 1 2)       => 3
    (+ 1 2 3)     => 6
    (+ 1 2 3 4)   => 10
    
    > (print (+ 1 2 (* 3.5 (/ 3.9 1.45))))
    12.4138  ; screen output of PRINT
    12.4138  ; return value
    

    See  * ,  / , print. XLISP first prints the value on the screen, the second number is the return value.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/prog2.htm0000644000175000000620000000511711512762341022210 0ustar stevestaffXLISP prog2 Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    prog2


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (prog2 [expr1 expr2 ... ])
    exprN - expressions comprising the body of the loop
    returns - the value of the second expression

    Description

    The 'prog2' special form is basically a 'block' construct that contains a block of code [expressions] to evaluate. The value of the second expression 'expr2' will be returned as the result of 'prog2'. If there is no 'expr2', 'expr1' is returned. If there is no 'expr1', NIL is returned.

    Examples

    (prog2 (print "hi") (print "ho"))  ; prints "hi" "ho"  returns "ho"
    (prog2)                            ; returns NIL
    (prog2 (print "hi"))               ; prints "hi"  returns "hi"
    (prog2 (print "ho") "hey")         ; prints "ho"  returns "hey"
    (prog2 'a 'b 'c)                   ; returns B
    

    Note: prog1 , 'prog2', progn and progv do not allow the use of return or go or tags for go.

    See the prog2 special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/alloc.htm0000644000175000000620000000512411512762341022247 0ustar stevestaffXLISP alloc Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    alloc


    Type:   -   function (subr)
    Source:   -   xldmem.c

    Syntax

    (alloc size)
    size - the number of nodes to allocate as an integer
    returns - the old number of nodes to allocate

    Description

    The 'alloc' function changes the number of memory nodes allocated per segment whenever memory is expanded. The previous number of nodes allocated per segment is the value returned as the result. The power-up default is 1000 nodes per segment. Note that 'alloc' does not, itself, expand memory. You need to call the expand function to do the expand operation.

    Examples

    > (room)
    Nodes:       4000
    Free nodes:  1669
    Segments:    4
    Allocate:    1000    ; default ALLOC value
    Total:       52570
    Collections: 8
    NIL
    
    > (alloc 2000)       ; new ALLOC value
    1000                 ; old ALLOC value
    
    > (room)
    Nodes:       4000
    Free nodes:  1655
    Segments:    4
    Allocate:    2000    ; new ALLOC value
    Total:       52570
    Collections: 8
    NIL
    

    See room.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-gc-hook.htm0000644000175000000620000001216111512762341023741 0ustar stevestaffXLISP *gc-hook* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *gc-hook*


    Type:   -   system variable
    Source:   -   xldmem.c

    Syntax

     *gc-hook*

    Description

    *gc-hook* is a system variable that allows a user function to be performed everytime garbage is collected [either explicitly with gc or automatically]. The default value for *gc-hook* is NIL. When *gc-hook* is set to a non-NIL symbol, it is enabled to execute the specified user routine. The user routine can be a quoted symbol or a closure. There are two parameters to the user routine, the total number of nodes and current free nodes after the garbage collection.

    Examples

    *gc-hook*                           ; returns NIL
    (gc)                                ; returns NIL
    
    (defun mygchook (&rest stuff)       ; define the hook
      (print stuff)
      (print "my hook"))
    
    (setq *gc-hook* 'mygchook)          ; set up *GC-HOOK*
    
    (gc)                                ; prints (2640 232)
                                        ;        "my hook"
                                        ; returns NIL
    
    (setq *gc-flag* T)                  ; turn on the system GC message
    
    (gc)                                ; prints
                                        ;   [ gc: total 2640, (2640 241)
                                        ;   "my hook"
                                        ;   236 free ]
                                        ; returns NIL
    
    (setq *gc-flag* NIL)                ; turn off GC message
    
    (setq *gc-hook* (lambda (x y)       ; enable user routine
                      (princ "\007")))  ;   that beeps at every GC
    
    (gc)                                ; beeps
    
    (defun expand-on-gc (total free)    ; define EXPAND-ON-GC
      (if (< (/ free 1.0 total) .1)     ; IF free/total < .10
          (progn (expand 2)             ;    THEN expand memory
                 (princ "\007"))))      ;         and beep
    
                                        ; NOTE: XLISP already gets more nodes
                                        ; automatically, this is just an example.
    
    (setq *gc-hook* 'expand-on-gc)      ; enable EXPAND-ON-GC
    (gc)                                ; beeps when low on nodes
    

    Note: The *gc-hook* and *gc-flag* facilities can interact. If you do printing in the *gc-hook* user form and enable *gc-flag* , the *gc-hook* printing will come out in the middle of the *gc-flag* message.

    Note: The *gc-hook* user form is evaluated after the execution of the actual garbage collection code. This means that if the user form causes an error, it does not prevent a garbage collection.

    Note: Since *gc-hook* is set to a symbol, the user defined form can be changed by doing another defun [or whatever] to the symbol in *gc-hook*. Note also that you should define the symbol first and then set *gc-hook* to the symbol. If you don't, an automatic garbage collection might occur before you set *gc-hook*, generating an error and stopping your program.

    See the *gc-hook* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/eval.htm0000644000175000000620000000465211512762341022111 0ustar stevestaffXLISP eval Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    eval


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xleval.c

    Syntax

    (eval expression)
    expression - an arbitrary expression
    returns - the result of evaluating the expression

    Description

    The 'eval' function evaluates the 'expression' and returns the resulting value.

    Examples

    (eval '(+ 2 2))            ; returns 4
    (eval (cons '+ '(2 2 2)))  ; returns 6
    (eval (list '+ '2 '3 ))    ; returns 5
    
    (setq a 10)                ; set up A with value 10
    (setq b 220)               ; set up B with value 220
    
    (eval (list '+ a b ))      ; returns 230 because
                               ;   (list '+ a b) => '(+ 10 220)
    
    (eval (list '+ 'a b))      ; returns 230 because
                               ;   (list '+ 'a b) => '(+ A 220)
                               ;   and A has the value 10
    

    See the eval function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/nstring-downcase.htm0000644000175000000620000000552311512762341024445 0ustar stevestaffXLISP nstring-downcase Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    nstring-downcase


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (nstring-downcase string [{:start | :end} offset] ... )
    string - a string expression
    offset - an optional integer expression for a keyword
    returns - the converted string, not a copy

    Description

    The 'nstring-downcase' function takes a string argument and makes it lower case. This function modifies the string or string variable itself, it does not just make a copy. The lower case string is returned.

    The keyword arguments allow for accessing substrings within 'string'. The keyword arguments require a keyword [':start' or ':end'] first and a single integer expression second. The ':start' keyword specifies the starting offset for the 'nstring-downcase' operation on 'string'. A value of 0 starts the string at the beginning [no offset]. The ':end' keyword specifies the end offset for the operation on 'string'.

    Examples

    (nstring-downcase "ABcd+-12&[")                ; returns "abcd+-&["
    (nstring-downcase "ABCDEFGH" :start 2 :end 4)  ; returns "ABcdEFGH"
    
    (setq mystr "ABcdEFgh")        ; set up variable
    (nstring-downcase mystr)       ; returns "abcdefgh"
    (print mystr)                  ; prints  "abcdefgh"
                                   ; note that MYSTR is modified
    

    See the nstring-downcase function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-isnew.htm0000644000175000000620000000637011512762341023770 0ustar stevestaffXLISP :isnew Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :isnew


    Type:   -   message selector
    Source:   -   xlobj.c

    Syntax

    (send object :isnew args)
    object - an existing object
    args - the arguments to be passed to the init code
    returns - the object
    (send class :isnew ivars [cvars [superclass]])
    class - an existing XLISP class
    ivars - list of instance variables for the new class
    cvars - list of class variable symbols for the new class
    superclass - superclass for the new object, default is object
    returns - the new class object

    Description

    The ':isnew' message selector causes an instance to run its initialization method. If an ':isnew' message is sent to a class, the class definition and state will be reset as specified in the arguments of the message.

    Examples

    (setq a-class (send class :new '(state)))   ; create a new class A-CLASS with STATE
    
    (send a-class :answer :isnew '()            ; set up initialization
                                 '((setq state nil) self))
    
    (send a-class :answer :set-it '(value)      ; create :SET-IT message
                                  '((setq state value)))
    
    (setq an-obj (send a-class :new))           ; create AN-OBJ out of A-CLASS
    
    (send an-obj :show)                         ; returns object - STATE = NIL
    
    (send an-obj :set-it 5)                     ; STATE is set to 5
    (send an-obj :show)                         ; returns object - STATE = 5
    
    (SEND an-obj :ISNEW)                        ; re-initialize AN-OBJ
    (send an-obj :show)                         ; returns object - STATE = NIL
    

    See the :isnew message selector in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/echoenabled.htm0000644000175000000620000000373511512762341023414 0ustar stevestaffXLISP echoenabled Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    echoenabled


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/win/wingui/winguistuff.c, sys/win/msvc/winstuff.c

    Syntax

    (echoenabled flag)
    flag -  T  to enable echo, NIL to disable
    returns - NIL

    Description

    The 'echoenabled' function turns console input echoing on or off.

    Note: The 'echoenabled' function is only implemented under Linux and Mac OS X. If Nyquist I/O is redirected through pipes, the Windows version does not echo the input, but the Linux and Mac versions do. You can turn off echoing with this function. Under windows it is defined to do nothing.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/flet.htm0000644000175000000620000000571511512762341022115 0ustar stevestaffXLISP flet Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    flet


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (flet ([function ... ]) expr ... )
    function - a function definition binding which is of the form:
    (symbol arg-list body)
    symbol - the symbol specifying the function name
    arg-list - the argument list for the function
    body - the body of the function
    expr - an expression
    returns - the value of the last expression

    Description

    The 'flet' special form is basically a local block construct that allows local 'function' definitions followed by a block of code to evaluate. The first form after the 'flet' is the 'binding' form. It contains a series of 'functions'. The 'flet' form will go through and define the 'symbols' of the 'functions' and then sequentially execute the 'exprs'. The value of the last 'expr' evaluated is returned. When the 'flet' is finished execution, the 'symbols' that were defined will no longer exist.

    Examples

    (flet ((fuzz (x) (+ x x)))  ; an FLET with FUZZ local function
      (fuzz 2))                 ; returns 4
                                ; FUZZ no longer exists
    
    (fuzz 2)                    ; error: unbound function - FUZZ
    
                                ; an empty flet
    (flet () (print 'a))        ; prints A
    

    Note: 'flet' does not allow recursive definitions of functions. The labels special form does allow this.

    See the flet special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/apply.htm0000644000175000000620000000523311512762341022303 0ustar stevestaffXLISP apply Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    apply


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (apply function args)
    function - the function or symbol to be applied to 'args'
    args - a list that contains the arguments to be passed to 'function'
    returns - the result of applying the function to the arguments

    Description

    The 'apply' function causes 'function' to be evaluated with 'args' as the parameters, returning the result of 'function'. The 'args' argument must be a list.

    Examples

    > (defun my-add (x y)        ; define MY-ADD function
        (+ x y))
    MY-ADD
    
    > (my-add 1 2)               ; ordinary function call
    3                            ; returns 3
    
    > (apply #'my-add '(2 4))    ; symbol-function applied to argument-list
    6                            ; returns 6
    

    Note: When using 'apply' to cause the evaluation of a function, you can use the sharp-quoted name of the function like #'my-add in the example, or (function my-add). In XLISP also 'my-add and (quote my-add) work, but this is no good Lisp style.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-float-format.htm0000644000175000000620000001467411512762341025020 0ustar stevestaffXLISP *float-format* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *float-format*


    Type:   -   system variable
    Source:   -   xlprin.c

    Syntax

     *float-format*
    returns - the print format for floating-point numbers

    Description

    *float-format* is a system variable that allows a user to specify how floating point numbers are to be printed by XLISP. The value of *float-format* should be set to one of the string expressions "%e", "%f" or "%g". These format strings are similar to C-language floating point specifications:

      "%e"   -  exponential. The number is converted to decimal notation of the form:
    [-]m.nnnnnnE[+-]xx
    
    There is one leading digit. There are 6 digits after the decimal point.
     
      "%f"   -  decimal. The number is converted to decimal notation of the form:
    [-]mmmmmm.nnnnnn
    
    There are as many digits before the decimal point as necessary. There are 6 digits after the decimal point.
     
      "%g"   -  shortest. The number is converted to either the form of "%e" or "%f", whichever produces the shortest output string. Non-significant zeroes are not printed.

    The default value for *float-format* is the string "%g".

    There are several additional flags and options available:

         +   -  always print the sign
       space   -  print a space instead of a + sign
         #   -  always print the dot, do not remove zeros after the dot
        .n   -  number of digits after the dot

    The flags and options must be written between the "%" and the formatting letter, as shown in the examples below.

    Examples

    (setq *float-format* "%e")       ; exponential notation
    (print 1.0)                      => 1.000000e+00
    (print -9e99)                    => -9.000000e+99
    
    (setq *float-format* "%f")       ; decimal notation
    (print 1.0)                      => 1.000000
    (print 1.0e4)                    => 10000.000000
    (print -999.99e-99)              => -0.000000
    
    (setq *float-format* "%g")       ; shortest notation
    (print 1.0)                      => 1
    (print 1.0e7)                    => 1e+07
    (print -999.999e99)              => -9.99999e+101
    
    (setq *float-format* "%+g")      ; always print the sign
    (print  1.1)                     => +1.1
    (print -1.1)                     => -1.1
    
    (setq *float-format* "% g")      ; print a space instead of the + sign
    (print  1.1)                     =>  1.1
    (print -1.1)                     => -1.1
    
    (setq *float-format* "%#.10g")   ; ten digits after the dot
    (print 1.0)                      => 1.000000000
    (print 1.0e7)                    => 10000000.00
    (print -999.9999999e99)          => -9.999999999e+101
    
    (setq *float-format* "%+#.10g")  ; ten digits after the dot plus sign
    (print  1.2345)                  => +1.234500000
    (print -1.2345)                  => -1.234500000
    
    (setq *float-format* "%%")       ; bad format
    (print 1.0)                      => %%
    
    (setq *float-format* "%g")       ; reset to shortest notation
    

    Note: The string in the *float-format* variable is the format specifier for the the underlying 'sprintf' C-function.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/logxor.htm0000644000175000000620000000517511512762341022475 0ustar stevestaffXLISP logxor Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    logxor


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (logxor expr1 ... )
    exprN - an integer expression
    returns - the result of the eXclusive OR operation

    Description

    The 'logxor' function returns the logical bitwise 'exclusive-or' of the list of expressions. If there is only one argument, it is returned unaltered. If there are two or more arguments, the 'logxor' function performs the 'exclusive-or' successively applying the bitwise operation.

    Examples

    (logxor 0 0)                  ; returns 0
    (logxor 0 1)                  ; returns 1
    (logxor 1 0)                  ; returns 1
    (logxor 1 1)                  ; returns 0
    
    (logxor #b0011 #b0101)        ; returns 6
    (logxor 255 #xF0)             ; returns 15
    (logxor 255 #x0F)             ; returns 240
    (logxor 255 (logxor 255 99))  ; returns 99
    

    Note: XLISP does not check when read-macro expansions like '#x0FF' are out of bounds. It gives no error message and will just truncate the number to the low-order bits that it can deal with [usually 32 bits or 8 hex digits].

    See the logxor function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/throw.htm0000644000175000000620000000074311512762341022322 0ustar stevestaffXLISP throw Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    throw


    See catch.

    nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/type-of.htm0000644000175000000620000000777711512762341022560 0ustar stevestaffXLISP type-of Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    type-of


    Type:   -   function (subr)
    Source:   -   xlsys.c

    Syntax

    (type-of expr)
    expr - an expression to check
    returns - the type of the expression

    Description

    The 'type-of' function returns the type of the expression.

    • SYMBOL - for symbols
    • OBJECT - for objects
    • CONS - for conses
    • SUBR - for built-in functions
    • FSUBR - for special forms
    • CLOSURE - for defined functions
    • STRING - for strings
    • FIXNUM - for integers
    • FLONUM - for floating point numbers
    • CHARACTER - for characters
    • FILE-STREAM - for file pointers
    • UNNAMED-STREAM - for unnamed streams
    • ARRAY - for arrays

    Examples

    (type-of NIL)                             ; returns NIL
    (type-of '#(1 2 3))                       ; returns ARRAY
    (type-of (lambda (x) (print x)))          ; returns CLOSURE
    (type-of '(a b))                          ; returns CONS
    (type-of #'savefun)                       ; returns CLOSURE
    (type-of '(a . b))                        ; returns CONS
    (type-of *standard-output*)               ; returns FILE-STREAM
    (type-of 1.2)                             ; returns FLONUM
    (type-of #'do)                            ; returns FSUBR
    (type-of 1)                               ; returns FIXNUM
    (type-of object)                          ; returns OBJECT
    (type-of "str")                           ; returns STRING
    (type-of #'car)                           ; returns SUBR
    (type-of 'a)                              ; returns SYMBOL
    (type-of #\a)                             ; returns CHARACTER
    (type-of (make-string-input-stream "a"))  ; returns UNNAMED-STREAM
    

    Common Lisp: The XLISP and Common Lisp 'type-of' functions are basically the same. Differences between the two can occur in what the types are called [like CHARACTER in XLISP and STANDARD-CHAR in Common Lisp]. Also, Common Lisp can give additional information. For strings, it returns a list of the form (SIMPLE-STRING 32) where the number 32 is the string size.

    See the type-of function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-standard-input.htm0000644000175000000620000000425711512762341025356 0ustar stevestaffXLISP *standard-input* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *standard-input*


    Type:   -   system variable
    Source:   -   xlinit.c

    Syntax

     *standard-input*

    Description

    The *standard-input* system variable contains a file pointer that points to the file where all normal input from the programmer or user comes from. The default file for *standard-input* is the system standard input device, normally the system keyboard.

    Examples

    *standard-input*   ; returns #<File-Stream: #2442e>
    

    Note: Be careful when modifying the *standard-input*. If you do not save the old file pointer, you will not be able to return to normal operation and will need to exit XLISP. If the file or source that you have set *standard-input* to does not reset *standard-input* to its previous value, you will never get control back to the keyboard.

    See the *standard-input* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/remove-if-not.htm0000644000175000000620000000517011512762341023645 0ustar stevestaffXLISP remove-if-not Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    remove-if-not


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (remove-if-not test list-expr)
    test - the test function to be performed
    list-expr - the list to remove from
    returns - a copy of list-expr with non-matching elements removed

    Description

    The 'remove-if-not' function searches through 'list-expr' and removes any elements that fail the 'test'. Note that this operation is non-destructive, it does not modify or affect 'list-expr' directly, it creates a modified copy.

    Examples

    (setq mylist '(1 2 3 4 5 6 7 8))   ; set up a list
    (remove-if-not 'oddp mylist)       ; returns (1 3 5 7)
    (remove-if-not 'evenp mylist)      ; returns (2 4 6 8)
    (print mylist)                     ; prints (1 2 3 4 5 6 7 8)
                                       ;   note that MYLIST is not affected
    
    (setq mylist '(a nil b nil c))     ; set up a list
    (remove-if-not 'null mylist)       ; returns (NIL NIL)
    

    Common Lisp: XLISP does not support the ':from-end', ':start', ':end', ':count' and ':key' keywords which Common Lisp does.

    See the remove-if-not function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-user.htm0000644000175000000620000000355311512762341022714 0ustar stevestaffXLISP get-user Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-user


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/win/msvc/winstuff.c

    Syntax

    (get-user)
    returns - a string naming the user, or "nyquist"

    Description

    The 'get-user' function returns the current user name. In Unix systems [including OS X and Linux], this is the value of the USER environment variable. In Windows, this is currently just "nyquist", which is also returned if the environment variable cannot be accessed. This function is used to avoid the case of two users creating files of the same name in the same temp directory.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/system.htm0000644000175000000620000000433111512762341022500 0ustar stevestaffXLISP system Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    system


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/mac/macfun.c, sys/win/msvc/winfun.c

    Syntax

    (system command)
    command - the OS command string to be executed
    returns -  T  if the command was successful, the error code otherwise

    Description

    The 'system' function will send the 'command' string to the underlying operating system for execution. After execution of the 'command', the 'system' function will return a  T  result if the 'command' was successful. If the 'command' was not successful, the numeric error code will be returned. Any output from the 'command' execution will not be put in the transcript file.

    Note: In Nyquist, this function is only defined to work on Unix systems [including Linux and Mac OS X]. On Windows systems, NIL is returned.

    Examples

    (system "ls")     ; do a directory listing
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/float.htm0000644000175000000620000000401311512762341022256 0ustar stevestaffXLISP float Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    float


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (float expr)
    expr - integer or floating point number/expression
    returns - the result as a floating point number

    Description

    The 'float' function takes a numeric expression and returns the result as a floating point number.

    Examples

    (/ 1 2)            ; returns 0 (integer division)
    (/ (float 1) 2)    ; returns 0.5
    (float (/ 1 2))    ; returns 0 (integer division)
    (/ 1 2 3)          ; returns 0 (integer division)
    (/ (float 1) 2 3)  ; returns 0.166667
    

    See the float function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/real-random.htm0000644000175000000620000000410511512762341023354 0ustar stevestaffXLISP real-random Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    real-random


    Type:   -   Lisp function (closure)
    Source:   -   misc.lsp

    Syntax

    (real-random from to)
    from, to - the limits as integer or floating point numbers
    returns - a random floating point number between from and to

    In Nyquist, 'real-random' is implemented as a Lisp function:

    (defun real-random (from to)
      (+ (* (rrandom) (- to from)) from))
    

    Description

    The 'real-random' function returns a random floating point number between 'from' and 'to'. See also rrandom, which is equivalent to:

    (real-random 0 1))
    

    Examples

    
    

    See also rrandom.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/upper-case-p.htm0000644000175000000620000000447711512762341023470 0ustar stevestaffXLISP upper-case-p Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    upper-case-p


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (upper-case-p char)
    char - a character expression
    returns -  T  if the character is upper case, NIL otherwise

    Description

    The 'upper-case-p' predicate function checks if the 'char' expression is an upper case character. If 'char' is upper case a  T  is returned, otherwise a NIL is returned. Upper case characters are 'A' [ASCII decimal value 65] through 'Z' [ASCII decimal value 90].

    Examples

    (upper-case-p #\A)   ; returns T
    (upper-case-p #\a)   ; returns NIL
    (upper-case-p #\1)   ; returns NIL
    (upper-case-p #\[)   ; returns NIL
    

    See the upper-case-p predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/object.htm0000644000175000000620000001053311512762341022423 0ustar stevestaffXLISP object Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    object


    Type:   -   object
    Source:   -   xlobj.c

    Syntax

     object

    Description

    'object' is an object class. An object is a composite structure that contains internal state information, methods [which respond to messages], a pointer to the object's class and a pointer to the object's super-class. XLISP contains two built in objects: 'object' and class. 'object' is the superclass for the class object.

    Examples

    (send object :show)                                     ; look at the object definition
    
                                                            ; example use of objects
    (setq my-class (send class :new '(state)))              ; new class MY-CLASS with STATE
           
    (send my-class :answer :isnew '()                       ; set up initialization
                                  '((setq state nil) self))
    
    (send my-class :answer :set-it '(value)                 ; create :SET-IT message
                                   '((setq state value)))
    
    (setq my-obj (send my-class :new))                      ; create MY-OBJ out of MY-CLASS
    (send my-obj :set-it 5)                                 ; STATE is set to 5
    

    Object definition: The internal definition of the 'object' object instance is:

    Object is #<Object: #23fd8>, Class is #<Object: #23fe2>
      MESSAGES = ((:SHOW . #<Subr-: #23db2>) 
                  (:CLASS . #<Subr-: #23dee>) 
                  (:ISNEW . #<Subr-: #23e2a>))
      IVARS = NIL
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = NIL
      IVARCNT = 0
      IVARTOTAL = 0
    #<Object: #23fd8>
    

    The class of 'object' is class. There is no superclass of 'object'. Remember that the location information [like #23fd8] varies from system to system, yours will probably look different.

    Built-in methods: The built in methods in XLISP include:

    • :answer - add a method to an object
    • :class - return the object's class
    • :isnew - run initialization code on object
    • :new - create a new object [instance or class]
    • :show - show the internal state of the object

    Message structure: The normal XLISP convention for a 'message' is to have a valid symbol preceeded by a colon like :isnew or ':my-message'. However, it is possible to define a 'message' that is a symbol without a colon, but this makes the code less readable.

    See the object class in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/flatc.htm0000644000175000000620000000413111512762341022243 0ustar stevestaffXLISP flatc Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    flatc


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlprin.c

    Syntax

    (flatc expr)
    expr - an expression
    returns - the length

    Description

    The 'flatc' function determines the character length that would be printed if the 'expr' were printed using princ. This means that the 'expr' would be printed without a new-line. If 'expr' is a string, it would not be printed with quotes around the string. The print character length is returned as the result.

    Examples

    (flatc 1234)          ; returns 4
    (flatc '(a b c))      ; returns 7
    (flatc "abcd")        ; returns 4
    (flatc 'mybigsymbol)  ; returns 11
    

    See the flatc function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/rplacd.htm0000644000175000000620000000530711512762341022425 0ustar stevestaffXLISP rplacd Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    rplacd


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (rplacd list expr)
    list - the list to destructively modify
    expr - the expression to replace the cdr of list
    returns - the list node after updating the cdr

    Description

    The 'rplacd' function destructively modifies the cdr of 'list' and replaces it with the 'expr'. The destructive aspect of this operation means that the actual symbol value is used in the list-modifying operations, not a copy. 'list' must evaluate to a valid list.

    An atom or NIL for 'list' will result in an error:

    error: bad argument type
    

    Examples

    (setq a '(1 2 3))          ; set up A with (1 2 3)
    (rplacd a 'new)            ; returns (1 . NEW)
    
    (print a)                  ; prints (1 . NEW)
                               ;   note that A is modified
    
    (rplacd a '(a new list))   ; returns (1 A NEW LIST)
    (rplacd '(1 2 3) '(more))  ; returns (1 MORE)
    
    (rplacd 'a 'b)             ; error: bad argument type
    (rplacd NIL 'b)            ; error: bad argument type
    

    See the rplacd function in the XLISP 2.0 manual.

      Back to Top


    XLISP > XLISP 2.0  -  Contents  -  Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/reverse.htm0000644000175000000620000000437211512762341022634 0ustar stevestaffXLISP reverse Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    reverse


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (reverse list-expr)
    list-expr - a list or list expression
    returns - a new list in the reverse order

    Description

    The 'reverse' function reverses the 'list-expr'. The reversed list is the returned value. The reversal process only occurs on the 'top-level' of the 'list-expr'. If there are nested sub-lists, these are left intact.

    Examples

    (reverse NIL)                     ; returns NIL
    (reverse 'a)                      ; error: bad argument type
    (reverse '(a))                    ; returns (A)
    (reverse '(a b c))                ; returns (C B A)
    (reverse '((a b) (c d) (e f)))    ; returns ((E F) (C D) (A B))
    (reverse (list (+ 1 2) (+ 3 4)))  ; returns (7 3)
    

    See the reverse function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-search.htm0000644000175000000620000000357211512762341023733 0ustar stevestaffXLISP string-search Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-search


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-search pattern string &key :start :end)
    pattern - a string to search for
    string - the string to be searched
    :start integer - the starting offset in string
    :end integer - the ending offset + 1
    returns - index of pattern in string or NIL if not found

    Description

    The 'string-search' function searches for 'pattern' in 'string' and returns the index of the first 'pattern' found in 'string' or NIL if no pattern was found.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/reference-format.htm0000644000175000000620000000501211512762341024375 0ustar stevestaffEntry Format Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Entry Format


    Each entry is a symbol of some variety that the XLISP system will recognize. The parts of each reference entry include:

    1. The Headline of the page gives the name or symbol of the entry.

    2. The Reference section below the headline gives infomations in the following order:

      • Type may be one of the following:

        • function (subr)
        • predicate function (subr)
        • special form (fsubr)
        • reader expansion
        • system variable
        • system constant
        • keyword
        • object
        • message selector
      • Source specifies the source file where the routine or code associated with the entry resides. [Please not that I have copied the source file locations out of the Tim I Mikkelsen manual without checking, so some of them may be wrong.]

    3. Syntax defines the syntax or usage of the entry. It is also used to specify the arguments. Items written in italics are arguments. Items enclosed between square brackets like '[' and ']' are optional entries. Items that have '...' [ellipses] indicate that there can be one or many of the item. Items enclosed between '{' and '}' which are separated by '|' indicate that one of the items should be included.

    4. Description defines the entry, necessary conditions, results, defaults, etc.

    5. Examples shows example uses of the entry.

    6. The Comments section after the examples includes additional information such as compatibility notes, bugs, usage notes, potential problems, keystroke equivalences, etc.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/dolist.htm0000644000175000000620000001025611512762341022455 0ustar stevestaffXLISP dolist Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    dolist


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (dolist (symbol list-expr [result]) [expr ... ])
    symbol - a symbol
    list-expr - a list expression
    result - an optional expression for the returned result
    expr - expressions comprising the body of the loop which may contain returns, gos or tags for go
    returns - the return value of the result expression or NIL

    Description

    The 'dolist' special form is basically a list-oriented 'for' looping construct that contains a loop 'symbol', a 'list-expr' to draw values from, an optional 'return' value and a block of code [expressions] to evaluate. The sequence of execution is:

      symbol    := CAR of list-expr
      temp-list := CDR of list-expr
      while  temp-list is not empty
        loop code execution
        symbol    := CAR of temp-list
        temp-list := CDR of temp-list
      end-while
      return result
    

    The main loop 'symbol' will take on successive values from 'list-expr'. The 'dolist' form will go through and create and initialize the 'symbol'. After execution of the loop 'exprs', the 'symbol' is set to the next value in the 'list-expr'. This continues until the 'list-expr' has been exhausted. The value of the 'result' expression is evaluated and returned. If no 'result' is specified, NIL is returned. When the 'dolist' is finished execution, the 'symbol' that was defined will no longer exist or retain its value. If the 'list-expr' is an empty list, then no loop execution takes place and the 'result' is returned.

    Examples

      (dolist (i () "done")        ; DOLIST with I loop variable
              (print "here"))      ;   an empty list
                                   ;   and a return value
                                   ;   returns "done"
    
      (dolist (x '(a b c) "fini")  ; DOLIST with X loop variable
              (princ x))           ;   a list with (A B C)
                                   ;   and a return value
                                   ;   prints  ABC   returns "fini"
    
      (dolist (y '(1 2 3))         ; DOLIST with Y loop variable
              (princ (* y y)))     ;   a list with (1 2 3)
                                   ;   and no return value
                                   ;   prints  149   returns NIL
                                   ;   returns "met in the middle"
    

    See the dolist special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/catch.htm0000644000175000000620000001254011512762341022237 0ustar stevestaffXLISP catch, throw Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    catch, throw


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c, xljump.c

    Syntax

    (catch tag-symbol [expr ... ])
    tag-symbol - an expression that evaluates to a symbol
    expr - an optional series of expressions to be evaluated
    returns - the value of the last expression the throw expression
    (throw tag-symbol [expr])
    tag-symbol - an expression that evaluates to a symbol
    expr - an optional expression to be returned
    returns - never returns

    Description

    The 'catch' and 'throw' special forms allow for non-local exits and traps without going through the intermediate evaluations and function returns:

    (catch tag-symbol
      [expr ...]
      (throw tag-symbol [expr]))
    

    If there is a 'catch' for a 'tag-symbol' that has no 'throw' performed to it, 'catch' returns the value returned from 'expr':

    > (catch 'mytag
        (+ 1 (+ 2 3)))
    6
    

    If there is no 'expr', NIL is returned:

    > (catch 'mytag)
    NIL
    

    The 'expr' in 'throw' specifies what value is to be returned by the corresponding 'catch':

    > (catch 'mytag
        (+ 1 (throw 'mytag 55)))
    55
    

    If there is no 'expr' in 'throw', NIL is returned to the corresponding 'catch':

    > (catch 'mytag
        (throw 'mytag))
    NIL
    

    If more than one 'catch' is set up for the same 'tag-symbol', the most recently evaluated 'tag-symbol' will be the one that does the actual catching:

    > (catch 'mytag
        (catch 'mytag
          (throw 'mytag))
        (print 'hello))
    HELLO
    

    If a 'throw' is evaluated with no corresponding 'catch', an error is signalled:

    > (catch 'mytag
        (throw 'foo))
    error: no target for THROW
    

    Examples

    (defun in (x)
      (if (numberp x)           ; if X is a number
          (+ x x)               ; then double X
          (throw 'math 42)))    ; else throw 42
    
    (defun out (x)
      (princ "<") 
      (princ  (* (in x) 2))     ; double via multiply
      (princ ">")
      "there")
    
    (defun main (x)
      (catch 'math (out x)))    ; catch the throw from IN
    
    > (in 5)
    10       ; return value
    
    > (out 5)
    <20>     ; screen output of PRINC
    "there"  ; return value
    
    > (main 5)
    <20>     ; screen output of PRINC
    "there"  ; return value
    
    > (main 'a)
    <        ; screen output of PRINC
    42       ; return value
    

    See  + ,  * , defun,  if , numberp, princ.

    Note: 'catch' and 'throw' accept not only symbols as 'tag-symbol', but if a 'tag-symbol' cannot be compared via eql, an error is signalled:

    > (catch "mytag"
        (throw "mytag"))
    error: no target for THROW
    

    This was reproduced with Nyquist 3.03 in December 2010.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/loop.htm0000644000175000000620000000540311512762341022126 0ustar stevestaffXLISP loop Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    loop


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (loop body ... )
    body - a series of expressions
    returns - never returns [must use non-local exit]

    Description

    The 'loop' special form specifies a 'repeat-forever' construct. The expressions in'body' will be evaluated. When the last expression is evaluated in 'body', 'loop' will then repeat the 'body'. When a return is evaluated within a 'loop', the specified value will be returned. 'loop' itself does not generate a return value. Other exit mechanisms include go , throw , return-from and errors.

    Examples

    (setq i 65)                      ; initial value
    
    (loop                            ; LOOP
      (princ (int-char i))           ;   print the character
      (if (= i 90) (return "done"))  ;   test for limit
      (setq i (1+ i)))               ;   increment and repeat
                                     ; prints ABCDEFGHIJKLMNOPQRSTUVWXYZ
                                     ; returns "done"
    

    Note: If you create a 'loop' with no exit mechanism, you will probably have to abort your XLISP session.

    See the loop special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/not.htm0000644000175000000620000000460411512762341021757 0ustar stevestaffXLISP not Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    not


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (not expr)
    expr - the expression to check
    return -  T  if the value is NIL , NIL otherwise

    Description

    The 'not' predicate function checks to see if the 'expr' is false.  T  is returned if the expression is NIL , NIL is returned otherwise.

    Examples

    (not '())      ; returns T - empty list
    (not ())       ; returns T - still empty
    (setq a NIL)   ; set up a variable
    (not a)        ; returns T - value = empty list
    
    (not "a")      ; returns NIL - not a list
    (not 'a)       ; returns NIL - not a list
    

    Note: The 'not' predicate is the same function as the null predicate.

    See the not predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-not-greaterp-s.htm0000644000175000000620000000534211512762341024741 0ustar stevestaffXLISP char<= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char<=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char<= char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically non-decreasing ASCII value, NIL otherwise
    Note: case is significant with this function

    Description

    The 'char<=' function tests if all character arguments are monotonically non-decreasing.  T  is returned if the arguments are of monotonically non-decreasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is less than or equal to 'char2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than the character '#\A'.

    Examples

    (char<= #\a #\b)      => T
    (char<= #\b #\a)      => NIL
    (char<= #\a #\b #\c)  => T
    (char<= #\a #\a)      => T
    (char<= #\a #\b #\b)  => T
    (char<= #\A #\a)      => T
    (char<= #\a #\A)      => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cos.htm0000644000175000000620000000373711512762341021751 0ustar stevestaffXLISP cos Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cos


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (cos expr)
    expr - floating point number/expression
    returns - the cosine of the number

    Description

    The 'cos' function returns the cosine of the 'expr'. The 'expr' is in radians.

    Examples

    (cos 0.0)            ; returns 1
    (cos (/ 3.14159 2))  ; returns 1.32679e-06 (almost 0)
    (cos .5)             ; returns 0.877583
    (cos 0)              ; error: bad integer operation
    (cos 1.)             ; error: bad integer operation
    

    See the cos function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get.htm0000644000175000000620000000632311512762341021736 0ustar stevestaffXLISP get Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (get symbol property)
    symbol - the symbol with a property list
    property - he property name being retrieved
    returns - the property value or NIL

    Description

    The 'get' function returns the value of the'property' from the 'symbol'. If the 'property' does not exist, a NIL is returned. The 'symbol' must be an existing symbol. The returned value may be a single value or a list.

    Property lists are lists attached to any user defined variables. The lists are in the form of:

    (name1 value1 name2 value2 ... )
    

    Any number of properties may be attached to a single variable.

    Examples

    (setq person 'bobby)                  ; create a variable with a value
    (putprop person 'boogie 'last-name)   ; add a LAST-NAME property
    (putprop person 'disc-jockey 'job)    ; add a JOB property
    
    (get person 'last-name)               ; retrieve LAST-NAME - boogie
    (get person 'job)                     ; retrieve JOB - disc-jockey
    (get person 'height)                  ; non-existant - returns NIL
    
    (putprop person '(10 20 30) 'stats)   ; add STATS - a list
    (get person 'stats)                   ; retrieve STATS - (10 20 30)
    

    Note: You can set a property to the value NIL. However, this NIL value is indistinguishable from the NIL returned when a property does not exist.

    Common Lisp: Common Lisp allows for an optional default value, which XLISP does not support.

    See the get function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/pop.htm0000644000175000000620000000411611512762341021753 0ustar stevestaffXLISP pop Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    pop


    Type:   -   Lisp macro
    Source:   -   misc.lsp

    Syntax

    (pop list)
    list - a list
    returns - the first element from the list

    'pop' is implemented as a Lisp macro:

    (defmacro pop (lis)
      `(prog1 (car ,lis)
              (setf ,lis (cdr ,lis))))
    

    Description

    The 'pop' macro reads, removes and returns the first element from the list.

    Examples

    (setq stack '(a b c))  => (A B C)
    (pop stack)            => A  
    stack                  => (B C)
    (pop stack)            => B  
    stack                  => (C)
    (pop stack)            => C 
    stack                  => NIL
    (pop stack)            => NIL
    stack                  => NIL
    

    See setq. See also the push macro.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/make-string-output-stream.htm0000644000175000000620000000524111512762341026225 0ustar stevestaffXLISP make-string-output-stream Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    make-string-output-stream


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (make-string-output-stream)
    returns - an unnamed output stream

    Description

    The 'make-string-output-stream' function creates and returns an unnamed output stream. The stream can then be used as any other stream object.

    Examples

    (make-string-output-stream)             ; returns #<Unnamed-Stream: #2d9c0>
    
    (setq out (make-string-output-stream))  ; returns #<Unnamed-Stream: #2d95c>
    
    (format out "fee fi fo fum ")           ; \
    (format out "I smell the blood of ")    ;  fill up output stream
    (format out "Elmer Fudd")               ; /
    (get-output-stream-string out)          ; returns "fee fi fo fum I smell the blood of Elmer Fudd"
    
    (format out "~%now what")               ; add more to output stream
    (get-output-stream-string out)          ; returns "\nnow what"
    
    (format out "hello")                    ; add more to output stream
    (read out)                              ; returns HELLO
    

    See the make-string-output-stream function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/nth.htm0000644000175000000620000000417211512762341021750 0ustar stevestaffXLISP nth Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    nth


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (nth expr list-expr)
    expr - an integer expression
    list-expr - a list or list expression
    returns - the nth element or NIL if the list isn't that long

    Description

    'nth' returns the 'expr'-th element of 'list-expr'. If the 'list-expr' is shorter than 'expr', a NIL is returned. The counting sequence is base zero, the first element is the 0th element.

    Examples

    (nth 4 '(0 1 2 3 4 5 6))  ; returns 4
    (nth 3 '(a b))            ; returns NIL
    
    (nth 4 'a)                ; error: bad argument type
    (nth 3 "abcdefg")         ; error: bad argument type
    

    See the nth function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-tracelist.htm0000644000175000000620000000417611512762341024413 0ustar stevestaffXLISP *tracelist* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *tracelist*


    Type:   -   system variable
    Source:   -   xlinit.c, xleval.c

    Syntax

     *tracelist*

    Description

    The *tracelist* system variable contains a list of the current functions being traced.

    Examples

    (defun foo (x) (print (car x)))  ; define FOO
    (trace foo)                      ; returns (FOO)
    (trace car)                      ; returns (CAR FOO)
    
    (print *tracelist*)              ; prints (CAR FOO)
    
    (untrace foo)                    ; returns (CAR)
    (untrace car)                    ; returns NIL
    
    (print *tracelist*)              ; prints NIL
    

    See the *tracelist* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-lessp-i.htm0000644000175000000620000000532111512762341023443 0ustar stevestaffXLISP char-lessp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-lessp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-lessp char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically increasing ASCII value, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'char-lessp' function tests if all the character arguments are monotonically increasing.  T  is returned if the arguments are of increasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is less than 'char2'. This test is case insensitive, the character '#\a' is considered to be the same ASCII value as the character '#\A'.

    Examples

    (char-lessp #\a #\b)      => T
    (char-lessp #\b #\a)      => NIL
    (char-lessp #\a #\b #\c)  => T
    (char-lessp #\a #\a)      => NIL
    (char-lessp #\a #\b #\b)  => NIL
    (char-lessp #\A #\a)      => NIL
    (char-lessp #\a #\A)      => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/increment.htm0000644000175000000620000000347211512762341023145 0ustar stevestaffXLISP 1+ Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    1+


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (1+ expr)
    expr - integer or floating point number/expression
    returns - the number plus one

    Description

    The '1+' [increment] function adds one to a number and returns the result.

    Examples

    (1+ 1)     => 2
    (1+ 99.1)  => 100.1
    (1+ 1 2)   => error: too many arguments
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cons.htm0000644000175000000620000000416511512762341022123 0ustar stevestaffXLISP cons Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cons


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (cons expr-car expr-cdr)
    expr-car - an expression
    expr-cdr - an expression
    returns - the new list

    Description

    The 'cons' function takes two expressions and constructs a new list from them. If the 'expr-cdr' is not a list, then the result will be a 'dotted-pair'.

    Examples

    (cons 'a 'b)           ; returns (A . B)
    (cons 'a nil)          ; returns (A)
    (cons 'a '(b))         ; returns (A B)
    (cons '(a b) '(c d))   ; returns ((A B) C D)
    (cons '(a b) 'c)       ; returns ((A B) . C)
    (cons (- 4 3) '(2 3))  ; returns (1 2 3)
    

    See the cons function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-equal-s.htm0000644000175000000620000000710011512762341024024 0ustar stevestaffXLISP string= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string= string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns -  T  if the string arguments have the same values, NIL otherwise
    Note: case is significant with this function

    Description

    The 'string=' [string-equal] function takes two string arguments. It checks to see if the string arguments have the same values.  T  is returned if 'string1' is equal to 'string2', NIL is returned otherwise. This test is case sensitive, the character '#\a' is different and of greater ASCII value than '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string= "a" "b")           ; returns NIL
    (string= "a" "a")           ; returns T
    (string= "a" "A")           ; returns NIL
    (string= "A" "a")           ; returns NIL
    (string= "abc" "abc ")      ; returns NIL
    
    (string= "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars 
                                                       ; returns T
    
    (string= "abc" "123456789" :end2 3 :end1 3)        ; leave just the first 3 chars 
                                                       ; returns NIL
    

    See the string= function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lambda-keyword-rest.htm0000644000175000000620000001057711512762341025042 0ustar stevestaffXLISP &rest Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    &rest


    Type:   -   keyword
    Source:   -   xleval.c

    Syntax

    &rest [rest-arg]
    rest-arg - rest argument symbol

    Description

    In XLISP, there are several times that you define a formal argument list for a body of code like defun , defmacro , :answer and lambda. All of the formal arguments that are defined are required to appear in the invocation of the defined function or operation. If there are any &optional arguments defined, they will be filled in order. If there is a '&rest' argument defined, and all the required formal arguments and &optional arguments are filled, any and all further parameters will be passed into the function via the 'rarg' argument. There can be only one 'rest-arg' argument for '&rest'. If there are insufficient parameters for any of the &optional or '&rest' arguments, they will contain NIL. At the end of the function or operation execution, these local symbols and their values are removed.

    Examples

    (defun foo                             ; define function FOO
      (a b &optional c d &rest e)          ;   with some of each argument
      (print a) (print b)
      (print c) (print d)                  ;   print out each
      (print e))
    (foo)                                  ; error: too few arguments
    (foo 1)                                ; error: too few arguments
    (foo 1 2)                              ; prints 1 2 NIL NIL NIL
    (foo 1 2 3)                            ; prints 1 2 3 NIL NIL
    (foo 1 2 3 4)                          ; prints 1 2 3 4 NIL
    (foo 1 2 3 4 5)                        ; prints 1 2 3 4 (5)
    (foo 1 2 3 4 5 6 7 8 9)                ; prints 1 2 3 4 (5 6 7 8 9)
    
    (defun my-add                          ; define function MY-ADD
      (num1 &rest num-list &aux sum)       ;   with 1 arg, rest, 1 aux var
      (setq sum num1)                      ;   clear SUM
      (dotimes (i (length num-list) )      ;   loop through rest list
        (setq sum (+ sum (car num-list)))  ;      add the number to sum
        (setq num-list (cdr num-list)))    ;      and remove num from list
      sum)                                 ;   return sum when finished
    (my-add 1 2 3 4)                       ; returns 10
    (my-add 5 5 5 5 5)                     ; returns 25
    

    See the &rest keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/power.htm0000644000175000000620000000360611512762341022314 0ustar stevestaffXLISP power Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    power


    Type:   -   Lisp function (closure)
    Source:   -   misc.lsp

    Syntax

    (power x y)
    x, y - two integer or floating point numbers
    returns - x raised to the y power as a floating point number

    In Nyquist, 'power' is implemented as a Lisp function:

    (defun power (x y)
      (exp (* (log (float x)) y)))
    

    Description

    The 'power' function returns 'x' raised to the 'y' power as a floating point number.

    Examples

    (power 2 8)   => 256
    (power 4 .5)  => 2.0
    

    See also expt.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/macroexpand-1.htm0000644000175000000620000000556311512762341023623 0ustar stevestaffXLISP macroexpand-1 Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    macroexpand-1


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (macroexpand-1 form)
    form - a macro form
    returns - the macro expansion

    Description

    The 'macroexpand-1' function takes a 'form' and expands the first level of the macro definition used in the 'form'. The function returns the expansion. If the 'form' does not contain a macro, the form is returned unaltered.

    Examples

    (defmacro plus (n1 n2) `(+ ,n1 ,n2))   ; define PLUS macro
    (plus 1 2)                             ; returns 3
    (macroexpand '(plus 3 4))              ; returns (+ 3 4)
    (macroexpand-1 '(plus 3 4))            ; returns (+ 3 4)
    
    (defmacro pl (p1 p2) `(plus ,p1 ,p2))  ; define PL macro using PLUS
    (pl 3 4)                               ; returns 7
    (macroexpand '(pl 3 4))                ; returns (+ 3 4)
    (macroexpand-1 '(pl 3 4))              ; returns (PLUS 3 4)
    

    Common Lisp: Common Lisp returns 2 values for its result of 'macroexpand-1', the expanded form and a  T  or NIL value that indicates if the form was a macro. XLISP returns only the expanded form. Common Lisp also supports an optional argument in 'macroexpand-1' for the environment of the expansion. XLISP does not support this optional argument.

    See the macroexpand-1 function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/address-of.htm0000644000175000000620000000572611512762341023214 0ustar stevestaffXLISP address-of Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    address-of


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (address-of expr)
    expr - an expression
    returns - the memory address of the expression as an integer

    Description

    The 'address-of' function returns the internal memory address of the XLISP node that corresponds to 'expr'. The value returned is an integer.

    Examples

    (setq var 0)                    => 0   ; set up VAR with 0
    (address-of var)                => 123224
    (address-of 'var)               => 182638
    (peek (address-of var))         => 83951616
    (peek (1+ (address-of var)))    => 16777216
    (peek (+ 2 (address-of var)))   => 0   ; value of VAR
    (setq var 14)                   => 14  ; change the value to 14
    (peek (+ 2 (address-of var)))   => 14
    (setq var 99)                   => 99  ; change the value to 99
    (peek (+ 2 (address-of var)))   => 99
    

    See  + , 1+, peek, setq.

    Nyquist: The 'address-of' function is internally disabled, but the code still exists. Look out for PEEK_AND_POKE in the Nyquist source code.

    Caution: Be careful when modifying the internal state of XLISP. If you have modified it, it would be a good idea to exit XLISP and re-enter before doing any work you really want to retain.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/tan.htm0000644000175000000620000000433311512762341021740 0ustar stevestaffXLISP tan Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    tan


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (tan expr)
    expr - floating point number or expression
    returns - the tangent of the number

    Description

    The 'tan' function calculates the tangent of the 'expr' and returns the result. The 'expr' is in radians.

    Examples

    (tan 0.0)             ; returns 0
    (tan 1.0)             ; returns 1.55741
    (tan (/ 3.14159 2))   ; returns 753696
    (tan 2.0)             ; returns -2.18504
    (tan 3.0)             ; returns -0.142547
    (tan 3.14159)         ; returns -2.65359e-06
    (tan 4.5)             ; returns 4.63733
    

    Common Lisp: Common Lisp allows for integer numbers, which XLISP does not support for 'tan'.

    See the tan function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/symbol-name.htm0000644000175000000620000000451011512762341023376 0ustar stevestaffXLISP symbol-name Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    symbol-name


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (symbol-name symbol)
    symbol - an expression that evaluates to a symbol name
    returns - the symbol's print name

    Description

    The 'symbol-name' function takes the 'symbol' expression and returns the printable string of the 'symbol'. If the 'symbol' had not existed, then it will be created and interned into the system symbol table *obarray* , but with it's value unbound and an empty property list.

    Examples

    (symbol-name 'foo)        ; returns "FOO"
    (symbol-name 'gleep)      ; returns "GLEEP"
    
    (setq my-symbol 'flop)    ; define MY-SYMBOL
    (symbol-name my-symbol)   ; returns "FLOP"
    

    XLISP Bug: The 'symbol-name' function signals a 'bad argument type' error with the symbol NIL [Nyquist 3.03 in December 2010].

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-answer.htm0000644000175000000620000000724411512762341024143 0ustar stevestaffXLISP :answer Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :answer


    Type:   -   message selector
    Source:   -   xlobj.c

    Syntax

    (send class :answer selector fargs body)
    class - an existing class
    selector - the message selector symbol
    fargs - formal argument list of the same form as a lambda argument list
    body - a list containing the method code
    returns - the class object

    Description

    The ':answer' message selector adds or changes a method in the specified class. This method consists of the message selector symbol, the formal argument list and the executable code associated with the message.

    Examples

    (setq myclass (send class :new '(var)))  ; create MYCLASS with VAR
    
    (send myclass :answer :isnew '()         ; set up initialization
      '((setq var nil) self))
    
    (send myclass :answer :set-it '(value)   ; create :SET-IT message
      '((setq var value)))
    
    (send myclass :answer :mine '()          ; create :MINE message
      '((print "hi there")))
    
    (setq my-obj (send myclass :new))        ; create MY-OBJ of MYCLASS
    (send my-obj :set-it 5)                  ; VAR is set to 5
    (send my-obj :mine)                      ; prints  "hi there"
    

    Note: When you define a message in a class, the message is only valid for instances of the class or its sub-classes. You will get an error if you try to send the message to the class where it was first defined. If you want to add a message to a class, you need to define it in the super-class of the class.

    Message structure: The normal XLISP convention for a message is to have a valid symbol preceeded by a colon like :isnew or ':my-message'. However, it is possible to define a message that is a symbol without a colon, but this pollutes the global namespace and also makes the code less readable.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/load.htm0000644000175000000620000001477711512762341022112 0ustar stevestaffXLISP load Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    load


    Type:   -   function (subr)
    Source:   -   xlsys.c, xlread.c

    Syntax

    (load file [:verbose v-flag] [:print p-flag]))
    file - a string expression or symbol
    v-flag - an optional key-word expression, default is  T 
    p-flag - an optional key-word expression, default is NIL
    returns - the filename

    Description

    The 'load' function opens the 'file', reads and evaluates all the forms within the 'file'. 'file' may be a string expression or a symbol. When 'file' is a string, you may specify a complete file location or extensions like "/usr/local/bin/myfile.lsp" or "A:\LISP\TIM.LSP". If 'file' is a string and includes a file type or an extension [like ".lsp"], then 'load' accesses the specified file. If there is no extension on 'file', it will add ".lsp". If the ':verbose' keyword is present and 'v-flag' is non-NIL , a load message of the form:

    ; loading "xxxx.lsp"
    

    will be printed to *standard-output*. If the ':print' keyword is present and 'p-flag' is non-NIL , the resulting value of each top-level form in 'file' will be printed to *standard-output*. If the file load was successful, then  T  is returned as the result. If the file load was not successful, a NIL is returned.

    Note: in Nyquist, the XLISP 'load' function first tries to load a file from the current directory. A '.lsp' extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32.

    Examples

    (load 'gloop)                     ; prints  ; loading "GLOOP.lsp"
                                      ; returns NIL   there is no file
    
    (defun foo (x) (print x))         ; create a function
    (savefun foo)                     ; create a file FOO.lsp
    
    (load 'foo)                       ; prints  ; loading "FOO.lsp"
                                      ; returns T
    
    (load 'foo :verbose NIL)          ; no printing   returns T
    
    (load 'foo :print T)              ; prints  FOO   returns T
    
    (load 'save :verbose T :print T)  ; prints  ; loading "FOO.lsp"
                                      ; prints  FOO   returns T
    
    (load "foo")                      ; prints  ; loading "foo.lsp"
                                      ; returns NIL - didn't work
                                      ;   because the file is "FOO.lsp"
    
    (load "FOO")                      ; prints  ; loading "FOO.lsp"
                                      ; returns T - did work
    
    (load "FOO.lsp")                  ; prints  ; loading "FOO.lsp"
                                      ; returns T - did work
    

    File names: In the PC and DOS world, all file names and extensions ["foo.bat"] are automatically made uppercase. In using XLISP, this means you don't have to worry about whether the name is "foo.bat", "FOO.BAT" or even "FoO.bAt", they will all work. However, in other file systems [UNIX in particular], uppercase and lowercase do make a difference:

    This will create a file named FOO-FILE in UNIX, because XLISP uppercases its symbols:

    (open 'foo-file :direction :output)
    

    This will create a file named 'foo-file' because UNIX doesn't uppercase its file names:

    (open "foo-file" :direction :output)
    

    So, if you are having trouble with opening and accessing files, check to make sure the file name is in the proper case.

    Common Lisp: Common Lisp has a 'load' function that is similar to XLISP's 'load'. The only difference is that Common Lisp uses an optional keyword parameter ':if-does-not-exist' which XLISP does not support.

    Nyquist: in Nyquist, the XLISP 'load' function first tries to load a file from the current directory. A '.lsp' extension is added if there is not already an alphanumeric extension following a period. If that fails, XLISP searches the path, which is obtained from the XLISPPATH environment variable in Unix and HKEY_LOCAL_MACHINE\SOFTWARE\CMU\Nyquist\XLISPPATH under Win32. [The Macintosh version has no search path.]

    Note: In XLISP, the keyword parameters are order sensitive. If both ':verbose' and ':print' keywords are used, ':verbose' must come first.

    See the load function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/arrayp.htm0000644000175000000620000000507411512762341022457 0ustar stevestaffXLISP arrayp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    arrayp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (arrayp expr)
    expr - an arbitrary Lisp expression
    returns -  T  if the value is an array, NIL otherwise

    Description

    The 'arrayp' function checks if 'expr' evaluates to an array.  T  is returned if 'expr' evaluates to an array, NIL is returned otherwise.

    Examples

    (arrayp #(0 1 2))  => T    ; array
    (setq a #(a b c))  => #(A B C))
    (arrayp a)         => T    ; evaluates to an array
    (arrayp '(a b c))  => NIL  ; list
    (arrayp 1)         => NIL  ; integer
    (arrayp 1.2)       => NIL  ; float
    (arrayp 'a)        => NIL  ; symbol
    (arrayp #\a)       => NIL  ; character
    (arrayp NIL)       => NIL  ; NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-lessp-i.htm0000644000175000000620000000745411512762341024045 0ustar stevestaffXLISP string-lessp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-lessp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-lessp string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is less than string2 in ASCII ordering, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'string-lessp' [string-less-than] predicate function takes two string arguments. A non-NIL value is returned if 'string1' is less than 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char-lessp [char-less-than] the corresponding character of 'string2'. This test is not case sensitive, the character '#\a' is considered to be the same as '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string-lessp "a" "b")                  ; returns 0
    (string-lessp "a" "a")                  ; returns NIL
    (string-lessp "a" "A")                  ; returns NIL
    (string-lessp "A" "a")                  ; returns NIL
    (string-lessp "abc" "abc ")             ; returns 3
    (string-lessp "1234567" "1234qrst")     ; returns 4
    
    (string-lessp "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars
                                                            ; returns NIL
    

    See the string-lessp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/minusp.htm0000644000175000000620000000512011512762341022464 0ustar stevestaffXLISP minusp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    minusp


    Type:   -   predicate function (subr)
    Source:   -   xlmath.c

    Syntax

    (minusp expr)
    expr - the numeric expression to check
    returns -  T  if the number is negative, NIL otherwise

    Description

    The 'minusp' predicate function checks to see if the number 'expr' is negative.  T  is returned if the number is negative [less than zero], NIL is returned otherwise. An error is generated if the 'expr' is not a numeric expression:

    error: bad argument type
    

    Examples

    (minusp 1)             ; returns NIL
    (minusp 0)             ; returns NIL
    (minusp -1)            ; returns T
    (minusp -.000000005)   ; returns T
    (minusp #xFFFFFFFF)    ; returns T
    (minusp #x01)          ; returns NIL
    
    (minusp 'a)            ; error: bad argument type
    (setq a -3.5)          ; set A to -3.5
    (minusp a)             ; returns T
    

    See the minusp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/objectp.htm0000644000175000000620000000405511512762341022605 0ustar stevestaffXLISP objectp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    objectp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (objectp expr)
    expr - the expression to check
    returns -  T  if the expression is an object, NIL otherwise

    Description

    The 'objectp' predicate function checks if the 'expr' is an object.  T  is returned if 'expr' is an object, NIL is returned otherwise.

    Examples

    (objectp object)   ; returns T
    (objectp class)    ; returns T
    (objectp NIL)      ; returns NIL
    (objectp '(a b))   ; returns NIL
    

    See the objectp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/third.htm0000644000175000000620000000502511512762341022267 0ustar stevestaffXLISP third Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    third


    Type:   -   function (subr)
    Source:   -   xlinit.c

    Syntax

    (third expr)
    expr - a list or list expression
    returns - the third element of expr or NIL

    Description

    The 'third' function returns the third element of a list or list expression. If the list is NIL , NIL is returned.

    Examples

    (third '(1 2 3 4))                       ; returns 3
    (third NIL)                              ; returns NIL
    
    (setq kids '(junie vickie cindy chris))  ; set up variable KIDS
    (first kids)                             ; returns JUNIE
    (second kids)                            ; returns VICKIE
    (third kids)                             ; returns CINDY
    (fourth kids)                            ; returns CHRIS
    (rest kids)                              ; returns (VICKIE CINDY CHRIS)
    

    Note: This function is set to the same code as caddr.

    See the third function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/delete-if-not.htm0000644000175000000620000001003011512762341023601 0ustar stevestaffXLISP delete-if-not Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    delete-if-not


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (delete-if-not test list)
    test - the test function to be performed
    list - the list to delete from
    returns - the list with non-matching elements deleted

    Description

    The 'delete-if-not' function destructively modifies the 'list' by removing the elements of the list that fail the 'test'. The destructive aspect of this operation means that the actual symbol value is used in the list-modifying operations, not a copy.

    'list' must evaluate to a valid list. An atom for 'list' will result in an error:

    error: bad argument type
    

    Having NIL for 'list' will return a NIL as the result.

    Examples

    Caution: there's a bug:

    (setq mylist '(1 2 3 4 5 6 7 8))             ; set up a list of numbers
    (delete-if-not 'evenp mylist)                ; returns (2 4 6 8)
    (print mylist)                               ; prints  (1 2 4 6 8) <-BUG!
    
    (setq mylist '(1 2 3 4 5 6 7 8))             ; set up the same list again
    (setq mylist (delete-if-not 'evenp mylist))  ; returns (3 5 7)
    (print mylist)                               ; prints  (3 5 7) <-OK
    
    (setq mylist '(1 2 3 4 5 6 7 8))             ; ... again ...
    (delete-if-not 'oddp mylist)                 ; returns (1 3 5 7)
    (print mylist)                               ; prints  (1 3 5 7) <-OK
    
    (setq mylist '(1 2 3 4 5 6 7 8))             ; ... and again ...
    (setq mylist (delete-if-not 'oddp mylist))   ; returns (1 3 5 7)
    (print mylist)                               ; prints  (1 3 5 7) <-OK
    

    Bug: 'delete-if-not' will return the proper value, but it does not always properly modify the symbol containing the value. This seems to be true if the first element of the 'list' fails the test [and should be deleted]. It's always better to use 'delete-if-not' together with setq or setf as shown in example 2 and 4.

    Common Lisp: XLISP does not support the ':from-end', ':start', ':end', ':count' and ':key' keywords which Common Lisp does.

    See the delete-if-not function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/multiplication.htm0000644000175000000620000000414011512762341024207 0ustar stevestaffXLISP * Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (* expr1 ...)
    exprN - integer or floating point number/expression
    returns - the result of the multiplication

    Description

    The '*' function multiplies one or more numbers together and returns the result.

    Examples

    (* 1)         => 1
    (* 1 2)       => 2
    (* 1 2 3)     => 6
    (* 1 2 3 4)   => 24
    
    > (print (+ 1 2 (* 3.5 (/ 3.9 1.45))))
    12.4138
    12.4138
    

    See  + ,  / , print. XLISP first prints the value on the screen, the second number is the return value.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/gc.htm0000644000175000000620000000401311512762341021542 0ustar stevestaffXLISP gc Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    gc


    Type:   -   function (subr)
    Source:   -   xldmem.c

    Syntax

    (gc)
    returns - always returns NIL

    Description

    The 'gc' function starts a garbage collection of the unused memory of XLISP. NIL is always returned.

    Examples

    (gc)  ; start a garbage collection right now
    

    Note: The system will cause an automatic garbage collection if it runs out of free memory.

    Note: When 'gc' is called or an automatic garbage collection occurs, if the amount of free memory is still low after the garbage collection, the system attempts to add more segments [an automatic expand].

    See the gc function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/backquote.htm0000644000175000000620000001370211512762341023134 0ustar stevestaffXLISP backquote Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    backquote


    backquote:

    Type:   -   special form (fsubr)
    Source:   -   xlcont.c, xlread.c

    comma, comma-at:

    Type:   -   reader expansion
    Source:   -   xlcont.c, xlread.c

    Syntax

    (backquote expr)
    expr - an expression which is not evaluated except for 'comma' and 'comma-at' portions
    returns - a copy of the template with 'comma' and 'comma-at' expressions expanded
    (comma expr)
    expr - an expression which is evaluated within a backquoted expression
    (comma-at expr)
    expr - an expression which is evaluated within a backquoted expression

    Description

    The 'backquote' special form returns 'expr' unevaluated, like quote. The difference is that portions of the expression may be evaluated when they are preceeded by a 'comma' or 'comma-at'.

    • comma will evaluate the portion of the expression the comma preceeds. If the portion is an atom or a list, it is placed as is within the expression.

    • comma-at will evaluate the portion of the expression that the 'comma-at' preceeds. The portion needs to be a list. The list is spliced into the expression. If the portion is not a list, 'comma-at' will splice in nothing.

    XLISP supports the following read macros:

       `expression   →   (backquote expression)
       ,expression   →   (comma expression)
       ,@expression   →   (comma-at expression)

    Examples

    (setq box 'stuff-inside)  => STUFF-INSIDE  ; BOX contains STUFF-INSIDE
    (print box)               => STUFF-INSIDE
    
    '(i have the box)   ≡ (quote (i have the box))                 => (I HAVE THE BOX)
    `(i have the box)   ≡ (backquote (i have the box))             => (I HAVE THE BOX)
    `(i have the ,box)  ≡ (backquote (i have the (comma box)))     => (I HAVE THE STUFF-INSIDE)
    `(i have the ,@box) ≡ (backquote (I have the (comma-at box)))  => (I HAVE THE)  ; STUFF-INSIDE is not a list
    
    (setq automobile '(a van))  => (A VAN)  ; AUTOMOBILE is a VAN
    (print automobile)          => (A VAN)
    
    '(I have automobile)   ≡ (quote (I have automobile))                 => (I HAVE AUTOMOBILE)
    `(I have automobile)   ≡ (backquote (I have automobile))             => (I HAVE AUTOMOBILE)
    `(I have ,automobile)  ≡ (backquote (I have (comma automobile)))     => (I HAVE (A VAN))
    `(I have ,@automobile) ≡ (backquote (I have (comma-at automobile)))  => (I HAVE A VAN)
    

    Common errors:

    `(,@(i am a list))   => error: bad function - I
    `(,@'(i am a list))  => (I AM A LIST)
    

    Note: 'backquote', 'comma', and 'comma-at' are very useful in defining macros via defmacro.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-lessp-s.htm0000644000175000000620000000522411512762341023457 0ustar stevestaffXLISP char< Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char<


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char< char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically increasing ASCII value, NIL otherwise
    Note: case is significant with this function

    Description

    The 'char<' function tests if all the character arguments are monotonically increasing.  T  is returned if the arguments are of monotonically increasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is less than 'char2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than the character '#\A'.

    Examples

    (char< #\a #\b)      => T
    (char< #\b #\a)      => NIL
    (char< #\a #\b #\c)  => T
    (char< #\a #\a)      => NIL
    (char< #\a #\b #\b)  => NIL
    (char< #\A #\a)      => T
    (char< #\a #\A)      => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/round.htm0000644000175000000620000000436711512762341022314 0ustar stevestaffXLISP round Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    round


    Type:   -   Lisp function (closure)
    Source:   -   fileio.lsp

    Syntax

    (round number)
    number - an integer or floating point numbers
    returns - the number, rounded to the next integer value

    In Nyquist, 'round' is implemented as a Lisp function:

    (defun round (x) 
      (cond ((> x 0) (truncate (+ x 0.5)))
            ((= (- x 0.5) (truncate (- x 0.5))) (truncate x))
            (t (truncate (- x 0.5)))))
    

    Description

    The 'round' function rounds a number to the next integer value. This is tricky because truncate rounds toward zero as does C in other words, rounding is down for positive numbers and up for negative numbers. You can convert rounding up to rounding down by subtracting one, but this fails on the integers, so we need a special test if (- x 0.5) is an integer.

    Examples

    (round .5)   => 1
    (round -.5)  => 0
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/class.htm0000644000175000000620000000755111512762341022270 0ustar stevestaffXLISP class Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    class


    Type:   -   object
    Source:   -   xlobj.c

    Syntax

     class

    Description

    'class' is the built-in object class that is used to build other classes. Classes are, essentially, the template for defining object instances.

    Examples

    (setq myclass (send class :new '(var)))  ; create MYCLASS with VAR
    
    (send myclass :answer :isnew '()         ; set up initialization
      '((setq var nil) self))
    
    (send myclass :answer :set-it '(value)   ; create :SET-IT message
      '((setq var value)))    
    
    (setq my-obj (send myclass :new))        ; create MY-OBJ of MYCLASS
    (send my-obj :set-it 5)                  ; VAR is set to 5
    

    Class definition: The internal definition of the 'class' object instance looks like:

    Object is #<Object: #23fe2>, Class is #<Object: #23fe2>
      MESSAGES = ((:ANSWER . #<Subr-: #23e48>) 
                  (:ISNEW . #<Subr-: #23e84>) 
                  (:NEW . #<Subr-: #23ea2>))
      IVARS = (MESSAGES IVARS CVARS CVALS SUPERCLASS IVARCNT IVARTOTAL)
      CVARS = NIL
      CVALS = NIL
      SUPERCLASS = #<Object: #23fd8>
      IVARCNT = 7
      IVARTOTAL = 7
    #<Object: #23fe2>
    

    The class of 'class' is 'class', itself. The superclass of 'class' is object. Remember that the location information [like #23fe2] varies from system to system, yours will probably look different.

    Built-in methods: The built in methods in XLISP include:

    Message Structure: The normal XLISP convention for a 'message' is to have a valid symbol preceeded by a colon like :isnew or ':my-message'. However, it is possible to define a 'message' that is a symbol without a colon, but this makes the code less readable.

    See the class object in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/reference-copyright.htm0000644000175000000620000000341411512762341025121 0ustar stevestaffCopyright Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    Copyright


    This XLISP language reference is a re-work of a 'XLISPREF.DOC' document with the following copyright:

    XLISP 2.0 Language Reference by Tim I Mikkelsen - December 11, 1989

    Copyright (c) 1989 by Tim I. Mikkelsen. All Rights Reserved. No part of this document may be copied, reproduced or translated for commercial use without prior written consent of the author. Permission is granted for non-commercial use as long as this notice is left intact.

    This document is intended to serve as a reference for the XLISP 2.0 dialect of LISP. It includes a description of each symbol, function, special form and keyword available in XLISP. This reference is not a complete and extensive introduction to LISP programming.

    If you find problems with the reference or find that I have left something out, drop me a line. If you find this useful, I would be interested in hearing that as well. If you are into 'pretty' looking documents (as opposed to plain ASCII text), I have a TeX version of the reference.

    Tim Mikkelsen, 4316 Picadilly Drive, Fort Collins, Colorado 80526


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-int.htm0000644000175000000620000000451211512762341022662 0ustar stevestaffXLISP char-int Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-int


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-int char)
    char - a character expression
    returns - the decimal ASCII value as an integer

    Description

    The 'char-int' function returns the decimal ASCII value of the 'char' expression.

    Examples

    (char-int #\0)              => 48
    (char-int #\A)              => 65
    (char-int #\a)              => 97
    (char-int #\[)              => 91
    (char-int #\newline)        => 10
    (char-int (code-char 127))  => 127
    (char-int (int-char 255))   => 255
    

    Note: In Nyquist/XLISP, char-code and 'char-int' are two different functions, but behave exactly the same [Nyquist 3.03, December 2010].

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/atom.htm0000644000175000000620000000617511512762341022124 0ustar stevestaffXLISP atom Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    atom


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (atom expr)
    expr - an arbitrary Lisp expression
    returns -  T  if the value is an atom, NIL otherwise

    Description

    The 'atom' predicate function tests if the 'expr' is an atom.  T  is returned if 'expr' is an atom, NIL is returned otherwise.

    Examples

    (atom 'a)                      => T   ; symbol
    (atom #'atom)                  => T   ; subr - function
    (atom "string")                => T   ; string
    (atom 4)                       => T   ; integer
    (atom 4.5)                     => T   ; float
    (atom object)                  => T   ; object
    (atom #(1 2 3))                => T   ; array
    (atom #'quote)                 => T   ; fsubr
    (atom *standard-output*)       => T   ; stream
    (atom '())                     => T   ; NIL is an atom
    (atom (lambda (x) (print x)))  => T   ; closure
    (atom '(a b c))                => NIL ; list
    (setq a '(a b))                => (A B)
    (atom a)                       => NIL ; value of A is not an atom
    

    Note: NIL or '() is used in many places as a list or atom expression. Both 'atom' and listp, when applied to NIL, return  T .

    See also:

      Back to Top


    XLISP > XLISP 2.0  -  Contents  -  Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-new.htm0000644000175000000620000000572311512762341023435 0ustar stevestaffXLISP :new Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :new


    Type:   -   message selector
    Source:   -   xlobj.c

    Syntax

    (send class :new args)
    class - an existing XLISP class except for class
    args - the initializing arguments for the new instance
    returns - the new class object
    (send class :new ivars [cvars [superclass]])
    ivars - list of instance variables for new class
    cvars - list of class variable symbols for new class
    superclass - superclass for new object, the default is object
    returns - the new class object

    Description

    The ':new' message selector exhibits two different behaviors. When you are creating an instance of a class you only need the ':new' message [consisting of the message selector and any data]. When you are creating a new class with ':new', you need to specify instance variables and optionally the class variables and superclass.

    Examples

    (setq new-class (send class :new '(state)))      ; create NEW-CLASS with STATE
    (setq new-obj (send new-class :new))             ; create NEW-OBJ of NEW-CLASS
    (send new-obj :show)                             ; shows the object
    
    (setq sub-class (send class :new '(sub-state)    ; create SUB-CLASS of NEW-CLASS
                                     '() new-class))
    (send sub-class :show)                           ; show the SUB-CLASS
    

    See the :new message selector in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/dribble.htm0000644000175000000620000000522111512762341022556 0ustar stevestaffXLISP dribble Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    dribble


    Type:   -   function (subr)
    Source:   -   xlisp.c, xlsys.c, msstuff.c

    Syntax

    (dribble [file-str])
    file-str - a string expression for a file name
    returns -  T  if the transcript is opened, NIL if it is closed

    Description

    The 'dribble' function, when called with a 'file-str' argument, opens the specified file and records a transcript of the XLISP session. When 'dribble' is called with no 'file-str' argument, it closes the current transcript file [if any]. 'dribble' will return  T  if the specified 'file-str' was successfully opened. It will return a NIL if the 'file-str' was not opened successfully or if 'dribble' was evaluated to close a transcript.

    Examples

    (dribble "my-trans-file")  ; open file "my-trans-file"
                               ;   for a session transcript
    (+ 2 2)                                 
    (dribble)                  ; close the transcript
    

    Note: It is also possible to start a transcript when invoking XLISP. To start XLISP with a transcript file of 'myfile' type in 'xlisp -tmyfile'. [I haven't tested this with Nyquist.]

    See the dribble function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/gensym.htm0000644000175000000620000000552411512762341022463 0ustar stevestaffXLISP gensym Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    gensym


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (gensym [tag])
    tag - an optional integer or string
    returns - the new symbol

    Description

    The 'gensym' function generates and returns a symbol. The default symbol form is as a character 'G' followed by a number, 'Gn'. The default numbering starts at '1'. You can change what the generated symbol looks like. By calling 'gensym' with a string 'tag', the default string is set to the string parameter. If 'tag' is an integer number, the current number is set to the integer parameter.

    Examples

    (gensym)             ; first time => G1
    (gensym 100)         ; returns G100
    (gensym "MYGENSYM")  ; returns MYGENSYM101
    (gensym 0)           ; returns MYGENSYM0
    (gensym)             ; returns MYGENSYM1
    (gensym "G")         ; \
    (gensym 0)           ; /  put it back to 'normal'
    (gensym)             ; just like first time => G1
    

    Note: It takes 2 calls to 'gensym' to set both portions of the 'gensym' symbol.

    Note: Although it is possible to call 'gensym' with numbers in the string like "AB1", this does generate an odd sequence. What will happen is you will get a sequence of symbols like:

    ... AB18 AB19 AB110 AB111 ...
    

    See the gensym function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/soundp.htm0000644000175000000620000000340111512762341022461 0ustar stevestaffXLISP soundp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    soundp


    Type:   -   function (subr)
    Source:   -   sndfnint.c, sound.c

    Syntax

    (soundp expr)
    expr - an arbitrary Lisp expression
    returns -  T  if expr is a sound, NIL otherwise

    Description

    The 'soundp' function returns  T  if 'expr' is a Nyquist sound, NIL otherwise.

    Examples

    
    

    Please see the Nyquist manual for Nyquist/XLISP audio functions.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-lambda-expression.htm0000644000175000000620000000477711512762341025364 0ustar stevestaffXLISP get-lambda-expression Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-lambda-expression


    Type:   -   function (subr)
    Source:   -   xlcont.c

    Syntax

    (get-lambda-expression closure)
    closure - a closure object from a previously defined function or macro
    returns - the original lambda expression

    Description

    The 'get-lambda-expression' function takes the 'closure' object and returns a reconstruction of a lambda or macro expression that defines the 'closure'. The parameter must be a 'closure' expression.

    Examples

    (defun mine (a b) (print (+ a b)))             ; define MINE defun
    (get-lambda-expression (function mine))        ; returns (LAMBDA (A B) (PRINT (+ A B)))
    
    (get-lambda-expression (lambda (a) (print a))  ; returns (LAMBDA (A) (PRINT A))
    
    (defmacro plus (n1 n2) `(+ ,n1 ,n2))           ; define PLUS macro
    (get-lambda-expression (function plus))        ; returns (MACRO (N1 N2) (BACKQUOTE (+ (COMMA N1) (COMMA N2))))
    

    See the get-lambda-expression function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keywordp.htm0000644000175000000620000000374711512762341023032 0ustar stevestaffXLISP keywordp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    keywordp


    Type:   -   Lisp function (closure)
    Source:   -   sal-parse.lsp

    Syntax

    (keywordp expr)
    expr - an arbitrary Lisp expression
    returns -  T  if the expression is a keyword symbol, NIL otherwise

    (defun keywordp (s)
      (and (symbolp s)
           (eq (type-of (symbol-name s)) 'string)
           (equal (char (symbol-name s) 0) #\:)))
    

    Description

    The 'keywordp' function tests if a lisp expression is a keyword symbol.

    Examples

    (keywordp :a)   => T
    (keywordp :B)   => T
    (keywordp 'c)   => NIL
    (keywordp "d")  => NIL
    (keywordp #\e)  => NIL
    (keywordp 123)  => NIL
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-trace-output.htm0000644000175000000620000000373011512762341025050 0ustar stevestaffXLISP *trace-output* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *trace-output*


    Type:   -   system variable
    Source:   -   xlinit.c, xlio.c

    Syntax

     *trace-output*

    Description

    The *trace-output* system variable contains a file pointer that points to the file where all trace output goes to. The default file for *trace-output* is the system standard error device, normally the screen.

    Examples

    *trace-output*   ; returns #<File-Stream...>
    

    Note: *trace-output*, *debug-io* and *error-output* are normally all set to the same file stream 'stderr'.

    See the *trace-output* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/characterp.htm0000644000175000000620000000533111512762341023271 0ustar stevestaffXLISP characterp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    characterp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (characterp expr)
    expr - the expression to check
    returns -  T  if the value is a character, NIL otherwise

    Description

    The 'characterp' predicate function tests if 'expr' evaluates to a character.  T  is returned if 'expr' evaluates to a character, NIL is returned otherwise.

    Examples

    (characterp #\a)       => T    ; character
    (setq a #\b)           => #\b
    (characterp a)         => T    ; evaluates to a character
    (characterp "a")       => NIL  ; string
    (characterp '(a b c))  => NIL  ; list
    (characterp 1)         => NIL  ; integer
    (characterp 1.2)       => NIL  ; float
    (characterp 'a)        => NIL  ; symbol
    (characterp #(0 1 2))  => NIL  ; array
    (characterp nil)       => NIL  ; NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/streamp.htm0000644000175000000620000000577711512762341022646 0ustar stevestaffXLISP streamp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    streamp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (streamp expr)
    expr - the expression to check
    returns -  T  if the value is a stream, NIL otherwise

    Description

    The 'streamp' predicate function checks if an 'expr' is a stream.  T  is returned if 'expr' is a stream, NIL is returned otherwise.

    EXAMPLES

    (streamp *standard-input*)             ; returns T - stream
    (streamp *debug-io*)                   ; returns T - stream
    (streamp (make-string-output-stream))  ; returns T - stream
    
    (setq a *standard-output*)
    (streamp a)                            ; returns T - evaluates to stream
    
    (streamp "a")                          ; returns NIL - string
    (streamp #\a)                          ; returns NIL - character
    (streamp '(a b c))                     ; returns NIL - list
    (streamp 1)                            ; returns NIL - integer
    (streamp 1.2)                          ; returns NIL - float
    (streamp '*debug-io*)                  ; returns NIL - symbol
    (streamp 'a)                           ; returns NIL - symbol
    (streamp #(0 1 2))                     ; returns NIL - array
    (streamp NIL)                          ; returns NIL - NIL
    

    See the streamp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-upcase.htm0000644000175000000620000000377311512762341023360 0ustar stevestaffXLISP char-upcase Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-upcase


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-upcase char)
    char - a character expression
    returns - the upper case character

    Description

    The 'char-upcase' function converts the 'char' expression to upper case. The upper case equivalent of 'char' is returned. If the 'char' is not alphabetic [a-z or A-Z], the character is returned unchanged.

    Examples

    (char-upcase #\0)  => #\0
    (char-upcase #\A)  => #\A
    (char-upcase #\a)  => #\A
    (char-upcase #\[)  => #\[
    (char-upcase #\+)  => #\+
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/function.htm0000644000175000000620000000574411512762341023012 0ustar stevestaffXLISP function Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    function


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (function expr)
    expr - an expression that evaluates to a function
    returns - the functional interpretation

    Description

    The 'function' special form returns the function definition of the 'expr'. Execution of the 'expr' form does not occur. 'function' will operate on functions, special forms, lambda-expressions and macros.

    Examples

    (function car)              ; returns #<Subr-CAR: #23ac4>
    (function quote)            ; returns #<FSubr-QUOTE: #23d1c>
    #'quote                     ; returns #<FSubr-QUOTE: #23d1c>
    (function 'cdr)             ; error: not a function
    
    (defun foo (x) (+ x x))     ; define FOO function
    (function foo)              ; returns #<Closure-FOO: #2cfb6>
    
    (defmacro bar (x) (+ x x))  ; define FOOMAC macro
    (function bar)              ; returns #<Closure-BAR: #2ceee>
    
    (setq my 99)                ; define a variable MY
    (function my)               ; error: unbound function
    
    (defun my (x) (print x))    ; define a function MY
    (function my)               ; returns #<Closure-MY: #2cdd6>
    

    Read macro: XLISP supports the normal Lisp read macro of a hash and quote [#'] as a short-hand method of writing the 'function' special form.

    See the function special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lambda-keyword-key.htm0000644000175000000620000001247011512762341024647 0ustar stevestaffXLISP &key Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    &key


    Type:   -   keyword
    Source:   -   xleval.c

    Syntax

    &key key-arg ...
    &key (key-arg [key-value [supplied-p-var]]) ...
    &key ((key-symbol key-arg) [key-value [supplied-p-var]]) ...
    key-arg - keyword argument
    key-symbol - keyword argument symbol
    key-value - keyword argument initialization
    supplied-p-var - argument existence variable

    Description

    In XLISP, there are several times that you define a formal argument list for a body of code [like defun , defmacro , :answer and lambda]. All of the formal arguments that are defined are required to appear in the invocation of the defined function or operation. If there are any &optional arguments defined, they will be filled in order.

    There are other optional arguments called 'keyword' arguments. These arguments are not position dependent but can be specified in any order by a preceding keyword [a symbol with a leading colon ':']. If there is no 'key-symbol' specified in the argument list, the keyword will be constructed from the 'key-arg' name by adding a leading colon ':'. For example a 'key-arg' of 'furter' will generate a keyword symbol of ':furter'.

    Like the &optional arguments, there can be initialization values provided via the 'key-value' argument. If there is no 'key-value' argument and no value is provided by the function call, the 'key-arg' value will be NIL.

    The 'supplied-p-var', if it is specified, will contain a  T  if the 'key-arg' value was supplied by the function call and a NIL if it was not supplied by the function call. This 'supplied-p-var' allows the programmer to test for an argument's existence. At the end of the function or operation execution, these local symbols and their values are are removed.

    Examples

    (defun foo (a &key b c)
      (print a) (print b) (print c))
    
    (foo)                           ; error: too few arguments
    (foo 1)                         ; prints 1 NIL NIL
    (foo 1 2)                       ; prints 1 NIL NIL
    (foo 1 :b 2 :c 3)               ; prints 1 2 3
    (foo 1 :c 3 :b 2)               ; prints 1 2 3
    (foo 1 :b 3 :b 2)               ; prints 1 3 NIL
    
    (defun fee (a &key (b 9 b-passed))
      (print a) (print b)
      (if b-passed (print "b was passed")
                   (print "b not passed")))
    
    (fee)                           ; error: too few arguments
    (fee 1)                         ; prints 1 9 "b not passed"
    (fee 1 2)                       ; prints 1 9 "b not passed"
    (fee 1 :b 2)                    ; prints 1 2 "b was passed"
    
    (defun fi (a &key ((:mykey b) 9 b-passed))
      (print a) (print b)
      (if b-passed (print "b was passed")
                   (print "b not passed")))
    
    (fi)                            ; error: too few arguments
    (fi 1)                          ; prints 1 9 "b not passed"
    (fi 1 2)                        ; prints 1 9 "b not passed"
    (fi 1 :b 2)                     ; prints 1 9 "b not passed"
    (fi 1 :mykey 2)                 ; prints 1 2 "b was passed"
    

    Note: There is a '&allow-other-keys' keyword in XLISP and Common Lisp. In the case of XLISP, this keyword is extraneous since the default for keyword arguments is to allow other keys (without errors).

    See the &key keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/open-binary.htm0000644000175000000620000000622611512762341023404 0ustar stevestaffXLISP open-binary Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    open-binary


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (open-binary file [:direction in-out])
    file - a string expression or symbol
    in-out - an optional keyword symbol that must be either ':input' or ':output'. The default is ':input'.
    returns - a stream

    Description

    The 'open-binary' function opens the 'file' for binary input or output. The 'file' may be a string expression or a symbol. Following the 'file', there is an optional keyword, ':direction'. The argument following this is either ':input' or ':output' which specifies the direction of the file. If no ':direction' is specified, the default is ':input'. When 'file' is a string, you may specify a complete file location or extensions like "/usr/local/bin/myfile.lsp" or "A:\LISP\TIM.BAT". If the file open was successful, then a file pointer of the following form is returned as the result:

    #<File: #99999>
    

    If the file open was not successful, a NIL is returned. For an input file, the file has to exist, or an error will be signaled.

    Examples

    
    

    This will create a file named FOO-FILE, because XLISP uppercases its symbols:

    (open-binary 'foo-file :direction :output)
    

    This will create a file named 'foo-file' because UNIX doesn't uppercase its file names:

    (open-binary "foo-file" :direction :output)
    

    So, if you are having trouble with opening and accessing files, check to make sure the file name is in the proper case.

    See also bigendianp, read-int, write-int, read-float, write-float.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/if.htm0000644000175000000620000000502711512762341021555 0ustar stevestaffXLISP if Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    if


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (if test-expr then-expr [else-expr])
    test-expr - an expression
    then-expr - the THEN clause, an expression
    else-expr - the ELSE clause, an optional expression
    returns - the value of the selected expression

    Description

    The 'if' special form evaluates the 'test-expr'. If 'test-expr' evaluates to a non-NIL value, then 'then-expr' is evaluated and returned as the result. If 'test-expr' evaluates to NIL and there is an 'else-expr', then the 'else-expr' is evaluated and its result is returned. If there is no 'else-expr' and 'test-expr' evaluates to NIL , then NIL is returned as a result.

    Examples

    (if T (print "will print")     ; prints  "will print"
          (print "won't print"))
    
    (if NIL (print "won't print")
            (print "will print"))  ; prints  "will print"
    
    (if 'a T NIL)                  ; returns T
    
    (if NIL 'nope 'yep)            ; returns YEP
    

    See the  if  special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/listdir.htm0000644000175000000620000000336111512762341022630 0ustar stevestaffXLISP listdir Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    listdir


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (listdir path)
    path - the path of the directory to be listed
    returns - list of filenames in the directory

    Description

    The 'listdir' function returns a list with all filenames in the directory or NIL if the directory could not be found.

    Examples

    (let ((filenames (sort (listdir ".") #'string-lessp)))
      (dolist (filename filenames)
        (print filename)))
    

    See also setdir.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-not-equal-i.htm0000644000175000000620000001110611512762341024611 0ustar stevestaffXLISP string-not-equal Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-not-equal


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-not-equal string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is not equal to string2, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'string-not-equal' function takes two string arguments. A non-NIL value is returned if 'string1' is not equal to 'string2', otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char-not-equal to the corresponding character of 'string2'. This test is not case sensitive, the character '#\a' is considered to be the same as '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string-not-equal "a" "b")               ; returns 0
    (string-not-equal "a" "a")               ; returns NIL
    (string-not-equal "a" "A")               ; returns NIL
    (string-not-equal "A" "a")               ; returns NIL
    (string-not-equal "abc" "abc ")          ; returns 3
    
    (string-not-equal "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars
                                                                ; returns NIL
    (string-not-equal "abc" "123456789" :end2 3 :end1 3)        ; leave just the first 3 chars
                                                                ; returns 0
    

    Bug: The 'string-not-equal' function is listed in the original XLISP documentation as 'string-not-equalp'. In the XLISP interpreter a call to 'string-not-equalp' causes an error:

    error: unbound function - STRING-NOT-EQUALP
    

    The 'string-not-equal' function works exactly as the 'string-not-equalp' function described in the XLISP manual. This bug had obviously been corrected in the manual only but never in the interpreter. As the bug still exists with Nyquist 2.36 in July 2007 as well as all other XLISP 2.x implementations I know, I have changed both manuals to 'string-not-equal' even if I myself whould consider 'string-not-equalp' as the better name.

    See the string-not-equal function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/continue.htm0000644000175000000620000000522611512762341023004 0ustar stevestaffXLISP continue Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    continue


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xldbug.c

    Syntax

    (continue)

    Description

    The 'continue' function attempts to continue from the break loop. This is valid only for cerrors [continuable errors]. If 'continue' is evaluated while not in a break loop , an error is generated:

    error: not in a break loop
    

    In Nyquist, the error is:

    error: this error can't be continued
    

    This error does not cause XLISP to go into a break loop. 'continue' never actually returns a value.

    Examples

    (continue)     ; error: not in a break loop
    (break "out")  ; break: out
    (continue)     ; to continue from break loop
                   ; BREAK returns NIL
    

    Keystroke equivalent: In the IBM PC and MS-DOS versions of XLISP, a 'Ctrl-p' key sequence has the same effect as doing a (continue). On a Macintosh, this can be accomplished by a pull-down menu or a 'Command-p'. [I haven't tested this with Nyquist.]

    See the continue function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cond.htm0000644000175000000620000000666411512762341022112 0ustar stevestaffXLISP cond Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cond


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (cond [(pred1 expr1) [(pred2 expr2) ... ]])
    predN - a predicate (NIL / non-NIL) expression
    exprN - an expression
    returns - the value of the first expression whose predicate is non-NIL

    Description

    The 'cond' special form evaluates a series of predicate / expression pairs. 'cond' will evaluate each predicate in sequential order until it finds one that returns a non-NIL value. The expression that is associated with the non-NIL value is evaluated. The resulting value of the evaluated expression is returned by 'cond'. If there are no predicates that return a non-NIL value, NIL is returned by 'cond'. Only one expression is evaluated, the first one with a non-NIL predicate. Note that the predicate can be a symbol or expression.

    Examples

    (cond                                       ; sample CONDitional
      ((not T) (print "this won't print"))
      ( NIL    (print "neither will this"))
      ( T      (print "this will print"))
      ( T      (print "won't get here")))       ; prints "this will print"
    
    (defun print-what (parm)
      (cond                                     ; start of COND
        ((numberp parm) (print "numeric"))      ; check for number
        ((consp parm)   (print "list"))         ; check for list
        ((null parm)    (print "nil"))          ; check for NIL
        (T              (print "something"))))  ; catch-all
    
    (print-what 'a)       ; prints "something"
    (print-what 12)       ; prints "numeric"
    (print-what NIL)      ; prints "nil"
    (print-what '(a b))   ; prints "list"
    

    See the cond special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-upcase.htm0000644000175000000620000000516511512762341023746 0ustar stevestaffXLISP string-upcase Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-upcase


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-upcase string [{:start | :end} offset] ... )
    string - a string expression
    offset - an optional integer expression for a keyword
    returns - a converted copy of the string

    Description

    The 'string-upcase' function takes a string argument and returns a new string that has been made upper case.

    The keyword arguments allow for accessing substrings within 'string'. The keyword arguments require a keyword ':start' or ':end' first and a single integer expression second. The ':start' keyword specifies the starting offset for the 'string-upcase' operation on 'string'. A value of 0 starts the string at the beginning [no offset]. The ':end' keyword specifies the end offset for the operation on 'string'.

    Examples

    (string-upcase "ABcd+-12&[")                ; returns "ABCD+-&["
    (string-upcase "abcdefgh" :start 2 :end 4)  ; returns "abCDefgh"
    
    (setq mystr "ABcdEFgh")       ; set up variable
    (string-upcase mystr)         ; returns "ABCDEFGH"
    (print mystr)                 ; prints  "ABcdEFgh"
    

    See the string-upcase function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/write-int.htm0000644000175000000620000000462011512762341023077 0ustar stevestaffXLISP write-int Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    write-int


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (write-int integer [stream [length]])
    integer - the integer to write
    stream - the output stream [default is standard output]
    length - the length of the integer in bytes [default is 4]
    returns - the integer

    Description

    The 'write-int' function writes an integer to a binary output stream, created by the open-binary function.

    Note: Integers and floats are assumed to be big-endian [high-order byte first] and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. '-4' indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    Examples

    
    

    See also read-int, read-float, write-float, bigendianp, open-binary.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/make-array.htm0000644000175000000620000000717511512762341023216 0ustar stevestaffXLISP make-array Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    make-array


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (make-array size)
    size - the size [integer] of the array to be created
    returns - the new array

    Description

    The 'make-array' function creates an array of the specified size and returns the array. Array elements may be any valid lisp data type, including lists or arrays. Arrays made by 'make-array' and accessed by aref are base 0. This means the first element is accessed by element number '0' and the last element is accessed by element number 'n-1', where 'n' is the array size. Array elements are initialized to NIL.

    Examples

    (setq my-array (make-array 16))     ; make the array
    (aref my-array 0)                   ; return 0th (first) element
    (aref my-array 15)                  ; return 15th (last) element
    (aref my-array 16)                  ; error: non existant element
    
    (dotimes (i 16)                     ; set each element to its index
      (setf (aref my-array i) i))       ;   by the setf function
    
    (setq new (make-array 4))           ; make another array
    (setf (aref new 0) (make-array 4))  ; make new[0] an array of 4
    (setf (aref (aref new 0) 1) 'a)     ; set new[0,1] = 'a
    (setf (aref new 2) '(a b c))        ; set new[2] = '(a b c)
    my-array                            ; look at array
    

    Read macro: There is a built-in read-macro for arrays, '#(...)' [the hash symbol with an opening and a closing parenthesis]. This allows you to create arbitrary arrays with initial values without going through a 'make-array' function. There is also the XLISP vector function to create initialized arrays.

    Common Lisp: Common Lisp supports multi-dimensional arrays, XLISP only supports one-dimensional arrays. In XLISP, multi-dimenstional arrays can be created by using 'arrays within arrays'. Common Lisp supports various keyword parameters that are not supported in XLISP.

    See the make-array function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/profile.htm0000644000175000000620000000474711512762341022627 0ustar stevestaff Profiling Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    profile


    Type:   -   function (subr)
    Source:   -   xlsys.c, xleval.c

    Syntax

    (profile flag) - turn profiling on or off
    flag - NIL turns profiling off, otherwise on
    returns - the previous state of profiling

    Description

    The Xlisp 2.0 release has been extended with a profiling facility, which counts how many times and where eval is executed. A separate count is maintained for each named function, closure, or macro, and a count indicates an eval in the immediately [lexically] enclosing named function, closure, or macro. Thus, the count gives an indication of the amount of time spent in a function, not counting nested function calls.

    The list of all functions executed is maintained on the global *profile* variable. These functions in turn have *profile* properties, which maintain the counts. The profile system merely increments counters and puts symbols on the *profile* list. It is up to the user to initialize data and gather results. Profiling is turned on or off with the 'profile' function.

    Unfortunately, methods cannot be profiled with this facility.

    Examples

    
    

      Back to top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/intersection.htm0000644000175000000620000000353211512762341023664 0ustar stevestaffXLISP intersection Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    intersection


    Type:   -   Lisp function (closure)
    Source:   -   xm.lsp

    Syntax

    (intersection list1 list2)
    listN - a list of symbols or numbers
    returns - the intersection of list1 and list2

    In Nyquist, 'intersection' is implemented as a Lisp function:

    (defun intersection (a b)
      (let (result)
        (dolist (elem a)
          (if (member elem b) (push elem result)))
        result))
    

    Description

    The 'intersection' function computes the intersection of two lists.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/progn.htm0000644000175000000620000000502511512762341022302 0ustar stevestaffXLISP progn Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    progn


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c, xllist.c

    Syntax

    (progn [expr1 expr2 ... ])
    exprN - expressions comprising the body of the loop
    returns - the value of the last expression

    Description

    The 'progn' special form is basically a 'block' construct that contains a block of code [expressions] to evaluate. The value of the last expression 'exprN' will be returned as the result of 'progn'. If there are no 'exprs', NIL is returned.

    Examples

    (progn (print "hi") (print "ho"))  ; prints "hi" "ho"  returns "ho"
    (progn)                            ; returns NIL
    (progn "hey" (print "ho"))         ; prints "ho"  returns "ho"
    (progn 'a)                         ; returns A
    (progn 'a 'b 'c)                   ; returns C
    

    Note: prog1 , prog2 , 'progn' and progv do not allow the use of return or go or tags for go.

    See the progn special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/floatp.htm0000644000175000000620000000524211512762341022443 0ustar stevestaffXLISP floatp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    floatp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (floatp expr)
    expr - the expression to check
    returns -  T  if the value is a floating point number, NIL otherwise

    Description

    The 'floatp' predicate function checks if an 'expr' is a floating point number.  T  is returned if 'expr' is a floating point number, NIL is returned otherwise.

    Examples

    (floatp 1.2)       ; returns T - float
    (floatp '1.2)      ; returns T - still a float
    (setq a 1.234)
    (floatp a)         ; returns T - evaluates to float
    (floatp 0.0)       ; returns T - float zero
    (floatp 0)         ; returns NIL - integer zero
    (floatp 1)         ; returns NIL - integer
    (floatp #x034)     ; returns NIL - integer readmacro
    (floatp 'a)        ; returns NIL - symbol
    (floatp #\a)       ; returns NIL - character
    (floatp NIL)       ; returns NIL - NIL
    (floatp #(0 1 2))  ; returns NIL - array
    

    See the floatp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-file-separator.htm0000644000175000000620000000340711512762341025332 0ustar stevestaffXLISP *file-separator* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *file-separator*


    Type:   -   system variable
    Source:   -   system.lsp

    Syntax

     *file-separator*

    Description

    The Nyquist *file-separator* variable is initialized to the operation system's file separator character. It has a value of #\\ on Windows and a value of #\/ on Unix [including Linux and Mac OS X].

    Examples

    *file-separator*  => #\/  ; on Unix, Linux, and Mac OS X
    *file-separator*  => #\\  ; on Windows
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/evenp.htm0000644000175000000620000000534211512762341022274 0ustar stevestaffXLISP evenp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    evenp


    Type:   -   predicate function (subr)
    Source:   -   xlmath.c

    Syntax

    (evenp expr)
    expr - the integer numeric expression to check
    returns -  T  if the integer is even, NIL otherwise

    Description

    The 'evenp' predicate function checks to see if the number 'expr' is even.  T  is returned if the number is even, NIL is returned otherwise.

    An error is generated if the 'expr' is not a numeric expression:

    error: bad argument type
    

    An error is generated if the 'expr' is a floating point number:

    error: bad floating point operation
    

    Zero is an even number.

    Examples

    (evenp 0)     ; returns T
    (evenp 1)     ; returns NIL
    (evenp 2)     ; returns T
    (evenp -1)    ; returns NIL
    (evenp -2)    ; returns T
    (evenp 14.0)  ; error: bad floating point operation
    (evenp 'a)    ; error: bad argument type
    (setq a 2)    ; set value of A to 2
    (evenp a)     ; returns T
    

    See the evenp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/number-not-greaterp.htm0000644000175000000620000000521711512762341025055 0ustar stevestaffXLISP <= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    <=


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (<= expr1 expr2 ...)
    exprN - a numeric expression
    returns -  T  if the results of comparing the expressions are all true, NIL otherwise

    Description

    The '<=' [less-than-or-equal] function takes an arbitrary number of numeric arguments. It checks to see if all the numbers are monotonically non-decreasing.  T  is returned if the arguments are numerically, and monotonically non-decreasing, NIL is returned otherwise. For two arguments, this has the effect of testing if 'expr1' is less than or equal to 'expr2'.

    Examples

    (<= 1 1)            => T
    (<= 1 2)            => T
    (<= 2.0 1.99)       => NIL
    (<= 1 2 3 3)        => T
    (<= 1 2 3 3 2)      => NIL
    (<= "aa" "aa")      => error: bad argument type
    (setq a 12 b 99.9)  => 99.9  ; set up A and B with values
    (<= a b)            => T
    (<= b a)            => NIL
    

    See setq.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/assoc.htm0000644000175000000620000000734111512762341022270 0ustar stevestaffXLISP assoc Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    assoc


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (assoc expr a-list [{:test | :test-not} test])
    expr - the expression to find as an atom or list
    a-list - the association list to search
    test - optional test function (default is eql)
    returns - the alist entry or NIL

    Description

    An association list is a collection of list pairs of the form:

    ((key1 item1) (key2 item2) ... (keyN itemN))
    

    The 'assoc' function searches through an association list 'a-list' looking for the key [a car in an association pair] that matches the search 'expr'. If a match is found, that association pair is returned as the result. If no match is found, NIL is returned. You may specify your own test with the ':test' and ':test-not' keywords followed by the 'test' you wish to perform.

    Examples

    (setq mylist '((a . my-a)
                   (b . his-b)
                   (c . her-c)
                   (d . end)))
    
    (assoc 'a mylist)  => (A . MY-A)
    (assoc 'b mylist)  => (B . HIS-B)
    (assoc  1 mylist)  => NIL
    
    (setq agelist '((1 (bill bob))
                    (2 (jane jill))
                    (3 (tim tom))
                    (5 (larry daryl daryl))))
    
    (assoc 1 agelist)                 => (1 (BILL BOB))
    (assoc 3 agelist :test #'>=)      => (1 (BILL BOB))
    (assoc 3 agelist :test #'<)       => (5 (LARRY DARYL DARYL))
    (assoc 3 agelist :test #'<=)      => (3 (TIM TOM))
    (assoc 3 agelist :test-not #'>=)  => (5 (LARRY DARYL DARYL))
    

    Using a list as key, tested with equal:

    > (assoc '(a b) '(((c d) e) ((a b) x)) :test #'equal)
    ((A B) X)
    

    Note: The 'assoc' function can work with a list or string as the 'expr'. However, the default eql test does not work with lists or strings, only symbols and numbers. To make this work, you need to use the ':test' keyword along with equal for 'test'.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/while.htm0000644000175000000620000000456111512762341022271 0ustar stevestaffXLISP while Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    while


    Type:   -   Lisp macro (closure)
    Source:   -   misc.lsp

    Syntax

    (while condition body)
    condition - test expression for terminating the 'while' loop
    body - Lisp expressions to be executed inside the loop
    returns - returns NIL or a value defined by (return expr) inside body

    In Nyquist, 'while' is implemented as a Lisp macro:

    (defmacro while (condition &rest body)
      `(prog () loop (if ,condition () (return)) ,@body (go loop)))
    

    Description

    The 'while' macro implements a conventional 'while' loop. If the 'condition' evaluates to true, the expressions in the in the 'body' are evaluated, then the 'condition' is tested again. If the 'condition' evaluates to false, the 'while' loop terminates. The 'while' macro returns NIL unless a (return expr) is evaluated in the 'body', in which case the value of 'expr' is returned.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/int-char.htm0000644000175000000620000000577511512762341022676 0ustar stevestaffXLISP int-char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    int-char


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (int-char int)
    int - an integer numeric expression
    returns - the character with that code

    Description

    The 'int-char' function returns a character which is the result of turning the 'int' expression into a character. If a 'int' cannot be made into a character, an error is signalled:

    error: character code out of range
    

    The range that 'int' produces a valid character is 0 through 255.

    Examples

    (int-char 48)    ; returns #\0
    (int-char 65)    ; returns #\A
    (int-char 97)    ; returns #\a
    (int-char 91)    ; returns #\[
    (int-char 10)    ; returns #\Newline
    (int-char 999)   ; error - character code out of range
    

    Common Lisp: Common Lisp specifies that 'int-char' should return a NIL when there is no valid character for the integer value being passed in while XLISP generates an error in these cases. In some cases it is possible to substitue the code-char function for 'int-char'.

    Note: Unlike the char-code and char-int functions, code-char and 'int-char' are not identical in use. code-char accepts 0..127 for its range and then produces NIL results while 'int-char' accepts 0..255 for its range and then produces errors.

    See the int-char function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/aref.htm0000644000175000000620000000735111512762341022076 0ustar stevestaffXLISP aref Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    aref


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (aref array element)
    array - an array expression
    element - an integer expression
    returns - the value of the array element

    Description

    The 'aref' function returns the specified element out of a previously created array. Array elements may be any valid lisp data type, including lists or arrays. Arrays made by make-array and accessed by 'aref' are base 0. This means the first element is accessed by element number '0' and the last element is accessed by element number 'n-1' [where 'n' is the array size]. Array elements are initialized to NIL.

    Examples

    (setq my-array '#(0 1 2 3 4))       => #(0 1 2 3 4)
    (aref my-array 0)                   => 0
    (aref my-array 4)                   => 4
    (aref my-array 5)                   => error: array index out of bounds - 5
    my-array                            => #(0 1 2 3 4)
                                        
    (setq new (make-array 4))           => #(NIL NIL NIL NIL)
    (setf (aref new 0) (make-array 4))  => #(NIL NIL NIL NIL)
    new                                 => #(#(NIL NIL NIL NIL) NIL NIL NIL) 
    (setf (aref (aref new 0) 1) 'a)     => A
    new                                 => #(#(NIL A NIL NIL) NIL NIL NIL)
    (setf (aref new 2) '(a b c))        => (A B C)
    new                                 => #(#(NIL A NIL NIL) NIL (A B C) NIL)
    

    Read macro: There is a built-in read-macro for arrays, '#(...)' [the hash symbol with the array elements in parentheses]. This allows you to create arbitrary arrays with initial values without going through a make-array function. See the Readtable section in the XLISP 2.0 Manual.

    Note: This function returns the value of an array element. However, there is no equivalent direct function to set the value of an array element to some value. To set an element value, you must use the setf function. The setf function is a generalized function that allows you to set the value of arbitrary lisp entities.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cddddr.htm0000644000175000000620000001213211512762341022376 0ustar stevestaffXLISP cdaaar ... cddddr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cdaaar ... cddddr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (cdaaar expr)
    (cdaadr expr)
    (cdadar expr)
    (cdaddr expr)
    (cddaar expr)
    (cddadr expr)
    (cdddar expr)
    (cddddr expr)
    expr - a list or list expression
    returns - the result of the last cdr function

    Description

    The 'cdaaar' ... 'cddddr' functions go through the list expression and perform a sequence of car or cdr operations. The sequence of operations is performed from right to left. So 'cddaar' does a car on the expression, followed by a car, followed by a cdr, followed by another cdr. If at any point the list is NIL, then NIL is returned. If at anypoint a car operation is performed on an atom [as opposed to a list] an error is signalled:

    error: bad argument
    

    Examples

    (setq mylist '((((111A 111B) (112A 112B) (113A 113B))   ; 1st set
                    ((121A 121B) (122A 122B) (123A 123B))
                    ((131A 131B) (132A 132B) (133A 133B))
                    ((141A 141B) (142A 142B) (143A 143B)))
                   (((211A 211B) (212A 212B) (213A 213B))   ; 2nd set
                    ((221A 221B) (222A 222B) (223A 223B))
                    ((231A 231B) (232A 232B) (233A 233B))
                    ((241A 241B) (242A 242B) (243A 243B)))
                   (((311A 311B) (312A 312B) (313A 313B))   ; 3rd set
                    ((321A 321B) (322A 322B) (323A 323B))
                    ((331A 331B) (332A 332B) (333A 333B))
                    ((341A 341B) (342A 342B) (343A 343B)))
                   (((411A 411B) (412A 412B) (413A 413B))   ; 4th set
                    ((421A 421B) (422A 422B) (423A 423B))
                    ((431A 431B) (432A 432B) (433A 433B))
                    ((441A 441B) (442A 442B) (443A 443B)))
                   (((511A 511B) (512A 512B) (513A 513B))   ; 5th set
                    ((521A 521B) (522A 522B) (523A 523B))
                    ((531A 531B) (532A 532B) (533A 533B))
                    ((541A 541B) (542A 542B) (543A 543B)))))
    
    (cdaaar mylist)  => (111B)
    (cdaadr mylist)  => ((212A 212B) (213A 213B))
    (cdadar mylist)  => ((122A 122B) (123A 123B))
    (cdaddr mylist)  => (((321A 321B) (322A 322B) (323A 323B))
                         ((331A 331B) (332A 332B) (333A 333B))
                         ((341A 341B) (342A 342B) (343A 343B)))
    (cddaar mylist)  => ((113A 113B))
    (cddadr mylist)      (((231A 231B) (232A 232B) (233A 233B))
                         ((241A 241B) (242A 242B) (243A 243B)))
    (cdddar mylist)  => (((141A 141B) (142A 142B) (143A 143B)))
    (cddddr mylist)  => ((((511A 511B) (512A 512B) (513A 513B))
                         ((521A 521B) (522A 522B) (523A 523B))
                         ((531A 531B) (532A 532B) (533A 533B))
                         ((541A 541B) (542A 542B) (543A 543B))))
    

    Note: The 'c...r' functions are part of the historical Lisp functions. You may find it easier to work with the modern lisp functions like nth and nthcdr.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lambda-keyword-aux.htm0000644000175000000620000000745311512762341024661 0ustar stevestaffXLISP &aux Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    &aux


    Type:   -   keyword
    Source:   -   xleval.c

    Syntax

    &aux [aux-var | (aux-var aux-value)] ...
    aux-var - auxiliary variable
    aux-value - auxiliary variable initialization

    Description

    In XLISP, there are several times that you define a formal argument list for a body of code [like defun, defmacro, :answer and lambda]. The 'aux-var' variables are a mechanism for you to define variables local to the function or operation definition. If there is an optional 'aux-value', they will be set to that value on entry to the body of code. Otherwise, they are initialized to NIL. At the end of the function or operation execution, these local symbols and their values are removed.

    Examples

    A function 'my-add' with one required argument 'num1', one &rest argument 'num-list', and one &aux variable 'sum':

    (defun my-add (num1 &rest num-list &aux sum)
      (setq sum num1)          ; initialize SUM
      (dolist (i num-list)     ; loop through the num-list
        (setq sum (+ sum i)))  ; add each number to SUM
      sum)                     ; return SUM when finished
    
    (my-add 1 2 3 4)    => 10
    (my-add 5 5 5 5 5)  => 25
    

    See  + , defun, dolist, &rest, setq.

    A function 'more-keys' with one required argument 'a' and three &aux variables 'b' [initialized to NIL], 'c' [initialized to 99], and 'd' [initialized to  T ]:

    (defun more-keys (a &aux b (c 99) (d t))
      (format t "a=~a b=~a c=~a d=~a~%" a b c d))
    
    > (more-keys "hi")
    a=hi b=NIL c=99 d=T
    NIL
    

    See defun, format.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/decf.htm0000644000175000000620000000433411512762341022060 0ustar stevestaffXLISP decf Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    decf


    Type:   -   Lisp macro (closure)
    Source:   -   misc.lsp

    Syntax

    (decf symbol)
    symbol - a symbol with numerical value bound to it
    returns - the new value of the symbol

    In Nyquist, 'decf' is implemented as a Lisp macro:

    (defmacro decf (symbol)
      `(setf ,symbol (1- ,symbol)))
    

    Description

    The 'decf' macro is used for decrementing a numerical value of a variable. 1 is substracted to the number and the result is stored in the variable. An error is signalled if the variable doesn't hold a number.

    Examples

    (setq n 3)    => 3
    (decf n)      => 2
    n             => 2
    (decf n)      => 1
    
    (setq n 1.8)  => 1.8
    (decf n)      => 0.8
    (decf n)      => -0.2
    (decf n)      => -1.2
    n             => -1.2
    
    (setq n #\a)  => #\a
    (decf a)      => error: bad argument type - #\a
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/do.htm0000644000175000000620000001305111512762341021555 0ustar stevestaffXLISP do Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    do


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (do ([binding ... ]) (test-expr [result]) [expr ... ])
    binding - a variable binding which is can take one of the following forms:
    symbol
    (symbol init-expr [step-expr])
    symbol - a symbol
    init-expr - an initialization expression for symbol
    step-expr - an expression with that symbol is updated at the end of each loop
    test-expr - iteration ends when this expression returns a non-NIL value
    result - an optional expression for the returned result
    expr - expressions comprising the body of the loop which may contain returns, gos or tags for go
    returns - the value of the last result expression

    Description

    The 'do' special form is basically a 'while' looping construct that contains symbols [with optional initializations and updates], a loop test [with an optional return value] and a block of code [expressions] to evaluate. The 'do' form evaluates its initializations and updates in no specified order [as opposed to do* which does it in sequential order]. The sequence of these events is:

      init-expr execution
      while not test-expr do
        loop code execution
        step-expr execution
      end-while
      return result
    

    The first form after the 'do' is the 'binding' form. It contains a series of 'symbols' or 'bindings'. The 'binding' is a 'symbol' followed by an initialization expression 'init-expr' and an optional 'step-expr'. If there is no 'init-expr', the 'symbol' will be initialized to NIL. There is no specification as to the order of execution of the bindings or the step expressions, except that they happen all together.

    The 'do' form will go through and create and initialize the symbols. This is followed by evaluating the 'test-expr'. If 'test-expr' returns a non-NIL value, the loop will terminate. If 'test-expr' returns a NIL value then the 'do' will sequentially execute the 'exprs'. After execution of the loop 'exprs', the 'symbols' are set to the 'step-exprs' [if the 'step-exprs' exist]. Then, the 'test-expr' is re-evaluated, and so on. The value of the 'result' expression is evaluated and returned. If no 'result' is specified, NIL is returned. When the 'do' is finished execution, the 'symbol's that were defined will no longer exist or retain their values.

    Examples

    (do (i)                              ; DO loop with var I
      ((eql i 0) "done")                 ;   test and result
      (print i) (setq i 0) (print i))    ;   prints NIL 0
                                         ;   returns "done"
    
    (do (i)                              ; DO loop with var I
      ((eql i 0))                        ;   test but no result
      (print i) (setq i 0) (print i))    ;   prints NIL 0
                                         ;   returns NIL
    
    (do                                  ; DO loop
       ((i 0 (setq i (1+ i)))            ;   var I=0  increment by 1
        (j 10 (setq j (1- j))))          ;   var J=10 decrement by 1
       ((eql i j)  "met in the middle")  ;   test and result
       (princ i) (princ " ")             ;   prints  0 10
       (princ j) (terpri))               ;           1 9
                                         ;           2 8
                                         ;           3 7
                                         ;           4 6
                                         ;   returns "met in the middle"
    

    See the do special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/sqrt.htm0000644000175000000620000000425511512762341022152 0ustar stevestaffXLISP sqrt Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    sqrt


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (sqrt expr)
    expr - floating point number or expression
    returns - the square root of the number

    Description

    The 'sqrt' function calculates the square root of 'expr' and returns this result.

    Examples

    (sqrt 1.0)    ; returns 1
    (sqrt 2.0)    ; returns 1.41421
    (sqrt 3.0)    ; returns 1.73205
    (sqrt 4.0)    ; returns 2
    (sqrt 5.0)    ; returns 2.23607
    (sqrt -1.0)   ; error: square root of a negative number
    (sqrt 2)      ; error: bad integer operation
    

    Common Lisp: Common Lisp allows for integer numbers, which XLISP does not support for 'sqrt'.

    See the sqrt function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/read.htm0000644000175000000620000001216111512762341022067 0ustar stevestaffXLISP read Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    read


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlread.c

    Syntax

    (read [source [eof-result [recursive-flag]]])
    source - an optional source, must be a file pointer or stream, the default is *standard-input*
    eof-result - an optional expression, default is NIL
    recursive-flag - an optional expression, NIL or non-NIL
    returns - the expression read

    Description

    The 'read' function reads an expression from the specified 'source'. The expression read is a normal XLISP expression, not necessarily a line. This means that white space is removed, where 'white space' is blanks, empty lines and comment lines. Read-macro expansions will occur. The expression needs to be an atom [numeric, string or symbol] or a valid list. It can span several lines. The expression read is returned as the result. The 'source' may be a file pointer or a stream. If there is no 'source', *standard-input* is the default. If an end-of-file is encountered in the 'source', then the 'eof-result' value will be returned as the result.

    If you wish to read just lines or characters, refer to the read-line or read-char functions.

    The 'recursive-flag' is intended for use with embedded calls to 'read'. This is useful in read-macro and read-table uses. If 'recursive-flag' is non-NIL , 'read' does not expect itself to be at a 'top-level', but recursively executing within another 'read' that is in progress.

    Examples

    (setq fp (open "f" :direction :output))  ; set up file
    (print "hello" fp)                       ; and fill it with stuff
    (print 12.34 fp)
    (princ "'(a b" fp) (terpri fp)
    (princ "; comment" fp) (terpri fp)
    (princ " c d)" fp )
    (close fp)
    
    (setq fp (open "f" :direction :input))   ; now read the file
    (read fp "done")                         ; returns "hello"
    (read fp "done")                         ; returns 12.34
    (read fp "done")                         ; returns (QUOTE (A B C D))
                                             ;   note the macro expansion of QUOTE
                                             ;   note that "; comment" is gone
    (read fp "done")                         ; returns "done"
    (close fp)
    

    Common Lisp: The XLISP and Common Lisp 'read' functions are similar. They both allow for 'source', 'eof-result' and 'recursive-flag'. However, in Common LISP, there is an additional end-of-file error parameter. This parameter occurs right after 'source' and specifies whether or not to flag an error on end-of-file. So, when porting, remember there is one additional argument in Common Lisp's 'read' function. You need to be concerned about this if you use more than just a 'source' argument, going either from XLISP to Common LISP or vice versa.

    Common Lisp: Common Lisp specifies that 'read' operations with a 'source' of NIL will come from *standard-input*. XLISP does not read the input from *standard-input* with a 'source' of NIL. Common Lisp also specifies that a 'source' of  T  will read from *terminal-io* which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'source'.

    See the read function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cdddr.htm0000644000175000000620000000633611512762341022243 0ustar stevestaffXLISP cdaar ... cdddr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cdaar ... cdddr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (cdaar expr)
    (cdadr expr)
    (cddar expr)
    (cdddr expr)
    expr - a list or list expression
    returns - the result of the last cdr function

    Description

    The 'cdaar', 'cdadr', 'cddar' and 'cdddr' functions go through the list expression and perform a sequence of car or cdr operations. The sequence of operations is performed from right to left. So 'cddar' does a car on the expression, followed by a acdr, followed by another cdr. If at any point the list is NIL, then NIL is returned. If at any point a car operation is performed on an atom [as opposed to a list] an error is signalled:

    error: bad argument
    

    Examples

    (setq mylist '(((11A 11B) (12A 12B) (13A 13B))
                   ((21A 21B) (22A 22B) (23A 23B))
                   ((31A 31B) (32A 32B) (33A 33B))
                   ((41A 41B) (42A 42B) (43A 43B))))
    
    (cdaar mylist)  => (11B)
    (cdadr mylist)  => ((22A 22B) (23A 23B))
    (cddar mylist)  => ((13A 13B))
    (cdddr mylist)  => (((41A 41B) (42A 42B) (43A 43B)))
    

    Note: The 'c...r' functions are part of the historical Lisp functions. You may find it easier to work with the modern lisp functions like nth and nthcdr.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/prin1.htm0000644000175000000620000000707211512762341022212 0ustar stevestaffXLISP prin1 Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    prin1


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlprin.c

    Syntax

    (prin1 expr [dest])
    expr - an expression
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - the expression

    Description

    The 'prin1' function prints the 'expr' to the specified 'destination'. The 'expr' is printed without a 'newline' character. If 'expr' is a string, it will be printed with quotes around the string. The 'expr' is returned as the result. The 'destination' may be a file pointer or a stream. If there is no 'destination', *standard-output* is the default. The terpri function is used to terminate the print lines produced.

    Examples

    (prin1 'a)                              ; prints A     without #\Newline
    (prin1 '(a b))                          ; prints (A B) without #\Newline
    (prin1 2.5)                             ; prints 2.5   without #\Newline
    (prin1 "hi")                            ; prints "hi"  without #\Newline
    
    (setq f (open "f" :direction :output))  ; create file
    (prin1 "hi" f)                          ; returns "hi"
    (prin1 1234 f)                          ; returns 1234
    (prin1 "he" f)                          ; returns "he"
    (close f)                               ; file contains "hi"1234"he"
    

    Common Lisp: Common Lisp specifies that 'pprint' with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the prin1 function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/second.htm0000644000175000000620000000465611512762341022441 0ustar stevestaffXLISP second Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    second


    Type:   -   function (subr)
    Source:   -   xlinit.c

    Syntax

    (second expr)
    expr - a list or list expression
    returns - the second element of expr

    Description

    The 'second' function returns the second element of a list or list expression. If the list is NIL , NIL is returned.

    Examples

    (second '(1 2 3))              ; returns 2
    (second NIL)                   ; returns NIL
    
    (setq carol '(a b c))          ; set up variable CAROL
    (first carol)                  ; returns A
    (second carol)                 ; returns B
    (rest carol)                   ; returns (B C)
    
    (setq children '(amanda ben))  ; set up variable CHILDREN
    (second children)              ; returns BEN
    

    Note: This function is set to the same code as the cadr function.

    See the second function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/pi.htm0000644000175000000620000000303211512762341021561 0ustar stevestaffXLISP rrandom Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    rrandom


    Type:   -   Lisp variable
    Source:   -   dspprims.lsp

    Syntax

    pi
    returns - a floating point value of 3.14159265358979

    Description

    The 'pi' variable returns a floating point approximation of the number 'pi'.

    Examples

    pi  => 3.14159265358979
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/format.htm0000644000175000000620000001436111512762341022450 0ustar stevestaffXLISP format Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    format


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (format destination format [expr1 ... ])
    destination - a required destination [see below]
    format - a format string
    exprN - an expression
    returns - output string if stream is NIL , NIL otherwise

    The 'destination' must be a file pointer, a stream, NIL [to create a string] or  T  [to print to *standard-output*].

    Description

    The 'format' function prints the specified expressions [if any] to the specified 'destination' using the 'format' string to control the print format. If the 'destination' is NIL , a string is created and returned with the contents of the 'format'. If the 'destination' is  T  , the printing occurs to *standard-output*. The 'format' function returns NIL , if the 'destination' was non-NIL. The 'format' string is a string [surrounded by double-quote characters]. This string contains ASCII text to be printed along with formatting directives [identified by a preceeding tilde '~' character]. The character following the tilde character is not case sensitive ['~a' and '~A' will function equivalently].

    Examples

    (format T "Now is the time for")         ; prints  Now is the time for
    (format T "all ~A ~S to" 'good 'men)     ; prints  all GOOD MEN to
    (format T "come to the")                 ; prints  come to the
    (format T "~A of their ~S"               ; prints  aid of their "party"
              "aid" "party")
    (format *standard-ouput* "Hello there")  ; prints  Hello there
    (format nil "ho ho ~S" 'ho)              ; returns "ho ho HO"
    (format T "this is ~%a break")           ; prints  this is
                                             ;         a break
    (format T "this is a long ~
               string")                      ; prints  this is a long string
    

    Supported format directives: The 'format' string in XLISP supports the following format directives:

    ~A   -   ASCII, prints the 'expr'. If it is a string print it without quotes. This is like the princ function.
     
    ~S   -   s-expr, prints the 'expr'. If it is a string print it with quotes. This is like the prin1 function.
     
    ~%   -   prints a 'newline' control character.
     
    ~~   -   prints a single tilde '~' character.
     
    ~<newline>   -   continue the 'format' string on the next line. This signals a line break in the format. The 'format' function will ignore all white-space [blanks, tabs, newlines]. This is useful when the 'format' string is longer than a program line. Note that the 'newline' character must immediately follow the tilde character.

    Common Lisp: The 'format' function in Common Lisp is quite impressive. It includes 26 different formatting directives. XLISP, as shown above, does not include most of these. The more difficult ones that you might encounter are the decimal, octal, hexidecimal, fixed-format floating-point and exponential floating-point. It is possible to print in octal and hexadecimal notation by setting *integer-format*. It is possible to print in fixed format and exponential by setting *float-format*. However, neither of these system variables are supported in Common Lisp and neither gives control over field size.

    See the format function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lower-case-p.htm0000644000175000000620000000445511512762341023461 0ustar stevestaffXLISP lower-case-p Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    lower-case-p


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (lower-case-p char)
    char - a character expression
    returns -  T  if the character is lower case, NIL otherwise

    Description

    The 'lower-case-p' predicate function checks if the 'char' expression is a lower case character. If 'char' is lower case a  T  is returned, otherwise a NIL is returned. Lower case characters are 'a' [ASCII decimal value 97] through 'z' [ASCII decimal value 122].

    Examples

    (lower-case-p #\a)   ; returns T
    (lower-case-p #\A)   ; returns NIL
    (lower-case-p #\1)   ; returns NIL
    (lower-case-p #\[)   ; returns NIL
    

    See the lower-case-p predicate function form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/symbol-plist.htm0000644000175000000620000000540211512762341023612 0ustar stevestaffXLISP symbol-plist Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    symbol-plist


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (symbol-plist symbol)
    symbol - the symbol name with a property list
    returns - the symbol's property list

    Description

    The 'symbol-plist' function returns the actual property list from the 'symbol'. The 'symbol' must be an existing, bound variable, but it does not need to have anything in it's property list.

    Property lists are lists attached to any user defined variables. The lists are in the form of:

    (name1 val1 name2 val2 ....)
    

    Any number of properties may be attached to a single variable.

    Examples

    (setq person 'bobby)                  ; create a var with a value
    (putprop person 'boogie 'last-name)   ; add a LAST-NAME property
    (putprop person 'disc-jockey 'job)    ; add a JOB property
    (putprop person '(10 20 30) 'stats)   ; add a STATS list
    
    (symbol-plist person)                 ; returns the property list:
                                          ;   (STATS (10 20 30)
                                          ;    JOB DISC-JOCKEY
                                          ;    LAST-NAME BOOGIE)
    

    See the symbol-plist function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-error-output.htm0000644000175000000620000000375411512762341025111 0ustar stevestaffXLISP *error-output* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *error-output*


    Type:   -   system variable
    Source:   -   xlinit.c, xlio.c

    Syntax

     *error-output*

    Description

    *error-output* is a system variable that contains a file pointer that points to the file where all error output goes to. The default file for *error-output* is the system standard error device, normally the screen.

    Examples

    *error-output*   ; returns #<File-Stream...>
    

    Note: *trace-output* , *debug-io* and *error-output* are normally all set to the same file stream 'stderr'.

    See the *error-output* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/asin.htm0000644000175000000620000000533311512762341022111 0ustar stevestaffXLISP asin Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    asin


    Type:   -   Lisp function (closure)
    Source:   -  

    Syntax

    (asin expr)
    expr - floating point number/expression
    returns - the arcsine of the number

    Note: The 'asin' function is not imlemented in Nyquist. Here is a Lisp implementation of 'asin', using the atan function:

    (defun asin (x)
      (cond ((not (numberp x)) (error "bad argument type" x))
            ((= x 1) (/ pi 2.0))
            ((= x -1) (/ pi -2.0))
            ((< -1 x 1) (atan (/ x (sqrt (1+ (* x (- x)))))))
            (t (error "argument out of range" x))))
    

    Description

    The 'asin' function returns the arc sine of a floating point expression. The result is a floating point number in radians. If the argument is less than -1 or greater than +1, the arc sine is a complex number. Complex numbers are not available in XLISP. In this case the 'asin' function signals an 'argument out of range' error.

    Examples

    (asin 0.0)   => 0.0
    (asin 1.0)   => 1.5708
    (asin -1.0)  => -1.5708
    (asin 0)     => error: bad integer operation
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-not-equal-s.htm0000644000175000000620000000775311512762341024640 0ustar stevestaffXLISP string/= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string/=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string/= string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is not equal to string2, NIL otherwise
    Note: case is significant with this function

    Description

    The 'string/=' [string-not-equal] function takes two string arguments. A non-NIL value is returned if 'string1' is not equal to 'string2', otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char/= [char-not-equal] to the corresponding character of 'string2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string/= "a" "b")           ; returns 0
    (string/= "a" "a")           ; returns NIL
    (string/= "a" "A")           ; returns 0
    (string/= "A" "a")           ; returns 0
    (string/= "abc" "abc ")      ; returns 3
    
    (string/= "J Smith" "K Smith" :start1 1 :start2 1)  ; returns NIL
    (string/= "abc" "123456789" :end2 3 :end1 3)        ; returns 0
    

    Note: Be sure that the 'string/=' function is properly typed in. The '/' is a forward slash. It is possible to mistakenly type a '\' backslash. This is especially easy because the character mechanism is '#\a'. If you do use the backslash, no error will be reported because backslash is the single escape character and the XLISP reader will evaluate 'string\=' as 'string='. No error will be reported, but the sense of the test is reversed.

    See the string/= function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/unwind-protect.htm0000644000175000000620000001227211512762341024141 0ustar stevestaffXLISP unwind-protect Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    unwind-protect


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (unwind-protect protect-form clean-up-form ... )
    protect-form - a form that is to be protected
    clean-up-form - a sequence forms to execute after protect-form
    returns - the value of protect-form

    Description

    The 'unwind-protect' special form allows the protecting [trapping] of all forms of exit from the 'protect-form'. The exits that are trapped include errors, throw , return and go. The 'clean-up-form' will be executed in all cases, when there is an exit from 'protect-form' and when the form does not have exit. 'unwind-protect' will return the result from the 'protect-form', not from the 'clean-up-forms'. Errors or exits that occur in the 'clean-up-form' are not protected. It is possible to trap these with another 'unwind-protect'.

    Note: 'unwind-protext' will not protect against errors signalled by built-in functions if *breakenable* is not NIL.

    Examples

    (unwind-protect
      (+ 2 2)                           ; protected form
      (print "an exit"))                ; clean up form
                                        ; prints "an exit"
                                        ; returns 4
    
    (setq *breakenable* nil)            ; to turn off break loop traps
    
    (unwind-protect
      (+ 1 "2")                         ; protected form
      (print "something happened"))     ; clean up form
                                        ; error: bad argument type - "2"
                                        ; prints "something happened"
    
    (catch 'mytag
      (unwind-protect
        (throw 'mytag)                  ; protected form
        (print "an exit")))             ; clean up form
                                        ; prints "an exit"
    
    (setq *breakenable* nil)            ; to turn off break loop traps
    
    (unwind-protect
      (throw 'notag)                    ; protected form
      (print "an exit"))                ; clean up form
                                        ; error: no target for THROW
                                        ; prints "an exit"
    
    (prog () (print "start")
             (unwind-protect
               (go end)                 ; protected form
               (print "an exit"))       ; clean-up form
        end  (print "end"))             ; prints "start"
                                        ; prints "an exit"
                                        ; prints "end"
    
    (prog () (print "start")
             (unwind-protect
               (return "I'm done")      ; protected form
               (print "but first"))     ; clean-up form
             (print "won't get here"))  ; prints "start"
                                        ; prints "but first"
                                        ; returns "I'm done"
    

    See the unwind-protect special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/nil.htm0000644000175000000620000000410311512762341021733 0ustar stevestaffXLISP nil Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    nil


    Type:   -   system constant
    Source:   -   xlsym.c

    Syntax

     nil

    Description

    The 'nil' constant represents the empty list or the false value, as oppossed to the true value [the symbol  T ]. 'nil' can be written as the three character symbol 'nil' or as the empty list ().

    Examples

    (setq myvar nil)                     ; set MYVAR to False
    (setq myvar 'nil)                    ; NIL and 'NIL evaluate to NIL
    (setq myvar ())                      ; () is the empty list = NIL
    (setq myvar '())                     ; () and '() evaluate to NIL
    (if nil (print "this won't print")   ; if/then/else
            (print "this will print"))
    

    Note: You can not change the value of NIL.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/save.htm0000644000175000000620000001043311512762341022112 0ustar stevestaffXLISP save Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    save


    Type:   -   function (subr)
    Source:   -   xldmem.c, xlimage.c

    Syntax

    (save file)
    file - a string or symbol for the name of the file
    returns -  T  if workspace was written, NIL otherwise

    Description

    The 'save' function saves the current XLISP workspace [system state] to the specified file. The 'file' may be a string or a symbol. If the 'file' does not include a '.wks' suffix, it will be extended to be called 'file.wks'. The function returns  T  if the workspace was properly created and saved, NIL is returned otherwise. There can be several saved workspaces. These workspaces can be restored as often as desired.

    Examples

    (setq myvar 5)       ; set MYVAR to value 5
    myvar                ; returns 5
    
    (save 'farp)         ; save workspace in FARP.wks
    
    (setq myvar "garp")  ; change MYVAR to "garp"
    myvar                ; returns "garp"
    
    (restore 'farp)      ; restore workspace
    myvar                ; returns 5
    

    Bug: The 'save' function generates a system error if the 'file' being created already exists. This 'file' will be modified and will not be restorable after restarting XLISP. [I still haven't tested this with Nyquist.]

    Note: The saved workspace size is implementation dependent, but can be fairly large.

    File names: In the PC and DOS world, all file names and extensions ["foo.bat"] are automatically made uppercase. In using XLISP, this means you don't have to worry about whether the name is "foo.bat", "FOO.BAT" or even "FoO.bAt", they will all work. However, in other file systems [UNIX in particular], uppercase and lowercase do make a difference:

    This will create a file named FOO-FILE in UNIX, because XLISP uppercases its symbols:

    (open 'foo-file :direction :output)
    

    This will create a file named 'foo-file' because UNIX doesn't uppercase its file names:

    (open "foo-file" :direction :output)
    

    So, if you are having trouble with opening and accessing files, check to make sure the file name is in the proper case.

    Common Lisp: The XLISP 'save' function is similar in use to the 'save-world' function in Common Lisp. The primarily difference is that 'save-world' allows you to restart everything since it creates an executable file. The 'save' function requires you to start XLISP up first and then do a restore. Depending on the operating system that you are using, it is possible to write a 'save-world' equivalent using 'save', restore and system.htm functions.

    See the save function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/sort.htm0000644000175000000620000000617611512762341022154 0ustar stevestaffXLISP sort Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    sort


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (sort list test)
    list - a list containing elements to be sorted
    test - the test to use for the sort
    returns - the sorted list

    Description

    The 'sort' function sorts the 'list' using the 'test' to order the list. The 'sort' function is destructive and modifies the 'list'.

    Examples

    (setq a '(3 1 4 1 5 9 6 7))          ; returns (3 1 4 1 5 9 6 7)
    
    (sort a '<)                          ; returns (1 1 3 4 5 6 7 9)
    
    (print a)                            ; returns (1 1 3 4 5 6 7 9)
                                         ; notice that A is modified
    
    (sort a '>)                          ; returns (9 7 6 5 4 3 1 1)
    
    (sort '("a" "bar" "foo") 'string>)   ; returns ("foo" "bar" "a")
    

    XLISP Bug

    Nyquist 'sort' returns the proper value, but improperly modifies the symbol or the actual 'list', for example:

    (setq a '(3 1 4 1 5 9 6 7))  => (3 1 4 1 5 9 6 7)
    (sort a '<)                  => (1 1 3 4 5 6 7 9)  ; OK
    a                            => (3 4 5 6 7 9)      ; BUG
    

    But this way it works:

    (setq a '(3 1 4 1 5 9 6 7))  => (3 1 4 1 5 9 6 7)
    (setq a (sort a '<))         => (1 1 3 4 5 6 7 9)
    a                            => (1 1 3 4 5 6 7 9)
    

    Common Lisp: Common Lisp allows for a ':key' keyword, which allows a specified function to be run before the ordering takes place, which XLISP does not support.

    See the sort function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/subsetp.htm0000644000175000000620000000370511512762341022645 0ustar stevestaffXLISP subsetp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    subsetp


    Type:   -   Lisp function (closure)
    Source:   -   xm.lsp

    Syntax

    (subsetp list1 list2)
    listN - a list of symbols or numbers
    returns -  T  if list1 is a subset of list2, NIL otherwise

    In Nyquist, 'subsetp' is implemented as a Lisp function:

    (defun subsetp (a b)
      (let ((result t))
        (dolist (elem a)
          (cond ((not (member elem b))
                 (setf result nil)
                 (return nil))))
        result))
    

    Description

    The 'subsetp' function tests if all elements of 'list1' are contained in 'list2'.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-tracelimit.htm0000644000175000000620000000773611512762341024563 0ustar stevestaffXLISP *tracelimit* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *tracelimit*


    Type:   -   system variable
    Source:   -   xlinit.c, xldbug.c

    Syntax

     *tracelimit*

    Description

    The *tracelimit* system variable controls the number of forms printed on entry to the break loop. If *tracelimit* is an integer, then the integer is the maximum number of forms that will be printed. If *tracelimit* is NIL or a non-integer, then all of the forms will be printed. Note that *tracenable* needs to be set to a non-NIL value to enable the printing of back-trace information on entry to the break loop.

    Examples

    (defun foo (x) (fee x))   ; define FOO
    (defun fee (y) (break))   ; define FEE
    (setq *tracenable* T)     ; enable the back trace
    (setq *tracelimit* NIL)   ; show all the entries
    
    (foo 5)                   ; break: **BREAK**
                              ; prints Function:#<Subr-BREAK...>
                              ;        Function:#<Closure-FEE...>
                              ;        Arguments:
                              ;          5
                              ;        Function:#<Closure-FOO...>
                              ;        Arguments:
                              ;          5
    
    (clean-up)                ; from break loop
    (setq *tracelimit* 2)     ; show only 2 entries
    
    (foo 5)                   ; break: **BREAK**
                              ; prints Function:#<Subr-BREAK...>
                              ;        Function:#<Closure-FEE...>
                              ;        Arguments:
                              ;          5
    
    (clean-up)                ; from break loop
    

    Note: *tracenable* and *tracelimit* system variables have to do with back trace information at entry to a break loop and are not related to the trace and untrace functions.

    See the *tracelimit* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/send-super.htm0000644000175000000620000000563211512762341023246 0ustar stevestaffXLISP send-super Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    send-super


    Type:   -   function (subr)
    Source:   -   xlobj.c

    Syntax

    (send-super message [args])
    message - the message selector
    args - the optional message arguments
    returns - the result of sending the message

    Description

    The 'send-super' function sends the specified arguments 'args' to the 'message' specified method of the superclass. It is necessary for 'send-super' to be executed from within a method being performed on an object. It will return the result of sending the message. If 'send-super' is performed outside of a method an error will result.

    error: not in a method
    

    Examples

    (setq a-class (send class :new '()))                       ; create A-CLASS
    
    (send a-class :answer :show '()                            ; set up special SHOW method
                                '((print "nobody here") self))
    
    (setq an-obj (send a-class :new))                          ; create AN-OBJ of A-CLASS
    (send an-obj :show)                                        ; prints "nobody here"
    
    (send a-class :answer :myshow '()                          ; set up MYSHOW method which
                                  '((send-super :show )))      ;   calls :SHOW in superclass
    
    (send an-obj :myshow)                                      ; prints Object is ...
    

    See the send-super function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/equal.htm0000644000175000000620000000644411512762341022272 0ustar stevestaffXLISP equal Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    equal


    Type:   -   predicate function (subr)
    Source:   -   xllist.c, xlsubr.c

    Syntax

    (equal expr1 expr2)
    exprN - arbitrary Lisp expressions
    returns -  T  if the expressions are structurally equivalent, NIL otherwise

    Description

    Two expressions are 'equal':

    • If the expressions are eql.

    • If two strings are string=.

    • If the two cars in conses are 'equal' and the two cdrs in conses are 'equal'.

    In all other cases 'equal' returns NIL. Note that arrays are only 'equal' if they are eq.

    A way to view 'equal' is that if 'expr1' and 'expr2' were printed [via print or princ] and they look the same, then 'equal' will return  T .

    Examples

    (equal 'a 'a)          => T
    (equal 1 1)            => T
    (equal 1 1.0)          => NIL  ; different number types
    (equal 1.0 1.0)        => T
    (equal "a" "a")        => T
    (equal '(a b) '(a b))  => T
    (equal 'a 34)          => NIL
    
    (setq a '(a b))        ; set value of A to (A B)
    (setq b a)             ; set B to point to A's value
    (setq c '(a b))        ; set value of C to different (A B)
    (equal a b)            => T
    (equal a c)            => T
    
    (equal '(a b) '(A B))  => T
    (equal '(a b) '(c d))  => NIL
    
    (equal "a" "A")        => NIL
    (equal "abc" "abcD")   => NIL
    

    See also eq, eql, cl:equalp.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-code.htm0000644000175000000620000000442611512762341023006 0ustar stevestaffXLISP char-code Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-code


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-code char)
    char - a character expression
    returns - the decimal ASCII value as an integer

    Description

    The 'char-code' function returns the decimal ASCII value of the 'char' expression.

    Examples

    (char-code #\0)              => 48
    (char-code #\A)              => 65
    (char-code #\a)              => 97
    (char-code #\[)              => 91
    (char-code #\newline)        => 10
    (char-code (code-char 127))  => 127
    (char-code (int-char 255))   => 255
    

    Note: In Nyquist/XLISP, 'char-code' and char-int are two different functions, but behave exactly the same [Nyquist 3.03, December 2010].

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/mapl.htm0000644000175000000620000000606311512762341022111 0ustar stevestaffXLISP mapl Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    mapl


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (mapl function list1 [list2 ... ])
    function - a function definition like a lambda form or a function name
    listN - a list or list expression
    returns - a list that is equivalent to list1

    Description

    Tha 'mapl' function applies the 'function' to the successive cdrs of each of the lists 'listN'. Each of the lists supplies one of the arguments to 'function'. The 'mapl' function returns a list that is equivalent to the first list 'list1'. It's purpose is to perform operations that have side-effects. If the lists are of different lengths, the shortest list will determine the number of applications of 'function'.

    Examples

    (mapl 'print '(a b c))       ; prints (A B C)
                                 ;        (B C)
                                 ;        (C)
                                 ; returns (A B C)
    
    ;; apply a lambda function to a list
    (mapl (lambda (x y) (princ x) (princ y) (terpri))
          '(a b c) '(1 2 3))     ; prints (A B C)(1 2 3)
                                 ;        (B C)(2 3)
                                 ;        (C)(3)
                                 ; returns (A B C)
    

    Note: The use of the 'function' will work properly when it is a quoted symbol [the name of the function], an unquoted symbol whose value is a function or a closure object like a lambda form.

    See the mapl function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/untrace.htm0000644000175000000620000000550411512762341022620 0ustar stevestaffXLISP untrace Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    untrace


    Type:   -   function (subr)
    Source:   -   xlcont.c

    Syntax

    (untrace function ... )
    function - a function name
    returns - the trace list

    Description

    The 'untrace' function removes 'function' from the current list of traced functions. 'untrace' returns a list containing the current set of functions that are being traced. If the 'function' does currently exist or is currently be traced, there will be no error reported. If there are no functions being traced, a NIL is returned. A list of all currently traced functions can be found in the *tracelist* system variable.

    Examples

    (defun foo (x) (print (car x)))  ; define FOO
    (trace 'foo)                     ; returns (FOO)
    
    (foo '(a))                       ; Entering: FOO, Argument list: ((A))
                                     ; A
                                     ; Exiting: FOO, Value: A
                                     ; returns A
    
    (untrace 'foo)                   ; returns NIL
    (untrace 'glip)                  ; returns NIL
    
    (foo '(a))                       ; prints A  returns A
    

    Common Lisp: The XLISP 'untrace' function does not support any options, which Common Lisp allows.

    See the untrace function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/open.htm0000644000175000000620000001000711512762341022112 0ustar stevestaffXLISP open Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    open


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (open file [:direction in-out])
    file - a string expression or symbol
    in-out - an optional keyword symbol that must be either ':input' or ':output'. The default is ':input'.
    returns - a stream

    Description

    The 'open' function opens the 'file' for input or output. The 'file' may be a string expression or a symbol. Following the 'file', there is an optional keyword, ':direction'. The argument following this is either ':input' or ':output' which specifies the direction of the file. If no ':direction' is specified, the default is ':input'. When 'file' is a string, you may specify a complete file location or extensions like "/usr/local/bin/myfile.lsp" or "A:\LISP\TIM.BAT". If the file open was successful, then a file pointer of the following form is returned as the result:

    #<File: #99999>
    

    If the file open was not successful, a NIL is returned. For an input file, the file has to exist, or an error will be signaled.

    Examples

    (setq f (open 'mine :direction :output))  ; create file named MINE
    (print "hi" f)                            ; returns "hi"
    (close f)                                 ; file contains "hi" <newline>
    (setq f (open 'mine :direction :input))   ; open MYFILE for input
    (read f)                                  ; returns "hi"
    (close f)                                 ; close it
    

    File names: In the PC and DOS world, all file names and extensions ["foo.bat"] are automatically made uppercase. In using XLISP, this means you don't have to worry about whether the name is "foo.bat", "FOO.BAT" or even "FoO.bAt", they will all work. However, in other file systems [UNIX in particular], uppercase and lowercase do make a difference:

    This will create a file named FOO-FILE in UNIX, because XLISP uppercases its symbols:

    (open 'foo-file :direction :output)
    

    This will create a file named 'foo-file' because UNIX doesn't uppercase its file names:

    (open "foo-file" :direction :output)
    

    So, if you are having trouble with opening and accessing files, check to make sure the file name is in the proper case.

    Common Lisp: Common Lisp supports bidirectional files. So, porting Common Lisp code may be difficult to port if it uses these other file types.

    See the open function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-unbound.htm0000644000175000000620000000376211512762341024073 0ustar stevestaffXLISP *unbound* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *unbound*


    Type:   -   system constant
    Source:   -   xlinit.c, xlsym.c

    Syntax

     *unbound*

    Description

    The *unbound* system constant is used to indicate when a symbol has no value. *unbound* is set to the value *unbound*. This means that the system thinks the symbol *unbound* has no value.

    Examples

    *unbound*            ; error: unbound variable
    (setq a 5)           ; returns 5
    a                    ; returns 5
    (setq a '*unbound*)  ; returns *UNBOUND*
    a                    ; error: unbound variable
    

    See the *unbound* system constant in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/nconc.htm0000644000175000000620000000602511512762341022256 0ustar stevestaffXLISP nconc Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    nconc


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (nconc [list1 ... ])
    listN - a list to destructively concatenate
    returns - the result of concatenating the lists

    Description

    The 'nconc' function destructively concatenates a sequence of lists and returns the result of this concatentation. The destructive aspect of this operation means that the actual symbol values are used in the list-modifying operations, not copies. This means, for 'nconc', that the lists are spliced together. 'listN' must evaluate to a valid list. An atom for 'listN' will result in an error. NIL is a valid 'listN'.

    Examples

    (setq a '(1 2 3))      ; set up A with (1 2 3)
    (setq b '(4 5 6))      ; set up B with (4 5 6)
    (setq c '(7 8 9))      ; set up C with (7 8 9)
    (NCONC a b c)          ; returns (1 2 3 4 5 6 7 8 9)
    (setf (nth 8 a) 'end)  ; change last element of A
    (print a)              ; prints (1 2 3 4 5 6 7 8 END)
    (print b)              ; prints (4 5 6 7 8 END)
    (print c)              ; prints (7 8 END)
    

    Note: with Nyquist, no error is raised if 'listN' is an atom. Instead, all atoms given to the 'nconc' function, if not given as the last argument, just disappear:

    (nconc 'a 'b 'c 'd)       ; returns D
    (nconc 'a '(b) 'c '(d))   ; returns (B D)
    (nconc '(a) 'b '(c) 'd)   ; returns (A C . D)
    

    See the nconc function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cerror.htm0000644000175000000620000000074511512762341022455 0ustar stevestaffXLISP cerror Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cerror


    See error.

    nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/endp.htm0000644000175000000620000000520011512762341022076 0ustar stevestaffXLISP endp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    endp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (endp list)
    list - the list to check
    returns -  T  if the list is empty, NIL otherwise

    Description

    The 'endp' predicate function checks to see if 'list' is an empty list.  T  is returned if the list is empty, NIL is returned if the list is not empty. The 'list' has to be a valid list. An error is returned if it is not a list:

    error: bad argument type
    

    Examples

    (endp '())       ; returns T - empty list
    (endp ())        ; returns T - still empty
    (endp '(a b c))  ; returns NIL
    (setq a NIL)     ; set up a variable
    (endp a)         ; returns T - value = empty list
    (endp "a")       ; error: bad argument type - "a"
    (endp 'a)        ; error: bad argument type - A
    

    Note: The 'endp' predicate is different from the null and not predicates in that it requires a valid list.

    See the endp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/maplist.htm0000644000175000000620000000557511512762341022640 0ustar stevestaffXLISP maplist Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    maplist


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (maplist function list1 [list2 ... ])
    function - a function definition like a lambda or a function name
    listN - a list or list expression
    returns - a list that is constructed from the results of the function applications

    Description

    The 'maplist' function applies the 'function' to the successive cdrs of each of the lists 'listN'. Each of the lists supplies one of the arguments to 'function'. The 'maplist' function returns a list that is constructed from the results of the 'function' applications. If the lists are of different lengths, the shortest list will determine the number of applications of 'function'.

    Examples

    (maplist 'print '(a b c))      ; prints (A B C)
                                   ;        (B C)
                                   ;        (C)
                                   ; returns ((A B C) (B C) (C))
    
    ;; append the lists into one list and find it's length
    (maplist (lambda (x y) (length (append x y)))
             '(a b c d) '(1 2 3 4))  ; returns (8 6 4 2)
    

    Note: The use of the 'function' will work properly when it is a quoted symbol [the name of the function], an unquoted symbol whose value is a function or a closure object like a lambda form.

    See the maplist function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/set-difference.htm0000644000175000000620000000371011512762341024037 0ustar stevestaffXLISP set-difference Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    set-difference


    Type:   -   Lisp function (closure)
    Source:   -   xm.lsp

    Syntax

    (set-difference list1 list2)
    listN - a list of symbols or numbers
    returns - the set-difference of list1 and list2

    In Nyquist, 'set-difference' is implemented as a Lisp function:

    (defun set-difference (a b)
      (remove-if (lambda (elem) (member elem b)) a))
    

    Description

    The 'set-difference' function computes the set-difference of two lists. The result is a list containing all elements that appear in only one of both lists.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/zerop.htm0000644000175000000620000000470511512762341022320 0ustar stevestaffXLISP zerop Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    zerop


    Type:   -   predicate function (subr)
    Source:   -   xlmath.c

    Syntax

    (zerop expr)
    expr - the numeric expression to check
    returns -  T  if the number is zero, NIL otherwise

    Description

    The 'zerop' predicate function checks to see if the number 'expr' is zero.  T  is returned if the number is zero, NIL is returned otherwise. An error is generated if the 'expr' is not a numeric expression:

    error: bad argument type
    

    Examples

    (zerop 0)                ; returns T
    (zerop 0.0)              ; returns T
    (zerop 99999.9)          ; returns NIL
    (zerop -0.000000000002)  ; returns NIL
    
    (zerop 'a)               ; error: bad argument type
    (setq a 0)               ; set value of A to 0
    (zerop a)                ; returns T
    

    See the zerop predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-readtable.htm0000644000175000000620000001342011512762341024334 0ustar stevestaffXLISP *readtable* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *readtable*


    Type:   -   system variable
    Source:   -   xlread.c

    Syntax

     *readtable*

    Description

    The *readtable* is a system variable that contains XLISP's data structures relating to the processing of characters from the user (or files) and read-macro expansions. The table is 128 entries [0..127] for each of the 7-bit ASCII characters that XLISP can read. Each entry in the *readtable* array must be one of NIL , :constituent , :white-space , :sescape , :mescape , a :tmacro dotted pair or a :nmacro dotted pair with the meaning of:

     NIL   -   the character is invalid    [see nil]
    :CONSTITUENT   -   the character is valid, as is    [see :constituent]
    :WHITE-SPACE   -   the character may be skipped over    [see :white-space]
    :SESCAPE   -   the single escape character '\'    [see :sescape]
    :MESCAPE   -   the multiple escape character '|'    [see :mescape]
    (:TMACRO . fun)   -   a terminating readmacro    [see :tmacro]
    (:NMACRO . fun)   -   a non-terminating readmacro    [see :nmacro]

    In the case of :nmacro and :tmacro , the form of the *readtable* entry is a list like:

    (:tmacro . function)
    (:nmacro . function)
    

    The 'function' can be a built-in read-macro function or a user defined lambda expression. The 'function' takes two parameters, an input stream specification, and an integer that is the character value. The 'function' should return NIL if the character is 'white-space' or a value consed with NIL to return the value.

    Examples

    *readtable*             ; returns the current table
    
    ;; define a function to look in a table and
    ;; print out any entries with a function
    
    (defun look-at (table)
      (dotimes (ch 127)
        (prog ((entry (aref table ch)))
          (case entry
            (nil          nil)
            (:constituent nil)
            (:white-space nil)
            (:sescape     nil)
            (:mescape     nil)
            (t (princ (int-char ch))))))
      (terpri))
    
    (look-at *readtable*)   ; prints "#'(),;`
    

    Caution: If you experiment with *readtable*, it is useful to save the old value in a variable, so that you can restore the system state.

    See the *readtable* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/number-lessp.htm0000644000175000000620000000510111512762341023564 0ustar stevestaffXLISP < Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    <


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (< expr1 expr2 ...)
    exprN - a numeric expression
    returns -  T  if the results of comparing the expressions are all true, NIL otherwise

    Description

    The '<' [less-than] function takes an arbitrary number of numeric arguments. It checks to see if all the numbers are monotonically increasing.  T  is returned if the arguments are numerically, and monotonically increasing, NIL is returned otherwise. In the case of two arguments, this has the effect of testing if 'expr1' is less than 'expr2'.

    Examples

    (< 1 2)              => T
    (< 1 1)              => NIL
    (< -1.5 -1.4)        => T
    (< 1 2 3 4)          => T
    (< 1 2 3 2)          => NIL
    (< "a" "b")          => error: bad argument type
    (setq a 12 b 13.99)  => 13.99  ; set up A and B with values
    (< a b)              => T
    (< b a)              => NIL
    

    See setq.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/pprint.htm0000644000175000000620000000646211512762341022477 0ustar stevestaffXLISP pprint Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    pprint


    Type:   -   function (subr)
    Source:   -   xlpp.c

    Syntax

    (pprint expr [dest])
    expr - an expression to be pretty printed
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - always returns NIL

    Description

    The 'pprint' function produces a pretty looking version of the 'expr' and prints it to the specified 'destination'. If 'expr' is an atom like a string, a symbol, a number, etc., 'pprint' will print it like print. If 'expr' is a list, it will perform indenting, as necessary. NIL is always returned as the result of 'pprint'. The 'destination' may be a file pointer or a stream. If there is no 'destination' or it is NIL , *standard-output* is the default.

    Examples

    (pprint 'a)      ; prints  A       returns NIL
    (pprint "abcd")  ; prints  "abcd"  returns NIL
    
    (pprint '(a-very-long-name (first list) (second list)))
    
                     ; prints (A-VERY-LONG-NAME (FIRST LIST)
                     ;                          (SECOND LIST))
                     ; returns NIL
    

    Common Lisp: Common Lisp specifies that 'pprint' with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the pprint function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/eql.htm0000644000175000000620000000544311512762341021742 0ustar stevestaffXLISP eql Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    eql


    Type:   -   predicate function (subr)
    Source:   -   xllist.c, xlsubr.c

    Syntax

    (eql expr1 expr2)
    expr1 - the first expression to compare
    expr2 - the second expression to compare
    returns -  T  if the expressions have the same symbolic or numerical value, NIL otherwise

    Description

    Two expressions are 'eql':

    • If the expressions are eq.

    • If two numbers of the same type are  = .

    • If two characters are char=.

    In all other cases 'eql' returns NIL. Note that arrays, lists, and strings are only 'eql' if they are eq.

    Examples

    (eql 'a 'a)          => T
    (eql 1 1)            => T
    (eql 1 1.0)          => NIL
    (eql 1.0 1.0)        => T
    (eql "a" "a")        => NIL
    (eql '(a b) '(a b))  => NIL
    (eql 'a 34)          => NIL
    
    (setq a '(a b))      ; set value of A to (A B)
    (setq b a)           ; set B to point to A's value
    (setq c '(a b))      ; set value of C to different (A B)
    (eql a b)            => T
    (eql a c)            => NIL
    

    See also eq, equal, cl:equalp.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/macroexpand.htm0000644000175000000620000000540511512762341023460 0ustar stevestaffXLISP macroexpand Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    macroexpand


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (macroexpand form)
    form - a macro form
    returns - the macro expansion

    Description

    The 'macroexpand' function takes a 'form' and recursively expands the macro definitions used in the 'form'. The function returns the expansion. If the 'form' does not contain a macro, the form is returned unaltered.

    Examples

    (defmacro plus (n1 n2) `(+ ,n1 ,n2))   ; define PLUS macro
    (plus 1 2)                             ; returns 3
    (macroexpand '(plus 3 4))              ; returns (+ 3 4)
    
    (defmacro pl (p1 p2) `(plus ,p1 ,p2))  ; define PL macro using PLUS
    (pl 3 4)                               ; returns 7
    (macroexpand '(pl 3 4))                ; returns (+ 3 4)
    (macroexpand-1 '(pl 3 4))              ; returns (PLUS 3 4)
    

    Common Lisp: Common Lisp returns 2 values for its result of 'macroexpand', the expanded form and a  T  or NIL value that indicates if the form was a macro. XLISP returns only the expanded form. Common Lisp also supports an optional argument in 'macroexpand' for the environment of the expansion. XLISP does not support this optional argument.

    See the macroexpand function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/errset.htm0000644000175000000620000001106111512762341022456 0ustar stevestaffXLISP errset Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    errset


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (errset expr [print-flag])
    expr - an expression to be evaluated
    print-flag - an optional expression [NIL or non-NIL]
    returns - the value of the last expression consed with NIL , or NIL on error

    Description

    The 'errset' special form is a mechanism that allows the trapping of errors within the execution of 'expr'. *breakenable* must be set to NIL for the 'errset' form to function. If *breakenable* is non-NIL , the normal break loop will handle the error. For 'errset', if no error occurs within 'expr', the value of the last expression is consed with NIL. If an error occurs within 'expr', the error is caught by 'errset' and a NIL is returned from 'errset'. If 'print-flag' is NIL , the error message normally generated by 'expr' will not be printed. If 'print-flag' is non-NIL or not present in the 'errset' form, the error message will be printed.

    Errors from error and cerror and system errors will be handled by 'errset'. Note that the cerror message will only include the error message portion, not the continue message portion. break is not intercepted by 'errset'.

    Examples

    (setq *breakenable* nil)          ; do not enter the break-loop on errors
    (errset (error "hi" "ho"))        ; prints  error: hi - "ho" returns NIL
    (errset (cerror "hi" "ho" "he"))  ; prints  error: ho - "he" returns NIL
    (errset (error "hey" "ho") NIL)   ; returns NIL
    (errset (break "hey"))            ; break: hey - if continued: return from BREAK
    (continue)                        ; [ continue from break loop ]
    (errset (+ 1 5))                  ; returns (6)
    (errset (+ 1 "a") NIL)            ; returns NIL
    (setq *breakenable* t)            ; re-enable the break-loop on errors
    

    How to keep XLISP from signalling an error:

    (setq *breakenable* nil)
    (errset expression-causing-an-error t)  ; print the error message
    (errset expression-causing-an-error)    ; do NOT print the error message
    

    Note: Be sure to set *breakenable* to NIL before using 'errset' and to non-NIL after using 'errset'. If you don't reset *breakenable* , no errors will be reported.

    See the errset function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/first.htm0000644000175000000620000000435311512762341022307 0ustar stevestaffXLISP first Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    first


    Type:   -   function (subr)
    Source:   -   xlinit.c

    Syntax

    (first expr)
    expr - a list or list expression
    returns - the first element of the expression

    Description

    The 'first' function returns the first element of the expression. If the first expression is itself a list, then the sublist is returned. If the list is NIL , NIL is returned.

    Examples

    (first '(a b c))               ; returns A
    (first '((a b) c d))           ; returns (A B)
    (first NIL)                    ; returns NIL
    (first 'a)                     ; error: bad argument type
    (setq children '(amanda ben))  ; set up variable CHILDREN
    (first children)               ; returns AMANDA
    

    See the first function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-gc-flag.htm0000644000175000000620000000434111512762341023713 0ustar stevestaffXLISP *gc-flag* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *gc-flag*


    Type:   -   system variable
    Source:   -   xldmem.c

    Syntax

     *gc-flag*

    Description

    *gc-flag* is a system variable that controls the printing of a garbage collection message. If *gc-flag* is NIL , no garbage collection messages will be printed. If *gc-flag* is non-NIL , a garbage collection message will be printed whenever a gc takes place. The default value for *gc-flag* is NIL. The message will be of the form:

    [ gc: total 4000, 2497 free ]
    

    Examples

    *gc-flag*           ; returns NIL
    (gc)                ; returns NIL
    (setq *gc-flag* T)  ; set up for message
    (gc)                ; prints a gc message
    

    See the *gc-flag* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/vector.htm0000644000175000000620000000413611512762341022461 0ustar stevestaffXLISP vector Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    vector


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (vector [expr ... ])
    expr - an expression
    returns - the new vector

    Description

    The 'vector' function creates an initialized vector and returns it as the result. 'vector' is essentially a fast method to do a one-dimensional make-array with initial data in the vector.

    Examples

    (vector 'a 'b 'c)        ; returns #(A B C)
    (vector '(a b) '(c d))   ; returns #((A B) (C D))
    (vector)                 ; returns #()
    (vector NIL)             ; returns #(NIL)
    (vector 'a () 4 "s")     ; returns #(A NIL 4 "s")
    

    See the vector function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/exit.htm0000644000175000000620000000335511512762341022132 0ustar stevestaffXLISP exit Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    exit


    Type:   -   function (subr)
    Source:   -   xlsys.c

    Syntax

    (exit)
    returns - never returns

    Description

    The 'exit' function causes the current XLISP session to be terminated. It never returns.

    Examples

    (exit)   ; never returns
    

    Note: When XLISP is exited, any dribble transcript file is automatically closed. However, other open files are not closed, and so may lose some information.

    See also quit.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/putprop.htm0000644000175000000620000000756611512762341022702 0ustar stevestaffXLISP putprop Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    putprop


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (putprop symbol value property)
    symbol - the symbol with a property list
    value - the value to be assigned to the property
    property - the property name being changed or added
    returns - the property value

    Description

    The 'putprop' function sets the value of the 'property' in the 'symbol'. If the 'property' does not exist, the 'property' is added to the property list. The 'symbol' must be an existing symbol. The 'value' may be a single value or a list.

    Property lists are lists attached to any user defined variables. The lists are in the form of:

    (name1 val1 name2 val2 ... )
    

    Any number of properties may be attached to a single variable.

    Examples

    (setq person 'bobby)                  ; create a var with a value
    (putprop person 'boogie 'last-name)   ; add a LAST-NAME property
    (putprop person 'disc-jockey 'job)    ; add a JOB property
    
    (get person 'last-name)               ; retrieve LAST-NAME - boogie
    (get person 'job)                     ; retrieve JOB - disc-jockey
    (get person 'height)                  ; non-existant - returns NIL
    
    (putprop person '(10 20 30) 'stats)   ; add STATS - a list
    (get person 'stats)                   ; retrieve STATS - (10 20 30)
    

    Note: You can set a property to the value NIL. However, this NIL value is indistinguishable from the NIL returned when a property does not exist.

    Common Lisp: Common LISP does not have a 'putprop' function. It uses setf to achieve this functionality. Porting from Common Lisp to XLISP will work fine since XLISP supports the setf modifications of property lists as well as the get function to retrieve property values from symbol names. Porting from XLISP to Common Lisp will require translating 'putprop' into setf forms.

    Caution: In XLISP, the order of 'putprop' arguments is 'symbol', 'value', 'property'. This is different from many other Lisps which normally use 'symbol', 'property', 'value'. Be careful when porting existing Lisp code.

    See the putprop function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/poke.htm0000644000175000000620000000607111512762341022115 0ustar stevestaffXLISP poke Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    poke


    Type:   -   function (subr)
    Source:   -   xlsys.c

    Syntax

    (poke address expr)
    address - an integer expression
    expr - an integer expression
    returns - the value

    Description

    The 'poke' function writes the 'expr' at the internal memory value at the specified 'address'. The returned value is 'expr'. Be very careful with this function.

    Examples

    (setq var 0)                        ; set up VAR with 0
    (address-of var)                    ; returns 123224
    (address-of 'var)                   ; returns 161922
    (peek (address-of var))             ; returns 83951616
    (peek (1+ (address-of var)))        ; returns 16777216
    (peek (+ 2 (address-of var)))       ; returns 0  <-- value of VAR
    (setq var 14)                       ; change the value to 14
    (peek (+ 2 (address-of var)))       ; returns 14
    (poke (+ 2 (address-of var)) 1023)  ; POKE the value to 1023
    (print var)                         ; prints  1023
    

    Caution: Be careful when modifying the internal state of XLISP. If you have modified it, it would be a good idea to exit XLISP and re-enter before doing any work you really want to retain.

    Caution: It is possible to peek and 'poke' not just XLISP's memory put other parts of your computer's memory. Be very careful when doing this. Also, in some computers, just looking at a memory location can cause things to happen, I/O locations fall in this category.

    See the poke function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/prog1.htm0000644000175000000620000000470011512762341022204 0ustar stevestaffXLISP prog1 Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    prog1


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (prog1 [expr1 expr2 ... ])
    exprN - expressions comprising the body of the loop
    returns - the value of the first expression

    Description

    The 'prog1' special form is basically a 'block' construct that contains a block of code [expressions] to evaluate. The value of the first expression 'expr1' will be returned as the result of 'prog1'. If there is no 'expr1', NIL is returned.

    Examples

    (prog1 (print "hi") (print "ho"))  ; prints "hi" "ho"  returns "hi"
    (prog1)                            ; returns NIL
    (prog1 'a)                         ; returns A
    (prog1 "hey" (print "ho"))         ; prints "ho"  returns "hey"
    

    Note: 'prog1', prog2 , progn and progv do not allow the use of return or go or tags for go.

    See the prog1 special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/evalhook.htm0000644000175000000620000001350111512762341022763 0ustar stevestaffXLISP evalhook Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    evalhook


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xleval.c

    Syntax

    (evalhook expr eval-expr apply-expr [env])
    expr - an expression to evaluate
    eval-expr - an expression for the evaluation routine
    apply-expr - an expression for apply [not used]
    env - an environment expression, default is NIL
    returns - the result of evaluating the expression

    Description

    The 'evalhook' function is a function that performs evaluation. The routine specified by 'eval-expr' is called with the 'expr' and 'env' parameters. If 'eval-expr' is NIL , then the normal system evaluator is called. The 'apply-hook' is a dummy parameter that is not used in the current XLISP system. The 'expr' contains the expression to be evaluated. If the 'env' argument to 'evalhook' is not specified, NIL is used, which specifies to use the current global environment. The 'env', if specified, is a structure composed of dotted pairs constructed of the symbol and its value which have the form:

    (((sym1 . val1) (sym2 . val2) ... )))
    

    Examples

    (setq a 100)                       ; set up global values
    (setq b 200)
    
    (evalhook '(+ a b) NIL NIL)        ; returns 300 - no 'env' was given
    
    (evalhook '(+ a b) NIL NIL         ; eval with a=1 and b=2
              '((((a . 1)(b . 2)))))   ;   returns 3
    
    (defun myeval (exp env)            ; define MYEVAL routine
      (princ "exp: ") (print exp)
      (princ "env: ") (print env)
      (evalhook exp #'myeval NIL env))
    
    (defun foo (a) (+ a a))            ; create simple function
    (setq *evalhook* #'myeval)         ; and install MYEVAL as hook
    
    (foo 1)                            ; prints exp: (FOO 1) env:NIL
                                       ;        exp: 1       env:NIL
                                       ;        exp: (+ A A) env:((((A . 1))))
                                       ;        exp: A       env:((((A . 1))))
                                       ;        exp: A       env:((((A . 1))))
                                       ; returns 2
    
    (top-level)                        ; to clean up *evalhook*
    

    Note: The 'evalhook' function and *evalhook* system variable are very useful in the construction of debugging facilities within XLISP. The trace and untrace functions use 'evalhook' and *evalhook* to implement their functionality. The other useful aspect of 'evalhook' and *evalhook* is to help in understanding how XLISP works to see the expressions, their environment and how they are evaluated.

    Caution: Be careful when using *evalhook* and 'evalhook'. If you put in a bad definition into *evalhook* , you might not be able to do anything and will need to exit XLISP.

    Unusual behaviour: The 'evalhook' function and *evalhook* system variable, by their nature, cause some unusual things to happen. After you have set *evalhook* to some non-NIL value, your function will be called. However, when you are all done and set *evalhook* to NIL or some other new routine, it will never be set. This is because the 'xevalhook' function [in the 'xlbfun.c' source file] saves the old value of *evalhook* before calling your routine, and then restores it after the evaluation. The mechanism to reset *evalhook* is to execute the top-level function, which sets *evalhook* to NIL.

    See the evalhook function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/max.htm0000644000175000000620000000405211512762341021741 0ustar stevestaffXLISP max Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    max


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (max expr1 ... )
    exprN - integer or floating point number/expression
    returns - the largest number in the list of numbers/expressions

    Description

    The 'max' function returns the largest numeric expression from the list of arguments.

    Examples

    (max 1)               ; returns 1
    (max 1 -5 9)          ; returns 9
    
    (setq a '( 9 3 5 2))  ; set up a list - (9 3 5 2)
    (apply 'max a)        ; returns 9
    (apply #'max a)       ; returns 9
    (apply 'min a)        ; returns 2
    

    See the max function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/delete-if.htm0000644000175000000620000001006411512762341023012 0ustar stevestaffXLISP delete-if Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    delete-if


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (delete-if test list)
    test - the test function to be performed
    list - the list to delete from
    returns - the list with matching elements deleted

    Description

    The 'delete-if' function destructively modifies the 'list' by removing the elements of the list that pass the 'test'. The destructive aspect of this operation means that the actual symbol value is used in the list-modifying operations, not a copy.

    'list' must evaluate to a valid list. An atom for 'list' will result in an error:

    error: bad argument type
    

    Having NIL for 'list' will return a NIL as the result.

    Examples

    Caution: there's a bug:

    (setq mylist '(1 2 3 4 5 6 7 8))         ; set up a list starting of numbers
    (delete-if 'oddp mylist)                 ; returns (2 4 6)
    (print mylist)                           ; prints  (1 2 4 6) <-BUG!
    
    (setq mylist '(1 2 3 4 5 6 7 8))         ; set up the same list again
    (setq mylist (delete-if 'oddp mylist))   ; returns (2 4 6)
    (print mylist)                           ; prints  (2 4 6) <-OK
    
    (setq mylist '(1 2 3 4 5 6 7 8))         ; ... again ...
    (delete-if 'evenp mylist)                ; returns (1 3 5 7)
    (print mylist)                           ; prints  (1 3 5 7) <-OK
    
    (setq mylist '(1 2 3 4 5 6 7 8))         ; ... and again ...
    (setq mylist (delete-if 'evenp mylist))  ; returns (1 3 5 7)
    (print mylist)                           ; prints  (1 3 5 7) <-OK
    

    Bug: 'delete-if' will return the proper value, but it does not always properly modify the symbol containing the value. This seems to be true if the first element of the 'list' passes the test [and should be deleted]. It's always better to use 'delete-if' together with setq or setf as shown in example 2 and 4.

    Note: This bug can be reproduced with Nyquist 2.36 [in June 2007], so please take care.

    Common Lisp: XLISP does not support the ':from-end', ':start', ':end', ':count' and ':key' keywords which Common LISP does.

    See the delete-if function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/get-key.htm0000644000175000000620000000351011512762341022517 0ustar stevestaffXLISP get-key Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    get-key


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/mac/macfun.c, sys/win/msvc/winfun.c

    Syntax

    (get-key)
    returns - the decimal ASCII value of the key pressed

    Description

    The 'get-key' function gets a single key stroke from the keyboard [as opposed to an entire line, as read does].

    Note: In Nyquist, this function is only defined to work on Unix systems [including Linux and Mac OS X]. On Windows systems, NIL is returned.

    Examples

    (setq mychar (get-key))   ; get a character
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/read-float.htm0000644000175000000620000000460411512762341023175 0ustar stevestaffXLISP read-float Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    read-float


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (read-float [stream [length]])
    stream - the input stream (default is standard input)
    length - the length of the float in bytes [default is 4, legal values are -4, -8, 4, and 8]
    returns - the float

    Description

    The 'read-float' function reads a binary floating point number from an input stream, created by the open-binary function.

    Note: Integers and floats are assumed to be big-endian [high-order byte first] and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. '-4' indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    Examples

    
    

    See also read-int, write-int, write-float, bigendianp, open-binary.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/setf.htm0000644000175000000620000002525511512762341022125 0ustar stevestaffXLISP setf Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    setf


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (setf [place1 expr1 ... ])
    placeN - a field specifier which may be one of:
    symbol - set value of a symbol
    (car expr) - set car of a cons node
    (cdr expr) - set cdr of a cons node
    (nth n expr) - set nth car of a list
    (aref expr n) - set nth element of an array
    (get symbol property) - set value of a property
    (symbol-value symbol) - set value of a symbol
    (symbol-function symbol) - set functional value of a symbol
    (symbol-plist symbol) - set property list of a symbol
    exprN - an expression, which will be the new value
    returns - the new value

    Description

    The 'setf' special form evaluates the field 'placeN' and sets 'exprN' as it's value. This is a generalized tool that allows you to set the value of the various data types of the system. 'setf' returns the value from 'exprN' as it's result. The specific action of 'setf' depends on the 'placeN' field. A more detailed explanation follows below the examples.

    Examples

    :; setf symbols
    
    (setf a 123)                          ; set a symbol A to value 123
    
    ;; setf symbol-values
    
    (setq x 'y)                           ; make symbol X with value Y
    (setf (symbol-value x) 'z)            ; set symbol that X contains (Y) to value Z
    
    ;; setf list elements
    
    (setq mylist '(a b c d))              ; MYLIST with value (A B C D)
    
    (setf (car mylist) 'x)                ; change CAR of MYLIST to X
                                          ;   MYLIST now is (X B C D)
    
    (setf (cdr mylist) '(y z da-end))     ; change CDR of MYLIST to (Y Z DA-END)
                                          ;   MYLIST now is (X Y Z DA-END)
    
    (setf (nth 3 mylist) 'here-i-am)      ; change 3rd of MYLIST to HERE-I-AM
                                          ;   MYLIST now is (X Y Z HERE-I-AM)
    
    ;; setf arrays
    
    (setq myarray (make-array 5))         ; make MYARRAY
    (aref myarray 2)                      ; get value of element 2 = NIL
    (setf (aref myarray 2) 'new-value)    ; set value of element 2 to value NEW-VALUE
    (print myarray)                       ; prints #(NIL NIL NEW-VALUE NIL NIL)
    
    ;; setf properties
    
    (setq person 'joe-bob)                ; make PERSON with value JOE-BOB
    (putprop person 'critic 'profession)  ; set PROFESSION property to value CRITIC
    (setf (get person 'profession)        ; change PROFESSION to value TEXAS-CRITIC
    (setf (get person 'home) 'texas)      ; add property HOME with value TEXAS
                    
    (symbol-plist person)                 ; returns property list:
                                          ;   (HOME TEXAS
                                          ;    PROFESSION TEXAS-CRITIC)
    
    (setf (symbol-plist person)           ; change the property list
          '(home on-the-range
            profession movie-critic))
    
    (get person 'profession)              ; now returns MOVIE-CRITIC
    (get person 'home)                    ; now returns ON-THE-RANGE
    

    Operations

    (setf sym exprN)
      -  Sets the value of 'symbol' to the value of 'exprN'. This is equivalent to (setq sym exprN)
    (setf (car expr) exprN)
      -  Sets the first element of the 'expr' list to 'exprN'. 'expr' must be a list. This is equivalent to (rplaca expr exprN) except that 'setf' will return 'exprN' as the value.
    (setf (cdr expr) exprN)
      -  Sets the tail of the 'expr' list to 'exprN'. 'expr' must be a list. This is equivalent to (rplacd expr exprN) except that 'setf' will return 'exprN' as the value.
    (setf (nth n expr) exprN)
      -  Sets the nth element of the 'expr' list to 'exprN'. 'expr' must be a list. This allows you to set an arbitrary element of a list to an arbitrary value. Note that the list is numbered from the 0th element (0, 1, 2, 3, ...).
    (setf (aref expr n) exprN)
      -  Sets the nth element of the 'expr' array to 'exprN'. 'expr' must be an array. This allows you to set an arbitrary element of an array to an arbitrary value. Note that the list is numbered from the 0th element (0, 1, 2, 3, ...). Note also that this is the intended way to set the value of an array element.
    (setf (get sym prop) exprN)
      -  Sets the 'property' of 'symbol' to the value 'exprN'. If 'symbol' does not have the 'property', one will be created. This is equivalent to (putprop sym exprN prop).
    (setf (symbol-value sym) exprN)
      -  Sets the symbol's value to contain 'exprN'. 'symbol' is an expression that must evaluate to a valid symbol, it doesn't have to exist before the 'setf' function is applied, it just has to be a valid symbol. This is equivalent to (set symbol exprN).
    (setf (symbol-plist sym) exprN)
      -  Sets the property list of 'symbol' to 'exprN'. This allows you to change or destroy the entire property list of a 'symbol' at one time.

    See the setf special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/consp.htm0000644000175000000620000000721011512762341022275 0ustar stevestaffXLISP consp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    consp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (consp expr)
    expr - the expression to check
    returns -  T  if the value is a cons, NIL otherwise

    Description

    The 'consp' predicate checks if the 'expr' is a non-empty list.  T  is returned if 'expr' is a list, NIL is returned otherwise. Note that if the 'expr' is NIL , NIL is returned.

    Examples

    (consp '(a b))                  ; returns T - list
    (consp '(a . b))                ; returns T - dotted pair list
    (consp #'defvar)                ; returns NIL - closure - macro
    (consp (lambda (x) (print x)))  ; returns NIL - closure - lambda
    (consp NIL)                     ; returns NIL - NIL
    (consp #(1 2 3))                ; returns NIL - array
    (consp *standard-output*)       ; returns NIL - stream
    (consp 1.2)                     ; returns NIL - float
    (consp #'quote)                 ; returns NIL - fsubr
    (consp 1)                       ; returns NIL - integer
    (consp object)                  ; returns NIL - object
    (consp "str")                   ; returns NIL - string
    (consp #'car)                   ; returns NIL - subr
    (consp 'a)                      ; returns NIL - symbol
    

    Note: When applied to 'consp', NIL , the empty list, returns a NIL. NIL or '() is used in many places as a list-class or atom-class expression. Both atom and listp , when applied to NIL , return  T . If you wish to check for a list where an empty list is still considered a valid list, use the listp predicate.

    See the consp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-greaterp-i.htm0000644000175000000620000000536611512762341024137 0ustar stevestaffXLISP char-greaterp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-greaterp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-greaterp char1 charN ... )
    char1 - a character expression
    charN - character expression(s) to compare
    returns -  T  if the characters are of monotonically decreasing ASCII value, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'char-greaterp' function tests if all the character arguments are monotonically decreasing.  T  is returned if the arguments are of monotonically decreasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is greater than 'char2'. This test is case insensitive, the character '#\a' is considered to be the same ASCII value as the character '#\A'.

    Examples

    (char-greaterp #\a #\b)      => NIL
    (char-greaterp #\b #\a)      => T
    (char-greaterp #\c #\b #\a)  => T
    (char-greaterp #\a #\a)      => NIL
    (char-greaterp #\c #\a #\b)  => NIL
    (char-greaterp #\A #\a)      => NIL
    (char-greaterp #\a #\A)      => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/psetq.htm0000644000175000000620000000470411512762341022314 0ustar stevestaffXLISP psetq Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    psetq


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (psetq [symbol expr] ... )
    symbol - un-evaluated symbol
    expr - value for symbol
    returns - the value from the last expr

    Description

    'psetq' sets 'expr' as the value of 'symbol'. There can be several pairs of assignment. 'psetq' performs these assignments in parallel, the 'symbols' are not assigned new values until all the 'exprs' have been evaluated. 'psetq' returns the value from the last 'expr' as it's result.

    Examples

    (psetq a 1)              ; symbol A gets value 1
    (psetq b '(a b c))       ; symbol B gets value (A B C)
    (psetq mynum (+ 3 4))    ; symbol MYNUM gets value 7
    
    (setq goo 'ber)          ; returns BER
    (setq num 1)             ; returns 1
    (psetq goo num num goo)  ; returns BER
    (print goo)              ; returns 1
    (print num)              ; returns BER
    

    See the psetq special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/baktrace.htm0000644000175000000620000000617211512762341022735 0ustar stevestaffXLISP baktrace Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    baktrace


    Type:   -   function (subr)
    Source:   -   xldbug.c, xlsys.c

    Syntax

    (baktrace [level])
    level - an optional integer expression
    returns - NIL

    Description

    The 'baktrace' function is used to examine the system execution stack from within the Break Loop. It shows the nested forms that got the system to the current state. The Break Loop can be entered by a system error, or by the Nyquist/XLISP error, cerror, or break functions. If the 'levels' parameter is not specified, all the nested forms will be shown back to the main loop form that started the execution. If 'level' is specified the most recent 'level' nested forms will be shown.

    Examples

    (defun out (x)
      (print x)
      (mid 99))
    
    (defun mid (x)
      (print x)
      (in 999))
    
    (defun in (x)
      (print x)
      (break "in" x))  ; break
    
    > (out 9)
    9
    99
    999
    break: in - 999
    if continued: return from BREAK
    
    1> (baktrace)   ; the 1 before the > indicates a break loop
    Function: #<Subr-BAKTRACE: #9af6688>
    Function: #<Subr-BREAK: #9af6778>
    Arguments:
      "in"
      999
    Function: #<Closure-IN: #9b99574>
    Arguments:
      999
    Function: #<Closure-MID: #9b99670>
    Arguments:
      99
    Function: #<Closure-OUT: #9b99778>
    Arguments:
      9
    NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/last.htm0000644000175000000620000000427311512762341022124 0ustar stevestaffXLISP last Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    last


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (last list-expr)
    list-expr - a list or list expression
    returns - the last list node in the list

    Description

    The 'last' function returns a list containing the last node or element of a list. If the last node is a sub-list, this is returned unaffected.

    Examples

    (last NIL)                     ; returns NIL
    (last 'a)                      ; error: bad argument type
    (last '(A))                    ; returns (A)
    (last '(A B C D E))            ; returns (E)
    (last '( A (B C) (D E (F))))   ; returns ((D E (F)))
    
    (setq children '(junie vicki cindy chris))
    
    (last children)                ; returns (CHRIS)
    

    See the last function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/labels.htm0000644000175000000620000000753511512762341022427 0ustar stevestaffXLISP labels Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    labels


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (labels ([function ... ]) expr ... )
    function - a function definition binding which is of the form:
    (symbol arg-list body)
    symbol - the symbol specifying the function name
    arg-list - the argument list for the function
    body - the body of the function
    expr - an expression
    returns - the value of the last expression

    Description

    The 'labels' special form is basically a local block construct that allows local 'function' definitions followed by a block of code to evaluate. The first form after the labels is the 'binding' form. It contains a series of 'functions'. 'labels' allows the'functions' to be defined in a mutually recursive manner. [The similar flet form does not allow this.] The 'labels' form will go through and define the 'symbols' of the 'functions' and then sequentially execute the 'exprs'. The value of the last 'expr' evaluated is returned. When the 'labels' is finished execution, the 'symbols' that were defined will no longer exist.

    Examples

    (labels ((fuzz (x) (+ x x)))      ; a LABELS with a local function FUZZ
      (fuzz 2))                       ; returns 4
    
                                      ; FUZZ no longer exists
    (fuzz 2)                          ; error: unbound function - FUZZ
    
                                      ; an empty LABELS
    (labels () (print 'a))            ; prints A
    
                                      ; LABELS form including
    (labels ((inc (arg) (est arg))    ;   INC definition using EST
             (est (var) (* .1 var)))  ;   EST definition
      (inc 99) )                      ;   returns 9.9
    
                                      ; FLET form including
    (flet ((inc (arg) (est arg))      ;   INC definition using EST
           (est (var) (* .1 var)))    ;   EST definition
      (inc 99)                        ; error: unbound function - EST
    

    Note: flet does not allow recursive definitions of functions. The 'label' special form does allow this.

    See the labels special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/sin.htm0000644000175000000620000000431611512762341021750 0ustar stevestaffXLISP sin Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    sin


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (sin expr)
    expr - floating point number or expression
    returns - the sine of the number

    Description

    The 'sin' function returns the sine of the 'expr'. The 'expr' is in radians.

    Examples

    (sin 0.0)             ; returns 0
    (sin .5)              ; returns 0.479426
    (sin 1.0)             ; returns 0.841471
    (sin (/ 3.14159 2))   ; returns 1
    (sin 3.14159)         ; returns 2.65359e-06
    (sin 0)               ; error: bad integer operation
    (sin 1.)              ; error: bad integer operation
    

    Common Lisp: Common LISP allows for integer numbers, which XLISP does not support for 'sin'.

    See the sin function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/sublis.htm0000644000175000000620000001331011512762341022452 0ustar stevestaffXLISP sublis Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    sublis


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (sublis a-list expr [{:test | :test-not} test])
    expr - the expression to substitute within, an atom
    a-list - the association list to search
    test - optional test function, default is eql
    returns - the expression with substitutions

    Description

    The 'sublis' function searches through an 'expr' and replaces each of the elements in the 'expr' that match the car of the elements of the association list 'a-list' with the cdr of elements of the 'a-list'. The 'expr' with the substitutions, if any, is returned. You may specify your own test with the ':test' and ':test-not' keywords followed by the 'test' you wish to perform. The 'sublis' function is normally used with a dotted pair (A . B) association list. It is possible to use a normal list pair (A B) or a list of the form (A (B C)).

    Examples

    (sublis '((a . b))   '(a a))            ; returns (B B)
    (sublis '((a b))     '(a a))            ; returns ((B) (B))
    (sublis '((a (b c))) '(a a))            ; returns (((B C)) ((B C)))
    
    (setq newlist '((a . 1)                 ; set up an association list
                    (b . 2)
                    (c . 3)))
    
    (sublis newlist '(a b c d e f b a c))   ; returns (1 2 3 D E F 2 1 3)
    
    (sublis newlist 'a)                     ; returns 1
    
    (setq mylist '((a my-a) (b his-b)       ; set up a non-dotted pair assoc list
                   (c her-c) (d end)))
    
    (sublis mylist '(a b c d e f g))        ; returns ((MY-A) (HIS-B)
                                            ;          (HER-C) (END) E F G)
    
    (sublis mylist 'a)                      ; returns (MY-A)
    
    (setq numlist '((1 . a) (2 . b)) )      ; set up a new assoc list
    
    (defun mytest (x y) (princ ": ")        ; set up my own test function with 2 parameters
                        (princ x)           ; to see what SUBLIS does
                        (princ " ")
                        (princ y) (terpri)
                        t)                  ; always return T
    
    (sublis numlist '(3 1) :test mytest)    ; prints : (3 1) 1
                                            ; returns A - because the entire list succeeds
                                            ; with the test and so (1 . A) produces the
                                            ; returned value
    
    (sublis numlist '(1) :test-not mytest)  ; prints : (1) 1
                                            ;        : (1) 2
                                            ;        : 1 1
                                            ;        : 1 2
                                            ;        : NIL 1
                                            ;        : NIL 2
                                            ; returns (1) - because SUBLIS tried to match
                                            ; every list/sublist against each entry in the
                                            ; assoc list and failed because of the :TEST-NOT
                                            ; and so returned the original list unaltered
    

    Note: The SUBLIS function can work with a list or string as the 'expr'. However, the default eql test does not work with lists or strings, only symbols and numbers. To make this work, you need to use the ':test' keyword along with equal for 'test'.

    Common Lisp: Common LISP supports the use of the ':key' keyword which specifies a function that is applied to each element of 'a-list' before it is tested. XLISP does not support this.

    See the sublis function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/defmacro.htm0000644000175000000620000001477511512762341022751 0ustar stevestaffXLISP defmacro Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    defmacro


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (defmacro symbol arg-list body)
    symbol - the name of the macro being defined
    arg-list - a list of the formal arguments to the macro of the form:
    ([arg1 ... ]
     [&optional oarg1 ... ]
     [&rest rarg]
     [&key ... ]
     [&aux aux1 ... ])
    body - a series of LISP forms (expressions) that are executed in order.
    returns - the macro symbol

    Description

    'defmacro' defines a macro expansion. When the 'symbol' name of the macro expansion is encountered [similar to a function invocation], the 'body' of code that was defined in the 'defmacro' is expanded and replaces the macro invocation.

    All of the 'argN' formal arguments that are defined are required to appear in the invocation of the macro expansion.

    If there are any &optional arguments defined, they will be filled in order.

    If there is a &rest argument defined, and all the required formal arguments and &optional arguments are filled, any and all further parameters will be passed into the function via the 'rarg' argument. Note that there can be only one 'rarg' argument for &rest.

    If there are insufficient parameters for any of the &optional or &rest arguments, they will contain NIL.

    The &aux variables are a mechanism for you to define variables local to the 'defmacro' execution. At the end of the function execution, these local symbols and their values are are removed.

    Examples

    (defmacro plus (num1 num2)               ; define PLUS macro
      `(+ ,num1 ,num2))                      ;   which is a 2 number add
    
    (plus 1 2)                               ; returns 3
    (setq x 10)                              ; set x to 10
    (setq y 20)                              ; set y to 20
    (plus x y)                               ; returns 30
    
    (defmacro betterplus (num &rest nlist)   ; define a BETTERPLUS macro
      `(+ ,num ,@nlist))                     ;   which can take many numbers
    
    (betterplus 1)                           ; returns 1
    (betterplus 1 2 3)                       ; returns 6
    (betterplus 1 2 3 4 5)                   ; returns 15
    
    (defmacro atest (x &optional y &rest z)  ; define ATEST macro
      (princ " x: ") (princ x)               ;    \
      (princ " y: ") (princ y)               ;     print out the parameters
      (princ " z: ") (princ z) (terpri)      ;    /      (un-evaluated)
      `(print (+ ,x ,y ,@z)))                ;   add them together (eval'ed)
    
    (atest 1)                                ; prints - x: 1 y: NIL z: NIL
                                             ;   error: bad argument type
                                             ;   because (+ 1 NIL) isn't valid
    (atest 1 2)                              ; prints - x: 1 y: 2 z: NIL
                                             ;   returns 3
    (atest 1 2 3)                            ; prints - x: 1 y: 2 z: (3)
                                             ;   returns 6
    (atest 1 2 3 4 5)                        ; prints - x: 1 y: 2 z: (3 4 5)
                                             ;   returns 15
    (setq a 99)                              ; set A to 99
    (setq b 101)                             ; set B to 101
    (atest a b)                              ; prints - x: A y: B z: NIL
                                             ;   returns 200
    (atest a b 9 10 11)                      ; prints - x: A y: B z: (9 10 11)
                                             ;   returns 230
    

    Common Lisp: Common Lisp supports an optional documentation string as the first form in the 'body' of a 'defmacro' or defun. XLISP will accept this string as a valid form, but it will not do anything special with it.

    See the defmacro special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/write-float.htm0000644000175000000620000000471411512762341023416 0ustar stevestaffXLISP write-float Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    write-float


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (write-float float [stream [length]])
    float - the floating point number to write
    stream - the output stream [default is standard output]
    length - the length of the float in bytes [default is 4, legal values are -4, -8, 4, and 8]
    returns - the float

    Description

    The 'write-float' function writes a binary floating point number to an output stream, created by the open-binary function.

    Note: Integers and floats are assumed to be big-endian [high-order byte first] and signed, regardless of the platform. To read little-endian format, use a negative number for the length, e.g. '-4' indicates a 4-bytes, low-order byte first. The file should be opened in binary mode.

    Examples

    
    

    See also read-int, write-int, read-float, bigendianp, open-binary.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-lessp-s.htm0000644000175000000620000000742011512762341024050 0ustar stevestaffXLISP string< Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string<


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string< string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is less than string2 in ASCII ordering, NIL otherwise
    Note: case is significant with this function

    Description

    The 'string<' [string-less-than] function takes two string arguments. A non-NIL value is returned if 'string1' is less than 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char< [char-less-than] the corresponding character of 'string2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string< "a" "b")                ; returns 0
    (string< "a" "a")                ; returns NIL
    (string< "a" "A")                ; returns NIL
    (string< "A" "a")                ; returns 0
    (string< "abc" "abc ")           ; returns 3
    (string< "1234567" "1234qrst")   ; returns 4
    
    (string< "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars
                                                       ; returns NIL
    

    See the string< function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/number-not-equal.htm0000644000175000000620000000541311512762341024351 0ustar stevestaffXLISP /= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    /=


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (/= expr1 expr2 ...)
    exprN - a numeric expression
    returns -  T  if the results of comparing the expressions are all true, NIL otherwise

    Description

    The '/=' [not-equal] function takes an arbitrary number of numeric arguments. It checks to see if all the numeric arguments are different.  T  is returned if the arguments are numerically not equivalent, NIL is returned otherwise.

    Examples

    (/= 1 1)            => NIL
    (/= 1 2)            => T
    (/= 1 1.0)          => NIL
    (/= 1 2 3)          => T
    (/= 1 2 2)          => NIL
    (/= "a" "b")        => error: bad argument type
    (setq a 1 b 12.4)   => 12.4  ; set up A and B with values
    (/= a b)            => NIL
    

    See setq.

    XLISP Bug

    (/= 1 2 3)      => T  ; OK
    (/= 1 2 3 2 1)  => T  ; wrong
    

    This is only a problem for the '/=' function. The bug can be reproduced with Nyquist 3.03 in November 2010.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/unless.htm0000644000175000000620000000473311512762341022473 0ustar stevestaffXLISP unless Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    unless


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (unless test [expr ... ])
    test - an expression, NIL or non-NIL
    expr - expressions comprising a body of code
    returns - the value of the last expression or NIL

    Description

    The 'unless' special form executes the 'expr' forms if 'test' evaluates to a NIL value. If 'test' is NIL , the value of the last 'expr' is returned as the result. If 'test' is non-NIL , NIL is returned with none of 'expr' evaluated.

    Examples

    (unless NIL)                    ; returns NIL
    (unless T)                      ; returns NIL
    
    (unless NIL (print "hi") 'foo)  ; prints "hi"  returns FOO
    
    (unless (listp "a")
            (print "not a list"))   ; prints  "not a list"
                                    ; returns "not a list"
    

    See the unless special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/listp.htm0000644000175000000620000000651111512762341022311 0ustar stevestaffXLISP listp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    listp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (listp expr)
    expr - the expression to check
    returns -  T  if the value is a list or NIL , NIL otherwise

    Description

    The 'listp' predicate function checks if the 'expr' is a list.  T  is returned if 'expr' is a list or an empty list [the NIL value], NIL is returned otherwise.

    Examples

    (listp '(a b))                  ; returns T - list
    (listp nil)                     ; returns T - NIL
    (listp '(a . b))                ; returns T - dotted pair list
    
    (listp (lambda (x) (print x)))  ; returns NIL - closure - lambda
    (listp #(1 2 3))                ; returns NIL - array
    (listp *standard-output*)       ; returns NIL - stream
    (listp 1.2)                     ; returns NIL - float
    (listp #'quote)                 ; returns NIL - fsubr
    (listp 1)                       ; returns NIL - integer
    (listp object)                  ; returns NIL - object
    (listp "str")                   ; returns NIL - string
    (listp #'car)                   ; returns NIL - subr
    (listp 'a)                      ; returns NIL - symbol
    

    Note: NIL or '() is used in many places as a list-class or atom-class expression. Both atom and 'listp', when applied to NIL , return  T . If you wish to check for a non-empty list, use the consp predicate function.

    See the listp function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/peek.htm0000644000175000000620000000572011512762341022103 0ustar stevestaffXLISP peek Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    peek


    Type:   -   function (subr)
    Source:   -   xlsys.c

    Syntax

    (peek address)
    address - an integer expression
    returns - the value at the specified address as an integer

    Description

    The 'peek' function returns the internal memory value at the 'address'. The returned value is an integer.

    Examples

    (setq var 0)                    ; set up VAR with 0
    (address-of var)                ; returns 123224
    (address-of 'var)               ; returns 161922
    (peek (address-of var))         ; returns 83951616
    (peek (1+ (address-of var)))    ; returns 16777216
    (peek (+ 2 (address-of var)))   ; returns 0  <-- value of VAR
    (setq var 14)                   ; change the value to 14
    (peek (+ 2 (address-of var)))   ; returns 14
    (setq var 99)                   ; change the value to 99
    (peek (+ 2 (address-of var)))   ; returns 99
    

    Caution: Be careful when modifying the internal state of XLISP. If you have modified it, it would be a good idea to exit XLISP and re-enter before doing any work you really want to retain.

    Caution: It is possible to 'peek' and poke not just XLISP's memory put other parts of your computer's memory. Be very careful when doing this. Also, in some computers, just looking at a memory location can cause things to happen, I/O locations fall in this category.

    See the peek function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lambda-keyword-optional.htm0000644000175000000620000000747111512762341025711 0ustar stevestaffXLISP &optional Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    &optional


    Type:   -   keyword
    Source:   -   xleval.c

    Syntax

    &optional [opt-arg | (opt-arg [opt-value [supplied-p]])] ...
    opt-arg - optional argument
    opt-value - optional argument initialization value
    supplied-p - optional argument existence variable

    Description

    In XLISP, there are several times that you define a formal argument list for a body of code like defun , defmacro , :answer and lambda. All of the formal arguments that are defined are required to appear in the invocation of the defined function or operation. If there are any '&optional' arguments defined, they will be filled in order. If there are insufficient parameters for the '&optional' arguments, they will contain NIL , unless the arguments have an 'opt-value' initial value specified. The 'supplied-p' variable, if specified, will contain  T  if the 'opt-arg' was supplied by the function call and NIL if it was not supplied by the function call. This 'supplied-p' variable allows the programmer to test for an arguments existence. At the end of the function or operation execution, these local symbols and their values are are removed.

    Examples

    (defun foo                              ; define function FOO
      (a &optional b (c 1) )                ;   with some optional args
      (print a) (print b) (print c))
    (foo)                                   ; error: too few arguments
    (foo 1)                                 ; prints 1 NIL 1
    (foo 1 2)                               ; prints 1 2 1
    (foo 1 2 3)                             ; prints 1 2 3
    
    (defun fee                              ; define function FEE
      (a &optional (b 9 b-passed) )         ;   with some optional args
      (print a) (print b)
      (if b-passed (print "b was passed")
                   (print "b not passed")))
    (fee 1)                                 ; prints 1 9 "b not passed"
    (fee 1 2)                               ; prints 1 2 "b was passed"
    

    See the &optional keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-not-lessp-s.htm0000644000175000000620000000533111512762341024254 0ustar stevestaffXLISP char>= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char>=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char>= char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically non-increasing ASCII value, NIL otherwise
    Note: case is significant with this function

    Description

    The 'char>=' function tests if all character arguments are monotonically non-increasing.  T  is returned if the arguments are of monotonically non-increasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is greater than or equal to 'char2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than the characrer '#\A'.

    Examples

    (char>= #\a #\b)      => NIL
    (char>= #\b #\a)      => T
    (char>= #\c #\b #\a)  => T
    (char>= #\a #\a)      => T
    (char>= #\c #\a #\b)  => NIL
    (char>= #\A #\a)      => NIL
    (char>= #\a #\A)      => T
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/subst.htm0000644000175000000620000000733711512762341022325 0ustar stevestaffXLISP subst Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    subst


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (subst new-expr old-expr expr [{:test | :test-not} test])
    old-expr - the expression to search for
    new-expr - the expression to replace old-expr with
    expr - the expression to substitute within, an atom or list
    test - optional test function, default is eql
    returns - the expression with substitutions

    Description

    The 'subst' function searches through an 'expr' and replaces each of the 'old-expr' elements with the 'new-expr'. The 'expr' with the substitutions, if any, is returned. You may specify your own test with the ':test' and ':test-not' keywords followed by the 'test' you wish to perform.

    Examples

    (subst 'new 'old '(old mid dif))           ; returns (NEW MID DIF)
    (subst '(a) 'old '(old mid dif))           ; returns ((A) MID DIF)
    (subst "a" 'old '(old mid dif))            ; returns ("a" MID DIF)
    
    (defun mytest (x y) (princ x) (princ " ")  ; define a test function
                        (princ y) (terpri)     ; that prints the arguments
                        T )                    ; and always returns T
    
    (subst 'a 'b '(a b c d) :test 'mytest)     ; prints (A B C D) B   returns A
    
    (subst 'a 'b '(a b) :test-not 'mytest)     ; prints (A B) B
                                               ;        A B
                                               ;        (B) B
                                               ;        B B
                                               ;        NIL B    returns (A B)
    

    Note: The 'subst' function can work with a list or string as the 'expr' However, the default eql test does not work with lists or strings, only symbols and numbers. To make this work, you need to use the ':test' keyword along with equal for 'test'.

    Common Lisp: Common Lisp supports the use of the ':key' keyword which specifies a function that is applied to each element of 'expr' before it is tested. XLISP does not support this.

    See the subst function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/trace.htm0000644000175000000620000000625711512762341022263 0ustar stevestaffXLISP trace Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    trace


    Type:   -   function (subr)
    Source:   -   xlcont.c

    Syntax

    (trace function ... )
    function - an unquoted function
    returns - the trace list

    Description

    The 'trace' special form allows the tracing of user or system functions. 'trace' returns a list containing the current set of functions that are being traced. The 'function' does not have to be currently defined, it can be created as part of the execution. The trace output consists of entry and exit information.

    At entry and exit of a traced 'function', lines will be printed of the form:

    Entering: function, Argument list: arg-list
    Exiting: function, Value: return-value
    

    A list of all currently traced functions can be found in the *tracelist* system variable.

    Examples

    (defun foo (x) (print (car x)))  ; define FOO
    (trace 'foo)                     ; returns (FOO)
    (trace 'car)                     ; returns (CAR FOO)
    
    (foo '(a))                       ; Entering: FOO, Argument list: ((A))
                                     ;  Entering: CAR, Argument list: ((A))
                                     ;  Exiting: CAR, Value: A
                                     ; A
                                     ; Exiting: FOO, Value: A
                                     ; returns A
    

    Common Lisp: The XLISP 'trace' function does not support any keyword options, which Common Lisp allows.

    See the trace special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/clean-up.htm0000644000175000000620000000536111512762341022664 0ustar stevestaffXLISP clean-up Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    clean-up


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xldbug.c

    Syntax

    (clean-up)

    Description

    The 'clean-up' function aborts one level of the break loop. This is valid for breaks , errors and cerrors [continuable errors]. If 'clean-up' is evaluated while not in a break loop , an error is generated:

    error: not in a break loop
    

    This error does not cause XLISP to go into a break loop. 'clean-up' never actually returns a value.

    Examples

    (clean-up)     ; [back to previous break level]
    (break "out")  ; break: out
    (clean-up)     ; to exit out of break loop
    

    Note: With Nyquist, no error is generated if 'clean-up' is invoked when not in a break loop.

    Keystroke equivalent: In the IBM PC and MS-DOS versions of XLISP, a 'Ctrl-g' key sequence has the same effect as doing a (clean-up). On a Macintosh, this can be accomplished by a pull-down menu or a 'Command-g'. [I haven't tested this with Nyquist].

    See the clean-up function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/t.htm0000644000175000000620000000401111512762341021412 0ustar stevestaffXLISP t Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    t


    Type:   -   system constant
    Source:   -   xlinit.c

    Syntax

     t

    Description

    The T system constant is built into XLISP. T represents 'true', as oppossed to NIL , representing 'false'.

    Examples

    (setq myvar T)                     ; set MYVAR to True
    (setq myvar 'T)                    ; T and 'T both evaluate to T
    (if t (print "this will print")    ; if, then, else
          (print "this won't print"))
    

    Note: Be careful with the T value. It is possible to do a setq on T and set it to other values like NIL. Some operations will still return proper T or NIL values, but the system will be in a bad state.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/strcat.htm0000644000175000000620000000421411512762341022454 0ustar stevestaffXLISP strcat Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    strcat


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (strcat [string1 ... ])
    stringN - a string expression
    returns - the result of concatenating the strings

    Description

    The 'strcat' function returns the concatenation of a sequence of string expressions. If there are no strings, an empty string is returned.

    Examples

    (strcat)                     ; returns ""
    (strcat "a")                 ; returns "a"
    (strcat "a" "b")             ; returns "ab"
    (strcat "ab" "cd" "ef")      ; returns "abcdef"
    (strcat "f" "ire tr" "uck")  ; returns "fire truck"
    (strcat 1 2)                 ; error: bad argument type
    

    See the strcat function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/set.htm0000644000175000000620000000525011512762341021750 0ustar stevestaffXLISP set Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    set


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (set symbol expr)
    symbol - expression that evaluates to a symbol name [if the expression is quoted, no evaluation occurs]
    expr - an expression, which will be the new value
    returns - the new value

    Description

    The 'set' function evaluates 'symbol' and sets 'expr' as it's value. If the 'symbol' value is quoted via the quote special form or read-macro expansion, the 'symbol' is not evaluated. 'set' returns the value from 'expr' as it's result.

    Examples

    (set 'a 2)            ; sets symbol A to value 2
    (set 'value a)        ; sets symbol VALUE to value 2
    (print value)         ; show the value - prints 2
    
    (set 'name 'myvar)    ; set symbol NAME to value MYVAR
    (set name 12345)      ; set symbol which is the value
                          ;   of NAME (MYVAR) to 12345
    
    (print name)          ; prints MYVAR
    (print myvar)         ; prints 12345
    
    (set notsymbol 1)     ; error: unbound variable
    (set name notvalue)   ; error: unbound variable
    

    See the set function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-left-trim.htm0000644000175000000620000000530011512762341024360 0ustar stevestaffXLISP string-left-trim Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-left-trim


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-left-trim trim-stuff string)
    trim-stuff - a string expression
    string - a string expression
    returns - a trimed copy of the string

    Description

    The 'string-left-trim' function takes the 'trim-stuff' characters and removes them from the left end of the 'string'. The 'trim-stuff' characters are an un-ordered set of characters to be removed, so any character that occurs in 'trim-stuff' is removed if it appears in left portion of 'string'. A new string is created and returned as the result of this function.

    Examples

    (string-left-trim "." "....foo....")     ; returns "foo...."
    (string-left-trim "<>" "<<<<bar>>>>")    ; returns "bar>>>>"
    (string-left-trim "(.)" "..(12.34)..")   ; returns "12.34).."
    

    Common Lisp: Common Lisp also supports a list of characters as a valid 'trim-stuff' argument. An example:

    (string-trim '(#\Tab #\Newline) mystring)
    

    XLISP does not support non-string parameters. Porting from XLISP will be no problem, but modifications will be necessary if porting from Common Lisp code which uses a list of characters.

    See the string-left-trim function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/prog-star.htm0000644000175000000620000000726411512762341023102 0ustar stevestaffXLISP prog* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    prog*


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (prog* ([binding ... ]) [expr ... ])
    binding - a variable binding which is can take one of
    symbol
    (symbol init-expr)
    symbol - a symbol
    init-expr - an initialization expression for symbol
    expr - expressions comprising the body of the loop which may contain returns, gos or tags for go
    returns - NIL or the argument passed to the return function

    Description

    The 'prog*' special form is basically a 'block' construct that contains symbols with optional initializations and a block of code [expressions] to evaluate. The 'prog*' special form evaluates its initializations in sequential order as opposed to prog which does it in no specified order. The first form after the 'prog*' is the 'binding' form. It contains a series of 'symbols' or 'bindings'. The 'binding' is a 'symbol' followed by an initialization expression 'init-expr'. If there is no 'init-expr', the 'symbol' will be initialized to NIL. The order of execution of the bindings is sequential. If a return form is evaluated, its value will be returned. Otherwise, NIL is returned. When the 'prog*' is finished execution, the 'symbols' that were defined will no longer exist or retain their values.

    Examples

    (prog* (i j)                 ; PROG* with vars I and J
           (print i) (print j))  ; prints  NIL NIL  returns NIL
    
    (prog* ((i 1) (j 2))         ; PROG* with vars I and J
           (print i) (print j)
           (return (+ i j)))     ; prints 1 2  returns 3
    
    (prog* () (print "hello"))   ; prints "hello"  returns NIL
    
    (prog ((i 1) (j (+ i 1)))    ; PROG won't work due to order
          (print (+ i j)) )      ; error: unbound variable - I
    
    (prog* ((i 1) (j (+ i 1)))   ; PROG* will work due to order
           (print (+ i j)) )     ; prints 3  returns NIL
    

    See the prog* special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/numberp.htm0000644000175000000620000000467211512762341022634 0ustar stevestaffXLISP numberp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    numberp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (numberp expr)
    expr - the expression to check
    returns -  T  if the expression is a number, NIL otherwise

    Description

    The 'numberp' predicate function checks if an 'expr' is a number.  T  is returned if 'expr' is an integer or floating point number, NIL is returned otherwise.

    Examples

    (numberp 1)         ; returns T - integer
    (numberp 1.2)       ; returns T - float
    (numberp '1)        ; returns T - still an integer
    (numberp #x034)     ; returns T - the readmacro produces an integer
    
    (numberp 'a)        ; returns NIL - symbol
    (numberp #\a)       ; returns NIL - character
    (numberp NIL)       ; returns NIL - NIL
    (numberp #(0 1 2))  ; returns NIL - array
    

    See the numberp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/push.htm0000644000175000000620000000401111512762341022126 0ustar stevestaffXLISP push Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    push


    Type:   -   Lisp macro
    Source:   -   misc.lsp

    Syntax

    (push expr list)
    expr - an expression
    list - a list
    returns - the new value of list

    'push' is implemented as a Lisp macro:

    (defmacro push (val lis)
      `(setf ,lis (cons ,val ,lis)))
    

    Description

    The 'push' macro stores the value of the expression to the front of the list and returns the list.

    Examples

    (setq lst nil)  => NIL
    (push 1 lst)    => (1)
    lst             => (1)
    (push 2 lst)    => (2 1)
    lst             => (2 1)
    (push 3 lst)    => (3 2 1)
    lst             => (3 2 1)
    

    See setq. See also the pop macro.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/number-not-lessp.htm0000644000175000000620000000530211512762341024365 0ustar stevestaffXLISP >= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    >=


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (>= expr1 expr2 ...)
    exprN - a numeric expression
    returns -  T  if the results of comparing the expressions are all true, NIL otherwise

    Description

    The '>=' [greater-than-or-equal] function takes an arbitrary number of numeric arguments. It checks to see if all the numbers are monotonically non-increasing.  T  is returned if 'expr1' is the arguments are numerically, and monotonically non-increasing, NIL is returned otherwise. For two arguments, this has the effect of testing if 'expr1' is greater than or equal to 'expr2'.

    Examples

    (>= 1 2)            => NIL
    (>= 1 1)            => T
    (>= -1.5 -1.4)      => NIL
    (>= 3 2 1)          => T
    (>= 3 2 2)          => T
    (>= 3 2 3)          => NIL
    (>= "aa" "abc")     => error: bad argument type
    (setq a 12 b 13.9)  => 13.9  ; set up A and B with values
    (>= a b)            => NIL
    (>= b a)            => T
    

    See setq.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-not-greaterp-s.htm0000644000175000000620000000753011512762341025333 0ustar stevestaffXLISP string<= Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string<=


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string<= string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is less than or equal to string2 in ASCII ordering, NIL otherwise
    Note: case is significant with this function

    Description

    The 'string<=' [string-less-than-or-equal] function takes two string arguments. A non-NIL value is returned if 'string1' is less than or equal to 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char<= [char-less-than-or-equal] to the corresponding character of 'string2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string<= "a" "b")                ; returns 0
    (string<= "a" "a")                ; returns 1
    (string<= "a" "A")                ; returns NIL
    (string<= "A" "a")                ; returns 0
    (string<= "abc" "abc ")           ; returns 3
    (string<= "1234567" "1234qrst")   ; returns 4
    
    (string<= "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars
                                                        ; returns 7
    

    See the string<= function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/atan.htm0000644000175000000620000000372311512762341022103 0ustar stevestaffXLISP atan Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    atan


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (atan expr [expr2])
    expr - an integer or floating point expression
    expr2 - an optional divisor [default value is 1.0]
    returns - the arctangent of the division of expr and expr2

    Description

    The 'atan' function returns the arc tangent of the division of 'expr' and 'expr2'. The result is in radians.

    Examples

    (atan  0.0)  =>  0
    (atan  1.0)  =>  0.785398
    (atan -1.0)  => -0.785398
    (atan    0)  =>  0
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/gcd.htm0000644000175000000620000000432111512762341021710 0ustar stevestaffXLISP gcd Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    gcd


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (gcd [int ... ])
    int - an integer expression
    returns - the greatest common divisor

    Description

    The 'gcd' function returns the greatest common divisor of a series of integers. If no arguments are given, a zero is returned. If only one argument is given, the absolute value of the argument is returned. The successful result is always a positive integer.

    Examples

    (gcd 51 34)       ; returns 17
    (gcd 99 66 22)    ; returns 11
    (gcd -99 66 -33)  ; returns 33
    (gcd -14)         ; returns 14
    (gcd 0)           ; returns 0
    (gcd)             ; returns 0
    (gcd .2)          ; error: bad argument type - 0.2
    

    See the gcd function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/logior.htm0000644000175000000620000000516711512762341022457 0ustar stevestaffXLISP logior Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    logior


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (logior expr1 ... )
    exprN - an integer expression
    returns - the result of the Inclusive OR operation

    Description

    The 'logior' function returns the logical bitwise 'inclusive-or' of the list of expressions. If there is only one argument, it is returned unaltered. If there are two or more arguments, the 'logior' function performs the 'inclusive-or' successively applying the bitwise operation.

    Examples

    (logior 0 0)               ; returns 0
    (logior 0 1)               ; returns 1
    (logior 1 0)               ; returns 1
    (logior 1 1)               ; returns 1
            
    (logior 1 2 4 8 16 32 64)  ; returns 127
    (logior 5 #b010)           ; returns 7
    (logior 99 #x1FF)          ; returns 511
    (logior 99 #x400)          ; returns 1123
    

    Note: XLISP does not check when read-macro expansions like '#x0FF' are out of bounds. It gives no error message and will just truncate the number to the low-order bits that it can deal with [usually 32 bits or 8 hex digits].

    See the logior function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/flatsize.htm0000644000175000000620000000416311512762341023000 0ustar stevestaffXLISP flatsize Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    flatsize


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlprin.c

    Syntax

    (flatsize expr)
    expr - an expression
    returns - the length

    Description

    The 'flatsize' function determines the character length that would be printed if the 'expr' were printed using prin1. This means that the 'expr' would be printed without a new-line. If 'expr' is a string, it would be printed with quotes around the string. The print character length is returned as the result.

    Examples

    (flatsize 1234)          ; returns 4
    (flatsize '(a b c))      ; returns 7
    (flatsize "abcd")        ; returns 6
    (flatsize 'mybigsymbol)  ; returns 11
    

    See the flatsize function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/block.htm0000644000175000000620000000543611512762341022255 0ustar stevestaffXLISP block Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    block


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (block name [body ... ])
    name - an unevaluated symbol for the block name
    body - an arbitrary number of Lisp expressions
    returns - the value of the last expression

    Description

    The 'block' special form specifies a 'named block' construct. The last expression in 'body' will be returned by the 'block' construct as its result unless a return or return-from is executed within 'block'. The return exit will exit the nearest [inner-most] 'block'. The return-from exit will exit the specified 'block'.

    Examples

    (defun test ()
      (block outer         ; outer BLOCK
        (print "outer")
        (block inner       ; inner BLOCK
          (print "inner")
          (return-from outer "all done")
          (print "won't get here"))))
    
    > (test)
    "outer"     ; screen output of PRINT
    "inner"     ; screen output of PRINT
    "all done"  ; return value
    

    See defun, print, return-from.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/caar.htm0000644000175000000620000000575411512762341022074 0ustar stevestaffXLISP caar, cadr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    caar, cadr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (caar expr)
    (cadr expr)
    expr - a list expression
    returns - the result of the last car function

    Description

    The 'caar' and 'cadr' functions go through the list expression and perform a sequence of car or cdr operations. The sequence of operations is performed from right to left. So 'cadr' does a cdr on the expression, followed by a car. If at any point the list is NIL, then NIL is returned. If at any point a car operation is performed on an atom [as opposed to a list] an error is signalled:

    error: bad argument
    

    The 'cadr' function returns the same result as the second function.

    Examples

    (setq mylist '((1A 1B) (2A 2B) (3A 3B)))
    
    (caar mylist)  => 1A
    (cadr mylist)  => (2A 2B)
    
    (caar 'a)      => error: bad argument
    (caar nil)     => NIL
    

    Note: The 'c...r' functions are part of the historical Lisp functions. You may find it easier to work with the modern lisp functions like nth and nthcdr.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/min.htm0000644000175000000620000000423111512762341021736 0ustar stevestaffXLISP min Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    min


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (min expr1 ... )
    exprN - integer or floating point number/expression
    returns - the smallest number in the list of numbers/expressions

    Description

    The 'min' function returns the minimum [most negative or most nearly negative] numeric expression from the list of arguments.

    Examples

    (min 1)               ; returns 1
    (min 8 7 4 2)         ; returns 2
    (min 2 3 -1 -99)      ; returns -99
    (setq a '( 9 3 5 2))  ; make a numeric list - (9 3 5 2)
    (apply 'min a)        ; returns 2
    (apply #'min a)       ; returns 2
    (apply 'max a)        ; returns 9
    

    See the min function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-rslt.htm0000644000175000000620000000402711512762341023400 0ustar stevestaffXLISP *rslt* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *rslt*


    Type:   -   system variable
    Source:   -   not explicitely defined

    Syntax

    *rslt*

    Description

    When a function returns more than one value, the global Nyquist *rslt* variable is set to a list of the 'extra' values. This provides a make-shift version of the 'multiple-value-return' facility in Common Lisp.

    Examples

    (defun cl:values (&rest args)
      (setq *rslt* args)
      (first args))
    
    (values 1 2 3)  => 1
    *rslt*          => (1 2 3)
    

    See defun, first, rest, &rest, setq.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/rest.htm0000644000175000000620000000506611512762341022137 0ustar stevestaffXLISP rest Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    rest


    Type:   -   function (subr)
    Source:   -   xlinit.lsp

    Syntax

    (rest expr)
    expr - a list or list expression
    returns - expr with the first element removed

    Description

    The 'rest' function returns the remainder of a list or list expression after first element of the list is removed. If the list is NIL , NIL is returned.

    Examples

    (rest '(a b c))                         ; returns (B C)
    (rest '((a b) c d))                     ; returns (C D)
    (rest NIL)                              ; returns NIL
    (rest 'a)                               ; error: bad argument type
    (rest '(a))                             ; returns NIL
    
    (setq sisters '(virginia vicki cindy))  ; set up variable SISTERS
    (first sisters)                         ; returns VIRGINIA
    (rest sisters)                          ; returns (VICKI CINDY)
    

    Note: The 'rest' function is set to the same code as the cdr function.

    See the rest function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-nmacro.htm0000644000175000000620000000703111512762341024115 0ustar stevestaffXLISP :nmacro Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :nmacro


    Type:   -   keyword
    Source:   -   xlread.c

    Syntax

    (:nmacro . function)
    function - a function

    Description

    ':nmacro' is an entry that is used in the *readtable* system variable that contains XLISP's data structures relating to the processing of characters from the user [or files] and read-macro expansions. The existance of the ':nmacro' keyword means that the specified character is the start of a non-terminal read macro. For ':nmacro', the form of the *readtable* entry is a dotted pair like:

    (:nmacro . function)
    

    The 'function' can be a built-in read-macro function or a user defined lambda expression. The 'function' takes two parameters, an input stream specification, and an integer that is the character value. The 'function' should return NIL if the character is 'white-space' or a value consed with NIL to return the value. The 'function' will probably read additional characters from the input stream.

    Examples

    (defun look-at (table)                ; define a function to
      (dotimes (ch 127)                   ;   look in a table
        (prog ((entry (aref table ch)))   ;   and print out any
          (if (and (consp entry)          ;   :NMACRO entries
                   (equal (car entry)
                          ':nmacro))
              (princ (int-char ch)))))
      (terpri))
    (look-at *readtable*)                 ;  prints #
    

    Note: The system defines that the hash [#] character is a non-terminal. This is because the hash is used for a variety of 'read macro expansions' including function, an ASCII code, and hexadecimal numbers.

    Caution: If you experiment with *readtable* , it is useful to save the old value in a variable, so that you can restore the system state.

    See the :nmacro keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/subtraction.htm0000644000175000000620000000430211512762341023507 0ustar stevestaffXLISP − Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (- expr1 ...)
    exprN - integer or floating point number/expression
    returns - the result of the subtraction

    Description

    The '-' function subtracts one or more numbers from the first number given and returns the result. If there is only one number as an argument, it is negated.

    Examples

    (- 1)         => -1
    (- 1 2)       => -1
    (- 1 2 3)     => -4
    (- 1 2 3 4)   => -8
    
    > (print (- 1 2 (* 3.5 (/ 3.9 1.45))))
    -10.4138
    -10.4138
    

    See  * ,  / , print. XLISP first prints the value on the screen, the second number is the return value.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/alphanumericp.htm0000644000175000000620000000460511512762341024010 0ustar stevestaffXLISP alphanumericp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    alphanumericp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (alphanumericp char)
    char - a character expression
    returns -  T  if the character is alphabetic or a digit, NIL otherwise

    Description

    The 'alphanumericp' function checks if the 'char' expression is an alphabetic or a digit character. If 'char' is an alphabetic [either an upper or lower case] or a digit character,  T  is returned, otherwise NIL is returned. Note that XLISP is limited to ASCII characters, so there is no way to find out if an Unicode character with a char-code greater than ASCII 127 is alphanumeric or not.

    Examples

    (alphanumericp #\A)  => T
    (alphanumericp #\a)  => T
    (alphanumericp #\1)  => T
    (alphanumericp #\[)  => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/setdir.htm0000644000175000000620000000323711512762341022452 0ustar stevestaffXLISP setdir Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    setdir


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/win/msvc/winfun.c

    Syntax

    (setdir path) - set current directory
    path - the path of the new directory
    returns - the resulting full path or NIL if an error occurs

    Description

    The 'setdir' function sets current directory, e.g. (setdir ".") gets the current working directory.

    Examples

    
    

    See also listdir.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-applyhook.htm0000644000175000000620000000401011512762341024412 0ustar stevestaffXLISP *applyhook* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *applyhook*


    Type:   -   system variable
    Source:   -   xlglob.c (not implemented)

    Syntax

     *applyhook*

    Description

    *applyhook* is a system variable that exists and is initialized to NIL. It is a hook that is intended to contain a user function that is to be called whenever a function is applied to a list of arguments. It is not, however, implemented in XLISP 2.0, it only exists as a dummy hook.

    Examples

    *applyhook*  => NIL
    

    *applyhook* is often used to implement function stepping functionality in a debugger.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/oddp.htm0000644000175000000620000000532311512762341022104 0ustar stevestaffXLISP oddp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    oddp


    Type:   -   predicate function (subr)
    Source:   -   xlmath.c

    Syntax

    (oddp expr)
    expr - the integer numeric expression to check
    returns -  T  if the integer is odd, NIL otherwise

    Description

    The 'oddp' predicate function checks to see if the number 'expr' is odd.  T  is returned if the number is odd, NIL is returned otherwise.

    An error is generated if the 'expr' is not a numeric expression:

    error: bad argument type
    

    An error is generated if the 'expr' is a floating point number:

    error: bad floating point operation
    

    Zero is an even number.

    Examples

    (oddp 0)     ; returns NIL
    (oddp 1)     ; returns T
    (oddp 2)     ; returns NIL
    (oddp -1)    ; returns T
    (oddp -2)    ; returns NIL
    
    (oddp 13.0)  ; error: bad floating point operation
    (oddp 'a)    ; error: bad argument type
    (setq a 3)   ; set value of A to 3
    (oddp a)     ; returns T
    

    See the oddp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/rrandom.htm0000644000175000000620000000304711512762341022621 0ustar stevestaffXLISP rrandom Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    rrandom


    Type:   -   function (subr)
    Source:   -   xlmath.c, xlisp.c

    Syntax

    (rrandom)
    returns - a random floating point number between 0 and 1 inclusive

    Description

    The 'random' function returns a random floating point number between 0 and 1 inclusive.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/tagbody.htm0000644000175000000620000000515511512762341022612 0ustar stevestaffXLISP tagbody Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    tagbody


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (tagbody [expr ... ])
    expr - expressions comprising the body of the block which may contain gos or tags for go
    returns - NIL

    Description

    The 'tagbody' special form is basically a 'block' construct that contains a block of code [expressions] to evaluate. After the execution of the 'tagbody' 'exprs', NIL is returned. The 'tagbody' special form allows 'go-to' style branching within the 'block' construct via the go special form. To allow this, each 'expr' may be a tag or a form. The tag-symbol is the 'label' and must exist somewhere within the 'block' that the go occurs within.

    Examples

    (tagbody                   ; build the 'block'
       start (print "begin")   ; tag - start
             (GO end)
             (print "hello")   ; won't ever be reached
       end   (print "done"))   ; tag - END
                               ; prints  "begin" "done"
                               ; returns NIL
    

    See the tagbody special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/or.htm0000644000175000000620000000615511512762341021602 0ustar stevestaffXLISP or Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    or


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (or [expr1 ... ])
    exprN - an expression
    returns - NIL if all expressions evaluate to NIL , otherwise the value of the first non-NIL expression
    Note: evaluation of expressions stops after the first expression that does not evaluate to NIL

    Description

    The 'or' special form evaluates a sequence of expressions and returns the effect of a logical 'inclusive-or' operation on the expressions. If all of the expressions are NIL , NIL is returned as the result. Evaluation of the expressions will stop when an expression evaluates to something other than NIL , none of the subsequent expressions will be evaluated. If there are no expressions, 'or' returns NIL as its result.

    Examples

    (or NIL NIL NIL)                    ; returns NIL
    (or NIL T NIL)                      ; returns T
    (or NIL (princ "hi") (princ "ho"))  ; prints  hi  and returns "hi"
    (or T T T)                          ; returns T
    (or)                                ; returns NIL
    
    (setq a 5)  (setq b 6)              ; set up A and B
    (if (or (< a b) (< b a))            ; if
       (print "not equal")              ;   then
       (print "equal"))                 ;   else
                                        ; prints  "not equal"
    

    See the or special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/mapc.htm0000644000175000000620000000572411512762341022103 0ustar stevestaffXLISP mapc Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    mapc


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (mapc function list1 [list2 ... ])
    function - a function definition like a lambda form or a function name
    listN - a list or list expression
    returns - the first list of arguments

    Description

    The 'mapc' function applies the 'function' to the succesive cars of each of the lists 'listN'. Each of the lists supplies one of the arguments to 'function'. The 'mapc' function returns a list that is equivalent to the first list 'list1'. It's purpose is to perform operations that have side-effects. If the lists are of different lengths, the shortest list will determine the number of applications of 'function'.

    Examples

    (mapc 'princ '(hi there bob))         ; prints HITHEREBOB
                                          ;   returns (HI THERE BOB)
    
    (mapc '+ '(1 2 3) '(1 2 3))           ; returns (1 2 3)
                                          ;   there were no side effects
    
    (mapc (lambda (x y) (print (+ x y)))  ; define a function with side effects
          '(1 2 3) '(1 2 3))              ;   prints 2 4 6 
                                          ;   returns (1 2 3)
    

    Note: The use of the 'function' will work properly when it is a quoted symbol [the name of the function], an unquoted symbol, whose value is a function, or a closure object like a lambda form.

    See the mapc function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/truncate.htm0000644000175000000620000000414011512762341022777 0ustar stevestaffXLISP truncate Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    truncate


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (truncate expr)
    expr - integer or floating point number or expression
    returns - the result of truncating expr

    Description

    The 'truncate' function takes the 'expr' and truncates it to an integer value and returns this result.

    Examples

    (truncate 123.456)   ; returns 123
    (truncate -1.49)     ; returns -1
    (truncate -1.59)     ; returns -1
    (truncate 123)       ; returns 123
    (truncate 123.999)   ; returns 123
    

    Common Lisp: Common LISP allows an optional division parameter, which XLISP does not support.

    See the truncate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/acos.htm0000644000175000000620000000530511512762341022103 0ustar stevestaffXLISP acos Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    acos


    Type:   -   Lisp function (closure)
    Source:   -  

    Syntax

    (acos flonum)
    flonum - an integer or floating point expression
    returns - the arc-cosine of the number

    Note: the 'acos' function is not implemented in Nyquist. Here is a Lisp implementation of 'acos', using the atan function:

    (defun acos (x)
      (cond ((not (numberp x)) (error "bad argument type" x))
            ((= x 1) 0.0)
            ((= x -1) pi)
            ((< -1 x 1) (+ (atan (/ (- x) (sqrt (1+ (* x (- (float x))))))) (/ pi 2.0)))
            (t (error "argument out of range" x))))
    

    Description

    The 'acos' function returns the arc-cosine of an integer or floating point expression. The result is a floating point number in radians. If the argument is less than -1 or greater than +1, the arc-cosine is a complex number. Complex numbers are not available in XLISP. In this case the 'acos' function signals an 'argument out of range' error.

    Examples

    (acos 0.0)   => 1.5708
    (acos 1.0)   => 0.0
    (acos -1.0)  => 3.14159
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/list.htm0000644000175000000620000000437411512762341022136 0ustar stevestaffXLISP list Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    list


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (list [expr1 ... ])
    exprN - an expression
    returns - the new list

    Description

    The 'list' function takes the expressions and constructs a list out of them. This constructed list is returned.

    Examples

    (list)                           ; returns NIL
    (list nil)                       ; returns (NIL)
    (list 'a)                        ; returns (A)
    (list 'a 'b)                     ; returns (A B)
    (list 'a 'b 'c)                  ; returns (A B C)
    (list 'a 'b nil)                 ; returns (A B NIL)
    (list '(a b) '(c d) '( (e f) ))  ; returns ((A B) (C D) ((E F)))
    (list (+ 1 2) (+ 3 4))           ; returns (3 7)
    

    See the list function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/princ.htm0000644000175000000620000000707111512762341022273 0ustar stevestaffXLISP princ Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    princ


    Type:   -   function (subr)
    Source:   -   xlfio.c, xlprin.c

    Syntax

    (princ expr [dest])
    expr - an expression
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - the expression

    Description

    The 'princ' function prints the 'expr' to the specified 'destination'. The 'expr' is printed without a 'newline' character. If 'expr' is a string, it will not be printed with quotes around the string. The 'expr' is returned as the result. The 'destination' may be a file pointer or a stream. If there is no 'destination', *standard-output* is the default. The terpri function is used to terminate the print lines produced.

    Examples

    (princ 'a)                              ; prints A     without #\Newline
    (princ '(a b))                          ; prints (A B) without #\Newline
    (princ 99)                              ; prints 99    without #\Newline
    (princ "hi")                            ; prints hi    without #\Newline
    
    (setq f (open "f" :direction :output))  ; create file
    (princ "hi" f)                          ; returns "hi"
    (princ 727 f)                           ; returns 727
    (princ "ho" f)                          ; returns "ho"
    (close f)                               ; file contains hi727ho
    

    Common Lisp: Common Lisp specifies that 'pprint' with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the princ function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/error.htm0000644000175000000620000001350611512762341022311 0ustar stevestaffXLISP error Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    error, cerror


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xldbug.c

    Syntax

    (error err-msg [arg])
    err-msg - a string expression for the error message
    arg - an optional argument expression, printed after the error message
    returns - never returns
    (cerror cont-msg err-msg [arg])
    cont-msg - a string expression for the continue message
    err-msg - a string expression for the error message
    arg - an optional argument expression, printed after the error message
    returns - NIL when continued from the Break Loop

    Description

    The 'error' function allows the generation of a non-correctable error. A non-correctable error requires evaluation of a clean-up or top-level function from within the XLISP Break Loop to return to normal execution. The form of the message generated is:

    error: err-msg - arg
    

    If a continue function is evaluated within the Break Loop, then a an error message is generated:

    error: this error can't be continued
    

    There is no return from the 'error' function.

    The 'cerror' function allows the generation of a correctable error. A correctable error can be corrected by some action within the XLISP Break Loop. The form of the message generated is:

    error: err-msg - arg
    if continued: cont-msg
    

    In the Break Loop, forms can be evaluated to correct the error. If a continue function is evaluated within the Break Loop, then NIL is returned from 'cerror'. If desired, the clean-up and top-level forms may be evaluated to abort out of the Break Loop.

    Note: The *breakenable* variable needs to be non-NIL for 'error', 'cerror' and system errors to be caught by the Nyquist/XLISP Break Loop.

    Examples

    Example of a non-correctable error:

    > (error "invalid argument" "arg")
    error: invalid argument - "arg"
    
    1> (continue)   ; the 1 before the > indicates a break loop
    error: this error can't be continued
    
    1> (clean-up)
    [ back to previous break level ]
    
    >               ; no break loop any longer
    

    Example of system generated correctable error:

    > (symbol-value 'f)
    error: unbound variable - F
    if continued: try evaluating symbol again
    
    1> (setq f 123)   ; the 1 before the > indicates a break loop
    123               ; return value of (setq f 123)
    
    1> (continue)
    123               ; return value of (symbol-value 'f)
    
    >                 ; no break loop any longer
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/interpolate.htm0000644000175000000620000000377611512762341023516 0ustar stevestaffXLISP interpolate Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    interpolate


    Type:   -   Lisp function (closure)
    Source:   -   xm.lsp

    Syntax

    (interpolate x x1 y1 x2 y2)
    x, x1, y1, x2, y2 - integer or floating point numbers
    returns - the 'y' value corresponding to 'x'

    In Nyquist, 'interpolate' is implemented as a Lisp function:

    (defun interpolate (x x1 y1 x2 y2)
      (cond ((= x1 x2) x1)
            (t (+ y1 (* (- x x1) (/ (- y2 y1) (- x2 (float x1))))))))
    

    Description

    The 'interpolate' function linearly interpolates [or extrapolates] between points (x1, y1) and (x2, y2) to compute the 'y' value corresponding to 'x'.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/log.htm0000644000175000000620000000312311512762341021733 0ustar stevestaffXLISP log Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    log


    Type:   -   function (subr)
    Source:   -   sndfnint.c, sound.h

    Syntax

    (log number)
    number - a floating-point number
    returns - the natural logarithm of number

    Description

    The 'log' function computes the natural logarithm of a floating-point number and returns the result.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lognot.htm0000644000175000000620000000454311512762341022463 0ustar stevestaffXLISP lognot Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    lognot


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (lognot expr)
    expr - an integer expression
    returns - the bitwise inversion of number

    Description

    The 'lognot' function returns the logical bitwise inversion of the expression.

    Examples

    (lognot 255)                 ; returns -256
    (lognot #xffff0000)          ; returns 65535
    (lognot #x00000000)          ; returns -1
    (lognot 1)                   ; returns -2
    
    (logand (lognot 256) 65535)  ; returns 65279
    (lognot #xFFFFFFFE)          ; returns 1
    (lognot #xFFFFFFFC)          ; returns 3
    

    Note: XLISP does not check when read-macro expansions like '#x0FF' are out of bounds. It gives no error message and will just truncate the number to the low-order bits that it can deal with [usually 32 bits or 8 hex digits].

    See the lognot function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/symbol-function.htm0000644000175000000620000000332711512762341024310 0ustar stevestaffXLISP symbol-name Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    symbol-function


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (symbol-function symbol)
    symbol - an expression that evaluates to a symbol name
    returns - the symbol's functional value

    Description

    The 'symbol-function' function ... [this page was missing in the original reference and still needs to be written].

    Examples

    
    

    See the symbol-function function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/logand.htm0000644000175000000620000000505211512762341022421 0ustar stevestaffXLISP logand Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    logand


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (logand expr1 ... )
    expr - an integer expression
    returns - the result of the AND operation

    Description

    The 'logand' function returns the logical bitwise 'and' of the list of expressions. If there is only one argument, it is returned unaltered. If there are two or more arguments, the 'logand' function performs the logical and operation successively applying the bitwise operation.

    Examples

    (logand 0 0)         ; returns 0
    (logand 0 1)         ; returns 0
    (logand 1 0)         ; returns 0
    (logand 1 1)         ; returns 1
    (logand 55 #x0F)     ; returns 7
    (logand 7 #b0011)    ; returns 3
    (logand 1 2 4 8 16)  ; returns 0
    (logand 15 7 3)      ; returns 3
    

    Note: XLISP does not check when read-macro expansions like '#x0FF' are out of bounds. It gives no error message and will just truncate the number to the low-order bits that it can deal with [usually 32 bits or 8 hex digits].

    See the logand function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/union.htm0000644000175000000620000000377211512762341022314 0ustar stevestaffXLISP union Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    union


    Type:   -   Lisp function (closure)
    Source:   -   xm.lsp

    Syntax

    (union list1 list2)
    listN - a list of symbols or numbers
    returns - the union of list1 and list2

    In Nyquist, 'union' is implemented as a Lisp function:

    (defun union (a b)
      (let (result)
        (dolist (elem a)
          (if (not (member elem result)) (push elem result)))
        (dolist (elem b)
          (if (not (member elem result)) (push elem result)))
        result))
    

    Description

    The 'union' function computes the union of two lists. The result is a list containing all elements of both lists, where every element appears exactly once.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/dotimes.htm0000644000175000000620000000670211512762341022624 0ustar stevestaffXLISP dotimes Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    dotimes


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (dotimes (symbol end-expr [result]) [expr ... ])
    symbol - a symbol
    end-expr - an integer expression
    result - an optional expression for the returned result
    expr - expressions comprising the body of the loop which may contain returns, gos or tags for go
    returns - the return value of the result expression or NIL

    Description

    The 'dotimes' special form is basically a 'for' looping construct that contains a loop 'symbol', an 'end-expr' to specify the final value for 'symbol', an optional 'return' value and a block of code [expressions] to evaluate. The sequence of execution is:

      symbol := 0
      while  symbol value is not equal to end-expr value
        loop code execution
        symbol := symbol + 1
      end-while
      return result
    

    The main loop 'symbol' will take on successive values from zero to ('end-expr' - 1). The 'dotimes' form will go through and create and initialize the 'symbol' to zero. After execution of the loop 'exprs', the 'symbol' value is incremented. This continues until the 'symbol' value is equal to 'end-expr'. The value of the 'result' expression is evaluated and returned. If no 'result' is specified, NIL is returned. When the 'dotimes' is finished execution, the 'symbol' that was defined will no longer exist or retain its value. If the 'end-expr' is zero or less, then there will be no execution of the loop body's code.

    Examples

    (dotimes (i 4 "done") (princ i))  ; prints 0123 returns "done"
    (dotimes (i 4) (princ i))         ; prints 0123 returns NIL
    (dotimes (i 1) (princ i))         ; prints 0    returns NIL
    (dotimes (i 0) (princ i))         ; returns NIL
    (dotimes (i -9) (princ i))        ; returns NIL
    

    See the dotimes special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/and.htm0000644000175000000620000000760411512762341021724 0ustar stevestaffXLISP and Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    and


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (and [expr1 ... ])
    exprN - an expression
    returns - NIL if any expression evaluates to NIL , otherwise the value of the last expression
    Note: evaluation of expressions stops after the first expression that evaluates to NIL

    Description

    The 'and' special form evaluates a sequence of expressions and returns the effect of a logical AND on the expressions. If, at any point, an expression is NIL, then NIL is returned as the result of the 'and' function. If all of the expressions have a non-NIL value, the value of the last expression is returned as the result. Evaluation of the expressions will stop when an expression evaluates to NIL, none of the subsequent expressions will be evaluated. If there are no expressions, then 'and' returns  T  as its result.

    Examples

    (and t t t)  => T
    (and nil t)  => NIL
    (and t nil)  => NIL
    (and)        => T
    

    Some more practical examples:

    > (and T "boo" "hiss" T "rah")
    "rah"    ; return value of AND
    
    > (and (princ "hi") NIL (princ "ho"))
    hi       ; prints "hi"
    NIL      ; return value of AND
    
    See princ.
    > (setq a 5 b 6)                 ; set up A and B
    6                                ; return value of SETQ
     
    > (if (and (numberp a)           ; if A is a number
               (numberp b)           ; and B is a number
               (< a b))              ; and A < B
        (print "A is less than B")   ; then do this
        (print "error"))             ; else do this
    "A is less than B"               ; screen output of PRINT
    "A is less than B"               ; return value of IF
    

    See  < ,  if , print, setq.

    See also:

      Back to Top


    XLISP > XLISP 2.0  -  Contents  -  Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/boundp.htm0000644000175000000620000000643511512762341022452 0ustar stevestaffXLISP boundp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    boundp


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (boundp symbol)
    symbol - a symbol expression
    returns -  T  if a value is bound to the symbol, NIL otherwise

    Description

    The 'boundp' predicate function tests if 'symbol' evaluates to a symbol in the *obarray* with a value bound to it.  T  is returned if 'symbol' has a value, NIL is returned otherwise. Note that 'boundp' does not test if local let variables, or class or instance variables exist.

    Examples

    (setq a 1)            => 1    ; create a variable A in the *OBARRAY*
    (boundp 'a)           => T    ; variable A has a value 1
    
    (let ((b 'value))
      (boundp b))         => NIL  ; BOUNDP does NOT test LET bindings
    
    (defun foo (x)                ; create a function FOO in the *OBARRAY*
      (print x))          => FOO
    
    (boundp 'foo)         => NIL  ; FOO is not a variable
    
    (print myvar)         => error: unbound variable - MYVAR
    (boundp 'myvar)       => NIL
    
    (setq myvar 'abc)             ; give MYVAR a value
    (boundp 'myvar)       => T
    

    Note that 'symbol' is a symbol expression. This means that 'symbol' is evaluated and the return value is tested:

    (setq myvar 'qq)              ; MYVAR evaluates to QQ
    (boundp myvar)        => NIL  ; but QQ has no value yet
    
    (setq qq 'new-value)          ; give QQ a value
    (boundp myvar)        => T
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-evalhook.htm0000644000175000000620000001163711512762341024231 0ustar stevestaffXLISP *evalhook* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *evalhook*


    Type:   -   system variable
    Source:   -   xleval.c

    Syntax

     *evalhook*

    Description

    *evalhook* is a system variable whose value is user code that will intercept evaluations either through normal system evaluation or through calls to evalhook. The default value for *evalhook* is NIL , which specifies to use the built in system evaluator. If *evalhook* is non-NIL , the routine is called with expression and environment parameters. If the environment argument is NIL , then the the current global environment is used. The environment, if non-NIL , is a structure composed of dotted pairs constructed of the symbol and its value which have the form:

    (((sym1 . val1) (sym2 . val2) ... )))
    

    Examples

    (defun myeval (exp env)           ; define MYEVAL routine
      (princ "exp: ") (print exp)
      (princ "env: ") (print env)
      (evalhook exp #'myeval NIL env))
    
    (defun foo (a) (+ a a))           ; create simple function
    (setq *evalhook* #'myeval)        ; and install MYEVAL as hook
    
    (foo 1)                           ; prints exp: (FOO 1) env:NIL
                                      ;        exp: 1       env:NIL
                                      ;        exp: (+ A A) env:((((A . 1))))
                                      ;        exp: A       env:((((A . 1))))
                                      ;        exp: A       env:((((A . 1))))
                                      ; returns 2
    
    (top-level)                       ; to clean up *evalhook*
    

    Note: The evalhook function and *evalhook* system variable are very useful in the construction of debugging facilities within XLISP. The trace and untrace functions use evalhook and *evalhook* to implement their functionality. The other useful aspect of evalhook and *evalhook* is to help in understanding how XLISP works to see the expressions, their environment and how they are evaluated.

    Caution: Be careful when using *evalhook* and evalhook. If you put in a bad definition into *evalhook*, you might not be able to do anything and will need to exit XLISP.

    Unusual behaviour: The evalhook function and *evalhook* system variable, by their nature, cause some unusual things to happen. After you have set *evalhook* to some non-NIL value, your function will be called. However, when you are all done and set *evalhook* to NIL or some other new routine, it will never be set. This is because the evalhook function [in the 'xlbfun.c' source file] saves the old value of *evalhook* before calling your routine, and then restores it after the evaluation. The mechanism to reset *evalhook* is to execute the top-level function, which sets *evalhook* to NIL.

    See the *evalhook* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/lambda.htm0000644000175000000620000001036611512762341022401 0ustar stevestaffXLISP lambda Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    lambda


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (lambda arg-list [body])
    arg-list - a list of the formal arguments to the function of the form:
    ([arg1 ... ]
     [&optional oarg1 ... ]
     [&rest rarg]
     [&key ... ]
     [&aux aux1 ... ])
    body - a series of LISP forms (expressions) that are executed in order
    returns - the function closure

    Description

    The LAMBDA special form returns a function definition [an executable function] that has no name. All of the 'argN' formal arguments that are defined are required to appear in a call to the defined function. If there are any &optional arguments defined, they will be filled in order. If there is a &rest argument defined, and all the required formal arguments and &optional arguments are filled, any and all further parameters will be passed into the function via the 'rarg' argument. Note that there can be only one 'rarg' argument for &rest. If there are insufficient parameters for any of the &optional or &rest arguments, they will contain NIL. The &aux variables are a mechanism for you to define variables local to the function definition. At the end of the function execution, these local symbols and their values are are removed.

    Read also the chapter about lambda lists in the XLISP 2.0 manual.

    Examples

    (funcall (lambda (a b) (* a b)) 4 8 )  ; evaluate a lambda function
                                           ;   returns 32
    
    (funcall (lambda '(a b) (+ a b)) 1 2)  ; evaluate another function
                                           ;   returns 3
    
    (funcall (lambda (a b)                 ; evaluate a more complex function
                (print "a no-name fnc")    ;   prints "a no-name fnc"
                (* a b)) 3 8)              ;   and returns 24
    

    Note: Using a setq on a 'lambda' expression is not the same as a defun. A setq on a 'lambda' will give the variable the value of the 'lambda' closure. This does not mean that the variable name can be used as a function.

    See the lambda special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-tracenable.htm0000644000175000000620000001004611512762341024512 0ustar stevestaffXLISP *tracenable* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *tracenable*


    Type:   -   system variable
    Source:   -   xlinit.c, xldbug.c

    Syntax

     *tracenable*

    Description

    The *tracenable* system variable controls whether or not the break loop prints any back trace information on entry to the break loop. If *tracenable* is NIL , then there will be no information printed on entry to the break loop. If *tracenable* is non-NIL , then information will be printed. The 'init.lsp' initialization file sets *tracenable* usually to NIL , which suppresses the printing.

    Examples

    (defun foo (x) (fee x))   ; define FOO
    (defun fee (y) (break))   ; define FEE
    (setq *tracenable* T)     ; enable the back trace
    (setq *tracelimit* NIL)   ; show all the entries
    
    (foo 5)                   ; break: **BREAK**
                              ; prints  Function:#<Subr-BREAK...>
                              ;         Function:#<Closure-FEE...>
                              ;         Arguments:
                              ;           5
                              ;         Function:#<Closure-FOO...>
                              ;         Arguments:
                              ;           5
    
    (clean-up)                ; from break loop
    (setq *tracelimit* 2)     ; show only 2 entries
    
    (foo 5)                   ; break: **BREAK**
                              ; prints  Function:#<Subr-BREAK...>
                              ;         Function:#<Closure-FEE...>
                              ;         Arguments:
                              ;           5
    
    (clean-up)                ; from break loop
    

    Note: *tracenable* and *tracelimit* system variables have to do with back trace information at entry to a break loop and are not related to the trace and untrace functions.

    See the *tracenable* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/quote.htm0000644000175000000620000000544611512762341022321 0ustar stevestaffXLISP quote Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    quote


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (quote expr)
    expr - an expression
    returns - the unevaluated expression

    Description

    The 'quote' function returns the 'expr' unevaluated.

    Examples

    my-var                    ; error: unbound variable
    (quote my-var)            ; returns MY-VAR
    my-var                    ; still error: unbound variable
    (set (quote my-var) 111)  ; give MY-VAR a value, make it exist
    my-var                    ; returns 111
    (quote my-var)            ; returns MY-VAR
    
    ;; Same as above but using the ' read macro for quote
    
    new-var                   ; error: unbound variable
    'new-var                  ; returns NEW-VAR
    new-var                   ; still error: unbound variable
    (setq new-var 222)        ; give NEW-VAR a value, make it exist
    new-var                   ; returns 222
    'new-var                  ; returns NEW-VAR
    

    Read macro: XLISP supports the read macro of a single quote as a short-hand method of writing the 'quote' function.

    See the quote special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/setup-console.htm0000644000175000000620000000420111512762341023750 0ustar stevestaffXLISP setup-console Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    setup-console


    Type:   -   function (subr)
    Source:   -   sys/unix/osstuff.c, sys/mac/macstuff.c, sys/win/msvc/winfun.c

    Syntax

    (setup-console)
    returns - NIL

    Description

    The 'setup-console' function sets the default console attributes.

    Note: Under Windows, Nyquist normally starts up in a medium-sized console window with black text and a white background, with a window title of 'Nyquist'. This is normally accomplished by calling 'setup-console' in 'system.lsp'. In Nyquist, you can avoid this behavior by setting *setup-console* to NIL in your 'init.lsp' file. If 'setup-console' is not called, Nyquist uses standard input and output as is. This is what you want if you are running Nyquist inside of emacs, for example.

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/delete.htm0000644000175000000620000000722411512762341022422 0ustar stevestaffXLISP delete Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    delete


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (delete expr list [{:test | :test-not} test])
    expr - the expression to delete from list
    list - the list to destructively modify
    test - optional test function (default is eql)
    returns - the list with the matching expressions deleted

    Description

    The 'delete' function destructively modifies the 'list' by removing the 'expr'. The destructive aspect of this operation means that the actual symbol value is used in the list-modifying operations, not a copy. If 'expr' appears multiple times in the 'list', all occurances will be removed.

    'list' must evaluate to a valid list. An atom for 'list' will result in an error:

    error: bad argument type
    

    Having NIL for 'list' will return a NIL as the result. You may specify your own test with the ':test' and ':test-not' keywords.

    Examples

    (delete 'b NIL)                          ; returns NIL
    (delete 'b '(a b b c b))                 ; returns (A C)
    (setq a '(1 2 3)) (setq b a)             ; set up A and B
    (delete '2 a)                            ; returns (1 3)
    (print a)                                ; prints (1 3)    A IS MODIFIED!
    (print b)                                ; prints (1 3)    B IS MODIFIED!
    (delete '(b) '((a)(b)(c)))               ; returns ((A) (B) (C))
                                             ;   EQL doesn't work on lists
    (delete '(b) '((a)(b)(c)) :test 'equal)  ; returns ((A) (C))
    

    Note: The 'delete' function can work with a list or string as the 'expr'. However, the default eql test does not work with lists or strings, only symbols and numbers. To make this work, you need to use the ':test' keyword along with equal for 'test'.

    Common Lisp: XLISP does not support the ':from-end', ':start', ':end', ':count' and ':key' keywords which Common Lisp does.

    See the delete function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/decrement.htm0000644000175000000620000000350711512762341023126 0ustar stevestaffXLISP 1- Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    1−


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (1- expr)
    expr - integer or floating point number/expression
    returns - the number minus one

    Description

    The '1-' [decrement] function subtracts one from a number and returns the result.

    Examples

    (1- 1)     => 0
    (1- 99.6)  => 98.6
    (1- 1 2)   => error: too many arguments
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/null.htm0000644000175000000620000000471311512762341022132 0ustar stevestaffXLISP null Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    null


    Type:   -   predicate function (subr)
    Source:   -   xlbfun.c

    Syntax

    (null expr)
    expr - the expression to check
    returns -  T  if the list is empty, NIL otherwise

    Description

    The 'null' predicate function checks 'expr' for an empty list.  T  is returned if the list is empty, NIL is returned otherwise. The 'expr' does not have to be a valid list, but if it is not a list then NIL is returned as the result.

    Examples

    (null '())     ; returns T - empty list
    (null ())      ; returns T - still empty
    (setq a NIL)   ; set up a variable
    (null a)       ; returns T - value = empty list
    
    (null "a")     ; returns NIL - not a list
    (null 'a)      ; returns NIL - not a list
    

    Note: The 'null' predicate function is the same function as the not predicate function.

    See the null predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/append.htm0000644000175000000620000000513311512762341022424 0ustar stevestaffXLISP append Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    append


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (append [expr ... ])
    expr - a list or list expression
    returns - the new list

    Description

    The 'append' function takes an arbitrary number of lists and splices them together into a single list. This single list is returned. If an empty list NIL is appended, it has no effect, it does not appear in the final list. Remember that '(nil) is not an empty list. If a list is appended to an atom, it also has no effect and the atom will not appear in the final list.

    Examples

    (append)                            => NIL
    (append 'a 'b)                      => B
    (append '(a) '(b))                  => (A B)
    (append 'a '(b))                    => (B)
    (append '(a) 'b)                    => (A . B)
    (append '(a) nil)                   => (A)
    (append (list 'a 'b) (list 'c 'd))  => (A B C D)
    (append '(a (b)) '(c (d)))          => (A (B) C (D))
    (append '(a) nil nil nil '(b))      => (A B)
    (append '(a) '(nil) '(b))           => (A NIL B)
    

    Note: If a list is appended to an atom, XLISP signals no error, the atom just disappears!

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/make-string-input-stream.htm0000644000175000000620000000650311512762341026026 0ustar stevestaffXLISP make-string-input-stream Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    make-string-input-stream


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (make-string-input-stream string [start-pos [end-pos]])
    string - a string expression
    start-pos - an optional numeric expression, default value is '0' [the first character of the string]
    end-pos - an optional numeric expression, default value is the length of the string
    returns - an unnamed stream that reads from the string

    Description

    The 'make-string-input-stream' function creates an unnamed stream from the 'string' expression. The stream can then be used as any other stream object. The optional 'start-pos' expression specifies the starting offset of the 'string' expression. A 'start-pos' of '0' will start with the beginning of the 'string'. The optional 'end-pos' expression specifies the ending offset of the 'string' expression. A 'end-pos' of 4 will make the fourth character the last in the stream. If the function is successful, it returns the unnamed stream object. If the string is empty, an unnamed stream is still returned. Error conditions include 'start-pos' and 'end-pos' being out of bounds.

    Examples

    (make-string-input-stream "abcdefgh")           ; returns #<Unnamed-Stream: #277e2>
    (read (make-string-input-stream "123456"))      ; returns 123456
    (read (make-string-input-stream "123456" 1))    ; returns 23456
    (read (make-string-input-stream "123456" 1 3))  ; returns 23
    (read (make-string-input-stream "123" 0))       ; returns 123
    (read (make-string-input-stream "123" 0 3))     ; returns 123
    (read (make-string-input-stream "123" 2 1))     ; returns NIL
    (read (make-string-input-stream "123" 0 4))     ; error: string index out of bounds - 4
    

    See the make-string-input-stream function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/prog.htm0000644000175000000620000000662711512762341022135 0ustar stevestaffXLISP prog Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    prog


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (prog ([binding ... ]) [expr ... ])
    binding - a variable binding which is can take one of
    symbol
    (symbol init-expr)
    symbol - a symbol
    init-expr - an initialization expression for symbol
    expr - expressions comprising the body of the loop which may contain returns, gos or tags for go
    returns - NIL or the argument passed to the return function

    Description

    The 'prog' special form is basically a 'block' construct that contains symbols with optional initializations and a block of code [expressions] to evaluate. The 'prog' special form evaluates its initializations in no specified order, as opposed to prog* which does it sequential order. The first form after the 'prog' is the 'binding' form. It contains a series of 'symbols' or 'bindings'. The 'binding' is a 'symbol' followed by an initialization expression 'init-expr'. If there is no 'init-expr', the 'symbol' will be initialized to NIL. There is no specification as to the order of execution of the bindings or the step expressions, except that they happen all together. If a return form is evaluated, its value will be returned. Otherwise, NIL is returned. When 'prog' is finished execution, the 'symbols' that were defined will no longer exist or retain their values.

    Examples

    (prog () (print "hello"))   ; prints "hello"  returns NIL
    
    (prog (i j)                 ; PROG with vars I and J
          (print i) (print j))  ; prints NIL NIL  returns NIL
    
    (prog ((i 1) (j 2))         ; PROG with vars I and J
          (print i) (print j)
          (return (+ i j)))     ; prints 1 2  returns 3
    

    See the prog special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/both-case-p.htm0000644000175000000620000000460411512762341023261 0ustar stevestaffXLISP both-case-p Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    both-case-p


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (both-case-p char)
    char - a character expression
    returns -  T  if the character is alphabetic, NIL otherwise

    Description

    The 'both-case-p' predicate function checks if the 'char' expression evaluates to an alphabetic character. If 'char' evaluates to an alphabetic [either an upper or lower case] character  T  is returned, otherwise NIL is returned. Note that XLISP is limited to ASCII characters, so there is no way to find out if an Unicode character is 'both-case-p' if the char-code is greater than 127.

    Examples

    (both-case-p #\A)  => T
    (both-case-p #\a)  => T
    (both-case-p #\1)  => NIL
    (both-case-p #\[)  => NIL
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/fourth.htm0000644000175000000620000000477411512762341022476 0ustar stevestaffXLISP fourth Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    fourth


    Type:   -   function (subr)
    Source:   -   xlinit.c

    Syntax

    (fourth expr)
    expr - a list or list expression
    returns - the fourth element of the list

    Description

    The 'fourth' function returns the fourth element of a list or list expression. If the list is NIL , NIL is returned.

    Examples

    (fourth '(1 2 3 4 5))                    ; returns 4
    (fourth NIL)                             ; returns NIL
    (setq kids '(junie vickie cindy chris))  ; set up variable KIDS
    (first kids)                             ; returns JUNIE
    (second kids)                            ; returns VICKIE
    (third kids)                             ; returns CINDY
    (fourth kids)                            ; returns CHRIS
    (rest kids)                              ; returns (VICKIE CINDY CHRIS)
    

    Note: This function is set to the same code as cadddr.

    See the fourth function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/nthcdr.htm0000644000175000000620000000420311512762341022434 0ustar stevestaffXLISP nthcdr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    nthcdr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (nthcdr expr list-expr)
    expr - an integer expression
    list-expr - a list or list expression
    returns - the nth cdr or NIL if the list isn't that long

    Description

    'nthcdr' returns the 'expr'-th cdr of 'list-expr'. If the 'list-expr' is shorter than 'exp', a NIL is returned. The counting sequence is base zero, the first element is the 0th element.

    Examples

    (nthcdr 4 '(0 1 2 3 4 5 6))  ; returns (4 5 6)
    (nthcdr 3 '(a b))            ; returns NIL
    
    (nthcdr 4 'a)                ; error: bad argument type
    

    See the nthcdr function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-right-trim.htm0000644000175000000620000000531011512762341024544 0ustar stevestaffXLISP string-right-trim Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-right-trim


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-right-trim trim-stuff string)
    trim-stuff - a string expression
    string - a string expression
    returns - a trimed copy of the string

    Description

    The 'string-right-trim' function takes the 'trim-stuff' characters and removes them from the right end of the 'string'. The 'trim-stuff' characters are an un-ordered set of characters to be removed, so any character that occurs in 'trim-stuff' is removed if it appears in right portion of 'string'. A new string is created and returned as the result of this function.

    Examples

    (string-right-trim "." "....foo....")     ; returns "....foo"
    (string-right-trim "<>" "<<<<bar>>>>")    ; returns "<<<<bar"
    (string-right-trim "(.)" "..(12.34)..")   ; returns "..(12.34"
    

    Common Lisp: Common LISP also supports a list of characters as a valid 'trim-stuff' argument. An example:

    (string-trim '(#\Tab #\Newline) mystring)
    

    XLISP does not support non-string parameters. Porting from XLISP will be no problem, but modifications will be necessary if porting from Common LISP code which uses a list of characters.

    See the string-right-trim function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-greaterp-s.htm0000644000175000000620000000524111512762341024141 0ustar stevestaffXLISP char> Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char>


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (char> char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically decreasing ASCII value, NIL otherwise
    Note: case is significant with this function

    Description

    The 'char>' function tests if all the character arguments are monotonically decreasing.  T  is returned if the arguments are of monotonically decreasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is greater than 'char2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than the character '#\A'.

    Examples

    (char> #\a #\b)      => NIL
    (char> #\b #\a)      => T
    (char> #\c #\b #\a)  => T
    (char> #\a #\a)      => NIL
    (char> #\c #\a #\b)  => NIL
    (char> #\A #\a)      => NIL
    (char> #\a #\A)      => T
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/rem.htm0000644000175000000620000000500611512762341021737 0ustar stevestaffXLISP rem Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    rem


    Type:   -   function (subr)
    Source:   -   xlmath.c

    Syntax

    (rem expr1 ... )
    exprN - integer number or expression
    returns - the result of the remainder operation

    Description

    The 'rem' function takes the first pair of expressions and determines what is the remainder from dividing the first by the second expression. If there are no other arguments, this value is returned. If there are additional arguments, the remainder of the first pair is applied to the next and then the next and so on. In other words:

    (REM A B C D)
    

    is equivalent to:

    (REM (REM (REM A B) C) D)
    

    Examples

    (rem 1)        ; returns 1
    (rem 1 2)      ; returns 1
    (rem 13 8)     ; returns 5
    (rem 13 8 3)   ; returns 2
    (rem 13.5 8)   ; error: bad floating point operation
    

    Common Lisp: Common Lisp only allows two arguments. XLISP supports an arbitrary number of arguments. Also, Common Lisp allows for floating point expressions where XLISP does not support this.

    See the rem function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/case.htm0000644000175000000620000001121611512762341022067 0ustar stevestaffXLISP case Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    case


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (case expr [(value action) ... ])
    expr - an expression that can be compared via eql
    value - an unevaluated expression or list of unevaluated expressions
    action - one or more expressions
    returns - the value of the last expression of the matching case

    Description

    The 'case' special form first evaluates 'expr', the return value of this evaluation is then compared against all the 'value' entries:

    (case expr
      (value-1 action-1)
      (value-2 action-2)
        ...
      (value-n action-n))
    

    If 'value' is a single atom, the atom is compared against 'expr':

    > (case 'a
        ('a "a")
        ('b "b"))
    "a"
    

    If 'value' is a list, each of the elements of the list are compared against 'expr':

    > (case 'a
        ((1 2 3 4) "number")
        ((a b c d) "alpha"))
    "alpha"
    

    The 'action' associated with the first 'value' that matches 'expr' is evaluated and returned as the result of the 'case' special form.

    If no 'value' matches, NIL is returned:

    > (case 'c
        ('a "a")
        ('b "b"))
    NIL
    

    If the last 'value' is the symbol  T  and no other 'value' has matched 'expr', then 'case' will evaluate the 'action' associated with  T :

    > (case 3
        (1 "one")
        (2 "two")
        (t "no match"))
    "no match"
    

    If there are multiple  T  entries, the first is considered to be the end of the 'case':

    > (case 9
        (1 "one")
        (t "first t")
        (t "second t"))
    "first t"
    

    Note: The 'case' special form does not work with a list or string as the 'expr' because 'case' uses eql which cannot compare lists or strings:

    > (case "a"   ; doesn't work!
        ("a" 'a)
        ("b" 'b))
    NIL
    

    The cond special form can be used to test Lisp expressions that cannot be handled by 'case'.

    Examples

    (case)     => NIL
    (case 'a)  => NIL
    
    (defun c-type (expr)
      (case (type-of expr)
        (flonum  "float")
        (fixnum  "integer")
        (string  "string")
        (cons    "non-empty list")
        (nil     "empty list")
        (t       "other")))
    
    (c-type 1.2)     => "float"
    (c-type 3)       => "integer"
    (c-type "ab")    => "string"
    (c-type '(a b))  => "non-empty list"
    (c-type '())     => "empty list"
    (c-type 'a)      => "other"
    

    See defun, type-of.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-greaterp-s.htm0000644000175000000620000000745111512762341024537 0ustar stevestaffXLISP string> Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string>


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string> string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is greater than string2 in ASCII ordering, NIL otherwise
    Note: case is significant with this function

    Description

    The 'string>' [string-greater-than] function takes two string arguments. A non-NIL value is returned if 'string1' is greater than 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char> [char-greater-than] the corresponding character of 'string2'. This test is case sensitive, the character '#\a' is different and of greater ASCII value than '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string> "a" "b")                   ; returns NIL
    (string> "a" "a")                   ; returns NIL
    (string> "a" "A")                   ; returns 0
    (string> "A" "a")                   ; returns NIL
    (string> "abc" "abc ")              ; returns NIL
    (string> "1234qrst" "12345678")     ; returns 4
    
    (string> "J Smith" "K Jones" :start1 1 :start2 1)  ; strip off the first chars
                                                       ; returns 2
    

    See the string> function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/go.htm0000644000175000000620000000671611512762341021572 0ustar stevestaffXLISP go Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    go


    Type:   -   special form (fsubr)
    Source:   -   xlcont.c

    Syntax

    (go tag-symbol)
    tag-symbol - a symbol
    returns - never returns a value

    Description

    The 'go' special form allows 'goto' style branching within 'block' constructs [do , do* , dolist , dotimes , tagbody , loop , prog and prog*]. The 'tag-symbol' is the 'label' and must exist somewhere within the 'block' that the 'go' occurs within. Otherwise an error will be generated:

    error: no target for GO
    

    'go' never returns a value. If the 'tag-symbol' exists, then the execution will continue immediately after the'tag-symbol'.

    Examples

    (defun foo (i j)                   ; define FOO
      (prog ()                         ; with a PROG
             (print "begin")
       start (print j)                 ; tag - START
             (setq j (1- j))
             (if (eql i j) (GO start)  ; 2-way branch
                           (GO end))
             (print "hello")           ; won't ever be reached
       end   (print "done")            ; tag - END
             (return 42)))
    
    (foo 1 2)                          ; prints  "begin" 2 1 "done"
                                       ;   returns 42
    
    (foo 2 1)                          ; prints  "begin" 1 "done"
                                       ;   returns 42
    

    Note: Although 'go' will accept a 'tag-symbol' that is not a symbol, it will not find this improper 'tag-symbol'. An error will be generated:

    error: no target for GO
    

    See the go special form in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/read-char.htm0000644000175000000620000000743011512762341023005 0ustar stevestaffXLISP read-char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    read-char


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (read-char [source])
    source - an optional source, must be a file pointer or stream, default is *standard-input*
    returns - the character

    Description

    The 'read-char' function reads a single character from the specified 'source'. The character read is returned as a single character value for the result. The 'source' may be a file pointer or a stream. If there is no 'source', *standard-input* is the default. If an end-of-file is encountered in the 'source', then NIL will be returned as the result.

    Examples

    (setq fp (open "f" :direction :output))  ; set up file
    (print 12.34 fp)
    (close fp)
    
    (setq fp (open "f" :direction :input))   ; now read the file
    (read-char fp)                           ; returns #\1
    (read-char fp)                           ; returns #\2
    (read-char fp)                           ; returns #\.
    (read-char fp)                           ; returns #\3
    (read-char fp)                           ; returns #\4
    (read-char fp)                           ; returns #\Newline
    (read-char fp)                           ; returns NIL - empty
    (close fp)
    

    Common Lisp: The XLISP and Common Lisp 'read-char' functions are compatible for simple cases. They both allow for the optional 'source'. However, in Common Lisp, there are addition parameters which occur right after 'source'. So, when porting from Common Lisp to XLISP, remember there are additional arguments in Common Lisp's 'read-char' function.

    Common Lisp: Common Lisp specifies that 'read' operations with a 'source' of NIL will come from *standard-input*. XLISP does not read the input from *standard-input* with a 'source' of NIL. Common Lisp also specifies that a 'source' of  T  will read from *terminal-io* which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'source'.

    See the read-char function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/digit-char.htm0000644000175000000620000000472311512762341023174 0ustar stevestaffXLISP digit-char Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    digit-char


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (digit-char int)
    int - an integer expression
    returns - the digit character or NIL

    Description

    The 'digit-char' function takes an integer expression 'int' and converts it into a decimal digit character. So, an integer value of '0' produces the character '#\0'. An integer value of '1' produces the character '#\1' and so on. If a valid character can be produce it is returned, otherwise a NIL is returned.

    Examples

    (digit-char 0)    ; returns #\0
    (digit-char 9)    ; returns #\9
    (digit-char 10)   ; returns NIL
    

    Common Lisp: Common Lisp supports the use of an optional radix parameter. This option specifies numeric base. This allows the 'digit-char' to function properly for hexadecimal digits [for example]. Common Lisp supports up to base 36 radix systems. XLISP does not support this radix parameter. Common Lisp also supports a font parameter which XLISP does not.

    See the digit-char function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/read-line.htm0000644000175000000620000000671511512762341023024 0ustar stevestaffXLISP read-line Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    read-line


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (read-line [source])
    source - an optional source, must be a file pointer or stream, default is *standard-input*
    returns - the line as a string

    Description

    The 'read-line' function reads a single line from the specified 'source'. The line read is returned as a string value for the result. The 'source' may be a file pointer or a stream. If there is no 'source', *standard-input* is the default. If an end-of-file is encountered in the 'source', then NIL will be returned as the result.

    Examples

    (setq fp (open "f" :direction :output))  ; set up file
    (print "fe fi" fp)
    (print 12.34 fp)
    (close fp)
    
    (setq fp (open "f" :direction :input))   ; now read the file
    (read-line fp)                           ; returns ""fe fi""    
    (read-line fp)                           ; returns "12.34"
    (read-line fp)                           ; returns NIL
    (close fp)
    

    Common Lisp: The XLISP and Common Lisp 'read-line' functions are compatible for simple cases. They both allow for the optional 'source'. However, in Common Lisp, there are additional parameters which occur right after 'source'. So, when porting from Common Lisp to XLISP, remember there are additional arguments in Common Lisp's 'read-line' function.

    Common Lisp: Common Lisp specifies that 'read' operations with a 'source' of NIL will come from *standard-input*. XLISP does not read the input from *standard-input* with a 'source' of NIL. Common Lisp also specifies that a 'source' of  T  will read from *terminal-io* which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'source'.

    See the read-line function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/close.htm0000644000175000000620000000551511512762341022266 0ustar stevestaffXLISP close Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    close


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (close file-ptr)
    file-ptr - a file pointer expression
    returns - NIL

    Description

    The 'close' function closes the file specified through 'file-ptr'. If the file close was successful, then a NIL is returned as the result. For the file close to be successful, the 'file-ptr' has to point to a valid file. If the file close was not successful, an error is generated:

    error: file not open
    

    Examples

    (close (open 'f :direction :output))           ; returns NIL
    (setq myfile (open 'mine :direction :output))  ; create MYFILE
    (print "hi" myfile)                            ; returns "hi"
    (close myfile)                                 ; returns NIL
                                                   ; file contains <hi> <NEWLINE>
    (setq myfile (open 'mine :direction :input))   ; open MYFILE for input
    (read myfile)                                  ; returns "hi"
    (close myfile)                                 ; returns NIL
    

    Common Lisp: Common LISP has an XLISP compatible 'close' function. Common LISP does support an ':abort' keyword, which is not supported in XLISP.

    See the close function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-white-space.htm0000644000175000000620000000553411512762341025055 0ustar stevestaffXLISP :white-space Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :white-space


    Type:   -   keyword
    Source:   -   xlread.c

    Syntax

     :white-space

    Description

    The ':white-space' keyword is an entry that is used in the *readtable* system variable that contains XLISP's data structures relating to the processing of characters from the user [or files] and read-macro expansions. The existance of the ':white-space' keyword means that the specified character may be skipped over. The system defines that 'tab', 'space', 'return' and 'line-feed' are ':white-space' characters.

    Examples

    ;; define a function to look in a table
    ;; and print out any white-space characters
    
    (defun look-at (table)
      (dotimes (ch 127)
        (prog ((entry (aref table ch)))
          (case entry
            (nil          nil)
            (:constituent nil)
            (:white-space (print ch))
            (t            nil))))
      (terpri))
    
    (look-at *readtable*)  ; prints  9   - tab
                           ;         10  - newline
                           ;         12  - formfeed
                           ;         13  - return
                           ;         32  - space
    

    Caution: If you experiment with *readtable* , it is useful to save the old value in a variable, so that you can restore the system state.

    See the :white-space keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/rplaca.htm0000644000175000000620000000653611512762341022427 0ustar stevestaffXLISP rplaca Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    rplaca


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (rplaca list expr)
    list - the list to destructively modify
    expr - the expression to replace car of list
    returns - the list node after updating the car

    Description

    The 'rplaca' function destructively modifies the car of 'list' and replaces it with the 'expr'. The destructive aspect of this operation means that the actual symbol value is used in the list-modifying operations, not a copy. 'list' must evaluate to a valid list.

    An atom or NIL for 'list' will result in an error:

    error: bad argument type
    

    Examples

    (setq a '(1 2 3))           ; make A with value (1 2 3)
    (setq b '(1 2 3))           ; make B with value (1 2 3)
    (setq c a)                  ; make C point to A's value
    (rplaca a 'new)             ; returns (NEW 2 3)
    
    (print a)                   ; prints (NEW 2 3)
                                ;   note that A is modified
    
    (print b)                   ; prints (1 2 3)
                                ;   note that B is not modified
    
    (print c)                   ; prints (NEW 2 3)
                                ;   note that C is modified too
    
    (setq a '(1 2 3))           ; reset A to value (1 2 3)
    (rplaca a '(the sub list))  ; returns ((THE SUB LIST) 2 3)
    (rplaca '(1 2 3) 'more)     ; returns (MORE 2 3)
    
    (rplaca 'a 'b)              ; error: bad argument type
    (rplaca NIL 'b)             ; error: bad argument type
    

    See the rplaca function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/char-not-greaterp-i.htm0000644000175000000620000000552311512762341024730 0ustar stevestaffXLISP char-not-greaterp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    char-not-greaterp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (char-not-greaterp char1 charN ... )
    char1 - a character expression
    charN - character expression[s] to compare
    returns -  T  if the characters are of monotonically non-decreasing ASCII value, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'char-not-greaterp' function tests if all character arguments are monotonically non-decreasing.  T  is returned if the arguments are of monotonically non-decreasing ASCII value, NIL otherwise. In the case of two arguments, this has the effect of testing if 'char1' is less than or equal to 'char2'. This test is case insensitive, the character '#\a' is considered to be the same ASCII value as the character '#\A'.

    Examples

    (char-not-greaterp #\a #\b)      => T
    (char-not-greaterp #\b #\a)      => NIL
    (char-not-greaterp #\a #\b #\c)  => T
    (char-not-greaterp #\a #\a)      => T
    (char-not-greaterp #\a #\b #\b)  => T
    (char-not-greaterp #\A #\a)      => T
    (char-not-greaterp #\a #\A)      => T
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-not-greaterp-i.htm0000644000175000000620000000776011512762341025326 0ustar stevestaffXLISP string-not-greaterp Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-not-greaterp


    Type:   -   predicate function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-not-greaterp string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns - a non-NIL value if string1 is less than or equal to string2 in ASCII ordering, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'string-not-greaterp' [string-not-greater-than] predicate function takes two string arguments. A non-NIL value is returned if 'string1' is less than or equal to 'string2' in ASCII ordering, otherwise NIL is returned. The non-NIL value returned is the integer index of the first character of 'string1' which is char-not-greaterp [char-not-greater-than] the corresponding character of 'string2'. This test is not case sensitive, the character '#\a' is considered to be the same as '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string-not-greaterp "a" "b")                ; returns 0
    (string-not-greaterp "b" "a")                ; returns NIL
    (string-not-greaterp "a" "a")                ; returns 1
    (string-not-greaterp "a" "A")                ; returns 1
    (string-not-greaterp "A" "a")                ; returns 1
    (string-not-greaterp "abc" "abc ")           ; returns 3
    (string-not-greaterp "12345" "1234qr")       ; returns 4
    
    (string-not-greaterp "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars
                                                                   ; returns 7
    

    See the string-not-greaterp predicate function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/car.htm0000644000175000000620000000454511512762341021730 0ustar stevestaffXLISP car Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    car


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (car expr)
    expr - a list or list expression
    returns - the first element of the list

    Description

    The 'car' function returns the first element of the expression. If the first expression is itself a list, then the sublist is returned. If the list is NIL , NIL is returned.

    The 'car' function returns the same result as the first function.

    Examples

    (car '(a b c))       => A
    (car '((a b) c d))   => (A B)
    (car NIL)            => NIL
    (car 'a)             => error: bad argument type
    (setq bob '(1 2 3))  => (1 2 3)
    (car bob)            => 1
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/hash.htm0000644000175000000620000000563511512762341022107 0ustar stevestaffXLISP hash Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    hash


    Type:   -   function (subr)
    Source:   -   xlbfun.c, xlsym.c

    Syntax

    (hash name table-size)
    name - a symbol or string expression
    table-size - an integer expression
    returns - the hash index as an integer value

    Description

    The 'hash' function computes and returns an integer index for a given symbol 'name' and a given size of hash table 'table-size'. The intention is for 'hash' to be used with tables made by make-array and accessed by aref.

    Examples

    (hash "zzzz" 1000)        ; returns index 322
    (hash "ZZZZ" 1000)        ; returns index 626
    (hash 'ZZZZ  1000)        ; returns index 626
    (hash "hiho" 1000)        ; returns index 519
    (hash 'hiho  1000)        ; returns index 143
    (hash "abcd" 1000)        ; returns index 72
    
    ;; create a function to look inside *OBARRAY* and
    ;; look for a specific symbol - returns a list
    
    (defun lookin (sym)
      (aref *obarray*
            (hash sym (length *obarray*))))
    
    (lookin 'caar)       ; returns the hash table entry
                         ;   (ZEROP CDDDDR CAAR HASH)
    

    Note: This is a useful function for creating and accessing tables. It is also useful for looking inside of XLISP's own symbol table *obarray*.

    See the hash function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/write-byte.htm0000644000175000000620000000635711512762341023261 0ustar stevestaffXLISP write-byte Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    write-byte


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (write-byte expr [dest])
    expr - an integer expression
    dest - an optional destination, must be a file pointer or stream, default is *standard-output*
    returns - the byte as an integer

    Description

    The 'write-byte' function writes the 'expr' as a single byte to the specified 'destination'. Only the 'expr' byte is written. The 'expr' must be an integer expression. The 'expr' is returned as the result. The 'destination' may be a file pointer or a stream. If there is no 'destination', *standard-output* is the default.

    Examples

    (write-byte 67)                          ; prints C  returns 67
    
    (setq fp (open "t" :direction :output))  ; create file
    (write-byte 65 fp)                       ; returns 65
    (write-byte 66 fp)                       ; returns 66
    (write-byte 10 fp)                       ; returns 10
    (close fp)                               ; returns NIL
    
    (read (open "t" :direction :input))      ; returns AB
    

    Common Lisp: Common Lisp specifies that print operations with a 'destination' of NIL will go to *standard-output*. XLISP does not send the output to *standard-output* with a 'destination' of NIL. Common Lisp also specifies that a 'destination' of  T  will be sent to *terminal-io*, which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'destination'.

    See the write-byte function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-isa.htm0000644000175000000620000000530711512762341023416 0ustar stevestaffXLISP :isnew Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :isa


    Type:   -   message selector
    Source:   -   xlobj.c

    Syntax

    (send object :isa class) - test if object inherits from class
    returns -  T  if object is an instance of class or a subclass of class, otherwise NIL

    Description

    The ':isa' message selector tests if an object inherits from a class.

    Examples

    (setq a-class (send class :new '(state)))   ; create a new class A-CLASS with STATE
    
    (send a-class :answer :isnew '()            ; set up initialization
                                 '((setq state nil) self))
    
    (send a-class :answer :set-it '(value)      ; create :SET-IT message
                                  '((setq state value)))
    
    (setq an-obj (send a-class :new))           ; create AN-OBJ out of A-CLASS
    
    (send an-obj :show)                         ; returns object - STATE = NIL
    
    (send an-obj :set-it 5)                     ; STATE is set to 5
    (send an-obj :show)                         ; returns object - STATE = 5
    
    (SEND an-obj :ISNEW)                        ; re-initialize AN-OBJ
    (send an-obj :show)                         ; returns object - STATE = NIL
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/info.htm0000644000175000000620000000277511512762341022121 0ustar stevestaffXLISP info Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    info


    Type:   -   function (subr)
    Source:   -   xldmem.c

    Syntax

    (info)
    returns - NIL

    Description

    The 'info' function shows information about memory usage.

    Examples

    > (info)
    [ Free: 5689, GC calls: 17, Total: 675111; samples 1KB, 0KB free]
    NIL
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/string-equal-i.htm0000644000175000000620000001050011512762341024010 0ustar stevestaffXLISP tring-equal Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    string-equal


    Type:   -   function (subr)
    Source:   -   xlstr.c

    Syntax

    (string-equal string1 string2 [key offset] ... )
    stringN - a string expression
    key - a keyword [one of :start1 :start2 :end1 :end2]
    offset - an optional integer expression for a keyword
    returns -  T  if string1 equal to string2, NIL otherwise
    Note: case is not significant with this function

    Description

    The 'string-equal' function takes two string arguments. It checks to see if the string arguments have the same values.  T  is returned if 'string1' is equal to 'string2', NIL is returned otherwise. This test is not case sensitive, the character '#\a' is considered to be the same as '#\A'.

    The keyword arguments allow for accessing substrings within 'string1' and 'string2'. The keyword arguments each require a keyword ':start1', ':end1', ':start2' or ':end2' and a single integer expression as a pair with the keyword first and the integer second. The pairs may be in any order. The ':startN' keywords specify the starting offset of the substring. A value of 0 starts the string at the beginning [no offset]. The ':endN' keywords specify the ending offset of the substring. A value of 3 ends the string after the 3rd character [an offset of 3 characters].

    Examples

    (string-equal "a" "b")            ; returns NIL
    (string-equal "a" "a")            ; returns T
    (string-equal "a" "A")            ; returns T
    (string-equal "A" "a")            ; returns T
    (string-equal "abc" "abc ")       ; returns NIL
    
    (string-equal "J Smith" "K Smith" :start1 1 :start2 1)  ; strip off the first chars
                                                            ; returns T
    
    (string-equal "abc" "123456789" :end2 3 :end1 3)        ; leave just the first 3 chars
                                                            ; returns NIL
    

    Bug: The 'string-equal' function is listed in the original XLISP documentation as 'string-equalp'. In the XLISP interpreter a call to 'string-equalp' causes an error:

    error: unbound function - STRING-EQUALP
    

    The 'string-equal' function works exactly as the 'string-equalp' function described in the XLISP manual. This bug had obviously been corrected in the manual only but never in the interpreter. As the bug still exists with Nyquist 2.36 in July 2007 as well as all other XLISP 2.x implementations I know, I have changed both manuals to 'string-equal' even if I myself whould consider 'string-equalp' as the better name.

    See the string-equal function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/caaaar.htm0000644000175000000620000001173511512762341022372 0ustar stevestaffXLISP caaaar ... cadddr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    caaaar ... cadddr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (caaaar expr)
    (caaadr expr)
    (caadar expr)
    (caaddr expr)
    (cadaar expr)
    (cadadr expr)
    (caddar expr)
    (cadddr expr)
    expr - a list or list expression
    returns - the result of the last car function

    Description

    The 'caaaar' ... 'cadddr' functions go through the list expression and perform a sequence of car or cdr operations. The sequence of operations is performed from right to left. So 'caaddr' does a cdr on the expression, followed by a cdr, followed by a car, followed by another car. If at any point the list is NIL, then NIL is returned. If at any point a car operation is performed on an atom [as opposed to a list] an error is signalled:

    error: bad argument
    

    The 'cadddr' function returns the same result as the fourth function.

    Examples

    (setq mylist '((((111A 111B) (112A 112B) (113A 113B))   ; 1st set
                    ((121A 121B) (122A 122B) (123A 123B))
                    ((131A 131B) (132A 132B) (133A 133B))
                    ((141A 141B) (142A 142B) (143A 143B)))
                   (((211A 211B) (212A 212B) (213A 213B))   ; 2nd set
                    ((221A 221B) (222A 222B) (223A 223B))
                    ((231A 231B) (232A 232B) (233A 233B))
                    ((241A 241B) (242A 242B) (243A 243B)))
                   (((311A 311B) (312A 312B) (313A 313B))   ; 3rd set
                    ((321A 321B) (322A 322B) (323A 323B))
                    ((331A 331B) (332A 332B) (333A 333B))
                    ((341A 341B) (342A 342B) (343A 343B)))
                   (((411A 411B) (412A 412B) (413A 413B))   ; 4th set
                    ((421A 421B) (422A 422B) (423A 423B))
                    ((431A 431B) (432A 432B) (433A 433B))
                    ((441A 441B) (442A 442B) (443A 443B)))
                   (((511A 511B) (512A 512B) (513A 513B))   ; 5th set
                    ((521A 521B) (522A 522B) (523A 523B))
                    ((531A 531B) (532A 532B) (533A 533B))
                    ((541A 541B) (542A 542B) (543A 543B)))))
    
    (caaaar mylist)  => 111A
    (caaadr mylist)  => (211A 211B)
    (caadar mylist)  => (121A 121B)
    (caaddr mylist)  => ((311A 311B) (312A 312B) (313A 313B))
    (cadaar mylist)  => (112A 112B)
    (cadadr mylist)  => ((221A 221B) (222A 222B) (223A 223B))
    (caddar mylist)  => ((131A 131B) (132A 132B) (133A 133B))
    (cadddr mylist)  => (((411A 411B) (412A 412B) (413A 413B))
                         ((421A 421B) (422A 422B) (423A 423B))
                         ((431A 431B) (432A 432B) (433A 433B))
                         ((441A 441B) (442A 442B) (443A 443B)))
    

    Note: The 'c...r' functions are part of the historical Lisp functions. You may find it easier to work with the modern lisp functions like nth and nthcdr.

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-standard-output.htm0000644000175000000620000000536711512762341025562 0ustar stevestaffXLISP *standard-output* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *standard-output*


    Type:   -   system variable
    Source:   -   xlinit.c

    Syntax

     *standard-output*

    Description

    The *standard-output* system variable contains a file pointer that points to the file where all normal printing and messages from XLISP will go. The default file for *standard-output* is the system standard output device, normally the screen display.

    Examples

    *standard-output*                        ; returns #<File-Stream: #24406>
    (setq old-so *standard-output*)          ; save the file pointer
    (setq fp (open "f" :direction :output))  ; open a new output file
    (setq *standard-output* fp)              ; change where output goes
    
    (+ 2 2)                                  ; you won't see any messages
                                             ; just the echo of input line
    
    (setq *standard-output* old-so)          ; restore standard output
    (close fp)                               ; close file
    

    Note: Be careful when modifying the *standard-output*, you will not be able to see what you are doing. If you do not save the old file pointer, you will not be able to return to normal operation and will need to exit XLISP.

    See the *standard-output* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/make-symbol.htm0000644000175000000620000000675011512762341023403 0ustar stevestaffXLISP make-symbol Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    make-symbol


    Type:   -   function (subr)
    Source:   -   xlbfun.c

    Syntax

    (make-symbol symbol-str)
    symbol-str - a string expression
    returns - the new symbol

    Description

    The 'make-symbol' function takes a string name 'symbol-str' and creates a new symbol. This symbol is temporary and is not interned [placed] into the symbol hash table *obarray*. If the symbol already exists, no error or action is taken and the old values and property lists remain intact. The 'make-symbol' function returns the symbol as its result.

    Examples

    (defun lookin (sym)                  ; create a function to
      (aref *obarray*                    ;   look inside *OBARRAY*
        (hash sym (length *obarray*))))  ;   and look for a specific
                                         ;   symbol - returns a list
    
    (lookin "FEE")                       ; returns (CHAR-INT NTH ++)
                                         ;   FEE symbol doesn't exist
    
    (make-symbol "FEE")                  ; returns FEE symbol
    (lookin "FEE")                       ; returns (CHAR-INT NTH ++)
                                         ;   FEE still doesn't exist
    
    (intern "FEE")                       ; intern FEE symbol
    (lookin "FEE")                       ; returns (FEE CHAR-INT NTH ++)
                                         ;   FEE does now exist
    

    Note: When you 'make-symbol' a string type symbol like "fingers", this is a lower case symbol. This is different from doing a 'make-symbol' on a string type symbol "FINGERS", which is an upper case symbol. With string type symbols, "fingers" and "FINGERS" are two different symbols. Remember also that normal symbols created by XLISP are automatically converted to upper case.

    See the make-symbol function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/cdr.htm0000644000175000000620000000450711512762341021731 0ustar stevestaffXLISP cdr Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    cdr


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (cdr expr)
    expr - a list expression
    returns - expr with the first element removed

    Description

    The 'cdr' function returns the rest of a list expression after the first element of the list is removed. If the list is NIL, then NIL is returned.

    The 'cdr' function returns the same result as the rest function.

    Examples

    (cdr '(a b c))       => (B C)
    (cdr '((a b) c d))   => (C D)
    (cdr nil)            => NIL
    (cdr 'a)             => error: bad argument type
    (cdr '(a))           => NIL
    (setq ben '(a b c))  =>
    (cdr ben)            => (B C)
    

    See also:

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/filep.htm0000644000175000000620000000352411512762341022256 0ustar stevestaffXLISP filep Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    filep


    Type:   -   Lisp function (closure)
    Source:   -   xlinit.lsp

    Syntax

    (filep expr)
    expr - an Lisp expression
    returns -  T  if expr is of type FPTR, NIL otherwise

    In Nyquist, 'filep' is implemented as a Lisp function:

    (defun filep (x)
      (eq (type-of x) 'FPTR))
    

    Description

    The 'filep' function returns  T  if 'expr' is of type FPTR, NIL otherwise

    Examples

    
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/global-print-case.htm0000644000175000000620000000524411512762341024463 0ustar stevestaffXLISP *print-case* Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    *print-case*


    Type:   -   system variable
    Source:   -   xlprin.c

    Syntax

     *print-case*

    Description

    *print-case* is a system variable that allows a user to specify how symbols are to be printed by XLISP. If *print-case* is set to ':downcase', all symbols will be printed in lower case characters. If *print-case* is set to ':upcase', all symbols will be printed in upper case characters. If *print-case* is set to anything other than ':upcase' or ':downcase', all symbols will be printed in upper case characters. The default value for *print-case* is ':upcase'.

    Examples

    (setq *print-case* :downcase)  ; returns :downcase
    (setq a 'b)                    ; returns b
    
    (setq *print-case* 'foo)       ; returns FOO
    (setq a 'b)                    ; returns B
    
    (setq *print-case* :upcase)    ; returns :UPCASE
    (setq a 'b)                    ; returns B
    

    Common Lisp: Common LISP supports a third keyword ':capitalize' to print the first character of symbol names in upper-case. XLISP does not support this. In XLISP, if *print-case* is set to ':capitalize', all characters in symbols names will be printed in upper-case characters.

    See the *print-case* system variable in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/quit.htm0000644000175000000620000000335511512762341022143 0ustar stevestaffXLISP quit Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    quit


    Type:   -   function (subr)
    Source:   -   xlsys.c

    Syntax

    (quit)
    returns - never returns

    Description

    The 'quit' function causes the current XLISP session to be terminated. It never returns.

    Examples

    (quit)   ; never returns
    

    Note: When XLISP is exited, any dribble transcript file is automatically closed. However, other open files are not closed, and so may lose some information.

    See also exit.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/keyword-tmacro.htm0000644000175000000620000000657111512762341024133 0ustar stevestaffXLISP :tmacro Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    :tmacro


    Type:   -   keyword
    Source:   -   xlread.c

    Syntax

    (:tmacro . function)
    function - a function

    Description

    ':tmacro' is an entry that is used in the *readtable* system variable that contains XLISP's data structures relating to the processing of characters from the user [or files] and read-macro expansions. The existance of the ':tmacro' keyword means that the specified character is the start of a terminal read macro. For ':tmacro', the form of the *readtable* entry is a dotted pair like:

    (:tmacro . function)
    

    The 'function' can be a built-in read-macro function or a user defined lambda expression. The 'function' takes two parameters, an input stream specification, and an integer that is the character value. The 'function' should return NIL if the character is 'white-space' or a value consed with NIL to return the value. The 'function' will probably read additional characters from the input stream.

    Examples

    (defun look-at (table)                ; define a function to look in a table
      (dotimes (ch 127)                   ; and print out any :TMACRO entries
        (prog ((entry (aref table ch)))
          (if (and (consp entry)
                   (equal (car entry) ':TMACRO))
              (princ (int-char ch)))))
      (terpri))
    
    (look-at *readtable*)                 ;  prints "'(),;`
    

    Note: The system defines that the following are ':tmacro' characters:

       \  "  `  ,  ( )  ;
    

    [backslash, double quote, backquote, comma, opening parenthesis, closing parenthesis, semicolon.]

    Caution: If you experiment with *readtable* , it is useful to save the old value in a variable, so that you can restore the system state.

    See the :tmacro keyword in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/read-byte.htm0000644000175000000620000000754411512762341023041 0ustar stevestaffXLISP read-byte Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    read-byte


    Type:   -   function (subr)
    Source:   -   xlfio.c

    Syntax

    (read-byte [source])
    source - an optional source, must be a file pointer or stream, default is *standard-input*
    returns - the byte as an integer

    Description

    The 'read-byte' function reads a single character from the specified 'source'. The character read is returned as an integer value for the result. The 'source' may be a file pointer or a stream. If there is no 'source', *standard-input* is the default. If an end-of-file is encountered in the 'source', then NIL will be returned as the result.

    Examples

    (setq fp (open "f" :direction :output))  ; set up file
    (print 12.34 fp)
    (close fp)
    
    (setq fp (open "f" :direction :input))   ; now read the file
    (read-byte fp)                           ; returns 49  - equals "1"
    (read-byte fp)                           ; returns 50  - equals "2"
    (read-byte fp)                           ; returns 46  - equals "."
    (read-byte fp)                           ; returns 51  - equals "3"
    (read-byte fp)                           ; returns 52  - equals "4"
    (read-byte fp)                           ; returns 10  - equals "\n"
    (read-byte fp)                           ; returns NIL - empty
    (close fp)
    

    Common Lisp: The XLISP and Common Lisp 'read-byte' functions are compatible for simple cases. They both allow for the optional 'source'. However, in Common Lisp, there are additional parameters which occur right after 'source'. So, when porting from Common Lisp to XLISP, remember there are additional arguments in Common Lisp's 'read-byte' function.

    Common Lisp: Common Lisp specifies that 'read' operations with a 'source' of NIL will come from *standard-input*. XLISP does not read the input from *standard-input* with a 'source' of NIL. Common Lisp also specifies that a 'source' of  T  will read from *terminal-io* which is not defined in XLISP by default. XLISP does not allow  T  as a valid argument for 'source'.

    See the read-byte function in the XLISP 2.0 manual.

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/reference/mapcar.htm0000644000175000000620000001167611512762341022431 0ustar stevestaffXLISP mapcar Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference

    mapcar


    Type:   -   function (subr)
    Source:   -   xllist.c

    Syntax

    (mapcar function list1 [list2 ... ])
    function - a function definition like a lambda or a function name
    listN - a list or list expression
    returns - a list that is constructed from the results of the function applications

    Description

    The mapcan function 'mapcar' applies the 'function' to the succesive cars of each of the lists 'listN'. Each of the lists supplies one of the arguments to 'function'. The 'mapcar' function returns a list that is constructed from the results of the 'function' applications. If the lists are of different lengths, the shortest list will determine the number of applications of 'function'.

    Examples

    > (mapcar #'+ '(1 2 3) '(1 2 3))
    (2 4 6)
    
    > (mapcar #'princ '(1 2 3))       
    123       ; screen output
    (1 2 3)   ; return value
    
    > (mapcar #'+ '(1 2 3) '(1 2 3 4 5 6)  ; different length lists
    (2 4 6)
    

    Note: The use of the 'function' will work properly when it is a sharp-quoted symbol, a quoted symbol [must be the name of a function], an unquoted symbol whose value is a function, or a closure object like a lambda form.

    Bug: The proper syntax for 'function' when 'function' is a lambda expression is, for example:

    (mapcar #'(lambda (arg1 arg2) (+ arg1 arg2)) '(1 2))
    

    and not:

    (mapcar '(lambda (arg1 arg2) (+ arg1 arg2)) '(1 2))
    

    That is, the #' [function] read macro must be present. This error should be caught by the XLISP interpreter, but it is not, with the result that very obscure garbage collection bugs occur. [I still haven't tested Nyquist for possible garbage collection bugs caused by this.]

    Notes

    In XLISP, a 'special form' of type FSUBR is not a function. This means that 'mapcar' only works with functions of type SUBR [built-in function] or CLOSURE [function defined by defun, flet, labels, or lambda], but with special forms of type FSUBR a 'bad function' error is signalled. Here is an example how to work around this behaviour:

    (defmacro mapcar* (function &rest args)
      (if (eq (type-of (symbol-function (second function))) 'fsubr)
          (let ((rest (gensym)))
            `(mapcar #'(lambda (&rest ,rest) 
                         (eval (cons ,function ,rest)))
                     ,@args))
          `(mapcar ,function ,@args)))
    

    Examples:

    (type-of #'eql)  => SUBR   ; built-in function
    (type-of #'and)  => FSUBR  ; built-in special form
    
    > (macroexpand-1 '(mapcar* #'eql '(1 2 3) '(t nil 3)))
    (MAPCAR (FUNCTION EQL)
            (QUOTE (1 2 3))
            (QUOTE (T NIL 3)))
    
    > (macroexpand-1 '(mapcar* #'and '(1 2 3) '(t nil 3)))
    (MAPCAR (FUNCTION (LAMBDA (&REST G7)
                        (EVAL (CONS (FUNCTION AND) G7))))
            (QUOTE (1 2 3))
            (QUOTE (T NIL 3)))
    
    (mapcar  #'eql '(1 2 3) '(t nil 3)))  => (NIL NIL T)
    (mapcar* #'eql '(1 2 3) '(t nil 3)))  => (NIL NIL T)
    
    (mapcar  #'and '(1 2 3) '(t nil 3)))  => error: bad function
    (mapcar* #'and '(1 2 3) '(t nil 3)))  => (T NIL 3)
    

      Back to Top


    Nyquist / XLISP 2.0  -  Contents | Tutorials | Examples | Reference nyquist-3.05/docsrc/xlisp/xlisp-doc/README0000644000175000000620000000041611512762341017364 0ustar stevestaffJanuary 11, 2011 The XLISP dos in this directory still in an unfinished state. The hyperlinking works, but many pages are still too messy. Just load "start.htm" into your web browser, everything else is linked from there. In case of doubt write to: edgar-rft@web.de nyquist-3.05/misc/0002755000175000000620000000000011537433127013126 5ustar stevestaffnyquist-3.05/misc/convert.h0000644000175000000620000000022510144436365014754 0ustar stevestaff/* convert.h -- convert from packer internal filenames to local OS */ void convert(char *filename); extern int pauseflag; #define PAUSE pauseflag nyquist-3.05/misc/intgen_win32/0002755000175000000620000000000011537433127015434 5ustar stevestaffnyquist-3.05/misc/intgen_win32/intgen.vcproj0000644000175000000620000001306411512143043020133 0ustar stevestaff nyquist-3.05/misc/intgen_win32/intgen.dsp0000644000175000000620000001032211466723256017432 0ustar stevestaff# Microsoft Developer Studio Project File - Name="intgen" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=intgen - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "intgen.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "intgen.mak" CFG="intgen - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "intgen - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "intgen - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "intgen - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "WinRel" # PROP Intermediate_Dir "WinRel" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\..\sys\win\msvc" /I "..\..\cmt" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "intgen - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "WinDebug" # PROP Intermediate_Dir "WinDebug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\sys\win\msvc" /I "..\..\cmt" /D "_CONSOLE" /D "_MBCS" /D "WIN32" /D "_DEBUG" /D "DEBUG_INPUT" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "intgen - Win32 Release" # Name "intgen - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\cmdline.c # End Source File # Begin Source File SOURCE=..\intgen2.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\cmdline.h # End Source File # Begin Source File SOURCE=..\..\sys\win\msvc\switches.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nyquist-3.05/misc/unpacker.vcproj0000644000175000000620000001377511512143043016162 0ustar stevestaff nyquist-3.05/misc/mac-to-win.lsp0000644000175000000620000000271310144436365015622 0ustar stevestaff;; mac-to-win -- convert text files in nyquist project ;; NOTE: this might work to convert any source tree to the local newline ;; convention, but it was written to run under windows and convert mac ;; sources to windows so that I could run windiff on the files. -RBD ;; files.txt is a listing of all the component files (defun mac-to-win (output-path) (let (files filename) (setf files (open "files.txt" :direction :input)) (while (setf filename (read-line files)) (process-file filename output-path)) (close files))) (defun process-file (filename output-path) (let ((filetype (char filename 0))) (cond ((eq filetype #\a) (setf filename (subseq filename 2)) (convert-file filename output-path))))) (defun convert-file (filename output-path) (let (infile outfile outfilename line) (setf outfilename (strcat output-path filename)) (setf infile (open filename :direction :input)) (setf outfile (open outfilename :direction :output)) (cond ((null infile) (format t "Could not open ~A~%" filename)) ((null outfile) (format t "Could not open ~A~%" outfilename)) (t (format t "~A~%" filename) (while (setf line (read-line infile)) (format outfile "~A~%" line)) (close infile) (close outfile))))) (defun convert-mac-to-win () (setdir "d:/rbd/icm_nyquist") (mac-to-win "d:/rbd/icm_nyquist_win/")) nyquist-3.05/misc/sampleprint.c0000644000175000000620000000153510144436365015632 0ustar stevestaff#include #define NPERLINE 10 main() { short line[2][NPERLINE]; register int n, i, j; register int curline = 0; int currently_printing = 1; for(i = 0; (n = fread(line[curline], sizeof(short), NPERLINE, stdin)) > 0; i += n, curline = 1-curline) { if(i != 0 && n == NPERLINE && sameline(line[0], line[1])) { if(currently_printing) { printf("*\n"); currently_printing = 0; } continue; } currently_printing = 1; printf("%7d ", i); for(j = 0; j < n; j++) printf("%6d ", line[curline][j]); printf("\n"); } printf("%4d\n", i); } sameline(l1, l2) register short *l1, *l2; { register n = NPERLINE; while(--n >= 0) if(*l1++ != *l2++) return 0; return 1; } nyquist-3.05/misc/play.c0000644000175000000620000000507710144436365014246 0ustar stevestaff/* A cheap command to play sample files to the D/A's. The sample files should have no headers. They can be eight or sixteen bits, with one or two channels. Sample rate is eigher 44.1 or 22.05. NOTE: samples brought from the VAX may have byte order reversed. Use "dd conv=swab" to fix this. William Walker, University of Illinois, 27 January 1989 (walker@m.cs.uiuc.edu) */ #include #include #define THESIZE 3000000 #include "args.h" #define TAG 9839283 main(argc, argv) char **argv; { int srate = SND_RATE_LOW; int nchannels = 1; int again = 1; int i; SNDSoundStruct *cow; FILE *data; ARGLOOP FLAGARG('h') srate = SND_RATE_HIGH; ENDFLAGARG FLAGARG('s') nchannels = 2; ENDFLAGARG STRINGARG('r') srate = atoi(p); ENDSTRINGARG FLAGARG('o') again = 0; ENDFLAGARG BADARG fprintf(stderr, "unknown option %c\n", *p); goto error; ENDBADARG ENDARGLOOP if (argc != 1) goto error; cow = (SNDSoundStruct *) malloc(THESIZE); /* these fields should probably be invariant: */ cow->magic = SND_MAGIC; cow->dataLocation = sizeof(SNDSoundStruct); cow->dataSize = 0; cow->dataFormat = SND_FORMAT_LINEAR_16; cow->samplingRate = srate; cow->channelCount = nchannels; printf("%d Hz sample rate, %d channels\n", cow->samplingRate, nchannels); do { data = fopen(argv[0],"r"); if (data == NULL) { printf("play: fopen error\n"); exit(1); } printf("Read %d bytes\n",cow->dataSize = fread((char *)cow+sizeof(SNDSoundStruct),1,THESIZE-sizeof(SNDSoundStruct),data)); fclose(data); /* printf("Reserve sound for playing (%d)\n",SNDReserve()); */ printf("Play (%d)\n", SNDStartPlaying(cow,TAG,0,0,(SNDNotificationFun)NULL,(SNDNotificationFun)NULL)); printf("Wait for played sound (%d)\n",SNDWait(TAG)); /* printf("Query played sound (%d)\n",SNDQueryPlayedSound()); */ /* printf("Unreserve sound for playing (%d)\n",SNDUnreserveSoundForPlaying()); */ if(again) { char line[100]; printf("Again? [y] "); gets(line); if(line[0] != 'y' && line[0] != 'Y' && line[0] != '\0') again = 0; } } while( again ); exit(0); error: fprintf(stderr, "\nUsage: play [ -h ] [ -s ] [ -o ] file\n\n"); fprintf(stderr, " -h 44.1KHz sample rate (default 22.1KHz)\n"); fprintf(stderr, " -s stereo (default mono)\n"); fprintf(stderr, " -o play only once (default asks to play again)\n"); fprintf(stderr, "\n"); exit(1); } nyquist-3.05/misc/args.h0000644000175000000620000000263510144436365014237 0ustar stevestaff/* * Argument processing macros * I got tired of rethinking this everytime, * and 4xbsd doesn't have getopt() * * The following is an example of the use of this stuff * #include "args.h" #include main(argc, argv) char **argv; { char *a = "a", *b = "b", *c = "c"; int x = 0, y = 0, z = 0; ARGLOOP STRINGARG(a) a = p; ENDSTRINGARG STRINGARG(b) b = p; ENDSTRINGARG STRINGARG(c) c = p; ENDSTRINGARG FLAGARG(x) x++; ENDFLAGARG FLAGARG(y) y++; ENDFLAGARG FLAGARG(z) z++; ENDFLAGARG BADARG fprintf(stderr, "unknown option %c\n", *p); fprintf(stderr, "Usage: usage\n"); exit(1); ENDBADARG ENDARGLOOP Here, the remaining args are argv[0] to argv[argc - 1] printf("a=%s b=%s c=%s x=%d y=%d z=%d\nargs:", a, b, c, x, y, z); { int i; for(i = 0; i < argc; i++) printf(" %s", argv[i]); } printf("\n"); } * */ #define ARGLOOP \ while(--argc > 0 && **++argv == '-') { \ register char *p; \ for(p = *argv + 1; *p != '\0'; p++) { \ switch(*p) { \ #define ENDARGLOOP \ } \ } \ nextarg:; \ } \ #define FLAGARG(c) case c: #define ENDFLAGARG break; #define STRINGARG(c) case c: if(!*++p) p = *++argv, argc--; #define ENDSTRINGARG goto nextarg; #define BADARG default: #define ENDBADARG break; nyquist-3.05/misc/makefile.lsp0000644000175000000620000005363511512414056015426 0ustar stevestaff;; makefile.lsp -- builds makefiles for various machine types (setf old-system-types '(rs6k next pmax sparc sgi)) (setf system-types '(alsa nonalsa)) (if (not (boundp 'system-type)) (setf system-type nil)) (if (not (boundp 'target-file)) (setf target-file "ny")) (format t "System types: ~A~%" system-types) (format t "The following types are not maintained but might get close: ~A~%" old-system-types) (format t "Current type: ~A~%" system-type) (format t "Current target: ~A~%" target-file) (format t "~%Instructions: (run from top nyquist directory)~%") (format t "Choose a system from the list above by typing:~%") (format t "\t(setf system-type ')~%") (format t "Override the executable name or location by:~%") (format t "\t(setf target-file \"unix-path-name/ny\")~%") (format t "To build the Makefile, type:~%") (format t "\t(makefile)~%") (format t "To make Makefiles for all system types, type:~%") (format t "\t(makeall)~%") (format t "To make sndfn.wcl and sndfn.cl, type:~%") (format t "\t(commandline)~%") ;(format t "To build the Makesrc file, type:~%") ;(format t "\t(makesrc)~%") ;(format t ;"Note: Makesrc is used to update sources from other directories. ; It isn't necessary if you got the sources from the normal ; .tar file release of Nyquist ;") (setf xlfiles '("extern" "xldmem" "xlbfun" "xlcont" "xldbug" "xleval" "xlfio" "xlftab" "xlglob" "xlimage" "xlinit" "xlio" "xlisp" "xljump" "xllist" "xlmath" "xlobj" "xlpp" "xlprin" "xlread" "xlstr" "xlsubr" "xlsym" "xlsys" "path")) (setf xlfiles-h '("osdefs" "osptrs" "xldmem" "xlisp" "extern")) (setf xlfiles-lsp '("xlinit" "misc" "evalenv" "printrec")) ; ************************************ ; CHANGED stksrcfiles. PJM July 2007 ; ************************************ (setf stksrcfiles '("Generator" "SineWave" "Function" "FileRead" "FileWvIn" "Effect" "Clarinet" "Delay" "DelayL" "Envelope" "Filter" "Instrmnt" "Noise" "OneZero" "ReedTable" "Saxofony" "Stk" "WaveLoop" "WvIn" "NRev" "JCRev" "PRCRev" "PitShift" "Chorus" "Bowed" "BowTable" "ADSR" "OnePole" "BiQuad" "BandedWG" "DelayA" "Mandolin" "PluckTwo" "Sitar" "ModalBar" "Modal" "Flute" "JetTable" "PoleZero" )) ; *************************************************** ; CHANGED stkfiles. PJM July 2007 ; Added stkint, An interface for new stk instruments ; *************************************************** (setf stkfiles '("stkinit" "instr" "stkint")) (setf fftfiles '("fftext" "fftlib" "matlib")) ; note: audio and snd will be prepended to this list, e.g. ; the strings "audiooss" and "sndlinux" will be added for linux systems ; (defun init-sndfiles () (setf sndfiles '("ieeecvt" "snd" "sndcvt" "sndio" "sndheader")) (setf sndfiles-lsp '("snd"))) (init-sndfiles) (setf depends-exceptions '( ("nyqsrc/handlers" "") ;("nyqsrc/sndfail" "") ("nyqsrc/local" "xlisp/xlisp.h nyqsrc/sound.h") ("nyqsrc/stats" "nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h") ("snd/sndcvt" "snd/snd.h") ("snd/sndio" "snd/snd.h") ("snd/audiors6k" "snd/snd.h") ("snd/audionext" "snd/snd.h") ("snd/audiosgi" "snd/snd.h") ("snd/audiopmax" "snd/snd.h") ("snd/audiosparc" "snd/snd.h") ("snd/audiolinux" "snd/snd.h") ("snd/audiooss" "snd/snd.h") ("nyqsrc/sndwritepa" "nyqsrc/sndwrite.h") ("nyqsrc/sndfnint" "") ; sparc needs explicit rule for sndfnint.o ("nyqsrc/seqfnint" "") ; ditto for seqfnint.o )) (setf nyqfiles-lsp '("init" "nyquist" "seqmidi" "seq" "makefile" "update" "transfiles" "examples" "nyinit")) (setf system-types-as-strings (mapcar #'string-downcase (mapcar #'symbol-name system-types))) (setf nyqfiles-lsp (append nyqfiles-lsp system-types-as-strings)) (setf nyqfiles-h '("localdefs" "localptrs" "seqdecls" "cque" "switches")) (setf intfiles '("sndfnint" "seqfnint")) (setf extrafiles nil) ;(dolist (m system-types) ; (push (strcat "Makefile." ; (string-downcase (symbol-name m))) ; extrafiles)) (push "export" extrafiles) (push "README" extrafiles) (push "howtorelease.doc" extrafiles) (setf cmtfiles '("cext" "cleanup" "cmdline" "cmtcmd" "moxc" "mem" "midifile" "midifns" "record" "seq" "seqmread" "seqmwrite" "seqread" "seqwrite" "tempomap" "timebase" "userio")) ; "midimgr" - removed by RBD (setf cmtfiles-h '("mfmidi" "midicode" "midierr" "musiprog" "pitch" "swlogic" "hash" "hashrout" "io" "midibuff")) (setf nylsffiles '("aiff" "alaw" "au" "avr" "broadcast" "caf" "command" "common" "dither" "double64" "dwd" "dwvw" "file_io" "flac" "float32" "gsm610" "htk" "ima_adpcm" "interleave" "ircam" "macbinary3" "macos" "mat4" "mat5" "ms_adpcm" "nist" "ogg" "paf" "pcm" "pvf" "raw" "rx2" "sd2" "sds" "sndfile" "strings" "svx" "txw" "ulaw" "voc" "vox_adpcm" "w64" "wav" "wav_w64" "wve" "xi" "g72x" "GSM610/add" "GSM610/code" "GSM610/decode" "GSM610/gsm_create" "GSM610/gsm_decode" "GSM610/gsm_destroy" "GSM610/gsm_encode" "GSM610/gsm_option" "GSM610/long_term" "GSM610/lpc" "GSM610/preprocess" "GSM610/rpe" "GSM610/short_term" "GSM610/table" "G72x/g721" "G72x/g723_16" "G72x/g723_24" "G72x/g723_40" "G72x/g72x")) (setf nylsffiles-h '("common" "config" "float_cast" "sfconfig" "endian" "sf_unistd" "sndfile" "wav_w64" "GSM610/gsm610_priv.h" "GSM610/gsm.h" "G72x/g72x.h" "G72x/g72x_priv.h")) (defun insert-separator (pre sep lis) (mapcar #'(lambda (pair) (cond ((= (length pair) 2) (strcat pre (car pair) sep (cadr pair) ".h")) (t (strcat (car pair) pre (cadr pair) sep (caddr pair) ".h")))) lis)) ;; COMMAND-PREFIX -- insert prefix before each file ;; (defun command-prefix (prefix lis) (mapcar #'(lambda (item) (list prefix item)) lis)) (defun fix-sndwritepa (lis) ;; exception: sndwritepa.h -> sndwrite.h (mapcar #'(lambda (f) (cond ((equal f "sndwritepa") "sndwrite") (t f))) lis)) ;; COMMAND-FILELIST -- build files for command line ;; (defun command-filelist (prefix separator) (let () (setf filelist '(("snd" "snd"))) (setf filelist (append filelist (command-prefix "nyqsrc" (fix-sndwritepa nyqsrcfiles)))) (display "after nyqsrc" filelist nyqsrcfiles) (setf filelist (append filelist '(("~" "nyqsrc" "sndheader")))) (setf filelist (append filelist (command-prefix "tran" transfiles))) (cons (strcat prefix "nyqsrc" separator "sndfnint") (insert-separator prefix separator filelist)))) ;; COMMANDLINE -- build sndfn.cl and sndfn.wcl for mac and windows ;; versions of intgen; the files will be written to current directory ;; (defun commandline () (princ "Your current directory should be nyquist, and you should have\n") (princ "just evaluated (load \"misc/makefile\") and (commandline).\n") (load "misc/transfiles") ;; get current versions of transfiles and nyqsrcfiles (let (filelist outf) (setf filelist (command-filelist "" "\\")) (setf outf (open "sndfn.wcl" :direction :output)) (write-file-list outf filelist #\ ) (close outf) ; now do the mac (setf filelist (command-filelist "" "/")) (setf outf (open "sndfn.cl" :direction :output)) (write-file-list outf filelist #\ ) (close outf) (princ "On Mac OS-X, you should now (exit) nyquist, and at the commandline\n") (princ "run macosxproject/build/Development/intgen @sndfn.cl\n") (princ "updates to sndfn.cl and sndfn.wcl should be moved to nyqsrc\n") )) ;; MAKEALL - makes all makefiles and copies them to nyqsrc ;; ;; run this in nyquist/src ;; (defun makeall () ; (makesrc) ; (system "cp -p Makesrc nyqsrc") (dolist (m system-types) (setf system-type m) (setf m (string-downcase (symbol-name m))) (init-sndfiles) (makefile))) ;; MAKE-AUDIO-NAME -- (strcat "audio" system-name) ;; jlh1 is audiooss something I need to track down and consider changing? (defun make-audio-name (system-name) (cond ((eq system-type 'linux) "audiooss") (t (strcat "audio" system-name)))) ;; MAKE-SND-NAME -- (strcat "audio" system-name) (defun make-snd-name (system-name) (strcat "snd" system-name)) ;; MAKEFILE - creates a Makefile from a list of sources ;; ;; reads sources from transfiles.lsp ;; ********************************************************* ;; CHANGED. PJM July 2007 ;; JAVASRC separators must be double bar \\ ;; Added onlyny: to compile only Nyquist. javac not needed ;; ********************************************************* (defun makefile () (let (system-name outf outf-name) (load "misc/transfiles.lsp") ; just to make sure we're current (while (null system-type) (format t "Write Makefile for what system? One of:~A~%" system-types) (setf system-type (read)) (cond ((not (member system-type system-types)) (format t "Unknown system type.~%") (setf system-type nil)))) (setf system-name (string-downcase (symbol-name system-type))) (setf outf-name (strcat "sys/unix/" system-name "/Makefile")) (format t "Opening for output: ~A\n" outf-name) (setf outf (open outf-name :direction :output)) (cond ((null outf) (error "could not open output file" outf-name))) (setf sndfiles (cons (make-audio-name system-name) (cons (make-snd-name system-name) sndfiles))) (format outf "# # Makefile for Nyquist, SYSTEM-TYPE is ~A # run make in the top-level Nyquist directory to compile Nyquist # # NOTE: this file is machine-generated. DO NOT EDIT! # Instead, modify makefile.lsp and regenerate the makefile. # Ports and bug fixes are welcome - please mail them to # dannenberg@cs.cmu.edu. Thanks. # # This is the resulting executable (normally \"ny\"): NY = ~A OPT = -O2 -m32 # OPT = -g -m32 EVERYTHING = $(NY) runtime/system.lsp jnyqide/jNyqIDE.jar \\ bin/ser-to-osc bin/test-client CURRENT = $(EVERYTHING) current: $(CURRENT) onlyny: $(NY) runtime/system.lsp JAVASRC = jnyqide/browser.java jnyqide/NyquistThread.java \\ jnyqide/Pair.java jnyqide/BareBonesBrowserLaunch.java \\ jnyqide/EnvelopeFrame.java jnyqide/Piano_Roll.java \\ jnyqide/FindDialog.java jnyqide/PlotFrame.java \\ jnyqide/InstrumentCharacteristics.java \\ jnyqide/PlotMouseAdapter.java \\ jnyqide/Jslide.java jnyqide/PopupListener.java \\ jnyqide/LispFileFilter.java jnyqide/PreferencesDialog.java \\ jnyqide/MainFrame_AboutBox.java jnyqide/ReplaceDialog.java \\ jnyqide/MainFrame.java jnyqide/SpringUtilities.java \\ jnyqide/Main.java \\ jnyqide/NotFoundDialog.java jnyqide/TextColor.java \\ jnyqide/NyqPlot.java jnyqide/Trie.java \\ jnyqide/NyquistFile.java jnyqide/WordList.java jnyqide/jNyqIDE.jar: $(JAVASRC) if [ -r jnyqide/SpecialMacHandler.java ] ; then \\ mv jnyqide/SpecialMacHandler.java jnyqide/SpecialMacHandler.hidden ;\\ fi cd jnyqide; javac *.java mv jnyqide/SpecialMacHandler.hidden jnyqide/SpecialMacHandler.java rm -rf jnyqide/jNyqIDE.jar jar -cfm jnyqide/jNyqIDE.jar jnyqide/manifest.txt jnyqide/*.class # Standard list of includes (common to all unix versions) # Keeping portaudio and libsndfile sources local to nyquist INCL = -Inyqsrc -Itran -Ixlisp -Isys/unix -Icmt -Iffts/src \\ -Inyqstk/include -Inyqstk -Iportaudio/include -Iportaudio/src/common \\ -Iportaudio/src/os/unix \\ -Iliblo -Inylsf # system dependent stuff for ~A: ~A INTGEN = misc/intgen # Object files for Nyquist: " system-type target-file system-name (system-defs)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (object-files outf) (format outf "# Sound functions to add to xlisp~%") (nyqheaders outf) (cmtheaders outf) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (format outf " bin: \tmkdir bin liblo/Makefile: \tcd liblo; ./configure CFLAGS=-m32 LDFLAGS=-m32 CXXFLAGS=-m32 --enable-static --disable-shared \t# sometimes, residual files cause problems \tcd liblo; make clean $(LIBLO_PATH)/liblo.a: liblo/Makefile \tcd liblo; make bin/ser-to-osc: bin $(LIBLO_PATH)/liblo.a \t$(CC) -c $(CFLAGS) liblo/ser-to-osc/ser-to-osc.cpp \\ \t -o liblo/ser-to-osc/ser-to-osc.o \t$(LN) liblo/ser-to-osc/ser-to-osc.o -o bin/ser-to-osc $(LFLAGS) bin/test-client: bin $(LIBLO_PATH)/liblo.a \t$(CC) -c $(CFLAGS) liblo/test-client/test-client.c \\ \t -o liblo/test-client/test-client.o \t$(LN) liblo/test-client/test-client.o -o bin/test-client $(LFLAGS) portaudio/Makefile: \t# note: without-jack avoids 32/64-bit link error on Debian \tcd portaudio; ./configure CFLAGS=-m32 LDFLAGS=-m32 CXXFLAGS=-m32 --enable-static --disable-shared --without-jack \t# sometimes, residual files cause problems \tcd portaudio; make clean $(LIBPA_PATH)/libportaudio.a: portaudio/Makefile \tcd portaudio; make $(NY): $(OBJECTS) $(LIBPA_PATH)/libportaudio.a $(LIBLO_PATH)/liblo.a \t$(LN) $(OBJECTS) $(LFLAGS) -o $(NY) # copy appropriate system.lsp and make it read-only; # changes should be made to sys/unix//system.lsp runtime/system.lsp: sys/unix/~A/system.lsp \t# make sure it's there before you make it writeable \ttouch runtime/system.lsp \tchmod +w runtime/system.lsp \tcp -p sys/unix/~A/system.lsp runtime/system.lsp \tchmod -w runtime/system.lsp " system-name system-name) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (dependencies outf system-name) (format outf (system-rules)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (format outf "misc/intgen: misc/intgen.c \tcd misc; make intgen misc/unpacker: misc/unpacker.c misc/convert.c \tcd misc; make unpacker misc/packer: misc/packer.c misc/convert.c \tcd misc; make packer nyqsrc/sndfnintptrs.h: $(NYQHDRS) misc/intgen \t$(INTGEN) nyqsrc/sndfnint $(NYQHDRS) nyqsrc/seqfnintptrs.h: $(CMTHDRS) misc/intgen \t$(INTGEN) nyqsrc/seqfnint $(CMTHDRS) clean: \tcd misc; make clean \tcd liblo; test -f Makefile && make clean || true \tcd portaudio; test -f Makefile && make clean || true \trm -f $(OBJECTS) # These could be deleted, but they're part of the release, so we won't # Note that these files are machine-generated: # \trm -f nyqsrc/sndfnintptrs.h nyqsrc/sndfnint.c nyqsrc/sndfnintdefs.h # \trm -f nyqsrc/seqfnintptrs.h nyqsrc/seqfnint.c nyqsrc/seqfnintdefs.h cleaner: clean \tcd misc; make cleaner \trm -f *.backup */*.backup \trm -f *~~ */*.*~~ \trm -f #*# */#*# \trm -f *.save */*.save \trm -f *.CKP */*.CKP \trm -f *.BAK */*.BAK \trm -f *.old */*.old \trm -f *.gold */*.gold \trm -f playparms \trm -f points.dat \trm -f core.* core \trm -f $(NY) release: cleaner \tcd misc; make packer \tmisc/packer files.txt release.pac \trm -f *.wav \tmv ny .. \tmv -f *.pac .. \trm -f unpacker \trm -f packer \tcd ..; zip -r nyquist.zip nyquist \t../ny misc/cmu/cmu-linux-install.lsp \tmv ../ny ./ny ") (cond ((eq system-type 'rs6k) (format outf " tar: cleaner \tsh -v sys/unix/cmu/tar.script backup: cleaner \tsh -v sys/unix/cmu/backup.script "))) (close outf) )) ;; system-defs looks for a string of system-dependent defs for the makefile ;; (defun system-defs () (system-var "-DEFS")) ;; system-rules looks for a string of system-dependent rules for the makefile ;; (defun system-rules () (system-var "-RULES")) ;; system-var returns a string stored in the variable (if any): ;; - ;; (defun system-var (suffix) (let ((v (intern (strcat (symbol-name system-type) suffix)))) (cond ((boundp v) (symbol-value v)) (t "")))) (defun fix-sndsliders (lis) (remove "sndsliders" lis :test #'string=)) ;; object-files - writes names of all object files for linking ;; (defun object-files (outf) (let ((flist (append (add-prefix "xlisp/" xlfiles) (add-prefix "tran/" transfiles) (add-prefix "cmt/" cmtfiles) (add-prefix "nylsf/" nylsffiles) (add-prefix "nyqsrc/" nyqfiles) (add-prefix "nyqsrc/" (fix-sndsliders nyqsrcfiles)) ; pjm January 2008 (add-prefix "nyqstk/src/" stksrcfiles) (add-prefix "nyqstk/" stkfiles) (add-prefix "ffts/src/" fftfiles) (add-prefix "nyqsrc/" intfiles) ;(add-prefix "snd/" sndfiles) '("sys/unix/osstuff" "sys/unix/term")))) (setf flist (add-suffix flist ".o")) (format outf "OBJECTS = ") (write-file-list outf flist #\\))) ;; add-prefix - place string at beginning of each string in list ;; (defun add-prefix (prefix lis) (mapcar #'(lambda (str) (strcat prefix str)) lis)) ;; add-suffix - place string at end of each string in list ;; (defun add-suffix (lis suffix) (mapcar #'(lambda (str) (strcat str suffix)) lis)) ;; write-file-list - write file names to Make macro ;; (defun write-file-list (outf flist continuation-char) (while flist (dotimes (i 2) (format outf "~A " (car flist)) (setf flist (cdr flist)) (if (null flist) (return))) (if flist (format outf " ~A~%\t" continuation-char))) (format outf "~%~%")) (defun nyqheaders (outf) (let ((flist (append (list "nyqsrc/sndfmt" "nylsf/sndfile") (add-prefix "nyqsrc/" (fix-sndwritepa nyqsrcfiles)) (add-prefix "tran/" transfiles)))) (setf flist (mapcar #'(lambda (f) (strcat f ".h")) flist)) (format outf "NYQHDRS = ") (write-file-list outf flist #\\))) (defun cmtheaders (outf) (let ((flist (append '("cmt/seqdecls" "nyqsrc/seqext" "cmt/seq" "nyqsrc/seqinterf") ; order is important here! (add-prefix "cmt/" '("seqread" "seqmread" "seqwrite" "seqmwrite"))))) (setf flist (add-suffix flist ".h")) (format outf "CMTHDRS = ") (write-file-list outf flist #\\))) (defun dependencies (outf system-name) ;; this forces generation of sndfnintdefs.h, seqfnintdefs.h: (dolist (f (append (add-prefix "nyqsrc/" nyqsrcfiles) (add-prefix "nyqsrc/" nyqfiles) ;(add-prefix "snd/" sndfiles) (add-prefix "ffts/src/" fftfiles) (add-prefix "tran/" transfiles) (add-prefix "nyqsrc/" intfiles))) (let ((ex (assoc f depends-exceptions :test #'equal))) (cond ((and ex (cdr ex)) (format outf "~A.o: ~A.c ~A~%" f f (cadr ex)) (format outf "\t$(CC) -c ~A.c -o ~A.o $(CFLAGS)~%~%" f f)) (t (format outf "~A.o: ~A.c ~A.h nyqsrc/sound.h nyqsrc/falloc.h nyqsrc/cque.h~%" f f f) (format outf "\t$(CC) -c ~A.c -o ~A.o $(CFLAGS)~%~%" f f))))) (dolist (f stkfiles) (format outf "nyqstk/~A.o: nyqstk/~A.cpp nyqstk/~A.h~%" f f f) (format outf "\tg++ -c nyqstk/~A.cpp -o nyqstk/~A.o $(CFLAGS)~%~%" f f)) (dolist (f stksrcfiles) (format outf "nyqstk/src/~A.o: nyqstk/src/~A.cpp nyqstk/include/~A.h~%" f f f) (format outf "\tg++ -c nyqstk/src/~A.cpp -o nyqstk/src/~A.o $(CFLAGS)~%~%" f f)) (format outf "xlisp/xlftab.o: nyqsrc/sndfnintptrs.h nyqsrc/sndfnintdefs.h") (format outf " nyqsrc/seqfnintptrs.h nyqsrc/seqfnintdefs.h~%") (format outf "\t$(CC) -c xlisp/xlftab.c -o xlisp/xlftab.o $(CFLAGS)~%~%") (dolist (f (append (add-prefix "xlisp/" xlfiles) (add-prefix "cmt/" cmtfiles) (add-prefix "nylsf/" nylsffiles) '("sys/unix/osstuff"))) (cond ((and (not (equal f "xlisp/xlftab")) ; special case handled above (not (and (equal f "xlisp/xljump") ; case handled below (equal system-name "next")))) (format outf "~A.o: ~A.c~%\t$(CC) -c ~A.c -o ~A.o $(CFLAGS)~%~%" f f f f))))) ;;=================================================== ;; SYSTEM DEPENDENCIES ;;=================================================== (setf rs6k-defs " MIDI = /afs/cs/project/music/rs6k/midilib CC = cc # change -g to -O for optimization # to enable command line editing, add -DREADLINE CFLAGS = -DCMTSTUFF -g $(INCL) -I$(MIDI) XFLAGS = $(CFLAGS) -qlanglvl=extended LN = xlc -qattr -qlist # to enable command line editing, add -lreadline -lcurses LFLAGS = -lm -lpthread -L$(MIDI) -lmidi -lbsd -lg ") (setf next-defs " CC = cc # to enable command line editing, insert -DREADLINE CFLAGS = -DCMTSTUFF -O $(INCL) LN = cc # to enable command line editing, insert -lreadline -lcurses LFLAGS = -lm -lpthread ") (setf next-rules " # this doesn't compile with the -O switch (a NeXT compiler bug?) xlisp/xljump.o : xlisp/xljump.c xlisp/xlisp.h \t$(CC) -DCMTSTUFF -c xlisp/xljump.c -o xlisp/xljump.o ") (setf pmax-defs " CC = cc # to enable command line editing, insert -DREADLINE CFLAGS = -DCMTSTUFF -g $(INCL) LN = cc # to enable command line editing, insert -lreadline -lcurses LFLAGS = -lm ") (setf sgi-defs " CC = cc # to enable command line editing, insert -DREADLINE CFLAGS = -DCMTSTUFF -g $(INCL) LN = cc # to enable command line editing, insert -lreadline -lcurses LFLAGS = -lm -lpthread # you would need -lmd if UNIX_IRIX_MIDIFNS were defined in midifns.c ") (setf sparc-defs " CC = gcc # to enable command line editing, insert -DREADLINE CFLAGS = -DCMTSTUFF -g $(INCL) LN = g++ # to enable command line editing, insert -lreadline -lcurses LFLAGS = -lm -lpthread ") ;; this is the general plan for linux, but Debian cannot link with -lasound, ;; so to this string you need to prepend a definition for AUDIOLIBS which ;; has extra link directives for audio libraries, e.g. -lasound (see below) (setf linux-defs " CC = gcc LIBPA_PATH = portaudio/lib/.libs LIBLO_PATH = liblo/src/.libs # to enable command line editing, use -DREADLINE. WARNING: THIS WILL # DISABLE THE ABILITY TO INTERRUPT LISP AND USE SOME OTHER HANDY # CONTROL CHARACTERS (You will also need the readline and curses libraries) CFLAGS = -DOSC -DCMTSTUFF $(OPT) $(INCL) \\ -DHAVE_LIBPTHREAD=1 -D_FILE_OFFSET_BITS=64 \\ -DSTK_NYQUIST -DUSE_VSPRINTF \\ -DHAVE_CONFIG_H LN = g++ -m32 AR = ar # to enable command line editing, insert -lreadline -lcurses LFLAGS = $(LIBPA_PATH)/libportaudio.a $(LIBLO_PATH)/liblo.a $(AUDIOLIBS) -lm -lpthread -lrt TAGS: find . \( -name "*.c" -o -name "*.h" \) -print | etags - tags: TAGS ") (setf alsa-defs (strcat " AUDIOLIBS = -lasound " linux-defs)) (setf nonalsa-defs (strcat " AUDIOLIBS = " linux-defs)) nyquist-3.05/misc/packer.dsp0000644000175000000620000001032711466723256015112 0ustar stevestaff# Microsoft Developer Studio Project File - Name="packer" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=packer - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "packer.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "packer.mak" CFG="packer - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "packer - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "packer - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "packer - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "packer_Release" # PROP Intermediate_Dir "packer_Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\cmt" /I "..\sys\win\msvc" /I "../cmt" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "packer - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "packer___Win32_Debug" # PROP BASE Intermediate_Dir "packer___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "packer_Debug" # PROP Intermediate_Dir "packer_Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\cmt" /I "..\sys\win\msvc" /I "../cmt" /D "_CONSOLE" /D "_MBCS" /D "WIN32" /D "_DEBUG" /D "DEBUG_INPUT" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "packer - Win32 Release" # Name "packer - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\convert.c # End Source File # Begin Source File SOURCE=.\packer.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\..\nyquist21\misc\convert.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nyquist-3.05/misc/intgen.c0000644000175000000620000007157611466723256014602 0ustar stevestaff/* intgen.c -- an interface generator for xlisp */ /* (c) Copyright Carnegie Mellon University 1991 * For a statement of limited permission to use, see Permission.doc * * HISTORY * * 5-Jul-95 Roger Dannenberg * strip directory prefixes from files before writing include statements * 24-Oct-88 Roger Dannenberg at CMU * Changed so that if C routine returns void and has result parameters, * then result parameters are returned by the lisp subr as well as * assigned to *RSLT*. * * 13-Apr-88 Roger Dannenberg at CMU * Modified for xlisp version 2.0 * * 22-Dec-87 Roger Dannenberg at NeXT * Added FILE type. * * 21-May-87 Dale Amon at CMU CSD * Included use of NODE *s_true under SCORE_EDITOR conditional. Standard * xlisp code use NODE *true instead. * * 13-May-87 Dale Amon at CMU CSD * Added conditional compilation switch SCORE_EDITOR so that this * program will work with both standard XLISP sources and with Roger's * (ahem) modified version. Also put in error checking for case where * user does not specifiy an output file so program will exit instead * of coredump. */ /* Summary and Design: (NOTE THAT AN INTGEN MANUAL IS AVAILABLE) * The first command line argument gives the name of * the .c file to generate. All following arguments are * .h files to read and use as interface specifications. * * The main program opens the output file, calls * write_prelude, and then process_file for each input * file. Then call write_postlude and close the file. * * process_file opens an input file and reads each line * into current_line. * if the first characters of the file are "ih", then * the rest of the file is processed as normal, except the * .h extension of the file is replaced by .ih before the * filename is written into an include statement in the * output file. This is done to handle ".ih" files generated * by the Andrew Toolkit Class processor. * In any case, the first line of EVERY .h file is discarded. * If #define is found, save the following identifier as * macro_name. * If "LISP:" is found, then see if it is preceded by one * or two identifiers and an open paren. * If yes, call routine_call, * else call macro_call. * * routine_call gets the first one or two identifiers off the * line into type_name and routine_name. If there is just one id, * assign it to routine_name and make type_name = "void". * If the routine_name starts with *, remove the * from * routine_name and append "*" to type_name. * Call write_interface with type_name, routine_name, and location * of parameter type description after "LISP:". * * macro_call gets a type_name from the input line after * "LISP:". * Then call write_interface with type_name, macro_name, and * location of parameter type description. * * lisp function names are saved in a table, and an * initialization routine is written to install the new * SUBRs into the xlisp symbol table, as well as to lookup * RSLT_sym, the atom on which results are placed * * */ /* Turn on special handling for Roger's Score Editor if the following #define * is uncommented: */ /* #define SCORE_EDITOR */ /* Turn on special handling for Chris's Sound Editor if the following #define * is uncommented: */ /* #define SOUND_EDITOR */ /* Turn on special handling for Nyquist if the following #define * is uncommented: */ #define NYQUIST /* atom 't is named s_true if this is defined, o.w. named true: */ #define S_TRUE 1 /* Turn on special handling for CMU MIDI Toolkit seq_type: */ #define SEQ_TYPE #define errfile stdout #define ident_max 100 #define line_max 200 #define subr_max 500 /* prefix for include files not to be included in interface module */ #define no_include_prefix '~' #define false 0 #define true 1 #include "switches.h" #include "stdlib.h" #include "cext.h" #include #ifndef boolean typedef int boolean; #endif #include "stdio.h" #include "ctype.h" #include "cmdline.h" #ifdef MACINTOSH #include "console.h" #endif #ifdef MACINTOSH #define FILESEP ':' #else #ifdef WINDOWS #define FILESEP '\\' #else #define FILESEP '/' #endif #endif static char *sindex(); #define whitep(c) ((c) == ' ' || (c) == '\t') #define symbolp(c) (isalpha(c) || (c) == '*' || (c) == '_' || (c) == '-' ||\ (c) == ':' || isdigit(c) || (c) == '^' || (c) == '*') /* c and Lisp parameters are encoded in the same table. * Field type_id is the string name of the type. * For c types (return types of C routines), code is 'C', * convert gives the routine for making a lisp node from * the c datum. * listtype_or_special is "v" for types that should be * returned as LISP NIL (e.g. "void"), "s" for types * that when NULL should be returned as NIL, "r" * for normal types, and "" to raise an error. * ctype is not used and should be NULL. * For Lisp types (from parameter specs), code is 'L'. * convert gives the routine that extracts a C value * from a lisp node whose type is given by the field * getarg_or_special. * c_type is the type of the local C variable which is * passed as a parameter to the C routine. * initializer is the initial value for result only parameters * * End of table is marked by a NULL type_id. * * Location 0 is reserved to indicate errors. * Location 1 MUST BE type ANY * */ #define any_index 1 struct { char *type_id; char code; char *convert; char *getarg_or_special; char *ctype; char *makenode; char *initializer; } type_table[] = { {" ", ' ', NULL, NULL, NULL, NULL, NULL}, {"ANY", 'L', "", "", "LVAL", "", "NIL"}, {"ATOM", 'L', "", "xlgasymbol", "LVAL", "", "NIL"}, {"FILE", 'L', "getfile", "xlgastream", "FILE *", "cvfile", "NULL"}, {"FIXNUM", 'L', "getfixnum", "xlgafixnum", "long", "cvfixnum", "0"}, {"FIXNUM", 'L', "getfixnum", "xlgafixnum", "int", "cvfixnum", "0"}, {"FLOAT", 'L', "getflonum", "xlgaflonum", "float", "cvflonum", "0.0"}, {"FLONUM", 'L', "getflonum", "xlgaflonum", "double", "cvflonum", "0.0"}, {"ANYNUM", 'L', "testarg2", "xlgaanynum", "double", "cvflonum", "0.0"}, {"STRING", 'L', "getstring", "xlgastring", "unsigned char *", "cvstring", "NULL"}, {"BOOLEAN", 'L', "getboolean", "xlgetarg", "int", "cvboolean", "0"}, {"atom_type", 'C', "", "r", NULL, NULL, NULL}, {"LVAL", 'C', "", "r", NULL, NULL, "NIL"}, #ifdef SOUND_EDITOR /* Extensions for Sound Type: */ {"SOUND", 'L', "getsound", "xlgasound", "SoundPtr", "cvsound", "NULL"}, {"SoundPtr", 'C', "cvsound", "r", NULL, NULL, NULL}, #endif #ifdef NYQUIST {"SOUND", 'L', "getsound", "xlgasound", "sound_type", "cvsound", "NULL"}, {"sound_type", 'C', "cvsound", "r", NULL, NULL, NULL}, #endif #ifdef SEQ_TYPE {"SEQ", 'L', "getseq", "xlgaseq", "seq_type", "cvseq", "NULL"}, {"seq_type", 'C', "cvseq", "r", NULL, NULL, NULL}, /* look out! event_type is treated as void to eliminate * warning messages ... */ {"event_type", 'C', "", "v", NULL, NULL, NULL}, #endif #ifdef SCORE_EDITOR {"VALUE", 'L', "getval", "xlgaval", "value_type", "cvval", "NULL"}, {"value_type", 'C', "cvval", "r", NULL, NULL, NULL}, {"EVENT", 'L', "getevent", "xlgaevent", "event_type", "cvevent", "NULL"}, {"event_type", 'C', "cvevent", "r", NULL, NULL, NULL}, {"score_type", 'C', "cvevent", "r", NULL, NULL, NULL}, #endif #ifdef DMA_EXTENSIONS /* begin DMA entries */ {"DEXT", 'L', "getdext", "xlgadext", "ext_type", "cvdext", "NULL"}, {"DEXT", 'C', "cvdext", "r", NULL, NULL, NULL}, {"SEXT", 'L', "getsext", "xlgasext", "ext_type", "cvsext", "NULL"}, {"SEXT", 'C', "cvsext", "r", NULL, NULL, NULL}, /* end DMA entries */ #endif {"int", 'C', "cvfixnum", "r", NULL, NULL, NULL}, {"long", 'C', "cvfixnum", "r", NULL, NULL, NULL}, {"boolean", 'C', "cvboolean", "r", NULL, NULL, NULL}, {"float", 'C', "cvflonum", "r", NULL, NULL, NULL}, {"double", 'C', "cvflonum", "r", NULL, NULL, NULL}, {"string", 'C', "cvstring", "s", NULL, NULL, NULL}, {"char*", 'C', "cvstring", "s", NULL, NULL, NULL}, {"char", 'C', "cvfixnum", "r", NULL, NULL, NULL}, {"string_type", 'C', "cvstring", "s", NULL, NULL, NULL}, {"FILE*", 'C', "cvfile", "s", NULL, NULL, NULL}, {"void", 'C', "", "v", NULL, NULL, NULL}, /*eot*/ {NULL, ' ', NULL, NULL, NULL, NULL, NULL}}; /* subr names get saved here: */ char *subr_table[subr_max]; int subr_table_x; #define get_c_special(i) type_table[(i)].getarg_or_special[0] #define get_c_conversion(i) type_table[(i)].convert #define get_lisp_extract(i) type_table[(i)].convert #define get_lisp_getarg(i) type_table[(i)].getarg_or_special #define get_lisp_ctype(i) type_table[(i)].ctype #define get_lisp_makenode(i) type_table[(i)].makenode #define get_lisp_initializer(i) type_table[(i)].initializer static void lisp_code(); static int lookup(); static void process_file(); static void routine_call(); static void write_interface(); static void write_postlude(); static void write_prelude(); static void write_ptrfile(); char source_file[ident_max]; /* source file */ char current_line[4 * line_max]; /* current line in source file */ char out_file[ident_max]; /* output file name */ char ptr_file[ident_max]; /* ptr.h file name */ char def_file[ident_max]; /* def.h file name */ FILE *lispout = NULL; /* output for lisp source code (if any) */ #define EOS '\000' /* getarg -- get an identifier from a string */ /**/ int getarg(start, result, pos) char *start; /* where to start scanning */ char *result; /* where to put the identifier */ char **pos; /* ptr to char after identifier in source */ { *result = EOS; while (whitep(*start) && *start != EOS) start++; if (*start == EOS) return false; if (!symbolp(*start)) return false; while (symbolp(*start) && *start != EOS) { *result = *start; result++; start++; } *result = EOS; *pos = start; return true; } /* error() -- print source file and line */ /**/ void error() { fprintf(errfile, "\n%s: |%s|\n", source_file, current_line); } /* lisp_code -- write lisp code to file */ /* * read from inp if necessary until close comment found */ static void lisp_code(inp, s) FILE *inp; char *s; { char lisp[line_max]; char *endcomment; char *inputline; /* for end of file detection */ if (lispout == NULL) { char lisp_file_name[ident_max]; char *extension; strcpy(lisp_file_name, out_file); extension = sindex(lisp_file_name, ".c"); strcpy(extension, ".lsp"); /* overwrite .c with .lsp */ lispout = fopen(lisp_file_name, "w"); if (lispout == NULL) { fprintf(stdout, "Error: couldn't open %s\n", lisp_file_name); exit(1); } printf("writing %s ...\n", lisp_file_name); } strcpy(lisp, s); /* don't modify s */ inputline = lisp; while (inputline != NULL && (endcomment = sindex(lisp, "*/")) == NULL) { fputs(lisp, lispout); inputline = fgets(lisp, line_max, inp); } strcpy(endcomment, "\n\n"); fputs(lisp, lispout); } /* lookup -- find type data */ /**/ static int lookup(s, t) char *s; char t; { int i = 1; while (type_table[i].type_id != NULL) { if (type_table[i].code == t && strcmp(type_table[i].type_id, s) == 0) return i; i++; } return 0; } /* macro_call -- generate xlisp interface for C routine */ /**/ void macro_call(in, out, curline, macro_name, arg_loc) FILE *in; /* input file */ FILE *out; /* output file */ char *curline; /* input line */ char *macro_name; /* name of the macro to call */ char *arg_loc; /* location after "LISP:" */ { char type_name[ident_max]; if (!getarg(arg_loc, type_name, &arg_loc)) { error(); fprintf(errfile, "no type given for macro.\n"); } else { write_interface(in, out, type_name, macro_name, arg_loc, true); } } /* main -- generate an xlisp to c interface file */ /**/ int main(argc, argv) int argc; char *argv[]; { char *s; FILE *out; FILE *ptrfile; FILE *deffile; int n; #ifdef MACINTOSH argc = ccommand(&argv); #endif for (n = 0; n < subr_max; n++) { subr_table[n] = (char *) malloc(ident_max); subr_table[n][0] = EOS; } subr_table_x = 0; cl_init(NULL, 0, NULL, 0, argv, argc); if ((s = cl_arg(1)) != NULL) { strcpy(out_file, s); if (sindex(out_file, ".") == 0) strcat(out_file, ".c"); else fprintf(stderr, "1st command line argument should be a legal c identifier\n"); out = fopen(out_file, "w"); if (out == NULL) { fprintf(stdout, "Error: couldn't open %s\n", out_file); exit(1); } strcpy(ptr_file, s); strcat(ptr_file, "ptrs.h"); ptrfile = fopen(ptr_file, "w"); if (ptrfile == NULL) { fprintf(stdout, "Error: couldn't open %s\n", ptr_file); exit(1); } strcpy(def_file, s); strcat(def_file, "defs.h"); deffile = fopen(def_file, "w"); if (deffile == NULL) { fprintf(stdout, "Error: couldn't open %s\n", def_file); exit(1); } } else { fprintf(stdout, "Error: no output file specified\n"); exit(1); } printf("writing %s ...\n", out_file); write_prelude(out, out_file); n = 2; while ((s = cl_arg(n)) != NULL) { printf(" %s\n", s); process_file(s, out); n++; } write_postlude(out); fclose(out); write_ptrfile(ptrfile, deffile); fclose(ptrfile); fclose(deffile); if (lispout != NULL) fclose(lispout); return 0; } static void process_file(fname, out) char *fname; FILE *out; { FILE *in; char *cp; char *pos; char incl_file[ident_max]; /* name of file to include */ char type_name[ident_max]; /* the type of the routine */ char routine_name[ident_max]; /* the name of the routine or macro */ char flag = fname[0]; boolean reading_parameters = false; /* says we've got a routine, and we're skipping over parameter declarations */ if (flag == no_include_prefix) fname++; strcpy(source_file, fname); /* for error reporting */ in = fopen(fname, "r"); if (in == NULL) { fprintf(errfile, "couldn't open %s\n", fname); /* however, we still write the file as an #include ... */ fprintf(out, "#include \"%s\"\n\n", fname); return; } /* first check out the first line: if the first two characters are "ih", then replace fname with file.ih so that the CLASS ".ih" file will be included instead of this ".h" file. This is a hack to allow calls into Andrew Tool Kit objects. */ strcpy(incl_file, fname); if (fgets(current_line, line_max, in) != NULL) { if (current_line[0] == 'i' && current_line[1] == 'h') { cp = sindex(incl_file, ".h"); if (cp != NULL) { strcpy(cp, ".ih"); } } } /* strip off leading directory prefix, if any */ cp = strrchr(incl_file, FILESEP); /* find the last slash */ if (cp) { strcpy(incl_file, cp + 1 /* skip the slash */); } if (flag != no_include_prefix) fprintf(out, "#include \"%s\"\n\n", incl_file); while (fgets(current_line, line_max, in) != NULL) { cp = sindex(current_line, "#define"); if (cp != NULL) { cp += strlen("#define"); if (!getarg(cp, routine_name, &cp)) { error(); fprintf(errfile, "#define not followed by identifier\n"); } /* watch out for multi-line macros: */ while (sindex(current_line, "\\\n")) { if (fgets(current_line, line_max, in) == NULL) return; } } else if ((cp = sindex(current_line, "LISP:")) != NULL) { char type_str[ident_max]; char routine_str[ident_max]; if (!reading_parameters && getarg(current_line, type_str, &pos) && getarg(pos, routine_str, &pos) && pos < cp) { routine_call(in, out, current_line, type_str, routine_str, cp + strlen("LISP:")); } else if (getarg(cp + strlen("LISP:"), type_str, &pos)) { macro_call(in, out, current_line, routine_name, cp + strlen("LISP:")); } else routine_call(in, out, current_line, type_name, routine_name, cp + strlen("LISP:")); } else if ((cp = sindex(current_line, "LISP-SRC:")) != NULL) { lisp_code(in, cp + strlen("LISP-SRC:")); } else if (reading_parameters && sindex(current_line, ")")) { reading_parameters = false; } else if (reading_parameters) { /* skip */ ; } else if (getarg(current_line, type_name, &pos) && getarg(pos, routine_name, &pos)) { /* we grabbed the type and routine name. Check to see if the * parameter list is open but not closed on this line: */ if (sindex(current_line, "(") && !sindex(current_line, ")")) { reading_parameters = true; } /* printf("saw %s %s\n", type_name, routine_name);*/ } else { /* wipe out names for safety: */ type_name[0] = EOS; routine_name[0] = EOS; } } fclose(in); } /* routine_call -- generate xlisp interface for C routine */ /**/ static void routine_call(in, out, curline, type_name, routine_name, arg_loc) FILE *in; /* input file */ FILE *out; /* output file */ char *curline; /* input line */ char *type_name; /* type id */ char *routine_name; /* routine id */ char *arg_loc; /* location after "LISP:" */ { if (*routine_name == EOS) { routine_name = type_name; type_name = "void"; } if (*routine_name == '*') { char *r = routine_name; while (*r != EOS) { /* shift left */ *r = *(r+1); r++; } strcat(type_name, "*"); } write_interface(in, out, type_name, routine_name, arg_loc, false); } /* sindex -- find substring */ /**/ static char *sindex(sup, sub) char *sup; /* the containing string */ char *sub; /* the substring */ { int i; for ( ; *sup != EOS; sup++) { for (i = 0; true; i++) { if (*(sub+i) == EOS) return sup; if (*(sup+i) != *(sub+i)) break; } } return EOS; } /* write_interface -- write SUBR for xlisp */ /* * NOTE: if is_macro and there are no arguments, then * do not write parens: e.g. "foo" instead of "foo()" */ static void write_interface(in, out, type_name, fn_name, arg_loc, is_macro) FILE *in; /* input file */ FILE *out; /* output file */ char *type_name; /* c type for return value */ char *fn_name; /* c function to be called */ char *arg_loc; /* LISP arg type are described here */ int is_macro; /* true if this is a macro */ { char lispfn[ident_max]; /* lisp fn name */ char *cp; /* a temporary */ int len; /* a string length */ #define args_max 20 struct { int index; /* table location for this type */ int res_flag; /* is a result returned? */ } args[args_max]; char arg_type[ident_max]; /* the original type spec */ char *c_type; /* c type for an argument */ char *c_str; /* temp for a c code line */ int argcnt = 0; /* counts arguments */ int i; /* argument index */ int result_flag = false; /* true if there are result parameters */ int result_x; /* index of result type */ char newline[line_max]; /* place to read continuation lines */ /* printf("write_interface: %s %s %s", type_name, fn_name, arg_loc);*/ if (*type_name == EOS || *fn_name == EOS) { error(); fprintf(errfile, "Error: bad syntax, maybe missing type\n"); return; } while (*arg_loc != '(' && *arg_loc != EOS) arg_loc++; if (*arg_loc == EOS) { error(); fprintf(errfile, "Error: '(' expected after 'LISP:'\n"); return; } else arg_loc++; if (!getarg(arg_loc, lispfn, &arg_loc)) { error(); fprintf(stdout, "Error: lisp function name expected\n"); return; } /* make it upper case: */ for (cp = lispfn; *cp != EOS; cp++) { if (islower(*cp)) *cp = toupper(*cp); } /* save SUBR name */ strcpy(subr_table[subr_table_x], lispfn); subr_table_x++; /* make lispfn lower case, dash, colon -> underscore: */ for (cp = lispfn; *cp != EOS; cp++) { if (isupper(*cp)) *cp = tolower(*cp); if (*cp == '-' || *cp == ':') *cp = '_'; } /* append continuation lines to arg_loc to handle multi-line specs */ while (sindex(arg_loc, "*/") == NULL) { /* remove newline */ if (strlen(arg_loc) > 0) arg_loc[strlen(arg_loc) - 1] = EOS; if (fgets(newline, line_max, in) == NULL) { error(); fprintf(stdout, "Error: end of file unexpected\n"); exit(1); } if ((strlen(arg_loc) + strlen(newline)) > (3 * line_max)) { error(); fprintf(stdout, "Error: specification too long or missing end of comment.\n"); exit(1); } strcat(arg_loc, newline); } fprintf(out, "/%c xlc_%s -- interface to C routine %s */\n/**/\n", '*', lispfn, fn_name); fprintf(out, "LVAL xlc_%s(void)\n{\n", lispfn); while (getarg(arg_loc, arg_type, &arg_loc)) { int result_only_flag = false; if (argcnt >= args_max) { error(); fprintf(errfile, "Internal error: too many args, increase args_max\n"); } len = strlen(arg_type); if (arg_type[len-1] == '*') { arg_type[len-1] = EOS; args[argcnt].res_flag = true; result_flag = true; } else if (arg_type[len-1] == '^') { arg_type[len-1] = EOS; args[argcnt].res_flag = true; result_flag = true; result_only_flag = true; } else args[argcnt].res_flag = false; args[argcnt].index = lookup(arg_type, 'L'); c_type = get_lisp_ctype(args[argcnt].index); if (c_type == NULL) { error(); fprintf(errfile, "Error: %s undefined, using int.\n", arg_type); c_type = "int"; args[argcnt].index = lookup("FIXNUM", 'L'); } fprintf(out, " %s arg%d = ", c_type, argcnt+1); if (result_only_flag) { fprintf(out, "%s;\n", get_lisp_initializer(args[argcnt].index)); } else if (args[argcnt].index == any_index) { fprintf(out, "xlgetarg();\n"); } else { c_str = "%s(%s());\n"; fprintf(out,c_str, get_lisp_extract(args[argcnt].index), get_lisp_getarg(args[argcnt].index)); } argcnt++; } if (*arg_loc != ')') { fprintf(errfile, "Warning: paren expected immediately after last arg of %s\n", lispfn); } /* check for close paren and close comment: */ cp = sindex(arg_loc, ")"); if (cp == NULL || sindex(cp+1, "*/") == NULL) { error(); fprintf(errfile, "Warning: close paren and close comment expected\n"); } /* lookup result type */ result_x = lookup(type_name, 'C'); if (result_x == 0) { fprintf(errfile, "(Warning) unknown type: %s, assuming void\n", type_name); result_x = lookup("void", 'C'); } /* if there are result parameters then return them rather than NIL * when the type is void */ if (get_c_special(result_x) == 'v' && result_flag) { fprintf(out, " LVAL result;\n"); } if (get_c_special(result_x) != 'v') { /* declare result: */ fprintf(out, " %s result;\n", type_name); } /* check for end of argument list: */ fprintf(out, "\n xllastarg();\n"); /* if there are results, we'll call cons, so * protect the result from garbage collection * if necessary */ if (result_flag && strcmp(type_name, "LVAL") == 0) { fprintf(out, " xlprot1(result);\n"); } /* call the c routine */ if (get_c_special(result_x) != 'v') { fprintf(out, " result = "); } else fprintf(out, " "); fprintf(out, "%s", fn_name); if (!is_macro || argcnt > 0) fprintf(out, "("); /* pass arguments: */ for (i = 0; i < argcnt; i++) { if (i > 0) fprintf(out, ", "); if (args[i].res_flag) fprintf(out, "&"); fprintf(out, "arg%d", i+1); } if (!is_macro || argcnt > 0) fprintf(out, ")"); fprintf(out, ";\n"); /* put results (if any) on *RSLT* */ if (result_flag) { int wrote_one_flag = false; fprintf(out, " {\tLVAL *next = &getvalue(RSLT_sym);\n"); for (i = 0; i < argcnt; i++) { if (args[i].res_flag) { if (wrote_one_flag) fprintf(out, "\tnext = &cdr(*next);\n"); wrote_one_flag = true; fprintf(out, "\t*next = cons(NIL, NIL);\n"); fprintf(out, "\tcar(*next) = %s(arg%d);", get_lisp_makenode(args[i].index), i+1); } } fprintf(out, "\n }\n"); /* copy *RSLT* to result if appropriate */ if (get_c_special(result_x) == 'v') { fprintf(out, " result = getvalue(RSLT_sym);\n"); } } /* generate xlpop() if there was an xlprot1() */ if (result_flag && strcmp(type_name, "LVAL") == 0) { fprintf(out, " xlpop();\n"); } /* now return actual return value */ if (get_c_special(result_x) == EOS) { error(); fprintf(errfile, "Warning: unknown type from C, coercing to int.\n"); fprintf(out, " return cvfixnum((int) result);\n"); } else if (get_c_special(result_x) == 'v' && !result_flag) { fprintf(out, " return NIL;\n"); } else if (get_c_special(result_x) == 'v' && result_flag) { fprintf(out, " return result;\n"); } else if (get_c_special(result_x) == 's') { fprintf(out, " if (result == NULL) return NIL;\n"); fprintf(out, " else return %s(result);\n", get_c_conversion(result_x)); } else { fprintf(out, " return %s(result);\n", get_c_conversion(result_x)); } fprintf(out, "}\n\n\n"); } /* write_postlude -- write stuff at end of file */ /**/ static void write_postlude(out) FILE *out; { /* nothing to do for version 2 */ } /* write_ptrfile -- write function definition table */ /**/ static void write_ptrfile(pf, df) FILE *pf; FILE *df; { int n; char *cp; char cname[ident_max]; for (n = 0; n < subr_table_x; n++) { strcpy(cname, subr_table[n]); /* make cname lower case, dash,colon -> underscore: */ for (cp = cname; *cp != EOS; cp++) { if (isupper(*cp)) *cp = tolower(*cp); if (*cp == '-' || *cp == ':') *cp = '_'; } fprintf(df, "extern LVAL xlc_%s(void);\n", cname); fprintf(pf, " { \"%s\", S, xlc_%s}, \n", subr_table[n], cname); } printf(" Add %s to localdefs.h and add %s to localptrs.h\n", def_file, ptr_file); } /* write_prelude -- write stuff at head of file */ /**/ static void write_prelude(out, out_file) FILE *out; char *out_file; { int i = 2; int col = strlen(out_file) + 21; char *s; fprintf(out, "/%c %s -- interface to ", '*', out_file); while ((s = cl_arg(i)) != NULL) { if (i > 2) { fprintf(out, ", "); col += 2; } col += strlen(s) + 2; if (col > 65) { fprintf(out, "\n * "); col = 4 + strlen(s) + 2; } fprintf(out, "%s", s); i++; } fprintf(out, " */\n\n%cifndef mips\n%cinclude \"stdlib.h\"\n", '#', '#'); fprintf(out, "%cendif\n%cinclude \"xlisp.h\"\n\n", '#', '#'); #ifdef S_TRUE fprintf(out, "extern LVAL s_true;\n"); fprintf(out, "%cdefine cvboolean(i) ((i) ? s_true : NIL)\n", '#'); #else fprintf(out, "extern LVAL true;\n"); fprintf(out, "%cdefine cvboolean(i) ((i) ? true : NIL)\n", '#'); #endif fprintf(out, "%c%s\n", '#', "define testarg2(e) (moreargs() ? (e) : (getflonum(xltoofew())))"); fprintf(out, "%c%s\n%s\n%s\n", '#', "define xlgaanynum() (floatp(*xlargv) ? getflonum(nextarg()) : \\", " (fixp(*xlargv) ? (double) getfixnum(nextarg()) : \\", /* note: getflonum never gets called here, but this makes typechecking happy */ " getflonum(xlbadtype(*xlargv))))"); fprintf(out, "%cdefine getboolean(lval) ((lval) != NIL)\n\n", '#'); fprintf(out, "extern LVAL RSLT_sym;\n\n\n"); } nyquist-3.05/misc/cext.h0000644000175000000620000000020610144436365014236 0ustar stevestaff/* cext.h -- extensions to c */ #define true 1 #define false 0 #define private static #define boolean int #define byte unsigned char nyquist-3.05/misc/stdefs2.h0000644000175000000620000000276210144436365014656 0ustar stevestaff/* * FILE: stdefs.h * BY: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu) * DESC: Defines standard stuff for inclusion in C programs. * * 1.0 ( 6-JUN-88) - created. (cf0v) * 1.1 (30-JUN-88) - moved GetUHWORD def here. (cf0v) * 1.2 (11-JUL-88) - added ffail() defs. (cf0v) * 1.3 (25-JUL-88) - added dB() and undB() defs. (cf0v) * 1.4 ( 8-AUG-88) - added stuff used by apple & new NULL def. (cf0v) */ /* General purpose constants: */ /* #define TRUE 1 #define FALSE 0 */ #define FATAL 1 #define WARN 0 #define PI (3.14159265358979232846) #define PI2 (6.28318530717958465692) #define D2R (0.01745329348) /* (2*pi)/360 */ #define R2D (57.29577951) /* 360/(2*pi) */ /* General purpose typedefs: */ typedef int bool; typedef char BOOL; typedef short HWORD; typedef unsigned short UHWORD; typedef int WORD; typedef unsigned int UWORD; /* General purpose macros: */ #define GetUHWORD(x,y,z) GetUShort(x,y,z) #define ffail(x,y) fail(sprintf(ERROR,x,y)) #define ffail2(x,y,z) fail(sprintf(ERROR,x,y,z)) #define MAX(x,y) ((x)>(y) ?(x):(y)) #define MIN(x,y) ((x)<(y) ?(x):(y)) #define ABS(x) ((x)<0 ?(-(x)):(x)) #define SGN(x) ((x)<0 ?(-1):((x)==0?(0):(1))) #define round(x) ((int)((x) + 0.5)) /* Convert amplitudes to and from dB scale: */ #define MINLIN undB(-100) #define undB(x) (((double)(REF)) * pow(10.0, ((double)(x))/20.0)) #define dB(x) (((x) 127) { fprintf(stderr, "non-ascii char 0x%x in %s.\n", c, convname); exit(1); } else if (c == '\n') { putc(c, outf); line_len = 0; pack_newline(inf, outf, &line_len); } else if (c == '$') { putc('$', outf); putc('$', outf); line_len += 2; } else if (c < 32) { putc('$', outf); putc('@' + c, outf); line_len += 2; } else { putc(c, outf); line_len++; } if (line_len > 70) { putc('$', outf); putc('\n', outf); line_len = 0; } } if (line_len) { fprintf(stderr, "missing newline added to the end of %s\n", convname); putc('\n', outf); if (PAUSE) getchar(); } /* printf("closing %lx\n", inf); */ fclose(inf); } /* pack_binary -- open binary filename and append its encoding to outf */ /**/ void pack_binary(filename, convname, outf) char *filename; char *convname; FILE *outf; { int line_len = 0; int c; long data; int n; FILE *inf; boolean isbinary = false; inf = fopen(convname, "rb"); /* printf("opened %lx\n", inf); */ if (!inf) { fprintf(stderr, "Couldn't open |%s| - skipped\n", convname); if (PAUSE) getchar(); return; } fprintf(outf, "#%s\n", filename); n = 0; data = 0; while ((c = getc(inf)) != EOF) { if (c > 127) isbinary = true; data = (data << 8) | c; n++; if (n == 3) { put_binary(data, outf); n = 0; data = 0; line_len += 4; if (line_len >= 70) { putc('\n', outf); line_len = 0; } } } if (n == 1) { data = data << 16; putc('0' + ((data >> 18) & 0x3F), outf); putc('0' + ((data >> 12) & 0x3F), outf); } if (n == 2) { data = data << 8; putc('0' + ((data >> 18) & 0x3F), outf); putc('0' + ((data >> 12) & 0x3F), outf); putc('0' + ((data >> 6) & 0x3F), outf); } putc('.', outf); putc('\n', outf); if (!isbinary) { fprintf(stderr, "%s seems to be an ascii file.\n", convname); if (PAUSE) getchar(); } /* printf("closing %lx\n", inf); */ fclose(inf); } /* pack_newline -- newline sequence encoding to outf */ /**/ void pack_newline(inf, outf, line_len) FILE *inf; /* input file */ FILE *outf; /* where to write output */ int *line_len; { int c; int count = 0; int outc; while (((c = getc(inf)) != EOF) && (c == '\n')) { count++; } while (count >= 10) { fprintf(outf, "9\n"); *line_len = 0; count -= 10; } if (count > 0) { fprintf(outf, "%c\n", '0' + count - 1); *line_len = 0; } /* now run-length encode leading blanks... */ count = 0; while (c != EOF) { if (c == ' ') count++; /* we no longer convert tabs to spaces... else if (c == '\t') count += TAB_WIDTH; */ else break; c = getc(inf); } if (c != EOF || count) { outc = 'A' + count; if (outc > '~') outc = '~'; putc(outc, outf); (*line_len) += 1; count -= (outc - 'A'); while (count > 0) { putc(' ', outf); (*line_len) += 1; count--; } } /* now do the rest of the line */ if (c != EOF) ungetc(c, inf); } /* put_binary -- write 3 binary bytes as 4 ascii bytes */ /**/ void put_binary(data, outf) long data; FILE *outf; { putc('0' + ((data >> 18) & 0x3F), outf); putc('0' + ((data >> 12) & 0x3F), outf); putc('0' + ((data >> 6) & 0x3F), outf); putc('0' + (data & 0x3F), outf); } nyquist-3.05/misc/filelist.c0000644000175000000620000001452510144436365015112 0ustar stevestaff/* filelist.c -- program to convert a DOS DIR listing into an input * file for the packer program * * To use the program, first run DIR *.* /s > ..\xxx * Then run filelist.exe ..\xxx files * to create "files" * Then you can run packer.exe files myproject.pac * to create the pac file. */ /* usage: filelist */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "cext.h" #include "cmdline.h" #define EOS '\0' FILE *inf; FILE *out; #ifdef MAYBE_THIS_IS_FOR_WIN95_DIRECTORY_LISTINGS /* findfilename -- look for pattern "*-*-*:* " in string */ /**/ int findfilename(char *line, char *rslt) { char *ptr; if (ptr = strchr(line, '-')) { if (ptr = strchr(ptr, '-')) { if (ptr = strchr(ptr, ':')) { if (ptr = strchr(ptr, ' ')) { strcpy(rslt, ptr + 1); if (strcmp(rslt, ".") == 0 || strcmp(rslt, "..") == 0 || strstr(line, "")) return 0; return 1; } } } } return 0; } #endif /* findfilename -- look for pattern "***:* " in string */ /* * NOTE: the is "/", part of the file date; ":" is in the file time * lines without these characters are not lines that contain filenames */ int findfilename(char *line, char *rslt) { char *ptr; if (ptr = strchr(line, '/')) { if (ptr = strchr(ptr + 1, '/')) { if (ptr = strchr(ptr + 1, ':')) { if (ptr = strrchr(line, ' ')) { // now ptr points to space before filename strcpy(rslt, ptr + 1); // make sure this is not directory if (strstr(line, "")) return 0; return 1; } } } } return 0; } int directory_filter(char *directory) { int skip = false;; if (strstr(directory, "WinDebug") != NULL) skip = true; if (strstr(directory, "trash") != NULL) skip = true; return skip; } /* fixup -- convert \ to / */ /**/ void fixup(char *s) { while (*s) { if (*s == '\\') *s = '/'; s++; } } /* giveup -- quit the program */ /**/ void giveup() { printf("Type return."); exit(1); } /* /* main -- */ /**/ int main(int argc, char **argv) { #define stringmax 128 char in_file[stringmax]; char out_file[stringmax]; char inline[stringmax]; char basedir[stringmax]; char filename[stringmax]; char directory[stringmax]; char wholename[stringmax]; char *s; int skip_directory = false; basedir[0] = 0; /* empty string */ cl_init(NULL, 0, NULL, 0, argv, argc); if ((s = cl_arg(1)) != NULL) { strcpy(in_file, s); inf = fopen(in_file, "r"); if (inf == NULL) { fprintf(stdout, "Error: couldn't open %s\n", in_file); exit(1); } } if ((s = cl_arg(2)) != NULL) { strcpy(out_file, s); out = fopen(out_file, "w"); if (out == NULL) { fprintf(stdout, "Error: couldn't open %s\n", out_file); exit(1); } } else { fprintf(stdout, "Error: no output file specified\n"); exit(1); } printf("writing %s ...\n", out_file); /* read a line at a time. * if the line has "Directory of", then * if you don't have base directory, grab it * otherwise search for base directory and grab remainder * if the line matches "*-*-*:* " then * grab remainder as filename * prepend directory and type ("a") and output */ while (fgets(inline, stringmax, inf)) { inline[strlen(inline) - 1] = EOS; /* remove newline at end */ if (inline[0] == EOS) continue; /* skip blank lines */ /* search for Directory */ s = strstr(inline, "Directory of "); if (s) { s += strlen("Directory of "); if (!basedir[0]) { strcpy(basedir, s); strcat(basedir, "\\"); /* append a slash to complete directory name */ strcpy(directory, ""); } else { s = strstr(s, basedir); if (!s) { printf("Expected %s at beginning of directory.\n"); printf("Input line: %s\n"); giveup(); } else { strcpy(directory, s + strlen(basedir)); fixup(directory); strcat(directory, "/"); } skip_directory = directory_filter(directory); } } else if (!skip_directory && findfilename(inline, filename)) { char type_of_file = 'a'; sprintf(wholename, "%s%s", directory, filename); /* strlwr(wholename); */ s = strchr(wholename, '.'); if (s) s++; else s = ""; if (strcmp(s, "nh") == 0 || strcmp(s, "rsrc") == 0 || strcmp(s, "dsp") == 0 || strcmp(s, "dsw") == 0 || strcmp(s, "cod") == 0 || strcmp(s, "tab") == 0 || strcmp(s, "pcm") == 0 || strcmp(s, "mp3") == 0 || strcmp(s, "mid") == 0 || strcmp(s, "aiff") == 0 || false) type_of_file = 'b'; if (strcmp(s, "pac") == 0 || strcmp(s, "ncb") == 0 || strcmp(s, "opt") == 0 || strcmp(s, "plg") == 0 || strcmp(s, "tar") == 0 || strcmp(s, "obj") == 0 || strcmp(s, "vcp") == 0 || strcmp(s, "exe") == 0 || strcmp(s, "vcp") == 0 || strcmp(s, "pdb") == 0 || strcmp(s, "sbr") == 0 || strcmp(s, "ilk") == 0 || strcmp(s, "bsc") == 0 || /* this last one says "only .lsp files in runtime directory (strcmp(directory, "runtime/") == 0 && strcmp(s, "lsp") != 0) || */ strstr(directory, "CVS/") || false ) { /* do nothing */ } else { fprintf(out, "%c %s\n", type_of_file, wholename); } } } fclose(inf); fclose(out); return 0; } nyquist-3.05/misc/unpacker.dsp0000644000175000000620000001025611466723256015456 0ustar stevestaff# Microsoft Developer Studio Project File - Name="unpacker" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=unpacker - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "unpacker.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "unpacker.mak" CFG="unpacker - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "unpacker - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "unpacker - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "unpacker - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "unpacker_Release" # PROP Intermediate_Dir "unpacker_Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\cmt" /I "..\sys\win\msvc" /I "../cmt" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "unpacker - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "unpacker___Win32_Debug" # PROP BASE Intermediate_Dir "unpacker___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "unpacker_Debug" # PROP Intermediate_Dir "unpacker_Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\cmt" /I "..\sys\win\msvc" /I "../cmt" /D "_CONSOLE" /D "_MBCS" /D "WIN32" /D "_DEBUG" /D "DEBUG_INPUT" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "unpacker - Win32 Release" # Name "unpacker - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\convert.c # End Source File # Begin Source File SOURCE=.\unpacker.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nyquist-3.05/misc/transfiles.lsp0000644000175000000620000000570311466723256016031 0ustar stevestaff;; these are files in /tran that implement nyquist primitives ;; they become arguments to intgen, which builds the stubs from lisp to C ;; ;******************************************************************* ; CHANGED. PJM July 2007 ; Added new ALG files related to new STK instruments ;******************************************************************* (setf transfiles '("abs" "allpoles" "alpass" "alpasscv" "alpassvv" "amosc" "areson" "aresonvc" "aresoncv" "aresonvv" "atone" "atonev" "biquadfilt" "buzz" "chase" "clip" "congen" "const" "coterm" "delaycc" "delaycv" "eqbandvvv" "exp" "follow" "fmosc" "fromobject" "fromarraystream" "gate" "ifft" "instrclar" "instrclarall" "instrclarfreq" "instrsax" "instrsaxall" "instrsaxfreq" "integrate" "log" "lpreson" "maxv" "offset" "oneshot" "osc" "partial" "pluck" "prod" "pwl" "quantize" "recip" "reson" "resonvc" "resoncv" "resonvv" "sampler" "scale" "shape" "sine" "siosc" "slope" "sqrt" "tapf" "tapv" "tone" "tonev" "upsample" "white" "stkrev" "stkpitshift" "stkchorus" "instrbow" "instrbowedfreq" "instrbanded" "instrmandolin" "instrsitar" "instrmodalbar" "instrflute" "instrflutefreq" "instrfluteall" "fmfb" "fmfbv" )) ; deleted comb ;****************************************************************** ; CHANGES. PJM July 2007 ; nyqsrcfiles: DELETED "sndsliders" -> January 2008: now ADDED ; and fixed in makefile.lsp ; RENAMED "sndwrite" -> "sndwritepa" ; ADDED "lpanal" ;****************************************************************** ;; these are files in /nyqsrc that implement nyquist primitives ;; they become arguments to intgen, which builds the stubs from lisp to C ;; (setf nyqsrcfiles '("sound" "add" "avg" "compose" "convolve" "downsample" "fft" "inverse" "multiseq" "resamp" "resampv" "samples" "sndmax" "sndread" "sndseq" "sndsliders" "sndwritepa" "yin" "nyq-osc-server" "trigger" "lpanal" "phasevocoder" "pvshell" )) ;; these are additional files in /nyqsrc that need to be compiled ;; and linked to make nyquist ;******************************************************************** ; CHANGES. PJM July 2007 ; nyqfiles: DELETED "lpanal" ; DELETED "trigger" ;******************************************************************** (setf nyqfiles '("debug" "falloc" "local" "handlers" "multiread" "seqext" "seqinterf" "stats" "ffilterkit" "sliders" )) nyquist-3.05/misc/convert.c0000644000175000000620000000255710144436365014761 0ustar stevestaff/* convert.c -- convert between file name notations */ #include "switches.h" #include "stdio.h" #include "string.h" #include "convert.h" char dir_separator = #ifdef MACINTOSH ':'; #endif #ifdef DOS '\\'; #endif #ifdef UNIX '/'; #endif #ifdef AMIGA '/'; #endif /* Note: syntax error if not one and only one is defined (this is a feature) */ int pauseflag; /* convert -- convert filename to local naming conventions */ /**/ void convert(char *filename) { int i; /* first test for problem characters */ for (i = strlen(filename); i >= 0; i--) { if (filename[i] == ':' || filename[i] == '\\') { fprintf(stderr, "WARNING: %s has one of \":\\\" and may not port.\n", filename); fprintf(stderr, " '/' should be used as directory separator.\n"); if (PAUSE) getchar(); } } #ifdef MACINTOSH /* prepend a ":" */ for (i = strlen(filename); i >= 0; i--) { filename[i + 1] = filename[i]; } filename[0] = ':'; #endif #ifndef UNIX #ifndef AMIGA /* replace '/' with local separator */ for (i = strlen(filename); i >= 0; i--) { if (filename[i] == '/') filename[i] = dir_separator; } #endif #endif } nyquist-3.05/misc/intgen2.c0000644000175000000620000007140310144436365014643 0ustar stevestaff/* intgen.c -- an interface generator for xlisp */ /* (c) Copyright Carnegie Mellon University 1991 * For a statement of limited permission to use, see Permission.doc * * HISTORY * * 5-Jul-95 Roger Dannenberg * strip directory prefixes from files before writing include statements * 24-Oct-88 Roger Dannenberg at CMU * Changed so that if C routine returns void and has result parameters, * then result parameters are returned by the lisp subr as well as * assigned to *RSLT*. * * 13-Apr-88 Roger Dannenberg at CMU * Modified for xlisp version 2.0 * * 22-Dec-87 Roger Dannenberg at NeXT * Added FILE type. * * 21-May-87 Dale Amon at CMU CSD * Included use of NODE *s_true under SCORE_EDITOR conditional. Standard * xlisp code use NODE *true instead. * * 13-May-87 Dale Amon at CMU CSD * Added conditional compilation switch SCORE_EDITOR so that this * program will work with both standard XLISP sources and with Roger's * (ahem) modified version. Also put in error checking for case where * user does not specifiy an output file so program will exit instead * of coredump. */ /* Summary and Design: (NOTE THAT AN INTGEN MANUAL IS AVAILABLE) * The first command line argument gives the name of * the .c file to generate. All following arguments are * .h files to read and use as interface specifications. * * The main program opens the output file, calls * write_prelude, and then process_file for each input * file. Then call write_postlude and close the file. * * process_file opens an input file and reads each line * into current_line. * if the first characters of the file are "ih", then * the rest of the file is processed as normal, except the * .h extension of the file is replaced by .ih before the * filename is written into an include statement in the * output file. This is done to handle ".ih" files generated * by the Andrew Toolkit Class processor. * In any case, the first line of EVERY .h file is discarded. * If #define is found, save the following identifier as * macro_name. * If "LISP:" is found, then see if it is preceded by one * or two identifiers and an open paren. * If yes, call routine_call, * else call macro_call. * * routine_call gets the first one or two identifiers off the * line into type_name and routine_name. If there is just one id, * assign it to routine_name and make type_name = "void". * If the routine_name starts with *, remove the * from * routine_name and append "*" to type_name. * Call write_interface with type_name, routine_name, and location * of parameter type description after "LISP:". * * macro_call gets a type_name from the input line after * "LISP:". * Then call write_interface with type_name, macro_name, and * location of parameter type description. * * lisp function names are saved in a table, and an * initialization routine is written to install the new * SUBRs into the xlisp symbol table, as well as to lookup * RSLT_sym, the atom on which results are placed * * */ /* Turn on special handling for Roger's Score Editor if the following #define * is uncommented: */ /* #define SCORE_EDITOR */ /* Turn on special handling for Chris's Sound Editor if the following #define * is uncommented: */ /* #define SOUND_EDITOR */ /* Turn on special handling for Nyquist if the following #define * is uncommented: */ #define NYQUIST /* atom 't is named s_true if this is defined, o.w. named true: */ #define S_TRUE 1 /* Turn on special handling for CMU MIDI Toolkit seq_type: */ #define SEQ_TYPE #define errfile stdout #define ident_max 100 #define line_max 200 #define subr_max 500 /* prefix for include files not to be included in interface module */ #define no_include_prefix '~' #define false 0 #define true 1 #include "stdlib.h" #include "switches.h" #include "cext.h" #include #ifndef boolean typedef int boolean; #endif #include "stdio.h" #include "ctype.h" #include "cmdline.h" #ifdef MACINTOSH #include "console.h" #endif #ifdef MACINTOSH #define FILESEP ':' #else #ifdef WINDOWS #define FILESEP '\\' #else #define FILESEP '/' #endif #endif static char *sindex(); #define whitep(c) ((c) == ' ' || (c) == '\t') #define symbolp(c) (isalpha(c) || (c) == '*' || (c) == '_' || (c) == '-' ||\ (c) == ':' || isdigit(c) || (c) == '^' || (c) == '*') /* c and Lisp parameters are encoded in the same table. * Field type_id is the string name of the type. * For c types (return types of C routines), code is 'C', * convert gives the routine for making a lisp node from * the c datum. * listtype_or_special is "v" for types that should be * returned as LISP NIL (e.g. "void"), "s" for types * that when NULL should be returned as NIL, "r" * for normal types, and "" to raise an error. * ctype is not used and should be NULL. * For Lisp types (from parameter specs), code is 'L'. * convert gives the routine that extracts a C value * from a lisp node whose type is given by the field * getarg_or_special. * c_type is the type of the local C variable which is * passed as a parameter to the C routine. * initializer is the initial value for result only parameters * * End of table is marked by a NULL type_id. * * Location 0 is reserved to indicate errors. * Location 1 MUST BE type ANY * */ #define any_index 1 struct { char *type_id; char code; char *convert; char *getarg_or_special; char *ctype; char *makenode; char *initializer; } type_table[] = { {" ", ' ', NULL, NULL, NULL, NULL, NULL}, {"ANY", 'L', "", "", "LVAL", "", "NIL"}, {"ATOM", 'L', "", "xlgasymbol", "LVAL", "", "NIL"}, {"FILE", 'L', "getfile", "xlgastream", "FILE *", "cvfile", "NULL"}, {"FIXNUM", 'L', "getfixnum", "xlgafixnum", "long", "cvfixnum", "0"}, {"FIXNUM", 'L', "getfixnum", "xlgafixnum", "int", "cvfixnum", "0"}, {"FLOAT", 'L', "getflonum", "xlgaflonum", "float", "cvflonum", "0.0"}, {"FLONUM", 'L', "getflonum", "xlgaflonum", "double", "cvflonum", "0.0"}, {"ANYNUM", 'L', "testarg2", "xlgaanynum", "double", "cvflonum", "0.0"}, {"STRING", 'L', "getstring", "xlgastring", "unsigned char *", "cvstring", "NULL"}, {"BOOLEAN", 'L', "getboolean", "xlgetarg", "int", "cvboolean", "0"}, {"atom_type", 'C', "", "r", NULL, NULL, NULL}, {"LVAL", 'C', "", "r", NULL, NULL, "NIL"}, #ifdef SOUND_EDITOR /* Extensions for Sound Type: */ {"SOUND", 'L', "getsound", "xlgasound", "SoundPtr", "cvsound", "NULL"}, {"SoundPtr", 'C', "cvsound", "r", NULL, NULL, NULL}, #endif #ifdef NYQUIST {"SOUND", 'L', "getsound", "xlgasound", "sound_type", "cvsound", "NULL"}, {"sound_type", 'C', "cvsound", "r", NULL, NULL, NULL}, #endif #ifdef SEQ_TYPE {"SEQ", 'L', "getseq", "xlgaseq", "seq_type", "cvseq", "NULL"}, {"seq_type", 'C', "cvseq", "r", NULL, NULL, NULL}, #endif #ifdef SCORE_EDITOR {"VALUE", 'L', "getval", "xlgaval", "value_type", "cvval", "NULL"}, {"value_type", 'C', "cvval", "r", NULL, NULL, NULL}, {"EVENT", 'L', "getevent", "xlgaevent", "event_type", "cvevent", "NULL"}, {"event_type", 'C', "cvevent", "r", NULL, NULL, NULL}, {"score_type", 'C', "cvevent", "r", NULL, NULL, NULL}, #endif #ifdef DMA_EXTENSIONS /* begin DMA entries */ {"DEXT", 'L', "getdext", "xlgadext", "ext_type", "cvdext", "NULL"}, {"DEXT", 'C', "cvdext", "r", NULL, NULL, NULL}, {"SEXT", 'L', "getsext", "xlgasext", "ext_type", "cvsext", "NULL"}, {"SEXT", 'C', "cvsext", "r", NULL, NULL, NULL}, /* end DMA entries */ #endif {"int", 'C', "cvfixnum", "r", NULL, NULL, NULL}, {"long", 'C', "cvfixnum", "r", NULL, NULL, NULL}, {"boolean", 'C', "cvboolean", "r", NULL, NULL, NULL}, {"float", 'C', "cvflonum", "r", NULL, NULL, NULL}, {"double", 'C', "cvflonum", "r", NULL, NULL, NULL}, {"string", 'C', "cvstring", "s", NULL, NULL, NULL}, {"char*", 'C', "cvstring", "s", NULL, NULL, NULL}, {"char", 'C', "cvfixnum", "r", NULL, NULL, NULL}, {"string_type", 'C', "cvstring", "s", NULL, NULL, NULL}, {"FILE*", 'C', "cvfile", "s", NULL, NULL, NULL}, {"void", 'C', "", "v", NULL, NULL, NULL}, /*eot*/ {NULL, ' ', NULL, NULL, NULL, NULL, NULL}}; /* subr names get saved here: */ char *subr_table[subr_max]; int subr_table_x; #define get_c_special(i) type_table[(i)].getarg_or_special[0] #define get_c_conversion(i) type_table[(i)].convert #define get_lisp_extract(i) type_table[(i)].convert #define get_lisp_getarg(i) type_table[(i)].getarg_or_special #define get_lisp_ctype(i) type_table[(i)].ctype #define get_lisp_makenode(i) type_table[(i)].makenode #define get_lisp_initializer(i) type_table[(i)].initializer static void lisp_code(); static int lookup(); static void process_file(); static void routine_call(); static void write_interface(); static void write_postlude(); static void write_prelude(); static void write_ptrfile(); char source_file[ident_max]; /* source file */ char current_line[4 * line_max]; /* current line in source file */ char out_file[ident_max]; /* output file name */ char ptr_file[ident_max]; /* ptr.h file name */ char def_file[ident_max]; /* def.h file name */ FILE *lispout = NULL; /* output for lisp source code (if any) */ #define EOS '\000' /* getarg -- get an identifier from a string */ /**/ int getarg(start, result, pos) char *start; /* where to start scanning */ char *result; /* where to put the identifier */ char **pos; /* ptr to char after identifier in source */ { char *save = result; *result = EOS; while (whitep(*start) && *start != EOS) start++; if (*start == EOS) return false; if (!symbolp(*start)) return false; while (symbolp(*start) && *start != EOS) { *result = *start; result++; start++; } *result = EOS; *pos = start; printf("getarg got %s\n", save); return true; } /* error() -- print source file and line */ /**/ error() { fprintf(errfile, "\n%s: |%s|\n", source_file, current_line); } /* lisp_code -- write lisp code to file */ /* * read from inp if necessary until close comment found */ static void lisp_code(inp, s) FILE *inp; char *s; { char lisp[line_max]; char *endcomment; char *inputline; /* for end of file detection */ if (lispout == NULL) { char lisp_file_name[ident_max]; char *extension; strcpy(lisp_file_name, out_file); extension = sindex(lisp_file_name, ".c"); strcpy(extension, ".lsp"); /* overwrite .c with .lsp */ lispout = fopen(lisp_file_name, "w"); if (lispout == NULL) { fprintf(stdout, "Error: couldn't open %s\n", lisp_file_name); exit(1); } printf("writing %s ...\n", lisp_file_name); } strcpy(lisp, s); /* don't modify s */ inputline = lisp; while (inputline != NULL && (endcomment = sindex(lisp, "*/")) == NULL) { fputs(lisp, lispout); inputline = fgets(lisp, line_max, inp); } strcpy(endcomment, "\n\n"); fputs(lisp, lispout); } /* lookup -- find type data */ /**/ static int lookup(s, t) char *s; char t; { int i = 1; while (type_table[i].type_id != NULL) { if (type_table[i].code == t && strcmp(type_table[i].type_id, s) == 0) return i; i++; } return 0; } /* macro_call -- generate xlisp interface for C routine */ /**/ void macro_call(in, out, curline, macro_name, arg_loc) FILE *in; /* input file */ FILE *out; /* output file */ char *curline; /* input line */ char *macro_name; /* name of the macro to call */ char *arg_loc; /* location after "LISP:" */ { char type_name[ident_max]; if (!getarg(arg_loc, type_name, &arg_loc)) { error(); fprintf(errfile, "no type given for macro.\n"); } else { write_interface(in, out, type_name, macro_name, arg_loc, true); } } /* main -- generate an xlisp to c interface file */ /**/ int main(argc, argv) int argc; char *argv[]; { char *s; FILE *out; FILE *ptrfile; FILE *deffile; int n; #ifdef MACINTOSH argc = ccommand(&argv); #endif for (n = 0; n < subr_max; n++) { subr_table[n] = (char *) malloc(ident_max); subr_table[n][0] = EOS; } subr_table_x = 0; cl_init(NULL, 0, NULL, 0, argv, argc); if ((s = cl_arg(1)) != NULL) { strcpy(out_file, s); if (sindex(out_file, ".") == 0) strcat(out_file, ".c"); else fprintf(stderr, "1st command line argument should be a legal c identifier\n"); out = fopen(out_file, "w"); if (out == NULL) { fprintf(stdout, "Error: couldn't open %s\n", out_file); exit(1); } strcpy(ptr_file, s); strcat(ptr_file, "ptrs.h"); ptrfile = fopen(ptr_file, "w"); if (ptrfile == NULL) { fprintf(stdout, "Error: couldn't open %s\n", ptr_file); exit(1); } strcpy(def_file, s); strcat(def_file, "defs.h"); deffile = fopen(def_file, "w"); if (deffile == NULL) { fprintf(stdout, "Error: couldn't open %s\n", def_file); exit(1); } } else { fprintf(stdout, "Error: no output file specified\n"); exit(1); } printf("writing %s ...\n", out_file); write_prelude(out, out_file); n = 2; while ((s = cl_arg(n)) != NULL) { printf(" %s\n", s); process_file(s, out); n++; } write_postlude(out); fclose(out); write_ptrfile(ptrfile, deffile); fclose(ptrfile); fclose(deffile); if (lispout != NULL) fclose(lispout); exit(0); } static void process_file(fname, out) char *fname; FILE *out; { FILE *in; char *cp; char *pos; char incl_file[ident_max]; /* name of file to include */ char type_name[ident_max]; /* the type of the routine */ char routine_name[ident_max]; /* the name of the routine or macro */ char flag = fname[0]; boolean reading_parameters = false; /* says we've got a routine, and we're skipping over parameter declarations */ if (flag == no_include_prefix) fname++; strcpy(source_file, fname); /* for error reporting */ in = fopen(fname, "r"); if (in == NULL) { fprintf(errfile, "couldn't open %s\n", fname); return; } /* first check out the first line: if the first two characters are "ih", then replace fname with file.ih so that the CLASS ".ih" file will be included instead of this ".h" file. This is a hack to allow calls into Andrew Tool Kit objects. */ strcpy(incl_file, fname); if (fgets(current_line, line_max, in) != NULL) { if (current_line[0] == 'i' && current_line[1] == 'h') { cp = sindex(incl_file, ".h"); if (cp != NULL) { strcpy(cp, ".ih"); } } } /* strip off leading directory prefix, if any */ cp = strrchr(incl_file, FILESEP); /* find the last slash */ if (cp) { strcpy(incl_file, cp + 1 /* skip the slash */); } if (flag != no_include_prefix) fprintf(out, "#include \"%s\"\n\n", incl_file); while (fgets(current_line, line_max, in) != NULL) { cp = sindex(current_line, "#define"); if (cp != NULL) { cp += strlen("#define"); if (!getarg(cp, routine_name, &cp)) { error(); fprintf(errfile, "#define not followed by identifier\n"); } /* watch out for multi-line macros: */ while (sindex(current_line, "\\\n")) { if (fgets(current_line, line_max, in) == NULL) return; } } else if ((cp = sindex(current_line, "LISP:")) != NULL) { char type_str[ident_max]; char routine_str[ident_max]; if (!reading_parameters && getarg(current_line, type_str, &pos) && getarg(pos, routine_str, &pos) && pos < cp) { routine_call(in, out, current_line, type_str, routine_str, cp + strlen("LISP:")); } else if (getarg(cp + strlen("LISP:"), type_str, &pos)) { macro_call(in, out, current_line, routine_name, cp + strlen("LISP:")); } else routine_call(in, out, current_line, type_name, routine_name, cp + strlen("LISP:")); } else if ((cp = sindex(current_line, "LISP-SRC:")) != NULL) { lisp_code(in, cp + strlen("LISP-SRC:")); } else if (reading_parameters && sindex(current_line, ")")) { reading_parameters = false; } else if (reading_parameters) { /* skip */ ; } else if (getarg(current_line, type_name, &pos) && getarg(pos, routine_name, &pos)) { /* we grabbed the type and routine name. Check to see if the * parameter list is open but not closed on this line: */ printf("type_name %s, routine_name %s\n", type_name, routine_name); if (sindex(current_line, "(") && !sindex(current_line, ")")) { reading_parameters = true; } /* printf("saw %s %s\n", type_name, routine_name);*/ } else { /* wipe out names for safety: */ type_name[0] = EOS; routine_name[0] = EOS; } } fclose(in); } /* routine_call -- generate xlisp interface for C routine */ /**/ static void routine_call(in, out, curline, type_name, routine_name, arg_loc) FILE *in; /* input file */ FILE *out; /* output file */ char *curline; /* input line */ char *type_name; /* type id */ char *routine_name; /* routine id */ char *arg_loc; /* location after "LISP:" */ { if (*routine_name == EOS) { routine_name = type_name; type_name = "void"; } if (*routine_name == '*') { char *r = routine_name; while (*r != EOS) { /* shift left */ *r = *(r+1); r++; } strcat(type_name, "*"); } write_interface(in, out, type_name, routine_name, arg_loc, false); } /* sindex -- find substring */ /**/ static char *sindex(sup, sub) char *sup; /* the containing string */ char *sub; /* the substring */ { int i; for ( ; *sup != EOS; sup++) { for (i = 0; true; i++) { if (*(sub+i) == EOS) return sup; if (*(sup+i) != *(sub+i)) break; } } return EOS; } /* write_interface -- write SUBR for xlisp */ /* * NOTE: if is_macro and there are no arguments, then * do not write parens: e.g. "foo" instead of "foo()" */ static void write_interface(in, out, type_name, fn_name, arg_loc, is_macro) FILE *in; /* input file */ FILE *out; /* output file */ char *type_name; /* c type for return value */ char *fn_name; /* c function to be called */ char *arg_loc; /* LISP arg type are described here */ int is_macro; /* true if this is a macro */ { char lispfn[ident_max]; /* lisp fn name */ char *cp; /* a temporary */ int len; /* a string length */ #define args_max 20 struct { int index; /* table location for this type */ int res_flag; /* is a result returned? */ } args[args_max]; char arg_type[ident_max]; /* the original type spec */ char *c_type; /* c type for an argument */ char *c_str; /* temp for a c code line */ int argcnt = 0; /* counts arguments */ int i; /* argument index */ int result_flag = false; /* true if there are result parameters */ int result_x; /* index of result type */ char newline[line_max]; /* place to read continuation lines */ /* printf("write_interface: %s %s %s", type_name, fn_name, arg_loc);*/ if (*type_name == EOS || *fn_name == EOS) { error(); fprintf(errfile, "Error: bad syntax, maybe missing type\n"); return; } while (*arg_loc != '(' && *arg_loc != EOS) arg_loc++; if (*arg_loc == EOS) { error(); fprintf(errfile, "Error: '(' expected after 'LISP:'\n"); return; } else arg_loc++; if (!getarg(arg_loc, lispfn, &arg_loc)) { error(); fprintf(stdout, "Error: lisp function name expected\n"); return; } /* make it upper case: */ for (cp = lispfn; *cp != EOS; cp++) { if (islower(*cp)) *cp = toupper(*cp); } /* save SUBR name */ strcpy(subr_table[subr_table_x], lispfn); subr_table_x++; /* make lispfn lower case, dash, colon -> underscore: */ for (cp = lispfn; *cp != EOS; cp++) { if (isupper(*cp)) *cp = tolower(*cp); if (*cp == '-' || *cp == ':') *cp = '_'; } /* append continuation lines to arg_loc to handle multi-line specs */ while (sindex(arg_loc, "*/") == NULL) { /* remove newline */ if (strlen(arg_loc) > 0) arg_loc[strlen(arg_loc) - 1] = EOS; if (fgets(newline, line_max, in) == NULL) { error(); fprintf(stdout, "Error: end of file unexpected\n"); exit(1); } if ((strlen(arg_loc) + strlen(newline)) > (3 * line_max)) { error(); fprintf(stdout, "Error: specification too long or missing end of comment.\n"); exit(1); } strcat(arg_loc, newline); } fprintf(out, "/%c xlc_%s -- interface to C routine %s */\n/**/\n", '*', lispfn, fn_name); fprintf(out, "LVAL xlc_%s(void)\n{\n", lispfn); while (getarg(arg_loc, arg_type, &arg_loc)) { int result_only_flag = false; if (argcnt >= args_max) { error(); fprintf(errfile, "Internal error: too many args, increase args_max\n"); } len = strlen(arg_type); if (arg_type[len-1] == '*') { arg_type[len-1] = EOS; args[argcnt].res_flag = true; result_flag = true; } else if (arg_type[len-1] == '^') { arg_type[len-1] = EOS; args[argcnt].res_flag = true; result_flag = true; result_only_flag = true; } else args[argcnt].res_flag = false; args[argcnt].index = lookup(arg_type, 'L'); c_type = get_lisp_ctype(args[argcnt].index); if (c_type == NULL) { error(); fprintf(errfile, "Error: %s undefined, using int.\n", arg_type); c_type = "int"; args[argcnt].index = lookup("FIXNUM", 'L'); } fprintf(out, " %s arg%d = ", c_type, argcnt+1); if (result_only_flag) { fprintf(out, "%s;\n", get_lisp_initializer(args[argcnt].index)); } else if (args[argcnt].index == any_index) { fprintf(out, "xlgetarg();\n"); } else { c_str = "%s(%s());\n"; fprintf(out,c_str, get_lisp_extract(args[argcnt].index), get_lisp_getarg(args[argcnt].index)); } argcnt++; } if (*arg_loc != ')') { fprintf(errfile, "Warning: paren expected immediately after last arg of %s\n", lispfn); } /* check for close paren and close comment: */ cp = sindex(arg_loc, ")"); if (cp == NULL || sindex(cp+1, "*/") == NULL) { error(); fprintf(errfile, "Warning: close paren and close comment expected\n"); } /* lookup result type */ result_x = lookup(type_name, 'C'); if (result_x == 0) { fprintf(errfile, "Error: unknown type: %s, assuming void\n", type_name); result_x = lookup("void", 'C'); } /* if there are result parameters then return them rather than NIL * when the type is void */ if (get_c_special(result_x) == 'v' && result_flag) { fprintf(out, " LVAL result;\n"); } if (get_c_special(result_x) != 'v') { /* declare result: */ fprintf(out, " %s result;\n", type_name); } /* check for end of argument list: */ fprintf(out, "\n xllastarg();\n"); /* if there are results, we'll call cons, so * protect the result from garbage collection * if necessary */ if (result_flag && strcmp(type_name, "LVAL") == 0) { fprintf(out, " xlprot1(result);\n"); } /* call the c routine */ if (get_c_special(result_x) != 'v') { fprintf(out, " result = "); } else fprintf(out, " "); fprintf(out, "%s", fn_name); if (!is_macro || argcnt > 0) fprintf(out, "("); /* pass arguments: */ for (i = 0; i < argcnt; i++) { if (i > 0) fprintf(out, ", "); if (args[i].res_flag) fprintf(out, "&"); fprintf(out, "arg%d", i+1); } if (!is_macro || argcnt > 0) fprintf(out, ")"); fprintf(out, ";\n"); /* put results (if any) on *RSLT* */ if (result_flag) { int wrote_one_flag = false; fprintf(out, " {\tLVAL *next = &getvalue(RSLT_sym);\n"); for (i = 0; i < argcnt; i++) { if (args[i].res_flag) { if (wrote_one_flag) fprintf(out, "\tnext = &cdr(*next);\n"); wrote_one_flag = true; fprintf(out, "\t*next = cons(NIL, NIL);\n"); fprintf(out, "\tcar(*next) = %s(arg%d);", get_lisp_makenode(args[i].index), i+1); } } fprintf(out, "\n }\n"); /* copy *RSLT* to result if appropriate */ if (get_c_special(result_x) == 'v') { fprintf(out, " result = getvalue(RSLT_sym);\n"); } } /* generate xlpop() if there was an xlprot1() */ if (result_flag && strcmp(type_name, "LVAL") == 0) { fprintf(out, " xlpop();\n"); } /* now return actual return value */ if (get_c_special(result_x) == EOS) { error(); fprintf(errfile, "Warning: unknown type from C, coercing to int.\n"); fprintf(out, " return cvfixnum((int) result);\n"); } else if (get_c_special(result_x) == 'v' && !result_flag) { fprintf(out, " return NIL;\n"); } else if (get_c_special(result_x) == 'v' && result_flag) { fprintf(out, " return result;\n"); } else if (get_c_special(result_x) == 's') { fprintf(out, " if (result == NULL) return NIL;\n"); fprintf(out, " else return %s(result);\n", get_c_conversion(result_x)); } else { fprintf(out, " return %s(result);\n", get_c_conversion(result_x)); } fprintf(out, "}\n\n\n"); } /* write_postlude -- write stuff at end of file */ /**/ static void write_postlude(out) FILE *out; { /* nothing to do for version 2 */ } /* write_ptrfile -- write function definition table */ /**/ static void write_ptrfile(pf, df) FILE *pf; FILE *df; { int n; char *cp; char cname[ident_max]; for (n = 0; n < subr_table_x; n++) { strcpy(cname, subr_table[n]); /* make cname lower case, dash,colon -> underscore: */ for (cp = cname; *cp != EOS; cp++) { if (isupper(*cp)) *cp = tolower(*cp); if (*cp == '-' || *cp == ':') *cp = '_'; } fprintf(df, "extern LVAL xlc_%s(void);\n", cname); fprintf(pf, " { \"%s\", S, xlc_%s}, \n", subr_table[n], cname); } printf(" Add %s to localdefs.h and add %s to localptrs.h\n", def_file, ptr_file); } /* write_prelude -- write stuff at head of file */ /**/ static void write_prelude(out, out_file) FILE *out; char *out_file; { int i = 2; int col = strlen(out_file) + 21; char *s; fprintf(out, "/%c %s -- interface to ", '*', out_file); while ((s = cl_arg(i)) != NULL) { if (i > 2) { fprintf(out, ", "); col += 2; } col += strlen(s) + 2; if (col > 65) { fprintf(out, "\n * "); col = 4 + strlen(s) + 2; } fprintf(out, "%s", s); i++; } fprintf(out, " */\n\n%cifndef mips\n%cinclude \"stdlib.h\"\n", '#', '#'); fprintf(out, "%cendif\n%cinclude \"xlisp.h\"\n\n", '#', '#'); #ifdef S_TRUE fprintf(out, "extern LVAL s_true;\n"); fprintf(out, "%cdefine cvboolean(i) ((i) ? s_true : NIL)\n", '#'); #else fprintf(out, "extern LVAL true;\n"); fprintf(out, "%cdefine cvboolean(i) ((i) ? true : NIL)\n", '#'); #endif fprintf(out, "%c%s\n", '#', "define testarg2(e) (moreargs() ? (e) : (getflonum(xltoofew())))"); fprintf(out, "%c%s\n%s\n%s\n", '#', "define xlgaanynum() (floatp(*xlargv) ? getflonum(nextarg()) : \\", " (fixp(*xlargv) ? (double) getfixnum(nextarg()) : \\", /* note: getflonum never gets called here, but this makes typechecking happy */ " getflonum(xlbadtype(*xlargv))))"); fprintf(out, "%cdefine getboolean(lval) ((lval) != NIL)\n\n", '#'); fprintf(out, "extern LVAL RSLT_sym;\n\n\n"); } nyquist-3.05/misc/plot.c0000644000175000000620000001561710144436365014260 0ustar stevestaff/* * FILE: plot.c * BY: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu) * DESC: graphs file of numbers on terminal * * 1.1 ( 1-JUN-88) - added lines from 0 to data points (cf0v) * 1.2 ( 3-JUN-88) - added skip parameter (cf0v) * 1.3 (23-JUN-88) - added -x and -y options (cf0v) * 1.4 (30-JUN-88) - clean-up. (cf0v) * 2.0 ( 5-JUL-88) - added binary sound file format option. Changed scaling * for "-n" option to only consider those values being * plotted, instead of whole file. */ char plotVERSION[] = "2.0 (5-JUL-88, 11:40am)"; /* * plot [ [-nxyab]] * Accepts input stream of numbers from (or stdin, if no * argument is present), drawing a graph to sdout. File is prescanned for * min and max values, and the graph is scaled accordingly. If making the * file's min non-zero delta equal to one char allows the entire graph to * fit on the screen, then this scalar is used. If the -n option is * used, then only every th number from the input stream is plotted. * The -x option enables printing the line number in the file on the screen * every 10 lines. The -y option enables printing the y value on the screen * every line. Note -x and -y are NOT mutually exclusive. The -a option * indicates the input file is in ascii format, while the -b option indicates * the input file is in the binary sound file format. When neither of these * is present, binary is assumed unless input is from stdin. */ #include #include "stdefs.h" #define MAXNUMINPUT 16*1024 #define BINARY 0 #define ASCII 1 fail(s, arg) char *s, *arg; { fprintf(stderr,"\nplot: "); fprintf(stderr, s, arg); fprintf(stderr,"\n\n"); exit(1); } FILE *fain; /* Pointer to input file for ascii format */ int fbin; /* Input file for binary format */ int ftype; /* Type of input file */ prescan(X, Num, Max, Min, Delta) HWORD X[]; int *Num, *Max, *Min, *Delta; { int last, i, len; *Min = *Delta = 32767; *Max = -32768; *Num = last = 0; if (ftype == ASCII) while (fscanf(fain,"%d",&i) != EOF) { *Min = MIN(i, *Min); *Max = MAX(i, *Max); if (i != last) *Delta = MIN(ABS(i-last), *Delta); *Num += 1; last = i; *X++ = i; } else { printf("| binary prescan, fbin:%d\n", fbin); len = read(fbin, (char *)X, MAXNUMINPUT*sizeof(HWORD)) / sizeof(HWORD); if (len >= MAXNUMINPUT) fprintf(stderr, "plot: input truncated to %d samples\n", MAXNUMINPUT); for (i=0; i] [-n/s] [-x/y/a/b]',\ \n where: to plot (stdin is default),\ \n -n plot every th value in file,\ \n -s start at the th sample,\ \n -x print line # in file every 10 lines,\ \n -y print y coordinate every line,\ \n -a indicates input file is in ascii format,\ \n -b indicates input is in binary sound file format.\ \n -x and -y are NOT mutually exclusive; -a and -b ARE.\ \n -b is assumed unless input is stdin.", *argv); file = *argv; printf("| file:%s\n", file); } else if ((*argv)[1]=='x' || (*argv)[1]=='X') *xPrint = TRUE; else if ((*argv)[1]=='y' || (*argv)[1]=='Y') *yPrint = TRUE; else if ((*argv)[1]=='a' || (*argv)[1]=='A') ftype = ASCII; else if ((*argv)[1]=='b' || (*argv)[1]=='B') ftype = BINARY; else if ((*argv)[1]=='n' || (*argv)[1]=='N') { if (1 != sscanf(*argv+2, "%d", skip)) fail("illegal -n parameter '%s'", *argv); } else if ((*argv)[1]=='s' || (*argv)[1]=='S') { if (1 != sscanf(*argv+2, "%d", start)) fail("illegal -s parameter '%s'", *argv); } } if (!file) ftype = ASCII; else if (ftype == ASCII) { if (NULL == (fain = fopen(file, "r"))) fail("could not open ascii input file '%s'\n", file); } else { if (NULL > (fbin = open(file, 0))) fail("could not open binary input file '%s'\n", file); } } main (argc,argv) int argc; char *argv[]; { int Num, Max, Min, Delta, i; HWORD X[MAXNUMINPUT]; double factor; int target, skip, start; int xCount, xPrint, yPrint; char *Star[41], *Space[41]; printf("\nData Plotting Program\n"); printf("by: Christopher Lee Fraley\n"); printf("Version: %s\n", plotVERSION); Star[40] = "****************************************"; Space[40] = " "; for (i=39; i>=0; i--) { Star[i] = Star[i+1] + 1; Space[i] = Space[i+1] + 1; } getargs(argc, argv, &skip, &xPrint, &yPrint, &start); prescan(X, &Num, &Max, &Min, &Delta); factor = 1.0/Delta; if (factor*Max>39) factor = 39.0/Max; if (factor*Min<-40) factor = 40.0/-Min; printf("\n Number of Data Points:%d \t [%d:%d]\n",Num,Min,Max); printf(" Scale: %g/char",1.0/factor); if (skip > 1) printf(" \t\t Plotting every %dth sample", skip); if (start) printf(" Starting plot at sample %d", start); printf("\n\n=========3=========2=========1=========0=========1=========2\ =========3=========\n"); if (xPrint) xCount = 11; else xCount = -1; for (i=start; i nyquist-3.05/misc/unpacker.c0000644000175000000620000001762710144436365015115 0ustar stevestaff/* unpacker -- a program to unpack a set of files */ /* See packer.c for a description of the input file format. */ #include "switches.h" #ifdef MACINTOSH #include #include #endif #include "cext.h" #include "convert.h" #include "string.h" /* since we aren't using the cleanup package, expose exit(): */ #undef exit #include "stdio.h" #ifdef THINK_C #include "console.h" #endif #define string_max 500 #ifndef EOS #define EOS 0 #endif void escape(); void unpack_ascii(); void unpack_binary(); void put_run(); #ifdef UNIX #define FILESEP '/' #include #include int dir_isvaliddir(char *path) { DIR *dir = opendir(path); if (!dir) return false; closedir(dir); return true; } #include int _mkdir(char *p) { int rslt = mkdir(p, S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IWGRP | S_IROTH | S_IXOTH); printf("_mkdir: %s, rslt %d\n", p, rslt); if (rslt == -1) { printf("mkdir error\n"); perror("unpacker mkdir"); } return rslt; } #endif #ifdef WINDOWS #define FILESEP '\\' // deal with some incompatible definitions #undef byte #undef boolean #include "windows.h" #include /* * Function: dir_isvaliddir * * Purpose: * * Is this a valid directory ? */ BOOL dir_isvaliddir(LPSTR path) { DWORD dwAttrib; dwAttrib = GetFileAttributes(path); if (dwAttrib == -1) { return(FALSE); } if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) { return(TRUE); } return(FALSE); } /* dir_isvaliddir */ #endif /* early_eof -- print error message and exit */ void early_eof() { fprintf(stderr, "Unexpected end of file while unpacking\n"); exit(1); } #ifdef MACINTOSH #define FILESEP ':' int dir_isvaliddir(char *path) { char filename[256]; OSErr err; FSSpec spec; strcpy(filename, path); c2pstr(filename); err = FSMakeFSSpec(0, 0, (unsigned char *) filename, &spec); if (err == noErr) { /* if we can open this as a file, it's not a directory */ SInt16 refnum; err = FSpOpenDF(&spec, fsCurPerm, &refnum); if (err == noErr) { FSClose(refnum); return false; } return true; } return false; } int _mkdir(char *p) { OSErr err; FSSpec spec; SInt32 dirid; spec.vRefNum = 0; spec.parID = 0; strcpy((char *) spec.name, p); c2pstr(spec.name); err = FSpDirCreate(&spec, smSystemScript, &dirid); if (err == noErr) { return 0; } if (err != noErr) { printf("mkdir error %d\n", err); } return -1; } #endif void make_path(char *full_name) // make directories as needed { char directory[256]; char *ptr = full_name; while (ptr = strchr(ptr, FILESEP)) { strcpy(directory, full_name); directory[ptr - full_name] = 0; if (!dir_isvaliddir(directory)) { if (_mkdir(directory) != 0) { printf("Could not create %s\n", directory); return; } else { printf("Created directory %s\n", directory); } } // now directory is valid, so move to next one ptr++; } } /* main -- unpack a set of files */ /**/ int main(argc, argv) int argc; char *argv[]; { FILE *inf; /* input file: a packed set of files */ FILE *outf; /* a file to unpack */ char filename[string_max]; /* holds names of inptu files */ #ifdef MACINTOSH argc = ccommand(&argv); #endif if (argc != 2) { fprintf(stderr, "Usage: unpack input-file\n"); exit(1); } inf = fopen(argv[1], "r"); if (!inf) { fprintf(stderr, "Couldn't open |%s|\n", argv[1]); exit(1); } while (fgets(filename, string_max, inf)) { char *filetype = "w"; filename[strlen(filename) - 1] = EOS; /* remove newline at end */ puts(filename + 1); /* don't print the leading ! or # */ convert(filename + 1); /* convert to local filename conventions */ if (filename[0] == '#') filetype = "wb"; outf = fopen(filename + 1, filetype); if (!outf) { make_path(filename + 1); outf = fopen(filename + 1, filetype); if (!outf) { fprintf(stderr, "Couldn't open |%s|\n", filename + 1); exit(1); } } if (filename[0] == '!') { unpack_ascii(inf, outf, filename + 1); } else if (filename[0] == '#') { unpack_binary(inf, outf); } if (outf) fclose(outf); } fclose(inf); return 0; } /* put_run -- output a run of characters */ /**/ void put_run(f, c, n) FILE *f; int c; int n; { while (n--) putc(c, f); } /* unpack_ascii -- from inf to outf */ /**/ void unpack_ascii(inf, outf, filename) FILE *inf; FILE *outf; char *filename; { for (;;) { int c = getc(inf); if (c == EOF) return; else if (c > 127) { fprintf(stderr, "Non-ascii char 0x%x found while unpacking %s.\n", c, filename); return; } else if (c >= 'A' && c <= '~') { int n = (c - 'A'); //DO NOT OUTPUT LEADING TABS -- USE SPACES INSTEAD // int tabs = (n / TAB_WIDTH); // n -= tabs * TAB_WIDTH; // put_run(outf, '\t', tabs); put_run(outf, ' ', n); } else if (c >= '0' && c <= '9') { put_run(outf, '\n', c - '0'); } else if (c == '!' || c == '#') { ungetc(c, inf); return; } else { fprintf(stderr, "Unexpected char in col 1 (%c) while unpacking %s.\n", c, filename); return; } /* now get rest of the line */ while ((c = getc(inf)) != EOF) { if (c == '$') { c = getc(inf); if (c == EOF) { early_eof(); } else if (c == '$') { putc('$', outf); } else if (c >= '@' && c <= '_') { putc(c - '@', outf); } else if (c == '\n') { ; /* do nothing */ } else { fprintf(stderr, "Bad char (%c) after '$' while unpacking %s.\n", c, filename); } } else { putc(c, outf); if (c == '\n') break; /* go up and process col. 1 char */ } } } } /* unpack_binary -- from inf to outf */ /**/ void unpack_binary(inf, outf) FILE *inf; FILE *outf; { for (;;) { long l; int c = getc(inf); if (c == EOF) { early_eof(); } else if (c == '.') { break; } else if (c == '\n') { ; /* do nothing */ } else { l = c - '0'; c = getc(inf); if (c == EOF) { early_eof(); } else { l = (l << 6) + (c - '0'); c = getc(inf); if (c == EOF) { early_eof(); } else if (c == '.') { putc(l >> 4, outf); break; } else { l = (l << 6) + (c - '0'); c = getc(inf); if (c == EOF) { early_eof(); } else if (c == '.') { putc((l >> 10) & 0xFF, outf); putc((l >> 2) & 0xFF, outf); break; } else { l = (l << 6) + (c - '0'); putc((l >> 16) & 0xFF, outf); putc((l >> 8) & 0xFF, outf); putc(l & 0xFF, outf); } } } } } getc(inf); /* read the final newline */ } nyquist-3.05/misc/Makefile0000644000175000000620000000206110144436365014563 0ustar stevestaff# # FILE: Makefile # BY: Christopher Lee Fraley # and Roger B. Dannenberg. # DESC: This file builds various utilities for Nyquist # CC = gcc $(CFLAGS) # the unix path gets us switches.h: # the cmt path gets us swlogic.h: CFLAGS = -g -I../sys/unix -I../cmt # Directory info: BINPATH = . # Intgen stuff: intgen: cmdline.o intgen.o $(CC) cmdline.o intgen.o -o $(BINPATH)/intgen cmdline.o: cext.h cmdline.h intgen.o: cext.h cmdline.h #sampleprint - dumb but useful sampleprint: sampleprint.o $(CC) sampleprint.o -o $(BINPATH)/sampleprint sampleprint.o: sampleprint.c #sine sne: sne.o $(CC) sne.o -o $(BINPATH)/sne sne.o: sne.c #play play: play.o $(CC) play.o -o $(BINPATH)/play play.o: play.c #plot plot: plot.o $(CC) plot.o -o $(BINPATH)/plot plot.o: plot.c #unpacker unpacker_o = unpacker.o convert.o unpacker: $(unpacker_o) $(CC) $(unpacker_o) -o unpacker #packer packer_o = packer.o convert.o packer: $(packer_o) $(CC) $(packer_o) -o packer clean: rm -f *.o cleaner: clean rm -f intgen play sine plot packer unpacker rm -f *.BAK rm -f *~ nyquist-3.05/misc/cmdline.h0000644000175000000620000000016310144436365014710 0ustar stevestaffboolean cl_init(); char *cl_option(); char *cl_noption(); boolean cl_switch(); char *cl_nswitch(); char *cl_arg(); nyquist-3.05/misc/sine.c0000644000175000000620000000374510144436365014237 0ustar stevestaff/* * FILE: sine.c * BY: Christopher Lee Fraley (cf0v@spice.cs.cmu.edu) * DESC: Creates sine waves of given period, amplitude, and length. * * 1.0 ( 1-JUN-88) - created. (cf0v) * 2.0 ( 5-JUL-88) - converted to binary sound file format. (cf0v) */ /* * sine [-outfile] * Outputs integer sine wave of maximum , with * samples per period, and number of periods to stdout. Illegal * arguments cause the defaults 32767, 20, and 3 to be used, respectively. * If the flag "-outfile" is present, the output is in binary format to the * named file. If the flag is ommitted, the output is to stdout, and is in * ascii format, one number per line. */ #include #include #include "stdefs.h" #define PERMS 0644 /* -rw-r--r-- */ fails(s, s2) char *s, *s2; { fprintf(stderr, s, s2); exit(1); } main (argc,argv) int argc; char *argv[]; { double Amp, Samps, Perds; int i; if (argc!=4 && argc!=5) fails("format is 'sine %s'\n", " <#-of-periods> [-outfile]"); if (!sscanf(*++argv, "%lf", &Amp)) Amp = 32767.0; if (!sscanf(*++argv, "%lf", &Samps)) Samps = 20.0; if (!sscanf(*++argv, "%lf", &Perds)) Perds = 3.0; if (argc==5) { int fout; HWORD *Data, *ptr; unsigned int outLen, len; if (NULL > (fout = creat(*++argv+1, PERMS))) fails("could not create '%s'\n", *argv+1); outLen = Samps*Perds*sizeof(HWORD); ptr = Data = (HWORD *)malloc(outLen); if (NULL == Data) fails("could not allocate enough memory for output", ""); for (i=0; i<(Samps*Perds); i++) *ptr++ = (HWORD) (sin(2*PI*i/Samps) * Amp); len = write(fout, (char *)Data, outLen); if (len != outLen) fails("incorrect number of bytes written", ""); } else { for (i=0; i<(Samps*Perds); i++) printf("%d\n", (int)(sin(2*PI*i/Samps)*Amp)); } } nyquist-3.05/misc/cmu/0002755000175000000620000000000011537433127013712 5ustar stevestaffnyquist-3.05/misc/cmu/cmuinstallmac.sh0000644000175000000620000000306311514640104017070 0ustar stevestaff# cmuinstallmac.sh -- to update website with Mac OS X version of Nyquist # run this like this: source cmuinstallmac.sh ls ~/nyquist/*/*~ echo "build jNyqIDE deployment project with Xcode and type return" read mkdir -p ~/tmp/Applications cd ~/tmp/Applications ## can't remove and replace plight -- if you do, it won't work. ## I don't know why. Also, the following fails without sudo... # rm -rf NyquistIDE.app/Contents/Resources/Java/demos/plight rm -rf nyquist mkdir nyquist mkdir nyquist/doc cp ~/nyquist/doc/* nyquist/doc echo "type the version string, e.g. \"232\" : " read versionstring tar cvfz "nyqosx"$versionstring".tgz" ~/nyquist/macosxproject/build/Deployment/NyquistIDE.app nyquist mv nyqosx*.tgz ~/nyquist # Make source release cd ~/nyquist rm -rf nyquist svn export -r BASE . nyquist rm -rf nyquist/demos/plight zip -r "nyqsrc"$versionstring".zip" nyquist # THE FOLLOWING PUTS THE VERSION AT CMU, BUT NOW RELEASES GO TO SOURCEFORGE #scp "nyqosx"$versionstring".tgz" rbd@linux.gp.cs.cmu.edu:music/web/nyquist/ # HERE IS THE LINE FOR SOURCEFORGE #echo "when sftp connects..." #echo "> put nyqosx"$versionstring".tgz" #echo "> put nyqsrc"$versionstring".zip" #echo "> exit" #sftp rbd@frs.sourceforge.net #echo "after sftp'ing mac, windows, and source release files, go to" #echo "Admin : File Releases : Add Release to make a new release" echo go to sourceforge.net/projects/nyquist, Files, open nyquist echo Add Folder for current version, click the folder to open it echo Add File and browse to ~/nyquist/nyqsrcNNN.zip echo Add File and browse to ~/nyquist/nyqosxNNN.zip nyquist-3.05/misc/cmu/cmuinstall2.bat0000644000175000000620000000075111466723256016646 0ustar stevestaffcopy ..\..\setup\setupnyqrun.exe q:\web\nyquist\setupnyqrun231.exe copy ..\..\setup\setupnyqwinrun.exe q:\web\nyquist\setupnyqwinrun231.exe copy ..\..\setup\setupnyqiderun.exe q:\web\nyquist\setupnyqiderun231.exe copy new.html q:\web\music.software.html call cleanup.bat echo "In d:\rbd, make nyquist.zip from nyquist now...then type return to the pause..." pause move ..\..\..\nyquist.zip ..\..\..\nyquist231.zip copy ..\..\..\nyquist231.zip q:\web\nyquist\nyqsrc231.zip call restore.bat nyquist-3.05/misc/cmu/restore.bat0000644000175000000620000000116211466723256016071 0ustar stevestaffrem restore what cleanup.bat did cd ..\.. move ..\nyquist-backup\idesetup idesetup move ..\nyquist-backup\winsetup winsetup move ..\nyquist-backup\setup setup move ..\nyquist-backup\NyqWinDebug NyqWinDebug move ..\nyquist-backup\NyqWinRel NyqWinRel move ..\nyquist-backup\WinDebug WinDebug move ..\nyquist-backup\WinRel WinRel move ..\nyquist-backup\portaudio_test portaudio_test move ..\nyquist-backup\jones jones move ..\nyquist-backup\sjlib_103_DOS.tgz sjlib_103_DOS.tgz move ..\nyquist-backup\sjlib_DOS_104.tgz sjlib_DOS_104.tgz move ..\nyquist-backup\plight demos\plight move ..\nyquist-backup\nyqide nyqide cd misc\cmu nyquist-3.05/misc/cmu/cmuinstall.bat0000644000175000000620000000032311466723256016557 0ustar stevestaffrem run this to update the nyquist website copy q:\web\music.software.html music.software.html rem edit music.software.html and build install.bat del /q cmuinstall2.bat ..\..\winrel\nyquist.exe cmuinstall2.bat nyquist-3.05/misc/cmu/Projects.zip0000644000175000000620000001337111466723256016240 0ustar stevestaffPKɻ-4hProjects/New Project.sgp]N0Eo!7)KVUݡJ $@HtUF(u>_?LjYŵf\3 묔uq.4SMe'|%9Bd?z\R>e8 托O9IC-Qƨ  :~6.Kc oe,֑0.Jk=wj?nQRӛzhz#ր̊Fԕ)bVdѾjp+jb 0U_PK34,)Projects/nyqide_setup.sgpuRn0~Cyq]v)ˆ *Ob2%v;hfǧtO^'J,N{r||}|7^KD;D,L*I[7OL 'X"HP{mDa _'&m'_ :<>&G|]wDU z95d4Y-3lVڤ̭+X KlQZ&{|QRa;zW*\pDלn h Sl؅Xxdy.i7 bۦq#T\Gq[44YH!Projects/nyquist_setup.sgpmRn0~i /}V lJVݭ胥ʛuOsfV{NΜx^+u^?h0?v ^34x:yvZE~˟]6[h(Bt֪'E ` S&|%|pmd$Oŗ&'t2ٟy2H8qʇ>u0^*V9~ `l0 i 3,`]+锥^[ӇGI翭aT a;97C-fXӋ#, I."wm+n uhCrn:F&+#gkE[uk3Ь6Ѯ(`F8=յ#OPMm|0f,١.S"OʨZz[*S8 }UV}{,'v,ME-l*r{J݄Zʲ;nPK34h6-Projects/nyqwin_setup.sgpuRKO0KK[5▮p[ѥ Abу%dn*Cw~N?3N"VH=|g7"GtfvqMWM615_2޶RI~ Oȷ/(2 't^я@ﳋJ;#`4yԋ8_sWE!}&xy_9It؃M3ǃ('t*`_KMֈIIT2mɜ̄r1V^9ukk5IXWY3?yc΅q^fl=]N m$viikVpn|]OKps@l!VwbXڤ9әrbDMUJoKzbD.)5_&m o|FXMŽ|Ŏdh⒦>n_Un]MPSXY TPK34~i`?Projects/temp.logKoFt٣;b {5`P-3C뷚j>dH%C$_]U]:?˿#+q͟y_6qߢ7K϶~sU+{HeǕƌ+%mvy(NM?uj Fs2ٺ)3Yv.U旾9}}O"r\i Dx73br%Jcn.T2 zO6oIYL~\GICMD~!.OW&C9oLG( sBB˘)/fHИ% g!|׉nx!)@γ-i,lS &χoKmweU/1o%fpAydMx`]GvZ^ZH yBS]۷yPeM"tiX SGu';x̷ HmAUd*8\KĬ? )u̝n5P)K:Ⱈ7  KYgNGt{*K$/[_t<ɈNn*bM J>4tDϼUK6-ye% X*>i}`ͩ\!!{*` Us_oC)vY<]uS8bw7= `_YL%Hf{g,G)+G%bXi40 4"IGFfJA%SzEf1U &DyQ:vy2tvx!Tl3/]W+@:(^Es* U/c&[RjyߏP\(ܿo2TäRGj*:,̏sjy HQuzc;\pr:E%ܛ)#!߼3 .ogMޗj˕xf?OMs$޸ n>/#U6>|@r; _~>36rχ$)2i¸{Wh,ĕLq.#:05gX@aH/ 1敠^ \Cb)Lk3tO<=Y 7ob5Sggi`5S:u1͚ 12K'蒻@bfV ;! Oyϑ"JE}ƧS˘sW*CQ$=_RǨezG 42Tz(OEGW*K?&W*|ƋLwŴrYHhbi9OEPdXC"sx|{HF2ifO`([sɴ}dvAL ebaWtļ,P`Lr F/'gLԂz*^s [grj#0WJStDZ>G>ƶi˳cȌ-|> xzOX3T[B z,@b0E zi}#j/#K&y ~#/k>KML>YCJjqI}g@{(\z=sfrڶꖉ2&߂hK<y 6?5=X;0 eJ}Z`.eQN#W5`.echV@r0}(CĘlwor:`.e MDOۖڼ/R : t} nH*yzݾ"Ɓ clE[``gYT !"|9)#ǕKϚ50y01MF:]#dҶͥ^m<-F:q|#g_CQOSI&m{?]b?M3-uOkO6b^&albt B4NLjۂ9֭~lPWչi/unAZ\c81ܖY42ءSwb?dzUi\;~0&bƏŧtɹ4je9# Tղgd2KE.#̲.WV/h$><ݪejmp}Q `bkIl.2:1D"M'n1?y:WM?zUkHJq$LN(CٍnV!&8Qݷl>e@L"1U:O 1G=o6FLI2v0xGމFKe()?cp8g=byzA35}#Lc>LɧX=[24d{g &G+T9Onb}D;~" 2Dj(>uG9ogw2ИGCg)4k.x>!u di_V&~cdX#'|?PK ɻ-4h Projects/New Project.sgpPK 34,) 2Projects/nyqide_setup.sgpPK 34>H! FProjects/nyquist_setup.sgpPK 34h6- GProjects/nyqwin_setup.sgpPK 34~i`? TProjects/temp.logPK[nyquist-3.05/misc/cmu/cmu-linux-install.lsp0000644000175000000620000000444610144436365020025 0ustar stevestaff;; edit music.software.html and copy zip file to web ;; where is the html page for nyquist downloads?: (setf ny-web-path "/afs/cs/project/music/web/") ;; where are the actual nyquist download files: (setf ny-web-bin-path "/afs/cs/project/music/web/nyquist/") (defun ny-web (file) (strcat ny-web-path file)) ;; verbose version of SYSTEM ;; (defun vsystem (cmd) (format t "system command: ~A~%" cmd) (system cmd)) (defun linux-edit-music-software-html () (let (inf outf input i prefix postfix postfix1 postfix2) (setf inf (open (ny-web "music.software.html"))) (setf outf (open (ny-web "new.html") :direction :output)) (format t "Major version number (e.g. 2): ") (setf *maj* (read)) (format t "Minor version number (e.g. 27): ") (setf *min* (read)) ;; find "source code for Linux" (print "source code for Linux") (setf input (read-line inf)) (while (not (setf i (string-search "source code for Linux" input))) (format outf "~A~%" input) (setf input (read-line inf))) ;; now we have the line with the reference to the zip file and ;; also the text description, but we have to find the text to change ;; (ignore the variable i, it's the wrong location to change) (setf i (string-search "nyquist/nyquist" input)) (setf prefix (subseq input 0 (+ i 15))) (setf postfix (subseq input (+ i 15))) (setf i (string-search ".zip" postfix)) (setf postfix (subseq postfix i)) (setf i (string-search "(v" postfix)) (setf postfix1 (subseq postfix 0 (+ i 2))) (setf postfix2 (subseq postfix (+ i 2))) (setf i (string-search ")" postfix2)) (setf postfix2 (subseq postfix2 i)) (format outf "~A~A~A~A~A.~A~A~%" prefix *maj* *min* postfix1 *maj* *min* postfix2) (setf input (read-line inf)) (while input (format outf "~A~%" input) (setf input (read-line inf))) (close inf) (close outf) (vsystem (strcat "rm " (ny-web "music.software.html"))) (vsystem (strcat "mv " (ny-web "new.html") " " (ny-web "music.software.html"))) (vsystem (format nil "cp ../nyquist.zip ~Anyquist~A~A.zip" ny-web-bin-path *maj* *min*)) (vsystem (format nil "mv ../release.pac nyquist~A~A.pac" *maj* *min*)) )) (linux-edit-music-software-html) (exit) nyquist-3.05/misc/cmu/install-plight.sh0000644000175000000620000000037511466723256017212 0ustar stevestaff# # this is a script to post the plight drum machine to the web # # usage: on the Mac, source install-plight.sh # cd ../../demos zip -r plight.zip plight scp plight.zip rbd@linux.gp.cs.cmu.edu:music/web/nyquist/plight-1.zip rm plight.zip cd ../misc/cmu nyquist-3.05/misc/cmu/music.software.html0000644000175000000620000001454510144436365017560 0ustar stevestaff The Computer Music Project Software

    The Computer Music Project Software

    PortMusic

    Information about PortMusic

    Aura

    Aura is not available for general distribution, but you can read about Aura here. Send mail to Roger Dannenberg to get a copy of work in progress.

    Nyquist

    Nyquist is a sound synthesis and composition language based on a Lisp syntax. Nyquist is an elegant and powerful system based on functional programming.

    Documentation

    Executables (v2.27)

    Source

    Version 2.14 (older, but more tested than the latest release)

    If you have problems getting Nyquist, please contact Roger Dannenberg (rbd@cs.cmu.edu). 

    CMU MIDI Toolkit

    The CMU Midi Toolkit (CMT) is a collection of software for writing interactive MIDI software in C. CMT includes a number of handy utilities allong with an application "shell" that provides timing, scheduling, and MIDI interfaces that are portable across DOS, Mac, SGI, and Amiga platforms.

    CMT is distributed by the CMU School of Computer Science. For $30 to cover our costs, we will send you 3.5" DS/DD disks (including executables and source code) and an 100 page manual. Please indicate your machine type. Checks should be payable to Carnegie Mellon University, and correspondence should be addressed to Roger Dannenberg, School of Computer Science, Carnegie Mellon University, Pittsburgh, PA 15213 USA.

    CMT runs on the following systems:

      Macintosh (requires Apple MIDI Manager),

      DOS (requires MPU-401 compatible MIDI interface), and

      Amiga (requires Commodore CAMD drivers),

    using the following compilers: Think C v5, Borland C++ v3, Turbo C++ for DOS v3, Microsoft C v7, Quick C v2.5, Lattice C v5 (Amiga), and Aztec C v5 (Amiga). (Amiga code is retained in the release but is no longer supported.)

    Documentation

    Executables

    Source

    Maintained by:
    rbd@cs.cmu.edu
    nyquist-3.05/misc/cmu/new.html0000644000175000000620000001454510144436365015400 0ustar stevestaff The Computer Music Project Software

    The Computer Music Project Software

    PortMusic

    Information about PortMusic

    Aura

    Aura is not available for general distribution, but you can read about Aura here. Send mail to Roger Dannenberg to get a copy of work in progress.

    Nyquist

    Nyquist is a sound synthesis and composition language based on a Lisp syntax. Nyquist is an elegant and powerful system based on functional programming.

    Documentation

    Executables (v2.29)

    Source

    Version 2.14 (older, but more tested than the latest release)

    If you have problems getting Nyquist, please contact Roger Dannenberg (rbd@cs.cmu.edu). 

    CMU MIDI Toolkit

    The CMU Midi Toolkit (CMT) is a collection of software for writing interactive MIDI software in C. CMT includes a number of handy utilities allong with an application "shell" that provides timing, scheduling, and MIDI interfaces that are portable across DOS, Mac, SGI, and Amiga platforms.

    CMT is distributed by the CMU School of Computer Science. For $30 to cover our costs, we will send you 3.5" DS/DD disks (including executables and source code) and an 100 page manual. Please indicate your machine type. Checks should be payable to Carnegie Mellon University, and correspondence should be addressed to Roger Dannenberg, School of Computer Science, Carnegie Mellon University, Pittsburgh, PA 15213 USA.

    CMT runs on the following systems:

      Macintosh (requires Apple MIDI Manager),

      DOS (requires MPU-401 compatible MIDI interface), and

      Amiga (requires Commodore CAMD drivers),

    using the following compilers: Think C v5, Borland C++ v3, Turbo C++ for DOS v3, Microsoft C v7, Quick C v2.5, Lattice C v5 (Amiga), and Aztec C v5 (Amiga). (Amiga code is retained in the release but is no longer supported.)

    Documentation

    Executables

    Source

    Maintained by:
    rbd@cs.cmu.edu
    nyquist-3.05/misc/cmu/nyqwin_setup.sgp0000644000175000000620000000146011466723256017177 0ustar stevestaff( nyqwin.exeT readme.txt Have fun!}3,"0,"Nyquist-Win32",0,"nyqwin.exe",""","0,"Nyquist Manual",0,"doc\home.html",""","0,"Demos",0,"demos\examples_home.htm","""0U1,"0,2,"SOFTWARE\CMU\Nyquist","XLISPPATH",0,""#setuppath#\runtime;#setuppath#\lib"""L0RE:\rbd\nyquist\nyqrelwin:EnglishInstalling NyquistNyquist0setupnyqwinrun.exe0E:\rbd\nyquist\winsetup\;0C:\Program Files\Setup Generator\Projects\nyqwin_setup.sgp?Nyquist, a language for sound synthesis and music composition.%E:\rbd\nyquist\nyqrelwin\license.txt % % Times Installation Nyquistnyquist-3.05/misc/cmu/init.lsp0000644000175000000620000001704011466723256015403 0ustar stevestaff;; edit music.software.html and make install.bat (load "nyinit.lsp") ;; see if we are running on Windows (setf *windowsp* (not (null (listdir "WinRel")))) (setf *remote* (if *windowsp* "q:\\web" "rbd@linux.gp.cs.cmu.edu:music/web")) (defun edit-music-software-html () (let (inf outf input i prefix postfix postfix1 postfix2) (setf inf (open "music.software.html")) (if (null inf) (error "could not open music.software.html")) (setf outf (open "new.html" :direction :output)) (if (null outf) (error "could not open new.html for output")) (format t "Major version number (e.g. 2): ") (setf *maj* (read)) (format t "Minor version number (e.g. 27): ") (setf *min* (read)) ;; find version in heading (print "find Executables") (setf input (read-line inf)) (while (not (setf i (string-search "Executables (v" input))) (format outf "~A~%" input) (setf input (read-line inf))) (setf prefix (subseq input 0 (+ i 14))) (setf postfix (subseq input (+ i 14))) (setf i (string-search ")" postfix)) (setf postfix (subseq postfix i)) (format outf "~A~A.~A~A~%" prefix *maj* *min* postfix) ;; find nyquist/setupnyqrun (print "find nyquist/setupnyqrun") (setf input (read-line inf)) (while (not (setf i (string-search "nyquist/setupnyqrun" input))) (format outf "~A~%" input) (setf input (read-line inf)) ;(display "finding nyquist/setupnyqrun" input) ) (setf prefix (subseq input 0 (+ i 19))) (setf postfix (subseq input (+ i 19))) (setf i (string-search "\">" postfix)) (setf postfix (subseq postfix i)) (format outf "~A~A~A.exe~A~%" prefix *maj* *min* postfix) ;; find nyquist/setupnyqwinrun ; (print "find nyquist/setupnyqwinrun") ; (setf input (read-line inf)) ; (while (not (setf i (string-search "nyquist/setupnyqwinrun" input))) ; (format outf "~A~%" input) ; (setf input (read-line inf))) ; (setf prefix (subseq input 0 (+ i 22))) ; (setf postfix (subseq input (+ i 22))) ; (setf i (string-search "\">" postfix)) ; (setf postfix (subseq postfix i)) ; (format outf "~A~A~A.exe~A~%" prefix *maj* *min* postfix) ;; find nyquist/setupnyqiderun (print "find nyquist/setupnyqiderun") (setf input (read-line inf)) (while (not (setf i (string-search "nyquist/setupnyqiderun" input))) (format outf "~A~%" input) (setf input (read-line inf))) (setf prefix (subseq input 0 (+ i 22))) (setf postfix (subseq input (+ i 22))) (setf i (string-search "\">" postfix)) (setf postfix (subseq postfix i)) (format outf "~A~A~A.exe~A~%" prefix *maj* *min* postfix) ;; find nyquist/nyqosx (print "find nyquist/nyqosx") (setf input (read-line inf)) (while (not (setf i (string-search "nyquist/nyqosx" input))) (format outf "~A~%" input) (setf input (read-line inf))) (setf prefix (subseq input 0 (+ i 14))) (setf postfix (subseq input (+ i 14))) (setf i (string-search ".tgz" postfix)) (setf postfix (subseq postfix i)) (setf i (string-search "(v" postfix)) (setf postfix1 (subseq postfix 0 (+ i 2))) (setf postfix2 (subseq postfix (+ i 2))) (setf i (string-search ")" postfix2)) (setf postfix2 (subseq postfix2 i)) (format outf "~A~A~A~A~A.~A~A~%" prefix *maj* *min* postfix1 *maj* *min* postfix2) ;; find nyqosx (print "find nyqosx") (setf input (read-line inf)) (while (not (setf i (string-search "nyqosx" input))) (format outf "~A~%" input) (setf input (read-line inf))) (setf prefix (subseq input 0 (+ i 10))) (setf postfix (subseq input (+ i 10))) (setf i (string-search "" postfix)) (setf postfix (subseq postfix i)) (format outf "~A~A~A~A~%" prefix *maj* *min* postfix) ;; find nyquist/nyqsrc (print "find nyquist/nyqsrc") (setf input (read-line inf)) (while (not (setf i (string-search "nyquist/nyqsrc" input))) (format outf "~A~%" input) (setf input (read-line inf))) (setf prefix (subseq input 0 (+ i 14))) (setf postfix (subseq input (+ i 14))) (setf i (string-search ".zip" postfix)) (setf postfix (subseq postfix i)) (setf i (string-search "(v" postfix)) (setf postfix1 (subseq postfix 0 (+ i 2))) (setf postfix2 (subseq postfix (+ i 2))) (setf i (string-search ")" postfix2)) (setf postfix2 (subseq postfix2 i)) (format outf "~A~A~A~A~A.~A~A~%" prefix *maj* *min* postfix1 *maj* *min* postfix2) (setf input (read-line inf)) (while input (format outf "~A~%" input) (setf input (read-line inf))) (close inf) (close outf) )) ; " (defun make-install-bat () (let (outf) (setf outf (open "cmuinstall2.bat" :direction :output)) (format outf "copy ..\\..\\setup\\setupnyqrun.exe ~A\\nyquist\\setupnyqrun~A~A.exe~%" *remote* *maj* *min*) ; (format outf "copy ..\\..\\setup\\setupnyqwinrun.exe ~A\\nyquist\\setupnyqwinrun~A~A.exe~%" ; *remote* *maj* *min*) (format outf "copy ..\\..\\setup\\setupnyqiderun.exe ~A\\nyquist\\setupnyqiderun~A~A.exe~%" *remote* *maj* *min*) (format outf "copy new.html ~A\\music.software.html~%" *remote*) (format outf "call cleanup.bat~%") (format outf "echo \"In d:\\rbd, make nyquist.zip from nyquist now...then type return to the pause...\"~%") (format outf "pause~%") (format outf "move ..\\..\\..\\nyquist.zip ..\\..\\..\\nyquist~A~A.zip~%" *maj* *min*) (format outf "copy ..\\..\\..\\nyquist~A~A.zip ~A\\nyquist\\nyqsrc~A~A.zip~%" *maj* *min* *remote* *maj* *min*) (format outf "call restore.bat~%") (close outf))) (defun make-install-sh () (let (outf) (setf outf (open "cmuinstall2.sh" :direction :output)) (format outf "echo \"Make sure /Volumes/rbd is mounted...then type return\"~%") (format outf "read~%"); (format outf "scp /Volumes/rbd/nyquist/setup/setupnyqrun.exe ~A/nyquist/setupnyqrun~A~A.exe~%" *remote* *maj* *min*) ; (format outf "scp /Volumes/rbd/nyquist/setup/setupnyqwinrun.exe ~A/nyquist/setupnyqwinrun~A~A.exe~%" ; *remote* *maj* *min*) (format outf "scp /Volumes/rbd/nyquist/setup/setupnyqiderun.exe ~A/nyquist/setupnyqiderun~A~A.exe~%" *remote* *maj* *min*) (format outf "scp new.html ~A/music.software.html~%" *remote*) #| ;; this is the old way to make a source zip file (format outf "echo \"In e:\\rbd\\nyquist\\misc\\cmu, run cleanup.bat now...then type return to the pause...\"~%") (format outf "read~%") (format outf "echo \"In e:\\rbd, make nyquist.zip from nyquist now...then type return to the pause...\"~%") (format outf "read~%") (format outf "mv /Volumes/rbd/nyquist.zip /Volumes/rbd/nyquist~A~A.zip~%" *maj* *min*) (format outf "scp /Volumes/rbd/nyquist~A~A.zip ~A/nyquist/nyqsrc~A~A.zip~%" *maj* *min* *remote* *maj* *min*) (format outf "echo \"In e:\\rbd\\nyquist\\misc\\cmu, run restore.bat now...then type return to the pause...\"~%") |# ;; this is the new way to make a source zip file (format outf "echo making source zip file...\n") (format outf "cd ../..\n") (format outf "cvs export -DNOW nyquist\n") (format outf "rm -rf nyquist/demos/plight\n") (format outf "zip -r nyquist.zip nyquist\n") (format outf "scp nyquist.zip ~A/nyquist/nyqsrc~A~A.zip~%" *remote* *maj* *min*) (format outf "rm -rf nyquist.zip nyquist\n") (format outf "cd misc/cmu\n") (format outf "read~%") (close outf))) (edit-music-software-html) (if *windowsp* (make-install-bat) (make-install-sh)) (exit) nyquist-3.05/misc/cmu/cmuinstall.sh0000644000175000000620000000033411466723256016425 0ustar stevestaff # source this to update the nyquist website scp rbd@linux.gp.cs.cmu.edu:music/web/music.software.html music.software.html # edit music.software.html and build install.bat rm -f cmuinstall2.sh ../../ny s cmuinstall2.sh nyquist-3.05/misc/cmu/nyquist_setup.sgp0000644000175000000620000000144111466723256017365 0ustar stevestaff nyquist.exeX readme.txt Have fun!RE:\rbd\nyquist\nyqrel0U1,"0,2,"SOFTWARE\CMU\Nyquist","XLISPPATH",0,""#setuppath#\runtime;#setuppath#\lib"""x3,"0,"Nyquist",0,"nyquist.exe",""","0,"Nyquist Manual",0,"doc\home.html",""","0,"Demos",0,"demos\examples_home.htm","""DEnglishInstalling NyquistNyquistXsetupnyqrun.exeXE:\rbd\nyquist\setup\0<C:\Program Files\Setup Generator\Projects\nyquist_setup.sgp? Nyquist, a language for sound synthesis and music composition." E:\rbd\nyquist\nyqrel\license.txt " " Times Installation Nyquistnyquist-3.05/misc/cmu/cleanup.bat0000644000175000000620000000230611466723256016036 0ustar stevestaffrem erase everything but source so we can save sources to web cd ..\.. rmdir /s /q nyqrel rmdir /s /q nyqrelide rmdir /s /q nyqrelwin rmdir /s /q misc\filelist_Release rmdir /s /q misc\packer_Release rmdir /s /q misc\intgen_win32 rmdir /s /q misc\unpacker_Release del *.pac del *.ncb del unpacker.exe del packer.exe del mt.dep del jnyqide\*.class del nyquist.exe del jnyqide\*.jar del *.jar rmdir /s /q ..\nyquist-backup mkdir ..\nyquist-backup move idesetup ..\nyquist-backup move winsetup ..\nyquist-backup move setup ..\nyquist-backup move NyqWinDebug ..\nyquist-backup move NyqWinRel ..\nyquist-backup move WinDebug ..\nyquist-backup move WinRel ..\nyquist-backup move portaudio_test ..\nyquist-backup move jones ..\nyquist-backup move sjlib_103_DOS.tgz ..\nyquist-backup move sjlib_DOS_104.tgz ..\nyquist-backup move demos\plight ..\nyquist-backup move nyqide ..\nyquist-backup del nyqide\nyquist.exe del nyquist.opt rmdir /s /q misc\filelist_Debug rmdir /s /q misc\intgen_Win32\WinDebug rmdir /s /q misc\packer_Debug rmdir /s /q misc\unpacker_Debug rmdir /s /q liblo\ser-to-osc\Debug rmdir /s /q liblo\ser-to-osc\Release rmdir /s /q liblo\test-client\Debug rmdir /s /q liblo\test-client\Release cd misc\cmu nyquist-3.05/misc/cmu/nyqide_setup.sgp0000644000175000000620000000145411466723256017146 0ustar stevestaff$ jnyqide.batT readme.txt Have fun!FE:\rbd\nyquist\nyqrelide00U1,"0,2,"SOFTWARE\CMU\Nyquist","XLISPPATH",0,""#setuppath#\runtime;#setuppath#\lib"""x3,"0,"Nyquist",0,"jnyqide.bat",""","0,"Nyquist Manual",0,"doc\home.html",""","0,"Demos",0,"demos\examples_home.htm",""":EnglishInstalling NyquistNyquistsetupnyqiderun.exeE:\rbd\nyquist\idesetup\;pC:\Program Files\Setup Generator\Projects\nyqide_setup.sgp? Nyquist, a language for sound synthesis and music composition.% E:\rbd\nyquist\nyqrelide\license.txt % % Times Installation Nyquistnyquist-3.05/misc/cmdline.c0000644000175000000620000003030110144436365014700 0ustar stevestaff/* cmdline.c -- command line parsing routines */ /* * This module is designed to allow various modules to scan (and rescan) * the command line for applicable arguments. The goal is to hide as * much information about switches and their names as possible so that * switches become more consistent across applications and so that the * author of an application need not do a lot of work to provide numerous * options. Instead, each module scans the command line for its own * arguments. * * Command lines are of the following form: * command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3 * command @filename * The @filename form reads commands of the first form from filename * Note that there are three kinds of command line parameters: * (1) A Switch is a "-" followed by a name, e.g. "-s1" * (2) An Option is a Switch followed by a space and name, e.g. "-s2 opt2" * (3) An Argument is a name by itself, e.g. "arg1" * Note also that a switch followed by an argument looks just like an * option, so a list of valid option names is necessary to disambiguate. * * A main program that uses cmdline.c should do the following: * (1) create an array of pointers to strings (char *names[]) that * contains every possible option name * (2) create another array of pointers to strings that contains * every possible switch name * (2) call cl_init(switches, nsw, options, nopt, argv, argc) * cl_init will report an error (to stderr) if it finds any illegal * switch or option names. * * Afterward, switches, options, and arguments can be accessed by * calling cl_switch, cl_option, and cl_arg. If cl_switch or cl_option * is called with a switch name that was not mentioned in the call to * cl_init, an error will result. This indicates that the application * author omitted a valid switch or option name when calling cl_init. * This is an error because the full set of names is needed for error * checking and to distinguish arguments from options. * * cl_nswitch and cl_noption are similar to cl_switch and cl_option, * except they each take a list of equivalent switch or option names. * This makes it simple to allow both verbose (-debug) and terse (-d) names. */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 13-Jun-86 | Created Change Log * 6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines * 27-Dec-93 | "@file" as first arg reads command line args from file *****************************************************************************/ #include "stdlib.h" #include "cext.h" #include "stdio.h" #include "ctype.h" #include "cmdline.h" #include "string.h" private char **voptions; /* valid options */ private int noptions; /* number of options */ private char **vswitches; /* valid switches */ private int nswitches; /* number of switches */ private char **argv; /* command line argument vector */ private int argc; /* length of argv */ private int cl_rdy = false; /* set to true when initialized */ /***************************************************************************** * Routines local to this module *****************************************************************************/ private void check_names(); private int find_match(); private int find_string(); private void ready_check(); void indirect_command(char *filename, char ***argvp, int *argcp, char *oldarg0); /**************************************************************** * check_names * Inputs: * char *names[]: array of alternative switch or option names * int nnames: number of alternative switch or option names * char *valid[]: array of valid names * int nvalid: number of valid names * Effect: * Checks that all names are in validnames. If not, print * an error message. *****************************************************************/ private void check_names(names, nnames, valid, nvalid) char *names[]; int nnames; char *valid[]; int nvalid; { int i; /* loop counters */ for (i = 0; i < nnames; i++) { if (find_string(names[i], valid, nvalid) >= nvalid) { fprintf(stderr, "internal error detected by cmdline module:\n"); fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]); } } } /**************************************************************** * cl_arg * Inputs: * n: the index of the arg needed * Results: * pointer to the nth arg, or NULL if none exists * arg 0 is the command name *****************************************************************/ char *cl_arg(n) int n; { int i = 1; if (n <= 0) return argv[0]; while (i < argc) { if (*argv[i] == '-') { if (find_string(argv[i], voptions, noptions) < noptions) i += 2; /* skip name and option */ else i += 1; /* skip over switch name */ } else if (n == 1) { return argv[i]; } else { /* skip over argument */ n--; i++; } } return NULL; } /***************************************************************************** * cl_init * Inputs: * char *switches[]: array of switch names * int nsw: number of switch names * char *options[]: array of option names * int nopt: number of option names * char *av: array of command line fields (argv) * int ac: number of command line fields (argc) * Effect: * Checks that all command line entries are valid. * Saves info for use by other routines. * Returns: * True if syntax checks OK, otherwise false *****************************************************************************/ boolean cl_init(switches, nsw, options, nopt, av, ac) char *switches[]; int nsw; char *options[]; int nopt; char *av[]; int ac; { int i; /* index into argv */ boolean result = true; vswitches = switches; nswitches = nsw; voptions = options; noptions = nopt; argv = av; argc = ac; if (ac == 2 && *(av[1]) == '@') { /* read new args from file */ indirect_command(av[1] + 1, &argv, &argc, av[0]); } for (i = 1; i < argc; i++) { /* case fold lower */ size_t j; for (j = 0; j < strlen(argv[i]); j++) if (isupper(argv[i][j])) argv[i][j] = tolower(argv[i][j]); } /* check command line syntax: */ i = 1; while (i < argc) { if (*argv[i] == '-') { if (find_string(argv[i], voptions, noptions) < noptions) { i += 1; /* skip name and option */ if (i < argc && *argv[i] == '-') { fprintf(stderr, "missing argument after %s\n", argv[i-1]); result = false; i += 1; } } else if (find_string(argv[i], vswitches, nswitches) < nswitches) { i += 1; /* skip over switch name */ } else { fprintf(stderr, "invalid switch: %s\n", argv[i]); i += 1; result = false; } } else i++; /* skip over argument */ } cl_rdy = true; return result; } /**************************************************************** * cl_noption * Inputs: * char *names[]: array of alternative switch names * int nnames: number of alternative switch names * Result: * returns pointer to if one exists, otherwise null * Effect: * looks for pattern in command line of the form "-n s", * where n is a member of names. Returns pointer to s. * Implementation: * find the option name, then * see if the switch is followed by a string that does * not start with "-" *****************************************************************/ char *cl_noption(names, nnames) char *names[]; int nnames; { int i; /* index of switch */ ready_check(); check_names(names, nnames, voptions, noptions); i = find_match(names, nnames) + 1; /* point at the option */ if (i < argc) { /* make sure option exists */ if (*(argv[i]) != '-') return argv[i]; } return NULL; } /***************************************************************** * cl_nswitch * Inputs: * char *names[]: array of alternative switch names * int nnames: number of alternative switch names * Effect: * Checks that names is valid. * Finds a pattern in command line of the form "-n", where * n is a member of names. * Result: * returns pointer to command line switch if one exists, * otherwise null *****************************************************************/ char *cl_nswitch(names, nnames) char *names[]; int nnames; { int i; /* index of switch */ ready_check(); check_names(names, nnames, vswitches, nswitches); i = find_match(names, nnames); if (i < argc) return argv[i]; /* else */ return NULL; } /**************************************************************** * cl_option * Inputs: * char *name: option name * Outputs: * returns char *: the option string if found, otherwise null ****************************************************************/ char *cl_option(name) char *name; { char *names[1]; /* array to hold name */ names[0] = name; return cl_noption(names, 1); } /**************************************************************** * cl_switch * Inputs: * char *name: switch name * Outputs: * boolean: true if switch found ****************************************************************/ boolean cl_switch(name) char *name; { char *names[1]; /* array to hold name */ names[0] = name; return cl_nswitch(names, 1) != NULL; } /**************************************************************** * find_match * Inputs: * char *names[]: array of alternative switch or option names * int nnames: number of alternative switch or option names * Effect: * Looks for command line switch that matches one of names. * Returns: * Index of switch if found, argc if not found. *****************************************************************/ private int find_match(names, nnames) char *names[]; int nnames; { int j; /* loop counter */ for (j = 0; j < argc; j++) { if (find_string(argv[j], names, nnames) < nnames) return j; } return argc; } /**************************************************************** * find_string * Inputs: * char *s: string to find * char *names[]: array of strings * int nnames: number of strings * Effect: * Looks for s in names * Returns: * Index of s in names if found, nnames if not found *****************************************************************/ private int find_string(s, names, nnames) char *s; char *names[]; int nnames; { int i; /* loop counter */ for (i = 0; i < nnames; i++) { if (strcmp(s, names[i]) == 0) { return i; } } return nnames; } boolean is_whitespace(int c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; } boolean get_arg(file, arg) FILE *file; char *arg; { int c; while ((c = getc(file)) != EOF && is_whitespace(c)) ; if (c == EOF) return false; ungetc(c, file); while ((c = getc(file)) != EOF && !is_whitespace(c)) { *arg++ = c; } *arg = 0; return true; } void indirect_command(filename, argvp, argcp, oldarg0) char *filename; char ***argvp; int *argcp; char *oldarg0; { FILE *argfile = fopen(filename, "r"); if (!argfile) { *argvp = (char **) malloc(sizeof(char *)); (*argvp)[0] = oldarg0; *argcp = 1; } else { int i = 1; char arg[100]; while (get_arg(argfile, arg)) i++; fclose(argfile); argfile = fopen(filename, "r"); *argvp = (char **) malloc(sizeof(char *) * i); (*argvp)[0] = oldarg0; *argcp = i; i = 1; while (get_arg(argfile, arg)) { (*argvp)[i] = (char *) malloc(strlen(arg) + 1); strcpy((*argvp)[i], arg); i++; } } } /**************************************************************** * ready_check * Effect: * Halt program if cl_rdy is not true. *****************************************************************/ private void ready_check() { if (!cl_rdy) { fprintf(stderr, "Internal error: cl_init was not called, see cmdline.c\n"); exit(1); } } nyquist-3.05/misc/filelist.dsp0000644000175000000620000001017611466723256015462 0ustar stevestaff# Microsoft Developer Studio Project File - Name="filelist" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=filelist - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "filelist.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "filelist.mak" CFG="filelist - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "filelist - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "filelist - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "filelist - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "filelist_Release" # PROP Intermediate_Dir "filelist_Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "filelist - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "filelist_Debug" # PROP Intermediate_Dir "filelist_Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../cmt" /D "_CONSOLE" /D "_MBCS" /D "WIN32" /D "_DEBUG" /D "DEBUG_INPUT" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "filelist - Win32 Release" # Name "filelist - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\cmdline.c # End Source File # Begin Source File SOURCE=.\filelist.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\tran\delaycc.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nyquist-3.05/misc/packer.vcproj0000644000175000000620000001411511512143043015604 0ustar stevestaff nyquist-3.05/runtime/0002755000175000000620000000000011537433122013651 5ustar stevestaffnyquist-3.05/runtime/printrec.lsp0000644000175000000620000000154010144436365016222 0ustar stevestaff; prints recursive list structure ;(let (seen-list) (setf seenlist nil) (defun seenp (l) (member l seenlist :test 'eq)) (defun make-seen (l) (setf seenlist (cons l seenlist))) (defun printrec (l) (printrec-any l) (setf seenlist nil)) (defun printrec-any (l) (cond ((atom l) (prin1 l) (princ " ")) ((seenp l) (princ "<...> ")) (t (make-seen l) (princ "(") (printrec-list l) (princ ") "))) nil) (defun printrec-list (l) (printrec-any (car l)) (cond ((cdr l) (cond ((seenp (cdr l)) (princ "<...> ")) ((atom (cdr l)) (princ ". ") (prin1 (cdr l)) (princ " ")) (t (make-seen (cdr l)) (printrec-list (cdr l)))))) nil) ; ) nyquist-3.05/runtime/fileio.lsp0000644000175000000620000003044711524074337015653 0ustar stevestaff;; fileio.lsp ;; if *default-sf-dir* undefined, set it to user's tmp directory ;; (cond ((not (boundp '*default-sf-dir*)) ;; it would be nice to use get-temp-path, but when running ;; the Java-based IDE, Nyquist does not get environment ;; variables to tell TMP or TEMP or USERPROFILE ;; We want to avoid the current directory because it may ;; be read-only. Search for some likely paths... ;; Note that since these paths don't work for Unix or OS X, ;; they will not be used, so no system-dependent code is ;; needed (let ((current (setdir "."))) (setf *default-sf-dir* (or (setdir "c:\\tmp\\" nil) (setdir "c:\\temp\\" nil) (setdir "d:\\tmp\\" nil) (setdir "d:\\temp\\" nil) (setdir "e:\\tmp\\" nil) (setdir "e:\\temp\\" nil) (get-temp-path))) (format t "Set *default-sf-dir* to \"~A\" in fileio.lsp~%" *default-sf-dir*) (setdir current)))) ;; if the steps above fail, then *default-sf-dir* might be "" (especially ;; on windows), and the current directory could be read-only on Vista and ;; Windows 7. Therefore, the Nyquist IDE will subsequently call ;; suggest-default-sf-dir with Java's idea of a valid temp directory. ;; If *default-sf-dir* is the empty string (""), this will set the variable: (defun suggest-default-sf-dir (path) (cond ((equal *default-sf-dir* "") (setf *default-sf-dir* path)))) ;; s-save -- saves a file (setf NY:ALL 1000000000) ; 1GIG constant for maxlen (defmacro s-save (expression &optional (maxlen NY:ALL) filename &key (format '*default-sf-format*) (mode '*default-sf-mode*) (bits '*default-sf-bits*) (endian NIL) ; nil, :big, or :little -- specifies file format (play nil)) `(let ((ny:fname ,filename) (ny:maxlen ,maxlen) (ny:endian ,endian) (ny:swap 0)) ; allow caller to omit maxlen, in which case the filename will ; be a string in the maxlen parameter position and filename will be null (cond ((null ny:fname) (cond ((stringp ny:maxlen) (setf ny:fname ny:maxlen) (setf ny:maxlen NY:ALL)) (t (setf ny:fname *default-sound-file*))))) (cond ((equal ny:fname "") (cond ((not ,play) (format t "s-save: no file to write! play option is off!\n")))) (t (setf ny:fname (soundfilename ny:fname)) (format t "Saving sound file to ~A~%" ny:fname))) (cond ((eq ny:endian :big) (setf ny:swap (if (bigendianp) 0 1))) ((eq ny:endian :little) (setf ny:swap (if (bigendianp) 1 0)))) (snd-save ',expression ny:maxlen ny:fname ,format ,mode ,bits ny:swap ,play))) ;; MULTICHANNEL-MAX -- find peak over all channels ;; (defun multichannel-max (snd samples) (cond ((soundp snd) (snd-max snd samples)) ((arrayp snd) ;; assume it is multichannel sound (let ((peak 0.0) (chans (length snd))) (dotimes (i chans) (setf peak (max peak (snd-max (aref snd i) (/ samples chans))))) peak)) (t (error "unexpected value in multichannel-max" snd)))) ;; AUTONORM -- look ahead to find peak and normalize sound to 80% ;; (defun autonorm (snd) (let (peak) (cond (*autonormflag* (cond ((and (not (soundp snd)) (not (eq (type-of snd) 'ARRAY))) (error "AUTONORM (or PLAY?) got unexpected value" snd)) ((eq *autonorm-type* 'previous) (scale *autonorm* snd)) ((eq *autonorm-type* 'lookahead) (setf peak (multichannel-max snd *autonorm-max-samples*)) (setf peak (max 0.001 peak)) (setf *autonorm* (/ *autonorm-target* peak)) (scale *autonorm* snd)) (t (error "unknown *autonorm-type*")))) (t snd)))) (defmacro s-save-autonorm (expression &rest arglist) `(let ((peak (s-save (autonorm ,expression) ,@arglist))) (autonorm-update peak))) ;; The "AutoNorm" facility: when you play something, the Nyquist play ;; command will automatically compute what normalization factor you ;; should have used. If you play the same thing again, the normalization ;; factor is automatically applied. ;; ;; Call AUTONORM-OFF to turn off this feature, and AUTONORM-ON to turn ;; it back on. ;; ;; *autonorm-target* is the peak value we're aiming for (it's set below 1 ;; so allow the next signal to get slightly louder without clipping) ;; (init-global *autonorm-target* 0.9) ;; ;; *autonorm-type* selects the autonorm algorithm to use ;; 'previous means normalize according to the last computed sound ;; 'precompute means precompute *autonorm-max-samples* samples in ;; memory and normalize according to the peak ;; (init-global *autonorm-type* 'lookahead) (init-global *autonorm-max-samples* 1000000) ; default is 4MB buffer ;; (defun autonorm-on () (setf *autonorm* 1.0) (setf *autonorm-previous-peak* 1.0) (setf *autonormflag* t) (format t "AutoNorm feature is on.~%")) (if (not (boundp '*autonormflag*)) (autonorm-on)) (defun autonorm-off () (setf *autonormflag* nil) (setf *autonorm* 1.0) (format t "AutoNorm feature is off.~%")) ;; AUTONORM-UPDATE -- called with true peak to report and prepare ;; ;; after saving/playing a file, we have the true peak. This along ;; with the autonorm state is printed in a summary and the autonorm ;; state is updated for next time. ;; ;; There are currently two types: PREVIOUS and LOOKAHEAD ;; With PREVIOUS: ;; compute the true peak and print the before and after peak ;; along with the scale factor to be used next time ;; With LOOKAHEAD: ;; compute the true peak and print the before and after peak ;; along with the "suggested scale factor" that would achieve ;; the *autonorm-target* ;; (defun autonorm-update (peak) (cond ((> peak 1.0) (format t "*** CLIPPING DETECTED! ***~%"))) (cond ((and *autonormflag* (> peak 0.0)) (setf *autonorm-previous-peak* (/ peak *autonorm*)) (setf *autonorm* (/ *autonorm-target* *autonorm-previous-peak*)) (format t "AutoNorm: peak was ~A,~%" *autonorm-previous-peak*) (format t " peak after normalization was ~A,~%" peak) (format t (if (eq *autonorm-type* 'PREVIOUS) " new normalization factor is ~A~%" " suggested normalization factor is ~A~%") *autonorm*)) (t (format t "Peak was ~A,~%" peak) (format t " suggested normalization factor is ~A~%" (/ *autonorm-target* peak))) peak )) ;; s-read -- reads a file (defun s-read (filename &key (time-offset 0) (srate *sound-srate*) (dur 10000.0) (nchans 1) (format *default-sf-format*) (mode *default-sf-mode*) (bits *default-sf-bits*) (endian NIL)) (let ((swap 0)) (cond ((eq endian :big) (setf swap (if (bigendianp) 0 1))) ((eq endian :little) (setf swap (if (bigendianp) 1 0)))) (if (minusp dur) (error "s-read :dur is negative" dur)) (snd-read (soundfilename filename) time-offset (local-to-global 0) format nchans mode bits swap srate dur))) ;; SF-INFO -- print sound file info ;; (defun sf-info (filename) (let (s format channels mode bits swap srate dur flags) (format t "~A:~%" (soundfilename filename)) (setf s (s-read filename)) (setf format (car *rslt*)) (setf channels (cadr *rslt*)) (setf mode (caddr *rslt*)) (setf bits (cadddr *rslt*)) (setf *rslt* (cddddr *rslt*)) (setf swap (car *rslt*)) (setf srate (cadr *rslt*)) (setf dur (caddr *rslt*)) (setf flags (cadddr *rslt*)) (format t "Format: ~A~%" (nth format '("none" "AIFF" "IRCAM" "NeXT" "Wave" "PAF" "SVX" "NIST" "VOC" "W64" "MAT4" "Mat5" "PVF" "XI" "HTK" "SDS" "AVR" "SD2" "FLAC" "CAF"))) (cond ((setp (logand flags snd-head-channels)) (format t "Channels: ~A~%" channels))) (cond ((setp (logand flags snd-head-mode)) (format t "Mode: ~A~%" (nth mode '("ADPCM" "PCM" "uLaw" "aLaw" "Float" "UPCM" "unknown" "double" "GSM610" "DWVW" "DPCM" "msadpcm"))))) (cond ((setp (logand flags snd-head-bits)) (format t "Bits/Sample: ~A~%" bits))) (cond ((setp (logand flags snd-head-srate)) (format t "SampleRate: ~A~%" srate))) (cond ((setp (logand flags snd-head-dur)) (format t "Duration: ~A~%" dur))) )) ;; SETP -- tests whether a bit is set (non-zero) ; (defun setp (bits) (not (zerop bits))) ;; IS-FILE-SEPARATOR -- is this a file path separation character, e.g. "/"? ;; (defun is-file-separator (c) (or (eq c *file-separator*) (and (eq *file-separator* #\\) ;; if this is windows (indicated by "\") (eq c #\/)))) ;; then "/" is also a file separator ;; SOUNDFILENAME -- add default directory to name to get filename ;; (defun soundfilename (filename) (cond ((= 0 (length filename)) (break "filename must be at least one character long" filename)) ((full-name-p filename)) (t ; if sf-dir nonempty and does not end with filename separator, ; append one (cond ((and (< 0 (length *default-sf-dir*)) (not (is-file-separator (char *default-sf-dir* (1- (length *default-sf-dir*)))))) (setf *default-sf-dir* (strcat *default-sf-dir* (string *file-separator*))) (format t "Warning: appending \"~A\" to *default-sf-dir*~%" *file-separator*))) (setf filename (strcat *default-sf-dir* (string filename))))) ;; now we have a file name, but it may be relative to current directory, so ;; expand it with the current directory (cond ((relative-path-p filename) ;; get current working directory and build full name (let ((path (setdir "."))) (cond (path (setf filename (strcat path (string *file-separator*) (string filename)))))))) filename) (setfn s-read-format car) (setfn s-read-channels cadr) (setfn s-read-mode caddr) (setfn s-read-bits cadddr) (defun s-read-swap (rslt) (car (cddddr rslt))) (defun s-read-srate (rslt) (cadr (cddddr rslt))) (defun s-read-dur (rslt) (caddr (cddddr rslt))) (defun s-read-byte-offset (rslt) (car (cddddr (cddddr rslt)))) ;; round is tricky because truncate rounds toward zero as does C ;; in other words, rounding is down for positive numbers and up ;; for negative numbers. You can convert rounding up to rounding ;; down by subtracting one, but this fails on the integers, so ;; we need a special test if (- x 0.5) is an integer (defun round (x) (cond ((> x 0) (truncate (+ x 0.5))) ((= (- x 0.5) (truncate (- x 0.5))) (truncate x)) (t (truncate (- x 0.5))))) ;; change defaults for PLAY macro: (init-global *soundenable* t) (defun sound-on () (setf *soundenable* t)) (defun sound-off () (setf *soundenable* nil)) (defun coterm (snd1 snd2) (multichan-expand #'snd-coterm snd1 snd2)) (defmacro s-add-to (expr maxlen filename &optional (time-offset 0.0)) `(let ((ny:fname (soundfilename ,filename)) ny:peak ny:input (ny:offset ,time-offset)) (format t "Adding sound to ~A at offset ~A~%" ny:fname ,time-offset) (setf ny:peak (snd-overwrite '(let ((ny:addend ,expr)) (sum (coterm (s-read ny:fname :time-offset ny:offset) ny:addend) ny:addend)) ,maxlen ny:fname ny:offset SND-HEAD-NONE 0 0 0)) (format t "Duration written: ~A~%" (car *rslt*)) ny:peak)) (defmacro s-overwrite (expr maxlen filename &optional (time-offset 0.0)) `(let ((ny:fname (soundfilename ,filename)) (ny:peak 0.0) ny:input ny:rslt ny:offset) (format t "Overwriting ~A at offset ~A~%" ny:fname ny:offset) (setf ny:offset (s-read-byte-offset ny:rslt)) (setf ny:peak (snd-overwrite `,expr ,maxlen ny:fname ,time-offset 0, 0, 0, 0.0, 0)) (format t "Duration written: ~A~%" (car *rslt*)) ny:peak)) nyquist-3.05/runtime/misc.lsp0000644000175000000620000001507511471652762015344 0ustar stevestaff;## misc.lsp -- a collection of useful support functions ;; Garbage collection "improvement" -- XLISP will GC without allocation ;; as long as it does not run out of cells. This can make it very slow ;; since GC does work proportional to the heap size. If there were ;; always at least, say, 1/3 of the heap free after GC, then allocating ;; cells would be more-or-less a constant time operation (amortized). ;; ;; So, after GC, we'll expand until we have 1/3 of the heap free. ;; (defun ny:gc-hook (heap-size free-cells) (cond ((< (* free-cells 2) heap-size) ;; free cells is < 1/3 heap ;; expand. Each expansion unit is 2000 cons cells (let* ((how-many-not-free (- heap-size free-cells)) (should-be-free (/ how-many-not-free 2)) (how-many-more (- should-be-free free-cells)) (expand-amount (/ how-many-more 2000))) (cond ((> expand-amount 0) (if *gc-flag* (format t "[ny:gc-hook allocating ~A more cells] " (* expand-amount 2000))) (expand expand-amount))))))) (setf *gc-hook* 'ny:gc-hook) ; set global if not already set ; (defmacro init-global (symb expr) `(if (boundp ',symb) ,symb (setf ,symb ,expr))) ; controlling breaks and tracebacks: ; XLISP and SAL behave differently, so there are four(!) flags: ; *sal-traceback* -- print SAL traceback on error in SAL mode ; Typically you want this on always. ; *sal-break* -- allow break (to XLISP prompt) on error when in SAL mode ; (overrides *sal-traceback*) Typically, you do not want ; this unless you need to see exactly where an error happened ; or the bug is in XLISP source code called from SAL. ; *xlisp-break* -- allow break on error when in XLISP mode ; Typically, you want this on. ; *xlisp-traceback* -- print XLISP traceback on error in XLISP mode ; Typically, you do not want this because the full ; stack can be long and tedious. (setf *sal-mode* nil) (setf *sal-traceback* t *sal-break* nil *xlisp-break* t *xlisp-traceback* nil) (defun sal-tracenable (flag) (setf *sal-traceback* flag)) (defun sal-breakenable (flag) (setf *sal-break* flag) (if *sal-mode* (setf *breakenable* flag))) (defun xlisp-breakenable (flag) (setf *xlisp-break* flag) (if (not *sal-mode*) (setf *breakenable* flag))) (defun xlisp-tracenable (flag) (setf *xlisp-traceback* flag) (if flag (setf *xlisp-break* t)) (cond ((not *sal-mode*) (if flag (setf *breakenable* t)) (setf *tracenable* flag)))) ; enable or disable breaks (defun bkon () (xlisp-breakenable t)) (defun bkoff () (xlisp-breakenable nil)) ;; (grindef 'name) - pretty print a function ;; (defun grindef (e) (pprint (get-lambda-expression (symbol-function e)))) ;; (args 'name) - print function and its formal arguments ;; (defun args (e) (pprint (cons e (second (get-lambda-expression (symbol-function e)))))) ;; (incf ), (decf ) - add/sub 1 to/from variable ;; (defmacro incf (symbol) `(setf ,symbol (1+ ,symbol))) (defmacro decf (symbol) `(setf ,symbol (1- ,symbol))) ;; (push val ) - cons val to list ;; (defmacro push (val lis) `(setf ,lis (cons ,val ,lis))) (defmacro pop (lis) `(prog1 (car ,lis) (setf ,lis (cdr ,lis)))) ;; include this to use RBD's XLISP profiling hooks ;;(load "/afs/andrew/usr/rbd/lib/xlisp/profile.lsp") ;(cond ((boundp 'application-file-name) ; (load application-file-name))) (defun get-input-file-name () (let (fname) (format t "Input file name: ") (setf fname (read-line)) (cond ((equal fname "") (get-input-file-name)) (t fname)))) (defun open-output-file () (let (fname) (format t "Output file name: ") (setf fname (read-line)) (cond ((equal fname "") t) (t (open fname :direction :output))))) (defmacro while (cond &rest stmts) `(prog () loop (if ,cond () (return)) ,@stmts (go loop))) ; when parens/quotes don't match, try this ; (defun file-sexprs () (let ((fin (open (get-input-file-name))) inp) (while (setf inp (read fin)) (print inp)))) ;; get path for currently loading file (if any) ;; (defun current-path () (let (fullpath n) (setf n -1) (cond (*loadingfiles* (setf fullpath (car *loadingfiles*)) (dotimes (i (length fullpath)) (cond ((equal (char fullpath i) *file-separator*) (setf n i)))) (setf fullpath (subseq fullpath 0 (1+ n))) ;; REMOVED SUPPORT FOR MAC OS-9 AND BELOW -RBD ;; if this is a Mac, use ':' in place of empty path ;; (cond ((and (equal fullpath "") ;; (equal *file-separator* #\:)) ;; (setf fullpath ":"))) ;; END MAC OS-9 CODE ;; Here's an interesting problem: fullpath is now the path ;; specified to LOAD, but it may be relative to the current ;; directory. What if we want to load a sound file from the ;; current directory? It seems that S-READ gives priority to ;; the *DEFAULT-SF-DIR*, so it will follow fullpath STARTING ;; FROM *DEFAULT-SF-DIR*. To fix this, we need to make sure ;; that fullpath is either an absolute path or starts with ;; and explicit ./ which tells s-read to look in the current ;; directory. (cond ((> (length fullpath) 0) (cond ((full-name-p fullpath)) (t ; not absolute, make it explicitly relative (setf fullpath (strcat "./" fullpath))))) (t (setf fullpath "./"))) ; use current directory fullpath) (t nil)))) ;; real-random -- pick a random real from a range ;; (defun real-random (from to) (+ (* (rrandom) (- to from)) from)) ;; power -- raise a number to some power x^y ;; (defun power (x y) (exp (* (log (float x)) y))) ;; require-from -- load a file if a function is undefined ;; ;; fn-symbol -- the function defined when the file is loaded ;; file-name -- the name of file to load if fn-symbol is undefined ;; path -- if t, load from current-path; if a string, prepend string ;; to file-name; if nil, ignore it ;; (defmacro require-from (fn-symbol file-name &optional path) (cond ((eq path t) (setf file-name `(strcat (current-path) ,file-name))) (path (setf file-name `(strcat ,path ,file-name)))) ; (display "require-from" file-name) `(if (fboundp (quote ,fn-symbol)) t ;; search for either .lsp or .sal file (sal-load ,file-name))) nyquist-3.05/runtime/sal.lsp0000644000175000000620000005242611530257127015161 0ustar stevestaff;;; ********************************************************************** ;;; Copyright (C) 2006 Rick Taube ;;; This program is free software; you can redistribute it and/or ;;; modify it under the terms of the Lisp Lesser Gnu Public License. ;;; See http://www.cliki.net/LLGPL for the text of this agreement. ;;; ********************************************************************** ;;; $Revision: 1.2 $ ;;; $Date: 2009-03-05 17:42:25 $ ;; DATA STRUCTURES AND ALGORITHMS (for sal.lsp and parse.lsp) ;; ;; TOKENIZE converts source language (a string) into a list of tokens ;; each token is represented as follows: ;; (:TOKEN ) ;; where is one of: ;; :id -- an identifier ;; :lp -- left paren ;; :rp -- right paren ;; :+, etc. -- operators ;; :int -- an integer ;; :float -- a float ;; :print, etc. -- a reserved word ;; is the source string for the token ;; is the column of the string ;; and are ?? ;; Tokenize uses a list of reserved words extracted from terminals in ;; the grammar. Each reserved word has an associated token type, but ;; all other identifiers are simply of type :ID. ;; ;; *** WHY REWRITE THE ORIGINAL PARSER? *** ;; Originally, the code interpreted a grammar using a recursive pattern ;; matcher, but XLISP does not have a huge stack and there were ;; stack overflow problems because even relatively small expressions ;; went through a very deep nesting of productions. E.g. ;; "print note(between(30,odds(.5, 60, 90)))" 0 t nil))" was at recursion ;; level 46 when the stack overflowed. The stack depth is 2000 or 4000, ;; but all locals and parameters get pushed here, so since PARSE is the ;; recursive function and it has lots of parameters and locals, it appears ;; to use 80 elements in the stack per call. ;; *** END *** ;; ;; The grammar for the recursive descent parser: ;; note: [ ] means optional , * means 0 or more of ;; ;; = | ;; = | | | ;; = { * } ;; = | | ;; = ;; = ? "(" , [ , ] ")" ;; = ;; = "(" [ ] ")" ;; = [ , ]* ;; = | ;; = + | - | "*" | / | % | ^ | = | != | ;; "<" | ">" | "<=" | ">=" | ~= | ! | & | "|" ;; = [ ]* ;; = <-> | | "(" ")" | ;; | | | | | ;; = | | class ;; = | | | | | ;; = exec ;; = | | ;; = define ;; = | ;; = variable ;; = [ , ]* ;; = [ <=> ] ;; = "(" [ ] ")" ;; = [ , ]* ;; this is new: key: expression for keyword parameter ;; = | [ ] ;; = | | | ;; | ;; = begin [ with [ ]* end ;; = if then [ ] [ else ] | ;; when | unless ;; = set [ , ]* ;; = ( | ) ;; = = | += | *= | &= | @= | ^= | "<=" | ">=" ;; = | chdir | ;; system | play ;; (note: system was removed) ;; = load [ , ]* ;; = | ;; = print [ , ]* | ;; output ;; = loop [ with ] [ ]* ;; [ ]* [ ]+ ;; [ finally ] end ;; = repeat | ;; for = [ then ] | ;; for in | ;; for over [ by ] | ;; for [ from ] ;; [ ( below | to | above | downto ) ] ;; [ by ] | ;; = while | until ;; = return ;(in-package cm) ; (progn (cd "/Lisp/sal/") (load "parse.lisp") (load "sal.lisp")) (setfn defconstant setf) (setfn defparameter setf) (setfn defmethod defun) (setfn defvar setf) (setfn values list) (if (not (boundp '*sal-secondary-prompt*)) (setf *sal-secondary-prompt* t)) (if (not (boundp '*sal-xlispbreak*)) (setf *sal-xlispbreak* nil)) (defun sal-trace-enter (fn &optional argvals argnames) (push (list fn *sal-line* argvals argnames) *sal-call-stack*)) (defun sal-trace-exit () (setf *sal-line* (second (car *sal-call-stack*))) (pop *sal-call-stack*)) ;; SAL-RETURN-FROM is generated by Sal compiler and ;; performs a return as well as a sal-trace-exit() ;; (defmacro sal-return-from (fn val) `(prog ((sal:return-value ,val)) (setf *sal-line* (second (car *sal-call-stack*))) (pop *sal-call-stack*) (return-from ,fn sal:return-value))) (setf *sal-traceback* t) (defun sal-traceback (&optional (file t) &aux comma name names line) (format file "Call traceback:~%") (setf line *sal-line*) (dolist (frame *sal-call-stack*) (setf comma "") (format file " ~A" (car frame)) (cond ((symbolp (car frame)) (format file "(") (setf names (cadddr frame)) (dolist (arg (caddr frame)) (setf name (car names)) (format file "~A~% ~A = ~A" comma name arg) (setf names (cdr names)) (setf comma ",")) (format file ") at line ~A~%" line) (setf line (second frame))) (t (format file "~%"))))) '(defmacro defgrammer (sym rules &rest args) `(defparameter ,sym (make-grammer :rules ',rules ,@args))) '(defun make-grammer (&key rules literals) (let ((g (list 'a-grammer rules literals))) (grammer-initialize g) g)) '(defmethod grammer-initialize (obj) (let (xlist) ;; each literal is (:name "name") (cond ((grammer-literals obj) (dolist (x (grammer-literals obj)) (cond ((consp x) (push x xlist)) (t (push (list (string->keyword (string-upcase (string x))) (string-downcase (string x))) xlist))))) (t (dolist (x (grammer-rules obj)) (cond ((terminal-rule? x) (push (list (car x) (string-downcase (subseq (string (car x)) 1))) xlist)))))) (set-grammer-literals obj (reverse xlist)))) '(setfn grammer-rules cadr) '(setfn grammer-literals caddr) '(defun set-grammer-literals (obj val) (setf (car (cddr obj)) val)) '(defun is-grammer (obj) (and (consp obj) (eq (car obj) 'a-grammer))) (defun string->keyword (str) (intern (strcat ":" (string-upcase str)))) (defun terminal-rule? (rule) (or (null (cdr rule)) (not (cadr rule)))) (load "sal-parse.lsp" :verbose nil) (defparameter *sal-print-list* t) (defun sal-printer (x &key (stream *standard-output*) (add-space t) (in-list nil)) (let ((*print-case* ':downcase)) (cond ((and (consp x) *sal-print-list*) (write-char #\{ stream) (do ((items x (cdr items))) ((null items)) (sal-printer (car items) :stream stream :add-space (cdr items) :in-list t) (cond ((cdr items) (cond ((not (consp (cdr items))) (princ " " stream) (sal-printer (cdr items) :stream stream :add-space nil) (setf items nil)))))) (write-char #\} stream)) ((not x) (princ "#f" stream) ) ((eq x t) (princ "#t" stream)) (in-list (prin1 x stream)) (t (princ x stream))) (if add-space (write-char #\space stream)))) (defparameter *sal-printer* #'sal-printer) (defun sal-message (string &rest args) (format t "~&; ") (apply #'format t string args)) ;; sal-print has been modified from the original SAL to print items separated ;; by spaces (no final trailing space) and followed by a newline. (defun sal-print (&rest args) (do ((items args (cdr items))) ((null items)) ;; add space unless we are at the last element (funcall *sal-printer* (car items) :add-space (cdr items))) (terpri) (values)) (defmacro keyword (sym) `(str-to-keyword (symbol-name ',sym))) (defun plus (&rest nums) (apply #'+ nums)) (defun minus (num &rest nums) (apply #'- num nums)) (defun times (&rest nums) (apply #'* nums)) (defun divide (num &rest nums) (apply #'/ num nums)) ;; implementation of infix "!=" operator (defun not-eql (x y) (not (eql x y))) ; dir "*.* ; chdir ; load "rts.sys" (defun sal-chdir ( dir) (cd (expand-path-name dir)) (sal-message "Directory: ~A" (pwd)) (values)) ;;; sigh, not all lisps support ~/ directory components. (defun expand-path-name (path &optional absolute?) (let ((dir (pathname-directory path))) (flet ((curdir () (truename (make-pathname :directory (pathname-directory *default-pathname-defaults*))))) (cond ((null dir) (if (equal path "~") (namestring (user-homedir-pathname)) (if absolute? (namestring (merge-pathnames path (curdir))) (namestring path)))) ((eql (car dir) ':absolute) (namestring path)) (t (let* ((tok (second dir)) (len (length tok))) (if (char= (char tok 0) #\~) (let ((uhd (pathname-directory (user-homedir-pathname)))) (if (= len 1) (namestring (make-pathname :directory (append uhd (cddr dir)) :defaults path)) (namestring (make-pathname :directory (append (butlast uhd) (list (subseq tok 1)) (cddr dir)) :defaults path)))) (if absolute? (namestring (merge-pathnames path (curdir))) (namestring path))))))))) (defun sal-load (filename &key (verbose t) print) (progv '(*sal-input-file-name*) (list filename) (prog (file extended-name) ;; first try to load exact name (cond ((setf file (open filename)) (close file) ;; found it: close it and load it (return (generic-loader filename verbose print)))) ;; try to load name with ".sal" or ".lsp" (cond ((string-search "." filename) ; already has extension nil) ; don't try to add another extension ((setf file (open (strcat filename ".sal"))) (close file) (return (sal-loader (strcat filename ".sal") :verbose verbose :print print))) ((setf file (open (strcat filename ".lsp"))) (close file) (return (lisp-loader filename :verbose verbose :print print)))) ;; search for file as is or with ".lsp" on path (setf fullpath (find-in-xlisp-path filename)) (cond ((and (not fullpath) ; search for file.sal on path (not (string-search "." filename))) ; no extension yet (setf fullpath (find-in-xlisp-path (strcat filename ".sal"))))) (cond ((null fullpath) (format t "sal-load: could not find ~A~%" filename)) (t (return (generic-loader filename verbose print))))))) ;; GENERIC-LOADER -- load a sal or lsp file based on extension ;; ;; assumes that file exists, and if no .sal extension, type is Lisp ;; (defun generic-loader (fullpath verbose print) (cond ((has-extension fullpath ".sal") (sal-loader fullpath :verbose verbose :print print)) (t (lisp-loader fullpath :verbose verbose :print print)))) #| (defun sal-load (filename &key (verbose t) print) (progv '(*sal-input-file-name*) (list filename) (let (file extended-name) (cond ((has-extension filename ".sal") (sal-loader filename :verbose verbose :print print)) ((has-extension filename ".lsp") (lisp-load filename :verbose verbose :print print)) ;; see if we can just open the exact filename and load it ((setf file (open filename)) (close file) (lisp-load filename :verbose verbose :print print)) ;; if not, then try loading file.sal and file.lsp ((setf file (open (setf *sal-input-file-name* (strcat filename ".sal")))) (close file) (sal-loader *sal-input-file-name* :verbose verbose :print print)) ((setf file (open (setf *sal-input-file-name* (strcat filename ".lsp")))) (close file) (lisp-load *sal-input-file-name* :verbose verbose :print print)) (t (format t "sal-load: could not find ~A~%" filename)))))) |# (defun lisp-loader (filename &key (verbose t) print) (if (load filename :verbose verbose :print print) nil ; be quiet if things work ok (format t "error loading lisp file ~A~%" filename))) (defun has-extension (filename ext) (let ((loc (string-search ext filename :start (max 0 (- (length filename) (length ext)))))) (not (null loc)))) ; coerce to t or nil (defmacro sal-at (s x) (list 'at x s)) (defmacro sal-at-abs (s x) (list 'at-abs x s)) (defmacro sal-stretch (s x) (list 'stretch x s)) (defmacro sal-stretch-abs (s x) (list 'stretch-abs x s)) ;; splice every pair of lines (defun strcat-pairs (lines) (let (rslt) (while lines (push (strcat (car lines) (cadr lines)) rslt) (setf lines (cddr lines))) (reverse rslt))) (defun strcat-list (lines) ;; like (apply 'strcat lines), but does not use a lot of stack ;; When there are too many lines, XLISP will overflow the stack ;; because args go on the stack. (let (r) (while (> (setf len (length lines)) 1) (if (oddp len) (setf lines (cons "" lines))) (setf lines (strcat-pairs lines))) ; if an empty list, return "", else list has one string: return it (if (null lines) "" (car lines)))) (defun sal-loader (filename &key verbose print) (let ((input "") (file (open filename)) line lines) (cond (file (push filename *loadingfiles*) (while (setf line (read-line file)) (push line lines) (push "\n" lines)) (close file) (setf input (strcat-list (reverse lines))) (sal-trace-enter (strcat "Loading " filename)) (sal-compile input t t filename) (pop *loadingfiles*) (sal-trace-exit)) (t (format t "error loading SAL file ~A~%" filename))))) ; SYSTEM command is not implemented ;(defun sal-system (sys &rest pairs) ; (apply #'use-system sys pairs)) (defun load-sal-file (file) (with-open-file (f file :direction :input) (let ((input (make-array '(512) :element-type 'character :fill-pointer 0 :adjustable t))) (loop with flag for char = (read-char f nil ':eof) until (or flag (eql char ':eof)) do (when (char= char #\;) (loop do (setq char (read-char f nil :eof)) until (or (eql char :eof) (char= char #\newline)))) (unless (eql char ':eof) (vector-push-extend char input))) (sal input :pattern :command-sequence)))) (defmacro sal-play (snd) (if (stringp snd) `(play-file ,snd) `(play ,snd))) (if (not (boundp '*sal-compiler-debug*)) (setf *sal-compiler-debug* nil)) (defmacro sal-simrep (variable iterations body) `(simrep (,variable ,iterations) ,body)) (defmacro sal-seqrep (variable iterations body) `(seqrep (,variable ,iterations) ,body)) ;; function called in sal programs to exit the sal read-compile-run-print loop (defun sal-exit () (setf *sal-exit* t)) (setf *sal-call-stack* nil) ;; read-eval-print loop for sal commands (defun sal () (progv '(*breakenable* *tracenable* *sal-exit* *sal-mode*) (list *sal-break* nil nil t) (let (input line) (setf *sal-call-stack* nil) (read-line) ; read the newline after the one the user ; typed to invoke this fn (princ "Entering SAL mode ...\n"); (while (not *sal-exit*) (princ "\nSAL> ") (sal-trace-enter "SAL top-level command interpreter") ;; get input terminated by two returns (setf input "") (while (> (length (setf line (read-line))) 0) (if *sal-secondary-prompt* (princ " ... ")) (setf input (strcat input "\n" line))) ;; input may have an extra return, remaining from previous read ;; if so, trim it because it affects line count in error messages (if (and (> (length input) 0) (char= (char input 0) #\newline)) (setf input (subseq input 1))) (sal-compile input t nil "") (sal-trace-exit)) (princ "Returning to Lisp ...\n"))) ;; in case *xlisp-break* or *xlisp-traceback* was set from SAL, impose ;; them here (cond ((not *sal-mode*) (setf *breakenable* *xlisp-break*) (setf *tracenable* *xlisp-traceback*))) t) (defun sal-error-output (stack) (if *sal-traceback* (sal-traceback)) (setf *sal-call-stack* stack)) ;; clear the stack ;; when true, top-level return statement is legal and compiled into MAIN (setf *audacity-top-level-return-flag* nil) ;; SAL-COMPILE-AUDACITY -- special treatment of RETURN ;; ;; This works like SAL-COMPILE, but if there is a top-level ;; return statement (not normally legal), it is compiled into ;; a function named MAIN. This is a shorthand for Audacity plug-ins ;; (defun sal-compile-audacity (input eval-flag multiple-statements filename) (progv '(*audacity-top-level-return-flag*) '(t) (sal-compile input eval-flag multiple-statements filename))) ;; SAL-COMPILE -- translate string or token list to lisp and eval ;; ;; input is either a string or a token list ;; eval-flag tells whether to evaluate the program or return the lisp ;; multiple-statements tells whether the input can contain multiple ;; top-level units (e.g. from a file) or just one (from command line) ;; returns: ;; if eval-flag, then nothing is returned ;; otherwise, returns nil if an error is encountered ;; otherwise, returns a list (PROGN p1 p2 p3 ...) where pn are lisp ;; expressions ;; (defun sal-compile (input eval-flag multiple-statements filename) ;; save some globals because eval could call back recursively (progv '(*sal-tokens* *sal-input* *sal-input-text*) '(nil nil nil) (let (output remainder rslt stack) (setf stack *sal-call-stack*) ;; if first input char is "(", then eval as a lisp expression: ;(display "sal-compile" input)(setf *sal-compiler-debug* t) (cond ((input-starts-with-open-paren input) ;(print "input is lisp expression") (errset (print (eval (read (make-string-input-stream input)))) t)) (t ;; compile SAL expression(s): (loop (setf output (sal-parse nil nil input multiple-statements filename)) (cond ((first output) ; successful parse (setf remainder *sal-tokens*) (setf output (second output)) (when *sal-compiler-debug* (terpri) (pprint output)) (cond (eval-flag ;; evaluate the compiled code (cond ((null (errset (eval output) t)) (sal-error-output stack) (return)))) ;; stop on error (t (push output rslt))) ;(display "sal-compile after eval" ; remainder *sal-tokens*) ;; if there are statements left over, maybe compile again (cond ((and multiple-statements remainder) ;; move remainder to input and iterate (setf input remainder)) ;; see if we've compiled everything ((and (not eval-flag) (not remainder)) (return (cons 'progn (reverse rslt)))) ;; if eval but no more input, return ((not remainder) (return)))) (t ; error encountered (return))))))))) ;; SAL just evaluates lisp expression if it starts with open-paren, ;; but sometimes reader reads previous newline(s), so here we ;; trim off initial newlines and check if first non-newline is open-paren (defun input-starts-with-open-paren (input) (let ((i 0)) (while (and (stringp input) (> (length input) i) (eq (char input i) #\newline)) (incf i)) (and (stringp input) (> (length input) i) (eq (char input i) #\()))) nyquist-3.05/runtime/stk.lsp0000644000175000000620000001525311466723256015211 0ustar stevestaff;; stk.lsp -- STK-based instruments ;; ;; currently clarinet and saxophony are implemented (defun instr-parameter (parm) ;; coerce parameter into a *sound-srate* signal (cond ((numberp parm) (stretch 30 (control-srate-abs *sound-srate* (const (float parm))))) (t (force-srate *sound-srate* parm)))) (defun clarinet (step breath-env) (snd-clarinet (step-to-hz step) (force-srate *sound-srate* breath-env) *sound-srate*)) (defun clarinet-freq (step breath-env freq-env) ;; note that the parameters are in a different order -- I defined ;; clarinet-freq this way so that the first two parameters are always ;; step and breath. I didn't redo snd-clarinet-freq. (snd-clarinet_freq (step-to-hz step) (instr-parameter breath-env) (instr-parameter freq-env) *sound-srate*)) (defun clarinet-all (step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise) ;; note that the parameters are not in the same order as snd-clarinet-all (setf breath-env (instr-parameter breath-env)) (setf freq-env (instr-parameter freq-env)) (setf reed-stiffness (instr-parameter reed-stiffness)) (setf noise (instr-parameter noise)) (snd-clarinet_all (step-to-hz step) breath-env freq-env ;; STK scales 1.0 to 12Hz. Scale here so vibrato-freq is in Hz (/ vibrato-freq 12.0) vibrato-gain reed-stiffness noise *sound-srate*)) (defun sax (step breath-env) (snd-sax (step-to-hz step) (force-srate *sound-srate* breath-env) *sound-srate*)) (defun sax-freq (step breath-env freq-env) (snd-sax_freq (step-to-hz step) (instr-parameter breath-env) (instr-parameter freq-env) *sound-srate*)) (defun sax-all (step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise blow-pos reed-table-offset) (snd-sax_all (step-to-hz step) (instr-parameter freq-env) (instr-parameter breath-env) (instr-parameter (/ vibrato-freq 12.0)) (instr-parameter vibrato-gain) (instr-parameter reed-stiffness) (instr-parameter noise) (instr-parameter blow-pos) (instr-parameter reed-table-offset) *sound-srate*) ) ; instr-parameter already defined in stk.lsp (defun flute (step breath-env) (snd-flute (step-to-hz step) (force-srate *sound-srate* breath-env) *sound-srate*)) (defun flute-freq (step breath-env freq-env) (snd-flute_freq (step-to-hz step) (instr-parameter breath-env) (instr-parameter freq-env) *sound-srate*)) (defun flute-all (step breath-env freq-env vibrato-freq vibrato-gain jet-delay noise) ;; note that the parameters are not in the same order as snd-clarinet-all (setf breath-env (instr-parameter breath-env)) (setf freq-env (instr-parameter freq-env)) (setf jet-delay (instr-parameter jet-delay)) (setf noise (instr-parameter noise)) (snd-flute_all (step-to-hz step) breath-env freq-env ;; STK scales 1.0 to 12Hz. Scale here so vibrato-freq is in Hz (/ vibrato-freq 12.0) vibrato-gain jet-delay noise *sound-srate*)) (defun bowed (step bowpress-env) (snd-bowed (step-to-hz step) (force-srate *sound-srate* bowpress-env) *sound-srate*)) (defun bowed-freq (step bowpress-env freq-env) (snd-bowed_freq (step-to-hz step) (instr-parameter bowpress-env) (instr-parameter freq-env) *sound-srate*)) (defun mandolin (step dur &optional (detune 4.0)) (let ((d (get-duration dur))) (snd-mandolin *rslt* (step-to-hz step) d 1.0 detune *sound-srate*))) (defun wg-uniform-bar (step bowpress-env) (snd-bandedwg (step-to-hz step) (force-srate *sound-srate* bowpress-env) 0 *sound-srate*)) (defun wg-tuned-bar (step bowpress-env) (snd-bandedwg (step-to-hz step) (force-srate *sound-srate* bowpress-env) 1 *sound-srate*)) (defun wg-glass-harm (step bowpress-env) (snd-bandedwg (step-to-hz step) (force-srate *sound-srate* bowpress-env) 2 *sound-srate*)) (defun wg-tibetan-bowl (step bowpress-env) (snd-bandedwg (step-to-hz step) (force-srate *sound-srate* bowpress-env) 3 *sound-srate*)) (defun modalbar (preset step duration) (let ((preset (case preset (MARIMBA 0) (VIBRAPHONE 1) (AGOGO 2) (WOOD1 3) (RESO 4) (WOOD2 5) (BEATS 6) (TWO-FIXED 7) (CLUMP 8) (t (error (format nil "Unknown preset for modalbar %A" preset))))) (d (get-duration duration))) (snd-modalbar *rslt* (step-to-hz step) preset d *sound-srate*))) (defun sitar (step dur) (let ((d (get-duration dur))) (snd-sitar *rslt* (step-to-hz step) d *sound-srate*))) (defun nyq:nrev (snd rev-time mix) (snd-stkrev 0 snd rev-time mix *sound-srate*)) (defun nyq:jcrev (snd rev-time mix) (snd-stkrev 1 snd rev-time mix *sound-srate*)) (defun nyq:prcrev (snd rev-time mix) (snd-stkrev 2 snd rev-time mix *sound-srate*)) (defun nrev (snd rev-time mix) (multichan-expand #'nyq:nrev snd rev-time mix)) (defun jcrev (snd rev-time mix) (multichan-expand #'nyq:jcrev snd rev-time mix)) (defun prcrev (snd rev-time mix) (multichan-expand #'nyq:prcrev snd rev-time mix)) (defun nyq:chorus (snd depth freq mix &optional (base-delay 6000)) (snd-stkchorus snd base-delay depth freq mix *sound-srate*)) (defun stkchorus (snd depth freq mix &optional (base-delay 6000)) (multichan-expand #'nyq:chorus snd depth freq mix base-delay)) (defun nyq:pitshift (snd shift mix) (snd-stkpitshift snd shift mix *sound-srate*)) (defun pitshift (snd shift mix) (multichan-expand #'nyq:pitshift snd shift mix)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; HELPER FUNCTIONS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; pass in rates of increase/decrease in begin/end... this is like noteOn and noteOff ; ; STK uses setRate but the actual ramp time is also a function of the sample rate. ; I will assume the clarinet was run at 44100Hz and fix things so that the envelope ; is sample-rate independent. ; ; STK seemed to always give a very fast release, so I changed the numbers so that ; note-off values from 0.01 to 1 give an interesting range of articulations. ; ; IMPORTANT: the returned envelope is 0.1s longer than dur. There is 0.1s of silence ; at the end so that the clarinet can "ring" after the driving force is removed. ; (defun stk-breath-env (dur note-on note-off) (let* ((target (+ 0.55 (* 0.3 note-on))) (on-time (/ (* target 0.0045) note-on)) (off-time (/ (* target 0.02) note-off))) ;(display "clarinet-breath-env" target on-time off-time) (pwl on-time target (- dur off-time) target dur 0 (+ dur 0.1)))) nyquist-3.05/runtime/nyquist.lsp0000644000175000000620000015455411466723256016134 0ustar stevestaff;;; ;;; ########################################################### ;;; ### NYQUIST-- A Language for Composition and Synthesis. ### ;;; ### ### ;;; ### Copyright (c) 1994-2006 by Roger B. Dannenberg ### ;;; ########################################################### ;;; (load "fileio.lsp" :verbose NIL) (prog () (setq lppp -12.0) (setq lpp -9.0) (setq lp -6.0) (setq lmp -3.0) (setq lfff 12.0) (setq lff 9.0) (setq lf 6.0) (setq lmf 3.0) (setq dB0 1.00) (setq dB1 1.122) (setq dB10 3.1623) (setq s 0.25) (setq sd 0.375) (setq st (/ 0.5 3.0)) (setq i 0.5) (setq id 0.75) (setq it (* st 2.0)) (setq q 1.0) (setq qd 1.5) (setq qt (* st 4.0)) (setq h 2.0) (setq hd 3.0) (setq ht (* st 8.0)) (setq w 4.0) (setq wd 6.0) (setq wt (* st 16.0)) ) (init-global *A4-Hertz* 440.0) ; next pitch, for initializations below ; (defun np () (incf nyq:next-pitch)) (defun set-pitch-names () (setq no-pitch 116.0) ; note: 58.0 is A4 - (C0 - 1) = 69 - (12 - 1) (setf nyq:next-pitch (- (hz-to-step *A4-Hertz*) 58.0)) (setf nyq:pitch-names '(c0 (cs0 df0) d0 (ds0 ef0) e0 f0 (fs0 gf0) g0 (gs0 af0) a0 (as0 bf0) b0 c1 (cs1 df1) d1 (ds1 ef1) e1 f1 (fs1 gf1) g1 (gs1 af1) a1 (as1 bf1) b1 c2 (cs2 df2) d2 (ds2 ef2) e2 f2 (fs2 gf2) g2 (gs2 af2) a2 (as2 bf2) b2 c3 (cs3 df3) d3 (ds3 ef3) e3 f3 (fs3 gf3) g3 (gs3 af3) a3 (as3 bf3) b3 c4 (cs4 df4) d4 (ds4 ef4) e4 f4 (fs4 gf4) g4 (gs4 af4) a4 (as4 bf4) b4 c5 (cs5 df5) d5 (ds5 ef5) e5 f5 (fs5 gf5) g5 (gs5 af5) a5 (as5 bf5) b5 c6 (cs6 df6) d6 (ds6 ef6) e6 f6 (fs6 gf6) g6 (gs6 af6) a6 (as6 bf6) b6 c7 (cs7 df7) d7 (ds7 ef7) e7 f7 (fs7 gf7) g7 (gs7 af7) a7 (as7 bf7) b7)) (dolist (p nyq:pitch-names) (cond ((atom p) (set p (np))) (t (let ((pitch (np))) (dolist (s p) (set s pitch))))))) (set-pitch-names) (init-global *default-sound-srate* 44100.0) (init-global *default-control-srate* 2205.0) (setf *environment-variables* '(*WARP* *SUSTAIN* *START* *LOUD* *TRANSPOSE* *STOP* *CONTROL-SRATE* *SOUND-SRATE*)) (setfn environment-time car) (setfn environment-stretch cadr) ; ENVIRONMENT-MAP - map virtual time using an environment ; ;(defun environment-map (env tim) ; (+ (environment-time env) ; (* (environment-stretch env) tim))) (defun nyq:the-environment () (mapcar 'eval *environment-variables*)) ;; GLOBAL ENVIRONMENT VARIABLES and their startup values: (defun nyq:environment-init () (setq *WARP* '(0.0 1.0 nil)) (setq *LOUD* 0.0) ; now in dB (setq *TRANSPOSE* 0.0) (setq *SUSTAIN* 1.0) (setq *START* MIN-START-TIME) (setq *STOP* MAX-STOP-TIME) (setq *CONTROL-SRATE* *DEFAULT-CONTROL-SRATE*) (setq *SOUND-SRATE* *DEFAULT-SOUND-SRATE*) t) ; return nothing in particular (nyq:environment-init) (defun get-duration (dur) (let ((duration (- (local-to-global (* (get-sustain) dur)) (setf *rslt* (local-to-global 0))))) (cond ((minusp duration) (error "duration is less than zero: perhaps a warp or stretch is ill-formed. Nyquist cannot continue because synthesis functions assume durations are always positive."))) duration)) (defun get-loud () (cond ((numberp *loud*) *loud*) ((soundp *loud*) (sref *loud* 0)) (t (error (format t "*LOUD* should be a number or sound: ~A" *LOUD*))))) (defun get-sustain () (cond ((numberp *SUSTAIN*) *SUSTAIN*) ((soundp *SUSTAIN*) ;(display "get-sustain: lookup " (local-to-global 0) 0)) (sref *SUSTAIN* 0)) (t (error (format t "*SUSTAIN* should be a number or sound: ~A" *SUSTAIN*))))) (defun get-tempo () (slope (snd-inverse (get-warp) (local-to-global 0) *control-srate*))) (defun get-transpose () (cond ((numberp *TRANSPOSE*) *TRANSPOSE*) ((soundp *TRANSPOSE*) ; (display "get-transpose: lookup " 0) ; (format t "samples: ~A~%" (snd-samples *TRANSPOSE* 100)) (sref *TRANSPOSE* 0)) (t (error (format t "*TRANSPOSE* should be a number or sound: ~A" *TRANSPOSE*))))) (defun get-warp () (let ((f (warp-function *WARP*))) (cond ((null f) (error "Null warp function")) (t (shift-time (scale-srate f (/ (warp-stretch *WARP*))) (- (warp-time *WARP*))))))) ;;;;;;;;;;;;;;;;;;;;;; ;; OSCILATORS ;;;;;;;;;;;;;;;;;;;;;; (defun build-harmonic (n table-size) (snd-sine 0 n table-size 1)) (setf *SINE-TABLE* (list (build-harmonic 1 2048) (hz-to-step 1.0) T)) (setf *TABLE* *SINE-TABLE*) ;; AMOSC ;; (defun amosc (pitch modulation &optional (sound *table*) (phase 0.0)) (let ((modulation-srate (snd-srate modulation)) (hz (step-to-hz (+ pitch (get-transpose))))) (cond ((> *SOUND-SRATE* modulation-srate) (setf modulation (snd-up *SOUND-SRATE* modulation))) ((< *SOUND-SRATE* modulation-srate) (format t "Warning: down-sampling AM modulation in amosc~%") (setf modulation (snd-down *SOUND-SRATE* modulation)))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: amosc frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (scale-db (get-loud) (snd-amosc (car sound) ; samples for table (cadr sound) ; step represented by table *SOUND-SRATE* ; output sample rate hz ; output hz (local-to-global 0) ; starting time modulation ; modulation phase)))) ; phase ;; FMOSC ;; ;; modulation rate must be less than or equal to sound-srate, so ;; force resampling and issue a warning if necessary. snd-fmosc can ;; handle upsampling cases internally. ;; (defun fmosc (pitch modulation &optional (sound *table*) (phase 0.0)) (let ((modulation-srate (snd-srate modulation)) (hz (step-to-hz (+ pitch (get-transpose))))) (cond ((< *SOUND-SRATE* modulation-srate) (format t "Warning: down-sampling FM modulation in fmosc~%") (setf modulation (snd-down *SOUND-SRATE* modulation)))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: fmosc nominal frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (scale-db (get-loud) (snd-fmosc (car sound) ; samples for table (cadr sound) ; step represented by table *SOUND-SRATE* ; output sample rate hz ; output hz (local-to-global 0) ; starting time modulation ; modulation phase)))) ; phase ;; FMFB ;; ;; this code is based on FMOSC above ;; (defun fmfb (pitch index &optional dur) (let ((hz (step-to-hz (+ pitch (get-transpose))))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format "Warning: fmfb nominal frequency (~A hz) will alias at current sample rate (~A hz).~%" hz *SOUND-SRATE*))) (setf dur (get-duration dur)) (cond ((soundp index) (ny:fmfbv hz index)) (t (scale-db (get-loud) (snd-fmfb (local-to-global 0) hz *SOUND-SRATE* index dur)))))) ;; private variable index version of fmfb (defun ny:fmfbv (hz index) (let ((modulation-srate (snd-srate index))) (cond ((< *SOUND-SRATE* modulation-srate) (format t "Warning: down-sampling FM modulation in fmfb~%") (setf index (snd-down *SOUND-SRATE* index)))) (scale-db (get-loud) (snd-fmfbv (local-to-global 0) hz *SOUND-SRATE* index)))) ;; BUZZ ;; ;; (ARGUMENTS ("long" "n") ("rate_type" "sr") ("double" "hz") ;; ("time_type" "t0") ("sound_type" "s_fm")) ;; (defun buzz (n pitch modulation) (let ((modulation-srate (snd-srate modulation)) (hz (step-to-hz (+ pitch (get-transpose))))) (cond ((< *SOUND-SRATE* modulation-srate) (format t "Warning: down-sampling modulation in buzz~%") (setf modulation (snd-down *SOUND-SRATE* modulation)))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: buzz nominal frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (setf n (max n 1)) ; avoid divide by zero problem (scale-db (get-loud) (snd-buzz n ; number of harmonics *SOUND-SRATE* ; output sample rate hz ; output hz (local-to-global 0) ; starting time modulation)))) ; freq. modulation ;; (HZOSC hz [table [phase]]) ;; ;; similar to FMOSC, but without "carrier" frequency parameter ;; also, hz may be a scalar or a sound ;; (defun hzosc (hz &optional (sound *table*) (phase 0.0)) (let (hz-srate) (cond ((numberp hz) (osc (hz-to-step hz) 1.0 sound phase)) (t (setf hz-srate (snd-srate hz)) (cond ((< *SOUND-SRATE* hz-srate) (format t "Warning: down-sampling hz in hzosc~%") (setf hz (snd-down *SOUND-SRATE* hz)))) (scale-db (get-loud) (snd-fmosc (car sound) ; samples for table (cadr sound) ; step repr. by table *SOUND-SRATE* ; output sample rate 0.0 ; dummy carrier (local-to-global 0) ; starting time hz phase)))))) ;; (SIOSC-BREAKPOINTS tab0 t1 tab1 ... tn tabn) ;; converts times to sample numbers ;; NOTE: time-warping the spectral envelope seems ;; like the wrong thing to do (wouldn't it be better ;; to warp the parameters that control the spectra, ;; or don't warp at all?). Nominally, a note should ;; have a "score" or local time duration equal to the ;; SUSTAIN environment variable. (When sustain is 1.0 ;; and no time-warping is in effect, the duration is 1). ;; So, scale all times by ;; (local-to-global (get-sustain)) ;; so that if the final time tn = 1.0, we get a nominal ;; length note. (defun siosc-breakpoints (breakpoints) (display "siosc-breakpoints" breakpoints) (prog (sample-count result (last-count 0) time-factor) (setf time-factor (- (local-to-global (get-sustain)) (local-to-global 0.0))) (setf time-factor (* time-factor *SOUND-SRATE*)) (cond ((and (listp breakpoints) (cdr breakpoints) (cddr breakpoints))) (t (error "SIOSC table list must have at least 3 elements"))) loop (cond ((and (listp breakpoints) (soundp (car breakpoints))) (push (car breakpoints) result) (setf breakpoints (cdr breakpoints))) (t (error "SIOSC expecting SOUND in table list"))) (cond ((and breakpoints (listp breakpoints) (numberp (car breakpoints))) (setf sample-count (truncate (+ 0.5 (* time-factor (car breakpoints))))) (cond ((< sample-count last-count) (setf sample-count (1+ last-count)))) (push sample-count result) (setf last-count sample-count) (setf breakpoints (cdr breakpoints)) (cond (breakpoints (go loop)))) (breakpoints (error "SIOSC expecting number (time) in table list"))) (setf result (reverse result)) (display "siosc-breakpoints" result) (return result))) ;; SIOSC -- spectral interpolation oscillator ;; ;; modulation rate must be less than or equal to sound-srate, so ;; force resampling and issue a warning if necessary. snd-fmosc can ;; handle upsampling cases internally. ;; (defun siosc (pitch modulation breakpoints) (let ((modulation-srate (snd-srate modulation)) (hz (step-to-hz (+ pitch (get-transpose))))) (cond ((< *SOUND-SRATE* modulation-srate) (format t "Warning: down-sampling FM modulation in siosc~%") (setf modulation (snd-down *SOUND-SRATE* modulation)))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: siosc nominal frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (scale-db (get-loud) (snd-siosc (siosc-breakpoints breakpoints) ; tables *SOUND-SRATE* ; output sample rate hz ; output hz (local-to-global 0) ; starting time modulation)))) ; modulation ;; LFO -- freq &optional duration sound phase) ;; ;; Default duration is 1.0 sec, default sound is *TABLE*, ;; default phase is 0.0. ;; (defun lfo (freq &optional (duration 1.0) (sound *SINE-TABLE*) (phase 0.0)) (let ((d (get-duration duration))) (if (minusp d) (setf d 0)) (cond ((> freq (/ *CONTROL-SRATE* 2)) (format t "Warning: lfo frequency (~A hz) will alias at current control rate (~A hz).\n" freq *CONTROL-SRATE*))) (set-logical-stop (snd-osc (car sound) ; samples for table (cadr sound) ; step represented by table *CONTROL-SRATE* ; output sample rate freq ; output hz *rslt* ; starting time d ; duration phase) ; phase duration))) ;; FMLFO -- like LFO but uses frequency modulation ;; (defun fmlfo (freq &optional (sound *SINE-TABLE*) (phase 0.0)) (let () (cond ((numberp freq) (lfo freq 1.0 sound phase)) ((soundp freq) (cond ((> (snd-srate freq) *CONTROL-SRATE*) (setf freq (force-srate *CONTROL-SRATE* freq)))) (snd-fmosc (car sound) (cadr sound) *CONTROL-SRATE* 0.0 (local-to-global 0) freq phase)) (t (error "frequency must be a number or sound"))))) ;; OSC - table lookup oscillator ;; (defun osc (pitch &optional (duration 1.0) (sound *TABLE*) (phase 0.0)) (let ((d (get-duration duration)) (hz (step-to-hz (+ pitch (get-transpose))))) ;(display "osc" *warp* global-start global-stop actual-dur ; (get-transpose)) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: osc frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (set-logical-stop (scale-db (get-loud) (snd-osc (car sound) ; samples for table (cadr sound) ; step represented by table *SOUND-SRATE* ; output sample rate hz ; output hz *rslt* ; starting time d ; duration phase)) ; phase duration))) ;; PARTIAL -- sine osc with built-in envelope scaling ;; (defun partial (steps env) (let ((hz (step-to-hz (+ steps (get-transpose))))) (cond ((> hz (/ *sound-srate* 2)) (format t "Warning: partial frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *sound-srate*))) (scale-db (get-loud) (snd-partial *sound-srate* hz (force-srate *sound-srate* env))))) ;; SAMPLER -- simple attack + sustain sampler ;; (defun sampler (pitch modulation &optional (sample *table*) (npoints 2)) (let ((samp (car sample)) (samp-pitch (cadr sample)) (samp-loop-start (caddr sample)) (hz (step-to-hz (+ pitch (get-transpose))))) ; make a waveform table look like a sample with no attack: (cond ((not (numberp samp-loop-start)) (setf samp-loop-start 0.0))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: sampler nominal frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (scale-db (get-loud) (snd-sampler samp ; samples for table samp-pitch ; step represented by table samp-loop-start ; time to start loop *SOUND-SRATE* ; output sample rate hz ; output hz (local-to-global 0) ; starting time modulation ; modulation npoints)))) ; number of interpolation points ;; SINE -- simple sine oscillator ;; (defun sine (steps &optional (duration 1.0)) (let ((hz (step-to-hz (+ steps (get-transpose)))) (d (get-duration duration))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: sine frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (set-logical-stop (scale-db (get-loud) (snd-sine *rslt* hz *sound-srate* d)) duration))) ;; PLUCK ;; ;; (ARGUMENTS ("double" "sr") ("double" "hz") ("time_type" "t0") ;; ("time_type" "d") ("double" "final_amp")) ;; (defun pluck (steps &optional (duration 1.0) (final-amp 0.001)) (let ((hz (step-to-hz (+ steps (get-transpose)))) (d (get-duration duration))) (cond ((> hz (/ *SOUND-SRATE* 2)) (format t "Warning: pluck frequency (~A hz) will alias at current sample rate (~A hz).\n" hz *SOUND-SRATE*))) (set-logical-stop (scale-db (get-loud) (snd-pluck *SOUND-SRATE* hz *rslt* d final-amp)) duration))) ;; abs-env -- restore the standard environment ;; (defmacro abs-env (s) `(progv '(*WARP* *LOUD* *TRANSPOSE* *SUSTAIN* *START* *STOP* *CONTROL-SRATE* *SOUND-SRATE*) (list '(0.0 1.0 NIL) 0.0 0.0 1.0 MIN-START-TIME MAX-STOP-TIME *DEFAULT-CONTROL-SRATE* *DEFAULT-SOUND-SRATE*) ,s)) ; nyq:add2 - add two arguments ; (defun nyq:add2 (s1 s2) (cond ((and (arrayp s1) (not (arrayp s2))) (setf s2 (vector s2))) ((and (arrayp s2) (not (arrayp s1))) (setf s1 (vector s1)))) (cond ((arrayp s1) (sum-of-arrays s1 s2)) (t (nyq:add-2-sounds s1 s2)))) ; (NYQ:ADD-2-SOUNDS S1 S2) - add two sound (or number) arguments ; (defun nyq:add-2-sounds (s1 s2) (cond ((numberp s1) (cond ((numberp s2) (+ s1 s2)) (t (snd-offset s2 s1)))) ((numberp s2) (snd-offset s1 s2)) (t (let ((s1sr (snd-srate s1)) (s2sr (snd-srate s2))) ; (display "nyq:add-2-sounds" s1sr s2sr) (cond ((> s1sr s2sr) (snd-add s1 (snd-up s1sr s2))) ((< s1sr s2sr) (snd-add (snd-up s2sr s1) s2)) (t (snd-add s1 s2))))))) (defmacro at (x s) `(progv '(*WARP*) (list (list (+ (warp-time *WARP*) (* (warp-stretch *WARP*) ,x)) (warp-stretch *WARP*) (warp-function *WARP*))) ,s)) ;; (AT-ABS t behavior) evaluate behavior at global time t ;; ;; *WARP* is the triple (d s f) denoting the function f(st+d), ;; a mapping from local to global time. ;; We want (d' s f) such that f(s*0 + d') = t ;; (Note that we keep the same s and f, and only change the offset. ;; To eliminate the warp and stretch use "(abs-env (at t behavior))") ;; Applying the inverse of f, d' = f-1(t), or (sref (snd-inverse f ...) t) ;; Rather than invert the entire function just to evaluate at one point, ;; we use SREF-INVERSE to find d'. ;; (defmacro at-abs (x s) `(progv '(*WARP*) (if (warp-function *WARP*) (list (list (sref-inverse (warp-function *WARP*) ,x) (warp-stretch *WARP*) (warp-function *WARP*))) (list (list ,x (warp-stretch *WARP*) NIL))) ;; issue warning if sound starts in the past (check-t0 ,s ',s))) (defun check-t0 (s src) (let (flag t0 (now (local-to-global 0))) (cond ((arrayp s) (dotimes (i (length s)) (setf t0 (snd-t0 (aref s i)))) (if (< t0 now) (setf flag t0))) (t (setf t0 (snd-t0 s)) (if (< t0 now) (setf flag t0)))) (if flag (format t "Warning: cannot go back in time to ~A, sound came from ~A~%" flag src)) ; (display "check-t0" t0 now src) ; return s whether or not warning was reported s)) ;; (CLIP S1 VALUE) - clip maximum amplitude to value ; (defun clip (x v) (cond ((numberp x) (max (min x v) (- v))) ((arrayp x) (let* ((len (length x)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (snd-clip (aref x i) v))) result)) (t (snd-clip x v)))) ;; (NYQ:COERCE-TO S1 S2) - expand sound s1 to type of s2 ; (defun nyq:coerce-to (s1 s2) (cond ((or (soundp s1) (numberp s1)) (cond ((arrayp s2) (nyq:sound-to-array s1 (length s2))) (t s1))) (t s1))) (defmacro continuous-control-warp (beh) `(snd-compose (warp-abs nil ,beh) (snd-inverse (get-warp) (local-to-global 0) *control-srate*))) (defmacro continuous-sound-warp (beh) `(snd-compose (warp-abs nil ,beh) (snd-inverse (get-warp) (local-to-global 0) *sound-srate*))) (defmacro control-srate-abs (r s) `(progv '(*CONTROL-SRATE*) (list ,r) ,s)) ; db = 20log(ratio) ; db = 20 ln(ratio)/ln(10) ; db/20 = ln(ratio)/ln(10) ; db ln(10)/20 = ln(ratio) ; e^(db ln(10)/20) = ratio ; (setf ln10over20 (/ (log 10.0) 20)) (defun db-to-linear (x) (cond ((numberp x) (exp (* ln10over20 x))) ((arrayp x) (let* ((len (length x)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (snd-exp (snd-scale ln10over20 (aref x i))))) result)) (t (snd-exp (snd-scale ln10over20 x))))) (defun linear-to-db (x) (cond ((numberp x) (/ (log (float x)) ln10over20)) ((arrayp x) (let* ((len (length x)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (snd-scale (/ 1.0 ln10over20) (snd-log (aref x i))))) result)) (t (snd-scale (/ 1.0 ln10over20) (snd-log x))))) (cond ((not (fboundp 'scalar-step-to-hz)) (setfn scalar-step-to-hz step-to-hz) (setfn scalar-hz-to-step hz-to-step))) (defun step-to-hz (x) (cond ((numberp x) (scalar-step-to-hz x)) ((arrayp x) (let* ((len (length x)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (step-to-hz (aref x i)))) result)) (t (s-exp (snd-offset (snd-scale 0.0577622650466621 x) 2.1011784386926213))))) (defun hz-to-step (x) (cond ((numberp x) (scalar-hz-to-step x)) ((arrayp x) (let* ((len (length x)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (hz-to-step (aref x i)))) result)) (t (snd-scale 17.312340490667565 (snd-offset (s-log x) -2.1011784386926213))))) ; sref - access a sound at a given time point ; note that the time is transformed to global (defun sref (sound point) (snd-sref sound (local-to-global point))) ; extract - start is stretched and shifted as is stop ; result is shifted to start at local time zero (defun extract (start stop sound) (snd-xform sound (snd-srate sound) (local-to-global 0) (local-to-global start) (local-to-global stop) 1.0)) (defun extract-abs (start stop sound) (snd-xform sound (snd-srate sound) 0 start stop 1.0)) (defun local-to-global (local-time) (let ((d (warp-time *WARP*)) (s (warp-stretch *WARP*)) (w (warp-function *WARP*)) global-time) (setf global-time (+ (* s local-time) d)) (if w (snd-sref w global-time) global-time))) (defmacro loud (x s) `(progv '(*LOUD*) (list (sum *LOUD* ,x)) ,s)) (defmacro loud-abs (x s) `(progv '(*LOUD*) (list ,x) ,s)) (defun must-be-sound (x) (cond ((soundp x) x) (t (error "SOUND type expected" x)))) ;; SCALE-DB -- same as scale, but argument is in db ;; (defun scale-db (factor sound) (scale (db-to-linear factor) sound)) (defun set-control-srate (rate) (setf *default-control-srate* (float rate)) (nyq:environment-init)) (defun set-sound-srate (rate) (setf *default-sound-srate* (float rate)) (nyq:environment-init)) ; s-plot -- compute and write n data points for plotting ; ; dur is how many seconds of sound to plot. If necessary, cut the ; sample rate to allow plotting dur seconds ; n is the number of points to plot. If there are more than n points, ; cut the sample rate. If there are fewer than n samples, just ; plot the points that exist. ; (defun s-plot (snd &optional (dur 2.0) (n 1000)) (prog* ((sr (snd-srate snd)) (t0 (snd-t0 snd)) (filename (soundfilename *default-plot-file*)) (s snd) ;; s is either snd or resampled copy of snd (outf (open filename :direction :output)) ;; for plot data (maximum -1000000.0) ;; maximum amplitude (minimum 1000000.0) ;; minimum amplitude actual-dur ;; is the actual-duration of snd sample-count ;; is how many samples to get from s period ;; is the period of samples to be plotted truncation-flag ;; true if we didn't get whole sound points) ;; is array of samples ;; If we need more than n samples to get dur seconds, resample (cond ((< n (* dur sr)) (setf s (force-srate (/ (float n) dur) snd)))) ;; Get samples from the signal (setf points (snd-samples s (1+ n))) ;; If we got fewer than n points, we can at least estimate the ;; actual duration (we might not know exactly if we use a lowered ;; sample rate). If the actual sample rate was lowered to avoid ;; getting more than n samples, we can now raise the sample rate ;; based on our estimate of the actual sample duration. (display "test" (length points) n) (cond ((< (length points) n) ;; sound is shorter than dur, estimate actual length (setf actual-dur (/ (length points) (snd-srate s))) (setf sample-count (round (min n (* actual-dur sr)))) (cond ((< n (* actual-dur sr)) (setf s (force-srate (/ (float n) actual-dur) snd))) (t ;; we can use original signal (setf s snd))) (setf points (snd-samples s sample-count)) ;; due to rounding, need to recalculate exact count (setf sample-count (length points))) ((= (length points) n) (setf actual-dur dur) (setf sample-count n)) (t ;; greater than n points, so we must have truncated sound (setf actual-dur dur) (setf sample-count n) (setf truncation-flag t))) ;; actual-dur is the duration of the plot ;; sample-count is how many samples we have (setf period (/ 1.0 (snd-srate s))) (cond ((null outf) (format t "s-plot: could not open ~A!~%" filename) (return nil))) (format t "s-plot: writing ~A ... ~%" filename) (cond (truncation-flag (format t " !!TRUNCATING SOUND TO ~As\n" actual-dur))) (cond ((/= (snd-srate s) (snd-srate snd)) (format t " !!RESAMPLING SOUND FROM ~A to ~Ahz\n" (snd-srate snd) (snd-srate s)))) (cond (truncation-flag (format t " Plotting ~As, actual sound duration is greater\n" actual-dur)) (t (format t " Sound duration is ~As~%" actual-dur))) (dotimes (i sample-count) (setf maximum (max maximum (aref points i))) (setf minimum (min minimum (aref points i))) (format outf "~A ~A~%" (+ t0 (* i period)) (aref points i))) (close outf) (format t " Wrote ~A points from ~As to ~As~%" sample-count t0 (+ t0 actual-dur)) (format t " Range of values ~A to ~A\n" minimum maximum) (cond ((or (< minimum -1) (> maximum 1)) (format t " !!SIGNAL EXCEEDS +/-1~%"))))) ; run something like this to plot the points: ; graph < points.dat | plot -Ttek (defmacro sound-srate-abs (r s) `(progv '(*SOUND-SRATE*) (list ,r) ,s)) (defmacro stretch (x s) `(progv '(*WARP*) (list (list (warp-time *WARP*) (* (warp-stretch *WARP*) ,x) (warp-function *WARP*))) (if (minusp (warp-stretch *WARP*)) (break "Negative stretch factor is not allowed")) ,s)) (defmacro stretch-abs (x s) `(progv '(*WARP*) (list (list (local-to-global 0) ,x nil)) (if (minusp (warp-stretch *WARP*)) (break "Negative stretch factor is not allowed")) ,s)) (defmacro sustain (x s) `(progv '(*SUSTAIN*) (list (prod *SUSTAIN* ,x)) ,s)) (defmacro sustain-abs (x s) `(progv '(*SUSTAIN*) (list ,x) ,s)) ;; (WARP-FUNCTION *WARP*) - extracts function field of warp triple ;; (setfn warp-function caddr) ;; (WARP-STRETCH *WARP*) - extracts stretch field of warp triple ;; (setfn warp-stretch cadr) ;; (WARP-TIME *WARP*) - extracts time field of warp triple ;; (setfn warp-time car) (defmacro transpose (x s) `(progv '(*TRANSPOSE*) (list (sum *TRANSPOSE* ,x)) ,s)) (defmacro transpose-abs (x s) `(progv '(*TRANSPOSE*) (list ,x) ,s)) ;; COMPUTE-DEFAULT-SOUND-FILE -- construct and set *default-sound-file* ;; ;; (this is harder than it might seem because the default place for ;; sound files is in /tmp, which is shared by users, so we'd like to ;; use a user-specific name to avoid collisions) ;; (defun compute-default-sound-file () (let (inf user extension) ; the reason for the user name is that if UserA creates a temp file, ; then UserB will not be able to overwrite it. The user name is a ; way to give each user a unique temp file name. Note that we don't ; want each session to generate a unique name because Nyquist doesn't ; delete the sound file at the end of the session. (setf user (get-user)) #| (cond ((null user) (format t "Please type your user-id so that I can construct a default sound-file name. To avoid this message in the future, add this to your .login file: setenv USER or add this to your init.lsp file: (setf *default-sound-file* \"\") (setf *default-sf-dir* \"\") Your id please: ") (setf user (read)))) |# ; now compute the extension based on *default-sf-format* (cond ((= *default-sf-format* snd-head-AIFF) (setf extension ".aif")) ((= *default-sf-format* snd-head-Wave) (setf extension ".wav")) (t (setf extension ".snd"))) (setf *default-sound-file* (strcat (string-downcase user) "-temp" extension)) (format t "Default sound file is ~A.~%" *default-sound-file*))) ;; CONTROL-WARP -- apply a warp function to a control function ;; (defun control-warp (warp-fn control &optional wrate) (cond (wrate (snd-resamplev control *control-srate* (snd-inverse warp-fn (local-to-global 0) wrate))) (t (snd-compose control (snd-inverse warp-fn (local-to-global 0) *control-srate*))))) ;; (cue sound) ;; Cues the given sound; that is, it applies the current *WARP*, *LOUD*, ;; *START*, and *STOP* values to the argument. The logical start time is at ;; local time 0. (defun cue (sound) (cond ((arrayp sound) (let* ((len (length sound)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (cue-sound (aref sound i)))) result)) (t (cue-sound sound)))) (defun cue-sound (sound) (snd-xform sound (snd-srate sound) (local-to-global 0) *START* *STOP* (db-to-linear (get-loud)))) ;; (sound sound) ;; Same as (cue sound), except also warps the sound. ;; Note that the *WARP* can change the pitch of the ;; sound as a result of resampling. ;; Here's the derivation for the warping code: ;; *WARP* is a triple: (d s f) which denotes that the warp from local to ;; global time is: f(st+d) ;; We need to compose sound with the inverse of this to get a function ;; of global time ;; Let f-1 be the inverse of f. Then the inverse of f(st+d) is ;; (f-1(t) - d)/s ;; The composition gives us: (snd-compose sound (f-1(t) - d)/s) ;; Eliminate the 1/s term by changing the sample rate of sound: ;; = (snd-compose (snd-scale-srate sound s) (f-1(t) - d)) ;; Eliminate the -d term by shifting f before taking the inverse: ;; = (snd-compose (scale-srate sound s) ((inverse f) - d)) ;; = (snd-compose (scale-srate sound s) (inverse f(t + d))) ;; = (snd-compose (scale-srate sound s) (inverse (shift f -d))) ;; snd-inverse takes a time and sample rate. For time, use zero. ;; The sample rate of inverse determines the final sample rate of ;; this function, so use *SOUND-SRATE*: ;; = (snd-compose (scale-srate sound s) (snd-inverse (shift-time f (- d)) ;; 0 *SOUND-SRATE*)) ;; (defun nyq:sound (sound) (cond ((null (warp-function *WARP*)) (snd-xform sound (/ (snd-srate sound) (warp-stretch *WARP*)) (local-to-global 0) *START* *STOP* (db-to-linear (get-loud)))) (t (snd-compose (scale-srate sound (warp-stretch *WARP*)) (snd-inverse (shift-time (warp-function *WARP*) (- (warp-time *WARP*))) 0 *SOUND-SRATE*))))) (defun nyq:sound-of-array (sound) (let* ((n (length sound)) (s (make-array n))) (dotimes (i n) (setf (aref s i) (nyq:sound (aref sound i)))) s)) (defun sound (sound) (cond ((arrayp sound) (nyq:sound-of-array sound)) (t (nyq:sound sound)))) ;; (SCALE-SRATE SOUND SCALE) ;; multiplies the sample rate by scale (defun scale-srate (sound scale) (let ((new-srate (* scale (snd-srate sound)))) (snd-xform sound new-srate (snd-time sound) MIN-START-TIME MAX-STOP-TIME 1.0))) ;; (SHIFT-TIME SOUND SHIFT) ;; shift the time of a function by SHIFT, i.e. if SOUND is f(t), ;; then (shift-time SOUND SHIFT) is f(t - SHIFT). Note that if ;; you look at plots, the shifted sound will move *right* when SHIFT ;; is positive. (defun shift-time (sound shift) (snd-xform sound (snd-srate sound) (+ (snd-t0 sound) shift) MIN-START-TIME MAX-STOP-TIME 1.0)) ;; (NYQ:SOUND-TO-ARRAY SOUND N) - duplicate SOUND to N channels ;; (defun nyq:sound-to-array (sound n) (let ((result (make-array n))) (dotimes (i n) (setf (aref result i) sound)) result)) ;; (control sound) ;; Same as (sound sound), except this is used for control signals. ;; This code is identical to sound. (setfn control sound) ;; (cue-file string) ;; Loads a sound file with the given name, returning a sound which is ;; transformed to the current environment. (defun cue-file (name) (cue (force-srate *SOUND-SRATE* (s-read name)))) ;; (env t1 t2 t4 l1 l2 l3 &optional duration) ;; Creates a 4-phase envelope. ;; tN is the duration of phase N, and lN is the final level of ;; phase N. t3 is implied by the duration, and l4 is 0.0. ;; If dur is not supplied, then 1.0 is assumed. The envelope ;; duration is the product of dur, *STRETCH*, and *SUSTAIN*. If ;; t1 + t2 + 2ms + t4 > duration, then a two-phase envelope is ;; substituted that has an attack/release time ratio = t1/t4. ;; The sample rate of the returned sound is *CONTROL-SRATE*. ;; ;; Time transformation: the envelope is not warped; the start time and ;; stop times are warped to global time. Then the value of *SUSTAIN* at ;; the begining of the envelope is used to determing absolute duration. ;; Since PWL is ultimately called to create the envelope, we must use ;; ABS-ENV to prevent any further transforms inside PWL. We use ;; (AT global-start ...) inside ABS-ENV so that the final result has ;; the proper starting time. ;; (defun env (t1 t2 t4 l1 l2 l3 &optional (duration 1.0)) (let (actual-dur min-dur ratio t3 (actual-dur (get-duration duration))) (setf min-dur (+ t1 t2 t4 0.002)) (cond ((< actual-dur min-dur) (setf ratio (/ t1 (float (+ t1 t4)))) (setf t1 (* ratio actual-dur)) (setf t2 (- actual-dur t1)) (setf t3 0.0) (setf t4 0.0) (setf l2 0.0) (setf l3 0.0)) (t (setf t3 (- actual-dur t1 t2 t4)))) (set-logical-stop (abs-env (at *rslt* (pwl t1 l1 (+ t1 t2) l2 (- actual-dur t4) l3 actual-dur))) duration))) (defun gate (sound lookahead risetime falltime floor threshold) (cond ((< lookahead risetime) (break "lookahead must be greater than risetime in GATE function")) ((or (< risetime 0) (< falltime 0) (< floor 0)) (break "risetime, falltime, and floor must all be positive in GATE function")) (t (let ((s (snd-gate (seq (cue sound) (abs-env (s-rest lookahead))) lookahead risetime falltime floor threshold))) (snd-xform s (snd-srate s) (snd-t0 sound) (+ (snd-t0 sound) lookahead) MAX-STOP-TIME 1.0))))) ;; (osc-note step &optional duration env sust volume sound) ;; Creates a note using table-lookup osc, but with an envelope. ;; The ENV parameter may be a parameter list for the env function, ;; or it may be a sound. ;; (defun osc-note (pitch &optional (duration 1.0) (env-spec '(0.02 0.1 0.3 1.0 .8 .7)) (volume 0.0) (table *TABLE*)) (set-logical-stop (mult (loud volume (osc pitch duration table)) (if (listp env-spec) (apply 'env env-spec) env-spec)) duration)) ;; force-srate -- resample snd if necessary to get sample rate ; (defun force-srate (sr snd) (cond ((not (numberp sr)) (error "force-srate: SR should be a number"))) (cond ((arrayp snd) (let* ((len (length snd)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (force-srate sr (aref snd i)))) result)) (t (let ((snd-sr (snd-srate snd))) (cond ((> sr snd-sr) (snd-up sr snd)) ((< sr snd-sr) (snd-down sr snd)) (t snd)))))) (defun force-srates (srs snd) (cond ((and (numberp srs) (soundp snd)) (force-srate srs snd)) ((and (arrayp srs) (arrayp snd)) (let* ((len (length snd)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (force-srate (aref srs i) (aref snd i)))) result)) (t (error "arguments not compatible")))) ;; (breakpoints-convert (t1 x1 t2 x2 ... tn) t0) ;; converts times to sample numbers and scales amplitudes ;; t0 is the global (after warping) start time ;; ;; NOTE: there were some stack overflow problems with the original ;; recursive version (in comments now), so it was rewritten as an ;; iteration. ;; (defun breakpoints-convert (list t0) (prog (sample-count result sust (last-count 0)) (setf sust (get-sustain)) loop (setf sample-count (truncate (+ 0.5 (* (- (local-to-global (* (car list) sust)) t0) *control-srate*)))) ; now we have a new sample count to put into result list ; make sure result is non-decreasing (cond ((< sample-count last-count) (setf sample-count last-count))) (setf last-count sample-count) (push sample-count result) (cond ((cdr list) (setf list (cdr list)) (push (float (car list)) result))) (setf list (cdr list)) (cond (list (go loop))) (return (reverse result)))) ;; (pwl t1 l1 t2 l2 ... tn) ;; Creates a piece-wise linear envelope from breakpoint data. ;; (defun pwl (&rest breakpoints) (pwl-list breakpoints)) (defun pwlr (&rest breakpoints) (pwlr-list breakpoints)) ;; (breakpoints-relative list) ;; converts list, which has the form (value dur value dur value ...) ;; into the form (value time value time value ...) ;; the list may have an even or odd length ;; (defun breakpoints-relative (breakpoints) (prog (result (sum 0.0)) loop (cond (breakpoints (push (car breakpoints) result) (setf breakpoints (cdr breakpoints)) (cond (breakpoints (setf sum (+ sum (car breakpoints))) (push sum result) (setf breakpoints (cdr breakpoints)) (go loop))))) (return (reverse result)))) (defun breakpoints-relative (breakpoints) (prog (result (sum 0.0)) loop (setf sum (+ sum (car breakpoints))) (push sum result) (cond ((cdr breakpoints) (setf breakpoints (cdr breakpoints)) (push (car breakpoints) result))) (setf breakpoints (cdr breakpoints)) (cond (breakpoints (go loop))) (return (reverse result)))) (defun pwlr-list (breakpoints) (pwl-list (breakpoints-relative breakpoints))) (defun pwl-list (breakpoints) (let ((t0 (local-to-global 0))) (snd-pwl t0 *control-srate* (breakpoints-convert breakpoints t0)))) ;; (pwlv l1 t1 l2 t2 ... ln) ;; Creates a piece-wise linear envelope from breakpoint data; ;; the function initial and final values are explicit ;; (defun pwlv (&rest breakpoints) ;use pwl, modify breakpoints with initial and final changes ;need to put initial time of 0, and final time of 0 (pwlv-list breakpoints)) (defun pwlv-list (breakpoints) (pwl-list (cons 0.0 (append breakpoints '(0.0))))) (defun pwlvr (&rest breakpoints) (pwlvr-list breakpoints)) (defun pwlvr-list (breakpoints) (pwlr-list (cons 0.0 (append breakpoints '(0.0))))) (defun pwe (&rest breakpoints) (pwe-list breakpoints)) (defun pwe-list (breakpoints) (pwev-list (cons 1.0 (append breakpoints '(1.0))))) (defun pwer (&rest breakpoints) (pwer-list breakpoints)) (defun pwer-list (breakpoints) (pwe-list (breakpoints-relative breakpoints))) (defun pwev (&rest breakpoints) (pwev-list breakpoints)) (defun pwev-list (breakpoints) (let ((lis (breakpoints-log breakpoints))) (s-exp (pwl-list lis)))) (defun pwevr (&rest breakpoints) (pwevr-list breakpoints)) (defun pwevr-list (breakpoints) (pwev-list (cdr (breakpoints-relative (cons 0.0 breakpoints))))) (defun breakpoints-log (breakpoints) (prog ((result '(0.0)) val tim) loop (cond (breakpoints (setf val (float (car breakpoints))) (setf breakpoints (cdr breakpoints)) (cond (breakpoints (setf tim (car breakpoints)) (setf breakpoints (cdr breakpoints)))) (setf result (cons tim (cons (log val) result))) (cond ((null breakpoints) (return (reverse result)))) (go loop)) (t (error "Expected odd number of elements in breakpoint list"))))) ;; SOUND-WARP -- apply warp function to a sound ;; (defun sound-warp (warp-fn signal &optional wrate) (cond (wrate (snd-resamplev signal *sound-srate* (snd-inverse warp-fn (local-to-global 0) wrate))) (t (snd-compose signal (snd-inverse warp-fn (local-to-global 0) *sound-srate*))))) (defun snd-extent (sound maxsamples) (list (snd-t0 sound) (+ (snd-t0 sound) (/ (snd-length sound maxsamples) (snd-srate sound))))) (setfn snd-flatten snd-length) ;; (maketable sound) ;; Creates a table for osc, lfo, etc. by assuming that the samples ;; in sound represent one period. The sound must start at time 0. (defun maketable (sound) (list sound (hz-to-step (/ 1.0 (cadr (snd-extent sound 1000000)))) T)) ;(defmacro endTime (sound) ; `(get-logical-stop ,sound)) ;(defmacro beginTime (sound) ; `(car (snd-extent ,sound))) ; simple stereo pan: as where goes from 0 to 1, sound ; is linearly panned from left to right ; (defun pan (sound where) (vector (mult sound (sum 1 (mult -1 where))) (mult sound where))) (defun prod (&rest snds) (cond ((null snds) (snd-zero (local-to-global 0) *sound-srate*)) ((null (cdr snds)) (car snds)) ((null (cddr snds)) (nyq:prod2 (car snds) (cadr snds))) (t (nyq:prod2 (car snds) (apply #'prod (cdr snds)))))) (setfn mult prod) ;; (NYQ:PROD-OF-ARRAYS S1 S2) - form pairwise products ; (defun nyq:prod-of-arrays (s1 s2) (let* ((n (length s1)) (p (make-array n))) (cond ((/= n (length s2)) (error "unequal number of channels in prod"))) (dotimes (i n) (setf (aref p i) (nyq:prod2 (aref s1 i) (aref s2 i)))) p)) ; nyq:prod2 - multiply two arguments ; (defun nyq:prod2 (s1 s2) (setf s1 (nyq:coerce-to s1 s2)) (setf s2 (nyq:coerce-to s2 s1)) (cond ((arrayp s1) (nyq:prod-of-arrays s1 s2)) (t (nyq:prod-2-sounds s1 s2)))) ; (PROD-2-SOUNDS S1 S2) - multiply two sound arguments ; (defun nyq:prod-2-sounds (s1 s2) (cond ((numberp s1) (cond ((numberp s2) (* s1 s2)) (t (scale s1 s2)))) ((numberp s2) (scale s2 s1)) (t (let ((s1sr (snd-srate s1)) (s2sr (snd-srate s2))) ; (display "nyq:prod-2-sounds" s1sr s2sr) (cond ((> s1sr s2sr) (snd-prod s1 (snd-up s1sr s2))) ((< s1sr s2sr) (snd-prod (snd-up s2sr s1) s2)) (t (snd-prod s1 s2))))))) ;; RAMP -- linear ramp from 0 to x ;; (defun ramp (&optional (x 1)) (let* ((duration (get-duration x))) (set-logical-stop (warp-abs nil (at *rslt* (sustain-abs 1 (pwl duration 1 (+ duration (/ *control-srate*)))))) x))) (defun resample (snd rate) (cond ((arrayp snd) (let* ((len (length snd)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (snd-resample (aref snd i) rate))) result)) (t (snd-resample snd rate)))) (defun scale (amt snd) (cond ((arrayp snd) (let* ((len (length snd)) (result (make-array len))) (dotimes (i len) (setf (aref result i) (snd-scale amt (aref snd i)))) result)) (t (snd-scale amt snd)))) (setfn s-print-tree snd-print-tree) ;; (PEAK sound-expression number-of-samples) - find peak amplitude ; ; NOTE: this used to be called s-max ; (defmacro peak (expression maxlen) `(snd-max ',expression ,maxlen)) ;; (S-MAX S1 S2) - return maximum of S1, S2 ; (defun s-max (s1 s2) (setf s1 (nyq:coerce-to s1 s2)) (setf s2 (nyq:coerce-to s2 s1)) (cond ((arrayp s1) (nyq:max-of-arrays s1 s2)) (t (nyq:max-2-sounds s1 s2)))) (defun nyq:max-of-arrays (s1 s2) (let* ((n (length s1)) (p (make-array n))) (cond ((/= n (length s2)) (error "unequal number of channels in max"))) (dotimes (i n) (setf (aref p i) (s-max (aref s1 i) (aref s2 i)))) p)) (defun nyq:max-2-sounds (s1 s2) (cond ((numberp s1) (cond ((numberp s2) (max s1 s2)) (t (snd-maxv s2 (snd-const s1 (local-to-global 0.0) (snd-srate s2) (get-duration 1.0)))))) ((numberp s2) (snd-maxv s1 (snd-const s2 (local-to-global 0.0) (snd-srate s1) (get-duration 1.0)))) (t (let ((s1sr (snd-srate s1)) (s2sr (snd-srate s2))) (cond ((> s1sr s2sr) (snd-maxv s1 (snd-up s1sr s2))) ((< s1sr s2sr) (snd-maxv (snd-up s2sr s1) s2)) (t (snd-maxv s1 s2))))))) (defun s-min (s1 s2) (setf s1 (nyq:coerce-to s1 s2)) (setf s2 (nyq:coerce-to s2 s1)) (cond ((arrayp s1) (nyq:min-of-arrays s1 s2)) (t (nyq:min-2-sounds s1 s2)))) (defun nyq:min-of-arrays (s1 s2) (let* ((n (length s1)) (p (make-array n))) (cond ((/= n (length s2)) (error "unequal number of channels in max"))) (dotimes (i n) (setf (aref p i) (s-min (aref s1 i) (aref s2 i)))) p)) (defun nyq:min-2-sounds (s1 s2) (cond ((numberp s1) (cond ((numberp s2) (min s1 s2)) (t (snd-minv s2 (snd-const s1 (local-to-global 0.0) (snd-srate s2) (get-duration 1.0)))))) ((numberp s2) (snd-minv s1 (snd-const s2 (local-to-global 0.0) (snd-srate s1) (get-duration 1.0)))) (t (let ((s1sr (snd-srate s1)) (s2sr (snd-srate s2))) (cond ((> s1sr s2sr) (snd-minv s1 (snd-up s1sr s2))) ((< s1sr s2sr) (snd-minv (snd-up s2sr s1) s2)) (t (snd-minv s1 s2))))))) (defun snd-minv (s1 s2) (scale -1.0 (snd-maxv (scale -1.0 s1) (scale -1.0 s2)))) ; sequence macros SEQ and SEQREP are now in seq.lsp: ; (load "seq" :verbose NIL) ; set-logical-stop - modify the sound and return it, time is shifted and ; stretched (defun set-logical-stop (snd tim) (let ((d (local-to-global tim))) (multichan-expand #'set-logical-stop-abs snd d))) ; set-logical-stop-abs - modify the sound and return it ; (defun set-logical-stop-abs (snd tim) (snd-set-logical-stop snd tim) snd) (defmacro simrep (pair sound) `(let (_snds) (dotimes ,pair (push ,sound _snds)) (sim-list _snds))) (defun sim (&rest snds) (sim-list snds)) (setfn sum sim) (defun sim-list (snds) (cond ((null snds) (snd-zero (local-to-global 0) *sound-srate*)) ((null (cdr snds)) (car snds)) ((null (cddr snds)) (nyq:add2 (car snds) (cadr snds))) (t (nyq:add2 (car snds) (sim-list (cdr snds)))))) (defun s-rest (&optional (dur 1.0) (chans 1)) (let ((d (get-duration dur)) r) (cond ((= chans 1) (snd-const 0.0 *rslt* *SOUND-SRATE* d)) (t (setf r (make-array chans)) (dotimes (i chans) (setf (aref r i) (snd-const 0.0 *rslt* *SOUND-SRATE* d))) r)))) (defun tempo (warpfn) (slope (snd-inverse warpfn (local-to-global 0) *control-srate*))) ;; (SUM-OF-ARRAYS S1 S2) - add multichannel sounds ; ; result has as many channels the largest of s1, s2 ; corresponding channels are added, extras are copied ; (defun sum-of-arrays (s1 s2) (let* ((n1 (length s1)) (n2 (length s2)) (n (min n1 n2)) (m (max n1 n2)) (result (make-array m)) (big-s (if (> n1 n2) s1 s2))) (dotimes (i n) (setf (aref result i) (nyq:add-2-sounds (aref s1 i) (aref s2 i)))) (dotimes (i (- m n)) (setf (aref result (+ n i)) (aref big-s (+ n i)))) result)) ;; (WARP fn behavior) - warp behavior according to fn ;; ;; fn is a map from behavior time to local time, and *WARP* expresses ;; a map from local to global time. ;; To produce a new *WARP* for the environment, we want to compose the ;; effect of the current *WARP* with fn. Note that fn is also a behavior. ;; It is evaluated in the current environment first, then it is used to ;; modify the environment seen by behavior. ;; *WARP* is a triple: (d s f) denoting the function f(st+d). ;; Letting g represent the new warp function fn, we want f(st+d) o g, or ;; f(s*g(t) + d) in the form (d' s' f'). ;; Let's do this one step at a time: ;; f(s*g(t) + d) = f(scale(s, g) + d) ;; = (shift f -d)(scale(s, g)) ;; = (snd-compose (shift-time f (- d)) (scale s g)) ;; ;; If f in NIL, it denotes the identity mapping f(t)=t, so we can ;; simplify: ;; f(scale(s, g) + d) = scale(s, g) + d ;; = (snd-offset (scale s g) d) (defmacro warp (x s) `(progv '(*WARP*) (list (list 0.0 1.0 (if (warp-function *WARP*) (snd-compose (shift-time (warp-function *WARP*) (- (warp-time *WARP*))) (scale (warp-stretch *WARP*) (must-be-sound ,x))) (snd-offset (scale (warp-stretch *WARP*) (must-be-sound ,x)) (warp-time *WARP*))))) ,s)) (defmacro warp-abs (x s) `(progv '(*WARP*) (list (list 0.0 1.0 ,x)) ,s)) ;; MULTICHAN-EXPAND -- construct and return array according to args ;; ;; arrays are used in Nyquist to represent multiple channels ;; if any argument is an array, make sure all array arguments ;; have the same length. Then, construct a multichannel result ;; by calling fn once for each channel. The arguments passed to ;; fn for the i'th channel are either the i'th element of an array ;; argument, or just a copy of a non-array argument. ;; (defun multichan-expand (fn &rest args) (let (len newlen result) ; len is a flag as well as a count (dolist (a args) (cond ((arrayp a) (setf newlen (length a)) (cond ((and len (/= len newlen)) (error (format nil "In ~A, two arguments are vectors of differing length." fn)))) (setf len newlen)))) (cond (len (setf result (make-array len)) ; for each channel, call fn with args (dotimes (i len) (setf (aref result i) (apply fn (mapcar #'(lambda (a) ; take i'th entry or replicate: (cond ((arrayp a) (aref a i)) (t a))) args)))) result) (t (apply fn args))))) ;; SELECT-IMPLEMENTATION-? -- apply an implementation according to args ;; ;; There is a different Nyquist primitive for each combination of ;; constant (NUMBERP) and time-variable (SOUNDP) arguments. E.g. ;; a filter with fixed parameters differs from one with varying ;; parameters. In most cases, the user just calls one function, ;; and the arguments are decoded here: ;; SELECT-IMPLEMENTATION-1-1 -- 1 sound arg, 1 selector ;; (defun select-implementation-1-1 (fns snd sel1 &rest others) (if (numberp sel1) (apply (aref fns 0) (cons snd (cons sel1 others))) (apply (aref fns 1) (cons snd (cons sel1 others))))) ;; SELECT-IMPLEMENTATION-1-2 -- 1 sound arg, 2 selectors ;; ;; choose implemenation according to args 2 and 3 ;; (defun select-implementation-1-2 (fns snd sel1 sel2 &rest others) (if (numberp sel2) (if (numberp sel1) (apply (aref fns 0) (cons snd (cons sel1 (cons sel2 others)))) (apply (aref fns 1) (cons snd (cons sel1 (cons sel2 others))))) (if (numberp sel1) (apply (aref fns 2) (cons snd (cons sel1 (cons sel2 others)))) (apply (aref fns 3) (cons snd (cons sel1 (cons sel2 others))))))) ;; some waveforms (setf *saw-table* (pwlvr -1 1 1)) ; eh, creepy way to get 2205 samples. (setf *saw-table* (list *saw-table* (hz-to-step 1) T)) (setf *tri-table* (pwlvr -1 0.5 1 0.5 -1)) (setf *tri-table* (list *tri-table* (hz-to-step 1) T)) (setf *id-shape* (pwlvr -1 2 1 .01 1)) ; identity (setf *step-shape* (seq (const -1) (const 1 1.01))) ; hard step at zero (defun exp-dec (hold halfdec length) (let* ((target (expt 0.5 (/ length halfdec))) (expenv (pwev 1 hold 1 length target))) expenv) ) ;;; operations on sounds (defun diff (x &optional y) (cond (y (sum x (prod -1 y))) (t (prod -1 x)))) ; compare-shape is a shape table -- origin 1. (defun compare (x y &optional (compare-shape *step-shape*)) (let ((xydiff (diff x y))) (shape xydiff compare-shape 1))) ;;; oscs (defun osc-saw (hz) (hzosc hz *saw-table*)) (defun osc-tri (hz) (hzosc hz *tri-table*)) ; bias is [-1, 1] pulse width. sound or scalar. ; hz is a sound or scalar (defun osc-pulse (hz bias &optional (compare-shape *step-shape*)) (compare bias (osc-tri hz) compare-shape)) ;;; tapped delays ;(tapv snd offset vardelay maxdelay) (setfn tapv snd-tapv) ;; linear interpolation (setfn tapf snd-tapf) ;; no interpolation nyquist-3.05/runtime/profile.lsp0000644000175000000620000000142310144436365016034 0ustar stevestaff ; profile.lsp -- support for profiling ;## show-profile -- print profile data (defun show-profile () (let ((profile-flag (profile nil)) (total 0)) (dolist (name *PROFILE*) (setq total (+ total (get name '*PROFILE*)))) (dolist (name *PROFILE*) (format t "~A (~A%): ~A~%" (get name '*PROFILE*) (truncate (+ 0.5 (/ (float (* 100 (get name '*PROFILE*))) total))) name)) (format t "Total: ~A~%" total) (profile profile-flag))) ;## start-profile -- clear old profile data and start profiling (defun start-profile () (profile nil) (dolist (name *PROFILE*) (remprop name '*PROFILE*)) (setq *PROFILE* nil) (profile t)) nyquist-3.05/runtime/nyqmisc.lsp0000644000175000000620000000221011466723256016060 0ustar stevestaff;; nyqmisc.lsp -- misc functions for nyquist (init-global *snd-display-max-samples* 10000) (init-global *snd-display-print-samples* 100) ; (snd-display sound) -- describe a sound (defun snd-display (sound) (let (t0 srate len extent dur samples) (setf srate (snd-srate sound)) (setf t0 (snd-t0 sound)) (setf len (snd-length sound *snd-display-max-samples*)) (cond ((= len *snd-display-max-samples*) (setf extent (format nil ">~A" (+ t0 (* srate *snd-display-max-samples*)))) (setf dur (format nil ">~A" (* srate *snd-display-max-samples*)))) (t (setf extent (cadr (snd-extent sound *snd-display-max-samples*))) (setf dur (/ (snd-length sound *snd-display-max-samples*) srate)))) (cond ((> len 100) (setf samples (format nil "1st ~A samples" *snd-display-print-samples*)) (setf nsamples *snd-display-print-samples*)) (t (setf samples (format nil "~A samples" len)) (setf nsamples len))) (format t "~A: srate ~A, t0 ~A, extent ~A, dur ~A, ~A: ~A" sound srate t0 extent dur samples (snd-samples sound nsamples)))) nyquist-3.05/runtime/follow.lsp0000644000175000000620000000613010144436365015676 0ustar stevestaff;(set-control-srate 100) ;(set-sound-srate 100) ;(setf xx (pwl 0 1 1 0 1.1 1 1.8 0 2 1 3 0 5)) ;(setf xx (pwl 0 1 1 .2 1.1 1 1.8 .2 2 1 3 0 5)) ;(setf yy (snd-follow xx 0.1 0.25 1.0 30)) ;(setf db-factor (/ 1.0 (log 0.00001))) ; COMPRESS-MAP -- constructs a map for the compress function ; ; The map consists of two parts: a compression part and an expansion part. ; The intended use is to compress everything above compress-threshold by ; compress-ratio, and to downward expand everything below expand-ratio ; by expand-ratio. Thresholds are in dB and ratios are dB-per-dB. ; 0dB corresponds to an amplitude of 1.0 ; If the input goes above 0dB, the output can optionally be limited ; by seting limit-flag to T. This effectively changes the compression ; ratio to infinity at 0dB. If limit-flag is NIL, then the compression-ratio ; continues to apply above 0dB. ; It is assumed that expand-threshold <= compress-threshold <= 0 ; The gain is unity at 0dB so if compression-ratio > 1, then gain ; will be greater than unity below 0dB ;(defun compress-map (compress-ratio compress-threshold expand-ratio ; expand-threshold limit-flag) ; (let () ; ( ;; I'm not sure if the rest of this function was lost due to version ;; problems, or it never existed. Email to rbd@cs.cmu.edu if you would ;; like some help with dynamics compression. ;; ;; Also, I had a really great 2-stage compressor for speech -- it did ;; something like a noise gate with a short time constant, and an automatic ;; gain control with a long time constant. Each one varied the gain by ;; about 12 dB -- any more would cause really ugly noise pumping, but ;; without the combined actions of both, there was not enough control. ;; Again, email me if you are interested. Lately, I've been using ;; more sophisticated multiple band noise reduction in Cool Edit. They ;; obviously put a lot of work into that, and I don't plan to redo the ;; work for Nyquist. -RBD (defun compress (input map rise-time fall-time) ; take the square of the input to get power (let ((in-squared (mult input input))) ; compute the time-average (sort of a low-pass) of the square (setf avg (snd-avg in-squared 1000 500 OP-AVERAGE)) ; use follower to anticipate rise and trail off smoothly (setf env (snd-follow avg 0.001 0.2 1.0 20)) ; take logarithm to get dB instead of linear (setf logenv (snd-log env)) ; tricky part: map converts dB of input to desired gain in dB ; this defines the character of the compressor (setf shaped-env (shape logenv map 1.0)) ; go back to linear (setf gain (snd-exp shaped-env)) ; return the scaled input sound, ; another trick: avg signal will be delayed. Also, snd-follow ; has a delayed response because it's looking ahead in sound ; 20 = the number of samples of lookahead from snd-follow ; 88.2 = 44,100 (sample rate) / 500 (the step-size in avg) ; in other words, 44100/500 is the sample rate of the control ; signal looked at by follow ; "44100" should be replace by the signal's sample rate ; = (snd-srate input) (mult (seq (s-rest (/ 20.0 88.2)) (cue input)) gain))) nyquist-3.05/runtime/xm.lsp0000644000175000000620000023404311536000012015004 0ustar stevestaff;; X-Music, inspired by Commmon Music #| PATTERN SEMANTICS Patterns are objects that are generally accessed by calling (next pattern). Each call returns the next item in an infinite sequence generated by the pattern. Items are organized into periods. You can access all (remaining) items in the current period using (next pattern t). Patterns mark the end-of-period with +eop+, a distinguished atom. The +eop+ markers are filtered out by the next function but returned by the :next method. Pattern items may be patterns. This is called a nested pattern. When patterns are nested, you return a period from the innermost pattern, i.e. traversal is depth-first. This means when you are using something like random, you have to remember the last thing returned and keep getting the next element from that thing until you see +eop+; then you move on. It's a bit more complicated because a pattern advances when its immediate child pattern finishes a cycle, but +eop+ is only returned from the "leaf" patterns. With nested patterns, i.e. patterns with items that are patterns, the implementation requires that *all* items must be patterns. The application does *not* have to make every item a pattern, so the implementation "cleans up" the item list: Any item that is not a pattern is be replaced with a cycle pattern whose list contains just the one item. EXPLICIT PATTERN LENGTH Pattern length may be given explicitly by a number or a pattern that generates numbers. Generally this is specified as the optional :for keyword parameter when the pattern is created. If the explicit pattern length is a number, this will be the period length, overriding all implicit lengths. If the pattern length is itself a pattern, the pattern is evaluated every period to determine the length of the next period, overriding any implicit length. IMPLEMENTATION There are 3 ways to determine lengths: 1) The length is implicit. The length can be computed (at some point) and turned into an explicit length. 2) The length is explicit. This overrides the implicit length. The explicit length is stored as a counter that tells how many more items to generate in the current period. 3) The length can be generated by a pattern. The pattern is evaluated to generate an explicit length. So ultimately, we just need a mechanism to handle explicit lengths. This is incorporated into the pattern-class. The pattern-class sends :start-period before calling :advance when the first item in a period is about to be generated. Also, :next returns +eop+ automatically at the end of a period. Because evaluation is "depth first," i.e. we advance to the next top-level item only after a period is generated from a lower-level pattern, every pattern has a "current" field that holds the current item. the "have-current" field is a flag to tell when the "current" field is valid. It is initialized to nil. To generate an element, you need to follow the nested patterns all the way to the leaf pattern for every generated item. This is perhaps less efficient than storing the current leaf pattern at the top level, but patterns can be shared, i.e. a pattern can be a sub-pattern of multiple patterns, so current position in the tree structure of patterns can change at any time. The evaluation of nested patterns is depth-first and the next shallower level advances when its current child pattern completes a cycle. To facilitate this step, the :advance method, which advances a pattern and computes "current", returns +eonp+, which is a marker that a nested pattern has completed a cycle. The :next method generates the next item or +eop+ from a pattern. The algorithm in psuedo-code is roughly this: next(p) while true: if not have-current pattern-advance() have-current = true if is-nested and current = eop: have-current = false return eonp if is-nested: rslt = next(current) if rslt == eonp have-current = false elif rslt == eop and not current.is-nested have-current = false return rslt else return rslt else have-current = nil return current pattern-advance // length-pattern is either a pattern or a constant if null(count) and length-pattern: count = next(length-pattern) start-period() // subclass-specific computation if null(count) error if count == 0 current = eop count = nil else advance() // subclass-specific computation count-- SUBCLASS RESPONSIBILITIES Note that :advance is the method to override in the various subclasses of pattern-class. The :advance() method computes the next element in the infinite sequence of items and puts the item in the "current" field. The :start-period method is called before calling advance to get the first item of a new period. Finally, set the is-nested flag if there are nested patterns, and make all items of any nested pattern be patterns (no mix of patterns and non-patterns is allowed; use (MAKE-CYCLE (LIST item)) to convert a non-pattern to a pattern). |# (setf SCORE-EPSILON 0.000001) (setf pattern-class (send class :new '(current have-current is-nested name count length-pattern trace))) (defun patternp (x) (and (objectp x) (send x :isa pattern-class))) (setf +eop+ '+eop+) (setf +eonp+ '+eonp+) ;; end of nested period, this indicates you ;; should advance yourself and call back to get the next element (defun check-for-list (lis name) (if (not (listp lis)) (error (format nil "~A, requires a list of elements" name)))) (defun check-for-list-or-pattern (lis name) (if (not (or (listp lis) (patternp lis))) (error (format nil "~A, requires a list of elements or a pattern" name)))) (defun list-has-pattern (lis) (dolist (e lis) (if (patternp e) (return t)))) (defun is-homogeneous (lis) (let (type) (dolist (elem lis t) (cond ((null type) (setf type (if (patternp elem) 'pattern 'atom))) ((and (eq type 'pattern) (not (patternp elem))) (return nil)) ((and (eq type 'atom) (patternp elem)) (return nil)))))) (defun make-homogeneous (lis) (cond ((is-homogeneous lis) lis) (t (mapcar #'(lambda (item) (if (patternp item) item (make-cycle (list item) ;; help debugging by naming the new pattern ;; probably, the name could be item, but ;; here we coerce item to a string to avoid ;; surprises in code that assumes string names. :name (format nil "~A" item)))) lis)))) (send pattern-class :answer :next '() '(;(display ":next" name is-nested) (loop (cond ((not have-current) (send self :pattern-advance) (setf have-current t) (cond (trace (format t "pattern ~A advanced to ~A~%" (if name name "") (if (patternp current) (if (send current :name) (send current :name) "") current)))) (cond ((and is-nested (eq current +eop+)) ;(display ":next returning eonp" name) (setf have-current nil) (return +eonp+))))) (cond (is-nested (let ((rslt (send current :next))) (cond ((eq rslt +eonp+) (setf have-current nil)) ;; advance next-to-leaf level at end of leaf's period ((and (eq rslt +eop+) (not (send current :is-nested))) (setf have-current nil) ;; return +eof+ because it's the end of leaf's period (return rslt)) (t (return rslt))))) (t (setf have-current nil) (return current)))))) ;; :PATTERN-ADVANCE -- advance to the next item in a pattern ;; ;; this code is used by every class. class-specific behavior ;; is implemented by :advance, which this method calls ;; (send pattern-class :answer :pattern-advance '() '(;(display "enter :pattern-advance" self name count current is-nested) (cond ((null count) ;(display "in :pattern-advance" name count length-pattern) (if length-pattern (setf count (next length-pattern))) ;; if count is still null, :start-period must set count (send self :start-period))) (cond ((null count) (error (format nil "~A, pattern-class :pattern-advance has null count" name)))) (cond ((zerop count) (setf current +eop+) (setf count nil)) (t (send self :advance) (decf count))) ;(display "exit :pattern-advance" name count current) )) (send pattern-class :answer :is-nested '() '(is-nested)) (send pattern-class :answer :name '() '(name)) (send pattern-class :answer :set-current '(c) '((setf current c) (let ((value (if (patternp current) (send current :name) current))) ;(display ":set-current" name value) ))) ;; next -- get the next element in a pattern ;; ;; any non-pattern value is simply returned ;; (defun next (pattern &optional period-flag) ;(display "next" pattern period-flag (patternp pattern)) (cond ((and period-flag (patternp pattern)) (let (rslt elem) (while (not (eq (setf elem (send pattern :next)) +eop+)) ;(display "next t" (send pattern :name) elem) (if (not (eq elem +eonp+)) (push elem rslt))) (reverse rslt))) (period-flag (display "next" pattern) (error (format nil "~A, next expected a pattern" (send pattern :name)))) ((patternp pattern) ;(display "next" (send pattern :name) pattern) (let (rslt) (dotimes (i 10000 (error (format nil "~A, just retrieved 10000 empty periods -- is there a bug?" (send pattern :name)))) (if (not (member (setf rslt (send pattern :next)) '(+eop+ +eonp+))) (return rslt))))) (t ;; pattern not a pattern, so just return it: ;(display "next" pattern) pattern))) ;; ---- LENGTH Class ---- (setf length-class (send class :new '(pattern length-pattern) '() pattern-class)) (send length-class :answer :isnew '(p l nm tr) '((setf pattern p length-pattern l name nm trace tr))) ;; note that count is used as a flag as well as a counter. ;; If count is nil, then the pattern-length has not been ;; determined. Count is nil intitially and again at the ;; end of each period. Otherwise, count is an integer ;; used to count down the number of items remaining in ;; the period. (send length-class :answer :start-period '() '((setf count (next length-pattern)))) (send length-class :answer :advance '() '((send self :set-current (next pattern)))) (defun make-length (pattern length-pattern &key (name "length") trace) (send length-class :new pattern length-pattern name trace)) ;; ---- CYCLE Class --------- (setf cycle-class (send class :new '(lis cursor lis-pattern) '() pattern-class)) (send cycle-class :answer :isnew '(l for nm tr) '((cond ((patternp l) (setf lis-pattern l)) ((listp l) (send self :set-list l)) (t (error (format nil "~A, expected list" nm) l))) (setf length-pattern for name nm trace tr))) (send cycle-class :answer :set-list '(l) '((setf lis l) (check-for-list lis "cycle-class :set-list") (setf is-nested (list-has-pattern lis)) (setf lis (make-homogeneous lis)))) (send cycle-class :answer :start-period '() '(;(display "cycle-class :start-period" lis-pattern lis count length-pattern) (cond (lis-pattern (send self :set-list (next lis-pattern t)) (setf cursor lis))) (if (null count) (setf count (length lis))))) (send cycle-class :answer :advance '() '((cond ((and (null cursor) lis) (setf cursor lis)) ((null cursor) (error (format nil "~A, :advance - no items" name)))) (send self :set-current (car cursor)) (pop cursor))) (defun make-cycle (lis &key for (name "cycle") trace) (check-for-list-or-pattern lis "make-cycle") (send cycle-class :new lis for name trace)) ;; ---- LINE class ---- (setf line-class (send class :new '(lis cursor lis-pattern) '() pattern-class)) (send line-class :answer :isnew '(l for nm tr) '((cond ((patternp l) (setf lis-pattern l)) ((listp l) (send self :set-list l)) (t (error (format nil "~A, expected list" nm) l))) (setf length-pattern for name nm trace tr))) (send line-class :answer :set-list '(l) '((setf lis l) (check-for-list lis "line-class :set-list") (setf is-nested (list-has-pattern lis)) (setf lis (make-homogeneous l)) (setf cursor lis))) (send line-class :answer :start-period '() '((cond (lis-pattern (send self :set-list (next lis-pattern t)) (setf cursor lis))) (if (null count) (setf count (length lis))))) (send line-class :answer :advance '() '((cond ((null cursor) (error (format nil "~A, :advance - no items" name)))) (send self :set-current (car cursor)) (if (cdr cursor) (pop cursor)))) (defun make-line (lis &key for (name "line") trace) (check-for-list-or-pattern lis "make-line") (send line-class :new lis for name trace)) ;; ---- RANDOM class ----- (setf random-class (send class :new '(lis lis-pattern len previous repeats mincnt maxcnt) '() pattern-class)) ;; the structure is (value weight weight-pattern max min) (setfn rand-item-value car) (defun set-rand-item-value (item value) (setf (car item) value)) (setfn rand-item-weight cadr) (defun set-rand-item-weight (item weight) (setf (car (cdr item)) weight)) (setfn rand-item-weight-pattern caddr) (setfn rand-item-max cadddr) (defun rand-item-min (lis) (car (cddddr lis))) (defun select-random (len lis previous repeats mincnt maxcnt) (let (sum items r) (cond ((zerop len) (break "random-class has no list to choose from") nil) (t (setf sum 0) (dolist (item lis) (setf sum (+ sum (rand-item-weight item)))) (setf items lis) (setf r (rrandom)) (setf sum (* sum r)) (setf rbd-count-all (incf rbd-count-all)) (loop (setf sum (- sum (rand-item-weight (car items)))) (if (<= sum 0) (return (car items))) (setf rbd-count-two (incf rbd-count-two)) (setf items (cdr items))))))) (defun random-convert-spec (item) ;; convert (value :weight wp :min min :max max) to (value nil wp max min) (let (value (wp 1) mincnt maxcnt lis) (setf value (car item)) (setf lis (cdr item)) (while lis (cond ((eq (car lis) :weight) (setf wp (cadr lis))) ((eq (car lis) :min) (setf mincnt (cadr lis))) ((eq (car lis) :max) (setf maxcnt (cadr lis))) (t (error "(make-random) item syntax error" item))) (setf lis (cddr lis))) (list value nil wp maxcnt mincnt))) (defun random-atom-to-list (a) (if (atom a) (list a nil 1 nil nil) (random-convert-spec a))) (send random-class :answer :isnew '(l for nm tr) ;; there are two things we have to normalize: ;; (1) make all items lists ;; (2) if any item is a pattern, make all items patterns '((cond ((patternp l) (setf lis-pattern l)) ((listp l) (send self :set-list l)) (t (error (format nil "~A, expected list") l))) (setf rbd-count-all 0 rbd-count-two 0) (setf length-pattern for name nm trace tr))) (send random-class :answer :set-list '(l) '((check-for-list l "random-class :set-list") (setf lis (mapcar #'random-atom-to-list l)) (dolist (item lis) (if (patternp (rand-item-value item)) (setf is-nested t))) (if is-nested (mapcar #'(lambda (item) (if (not (patternp (rand-item-value item))) (set-rand-item-value item (make-cycle (list (rand-item-value item)))))) lis)) ;(display "random is-new" lis) (setf repeats 0) (setf len (length lis)))) (send random-class :answer :start-period '() '(;(display "random-class :start-period" count len lis lis-pattern) (cond (lis-pattern (send self :set-list (next lis-pattern t)))) (if (null count) (setf count len)) (dolist (item lis) (set-rand-item-weight item (next (rand-item-weight-pattern item)))))) (send random-class :answer :advance '() '((let (selection (iterations 0)) ;(display "random-class :advance" mincnt repeats) (cond ((and mincnt (< repeats mincnt)) (setf selection previous) (incf repeats)) (t (setf selection (select-random len lis previous repeats mincnt maxcnt)))) (loop ; make sure selection is ok, otherwise try again (cond ((and (eq selection previous) maxcnt (>= repeats maxcnt)) ; hit maximum limit, try again (setf selection (select-random len lis previous repeats mincnt maxcnt)) (incf iterations) (cond ((> iterations 10000) (error (format nil "~A, unable to pick next item after 10000 tries" name) lis)))) (t (return)))) ; break from loop, we found a selection ; otherwise, we are ok (if (not (eq selection previous)) (setf repeats 1) (incf repeats)) (setf mincnt (rand-item-min selection)) (setf maxcnt (rand-item-max selection)) (setf previous selection) ;(display "new selection" repeats mincnt maxcnt selection) (send self :set-current (rand-item-value selection))))) (defun make-random (lis &key for (name "random") trace) (check-for-list-or-pattern lis "make-random") (send random-class :new lis for name trace)) ;; ---- PALINDROME class ----- #| Palindrome includes elide, which is either t, nil, :first, or :last. The pattern length is the "natural" length of the pattern, which goes forward and backward through the list. Thus, if the list is of length N, the palindrome length depends on elide as follows: elide length nil 2N t 2N - 2 :first 2N - 1 :last 2N - 1 If elide is a pattern, and if length is not specified, then length should be computed based on elide. |# (setf palindrome-class (send class :new '(lis revlis lis-pattern direction elide-pattern elide cursor) '() pattern-class)) (send palindrome-class :answer :set-list '(l) '((setf lis l) (check-for-list lis "palindrome-class :start-period") (setf is-nested (list-has-pattern lis)) (setf lis (make-homogeneous l)) (setf revlis (reverse lis) direction t cursor lis))) (send palindrome-class :answer :isnew '(l e for nm tr) '((cond ((patternp l) (setf lis-pattern l)) ((listp l) (send self :set-list l)) (t (error (format nil "~A, expected list" nm) l))) (setf elide-pattern e length-pattern for name nm trace tr))) (send palindrome-class :answer :start-period '() '((cond (lis-pattern (send self :set-list (next lis-pattern t)) (setf cursor lis))) (setf elide (next elide-pattern)) (if (and elide (null lis)) (error (format nil "~A, cannot elide if list is empty" name))) (if (null count) (setf count (- (* 2 (length lis)) (if (member elide '(:first :last)) 1 (if elide 2 0))))))) (send palindrome-class :answer :next-item '() '((send self :set-current (car cursor)) (pop cursor) (cond ((and cursor (not (cdr cursor)) (or (and direction (member elide '(:last t))) (and (not direction) (member elide '(:first t))))) (pop cursor))))) (send palindrome-class :answer :advance '() '( (cond (cursor (send self :next-item)) (direction ;; we're going forward (setf direction nil) ;; now going backward (setf cursor revlis) (send self :next-item)) (t ;; direction is reverse (setf direction t) (setf cursor lis) (send self :next-item))))) (defun make-palindrome (lis &key elide for (name "palindrome") trace) (check-for-list-or-pattern lis "make-palindrome") (send palindrome-class :new lis elide for name trace)) ;; ================= HEAP CLASS ====================== ;; to handle the :max keyword, which tells the object to avoid ;; repeating the last element of the previous period: ;; ;; maxcnt = 1 means "avoid the repetition" ;; check-repeat signals we are at the beginning of the period and must check ;; prev holds the previous value (initially nil) ;; after each item is generated, check-repeat is cleared. It is ;; recalculated when a new period is started. (setf heap-class (send class :new '(lis used maxcnt prev check-repeat lis-pattern len) '() pattern-class)) (send heap-class :answer :isnew '(l for mx nm tr) '((cond ((patternp l) (setf lis-pattern l)) ((listp l) ; make a copy of l to avoid side effects (send self :set-list (append l nil))) (t (error (format nil "~A, expected list" nm) l))) (setf length-pattern for maxcnt mx name nm trace tr))) (send heap-class :answer :set-list '(l) '((setf lis l) (check-for-list lis "heap-class :set-list") (setf is-nested (list-has-pattern lis)) (setf lis (make-homogeneous lis)) (setf len (length lis)))) (send heap-class :answer :start-period '() '(;(display "heap-class :start-period" lis-pattern count lis) (cond (lis-pattern (send self :set-list (next lis-pattern t)))) ; start of period -- may need to avoid repeating previous item (if (= maxcnt 1) (setf check-repeat t)) (if (null count) (setf count len)))) (defun delete-first (elem lis) (cond ((null lis) nil) ((eq elem (car lis)) (cdr lis)) (t (cons (car lis) (delete-first elem (cdr lis)))))) ;; NO-DISTINCT-ELEM -- check if any element of list is not val ;; (defun no-distinct-elem (lis val) (not (dolist (elem lis) (if (not (equal elem val)) ;; there is a distinct element, return t from dolist (return t))))) ;; if no distinct element, dolist returns nil, but this is negated ;; by the NOT so the function will return t (send heap-class :answer :advance '() '((cond ((null lis) (setf lis used) (setf used nil))) (let (n elem) (cond ((and check-repeat (no-distinct-elem lis prev)) (error (format nil "~A, cannot avoid repetition, but :max is 1" name)))) (loop (setf n (random (length lis))) (setf elem (nth n lis)) (if (or (not check-repeat) (not (equal prev elem))) (return))) ;; loop until suitable element is chosen (setf lis (delete-first elem lis)) (push elem used) (setf check-repeat nil) (setf prev elem) (send self :set-current elem)))) (defun make-heap (lis &key for (max 2) (name "heap") trace) (send heap-class :new lis for max name trace)) ;;================== COPIER CLASS ==================== (setf copier-class (send class :new '(sub-pattern repeat repeat-pattern merge merge-pattern period cursor) '() pattern-class)) (send copier-class :answer :isnew '(p r m for nm tr) '((setf sub-pattern p repeat-pattern r merge-pattern m) (setf length-pattern for name nm trace tr))) #| copier-class makes copies of periods from sub-pattern If merge is true, the copies are merged into one big period. If merge is false, then repeat separate periods are returned. If repeat is negative, then -repeat periods of sub-pattern are skipped. merge and repeat are computed from merge-pattern and repeat-pattern initially and after making repeat copies To repeat individual items, set the :for keyword parameter of the sub-pattern to 1. |# (send copier-class :answer :start-period '() '((cond ((null count) (cond ((or (null repeat) (zerop repeat)) (send self :really-start-period)) (t (setf count (length period)))))))) (send copier-class :answer :really-start-period '() '(;(display "copier-class :really-start-period" count) (setf merge (next merge-pattern)) (setf repeat (next repeat-pattern)) (while (minusp repeat) (dotimes (i (- repeat)) (setf period (next sub-pattern t))) (setf repeat (next repeat-pattern)) (setf merge (next merge-pattern))) (setf period (next sub-pattern t)) (setf cursor nil) (if (null count) (setf count (* (if merge repeat 1) (length period)))))) (send copier-class :answer :advance '() '((let ((loop-count 0)) (loop ;(display "copier loop" repeat cursor period) (cond (cursor (send self :set-current (car cursor)) (pop cursor) (return)) ((plusp repeat) (decf repeat) (setf cursor period)) ((> loop-count 10000) (error (format nil "~A, copier-class :advance encountered 10000 empty periods" name))) (t (send self :really-start-period))) (incf loop-count))))) (defun make-copier (sub-pattern &key for (repeat 1) merge (name "copier") trace) (send copier-class :new sub-pattern repeat merge for name trace)) ;; ================= ACCUMULATE-CLASS =================== (setf accumulate-class (send class :new '(sub-pattern period cursor sum mini maxi) '() pattern-class)) (send accumulate-class :answer :isnew '(p for nm tr mn mx) '((setf sub-pattern p length-pattern for name nm trace tr sum 0 mini mn maxi mx) ; (display "accumulate isnew" self nm) )) #| accumulate-class creates sums of numbers from another pattern The output periods are the same as the input periods (by default). |# (send accumulate-class :answer :start-period '() '((cond ((null count) (send self :really-start-period))))) (send accumulate-class :answer :really-start-period '() '((setf period (next sub-pattern t)) (setf cursor period) ;(display "accumulate-class :really-start-period" period cursor count) (if (null count) (setf count (length period))))) (send accumulate-class :answer :advance '() '((let ((loop-count 0) (minimum (next mini)) (maximum (next maxi))) (loop (cond (cursor (setf sum (+ sum (car cursor))) (cond ((and (numberp minimum) (< sum minimum)) (setf sum minimum))) (cond ((and (numberp maximum) (> sum maximum)) (setf sum maximum))) (send self :set-current sum) (pop cursor) (return)) ((> loop-count 10000) (error (format nil "~A, :advance encountered 10000 empty periods" name))) (t (send self :really-start-period))) (incf loop-count))))) (defun make-accumulate (sub-pattern &key for min max (name "accumulate") trace) (send accumulate-class :new sub-pattern for name trace min max)) ;;================== ACCUMULATION CLASS =================== ;; for each item, generate all items up to and including the item, e.g. ;; (a b c) -> (a a b a b c) (setf accumulation-class (send class :new '(lis lis-pattern outer inner len) '() pattern-class)) (send accumulation-class :answer :isnew '(l for nm tr) '((cond ((patternp l) (setf lis-pattern l)) ((listp l) (send self :set-list l)) (t (error (format nil "~A, expected list" nm) l))) (setf length-pattern for name nm trace tr))) (send accumulation-class :answer :set-list '(l) '((setf lis l) (check-for-list lis "heap-class :set-list") (setf lis (make-homogeneous lis)) (setf inner lis) (setf outer lis) (setf len (length lis)))) (send accumulation-class :answer :start-period '() '((cond (lis-pattern (send self :set-list (next lis-pattern t)))) ; start of period, length = (n^2 + n) / 2 (if (null count) (setf count (/ (+ (* len len) len) 2))))) (send accumulation-class :answer :advance '() ;; inner traverses lis from first to outer ;; outer traverses lis '((let ((elem (car inner))) (cond ((eq inner outer) (setf outer (rest outer)) (setf outer (if outer outer lis)) (setf inner lis)) (t (setf inner (rest inner)))) (send self :set-current elem)))) (defun make-accumulation (lis &key for (name "accumulation") trace) (send accumulation-class :new lis for name trace)) ;;================== SUM CLASS ================= (setf sum-class (send class :new '(x y period cursor fn) '() pattern-class)) (send sum-class :answer :isnew '(xx yy for nm tr) '((setf x xx y yy length-pattern for name nm trace tr fn #'+))) #| sum-class creates pair-wise sums of numbers from 2 streams. The output periods are the same as the input periods of the first pattern argument (by default). |# (send sum-class :answer :start-period '() '((cond ((null count) (send self :really-start-period))))) (send sum-class :answer :really-start-period '() '((setf period (next x t)) (setf cursor period) (if (null count) (setf count (length period))))) (send sum-class :answer :advance '() '((let ((loop-count 0) rslt) (loop (cond (cursor (setf rslt (funcall fn (car cursor) (next y))) (send self :set-current rslt) (pop cursor) (return)) ((> loop-count 10000) (error (format nil "~A, :advance encountered 10000 empty periods" name))) (t (send self :really-start-period))) (incf loop-count))))) (defun make-sum (x y &key for (name "sum") trace) (send sum-class :new x y for name trace)) ;;================== PRODUCT CLASS ================= (setf product-class (send class :new '() '() sum-class)) (send product-class :answer :isnew '(xx yy for nm tr) '((setf x xx y yy length-pattern for name nm trace tr fn #'*))) (defun make-product (x y &key for (name "product") trace) (send product-class :new x y for name trace)) ;;================== EVAL CLASS ================= (setf eval-class (send class :new '(expr expr-pattern) '() pattern-class)) (send eval-class :answer :isnew '(e for nm tr) '((cond ((patternp e) (setf expr-pattern e)) (t (setf expr e))) (setf length-pattern for name nm trace tr))) (send eval-class :answer :start-period '() '(;(display "cycle-class :start-period" lis-pattern lis count length-pattern) (cond (expr-pattern (setf expr (next expr-pattern)))))) (send eval-class :answer :advance '() '((send self :set-current (eval expr)))) (defun make-eval (expr &key (for 1) (name "eval") trace) (send eval-class :new expr for name trace)) ;;================== MARKOV CLASS ==================== (setf markov-class (send class :new '(rules order state produces pattern len) '() pattern-class)) (defun is-produces-homogeneous (produces) (let (type elem) (setf *rslt* nil) (loop (cond ((or (null produces) (eq produces :eval) (null (cadr produces))) (return t))) (setf elem (cadr produces)) (cond ((null type) (setf type (if (patternp elem) 'pattern 'atom)) ;(display "is-produces-homogeneous" type) (setf *rslt* (eq type 'pattern)) ;(display "is-produces-homogeneous" *rslt*) ) ((and (eq type 'pattern) (not (patternp elem))) (return nil)) ((and (eq type 'atom) (patternp elem)) (return nil))) (setf produces (cddr produces))))) (defun make-produces-homogeneous (produces) (let (result item) (loop (if (null produces) (return nil)) (push (car produces) result) (setf produces (cdr produces)) (setf item (car produces)) (setf produces (cdr produces)) (if (not (patternp item)) (setf item (make-cycle (list item)))) (push item result)) (reverse result))) (send markov-class :answer :isnew '(r o s p for nm tr) ;; input parameters are rules, order, state, produces, for, name, trace '((setf order o state s produces p length-pattern for name nm trace tr) (setf len (length r)) ;; input r looks like this: ;; ((prev1 prev2 -> next1 next2 (next3 weight) ... ) ...) ;; transition table will look like a list of these: ;; ((prev1 prev2 ... prevn) (next1 weight weight-pattern) ...) (dolist (rule r) (let ((targets (cdr (nthcdr order rule))) entry pattern) ;; build entry in reverse order (dolist (target targets) (push (if (atom target) (list target 1 1) (list (first target) (next (second target)) (second target))) entry)) ; (display "isnew" entry rule targets order (nthcdr order rule)) (dotimes (i order) (push (nth i rule) pattern)) (push (cons (reverse pattern) entry) rules))) (setf rules (reverse rules)) ;; keep rules in original order (setf *rslt* nil) ;; in case produces is nil (cond ((and produces (not (is-produces-homogeneous produces))) (setf produces (make-produces-homogeneous produces)))) ;(display "markov-class :isnew" *rslt*) (setf is-nested *rslt*) ;; returned by is-produces-homogeneous ;(display "markov-class :isnew" is-nested) )) (defun markov-match (state pattern) (dolist (p pattern t) ;; return true if no mismatch ;; compare element-by-element (cond ((eq p '*)) ; anything matches '* ((eql p (car state))) (t (return nil))) ; a mismatch: return false (setf state (cdr state)))) (defun markov-sum-of-weights (rule) ;(display "sum-of-weights" rule) (let ((sum 0.0)) (dolist (target (cdr rule)) ;(display "markov-sum-of-weights" target) (setf sum (+ sum (second target)))) sum)) (defun markov-pick-target (sum rule) (let ((total 0.0) ;; want to choose a value in the interval [0, sum) ;; but real-random is not open on the right, so fudge ;; the range by a small amount: (r (real-random 0.0 (- sum SCORE-EPSILON)))) (dolist (target (cdr rule)) (setf total (+ total (second target))) (cond ((> total r) (return (car target))))))) (defun markov-update-weights (rule) (dolist (target (cdr rule)) (setf (car (cdr target)) (next (caddr target))))) (defun markov-map-target (target produces) (while (and produces (not (eq target (car produces)))) (setf produces (cddr produces))) (cadr produces)) (send markov-class :answer :find-rule '() '((let (rslt) ;(display "find-rule" rules) (dolist (rule rules) ;(display "find-rule" state rule) (cond ((markov-match state (car rule)) (setf rslt rule) (return rslt)))) (cond ((null rslt) (display "Error, no matching rule found" state rules) (error (format nil "~A, (markov-class)" name)))) rslt))) (send markov-class :answer :start-period '() '((if (null count) (setf count len)))) (defun markov-general-rule-p (rule) (let ((pre (car rule))) (cond ((< (length pre) 2) nil) ;; 1st-order mm (t ;; return false if any member not * ;; return t if all members are * (dolist (s pre t) (if (eq s '*) t (return nil))))))) (defun markov-find-state-leading-to (target rules) (let (candidates) (dolist (rule rules) (let ((targets (cdr rule))) (dolist (targ targets) (cond ((eql (car targ) target) (push (car rule) candidates)))))) (cond (candidates ;; found at least one (nth (random (length candidates)) candidates)) (t nil)))) (send markov-class :answer :advance '() '((let (rule sum target rslt new-state) ;(display "markov" pattern rules) (setf rule (send self :find-rule)) ;(display "advance 1" rule) (markov-update-weights rule) ;(display "advance 2" rule) (setf sum (markov-sum-of-weights rule)) ;; the target can be a pattern, so apply NEXT to it (setf target (next (markov-pick-target sum rule))) ;; if the matching rule is multiple *'s, then this ;; is a higher-order Markov model, and we may now ;; wander around in parts of the state space that ;; never appeared in the training data. To avoid this ;; we violate the strict interpretation of the rules ;; and pick a random state sequence from the rule set ;; that might have let to the current state. We jam ;; this state sequence into state so that when we ;; append target, we'll have a history that might ;; have a corresponding rule next time. (cond ((markov-general-rule-p rule) (setf new-state (markov-find-state-leading-to target rules)) (cond (new-state ;(display "state replacement" new-state target) (setf state new-state))))) (setf state (append (cdr state) (list target))) ;(display "markov next" rule sum target state) ;; target is the symbol for the current state. We can ;; return target (default), the value of target, or a ;; mapped value: (cond ((eq produces :eval) (setf target (eval target))) ((and produces (listp produces)) ;(display "markov-produce" target produces) (setf target (markov-map-target target produces)))) (if (not (eq is-nested (patternp target))) (error (format nil "~A :is-nested keyword (~A) not consistent with result (~A)" name is-nested target))) (send self :set-current target)))) (defun make-markov (rules &key produces past for (name "markov") trace) ;; check to make sure past and rules are consistent (let ((order (length past))) (dolist (rule rules) (dotimes (i order) (if (eq (car rule) '->) (error (format nil "~A, a rule does not match the length of :past" name))) (pop rule)) (if (eq (car rule) '->) nil (error (format nil "~A, a rule does not match the length of :past" name))))) (cond ((null for) (setf for (length rules)))) (send markov-class :new rules (length past) past produces for name trace)) (defun markov-rule-match (rule state) (cond ((null state) t) ((eql (car rule) (car state)) (markov-rule-match (cdr rule) (cdr state))) (t nil))) (defun markov-find-rule (rules state) (dolist (rule rules) ;(display "find-rule" rule) (cond ((markov-rule-match rule state) (return rule))))) ;; ------- functions below are for MARKOV-CREATE-RULES -------- ;; MARKOV-FIND-CHOICE -- given a next state, find it in rule ;; ;; use state to get the order of the Markov model, e.g. how ;; many previous states to skip in the rule, (add 1 for '->). ;; then use assoc to do a quick search ;; ;; example: ;; (markov-find-choice '(a b -> (c 1) (d 2)) '(a b) 'd) ;; returns (d 2) from the rule ;; (defun markov-find-choice (rule state next) (assoc next (nthcdr (1+ (length state)) rule))) (defun markov-update-rule (rule state next) (let ((choice (markov-find-choice rule state next))) (cond (choice (setf (car (cdr choice)) (1+ (cadr choice)))) (t (nconc rule (list (list next 1))))) rule)) (defun markov-update-rules (rules state next) (let ((rule (markov-find-rule rules state))) (cond (rule (markov-update-rule rule state next)) (t (setf rules (nconc rules (list (append state (cons '-> (list (list next 1))))))))) rules)) ;; MARKOV-UPDATE-HISTOGRAM -- keep a list of symbols and counts ;; ;; This histogram will become the right-hand part of a rule, so ;; the format is ((symbol count) (symbol count) ...) ;; (defun markov-update-histogram (histogram next) (let ((pair (assoc next histogram))) (cond (pair (setf (car (cdr pair)) (1+ (cadr pair)))) (t (setf histogram (cons (list next 1) histogram)))) histogram)) (defun markov-create-rules (sequence order &optional generalize) (let ((seqlen (length sequence)) state rules next histogram rule) (cond ((<= seqlen order) (error "markov-create-rules: sequence must be longer than order")) ((< order 1) (error "markov-create-rules: order must be 1 or greater"))) ; build initial state sequence (dotimes (i order) (setf state (nconc state (list (car sequence)))) (setf sequence (cdr sequence))) ; for each symbol, either update a rule or add a rule (while sequence (setf next (car sequence)) (setf sequence (cdr sequence)) (setf rules (markov-update-rules rules state next)) (setf histogram (markov-update-histogram histogram next)) ; shift next state onto current state list (setf state (nconc (cdr state) (list next)))) ; generalize? (cond (generalize (setf rule (cons '-> histogram)) (dotimes (i order) (setf rule (cons '* rule))) (setf rules (nconc rules (list rule))))) rules)) ;; ----- WINDOW Class --------- (setf window-class (send class :new '(pattern skip-pattern lis cursor) '() pattern-class)) (send window-class :answer :isnew '(p for sk nm tr) '((setf pattern p length-pattern for skip-pattern sk name nm trace tr))) (send window-class :answer :start-period '() '((if (null count) (error (format nil "~A, :start-period -- count is null" name))) (cond ((null lis) ;; first time (dotimes (i count) (push (next pattern) lis)) (setf lis (reverse lis))) (t (let ((skip (next skip-pattern))) (dotimes (i skip) (if lis (pop lis) (next pattern)))) (setf lis (reverse lis)) (let ((len (length lis))) (while (< len count) (incf len) (push (next pattern) lis)) (while (> len count) (decf len) (pop lis)) (setf lis (reverse lis))))) (setf cursor lis))) (send window-class :answer :advance '() '((send self :set-current (car cursor)) (pop cursor))) (defun make-window (pattern length-pattern skip-pattern &key (name "window") trace) (send window-class :new pattern length-pattern skip-pattern name trace)) ;; SCORE-SORTED -- test if score is sorted ;; (defun score-sorted (score) (let ((result t)) (while (cdr score) (cond ((event-before (cadr score) (car score)) (setf result nil) (return nil))) (setf score (cdr score))) result)) (defmacro score-gen (&rest args) (let (key val tim dur (name ''note) ioi trace save score-len score-dur others pre post next-expr (score-begin 0) score-end) (while (and args (cdr args)) (setf key (car args)) (setf val (cadr args)) (setf args (cddr args)) (case key (:time (setf tim val)) (:dur (setf dur val)) (:name (setf name val)) (:ioi (setf ioi val)) (:trace (setf trace val)) (:save (setf save val)) (:pre (setf pre val)) (:post (setf post val)) (:score-len (setf score-len val)) (:score-dur (setf score-dur val)) (:begin (setf score-begin val)) (:end (setf score-end val)) (t (setf others (cons key (cons val others)))))) ;; make sure at least one of score-len, score-dur is present (cond ((and (null score-len) (null score-dur)) (error "score-gen needs either :score-len or :score-dur to limit length"))) ;; compute expression for dur (cond ((null dur) (setf dur 'sg:ioi))) ;; compute expression for ioi (cond ((null ioi) (setf ioi 1))) ;; compute expression for next start time (setf next-expr '(+ sg:start sg:ioi)) ; (display "score-gen" others) `(let (sg:seq (sg:start ,score-begin) sg:ioi (sg:score-len ,score-len) (sg:score-dur ,score-dur) (sg:count 0) (sg:save ,save) (sg:begin ,score-begin) (sg:end ,score-end) sg:det-end) ;; sg:det-end is a flag that tells us to determine the end time (cond ((null sg:end) (setf sg:end 0 sg:det-end t))) ;; make sure at least one of score-len, score-dur is present (loop (cond ((or (and sg:score-len (<= sg:score-len sg:count)) (and sg:score-dur (<= (+ sg:begin sg:score-dur) sg:start))) (return))) ,pre ,(cond (tim (list 'setf 'sg:start tim))) (setf sg:ioi ,ioi) (setf sg:dur ,dur) (push (list sg:start sg:dur (list ,name ,@others)) sg:seq) ,post (cond (,trace (format t "get-seq trace at ~A stretch ~A: ~A~%" sg:start sg:dur (car sg:seq)))) (incf sg:count) (setf sg:start ,next-expr) ;; end time of score will be max over start times of the next note ;; this bases the score duration on ioi's rather than durs. But ;; if user specified sg:end, sg:det-end is false and we do not ;; try to compute sg:end. (cond ((and sg:det-end (> sg:start sg:end)) (setf sg:end sg:start)))) (setf sg:seq (reverse sg:seq)) ;; avoid sorting a sorted list -- XLisp's quicksort can overflow the ;; stack if the list is sorted because (apparently) the pivot points ;; are not random. (cond ((not (score-sorted sg:seq)) (setf sg:seq (bigsort sg:seq #'event-before)))) (push (list 0 0 (list 'SCORE-BEGIN-END ,score-begin sg:end)) sg:seq) (cond (sg:save (set sg:save sg:seq))) sg:seq))) ;; ============== score manipulation =========== (defun event-before (a b) (< (car a) (car b))) ;; EVENT-END -- get the ending time of a score event ;; (defun event-end (e) (+ (car e) (cadr e))) ;; EVENT-TIME -- time of an event ;; (setfn event-time car) ;; EVENT-DUR -- duration of an event ;; (setfn event-dur cadr) ;; EVENT-SET-TIME -- new event with new time ;; (defun event-set-time (event time) (cons time (cdr event))) ;; EVENT-SET-DUR -- new event with new dur ;; (defun event-set-dur (event dur) (list (event-time event) dur (event-expression event))) ;; EVENT-SET-EXPRESSION -- new event with new expression ;; (defun event-set-expression (event expression) (list (event-time event) (event-dur event) expression)) ;; EXPR-HAS-ATTR -- test if expression has attribute ;; (defun expr-has-attr (expression attr) (member attr expression)) ;; EXPR-GET-ATTR -- get value of attribute from expression ;; (defun expr-get-attr (expression attr &optional default) (let ((m (member attr expression))) (if m (cadr m) default))) ;; EXPR-SET-ATTR -- set value of an attribute in expression ;; (returns new expression) (defun expr-set-attr (expr attr value) (cons (car expr) (expr-parameters-set-attr (cdr expr) attr value))) (defun expr-parameters-set-attr (lis attr value) (cond ((null lis) (list attr value)) ((eq (car lis) attr) (cons attr (cons value (cddr lis)))) (t (cons (car lis) (cons (cadr lis) (expr-parameters-set-attr (cddr lis) attr value)))))) ;; EXPR-REMOVE-ATTR -- expression without attribute value pair (defun expr-remove-attr (event attr) (cons (car expr) (expr-parameters-remove-attr (cdr expr) attr))) (defun expr-parameters-remove-attr (lis attr) (cond ((null lis) nil) ((eq (car lis) attr) (cddr lis)) (t (cons (car lis) (cons (cadr lis) (expr-parameters-remove-attr (cddr lis) attr)))))) ;; EVENT-GET-ATTR -- get value of attribute from event ;; (defun event-get-attr (note attr &optional default) (expr-get-attr (event-expression note) attr default)) ;; EVENT-SET-ATTR -- new event with attribute = value (defun event-set-attr (event attr value) (event-set-expression event (expr-set-attr (event-expression event) attr value))) ;; EVENT-REMOVE-ATTR -- new event without atttribute value pair (defun event-remove-attr (event attr) (event-set-expression event (event-remove-attr (event-expression event) attr))) ;; SCORE-GET-BEGIN -- get the begin time of a score ;; (defun score-get-begin (score) (setf score (score-must-have-begin-end score)) (cadr (event-expression (car score)))) ;; SCORE-SET-BEGIN -- set the begin time of a score ;; (defun score-set-begin (score time) (setf score (score-must-have-begin-end score)) (cons (list 0 0 (list 'score-begin-end time (caddr (event-expression (car score))))) (cdr score))) ;; SCORE-GET-END -- get the end time of a score ;; (defun score-get-end (score) (setf score (score-must-have-begin-end score)) (caddr (event-expression (car score)))) ;; SCORE-SET-END -- set the end time of a score ;; (defun score-set-end (score time) (setf score (score-must-have-begin-end score)) (cons (list 0 0 (list 'score-begin-end (cadr (event-expression (car score))) time)) (cdr score))) ;; FIND-FIRST-NOTE -- use keywords to find index of first selected note ;; (defun find-first-note (score from-index from-time) (let ((s (cdr score))) ;; offset by one because we removed element 0 (setf from-index (if from-index (max 0 (- from-index 1)) 0)) (setf from-time (if from-time (- from-time SCORE-EPSILON) (- SCORE-EPSILON))) (if s (setf s (nthcdr from-index s))) (while (and s (>= from-time (event-time (car s)))) (setf s (cdr s)) (incf from-index)) (1+ from-index))) ;; EVENT-BEFORE -- useful function for sorting scores ;; (defun event-before (a b) (< (car a) (car b))) ;; bigsort -- a sort routine that avoids recursion in order ;; to sort large lists without overflowing the evaluation stack ;; ;; Does not modify input list. Does not minimize cons-ing. ;; ;; Algorithm: first accumulate sorted sub-sequences into lists ;; Then merge pairs iteratively until only one big list remains ;; (defun bigsort (lis cmp) ; sort lis using cmp function ;; if (funcall cmp a b) then a and b are in order (prog (rslt sub pairs) ;; first, convert to sorted sublists stored on rslt ;; accumulate sublists in sub get-next-sub (if (null lis) (go done-1)) (setf sub (list (car lis))) (setf lis (cdr lis)) fill-sub ;; invariant: sub is non-empty, in reverse order (cond ((and lis (funcall cmp (car sub) (car lis))) (setf sub (cons (car lis) sub)) (setf lis (cdr lis)) (go fill-sub))) (setf sub (reverse sub)) ;; put sub in correct order (setf rslt (cons sub rslt)) ;; build rslt in reverse order (go get-next-sub) done-1 ;; invariant: rslt is list of sorted sublists (if (cdr rslt) nil (go done-2)) ;; invariant: rslt has at least one list (setf pairs rslt) (setf rslt nil) merge-pairs ;; merge a pair and save on rslt (if (car pairs) nil (go end-of-pass)) ;; loop until all pairs merged ;; invariant: pairs has at least one list (setf list1 (car pairs)) ;; list1 is non-empty (setf list2 (cadr pairs)) ;; list2 could be empty (setf pairs (cddr pairs)) (cond (list2 (setf rslt (cons (list-merge list1 list2 cmp) rslt))) (t (setf rslt (cons list1 rslt)))) (go merge-pairs) end-of-pass (go done-1) done-2 ;; invariant: rslt has one sorted list! (return (car rslt)))) (defun list-merge (list1 list2 cmp) (prog (rslt) merge-loop (cond ((and list1 list2) (cond ((funcall cmp (car list1) (car list2)) (setf rslt (cons (car list1) rslt)) (setf list1 (cdr list1))) (t (setf rslt (cons (car list2) rslt)) (setf list2 (cdr list2))))) (list1 (return (nconc (reverse rslt) list1))) (t (return (nconc (reverse rslt) list2)))) (go merge-loop))) ;; SCORE-SORT -- sort a score into time order ;; (defun score-sort (score &optional (copy-flag t)) (setf score (score-must-have-begin-end score)) (let ((begin-end (car score))) (setf score (cdr score)) (if copy-flag (setf score (append score nil))) (cons begin-end (bigsort score #'event-before)))) ;; PUSH-SORT -- insert an event in (reverse) sorted order ;; ;; Note: Score should NOT have a score-begin-end expression ;; (defun push-sort (event score) (let (insert-after) (cond ((null score) (list event)) ((event-before (car score) event) (cons event score)) (t (setf insert-after score) (while (and (cdr insert-after) (event-before event (cadr insert-after))) (setf insert-after (cdr insert-after))) (setf (cdr insert-after) (cons event (cdr insert-after))) score)))) (setf FOREVER 3600000000.0) ; 1 million hours ;; FIND-LAST-NOTE -- use keywords to find index beyond last selected note ;; ;; note that the :to-index keyword is the index of the last note (numbered ;; from zero), whereas this function returns the index of the last note ;; plus one, i.e. selected notes have an index *less than* this one ;; (defun find-last-note (score to-index to-time) ;; skip past score-begin-end event (let ((s (cdr score)) (n 1)) (setf to-index (if to-index (1+ to-index) (length score))) (setf to-time (if to-time (- to-time SCORE-EPSILON) FOREVER)) (while (and s (< n to-index) (< (event-time (car s)) to-time)) (setf s (cdr s)) (incf n)) n)) ;; SCORE-MUST-HAVE-BEGIN-END -- add score-begin-end event if necessary ;; (defun score-must-have-begin-end (score) (cond ((null score) (list (list 0 0 (list 'SCORE-BEGIN-END 0 0)))) ((eq (car (event-expression (car score))) 'SCORE-BEGIN-END) score) (t (cons (list 0 0 (list 'SCORE-BEGIN-END (event-time (car score)) (event-end (car (last score))))) score)))) ;; SCORE-SHIFT -- add offset to times of score events ;; (defun score-shift (score offset &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((i 1) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) (end (caddr (event-expression (car score)))) result) (dolist (event (cdr score)) (cond ((and (<= start i) (< i stop)) (setf event (event-set-time event (+ (event-time event) offset))) (setf end (max end (event-end event))))) (setf result (push-sort event result)) (incf i)) (cons (list 0 0 (list 'SCORE-BEGIN-END (cadr (event-expression (car score))) end)) (reverse result)))) ;; TIME-STRETCH -- map a timestamp according to stretch factor ;; (defun time-stretch (time stretch start-time stop-time) (cond ((< time start-time) time) ((< time stop-time) (+ start-time (* stretch (- time start-time)))) (t ; beyond stop-time (+ (- time stop-time) ; how much beyond stop-time start-time (* stretch (- stop-time start-time)))))) ;; EVENT-STRETCH -- apply time warp to an event (defun event-stretch (event stretch dur-flag time-flag start-time stop-time) (let* ((new-time (event-time event)) (new-dur (event-dur event)) (end-time (+ new-time new-dur))) (cond (time-flag (setf new-time (time-stretch new-time stretch start-time stop-time)))) (cond ((and time-flag dur-flag) ;; both time and dur are stretched, so map the end time just ;; like the start time, then subtract to get new duration (setf end-time (time-stretch end-time stretch start-time stop-time)) (setf new-dur (- end-time new-time))) ((and dur-flag (>= new-time start-time) (< new-time stop-time)) ;; stretch only duration, not time. If note starts in range ;; scale to get the new duration. (setf new-dur (* stretch new-dur)))) (list new-time new-dur (event-expression event)))) ;; SCORE-STRETCH -- stretch a region of the score ;; (defun score-stretch (score factor &key (dur t) (time t) from-index to-index (from-time 0) (to-time FOREVER)) (setf score (score-must-have-begin-end score)) (let ((begin-end (event-expression (car score))) (i 1)) (if from-index (setf from-time (max from-time (event-time (nth from-index score))))) (if to-index (setf to-time (min to-time (event-end (nth to-index score))))) ; stretch from start-time to stop-time (cons (list 0 0 (list 'SCORE-BEGIN-END (time-stretch (cadr begin-end) factor from-time to-time) (time-stretch (caddr begin-end) factor from-time to-time))) (mapcar #'(lambda (event) (event-stretch event factor dur time from-time to-time)) (cdr score))))) ;; Get the second element of params (the value field) and turn it ;; into a numeric value if possible (by looking up a global variable ;; binding). This allows scores to say C4 instead of 60. ;; (defun get-numeric-value (params) (let ((v (cadr params))) (cond ((and (symbolp v) (boundp v) (numberp (symbol-value v))) (setf v (symbol-value v)))) v)) (defun params-transpose (params keyword amount) (cond ((null params) nil) ((eq keyword (car params)) (let ((v (get-numeric-value params))) (cond ((numberp v) (setf v (+ v amount)))) (cons (car params) (cons v (cddr params))))) (t (cons (car params) (cons (cadr params) (params-transpose (cddr params) keyword amount)))))) (defun score-transpose (score keyword amount &key from-index to-index from-time to-time) (score-apply score #'(lambda (time dur expression) (list time dur (cons (car expression) (params-transpose (cdr expression) keyword amount)))) :from-index from-index :to-index to-index :from-time from-time :to-time to-time)) (defun params-scale (params keyword amount) (cond ((null params) nil) ((eq keyword (car params)) (let ((v (get-numeric-value params))) (cond ((numberp v) (setf v (* v amount)))) (cons (car params) (cons v (cddr params))))) (t (cons (car params) (cons (cadr params) (params-scale (cddr params) keyword amount)))))) (defun score-scale (score keyword amount &key from-index to-index from-time to-time) (score-apply score #'(lambda (time dur expression) (list time dur (cons (car expression) (params-scale (cdr expression) keyword amount)))) :from-index from-index :to-index to-index :from-time from-time :to-time to-time)) (defun score-sustain (score factor &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((i 0) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) result) (dolist (event score) (cond ((and (<= start i) (< i stop)) (setf event (event-set-dur event (* (event-dur event) factor))))) (push event result) (incf i)) (reverse result))) (defun map-voice (expression replacement-list) (let ((mapping (assoc (car expression) replacement-list))) (cond (mapping (cons (second mapping) (cdr expression))) (t expression)))) (defun score-voice (score replacement-list &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((i 0) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) result) (dolist (event score) (cond ((and (<= start i) (< i stop)) (setf event (event-set-expression event (map-voice (event-expression event) replacement-list))))) (push event result) (incf i)) (reverse result))) (defun score-merge (&rest scores) ;; scores is a list of scores (cond ((null scores) nil) (t (score-merge-1 (car scores) (cdr scores))))) ;; SCORE-MERGE-1 -- merge list of scores into score ;; (defun score-merge-1 (score scores) ;; scores is a list of scores to merge (cond ((null scores) score) (t (score-merge-1 (score-merge-2 score (car scores)) (cdr scores))))) ;; SCORE-MERGE-2 -- merge 2 scores ;; (defun score-merge-2 (score addin) ;(display "score-merge-2 before" score addin) (setf score (score-must-have-begin-end score)) (setf addin (score-must-have-begin-end addin)) ;(display "score-merge-2" score addin) (let (start1 start2 end1 end2) (setf start1 (score-get-begin score)) (setf start2 (score-get-begin addin)) (setf end1 (score-get-end score)) (setf end2 (score-get-end addin)) ;; note: score-sort is destructive, but append copies score ;; and score-shift copies addin (score-sort (cons (list 0 0 (list 'SCORE-BEGIN-END (min start1 start2) (max end1 end2))) (append (cdr score) (cdr addin) nil))))) ;; SCORE-APPEND -- append scores together in sequence ;; (defun score-append (&rest scores) ;; scores is a list of scores (cond ((null scores) nil) (t (score-append-1 (car scores) (cdr scores))))) ;; SCORE-APPEND-1 -- append list of scores into score ;; (defun score-append-1 (score scores) ;; scores is a list of scores to append (cond ((null scores) score) (t (score-append-1 (score-append-2 score (car scores)) (cdr scores))))) ;; SCORE-APPEND-2 -- append 2 scores ;; (defun score-append-2 (score addin) ;(display "score-append-2" score addin) (setf score (score-must-have-begin-end score)) (setf addin (score-must-have-begin-end addin)) (let (end1 start2 begin-end1 begin-end2) (setf start1 (score-get-begin score)) (setf end1 (score-get-end score)) (setf start2 (score-get-begin addin)) (setf end2 (score-get-end addin)) (setf begin-end1 (event-expression (car score))) (setf begin-end2 (event-expression (car addin))) (setf addin (score-shift addin (- end1 start2))) ;; note: score-sort is destructive, but append copies score ;; and score-shift copies addin (score-sort (cons (list 0 0 (list 'SCORE-BEGIN-END start1 (+ end1 (- end2 start2)))) (append (cdr score) (cdr addin) nil))))) (defun score-select (score predicate &key from-index to-index from-time to-time reject) (setf score (score-must-have-begin-end score)) (let ((begin-end (car score)) (i 1) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) result) ;; selected if start <= i AND i < stop AND predicate(...) ;; choose if not reject and selected or reject and not selected ;; so in other words choose if reject != selected. Use NULL to ;; coerce into boolean values and then use NOT EQ to compare (dolist (event (cdr score)) (cond ((not (eq (null reject) (null (and (<= start i) (< i stop) (or (eq predicate t) (funcall predicate (event-time event) (event-dur event) (event-expression event))))))) (push event result))) (incf i)) (cons begin-end (reverse result)))) ;; SCORE-FILTER-LENGTH -- remove notes beyond cutoff time ;; (defun score-filter-length (score cutoff) (let (result) (dolist (event score) (cond ((<= (event-end event) cutoff) (push event result)))) (reverse result))) ;; SCORE-REPEAT -- make n copies of score in sequence ;; (defun score-repeat (score n) (let (result) (dotimes (i n) (setf result (score-append result score))) result)) ;; SCORE-STRETCH-TO-LENGTH -- stretch score to have given length ;; (defun score-stretch-to-length (score length) (let ((begin-time (score-get-begin score)) (end-time (score-get-end score)) duration stretch) (setf duration (- end-time begin-time)) (cond ((< 0 duration) (setf stretch (/ length (- end-time begin-time))) (score-stretch score stretch)) (t score)))) (defun score-filter-overlap (score) (setf score (score-must-have-begin-end score)) (prog (event end-time filtered-score (begin-end (car score))) (setf score (cdr score)) (cond ((null score) (return (list begin-end)))) loop ;; get event from score (setf event (car score)) ;; add a note to filtered-score (push event filtered-score) ;; save the end-time of this event: start + duration (setf end-time (+ (car event) (cadr event))) ;; now skip everything until end-time in score loop2 (pop score) ;; move to next event in score (cond ((null score) (return (cons begin-end (reverse filtered-score))))) (setf event (car score)) ;; examine next event (setf start-time (car event)) ;(display "overlap" start-time (- end-time SCORE-EPSILON)) (cond ((< start-time (- end-time SCORE-EPSILON)) ;(display "toss" event start-time end-time) (go loop2))) (go loop))) (defun score-print (score) (format t "(") (dolist (event score) (format t "~S~%" event)) (format t ")~%")) (defun score-play (score) (play (timed-seq score))) (defun score-adjacent-events (score function &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((begin-end (car score)) (a nil) (b (second score)) (c-list (cddr score)) r newscore (i 1) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time))) (dolist (event (cdr score)) (setf r b) (cond ((and (<= start i) (< i stop)) (setf r (funcall function a b (car c-list))))) (cond (r (push r newscore) (setf a r))) (setf b (car c-list)) (setf c-list (cdr c-list)) (incf i)) (score-sort (cons begin-end newscore)))) (defun score-apply (score fn &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((begin-end (car score)) (i 1) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) result) (dolist (event (cdr score)) (push (cond ((and (<= start i) (< i stop)) (funcall fn (event-time event) (event-dur event) (event-expression event))) (t event)) result) (incf i)) (score-sort (cons begin-end result)))) (defun score-indexof (score fn &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((i 1) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) result) (dolist (event (cdr score)) (cond ((and (<= start i) (< i stop) (funcall fn (event-time event) (event-dur event) (event-expression event))) (setf result i) (return))) (incf i)) result)) (defun score-last-indexof (score fn &key from-index to-index from-time to-time) (setf score (score-must-have-begin-end score)) (let ((i 1) (start (find-first-note score from-index from-time)) (stop (find-last-note score to-index to-time)) result) (dolist (event (cdr score)) (cond ((and (<= start i) (< i stop) (funcall fn (event-time event) (event-dur event) (event-expression event))) (setf result i))) (incf i)) result)) ;; SCORE-RANDOMIZE-START -- alter start times with offset ;; keywords: jitter, offset, feel factor ;; (defun score-randomize-start (score amt &key from-index to-index from-time to-time) (score-apply score (lambda (time dur expr) (setf time (+ (real-random (- amt) amt) time)) (setf time (max 0.0 time)) (list time dur expr)))) ;; SCORE-READ-SMF -- read a standard MIDI file to a score ;; (defun score-read-smf (filename) (let ((seq (seq-create)) (file (open-binary filename))) (cond (file (seq-read-smf seq file) (close file) (score-from-seq seq)) (t nil)))) ;; SET-PROGRAM-TO -- a helper function to set a list value (defun set-program-to (lis index value default) ;; if length or lis <= index, extend the lis with default (while (<= (length lis) index) (setf lis (nconc lis (list default)))) ;; set the nth element (setf (nth index lis) value) ;; return the list lis) (defun score-from-seq (seq) (prog (event tag score programs) (seq-reset seq) loop (setf event (seq-get seq)) (setf tag (seq-tag event)) (cond ((= tag seq-done-tag) (go exit)) ((= tag seq-prgm-tag) (let ((chan (seq-channel event)) (when (seq-time event)) (program (seq-program event))) (setf programs (set-program-to programs chan program 0)) (push (list (* when 0.001) 1 (list 'NOTE :pitch nil :program program)) score))) ((= tag seq-note-tag) (let ((chan (seq-channel event)) (pitch (seq-pitch event)) (vel (seq-velocity event)) (when (seq-time event)) (dur (seq-duration event))) (push (list (* when 0.001) (* dur 0.001) (list 'NOTE :chan (1- chan) :pitch pitch :vel vel)) score)))) (seq-next seq) (go loop) exit (setf *rslt* programs) ;; extra return value (return (score-sort score)))) (defun score-write-smf (score filename &optional programs) (let ((file (open-binary filename :direction :output)) (seq (seq-create)) (chan 1)) (cond (file (dolist (program programs) ;; 6 = SEQ_PROGRAM (seq-insert-ctrl seq 0 0 6 chan program) ;(display "insert ctrl" seq 0 0 6 chan program) (incf chan)) (dolist (event (cdr (score-must-have-begin-end score))) (let ((time (event-time event)) (dur (event-dur event)) (chan (event-get-attr event :chan 0)) (pitch (event-get-attr event :pitch)) (program (event-get-attr event :program)) (vel (event-get-attr event :vel 100))) (cond (program ;(display "score-write-smf program" chan program) (seq-insert-ctrl seq (round (* time 1000)) 0 6 (1+ chan) (round program)))) (cond ((consp pitch) (dolist (p pitch) (seq-insert-note seq (round (* time 1000)) 0 (1+ chan) (round p) (round (* dur 1000)) (round vel)))) (pitch (seq-insert-note seq (round (* time 1000)) 0 (1+ chan) (round pitch) (round (* dur 1000)) (round vel)))))) (seq-write-smf seq file) (close file))))) ;; make a default note function for scores ;; (defun note (&key (pitch 60) (vel 100)) ;; load the piano if it is not loaded already (if (not (boundp '*piano-srate*)) (abs-env (load "pianosyn"))) (piano-note-2 pitch vel)) ;;================================================================ ;; WORKSPACE functions have moved to envelopes.lsp ;; DESCRIBE -- add a description to a global variable ;; (defun describe (symbol &optional description) (add-to-workspace symbol) (cond (description (putprop symbol description 'description)) (t (get symbol 'description)))) ;; INTERPOLATE -- linear interpolation function ;; ;; compute y given x by interpolating between points (x1, y1) and (x2, y2) (defun interpolate (x x1 y1 x2 y2) (cond ((= x1 x2) x1) (t (+ y1 (* (- x x1) (/ (- y2 y1) (- x2 (float x1)))))))) ;; INTERSECTION -- set intersection ;; ;; compute the intersection of two lists (defun intersection (a b) (let (result) (dolist (elem a) (if (member elem b) (push elem result))) result)) ;; UNION -- set union ;; ;; compute the union of two lists (defun union (a b) (let (result) (dolist (elem a) (if (not (member elem result)) (push elem result))) (dolist (elem b) (if (not (member elem result)) (push elem result))) result)) ;; SET-DIFFERENCE -- set difference ;; ;; compute the set difference between two sets (defun set-difference (a b) (remove-if (lambda (elem) (member elem b)) a)) ;; SUBSETP -- test is list is subset ;; ;; test if a is subset of b (defun subsetp (a b) (let ((result t)) (dolist (elem a) (cond ((not (member elem b)) (setf result nil) (return nil)))) result)) ;; functions to support score editing in jNyqIDE (if (not (boundp '*default-score-file*)) (setf *default-score-file* "score.dat")) ;; SCORE-EDIT -- save a score for editing by jNyqIDE ;; ;; file goes to a data file to be read by jNyqIDE ;; Note that the parameter is a global variable name, not a score, ;; but you do not quote the global variable name, e.g. call ;; (score-edit my-score) ;; (defmacro score-edit (score-name) `(score-edit-symbol (quote ,score-name))) (defun score-edit-symbol (score-name) (prog ((f (open *default-score-file* :direction :output)) score expr) (cond ((symbolp score-name) (setf score (eval score-name))) (t (error "score-edit expects a symbol naming the score to edit"))) (cond ((null f) (format t "score-edit: error in output file ~A!~%" *default-score-file*) (return nil))) (format t "score-edit: writing ~A ...~%" *default-score-file*) (format f "~A~%" score-name) ; put name on first line (dolist (event score) ;cdr scor (format f "~A " (event-time event)) ; print start time (format f "~A " (event-dur event)) ; print duration (setf expr (event-expression event)) ; print the pitch and the rest of the attributes (format f "~A " (expr-get-attr expr :pitch)) (format f "~A~%" (expr-parameters-remove-attr expr :pitch))) (close f) (format t "score-edit: wrote ~A events~%" (length score)))) ;; Read in a data file stored in the score-edit format and save ;; it to the global variable it came from (defun score-restore () (prog ((inf (open *default-score-file*)) name start dur pitch expr score) (cond ((null inf) (format t "score-restore: could not open ~A~%" *default-score-file*) (return nil))) (setf name (read inf)) ;; score name (loop (setf start (read inf)) (cond ((null start) (return))) (setf dur (read inf)) (setf pitch (read inf)) (setf expr (read inf)) (cond (pitch (setf expr (expr-set-attr expr :pitch pitch))))) (close inf) (setf (symbol-value name) score))) nyquist-3.05/runtime/seqfnint.lsp0000644000175000000620000000156710144436365016234 0ustar stevestaff (setfn seq-tag first) (setfn seq-time second) (setfn seq-line third) (setfn seq-channel fourth) (defun seq-value1 (e) (nth 4 e)) (setfn seq-pitch seq-value1) ; pitch of a note (setfn seq-control seq-value1) ; control number of a control change (setfn seq-program seq-value1) ; program number of a program change (setfn seq-bend seq-value1) ; pitch bend amount (setfn seq-touch seq-value1) ; aftertouch amount (defun seq-value2 (e) (nth 5 e)) (setfn seq-velocity seq-value2) ; velocity of a note (setfn seq-value seq-value2) ; value of a control change (defun seq-duration (e) (nth 6 e)) (setf seq-done-tag 0) (setf seq-other-tag 1) (setf seq-note-tag 2) (setf seq-ctrl-tag 3) (setf seq-prgm-tag 4) (setf seq-touch-tag 5) (setf seq-bend-tag 6) nyquist-3.05/runtime/dspprims.lsp0000644000175000000620000004317011466723256016250 0ustar stevestaff;; dspprims.lsp -- interface to dsp primitives ;; ARESON - notch filter ;; (defun areson (s c b &optional (n 0)) (multichan-expand #'nyq:areson s c b n)) (setf areson-implementations (vector #'snd-areson #'snd-aresonvc #'snd-aresoncv #'snd-aresonvv)) ;; NYQ:ARESON - notch filter, single channel ;; (defun nyq:areson (signal center bandwidth normalize) (select-implementation-1-2 areson-implementations signal center bandwidth normalize)) ;; hp - highpass filter ;; (defun hp (s c) (multichan-expand #'nyq:hp s c)) (setf hp-implementations (vector #'snd-atone #'snd-atonev)) ;; NYQ:hp - highpass filter, single channel ;; (defun nyq:hp (s c) (select-implementation-1-1 hp-implementations s c)) ;; comb-delay-from-hz -- compute the delay argument ;; (defun comb-delay-from-hz (hz caller) (recip hz)) ;; comb-feedback-from-decay -- compute the feedback argument ;; (defun comb-feedback (decay delay) (s-exp (mult -6.9087 delay (recip decay)))) ;; COMB - comb filter ;; ;; this is just a feedback-delay with different arguments ;; (defun comb (snd decay hz) (multichan-expand #'nyq:comb snd decay hz)) (defun nyq:comb (snd decay hz) (let (delay feedback len d) ; convert decay to feedback, iterate over array if necessary (setf delay (comb-delay-from-hz hz "comb")) (setf feedback (comb-feedback decay delay)) (nyq:feedback-delay snd delay feedback))) ;; ALPASS - all-pass filter ;; (defun alpass (snd decay hz &optional min-hz) (multichan-expand #'nyq:alpass snd decay hz min-hz)) (defun nyq:alpass (snd decay hz min-hz) (let (delay feedback len d) ; convert decay to feedback, iterate over array if necessary (setf delay (comb-delay-from-hz hz "alpass")) (setf feedback (comb-feedback decay delay)) (nyq:alpass1 snd delay feedback min-hz))) ;; CONST -- a constant at control-srate ;; (defun const (value &optional (dur 1.0)) (let ((d (get-duration dur))) (snd-const value *rslt* *CONTROL-SRATE* d))) ;; CONVOLVE - slow convolution ;; (defun convolve (s r) (multichan-expand #'snd-convolve s r)) ;; FEEDBACK-DELAY -- (delay is quantized to sample period) ;; (defun feedback-delay (snd delay feedback) (multichan-expand #'nyq:feedback-delay snd delay feedback)) ;; SND-DELAY-ERROR -- report type error ;; (defun snd-delay-error (snd delay feedback) (error "feedback-delay with variable delay is not implemented")) ;; NYQ::DELAYCV -- coerce sample rates and call snd-delaycv ;; (defun nyq:delaycv (the-snd delay feedback) (display "delaycv" the-snd delay feedback) (let ((the-snd-srate (snd-srate the-snd)) (feedback-srate (snd-srate feedback))) (cond ((> the-snd-srate feedback-srate) (setf feedback (snd-up the-snd-srate feedback))) ((< the-snd-srate feedback-srate) (format t "Warning: down-sampling feedback in feedback-delay/comb~%") (setf feedback (snd-down the-snd-srate feedback)))) (snd-delaycv the-snd delay feedback))) (setf feedback-delay-implementations (vector #'snd-delay #'snd-delay-error #'nyq:delaycv #'snd-delay-error)) ;; NYQ:FEEDBACK-DELAY -- single channel delay ;; (defun nyq:feedback-delay (snd delay feedback) (select-implementation-1-2 feedback-delay-implementations snd delay feedback)) ;; SND-ALPASS-ERROR -- report type error ;; (defun snd-alpass-error (snd delay feedback) (error "alpass with constant decay and variable hz is not implemented")) (if (not (fboundp 'snd-alpasscv)) (defun snd-alpasscv (snd delay feedback min-hz) (error "snd-alpasscv (ALPASS with variable decay) is not implemented"))) (if (not (fboundp 'snd-alpassvv)) (defun snd-alpassvv (snd delay feedback min-hz) (error "snd-alpassvv (ALPASS with variable decay and feedback) is not implemented"))) (defun snd-alpass-4 (snd delay feedback min-hz) (snd-alpass snd delay feedback)) (defun snd-alpasscv-4 (the-snd delay feedback min-hz) (display "snd-alpasscv-4" (snd-srate the-snd) (snd-srate feedback)) (let ((the-snd-srate (snd-srate the-snd)) (feedback-srate (snd-srate feedback))) (cond ((> the-snd-srate feedback-srate) (setf feedback (snd-up the-snd-srate feedback))) ((< the-snd-srate feedback-srate) (format t "Warning: down-sampling feedback in alpass~%") (setf feedback (snd-down the-snd-srate feedback)))) ;(display "snd-alpasscv-4 after cond" (snd-srate the-snd) (snd-srate feedback)) (snd-alpasscv the-snd delay feedback))) (defun snd-alpassvv-4 (the-snd delay feedback min-hz) ;(display "snd-alpassvv-4" (snd-srate the-snd) (snd-srate feedback)) (let ((the-snd-srate (snd-srate the-snd)) (delay-srate (snd-srate delay)) (feedback-srate (snd-srate feedback)) max-delay) (cond ((or (not (numberp min-hz)) (<= min-hz 0)) (error "alpass needs numeric (>0) 4th parameter (min-hz) when delay is variable"))) (setf max-delay (/ 1.0 min-hz)) ; make sure delay is between 0 and max-delay ; use clip function, which is symetric, with an offset (setf delay (snd-offset (clip (snd-offset delay (* max-delay -0.5)) (* max-delay 0.5)) (* max-delay 0.5))) ; now delay is between 0 and max-delay, so we won't crash nyquist when ; we call snd-alpassvv, which doesn't test for out-of-range data (cond ((> the-snd-srate feedback-srate) (setf feedback (snd-up the-snd-srate feedback))) ((< the-snd-srate feedback-srate) (format t "Warning: down-sampling feedback in alpass~%") (setf feedback (snd-down the-snd-srate feedback)))) (cond ((> the-snd-srate delay-srate) (setf delay (snd-up the-snd-srate delay))) ((< the-snd-srate delay-srate) (format t "Warning: down-sampling delay in alpass~%") (setf delay (snd-down the-snd-srate delay)))) (display "snd-alpassvv-4 after cond" (snd-srate the-snd) (snd-srate feedback)) (snd-alpassvv the-snd delay feedback max-delay))) (setf alpass-implementations (vector #'snd-alpass-4 #'snd-alpass-error #'snd-alpasscv-4 #'snd-alpassvv-4)) ;; NYQ:ALPASS1 -- single channel alpass ;; (defun nyq:alpass1 (snd delay feedback min-hz) (select-implementation-1-2 alpass-implementations snd delay feedback min-hz)) ;; CONGEN -- contour generator, patterned after gated analog env gen ;; (defun congen (gate rise fall) (multichan-expand #'snd-congen gate rise fall)) ;; S-EXP -- exponentiate a sound ;; (defun s-exp (s) (multichan-expand #'nyq:exp s)) ;; NYQ:EXP -- exponentiate number or sound ;; (defun nyq:exp (s) (if (soundp s) (snd-exp s) (exp s))) ;; S-ABS -- absolute value of a sound ;; (defun s-abs (s) (multichan-expand #'nyq:abs s)) ;; NYQ:ABS -- absolute value of number or sound ;; (defun nyq:abs (s) (if (soundp s) (snd-abs s) (abs s))) ;; S-SQRT -- square root of a sound ;; (defun s-sqrt (s) (multichan-expand #'nyq:sqrt s)) ;; NYQ:SQRT -- square root of a number or sound ;; (defun nyq:sqrt (s) (if (soundp s) (snd-sqrt s) (sqrt s))) ;; INTEGRATE -- integration ;; (defun integrate (s) (multichan-expand #'snd-integrate s)) ;; S-LOG -- natural log of a sound ;; (defun s-log (s) (multichan-expand #'nyq:log s)) ;; NYQ:LOG -- log of a number or sound ;; (defun nyq:log (s) (if (soundp s) (snd-log s) (log s))) ;; NOISE -- white noise ;; (defun noise (&optional (dur 1.0)) (let ((d (get-duration dur))) (snd-white *rslt* *SOUND-SRATE* d))) (defun noise-gate (snd &optional (lookahead 0.5) (risetime 0.02) (falltime 0.5) (floor 0.01) (threshold 0.01)) (let ((rms (lp (mult snd snd) (/ *control-srate* 10.0)))) (setf threshold (* threshold threshold)) (mult snd (gate rms floor risetime falltime lookahead threshold)))) ;; QUANTIZE -- quantize a sound ;; (defun quantize (s f) (multichan-expand #'snd-quantize s f)) ;; RECIP -- reciprocal of a sound ;; (defun recip (s) (multichan-expand #'nyq:recip s)) ;; NYQ:RECIP -- reciprocal of a number or sound ;; (defun nyq:recip (s) (if (soundp s) (snd-recip s) (/ (float s)))) ;; RMS -- compute the RMS of a sound ;; (defun rms (s &optional (rate 100.0) window-size) (let (rslt step-size) (cond ((not (eq (type-of s) 'SOUND)) (break "in RMS, first parameter must be a monophonic SOUND"))) (setf step-size (round (/ (snd-srate s) rate))) (cond ((null window-size) (setf window-size step-size))) (setf s (prod s s)) (setf result (snd-avg s window-size step-size OP-AVERAGE)) ;; compute square root of average (s-exp (scale 0.5 (s-log result))))) ;; RESON - bandpass filter ;; (defun reson (s c b &optional (n 0)) (multichan-expand #'nyq:reson s c b n)) (setf reson-implementations (vector #'snd-reson #'snd-resonvc #'snd-resoncv #'snd-resonvv)) ;; NYQ:RESON - bandpass filter, single channel ;; (defun nyq:reson (signal center bandwidth normalize) (select-implementation-1-2 reson-implementations signal center bandwidth normalize)) ;; SHAPE -- waveshaper ;; (defun shape (snd shape origin) (multichan-expand #'snd-shape snd shape origin)) ;; SLOPE -- calculate the first derivative of a signal ;; (defun slope (s) (multichan-expand #'nyq:slope s)) ;; NYQ:SLOPE -- first derivative of single channel ;; (defun nyq:slope (s) (let* ((sr (snd-srate s)) (sr-inverse (/ sr))) (snd-xform (snd-slope s) sr 0 sr-inverse MAX-STOP-TIME 1.0))) ;; lp - lowpass filter ;; (defun lp (s c) (multichan-expand #'nyq:lp s c)) (setf lp-implementations (vector #'snd-tone #'snd-tonev)) ;; NYQ:lp - lowpass filter, single channel ;; (defun nyq:lp (s c) (select-implementation-1-1 lp-implementations s c)) ;;; fixed-parameter filters based on snd-biquad ;;; note: snd-biquad is implemented in biquadfilt.[ch], ;;; while BiQuad.{cpp,h} is part of STK (setf Pi 3.14159265358979) (defun square (x) (* x x)) (defun sinh (x) (* 0.5 (- (exp x) (exp (- x))))) ; remember that snd-biquad uses the opposite sign convention for a_i's ; than Matlab does. ; convenient biquad: normalize a0, and use zero initial conditions. (defun nyq:biquad (x b0 b1 b2 a0 a1 a2) (let ((a0r (/ 1.0 a0))) (snd-biquad x (* a0r b0) (* a0r b1) (* a0r b2) (* a0r a1) (* a0r a2) 0 0))) (defun biquad (x b0 b1 b2 a0 a1 a2) (multichan-expand #'nyq:biquad x b0 b1 b2 a0 a1 a2)) ; biquad with Matlab sign conventions for a_i's. (defun biquad-m (x b0 b1 b2 a0 a1 a2) (multichan-expand #'nyq:biquad-m x b0 b1 b2 a0 a1 a2)) (defun nyq:biquad-m (x b0 b1 b2 a0 a1 a2) (nyq:biquad x b0 b1 b2 a0 (- a1) (- a2))) ; two-pole lowpass (defun lowpass2 (x hz &optional (q 0.7071)) (multichan-expand #'nyq:lowpass2 x hz q)) ;; NYQ:LOWPASS2 -- operates on single channel (defun nyq:lowpass2 (x hz q) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (cw (cos w)) (sw (sin w)) (alpha (* sw (sinh (/ 0.5 q)))) (a0 (+ 1.0 alpha)) (a1 (* -2.0 cw)) (a2 (- 1.0 alpha)) (b1 (- 1.0 cw)) (b0 (* 0.5 b1)) (b2 b0)) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) ; two-pole highpass (defun highpass2 (x hz &optional (q 0.7071)) (multichan-expand #'nyq:highpass2 x hz q)) (defun nyq:highpass2 (x hz q) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (cw (cos w)) (sw (sin w)) (alpha (* sw (sinh (/ 0.5 q)))) (a0 (+ 1.0 alpha)) (a1 (* -2.0 cw)) (a2 (- 1.0 alpha)) (b1 (- -1.0 cw)) (b0 (* -0.5 b1)) (b2 b0)) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) ; two-pole bandpass. max gain is unity. (defun bandpass2 (x hz q) (multichan-expand #'nyq:bandpass2 x hz q)) (defun nyq:bandpass2 (x hz q) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (cw (cos w)) (sw (sin w)) (alpha (* sw (sinh (/ 0.5 q)))) (a0 (+ 1.0 alpha)) (a1 (* -2.0 cw)) (a2 (- 1.0 alpha)) (b0 alpha) (b1 0.0) (b2 (- alpha))) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) ; two-pole notch. (defun notch2 (x hz q) (multichan-expand #'nyq:notch2 x hz q)) (defun nyq:notch2 (x hz q) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (cw (cos w)) (sw (sin w)) (alpha (* sw (sinh (/ 0.5 q)))) (a0 (+ 1.0 alpha)) (a1 (* -2.0 cw)) (a2 (- 1.0 alpha)) (b0 1.0) (b1 (* -2.0 cw)) (b2 1.0)) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) ; two-pole allpass. (defun allpass2 (x hz q) (multichan-expand #'nyq:allpass x hz q)) (defun nyq:allpass (x hz q) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (cw (cos w)) (sw (sin w)) (k (exp (* -0.5 w (/ 1.0 q)))) (a0 1.0) (a1 (* -2.0 cw k)) (a2 (* k k)) (b0 a2) (b1 a1) (b2 1.0)) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) ; bass shelving EQ. gain in dB; Fc is halfway point. ; response becomes peaky at slope > 1. (defun eq-lowshelf (x hz gain &optional (slope 1.0)) (multichan-expand #'nyq:eq-lowshelf x hz gain slope)) (defun nyq:eq-lowshelf (x hz gain slope) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (sw (sin w)) (cw (cos w)) (A (expt 10.0 (/ gain (* 2.0 20.0)))) (b (sqrt (- (/ (+ 1.0 (square A)) slope) (square (- A 1.0))))) (apc (* cw (+ A 1.0))) (amc (* cw (- A 1.0))) (bs (* b sw)) (b0 (* A (+ A 1.0 (- amc) bs ))) (b1 (* 2.0 A (+ A -1.0 (- apc) ))) (b2 (* A (+ A 1.0 (- amc) (- bs) ))) (a0 (+ A 1.0 amc bs )) (a1 (* -2.0 (+ A -1.0 apc ))) (a2 (+ A 1.0 amc (- bs) ))) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) ; treble shelving EQ. gain in dB; Fc is halfway point. ; response becomes peaky at slope > 1. (defun eq-highshelf (x hz gain &optional (slope 1.0)) (multichan-expand #'nyq:eq-highshelf x hz gain slope)) (defun nyq:eq-highshelf (x hz gain slope) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (sw (sin w)) (cw (cos w)) (A (expt 10.0 (/ gain (* 2.0 20.0)))) (b (sqrt (- (/ (+ 1.0 (square A)) slope) (square (- A 1.0))))) (apc (* cw (+ A 1.0))) (amc (* cw (- A 1.0))) (bs (* b sw)) (b0 (* A (+ A 1.0 amc bs ))) (b1 (* -2.0 A (+ A -1.0 apc ))) (b2 (* A (+ A 1.0 amc (- bs) ))) (a0 (+ A 1.0 (- amc) bs )) (a1 (* 2.0 (+ A -1.0 (- apc) ))) (a2 (+ A 1.0 (- amc) (- bs) ))) (nyq:biquad-m x b0 b1 b2 a0 a1 a2))) (defun nyq:eq-band (x hz gain width) (cond ((and (numberp hz) (numberp gain) (numberp width)) (eq-band-ccc x hz gain width)) ((and (soundp hz) (soundp gain) (soundp width)) (snd-eqbandvvv x hz (db-to-linear gain) width)) (t (error "eq-band hz, gain, and width must be all numbers or all sounds")))) ; midrange EQ. gain in dB, width in octaves (half-gain width). (defun eq-band (x hz gain width) (multichan-expand #'nyq:eq-band x hz gain width)) (defun eq-band-ccc (x hz gain width) (let* ((w (* 2.0 Pi (/ hz (snd-srate x)))) (sw (sin w)) (cw (cos w)) (J (sqrt (expt 10.0 (/ gain 20.0)))) ;(dummy (display "eq-band-ccc" gain J)) (g (* sw (sinh (* 0.5 (log 2.0) width (/ w sw))))) ;(dummy2 (display "eq-band-ccc" width w sw g)) (b0 (+ 1.0 (* g J))) (b1 (* -2.0 cw)) (b2 (- 1.0 (* g J))) (a0 (+ 1.0 (/ g J))) (a1 (- b1)) (a2 (- (/ g J) 1.0))) (biquad x b0 b1 b2 a0 a1 a2))) ; see failed attempt in eub-reject.lsp to do these with higher-order fns: ; four-pole Butterworth lowpass (defun lowpass4 (x hz) (lowpass2 (lowpass2 x hz 0.60492333) hz 1.33722126)) ; six-pole Butterworth lowpass (defun lowpass6 (x hz) (lowpass2 (lowpass2 (lowpass2 x hz 0.58338080) hz 0.75932572) hz 1.95302407)) ; eight-pole Butterworth lowpass (defun lowpass8 (x hz) (lowpass2 (lowpass2 (lowpass2 (lowpass2 x hz 0.57622191) hz 0.66045510) hz 0.94276399) hz 2.57900101)) ; four-pole Butterworth highpass (defun highpass4 (x hz) (highpass2 (highpass2 x hz 0.60492333) hz 1.33722126)) ; six-pole Butterworth highpass (defun highpass6 (x hz) (highpass2 (highpass2 (highpass2 x hz 0.58338080) hz 0.75932572) hz 1.95302407)) ; eight-pole Butterworth highpass (defun highpass8 (x hz) (highpass2 (highpass2 (highpass2 (highpass2 x hz 0.57622191) hz 0.66045510) hz 0.94276399) hz 2.57900101)) ; YIN ; maybe this should handle multiple channels, etc. (setfn yin snd-yin) ; FOLLOW (defun follow (sound floor risetime falltime lookahead) ;; use 10000s as "infinite" -- that's about 2^30 samples at 96K (setf lookahead (round (* lookahead (snd-srate sound)))) (extract (/ lookahead (snd-srate sound)) 10000 (snd-follow sound floor risetime falltime lookahead))) ; Note: gate implementation moved to nyquist.lsp ;(defun gate (sound floor risetime falltime lookahead threshold) ; (setf lookahead (round (* lookahead (snd-srate sound)))) ; (setf lookahead (/ lookahead (snd-srate sound))) ; (extract lookahead 10000 ; (snd-gate sound lookahead risetime falltime floor threshold))) nyquist-3.05/runtime/upic.sal0000644000175000000620000000253411537224066015321 0ustar stevestaff;; upic.sal -- play upic data ;; define function upic(data) begin if data then ;; use reverse to make a copy of data since sort is destructive return upic-curve(sort(reverse(data), quote(upic-compare))) else return s-rest() end define function upic-compare(a, b) return third(a) < third(b) define function upic-curve(data) begin with curve = first(data), waveform = first(curve), envelope = second(curve), points = cddr(curve), from-time = first(points), to-time = nth(length(points) - 2, points), dur = to-time - from-time, next = rest(data), next-start, snd ;; shift curve to start at t = 0 loop with relpoints while points set relpoints @= first(points) - from-time set relpoints @= second(points) set points = cddr(points) finally set points = cdr(reverse(relpoints)) end set snd = hzosc(pwlv-list(points), symbol-value(waveform)) * (funcall(envelope) ~ dur) if next then begin set next-start = third(first(next)) ;; display "curve", from-time, dur set snd = seq(set-logical-stop(snd, next-start - from-time), upic-curve(next)) end return snd end define function upic-env() return env(0.01, 0.01, 0.01, 1, 1, 1) nyquist-3.05/runtime/sndfnint.lsp0000644000175000000620000000221411466723256016224 0ustar stevestaff (setf snd-head-none 0) (setf snd-head-AIFF 1) (setf snd-head-IRCAM 2) (setf snd-head-NeXT 3) (setf snd-head-Wave 4) (setf snd-head-PAF 5) (setf snd-head-SVX 6) (setf snd-head-NIST 7) (setf snd-head-VOC 8) (setf snd-head-W64 9) (setf snd-head-MAT4 10) (setf snd-head-MAT5 11) (setf snd-head-PVF 12) (setf snd-head-XI 13) (setf snd-head-HTK 14) (setf snd-head-SDS 15) (setf snd-head-AVR 16) (setf snd-head-SD2 17) (setf snd-head-FLAC 18) (setf snd-head-CAF 19) (setf snd-head-raw 20) (setf snd-head-channels 1) (setf snd-head-mode 2) (setf snd-head-bits 4) (setf snd-head-srate 8) (setf snd-head-dur 16) (setf snd-head-latency 32) (setf snd-head-type 64) (setf snd-mode-adpcm 0) (setf snd-mode-pcm 1) (setf snd-mode-ulaw 2) (setf snd-mode-alaw 3) (setf snd-mode-float 4) (setf snd-mode-upcm 5) (setf snd-mode-unknown 6) (setf snd-mode-double 7) (setf snd-mode-GSM610 8) (setf snd-mode-DWVW 9) (setf snd-mode-DPCM 10) (setf snd-mode-msadpcm 11) (SETF MAX-STOP-TIME 10E20) (SETF MIN-START-TIME -10E20) (setf OP-AVERAGE 1) (setf OP-PEAK 2) nyquist-3.05/runtime/seq.lsp0000644000175000000620000002464511466723256015205 0ustar stevestaff;; seq.lsp -- sequence control constructs for Nyquist ;; get-srates -- this either returns the sample rate of a sound or a ;; vector of sample rates of a vector of sounds ;; (defun get-srates (sounds) (cond ((arrayp sounds) (let ((result (make-array (length sounds)))) (dotimes (i (length sounds)) (setf (aref result i) (snd-srate (aref sounds i)))) result)) (t (snd-srate sounds)))) ; These are complex macros that implement sequences of various types. ; The complexity is due to the fact that a behavior within a sequence ; can reference the environment, e.g. (let ((p 60)) (seq (osc p) (osc p))) ; is an example where p must be in the environment of each member of ; the sequence. Since the execution of the sequence elements are delayed, ; the environment must be captured and then used later. In XLISP, the ; EVAL function does not execute in the current environment, so a special ; EVAL, EVALHOOK must be used to evaluate with an environment. Another ; feature of XLISP (see evalenv.lsp) is used to capture the environment ; when the seq is first evaluated, so that the environment can be used ; later. Finally, it is also necessary to save the current transformation ; environment until later. (defmacro seq (&rest list) (cond ((null list) (snd-zero (warp-time *WARP*) *sound-srate*)) ((null (cdr list)) (car list)) ((null (cddr list)) ; (format t "SEQ with 2 behaviors: ~A~%" list) `(let* ((first%sound ,(car list)) (s%rate (get-srates first%sound))) (cond ((arrayp first%sound) (snd-multiseq (prog1 first%sound (setf first%sound nil)) #'(lambda (t0) (format t "MULTISEQ's 2nd behavior: ~A~%" ',(cadr list)) (with%environment ',(nyq:the-environment) ; (display "MULTISEQ 1" t0) (at-abs t0 (force-srates s%rate ,(cadr list))))))) (t ; allow gc of first%sound: (snd-seq (prog1 first%sound (setf first%sound nil)) #'(lambda (t0) ; (format t "SEQ's 2nd behavior: ~A~%" ',(cadr list)) (with%environment ',(nyq:the-environment) (at-abs t0 (force-srate s%rate ,(cadr list)))))))))) (t `(let* ((nyq%environment (nyq:the-environment)) (first%sound ,(car list)) (s%rate (get-srates first%sound)) (seq%environment (getenv))) (cond ((arrayp first%sound) ; (print "calling snd-multiseq") (snd-multiseq (prog1 first%sound (setf first%sound nil)) #'(lambda (t0) (multiseq-iterate ,(cdr list))))) (t ; (print "calling snd-seq") ; allow gc of first%sound: (snd-seq (prog1 first%sound (setf first%sound nil)) #'(lambda (t0) (seq-iterate ,(cdr list)))))))))) (defun envdepth (e) (length (car e))) (defmacro myosd (pitch) `(let () (format t "myosc env depth is ~A~%" (envdepth (getenv))) (osc ,pitch))) (defmacro seq-iterate (behavior-list) (cond ((null (cdr behavior-list)) `(eval-seq-behavior ,(car behavior-list))) (t `(snd-seq (eval-seq-behavior ,(car behavior-list)) (evalhook '#'(lambda (t0) ; (format t "lambda depth ~A~%" (envdepth (getenv))) (seq-iterate ,(cdr behavior-list))) nil nil seq%environment))))) (defmacro multiseq-iterate (behavior-list) (cond ((null (cdr behavior-list)) `(eval-multiseq-behavior ,(car behavior-list))) (t `(snd-multiseq (eval-multiseq-behavior ,(car behavior-list)) (evalhook '#'(lambda (t0) ; (format t "lambda depth ~A~%" (envdepth (getenv))) (multiseq-iterate ,(cdr behavior-list))) nil nil seq%environment))))) (defmacro eval-seq-behavior (beh) `(with%environment nyq%environment (at-abs t0 (force-srate s%rate ,beh)))) (defmacro eval-multiseq-behavior (beh) `(with%environment nyq%environment ; (display "MULTISEQ 2" t0) (at-abs t0 (force-srates s%rate ,beh)))) (defmacro with%environment (env &rest expr) `(progv ',*environment-variables* ,env ,@expr)) (defmacro seqrep (pair sound) `(let ((,(car pair) 0) (loop%count ,(cadr pair)) (nyq%environment (nyq:the-environment)) seqrep%closure first%sound s%rate) ; note: s%rate will tell whether we want a single or multichannel ; sound, and what the sample rates should be. (cond ((not (integerp loop%count)) (error "bad argument type" loop%count)) (t (setf seqrep%closure #'(lambda (t0) ; (display "SEQREP" loop%count ,(car pair)) (cond ((< ,(car pair) loop%count) (setf first%sound (with%environment nyq%environment (at-abs t0 ,sound))) ; (display "seqrep" s%rate nyq%environment ,(car pair) ; loop%count) (if s%rate (setf first%sound (force-srates s%rate first%sound)) (setf s%rate (get-srates first%sound))) (setf ,(car pair) (1+ ,(car pair))) ; note the following test is AFTER the counter increment (cond ((= ,(car pair) loop%count) ; (display "seqrep: computed the last sound at" ; ,(car pair) loop%count ; (local-to-global 0)) first%sound) ;last sound ((arrayp s%rate) ; (display "seqrep: calling snd-multiseq at" ; ,(car pair) loop%count (local-to-global 0) ; (snd-t0 (aref first%sound 0))) (snd-multiseq (prog1 first%sound (setf first%sound nil)) seqrep%closure)) (t ; (display "seqrep: calling snd-seq at" ; ,(car pair) loop%count (local-to-global 0) ; (snd-t0 first%sound)) (snd-seq (prog1 first%sound (setf first%sound nil)) seqrep%closure)))) (t (snd-zero (warp-time *WARP*) *sound-srate*))))) (funcall seqrep%closure (local-to-global 0)))))) (defmacro trigger (input beh) `(let ((nyq%environment (nyq:the-environment))) (snd-trigger ,input #'(lambda (t0) (with%environment nyq%environment (at-abs t0 ,beh)))))) ;; EVENT-EXPRESSION -- the sound of the event ;; (setfn event-expression caddr) ;; EVENT-HAS-ATTR -- test if event has attribute ;; (defun event-has-attr (note attr) (expr-has-attr (event-expression note))) ;; EXPR-SET-ATTR -- new expression with attribute = value ;; (defun expr-set-attr (expr attr value) (cons (car expr) (list-set-attr-value (cdr expr) attr value))) (defun list-set-attr-value (lis attr value) (cond ((null lis) (list attr value)) ((eq (car lis) attr) (cons attr (cons value (cddr lis)))) (t (cons (car lis) (cons (cadr lis) (list-set-attr-value (cddr lis) attr value)))))) ;; EXPAND-AND-EVAL-EXPR -- evaluate a note, chord, or rest for timed-seq ;; (defun expand-and-eval-expr (expr) (let ((pitch (member :pitch expr))) (cond ((and pitch (cdr pitch) (listp (cadr pitch))) (setf pitch (cadr pitch)) (simrep (i (length pitch)) (eval (expr-set-attr expr :pitch (nth i pitch))))) (t (eval expr))))) ;; (timed-seq '((time1 stretch1 expr1) (time2 stretch2 expr2) ...)) ;; a timed-seq takes a list of events as shown above ;; it sums the behaviors, similar to ;; (sim (at time1 (stretch stretch1 expr1)) ...) ;; but the implementation avoids starting all expressions at once ;; ;; Notes: (1) the times must be in increasing order ;; (2) EVAL is used on each event, so events cannot refer to parameters ;; or local variables ;; (defun timed-seq (score) ; check to insure that times are strictly increasing and >= 0 and stretches are >= 0 (let ((start-time 0) error-msg) (dolist (event score) (cond ((< (car event) start-time) (error (format nil "Out-of-order time in TIMED-SEQ: ~A" event))) ((< (cadr event) 0) (error (format nil "Negative stretch factor in TIMED-SEQ: ~A" event))) (t (setf start-time (car event))))) ;; remove rests (a rest has a :pitch attribute of nil) (setf score (score-select score #'(lambda (tim dur evt) (expr-get-attr evt :pitch t)))) (cond ((and score (car score) (eq (car (event-expression (car score))) 'score-begin-end)) (setf score (cdr score)))) ; skip score-begin-end data ; (score-print score) ;; debugging (cond ((null score) (s-rest 0)) (t (at (caar score) (seqrep (i (length score)) (cond ((cdr score) (let (event) (prog1 (set-logical-stop (stretch (cadar score) (setf event (expand-and-eval-expr (caddar score)))) (- (caadr score) (caar score))) ;(display "timed-seq" (caddar score) ; (local-to-global 0) ; (snd-t0 event) ; (- (caadr score) ; (caar score))) (setf score (cdr score))))) (t (stretch (cadar score) (expand-and-eval-expr (caddar score))))))))))) nyquist-3.05/runtime/evalenv.lsp0000644000175000000620000000253710144436365016043 0ustar stevestaff;; ;; The EVAL function in the original XLISP evaluated in the current lexical ;; context. This was changed to evaluate in the NIL (global) context to ;; match Common Lisp. But this created a problem: how do you EVAL an ;; expression in the current lexical context? ;; ;; The answer is you can use the evalhook facility. The evalhook function ;; will evaluate an expression using an environment given to it as an ;; argument. But then the problem is "how do you get the current ;; environment?" Well the getenv macro, below obtains the environent by ;; using an *evalhook* form. ;; ;; The following two macros do the job. Insteading of executing (eval ) ;; just execute (eval-env ). If you want, you can dispense with the ;; macros and execute: ;; ;;(evalhook nil nil (let ((*evalhook* (lambda (x env) env))) ;; (eval nil))) ;; ;; Tom Almy 10/91 ;; (defmacro getenv () '(progv '(*evalhook*) (list #'(lambda (exp env) env)) (eval nil))) ; this didn't work, may be for a later (Almy) version of xlisp? ;(defmacro getenv () ; '(let ((*evalhook* (lambda (x env) env))) ; (eval nil))) ; hook function evaluates by returning ; environment (defmacro eval-env (arg) ; evaluate in current environment `(evalhook ,arg nil nil (getenv))) nyquist-3.05/runtime/nyinit.lsp0000644000175000000620000000173211537432671015714 0ustar stevestaff(expand 5) (load "xlinit.lsp" :verbose NIL) (setf *gc-flag* nil) (load "misc.lsp" :verbose NIL) (load "evalenv.lsp" :verbose NIL) (load "printrec.lsp" :verbose NIL) (load "sndfnint.lsp" :verbose NIL) (load "seqfnint.lsp" :verbose NIL) (load "dspprims.lsp" :verbose NIL) (load "nyquist.lsp" :verbose NIL) (load "follow.lsp" :verbose NIL) (load "system.lsp" :verbose NIL) (load "seqmidi.lsp" :verbose NIL) (load "nyqmisc.lsp" :verbose NIL) (load "stk.lsp" :verbose NIL) (load "envelopes.lsp" :verbose NIL) (load "equalizer.lsp" :verbose NIL) (load "xm.lsp" :verbose NIL) (load "sal.lsp" :verbose NIL) ;; set to T to get ANSI headers and NIL to get antique headers (setf *ANSI* NIL) ;; set to T to generate tracing code, NIL to disable tracing code (setf *WATCH* NIL) (format t "~%Nyquist -- A Language for Sound Synthesis and Composition~%") (format t " Copyright (c) 1991,1992,1995,2007-2011 by Roger B. Dannenberg~%") (format t " Version 3.05~%~%") ;(setf *gc-flag* t) nyquist-3.05/runtime/test.lsp0000644000175000000620000000216210144436365015354 0ustar stevestaff (defun ss () (osc c5)) (defun tt () (stretch 2 (snd-tapv (ss) 1.1 (scale *d* (lfo 10)) 2.2))) (setf *d* .01) (defun g () (play (tt))) ;(set-sound-srate 10) ;(set-control-srate 10) (defun rr () (stretch 10 (ramp))) (defun ll () (stretch 10 (lfo .5))) (defun xx () (snd-tapv (rr) 1.1 (ll) 2.2)) (defun h () (snd-samples (xx) 150)) (defun chorus (sound maxdepth depth rate saturation) (let ((modulation (prod depth (stretch-abs 10000.0 (general-lfo rate)))) (offset (/ maxdepth 2.0)) chor) (setf chor (snd-tapv sound offset modulation maxdepth)) (sum (prod chor saturation) (prod (seq (s-rest offset) sound) (sum 1.0 (prod -1.0 saturation)))))) (set-sound-srate 22050.0) (defun f () (chorus (s-read "runtime\\ah.wav") .1 .1 1 .5)) (defun e () (seq (s-rest .05) (chorus (s-read "rpd.wav") .07 .07 .7 .5))) (defun d () (sum (e) (f))) (defun rou () (s-read "round.wav" :time-offset 1.18 :dur (- 8.378 1.18))) (defun rou4 () (sim (rou) (at *rd* (rou)) (at (* *rd* 2) (rou)) (at (* *rd* 3) (rou)))) nyquist-3.05/runtime/seqmidi.lsp0000644000175000000620000001345310144436365016035 0ustar stevestaff;; seqmidi.lsp -- functions to use MIDI files in Nyquist ; ; example call: ; ; (seq-midi my-seq ; (note (chan pitch velocity) (= chan 2) (my-note pitch velocity)) ; (ctrl (chan control value) (...)) ; (bend (chan value) (...)) ; (touch (chan value) (...)) ; (prgm (chan value) (setf (aref my-prgm chan) value)) ;; seq-midi - a macro to create a sequence of sounds based on midi file ; ; (defmacro seq-midi (the-seq &rest cases) (seq-midi-cases-syntax-check cases) `(let (_the-event _next-time _the-seq _seq-midi-closure _nyq-environment _the-seq _tag) (setf _the-seq (seq-copy ,the-seq)) (setf _nyq-environment (nyq:the-environment)) (setf _seq-midi-closure #'(lambda (t0) ; (format t "_seq_midi_closure: t0 = ~A~%" t0) (prog (_the-sound) loop ; go forward until we find note to play (we may be there) ; then go forward to find time of next note (setf _the-event (seq-get _the-seq)) ; (display "seq-midi" _the-event t0) (setf _tag (seq-tag _the-event)) (cond ((= _tag seq-ctrl-tag) ,(make-ctrl-handler cases)) ((= _tag seq-bend-tag) ,(make-bend-handler cases)) ((= _tag seq-touch-tag) ,(make-touch-handler cases)) ((= _tag seq-prgm-tag) ,(make-prgm-handler cases)) ((= _tag seq-done-tag) ; (format t "_seq_midi_closure: seq-done") (cond (_the-sound ; this is the last sound of sequence ; (format t "returning _the-sound~%") (return _the-sound)) (t ; sequence is empty, return silence ; (format t "returning snd-zero~%") (return (snd-zero t0 *sound-srate*))))) ((and (= _tag seq-note-tag) ,(make-note-test cases)) (cond (_the-sound ; we now have time of next note (setf _next-time (/ (seq-time _the-event) 1000.0)) (go exit-loop)) (t (setf _the-sound ,(make-note-handler cases)))))) (seq-next _the-seq) (go loop) exit-loop ; here, we know time of next note ; (display "seq-midi" _next-time) ; (format t "seq-midi calling snd-seq\n") (return (snd-seq (set-logical-stop-abs _the-sound (local-to-global _next-time)) _seq-midi-closure))))) ; (display "calling closure" (get-lambda-expression _seq-midi-closure)) (funcall _seq-midi-closure (local-to-global 0)))) (defun seq-midi-cases-syntax-check (cases &aux n) (cond ((not (listp cases)) (break "syntax error in" cases))) (dolist (case cases) (cond ((or (not (listp case)) (not (member (car case) '(NOTE CTRL BEND TOUCH PRGM))) (not (listp (cdr case))) (not (listp (cadr case))) (not (listp (cddr case))) (not (listp (last (cddr case))))) (break "syntax error in" case)) ((/= (length (cadr case)) (setf n (cdr (assoc (car case) '((NOTE . 3) (CTRL . 3) (BEND . 2) (TOUCH . 2) (PRGM . 2)))))) (break (format nil "expecting ~A arguments in" n) case)) ((and (eq (car case) 'NOTE) (not (member (length (cddr case)) '(1 2)))) (break "note handler syntax is (NOTE (ch pitch vel) [filter] behavior)" case))))) (defun make-ctrl-handler (cases) (let ((case (assoc 'ctrl cases))) (cond (case `(let ((,(caadr case) (seq-channel _the-event)) (,(cadadr case) (seq-control _the-event)) (,(caddar (cdr case)) (seq-value _the-event))) ,@(cddr case))) (t nil)))) (defun make-bend-handler (cases) (let ((case (assoc 'bend cases))) (cond (case `(let ((,(caadr case) (seq-channel _the-event)) (,(cadadr case) (seq-value _the-event))) ,@(cddr case))) (t nil)))) (defun make-touch-handler (cases) (let ((case (assoc 'touch cases))) (cond (case `(let ((,(caadr case) (seq-channel _the-event)) (,(cadadr case) (seq-value _the-event))) ,@(cddr case))) (t nil)))) (defun make-prgm-handler (cases) (let ((case (assoc 'pgrm cases))) (cond (case `(let ((,(caadr case) (seq-channel _the-event)) (,(cadadr case) (seq-value _the-event))) ,@(cddr case))) (t nil)))) (defun make-note-test (cases) (let ((case (assoc 'note cases))) (cond ((and case (cdddr case)) (caddr case)) (t t)))) (defun make-note-handler (cases) (let ((case (assoc 'note cases)) behavior) (cond ((and case (cdddr case)) (setf behavior (cadddr case))) (t (setf behavior (caddr case)))) `(with%environment _nyq-environment (with-note-args ,(cadr case) _the-event ,behavior)))) (defmacro with-note-args (note-args the-event note-behavior) ; (display "with-note-args" the-event) `(let ((,(car note-args) (seq-channel ,the-event)) (,(cadr note-args) (seq-pitch ,the-event)) (,(caddr note-args) (seq-velocity ,the-event))) (at (/ (seq-time ,the-event) 1000.0) (stretch (/ (seq-duration ,the-event) 1000.0) ,note-behavior)))) ;(defun seq-next-note-time (the-seq find-first-flag) ; (prog (event) ; (if find-first-flag nil (seq-next the-seq)) ;loop ; (setf event (seq-get the-seq)) ; (cond ((eq (seq-tag event) seq-done-tag) ; (return (if find-first-flag 0.0 nil))) ; ((eq (seq-tag event) seq-note-tag) ; (return (/ (seq-time event) 1000.0)))) ; (seq-next the-seq) ; (go loop))) ; nyquist-3.05/runtime/init.lsp0000644000175000000620000000025311466723256015345 0ustar stevestaff; init.lsp -- default Nyquist startup file (load "nyinit.lsp" :verbose nil) ; add your customizations here: ; e.g. (setf *default-sf-dir* "...") ; (load "test.lsp") nyquist-3.05/runtime/sal-parse.lsp0000644000175000000620000017510711470054305016267 0ustar stevestaff;; SAL parser -- replaces original pattern-directed parser with ;; a recursive descent one ;; ;; Parse functions either parse correctly and return ;; compiled code as a lisp expression (which could be nil) ;; or else they call parse-error, which does not return ;; (instead, parse-error forces a return from parse) ;; In the original SAL parser, triples were returned ;; including the remainder if any of the tokens to be ;; parsed. In this parser, tokens are on the list ;; *sal-tokens*, and whatever remains on the list is ;; the list of unparsed tokens. ;; scanning delimiters. (setfn nreverse reverse) (defconstant +quote+ #\") ; "..." string (defconstant +kwote+ #\') ; '...' kwoted expr (defconstant +comma+ #\,) ; positional arg delimiter (defconstant +pound+ #\#) ; for bools etc (defconstant +semic+ #\;) ; comment char (defconstant +lbrace+ #\{) ; {} list notation (defconstant +rbrace+ #\}) (defconstant +lbrack+ #\[) ; unused for now (defconstant +rbrack+ #\]) (defconstant +lparen+ #\() ; () expr and arg grouping (defconstant +rparen+ #\)) ;; these are defined so that SAL programs can name these symbols ;; note that quote(>) doesn't work, so you need quote(symbol:greater) (setf symbol:greater '>) (setf symbol:less '<) (setf symbol:greater-equal '>=) (setf symbol:less-equal '<=) (setf symbol:equal '=) (setf symbol:not '!) (setf symbol:not-equal '/=) (defparameter +whites+ (list #\space #\tab #\newline (code-char 13))) (defparameter +kwstyle+ (list :suffix #\:)) ; let's try dylan (defparameter +operators+ ;; each op is: ( ) '((:+ "+" sum) (:- "-" diff) (:* "*" mult) (:/ "/" /) (:% "%" rem) (:^ "^" expt) (:= "=" eql) ; equality and assigment (:!= "!=" not-eql) (:< "<" <) (:> ">" >) (:<= "<=" <=) ; leq and assignment minimization (:>= ">=" >=) ; geq and assignment maximization (:~= "~=" equal) ; general equality (:+= "+=" +=) ; assignment increment-and-store (:-= "-=" -=) ; assignment increment-and-store (:*= "*=" *=) ; assignment multiply-and-store (:/= "/=" /=) ; assignment multiply-and-store (:&= "&=" &=) ; assigment list collecting (:@= "@=" @=) ; assigment list prepending (:^= "^=" ^=) ; assigment list appending (:! "!" not) (:& "&" and) (:\| "|" or) (:~ "~" sal-stretch) (:~~ "~~" sal-stretch-abs) (:@ "@" sal-at) (:@@ "@@" sal-at-abs) )) (setf *sal-local-variables* nil) ;; used to avoid warning about variable ;; names when the variable has been declared as a local (defparameter *sal-operators* '(:+ :- :* :/ :% :^ := :!= :< :> :<= :>= :~= :+= :*= :&= :@= :^= :! :& :\| :~ :~~ :@ :@@)) (defparameter +delimiters+ '((:lp #\() (:rp #\)) (:lc #\{) ; left curly (:rc #\}) (:lb #\[) (:rb #\]) (:co #\,) (:kw #\') ; kwote (nil #\") ; not token ; (nil #\#) (nil #\;) )) (setf *reserved-words* '((::+ ":+") (::- ":-") (::* ":*") (::/ ":/") (::= ":=") (::!= ":!=") (::< ":<") (::> ":>") (::<= ":<=") (::>= ":>=") (::~= ":~=") (::! ":!") (::& ":&") (::\| ":|") (:IF "if") (:THEN "then") (:ELSE "else") (:WHEN "when") (:UNLESS "unless") (:SET "set") (:= "=") (:+= "+=") (:*= "*=") (:&= "&=") (:@= "@=") (:^= "^=") (:<= "<=") (:>= ">=") (:PRINT "print") (:LOOP "loop") (:RUN "run") (:REPEAT "repeat") (:FOR "for") (:FROM "from") (:IN "in") (:BELOW "below") (:TO "to") (:ABOVE "above") (:DOWNTO "downto") (:BY "by") (:OVER "over") (:WHILE "while") (:UNTIL "until") (:FINALLY "finally") (:RETURN "return") (:WAIT "wait") (:BEGIN "begin") (:WITH "with") (:END "end") (:VARIABLE "variable") (:FUNCTION "function") (:PROCESS "process") (:CHDIR "chdir") (:DEFINE "define") (:LOAD "load") (:PLAY "play") (:EXEC "exec") (:exit "exit") (:DISPLAY "display") (:~ "~") (:~~ "~~") (:@ ":@") (:@@ ":@@"))) (setf *sal-fn-name* nil) (defun make-sal-error (&key type text (line nil) start) ; (error 'make-sal-error-was-called-break) (list 'sal-error type text line start)) (setfn sal-error-type cadr) (setfn sal-error-text caddr) (setfn sal-error-line cadddr) (defun sal-error-start (x) (cadddr (cdr x))) (defun is-sal-error (x) (and x (eq (car x) 'sal-error))) (defun sal-tokens-error-start (start) (cond (start start) (*sal-tokens* (token-start (car *sal-tokens*))) (t (length *sal-input-text*)))) (defmacro errexit (message &optional start) `(parse-error (make-sal-error :type "parse" :line *sal-input-text* :text ,message :start ,(sal-tokens-error-start start)))) (defmacro sal-warning (message &optional start) `(pperror (make-sal-error :type "parse" :line *sal-input-text* :text ,message :start ,(sal-tokens-error-start start)) "warning")) (setf *pos-to-line-source* nil) (setf *pos-to-line-pos* nil) (setf *pos-to-line-line* nil) (defun pos-to-line (pos source) ;; this is really inefficient to search every line from ;; the beginning, so cache results and search forward ;; from there if possible (let ((i 0) (line-no 1)) ;; assume no cache ;; see if we can use the cache (cond ((and (eq source *pos-to-line-source*) *pos-to-line-pos* *pos-to-line-line* (>= pos *pos-to-line-pos*)) (setf i *pos-to-line-pos*) (setf line-no *pos-to-line-line*))) ;; count newlines up to pos (while (< i pos) (if (char= (char source i) #\newline) (incf line-no)) (setf i (1+ i))) ;; save results in cache (setf *pos-to-line-source* source *pos-to-line-pos* pos *pos-to-line-line* line-no) ;; return the line number at pos in source line-no)) ;; makes a string of n spaces, empty string if n <= 0 (defun make-spaces (n) (cond ((> n 16) (let* ((half (/ n 2)) (s (make-spaces half))) (strcat s s (make-spaces (- n half half))))) (t (subseq " " 0 (max n 0))))) (defun pperror (x &optional (msg-type "error")) (let* ((source (sal-error-line x)) (llen (length source)) line-no beg end) ; (display "pperror" x (strcat "|" (sal-error-line x) "|")) ;; isolate line containing error (setf beg (sal-error-start x)) (setf beg (min beg (1- llen))) (do ((i beg (- i 1)) (n nil)) ; n gets set when we find a newline ((or (< i 0) n) (setq beg (or n 0))) (if (char= (char source i) #\newline) (setq n (+ i 1)))) (do ((i (sal-error-start x) (+ i 1)) (n nil)) ((or (>= i llen) n) (setq end (or n llen))) (if (char= (char source i) #\newline) (setq n i))) (setf line-no (pos-to-line beg source)) ; (display "pperror" beg end (sal-error-start x)) ;; print the error. include the specfic line of input containing ;; the error as well as a line below it marking the error position ;; with an arrow: ^ (let* ((pos (- (sal-error-start x) beg)) (line (if (and (= beg 0) (= end llen)) source (subseq source beg end))) (mark (make-spaces pos))) (format t "~%>>> ~A ~A: ~A.~%>>> in ~A, line ~A, col ~A.~%~%~A~%~A^~%" (sal-error-type x) msg-type (sal-error-text x) *sal-input-file-name* line-no (1+ pos) line mark) ; (format t "~%>>> ~A error in \"~A\", line ~A, col ~A: ~A.~%~%~A~%~A^~%" ; (sal-error-type x) *sal-input-file-name* line-no pos ; (sal-error-text x) line mark) x))) ;;; ;;; the lexer. right now it assumes input string is complete and ready ;;; to be processed as a valid expression. ;;; (defun advance-white (str white start end) ;; skip "white" chars, where white can be a char, list of chars ;; or predicate test (do ((i start ) (p nil)) ((or p (if (< start end) (not (< -1 i end)) (not (> i end -1)))) (or p end)) (cond ((consp white) (unless (member (char str i) white :test #'char=) (setq p i))) ((characterp white) (unless (char= (char str i) white) (setq p i))) ((functionp white) (unless (funcall white (char str i)) (setq p i)))) (if (< start end) (incf i) (decf i)))) (defun search-delim (str delim start end) ;; find position of "delim" chars, where delim can be ;; a char, list of chars or predicate test (do ((i start (+ i 1)) (p nil)) ((or (not (< i end)) p) (or p end)) (cond ((consp delim) (if (member (char str i) delim :test #'char=) (setq p i))) ((characterp delim) (if (char= (char str i) delim) (setq p i))) ((functionp delim) (if (funcall delim (char str i)) (setq p i)))))) ;; UNBALANCED-INPUT AND TOKENIZE HAVE BEEN REWRITTEN, SEE BELOW. THIS ONE IS ;; OLD AND JUST KEPT HERE FOR REFERENCE #| (defun unbalanced-input (errf line toks par bra brk kwo) ;; search input for the starting position of some unbalanced ;; delimiter, toks is reversed list of tokens with something ;; unbalanced (let (char text targ othr levl pos) (cond ((> par 0) (setq char #\( targ ':lp othr ':rp levl par)) ((< par 0) (setq char #\) targ ':rp othr ':lp levl 0)) ((> bra 0) (setq char #\{ targ ':lc othr ':rc levl bra)) ((< bra 0) (setq char #\} targ ':rc othr ':lc levl 0)) ((> brk 0) (setq char #\[ targ ':ls othr ':rs levl brk)) ((< brk 0) (setq char #\] targ ':rs othr ':ls levl 0)) ((> kwo 0) (setq char #\' targ ':kw othr ':kw levl kwo))) (setq text (format nil "Unmatched '~A'" char)) ;; search for start of error in token list (do ((n levl) (tail toks (cdr tail))) ((or (null tail) pos) (or pos (error (format nil "Shouldn't! can't find op ~A in ~A." targ (reverse toks))))) (if (eql (token-type (car tail)) targ) (if (= n levl) (setq pos (token-start (car tail))) (decf n)) (if (eql (token-type (car tail)) othr) (incf n)))) (errexit text pos))) (defun tokenize (str reserved error-fn) ;&key (start 0) (end (length str)) ; (white-space +whites+) (delimiters +delimiters+) ; (operators +operators+) (null-ok t) ; (keyword-style +kwstyle+) (reserved nil) ; (error-fn nil) ; &allow-other-keys) ;; return zero or more tokens or a sal-error (let ((toks (list t)) (start 0) (end (length str)) (all-delimiters +whites+) (errf (or error-fn (lambda (x) (pperror x) (return-from tokenize x))))) (dolist (x +delimiters+) (push (cadr x) all-delimiters)) (do ((beg start) (pos nil) (all all-delimiters) (par 0) (bra 0) (brk 0) (kwo 0) (tok nil) (tail toks)) ((not (< beg end)) ;; since input is complete check parens levels. (if (= 0 par bra brk kwo) (if (null (cdr toks)) (list) (cdr toks)) (unbalanced-input errf str (reverse (cdr toks)) par bra brk kwo))) (setq beg (advance-white str +whites+ beg end)) (setf tok (read-delimited str :start beg :end end :white +whites+ :delimit all :skip-initial-white nil :errorf errf)) ;; multiple values are returned, so split them here: (setf pos (second tok)) ; pos is the end of the token (!) (setf tok (first tok)) ;; tok now string, char (delimiter), :eof or token since input ;; is complete keep track of balancing delims (cond ((eql tok +lbrace+) (incf bra)) ((eql tok +rbrace+) (decf bra)) ((eql tok +lparen+) (incf par)) ((eql tok +rparen+) (decf par)) ((eql tok +lbrack+) (incf brk)) ((eql tok +rbrack+) (decf brk)) ((eql tok +kwote+) (setq kwo (mod (+ kwo 1) 2)))) (cond ((eql tok ':eof) (setq beg end)) (t ;; may have to skip over comments to reach token, so ;; token beginning is computed by backing up from current ;; position (returned by read-delimited) by string length (setf beg (if (stringp tok) (- pos (length tok)) (1- pos))) (setq tok (classify-token tok beg str errf +delimiters+ +operators+ +kwstyle+ reserved)) ;(display "classify-token-result" tok) (setf (cdr tail) (list tok )) (setf tail (cdr tail)) (setq beg pos)))))) |# ;; old tokenize (above) counted delimiters to check for balance, ;; but that does not catch constructions like ({)}. I think ;; we could just leave this up to the parser, but this rewrite ;; uses a stack to check balanced parens, braces, quotes, etc. ;; The checking establishes at least some minimal global properties ;; of the input before evaluating anything, which might be good ;; even though it's doing some extra work. In fact, using a ;; stack rather than counts is doing even more work, but the ;; problem with counters is that some very misleading or just ;; plain wrong error messages got generated. ;; ;; these five delimiter- functions do checks on balanced parens, ;; braces, and brackets, leaving delimiter-mismatch set to bad ;; token if there is a mismatch (defun delimiter-init () (setf delimiter-stack nil) (setf delimiter-mismatch nil)) (defun delimiter-match (tok what) (cond ((eql (token-string (first delimiter-stack)) what) (pop delimiter-stack)) ((null delimiter-mismatch) ;(display "delimiter-mismatch" tok) (setf delimiter-mismatch tok)))) (defun delimiter-check (tok) (let ((c (token-string tok))) (cond ((member c '(#\( #\{ #\[)) (push tok delimiter-stack)) ((eql c +rbrace+) (delimiter-match tok +lbrace+)) ((eql c +rparen+) (delimiter-match tok +lparen+)) ((eql c +rbrack+) (delimiter-match tok +lbrack+))))) (defun delimiter-error (tok) (errexit (format nil "Unmatched '~A'" (token-string tok)) (token-start tok))) (defun delimiter-finish () (if delimiter-mismatch (delimiter-error delimiter-mismatch)) (if delimiter-stack (delimiter-error (car delimiter-stack)))) (defun tokenize (str reserved error-fn) ;; return zero or more tokens or a sal-error (let ((toks (list t)) (start 0) (end (length str)) (all-delimiters +whites+) (errf (or error-fn (lambda (x) (pperror x) (return-from tokenize x))))) (dolist (x +delimiters+) (push (cadr x) all-delimiters)) (delimiter-init) (do ((beg start) (pos nil) (all all-delimiters) (tok nil) (tail toks)) ((not (< beg end)) ;; since input is complete check parens levels. (delimiter-finish) (if (null (cdr toks)) nil (cdr toks))) (setq beg (advance-white str +whites+ beg end)) (setf tok (read-delimited str :start beg :end end :white +whites+ :delimit all :skip-initial-white nil :errorf errf)) ;; multiple values are returned, so split them here: (setf pos (second tok)) ; pos is the end of the token (!) (setf tok (first tok)) (cond ((eql tok ':eof) (setq beg end)) (t ;; may have to skip over comments to reach token, so ;; token beginning is computed by backing up from current ;; position (returned by read-delimited) by string length (setf beg (if (stringp tok) (- pos (length tok)) (1- pos))) (setq tok (classify-token tok beg str errf +delimiters+ +operators+ +kwstyle+ reserved)) (delimiter-check tok) ;(display "classify-token-result" tok) (setf (cdr tail) (list tok )) (setf tail (cdr tail)) (setq beg pos)))))) (defun read-delimited (input &key (start 0) end (null-ok t) (delimit +delims+) ; includes whites... (white +whites+) (skip-initial-white t) (errorf #'pperror)) ;; read a substring from input, optionally skipping any white chars ;; first. reading a comment delim equals end-of-line, input delim ;; reads whole input, pound reads next token. call errf if error ;(FORMAT T "~%READ-DELIMITED: ~S :START ~S :END ~S" input start end) (let ((len (or end (length input)))) (while t ;; loop over comment lines (when skip-initial-white (setq start (advance-white input white start len))) (if (< start len) (let ((char (char input start))) (setq end (search-delim input delimit start len)) (if (equal start end) ; have a delimiter (cond ((char= char +semic+) ;; comment skips to next line and trys again... (while (and (< start len) (char/= (char input start) #\newline)) (incf start)) (cond ((< start len) ;; advance past comment and iterate (incf start) (setf skip-initial-white t)) (null-ok (return (list ':eof end))) (t (errexit "Unexpected end of input")))) ; ((char= char +pound+) ; ;; read # dispatch ; (read-hash input delimit start len errorf)) ((char= char +quote+) ;; input delim reads whole input (return (sal:read-string input delimit start len errorf))) ((char= char +kwote+) (errexit "Illegal delimiter" start)) (t ;; all other delimiters are tokens in and of themselves (return (list char (+ start 1))))) ; else part of (equal start end), so we have token before delimiter (return (list (subseq input start end) end)))) ; else part of (< start len)... (if null-ok (return (list ':eof end)) (errexit "Unexpected end of input" start)))))) (defparameter hash-readers '(( #\t sal:read-bool) ( #\f sal:read-bool) ( #\? read-iftok) )) (defun read-hash (str delims pos len errf) (let ((e (+ pos 1))) (if (< e len) (let ((a (assoc (char str e) hash-readers))) (if (not a) (errexit "Illegal # character" e) (funcall (cadr a) str delims e len errf))) (errexit "Missing # character" pos)))) (defun read-iftok (str delims pos len errf) str delims len errf (list (make-token :type ':? :string "#?" :lisp 'if :start (- pos 1)) (+ pos 1))) ; (sal:read-string str start len) (defun sal:read-bool (str delims pos len errf) delims len errf (let ((end (search-delim str delims pos len))) (unless (= end (+ pos 1)) (errexit "Illegal # expression" (- pos 1))) (list (let ((t? (char= (char str pos) #\t) )) (make-token :type ':bool :string (if t? "#t" "#f") :lisp t? :start (- pos 1))) (+ pos 1)))) (defun sal:read-string (str delims pos len errf) (let* ((i (1+ pos)) ; i is index into string; start after open quote c c2; c is the character at str[i] (string (make-string-output-stream))) ;; read string, processing escaped characters ;; write the chars to string until end quote is found ;; then retrieve the string. quotes are not included in result token ;; in the loop, i is the next character location to examine (while (and (< i len) (not (char= (setf c (char str i)) +quote+))) (if (char= c #\\) ;; escape character, does another character follow this? (cond ((< (1+ i) len) (incf i) ;; yes, set i so we'll get the escaped char (setf c2 (char str i)) (setf c (assoc c2 `((#\n . #\newline) (#\t . #\tab) (#\r . ,(char "\r" 0)) (#\f . ,(char "\f" 0))))) (setf c (if c (cdr c) c2))) ;; use c2 if c wasn't listed (t ;; no, we've hit the end of input too early (errexit "Unmatched \"" i)))) ;; we're good to take this character and move on to the next one (write-char c string) (incf i)) ;; done with loop, so either we're out of string or we found end quote (if (>= i len) (errexit "Unmatched \"" i)) ;; must have found the quote (setf string (get-output-stream-string string)) (list (make-token :type :string :start pos :string string :lisp string) (1+ i)))) ;;; ;;; tokens ;;; (defun make-token (&key (type nil) (string "") start (info nil) lisp) (list :token type string start info lisp)) (setfn token-type cadr) (setfn token-string caddr) (defun token-start (x) (cadddr x)) (defun token-info (token) (car (cddddr token))) (defun token-lisp (token) (cadr (cddddr token))) (defmacro set-token-type (tok val) `(setf (car (cdr ,tok)) ,val)) (defmacro set-token-lisp (tok val) `(setf (car (cdr (cddddr ,tok))) ,val)) (defun tokenp (tok) (and (consp tok) (eq (car tok) :token))) (defun token=? (tok op) (if (tokenp tok) (equal (token-type tok) op) (eql tok op))) (defmethod token-print (obj stream) (let ((*print-case* ':downcase)) (format stream "#<~s ~s>" (token-type obj) (token-string obj)))) (defun parse-token () (prog1 (car *sal-tokens*) (setf *sal-tokens* (cdr *sal-tokens*)))) ;;; ;;; token classification. types not disjoint! ;;; (defun classify-token (str pos input errf delims ops kstyle res) (let ((tok nil)) (cond ((characterp str) ;; normalize char delimiter tokens (setq tok (delimiter-token? str pos input errf delims))) ((stringp str) (setq tok (or (number-token? str pos input errf) (operator-token? str pos input errf ops) (keyword-token? str pos input errf kstyle) (class-token? str pos input errf res) (reserved-token? str pos input errf res) (symbol-token? str pos input errf) )) (unless tok (errexit "Not an expression or symbol" pos))) (t (setq tok str))) tok)) (defun delimiter-token? (str pos input errf delims) (let ((typ (member str delims :test (lambda (a b) (char= a (cadr b)))))) ;; member returns remainder of the list ;(display "delimiter-token?" str delims typ) (if (and typ (car typ) (caar typ)) (make-token :type (caar typ) :string str :start pos) (+ (break) (errexit "Shouldn't: non-token delimiter" pos))))) (defun string-to-number (s) (read (make-string-input-stream s))) (defun number-token? (str pos input errf) errf input (do ((i 0 (+ i 1)) (len (length str)) (c nil) (dot 0) (typ ':int) (sig 0) (sla 0) (dig 0) (non nil)) ((or (not (< i len)) non) (if non nil (if (> dig 0) (make-token :type typ :string str :start pos :lisp (string-to-number str)) nil))) (setq c (char str i)) (cond ((member c '(#\+ #\-)) (if (> i 0) (setq non t) (incf sig))) ((char= c #\.) (if (> dot 0) (setq non t) (if (> sla 0) (setq non t) (incf dot)))) ; xlisp does not have ratios ; ((char= c #\/) ; (setq typ ':ratio) ; (if (> sla 0) (setq non t) ; (if (= dig 0) (setq non t) ; (if (> dot 0) (setq non t) ; (if (= i (1- len)) (setq non t) ; (incf sla)))))) ((digit-char-p c) (incf dig) (if (> dot 0) (setq typ ':float))) (t (setq non t))))) #|| (number-token? "" 0 "" #'pperror) (number-token? " " 0 "" #'pperror) (number-token? "a" 0 "" #'pperror) (number-token? "1" 0 "" #'pperror) (number-token? "+" 0 "" #'pperror) (number-token? "-1/2" 0 "" #'pperror) (number-token? "1." 0 "" #'pperror) (number-token? "1.." 0 "" #'pperror) (number-token? ".1." 0 "" #'pperror) (number-token? ".1" 0 "" #'pperror) (number-token? "-0.1" 0 "" #'pperror) (number-token? "1/2" 0 "" #'pperror) (number-token? "1//2" 0 "" #'pperror) (number-token? "/12" 0 "" #'pperror) (number-token? "12/" 0 "" #'pperror) (number-token? "12/1" 0 "" #'pperror) (number-token? "12./1" 0 "" #'pperror) (number-token? "12/.1" 0 "" #'pperror) ||# (defun operator-token? (str pos input errf ops) ;; tok can be string or char (let ((typ (member str ops :test (lambda (a b) (equal a (cadr b)))))) (cond (typ (setf typ (car typ)) ;; member returns remainder of list (make-token :type (car typ) :string str :start pos :lisp (or (third typ) (read-from-string str))))))) (defun str-to-keyword (str) (intern (strcat ":" (string-upcase str)))) (defun keyword-token? (tok pos input errf style) (let* ((tlen (length tok)) (keys (cdr style)) (klen (length keys))) (cond ((not (< klen tlen)) nil) ((eql (car style) ':prefix) (do ((i 0 (+ i 1)) (x nil)) ((or (not (< i klen)) x) (if (not x) (let ((sym (symbol-token? (subseq tok i) pos input errf ))) (cond (sym (set-token-type sym ':key) (set-token-lisp sym (str-to-keyword (token-string sym))) sym))) nil)) (unless (char= (char tok i) (nth i keys)) (setq x t)))) ((eql (car style) ':suffix) (do ((j (- tlen klen) (+ j 1)) (i 0 (+ i 1)) (x nil)) ((or (not (< i klen)) x) (if (not x) (let ((sym (symbol-token? (subseq tok 0 (- tlen klen)) pos input errf ))) (cond (sym (set-token-type sym ':key) (set-token-lisp sym (str-to-keyword (token-string sym))) sym))) nil)) (unless (char= (char tok j) (nth i keys)) (setq x t))))))) (setfn alpha-char-p both-case-p) (defun class-token? (str pos input errf res) res (let ((a (char str 0))) (if (char= a #\<) (let* ((l (length str)) (b (char str (- l 1)))) (if (char= b #\>) (let ((tok (symbol-token? (subseq str 1 (- l 1)) pos input errf))) ;; class token has <> removed! (if tok (progn (set-token-type tok ':class) tok) (errexit "Not a class identifer" pos))) (errexit "Not a class identifer" pos))) nil))) ; (keyword-token? ":asd" '(:prefix #\:)) ; (keyword-token? "asd" KSTYLE) ; (keyword-token? "asd:" KSTYLE) ; (keyword-token? "123:" KSTYLE) ; (keyword-token? ":foo" '(:prefix #\:)) ; (keyword-token? "foo=" '(:suffix #\=)) ; (keyword-token? "--foo" '(:prefix #\- #\-)) ; (keyword-token? ":123" '(:suffix #\:)) ; (keyword-token? "--asd" '(:prefix #\-)) ; ok since -asd is legal symbol (defun reserved-token? (str pos input errf reserved) errf input (let ((typ (member str reserved :test (lambda (a b) (equal a (cadr b)))))) (if typ (make-token :type (caar typ) :string str :start pos) nil))) (defun sal-string-to-symbol (str) (let ((sym (intern (string-upcase str))) sal-sym) (cond ((and sym ;; (it might be "nil") (setf sal-sym (get sym :sal-name))) sal-sym) (t sym)))) (putprop 'simrep 'sal-simrep :sal-name) (putprop 'seqrep 'sal-seqrep :sal-name) (defun contains-op-char (s) ;; assume most identifiers are very short, so we search ;; over identifier letters, not over operator characters ;; Minus (-) is so common, we don't complain about it. (dotimes (i (length s)) (if (string-search (subseq s i (1+ i)) "*/+=<>!%^&|") (return t)))) (defun test-for-suspicious-symbol (token) ;; assume token is of type :id (let ((sym (token-lisp token)) (str (token-string token)) (pos (token-start token))) (cond ((and sym ; nil is not suspicious, but it's not "boundp" (not (fboundp sym)) ; existing functions not suspicious (not (boundp sym)) ; existing globals not suspicious (not (member sym *sal-local-variables*)) (contains-op-char str)) ; suspicious if embedded operators (sal-warning (strcat "Identifier contains operator character(s).\n" " Perhaps you omitted spaces around an operator") pos))))) (defun symbol-token? (str pos input errf) ;; if a potential symbol is preceded by #, drop the # (if (and (> (length str) 1) (char= (char str 0) #\#)) ;; there are a couple of special cases: SAL defines #f and #? (cond ((equal str "#f") (return-from symbol-token? (make-token :type ':id :string str :start pos :lisp nil))) ((equal str "#?") (return-from symbol-token? (make-token :type ':id :string str :start pos :lisp 'if))) (t (setf str (subseq str 1))))) ;; let's insist on at least one letter for sanity's sake ;; exception: allow '-> because it is used in markov pattern specs (do ((i 0 (+ i 1)) ; i is index into string (bad "Not an expression or symbol") (chr nil) (ltr 0) ; ltr is count of alphabetic letters in string (dot nil) ; dot is index of "." (pkg nil) ; pkg is index if package name "xxx:" found (len (length str)) (err nil)) ;; loop ends when i is at end of string or when err is set ((or (not (< i len)) err) (if (or (> ltr 0) ; must be at least one letter, or (equal str "->")) ; symbol can be "->" (let ((info ()) sym) (if pkg (push (cons ':pkg pkg) info)) (if dot (push (cons ':slot dot) info)) ;(display "in symbol-token?" str) (setf sym (sal-string-to-symbol str)) (make-token :type ':id :string str :info info :start pos :lisp sym)) nil)) (setq chr (char str i)) (cond ((alpha-char-p chr) (incf ltr)) ; need to allow arbitrary lisp symbols ; ((member chr '(#\* #\+)) ;; special variable names can start/end ; (if (< 0 i (- len 2)) ;; with + or * ; (errexit bad pos))) ((char= chr #\/) ;; embedded / is not allowed (errexit bad pos)) ;((char= chr #\-) ;; hyphens are allowed anywhere in symbol ; (if (= ltr 0) ; (errexit errf input bad pos ) ; (setq ltr 0) ; )) ((char= chr #\:) ; allowable forms are :foo, foo:bar, :foo:bar (if (> i 0) ;; lisp keyword symbols ok (cond ((= ltr 0) (errexit bad pos)) ((not pkg) (setq pkg i)) (t (errexit errf input (format nil "Too many colons in ~s" str) pos)))) (setq ltr 0)) ((char= chr #\.) (if (or dot (= i 0) (= i (- len 1))) (errexit bad pos) (progn (setq dot i) (setq ltr 0))))))) ; (let ((i "foo")) (symbol-token? i 0 i #'pperror)) ; (let ((i "foo..bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i ".bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "bar.")) (symbol-token? i 0 i #'pperror)) ; (let ((i "1...")) (symbol-token? i 0 i #'pperror)) ; (let ((i "a1..." )) (symbol-token? i 0 i #'pperror)) ; (let ((i "a{b")) (symbol-token? i 0 i #'pperror)) ; (let ((i "foo-bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "123-a")) (symbol-token? i 0 i #'pperror)) ; (let ((i "1a23-a")) (symbol-token? i 0 i #'pperror)) ; (let ((i "*foo*")) (symbol-token? i 0 i #'pperror)) ; (let ((i "+foo+")) (symbol-token? i 0 i #'pperror)) ; (let ((i "foo+bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "foo/bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i ":bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "::bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "foo:bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "cl-user:bar")) (symbol-token? i 0 i #'pperror)) ; (let ((i "cl-user::bar")) (symbol-token? i 0 i #'pperror)) ; (tokenize "aaa + bbb \"asdasdd\" aaa(1,2,3)") ; (tokenize "aaa+bbb \"asdasdd\" aaa(1,2,3)") (setf *in-sal-parser* nil) ;; line number info for debugging (setf *sal-line-number-info* t) (setf *sal-line* 0) (defun add-line-info-to-expression (expr token) (let (line-no) (cond ((and token ;; null token means do not change expr *sal-line-number-info* ;; is this feature enabled? (stringp *sal-input-text*)) ;; first, get line number (setf line-no (pos-to-line (token-start token) *sal-input-text*)) `(prog2 (setf *sal-line* ,line-no) ,expr)) (t expr)))) ;; single statement is handled just like an expression (setfn add-line-info-to-stmt add-line-info-to-expression) ;; list of statements is simple to handle: prepend SETF (defun add-line-info-to-stmts (stmts token) (let (line-no) (cond ((and *sal-line-number-info* ;; is this feature enabled? (stringp *sal-input-text*)) (setf line-no (pos-to-line (token-start token) *sal-input-text*)) (cons `(setf *sal-line* ,line-no) stmts)) (t stmts)))) ;; PARSE-ERROR -- print error message, return from top-level ;; (defun parse-error (e) (unless (sal-error-line e) (setf (sal-error-line e) *sal-input*)) (pperror e) (return-from sal-parse (values nil e *sal-tokens*))) ;; SAL-PARSE -- parse string or token input, translate to Lisp ;; ;; If input is text, *sal-input-text* is set to the text and ;; read later (maybe) by ERREXIT. ;; If input is a token list, it is assumed these are leftovers ;; from tokenized text, so *sal-input-text* is already valid. ;; *Therfore*, do not call sal-parse with tokens unless ;; *sal-input-text* is set to the corresponding text. ;; (defun sal-parse (grammar pat input multiple-statements file) (progv '(*sal-input-file-name*) (list file) (let (rslt expr rest) ; ignore grammar and pat (just there for compatibility) ; parse input and return lisp expression (cond ((stringp input) (setf *sal-input-text* input) (setq input (tokenize input *reserved-words* #'parse-error)))) (setf *sal-input* input) ;; all input (setf *sal-tokens* input) ;; current input (cond ((null input) (values t nil nil)) ; e.g. comments compile to nil (t (setf rslt (or (maybe-parse-command) (maybe-parse-block) (maybe-parse-conditional) (maybe-parse-assignment) (maybe-parse-loop) (maybe-parse-exec) (maybe-parse-exit) (errexit "Syntax error"))) ;; note: there is a return-from parse in parse-error that ;; returns (values nil error ) (cond ((and *sal-tokens* (not multiple-statements)) (errexit "leftover tokens"))) ;((null rslt) ; (errexit "nothing to compile"))) (values t rslt *sal-tokens*)))))) ;; TOKEN-IS -- test if the type of next token matches expected type(s) ;; ;; type can be a list of possibilities or just a symbol ;; Usually, suspicious-id-warn is true by default, and any symbol ;; with embedded operator symbols, e.g. x+y results in a warning ;; that this is an odd variable name. But if the symbol is declared ;; as a local, a parameter, a function name, or a global variable, ;; then the warning is supressed. ;; (defun token-is (type &optional (suspicious-id-warn t)) (let ((token-type (if *sal-tokens* (token-type (car *sal-tokens*)) nil)) rslt) ; input can be list of possible types or just a type: (setf rslt (or (and (listp type) (member token-type type)) (and (symbolp type) (eq token-type type)))) ; test if symbol has embedded operator characters: (cond ((and rslt suspicious-id-warn (eq token-type :id)) (test-for-suspicious-symbol (car *sal-tokens*)))) rslt)) (defun maybe-parse-command () (if (token-is '(:define :load :chdir :variable :function ; :system :play :print :display)) (parse-command) (if (and (token-is '(:return)) *audacity-top-level-return-flag*) (parse-command)))) (defun parse-command () (cond ((token-is '(:define :variable :function)) (parse-declaration)) ((token-is :load) (parse-load)) ((token-is :chdir) (parse-chdir)) ((token-is :play) (parse-play)) ; ((token-is :system) ; (parse-system)) ((token-is :print) (parse-print-display :print 'sal-print)) ((token-is :display) (parse-print-display :display 'display)) ((and *audacity-top-level-return-flag* (token-is :return)) (parse-return)) ; ((token-is :output) ; (parse-output)) (t (errexit "Command not found")))) (defun parse-stmt () (cond ((token-is :begin) (parse-block)) ((token-is '(:if :when :unless)) (parse-conditional)) ((token-is :set) (parse-assignment)) ((token-is :loop) (parse-loop)) ((token-is :print) (parse-print-display :print 'sal-print)) ((token-is :display) (parse-print-display :display 'display)) ; ((token-is :output) ; (parse-output)) ((token-is :exec) (parse-exec)) ((token-is :exit) (parse-exit)) ((token-is :return) (parse-return)) ((token-is :load) (parse-load)) ((token-is :chdir) (parse-chdir)) ; ((token-is :system) ; (parse-system)) ((token-is :play) (parse-play)) (t (errexit "Command not found")))) ;; GET-PARM-NAMES -- given parms like (a b &key (x 1) (y 2)), ;; return list of parameters: (a b x y) (defun get-parm-names (parms) (let (rslt) (dolist (p parms) (cond ((symbolp p) (if (eq p '&key) nil (push p rslt))) (t (push (car p) rslt)))) (reverse rslt))) ;; RETURNIZE -- make a statement (list) end with a sal-return-from ;; ;; SAL returns nil from begin-end statement lists ;; (defun returnize (stmt) (let (rev) (setf rev (reverse stmt)) (setf expr (car rev)) ; last expression in list (cond ((and (consp expr) (eq (car expr) 'sal-return-from)) stmt) ; already ends in sal-return-from (t (reverse (cons (list 'sal-return-from *sal-fn-name* nil) rev)))))) (defun parse-declaration () (if (token-is :define) (parse-token)) ; SAL extension: "define" is optional (let (bindings setf-args formals parms stmt locals loc) (cond ((token-is :variable) (setf bindings (parse-bindings)) (setf loc *rslt*) ; the "variable" token (dolist (b bindings) (cond ((symbolp b) (push b setf-args) (push `(if (boundp ',b) ,b) setf-args)) (t (push (first b) setf-args) (push (second b) setf-args)))) (add-line-info-to-stmt (cons 'setf (reverse setf-args)) loc)) ((token-is :function) (parse-token) (if (token-is :id nil) (setf *sal-fn-name* (token-lisp (parse-token))) (errexit "function name expected here")) (setf locals *sal-local-variables*) (setf formals (parse-parms)) (setf stmt (parse-stmt)) ;; stmt may contain a return-from, so make this a progn or prog* (cond ((and (consp stmt) (not (eq (car stmt) 'progn)) (not (eq (car stmt) 'prog*))) (setf stmt (list 'progn stmt)))) ;; need return to pop traceback stack (setf stmt (returnize stmt)) ;; get list of parameter names (setf parms (get-parm-names formals)) (setf *sal-local-variables* locals) ;; build the defun (prog1 (list 'defun *sal-fn-name* formals (list 'sal-trace-enter (list 'quote *sal-fn-name*) (cons 'list parms) (list 'quote parms)) stmt) (setf *sal-fn-name* nil))) (t (errexit "bad syntax"))))) (defun parse-one-parm (kargs) ;; kargs is a flag indicating previous parameter was a keyword (all ;; the following parameters must then also be keyword parameters) ;; returns: ( ) or (nil ) ;; where is a keyward parameter name (nil if not a keyword parm) ;; is an expression for the default value ;; is the parameter name (if not a keyword parm) (let (key default-value id) (cond ((and kargs (token-is :id)) (errexit "positional parameter not allowed after keyword parameter")) ((token-is :id) ;(display "parse-one-1" (token-is :id) (car *sal-tokens*)) (setf id (token-lisp (parse-token))) (push id *sal-local-variables*) (list nil id)) ((token-is :key) (setf key (sal-string-to-symbol (token-string (parse-token)))) (cond ((or (token-is :co) (token-is :rp))) ; no default value (t (setf default-value (parse-sexpr)))) (list key default-value)) (kargs (errexit "expected keyword name")) (t (errexit "expected parameter name"))))) (defun parse-parms () ;(display "parse-parms" *sal-tokens*) (let (parms parm kargs expecting) (if (token-is :lp) (parse-token) ;; eat the left paren (errexit "expected left parenthesis")) (setf expecting (not (token-is :rp))) (while expecting (setf parm (parse-one-parm kargs)) ;(display "parm" parm) ;; returns list of (kargs . parm) (if (and (car parm) (not kargs)) ; kargs just set (push '&key parms)) (setf kargs (car parm)) ;; normally push the ; for keyword parms, push id and default value (push (if kargs parm (cadr parm)) parms) (if (token-is :co) (parse-token) (setf expecting nil))) (if (token-is :rp) (parse-token) (errexit "expected right parenthesis")) ;(display "parse-parms" (reverse parms)) (reverse parms))) (defun parse-bindings () (let (bindings bind) (setf *rslt* (parse-token)) ; skip "variable" or "with" ; return token as "extra" return value (setf bind (parse-bind)) (push (if (second bind) bind (car bind)) bindings) (while (token-is :co) (parse-token) (setf bind (parse-bind)) ;; if non-nil initializer, push (id expr) (push (if (second bind) bind (car bind)) bindings)) (reverse bindings))) (defun parse-bind () (let (id val) (if (token-is :id nil) (setf id (token-lisp (parse-token))) (errexit "expected a variable name")) (cond ((token-is :=) (parse-token) (setf val (parse-sexpr)))) (push id *sal-local-variables*) (list id val))) (defun parse-chdir () ;; assume next token is :chdir (or (token-is :chdir) (error "parse-chdir internal error")) (let (path loc) (setf loc (parse-token)) (setf path (parse-path)) (add-line-info-to-stmt (list 'setdir path) loc))) (defun parse-play () ;; assume next token is :play (or (token-is :play) (error "parse-play internal error")) (let ((loc (parse-token))) (add-line-info-to-stmt (list 'sal-play (parse-sexpr)) loc))) (defun parse-return () (or (token-is :return) (error "parse-return internal error")) (let (loc expr) ;; this seems to be a redundant test (if (and (null *sal-fn-name*) (not *audacity-top-level-return-flag*)) (errexit "Return must be inside a function body")) (setf loc (parse-token)) (setf expr (parse-sexpr)) (if *sal-fn-name* (add-line-info-to-stmt (list 'sal-return-from *sal-fn-name* expr) loc) (list 'defun 'main '() (list 'sal-trace-enter '(quote main) '() '()) (add-line-info-to-stmt expr loc))))) (defun parse-load () ;; assume next token is :load (or (token-is :load) (error "parse-load internal error")) (let (path args loc) (setf loc (parse-token)) (setf path (parse-path)) ; must return path or raise error (setf args (parse-keyword-args)) (add-line-info-to-stmt (cons 'sal-load (cons path args)) loc))) (defun parse-keyword-args () (let (args) (while (token-is :co) (parse-token) (cond ((token-is :key) (push (token-value) args) (push (parse-sexpr) args)))) (reverse args))) '(defun parse-system () ;; assume next token is :system (or (token-is :system) (error "parse-system internal error")) (let (path arg args) (parse-token) (setf path (parse-sexpr)) (list 'sal-system path))) (defun parse-path () (if (token-is '(:id :string)) (token-lisp (parse-token)) (errexit "path not found"))) (defun parse-print-display (token function) ;; assumes next token is :print (or (token-is token) (error "parse-print-display internal error")) (let (args arg loc) (setf loc (parse-token)) (setf arg (parse-sexpr)) (setf args (list arg)) (while (token-is :co) (parse-token) ; remove and ignore the comma (setf arg (parse-sexpr)) (push arg args)) (add-line-info-to-stmt (cons function (reverse args)) loc))) ;(defun parse-output () ; ;; assume next token is :output ; (or (token-is :output) (error "parse-output internal error")) ; (parse-token) ; (list 'sal-output (parse-sexpr))) (defun maybe-parse-block () (if (token-is :begin) (parse-block))) (defun parse-block () ;; assumes next token is :block (or (token-is :begin) (error "parse-block internal error")) (let (args stmts (locals *sal-local-variables*)) (parse-token) (cond ((token-is :with) (setf args (parse-bindings)))) (while (not (token-is :end)) (push (parse-stmt) stmts)) (parse-token) (setf stmts (reverse stmts)) ;(display "parse-block" args stmts) (setf *sal-local-variables* locals) (cons 'prog* (cons args stmts)))) ;; MAKE-STATEMENT-LIST -- convert stmt to a stmt list ;; ;; if it is a (PROGN ...) then return cdr -- it's already a list ;; otherwise, put single statement into a list ;; (defun make-statement-list (stmt) (cond ((atom stmt) (list stmt)) ((eq (car stmt) 'progn) (cdr stmt)) (t (list stmt)))) (setf *conditional-tokens* '(:if :when :unless)) (defun maybe-parse-conditional () (if (token-is *conditional-tokens*) (parse-conditional))) (defun parse-conditional () ;; assumes next token is :if (or (token-is *conditional-tokens*) (error "parse-conditional internal error")) (let (test then-stmt else-stmt if-token) (cond ((token-is :if) (setf if-token (parse-token)) (setf test (parse-sexpr if-token)) (if (not (token-is :then)) (errexit "expected then after if")) (parse-token) (if (not (token-is :else)) ;; no then statement (setf then-stmt (parse-stmt))) (cond ((token-is :else) (parse-token) (setf else-stmt (parse-stmt)))) ;(display "cond" test then-stmt else-stmt) (if else-stmt (list 'if test then-stmt else-stmt) (list 'if test then-stmt))) ((token-is :when) (parse-token) (setf test (parse-sexpr)) (setf then-stmt (parse-stmt)) (cons 'when (cons test (make-statement-list then-stmt)))) ((token-is :unless) (parse-token) (setf test (parse-sexpr)) (setf else-stmt (parse-stmt)) (cons 'unless (cons test (make-statement-list else-stmt))))))) (defun maybe-parse-assignment () (if (token-is :set) (parse-assignment))) (defun parse-assignment () ;; first token must be set (or (token-is :set) (error "parse-assignment internal error")) (let (assignments rslt vref op expr set-token) (setf set-token (parse-token)) (push (parse-assign) assignments) ; returns (target op value) (while (token-is :co) (parse-token) ; skip the comma (push (parse-assign) assignments)) ; now assignments is ((target op value) (target op value)...) (dolist (assign assignments) (setf vref (first assign) op (second assign) expr (third assign)) (cond ((eq op '=)) ((eq op '-=) (setf expr `(diff ,vref ,expr))) ((eq op '+=) (setf expr `(sum ,vref ,expr))) ((eq op '*=) (setq expr `(mult ,vref ,expr))) ((eq op '/=) (setq expr `(/ ,vref ,expr))) ((eq op '&=) (setq expr `(nconc ,vref (list ,expr)))) ((eq op '@=) (setq expr `(cons ,expr ,vref))) ((eq op '^=) (setq expr `(nconc ,vref (append ,expr nil)))) ((eq op '<=) (setq expr `(min ,vref ,expr))) ((eq op '>=) (setq expr `(max ,vref ,expr))) (t (errexit (format nil "unknown assigment operator ~A" op)))) (push (list 'setf vref expr) rslt)) (setf rslt (add-line-info-to-stmts rslt set-token)) (if (> (length rslt) 1) (cons 'progn rslt) (car rslt)))) ;; PARSE-ASSIGN -- based on parse-bind, but with different operators ;; ;; allows arbitrary term on left because it could be an array ;; reference. After parsing, we can check that the target of the ;; assignment is either an identifier or an (aref ...) ;; (defun parse-assign () (let ((lhs (parse-term) op val)) (cond ((token-is '(:= :-= :+= :*= :/= :&= :@= :^= :<= :>=)) (setf op (parse-token)) (setf op (if (eq (token-type op) ':=) '= (token-lisp op))) (setf val (parse-sexpr)))) (cond ((and (consp lhs) (eq (car lhs) 'aref))) ;; aref good ((symbolp lhs)) ;; id good (t (errexit "expected a variable name or array reference"))) (list lhs op val))) (defun maybe-parse-loop () (if (token-is :loop) (parse-loop))) ;; loops are compiled to do* ;; bindings go next as usual, but bindings include for variables ;; and repeat is converted to a for +count+ from 0 to ;; stepping is done after statement ;; termination clauses are combined with OR and ;; finally goes after termination ;; statement goes in do* body ;; (defun parse-loop () (or (token-is :loop) (error "parse-loop: internal error")) (let (bindings termination-tests stmts sexpr rslt finally loc (locals *sal-local-variables*)) (parse-token) ; skip "loop" (if (token-is :with) (setf bindings (reverse (parse-bindings)))) (while (token-is '(:repeat :for)) (cond ((token-is :repeat) (setf loc (parse-token)) (push (list 'sal:loopcount 0 '(1+ sal:loopcount)) bindings) (setf sexpr (parse-sexpr loc)) ; get final count expression (push (list 'sal:loopfinal sexpr) bindings) (push '(>= sal:loopcount sal:loopfinal) termination-tests)) ((token-is :for) (setf rslt (parse-for-clause)) ; there can be multiple bindings, build bindings in reverse (cond ((first rslt) (setf bindings (append (reverse (first rslt)) bindings)))) (if (second rslt) (push (second rslt) termination-tests))))) (while (token-is '(:while :until)) (cond ((token-is :while) (setf loc (parse-token)) (push (list 'not (parse-sexpr loc)) termination-tests)) ((token-is :until) (setf loc (parse-token)) (push (parse-sexpr loc) termination-tests)))) ; (push (parse-stmt) stmts) (while (not (token-is '(:end :finally))) (push (parse-stmt) stmts)) (cond ((token-is :finally) (parse-token) ; skip "finally" (setf finally (parse-stmt)))) (if (token-is :end) (parse-token) (errexit "expected end after loop")) (setf *sal-local-variables* locals) `(do* ,(reverse bindings) ,(list (or-ize (reverse termination-tests)) finally) ,@(reverse stmts)))) ;; OR-IZE -- compute the OR of a list of expressions ;; (defun or-ize (exprs) (if (> 1 (length exprs)) (cons 'or exprs) (car exprs))) (defun maybe-parse-exec () (if (token-is :exec) (parse-exec))) (defun parse-exec () (or (token-is :exec) (error "parse-exec internal error")) (let ((loc (parse-token))) ; skip the :exec (parse-sexpr loc))) (defun maybe-parse-exit () (if (token-is :exit) (parse-exit))) (defun parse-exit () (let (tok loc) (or (token-is :exit) (error "parse-exit internal error")) (setf loc (parse-token)) ; skip the :exit (cond ((token-is :id) (setf tok (parse-token)) (cond ((eq (token-lisp tok) 'nyquist) (add-line-info-to-stmt '(exit) loc)) ((eq (token-lisp tok) 'sal) (add-line-info-to-stmt '(sal-exit) loc)) (t (errexit "expected \"nyquist\" or \"sal\" after \"exit\"")))) (t (add-line-info-to-stmt '(sal-exit) loc))))) ;; PARSE-FOR-CLAUSE - returns (bindings term-test) ;; (defun parse-for-clause () (or (token-is :for) (error "parse-for-clause: internal error")) (let (id init next rslt binding term-test list-id loc) (setf loc (parse-token)) ; skip for (if (token-is :id) (setf id (token-lisp (parse-token))) (errexit "expected identifier after for")) (cond ((token-is :=) ;; if the clause is just for id = expr, then assume that ;; expr depends on something that changes each iteration: ;; recompute and assign expr to id each time around (parse-token) ; skip "=" (setf init (parse-sexpr loc)) (cond ((token-is :then) (parse-token) ; skip "then" (setf binding (list id init (parse-sexpr loc)))) (t (setf binding (list id init init)))) (setf binding (list binding))) ((token-is :in) (setf loc (parse-token)) ; skip "in" (setf list-id (intern (format nil "SAL:~A-LIST" id))) (setf binding (list (list list-id (parse-sexpr loc) (list 'cdr list-id)) (list id (list 'car list-id) (list 'car list-id)))) (setf term-test (list 'null list-id))) ((token-is :over) (setf loc (parse-token)) ; skip "over" (setf start (parse-sexpr loc)) #| (cond ((token-is :by) (parse-token) ; skip "by" (parse-sexpr))) ;-- I don't know what "by" means - RBD |# (setf list-id (intern (format nil "SAL:~A-PATTERN" id))) (setf binding (list (list list-id start) (list id (list 'next list-id) (list 'next list-id))))) ((token-is '(:from :below :to :above :downto :by)) (cond ((token-is :from) (setf loc (parse-token)) ; skip "from" (setf init (parse-sexpr loc))) (t (setf init 0))) (cond ((token-is :below) (setf loc (parse-token)) ; skip "below" (setf term-test (list '>= id (parse-sexpr loc)))) ((token-is :to) (setf loc (parse-token)) ; skip "to" (setf term-test (list '> id (parse-sexpr loc)))) ((token-is :above) (setf loc (parse-token)) ; skip "above" (setf term-test (list '<= id (parse-sexpr loc)))) ((token-is :downto) (setf loc (parse-token)) ; skip "downto" (setf term-test (list '< id (parse-sexpr loc))))) (cond ((token-is :by) (setf loc (parse-token)) ; skip "by" (setf binding (list id init (list '+ id (parse-sexpr loc))))) ((or (null term-test) (and term-test (member (car term-test) '(>= >)))) (setf binding (list id init (list '1+ id)))) (t ; loop goes down because of "above" or "downto" ; (display "for step" term-test) (setf binding (list id init (list '1- id))))) (setf binding (list binding))) (t (errexit "for statement syntax error"))) (list binding term-test))) ;; parse-sexpr works by building a list: (term op term op term ...) ;; later, the list is parsed again using operator precedence rules (defun parse-sexpr (&optional loc) (let (term rslt) (push (parse-term) rslt) (while (token-is *sal-operators*) (push (token-type (parse-token)) rslt) (push (parse-term) rslt)) (setf rslt (reverse rslt)) ;(display "parse-sexpr before inf->pre" rslt) (setf rslt (if (consp (cdr rslt)) (inf->pre rslt) (car rslt))) (if loc (setf rslt (add-line-info-to-expression rslt loc))) rslt)) (defun get-lisp-op (op) (third (assoc op +operators+))) ;; a term is , or ;; ( ), or ;; ? ( , , ), or ;; , or ;; ( ), or ;; [ ] ;; Since any term can be followed by indexing, handle everything ;; but the indexing here in parse-term-1, then write parse-term ;; to do term-1 followed by indexing operations ;; (defun parse-term-1 () (let (sexpr id) (cond ((token-is '(:- :!)) (list (token-lisp (parse-token)) (parse-term))) ((token-is :lp) (parse-token) ; skip left paren (setf sexpr (parse-sexpr)) (if (token-is :rp) (parse-token) (errexit "right parenthesis not found")) sexpr) ((token-is :?) (parse-ifexpr)) ((token-is :lc) (list 'quote (parse-list))) ((token-is '(:int :float :bool :list :string)) ;(display "parse-term int float bool list string" (car *sal-tokens*)) (token-lisp (parse-token))) ((token-is :id) ;; aref or funcall (setf id (token-lisp (parse-token))) ;; array indexing was here, but that only allows [x] after ;; identifiers. Move this to expression parsing. (cond ((token-is :lp) (parse-token) (setf sexpr (cons id (parse-pargs t))) (if (token-is :rp) (parse-token) (errexit "right paren not found")) sexpr) (t id))) (t (errexit "expression not found"))))) (defun parse-term () (let ((term (parse-term-1))) ; (display "parse-term" term (token-is :lb)) (while (token-is :lb) (parse-token) (setf term (list 'aref term (parse-sexpr))) (if (token-is :rb) (parse-token) (errexit "right bracket not found"))) term)) (defun parse-ifexpr () (or (token-is :?) (error "parse-ifexpr internal error")) (let (condition then-sexpr else-sexpr) (parse-token) ; skip the :? (if (token-is :lp) (parse-token) (errexit "expected left paren")) (setf condition (parse-sexpr)) (if (token-is :co) (parse-token) (errexit "expected comma")) (setf then-sexpr (parse-sexpr)) (if (token-is :co) (parse-token) (errexit "expected comma")) (setf else-sexpr (parse-sexpr)) (if (token-is :rp) (parse-token) (errexit "expected left paren")) (list 'if condition then-sexpr else-sexpr))) (defun keywordp (s) (and (symbolp s) (eq (type-of (symbol-name s)) 'string) (equal (char (symbol-name s) 0) #\:))) (defun functionp (x) (eq (type-of x) 'closure)) (defun parse-pargs (keywords-allowed) ;; get a list of sexprs. If keywords-allowed, then at any point ;; the arg syntax can switch from [ ]* to ;; [ ]* ;; also if keywords-allowed, it's a function call and the ;; list may be empty. Otherwise, it's a list of indices and ;; the list may not be empty (let (pargs keyword-expected sexpr keyword) (if (and keywords-allowed (token-is :rp)) nil ; return empty parameter list (loop ; look for one or more [keyword] sexpr ; optional keyword test (setf keyword nil) ;(display "pargs" (car *sal-tokens*)) (if (token-is :key) (setf keyword (token-lisp (parse-token)))) ; (display "parse-pargs" keyword) ; did we need a keyword? (if (and keyword-expected (not keyword)) (errexit "expected keyword")) ; was a keyword legal (if (and keyword (not keywords-allowed)) (errexit "keyword not allowed here")) (setf keyword-expected keyword) ; once we get a keyword, we need ; one before each sexpr ; now find sexpr (setf sexpr (parse-sexpr)) (if keyword (push keyword pargs)) (push sexpr pargs) ; (display "parse-pargs" keyword sexpr pargs) (cond ((token-is :co) (parse-token)) (t (return (reverse pargs)))))))) ;; PARSE-LIST -- parse list in braces {}, return list not quoted list ;; (defun parse-list () (or (token-is :lc) (error "parse-list internal error")) (let (elts) (parse-token) (while (not (token-is :rc)) (cond ((token-is '(:int :float :id :bool :key :string)) (push (token-lisp (parse-token)) elts)) ((token-is :lc) (push (parse-list) elts)) (t (errexit "expected list element or right brace")))) (parse-token) (reverse elts))) (defparameter *op-weights* '( (:\| 1) (:& 2) (:! 3) (:= 4) (:!= 4) (:> 4) (:>= 4) (:< 4) (:<= 4) (:~= 4) ; general equality (:+ 5) (:- 5) (:% 5) (:* 6) (:/ 6) (:^ 7) (:~ 8) (:~~ 8) (:@ 8) (:@@ 8))) (defun is-op? (x) ;; return op weight if x is operator (let ((o (assoc (if (listp x) (token-type x) x) *op-weights*))) (and o (cadr o)))) (defun inf->pre (inf) ;; this does NOT rewrite subexpressions because parser applies rules ;; depth-first so subexprs are already processed (let (op lh rh w1) (if (consp inf) (do () ((null inf) lh) (setq op (car inf)) ; look at each element of in (pop inf) (setq w1 (is-op? op)) (cond ((numberp w1) ; found op (w1 is precedence) (do ((w2 nil) (ok t) (li (list))) ((or (not inf) (not ok)) (setq rh (inf->pre (nreverse li))) (setq lh (if lh (list (get-lisp-op op) lh rh) (list (get-lisp-op op) rh nil)))) (setq w2 (is-op? (first inf))) (cond ((and w2 (<= w2 w1)) (setq ok nil)) (t (push (car inf) li) (pop inf))))) (t (setq lh op)))) inf))) nyquist-3.05/runtime/rawwaves/0002755000175000000620000000000011537433122015510 5ustar stevestaffnyquist-3.05/runtime/rawwaves/mand9.raw0000644000175000000620000000400011466723256017236 0ustar stevestaff(9$? ,R9P k>d XM?g{"3'wi#$Z}   "=~z8@ B.kV+PI[Bm=.F$jN5JHL3d]X+zn[:Y:xe;bP<B@/6g@C96I" w|al% pMb2T b2+L+b |q\ 6HyrDcCEzB#8 cT1.Kq08??XTqtoYxsfi `HeH+( TgnHx_OPlgF1>bl_a{   %'0>@6,0BT`T, 7Vi`? &446E`x~qW1S.,Gdy -=CLZnzxoged\E/(+6Lerm\QLH:# ()$ '19G_vu`N=0**.11*      ###%&()& nyquist-3.05/runtime/rawwaves/mand8.raw0000644000175000000620000000400011466723256017235 0ustar stevestaffSR7($rz-kRJ1WbRN&`LaL|h D p;t0$MkzC5G5)B{lQ(%;k2sdu/7y>( 9 5b9ud9uI%_\]'ibngT6(=;2Dl 5Rcdu 9aztxkN02MUQIJH<$q]YVPJA949:9=HXhw)G^kztYD7*|dH623+&4DWjz&++-,*' !*67/)$(,($&.31,(-:EIKLLKJD@=842/% |smkhdfmu0DS`lsxyvsqrqoqz~vk`TG<4,'$     #',88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888nyquist-3.05/runtime/rawwaves/marmstk1.raw0000644000175000000620000000100011466723256017762 0ustar stevestaff - i02 T|og1;sd h'>Q-;# Ҕ( *eh O5 )A CE>/^+s cV tP5qC  R^d  ) Y <F }ocC ` m ;XesE Bt olw R#V N fWn<* LRnyquist-3.05/runtime/rawwaves/mandpluk.raw0000644000175000000620000002130411466723256020047 0ustar stevestaff e  Kr sٶަ7mP6L`[nt[p-eW?H8!?ýק Z\¼q=0*Qy678[s|yqji>knlbP_;R)} #. 8<5(&~7 xQ : ZB$&[¦^ ? "): Qdpу*Ւj00hU  p'+a)$c &58E4PUUUY_c`SA1<)z,5]?D{D_@`:|3Q* &LX3zа͜nRQPȼKlSܹܞJ/g MN+ ""_ eR'5CKKC 701=PLXwZxR?D70/L/.( w KD k  $>a͵,J"pU(ާ)ƻh8дەT iaDy r!)6F841C-) "WRR 2 er?&a HOѦBtЍTZ2MAilX&MDݷd1b7{#S ]"2',*19CMSfS6M7D;7P7j:e=d> ;71,(/$ 3 Gw)jU'X{t=Wd͞nհ^ӎyKѺ;ɞũȬ(ڄ޴nC8+sZ o Zls^f#/";CE{LSOPNFJE%>8(2.l+)&K"5% LP^xYE߻ۢqӑڲ7:Rρ2آڪM/x: m).] q&E,J16;@F.K; 7333/,*A'$ {}  V\d*ߋ9LV2[k&y}L$4 w D! Bc`P#(-//.,)e& " L, ~?)2 2>+XZ!gjsoN>ks:U`~H? \ @ U\pr8z#!=ne 1A=UT!lbaeySTKMsmChU=]9"]5- t y= \eX}uvz<4M`J < "U:@sQ"cC?*}b\y_OFIW;.YG q ` 00wc*j6  .|0pcg1@JvFdP0R7Z@Fz,l^ Z V 8 { - C7  _I3J!5YqS3^]kvvYDDaSTDu71TU k-KlC7mQ%0bhQcc&H[^ZROF, Nm#xMmE3[ /, Z9j3c!xC>l GW0htrncZcyQ)Yu=/geJ605;8'S,~OA] 0j*G Fi VYJNNJ%-V4gB_XA,! uf} b}%c. }ML~ZXdgPu ]&(}dsMVMNkO)hxjVN%.'mxul66OUD!@UO/yf-YS_9|8jOW>mvgl(SxMwy]3[|b9I2Tt+`=)2&lO8,0Fl/bSkVNUbh[8l@Z)>oi&^0B(-gAZ MP0Sd^E'  \'5jp&xa`~l%%j8]qkT%zL=jqN;83Y) W qhkx ;u"m+:|(BUrLvup[-h`[L21w &^\!<b KN*e5>sG $Do xN(B4?pDK  dGcjo~M{mW- `3s0>i0~r]=##C$j8d3Xj_<Jd}5}X0dk0_iL:5ASj 6GB!fP:lXXo8B0et.~^?j4OSP~U#r>ZsAay{_;uP&AvcR`#j"8;'uP&udWPRXcr ,Syx[D?FOP>iF kK5),>d2'm%0.$p\O?'}} 6Sm~{U j~kc^ao R#//&!06,p^PJJMOJ>-$8XD9[qvhJ'i0~Z45Mg?VXJ9//6;6gI&*Rr 3VuyV#m[G, F{Bb|o<U/8o!,3ARj^85m5^~bMDGLJ<lU@2-2@P^gmr,000232* xaM=/))-4;FWm5Xs~R&`q [W$Ll~pd[VV[agllia\SF2 '?[us<f5!>]*Uig\RMORSSOLD6P/iGxrU;!mL4# -=LZi 6RYUPUi{[;#pD-UzJiy~||{uiS>0/9LVUD$iF#2Oo&Oro> gF#0Pjusld`co 0IasyuoigaO,udXM@7=U}!Bi~_A' U& -S-D\vjI!l^`o 3Ldx|jP- {L# $Do&29?DIP[gsyviO0iUMORUSUXdxFjydFU2 #$!#8Xz;XppBoS8$*Dg ,?B<0))-5;93'^C>Znyquist-3.05/runtime/rawwaves/mand1.raw0000644000175000000620000000400011466723256017226 0ustar stevestaff&ǔ6.! XU 8r ,$qPwlD5rC*Z0d -!9kpL (L{&,qeAt)LtVJ(,owW~TL 6Xp Z  K 2  g Z - z*?<[x{gS,@c:rI#iZ!HSh m Du Ub/HQ{b&5|rQX,"NYzW.y*X6HNs`s@Guo168mP&hJMr}#h!S\?r4K";O/9uYZw(< .l$7!]@M1 <St,\ wRZr^ !8u[Vw & JFb:YcOZJ;.qP%mZj-Fetkj/IpoVJ*`SZI\0$B]{Be qasnyquist-3.05/runtime/rawwaves/mand4.raw0000644000175000000620000000400011466723256017231 0ustar stevestaffh7w}.\ (f!~A< x4pV'pC 2 +  2 . y wu J wO U'1s}x6~$,+8uzc U y9 oJ;!w 8i#Wtt-uIrP kYl9VdOn`^Y VNZA 3!N&B#RT!I(Gb}-d L7~Neh=m)QQokEy#REh(64wb+ bQmKEDQE?v9d_O#Xxk{R  W]ypuh<3JU7j]+ gtuK 2_~1jb_nB-Mj^bV#  $,0;JUbt{febB "4CC=;H\jkhl}xqz|dOCBA@51+1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111nyquist-3.05/runtime/rawwaves/mand3.raw0000644000175000000620000000400011466723256017230 0ustar stevestaff\Ybb!&0 i X%O<K9mJRN| !6BD 7,.x !j !  B 8 J9` Gt(=:N#V(N T  % 9*  0 D 0"4~Gtf>f=X+=n ,g ^ku_$ >I/z:U/r X  H b5H>pJGO<* jwQ _}[V:&T%e s,Q|-Ljghw*1YNDC;o5{n1$gOz~lp~ =*!7QC(HKReQ cO:%\ ~G3z]a!GK7!/Gi1b}xcLL]mm\^qnyquist-3.05/runtime/rawwaves/mand2.raw0000644000175000000620000000400011466723256017227 0ustar stevestaffe^en9e  ff[jho?\y`tFf=  c M   e I 3 h  *>dn>W @O U d1x4b3 sQ  r TF(p&\j`l8"gtq 47PTuTj* .z$!>;xNCQeISN UX=V1H'si) 4:H-^9TY:[l(u^}@g+<6 uY.dL<2"##AGf$2B]fJ tbI3 jD!&,:YO8FVgr{xmlwzrovol|ubaliT5 Clp\LGE=1nyquist-3.05/runtime/rawwaves/mand10.raw0000644000175000000620000000400011466723256017306 0ustar stevestaff#}$"Zka $42 %=_UP=gK< /   + +"i;lq^{ FlfJ0fCH{o^U-r3{kV`DNWJh_HxqMd0 s{JF#*R+6 MkOA%6'|q6g3m#g;3Z"Wk)S[@|1\A")%6t KF! C6fu 5%Q/}@m\A@*y{B'aQ8z3KTQPlQ0 Vlc,[g@! M>nb$f< #4AZsW;ARjwqTPg]#k: h/`8#%2=K`}/dK9WklX>(uXC/ )01159<BINQJDC?>BLNHBFV]N1hK@@9'%//(%.D]nuz-Nh| "# wcRD3lVQPG6'#)30063& nyquist-3.05/runtime/rawwaves/sinewave.raw0000644000175000000620000000400011466723256020047 0ustar stevestaff[$~G j 2 Sr9Um3F V !a"#"#$g%'%&'g(&()*a++,-T../0A012m3&345M667o8$89:?:;g??@sA AByC%CDzE#EFtGGHiIIJWJKL?LMN NO]OPQ3QRhSST2TU_UVWWXBXYcYZ[[\(\]=]^O^_]_`g`anabqbcpcdkdebefVfgEgh1hiiijljkJkl#llmamn0nno^op"ppq@qqrTrss^st t^tuuTuuv@vvw"wkwwx?xxyyIyyzzAz|zz{%{\{{{|)|Y|||}}8}a}}}}~~>~^~~~~~~ 7LattaL7 ~~~~~~~^~>~}}}}}a}8}||||Y|){{{{\{%zzz|zAzyyyIyxxx?wwwkw"vvv@uuuTutt^t ss^srrTqqq@ppp"oo^nnn0mmalll#kkJjjliiihh1ggEffVeebddkccpbbqaan``g__]^^O]]=\\([[ZYYcXXBWWVUU_TT2SSRhQQ3POO]NN MLL?KJJWIIHiGGFtEE#DzCC%ByAA @s??>g==OtZO./P (UON\>_t}X>7G2wXu> il?< uGoEQPv&M< [ sjgsr|cplmvcP\t5EOh"6@@@?GPB% }yub;oK!5=3"%7L^hr&#3:G^yyv}|vx~{zzyyrj`SHABFD8*###!!! ysrtmaUPSXajx "29;?Oah`RR[dmsz}reZPIB81/(  &7=DKMRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRnyquist-3.05/runtime/rawwaves/mand7.raw0000644000175000000620000000400011466723256017234 0ustar stevestaffsv0$nLV'c t~f')/%5]M0Kx Kg,v-7/eP}Y H@|aKH  @gl`=ah.O:XzfJX:SEO }u\ (/2\O8o;n\b8[Rvk I^G"QcRl:n<;Xq88NdQ$c> 'ZRH.U()<cJh n<!2O" bAD"rI^eq  (Hl}8oC yx~zyz&8+ {t_L@?JXf]9+<`Y#E^_M/ #pfkgKh6 -$.*"##{uutr{%0CWdmv{{||ywoeZQB* }~!*1AT\\^a_YWSLLONHEA>7+%&&$!$)/-&nyquist-3.05/runtime/xlinit.lsp0000644000175000000620000000311111466723256015705 0ustar stevestaff;; xlinit.lsp -- standard definitions and setup code for XLisp ;; (defun bt () (baktrace 6)) (defmacro setfn (a b) `(setf (symbol-function ',a) (symbol-function ',b))) (setfn co continue) (setfn top top-level) (setfn res clean-up) (setfn up clean-up) ;## display -- debugging print macro ; ; call like this (display "heading" var1 var2 ...) ; and get printout like this: ; "heading : VAR1 = VAR2 = ..." ; ; returns: ; (let () ; (format t "~A: " ,label) ; (format t "~A = ~A " ',item1 ,item1) ; (format t "~A = ~A " ',item2 ,item2) ; ...) ; (defmacro display-macro (label &rest items) (let ($res$) (dolist ($item$ items) (setq $res$ (cons `(format t "~A = ~A " ',$item$ ,$item$) $res$))) (append (list 'let nil `(format t "~A : " ,label)) (reverse $res$) '((terpri))))) (defun display-on () (setfn display display-macro) t) (defun display-off () (setfn display or) nil) (display-on) ; (objectp expr) - object predicate ; ;this is built-in: (defun objectp (x) (eq (type-of x) 'OBJ)) ; (filep expr) - file predicate ; (defun filep (x) (eq (type-of x) 'FPTR)) (load "profile.lsp" :verbose NIL) (setq *breakenable* t) (setq *tracenable* nil) (defmacro defclass (name super locals class-vars) (if (not (boundp name)) (if super `(setq ,name (send class :new ',locals ',class-vars ,super)) `(setq ,name (send class :new ',locals ',class-vars))))) ;(cond ((boundp 'application-file-name) ; (load application-file-name))) (setq *gc-flag* t) nyquist-3.05/runtime/equalizer.lsp0000644000175000000620000000432011466723256016402 0ustar stevestaff;; equalizer.lsp -- support functions for equalizer editor in jNyqIDE #| This is modeled after envelopes.lsp, which details how envelope data is exchanged between Nyquist and jNyqIDE. The jNyqIDE code needs some work to make it look like the envelope editor (which also needs work, but that's another matter). For consistency, both should support named envelopes and equalizers. However, for now, we have equalizers numbered from 0 to 9. The format for exchange will be: get-eq-data: begin name parameters newline name parameters newline ... get-eq-data: end and when the IDE wants to save a definition, it should call (DEFINE-EQ 'NAME 'PARAMETER-LIST) |# (cond ((not (boundp '*equalizers*)) (setf *equalizers* nil))) ;; DEFINE-EQ -- save the eq data and make corresponding function ;; (defun define-eq (name expression) (setf *equalizers* (remove name *equalizers* :test #'(lambda (key item) (eql key (car item))))) (push (list name expression) *equalizers*) (make-eq-function name expression) ; make sure equalizers are redefined when workspace is loaded (add-to-workspace '*equalizers*) (describe '*equalizers* "data for equalizers in jNyqIDE") (add-action-to-workspace 'make-eq-functions) nil) ;; MAKE-EQ-FUNCTION -- convert data to a defined function ;; (defun make-eq-function (name parameters) (cond ((numberp name) (setf name (intern (format nil "EQ-~A" name))))) (if (not (boundp '*grapheq-loaded*)) (load "grapheq.lsp")) (setf (symbol-function name) (eval `(lambda (s) (nband-range s ',parameters 60 14000))))) ;; MAKE-EQ-FUNCTIONS -- convert data to defined functions ;; (defun make-eq-functions () (let (name type parameters) (dolist (eq *equalizers*) (setf name (car eq)) (setf parameters (second parameters)) (make-eq-function name parameters)))) ;; GET-EQ-DATA -- print env data for IDE ;; (defun get-eq-data () (let (parameters) (princ "get-eq-data: begin\n") (dolist (env *equalizers*) (format t "~A" (car env)) (setf parameters (second env)) (dotimes (i (length parameters)) (format t " ~A" (aref parameters i))) (format t "~%")) (princ "get-eq-data: end\n") nil)) nyquist-3.05/runtime/nyquist-plot.txt0000644000175000000620000000005010144436365017100 0ustar stevestaffset nokey plot "points.dat" with lines nyquist-3.05/runtime/envelopes.lsp0000644000175000000620000001227111466723256016405 0ustar stevestaff;; envelopes.lsp -- support functions for envelope editor in jNyqIDE #| In Nyquist, editable envelopes are saved as one entry in the workspace named *envelopes*. The entry is an association list where each element looks like this: (name type parameters... ) where name is a symbol, e.g. MY-ENVELOPE-1, type is a function name, e.g. PWL, PWLV, PWE, etc., and parameters are breakpoint data, e.g. 0.1 1 0.2 0.5 1 Example of two envelopes named FOO and BAR: ((FOO PWL 0.1 1 1) (BAR PWE 0.2 1 1)) To convert envelope data into functions, call (MAKE-ENV-FUNCTIONS). This function should be on the workspace's list of functions to call. (See ADD-ACTION-TO-WORKSPACE in Nyquist Manual.) When the jNyqIDE wants to get the envelope data from the workspace, it should call (GET-ENV-DATA), which will dump formatted data to Nyquist's standard output as follows: get-env-data: begin name (type parameters...) newline name (type parameters...) newline ... get-env-data: end When the IDE wants to save a definition, it should call (DEFINE-ENV 'NAME 'EXPRESSION) To delete a definition, call: (DELETE-ENV 'NAME) Envelope data will be loaded when the editor window is opened and saved whenever the user issues a "save" command. If the user switches envelopes without saving, there is a prompt to save or ignore. The user will also be prompted to save when the editor window is closed or when Nyquist is exited. Saving the workspace automatically is something that Nyquist should do (or prompt the user to do) when it exits. |# ;; WORKSPACE -- the workspace is just a set of variables, typically ;; with scores as values. These are stored in the file workspace.lsp ;; so that you can work on some data and then store it for use later. (cond ((not (boundp '*workspace*)) (setf *workspace* nil))) (cond ((not (boundp '*workspace-actions*)) (setf *workspace-actions* nil))) ;; one of the variables in the workspace is *envelopes* (cond ((not (boundp '*envelopes*)) (setf *envelopes* nil))) ;; DESCRIBE -- add a description to a global variable ;; (defun describe (symbol &optional description) (add-to-workspace symbol) (cond (description (putprop symbol description 'description)) (t (get symbol 'description)))) ;; ADD-TO-WORKSPACE -- add a global symbol to workspace ;; (defun add-to-workspace (symbol) (cond ((not (symbolp symbol)) (format t "add-to-workspace expects a (quoted) symbol~%")) ((not (member symbol *workspace*)) (push symbol *workspace*)))) ;; ADD-ACTION-TO-WORKSPACE -- call function when workspace is loaded ;; (defun add-action-to-workspace (symbol) (cond ((not (symbolp symbol)) (format t "add-action-to-workspace expects a (quoted) symbol~%")) ((not (member symbol *workspace-actions*)) (push symbol *workspace-actions*)))) ;; SAVE-WORKSPACE -- write data to file ;; (defun save-workspace () (let (val (outf (open "workspace.lsp" :direction :output))) (dolist (sym *workspace*) (format outf "(add-to-workspace '~A)~%" sym) (cond ((get sym 'description) (format outf "(putprop '~A \"~A\" 'description)~%" sym (get sym 'description)))) (format outf "(setf ~A '" sym) (setf val (symbol-value sym)) (cond ((listp val) (format outf "(~%") (dolist (elem val) (format outf " ~A~%" elem)) (format outf " ))~%~%")) (t (format outf "~A)~%~%" val)))) (dolist (sym *workspace-actions*) ;; call hooks after reading data (format outf "(add-action-to-workspace '~A)~%" sym) (format outf "(if (fboundp '~A) (~A))~%" sym sym)) (format outf "(princ \"workspace loaded\\n\")~%") (close outf) (princ "workspace saved\n") nil)) ;; DEFINE-ENV -- save the env data and make corresponding function ;; (defun define-env (name expression) (delete-env name) (push (cons name expression) *envelopes*) (make-env-function name expression) ; make sure envelopes are redefined when workspace is loaded (add-to-workspace '*envelopes*) ; so *envelopes* will be saved (describe '*envelopes* "data for envelope editor in jNyqIDE") (add-action-to-workspace 'make-env-functions) nil) ;; DELETE-ENV -- delete an envelope definition from workspace ;; ;; note that this will not undefine the corresponding envelope function ;; (defun delete-env (name) (setf *envelopes* (remove name *envelopes* :test #'(lambda (key item) (eql key (car item)))))) ;; MAKE-ENV-FUNCTION -- convert data to a defined function ;; (defun make-env-function (name expression) (setf (symbol-function name) (eval (list 'lambda '() expression)))) ;; MAKE-ENV-FUNCTIONS -- convert data to defined functions ;; (defun make-env-functions () (let (name type parameters) (dolist (env *envelopes*) (setf name (car env)) (setf type (cadr env)) (setf parameters (cddr env)) (make-env-function name (cons type parameters))))) ;; GET-ENV-DATA -- print env data for IDE ;; (defun get-env-data () (princ "get-env-data: begin\n") (dolist (env *envelopes*) (format t "~A ~A~%" (car env) (cdr env))) (princ "get-env-data: end\n") nil) nyquist-3.05/lpc/0002755000175000000620000000000011537433132012745 5ustar stevestaffnyquist-3.05/lpc/src/0002755000175000000620000000000011537433132013534 5ustar stevestaffnyquist-3.05/lpc/src/lpanal.h0000644000175000000620000000014710144436365015160 0ustar stevestaff/* lpanal.h -- LPC analysis */ LVAL snd_lpanal (LVAL v, long P); /* LISP: (SND-LPC ANY FIXNUM) */ nyquist-3.05/lpc/src/lpanal.c0000644000175000000620000000733110144436365015155 0ustar stevestaff/* lpc.c -- implement LPC analysis */ #include #ifndef mips #include "stdlib.h" #endif #include "xlisp.h" void abs_max(double *x, long desde, long hasta, double *x_maxptr, long *indptr) { /* use: abs_max(s,0,10,&mimax,&miind); */ double x_max = x[desde]; long ind = desde; long i; for(i = desde+1; i x_max) { x_max = fabs(x[i]); ind = i; } *x_maxptr = x_max; *indptr = ind; } void xcorr(double *s, double *rxx, long N) { /* use: xcorr(s,rxx,N); */ long i,j; for(i=0; i < N; i++) { rxx[i] = 0.0; for(j=0; j < N-i; j++) rxx[i] += s[j]*s[j+i]; } } // SOUND PARAMETERS // w Lisp vector containinig signal values // P number of poles // N length of sound // AUTOCORRELEATION PARAMETERS // rxx array containing autocorrelation coefs // max_rxx temporal maximun value of rxx // i_max index of max_rxx // LPC PARAMETERS // alpha array of filter coefs // k reflection coef // E residual energy // rms1 energy of input signal (not RMS) // rms2 residual energy = E // unv voiced/unvoiced parameter = ERR = rms2/rms1 // PITCH DETECTION ALGORITHM: Implemented separately LVAL snd_lpanal(LVAL w, long P) { double *s, *rxx; long N; double *alpha; // double *k, *E; THIS ONLY FOR VECTORIZED k AND E double k, E; double rms1; // rms2=E; double unv; double suma, alphatemp; // help variables long i,j; LVAL result; xlsave1(result); //// end vars ///////////// //// allocate memory /////// N = getsize(w); s = calloc(sizeof(double),N); //signal rxx = calloc(sizeof(double),N); //autocorrelation alpha = calloc(sizeof(double), P); // filter coefs //k = calloc(sizeof(double), P); // reflection coefs //E = calloc(sizeof(double), P); // residual energy ////// copy Lisp array sound data to array of double /////// for(i=0; i> 1); j++) { //alphatemp = alpha[j] - k[i] * alpha[i-j-1]; //alpha[i-j-1] -= k[i] * alpha[j]; //alpha[j] = alphatemp; alphatemp = alpha[j] - k * alpha[i-j-1]; alpha[i-j-1] -= k * alpha[j]; alpha[j] = alphatemp; } //E[i] = E[i-1] * (1 - pow(k[i],2)); E *= (1 - pow(k,2)); } // input signal energy = rxx[0]; rms1 = rxx[0]; // voiced/unvoiced unv= sqrt(E/rms1); ///// HERE: CHECK STABILITY AND MODIFY COEFS ///////////// ///// not implemented // prepare output result result = newvector(P); for (i = 0; i < P; i++) setelement(result, i, cvflonum(alpha[P-i-1])); // alpoles format xlpop(); // free memory free(s); free(rxx); free(alpha); return (cons (cvflonum(rms1), // input signal energy cons(cvflonum(E), // residual energy cons(cvflonum(unv), // ERR, voiced/unvoiced cons(result, NULL))))); // coefs } nyquist-3.05/lpc/src/lpreson.alg0000644000175000000620000000613310144436365015710 0ustar stevestaff(LPRESON-ALG (NAME "lpreson") (ARGUMENTS ("sound_type" "x_snd")("LVAL" "src")("time_type" "frame_time")) (SUPPORT-FUNCTIONS " #include \"samples.h\" ") (START (MIN x_snd)) (ALWAYS-SCALE x_snd) (TERMINATE (MIN x_snd)) (LOGICAL-STOP (MIN x_snd)) (SAMPLE-RATE "x_snd->sr") (STATE ("long" "fr_indx" "0") ("long" "ak_len" "0") ; length of coefs ak array ("long" "frame_length" "(long) (frame_time*x_snd->sr)") ; samples length ("LVAL" "src" "src") ("LVAL" "array" "NULL") ("double *" "ak_coefs" "NULL") ; coefs array ("double *" "zk_buf" "NULL") ; last values of output ("double" "gain" "1.0") ("long" "index" "0") ) (OUTER-LOOP " if (susp->src == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } if(susp->fr_indx >= susp->frame_length) susp->fr_indx -= susp->frame_length; if (susp->fr_indx==0) { long i; susp->array = xleval(cons(s_send, cons(susp->src, consa(s_next)))); if (susp->array == NULL) { susp->src = NULL; goto out; } /* en susp->array tenemos la lista proporcionada por el objeto */ else if (!listp(susp->array)) xlerror(\"list expected\", susp->array); susp->gain = getflonum(car(susp->array)); susp->array=car(cdr(susp->array)); if (!vectorp(susp->array)) { xlerror(\"array expected\", susp->array); } else if (susp->ak_coefs == NULL) { susp->ak_len = getsize(susp->array); if (susp->ak_len < 1) xlerror(\"array has no elements\", susp->array); susp->ak_coefs = (double *) calloc(susp->ak_len, sizeof(double)); susp->zk_buf = (double *) calloc(susp->ak_len, sizeof(double)); } /* at this point we have a new array and a place to put ak coefs */ for(i=0; i < susp->ak_len; i++) { LVAL elem = getelement(susp->array,i); if (ntype(elem) != FLONUM) { xlerror(\"flonum expected\", elem); } susp->ak_coefs[i] = getflonum(elem); } // printf(\"NUEVO FILTRO: \"); /* here for debug */ // for(k=0; k < susp->ak_len; k++) printf(\" %g \", susp->ak_coefs[k]); // printf(\"GAIN %g AKLEN %d \", susp->gain, susp->ak_len); susp->array = NULL; /* free the array */ } togo = min(susp->frame_length - susp->fr_indx, togo); ") (INNER-LOOP-LOCALS "double z0; long xi; long xj;") (INNER-LOOP " z0 = x_snd * gain; for (xi=0; xi < ak_len; xi++) { xj = index + xi; if (xj >= ak_len) xj -= ak_len; z0 += ak_coefs[xi] * zk_buf[xj]; } zk_buf[index] = z0; index++; if (index == ak_len) index = 0; fr_indx++; output = (sample_type) z0; ") (CONSTANT "frame_length" "src") (FINALIZATION " free(susp->ak_coefs); free(susp->zk_buf); ") ) nyquist-3.05/lpc/src/allpoles.alg0000644000175000000620000000417610144436365016046 0ustar stevestaff(ALLPOLES-ALG (NAME "allpoles") (ARGUMENTS ("sound_type" "x_snd")("LVAL" "ak_array")("double" "gain")) (START (MIN x_snd)) (NOT-IN-INNER-LOOP "ak_array") (ALWAYS-SCALE x_snd) (TERMINATE (MIN x_snd)) (LOGICAL-STOP (MIN x_snd)) (STATE ("long" "ak_len" "0") ; length of coefs ak array ("LVAL" "ak_array" "ak_array") ("double" "gain" "gain") ("double *" "ak_coefs" "NULL") ; coefs array ("double *" "zk_buf" "NULL") ; last values of output ("long" "index" "0") ) (OUTER-LOOP " if (susp->ak_array == NULL) { out: togo = 0; /* indicate termination */ break; /* we're done */ } else if (!vectorp(susp->ak_array)) xlerror(\"array expected\", susp->ak_array); else if (susp->ak_coefs == NULL) { long i; susp->ak_len = getsize(susp->ak_array); if (susp->ak_len < 1) xlerror(\"array has not elements\", susp->ak_array); susp->ak_coefs = (double *) calloc(susp->ak_len, sizeof(double)); susp->zk_buf = (double *) calloc(susp->ak_len, sizeof(double)); /* at this point we have a new array and a place to put ak coefs */ for(i=0; i < susp->ak_len; i++) { LVAL elem = getelement(susp->ak_array,i); if (ntype(elem) != FLONUM) { xlerror(\"flonum expected\", elem); } susp->ak_coefs[i] = getflonum(elem); } } ") (CONSTANT "ak_array" "ak_coefs" "ak_len" "gain") (SAMPLE-RATE "x_snd->sr") (INNER-LOOP-LOCALS "double z0; long xi; long xj;") (INNER-LOOP " z0 = x_snd*gain; for (xi=0; xi < ak_len ; xi++) { xj = index + xi; if (xj >= ak_len) xj -= ak_len; z0 += ak_coefs[xi] * zk_buf[xj]; } zk_buf[index] = z0; index++; if (index == ak_len) index = 0; output = (sample_type) z0; ") (FINALIZATION " free(susp->zk_buf); free(susp->ak_coefs); susp->ak_array = NULL; /* free array */ ") ) nyquist-3.05/lpc/lpcdemo.lsp0000644000175000000620000001763410144436365015125 0ustar stevestaff;;; LPC demo 1 ;;; Pedro J. Morales. ;;; February, 04 ;;; Roger B. Dannenberg ;;; July, 04 ; PLEASE config ====================================================== ; where is the file lpc-example.dat (setf *lpc-data* "d:/rbd/nyquist/lpc/lpc-exmpl.dat") ; this file generated by Nyquist will be loaded by Octave (or Matlab) (setf *default-octave-file* "d:/rbd/temp/nyquist.dat") ; config END =========================================================== ; file-io tools ======================================================== (defun octave-1 (outf data varname datatype &optional (n 1000)) (prog ((points (case datatype (SND (snd-samples data (1+ n))) (ARR data))) len) (setf len (length points)) (cond ((> len n) (setf len n) (format t "WARNING: DATA TRUNCATED TO ~A POINTS~%" len))) (format outf "# name: ~A\n" varname) (format outf "# type: matrix\n# rows: 1\n# columns: ~A\n " len) (dotimes (i len) (format outf "~A " (aref points i))) (format outf "\n"))) (defun octave (data-lists) ; (data varname datatype &optional (n 1000)) (prog ((filename *default-octave-file*) outf) (setf outf (open filename :direction :output)) (cond ((null outf) (format t "octave: could not open ~A!~%" filename) (return nil))) (format t "octave: writing ~A ... ~%" filename) (cond ((null outf) (format t "octave: could not open ~A!~%" filename) (return nil))) ;(format t "octave: writing ~A ... ~%" filename) (dolist (l data-lists) (apply #'octave-1 (cons outf l))) (close outf))) ; LPANAL ====================================================== ; get lpc data --------------------------------------------------- (defun do-lpc-analysis () (setf *myfile* "d:/rbd/nyquist/voice.wav") (save-lpc-file (make-lpanal-iterator (s-read *myfile*) 0.08 0.04 50) "temp.dat")) ;(if (not (boundp 'lpc-example)) ; (do-lpc-analysis)) ;(if (not (boundp 'lpc-example)) ; (setf lpc-example (load-file-data *lpc-data*))) ;----------------------------------------------------------------- ; SHOW-LPC-DATA ------------------------------------------------ ; show values of LPC analysis frames ---------------------------- (defun ex-1 () ; do not show filter coefs (show-lpc-data (make-lpc-file-iterator *lpc-data*) 100 120 NIL)) ; ------- SAVE-FILE-DATA --------------------------------------- (defun ex-2 () (save-lpc-file (make-lpc-file-iterator *lpc-data*) "temp.dat")) ;----------- LPC-FREQ ------------------------------------------ ; LPC-FREQ. Show frequency response of ALLPOLES filter. ; NEEDS MATLAB or OCTAVE ; (defun ex-3 () (lpc-freq "frm70" (make-lpc-file-iterator *lpc-data*) 70)) ; in MATLAB/OCTAVE: ; >> load -force nyquist.dat ; >> [H,W] = freqz(1, frm70, 512); ; >> plot(W,20*log10(abs(H))); ;------------------------------------------------------------------------- ; LPC-STABILITY Check for Stability of LPC filters ; NEEDS MATLAB/OCTAVE ; EXAMPLE ; (ex-3) ; in MATLAB/OCTAVE: ; >> load -force nyquist.dat ; >> find(abs(roots(frm70)) > 1) ; if any abs root is > 1.0 then UNSTABLE ;-------------------------------------------------------------------------- ; ALLPOLES LPC allpoles filter ; WARNING: this is a static filter ; for LPC resynthesis a dynamic LPC filter is needed ; EXAMPLE (defun ex-4 () (play (seq (allpoles-from-lpc (buzz 12 f2 (lfo 5.0 4.0)) (nth-frame (make-lpc-file-iterator *lpc-data*) 30)) (allpoles-from-lpc (buzz 12 f2 (lfo 5.1 4.0)) (nth-frame (make-lpc-file-iterator *lpc-data*) 60)) (allpoles-from-lpc (buzz 12 g2 (lfo 5.3 4.0)) (nth-frame (make-lpc-file-iterator *lpc-data*) 100)) ))) (setf a-lpcdata '(63.2144 0.674387 0.103287 #(-0.0381026 0.00804115 0.0109905 0.0145117 0.00199174 -0.00129314 0.0171826 0.0181176 0.00179391 -0.0114089 -0.0120949 -0.000410595 -0.0122539 -0.0209354 -0.00804976 -0.00345041 -0.00409532 -0.00227011 0.014224 0.0135451 0.0056023 -0.00651142 -0.00564953 -0.0168921 -0.0377939 -0.0449506 -0.0355592 -0.0339316 -0.0454434 1.19336))) (setf e-lpcdata '(40.7157 0.149753 0.0606467 #(0.0244574 -0.0225545 -0.0172724 -0.0122709 -0.0042946 0.00886974 0.0121516 0.0120936 0.00197545 -0.00582163 -0.018367 -0.0201546 -0.00440599 0.00638936 0.0166275 0.0185066 0.00890464 -0.00158013 -0.00494974 -0.00479037 0.0130814 0.0138648 -0.0022018 -0.021368 -0.0343532 -0.0312712 -0.0574975 -0.0918824 -0.112016 1.31398))) (setf i-lpcdata '(5.5391 0.0321825 0.0762238 #(-0.0341124 -0.0149688 -0.00585657 -0.0111572 0.00769712 0.0190367 0.00885366 0.0112762 0.0118286 -0.00059044 -0.0140864 -0.0123688 -0.0151128 0.00214354 -0.00810219 -0.00538188 0.00631382 0.020771 0.0356498 0.0295531 0.0242797 0.0124296 0.00445127 -0.013062 -0.0387178 -0.0527783 -0.0685511 -0.076575 -0.0846335 1.24521))) (defun noise-vocal (lpcdata dur) (allpoles-from-lpc (noise dur) lpcdata)) (defun ex-5 () (play (seq (noise-vocal a-lpcdata 1) (noise-vocal e-lpcdata 1) (noise-vocal i-lpcdata 1)))) (defun buzz-vocal (lpcdata dur) (allpoles-from-lpc (buzz 16 e2 (const 0.0 dur)) lpcdata)) (defun ex-6 () (play (seq (buzz-vocal a-lpcdata 1) (buzz-vocal e-lpcdata 1) (buzz-vocal i-lpcdata 1)))) ; ---- LPRESON ------------------------------------------------------------ ; (defun ex-7a () ;; parameters are sound, lpc-iterator, skiptime (lpreson (noise 6.5) (make-lpc-file-iterator *lpc-data*) 0.04)) (defun ex-7 () (play (ex-7a))) (defun ex-8a (p dur) (lpreson (buzz 16 p (scale 1.5 (lfo 3.0 dur))) (make-lpc-file-iterator *lpc-data*) 0.04)) (defun ex-8 () (play (sim (seq (ex-8a c4 1) (ex-8a g3 1) (ex-8a a3 1) (ex-8a b3 1) (ex-8a c4 1)) (seq (ex-8a c2 2) (ex-8a f2 1) (ex-8a g2 1) (ex-8a e2 1))))) (defun noalias-buzz (p nmax) (min (round (/ *sound-srate* (* 2.0 (step-to-hz p)))) nmax)) (defun ex-9a (p dur skiptime) (mult (env 0.01 0.01 0.1 1.0 1.0 1.0 dur) (lpreson (buzz (noalias-buzz p 16) p (scale 1.5 (lfo 3.0 dur))) (make-lpc-file-iterator *lpc-data*) skiptime))) (defun ex-9b (stretch skiptime) (play (sim (seq (ex-9a c4 (* 1 stretch) skiptime) (ex-9a g3 (* 1 stretch) skiptime) (ex-9a a3 (* 1 stretch) skiptime) (ex-9a b3 (* 1 stretch) skiptime) (ex-9a c4 (* 1 stretch) skiptime)) (seq (ex-9a c2 (* 2 stretch) skiptime) (ex-9a f2 (* 1 stretch) skiptime) (ex-9a g2 (* 1 stretch) skiptime) (ex-9a e2 (* 1 stretch) skiptime))))) (defun ex-9 () (ex-9b 1.0 0.04)) (defun ex-10 () (ex-9b 1.0 0.02)) (defun ex-11 () (ex-9b 2.0 0.04)) (defun ex-12 () (ex-9b 0.5 0.02)) (defun ex-13 () (ex-9b 4 0.02)) (defun ex-14a (p dur skiptime) (mult (env 0.01 0.01 0.1 1.0 1.0 1.0 dur) (lpreson (osc-saw (sim (step-to-hz (+ p 0)) (scale 1.5 (lfo 3.0 dur)))) (make-lpc-file-iterator *lpc-data*) skiptime))) (defun ex-14b (stretch skiptime) (play (sim (seq (ex-14a c4 (* 1 stretch) skiptime) (ex-14a g3 (* 1 stretch) skiptime) (ex-14a a3 (* 1 stretch) skiptime) (ex-14a b3 (* 1 stretch) skiptime) (ex-14a c4 (* 1 stretch) skiptime)) (seq (ex-14a c2 (* 2 stretch) skiptime) (ex-14a f2 (* 1 stretch) skiptime) (ex-14a g2 (* 1 stretch) skiptime) (ex-14a e2 (* 1 stretch) skiptime))))) (defun ex-14 () (ex-14b 1 0.04)) (defun ex-15 () (ex-14b 4 0.02)) (defun ex-16 () (ex-14b 8 0.08)) nyquist-3.05/lpc/lpc-exmpl.dat0000644000175000000620000026342510144436365015356 0ustar stevestaff(0.0205328 0.000539653 0.162119 #(0.0172437 -0.00206371 0.0199834 0.0140023 -0.107106 0.105376 -0.014147 -0.0456254 -0.035733 0.000526876 0.024559 -0.077979 0.0379572 0.0550832 0.0251978 -0.0158793 0.000201547 0.0183836 0.0120267 -0.0145289 0.0270053 0.0215023 -0.0674045 0.0868633 -0.0759818 0.0123872 -0.100426 0.0670379 0.153223 -0.160887 0.0200027 0.00857184 -0.0319345 0.0372642 -0.039906 0.0370124 -0.0406953 0.0916241 -0.0794324 0.0994091 -0.152256 0.122422 -0.131096 0.143904 -0.182573 0.107067 -0.216319 0.338997 -0.171402 1.04299)) (0.0746031 0.000883533 0.108826 #(0.043002 -0.0168565 0.0116234 -0.031321 -0.0728684 0.134856 0.0052372 -0.0477521 -0.0767405 0.0307031 0.00286882 -0.0188694 -0.0103552 0.0410824 -0.00991496 0.0129631 -0.0070764 0.0446677 -0.0316206 0.0103328 -0.00314631 0.0721652 -0.028264 0.0429488 -0.0757499 0.0355948 -0.124679 0.0341884 0.147169 -0.115948 0.0350534 -0.022784 0.00255128 0.000132609 0.00266292 0.0235752 -0.0270638 0.00319338 -0.0405898 0.0510949 -0.0525406 0.112875 -0.120262 0.103579 -0.140658 0.030511 -0.195171 0.226418 -0.194436 1.19625)) (7.90651 0.00254103 0.0179272 #(0.0298438 -0.0150177 0.00856811 0.00178307 -0.156251 0.141521 0.0377321 -0.00862076 0.0358013 -0.0526648 -0.0746482 0.0176761 0.0180553 0.0110547 -0.0149859 -0.00274912 0.00753696 0.0570906 -0.00985159 -0.0460384 -0.0312089 0.0275762 -0.00179828 0.0498972 -0.0462076 0.111785 -0.101277 -0.0429219 0.135046 -0.118618 0.0320909 0.0152628 0.00229011 0.000619642 -0.00148223 0.0698463 -0.0192731 -0.061608 -0.105966 0.00760205 -0.0556964 0.172818 -0.0018539 0.14807 -0.115714 0.0485711 -0.341883 0.118442 -0.644804 1.76356)) (16.8204 0.00353871 0.0145046 #(0.0242379 0.0163801 -0.0441124 0.0515951 -0.165318 0.0553254 0.118888 -0.00888211 0.0686623 -0.103195 -0.109872 0.0873954 -0.00312068 -0.0157818 0.00793753 -0.0102677 0.0385871 0.0402539 0.0275778 -0.124176 -0.0224998 -0.0083091 0.139262 -0.0326057 -0.0686154 0.152026 -0.0710961 -0.100093 0.0921394 -0.0886168 0.0962788 0.0235546 -0.0835561 0.0289921 -0.0519826 0.0819953 0.0677047 -0.04636 -0.154177 0.0188317 -0.0733893 0.18706 -0.117089 0.276443 -0.188078 0.136406 -0.348012 0.354862 -1.21044 2.05642)) (15.7527 0.00488585 0.0176113 #(0.0410332 -0.0212341 -0.0186016 0.0139835 -0.10253 0.0317464 0.098534 0.0577219 -0.00603218 -0.119189 -0.0560336 0.0600247 0.00563636 -0.00741701 -0.022568 0.0551003 0.0172174 -0.0145449 0.0377798 -0.0774387 -0.0623132 0.0156745 0.116856 0.0167625 -0.0740776 0.0976961 -0.0589157 -0.0592283 0.0621122 -0.0668073 0.0672344 0.0433492 -0.0724394 -0.0149194 -0.0174723 0.0940844 0.0192709 -0.037947 -0.145742 0.0166333 -0.0382952 0.137928 -0.0235971 0.142885 -0.0641163 -0.0401743 -0.14418 0.182686 -1.00692 1.93978)) (16.3531 0.0136897 0.0289333 #(-0.024896 0.016421 0.00786502 -0.0118406 0.00603457 0.0343453 0.0250988 -0.00670104 -0.0483285 -0.0402459 0.00284676 0.0223309 0.00649693 -0.0116516 0.00923614 0.0111503 -0.000440774 -0.0275555 0.00682401 -0.0125723 0.00263826 0.0153074 0.0242379 0.0142031 0.0060273 0.0192062 -0.0368178 0.00965019 0.0058204 -0.00736851 0.0414994 0.00440613 -0.0394615 -0.0217087 0.0132956 0.0116567 -0.024931 -0.0592983 -0.0327111 0.00831445 0.0282831 0.0678891 0.00450369 0.00915988 -0.0181229 -0.0469828 -0.0555707 -0.0913728 -0.228273 1.41019)) (22.7776 0.0128829 0.0237823 #(-0.0244512 0.00852192 0.00355279 0.0100932 -0.00419528 0.0237172 0.0103759 -0.0137028 -0.0251104 -0.0134613 -0.000615256 0.00165147 -0.00407305 -0.00344569 -0.00120993 0.0089017 0.000495352 -0.000238208 0.00294549 0.00112805 0.00425276 0.0266437 0.0165051 -0.0296654 -0.00157895 0.0406957 -0.0203225 0.000875471 0.0187371 -0.00604564 0.0124178 0.00848914 -0.00870932 -0.0345038 -0.0166086 -0.00777551 -0.0127552 -0.0198208 -0.018883 0.00170381 0.0281818 0.0335668 0.00621638 0.000123257 -0.0400046 -0.0251494 -0.0599436 -0.0484318 -0.0953316 1.26394)) (25.9418 0.014063 0.023283 #(-0.0146976 0.0123669 -0.00238331 -0.00566441 0.000213927 0.0251708 0.0058586 -0.0152624 -0.0096643 0.000380473 -0.00692432 -0.0103325 -0.00570062 -0.00779317 -0.00373097 -0.00244446 0.0232326 0.00687431 -0.0123666 0.0136142 0.000873428 0.01297 0.00157535 -0.0189359 0.0103542 0.0149338 -0.00232667 0.018195 0.0122806 0.000705099 0.0180465 -0.00723085 -0.0333543 -0.0209618 -0.00258482 -0.00346647 -0.0161793 -0.00443528 -0.0107334 -0.00729346 0.0212632 0.017004 -0.0134609 -0.0122188 -0.0266593 -0.0240987 -0.0584669 -0.0204726 -0.0728998 1.23429)) (26.411 0.0454326 0.0414755 #(-0.0109339 -0.0010968 -0.0010053 0.00617609 0.00306015 0.000136934 0.00372594 -0.00564924 -0.00591968 -0.00522412 -0.00509402 -3.17432e-006 -0.00446083 0.00456961 0.00243643 0.00451923 0.00334826 0.00559344 0.00805774 0.000849614 0.00365901 -0.000214671 -0.00258062 0.00132718 0.00916179 0.00321858 -0.00441098 0.00674969 0.00362521 0.00233835 0.00103611 -0.00365412 -0.0110665 -0.0113001 -0.00483079 -0.00471838 -0.0072024 -0.0112189 -0.00842469 -0.00122134 0.00258161 -0.00404681 -0.0108012 -0.0163903 -0.0156165 -0.0101237 -0.0119205 -0.0127908 -0.0241693 1.1353)) (26.023 0.0171174 0.0256472 #(-0.00659148 -0.0022813 0.00245043 0.0119932 0.00673879 0.0106215 0.000193227 -0.0118672 -0.00229731 -8.44562e-005 -0.010244 -0.0224172 -0.0074773 0.00139424 0.00442344 -0.00372009 0.00631038 0.00399001 0.00074413 0.00143648 0.0117816 0.0167116 -0.011429 0.00660101 -0.0154429 0.0245051 0.00954568 0.00221017 0.00972422 0.00691179 0.00198784 0.00641321 -0.0164092 -0.0286664 -0.00348171 -0.00646432 -0.0149224 -0.00929398 0.000946284 -0.00786511 0.0105857 0.0116371 -0.0208869 -0.0167969 -0.039235 -0.0416232 -0.0188724 -0.0395318 -0.0672928 1.2529)) (20.1471 0.0413173 0.0452855 #(0.0028042 0.00238915 0.00320531 0.00204744 -0.00128491 -0.000625469 0.00121502 -0.00053792 -0.00926453 -0.00168529 -0.0176347 -0.00451895 0.000996928 0.00430582 0.00194222 -0.00398466 0.00259957 0.00390882 0.0116503 0.00167209 -0.001884 0.00309071 0.00380416 0.00551039 0.0052082 0.00707811 -0.00293764 0.0110331 0.0118179 0.000155053 0.0029885 -0.0120471 -0.00528422 -0.0186305 -0.00389795 -0.01138 -0.0130287 -0.0114016 -0.00348096 0.00720399 -0.00393767 -0.00782219 -0.00889679 -0.0106665 -0.0241594 -0.0212916 -0.0261109 -0.0222356 -0.042137 1.1898)) (15.5487 0.0153078 0.0313768 #(0.0038797 -0.00898583 -0.00129375 0.0135476 0.00658722 0.0365788 0.00343157 -0.0308747 -0.0106992 -0.00551437 0.00041832 -0.0139702 -0.0154675 -0.0119801 -0.00961124 0.0151818 0.00235315 -0.00360607 -0.00300882 0.0133151 0.00953059 0.00235415 -1.91313e-005 0.00280704 0.0099642 0.0205634 0.00397632 0.00529698 0.023866 -0.00799138 0.0100504 0.0079582 -0.0250386 -0.029848 -0.0097943 -0.00418491 -0.0133331 -0.0233978 -0.00335522 0.0048438 0.0168547 0.0205229 -0.0161785 -0.0256227 -0.0427417 -0.0322054 -0.0493791 -0.0330071 -0.0981295 1.29245)) (19.0253 0.00596731 0.0177102 #(-0.0146168 -0.0100904 0.00214927 0.0184939 0.01049 0.0612408 -0.00438104 -0.0265871 -0.026429 0.00668405 0.0269023 -0.0263329 -0.0230587 -0.0429497 0.00384385 0.0294333 -0.00318107 -0.0136982 -0.00792112 0.0090845 0.0366004 -0.0174499 -0.00897093 -0.00784815 -0.00441435 0.0551205 -0.0163865 0.00471411 0.0446577 -0.0132054 0.0401863 0.0217569 -0.0372981 -0.0637524 -0.0140608 0.0379691 -0.012396 -0.0571539 -0.0387487 0.0285809 0.0555209 0.0533837 -0.020053 -0.00430533 -0.102708 -0.0554588 -0.0775484 0.00345876 -0.257812 1.45669)) (24.3361 0.00252815 0.0101924 #(-0.0257512 -0.0008726 0.0176086 0.0124685 -0.0534896 0.100064 0.0398205 -0.0701561 -0.0307596 0.00460567 0.0732452 -0.00591591 -0.0655563 -0.0244842 0.0128442 0.0333025 -0.0171489 -0.0529101 -0.0145168 -0.00558627 0.0716373 0.0169233 -0.00522713 0.00671804 -0.0615778 0.0634442 -0.0921752 0.00951979 0.120483 -0.077487 0.0914363 0.104565 -0.0653618 -0.089458 -0.0420491 0.0741933 -0.0368942 -0.0224205 -0.159684 0.0706304 0.0604807 0.156387 -0.0368354 0.00141878 -0.11703 -0.0250188 -0.215087 0.140998 -0.528956 1.65826)) (25.4722 0.00168582 0.00813527 #(-0.0361914 0.0503908 -0.052739 0.0874611 -0.161167 0.205034 -0.030822 -0.0297436 -0.0881124 0.0515133 0.029009 0.0911085 -0.133234 0.00447612 -0.0102752 0.0672411 -0.0743354 0.0278325 -0.088049 0.0254583 0.00378763 0.110739 -0.0335123 0.0437825 -0.111471 0.143021 -0.205556 0.0105061 0.178276 -0.139079 0.108138 0.100769 -0.0514441 -0.061891 -0.0335699 0.078663 -0.0342434 -0.0322647 -0.218112 0.133516 -0.053587 0.327015 -0.200594 0.23237 -0.331232 0.175309 -0.44634 0.403636 -0.874447 1.84189)) (24.4789 0.00660193 0.0164225 #(-0.0129511 0.000294328 -0.0197443 0.0228973 0.0144379 0.0576108 -0.00978518 -0.00793303 -0.0138883 -0.0222251 0.0319748 -0.0148723 -0.0204648 -0.0414119 -0.0116904 0.010987 -0.0113676 0.0117234 -0.00638076 0.0237907 0.020048 0.00399678 -0.00498899 -0.00973827 -0.00584135 0.0192609 -0.0220209 0.0192987 0.0427776 -0.0141488 0.0260689 0.053246 -0.0359298 -0.0407085 -0.0153808 0.000894089 -0.0255827 -0.0505249 -0.0252819 0.0272812 0.0597201 0.0367404 0.00457889 -0.0014007 -0.0717525 -0.0699291 -0.107446 -0.0187547 -0.27242 1.49509)) (26.2758 0.0176864 0.0259442 #(0.0033549 -0.00945348 0.0065972 0.011377 0.00754275 0.0138938 0.00853247 0.000314037 -0.00732074 -0.0137922 -0.008441 -0.0188535 -0.0266481 -0.0205979 0.00421144 0.0117094 0.0169971 -0.0179554 -0.00098244 0.035148 0.00857569 -0.0052743 -0.000887931 0.00311146 -0.00552477 0.00948484 -0.000848823 0.0254957 0.0295882 -0.0096005 0.019213 0.00984905 -0.0239854 -0.0251062 -0.0378088 -0.00656597 -0.0252241 -0.0322219 0.024789 0.0259035 0.0228412 0.0272441 -0.00713364 -0.0104557 -0.0465321 -0.0714479 -0.0841954 -0.0538046 -0.134946 1.37684)) (33.8769 0.00801222 0.0153789 #(-0.00258214 -0.00821759 0.0196898 -0.000392261 0.0140521 0.00440578 -0.0286329 0.000567736 0.0125327 0.00426797 -0.0066993 0.0334311 -0.0281124 -0.0422645 -0.0221943 0.0377913 -0.00618192 -0.0265775 -0.00448782 0.027992 0.0456436 0.00158737 -0.0145791 -0.00474223 -0.0115839 0.0136965 -0.0283794 0.032301 0.000935378 -0.0386639 0.0497046 0.0790239 -0.0338661 -0.0499984 -0.00571791 0.0381896 -0.0512542 -0.0879677 -0.0317509 0.0295627 0.0690141 0.0544617 0.0545729 0.0472211 -0.0781932 -0.090823 -0.112884 -0.113677 -0.42381 1.68183)) (47.5854 0.03461 0.0269689 #(0.00703504 0.0042176 -0.007448 0.00601103 0.00320568 0.00838487 0.0062723 -0.0120179 0.000336154 0.000458805 -0.00549983 -0.000896449 -0.0239517 -0.0277963 -0.00199031 0.00441657 0.0118858 -0.00555538 0.0186382 0.000599233 0.0253149 0.00947596 -0.0151058 -0.0109278 -0.00257833 0.0161187 -0.000843106 0.0151509 0.00682266 0.00837561 0.0212141 0.019091 -0.0166389 -0.0383569 -0.0276626 -0.0067535 -0.0278646 -0.0358582 -0.00485826 0.02398 0.0407189 0.0544763 0.0300379 -0.00650959 -0.0404744 -0.0715788 -0.100036 -0.13855 -0.218292 1.50233)) (67.1502 0.0503262 0.0273762 #(0.00163764 0.00156368 0.000896518 -0.00356924 0.0146311 0.0115155 0.000718131 -0.010003 -0.00103783 0.00202199 -0.00199034 -0.0161105 -0.0194743 -0.0104963 -0.00591896 0.0121449 0.00486055 -0.00401805 0.00316407 0.00376875 0.0156482 0.00483055 -0.00410957 -0.00432992 -0.00485066 0.0143753 0.00558336 0.0130507 0.00596937 0.00550279 0.0213288 0.00884339 -0.00423094 -0.0320471 -0.0225288 -0.0132194 -0.0288979 -0.0323811 -0.0196434 0.0287962 0.0448142 0.0421381 0.0389864 -0.00463365 -0.0331114 -0.0584344 -0.112601 -0.149007 -0.247096 1.5331)) (87.0259 0.146162 0.040982 #(0.0066813 0.0031666 0.00524609 -0.0082533 -0.00391559 0.0131647 0.0226346 0.00201689 -0.0300066 -0.0164448 0.00249676 0.012122 -0.0120514 -0.0290936 -0.00477291 0.0062677 0.00679358 0.00355967 0.0074764 0.00641204 0.00203213 -0.000103927 0.00208319 0.00592471 -0.00531212 -0.00286345 0.0194362 0.0235452 0.0145299 0.000873052 0.0170015 0.00926635 -0.0249864 -0.0345525 -0.026674 -0.0209155 -0.0204941 -0.0180144 -0.000742368 0.0206704 0.0347392 0.0281013 0.0231078 0.00568184 -0.0455544 -0.0687793 -0.0774324 -0.112311 -0.16092 1.413)) (103.805 0.0839127 0.0284317 #(0.0305305 -0.0232935 -0.0123279 -0.00539001 0.00241112 0.0181144 0.0198195 -0.0119952 -0.00946969 -0.00768942 0.0176179 0.0159392 -0.0270933 -0.0533804 -0.0238979 0.042285 0.0419821 -0.0130642 -0.02037 0.00470052 0.0265474 0.00800111 -0.0193407 -0.00539329 -0.00768145 -0.00352887 0.00818424 0.0306883 0.00191179 -0.011258 0.0201576 0.0424102 0.000582659 -0.0480861 -0.0335357 0.00238416 -0.000149278 -0.0762318 -0.0235003 0.0537691 0.0525345 0.0284459 0.0125174 0.044311 -0.0359816 -0.0879433 -0.0942918 -0.141744 -0.328099 1.59425)) (124.841 0.162496 0.036078 #(0.0154669 -9.72884e-006 -0.0101342 -0.00793859 0.0059567 0.0228617 0.00768918 -0.0107367 -0.0153092 -0.00690622 0.00137529 0.00756771 -0.0173113 -0.0348903 -0.015329 0.0277865 0.0313134 0.00105124 -0.0143057 -0.00667794 0.011448 0.00558312 -0.00253005 0.000195594 -0.00582771 0.00497205 0.0183721 0.0241788 0.0151434 -0.0120356 0.00834879 0.019273 -0.0189529 -0.0436641 -0.017064 0.0110478 -0.0142619 -0.0454921 -0.0275606 0.0195142 0.0430997 0.0479311 0.0369613 0.00241956 -0.049964 -0.0670036 -0.063226 -0.132439 -0.269048 1.51163)) (180.716 0.293325 0.040288 #(0.0258335 -0.0119538 -0.0193954 -0.00626257 0.0234294 0.0231874 0.0109882 -0.0140674 -0.0204807 -0.0175573 0.000633931 0.000397377 -0.011624 -0.022438 -0.0107618 0.0178291 0.0325036 0.0112156 -0.0171066 -0.00548084 0.00984786 -0.00170732 -0.00485124 -0.00691943 -0.00247698 0.0118085 0.0178137 0.0244233 0.0229053 0.003698 -0.0103266 -0.00441229 -0.00122563 -0.0243714 -0.0381239 -0.0309188 -0.0100181 -0.00337076 -0.00420997 0.0204227 0.0439681 0.0382338 0.00823855 -0.0138448 -0.0326542 -0.0661078 -0.097244 -0.115524 -0.154429 1.42031)) (234.118 0.205985 0.029662 #(0.0192157 -0.0031935 -0.00784433 -0.00677489 0.00286156 0.0114244 0.0199407 0.00873447 -0.0210833 -0.0382217 0.00335562 0.018978 -0.0148748 -0.0242473 -0.0051396 0.0205883 0.00181457 -0.0139292 0.0109887 0.0201683 0.00322887 -0.00941825 -0.00196576 0.0112985 -0.0102269 -0.0019795 0.0216591 0.0239712 0.00292886 -0.0126777 0.0229174 0.0228922 -0.0279371 -0.0544655 -0.0105665 0.0201515 -0.0232041 -0.0500812 -0.0122807 0.0286273 0.0377097 0.0333467 0.0362003 0.00682096 -0.0421918 -0.0623608 -0.0697533 -0.142768 -0.286476 1.53382)) (240.477 0.393671 0.0404604 #(0.0141351 -0.00376777 -0.0127499 0.00507208 0.0136482 0.0136646 0.00963351 -0.00969488 -0.0204225 -0.0195809 -0.00608936 0.0113476 -0.00348937 -0.0263493 -0.00860379 0.0196824 0.0270435 0.00279308 -0.0216122 -0.00311376 0.0167268 0.0026715 -0.00951989 -0.00655211 -0.000521916 0.00286717 0.0195184 0.0369098 0.0212964 -0.00938696 -0.00852238 0.0157752 -0.010538 -0.0511757 -0.0367333 -0.00701777 -0.00496757 -0.0218476 -0.00180121 0.0358277 0.0423497 0.0250602 0.0161893 -0.00886896 -0.0517459 -0.0757613 -0.0763744 -0.0986088 -0.163602 1.41088)) (208.983 0.298555 0.0377969 #(0.0164121 0.0048719 -0.0123277 -0.0082839 0.00553303 0.0215874 0.00343585 -0.0106931 -0.0143605 -0.0149133 -0.000867135 0.00882374 -0.00160873 -0.0229544 -0.0199348 0.0112933 0.0268215 0.00930974 -0.0129465 0.00684308 0.00823984 -0.00100629 -0.00874536 -0.0125536 0.0018266 0.00222032 0.0179517 0.0318532 0.0216125 -0.00395573 0.00757547 0.000995567 -0.0228842 -0.0368795 -0.018438 -0.00111154 -0.0249076 -0.0299492 0.000929623 0.034715 0.0335621 0.0270658 0.0181262 -0.000710647 -0.0431774 -0.0595626 -0.0734814 -0.128686 -0.215031 1.46608)) (169.872 0.295057 0.0416766 #(0.0319486 -0.0152698 -0.0178871 -0.00121978 0.0101795 0.0113419 0.00466058 -0.0163847 -0.00962441 -0.00255257 0.0034453 0.00333557 -0.00638092 -0.0185545 -0.0171695 0.00620859 0.027439 0.00889597 -0.00634335 0.00222882 0.00733991 0.00272018 -0.00324214 -0.00743471 -0.0202102 -0.0144455 0.0143375 0.0353734 0.03177 0.0180433 0.00470567 0.00350029 -0.0211588 -0.0400762 -0.0312031 -0.00502416 -0.0137467 -0.0287056 -0.00591527 0.0317417 0.0557392 0.030424 0.00295205 -0.00796262 -0.0331349 -0.0705161 -0.0935693 -0.117755 -0.17632 1.44112)) (198.736 0.583121 0.0541678 #(0.0239533 -0.0108176 -0.0102808 0.00564068 0.0150349 0.00994732 -0.00604523 -0.00984589 -0.0142772 -0.0121714 -0.00415331 -9.11199e-005 -0.00732939 -0.0188397 -0.00379378 0.0155464 0.0238681 0.0102193 -0.00649659 -0.0166725 -0.00159701 0.0168372 0.00555774 -0.0076568 -0.0152812 0.00621925 0.0304524 0.0302777 0.0179796 -7.1259e-005 -0.0110991 -0.0120554 -0.0207771 -0.0196221 -0.019649 -0.0276093 -0.0267218 -0.00462518 0.0217483 0.0300955 0.0254635 0.0179527 0.00908021 -0.0147737 -0.0434505 -0.0549393 -0.067622 -0.0980195 -0.11752 1.34832)) (235.893 0.196632 0.0288715 #(0.0304126 -0.0184424 -0.0165599 -0.000407823 0.00801631 0.0195737 0.0118165 -0.00905007 -0.0134561 -0.0135 -0.00394936 0.00567199 0.00352691 -0.0209869 -0.0335421 0.00501761 0.033716 0.0178405 0.00147093 -0.011718 -0.00133608 -0.00135017 0.00902945 0.00737444 -0.0033788 -0.00925621 -0.0209713 0.0180258 0.0548861 0.0175237 -0.0085279 -0.00515863 -0.0139746 -0.031351 -0.0115241 0.00705294 -0.0364894 -0.0527857 -0.0113735 0.0463322 0.0573369 0.0344311 0.019218 0.00187843 -0.0302693 -0.0656353 -0.0907326 -0.155003 -0.284321 1.55441)) (250.351 0.920652 0.0606419 #(0.0221283 -0.00175026 -0.00689412 0.000872708 0.00825388 0.00110956 -0.00632789 -0.0125022 -0.0104057 -0.00936074 -0.00616766 0.00522704 0.000860839 -0.00548061 -0.0014818 0.00943791 0.00798624 0.000154997 -0.00816161 -0.00716682 0.000403966 0.00149304 0.00596023 0.00691071 0.00706264 0.0106029 0.0144444 0.01869 0.0103569 -0.00377258 -0.00598677 -0.011182 -0.0229358 -0.0277385 -0.0171593 -0.00963866 -0.0130767 -0.00448601 0.01284 0.0232398 0.0183027 0.00684207 0.000345183 -0.017907 -0.0388241 -0.0491714 -0.0555385 -0.0671155 -0.080383 1.27961)) (265.144 0.37479 0.037597 #(0.0178487 0.0013791 -0.0116388 -0.00507206 0.0138357 0.0176418 0.0040927 -0.0179262 -0.017936 -0.00558455 0.00209339 -0.00600955 -0.011245 -0.00868085 -0.00205561 0.000295947 0.0125599 0.0156985 -0.00318278 -0.0132323 -0.000274777 0.00777626 -0.00183865 0.00266585 0.0125194 0.00603461 -0.00305746 0.0220627 0.0328774 0.00937883 -0.00296813 -0.0139498 -0.023661 -0.0265224 -0.0152562 -0.00981502 -0.0187505 -0.0249964 -0.00613381 0.0245956 0.0383716 0.0292479 -0.00259061 -0.00982094 -0.0297847 -0.0422148 -0.0701577 -0.115859 -0.177598 1.41175)) (250.53 0.735674 0.0541892 #(0.0238545 -0.00486949 -0.00173591 0.00252099 0.00404998 0.00118642 -0.00418862 -0.0123793 -0.0138166 -0.00838696 -0.00266911 -0.000717441 -0.00433613 -0.00087901 3.08753e-005 0.00695944 0.00812309 0.00161619 -0.00106495 -0.00230766 -0.00318343 -0.00717512 0.00130251 0.0107457 0.00679086 0.00860716 0.0173261 0.0173051 0.0100283 0.00988019 0.00145606 -0.0181773 -0.0255863 -0.0227028 -0.0191551 -0.0156616 -0.0149123 -0.00943028 0.00703709 0.0185155 0.0208948 0.0180594 0.00541843 -0.016114 -0.0379061 -0.0507604 -0.0578965 -0.0768728 -0.0909356 1.29924)) (197.598 0.485401 0.0495631 #(0.0248193 -0.00306678 -0.00667275 -0.0014236 0.0114491 0.0091926 -0.0023926 -0.0167224 -0.0201609 -0.00339142 -0.00311447 -0.00213343 -0.00661917 -0.00708419 0.00117074 0.0105285 0.010503 0.000885714 -0.00157855 -0.00449273 -0.0024985 -0.000379483 -0.0043849 0.0022342 0.0114984 0.0120889 0.0118227 0.0206663 0.0203387 0.01268 -0.00367646 -0.0148372 -0.0196786 -0.0256279 -0.0246386 -0.0201119 -0.0148319 -0.00916508 -0.00126804 0.0198383 0.0319355 0.0159117 0.00101828 -0.0089909 -0.0292361 -0.0476222 -0.0687146 -0.089934 -0.113823 1.33378)) (125.124 0.316632 0.0503045 #(0.0130568 -0.00225892 0.00216152 0.0102169 0.00996052 -0.00255912 -0.0097279 -0.0196243 -0.00656228 -0.000937932 -6.12063e-005 -0.000608431 -0.00526008 -0.00223335 0.00268855 0.00317693 0.00183598 0.00660908 0.00583385 -0.00116981 -0.00278075 -0.00730575 -0.0127456 -0.00600758 0.00295042 0.00742113 0.0148913 0.0264792 0.0296855 0.00264396 -0.00385496 -0.00327753 -0.023196 -0.0218689 -0.015055 -0.00831472 -0.0139174 -0.0128882 -0.000967953 0.012294 0.0210776 0.0214656 0.0105105 -0.0134574 -0.0314187 -0.0453388 -0.0664272 -0.107779 -0.148171 1.37876)) (71.37 0.227496 0.0564585 #(-0.0142429 0.012727 0.0152038 0.013247 0.0124478 0.00703828 -0.0126102 -0.0229412 -0.0168578 -0.00561364 0.00559436 0.00298623 -0.0049227 -0.00038521 -0.00127981 0.00423441 0.000763587 0.00976382 0.0108994 0.00630644 -0.00368733 -0.0148032 -0.023322 -0.0161698 -0.000889858 0.011531 0.0186532 0.0329139 0.0305486 0.00665483 -0.0125951 -0.0144017 -0.0205354 -0.0305956 -0.0183857 -0.000585577 0.0114074 0.00891327 0.00153785 0.00446643 0.00473343 0.015059 0.0101803 -0.0146464 -0.0351526 -0.0511088 -0.0647666 -0.0850186 -0.118079 1.33668)) (40.4377 0.0852366 0.0459113 #(-0.0335089 0.029908 0.0183897 0.0176984 0.0101193 0.00829117 -0.0170098 -0.0268985 -0.022606 0.00232026 0.0189546 -0.0045041 -0.00575308 -0.0100939 0.00425405 0.00177554 0.00632439 0.0070991 0.0135077 0.0172888 -0.00309632 -0.0159993 -0.0288205 -0.0254887 -0.0108957 0.00733041 0.0214328 0.0301479 0.0306404 0.0070994 -0.0123194 -0.025963 -0.0100594 -0.00332728 -0.00658321 -0.000959254 0.00177248 0.00985076 -0.0049481 -0.00260225 0.00144116 0.00476165 0.00342908 -0.0128849 -0.0221734 -0.0326228 -0.0534822 -0.0924536 -0.143692 1.34984)) (27.3832 0.070801 0.0508484 #(-0.0140748 0.0135211 0.0169284 0.0134048 0.00664361 -0.000844623 -0.025384 -0.00976012 0.00801802 0.00636203 -0.00289115 -0.0127367 0.000562452 0.00700169 0.00416503 0.00548033 0.00503239 0.00518513 0.00212309 -0.00811506 -0.0249022 -0.0165552 -0.00808011 -0.0032732 -0.00323997 0.0128592 0.0143886 0.0210239 0.0149843 -0.0102482 -0.00523455 -0.0127067 -0.00629629 -0.0118239 -0.00186732 0.00661671 0.000807708 0.0076143 -0.00151332 -0.0141276 0.000588052 0.013716 -0.00222398 -0.0188076 -0.0188453 -0.0187286 -0.0391334 -0.0564238 -0.0793644 1.23514)) (30.7375 0.040934 0.0364929 #(-0.0243691 0.00812592 0.015261 0.01097 0.0205355 0.0101767 -0.0151796 -0.0251579 0.00184063 0.0088331 0.00252205 0.000583772 -0.00157531 -0.000798763 0.00905121 0.00117476 0.00355867 -0.00185548 0.00468458 -0.00729399 -0.0289016 -0.0190386 0.00930854 -0.00472978 -0.0131431 -0.00543118 0.00841419 0.0272355 0.0256443 -0.00636553 -0.00757628 -0.00558504 -0.000516058 -0.00121443 -0.0138289 0.00110727 0.00668947 0.00434654 -0.00919808 -0.0198922 0.00235468 0.0144602 -0.000975259 -0.0245124 -0.0246625 -0.015985 -0.0371288 -0.0397989 -0.0669062 1.22136)) (42.0859 0.00626129 0.0121973 #(-0.0734655 0.0296172 0.013634 0.0452539 0.00702914 0.057469 -0.0232954 -0.0727147 -0.0229838 0.0545064 0.022556 -0.0378221 -0.0116609 -0.0131154 0.0381253 0.0259823 -0.0219215 -0.0248628 0.0469329 -0.00591986 0.0161304 -0.0248895 -0.0474258 -0.0134104 -0.011063 0.0414246 -0.0607445 0.0508991 0.0641952 0.00526139 -0.0600509 0.00150282 0.00627574 -0.070137 0.0242186 0.0169948 0.0408282 0.0438345 -0.0204922 -0.0610643 -0.0804496 0.0966152 0.0588874 -0.0136561 -0.0697122 0.00834575 -0.047428 -0.0855743 -0.478215 1.63444)) (48.3822 0.0133138 0.0165886 #(-0.0991241 0.0620696 0.0256428 0.0325504 0.030601 0.0200286 -0.0346818 -0.0543453 -0.000353481 0.0292389 0.0225596 -0.0231814 -0.0230041 -0.00406665 0.0324386 0.00882869 -0.0235801 0.0419879 0.00354304 -0.0088214 0.00179125 -0.0386059 -0.020162 -0.0161291 -0.0274193 0.0200131 0.00125343 0.0450822 0.0571638 -0.0335057 -0.0273933 -0.0201817 -0.0220575 -0.0085605 -0.000251926 0.0202286 0.0402841 0.0305421 -0.0148375 -0.0251732 -0.04472 0.0420287 0.0255921 -0.0131808 -0.0380019 -0.0228509 -0.0479855 -0.104387 -0.277699 1.47947)) (52.3586 0.0659523 0.0354912 #(-0.0350294 0.0226496 0.0266707 0.0151374 0.00559978 -0.00178336 -0.0131273 -0.00792491 0.00702189 0.00803718 0.000224972 -0.0104286 -0.0107735 0.000890825 0.000619345 0.00514007 -0.000477151 0.00445113 0.0122391 0.00292333 -0.0091859 -0.0264601 -0.0178257 -0.00867586 0.00144957 0.00389939 -0.00103973 0.00526759 0.0114127 0.00266532 -0.0114983 -0.0129203 -0.0101913 0.00682779 0.023871 0.0120872 0.00875099 0.0033859 -0.00336156 -0.00727741 -0.00798061 0.00279848 -0.00798744 -0.0160221 -0.02748 -0.0249909 -0.0413176 -0.0503363 -0.0665837 1.23408)) (57.2864 0.0998289 0.0417448 #(-0.0107891 0.0182459 0.0133387 0.00654529 0.00351746 -0.0028236 -0.00652551 -0.00276973 0.00189705 0.00363537 -0.00543967 -0.00428984 -4.74181e-005 0.00728144 -0.000418819 -0.00318095 0.00296512 0.00149376 0.00209253 -0.0105876 -0.0105755 -0.00732988 -0.0124828 -0.00540931 -0.00364074 0.00253872 -0.000591894 0.0020125 0.00672111 -0.0103777 -0.00817489 -0.00341224 0.00892754 0.00393065 0.00183264 0.0170761 0.0103609 0.0093558 -0.00221637 -0.00689539 -0.00883095 -0.00260063 -0.00561736 -0.0152408 -0.0198652 -0.0251051 -0.0359384 -0.043327 -0.0516084 1.19939)) (63.2886 0.0659521 0.0322813 #(-0.0395131 0.0278336 0.0226114 0.0208169 0.00156559 -0.00586198 -0.00373168 -0.0129797 -0.000442788 0.00591266 0.00384389 -0.00649693 -0.000432298 0.00820201 0.00205019 -0.00693928 -0.00561469 0.00651516 0.00426545 -0.00287469 -0.0195372 -0.0148713 -0.00282639 -0.00135895 0.00476877 0.00385195 -0.00114983 0.00160519 0.0150339 -0.00888809 -0.0157333 -0.00871617 -0.00192295 0.00638566 0.00653376 0.0147419 0.00964909 0.00830972 -0.00471322 -0.00721979 -0.00854983 -0.00297041 0.000582071 -0.00321452 -0.0251575 -0.0448269 -0.0465566 -0.0617166 -0.0814745 1.26877)) (68.2143 0.127344 0.0432067 #(-0.00650372 0.0166661 0.0110006 0.0046084 -0.000191608 -0.000655383 -0.0075612 -0.00289214 0.00188358 0.00579054 0.000329202 -0.00681358 -0.00225101 -0.000353251 0.0031628 -0.0053415 -0.000525401 0.00656196 0.00272409 0.00256422 -0.0160209 -0.0140322 -0.00207772 -0.00301927 -0.000189949 -0.00236457 0.00311191 0.00706533 -0.000524762 -0.00984277 -0.0108244 -0.00768298 0.000888997 0.00214318 0.0071796 0.0118653 0.0159322 0.00963205 -0.00200409 -0.0107815 -0.00688397 0.000662548 0.00124322 -0.0216095 -0.024252 -0.0275861 -0.0290191 -0.0455658 -0.0594961 1.20854)) (74.5766 0.00960274 0.0113474 #(-0.0930925 0.0474147 0.0783675 0.00847634 -0.0083235 0.0389507 -0.0156469 -0.0811489 -0.00383005 0.0271399 0.0027488 -0.0036905 -0.0380551 0.0424861 0.036423 -0.0258928 -0.0261861 0.00709007 0.0423739 0.0478494 -0.0457433 -0.0682701 -0.0230027 0.0330979 0.0021217 -0.00664132 -0.0268997 0.0548632 0.100473 -0.0711387 -0.0110561 -0.0158289 -0.0476065 -0.0351137 0.00284219 0.0323319 0.0313311 0.0736398 0.0142766 -0.10177 -0.0582263 0.0770375 0.0914699 0.0357695 -0.12508 -0.0345359 -0.0237482 -0.0585581 -0.687455 1.80702)) (89.851 0.0668036 0.0272671 #(-0.047951 0.0391961 0.0312392 0.0264315 0.0152606 -0.0229461 -0.0203805 -0.0182092 -0.00178092 0.00435629 -0.00460121 -0.00718773 -0.00219992 0.00637422 0.00988643 0.00875952 0.00355863 0.0092556 -0.00376029 -0.00369781 -0.0084366 -0.0248106 -0.00997018 -0.00992863 -0.00298569 0.00552284 0.0193635 0.0324098 0.00560115 -0.0147652 -0.0174123 -0.0176175 -0.017063 -0.00976483 0.00645685 0.0115746 0.0243375 0.0212918 0.0038104 -0.00756 0.00845826 0.00991446 0.00809276 -0.000765567 -0.0407473 -0.0481121 -0.0785197 -0.118162 -0.175228 1.42139)) (111.491 0.0612596 0.0234406 #(-0.071768 0.0568083 0.0427606 0.0216603 -0.00175519 0.00236969 -0.0168044 -0.027955 -0.00413897 0.00759891 0.00307185 -0.0137154 -0.021489 0.00188837 0.0194342 0.0167963 0.0109949 -0.00132022 0.0129203 0.00409717 -0.016515 -0.035451 -0.0211164 -0.0147696 -0.00623048 0.017651 0.0231703 0.0352329 0.0277801 -0.0201851 -0.0270755 -0.0333369 -0.0135395 -0.0048966 -0.00213377 0.01776 0.0243864 0.0268 0.00479255 -0.0136091 0.00196506 0.0109521 0.0263541 0.00149658 -0.0351393 -0.0414662 -0.0804536 -0.15343 -0.262886 1.52039)) (131.563 0.0385887 0.0171263 #(-0.0518673 0.0134846 0.0263128 0.0468026 0.024454 0.0220736 -0.0400596 -0.0676488 -0.0114445 0.0413724 0.0448596 -0.0289181 -0.0607654 0.00419211 0.039212 0.0198165 -0.0106986 -0.00978497 0.0268256 0.0153281 -0.014289 -0.0258232 -0.021492 0.00140582 -0.0194537 -0.0176859 0.00346931 0.0616223 0.0476843 0.000242224 -0.0396149 -0.0480542 -0.0287999 0.00734256 0.00921102 0.0219239 0.0281868 0.0214498 0.0045841 -0.0526773 -0.0290021 0.0477786 0.066508 -0.00482082 -0.060896 0.00723903 0.00689539 -0.17291 -0.656903 1.81153)) (151.886 0.102626 0.0259939 #(-0.070856 0.0486957 0.0480601 0.0368429 0.0182886 -0.00829156 -0.0513057 -0.0475156 -0.00697538 0.0443591 0.0264049 -0.0186967 -0.046636 -0.00991082 0.0358113 0.0296259 -0.00965236 -0.00183771 0.0116684 0.0166791 -0.0164862 -0.0397139 -0.0181811 -0.0084272 -0.01239 -0.000257272 0.0267701 0.0470878 0.0342028 -0.0154802 -0.0370322 -0.0415501 -0.0235126 1.97047e-005 0.0225005 0.0265028 0.0239742 0.0125777 -0.00895148 -0.0232263 -0.000947537 0.0428729 0.0258008 -0.0298816 -0.037036 -0.00471161 -0.0249833 -0.174155 -0.397768 1.60503)) (165.11 0.169794 0.0320682 #(-0.0409658 0.0441689 0.0293712 0.0214998 0.0154116 -0.00248447 -0.0422952 -0.0478381 -0.00388453 0.0270632 0.0266513 -0.00557179 -0.022944 -0.0116277 0.0116475 0.0182246 0.00737678 -0.00598205 -0.00128794 0.00345216 -0.00394256 -0.00695017 -0.0256291 -0.0322332 -0.012631 0.0176517 0.0309905 0.0230604 0.0224319 -0.0106256 -0.0268479 -0.0207674 -0.00587152 -0.00570336 -0.00197812 0.0122906 0.0205968 0.031643 0.00252642 -0.0332331 -0.00542228 0.0405915 0.0309338 -0.0143715 -0.0384462 -0.0185082 -0.0347614 -0.166035 -0.349634 1.55773)) (177.174 0.178624 0.0317519 #(-0.0375195 0.0292643 0.0300942 0.0307154 0.0193178 -0.00509529 -0.0345436 -0.0373165 -0.0172528 0.0236766 0.0201161 -0.0183973 -0.0276741 0.00996924 0.0330329 0.0152227 -0.00951397 -0.0122329 -0.00113485 0.0194899 -0.0119267 -0.0292984 -0.015638 -0.0142287 -0.0148578 -0.000859865 0.0260062 0.0534978 0.0402742 -0.0219816 -0.040437 -0.0341774 -0.0049463 -0.0116811 -0.0123897 0.0190348 0.0504628 0.0449273 -0.00894907 -0.0495895 -0.0187866 0.0407222 0.046073 -0.00801632 -0.0446076 -0.0182126 -0.03077 -0.167466 -0.369669 1.57394)) (179.99 0.221245 0.03506 #(-0.037004 0.0260371 0.0372679 0.0497295 0.0157299 -0.0244911 -0.0537488 -0.0510671 0.00512908 0.05199 0.0203676 -0.0338469 -0.0238147 0.0127183 0.0230843 0.00442021 -0.0115414 0.00421587 0.0188467 -0.00272606 -0.0256457 -0.0344065 -0.0104499 -0.00267908 -0.00204974 0.00352165 0.02398 0.0343543 0.0255179 -0.0152773 -0.0303301 -0.0266642 -0.0139434 -0.00355751 -0.0084824 0.0107571 0.0423518 0.0526576 -0.00233367 -0.0445417 -0.0249914 0.0319504 0.0506834 -0.0160456 -0.0561795 -0.0084321 -0.00738221 -0.153557 -0.379863 1.55632)) (166.887 0.252327 0.038884 #(-0.0419053 0.0366535 0.0498127 0.0359369 0.00208074 -0.0250268 -0.0524974 -0.0402762 0.00682585 0.0354895 0.0297739 -0.0147708 -0.0304251 -0.00374599 0.0183841 0.0130221 0.00121661 0.00411938 0.00494517 0.000507366 -0.0263356 -0.0463632 -0.0168647 0.0149596 0.0144969 0.00307392 0.0082568 0.0288554 0.0295293 -0.00737698 -0.0363064 -0.0244228 -0.0110509 -0.00137184 -0.01354 0.00159516 0.0392046 0.0550105 0.0155153 -0.0394186 -0.0271276 0.0202588 0.0342747 -0.0055672 -0.0407041 -0.0119139 -0.0198007 -0.157004 -0.344951 1.53129)) (164.943 0.182476 0.0332611 #(-0.0614847 0.034366 0.0618075 0.0440773 0.010115 -0.0176925 -0.0502932 -0.0698586 -0.0117179 0.0583499 0.0553452 -0.0141319 -0.052825 -0.00920142 0.0291995 0.0159293 -0.00586749 -0.00306322 0.0226316 0.00427445 -0.0340741 -0.0437776 -0.0123615 0.00698813 0.00470649 0.00949797 0.00789906 0.0335011 0.0219034 -0.00266724 -0.0265675 -0.030155 -0.0143053 -0.0093868 -0.00158663 0.0163901 0.0203923 0.0417646 0.0187303 -0.0392964 -0.037276 0.0437944 0.0678762 -0.016769 -0.0789091 -0.0197703 0.0398731 -0.156601 -0.511722 1.65878)) (176.99 0.261053 0.0384053 #(-0.06 0.056536 0.045999 0.0280942 0.0117416 -0.0124533 -0.0449422 -0.0463361 -0.00718186 0.0308653 0.0198448 -0.0192072 -0.0242862 0.0065568 0.031481 0.0162032 -0.00801501 -0.00216827 0.0134013 -0.00587761 -0.0383848 -0.0362193 -0.0129257 0.0157857 0.00474063 -0.00184301 0.0202611 0.041013 0.0198278 -0.0191734 -0.029208 -0.0221024 -0.0116136 -0.0121702 -0.00611537 0.0173498 0.0404119 0.0315245 -0.00593292 -0.0237962 -0.000431722 0.0439062 0.0334822 -0.0297822 -0.0607389 -0.0164012 -0.00830834 -0.154607 -0.362478 1.54998)) (176.048 0.159462 0.0300963 #(-0.0377232 0.0103334 0.036835 0.0488153 0.0179723 -0.00819109 -0.0460628 -0.0619188 -0.00111458 0.0446256 0.032363 -0.00836746 -0.0360712 -0.00850298 0.0216202 0.0175984 -0.000914048 -0.0173185 0.00126597 0.0264074 -0.00629105 -0.043736 -0.017196 0.00494882 -0.000320422 -0.012511 0.00430157 0.0466093 0.0305521 -0.0031329 -0.0376142 -0.024873 0.00750779 -0.012678 -0.0104912 0.00134055 0.0376222 0.0412994 -0.0218273 -0.0452171 -0.0128663 0.072725 0.0680508 -0.0173601 -0.0684261 -0.0212582 0.0188153 -0.175166 -0.561992 1.72452)) (171.946 0.2352 0.0369847 #(-0.0512015 0.0329072 0.0503361 0.0280294 0.00184622 -0.0107644 -0.0348259 -0.0337681 0.00209173 0.0265416 0.028044 -0.0189349 -0.0371111 -0.000802031 0.0279831 0.0122725 -0.00874739 -0.00112342 0.0180879 0.000223799 -0.0259366 -0.0351892 -0.00449204 0.00197593 -0.0162875 -0.011366 0.0181628 0.0541492 0.0395807 -0.0167336 -0.0418708 -0.0160073 -0.00774302 -0.00128406 -0.00712924 -0.00703709 0.0178146 0.0397532 0.00726889 -0.0174794 -0.00498909 0.0427668 0.0408804 -0.0175914 -0.0525046 -0.0244365 -0.014682 -0.171468 -0.395718 1.59284)) (185.859 0.163683 0.0296764 #(-0.0468658 0.0116617 0.0555765 0.036102 0.0116869 -0.0136073 -0.0419413 -0.0311445 -0.015847 0.0536179 0.0374088 -0.0318291 -0.0562696 -0.0204646 0.0520056 0.0366832 -0.00267281 -0.0268453 0.00390152 0.0151844 -0.0141306 -0.026449 -0.00214409 -0.00146158 -0.0202671 -0.0306729 0.00986482 0.0542944 0.0595679 0.00293662 -0.0374089 -0.0316308 -0.0279362 -0.00383883 -0.00461755 -0.00381387 0.0302674 0.0462364 0.00234255 -0.0420869 -0.0176493 0.0621579 0.0781717 -0.0259631 -0.0837177 -0.0197173 0.0222038 -0.172749 -0.543442 1.71216)) (211.324 0.258974 0.0350069 #(-0.0303184 0.0212199 0.0351346 0.0323836 0.0108293 -0.0194528 -0.0440712 -0.0258231 0.0179244 0.0423101 0.00743043 -0.040367 -0.0363898 0.0067014 0.0337238 0.0109171 -0.0145224 -0.00777405 0.0187512 0.010748 -0.0157507 -0.020169 -0.00503133 -0.00636303 -0.0319918 -0.0279937 0.0172805 0.0607111 0.0519986 -0.00764891 -0.0419867 -0.0321224 0.0100713 0.00236086 -0.0196657 -0.0170583 0.0223451 0.0362193 0.000122523 -0.0184589 0.0140273 0.0644042 0.0497302 -0.0380606 -0.0744375 -0.0264989 -0.0209174 -0.164711 -0.384479 1.59087)) (230.546 0.254813 0.0332454 #(-0.0214216 0.00872379 0.0339929 0.0315809 0.0174031 -0.0232373 -0.0489485 -0.0241287 0.0209643 0.0453702 0.0190406 -0.0440306 -0.0441669 -0.00157853 0.0268724 0.0234296 -0.000401617 -0.0057701 0.000344993 -0.0054568 -0.0178071 0.0024068 0.0155485 0.000746876 -0.0375718 -0.0484998 0.00853225 0.0571187 0.0551759 -0.0142224 -0.0451274 -0.0277836 0.0263546 0.0402985 -0.0197452 -0.0401687 -0.00351748 0.0313089 0.00705256 -0.0369839 -0.00653953 0.0851077 0.0978434 -0.0156217 -0.102129 -0.0527658 0.00792703 -0.158984 -0.494505 1.67382)) (251.512 0.22152 0.0296775 #(0.00271906 -0.0125085 0.0301646 0.0306547 0.00855251 -0.0179234 -0.0350287 -0.0305762 0.00779454 0.053486 0.0394365 -0.0393962 -0.0650717 -0.0198502 0.0326874 0.039916 -0.0010092 -0.0179188 0.00205602 -0.00398159 -0.00877683 0.0106262 0.0187416 -0.0120917 -0.0564597 -0.0545574 0.0119312 0.0765 0.0649359 -0.0149672 -0.0521681 -0.0268912 0.0228738 0.0277597 -0.00505434 -0.0391086 -0.000955081 0.0337932 -0.00277864 -0.0493297 -0.0119853 0.100552 0.124828 -0.0159932 -0.127861 -0.0612138 0.0295559 -0.144989 -0.555044 1.70991)) (254.186 0.155867 0.0247629 #(0.011018 -0.035849 0.0315776 0.0392745 0.01848 -0.0184897 -0.0290829 -0.049739 -0.000114797 0.0517803 0.04403 -0.0251357 -0.0530782 -0.0079027 0.0214459 0.0319004 -0.0185972 -0.0210457 -0.00556451 0.0118538 0.000887009 0.0257463 0.0265477 -0.0284303 -0.0724463 -0.0721507 0.0469847 0.0785231 0.069301 -0.026447 -0.064972 -0.032767 0.00653783 0.0563972 0.0303594 -0.0350536 -0.0475477 0.0379776 0.00958391 -0.0490296 -0.0492565 0.0859668 0.161288 -0.000991608 -0.140484 -0.0439296 0.0763862 -0.147115 -0.750695 1.84834)) (225.37 0.0803291 0.0188794 #(0.0290101 -0.0687017 0.0407707 0.0383633 -0.0152389 0.00254714 0.0114647 -0.0328925 -0.021924 0.00257726 0.0623568 -0.00416147 -0.0660898 -0.0300196 0.0572706 0.0552422 -0.027837 -0.0653128 0.00149151 0.0264922 -0.00315019 0.0193053 0.0486365 0.00427569 -0.0987687 -0.0861261 0.00501995 0.0945006 0.109231 -0.0131216 -0.077788 -0.0512939 -0.00858637 0.0620822 0.041699 -0.0369608 -0.0380424 0.0273551 0.0409665 -0.0644617 -0.0854918 0.0805598 0.178136 0.0300991 -0.186435 -0.0584791 0.205418 -0.075875 -1.13303 2.07226)) (198.485 0.0417265 0.0144991 #(0.0414603 -0.0623938 0.0061811 0.0288222 -0.0158102 0.0252802 0.00307337 -0.00304176 0.00367747 -0.0489033 0.0357009 0.0204158 -0.0552591 -0.0256414 0.0346049 0.0958179 -0.0284009 -0.100873 -0.00722169 0.0205522 0.0295442 0.033256 0.0421494 0.00768483 -0.110423 -0.0846969 -0.0244979 0.0889337 0.157045 0.00102777 -0.0813333 -0.0900497 -0.0138341 0.0341514 0.0721558 0.00377355 -0.033424 0.010766 0.0245269 -0.0515001 -0.119286 0.0335791 0.213235 0.125951 -0.204453 -0.179761 0.270221 0.202002 -1.65027 2.32378)) (171.548 0.1509 0.0296587 #(0.0250778 -0.0426171 0.00843798 0.0396997 0.0226322 -0.0146932 -0.0283293 -0.01936 0.0069322 0.0354412 0.0250028 -0.0357834 -0.0414478 -0.0136723 0.0292158 0.020287 -0.00117164 -0.00726955 -0.00706735 0.000159039 -0.00407658 0.0190887 0.0257392 -0.0278326 -0.0682253 -0.0552612 0.0202806 0.0931883 0.0784599 -0.037487 -0.082894 -0.0424946 0.0518775 0.0627942 0.000169138 -0.0458972 -0.0190695 0.0107115 -0.00659794 -0.0314802 0.00511231 0.0991288 0.0788463 -0.0108271 -0.0699992 -0.0146887 -0.00873203 -0.228192 -0.553044 1.75651)) (138.651 0.0571929 0.02031 #(0.0213914 -0.0306978 0.00848927 0.0130779 0.00721775 0.00427365 0.00961346 -0.0314829 -0.018867 0.036295 0.03503 -0.0305203 -0.0463152 -0.0107846 0.0382213 0.0409777 -0.0373991 -0.0384969 0.0128019 0.00295524 0.0157249 0.0419502 0.0294107 -0.0318793 -0.11091 -0.0681277 0.0179675 0.131618 0.114326 -0.0427296 -0.109902 -0.0736138 0.0191553 0.091943 0.0543933 -0.0340794 -0.0436619 0.00746334 -0.0066161 -0.0679531 -0.0238454 0.0924077 0.161235 0.0122723 -0.139703 -0.0326624 0.115233 -0.166794 -0.931623 1.99133)) (113.308 0.193753 0.0413518 #(-0.0270571 0.018724 0.0316812 0.0297654 0.00202789 -0.0163134 -0.0290023 -0.0123064 0.0176842 0.0233915 -0.00357253 -0.0336344 -0.0271282 0.00653117 0.0284495 0.0179925 -0.004167 -0.0157728 -0.00964692 0.000267421 0.00122534 0.0146035 0.00149512 -0.0396562 -0.058053 -0.0255875 0.0451789 0.0754793 0.044493 -0.0379303 -0.0597916 -0.015322 0.0420665 0.0354546 -0.0132543 -0.0383832 -0.0285421 0.000937585 0.0195054 0.0265873 0.0502106 0.0593278 0.0136192 -0.0502636 -0.0466451 -0.0180557 -0.0524014 -0.164365 -0.318595 1.53476)) (103.037 0.0623253 0.0245944 #(-0.00724495 -0.00593484 0.0107629 0.0261896 0.0129414 0.00340164 -0.0251773 -0.0270683 0.00747135 0.0385192 0.018441 -0.0377958 -0.0304305 0.00450653 0.0229534 0.00567204 -0.0264594 -0.0176736 0.000876183 0.0471199 0.0172663 0.0124283 0.00241253 -0.0617734 -0.103682 -0.0406255 0.0578767 0.121063 0.0822661 -0.0454017 -0.102194 -0.042812 0.0321046 0.0833275 0.00602523 -0.0478943 -0.043304 0.000262387 0.00598665 -0.00374976 0.0385322 0.079333 0.0654235 -0.0354309 -0.092082 0.00159915 0.0131218 -0.204327 -0.571633 1.75234)) (92.5577 0.120027 0.0360108 #(-0.0398489 0.0324612 0.0367935 0.0220619 0.00704562 -0.0272926 -0.0200099 -0.00659618 0.0169783 0.015708 -0.00599385 -0.0153675 -0.0128987 0.0082064 0.0102226 -0.000522355 -0.00199441 -0.00674596 -0.00220103 -0.00689017 -0.00809083 0.00336812 -0.0126411 -0.0439452 -0.04063 0.00361202 0.0505336 0.0555444 0.02238 -0.0310165 -0.038806 -0.00364963 0.0180895 0.00954 -0.00503501 -0.0195219 -0.0205427 0.00318622 0.0185383 0.0345637 0.0376351 0.0372337 0.00566722 -0.0260961 -0.0314731 -0.0229805 -0.0612615 -0.148592 -0.24421 1.45165)) (66.5989 0.0842179 0.0355606 #(-0.0384904 0.0427509 0.0324356 0.0194716 -0.00585732 -0.0144022 -0.0118444 -0.00525952 0.0111836 0.00537657 -0.00948216 -0.00957872 -0.000929858 0.00996204 0.00650146 0.00151737 -0.00610687 -0.00883977 -0.0111524 -0.00821151 -0.0121669 -0.00254634 -0.0339117 -0.0355781 -0.013952 0.0280202 0.0436449 0.0292268 0.00874941 -0.0239858 -0.0194654 -0.00890681 0.0037191 -0.00475951 -0.00518569 -0.00236431 0.00776458 0.0118334 0.0107269 0.0178917 0.0261446 0.0384696 0.0138593 -0.0230752 -0.043364 -0.0319342 -0.0459236 -0.112816 -0.180369 1.35766)) (42.7254 0.0264534 0.0248827 #(-0.0413135 0.0213958 0.036281 0.0248983 -0.0151715 -0.0222269 -0.00567853 0.00505671 0.017208 0.024368 -0.0203921 -0.0162792 0.000440382 0.0151094 0.0109901 -0.000613158 -0.00984668 -0.00906093 -0.00789341 0.00260445 0.0124987 -0.0123556 -0.0457957 -0.0562666 -0.0106157 0.0486385 0.0540115 0.0360568 -0.00307563 -0.0466828 -0.0306841 0.00913136 0.0174993 0.00528422 -0.0273256 -0.0166686 0.00261137 0.0230377 0.0120899 -0.00600584 0.0223933 0.0459099 0.00977329 -0.0223494 -0.0479412 -0.0230021 -0.0404154 -0.102133 -0.204478 1.38436)) (30.9113 0.0516676 0.0408837 #(-0.014936 0.00941983 0.0118751 0.000575508 0.00581291 -0.00413739 -0.012136 0.0103523 0.00720992 0.0100773 -0.000124851 -0.00765056 0.00255218 0.000894253 0.00544408 0.000794387 -0.00215897 -0.00898489 -0.0117924 -0.00653947 -0.0064785 -0.00840759 -0.0105823 -0.0100678 0.000175767 0.0102663 0.00786819 0.0237505 -0.00215373 -0.0266525 -0.00900966 -0.00600343 -0.0028658 -0.00373159 -0.00238924 -0.00278976 -0.00429102 -0.00212087 0.00253061 0.0127614 0.0230914 0.0151189 0.00146143 -0.0117057 -0.00462498 -0.00318648 -0.0265484 -0.0369997 -0.0675645 1.14867)) (15.3693 0.00836665 0.0233319 #(-0.0341159 0.00806944 0.0216334 0.0174292 -0.0149921 0.016248 -0.0180928 -0.00306738 0.0350942 0.00513288 -0.00769301 0.00579646 -0.0107035 0.0131971 0.00589453 -0.00674269 0.00261838 -0.00786856 -0.00176616 0.00564664 -0.0345646 -0.0240044 -0.0148234 -0.0133658 -0.00412353 0.0369617 0.00196105 0.0368174 0.00564198 -0.0501549 -0.0297051 0.0178704 0.0210161 -0.0155626 -0.00837293 -0.0178571 0.00812323 0.00816448 0.00151141 0.0221456 -0.00390799 0.026406 0.0064334 -0.00797861 -0.0261832 0.013857 -0.0837799 -0.0591936 -0.120175 1.27127)) (7.76696 0.0131245 0.041107 #(-0.0123117 0.00617644 -0.00098044 0.00751582 -0.00251782 -0.00337365 -0.00106648 -0.00202962 0.024234 0.000865013 -0.000377017 0.00388929 -0.00333191 0.0133695 -0.00022004 -0.00378028 -0.00320862 -0.00759729 0.010062 -0.0256383 -0.0192849 -0.0214377 -0.0114302 -0.00124626 0.00155824 0.0193932 0.00236924 0.0225305 0.00325289 -0.026002 -0.0156565 0.0123504 0.013013 -0.00652565 -0.00493443 -0.0110295 -0.00472477 0.0120849 0.0080524 0.00918786 -0.00908903 0.0273415 -0.00444183 -0.0233399 -0.0047778 -0.00719849 -0.0426428 -0.018549 -0.0650151 1.15688)) (8.89632 0.0142545 0.0400286 #(-0.00575181 0.0168131 -0.000191827 -0.023498 -0.00423681 0.025755 -0.0183111 -0.00376236 0.0252077 0.008183 -0.0122062 -0.003721 0.00288939 0.0148372 0.00886276 0.00423061 -0.00963574 0.000873132 0.00541097 -0.0280967 -0.00998672 -0.0238806 -0.0217161 -0.00753574 0.000230236 0.0280799 -0.00512027 0.00849866 0.0322065 -0.0343016 -0.00927757 0.00120511 0.0135002 -0.00237087 -0.0093355 -0.00156968 -0.00792312 0.012794 0.00838747 -0.0119611 0.00605868 -0.00193377 0.0117903 0.00816965 -0.0157005 -0.000300004 -0.0367019 -0.0246368 -0.0709357 1.15223)) (9.78194 0.0170927 0.0418016 #(-0.0124638 0.0024989 -0.00185738 -0.00369259 -0.00329147 0.0015451 0.00184027 0.00970003 0.0141567 0.0120678 0.00775671 -0.00277263 0.00105104 0.000310846 0.00513042 -0.0141369 -0.008812 0.00521768 -0.00206552 -0.00604551 -0.0120649 -0.0176494 -0.0204137 -0.0115251 0.00627893 0.0162767 0.0108663 0.00560173 0.00467505 -0.02242 -0.0112209 0.000456198 0.00829053 2.30481e-005 0.00913467 -0.00846952 0.00517986 0.00864013 -0.00133154 0.00581594 -0.00610526 0.00869507 0.00727336 -0.00365842 -0.0143366 -0.0169279 -0.0336561 -0.0311221 -0.071088 1.16895)) (11.5445 0.0160741 0.0373143 #(-0.0249007 -0.00275895 -0.000517276 0.00756758 -0.00172192 0.0176724 0.00486407 0.00102775 0.0190812 0.027876 -0.00029893 -0.00443258 -0.00532617 -0.0133783 -0.00615458 -0.00822798 -0.00903328 0.00488343 0.0122464 -0.0119956 -0.0122127 -0.0164293 -0.0183456 -0.00082874 -0.00101657 0.00939199 0.0092591 0.0164931 -0.0114048 -0.0252425 -0.0161846 -0.00699262 0.00668263 0.0180297 0.000800448 0.00638066 0.00681553 0.0168308 0.0103385 -0.00081722 -0.00148622 0.00392006 -0.00755191 -0.0011792 -0.0241647 -0.0123012 -0.0393747 -0.0402423 -0.0754633 1.19146)) (13.3295 0.0127553 0.0309342 #(-0.0231698 0.0191559 -0.0139377 0.0092944 0.0121271 -0.000232179 -0.0124583 0.0134314 0.0164421 0.024357 -7.36386e-005 -0.0199401 -0.00337023 0.0151218 -0.00455778 -0.0115682 -0.0172743 0.000976708 0.017724 -0.0074562 -0.0285266 -0.0151716 -0.030822 0.00497904 0.00790638 0.0099445 0.0162362 0.0264739 0.0175367 -0.0501894 -0.0343044 -0.00901378 0.014952 0.0105903 -0.0101648 -0.000755211 0.0171476 0.0293293 0.00838466 -0.0102206 0.00315026 0.0306831 -0.00269206 0.00531439 -0.0326658 -0.0252288 -0.0474296 -0.0704353 -0.143764 1.28812)) (15.3429 0.0120405 0.0280135 #(-0.0309064 0.0271264 0.0147487 0.00498133 0.00106183 0.0147637 -0.040844 -0.0169095 0.0389369 0.0194572 -0.00221378 -0.0170094 -0.00138509 0.0162374 0.00582746 -0.0230331 -0.0117961 -0.00156591 0.0229133 0.027122 -0.0540262 -0.0410968 -0.013133 -0.00158327 -0.0109391 0.0261228 0.0330272 0.0405228 0.0323432 -0.0623613 -0.0561195 -0.00527043 0.00668445 0.0267738 -0.00936441 -0.0283996 0.0234758 0.0255722 0.014511 -0.0129606 0.00174176 0.0403901 0.0353441 -0.000116604 -0.0455759 -0.0479024 -0.0481118 -0.0843258 -0.209947 1.37135)) (17.6721 0.019402 0.0331344 #(-0.0350609 0.0339703 0.0145886 0.000690795 0.000922172 0.00738286 -0.01517 -0.0088783 0.0201723 0.0122574 -0.0158588 -0.0119165 -0.0019645 0.020945 -0.000870479 -0.0108681 -0.00586048 0.00538485 0.0104022 -0.00321434 -0.0157964 -0.0469299 -0.0215821 -0.00373954 0.00283885 0.0148254 0.0275313 0.0364303 0.0161417 -0.0308895 -0.0417433 -0.00377748 0.0165364 0.00397155 -0.0227846 -0.0260575 0.00618754 0.0551286 0.0147865 -0.0176932 0.00941883 0.0495573 0.031147 -0.00860301 -0.0380403 -0.0458936 -0.0610949 -0.096874 -0.18716 1.3588)) (20.0442 0.0140521 0.0264774 #(-0.0709867 0.0453836 0.0460421 0.0146813 -0.0179832 0.00433517 -0.0165851 -0.00628279 0.0245804 0.0150767 -0.0114593 -0.0368579 0.00386748 0.0248403 0.00774181 -0.0237615 -0.0110972 0.00908011 0.0143327 0.012267 0.00781146 -0.0256289 -0.0705544 -0.0244927 -0.0213969 0.0392408 0.0426976 0.0769561 0.011974 -0.0784876 -0.0580746 0.0130622 0.0449024 0.0142022 -0.0384532 -0.0269607 0.00680663 0.0207385 0.0149218 -0.0149792 0.0278171 0.0648385 0.0568704 -0.00419316 -0.0892845 -0.0271809 -0.0635848 -0.137194 -0.290703 1.49428)) (22.8017 0.0273646 0.0346427 #(-0.0720317 0.0448821 0.0348815 0.0233662 -0.000985435 0.00226309 -0.0135519 -0.0209769 0.0167468 0.0101012 -0.0194102 -0.00439263 0.00504041 0.0156837 0.00598467 -0.0264652 -0.0115608 0.0185426 -0.0068165 0.0100013 -0.00188157 -0.018496 -0.0458203 -0.0312296 -0.00116534 0.0335279 0.0330629 0.0395021 0.0183978 -0.0427994 -0.0459782 0.0054253 0.0243994 -0.00582722 -0.0111125 -0.0241409 0.0054475 0.0251814 0.00891366 -0.000905372 0.0228307 0.0523174 0.0382179 -0.00320691 -0.0354807 -0.0419394 -0.0835182 -0.139596 -0.249583 1.45587)) (26.3474 0.0219953 0.0288932 #(-0.0765435 0.0426832 0.0419785 0.0283921 0.00340572 -0.00535423 -0.0212032 -0.0116924 0.00206213 0.00816488 -0.0127589 0.00934433 0.0163962 0.00930891 -0.00568188 -0.0355663 -0.0130979 0.0042239 0.0221761 0.0294585 -0.00590132 -0.0300225 -0.0529725 -0.04428 -0.00514512 0.0547305 0.0372759 0.0478592 0.0239117 -0.0702372 -0.0687804 0.0195622 0.0191373 0.0223794 0.0135526 -0.038104 -0.00282542 0.00433172 0.00929822 -0.00582157 0.0154465 0.0665377 0.0342229 0.00927136 -0.0205276 -0.0192793 -0.0956723 -0.177253 -0.343554 1.56045)) (30.1984 0.030065 0.0315528 #(-0.0979213 0.0706986 0.0397353 0.027229 -0.00146723 -0.00438662 -0.0236935 -0.0188674 0.00900385 0.011066 0.00529251 -0.00704211 0.00609007 0.00670222 0.011048 -0.0216173 -0.0263168 0.00421382 0.0169606 0.0205924 -0.018071 -0.0136472 -0.0356033 -0.0382373 0.00240587 0.00751786 0.0412371 0.0584634 0.033329 -0.0663578 -0.0641406 -0.00811986 0.0285871 0.0444783 -0.00260303 -0.0335565 -0.018181 0.00985673 0.00558086 0.0118218 0.023386 0.0433098 0.0400329 0.0116843 -0.0148176 -0.058095 -0.0779079 -0.157939 -0.31358 1.52513)) (32.1428 0.0318259 0.0314665 #(-0.0775589 0.051683 0.0288251 0.0187194 0.00984706 0.00338128 -0.0202275 -0.00651548 0.0136416 -0.00760369 0.00215332 -0.0233182 0.0134451 0.0247162 -0.00404254 -0.0118734 -0.018538 0.0113604 0.00736548 0.00204067 -0.0115196 -0.0197442 -0.0154772 -0.0363295 -0.0150368 0.0175515 0.0394107 0.053815 0.00585165 -0.0330152 -0.054677 -0.0159929 0.0341672 0.015965 -0.00299163 -0.0189119 -0.0067154 0.0143037 -0.000256563 -0.00532035 0.0260945 0.0429435 0.0476952 0.0109455 -0.0235557 -0.0298008 -0.0826709 -0.176099 -0.325686 1.54201)) (31.4202 0.0318335 0.0318301 #(-0.0971744 0.0647286 0.0577288 0.0197214 -0.00649152 -0.0216951 -0.0189122 0.00437908 0.0284074 -0.000966733 -0.0171446 -0.0107114 0.00440035 0.0142388 0.00532634 -0.0126468 -0.02169 0.00523199 0.0297256 2.45184e-005 -0.00810739 -0.0215433 -0.0335994 -0.053856 -0.00465438 0.037238 0.0491757 0.0548962 0.014561 -0.073022 -0.0403319 -0.0130117 0.00834094 0.0434427 -0.00417276 -0.0078477 -0.0118494 0.00744896 -0.00313036 -0.0123154 0.0214602 0.059643 0.056315 0.00853147 -0.0377529 -0.0250175 -0.0860953 -0.178818 -0.327932 1.55029)) (32.4444 0.0301064 0.0304621 #(-0.0807 0.057348 0.0412646 0.0366669 -0.00996071 -0.0130091 -0.0387371 -0.00774177 0.0350818 0.0241313 -0.0154081 -0.0231186 0.00127267 0.0151109 -0.000317825 -0.0114935 -0.0136006 -0.00971232 0.0131985 0.0123626 0.0233086 -0.0265093 -0.0606854 -0.0258504 -0.0165391 0.0251411 0.0470309 0.053574 0.0180307 -0.0502542 -0.0485886 -0.0164236 0.019835 0.0329606 -0.00101179 -0.0302517 -0.0018849 0.0308459 -0.00743693 -0.0159462 0.0094627 0.0539938 0.0554317 0.0208811 -0.0307534 -0.0204858 -0.0821197 -0.181269 -0.37734 1.5857)) (40.9172 0.0650495 0.0398721 #(-0.0572582 0.0414552 0.0350494 0.0183922 0.00440463 -0.00850967 -0.00613651 -0.0179503 -0.00262387 0.0195232 -0.0131559 -0.00454892 0.00177392 0.0065445 0.00194393 -0.00781929 -0.00616173 -0.00313379 -0.000702812 -0.00178652 -0.014563 -0.0209123 -0.0269462 -0.0162782 0.00491859 0.0228838 0.0258315 0.027738 0.00459301 -0.0176909 -0.0295674 -0.0017052 0.0107792 -0.00448647 -0.00151116 -0.00392171 -0.00643332 0.00597558 0.0150378 0.0149934 0.0222908 0.0451681 0.0323751 0.00353828 -0.0263688 -0.050642 -0.0923144 -0.142247 -0.194605 1.40832)) (42.9245 0.0380718 0.0297817 #(-0.0619835 0.0538987 0.0254833 0.0191851 0.000713942 -0.00965684 -0.0114323 -0.0178469 0.0175577 0.0131995 -0.0072923 -0.00832834 -0.00811007 0.00959091 0.00557504 -0.00996733 -0.00855112 -0.00974844 0.00913783 0.0117909 -0.0045425 -0.0256592 -0.0292943 -0.0307577 -0.00238131 0.0201101 0.0259082 0.0446931 0.0181626 -0.0452096 -0.0297406 -0.0143662 0.023201 0.0203186 -0.00421108 -0.0211625 -0.00441318 0.019116 0.000645667 -0.00607597 0.0221206 0.0483723 0.0479185 0.015123 -0.02304 -0.0353189 -0.100976 -0.171954 -0.291149 1.51649)) (35.4435 0.0741689 0.0457449 #(-0.0592469 0.0408393 0.0310192 0.0213087 0.000897261 -0.0097075 -0.0127374 0.00034184 0.00697528 0.00416767 -0.00709337 -0.00543548 -0.00262597 -0.000460251 0.00462508 -0.000103108 -0.00210094 -0.000600998 -0.0064083 -0.00812498 -0.0110879 -0.014929 -0.0210607 -0.0126928 -0.00625044 0.0121755 0.0253735 0.0353037 0.00209597 -0.0177743 -0.0179092 -0.0111032 0.00635534 -0.000694276 -0.00804003 -0.00382186 0.00598897 0.00926817 0.00874331 0.0115986 0.0207321 0.0434171 0.0317387 0.00501884 -0.0295828 -0.0488442 -0.0859817 -0.140721 -0.179372 1.38875)) (31.5655 0.0508454 0.0401347 #(-0.0590031 0.0481201 0.0415922 0.0145118 -0.00625927 -0.010634 -0.022698 0.00794115 0.0129372 0.011031 -0.00684227 -0.0269145 0.000574552 0.0097944 0.00870401 -0.0154143 -0.00608816 -0.00337432 0.00658044 -0.000562268 -0.0114323 -0.0168882 -0.0267139 -0.0354475 -0.00491647 0.0324642 0.0368173 0.0353376 5.39129e-005 -0.039796 -0.021031 -0.00123375 0.0136188 -0.00348024 -0.00871654 0.00380723 0.0164729 0.0135323 -0.00439517 -0.0080045 0.0109003 0.0528155 0.0444091 0.0206946 -0.0118078 -0.0443984 -0.10415 -0.168437 -0.257971 1.47706)) (30.9527 0.0382595 0.0351577 #(-0.0677928 0.0651594 0.0430938 0.00356799 -0.0158889 0.000628987 -0.0127898 -0.00558382 0.0158968 -0.00226313 -0.00538957 -0.00778266 0.00155987 0.00443769 0.00375692 -0.0105507 -0.0224075 0.00426307 0.00792974 0.000294564 -0.000787178 -0.0161313 -0.0342735 -0.0403149 -0.00675935 0.0293195 0.0435918 0.0478281 0.00545949 -0.0534773 -0.037442 -0.0111263 0.0321929 0.020819 -0.00755799 -0.00482975 -0.00528935 0.0154923 0.00365394 -0.00549552 0.0121106 0.053678 0.0478409 0.019575 -0.0286409 -0.0335462 -0.0765612 -0.177995 -0.331 1.53233)) (31.4075 0.0364452 0.0340646 #(-0.0649986 0.0576299 0.0324902 0.00773543 -0.00458665 0.00495247 -0.0191388 0.000145591 0.000613326 0.00395394 0.000636622 -0.0207581 0.00467082 0.0155624 0.0110861 -0.0131649 -0.0232556 -0.00176555 0.00395216 0.00802351 -0.00893858 -0.021152 -0.016588 -0.0283998 -0.0138537 0.0249458 0.0287153 0.0452579 0.0204232 -0.053952 -0.0535749 0.00280977 0.0440965 0.0328232 -0.0150095 -0.0388665 -0.0096805 0.0162576 0.0154429 -0.00290426 0.029801 0.0596534 0.0460045 -0.00865289 -0.0497685 -0.0141297 -0.0805603 -0.160605 -0.335686 1.53526)) (31.6576 0.0348485 0.0331782 #(-0.0618954 0.0523533 0.0235303 0.0153525 0.00172889 -0.00168407 -0.0110182 -0.0142045 0.0170727 1.99435e-006 0.0017121 -0.0190737 -0.0111033 0.0169703 0.0280168 -0.01063 -0.0322064 0.00426402 -0.00485 0.0146215 -0.00758876 -0.0226077 -0.0252398 -0.0189545 -0.00568113 0.00980641 0.0269183 0.0392206 0.0257317 -0.0475402 -0.0534524 0.00178895 0.0586262 0.0278462 -0.0327184 -0.0414883 -0.0120922 0.029826 0.0131607 0.00598402 0.00931486 0.0642811 0.057244 -0.00679361 -0.0464739 -0.04173 -0.072625 -0.161229 -0.31275 1.52407)) (34.7383 0.0559897 0.0401467 #(-0.0415582 0.026703 0.0259679 0.0111422 0.00204608 -0.00618647 -0.00950887 0.0120808 0.0102095 -0.00150538 -0.0114168 -0.0193223 -0.00463892 0.0133971 0.0187653 -0.00583736 -0.0127744 -0.0100488 0.0111868 0.0106626 -0.0205418 -0.0312655 -0.0304695 -0.0160161 -0.00137347 0.0194299 0.0309445 0.0366569 0.00705069 -0.0166283 -0.0404884 -0.00764167 0.0169512 0.0132674 -0.00907035 -0.0275286 -0.0054365 0.0307347 0.0158178 0.00474018 0.0264909 0.0460957 0.0291759 -0.00850643 -0.0359522 -0.0586856 -0.0731063 -0.11696 -0.205816 1.40186)) (36.4119 0.0463771 0.0356887 #(-0.0389951 0.0307876 0.0205879 0.00908905 0.00555359 -0.0121034 -0.00687764 0.00752914 0.0176609 0.00566536 -0.0208413 -0.0229413 0.00156059 0.00543264 0.00694066 0.00249693 -0.00335328 0.000401892 0.0138262 0.00128668 -0.0283111 -0.0256373 -0.0237493 -0.0291584 -0.00703129 0.0152271 0.0393229 0.0452958 0.0231804 -0.0291094 -0.0417306 -0.00489797 0.0160917 0.000583816 -0.0194554 -0.0235409 0.00563181 0.0393978 0.0237208 -0.00447947 0.0171657 0.0551852 0.0282278 -0.022097 -0.0371377 -0.0598215 -0.0687185 -0.118988 -0.195594 1.40087)) (31.5195 0.0823719 0.0511211 #(-0.0506811 0.032627 0.0260271 0.0133287 0.00707792 -0.00716418 -0.00792555 -0.00164158 4.37169e-005 0.00655899 -0.00403331 -0.00510847 -0.00250636 0.00465444 0.012035 0.0010902 -0.00567664 -0.00723898 -0.00466529 -0.00771452 -0.0268553 -0.0264261 -0.00282889 0.000687852 0.00062155 0.00777579 0.0113666 0.0250398 0.020167 -0.0104087 -0.0261586 -0.0112883 -0.00423545 0.0070317 -0.000811418 -0.0200803 0.00317688 0.0237687 0.0201803 0.0121356 0.0175142 0.033371 0.0253085 -0.00456846 -0.0415392 -0.0596395 -0.0783815 -0.0936876 -0.114877 1.30627)) (25.4029 0.0602808 0.0487134 #(-0.0551556 0.0394576 0.0270103 0.0236226 0.00186073 -0.00761447 -0.00740441 -0.00712806 0.00591052 -0.00309897 -0.00157216 -0.0120145 -0.00111416 0.0139671 0.00880658 -0.0012513 0.00244409 -0.0133322 -0.00925009 0.00123142 -0.034305 -0.0168858 -0.00914378 -0.0110158 0.000306792 0.0116358 0.0236282 0.0251389 0.00218792 -0.00727665 -0.0207191 -0.00825958 0.00274023 -0.00288428 -0.00666814 -0.0172675 0.00904082 0.0154382 0.0150386 0.0254515 0.0314402 0.0294853 0.0295901 -0.00445611 -0.0469681 -0.0574121 -0.0877862 -0.106583 -0.135491 1.339)) (22.7468 0.078061 0.0585811 #(-0.04486 0.0298865 0.0293551 0.0157202 0.00558635 -0.00166327 -0.0153884 -0.00699228 0.00676223 0.00247051 -0.00958823 -0.00736895 0.00134663 0.00697311 0.0112086 -0.000206178 -0.00881016 -0.00624388 -0.00932781 -0.0197023 -0.0190608 -0.011131 -0.0120463 0.000508607 0.00205883 0.0130596 0.00678453 0.017637 0.0173591 -0.00929612 -0.0146321 -0.00917131 -0.0076256 0.0010683 -0.00392937 -0.00849227 0.006057 0.0173038 0.0170559 0.0185356 0.0307804 0.0321241 0.0197208 -0.00024348 -0.0379323 -0.0627024 -0.0771216 -0.096205 -0.116027 1.29578)) (22.8884 0.0716601 0.055954 #(-0.0482403 0.0307585 0.0275873 0.0182651 0.000529184 -0.0022478 -0.00768153 -0.00720601 0.00320312 0.000542559 -0.00613952 -0.00509576 0.000853576 0.00746592 0.00241067 0.00149092 -0.0103518 -0.00548361 0.00260866 -0.00854271 -0.0165325 -0.024049 -0.0159926 -0.0106845 0.00539235 0.0217353 0.013189 0.0138549 0.0113874 -0.00669787 -0.0144154 -0.00952096 -0.00989752 0.000984178 -0.00567269 -0.0075391 0.00597343 0.0157336 0.0231019 0.0212661 0.0260539 0.0267702 0.0234177 -0.00360673 -0.0411499 -0.0479637 -0.0797028 -0.101779 -0.123467 1.30416)) (25.0679 0.0404904 0.04019 #(-0.0569264 0.0393012 0.0442286 0.0105388 -0.0280166 0.0130403 -0.000293758 0.00097423 0.0019422 -0.0135517 -0.0129558 -0.00137247 0.0176797 0.0111486 -0.00223964 -0.00550807 -0.00602055 -0.00683842 -0.0111893 0.0040559 -0.00320025 -0.0210676 -0.0166252 -0.0273107 -0.00925243 0.0352852 0.0153395 0.028238 0.0100151 -0.0296035 -0.0250562 0.00185137 0.0255143 0.00681541 -0.0269629 -0.0225865 0.00339151 0.0176583 0.0135256 0.0128693 0.0308694 0.0396139 0.0268478 -0.00453411 -0.0321182 -0.0411832 -0.0894552 -0.13549 -0.18868 1.40068)) (26.172 0.0414675 0.0398048 #(-0.0630411 0.0445934 0.0340673 0.0179641 -0.0126086 -0.000847251 0.000227371 0.00106207 0.0131494 -0.0118745 -0.0160848 -0.00908814 0.00502605 0.0118554 0.0134411 0.006348 -0.0203072 1.60219e-005 -0.0092216 -0.0131313 0.00614179 -0.023434 -0.0225044 -0.0205765 -0.00759216 0.0190882 0.0216325 0.0341826 0.0139076 -0.0241181 -0.0163891 -0.0082327 0.0124357 -0.00390939 -0.0224453 -0.0154005 0.00127452 0.0147405 0.0170827 0.0260113 0.0421892 0.0303767 0.0235349 -0.0138023 -0.0474366 -0.0434775 -0.0753137 -0.111706 -0.172436 1.36862)) (24.9425 0.0127896 0.0226443 #(-0.0733194 0.0354206 0.0577736 0.0308347 -0.0289842 -0.00604918 -0.014531 -0.0101977 0.0240066 0.0242339 -0.0217081 -0.0255996 0.00547605 0.0210583 0.0282309 -0.0144568 -0.0284572 -0.0338683 0.0165173 0.0371958 0.00744609 0.00585112 -0.0600074 -0.0549116 0.000340121 0.0385451 -0.00124994 0.0513382 0.0555081 -0.0592178 -0.0733577 -0.0170409 0.0586459 0.0553344 -0.0225186 -0.0556362 -0.0233135 0.0506938 -0.00436045 -0.0332437 0.00902178 0.0879455 0.0599741 -0.000640262 -0.0442607 -0.0220114 -0.0610923 -0.165358 -0.458725 1.64915)) (22.7641 0.0174743 0.027706 #(-0.0584102 0.0459445 0.031618 0.0172284 -0.0102017 -0.00307119 -0.0147159 -0.0128069 0.0192186 0.0263737 -0.0162587 -0.0214138 -0.00164627 0.0164729 0.0190751 -0.00745766 -0.0243652 -0.0185078 -0.0136905 0.043886 0.0129518 -0.0298972 -0.0265289 -0.0403765 -0.00958069 0.0232809 0.0161453 0.044125 0.0361099 -0.0522329 -0.0619475 -0.000899218 0.0508566 0.0368301 -0.0180012 -0.0430501 -0.00970191 0.00226846 0.0163143 0.00440859 0.00654716 0.0745107 0.0559268 -0.0237278 -0.0297872 -0.0202482 -0.0711893 -0.150335 -0.394529 1.58051)) (19.5777 0.0125371 0.0253057 #(-0.0826795 0.0683275 0.0428367 0.02936 -0.021953 -0.0169267 -0.0348315 -0.00679442 0.025703 0.045118 -0.00592805 -0.0419876 -0.00936561 0.0199536 0.035517 -0.0131276 -0.0408877 -0.0219309 0.0500002 -0.0214081 0.0310525 -0.0126166 -0.046124 -0.0345309 -0.027267 0.0407647 0.00779675 0.0551954 0.0525408 -0.0538993 -0.0680158 -0.0475148 0.0549138 0.0610506 0.00643009 -0.0500036 -0.0294172 0.0234389 0.0124404 -0.0212963 0.0223014 0.0563873 0.0415865 0.0218463 -0.0398211 0.00419091 -0.103894 -0.150699 -0.43171 1.62141)) (18.2418 0.0253117 0.0372501 #(-0.0607523 0.0562677 0.0384613 0.00424439 -0.0162383 -0.00801906 -0.00889723 -0.00153158 0.0178735 0.00687857 -0.00841403 -0.0109761 -0.000752748 0.0188549 0.0145737 -0.0116472 -0.0244779 -0.0102738 0.00684694 -0.00289441 -0.0144796 -0.0119951 -0.0216497 -0.0176858 0.000835 0.00693356 0.0142641 0.0338318 0.0169442 -0.0304174 -0.03766 -0.00345847 0.0310024 0.00119207 -0.0121249 -0.0113758 -0.00784907 0.0241519 0.0161341 0.0165755 0.0178807 0.0323894 0.0223039 0.0113459 -0.0211709 -0.0354951 -0.0753201 -0.130449 -0.212926 1.39061)) (18.2633 0.0252861 0.0372093 #(-0.045203 0.0314978 0.0349495 0.00211169 -0.00893727 0.00352343 -0.0123056 -0.00291805 0.0126091 0.00904179 -0.00646769 -0.0145041 -0.00502528 0.0120276 0.0164997 -0.0114284 -0.0165834 -0.00612101 0.0129625 0.0025109 -0.0220033 -0.00506117 -0.0341916 -0.0253116 0.0116913 0.0206707 0.00947406 0.0215501 0.018648 -0.0253815 -0.0210033 -0.00128285 0.00803003 0.00165846 -0.00961188 -0.0112029 -0.00390969 0.018762 0.0176612 0.0141336 0.0162613 0.0423988 0.0169786 0.00664183 -0.0149723 -0.0514017 -0.0758318 -0.125953 -0.214712 1.39864)) (17.5015 0.0281862 0.0401311 #(-0.0467037 0.0285618 0.0290192 0.00889659 0.00523947 -0.0106185 -0.00584188 0.00343646 0.0078645 0.00378798 -0.0136156 -0.012084 0.00284047 0.0112584 0.00930852 -0.0112164 -0.00383024 -0.00982824 0.0153711 -0.00475254 -0.018373 -0.0203009 -0.0232701 -0.0175478 0.00286289 0.0183034 0.0126237 0.036949 0.00550275 -0.0201175 -0.0171514 0.000764537 0.00264071 -0.0167697 -0.00575089 -0.00377642 -0.00121029 0.0205625 0.019458 0.00863159 0.025104 0.0386815 0.0262647 -0.00411803 -0.0406888 -0.0471502 -0.083648 -0.103756 -0.174039 1.36212)) (17.2526 0.0295366 0.0413764 #(-0.0459645 0.0347026 0.0174516 0.0140821 0.00442935 -0.00595253 0.000786888 -0.00770935 0.00586936 0.00240675 0.00201615 -0.0114029 -0.00715992 0.0219725 0.00668619 -0.00508303 -0.0104611 -0.00929612 -0.00120529 -0.00989537 -0.0169932 -0.0133932 -0.0188951 -0.000876892 -0.000297876 0.000200907 0.0129674 0.0262989 0.00787067 -0.0241803 -0.0115058 -0.000143185 0.0150916 0.0138443 -0.0335769 -0.0206819 -0.00174932 0.0245576 0.0198266 0.017498 0.020447 0.0325335 0.0246589 0.00835593 -0.033657 -0.0520807 -0.0742558 -0.105502 -0.158577 1.3385)) (17.7939 0.0194564 0.0330671 #(-0.0393023 0.0249954 0.0281254 0.00881808 -0.0170303 -0.000254086 -0.0238422 0.0104953 0.0267727 0.0218212 -0.00832039 -0.0378733 -0.00966003 0.0208957 0.0258569 0.00523595 -0.0125616 -0.0198685 -0.00261361 0.0267587 -0.00756953 -0.0295961 -0.0220904 -0.0216108 -0.022352 0.010996 0.018242 0.0477541 0.0378138 -0.0342758 -0.0460006 -0.0110206 0.0200271 0.0216202 -0.0010694 -0.0481358 -0.00989713 0.0183853 0.0178495 0.0123016 0.00932306 0.0462944 0.0355045 0.00738312 -0.0433972 -0.0431022 -0.0752448 -0.111662 -0.22808 1.41783)) (16.2645 0.0198753 0.0349571 #(-0.0444276 0.0359794 0.0176339 0.0166024 -0.00509977 -0.00228653 -0.0161215 0.0145134 0.0174299 0.000749843 -0.00504707 -0.026946 -0.00241593 0.0172678 0.024325 -0.00596551 -0.0248575 -0.0135324 0.0111395 0.00225044 -0.0129778 -0.0134113 -0.0270257 -0.0234719 -0.000202711 0.0218519 0.00693315 0.0315688 0.0147574 -0.0374582 -0.0197909 -0.0087806 0.0357156 0.00379843 -0.0129535 -0.0288524 -0.0066429 0.02112 0.00394448 0.0222445 0.0191879 0.0458149 0.0290641 0.00188522 -0.0291704 -0.0394177 -0.0755161 -0.123621 -0.231673 1.41693)) (13.9843 0.0203448 0.0381422 #(-0.0406508 0.0247845 0.0280528 0.016247 -0.00667394 0.00575473 -0.00883099 -0.00538796 0.0124414 0.00246849 -0.0144231 -0.0122821 5.65498e-006 0.0240839 0.00861459 -0.00217033 -0.0235125 -0.0168742 0.0055966 -0.00328378 -0.00988276 -0.0124962 -0.0202922 -0.0046567 0.00286656 0.0025336 0.000137633 0.0296567 0.0200221 -0.0189908 -0.0237597 -0.000666055 0.0173422 0.0148898 -0.028545 -0.0280338 -0.00862389 0.0107104 0.0292579 0.0223673 0.0356336 0.027171 0.0365469 -0.00876548 -0.0413912 -0.0440555 -0.0862704 -0.0992445 -0.175119 1.36053)) (13.7519 0.0318418 0.0481192 #(-0.0439203 0.0286811 0.019099 0.0131209 0.00116507 0.00239283 -0.00349781 -0.00764389 0.00731754 0.00111961 -0.0119648 -0.0166307 0.0112826 0.0209392 0.00437699 0.00510248 -0.00768695 -0.0223086 -0.0103192 -0.00707175 -0.0131623 -0.0187769 0.00250121 -0.00532104 -0.0114664 0.00451569 0.0158921 0.0267952 0.00829616 -0.0112708 -0.0156018 -0.00644018 0.00364066 -0.00682353 -0.0102232 -0.0152849 -0.00104906 0.0131723 0.0312335 0.0306407 0.0224566 0.0393104 0.00734389 -0.0167909 -0.0521184 -0.0325935 -0.0547162 -0.0785076 -0.107318 1.25643)) (14.1001 0.036371 0.0507887 #(-0.0416909 0.0311513 0.0216856 0.010757 0.0023053 -0.00539498 -0.0122303 -0.00307753 0.0143497 -0.0013006 -0.00140553 -0.0114054 0.00277976 0.0180154 0.00290372 -0.000693336 -0.0231679 -0.00686742 -0.00978564 -0.00577415 -0.00821437 -0.0128852 -0.00872088 -0.0119665 0.00729519 0.00605096 0.00574081 0.0229577 0.00811213 -0.0167 -0.00908976 0.00335362 -0.00364028 -0.00150706 -0.00937789 -0.0185555 -0.000902989 0.0273121 0.0204276 0.0180267 0.0271863 0.0347298 0.0131781 -0.0189297 -0.042958 -0.0488664 -0.0552135 -0.0687342 -0.0978135 1.24792)) (14.2751 0.0340747 0.048857 #(-0.0375261 0.024581 0.0173357 0.0105803 0.00152478 5.81223e-005 -0.0049663 0.000233414 -0.0059578 0.0172982 -0.0123975 -0.0121001 0.00817213 0.00614464 0.0063125 0.00277281 -0.0072908 -0.00298882 -0.00532286 -0.0151193 -0.0130224 -0.0190079 -0.00477871 -0.00682809 -0.00484661 0.0136435 0.0106479 0.0201277 0.016766 -0.0148155 -0.0230016 0.0010569 0.00368719 -0.00836747 -0.0108471 -0.0115598 -0.000523546 0.020508 0.0238148 0.0105346 0.0278912 0.030346 0.015747 -0.00584426 -0.0429999 -0.0557868 -0.0671162 -0.0745447 -0.115248 1.28424)) (15.2833 0.022009 0.0379483 #(-0.0444502 0.0319226 0.0206898 0.00408402 0.0038444 0.00518289 -0.0102187 0.00644884 0.0154201 0.00243678 -0.0155881 -0.0226183 -0.00535144 0.0143481 0.0263679 -0.00816404 -0.00439294 -0.00726711 0.00245852 -0.0075432 -0.0210695 -0.022927 -0.0121272 -0.00257655 -0.0142863 0.0116892 0.0195945 0.0314798 0.0171628 -0.026222 -0.0236029 -0.00279915 0.0139127 -0.00411994 -0.0220793 -0.0223499 0.0130053 0.0163297 0.014851 0.0168635 0.030113 0.0393203 0.0185481 -0.0032677 -0.0508295 -0.049786 -0.0681459 -0.100596 -0.141854 1.3324)) (16.2369 0.0167683 0.0321361 #(-0.0461453 0.0336128 0.0171639 0.00638196 0.00304988 0.00700732 -0.0124934 -0.0014443 0.0229149 0.00812651 -0.0156464 -0.027978 0.00155632 0.0148617 0.0236262 -0.0053183 -0.0306435 0.0156539 0.00576177 -0.00936416 -0.019092 -0.0214782 -0.0106117 -0.0139679 -0.00487678 0.0153928 -0.000839796 0.0328364 0.0370444 -0.0267438 -0.0258321 -0.0084227 0.00140206 0.0170352 -0.0249207 -0.0137748 0.00622318 0.00877071 0.0176743 0.0140944 0.0160371 0.0299227 0.0280204 0.00486572 -0.0471303 -0.0549004 -0.0792787 -0.0862093 -0.156202 1.34944)) (15.8715 0.00862119 0.0233064 #(-0.0416665 0.0196847 0.0351245 0.00540738 0.000268711 0.000455022 -0.00585776 -0.00906765 0.019069 0.0231938 -0.0242396 -0.0320143 0.00375507 0.0115636 0.0160781 -0.00497688 0.0104297 -0.0136434 0.0112971 0.000516813 -0.0335269 -0.00981996 -0.0165414 -0.0128344 -0.00386654 0.0142686 -0.0124378 0.0254652 0.0577827 -0.0404511 -0.0399016 0.00257038 0.0284287 0.00205934 -0.00698707 -0.0282862 -0.0129552 0.0375839 -0.00052652 -0.00139833 0.010455 0.0601005 0.027725 0.00917528 -0.0452916 -0.0495308 -0.114218 -0.0824053 -0.228428 1.43507)) (14.8358 0.0137405 0.030433 #(-0.035238 0.0325776 0.00811017 0.00564153 0.00956963 0.00160376 -0.00735718 -0.0106363 0.00927161 0.0156551 -0.014077 -0.0256614 0.00892661 0.0141185 0.0219964 0.00497017 -0.0213388 -0.00393183 0.00307147 -0.00527207 -0.00932004 -0.0149748 -0.0293915 -0.0137217 0.0110029 0.00820573 -0.00731358 0.0228706 0.0342061 -0.0270083 -0.0231551 -0.00456665 0.0112681 -0.00073322 -0.00608638 -0.0299522 0.00616215 0.0218085 0.0147894 0.01267 0.0171617 0.0382049 0.0155666 0.00222878 -0.0301421 -0.0626113 -0.101723 -0.0618076 -0.14028 1.33014)) (12.9037 0.0170322 0.0363311 #(-0.0361427 0.0205666 0.0172627 0.017552 -0.00678439 0.00380304 -0.00573859 0.00913126 0.0155822 -0.00543546 -0.00759378 -0.0190302 -0.00357661 0.0192382 0.00804061 0.000652122 0.000361389 -0.0179953 -0.00446666 0.00560995 -0.0184849 -0.0113776 -0.0232038 -0.00865374 -0.000620224 0.00406897 0.00305195 0.0334702 0.0202773 -0.0270967 -0.0247178 0.00910172 -0.000104248 0.000138012 -0.0102208 -0.0169238 0.00120545 0.0203969 0.0133169 0.0181668 0.0202681 0.0266863 0.021128 -0.0131285 -0.0365628 -0.0378504 -0.0756192 -0.0782206 -0.137483 1.31255)) (10.7606 0.0176641 0.0405161 #(-0.0483414 0.0247989 0.0315676 0.00585319 -0.00234617 0.009571 0.00527321 -0.010687 0.0163059 0.00885164 -0.0125577 -0.0134762 -0.00967633 0.0164184 0.00952228 -0.00630756 -0.0123339 0.00271924 -0.00671046 -0.0020015 -0.00886391 -0.0281787 -0.0135787 -0.0134191 0.00144693 0.00931767 0.000242524 0.0183011 0.0329657 -0.0164957 -0.0380229 0.00540505 0.0215291 -0.00189809 -0.0201857 -0.0100815 0.00201447 0.0118938 0.00726428 0.0202927 0.0107608 0.0392477 0.0177106 -0.00825438 -0.0278289 -0.0360925 -0.0803767 -0.0690058 -0.118693 1.27992)) (9.692 0.0163592 0.0410842 #(-0.0435487 0.0238735 0.0221766 0.0130095 -0.0102838 0.0102648 -0.00263138 0.00405493 0.0139175 0.00368894 -0.0144828 -0.0187693 0.000191167 0.0191079 0.0188621 -0.00391941 -0.0163057 -0.0108496 0.0112138 -0.0054916 -0.0242603 -0.0107545 -0.03524 -0.00986785 0.00436468 0.0159444 0.00288566 0.0280451 0.0177601 -0.0226378 -0.0232638 -0.00458616 0.0132367 -0.00669003 -0.00879428 -0.0174804 -0.00444567 0.0183938 0.0174463 0.0192643 0.0206223 0.0364433 0.00547454 0.00493223 -0.0256411 -0.0374557 -0.0770796 -0.0699102 -0.107736 1.2591)) (10.6083 0.0116637 0.0331585 #(-0.0339536 0.0239064 0.0193139 -0.00206308 -0.00420809 0.0162964 -0.00446401 -0.00723342 0.032238 0.00872946 -0.0187994 -0.0242643 -0.0134408 0.0259891 0.0161434 0.00132369 -0.0197008 -0.00519451 0.00655926 -0.00738285 -0.0172127 -0.0237242 -0.0212511 -0.0206254 0.0103538 0.0122223 -0.00456432 0.0447003 0.0352811 -0.0406705 -0.0316736 0.00797188 0.00656864 -0.0115901 -0.0027629 -0.0128048 -0.00570429 0.0118761 0.0188073 0.0222462 0.0124456 0.0410702 0.00791332 -0.00379496 -0.0170523 -0.0476136 -0.0781826 -0.0542285 -0.143112 1.28919)) (13.6333 0.00775797 0.0238547 #(-0.0364152 0.0291058 0.0227928 0.00502204 -0.0253292 0.048831 -0.0291211 -0.014896 0.0320535 0.00774532 0.000503408 -0.0316866 -0.00546139 0.0360913 0.00840064 -0.0208066 -0.0145649 0.000116066 0.00307052 -0.0122648 -0.0118387 -0.0277435 -0.0112472 -0.0110968 0.0148855 -0.00123177 -0.021587 0.0284518 0.0631961 -0.0358807 -0.0443364 0.00976814 0.00940558 0.00815862 -0.0182798 -0.0167586 0.0109045 0.0136983 0.0074112 0.00384714 0.0165089 0.0481128 0.0182451 0.00169633 -0.0279793 -0.0379538 -0.093019 -0.0760834 -0.15798 1.33196)) (14.9529 0.0090799 0.0246421 #(-0.0173912 0.0117589 0.0215592 -0.000100125 -0.00958332 0.0178238 -0.0220747 0.00944662 0.0241577 0.0100921 -0.0118245 -0.0308733 -0.0111011 0.0260419 0.0364623 -0.0174218 -0.0250652 -0.02109 0.0203074 0.00684312 -0.0399599 -0.0207732 -0.0171705 -0.0007063 0.00839398 0.0148383 -0.0116208 0.0395184 0.0320917 -0.0477367 -0.0288544 -0.013006 0.0343035 0.0151606 -0.0250012 -0.0238014 0.010687 0.0287551 0.00443121 -0.00885899 0.0187292 0.0305535 0.0398672 0.0256628 -0.0622547 -0.0391768 -0.0803045 -0.063373 -0.174028 1.33167)) (15.4713 0.0103036 0.0258065 #(-0.0317778 0.0220012 0.023046 0.0107401 -0.00700271 0.0157947 -0.0168062 -0.0275037 0.0367403 0.0183112 -0.0155777 -0.0184876 0.00537082 0.00657688 0.00920857 -0.00738122 -0.0258576 -0.00495231 0.0158989 0.0138713 -0.0316929 -0.0372503 -0.00456503 0.00398878 -8.80907e-005 0.00931697 -0.0254795 0.0441872 0.0447222 -0.0413425 -0.0365677 -0.00544457 0.0244433 0.0112955 -0.0182531 -0.0124006 0.00266321 0.0168735 0.014526 -0.0109792 0.0141278 0.0440501 0.000770168 0.0424379 -0.0278247 -0.0526684 -0.0777227 -0.0873046 -0.175866 1.34552)) (14.1187 0.00916422 0.0254771 #(-0.045858 0.0400202 0.0205128 0.00743514 -0.00145771 0.00837235 -0.0248272 -0.00172827 0.0233621 0.0100241 -0.0135858 -0.0126684 -0.00336266 0.0149539 0.0171219 -0.016675 -0.0227132 -0.000102549 0.020379 0.00582718 -0.016864 -0.0320013 -0.0340711 0.00940389 -0.00660789 0.0171697 -0.029894 0.0563412 0.0606243 -0.07549 -0.0483998 -0.000330146 0.0359239 0.0257492 -0.00142432 -0.0289091 -0.0018749 0.012466 0.00260386 -0.0152575 0.00862908 0.053457 0.03697 0.0345913 -0.0435553 -0.039316 -0.0996627 -0.0778146 -0.205904 1.3743)) (12.5142 0.0109789 0.0296196 #(-0.0372881 0.0196089 0.0233113 0.000903561 -0.0047855 0.0192033 -0.00402685 -0.00304796 0.0072131 0.000961789 -0.00506267 -0.0118756 0.00342084 0.015397 0.00417627 0.00558174 -0.014547 -0.00178372 -0.00917506 0.0153024 -0.021183 -0.0321192 -0.0190146 -0.0116695 0.0083767 0.00252157 0.0031781 0.03148 0.0255226 -0.0305256 -0.0148153 0.00160903 0.010152 0.00196973 -0.0133266 -0.0138634 -0.0111339 0.0246016 0.00657759 0.0046415 0.0102237 0.0405588 0.0267124 -0.0205946 -0.0262742 -0.0302408 -0.0733365 -0.0751875 -0.141942 1.30887)) (13.1881 0.0149057 0.033619 #(-0.0392646 0.0235916 0.0113109 0.0165674 0.000356377 0.0096727 -0.00454504 -0.0118521 0.0189847 5.30982e-006 -0.00576891 -0.00829558 -0.00267612 0.0116296 0.0180062 -0.00463104 -0.015852 -0.0119515 0.00220159 0.00224108 -0.027798 -0.0126524 -0.0149994 -0.00157439 -0.00384594 0.00016854 0.00338744 0.0262442 0.0138858 -0.0262235 -0.0060537 -0.000456936 0.0188089 0.00153812 -0.0108762 -0.0196819 -0.00571758 0.0244648 0.0111209 0.00558558 0.0127132 0.0348169 0.015571 -0.0175171 -0.0217261 -0.045869 -0.0708379 -0.0505154 -0.114525 1.26721)) (12.7999 0.015072 0.0343149 #(-0.0333835 0.0122214 0.0259325 -0.000845576 -0.00411607 0.0249855 -0.00362802 -0.00123161 0.00374519 0.00881159 -0.00779002 -0.0221836 -0.00150112 0.0259934 0.00794084 -0.00206094 -0.0134564 -0.00876726 -0.00201227 -0.0224425 0.00930002 -0.0259136 -0.0165928 -0.00342897 -0.00262414 0.00704048 -0.00242533 0.0235934 0.0114056 -0.0151016 -0.0109616 0.00159531 0.0111167 -0.000793585 -0.00855475 -0.0193289 0.00818316 0.0173823 0.00418687 0.0104691 0.0231481 0.0104235 0.0158543 -0.00351913 -0.0424822 -0.0357488 -0.0522538 -0.0381995 -0.0936292 1.22602)) (12.2473 0.0193377 0.0397359 #(-0.0208312 0.0113622 0.0107963 0.0102407 -0.0113957 0.00688707 0.00914879 -0.00983215 0.00520417 0.00334524 -0.0068846 -0.004754 -0.00291994 0.0137996 0.0146112 -0.00155131 -0.0176285 0.00365784 -0.0104858 -0.0192718 -0.000923549 -0.0131308 -0.0111267 -0.00719019 0.000579761 0.0111471 -0.00676168 0.0234209 0.0115352 -0.0168934 0.0025673 -0.00926516 0.00685466 -0.00665536 -0.00981694 0.000390394 0.00485606 0.00488992 0.00723448 0.0167406 0.00949511 0.00968203 0.0148381 -0.0192989 -0.0238238 -0.0274632 -0.0505583 -0.0318813 -0.0690697 1.18902)) (12.5963 0.016594 0.0362957 #(-0.022897 0.0164408 0.00922307 0.00712825 0.00029965 0.0126678 -0.00781488 -0.00903336 0.00276701 0.00841422 -0.00438664 -0.00758085 0.00516114 0.00530365 0.00871018 -0.00177273 -0.00100205 -0.00497492 -0.00829477 -0.00643409 -0.0175788 -0.016037 -0.0116676 -0.00203718 -0.000523905 0.0101769 -0.00147634 0.0081845 0.0146411 -0.0119274 -0.00436797 -0.000224399 -0.00513704 -0.00984378 0.0115129 -0.0102507 0.00516442 0.00549147 0.00572397 0.0118901 0.0113157 0.0218897 0.00945389 -0.0113134 -0.0298536 -0.0302538 -0.053088 -0.0372686 -0.0642578 1.19366)) (13.5525 0.01008 0.0272723 #(-0.0123657 0.0053427 0.019458 -0.0176663 -0.0176549 0.0404966 -0.00390325 -0.00579765 0.00887555 0.00317001 0.00172718 -0.00829583 0.010417 0.0153962 -0.00556122 -0.00680748 -0.00745445 -0.00852993 -0.00462103 -0.0159715 -0.000628177 -0.0183191 -0.0147015 -0.00193298 -0.00415885 0.0236506 -0.0098982 0.015603 0.0132994 -0.0134173 -0.00543716 0.00140853 -0.000410987 -0.0155814 -0.00399504 -0.000352762 -0.00284362 0.0100352 0.0139833 0.0156556 0.00280102 0.00782334 -5.04827e-005 -0.0182239 -0.0189623 -0.0239327 -0.0540221 -0.0168124 -0.0578101 1.18215)) (12.068 0.00596845 0.0222389 #(-0.00770466 -0.00247063 0.020446 -0.00341433 -0.0175267 0.0299728 -0.00334073 -0.021708 0.0222189 0.00349176 -0.00219307 0.000507939 -0.000906229 0.0251413 -0.00347692 -0.0193672 -0.008356 0.0107288 -0.00522202 -0.0373399 0.0110019 0.00334983 -0.0260176 -0.00508717 0.0076833 0.0123874 -0.0218113 0.0217126 0.0137616 -0.0343426 0.00107652 -0.0108971 0.00723602 -0.0140256 0.00945629 0.008111 -0.013161 0.0263409 0.00322294 0.0169951 0.0125402 0.00634017 -0.0281478 0.00833678 -0.0210252 -0.0480639 -0.0657505 0.00962592 -0.0670183 1.193)) (8.95623 0.00286173 0.0178752 #(-0.0299596 -0.00271054 0.0316405 0.00830122 -0.0430843 0.052154 0.00778072 -0.0218403 0.015222 0.00900955 0.000450335 -0.0294424 0.0109118 0.0305165 0.0185617 -0.0211344 -0.00754338 0.000348268 -0.015125 0.000259483 -0.00953378 0.00744751 -0.0392438 -0.0133562 -0.0140394 0.0473366 -0.0574915 0.0274957 0.0739216 -0.0633229 -0.00625577 -0.00332914 0.0318236 -0.039495 -0.0259531 0.0239393 -0.0180297 0.0156937 0.0245471 0.0241233 0.00445331 0.0143366 -0.0112595 0.0136985 -0.0568217 -0.0400073 -0.106216 0.040655 -0.0915969 1.22924)) (6.49921 0.00445611 0.0261847 #(-0.0170517 -0.0101715 0.0184278 0.00588615 -0.0192503 0.0377397 -0.00414877 -0.0237132 0.0261238 0.0049736 -0.00638682 0.00527185 -0.00923617 0.0111306 0.0255296 -0.0039067 -0.0151077 0.00377979 7.06266e-005 -0.0208127 0.00467839 -0.022734 -0.0168833 -0.00336075 -0.01055 0.033853 -0.0379811 0.010155 0.0492233 -0.0412482 -0.00933746 -0.0204949 0.0208357 0.00125835 -0.0115378 -0.000968487 0.00445165 0.00835097 0.00622662 0.0115168 0.000545416 0.00342692 -0.00927968 0.0260598 -0.0528268 -0.0332704 -0.0524391 0.0325668 -0.0789734 1.17526)) (5.25729 0.00395311 0.0274213 #(-0.0240403 0.0205123 0.0153895 -0.0123595 -0.0220413 0.0554869 -0.00704868 -0.0433425 0.0501927 -0.00331648 -0.0181042 -0.0055328 -0.0079657 0.0218988 0.0184512 0.000216515 -0.0131423 -0.00679136 0.0172376 -0.0200239 0.00385909 -0.0187232 -0.0339574 -0.0205053 0.00639417 0.0217717 -0.022982 0.0227078 0.0735146 -0.0648862 -0.0373938 0.00153798 0.00527095 0.0142592 -0.0107342 -0.0298141 0.00548001 0.0163492 -0.00212356 0.00278833 0.0101466 0.0397622 0.0149 0.023642 -0.01529 -0.0428728 -0.0909119 0.00412615 -0.130688 1.23334)) (4.64889 0.00405787 0.0295443 #(-0.0083154 0.00615811 0.0229795 -0.0118895 -0.011159 0.0234972 -0.00391371 -0.0106054 0.0152195 0.0045161 -0.0309345 -0.0133451 0.0142733 0.0022754 0.0224104 0.00053866 -0.0105869 0.014126 -0.00594441 -0.016928 0.000217074 -0.00374499 -0.0370543 -0.0101543 -0.0131152 0.0467066 -0.0290259 0.0361985 0.048131 -0.0712857 -0.010248 0.0200725 -0.00527912 -0.033853 0.00625684 -0.0132771 -0.00059062 0.00807303 0.0207666 -0.005388 0.00403096 0.0390784 0.0263475 0.00420176 -0.0247701 -0.0169901 -0.0981137 0.00202813 -0.122794 1.22287)) (4.2687 0.00527028 0.0351374 #(0.0119431 0.000370011 0.00297805 -0.0086345 -0.00619318 0.0209268 -0.0214211 -0.00264095 0.000795118 0.0018904 0.00504403 -0.00221174 0.000734628 0.0115394 0.00269348 0.00862158 -0.0112626 0.0128954 -0.0100209 -0.0261409 -0.00341844 -0.00612675 -0.023003 0.0109423 -0.00282099 0.0203828 -0.0265252 0.0270202 0.0322998 -0.0362086 -0.00119129 -0.0153138 -0.00350063 0.00240223 -0.0210972 -0.00135233 -0.00711855 0.000712969 0.0123906 -0.00078104 0.000209776 0.0312843 -0.00727613 0.0274143 -0.0141633 -0.0350039 -0.0442454 0.0167168 -0.0482093 1.11671)) (5.08667 0.00434494 0.0292264 #(-0.00272251 0.00941567 0.00822995 -0.014127 -0.00472909 0.0256388 -0.0205545 -0.00637778 -0.0112651 0.0378657 -0.0158337 -0.00984417 0.00216444 0.030978 -0.00207667 -0.00625094 -0.00241573 0.000887676 -0.0113091 -0.0167408 -0.00726853 -0.00532588 -0.0106122 0.000375745 -0.00057362 0.0254724 -0.018358 0.0306097 0.0326059 -0.0225176 -0.0471872 0.00568396 -0.0101327 -0.0167238 -0.0112461 -0.0017848 -0.00424018 0.0120333 0.0037898 0.0135469 0.0227388 0.0193921 -0.0318962 0.0246949 -0.0262602 -0.0227707 -0.0672516 0.0572928 -0.0571018 1.11738)) (5.64243 0.00660276 0.0342082 #(0.00180166 0.00187813 0.00574493 -0.000219231 -0.0214208 0.0292124 -0.0171232 -0.0116133 0.0143524 -0.0080191 0.00040181 -0.000264368 0.00500117 0.0156718 0.00494422 0.00107104 -0.0174182 0.00156305 -0.00116767 -0.0143132 -0.00873124 0.00879861 -0.0235025 -0.00555377 0.0159542 0.0120798 -0.00968709 0.0101018 0.0241207 -0.0283285 -0.00464771 0.00488285 -0.0317064 0.000691314 -0.0122031 -0.0076785 0.00264264 0.00947001 0.0122303 0.00967777 0.0183964 0.00361356 -0.0121287 0.0116267 -0.0186891 -0.0143781 -0.0485434 0.0242676 -0.0335089 1.09521)) (4.34906 0.00506972 0.0341424 #(0.0023974 -0.00279862 0.0120042 -0.00157989 -0.0157521 0.0239786 -0.0126398 -0.0135926 -0.0020871 0.00151955 -0.00174203 -0.00773394 0.0159697 0.00780768 0.021657 0.00663021 -0.0142795 0.00149963 -0.00494957 -0.00158777 -0.0254905 -0.0117564 -0.017529 -0.00628616 0.00849666 0.00422017 -0.0116558 0.0310608 0.0345892 -0.0316539 -0.0132967 -0.00584913 0.00354922 -0.0173338 -0.0110622 -0.0096414 0.00859083 -0.0039589 0.0226801 0.0154026 0.00896204 0.0230092 0.00481482 0.00292927 -0.0234833 -0.0254714 -0.0981472 0.0441442 -0.0688532 1.14897)) (2.61565 0.00474862 0.0426083 #(0.00879548 -0.00707132 0.0105265 0.00589761 -0.0181165 0.0122799 0.000610275 -0.0196829 -0.011157 0.0120507 -0.0115164 -0.0105635 0.0167566 0.0110644 0.0208706 0.00165262 0.00444448 -0.00889109 -0.00448973 -0.00204069 -0.0176097 -0.0204983 -0.00444134 -0.0102928 -0.000729621 0.00828533 -0.0156112 0.0249824 0.046813 -0.034427 -0.0110774 -0.0109798 -0.00690826 -0.00195731 -0.0157386 -0.00195138 0.00642795 -0.00283065 0.0119922 0.0211103 0.0124749 0.0247881 0.0132657 -0.00455936 -0.0371286 -0.0106291 -0.0739445 0.0263266 -0.0843839 1.15059)) (2.02703 0.00255318 0.0354904 #(0.0134249 -0.00506588 0.00680395 0.0105582 -0.0323818 0.0493337 -0.0217674 -0.0241798 0.00928927 -0.023553 0.0104105 -0.0160771 0.00235487 0.00839372 0.0312377 0.00805041 0.000414273 -0.0136668 -0.0141831 0.0145558 -0.01835 -0.0176581 0.00780919 -0.0178566 -0.00798348 0.0228851 -0.0520132 0.0414188 0.066511 -0.0612651 0.00654983 -0.0331677 0.0129804 -0.0240143 0.0167766 -0.000209965 -0.0232557 0.0166038 0.0163538 0.0123617 -0.00410349 0.0241719 -0.00992855 0.0157116 -0.0186285 -0.0253129 -0.0767908 0.0521641 -0.0693304 1.12793)) (2.64432 0.00171959 0.0255009 #(-0.0191815 0.0127539 0.0107323 0.00105373 -0.0253985 0.0548691 -0.00350344 -0.0407332 0.00805417 -0.00516293 0.0269923 -0.0481122 0.045745 -0.00949443 0.029402 0.00253762 -0.0224486 0.00621702 -0.0126075 -0.000360755 -0.0107886 -0.00802914 -0.0263488 -0.00418882 0.00777657 0.0122917 -0.0655835 0.0318259 0.0745041 -0.046913 -0.0178272 -0.014913 0.00287156 -0.0266232 0.016267 0.00797917 0.00580041 0.0114133 0.00738462 0.0441676 -0.0136994 0.0335519 -0.0324743 0.0188773 -0.0348701 -0.0234333 -0.174669 0.177908 -0.0964444 1.12857)) (3.49525 0.0028907 0.0287582 #(-0.022997 0.00390569 0.0195987 -0.00368246 -0.0249804 0.0205793 -0.000749982 -0.0146779 0.0253093 -0.027436 -0.00506964 0.0229678 0.0122114 -0.00660955 0.0289347 0.00446956 -0.0240813 0.0124458 -0.000533498 -0.0357979 -0.00426894 0.00482643 -0.0216519 0.00376066 -0.0166858 0.0254196 -0.047756 0.0296842 0.05304 -0.053725 0.0233847 -0.00627376 -0.0327575 0.0242391 -0.00986949 0.0018908 0.0199183 -0.001377 0.00140167 0.0246927 0.00391399 0.00494078 -0.0242442 0.0174991 -0.0272264 -0.0343578 -0.0611368 0.0862893 -0.0566336 1.08269)) (3.59173 0.00241115 0.0259096 #(-0.0280463 0.00239539 0.0275002 -0.0139323 -0.0348279 0.0607939 -0.0263654 -0.0111383 0.00125177 0.0134574 -0.0201514 0.0256755 0.0152298 -0.0129894 0.040595 -0.0242227 0.0223003 -0.0198948 -0.00945686 -0.0104881 -0.0149074 0.000106048 -0.0155021 0.00164234 -0.0275243 0.0334275 -0.0597113 0.0490029 0.0458835 -0.0406038 -0.00296535 0.00162114 0.00027736 -0.0194494 0.0124248 -0.00222679 0.0104655 -0.00167292 0.00815926 0.0283748 -0.0225562 0.0143205 -0.0188394 0.00579293 -0.0147764 -0.0167599 -0.050156 0.0847534 -0.0659405 1.07315)) (2.26719 0.00255288 0.0335561 #(-0.0136514 -0.00925972 0.0167188 -0.00485284 -0.0336646 0.0412232 -0.000246899 -0.0298077 0.00712888 0.0134616 0.0103107 -0.00485241 -0.00127703 0.0164119 0.0132654 -0.019095 0.00456902 -0.00259853 -0.000275873 -0.0127027 -0.00593184 0.0101047 -0.0413224 0.018843 -0.0107773 0.0150738 -0.0289957 0.0254439 0.0380609 -0.0406301 -0.00392326 0.0172783 -0.00857435 -0.0223009 0.00749708 -0.0165367 0.0238457 0.018136 -0.00458933 0.00245699 0.00172918 0.00670983 -0.024566 0.00660529 -0.0205404 0.00950086 -0.0578217 0.0939725 -0.0510117 1.04425)) (0.609353 0.00163717 0.0518337 #(0.00316256 -0.0122567 0.00518264 0.0126123 -0.0397706 0.0392831 0.0116002 -0.0471934 0.00805918 -0.00560564 0.000558784 -0.00409364 -0.00452707 -0.00113856 0.0257756 -0.00932488 0.00381936 -0.00247659 0.00301922 0.00335715 -0.00619763 0.0345422 -0.0321831 0.00519092 -0.00104381 -0.021393 -0.028818 0.0308446 0.0615516 -0.0569711 -0.0213437 0.00541473 0.00891156 -0.00345845 -0.00526036 -0.0140875 0.0217332 0.0150425 0.00302012 0.000750344 -0.0227373 0.0355403 -0.0606219 0.0543924 -0.0197096 0.0106198 -0.0761164 0.133679 -0.0540805 1.00403)) (0.116473 0.000738204 0.0796116 #(-0.0020667 -0.00708028 0.00649903 0.00525495 -0.0577545 0.0708488 0.0241519 -0.0957537 0.0444855 0.00816514 -0.0260424 -0.00887706 0.0161092 -0.00643925 0.0365329 -0.0114855 -0.0214506 0.00323551 4.06337e-005 0.00984418 0.00579543 0.0340158 -0.0244511 -0.00303321 -0.0329481 0.0117391 -0.0672089 0.0657941 0.120411 -0.0823802 -0.0449917 0.00125354 0.00608117 -0.0209081 -0.0254859 0.0413741 -0.00546445 0.0228035 -0.0102555 0.0282721 -0.0411615 0.0264412 -0.0625765 0.0651369 -0.0960416 0.0914793 -0.12826 0.244372 -0.0968032 0.978677)) (0.0472545 0.000482073 0.101003 #(-0.0132409 -0.00177229 -0.00651967 0.0181785 -0.057867 0.0886454 -0.0060562 -0.0415304 -0.00604645 0.00809692 -0.0261498 0.0308232 -0.0207518 0.039377 0.0286866 -0.00414628 -0.101779 0.0925687 -0.0566329 0.0285281 -0.0124488 0.0429751 -0.0231868 0.00492606 -0.0382182 0.0353667 -0.0854897 0.072105 0.138783 -0.152908 0.0118608 -0.0236536 0.0280545 -0.0358662 -0.00158007 0.0410328 -0.0307116 0.0351427 -0.0487812 0.0650863 -0.105127 0.0931477 -0.118991 0.157664 -0.204664 0.186411 -0.180145 0.351459 -0.130844 0.92427)) (0.0200657 0.000490229 0.156305 #(-0.0167117 0.0226238 -0.0290179 0.0310399 -0.05596 0.0754746 -0.00102182 -0.0240663 -0.00557826 -0.00226293 0.00760277 0.00121096 -0.0371931 0.0368175 0.00439128 -0.00121828 -0.0701961 0.0851828 -0.0429475 0.0221135 -0.0202851 0.0294757 0.0173632 -0.014941 0.0101552 -0.0156045 -0.0714142 0.0373879 0.140392 -0.155288 0.0474913 -0.015392 0.010226 -0.0506144 0.00775825 0.0425248 -0.0111819 0.0198418 -0.0465491 0.0473969 -0.0958641 0.069069 -0.0800155 0.135248 -0.167486 0.159519 -0.163318 0.341011 -0.122999 0.899713)) (0.0189561 0.000463645 0.156394 #(0.0136824 -0.010146 -0.00340101 0.00501791 -0.052312 0.0825702 -0.0198587 -0.00941267 0.00742931 -0.00822124 -0.00559287 0.0070671 -0.0295775 0.0163785 -0.000200317 -0.0124918 -0.0388802 0.0517694 -0.0148913 -0.0019372 0.0130002 0.0529274 -0.051331 0.0468511 -0.0493757 0.0488883 -0.0877978 0.0390208 0.120372 -0.130924 0.00454228 0.0284801 -0.0370236 -0.0207961 0.00413483 0.0556726 -0.0461664 0.043992 -0.0572133 0.0680651 -0.129146 0.0933036 -0.0903923 0.0963898 -0.115223 0.173486 -0.16108 0.327376 -0.109485 0.877362)) (0.0157623 0.000457797 0.170422 #(0.00679172 0.0179331 -0.0180012 0.00985177 -0.0710897 0.0804711 -0.0138887 -0.00160079 -0.0130131 -0.0116605 -0.00195402 0.0102408 0.00544203 -0.00882841 -0.00664669 -0.000185585 -0.0333044 0.0571107 -0.0324269 0.00482369 0.00173713 0.0817342 -0.0689869 0.0314419 -0.0416472 0.0452527 -0.104628 0.0733021 0.109757 -0.112525 -0.040671 0.0457447 -0.033124 0.0189072 -0.0182032 0.0382207 -0.0430175 0.0633007 -0.0880582 0.0891837 -0.145313 0.126151 -0.130188 0.133809 -0.156576 0.210072 -0.192572 0.343954 -0.102867 0.867452)) (0.0193939 0.000457706 0.153625 #(-0.00460792 0.0355563 -0.0550596 0.043009 -0.0897849 0.0978742 -0.0187992 0.00582897 -0.0109002 0.000631806 -0.0163601 0.0133513 -0.0165699 0.0221935 -0.0312557 0.04581 -0.0629084 0.0434437 -0.0167021 0.0323193 -0.0250667 0.0627469 -0.0306966 -0.00490861 -0.0368386 0.0217197 -0.0728413 0.0668549 0.145474 -0.169416 0.0122649 0.00448438 0.013949 -0.0353851 0.020688 0.00875267 -0.0340474 0.0569403 -0.0747049 0.0865628 -0.127027 0.0997718 -0.118786 0.172951 -0.208013 0.216935 -0.215728 0.401293 -0.19069 0.923122)) (0.0267348 0.000456167 0.130624 #(0.0221721 0.012707 -0.0342673 0.0498141 -0.125798 0.0945948 -0.009383 -0.0118047 -0.00833615 0.0354772 -0.041698 0.0220065 -0.043747 0.0427328 -0.0334768 0.0279624 -0.0268537 0.00968139 0.00111546 0.0377293 -0.0348329 0.0808209 -0.0457136 0.00457449 -0.0453242 -0.0107467 -0.0188348 0.0300905 0.173791 -0.194862 0.0537233 -0.0419804 0.0496971 -0.0701674 0.0499813 -0.00747099 -0.0222291 0.0273433 -0.0549461 0.0661543 -0.122178 0.0944649 -0.101576 0.17229 -0.189446 0.207714 -0.21558 0.418696 -0.215629 0.931565)) (0.0200745 0.000471228 0.153212 #(0.0163527 0.00660207 -0.0143944 0.046632 -0.126296 0.118434 -0.0369965 -0.00451566 -0.0201182 0.0417401 -0.0308534 -0.00543496 -0.0172945 0.0438493 -0.0319897 -0.0176332 -0.00909391 0.00684448 0.00776292 0.0226499 -0.00129345 0.0597638 -0.057499 0.0439582 -0.0376084 -0.009205 -0.0282326 0.0349981 0.136497 -0.137021 0.0108061 -0.0220325 0.0138336 -0.0341895 0.00554748 0.0125278 -0.0174402 0.0430164 -0.0595981 0.048263 -0.112704 0.102835 -0.101221 0.15651 -0.167554 0.189205 -0.200076 0.383302 -0.1668 0.902884)) (0.0178948 0.000884452 0.222317 #(-0.00627428 0.017076 -0.0217517 0.0596357 -0.115011 0.137658 -0.140797 0.0413646 -0.025147 0.0409271 -0.0298679 0.0230878 -0.00804102 0.0133819 -0.0343905 0.081481 -0.0160831 0.031044 -0.0362416 0.0814956 -0.0892642 -0.0230409 -0.0232022 0.112084 -0.0729296 -0.0349948 0.00901226 -0.0373362 0.140441 -0.0702999 -0.00257567 -0.0348515 -0.00258082 0.0140751 -0.0718087 0.0880132 -0.061838 0.0690842 -0.118292 0.142831 -0.185955 0.190591 -0.155962 0.45873 -0.106312 0.127302 -0.523777 0.419269 -0.501987 1.22411)) (0.014956 0.000914502 0.247278 #(-0.023965 0.0260125 -0.0174047 0.0515138 -0.0830966 0.07056 -0.0839288 -0.00253678 0.0274258 -0.000953763 -0.00370321 0.0051892 0.0273904 -0.020619 -0.0100326 0.0564985 0.00785514 0.0225726 -0.0248022 0.0636671 -0.0849298 -0.0493795 0.0247842 0.0783257 -0.054683 -0.0485245 0.00161631 -0.0165824 0.139226 -0.0743001 -0.00122059 -0.0566757 0.0247024 0.00172735 -0.0647441 0.0783151 -0.0575751 0.0609131 -0.105484 0.127889 -0.170536 0.193175 -0.164876 0.462587 -0.105663 0.112055 -0.495609 0.396188 -0.497893 1.21815)) (0.00871568 0.000567858 0.255252 #(-0.0124666 0.0309579 -0.00109739 0.0135459 -0.057433 0.0477187 -0.0502651 0.00271826 0.0372547 0.0164188 -0.0446111 -0.0127535 -0.0377459 0.05085 -0.0332468 0.0648767 -0.0421368 0.0453716 -0.00560286 0.010505 -0.0502685 0.0272348 -0.0168195 0.0334298 -0.045445 0.0609193 -0.0939262 0.0603289 0.127758 -0.127759 -0.0161537 -0.0241133 0.0220789 0.0501327 -0.0297039 0.0276074 -0.0749799 0.0195223 -0.134458 0.0784379 -0.103965 0.143044 -0.0238226 0.243323 -0.14168 0.124602 -0.245754 0.281028 -0.225522 0.993662)) (0.0086891 0.000454286 0.228653 #(0.000182833 -0.00254678 0.0082363 -0.0153415 -0.0299224 0.0849131 -0.0489407 0.00623273 0.00330074 0.015936 -0.0400408 -0.020401 -0.0247914 0.0710104 -0.015902 0.00164445 -0.0397469 0.0223963 0.0144133 0.00597068 -0.0101367 0.0517253 -0.0400181 0.0204692 -0.0703128 0.0792271 -0.0877888 0.0647522 0.100521 -0.114483 -0.00566729 -0.0255629 0.0314529 0.0182582 -0.0152464 0.0337968 -0.0685177 0.0350596 -0.0735331 0.0771414 -0.107742 0.0609778 -0.0612328 0.122617 -0.132552 0.162598 -0.143835 0.327107 -0.115002 0.855719)) nyquist-3.05/lpc/lpc-orig.lsp0000644000175000000620000001206310144436365015205 0ustar stevestaff;--------------------------------------------------------------------- ; LPANAL. Performs LPC analysis ; ; snd sound for analysis ; an-dur duration of analysis (= duration of sound) ; skiptime step frame to frame ; npoles number of poles ; ; RESULT: analysis data in list format. ; Every element of the list is a list of the form ; ; (RMS1 RMS2 ERR FILTER-COEFS) ; ; RMS1 Energy (not rms value) of input signal ; RMS2 Energy (not rms value) of residual signal ; ERR = sqrt(RMS2/RMS1) If it is small then VOICED sound, ; else UNVOICED ; FILTER-COEFS Array of filter coefs. ; ; ; The z transform of filter is H(z) = 1/A(z) ; ; where A(z) is a polynome of the form: ; ; ; A(z) = 1 + a1 z + a2 z^2 + a3 z^3 + ... + aP z^P ; ; FILTER-COEFS is the array ; ; #(-aP -aP-1 -aP-2 ... a3 a2 a1) ; ; (this format is suited for the filter ALLPOLES) ; (defun lpanal (snd an-dur skiptime npoles) (let* ((sr (snd-srate snd)) (skipsize (round (* sr skiptime))) (numframes (round (- (/ (* sr an-dur) skipsize) 0.5))) (sndcpy (snd-copy snd)) (result (make-array numframes))) (dotimes (i numframes) (setf (aref result i) (snd-lpanal (snd-fetch-array sndcpy (* 2 skipsize) skipsize) npoles))) (format t "LPANAL: duration: ~A frames: ~A framedur: ~A skip: ~A poles ~A\n" an-dur numframes (* skiptime 2) skiptime npoles) result)) ;; this code is based on fft_demo.lsp -- the idea is that an object ;; will return a stream of LPC frames. Other objects can manipulate ;; these frames, creating a new stream, or turn the frames back into ;; sound. (setf lpc-class (send class :new '(sound framesize skipsize npoles))) (send lpc-class :answer :isnew '(snd framedur skiptime np) '( (let ((sr (snd-srate snd))) (setf sound snd) (setf framesize (round (* sr framedur))) (setf skiptime (round (* sr skiptime))) (setf npoles np))) (send lpc-class :next '() '( (let ((samps (snd-fetch-array framesize skipsize))) (cond ((null samps) nil) (t (snd-lpanal samps npoles))))) (defun make-lpanal-iterator (sound framedur skiptime npoles) (send lpc-class :new (snd-copy sound) framedur skiptime npoles)) ;--------------------------------------------------------------------- ; SHOW-LPC-DATA. Show values of LPC analysis frames ; ; lpc-data data generated by LPANAL ; iniframe first frame to show ; endframe last frame to show ; poles? T or NIL show or not filter coefs (defun show-lpc-data (lpc-data iniframe endframe &optional (poles? NIL)) (if (> endframe (length lpc-data)) (setf endframe (length lpc-data))) (dotimes (i (- endframe iniframe)) (if poles? (format t "FRM ~A : ~A\n" (+ i iniframe) (aref lpc-data (+ i iniframe))) (format t "FRM ~A : ~A\n" (+ i iniframe) (reverse (cdr (reverse (aref lpc-data (+ i iniframe))))))))) ;---------------------------------------------------------------------- ; LPC-FREQ. Show frequency response of ALLPOLES filter. ; NEEDS MATLAB or OCTAVE ; ; ; HELPER FUNS : GET-FILTER-COEFS from a LPC analysis data ; lpc-data: data generated by LPCANAL ; numframe: index of frame data ; ; LPC-COEFS-TO-MATLAB : transforms LPC coefs format to Matlab format ; ; LPC-FREQ. ; ; varname : the name of variable that holds coef array in MATLAB ; lpc-data : as above ; numframe : as above ; (defun get-filter-coefs (lpc-data numframe) (nth 3 (aref lpc-data numframe))) (defun lpc-coefs-to-matlab (lpc-data numframe) (let* ((lpc-coefs (get-filter-coefs lpc-data numframe)) (lencoefs (length lpc-coefs)) (result (make-array (1+ lencoefs)))) (setf (aref result 0) 1.0) (dotimes (i lencoefs) (setf (aref result (1+ i)) (- (aref lpc-coefs (- lencoefs i 1))))) result)) (defun lpc-freq (varname lpc-data numframe) (octave (list (list (lpc-coefs-to-matlab lpc-data numframe) varname 'ARR)))) ;---------------------------------------------------------------------------- ; ALLPOLES ; (defun get-allpoles-gain (lpc-data numframe) (nth 2 (aref lpc-data numframe))) ; se toma ERR para que la amplitud de ; la salida se aproxime a 1 (defun allpoles-from-lpc (snd lpc-data numframe) (snd-allpoles snd (get-filter-coefs lpc-data numframe) (get-allpoles-gain lpc-data numframe))) ;------------------------------------------------------------------------------- ; LPRESON (defun get-lpreson-gain (lpc-data numframe) (sqrt (nth 1 (aref lpc-data numframe)))) ; se toma (sqrt RMS2) para que la amplitud se ; aproxime a la original (defun get-lpreson-coefs (lpc-data numframe) (nth 3 (aref lpc-data numframe))) nyquist-3.05/lpc/lpcdemo-orig.lsp0000644000175000000620000002056210144436365016055 0ustar stevestaff;;; LPC demo 1 ;;; Pedro J. Morales. ;;; February, 04 ; PLEASE config ====================================================== ; don't need this because file-io utilities are embedded in this file ; (setf *file-io* "c:/04-nyquist/nyqdoc/tools/file-io.lsp") ; where is the file lpc-example.dat (setf *lpc-data* "d:/rbd/nyquist/lpc/lpc-example.dat") ; this file generated by Nyquist will be loaded by Octave (or Matlab) (setf *default-octave-file* "d:/rbd/temp/nyquist.dat") ; config END =========================================================== ; file-io tools ======================================================== (defun load-file-data (filename) (let (result (fp (open filename :direction :input))) (when fp (setf result (read fp))) (close fp) result)) (defun save-file-data (data filename) (let ((fp (open filename :direction :output))) (when fp (format fp "~A" data)) (close fp))) (defun octave-1 (outf data varname datatype &optional (n 1000)) (prog ((points (case datatype (SND (snd-samples data (1+ n))) (ARR data))) len) (setf len (length points)) (cond ((> len n) (setf len n) (format t "WARNING: DATA TRUNCATED TO ~A POINTS~%" len))) (format outf "# name: ~A\n" varname) (format outf "# type: matrix\n# rows: 1\n# columns: ~A\n " len) (dotimes (i len) (format outf "~A " (aref points i))) (format outf "\n"))) (defun octave (data-lists) ; (data varname datatype &optional (n 1000)) (prog ((filename *default-octave-file*) outf) (setf outf (open filename :direction :output)) (cond ((null outf) (format t "octave: could not open ~A!~%" filename) (return nil))) (format t "octave: writing ~A ... ~%" filename) (cond ((null outf) (format t "octave: could not open ~A!~%" filename) (return nil))) ;(format t "octave: writing ~A ... ~%" filename) (dolist (l data-lists) (apply #'octave-1 (cons outf l))) (close outf))) ; load file-io --------------------------------------------------- ; (load *file-io*) ; file-io END ==================================================== ; LPANAL ====================================================== ; get lpc data --------------------------------------------------- (defun do-lpc-analysis () (prog () (setf *myfile* "d:/rbd/nyquist/voice.wav") (setf mysound (s-read *myfile*)) ; duration 6.5 skiptime 20ms npoles 50 (setf lpc-example (lpanal (cue mysound) 1.3 0.04 50)))) ;(if (not (boundp 'lpc-example)) ; (do-lpc-analysis)) (if (not (boundp 'lpc-example)) (setf lpc-example (load-file-data *lpc-data*))) ;----------------------------------------------------------------- ; SHOW-LPC-DATA ------------------------------------------------ ; show values of LPC analysis frames ---------------------------- (defun ex-1 () (show-lpc-data lpc-example 100 120 NIL)) ; do not show filter coefs ; ------- SAVE-FILE-DATA --------------------------------------- (defun ex-2 () (save-file-data lpc-example *lpc-data*)) ;----------- LPC-FREQ ------------------------------------------ ; LPC-FREQ. Show frequency response of ALLPOLES filter. ; NEEDS MATLAB or OCTAVE ; (defun ex-3 () (lpc-freq "frm70" lpc-example 70)) ; in MATLAB/OCTAVE: ; >> load -force nyquist.dat ; >> [H,W] = freqz(1, frm70, 512); ; >> plot(W,20*log10(abs(H))); ;------------------------------------------------------------------------- ; LPC-STABILITY Check for Stability of LPC filters ; NEEDS MATLAB/OCTAVE ; EXAMPLE ; (ex-3) ; in MATLAB/OCTAVE: ; >> load -force nyquist.dat ; >> find(abs(roots(frm70)) > 1) ; if any abs root is > 1.0 then UNSTABLE ;-------------------------------------------------------------------------- ; ALLPOLES LPC allpoles filter ; WARNING: this is a static filter ; for LPC resynthesis a dinamic LPC filter is needed ; EXAMPLE (defun ex-4 () (play (seq (allpoles-from-lpc (buzz 12 f2 (lfo 5.0 4.0)) lpc-example 30) (allpoles-from-lpc (buzz 12 f2 (lfo 5.1 4.0)) lpc-example 60) (allpoles-from-lpc (buzz 12 g2 (lfo 5.3 4.0)) lpc-example 100)))) (setf a-lpcdata '(63.2144 0.674387 0.103287 #(-0.0381026 0.00804115 0.0109905 0.0145117 0.00199174 -0.00129314 0.0171826 0.0181176 0.00179391 -0.0114089 -0.0120949 -0.000410595 -0.0122539 -0.0209354 -0.00804976 -0.00345041 -0.00409532 -0.00227011 0.014224 0.0135451 0.0056023 -0.00651142 -0.00564953 -0.0168921 -0.0377939 -0.0449506 -0.0355592 -0.0339316 -0.0454434 1.19336))) (setf e-lpcdata '(40.7157 0.149753 0.0606467 #(0.0244574 -0.0225545 -0.0172724 -0.0122709 -0.0042946 0.00886974 0.0121516 0.0120936 0.00197545 -0.00582163 -0.018367 -0.0201546 -0.00440599 0.00638936 0.0166275 0.0185066 0.00890464 -0.00158013 -0.00494974 -0.00479037 0.0130814 0.0138648 -0.0022018 -0.021368 -0.0343532 -0.0312712 -0.0574975 -0.0918824 -0.112016 1.31398))) (setf i-lpcdata '(5.5391 0.0321825 0.0762238 #(-0.0341124 -0.0149688 -0.00585657 -0.0111572 0.00769712 0.0190367 0.00885366 0.0112762 0.0118286 -0.00059044 -0.0140864 -0.0123688 -0.0151128 0.00214354 -0.00810219 -0.00538188 0.00631382 0.020771 0.0356498 0.0295531 0.0242797 0.0124296 0.00445127 -0.013062 -0.0387178 -0.0527783 -0.0685511 -0.076575 -0.0846335 1.24521))) (defun noise-vocal (lpcdata dur) (snd-allpoles (noise dur) (nth 3 lpcdata) (nth 2 lpcdata))) (defun ex-5 () (play (seq (noise-vocal a-lpcdata 1)(noise-vocal e-lpcdata 1)(noise-vocal i-lpcdata 1)))) (defun buzz-vocal (lpcdata dur) (snd-allpoles (buzz 16 e2 (const 0.0 dur)) (nth 3 lpcdata) (nth 2 lpcdata))) (defun ex-6 () (play (seq (buzz-vocal a-lpcdata 1)(buzz-vocal e-lpcdata 1)(buzz-vocal i-lpcdata 1)))) ; ---- LPRESON ------------------------------------------------------------ ; (setf example-lpc-class (send class :new '(cnt limit))) (send example-lpc-class :answer :isnew '() '((setf cnt 0) (setf limit (length lpc-example)))) (send example-lpc-class :answer :reset '() '((setf cnt 0))) (send example-lpc-class :answer :next '() '((setf cnt (1+ cnt)) (if (= cnt limit) (setf cnt 0)) (if (< cnt limit) (list (get-lpreson-gain lpc-example cnt) (get-lpreson-coefs lpc-example cnt)) NIL))) (setf mylpc (send example-lpc-class :new)) (defun ex-7a () (send mylpc :reset) (snd-lpreson (noise 6.5) mylpc 0.04)) (defun ex-7 () (play (ex-7a))) (defun ex-8a (p dur) (send mylpc :reset) (snd-lpreson (buzz 16 p (scale 1.5 (lfo 3.0 dur))) mylpc 0.04)) (defun ex-8 () (play (sim (seq (ex-8a c4 1)(ex-8a g3 1)(ex-8a a3 1)(ex-8a b3 1)(ex-8a c4 1)) (seq (ex-8a c2 2)(ex-8a f2 1)(ex-8a g2 1)(ex-8a e2 1))))) (defun noalias-buzz (p nmax) (min (round (/ *sound-srate* (* 2.0 (step-to-hz p)))) nmax)) (defun ex-9a (p dur skiptime) (send mylpc :reset) (mult (env 0.01 0.01 0.1 1.0 1.0 1.0 dur) (snd-lpreson (buzz (noalias-buzz p 16) p (scale 1.5 (lfo 3.0 dur))) mylpc skiptime))) (defun ex-9b (stretch skiptime) (play (sim (seq (ex-9a c4 (* 1 stretch) skiptime)(ex-9a g3 (* 1 stretch) skiptime) (ex-9a a3 (* 1 stretch) skiptime) (ex-9a b3 (* 1 stretch) skiptime)(ex-9a c4 (* 1 stretch) skiptime)) (seq (ex-9a c2 (* 2 stretch) skiptime)(ex-9a f2 (* 1 stretch) skiptime) (ex-9a g2 (* 1 stretch) skiptime)(ex-9a e2 (* 1 stretch) skiptime))))) (defun ex-9 () (ex-9b 1.0 0.04)) (defun ex-10 () (ex-9b 1.0 0.02)) (defun ex-11 () (ex-9b 2.0 0.04)) (defun ex-12 () (ex-9b 0.5 0.02)) (defun ex-13 () (ex-9b 4 0.02)) (defun ex-14a (p dur skiptime) (send mylpc :reset) (mult (env 0.01 0.01 0.1 1.0 1.0 1.0 dur) (snd-lpreson (osc-saw (sim (step-to-hz (+ p 0)) (scale 1.5 (lfo 3.0 dur)))) mylpc skiptime))) (defun ex-14b (stretch skiptime) (play (sim (seq (ex-14a c4 (* 1 stretch) skiptime)(ex-14a g3 (* 1 stretch) skiptime) (ex-14a a3 (* 1 stretch) skiptime) (ex-14a b3 (* 1 stretch) skiptime)(ex-14a c4 (* 1 stretch) skiptime)) (seq (ex-14a c2 (* 2 stretch) skiptime)(ex-14a f2 (* 1 stretch) skiptime) (ex-14a g2 (* 1 stretch) skiptime)(ex-14a e2 (* 1 stretch) skiptime))))) (defun ex-14 () (ex-14b 1 0.04)) (defun ex-15 () (ex-14b 4 0.02)) (defun ex-16 () (ex-14b 8 0.08)) nyquist-3.05/lpc/prims-ref.txt0000644000175000000620000000362210144436365015417 0ustar stevestaff==================================== Reference of LPC primitive functions ==================================== snd-lpanal ARGS: snd-array npoles snd-array: array of samples from a sound to be analyzed npoles: number of poles for LPC analysis returns: a list (RMS1 RMS2 ERR VECTOR) where RMS1: energy of input data (not rms value!) RMS2: energy of residual ERR: sqrt(RMS2/RMS1) VECTOR: array of LPC filter coefficients Note: this analysis lacks pitch detection ------------------------------------------------------------------- snd-allpoles ARGS: snd coefs gain snd: A sound coefs: Array of coefficients of an allpoles filter. The format of this array is the same of the fourth element of the list returned by snd-lpcanal. (see details in lpc.lsp) gain: gain of the LPC filter (a FLONUM) returns: The sound filtered by the specified allpoles filter Note: This is a static filter. Coefficients do not change. -------------------------------------------------------------------- snd-lpreson ARGS: snd lpc-obj skiptime snd: A sound lpc-obj A Lisp object such as when a :next message is send to this object it returns a list of two elements (GAIN COEFS) where: GAIN: gain of the filter COEFS: coefficients of LPC filter skiptime: a FLONUM. This is the frame duration for resyntesis. returns: The sound snd filtered by a dinamic LPC filter. The coefficients and gain of LPC filter are changed every frame The data for every frame is obtained by sending a :next message to lpc-obj. The output sound finish when input sound finish or when lpc-obj returns NIL nyquist-3.05/lpc/compile.txt0000644000175000000620000000405310144436365015142 0ustar stevestaffHow to compile Nyquist with LPC functions Note: this is compiled with MSVC 6 in Windows 1. Translate lpreson.alg : Result lpreson.h, lpreson.c 2. Translate allpoles.alg: Result allpoles.h, allpoles.c 3. lpanal.h and lpanal.c are coded in C (no alg file) 4. Modify the files sndfint.c sndfnintptrs.h sndfintdefs.h as it is show below (I modify this "by hand" although it may be automatized) 5. Add all these files to Nyquist project 6. Compile ---------------------------------------------------------------------------------- To add these functions to Nyquist "by hand" edit the files and add this C code SOURCE CODE FOR sndfint.c #include "lpanal.h" /* xlc_snd_lpanal -- interface to C routine snd_lpanal */ /**/ LVAL xlc_snd_lpanal(void) { LVAL arg1 = xlgetarg(); long arg2 = getfixnum(xlgafixnum()); LVAL result; xllastarg(); result = snd_lpanal(arg1,arg2); return (result); } #include "allpoles.h" /* xlc_snd_allpoles -- interface to C routine snd_allpoles */ /**/ LVAL xlc_snd_allpoles(void) { sound_type arg1 = getsound(xlgasound()); LVAL arg2 = xlgetarg(); double arg3 = testarg2(xlgaanynum()); sound_type result; xllastarg(); result = snd_allpoles(arg1, arg2, arg3); return cvsound(result); } #include "lpreson.h" /* xlc_snd_lpreson -- interface to C routine snd_lpreson */ /**/ LVAL xlc_snd_lpreson(void) { sound_type arg1 = getsound(xlgasound()); LVAL arg2 = xlgetarg(); double arg3 = testarg2(xlgaanynum()); LVAL result; xllastarg(); result = snd_lpreson(arg1, arg2, arg3); return cvsound(result); } ========================================================================= SOURCE CODE FOR sndfintptrs.h { "SND-LPANAL", S, xlc_snd_lpanal}, { "SND-ALLPOLES", S, xlc_snd_allpoles}, { "SND-LPRESON", S, xlc_snd_lpreson}, ========================================================================= SOURCE CODE FOR sndfintdefs.h extern LVAL xlc_snd_lpanal(void); extern LVAL xlc_snd_allpoles(void); extern LVAL xlc_snd_lpreson(void); nyquist-3.05/lpc/lpc.lsp0000644000175000000620000001314710144436365014253 0ustar stevestaff;--------------------------------------------------------------------- ; LPANAL. Performs LPC analysis ; ; snd sound for analysis ; an-dur duration of analysis (= duration of sound) ; skiptime step frame to frame ; npoles number of poles ; ; RESULT: analysis data in list format. ; Every element of the list is a list of the form ; ; (RMS1 RMS2 ERR FILTER-COEFS) ; ; RMS1 Energy (not rms value) of input signal ; RMS2 Energy (not rms value) of residual signal ; ERR = sqrt(RMS2/RMS1) If it is small then VOICED sound, ; else UNVOICED ; FILTER-COEFS Array of filter coefs. ; ; ; The z transform of filter is H(z) = 1/A(z) ; ; where A(z) is a polynome of the form: ; ; ; A(z) = 1 + a1 z + a2 z^2 + a3 z^3 + ... + aP z^P ; ; FILTER-COEFS is the array ; ; #(-aP -aP-1 -aP-2 ... a3 a2 a1) ; ; (this format is suited for the filter ALLPOLES) ; (setfn lpc-frame-rms1 car) (setfn lpc-frame-rms2 cadr) (setfn lpc-frame-err caddr) (setfn lpc-frame-filter-coefs cadddr) ;; LPANAL-CLASS -- does lpc analysis. Frames are returned ;; from an iterator object (setf lpanal-class (send class :new '(sound framesize skipsize npoles))) (send lpanal-class :answer :isnew '(snd framedur skiptime np) '( (let ((sr (snd-srate snd))) (setf sound snd) (setf framesize (round (* sr framedur))) (setf skiptime (round (* sr skiptime))) (setf npoles np)))) (send lpanal-class :answer :next '() '( (let ((samps (snd-fetch-array framesize skipsize))) (cond ((null samps) nil) (t (snd-lpanal samps npoles)))))) (defun make-lpanal-iterator (sound framedur skiptime npoles) (send lpanal-class :new (snd-copy sound) framedur skiptime npoles)) ;; LPC-FILE-CLASS -- iterator returns frames from file ;; (setf lpc-file-class (send class :new '(file))) (send lpc-file-class :answer :isnew '(filename) '( (setf file (open filename)))) (send lpc-file-class :answer :next '() '( (read file))) (defun make-lpc-file-iterator (filename) (send lpc-file-class :new filename)) ;; SAVE-LPC-FILE -- create a file from an iterator. This file can ;; be turned back into an iterator using make-lpc-file-iterator. ;; (defun save-lpc-file (lpc-iterator filename) (let ((fp (open filename :direction :output)) (frame t)) (while frame (setf frame (send lpc-iterator :next)) (if frame (format fp "~A~%" frame))) (close fp))) ;; SHOW-LPC-DATA. Show values of LPC analysis frames from interator. ;; (defun show-lpc-data (lpc-iterator iniframe endframe &optional (poles? NIL)) (dotimes (i iniframe) (send lpc-iterator :next)) (dotimes (i (- endframe iniframe)) (let ((frame (send lpc-iterator :next))) (cond ((null frame) (return)) (poles? (format t "FRM ~A : ~A\n" (+ i iniframe) frame)) (t (format t "FRM ~A : ~A\n" (+ i iniframe) (reverse (cdr (reverse frame))))))))) ;---------------------------------------------------------------------- ; LPC-FREQ. Show frequency response of ALLPOLES filter. ; NEEDS MATLAB or OCTAVE ; ; ; HELPER FUNS : GET-FILTER-COEFS from a LPC analysis data ; lpc-data: data generated by LPCANAL ; numframe: index of frame data ; ; LPC-COEFS-TO-MATLAB : transforms LPC coefs format to Matlab format ; ; LPC-FREQ. ; ; varname : the name of variable that holds coef array in MATLAB ; lpc-data : as above ; numframe : as above ; ; THIS CODE TO GET FREQUENCY ASSUMES AN ARRAY OF LPC FRAMES AND REQUIRES ; MATLAB OR OCTAVE. I HAVE NOT ADAPTED THIS TO USE THE STREAM OF FRAMES ; APPROACH. -RBD ; ;(defun get-filter-coefs (lpc-data numframe) ; (nth 3 (aref lpc-data numframe))) ; ; ;(defun lpc-coefs-to-matlab (lpc-data numframe) ; (let* ((lpc-coefs (get-filter-coefs lpc-data numframe)) ; (lencoefs (length lpc-coefs)) ; (result (make-array (1+ lencoefs)))) ; (setf (aref result 0) 1.0) ; (dotimes (i lencoefs) ; (setf (aref result (1+ i)) ; (- (aref lpc-coefs (- lencoefs i 1))))) ; result)) ; ; ;(defun lpc-freq (varname lpc-data numframe) ; (octave (list (list (lpc-coefs-to-matlab lpc-data numframe) varname 'ARR)))) ;---------------------------------------------------------------------------- ; ALLPOLES ; ; THIS VERSION IS FOR ARRAY OF FRAMES ; ;(defun get-allpoles-gain (lpc-data numframe) ; (nth 2 (aref lpc-data numframe))) ; se toma ERR para que la amplitud de ; ; la salida se aproxime a 1 ; ;(defun allpoles-from-lpc (snd lpc-data numframe) ; (snd-allpoles snd (get-filter-coefs lpc-data numframe) (get-allpoles-gain lpc-data numframe))) ; ALLPOLES USES A SINGLE FRAME TO CREATE A FILTER ; ; We introduce two functions: ; NTH-FRAME runs the interator to get the nth frame; ; ALLPOLES-FROM-LPC filters a sound given a frame from an iterator ;; NTH-FRAME - get the nth frame from lpc iterator, ;; first frame is numbered zero (defun nth-frame (lpc-iterator numframe) (dotimes (i numframe) (send lpc-iterator :next)) (send lpc-iterator :next)) ;; ALLPOLES-FROM-LPC -- filter a sound using an LPC frame ;; (defun allpoles-from-lpc (snd lpc-frame) (snd-allpoles snd (lpc-frame-filter-coefs lpc-frame) (lpc-frame-err lpc-frame))) ;; use ERR for gain ;------------------------------------------------------------------------------- ; LPRESON (setfn lpreson snd-lpreson) nyquist-3.05/lpc/readme.txt0000644000175000000620000000153510144436365014751 0ustar stevestaff; LPC functions for Nyquist ; Pedro J. Morales, 2004 1. Compile Nyquist with LPC functions See file compile.txt for details Source code is in src folder 2. Reference of LPC primitives. See file prims-ref.txt 3. Implementation of high level LPC Lisp functions File: lpc.lsp 4. Reference of high level LPC Lisp functions See file lpc.lsp 5. LPC demo 5.1. Compile and start Nyquist 5.2. Load lpc.lsp 5.3. Edit lpcdemo.lsp and configure it. 5.4. Load lpcdemo.lsp Note: lpcdemo should perform an analysis of an audio file. This audio file is not supplied (for size reasons) Instead, the result is supplied as a Lisp data structure contained in the file lpc-example.dat that is loaded by lpcdemo. 5.5. Run the examples. Note: You don't have to run all the examples nyquist-3.05/lpc/lpc-example.dat0000644000175000000620000026343010144436365015660 0ustar stevestaff#((0.0205328 0.000539653 0.162119 #(0.0172437 -0.00206371 0.0199834 0.0140023 -0.107106 0.105376 -0.014147 -0.0456254 -0.035733 0.000526876 0.024559 -0.077979 0.0379572 0.0550832 0.0251978 -0.0158793 0.000201547 0.0183836 0.0120267 -0.0145289 0.0270053 0.0215023 -0.0674045 0.0868633 -0.0759818 0.0123872 -0.100426 0.0670379 0.153223 -0.160887 0.0200027 0.00857184 -0.0319345 0.0372642 -0.039906 0.0370124 -0.0406953 0.0916241 -0.0794324 0.0994091 -0.152256 0.122422 -0.131096 0.143904 -0.182573 0.107067 -0.216319 0.338997 -0.171402 1.04299)) (0.0746031 0.000883533 0.108826 #(0.043002 -0.0168565 0.0116234 -0.031321 -0.0728684 0.134856 0.0052372 -0.0477521 -0.0767405 0.0307031 0.00286882 -0.0188694 -0.0103552 0.0410824 -0.00991496 0.0129631 -0.0070764 0.0446677 -0.0316206 0.0103328 -0.00314631 0.0721652 -0.028264 0.0429488 -0.0757499 0.0355948 -0.124679 0.0341884 0.147169 -0.115948 0.0350534 -0.022784 0.00255128 0.000132609 0.00266292 0.0235752 -0.0270638 0.00319338 -0.0405898 0.0510949 -0.0525406 0.112875 -0.120262 0.103579 -0.140658 0.030511 -0.195171 0.226418 -0.194436 1.19625)) (7.90651 0.00254103 0.0179272 #(0.0298438 -0.0150177 0.00856811 0.00178307 -0.156251 0.141521 0.0377321 -0.00862076 0.0358013 -0.0526648 -0.0746482 0.0176761 0.0180553 0.0110547 -0.0149859 -0.00274912 0.00753696 0.0570906 -0.00985159 -0.0460384 -0.0312089 0.0275762 -0.00179828 0.0498972 -0.0462076 0.111785 -0.101277 -0.0429219 0.135046 -0.118618 0.0320909 0.0152628 0.00229011 0.000619642 -0.00148223 0.0698463 -0.0192731 -0.061608 -0.105966 0.00760205 -0.0556964 0.172818 -0.0018539 0.14807 -0.115714 0.0485711 -0.341883 0.118442 -0.644804 1.76356)) (16.8204 0.00353871 0.0145046 #(0.0242379 0.0163801 -0.0441124 0.0515951 -0.165318 0.0553254 0.118888 -0.00888211 0.0686623 -0.103195 -0.109872 0.0873954 -0.00312068 -0.0157818 0.00793753 -0.0102677 0.0385871 0.0402539 0.0275778 -0.124176 -0.0224998 -0.0083091 0.139262 -0.0326057 -0.0686154 0.152026 -0.0710961 -0.100093 0.0921394 -0.0886168 0.0962788 0.0235546 -0.0835561 0.0289921 -0.0519826 0.0819953 0.0677047 -0.04636 -0.154177 0.0188317 -0.0733893 0.18706 -0.117089 0.276443 -0.188078 0.136406 -0.348012 0.354862 -1.21044 2.05642)) (15.7527 0.00488585 0.0176113 #(0.0410332 -0.0212341 -0.0186016 0.0139835 -0.10253 0.0317464 0.098534 0.0577219 -0.00603218 -0.119189 -0.0560336 0.0600247 0.00563636 -0.00741701 -0.022568 0.0551003 0.0172174 -0.0145449 0.0377798 -0.0774387 -0.0623132 0.0156745 0.116856 0.0167625 -0.0740776 0.0976961 -0.0589157 -0.0592283 0.0621122 -0.0668073 0.0672344 0.0433492 -0.0724394 -0.0149194 -0.0174723 0.0940844 0.0192709 -0.037947 -0.145742 0.0166333 -0.0382952 0.137928 -0.0235971 0.142885 -0.0641163 -0.0401743 -0.14418 0.182686 -1.00692 1.93978)) (16.3531 0.0136897 0.0289333 #(-0.024896 0.016421 0.00786502 -0.0118406 0.00603457 0.0343453 0.0250988 -0.00670104 -0.0483285 -0.0402459 0.00284676 0.0223309 0.00649693 -0.0116516 0.00923614 0.0111503 -0.000440774 -0.0275555 0.00682401 -0.0125723 0.00263826 0.0153074 0.0242379 0.0142031 0.0060273 0.0192062 -0.0368178 0.00965019 0.0058204 -0.00736851 0.0414994 0.00440613 -0.0394615 -0.0217087 0.0132956 0.0116567 -0.024931 -0.0592983 -0.0327111 0.00831445 0.0282831 0.0678891 0.00450369 0.00915988 -0.0181229 -0.0469828 -0.0555707 -0.0913728 -0.228273 1.41019)) (22.7776 0.0128829 0.0237823 #(-0.0244512 0.00852192 0.00355279 0.0100932 -0.00419528 0.0237172 0.0103759 -0.0137028 -0.0251104 -0.0134613 -0.000615256 0.00165147 -0.00407305 -0.00344569 -0.00120993 0.0089017 0.000495352 -0.000238208 0.00294549 0.00112805 0.00425276 0.0266437 0.0165051 -0.0296654 -0.00157895 0.0406957 -0.0203225 0.000875471 0.0187371 -0.00604564 0.0124178 0.00848914 -0.00870932 -0.0345038 -0.0166086 -0.00777551 -0.0127552 -0.0198208 -0.018883 0.00170381 0.0281818 0.0335668 0.00621638 0.000123257 -0.0400046 -0.0251494 -0.0599436 -0.0484318 -0.0953316 1.26394)) (25.9418 0.014063 0.023283 #(-0.0146976 0.0123669 -0.00238331 -0.00566441 0.000213927 0.0251708 0.0058586 -0.0152624 -0.0096643 0.000380473 -0.00692432 -0.0103325 -0.00570062 -0.00779317 -0.00373097 -0.00244446 0.0232326 0.00687431 -0.0123666 0.0136142 0.000873428 0.01297 0.00157535 -0.0189359 0.0103542 0.0149338 -0.00232667 0.018195 0.0122806 0.000705099 0.0180465 -0.00723085 -0.0333543 -0.0209618 -0.00258482 -0.00346647 -0.0161793 -0.00443528 -0.0107334 -0.00729346 0.0212632 0.017004 -0.0134609 -0.0122188 -0.0266593 -0.0240987 -0.0584669 -0.0204726 -0.0728998 1.23429)) (26.411 0.0454326 0.0414755 #(-0.0109339 -0.0010968 -0.0010053 0.00617609 0.00306015 0.000136934 0.00372594 -0.00564924 -0.00591968 -0.00522412 -0.00509402 -3.17432e-006 -0.00446083 0.00456961 0.00243643 0.00451923 0.00334826 0.00559344 0.00805774 0.000849614 0.00365901 -0.000214671 -0.00258062 0.00132718 0.00916179 0.00321858 -0.00441098 0.00674969 0.00362521 0.00233835 0.00103611 -0.00365412 -0.0110665 -0.0113001 -0.00483079 -0.00471838 -0.0072024 -0.0112189 -0.00842469 -0.00122134 0.00258161 -0.00404681 -0.0108012 -0.0163903 -0.0156165 -0.0101237 -0.0119205 -0.0127908 -0.0241693 1.1353)) (26.023 0.0171174 0.0256472 #(-0.00659148 -0.0022813 0.00245043 0.0119932 0.00673879 0.0106215 0.000193227 -0.0118672 -0.00229731 -8.44562e-005 -0.010244 -0.0224172 -0.0074773 0.00139424 0.00442344 -0.00372009 0.00631038 0.00399001 0.00074413 0.00143648 0.0117816 0.0167116 -0.011429 0.00660101 -0.0154429 0.0245051 0.00954568 0.00221017 0.00972422 0.00691179 0.00198784 0.00641321 -0.0164092 -0.0286664 -0.00348171 -0.00646432 -0.0149224 -0.00929398 0.000946284 -0.00786511 0.0105857 0.0116371 -0.0208869 -0.0167969 -0.039235 -0.0416232 -0.0188724 -0.0395318 -0.0672928 1.2529)) (20.1471 0.0413173 0.0452855 #(0.0028042 0.00238915 0.00320531 0.00204744 -0.00128491 -0.000625469 0.00121502 -0.00053792 -0.00926453 -0.00168529 -0.0176347 -0.00451895 0.000996928 0.00430582 0.00194222 -0.00398466 0.00259957 0.00390882 0.0116503 0.00167209 -0.001884 0.00309071 0.00380416 0.00551039 0.0052082 0.00707811 -0.00293764 0.0110331 0.0118179 0.000155053 0.0029885 -0.0120471 -0.00528422 -0.0186305 -0.00389795 -0.01138 -0.0130287 -0.0114016 -0.00348096 0.00720399 -0.00393767 -0.00782219 -0.00889679 -0.0106665 -0.0241594 -0.0212916 -0.0261109 -0.0222356 -0.042137 1.1898)) (15.5487 0.0153078 0.0313768 #(0.0038797 -0.00898583 -0.00129375 0.0135476 0.00658722 0.0365788 0.00343157 -0.0308747 -0.0106992 -0.00551437 0.00041832 -0.0139702 -0.0154675 -0.0119801 -0.00961124 0.0151818 0.00235315 -0.00360607 -0.00300882 0.0133151 0.00953059 0.00235415 -1.91313e-005 0.00280704 0.0099642 0.0205634 0.00397632 0.00529698 0.023866 -0.00799138 0.0100504 0.0079582 -0.0250386 -0.029848 -0.0097943 -0.00418491 -0.0133331 -0.0233978 -0.00335522 0.0048438 0.0168547 0.0205229 -0.0161785 -0.0256227 -0.0427417 -0.0322054 -0.0493791 -0.0330071 -0.0981295 1.29245)) (19.0253 0.00596731 0.0177102 #(-0.0146168 -0.0100904 0.00214927 0.0184939 0.01049 0.0612408 -0.00438104 -0.0265871 -0.026429 0.00668405 0.0269023 -0.0263329 -0.0230587 -0.0429497 0.00384385 0.0294333 -0.00318107 -0.0136982 -0.00792112 0.0090845 0.0366004 -0.0174499 -0.00897093 -0.00784815 -0.00441435 0.0551205 -0.0163865 0.00471411 0.0446577 -0.0132054 0.0401863 0.0217569 -0.0372981 -0.0637524 -0.0140608 0.0379691 -0.012396 -0.0571539 -0.0387487 0.0285809 0.0555209 0.0533837 -0.020053 -0.00430533 -0.102708 -0.0554588 -0.0775484 0.00345876 -0.257812 1.45669)) (24.3361 0.00252815 0.0101924 #(-0.0257512 -0.0008726 0.0176086 0.0124685 -0.0534896 0.100064 0.0398205 -0.0701561 -0.0307596 0.00460567 0.0732452 -0.00591591 -0.0655563 -0.0244842 0.0128442 0.0333025 -0.0171489 -0.0529101 -0.0145168 -0.00558627 0.0716373 0.0169233 -0.00522713 0.00671804 -0.0615778 0.0634442 -0.0921752 0.00951979 0.120483 -0.077487 0.0914363 0.104565 -0.0653618 -0.089458 -0.0420491 0.0741933 -0.0368942 -0.0224205 -0.159684 0.0706304 0.0604807 0.156387 -0.0368354 0.00141878 -0.11703 -0.0250188 -0.215087 0.140998 -0.528956 1.65826)) (25.4722 0.00168582 0.00813527 #(-0.0361914 0.0503908 -0.052739 0.0874611 -0.161167 0.205034 -0.030822 -0.0297436 -0.0881124 0.0515133 0.029009 0.0911085 -0.133234 0.00447612 -0.0102752 0.0672411 -0.0743354 0.0278325 -0.088049 0.0254583 0.00378763 0.110739 -0.0335123 0.0437825 -0.111471 0.143021 -0.205556 0.0105061 0.178276 -0.139079 0.108138 0.100769 -0.0514441 -0.061891 -0.0335699 0.078663 -0.0342434 -0.0322647 -0.218112 0.133516 -0.053587 0.327015 -0.200594 0.23237 -0.331232 0.175309 -0.44634 0.403636 -0.874447 1.84189)) (24.4789 0.00660193 0.0164225 #(-0.0129511 0.000294328 -0.0197443 0.0228973 0.0144379 0.0576108 -0.00978518 -0.00793303 -0.0138883 -0.0222251 0.0319748 -0.0148723 -0.0204648 -0.0414119 -0.0116904 0.010987 -0.0113676 0.0117234 -0.00638076 0.0237907 0.020048 0.00399678 -0.00498899 -0.00973827 -0.00584135 0.0192609 -0.0220209 0.0192987 0.0427776 -0.0141488 0.0260689 0.053246 -0.0359298 -0.0407085 -0.0153808 0.000894089 -0.0255827 -0.0505249 -0.0252819 0.0272812 0.0597201 0.0367404 0.00457889 -0.0014007 -0.0717525 -0.0699291 -0.107446 -0.0187547 -0.27242 1.49509)) (26.2758 0.0176864 0.0259442 #(0.0033549 -0.00945348 0.0065972 0.011377 0.00754275 0.0138938 0.00853247 0.000314037 -0.00732074 -0.0137922 -0.008441 -0.0188535 -0.0266481 -0.0205979 0.00421144 0.0117094 0.0169971 -0.0179554 -0.00098244 0.035148 0.00857569 -0.0052743 -0.000887931 0.00311146 -0.00552477 0.00948484 -0.000848823 0.0254957 0.0295882 -0.0096005 0.019213 0.00984905 -0.0239854 -0.0251062 -0.0378088 -0.00656597 -0.0252241 -0.0322219 0.024789 0.0259035 0.0228412 0.0272441 -0.00713364 -0.0104557 -0.0465321 -0.0714479 -0.0841954 -0.0538046 -0.134946 1.37684)) (33.8769 0.00801222 0.0153789 #(-0.00258214 -0.00821759 0.0196898 -0.000392261 0.0140521 0.00440578 -0.0286329 0.000567736 0.0125327 0.00426797 -0.0066993 0.0334311 -0.0281124 -0.0422645 -0.0221943 0.0377913 -0.00618192 -0.0265775 -0.00448782 0.027992 0.0456436 0.00158737 -0.0145791 -0.00474223 -0.0115839 0.0136965 -0.0283794 0.032301 0.000935378 -0.0386639 0.0497046 0.0790239 -0.0338661 -0.0499984 -0.00571791 0.0381896 -0.0512542 -0.0879677 -0.0317509 0.0295627 0.0690141 0.0544617 0.0545729 0.0472211 -0.0781932 -0.090823 -0.112884 -0.113677 -0.42381 1.68183)) (47.5854 0.03461 0.0269689 #(0.00703504 0.0042176 -0.007448 0.00601103 0.00320568 0.00838487 0.0062723 -0.0120179 0.000336154 0.000458805 -0.00549983 -0.000896449 -0.0239517 -0.0277963 -0.00199031 0.00441657 0.0118858 -0.00555538 0.0186382 0.000599233 0.0253149 0.00947596 -0.0151058 -0.0109278 -0.00257833 0.0161187 -0.000843106 0.0151509 0.00682266 0.00837561 0.0212141 0.019091 -0.0166389 -0.0383569 -0.0276626 -0.0067535 -0.0278646 -0.0358582 -0.00485826 0.02398 0.0407189 0.0544763 0.0300379 -0.00650959 -0.0404744 -0.0715788 -0.100036 -0.13855 -0.218292 1.50233)) (67.1502 0.0503262 0.0273762 #(0.00163764 0.00156368 0.000896518 -0.00356924 0.0146311 0.0115155 0.000718131 -0.010003 -0.00103783 0.00202199 -0.00199034 -0.0161105 -0.0194743 -0.0104963 -0.00591896 0.0121449 0.00486055 -0.00401805 0.00316407 0.00376875 0.0156482 0.00483055 -0.00410957 -0.00432992 -0.00485066 0.0143753 0.00558336 0.0130507 0.00596937 0.00550279 0.0213288 0.00884339 -0.00423094 -0.0320471 -0.0225288 -0.0132194 -0.0288979 -0.0323811 -0.0196434 0.0287962 0.0448142 0.0421381 0.0389864 -0.00463365 -0.0331114 -0.0584344 -0.112601 -0.149007 -0.247096 1.5331)) (87.0259 0.146162 0.040982 #(0.0066813 0.0031666 0.00524609 -0.0082533 -0.00391559 0.0131647 0.0226346 0.00201689 -0.0300066 -0.0164448 0.00249676 0.012122 -0.0120514 -0.0290936 -0.00477291 0.0062677 0.00679358 0.00355967 0.0074764 0.00641204 0.00203213 -0.000103927 0.00208319 0.00592471 -0.00531212 -0.00286345 0.0194362 0.0235452 0.0145299 0.000873052 0.0170015 0.00926635 -0.0249864 -0.0345525 -0.026674 -0.0209155 -0.0204941 -0.0180144 -0.000742368 0.0206704 0.0347392 0.0281013 0.0231078 0.00568184 -0.0455544 -0.0687793 -0.0774324 -0.112311 -0.16092 1.413)) (103.805 0.0839127 0.0284317 #(0.0305305 -0.0232935 -0.0123279 -0.00539001 0.00241112 0.0181144 0.0198195 -0.0119952 -0.00946969 -0.00768942 0.0176179 0.0159392 -0.0270933 -0.0533804 -0.0238979 0.042285 0.0419821 -0.0130642 -0.02037 0.00470052 0.0265474 0.00800111 -0.0193407 -0.00539329 -0.00768145 -0.00352887 0.00818424 0.0306883 0.00191179 -0.011258 0.0201576 0.0424102 0.000582659 -0.0480861 -0.0335357 0.00238416 -0.000149278 -0.0762318 -0.0235003 0.0537691 0.0525345 0.0284459 0.0125174 0.044311 -0.0359816 -0.0879433 -0.0942918 -0.141744 -0.328099 1.59425)) (124.841 0.162496 0.036078 #(0.0154669 -9.72884e-006 -0.0101342 -0.00793859 0.0059567 0.0228617 0.00768918 -0.0107367 -0.0153092 -0.00690622 0.00137529 0.00756771 -0.0173113 -0.0348903 -0.015329 0.0277865 0.0313134 0.00105124 -0.0143057 -0.00667794 0.011448 0.00558312 -0.00253005 0.000195594 -0.00582771 0.00497205 0.0183721 0.0241788 0.0151434 -0.0120356 0.00834879 0.019273 -0.0189529 -0.0436641 -0.017064 0.0110478 -0.0142619 -0.0454921 -0.0275606 0.0195142 0.0430997 0.0479311 0.0369613 0.00241956 -0.049964 -0.0670036 -0.063226 -0.132439 -0.269048 1.51163)) (180.716 0.293325 0.040288 #(0.0258335 -0.0119538 -0.0193954 -0.00626257 0.0234294 0.0231874 0.0109882 -0.0140674 -0.0204807 -0.0175573 0.000633931 0.000397377 -0.011624 -0.022438 -0.0107618 0.0178291 0.0325036 0.0112156 -0.0171066 -0.00548084 0.00984786 -0.00170732 -0.00485124 -0.00691943 -0.00247698 0.0118085 0.0178137 0.0244233 0.0229053 0.003698 -0.0103266 -0.00441229 -0.00122563 -0.0243714 -0.0381239 -0.0309188 -0.0100181 -0.00337076 -0.00420997 0.0204227 0.0439681 0.0382338 0.00823855 -0.0138448 -0.0326542 -0.0661078 -0.097244 -0.115524 -0.154429 1.42031)) (234.118 0.205985 0.029662 #(0.0192157 -0.0031935 -0.00784433 -0.00677489 0.00286156 0.0114244 0.0199407 0.00873447 -0.0210833 -0.0382217 0.00335562 0.018978 -0.0148748 -0.0242473 -0.0051396 0.0205883 0.00181457 -0.0139292 0.0109887 0.0201683 0.00322887 -0.00941825 -0.00196576 0.0112985 -0.0102269 -0.0019795 0.0216591 0.0239712 0.00292886 -0.0126777 0.0229174 0.0228922 -0.0279371 -0.0544655 -0.0105665 0.0201515 -0.0232041 -0.0500812 -0.0122807 0.0286273 0.0377097 0.0333467 0.0362003 0.00682096 -0.0421918 -0.0623608 -0.0697533 -0.142768 -0.286476 1.53382)) (240.477 0.393671 0.0404604 #(0.0141351 -0.00376777 -0.0127499 0.00507208 0.0136482 0.0136646 0.00963351 -0.00969488 -0.0204225 -0.0195809 -0.00608936 0.0113476 -0.00348937 -0.0263493 -0.00860379 0.0196824 0.0270435 0.00279308 -0.0216122 -0.00311376 0.0167268 0.0026715 -0.00951989 -0.00655211 -0.000521916 0.00286717 0.0195184 0.0369098 0.0212964 -0.00938696 -0.00852238 0.0157752 -0.010538 -0.0511757 -0.0367333 -0.00701777 -0.00496757 -0.0218476 -0.00180121 0.0358277 0.0423497 0.0250602 0.0161893 -0.00886896 -0.0517459 -0.0757613 -0.0763744 -0.0986088 -0.163602 1.41088)) (208.983 0.298555 0.0377969 #(0.0164121 0.0048719 -0.0123277 -0.0082839 0.00553303 0.0215874 0.00343585 -0.0106931 -0.0143605 -0.0149133 -0.000867135 0.00882374 -0.00160873 -0.0229544 -0.0199348 0.0112933 0.0268215 0.00930974 -0.0129465 0.00684308 0.00823984 -0.00100629 -0.00874536 -0.0125536 0.0018266 0.00222032 0.0179517 0.0318532 0.0216125 -0.00395573 0.00757547 0.000995567 -0.0228842 -0.0368795 -0.018438 -0.00111154 -0.0249076 -0.0299492 0.000929623 0.034715 0.0335621 0.0270658 0.0181262 -0.000710647 -0.0431774 -0.0595626 -0.0734814 -0.128686 -0.215031 1.46608)) (169.872 0.295057 0.0416766 #(0.0319486 -0.0152698 -0.0178871 -0.00121978 0.0101795 0.0113419 0.00466058 -0.0163847 -0.00962441 -0.00255257 0.0034453 0.00333557 -0.00638092 -0.0185545 -0.0171695 0.00620859 0.027439 0.00889597 -0.00634335 0.00222882 0.00733991 0.00272018 -0.00324214 -0.00743471 -0.0202102 -0.0144455 0.0143375 0.0353734 0.03177 0.0180433 0.00470567 0.00350029 -0.0211588 -0.0400762 -0.0312031 -0.00502416 -0.0137467 -0.0287056 -0.00591527 0.0317417 0.0557392 0.030424 0.00295205 -0.00796262 -0.0331349 -0.0705161 -0.0935693 -0.117755 -0.17632 1.44112)) (198.736 0.583121 0.0541678 #(0.0239533 -0.0108176 -0.0102808 0.00564068 0.0150349 0.00994732 -0.00604523 -0.00984589 -0.0142772 -0.0121714 -0.00415331 -9.11199e-005 -0.00732939 -0.0188397 -0.00379378 0.0155464 0.0238681 0.0102193 -0.00649659 -0.0166725 -0.00159701 0.0168372 0.00555774 -0.0076568 -0.0152812 0.00621925 0.0304524 0.0302777 0.0179796 -7.1259e-005 -0.0110991 -0.0120554 -0.0207771 -0.0196221 -0.019649 -0.0276093 -0.0267218 -0.00462518 0.0217483 0.0300955 0.0254635 0.0179527 0.00908021 -0.0147737 -0.0434505 -0.0549393 -0.067622 -0.0980195 -0.11752 1.34832)) (235.893 0.196632 0.0288715 #(0.0304126 -0.0184424 -0.0165599 -0.000407823 0.00801631 0.0195737 0.0118165 -0.00905007 -0.0134561 -0.0135 -0.00394936 0.00567199 0.00352691 -0.0209869 -0.0335421 0.00501761 0.033716 0.0178405 0.00147093 -0.011718 -0.00133608 -0.00135017 0.00902945 0.00737444 -0.0033788 -0.00925621 -0.0209713 0.0180258 0.0548861 0.0175237 -0.0085279 -0.00515863 -0.0139746 -0.031351 -0.0115241 0.00705294 -0.0364894 -0.0527857 -0.0113735 0.0463322 0.0573369 0.0344311 0.019218 0.00187843 -0.0302693 -0.0656353 -0.0907326 -0.155003 -0.284321 1.55441)) (250.351 0.920652 0.0606419 #(0.0221283 -0.00175026 -0.00689412 0.000872708 0.00825388 0.00110956 -0.00632789 -0.0125022 -0.0104057 -0.00936074 -0.00616766 0.00522704 0.000860839 -0.00548061 -0.0014818 0.00943791 0.00798624 0.000154997 -0.00816161 -0.00716682 0.000403966 0.00149304 0.00596023 0.00691071 0.00706264 0.0106029 0.0144444 0.01869 0.0103569 -0.00377258 -0.00598677 -0.011182 -0.0229358 -0.0277385 -0.0171593 -0.00963866 -0.0130767 -0.00448601 0.01284 0.0232398 0.0183027 0.00684207 0.000345183 -0.017907 -0.0388241 -0.0491714 -0.0555385 -0.0671155 -0.080383 1.27961)) (265.144 0.37479 0.037597 #(0.0178487 0.0013791 -0.0116388 -0.00507206 0.0138357 0.0176418 0.0040927 -0.0179262 -0.017936 -0.00558455 0.00209339 -0.00600955 -0.011245 -0.00868085 -0.00205561 0.000295947 0.0125599 0.0156985 -0.00318278 -0.0132323 -0.000274777 0.00777626 -0.00183865 0.00266585 0.0125194 0.00603461 -0.00305746 0.0220627 0.0328774 0.00937883 -0.00296813 -0.0139498 -0.023661 -0.0265224 -0.0152562 -0.00981502 -0.0187505 -0.0249964 -0.00613381 0.0245956 0.0383716 0.0292479 -0.00259061 -0.00982094 -0.0297847 -0.0422148 -0.0701577 -0.115859 -0.177598 1.41175)) (250.53 0.735674 0.0541892 #(0.0238545 -0.00486949 -0.00173591 0.00252099 0.00404998 0.00118642 -0.00418862 -0.0123793 -0.0138166 -0.00838696 -0.00266911 -0.000717441 -0.00433613 -0.00087901 3.08753e-005 0.00695944 0.00812309 0.00161619 -0.00106495 -0.00230766 -0.00318343 -0.00717512 0.00130251 0.0107457 0.00679086 0.00860716 0.0173261 0.0173051 0.0100283 0.00988019 0.00145606 -0.0181773 -0.0255863 -0.0227028 -0.0191551 -0.0156616 -0.0149123 -0.00943028 0.00703709 0.0185155 0.0208948 0.0180594 0.00541843 -0.016114 -0.0379061 -0.0507604 -0.0578965 -0.0768728 -0.0909356 1.29924)) (197.598 0.485401 0.0495631 #(0.0248193 -0.00306678 -0.00667275 -0.0014236 0.0114491 0.0091926 -0.0023926 -0.0167224 -0.0201609 -0.00339142 -0.00311447 -0.00213343 -0.00661917 -0.00708419 0.00117074 0.0105285 0.010503 0.000885714 -0.00157855 -0.00449273 -0.0024985 -0.000379483 -0.0043849 0.0022342 0.0114984 0.0120889 0.0118227 0.0206663 0.0203387 0.01268 -0.00367646 -0.0148372 -0.0196786 -0.0256279 -0.0246386 -0.0201119 -0.0148319 -0.00916508 -0.00126804 0.0198383 0.0319355 0.0159117 0.00101828 -0.0089909 -0.0292361 -0.0476222 -0.0687146 -0.089934 -0.113823 1.33378)) (125.124 0.316632 0.0503045 #(0.0130568 -0.00225892 0.00216152 0.0102169 0.00996052 -0.00255912 -0.0097279 -0.0196243 -0.00656228 -0.000937932 -6.12063e-005 -0.000608431 -0.00526008 -0.00223335 0.00268855 0.00317693 0.00183598 0.00660908 0.00583385 -0.00116981 -0.00278075 -0.00730575 -0.0127456 -0.00600758 0.00295042 0.00742113 0.0148913 0.0264792 0.0296855 0.00264396 -0.00385496 -0.00327753 -0.023196 -0.0218689 -0.015055 -0.00831472 -0.0139174 -0.0128882 -0.000967953 0.012294 0.0210776 0.0214656 0.0105105 -0.0134574 -0.0314187 -0.0453388 -0.0664272 -0.107779 -0.148171 1.37876)) (71.37 0.227496 0.0564585 #(-0.0142429 0.012727 0.0152038 0.013247 0.0124478 0.00703828 -0.0126102 -0.0229412 -0.0168578 -0.00561364 0.00559436 0.00298623 -0.0049227 -0.00038521 -0.00127981 0.00423441 0.000763587 0.00976382 0.0108994 0.00630644 -0.00368733 -0.0148032 -0.023322 -0.0161698 -0.000889858 0.011531 0.0186532 0.0329139 0.0305486 0.00665483 -0.0125951 -0.0144017 -0.0205354 -0.0305956 -0.0183857 -0.000585577 0.0114074 0.00891327 0.00153785 0.00446643 0.00473343 0.015059 0.0101803 -0.0146464 -0.0351526 -0.0511088 -0.0647666 -0.0850186 -0.118079 1.33668)) (40.4377 0.0852366 0.0459113 #(-0.0335089 0.029908 0.0183897 0.0176984 0.0101193 0.00829117 -0.0170098 -0.0268985 -0.022606 0.00232026 0.0189546 -0.0045041 -0.00575308 -0.0100939 0.00425405 0.00177554 0.00632439 0.0070991 0.0135077 0.0172888 -0.00309632 -0.0159993 -0.0288205 -0.0254887 -0.0108957 0.00733041 0.0214328 0.0301479 0.0306404 0.0070994 -0.0123194 -0.025963 -0.0100594 -0.00332728 -0.00658321 -0.000959254 0.00177248 0.00985076 -0.0049481 -0.00260225 0.00144116 0.00476165 0.00342908 -0.0128849 -0.0221734 -0.0326228 -0.0534822 -0.0924536 -0.143692 1.34984)) (27.3832 0.070801 0.0508484 #(-0.0140748 0.0135211 0.0169284 0.0134048 0.00664361 -0.000844623 -0.025384 -0.00976012 0.00801802 0.00636203 -0.00289115 -0.0127367 0.000562452 0.00700169 0.00416503 0.00548033 0.00503239 0.00518513 0.00212309 -0.00811506 -0.0249022 -0.0165552 -0.00808011 -0.0032732 -0.00323997 0.0128592 0.0143886 0.0210239 0.0149843 -0.0102482 -0.00523455 -0.0127067 -0.00629629 -0.0118239 -0.00186732 0.00661671 0.000807708 0.0076143 -0.00151332 -0.0141276 0.000588052 0.013716 -0.00222398 -0.0188076 -0.0188453 -0.0187286 -0.0391334 -0.0564238 -0.0793644 1.23514)) (30.7375 0.040934 0.0364929 #(-0.0243691 0.00812592 0.015261 0.01097 0.0205355 0.0101767 -0.0151796 -0.0251579 0.00184063 0.0088331 0.00252205 0.000583772 -0.00157531 -0.000798763 0.00905121 0.00117476 0.00355867 -0.00185548 0.00468458 -0.00729399 -0.0289016 -0.0190386 0.00930854 -0.00472978 -0.0131431 -0.00543118 0.00841419 0.0272355 0.0256443 -0.00636553 -0.00757628 -0.00558504 -0.000516058 -0.00121443 -0.0138289 0.00110727 0.00668947 0.00434654 -0.00919808 -0.0198922 0.00235468 0.0144602 -0.000975259 -0.0245124 -0.0246625 -0.015985 -0.0371288 -0.0397989 -0.0669062 1.22136)) (42.0859 0.00626129 0.0121973 #(-0.0734655 0.0296172 0.013634 0.0452539 0.00702914 0.057469 -0.0232954 -0.0727147 -0.0229838 0.0545064 0.022556 -0.0378221 -0.0116609 -0.0131154 0.0381253 0.0259823 -0.0219215 -0.0248628 0.0469329 -0.00591986 0.0161304 -0.0248895 -0.0474258 -0.0134104 -0.011063 0.0414246 -0.0607445 0.0508991 0.0641952 0.00526139 -0.0600509 0.00150282 0.00627574 -0.070137 0.0242186 0.0169948 0.0408282 0.0438345 -0.0204922 -0.0610643 -0.0804496 0.0966152 0.0588874 -0.0136561 -0.0697122 0.00834575 -0.047428 -0.0855743 -0.478215 1.63444)) (48.3822 0.0133138 0.0165886 #(-0.0991241 0.0620696 0.0256428 0.0325504 0.030601 0.0200286 -0.0346818 -0.0543453 -0.000353481 0.0292389 0.0225596 -0.0231814 -0.0230041 -0.00406665 0.0324386 0.00882869 -0.0235801 0.0419879 0.00354304 -0.0088214 0.00179125 -0.0386059 -0.020162 -0.0161291 -0.0274193 0.0200131 0.00125343 0.0450822 0.0571638 -0.0335057 -0.0273933 -0.0201817 -0.0220575 -0.0085605 -0.000251926 0.0202286 0.0402841 0.0305421 -0.0148375 -0.0251732 -0.04472 0.0420287 0.0255921 -0.0131808 -0.0380019 -0.0228509 -0.0479855 -0.104387 -0.277699 1.47947)) (52.3586 0.0659523 0.0354912 #(-0.0350294 0.0226496 0.0266707 0.0151374 0.00559978 -0.00178336 -0.0131273 -0.00792491 0.00702189 0.00803718 0.000224972 -0.0104286 -0.0107735 0.000890825 0.000619345 0.00514007 -0.000477151 0.00445113 0.0122391 0.00292333 -0.0091859 -0.0264601 -0.0178257 -0.00867586 0.00144957 0.00389939 -0.00103973 0.00526759 0.0114127 0.00266532 -0.0114983 -0.0129203 -0.0101913 0.00682779 0.023871 0.0120872 0.00875099 0.0033859 -0.00336156 -0.00727741 -0.00798061 0.00279848 -0.00798744 -0.0160221 -0.02748 -0.0249909 -0.0413176 -0.0503363 -0.0665837 1.23408)) (57.2864 0.0998289 0.0417448 #(-0.0107891 0.0182459 0.0133387 0.00654529 0.00351746 -0.0028236 -0.00652551 -0.00276973 0.00189705 0.00363537 -0.00543967 -0.00428984 -4.74181e-005 0.00728144 -0.000418819 -0.00318095 0.00296512 0.00149376 0.00209253 -0.0105876 -0.0105755 -0.00732988 -0.0124828 -0.00540931 -0.00364074 0.00253872 -0.000591894 0.0020125 0.00672111 -0.0103777 -0.00817489 -0.00341224 0.00892754 0.00393065 0.00183264 0.0170761 0.0103609 0.0093558 -0.00221637 -0.00689539 -0.00883095 -0.00260063 -0.00561736 -0.0152408 -0.0198652 -0.0251051 -0.0359384 -0.043327 -0.0516084 1.19939)) (63.2886 0.0659521 0.0322813 #(-0.0395131 0.0278336 0.0226114 0.0208169 0.00156559 -0.00586198 -0.00373168 -0.0129797 -0.000442788 0.00591266 0.00384389 -0.00649693 -0.000432298 0.00820201 0.00205019 -0.00693928 -0.00561469 0.00651516 0.00426545 -0.00287469 -0.0195372 -0.0148713 -0.00282639 -0.00135895 0.00476877 0.00385195 -0.00114983 0.00160519 0.0150339 -0.00888809 -0.0157333 -0.00871617 -0.00192295 0.00638566 0.00653376 0.0147419 0.00964909 0.00830972 -0.00471322 -0.00721979 -0.00854983 -0.00297041 0.000582071 -0.00321452 -0.0251575 -0.0448269 -0.0465566 -0.0617166 -0.0814745 1.26877)) (68.2143 0.127344 0.0432067 #(-0.00650372 0.0166661 0.0110006 0.0046084 -0.000191608 -0.000655383 -0.0075612 -0.00289214 0.00188358 0.00579054 0.000329202 -0.00681358 -0.00225101 -0.000353251 0.0031628 -0.0053415 -0.000525401 0.00656196 0.00272409 0.00256422 -0.0160209 -0.0140322 -0.00207772 -0.00301927 -0.000189949 -0.00236457 0.00311191 0.00706533 -0.000524762 -0.00984277 -0.0108244 -0.00768298 0.000888997 0.00214318 0.0071796 0.0118653 0.0159322 0.00963205 -0.00200409 -0.0107815 -0.00688397 0.000662548 0.00124322 -0.0216095 -0.024252 -0.0275861 -0.0290191 -0.0455658 -0.0594961 1.20854)) (74.5766 0.00960274 0.0113474 #(-0.0930925 0.0474147 0.0783675 0.00847634 -0.0083235 0.0389507 -0.0156469 -0.0811489 -0.00383005 0.0271399 0.0027488 -0.0036905 -0.0380551 0.0424861 0.036423 -0.0258928 -0.0261861 0.00709007 0.0423739 0.0478494 -0.0457433 -0.0682701 -0.0230027 0.0330979 0.0021217 -0.00664132 -0.0268997 0.0548632 0.100473 -0.0711387 -0.0110561 -0.0158289 -0.0476065 -0.0351137 0.00284219 0.0323319 0.0313311 0.0736398 0.0142766 -0.10177 -0.0582263 0.0770375 0.0914699 0.0357695 -0.12508 -0.0345359 -0.0237482 -0.0585581 -0.687455 1.80702)) (89.851 0.0668036 0.0272671 #(-0.047951 0.0391961 0.0312392 0.0264315 0.0152606 -0.0229461 -0.0203805 -0.0182092 -0.00178092 0.00435629 -0.00460121 -0.00718773 -0.00219992 0.00637422 0.00988643 0.00875952 0.00355863 0.0092556 -0.00376029 -0.00369781 -0.0084366 -0.0248106 -0.00997018 -0.00992863 -0.00298569 0.00552284 0.0193635 0.0324098 0.00560115 -0.0147652 -0.0174123 -0.0176175 -0.017063 -0.00976483 0.00645685 0.0115746 0.0243375 0.0212918 0.0038104 -0.00756 0.00845826 0.00991446 0.00809276 -0.000765567 -0.0407473 -0.0481121 -0.0785197 -0.118162 -0.175228 1.42139)) (111.491 0.0612596 0.0234406 #(-0.071768 0.0568083 0.0427606 0.0216603 -0.00175519 0.00236969 -0.0168044 -0.027955 -0.00413897 0.00759891 0.00307185 -0.0137154 -0.021489 0.00188837 0.0194342 0.0167963 0.0109949 -0.00132022 0.0129203 0.00409717 -0.016515 -0.035451 -0.0211164 -0.0147696 -0.00623048 0.017651 0.0231703 0.0352329 0.0277801 -0.0201851 -0.0270755 -0.0333369 -0.0135395 -0.0048966 -0.00213377 0.01776 0.0243864 0.0268 0.00479255 -0.0136091 0.00196506 0.0109521 0.0263541 0.00149658 -0.0351393 -0.0414662 -0.0804536 -0.15343 -0.262886 1.52039)) (131.563 0.0385887 0.0171263 #(-0.0518673 0.0134846 0.0263128 0.0468026 0.024454 0.0220736 -0.0400596 -0.0676488 -0.0114445 0.0413724 0.0448596 -0.0289181 -0.0607654 0.00419211 0.039212 0.0198165 -0.0106986 -0.00978497 0.0268256 0.0153281 -0.014289 -0.0258232 -0.021492 0.00140582 -0.0194537 -0.0176859 0.00346931 0.0616223 0.0476843 0.000242224 -0.0396149 -0.0480542 -0.0287999 0.00734256 0.00921102 0.0219239 0.0281868 0.0214498 0.0045841 -0.0526773 -0.0290021 0.0477786 0.066508 -0.00482082 -0.060896 0.00723903 0.00689539 -0.17291 -0.656903 1.81153)) (151.886 0.102626 0.0259939 #(-0.070856 0.0486957 0.0480601 0.0368429 0.0182886 -0.00829156 -0.0513057 -0.0475156 -0.00697538 0.0443591 0.0264049 -0.0186967 -0.046636 -0.00991082 0.0358113 0.0296259 -0.00965236 -0.00183771 0.0116684 0.0166791 -0.0164862 -0.0397139 -0.0181811 -0.0084272 -0.01239 -0.000257272 0.0267701 0.0470878 0.0342028 -0.0154802 -0.0370322 -0.0415501 -0.0235126 1.97047e-005 0.0225005 0.0265028 0.0239742 0.0125777 -0.00895148 -0.0232263 -0.000947537 0.0428729 0.0258008 -0.0298816 -0.037036 -0.00471161 -0.0249833 -0.174155 -0.397768 1.60503)) (165.11 0.169794 0.0320682 #(-0.0409658 0.0441689 0.0293712 0.0214998 0.0154116 -0.00248447 -0.0422952 -0.0478381 -0.00388453 0.0270632 0.0266513 -0.00557179 -0.022944 -0.0116277 0.0116475 0.0182246 0.00737678 -0.00598205 -0.00128794 0.00345216 -0.00394256 -0.00695017 -0.0256291 -0.0322332 -0.012631 0.0176517 0.0309905 0.0230604 0.0224319 -0.0106256 -0.0268479 -0.0207674 -0.00587152 -0.00570336 -0.00197812 0.0122906 0.0205968 0.031643 0.00252642 -0.0332331 -0.00542228 0.0405915 0.0309338 -0.0143715 -0.0384462 -0.0185082 -0.0347614 -0.166035 -0.349634 1.55773)) (177.174 0.178624 0.0317519 #(-0.0375195 0.0292643 0.0300942 0.0307154 0.0193178 -0.00509529 -0.0345436 -0.0373165 -0.0172528 0.0236766 0.0201161 -0.0183973 -0.0276741 0.00996924 0.0330329 0.0152227 -0.00951397 -0.0122329 -0.00113485 0.0194899 -0.0119267 -0.0292984 -0.015638 -0.0142287 -0.0148578 -0.000859865 0.0260062 0.0534978 0.0402742 -0.0219816 -0.040437 -0.0341774 -0.0049463 -0.0116811 -0.0123897 0.0190348 0.0504628 0.0449273 -0.00894907 -0.0495895 -0.0187866 0.0407222 0.046073 -0.00801632 -0.0446076 -0.0182126 -0.03077 -0.167466 -0.369669 1.57394)) (179.99 0.221245 0.03506 #(-0.037004 0.0260371 0.0372679 0.0497295 0.0157299 -0.0244911 -0.0537488 -0.0510671 0.00512908 0.05199 0.0203676 -0.0338469 -0.0238147 0.0127183 0.0230843 0.00442021 -0.0115414 0.00421587 0.0188467 -0.00272606 -0.0256457 -0.0344065 -0.0104499 -0.00267908 -0.00204974 0.00352165 0.02398 0.0343543 0.0255179 -0.0152773 -0.0303301 -0.0266642 -0.0139434 -0.00355751 -0.0084824 0.0107571 0.0423518 0.0526576 -0.00233367 -0.0445417 -0.0249914 0.0319504 0.0506834 -0.0160456 -0.0561795 -0.0084321 -0.00738221 -0.153557 -0.379863 1.55632)) (166.887 0.252327 0.038884 #(-0.0419053 0.0366535 0.0498127 0.0359369 0.00208074 -0.0250268 -0.0524974 -0.0402762 0.00682585 0.0354895 0.0297739 -0.0147708 -0.0304251 -0.00374599 0.0183841 0.0130221 0.00121661 0.00411938 0.00494517 0.000507366 -0.0263356 -0.0463632 -0.0168647 0.0149596 0.0144969 0.00307392 0.0082568 0.0288554 0.0295293 -0.00737698 -0.0363064 -0.0244228 -0.0110509 -0.00137184 -0.01354 0.00159516 0.0392046 0.0550105 0.0155153 -0.0394186 -0.0271276 0.0202588 0.0342747 -0.0055672 -0.0407041 -0.0119139 -0.0198007 -0.157004 -0.344951 1.53129)) (164.943 0.182476 0.0332611 #(-0.0614847 0.034366 0.0618075 0.0440773 0.010115 -0.0176925 -0.0502932 -0.0698586 -0.0117179 0.0583499 0.0553452 -0.0141319 -0.052825 -0.00920142 0.0291995 0.0159293 -0.00586749 -0.00306322 0.0226316 0.00427445 -0.0340741 -0.0437776 -0.0123615 0.00698813 0.00470649 0.00949797 0.00789906 0.0335011 0.0219034 -0.00266724 -0.0265675 -0.030155 -0.0143053 -0.0093868 -0.00158663 0.0163901 0.0203923 0.0417646 0.0187303 -0.0392964 -0.037276 0.0437944 0.0678762 -0.016769 -0.0789091 -0.0197703 0.0398731 -0.156601 -0.511722 1.65878)) (176.99 0.261053 0.0384053 #(-0.06 0.056536 0.045999 0.0280942 0.0117416 -0.0124533 -0.0449422 -0.0463361 -0.00718186 0.0308653 0.0198448 -0.0192072 -0.0242862 0.0065568 0.031481 0.0162032 -0.00801501 -0.00216827 0.0134013 -0.00587761 -0.0383848 -0.0362193 -0.0129257 0.0157857 0.00474063 -0.00184301 0.0202611 0.041013 0.0198278 -0.0191734 -0.029208 -0.0221024 -0.0116136 -0.0121702 -0.00611537 0.0173498 0.0404119 0.0315245 -0.00593292 -0.0237962 -0.000431722 0.0439062 0.0334822 -0.0297822 -0.0607389 -0.0164012 -0.00830834 -0.154607 -0.362478 1.54998)) (176.048 0.159462 0.0300963 #(-0.0377232 0.0103334 0.036835 0.0488153 0.0179723 -0.00819109 -0.0460628 -0.0619188 -0.00111458 0.0446256 0.032363 -0.00836746 -0.0360712 -0.00850298 0.0216202 0.0175984 -0.000914048 -0.0173185 0.00126597 0.0264074 -0.00629105 -0.043736 -0.017196 0.00494882 -0.000320422 -0.012511 0.00430157 0.0466093 0.0305521 -0.0031329 -0.0376142 -0.024873 0.00750779 -0.012678 -0.0104912 0.00134055 0.0376222 0.0412994 -0.0218273 -0.0452171 -0.0128663 0.072725 0.0680508 -0.0173601 -0.0684261 -0.0212582 0.0188153 -0.175166 -0.561992 1.72452)) (171.946 0.2352 0.0369847 #(-0.0512015 0.0329072 0.0503361 0.0280294 0.00184622 -0.0107644 -0.0348259 -0.0337681 0.00209173 0.0265416 0.028044 -0.0189349 -0.0371111 -0.000802031 0.0279831 0.0122725 -0.00874739 -0.00112342 0.0180879 0.000223799 -0.0259366 -0.0351892 -0.00449204 0.00197593 -0.0162875 -0.011366 0.0181628 0.0541492 0.0395807 -0.0167336 -0.0418708 -0.0160073 -0.00774302 -0.00128406 -0.00712924 -0.00703709 0.0178146 0.0397532 0.00726889 -0.0174794 -0.00498909 0.0427668 0.0408804 -0.0175914 -0.0525046 -0.0244365 -0.014682 -0.171468 -0.395718 1.59284)) (185.859 0.163683 0.0296764 #(-0.0468658 0.0116617 0.0555765 0.036102 0.0116869 -0.0136073 -0.0419413 -0.0311445 -0.015847 0.0536179 0.0374088 -0.0318291 -0.0562696 -0.0204646 0.0520056 0.0366832 -0.00267281 -0.0268453 0.00390152 0.0151844 -0.0141306 -0.026449 -0.00214409 -0.00146158 -0.0202671 -0.0306729 0.00986482 0.0542944 0.0595679 0.00293662 -0.0374089 -0.0316308 -0.0279362 -0.00383883 -0.00461755 -0.00381387 0.0302674 0.0462364 0.00234255 -0.0420869 -0.0176493 0.0621579 0.0781717 -0.0259631 -0.0837177 -0.0197173 0.0222038 -0.172749 -0.543442 1.71216)) (211.324 0.258974 0.0350069 #(-0.0303184 0.0212199 0.0351346 0.0323836 0.0108293 -0.0194528 -0.0440712 -0.0258231 0.0179244 0.0423101 0.00743043 -0.040367 -0.0363898 0.0067014 0.0337238 0.0109171 -0.0145224 -0.00777405 0.0187512 0.010748 -0.0157507 -0.020169 -0.00503133 -0.00636303 -0.0319918 -0.0279937 0.0172805 0.0607111 0.0519986 -0.00764891 -0.0419867 -0.0321224 0.0100713 0.00236086 -0.0196657 -0.0170583 0.0223451 0.0362193 0.000122523 -0.0184589 0.0140273 0.0644042 0.0497302 -0.0380606 -0.0744375 -0.0264989 -0.0209174 -0.164711 -0.384479 1.59087)) (230.546 0.254813 0.0332454 #(-0.0214216 0.00872379 0.0339929 0.0315809 0.0174031 -0.0232373 -0.0489485 -0.0241287 0.0209643 0.0453702 0.0190406 -0.0440306 -0.0441669 -0.00157853 0.0268724 0.0234296 -0.000401617 -0.0057701 0.000344993 -0.0054568 -0.0178071 0.0024068 0.0155485 0.000746876 -0.0375718 -0.0484998 0.00853225 0.0571187 0.0551759 -0.0142224 -0.0451274 -0.0277836 0.0263546 0.0402985 -0.0197452 -0.0401687 -0.00351748 0.0313089 0.00705256 -0.0369839 -0.00653953 0.0851077 0.0978434 -0.0156217 -0.102129 -0.0527658 0.00792703 -0.158984 -0.494505 1.67382)) (251.512 0.22152 0.0296775 #(0.00271906 -0.0125085 0.0301646 0.0306547 0.00855251 -0.0179234 -0.0350287 -0.0305762 0.00779454 0.053486 0.0394365 -0.0393962 -0.0650717 -0.0198502 0.0326874 0.039916 -0.0010092 -0.0179188 0.00205602 -0.00398159 -0.00877683 0.0106262 0.0187416 -0.0120917 -0.0564597 -0.0545574 0.0119312 0.0765 0.0649359 -0.0149672 -0.0521681 -0.0268912 0.0228738 0.0277597 -0.00505434 -0.0391086 -0.000955081 0.0337932 -0.00277864 -0.0493297 -0.0119853 0.100552 0.124828 -0.0159932 -0.127861 -0.0612138 0.0295559 -0.144989 -0.555044 1.70991)) (254.186 0.155867 0.0247629 #(0.011018 -0.035849 0.0315776 0.0392745 0.01848 -0.0184897 -0.0290829 -0.049739 -0.000114797 0.0517803 0.04403 -0.0251357 -0.0530782 -0.0079027 0.0214459 0.0319004 -0.0185972 -0.0210457 -0.00556451 0.0118538 0.000887009 0.0257463 0.0265477 -0.0284303 -0.0724463 -0.0721507 0.0469847 0.0785231 0.069301 -0.026447 -0.064972 -0.032767 0.00653783 0.0563972 0.0303594 -0.0350536 -0.0475477 0.0379776 0.00958391 -0.0490296 -0.0492565 0.0859668 0.161288 -0.000991608 -0.140484 -0.0439296 0.0763862 -0.147115 -0.750695 1.84834)) (225.37 0.0803291 0.0188794 #(0.0290101 -0.0687017 0.0407707 0.0383633 -0.0152389 0.00254714 0.0114647 -0.0328925 -0.021924 0.00257726 0.0623568 -0.00416147 -0.0660898 -0.0300196 0.0572706 0.0552422 -0.027837 -0.0653128 0.00149151 0.0264922 -0.00315019 0.0193053 0.0486365 0.00427569 -0.0987687 -0.0861261 0.00501995 0.0945006 0.109231 -0.0131216 -0.077788 -0.0512939 -0.00858637 0.0620822 0.041699 -0.0369608 -0.0380424 0.0273551 0.0409665 -0.0644617 -0.0854918 0.0805598 0.178136 0.0300991 -0.186435 -0.0584791 0.205418 -0.075875 -1.13303 2.07226)) (198.485 0.0417265 0.0144991 #(0.0414603 -0.0623938 0.0061811 0.0288222 -0.0158102 0.0252802 0.00307337 -0.00304176 0.00367747 -0.0489033 0.0357009 0.0204158 -0.0552591 -0.0256414 0.0346049 0.0958179 -0.0284009 -0.100873 -0.00722169 0.0205522 0.0295442 0.033256 0.0421494 0.00768483 -0.110423 -0.0846969 -0.0244979 0.0889337 0.157045 0.00102777 -0.0813333 -0.0900497 -0.0138341 0.0341514 0.0721558 0.00377355 -0.033424 0.010766 0.0245269 -0.0515001 -0.119286 0.0335791 0.213235 0.125951 -0.204453 -0.179761 0.270221 0.202002 -1.65027 2.32378)) (171.548 0.1509 0.0296587 #(0.0250778 -0.0426171 0.00843798 0.0396997 0.0226322 -0.0146932 -0.0283293 -0.01936 0.0069322 0.0354412 0.0250028 -0.0357834 -0.0414478 -0.0136723 0.0292158 0.020287 -0.00117164 -0.00726955 -0.00706735 0.000159039 -0.00407658 0.0190887 0.0257392 -0.0278326 -0.0682253 -0.0552612 0.0202806 0.0931883 0.0784599 -0.037487 -0.082894 -0.0424946 0.0518775 0.0627942 0.000169138 -0.0458972 -0.0190695 0.0107115 -0.00659794 -0.0314802 0.00511231 0.0991288 0.0788463 -0.0108271 -0.0699992 -0.0146887 -0.00873203 -0.228192 -0.553044 1.75651)) (138.651 0.0571929 0.02031 #(0.0213914 -0.0306978 0.00848927 0.0130779 0.00721775 0.00427365 0.00961346 -0.0314829 -0.018867 0.036295 0.03503 -0.0305203 -0.0463152 -0.0107846 0.0382213 0.0409777 -0.0373991 -0.0384969 0.0128019 0.00295524 0.0157249 0.0419502 0.0294107 -0.0318793 -0.11091 -0.0681277 0.0179675 0.131618 0.114326 -0.0427296 -0.109902 -0.0736138 0.0191553 0.091943 0.0543933 -0.0340794 -0.0436619 0.00746334 -0.0066161 -0.0679531 -0.0238454 0.0924077 0.161235 0.0122723 -0.139703 -0.0326624 0.115233 -0.166794 -0.931623 1.99133)) (113.308 0.193753 0.0413518 #(-0.0270571 0.018724 0.0316812 0.0297654 0.00202789 -0.0163134 -0.0290023 -0.0123064 0.0176842 0.0233915 -0.00357253 -0.0336344 -0.0271282 0.00653117 0.0284495 0.0179925 -0.004167 -0.0157728 -0.00964692 0.000267421 0.00122534 0.0146035 0.00149512 -0.0396562 -0.058053 -0.0255875 0.0451789 0.0754793 0.044493 -0.0379303 -0.0597916 -0.015322 0.0420665 0.0354546 -0.0132543 -0.0383832 -0.0285421 0.000937585 0.0195054 0.0265873 0.0502106 0.0593278 0.0136192 -0.0502636 -0.0466451 -0.0180557 -0.0524014 -0.164365 -0.318595 1.53476)) (103.037 0.0623253 0.0245944 #(-0.00724495 -0.00593484 0.0107629 0.0261896 0.0129414 0.00340164 -0.0251773 -0.0270683 0.00747135 0.0385192 0.018441 -0.0377958 -0.0304305 0.00450653 0.0229534 0.00567204 -0.0264594 -0.0176736 0.000876183 0.0471199 0.0172663 0.0124283 0.00241253 -0.0617734 -0.103682 -0.0406255 0.0578767 0.121063 0.0822661 -0.0454017 -0.102194 -0.042812 0.0321046 0.0833275 0.00602523 -0.0478943 -0.043304 0.000262387 0.00598665 -0.00374976 0.0385322 0.079333 0.0654235 -0.0354309 -0.092082 0.00159915 0.0131218 -0.204327 -0.571633 1.75234)) (92.5577 0.120027 0.0360108 #(-0.0398489 0.0324612 0.0367935 0.0220619 0.00704562 -0.0272926 -0.0200099 -0.00659618 0.0169783 0.015708 -0.00599385 -0.0153675 -0.0128987 0.0082064 0.0102226 -0.000522355 -0.00199441 -0.00674596 -0.00220103 -0.00689017 -0.00809083 0.00336812 -0.0126411 -0.0439452 -0.04063 0.00361202 0.0505336 0.0555444 0.02238 -0.0310165 -0.038806 -0.00364963 0.0180895 0.00954 -0.00503501 -0.0195219 -0.0205427 0.00318622 0.0185383 0.0345637 0.0376351 0.0372337 0.00566722 -0.0260961 -0.0314731 -0.0229805 -0.0612615 -0.148592 -0.24421 1.45165)) (66.5989 0.0842179 0.0355606 #(-0.0384904 0.0427509 0.0324356 0.0194716 -0.00585732 -0.0144022 -0.0118444 -0.00525952 0.0111836 0.00537657 -0.00948216 -0.00957872 -0.000929858 0.00996204 0.00650146 0.00151737 -0.00610687 -0.00883977 -0.0111524 -0.00821151 -0.0121669 -0.00254634 -0.0339117 -0.0355781 -0.013952 0.0280202 0.0436449 0.0292268 0.00874941 -0.0239858 -0.0194654 -0.00890681 0.0037191 -0.00475951 -0.00518569 -0.00236431 0.00776458 0.0118334 0.0107269 0.0178917 0.0261446 0.0384696 0.0138593 -0.0230752 -0.043364 -0.0319342 -0.0459236 -0.112816 -0.180369 1.35766)) (42.7254 0.0264534 0.0248827 #(-0.0413135 0.0213958 0.036281 0.0248983 -0.0151715 -0.0222269 -0.00567853 0.00505671 0.017208 0.024368 -0.0203921 -0.0162792 0.000440382 0.0151094 0.0109901 -0.000613158 -0.00984668 -0.00906093 -0.00789341 0.00260445 0.0124987 -0.0123556 -0.0457957 -0.0562666 -0.0106157 0.0486385 0.0540115 0.0360568 -0.00307563 -0.0466828 -0.0306841 0.00913136 0.0174993 0.00528422 -0.0273256 -0.0166686 0.00261137 0.0230377 0.0120899 -0.00600584 0.0223933 0.0459099 0.00977329 -0.0223494 -0.0479412 -0.0230021 -0.0404154 -0.102133 -0.204478 1.38436)) (30.9113 0.0516676 0.0408837 #(-0.014936 0.00941983 0.0118751 0.000575508 0.00581291 -0.00413739 -0.012136 0.0103523 0.00720992 0.0100773 -0.000124851 -0.00765056 0.00255218 0.000894253 0.00544408 0.000794387 -0.00215897 -0.00898489 -0.0117924 -0.00653947 -0.0064785 -0.00840759 -0.0105823 -0.0100678 0.000175767 0.0102663 0.00786819 0.0237505 -0.00215373 -0.0266525 -0.00900966 -0.00600343 -0.0028658 -0.00373159 -0.00238924 -0.00278976 -0.00429102 -0.00212087 0.00253061 0.0127614 0.0230914 0.0151189 0.00146143 -0.0117057 -0.00462498 -0.00318648 -0.0265484 -0.0369997 -0.0675645 1.14867)) (15.3693 0.00836665 0.0233319 #(-0.0341159 0.00806944 0.0216334 0.0174292 -0.0149921 0.016248 -0.0180928 -0.00306738 0.0350942 0.00513288 -0.00769301 0.00579646 -0.0107035 0.0131971 0.00589453 -0.00674269 0.00261838 -0.00786856 -0.00176616 0.00564664 -0.0345646 -0.0240044 -0.0148234 -0.0133658 -0.00412353 0.0369617 0.00196105 0.0368174 0.00564198 -0.0501549 -0.0297051 0.0178704 0.0210161 -0.0155626 -0.00837293 -0.0178571 0.00812323 0.00816448 0.00151141 0.0221456 -0.00390799 0.026406 0.0064334 -0.00797861 -0.0261832 0.013857 -0.0837799 -0.0591936 -0.120175 1.27127)) (7.76696 0.0131245 0.041107 #(-0.0123117 0.00617644 -0.00098044 0.00751582 -0.00251782 -0.00337365 -0.00106648 -0.00202962 0.024234 0.000865013 -0.000377017 0.00388929 -0.00333191 0.0133695 -0.00022004 -0.00378028 -0.00320862 -0.00759729 0.010062 -0.0256383 -0.0192849 -0.0214377 -0.0114302 -0.00124626 0.00155824 0.0193932 0.00236924 0.0225305 0.00325289 -0.026002 -0.0156565 0.0123504 0.013013 -0.00652565 -0.00493443 -0.0110295 -0.00472477 0.0120849 0.0080524 0.00918786 -0.00908903 0.0273415 -0.00444183 -0.0233399 -0.0047778 -0.00719849 -0.0426428 -0.018549 -0.0650151 1.15688)) (8.89632 0.0142545 0.0400286 #(-0.00575181 0.0168131 -0.000191827 -0.023498 -0.00423681 0.025755 -0.0183111 -0.00376236 0.0252077 0.008183 -0.0122062 -0.003721 0.00288939 0.0148372 0.00886276 0.00423061 -0.00963574 0.000873132 0.00541097 -0.0280967 -0.00998672 -0.0238806 -0.0217161 -0.00753574 0.000230236 0.0280799 -0.00512027 0.00849866 0.0322065 -0.0343016 -0.00927757 0.00120511 0.0135002 -0.00237087 -0.0093355 -0.00156968 -0.00792312 0.012794 0.00838747 -0.0119611 0.00605868 -0.00193377 0.0117903 0.00816965 -0.0157005 -0.000300004 -0.0367019 -0.0246368 -0.0709357 1.15223)) (9.78194 0.0170927 0.0418016 #(-0.0124638 0.0024989 -0.00185738 -0.00369259 -0.00329147 0.0015451 0.00184027 0.00970003 0.0141567 0.0120678 0.00775671 -0.00277263 0.00105104 0.000310846 0.00513042 -0.0141369 -0.008812 0.00521768 -0.00206552 -0.00604551 -0.0120649 -0.0176494 -0.0204137 -0.0115251 0.00627893 0.0162767 0.0108663 0.00560173 0.00467505 -0.02242 -0.0112209 0.000456198 0.00829053 2.30481e-005 0.00913467 -0.00846952 0.00517986 0.00864013 -0.00133154 0.00581594 -0.00610526 0.00869507 0.00727336 -0.00365842 -0.0143366 -0.0169279 -0.0336561 -0.0311221 -0.071088 1.16895)) (11.5445 0.0160741 0.0373143 #(-0.0249007 -0.00275895 -0.000517276 0.00756758 -0.00172192 0.0176724 0.00486407 0.00102775 0.0190812 0.027876 -0.00029893 -0.00443258 -0.00532617 -0.0133783 -0.00615458 -0.00822798 -0.00903328 0.00488343 0.0122464 -0.0119956 -0.0122127 -0.0164293 -0.0183456 -0.00082874 -0.00101657 0.00939199 0.0092591 0.0164931 -0.0114048 -0.0252425 -0.0161846 -0.00699262 0.00668263 0.0180297 0.000800448 0.00638066 0.00681553 0.0168308 0.0103385 -0.00081722 -0.00148622 0.00392006 -0.00755191 -0.0011792 -0.0241647 -0.0123012 -0.0393747 -0.0402423 -0.0754633 1.19146)) (13.3295 0.0127553 0.0309342 #(-0.0231698 0.0191559 -0.0139377 0.0092944 0.0121271 -0.000232179 -0.0124583 0.0134314 0.0164421 0.024357 -7.36386e-005 -0.0199401 -0.00337023 0.0151218 -0.00455778 -0.0115682 -0.0172743 0.000976708 0.017724 -0.0074562 -0.0285266 -0.0151716 -0.030822 0.00497904 0.00790638 0.0099445 0.0162362 0.0264739 0.0175367 -0.0501894 -0.0343044 -0.00901378 0.014952 0.0105903 -0.0101648 -0.000755211 0.0171476 0.0293293 0.00838466 -0.0102206 0.00315026 0.0306831 -0.00269206 0.00531439 -0.0326658 -0.0252288 -0.0474296 -0.0704353 -0.143764 1.28812)) (15.3429 0.0120405 0.0280135 #(-0.0309064 0.0271264 0.0147487 0.00498133 0.00106183 0.0147637 -0.040844 -0.0169095 0.0389369 0.0194572 -0.00221378 -0.0170094 -0.00138509 0.0162374 0.00582746 -0.0230331 -0.0117961 -0.00156591 0.0229133 0.027122 -0.0540262 -0.0410968 -0.013133 -0.00158327 -0.0109391 0.0261228 0.0330272 0.0405228 0.0323432 -0.0623613 -0.0561195 -0.00527043 0.00668445 0.0267738 -0.00936441 -0.0283996 0.0234758 0.0255722 0.014511 -0.0129606 0.00174176 0.0403901 0.0353441 -0.000116604 -0.0455759 -0.0479024 -0.0481118 -0.0843258 -0.209947 1.37135)) (17.6721 0.019402 0.0331344 #(-0.0350609 0.0339703 0.0145886 0.000690795 0.000922172 0.00738286 -0.01517 -0.0088783 0.0201723 0.0122574 -0.0158588 -0.0119165 -0.0019645 0.020945 -0.000870479 -0.0108681 -0.00586048 0.00538485 0.0104022 -0.00321434 -0.0157964 -0.0469299 -0.0215821 -0.00373954 0.00283885 0.0148254 0.0275313 0.0364303 0.0161417 -0.0308895 -0.0417433 -0.00377748 0.0165364 0.00397155 -0.0227846 -0.0260575 0.00618754 0.0551286 0.0147865 -0.0176932 0.00941883 0.0495573 0.031147 -0.00860301 -0.0380403 -0.0458936 -0.0610949 -0.096874 -0.18716 1.3588)) (20.0442 0.0140521 0.0264774 #(-0.0709867 0.0453836 0.0460421 0.0146813 -0.0179832 0.00433517 -0.0165851 -0.00628279 0.0245804 0.0150767 -0.0114593 -0.0368579 0.00386748 0.0248403 0.00774181 -0.0237615 -0.0110972 0.00908011 0.0143327 0.012267 0.00781146 -0.0256289 -0.0705544 -0.0244927 -0.0213969 0.0392408 0.0426976 0.0769561 0.011974 -0.0784876 -0.0580746 0.0130622 0.0449024 0.0142022 -0.0384532 -0.0269607 0.00680663 0.0207385 0.0149218 -0.0149792 0.0278171 0.0648385 0.0568704 -0.00419316 -0.0892845 -0.0271809 -0.0635848 -0.137194 -0.290703 1.49428)) (22.8017 0.0273646 0.0346427 #(-0.0720317 0.0448821 0.0348815 0.0233662 -0.000985435 0.00226309 -0.0135519 -0.0209769 0.0167468 0.0101012 -0.0194102 -0.00439263 0.00504041 0.0156837 0.00598467 -0.0264652 -0.0115608 0.0185426 -0.0068165 0.0100013 -0.00188157 -0.018496 -0.0458203 -0.0312296 -0.00116534 0.0335279 0.0330629 0.0395021 0.0183978 -0.0427994 -0.0459782 0.0054253 0.0243994 -0.00582722 -0.0111125 -0.0241409 0.0054475 0.0251814 0.00891366 -0.000905372 0.0228307 0.0523174 0.0382179 -0.00320691 -0.0354807 -0.0419394 -0.0835182 -0.139596 -0.249583 1.45587)) (26.3474 0.0219953 0.0288932 #(-0.0765435 0.0426832 0.0419785 0.0283921 0.00340572 -0.00535423 -0.0212032 -0.0116924 0.00206213 0.00816488 -0.0127589 0.00934433 0.0163962 0.00930891 -0.00568188 -0.0355663 -0.0130979 0.0042239 0.0221761 0.0294585 -0.00590132 -0.0300225 -0.0529725 -0.04428 -0.00514512 0.0547305 0.0372759 0.0478592 0.0239117 -0.0702372 -0.0687804 0.0195622 0.0191373 0.0223794 0.0135526 -0.038104 -0.00282542 0.00433172 0.00929822 -0.00582157 0.0154465 0.0665377 0.0342229 0.00927136 -0.0205276 -0.0192793 -0.0956723 -0.177253 -0.343554 1.56045)) (30.1984 0.030065 0.0315528 #(-0.0979213 0.0706986 0.0397353 0.027229 -0.00146723 -0.00438662 -0.0236935 -0.0188674 0.00900385 0.011066 0.00529251 -0.00704211 0.00609007 0.00670222 0.011048 -0.0216173 -0.0263168 0.00421382 0.0169606 0.0205924 -0.018071 -0.0136472 -0.0356033 -0.0382373 0.00240587 0.00751786 0.0412371 0.0584634 0.033329 -0.0663578 -0.0641406 -0.00811986 0.0285871 0.0444783 -0.00260303 -0.0335565 -0.018181 0.00985673 0.00558086 0.0118218 0.023386 0.0433098 0.0400329 0.0116843 -0.0148176 -0.058095 -0.0779079 -0.157939 -0.31358 1.52513)) (32.1428 0.0318259 0.0314665 #(-0.0775589 0.051683 0.0288251 0.0187194 0.00984706 0.00338128 -0.0202275 -0.00651548 0.0136416 -0.00760369 0.00215332 -0.0233182 0.0134451 0.0247162 -0.00404254 -0.0118734 -0.018538 0.0113604 0.00736548 0.00204067 -0.0115196 -0.0197442 -0.0154772 -0.0363295 -0.0150368 0.0175515 0.0394107 0.053815 0.00585165 -0.0330152 -0.054677 -0.0159929 0.0341672 0.015965 -0.00299163 -0.0189119 -0.0067154 0.0143037 -0.000256563 -0.00532035 0.0260945 0.0429435 0.0476952 0.0109455 -0.0235557 -0.0298008 -0.0826709 -0.176099 -0.325686 1.54201)) (31.4202 0.0318335 0.0318301 #(-0.0971744 0.0647286 0.0577288 0.0197214 -0.00649152 -0.0216951 -0.0189122 0.00437908 0.0284074 -0.000966733 -0.0171446 -0.0107114 0.00440035 0.0142388 0.00532634 -0.0126468 -0.02169 0.00523199 0.0297256 2.45184e-005 -0.00810739 -0.0215433 -0.0335994 -0.053856 -0.00465438 0.037238 0.0491757 0.0548962 0.014561 -0.073022 -0.0403319 -0.0130117 0.00834094 0.0434427 -0.00417276 -0.0078477 -0.0118494 0.00744896 -0.00313036 -0.0123154 0.0214602 0.059643 0.056315 0.00853147 -0.0377529 -0.0250175 -0.0860953 -0.178818 -0.327932 1.55029)) (32.4444 0.0301064 0.0304621 #(-0.0807 0.057348 0.0412646 0.0366669 -0.00996071 -0.0130091 -0.0387371 -0.00774177 0.0350818 0.0241313 -0.0154081 -0.0231186 0.00127267 0.0151109 -0.000317825 -0.0114935 -0.0136006 -0.00971232 0.0131985 0.0123626 0.0233086 -0.0265093 -0.0606854 -0.0258504 -0.0165391 0.0251411 0.0470309 0.053574 0.0180307 -0.0502542 -0.0485886 -0.0164236 0.019835 0.0329606 -0.00101179 -0.0302517 -0.0018849 0.0308459 -0.00743693 -0.0159462 0.0094627 0.0539938 0.0554317 0.0208811 -0.0307534 -0.0204858 -0.0821197 -0.181269 -0.37734 1.5857)) (40.9172 0.0650495 0.0398721 #(-0.0572582 0.0414552 0.0350494 0.0183922 0.00440463 -0.00850967 -0.00613651 -0.0179503 -0.00262387 0.0195232 -0.0131559 -0.00454892 0.00177392 0.0065445 0.00194393 -0.00781929 -0.00616173 -0.00313379 -0.000702812 -0.00178652 -0.014563 -0.0209123 -0.0269462 -0.0162782 0.00491859 0.0228838 0.0258315 0.027738 0.00459301 -0.0176909 -0.0295674 -0.0017052 0.0107792 -0.00448647 -0.00151116 -0.00392171 -0.00643332 0.00597558 0.0150378 0.0149934 0.0222908 0.0451681 0.0323751 0.00353828 -0.0263688 -0.050642 -0.0923144 -0.142247 -0.194605 1.40832)) (42.9245 0.0380718 0.0297817 #(-0.0619835 0.0538987 0.0254833 0.0191851 0.000713942 -0.00965684 -0.0114323 -0.0178469 0.0175577 0.0131995 -0.0072923 -0.00832834 -0.00811007 0.00959091 0.00557504 -0.00996733 -0.00855112 -0.00974844 0.00913783 0.0117909 -0.0045425 -0.0256592 -0.0292943 -0.0307577 -0.00238131 0.0201101 0.0259082 0.0446931 0.0181626 -0.0452096 -0.0297406 -0.0143662 0.023201 0.0203186 -0.00421108 -0.0211625 -0.00441318 0.019116 0.000645667 -0.00607597 0.0221206 0.0483723 0.0479185 0.015123 -0.02304 -0.0353189 -0.100976 -0.171954 -0.291149 1.51649)) (35.4435 0.0741689 0.0457449 #(-0.0592469 0.0408393 0.0310192 0.0213087 0.000897261 -0.0097075 -0.0127374 0.00034184 0.00697528 0.00416767 -0.00709337 -0.00543548 -0.00262597 -0.000460251 0.00462508 -0.000103108 -0.00210094 -0.000600998 -0.0064083 -0.00812498 -0.0110879 -0.014929 -0.0210607 -0.0126928 -0.00625044 0.0121755 0.0253735 0.0353037 0.00209597 -0.0177743 -0.0179092 -0.0111032 0.00635534 -0.000694276 -0.00804003 -0.00382186 0.00598897 0.00926817 0.00874331 0.0115986 0.0207321 0.0434171 0.0317387 0.00501884 -0.0295828 -0.0488442 -0.0859817 -0.140721 -0.179372 1.38875)) (31.5655 0.0508454 0.0401347 #(-0.0590031 0.0481201 0.0415922 0.0145118 -0.00625927 -0.010634 -0.022698 0.00794115 0.0129372 0.011031 -0.00684227 -0.0269145 0.000574552 0.0097944 0.00870401 -0.0154143 -0.00608816 -0.00337432 0.00658044 -0.000562268 -0.0114323 -0.0168882 -0.0267139 -0.0354475 -0.00491647 0.0324642 0.0368173 0.0353376 5.39129e-005 -0.039796 -0.021031 -0.00123375 0.0136188 -0.00348024 -0.00871654 0.00380723 0.0164729 0.0135323 -0.00439517 -0.0080045 0.0109003 0.0528155 0.0444091 0.0206946 -0.0118078 -0.0443984 -0.10415 -0.168437 -0.257971 1.47706)) (30.9527 0.0382595 0.0351577 #(-0.0677928 0.0651594 0.0430938 0.00356799 -0.0158889 0.000628987 -0.0127898 -0.00558382 0.0158968 -0.00226313 -0.00538957 -0.00778266 0.00155987 0.00443769 0.00375692 -0.0105507 -0.0224075 0.00426307 0.00792974 0.000294564 -0.000787178 -0.0161313 -0.0342735 -0.0403149 -0.00675935 0.0293195 0.0435918 0.0478281 0.00545949 -0.0534773 -0.037442 -0.0111263 0.0321929 0.020819 -0.00755799 -0.00482975 -0.00528935 0.0154923 0.00365394 -0.00549552 0.0121106 0.053678 0.0478409 0.019575 -0.0286409 -0.0335462 -0.0765612 -0.177995 -0.331 1.53233)) (31.4075 0.0364452 0.0340646 #(-0.0649986 0.0576299 0.0324902 0.00773543 -0.00458665 0.00495247 -0.0191388 0.000145591 0.000613326 0.00395394 0.000636622 -0.0207581 0.00467082 0.0155624 0.0110861 -0.0131649 -0.0232556 -0.00176555 0.00395216 0.00802351 -0.00893858 -0.021152 -0.016588 -0.0283998 -0.0138537 0.0249458 0.0287153 0.0452579 0.0204232 -0.053952 -0.0535749 0.00280977 0.0440965 0.0328232 -0.0150095 -0.0388665 -0.0096805 0.0162576 0.0154429 -0.00290426 0.029801 0.0596534 0.0460045 -0.00865289 -0.0497685 -0.0141297 -0.0805603 -0.160605 -0.335686 1.53526)) (31.6576 0.0348485 0.0331782 #(-0.0618954 0.0523533 0.0235303 0.0153525 0.00172889 -0.00168407 -0.0110182 -0.0142045 0.0170727 1.99435e-006 0.0017121 -0.0190737 -0.0111033 0.0169703 0.0280168 -0.01063 -0.0322064 0.00426402 -0.00485 0.0146215 -0.00758876 -0.0226077 -0.0252398 -0.0189545 -0.00568113 0.00980641 0.0269183 0.0392206 0.0257317 -0.0475402 -0.0534524 0.00178895 0.0586262 0.0278462 -0.0327184 -0.0414883 -0.0120922 0.029826 0.0131607 0.00598402 0.00931486 0.0642811 0.057244 -0.00679361 -0.0464739 -0.04173 -0.072625 -0.161229 -0.31275 1.52407)) (34.7383 0.0559897 0.0401467 #(-0.0415582 0.026703 0.0259679 0.0111422 0.00204608 -0.00618647 -0.00950887 0.0120808 0.0102095 -0.00150538 -0.0114168 -0.0193223 -0.00463892 0.0133971 0.0187653 -0.00583736 -0.0127744 -0.0100488 0.0111868 0.0106626 -0.0205418 -0.0312655 -0.0304695 -0.0160161 -0.00137347 0.0194299 0.0309445 0.0366569 0.00705069 -0.0166283 -0.0404884 -0.00764167 0.0169512 0.0132674 -0.00907035 -0.0275286 -0.0054365 0.0307347 0.0158178 0.00474018 0.0264909 0.0460957 0.0291759 -0.00850643 -0.0359522 -0.0586856 -0.0731063 -0.11696 -0.205816 1.40186)) (36.4119 0.0463771 0.0356887 #(-0.0389951 0.0307876 0.0205879 0.00908905 0.00555359 -0.0121034 -0.00687764 0.00752914 0.0176609 0.00566536 -0.0208413 -0.0229413 0.00156059 0.00543264 0.00694066 0.00249693 -0.00335328 0.000401892 0.0138262 0.00128668 -0.0283111 -0.0256373 -0.0237493 -0.0291584 -0.00703129 0.0152271 0.0393229 0.0452958 0.0231804 -0.0291094 -0.0417306 -0.00489797 0.0160917 0.000583816 -0.0194554 -0.0235409 0.00563181 0.0393978 0.0237208 -0.00447947 0.0171657 0.0551852 0.0282278 -0.022097 -0.0371377 -0.0598215 -0.0687185 -0.118988 -0.195594 1.40087)) (31.5195 0.0823719 0.0511211 #(-0.0506811 0.032627 0.0260271 0.0133287 0.00707792 -0.00716418 -0.00792555 -0.00164158 4.37169e-005 0.00655899 -0.00403331 -0.00510847 -0.00250636 0.00465444 0.012035 0.0010902 -0.00567664 -0.00723898 -0.00466529 -0.00771452 -0.0268553 -0.0264261 -0.00282889 0.000687852 0.00062155 0.00777579 0.0113666 0.0250398 0.020167 -0.0104087 -0.0261586 -0.0112883 -0.00423545 0.0070317 -0.000811418 -0.0200803 0.00317688 0.0237687 0.0201803 0.0121356 0.0175142 0.033371 0.0253085 -0.00456846 -0.0415392 -0.0596395 -0.0783815 -0.0936876 -0.114877 1.30627)) (25.4029 0.0602808 0.0487134 #(-0.0551556 0.0394576 0.0270103 0.0236226 0.00186073 -0.00761447 -0.00740441 -0.00712806 0.00591052 -0.00309897 -0.00157216 -0.0120145 -0.00111416 0.0139671 0.00880658 -0.0012513 0.00244409 -0.0133322 -0.00925009 0.00123142 -0.034305 -0.0168858 -0.00914378 -0.0110158 0.000306792 0.0116358 0.0236282 0.0251389 0.00218792 -0.00727665 -0.0207191 -0.00825958 0.00274023 -0.00288428 -0.00666814 -0.0172675 0.00904082 0.0154382 0.0150386 0.0254515 0.0314402 0.0294853 0.0295901 -0.00445611 -0.0469681 -0.0574121 -0.0877862 -0.106583 -0.135491 1.339)) (22.7468 0.078061 0.0585811 #(-0.04486 0.0298865 0.0293551 0.0157202 0.00558635 -0.00166327 -0.0153884 -0.00699228 0.00676223 0.00247051 -0.00958823 -0.00736895 0.00134663 0.00697311 0.0112086 -0.000206178 -0.00881016 -0.00624388 -0.00932781 -0.0197023 -0.0190608 -0.011131 -0.0120463 0.000508607 0.00205883 0.0130596 0.00678453 0.017637 0.0173591 -0.00929612 -0.0146321 -0.00917131 -0.0076256 0.0010683 -0.00392937 -0.00849227 0.006057 0.0173038 0.0170559 0.0185356 0.0307804 0.0321241 0.0197208 -0.00024348 -0.0379323 -0.0627024 -0.0771216 -0.096205 -0.116027 1.29578)) (22.8884 0.0716601 0.055954 #(-0.0482403 0.0307585 0.0275873 0.0182651 0.000529184 -0.0022478 -0.00768153 -0.00720601 0.00320312 0.000542559 -0.00613952 -0.00509576 0.000853576 0.00746592 0.00241067 0.00149092 -0.0103518 -0.00548361 0.00260866 -0.00854271 -0.0165325 -0.024049 -0.0159926 -0.0106845 0.00539235 0.0217353 0.013189 0.0138549 0.0113874 -0.00669787 -0.0144154 -0.00952096 -0.00989752 0.000984178 -0.00567269 -0.0075391 0.00597343 0.0157336 0.0231019 0.0212661 0.0260539 0.0267702 0.0234177 -0.00360673 -0.0411499 -0.0479637 -0.0797028 -0.101779 -0.123467 1.30416)) (25.0679 0.0404904 0.04019 #(-0.0569264 0.0393012 0.0442286 0.0105388 -0.0280166 0.0130403 -0.000293758 0.00097423 0.0019422 -0.0135517 -0.0129558 -0.00137247 0.0176797 0.0111486 -0.00223964 -0.00550807 -0.00602055 -0.00683842 -0.0111893 0.0040559 -0.00320025 -0.0210676 -0.0166252 -0.0273107 -0.00925243 0.0352852 0.0153395 0.028238 0.0100151 -0.0296035 -0.0250562 0.00185137 0.0255143 0.00681541 -0.0269629 -0.0225865 0.00339151 0.0176583 0.0135256 0.0128693 0.0308694 0.0396139 0.0268478 -0.00453411 -0.0321182 -0.0411832 -0.0894552 -0.13549 -0.18868 1.40068)) (26.172 0.0414675 0.0398048 #(-0.0630411 0.0445934 0.0340673 0.0179641 -0.0126086 -0.000847251 0.000227371 0.00106207 0.0131494 -0.0118745 -0.0160848 -0.00908814 0.00502605 0.0118554 0.0134411 0.006348 -0.0203072 1.60219e-005 -0.0092216 -0.0131313 0.00614179 -0.023434 -0.0225044 -0.0205765 -0.00759216 0.0190882 0.0216325 0.0341826 0.0139076 -0.0241181 -0.0163891 -0.0082327 0.0124357 -0.00390939 -0.0224453 -0.0154005 0.00127452 0.0147405 0.0170827 0.0260113 0.0421892 0.0303767 0.0235349 -0.0138023 -0.0474366 -0.0434775 -0.0753137 -0.111706 -0.172436 1.36862)) (24.9425 0.0127896 0.0226443 #(-0.0733194 0.0354206 0.0577736 0.0308347 -0.0289842 -0.00604918 -0.014531 -0.0101977 0.0240066 0.0242339 -0.0217081 -0.0255996 0.00547605 0.0210583 0.0282309 -0.0144568 -0.0284572 -0.0338683 0.0165173 0.0371958 0.00744609 0.00585112 -0.0600074 -0.0549116 0.000340121 0.0385451 -0.00124994 0.0513382 0.0555081 -0.0592178 -0.0733577 -0.0170409 0.0586459 0.0553344 -0.0225186 -0.0556362 -0.0233135 0.0506938 -0.00436045 -0.0332437 0.00902178 0.0879455 0.0599741 -0.000640262 -0.0442607 -0.0220114 -0.0610923 -0.165358 -0.458725 1.64915)) (22.7641 0.0174743 0.027706 #(-0.0584102 0.0459445 0.031618 0.0172284 -0.0102017 -0.00307119 -0.0147159 -0.0128069 0.0192186 0.0263737 -0.0162587 -0.0214138 -0.00164627 0.0164729 0.0190751 -0.00745766 -0.0243652 -0.0185078 -0.0136905 0.043886 0.0129518 -0.0298972 -0.0265289 -0.0403765 -0.00958069 0.0232809 0.0161453 0.044125 0.0361099 -0.0522329 -0.0619475 -0.000899218 0.0508566 0.0368301 -0.0180012 -0.0430501 -0.00970191 0.00226846 0.0163143 0.00440859 0.00654716 0.0745107 0.0559268 -0.0237278 -0.0297872 -0.0202482 -0.0711893 -0.150335 -0.394529 1.58051)) (19.5777 0.0125371 0.0253057 #(-0.0826795 0.0683275 0.0428367 0.02936 -0.021953 -0.0169267 -0.0348315 -0.00679442 0.025703 0.045118 -0.00592805 -0.0419876 -0.00936561 0.0199536 0.035517 -0.0131276 -0.0408877 -0.0219309 0.0500002 -0.0214081 0.0310525 -0.0126166 -0.046124 -0.0345309 -0.027267 0.0407647 0.00779675 0.0551954 0.0525408 -0.0538993 -0.0680158 -0.0475148 0.0549138 0.0610506 0.00643009 -0.0500036 -0.0294172 0.0234389 0.0124404 -0.0212963 0.0223014 0.0563873 0.0415865 0.0218463 -0.0398211 0.00419091 -0.103894 -0.150699 -0.43171 1.62141)) (18.2418 0.0253117 0.0372501 #(-0.0607523 0.0562677 0.0384613 0.00424439 -0.0162383 -0.00801906 -0.00889723 -0.00153158 0.0178735 0.00687857 -0.00841403 -0.0109761 -0.000752748 0.0188549 0.0145737 -0.0116472 -0.0244779 -0.0102738 0.00684694 -0.00289441 -0.0144796 -0.0119951 -0.0216497 -0.0176858 0.000835 0.00693356 0.0142641 0.0338318 0.0169442 -0.0304174 -0.03766 -0.00345847 0.0310024 0.00119207 -0.0121249 -0.0113758 -0.00784907 0.0241519 0.0161341 0.0165755 0.0178807 0.0323894 0.0223039 0.0113459 -0.0211709 -0.0354951 -0.0753201 -0.130449 -0.212926 1.39061)) (18.2633 0.0252861 0.0372093 #(-0.045203 0.0314978 0.0349495 0.00211169 -0.00893727 0.00352343 -0.0123056 -0.00291805 0.0126091 0.00904179 -0.00646769 -0.0145041 -0.00502528 0.0120276 0.0164997 -0.0114284 -0.0165834 -0.00612101 0.0129625 0.0025109 -0.0220033 -0.00506117 -0.0341916 -0.0253116 0.0116913 0.0206707 0.00947406 0.0215501 0.018648 -0.0253815 -0.0210033 -0.00128285 0.00803003 0.00165846 -0.00961188 -0.0112029 -0.00390969 0.018762 0.0176612 0.0141336 0.0162613 0.0423988 0.0169786 0.00664183 -0.0149723 -0.0514017 -0.0758318 -0.125953 -0.214712 1.39864)) (17.5015 0.0281862 0.0401311 #(-0.0467037 0.0285618 0.0290192 0.00889659 0.00523947 -0.0106185 -0.00584188 0.00343646 0.0078645 0.00378798 -0.0136156 -0.012084 0.00284047 0.0112584 0.00930852 -0.0112164 -0.00383024 -0.00982824 0.0153711 -0.00475254 -0.018373 -0.0203009 -0.0232701 -0.0175478 0.00286289 0.0183034 0.0126237 0.036949 0.00550275 -0.0201175 -0.0171514 0.000764537 0.00264071 -0.0167697 -0.00575089 -0.00377642 -0.00121029 0.0205625 0.019458 0.00863159 0.025104 0.0386815 0.0262647 -0.00411803 -0.0406888 -0.0471502 -0.083648 -0.103756 -0.174039 1.36212)) (17.2526 0.0295366 0.0413764 #(-0.0459645 0.0347026 0.0174516 0.0140821 0.00442935 -0.00595253 0.000786888 -0.00770935 0.00586936 0.00240675 0.00201615 -0.0114029 -0.00715992 0.0219725 0.00668619 -0.00508303 -0.0104611 -0.00929612 -0.00120529 -0.00989537 -0.0169932 -0.0133932 -0.0188951 -0.000876892 -0.000297876 0.000200907 0.0129674 0.0262989 0.00787067 -0.0241803 -0.0115058 -0.000143185 0.0150916 0.0138443 -0.0335769 -0.0206819 -0.00174932 0.0245576 0.0198266 0.017498 0.020447 0.0325335 0.0246589 0.00835593 -0.033657 -0.0520807 -0.0742558 -0.105502 -0.158577 1.3385)) (17.7939 0.0194564 0.0330671 #(-0.0393023 0.0249954 0.0281254 0.00881808 -0.0170303 -0.000254086 -0.0238422 0.0104953 0.0267727 0.0218212 -0.00832039 -0.0378733 -0.00966003 0.0208957 0.0258569 0.00523595 -0.0125616 -0.0198685 -0.00261361 0.0267587 -0.00756953 -0.0295961 -0.0220904 -0.0216108 -0.022352 0.010996 0.018242 0.0477541 0.0378138 -0.0342758 -0.0460006 -0.0110206 0.0200271 0.0216202 -0.0010694 -0.0481358 -0.00989713 0.0183853 0.0178495 0.0123016 0.00932306 0.0462944 0.0355045 0.00738312 -0.0433972 -0.0431022 -0.0752448 -0.111662 -0.22808 1.41783)) (16.2645 0.0198753 0.0349571 #(-0.0444276 0.0359794 0.0176339 0.0166024 -0.00509977 -0.00228653 -0.0161215 0.0145134 0.0174299 0.000749843 -0.00504707 -0.026946 -0.00241593 0.0172678 0.024325 -0.00596551 -0.0248575 -0.0135324 0.0111395 0.00225044 -0.0129778 -0.0134113 -0.0270257 -0.0234719 -0.000202711 0.0218519 0.00693315 0.0315688 0.0147574 -0.0374582 -0.0197909 -0.0087806 0.0357156 0.00379843 -0.0129535 -0.0288524 -0.0066429 0.02112 0.00394448 0.0222445 0.0191879 0.0458149 0.0290641 0.00188522 -0.0291704 -0.0394177 -0.0755161 -0.123621 -0.231673 1.41693)) (13.9843 0.0203448 0.0381422 #(-0.0406508 0.0247845 0.0280528 0.016247 -0.00667394 0.00575473 -0.00883099 -0.00538796 0.0124414 0.00246849 -0.0144231 -0.0122821 5.65498e-006 0.0240839 0.00861459 -0.00217033 -0.0235125 -0.0168742 0.0055966 -0.00328378 -0.00988276 -0.0124962 -0.0202922 -0.0046567 0.00286656 0.0025336 0.000137633 0.0296567 0.0200221 -0.0189908 -0.0237597 -0.000666055 0.0173422 0.0148898 -0.028545 -0.0280338 -0.00862389 0.0107104 0.0292579 0.0223673 0.0356336 0.027171 0.0365469 -0.00876548 -0.0413912 -0.0440555 -0.0862704 -0.0992445 -0.175119 1.36053)) (13.7519 0.0318418 0.0481192 #(-0.0439203 0.0286811 0.019099 0.0131209 0.00116507 0.00239283 -0.00349781 -0.00764389 0.00731754 0.00111961 -0.0119648 -0.0166307 0.0112826 0.0209392 0.00437699 0.00510248 -0.00768695 -0.0223086 -0.0103192 -0.00707175 -0.0131623 -0.0187769 0.00250121 -0.00532104 -0.0114664 0.00451569 0.0158921 0.0267952 0.00829616 -0.0112708 -0.0156018 -0.00644018 0.00364066 -0.00682353 -0.0102232 -0.0152849 -0.00104906 0.0131723 0.0312335 0.0306407 0.0224566 0.0393104 0.00734389 -0.0167909 -0.0521184 -0.0325935 -0.0547162 -0.0785076 -0.107318 1.25643)) (14.1001 0.036371 0.0507887 #(-0.0416909 0.0311513 0.0216856 0.010757 0.0023053 -0.00539498 -0.0122303 -0.00307753 0.0143497 -0.0013006 -0.00140553 -0.0114054 0.00277976 0.0180154 0.00290372 -0.000693336 -0.0231679 -0.00686742 -0.00978564 -0.00577415 -0.00821437 -0.0128852 -0.00872088 -0.0119665 0.00729519 0.00605096 0.00574081 0.0229577 0.00811213 -0.0167 -0.00908976 0.00335362 -0.00364028 -0.00150706 -0.00937789 -0.0185555 -0.000902989 0.0273121 0.0204276 0.0180267 0.0271863 0.0347298 0.0131781 -0.0189297 -0.042958 -0.0488664 -0.0552135 -0.0687342 -0.0978135 1.24792)) (14.2751 0.0340747 0.048857 #(-0.0375261 0.024581 0.0173357 0.0105803 0.00152478 5.81223e-005 -0.0049663 0.000233414 -0.0059578 0.0172982 -0.0123975 -0.0121001 0.00817213 0.00614464 0.0063125 0.00277281 -0.0072908 -0.00298882 -0.00532286 -0.0151193 -0.0130224 -0.0190079 -0.00477871 -0.00682809 -0.00484661 0.0136435 0.0106479 0.0201277 0.016766 -0.0148155 -0.0230016 0.0010569 0.00368719 -0.00836747 -0.0108471 -0.0115598 -0.000523546 0.020508 0.0238148 0.0105346 0.0278912 0.030346 0.015747 -0.00584426 -0.0429999 -0.0557868 -0.0671162 -0.0745447 -0.115248 1.28424)) (15.2833 0.022009 0.0379483 #(-0.0444502 0.0319226 0.0206898 0.00408402 0.0038444 0.00518289 -0.0102187 0.00644884 0.0154201 0.00243678 -0.0155881 -0.0226183 -0.00535144 0.0143481 0.0263679 -0.00816404 -0.00439294 -0.00726711 0.00245852 -0.0075432 -0.0210695 -0.022927 -0.0121272 -0.00257655 -0.0142863 0.0116892 0.0195945 0.0314798 0.0171628 -0.026222 -0.0236029 -0.00279915 0.0139127 -0.00411994 -0.0220793 -0.0223499 0.0130053 0.0163297 0.014851 0.0168635 0.030113 0.0393203 0.0185481 -0.0032677 -0.0508295 -0.049786 -0.0681459 -0.100596 -0.141854 1.3324)) (16.2369 0.0167683 0.0321361 #(-0.0461453 0.0336128 0.0171639 0.00638196 0.00304988 0.00700732 -0.0124934 -0.0014443 0.0229149 0.00812651 -0.0156464 -0.027978 0.00155632 0.0148617 0.0236262 -0.0053183 -0.0306435 0.0156539 0.00576177 -0.00936416 -0.019092 -0.0214782 -0.0106117 -0.0139679 -0.00487678 0.0153928 -0.000839796 0.0328364 0.0370444 -0.0267438 -0.0258321 -0.0084227 0.00140206 0.0170352 -0.0249207 -0.0137748 0.00622318 0.00877071 0.0176743 0.0140944 0.0160371 0.0299227 0.0280204 0.00486572 -0.0471303 -0.0549004 -0.0792787 -0.0862093 -0.156202 1.34944)) (15.8715 0.00862119 0.0233064 #(-0.0416665 0.0196847 0.0351245 0.00540738 0.000268711 0.000455022 -0.00585776 -0.00906765 0.019069 0.0231938 -0.0242396 -0.0320143 0.00375507 0.0115636 0.0160781 -0.00497688 0.0104297 -0.0136434 0.0112971 0.000516813 -0.0335269 -0.00981996 -0.0165414 -0.0128344 -0.00386654 0.0142686 -0.0124378 0.0254652 0.0577827 -0.0404511 -0.0399016 0.00257038 0.0284287 0.00205934 -0.00698707 -0.0282862 -0.0129552 0.0375839 -0.00052652 -0.00139833 0.010455 0.0601005 0.027725 0.00917528 -0.0452916 -0.0495308 -0.114218 -0.0824053 -0.228428 1.43507)) (14.8358 0.0137405 0.030433 #(-0.035238 0.0325776 0.00811017 0.00564153 0.00956963 0.00160376 -0.00735718 -0.0106363 0.00927161 0.0156551 -0.014077 -0.0256614 0.00892661 0.0141185 0.0219964 0.00497017 -0.0213388 -0.00393183 0.00307147 -0.00527207 -0.00932004 -0.0149748 -0.0293915 -0.0137217 0.0110029 0.00820573 -0.00731358 0.0228706 0.0342061 -0.0270083 -0.0231551 -0.00456665 0.0112681 -0.00073322 -0.00608638 -0.0299522 0.00616215 0.0218085 0.0147894 0.01267 0.0171617 0.0382049 0.0155666 0.00222878 -0.0301421 -0.0626113 -0.101723 -0.0618076 -0.14028 1.33014)) (12.9037 0.0170322 0.0363311 #(-0.0361427 0.0205666 0.0172627 0.017552 -0.00678439 0.00380304 -0.00573859 0.00913126 0.0155822 -0.00543546 -0.00759378 -0.0190302 -0.00357661 0.0192382 0.00804061 0.000652122 0.000361389 -0.0179953 -0.00446666 0.00560995 -0.0184849 -0.0113776 -0.0232038 -0.00865374 -0.000620224 0.00406897 0.00305195 0.0334702 0.0202773 -0.0270967 -0.0247178 0.00910172 -0.000104248 0.000138012 -0.0102208 -0.0169238 0.00120545 0.0203969 0.0133169 0.0181668 0.0202681 0.0266863 0.021128 -0.0131285 -0.0365628 -0.0378504 -0.0756192 -0.0782206 -0.137483 1.31255)) (10.7606 0.0176641 0.0405161 #(-0.0483414 0.0247989 0.0315676 0.00585319 -0.00234617 0.009571 0.00527321 -0.010687 0.0163059 0.00885164 -0.0125577 -0.0134762 -0.00967633 0.0164184 0.00952228 -0.00630756 -0.0123339 0.00271924 -0.00671046 -0.0020015 -0.00886391 -0.0281787 -0.0135787 -0.0134191 0.00144693 0.00931767 0.000242524 0.0183011 0.0329657 -0.0164957 -0.0380229 0.00540505 0.0215291 -0.00189809 -0.0201857 -0.0100815 0.00201447 0.0118938 0.00726428 0.0202927 0.0107608 0.0392477 0.0177106 -0.00825438 -0.0278289 -0.0360925 -0.0803767 -0.0690058 -0.118693 1.27992)) (9.692 0.0163592 0.0410842 #(-0.0435487 0.0238735 0.0221766 0.0130095 -0.0102838 0.0102648 -0.00263138 0.00405493 0.0139175 0.00368894 -0.0144828 -0.0187693 0.000191167 0.0191079 0.0188621 -0.00391941 -0.0163057 -0.0108496 0.0112138 -0.0054916 -0.0242603 -0.0107545 -0.03524 -0.00986785 0.00436468 0.0159444 0.00288566 0.0280451 0.0177601 -0.0226378 -0.0232638 -0.00458616 0.0132367 -0.00669003 -0.00879428 -0.0174804 -0.00444567 0.0183938 0.0174463 0.0192643 0.0206223 0.0364433 0.00547454 0.00493223 -0.0256411 -0.0374557 -0.0770796 -0.0699102 -0.107736 1.2591)) (10.6083 0.0116637 0.0331585 #(-0.0339536 0.0239064 0.0193139 -0.00206308 -0.00420809 0.0162964 -0.00446401 -0.00723342 0.032238 0.00872946 -0.0187994 -0.0242643 -0.0134408 0.0259891 0.0161434 0.00132369 -0.0197008 -0.00519451 0.00655926 -0.00738285 -0.0172127 -0.0237242 -0.0212511 -0.0206254 0.0103538 0.0122223 -0.00456432 0.0447003 0.0352811 -0.0406705 -0.0316736 0.00797188 0.00656864 -0.0115901 -0.0027629 -0.0128048 -0.00570429 0.0118761 0.0188073 0.0222462 0.0124456 0.0410702 0.00791332 -0.00379496 -0.0170523 -0.0476136 -0.0781826 -0.0542285 -0.143112 1.28919)) (13.6333 0.00775797 0.0238547 #(-0.0364152 0.0291058 0.0227928 0.00502204 -0.0253292 0.048831 -0.0291211 -0.014896 0.0320535 0.00774532 0.000503408 -0.0316866 -0.00546139 0.0360913 0.00840064 -0.0208066 -0.0145649 0.000116066 0.00307052 -0.0122648 -0.0118387 -0.0277435 -0.0112472 -0.0110968 0.0148855 -0.00123177 -0.021587 0.0284518 0.0631961 -0.0358807 -0.0443364 0.00976814 0.00940558 0.00815862 -0.0182798 -0.0167586 0.0109045 0.0136983 0.0074112 0.00384714 0.0165089 0.0481128 0.0182451 0.00169633 -0.0279793 -0.0379538 -0.093019 -0.0760834 -0.15798 1.33196)) (14.9529 0.0090799 0.0246421 #(-0.0173912 0.0117589 0.0215592 -0.000100125 -0.00958332 0.0178238 -0.0220747 0.00944662 0.0241577 0.0100921 -0.0118245 -0.0308733 -0.0111011 0.0260419 0.0364623 -0.0174218 -0.0250652 -0.02109 0.0203074 0.00684312 -0.0399599 -0.0207732 -0.0171705 -0.0007063 0.00839398 0.0148383 -0.0116208 0.0395184 0.0320917 -0.0477367 -0.0288544 -0.013006 0.0343035 0.0151606 -0.0250012 -0.0238014 0.010687 0.0287551 0.00443121 -0.00885899 0.0187292 0.0305535 0.0398672 0.0256628 -0.0622547 -0.0391768 -0.0803045 -0.063373 -0.174028 1.33167)) (15.4713 0.0103036 0.0258065 #(-0.0317778 0.0220012 0.023046 0.0107401 -0.00700271 0.0157947 -0.0168062 -0.0275037 0.0367403 0.0183112 -0.0155777 -0.0184876 0.00537082 0.00657688 0.00920857 -0.00738122 -0.0258576 -0.00495231 0.0158989 0.0138713 -0.0316929 -0.0372503 -0.00456503 0.00398878 -8.80907e-005 0.00931697 -0.0254795 0.0441872 0.0447222 -0.0413425 -0.0365677 -0.00544457 0.0244433 0.0112955 -0.0182531 -0.0124006 0.00266321 0.0168735 0.014526 -0.0109792 0.0141278 0.0440501 0.000770168 0.0424379 -0.0278247 -0.0526684 -0.0777227 -0.0873046 -0.175866 1.34552)) (14.1187 0.00916422 0.0254771 #(-0.045858 0.0400202 0.0205128 0.00743514 -0.00145771 0.00837235 -0.0248272 -0.00172827 0.0233621 0.0100241 -0.0135858 -0.0126684 -0.00336266 0.0149539 0.0171219 -0.016675 -0.0227132 -0.000102549 0.020379 0.00582718 -0.016864 -0.0320013 -0.0340711 0.00940389 -0.00660789 0.0171697 -0.029894 0.0563412 0.0606243 -0.07549 -0.0483998 -0.000330146 0.0359239 0.0257492 -0.00142432 -0.0289091 -0.0018749 0.012466 0.00260386 -0.0152575 0.00862908 0.053457 0.03697 0.0345913 -0.0435553 -0.039316 -0.0996627 -0.0778146 -0.205904 1.3743)) (12.5142 0.0109789 0.0296196 #(-0.0372881 0.0196089 0.0233113 0.000903561 -0.0047855 0.0192033 -0.00402685 -0.00304796 0.0072131 0.000961789 -0.00506267 -0.0118756 0.00342084 0.015397 0.00417627 0.00558174 -0.014547 -0.00178372 -0.00917506 0.0153024 -0.021183 -0.0321192 -0.0190146 -0.0116695 0.0083767 0.00252157 0.0031781 0.03148 0.0255226 -0.0305256 -0.0148153 0.00160903 0.010152 0.00196973 -0.0133266 -0.0138634 -0.0111339 0.0246016 0.00657759 0.0046415 0.0102237 0.0405588 0.0267124 -0.0205946 -0.0262742 -0.0302408 -0.0733365 -0.0751875 -0.141942 1.30887)) (13.1881 0.0149057 0.033619 #(-0.0392646 0.0235916 0.0113109 0.0165674 0.000356377 0.0096727 -0.00454504 -0.0118521 0.0189847 5.30982e-006 -0.00576891 -0.00829558 -0.00267612 0.0116296 0.0180062 -0.00463104 -0.015852 -0.0119515 0.00220159 0.00224108 -0.027798 -0.0126524 -0.0149994 -0.00157439 -0.00384594 0.00016854 0.00338744 0.0262442 0.0138858 -0.0262235 -0.0060537 -0.000456936 0.0188089 0.00153812 -0.0108762 -0.0196819 -0.00571758 0.0244648 0.0111209 0.00558558 0.0127132 0.0348169 0.015571 -0.0175171 -0.0217261 -0.045869 -0.0708379 -0.0505154 -0.114525 1.26721)) (12.7999 0.015072 0.0343149 #(-0.0333835 0.0122214 0.0259325 -0.000845576 -0.00411607 0.0249855 -0.00362802 -0.00123161 0.00374519 0.00881159 -0.00779002 -0.0221836 -0.00150112 0.0259934 0.00794084 -0.00206094 -0.0134564 -0.00876726 -0.00201227 -0.0224425 0.00930002 -0.0259136 -0.0165928 -0.00342897 -0.00262414 0.00704048 -0.00242533 0.0235934 0.0114056 -0.0151016 -0.0109616 0.00159531 0.0111167 -0.000793585 -0.00855475 -0.0193289 0.00818316 0.0173823 0.00418687 0.0104691 0.0231481 0.0104235 0.0158543 -0.00351913 -0.0424822 -0.0357488 -0.0522538 -0.0381995 -0.0936292 1.22602)) (12.2473 0.0193377 0.0397359 #(-0.0208312 0.0113622 0.0107963 0.0102407 -0.0113957 0.00688707 0.00914879 -0.00983215 0.00520417 0.00334524 -0.0068846 -0.004754 -0.00291994 0.0137996 0.0146112 -0.00155131 -0.0176285 0.00365784 -0.0104858 -0.0192718 -0.000923549 -0.0131308 -0.0111267 -0.00719019 0.000579761 0.0111471 -0.00676168 0.0234209 0.0115352 -0.0168934 0.0025673 -0.00926516 0.00685466 -0.00665536 -0.00981694 0.000390394 0.00485606 0.00488992 0.00723448 0.0167406 0.00949511 0.00968203 0.0148381 -0.0192989 -0.0238238 -0.0274632 -0.0505583 -0.0318813 -0.0690697 1.18902)) (12.5963 0.016594 0.0362957 #(-0.022897 0.0164408 0.00922307 0.00712825 0.00029965 0.0126678 -0.00781488 -0.00903336 0.00276701 0.00841422 -0.00438664 -0.00758085 0.00516114 0.00530365 0.00871018 -0.00177273 -0.00100205 -0.00497492 -0.00829477 -0.00643409 -0.0175788 -0.016037 -0.0116676 -0.00203718 -0.000523905 0.0101769 -0.00147634 0.0081845 0.0146411 -0.0119274 -0.00436797 -0.000224399 -0.00513704 -0.00984378 0.0115129 -0.0102507 0.00516442 0.00549147 0.00572397 0.0118901 0.0113157 0.0218897 0.00945389 -0.0113134 -0.0298536 -0.0302538 -0.053088 -0.0372686 -0.0642578 1.19366)) (13.5525 0.01008 0.0272723 #(-0.0123657 0.0053427 0.019458 -0.0176663 -0.0176549 0.0404966 -0.00390325 -0.00579765 0.00887555 0.00317001 0.00172718 -0.00829583 0.010417 0.0153962 -0.00556122 -0.00680748 -0.00745445 -0.00852993 -0.00462103 -0.0159715 -0.000628177 -0.0183191 -0.0147015 -0.00193298 -0.00415885 0.0236506 -0.0098982 0.015603 0.0132994 -0.0134173 -0.00543716 0.00140853 -0.000410987 -0.0155814 -0.00399504 -0.000352762 -0.00284362 0.0100352 0.0139833 0.0156556 0.00280102 0.00782334 -5.04827e-005 -0.0182239 -0.0189623 -0.0239327 -0.0540221 -0.0168124 -0.0578101 1.18215)) (12.068 0.00596845 0.0222389 #(-0.00770466 -0.00247063 0.020446 -0.00341433 -0.0175267 0.0299728 -0.00334073 -0.021708 0.0222189 0.00349176 -0.00219307 0.000507939 -0.000906229 0.0251413 -0.00347692 -0.0193672 -0.008356 0.0107288 -0.00522202 -0.0373399 0.0110019 0.00334983 -0.0260176 -0.00508717 0.0076833 0.0123874 -0.0218113 0.0217126 0.0137616 -0.0343426 0.00107652 -0.0108971 0.00723602 -0.0140256 0.00945629 0.008111 -0.013161 0.0263409 0.00322294 0.0169951 0.0125402 0.00634017 -0.0281478 0.00833678 -0.0210252 -0.0480639 -0.0657505 0.00962592 -0.0670183 1.193)) (8.95623 0.00286173 0.0178752 #(-0.0299596 -0.00271054 0.0316405 0.00830122 -0.0430843 0.052154 0.00778072 -0.0218403 0.015222 0.00900955 0.000450335 -0.0294424 0.0109118 0.0305165 0.0185617 -0.0211344 -0.00754338 0.000348268 -0.015125 0.000259483 -0.00953378 0.00744751 -0.0392438 -0.0133562 -0.0140394 0.0473366 -0.0574915 0.0274957 0.0739216 -0.0633229 -0.00625577 -0.00332914 0.0318236 -0.039495 -0.0259531 0.0239393 -0.0180297 0.0156937 0.0245471 0.0241233 0.00445331 0.0143366 -0.0112595 0.0136985 -0.0568217 -0.0400073 -0.106216 0.040655 -0.0915969 1.22924)) (6.49921 0.00445611 0.0261847 #(-0.0170517 -0.0101715 0.0184278 0.00588615 -0.0192503 0.0377397 -0.00414877 -0.0237132 0.0261238 0.0049736 -0.00638682 0.00527185 -0.00923617 0.0111306 0.0255296 -0.0039067 -0.0151077 0.00377979 7.06266e-005 -0.0208127 0.00467839 -0.022734 -0.0168833 -0.00336075 -0.01055 0.033853 -0.0379811 0.010155 0.0492233 -0.0412482 -0.00933746 -0.0204949 0.0208357 0.00125835 -0.0115378 -0.000968487 0.00445165 0.00835097 0.00622662 0.0115168 0.000545416 0.00342692 -0.00927968 0.0260598 -0.0528268 -0.0332704 -0.0524391 0.0325668 -0.0789734 1.17526)) (5.25729 0.00395311 0.0274213 #(-0.0240403 0.0205123 0.0153895 -0.0123595 -0.0220413 0.0554869 -0.00704868 -0.0433425 0.0501927 -0.00331648 -0.0181042 -0.0055328 -0.0079657 0.0218988 0.0184512 0.000216515 -0.0131423 -0.00679136 0.0172376 -0.0200239 0.00385909 -0.0187232 -0.0339574 -0.0205053 0.00639417 0.0217717 -0.022982 0.0227078 0.0735146 -0.0648862 -0.0373938 0.00153798 0.00527095 0.0142592 -0.0107342 -0.0298141 0.00548001 0.0163492 -0.00212356 0.00278833 0.0101466 0.0397622 0.0149 0.023642 -0.01529 -0.0428728 -0.0909119 0.00412615 -0.130688 1.23334)) (4.64889 0.00405787 0.0295443 #(-0.0083154 0.00615811 0.0229795 -0.0118895 -0.011159 0.0234972 -0.00391371 -0.0106054 0.0152195 0.0045161 -0.0309345 -0.0133451 0.0142733 0.0022754 0.0224104 0.00053866 -0.0105869 0.014126 -0.00594441 -0.016928 0.000217074 -0.00374499 -0.0370543 -0.0101543 -0.0131152 0.0467066 -0.0290259 0.0361985 0.048131 -0.0712857 -0.010248 0.0200725 -0.00527912 -0.033853 0.00625684 -0.0132771 -0.00059062 0.00807303 0.0207666 -0.005388 0.00403096 0.0390784 0.0263475 0.00420176 -0.0247701 -0.0169901 -0.0981137 0.00202813 -0.122794 1.22287)) (4.2687 0.00527028 0.0351374 #(0.0119431 0.000370011 0.00297805 -0.0086345 -0.00619318 0.0209268 -0.0214211 -0.00264095 0.000795118 0.0018904 0.00504403 -0.00221174 0.000734628 0.0115394 0.00269348 0.00862158 -0.0112626 0.0128954 -0.0100209 -0.0261409 -0.00341844 -0.00612675 -0.023003 0.0109423 -0.00282099 0.0203828 -0.0265252 0.0270202 0.0322998 -0.0362086 -0.00119129 -0.0153138 -0.00350063 0.00240223 -0.0210972 -0.00135233 -0.00711855 0.000712969 0.0123906 -0.00078104 0.000209776 0.0312843 -0.00727613 0.0274143 -0.0141633 -0.0350039 -0.0442454 0.0167168 -0.0482093 1.11671)) (5.08667 0.00434494 0.0292264 #(-0.00272251 0.00941567 0.00822995 -0.014127 -0.00472909 0.0256388 -0.0205545 -0.00637778 -0.0112651 0.0378657 -0.0158337 -0.00984417 0.00216444 0.030978 -0.00207667 -0.00625094 -0.00241573 0.000887676 -0.0113091 -0.0167408 -0.00726853 -0.00532588 -0.0106122 0.000375745 -0.00057362 0.0254724 -0.018358 0.0306097 0.0326059 -0.0225176 -0.0471872 0.00568396 -0.0101327 -0.0167238 -0.0112461 -0.0017848 -0.00424018 0.0120333 0.0037898 0.0135469 0.0227388 0.0193921 -0.0318962 0.0246949 -0.0262602 -0.0227707 -0.0672516 0.0572928 -0.0571018 1.11738)) (5.64243 0.00660276 0.0342082 #(0.00180166 0.00187813 0.00574493 -0.000219231 -0.0214208 0.0292124 -0.0171232 -0.0116133 0.0143524 -0.0080191 0.00040181 -0.000264368 0.00500117 0.0156718 0.00494422 0.00107104 -0.0174182 0.00156305 -0.00116767 -0.0143132 -0.00873124 0.00879861 -0.0235025 -0.00555377 0.0159542 0.0120798 -0.00968709 0.0101018 0.0241207 -0.0283285 -0.00464771 0.00488285 -0.0317064 0.000691314 -0.0122031 -0.0076785 0.00264264 0.00947001 0.0122303 0.00967777 0.0183964 0.00361356 -0.0121287 0.0116267 -0.0186891 -0.0143781 -0.0485434 0.0242676 -0.0335089 1.09521)) (4.34906 0.00506972 0.0341424 #(0.0023974 -0.00279862 0.0120042 -0.00157989 -0.0157521 0.0239786 -0.0126398 -0.0135926 -0.0020871 0.00151955 -0.00174203 -0.00773394 0.0159697 0.00780768 0.021657 0.00663021 -0.0142795 0.00149963 -0.00494957 -0.00158777 -0.0254905 -0.0117564 -0.017529 -0.00628616 0.00849666 0.00422017 -0.0116558 0.0310608 0.0345892 -0.0316539 -0.0132967 -0.00584913 0.00354922 -0.0173338 -0.0110622 -0.0096414 0.00859083 -0.0039589 0.0226801 0.0154026 0.00896204 0.0230092 0.00481482 0.00292927 -0.0234833 -0.0254714 -0.0981472 0.0441442 -0.0688532 1.14897)) (2.61565 0.00474862 0.0426083 #(0.00879548 -0.00707132 0.0105265 0.00589761 -0.0181165 0.0122799 0.000610275 -0.0196829 -0.011157 0.0120507 -0.0115164 -0.0105635 0.0167566 0.0110644 0.0208706 0.00165262 0.00444448 -0.00889109 -0.00448973 -0.00204069 -0.0176097 -0.0204983 -0.00444134 -0.0102928 -0.000729621 0.00828533 -0.0156112 0.0249824 0.046813 -0.034427 -0.0110774 -0.0109798 -0.00690826 -0.00195731 -0.0157386 -0.00195138 0.00642795 -0.00283065 0.0119922 0.0211103 0.0124749 0.0247881 0.0132657 -0.00455936 -0.0371286 -0.0106291 -0.0739445 0.0263266 -0.0843839 1.15059)) (2.02703 0.00255318 0.0354904 #(0.0134249 -0.00506588 0.00680395 0.0105582 -0.0323818 0.0493337 -0.0217674 -0.0241798 0.00928927 -0.023553 0.0104105 -0.0160771 0.00235487 0.00839372 0.0312377 0.00805041 0.000414273 -0.0136668 -0.0141831 0.0145558 -0.01835 -0.0176581 0.00780919 -0.0178566 -0.00798348 0.0228851 -0.0520132 0.0414188 0.066511 -0.0612651 0.00654983 -0.0331677 0.0129804 -0.0240143 0.0167766 -0.000209965 -0.0232557 0.0166038 0.0163538 0.0123617 -0.00410349 0.0241719 -0.00992855 0.0157116 -0.0186285 -0.0253129 -0.0767908 0.0521641 -0.0693304 1.12793)) (2.64432 0.00171959 0.0255009 #(-0.0191815 0.0127539 0.0107323 0.00105373 -0.0253985 0.0548691 -0.00350344 -0.0407332 0.00805417 -0.00516293 0.0269923 -0.0481122 0.045745 -0.00949443 0.029402 0.00253762 -0.0224486 0.00621702 -0.0126075 -0.000360755 -0.0107886 -0.00802914 -0.0263488 -0.00418882 0.00777657 0.0122917 -0.0655835 0.0318259 0.0745041 -0.046913 -0.0178272 -0.014913 0.00287156 -0.0266232 0.016267 0.00797917 0.00580041 0.0114133 0.00738462 0.0441676 -0.0136994 0.0335519 -0.0324743 0.0188773 -0.0348701 -0.0234333 -0.174669 0.177908 -0.0964444 1.12857)) (3.49525 0.0028907 0.0287582 #(-0.022997 0.00390569 0.0195987 -0.00368246 -0.0249804 0.0205793 -0.000749982 -0.0146779 0.0253093 -0.027436 -0.00506964 0.0229678 0.0122114 -0.00660955 0.0289347 0.00446956 -0.0240813 0.0124458 -0.000533498 -0.0357979 -0.00426894 0.00482643 -0.0216519 0.00376066 -0.0166858 0.0254196 -0.047756 0.0296842 0.05304 -0.053725 0.0233847 -0.00627376 -0.0327575 0.0242391 -0.00986949 0.0018908 0.0199183 -0.001377 0.00140167 0.0246927 0.00391399 0.00494078 -0.0242442 0.0174991 -0.0272264 -0.0343578 -0.0611368 0.0862893 -0.0566336 1.08269)) (3.59173 0.00241115 0.0259096 #(-0.0280463 0.00239539 0.0275002 -0.0139323 -0.0348279 0.0607939 -0.0263654 -0.0111383 0.00125177 0.0134574 -0.0201514 0.0256755 0.0152298 -0.0129894 0.040595 -0.0242227 0.0223003 -0.0198948 -0.00945686 -0.0104881 -0.0149074 0.000106048 -0.0155021 0.00164234 -0.0275243 0.0334275 -0.0597113 0.0490029 0.0458835 -0.0406038 -0.00296535 0.00162114 0.00027736 -0.0194494 0.0124248 -0.00222679 0.0104655 -0.00167292 0.00815926 0.0283748 -0.0225562 0.0143205 -0.0188394 0.00579293 -0.0147764 -0.0167599 -0.050156 0.0847534 -0.0659405 1.07315)) (2.26719 0.00255288 0.0335561 #(-0.0136514 -0.00925972 0.0167188 -0.00485284 -0.0336646 0.0412232 -0.000246899 -0.0298077 0.00712888 0.0134616 0.0103107 -0.00485241 -0.00127703 0.0164119 0.0132654 -0.019095 0.00456902 -0.00259853 -0.000275873 -0.0127027 -0.00593184 0.0101047 -0.0413224 0.018843 -0.0107773 0.0150738 -0.0289957 0.0254439 0.0380609 -0.0406301 -0.00392326 0.0172783 -0.00857435 -0.0223009 0.00749708 -0.0165367 0.0238457 0.018136 -0.00458933 0.00245699 0.00172918 0.00670983 -0.024566 0.00660529 -0.0205404 0.00950086 -0.0578217 0.0939725 -0.0510117 1.04425)) (0.609353 0.00163717 0.0518337 #(0.00316256 -0.0122567 0.00518264 0.0126123 -0.0397706 0.0392831 0.0116002 -0.0471934 0.00805918 -0.00560564 0.000558784 -0.00409364 -0.00452707 -0.00113856 0.0257756 -0.00932488 0.00381936 -0.00247659 0.00301922 0.00335715 -0.00619763 0.0345422 -0.0321831 0.00519092 -0.00104381 -0.021393 -0.028818 0.0308446 0.0615516 -0.0569711 -0.0213437 0.00541473 0.00891156 -0.00345845 -0.00526036 -0.0140875 0.0217332 0.0150425 0.00302012 0.000750344 -0.0227373 0.0355403 -0.0606219 0.0543924 -0.0197096 0.0106198 -0.0761164 0.133679 -0.0540805 1.00403)) (0.116473 0.000738204 0.0796116 #(-0.0020667 -0.00708028 0.00649903 0.00525495 -0.0577545 0.0708488 0.0241519 -0.0957537 0.0444855 0.00816514 -0.0260424 -0.00887706 0.0161092 -0.00643925 0.0365329 -0.0114855 -0.0214506 0.00323551 4.06337e-005 0.00984418 0.00579543 0.0340158 -0.0244511 -0.00303321 -0.0329481 0.0117391 -0.0672089 0.0657941 0.120411 -0.0823802 -0.0449917 0.00125354 0.00608117 -0.0209081 -0.0254859 0.0413741 -0.00546445 0.0228035 -0.0102555 0.0282721 -0.0411615 0.0264412 -0.0625765 0.0651369 -0.0960416 0.0914793 -0.12826 0.244372 -0.0968032 0.978677)) (0.0472545 0.000482073 0.101003 #(-0.0132409 -0.00177229 -0.00651967 0.0181785 -0.057867 0.0886454 -0.0060562 -0.0415304 -0.00604645 0.00809692 -0.0261498 0.0308232 -0.0207518 0.039377 0.0286866 -0.00414628 -0.101779 0.0925687 -0.0566329 0.0285281 -0.0124488 0.0429751 -0.0231868 0.00492606 -0.0382182 0.0353667 -0.0854897 0.072105 0.138783 -0.152908 0.0118608 -0.0236536 0.0280545 -0.0358662 -0.00158007 0.0410328 -0.0307116 0.0351427 -0.0487812 0.0650863 -0.105127 0.0931477 -0.118991 0.157664 -0.204664 0.186411 -0.180145 0.351459 -0.130844 0.92427)) (0.0200657 0.000490229 0.156305 #(-0.0167117 0.0226238 -0.0290179 0.0310399 -0.05596 0.0754746 -0.00102182 -0.0240663 -0.00557826 -0.00226293 0.00760277 0.00121096 -0.0371931 0.0368175 0.00439128 -0.00121828 -0.0701961 0.0851828 -0.0429475 0.0221135 -0.0202851 0.0294757 0.0173632 -0.014941 0.0101552 -0.0156045 -0.0714142 0.0373879 0.140392 -0.155288 0.0474913 -0.015392 0.010226 -0.0506144 0.00775825 0.0425248 -0.0111819 0.0198418 -0.0465491 0.0473969 -0.0958641 0.069069 -0.0800155 0.135248 -0.167486 0.159519 -0.163318 0.341011 -0.122999 0.899713)) (0.0189561 0.000463645 0.156394 #(0.0136824 -0.010146 -0.00340101 0.00501791 -0.052312 0.0825702 -0.0198587 -0.00941267 0.00742931 -0.00822124 -0.00559287 0.0070671 -0.0295775 0.0163785 -0.000200317 -0.0124918 -0.0388802 0.0517694 -0.0148913 -0.0019372 0.0130002 0.0529274 -0.051331 0.0468511 -0.0493757 0.0488883 -0.0877978 0.0390208 0.120372 -0.130924 0.00454228 0.0284801 -0.0370236 -0.0207961 0.00413483 0.0556726 -0.0461664 0.043992 -0.0572133 0.0680651 -0.129146 0.0933036 -0.0903923 0.0963898 -0.115223 0.173486 -0.16108 0.327376 -0.109485 0.877362)) (0.0157623 0.000457797 0.170422 #(0.00679172 0.0179331 -0.0180012 0.00985177 -0.0710897 0.0804711 -0.0138887 -0.00160079 -0.0130131 -0.0116605 -0.00195402 0.0102408 0.00544203 -0.00882841 -0.00664669 -0.000185585 -0.0333044 0.0571107 -0.0324269 0.00482369 0.00173713 0.0817342 -0.0689869 0.0314419 -0.0416472 0.0452527 -0.104628 0.0733021 0.109757 -0.112525 -0.040671 0.0457447 -0.033124 0.0189072 -0.0182032 0.0382207 -0.0430175 0.0633007 -0.0880582 0.0891837 -0.145313 0.126151 -0.130188 0.133809 -0.156576 0.210072 -0.192572 0.343954 -0.102867 0.867452)) (0.0193939 0.000457706 0.153625 #(-0.00460792 0.0355563 -0.0550596 0.043009 -0.0897849 0.0978742 -0.0187992 0.00582897 -0.0109002 0.000631806 -0.0163601 0.0133513 -0.0165699 0.0221935 -0.0312557 0.04581 -0.0629084 0.0434437 -0.0167021 0.0323193 -0.0250667 0.0627469 -0.0306966 -0.00490861 -0.0368386 0.0217197 -0.0728413 0.0668549 0.145474 -0.169416 0.0122649 0.00448438 0.013949 -0.0353851 0.020688 0.00875267 -0.0340474 0.0569403 -0.0747049 0.0865628 -0.127027 0.0997718 -0.118786 0.172951 -0.208013 0.216935 -0.215728 0.401293 -0.19069 0.923122)) (0.0267348 0.000456167 0.130624 #(0.0221721 0.012707 -0.0342673 0.0498141 -0.125798 0.0945948 -0.009383 -0.0118047 -0.00833615 0.0354772 -0.041698 0.0220065 -0.043747 0.0427328 -0.0334768 0.0279624 -0.0268537 0.00968139 0.00111546 0.0377293 -0.0348329 0.0808209 -0.0457136 0.00457449 -0.0453242 -0.0107467 -0.0188348 0.0300905 0.173791 -0.194862 0.0537233 -0.0419804 0.0496971 -0.0701674 0.0499813 -0.00747099 -0.0222291 0.0273433 -0.0549461 0.0661543 -0.122178 0.0944649 -0.101576 0.17229 -0.189446 0.207714 -0.21558 0.418696 -0.215629 0.931565)) (0.0200745 0.000471228 0.153212 #(0.0163527 0.00660207 -0.0143944 0.046632 -0.126296 0.118434 -0.0369965 -0.00451566 -0.0201182 0.0417401 -0.0308534 -0.00543496 -0.0172945 0.0438493 -0.0319897 -0.0176332 -0.00909391 0.00684448 0.00776292 0.0226499 -0.00129345 0.0597638 -0.057499 0.0439582 -0.0376084 -0.009205 -0.0282326 0.0349981 0.136497 -0.137021 0.0108061 -0.0220325 0.0138336 -0.0341895 0.00554748 0.0125278 -0.0174402 0.0430164 -0.0595981 0.048263 -0.112704 0.102835 -0.101221 0.15651 -0.167554 0.189205 -0.200076 0.383302 -0.1668 0.902884)) (0.0178948 0.000884452 0.222317 #(-0.00627428 0.017076 -0.0217517 0.0596357 -0.115011 0.137658 -0.140797 0.0413646 -0.025147 0.0409271 -0.0298679 0.0230878 -0.00804102 0.0133819 -0.0343905 0.081481 -0.0160831 0.031044 -0.0362416 0.0814956 -0.0892642 -0.0230409 -0.0232022 0.112084 -0.0729296 -0.0349948 0.00901226 -0.0373362 0.140441 -0.0702999 -0.00257567 -0.0348515 -0.00258082 0.0140751 -0.0718087 0.0880132 -0.061838 0.0690842 -0.118292 0.142831 -0.185955 0.190591 -0.155962 0.45873 -0.106312 0.127302 -0.523777 0.419269 -0.501987 1.22411)) (0.014956 0.000914502 0.247278 #(-0.023965 0.0260125 -0.0174047 0.0515138 -0.0830966 0.07056 -0.0839288 -0.00253678 0.0274258 -0.000953763 -0.00370321 0.0051892 0.0273904 -0.020619 -0.0100326 0.0564985 0.00785514 0.0225726 -0.0248022 0.0636671 -0.0849298 -0.0493795 0.0247842 0.0783257 -0.054683 -0.0485245 0.00161631 -0.0165824 0.139226 -0.0743001 -0.00122059 -0.0566757 0.0247024 0.00172735 -0.0647441 0.0783151 -0.0575751 0.0609131 -0.105484 0.127889 -0.170536 0.193175 -0.164876 0.462587 -0.105663 0.112055 -0.495609 0.396188 -0.497893 1.21815)) (0.00871568 0.000567858 0.255252 #(-0.0124666 0.0309579 -0.00109739 0.0135459 -0.057433 0.0477187 -0.0502651 0.00271826 0.0372547 0.0164188 -0.0446111 -0.0127535 -0.0377459 0.05085 -0.0332468 0.0648767 -0.0421368 0.0453716 -0.00560286 0.010505 -0.0502685 0.0272348 -0.0168195 0.0334298 -0.045445 0.0609193 -0.0939262 0.0603289 0.127758 -0.127759 -0.0161537 -0.0241133 0.0220789 0.0501327 -0.0297039 0.0276074 -0.0749799 0.0195223 -0.134458 0.0784379 -0.103965 0.143044 -0.0238226 0.243323 -0.14168 0.124602 -0.245754 0.281028 -0.225522 0.993662)) (0.0086891 0.000454286 0.228653 #(0.000182833 -0.00254678 0.0082363 -0.0153415 -0.0299224 0.0849131 -0.0489407 0.00623273 0.00330074 0.015936 -0.0400408 -0.020401 -0.0247914 0.0710104 -0.015902 0.00164445 -0.0397469 0.0223963 0.0144133 0.00597068 -0.0101367 0.0517253 -0.0400181 0.0204692 -0.0703128 0.0792271 -0.0877888 0.0647522 0.100521 -0.114483 -0.00566729 -0.0255629 0.0314529 0.0182582 -0.0152464 0.0337968 -0.0685177 0.0350596 -0.0735331 0.0771414 -0.107742 0.0609778 -0.0612328 0.122617 -0.132552 0.162598 -0.143835 0.327107 -0.115002 0.855719))) nyquist-3.05/jny0000755000175000000620000000005111510141774012706 0ustar stevestaff#!/bin/sh java -jar jnyqide/jNyqIDE.jar nyquist-3.05/macosxproject/0002755000175000000620000000000011537433126015053 5ustar stevestaffnyquist-3.05/macosxproject/NyquistIDE-Info.plist0000644000175000000620000000222611470226246021016 0ustar stevestaff CFBundleDevelopmentRegion English CFBundleExecutable NyquistIDE CFBundleIconFile Nyquist.icns CFBundleIdentifier edu.cmu.cs.nyquist CFBundleInfoDictionaryVersion 6.0 CFBundleName NyquistIDE CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 1.0 CFBundleShortVersionString 1.0 Java ClassPath $JAVAROOT/jnyqide.jar JVMVersion 1.5+ MainClass jnyqide.Main WorkingDirectory $JAVAROOT Properties apple.laf.useScreenMenuBar true nyquist-3.05/macosxproject/nyquist.pbproj/0002755000175000000620000000000011537433126020062 5ustar stevestaffnyquist-3.05/macosxproject/nyquist.pbproj/project.pbxproj0000644000175000000620000040372111466723256023152 0ustar stevestaff// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 38; objects = { 014CEA520018CE5811CA2923 = { buildRules = ( ); buildSettings = { COPY_PHASE_STRIP = NO; OPTIMIZATION_CFLAGS = "-O0"; }; isa = PBXBuildStyle; name = Development; }; 014CEA530018CE5811CA2923 = { buildRules = ( ); buildSettings = { COPY_PHASE_STRIP = YES; DEPLOYMENT_LOCATION = YES; DEPLOYMENT_POSTPROCESSING = YES; DSTROOT = /Users/rbd/tmp; }; isa = PBXBuildStyle; name = Deployment; }; //010 //011 //012 //013 //014 //030 //031 //032 //033 //034 034768E8FF38A79811DB9C8B = { isa = PBXExecutableFileReference; path = ny; refType = 3; }; //030 //031 //032 //033 //034 //080 //081 //082 //083 //084 08FB7793FE84155DC02AAC07 = { buildStyles = ( 014CEA520018CE5811CA2923, 014CEA530018CE5811CA2923, ); hasScannedForEncodings = 1; isa = PBXProject; mainGroup = 08FB7794FE84155DC02AAC07; projectDirPath = ""; targets = ( 08FB779FFE84155DC02AAC07, F5C6A9B703A10C0501029006, 3DF21F2604FD4FDC0002CE69, ); }; 08FB7794FE84155DC02AAC07 = { children = ( F5DA143903A1108C01029006, F510BDB903A0314301029006, F543F19F0375E1E401029006, 1AB674ADFE9D54B511CA2CBB, 3DA446C00789FF350002CE69, 3DA446C20789FF430002CE69, 3D676BB907CE68A90002CE69, ); isa = PBXGroup; name = MacOSXProject; refType = 4; }; 08FB7795FE84155DC02AAC07 = { children = ( 3D9E08110779F7050002CE69, 3D9E07E60779F63A0002CE69, F510BCA7039F84FD01029006, F510BCDA039F84FE01029006, F510BD73039FB49C01029006, F5FF5F48039D84B901029006, F5FF5F9E039D863401029006, F543EE570375CD5801029006, 3D35A7C405690E180002CE69, F5FF60A6039D87B001029006, F543EF940375CD8D01029006, F543EF3D0375CD7101029006, F543EF990375CD9901029006, 3DF21F3104FD526A0002CE69, ); isa = PBXGroup; name = nyquist; path = ..; refType = 2; }; 08FB779FFE84155DC02AAC07 = { buildPhases = ( 08FB77A0FE84155DC02AAC07, 08FB77A1FE84155DC02AAC07, 08FB77A3FE84155DC02AAC07, 08FB77A5FE84155DC02AAC07, C6A0FF2D029079AD04C91782, ); buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "\"$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers\" ../fft ../snd ../cmt ../sys/unix ../xlisp ../tran ../nyqsrc ../nyqstk/include ../pa/pa_common"; LIBRARY_SEARCH_PATHS = ""; OPTIMIZATION_CFLAGS = "-O3"; OTHER_CFLAGS = "-DCMTSTUFF -Dmacintosh -DPA_USE_COREAUDIO"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = ny; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; }; dependencies = ( ); isa = PBXToolTarget; name = Nyquist; productName = MacOSXProject; productReference = 034768E8FF38A79811DB9C8B; }; 08FB77A0FE84155DC02AAC07 = { buildActionMask = 2147483647; files = ( F543EF980375CD8D01029006, F5FF5F84039D84DB01029006, F5FF5F86039D84DF01029006, F5FF5F92039D850B01029006, F5FF6010039D866201029006, F5FF6012039D866201029006, F5FF6014039D866201029006, F5FF6016039D866201029006, F5FF6018039D866201029006, F5FF601A039D866201029006, F5FF601C039D866201029006, F5FF601E039D866201029006, F5FF6020039D866201029006, F5FF6022039D866201029006, F5FF6024039D866201029006, F5FF6026039D866201029006, F5FF6028039D866201029006, F5FF602A039D866201029006, F5FF602C039D866201029006, F5FF6030039D866201029006, F5FF6034039D866201029006, F5FF6036039D866201029006, F5FF6038039D866201029006, F5FF603A039D866201029006, F5FF603C039D866201029006, F5FF603E039D866201029006, F5FF6040039D866201029006, F5FF6042039D866201029006, F5FF6044039D866201029006, F5FF6046039D866201029006, F5FF6048039D866201029006, F5FF604A039D866201029006, F5FF604C039D866201029006, F5FF604E039D866201029006, F5FF6050039D866201029006, F5FF6052039D866201029006, F5FF6054039D866201029006, F5FF6056039D866201029006, F5FF605A039D866201029006, F5FF605C039D866201029006, F5FF605E039D866201029006, F5FF6060039D866201029006, F5FF6062039D866201029006, F5FF6064039D866201029006, F5FF6066039D866201029006, F5FF6068039D866201029006, F5FF606A039D866201029006, F5FF606C039D866201029006, F5FF606E039D866201029006, F5FF6070039D866201029006, F5FF6072039D866201029006, F5FF6074039D866201029006, F5FF6076039D866201029006, F5FF6078039D866201029006, F5FF607A039D866201029006, F5FF607C039D866201029006, F5FF6085039D871B01029006, F5FF6087039D871E01029006, F5FF6089039D872001029006, F5FF608B039D872301029006, F5FF608D039D873001029006, F5FF608F039D873501029006, F5FF6091039D874001029006, F5FF6093039D874101029006, F5FF6095039D874601029006, F5FF6097039D874E01029006, F5FF6099039D875301029006, F5FF609C039D875F01029006, F5FF609D039D876001029006, F5FF609F039D876401029006, F5FF60A1039D876B01029006, F5FF60A3039D876D01029006, F5FF60A5039D876F01029006, F5FF612E039D87DC01029006, F5FF6130039D87E101029006, F5FF6132039D87E601029006, F5FF6135039D87EF01029006, F5FF613A039D87FE01029006, F5FF613B039D880001029006, F5FF613D039D880401029006, F5FF613F039D880901029006, F5FF6141039D880E01029006, F5FF6143039D881C01029006, F5FF6145039D882001029006, F5FF6147039D882901029006, F5FF6149039D884301029006, F5FF614B039D885401029006, F5FF614F039D885D01029006, F5FF6151039D886201029006, F5FF6153039D886D01029006, F5FF6155039D887501029006, F5FF6157039D887B01029006, F5FF6159039D888201029006, F5FF615B039D888601029006, F5FF6160039D899F01029006, F5FF6161039D899F01029006, F5FF6166039D89B101029006, F5FF6167039D89B101029006, F5FF616C039D8A5401029006, F5FF6172039D8A6C01029006, F5779DA4039D8E1901029006, F5779DB1039D99D901029006, 3D9867CF04FFDD6B0002CE69, 3D9867DA050920140002CE69, 3D9867DC0509202C0002CE69, 3D9867E0050920400002CE69, 3D9867E4050920730002CE69, 3D9E07DF0779F4800002CE69, 3D9E07E30779F4DC0002CE69, 3D9E07FC0779F6820002CE69, 3D9E07FE0779F6820002CE69, 3D9E08000779F6820002CE69, 3D9E08020779F6820002CE69, 3D9E08030779F6820002CE69, 3D9E08050779F6820002CE69, 3D9E08070779F6820002CE69, 3D9E080A0779F6820002CE69, 3D9E080C0779F6820002CE69, 3D9E080D0779F6820002CE69, 3D9E080E0779F6820002CE69, 3D9E08130779F7370002CE69, 3D9E08150779F74D0002CE69, 3D9E08230779F7680002CE69, 3D9E08240779F7680002CE69, 3D9E08250779F7680002CE69, 3D9E08260779F7680002CE69, 3D9E08270779F7680002CE69, 3D9E08280779F7680002CE69, 3D9E08290779F7680002CE69, 3D9E082A0779F7680002CE69, 3D9E082B0779F7680002CE69, 3D9E082D0779F7680002CE69, 3D9E082E0779F7680002CE69, 3D9E082F0779F7680002CE69, 3D9E08330779F78B0002CE69, 3D9E0851077C6FC00002CE69, 3D9E086D0789D6000002CE69, 3D9E08710789D81B0002CE69, 3D9E08750789D82F0002CE69, 3D9E08790789D8520002CE69, 3D9E087D0789D8B20002CE69, 3D9E08810789D8CF0002CE69, 3D9E08850789D8E70002CE69, 3D9E08890789D9100002CE69, 3D9E088D0789D9230002CE69, 3D9E08910789D9430002CE69, 3D9E08950789D9680002CE69, 3D6032F40790A48F007A3CA5, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 08FB77A1FE84155DC02AAC07 = { buildActionMask = 2147483647; files = ( F543EF970375CD8D01029006, F543F0100375CD9901029006, F5FF5F83039D84DB01029006, F5FF5F85039D84DF01029006, F5FF5F87039D84E301029006, F5FF5F88039D84E801029006, F5FF5F89039D84EF01029006, F5FF5F8A039D84F301029006, F5FF5F8B039D84F701029006, F5FF5F8C039D84FB01029006, F5FF5F8D039D84FE01029006, F5FF5F8E039D850301029006, F5FF5F8F039D850701029006, F5FF5F90039D850801029006, F5FF5F91039D850A01029006, F5FF5F93039D850E01029006, F5FF5F94039D851101029006, F5FF5F95039D851201029006, F5FF5F96039D851501029006, F5FF5F97039D851801029006, F5FF5F98039D851A01029006, F5FF5F99039D851D01029006, F5FF5F9A039D852201029006, F5FF5F9B039D852301029006, F5FF5F9C039D852401029006, F5FF5F9D039D852601029006, F5FF600F039D866201029006, F5FF6011039D866201029006, F5FF6013039D866201029006, F5FF6015039D866201029006, F5FF6017039D866201029006, F5FF6019039D866201029006, F5FF601B039D866201029006, F5FF601D039D866201029006, F5FF601F039D866201029006, F5FF6021039D866201029006, F5FF6023039D866201029006, F5FF6025039D866201029006, F5FF6027039D866201029006, F5FF6029039D866201029006, F5FF602B039D866201029006, F5FF602F039D866201029006, F5FF6033039D866201029006, F5FF6035039D866201029006, F5FF6037039D866201029006, F5FF6039039D866201029006, F5FF603B039D866201029006, F5FF603D039D866201029006, F5FF603F039D866201029006, F5FF6041039D866201029006, F5FF6043039D866201029006, F5FF6045039D866201029006, F5FF6047039D866201029006, F5FF6049039D866201029006, F5FF604B039D866201029006, F5FF604D039D866201029006, F5FF604F039D866201029006, F5FF6051039D866201029006, F5FF6053039D866201029006, F5FF6055039D866201029006, F5FF6059039D866201029006, F5FF605B039D866201029006, F5FF605D039D866201029006, F5FF605F039D866201029006, F5FF6061039D866201029006, F5FF6063039D866201029006, F5FF6065039D866201029006, F5FF6067039D866201029006, F5FF6069039D866201029006, F5FF606B039D866201029006, F5FF606D039D866201029006, F5FF606F039D866201029006, F5FF6071039D866201029006, F5FF6073039D866201029006, F5FF6075039D866201029006, F5FF6077039D866201029006, F5FF6079039D866201029006, F5FF607B039D866201029006, F5FF6084039D871B01029006, F5FF6086039D871D01029006, F5FF6088039D872001029006, F5FF608A039D872301029006, F5FF608C039D872E01029006, F5FF608E039D873401029006, F5FF6090039D873F01029006, F5FF6092039D874101029006, F5FF6094039D874501029006, F5FF6096039D874D01029006, F5FF6098039D875201029006, F5FF609A039D875B01029006, F5FF609B039D875E01029006, F5FF609E039D876301029006, F5FF60A0039D876B01029006, F5FF60A2039D876C01029006, F5FF60A4039D876F01029006, F5FF612D039D87DC01029006, F5FF612F039D87E001029006, F5FF6131039D87E401029006, F5FF6133039D87E801029006, F5FF6134039D87EE01029006, F5FF6136039D87F301029006, F5FF6138039D87F801029006, F5FF6139039D87FD01029006, F5FF613C039D880301029006, F5FF613E039D880801029006, F5FF6140039D880D01029006, F5FF6142039D881B01029006, F5FF6144039D881F01029006, F5FF6146039D882701029006, F5FF6148039D884201029006, F5FF614A039D885301029006, F5FF614C039D885701029006, F5FF614E039D885C01029006, F5FF6150039D886101029006, F5FF6152039D886C01029006, F5FF6154039D887401029006, F5FF6156039D887A01029006, F5FF6158039D888101029006, F5FF615A039D888601029006, F5FF615F039D899F01029006, F5FF6165039D89B101029006, F5FF616A039D8A3701029006, F5FF616F039D8A5C01029006, F5FF6170039D8A6601029006, F5FF6171039D8A6B01029006, F5779DA8039D8E9501029006, F5779DB2039D99DA01029006, 3D9867CD04FFDD3C0002CE69, 3D9867D104FFDDA30002CE69, 3D9867D204FFDDAC0002CE69, 3D9867D404FFE8E20002CE69, 3D9867D605091F760002CE69, 3D9867D8050920060002CE69, 3D9867DF050920400002CE69, 3D9867E3050920730002CE69, 3D9867E6050921720002CE69, 3D9E07DE0779F4800002CE69, 3D9E07E20779F4DC0002CE69, 3D9E07E50779F61B0002CE69, 3D9E07FB0779F6820002CE69, 3D9E07FD0779F6820002CE69, 3D9E07FF0779F6820002CE69, 3D9E08010779F6820002CE69, 3D9E08040779F6820002CE69, 3D9E08060779F6820002CE69, 3D9E08080779F6820002CE69, 3D9E08090779F6820002CE69, 3D9E080B0779F6820002CE69, 3D9E08100779F6A20002CE69, 3D9E08320779F78B0002CE69, 3D9E08350779F7A30002CE69, 3D9E08420779F7B80002CE69, 3D9E08430779F7B80002CE69, 3D9E08440779F7B80002CE69, 3D9E08450779F7B80002CE69, 3D9E08460779F7B80002CE69, 3D9E08470779F7B80002CE69, 3D9E08480779F7B80002CE69, 3D9E08490779F7B80002CE69, 3D9E084A0779F7B80002CE69, 3D9E084B0779F7B80002CE69, 3D9E084C0779F7B80002CE69, 3D9E084D0779F7B80002CE69, 3D9E0850077C6FC00002CE69, 3D9E086C0789D6000002CE69, 3D9E08700789D81B0002CE69, 3D9E08740789D82F0002CE69, 3D9E08780789D8520002CE69, 3D9E087C0789D8B20002CE69, 3D9E08800789D8CF0002CE69, 3D9E08840789D8E70002CE69, 3D9E08880789D9100002CE69, 3D9E088C0789D9230002CE69, 3D9E08900789D9430002CE69, 3D9E08940789D9680002CE69, 3D9E08970789D9E30002CE69, 3D6032F30790A48F007A3CA5, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 08FB77A3FE84155DC02AAC07 = { buildActionMask = 2147483647; files = ( 3DA446C10789FF350002CE69, 3DA446C30789FF430002CE69, ); isa = PBXFrameworksBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 08FB77A5FE84155DC02AAC07 = { buildActionMask = 2147483647; files = ( ); isa = PBXRezBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; //080 //081 //082 //083 //084 //1A0 //1A1 //1A2 //1A3 //1A4 1AB674ADFE9D54B511CA2CBB = { children = ( 034768E8FF38A79811DB9C8B, F5C6A9B803A10C0501029006, 3DF21F2704FD4FDC0002CE69, ); isa = PBXGroup; name = Products; refType = 4; }; //1A0 //1A1 //1A2 //1A3 //1A4 //3D0 //3D1 //3D2 //3D3 //3D4 3D35A7C405690E180002CE69 = { children = ( 3D35A7C505690E180002CE69, 3D6032F50790A600007A3CA5, 3D35A7C605690E180002CE69, 3D35A7C705690E180002CE69, 3D35A7C805690E180002CE69, 3D35A7C905690E180002CE69, 3D35A7CA05690E180002CE69, 3D6032F80790A618007A3CA5, 3D35A7CB05690E180002CE69, 3D35A7CC05690E180002CE69, 3D35A7CD05690E180002CE69, 3D35A7CE05690E180002CE69, 3D35A7CF05690E180002CE69, 3D35A7D005690E180002CE69, 3D35A7D105690E180002CE69, 3D6032FA0790A62C007A3CA5, 3D35A7D205690E180002CE69, 3D35A7D305690E180002CE69, 3D36DDE60796D6D40002CE69, ); isa = PBXGroup; path = jnyqide; refType = 4; }; 3D35A7C505690E180002CE69 = { isa = PBXFileReference; path = closeFile.gif; refType = 4; }; 3D35A7C605690E180002CE69 = { isa = PBXFileReference; path = help.gif; refType = 4; }; 3D35A7C705690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = LispFileFilter.java; refType = 4; }; 3D35A7C805690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = Main.java; refType = 4; }; 3D35A7C905690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = MainFrame.java; refType = 4; }; 3D35A7CA05690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = MainFrame_AboutBox.java; refType = 4; }; 3D35A7CB05690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = NyqPlot.java; refType = 4; }; 3D35A7CC05690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = NyquistFile.java; refType = 4; }; 3D35A7CD05690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = NyquistThread.java; refType = 4; }; 3D35A7CE05690E180002CE69 = { isa = PBXFileReference; path = openFile.gif; refType = 4; }; 3D35A7CF05690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = Pair.java; refType = 4; }; 3D35A7D005690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = PlotFrame.java; refType = 4; }; 3D35A7D105690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = PlotMouseAdapter.java; refType = 4; }; 3D35A7D205690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = SyntaxThread.java; refType = 4; }; 3D35A7D305690E180002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = TextColor.java; refType = 4; }; 3D35A7D405690E180002CE69 = { fileRef = 3D35A7C505690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7D505690E180002CE69 = { fileRef = 3D35A7C605690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7D605690E180002CE69 = { fileRef = 3D35A7C705690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7D705690E180002CE69 = { fileRef = 3D35A7C805690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7D805690E180002CE69 = { fileRef = 3D35A7C905690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7D905690E180002CE69 = { fileRef = 3D35A7CA05690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7DA05690E180002CE69 = { fileRef = 3D35A7CB05690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7DB05690E180002CE69 = { fileRef = 3D35A7CC05690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7DC05690E180002CE69 = { fileRef = 3D35A7CD05690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7DD05690E180002CE69 = { fileRef = 3D35A7CE05690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7DE05690E180002CE69 = { fileRef = 3D35A7CF05690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7DF05690E180002CE69 = { fileRef = 3D35A7D005690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7E005690E180002CE69 = { fileRef = 3D35A7D105690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7E105690E180002CE69 = { fileRef = 3D35A7D205690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D35A7E205690E180002CE69 = { fileRef = 3D35A7D305690E180002CE69; isa = PBXBuildFile; settings = { }; }; 3D36DDE60796D6D40002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = keywords.txt; refType = 4; }; 3D36DDE70796D6D40002CE69 = { fileRef = 3D36DDE60796D6D40002CE69; isa = PBXBuildFile; settings = { }; }; 3D36DDEC0796D71B0002CE69 = { fileRef = F510BD73039FB49C01029006; isa = PBXBuildFile; settings = { }; }; 3D36DDED0796E1AB0002CE69 = { fileRef = F510BCDA039F84FE01029006; isa = PBXBuildFile; settings = { }; }; 3D36DDEE0796E5CA0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = run; path = osx/run; refType = 4; }; 3D36DDEF0796E5CA0002CE69 = { fileRef = 3D36DDEE0796E5CA0002CE69; isa = PBXBuildFile; settings = { }; }; 3D36DDF00796E5DE0002CE69 = { children = ( 3D36DDEE0796E5CA0002CE69, 3D36DDF20796E60F0002CE69, ); isa = PBXGroup; name = osx; refType = 4; }; 3D36DDF10796E5E80002CE69 = { fileRef = 3D36DDEE0796E5CA0002CE69; isa = PBXBuildFile; settings = { }; }; 3D36DDF20796E60F0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = system.lsp; path = osx/system.lsp; refType = 4; }; 3D36DDF30796E60F0002CE69 = { fileRef = 3D36DDF20796E60F0002CE69; isa = PBXBuildFile; settings = { }; }; 3D36DDF40796E6170002CE69 = { fileRef = 3D36DDF20796E60F0002CE69; isa = PBXBuildFile; settings = { }; }; 3D6032F10790A48F007A3CA5 = { fileEncoding = 30; isa = PBXFileReference; name = ringofframes.c; path = portaudio/pa_mac_core/ringofframes.c; refType = 4; }; 3D6032F20790A48F007A3CA5 = { fileEncoding = 30; isa = PBXFileReference; name = ringofframes.h; path = portaudio/pa_mac_core/ringofframes.h; refType = 4; }; 3D6032F30790A48F007A3CA5 = { fileRef = 3D6032F10790A48F007A3CA5; isa = PBXBuildFile; settings = { }; }; 3D6032F40790A48F007A3CA5 = { fileRef = 3D6032F20790A48F007A3CA5; isa = PBXBuildFile; settings = { }; }; 3D6032F50790A600007A3CA5 = { fileEncoding = 30; isa = PBXFileReference; path = FindDialog.java; refType = 4; }; 3D6032F60790A600007A3CA5 = { fileRef = 3D6032F50790A600007A3CA5; isa = PBXBuildFile; settings = { }; }; 3D6032F80790A618007A3CA5 = { fileEncoding = 30; isa = PBXFileReference; path = NotFoundDialog.java; refType = 4; }; 3D6032F90790A618007A3CA5 = { fileRef = 3D6032F80790A618007A3CA5; isa = PBXBuildFile; settings = { }; }; 3D6032FA0790A62C007A3CA5 = { fileEncoding = 30; isa = PBXFileReference; path = ReplaceDialog.java; refType = 4; }; 3D6032FB0790A62C007A3CA5 = { fileRef = 3D6032FA0790A62C007A3CA5; isa = PBXBuildFile; settings = { }; }; 3D676BB907CE68A90002CE69 = { fileEncoding = 4; isa = PBXFileReference; name = xlisppath; path = /Users/rbd/nyquist/xlisppath; refType = 0; }; 3D9867CC04FFDD3C0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = tapf.c; refType = 4; }; 3D9867CD04FFDD3C0002CE69 = { fileRef = 3D9867CC04FFDD3C0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867CE04FFDD6B0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = tapf.h; refType = 4; }; 3D9867CF04FFDD6B0002CE69 = { fileRef = 3D9867CE04FFDD6B0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867D104FFDDA30002CE69 = { fileRef = F53626EE03761E6C01029006; isa = PBXBuildFile; settings = { }; }; 3D9867D204FFDDAC0002CE69 = { fileRef = F543EF4A0375CD7101029006; isa = PBXBuildFile; settings = { }; }; 3D9867D304FFE8E20002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = term.c; refType = 4; }; 3D9867D404FFE8E20002CE69 = { fileRef = 3D9867D304FFE8E20002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867D505091F760002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = yin.c; refType = 4; }; 3D9867D605091F760002CE69 = { fileRef = 3D9867D505091F760002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867D7050920060002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = alpasscv.c; path = ../tran/alpasscv.c; refType = 4; }; 3D9867D8050920060002CE69 = { fileRef = 3D9867D7050920060002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867D9050920140002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = yin.h; refType = 4; }; 3D9867DA050920140002CE69 = { fileRef = 3D9867D9050920140002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867DB0509202C0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = alpasscv.h; path = ../tran/alpasscv.h; refType = 4; }; 3D9867DC0509202C0002CE69 = { fileRef = 3D9867DB0509202C0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867DD050920400002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = alpassvv.c; path = ../tran/alpassvv.c; refType = 4; }; 3D9867DE050920400002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = alpassvv.h; path = ../tran/alpassvv.h; refType = 4; }; 3D9867DF050920400002CE69 = { fileRef = 3D9867DD050920400002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867E0050920400002CE69 = { fileRef = 3D9867DE050920400002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867E1050920730002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = eqbandvvv.c; path = ../tran/eqbandvvv.c; refType = 4; }; 3D9867E2050920730002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = eqbandvvv.h; path = ../tran/eqbandvvv.h; refType = 4; }; 3D9867E3050920730002CE69 = { fileRef = 3D9867E1050920730002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867E4050920730002CE69 = { fileRef = 3D9867E2050920730002CE69; isa = PBXBuildFile; settings = { }; }; 3D9867E5050921720002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = path.c; path = ../xlisp/path.c; refType = 4; }; 3D9867E6050921720002CE69 = { fileRef = 3D9867E5050921720002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07DC0779F4800002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = convolve.c; refType = 4; }; 3D9E07DD0779F4800002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = convolve.h; refType = 4; }; 3D9E07DE0779F4800002CE69 = { fileRef = 3D9E07DC0779F4800002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07DF0779F4800002CE69 = { fileRef = 3D9E07DD0779F4800002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07E00779F4DC0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = delaycc.c; refType = 4; }; 3D9E07E10779F4DC0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = delaycc.h; refType = 4; }; 3D9E07E20779F4DC0002CE69 = { fileRef = 3D9E07E00779F4DC0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07E30779F4DC0002CE69 = { fileRef = 3D9E07E10779F4DC0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07E40779F61B0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_mac_hostapis.c; path = portaudio/pa_mac/pa_mac_hostapis.c; refType = 4; }; 3D9E07E50779F61B0002CE69 = { fileRef = 3D9E07E40779F61B0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07E60779F63A0002CE69 = { children = ( 3D9E07E70779F6820002CE69, 3D9E07E80779F6820002CE69, 3D9E07E90779F6820002CE69, 3D9E07EA0779F6820002CE69, 3D9E07EB0779F6820002CE69, 3D9E07EC0779F6820002CE69, 3D9E07ED0779F6820002CE69, 3D9E07EE0779F6820002CE69, 3D9E07EF0779F6820002CE69, 3D9E07F00779F6820002CE69, 3D9E07F10779F6820002CE69, 3D9E07F20779F6820002CE69, 3D9E07F30779F6820002CE69, 3D9E07F40779F6820002CE69, 3D9E07F50779F6820002CE69, 3D9E07F60779F6820002CE69, 3D9E07F70779F6820002CE69, 3D9E07F80779F6820002CE69, 3D9E07F90779F6820002CE69, 3D9E07FA0779F6820002CE69, 3D9E080F0779F6A20002CE69, 3D9E07E40779F61B0002CE69, 3D6032F10790A48F007A3CA5, 3D6032F20790A48F007A3CA5, ); isa = PBXGroup; name = portaudio; refType = 4; }; 3D9E07E70779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_allocation.c; path = portaudio/pa_common/pa_allocation.c; refType = 4; }; 3D9E07E80779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_allocation.h; path = portaudio/pa_common/pa_allocation.h; refType = 4; }; 3D9E07E90779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_converters.c; path = portaudio/pa_common/pa_converters.c; refType = 4; }; 3D9E07EA0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_converters.h; path = portaudio/pa_common/pa_converters.h; refType = 4; }; 3D9E07EB0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_cpuload.c; path = portaudio/pa_common/pa_cpuload.c; refType = 4; }; 3D9E07EC0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_cpuload.h; path = portaudio/pa_common/pa_cpuload.h; refType = 4; }; 3D9E07ED0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_dither.c; path = portaudio/pa_common/pa_dither.c; refType = 4; }; 3D9E07EE0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_dither.h; path = portaudio/pa_common/pa_dither.h; refType = 4; }; 3D9E07EF0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_endianness.h; path = portaudio/pa_common/pa_endianness.h; refType = 4; }; 3D9E07F00779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_front.c; path = portaudio/pa_common/pa_front.c; refType = 4; }; 3D9E07F10779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_hostapi.h; path = portaudio/pa_common/pa_hostapi.h; refType = 4; }; 3D9E07F20779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_process.c; path = portaudio/pa_common/pa_process.c; refType = 4; }; 3D9E07F30779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_process.h; path = portaudio/pa_common/pa_process.h; refType = 4; }; 3D9E07F40779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_skeleton.c; path = portaudio/pa_common/pa_skeleton.c; refType = 4; }; 3D9E07F50779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_stream.c; path = portaudio/pa_common/pa_stream.c; refType = 4; }; 3D9E07F60779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_stream.h; path = portaudio/pa_common/pa_stream.h; refType = 4; }; 3D9E07F70779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_trace.c; path = portaudio/pa_common/pa_trace.c; refType = 4; }; 3D9E07F80779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_trace.h; path = portaudio/pa_common/pa_trace.h; refType = 4; }; 3D9E07F90779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_util.h; path = portaudio/pa_common/pa_util.h; refType = 4; }; 3D9E07FA0779F6820002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = portaudio.h; path = portaudio/pa_common/portaudio.h; refType = 4; }; 3D9E07FB0779F6820002CE69 = { fileRef = 3D9E07E70779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07FC0779F6820002CE69 = { fileRef = 3D9E07E80779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07FD0779F6820002CE69 = { fileRef = 3D9E07E90779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07FE0779F6820002CE69 = { fileRef = 3D9E07EA0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E07FF0779F6820002CE69 = { fileRef = 3D9E07EB0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08000779F6820002CE69 = { fileRef = 3D9E07EC0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08010779F6820002CE69 = { fileRef = 3D9E07ED0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08020779F6820002CE69 = { fileRef = 3D9E07EE0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08030779F6820002CE69 = { fileRef = 3D9E07EF0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08040779F6820002CE69 = { fileRef = 3D9E07F00779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08050779F6820002CE69 = { fileRef = 3D9E07F10779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08060779F6820002CE69 = { fileRef = 3D9E07F20779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08070779F6820002CE69 = { fileRef = 3D9E07F30779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08080779F6820002CE69 = { fileRef = 3D9E07F40779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08090779F6820002CE69 = { fileRef = 3D9E07F50779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E080A0779F6820002CE69 = { fileRef = 3D9E07F60779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E080B0779F6820002CE69 = { fileRef = 3D9E07F70779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E080C0779F6820002CE69 = { fileRef = 3D9E07F80779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E080D0779F6820002CE69 = { fileRef = 3D9E07F90779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E080E0779F6820002CE69 = { fileRef = 3D9E07FA0779F6820002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E080F0779F6A20002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_mac_core.c; path = portaudio/pa_mac_core/pa_mac_core.c; refType = 4; }; 3D9E08100779F6A20002CE69 = { fileRef = 3D9E080F0779F6A20002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08110779F7050002CE69 = { children = ( 3D9E08120779F7370002CE69, 3D9E08140779F74C0002CE69, 3D9E08160779F7680002CE69, 3D9E08170779F7680002CE69, 3D9E08180779F7680002CE69, 3D9E08190779F7680002CE69, 3D9E081A0779F7680002CE69, 3D9E081B0779F7680002CE69, 3D9E081C0779F7680002CE69, 3D9E081D0779F7680002CE69, 3D9E081E0779F7680002CE69, 3D9E081F0779F7680002CE69, 3D9E08300779F78B0002CE69, 3D9E08310779F78B0002CE69, 3D9E08340779F7A30002CE69, 3D9E08360779F7B80002CE69, 3D9E08370779F7B80002CE69, 3D9E08380779F7B80002CE69, 3D9E08390779F7B80002CE69, 3D9E083A0779F7B80002CE69, 3D9E083B0779F7B80002CE69, 3D9E083C0779F7B80002CE69, 3D9E083D0779F7B80002CE69, 3D9E083E0779F7B80002CE69, 3D9E083F0779F7B80002CE69, 3D9E08400779F7B80002CE69, 3D9E08410779F7B80002CE69, 3D9E084E077C6FC00002CE69, 3D9E084F077C6FC00002CE69, 3D9E08200779F7680002CE69, 3D9E08210779F7680002CE69, 3D9E08220779F7680002CE69, ); isa = PBXGroup; name = stk; refType = 4; }; 3D9E08120779F7370002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Clarinet.h; path = nyqstk/include/Clarinet.h; refType = 4; }; 3D9E08130779F7370002CE69 = { fileRef = 3D9E08120779F7370002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08140779F74C0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = globals.h; path = nyqstk/globals.h; refType = 4; }; 3D9E08150779F74D0002CE69 = { fileRef = 3D9E08140779F74C0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08160779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Delay.h; path = nyqstk/include/Delay.h; refType = 4; }; 3D9E08170779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = DelayL.h; path = nyqstk/include/DelayL.h; refType = 4; }; 3D9E08180779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Envelope.h; path = nyqstk/include/Envelope.h; refType = 4; }; 3D9E08190779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Filter.h; path = nyqstk/include/Filter.h; refType = 4; }; 3D9E081A0779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Instrmnt.h; path = nyqstk/include/Instrmnt.h; refType = 4; }; 3D9E081B0779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Noise.h; path = nyqstk/include/Noise.h; refType = 4; }; 3D9E081C0779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = OneZero.h; path = nyqstk/include/OneZero.h; refType = 4; }; 3D9E081D0779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = ReedTabl.h; path = nyqstk/include/ReedTabl.h; refType = 4; }; 3D9E081E0779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Saxofony.h; path = nyqstk/include/Saxofony.h; refType = 4; }; 3D9E081F0779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = SKINI.msg; path = nyqstk/include/SKINI.msg; refType = 4; }; 3D9E08200779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Stk.h; path = nyqstk/include/Stk.h; refType = 4; }; 3D9E08210779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = WaveLoop.h; path = nyqstk/include/WaveLoop.h; refType = 4; }; 3D9E08220779F7680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = WvIn.h; path = nyqstk/include/WvIn.h; refType = 4; }; 3D9E08230779F7680002CE69 = { fileRef = 3D9E08160779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08240779F7680002CE69 = { fileRef = 3D9E08170779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08250779F7680002CE69 = { fileRef = 3D9E08180779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08260779F7680002CE69 = { fileRef = 3D9E08190779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08270779F7680002CE69 = { fileRef = 3D9E081A0779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08280779F7680002CE69 = { fileRef = 3D9E081B0779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08290779F7680002CE69 = { fileRef = 3D9E081C0779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E082A0779F7680002CE69 = { fileRef = 3D9E081D0779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E082B0779F7680002CE69 = { fileRef = 3D9E081E0779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E082C0779F7680002CE69 = { fileRef = 3D9E081F0779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E082D0779F7680002CE69 = { fileRef = 3D9E08200779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E082E0779F7680002CE69 = { fileRef = 3D9E08210779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E082F0779F7680002CE69 = { fileRef = 3D9E08220779F7680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08300779F78B0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instr.cpp; path = nyqstk/instr.cpp; refType = 4; }; 3D9E08310779F78B0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instr.h; path = nyqstk/instr.h; refType = 4; }; 3D9E08320779F78B0002CE69 = { fileRef = 3D9E08300779F78B0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08330779F78B0002CE69 = { fileRef = 3D9E08310779F78B0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08340779F7A30002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Clarinet.cpp; path = nyqstk/src/Clarinet.cpp; refType = 4; }; 3D9E08350779F7A30002CE69 = { fileRef = 3D9E08340779F7A30002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08360779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Delay.cpp; path = nyqstk/src/Delay.cpp; refType = 4; }; 3D9E08370779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = DelayL.cpp; path = nyqstk/src/DelayL.cpp; refType = 4; }; 3D9E08380779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Envelope.cpp; path = nyqstk/src/Envelope.cpp; refType = 4; }; 3D9E08390779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Filter.cpp; path = nyqstk/src/Filter.cpp; refType = 4; }; 3D9E083A0779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Instrmnt.cpp; path = nyqstk/src/Instrmnt.cpp; refType = 4; }; 3D9E083B0779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Noise.cpp; path = nyqstk/src/Noise.cpp; refType = 4; }; 3D9E083C0779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = OneZero.cpp; path = nyqstk/src/OneZero.cpp; refType = 4; }; 3D9E083D0779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = ReedTabl.cpp; path = nyqstk/src/ReedTabl.cpp; refType = 4; }; 3D9E083E0779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Saxofony.cpp; path = nyqstk/src/Saxofony.cpp; refType = 4; }; 3D9E083F0779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = Stk.cpp; path = nyqstk/src/Stk.cpp; refType = 4; }; 3D9E08400779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = WaveLoop.cpp; path = nyqstk/src/WaveLoop.cpp; refType = 4; }; 3D9E08410779F7B80002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = WvIn.cpp; path = nyqstk/src/WvIn.cpp; refType = 4; }; 3D9E08420779F7B80002CE69 = { fileRef = 3D9E08360779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08430779F7B80002CE69 = { fileRef = 3D9E08370779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08440779F7B80002CE69 = { fileRef = 3D9E08380779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08450779F7B80002CE69 = { fileRef = 3D9E08390779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08460779F7B80002CE69 = { fileRef = 3D9E083A0779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08470779F7B80002CE69 = { fileRef = 3D9E083B0779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08480779F7B80002CE69 = { fileRef = 3D9E083C0779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08490779F7B80002CE69 = { fileRef = 3D9E083D0779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E084A0779F7B80002CE69 = { fileRef = 3D9E083E0779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E084B0779F7B80002CE69 = { fileRef = 3D9E083F0779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E084C0779F7B80002CE69 = { fileRef = 3D9E08400779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E084D0779F7B80002CE69 = { fileRef = 3D9E08410779F7B80002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E084E077C6FC00002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = stkinit.cpp; path = nyqstk/stkinit.cpp; refType = 4; }; 3D9E084F077C6FC00002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = stkinit.h; path = nyqstk/stkinit.h; refType = 4; }; 3D9E0850077C6FC00002CE69 = { fileRef = 3D9E084E077C6FC00002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E0851077C6FC00002CE69 = { fileRef = 3D9E084F077C6FC00002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E086A0789D6000002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = lpanal.c; refType = 4; }; 3D9E086B0789D6000002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = lpanal.h; refType = 4; }; 3D9E086C0789D6000002CE69 = { fileRef = 3D9E086A0789D6000002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E086D0789D6000002CE69 = { fileRef = 3D9E086B0789D6000002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E086E0789D81B0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = alpassvc.c; path = ../tran/alpassvc.c; refType = 4; }; 3D9E086F0789D81B0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = alpassvc.h; path = ../tran/alpassvc.h; refType = 4; }; 3D9E08700789D81B0002CE69 = { fileRef = 3D9E086E0789D81B0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08710789D81B0002CE69 = { fileRef = 3D9E086F0789D81B0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08720789D82F0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = allpoles.c; path = ../tran/allpoles.c; refType = 4; }; 3D9E08730789D82F0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = allpoles.h; path = ../tran/allpoles.h; refType = 4; }; 3D9E08740789D82F0002CE69 = { fileRef = 3D9E08720789D82F0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08750789D82F0002CE69 = { fileRef = 3D9E08730789D82F0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08760789D8520002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = f0.cpp; refType = 4; }; 3D9E08770789D8520002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = f0.h; refType = 4; }; 3D9E08780789D8520002CE69 = { fileRef = 3D9E08760789D8520002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08790789D8520002CE69 = { fileRef = 3D9E08770789D8520002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E087A0789D8B20002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrclar.c; path = ../tran/instrclar.c; refType = 4; }; 3D9E087B0789D8B20002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrclar.h; path = ../tran/instrclar.h; refType = 4; }; 3D9E087C0789D8B20002CE69 = { fileRef = 3D9E087A0789D8B20002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E087D0789D8B20002CE69 = { fileRef = 3D9E087B0789D8B20002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E087E0789D8CF0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrsaxall.c; path = ../tran/instrsaxall.c; refType = 4; }; 3D9E087F0789D8CF0002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrsaxall.h; path = ../tran/instrsaxall.h; refType = 4; }; 3D9E08800789D8CF0002CE69 = { fileRef = 3D9E087E0789D8CF0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08810789D8CF0002CE69 = { fileRef = 3D9E087F0789D8CF0002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08820789D8E70002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = lpreson.c; path = /Users/rbd/nyquist/tran/lpreson.c; refType = 0; }; 3D9E08830789D8E70002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = lpreson.h; path = ../tran/lpreson.h; refType = 4; }; 3D9E08840789D8E70002CE69 = { fileRef = 3D9E08820789D8E70002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08850789D8E70002CE69 = { fileRef = 3D9E08830789D8E70002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08860789D9100002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrclarall.c; path = ../tran/instrclarall.c; refType = 4; }; 3D9E08870789D9100002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrclarall.h; path = ../tran/instrclarall.h; refType = 4; }; 3D9E08880789D9100002CE69 = { fileRef = 3D9E08860789D9100002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08890789D9100002CE69 = { fileRef = 3D9E08870789D9100002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E088A0789D9230002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrsaxfreq.c; path = ../tran/instrsaxfreq.c; refType = 4; }; 3D9E088B0789D9230002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrsaxfreq.h; path = ../tran/instrsaxfreq.h; refType = 4; }; 3D9E088C0789D9230002CE69 = { fileRef = 3D9E088A0789D9230002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E088D0789D9230002CE69 = { fileRef = 3D9E088B0789D9230002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E088E0789D9430002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrclarfreq.c; path = ../tran/instrclarfreq.c; refType = 4; }; 3D9E088F0789D9430002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrclarfreq.h; path = ../tran/instrclarfreq.h; refType = 4; }; 3D9E08900789D9430002CE69 = { fileRef = 3D9E088E0789D9430002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08910789D9430002CE69 = { fileRef = 3D9E088F0789D9430002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08920789D9680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrsax.c; path = ../tran/instrsax.c; refType = 4; }; 3D9E08930789D9680002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = instrsax.h; path = ../tran/instrsax.h; refType = 4; }; 3D9E08940789D9680002CE69 = { fileRef = 3D9E08920789D9680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08950789D9680002CE69 = { fileRef = 3D9E08930789D9680002CE69; isa = PBXBuildFile; settings = { }; }; 3D9E08960789D9E30002CE69 = { fileEncoding = 30; isa = PBXFileReference; name = pa_unix_util.c; path = ../portaudio/pa_unix/pa_unix_util.c; refType = 4; }; 3D9E08970789D9E30002CE69 = { fileRef = 3D9E08960789D9E30002CE69; isa = PBXBuildFile; settings = { }; }; 3DA446C00789FF350002CE69 = { isa = PBXFrameworkReference; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; refType = 0; }; 3DA446C10789FF350002CE69 = { fileRef = 3DA446C00789FF350002CE69; isa = PBXBuildFile; settings = { }; }; 3DA446C20789FF430002CE69 = { isa = PBXFrameworkReference; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; refType = 0; }; 3DA446C30789FF430002CE69 = { fileRef = 3DA446C20789FF430002CE69; isa = PBXBuildFile; settings = { }; }; 3DF21F2204FD4FDC0002CE69 = { buildActionMask = 2147483647; files = ( 3DF21F5104FD526A0002CE69, 3DF21F5204FD526A0002CE69, 3DF21F5404FD526A0002CE69, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 3DF21F2304FD4FDC0002CE69 = { buildActionMask = 2147483647; files = ( 3DF21F5304FD526A0002CE69, 3DF21F6104FD52BC0002CE69, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 3DF21F2404FD4FDC0002CE69 = { buildActionMask = 2147483647; files = ( ); isa = PBXFrameworksBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 3DF21F2504FD4FDC0002CE69 = { buildActionMask = 2147483647; files = ( ); isa = PBXRezBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 3DF21F2604FD4FDC0002CE69 = { buildPhases = ( 3DF21F2204FD4FDC0002CE69, 3DF21F2304FD4FDC0002CE69, 3DF21F2404FD4FDC0002CE69, 3DF21F2504FD4FDC0002CE69, ); buildSettings = { HEADER_SEARCH_PATHS = ../sys/unix; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = intgen; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; }; dependencies = ( ); isa = PBXToolTarget; name = InterfaceGenerator; productInstallPath = /usr/local/bin; productName = InterfaceGenerator; productReference = 3DF21F2704FD4FDC0002CE69; }; 3DF21F2704FD4FDC0002CE69 = { isa = PBXExecutableFileReference; path = intgen; refType = 3; }; 3DF21F3104FD526A0002CE69 = { children = ( 3DF21F3204FD526A0002CE69, 3DF21F3304FD526A0002CE69, 3DF21F3404FD526A0002CE69, 3DF21F3504FD526A0002CE69, 3DF21F3604FD526A0002CE69, 3DF21F3C04FD526A0002CE69, 3DF21F3D04FD526A0002CE69, 3DF21F3E04FD526A0002CE69, 3DF21F3F04FD526A0002CE69, 3DF21F4004FD526A0002CE69, 3DF21F4104FD526A0002CE69, 3DF21F4204FD526A0002CE69, 3DF21F4404FD526A0002CE69, 3DF21F4504FD526A0002CE69, 3DF21F4604FD526A0002CE69, 3DF21F4704FD526A0002CE69, 3DF21F4804FD526A0002CE69, 3DF21F4904FD526A0002CE69, 3DF21F4A04FD526A0002CE69, 3DF21F4B04FD526A0002CE69, 3DF21F4C04FD526A0002CE69, 3DF21F4D04FD526A0002CE69, 3DF21F4E04FD526A0002CE69, 3DF21F4F04FD526A0002CE69, 3DF21F5004FD526A0002CE69, ); isa = PBXGroup; path = misc; refType = 4; }; 3DF21F3204FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = args.h; refType = 4; }; 3DF21F3304FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = cext.h; refType = 4; }; 3DF21F3404FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = cmdline.c; refType = 4; }; 3DF21F3504FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = cmdline.h; refType = 4; }; 3DF21F3604FD526A0002CE69 = { children = ( 3DF21F3704FD526A0002CE69, 3DF21F3804FD526A0002CE69, 3DF21F3904FD526A0002CE69, 3DF21F3A04FD526A0002CE69, 3DF21F3B04FD526A0002CE69, ); isa = PBXGroup; path = cmu; refType = 4; }; 3DF21F3704FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = cleanup.bat; refType = 4; }; 3DF21F3804FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = "cmu-linux-install.lsp"; refType = 4; }; 3DF21F3904FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = cmuinstall.bat; refType = 4; }; 3DF21F3A04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = init.lsp; refType = 4; }; 3DF21F3B04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = restore.bat; refType = 4; }; 3DF21F3C04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = convert.c; refType = 4; }; 3DF21F3D04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = convert.h; refType = 4; }; 3DF21F3E04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = filelist.c; refType = 4; }; 3DF21F3F04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = filelist.dsp; refType = 4; }; 3DF21F4004FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = intgen.c; refType = 4; }; 3DF21F4104FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = intgen2.c; refType = 4; }; 3DF21F4204FD526A0002CE69 = { children = ( 3DF21F4304FD526A0002CE69, ); isa = PBXGroup; path = intgen_win32; refType = 4; }; 3DF21F4304FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = intgen.dsp; refType = 4; }; 3DF21F4404FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = "mac-to-win.lsp"; refType = 4; }; 3DF21F4504FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = Makefile; refType = 4; }; 3DF21F4604FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = makefile.lsp; refType = 4; }; 3DF21F4704FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = packer.c; refType = 4; }; 3DF21F4804FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = packer.dsp; refType = 4; }; 3DF21F4904FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = play.c; refType = 4; }; 3DF21F4A04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = plot.c; refType = 4; }; 3DF21F4B04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = sampleprint.c; refType = 4; }; 3DF21F4C04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = sine.c; refType = 4; }; 3DF21F4D04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = stdefs2.h; refType = 4; }; 3DF21F4E04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = transfiles.lsp; refType = 4; }; 3DF21F4F04FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = unpacker.c; refType = 4; }; 3DF21F5004FD526A0002CE69 = { fileEncoding = 30; isa = PBXFileReference; path = unpacker.dsp; refType = 4; }; 3DF21F5104FD526A0002CE69 = { fileRef = 3DF21F3204FD526A0002CE69; isa = PBXBuildFile; settings = { }; }; 3DF21F5204FD526A0002CE69 = { fileRef = 3DF21F3304FD526A0002CE69; isa = PBXBuildFile; settings = { }; }; 3DF21F5304FD526A0002CE69 = { fileRef = 3DF21F3404FD526A0002CE69; isa = PBXBuildFile; settings = { }; }; 3DF21F5404FD526A0002CE69 = { fileRef = 3DF21F3504FD526A0002CE69; isa = PBXBuildFile; settings = { }; }; 3DF21F6104FD52BC0002CE69 = { fileRef = 3DF21F4004FD526A0002CE69; isa = PBXBuildFile; settings = { }; }; //3D0 //3D1 //3D2 //3D3 //3D4 //C60 //C61 //C62 //C63 //C64 C6A0FF2D029079AD04C91782 = { buildActionMask = 12; dstPath = ""; dstSubfolderSpec = 16; files = ( 3D9E082C0779F7680002CE69, ); isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; //C60 //C61 //C62 //C63 //C64 //F50 //F51 //F52 //F53 //F54 F510BCA7039F84FD01029006 = { includeInIndex = 1; isa = PBXFolderReference; path = lib; refType = 4; }; F510BCDA039F84FE01029006 = { includeInIndex = 1; isa = PBXFolderReference; path = runtime; refType = 4; }; F510BD73039FB49C01029006 = { includeInIndex = 1; isa = PBXFolderReference; path = doc; refType = 4; }; F510BDB903A0314301029006 = { children = ( F543E76B0375C24D01029006, F543E7750375C25A01029006, ); isa = PBXGroup; name = Frameworks; path = /System/Library/Frameworks; refType = 0; }; F53626EE03761E6C01029006 = { fileEncoding = 30; isa = PBXFileReference; path = audiopa.c; refType = 4; }; F543E76B0375C24D01029006 = { isa = PBXFrameworkReference; path = CoreAudio.framework; refType = 4; }; F543E7750375C25A01029006 = { isa = PBXFrameworkReference; path = AudioToolbox.framework; refType = 4; }; F543EE570375CD5801029006 = { children = ( F543EE580375CD5801029006, F543EE590375CD5801029006, F543EE5A0375CD5801029006, F543EE5B0375CD5801029006, F543EE5C0375CD5801029006, F543EE5D0375CD5801029006, F543EE5E0375CD5801029006, F543EE5F0375CD5801029006, F543EE600375CD5801029006, F543EE610375CD5801029006, F543EE620375CD5801029006, F543EE630375CD5801029006, F543EE640375CD5801029006, F543EE650375CD5801029006, F543EE660375CD5801029006, F543EE670375CD5801029006, F543EE680375CD5801029006, F543EE690375CD5801029006, F543EE6A0375CD5801029006, F543EE6B0375CD5801029006, F543EE6C0375CD5801029006, F543EE6D0375CD5801029006, F543EE6E0375CD5801029006, F543EE6F0375CD5801029006, F543EE700375CD5801029006, F543EE710375CD5801029006, F543EE720375CD5801029006, F543EE730375CD5801029006, F543EE740375CD5801029006, F543EE750375CD5801029006, F543EE760375CD5801029006, F543EE770375CD5801029006, F543EE780375CD5801029006, F543EE790375CD5801029006, F543EE7A0375CD5801029006, F543EE7B0375CD5801029006, F543EE7C0375CD5801029006, F543EE7D0375CD5801029006, F543EE7E0375CD5801029006, F543EE7F0375CD5801029006, F543EE800375CD5801029006, F543EE810375CD5801029006, F543EE820375CD5801029006, F543EE830375CD5801029006, F543EE840375CD5801029006, F543EE850375CD5801029006, F543EE860375CD5801029006, F543EE870375CD5801029006, ); isa = PBXGroup; path = cmt; refType = 4; }; F543EE580375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cext.c; refType = 4; }; F543EE590375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cext.h; refType = 4; }; F543EE5A0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cleanup.c; refType = 4; }; F543EE5B0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cleanup.h; refType = 4; }; F543EE5C0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cmdline.c; refType = 4; }; F543EE5D0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cmdline.h; refType = 4; }; F543EE5E0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cmtcmd.c; refType = 4; }; F543EE5F0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cmtcmd.h; refType = 4; }; F543EE600375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cmtio.c; refType = 4; }; F543EE610375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = cmtio.h; refType = 4; }; F543EE620375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = hash.h; refType = 4; }; F543EE630375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = hashrout.h; refType = 4; }; F543EE640375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = mem.c; refType = 4; }; F543EE650375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = mem.h; refType = 4; }; F543EE660375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = mfmidi.h; refType = 4; }; F543EE670375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midibuff.h; refType = 4; }; F543EE680375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midicode.h; refType = 4; }; F543EE690375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midierr.h; refType = 4; }; F543EE6A0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midifile.c; refType = 4; }; F543EE6B0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midifile.h; refType = 4; }; F543EE6C0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midifns.c; refType = 4; }; F543EE6D0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midifns.h; refType = 4; }; F543EE6E0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midimgr.c; refType = 4; }; F543EE6F0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = midimgr.h; refType = 4; }; F543EE700375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = moxc.c; refType = 4; }; F543EE710375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = moxc.h; refType = 4; }; F543EE720375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = musiprog.h; refType = 4; }; F543EE730375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = pitch.h; refType = 4; }; F543EE740375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = record.c; refType = 4; }; F543EE750375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = record.h; refType = 4; }; F543EE760375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seq.c; refType = 4; }; F543EE770375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seq.h; refType = 4; }; F543EE780375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqdecls.h; refType = 4; }; F543EE790375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqmread.c; refType = 4; }; F543EE7A0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqmread.h; refType = 4; }; F543EE7B0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqmwrite.c; refType = 4; }; F543EE7C0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqmwrite.h; refType = 4; }; F543EE7D0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqread.c; refType = 4; }; F543EE7E0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqread.h; refType = 4; }; F543EE7F0375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqwrite.c; refType = 4; }; F543EE800375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqwrite.h; refType = 4; }; F543EE810375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = swlogic.h; refType = 4; }; F543EE820375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = tempomap.c; refType = 4; }; F543EE830375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = tempomap.h; refType = 4; }; F543EE840375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = timebase.c; refType = 4; }; F543EE850375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = timebase.h; refType = 4; }; F543EE860375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = userio.c; refType = 4; }; F543EE870375CD5801029006 = { fileEncoding = 30; isa = PBXFileReference; path = userio.h; refType = 4; }; F543EF3D0375CD7101029006 = { children = ( F53626EE03761E6C01029006, F543EF4A0375CD7101029006, F543EF4B0375CD7101029006, F543EF4D0375CD7101029006, F543EF4E0375CD7101029006, F543EF510375CD7101029006, F543EF520375CD7101029006, F543EF550375CD7101029006, F543EF570375CD7101029006, F543EF580375CD7101029006, F543EF590375CD7101029006, F543EF5A0375CD7101029006, F543EF5D0375CD7101029006, F543EF5E0375CD7101029006, F543EF620375CD7101029006, F543EF630375CD7101029006, F543EF660375CD7101029006, ); isa = PBXGroup; path = snd; refType = 4; }; F543EF4A0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = ieeecvt.c; refType = 4; }; F543EF4B0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = ieeecvt.h; refType = 4; }; F543EF4D0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = snd.c; refType = 4; }; F543EF4E0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = snd.h; refType = 4; }; F543EF510375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndconfig.h; refType = 4; }; F543EF520375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndcvt.c; refType = 4; }; F543EF550375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfileio.h; refType = 4; }; F543EF570375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndhead.h; refType = 4; }; F543EF580375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndheader.c; refType = 4; }; F543EF590375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndheader.h; refType = 4; }; F543EF5A0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndio.c; refType = 4; }; F543EF5D0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndmac.c; refType = 4; }; F543EF5E0375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndmac.h; refType = 4; }; F543EF620375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndsystem.h; refType = 4; }; F543EF630375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndsystemmac.h; refType = 4; }; F543EF660375CD7101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndwrite.h; refType = 4; }; F543EF940375CD8D01029006 = { children = ( F543EF950375CD8D01029006, F543EF960375CD8D01029006, ); isa = PBXGroup; path = fft; refType = 4; }; F543EF950375CD8D01029006 = { fileEncoding = 30; isa = PBXFileReference; path = fftn.c; refType = 4; }; F543EF960375CD8D01029006 = { fileEncoding = 30; isa = PBXFileReference; path = fftn.h; refType = 4; }; F543EF970375CD8D01029006 = { fileRef = F543EF950375CD8D01029006; isa = PBXBuildFile; settings = { }; }; F543EF980375CD8D01029006 = { fileRef = F543EF960375CD8D01029006; isa = PBXBuildFile; settings = { }; }; F543EF990375CD9901029006 = { children = ( F543EFB10375CD9901029006, ); isa = PBXGroup; path = sys; refType = 4; }; F543EFB10375CD9901029006 = { children = ( 3D36DDF00796E5DE0002CE69, F543EFBF0375CD9901029006, 3D9867D304FFE8E20002CE69, ); isa = PBXGroup; path = unix; refType = 4; }; F543EFBF0375CD9901029006 = { fileEncoding = 30; isa = PBXFileReference; path = osstuff.c; refType = 4; }; F543F0100375CD9901029006 = { fileRef = F543EFBF0375CD9901029006; isa = PBXBuildFile; settings = { }; }; F543F19F0375E1E401029006 = { children = ( 08FB7795FE84155DC02AAC07, ); isa = PBXGroup; name = Source; path = ""; refType = 2; }; F5779DA4039D8E1901029006 = { fileRef = F543EF5E0375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5779DA8039D8E9501029006 = { fileRef = F5FF60D9039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5779DB1039D99D901029006 = { fileRef = F543EF4E0375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5779DB2039D99DA01029006 = { fileRef = F543EF4D0375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5C6A9B303A10C0501029006 = { buildActionMask = 2147483647; files = ( 3D35A7D605690E180002CE69, 3D35A7D705690E180002CE69, 3D35A7D805690E180002CE69, 3D35A7D905690E180002CE69, 3D35A7DA05690E180002CE69, 3D35A7DB05690E180002CE69, 3D35A7DC05690E180002CE69, 3D35A7DE05690E180002CE69, 3D35A7DF05690E180002CE69, 3D35A7E005690E180002CE69, 3D35A7E105690E180002CE69, 3D35A7E205690E180002CE69, 3D6032F60790A600007A3CA5, 3D6032F90790A618007A3CA5, 3D6032FB0790A62C007A3CA5, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; F5C6A9B403A10C0501029006 = { buildActionMask = 2147483647; files = ( 3D35A7D405690E180002CE69, 3D35A7D505690E180002CE69, 3D35A7DD05690E180002CE69, 3D36DDE70796D6D40002CE69, 3D36DDEF0796E5CA0002CE69, 3D36DDF30796E60F0002CE69, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; F5C6A9B503A10C0501029006 = { buildActionMask = 2147483647; files = ( ); isa = PBXJavaArchiveBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; F5C6A9B603A10C0501029006 = { buildActionMask = 2147483647; files = ( ); isa = PBXFrameworksBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; F5C6A9B703A10C0501029006 = { buildPhases = ( F5C6A9B303A10C0501029006, F5C6A9B403A10C0501029006, F5C6A9B503A10C0501029006, F5C6A9B603A10C0501029006, F5DA146003A112BF01029006, ); buildSettings = { HEADER_SEARCH_PATHS = ""; INSTALL_PATH = Applications; JAVA_CLASS_SEARCH_PATHS = ../jnyqide; JAVA_COMPILER = /usr/bin/javac; JAVA_ONLY = YES; JAVA_SOURCE_SUBDIR = .; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = NyquistIDE; SECTORDER_FLAGS = ""; WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; WRAPPER_EXTENSION = app; }; dependencies = ( F5DA143703A10FDA01029006, ); isa = PBXApplicationTarget; name = NyquistIDE; productInstallPath = Applications; productName = NyquistIDE; productReference = F5C6A9B803A10C0501029006; productSettingsXML = " CFBundleDevelopmentRegion English CFBundleExecutable CFBundleGetInfoString CFBundleIconFile CFBundleIdentifier CFBundleInfoDictionaryVersion 6.0 CFBundleName CFBundlePackageType APPL CFBundleShortVersionString CFBundleSignature ???? CFBundleVersion 0.0.1d1 Java ClassPath $JAVAROOT/NyquistIDE.jar MainClass jnyqide.Main Properties com.apple.macos.useScreenMenuBar true WorkingDirectory $APP_PACKAGE/Contents/Resources/Java NSJavaNeeded YES NSJavaPath NyquistIDE.jar NSJavaRoot Contents/Resources/Java "; }; F5C6A9B803A10C0501029006 = { isa = PBXApplicationReference; path = NyquistIDE.app; refType = 3; }; F5C6A9C903A10C6201029006 = { fileRef = 034768E8FF38A79811DB9C8B; isa = PBXBuildFile; settings = { JAVA_ARCHIVE_SUBDIR = build; }; }; F5C6A9CA03A10C6401029006 = { fileRef = F510BCA7039F84FD01029006; isa = PBXBuildFile; settings = { JAVA_ARCHIVE_SUBDIR = ..; }; }; F5DA143703A10FDA01029006 = { isa = PBXTargetDependency; target = 08FB779FFE84155DC02AAC07; }; F5DA143903A1108C01029006 = { fileEncoding = 30; isa = PBXFileReference; path = README; refType = 4; }; F5DA146003A112BF01029006 = { buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 15; files = ( F5C6A9C903A10C6201029006, 3D36DDEC0796D71B0002CE69, F5C6A9CA03A10C6401029006, 3D36DDED0796E1AB0002CE69, 3D36DDF10796E5E80002CE69, 3D36DDF40796E6170002CE69, ); isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; F5FF5F48039D84B901029006 = { children = ( F5FF5F49039D84B901029006, F5FF5F4A039D84B901029006, F5FF5F4B039D84B901029006, F5FF5F4C039D84B901029006, F5FF5F4D039D84B901029006, F5FF5F4E039D84B901029006, F5FF5F4F039D84B901029006, F5FF5F50039D84B901029006, F5FF5F51039D84B901029006, F5FF5F52039D84B901029006, F5FF5F53039D84B901029006, F5FF5F54039D84B901029006, F5FF5F55039D84B901029006, F5FF5F56039D84B901029006, F5FF5F57039D84B901029006, F5FF5F58039D84B901029006, F5FF5F59039D84B901029006, F5FF5F5A039D84B901029006, F5FF5F5B039D84B901029006, F5FF5F5C039D84B901029006, F5FF5F5D039D84B901029006, F5FF5F5E039D84B901029006, F5FF5F5F039D84B901029006, F5FF5F60039D84B901029006, F5FF5F61039D84B901029006, F5FF5F62039D84B901029006, F5FF5F63039D84B901029006, F5FF5F64039D84B901029006, F5FF5F65039D84B901029006, ); isa = PBXGroup; path = xlisp; refType = 4; }; F5FF5F49039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = extern.c; refType = 4; }; F5FF5F4A039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = extern.h; refType = 4; }; F5FF5F4B039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = osdefs.h; refType = 4; }; F5FF5F4C039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = osptrs.h; refType = 4; }; F5FF5F4D039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlbfun.c; refType = 4; }; F5FF5F4E039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlcont.c; refType = 4; }; F5FF5F4F039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xldbug.c; refType = 4; }; F5FF5F50039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xldmem.c; refType = 4; }; F5FF5F51039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xldmem.h; refType = 4; }; F5FF5F52039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xleval.c; refType = 4; }; F5FF5F53039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlfio.c; refType = 4; }; F5FF5F54039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlftab.c; refType = 4; }; F5FF5F55039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlglob.c; refType = 4; }; F5FF5F56039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlimage.c; refType = 4; }; F5FF5F57039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlinit.c; refType = 4; }; F5FF5F58039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlio.c; refType = 4; }; F5FF5F59039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlisp.c; refType = 4; }; F5FF5F5A039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlisp.h; refType = 4; }; F5FF5F5B039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xljump.c; refType = 4; }; F5FF5F5C039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xllist.c; refType = 4; }; F5FF5F5D039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlmath.c; refType = 4; }; F5FF5F5E039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlobj.c; refType = 4; }; F5FF5F5F039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlpp.c; refType = 4; }; F5FF5F60039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlprin.c; refType = 4; }; F5FF5F61039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlread.c; refType = 4; }; F5FF5F62039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlstr.c; refType = 4; }; F5FF5F63039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlsubr.c; refType = 4; }; F5FF5F64039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlsym.c; refType = 4; }; F5FF5F65039D84B901029006 = { fileEncoding = 30; isa = PBXFileReference; path = xlsys.c; refType = 4; }; F5FF5F83039D84DB01029006 = { fileRef = F5FF5F49039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F84039D84DB01029006 = { fileRef = F5FF5F4A039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F85039D84DF01029006 = { fileRef = F5FF5F50039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F86039D84DF01029006 = { fileRef = F5FF5F51039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F87039D84E301029006 = { fileRef = F5FF5F4D039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F88039D84E801029006 = { fileRef = F5FF5F4E039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F89039D84EF01029006 = { fileRef = F5FF5F4F039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F8A039D84F301029006 = { fileRef = F5FF5F52039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F8B039D84F701029006 = { fileRef = F5FF5F53039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F8C039D84FB01029006 = { fileRef = F5FF5F54039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F8D039D84FE01029006 = { fileRef = F5FF5F55039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F8E039D850301029006 = { fileRef = F5FF5F56039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F8F039D850701029006 = { fileRef = F5FF5F57039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F90039D850801029006 = { fileRef = F5FF5F58039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F91039D850A01029006 = { fileRef = F5FF5F59039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F92039D850B01029006 = { fileRef = F5FF5F5A039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F93039D850E01029006 = { fileRef = F5FF5F5B039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F94039D851101029006 = { fileRef = F5FF5F5C039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F95039D851201029006 = { fileRef = F5FF5F5D039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F96039D851501029006 = { fileRef = F5FF5F5E039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F97039D851801029006 = { fileRef = F5FF5F5F039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F98039D851A01029006 = { fileRef = F5FF5F60039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F99039D851D01029006 = { fileRef = F5FF5F61039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F9A039D852201029006 = { fileRef = F5FF5F62039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F9B039D852301029006 = { fileRef = F5FF5F63039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F9C039D852401029006 = { fileRef = F5FF5F64039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F9D039D852601029006 = { fileRef = F5FF5F65039D84B901029006; isa = PBXBuildFile; settings = { }; }; F5FF5F9E039D863401029006 = { children = ( F5FF5FA1039D866201029006, F5FF5FA2039D866201029006, F5FF5FA3039D866201029006, F5FF5FA4039D866201029006, F5FF5FA5039D866201029006, F5FF5FA6039D866201029006, F5FF5FA7039D866201029006, F5FF5FA8039D866201029006, F5FF5FA9039D866201029006, F5FF5FAA039D866201029006, F5FF5FAB039D866201029006, F5FF5FAC039D866201029006, F5FF5FAD039D866201029006, F5FF5FAE039D866201029006, F5FF5FAF039D866201029006, F5FF5FB0039D866201029006, F5FF5FB1039D866201029006, F5FF5FB2039D866201029006, F5FF5FB3039D866201029006, F5FF5FB4039D866201029006, F5FF5FB5039D866201029006, F5FF5FB6039D866201029006, F5FF5FB7039D866201029006, F5FF5FB8039D866201029006, F5FF5FB9039D866201029006, F5FF5FBA039D866201029006, F5FF5FBB039D866201029006, F5FF5FBC039D866201029006, F5FF5FBD039D866201029006, F5FF5FBE039D866201029006, F5FF5FC1039D866201029006, F5FF5FC2039D866201029006, 3D9E07E00779F4DC0002CE69, 3D9E07E10779F4DC0002CE69, F5FF5FC5039D866201029006, F5FF5FC6039D866201029006, F5FF5FC7039D866201029006, F5FF5FC8039D866201029006, F5FF5FC9039D866201029006, F5FF5FCA039D866201029006, F5FF5FCB039D866201029006, F5FF5FCC039D866201029006, F5FF5FCD039D866201029006, F5FF5FCE039D866201029006, F5FF5FCF039D866201029006, F5FF5FD0039D866201029006, F5FF5FD1039D866201029006, F5FF5FD2039D866201029006, F5FF5FD3039D866201029006, F5FF5FD4039D866201029006, F5FF5FD5039D866201029006, F5FF5FD6039D866201029006, F5FF5FD7039D866201029006, F5FF5FD8039D866201029006, F5FF5FD9039D866201029006, F5FF5FDA039D866201029006, F5FF5FDB039D866201029006, F5FF5FDC039D866201029006, F5FF5FDD039D866201029006, F5FF5FDE039D866201029006, F5FF5FDF039D866201029006, F5FF5FE0039D866201029006, F5FF5FE1039D866201029006, F5FF5FE2039D866201029006, F5FF5FE3039D866201029006, F5FF5FE4039D866201029006, F5FF5FE5039D866201029006, F5FF5FE6039D866201029006, F5FF5FE7039D866201029006, F5FF5FE8039D866201029006, F5FF5FEB039D866201029006, F5FF5FEC039D866201029006, F5FF5FED039D866201029006, F5FF5FEE039D866201029006, F5FF5FEF039D866201029006, F5FF5FF0039D866201029006, F5FF5FF1039D866201029006, F5FF5FF2039D866201029006, F5FF5FF3039D866201029006, F5FF5FF4039D866201029006, F5FF5FF5039D866201029006, F5FF5FF6039D866201029006, F5FF5FF7039D866201029006, F5FF5FF8039D866201029006, F5FF5FF9039D866201029006, F5FF5FFA039D866201029006, F5FF5FFB039D866201029006, F5FF5FFC039D866201029006, F5FF5FFD039D866201029006, F5FF5FFE039D866201029006, F5FF5FFF039D866201029006, F5FF6000039D866201029006, F5FF6001039D866201029006, F5FF6002039D866201029006, F5FF6003039D866201029006, F5FF6004039D866201029006, 3D9867CC04FFDD3C0002CE69, 3D9867CE04FFDD6B0002CE69, F5FF6005039D866201029006, F5FF6006039D866201029006, F5FF6007039D866201029006, F5FF6008039D866201029006, F5FF6009039D866201029006, F5FF600A039D866201029006, F5FF600B039D866201029006, F5FF600C039D866201029006, F5FF600D039D866201029006, F5FF600E039D866201029006, ); isa = PBXGroup; path = tran; refType = 4; }; F5FF5FA1039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = abs.c; refType = 4; }; F5FF5FA2039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = abs.h; refType = 4; }; F5FF5FA3039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = alpass.c; refType = 4; }; F5FF5FA4039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = alpass.h; refType = 4; }; F5FF5FA5039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = amosc.c; refType = 4; }; F5FF5FA6039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = amosc.h; refType = 4; }; F5FF5FA7039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = areson.c; refType = 4; }; F5FF5FA8039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = areson.h; refType = 4; }; F5FF5FA9039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = aresoncv.c; refType = 4; }; F5FF5FAA039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = aresoncv.h; refType = 4; }; F5FF5FAB039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = aresonvc.c; refType = 4; }; F5FF5FAC039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = aresonvc.h; refType = 4; }; F5FF5FAD039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = aresonvv.c; refType = 4; }; F5FF5FAE039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = aresonvv.h; refType = 4; }; F5FF5FAF039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = atone.c; refType = 4; }; F5FF5FB0039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = atone.h; refType = 4; }; F5FF5FB1039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = atonev.c; refType = 4; }; F5FF5FB2039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = atonev.h; refType = 4; }; F5FF5FB3039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = biquad.c; refType = 4; }; F5FF5FB4039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = biquad.h; refType = 4; }; F5FF5FB5039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = buzz.c; refType = 4; }; F5FF5FB6039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = buzz.h; refType = 4; }; F5FF5FB7039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = chase.c; refType = 4; }; F5FF5FB8039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = chase.h; refType = 4; }; F5FF5FB9039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = clip.c; refType = 4; }; F5FF5FBA039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = clip.h; refType = 4; }; F5FF5FBB039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = congen.c; refType = 4; }; F5FF5FBC039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = congen.h; refType = 4; }; F5FF5FBD039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = const.c; refType = 4; }; F5FF5FBE039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = const.h; refType = 4; }; F5FF5FC1039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = coterm.c; refType = 4; }; F5FF5FC2039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = coterm.h; refType = 4; }; F5FF5FC5039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = delaycv.c; refType = 4; }; F5FF5FC6039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = delaycv.h; refType = 4; }; F5FF5FC7039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = exp.c; refType = 4; }; F5FF5FC8039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = exp.h; refType = 4; }; F5FF5FC9039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = fmosc.c; refType = 4; }; F5FF5FCA039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = fmosc.h; refType = 4; }; F5FF5FCB039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = follow.c; refType = 4; }; F5FF5FCC039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = follow.h; refType = 4; }; F5FF5FCD039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = fromarraystream.c; refType = 4; }; F5FF5FCE039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = fromarraystream.h; refType = 4; }; F5FF5FCF039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = fromobject.c; refType = 4; }; F5FF5FD0039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = fromobject.h; refType = 4; }; F5FF5FD1039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = gate.c; refType = 4; }; F5FF5FD2039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = gate.h; refType = 4; }; F5FF5FD3039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = ifft.c; refType = 4; }; F5FF5FD4039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = ifft.h; refType = 4; }; F5FF5FD5039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = integrate.c; refType = 4; }; F5FF5FD6039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = integrate.h; refType = 4; }; F5FF5FD7039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = log.c; refType = 4; }; F5FF5FD8039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = log.h; refType = 4; }; F5FF5FD9039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = maxv.c; refType = 4; }; F5FF5FDA039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = maxv.h; refType = 4; }; F5FF5FDB039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = offset.c; refType = 4; }; F5FF5FDC039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = offset.h; refType = 4; }; F5FF5FDD039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = oneshot.c; refType = 4; }; F5FF5FDE039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = oneshot.h; refType = 4; }; F5FF5FDF039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = osc.c; refType = 4; }; F5FF5FE0039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = osc.h; refType = 4; }; F5FF5FE1039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = partial.c; refType = 4; }; F5FF5FE2039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = partial.h; refType = 4; }; F5FF5FE3039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = pluck.c; refType = 4; }; F5FF5FE4039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = pluck.h; refType = 4; }; F5FF5FE5039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = prod.c; refType = 4; }; F5FF5FE6039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = prod.h; refType = 4; }; F5FF5FE7039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = pwl.c; refType = 4; }; F5FF5FE8039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = pwl.h; refType = 4; }; F5FF5FEB039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = quantize.c; refType = 4; }; F5FF5FEC039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = quantize.h; refType = 4; }; F5FF5FED039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = recip.c; refType = 4; }; F5FF5FEE039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = recip.h; refType = 4; }; F5FF5FEF039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = reson.c; refType = 4; }; F5FF5FF0039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = reson.h; refType = 4; }; F5FF5FF1039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = resoncv.c; refType = 4; }; F5FF5FF2039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = resoncv.h; refType = 4; }; F5FF5FF3039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = resonvc.c; refType = 4; }; F5FF5FF4039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = resonvc.h; refType = 4; }; F5FF5FF5039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = resonvv.c; refType = 4; }; F5FF5FF6039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = resonvv.h; refType = 4; }; F5FF5FF7039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = sampler.c; refType = 4; }; F5FF5FF8039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = sampler.h; refType = 4; }; F5FF5FF9039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = scale.c; refType = 4; }; F5FF5FFA039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = scale.h; refType = 4; }; F5FF5FFB039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = shape.c; refType = 4; }; F5FF5FFC039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = shape.h; refType = 4; }; F5FF5FFD039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = sine.c; refType = 4; }; F5FF5FFE039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = sine.h; refType = 4; }; F5FF5FFF039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = siosc.c; refType = 4; }; F5FF6000039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = siosc.h; refType = 4; }; F5FF6001039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = slope.c; refType = 4; }; F5FF6002039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = slope.h; refType = 4; }; F5FF6003039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = sqrt.c; refType = 4; }; F5FF6004039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = sqrt.h; refType = 4; }; F5FF6005039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = tapv.c; refType = 4; }; F5FF6006039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = tapv.h; refType = 4; }; F5FF6007039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = tone.c; refType = 4; }; F5FF6008039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = tone.h; refType = 4; }; F5FF6009039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = tonev.c; refType = 4; }; F5FF600A039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = tonev.h; refType = 4; }; F5FF600B039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = upsample.c; refType = 4; }; F5FF600C039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = upsample.h; refType = 4; }; F5FF600D039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = white.c; refType = 4; }; F5FF600E039D866201029006 = { fileEncoding = 30; isa = PBXFileReference; path = white.h; refType = 4; }; F5FF600F039D866201029006 = { fileRef = F5FF5FA1039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6010039D866201029006 = { fileRef = F5FF5FA2039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6011039D866201029006 = { fileRef = F5FF5FA3039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6012039D866201029006 = { fileRef = F5FF5FA4039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6013039D866201029006 = { fileRef = F5FF5FA5039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6014039D866201029006 = { fileRef = F5FF5FA6039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6015039D866201029006 = { fileRef = F5FF5FA7039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6016039D866201029006 = { fileRef = F5FF5FA8039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6017039D866201029006 = { fileRef = F5FF5FA9039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6018039D866201029006 = { fileRef = F5FF5FAA039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6019039D866201029006 = { fileRef = F5FF5FAB039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF601A039D866201029006 = { fileRef = F5FF5FAC039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF601B039D866201029006 = { fileRef = F5FF5FAD039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF601C039D866201029006 = { fileRef = F5FF5FAE039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF601D039D866201029006 = { fileRef = F5FF5FAF039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF601E039D866201029006 = { fileRef = F5FF5FB0039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF601F039D866201029006 = { fileRef = F5FF5FB1039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6020039D866201029006 = { fileRef = F5FF5FB2039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6021039D866201029006 = { fileRef = F5FF5FB3039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6022039D866201029006 = { fileRef = F5FF5FB4039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6023039D866201029006 = { fileRef = F5FF5FB5039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6024039D866201029006 = { fileRef = F5FF5FB6039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6025039D866201029006 = { fileRef = F5FF5FB7039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6026039D866201029006 = { fileRef = F5FF5FB8039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6027039D866201029006 = { fileRef = F5FF5FB9039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6028039D866201029006 = { fileRef = F5FF5FBA039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6029039D866201029006 = { fileRef = F5FF5FBB039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF602A039D866201029006 = { fileRef = F5FF5FBC039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF602B039D866201029006 = { fileRef = F5FF5FBD039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF602C039D866201029006 = { fileRef = F5FF5FBE039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF602F039D866201029006 = { fileRef = F5FF5FC1039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6030039D866201029006 = { fileRef = F5FF5FC2039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6033039D866201029006 = { fileRef = F5FF5FC5039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6034039D866201029006 = { fileRef = F5FF5FC6039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6035039D866201029006 = { fileRef = F5FF5FC7039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6036039D866201029006 = { fileRef = F5FF5FC8039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6037039D866201029006 = { fileRef = F5FF5FC9039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6038039D866201029006 = { fileRef = F5FF5FCA039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6039039D866201029006 = { fileRef = F5FF5FCB039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF603A039D866201029006 = { fileRef = F5FF5FCC039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF603B039D866201029006 = { fileRef = F5FF5FCD039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF603C039D866201029006 = { fileRef = F5FF5FCE039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF603D039D866201029006 = { fileRef = F5FF5FCF039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF603E039D866201029006 = { fileRef = F5FF5FD0039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF603F039D866201029006 = { fileRef = F5FF5FD1039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6040039D866201029006 = { fileRef = F5FF5FD2039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6041039D866201029006 = { fileRef = F5FF5FD3039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6042039D866201029006 = { fileRef = F5FF5FD4039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6043039D866201029006 = { fileRef = F5FF5FD5039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6044039D866201029006 = { fileRef = F5FF5FD6039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6045039D866201029006 = { fileRef = F5FF5FD7039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6046039D866201029006 = { fileRef = F5FF5FD8039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6047039D866201029006 = { fileRef = F5FF5FD9039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6048039D866201029006 = { fileRef = F5FF5FDA039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6049039D866201029006 = { fileRef = F5FF5FDB039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF604A039D866201029006 = { fileRef = F5FF5FDC039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF604B039D866201029006 = { fileRef = F5FF5FDD039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF604C039D866201029006 = { fileRef = F5FF5FDE039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF604D039D866201029006 = { fileRef = F5FF5FDF039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF604E039D866201029006 = { fileRef = F5FF5FE0039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF604F039D866201029006 = { fileRef = F5FF5FE1039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6050039D866201029006 = { fileRef = F5FF5FE2039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6051039D866201029006 = { fileRef = F5FF5FE3039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6052039D866201029006 = { fileRef = F5FF5FE4039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6053039D866201029006 = { fileRef = F5FF5FE5039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6054039D866201029006 = { fileRef = F5FF5FE6039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6055039D866201029006 = { fileRef = F5FF5FE7039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6056039D866201029006 = { fileRef = F5FF5FE8039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6059039D866201029006 = { fileRef = F5FF5FEB039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF605A039D866201029006 = { fileRef = F5FF5FEC039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF605B039D866201029006 = { fileRef = F5FF5FED039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF605C039D866201029006 = { fileRef = F5FF5FEE039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF605D039D866201029006 = { fileRef = F5FF5FEF039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF605E039D866201029006 = { fileRef = F5FF5FF0039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF605F039D866201029006 = { fileRef = F5FF5FF1039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6060039D866201029006 = { fileRef = F5FF5FF2039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6061039D866201029006 = { fileRef = F5FF5FF3039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6062039D866201029006 = { fileRef = F5FF5FF4039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6063039D866201029006 = { fileRef = F5FF5FF5039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6064039D866201029006 = { fileRef = F5FF5FF6039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6065039D866201029006 = { fileRef = F5FF5FF7039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6066039D866201029006 = { fileRef = F5FF5FF8039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6067039D866201029006 = { fileRef = F5FF5FF9039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6068039D866201029006 = { fileRef = F5FF5FFA039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6069039D866201029006 = { fileRef = F5FF5FFB039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF606A039D866201029006 = { fileRef = F5FF5FFC039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF606B039D866201029006 = { fileRef = F5FF5FFD039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF606C039D866201029006 = { fileRef = F5FF5FFE039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF606D039D866201029006 = { fileRef = F5FF5FFF039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF606E039D866201029006 = { fileRef = F5FF6000039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF606F039D866201029006 = { fileRef = F5FF6001039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6070039D866201029006 = { fileRef = F5FF6002039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6071039D866201029006 = { fileRef = F5FF6003039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6072039D866201029006 = { fileRef = F5FF6004039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6073039D866201029006 = { fileRef = F5FF6005039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6074039D866201029006 = { fileRef = F5FF6006039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6075039D866201029006 = { fileRef = F5FF6007039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6076039D866201029006 = { fileRef = F5FF6008039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6077039D866201029006 = { fileRef = F5FF6009039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6078039D866201029006 = { fileRef = F5FF600A039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6079039D866201029006 = { fileRef = F5FF600B039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF607A039D866201029006 = { fileRef = F5FF600C039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF607B039D866201029006 = { fileRef = F5FF600D039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF607C039D866201029006 = { fileRef = F5FF600E039D866201029006; isa = PBXBuildFile; settings = { }; }; F5FF6084039D871B01029006 = { fileRef = F543EE580375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6085039D871B01029006 = { fileRef = F543EE590375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6086039D871D01029006 = { fileRef = F543EE5A0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6087039D871E01029006 = { fileRef = F543EE5B0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6088039D872001029006 = { fileRef = F543EE5C0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6089039D872001029006 = { fileRef = F543EE5D0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF608A039D872301029006 = { fileRef = F543EE5E0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF608B039D872301029006 = { fileRef = F543EE5F0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF608C039D872E01029006 = { fileRef = F543EE700375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF608D039D873001029006 = { fileRef = F543EE710375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF608E039D873401029006 = { fileRef = F543EE640375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF608F039D873501029006 = { fileRef = F543EE650375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6090039D873F01029006 = { fileRef = F543EE6A0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6091039D874001029006 = { fileRef = F543EE6B0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6092039D874101029006 = { fileRef = F543EE6C0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6093039D874101029006 = { fileRef = F543EE6D0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6094039D874501029006 = { fileRef = F543EE740375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6095039D874601029006 = { fileRef = F543EE750375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6096039D874D01029006 = { fileRef = F543EE760375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6097039D874E01029006 = { fileRef = F543EE770375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6098039D875201029006 = { fileRef = F543EE790375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF6099039D875301029006 = { fileRef = F543EE7A0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF609A039D875B01029006 = { fileRef = F543EE7B0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF609B039D875E01029006 = { fileRef = F543EE7D0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF609C039D875F01029006 = { fileRef = F543EE7E0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF609D039D876001029006 = { fileRef = F543EE7C0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF609E039D876301029006 = { fileRef = F543EE7F0375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF609F039D876401029006 = { fileRef = F543EE800375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A0039D876B01029006 = { fileRef = F543EE820375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A1039D876B01029006 = { fileRef = F543EE830375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A2039D876C01029006 = { fileRef = F543EE840375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A3039D876D01029006 = { fileRef = F543EE850375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A4039D876F01029006 = { fileRef = F543EE860375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A5039D876F01029006 = { fileRef = F543EE870375CD5801029006; isa = PBXBuildFile; settings = { }; }; F5FF60A6039D87B001029006 = { children = ( F5FF615C039D899F01029006, F5FF615D039D899F01029006, F5FF615E039D899F01029006, F5FF6162039D89B101029006, F5FF6163039D89B101029006, F5FF6164039D89B101029006, F5FF60A7039D87B001029006, F5FF60A8039D87B001029006, 3D9867D7050920060002CE69, 3D9867DB0509202C0002CE69, 3D9867DD050920400002CE69, 3D9867DE050920400002CE69, F5FF60A9039D87B001029006, F5FF60AA039D87B001029006, F5FF60AB039D87B001029006, F5FF60AC039D87B001029006, F5FF60AD039D87B001029006, F5FF60AE039D87B001029006, F5FF60AF039D87B001029006, F5FF60B0039D87B001029006, F5FF60B1039D87B001029006, 3D9867E1050920730002CE69, 3D9867E2050920730002CE69, F5FF60B2039D87B001029006, F5FF60B3039D87B001029006, F5FF60B4039D87B001029006, F5FF60B5039D87B001029006, F5FF60B6039D87B001029006, F5FF60B7039D87B001029006, F5FF60B8039D87B001029006, F5FF60B9039D87B001029006, F5FF60BA039D87B001029006, F5FF60BB039D87B001029006, F5FF60BC039D87B001029006, F5FF60BD039D87B001029006, F5FF60BE039D87B001029006, F5FF60BF039D87B001029006, F5FF60C0039D87B001029006, F5FF60C1039D87B001029006, F5FF60C2039D87B001029006, F5FF60C3039D87B001029006, F5FF60C4039D87B001029006, F5FF60C5039D87B001029006, F5FF60C6039D87B001029006, F5FF60C7039D87B001029006, F5FF60C8039D87B001029006, 3D9867E5050921720002CE69, F5FF60C9039D87B001029006, F5FF60CA039D87B001029006, F5FF60CB039D87B001029006, F5FF60CC039D87B001029006, F5FF60CD039D87B001029006, F5FF60CE039D87B001029006, F5FF60CF039D87B001029006, F5FF60D0039D87B001029006, F5FF60D1039D87B001029006, F5FF60D2039D87B001029006, F5FF60D3039D87B001029006, F5FF60D4039D87B001029006, F5FF60D5039D87B001029006, F5FF60D6039D87B001029006, F5FF60D7039D87B001029006, F5FF60D8039D87B001029006, F5FF60D9039D87B001029006, F5FF60DA039D87B001029006, F5FF60DB039D87B001029006, F5FF60DC039D87B001029006, F5FF60DD039D87B001029006, F5FF60DE039D87B001029006, F5FF60DF039D87B001029006, F5FF60E0039D87B001029006, F5FF60E1039D87B001029006, F5FF60E2039D87B001029006, F5FF60E4039D87B001029006, F5FF60E5039D87B001029006, F5FF60E6039D87B001029006, 3D9E086A0789D6000002CE69, 3D9E086B0789D6000002CE69, 3D9E086E0789D81B0002CE69, 3D9E086F0789D81B0002CE69, 3D9E08720789D82F0002CE69, 3D9E08730789D82F0002CE69, 3D9E08760789D8520002CE69, 3D9E08770789D8520002CE69, 3D9E087A0789D8B20002CE69, 3D9E087B0789D8B20002CE69, 3D9E087E0789D8CF0002CE69, 3D9E087F0789D8CF0002CE69, 3D9E08820789D8E70002CE69, 3D9E08830789D8E70002CE69, 3D9E08860789D9100002CE69, 3D9E08870789D9100002CE69, 3D9E088A0789D9230002CE69, 3D9E088B0789D9230002CE69, 3D9E088E0789D9430002CE69, 3D9E088F0789D9430002CE69, 3D9E08920789D9680002CE69, 3D9E08930789D9680002CE69, 3D9E08960789D9E30002CE69, F5FF60E7039D87B001029006, F5FF60E8039D87B001029006, F5FF60E9039D87B001029006, 3D9867D505091F760002CE69, 3D9867D9050920140002CE69, 3D9E07DC0779F4800002CE69, 3D9E07DD0779F4800002CE69, ); isa = PBXGroup; path = nyqsrc; refType = 4; }; F5FF60A7039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = add.c; refType = 4; }; F5FF60A8039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = add.h; refType = 4; }; F5FF60A9039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = avg.c; refType = 4; }; F5FF60AA039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = avg.h; refType = 4; }; F5FF60AB039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = compose.c; refType = 4; }; F5FF60AC039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = compose.h; refType = 4; }; F5FF60AD039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = cque.h; refType = 4; }; F5FF60AE039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = debug.c; refType = 4; }; F5FF60AF039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = debug.h; refType = 4; }; F5FF60B0039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = downsample.c; refType = 4; }; F5FF60B1039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = downsample.h; refType = 4; }; F5FF60B2039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = falloc.c; refType = 4; }; F5FF60B3039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = falloc.h; refType = 4; }; F5FF60B4039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = ffilterkit.c; refType = 4; }; F5FF60B5039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = ffilterkit.h; refType = 4; }; F5FF60B6039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = "fft-rbd.c"; refType = 4; }; F5FF60B7039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = fft.c; refType = 4; }; F5FF60B8039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = fft.h; refType = 4; }; F5FF60B9039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = fftr4.c; refType = 4; }; F5FF60BA039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = fftw.h; refType = 4; }; F5FF60BB039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = fresample.h; refType = 4; }; F5FF60BC039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = fsmallfilter.h; refType = 4; }; F5FF60BD039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = handlers.c; refType = 4; }; F5FF60BE039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = inverse.c; refType = 4; }; F5FF60BF039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = inverse.h; refType = 4; }; F5FF60C0039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = local.c; refType = 4; }; F5FF60C1039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = localdefs.h; refType = 4; }; F5FF60C2039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = localptrs.h; refType = 4; }; F5FF60C3039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = multiread.c; refType = 4; }; F5FF60C4039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = multiread.h; refType = 4; }; F5FF60C5039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = multiseq.c; refType = 4; }; F5FF60C6039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = multiseq.h; refType = 4; }; F5FF60C7039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = nfilterkit.c; refType = 4; }; F5FF60C8039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = nfilterkit.h; refType = 4; }; F5FF60C9039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = probe.c; refType = 4; }; F5FF60CA039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = probe.h; refType = 4; }; F5FF60CB039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = resamp.c; refType = 4; }; F5FF60CC039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = resamp.h; refType = 4; }; F5FF60CD039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = resampv.c; refType = 4; }; F5FF60CE039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = resampv.h; refType = 4; }; F5FF60CF039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = rfftw.h; refType = 4; }; F5FF60D0039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = samples.c; refType = 4; }; F5FF60D1039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = samples.h; refType = 4; }; F5FF60D2039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqext.c; refType = 4; }; F5FF60D3039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqext.h; refType = 4; }; F5FF60D4039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqfn.wcl; refType = 4; }; F5FF60D5039D87B001029006 = { isa = PBXFileReference; path = seqfnint; refType = 4; }; F5FF60D6039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqfnint.lsp; refType = 4; }; F5FF60D7039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqinterf.c; refType = 4; }; F5FF60D8039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqinterf.h; refType = 4; }; F5FF60D9039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfail.c; refType = 4; }; F5FF60DA039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfn.wcl; refType = 4; }; F5FF60DB039D87B001029006 = { isa = PBXFileReference; path = sndfnint; refType = 4; }; F5FF60DC039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfnint.lsp; refType = 4; }; F5FF60DD039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndmax.c; refType = 4; }; F5FF60DE039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndmax.h; refType = 4; }; F5FF60DF039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndread.c; refType = 4; }; F5FF60E0039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndread.h; refType = 4; }; F5FF60E1039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndseq.c; refType = 4; }; F5FF60E2039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndseq.h; refType = 4; }; F5FF60E4039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndwrite.h; refType = 4; }; F5FF60E5039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndwritepa.c; refType = 4; }; F5FF60E6039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sound.c; refType = 4; }; F5FF60E7039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = sound.h; refType = 4; }; F5FF60E8039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = stats.c; refType = 4; }; F5FF60E9039D87B001029006 = { fileEncoding = 30; isa = PBXFileReference; path = stdefs.h; refType = 4; }; F5FF612D039D87DC01029006 = { fileRef = F5FF60AE039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF612E039D87DC01029006 = { fileRef = F5FF60AF039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF612F039D87E001029006 = { fileRef = F5FF60B2039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6130039D87E101029006 = { fileRef = F5FF60B3039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6131039D87E401029006 = { fileRef = F5FF60A7039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6132039D87E601029006 = { fileRef = F5FF60A8039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6133039D87E801029006 = { fileRef = F5FF60C0039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6134039D87EE01029006 = { fileRef = F5FF60B0039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6135039D87EF01029006 = { fileRef = F5FF60B1039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6136039D87F301029006 = { fileRef = F5FF60BD039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6138039D87F801029006 = { fileRef = F5FF60C3039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6139039D87FD01029006 = { fileRef = F5FF60C5039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF613A039D87FE01029006 = { fileRef = F5FF60C4039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF613B039D880001029006 = { fileRef = F5FF60C6039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF613C039D880301029006 = { fileRef = F5FF60D0039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF613D039D880401029006 = { fileRef = F5FF60D1039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF613E039D880801029006 = { fileRef = F5FF60D2039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF613F039D880901029006 = { fileRef = F5FF60D3039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6140039D880D01029006 = { fileRef = F5FF60D7039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6141039D880E01029006 = { fileRef = F5FF60D8039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6142039D881B01029006 = { fileRef = F5FF60DF039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6143039D881C01029006 = { fileRef = F5FF60E0039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6144039D881F01029006 = { fileRef = F5FF60E1039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6145039D882001029006 = { fileRef = F5FF60E2039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6146039D882701029006 = { fileRef = F5FF60E5039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6147039D882901029006 = { fileRef = F5FF60E4039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6148039D884201029006 = { fileRef = F5FF60DD039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6149039D884301029006 = { fileRef = F5FF60DE039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF614A039D885301029006 = { fileRef = F5FF60E6039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF614B039D885401029006 = { fileRef = F5FF60E7039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF614C039D885701029006 = { fileRef = F5FF60E8039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF614E039D885C01029006 = { fileRef = F5FF60AB039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF614F039D885D01029006 = { fileRef = F5FF60AC039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6150039D886101029006 = { fileRef = F5FF60BE039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6151039D886201029006 = { fileRef = F5FF60BF039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6152039D886C01029006 = { fileRef = F5FF60CB039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6153039D886D01029006 = { fileRef = F5FF60CC039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6154039D887401029006 = { fileRef = F5FF60CD039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6155039D887501029006 = { fileRef = F5FF60CE039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6156039D887A01029006 = { fileRef = F5FF60B4039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6157039D887B01029006 = { fileRef = F5FF60B5039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6158039D888101029006 = { fileRef = F5FF60A9039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF6159039D888201029006 = { fileRef = F5FF60AA039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF615A039D888601029006 = { fileRef = F5FF60B7039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF615B039D888601029006 = { fileRef = F5FF60B8039D87B001029006; isa = PBXBuildFile; settings = { }; }; F5FF615C039D899F01029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqfnint.c; refType = 4; }; F5FF615D039D899F01029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqfnintdefs.h; refType = 4; }; F5FF615E039D899F01029006 = { fileEncoding = 30; isa = PBXFileReference; path = seqfnintptrs.h; refType = 4; }; F5FF615F039D899F01029006 = { fileRef = F5FF615C039D899F01029006; isa = PBXBuildFile; settings = { }; }; F5FF6160039D899F01029006 = { fileRef = F5FF615D039D899F01029006; isa = PBXBuildFile; settings = { }; }; F5FF6161039D899F01029006 = { fileRef = F5FF615E039D899F01029006; isa = PBXBuildFile; settings = { }; }; F5FF6162039D89B101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfnint.c; refType = 4; }; F5FF6163039D89B101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfnintdefs.h; refType = 4; }; F5FF6164039D89B101029006 = { fileEncoding = 30; isa = PBXFileReference; path = sndfnintptrs.h; refType = 4; }; F5FF6165039D89B101029006 = { fileRef = F5FF6162039D89B101029006; isa = PBXBuildFile; settings = { }; }; F5FF6166039D89B101029006 = { fileRef = F5FF6163039D89B101029006; isa = PBXBuildFile; settings = { }; }; F5FF6167039D89B101029006 = { fileRef = F5FF6164039D89B101029006; isa = PBXBuildFile; settings = { }; }; F5FF616A039D8A3701029006 = { fileRef = F543EF5D0375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5FF616C039D8A5401029006 = { fileRef = F543EF4B0375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5FF616F039D8A5C01029006 = { fileRef = F543EF520375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5FF6170039D8A6601029006 = { fileRef = F543EF5A0375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5FF6171039D8A6B01029006 = { fileRef = F543EF580375CD7101029006; isa = PBXBuildFile; settings = { }; }; F5FF6172039D8A6C01029006 = { fileRef = F543EF590375CD7101029006; isa = PBXBuildFile; settings = { }; }; }; rootObject = 08FB7793FE84155DC02AAC07; } nyquist-3.05/macosxproject/README.txt0000644000175000000620000000003211510141774016536 0ustar stevestaffSee ../sys/mac/README.txt nyquist-3.05/macosxproject/Nyquist.icns0000644000175000000620000010034211466723256017412 0ustar stevestafficnsis32j,Z]ܽG? `@J3P6{iqch0^yT=Ug=(pic-X,X'dz BR {tYLwۊj,Z]ܽG? `@J3P6{iqch0^yT=Ug=(pic-X,X'dz BR {tYLwۊs8mkil32ߍݚPߍKVc:ɐ^ hh̒{ Fncaspcbe\ Cp MF_,ځWMCRkwV "6 Wtk9=~I)o܂VVT)gO]$U7evu BLƀO_0V1&DD>} TE7fl#pT+! 3݁us4Ucޯ&A}҂'Qv<܂ .UiR[Fm} #Y2ѵi=A4y<əN CxĒߍݚPߍKVc:ɐ^ hh̒{ Fncaspcbe\ Cp MF_,ځWMCRkwV "6 Wtk9=~I)o܂VVT)gO]$U7evu BLƀO_0V1&DD>} TE7fl#pT+! 3݁us4Ucޯ&A}҂'Qv<܂ .UiR[Fm} #Y2ѵi=A4y<əN CxĒl8mkih32 d}BՌ\ "Ê.!.RiLeۆܜw(Qz ԝ@) KPك 1 QLSɂ A x S +ЄTFQj%W 2_{ʱ0c9Չ ҁe vׂ;@G#-"k2sm/$/~F<R@&Ȅ[he[T "ރ8J{ނԀwh<k1-~ ؁1>@ izP26.ˁg + [2q3Ձoi:5O>ہ **,XۀT Yρ~.*? рdմ. * 5Wk9j{1 ˇ6Yl{  &K׆yic y[1. xZُ . ?a 3"Υ JZ3I΃L31X}BՌ\ "Ê.!.RiLeۆܜw(Qz ԝ@) KPك 1 QLSɂ A x S +ЄTFQj%W 2_{ʱ0c9Չ ҁe vׂ;@G#-"k2sm/$/~F<R@&Ȅ[he[T "ރ8J{ނԀwh<k1-~ ؁1>@ izP26.ˁg + [2q3Ձoi:5O>ہ **,XۀT Yρ~.*? рdմ. * 5Wk9j{1 ˇ6Yl{  &K׆yic y[1. xZُ . ?a 3"Υ JZ3I΃L31Xh8mk it32"Θ##}^>""6l | ~^%L3X2Q9`ߜZ+OZ HٚojR/f6 i !LJ˔B]Yn l)WWQǃՃ!Đn j4!!*H zVJz<;\ގ}ńX QИ.:->@ 6΃pb@9.X@;4!!3P0ZB08sE m-p)3;  Ԁ;рل؊GcFĄÊg@qGEǐq.D fc,c7)9v!9Ơh>>]FFԊb "ƌ"K7)EDEN 1oNoل _NfBŌfsl<ÄL<állvMH"ĊH"ČB2 FITg$($(l P؃Y%j//iN^=ۄLۄL?4B=!ѠT Q j jLpczb% ^'oo?#?4K%ĊM!ŒiC-il OϏ&0-(l l3=/B@B݄ ^J4* b hwP쇄2ȋ)À< À<k@f-BfAnG`܊o:yoC9֊%ڌE Ej5=$ꂃM l|튃F@ƀ98z9td~Zau B8c%|C,pq4o{(Y،F ? l}iρdFy׀ Lj>9P m@  n$e76m\.z ae D͎W tLA>ÇNg}|/&0Đp|}D6(  4=H7ߊe l < N OU ^k4 | k=/x_KTYn2ؒ쇂4ݚr2>ӆ07o n{_۔I# { 9bxI4xw u xL=-o7{ř'r4 LuJ ZIؘL,~ h#@ ~4Zט)|F3"^`۔st" ^-ח>n"y{*f0 đ9e( _ܨw 삃>Vy}6+T aL%dF߄*Ba׊)Ṗ;4@O ,xخm  y$|E  ]泇eQ9"Z5?d +u6@+Z& R1(HΘ##}^>""6l | ~^%L3X2Q9`ߜZ+OZ HٚojR/f6 i !LJ˔B]Yn l)WWQǃՃ!Đn j4!!*H zVJz<;\ގ}ńX QИ.:->@ 6΃pb@9.X@;4!!3P0ZB08sE m-p)3;  Ԁ;рل؊GcFĄÊg@qGEǐq.D fc,c7)9v!9Ơh>>]FFԊb "ƌ"K7)EDEN 1oNoل _NfBŌfsl<ÄL<állvMH"ĊH"ČB2 FITg$($(l P؃Y%j//iN^=ۄLۄL?4B=!ѠT Q j jLpczb% ^'oo?#?4K%ĊM!ŒiC-il OϏ&0-(l l3=/B@B݄ ^J4* b hwP쇄2ȋ)À< À<k@f-BfAnG`܊o:yoC9֊%ڌE Ej5=$ꂃM l|튃F@ƀ98z9td~Zau B8c%|C,pq4o{(Y،F ? l}iρdFy׀ Lj>9P m@  n$e76m\.z ae D͎W tLA>ÇNg}|/&0Đp|}D6(  4=H7ߊe l < N OU ^k4 | k=/x_KTYn2ؒ쇂4ݚr2>ӆ07o n{_۔I# { 9bxI4xw u xL=-o7{ř'r4 LuJ ZIؘL,~ h#@ ~4Zט)|F3"^`۔st" ^-ח>n"y{*f0 đ9e( _ܨw 삃>Vy}6+T aL%dF߄*Ba׊)Ṗ;4@O ,xخm  y$|E  ]泇eQ9"Z5?d +u6@+Z& R1(Ht8mk@nyquist-3.05/macosxproject/alternate.icns0000644000175000000620000023110611466723256017720 0ustar stevestafficns2Fis32aj+alruōJzw^Ʋȶũ`˩ewjFyJ ʶ[''9WeZth;ǻǿ¾ӺǾ½Ƕ·ƴŻÿλưʼɑͽѿhjms?onMfmŨ”ǞΩqՕÎǛ`ƒ̒aʰřf,ǵZ"%ƻʾ|ūLmǿɹŨeŲ€ſĀaиǹûϲ϶̺;ȹļǼ·Кefeh6jvs|ʼnT”sǖ¹ǘʝx~µ~|+½ŷýΪ&#dɼ»ĽúüȌƶКźʽûĽȒôľ«ƹýŽiys8mkil32 !SFoRVU) 1jqk[g\kbkff\V^5f^7cɵoº»ͱѵ˥ciD̼͵ɬü˶ƾg`ҹML ]H`^`_eehw[m_XPMjBY`cYe꾶¤׫ęd_֫ɫaʧ¶|rܷ`]cQja`cbjb_\Y]WLLa:RPȶ[IJʻְ̺ĦVATž°˶ѱִɼѬy^[&ps[`[vDXXdYdXka^Xqch8UX!+ҿΥŷjjWϽ֥񼯫̳^bIT`nzn]jZjRXSZfk\SWn50.]@}ǾȽ¿˵ waZ*t`vQ]nqɾѩ̹ɯů SdʭaThUfpjPXjRb_W\mcbZp[ff`g\6]Ʒɨ˴¯ƹ̺÷Q\ɳȼοǾѽӾMbºڥɶڻקԼ˳clγΰӺѹ̢ƲcJɩҹųɳǬ¬`XҩؽҴϭˬس[`Ϲҽ˳үؤѨŮ˱mbðࢰҹʿжͤʴmcǻ۠˶Դ٢ʾλտ`\⾼ºȼϲ߷ܶ_fήԼ̪нѲȾѾνXV̾ϵñαɺժմ^T̪ƺ­žϿ˯̲d]YʿɳŨ˵h`ԶٱŴƿкĿN2^Xa`PM`k`\a\Mg^p_g]Oqaa\kcf^eX:(hmSL]l>Khc\fb_dQiK`V[ZgdjMdR(a[չ§`iʹɰncZQӰI Шk۝཯bcrT[߼cDsc6Sƾ\kTw±|W\sݠg ~ҪZГ_O˹םZsl_mishĭWȮկJҩb֬VBa[ɺީϘfصdcaSBW^ϿmȾlev/8ϵľjàewM[ ֱͫٴطxbOhX μͷтȼ6ri`X/ ΤظĻeŲNebr<HʥͻŻj4ͽcW¼ֶľȷϽ˹ӿi[Ʒƶط¼ŸҿƦPZѽɺǾȪܳV_ʬɺĶʷǻɟ_r̻ͩǾϯX\˶үѸ¼ͿҹƢk_Ԫ˺ùϦʺķƼóμľ^[˽ƿȿƼ÷ӦỼ^bԲžॲdzìշǩӧf_ƦʬëƵ;ϻbYͼҷǺ¾ӾٸӻnZյ´ɴ뼣ӷϵܫPc͵оżѵ̿ȿ[U­ֿݴúȱǖܻt[YƴĴַԶϳӷm]̽ļĴ׵ȴƹŭU0TMa]]gUhkV^r[i]j^dgZZllU\XUXSj-/Hscd{](+]Q_bf^MZbd_PghW^\qao*g缭ZӴvɷiSݷUɺ\NL^_8ZeŰѭpte̴g߾bÝܬٳqk⹢Ƽ}̮nު^}U:8b^vgvޥƶƫLȻџBfïԘοǧȤwبոjr?V~hŘvk9 TɭǹБn ƿзʪȩԏўp}ԓSa6Dnɫ㦭ѿŻɿֱXZl'Mڼ̼ζɴtVպآ|Hp͟ǩпعʾŭN`ƾε®̽Ķ^b̻ԭгɸǻƦѶXkѴֹżκg`ʪ׾ȳ¸ѻƯXlͿ϶̼ǸǷÞ¯йfYţϱϺŴij̸k`ڽϫʦùѭѺsSؾ֞ͽƶa]°ȣηļ»̽akĿνȵƢ⮲ҾɧûɿmjѫʹǭԹ̼͡ƱѾ̺Y_յľǶ˳͝žվβдȽaUȨ͵ȱĸħ^_Ƚʻκż˯׻ϴv-Pba`X\ft[Rd_aLZ_\bOZ^VllbRL]bX8l8mkih32 ͎ǵctQhp_ſ˾ƢͲԻndž񽻋]gȩۍ׫ՙֱº~xӳj¸οѯ¾٭мqŵгQ. qvVYXlSVU[KbZPX\U\ZSeqT\;YBRibϫλQ|ŚĘġϸƹtuVο)\¯ۯƿسЍgÜرϬϹͦڸscȖ巻4ێľޣƧڵP^󾥇Ε+X3 К֎)ϳNmںɱըŃ+QߙŽкʫĿۿܼ&pÛ"Ğ£àǻ۳ġؽ-[da&hcaRngLUddaYcdmrinjdkoc]QoQ`mul9͜9(Ʀ}œؓ(D(V)̴ǯ۸ٴޝЩ˷Ԗ/a .* ާ՜άⶻ)K$үΛʝզϪë'I&  /'VѸƨéҩлȷǸb^iNҘɛڴի¶x,67;\=ᢪџԢΫZŸ^Aϸ{ѭո汮ë)(Ư F\éò΍ěƜᰦպдsuF=Ͷ{͏㾳ꩋ yĬД¸஧Źuvӧ=<{Й۾|£橋iƿɵӊܪ躸ɾvv֥=={ܨӷϵȶ#)5JŜ͉٩۲㹯ޠᮬxrͽDCȥ{៝·εƸ0&();ƥÉ٬«ײ⴫ܠߩ|wTQ{žٲˢӺ$DYʸۓɶҾö˺̣ı~z߶خPX¦{λڸƤع/Aս{qȨʻeb{ʢ9?˧/ʢûȖͲ) %lj01 &Ο»ʓǭ+ UX%,23{鮮Ч{+(k»Φ-+0/09MNjÔ޽gc(${{㸺ѱƣw*+{ϻ輣;(BHGGDWަλثǼˮȺԛ»upùdz-){飗})'۪suˮն۬ۮΩxp(,{׻ﭡ荃'%تƹ˵׼ϭԵ௥ܯί©}v',ï{止߼Dzk㽷ӼúԫѭƴýÿٟԚ&,{ީɻ̻nžսȾتϭ̷ƿܤԠ&,{Ÿ຺؜ »q{亲˸ڭƾܰѲܟ¿,0۽{ýؚ"ľὴʻީĿܴӵؠż˶-0ݼ{vƻćƼ,+ȹȜп̽ݨ1.{n¿ü,)ՙةǰ¼˭Şк,)Ư$w˾'3뙕ؽ   14-% ƨwрֻ'--,* ۿ'$$i(/96(́ȸ}q}´ٖ(&w ෪nx ߞʱê萅ǨľʫȿݦجåҞ§ͷ-+z%~!s BU-1țʲǗܻٲР㥜卵קˢ۟0.+&im+:sp)1̤Ƿݽٵ̝ޣ򣚳ᩥϟӞ//"j鶱斖豩߾ҮƳ򢙮ťåԧ(.{{f甓䬤ǽ֯§翸˝ɟ֡'.((g/˽ľյڟ؝ູؼĜҢ仹ո*0a0ü־{|¤ՠį֡㲰ӹա྽ָ*/`Ư΢ưߵżϟխī֞ڢ')`ںƚͰƽǺɿu"#}{qqL27,,  :5.(g,;sѮȑȵĉ̫&'g8Jžǽر੡ĿĬīà㾥98)tм˸þ<߷ὴ»ʥЪثŸ|7&3l#̰з޷ῷ߽ɢԧج'o'u戅֯Ε៘Կô߶ʫڷ®)0p+yolüȈıڸòڮ¹ʫۯƫ°)"&219;1+BL]W#11!#ĜոҮߴ̿ʟѢͥ'&*,/1:867&!;Ea\$#>=)¿ܵѲṮ˟ɢΩ(yrq!qq·nfûْᢡʺҳˣԩ˰Ǜ̼.}v4$mlia»ԒƋǨڼ*uu涴ӷr'\ռ#$Ծ׺͏ȞɿeӻӷҧͧԻڹȬʭɳġ؀պιåŬŹУɶ;ŲյִٜżԢʫҥSڲͺȽŹԠչ˷޵è؟ϭۡʭΫ۵ϲĽנުݳƬ۫ۿΡݿݱ⥝߮۳ª ,ݯǽ՟ݸŵݯ஦Ȼӱձٵ׸ṳӣµำȺڣƼѰƾͲܷ۾¼ئĹۻᢅ蹯ư۸ʱߢУŽƘſڢùŦѵ˼ף߸Įܴ̹¹֠ףƾɞٜɥʹͽЦέťըћþ⩢ÿٽɺɲDZ̧̤¿աϝƿܨȘкñѳªûݩ¾˧ϲܛ粭\ÞûïؾభɽǾɦԶҶĻߠ¿߮ºį䫦բĢӶɲӵ⺸׮ȾݼⰬ֞ãԺĽɭêӷٴĽյIJ½ڼߨҾ̲ɻʳ̴ʬӷĽںɸި˲Ƕ˵Ͳǩҵ̵µ;輺Ԡ½üϠIJخɠȫöϺȹ仺ܾأȻə٨̦Ǭɟ͞ҢѦɟަ߶.еݳȝ ٱѸ܀̟͟ԤɢŠᥢ಩àϸ輷 ĞݳٵŞּȜ˿跶ݲѬζ͢張ũȷŜƵ巶յͰϷΤü鿸ɯdzؾͶɣܯ˰ۣӞ¥ҢѮնӠɺʩĦܸ{̴ǟ߯ʭ֛å̚äɢͬղ֟ȳƫ©ༀɢ翺Ψͦ׹Ǿקנ¦¯ù˥徹ҩ̠ڹŻө¼ܡʼíõƺüܼȼƛŤպйäƶàդùɼƳòǨڻϱýųľ֢Ƽ̶Ǵ޶߶دžǫϲĢ੤żƽϴاԸnݵյթڼƬϷĠߧɿ¸̴ۀڥպ۱ȟӸҥ߷ԩӺɬγ¿ͻګƻʳำǜӵӜᶫѮ̸̮ѵʷӻٯŹòÿĬ߭ڵ´֛±й߹ا䵮ذ֥ßǾշݯع؛ŷΰ徴ܮᯨخʽޤìֹҧĢҵݢѝѶжΠڮ֠հ佷֠Χܨ˳ץ̢гݨЛδԼ̤ݰТѲڻ˟̤䰧˳ԱբϷǨݬ׽ğìơۧٺſʨƸදҤı֮޽ƽƣʬ΢٦ҿìö⤠޼ϡί޽УЭկǞةʟªƥղįأ࿾Х֮ݷԞѮճˡۦЦſğޱDzȧ϶ۼ߼ڻ֧ȲԣѿɱнĽڼͽ٩௭ΞΆ̵ʦҷִڻԼӣȻפ̷Į̸⾷ῼר౯~ʥཹƯжԤջòѧܳۢͭԱ٠͞屮̮שү̡Ѻɦ޶Ѡϱέ࣠ʝ汭ʫثѤټÿ߮«ԾݽѪɻݹ徴ڼ㫤Ĭϛû¼þമļڷХƺ㿴ڽ䦠hȯýɵ漶Ƽ֤ϛഫξشݽޭͧѧɦ϶Ľʹ帳͢͠ٶԵyڭӧЯʠʹĿùǰө֯ϷƦԧǀ̪٣ɠݾѨ´ʬҲִ˪ѧʬۛʧ࿹ʤˠТɢ֧˹ήŴָϯ߽׮Ʈʘʱ¾ʦΤΠ¿ۡҶѵýмعШബѪŽˮןӷڷҼᢡ٬ʥۻܶԮ侴ƶƾܼۨ¾ýη؞ڳ׾Լߩ׬ѠٳִҲ紪ŴȺޭزĹĽӼ崯˴àˢݢƵ¤䢜˼QսʳɴṶŶлȜʞ׷קǰě䧢©мſڹκįߢݜПᲧ˥YĻƼԨȡӭܶٲ±ϲ!ݞ؞ʥ௥Ϣf¾حȥئ۶ٯîѭ͢׼;ڀҪƺÙԶ־΀ƾڶư÷✖ס¾ث˨غ̼ʢϹŢϼڽϽ̾ԾոȬƺޠդ½ݥåݞϽ̴̧ͻإקԭӣȻŸРྐྵ嫦Nj̽Xť¾ϽƳƦɘȳ!! zʤקkp{v׾*CսǾ̪Œw|õǐ+CijٚۼսȤϟĤͳֵɤ-ɴ噙ΛŘ#5 2ỽ鵪;.~/05IտǸѨƺʠ-,˰ᗘ齰ϙƽx -I,ڽ䴪ڸ|;/BвլÞϷϳΣۢȒϤĶDN䬏鸮ŻF0,:BCĺާ̸/¿Рޞ̐Ѭ¯CMŨⷮļ1,?D?⫨˷5̴Ҵĕz%9ջǕκ @@࢝Ȩλٱş̸ēz%9̵ΗϺκ/*C=ڢͯở¹ÿ ѧλȻê./Ѡ=FڵܯƟëȲԽϿŬبнŖ)0յ,3⾵ݭʨū ̶ѬХT־,)ӸрU43ֿ34׽v|аިӹрӹжGJ42~}ǰ˸.بҼݯݯϩ*1GĿپ׳5/ Dz1ɏɬƻJ3ܪBѾج٪ɥ@02ɼҴҭĬ{{ݫ૥ȥ0ᦥ½°01ü{۠ߪƪϹ46þ41׼{ºٛ񧞭Ͻȱ緹μ14εϦ45ۭ؜Φ{Ӡ񨝣ָѻyἿǷ浯֮FDɪ١ƫѽģ۶e꣢!+ХĽƮڪDBƤٲڶΥнʧ{ʦ࿸禥.!Ƞέ%.ʴף0,Ϧڲ״ͻ45֦2*ѥ{ɺȸƒy2B~ֺ⣈&&ļǿƫ.,ֺӰӵ04ೱԼ*/ũ|ƸɷǪ, *e|Ӻޏu(.żɽƲ+*޹ٰԺ!ẸԹ ּ̰ԛ֏騢*(%(+'ցՀـӻ34Ҁ,34־3ՙٖȷ-*Ӂ:־1'׾рс3233й3䳲λⴱ2*ƾv(//ʦպҦ2.੣ԿӼ{庻ſմ0*ȝ+++.ȝԼѠ41ߢԺ˵{񠗱ݹϛ*-˳ƦƬ̘߿Ϋ13ӤƩũ߳ʵ{瘑ܻŕ&*Ȩxz߷گ̛þDZ10Уέɬٯл{ܲ쫡蘐¸w|˦ɡƩ٠40FÚ޻Ȭ׺Ӽι{ج읕Ǿɩɠ˭߿ءB*1ſῷ˯ҳĪʴ{|㼟붱ȽĭƦ䷴ťİȷz*/ɺۿ²{ݎƹ轟キŷìǨḵǞİķ,/ͻŬ,,{墡ϋտۯҘŴڪIJijØȯ1/՞-+̷ɳ˱G}yuΩΔڬƹ˹Ɵ0ж/,עҽдҷ<~@'/қŪփu׼к33һ34׿3ql˶1}Ūс π׀ֻҼ33րй34ѹ3ŝj.FҼ×ı±ۺǮ.+Լ溵ױ ܯɹis0λʿ¿طĬ.+н޳Үі~($ r#;.(}ŗxxĞ֧Ǥėǯ߭Ʀ$'p !+'u{ɦ֤ʪʡɱߪѶǢ°. n掉IJԼʟ߶1ê h숃Ӷɜ/$zධ-ë44e␊ޖӳߩ㼶᠅#-ܝ̶İӦ_Ÿ㑊ܚܸ֥«㽶߸䟛̴ȳϞ_ﻳʫަեޞ֡г緳ۣѾ_Ļʴޯڤ⣞ݥҲ$%澻তŰ/րSS׾Ѐ 3333 րЁSSׁ3333g6ޣɬľʪ۸ת㮪˳ӣ#$̭-ƿد̷j1IءʩٲԬߪǰϢǭ)ӯ̹-%nŹĞЫ½ùһ˶ëtڽʺӠ%'o(ǺλŞɨ侸ռñ/,ĽڴͼϮy,oz٢ȊüṳĢ+.ϝԣJ7x%9⧞Ӆ~čʾ۶ʞƶ)&|&)ϙלֽ흓ܞɟ඲ۤs'3ж*&ՠ̵ּ֜9-**㦝ᦟƞǛޯժ'/ͺżשԼϢԼٵ%wzzò瞛ȼƏڹӧdzŵξŶ̸.ȷҳӻнտ.->Eᚘ÷Βչ٫Ǻƻĵѻ-c/ɹױҽ0+ɩԞŽǀòɀ;ųĬԳƂƀ Ȁʁʱ¾ϥӼעڳȼݣàثۥ֮߫٬˸ؾּͤϸќٰ̾ܥÞӮڣ٦п~׾ѱܧ˻ӹẲŲȺĹʳŸ׀Ӹʥ»䤟ݯಫ¿µ̺ë׹ɠުܧˮ˦⽺ɨѧӬ׫бש­IJŸǥǤžаѭɧἹΪЧثҥѲ׫Ǭ¶ɣƸƢ¥ĭԬȯӻīծ̤ӿܽիXЬ˱ؼǜ̹ѿ̭ӻـ֯ΤҮҲȪĝǹћÿťާԮХˬͨŢʬŸսף߽ƿި[ѨཻҦʩʥĞåĻٵîΦЀȟ֫۶徸̢ڻ¦Ʈ㥛ӶƳļ֧Ȣت䱫¼˟۽¿į¤ëݢҽкĘӺݞ̝ڪ̯þտŬͼșڷ՟Нخ輹Ѳ྾ݽʨΡ۰Ȼشع߸ʵ伺ӵסܹʶ̫ܯԦ¢ĬĽٮǴӯػἺѴ޺ϮУٺǿͲ޳պƿةݽ௦ҭå浭Ծ̙֮ǼʸʹŨڵּܰ㥝˭౪͹ԾС«³ߨ˷·̳ƪǛӳĥԠʨö̲ѻͻźëмϜ宬¡䬨ǥܸȲܵ˧ңɣɼȲѱзºһϜ౰ĺۧǥ൲ιԽӻץ#ӤϼѢ̳л€ñ˟ѩοנП¿ӠȮͼɟ̪ѽӻåŶݽŞңž˳׺߾ŷٶȟó޼̡ԙǿ¼ɳñ%ݽºǫڀӷʧٲƿ®ިȘֹ͠þ֥»ʤɳڵƺƬӼ˱ٷĿ۩ƞϾ׼ǞРʥĮޮ;¾Ѹ֮ŗܰƳڹƾɺզߣޤ೯ࢗԡݭӳΫʜ۱۾Ƚ֮ڧ֚൰û夙ҡڭٵľ̳׬ɹëܤٵܵ˟ҧ̭Һٽ¼ҳگŲ¬ۢݸᳩëѩѮƫ׿̴ܪ߷ʹ֫ϳկЭҵڥ嬧»¾ФڼʩƲӺ㱭ݶȱۨӶجѨܽݪުқڶ̪űéǶ ɡ⻱Ŀ̩භͮŵѴݷ·ϷDzdzɢʰ޴˳͸˭າὴʲǺ­櫪޹ÿ̿нȹ޺ᦤԴͻɲЦĴüܡ๵ļľ¾ټźڢԺ̴˲ԡիˮΘبݶѺʻ֡ťҲʩĴˣĤХƳդ֥ڵ»ʹ٥ṱƟ̱ʫıţä֠ۥֶѩǸ˳੣ϲỲƥ۾Ƭț˹Ӡ䯮޼ʬՀι̲ۨ׷ۼäƩ¼ȝ˹ٿͲݼî¹ϰ߶ڪצɰʩؼîʾҭԽڷ۽گ֝ŴžǾμƭ۾հٮ֠ڶ˳ʻӪ̶ûϾåӭ߯ӟصʬķýӱԸ湴¾dǠ㪩ݡȜ̛دǥ㴯̀ǿ̺ȥݯަļžТ׮͟ΠثРǜȡΤǥƞųſ̷ẹ̈áٯФŸѪۺɢ˼ơ̶ýʽ¯©ܜݯ䤡ӻӼݫɡ֣Ϊڣө÷ȫۤ泳ާܹϼ䨢ΟӡѰԽס྾خż٫`س繵DzɿٶɶɴŻٶŶןրӹտ߯žث㹶˳ŷչ˺ȵ¿þҴ˼ϛkյŵ֣ɺާŸѥÀިӼŸЧùડؾŷҩݨպܸڱ¶ƩԽРдⱩͲɾԼٝѺỺخб̷Ԡг߫Ӷʿü̽׻ᢘ̸ѬөøʭļŠŽȬڲϴɺɹڮػέѮ˸ɭ¤¼ûdzۯ̴ʺϴէѴĨѩ⫩իαע¢ƨ՛»ۿ߯Ŷĥభ ޲īԮᰭ˦ϹҧťƬ֡ѻ߾تɺǥ޳ Ԯ²ӳԛѬŸƿȦռۧ޾୥ϸȽƬסŴҵء׫ƸÝ˧ञ׺ᩡ˶ɻĨԧñἸ̧žȼ丯þƣқӹˮƠɭʝʳ8&  Juzڹ՚{Å}zÔţƦĚϽġ++ԙѳؿت̳ѩûĽͻܴΑ֠Ƴp%圕ԻյµF434;H˽ŵ١Ӱ߭Ϸ֔˖˲t/~򟕬֭G8:;:Dƺ;עج߫Լޔַ̺448"̸񶧆ߵC47GıDAԮڥdzѶٓڸʸŲ43ɶ8ȳݱ2"1GӿOGҳԩ˰˱˹ڹ¹ľӸƱʼGB֩ìҢ«̼ܼ²Ϫエ('ĬMCΟǵПͿ¹u¿}¬ЮoѪţ*'zɼ۴C@ͨީõུkŶѯ~hŞyԥ93ţ՞﨤ָn漳dqj\ cpkkoommuuoosuwwvuvvtoOLY]lotuqqrswvqptl76emmnstvuponnmovvpostppsrpon|}qwa}qvwsqn` t궪ﯦfttfixzxmmwwjisspqvvqonotn?>hossnmoqvvonvwwn74Ybqtsropvvonoputoopqpopqxǃwr~{ovvqqxkԸ°C.3wrҤ± Й;&+>ә溸ծ횖ң󦞺̶è̻S>'8矝ڇūث͹ƣ؟H1%8ߢʤܶ੫ƻʩ𐈵嶭73yF9!/܏ȿ19ȺɲϨޝƵë㓌ð74F3刉ǽ֫-.ȴ39Ǿɺͨ֞鸯ײѽ"%۪IJϺѻ/-÷Ţ33ľزϺ$"ӫĴռԻɨGEý󦛟ͭҮ¹캜@+69DTҧگþѡöEFǾʼæܮ󤚦̥ͮ곲潴S?95*7֞Ժ+&Ұӥ::Խ¿ͭ۲鮦輵|}ۻѼ9.q ,Gҍ࿦2,{ڶťٰ5:УȾ׮Μ|}շ:-k}" 2ćϫ Үѧ6;”g·򹬙ȜƖ컹ޚ뺷Լ˳#]jrsqqro^P 'kvvullvqMJX]lovwqpssnnvvpwqpprrph==nunnooponnmnrsuustwqoorsvuo|σun{礥ںѮѼbpttwwssui#U^[[]][V69ovpptutuwwvuvwqpvvutog<=ipnmmntuppqrwwqop~}puurrutp}ςusלɽ饙Ϻ0 !ϣ½լğ57Ŭթdz¡¹Ւş竟 $ƺ3 "#1ݯٴͦ25Ϸܸͺ˯פ⠡篩54ſqhʬý27ģܹԳΡߚ븲64Ɣʊƻɥ35¼ 㺴ٶڶ㘒ԶԵ쩢Ŀųњܳȴ8&5LӨƩ㪧ݦӼ玆շѰ¼͢ᱪλI4%8ɫ̭ا毥~}·xw~쫨ۧD>ȫ⽹Ĩʩɿƿ42צϴxvDZyЙD=ﺫæڷüƢƼ72٦뱮ֶswܟ䰧|&ɷȡƷºݥɰ99νݻĬy~ǎ˶!~ƾҷЙɷ;;ȮΫK׵98ź `ovwvuttppsrnmmnstqrxwrqnnoqwvomnnmmoptuqpoostrrvn==nvqqwwpo,qrqpnpqqooqrsrp}Єwsʹ$İivnovwxvpokmxxlkpquvwvonpSonouuppuuonnoqqnnrsqpnmmnun==jrwwsswwqpoovwrqrrutooppn{|or飝2((!y&K^ΕͣއϙɣȚȺ;8Ӿ̳Ӷ¾願t/B$ޟٱ鑉ܨάӡ?<»áz."&"s 1II緵֡Źܪɥɟءܷb_ާ͞m#"oGJ蹵ߨ߰ˣ£٥޸he᪢ԣ]Ao85$⮩ള޺͢Ϯmg۷Ǽ־ٺM3nݭﴭý٭߳ͥť}uܹ¼ع77j %ȴʨͤĺúʬԥusƬ󪞛ƱӢ޿a $öŮϟ༲˲ؼԣmjĬ󤖑ʞ`޸زҦºᰞfjȺ`ܡѪʨʗлӠmpĶܽ$2irrsyxpostwwu wwppssuuvvpop qpprrwwuuwvnnopwwsrpqvvpswroorropqۃsmmooppqqoorЄЄi,9gnklqrutnovxywpossp ooqrppssvuonnpquuqssrruuttrwysoouvqqpqyہrvvssponmn|στig>P֛ɟð¿̳οٺg DXśߟ˳׮ʼȾéӺǬi Rkܞܤب˥ӴϠΧԡҳ0k!]tȘ壞تʥ̯Ѩҫ򣚲եʫnȞԓȡ˵ߩ㺹ݪ±ɡþκ6r ͨޑŬŸܮỺܨҩ뜘Ʃ?$#,G]܎ϭǗǻبΦȻҴX= :Datב˱˗йܧѭҹy1@v屪۟಩ϪҮþͱϴ)=Kӝop۶ڸҔԡؾƝõƿ⳨ȳ¤Է⽹\PVXZZ_A`ccZY[ZTT\]ZZ\]_`dc^^cc^^cc``ccYYbb[ZZ[cc``_`a`[[`a`__^\]`a`_[Z\]_`e d^]YZaba`^]\\^_\[Z[debV ۼk]_]^_``_bcba_^[[YY\]bb^]__XX\ ^^YY_`bcbb`_bca``_ZZ^^YYZ[__YYbb]]aa__abcbYXZ[bc`_aa^]\]aa[Z^__T ϣܴзҰ¾˻ӱиєƺ̴ˢȝ׭Ǻšêͭ¥̜ṹ⦝ۼԳɱɢȥӨð୤ǸٲžþСܱĢղΟǣͨȰ˿氨ȷ׻¿Ԥد ڶƽºɨټϜĥؼ¸ƨȳ˰ѤǧݺΛŧԼó侺ʦÛŷӸУ̿Э¹ƽѾ幱ì֪ ؚخͺϲäݶȿݮڛҭ֜¿٦ɢٲĻҿİ͠ƫּݠ¾ؤҚؾ๸ƿ̾įɦǫپԾŷ˱㥞ÿכỷ¿ªڻƳмëƺ"ǰƾξ²д⩢Ŝট⹵Ժڷ̷Ǯȹǣθ˭ҷٲ追Ң¥ˬڹٷȧͭʵҵ侼צ½åýȬڶȽҲ̭Ǻýìϫট֨έ㵬̛ѦްػɭýǮɥ姠ͧ˯ڵ͡ѧᶱ׼ͱᡝʺϬ̳߮ý̢خʯ۽צХԻޝӾίೱԹѣ׬ūϥҩζѥܥǺĽáŸȳ¥׮ɥ˥؝˻ę㿺£ŹDzܮŴЧijMӻӞתğߝҹǷ΁rɬٯ׾ɲɿѿסتۡд¿̀ɴĬԴڿɩԾүغգܴժٱýæŻѭԽ՞յަdzԭؿơٰսݠųڣŶԽިӦ۬ظĽ`ڵ־ڻڧ㟘٣ƽĽޤФˀvݦɸܻýݽס١ǨѴϻŵ֛ڶ׵§٧ȳŰҩՠȰʼϻÿ̞ӵҴæ٧θưƸڡŞеý۰ӵԨ׫˳໴žǶߤƟ;ſ୪ԵիܰŮᷯƢޥûƛķ֮ΪʫȞᨣɥ٧Ծ¹ȜĴյҩìǟڨǥע¡ԱμӶڼͧᰧ轹ٰͭѦڡÚƢ׮οܻê׺ѨŲ׮泰˦ڮмިʽʮ߾ͫ½Ȭ˻۩ڣخüߩѸ˯⾹ҮÿĬ;ݦתֵд·םܱ޼ˣ୨˺ˀ۵پø߾зϴҞ۶ܾȢ䯪ʼ سݻ=ó⽼ؽýɨȀɿƹدާݫɺ⬪ۼԽ߬ٯ͞Ժþɩιùƺ׳ۣڬͺ٨߿ҹժԧ˘εƺҮƵťíѢװ¼ȣٶڬԺЫȯϪͯ¿ğĽǡִ۪ԳչԤ۪¿ƴɭУۧධǞ¼أذҞȶҶПکɺùˮС⥢㲬¦ʝޡڬΣϼŦΥŤ½ͧ؝͸״ַ͟Ωг˦ɝ¤ݽΤĪС̸ٵ׷ʧ˪ǯ۾ᦡǥŞɲأښĥûأόƹɡǰȞհߧéKлŤŷĿ؝ܛŦ»ݪຶĀ͢ȷȡԭ׼­¿˽۵͡ɟģçڹִŹס١æٵɺìմРʟ˩޽㻲ڳʹޥŨݰ ȯγ֟ɢ¸ٱۨ߷ڽٱڻ؞ңְ›ǩδާ͟ҳߨ׵ռ԰շ֣ϩ͠ѵöܥʶʴ⩡ڨˢṴͿ̤ڼƥжӢԷ١̿ǹŴ٢ӦҢڸÿͼ̢ḶǾӹ³֠į̧̂֟ᱭǣԻҽԽŵԠͨҥݟ۩˦ٸ«¼ͷȵരͽɫʫ涬ɣݭݰſÿ強ƬĪϩ޶̠ݭ巯Ȟ¹ޤϪ˧ʥھߵ̚ѱȚĸؤͩúʥ˥ſ۰˛ijմIJȳȹūة»ʩ֪ʩIJݯ½ȱ³§źکӻİ֩ͬˮժ׼̴ǶܧȺͻ¾Ͱҷɦ¼Э߱խǒƜȤ-Ft8mk@nyquist-3.05/macosxproject/nycon2008.xcf0000644000175000000620000003421011466723256017222 0ustar stevestaffgimp xcf fileBB / gimp-commentCreated with The GIMPS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) p'U7iH[Q     $(gimp-text-layer(text "Q") (font "#GungSeo") (font-size 90.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) H[dH[ t T////000000 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5666666777777777777777777////000000 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5666666777777777777777777////000000 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5666666777777777777777777MrzU',T ڕ> '4O #-yF ._&IM gYf lLI09#t;i(x7sOYsU{6-)|% , gb }P Dm^ :b _ SYQ 0M , ^ U w oa B<   = J b x ~X t., r S |} X n& jS k D Q-y s   u eN XI7K$fkC`p &&&777777777777777777777777777777777777777777777777777777777777777777777777777777777 =; }-2c=( a3<[IcӇM! 'Q!]&^ *Lxj/ pn/w|0i !.M].: O.' ԊN" * Z@)i H+ O X .Dy׷w4$--j)     Zgimp-text-layer(text ")") (font "#GungSeo") (font-size 105.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) :-jR-jf 1g(}w&I$^h$8 #:$ gq$)H#c #c#}&#V"" ]O#E"44"O#g "i!8"+;"9g"8|!*!!"!!"!*A!1R!3R!.>!((&' ;< UG vI >!+! !&!K!ou!X!;!!!$!H!lx!Z!;!! "!F| n[ > # v FI u #!:O!V'!j ! !Dr!|2!/z!];"~" ?"'"Dv"$"7F#f "" ":[#*u"} #j#Cy#3t"Hh#D#F#$Q%Q'5-j(     gimp-text-layer(text "(") (font "#GungSeo") (font-size 105.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) -j'I-j#3 I[&x$s^#;!{C!  "!#"-9"'V"g""Y p" !\h">!W"C""S *!"BT! %!>o!:! 1!_!08![ | M ; j!!/!Qx!vX!9! !%!J!ov!X!;!!!$!H!lx!Z!=!! !<!T} ha!qD!r%!k a! _ h!s!o![|!3!"."," ""d""#x"#TE#5Y#c#O# #N:$%$W'$b$C(%g\ %.$(%E%w% b}' {T)5M[N     gimp-text-layer(text "N") (font "#GungSeo") (font-size 90.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "c") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) )M[)67]M[)R1s46////000000 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5666666777777888888999999////000000 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5666666777777888888999999////000000 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5666666777777888888999999 B    l(+M> S2 CB% 1X=""+| . M!xNs98scWzc989  /PElEo3v ofm: f<w <:,   B2c Bl p' li )m i? d/?   -5? x ?i :gil v/lBf BK& <6l<fw6fo3oErJE69 c@ y~qX"G ?^?                  ?                  ?                  / ôy<@  ::::::;;;;;;<<<<<<<<<<<<<<<::::::;;;;;;<<<<<<<<<<<<<<<::::::;;;;;;<<<<<<<<<<<<<<< (8 dE;)Sjc=t%f~J ·{ B -97c                  _&- Background     8808|8L8X8d8p@@nyquist-3.05/macosxproject/nycon2008.png0000644000175000000620000014054211466723256017234 0ustar stevestaffPNG  IHDRL\ pHYs  tIMEmtEXtCommentCreated with The GIMPd%n IDATx*hh;;##}}^^>>""""66ll || ~~^^%%LL33XX22QQ99``ZZ++ IDATOOZZ HHoojjRR//kkwwPP00ee aa ..<<JJ$$ KKDD55**QQNN   UU##AA,,//::55YY RR  -->>@@ 6622TTllNN ;; ""pp;;JJCCSS22''((QQ99MMbb''77||<<$$ Z IDAT55&&)) 44// 66..yy66[[cc**,,**!!ccGG++&&++99aa,,++ !!**UUJJ**  **,,**** {{****99KK** **22DD****^^..****yy **..eezz** WWccGG %%..""$$((ll PPYY%%jj////iiNN^^==LLLL??44BB==!!TT QQ jj jjLLppcczzbb%% ^^''9; IDAToo**vv## **\\|| **>>BB--dd** ^^RR **77FF uuFF**pp&& **^^))**##cc !!****OO##%%ww]]!!********#### ****00))** **''00!!**((**.. (( 88++**EE!!qq**88((''33EE88**22%%-- 99II++--(( !!77\\..** <<))""bb** MM (( &&VV??  @@ ,,tt**MM** ++''ee****@@!!--CC>>**%%AA,,@T HQ IDAT NN,,==@@**''--??pp||}}DD66(( 44==HH77ee ll << NNGGKK""))gg**.. cc 44--]] HH++))mmJJ""7777"",,WW''$$ 00GGRR00 99 ZZ$$00 ))<<zz::NN  DDLL^^ NN  ++CCtt OO11LLuuJJ ZZIILL,,~~ hh##@@ ~~44ZZ))||FF33""^^``sstt"" ^^-->>nn""yy{{**ff00 99ee(( __ww >>VVyy}}66++5M IDATTT aaLL%%ddFF**BBaa))PP;;44@@OO,,xxmm  yy$$||EE ]]""ssff33'' ZZ55??&&JJ<<,, 66@@++ZZ&& @@CC44+IDAT͍؋sIENDB`nyquist-3.05/macosxproject/nycon2008.gif0000644000175000000620000001037011466723256017210 0ustar stevestaffGIF89a  !!""##$$%%&&''(())**++,,--..//00112233445566778899::;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ\\]]^^__``aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~!Created with The GIMP, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8a6tnfZr: `!r/І]ࣖ SD*һlZ`͸  `z& Z.}p#>%E]Bݘp0cհp VhQF(aM6yVj 6NK .]0Hutat~0*|K=A\I-žEmzBu*20}h Eh!XB Dh6\q΄EwW>m<vI<BwWpC6Tݭ2܎ cLwXDPd 4A8D]iXP14t%Bw*"fC QH>6Lɏk099HQ:X !*!l$NLC$05ohi;LSQ?aChGL <L`CakzZ*'H@$ <4ʁiCph+ \ \ɁTH$7ku'<eaE() L>C4d, 24_j@0UK pc'Hh5c+4Ǝ?p < W R?hJ5oS) WGt#B>pe`!3P:f0I-sE, RG 4 L.PDK@i3Q />hzC- bhHP\?uHi Ry?gh !hQ%=> )IW'1bHj\A 0)8"X0i b ם`!J Ip4 Bp$M" 'hB(!$pLR0;| # ,-#" V\q b(x `tv8H؝ $! Iŏ!Fio!$EMm~ $>sp G4e&( *I"'&`K ewn^pE 3d)8! B#$ f D*ᩍ@S(GCɤl>D\cBv'P \Aء,l@ aDT/p>!Tb!pn* WЃWؓ"А^W~Mq440U4`MRE; *0+Q b M!5eMRJ!`q10ȃ6{*a'PQLUJm!JIp4 m*`[wNP h]GW+?p: 1P&TkyHlݡ,&M iBa`+hx10h5s4OpDL)|!-, Q@Z"BA18NEʃs&$\yub2"f0t =J@ 0J0L6P"*`R\hh0b3<H90@j&B)#T U|T*CgKcx!x1*C b !SW~TWB@@,*+cRɐxI_ C)!{#LIàG hiŽD4==>d-\A ug@Gxb~\1=miy%u8d\BfG%pLڃ2Z&D YĤ4\)Ŀ2w H ʤ4ДBTIYP'";?T!0 L1s*;K%w:2 0IAb<,_L '& ہ\!$!FL Psw?H?%D>T {h̦(͆l!D!v䴡!WH鄤"L"5!8C#"`gH5b!yhhqwu!`p>Ƞ@9![wH ŝCC( l`B‹#̣y'H FCPu |Pvٰ/ 0oY@tPk0t 50Y"{rD`((4H0wF pF 0/d}_R H^+ 0`iE 6 p 0@dv\qnR@kgp@.\1u~ݑ2'q # a / ˑbr Yw`V7 e@  @ L7'hRyh݈vov P9BF $q k 670r0? b tJ7Ԡ\x󐕣a3i`<݁t9ag@B ny')# Q`,@hA 6`sZ` Q  u\1AP -9h 7dy @1{TЀ1 B PH !&1-`?  ݁ # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=portaudio_test - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "portaudio_test.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "portaudio_test.mak" CFG="portaudio_test - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "portaudio_test - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "portaudio_test - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "portaudio_test - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "../portaudio/pa_common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "portaudio_test - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../portaudio/pa_common" /D "_CONSOLE" /D "_MBCS" /D "PA_NO_ASIO" /D "PA_NO_DS" /D "WIN32" /D "_DEBUG" /D "DEBUG_INPUT" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "portaudio_test - Win32 Release" # Name "portaudio_test - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\portaudio\pa_common\pa_allocation.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_converters.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_cpuload.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_dither.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_front.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_process.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_skeleton.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_stream.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_win\pa_win_hostapis.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_win\pa_win_util.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_win_wmme\pa_win_wmme.c # End Source File # Begin Source File SOURCE=..\portaudio\pa_tests\patest_read_record.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\portaudio\pa_common\pa_allocation.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_converters.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_cpuload.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_dither.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_process.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_stream.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\pa_util.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_win_wmme\pa_win_wmme.h # End Source File # Begin Source File SOURCE=..\portaudio\pa_common\portaudio.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nyquist-3.05/portaudio_test/syncwrite.c0000644000175000000620000001104210144436365017427 0ustar stevestaff/** @file syncwrite.c @brief Play a sine wave for several seconds with synchronous writes. @author Ross Bencina @author Phil Burk @author Roger B. Dannenberg */ /* * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (5) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (64) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; } paTestData; /*******************************************************************/ int main(void); int main(void) { PaStreamParameters outputParameters; PaStream *stream; PaError err; paTestData data; int i, count; float samples[FRAMES_PER_BUFFER * 2]; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; idefaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; err = Pa_OpenStream( &stream, NULL, /* no input */ &outputParameters, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, /* we won't output out of range samples so don't bother clipping them */ NULL, /* no callback */ &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Play for %d seconds.\n", NUM_SECONDS ); for (count = 0; count < SAMPLE_RATE * NUM_SECONDS / FRAMES_PER_BUFFER; count++) { float *out = samples; for (i = 0; i < FRAMES_PER_BUFFER; i++) { *out++ = data.sine[data.left_phase]; *out++ = data.sine[data.right_phase]; /* right */ data.left_phase += 1; if( data.left_phase >= TABLE_SIZE ) data.left_phase -= TABLE_SIZE; data.right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data.right_phase >= TABLE_SIZE ) data.right_phase -= TABLE_SIZE; } Pa_WriteStream( stream, samples, FRAMES_PER_BUFFER); } err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } nyquist-3.05/xlisp/0002755000175000000620000000000011537433122013325 5ustar stevestaffnyquist-3.05/xlisp/extern.h0000644000175000000620000000034011524127024014773 0ustar stevestaff xtype_desc create_desc(char *type_name, void (*fm)(void*), void (*pm)(void*, void*), void (*sm)(FILE*, void*), unsigned char * (*rm)(FILE*), void (*mm)(void*)); int exttypep(LVAL x, LVAL type_sym); nyquist-3.05/xlisp/xlftab.c0000644000175000000620000004713411466723256014773 0ustar stevestaff/* xlftab.c - xlisp function table */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use HISTORY 23-Apr-03 Mazzoni Eliminated some compiler warnings 1-Apr-88 Dale Amon at CSD Added include file hook for local language extensions: localdefs.h and localptrs.h */ #include "switches.h" #include "xlisp.h" #ifndef NO_PROTOTYPES_IN_XLISP_H /* external functions */ extern LVAL xbisubr(void),xbifsubr(void), rmhash(void),rmquote(void),rmdquote(void),rmbquote(void),rmcomma(void), clnew(void),clisnew(void),clanswer(void), obisnew(void),obclass(void),obshow(void),obisa(void), rmlpar(void),rmrpar(void),rmsemi(void), xeval(void),xapply(void),xfuncall(void),xquote(void),xfunction(void),xbquote(void), xlambda(void),xset(void),xsetq(void),xsetf(void),xdefun(void),xdefmacro(void), xgensym(void),xmakesymbol(void),xintern(void), xsymname(void),xsymvalue(void),xsymplist(void), xget(void),xputprop(void),xremprop(void), xhash(void),xmkarray(void),xaref(void), xcar(void),xcdr(void), xcaar(void),xcadr(void),xcdar(void),xcddr(void), xcaaar(void),xcaadr(void),xcadar(void),xcaddr(void), xcdaar(void),xcdadr(void),xcddar(void),xcdddr(void), xcaaaar(void),xcaaadr(void),xcaadar(void),xcaaddr(void), xcadaar(void),xcadadr(void),xcaddar(void),xcadddr(void), xcdaaar(void),xcdaadr(void),xcdadar(void),xcdaddr(void), xcddaar(void),xcddadr(void),xcdddar(void),xcddddr(void), xcons(void),xlist(void),xappend(void),xreverse(void),xlast(void),xnth(void),xnthcdr(void), xmember(void),xassoc(void),xsubst(void),xsublis(void),xlength(void),xsort(void), xremove(void),xremif(void),xremifnot(void), xmapc(void),xmapcar(void),xmapl(void),xmaplist(void), xrplca(void),xrplcd(void),xnconc(void), xdelete(void),xdelif(void),xdelifnot(void), xatom(void),xsymbolp(void),xnumberp(void),xboundp(void),xnull(void),xlistp(void),xendp(void),xconsp(void), xeq(void),xeql(void),xequal(void), xcond(void),xcase(void),xand(void),x_or(void),xlet(void),xletstar(void),xif(void), xprog(void),xprogstar(void),xprog1(void),xprog2(void),xprogn(void),xgo(void),xreturn(void), xcatch(void),xthrow(void), xerror(void),xcerror(void),xbreak(void), xcleanup(void),xtoplevel(void),xcontinue(void),xerrset(void), xbaktrace(void),xevalhook(void), xdo(void),xdostar(void),xdolist(void),xdotimes(void), xminusp(void),xzerop(void),xplusp(void),xevenp(void),xoddp(void), xfix(void),xfloat(void), xgcd(void),xadd(void),xsub(void),xmul(void),xdiv(void),xrem(void),xmin(void),xmax(void),xabs(void), xadd1(void),xsub1(void),xlogand(void),xlogior(void),xlogxor(void),xlognot(void), xsin(void),xcos(void),xtan(void),xatan(void),xexpt(void),xexp(void),xsqrt(void),xrand(void), xrealrand(void), xlss(void),xleq(void),xequ(void),xneq(void),xgeq(void),xgtr(void), xstrcat(void),xsubseq(void),xstring(void),xchar(void), xread(void),xprint(void),xprin1(void),xprinc(void),xterpri(void), xflatsize(void),xflatc(void), xopen(void),xbopen(void),xclose(void),xrdchar(void),xpkchar(void),xwrchar(void),xreadline(void), xrdint(void),xwrint(void),xrdfloat(void),xwrfloat(void), xget_env(void), xload(void),xtranscript(void), xtype(void),xquit(void),xexit(void),xpeek(void),xpoke(void),xaddrs(void), xvector(void),xblock(void),xrtnfrom(void),xtagbody(void), xpsetq(void),xflet(void),xlabels(void),xmacrolet(void),xunwindprotect(void),xpp(void), xstrlss(void),xstrleq(void),xstreql(void),xstrneq(void),xstrgeq(void),xstrgtr(void), xstrilss(void),xstrileq(void),xstrieql(void),xstrineq(void),xstrigeq(void),xstrigtr(void), xupcase(void),xdowncase(void),xnupcase(void),xndowncase(void), xtrim(void),xlefttrim(void),xrighttrim(void), xuppercasep(void),xlowercasep(void),xbothcasep(void),xdigitp(void),xalphanumericp(void), xcharcode(void),xcodechar(void),xchupcase(void),xchdowncase(void),xdigitchar(void), xchrlss(void),xchrleq(void),xchreql(void),xchrneq(void),xchrgeq(void),xchrgtr(void), xchrilss(void),xchrileq(void),xchrieql(void),xchrineq(void),xchrigeq(void),xchrigtr(void), xintegerp(void),xfloatp(void),xstringp(void),xarrayp(void),xstreamp(void),xobjectp(void), xwhen(void),xunless(void),xloop(void), xsymfunction(void),xfboundp(void),xsend(void),xsendsuper(void), xprogv(void),xrdbyte(void),xwrbyte(void),xformat(void), xcharp(void),xcharint(void),xintchar(void), xmkstrinput(void),xmkstroutput(void),xgetstroutput(void),xgetlstoutput(void), xgetlambda(void),xmacroexpand(void),x1macroexpand(void), xinfo(void), //Added by Ning Hu Apr.2001 xsetdir(void), //Added by Ning Hu May.2001 xbigendianp(void), xtrace(void),xuntrace(void),xprofile(void),xstrsearch(void), xsetupconsole(void), xechoenabled(void),xslider_read(void), xget_user(void), // added by RBD, Jul 2007 xfind_in_xlisp_path(void); // added by RBD, Jan 2008 #endif /* functions specific to xldmem.c */ LVAL xgc(void),xexpand(void),xalloc(void),xmem(void); #ifdef SAVERESTORE LVAL xsave(void),xrestore(void); #endif /* include system dependant definitions */ #include "osdefs.h" #include "localdefs.h" /* SUBR/FSUBR indicator */ #define S SUBR #define F FSUBR /* forward declarations */ LOCAL LVAL xnotimp(void); /* debugging functions */ #ifdef DEBUG_INPUT LVAL xstartrecordio(void); LVAL xstoprecordio(void); #endif /* the function table */ FUNDEF funtab[] = { /* read macro functions */ { NULL, S, rmhash }, /* 0 */ { NULL, S, rmquote }, /* 1 */ { NULL, S, rmdquote }, /* 2 */ { NULL, S, rmbquote }, /* 3 */ { NULL, S, rmcomma }, /* 4 */ { NULL, S, rmlpar }, /* 5 */ { NULL, S, rmrpar }, /* 6 */ { NULL, S, rmsemi }, /* 7 */ { NULL, S, xnotimp }, /* 8 */ { NULL, S, xnotimp }, /* 9 */ /* methods */ { NULL, S, clnew }, /* 10 */ { NULL, S, clisnew }, /* 11 */ { NULL, S, clanswer }, /* 12 */ { NULL, S, obisnew }, /* 13 */ { NULL, S, obclass }, /* 14 */ { NULL, S, obshow }, /* 15 */ { NULL, S, obisa }, /* 16 */ { NULL, S, xnotimp }, /* 17 */ { NULL, S, xnotimp }, /* 18 */ { NULL, S, xnotimp }, /* 19 */ /* evaluator functions */ { "EVAL", S, xeval }, /* 20 */ { "APPLY", S, xapply }, /* 21 */ { "FUNCALL", S, xfuncall }, /* 22 */ { "QUOTE", F, xquote }, /* 23 */ { "FUNCTION", F, xfunction }, /* 24 */ { "BACKQUOTE", F, xbquote }, /* 25 */ { "LAMBDA", F, xlambda }, /* 26 */ /* symbol functions */ { "SET", S, xset }, /* 27 */ { "SETQ", F, xsetq }, /* 28 */ { "SETF", F, xsetf }, /* 29 */ { "DEFUN", F, xdefun }, /* 30 */ { "DEFMACRO", F, xdefmacro }, /* 31 */ { "GENSYM", S, xgensym }, /* 32 */ { "MAKE-SYMBOL", S, xmakesymbol }, /* 33 */ { "INTERN", S, xintern }, /* 34 */ { "SYMBOL-NAME", S, xsymname }, /* 35 */ { "SYMBOL-VALUE", S, xsymvalue }, /* 36 */ { "SYMBOL-PLIST", S, xsymplist }, /* 37 */ { "GET", S, xget }, /* 38 */ { "PUTPROP", S, xputprop }, /* 39 */ { "REMPROP", S, xremprop }, /* 40 */ { "HASH", S, xhash }, /* 41 */ /* array functions */ { "MAKE-ARRAY", S, xmkarray }, /* 42 */ { "AREF", S, xaref }, /* 43 */ /* list functions */ { "CAR", S, xcar }, /* 44 */ { "CDR", S, xcdr }, /* 45 */ { "CAAR", S, xcaar }, /* 46 */ { "CADR", S, xcadr }, /* 47 */ { "CDAR", S, xcdar }, /* 48 */ { "CDDR", S, xcddr }, /* 49 */ { "CAAAR", S, xcaaar }, /* 50 */ { "CAADR", S, xcaadr }, /* 51 */ { "CADAR", S, xcadar }, /* 52 */ { "CADDR", S, xcaddr }, /* 53 */ { "CDAAR", S, xcdaar }, /* 54 */ { "CDADR", S, xcdadr }, /* 55 */ { "CDDAR", S, xcddar }, /* 56 */ { "CDDDR", S, xcdddr }, /* 57 */ { "CAAAAR", S, xcaaaar }, /* 58 */ { "CAAADR", S, xcaaadr }, /* 59 */ { "CAADAR", S, xcaadar }, /* 60 */ { "CAADDR", S, xcaaddr }, /* 61 */ { "CADAAR", S, xcadaar }, /* 62 */ { "CADADR", S, xcadadr }, /* 63 */ { "CADDAR", S, xcaddar }, /* 64 */ { "CADDDR", S, xcadddr }, /* 65 */ { "CDAAAR", S, xcdaaar }, /* 66 */ { "CDAADR", S, xcdaadr }, /* 67 */ { "CDADAR", S, xcdadar }, /* 68 */ { "CDADDR", S, xcdaddr }, /* 69 */ { "CDDAAR", S, xcddaar }, /* 70 */ { "CDDADR", S, xcddadr }, /* 71 */ { "CDDDAR", S, xcdddar }, /* 72 */ { "CDDDDR", S, xcddddr }, /* 73 */ { "CONS", S, xcons }, /* 74 */ { "LIST", S, xlist }, /* 75 */ { "APPEND", S, xappend }, /* 76 */ { "REVERSE", S, xreverse }, /* 77 */ { "LAST", S, xlast }, /* 78 */ { "NTH", S, xnth }, /* 79 */ { "NTHCDR", S, xnthcdr }, /* 80 */ { "MEMBER", S, xmember }, /* 81 */ { "ASSOC", S, xassoc }, /* 82 */ { "SUBST", S, xsubst }, /* 83 */ { "SUBLIS", S, xsublis }, /* 84 */ { "REMOVE", S, xremove }, /* 85 */ { "LENGTH", S, xlength }, /* 86 */ { "MAPC", S, xmapc }, /* 87 */ { "MAPCAR", S, xmapcar }, /* 88 */ { "MAPL", S, xmapl }, /* 89 */ { "MAPLIST", S, xmaplist }, /* 90 */ /* destructive list functions */ { "RPLACA", S, xrplca }, /* 91 */ { "RPLACD", S, xrplcd }, /* 92 */ { "NCONC", S, xnconc }, /* 93 */ { "DELETE", S, xdelete }, /* 94 */ /* predicate functions */ { "ATOM", S, xatom }, /* 95 */ { "SYMBOLP", S, xsymbolp }, /* 96 */ { "NUMBERP", S, xnumberp }, /* 97 */ { "BOUNDP", S, xboundp }, /* 98 */ { "NULL", S, xnull }, /* 99 */ { "LISTP", S, xlistp }, /* 100 */ { "CONSP", S, xconsp }, /* 101 */ { "MINUSP", S, xminusp }, /* 102 */ { "ZEROP", S, xzerop }, /* 103 */ { "PLUSP", S, xplusp }, /* 104 */ { "EVENP", S, xevenp }, /* 105 */ { "ODDP", S, xoddp }, /* 106 */ { "EQ", S, xeq }, /* 107 */ { "EQL", S, xeql }, /* 108 */ { "EQUAL", S, xequal }, /* 109 */ /* special forms */ { "COND", F, xcond }, /* 110 */ { "CASE", F, xcase }, /* 111 */ { "AND", F, xand }, /* 112 */ { "OR", F, x_or }, /* 113 */ { "LET", F, xlet }, /* 114 */ { "LET*", F, xletstar }, /* 115 */ { "IF", F, xif }, /* 116 */ { "PROG", F, xprog }, /* 117 */ { "PROG*", F, xprogstar }, /* 118 */ { "PROG1", F, xprog1 }, /* 119 */ { "PROG2", F, xprog2 }, /* 120 */ { "PROGN", F, xprogn }, /* 121 */ { "GO", F, xgo }, /* 122 */ { "RETURN", F, xreturn }, /* 123 */ { "DO", F, xdo }, /* 124 */ { "DO*", F, xdostar }, /* 125 */ { "DOLIST", F, xdolist }, /* 126 */ { "DOTIMES", F, xdotimes }, /* 127 */ { "CATCH", F, xcatch }, /* 128 */ { "THROW", F, xthrow }, /* 129 */ /* debugging and error handling functions */ { "ERROR", S, xerror }, /* 130 */ { "CERROR", S, xcerror }, /* 131 */ { "BREAK", S, xbreak }, /* 132 */ { "CLEAN-UP", S, xcleanup }, /* 133 */ { "TOP-LEVEL", S, xtoplevel }, /* 134 */ { "CONTINUE", S, xcontinue }, /* 135 */ { "ERRSET", F, xerrset }, /* 136 */ { "BAKTRACE", S, xbaktrace }, /* 137 */ { "EVALHOOK", S, xevalhook }, /* 138 */ /* arithmetic functions */ { "TRUNCATE", S, xfix }, /* 139 */ { "FLOAT", S, xfloat }, /* 140 */ { "+", S, xadd }, /* 141 */ { "-", S, xsub }, /* 142 */ { "*", S, xmul }, /* 143 */ { "/", S, xdiv }, /* 144 */ { "1+", S, xadd1 }, /* 145 */ { "1-", S, xsub1 }, /* 146 */ { "REM", S, xrem }, /* 147 */ { "MIN", S, xmin }, /* 148 */ { "MAX", S, xmax }, /* 149 */ { "ABS", S, xabs }, /* 150 */ { "SIN", S, xsin }, /* 151 */ { "COS", S, xcos }, /* 152 */ { "TAN", S, xtan }, /* 153 */ { "EXPT", S, xexpt }, /* 154 */ { "EXP", S, xexp }, /* 155 */ { "SQRT", S, xsqrt }, /* 156 */ { "RANDOM", S, xrand }, /* 157 */ /* bitwise logical functions */ { "LOGAND", S, xlogand }, /* 158 */ { "LOGIOR", S, xlogior }, /* 159 */ { "LOGXOR", S, xlogxor }, /* 160 */ { "LOGNOT", S, xlognot }, /* 161 */ /* numeric comparison functions */ { "<", S, xlss }, /* 162 */ { "<=", S, xleq }, /* 163 */ { "=", S, xequ }, /* 164 */ { "/=", S, xneq }, /* 165 */ { ">=", S, xgeq }, /* 166 */ { ">", S, xgtr }, /* 167 */ /* string functions */ { "STRCAT", S, xstrcat }, /* 168 */ { "SUBSEQ", S, xsubseq }, /* 169 */ { "STRING", S, xstring }, /* 170 */ { "CHAR", S, xchar }, /* 171 */ /* I/O functions */ { "READ", S, xread }, /* 172 */ { "PRINT", S, xprint }, /* 173 */ { "PRIN1", S, xprin1 }, /* 174 */ { "PRINC", S, xprinc }, /* 175 */ { "TERPRI", S, xterpri }, /* 176 */ { "FLATSIZE", S, xflatsize }, /* 177 */ { "FLATC", S, xflatc }, /* 178 */ /* file I/O functions */ { "OPEN", S, xopen }, /* 179 */ { "FORMAT", S, xformat }, /* 180 */ { "CLOSE", S, xclose }, /* 181 */ { "READ-CHAR", S, xrdchar }, /* 182 */ { "PEEK-CHAR", S, xpkchar }, /* 183 */ { "WRITE-CHAR", S, xwrchar }, /* 184 */ { "READ-LINE", S, xreadline }, /* 185 */ /* system functions */ { "LOAD", S, xload }, /* 186 */ { "DRIBBLE", S, xtranscript }, /* 187 */ /* functions specific to xldmem.c */ { "GC", S, xgc }, /* 188 */ { "EXPAND", S, xexpand }, /* 189 */ { "ALLOC", S, xalloc }, /* 190 */ { "ROOM", S, xmem }, /* 191 */ #ifdef SAVERESTORE { "SAVE", S, xsave }, /* 192 */ { "RESTORE", S, xrestore }, /* 193 */ #else { NULL, S, xnotimp }, /* 192 */ { NULL, S, xnotimp }, /* 193 */ #endif /* end of functions specific to xldmem.c */ { "TYPE-OF", S, xtype }, /* 194 */ { "EXIT", S, xexit }, /* 195 */ #ifdef PEEK_AND_POKE { "PEEK", S, xpeek }, /* 196 */ { "POKE", S, xpoke }, /* 197 */ { "ADDRESS-OF", S, xaddrs }, /* 198 */ #else { NULL, S, xnotimp }, /* 196 */ { NULL, S, xnotimp }, /* 197 */ { NULL, S, xnotimp }, /* 198 */ #endif /* new functions and special forms */ { "VECTOR", S, xvector }, /* 199 */ { "BLOCK", F, xblock }, /* 200 */ { "RETURN-FROM", F, xrtnfrom }, /* 201 */ { "TAGBODY", F, xtagbody }, /* 202 */ { "PSETQ", F, xpsetq }, /* 203 */ { "FLET", F, xflet }, /* 204 */ { "LABELS", F, xlabels }, /* 205 */ { "MACROLET", F, xmacrolet }, /* 206 */ { "UNWIND-PROTECT", F, xunwindprotect }, /* 207 */ { "PPRINT", S, xpp }, /* 208 */ { "STRING<", S, xstrlss }, /* 209 */ { "STRING<=", S, xstrleq }, /* 210 */ { "STRING=", S, xstreql }, /* 211 */ { "STRING/=", S, xstrneq }, /* 212 */ { "STRING>=", S, xstrgeq }, /* 213 */ { "STRING>", S, xstrgtr }, /* 214 */ { "STRING-LESSP", S, xstrilss }, /* 215 */ { "STRING-NOT-GREATERP", S, xstrileq }, /* 216 */ { "STRING-EQUAL", S, xstrieql }, /* 217 */ { "STRING-NOT-EQUAL", S, xstrineq }, /* 218 */ { "STRING-NOT-LESSP", S, xstrigeq }, /* 219 */ { "STRING-GREATERP", S, xstrigtr }, /* 220 */ { "INTEGERP", S, xintegerp }, /* 221 */ { "FLOATP", S, xfloatp }, /* 222 */ { "STRINGP", S, xstringp }, /* 223 */ { "ARRAYP", S, xarrayp }, /* 224 */ { "STREAMP", S, xstreamp }, /* 225 */ { "OBJECTP", S, xobjectp }, /* 226 */ { "STRING-UPCASE", S, xupcase }, /* 227 */ { "STRING-DOWNCASE", S, xdowncase }, /* 228 */ { "NSTRING-UPCASE", S, xnupcase }, /* 229 */ { "NSTRING-DOWNCASE", S, xndowncase }, /* 230 */ { "STRING-TRIM", S, xtrim }, /* 231 */ { "STRING-LEFT-TRIM", S, xlefttrim }, /* 232 */ { "STRING-RIGHT-TRIM", S, xrighttrim }, /* 233 */ { "WHEN", F, xwhen }, /* 234 */ { "UNLESS", F, xunless }, /* 235 */ { "LOOP", F, xloop }, /* 236 */ { "SYMBOL-FUNCTION", S, xsymfunction }, /* 237 */ { "FBOUNDP", S, xfboundp }, /* 238 */ { "SEND", S, xsend }, /* 239 */ { "SEND-SUPER", S, xsendsuper }, /* 240 */ { "PROGV", F, xprogv }, /* 241 */ { "CHARACTERP", S, xcharp }, /* 242 */ { "CHAR-INT", S, xcharint }, /* 243 */ { "INT-CHAR", S, xintchar }, /* 244 */ { "READ-BYTE", S, xrdbyte }, /* 245 */ { "WRITE-BYTE", S, xwrbyte }, /* 246 */ { "MAKE-STRING-INPUT-STREAM", S, xmkstrinput }, /* 247 */ { "MAKE-STRING-OUTPUT-STREAM", S, xmkstroutput }, /* 248 */ { "GET-OUTPUT-STREAM-STRING", S, xgetstroutput }, /* 249 */ { "GET-OUTPUT-STREAM-LIST", S, xgetlstoutput }, /* 250 */ { "GCD", S, xgcd }, /* 251 */ { "GET-LAMBDA-EXPRESSION", S, xgetlambda }, /* 252 */ { "MACROEXPAND", S, xmacroexpand }, /* 253 */ { "MACROEXPAND-1", S, x1macroexpand }, /* 254 */ { "CHAR<", S, xchrlss }, /* 255 */ { "CHAR<=", S, xchrleq }, /* 256 */ { "CHAR=", S, xchreql }, /* 257 */ { "CHAR/=", S, xchrneq }, /* 258 */ { "CHAR>=", S, xchrgeq }, /* 259 */ { "CHAR>", S, xchrgtr }, /* 260 */ { "CHAR-LESSP", S, xchrilss }, /* 261 */ { "CHAR-NOT-GREATERP", S, xchrileq }, /* 262 */ { "CHAR-EQUAL", S, xchrieql }, /* 263 */ { "CHAR-NOT-EQUAL", S, xchrineq }, /* 264 */ { "CHAR-NOT-LESSP", S, xchrigeq }, /* 265 */ { "CHAR-GREATERP", S, xchrigtr }, /* 266 */ { "UPPER-CASE-P", S, xuppercasep }, /* 267 */ { "LOWER-CASE-P", S, xlowercasep }, /* 268 */ { "BOTH-CASE-P", S, xbothcasep }, /* 269 */ { "DIGIT-CHAR-P", S, xdigitp }, /* 270 */ { "ALPHANUMERICP", S, xalphanumericp }, /* 271 */ { "CHAR-UPCASE", S, xchupcase }, /* 272 */ { "CHAR-DOWNCASE", S, xchdowncase }, /* 273 */ { "DIGIT-CHAR", S, xdigitchar }, /* 274 */ { "CHAR-CODE", S, xcharcode }, /* 275 */ { "CODE-CHAR", S, xcodechar }, /* 276 */ { "ENDP", S, xendp }, /* 277 */ { "REMOVE-IF", S, xremif }, /* 278 */ { "REMOVE-IF-NOT", S, xremifnot }, /* 279 */ { "DELETE-IF", S, xdelif }, /* 280 */ { "DELETE-IF-NOT", S, xdelifnot }, /* 281 */ { "TRACE", F, xtrace }, /* 282 */ { "UNTRACE", F, xuntrace }, /* 283 */ { "SORT", S, xsort }, /* 284 */ /* extra table entries */ { "PROFILE", S, xprofile }, /* 285 */ { "STRING-SEARCH", S, xstrsearch }, /* 286 */ { "QUIT", S, xquit }, /* 287 */ { "OPEN-BINARY", S, xbopen }, /* 288 */ { "SETUP-CONSOLE", S, xsetupconsole }, /* 289 */ { "READ-INT", S, xrdint }, /* 290 */ { "READ-FLOAT", S, xrdfloat }, /* 291 */ { "WRITE-INT", S, xwrint }, /* 292 */ { "WRITE-FLOAT", S, xwrfloat }, /* 293 */ { "INFO", S, xinfo }, /* 294 */ /* Ning Hu, Apr 2001 */ { "RRANDOM", S, xrealrand }, /* 295 */ #ifdef DEBUG_INPUT { "START-RECORD-IO", S, xstartrecordio }, /* 296 */ { "STOP-RECORD-IO", S, xstoprecordio }, /* 297 */ #else { NULL, S, xnotimp }, /* 296 */ { NULL, S, xnotimp }, /* 297 */ #endif { "ATAN", S, xatan }, /* 298 */ { "BIGENDIANP", S, xbigendianp }, /* 299 */ { "SETDIR", S, xsetdir }, /* 300 */ //Added by Ning Hu May.2001 { "LISTDIR", S, xlistdir }, /* 301 */ // Added by RBD, Mar 2005 { "ECHOENABLED", S, xechoenabled }, /* 302 */ // Added by RBD, Dec 2005 { "GET-SLIDER-VALUE", S, xslider_read }, /* 303 */ { "OSC-ENABLE", S, xosc_enable }, /* 304 */ { "GET-TEMP-PATH", S, xget_temp_path }, /* 305 */ { "GET-USER", S, xget_user }, /* 306 */ { "FIND-IN-XLISP-PATH", S, xfind_in_xlisp_path }, /* 307 */ { "GET-ENV", S, xget_env }, /* 308 */ #ifdef MACINTOSH #include "macptrs.h" #endif /* include system dependant function pointers */ #include "osptrs.h" #include "localptrs.h" {0,0,0} /* end of table marker */ }; /* xnotimp does not return anything on purpose, so disable * "no return value" warning */ /* #pragma warning(disable: 4716)*/ /* xnotimp - function table entries that are currently not implemented */ LOCAL LVAL xnotimp(void) { xlfail("function not implemented"); return NIL; /* never happens */ } nyquist-3.05/xlisp/osdefs.h0000644000175000000620000000014210144436365014761 0ustar stevestaff/* osdefs.h - system specific function declarations */ extern LVAL xsystem(void),xgetkey(void); nyquist-3.05/xlisp/xlbfun.c0000644000175000000620000003234711466723256015011 0ustar stevestaff/* xlbfun.c - xlisp basic built-in functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ #include "xlisp.h" #include "string.h" /* forward declarations */ FORWARD LOCAL LVAL makesymbol(int iflag); /* xeval - the built-in function 'eval' */ LVAL xeval(void) { LVAL expr; /* get the expression to evaluate */ expr = xlgetarg(); xllastarg(); /* evaluate the expression */ return (xleval(expr)); } /* xapply - the built-in function 'apply' */ LVAL xapply(void) { LVAL fun,arglist; /* get the function and argument list */ fun = xlgetarg(); arglist = xlgalist(); xllastarg(); /* apply the function to the arguments */ return (xlapply(pushargs(fun,arglist))); } /* xfuncall - the built-in function 'funcall' */ LVAL xfuncall(void) { LVAL *newfp; int argc; /* build a new argument stack frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(xlgetarg()); pusharg(NIL); /* will be argc */ /* push each argument */ for (argc = 0; moreargs(); ++argc) pusharg(nextarg()); /* establish the new stack frame */ newfp[2] = cvfixnum((FIXTYPE)argc); xlfp = newfp; /* apply the function to the arguments */ return (xlapply(argc)); } /* xmacroexpand - expand a macro call repeatedly */ LVAL xmacroexpand(void) { LVAL form; form = xlgetarg(); xllastarg(); return (xlexpandmacros(form)); } /* x1macroexpand - expand a macro call */ LVAL x1macroexpand(void) { LVAL form,fun,args; /* protect some pointers */ xlstkcheck(2); xlsave(fun); xlsave(args); /* get the form */ form = xlgetarg(); xllastarg(); /* expand until the form isn't a macro call */ if (consp(form)) { fun = car(form); /* get the macro name */ args = cdr(form); /* get the arguments */ if (symbolp(fun) && fboundp(fun)) { fun = xlgetfunction(fun); /* get the expansion function */ macroexpand(fun,args,&form); } } /* restore the stack and return the expansion */ xlpopn(2); return (form); } /* xatom - is this an atom? */ LVAL xatom(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (atomp(arg) ? s_true : NIL); } /* xsymbolp - is this an symbol? */ LVAL xsymbolp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (arg == NIL || symbolp(arg) ? s_true : NIL); } /* xnumberp - is this a number? */ LVAL xnumberp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (fixp(arg) || floatp(arg) ? s_true : NIL); } /* xintegerp - is this an integer? */ LVAL xintegerp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (fixp(arg) ? s_true : NIL); } /* xfloatp - is this a float? */ LVAL xfloatp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (floatp(arg) ? s_true : NIL); } /* xcharp - is this a character? */ LVAL xcharp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (charp(arg) ? s_true : NIL); } /* xstringp - is this a string? */ LVAL xstringp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (stringp(arg) ? s_true : NIL); } /* xarrayp - is this an array? */ LVAL xarrayp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (vectorp(arg) ? s_true : NIL); } /* xstreamp - is this a stream? */ LVAL xstreamp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (streamp(arg) || ustreamp(arg) ? s_true : NIL); } /* xobjectp - is this an object? */ LVAL xobjectp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (objectp(arg) ? s_true : NIL); } /* xboundp - is this a value bound to this symbol? */ LVAL xboundp(void) { LVAL sym; sym = xlgasymbol(); xllastarg(); return (boundp(sym) ? s_true : NIL); } /* xfboundp - is this a functional value bound to this symbol? */ LVAL xfboundp(void) { LVAL sym; sym = xlgasymbol(); xllastarg(); return (fboundp(sym) ? s_true : NIL); } /* xnull - is this null? */ LVAL xnull(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (null(arg) ? s_true : NIL); } /* xlistp - is this a list? */ LVAL xlistp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (listp(arg) ? s_true : NIL); } /* xendp - is this the end of a list? */ LVAL xendp(void) { LVAL arg; arg = xlgalist(); xllastarg(); return (null(arg) ? s_true : NIL); } /* xconsp - is this a cons? */ LVAL xconsp(void) { LVAL arg; arg = xlgetarg(); xllastarg(); return (consp(arg) ? s_true : NIL); } /* xeq - are these equal? */ LVAL xeq(void) { LVAL arg1,arg2; /* get the two arguments */ arg1 = xlgetarg(); arg2 = xlgetarg(); xllastarg(); /* compare the arguments */ return (arg1 == arg2 ? s_true : NIL); } /* xeql - are these equal? */ LVAL xeql(void) { LVAL arg1,arg2; /* get the two arguments */ arg1 = xlgetarg(); arg2 = xlgetarg(); xllastarg(); /* compare the arguments */ return (eql(arg1,arg2) ? s_true : NIL); } /* xequal - are these equal? (recursive) */ LVAL xequal(void) { LVAL arg1,arg2; /* get the two arguments */ arg1 = xlgetarg(); arg2 = xlgetarg(); xllastarg(); /* compare the arguments */ return (lval_equal(arg1,arg2) ? s_true : NIL); } /* xset - built-in function set */ LVAL xset(void) { LVAL sym,val; /* get the symbol and new value */ sym = xlgasymbol(); val = xlgetarg(); xllastarg(); /* assign the symbol the value of argument 2 and the return value */ setvalue(sym,val); /* return the result value */ return (val); } /* xgensym - generate a symbol */ LVAL xgensym(void) { char sym[STRMAX+11]; /* enough space for prefix and number */ LVAL x; /* get the prefix or number */ if (moreargs()) { x = xlgetarg(); switch (ntype(x)) { case SYMBOL: x = getpname(x); case STRING: strncpy(gsprefix, (char *) getstring(x),STRMAX); gsprefix[STRMAX] = '\0'; break; case FIXNUM: gsnumber = getfixnum(x); break; default: xlerror("bad argument type",x); } } xllastarg(); /* create the pname of the new symbol */ sprintf(sym,"%s%d",gsprefix,gsnumber++); /* make a symbol with this print name */ return (xlmakesym(sym)); } /* xmakesymbol - make a new uninterned symbol */ LVAL xmakesymbol(void) { return (makesymbol(FALSE)); } /* xintern - make a new interned symbol */ LVAL xintern(void) { return (makesymbol(TRUE)); } /* makesymbol - make a new symbol */ LOCAL LVAL makesymbol(int iflag) { LVAL pname; /* get the print name of the symbol to intern */ pname = xlgastring(); xllastarg(); /* make the symbol */ return (iflag ? xlenter((char *) getstring(pname)) : xlmakesym((char *) getstring(pname))); } /* xsymname - get the print name of a symbol */ LVAL xsymname(void) { LVAL sym; /* get the symbol */ sym = xlgasymbol(); xllastarg(); /* return the print name */ return (getpname(sym)); } /* xsymvalue - get the value of a symbol */ LVAL xsymvalue(void) { LVAL sym,val; /* get the symbol */ sym = xlgasymbol(); xllastarg(); /* get the global value */ while ((val = getvalue(sym)) == s_unbound) xlunbound(sym); /* return its value */ return (val); } /* xsymfunction - get the functional value of a symbol */ LVAL xsymfunction(void) { LVAL sym,val; /* get the symbol */ sym = xlgasymbol(); xllastarg(); /* get the global value */ while ((val = getfunction(sym)) == s_unbound) xlfunbound(sym); /* return its value */ return (val); } /* xsymplist - get the property list of a symbol */ LVAL xsymplist(void) { LVAL sym; /* get the symbol */ sym = xlgasymbol(); xllastarg(); /* return the property list */ return (getplist(sym)); } /* xget - get the value of a property */ LVAL xget(void) { LVAL sym,prp; /* get the symbol and property */ sym = xlgasymbol(); prp = xlgasymbol(); xllastarg(); /* retrieve the property value */ return (xlgetprop(sym,prp)); } /* xputprop - set the value of a property */ LVAL xputprop(void) { LVAL sym,val,prp; /* get the symbol and property */ sym = xlgasymbol(); val = xlgetarg(); prp = xlgasymbol(); xllastarg(); /* set the property value */ xlputprop(sym,val,prp); /* return the value */ return (val); } /* xremprop - remove a property value from a property list */ LVAL xremprop(void) { LVAL sym,prp; /* get the symbol and property */ sym = xlgasymbol(); prp = xlgasymbol(); xllastarg(); /* remove the property */ xlremprop(sym,prp); /* return nil */ return (NIL); } /* xhash - compute the hash value of a string or symbol */ LVAL xhash(void) { unsigned char *str; LVAL len,val; int n; /* get the string and the table length */ val = xlgetarg(); len = xlgafixnum(); n = (int)getfixnum(len); xllastarg(); /* get the string */ if (symbolp(val)) str = getstring(getpname(val)); else if (stringp(val)) str = getstring(val); else { xlerror("bad argument type",val); str = NULL; } /* return the hash index */ return (cvfixnum((FIXTYPE)hash((char *) str, n))); } /* xaref - array reference function */ LVAL xaref(void) { LVAL array,index; int i; /* get the array and the index */ array = xlgavector(); index = xlgafixnum(); i = (int)getfixnum(index); xllastarg(); /* range check the index */ if (i < 0 || i >= getsize(array)) xlerror("array index out of bounds",index); /* return the array element */ return (getelement(array,i)); } /* xmkarray - make a new array */ LVAL xmkarray(void) { LVAL size; int n; /* get the size of the array */ size = xlgafixnum() ; n = (int)getfixnum(size); xllastarg(); /* create the array */ return (newvector(n)); } /* xvector - make a vector */ LVAL xvector(void) { LVAL val; int i; /* make the vector */ val = newvector(xlargc); /* store each argument */ for (i = 0; moreargs(); ++i) setelement(val,i,nextarg()); xllastarg(); /* return the vector */ return (val); } /* allow xerror, xcleanup, xtoplevel, and xcontinue to return nothing */ /* #pragma warning(disable: 4035)*/ /* xerror - special form 'error' */ LVAL xerror(void) { LVAL emsg,arg; /* get the error message and the argument */ emsg = xlgastring(); arg = (moreargs() ? xlgetarg() : s_unbound); xllastarg(); /* signal the error */ xlerror((char *) getstring(emsg),arg); return NIL; /* won't ever happen */ } /* xcerror - special form 'cerror' */ LVAL xcerror(void) { LVAL cmsg,emsg,arg; /* get the correction message, the error message, and the argument */ cmsg = xlgastring(); emsg = xlgastring(); arg = (moreargs() ? xlgetarg() : s_unbound); xllastarg(); /* signal the error */ xlcerror((char *) getstring(cmsg), (char *) getstring(emsg),arg); /* return nil */ return (NIL); } /* xbreak - special form 'break' */ LVAL xbreak(void) { LVAL emsg,arg; /* get the error message */ emsg = (moreargs() ? xlgastring() : NIL); arg = (moreargs() ? xlgetarg() : s_unbound); xllastarg(); /* enter the break loop */ xlbreak((emsg ? (char *) getstring(emsg) : "**BREAK**"),arg); /* return nil */ return (NIL); } /* xcleanup - special form 'clean-up' */ LVAL xcleanup(void) { xllastarg(); xlcleanup(); } /* xtoplevel - special form 'top-level' */ LVAL xtoplevel(void) { xllastarg(); xltoplevel(); /* this point will never be reached because xltoplevel() does a longjmp(). The return is added to avoid false positive error messages from static analyzers and compilers */ return (NIL); } /* xcontinue - special form 'continue' */ LVAL xcontinue(void) { xllastarg(); xlcontinue(); return (NIL); } /* xevalhook - eval hook function */ LVAL xevalhook(void) { LVAL expr,newehook,newahook,newenv,oldenv,oldfenv,olddenv,val; /* protect some pointers */ xlstkcheck(3); xlsave(oldenv); xlsave(oldfenv); xlsave(newenv); /* get the expression, the new hook functions and the environment */ expr = xlgetarg(); newehook = xlgetarg(); newahook = xlgetarg(); newenv = (moreargs() ? xlgalist() : NIL); xllastarg(); /* bind *evalhook* and *applyhook* to the hook functions */ olddenv = xldenv; xldbind(s_evalhook,newehook); xldbind(s_applyhook,newahook); /* establish the environment for the hook function */ if (newenv) { oldenv = xlenv; oldfenv = xlfenv; xlenv = car(newenv); xlfenv = cdr(newenv); } /* evaluate the expression (bypassing *evalhook*) */ val = xlxeval(expr); /* restore the old environment */ xlunbind(olddenv); if (newenv) { xlenv = oldenv; xlfenv = oldfenv; } /* restore the stack */ xlpopn(3); /* return the result */ return (val); } nyquist-3.05/xlisp/xlglob.c0000644000175000000620000000611610144436365014767 0ustar stevestaff/* xlglobals - xlisp global variables */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use * 3-Apr-88 Dale Amon at CMU-CSD * Added a_extern to xlisp 2.0 * * 18-Oct-87 Dale Amon at CMU-CSD * Added global pointer a_extern for node defining new EXTERN * node type. * * 12 Oct 90 RBD Added s_profile, profile_fixnum */ #include "xlisp.h" /* symbols */ LVAL s_true=NIL,obarray=NIL; LVAL s_unbound=NIL,s_dot=NIL; LVAL s_quote=NIL,s_function=NIL; LVAL s_bquote=NIL,s_comma=NIL,s_comat=NIL; LVAL s_evalhook=NIL,s_applyhook=NIL,s_tracelist; LVAL s_lambda=NIL,s_macro=NIL; LVAL s_stdin=NIL,s_stdout=NIL,s_stderr=NIL,s_debugio=NIL,s_traceout=NIL; LVAL s_rtable=NIL; LVAL s_tracenable=NIL,s_tlimit=NIL,s_breakenable=NIL; LVAL s_loadingfiles=NIL; LVAL s_profile = NIL, profile_fixnum = NIL; LVAL s_setf=NIL,s_car=NIL,s_cdr=NIL,s_nth=NIL,s_aref=NIL,s_get=NIL; LVAL s_svalue=NIL,s_sfunction=NIL,s_splist=NIL; LVAL s_eql=NIL,s_gcflag=NIL,s_gchook=NIL; LVAL s_ifmt=NIL,s_ffmt=NIL; LVAL s_1plus=NIL,s_2plus=NIL,s_3plus=NIL; LVAL s_1star=NIL,s_2star=NIL,s_3star=NIL; LVAL s_minus=NIL,s_printcase=NIL; LVAL s_search_path=NIL; /* keywords */ LVAL k_test=NIL,k_tnot=NIL; LVAL k_wspace=NIL,k_const=NIL,k_nmacro=NIL,k_tmacro=NIL; LVAL k_sescape=NIL,k_mescape=NIL; LVAL k_direction=NIL,k_input=NIL,k_output=NIL; LVAL k_start=NIL,k_end=NIL,k_1start=NIL,k_1end=NIL; LVAL k_2start=NIL,k_2end=NIL,k_count=NIL,k_key=NIL; LVAL k_verbose=NIL,k_print=NIL; LVAL k_upcase=NIL,k_downcase=NIL; /* lambda list keywords */ LVAL lk_optional=NIL,lk_rest=NIL,lk_key=NIL,lk_aux=NIL; LVAL lk_allow_other_keys=NIL; /* type names */ LVAL a_subr=NIL,a_fsubr=NIL; LVAL a_cons=NIL,a_symbol=NIL,a_fixnum=NIL,a_flonum=NIL; LVAL a_string=NIL,a_object=NIL,a_stream=NIL,a_vector=NIL; LVAL a_extern = NIL; LVAL a_closure=NIL,a_char=NIL,a_ustream=NIL; /* evaluation variables */ LVAL **xlstack = NULL,**xlstkbase = NULL,**xlstktop = NULL; LVAL xlenv=NIL,xlfenv=NIL,xldenv=NIL; /* argument stack */ LVAL *xlargstkbase = NULL; /* argument stack base */ LVAL *xlargstktop = NULL; /* argument stack top */ LVAL *xlfp = NULL; /* argument frame pointer */ LVAL *xlsp = NULL; /* argument stack pointer */ LVAL *xlargv = NULL; /* current argument vector */ int xlargc = 0; /* current argument count */ /* exception handling variables */ XLCONTEXT *xlcontext = NULL; /* current exception handler */ XLCONTEXT *xltarget = NULL; /* target context (for xljump) */ LVAL xlvalue=NIL; /* exception value (for xljump) */ int xlmask=0; /* exception type (for xljump) */ /* debugging variables */ int xldebug = 0; /* debug level */ int xlsample = 0; /* control character sample rate */ int xltrcindent = 0; /* trace indent level */ /* gensym variables */ char gsprefix[STRMAX+1] = { 'G',0 }; /* gensym prefix string */ int gsnumber = 1; /* gensym number */ /* i/o variables */ int xlfsize = 0; /* flat size of current print call */ FILE *tfp = NULL; /* transcript file pointer */ /* general purpose string buffer */ char buf[STRMAX+1] = { 0 }; int xlatomcount = 0; /* how many atoms are there? */ nyquist-3.05/xlisp/xlprin.c0000644000175000000620000002204111466723256015015 0ustar stevestaff/* xlprint - xlisp print routine */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use * HISTORY * 28-Apr-03 Mazzoni * Eliminated some compiler warnings * * 3-Apr-88 Dale Amon at CMU-CSD * Added extern support to xlisp 2.0 * * 18-Oct-87 Dale Amon at CMU-CSD * Added print support for EXTERN nodes */ #include "string.h" #include "xlisp.h" /* external variables */ extern LVAL s_printcase,k_downcase,k_const,k_nmacro; extern LVAL s_ifmt,s_ffmt; extern FUNDEF funtab[]; extern char buf[]; LOCAL void putsymbol(LVAL fptr, char *str, int escflag); LOCAL void putsubr(LVAL fptr, char *tag, LVAL val); LOCAL void putfixnum(LVAL fptr, FIXTYPE n); LOCAL void putflonum(LVAL fptr, FLOTYPE n); LOCAL void putchcode(LVAL fptr, int ch, int escflag); LOCAL void putstring(LVAL fptr, LVAL str); LOCAL void putqstring(LVAL fptr, LVAL str); LOCAL void putclosure(LVAL fptr, LVAL val); LOCAL void putoct(LVAL fptr, int n); /* xlprint - print an xlisp value */ void xlprint(LVAL fptr, LVAL vptr, int flag) { LVAL nptr,next; int n,i; /* print nil */ if (vptr == NIL) { putsymbol(fptr,"NIL",flag); return; } /* check value type */ switch (ntype(vptr)) { case SUBR: putsubr(fptr,"Subr",vptr); break; case FSUBR: putsubr(fptr,"FSubr",vptr); break; case CONS: xlputc(fptr,'('); for (nptr = vptr; nptr != NIL; nptr = next) { xlprint(fptr,car(nptr),flag); if ((next = cdr(nptr))) { if (consp(next)) xlputc(fptr,' '); else { xlputstr(fptr," . "); xlprint(fptr,next,flag); break; } } } xlputc(fptr,')'); break; case SYMBOL: putsymbol(fptr,(char *) getstring(getpname(vptr)),flag); break; case FIXNUM: putfixnum(fptr,getfixnum(vptr)); break; case FLONUM: putflonum(fptr,getflonum(vptr)); break; case CHAR: putchcode(fptr,getchcode(vptr),flag); break; case STRING: if (flag) putqstring(fptr,vptr); else putstring(fptr,vptr); break; case STREAM: putatm(fptr,"File-Stream",vptr); break; case USTREAM: putatm(fptr,"Unnamed-Stream",vptr); break; case OBJECT: putatm(fptr,"Object",vptr); break; case VECTOR: xlputc(fptr,'#'); xlputc(fptr,'('); for (i = 0, n = getsize(vptr); n-- > 0; ) { xlprint(fptr,getelement(vptr,i++),flag); if (n) xlputc(fptr,' '); } xlputc(fptr,')'); break; case CLOSURE: putclosure(fptr,vptr); break; case EXTERN: if (getdesc(vptr)) { (*(getdesc(vptr)->print_meth))(fptr, getinst(vptr)); } break; case FREE_NODE: putatm(fptr,"Free",vptr); break; default: putatm(fptr,"Foo",vptr); break; } } /* xlterpri - terminate the current print line */ void xlterpri(LVAL fptr) { xlputc(fptr,'\n'); } /* xlputstr - output a string */ void xlputstr(LVAL fptr, char *str) { while (*str) xlputc(fptr,*str++); } /* putsymbol - output a symbol */ LOCAL void putsymbol(LVAL fptr, char *str, int escflag) { int downcase; LVAL type; char *p; /* check for printing without escapes */ if (!escflag) { xlputstr(fptr,str); return; } /* check to see if symbol needs escape characters */ if (tentry(*str) == k_const) { for (p = str; *p; ++p) if (islower(*p) || ((type = tentry(*p)) != k_const && (!consp(type) || car(type) != k_nmacro))) { xlputc(fptr,'|'); while (*str) { if (*str == '\\' || *str == '|') xlputc(fptr,'\\'); xlputc(fptr,*str++); } xlputc(fptr,'|'); return; } } /* get the case translation flag */ downcase = (getvalue(s_printcase) == k_downcase); /* check for the first character being '#' */ if (*str == '#' || *str == '.' || xlisnumber(str,NULL)) xlputc(fptr,'\\'); /* output each character */ while (*str) { /* don't escape colon until we add support for packages */ if (*str == '\\' || *str == '|' /* || *str == ':' */) xlputc(fptr,'\\'); xlputc(fptr,(downcase && isupper(*str) ? tolower(*str++) : *str++)); } } /* putstring - output a string */ LOCAL void putstring(LVAL fptr, LVAL str) { unsigned char *p; int ch; /* output each character */ for (p = getstring(str); (ch = *p) != '\0'; ++p) xlputc(fptr,ch); } /* putqstring - output a quoted string */ LOCAL void putqstring(LVAL fptr, LVAL str) { unsigned char *p; int ch; /* get the string pointer */ p = getstring(str); /* output the initial quote */ xlputc(fptr,'"'); /* output each character in the string */ for (p = getstring(str); (ch = *p) != '\0'; ++p) /* check for a control character */ if (ch < 040 || ch == '\\' || ch > 0176) { xlputc(fptr,'\\'); switch (ch) { case '\011': xlputc(fptr,'t'); break; case '\012': xlputc(fptr,'n'); break; case '\014': xlputc(fptr,'f'); break; case '\015': xlputc(fptr,'r'); break; case '\\': xlputc(fptr,'\\'); break; default: putoct(fptr,ch); break; } } /* output a normal character */ else xlputc(fptr,ch); /* output the terminating quote */ xlputc(fptr,'"'); } /* putatm - output an atom */ void putatm(LVAL fptr, char *tag, LVAL val) { sprintf(buf,"#<%s: #",tag); xlputstr(fptr,buf); sprintf(buf,AFMT,(long unsigned int)val); xlputstr(fptr,buf); xlputc(fptr,'>'); } /* putsubr - output a subr/fsubr */ LOCAL void putsubr(LVAL fptr, char *tag, LVAL val) { sprintf(buf,"#<%s-%s: #",tag,funtab[getoffset(val)].fd_name); xlputstr(fptr,buf); sprintf(buf,AFMT,(long unsigned int)val); xlputstr(fptr,buf); xlputc(fptr,'>'); } /* putclosure - output a closure */ LOCAL void putclosure(LVAL fptr, LVAL val) { LVAL name; if ((name = getname(val))) sprintf(buf,"#'); /* xlputstr(fptr,"\nName: "); xlprint(fptr,getname(val),TRUE); xlputstr(fptr,"\nType: "); xlprint(fptr,gettype(val),TRUE); xlputstr(fptr,"\nLambda: "); xlprint(fptr,getlambda(val),TRUE); xlputstr(fptr,"\nArgs: "); xlprint(fptr,getargs(val),TRUE); xlputstr(fptr,"\nOargs: "); xlprint(fptr,getoargs(val),TRUE); xlputstr(fptr,"\nRest: "); xlprint(fptr,getrest(val),TRUE); xlputstr(fptr,"\nKargs: "); xlprint(fptr,getkargs(val),TRUE); xlputstr(fptr,"\nAargs: "); xlprint(fptr,getaargs(val),TRUE); xlputstr(fptr,"\nBody: "); xlprint(fptr,getbody(val),TRUE); xlputstr(fptr,"\nEnv: "); xlprint(fptr,closure_getenv(val),TRUE); xlputstr(fptr,"\nFenv: "); xlprint(fptr,getfenv(val),TRUE); */ } /* putfixnum - output a fixnum */ LOCAL void putfixnum(LVAL fptr, FIXTYPE n) { unsigned char *fmt; LVAL val; fmt = ((val = getvalue(s_ifmt)) && stringp(val) ? getstring(val) : (unsigned char *)IFMT); sprintf(buf, (char *) fmt,n); xlputstr(fptr,buf); } /* putflonum - output a flonum */ LOCAL void putflonum(LVAL fptr, FLOTYPE n) { unsigned char *fmt; LVAL val; fmt = ((val = getvalue(s_ffmt)) && stringp(val) ? getstring(val) : (unsigned char *)"%g"); sprintf(buf,(char *) fmt,n); xlputstr(fptr,buf); } /* putchcode - output a character */ LOCAL void putchcode(LVAL fptr, int ch, int escflag) { if (escflag) { switch (ch) { case '\n': xlputstr(fptr,"#\\Newline"); break; case ' ': xlputstr(fptr,"#\\Space"); break; case '\t': xlputstr(fptr, "#\\Tab"); break; default: sprintf(buf,"#\\%c",ch); xlputstr(fptr,buf); break; } } else xlputc(fptr,ch); } /* putoct - output an octal byte value */ LOCAL void putoct(LVAL fptr, int n) { sprintf(buf,"%03o",n); xlputstr(fptr,buf); } nyquist-3.05/xlisp/xlread.c0000644000175000000620000006101011466723256014757 0ustar stevestaff/* xlread - xlisp expression input routine */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings * replaced system-specific code with generic calls (see path.c) */ #include "stdlib.h" #include "string.h" #include "switches.h" #include "xlisp.h" #ifdef WINDOWS #include "winfun.h" #endif #ifdef MACINTOSH #include "macstuff.h" #endif #ifdef DEBUG_INPUT extern FILE *debug_input_fp; #endif /* symbol parser modes */ #define DONE 0 #define NORMAL 1 #define ESCAPE 2 /* external variables */ extern LVAL s_stdout,s_true,s_dot; extern LVAL s_quote,s_function,s_bquote,s_comma,s_comat; extern LVAL s_rtable,k_wspace,k_const,k_nmacro,k_tmacro; extern LVAL k_sescape,k_mescape; extern char buf[]; /* external routines */ extern FILE *osaopen(); /* on the NeXT, atof is a macro in stdlib.h */ #if !defined(atof) && !defined(_WIN32) extern double atof(); #endif #ifndef __MWERKS__ #if !defined(ITYPE) && !defined(_WIN32) extern ITYPE; #endif #endif #define WSPACE "\t \f\r\n" #define CONST1 "!$%&*+-./0123456789:<=>?@[]^_{}~" #define CONST2 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" /* forward declarations */ FORWARD LVAL callmacro(LVAL fptr, int ch); FORWARD LOCAL LVAL psymbol(LVAL fptr); FORWARD LOCAL LVAL punintern(LVAL fptr); FORWARD LOCAL LVAL pnumber(LVAL fptr, int radix); FORWARD LOCAL LVAL pquote(LVAL fptr, LVAL sym); FORWARD LOCAL LVAL plist(LVAL fptr); FORWARD LOCAL LVAL pvector(LVAL fptr); FORWARD LOCAL void upcase(char *str); FORWARD LOCAL int pname(LVAL fptr,int *pescflag); FORWARD LOCAL void pcomment(LVAL fptr); FORWARD LOCAL int checkeof(LVAL fptr); FORWARD LOCAL int nextch(LVAL fptr); FORWARD LOCAL void badeof(LVAL fptr); FORWARD LOCAL int storech(char *buf, int i, int ch); #ifdef WINDOWS static char save_file_name[STRMAX+1]; /* keeps files opened by prompt */ static int sfn_valid = FALSE; #endif #ifdef DEBUG_INPUT extern FILE *read_by_xlisp; #endif /* xlload - load a file of xlisp expressions */ int xlload(char *fname, int vflag, int pflag) { char fullname[STRMAX+1]; #ifdef WINDOWS char *ptr; #endif LVAL fptr,expr; XLCONTEXT cntxt; FILE *fp; int sts; /* protect some pointers */ xlstkcheck(2); xlsave(fptr); xlsave(expr); /* space for copy + extension? */ if (strlen(fname) > STRMAX - 4) { expr = cvstring(fname); goto toolong; } strcpy(fullname,fname); #ifdef WINDOWS #ifdef WINGUI if (strcmp(fullname, "*") == 0) { if (sfn_valid) { strcpy(fullname, save_file_name); } else { strcpy(fullname, "*.*"); } } if (strcmp(fullname, "*.*") == 0) { char *name = getfilename(NULL, "lsp", "r", "Load file"); if (name) { strcpy(fullname, name); strcpy(save_file_name, name); sfn_valid = TRUE; } else { xlpopn(2); return FALSE; } } #endif /* replace "/" with "\" so that (current-path) will work */ for (ptr = fullname; *ptr; ptr++) { if (*ptr == '/') *ptr = '\\'; } #endif /* allocate a file node */ fptr = cvfile(NULL); /* open the file */ fp = osaopen(fullname, "r"); if (fp == NULL) { /* default the extension if there is room */ if (needsextension(fullname)) { char fullname_plus[STRMAX+1]; strcpy(fullname_plus, fullname); strcat(fullname_plus, ".lsp"); fp = osaopen(fullname_plus, "r"); if (fp) strcpy(fullname, fullname_plus); } } if (fp == NULL) { /* new cross-platform code by dmazzoni - new xlisp_path implementation is in path.c */ const char *newname = find_in_xlisp_path(fullname); if (newname && newname[0]) { if (strlen(newname) > STRMAX) { expr = cvstring(newname); goto toolong; } strcpy(fullname, newname); fp = osaopen(fullname, "r"); } } if (fp == NULL) { /* the file STILL wasn't found */ #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: failed to open %s\n", fullname); } #endif xlpopn(2); return (FALSE); } setfile(fptr,fp); setvalue(s_loadingfiles, cons(fptr, getvalue(s_loadingfiles))); setvalue(s_loadingfiles, cons(cvstring(fullname), getvalue(s_loadingfiles))); /* print the information line */ if (vflag) { sprintf(buf,"; loading \"%s\"\n",fullname); stdputstr(buf); } #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: begin loading %s\n", fullname); } #endif /* read, evaluate and possibly print each expression in the file */ xlbegin(&cntxt,CF_ERROR,s_true); if (setjmp(cntxt.c_jmpbuf)) sts = FALSE; #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: catch longjump, back to %s\n", fullname); } #endif else { #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: about to read from %s (%x)\n", fullname, fptr); } #endif /* a nested load that fails will cause all loading files to be closed, * so check to make sure fptr is still valid each time through the loop */ while (getfile(fptr) && xlread(fptr,&expr,FALSE)) { #ifdef DEBUG_INPUT if (debug_input_fp) { int c = getc(debug_input_fp); ungetc(c, debug_input_fp); } #endif expr = xleval(expr); #ifdef DEBUG_INPUT if (debug_input_fp) { int c = getc(debug_input_fp); ungetc(c, debug_input_fp); } #endif if (pflag) stdprint(expr); #ifdef DEBUG_INPUT if (debug_input_fp) { int c = getc(debug_input_fp); ungetc(c, debug_input_fp); } #endif #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: about to read from %s (%x)\n", fullname, fptr); } #endif } #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: xlread returned false for %s (%x)\n", fullname, fptr); } #endif /* return success only if file did not disappear out from under us */ sts = (getfile(fptr) != NULL); } xlend(&cntxt); /* close the file */ if (getfile(fptr)) { /* test added by RBD, see close_loadingfiles() */ osclose(getfile(fptr)); setfile(fptr,NULL); } if (consp(getvalue(s_loadingfiles)) && consp(cdr(getvalue(s_loadingfiles))) && car(cdr(getvalue(s_loadingfiles))) == fptr) { setvalue(s_loadingfiles, cdr(cdr(getvalue(s_loadingfiles)))); } /* restore the stack */ xlpopn(2); #ifdef DEBUG_INPUT if (read_by_xlisp) { fprintf(read_by_xlisp, ";;;;xlload: finished loading %s\n", fullname); } #endif /* return status */ return (sts); toolong: xlcerror("ignore file", "file name too long", expr); xlpopn(2); return FALSE; } /* xlread - read an xlisp expression */ int xlread(LVAL fptr, LVAL *pval, int rflag) { int sts; /* read an expression */ while ((sts = readone(fptr,pval)) == FALSE) #ifdef DEBUG_INPUT if (debug_input_fp) { int c = getc(debug_input_fp); ungetc(c, debug_input_fp); } #endif ; /* return status */ return (sts == EOF ? FALSE : TRUE); } /* readone - attempt to read a single expression */ int readone(LVAL fptr, LVAL *pval) { LVAL val,type; int ch; #ifdef DEBUG_INPUT if (debug_input_fp) { int c = getc(debug_input_fp); ungetc(c, debug_input_fp); } #endif /* get a character and check for EOF */ if ((ch = xlgetc(fptr)) == EOF) return (EOF); /* handle white space */ if ((type = tentry(ch)) == k_wspace) return (FALSE); /* handle symbol constituents */ else if (type == k_const) { xlungetc(fptr,ch); *pval = psymbol(fptr); return (TRUE); } /* handle single and multiple escapes */ else if (type == k_sescape || type == k_mescape) { xlungetc(fptr,ch); *pval = psymbol(fptr); return (TRUE); } /* handle read macros */ else if (consp(type)) { if ((val = callmacro(fptr,ch)) && consp(val)) { *pval = car(val); return (TRUE); } else return (FALSE); } /* handle illegal characters */ else { xlerror("illegal character",cvfixnum((FIXTYPE)ch)); /* this point will never be reached because xlerror() does a longjmp(). The return is added to avoid false positive error messages from static analyzers and compilers */ return (FALSE); } } /* rmhash - read macro for '#' */ LVAL rmhash(void) { LVAL fptr,mch,val; int escflag,ch; /* protect some pointers */ xlsave1(val); /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* make the return value */ val = consa(NIL); /* check the next character */ switch (ch = xlgetc(fptr)) { case '\'': rplaca(val,pquote(fptr,s_function)); break; case '(': rplaca(val,pvector(fptr)); break; case 'b': case 'B': rplaca(val,pnumber(fptr,2)); break; case 'o': case 'O': rplaca(val,pnumber(fptr,8)); break; case 'x': case 'X': rplaca(val,pnumber(fptr,16)); break; case '\\': xlungetc(fptr,ch); pname(fptr,&escflag); ch = buf[0]; if (strlen(buf) > 1) { upcase((char *) buf); if (strcmp(buf,"NEWLINE") == 0) ch = '\n'; else if (strcmp(buf,"SPACE") == 0) ch = ' '; else if (strcmp(buf,"TAB") == 0) ch = '\t'; else xlerror("unknown character name",cvstring(buf)); } rplaca(val,cvchar(ch)); break; case ':': rplaca(val,punintern(fptr)); break; case '|': pcomment(fptr); val = NIL; break; default: xlerror("illegal character after #",cvfixnum((FIXTYPE)ch)); } /* restore the stack */ xlpop(); /* return the value */ return (val); } /* rmquote - read macro for '\'' */ LVAL rmquote(void) { LVAL fptr,mch; /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* parse the quoted expression */ return (consa(pquote(fptr,s_quote))); } /* rmdquote - read macro for '"' */ LVAL rmdquote(void) { unsigned char buf[STRMAX+1],*p,*sptr; LVAL fptr,str,newstr,mch; int len,blen,ch,d2,d3; /* protect some pointers */ xlsave1(str); /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* loop looking for a closing quote */ len = blen = 0; p = buf; while ((ch = checkeof(fptr)) != '"') { /* handle escaped characters */ switch (ch) { case '\\': switch (ch = checkeof(fptr)) { case 't': ch = '\011'; break; case 'n': ch = '\012'; break; case 'f': ch = '\014'; break; case 'r': ch = '\015'; break; default: if (ch >= '0' && ch <= '7') { d2 = checkeof(fptr); d3 = checkeof(fptr); if (d2 < '0' || d2 > '7' || d3 < '0' || d3 > '7') xlfail("invalid octal digit"); ch -= '0'; d2 -= '0'; d3 -= '0'; ch = (ch << 6) | (d2 << 3) | d3; } break; } } /* check for buffer overflow */ if (blen >= STRMAX) { newstr = new_string(len + STRMAX + 1); sptr = getstring(newstr); *sptr = '\0'; if (str) strcat((char *) sptr, (char *) getstring(str)); *p = '\0'; strcat((char *) sptr, (char *) buf); p = buf; blen = 0; len += STRMAX; str = newstr; } /* store the character */ *p++ = ch; ++blen; } /* append the last substring */ if (str == NIL || blen) { newstr = new_string(len + blen + 1); sptr = getstring(newstr); *sptr = '\0'; if (str) strcat((char *) sptr, (char *) getstring(str)); *p = '\0'; strcat((char *) sptr, (char *) buf); str = newstr; } /* restore the stack */ xlpop(); /* return the new string */ return (consa(str)); } /* rmbquote - read macro for '`' */ LVAL rmbquote(void) { LVAL fptr,mch; /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* parse the quoted expression */ return (consa(pquote(fptr,s_bquote))); } /* rmcomma - read macro for ',' */ LVAL rmcomma(void) { LVAL fptr,mch,sym; int ch; /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* check the next character */ if ((ch = xlgetc(fptr)) == '@') sym = s_comat; else { xlungetc(fptr,ch); sym = s_comma; } /* make the return value */ return (consa(pquote(fptr,sym))); } /* rmlpar - read macro for '(' */ LVAL rmlpar(void) { LVAL fptr,mch; /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* make the return value */ return (consa(plist(fptr))); } /* 4035 is the "no return value" warning message */ /* rmrpar, pcomment, badeof, and upcase don't return anything */ /* #pragma warning(disable: 4035) */ /* rmrpar - read macro for ')' */ LVAL rmrpar(void) { xlfail("misplaced right paren"); return NULL; /* never used */ } /* rmsemi - read macro for ';' */ LVAL rmsemi(void) { LVAL fptr,mch; int ch; /* get the file and macro character */ fptr = xlgetfile(); mch = xlgachar(); xllastarg(); /* skip to end of line */ while ((ch = xlgetc(fptr)) != EOF && ch != '\n') ; /* return nil (nothing read) */ return (NIL); } /* pcomment - parse a comment delimited by #| and |# */ LOCAL void pcomment(LVAL fptr) { int lastch,ch,n; /* look for the matching delimiter (and handle nesting) */ for (n = 1, lastch = -1; n > 0 && (ch = xlgetc(fptr)) != EOF; ) { if (lastch == '|' && ch == '#') { --n; ch = -1; } else if (lastch == '#' && ch == '|') { ++n; ch = -1; } lastch = ch; } } /* pnumber - parse a number */ LOCAL LVAL pnumber(LVAL fptr, int radix) { int digit,ch; long num; for (num = 0L; (ch = xlgetc(fptr)) != EOF; ) { if (islower(ch)) ch = toupper(ch); if (!('0' <= ch && ch <= '9') && !('A' <= ch && ch <= 'F')) break; if ((digit = (ch <= '9' ? ch - '0' : ch - 'A' + 10)) >= radix) break; num = num * (long)radix + (long)digit; } xlungetc(fptr,ch); return (cvfixnum((FIXTYPE)num)); } /* plist - parse a list */ LOCAL LVAL plist(LVAL fptr) { LVAL val,expr,lastnptr,nptr; /* protect some pointers */ xlstkcheck(2); xlsave(val); xlsave(expr); /* keep appending nodes until a closing paren is found */ for (lastnptr = NIL; nextch(fptr) != ')'; ) /* get the next expression */ switch (readone(fptr,&expr)) { case EOF: badeof(fptr); case TRUE: /* check for a dotted tail */ if (expr == s_dot) { /* make sure there's a node */ if (lastnptr == NIL) xlfail("invalid dotted pair"); /* parse the expression after the dot */ if (!xlread(fptr,&expr,TRUE)) badeof(fptr); rplacd(lastnptr,expr); /* make sure its followed by a close paren */ if (nextch(fptr) != ')') xlfail("invalid dotted pair"); } /* otherwise, handle a normal list element */ else { nptr = consa(expr); if (lastnptr == NIL) val = nptr; else rplacd(lastnptr,nptr); lastnptr = nptr; } break; } /* skip the closing paren */ xlgetc(fptr); /* restore the stack */ xlpopn(2); /* return successfully */ return (val); } /* pvector - parse a vector */ LOCAL LVAL pvector(LVAL fptr) { LVAL list,expr,val,lastnptr,nptr; int len,ch,i; /* protect some pointers */ xlstkcheck(2); xlsave(list); xlsave(expr); /* keep appending nodes until a closing paren is found */ for (lastnptr = NIL, len = 0; (ch = nextch(fptr)) != ')'; ) { /* check for end of file */ if (ch == EOF) badeof(fptr); /* get the next expression */ switch (readone(fptr,&expr)) { case EOF: badeof(fptr); case TRUE: nptr = consa(expr); if (lastnptr == NIL) list = nptr; else rplacd(lastnptr,nptr); lastnptr = nptr; len++; break; } } /* skip the closing paren */ xlgetc(fptr); /* make a vector of the appropriate length */ val = newvector(len); /* copy the list into the vector */ for (i = 0; i < len; ++i, list = cdr(list)) setelement(val,i,car(list)); /* restore the stack */ xlpopn(2); /* return successfully */ return (val); } /* pquote - parse a quoted expression */ LOCAL LVAL pquote(LVAL fptr, LVAL sym) { LVAL val,p; /* protect some pointers */ xlsave1(val); /* allocate two nodes */ val = consa(sym); rplacd(val,consa(NIL)); /* initialize the second to point to the quoted expression */ if (!xlread(fptr,&p,TRUE)) badeof(fptr); rplaca(cdr(val),p); /* restore the stack */ xlpop(); /* return the quoted expression */ return (val); } /* psymbol - parse a symbol name */ LOCAL LVAL psymbol(LVAL fptr) { int escflag; LVAL val; pname(fptr,&escflag); return (escflag || !xlisnumber(buf,&val) ? xlenter(buf) : val); } /* punintern - parse an uninterned symbol */ LOCAL LVAL punintern(LVAL fptr) { int escflag; pname(fptr,&escflag); return (xlmakesym(buf)); } /* pname - parse a symbol/package name */ LOCAL int pname(LVAL fptr,int *pescflag) { int mode,ch=0,i; LVAL type; /* initialize */ *pescflag = FALSE; mode = NORMAL; i = 0; /* accumulate the symbol name */ while (mode != DONE) { /* handle normal mode */ while (mode == NORMAL) if ((ch = xlgetc(fptr)) == EOF) mode = DONE; else if ((type = tentry(ch)) == k_sescape) { i = storech(buf,i,checkeof(fptr)); *pescflag = TRUE; } else if (type == k_mescape) { *pescflag = TRUE; mode = ESCAPE; } else if (type == k_const || (consp(type) && car(type) == k_nmacro)) i = storech(buf,i,islower(ch) ? toupper(ch) : ch); else mode = DONE; /* handle multiple escape mode */ while (mode == ESCAPE) if ((ch = xlgetc(fptr)) == EOF) badeof(fptr); else if ((type = tentry(ch)) == k_sescape) i = storech(buf,i,checkeof(fptr)); else if (type == k_mescape) mode = NORMAL; else i = storech(buf,i,ch); } buf[i] = 0; /* check for a zero length name */ if (i == 0) xlerror("zero length name", s_unbound); /* unget the last character and return it */ xlungetc(fptr,ch); return (ch); } /* storech - store a character in the print name buffer */ LOCAL int storech(char *buf, int i, int ch) { if (i < STRMAX) buf[i++] = ch; return (i); } /* tentry - get a readtable entry */ LVAL tentry(int ch) { LVAL rtable; rtable = getvalue(s_rtable); if (!vectorp(rtable) || ch < 0 || ch >= getsize(rtable)) return (NIL); return (getelement(rtable,ch)); } /* nextch - look at the next non-blank character */ LOCAL int nextch(LVAL fptr) { int ch; /* return and save the next non-blank character */ while ((ch = xlgetc(fptr)) != EOF && isspace(ch)) ; xlungetc(fptr,ch); return (ch); } /* checkeof - get a character and check for end of file */ LOCAL int checkeof(LVAL fptr) { int ch; if ((ch = xlgetc(fptr)) == EOF) badeof(fptr); return (ch); } /* badeof - unexpected eof */ LOCAL void badeof(LVAL fptr) { xlgetc(fptr); xlfail("unexpected EOF"); } /* xlisnumber - check if this string is a number */ int xlisnumber(char *str, LVAL *pval) { int dl,dr; char *p; /* initialize */ p = str; dl = dr = 0; /* check for a sign */ if (*p == '+' || *p == '-') p++; /* check for a string of digits */ while (isdigit(*p)) p++, dl++; /* check for a decimal point */ if (*p == '.') { p++; while (isdigit(*p)) p++, dr++; } /* check for an exponent */ if ((dl || dr) && *p == 'E') { p++; /* check for a sign */ if (*p == '+' || *p == '-') p++; /* check for a string of digits */ while (isdigit(*p)) p++, dr++; } /* make sure there was at least one digit and this is the end */ if ((dl == 0 && dr == 0) || *p) return (FALSE); /* convert the string to an integer and return successfully */ if (pval) { if (*str == '+') ++str; if (str[strlen(str)-1] == '.') str[strlen(str)-1] = 0; *pval = (dr ? cvflonum(atof(str)) : cvfixnum(ICNV(str))); } return (TRUE); } /* defmacro - define a read macro */ void defmacro(int ch, LVAL type, int offset) { extern FUNDEF funtab[]; LVAL subr; subr = cvsubr(funtab[offset].fd_subr,funtab[offset].fd_type,offset); setelement(getvalue(s_rtable),ch,cons(type,subr)); } /* callmacro - call a read macro */ LVAL callmacro(LVAL fptr, int ch) { LVAL *newfp; /* create the new call frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(cdr(getelement(getvalue(s_rtable),ch))); pusharg(cvfixnum((FIXTYPE)2)); pusharg(fptr); pusharg(cvchar(ch)); xlfp = newfp; return (xlapply(2)); } /* upcase - translate a string to upper case */ LOCAL void upcase(char *str) { for (; *str != '\0'; ++str) if (islower(*str)) *str = toupper(*str); } /* xlrinit - initialize the reader */ void xlrinit(void) { LVAL rtable; char *p; int ch; /* create the read table */ rtable = newvector(256); setvalue(s_rtable,rtable); /* initialize the readtable */ for (p = WSPACE; (ch = *p++); ) setelement(rtable,ch,k_wspace); for (p = CONST1; (ch = *p++); ) setelement(rtable,ch,k_const); for (p = CONST2; (ch = *p++); ) setelement(rtable,ch,k_const); /* setup the escape characters */ setelement(rtable,'\\',k_sescape); setelement(rtable,'|', k_mescape); /* install the read macros */ defmacro('#', k_nmacro,FT_RMHASH); defmacro('\'',k_tmacro,FT_RMQUOTE); defmacro('"', k_tmacro,FT_RMDQUOTE); defmacro('`', k_tmacro,FT_RMBQUOTE); defmacro(',', k_tmacro,FT_RMCOMMA); defmacro('(', k_tmacro,FT_RMLPAR); defmacro(')', k_tmacro,FT_RMRPAR); defmacro(';', k_tmacro,FT_RMSEMI); } nyquist-3.05/xlisp/xldmem.h0000644000175000000620000001503111524127024014757 0ustar stevestaff/* xldmem.h - dynamic memory definitions */ /* Copyright (c) 1987, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* small fixnum range */ #define SFIXMIN (-128) #define SFIXMAX 255 #define SFIXSIZE 384 /* character range */ #define CHARMIN 0 #define CHARMAX 255 #define CHARSIZE 256 /* new node access macros */ #define ntype(x) ((x)->n_type) /* cons access macros */ #define car(x) ((x)->n_car) #define cdr(x) ((x)->n_cdr) #define rplaca(x,y) ((x)->n_car = (y)) #define rplacd(x,y) ((x)->n_cdr = (y)) /* symbol access macros */ #define getvalue(x) ((x)->n_vdata[0]) #define setvalue(x,v) ((x)->n_vdata[0] = (v)) #define getfunction(x) ((x)->n_vdata[1]) #define setfunction(x,v) ((x)->n_vdata[1] = (v)) #define getplist(x) ((x)->n_vdata[2]) #define setplist(x,v) ((x)->n_vdata[2] = (v)) #define getpname(x) ((x)->n_vdata[3]) #define setpname(x,v) ((x)->n_vdata[3] = (v)) #define SYMSIZE 4 /* closure access macros */ #define getname(x) ((x)->n_vdata[0]) #define setname(x,v) ((x)->n_vdata[0] = (v)) #define gettype(x) ((x)->n_vdata[1]) #define settype(x,v) ((x)->n_vdata[1] = (v)) #define getargs(x) ((x)->n_vdata[2]) #define setargs(x,v) ((x)->n_vdata[2] = (v)) #define getoargs(x) ((x)->n_vdata[3]) #define setoargs(x,v) ((x)->n_vdata[3] = (v)) #define getrest(x) ((x)->n_vdata[4]) #define setrest(x,v) ((x)->n_vdata[4] = (v)) #define getkargs(x) ((x)->n_vdata[5]) #define setkargs(x,v) ((x)->n_vdata[5] = (v)) #define getaargs(x) ((x)->n_vdata[6]) #define setaargs(x,v) ((x)->n_vdata[6] = (v)) #define getbody(x) ((x)->n_vdata[7]) #define setbody(x,v) ((x)->n_vdata[7] = (v)) /* use closure_getenv to avoid Unix getenv conflict */ #define closure_getenv(x) ((x)->n_vdata[8]) #define setenv(x,v) ((x)->n_vdata[8] = (v)) #define getfenv(x) ((x)->n_vdata[9]) #define setfenv(x,v) ((x)->n_vdata[9] = (v)) #define getlambda(x) ((x)->n_vdata[10]) #define setlambda(x,v) ((x)->n_vdata[10] = (v)) #define CLOSIZE 11 /* vector access macros */ #define getsize(x) ((x)->n_vsize) #define getelement(x,i) ((x)->n_vdata[i]) #define setelement(x,i,v) ((x)->n_vdata[i] = (v)) /* object access macros */ #define getclass(x) ((x)->n_vdata[0]) #define getivar(x,i) ((x)->n_vdata[i+1]) #define setivar(x,i,v) ((x)->n_vdata[i+1] = (v)) /* subr/fsubr access macros */ #define getsubr(x) ((x)->n_subr) #define getoffset(x) ((x)->n_offset) /* fixnum/flonum/char access macros */ #define getfixnum(x) ((x)->n_fixnum) #define getflonum(x) ((x)->n_flonum) #define getchcode(x) ((x)->n_chcode) /* string access macros */ #define getstring(x) ((x)->n_string) #define getslength(x) ((x)->n_strlen) /* file stream access macros */ #define getfile(x) ((x)->n_fp) #define setfile(x,v) ((x)->n_fp = (v)) #define getsavech(x) ((x)->n_savech) #define setsavech(x,v) ((x)->n_savech = (v)) /* unnamed stream access macros */ #define gethead(x) ((x)->n_car) #define sethead(x,v) ((x)->n_car = (v)) #define gettail(x) ((x)->n_cdr) #define settail(x,v) ((x)->n_cdr = (v)) /* extern access macros */ #define getdesc(x) ((x)->n_desc) #define setdesc(x,d) ((x)->n_desc = (d)) #define getinst(x) ((x)->n_inst) #define setinst(x,i) ((x)->n_inst = (i)) /* node types */ #define FREE_NODE 0 #define SUBR 1 #define FSUBR 2 #define CONS 3 #define SYMBOL 4 #define FIXNUM 5 #define FLONUM 6 #define STRING 7 #define OBJECT 8 #define STREAM 9 #define VECTOR 10 #define CLOSURE 11 #define CHAR 12 #define USTREAM 13 #define EXTERN 14 /* node flags */ #define WATCH 4 /* subr/fsubr node */ #define n_subr n_info.n_xsubr.xs_subr #define n_offset n_info.n_xsubr.xs_offset /* cons node */ #define n_car n_info.n_xcons.xc_car #define n_cdr n_info.n_xcons.xc_cdr /* fixnum node */ #define n_fixnum n_info.n_xfixnum.xf_fixnum /* flonum node */ #define n_flonum n_info.n_xflonum.xf_flonum /* character node */ #define n_chcode n_info.n_xchar.xc_chcode /* string node */ #define n_string n_info.n_xstring.xs_string #define n_strlen n_info.n_xstring.xs_length /* stream node */ #define n_fp n_info.n_xstream.xs_fp #define n_savech n_info.n_xstream.xs_savech /* vector/object node */ #define n_vsize n_info.n_xvector.xv_size #define n_vdata n_info.n_xvector.xv_data /* extern node */ #define n_desc n_info.n_xextern.xe_desc #define n_inst n_info.n_xextern.xe_inst /* xtype_desc structure */ typedef struct xtype_desc_struct { char *type_name; struct node *type_symbol; void (*free_meth)(void*); void (*print_meth)(void*, void*); void (*save_meth)(FILE*, void*); unsigned char * (*restore_meth)(FILE*); void (*mark_meth)(void*); } *xtype_desc; /* node structure */ typedef struct node { char n_type; /* type of node */ char n_flags; /* flag bits */ union ninfo { /* value */ struct xsubr { /* subr/fsubr node */ struct node *(*xs_subr)(void); /* function pointer */ int xs_offset; /* offset into funtab */ } n_xsubr; struct xcons { /* cons node */ struct node *xc_car; /* the car pointer */ struct node *xc_cdr; /* the cdr pointer */ } n_xcons; struct xfixnum { /* fixnum node */ FIXTYPE xf_fixnum; /* fixnum value */ } n_xfixnum; struct xflonum { /* flonum node */ FLOTYPE xf_flonum; /* flonum value */ } n_xflonum; struct xchar { /* character node */ int xc_chcode; /* character code */ } n_xchar; struct xstring { /* string node */ int xs_length; /* string length */ unsigned char *xs_string; /* string pointer */ } n_xstring; struct xstream { /* stream node */ FILE *xs_fp; /* the file pointer */ int xs_savech; /* lookahead character */ } n_xstream; struct xvector { /* vector/object/symbol/structure node */ int xv_size; /* vector size */ struct node **xv_data; /* vector data */ } n_xvector; struct xextern { /* external data type */ struct xtype_desc_struct *xe_desc; /* ptr to type descriptor */ unsigned char *xe_inst; /* pointer to external data */ } n_xextern; } n_info; } *LVAL; /* memory segment structure definition */ typedef struct segment { int sg_size; struct segment *sg_next; struct node sg_nodes[1]; } SEGMENT; /* initialize a type descriptor */ extern xtype_desc create_desc(char *type_name, void (*fm)(void*), void (*pm)(void*, void*), void (*sm)(FILE*, void*), unsigned char * (*rm)(FILE*), void (*mm)(void*)); nyquist-3.05/xlisp/xlsym.c0000644000175000000620000002304710144436365014656 0ustar stevestaff/* xlsym - symbol handling routines */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* HISTORY * 28-apr-03 DM eliminate some compiler warnings * 12-oct-90 RBD added xlatomcount to keep track of how many atoms there are. * (something I need for writing out score files). */ #include "string.h" #include "xlisp.h" extern int xlatomcount; /* forward declarations */ FORWARD LVAL findprop(LVAL sym, LVAL prp); #ifdef FRAME_DEBUG /* these routines were used to debug a missing call to protect(). * The routines can check for a consistent set of frames. Note * that frames must be pushed on the stack declared here because * XLisp keeps frame pointers as local variables in C routines. * I deleted the calls to push_xlenv etc throughout the XLisp * sources, but decided to leave the following code for possible * future debugging. - RBD */ int envstack_top = 0; LVAL envstack[envstack_max]; LVAL *fpstack[envstack_max]; extern long cons_count; FORWARD LOCAL void test_one_env(LVAL environment, int i, char *s); void push_xlenv(void) { char s[10]; /* sprintf(s, "<%d ", envstack_top); stdputstr(s); */ if (envstack_top >= envstack_max) { xlabort("envstack overflow"); } else { fpstack[envstack_top] = xlfp; envstack[envstack_top++] = xlenv; } } void pop_xlenv(void) { char s[10]; if (envstack_top <= 0) { sprintf(s, ", %d! ", envstack_top); stdputstr(s); xlabort("envstack underflow!"); } else envstack_top--; /* sprintf(s, "%d> ", envstack_top); stdputstr(s); */ } void pop_multiple_xlenv(void) { int i; for (i = envstack_top - 1; i >= 0; i--) { if (envstack[i] == xlenv) { char s[10]; envstack_top = i + 1; /* sprintf(s, "%d] ", envstack_top); stdputstr(s); */ return; } } } void testenv(char *s) { int i; for (i = envstack_top - 1; i >= 0; i--) { test_one_env(envstack[i], i, s); } } LOCAL void report_exit(char *msg, int i) { sprintf(buf, "env stack index: %d, cons_count %ld, Function: ", i, cons_count); errputstr(buf); stdprint(fpstack[i][1]); xlabort(msg); } LOCAL void test_one_env(LVAL environment, int i, char *s) { register LVAL fp,ep; LVAL val; /* check the environment list */ for (fp = environment; fp; fp = cdr(fp)) { /* check that xlenv is good */ if (!consp(fp)) { sprintf(buf,"%s: xlenv 0x%lx, frame 0x%lx, type(frame) %d\n", s, xlenv, fp, ntype(fp)); errputstr(buf); report_exit("xlenv points to a bad list", i); } /* check for an instance variable */ if ((ep = car(fp)) && objectp(car(ep))) { /* do nothing */ } /* check an environment stack frame */ else { for (; ep; ep = cdr(ep)) { /* check that ep is good */ if (!consp(ep)) { sprintf(buf,"%s: fp 0x%lx, ep 0x%lx, type(ep) %d\n", s, fp, ep, ntype(ep)); errputstr(buf); report_exit("car(fp) points to a bad list", i); } /* check that car(ep) is nonnull */ if (!car(ep)) { sprintf(buf,"%s: ep 0x%lx, car(ep) 0x%lx\n", s, ep, car(ep)); errputstr(buf); report_exit("car(ep) (an association) is NULL", i); } /* check that car(ep) is a cons */ if (!consp(car(ep))) { sprintf(buf,"%s: ep 0x%lx, car(ep) 0x%lx, type(car(ep)) %d\n", s, ep, car(ep), ntype(car(ep))); errputstr(buf); report_exit("car(ep) (an association) is not a cons", i); } /* check that car(car(ep)) is a symbol */ if (!symbolp(car(car(ep)))) { sprintf(buf,"%s: ep 0x%lx, car(ep) 0x%lx, car(car(ep)) 0x%lx, type(car(car(ep))) %d\n", s, ep, car(ep), car(car(ep)), ntype(car(car(ep)))); errputstr(buf); report_exit("car(car(ep)) is not a symbol", i); } } } } } #endif /* xlenter - enter a symbol into the obarray */ LVAL xlenter(char *name) { LVAL sym,array; int i; /* check for nil */ if (strcmp(name,"NIL") == 0) return (NIL); /* check for symbol already in table */ array = getvalue(obarray); i = hash(name,HSIZE); for (sym = getelement(array,i); sym; sym = cdr(sym)) if (strcmp(name,(char *) getstring(getpname(car(sym)))) == 0) return (car(sym)); /* make a new symbol node and link it into the list */ xlsave1(sym); sym = consd(getelement(array,i)); rplaca(sym,xlmakesym(name)); setelement(array,i,sym); xlpop(); /* return the new symbol */ return (car(sym)); } /* xlmakesym - make a new symbol node */ LVAL xlmakesym(char *name) { LVAL sym; sym = cvsymbol(name); if (*name == ':') setvalue(sym,sym); return (sym); } /* xlgetvalue - get the value of a symbol (with check) */ LVAL xlgetvalue(LVAL sym) { LVAL val; /* look for the value of the symbol */ while ((val = xlxgetvalue(sym)) == s_unbound) xlunbound(sym); /* return the value */ return (val); } /* xlxgetvalue - get the value of a symbol */ LVAL xlxgetvalue(LVAL sym) { register LVAL fp,ep; LVAL val; /* check the environment list */ for (fp = xlenv; fp; fp = cdr(fp)) /* check for an instance variable */ if ((ep = car(fp)) && objectp(car(ep))) { if (xlobgetvalue(ep,sym,&val)) return (val); } /* check an environment stack frame */ else { for (; ep; ep = cdr(ep)) if (sym == car(car(ep))) return (cdr(car(ep))); } /* return the global value */ return (getvalue(sym)); } /* xlsetvalue - set the value of a symbol */ void xlsetvalue(LVAL sym, LVAL val) { register LVAL fp,ep; /* look for the symbol in the environment list */ for (fp = xlenv; fp; fp = cdr(fp)) /* check for an instance variable */ if ((ep = car(fp)) && objectp(car(ep))) { if (xlobsetvalue(ep,sym,val)) return; } /* check an environment stack frame */ else { for (; ep; ep = cdr(ep)) if (sym == car(car(ep))) { rplacd(car(ep),val); return; } } /* store the global value */ setvalue(sym,val); } /* xlgetfunction - get the functional value of a symbol (with check) */ LVAL xlgetfunction(LVAL sym) { LVAL val; /* look for the functional value of the symbol */ while ((val = xlxgetfunction(sym)) == s_unbound) xlfunbound(sym); /* return the value */ return (val); } /* xlxgetfunction - get the functional value of a symbol */ LVAL xlxgetfunction(LVAL sym) { register LVAL fp,ep; /* check the environment list */ for (fp = xlfenv; fp; fp = cdr(fp)) for (ep = car(fp); ep; ep = cdr(ep)) if (sym == car(car(ep))) return (cdr(car(ep))); /* return the global value */ return (getfunction(sym)); } /* xlsetfunction - set the functional value of a symbol */ void xlsetfunction(LVAL sym, LVAL val) { register LVAL fp,ep; /* look for the symbol in the environment list */ for (fp = xlfenv; fp; fp = cdr(fp)) for (ep = car(fp); ep; ep = cdr(ep)) if (sym == car(car(ep))) { rplacd(car(ep),val); return; } /* store the global value */ setfunction(sym,val); } /* xlgetprop - get the value of a property */ LVAL xlgetprop(LVAL sym, LVAL prp) { LVAL p; return ((p = findprop(sym,prp)) ? car(p) : NIL); } /* xlputprop - put a property value onto the property list */ void xlputprop(LVAL sym, LVAL val, LVAL prp) { LVAL pair; if ((pair = findprop(sym,prp))) rplaca(pair,val); else setplist(sym,cons(prp,cons(val,getplist(sym)))); } /* xlremprop - remove a property from a property list */ void xlremprop(LVAL sym, LVAL prp) { LVAL last,p; last = NIL; for (p = getplist(sym); consp(p) && consp(cdr(p)); p = cdr(last)) { if (car(p) == prp) { if (last) rplacd(last,cdr(cdr(p))); else setplist(sym,cdr(cdr(p))); } last = cdr(p); } } /* findprop - find a property pair */ LVAL findprop(LVAL sym, LVAL prp) { LVAL p; for (p = getplist(sym); consp(p) && consp(cdr(p)); p = cdr(cdr(p))) if (car(p) == prp) return (cdr(p)); return (NIL); } /* hash - hash a symbol name string */ int hash(char *str, int len) { int i; for (i = 0; *str; ) i = (i << 2) ^ *str++; i %= len; return (i < 0 ? -i : i); } /* xlsinit - symbol initialization routine */ void xlsinit(void) { LVAL array,p; /* initialize the obarray */ obarray = xlmakesym("*OBARRAY*"); array = newvector(HSIZE); setvalue(obarray,array); /* add the symbol *OBARRAY* to the obarray */ p = consa(obarray); setelement(array,hash("*OBARRAY*",HSIZE),p); } nyquist-3.05/xlisp/xlsubr.c0000644000175000000620000001116210144436365015014 0ustar stevestaff/* xlsubr - xlisp builtin function support routines */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "string.h" #include "xlisp.h" /* external variables */ extern LVAL k_test,k_tnot,s_eql; /* xlsubr - define a builtin function */ LVAL xlsubr(char *sname, int type, LVAL (*fcn)(void), int offset) { LVAL sym; sym = xlenter(sname); setfunction(sym,cvsubr(fcn,type,offset)); return (sym); } /* xlgetkeyarg - get a keyword argument */ int xlgetkeyarg(LVAL key, LVAL *pval) { LVAL *argv=xlargv; int argc=xlargc; for (argv = xlargv, argc = xlargc; (argc -= 2) >= 0; argv += 2) { if (*argv == key) { *pval = *++argv; return (TRUE); } } return (FALSE); } /* xlgkfixnum - get a fixnum keyword argument */ int xlgkfixnum(LVAL key, LVAL *pval) { if (xlgetkeyarg(key,pval)) { if (!fixp(*pval)) xlbadtype(*pval); return (TRUE); } return (FALSE); } /* xltest - get the :test or :test-not keyword argument */ void xltest(LVAL *pfcn, int *ptresult) { if (xlgetkeyarg(k_test,pfcn)) /* :test */ *ptresult = TRUE; else if (xlgetkeyarg(k_tnot,pfcn)) /* :test-not */ *ptresult = FALSE; else { *pfcn = getfunction(s_eql); *ptresult = TRUE; } } /* xlgetfile - get a file or stream */ LVAL xlgetfile(void) { LVAL arg; /* get a file or stream (cons) or nil */ if ((arg = xlgetarg())) { if (streamp(arg)) { if (getfile(arg) == NULL) xlfail("file not open"); } else if (!ustreamp(arg)) xlerror("bad argument type",arg); } return (arg); } /* xlgetfname - get a filename */ LVAL xlgetfname(void) { LVAL name; /* get the next argument */ name = xlgetarg(); /* get the filename string */ if (symbolp(name)) name = getpname(name); else if (!stringp(name)) xlerror("bad argument type",name); /* return the name */ return (name); } /* needsextension - check if a filename needs an extension */ int needsextension(char *name) { char *p; /* check for an extension */ for (p = &name[strlen(name)]; --p >= &name[0]; ) if (*p == '.') return (FALSE); else if (!islower(*p) && !isupper(*p) && !isdigit(*p)) return (TRUE); /* no extension found */ return (TRUE); } /* the next three functions must be declared as LVAL because they * are used in LVAL expressions, but they do not return anything * warning 4035 is "no return value" */ /* #pragma warning(disable: 4035) */ /* xlbadtype - report a "bad argument type" error */ LVAL xlbadtype(LVAL arg) { xlerror("bad argument type",arg); return NIL; /* never happens */ } /* xltoofew - report a "too few arguments" error */ LVAL xltoofew(void) { xlfail("too few arguments"); return NIL; /* never happens */ } /* xltoomany - report a "too many arguments" error */ LVAL xltoomany(void) { xlfail("too many arguments"); return NIL; /* never happens */ } /* eq - internal eq function */ int eq(LVAL arg1, LVAL arg2) { return (arg1 == arg2); } /* eql - internal eql function */ int eql(LVAL arg1, LVAL arg2) { /* compare the arguments */ if (arg1 == arg2) return (TRUE); else if (arg1) { switch (ntype(arg1)) { case FIXNUM: return (fixp(arg2) ? getfixnum(arg1)==getfixnum(arg2) : FALSE); case FLONUM: return (floatp(arg2) ? getflonum(arg1)==getflonum(arg2) : FALSE); default: return (FALSE); } } else return (FALSE); } /* lval_equal - internal equal function */ int lval_equal(LVAL arg1, LVAL arg2) { /* compare the arguments */ if (arg1 == arg2) return (TRUE); else if (arg1) { switch (ntype(arg1)) { case FIXNUM: return (fixp(arg2) ? getfixnum(arg1)==getfixnum(arg2) : FALSE); case FLONUM: return (floatp(arg2) ? getflonum(arg1)==getflonum(arg2) : FALSE); case STRING: return (stringp(arg2) ? strcmp((char *) getstring(arg1), (char *) getstring(arg2)) == 0 : FALSE); case CONS: return (consp(arg2) ? lval_equal(car(arg1),car(arg2)) && lval_equal(cdr(arg1),cdr(arg2)) : FALSE); default: return (FALSE); } } else return (FALSE); } nyquist-3.05/xlisp/xlstr.c0000644000175000000620000003565611466723256014675 0ustar stevestaff/* xlstr - xlisp string and character built-in functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "string.h" #include "xlisp.h" /* local definitions */ #define fix(n) cvfixnum((FIXTYPE)(n)) #define TLEFT 1 #define TRIGHT 2 /* external variables */ extern LVAL k_start,k_end,k_1start,k_1end,k_2start,k_2end; extern LVAL s_true; extern char buf[]; /* forward declarations */ FORWARD LOCAL LVAL strcompare(int fcn, int icase); FORWARD LOCAL LVAL chrcompare(int fcn, int icase); FORWARD LOCAL LVAL changecase(int fcn, int destructive); FORWARD LOCAL LVAL trim(int fcn); FORWARD LOCAL void getbounds(LVAL str, LVAL skey, LVAL ekey, int *pstart, int *pend); FORWARD LOCAL int inbag(int ch, LVAL bag); /* string comparision functions */ LVAL xstrlss(void) { return (strcompare('<',FALSE)); } /* string< */ LVAL xstrleq(void) { return (strcompare('L',FALSE)); } /* string<= */ LVAL xstreql(void) { return (strcompare('=',FALSE)); } /* string= */ LVAL xstrneq(void) { return (strcompare('#',FALSE)); } /* string/= */ LVAL xstrgeq(void) { return (strcompare('G',FALSE)); } /* string>= */ LVAL xstrgtr(void) { return (strcompare('>',FALSE)); } /* string> */ /* string comparison functions (not case sensitive) */ LVAL xstrilss(void) { return (strcompare('<',TRUE)); } /* string-lessp */ LVAL xstrileq(void) { return (strcompare('L',TRUE)); } /* string-not-greaterp */ LVAL xstrieql(void) { return (strcompare('=',TRUE)); } /* string-equal */ LVAL xstrineq(void) { return (strcompare('#',TRUE)); } /* string-not-equal */ LVAL xstrigeq(void) { return (strcompare('G',TRUE)); } /* string-not-lessp */ LVAL xstrigtr(void) { return (strcompare('>',TRUE)); } /* string-greaterp */ /* strcompare - compare strings */ LOCAL LVAL strcompare(int fcn, int icase) { int start1,end1,start2,end2,ch1,ch2; unsigned char *p1,*p2; LVAL str1,str2; /* get the strings */ str1 = xlgastring(); str2 = xlgastring(); /* get the substring specifiers */ getbounds(str1,k_1start,k_1end,&start1,&end1); getbounds(str2,k_2start,k_2end,&start2,&end2); /* setup the string pointers */ p1 = &getstring(str1)[start1]; p2 = &getstring(str2)[start2]; /* compare the strings */ for (; start1 < end1 && start2 < end2; ++start1,++start2) { ch1 = *p1++; ch2 = *p2++; if (icase) { if (isupper(ch1)) ch1 = tolower(ch1); if (isupper(ch2)) ch2 = tolower(ch2); } if (ch1 != ch2) switch (fcn) { case '<': return (ch1 < ch2 ? fix(start1) : NIL); case 'L': return (ch1 <= ch2 ? fix(start1) : NIL); case '=': return (NIL); case '#': return (fix(start1)); case 'G': return (ch1 >= ch2 ? fix(start1) : NIL); case '>': return (ch1 > ch2 ? fix(start1) : NIL); } } /* check the termination condition */ switch (fcn) { case '<': return (start1 >= end1 && start2 < end2 ? fix(start1) : NIL); case 'L': return (start1 >= end1 ? fix(start1) : NIL); case '=': return (start1 >= end1 && start2 >= end2 ? s_true : NIL); case '#': return (start1 >= end1 && start2 >= end2 ? NIL : fix(start1)); case 'G': return (start2 >= end2 ? fix(start1) : NIL); case '>': return (start2 >= end2 && start1 < end1 ? fix(start1) : NIL); } return NIL; /* Normally shouldn't happen */ } /* case conversion functions */ LVAL xupcase(void) { return (changecase('U',FALSE)); } LVAL xdowncase(void) { return (changecase('D',FALSE)); } /* destructive case conversion functions */ LVAL xnupcase(void) { return (changecase('U',TRUE)); } LVAL xndowncase(void) { return (changecase('D',TRUE)); } /* changecase - change case */ LOCAL LVAL changecase(int fcn, int destructive) { unsigned char *srcp,*dstp; int start,end,len,ch,i; LVAL src,dst; /* get the string */ src = xlgastring(); /* get the substring specifiers */ getbounds(src,k_start,k_end,&start,&end); len = getslength(src) - 1; /* make a destination string */ dst = (destructive ? src : new_string(len+1)); /* setup the string pointers */ srcp = getstring(src); dstp = getstring(dst); /* copy the source to the destination */ for (i = 0; i < len; ++i) { ch = *srcp++; if (i >= start && i < end) switch (fcn) { case 'U': if (islower(ch)) ch = toupper(ch); break; case 'D': if (isupper(ch)) ch = tolower(ch); break; } *dstp++ = ch; } *dstp = '\0'; /* return the new string */ return (dst); } /* search for string within a string */ LVAL xstrsearch(void) { int start,end,pat_len,str_len; unsigned char *pat,*str,*patptr,*strptr,*patend; LVAL str1,str2; /* get the strings */ str1 = xlgastring(); /* the pat */ str2 = xlgastring(); /* the string */ /* get the substring specifiers */ getbounds(str2, k_start, k_end, &start, &end); /* setup the string pointers */ pat = getstring(str1); str = &getstring(str2)[start]; pat_len = getslength(str1) - 1; str_len = end - start; patend = pat + pat_len; for (; pat_len <= str_len; str_len--) { patptr = pat; strptr = str; /* two outcomes: (1) no match, goto step (2) match, return */ while (patptr < patend) { if (*patptr++ != *strptr++) goto step; } /* compute match index */ return cvfixnum(str - getstring(str2)); step: str++; } /* no match */ return NIL; } /* trim functions */ LVAL xtrim(void) { return (trim(TLEFT|TRIGHT)); } LVAL xlefttrim(void) { return (trim(TLEFT)); } LVAL xrighttrim(void) { return (trim(TRIGHT)); } /* trim - trim character from a string */ LOCAL LVAL trim(int fcn) { unsigned char *leftp,*rightp,*dstp; LVAL bag,src,dst; /* get the bag and the string */ bag = xlgastring(); src = xlgastring(); xllastarg(); /* setup the string pointers */ leftp = getstring(src); rightp = leftp + getslength(src) - 2; /* trim leading characters */ if (fcn & TLEFT) while (leftp <= rightp && inbag(*leftp,bag)) ++leftp; /* trim character from the right */ if (fcn & TRIGHT) while (rightp >= leftp && inbag(*rightp,bag)) --rightp; /* make a destination string and setup the pointer */ dst = new_string((int)(rightp-leftp+2)); dstp = getstring(dst); /* copy the source to the destination */ while (leftp <= rightp) *dstp++ = *leftp++; *dstp = '\0'; /* return the new string */ return (dst); } /* getbounds - get the start and end bounds of a string */ LOCAL void getbounds(LVAL str, LVAL skey, LVAL ekey, int *pstart, int *pend) { LVAL arg; int len; /* get the length of the string */ len = getslength(str) - 1; /* get the starting index */ if (xlgkfixnum(skey,&arg)) { *pstart = (int)getfixnum(arg); if (*pstart < 0 || *pstart > len) xlerror("string index out of bounds",arg); } else *pstart = 0; /* get the ending index */ if (xlgkfixnum(ekey,&arg)) { *pend = (int)getfixnum(arg); if (*pend < 0 || *pend > len) xlerror("string index out of bounds",arg); } else *pend = len; /* make sure the start is less than or equal to the end */ if (*pstart > *pend) xlerror("starting index error",cvfixnum((FIXTYPE)*pstart)); } /* inbag - test if a character is in a bag */ LOCAL int inbag(int ch, LVAL bag) { unsigned char *p; for (p = getstring(bag); *p != '\0'; ++p) if (*p == ch) return (TRUE); return (FALSE); } /* xstrcat - concatenate a bunch of strings */ LVAL xstrcat(void) { LVAL *saveargv,tmp,val; unsigned char *str; int saveargc,len; /* save the argument list */ saveargv = xlargv; saveargc = xlargc; /* find the length of the new string */ for (len = 0; moreargs(); ) { tmp = xlgastring(); len += (int)getslength(tmp) - 1; } /* create the result string */ val = new_string(len+1); str = getstring(val); /* restore the argument list */ xlargv = saveargv; xlargc = saveargc; /* combine the strings */ for (*str = '\0'; moreargs(); ) { tmp = nextarg(); strcat((char *) str, (char *) getstring(tmp)); } /* return the new string */ return (val); } /* xsubseq - return a subsequence */ LVAL xsubseq(void) { unsigned char *srcp,*dstp; int start,end,len; LVAL src,dst; /* get string and starting and ending positions */ src = xlgastring(); /* get the starting position */ dst = xlgafixnum(); start = (int)getfixnum(dst); if (start < 0 || start > getslength(src) - 1) xlerror("string index out of bounds",dst); /* get the ending position */ if (moreargs()) { dst = xlgafixnum(); end = (int)getfixnum(dst); if (end < 0 || end > getslength(src) - 1) xlerror("string index out of bounds",dst); } else end = getslength(src) - 1; xllastarg(); /* setup the source pointer */ srcp = getstring(src) + start; len = end - start; /* make a destination string and setup the pointer */ dst = new_string(len+1); dstp = getstring(dst); /* copy the source to the destination */ while (--len >= 0) *dstp++ = *srcp++; *dstp = '\0'; /* return the substring */ return (dst); } /* xstring - return a string consisting of a single character */ LVAL xstring(void) { LVAL arg; /* get the argument */ arg = xlgetarg(); xllastarg(); /* make sure its not NIL */ if (null(arg)) xlbadtype(arg); /* check the argument type */ switch (ntype(arg)) { case STRING: return (arg); case SYMBOL: return (getpname(arg)); case CHAR: buf[0] = (int)getchcode(arg); buf[1] = '\0'; return (cvstring(buf)); case FIXNUM: buf[0] = getfixnum(arg); buf[1] = '\0'; return (cvstring(buf)); default: xlbadtype(arg); return NIL; /* never happens */ } } /* xchar - extract a character from a string */ LVAL xchar(void) { LVAL str,num; int n; /* get the string and the index */ str = xlgastring(); num = xlgafixnum(); xllastarg(); /* range check the index */ if ((n = (int)getfixnum(num)) < 0 || n >= getslength(str) - 1) xlerror("index out of range",num); /* return the character */ return (cvchar(getstring(str)[n])); } /* xcharint - convert an integer to a character */ LVAL xcharint(void) { LVAL arg; arg = xlgachar(); xllastarg(); return (cvfixnum((FIXTYPE)getchcode(arg))); } /* xintchar - convert a character to an integer */ LVAL xintchar(void) { LVAL arg; arg = xlgafixnum(); xllastarg(); return (cvchar((int)getfixnum(arg))); } /* xuppercasep - built-in function 'upper-case-p' */ LVAL xuppercasep(void) { int ch; ch = getchcode(xlgachar()); xllastarg(); return (isupper(ch) ? s_true : NIL); } /* xlowercasep - built-in function 'lower-case-p' */ LVAL xlowercasep(void) { int ch; ch = getchcode(xlgachar()); xllastarg(); return (islower(ch) ? s_true : NIL); } /* xbothcasep - built-in function 'both-case-p' */ LVAL xbothcasep(void) { int ch; ch = getchcode(xlgachar()); xllastarg(); return (isupper(ch) || islower(ch) ? s_true : NIL); } /* xdigitp - built-in function 'digit-char-p' */ LVAL xdigitp(void) { int ch; ch = getchcode(xlgachar()); xllastarg(); return (isdigit(ch) ? cvfixnum((FIXTYPE)(ch - '0')) : NIL); } /* xcharcode - built-in function 'char-code' */ LVAL xcharcode(void) { int ch; ch = getchcode(xlgachar()); xllastarg(); return (cvfixnum((FIXTYPE)ch)); } /* xcodechar - built-in function 'code-char' */ LVAL xcodechar(void) { LVAL arg; int ch; arg = xlgafixnum(); ch = getfixnum(arg); xllastarg(); return (ch >= 0 && ch <= 127 ? cvchar(ch) : NIL); } /* xchupcase - built-in function 'char-upcase' */ LVAL xchupcase(void) { LVAL arg; int ch; arg = xlgachar(); ch = getchcode(arg); xllastarg(); return (islower(ch) ? cvchar(toupper(ch)) : arg); } /* xchdowncase - built-in function 'char-downcase' */ LVAL xchdowncase(void) { LVAL arg; int ch; arg = xlgachar(); ch = getchcode(arg); xllastarg(); return (isupper(ch) ? cvchar(tolower(ch)) : arg); } /* xdigitchar - built-in function 'digit-char' */ LVAL xdigitchar(void) { LVAL arg; int n; arg = xlgafixnum(); n = getfixnum(arg); xllastarg(); return (n >= 0 && n <= 9 ? cvchar(n + '0') : NIL); } /* xalphanumericp - built-in function 'alphanumericp' */ LVAL xalphanumericp(void) { int ch; ch = getchcode(xlgachar()); xllastarg(); return (isupper(ch) || islower(ch) || isdigit(ch) ? s_true : NIL); } /* character comparision functions */ LVAL xchrlss(void) { return (chrcompare('<',FALSE)); } /* char< */ LVAL xchrleq(void) { return (chrcompare('L',FALSE)); } /* char<= */ LVAL xchreql(void) { return (chrcompare('=',FALSE)); } /* char= */ LVAL xchrneq(void) { return (chrcompare('#',FALSE)); } /* char/= */ LVAL xchrgeq(void) { return (chrcompare('G',FALSE)); } /* char>= */ LVAL xchrgtr(void) { return (chrcompare('>',FALSE)); } /* char> */ /* character comparision functions (case insensitive) */ LVAL xchrilss(void) { return (chrcompare('<',TRUE)); } /* char-lessp */ LVAL xchrileq(void) { return (chrcompare('L',TRUE)); } /* char-not-greaterp */ LVAL xchrieql(void) { return (chrcompare('=',TRUE)); } /* char-equal */ LVAL xchrineq(void) { return (chrcompare('#',TRUE)); } /* char-not-equal */ LVAL xchrigeq(void) { return (chrcompare('G',TRUE)); } /* char-not-lessp */ LVAL xchrigtr(void) { return (chrcompare('>',TRUE)); } /* char-greaterp */ /* chrcompare - compare characters */ LOCAL LVAL chrcompare(int fcn, int icase) { int ch1,ch2,icmp; LVAL arg; /* get the characters */ arg = xlgachar(); ch1 = getchcode(arg); /* convert to lowercase if case insensitive */ if (icase && isupper(ch1)) ch1 = tolower(ch1); /* handle each remaining argument */ for (icmp = TRUE; icmp && moreargs(); ch1 = ch2) { /* get the next argument */ arg = xlgachar(); ch2 = getchcode(arg); /* convert to lowercase if case insensitive */ if (icase && isupper(ch2)) ch2 = tolower(ch2); /* compare the characters */ switch (fcn) { case '<': icmp = (ch1 < ch2); break; case 'L': icmp = (ch1 <= ch2); break; case '=': icmp = (ch1 == ch2); break; case '#': icmp = (ch1 != ch2); break; case 'G': icmp = (ch1 >= ch2); break; case '>': icmp = (ch1 > ch2); break; } } /* return the result */ return (icmp ? s_true : NIL); } nyquist-3.05/xlisp/xlimage.c0000644000175000000620000002611211466723256015132 0ustar stevestaff/* xlimage - xlisp memory image save/restore functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ #include "stdlib.h" #include "string.h" #include "xlisp.h" #ifdef SAVERESTORE /* external variables */ extern LVAL obarray,s_gchook,s_gcflag; extern long nnodes,nfree,total; extern int anodes,nsegs,gccalls; extern struct segment *segs,*lastseg,*fixseg,*charseg; extern XLCONTEXT *xlcontext; extern LVAL fnodes; extern struct xtype_desc_struct desc_table[NTYPES]; /* local variables */ static OFFTYPE off,foff; static FILE *fp; /* forward declarations */ LOCAL OFFTYPE readptr(void); LOCAL OFFTYPE cvoptr(LVAL p); LOCAL LVAL cviptr(OFFTYPE o); LOCAL void writeptr(OFFTYPE off); LOCAL void setoffset(void); LOCAL void writenode(LVAL node); LOCAL void freeimage(void); LOCAL void readnode(int type, LVAL node); /* xlisave - save the memory image */ int xlisave(char *fname) { char fullname[STRMAX+1]; unsigned char *cp; SEGMENT *seg; int n,i,max; LVAL p; /* default the extension */ if (needsextension(fname)) { strcpy(fullname,fname); strcat(fullname,".wks"); fname = fullname; } /* open the output file */ if ((fp = osbopen(fname,"w")) == NULL) return (FALSE); /* first call the garbage collector to clean up memory */ gc(); /* invalidate extern type descriptor symbol caches */ inval_caches(); /* write out the pointer to the *obarray* symbol */ writeptr(cvoptr(obarray)); /* setup the initial file offsets */ off = foff = (OFFTYPE)2; /* write out all nodes that are still in use */ for (seg = segs; seg != NULL; seg = seg->sg_next) { p = &seg->sg_nodes[0]; for (n = seg->sg_size; --n >= 0; ++p, off += 2) switch (ntype(p)) { case FREE_NODE: break; case CONS: case USTREAM: setoffset(); osbputc(p->n_type,fp); writeptr(cvoptr(car(p))); writeptr(cvoptr(cdr(p))); foff += 2; break; case EXTERN: setoffset(); osbputc(EXTERN, fp); /* printf("saving EXTERN p = %x, desc %x\n", p, getdesc(p)); fflush(stdout);*/ writeptr((OFFTYPE) (getdesc(p) - desc_table)); /* write type index */ writeptr((OFFTYPE) 0); /* pointer gets reconstructed on input */ foff += 2; break; default: setoffset(); writenode(p); break; } } /* write the terminator */ osbputc(FREE_NODE,fp); writeptr((OFFTYPE)0); /* write out data portion of SYMBOL/VECTOR/OBJECT/STRING/CLOSURE nodes */ for (seg = segs; seg != NULL; seg = seg->sg_next) { p = &seg->sg_nodes[0]; for (n = seg->sg_size; --n >= 0; ++p) switch (ntype(p)) { case SYMBOL: case OBJECT: case VECTOR: case CLOSURE: max = getsize(p); for (i = 0; i < max; ++i) writeptr(cvoptr(getelement(p,i))); break; case STRING: max = getslength(p); for (cp = getstring(p); --max >= 0; ) osbputc(*cp++,fp); break; case EXTERN: /* printf("saving extern data for p = %x\n", p);*/ (*(getdesc(p)->save_meth))(fp, getinst(p)); break; } } /* close the output file */ osclose(fp); /* return successfully */ return (TRUE); } /* xlirestore - restore a saved memory image */ int xlirestore(char *fname) { extern FUNDEF funtab[]; char fullname[STRMAX+1]; unsigned char *cp; int n,i,max,type; SEGMENT *seg; LVAL p; /* default the extension */ if (needsextension(fname)) { strcpy(fullname,fname); strcat(fullname,".wks"); fname = fullname; } /* open the file */ if ((fp = osbopen(fname,"r")) == NULL) return (FALSE); /* free the old memory image */ freeimage(); /* initialize */ off = (OFFTYPE)2; total = nnodes = nfree = 0L; fnodes = NIL; segs = lastseg = NULL; nsegs = gccalls = 0; xlenv = xlfenv = xldenv = s_gchook = s_gcflag = NIL; xlstack = xlstkbase + EDEPTH; xlcontext = NULL; /* create the fixnum segment */ if ((fixseg = newsegment(SFIXSIZE)) == NULL) xlfatal("insufficient memory - fixnum segment"); /* create the character segment */ if ((charseg = newsegment(CHARSIZE)) == NULL) xlfatal("insufficient memory - character segment"); /* read the pointer to the *obarray* symbol */ obarray = cviptr(readptr()); /* read each node */ while ((type = osbgetc(fp)) >= 0) switch (type) { case FREE_NODE: if ((off = readptr()) == (OFFTYPE)0) goto done; break; case CONS: case USTREAM: p = cviptr(off); p->n_type = type; p->n_flags = 0; rplaca(p,cviptr(readptr())); rplacd(p,cviptr(readptr())); off += 2; break; case EXTERN: p = cviptr(off); /* printf("reading extern node p = %x\n", p);*/ p->n_type = EXTERN; setdesc(p, desc_table + (int) readptr()); /* printf("type desc is %x\n", getdesc(p));*/ setinst(p, (unsigned char *) readptr()); /* printf("initial inst is %x\n", getinst(p));*/ off += 2; break; default: readnode(type,cviptr(off)); off += 2; break; } done: /* read the data portion of SYMBOL/VECTOR/OBJECT/STRING/CLOSURE nodes */ for (seg = segs; seg != NULL; seg = seg->sg_next) { p = &seg->sg_nodes[0]; for (n = seg->sg_size; --n >= 0; ++p) switch (ntype(p)) { case SYMBOL: case OBJECT: case VECTOR: case CLOSURE: max = getsize(p); if ((p->n_vdata = (LVAL *)malloc(max * sizeof(LVAL))) == NULL) xlfatal("insufficient memory - vector"); total += (long)(max * sizeof(LVAL)); for (i = 0; i < max; ++i) setelement(p,i,cviptr(readptr())); break; case STRING: max = getslength(p); if ((p->n_string = (unsigned char *)malloc(max)) == NULL) xlfatal("insufficient memory - string"); total += (long)max; for (cp = getstring(p); --max >= 0; ) *cp++ = osbgetc(fp); break; case STREAM: setfile(p,NULL); break; case SUBR: case FSUBR: p->n_subr = funtab[getoffset(p)].fd_subr; break; case EXTERN: /* printf("restoring extern %x\n", p); fflush(stdout); */ setinst(p, (*(getdesc(p)->restore_meth))(fp)); break; } } /* close the input file */ osclose(fp); /* collect to initialize the free space */ gc(); /* lookup all of the symbols the interpreter uses */ xlsymbols(); /* return successfully */ return (TRUE); } /* freeimage - free the current memory image */ LOCAL void freeimage(void) { SEGMENT *seg,*next; FILE *fp; LVAL p; int n; /* free the data portion of SYMBOL/VECTOR/OBJECT/STRING nodes */ for (seg = segs; seg != NULL; seg = next) { p = &seg->sg_nodes[0]; for (n = seg->sg_size; --n >= 0; ++p) switch (ntype(p)) { case SYMBOL: case OBJECT: case VECTOR: case CLOSURE: if (p->n_vsize) free(p->n_vdata); break; case STRING: if (getslength(p)) free((void *) getstring(p)); break; case STREAM: if ((fp = getfile(p)) && (fp != stdin && fp != stdout && fp != STDERR)) osclose(getfile(p)); break; } next = seg->sg_next; free((void *) seg); } } /* setoffset - output a positioning command if nodes have been skipped */ LOCAL void setoffset(void) { if (off != foff) { osbputc(FREE_NODE,fp); writeptr(off); foff = off; } } /* writenode - write a node to a file */ LOCAL void writenode(LVAL node) { char *p = (char *)&node->n_info; int n = sizeof(union ninfo); osbputc(node->n_type,fp); while (--n >= 0) osbputc(*p++,fp); foff += 2; } /* writeptr - write a pointer to a file */ LOCAL void writeptr(OFFTYPE off) { char *p = (char *)&off; int n = sizeof(OFFTYPE); while (--n >= 0) osbputc(*p++,fp); } /* readnode - read a node */ LOCAL void readnode(int type, LVAL node) { char *p = (char *)&node->n_info; int n = sizeof(union ninfo); node->n_type = type; node->n_flags = 0; while (--n >= 0) *p++ = osbgetc(fp); } /* readptr - read a pointer */ LOCAL OFFTYPE readptr(void) { OFFTYPE off; char *p = (char *)&off; int n = sizeof(OFFTYPE); while (--n >= 0) *p++ = osbgetc(fp); return (off); } /* cviptr - convert a pointer on input */ LOCAL LVAL cviptr(OFFTYPE o) { OFFTYPE off = (OFFTYPE)2; SEGMENT *seg; /* check for nil */ if (o == (OFFTYPE)0) return ((LVAL)o); /* compute a pointer for this offset */ for (seg = segs; seg != NULL; seg = seg->sg_next) { if (o >= off && o < off + (OFFTYPE)(seg->sg_size << 1)) return (seg->sg_nodes + ((int)(o - off) >> 1)); off += (OFFTYPE)(seg->sg_size << 1); } /* create new segments if necessary */ for (;;) { /* create the next segment */ if ((seg = newsegment(anodes)) == NULL) xlfatal("insufficient memory - segment"); /* check to see if the offset is in this segment */ if (o >= off && o < off + (OFFTYPE)(seg->sg_size << 1)) return (seg->sg_nodes + ((int)(o - off) >> 1)); off += (OFFTYPE)(seg->sg_size << 1); } } /* cvoptr - convert a pointer on output */ LOCAL OFFTYPE cvoptr(LVAL p) { OFFTYPE off = (OFFTYPE)2; SEGMENT *seg; /* check for nil and small fixnums */ if (p == NIL) return ((OFFTYPE)p); /* compute an offset for this pointer */ for (seg = segs; seg != NULL; seg = seg->sg_next) { if (CVPTR(p) >= CVPTR(&seg->sg_nodes[0]) && CVPTR(p) < CVPTR(&seg->sg_nodes[0] + seg->sg_size)) return (off + (OFFTYPE)((p - seg->sg_nodes) << 1)); off += (OFFTYPE)(seg->sg_size << 1); } /* pointer not within any segment */ xlerror("bad pointer found during image save",p); /* this point will never be reached because xlerror() does a longjmp(). The return is added to avoid false positive error messages from static analyzers and compilers */ return ((OFFTYPE)NIL); } #endif nyquist-3.05/xlisp/path.c0000644000175000000620000001354711466723256014450 0ustar stevestaff/* * New xlisp_path code by Dominic Mazzoni * * There is now a function provided to set the xlisp_path. * This is particularly useful for external programs * (e.g. Audacity, or a Nyquist GUI) that have their own * mechanism of setting/finding the path. If xlisp_path * is NULL, the old platform-specific methods are still * used. */ /* CHANGE LOG * * 24-dec-05 RBD * Made ';' a valid path separator for every system (to work * around a windows installer limitation) * * 22-jul-07 RBD * Added get_user_id() * * 9-jan-08 RBD * Added find-in-xlisp-path as XLISP primitive */ #include #include "switches.h" #include "xlisp.h" static char *g_xlisp_path = NULL; void set_xlisp_path(const char *p) { if (g_xlisp_path) { free(g_xlisp_path); g_xlisp_path = NULL; } if (p) { g_xlisp_path = malloc(strlen(p)+1); strcpy(g_xlisp_path, p); } } #ifdef UNIX const char *unix_return_xlisp_path() { char *paths = getenv("XLISPPATH"); if (!paths || !*paths) { char msg[512]; sprintf(msg, "\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "Warning: XLISP failed to find XLISPPATH in the environment.", "If you are using Nyquist, probably you should cd to the", "nyquist directory and type:", " setenv XLISPPATH `pwd`/runtime:`pwd`/lib", "or set XLISPPATH in your .login or .cshrc file.", "If you use the bash shell, try:", " XLISPPATH=`pwd`/runtime:`pwd`/lib; export XLISPPATH"); errputstr(msg); } return paths; } #endif #ifdef WINDOWS #include "winfun.h" const char *windows_return_xlisp_path() { #define paths_max 1024 static char paths[paths_max]; get_xlisp_path(paths, paths_max); /* make sure we got paths, and the list is not empty */ if (!paths[0]) { sprintf(paths, "\n%s\n%s\n%s\n", "Warning: XLISP failed to find XLISPPATH in the Registry.", "You should follow the installation instructions. Enter an", "empty string if you really want no search path."); errputstr(paths); } return paths; } #endif #ifdef MACINTOSH const char *mac_return_xlisp_path() { #define paths_max 1024 static char paths[paths_max]; int prefs_found = false; get_xlisp_path(paths, paths_max, &prefs_found); if (!paths[0]) { if (prefs_found) { sprintf(paths, "\n%s\n%s\n%s\n", "Warning: XLISP failed to find XLISPPATH in XLisp Preferences.", "You should probably delete XLisp Preferences and let XLisp", "create a new one for you."); } else { sprintf(paths, "\n%s\n%s\n%s\n%s\n%s\n", "Warning: XLISP failed to find XLisp Preferences.", "You should manually locate and load the file runtime:init.lsp", "Nyquist will create an XLisp Preferences file to automatically", "find the file next time. You may edit XLisp Preferences to add", "additional search paths, using a comma as separator."); } errputstr(paths); } return paths; } const char *get_user_id() { // not implemented for MACINTOSH (OS 9), just use "nyquist" return "nyquist"; } #endif const char *return_xlisp_path() { if (g_xlisp_path) return g_xlisp_path; #ifdef WINDOWS return windows_return_xlisp_path(); #endif #ifdef MACINTOSH return mac_return_xlisp_path(); #endif #ifdef UNIX return unix_return_xlisp_path(); #endif } char *g_xlptemp = NULL; // find_in_xlisp_path -- find fname or fname.lsp by searching XLISP_PATH // // NOTE: this module owns the string. The string is valid // until the next call to find_in_xlisp_path() // const char *find_in_xlisp_path(const char *fname) { const char *paths = return_xlisp_path(); if (!paths) return NULL; while (paths && *paths) { FILE *fp; const char *start; int len; /* skip over separator */ while (*paths == os_sepchar || *paths == ';') paths++; /* find next directory */ start = paths; while (*paths && (*paths != os_sepchar && *paths != ';')) paths++; if (g_xlptemp) { free(g_xlptemp); g_xlptemp = NULL; } len = paths - start; g_xlptemp = malloc(len + strlen(fname) + 10); memcpy(g_xlptemp, start, len); if (len == 0) continue; /* add "/" if needed */ if (g_xlptemp[len-1] != os_pathchar) g_xlptemp[len++] = os_pathchar; /* append the file name */ memcpy(&g_xlptemp[len], fname, strlen(fname)); len += strlen(fname); g_xlptemp[len] = 0; /* printf("Attempting to open %s, start is %s\n", g_xlptemp, start); */ fp = osaopen(g_xlptemp, "r"); if (!fp) { /* try appending the .lsp extension */ if (needsextension(g_xlptemp)) { strcat(g_xlptemp, ".lsp"); fp = osaopen(g_xlptemp, "r"); if (!fp) { g_xlptemp[strlen(g_xlptemp) - 4] = 0; /* remove .lsp */ } } } if (fp) { fclose(fp); #ifdef MACINTOSH /* We found the file ok, call setup_preferences to create * XLisp Preferences file (this only happens if previous * attempt to find the file failed */ setup_preferences(g_xlptemp); #endif return g_xlptemp; } } /* It wasn't found */ return NULL; } /* xfind_in_xlisp_path -- search XLISPPATH for file, return full path */ LVAL xfind_in_xlisp_path() { LVAL string = xlgastring(); const char *path = (const char *) getstring(string); xllastarg(); path = find_in_xlisp_path(path); return (path ? cvstring(path) : NULL); } nyquist-3.05/xlisp/xlobj.c0000644000175000000620000003111411466723256014620 0ustar stevestaff/* xlobj - xlisp object functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "xlisp.h" /* external variables */ extern LVAL s_stdout,s_lambda; /* local variables */ static LVAL s_self,k_new,k_isnew; static LVAL class,object; /* instance variable numbers for the class 'Class' */ #define MESSAGES 0 /* list of messages */ #define IVARS 1 /* list of instance variable names */ #define CVARS 2 /* list of class variable names */ #define CVALS 3 /* list of class variable values */ #define SUPERCLASS 4 /* pointer to the superclass */ #define IVARCNT 5 /* number of class instance variables */ #define IVARTOTAL 6 /* total number of instance variables */ /* number of instance variables for the class 'Class' */ #define CLASSSIZE 7 /* forward declarations */ FORWARD LOCAL LVAL entermsg(LVAL cls, LVAL msg); FORWARD LOCAL LVAL xsendmsg(LVAL obj, LVAL cls, LVAL sym); FORWARD LOCAL LVAL evmethod(LVAL obj, LVAL msgcls, LVAL method); FORWARD LOCAL int getivcnt(LVAL cls, int ivar); FORWARD LOCAL int listlength(LVAL list); /* xsend - send a message to an object */ LVAL xsend(void) { LVAL obj; obj = xlgaobject(); return (xsendmsg(obj,getclass(obj),xlgasymbol())); } /* xsendsuper - send a message to the superclass of an object */ LVAL xsendsuper(void) { LVAL env,p; for (env = xlenv; env; env = cdr(env)) if ((p = car(env)) && objectp(car(p))) return (xsendmsg(car(p), getivar(cdr(p),SUPERCLASS), xlgasymbol())); xlfail("not in a method"); return NULL; /* never called */ } /* xlclass - define a class */ LVAL xlclass(char *name, int vcnt) { LVAL sym,cls; /* create the class */ sym = xlenter(name); cls = newobject(class,CLASSSIZE); setvalue(sym,cls); /* set the instance variable counts */ setivar(cls,IVARCNT,cvfixnum((FIXTYPE)vcnt)); setivar(cls,IVARTOTAL,cvfixnum((FIXTYPE)vcnt)); /* set the superclass to 'Object' */ setivar(cls,SUPERCLASS,object); /* return the new class */ return (cls); } /* xladdivar - enter an instance variable */ void xladdivar(LVAL cls, char *var) { setivar(cls,IVARS,cons(xlenter(var),getivar(cls,IVARS))); } /* xladdmsg - add a message to a class */ void xladdmsg(LVAL cls, char *msg, int offset) { extern FUNDEF funtab[]; LVAL mptr; /* enter the message selector */ mptr = entermsg(cls,xlenter(msg)); /* store the method for this message */ rplacd(mptr,cvsubr(funtab[offset].fd_subr,funtab[offset].fd_type,offset)); } /* xlobgetvalue - get the value of an instance variable */ int xlobgetvalue(LVAL pair, LVAL sym, LVAL *pval) { LVAL cls,names; int ivtotal,n; /* find the instance or class variable */ for (cls = cdr(pair); objectp(cls); cls = getivar(cls,SUPERCLASS)) { /* check the instance variables */ names = getivar(cls,IVARS); ivtotal = getivcnt(cls,IVARTOTAL); for (n = ivtotal - getivcnt(cls,IVARCNT); n < ivtotal; ++n) { if (car(names) == sym) { *pval = getivar(car(pair),n); return (TRUE); } names = cdr(names); } /* check the class variables */ names = getivar(cls,CVARS); for (n = 0; consp(names); ++n) { if (car(names) == sym) { *pval = getelement(getivar(cls,CVALS),n); return (TRUE); } names = cdr(names); } } /* variable not found */ return (FALSE); } /* xlobsetvalue - set the value of an instance variable */ int xlobsetvalue(LVAL pair, LVAL sym, LVAL val) { LVAL cls,names; int ivtotal,n; /* find the instance or class variable */ for (cls = cdr(pair); objectp(cls); cls = getivar(cls,SUPERCLASS)) { /* check the instance variables */ names = getivar(cls,IVARS); ivtotal = getivcnt(cls,IVARTOTAL); for (n = ivtotal - getivcnt(cls,IVARCNT); n < ivtotal; ++n) { if (car(names) == sym) { setivar(car(pair),n,val); return (TRUE); } names = cdr(names); } /* check the class variables */ names = getivar(cls,CVARS); for (n = 0; consp(names); ++n) { if (car(names) == sym) { setelement(getivar(cls,CVALS),n,val); return (TRUE); } names = cdr(names); } } /* variable not found */ return (FALSE); } /* obisnew - default 'isnew' method */ LVAL obisnew(void) { LVAL self; self = xlgaobject(); xllastarg(); return (self); } /* obclass - get the class of an object */ LVAL obclass(void) { LVAL self; self = xlgaobject(); xllastarg(); return (getclass(self)); } /* obshow - show the instance variables of an object */ LVAL obshow(void) { LVAL self,fptr,cls,names; int ivtotal,n; /* get self and the file pointer */ self = xlgaobject(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* get the object's class */ cls = getclass(self); /* print the object and class */ xlputstr(fptr,"Object is "); xlprint(fptr,self,TRUE); xlputstr(fptr,", Class is "); xlprint(fptr,cls,TRUE); xlterpri(fptr); /* print the object's instance variables */ for (; cls; cls = getivar(cls,SUPERCLASS)) { names = getivar(cls,IVARS); ivtotal = getivcnt(cls,IVARTOTAL); for (n = ivtotal - getivcnt(cls,IVARCNT); n < ivtotal; ++n) { xlputstr(fptr," "); xlprint(fptr,car(names),TRUE); xlputstr(fptr," = "); xlprint(fptr,getivar(self,n),TRUE); xlterpri(fptr); names = cdr(names); } } /* return the object */ return (self); } /* obisa - does an object inherit from class? */ LVAL obisa(void) { LVAL self, cl, obcl; self = xlgaobject(); cl = xlgaobject(); xllastarg(); obcl = getclass(self); while (obcl) { if (obcl == cl) return s_true; obcl = getivar(obcl, SUPERCLASS); } return NIL; } /* clnew - create a new object instance */ LVAL clnew(void) { LVAL self; self = xlgaobject(); return (newobject(self,getivcnt(self,IVARTOTAL))); } /* clisnew - initialize a new class */ LVAL clisnew(void) { LVAL self,ivars,cvars,super; int n; /* get self, the ivars, cvars and superclass */ self = xlgaobject(); ivars = xlgalist(); cvars = (moreargs() ? xlgalist() : NIL); super = (moreargs() ? xlgaobject() : object); xllastarg(); /* store the instance and class variable lists and the superclass */ setivar(self,IVARS,ivars); setivar(self,CVARS,cvars); setivar(self,CVALS,(cvars ? newvector(listlength(cvars)) : NIL)); setivar(self,SUPERCLASS,super); /* compute the instance variable count */ n = listlength(ivars); setivar(self,IVARCNT,cvfixnum((FIXTYPE)n)); n += getivcnt(super,IVARTOTAL); setivar(self,IVARTOTAL,cvfixnum((FIXTYPE)n)); /* return the new class object */ return (self); } /* clanswer - define a method for answering a message */ LVAL clanswer(void) { LVAL self,msg,fargs,code,mptr; /* message symbol, formal argument list and code */ self = xlgaobject(); msg = xlgasymbol(); fargs = xlgalist(); code = xlgalist(); xllastarg(); /* make a new message list entry */ mptr = entermsg(self,msg); /* setup the message node */ xlprot1(fargs); fargs = cons(s_self,fargs); /* add 'self' as the first argument */ rplacd(mptr,xlclose(msg,s_lambda,fargs,code,NIL,NIL)); xlpop(); /* return the object */ return (self); } /* entermsg - add a message to a class */ LOCAL LVAL entermsg(LVAL cls, LVAL msg) { LVAL lptr,mptr; /* lookup the message */ for (lptr = getivar(cls,MESSAGES); lptr; lptr = cdr(lptr)) if (car(mptr = car(lptr)) == msg) return (mptr); /* allocate a new message entry if one wasn't found */ xlsave1(mptr); mptr = consa(msg); setivar(cls,MESSAGES,cons(mptr,getivar(cls,MESSAGES))); xlpop(); /* return the symbol node */ return (mptr); } /* xsendmsg - send a message to an object */ LOCAL LVAL xsendmsg(LVAL obj, LVAL cls, LVAL sym) { LVAL msg=NULL,msgcls,method,val,p; /* look for the message in the class or superclasses */ for (msgcls = cls; msgcls; ) { /* lookup the message in this class */ for (p = getivar(msgcls,MESSAGES); p; p = cdr(p)) if ((msg = car(p)) && car(msg) == sym) goto send_message; /* look in class's superclass */ msgcls = getivar(msgcls,SUPERCLASS); } /* message not found */ xlerror("no method for this message",sym); send_message: /* insert the value for 'self' (overwrites message selector) */ *--xlargv = obj; ++xlargc; /* invoke the method */ if ((method = cdr(msg)) == NULL) xlerror("bad method",method); switch (ntype(method)) { case SUBR: val = (*getsubr(method))(); break; case CLOSURE: if (gettype(method) != s_lambda) xlerror("bad method",method); val = evmethod(obj,msgcls,method); break; default: xlerror("bad method",method); } /* after creating an object, send it the ":isnew" message */ if (car(msg) == k_new && val) { xlprot1(val); xsendmsg(val,getclass(val),k_isnew); xlpop(); } /* return the result value */ return (val); } /* evmethod - evaluate a method */ LOCAL LVAL evmethod(LVAL obj, LVAL msgcls, LVAL method) { LVAL oldenv,oldfenv,cptr,name,val=NULL; XLCONTEXT cntxt; /* protect some pointers */ xlstkcheck(3); xlsave(oldenv); xlsave(oldfenv); xlsave(cptr); /* create an 'object' stack entry and a new environment frame */ oldenv = xlenv; oldfenv = xlfenv; xlenv = cons(cons(obj,msgcls),closure_getenv(method)); xlenv = xlframe(xlenv); xlfenv = getfenv(method); /* bind the formal parameters */ xlabind(method,xlargc,xlargv); /* setup the implicit block */ if ((name = getname(method))) xlbegin(&cntxt,CF_RETURN,name); /* execute the block */ if (name && setjmp(cntxt.c_jmpbuf)) val = xlvalue; else for (cptr = getbody(method); consp(cptr); cptr = cdr(cptr)) val = xleval(car(cptr)); /* finish the block context */ if (name) xlend(&cntxt); /* restore the environment */ xlenv = oldenv; xlfenv = oldfenv; /* restore the stack */ xlpopn(3); /* return the result value */ return (val); } /* getivcnt - get the number of instance variables for a class */ LOCAL int getivcnt(LVAL cls, int ivar) { LVAL cnt; if ((cnt = getivar(cls,ivar)) == NIL || !fixp(cnt)) xlfail("bad value for instance variable count"); return ((int)getfixnum(cnt)); } /* listlength - find the length of a list */ LOCAL int listlength(LVAL list) { int len; for (len = 0; consp(list); len++) list = cdr(list); return (len); } /* obsymbols - initialize symbols */ void obsymbols(void) { /* enter the object related symbols */ s_self = xlenter("SELF"); k_new = xlenter(":NEW"); k_isnew = xlenter(":ISNEW"); /* get the Object and Class symbol values */ object = getvalue(xlenter("OBJECT")); class = getvalue(xlenter("CLASS")); } /* xloinit - object function initialization routine */ void xloinit(void) { /* create the 'Class' object */ class = xlclass("CLASS",CLASSSIZE); setelement(class,0,class); /* create the 'Object' object */ object = xlclass("OBJECT",0); /* finish initializing 'class' */ setivar(class,SUPERCLASS,object); xladdivar(class,"IVARTOTAL"); /* ivar number 6 */ xladdivar(class,"IVARCNT"); /* ivar number 5 */ xladdivar(class,"SUPERCLASS"); /* ivar number 4 */ xladdivar(class,"CVALS"); /* ivar number 3 */ xladdivar(class,"CVARS"); /* ivar number 2 */ xladdivar(class,"IVARS"); /* ivar number 1 */ xladdivar(class,"MESSAGES"); /* ivar number 0 */ xladdmsg(class,":NEW",FT_CLNEW); xladdmsg(class,":ISNEW",FT_CLISNEW); xladdmsg(class,":ANSWER",FT_CLANSWER); /* finish initializing 'object' */ setivar(object,SUPERCLASS,NIL); xladdmsg(object,":ISNEW",FT_OBISNEW); xladdmsg(object,":CLASS",FT_OBCLASS); xladdmsg(object,":SHOW",FT_OBSHOW); xladdmsg(object,":ISA",FT_OBISA); } nyquist-3.05/xlisp/xlisp.h0000644000175000000620000005766311524127024014651 0ustar stevestaff/* xlisp - a small subset of lisp */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use HISTORY 28-Apr-03 Mazzoni Added declarations for path.c (new file) 30-Mar-88 Dale Amon CMU-CSD Set it up for unix. Picked _TURBOC_ because defs are reasonable. */ /* system specific definitions */ #include /* needed for getenv(); note that this was a problem for PMAX implementation, but I assume PMAX is obsolete now. - RBD 16apr04 */ #include #include #include /* NNODES number of nodes to allocate in each request (1000) */ /* EDEPTH evaluation stack depth (2000) */ /* ADEPTH argument stack depth (1000) */ /* FORWARD type of a forward declaration () */ /* LOCAL type of a local function (static) */ /* AFMT printf format for addresses ("%x") */ /* FIXTYPE data type for fixed point numbers (long) */ /* ITYPE fixed point input conversion routine type (long atol()) */ /* ICNV fixed point input conversion routine (atol) */ /* IFMT printf format for fixed point numbers ("%ld") */ /* FLOTYPE data type for floating point numbers (float) */ /* OFFTYPE number the size of an address (int) */ /* for the Win32 environment */ #ifdef WIN32 #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define SAVERESTORE #define XL_LITTLE_ENDIAN #endif /* for the Turbo C compiler - MS-DOS, large model */ #ifdef _TURBOC_ #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define SAVERESTORE #define XL_LITTLE_ENDIAN #endif /* for the AZTEC C compiler - MS-DOS, large model */ #ifdef AZTEC_LM #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define CVPTR(x) ptrtoabs(x) #define NIL (void *)0 extern long ptrtoabs(); #define SAVERESTORE #define XL_LITTLE_ENDIAN #endif /* for the AZTEC C compiler - Macintosh */ #ifdef AZTEC_MAC #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define NIL (void *)0 #define SAVERESTORE #define XL_BIG_ENDIAN #endif /* for the AZTEC C compiler - Amiga */ #ifdef AZTEC_AMIGA #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define NIL (void *)0 #define SAVERESTORE #define XL_BIG_ENDIAN #endif /* for the Lightspeed C compiler - Macintosh */ #ifdef LSC #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define NIL (void *)0 #define SAVERESTORE #define XL_BIG_ENDIAN #endif /* for the Microsoft C compiler - MS-DOS, large model */ #ifdef MSC #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define XL_LITTLE_ENDIAN #endif /* for the Mark Williams C compiler - Atari ST */ #ifdef MWC #define AFMT "%lx" #define OFFTYPE long #define XL_BIG_ENDIAN #endif /* for the Lattice C compiler - Atari ST */ #ifdef LATTICE #define FIXTYPE int #define ITYPE int atoi() #define ICNV(n) atoi(n) #define IFMT "%d" #define XL_BIG_ENDIAN #endif /* for the Digital Research C compiler - Atari ST */ #ifdef DR #define LOCAL #define AFMT "%lx" #define OFFTYPE long #undef NULL #define NULL 0L #define XL_BIG_ENDIAN #endif /* Mac Metrowerks CW 6 */ #ifdef __MWERKS__ #define LSC #undef PATHNAMES #undef FILETABLE #undef SAVERESTORE #undef MEDMEM #define EDEPTH 4000 #define ADEPTH 3000 #define OSAOPEN osaopen #define OSBOPEN osbopen #define NO_EXTENSIONS /* don't add ".lsp" onto filenames */ #define XL_BIG_ENDIAN #endif /* Linux on Pentium */ #if defined(__linux__) || defined(__GLIBC__) #include #if __BYTE_ORDER == __LITTLE_ENDIAN #define XL_LITTLE_ENDIAN #else #define XL_BIG_ENDIAN #endif #endif /* Apple CC */ #ifdef __APPLE__ #define NNODES 2000 #define AFMT "%lx" #define OFFTYPE long #define NIL (void *)0 #define SAVERESTORE #include /* #if __BYTE_ORDER == __LITTLE_ENDIAN */ #if defined(__LITTLE_ENDIAN__) #define XL_LITTLE_ENDIAN #else #define XL_BIG_ENDIAN #endif #endif /* default important definitions */ #ifndef NNODES #define NNODES 1000 #endif #ifndef NTYPES #define NTYPES 20 #endif #ifndef EDEPTH /* originally was 2000 */ #define EDEPTH 4000 #endif #ifndef ADEPTH /* originally was 1000 */ #define ADEPTH 2000 #endif #ifndef FORWARD #define FORWARD #endif #ifndef LOCAL #define LOCAL static #endif #ifndef AFMT #define AFMT "%x" #endif #ifndef FIXTYPE #define FIXTYPE long #endif #ifndef ITYPE #ifndef atol /* if atol is a macro, this will mess things up */ #define ITYPE long atol() #endif #endif #ifndef ICNV #define ICNV(n) atol(n) #endif #ifndef IFMT #define IFMT "%ld" #endif #ifndef FLOTYPE #define FLOTYPE double #endif #ifndef OFFTYPE #define OFFTYPE int #endif #ifndef CVPTR #define CVPTR(x) (x) #endif #ifndef UCHAR #define UCHAR unsigned char #endif #ifndef STDERR #define STDERR stderr #endif /* useful definitions */ #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define externp(x) ((x) && ntype(x) == EXTERN) #ifndef NIL #define NIL (LVAL )0 #endif /* include the dynamic memory definitions */ #include "xldmem.h" /* program limits */ #define STRMAX 250 /* maximum length of a string constant */ /* this was 100 -- I had a perfectly good full path to init.lsp using a directory structure created by Apple's Xcode that was about 108 characters, so I picked a bigger value. -RBD */ #define HSIZE 1499 /* symbol hash table size */ #define SAMPLE 1000 /* control character sample rate */ /* function table offsets for the initialization functions */ #define FT_RMHASH 0 #define FT_RMQUOTE 1 #define FT_RMDQUOTE 2 #define FT_RMBQUOTE 3 #define FT_RMCOMMA 4 #define FT_RMLPAR 5 #define FT_RMRPAR 6 #define FT_RMSEMI 7 #define FT_CLNEW 10 #define FT_CLISNEW 11 #define FT_CLANSWER 12 #define FT_OBISNEW 13 #define FT_OBCLASS 14 #define FT_OBSHOW 15 #define FT_OBISA 16 /* macro to push a value onto the argument stack */ #define pusharg(x) {if (xlsp >= xlargstktop) xlargstkoverflow();\ *xlsp++ = (x);} /* #define DEBUG_GC */ /* macros to protect pointers */ #ifdef DEBUG_GC void dbg_gc_xlsave(LVAL *n); #define xlstkcheck(n) {if (xlstack - (n) < xlstkbase) xlstkoverflow();} #define xlsave(n) {*--xlstack = &n; n = NIL; dbg_gc_xlsave(&n);} #define xlprotect(n) {*--xlstack = &n; dbg_gc_xlsave(&n);} /* check the stack and protect a single pointer */ #define xlsave1(n) {if (xlstack <= xlstkbase) xlstkoverflow();\ *--xlstack = &n; n = NIL; dbg_gc_xlsave(&n);} #define xlprot1(n) {if (xlstack <= xlstkbase) xlstkoverflow();\ *--xlstack = &n; dbg_gc_xlsave(&n);} /* macros to pop pointers off the stack */ #define xlpop() {++xlstack;} #define xlpopn(n) {xlstack+=(n);} #else #define xlstkcheck(n) {if (xlstack - (n) < xlstkbase) xlstkoverflow();} #define xlsave(n) {*--xlstack = &n; n = NIL;} #define xlprotect(n) {*--xlstack = &n;} /* check the stack and protect a single pointer */ #define xlsave1(n) {if (xlstack <= xlstkbase) xlstkoverflow();\ *--xlstack = &n; n = NIL;} #define xlprot1(n) {if (xlstack <= xlstkbase) xlstkoverflow();\ *--xlstack = &n;} /* macros to pop pointers off the stack */ #define xlpop() {++xlstack;} #define xlpopn(n) {xlstack+=(n);} #endif /* macros to manipulate the lexical environment */ #define xlframe(e) cons(NIL,e) #define xlbind(s,v) xlpbind(s,v,xlenv) #define xlfbind(s,v) xlpbind(s,v,xlfenv); #define xlpbind(s,v,e) {rplaca(e,cons(cons(s,v),car(e)));} /* macros to manipulate the dynamic environment */ #define xldbind(s,v) {xldenv = cons(cons(s,getvalue(s)),xldenv);\ setvalue(s,v);} #define xlunbind(e) {for (; xldenv != (e); xldenv = cdr(xldenv))\ setvalue(car(car(xldenv)),cdr(car(xldenv)));} /* type predicates */ #define atomp(x) ((x) == NIL || ntype(x) != CONS) #define null(x) ((x) == NIL) #define listp(x) ((x) == NIL || ntype(x) == CONS) #define consp(x) ((x) && ntype(x) == CONS) #define subrp(x) ((x) && ntype(x) == SUBR) #define fsubrp(x) ((x) && ntype(x) == FSUBR) #define stringp(x) ((x) && ntype(x) == STRING) #define symbolp(x) ((x) && ntype(x) == SYMBOL) #define streamp(x) ((x) && ntype(x) == STREAM) #define objectp(x) ((x) && ntype(x) == OBJECT) #define fixp(x) ((x) && ntype(x) == FIXNUM) #define floatp(x) ((x) && ntype(x) == FLONUM) #define vectorp(x) ((x) && ntype(x) == VECTOR) #define closurep(x) ((x) && ntype(x) == CLOSURE) #define charp(x) ((x) && ntype(x) == CHAR) #define ustreamp(x) ((x) && ntype(x) == USTREAM) #define boundp(x) (getvalue(x) != s_unbound) #define fboundp(x) (getfunction(x) != s_unbound) /* shorthand functions */ #define consa(x) cons(x,NIL) #define consd(x) cons(NIL,x) /* argument list parsing macros */ #define xlgetarg() (testarg(nextarg())) #define xllastarg() {if (xlargc != 0) xltoomany();} #define testarg(e) (moreargs() ? (e) : xltoofew()) #define typearg(tp) (tp(*xlargv) ? nextarg() : xlbadtype(*xlargv)) #define nextarg() (--xlargc, *xlargv++) #define moreargs() (xlargc > 0) /* macros to get arguments of a particular type */ #define xlgacons() (testarg(typearg(consp))) #define xlgalist() (testarg(typearg(listp))) #define xlgasymbol() (testarg(typearg(symbolp))) #define xlgastring() (testarg(typearg(stringp))) #define xlgaobject() (testarg(typearg(objectp))) #define xlgafixnum() (testarg(typearg(fixp))) #define xlgaflonum() (testarg(typearg(floatp))) #define xlgachar() (testarg(typearg(charp))) #define xlgavector() (testarg(typearg(vectorp))) #define xlgastream() (testarg(typearg(streamp))) #define xlgaustream() (testarg(typearg(ustreamp))) #define xlgaclosure() (testarg(typearg(closurep))) /* function definition structure */ typedef struct { char *fd_name; /* function name */ int fd_type; /* function type */ LVAL (*fd_subr)(void); /* function entry point */ } FUNDEF; /* execution context flags */ #define CF_GO 0x0001 #define CF_RETURN 0x0002 #define CF_THROW 0x0004 #define CF_ERROR 0x0008 #define CF_CLEANUP 0x0010 #define CF_CONTINUE 0x0020 #define CF_TOPLEVEL 0x0040 #define CF_BRKLEVEL 0x0080 #define CF_UNWIND 0x0100 /* execution context */ typedef struct context { int c_flags; /* context type flags */ LVAL c_expr; /* expression (type dependant) */ jmp_buf c_jmpbuf; /* longjmp context */ struct context *c_xlcontext; /* old value of xlcontext */ LVAL **c_xlstack; /* old value of xlstack */ LVAL *c_xlargv; /* old value of xlargv */ int c_xlargc; /* old value of xlargc */ LVAL *c_xlfp; /* old value of xlfp */ LVAL *c_xlsp; /* old value of xlsp */ LVAL c_xlenv; /* old value of xlenv */ LVAL c_xlfenv; /* old value of xlfenv */ LVAL c_xldenv; /* old value of xldenv */ } XLCONTEXT; /* external variables */ extern LVAL **xlstktop; /* top of the evaluation stack */ extern LVAL **xlstkbase; /* base of the evaluation stack */ extern LVAL **xlstack; /* evaluation stack pointer */ extern LVAL *xlargstkbase; /* base of the argument stack */ extern LVAL *xlargstktop; /* top of the argument stack */ extern LVAL *xlfp; /* argument frame pointer */ extern LVAL *xlsp; /* argument stack pointer */ extern LVAL *xlargv; /* current argument vector */ extern int xlargc; /* current argument count */ /* more external variables */ extern LVAL xlenv,xlfenv,xldenv,xlvalue,s_true; extern LVAL lk_optional,lk_rest,lk_key,lk_aux,lk_allow_other_keys; extern LVAL s_evalhook,s_applyhook,s_tracelist; extern LVAL s_lambda,s_macro; extern LVAL s_unbound; extern int xlsample; extern char buf[]; extern LVAL obarray,s_gcflag,s_gchook; extern int xldebug; extern LVAL s_debugio; extern LVAL s_tracenable,s_tlimit,s_breakenable; extern LVAL s_loadingfiles; extern LVAL k_direction,k_input,k_output; extern LVAL s_stdin,s_stdout; extern int xlfsize; /* external variables */ extern LVAL s_car,s_cdr,s_nth,s_get,s_svalue,s_splist,s_aref; extern LVAL s_comma,s_comat; extern char gsprefix[]; extern int gsnumber; /* additional prototypes */ extern FILE *osaopen (char *name, char *mode); extern FILE *osbopen (char *name, char *mode); #ifdef __MWERKS__ /* macfun.c */ LVAL xptsize(void); LVAL xhidepen(void); LVAL xshowpen(void); LVAL xgetpen(void); LVAL xpenmode(void); LVAL xpensize(void); LVAL xpenpat(void); LVAL xpennormal(void); LVAL xmoveto(void); LVAL xmove(void); LVAL xdrawto(void); LVAL xdraw(void); LVAL xshowgraphics(void); LVAL xhidegraphics(void); LVAL xcleargraphics(void); LVAL xtool(void); LVAL xtool16(void); LVAL xtool32(void); LVAL xnewhandle(void); LVAL xnewptr(void); LVAL xhiword(void); LVAL xloword(void); LVAL xrdnohang(void); /* #include "macstuff.h" */ #endif /* for extern.c */ void inval_caches(void); /* for xlbfun.c */ LVAL xeval(void); LVAL xapply(void); LVAL xfuncall(void); LVAL xmacroexpand(void); LVAL x1macroexpand(void); LVAL xatom(void); LVAL xsymbolp(void); LVAL xnumberp(void); LVAL xintegerp(void); LVAL xfloatp(void); LVAL xcharp(void); LVAL xstringp(void); LVAL xarrayp(void); LVAL xstreamp(void); LVAL xobjectp(void); LVAL xboundp(void); LVAL xfboundp(void); LVAL xnull(void); LVAL xlistp(void); LVAL xendp(void); LVAL xconsp(void); LVAL xeq(void); LVAL xeql(void); LVAL xequal(void); LVAL xset(void); LVAL xgensym(void); LVAL xmakesymbol(void); LVAL xintern(void); LVAL xsymname(void); LVAL xsymvalue(void); LVAL xsymfunction(void); LVAL xsymplist(void); LVAL xget(void); LVAL xputprop(void); LVAL xremprop(void); LVAL xhash(void); LVAL xaref(void); LVAL xmkarray(void); LVAL xvector(void); LVAL xerror(void); LVAL xcerror(void); LVAL xbreak(void); LVAL xcleanup(void); LVAL xtoplevel(void); LVAL xcontinue(void); LVAL xevalhook(void); /* xlcont.c */ LVAL xquote(void); LVAL xfunction(void); LVAL xbquote(void); LVAL xlambda(void); LVAL xgetlambda(void); LVAL xsetq(void); LVAL xpsetq(void); LVAL xsetf(void); LVAL xdefun(void); LVAL xdefmacro(void); LVAL xcond(void); LVAL xwhen(void); LVAL xunless(void); LVAL xcase(void); LVAL xand(void); LVAL x_or(void); // xor causes problems for gcc, so I renamed it. -RBD LVAL xif(void); LVAL xlet(void); LVAL xletstar(void); LVAL xflet(void); LVAL xlabels(void); LVAL xmacrolet(void); LVAL xprog(void); LVAL xprogstar(void); LVAL xgo(void); LVAL xreturn(void); LVAL xrtnfrom(void); LVAL xprog1(void); LVAL xprog2(void); LVAL xprogn(void); LVAL xprogv(void); LVAL xloop(void); LVAL xdo(void); LVAL xdostar(void); LVAL xdolist(void); LVAL xdotimes(void); LVAL xblock(void); LVAL xtagbody(void); LVAL xcatch(void); LVAL xthrow(void); LVAL xunwindprotect(void); LVAL xerrset(void); LVAL xtrace(void); LVAL xuntrace(void); /* xldbug.c */ void xlabort(char *emsg); void xlbreak(char *emsg, LVAL arg); void xlfail(char *emsg); void xlerror(char *emsg, LVAL arg); void xlcerror(char *cmsg, char *emsg, LVAL arg); void xlerrprint(char *hdr, char *cmsg, char *emsg, LVAL arg); void xlbaktrace(int n); void xldinit(void); void close_loadingfiles(void); /* xldmem.c */ LVAL cons(LVAL x, LVAL y); LVAL cvstring(const char *str); LVAL new_string(int size); LVAL cvsymbol(char *pname); LVAL cvsubr(LVAL (*fcn)(void), int type, int offset); LVAL cvfile(FILE *fp); LVAL cvfixnum(FIXTYPE n); LVAL cvflonum(FLOTYPE n); LVAL cvchar(int n); LVAL newustream(void); LVAL newobject(LVAL cls, int size); LVAL newclosure(LVAL name, LVAL type, LVAL env, LVAL fenv); LVAL newvector(int size); void gc(void); SEGMENT *newsegment(int n); LVAL xgc(void); LVAL xexpand(void); LVAL xalloc(void); LVAL xmem(void); LVAL xsave(void); LVAL xrestore(void); void xlminit(void); LVAL cvextern(xtype_desc typeptr, unsigned char *instptr); /* convert an external type */ LVAL newnode(int type); void mark(LVAL ptr); /* xleval.c */ LVAL xleval(LVAL expr); LVAL xlxeval(LVAL expr); LVAL xlapply(int argc); LVAL xlexpandmacros(LVAL form); int macroexpand(LVAL fun, LVAL args, LVAL *pval); int pushargs(LVAL fun, LVAL args); LVAL makearglist(int argc, LVAL *argv); LVAL xlclose(LVAL name, LVAL type, LVAL fargs, LVAL body, LVAL env, LVAL fenv); void xlabind(LVAL fun, int argc, LVAL *argv); void xlunbound(LVAL sym); void xlfunbound(LVAL sym); void xlstkoverflow(void); void xlargstkoverflow(void); /* xlfio.c */ LVAL xread(void); LVAL xprint(void); LVAL xprin1(void); LVAL xprinc(void); LVAL xterpri(void); LVAL xflatsize(void); LVAL xflatc(void); LVAL xopen(void); LVAL xbopen(void); LVAL xclose(void); LVAL xrdchar(void); LVAL xrdbyte(void); LVAL xpkchar(void); LVAL xwrchar(void); LVAL xwrbyte(void); LVAL xrdint(void); LVAL xwrint(void); LVAL xrdfloat(void); LVAL xwrfloat(void); LVAL xreadline(void); LVAL xmkstrinput(void); LVAL xmkstroutput(void); LVAL xgetstroutput(void); LVAL xgetlstoutput(void); LVAL xformat(void); LVAL xlistdir(void); /* xlimage.c */ int xlisave(char *fname); int xlirestore(char *fname); /* xlinit.c */ void xlinit(void); void xlsymbols(void); /* xlio.c */ int xlgetc(LVAL fptr); void xlungetc(LVAL fptr, int ch); int xlpeek(LVAL fptr); void xlputc(LVAL fptr, int ch); void xloutflush(LVAL fptr); void xlflush(void); void stdprint(LVAL expr); void stdputstr(char *str); void stdflush(void); void errprint(LVAL expr); void errputstr(char *str); void dbgprint(LVAL expr); void dbgputstr(char *str); void trcprin1(LVAL expr); void trcputstr(char *str); /* xlisp.c */ long xlrand(long range); double xlrealrand(void); void xlrdsave(LVAL expr); void xlevsave(LVAL expr); void xlfatal(char *msg); void xlisp_main_init(int, char **); void xlisp_main(void); void xlisp_wrapup(void); /* xljump.c */ void xlbegin(XLCONTEXT *cptr, int flags, LVAL expr); void xlend(XLCONTEXT *cptr); void xlgo(LVAL label); void xlreturn(LVAL name, LVAL val); void xlthrow(LVAL tag, LVAL val); void xlsignal(char *emsg, LVAL arg); void xltoplevel(void); void xlbrklevel(void); void xlcleanup(void); void xlcontinue(void); void xljump(XLCONTEXT *target, int mask, LVAL val); /* xllist.c */ LVAL xcar(void); LVAL xcdr(void); LVAL xcaar(void); LVAL xcadr(void); LVAL xcdar(void); LVAL xcddr(void); LVAL xcaaar(void); LVAL xcaadr(void); LVAL xcadar(void); LVAL xcaddr(void); LVAL xcdaar(void); LVAL xcdadr(void); LVAL xcddar(void); LVAL xcdddr(void); /* cxxxxr functions */ LVAL xcaaaar(void); LVAL xcaaadr(void); LVAL xcaadar(void); LVAL xcaaddr(void); LVAL xcadaar(void); LVAL xcadadr(void); LVAL xcaddar(void); LVAL xcadddr(void); LVAL xcdaaar(void); LVAL xcdaadr(void); LVAL xcdadar(void); LVAL xcdaddr(void); LVAL xcddaar(void); LVAL xcddadr(void); LVAL xcdddar(void); LVAL xcddddr(void); LVAL xcons(void); LVAL xlist(void); LVAL xappend(void); LVAL xreverse(void); LVAL xlast(void); LVAL xmember(void); LVAL xassoc(void); LVAL xsubst(void); LVAL xsublis(void); LVAL xremove(void); LVAL xremif(void); LVAL xremifnot(void); int dotest1(LVAL arg, LVAL fun); int dotest2(LVAL arg1, LVAL arg2, LVAL fun); LVAL xnth(void); LVAL xnthcdr(void); LVAL xlength(void); LVAL xmapc(void); LVAL xmapcar(void); LVAL xmapl(void); LVAL xmaplist(void); LVAL xrplca(void); LVAL xrplcd(void); LVAL xnconc(void); LVAL xdelete(void); LVAL xdelif(void); LVAL xdelifnot(void); LVAL xsort(void); /* xlmath.c */ LVAL xadd(void); LVAL xsub(void); LVAL xmul(void); LVAL xdiv(void); LVAL xrem(void); LVAL xmin(void); LVAL xmax(void); LVAL xexpt(void); LVAL xlogand(void); LVAL xlogior(void); LVAL xlogxor(void); LVAL xgcd(void); void checkizero(FIXTYPE iarg); void checkfzero(FLOTYPE farg); void checkfneg(FLOTYPE farg); LVAL xlognot(void); LVAL xabs(void); LVAL xadd1(void); LVAL xsub1(void); LVAL xsin(void); LVAL xcos(void); LVAL xtan(void); LVAL xexp(void); LVAL xsqrt(void); LVAL xfix(void); LVAL xfloat(void); LVAL xrand(void); LVAL xminusp(void); LVAL xzerop(void); LVAL xplusp(void); LVAL xevenp(void); LVAL xoddp(void); LVAL xlss(void); LVAL xleq(void); LVAL xequ(void); LVAL xneq(void); LVAL xgeq(void); LVAL xgtr(void); /* xlobj.c */ LVAL xsend(void); LVAL xsendsuper(void); LVAL xlclass(char *name, int vcnt); void xladdivar(LVAL cls, char *var); void xladdmsg(LVAL cls, char *msg, int offset); int xlobgetvalue(LVAL pair, LVAL sym, LVAL *pval); int xlobsetvalue(LVAL pair, LVAL sym, LVAL val); LVAL obisnew(void); LVAL obclass(void); LVAL obshow(void); LVAL obisa(void); LVAL clnew(void); LVAL clisnew(void); LVAL clanswer(void); void obsymbols(void); void xloinit(void); /* xlpp.c */ LVAL xpp(void); /* xlprin.c */ void xlprint(LVAL fptr, LVAL vptr, int flag); void xlterpri(LVAL fptr); void xlputstr(LVAL fptr, char *str); void putatm(LVAL fptr, char *tag, LVAL val); /* xlread.c */ int xlload(char *fname, int vflag, int pflag); int xlread(LVAL fptr, LVAL *pval, int rflag); int readone(LVAL fptr, LVAL *pval); LVAL rmhash(void); LVAL rmquote(void); LVAL rmdquote(void); LVAL rmbquote(void); LVAL rmcomma(void); LVAL rmlpar(void); LVAL rmrpar(void); LVAL rmsemi(void); LVAL tentry(int ch); int xlisnumber(char *str, LVAL *pval); void defmacro(int ch, LVAL type, int offset); LVAL callmacro(LVAL fptr, int ch); void xlrinit(void); /* xlstr.c */ LVAL xstrlss(void); LVAL xstrleq(void); LVAL xstreql(void); LVAL xstrneq(void); LVAL xstrgeq(void); LVAL xstrgtr(void); LVAL xstrilss(void); LVAL xstrileq(void); LVAL xstrieql(void); LVAL xstrineq(void); LVAL xstrigeq(void); LVAL xstrigtr(void); LVAL xupcase(void); LVAL xdowncase(void); LVAL xnupcase(void); LVAL xndowncase(void); LVAL xstrsearch(void); LVAL xtrim(void); LVAL xlefttrim(void); LVAL xrighttrim(void); LVAL xstrcat(void); LVAL xsubseq(void); LVAL xstring(void); LVAL xchar(void); LVAL xcharint(void); LVAL xintchar(void); LVAL xuppercasep(void); LVAL xlowercasep(void); LVAL xbothcasep(void); LVAL xdigitp(void); LVAL xcharcode(void); LVAL xcodechar(void); LVAL xchupcase(void); LVAL xchdowncase(void); LVAL xdigitchar(void); LVAL xalphanumericp(void); LVAL xchrlss(void); LVAL xchrleq(void); LVAL xchreql(void); LVAL xchrneq(void); LVAL xchrgeq(void); LVAL xchrgtr(void); LVAL xchrilss(void); LVAL xchrileq(void); LVAL xchrieql(void); LVAL xchrineq(void); LVAL xchrigeq(void); LVAL xchrigtr(void); LVAL xinfo(void); /* xlsubr.c */ LVAL xlsubr(char *sname, int type, LVAL (*fcn)(void), int offset); int xlgetkeyarg(LVAL key, LVAL *pval); void xltest(LVAL *pfcn, int *ptresult); int xlgkfixnum(LVAL key, LVAL *pval); /* argument list parsing functions */ extern LVAL xlgetfile(void); /* get a file/stream argument */ extern LVAL xlgetfname(void); /* get a filename argument */ int needsextension(char *name); /* error reporting functions (don't *really* return at all) */ extern LVAL xlbadtype(LVAL arg); /* report "bad argument type" error */ extern LVAL xltoofew(void); /* report "too few arguments" error */ extern LVAL xltoomany(void); int eq(LVAL arg1, LVAL arg2); int eql(LVAL arg1, LVAL arg2); int lval_equal(LVAL arg1, LVAL arg2); /* xlsym.c */ LVAL xlenter(char *name); /* enter a symbol */ LVAL xlmakesym(char *name); /* make an uninterned symbol */ LVAL xlgetvalue(LVAL sym); /* get value of a symbol (checked) */ LVAL xlxgetvalue(LVAL sym); /* get value of a symbol */ void xlsetvalue(LVAL sym, LVAL val); LVAL xlgetfunction(LVAL sym); /* get functional value of a symbol */ LVAL xlxgetfunction(LVAL sym); /* get functional value of a symbol (checked) */ void xlsetfunction(LVAL sym, LVAL val); LVAL xlgetprop(LVAL sym, LVAL prp); void xlputprop(LVAL sym, LVAL val, LVAL prp); void xlremprop(LVAL sym, LVAL prp); int hash(char *str, int len); void xlsinit(void); LVAL findprop(LVAL sym, LVAL prp); /* xlsys.c */ LVAL xget_env(void); LVAL xload(void); LVAL xtranscript(void); LVAL xtype(void); LVAL xbaktrace(void); LVAL xexit(void); LVAL xpeek(void); LVAL xpoke(void); LVAL xaddrs(void); /* macstuff, unixstuff, winstuff */ extern const char os_pathchar; extern const char os_sepchar; void osinit(char *banner); void oserror(char *msg); void osfinish(void); int osclose(FILE *fp); void osflush(void); void oscheck(void); int osaputc(int ch, FILE *fp); void osoutflush(FILE *fp); int osbputc(int ch, FILE *fp); void ostputc(int ch); void ostoutflush(void); int osagetc(FILE *fp); int osbgetc(FILE *fp); int ostgetc(void); void ossymbols(void); LVAL xlinfo(void); LVAL xsetdir(void); int osdir_list_start(char *path); char *osdir_list_next(void); void osdir_list_finish(void); LVAL xosc_enable(void); LVAL xget_temp_path(void); LVAL xfind_in_xlisp_path(void); /* These are now implemented in path.c -dmazzoni */ const char *return_xlisp_path(void); const char *find_in_xlisp_path(const char *fname); void set_xlisp_path(const char *p); /* local.c - these procedures are specific to each implementation */ void localinit(void); void localsymbols(void); void print_local_gc_info(void); nyquist-3.05/xlisp/osptrs.h0000644000175000000620000000015310144436365015032 0ustar stevestaff/* osptrs.h - system specific function pointers */ { "SYSTEM", S, xsystem }, { "GET-KEY", S, xgetkey }, nyquist-3.05/xlisp/xlcont.c0000644000175000000620000007565511471407277015031 0ustar stevestaff/* xlcont - xlisp special forms */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "xlisp.h" /* external variables */ extern LVAL xlvalue; extern LVAL s_setf,s_car,s_cdr,s_nth,s_aref,s_get; extern LVAL s_svalue,s_sfunction,s_splist; extern LVAL s_lambda,s_macro; /* forward declarations */ FORWARD LOCAL LVAL bquote1(LVAL expr); FORWARD LOCAL void placeform(LVAL place, LVAL value); FORWARD LOCAL LVAL let(int pflag); FORWARD LOCAL LVAL flet(LVAL type, int letflag); FORWARD LOCAL LVAL prog(int pflag); FORWARD LOCAL LVAL progx(int n); FORWARD LOCAL LVAL doloop(int pflag); FORWARD LOCAL LVAL evarg(LVAL *pargs); FORWARD LOCAL LVAL match(int type, LVAL *pargs); FORWARD LOCAL LVAL evmatch(int type, LVAL *pargs); FORWARD LOCAL void toofew(LVAL args); FORWARD LOCAL void toomany(LVAL args); FORWARD LOCAL void setffunction(LVAL fun, LVAL place, LVAL value); FORWARD LOCAL int keypresent(LVAL key, LVAL list); FORWARD LOCAL void dobindings(LVAL list, LVAL env); FORWARD LOCAL void tagbody(void); FORWARD LOCAL void doupdates(LVAL list, int pflag); /* dummy node type for a list */ #define LIST -1 /* xquote - special form 'quote' */ LVAL xquote(void) { LVAL val; val = xlgetarg(); xllastarg(); return (val); } /* xfunction - special form 'function' */ LVAL xfunction(void) { LVAL val; /* get the argument */ val = xlgetarg(); xllastarg(); /* create a closure for lambda expressions */ if (consp(val) && car(val) == s_lambda && consp(cdr(val))) val = xlclose(NIL,s_lambda,car(cdr(val)),cdr(cdr(val)),xlenv,xlfenv); /* otherwise, get the value of a symbol */ else if (symbolp(val)) val = xlgetfunction(val); /* otherwise, its an error */ else xlerror("not a function",val); /* return the function */ return (val); } /* xbquote - back quote special form */ LVAL xbquote(void) { LVAL expr; /* get the expression */ expr = xlgetarg(); xllastarg(); /* fill in the template */ return (bquote1(expr)); } /* bquote1 - back quote helper function */ LOCAL LVAL bquote1(LVAL expr) { LVAL val,list,last,new; /* handle atoms */ if (atomp(expr)) val = expr; /* handle (comma ) */ else if (car(expr) == s_comma) { if (atomp(cdr(expr))) xlfail("bad comma expression"); val = xleval(car(cdr(expr))); } /* handle ((comma-at ) ... ) */ else if (consp(car(expr)) && car(car(expr)) == s_comat) { xlstkcheck(2); xlsave(list); xlsave(val); if (atomp(cdr(car(expr)))) xlfail("bad comma-at expression"); list = xleval(car(cdr(car(expr)))); for (last = NIL; consp(list); list = cdr(list)) { new = consa(car(list)); if (last) rplacd(last,new); else val = new; last = new; } if (last) rplacd(last,bquote1(cdr(expr))); else val = bquote1(cdr(expr)); xlpopn(2); } /* handle any other list */ else { xlsave1(val); val = consa(NIL); rplaca(val,bquote1(car(expr))); rplacd(val,bquote1(cdr(expr))); xlpop(); } /* return the result */ return (val); } /* xlambda - special form 'lambda' */ LVAL xlambda(void) { LVAL fargs,arglist,val; /* get the formal argument list and function body */ xlsave1(arglist); fargs = xlgalist(); arglist = makearglist(xlargc,xlargv); /* create a new function definition */ val = xlclose(NIL,s_lambda,fargs,arglist,xlenv,xlfenv); /* restore the stack and return the closure */ xlpop(); return (val); } /* xgetlambda - get the lambda expression associated with a closure */ LVAL xgetlambda(void) { LVAL closure; closure = xlgaclosure(); return (cons(gettype(closure), cons(getlambda(closure),getbody(closure)))); } /* xsetq - special form 'setq' */ LVAL xsetq(void) { LVAL sym,val; /* handle each pair of arguments */ for (val = NIL; moreargs(); ) { sym = xlgasymbol(); val = xleval(nextarg()); xlsetvalue(sym,val); } /* return the result value */ return (val); } /* xpsetq - special form 'psetq' */ LVAL xpsetq(void) { LVAL plist,sym,val; /* protect some pointers */ xlsave1(plist); /* handle each pair of arguments */ for (val = NIL; moreargs(); ) { sym = xlgasymbol(); val = xleval(nextarg()); plist = cons(cons(sym,val),plist); } /* do parallel sets */ for (; plist; plist = cdr(plist)) xlsetvalue(car(car(plist)),cdr(car(plist))); /* restore the stack */ xlpop(); /* return the result value */ return (val); } /* xsetf - special form 'setf' */ LVAL xsetf(void) { LVAL place,value; /* protect some pointers */ xlsave1(value); /* handle each pair of arguments */ while (moreargs()) { /* get place and value */ place = xlgetarg(); value = xleval(nextarg()); /* expand macros in the place form */ if (consp(place)) place = xlexpandmacros(place); /* check the place form */ if (symbolp(place)) xlsetvalue(place,value); else if (consp(place)) placeform(place,value); else xlfail("bad place form"); } /* restore the stack */ xlpop(); /* return the value */ return (value); } /* placeform - handle a place form other than a symbol */ LOCAL void placeform(LVAL place, LVAL value) { LVAL fun,arg1,arg2; int i; /* check the function name */ if ((fun = match(SYMBOL,&place)) == s_get) { xlstkcheck(2); xlsave(arg1); xlsave(arg2); arg1 = evmatch(SYMBOL,&place); arg2 = evmatch(SYMBOL,&place); if (place) toomany(place); xlputprop(arg1,value,arg2); xlpopn(2); } else if (fun == s_svalue) { arg1 = evmatch(SYMBOL,&place); if (place) toomany(place); setvalue(arg1,value); } else if (fun == s_sfunction) { arg1 = evmatch(SYMBOL,&place); if (place) toomany(place); setfunction(arg1,value); } else if (fun == s_splist) { arg1 = evmatch(SYMBOL,&place); if (place) toomany(place); setplist(arg1,value); } else if (fun == s_car) { arg1 = evmatch(CONS,&place); if (place) toomany(place); rplaca(arg1,value); } else if (fun == s_cdr) { arg1 = evmatch(CONS,&place); if (place) toomany(place); rplacd(arg1,value); } else if (fun == s_nth) { xlsave1(arg1); arg1 = evmatch(FIXNUM,&place); arg2 = evmatch(LIST,&place); if (place) toomany(place); for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i) arg2 = cdr(arg2); if (consp(arg2)) rplaca(arg2,value); xlpop(); } else if (fun == s_aref) { xlsave1(arg1); arg1 = evmatch(VECTOR,&place); arg2 = evmatch(FIXNUM,&place); i = (int)getfixnum(arg2); if (place) toomany(place); if (i < 0 || i >= getsize(arg1)) xlerror("index out of range",arg2); setelement(arg1,i,value); xlpop(); } else if ((fun = xlgetprop(fun,s_setf))) setffunction(fun,place,value); else xlfail("bad place form"); } /* setffunction - call a user defined setf function */ LOCAL void setffunction(LVAL fun, LVAL place, LVAL value) { LVAL *newfp; int argc; /* create the new call frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(NIL); /* push the values of all of the place expressions and the new value */ for (argc = 1; consp(place); place = cdr(place), ++argc) pusharg(xleval(car(place))); pusharg(value); /* insert the argument count and establish the call frame */ newfp[2] = cvfixnum((FIXTYPE)argc); xlfp = newfp; /* apply the function */ xlapply(argc); } /* xdefun - special form 'defun' */ LVAL xdefun(void) { LVAL sym,fargs,arglist; /* get the function symbol and formal argument list */ xlsave1(arglist); sym = xlgasymbol(); fargs = xlgalist(); arglist = makearglist(xlargc,xlargv); /* make the symbol point to a new function definition */ xlsetfunction(sym,xlclose(sym,s_lambda,fargs,arglist,xlenv,xlfenv)); /* restore the stack and return the function symbol */ xlpop(); return (sym); } /* xdefmacro - special form 'defmacro' */ LVAL xdefmacro(void) { LVAL sym,fargs,arglist; /* get the function symbol and formal argument list */ xlsave1(arglist); sym = xlgasymbol(); fargs = xlgalist(); arglist = makearglist(xlargc,xlargv); /* make the symbol point to a new function definition */ xlsetfunction(sym,xlclose(sym,s_macro,fargs,arglist,NIL,NIL)); /* restore the stack and return the function symbol */ xlpop(); return (sym); } /* xcond - special form 'cond' */ LVAL xcond(void) { LVAL list,val; /* find a predicate that is true */ for (val = NIL; moreargs(); ) { /* get the next conditional */ list = nextarg(); /* evaluate the predicate part */ if (consp(list) && (val = xleval(car(list)))) { /* evaluate each expression */ for (list = cdr(list); consp(list); list = cdr(list)) val = xleval(car(list)); /* exit the loop */ break; } } /* return the value */ return (val); } /* xwhen - special form 'when' */ LVAL xwhen(void) { LVAL val; /* check the test expression */ if ((val = xleval(xlgetarg()))) while (moreargs()) val = xleval(nextarg()); /* return the value */ return (val); } /* xunless - special form 'unless' */ LVAL xunless(void) { LVAL val=NIL; /* check the test expression */ if (xleval(xlgetarg()) == NIL) while (moreargs()) val = xleval(nextarg()); /* return the value */ return (val); } /* xcase - special form 'case' */ LVAL xcase(void) { LVAL key,list,cases,val; /* protect some pointers */ xlsave1(key); /* get the key expression */ key = xleval(nextarg()); /* find a case that matches */ for (val = NIL; moreargs(); ) { /* get the next case clause */ list = nextarg(); /* make sure this is a valid clause */ if (consp(list)) { /* compare the key list against the key */ if ((cases = car(list)) == s_true || (listp(cases) && keypresent(key,cases)) || eql(key,cases)) { /* evaluate each expression */ for (list = cdr(list); consp(list); list = cdr(list)) val = xleval(car(list)); /* exit the loop */ break; } } else xlerror("bad case clause",list); } /* restore the stack */ xlpop(); /* return the value */ return (val); } /* keypresent - check for the presence of a key in a list */ LOCAL int keypresent(LVAL key, LVAL list) { for (; consp(list); list = cdr(list)) if (eql(car(list),key)) return (TRUE); return (FALSE); } /* xand - special form 'and' */ LVAL xand(void) { LVAL val; /* evaluate each argument */ for (val = s_true; moreargs(); ) if ((val = xleval(nextarg())) == NIL) break; /* return the result value */ return (val); } /* x_or - special form 'or' */ /* this was named xor, but that caused problems with c++ under gcc */ LVAL x_or(void) { LVAL val; /* evaluate each argument */ for (val = NIL; moreargs(); ) if ((val = xleval(nextarg()))) break; /* return the result value */ return (val); } /* xif - special form 'if' */ LVAL xif(void) { LVAL testexpr,thenexpr,elseexpr; /* get the test expression, then clause and else clause */ testexpr = xlgetarg(); thenexpr = xlgetarg(); elseexpr = (moreargs() ? xlgetarg() : NIL); xllastarg(); /* evaluate the appropriate clause */ return (xleval(xleval(testexpr) ? thenexpr : elseexpr)); } /* xlet - special form 'let' */ LVAL xlet(void) { return (let(TRUE)); } /* xletstar - special form 'let*' */ LVAL xletstar(void) { return (let(FALSE)); } /* let - common let routine */ LOCAL LVAL let(int pflag) { LVAL newenv,val; /* protect some pointers */ xlsave1(newenv); /* create a new environment frame */ newenv = xlframe(xlenv); /* get the list of bindings and bind the symbols */ if (!pflag) { xlenv = newenv; } dobindings(xlgalist(),newenv); if (pflag) { xlenv = newenv; } /* execute the code */ for (val = NIL; moreargs(); ) val = xleval(nextarg()); /* unbind the arguments */ xlenv = cdr(xlenv); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* xflet - built-in function 'flet' */ LVAL xflet(void) { return (flet(s_lambda,TRUE)); } /* xlabels - built-in function 'labels' */ LVAL xlabels(void) { return (flet(s_lambda,FALSE)); } /* xmacrolet - built-in function 'macrolet' */ LVAL xmacrolet(void) { return (flet(s_macro,TRUE)); } /* flet - common flet/labels/macrolet routine */ LOCAL LVAL flet(LVAL type, int letflag) { LVAL list,bnd,sym,fargs,val; /* create a new environment frame */ xlfenv = xlframe(xlfenv); /* bind each symbol in the list of bindings */ for (list = xlgalist(); consp(list); list = cdr(list)) { /* get the next binding */ bnd = car(list); /* get the symbol and the function definition */ sym = match(SYMBOL,&bnd); fargs = match(LIST,&bnd); val = xlclose(sym,type,fargs,bnd,xlenv,(letflag?cdr(xlfenv):xlfenv)); /* bind the value to the symbol */ xlfbind(sym,val); } /* execute the code */ for (val = NIL; moreargs(); ) val = xleval(nextarg()); /* unbind the arguments */ xlfenv = cdr(xlfenv); /* return the result */ return (val); } /* xprog - special form 'prog' */ LVAL xprog(void) { return (prog(TRUE)); } /* xprogstar - special form 'prog*' */ LVAL xprogstar(void) { return (prog(FALSE)); } /* prog - common prog routine */ LOCAL LVAL prog(int pflag) { LVAL newenv,val; XLCONTEXT cntxt; /* protect some pointers */ xlsave1(newenv); /* create a new environment frame */ newenv = xlframe(xlenv); /* establish a new execution context */ xlbegin(&cntxt,CF_RETURN,NIL); if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; else { /* get the list of bindings and bind the symbols */ if (!pflag) { xlenv = newenv; } dobindings(xlgalist(),newenv); if (pflag) { xlenv = newenv; } /* execute the code */ tagbody(); val = NIL; /* unbind the arguments */ xlenv = cdr(xlenv); } xlend(&cntxt); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* 4035 is the "no return value" warning message */ /* xgo, xreturn, xrtnfrom, and xthrow don't return anything */ /* #pragma warning(disable: 4035) */ /* xgo - special form 'go' */ LVAL xgo(void) { LVAL label; /* get the target label */ label = xlgetarg(); xllastarg(); /* transfer to the label */ xlgo(label); return NIL; /* never happens */ } /* xreturn - special form 'return' */ LVAL xreturn(void) { LVAL val; /* get the return value */ val = (moreargs() ? xleval(nextarg()) : NIL); xllastarg(); /* return from the inner most block */ xlreturn(NIL,val); return NIL; /* never happens */ } /* xrtnfrom - special form 'return-from' */ LVAL xrtnfrom(void) { LVAL name,val; /* get the return value */ name = xlgasymbol(); val = (moreargs() ? xleval(nextarg()) : NIL); xllastarg(); /* return from the inner most block */ xlreturn(name,val); return NIL; /* never happens */ } /* xprog1 - special form 'prog1' */ LVAL xprog1(void) { return (progx(1)); } /* xprog2 - special form 'prog2' */ LVAL xprog2(void) { return (progx(2)); } /* progx - common progx code */ LOCAL LVAL progx(int n) { LVAL val; /* protect some pointers */ xlsave1(val); /* evaluate the first n expressions */ while (moreargs() && --n >= 0) val = xleval(nextarg()); /* evaluate each remaining argument */ while (moreargs()) xleval(nextarg()); /* restore the stack */ xlpop(); /* return the last test expression value */ return (val); } /* xprogn - special form 'progn' */ LVAL xprogn(void) { LVAL val; /* evaluate each expression */ for (val = NIL; moreargs(); ) val = xleval(nextarg()); /* return the last test expression value */ return (val); } /* xprogv - special form 'progv' */ LVAL xprogv(void) { LVAL olddenv,vars,vals,val; /* protect some pointers */ xlstkcheck(2); xlsave(vars); xlsave(vals); /* get the list of variables and the list of values */ vars = xlgetarg(); vars = xleval(vars); vals = xlgetarg(); vals = xleval(vals); /* bind the values to the variables */ for (olddenv = xldenv; consp(vars); vars = cdr(vars)) { if (!symbolp(car(vars))) xlerror("expecting a symbol",car(vars)); if (consp(vals)) { xldbind(car(vars),car(vals)); vals = cdr(vals); } else xldbind(car(vars),s_unbound); } /* evaluate each expression */ for (val = NIL; moreargs(); ) val = xleval(nextarg()); /* restore the previous environment and the stack */ xlunbind(olddenv); xlpopn(2); /* return the last test expression value */ return (val); } /* xloop - special form 'loop' */ LVAL xloop(void) { LVAL *argv,arg,val; XLCONTEXT cntxt; int argc; /* protect some pointers */ xlsave1(arg); /* establish a new execution context */ xlbegin(&cntxt,CF_RETURN,NIL); if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; else for (argv = xlargv, argc = xlargc; ; xlargv = argv, xlargc = argc) while (moreargs()) { arg = nextarg(); if (consp(arg)) xleval(arg); } xlend(&cntxt); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* xdo - special form 'do' */ LVAL xdo(void) { return (doloop(TRUE)); } /* xdostar - special form 'do*' */ LVAL xdostar(void) { return (doloop(FALSE)); } /* doloop - common do routine */ LOCAL LVAL doloop(int pflag) { LVAL newenv,*argv,blist,clist,test,val; XLCONTEXT cntxt; int argc; /* protect some pointers */ xlsave1(newenv); /* get the list of bindings, the exit test and the result forms */ blist = xlgalist(); clist = xlgalist(); test = (consp(clist) ? car(clist) : NIL); argv = xlargv; argc = xlargc; /* create a new environment frame */ newenv = xlframe(xlenv); /* establish a new execution context */ xlbegin(&cntxt,CF_RETURN,NIL); if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; else { /* bind the symbols */ if (!pflag) { xlenv = newenv; } dobindings(blist,newenv); if (pflag) { xlenv = newenv; } /* execute the loop as long as the test is false */ for (val = NIL; xleval(test) == NIL; doupdates(blist,pflag)) { xlargv = argv; xlargc = argc; tagbody(); } /* evaluate the result expression */ if (consp(clist)) for (clist = cdr(clist); consp(clist); clist = cdr(clist)) val = xleval(car(clist)); /* unbind the arguments */ xlenv = cdr(xlenv); } xlend(&cntxt); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* xdolist - special form 'dolist' */ LVAL xdolist(void) { LVAL list,*argv,clist,sym,val; XLCONTEXT cntxt; int argc; /* protect some pointers */ xlsave1(list); /* get the control list (sym list result-expr) */ clist = xlgalist(); sym = match(SYMBOL,&clist); list = evmatch(LIST,&clist); argv = xlargv; argc = xlargc; /* initialize the local environment */ xlenv = xlframe(xlenv); xlbind(sym,NIL); /* establish a new execution context */ xlbegin(&cntxt,CF_RETURN,NIL); if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; else { /* loop through the list */ for (val = NIL; consp(list); list = cdr(list)) { /* bind the symbol to the next list element */ xlsetvalue(sym,car(list)); /* execute the loop body */ xlargv = argv; xlargc = argc; tagbody(); } /* evaluate the result expression */ xlsetvalue(sym,NIL); val = (consp(clist) ? xleval(car(clist)) : NIL); /* unbind the arguments */ xlenv = cdr(xlenv); } xlend(&cntxt); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* xdotimes - special form 'dotimes' */ LVAL xdotimes(void) { LVAL *argv,clist,sym,cnt,val; XLCONTEXT cntxt; int argc,n,i; /* get the control list (sym list result-expr) */ clist = xlgalist(); sym = match(SYMBOL,&clist); cnt = evmatch(FIXNUM,&clist); n = getfixnum(cnt); argv = xlargv; argc = xlargc; /* establish a new execution context */ xlbegin(&cntxt,CF_RETURN,NIL); /* initialize the local environment */ xlenv = xlframe(xlenv); xlbind(sym,NIL); if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; else { /* loop through for each value from zero to n-1 */ for (val = NIL, i = 0; i < n; ++i) { /* bind the symbol to the next list element */ xlsetvalue(sym,cvfixnum((FIXTYPE)i)); /* execute the loop body */ xlargv = argv; xlargc = argc; tagbody(); } /* evaluate the result expression */ xlsetvalue(sym,cnt); val = (consp(clist) ? xleval(car(clist)) : NIL); /* unbind the arguments */ xlenv = cdr(xlenv); } xlend(&cntxt); /* return the result */ return (val); } /* xblock - special form 'block' */ LVAL xblock(void) { LVAL name,val; XLCONTEXT cntxt; /* get the block name */ name = xlgetarg(); if (name && !symbolp(name)) xlbadtype(name); /* execute the block */ xlbegin(&cntxt,CF_RETURN,name); if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; else for (val = NIL; moreargs(); ) val = xleval(nextarg()); xlend(&cntxt); /* return the value of the last expression */ return (val); } /* xtagbody - special form 'tagbody' */ LVAL xtagbody(void) { tagbody(); return (NIL); } /* xcatch - special form 'catch' */ LVAL xcatch(void) { XLCONTEXT cntxt; LVAL tag,val; /* protect some pointers */ xlsave1(tag); /* get the tag */ tag = xleval(nextarg()); /* establish an execution context */ xlbegin(&cntxt,CF_THROW,tag); /* check for 'throw' */ if (setjmp(cntxt.c_jmpbuf)) val = xlvalue; /* otherwise, evaluate the remainder of the arguments */ else { for (val = NIL; moreargs(); ) val = xleval(nextarg()); } xlend(&cntxt); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* xthrow - special form 'throw' */ LVAL xthrow(void) { LVAL tag,val; /* get the tag and value */ tag = xleval(nextarg()); val = (moreargs() ? xleval(nextarg()) : NIL); xllastarg(); /* throw the tag */ xlthrow(tag,val); return NIL; /* never happens */ } /* xunwindprotect - special form 'unwind-protect' */ LVAL xunwindprotect(void) { extern XLCONTEXT *xltarget; extern int xlmask; XLCONTEXT cntxt; XLCONTEXT *target = NULL; int mask = 0; int sts; LVAL val; /* protect some pointers */ xlsave1(val); /* get the expression to protect */ val = xlgetarg(); /* evaluate the protected expression */ xlbegin(&cntxt,CF_UNWIND,NIL); if ((sts = setjmp(cntxt.c_jmpbuf))) { target = xltarget; mask = xlmask; val = xlvalue; } else val = xleval(val); xlend(&cntxt); /* evaluate the cleanup expressions */ while (moreargs()) xleval(nextarg()); /* if unwinding, continue unwinding */ if (sts) xljump(target,mask,val); /* restore the stack */ xlpop(); /* return the value of the protected expression */ return (val); } /* xerrset - special form 'errset' */ LVAL xerrset(void) { LVAL expr,flag,val; XLCONTEXT cntxt; /* get the expression and the print flag */ expr = xlgetarg(); flag = (moreargs() ? xlgetarg() : s_true); xllastarg(); /* establish an execution context */ xlbegin(&cntxt,CF_ERROR,flag); /* check for error */ if (setjmp(cntxt.c_jmpbuf)) val = NIL; /* otherwise, evaluate the expression */ else { expr = xleval(expr); val = consa(expr); } xlend(&cntxt); /* return the result */ return (val); } /* xtrace - special form 'trace' */ LVAL xtrace(void) { LVAL sym,fun,this; /* loop through all of the arguments */ sym = xlenter("*TRACELIST*"); while (moreargs()) { fun = xlgasymbol(); /* check for the function name already being in the list */ for (this = getvalue(sym); consp(this); this = cdr(this)) if (car(this) == fun) break; /* add the function name to the list */ if (null(this)) setvalue(sym,cons(fun,getvalue(sym))); } return (getvalue(sym)); } /* xuntrace - special form 'untrace' */ LVAL xuntrace(void) { LVAL sym,fun,this,last; /* loop through all of the arguments */ sym = xlenter("*TRACELIST*"); while (moreargs()) { fun = xlgasymbol(); /* remove the function name from the list */ last = NIL; for (this = getvalue(sym); consp(this); this = cdr(this)) { if (car(this) == fun) { if (last) rplacd(last,cdr(this)); else setvalue(sym,cdr(this)); break; } last = this; } } return (getvalue(sym)); } /* dobindings - handle bindings for let/let*, prog/prog*, do/do* */ LOCAL void dobindings(LVAL list, LVAL env) { LVAL bnd, val; LVAL sym = NULL; /* protect some pointers */ xlsave1(val); /* bind each symbol in the list of bindings */ for (; consp(list); list = cdr(list)) { /* get the next binding */ bnd = car(list); /* handle a symbol */ if (symbolp(bnd)) { sym = bnd; val = NIL; } /* handle a list of the form (symbol expr) */ else if (consp(bnd)) { sym = match(SYMBOL,&bnd); val = evarg(&bnd); } else xlfail("bad binding"); /* bind the value to the symbol */ xlpbind(sym,val,env); } /* restore the stack */ xlpop(); } /* doupdates - handle updates for do/do* */ LOCAL void doupdates(LVAL list, int pflag) { LVAL plist,bnd,sym,val; /* protect some pointers */ xlstkcheck(2); xlsave(plist); xlsave(val); /* bind each symbol in the list of bindings */ for (; consp(list); list = cdr(list)) { /* get the next binding */ bnd = car(list); /* handle a list of the form (symbol expr) */ if (consp(bnd)) { sym = match(SYMBOL,&bnd); bnd = cdr(bnd); if (bnd) { val = evarg(&bnd); if (pflag) plist = cons(cons(sym,val),plist); else xlsetvalue(sym,val); } } } /* set the values for parallel updates */ for (; plist; plist = cdr(plist)) xlsetvalue(car(car(plist)),cdr(car(plist))); /* restore the stack */ xlpopn(2); } /* tagbody - execute code within a block and tagbody */ LOCAL void tagbody(void) { LVAL *argv,arg; XLCONTEXT cntxt; int argc; /* establish an execution context */ xlbegin(&cntxt,CF_GO,NIL); argc = xlargc; argv = xlargv; /* check for a 'go' */ if (setjmp(cntxt.c_jmpbuf)) { cntxt.c_xlargc = argc; cntxt.c_xlargv = argv; } /* execute the body */ while (moreargs()) { arg = nextarg(); if (consp(arg)) xleval(arg); } xlend(&cntxt); } /* match - get an argument and match its type */ LOCAL LVAL match(int type, LVAL *pargs) { LVAL arg; /* make sure the argument exists */ if (!consp(*pargs)) toofew(*pargs); /* get the argument value */ arg = car(*pargs); /* move the argument pointer ahead */ *pargs = cdr(*pargs); /* check its type */ if (type == LIST) { if (arg && ntype(arg) != CONS) xlerror("bad argument type",arg); } else { if (arg == NIL || ntype(arg) != type) xlerror("bad argument type",arg); } /* return the argument */ return (arg); } /* evarg - get the next argument and evaluate it */ LOCAL LVAL evarg(LVAL *pargs) { LVAL arg; /* protect some pointers */ xlsave1(arg); /* make sure the argument exists */ if (!consp(*pargs)) toofew(*pargs); /* get the argument value */ arg = car(*pargs); /* move the argument pointer ahead */ *pargs = cdr(*pargs); /* evaluate the argument */ arg = xleval(arg); /* restore the stack */ xlpop(); /* return the argument */ return (arg); } /* evmatch - get an evaluated argument and match its type */ LOCAL LVAL evmatch(int type, LVAL *pargs) { LVAL arg; /* protect some pointers */ xlsave1(arg); /* make sure the argument exists */ if (!consp(*pargs)) toofew(*pargs); /* get the argument value */ arg = car(*pargs); /* move the argument pointer ahead */ *pargs = cdr(*pargs); /* evaluate the argument */ arg = xleval(arg); /* check its type */ if (type == LIST) { if (arg && ntype(arg) != CONS) xlerror("bad argument type",arg); } else { if (arg == NIL || ntype(arg) != type) xlerror("bad argument type",arg); } /* restore the stack */ xlpop(); /* return the argument */ return (arg); } /* toofew - too few arguments */ LOCAL void toofew(LVAL args) { xlerror("too few arguments",args); } /* toomany - too many arguments */ LOCAL void toomany(LVAL args) { xlerror("too many arguments",args); } nyquist-3.05/xlisp/xlfio.c0000644000175000000620000003776111511415575014632 0ustar stevestaff/* xlfio.c - xlisp file i/o */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 30Sep06 rbd added xbigendianp * 28Apr03 dm eliminate some compiler warnings */ #include "switches.h" #include #include "xlisp.h" /* do some sanity checking: */ #ifndef XL_BIG_ENDIAN #ifndef XL_LITTLE_ENDIAN #error configuration error -- either XL_BIG_ or XL_LITTLE_ENDIAN must be defined in xlisp.h #endif #endif #ifdef XL_BIG_ENDIAN #ifdef XL_LITTLE_ENDIAN #error configuration error -- both XL_BIG_ and XL_LITTLE_ENDIAN are defined! #endif #endif /* forward declarations */ FORWARD LOCAL LVAL getstroutput(LVAL stream); FORWARD LOCAL LVAL printit(int pflag, int tflag); FORWARD LOCAL LVAL flatsize(int pflag); /* xread - read an expression */ LVAL xread(void) { LVAL fptr,eof,rflag,val; /* get file pointer and eof value */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); eof = (moreargs() ? xlgetarg() : NIL); rflag = (moreargs() ? xlgetarg() : NIL); xllastarg(); /* read an expression */ if (!xlread(fptr,&val,rflag != NIL)) val = eof; /* return the expression */ return (val); } /* xprint - built-in function 'print' */ LVAL xprint(void) { return (printit(TRUE,TRUE)); } /* xprin1 - built-in function 'prin1' */ LVAL xprin1(void) { return (printit(TRUE,FALSE)); } /* xprinc - built-in function princ */ LVAL xprinc(void) { return (printit(FALSE,FALSE)); } /* xterpri - terminate the current print line */ LVAL xterpri(void) { LVAL fptr; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* terminate the print line and return nil */ xlterpri(fptr); return (NIL); } /* printit - common print function */ LOCAL LVAL printit(int pflag, int tflag) { LVAL fptr,val; /* get expression to print and file pointer */ val = xlgetarg(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* print the value */ xlprint(fptr,val,pflag); /* terminate the print line if necessary */ if (tflag) xlterpri(fptr); /* return the result */ return (val); } /* xflatsize - compute the size of a printed representation using prin1 */ LVAL xflatsize(void) { return (flatsize(TRUE)); } /* xflatc - compute the size of a printed representation using princ */ LVAL xflatc(void) { return (flatsize(FALSE)); } /* flatsize - compute the size of a printed expression */ LOCAL LVAL flatsize(int pflag) { LVAL val; /* get the expression */ val = xlgetarg(); xllastarg(); /* print the value to compute its size */ xlfsize = 0; xlprint(NIL,val,pflag); /* return the length of the expression */ return (cvfixnum((FIXTYPE)xlfsize)); } /* xlopen - open a text or binary file */ LVAL xlopen(int binaryflag) { char *name,*mode=NULL; FILE *fp; LVAL dir; /* get the file name and direction */ name = (char *)getstring(xlgetfname()); if (!xlgetkeyarg(k_direction,&dir)) dir = k_input; /* get the mode */ if (dir == k_input) mode = "r"; else if (dir == k_output) mode = "w"; else xlerror("bad direction",dir); /* try to open the file */ if (binaryflag) { fp = osbopen(name,mode); } else { fp = osaopen(name,mode); } return (fp ? cvfile(fp) : NIL); } /* xopen - open a file */ LVAL xopen(void) { return xlopen(FALSE); } /* xbopen - open a binary file */ LVAL xbopen(void) { return xlopen(TRUE); } /* xclose - close a file */ LVAL xclose(void) { LVAL fptr; /* get file pointer */ fptr = xlgastream(); xllastarg(); /* make sure the file exists */ if (getfile(fptr) == NULL) xlfail("file not open"); /* close the file */ osclose(getfile(fptr)); setfile(fptr,NULL); /* return nil */ return (NIL); } /* xrdchar - read a character from a file */ LVAL xrdchar(void) { LVAL fptr; int ch; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* get character and check for eof */ return ((ch = xlgetc(fptr)) == EOF ? NIL : cvchar(ch)); } /* xrdint - read an integer from a file */ /* positive byte count means big-endian, negative is little-endian */ LVAL xrdint(void) { LVAL fptr; unsigned char b[4]; long i; int n = 4; int index = 0; /* where to start in array */ int incr = 1; /* how to step through array */ int rslt; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); /* get byte count */ if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); if (n < 0) { n = -n; index = n - 1; incr = -1; } if (n > 4) { xlerror("4-byte limit", count); } } xllastarg(); for (i = 0; i < n; i++) { int ch = xlgetc(fptr); if (ch == EOF) return NIL; b[index] = ch; index += incr; } /* build result, b is now big-endian */ /* extend sign bit for short integers */ rslt = ((b[0] & 0x80) ? -1 : 0); for (i = 0; i < n; i++) { rslt = (rslt << 8) + b[i]; } /* return integer result */ return cvfixnum(rslt); } /* xrdfloat - read a float from a file */ LVAL xrdfloat(void) { LVAL fptr; union { char b[8]; float f; double d; } rslt; int n = 4; int i; int index = 3; /* where to start in array */ int incr = -1; /* how to step through array */ /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); /* get byte count */ if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); if (n < 0) { n = -n; index = 0; incr = 1; } if (n != 4 && n != 8) { xlerror("must be 4 or 8 bytes", count); } } xllastarg(); #ifdef XL_BIG_ENDIAN /* flip the bytes */ index = n - 1 - index; incr = -incr; #endif for (i = 0; i < n; i++) { int ch = xlgetc(fptr); if (ch == EOF) return NIL; rslt.b[index] = ch; index += incr; } /* return result */ return cvflonum(n == 4 ? rslt.f : rslt.d); } /* xrdbyte - read a byte from a file */ LVAL xrdbyte(void) { LVAL fptr; int ch; /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* get character and check for eof */ return ((ch = xlgetc(fptr)) == EOF ? NIL : cvfixnum((FIXTYPE)ch)); } /* xpkchar - peek at a character from a file */ LVAL xpkchar(void) { LVAL flag,fptr; int ch; /* peek flag and get file pointer */ flag = (moreargs() ? xlgetarg() : NIL); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* skip leading white space and get a character */ if (flag) while ((ch = xlpeek(fptr)) != EOF && isspace(ch)) xlgetc(fptr); else ch = xlpeek(fptr); /* return the character */ return (ch == EOF ? NIL : cvchar(ch)); } /* xwrchar - write a character to a file */ LVAL xwrchar(void) { LVAL fptr,chr; /* get the character and file pointer */ chr = xlgachar(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* put character to the file */ xlputc(fptr,getchcode(chr)); /* return the character */ return (chr); } /* xwrbyte - write a byte to a file */ LVAL xwrbyte(void) { LVAL fptr,chr; /* get the byte and file pointer */ chr = xlgafixnum(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* put byte to the file */ xlputc(fptr,(int)getfixnum(chr)); /* return the character */ return (chr); } /* xwrint - write an integer to a file */ /* positive count means write big-endian */ LVAL xwrint(void) { LVAL val, fptr; unsigned char b[4]; long i; int n = 4; int index = 3; /* where to start in array */ int incr = -1; /* how to step through array */ int v; /* get the int and file pointer and optional byte count */ val = xlgafixnum(); v = getfixnum(val); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); index = n - 1; if (n < 0) { n = -n; index = 0; incr = 1; } if (n > 4) { xlerror("4-byte limit", count); } } xllastarg(); /* build output b as little-endian */ for (i = 0; i < n; i++) { b[i] = (unsigned char) v; v = v >> 8; } /* put bytes to the file */ while (n) { n--; xlputc(fptr, b[index]); index += incr; } /* return the integer */ return val; } /* xwrfloat - write a float to a file */ LVAL xwrfloat(void) { LVAL val, fptr; union { char b[8]; float f; double d; } v; int n = 4; int i; int index = 3; /* where to start in array */ int incr = -1; /* how to step through array */ /* get the float and file pointer and optional byte count */ val = xlgaflonum(); fptr = (moreargs() ? xlgetfile() : getvalue(s_stdout)); if (moreargs()) { LVAL count = typearg(fixp); n = getfixnum(count); if (n < 0) { n = -n; index = 0; incr = 1; } if (n != 4 && n != 8) { xlerror("must be 4 or 8 bytes", count); } } xllastarg(); #ifdef XL_BIG_ENDIAN /* flip the bytes */ index = n - 1 - index; incr = -incr; #endif /* build output v.b */ if (n == 4) v.f = (float) getflonum(val); else v.d = getflonum(val); /* put bytes to the file */ for (i = 0; i < n; i++) { xlputc(fptr, v.b[index]); index += incr; } /* return the flonum */ return val; } /* xreadline - read a line from a file */ LVAL xreadline(void) { unsigned char buf[STRMAX+1],*p,*sptr; LVAL fptr,str,newstr; int len,blen,ch; /* protect some pointers */ xlsave1(str); /* get file pointer */ fptr = (moreargs() ? xlgetfile() : getvalue(s_stdin)); xllastarg(); /* get character and check for eof */ len = blen = 0; p = buf; while ((ch = xlgetc(fptr)) != EOF && ch != '\n') { /* check for buffer overflow */ if (blen >= STRMAX) { newstr = new_string(len + STRMAX + 1); sptr = getstring(newstr); *sptr = '\0'; if (str) strcat((char *) sptr, (char *) getstring(str)); *p = '\0'; strcat((char *) sptr, (char *) buf); p = buf; blen = 0; len += STRMAX; str = newstr; } /* store the character */ *p++ = ch; ++blen; } /* check for end of file */ if (len == 0 && p == buf && ch == EOF) { xlpop(); return (NIL); } /* append the last substring */ if (str == NIL || blen) { newstr = new_string(len + blen + 1); sptr = getstring(newstr); *sptr = '\0'; if (str) strcat((char *) sptr, (char *) getstring(str)); *p = '\0'; strcat((char *) sptr, (char *) buf); str = newstr; } /* restore the stack */ xlpop(); /* return the string */ return (str); } /* xmkstrinput - make a string input stream */ LVAL xmkstrinput(void) { int start,end,len,i; unsigned char *str; LVAL string,val; /* protect the return value */ xlsave1(val); /* get the string and length */ string = xlgastring(); str = getstring(string); len = getslength(string) - 1; /* get the starting offset */ if (moreargs()) { val = xlgafixnum(); start = (int)getfixnum(val); } else start = 0; /* get the ending offset */ if (moreargs()) { val = xlgafixnum(); end = (int)getfixnum(val); } else end = len; xllastarg(); /* check the bounds */ if (start < 0 || start > len) xlerror("string index out of bounds",cvfixnum((FIXTYPE)start)); if (end < 0 || end > len) xlerror("string index out of bounds",cvfixnum((FIXTYPE)end)); /* make the stream */ val = newustream(); /* copy the substring into the stream */ for (i = start; i < end; ++i) xlputc(val,str[i]); /* restore the stack */ xlpop(); /* return the new stream */ return (val); } /* xmkstroutput - make a string output stream */ LVAL xmkstroutput(void) { return (newustream()); } /* xgetstroutput - get output stream string */ LVAL xgetstroutput(void) { LVAL stream; stream = xlgaustream(); xllastarg(); return (getstroutput(stream)); } /* xgetlstoutput - get output stream list */ LVAL xgetlstoutput(void) { LVAL stream,val; /* get the stream */ stream = xlgaustream(); xllastarg(); /* get the output character list */ val = gethead(stream); /* empty the character list */ sethead(stream,NIL); settail(stream,NIL); /* return the list */ return (val); } /* xformat - formatted output function */ LVAL xformat(void) { unsigned char *fmt; LVAL stream,val; int ch; /* protect stream in case it is a new ustream */ xlsave1(stream); /* get the stream and format string */ stream = xlgetarg(); if (stream == NIL) val = stream = newustream(); else { if (stream == s_true) stream = getvalue(s_stdout); else if (!streamp(stream) && !ustreamp(stream)) xlbadtype(stream); val = NIL; } fmt = getstring(xlgastring()); /* process the format string */ while ((ch = *fmt++)) if (ch == '~') { switch (*fmt++) { case '\0': xlerror("expecting a format directive",cvstring((char *) (fmt-1))); case 'a': case 'A': xlprint(stream,xlgetarg(),FALSE); break; case 's': case 'S': xlprint(stream,xlgetarg(),TRUE); break; case '%': xlterpri(stream); break; case '~': xlputc(stream,'~'); break; case '\n': case '\r': /* mac may read \r -- this should be ignored */ if (*fmt == '\r') *fmt++; while (*fmt && *fmt != '\n' && isspace(*fmt)) ++fmt; break; default: xlerror("unknown format directive",cvstring((char *) (fmt-1))); } } else xlputc(stream,ch); /* return the value */ if (val) val = getstroutput(val); xlpop(); return val; } /* getstroutput - get the output stream string (internal) */ LOCAL LVAL getstroutput(LVAL stream) { unsigned char *str; LVAL next,val; int len,ch; /* compute the length of the stream */ for (len = 0, next = gethead(stream); next != NIL; next = cdr(next)) ++len; /* create a new string */ val = new_string(len + 1); /* copy the characters into the new string */ str = getstring(val); while ((ch = xlgetc(stream)) != EOF) *str++ = ch; *str = '\0'; /* return the string */ return (val); } LVAL xlistdir(void) { char *path; LVAL result = NULL; LVAL *tail; /* get the path */ path = (char *)getstring(xlgetfname()); /* try to start listing */ if (osdir_list_start(path)) { char *filename; xlsave1(result); tail = &result; while (filename = osdir_list_next()) { *tail = cons(NIL, NIL); rplaca(*tail, cvstring(filename)); tail = &cdr(*tail); } osdir_list_finish(); xlpop(); } return result; } /* xbigendianp -- is this a big-endian machine? T or NIL */ LVAL xbigendianp() { #ifdef XL_BIG_ENDIAN return s_true; #else return NIL; #endif } nyquist-3.05/xlisp/xlsys.c0000644000175000000620000001425011466723256014666 0ustar stevestaff/* xlsys.c - xlisp builtin system functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* HISTORY * * 11-Dec-09 Roger Dannenberg * Added getenv * * 28-Apr-03 Dominic Mazzoni * Eliminated some compiler warnings * * 25-Oct-87 Roger Dannenberg at NeXT * profiling code added: enable with (PROFILE t), disable with * (PROFILE nil). While enabled, the profile code counts evals * within functions and macros. The count is only for evals * directly within the form; i.e. only the count of the most * top-most function or macro form on the stack is incremented. * Also, counts are only maintained for named functions and macros * because the count itself is on the property list of the function * or macro name under the *PROFILE* property. If a function or * macro is entered and the *PROFILE* does not exist, the property * is created with initial value 0, and the name is inserted at the * head of the list stored as the value of *PROFILE*. Thus, *PROFILE* * will list the functions that were touched, and the *PROFILE* property * of each function gives some idea of how much time it consumed. * See the file profile.lsp for helpful profiling functions. */ #include "xlisp.h" /* profile variables */ static FIXTYPE invisible_counter; FIXTYPE *profile_count_ptr = &invisible_counter; FIXTYPE profile_flag = FALSE; /* external variables */ extern jmp_buf top_level; extern FILE *tfp; extern int xl_main_loop; /* external symbols */ extern LVAL a_subr,a_fsubr,a_cons,a_symbol; extern LVAL a_fixnum,a_flonum,a_string,a_object,a_stream; extern LVAL a_vector,a_closure,a_char,a_ustream; extern LVAL k_verbose,k_print; extern LVAL s_true; /* external routines */ extern FILE *osaopen(); extern LVAL exttype(); /* xget_env - get the value of an environment variable */ LVAL xget_env(void) { const char *name = (char *) getstring(xlgetfname()); char *val; /* check for too many arguments */ xllastarg(); /* get the value of the environment variable */ val = getenv(name); return (val ? cvstring(val) : NULL); } /* xload - read and evaluate expressions from a file */ LVAL xload(void) { unsigned char *name; int vflag,pflag; LVAL arg; /* get the file name */ name = getstring(xlgetfname()); /* get the :verbose flag */ if (xlgetkeyarg(k_verbose,&arg)) vflag = (arg != NIL); else vflag = TRUE; /* get the :print flag */ if (xlgetkeyarg(k_print,&arg)) pflag = (arg != NIL); else pflag = FALSE; /* load the file */ return (xlload((char *) name, vflag, pflag) ? s_true : NIL); } /* xtranscript - open or close a transcript file */ LVAL xtranscript(void) { unsigned char *name; /* get the transcript file name */ name = (moreargs() ? getstring(xlgetfname()) : NULL); xllastarg(); /* close the current transcript */ if (tfp) osclose(tfp); /* open the new transcript */ tfp = (name ? osaopen((char *) name,"w") : NULL); /* return T if a transcript is open, NIL otherwise */ return (tfp ? s_true : NIL); } /* xtype - return type of a thing */ LVAL xtype(void) { LVAL arg; if (!(arg = xlgetarg())) return (NIL); switch (ntype(arg)) { case SUBR: return (a_subr); case FSUBR: return (a_fsubr); case CONS: return (a_cons); case SYMBOL: return (a_symbol); case FIXNUM: return (a_fixnum); case FLONUM: return (a_flonum); case STRING: return (a_string); case OBJECT: return (a_object); case STREAM: return (a_stream); case VECTOR: return (a_vector); case CLOSURE: return (a_closure); case CHAR: return (a_char); case USTREAM: return (a_ustream); case EXTERN: return (exttype(arg)); default: xlfail("bad node type"); return NIL; /* never happens */ } } /* xbaktrace - print the trace back stack */ LVAL xbaktrace(void) { LVAL num; int n; if (moreargs()) { num = xlgafixnum(); n = getfixnum(num); } else n = -1; xllastarg(); xlbaktrace(n); return (NIL); } /* xquit - get out of read/eval/print loop */ LVAL xquit() { xllastarg(); xl_main_loop = FALSE; return NIL; } /* xexit does not return anything, so turn off "no return value" warning" */ /* #pragma warning(disable: 4035) */ /* xexit - get out of xlisp */ LVAL xexit(void) { xllastarg(); xlisp_wrapup(); return NIL; /* never happens */ } #ifdef PEEK_AND_POKE /* xpeek - peek at a location in memory */ LVAL xpeek(void) { LVAL num; int *adr; /* get the address */ num = xlgafixnum(); adr = (int *)getfixnum(num); xllastarg(); /* return the value at that address */ return (cvfixnum((FIXTYPE)*adr)); } /* xpoke - poke a value into memory */ LVAL xpoke(void) { LVAL val; int *adr; /* get the address and the new value */ val = xlgafixnum(); adr = (int *)getfixnum(val); val = xlgafixnum(); xllastarg(); /* store the new value */ *adr = (int)getfixnum(val); /* return the new value */ return (val); } /* xaddrs - get the address of an XLISP node */ LVAL xaddrs(void) { LVAL val; /* get the node */ val = xlgetarg(); xllastarg(); /* return the address of the node */ return (cvfixnum((FIXTYPE)val)); } #endif PEEK_AND_POKE /* xprofile - turn profiling on and off */ LVAL xprofile() { LVAL flag, result; /* get the argument */ flag = xlgetarg(); xllastarg(); result = (profile_flag ? s_true : NIL); profile_flag = !null(flag); /* turn off profiling right away: */ if (!profile_flag) profile_count_ptr = &invisible_counter; return result; } #ifdef DEBUG_INPUT FILE *debug_input_fp = NULL; FILE *to_input_buffer = NULL; FILE *read_by_xlisp = NULL; LVAL xstartrecordio() { to_input_buffer = fopen("to-input-buffer.txt", "w"); read_by_xlisp = fopen("read-by-xlisp.txt", "w"); if (!to_input_buffer || !read_by_xlisp) { return NIL; } return s_true; } LVAL xstoprecordio() { if (to_input_buffer) fclose(to_input_buffer); if (read_by_xlisp) fclose(read_by_xlisp); to_input_buffer = NULL; read_by_xlisp = NULL; return NIL; } #endif nyquist-3.05/xlisp/xleval.c0000644000175000000620000005762311466723256015012 0ustar stevestaff/* xleval - xlisp evaluator */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* HISTORY 28 Apr 03 DM eliminated some compiler warnings 12 Oct 90 RBD added profiling support */ #include "string.h" #include "xlisp.h" /* macro to check for lambda list keywords */ #define iskey(s) ((s) == lk_optional \ || (s) == lk_rest \ || (s) == lk_key \ || (s) == lk_aux \ || (s) == lk_allow_other_keys) /* macros to handle tracing */ #define trenter(sym,argc,argv) {if (sym) doenter(sym,argc,argv);} #define trexit(sym,val) {if (sym) doexit(sym,val);} /* forward declarations */ FORWARD LOCAL LVAL evalhook(LVAL expr); FORWARD LOCAL LVAL evform(LVAL form); FORWARD LOCAL LVAL evfun(LVAL fun, int argc, LVAL *argv); FORWARD LVAL xlclose(LVAL name, LVAL type, LVAL fargs, LVAL body, LVAL env, LVAL fenv); FORWARD LOCAL int member( LVAL x, LVAL list); FORWARD LOCAL int evpushargs(LVAL fun, LVAL args); FORWARD LOCAL void doenter(LVAL sym, int argc, LVAL *argv); FORWARD LOCAL void doexit(LVAL sym, LVAL val); FORWARD LOCAL void badarglist(void); /* profiling extensions by RBD */ extern LVAL s_profile, profile_fixnum; extern FIXTYPE *profile_count_ptr, profile_flag; /* xleval - evaluate an xlisp expression (checking for *evalhook*) */ LVAL xleval(LVAL expr) { /* check for control codes */ if (--xlsample <= 0) { xlsample = SAMPLE; oscheck(); } /* check for *evalhook* */ if (getvalue(s_evalhook)) return (evalhook(expr)); /* check for nil */ if (null(expr)) return (NIL); /* dispatch on the node type */ switch (ntype(expr)) { case CONS: return (evform(expr)); case SYMBOL: return (xlgetvalue(expr)); default: return (expr); } } /* xlxeval - evaluate an xlisp expression (bypassing *evalhook*) */ LVAL xlxeval(LVAL expr) { /* check for nil */ if (null(expr)) return (NIL); /* dispatch on node type */ switch (ntype(expr)) { case CONS: return (evform(expr)); case SYMBOL: return (xlgetvalue(expr)); default: return (expr); } } /* xlapply - apply a function to arguments (already on the stack) */ LVAL xlapply(int argc) { LVAL *oldargv,fun,val=NULL; LVAL funname; LVAL old_profile_fixnum = profile_fixnum; FIXTYPE *old_profile_count_ptr = profile_count_ptr; int oldargc; /* get the function */ fun = xlfp[1]; /* get the functional value of symbols */ if (symbolp(fun)) { funname = fun; /* save it */ while ((val = getfunction(fun)) == s_unbound) xlfunbound(fun); fun = xlfp[1] = val; if (profile_flag && atomp(funname)) { LVAL profile_prop = findprop(funname, s_profile); if (null(profile_prop)) { /* make a new fixnum, don't use cvfixnum because it would return shared pointer to zero, but we are going to modify this integer in place -- dangerous but efficient. */ profile_fixnum = newnode(FIXNUM); profile_fixnum->n_fixnum = 0; setplist(funname, cons(s_profile, cons(profile_fixnum, getplist(funname)))); setvalue(s_profile, cons(funname, getvalue(s_profile))); } else profile_fixnum = car(profile_prop); profile_count_ptr = &getfixnum(profile_fixnum); } } /* check for nil */ if (null(fun)) xlerror("bad function",fun); /* dispatch on node type */ switch (ntype(fun)) { case SUBR: oldargc = xlargc; oldargv = xlargv; xlargc = argc; xlargv = xlfp + 3; val = (*getsubr(fun))(); xlargc = oldargc; xlargv = oldargv; break; case CONS: if (!consp(cdr(fun))) xlerror("bad function",fun); if (car(fun) == s_lambda) { fun = xlclose(NIL, s_lambda, car(cdr(fun)), cdr(cdr(fun)), xlenv,xlfenv); } else xlerror("bad function",fun); /**** fall through into the next case ****/ case CLOSURE: if (gettype(fun) != s_lambda) xlerror("bad function",fun); val = evfun(fun,argc,xlfp+3); break; default: xlerror("bad function",fun); } /* restore original profile counting state */ profile_fixnum = old_profile_fixnum; profile_count_ptr = old_profile_count_ptr; /* remove the call frame */ xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); /* return the function value */ return (val); } /* evform - evaluate a form */ LOCAL LVAL evform(LVAL form) { LVAL fun,args,val=NULL,type; LVAL tracing=NIL; LVAL *argv; LVAL old_profile_fixnum = profile_fixnum; FIXTYPE *old_profile_count_ptr = profile_count_ptr; LVAL funname; int argc; /* protect some pointers */ xlstkcheck(2); xlsave(fun); xlsave(args); (*profile_count_ptr)++; /* increment profile counter */ /* get the function and the argument list */ fun = car(form); args = cdr(form); funname = fun; /* get the functional value of symbols */ if (symbolp(fun)) { if (getvalue(s_tracelist) && member(fun,getvalue(s_tracelist))) tracing = fun; fun = xlgetfunction(fun); } /* check for nil */ if (null(fun)) xlerror("bad function",NIL); /* dispatch on node type */ switch (ntype(fun)) { case SUBR: argv = xlargv; argc = xlargc; xlargc = evpushargs(fun,args); xlargv = xlfp + 3; trenter(tracing,xlargc,xlargv); val = (*getsubr(fun))(); trexit(tracing,val); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); xlargv = argv; xlargc = argc; break; case FSUBR: argv = xlargv; argc = xlargc; xlargc = pushargs(fun,args); xlargv = xlfp + 3; val = (*getsubr(fun))(); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); xlargv = argv; xlargc = argc; break; case CONS: if (!consp(cdr(fun))) xlerror("bad function",fun); if ((type = car(fun)) == s_lambda) fun = xlclose(NIL, s_lambda, car(cdr(fun)), cdr(cdr(fun)), xlenv,xlfenv); else xlerror("bad function",fun); /**** fall through into the next case ****/ case CLOSURE: /* do profiling */ if (profile_flag && atomp(funname)) { LVAL profile_prop = findprop(funname, s_profile); if (null(profile_prop)) { /* make a new fixnum, don't use cvfixnum because it would return shared pointer to zero, but we are going to modify this integer in place -- dangerous but efficient. */ profile_fixnum = newnode(FIXNUM); profile_fixnum->n_fixnum = 0; setplist(funname, cons(s_profile, cons(profile_fixnum, getplist(funname)))); setvalue(s_profile, cons(funname, getvalue(s_profile))); } else profile_fixnum = car(profile_prop); profile_count_ptr = &getfixnum(profile_fixnum); } if (gettype(fun) == s_lambda) { argc = evpushargs(fun,args); argv = xlfp + 3; trenter(tracing,argc,argv); val = evfun(fun,argc,argv); trexit(tracing,val); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); } else { macroexpand(fun,args,&fun); val = xleval(fun); } profile_fixnum = old_profile_fixnum; profile_count_ptr = old_profile_count_ptr; break; default: xlerror("bad function",fun); } /* restore the stack */ xlpopn(2); /* return the result value */ return (val); } /* xlexpandmacros - expand macros in a form */ LVAL xlexpandmacros(LVAL form) { LVAL fun,args; /* protect some pointers */ xlstkcheck(3); xlprotect(form); xlsave(fun); xlsave(args); /* expand until the form isn't a macro call */ while (consp(form)) { fun = car(form); /* get the macro name */ args = cdr(form); /* get the arguments */ if (!symbolp(fun) || !fboundp(fun)) break; fun = xlgetfunction(fun); /* get the expansion function */ if (!macroexpand(fun,args,&form)) break; } /* restore the stack and return the expansion */ xlpopn(3); return (form); } /* macroexpand - expand a macro call */ int macroexpand(LVAL fun, LVAL args, LVAL *pval) { LVAL *argv; int argc; /* make sure it's really a macro call */ if (!closurep(fun) || gettype(fun) != s_macro) return (FALSE); /* call the expansion function */ argc = pushargs(fun,args); argv = xlfp + 3; *pval = evfun(fun,argc,argv); xlsp = xlfp; xlfp = xlfp - (int)getfixnum(*xlfp); return (TRUE); } /* evalhook - call the evalhook function */ LOCAL LVAL evalhook(LVAL expr) { LVAL *newfp,olddenv,val; /* create the new call frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(getvalue(s_evalhook)); pusharg(cvfixnum((FIXTYPE)2)); pusharg(expr); pusharg(cons(xlenv,xlfenv)); xlfp = newfp; /* rebind the hook functions to nil */ olddenv = xldenv; xldbind(s_evalhook,NIL); xldbind(s_applyhook,NIL); /* call the hook function */ val = xlapply(2); /* unbind the symbols */ xlunbind(olddenv); /* return the value */ return (val); } /* evpushargs - evaluate and push a list of arguments */ LOCAL int evpushargs(LVAL fun, LVAL args) { LVAL *newfp; int argc; /* protect the argument list */ xlprot1(args); /* build a new argument stack frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(NIL); /* will be argc */ /* evaluate and push each argument */ for (argc = 0; consp(args); args = cdr(args), ++argc) { pusharg(xleval(car(args))); } /* establish the new stack frame */ newfp[2] = cvfixnum((FIXTYPE)argc); xlfp = newfp; /* restore the stack */ xlpop(); /* return the number of arguments */ return (argc); } /* pushargs - push a list of arguments */ int pushargs(LVAL fun, LVAL args) { LVAL *newfp; int argc; /* build a new argument stack frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(NIL); /* will be argc */ /* push each argument */ for (argc = 0; consp(args); args = cdr(args), ++argc) pusharg(car(args)); /* establish the new stack frame */ newfp[2] = cvfixnum((FIXTYPE)argc); xlfp = newfp; /* return the number of arguments */ return (argc); } /* makearglist - make a list of the remaining arguments */ LVAL makearglist(int argc, LVAL *argv) { LVAL list,this,last; xlsave1(list); for (last = NIL; --argc >= 0; last = this) { this = cons(*argv++,NIL); if (last) rplacd(last,this); else list = this; last = this; } xlpop(); return (list); } /* evfun - evaluate a function */ LOCAL LVAL evfun(LVAL fun, int argc, LVAL *argv) { LVAL oldenv,oldfenv,cptr,name,val; XLCONTEXT cntxt; /* protect some pointers */ xlstkcheck(4); xlsave(oldenv); xlsave(oldfenv); xlsave(cptr); xlprotect(fun); /* (RBD) Otherwise, fun is unprotected */ /* create a new environment frame */ oldenv = xlenv; oldfenv = xlfenv; xlenv = xlframe(closure_getenv(fun)); xlfenv = getfenv(fun); /* bind the formal parameters */ xlabind(fun,argc,argv); /* setup the implicit block */ if ((name = getname(fun))) xlbegin(&cntxt,CF_RETURN,name); /* execute the block */ if (name && setjmp(cntxt.c_jmpbuf)) val = xlvalue; else for (val = NIL, cptr = getbody(fun); consp(cptr); cptr = cdr(cptr)) val = xleval(car(cptr)); /* finish the block context */ if (name) xlend(&cntxt); /* restore the environment */ xlenv = oldenv; xlfenv = oldfenv; /* restore the stack */ xlpopn(4); /* return the result value */ return (val); } /* xlclose - create a function closure */ LVAL xlclose(LVAL name, LVAL type, LVAL fargs, LVAL body, LVAL env, LVAL fenv) { LVAL closure,key=NULL,arg,def,svar,new,last; char keyname[STRMAX+2]; /* protect some pointers */ xlsave1(closure); /* create the closure object */ closure = newclosure(name,type,env,fenv); setlambda(closure,fargs); setbody(closure,body); /* handle each required argument */ last = NIL; while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) { /* make sure the argument is a symbol */ if (!symbolp(arg)) badarglist(); /* create a new argument list entry */ new = cons(arg,NIL); /* link it into the required argument list */ if (last) rplacd(last,new); else setargs(closure,new); last = new; /* move the formal argument list pointer ahead */ fargs = cdr(fargs); } /* check for the '&optional' keyword */ if (consp(fargs) && car(fargs) == lk_optional) { fargs = cdr(fargs); /* handle each optional argument */ last = NIL; while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) { /* get the default expression and specified-p variable */ def = svar = NIL; if (consp(arg)) { if ((def = cdr(arg))) { if (consp(def)) { if ((svar = cdr(def))) { if (consp(svar)) { svar = car(svar); if (!symbolp(svar)) badarglist(); } else badarglist(); } def = car(def); } else badarglist(); } arg = car(arg); } /* make sure the argument is a symbol */ if (!symbolp(arg)) badarglist(); /* create a fully expanded optional expression */ new = cons(cons(arg,cons(def,cons(svar,NIL))),NIL); /* link it into the optional argument list */ if (last) rplacd(last,new); else setoargs(closure,new); last = new; /* move the formal argument list pointer ahead */ fargs = cdr(fargs); } } /* check for the '&rest' keyword */ if (consp(fargs) && car(fargs) == lk_rest) { fargs = cdr(fargs); /* get the &rest argument */ if (consp(fargs) && (arg = car(fargs)) && !iskey(arg) && symbolp(arg)) setrest(closure,arg); else badarglist(); /* move the formal argument list pointer ahead */ fargs = cdr(fargs); } /* check for the '&key' keyword */ if (consp(fargs) && car(fargs) == lk_key) { fargs = cdr(fargs); /* handle each key argument */ last = NIL; while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) { /* get the default expression and specified-p variable */ def = svar = NIL; if (consp(arg)) { if ((def = cdr(arg))) { if (consp(def)) { if ((svar = cdr(def))) { if (consp(svar)) { svar = car(svar); if (!symbolp(svar)) badarglist(); } else badarglist(); } def = car(def); } else badarglist(); } arg = car(arg); } /* get the keyword and the variable */ if (consp(arg)) { key = car(arg); if (!symbolp(key)) badarglist(); if ((arg = cdr(arg))) { if (consp(arg)) arg = car(arg); else badarglist(); } } else if (symbolp(arg)) { strcpy(keyname,":"); strcat(keyname,(char *) getstring(getpname(arg))); key = xlenter(keyname); } /* make sure the argument is a symbol */ if (!symbolp(arg)) badarglist(); /* create a fully expanded key expression */ new = cons(cons(key,cons(arg,cons(def,cons(svar,NIL)))),NIL); /* link it into the optional argument list */ if (last) rplacd(last,new); else setkargs(closure,new); last = new; /* move the formal argument list pointer ahead */ fargs = cdr(fargs); } } /* check for the '&allow-other-keys' keyword */ if (consp(fargs) && car(fargs) == lk_allow_other_keys) fargs = cdr(fargs); /* this is the default anyway */ /* check for the '&aux' keyword */ if (consp(fargs) && car(fargs) == lk_aux) { fargs = cdr(fargs); /* handle each aux argument */ last = NIL; while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) { /* get the initial value */ def = NIL; if (consp(arg)) { if ((def = cdr(arg))) { if (consp(def)) def = car(def); else badarglist(); } arg = car(arg); } /* make sure the argument is a symbol */ if (!symbolp(arg)) badarglist(); /* create a fully expanded aux expression */ new = cons(cons(arg,cons(def,NIL)),NIL); /* link it into the aux argument list */ if (last) rplacd(last,new); else setaargs(closure,new); last = new; /* move the formal argument list pointer ahead */ fargs = cdr(fargs); } } /* make sure this is the end of the formal argument list */ if (fargs) badarglist(); /* restore the stack */ xlpop(); /* return the new closure */ return (closure); } /* xlabind - bind the arguments for a function */ void xlabind(LVAL fun, int argc, LVAL *argv) { LVAL *kargv,fargs,key,arg,def,svar,p; int rargc,kargc; /* protect some pointers */ xlsave1(def); /* bind each required argument */ for (fargs = getargs(fun); fargs; fargs = cdr(fargs)) { /* make sure there is an actual argument */ if (--argc < 0) xlfail("too few arguments"); /* bind the formal variable to the argument value */ xlbind(car(fargs),*argv++); } /* bind each optional argument */ for (fargs = getoargs(fun); fargs; fargs = cdr(fargs)) { /* get argument, default and specified-p variable */ p = car(fargs); arg = car(p); p = cdr(p); def = car(p); p = cdr(p); svar = car(p); /* bind the formal variable to the argument value */ if (--argc >= 0) { xlbind(arg,*argv++); if (svar) xlbind(svar,s_true); } /* bind the formal variable to the default value */ else { if (def) def = xleval(def); xlbind(arg,def); if (svar) xlbind(svar,NIL); } } /* save the count of the &rest of the argument list */ rargc = argc; /* handle '&rest' argument */ if ((arg = getrest(fun))) { def = makearglist(argc,argv); xlbind(arg,def); argc = 0; } /* handle '&key' arguments */ if ((fargs = getkargs(fun))) { for (; fargs; fargs = cdr(fargs)) { /* get keyword, argument, default and specified-p variable */ p = car(fargs); key = car(p); p = cdr(p); arg = car(p); p = cdr(p); def = car(p); p = cdr(p); svar = car(p); /* look for the keyword in the actual argument list */ for (kargv = argv, kargc = rargc; (kargc -= 2) >= 0; kargv += 2) if (*kargv == key) break; /* bind the formal variable to the argument value */ if (kargc >= 0) { xlbind(arg,*++kargv); if (svar) xlbind(svar,s_true); } /* bind the formal variable to the default value */ else { if (def) def = xleval(def); xlbind(arg,def); if (svar) xlbind(svar,NIL); } } argc = 0; } /* check for the '&aux' keyword */ for (fargs = getaargs(fun); fargs; fargs = cdr(fargs)) { /* get argument and default */ p = car(fargs); arg = car(p); p = cdr(p); def = car(p); /* bind the auxiliary variable to the initial value */ if (def) def = xleval(def); xlbind(arg,def); } /* make sure there aren't too many arguments */ if (argc > 0) xlfail("too many arguments"); /* restore the stack */ xlpop(); } /* doenter - print trace information on function entry */ LOCAL void doenter(LVAL sym, int argc, LVAL *argv) { extern int xltrcindent; int i; /* indent to the current trace level */ for (i = 0; i < xltrcindent; ++i) trcputstr(" "); ++xltrcindent; /* display the function call */ sprintf(buf,"Entering: %s, Argument list: (",getstring(getpname(sym))); trcputstr(buf); while (--argc >= 0) { trcprin1(*argv++); if (argc) trcputstr(" "); } trcputstr(")\n"); } /* doexit - print trace information for function/macro exit */ LOCAL void doexit(LVAL sym, LVAL val) { extern int xltrcindent; int i; /* indent to the current trace level */ --xltrcindent; for (i = 0; i < xltrcindent; ++i) trcputstr(" "); /* display the function value */ sprintf(buf,"Exiting: %s, Value: ",getstring(getpname(sym))); trcputstr(buf); trcprin1(val); trcputstr("\n"); } /* member - is 'x' a member of 'list'? */ LOCAL int member( LVAL x, LVAL list) { for (; consp(list); list = cdr(list)) if (x == car(list)) return (TRUE); return (FALSE); } /* xlunbound - signal an unbound variable error */ void xlunbound(LVAL sym) { xlcerror("try evaluating symbol again","unbound variable",sym); } /* xlfunbound - signal an unbound function error */ void xlfunbound(LVAL sym) { xlcerror("try evaluating symbol again","unbound function",sym); } /* xlstkoverflow - signal a stack overflow error */ void xlstkoverflow(void) { xlabort("evaluation stack overflow"); } /* xlargstkoverflow - signal an argument stack overflow error */ void xlargstkoverflow(void) { xlabort("argument stack overflow"); } /* badarglist - report a bad argument list error */ LOCAL void badarglist(void) { xlfail("bad formal argument list"); } nyquist-3.05/xlisp/xldmem.c0000644000175000000620000004527311466723256015003 0ustar stevestaff/* xldmem - xlisp dynamic memory management routines */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use * HISTORY * 28-Apr-03 Mazzoni * eliminate some compiler warnings * 14-Apr-88 Dannenberg * Call free method when an EXTERN node is garbage collected */ /* #define DEBUG_MEM 1 */ #include "stdlib.h" #include "string.h" #include "xlisp.h" #ifdef WIN32 #include "malloc.h" // defines alloca() #endif /* node flags */ #define MARK 1 #define LEFT 2 /* macro to compute the size of a segment */ #define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node)) #ifdef DEBUG_INPUT extern FILE *debug_input_fp; #endif /* variables local to xldmem.c and xlimage.c */ SEGMENT *segs,*lastseg,*fixseg,*charseg; int anodes,nsegs,gccalls; long nnodes,nfree,total; LVAL fnodes; #ifdef DEBUG_MEM long xldmem_trace = 0; /* debugging */ #endif /* forward declarations */ FORWARD LOCAL void findmem(void); FORWARD LVAL newnode(int type); FORWARD LOCAL unsigned char *stralloc(int size); FORWARD LOCAL int addseg(void); FORWARD void mark(LVAL ptr); FORWARD LOCAL void sweep(void); #ifdef DEBUG_GC static long dbg_gc_n = 0; /* counts save operations */ long dbg_gc_count = 0; /* says when to stop */ LVAL *dbg_gc_addr = NULL; /* says what we're looking for */ void dbg_gc_xlsave(LVAL *n) { dbg_gc_n++; if (n == dbg_gc_addr) { printf("dbg_gc_xlsave: %x at count %d\n", dbg_gc_addr, dbg_gc_n); } if (dbg_gc_count == dbg_gc_n) { printf("dbg_gc_xlsave: reached %d\n", dbg_gc_count); } } #endif /* cons - construct a new cons node */ LVAL cons(LVAL x, LVAL y) { LVAL nnode; /* get a free node */ if ((nnode = fnodes) == NIL) { xlstkcheck(2); xlprotect(x); xlprotect(y); findmem(); if ((nnode = fnodes) == NIL) xlabort("insufficient node space"); xlpop(); xlpop(); } /* unlink the node from the free list */ fnodes = cdr(nnode); --nfree; /* initialize the new node */ nnode->n_type = CONS; rplaca(nnode,x); rplacd(nnode,y); /* return the new node */ return (nnode); } /* cvstring - convert a string to a string node */ LVAL cvstring(const char *str) { LVAL val; xlsave1(val); val = newnode(STRING); val->n_strlen = strlen(str) + 1; val->n_string = stralloc(getslength(val)); strcpy((char *) getstring(val),str); xlpop(); return (val); } /* new_string - allocate and initialize a new string */ LVAL new_string(int size) { LVAL val; xlsave1(val); val = newnode(STRING); val->n_strlen = size; val->n_string = stralloc(getslength(val)); strcpy((char *) getstring(val),""); xlpop(); return (val); } /* cvsymbol - convert a string to a symbol */ LVAL cvsymbol(char *pname) { /* pname points to a global buffer space. This is ok unless you have * a gc hook that writes things and therefore uses the buffer. Then * if newvector causes a GC, pname is overwritten before cvstring is * called and the symbol will have the wrong name! * The bug is fixed by copying pname to the stack. */ LVAL val; int len = strlen(pname) + 1; /* don't forget the terminating zero */ char *local_pname_copy = (char *) alloca(len); memcpy(local_pname_copy, pname, len); xlsave1(val); val = newvector(SYMSIZE); val->n_type = SYMBOL; setvalue(val,s_unbound); setfunction(val,s_unbound); setpname(val,cvstring(local_pname_copy)); xlpop(); return (val); } /* cvsubr - convert a function to a subr or fsubr */ LVAL cvsubr(LVAL (*fcn)(void), int type, int offset) { LVAL val; val = newnode(type); val->n_subr = fcn; val->n_offset = offset; return (val); } /* cvfile - convert a file pointer to a stream */ LVAL cvfile(FILE *fp) { LVAL val; val = newnode(STREAM); setfile(val,fp); setsavech(val,'\0'); return (val); } /* cvfixnum - convert an integer to a fixnum node */ LVAL cvfixnum(FIXTYPE n) { LVAL val; if (n >= SFIXMIN && n <= SFIXMAX) return (&fixseg->sg_nodes[(int)n-SFIXMIN]); val = newnode(FIXNUM); val->n_fixnum = n; return (val); } /* cvflonum - convert a floating point number to a flonum node */ LVAL cvflonum(FLOTYPE n) { LVAL val; val = newnode(FLONUM); val->n_flonum = n; return (val); } /* cvchar - convert an integer to a character node */ LVAL cvchar(int n) { if (n >= CHARMIN && n <= CHARMAX) return (&charseg->sg_nodes[n-CHARMIN]); xlerror("character code out of range",cvfixnum((FIXTYPE)n)); return NIL; /* won't reach this line */ } /* newustream - create a new unnamed stream */ LVAL newustream(void) { LVAL val; val = newnode(USTREAM); sethead(val,NIL); settail(val,NIL); return (val); } /* newobject - allocate and initialize a new object */ LVAL newobject(LVAL cls, int size) { LVAL val; val = newvector(size+1); val->n_type = OBJECT; setelement(val,0,cls); return (val); } /* newclosure - allocate and initialize a new closure */ LVAL newclosure(LVAL name, LVAL type, LVAL env, LVAL fenv) { LVAL val; val = newvector(CLOSIZE); val->n_type = CLOSURE; setname(val,name); settype(val,type); setenv(val,env); setfenv(val,fenv); return (val); } /* newvector - allocate and initialize a new vector node */ LVAL newvector(int size) { LVAL vect; int bsize; xlsave1(vect); vect = newnode(VECTOR); vect->n_vsize = 0; if ((bsize = size * sizeof(LVAL))) { if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL) { findmem(); if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL) xlfail("insufficient vector space"); } vect->n_vsize = size; total += (long) bsize; } xlpop(); return (vect); } /* newnode - allocate a new node */ LVAL newnode(int type) { LVAL nnode; /* get a free node */ if ((nnode = fnodes) == NIL) { findmem(); if ((nnode = fnodes) == NIL) xlabort("insufficient node space"); } /* unlink the node from the free list */ fnodes = cdr(nnode); nfree -= 1L; /* initialize the new node */ nnode->n_type = type; rplacd(nnode,NIL); /* return the new node */ return (nnode); } /* stralloc - allocate memory for a string adding a byte for the terminator */ LOCAL unsigned char *stralloc(int size) { unsigned char *sptr; /* allocate memory for the string copy */ if ((sptr = (unsigned char *)malloc(size)) == NULL) { gc(); if ((sptr = (unsigned char *)malloc(size)) == NULL) xlfail("insufficient string space"); } total += (long)size; /* return the new string memory */ return (sptr); } /* findmem - find more memory by collecting then expanding */ LOCAL void findmem(void) { gc(); if (nfree < (long)anodes) addseg(); } /* gc - garbage collect (only called here and in xlimage.c) */ void gc(void) { register LVAL **p,*ap,tmp; char buf[STRMAX+1]; LVAL *newfp,fun; extern LVAL profile_fixnum; /* print the start of the gc message */ if (s_gcflag && getvalue(s_gcflag)) { sprintf(buf,"[ gc: total %ld, ",nnodes); stdputstr(buf); } /* mark the fixnum used by profiler */ if (!null(profile_fixnum)) mark(profile_fixnum); /* mark the obarray, the argument list and the current environment */ if (obarray) mark(obarray); if (xlenv) mark(xlenv); if (xlfenv) mark(xlfenv); if (xldenv) mark(xldenv); /* mark the evaluation stack */ for (p = xlstack; p < xlstktop; ++p) if ((tmp = **p)) mark(tmp); /* mark the argument stack */ for (ap = xlargstkbase; ap < xlsp; ++ap) if ((tmp = *ap)) mark(tmp); /* sweep memory collecting all unmarked nodes */ sweep(); /* count the gc call */ ++gccalls; /* call the *gc-hook* if necessary */ if (s_gchook && (fun = getvalue(s_gchook))) { newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(cvfixnum((FIXTYPE)2)); pusharg(cvfixnum((FIXTYPE)nnodes)); pusharg(cvfixnum((FIXTYPE)nfree)); xlfp = newfp; xlapply(2); } /* print the end of the gc message */ if (s_gcflag && getvalue(s_gcflag)) { sprintf(buf,"%ld free", nfree); stdputstr(buf); /* print additional info (e.g. sound blocks in Nyquist) */ print_local_gc_info(); stdputstr(" ]\n"); stdflush(); /* output in a timely fashion so user sees progress */ } #ifdef DEBUG_INPUT if (debug_input_fp) { int c = getc(debug_input_fp); ungetc(c, debug_input_fp); } #endif } /* mark - mark all accessible nodes */ void mark(LVAL ptr) { register LVAL this,prev,tmp; int type,i,n; /* initialize */ prev = NIL; this = ptr; /* mark this list */ for (;;) { /* descend as far as we can */ while (!(this->n_flags & MARK)) /* check cons and symbol nodes */ if (((type = ntype(this))) == CONS || type == USTREAM) { if ((tmp = car(this))) { this->n_flags |= MARK|LEFT; rplaca(this,prev); } else if ((tmp = cdr(this))) { this->n_flags |= MARK; rplacd(this,prev); } else { /* both sides nil */ this->n_flags |= MARK; break; } prev = this; /* step down the branch */ this = tmp; } /* mark other node types */ else { this->n_flags |= MARK; switch (type) { case SYMBOL: case OBJECT: case VECTOR: case CLOSURE: for (i = 0, n = getsize(this); --n >= 0; ++i) if ((tmp = getelement(this,i))) mark(tmp); break; case EXTERN: if (getdesc(this)->mark_meth) { (*(getdesc(this)->mark_meth))(getinst(this)); } } break; } /* backup to a point where we can continue descending */ for (;;) /* make sure there is a previous node */ if (prev) { if (prev->n_flags & LEFT) { /* came from left side */ prev->n_flags &= ~LEFT; tmp = car(prev); rplaca(prev,this); if ((this = cdr(prev))) { rplacd(prev,tmp); break; } } else { /* came from right side */ tmp = cdr(prev); rplacd(prev,this); } this = prev; /* step back up the branch */ prev = tmp; } /* no previous node, must be done */ else return; } } /* sweep - sweep all unmarked nodes and add them to the free list */ LOCAL void sweep(void) { SEGMENT *seg; LVAL p; int n; /* empty the free list */ fnodes = NIL; nfree = 0L; /* add all unmarked nodes */ for (seg = segs; seg; seg = seg->sg_next) { if (seg == fixseg) /* don't sweep the fixnum segment */ continue; else if (seg == charseg) /* don't sweep the character segment */ continue; p = &seg->sg_nodes[0]; for (n = seg->sg_size; --n >= 0; ++p) { #ifdef DEBUG_MEM if (xldmem_trace && ntype(p) == EXTERN && xldmem_trace == getinst(p)) { printf("sweep: EXTERN node %lx is %smarked, points to %lx\n", p, (p->n_flags & MARK ? "" : "un"), getinst(p)); } #endif if (!(p->n_flags & MARK)) { switch (ntype(p)) { case STRING: if (getstring(p) != NULL) { total -= (long)getslength(p); free(getstring(p)); } break; case STREAM: if (getfile(p)) osclose(getfile(p)); break; case SYMBOL: case OBJECT: case VECTOR: case CLOSURE: if (p->n_vsize) { total -= (long) (p->n_vsize * sizeof(LVAL)); free((void *) p->n_vdata); } break; case EXTERN: /* printf("GC about to free %x\n", p); * fflush(stdout); */ if (getdesc(p)) { (*(getdesc(p)->free_meth))(getinst(p)); } break; } p->n_type = FREE_NODE; rplaca(p,NIL); rplacd(p,fnodes); fnodes = p; nfree += 1L; } else p->n_flags &= ~MARK; } } } /* addseg - add a segment to the available memory */ LOCAL int addseg(void) { SEGMENT *newseg; LVAL p; int n; /* allocate the new segment */ if (anodes == 0 || (newseg = newsegment(anodes)) == NULL) return (FALSE); /* add each new node to the free list */ p = &newseg->sg_nodes[0]; for (n = anodes; --n >= 0; ++p) { rplacd(p,fnodes); fnodes = p; } /* return successfully */ return (TRUE); } /* newsegment - create a new segment (only called here and in xlimage.c) */ SEGMENT *newsegment(int n) { SEGMENT *newseg; /* allocate the new segment */ if ((newseg = (SEGMENT *)calloc(1,segsize(n))) == NULL) return (NULL); /* initialize the new segment */ newseg->sg_size = n; newseg->sg_next = NULL; if (segs) lastseg->sg_next = newseg; else segs = newseg; lastseg = newseg; /* update the statistics */ total += (long)segsize(n); nnodes += (long)n; nfree += (long)n; ++nsegs; /* return the new segment */ return (newseg); } /* stats - print memory statistics */ LOCAL void stats(void) { sprintf(buf,"Nodes: %ld\n",nnodes); stdputstr(buf); sprintf(buf,"Free nodes: %ld\n",nfree); stdputstr(buf); sprintf(buf,"Segments: %d\n",nsegs); stdputstr(buf); sprintf(buf,"Allocate: %d\n",anodes); stdputstr(buf); sprintf(buf,"Total: %ld\n",total); stdputstr(buf); sprintf(buf,"Collections: %d\n",gccalls); stdputstr(buf); } /* xgc - xlisp function to force garbage collection */ LVAL xgc(void) { /* make sure there aren't any arguments */ xllastarg(); /* garbage collect */ gc(); /* return nil */ return (NIL); } /* xexpand - xlisp function to force memory expansion */ LVAL xexpand(void) { LVAL num; int n,i; /* get the new number to allocate */ if (moreargs()) { num = xlgafixnum(); n = getfixnum(num); } else n = 1; xllastarg(); /* allocate more segments */ for (i = 0; i < n; i++) if (!addseg()) break; /* return the number of segments added */ return (cvfixnum((FIXTYPE)i)); } /* xalloc - xlisp function to set the number of nodes to allocate */ LVAL xalloc(void) { int n,oldn; LVAL num; /* get the new number to allocate */ num = xlgafixnum(); n = getfixnum(num); /* make sure there aren't any more arguments */ xllastarg(); /* set the new number of nodes to allocate */ oldn = anodes; anodes = n; /* return the old number */ return (cvfixnum((FIXTYPE)oldn)); } /* xmem - xlisp function to print memory statistics */ LVAL xmem(void) { /* allow one argument for compatiblity with common lisp */ if (moreargs()) xlgetarg(); xllastarg(); /* print the statistics */ stats(); /* return nil */ return (NIL); } /* xinfo - show information on control-t */ LVAL xinfo() { char buf[80]; sprintf(buf,"\n[ Free: %d, GC calls: %d, Total: %d", (int)nfree, (int)gccalls, (int)total); stdputstr(buf); print_local_gc_info(); stdputstr("]\n"); return NULL; } #ifdef SAVERESTORE /* xsave - save the memory image */ LVAL xsave(void) { unsigned char *name; /* get the file name, verbose flag and print flag */ name = getstring(xlgetfname()); xllastarg(); /* save the memory image */ return (xlisave((char *) name) ? s_true : NIL); } /* xrestore - restore a saved memory image */ LVAL xrestore(void) { extern jmp_buf top_level; unsigned char *name; /* get the file name, verbose flag and print flag */ name = getstring(xlgetfname()); xllastarg(); /* restore the saved memory image */ if (!xlirestore((char *) name)) return (NIL); /* return directly to the top level */ stdputstr("[ returning to the top level ]\n"); longjmp(top_level,1); } #endif /* xlminit - initialize the dynamic memory module */ void xlminit(void) { LVAL p; int i; /* initialize our internal variables */ segs = lastseg = NULL; nnodes = nfree = total = 0L; nsegs = gccalls = 0; anodes = NNODES; fnodes = NIL; /* allocate the fixnum segment */ if ((fixseg = newsegment(SFIXSIZE)) == NULL) xlfatal("insufficient memory"); /* initialize the fixnum segment */ p = &fixseg->sg_nodes[0]; for (i = SFIXMIN; i <= SFIXMAX; ++i) { p->n_type = FIXNUM; p->n_fixnum = i; ++p; } /* allocate the character segment */ if ((charseg = newsegment(CHARSIZE)) == NULL) xlfatal("insufficient memory"); /* initialize the character segment */ p = &charseg->sg_nodes[0]; for (i = CHARMIN; i <= CHARMAX; ++i) { p->n_type = CHAR; p->n_chcode = i; ++p; } /* initialize structures that are marked by the collector */ obarray = xlenv = xlfenv = xldenv = NIL; s_gcflag = s_gchook = NIL; /* allocate the evaluation stack */ if ((xlstkbase = (LVAL **)malloc(EDEPTH * sizeof(LVAL *))) == NULL) xlfatal("insufficient memory"); xlstack = xlstktop = xlstkbase + EDEPTH; /* allocate the argument stack */ if ((xlargstkbase = (LVAL *)malloc(ADEPTH * sizeof(LVAL))) == NULL) xlfatal("insufficient memory"); // printf("ADEPTH is %d\n", ADEPTH); xlargstktop = xlargstkbase + ADEPTH; xlfp = xlsp = xlargstkbase; *xlsp++ = NIL; } nyquist-3.05/xlisp/xlinit.c0000644000175000000620000002147511466723256015022 0ustar stevestaff/* xlinit.c - xlisp initialization module */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use * HISTORY * 3-Apr-88 Dale Amon at CMU-CSD * Added EXTERN to xlisp 2.0 * * 18-Oct-87 Dale Amon at CMU-CSD * Added initialization for new EXTERN node type. * * 12 Oct 90 RBD Added s_profile declaration * * 5 Jun 95 EAD took out extern init (put back when building nyquest) */ #include "xlisp.h" /* external variables */ extern LVAL s_true,s_dot,s_unbound; extern LVAL s_quote,s_function,s_bquote,s_comma,s_comat; extern LVAL s_lambda,s_macro; extern LVAL s_stdin,s_stdout,s_stderr,s_debugio,s_traceout; extern LVAL s_evalhook,s_applyhook,s_tracelist; extern LVAL s_tracenable,s_tlimit,s_breakenable, s_profile; extern LVAL s_setf,s_car,s_cdr,s_nth,s_aref,s_get,s_eql; extern LVAL s_svalue,s_sfunction,s_splist; extern LVAL s_rtable,k_wspace,k_const,k_nmacro,k_tmacro; extern LVAL k_sescape,k_mescape; extern LVAL s_ifmt,s_ffmt,s_printcase; extern LVAL s_1plus,s_2plus,s_3plus,s_1star,s_2star,s_3star,s_minus; extern LVAL k_test,k_tnot; extern LVAL k_direction,k_input,k_output; extern LVAL k_start,k_end,k_1start,k_1end,k_2start,k_2end; extern LVAL k_verbose,k_print,k_count,k_key,k_upcase,k_downcase; extern LVAL lk_optional,lk_rest,lk_key,lk_aux,lk_allow_other_keys; extern LVAL a_subr,a_fsubr,a_cons,a_symbol; extern LVAL a_fixnum,a_flonum,a_string,a_stream,a_object; extern LVAL a_vector,a_closure,a_char,a_ustream,a_extern; extern LVAL s_gcflag,s_gchook; extern LVAL s_search_path; extern FUNDEF funtab[]; /* forward declarations */ FORWARD LOCAL void initwks(); /* xlinit - xlisp initialization routine */ void xlinit(void) { /* initialize xlisp (must be in this order) */ xlminit(); /* initialize xldmem.c */ xldinit(); /* initialize xldbug.c */ /* finish initializing */ #ifdef SAVERESTORE if (!xlirestore("xlisp.wks")) #endif { initwks(); } /* note: localinit creates type descriptors, but these may be necessary for xlirestore to work. On the other hand, localinit creates atoms, so it needs obarray to be in place, and obarray is created by initwks. We may have a circular dependency to break before xlirestore will work */ localinit(); /* initialize lisp extensions */ } /* initwks - build an initial workspace */ LOCAL void initwks(void) { FUNDEF *p; int i; xlsinit(); /* initialize xlsym.c */ xlsymbols();/* enter all symbols used by the interpreter */ xlrinit(); /* initialize xlread.c */ xloinit(); /* initialize xlobj.c */ /* setup defaults */ setvalue(s_evalhook,NIL); /* no evalhook function */ setvalue(s_applyhook,NIL); /* no applyhook function */ setvalue(s_tracelist,NIL); /* no functions being traced */ setvalue(s_tracenable,NIL); /* traceback disabled */ setvalue(s_tlimit,NIL); /* trace limit infinite */ setvalue(s_breakenable,NIL); /* don't enter break loop on errors */ setvalue(s_loadingfiles,NIL); /* not loading any files initially */ setvalue(s_profile,NIL); /* don't do profiling */ setvalue(s_gcflag,NIL); /* don't show gc information */ setvalue(s_gchook,NIL); /* no gc hook active */ setvalue(s_ifmt,cvstring(IFMT)); /* integer print format */ setvalue(s_ffmt,cvstring("%g")); /* float print format */ setvalue(s_printcase,k_upcase); /* upper case output of symbols */ /* install the built-in functions and special forms */ for (i = 0, p = funtab; p->fd_subr != NULL; ++i, ++p) if (p->fd_name) xlsubr(p->fd_name,p->fd_type,p->fd_subr,i); /* add some synonyms */ setfunction(xlenter("NOT"),getfunction(xlenter("NULL"))); setfunction(xlenter("FIRST"),getfunction(xlenter("CAR"))); setfunction(xlenter("SECOND"),getfunction(xlenter("CADR"))); setfunction(xlenter("THIRD"),getfunction(xlenter("CADDR"))); setfunction(xlenter("FOURTH"),getfunction(xlenter("CADDDR"))); setfunction(xlenter("REST"),getfunction(xlenter("CDR"))); } /* xlsymbols - enter all of the symbols used by the interpreter */ void xlsymbols(void) { LVAL sym; /* enter the unbound variable indicator (must be first) */ s_unbound = xlenter("*UNBOUND*"); setvalue(s_unbound,s_unbound); /* enter the 't' symbol */ s_true = xlenter("T"); setvalue(s_true,s_true); /* enter some important symbols */ s_dot = xlenter("."); s_quote = xlenter("QUOTE"); s_function = xlenter("FUNCTION"); s_bquote = xlenter("BACKQUOTE"); s_comma = xlenter("COMMA"); s_comat = xlenter("COMMA-AT"); s_lambda = xlenter("LAMBDA"); s_macro = xlenter("MACRO"); s_eql = xlenter("EQL"); s_ifmt = xlenter("*INTEGER-FORMAT*"); s_ffmt = xlenter("*FLOAT-FORMAT*"); /* symbols set by the read-eval-print loop */ s_1plus = xlenter("+"); s_2plus = xlenter("++"); s_3plus = xlenter("+++"); s_1star = xlenter("*"); s_2star = xlenter("**"); s_3star = xlenter("***"); s_minus = xlenter("-"); /* enter setf place specifiers */ s_setf = xlenter("*SETF*"); s_car = xlenter("CAR"); s_cdr = xlenter("CDR"); s_nth = xlenter("NTH"); s_aref = xlenter("AREF"); s_get = xlenter("GET"); s_svalue = xlenter("SYMBOL-VALUE"); s_sfunction = xlenter("SYMBOL-FUNCTION"); s_splist = xlenter("SYMBOL-PLIST"); /* enter the readtable variable and keywords */ s_rtable = xlenter("*READTABLE*"); k_wspace = xlenter(":WHITE-SPACE"); k_const = xlenter(":CONSTITUENT"); k_nmacro = xlenter(":NMACRO"); k_tmacro = xlenter(":TMACRO"); k_sescape = xlenter(":SESCAPE"); k_mescape = xlenter(":MESCAPE"); /* enter parameter list keywords */ k_test = xlenter(":TEST"); k_tnot = xlenter(":TEST-NOT"); /* "open" keywords */ k_direction = xlenter(":DIRECTION"); k_input = xlenter(":INPUT"); k_output = xlenter(":OUTPUT"); /* enter *print-case* symbol and keywords */ s_printcase = xlenter("*PRINT-CASE*"); k_upcase = xlenter(":UPCASE"); k_downcase = xlenter(":DOWNCASE"); /* other keywords */ k_start = xlenter(":START"); k_end = xlenter(":END"); k_1start = xlenter(":START1"); k_1end = xlenter(":END1"); k_2start = xlenter(":START2"); k_2end = xlenter(":END2"); k_verbose = xlenter(":VERBOSE"); k_print = xlenter(":PRINT"); k_count = xlenter(":COUNT"); k_key = xlenter(":KEY"); /* enter lambda list keywords */ lk_optional = xlenter("&OPTIONAL"); lk_rest = xlenter("&REST"); lk_key = xlenter("&KEY"); lk_aux = xlenter("&AUX"); lk_allow_other_keys = xlenter("&ALLOW-OTHER-KEYS"); /* enter *standard-input*, *standard-output* and *error-output* */ s_stdin = xlenter("*STANDARD-INPUT*"); setvalue(s_stdin,cvfile(stdin)); s_stdout = xlenter("*STANDARD-OUTPUT*"); setvalue(s_stdout,cvfile(stdout)); s_stderr = xlenter("*ERROR-OUTPUT*"); setvalue(s_stderr,cvfile(STDERR)); /* enter *debug-io* and *trace-output* */ s_debugio = xlenter("*DEBUG-IO*"); setvalue(s_debugio,getvalue(s_stderr)); s_traceout = xlenter("*TRACE-OUTPUT*"); setvalue(s_traceout,getvalue(s_stderr)); /* enter the eval and apply hook variables */ s_evalhook = xlenter("*EVALHOOK*"); s_applyhook = xlenter("*APPLYHOOK*"); /* enter the symbol pointing to the list of functions being traced */ s_tracelist = xlenter("*TRACELIST*"); /* enter the error traceback and the error break enable flags */ s_tracenable = xlenter("*TRACENABLE*"); s_tlimit = xlenter("*TRACELIMIT*"); s_breakenable = xlenter("*BREAKENABLE*"); s_profile = xlenter("*PROFILE*"); /* enter the symbol pointing to the list of loading files */ s_loadingfiles = xlenter("*LOADINGFILES*"); /* enter a symbol to control printing of garbage collection messages */ s_gcflag = xlenter("*GC-FLAG*"); s_gchook = xlenter("*GC-HOOK*"); /* enter the symbol for the search path */ s_search_path = xlenter("*SEARCH-PATH*"); /* enter a copyright notice into the oblist */ sym = xlenter("**Copyright-1988-by-David-Betz**"); setvalue(sym,s_true); /* enter type names */ a_subr = xlenter("SUBR"); a_fsubr = xlenter("FSUBR"); a_cons = xlenter("CONS"); a_symbol = xlenter("SYMBOL"); a_fixnum = xlenter("FIXNUM"); a_flonum = xlenter("FLONUM"); a_string = xlenter("STRING"); a_object = xlenter("OBJECT"); a_stream = xlenter("FILE-STREAM"); a_vector = xlenter("ARRAY"); a_extern = xlenter("EXTERN"); a_closure = xlenter("CLOSURE"); a_char = xlenter("CHARACTER"); a_ustream = xlenter("UNNAMED-STREAM"); /* add the object-oriented programming symbols and os specific stuff */ obsymbols(); /* object-oriented programming symbols */ ossymbols(); /* os specific symbols */ localsymbols(); /* lisp extension symbols */ } nyquist-3.05/xlisp/xlisp.c0000644000175000000620000001634511466723256014652 0ustar stevestaff/* xlisp.c - a small implementation of lisp with object-oriented programming */ /* Copyright (c) 1987, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGELOG: 8 Oct 90 (Dannenberg) changed main() to xlisp_main_init and xlisp_main. made xlisp run as a module that evaluates expressions and retains state */ #include "switches.h" #include "stdlib.h" /* declares exit() */ #include "cext.h" #include "xlisp.h" #ifdef MACINTOSH #include "Memory.h" #endif FORWARD void xlisp_wrapup(void); /* define the banner line string */ #ifdef EXT #ifdef NYQUIST #define BANNER "XLISP version 2.0, Copyright (c) 1986, by David Betz" #else #define BANNER "Music Editor, Copyright (c) 1987, by Roger B. Dannenberg\n\ XLISP version 2.0, Copyright (c) 1986, by David Betz" #endif #else #ifdef CMTSTUFF #define BANNER "XLISP version 2.0, Copyright (c) 1986, by David Betz\n\ CMU MIDI Toolkit, Copyright (c) 1993,1994, by Roger B. Dannenberg" #else #define BANNER "XLISP version 2.0, Copyright (c) 1986, by David Betz" #endif #endif /* global variables */ jmp_buf top_level; int in_a_context = FALSE; int xl_main_loop = FALSE; /* external variables */ extern LVAL s_stdin,s_evalhook,s_applyhook; extern LVAL s_1plus,s_2plus,s_3plus,s_1star,s_2star,s_3star,s_minus; extern int xltrcindent; extern int xldebug; extern LVAL s_true; extern char buf[]; extern FILE *tfp; /* external routines */ extern FILE *osaopen(); #ifdef USE_RANDOM /* use a fast (but not particularly good) random number generator */ long randomseed = 1L; long random() { // note that this takes a seed and returns a big number, // whereas I think XLisp's RANDOM is defined differently long k1; /* algorithm taken from Dr. Dobbs Journal, November 1985, page 91 */ k1 = randomseed / 127773L; if ((randomseed = 16807L * (randomseed - k1 * 127773L) - k1 * 2836L) < 0L) randomseed += 2147483647L; /* return a random number between 0 and MAXFIX */ return randomseed; } #endif /* xlrand - return next random number in sequence */ long xlrand (long range) { #ifdef USE_RAND return rand() % range; #endif #ifdef USE_RANDOM return random() % range; #endif } /* xlrealrand - return random number in [0, 1] */ double xlrealrand() { /* always use the random generator from the C library, (do not use random() even if USE_RANDOM is defined */ return (double) rand() / RAND_MAX; } /* xlisp_main_init - the main initialization routine */ void xlisp_main_init(int argc, char *argv[]) { char *transcript; XLCONTEXT cntxt; int verbose,i; /* setup default argument values */ transcript = NULL; verbose = FALSE; /* parse the argument list switches */ #ifndef LSC for (i = 1; i < argc; ++i) if (argv[i][0] == '-') switch(argv[i][1]) { case 't': case 'T': transcript = &argv[i][2]; break; case 'v': case 'V': verbose = TRUE; break; } #endif /* initialize and print the banner line */ osinit(BANNER); /* setup initialization error handler */ xlbegin(&cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,(LVAL)1); if (setjmp(cntxt.c_jmpbuf)) xlfatal("fatal initialization error"); if (setjmp(top_level)) xlfatal("RESTORE not allowed during initialization"); /* initialize xlisp */ xlinit(); xlend(&cntxt); #ifdef EXT /* special initialization */ #include "xlextstart.c" #endif /* reset the error handler */ xlbegin(&cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,s_true); /* open the transcript file */ if (transcript && (tfp = osaopen(transcript,"w")) == NULL) { sprintf(buf,"error: can't open transcript file: %s",transcript); stdputstr(buf); } /* load "init.lsp" */ if (setjmp(cntxt.c_jmpbuf) == 0) { xlload("init.lsp",TRUE,FALSE); } /* load any files mentioned on the command line */ if (setjmp(cntxt.c_jmpbuf) == 0) for (i = 1; i < argc; i++) if (argv[i][0] != '-' && !xlload(argv[i],TRUE,verbose)) xlerror("can't load file",cvstring(argv[i])); xlend(&cntxt); if (setjmp(top_level)) xlfatal("RESTORE not allowed out of read-eval-print loop"); } /* xlisp_eval -- evaluate an expression created externally */ LVAL xlisp_eval(LVAL expr) { int was_in_a_context = in_a_context; XLCONTEXT cntxt; if (in_a_context == FALSE) { /* create an execution context */ xlbegin(&cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,s_true); if (setjmp(cntxt.c_jmpbuf)) { setvalue(s_evalhook,NIL); setvalue(s_applyhook,NIL); xltrcindent = 0; xldebug = 0; xlflush(); oserror("xlisp_eval returning NIL to caller"); in_a_context = FALSE; return NIL; } in_a_context = TRUE; } expr = xleval(expr); if (!was_in_a_context) { xlend(&cntxt); in_a_context = FALSE; } return expr; } /* xlisp_main -- run normal lisp read-eval-print loop */ void xlisp_main() { LVAL expr; XLCONTEXT cntxt; /* build an outer-most context */ xlbegin(&cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,s_true); in_a_context = TRUE; /* target for restore */ if (setjmp(top_level)) xlbegin(&cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,s_true); /* protect some pointers */ xlsave1(expr); /* main command processing loop */ for (xl_main_loop = TRUE; xl_main_loop;) { /* setup the error return */ if (setjmp(cntxt.c_jmpbuf)) { setvalue(s_evalhook,NIL); setvalue(s_applyhook,NIL); xltrcindent = 0; xldebug = 0; xlflush(); } #ifndef READ_LINE /* print a prompt */ stdputstr("> "); #endif /* read an expression */ if (!xlread(getvalue(s_stdin),&expr,FALSE)) break; /* save the input expression */ xlrdsave(expr); /* evaluate the expression */ expr = xleval(expr); /* save the result */ xlevsave(expr); /* print it */ stdprint(expr); } xlend(&cntxt); in_a_context = FALSE; } /* #include "alloca.h" -- what was this for? -RBD */ #ifndef EXT int main(int argc, char *argv[]) { xlisp_main_init(argc,argv); xlisp_main(); /* clean up */ xlisp_wrapup(); return 0; } #endif /* xlrdsave - save the last expression returned by the reader */ void xlrdsave(LVAL expr) { setvalue(s_3plus,getvalue(s_2plus)); setvalue(s_2plus,getvalue(s_1plus)); setvalue(s_1plus,getvalue(s_minus)); setvalue(s_minus,expr); } /* xlevsave - save the last expression returned by the evaluator */ void xlevsave(LVAL expr) { setvalue(s_3star,getvalue(s_2star)); setvalue(s_2star,getvalue(s_1star)); setvalue(s_1star,expr); } /* xlfatal - print a fatal error message and exit */ void xlfatal(char *msg) { oserror(msg); xlisp_wrapup(); } /* wrapup - clean up and exit to the operating system */ void xlisp_wrapup(void) { if (tfp) osclose(tfp); osfinish(); #ifdef CMTSTUFF EXIT(0); #else exit(0); #endif } nyquist-3.05/xlisp/extern.c0000644000175000000620000001110411524127024014766 0ustar stevestaff/* extern.c - external type support for xlisp 2.0 */ /* Description of external types: A new node type EXTERN has been created to allow extensions to the xlisp type system. If a node is of type EXTERN then it contains two fields: (1) a pointer to a type descriptor, and (2) a value which is normally a pointer to an instance of the data type. The type descriptor has 6 fields: type_name: a string name for the type type_symbol: a pointer to a symbol whose print name is type_name free_meth: routine to call when the node is freed print_meth: routine to call to print the node save_meth: routine to save the value to a file restore_meth: routine to restore the value from a file The routine create_desc() is used to allocate and initialize a type descriptor. There should be only one type descriptor for each unique type. Typically, the module that manages a type will create the type descriptor at initialization time. The routine cvextern() is used to combine a type descriptor and a value to create an EXTERN node that can be used by xlisp. This routine is called whenever a new value is allocated and returned to xlisp. The routine exttype() returns the type symbol for an EXTERN type. The routine exttypep() tests for a type match. If EXTERN objects are dynamically allocated and freed, then there should only be one EXTERN node whose value field (xe_inst) points to the object. If there is more than one node (normally created only by cvextern), then one of the following should hold: 1. the object is not dynamically freed. 2. the object is reference counted and freed when the last EXTERN node is gc'd. 3. the object will be freed when the first node pointing to it is gc'd, resulting in a dangling pointer bug. The save and restore capability of xlisp version 2.0 causes some difficulties in that symbols get relocated whenever a workspace is loaded. However, type descriptors must point to symbols and type descriptors must be present in order to load external types from a workspace. My solution to this problem is to store a string name for each type and also to cache a pointer to the corresponding symbol. The cache is invalidated whenever a workspace is loaded (causing symbols to be reallocated). To make it possible to save and restore references to type descriptors, all type descriptors are kept in static storage. Internally, they are referenced by pointers, but when saved, an integer index is used. Because of the integer index, types must always be allocated in the same order. This is taken care of in localinit(). */ #include "xlisp.h" #include "extern.h" int extindex = 0; struct xtype_desc_struct desc_table[NTYPES]; /* create_desc - create a new external type */ /**/ xtype_desc create_desc( char *type_name, /* the type string name */ void (*fm)(void*), /* method to free instances of the type */ void (*pm)(void*, void*), /* method to print instances of the type */ void (*sm)(FILE*, void*), /* method to save instances of the type */ unsigned char * (*rm)(FILE*), /* method to restore instances of the type */ void (*mm)(void*)) /* method to mark instances of the type for GC */ { xtype_desc td; /* the new type descriptor */ if (extindex >= NTYPES) xlfail("insufficient type desc space"); td = &desc_table[extindex++]; td->type_name = type_name; td->type_symbol = NULL; td->free_meth = fm; td->print_meth = pm; td->save_meth = sm; td->restore_meth = rm; td->mark_meth = mm; return td; } /* cvextern - create an instance of some type */ /**/ LVAL cvextern(typeptr, instptr) xtype_desc typeptr; /* pointer to type descriptor */ unsigned char *instptr; /* pointer to the data */ { LVAL xnode; /* the resulting lisp node */ xnode = newnode(EXTERN); setdesc(xnode, typeptr); setinst(xnode, instptr); return xnode; } /* exttype -- get the type of an EXTERN */ /**/ LVAL exttype(x) LVAL x; { if (!(getdesc(x)->type_symbol)) { getdesc(x)->type_symbol = xlenter(getdesc(x)->type_name); } return getdesc(x)->type_symbol; } /* exttypep -- test for type match */ /* * x is a node, type_sym is a symbol */ int exttypep(LVAL x, LVAL type_sym) { if ((x) && ntype(x) == EXTERN) { if (!(getdesc(x)->type_symbol)) { getdesc(x)->type_symbol = xlenter(getdesc(x)->type_name); } return (getdesc(x)->type_symbol == type_sym); } return FALSE; } /* inval_caches -- set type_symbol fields to NULL */ /**/ void inval_caches() { int i; for (i = 0; i < extindex; i++) { desc_table[i].type_symbol = NULL; } } nyquist-3.05/xlisp/xlio.c0000644000175000000620000001233111466723256014455 0ustar stevestaff/* xlio - xlisp i/o routines */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "xlisp.h" /* external variables */ extern LVAL s_stdin,s_stdout,s_stderr,s_debugio,s_traceout,s_unbound; extern int xlfsize; #ifdef DEBUG_INPUT extern FILE *read_by_xlisp; #endif /* xlgetc - get a character from a file or stream */ int xlgetc(LVAL fptr) { LVAL lptr, cptr=NULL; FILE *fp; int ch; /* check for input from nil */ if (fptr == NIL) ch = EOF; /* otherwise, check for input from a stream */ else if (ustreamp(fptr)) { if ((lptr = gethead(fptr)) == NIL) ch = EOF; else { if (!consp(lptr) || (cptr = car(lptr)) == NIL || !charp(cptr)) xlfail("bad stream"); sethead(fptr,lptr = cdr(lptr)); if (lptr == NIL) settail(fptr,NIL); ch = getchcode(cptr); } } /* otherwise, check for a buffered character */ else if ((ch = getsavech(fptr))) setsavech(fptr,'\0'); /* otherwise, check for terminal input or file input */ else { fp = getfile(fptr); if (fp == stdin || fp == STDERR) ch = ostgetc(); else ch = osagetc(fp); #ifdef DEBUG_INPUT if (read_by_xlisp && ch != -1) { putc(ch, read_by_xlisp); } #endif } /* return the character */ return (ch); } /* xlungetc - unget a character */ void xlungetc(LVAL fptr, int ch) { LVAL lptr; /* check for ungetc from nil */ if (fptr == NIL) ; /* otherwise, check for ungetc to a stream */ if (ustreamp(fptr)) { if (ch != EOF) { lptr = cons(cvchar(ch),gethead(fptr)); if (gethead(fptr) == NIL) settail(fptr,lptr); sethead(fptr,lptr); } } /* otherwise, it must be a file */ else setsavech(fptr,ch); } /* xlpeek - peek at a character from a file or stream */ int xlpeek(LVAL fptr) { LVAL lptr, cptr=NULL; int ch; /* check for input from nil */ if (fptr == NIL) ch = EOF; /* otherwise, check for input from a stream */ else if (ustreamp(fptr)) { if ((lptr = gethead(fptr)) == NIL) ch = EOF; else { if (!consp(lptr) || (cptr = car(lptr)) == NIL || !charp(cptr)) xlfail("bad stream"); ch = getchcode(cptr); } } /* otherwise, get the next file character and save it */ else { ch = xlgetc(fptr); setsavech(fptr,ch); } /* return the character */ return (ch); } /* xlputc - put a character to a file or stream */ void xlputc(LVAL fptr, int ch) { LVAL lptr; FILE *fp; /* count the character */ ++xlfsize; /* check for output to nil */ if (fptr == NIL) ; /* otherwise, check for output to an unnamed stream */ else if (ustreamp(fptr)) { lptr = consa(cvchar(ch)); if (gettail(fptr)) rplacd(gettail(fptr),lptr); else sethead(fptr,lptr); settail(fptr,lptr); } /* otherwise, check for terminal output or file output */ else { fp = getfile(fptr); if (!fp) xlfail("file not open"); else if (fp == stdout || fp == STDERR) ostputc(ch); else osaputc(ch,fp); } } /* xloutflush -- flush output buffer */ void xloutflush(LVAL fptr) { FILE *fp; /* check for output to nil or unnamed stream */ if (fptr == NIL || ustreamp(fptr)) ; /* otherwise, check for terminal output or file output */ else { fp = getfile(fptr); if (!fp) xlfail("file not open"); else if (fp == stdout || fp == STDERR) ostoutflush(); else osoutflush(fp); } } /* xlflush - flush the input buffer */ void xlflush(void) { osflush(); } /* stdprint - print to *standard-output* */ void stdprint(LVAL expr) { xlprint(getvalue(s_stdout),expr,TRUE); xlterpri(getvalue(s_stdout)); } /* stdputstr - print a string to *standard-output* */ void stdputstr(char *str) { xlputstr(getvalue(s_stdout),str); } /* stdflush - flush the *standard-output* buffer */ void stdflush() { xloutflush(getvalue(s_stdout)); } /* errprint - print to *error-output* */ void errprint(LVAL expr) { xlprint(getvalue(s_stderr),expr,TRUE); xlterpri(getvalue(s_stderr)); } /* errputstr - print a string to *error-output* */ void errputstr(char *str) { xlputstr(getvalue(s_stderr),str); } /* dbgprint - print to *debug-io* */ void dbgprint(LVAL expr) { xlprint(getvalue(s_debugio),expr,TRUE); xlterpri(getvalue(s_debugio)); } /* dbgputstr - print a string to *debug-io* */ void dbgputstr(char *str) { xlputstr(getvalue(s_debugio),str); } /* trcprin1 - print to *trace-output* */ void trcprin1(LVAL expr) { xlprint(getvalue(s_traceout),expr,TRUE); } /* trcputstr - print a string to *trace-output* */ void trcputstr(char *str) { xlputstr(getvalue(s_traceout),str); } nyquist-3.05/xlisp/xldbug.c0000644000175000000620000001231211466723256014766 0ustar stevestaff/* xldebug - xlisp debugging support */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "stdlib.h" #include "xlisp.h" /* forward declarations */ FORWARD LVAL stacktop(void); FORWARD LOCAL void breakloop(char *hdr, char *cmsg, char *emsg, LVAL arg, int cflag); /* xlabort - xlisp serious error handler */ void xlabort(char *emsg) { xlsignal(emsg,s_unbound); xlerrprint("error",(char *) NULL,emsg,s_unbound); xlbrklevel(); } /* xlbreak - enter a break loop */ void xlbreak(char *emsg, LVAL arg) { breakloop("break","return from BREAK",emsg,arg,TRUE); } /* xlfail - xlisp error handler */ void xlfail(char *emsg) { xlerror(emsg,s_unbound); } /* close_loadingfiles - close files we were loading from */ void close_loadingfiles() { /* close open files that are being loaded so that user can overwrite bug fixes immediately. (Windows locks files until they are closed.) */ while (consp(getvalue(s_loadingfiles)) && consp(cdr(getvalue(s_loadingfiles))) && streamp(car(cdr(getvalue(s_loadingfiles)))) && getfile(car(cdr(getvalue(s_loadingfiles))))) { osclose(getfile(car(cdr(getvalue(s_loadingfiles))))); /* make the file NULL so GC will not close it again */ setfile(car(cdr(getvalue(s_loadingfiles))), NULL); setvalue(s_loadingfiles, cdr(cdr(getvalue(s_loadingfiles)))); } } /* xlerror - handle a fatal error */ void xlerror(char *emsg, LVAL arg) { close_loadingfiles(); if (getvalue(s_breakenable) != NIL) breakloop("error",NULL,emsg,arg,FALSE); else { xlsignal(emsg,arg); xlerrprint("error",NULL,emsg,arg); xlbrklevel(); } } /* xlcerror - handle a recoverable error */ void xlcerror(char *cmsg, char *emsg, LVAL arg) { if (getvalue(s_breakenable) != NIL) breakloop("error",cmsg,emsg,arg,TRUE); else { xlsignal(emsg,arg); xlerrprint("error",NULL,emsg,arg); xlbrklevel(); } } /* xlerrprint - print an error message */ void xlerrprint(char *hdr, char *cmsg, char *emsg, LVAL arg) { /* print the error message */ sprintf(buf,"%s: %s",hdr,emsg); errputstr(buf); /* print the argument */ if (arg != s_unbound) { errputstr(" - "); errprint(arg); } /* no argument, just end the line */ else errputstr("\n"); /* print the continuation message */ if (cmsg) { sprintf(buf,"if continued: %s\n",cmsg); errputstr(buf); } } /* breakloop - the debug read-eval-print loop */ LOCAL void breakloop(char *hdr, char *cmsg, char *emsg, LVAL arg, int cflag) { LVAL expr,val; XLCONTEXT cntxt; int type; /* print the error message */ xlerrprint(hdr,cmsg,emsg,arg); /* flush the input buffer */ xlflush(); /* do the back trace */ if (getvalue(s_tracenable)) { val = getvalue(s_tlimit); xlbaktrace(fixp(val) ? (int)getfixnum(val) : -1); } /* protect some pointers */ xlsave1(expr); /* increment the debug level */ ++xldebug; /* debug command processing loop */ xlbegin(&cntxt,CF_BRKLEVEL|CF_CLEANUP|CF_CONTINUE,s_true); for (type = 0; type == 0; ) { /* setup the continue trap */ if ((type = setjmp(cntxt.c_jmpbuf))) switch (type) { case CF_CLEANUP: continue; case CF_BRKLEVEL: type = 0; break; case CF_CONTINUE: if (cflag) { dbgputstr("[ continue from break loop ]\n"); continue; } else xlabort("this error can't be continued"); } #ifndef READ_LINE /* print a prompt */ sprintf(buf,"%d> ",xldebug); dbgputstr(buf); #endif /* read an expression and check for eof */ if (!xlread(getvalue(s_debugio),&expr,FALSE)) { type = CF_CLEANUP; #ifdef READ_LINE dbgputstr("\n"); #endif break; } /* save the input expression */ xlrdsave(expr); /* evaluate the expression */ expr = xleval(expr); /* save the result */ xlevsave(expr); /* print it */ dbgprint(expr); } xlend(&cntxt); /* decrement the debug level */ --xldebug; /* restore the stack */ xlpop(); /* check for aborting to the previous level */ if (type == CF_CLEANUP) xlbrklevel(); } /* baktrace - do a back trace */ void xlbaktrace(int n) { LVAL *fp,*p; int argc; for (fp = xlfp; (n < 0 || n--) && *fp; fp = fp - (int)getfixnum(*fp)) { p = fp + 1; errputstr("Function: "); errprint(*p++); if ((argc = (int)getfixnum(*p++))) errputstr("Arguments:\n"); while (--argc >= 0) { errputstr(" "); errprint(*p++); } } } /* xldinit - debug initialization routine */ void xldinit(void) { xlsample = 0; xldebug = 0; } nyquist-3.05/xlisp/xljump.c0000644000175000000620000001017210144436365015014 0ustar stevestaff/* xljump - execution context routines */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ #include "xlisp.h" /* external variables */ extern XLCONTEXT *xlcontext,*xltarget; extern LVAL xlvalue,xlenv,xlfenv,xldenv; extern int xlmask; LOCAL void findandjump(int mask, char *error); /* xlbegin - beginning of an execution context */ void xlbegin(XLCONTEXT *cptr, int flags, LVAL expr) { cptr->c_flags = flags; cptr->c_expr = expr; cptr->c_xlstack = xlstack; cptr->c_xlenv = xlenv; cptr->c_xlfenv = xlfenv; cptr->c_xldenv = xldenv; cptr->c_xlcontext = xlcontext; cptr->c_xlargv = xlargv; cptr->c_xlargc = xlargc; cptr->c_xlfp = xlfp; cptr->c_xlsp = xlsp; xlcontext = cptr; } /* xlend - end of an execution context */ void xlend(XLCONTEXT *cptr) { xlcontext = cptr->c_xlcontext; } /* xlgo - go to a label */ void xlgo(LVAL label) { XLCONTEXT *cptr; LVAL *argv; int argc; /* find a tagbody context */ for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext) if (cptr->c_flags & CF_GO) { argc = cptr->c_xlargc; argv = cptr->c_xlargv; while (--argc >= 0) if (*argv++ == label) { cptr->c_xlargc = argc; cptr->c_xlargv = argv; xljump(cptr,CF_GO,NIL); } } xlfail("no target for GO"); } /* xlreturn - return from a block */ void xlreturn(LVAL name, LVAL val) { XLCONTEXT *cptr; /* find a block context */ for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext) if (cptr->c_flags & CF_RETURN && cptr->c_expr == name) xljump(cptr,CF_RETURN,val); xlfail("no target for RETURN"); } /* xlthrow - throw to a catch */ void xlthrow(LVAL tag, LVAL val) { XLCONTEXT *cptr; /* find a catch context */ for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext) if ((cptr->c_flags & CF_THROW) && cptr->c_expr == tag) xljump(cptr,CF_THROW,val); xlfail("no target for THROW"); } /* xlsignal - signal an error */ void xlsignal(char *emsg, LVAL arg) { XLCONTEXT *cptr; /* find an error catcher */ for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext) if (cptr->c_flags & CF_ERROR) { if (cptr->c_expr && emsg) xlerrprint("error",NULL,emsg,arg); xljump(cptr,CF_ERROR,NIL); } } /* xltoplevel - go back to the top level */ void xltoplevel(void) { close_loadingfiles(); stdputstr("[ back to top level ]\n"); findandjump(CF_TOPLEVEL,"no top level"); } /* xlbrklevel - go back to the previous break level */ void xlbrklevel(void) { findandjump(CF_BRKLEVEL,"no previous break level"); } /* xlcleanup - clean-up after an error */ void xlcleanup(void) { stdputstr("[ back to previous break level ]\n"); findandjump(CF_CLEANUP,"not in a break loop"); } /* xlcontinue - continue from an error */ void xlcontinue(void) { findandjump(CF_CONTINUE,"not in a break loop"); } /* xljump - jump to a saved execution context */ void xljump(XLCONTEXT *target, int mask, LVAL val) { /* unwind the execution stack */ for (; xlcontext != target; xlcontext = xlcontext->c_xlcontext) /* check for an UNWIND-PROTECT */ if ((xlcontext->c_flags & CF_UNWIND)) { xltarget = target; xlmask = mask; break; } /* restore the state */ xlstack = xlcontext->c_xlstack; xlenv = xlcontext->c_xlenv; xlfenv = xlcontext->c_xlfenv; xlunbind(xlcontext->c_xldenv); xlargv = xlcontext->c_xlargv; xlargc = xlcontext->c_xlargc; xlfp = xlcontext->c_xlfp; xlsp = xlcontext->c_xlsp; xlvalue = val; /* call the handler */ longjmp(xlcontext->c_jmpbuf,mask); } /* findandjump - find a target context frame and jump to it */ LOCAL void findandjump(int mask, char *error) { XLCONTEXT *cptr; /* find a block context */ for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext) if (cptr->c_flags & mask) xljump(cptr,mask,NIL); xlabort(error); } nyquist-3.05/xlisp/xlpp.c0000644000175000000620000000464610144436365014471 0ustar stevestaff/* xlpp.c - xlisp pretty printer */ /* Copyright (c) 1985, by David Betz All Rights Reserved */ #include "xlisp.h" /* external variables */ extern LVAL s_stdout; extern int xlfsize; /* local variables */ static int pplevel,ppmargin,ppmaxlen; static LVAL ppfile; LOCAL void pp(LVAL expr); LOCAL void ppterpri(void); LOCAL void pplist(LVAL expr); LOCAL void ppexpr(LVAL expr); LOCAL int flatsize(LVAL expr); LOCAL void ppputc(int ch); /* xpp - pretty-print an expression */ LVAL xpp(void) { LVAL expr; /* get expression to print and file pointer */ expr = xlgetarg(); ppfile = (moreargs() ? xlgetfile() : getvalue(s_stdout)); xllastarg(); /* pretty print the expression */ pplevel = ppmargin = 0; ppmaxlen = 40; pp(expr); ppterpri(); /* return nil */ return (NIL); } /* pp - pretty print an expression */ LOCAL void pp(LVAL expr) { if (consp(expr)) pplist(expr); else ppexpr(expr); } /* pplist - pretty print a list */ LOCAL void pplist(LVAL expr) { int n; /* if the expression will fit on one line, print it on one */ if ((n = flatsize(expr)) < ppmaxlen) { xlprint(ppfile,expr,TRUE); pplevel += n; } /* otherwise print it on several lines */ else { n = ppmargin; ppputc('('); if (atomp(car(expr))) { ppexpr(car(expr)); ppputc(' '); ppmargin = pplevel; expr = cdr(expr); } else ppmargin = pplevel; for (; consp(expr); expr = cdr(expr)) { pp(car(expr)); if (consp(cdr(expr))) ppterpri(); } if (expr != NIL) { ppputc(' '); ppputc('.'); ppputc(' '); ppexpr(expr); } ppputc(')'); ppmargin = n; } } /* ppexpr - print an expression and update the indent level */ LOCAL void ppexpr(LVAL expr) { xlprint(ppfile,expr,TRUE); pplevel += flatsize(expr); } /* ppputc - output a character and update the indent level */ LOCAL void ppputc(int ch) { xlputc(ppfile,ch); pplevel++; } /* ppterpri - terminate the print line and indent */ LOCAL void ppterpri(void) { xlterpri(ppfile); for (pplevel = 0; pplevel < ppmargin; pplevel++) xlputc(ppfile,' '); } /* flatsize - compute the flat size of an expression */ LOCAL int flatsize(LVAL expr) { xlfsize = 0; xlprint(NIL,expr,TRUE); return (xlfsize); } nyquist-3.05/xlisp/xlmath.c0000644000175000000620000003043711466723256015006 0ustar stevestaff/* xlmath - xlisp built-in arithmetic functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings */ #include "xlisp.h" #include /* external variables */ extern LVAL s_true; /* forward declarations */ FORWARD LOCAL LVAL unary(int fcn); FORWARD LOCAL LVAL binary(int fcn); FORWARD LOCAL LVAL predicate(int fcn); FORWARD LOCAL LVAL compare(int fcn); FORWARD LOCAL void badiop(void); FORWARD LOCAL void badfop(void); /* binary functions */ LVAL xadd(void) { return (binary('+')); } /* + */ LVAL xsub(void) { return (binary('-')); } /* - */ LVAL xmul(void) { return (binary('*')); } /* * */ LVAL xdiv(void) { return (binary('/')); } /* / */ LVAL xrem(void) { return (binary('%')); } /* rem */ LVAL xmin(void) { return (binary('m')); } /* min */ LVAL xmax(void) { return (binary('M')); } /* max */ LVAL xexpt(void) { return (binary('E')); } /* expt */ LVAL xlogand(void) { return (binary('&')); } /* logand */ LVAL xlogior(void) { return (binary('|')); } /* logior */ LVAL xlogxor(void) { return (binary('^')); } /* logxor */ LVAL xatan(void) { return (binary('A')); } /* atan */ /* xgcd - greatest common divisor */ LVAL xgcd(void) { FIXTYPE m,n,r; LVAL arg; if (!moreargs()) /* check for identity case */ return (cvfixnum((FIXTYPE)0)); arg = xlgafixnum(); n = getfixnum(arg); if (n < (FIXTYPE)0) n = -n; /* absolute value */ while (moreargs()) { arg = xlgafixnum(); m = getfixnum(arg); if (m < (FIXTYPE)0) m = -m; /* absolute value */ for (;;) { /* euclid's algorithm */ r = m % n; if (r == (FIXTYPE)0) break; m = n; n = r; } } return (cvfixnum(n)); } /* binary - handle binary operations */ LOCAL LVAL binary(int fcn) { FIXTYPE ival=0,iarg=0; FLOTYPE fval=0,farg=0; LVAL arg; int mode=0; /* get the first argument */ arg = xlgetarg(); /* set the type of the first argument */ if (fixp(arg)) { ival = getfixnum(arg); mode = 'I'; } else if (floatp(arg)) { fval = getflonum(arg); mode = 'F'; } else xlerror("bad argument type",arg); /* treat a single argument as a special case */ if (!moreargs()) { switch (fcn) { case '-': switch (mode) { case 'I': ival = -ival; break; case 'F': fval = -fval; break; } break; case '/': switch (mode) { case 'I': checkizero(ival); ival = 1 / ival; break; case 'F': checkfzero(fval); fval = 1.0 / fval; break; } break; case 'A': switch (mode) { case 'I': mode = 'F'; fval = ival; case 'F': fval = atan(fval); break; } break; } } /* handle each remaining argument */ while (moreargs()) { /* get the next argument */ arg = xlgetarg(); /* check its type */ if (fixp(arg)) { switch (mode) { case 'I': iarg = getfixnum(arg); break; case 'F': farg = (FLOTYPE)getfixnum(arg); break; } } else if (floatp(arg)) { switch (mode) { case 'I': fval = (FLOTYPE)ival; farg = getflonum(arg); mode = 'F'; break; case 'F': farg = getflonum(arg); break; } } else xlerror("bad argument type",arg); /* accumulate the result value */ switch (mode) { case 'I': switch (fcn) { case '+': ival += iarg; break; case '-': ival -= iarg; break; case '*': ival *= iarg; break; case '/': checkizero(iarg); ival /= iarg; break; case '%': checkizero(iarg); ival %= iarg; break; case 'M': if (iarg > ival) ival = iarg; break; case 'm': if (iarg < ival) ival = iarg; break; case '&': ival &= iarg; break; case '|': ival |= iarg; break; case '^': ival ^= iarg; break; case 'A': fval = atan2((double) ival, (double) iarg); mode = 'F'; xllastarg(); break; default: badiop(); } break; case 'F': switch (fcn) { case '+': fval += farg; break; case '-': fval -= farg; break; case '*': fval *= farg; break; case '/': checkfzero(farg); fval /= farg; break; case 'M': if (farg > fval) fval = farg; break; case 'm': if (farg < fval) fval = farg; break; case 'E': fval = pow(fval,farg); break; case 'A': fval = atan2(fval, farg); xllastarg(); break; default: badfop(); } break; } } /* return the result */ switch (mode) { case 'I': return (cvfixnum(ival)); case 'F': return (cvflonum(fval)); } /* This shouldn't fall through, but just in case, this will catch it and make the compiler happy... */ xlerror("bad argument type",arg); return NULL; } /* checkizero - check for integer division by zero */ void checkizero(FIXTYPE iarg) { if (iarg == 0) xlfail("division by zero"); } /* checkfzero - check for floating point division by zero */ void checkfzero(FLOTYPE farg) { if (farg == 0.0) xlfail("division by zero"); } /* checkfneg - check for square root of a negative number */ void checkfneg(FLOTYPE farg) { if (farg < 0.0) xlfail("square root of a negative number"); } /* real-random */ LVAL xrealrand(void) { xllastarg(); return cvflonum(xlrealrand()); } /* unary functions */ LVAL xlognot(void) { return (unary('~')); } /* lognot */ LVAL xabs(void) { return (unary('A')); } /* abs */ LVAL xadd1(void) { return (unary('+')); } /* 1+ */ LVAL xsub1(void) { return (unary('-')); } /* 1- */ LVAL xsin(void) { return (unary('S')); } /* sin */ LVAL xcos(void) { return (unary('C')); } /* cos */ LVAL xtan(void) { return (unary('T')); } /* tan */ LVAL xexp(void) { return (unary('E')); } /* exp */ LVAL xsqrt(void) { return (unary('R')); } /* sqrt */ LVAL xfix(void) { return (unary('I')); } /* truncate */ LVAL xfloat(void) { return (unary('F')); } /* float */ LVAL xrand(void) { return (unary('?')); } /* random */ /* unary - handle unary operations */ LOCAL LVAL unary(int fcn) { FLOTYPE fval; FIXTYPE ival; LVAL arg; /* get the argument */ arg = xlgetarg(); xllastarg(); /* check its type */ if (fixp(arg)) { ival = getfixnum(arg); switch (fcn) { case '~': ival = ~ival; break; case 'A': ival = (ival < 0 ? -ival : ival); break; case '+': ival++; break; case '-': ival--; break; case 'I': break; case 'F': return (cvflonum((FLOTYPE)ival)); case '?': ival = (FIXTYPE)xlrand((int)ival); break; default: badiop(); } return (cvfixnum(ival)); } else if (floatp(arg)) { fval = getflonum(arg); switch (fcn) { case 'A': fval = (fval < 0.0 ? -fval : fval); break; case '+': fval += 1.0; break; case '-': fval -= 1.0; break; case 'S': fval = sin(fval); break; case 'C': fval = cos(fval); break; case 'T': fval = tan(fval); break; case 'E': fval = exp(fval); break; case 'R': checkfneg(fval); fval = sqrt(fval); break; case 'I': return (cvfixnum((FIXTYPE)fval)); case 'F': break; default: badfop(); } return (cvflonum(fval)); } else { xlerror("bad argument type",arg); return NULL; } } /* unary predicates */ LVAL xminusp(void) { return (predicate('-')); } /* minusp */ LVAL xzerop(void) { return (predicate('Z')); } /* zerop */ LVAL xplusp(void) { return (predicate('+')); } /* plusp */ LVAL xevenp(void) { return (predicate('E')); } /* evenp */ LVAL xoddp(void) { return (predicate('O')); } /* oddp */ /* predicate - handle a predicate function */ LOCAL LVAL predicate(int fcn) { FLOTYPE fval; FIXTYPE ival=0; LVAL arg; /* get the argument */ arg = xlgetarg(); xllastarg(); /* check the argument type */ if (fixp(arg)) { ival = getfixnum(arg); switch (fcn) { case '-': ival = (ival < 0); break; case 'Z': ival = (ival == 0); break; case '+': ival = (ival > 0); break; case 'E': ival = ((ival & 1) == 0); break; case 'O': ival = ((ival & 1) != 0); break; default: badiop(); } } else if (floatp(arg)) { fval = getflonum(arg); switch (fcn) { case '-': ival = (fval < 0); break; case 'Z': ival = (fval == 0); break; case '+': ival = (fval > 0); break; default: badfop(); } } else xlerror("bad argument type",arg); /* return the result value */ return (ival ? s_true : NIL); } /* comparison functions */ LVAL xlss(void) { return (compare('<')); } /* < */ LVAL xleq(void) { return (compare('L')); } /* <= */ LVAL xequ(void) { return (compare('=')); } /* = */ LVAL xneq(void) { return (compare('#')); } /* /= */ LVAL xgeq(void) { return (compare('G')); } /* >= */ LVAL xgtr(void) { return (compare('>')); } /* > */ /* compare - common compare function */ LOCAL LVAL compare(int fcn) { FIXTYPE icmp,ival=0,iarg=0; FLOTYPE fcmp,fval=0,farg=0; LVAL arg; int mode=0; /* get the first argument */ arg = xlgetarg(); /* set the type of the first argument */ if (fixp(arg)) { ival = getfixnum(arg); mode = 'I'; } else if (floatp(arg)) { fval = getflonum(arg); mode = 'F'; } else xlerror("bad argument type",arg); /* handle each remaining argument */ for (icmp = TRUE; icmp && moreargs(); ival = iarg, fval = farg) { /* get the next argument */ arg = xlgetarg(); /* check its type */ if (fixp(arg)) { switch (mode) { case 'I': iarg = getfixnum(arg); break; case 'F': farg = (FLOTYPE)getfixnum(arg); break; } } else if (floatp(arg)) { switch (mode) { case 'I': fval = (FLOTYPE)ival; farg = getflonum(arg); mode = 'F'; break; case 'F': farg = getflonum(arg); break; } } else xlerror("bad argument type",arg); /* compute result of the compare */ switch (mode) { case 'I': icmp = ival - iarg; switch (fcn) { case '<': icmp = (icmp < 0); break; case 'L': icmp = (icmp <= 0); break; case '=': icmp = (icmp == 0); break; case '#': icmp = (icmp != 0); break; case 'G': icmp = (icmp >= 0); break; case '>': icmp = (icmp > 0); break; } break; case 'F': fcmp = fval - farg; switch (fcn) { case '<': icmp = (fcmp < 0.0); break; case 'L': icmp = (fcmp <= 0.0); break; case '=': icmp = (fcmp == 0.0); break; case '#': icmp = (fcmp != 0.0); break; case 'G': icmp = (fcmp >= 0.0); break; case '>': icmp = (fcmp > 0.0); break; } break; } } /* return the result */ return (icmp ? s_true : NIL); } /* badiop - bad integer operation */ LOCAL void badiop(void) { xlfail("bad integer operation"); } /* badfop - bad floating point operation */ LOCAL void badfop(void) { xlfail("bad floating point operation"); } nyquist-3.05/xlisp/xllist.c0000644000175000000620000005127210144436365015022 0ustar stevestaff/* xllist.c - xlisp built-in list functions */ /* Copyright (c) 1985, by David Michael Betz All Rights Reserved Permission is granted for unrestricted non-commercial use */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm eliminate some compiler warnings * 28Apr03 rbd fix check in sort routine */ #include "xlisp.h" /* forward declarations */ FORWARD LOCAL LVAL cxr(char *adstr); FORWARD LOCAL LVAL nth(int carflag); FORWARD LOCAL LVAL assoc(LVAL expr, LVAL alist, LVAL fcn, int tresult); FORWARD LOCAL LVAL subst(LVAL to, LVAL from, LVAL expr, LVAL fcn, int tresult); FORWARD LOCAL LVAL sublis(LVAL alist, LVAL expr, LVAL fcn, int tresult); FORWARD LOCAL LVAL map(int carflag, int valflag); FORWARD LOCAL LVAL remif(int tresult); FORWARD LOCAL LVAL delif(int tresult); FORWARD LOCAL LVAL sortlist(LVAL list, LVAL fcn); FORWARD LOCAL void splitlist(LVAL pivot, LVAL list, LVAL *psmaller, LVAL *plarger, LVAL fcn); FORWARD LOCAL LVAL gluelists(LVAL smaller, LVAL pivot, LVAL larger); /* xcar - take the car of a cons cell */ LVAL xcar(void) { LVAL list; list = xlgalist(); xllastarg(); return (list ? car(list) : NIL); } /* xcdr - take the cdr of a cons cell */ LVAL xcdr(void) { LVAL list; list = xlgalist(); xllastarg(); return (list ? cdr(list) : NIL); } /* cxxr functions */ LVAL xcaar(void) { return (cxr("aa")); } LVAL xcadr(void) { return (cxr("da")); } LVAL xcdar(void) { return (cxr("ad")); } LVAL xcddr(void) { return (cxr("dd")); } /* cxxxr functions */ LVAL xcaaar(void) { return (cxr("aaa")); } LVAL xcaadr(void) { return (cxr("daa")); } LVAL xcadar(void) { return (cxr("ada")); } LVAL xcaddr(void) { return (cxr("dda")); } LVAL xcdaar(void) { return (cxr("aad")); } LVAL xcdadr(void) { return (cxr("dad")); } LVAL xcddar(void) { return (cxr("add")); } LVAL xcdddr(void) { return (cxr("ddd")); } /* cxxxxr functions */ LVAL xcaaaar(void) { return (cxr("aaaa")); } LVAL xcaaadr(void) { return (cxr("daaa")); } LVAL xcaadar(void) { return (cxr("adaa")); } LVAL xcaaddr(void) { return (cxr("ddaa")); } LVAL xcadaar(void) { return (cxr("aada")); } LVAL xcadadr(void) { return (cxr("dada")); } LVAL xcaddar(void) { return (cxr("adda")); } LVAL xcadddr(void) { return (cxr("ddda")); } LVAL xcdaaar(void) { return (cxr("aaad")); } LVAL xcdaadr(void) { return (cxr("daad")); } LVAL xcdadar(void) { return (cxr("adad")); } LVAL xcdaddr(void) { return (cxr("ddad")); } LVAL xcddaar(void) { return (cxr("aadd")); } LVAL xcddadr(void) { return (cxr("dadd")); } LVAL xcdddar(void) { return (cxr("addd")); } LVAL xcddddr(void) { return (cxr("dddd")); } /* cxr - common car/cdr routine */ LOCAL LVAL cxr(char *adstr) { LVAL list; /* get the list */ list = xlgalist(); xllastarg(); /* perform the car/cdr operations */ while (*adstr && consp(list)) list = (*adstr++ == 'a' ? car(list) : cdr(list)); /* make sure the operation succeeded */ if (*adstr && list) xlfail("bad argument"); /* return the result */ return (list); } /* xcons - construct a new list cell */ LVAL xcons(void) { LVAL arg1,arg2; /* get the two arguments */ arg1 = xlgetarg(); arg2 = xlgetarg(); xllastarg(); /* construct a new list element */ return (cons(arg1,arg2)); } /* xlist - built a list of the arguments */ LVAL xlist(void) { LVAL last=NULL,next,val; /* protect some pointers */ xlsave1(val); /* add each argument to the list */ for (val = NIL; moreargs(); ) { /* append this argument to the end of the list */ next = consa(nextarg()); if (val) rplacd(last,next); else val = next; last = next; } /* restore the stack */ xlpop(); /* return the list */ return (val); } /* xappend - built-in function append */ LVAL xappend(void) { LVAL list,last=NULL,next,val; /* protect some pointers */ xlsave1(val); /* initialize */ val = NIL; /* append each argument */ if (moreargs()) { while (xlargc > 1) { /* append each element of this list to the result list */ for (list = nextarg(); consp(list); list = cdr(list)) { next = consa(car(list)); if (val) rplacd(last,next); else val = next; last = next; } } /* handle the last argument */ if (val) rplacd(last,nextarg()); else val = nextarg(); } /* restore the stack */ xlpop(); /* return the list */ return (val); } /* xreverse - built-in function reverse */ LVAL xreverse(void) { LVAL list,val; /* protect some pointers */ xlsave1(val); /* get the list to reverse */ list = xlgalist(); xllastarg(); /* append each element to the head of the result list */ for (val = NIL; consp(list); list = cdr(list)) val = cons(car(list),val); /* restore the stack */ xlpop(); /* return the list */ return (val); } /* xlast - return the last cons of a list */ LVAL xlast(void) { LVAL list; /* get the list */ list = xlgalist(); xllastarg(); /* find the last cons */ while (consp(list) && cdr(list)) list = cdr(list); /* return the last element */ return (list); } /* xmember - built-in function 'member' */ LVAL xmember(void) { LVAL x,list,fcn,val; int tresult; /* protect some pointers */ xlsave1(fcn); /* get the expression to look for and the list */ x = xlgetarg(); list = xlgalist(); xltest(&fcn,&tresult); /* look for the expression */ for (val = NIL; consp(list); list = cdr(list)) if (dotest2(x,car(list),fcn) == tresult) { val = list; break; } /* restore the stack */ xlpop(); /* return the result */ return (val); } /* xassoc - built-in function 'assoc' */ LVAL xassoc(void) { LVAL x,alist,fcn,pair,val; int tresult; /* protect some pointers */ xlsave1(fcn); /* get the expression to look for and the association list */ x = xlgetarg(); alist = xlgalist(); xltest(&fcn,&tresult); /* look for the expression */ for (val = NIL; consp(alist); alist = cdr(alist)) if ((pair = car(alist)) && consp(pair)) if (dotest2(x,car(pair),fcn) == tresult) { val = pair; break; } /* restore the stack */ xlpop(); /* return result */ return (val); } /* xsubst - substitute one expression for another */ LVAL xsubst(void) { LVAL to,from,expr,fcn,val; int tresult; /* protect some pointers */ xlsave1(fcn); /* get the to value, the from value and the expression */ to = xlgetarg(); from = xlgetarg(); expr = xlgetarg(); xltest(&fcn,&tresult); /* do the substitution */ val = subst(to,from,expr,fcn,tresult); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* subst - substitute one expression for another */ LOCAL LVAL subst(LVAL to, LVAL from, LVAL expr, LVAL fcn, int tresult) { LVAL carval,cdrval; if (dotest2(expr,from,fcn) == tresult) return (to); else if (consp(expr)) { xlsave1(carval); carval = subst(to,from,car(expr),fcn,tresult); cdrval = subst(to,from,cdr(expr),fcn,tresult); xlpop(); return (cons(carval,cdrval)); } else return (expr); } /* xsublis - substitute using an association list */ LVAL xsublis(void) { LVAL alist,expr,fcn,val; int tresult; /* protect some pointers */ xlsave1(fcn); /* get the assocation list and the expression */ alist = xlgalist(); expr = xlgetarg(); xltest(&fcn,&tresult); /* do the substitution */ val = sublis(alist,expr,fcn,tresult); /* restore the stack */ xlpop(); /* return the result */ return (val); } /* sublis - substitute using an association list */ LOCAL LVAL sublis(LVAL alist, LVAL expr, LVAL fcn, int tresult) { LVAL carval,cdrval,pair; if ((pair = assoc(expr,alist,fcn,tresult))) return (cdr(pair)); else if (consp(expr)) { xlsave1(carval); carval = sublis(alist,car(expr),fcn,tresult); cdrval = sublis(alist,cdr(expr),fcn,tresult); xlpop(); return (cons(carval,cdrval)); } else return (expr); } /* assoc - find a pair in an association list */ LOCAL LVAL assoc(LVAL expr, LVAL alist, LVAL fcn, int tresult) { LVAL pair; for (; consp(alist); alist = cdr(alist)) if ((pair = car(alist)) && consp(pair)) if (dotest2(expr,car(pair),fcn) == tresult) return (pair); return (NIL); } /* xremove - built-in function 'remove' */ LVAL xremove(void) { LVAL x,list,fcn,val,last=NULL,next; int tresult; /* protect some pointers */ xlstkcheck(2); xlsave(fcn); xlsave(val); /* get the expression to remove and the list */ x = xlgetarg(); list = xlgalist(); xltest(&fcn,&tresult); /* remove matches */ for (; consp(list); list = cdr(list)) /* check to see if this element should be deleted */ if (dotest2(x,car(list),fcn) != tresult) { next = consa(car(list)); if (val) rplacd(last,next); else val = next; last = next; } /* restore the stack */ xlpopn(2); /* return the updated list */ return (val); } /* xremif - built-in function 'remove-if' */ LVAL xremif(void) { LVAL remif(); return (remif(TRUE)); } /* xremifnot - built-in function 'remove-if-not' */ LVAL xremifnot(void) { LVAL remif(); return (remif(FALSE)); } /* remif - common code for 'remove-if' and 'remove-if-not' */ LOCAL LVAL remif(int tresult) { LVAL list,fcn,val,last=NULL,next; /* protect some pointers */ xlstkcheck(2); xlsave(fcn); xlsave(val); /* get the expression to remove and the list */ fcn = xlgetarg(); list = xlgalist(); xllastarg(); /* remove matches */ for (; consp(list); list = cdr(list)) /* check to see if this element should be deleted */ if (dotest1(car(list),fcn) != tresult) { next = consa(car(list)); if (val) rplacd(last,next); else val = next; last = next; } /* restore the stack */ xlpopn(2); /* return the updated list */ return (val); } /* dotest1 - call a test function with one argument */ int dotest1(LVAL arg, LVAL fun) { LVAL *newfp; /* create the new call frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(cvfixnum((FIXTYPE)1)); pusharg(arg); xlfp = newfp; /* return the result of applying the test function */ return (xlapply(1) != NIL); } /* dotest2 - call a test function with two arguments */ int dotest2(LVAL arg1, LVAL arg2, LVAL fun) { LVAL *newfp; /* create the new call frame */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(cvfixnum((FIXTYPE)2)); pusharg(arg1); pusharg(arg2); xlfp = newfp; /* return the result of applying the test function */ return (xlapply(2) != NIL); } /* xnth - return the nth element of a list */ LVAL xnth(void) { return (nth(TRUE)); } /* xnthcdr - return the nth cdr of a list */ LVAL xnthcdr(void) { return (nth(FALSE)); } /* nth - internal nth function */ LOCAL LVAL nth(int carflag) { LVAL list,num; FIXTYPE n; /* get n and the list */ num = xlgafixnum(); list = xlgacons(); xllastarg(); /* make sure the number isn't negative */ if ((n = getfixnum(num)) < 0) xlfail("bad argument"); /* find the nth element */ while (consp(list) && --n >= 0) list = cdr(list); /* return the list beginning at the nth element */ return (carflag && consp(list) ? car(list) : list); } /* xlength - return the length of a list or string */ LVAL xlength(void) { FIXTYPE n=0; LVAL arg; /* get the list or string */ arg = xlgetarg(); xllastarg(); /* find the length of a list */ if (listp(arg)) for (n = 0; consp(arg); n++) arg = cdr(arg); /* find the length of a string */ else if (stringp(arg)) n = (FIXTYPE)getslength(arg)-1; /* find the length of a vector */ else if (vectorp(arg)) n = (FIXTYPE)getsize(arg); /* otherwise, bad argument type */ else xlerror("bad argument type",arg); /* return the length */ return (cvfixnum(n)); } /* xmapc - built-in function 'mapc' */ LVAL xmapc(void) { return (map(TRUE,FALSE)); } /* xmapcar - built-in function 'mapcar' */ LVAL xmapcar(void) { return (map(TRUE,TRUE)); } /* xmapl - built-in function 'mapl' */ LVAL xmapl(void) { return (map(FALSE,FALSE)); } /* xmaplist - built-in function 'maplist' */ LVAL xmaplist(void) { return (map(FALSE,TRUE)); } /* map - internal mapping function */ LOCAL LVAL map(int carflag, int valflag) { LVAL *newfp,fun,lists,val,last,p,x,y; int argc; /* protect some pointers */ xlstkcheck(3); xlsave(fun); xlsave(lists); xlsave(val); /* get the function to apply and the first list */ fun = xlgetarg(); lists = xlgalist(); /* initialize the result list */ val = (valflag ? NIL : lists); /* build a list of argument lists */ for (lists = last = consa(lists); moreargs(); last = cdr(last)) rplacd(last,cons(xlgalist(),NIL)); /* loop through each of the argument lists */ for (;;) { /* build an argument list from the sublists */ newfp = xlsp; pusharg(cvfixnum((FIXTYPE)(newfp - xlfp))); pusharg(fun); pusharg(NIL); argc = 0; for (x = lists; x && (y = car(x)) && consp(y); x = cdr(x)) { pusharg(carflag ? car(y) : y); rplaca(x,cdr(y)); ++argc; } /* quit if any of the lists were empty */ if (x) { xlsp = newfp; break; } /* apply the function to the arguments */ newfp[2] = cvfixnum((FIXTYPE)argc); xlfp = newfp; if (valflag) { p = consa(xlapply(argc)); if (val) rplacd(last,p); else val = p; last = p; } else xlapply(argc); } /* restore the stack */ xlpopn(3); /* return the last test expression value */ return (val); } /* xrplca - replace the car of a list node */ LVAL xrplca(void) { LVAL list,newcar; /* get the list and the new car */ list = xlgacons(); newcar = xlgetarg(); xllastarg(); /* replace the car */ rplaca(list,newcar); /* return the list node that was modified */ return (list); } /* xrplcd - replace the cdr of a list node */ LVAL xrplcd(void) { LVAL list,newcdr; /* get the list and the new cdr */ list = xlgacons(); newcdr = xlgetarg(); xllastarg(); /* replace the cdr */ rplacd(list,newcdr); /* return the list node that was modified */ return (list); } /* xnconc - destructively append lists */ LVAL xnconc(void) { LVAL next,last=NULL,val; /* initialize */ val = NIL; /* concatenate each argument */ if (moreargs()) { while (xlargc > 1) { /* ignore everything except lists */ if ((next = nextarg()) && consp(next)) { /* concatenate this list to the result list */ if (val) rplacd(last,next); else val = next; /* find the end of the list */ while (consp(cdr(next))) next = cdr(next); last = next; } } /* handle the last argument */ if (val) rplacd(last,nextarg()); else val = nextarg(); } /* return the list */ return (val); } /* xdelete - built-in function 'delete' */ LVAL xdelete(void) { LVAL x,list,fcn,last,val; int tresult; /* protect some pointers */ xlsave1(fcn); /* get the expression to delete and the list */ x = xlgetarg(); list = xlgalist(); xltest(&fcn,&tresult); /* delete leading matches */ while (consp(list)) { if (dotest2(x,car(list),fcn) != tresult) break; list = cdr(list); } val = last = list; /* delete embedded matches */ if (consp(list)) { /* skip the first non-matching element */ list = cdr(list); /* look for embedded matches */ while (consp(list)) { /* check to see if this element should be deleted */ if (dotest2(x,car(list),fcn) == tresult) rplacd(last,cdr(list)); else last = list; /* move to the next element */ list = cdr(list); } } /* restore the stack */ xlpop(); /* return the updated list */ return (val); } /* xdelif - built-in function 'delete-if' */ LVAL xdelif(void) { LVAL delif(); return (delif(TRUE)); } /* xdelifnot - built-in function 'delete-if-not' */ LVAL xdelifnot(void) { LVAL delif(); return (delif(FALSE)); } /* delif - common routine for 'delete-if' and 'delete-if-not' */ LOCAL LVAL delif(int tresult) { LVAL list,fcn,last,val; /* protect some pointers */ xlsave1(fcn); /* get the expression to delete and the list */ fcn = xlgetarg(); list = xlgalist(); xllastarg(); /* delete leading matches */ while (consp(list)) { if (dotest1(car(list),fcn) != tresult) break; list = cdr(list); } val = last = list; /* delete embedded matches */ if (consp(list)) { /* skip the first non-matching element */ list = cdr(list); /* look for embedded matches */ while (consp(list)) { /* check to see if this element should be deleted */ if (dotest1(car(list),fcn) == tresult) rplacd(last,cdr(list)); else last = list; /* move to the next element */ list = cdr(list); } } /* restore the stack */ xlpop(); /* return the updated list */ return (val); } /* xsort - built-in function 'sort' */ LVAL xsort(void) { LVAL sortlist(); LVAL list,fcn; /* protect some pointers */ xlstkcheck(2); xlsave(list); xlsave(fcn); /* get the list to sort and the comparison function */ list = xlgalist(); fcn = xlgetarg(); xllastarg(); /* sort the list */ list = sortlist(list,fcn); if (list && (ntype(list) == FREE_NODE)) { stdputstr("error in sort 2"); } /* restore the stack and return the sorted list */ xlpopn(2); return (list); } /* This sorting algorithm is based on a Modula-2 sort written by Richie Bielak and published in the February 1988 issue of "Computer Language" magazine in a letter to the editor. */ /* sortlist - sort a list using quicksort */ LOCAL LVAL sortlist(LVAL list, LVAL fcn) { LVAL gluelists(); LVAL smaller,pivot,larger; /* protect some pointers */ xlstkcheck(3); xlsave(smaller); xlsave(pivot); xlsave(larger); /* lists with zero or one element are already sorted */ if (consp(list) && consp(cdr(list))) { pivot = list; list = cdr(list); splitlist(pivot,list,&smaller,&larger,fcn); smaller = sortlist(smaller,fcn); larger = sortlist(larger,fcn); list = gluelists(smaller,pivot,larger); } /* cleanup the stack and return the sorted list */ xlpopn(3); return (list); } /* splitlist - split the list around the pivot */ LOCAL void splitlist(LVAL pivot, LVAL list, LVAL *psmaller, LVAL *plarger, LVAL fcn) { LVAL next; xlprot1(list); // protect list from gc // the rplacd disconnects list, and next is the only // reference to it, but next is immediately assigned to list // before dotest2 which is where gc might run. /* initialize the result lists */ *psmaller = *plarger = NIL; /* split the list */ for (; consp(list); list = next) { next = cdr(list); if (dotest2(car(list),car(pivot),fcn)) { rplacd(list,*psmaller); *psmaller = list; } else { rplacd(list,*plarger); *plarger = list; } } xlpop(); } /* gluelists - glue the smaller and larger lists with the pivot */ LOCAL LVAL gluelists(LVAL smaller, LVAL pivot, LVAL larger) { LVAL last; /* larger always goes after the pivot */ rplacd(pivot,larger); /* if the smaller list is empty, we're done */ if (null(smaller)) return (pivot); /* append the smaller to the front of the resulting list */ for (last = smaller; consp(cdr(last)); last = cdr(last)) ; rplacd(last,pivot); return (smaller); } nyquist-3.05/nyquist.vcproj0000644000175000000620000031423111512143043015122 0ustar stevestaff nyquist-3.05/cmt/0002755000175000000620000000000011537433127012756 5ustar stevestaffnyquist-3.05/cmt/midierr.h0000644000175000000620000000114510144436365014561 0ustar stevestaff/* midierr.h -- error codes */ #define NESTERR 1 /* nested interrupts */ #define BUFFOVFL 2 /* input buffer overflow */ #define CMDERR 3 /* unknown command from mpu-401 */ #define TIMEOUTERR 4 /* interface timeout */ #define MSGERR 5 /* invalid message */ #define SYSEXOVFL 6 /* sysex buffer overflow */ #define MEMERR 7 /* internal out of memory */ #define RECVERR 8 /* receive error or device buffer overflow */ #define MIDIMGRERR 9 /* error reported by midi manager (Macintosh) */ #define SYSEX_ERR ((1< #endif /* * Declare counter if necessary */ #ifdef COUNTER extern COUNTER; #endif /* * The enter routine */ #ifdef HASHPOINT HASHTYPE * #else int #endif HASHENTER (s) char *s; { register int i, hash; register hashelem *elem; /* * Compute s's hash value * I really should look up some good hash functions, but * I haven't bothered. */ for(i = 0, hash = 0; s[i] != '\0' && i < 15; i++) hash += (i + 1) * s[i]; hash %= HASHVAL; /* * search for s in the table */ for(elem = hashtab[hash]; elem != NULL; elem = elem->h_next) if(strcmp(s, HASHELEM((elem->h_elem))) == 0) { /* found it */ #ifdef HASHPOINT return(&elem->h_elem); #else return(elem - hashfirstchunk); #endif } if(hashindex >= HASHENTRIES) { #ifdef HASHPOINT char *calloc(); hashindex = 0; hashchunk = (hashelem *) calloc(HASHENTRIES, sizeof(hashelem)); if(hashchunk == NULL) { gprintf(FATAL, "No mem for hash symbol table\n"); EXIT(1); #ifdef COUNTER COUNTER++; /* optional symbol counter */ #endif } #else gprintf(FATAL, "No hash table space, increase HASHENTRIES\n"); EXIT(1); #endif } /* * Splice a new entry into the list and fill in the string field */ elem = &hashchunk[hashindex++]; elem->h_next = hashtab[hash]; hashtab[hash] = elem; #ifdef HASHNOCOPY HASHELEM((elem->h_elem)) = s; #else { char *strcpy(); HASHELEM((elem->h_elem)) = memget((strlen(s) + 1)); strcpy(HASHELEM((elem->h_elem)), s); } #endif #ifdef HASHPOINT return(&elem->h_elem); #else return(elem - hashfirstchunk); #endif } nyquist-3.05/cmt/seq.c0000644000175000000620000010727511524127024013714 0ustar stevestaff/* seq.c -- implement adagio scores as abstract data type */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 2-Apr-91 | JDW : further changes * 16-Feb-92 | GWL : use reg_timebase in seq_play() * 28-Apr-03 | DM : false->FALSE, true->TRUE, portability changes * 19-May-03 | RBD : no longer assume seq->current remains untouched between * | note inserts *****************************************************************************/ #include "stdio.h" #include "cext.h" #include "userio.h" #include "midicode.h" #include "midifns.h" #include "timebase.h" #include "moxc.h" #include "seq.h" #include "string.h" extern int moxcdebug; extern timebase_type default_base; boolean seq_print = FALSE; /* debugging print switch */ seq_type sequence; /* this is a global to be accessed by routines called * from the sequence */ /* clock state: */ time_type clock_ticksize; /* millisec per tick shifted 16 bits */ boolean clock_running = FALSE; /* TRUE if clock is running */ boolean external_midi_clock = FALSE; boolean suppress_midi_clock = FALSE; private void insert_event(seq_type, register event_type); private void process_event(seq_type); private char *chunk_alloc(seq_type seq, int size); private void clock_tick(seq_type seq, time_type fraction); private void ramp_event(seq_type seq, event_type event, unsigned int value, unsigned int to_value, int increment, time_type step, int n); /*private*/ void send_macro(register unsigned char *ptr, int voice, short parameter[], int parm_num, int value, int nline); /* chunk_alloc -- allocate data for a sequence */ /* * NOTE: This assumes one chunk is already allocated. * The first chunk holds shared sequence information in * the info struct, and by convention this is always in * the first chunk. */ private char *chunk_alloc(seq_type seq, int size) { chunk_type chunk = seq->chunklist->u.info.last_chunk; /* gprintf(TRANS, "chunk_alloc: seq %lx size %d\n", seq, size); */ if (size & 1) size++; /* make it even */ if (chunk->free + size >= CHUNK_SIZE) { chunk_type new_chunk = chunk_create(FALSE); if (!new_chunk) { gprintf(FATAL, "Out of memory while reading seq\n"); return NULL; } /* add new_chunk to chunk chain */ seq->chunklist->u.info.last_chunk = new_chunk; chunk->next = new_chunk; chunk = new_chunk; } chunk->free += size; return &(chunk->u.data[chunk->free - size]); } /* chunk_create -- create a new chunk for seq data */ /* * If this is the first chunk, set first_flag to reserve * space for the info structure. */ chunk_type chunk_create(boolean first_flag) { chunk_type result = (chunk_type) memget(sizeof(chunk_node)); if (result) { result->next = NULL; result->u.info.refcount = 1; /* pre-initialize for caller */ result->free = 0; if (first_flag) { result->free = sizeof(struct info_struct); result->u.info.last_chunk = result; result->u.info.dictionary = NULL; result->u.info.eventlist = NULL; result->u.info.ctrlcount = 0; result->u.info.notecount = 0; result->u.info.duration = 0; result->u.info.used_mask = 0; } } /* gprintf(TRANS, "chunk_create: got %lx (size %d)\n", */ /* result, sizeof(chunk_node)); */ return result; } /* clock_tick -- advance the clock and send a tick */ /**/ private void clock_tick(seq_type seq, time_type fraction) { int delay; fraction += clock_ticksize; delay = fraction >> 16; fraction &= 0xFFFF; if (seq->runflag && clock_ticksize && seq->note_enable) { midi_clock(); cause((delay_type)delay, clock_tick, seq, fraction); } else { clock_running = FALSE; midi_stop(); midi_clock(); /* stop takes effect on next clock, so provide one */ } } private void cycle(seq_type seq) { seq_reset(seq); seq_play(seq); } /**************************************************************************** * event_create * Inputs: * seq_type seq: the seq to hold the event * int size: the size of the event in bytes * time_type etime: the time of the event * int eline: the line number of the event * Returns: * event_type: a new event structure or * NULL if there is not enough memory left * Effect: * allocates memory from the chunk, then heap as needed * Implementation: * to reduce the per block storage overhead, we allocate memory in * large chunks and do our own allocation. Allocate from first * chunk first. If full, allocate a new chunk. * WARNING: this implementation assumes that individual events are never freed!! ****************************************************************************/ private event_type event_create(seq, size, etime, eline) seq_type seq; int size; time_type etime; int eline; { event_type result = (event_type) chunk_alloc(seq, size); if (result) { result->ntime = etime; result->nline = eline; /* since we know the time, we can insert now: */ insert_event(seq, result); seq_duration(seq) = MAX(seq_duration(seq), etime); } return result; } /* insert_call -- add a call event to the seq */ /**/ event_type insert_call(seq, ctime, cline, voice, addr, value, n) seq_type seq; time_type ctime; int cline; int voice; int (*addr)(); long value[SEQ_MAX_PARMS]; int n; { int i; register event_type event = event_create(seq, callsize, ctime, cline); if (seq_print) { gprintf(TRANS, "call(%lx): time %ld, line %d, voice %d, fn %lx,\n\tvalues:", event, ctime, cline, voice, addr); for (i = 0; i < n; i++) gprintf(TRANS, " %ld", value[i]); gprintf(TRANS, "\n"); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = CALL_VALUE; event->u.call.routine = addr; /* save the arguments */ for (i = 0; i < n; i++) event->u.call.args.a[i] = value[i]; seq_ctrlcount(seq)++; } return event; } /* insert_clock -- add a clock cmd to the seq */ /**/ event_type insert_clock(seq, ctime, cline, ticksize) seq_type seq; time_type ctime; int cline; time_type ticksize; { register event_type event = event_create(seq, clocksize, ctime, cline); if (seq_print) { gprintf(TRANS, "clock(%lx): time %ld, line %d\n", event, ctime, cline); } if (event) { event->nvoice = ctrl_voice(ESC_CTRL, 1); event->value = CLOCK_VALUE; event->u.clock.ticksize = ticksize; seq_ctrlcount(seq)++; } return event; } /* insert_ctrl -- add a control to the seq */ /**/ event_type insert_ctrl(seq, ctime, cline, ctrl, voice, value) seq_type seq; time_type ctime; int cline; int ctrl; int voice; int value; { register event_type event = event_create(seq, ctrlsize, ctime, cline); if (seq_print) { gprintf(TRANS, "ctrl(%lx): time %ld, line %d, ctrl %d, voice %d, value %d\n", event, ctime, cline, ctrl, voice, value); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ctrl, voice); event->value = value; seq_ctrlcount(seq)++; } return event; } /* insert_ctrlramp -- add a control ramp event to the seq */ /**/ event_type insert_ctrlramp(seq, rtime, rline, voice, step, dur, ctrl, v1, v2) seq_type seq; time_type rtime; int rline; int voice; time_type step; time_type dur; int ctrl; int v1, v2; { register event_type event = event_create(seq, ctrlrampsize, rtime, rline); if (seq_print) { gprintf(TRANS, "ctrlramp(%lx): time %ld, line %d, step %ld, dur %ld, ctrl %d, voice %d\n", event, rtime, rline, step, dur, ctrl, voice); gprintf(TRANS, "\tfrom %d to %d\n", v1, v2); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = CTRLRAMP_VALUE; if (dur <= 0) dur = 1L; /* don't allow zero duration */ event->u.ramp.dur = dur; event->u.ramp.ctrl = ctrl; if (step <= 0) step = 1; /* don't allow zero step size */ event->u.ramp.step = (short) step; event->u.ramp.u.ctrl.from_value = v1; event->u.ramp.u.ctrl.to_value = v2; seq_ctrlcount(seq)++; seq_duration(seq) = MAX(seq_duration(seq), rtime + dur); } return event; } /* insert_def -- add a definition to the dictionary */ /**/ def_type insert_def(seq, symbol, definition, deflen) seq_type seq; char *symbol; unsigned char *definition; int deflen; { int i; def_type defn = (def_type) chunk_alloc(seq, sizeof(def_node)); defn->symbol = chunk_alloc(seq, strlen(symbol) + 1); defn->definition = (unsigned char *) chunk_alloc(seq, deflen); strcpy(defn->symbol, symbol); for (i = 0; i < deflen; i++) { defn->definition[i] = definition[i]; } defn->next = seq_dictionary(seq); seq_dictionary(seq) = defn; if (seq_print) { gprintf(TRANS, "def(%ld): symbol %s defn \n", defn, symbol); for (i = 0; i < deflen; i++) gprintf(TRANS, "%x", definition[i]); gprintf(TRANS, "\n"); } return defn; } /* insert_deframp -- add a def ramp event to the seq */ /**/ event_type insert_deframp(seq, rtime, rline, voice, step, dur, def, nparms, parms, parm_num, to_value) seq_type seq; time_type rtime; int rline; int voice; time_type step; time_type dur; def_type def; int nparms; /* number of parameters for macro */ short parms[]; /* actual parameter vector */ int parm_num; /* which of the actual parameters to ramp */ int to_value; /* final destination of ramp */ { register event_type event = event_create(seq, deframpsize, rtime, rline); if (seq_print) { int i; gprintf(TRANS, "deframp(%ld): time %ld, line %d, voice %d, step %ld, dur %ld\n", event, rtime, rline, voice, step, dur); gprintf(TRANS, "def %ld, parms"); for (i = 0; i < nparms; i++) gprintf(TRANS, " %d", parms[i]); gprintf(TRANS, "parm_num %d to %d\n", parm_num, to_value); } if (event) { int i; seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = DEFRAMP_VALUE; if (dur <= 0) dur = 1L; /* don't allow zero duration */ event->u.ramp.dur = dur; event->u.ramp.ctrl = 0; if (step <= 0) step = 1; /* don't allow zero step size */ event->u.ramp.step = (short) step; event->u.ramp.u.def.definition = def->definition; for (i = 0; i < nmacroparms; i++) { event->u.ramp.u.def.parameter[i] = (i < nparms ? parms[i] : 0); } event->u.ramp.u.def.parm_num = parm_num; event->u.ramp.u.def.to_value = to_value; seq_ctrlcount(seq)++; seq_duration(seq) = MAX(seq_duration(seq), rtime + dur); } return event; } /**************************************************************************** * insert_event * Inputs: * seq_type seq: where to put the event * event_type event: the event to insert * Effect: * inserts event into the event list * NOTE: it is inserted *after* previously inserted events with the same time * Implementation: * adagio files often contain many independent voices. Although each voice * consists of events in sequence, the voices need not be inter-twined in * the input file. Rather, all the events of voice 1 appear followed by all * the events of voice 2, and so forth. As phase one merges these event * sequences, it must make many passes over an increasingly long list of * events: expensive if we always start from the beginning of the list! * we can exploit the fact that each voice is sequential by starting the * search for the proper point of insertion at the last event inserted. * the variable "last_event" is used to remember this hint. We could * also snapshot "last_event" in "ref_event" when a !tempo or !rate * command occurs as another hint, but we don't. ****************************************************************************/ private void insert_event(seq, event) seq_type seq; register event_type event; { event_type *evlptr = &(seq_eventlist(seq)); if ((*evlptr == NULL) || (event->ntime < (*evlptr)->ntime)) { /* insert at the head of the list */ event->next = *evlptr; *evlptr = event; seq->current = event; } else { /* insert somewhere after the head of the list * do not assume: current is not NULL. Although we always leave * it set, the client may access the sequence before the next * insert. */ register event_type previous; register event_type insert_before; if (!seq->current) { seq->current = seq_eventlist(seq); } if (event->ntime >= seq->current->ntime) { /* insertion point is after current */ previous = seq->current; insert_before = previous->next; } else { /* insertion point is before current; start at beginning */ /* assume: not inserting at very head of list; that would * have been taken care of above */ previous = seq_events(seq); insert_before = previous->next; } while ((insert_before != NULL) && (event->ntime >= insert_before->ntime)) { previous = insert_before; insert_before = insert_before->next; } previous->next = event; event->next = insert_before; seq->current = event; } } /* insert_macctrl -- add a control to the seq */ /**/ event_type insert_macctrl(seq, ctime, cline, ctrl, voice, value) seq_type seq; time_type ctime; int cline; int ctrl; int voice; int value; { register event_type event = event_create(seq, macctrlsize, ctime, cline); if (seq_print) { gprintf(TRANS, "macctrl(%lx): time %ld, line %d, ctrl %d, voice %d, value %d\n", event, ctime, cline, ctrl, voice, value); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = MACCTRL_VALUE; event->u.macctrl.ctrl_number = ctrl; event->u.macctrl.value = value; seq_ctrlcount(seq)++; } return event; } /* insert_macro -- insert a macro call seq */ /**/ event_type insert_macro(seq, ctime, cline, def, voice, nparms, parms) seq_type seq; time_type ctime; int cline; def_type def; int voice; int nparms; short *parms; { register event_type event = event_create(seq, macrosize, ctime, cline); if (seq_print) { int i; gprintf(TRANS, "macro(%lx): time %ld, line %d, def %ld, voice %d, parms", event, ctime, cline, def, voice); for (i = 0; i < nparms; i++) gprintf(TRANS, " %d", parms[i]); gprintf(TRANS, "\n"); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = MACRO_VALUE; event->u.macro.definition = def->definition; while (nparms-- > 0) { event->u.macro.parameter[nparms] = parms[nparms]; } seq_ctrlcount(seq)++; } return event; } /* insert_note -- add a note to the seq */ /**/ event_type insert_note(seq, ntime, nline, voice, pitch, dur, loud) seq_type seq; time_type ntime; int nline; int voice; int pitch; time_type dur; int loud; { register event_type event = event_create(seq, notesize, ntime, nline); if (seq_print) { gprintf(TRANS, "note(%lx): time %ld, line %d, dur %ld, pitch %d, voice %d, loudness %d\n", event, ntime, nline, dur, pitch, voice, loud); } if (event) { seq_used_mask(seq) |= 1 << (voice - 1); event->nvoice = voice - 1; event->value = pitch; event->u.note.ndur = (dur << 8) + loud; seq_notecount(seq)++; seq_duration(seq) = MAX(seq_duration(seq), ntime + dur); } return event; } /* insert_seti -- add a seti event to the seq */ /**/ event_type insert_seti(seq, stime, sline, voice, addr, value) seq_type seq; time_type stime; int sline; int voice; int *addr; int value; { register event_type event = event_create(seq, setisize, stime, sline); if (seq_print) { gprintf(TRANS, "seti(%ld): time %ld, line %d, voice %d, addr %ld, value %d\n", event, stime, sline, voice, addr, value); } if (event) { event->nvoice = ctrl_voice(ESC_CTRL, voice); event->value = SETI_VALUE; event->u.seti.int_to_set = addr; event->u.seti.value = value; seq_ctrlcount(seq)++; } return event; } /* noop -- just returns, the default stopfunc for sequences */ /**/ void noop(seq_type seq) {} private void process_event(seq) seq_type seq; { register event_type event; if (!seq->runflag) return; while ((event = seq->current) && (event->ntime <= virttime)) { int voice; /* process all current (and earlier) events */ if (is_note(event)) { /*** play a note or rest ***/ /* if this note is not a rest, play it and schedule an off event */ if (event->value != NO_PITCH && (seq_channel_mask(seq) & (1 << ((voice = vc_voice(event->nvoice)) - 1)))) { seq_noteon(seq, voice, event->value, (int) event->u.note.ndur & 0xFF); if (debug) { gprintf(TRANS, "play pitch %d at %ld\n", event->value, event->ntime); } seq_cause_noteoff(seq, (event->u.note.ndur) >> 8, voice, event->value); } } else { /*** send a control command ***/ int n; time_type step; int delta; long increment; int voice = vc_voice(event->nvoice); ulong enabled = seq_channel_mask(seq) & (1 << (voice - 1)); switch (vc_ctrl(event->nvoice)) { case PSWITCH_CTRL: if (!enabled) break; seq_midi_ctrl(seq, voice, PORTASWITCH, event->value); break; case MODWHEEL_CTRL: if (!enabled) break; seq_midi_ctrl(seq, voice, MODWHEEL, event->value); break; case TOUCH_CTRL: if (!enabled) break; seq_midi_touch(seq, voice, event->value); break; case VOLUME_CTRL: if (!enabled) break; seq_midi_ctrl(seq, voice, VOLUME, event->value); break; case BEND_CTRL: if (!enabled) break; seq_midi_bend(seq, voice, (event->value << 6)); break; case PROGRAM_CTRL: if (!enabled) break; seq_midi_program(seq, voice, event->value + 1); break; case ESC_CTRL: switch (event->value) { case CALL_VALUE: sequence = seq; (*(event->u.call.routine))(event->u.call.args); break; case CLOCK_VALUE: clock_ticksize = event->u.clock.ticksize; if (!clock_running && !suppress_midi_clock && !external_midi_clock) { clock_running = TRUE; midi_start(); clock_tick(seq, 0L); } break; case MACCTRL_VALUE: if (!enabled) break; seq_midi_ctrl(seq, voice, event->u.macctrl.ctrl_number, event->u.macctrl.value); break; case MACRO_VALUE: { if (!enabled) break; send_macro(event->u.macro.definition, voice, event->u.macro.parameter, -1, 0, event->nline); break; } case CTRLRAMP_VALUE: case DEFRAMP_VALUE: { int from, to; if (!enabled) break; step = event->u.ramp.step; if (event->value == CTRLRAMP_VALUE) { from = event->u.ramp.u.ctrl.from_value; to = event->u.ramp.u.ctrl.to_value; } else { from = event->u.ramp.u.def.parameter[ event->u.ramp.u.def.parm_num]; to = event->u.ramp.u.def.to_value; } delta = to - from; increment = delta; if (delta < 0) delta = -delta; /* Note: Step is always non-zero */ n = event->u.ramp.dur / step; increment = (increment << 8) / n; ramp_event(seq, event, from << 8, to << 8, (int) increment, step, n); seq->noteoff_count++; break; } case SETI_VALUE: *(event->u.seti.int_to_set) = event->u.seti.value; break; default: gprintf(TRANS, "unexpected ESC_CTRL value\n"); break; } break; default: gprintf(TRANS, "unexpected seq data\n"); break; } } seq->current = event->next; } if (seq->current) { cause((delay_type)(event->ntime - virttime), process_event, seq); } else if (seq->noteoff_count == 0 && seq->note_enable) { /* if we're just advancing to a start point, note_enable will be * FALSE and this won't get called: */ if (seq->stopfunc) { (*(seq->stopfunc))(seq); } } } /* ramp_event -- generate a ramp */ /**/ private void ramp_event(seq, event, value, to_value, increment, step, n) seq_type seq; register event_type event; unsigned int value; unsigned int to_value; int increment; time_type step; int n; { if (seq->runflag) { int voice = vc_voice(event->nvoice); /* printf("ramp_event: value %d to_value %d increment %d step %d n %d time %d\n", value, to_value, increment, step, n, virttime); */ if (n == 0) value = to_value; else { causepri((delay_type)step, 5, ramp_event, seq, event, value + increment, to_value, increment, step, n - 1); } if (event->value == CTRLRAMP_VALUE) { int ctrl = event->u.ramp.ctrl; if (ctrl == -TOUCH_CTRL) midi_touch(voice, value >> 8); else if (ctrl == -BEND_CTRL) midi_bend(voice, value >> 2); else midi_ctrl(voice, ctrl, value >> 8); } else { /* must be DEFRAMP_VALUE */ send_macro(event->u.ramp.u.def.definition, vc_voice(event->nvoice), event->u.ramp.u.def.parameter, event->u.ramp.u.def.parm_num, value >> 8, event->nline); } if (n == 0) seq_end_event(seq); } } /* report_enabled_channels -- print out concise listing of channels */ /* * to fit on one line, write out ranges, e.g. 1-5 9-11 */ void report_enabled_channels(seq) seq_type seq; { ulong mask = seq_channel_mask(seq); int i, range_open_at = 0; for (i = 1; i <= MAX_CHANNELS; i++) { if (!range_open_at && (mask & 1)) { gprintf(TRANS, " %d", i); range_open_at = i; } else if (range_open_at && !(mask & 1)) { if (i > (range_open_at + 1)) { gprintf(TRANS, "-%d", i - 1); } range_open_at = 0; /* FALSE */ } mask = mask >> 1; } if (range_open_at) gprintf(TRANS, "-%d", MAX_CHANNELS); } /* send_macro -- instantiate macro and send it */ /* * note: to support ramping, "value" is used in place of * parameter["parm_num"] */ /*private*/ void send_macro(ptr, voice, parameter, parm_num, value, nline) register unsigned char *ptr; int voice; short parameter[]; int parm_num; int value; int nline; { register unsigned char code, *loc; while ((code = *ptr++)) { loc = ptr + *ptr; ptr++; if (code <= nmacroparms) { code--; *loc = (code == parm_num ? value : parameter[code]) & 0x7f; } else if (code == nmacroparms + 1) { /* take old high order bits and OR in 4 voice bits */ *loc = (*loc & 0xF0) | ((voice - 1) & 0xF); } else { code -= (nmacroparms + 2); *loc = ((code == parm_num ? value : parameter[code]) >> 7) & 0x7F; } } if (ptr[1] == MIDI_SYSEX) { midi_exclusive(ptr + 1); } else { /* make sure user didn't try to send more than 3 bytes. This test * could be done at sequence read time, but it's tricky because the * first byte could be a parameter, so in general you need to * plug the actual parameters into the message and then do the test. * Currently, this is the only place parameters are plugged in. */ if (*ptr > 3) { gprintf(ERROR, "Non-sysex macro longer than 3 bytes ignored, line %d.\n", nline); } else { midi_write((int) *ptr, MIDI_PORT(voice), ptr[1], ptr[2], ptr[3]); } } } /* seq_alloc -- a utility function to allocate a seq struct */ /**/ seq_type seq_alloc() { seq_type seq; seq = (seq_type) memget(sizeof(seq_node)); return seq; } /* seq_at_end -- set the function to be called at sequence end */ /**/ void seq_at_end(seq, fn) seq_type seq; void (*fn)(seq_type); { if (!fn) fn = noop; seq->stopfunc = fn; } /* seq_cause_noteoff_meth -- turn off a note in the future */ /**/ void seq_cause_noteoff_meth(seq_type seq, time_type delay, int voice, int pitch) { if (seq->note_enable) { pitch += seq->transpose; while (pitch < 0) pitch += 12; while (pitch > 127) pitch -= 12; seq->noteoff_count++; causepri((delay_type) delay, 10, seq->noteoff_fn, seq, voice, pitch); } } /* seq_copy -- copy a sequence, share the eventlist */ /**/ seq_type seq_copy(from_seq) seq_type from_seq; { register seq_type seq = seq_init(seq_alloc(), FALSE); if (!seq) return NULL; seq->chunklist = from_seq->chunklist; seq->current = seq_events(seq); seq->chunklist->u.info.refcount++; seq->transpose = from_seq->transpose; seq->loudness = from_seq->loudness; seq->rate = from_seq->rate; seq->paused = from_seq->paused; seq->noteoff_count = 0; return seq; } /* seq_create -- create a seq structure and an initial event chunk */ /**/ seq_type seq_create() { return seq_init(seq_alloc(), TRUE); } /* seq_cycle -- set parameters for cycling a sequence */ /**/ void seq_cycle(seq_type seq, boolean flag, time_type dur) { seq->cycleflag = flag; seq->cycledur = dur; } /* seq_end_event -- call this when an score-generated event ends */ /* * Assumes that noteoff_count was incremented when event started. */ void seq_end_event(seq) seq_type seq; { /*gprintf(TRANS, "nd");*/ seq->noteoff_count--; if (seq->current == NULL /* finished seq */ && seq->noteoff_count == 0 /* finished noteoff's */ && seq->runflag /* we've not been stopped */) { if (seq->cycleflag) { cause((delay_type) (seq->cycledur - virttime), cycle, seq); } else if (seq->stopfunc) { (*(seq->stopfunc))(seq); } } } /**************************************************************************** * seq_free_meth * Input: a seq_type * Effect: * frees storage occupied by a seq ****************************************************************************/ private void seq_free_meth(seq) seq_type seq; { seq_free_chunks(seq); if (seq->timebase) timebase_free(seq->timebase); memfree((void *) seq, sizeof(seq_node)); } /* seq_free_chunks -- free storage for note list */ /* * NOTE: in its original form, this routine was perhaps more readable, * but would not compile under Microsoft C V7.00 due to a compiler bug. * I rewrote the code until the bug disappeared, hopefully without * changing the semantics! If you change this code, make sure it still * compiles under Microsoft C. * * This module frees chunks from a seq_type in preparation for freeing * the seq_type itself. Reference counts are checked and chunks are * only freed when the last reference is removed. */ public void seq_free_chunks(seq) seq_type seq; { chunk_type tail; chunk_type head; head = seq->chunklist; if (((head->u.info.refcount)--) != 0) return; while (head != NULL) { tail = head->next; memfree((void *) head, sizeof(chunk_node)); head = tail; seq->chunklist = head; } } seq_type seq_init(seq, create_chunk) seq_type seq; int create_chunk; { if (!seq || !(seq->timebase = timebase_create(50))) { return NULL; } seq->chunklist = NULL; if (create_chunk) { seq->chunklist = chunk_create(TRUE); if (!seq->chunklist) { seq_free(seq); return NULL; } } seq->cause_noteoff_fn = seq_cause_noteoff_meth; seq->midi_bend_fn = seq_midi_bend_meth; seq->midi_ctrl_fn = seq_midi_ctrl_meth; seq->midi_program_fn = seq_midi_program_meth; seq->midi_touch_fn = seq_midi_touch_meth; seq->noteoff_fn = seq_noteoff_meth; seq->noteon_fn = seq_noteon_meth; seq->free_fn = seq_free_meth; seq->reset_fn = seq_reset_meth; seq->current = NULL; seq->transpose = 0; seq->loudness = 0; seq->cycleflag = FALSE; seq->cycledur = 0L; seq->rate = 256L; seq->paused = FALSE; seq->stopfunc = noop; seq->channel_mask = 0xFFFFFFFFL; seq->runflag = seq->note_enable = FALSE; return seq; } /* seq_midi_bend_meth -- send a midi bend */ /**/ void seq_midi_bend_meth(seq_type seq, int voice, int value) { midi_bend(voice, value); } /* seq_midi_ctrl_meth -- send a midi ctrl change */ /**/ void seq_midi_ctrl_meth(seq_type seq, int voice, int ctrl, int value) { midi_ctrl(voice, ctrl, value); } /* seq_midi_program_meth -- send a midi program change */ /**/ void seq_midi_program_meth(seq_type seq, int voice, int prog) { midi_bend(voice, prog); } /* seq_midi_touch_meth -- send a midi touch */ /**/ void seq_midi_touch_meth(seq_type seq, int voice, int value) { midi_touch(voice, value); } /* seq_noteoff_meth -- turn a seq note off */ /**/ void seq_noteoff_meth(seq_type seq, int voice, int pitch) { midi_note(voice, pitch, 0); /*gprintf(TRANS, "_e");*/ seq_end_event(seq); } /* seq_noteon_meth -- play a note with transformations */ /**/ void seq_noteon_meth(seq_type seq, int chan, int pitch, int vel) { if (seq->note_enable) { pitch += seq->transpose; while (pitch < 0) pitch += 12; while (pitch > 127) pitch -= 12; vel += seq->loudness; if (vel <= 0) vel = 1; else if (vel > 127) vel = 127; midi_note(chan, pitch, vel); } } /* seq_pause -- stop playing momentarily or resume playing */ /**/ time_type seq_pause(seq_type seq, boolean flag) { if (!seq->paused && flag) { seq->paused = TRUE; seq->rate = seq->timebase->rate; set_rate(seq->timebase, STOPRATE); } else if (seq->paused && !flag) { seq_play(seq); } return (time_type) seq->timebase->virt_base; } /* seq_play -- play a sequence from the current event forward */ /**/ void seq_play(seq) seq_type seq; { timebase_type prev_timebase = timebase; register timebase_type reg_timebase = seq->timebase; if (!seq->runflag) { seq_reset(seq); } if (!seq->paused) return; eventtime = gettime(); /* assume that virt_base is correct virtual time as the result of seq_start_time or seq_reset */ timebase = reg_timebase; virttime = reg_timebase->virt_base; /* note that set_rate will set reg_timebase->real_base to eventtime */ set_rate(reg_timebase, seq->rate); seq->paused = FALSE; /* in case the score had been paused; note that seq_pause() has no effect if paused is TRUE */ seq->runflag = TRUE; seq->note_enable = TRUE; /* restore previous timebase */ timebase_use(prev_timebase); } /* seq_reset_meth -- reset a sequence to start back at the first event */ /**/ void seq_reset_meth(seq_type seq) { timebase_type old_timebase = timebase; if (seq->runflag) { /* maybe this seq is already reset, and process_event is * already scheduled. If so, don't schedule another one. */ if ((seq->timebase->virt_base == 0) && (seq->timebase->rate == STOPRATE)) { /* in case the reader just iterated through the list without * cause'ing events, reset the event list */ seq->current = seq_events(seq); return; } /* Otherwise, the seq is running, so stop it. */ seq_stop(seq); } timebase_use(seq->timebase); set_rate(seq->timebase, STOPRATE); set_virttime(seq->timebase, 0L); seq->current = seq_events(seq); seq->noteoff_count = 0L; seq->runflag = TRUE; seq->paused = TRUE; if (seq->current) cause((delay_type)(seq->current->ntime - virttime), process_event, seq); timebase_use(old_timebase); } /* seq_set_loudness -- set the loudness offset of a sequence */ /**/ void seq_set_loudness(seq, loud) seq_type seq; int loud; { seq->loudness = loud; } /* seq_set_rate -- set the rate of a sequence */ /**/ void seq_set_rate(seq, rate) seq_type seq; time_type rate; { seq->rate = rate; if (!seq->paused) set_rate(seq->timebase, rate); } /* seq_set_transpose -- set the sequence transposition */ /**/ void seq_set_transpose(seq, trans) seq_type seq; int trans; { seq->transpose = trans; } /* seq_start_time -- set the current pointer so the sequence starts here */ /**/ void seq_start_time(seq, start_time) seq_type seq; time_type start_time; { timebase_type prev_timebase = timebase; if (!seq->runflag) { seq_reset(seq); } if (real_to_virt(seq->timebase, eventtime) > start_time) { seq_reset(seq); } timebase_use(seq->timebase); seq->note_enable = FALSE; /* prime the pump */ set_rate(timebase, STOPRATE); set_virttime(timebase, start_time); catchup(); seq->note_enable = TRUE; seq->paused = TRUE; /* restore previous timebase */ timebase_use(prev_timebase); } /* seq_stop -- stop a sequence, clear out all pending events */ /**/ void seq_stop(seq) seq_type seq; { timebase_type prev_timebase = timebase; if (seq->runflag) { if (moxcdebug) gprintf(TRANS, "seq_reset swap from timebase 0x%x to 0x%x\n", timebase, seq->timebase); timebase = seq->timebase; seq->runflag = FALSE; set_rate(timebase, STOPRATE); set_virttime(timebase, MAXTIME); catchup(); } timebase_use(prev_timebase); } nyquist-3.05/cmt/moxc.c0000644000175000000620000005251011466723256014077 0ustar stevestaff/* MOXC -- a C version of Collinge's MOXIE language */ /* Copyright 1989 Carnegie Mellon University */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 31-Dec-85 | Modified for use with midi * 5-Feb-86 | Added m_rest and m_restuntil allowing rests at top level * 28-May-86 | Added command line parsing * 4-Jun-86 | changed keyevent to separate calls for each event type * 10-Jul-86 | put loop in mainscore with prompt to play and replay * 03-Jun-88 | modified for portability (AMIGA) -JCD * 07-Jul-89 | time bases -RBD * 31-Jan-90 | GWL : cleaned up for LATTICE * 30-Jun-90 | RBD : further changes * 2-Apr-91 | JDW : further changes * 4-Mar-91 | GWL : DOS allows odd inst addrs * 10-Oct-94 | nix : posicionador tridimensionale interface * 28-Apr-03 | DM : true->TRUE, false->FALSE *****************************************************************************/ #include "switches.h" #ifdef AMIGA #ifdef AZTEC #include "functions.h" #else #include "amiga.h" #endif #include "exec/exec.h" #include "cmtcmd.h" extern long event_mask; /* imported from midifns.c */ #endif extern int abort_flag; /*DMH: taken out of ifdef AMIGA for moxcrun*/ #include "stdio.h" #include "cext.h" #include "userio.h" #include "midifns.h" #include "cmdline.h" #include "midicode.h" #include "timebase.h" #include "moxc.h" #ifdef AMIGA /*DMH: only AMIGA cares about AMIGA's "proportional controllers"*/ #include "prop1.h" #endif #ifdef POSICIONADOR_3D #include "pos3d.h" #include "pos3dbuf.h" #endif /* POSICIONADOR_3D */ extern char *app_syntax; /*************************************************************************** * * IMPORTS: * asciievent(k) user-defined action for terminal input * bendchange(ch, val) user-defined pitch bend handler * ctrlchange(ch, c, val) user-defined control change handler * keydown(ch, p, v) user-defined MIDI note on handler * keyup(ch, p) user-defined MIDI note off handler * mainscore() user-defined first action(s) * musicfns lots of time and io functions * peddown(ch) user-defined pedal down handler * pedup(ch) user-defined pedal up handler * touchchange(ch, val) user-defined aftertouch handler * app_syntax string defining extra command line options * * EXPORTS: * * cause(delay, routine, p1, p2, ..., p8) * moxcdone -- set to TRUE to quit * eventtime -- ideallized current time * *****************************************************************************/ #define SAFEMOXC TRUE #define BREAKKEY 0x03 int moxcdone; /* flag to halt execution */ time_type eventtime; /* time of current call -- used to avoid */ /* timing errors due to finite execution speed */ time_type virttime; /* virtual time of current call */ timebase_type timebase; /* time base of current call */ int mididecode = TRUE; /* whether to decode messages or just call midievent */ int debug = FALSE; int moxcdebug = FALSE; time_type next_wakeup; timebase_type default_base; #ifdef AMIGA int pub_port_signal; struct MsgPort pub_port; #endif /***************************************************************************** * Routines local to this module *****************************************************************************/ private void callrun(); private void decode(); private void moxcterm(); /**************************************************************************** * callallcancel * Inputs: * timebase_queue * Effect: * return all calls to free list * Implementation: * If timebase_queue is not empty, there's a pending call. Remove the call * (not necessarily the timebase) and repeat. ****************************************************************************/ void callallcancel() { if (moxcdebug) gprintf(GDEBUG, "cancel all calls\n"); while (timebase_queue) { timebase = timebase_queue; timebase_queue = timebase->next; while (timebase->heap_size > 0) { call_free(remove_call(timebase)); } insert_base(timebase); } } /* catchup -- bring current timebase up to date by running its calls */ /**/ void catchup() { register call_type call; /* Remember where we're going in virtual time because setting the * rate will also modify timebase->virt_base. We don't want catchup * to stop short: */ time_type target_time = timebase->virt_base; /* remember timebase here because it's possible that a call will do * a timebase_use() and change it: */ register timebase_type my_base = timebase; while (my_base->heap_size != 0 && (my_base->heap[1]->u.e.time < target_time)) { /* eventtime is the real time at which something was scheduled */ eventtime = (my_base->next_time) >> 8; call = remove_call(my_base); virttime = call->u.e.time; (*(call->u.e.routine))(CALLARGS(call)); call_free(call); } /* now that we've possibly pulled events out of the timebase, adjust * the position in the timebase queue (and possibly remove it). */ remove_base(my_base); insert_base(my_base); } /**************************************************************************** * cause * Inputs: * delay_type (long) delay: time before this call should occur * int (*routine)(): routine that implements the call * int p1 through p8: parameters to pass to routine * Effect: * builds a call and puts it in pending queue for later scheduling ****************************************************************************/ #ifndef DOTS_FOR_ARGS void cause(delay, routine, p) delay_type delay; int (*routine)(); call_args_node p; #else #include void cause(delay_type delay, ...) /* note: the routine parameter is not checked because any routine type can be passed as a parameter, but in the call struct it's an int (*)() */ #endif { register call_type call = call_alloc(); #ifdef DOTS_FOR_ARGS va_list xp; #endif if (!call) { gprintf(ERROR, "cause: out of memory\n"); EXIT(1); } #ifdef DOTS_FOR_ARGS call->u.e.time = virttime + delay; call->u.e.priority = 128; /* default priority */ va_start(xp, delay); call->u.e.routine = (int (*)()) va_arg(xp, long *); call->u.e.p = va_arg(xp, call_args_node); va_end(xp); #else call->u.e.time = virttime + delay; call->u.e.priority = 128; /* default priority */ call->u.e.routine = routine; call->u.e.p = p; #endif #ifdef SAFEMOXC if (call->u.e.routine == 0) { gprintf(ERROR,"cause called with NULL routine\n"); EXIT(1); #ifndef DOS /* IBM allows odd addresses */ #if (__APPLE__ != 1 || __i386__ != 1) /* Intel Mac allows odd addresses */ } else if (((long) call->u.e.routine) & 1) { gprintf(ERROR, "cause called with bad routine address: 0x%lx\n", call->u.e.routine); #ifndef GCC_MODEL_CPU #define GCC_MODEL_CPU "GCC_MODEL_CPU is undefined for this compilation" #endif gprintf(ERROR, GCC_MODEL_CPU); EXIT(1); #endif #endif } #endif /* put call in default queue */ callinsert(timebase, call); if (moxcdebug) { gprintf(GDEBUG,"(cause) call is pending on timebase 0x%x:\n", timebase); callshow(call); } } /**************************************************************************** * causepri * Inputs: * int delay: time before this call should occur * int pri: priority, lowest priority goes first * int (*routine)(): routine that implements the call * int p1 through p8: parameters to pass to routine * Effect: * builds a call and puts it in pending queue for later scheduling ****************************************************************************/ #ifndef DOTS_FOR_ARGS void causepri(delay, pri, routine, p) delay_type delay; int pri; int (*routine)(); call_args_node p; #else /* already included stdarg.h */ void causepri(delay_type delay, int pri, ...) #endif { register call_type call = call_alloc(); #ifdef DOTS_FOR_ARGS va_list xp; #endif if (!call) { gprintf(ERROR, "cause: out of memory\n"); EXIT(1); } #ifdef DOTS_FOR_ARGS call->u.e.time = virttime + delay; call->u.e.priority = pri; /* default priority */ va_start(xp, pri); call->u.e.routine = (int (*)()) va_arg(xp, long *); call->u.e.p = va_arg(xp, call_args_node); va_end(xp); #else call->u.e.time = virttime + delay; call->u.e.priority = pri; /* default priority */ call->u.e.routine = routine; call->u.e.p = p; #endif #ifdef SAFEMOXC if (call->u.e.routine == 0) { gprintf(ERROR,"cause called with NULL routine\n"); EXIT(1); #ifndef DOS /* IBM allows odd addresses */ #if (__APPLE__ != 1 || __i386__ != 1) /* Intel Mac allows odd addresses */ } else if (((long) call->u.e.routine) & 1) { gprintf(ERROR, "causepri called with bad routine address: 0x%lx\n", call->u.e.routine); EXIT(1); #endif #endif } #endif /* put call in default queue */ callinsert(timebase, call); if (moxcdebug) { gprintf(GDEBUG,"(cause) call is pending:"); callshow(call); } } /**************************************************************************** * callrun * Inputs: * call_type call: the call to execute * Effect: * executes the previously scheduled call call and deallocates it ****************************************************************************/ private void callrun() { call_type call; if (moxcdebug) { gprintf(GDEBUG,"(callrun) running a call: \n"); } /* remove from head of queue */ while (!timebase_queue) gprintf(TRANS, "callrun fatal error\n"); timebase = timebase_queue; timebase_queue = timebase->next; if (debug) gprintf(TRANS, "callrun time %ld\n", timebase->next_time); eventtime = (timebase->next_time) >> 8; /* real time of the call */ /* remove first call from timebase */ call = remove_call(timebase); if (debug) gprintf(TRANS, "callrun call %lx\n", (ulong)call); insert_base(timebase); virttime = call->u.e.time; /* virtual time of the call */ if (moxcdebug) callshow(call); (*(call->u.e.routine))(CALLARGS(call)); call_free(call); } /**************************************************************************** * m_restuntil * Inputs: * int time: call time to rest until * Effect: * Waits until the specified time has been reached (absolute time). * Other "caused" calls will take place during the rest provided * this routine is called from "mainscore" (see m_rest description). ****************************************************************************/ void m_restuntil(time) time_type time; { time = virt_to_real(timebase, time); while(time > gettime()) { moxcwait(time); } } /**************************************************************************** * m_rest * Inputs: * int time: Amount of time to rest * Effect: * Waits until the amount of time specified has lapsed * Assumes: * Must not be called from a "caused" routine. Must only be called * from "mainscore" or a routine called directly or indirectly from * "mainscore" without using "cause". ****************************************************************************/ void m_rest(time) time_type time; { m_restuntil(time + real_to_virt(timebase, gettime())); } /**************************************************************************** * moxcinit * Inputs: * int argc: number of command line arguments * char * argv: command line argument array * Effect: initializes moxc system ****************************************************************************/ boolean moxcinit(argc, argv) int argc; char * argv[]; { meminit(); io_init(); #ifdef AMIGA pub_port_signal = AllocSignal(-1L); pub_port.mp_Node.ln_Type = NT_MSGPORT; pub_port.mp_SigBit = pub_port_signal; pub_port.mp_SigTask = FindTask(0L); pub_port.mp_Flags = PA_SIGNAL; pub_port.mp_Node.ln_Name = "CMTcmdport"; pub_port.mp_MsgList.lh_Head = (struct Node *)&pub_port.mp_MsgList.lh_Tail; pub_port.mp_MsgList.lh_TailPred = (struct Node *)&pub_port.mp_MsgList.lh_Head; event_mask |= (1L << pub_port_signal); AddPort(&pub_port); #endif cu_register((cu_fn_type) moxcterm, NULL); cl_syntax(midifns_syntax); cl_syntax("debugEnable verbose debugging;\ moxcEnable moxc debug mode;"); cl_syntax(app_syntax); if (!cl_init(argv, argc)) { /* make sure user gets to read the error message(s): */ gprintf(TRANS, "Type anything to exit..."); #ifdef DOS wait_ascii(); #else ggetchar(); #endif return FALSE; } debug = cl_switch("debug"); moxcdebug = cl_switch("moxc"); timebase = default_base = timebase_create(100); default_base->rate = 2560L; eventtime = 0L; next_wakeup = MAXTIME; musicinit(); #ifdef POSICIONADOR_3D ptInit(); #endif moxcdone = 0; return TRUE; } /**************************************************************************** * moxcwait * Input: * -1 => wait for next keyboard or midi event or queued event * 0 => don't wait * T => wait up to T for next keyboard or midi event or queued event * (this is used by m_restuntil) * Assume: there is work to do (npending > 0 || evqueue) ?? * Effect: dispatch on user inputs, cause calls ****************************************************************************/ void moxcwait(dateoftimeout) time_type dateoftimeout; { time_type maxtime = dateoftimeout; if (timebase_queue) { if ((timebase_queue->next_time >> 8) < maxtime) maxtime = (timebase_queue->next_time) >> 8; } eventwait(maxtime); decode(); } /**************************************************************************** * decode * Effect: dispatch on user inputs, cause calls ****************************************************************************/ private void decode() { /* It is important that midi_data is on a word boundary because we copy to it by doing a word transfer. */ byte midi_data[4]; time_type now; byte code; char k; #ifdef AMIGA struct cmd_msg *cmd; #endif now = gettime(); timebase = default_base; eventtime = now; virttime = 0L; /* gprintf(GDEBUG, "decode at time %ld\n", now); */ /********************************************** * poll for and decode midi keyboard input ***********************************************/ while (getbuf(FALSE, midi_data)) { /* only divide if necessary, divides take 100us on 8MHz 68000: */ if (virttime == 0) virttime = real_to_virt(default_base, now); /* short-circuit midi decoding */ if (!mididecode) { midievent(midi_data); continue; } code = midi_data[0] & MIDI_CODE_MASK; if (code == MIDI_ON_NOTE) { if (midi_data[2] == 0) { /* velocity 0 -> note off */ keyup(1+(midi_data[0] & MIDI_CHN_MASK), midi_data[1]); } else { keydown((midi_data[0] & MIDI_CHN_MASK)+1, midi_data[1], midi_data[2]); } } else if (code == MIDI_OFF_NOTE) { keyup((midi_data[0] & MIDI_CHN_MASK)+1, midi_data[1]); } else if (code == MIDI_TOUCH) { touchchange((midi_data[0] & MIDI_CHN_MASK)+1,midi_data[1]); } else if (code == MIDI_BEND) { bendchange((midi_data[0] & MIDI_CHN_MASK)+1, midi_data[1] + (midi_data[2] << 7)); } else if (code == MIDI_CTRL && midi_data[1] == SUSTAIN) { if (midi_data[2] == 0) pedup((midi_data[0] & MIDI_CHN_MASK) + 1); else peddown((midi_data[0] & MIDI_CHN_MASK) + 1); } else if (code == MIDI_CTRL) { ctrlchange((midi_data[0] & MIDI_CHN_MASK) + 1, midi_data[1], midi_data[2]); } else if (code == MIDI_CH_PROGRAM) { prgmchange((midi_data[0] & MIDI_CHN_MASK) + 1, midi_data[1] + 1); /* think C midi driver doesn't handle sysex the way the Amiga drivers do (yet) */ #ifndef MACINTOSH } else if (code == MIDI_SYSEX) { sysex(); #endif } } /********************************************** * poll for ASCII keyboard input ***********************************************/ while (get_ascii(&k)) { virttime = real_to_virt(default_base, now); asciievent(k); /* if user doesn't handle abort char in asciievent, we should exit now to avoid an infinite loop */ if (abort_flag) EXIT(1); } #ifdef POSICIONADOR_3D /********************************************** * poll for posicionador tridimensionale input **********************************************/ { pt_value pt_data; while (ptGetValue(&pt_data)) { /* only divide if necessary, divides take 100us on 8MHz 68000: */ if (virttime == 0) virttime = real_to_virt(default_base, now); ptevent(&pt_data); } } #endif /* POSICIONADOR_3D */ #ifdef AMIGA /********************************************** * poll for proportional controller port **********************************************/ if (prop_1_events) { int events; Disable(); events = prop_1_events; prop_1_events = 0; Enable(); if (events & BUTTON_1_RIGHT_CHANGE) buttonchange(3, prop_1_right_button); if (events & BUTTON_1_LEFT_CHANGE) buttonchange(2, prop_1_left_button); if (events & PROP_1_LEFT_CHANGE) propchange(2, prop_1_left_data); if (events & PROP_1_RIGHT_CHANGE) propchange(3, prop_1_right_data); } /********************************************** * poll for input from public command port ***********************************************/ while (cmd = (struct cmd_msg *) GetMsg(&pub_port)) { struct symb_descr *desc = &HASHENTRY(lookup(cmd->symbol_name)); /* gprintf(TRANS, "got %lx (%s) from pub_port\n", cmd, cmd->symbol_name); */ virttime = real_to_virt(default_base, now); if (!desc) { gprintf(TRANS, "Error, symbol %s undefined.\n", cmd->symbol_name); } else if (desc->symb_type != cmd->symb_type) { gprintf(TRANS, "Error, wrong type for symbol %s\n", cmd->symbol_name); } else if (cmd->symb_type == fn_symb_type) { /* gprintf(TRANS, "Calling routine\n"); */ (*(desc->ptr.routine))( (int) cmd->the_args[0], (int) cmd->the_args[1], (int) cmd->the_args[2], (int) cmd->the_args[3], (int) cmd->the_args[4], (int) cmd->the_args[5], (int) cmd->the_args[6], (int) cmd->the_args[7] ); } else if (cmd->symb_type == var_symb_type) { *(desc->ptr.intptr) = (int) cmd->the_args[0]; } else if (cmd->symb_type == vec_symb_type) { if (cmd->the_args[0] >= desc->size) { gprintf(TRANS, "Error: Vector %s is of size %d\n", cmd->symbol_name, desc->size); } else { (desc->ptr.intptr)[cmd->the_args[0]] = cmd->the_args[1]; /* gprintf(TRANS, "vec: setting %lx\n", &(desc->ptr.intptr)[cmd->the_args[0]]); */ } } else gprintf(TRANS, "Symbol Type Error\n"); ReplyMsg(&(cmd->msg)); } #endif /********************************************** * poll for next call in queue ***********************************************/ now = (now + 1) << 8; /* shift because next_time is also scaled, * add 256 because next_time has added priority */ if (debug) gprintf(TRANS, "now %ld next_time %ld\n", now, (timebase_queue ? timebase_queue->next_time : 1234)); /* give pending events priority, but every 100 events, loop to allow input processing (user may want to give a "quit" command) */ for (k = 0; k < 100 && timebase_queue && (now > timebase_queue->next_time); k++) { callrun(); } /******************* * flush text output ********************/ #ifdef MACINTOSH_OR_UNIX gflush(); #endif } /**************************************************************************** * quit * Effect: tells moxc to shut down ****************************************************************************/ void quit() { moxcdone = TRUE; } /* moxcrun -- schedule events until done */ /**/ void moxcrun() { moxcdone = FALSE; while (!moxcdone && !abort_flag) { /* test for finish */ if (!timebase_queue) moxcdone = TRUE; else moxcwait(MAXTIME); /* do work */ } } /* moxcterm -- clean up after moxcinit */ /**/ private void moxcterm() { #ifdef AMIGA FreeSignal((long) pub_port_signal); RemPort(&pub_port); #endif } nyquist-3.05/cmt/timebase.h0000644000175000000620000000651510144436365014725 0ustar stevestaff/* timebase.h -- management of calls, time bases and heaps for moxc */ #define STOPRATE 0xFFFFL /*************************************************************************** * call structure ****************************************************************************/ /* ---NOTE!!! if you change MAX_CALL_ARGS, change CALLARGS macro below--- */ #define MAX_CALL_ARGS 8 typedef struct call_args_struct { long arg[MAX_CALL_ARGS]; } call_args_node; typedef struct call { union { struct { time_type time; /* virtual time of this call */ int priority; /* an 8-bit the priority, low priority first */ int (*routine)(); /* who to call */ call_args_node p; /* what to pass */ } e; struct call *p; /* used to link free calls */ } u; } *call_type, call_node; /* CALLARGS - given a call_type, this macro generates an argument list */ /* * NOTE: originally, I thought call->u.e.p (a structure), would do it, but * Lattice C for the Amiga has a compiler bug, and even in places where the * bug doesn't show up, the code generated for the structure passing is * a sequence of two loops: one to copy data to a local area on the stack, * and one to push this data (a byte at a time!) to the top of the stack. * With Lattice (and perhaps others, I haven't checked), it's better to * push the data in-line. */ #ifdef LATTICE #define CARG(n) call->u.e.p.arg[n] #define CALLARGS(call) CARG(0), CARG(1), CARG(2), CARG(3), \ CARG(4), CARG(5), CARG(6), CARG(7) #else #define CALLARGS(call) call->u.e.p #endif /*************************************************************************** * timebase structure ****************************************************************************/ typedef struct timebase_struct { struct timebase_struct *next; /* used for list */ time_type next_time; time_type virt_base; time_type real_base; time_type rate; /* ratio of real/virt time, STOPRATE or more is infinity */ short heap_size; short heap_max; call_type *heap; } timebase_node, *timebase_type; extern timebase_type timebase_queue; #define call_alloc() ((call_type) memget(sizeof(call_node))) #define call_free(c) memfree((char *) (c), sizeof(call_node)) timebase_type timebase_create(int maxsize); void callinsert(timebase_type base, call_type call); void callshow(call_type call); void timebase_free(timebase_type timebase); void insert_base(timebase_type timebase); void remove_base(timebase_type timebase); call_type remove_call(timebase_type a_timebase); void set_rate(timebase_type base, time_type rate); void set_virttime(timebase_type base, time_type vtime); void timebase_use(timebase_type base); #define real_to_virt(base, rtime) ((base)->rate == 0 ? MAXTIME : \ ((base)->virt_base + (((rtime) - (base)->real_base) << 8) / (base)->rate)) #define virt_to_real(base, vtime) ((base)->rate >= STOPRATE ? \ ((base)->virt_base > vtime ? (base)->real_base : MAXTIME) : \ (base)->real_base + ((((vtime) - (base)->virt_base) * (base)->rate) >> 8)) #define virt_to_real_256(base, vtime) ((base)->rate >= STOPRATE ? \ ((base)->virt_base > vtime ? (base)->real_base << 8 : MAXTIME) : \ ((base)->real_base << 8) + ((((vtime) - (base)->virt_base) * (base)->rate))) nyquist-3.05/cmt/seqmread.h0000644000175000000620000000016610144436365014731 0ustar stevestaff/* seqmread.h -- midi file reader */ void seq_read_smf(seq_type seq, FILE *fp); /* LISP: (SEQ-READ-SMF SEQ FILE) */ nyquist-3.05/cmt/hash.h0000644000175000000620000000103510144436365014047 0ustar stevestaff/* * This file should be included in all files that use * the HASHENTRY macro; see hashrout.h for details */ /* Copyright 1989 Carnegie Mellon University */ #ifndef HASHTYPE # include "-- HASHTYPE undefined" #endif /* * An element really is a HASHTYPE along with a h_next entry, * which chains together entries of the same hash value. */ typedef struct hashelem { HASHTYPE h_elem; struct hashelem *h_next; } hashelem; extern hashelem hashfirstchunk[]; #define HASHENTRY(i) (hashfirstchunk[i].h_elem) nyquist-3.05/cmt/record.h0000644000175000000620000000032010144436365014376 0ustar stevestaff/* Copyright 1989 Carnegie Mellon University */ boolean rec_init(boolean bender); boolean rec_event(long *data, time_type time); void rec_final(FILE *fp, boolean absflag); void write_pitch(FILE *fp, int p); nyquist-3.05/cmt/cext.c0000644000175000000620000000513610144436365014070 0ustar stevestaff/**************************************************************************** cext.c Copyright 1989 Carnegie Mellon University August 3, 1987 Author: Frits Habermann ---------------------------------------------------------------------------- 02-May-1988 | JCD : portable & AMIGA version. 17-Oct-1988 | JCD : more portability (FREE). 28-Apr-2003 | DM : changed includes for portability ****************************************************************************/ #include "switches.h" #include #include #include "cext.h" #include "userio.h" #define calc_middle(top, bot) (((top - bot) / 2 ) + bottom ) #define kbyte 1000 #define outof_mem(blocksize) (blocksize == 0 ) #define done_search(top, bot, middle) ( (( (top - bot) < kbyte ) && \ ( !toomuch_mem(middle)) ) || \ ( outof_mem( middle )) ) private boolean toomuch_mem(ushort maximum) { char *test; boolean istoo_much; istoo_much = ( (test = (char *) MALLOC(maximum)) == NULL ); if (test) FREE(test); return( istoo_much ); } private boolean toolittle_mem(maximum) ushort maximum; { char *test; boolean istoo_little; istoo_little = !( (test = (char *) MALLOC(maximum)) == NULL ); if (test) FREE( test ); return(istoo_little); } private ushort get_biggest_block( maximum ) ushort maximum; { ushort maxblock; ushort top = maximum; ushort bottom = 0; if (!toomuch_mem(maximum)) return(maximum); /* If there's enough memory */ else { gprintf(ERROR, "Running out of memory...\n"); maxblock = calc_middle( top, bottom ); while( !done_search(top, bottom, maxblock) ) { if( toomuch_mem(maxblock) ) { top = maxblock; maxblock = calc_middle(top,bottom); } else if (toolittle_mem(maxblock)) { bottom = maxblock; maxblock = calc_middle(top,bottom); } } } return( maxblock ); } public ulong MyMaxMem(ushort *growbytes) { ulong x; if( growbytes != NULL ) *growbytes = 0; x=( (ulong)get_biggest_block((ushort)BIGGEST_BLOCK)); /* gprintf(TRANS,"cext: MyMaxMem %ld\n",x); */ return x; } /* note: EXIT is defined to be cmt_exit */ void cmt_exit(n) int n; { cu_cleanup(); /* For protection, exit is #defined to hide it. Expose it and call it. */ #undef exit exit(n); } #ifdef AMIGA #ifdef LATTICE /* for some reason, these don't seem to be defined anywhere in the standard libraries */ #include "signal.h" int _FPERR; int (*_SIGFPE)(int) = SIG_DFL; int _oserr; #endif #endif nyquist-3.05/cmt/cmtio.c0000644000175000000620000000713010144436365014234 0ustar stevestaff/* ********************************************************************** * File io.c ********************************************************************** * * Non blocking input routine * Works by puttng the terminal in CBREAK mode and using the FIONREAD * ioctl call to determine the number of characters in the input queue */ #include "stdio.h" #include "io.h" #include #include #include #include #include "cext.h" int IOinputfd; /* input file descriptor (usually 0) */ int IOnochar; /* Value to be returned by IOgetchar() where there is no input to be had */ static struct sgttyb IOoldmodes, IOcurrentmodes; /* Initial and current tty modes */ /* * IOsetup(inputfd) * Args: * inputfd - input file descriptor (should be zero for standard input) * Returns: * 0 - if all goes well * -1 - if an ioctl fails (also calls perror) * Side Effects: * Puts the terminal in CBREAK mode - before process termination * IOcleanup() should be called to restore old terminal modes * Catch's interrupts (if they are not already being caught) and * calls IOcleanup before exiting * */ #define ERROR(s) return (perror(s), -1) IOsetup(inputfd) { static IOdiegracefully(); int (*interrupt_handler)(); IOinputfd = inputfd; IOnochar = NOCHAR; if(ioctl(IOinputfd, TIOCGETP, &IOoldmodes) < 0) ERROR("IOsetup"); IOcurrentmodes = IOoldmodes; IOcurrentmodes.sg_flags |= CBREAK; IOcurrentmodes.sg_flags &= ~ECHO; if(ioctl(IOinputfd, TIOCSETP, &IOcurrentmodes)) ERROR("IOsetup-2"); if( (interrupt_handler = signal(SIGINT, IOdiegracefully)) != 0) signal(SIGINT, interrupt_handler); return 0; } static IOdiegracefully() { write(2, "\nBye\n", 5); IOcleanup(); EXIT(2); } /* * IOcleanup() * Returns: * 0 - if all goes well * -1 - if an ioctl fails (also calls perror) * Side Effects: * Restores initial terminal modes */ IOcleanup() { if(ioctl(IOinputfd, TIOCSETP, &IOoldmodes) < 0) ERROR("IOclean"); return 0; } /* * IOgetchar() * Returns: * A character off the input queue if there is one, * IOnochar if there is no character waiting to be read, * -1 if an ioctl fails (shouldn't happen if IOsetup went OK) */ #ifndef UNIX_MACH IOgetchar() { int n; char c; if(ioctl(IOinputfd, FIONREAD, &n) < 0) ERROR("IOgetchar"); if(n <= 0) return IOnochar; switch(read(IOinputfd, &c, 1)) { case 1: return c; case 0: return EOF; default: ERROR("IOgetchar-read"); } } #ifdef IOGETCHAR2 IOgetchar2() { int nfds, readfds = 1 << IOinputfd; char c; static struct timeval zero; if(IOinputfd < 0 || IOinputfd >= 32) { printf("IOgetchar2: bad IOinputfd (%d)%s\n", IOinputfd, IOinputfd == -1 ? "Did you call IOsetup(fd)?" : ""); } nfds = select(32, &readfds, 0, 0, &zero); if(nfds > 0) { switch(read(IOinputfd, &c, 1)) { case 0: return EOF; case 1: return c; default: printf("IOgetchar2: read failed!\n"); return NOCHAR; } } else if(nfds < 0) printf("IOgetchar2: select failed!\n"); return NOCHAR; } #endif /* * IOwaitchar() * Returns: * A character off the input queue. Waits if necessary. */ int IOwaitchar() { char c; if (read(IOinputfd, &c, 1) == 1) return c; else return EOF; } #endif /* not UNIX_MACH */ nyquist-3.05/cmt/midifile.c0000644000175000000620000004203610144436365014707 0ustar stevestaff/* * Read a Standard MIDI File. Externally-assigned function pointers are * called upon recognizing things in the file. See midifile(3). */ /***************************************************************************** * Change Log * Date | who : Change *-----------+----------------------------------------------------------------- * 2-Mar-92 | GWL : created changelog; MIDIFILE_ERROR to satisfy compiler * 28-Apr-03 | DM : changed #includes and give return types for portability *****************************************************************************/ #include "switches.h" #include #include #include "mfmidi.h" #include "midifile.h" #include "cext.h" #include "userio.h" #include "string.h" #define MIDIFILE_ERROR -1 #ifdef PROTOTYPES #define NOARGS void #else #define NOARGS #endif /* public stuff */ extern int abort_flag; /* Functions to be called while processing the MIDI file. */ void (*Mf_starttrack)(NOARGS) = 0; void (*Mf_endtrack)(NOARGS) = 0; int (*Mf_getc)(NOARGS) = 0; void (*Mf_eot)(NOARGS) = 0; #ifdef PROTOTYPES void (*Mf_error)(char *) = 0; void (*Mf_header)(int,int,int) = 0; void (*Mf_on)(int,int,int) = 0; void (*Mf_off)(int,int,int) = 0; void (*Mf_pressure)(int,int,int) = 0; void (*Mf_controller)(int,int,int) = 0; void (*Mf_pitchbend)(int,int,int) = 0; void (*Mf_program)(int,int) = 0; void (*Mf_chanpressure)(int,int) = 0; void (*Mf_sysex)(int,char*) = 0; void (*Mf_arbitrary)(int,char*) = 0; void (*Mf_metamisc)(int,int,char*) = 0; void (*Mf_seqnum)(int) = 0; void (*Mf_smpte)(int,int,int,int,int) = 0; void (*Mf_timesig)(int,int,int,int) = 0; void (*Mf_tempo)(int) = 0; void (*Mf_keysig)(int,int) = 0; void (*Mf_sqspecific)(int,char*) = 0; void (*Mf_text)(int,int,char*) = 0; #else void (*Mf_error)() = 0; void (*Mf_header)() = 0; void (*Mf_on)() = 0; void (*Mf_off)() = 0; void (*Mf_pressure)() = 0; void (*Mf_controller)() = 0; void (*Mf_pitchbend)() = 0; void (*Mf_program)() = 0; void (*Mf_chanpressure)() = 0; void (*Mf_sysex)() = 0; void (*Mf_arbitrary)() = 0; void (*Mf_metamisc)() = 0; void (*Mf_seqnum)() = 0; void (*Mf_smpte)() = 0; void (*Mf_tempo)() = 0; void (*Mf_timesig)() = 0; void (*Mf_keysig)() = 0; void (*Mf_sqspecific)() = 0; void (*Mf_text)() = 0; #endif int Mf_nomerge = 0; /* 1 => continue'ed system exclusives are */ /* not collapsed. */ long Mf_currtime = 0L; /* current time in delta-time units */ int Mf_skipinit = 0; /* 1 if initial garbage should be skipped */ /* private stuff */ static long Mf_toberead = 0L; static long readvarinum(NOARGS); static long read32bit(NOARGS); static int read16bit(NOARGS); static void msgenlarge(NOARGS); static char *msg(NOARGS); static int readheader(NOARGS); static void readtrack(NOARGS); static void sysex(NOARGS), msginit(NOARGS); static int egetc(NOARGS); static int msgleng(NOARGS); #ifdef PROTOTYPES static int readmt(char*,int); static long to32bit(int,int,int,int); static int to16bit(int,int); static void mferror(char *); static void badbyte(int); static void metaevent(int); static void msgadd(int); static void chanmessage(int,int,int); #else static long to32bit(); static int to16bit(); static void mferror(); static void badbyte(); static void metaevent(); static void msgadd(); static void chanmessage(); #endif static int midifile_error; void midifile() /* The only non-static function in this file. */ { int ntrks; midifile_error = 0; if ( Mf_getc == 0 ) { mferror("mf.h() called without setting Mf_getc"); return; } ntrks = readheader(); if (midifile_error) return; if ( ntrks <= 0 ) { mferror("No tracks!"); /* no need to return since midifile_error is set */ } while ( ntrks-- > 0 && !midifile_error && !check_aborted()) readtrack(); if (check_aborted()) { mferror("Midifile read aborted\n\ \tthe rest of your file will be ignored.\n"); if (abort_flag == BREAK_LEVEL) abort_flag = 0; } } static int readmt(s,skip) /* read through the "MThd" or "MTrk" header string */ char *s; int skip; /* if 1, we attempt to skip initial garbage. */ { int nread = 0; char b[4]; char buff[32]; int c; char *errmsg = "expecting "; retry: while ( nread<4 ) { c = (*Mf_getc)(); if ( c == EOF ) { errmsg = "EOF while expecting "; goto err; } b[nread++] = c; } /* See if we found the 4 characters we're looking for */ if ( s[0]==b[0] && s[1]==b[1] && s[2]==b[2] && s[3]==b[3] ) return(0); if ( skip ) { /* If we are supposed to skip initial garbage, */ /* try again with the next character. */ b[0]=b[1]; b[1]=b[2]; b[2]=b[3]; nread = 3; goto retry; } err: (void) strcpy(buff,errmsg); (void) strcat(buff,s); mferror(buff); return(0); } static int egetc() /* read a single character and abort on EOF */ { int c = (*Mf_getc)(); if ( c == EOF ) { mferror("premature EOF"); return EOF; } Mf_toberead--; return(c); } static int readheader() /* read a header chunk */ { int format, ntrks, division; if ( readmt("MThd",Mf_skipinit) == EOF ) return(0); Mf_toberead = read32bit(); if (midifile_error) return MIDIFILE_ERROR; format = read16bit(); if (midifile_error) return MIDIFILE_ERROR; ntrks = read16bit(); if (midifile_error) return MIDIFILE_ERROR; division = read16bit(); if (midifile_error) return MIDIFILE_ERROR; if ( Mf_header ) (*Mf_header)(format,ntrks,division); /* flush any extra stuff, in case the length of header is not 6 */ while ( Mf_toberead > 0 && !midifile_error) (void) egetc(); return(ntrks); } static void readtrack() /* read a track chunk */ { /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; long lookfor, lng; int c, c1, type; int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ int running = 0; /* 1 when running status used */ int status = 0; /* (possibly running) status byte */ int needed; if ( readmt("MTrk",0) == EOF ) return; Mf_toberead = read32bit(); if (midifile_error) return; Mf_currtime = 0L; if ( Mf_starttrack ){ (*Mf_starttrack)(); } while ( Mf_toberead > 0 ) { Mf_currtime += readvarinum(); /* delta time */ if (midifile_error) return; c = egetc(); if (midifile_error) return; if ( sysexcontinue && c != 0xf7 ) { mferror("didn't find expected continuation of a sysex"); return; } if ( (c & 0x80) == 0 ) { /* running status? */ if ( status == 0 ) { mferror("unexpected running status"); return; } running = 1; } else { status = c; running = 0; } needed = chantype[ (status>>4) & 0xf ]; if ( needed ) { /* ie. is it a channel message? */ if ( running ) c1 = c; else { c1 = egetc(); if (midifile_error) return; } chanmessage( status, c1, (needed>1) ? egetc() : 0 ); if (midifile_error) return; continue;; } switch ( c ) { case 0xff: /* meta event */ type = egetc(); if (midifile_error) return; /* watch out - Don't combine the next 2 statements */ lng = readvarinum(); if (midifile_error) return; lookfor = Mf_toberead - lng; msginit(); while ( Mf_toberead > lookfor ) { char c = egetc(); if (midifile_error) return; msgadd(c); } metaevent(type); break; case 0xf0: /* start of system exclusive */ /* watch out - Don't combine the next 2 statements */ lng = readvarinum(); if (midifile_error) return; lookfor = Mf_toberead - lng; msginit(); msgadd(0xf0); while ( Mf_toberead > lookfor ) { c = egetc(); if (midifile_error) return; msgadd(c); } if ( c==0xf7 || Mf_nomerge==0 ) sysex(); else sysexcontinue = 1; /* merge into next msg */ break; case 0xf7: /* sysex continuation or arbitrary stuff */ /* watch out - Don't combine the next 2 statements */ lng = readvarinum(); if (midifile_error) return; lookfor = Mf_toberead - lng; if ( ! sysexcontinue ) msginit(); while ( Mf_toberead > lookfor ) { c = egetc(); if (midifile_error) return; msgadd(c); } if ( ! sysexcontinue ) { if ( Mf_arbitrary ) (*Mf_arbitrary)(msgleng(),msg()); } else if ( c == 0xf7 ) { sysex(); sysexcontinue = 0; } break; default: badbyte(c); break; } } if ( Mf_endtrack ) (*Mf_endtrack)(); return; } static void badbyte(c) int c; { char buff[32]; (void) sprintf(buff,"unexpected byte: 0x%02x",c); mferror(buff); } static void metaevent(type) { int leng = msgleng(); char *m = msg(); switch ( type ) { case 0x00: if ( Mf_seqnum ) (*Mf_seqnum)(to16bit(m[0],m[1])); break; case 0x01: /* Text event */ case 0x02: /* Copyright notice */ case 0x03: /* Sequence/Track name */ case 0x04: /* Instrument name */ case 0x05: /* Lyric */ case 0x06: /* Marker */ case 0x07: /* Cue point */ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* These are all text events */ if ( Mf_text ) (*Mf_text)(type,leng,m); break; case 0x2f: /* End of Track */ if ( Mf_eot ) (*Mf_eot)(); break; case 0x51: /* Set tempo */ if ( Mf_tempo ) (*Mf_tempo)(to32bit(0,m[0],m[1],m[2])); break; case 0x54: if ( Mf_smpte ) (*Mf_smpte)(m[0],m[1],m[2],m[3],m[4]); break; case 0x58: if ( Mf_timesig ) (*Mf_timesig)(m[0],m[1],m[2],m[3]); break; case 0x59: if ( Mf_keysig ) (*Mf_keysig)(m[0],m[1]); break; case 0x7f: if ( Mf_sqspecific ) (*Mf_sqspecific)(leng,m); break; default: if ( Mf_metamisc ) (*Mf_metamisc)(type,leng,m); } } static void sysex() { if ( Mf_sysex ) (*Mf_sysex)(msgleng(),msg()); } static void chanmessage(status,c1,c2) int status; int c1, c2; { int chan = status & 0xf; switch ( status & 0xf0 ) { case NOTEOFF: if ( Mf_off ) (*Mf_off)(chan,c1,c2); break; case NOTEON: if ( Mf_on ) (*Mf_on)(chan,c1,c2); break; case PRESSURE: if ( Mf_pressure ) (*Mf_pressure)(chan,c1,c2); break; case CONTROLLER: if ( Mf_controller ) (*Mf_controller)(chan,c1,c2); break; case PITCHBEND: if ( Mf_pitchbend ) (*Mf_pitchbend)(chan,c1,c2); break; case PROGRAM: if ( Mf_program ) (*Mf_program)(chan,c1); break; case CHANPRESSURE: if ( Mf_chanpressure ) (*Mf_chanpressure)(chan,c1); break; } } /* readvarinum - read a varying-length number, and return the */ /* number of characters it took. */ static long readvarinum() { long value; int c; c = egetc(); if (midifile_error) return 0; value = (long) c; if ( c & 0x80 ) { value &= 0x7f; do { c = egetc(); if (midifile_error) return 0; value = (value << 7) + (c & 0x7f); } while (c & 0x80); } return (value); } static long to32bit(c1,c2,c3,c4) { long value = 0L; value = (c1 & 0xff); value = (value<<8) + (c2 & 0xff); value = (value<<8) + (c3 & 0xff); value = (value<<8) + (c4 & 0xff); return (value); } static int to16bit(c1,c2) int c1, c2; { return ((c1 & 0xff ) << 8) + (c2 & 0xff); } static long read32bit() { int c1, c2, c3, c4; c1 = egetc(); if (midifile_error) return 0; c2 = egetc(); if (midifile_error) return 0; c3 = egetc(); if (midifile_error) return 0; c4 = egetc(); if (midifile_error) return 0; return to32bit(c1,c2,c3,c4); } static int read16bit() { int c1, c2; c1 = egetc(); if (midifile_error) return 0; c2 = egetc(); if (midifile_error) return 0; return to16bit(c1,c2); } static void mferror(s) char *s; { if ( Mf_error ) (*Mf_error)(s); midifile_error = 1; } /* The code below allows collection of a system exclusive message of */ /* arbitrary length. The Msgbuff is expanded as necessary. The only */ /* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */ #define MSGINCREMENT 128 static char *Msgbuff = 0; /* message buffer */ static int Msgsize = 0; /* Size of currently allocated Msg */ static int Msgindex = 0; /* index of next available location in Msg */ static void msginit() { Msgindex = 0; } static char * msg() { return(Msgbuff); } static int msgleng() { return(Msgindex); } static void msgadd(c) int c; { /* If necessary, allocate larger message buffer. */ if ( Msgindex >= Msgsize ) msgenlarge(); Msgbuff[Msgindex++] = c; } static void msgenlarge() { char *newmess; char *oldmess = Msgbuff; int oldleng = Msgsize; Msgsize += MSGINCREMENT; newmess = MALLOC((sizeof(char)*Msgsize) ); /* copy old message into larger new one */ if ( oldmess != 0 ) { register char *p = newmess; register char *q = oldmess; register char *endq = &oldmess[oldleng]; for ( ; q!=endq ; p++,q++ ) *p = *q; free(oldmess); } Msgbuff = newmess; } nyquist-3.05/cmt/cext.h0000644000175000000620000000777310144436365014106 0ustar stevestaff/****************************************************************** * modified JCD 27 Apr-88 for AMIGA * cext.h -- extensions to c to make it more portable * Copyright 1989 Carnegie Mellon University * ******************************************************************* cext must provide the following definitions: true -- a constant false -- a boolean constant private -- defined as static, used to declare local functions public -- defined as empty string, used to declare exported functions boolean -- a new type byte -- unsigned 8-bit quantity ushort -- unsigned 16-bit quantity ulong -- unsigned 32-bit quantity Pointer -- pointer to char, a generic pointer ABS() -- absolute value of any type of number MAX() -- maximum of two numbers MIN() -- minimum of two numbers ROUND() -- round a double to long NULL -- pointer to nothing, a constant EOS -- end of string, a constant '\0' MALLOC(x) -- allocates x bytes FREE(x) -- frees something from MALLOC AVAILMEM -- tells how much memory is available. (N.B.: no parens, no args.) EXIT(n) -- calls exit(n) after shutting down/deallocating resources *****************************************************************************/ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm many changes for new conditional compilation switches * 28Apr03 rbd removed macro redefinitions: min, max */ #ifndef CEXT_H #ifndef SWITCHES #include "switches.h" #endif #include #include #include #if HAS_STDLIB_H #include #endif #if HAS_SYS_TYPES_H #include #endif #if HAS_MALLOC_H #include #endif #if NEED_ULONG typedef unsigned long ulong; #endif #if NEED_USHORT typedef unsigned long ushort; #endif #if NEED_BYTE typedef unsigned char byte; #endif /* There's a name conflict between true/false as an enum type in * Apple #includes:Types.h on the Mac, and true/false as #defined below */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define private static #define public #if NEED_DEFINE_MALLOC public void *malloc(); #endif typedef char *Pointer; #ifdef UNIX_MACH typedef int boolean; #else /* hopefully, unsigned short will save sign extension instructions */ typedef unsigned char boolean; #endif #ifndef ABS #define ABS(a) (((a) > 0) ? (a) : -(a)) #endif #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #define MAXULONG 0xffffffff #ifndef NULL #define NULL 0L #endif #ifndef EOS #define EOS '\0' #endif #define SAFETYBUF 10 /* Safety buffer when allocating memory */ #define BIGGEST_BLOCK 32765 /* Should find a happy medium for this */ #ifdef MACINTOSH /*DMH: gets AVAILMEM in record.c*/ #include #define MALLOC(x) malloc((size_t)(x)) /*DMH: size_t is ulong, for MAC*/ #define FREE(x) free((char *)(x)) #define AVAILMEM MyMaxMem(NULL)/*???*/ #endif #ifdef LATTICE322 #define MALLOC malloc #define FREE free #define AVAILMEM MyMaxMem(NULL) #else #ifdef DOS /* was MICROSOFT */ #define MALLOC malloc #define FREE free #define AVAILMEM MyMaxMem(NULL) #endif #endif #ifdef UNIX #define MALLOC malloc #define FREE free #define AVAILMEM 10000000 /* since we have virtual memory, assume 10Mb */ #endif #ifdef AMIGA #define MALLOC malloc #define FREE free #define AVAILMEM 128000 #endif public ulong MyMaxMem(ushort *); #ifndef MEM #include "mem.h" #endif #ifndef CLEANUP #include "cleanup.h" #endif #ifdef CMTSTUFF #define EXIT cmt_exit public void EXIT(int); /* don't allow anyone to call exit directly */ #define exit(n) PLEASE_CALL_EXIT_NOT_exit #else #define EXIT(n) exit(n) #endif #define _cext #ifndef MALLOC MALLOC is not defined! #endif #define ROUND(x) ((long) ((x) + 0.5)) /* for compatibility */ #ifdef NEED_ROUND #define round ROUND #endif #ifndef min #define min MIN #define max MAX #endif #define CEXT_H #endif nyquist-3.05/cmt/record.c0000644000175000000620000005345210144436365014407 0ustar stevestaff/* record.c -- keyboard to adagio recorder * Copyright 1989 Carnegie Mellon University * * the interface consists of three routines: * rec_init() -- initialization * rec_event(byte *data) -- called to insert (record) midi data, * -- returns FALSE if no more space * rec_final() -- called to finish up */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 27-Feb-86 | Created changelog * | Use pedal information when computing durations (code taken * | from transcribe.c) * 23-Mar-86 | Determine size of transcription when rec_init is called. * 21-May-86 | Major rewrite to use continuous controls (code taken * | from transcribe.c) * 1-Aug-87 | F.H. Changed rec_init() to new memory handling. * 17-Oct-88 | JCD : portable version. * 31-Jan-90 | GWL : cleaned up for LATTICE * 30-Jun-90 | RBD : further changes * 2-Apr-91 | JDW : further changes * 28-Apr-03 | DM : changed for portability; true->TRUE, false->FALSE *****************************************************************************/ #include "switches.h" #include #include #include "cext.h" #include "midifns.h" #include "userio.h" #include "midicode.h" #include "record.h" #include "cmdline.h" extern long space; /* how much space is left? */ int debug_rec = FALSE; /* verbose debug flag for this module */ long max_notes = -1L; /* -1 is flag that space must be allocated */ time_type previous_time; /**************************************************************** * data structure notes: the midi stream is stored as an array * of 4-byte records, each of which is either a time or midi * data. Midi data always begins with a control byte (high * order bit set), and it is assumed times are positive (high * order bit clear), so the two are easy to distinguish * IF THE COMPILER PUTS THESE BITS IN THE SAME PLACE. It looks * like the high order byte of the time lines up with the last * byte of a 4 byte array, so we will always set the high order * bit of the last array byte when the first 3 bytes are filled * with MIDI data. This is refered to as the "tag" bit. * WARNING: Lattice C longs are UNSIGNED, therefore always * positive. Test the high order bit with a mask. ****************************************************************/ #define MIDI_CMD_BIT 0x80 #define HIGH_BIT 0x80000000 #define istime(note) (!(((note)->when) & HIGH_BIT)) typedef union note_struct { byte n[4]; long when; } *note_type, note_node; private note_type event_buff; /* pointer to allocated buffer */ private note_type next; /* pointer to next entry in buffer */ private note_type last; /* pointer to last entry in buffer */ private int pile_ups; /* inner loop iteration count */ private int max_pile_up; /* maximum of pile_ups */ private boolean fixed_octave; /* used to avoid many error messages */ /**************************************************************************** * Routines local to this module ****************************************************************************/ private void bend_filter(); private void byteorder(); private void ctrl_filter(); private int event_bend(); private void filter(); private long getdur(); private long getnext(); private char map_ctrl(); private void output(); /**************************************************************************** * bend_filter * Inputs: * note_type note: the current note * note_type last: the last recorded event * long now: the current time * Effect: * remove pitch bend events in same 0.01 sec time slot * Implementation: * If the current event is a pitch bend that bends again * in the same time slot, make it a no-op by replacing it with * the time. ****************************************************************************/ private void bend_filter(note, last, now) note_type note; /* current note */ note_type last; /* the last recorded event */ long now; /* the current time */ { /* first see if there is another bend in this time * slot. */ note_type note2 = note + 1; while (note2 < last) { if (istime(note2) && (note2->when > now)) { break; /* new time slot */ } else if (note->n[0] == note2->n[0]) { note->when = now; return; /* found another bend */ } note2++; } } /**************************************************************************** * byteorder * Effect: * check out assumptions about byte order and placement ****************************************************************************/ private void byteorder() { note_node test_event; if ((sizeof(test_event) != 4) || (sizeof(test_event.when) != 4) || (sizeof(test_event.n[0]) != 1)) { gprintf(ERROR, "implementation error: size problem\n"); EXIT(1); } test_event.n[0] = 0x12; test_event.n[1] = 0x34; test_event.n[2] = 0x56; test_event.n[3] = 0x78; if ((test_event.when != 0x78563412) && (test_event.when != 0x12345678)) { gprintf(ERROR, "implementation error: layout problem\n"); EXIT(1); } } /**************************************************************************** * ctrl_filter * Inputs: * note_type note: the current note * note_type last: the last recorded event * long now: the current time * Effect: * remove ctrl change events in same 0.01 sec time slot * Implementation: * If the current event is a control change that changes again * in the same time slot, make it a no-op by replacing it with * the time. ****************************************************************************/ private void ctrl_filter(note, last, now) note_type note; /* the current note */ note_type last; /* the last recorded event */ long now; /* the current time */ { /* see if there is another control change in this time * slot. */ note_type note2 = note+1; while (note2 < last) { if (istime(note2) && (note2->when > now)) { break; /* new time slot */ } else if ((note->n[0] == note2->n[0]) && (note->n[1] == note2->n[1])) { note->when = now; return; /* found another change */ } note2++; } } /**************************************************************************** * event_bend * Inputs: * note_type note: pointer to a pitch bend event * Outputs: * returns int: an 8 bit pitch bend number ****************************************************************************/ private int event_bend(note) note_type note; { return((int) (((note->n[1]) >> 6) + ((note->n[2]) << 1))); } /**************************************************************************** * filter * Inputs: * note_type last: the last note recorded * Effect: allow only one control change per time slot (0.01 sec) * Implementation: * call ctrl_filter and bend_filter to overwrite control changes with * noop data (the current time is used as a noop) ****************************************************************************/ private void filter(last) note_type last; { note_type note; /* loop control variable */ long now=0; /* last time seen */ int command; /* command pointed to by note */ for (note = event_buff; note <= last; note++) { if (istime(note)) { now = note->when; } else { command = note->n[0] & MIDI_CODE_MASK; if (command == MIDI_CTRL && note->n[1] == SUSTAIN) { /* do nothing */; } else if (command == MIDI_CTRL) { ctrl_filter(note, last, now); } else if (command == MIDI_TOUCH) { bend_filter(note, last, now); /* bend and touch use the */ } else if (command == MIDI_BEND) { /* same filter routines */ bend_filter(note, last, now); } } } } /**************************************************************************** * getdur * Inputs: * int i: index of the note * note_type last: pointer to the last event recorded * int ped: TRUE if pedal is down at event i * long now: the time at event i * Outputs: * returns long: the duration of note i * Assumes: * assumes i is a note * Implementation: * This is tricky because of pedal messages. The note is kept on by * either the key or the pedal. Keep 2 flags, key and ped. Key is * turned off when a key is released, ped goes off and on with pedal. * Note ends when (1) both key and ped are FALSE, (2) key is * pressed (this event will also start another note). ****************************************************************************/ private long getdur(i, last, ped, now) int i; note_type last; int ped; long now; { int key = TRUE; /* flag that says if note is on */ long start = now; int chan = event_buff[i].n[0] & MIDI_CHN_MASK; int pitch = event_buff[i].n[1]; note_type note = &(event_buff[i+1]); int noteon; /* TRUE if a noteon message received on chan */ int keyon; /* TRUE if noteon message had non-zero velocity */ /* search from the next event (i+1) to the end of the buffer: */ for (; note < last; note++) { if (istime(note)) { now = note->when; } else { noteon = keyon = FALSE; if ((note->n[0] & MIDI_CHN_MASK) == chan) { noteon = ((note->n[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) && (note->n[1] == pitch); keyon = noteon && (note->n[2] != 0); if ((noteon && (note->n[2] == 0)) || (((note->n[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) && (note->n[1] == pitch))) key = FALSE; if (((note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) && note->n[1] == SUSTAIN && note->n[2] == 127) ped = TRUE; if (((note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) && note->n[1] == SUSTAIN && note->n[2] == 0) ped = FALSE; if ((!key && !ped) || keyon) return(now - start); } } } return(last->when - start); } /**************************************************************************** * getnext * Inputs: * int i: the index of the current note * note_type last: pointer to last valid data * long now: the current time * Outputs: * returns long: the time of the next note, program, or control change * (returns time of last event if nothing else is found) ****************************************************************************/ private long getnext(i, last, now) int i; /* the index of the current note */ note_type last; /* pointer to last valid data */ long now; /* the current time */ { i++; /* advance to next item */ for (; event_buff + i < last; i++) { note_type note = &(event_buff[i]); int cmd = note->n[0] & MIDI_CODE_MASK; if (istime(note)) { now = note->when; } else if (((cmd == MIDI_ON_NOTE) && (note->n[2] != 0)) /* note on */ || (cmd == MIDI_CH_PROGRAM) /* program change */ || ((cmd == MIDI_CTRL) && (note->n[1] != SUSTAIN) /* control change */ ) || (cmd == MIDI_TOUCH) || (cmd == MIDI_BEND)) { return(now); } } return(last->when); } /**************************************************************************** * map_ctrl * Inputs: * int control: a midi control number * Outputs: * returns char: an adagio control change command letter, EOS if * control change is not one of PORTARATE, PORTASWITCH, * MODWHEEL, FOOT ****************************************************************************/ private char map_ctrl(control) int control; { switch (control) { /* 'J' is no longer code for PORTARATE case PORTARATE: return 'J'; */ case PORTASWITCH: return 'K'; case MODWHEEL: return 'M'; case VOLUME: return 'X'; default: return EOS; } #ifdef LATTICE322 return EOS; /* make Lattice C type checker happy */ #endif } /**************************************************************************** * output * Inputs: * FILE *fp: an opened file pointer * note_type last: the last data in the buffer * boolean absflag: set to TRUE if first line of the adagio score should * include the absolute time * Effect: * write adagio file using data in event_buff * Implementation: * NOTE: put all program changes in rests * use N(ext) notation for all timing * output no more than one continuous parameter change per * clock tick for each continuous change parameter ****************************************************************************/ private void output(fp, last, absflag) FILE *fp; note_type last; boolean absflag; { int i; /* loop counter */ int command; /* the current command */ int voice; /* the midi channel of the current event */ int last_velocity = -1; /* used to filter repeated Lnn attributes */ int last_voice = 0; /* the default adagio channel (1) */ int ped = FALSE; /* flag maintains state of pedal */ int how_many = last - event_buff; long now=0; /* the time of the next event */ if (fp == NULL) { gprintf(ERROR, "internal error: output called with NULL file.\n"); EXIT(1); } if (debug_rec) gprintf(GDEBUG,"hint: if file is not being closed, decrease MAXSPACE\n"); fprintf(fp, "!MSEC\n"); /* times will be in milliseconds */ /* set the initial absolute time, all other times are relative */ if (absflag) { now = event_buff[0].when; if (now < 0) { fprintf(fp, "* First event took place at Adagio time %d,\n", (int)now); fprintf(fp, "* but Adagio cannot represent negative times,\n"); fprintf(fp, "* so this entire score will be %d ms late\n", (int)-now); gprintf(TRANS, "First event took place at Adagio time %d!\n", (int)now); gprintf(TRANS, "All events times will be %d ms late\n", (int)-now); now = 0L; } fprintf(fp, "T%ld ", now); } for (i = 0; i < how_many; i++) { if (debug_rec) { gprintf(GDEBUG,"ev %d: %x %x %x (%ld)\n", i, event_buff[i].n[0], event_buff[i].n[1], event_buff[i].n[2], event_buff[i].when); } if (istime(event_buff+i)) { now = event_buff[i].when; if (debug_rec) gprintf(GDEBUG,"i = %d, now = %ld\n", i, now); } else { boolean needs_voice = TRUE; command = event_buff[i].n[0] & MIDI_CODE_MASK; voice = event_buff[i].n[0] & MIDI_CHN_MASK; if (command == MIDI_ON_NOTE && event_buff[i].n[2] != 0) { int velocity = event_buff[i].n[2]; write_pitch(fp, event_buff[i].n[1]); fprintf(fp, " U%ld", getdur(i, last, ped, now)); if (last_velocity != velocity) { fprintf(fp, " L%d", velocity); last_velocity = velocity; } } else if (command == MIDI_CH_PROGRAM) { fprintf(fp, "Z%d", event_buff[i].n[1] + 1); } else if (command == MIDI_CTRL && event_buff[i].n[1] == SUSTAIN) { ped = (event_buff[i].n[2] != 0); needs_voice = FALSE; } else if (command == MIDI_CTRL) { char c = map_ctrl(event_buff[i].n[1]); if (c != EOS) fprintf(fp, "%c%d", c, event_buff[i].n[2]); else fprintf(fp, "~%d(%d)", event_buff[i].n[1], event_buff[i].n[2]); } else if (command == MIDI_TOUCH) { fprintf(fp, "O%d", event_buff[i].n[1]); } else if (command == MIDI_BEND) { fprintf(fp, "Y%d", event_bend(&event_buff[i])); } else if (command == MIDI_ON_NOTE || command == MIDI_OFF_NOTE) { needs_voice = FALSE; /* ignore note-offs */ } else { gprintf(ERROR, "Command 0x%x ignored\n", command); needs_voice = FALSE; } if (needs_voice) { if (last_voice != voice) { fprintf(fp, " V%d", voice + 1); last_voice = voice; } fprintf(fp, " N%d", (int)(getnext(i, last, now) - now)); fprintf(fp, "\n"); } } } } /**************************************************************************** * write_pitch * Inputs: * FILE *fp: an open file * int p: a pitch number * Effect: write out the pitch name for a given number ****************************************************************************/ void write_pitch(FILE *fp, int p) { static char *ptos[] = { "C", "CS", "D", "EF", "E", "F", "FS", "G", "GS", "A", "BF", "B" }; /* avoid negative numbers: adagio can't express lowest octave: */ while (p < 12) { if (!fixed_octave) { gprintf(ERROR, "%s%s%s", "A low note was transposed up an octave\n", "(Adagio cannot express the lowest MIDI octave).\n", "This message will appear only once.\n"); fixed_octave = TRUE; } p += 12; } fprintf(fp, "%s%d", ptos[p % 12], (p / 12) - 1); } /********************************************************************** * rec_final * Inputs: * boolean absflag: output absolute time of first note if TRUE * Effect: * Write recorded data to a file **********************************************************************/ void rec_final(FILE *fp, boolean absflag) { next->when = gettime(); last = next; if (debug_rec) gprintf(GDEBUG,"max_pile_up = %d, ", max_pile_up); gprintf(TRANS,"%ld times and events recorded.\n", (long) (last - event_buff)); filter(last); output(fp, last, absflag); fclose(fp); FREE(event_buff); max_notes = -1; } /**************************************************************************** * rec_init * Inputs: * char *file: pointer to file name from command line (if any) * boolean bender: TRUE if pitch bend should be enabled * Outputs: * return TRUE if initialization succeeds * Effect: * prepares module to record midi input ****************************************************************************/ /* ENOUGH_ROOM says if we have room for 10000 events + 10000 timestamps = * 20000 note_struct's, then that's "enough room" for recording a sequence. * If more ram is available, it won't be used. If less is available, we'll * use as much as we can get, minus "SPACE_FOR_PLAY", which leaves a little * bit of spare ram in case Moxc or stdio need to allocate some space. * For DOS, we limit recording space to 64K. */ #ifdef DOS #define ENOUGH_ROOM 64000L #else #define ENOUGH_ROOM (20000L * sizeof(union note_struct)) #endif boolean rec_init(boolean bender) { size_t biggestChunk, spaceForRecord; debug_rec = cl_switch("debug"); byteorder(); pile_ups = 0; max_pile_up = 0; previous_time = (unsigned) -1L; /* this will force putting in initial timestamp */ fixed_octave = FALSE; if (max_notes == -1) { /* allocate space 1st time rec_init called */ biggestChunk = AVAILMEM; if (biggestChunk <= SPACE_FOR_PLAY) { /* not enough memory; give up */ return(FALSE); } else { spaceForRecord = MIN((biggestChunk - SPACE_FOR_PLAY), ENOUGH_ROOM); /* leave SPACE_FOR_PLAY contiguous bytes of memory */ } max_notes = spaceForRecord / sizeof(note_node); /* gprintf(GDEBUG,"max_notes = %d\n", max_notes);*/ event_buff = (note_type) MALLOC(spaceForRecord); if (event_buff == NULL) { /* should never happen */ gprintf(FATAL, "Implementation error (record.c): getting memory."); return FALSE; } } next = event_buff; last = event_buff + max_notes - 2; /* it is critical that last not point * to the very last storage loc */ midi_cont(bender); return((boolean)(max_notes > 10)); /* it would be silly to record with only room enough for 10 notes! */ } /**************************************************************************** * rec_event * Inputs: * long time: the current time * long data: midi data to record * Outputs: * returns FALSE if there is no more memory * Effect: reads and stores any input * Implementation: * time stamps and midi events share the same buffer of 4-byte events * save time at most once per call to rec_poll * save time only if it changes ****************************************************************************/ boolean rec_event(long *data, time_type time) { /* can't allow negative time because sign bit distinguishes * data from time: */ if (time < 0) time = 0; if (previous_time != time) { next++->when = previous_time = time; if (next >= last) goto overflow; } next->when = *data; next++->n[3] = MIDI_CMD_BIT; /* set tag bit */ if (next >= last) goto overflow; return TRUE; overflow: next = last; /* last doesn't really point to last storage */ gprintf(ERROR, "No more memory.\n"); return FALSE; } nyquist-3.05/cmt/userio.c0000644000175000000620000010624711466723256014446 0ustar stevestaff/* userio.c -- handy user interface functions */ /* Copyright 1989 Carnegie Mellon University */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 21-May-86 | Created * 11-Aug-87 | F.H: Added clear_abort(), stop() * May-88 | JCD : AMIGA VERSION * 11-Jun-88 | RBD: disable printing of GDEBUG messages * 12-Oct-88 | JCD : EXCLUSIVE AMIGA VERSION * 13-Apr-89 | JCD : New portable version. * 5-Apr | JDW : Further changes * 2-Mar-92 | GWL : Little changes to satisfy compiler * 19-Nov-92 | JDZ : Mach tty io threads * 28-Apr-03 | DM : portability changes. true->TRUE, false->FALSE *****************************************************************************/ /* Notes on ascii input: Input is complicated because different systems have varying input models, especially with regard to handling ^C. The CMT model handles ^C and ^G as special characters, and these do not cause software interrupts. Also, the lowest level of the CMT model does not support line editing: Every character is acted upon immediately. This has two implications: (1) CMT must "read ahead" looking for ^C and ^G characters. This is handled by the check_aborted() procedure, which reads characters into the type_ahead[] array. (2) CMT must do its own line editing. This is handled by the ggets() routine. A number of functions support ascii input, only some of which are visible to the application programmer. Let's start at the top-level and work down; each of the following calls the routine below it: ggets() - gets a string with line editing support. This function is fairly machine independent, except for some backspace-and-erase control character code sequences. ggetchar() - gets a raw character. This function calls wait_ascii() and echoes it. Note that it may return ABORT_CHAR or BREAK_CHAR. wait_ascii() - gets a raw character without echo and without character code translation. wait_ascii() either polls get_ascii() or uses some kind of system-dependent event waiting. Returns ABORT_CHAR or BREAK_CHAR immediately if abort_flag has been set, regardless of whether there is new ascii input. get_ascii() - checks to see if a character is available. (Using check_aborted().) The only dependency here is on the Amiga, we restart input when buffer goes from full to non-full. check_aborted() - looks for input by calling ascii_input. If found, put the input into the type_ahead[] buffer. Returns abort_flag. ascii_input() - lowest level of input; just gets a character if there is one. Does conversion from RETURN (\r) to EOL (\n). The Amiga handles this in-line directly in check_aborted(). Here's a quick summary: ggets = ggetchar + line editing & string building ggetchar = wait_ascii + character echo wait_ascii = get_ascii + wait for character get_ascii = check_aborted + pull char from buffer check_aborted = ascii_input + test for ^C,^G + put in buffer ascii_input = poll for char + CR->EOL conversion */ #include "switches.h" #include #include #if HAS_STDLIB_H #include /* normal case */ #endif #ifdef MACINTOSH # include "StandardFile.h" /* added for ThinkC 7 */ # ifdef THINK_C # include # endif #endif #ifdef AMIGA # ifdef AZTEC # include "functions.h" # else /* LATTICE */ # include "amiga.h" # include "stdarg.h" # endif # include "intuition/intuition.h" # include "devices/console.h" #endif #include "ctype.h" #include "stdio.h" #include "cext.h" #include "userio.h" #ifdef MICROSOFT #include "signal.h" #endif #ifdef UNIX_MACH #include #include extern char a_in; extern int a_in_flag; extern int i_am_running; #ifdef RTMach extern itc_mutex_t a_mutex; extern itc_condition_t a_cond, a_in_cond; #define A_LOCK() itc_mutex_lock(&a_mutex) #define A_UNLOCK() itc_mutex_unlock(&a_mutex) #else /* RTMach */ extern struct mutex a_mutex; extern struct condition a_cond, a_in_cond; #define A_LOCK() mutex_lock(&a_mutex) #define A_UNLOCK() mutex_unlock(&a_mutex) #endif /* RTMach */ #endif #ifdef DOTS_FOR_ARGS #include #endif #ifdef UNIX #include #include #include "cmtio.h" #ifdef _IBMR2 #define NBBY 8 #define OPEN_MAX 2000 #endif #include #endif #ifdef linux #include /* for FD_ZERO / FD_SET */ #endif extern int debug; #ifdef NYQUIST /* get definitions for stdputstr, etc. */ #include "xlisp.h" #endif /**************************************************************************** * * routines private to this module * ****************************************************************************/ int GetReadFileName(); int GetWriteFileName(); #ifdef MACINTOSH private void PtoC_StrCopy(char *p1, char *p2); #endif #ifdef AMIGA char ConGetChar(); ConMayGetChar(); private void ConRead(); private void ConPutStr(); private void ConPutChar(); UBYTE ascii_signal(); UBYTE KeybSig(); #endif /**************************************************************************** * * variables shared with other modules * ****************************************************************************/ public int abort_flag; /* control C or control G equivalent */ public int redirect_flag; /* check whether the I/O has been redirected-- Added by Ning Hu Apr.2001*/ /* extern void musicterm(); */ /*DMH: from macmidi.c, to allow abort_check*/ public boolean ascii_input(); /**************************************************************************** * * variables private to this module * ****************************************************************************/ #ifdef AMIGA struct IntuitionBase *IntuitionBase; private struct IOStdReq *ConOutReq; private struct MsgPort *ConOutPort; private struct IOStdReq *ConInReq; private struct MsgPort *ConInPort; private char KeyBuff[16]; private struct Window *Window; private struct NewWindow NewWindow = { 0,11,640,189, 0,1, NULL, SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING, NULL,NULL, (STRPTR) "Carnegie Mellon University MIDI Toolkit for Commodore AMIGA", NULL,NULL, 100,25,640,200, WBENCHSCREEN }; #endif #ifdef MACINTOSH private OSType io_file_type = 0x3F3F3F3F; /* '????' */ private OSType io_file_creator = 0x3F3F3F3F; /* '????' */ #endif #define type_ahead_max 100 char type_ahead[100]; int type_ahead_head = 0; int type_ahead_tail = 0; int type_ahead_count = 0; #ifdef DOS #ifdef BORLAND int c_break(void) { gprintf(TRANS, " BREAK "); abort_flag = ABORT_LEVEL; return 1; /* non-zero means do not exit program */ } #endif #ifdef MICROSOFT void c_break(int sig) { abort_flag = ABORT_LEVEL; /* The CTRL+C interrupt must be reset to our handler since * by default it is reset to the system handler. */ signal(SIGINT, c_break); /* assume this succeeds */ } #endif #endif #ifdef MACINTOSH #ifdef NYQUIST void FlushOutput (void); #endif #endif /* gflush -- flush output produced by gprintf, etc. */ /**/ void gflush(void) { #ifdef MACINTOSH #ifdef NYQUIST FlushOutput(); #else fflush(stdout); /* make sure any prompts or errors have been output */ fflush(STDERR); #endif /* NYQUIST */ #endif /* MACINTOSH */ #ifdef UNIX fflush(stdout); /* make sure any prompts or errors have been output */ fflush(STDERR); #endif } /**************************************************************************** * io_init * * I added this init function for the AMIGA version. * * io_init : opens a window * and exits if initialisation can not be done properly. * registers cleanup calls to carefully deallocate resources. * * io_init is not amiga specific : the simplest version * of io_init could be a clear screen statement for example, and a * printf("Good bye !\n") on exit. * * for the Mac, it seems that ascii_input doesn't work unless getchar() is * called first. I assume this is because getchar() initializes the ability * of the window to process type-in, so there is probably a way to set this * directly. If you figure it out, let me know. -RBD * *****************************************************************************/ void io_init() { #ifdef AMIGA int error; /* Window and console initialisation */ IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",1L); if (IntuitionBase == NULL) EXIT(1); cu_register((cu_fn_type) CloseLibrary, IntuitionBase); ConOutPort = CreatePort("conoutport", 0L); if (ConOutPort == NULL) EXIT(1); cu_register((cu_fn_type) DeletePort, ConOutPort); ConOutReq = CreateStdIO(ConOutPort); if (ConOutReq == NULL) EXIT(1); cu_register((cu_fn_type) DeleteStdIO, ConOutReq); ConInPort = CreatePort("coninport", 0L); if (ConInPort == NULL) EXIT(1); cu_register((cu_fn_type) DeletePort, ConInPort); ConInReq = CreateStdIO(ConInPort); if (ConInReq == NULL) EXIT(1); cu_register((cu_fn_type) DeleteStdIO, ConInReq); Window = OpenWindow(&NewWindow); if (Window == NULL) EXIT(1); cu_register((cu_fn_type) CloseWindow, Window); ConOutReq->io_Data = (APTR)Window; ConOutReq->io_Length = sizeof(*Window); error = OpenDevice("console.device", 0L, (struct IORequest *) ConOutReq, 0L); ConInReq->io_Device = ConOutReq->io_Device; ConInReq->io_Unit = ConOutReq->io_Unit; if (error != NULL) EXIT(1); cu_register((cu_fn_type) CloseDevice, ConOutReq); ConInReq->io_Command = CMD_READ; ConInReq->io_Data = (APTR)KeyBuff; ConInReq->io_Length = 1; SendIO((struct IORequest *) ConInReq); #endif #ifdef UNIX #ifndef BUFFERED_SYNCHRONOUS_INPUT IOsetup(0 /* standard input */); cu_register((cu_fn_type) IOcleanup, NULL); #endif #endif #ifdef MACINTOSH #ifndef NYQUIST /* don't need this if we're in Nyquist */ char s[100]; printf("Type to start: "); fgets(s, 100, stdin); #endif /* NYQUIST */ #endif #ifdef DOS #ifdef MICROSOFT if (signal(SIGINT, c_break) == SIG_ERR) { gprintf(ERROR, "Couldn't set Ctrl C handler\n"); EXIT(1); } #else #ifdef BORLAND ctrlbrk(c_break); #else ... we are in DOS, but neither MICROSOFT nor BORLAND, please set up a control C handler here... #endif #endif #endif } #ifdef MACINTOSH /**************************************************************************** * abort_check * Effect: * exit nicely if the aborted flag is set ****************************************************************************/ public void abort_check() { if (abort_flag) clean_exit(); } /**************************************************************************** * clean_exit * Effect: * clean up and exit ****************************************************************************/ public void clean_exit() { gprintf(TRANS, "Exiting...\n"); EXIT(1); } #ifdef MPW /**************************************************************************** * cleanup_abort_handler * Effect: * shuts down abort watcher ****************************************************************************/ public void cleanup_abort_handler() { (void) sigset(SIGINT, SIG_DFL); /* deactivate abort watcher */ } /**************************************************************************** * init_abort_handler * Effect: * starts abort watcher * aborted flag is set to FALSE ****************************************************************************/ public void init_abort_handler() { abort_flag = FALSE; (void) sigset(SIGINT, abort_watcher); /* activate abort watcher */ } #endif #endif /**************************************************************************** * askbool * Inputs: * char *prompt: string to prompt for user input * int deflt: TRUE or FALSE default * Returns: * boolean: TRUE or FALSE as entered by user * Effect: * prompts user for yes or no input, returns result ****************************************************************************/ int askbool(prompt, deflt) char *prompt; int deflt; { #define undefined -1 char defchar; /* the default answer */ char c; /* user input */ char in_string[100]; int result = -1; /* the result: -1 = undefined, 0 = FALSE, 1 = TRUE */ if (deflt) defchar = 'y'; else defchar = 'n'; while (result == undefined) { gprintf(TRANS, "%s? [%c]: ", prompt, defchar); ggets(in_string); c = in_string[0]; if (islower(c)) c = toupper(c); if (c == 'Y') result = TRUE; else if (c == 'N') result = FALSE; else if (c == EOS) result = deflt; else if (abort_flag) result = deflt; /* space before Please to separate from user's type-in: */ else gprintf(TRANS, " Please type Y or N.\n"); } if (abort_flag == BREAK_LEVEL) { abort_flag = 0; result = deflt; gprintf(TRANS, "\n"); } return result; } /**************************************************************************** * fileopen * Inputs: * char *deflt: the default file name (e.g. from command line) * char *extension: default extension * char *mode: read ("r") or write ("w") * char *prompt: prompt for user * Returns: * opened file pointer * Effect: * opens file, prompts for user input if necessary and warns about * possible confusion. If deflt is a null string or NULL, the user will * be prompted for a name. The routine loops until a file is opened. * If the mode is "r", a check is made to see if the file exists * with and without the extension. If both exist a warning is given. * For mode "w", a check is made to see if the file will be overwritten. * The extension is automatically added if the default or user-typed * file has no "." At the bottom of the loop body, if no file has * been opened, the user is prompted for another file name. ****************************************************************************/ char fileopen_name[100]; /* name of the opened file */ FILE *fileopen(deflt, extension, mode, prompt) char *deflt; char *extension; /* default extension */ char *mode; /* read "r" or write "w" */ char *prompt; /* prompt for user */ { char extname[100]; /* trial name with extension added */ FILE *fp = NULL; /* file corresponding to filename */ FILE *fpext; /* file corresponding to extname */ char *problem = NULL; /* tells user why he has to try again */ if (!deflt) deflt = ""; /* treat NULL as the empty string */ strcpy(fileopen_name, deflt); /* keep trying until a good file is found: */ while (fp == NULL) { /* avoid null file names: */ while (strlen(fileopen_name) == 0) { #ifndef MACINTOSH gprintf(TRANS, "%s : ", prompt); ggets(fileopen_name); if (abort_flag) { if (abort_flag == BREAK_LEVEL) { abort_flag = 0; /* type return since user didn't... */ gprintf(TRANS, "\n"); } return NULL; } #else /* use Macintosh file dialog */ if (mode[0] == 'r') { if (!GetReadFileName(fileopen_name)) return NULL; } else if (mode[0] == 'w') { if (!(GetWriteFileName(fileopen_name, prompt))) return NULL; } else { gprintf(ERROR, "(fileopen) internal error: bad mode\n"); } #endif /* MACINTOSH */ } if (mode[0] == 'r') { strcpy(extname, fileopen_name); strcat(extname, "."); strcat(extname, extension); fp = fopen(fileopen_name, mode); fpext = fopen(extname, mode); if (fp != NULL && fpext != NULL) { gprintf(TRANS, "warning: both %s and %s exist. %s will be used.\n", fileopen_name, extname, fileopen_name); fclose(fpext); } else if (fpext != NULL) { fp = fpext; strcpy(fileopen_name, extname); /* remember what was opened */ } if (fp == NULL) problem = "Couldn't find %s.\n"; } else if (mode[0] == 'w') { boolean added_extension = FALSE; /* add the extension if there is no '.' in the file name */ if (!strchr(fileopen_name, '.')) { strcat(fileopen_name, "."); strcat(fileopen_name, extension); added_extension = TRUE; } if (TRUE #ifdef MACINTOSH /* file open dialog already asked user to confirm unless we're * adding an extension */ && added_extension #endif ) { fp = fopen(fileopen_name, "r"); if (fp != NULL) { char question[100]; fclose(fp); strcpy(question, "OK to overwrite "); strcat(question, fileopen_name); if (!askbool(question, FALSE)) { fp = NULL; problem = "\n"; goto tryagain; } } } fp = fopen(fileopen_name, mode); if (fp == NULL) problem = "Couldn't create %s.\n"; } tryagain: if (fp == NULL) { gprintf(TRANS, problem, fileopen_name); gprintf(TRANS,"Try again.\n"); fileopen_name[0] = EOS; } } return fp; } #ifdef MACINTOSH static int GetReadFileName(name) char *name; { static Point p = {100,100}; SFReply loadfile; SFTypeList mytypes; mytypes[0] = 0x54455854; /* 'TEXT' */ mytypes[1] = 0x4D696469; /* 'Midi' */ mytypes[2] = 0x3F3F3F3F; /* '????' */ /* could put any filter here (i.e. giofilefileter) */ SFGetFile(p, "\p", NULL, 3, mytypes, 0L, &loadfile); if (loadfile.good) { SetVol(0L,loadfile.vRefNum); PtoC_StrCopy((char *) &loadfile.fName, name); return(true); } else return(false); } static int GetWriteFileName(fn, str) char *fn, *str; { static Point SFPwhere = { 106, 104 }; unsigned char Pstr[100], Pfn[100]; SFReply reply; strcpy((char *)Pstr, str); CtoPstr((char *)Pstr); strcpy((char *)Pfn, fn); CtoPstr((char *)Pfn); SFPutFile(SFPwhere, (ConstStr255Param) Pstr, (ConstStr255Param) Pfn, 0L, &reply); if (reply.good) { SetVol (0L,reply.vRefNum); PtoC_StrCopy((char *) &reply.fName, fn); return(true); } else return(false); } void PtoC_StrCopy(p1, p2) register char *p1, *p2; /* copies a pascal string from p1 to p2 */ { register int len; len = *p1++; while (--len>=0) *p2++=*p1++; *p2 = '\0'; } boolean get_file_info(char *filename, OSType *file_type, OSType *file_creator) { short rc; /* toolbox return code */ FInfo fi; /* toolbox file info */ char fn[101]; /* temporary file name */ strcpy(fn, filename); CtoPstr(fn); if (rc = GetFInfo((byte*)fn, 0, &fi)) { gprintf(ERROR, "rc from GetFInfo=%d\n", rc); gprintf(ERROR, "unable to get file type\n"); *file_type = 0x3F3F3F3F; /* '????' */ *file_creator = 0x3F3F3F3F; /* '????' */ return FALSE; } else /* set file type & creator */ { if (debug) gprintf(TRANS, "File Type: '%.4s' File Creator: '%.4s'\n", &fi.fdType, &fi.fdCreator ); *file_type = fi.fdType; *file_creator = fi.fdCreator; } return TRUE; } boolean put_file_info(char *filename, OSType file_type, OSType file_creator) { short rc; /* toolbox return code */ FInfo fi; /* toolbox file info */ char fn[101]; /* temporary file name */ if (debug) gprintf(TRANS,"set file %s to become type '%.4s'\n", filename, &file_type); strcpy(fn, filename); CtoPstr(fn); if (rc = GetFInfo((byte*)fn, 0, &fi)) { gprintf(TRANS, "rc from GetFInfo=%d\n", rc); gprintf(TRANS, "unable to set file type\n"); } else /* set file type & creator */ { if (debug) gprintf(TRANS, "File Type: '%.4s' File Creator: '%.4s'\n", &fi.fdType, &fi.fdCreator ); fi.fdType = file_type; fi.fdCreator = file_creator; if (rc=SetFInfo((byte*)fn, 0, &fi)) { gprintf(TRANS, "rc from SetFInfo=%d\n", rc); gprintf(TRANS, "unable to set file type\n"); } else if (rc=GetFInfo((byte*)fn, 0, &fi)) { gprintf(TRANS, "rc from GetFInfo=%d\n", rc); gprintf(TRANS, "unable to verify file type\n"); } else { if (debug) gprintf(TRANS, "File Type: '%.4s' File Creator: '%.4s'\n", &fi.fdType, &fi.fdCreator ); } } } #endif /* MACINTOSH */ #ifdef AMIGA /*************************************************************** * ascii_signal * * Input : none * Ouput : none * Return: the signal that will be raised on ascii input * Effect: none ***************************************************************/ UBYTE ascii_signal() { return ConInPort->mp_SigBit; } #endif /* check_aborted -- see if any characters are available, check for ctrl C */ int check_aborted() { char in_c; #ifdef AMIGA if (GetMsg(ConInPort)) { in_c = KeyBuff[0]; if (in_c == '\r') in_c = '\n'; #endif #ifndef AMIGA /* DOS or MACINTOSH or UNIX */ if (type_ahead_count < type_ahead_max && ascii_input(&in_c)) { #endif type_ahead[type_ahead_tail] = in_c; if (in_c == ABORT_CHAR) abort_flag = ABORT_LEVEL; else if (!abort_flag && in_c == BREAK_CHAR) abort_flag = BREAK_LEVEL; /* go ahead and insert anything into buffer, including ^C, ^G: */ type_ahead_count++; type_ahead_tail++; if (type_ahead_tail == type_ahead_max) type_ahead_tail = 0; #ifdef AMIGA if (type_ahead_count < type_ahead_max) ConRead(); #endif } return abort_flag; } /**************************************************************************** * readln * Inputs: * FILE * fp: File to read from * Effect: * Reads and discards characters until a newline is seen ****************************************************************************/ void readln(fp) register FILE *fp; { register int c; while (((c = getc(fp)) != '\n') && (c != EOF)) ; } /**************************************************************************** * gprintf * Inputs: * int * handler: pointer to output handler (say, a window) * or one of {TRANS, ERROR, FATAL, GDEBUG} from userio.h * char * format: a null-terminated printf style format string * int arg0 through arg14: a variable number of arguments for printf * Effect: * formats and outputs the specified information to an output handler. * this is a system-independent approach to output. On * a simple machine, it is like printf. on a more complex machine, * output is directed to the appropriate window. * Implementation * Note that to handle the variable argument list, a number of different * approaches are implemented. The first part of the implementation selects * one of 4 ways to build temp1, a formatted string. The 4 ways arise from * use or non-use of vsprintf, and use or non-use of ... in the arg list. * After building temp1, non-Amiga systems write to stdout or stderr, * whereas AMIGA writes to a special console. Why? Because the Amiga * needs a new console so we can set up a signal upon character typein. ****************************************************************************/ #ifndef gprintf #define GPRINTF_MESSAGE_LEN 512 #ifdef USE_VSPRINTF #ifdef DOTS_FOR_ARGS /* define with ... in arg list and use vsprintf to get temp1 */ public void gprintf(long where, char *format, ...) { char temp1[GPRINTF_MESSAGE_LEN]; #ifdef AMIGA char temp2[GPRINTF_MESSAGE_LEN]; #endif va_list ap; va_start(ap, format); vsprintf(temp1, format, ap); va_end(ap); #else /* !DOTS_FOR_ARGS */ /* define with va_alist and use vsprintf to get temp1 */ public void gprintf(where, format, va_alist) long where; char *format; va_dcl { char temp1[GPRINTF_MESSAGE_LEN]; va_list pvar; /* this is a syntax error - if you don't have to remove this, */ /* then this whole section of code is unnecessary. */ va_start(pvar); vsprintf(temp1, format, pvar); va_end(pvar); #endif /* DOTS_FOR_ARGS */ #else /* !USE_VSPRINTF */ #define MAX_GPRINTF_ARGS 10 typedef struct gp_args_struct { long arg[MAX_GPRINTF_ARGS]; } gp_args_node; #ifdef DOTS_FOR_ARGS /* use ... but not vsprintf */ public void gprintf(long where, char *format, ...) { char temp1[GPRINTF_MESSAGE_LEN]; #ifdef AMIGA char temp2[GPRINTF_MESSAGE_LEN]; #endif va_list ap; gp_args_node args; va_start(ap, format); args = va_arg(ap, gp_args_node); va_end(ap); #else /* !DOTS_FOR_ARGS */ /* don't use ... and don't use vsprintf */ public void gprintf(where, format, args) long where; char *format; gp_args_node args; { char temp1[GPRINTF_MESSAGE_LEN]; #ifdef AMIGA char temp2[GPRINTF_MESSAGE_LEN]; #endif /* AMIGA*/ #endif /* DOTS_FOR_ARGS */ sprintf(temp1, format, args); #endif /* USE_VSPRINTF */ /* * Now we've got formatted output in temp1. Write it out. */ #ifdef NYQUIST switch ((long) where) { case TRANS: stdputstr(temp1); break; case ERROR: errputstr(temp1); break; case FATAL: errputstr("FATAL: "); errputstr(temp1); break; case GDEBUG: errputstr("DEBUG: "); errputstr(temp1); break; default: errputstr("UNKNOWN: "); errputstr(temp1); break; } gflush(); #else /* not NYQUIST */ #ifdef AMIGA switch((long) where) { case TRANS: strcpy(temp2, temp1); break; case ERROR: strcpy(temp2, temp1); break; case FATAL: strcpy(temp2, "FATAL: "); strcat(temp2, temp1); break; case GDEBUG: strcpy(temp2,"DEBUG: "); strcat(temp2, temp1); break; default: strcpy(temp2, "UNKNOWN: "); strcat(temp2, temp1); break; } ConOutReq->io_Command = CMD_WRITE; ConOutReq->io_Data = (APTR)temp2; ConOutReq->io_Length = -1; /* NULL terminated string */ DoIO((struct IORequest *) ConOutReq); #else /* not NYQUIST or AMIGA */ switch(where) { case TRANS: printf("%s", temp1); break; case ERROR: fprintf(STDERR, "%s", temp1); break; case GDEBUG: fprintf(STDERR, "DEBUG %s", temp1); break; case FATAL: fprintf(STDERR, "FATAL %s", temp1); break; default: fprintf(STDERR, "UNKNOWN %s", temp1); break; } #endif /* AMIGA */ #endif /* NYQUIST */ } #endif /* ifndef gprintf */ /************************************************************************** * gputchar * General putchar **************************************************************************/ #ifndef gputchar #ifdef AMIGA public int gputchar(c) int c; { ConPutChar((char)c); return(c); } #else public int gputchar(c) int c; { putchar((char)c); return(c); } #endif #endif /* ifndef gputchar */ /************************************************************************** * ggetchar * General getchar **************************************************************************/ public int ggetchar() { #ifdef BUFFERED_SYNCHRONOUS_INPUT return getchar(); #else int key = wait_ascii(); if (key != ABORT_CHAR && key != '\b') gputchar((char)key); return(key); #endif } /************************************************************************** * ggets * General gets **************************************************************************/ #ifndef ggets public char *ggets(str) char *str; { char *s = str; int c; do { c = ggetchar(); if (c == '\b' /* backspace */) { if (s != str) { gputchar('\b'); gputchar((int)' '); gputchar('\b'); s--; } else { #ifdef AMIGA gputchar((int)0x9b); gputchar((int)0x43); #else /* gputchar((int)' '); */ #endif gputchar((int)0x07); } } else *s++ = (char) c; } while (c != (int) '\n' && !abort_flag); *(s-1) = EOS; if (abort_flag) *str = EOS; return str; } #endif /* ifndef ggets */ /**************************************************************************** * get_ascii * Returns: * boolean: TRUE if a character was found * int * c: pointer to int into which to store the character, if any * Effect: * polls (doesn't wait) for an ascii character and says if it got one * the character is returned in *c. ****************************************************************************/ public boolean get_ascii(c) char *c; { check_aborted(); /* input buffer check */ if (type_ahead_count == 0) return FALSE; #ifdef AMIGA /* if the buffer is full, then there is no outstanding read, restart it: */ if (type_ahead_count == type_ahead_max) ConRead(); #endif type_ahead_count--; *c = type_ahead[type_ahead_head++]; if (type_ahead_head == type_ahead_max) type_ahead_head = 0; return TRUE; } #ifdef MACINTOSH /** Macintosh direct ascii input**/ public boolean ascii_input(c) char *c; { EventRecord theEvent; (void) GetNextEvent((keyDownMask | autoKeyMask), &theEvent); if ((theEvent.what == keyDown) || (theEvent.what == autoKey)) { *c = theEvent.message & charCodeMask; if (*c == '\r') *c = '\n'; return(true); } else { return(false); } } #endif #ifdef WINDOWS #include "conio.h" #define kbhit _kbhit #define getch _getch #endif #ifdef DOS public boolean ascii_input(c) char *c; { if (abort_flag == ABORT_LEVEL) { *c=ABORT_CHAR; return((boolean)TRUE); } if (kbhit()) { /* If the keyboard was hit */ *c = getch(); /* Don't echo it */ // printf("now break"); if (*c == '\r') *c = '\n'; return((boolean)TRUE); } return((boolean)FALSE); /* Keeps Lattice compiler happy */ } #endif #ifdef UNIX public boolean ascii_input(c) char *c; { #ifdef UNIX_MACH /* * we can't read from stdin directly, because the ascii * input thread is already doing so, so instead we'll * wait for that thread to read a character and then take * it */ boolean ret = FALSE; A_LOCK(); if (a_in_flag) { (*c) = a_in; a_in_flag = 0; ret = TRUE; } A_UNLOCK(); if (ret) { #ifdef RTMach itc_condition_signal(&a_cond); #else /* RTMach */ condition_signal(&a_cond); #endif /* RTMach */ } if ((*c) == '\r') (*c) = '\n'; return(ret); #else /* UNIX_MACH */ #ifndef BUFFERED_SYNCHRONOUS_INPUT int input = IOgetchar(); if (input != IOnochar) { *c = input; if (*c == '\r') *c = '\n'; return TRUE; } #endif /* BUFFERED_SYNCHRONOUS_INPUT */ return FALSE; #endif /* UNIX_MACH */ } #endif #ifndef AMIGA /*DOS and MAC and UNIX */ public void unget_ascii(char c) { if (type_ahead_head == 0) type_ahead_head = type_ahead_max; type_ahead_head--; type_ahead[type_ahead_head] = c; type_ahead_count++; } public boolean check_ascii() { char c; if(get_ascii(&c)) { unget_ascii(c); return TRUE; } else return FALSE; } #endif /**************************************************************************** * wait_ascii * Returns: * int: character for key pressed * Effect: * waits for the user to type a key on the terminal keyboard * (versus the synthesizer keyboard) and returns the key typed ****************************************************************************/ #ifdef MACINTOSH public int wait_ascii() { char key ; /* key typed */ if (abort_flag == ABORT_LEVEL) return ABORT_CHAR; if (abort_flag == BREAK_LEVEL) return BREAK_CHAR; gflush(); while (!get_ascii(&key)) ; return(key); } #endif #ifdef DOS public int wait_ascii() { char key ; /* key typed */ if (abort_flag == ABORT_LEVEL) return ABORT_CHAR; if (abort_flag == BREAK_LEVEL) return BREAK_CHAR; if (!get_ascii(&key)) { key = _getch(); // block until we get an input } /* GWL - check for abort on previos line */ return (int)key; } #endif #ifndef MACINTOSH #ifndef DOS public int wait_ascii() { #ifdef UNIX /* was defined (UNIX) || defined(ITC) */ #ifndef UNIX_MACH fd_set readfds; #endif /* !UNIX_MACH */ #endif char c; struct rlimit file_limit; if (abort_flag == ABORT_LEVEL) return ABORT_CHAR; if (abort_flag == BREAK_LEVEL) return BREAK_CHAR; while (!get_ascii(&c)) { #ifdef AMIGA WaitPort(ConInPort); #endif #ifdef UNIX fflush(stdout); #ifdef UNIX_MACH /* * we can't select, since another thread is reading * from stdin, and we don't want to have an input war * so instead, the ascii input thread will signal * a_in_cond when it gets input, so we just wait * for that to happen */ A_LOCK(); #ifdef RTMach itc_condition_wait(&a_in_cond, &a_mutex); #else /* RTMach */ condition_wait(&a_in_cond, &a_mutex); #endif /* RTMach */ A_UNLOCK(); #else /* UNIX_MACH */ FD_ZERO(&readfds); FD_SET(IOinputfd, &readfds); gflush(); getrlimit(RLIMIT_NOFILE, &file_limit); select(file_limit.rlim_max+1, &readfds, 0, 0, NULL); #endif /* !UNIX_MACH */ #endif /* ifdef UNIX */ } return (int) c; } #endif #endif #ifdef AMIGA /****************************************************************** AMIGA 2000. Console IO Functions JCD 25-Apr-88 *******************************************************************/ UBYTE KeybSig() { return ConInPort->mp_SigBit; } private void ConPutChar(c) char c; { ConOutReq->io_Command = CMD_WRITE; ConOutReq->io_Data = (APTR)&c; ConOutReq->io_Length = 1; DoIO((struct IORequest *) ConOutReq); } private void ConPutStr(str) char *str; { ConOutReq->io_Command = CMD_WRITE; ConOutReq->io_Data = (APTR)str; ConOutReq->io_Length = -1; DoIO((struct IORequest *) ConOutReq); } private void ConRead() { ConInReq->io_Command = CMD_READ; ConInReq->io_Data = (APTR)KeyBuff; ConInReq->io_Length = 1; SendIO((struct IORequest *) ConInReq); } #endif nyquist-3.05/cmt/seqmwrite.c0000644000175000000620000005731211530257127015145 0ustar stevestaff/* created by DMH (damonhorowitz): write seq_type as standard midifile */ /*************************************************************************** * Change Log * Date | Change *-----------+--------------------------------------------------------------- * 11-Mar-94 | Created Change Log * 11-Mar-94 | PLu : Added private to function defs. * 28-Apr-03 | DM : Change #include's for portability ****************************************************************************/ #include "switches.h" #include #include "cext.h" #include "userio.h" #include "midicode.h" #include "mfmidi.h" #include "midifns.h" #include "timebase.h" #include "moxc.h" #include "seq.h" #include "seqread.h" /* to get scale() */ #include "seqmwrite.h" long chunk_size_marker; int seti_counter; extern time_type a_start_time; long last_event; /*time from last_clock_event to the last event*/ time_type last_clock_event; time_type last_tick_size; /* millisec per tick shifted 16 bits */ struct smf_write_seq { seq_type seq; int track; FILE *outfile; } smfw_seq; extern seq_type sequence; /* this is a global to be accessed by * routines called from the sequence */ /* clock state: */ extern time_type clock_ticksize; /* millisec per tick shifted 16 bits */ extern boolean clock_running; /* TRUE if clock is running */ extern boolean use_midi_clock; private void smfw_bend(); private void smfw_cause_noteoff(); private void smfw_ctrl(); private void smfw_deltatime(); private void smfw_dotrack(); private void smfw_exclusive(); private void smfw_noteoff(); private void smfw_noteon(); private void smfw_process_event(); private void smfw_ramp_event(seq_type seq, event_type event, unsigned int value, unsigned int to_value, int increment, time_type step, int n); private void smfw_send_macro(); private void smfw_touch(seq_type seq, int voice, int value); private void writevarlen(); /* smfw_bend -- write a pitch bend to a midi file */ /**/ private void smfw_bend(seq_type seq, int voice, int value) { if(debug) gprintf(TRANS, "smfw_bend %d\n", value); smfw_deltatime(); putc(MIDI_BEND | (voice - 1), smfw_seq.outfile); putc(0xFF & ((value & 0x1) << 6) , smfw_seq.outfile); putc(0xFF & (value >> 1), smfw_seq.outfile); } /* smfw_cause_noteoff -- schedule a noteoff for midi file */ /* * NOTE: this is called by smfw_process_event when it handles a note * event node in a seq_type's event list. The ordinary moxc scheduler * is used to "schedule" the noteoff in the future. In reality, the * output is done as fast as possible (by attempting an infinite rate), * so no real timing delays occur. The effect is to sort events by their * specified time. */ private void smfw_cause_noteoff(seq, delay, voice, pitch) seq_type seq; time_type delay; int voice; int pitch; { if(debug) gprintf(TRANS, "cause noteoff at %ld...", virttime + delay); pitch += seq->transpose; while (pitch <= 0) pitch += 12; while (pitch >= 127) pitch -= 12; seq->noteoff_count++; causepri((delay_type) delay, 10, seq->noteoff_fn, seq, voice, pitch); } private void smfw_clock_event(old_ticksize, new_ticksize) time_type old_ticksize, new_ticksize; { time_type temp_ticksize = new_ticksize; new_ticksize = scale(new_ticksize, 375L, 1024L); /* (new_ticksize >> 16) * 24000 ms/clock becomes us/midiquarter */ if(debug) gprintf(TRANS, "smfw_clock: write %ld (time:%ld) ->->->tempo %ld\n", new_ticksize, virttime, 2500L / (new_ticksize / 24000)); /*use old ticksize to write the delta for the clock event*/ last_tick_size = old_ticksize; smfw_deltatime(); last_tick_size = temp_ticksize;/* reset to = new_tick_size */ putc(0xFF, smfw_seq.outfile); putc(0x51, smfw_seq.outfile); putc(0x03, smfw_seq.outfile); putc((int) ((new_ticksize >> 16) & 0xFF), smfw_seq.outfile); putc((int) ((new_ticksize >> 8) & 0xFF), smfw_seq.outfile); putc((int) (new_ticksize & 0xFF), smfw_seq.outfile); last_clock_event = virttime; last_event = 0L; /*no time expired between last clockevent and last event(they are the same).*/ /*next clock event will be exactly the next this_event from last_clock_event*/ } /* smfw_ctrl -- write a control change to a midi file */ /**/ private void smfw_ctrl(seq_type seq, int voice, int ctrl_name, int value) { if(debug) gprintf(TRANS, "smfw_ctrl %d: %d\n", ctrl_name, value); smfw_deltatime(); putc(MIDI_CTRL | (voice - 1), smfw_seq.outfile); putc(ctrl_name, smfw_seq.outfile); putc(value, smfw_seq.outfile); } /* smfw_deltatime -- write the time difference between now an previous event */ /**/ private void smfw_deltatime() { /* if last_ and clock_ are different, use last_ for clock deltatime*/ time_type use_ticksize = (clock_ticksize != last_tick_size) ? last_tick_size : clock_ticksize; time_type this_event = virttime - last_clock_event; if(debug) gprintf(TRANS, "delta! ticksize: %lu Lastev: %ld ThisevScaled: %lu Thisev: %lu ", clock_ticksize, last_event, (this_event * ((2500L << 16) / use_ticksize)) / 100, this_event); this_event = ((virttime - last_clock_event) * ((2500L << 16) / use_ticksize)) / 100; if(debug) gprintf(TRANS, "--- deltatime: %lu\n", this_event - last_event); writevarlen((long) (this_event - last_event)); last_event = this_event; } /* smfw_dotrack -- write the remainder of a track */ private void smfw_dotrack(seq) seq_type seq; { long end_marker; timebase_type old_timebase = timebase; unsigned long chunk_size; if (seq->runflag) { if ((seq->timebase->virt_base == 0) && (seq->timebase->rate == STOPRATE)) /*we just set these last time through... do nothing*/; seq_stop(seq); } timebase_use(seq->timebase); set_rate(seq->timebase, STOPRATE); set_virttime(seq->timebase, 0L); seq->current = seq_events(seq); seq->noteoff_count = 0L; seq->runflag = TRUE; seq->paused = TRUE; last_clock_event = 0L; last_event = 0L; if(debug) gprintf(TRANS, "dotrack (reset) %d %ld (%lu) \n", smfw_seq.track, last_event, virttime); if (seq->current) cause((delay_type)(seq->current->ntime - virttime), smfw_process_event, seq); set_virttime(timebase, MAXTIME); catchup(); putc(0x00, smfw_seq.outfile); putc(0xFF, smfw_seq.outfile);/*end of track chunk*/ putc(0x2F, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); end_marker = ftell(smfw_seq.outfile); fseek(smfw_seq.outfile, chunk_size_marker, 0);/*go back to enter chunksize*/ chunk_size = (end_marker - chunk_size_marker) - 4;/* - 4 for 4 size bytes*/ if(debug) gprintf(TRANS, "bytes written in previous track: %ld \n\n", chunk_size); putc((int) ((0xFF & (chunk_size >> 24))), smfw_seq.outfile); putc((int) ((0xFF & (chunk_size >> 16))), smfw_seq.outfile); putc((int) ((0xFF & (chunk_size >> 8))), smfw_seq.outfile); putc((int) ((0xFF & chunk_size)), smfw_seq.outfile); fseek(smfw_seq.outfile, end_marker, 0);/*return file pointer to end of track*/ timebase_use(old_timebase); } /* smfw_exclusive -- write a system excl. msg to midi file */ private void smfw_exclusive(length, msg) int length; unsigned char *msg; { int length_count = 0; if(debug) gprintf(TRANS, "SYSEX (time:%ld)\n", virttime); smfw_deltatime(); while (length > length_count){ /* *(msg-1) != MIDI_EOX) { */ putc(*msg++, smfw_seq.outfile); length_count++; } if(*(--msg) != MIDI_EOX) gprintf(TRANS, "ERROR: no end of sysex\n"); } private void smfw_msg_write(n,c1,c2,c3) int n; unsigned char c1,c2,c3; { if(debug) gprintf(TRANS, "MSGWRITE %d bytes (time:%ld)\n", n, virttime); smfw_deltatime(); switch(n) { case 1: putc(c1, smfw_seq.outfile); break; case 2: putc(c1, smfw_seq.outfile); putc(c2, smfw_seq.outfile); break; case 3: putc(c1, smfw_seq.outfile); putc(c2, smfw_seq.outfile); putc(c3, smfw_seq.outfile); break; } } /* smfw_noteoff -- write noteoff to midi file */ /**/ private void smfw_noteoff(seq_type seq, int voice, int pitch) { if(debug) gprintf(TRANS, "smfw_noteoff %d: %d (time:%ld)\n", voice, pitch, virttime); smfw_deltatime(); putc(NOTEOFF | (voice - 1), smfw_seq.outfile); putc(pitch, smfw_seq.outfile); putc(0x40, smfw_seq.outfile); } /* smfw_noteon -- write noteon to midi file */ /* * NOTE: the seq parameter is not used here, but is passed in by the * seq_noteon macro, so we have to have a placeholder for it. */ private void smfw_noteon(seq, voice, pitch, vel) seq_type seq; int voice, pitch, vel; { if(debug) gprintf(TRANS, "smfw_noteon %d: %d %d(time:%ld)\n", voice, pitch, vel, virttime); smfw_deltatime(); putc(NOTEON | (voice - 1), smfw_seq.outfile); putc(pitch, smfw_seq.outfile); putc(vel, smfw_seq.outfile); } /* smfw_process_event -- write a seq event to a midi file */ /**/ private void smfw_process_event(seq) seq_type seq; { register event_type event; if (!seq->runflag) return; while ((event = seq->current) && (event->ntime <= virttime)) { unsigned int voice; if ((vc_voice(event->nvoice) == smfw_seq.track) || /*if on current track*/ (((vc_voice(event->nvoice) - 16) == smfw_seq.track) && (smfw_seq.track > 0)) || /* acknowledge clock change on all tracks*/ (event->value == CLOCK_VALUE && vc_ctrl(event->nvoice) == ESC_CTRL)) { /* process all current (and earlier) events */ if (is_note(event)) { /*** play a note or rest ***/ /* if this note is not a rest, play it and schedule an off event */ if (event->value != NO_PITCH && (seq_channel_mask(seq) & (1 << ((voice = vc_voice(event->nvoice)) - 1)))) { seq_noteon(seq, voice, (0xFF & event->value), (int) (event->u.note.ndur & 0xFF)); seq_cause_noteoff(seq, (event->u.note.ndur) >> 8, voice, (0xFF & event->value)); } } else { /*** send a control command ***/ int n; time_type step; int delta; int increment; int voice = vc_voice(event->nvoice); ulong enabled = seq_channel_mask(seq) & (1 << (voice - 1)); switch (vc_ctrl(event->nvoice)) { case PSWITCH_CTRL: if (!enabled) break; if(debug) gprintf(TRANS, "porta %d (time:%ld)... ", event->value, virttime); seq_midi_ctrl(seq, voice, PORTASWITCH, 0xFF & event->value); break; case MODWHEEL_CTRL: if (!enabled) break; if(debug) gprintf(TRANS, "modw %d (time:%ld)...", event->value, virttime); seq_midi_ctrl(seq, voice, MODWHEEL, 0xFF & event->value); break; case TOUCH_CTRL: if (!enabled) break; if(debug) gprintf(TRANS, "touch %d (time:%ld)... ", event->value, virttime); seq_midi_touch(seq, voice, 0xFF & event->value); break; case VOLUME_CTRL: if (!enabled) break; if(debug) gprintf(TRANS, "ftvol %d (time:%ld)...", event->value, virttime); seq_midi_ctrl(seq, voice, VOLUME, 0xFF & event->value); break; case BEND_CTRL: if (!enabled) break; if(debug) gprintf(TRANS, "bend %d (time:%ld)... ", event->value, virttime); seq_midi_bend(seq, voice, event->value); break; case PROGRAM_CTRL: if (!enabled) break; if(debug) gprintf(TRANS, "prog %d (time:%ld)\n", event->value, virttime); smfw_deltatime(); putc(MIDI_CH_PROGRAM | (voice - 1), smfw_seq.outfile); putc(0xFF & event->value, smfw_seq.outfile); break; case ESC_CTRL: switch (event->value) { time_type this_event; case CALL_VALUE: /*called routine will write to midifile in execution */ sequence = seq; (*(event->u.call.routine))(event->u.call.args); break; case CLOCK_VALUE: clock_ticksize = event->u.clock.ticksize; if(debug) gprintf(TRANS, "clockevent! ticksize: %lu (time:%ld)\n", clock_ticksize, virttime); if (virttime > 0) { /* any clock before this is already recorded in the header */ if (smfw_seq.track == 0) { /* record clock event on tempo track = 0 */ /* cause clock write in half a newtick, because it was written .5 tick early*/ cause((delay_type) (clock_ticksize >> 17), smfw_clock_event, last_tick_size, clock_ticksize); last_tick_size = clock_ticksize; /*set new ticksize*/ } else { /*not on tempo track*/ this_event = ((virttime - last_clock_event) * ((2500L << 16) / last_tick_size)) / 100; if(debug) gprintf(TRANS, "track != 0: Lastev: %ld Thisev: %ld NewLast: %ld\n", last_event, this_event, this_event - last_event); last_event = 0L - (this_event - last_event); last_clock_event = virttime; /*last_event is negative, so will be ADDED to next this_event*/ last_tick_size = clock_ticksize; } } else if (debug) gprintf(TRANS, "IGNORED\n");/* if virttime <= 0 */ break; case MACCTRL_VALUE: if (!enabled) break; if (debug) gprintf(TRANS, "MACCTRL %d: %d (time:%ld)\n", event->u.macctrl.ctrl_number, event->u.macctrl.value, virttime); smfw_deltatime(); putc(MIDI_CTRL | (voice - 1), smfw_seq.outfile); putc(0xFF & event->u.macctrl.ctrl_number, smfw_seq.outfile); putc(0xFF & event->u.macctrl.value, smfw_seq.outfile); break; case MACRO_VALUE: if (!enabled) break; if (debug) gprintf(TRANS, "MACRO sent to...\n"); smfw_send_macro(event->u.macro.definition, voice, event->u.macro.parameter, -1, 0); break; case CTRLRAMP_VALUE: case DEFRAMP_VALUE: { int from, to; if (!enabled) break; step = event->u.ramp.step; if (event->value == CTRLRAMP_VALUE) { if(debug) gprintf(TRANS, "CTRLRAMP (time:%ld)...", virttime); from = event->u.ramp.u.ctrl.from_value; to = event->u.ramp.u.ctrl.to_value; } else { if (debug) gprintf(TRANS, "DEFRAMP (time:%ld)...", virttime); from = event->u.ramp.u.def.parameter[ event->u.ramp.u.def.parm_num]; to = event->u.ramp.u.def.to_value; } delta = to - from; increment = delta; if (delta < 0) delta = -delta; /* RBD - Note: Step is always non-zero */ n = event->u.ramp.dur / step; increment = (increment << 8) / n; smfw_ramp_event(seq, event, from << 8, to << 8, increment, step, n); seq->noteoff_count++; break; } case SETI_VALUE: seti_counter++; /*will be printed after writing is completed*/ *(event->u.seti.int_to_set) = event->u.seti.value; break; default: gprintf(TRANS, "unexpected ESC_CTRL value\n"); break; } break; default: gprintf(TRANS, "unexpected seq data\n"); break; } } } seq->current = event->next; } if (seq->current) { /* if there is an event: delay, and then process again */ cause((delay_type)(event->ntime - virttime), smfw_process_event, seq); } } /* smfw_ramp_event -- generate a ramp to write*/ private void smfw_ramp_event(seq, event, value, to_value, increment, step, n) seq_type seq; register event_type event; unsigned int value; unsigned int to_value; int increment; time_type step; int n; { if(debug) gprintf(TRANS, "ramp of %d: %d to %d\n", event->u.ramp.ctrl, value >> 8, to_value >> 8); if (seq->runflag) { int voice = vc_voice(event->nvoice); if (n == 0) value = to_value; else cause((delay_type)step, smfw_ramp_event, seq, event, value + increment, to_value, increment, step, n - 1); if (event->value == CTRLRAMP_VALUE) { int ctrl = event->u.ramp.ctrl; if (ctrl == -TOUCH_CTRL) smfw_touch(seq, voice, value >> 8); else if (ctrl == -BEND_CTRL) smfw_bend(seq, voice, value >> 8); else smfw_ctrl(seq, voice, ctrl, value >> 8); } else { /* must be DEFRAMP_VALUE */ smfw_send_macro(event->u.ramp.u.def.definition, vc_voice(event->nvoice), event->u.ramp.u.def.parameter, event->u.ramp.u.def.parm_num, value >> 8); } if (n == 0) seq_end_event(seq); } } /* smfw_send_macro -- write msg to midi file from a seq "macro" event */ /**/ private void smfw_send_macro(ptr, voice, parameter, parm_num, value) register unsigned char *ptr; int voice; short parameter[]; int parm_num; int value; { register unsigned char code, *loc; while ((code = *ptr++)) { loc = ptr + *ptr; ptr++; if (code <= nmacroparms) { code--; *loc = (code == parm_num ? value : parameter[code]) & 0x7f; } else if (code == nmacroparms + 1) { *loc = ((voice - 1) & 0xF) | *loc; } else { code -= (nmacroparms + 2); *loc = ((code == parm_num ? value : parameter[code]) >> 7) & 0x7F; } } if (ptr[1] == MIDI_SYSEX) smfw_exclusive(*ptr, ptr + 1); else smfw_msg_write(*ptr, ptr[1], ptr[2], ptr[3]); } /* smfw_touch -- write aftertouch msg to midi file */ /**/ private void smfw_touch(seq_type seq, int voice, int value) { if(debug) gprintf(TRANS, "smfw_touch %d\n", value); smfw_deltatime(); putc(MIDI_TOUCH | (voice - 1), smfw_seq.outfile); putc(value, smfw_seq.outfile); } void seq_write_smf(seq, outfile) seq_type seq; FILE *outfile; { time_type put_tick_size; int i; /* ticksize is milliseconds << 16, and tickrate = 24*tempo 60000ms/min / (24 * tempo) = 2500/tempo = 25 25 << 16 = 1638400 */ time_type starting_ticksize = 1638400L; /*default midifile tempo 100*/ int track_count = 0; long track_count_marker; register event_type event; seti_counter = 0; /*initialize the smfw_seq struct*/ smfw_seq.outfile = outfile; smfw_seq.seq = seq_copy(seq); smfw_seq.seq->cause_noteoff_fn = smfw_cause_noteoff; smfw_seq.seq->midi_bend_fn = smfw_bend; smfw_seq.seq->midi_ctrl_fn = smfw_ctrl; smfw_seq.seq->midi_touch_fn = smfw_touch; smfw_seq.seq->noteoff_fn = smfw_noteoff; smfw_seq.seq->noteon_fn = smfw_noteon; event = seq_events(smfw_seq.seq); /* search for clock events up till start of score */ /* careful: there may be no events at all */ while(event && event->ntime <= 0){ if(debug) gprintf(TRANS, "event (time:%ld)\n", event->ntime); if(vc_ctrl(event->nvoice) == ESC_CTRL && event->value == CLOCK_VALUE) { if(debug) gprintf(TRANS, "clock %lu at 0\n", event->u.clock.ticksize); starting_ticksize = event->u.clock.ticksize; break; } event = event->next; } putc(0x4D, smfw_seq.outfile); /*header: MThd*/ putc(0x54, smfw_seq.outfile); putc(0x68, smfw_seq.outfile); putc(0x64, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); putc(0x06, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); putc(0x01, smfw_seq.outfile); /*format 1 */ putc(0x00, smfw_seq.outfile); track_count_marker = ftell(smfw_seq.outfile); /*number of tracks will be written later*/ putc(0x00, smfw_seq.outfile); /*will be filled by track_count_marker*/ putc(0x02, smfw_seq.outfile);/*division resolution of 600*/ putc(0x58, smfw_seq.outfile); for (i = 0; i < 17; i++) { /* for each track... */ if (((seq_used_mask(smfw_seq.seq) >> (i - 1)) & 0x1) || (i == 0)) { if (debug) gprintf(TRANS, "write track %d \n", i); track_count++; clock_ticksize = starting_ticksize; last_tick_size = starting_ticksize; putc(0x4D, smfw_seq.outfile);/*track header: MTrk*/ putc(0x54, smfw_seq.outfile); putc(0x72, smfw_seq.outfile); putc(0x6B, smfw_seq.outfile); chunk_size_marker = ftell(smfw_seq.outfile); /* size of chunk will be written later */ /* will be filled by chunk_size_marker */ putc(0x00, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); if (i == 0) { /* tempo and time signature track */ putc(0x00, smfw_seq.outfile);/* default time sig stuff*/ putc(0xFF, smfw_seq.outfile); putc(0x58, smfw_seq.outfile); putc(0x04, smfw_seq.outfile); putc(0x04, smfw_seq.outfile); putc(0x02, smfw_seq.outfile); putc(0x18, smfw_seq.outfile); putc(0x08, smfw_seq.outfile); putc(0x00, smfw_seq.outfile); /* TEMPO: inserted here in case default is used */ putc(0xFF, smfw_seq.outfile); putc(0x51, smfw_seq.outfile); putc(0x03, smfw_seq.outfile); /* ticksize is in ms<<16, so to get milliseconds per tick, it's ticksize / 65536. To get beat durations, multiply by 24 to get ticksize * 24 / 65536. To get microseconds, multiply by 1000: ticksize * 24000 / 65536. Divide both constants by 64 to get ticksize * 375 / 1024 = microseconds per quarter note. */ put_tick_size = scale(clock_ticksize, 375L, 1024L); putc((int) ((put_tick_size >> 16) & 0xFF), smfw_seq.outfile); putc((int) ((put_tick_size >> 8) & 0xFF), smfw_seq.outfile); putc((int) (put_tick_size & 0xFF), smfw_seq.outfile); } smfw_seq.track = i; smfw_dotrack(smfw_seq.seq); } } if (seti_counter) gprintf(TRANS, "%d SETI events IGNORED!\n", seti_counter); seq_stop(smfw_seq.seq); /* go back and insert number of tracks */ fseek(smfw_seq.outfile, track_count_marker, 0); putc(0xFF & track_count, smfw_seq.outfile); fclose(smfw_seq.outfile); } /* writevarlen -- write a variable length integer to midi file */ /**/ private void writevarlen(value) register long value; { register ulong buffer; if(debug) gprintf(TRANS, "variable length quantity..."); buffer = value & 0x7f; while((value >>= 7) > 0) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x7f); } for(;;) { if(debug) gprintf(TRANS, " byte "); putc((int) (buffer & 0xFF), smfw_seq.outfile); if (buffer & 0x80) buffer >>= 8; else break; } if(debug) gprintf(TRANS, "written!\n"); } nyquist-3.05/cmt/cmtcmd.h0000644000175000000620000000164510144436365014402 0ustar stevestaff/* cmtcmd.h -- header for remote action and variable setting interface */ #define var_symb_type 333 #define fn_symb_type 555 #define vec_symb_type 777 #ifdef AMIGA struct cmd_msg { struct Message msg; long symb_type; /* one of var_, fn_, or vec_symb_type */ char *symbol_name; long the_args[8]; /* args for function call. If var_symb_type, the_args[0] is the new value. If vec_symb_type, the_args[0] is index, the_args[1] is new value. */ }; #endif typedef struct symb_descr { char *symbol_name; int symb_type; int size; /* for array bounds checking */ union { int *intptr; int (*routine)(); } ptr; } symb_descr_node; int lookup(char *s); void defvar(char *name, int *addr); void defvec(char *name, int *addr, int size); typedef int (*defun_type)(); void defun(char *name, defun_type addr); #define HASHTYPE symb_descr_node #include "hash.h" nyquist-3.05/cmt/midibuff.h0000644000175000000620000000135610144436365014717 0ustar stevestaff/* midibuff.h -- defines the size of the midi input buffer */ /* midi input buffer */ /* WARNING: BUFF_SIZE must be a power of 2 so we can use masking to wrap */ #define EVENT_COUNT 128 #define EVENT_SIZE 4 #define BUFF_SIZE (EVENT_COUNT * EVENT_SIZE) #define BUFF_MASK (BUFF_SIZE - 1) #ifdef WINDOWS #define huge #endif extern byte huge *xbuff; /* application-supplied sysex buffer */ extern long xbufmask; /* mask for circular buffer */ extern long xbufhead; /* buffer head and tail offsets */ extern long xbuftail; extern int midi_error; /* midi input buffer */ /* data buffer, declared long to get 32-bit alignment: */ extern long buff[BUFF_SIZE/4]; extern int buffhead; /* buffer head and tail pointers */ extern int bufftail; nyquist-3.05/cmt/seqdecls.h0000644000175000000620000000043210144436365014727 0ustar stevestaff/* This .h file declares everything you need to include seq.h */ /* * This file gets included by an interface to seq generated by intgen */ #include "switches.h" #include "stdio.h" #include "cext.h" #include "userio.h" #include "midifns.h" #include "timebase.h" #include "moxc.h" nyquist-3.05/cmt/midimgr.c0000644000175000000620000007017410144436365014561 0ustar stevestaff/* midimgr.c -- this file contains interface code to support use of Apple Midi Manager */ /* * This code is based on code supplied with the Apple Midi Manager. * Copyright 1991, Carnegie Mellon University */ /* BUGS: * If exclusive() is called to turn exclusive messages on or off DURING the * receipt of an exclusive message, incoming data will be garbled. The correct * handling would be to record when receipt of an exclusive message is in * progress, then properly remove any partial message when exclusive is turned * off, and ignore any remaining message part when exclusive is turned on. * The present code does neither. */ #include "cext.h" #undef round #ifdef THINK_C #include /* for ThinkC 7 */ #endif #include "stdio.h" #include "userio.h" #include "MIDI.h" #include "midifns.h" #include "midibuff.h" #include "midierr.h" #include "midimgr.h" #include "midicode.h" #include "cmdline.h" /* Needed for KillEverybody */ #include #include #include #include #include #include #include #define CMTclientID 'CMT ' /* note the following are in alphabetical order for Patcher display */ #define timePortID 'Atim' #define inputPortID 'Bin ' #define outputPortID 'Cout' #define noClient ' ' #define noTimeBaseRefNum 0 #define noReadHook 0L #define zeroTime 0L #define timePortBuffSize 0L #define inputPortBuffSize 2048 #define outputPortBuffSize 0L #define refCon0 0L pascal short CMTreader(MIDIPacket *ThePacketPtr, long TheRefCon); /* "patch" switch from command line. This switch is cached in patch_flag and tells whether to look in the resource fork for a patch, or just hook up to midi in and out. If the resource fork is used, the patch will be saved upon exit. */ private boolean patch_flag; extern boolean ctrlFilter; extern boolean exclFilter; extern boolean realFilter; private midi_read_lock = false; /* used to stop input during data structure manipulation */ private void set_error(int bit); #ifndef NYQUIST void PatchPorts(void); void SavePatch(OSType PortID, short PortInfoResID, char *PortInfoResName); #endif /* exported: */ public short InputRefNum; /* Input port reference number. */ public short OutputRefNum; /* Output port reference number. */ public short TimeRefNum; /* Time base port reference number. */ Boolean GManualPatch; /* True if not launched by a PatchBay Config. File. */ /**************************************************************************** * * variables shared with other modules * ****************************************************************************/ /* midi input buffer */ long buff[BUFF_SIZE/4]; /* data buffer, declared long to get 32-bit alignment */ int buffhead = 0; /* buffer head and tail pointers */ int bufftail = 0; /* user supplied system exclusive buffer */ byte *xbuff = NULL; /* address of the user-supplied buffer */ public long xbufmask; /* mask for circular buffer address calculation */ long xbufhead = 0; /* buffer head and tail pointers */ long xbuftail = 0; boolean xbuf_flush = true; /* says to flush remainder of sysex message */ #ifdef SYSEXDEBUG int sysexcount = 0; /* for debugging */ int sysexdone = 0; int sysexheadcount = 0; byte sysexfirst = 0; int sysexsysex = 0; #endif /* midi_flush -- empty out buffers */ /**/ void midi_flush() { midi_read_lock = true; buffhead = 0; bufftail = 0; xbufhead = 0; xbuftail = 0; xbuf_flush = true; /* in case sysex continuation messages are still coming */ midi_read_lock = false; } /* Nyquist only uses CMT for Midi and Adagio file IO */ #ifndef NYQUIST /* Get String representation of MIDI Mgr Version Num.*/ /* See Mac Tech Note #189 for details. */ char *StdMacVerNumToStr(long VerNum, char *VerStr) { char *RetVal; char MajVer, MinVer, VerStage, VerRev, BugFixVer = 0; if (VerNum == 0) { RetVal = NULL; } else { MajVer = (VerNum & 0xFF000000) >> 24; MinVer = (VerNum & 0x00FF0000) >> 16; VerStage = (VerNum & 0x0000FF00) >> 8; VerRev = (VerNum & 0x000000FF) >> 0; BugFixVer = MinVer & 0x0F; switch (VerStage) { case 0x20: VerStage = 'd'; break; case 0x40: VerStage = 'a'; break; case 0x60: VerStage = 'b'; break; case 0x80: VerStage = ' '; break; default: VerStage = '?'; break; } if (BugFixVer == 0) { sprintf(VerStr,"%X.%X%c%X", MajVer, MinVer>>4, VerStage, VerRev); } else { sprintf(VerStr,"%X.%X.%X%c%X", MajVer, MinVer >> 4, MinVer & 0x0F, VerStage, VerRev); } RetVal = VerStr; } return(RetVal); } /* C2PStrCpy -- Convert a C String (from Cstr) into a Pascal string */ /* * NOTE: this is not the same code as shipped with midi manager example */ char *C2PStrCpy(char *Cstr, Str255 Pstr) { char *c = Cstr; char *p = ((char *) Pstr) + 1; while (*c) *p++ = *c++; *Pstr = c - Cstr; return( (char *) Pstr ); } /* This checks to see if THINK C is running under System 7, and ONLY WORKS UNDER SYSTEM 7! Don't use unless you check! */ boolean ThinkCRunning(void) { ProcessSerialNumber processSN; OSErr myErr; ProcessInfoRec infoRec; processSN.lowLongOfPSN = kNoProcess; processSN.highLongOfPSN = kNoProcess; do { myErr = GetNextProcess(&processSN); infoRec.processInfoLength = sizeof(ProcessInfoRec); infoRec.processName = 0L; infoRec.processAppSpec = 0L; myErr = GetProcessInformation(&processSN, &infoRec); if (!myErr) { if (infoRec.processSignature == 'KAHL') { return(true); } } } while (myErr == noErr); return(false); } /* This kills off all the other running processes... ONLY WORKS UNDER SYSTEM 7! Don't use unless you check! */ void KillEverybody(void) { ProcessSerialNumber myProc, processSN; ProcessSerialNumber finderPSN; ProcessInfoRec infoRec; Str31 processName; FSSpec procSpec; OSErr myErr = noErr; OSErr otherError; AppleEvent theEvent; AEDesc theAddress; Boolean ourFlag, notFinder; Boolean finderFound = false; GetCurrentProcess(&myProc); /* Preset the PSN to no PSN, see IM VI, the Process Manager */ processSN.lowLongOfPSN = kNoProcess; processSN.highLongOfPSN = kNoProcess; finderPSN.lowLongOfPSN = 0UL; /* brk: was nil */ finderPSN.highLongOfPSN = 0UL; /* brk: was nil */ do { myErr = GetNextProcess(&processSN); /* See if it's us first */ notFinder = true; SameProcess(&myProc, &processSN, &ourFlag); infoRec.processInfoLength = sizeof(ProcessInfoRec); infoRec.processName = (StringPtr) &processName; infoRec.processAppSpec = &procSpec; GetProcessInformation(&processSN, &infoRec); if (!ourFlag && !finderFound) { /* see if it's the Finder, we have to kill the finder LAST */ /* or else non-sys 7 apps won't get killed */ /* since the Finder must be there to convert the AppleEvent to Puppet Strings */ /* if the app is not APpleEvent aware */ /* Also, FileShare HAS to be killed before the Finder */ /* or your life will be unpleasant */ if (infoRec.processSignature == 'MACS' && infoRec.processType == 'FNDR') { /* save this number for later */ finderPSN = processSN; notFinder = false; finderFound = true; } else { notFinder = true; } } if (!myErr && !ourFlag && notFinder) { otherError = AECreateDesc(typeProcessSerialNumber, (Ptr)&processSN, sizeof(processSN), &theAddress); if (!otherError) otherError = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent); if (!otherError) AEDisposeDesc(&theAddress); /* Again, the Finder will convert the AppleEvent to puppetstrings if */ /* the application is a System 6 or non-AE aware app. This ONLY */ /* happens for the 4 required (oapp,odoc,pdoc, and quit) AppleEvents */ /* and ONLY if you use the PSN for the address */ if (!otherError) AESend(&theEvent, 0L, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, 0L, 0L); AEDisposeDesc(&theEvent); } } while (!myErr); /* Now, if the finder was running, it's safe to kill it */ if (finderPSN.lowLongOfPSN || finderPSN.highLongOfPSN) { otherError = AECreateDesc(typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(processSN), &theAddress); if (!otherError) otherError = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent); if (!otherError) AEDisposeDesc(&theAddress); if (!otherError) AESend(&theEvent, 0L, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, 0L, 0L); AEDisposeDesc(&theEvent); } } /* Sign into the MIDI Manager. */ /* Set up time, input, and output ports. */ /* Start our time base clock. */ void setup_midimgr(void) { MIDIPortParams Init; /* MIDI Mgr Init data structure */ Handle TheIconHndl; OSErr TheErr; long MIDIMgrVerNum; /* MIDI Manager Ver (Std Mac Ver #) */ Str255 name = "\pCMU MIDI Toolkit"; char MIDIMgrVerStr[256]; /* MIDI Manager Ver (Std Mac Ver # String) */ long vers; EventRecord theEvent; Gestalt(gestaltSystemVersion, &vers); vers = (vers >> 8) & 0xf; /* shift result over and mask out major version number */ if ((vers >= 7) && (!cl_switch("keep")) && (!ThinkCRunning())) { gprintf(TRANS,"Killing other processes...\n"); KillEverybody(); for (vers=0; vers<100; ++vers) { while (WaitNextEvent(everyEvent, &theEvent, 0L, 0L)) ; } } /* Make sure MIDIMgr is installed and save version num. */ MIDIMgrVerNum = SndDispVersion(midiToolNum); if (MIDIMgrVerNum == 0) { gprintf(ERROR, "The MIDI Manager is not installed! Exiting...\n"); EXIT(1); } else { StdMacVerNumToStr(MIDIMgrVerNum, MIDIMgrVerStr); gprintf(TRANS,"MIDI Manager Version %s\n", MIDIMgrVerStr); } /* Sign in to the MIDI Manager. */ TheIconHndl = GetResource('ICN#', 1); TheErr = MIDISignIn(CMTclientID, 0L, TheIconHndl, name); if (TheErr) { gprintf(ERROR, "Trouble signing into MIDI Manager! Aborting..."); EXIT(1); } /* Assume not a Patchbay configuration. */ GManualPatch = true; /* Add time port. */ Init.portID = timePortID; Init.portType = midiPortTypeTime; Init.timeBase = noTimeBaseRefNum; Init.readHook = noReadHook; Init.initClock.syncType = midiInternalSync; Init.initClock.curTime = zeroTime; Init.initClock.format = midiFormatMSec; Init.refCon = SetCurrentA5(); C2PStrCpy("TimeBase", Init.name); TheErr = MIDIAddPort(CMTclientID, timePortBuffSize, &TimeRefNum, &Init); /* Has a PatchBay connection been resolved? */ if (TheErr == midiVConnectMade) { GManualPatch = false; } else if (TheErr == memFullErr) { gprintf(ERROR, "Not enough room in heap zone to add time port! Aborting..."); MIDISignOut(CMTclientID); EXIT(1); } /* Add an input port. */ Init.portID = inputPortID; Init.portType = midiPortTypeInput; Init.timeBase = TimeRefNum; Init.offsetTime = midiGetCurrent; Init.readHook = NewMIDIReadHookProc(CMTreader); Init.refCon = SetCurrentA5(); C2PStrCpy("InputPort", Init.name); TheErr = MIDIAddPort(CMTclientID, inputPortBuffSize, &InputRefNum, &Init); /* Has a PatchBay connection been resolved? */ if (TheErr == midiVConnectMade) { GManualPatch = false; } else if (TheErr == memFullErr) { gprintf(ERROR, "Not enough room in heap zone to add input port! Aborting..."); MIDISignOut(CMTclientID); EXIT(1); } /* Add an output port. */ Init.portID = outputPortID; Init.portType = midiPortTypeOutput; Init.timeBase = TimeRefNum; Init.offsetTime = midiGetCurrent; Init.readHook = NULL; Init.refCon = refCon0; C2PStrCpy("OutputPort", Init.name); TheErr = MIDIAddPort(CMTclientID, outputPortBuffSize, &OutputRefNum, &Init); /* Has a PatchBay connection been resolved? */ if (TheErr == midiVConnectMade) { GManualPatch = false; } else if (TheErr == memFullErr) { printf("Not enough room in heap zone to add output port! Aborting..."); MIDISignOut(CMTclientID); EXIT(1); } if (GManualPatch) { PatchPorts(); /* connect ports as they were */ } /* to clean this up (later) call finish_midimgr() */ cu_register((cu_fn_type) finish_midimgr, (cu_parm_type) finish_midimgr); /* Start our Clock. */ MIDIStartTime(TimeRefNum); } /* The Read Hook Function. */ /* 1st 4 bytes of sysex message get saved here and enqueued later */ char save_sysex_head[4]; int save_sysex_head_x = 0; void sysex_insert(unsigned char data) { if (save_sysex_head_x < 4) { save_sysex_head[save_sysex_head_x++] = data; } xbuff[xbuftail++] = data; xbuftail &= xbufmask; if (xbuftail == xbufhead) { set_error(SYSEXOVFL); } if (data == MIDI_EOX) { /* we're done with the message */ *((long *) (((byte *) buff) + bufftail)) = *((long *)save_sysex_head); bufftail = (bufftail + 4) & BUFF_MASK; if (bufftail == buffhead) { set_error(BUFFOVFL); } } } /* Read all incomming MIDI data. */ pascal short CMTreader(MIDIPacket *ThePacketPtr, long TheRefCon) { /* Set up our A5 world. */ long SysA5 = SetA5(TheRefCon); short RetVal = midiMorePacket, i, j; unsigned char *mm_data = ThePacketPtr->data; register byte data1 = mm_data[1]; if (midi_read_lock) { /* Don't want to read packet now, get it later */ /* DOES THIS REALLY WORK? WHAT WILL CAUSE AN INTERRUPT * TO OCCUR LATER? THIS IS ONLY USED BY midi_flush, IS * BASED ON THE MidiArp CODE FROM APPLE, AND IS UNTESTED - RBD */ RetVal = midiKeepPacket; goto alldone; } /* see if Packet is an error message */ if (((ThePacketPtr->flags & midiTypeMask) == midiMgrType) && *((short *) (&(ThePacketPtr->data))) < midiMaxErr) { set_error(MIDIMGRERR); goto alldone; } /* filter out control changes */ if (ctrlFilter) { register int hibits = *mm_data & 0xF0; if (hibits == 0xD0 || /* Chan Pressure */ hibits == 0xE0 || /* Pitch Bend */ hibits == 0xA0 || /* Poly Pressure */ ((hibits == 0xB0) && /* Control change (don't count switches) */ ((data1 < 64) || (data1 > 121)))) { /* CONTROL MESSAGE HAS BEEN FILTERED */ goto alldone; } } else if (realFilter) { register int hibits = *mm_data & 0xF0; if (hibits >= 0xF8) goto alldone; } /* if not a continuation, copy the data into cmt_data */ /* The logic to detect a non-continued * packet or a first packet is: "flags bit 1 is clear". */ if ((((ThePacketPtr->flags & midiContMask) == midiNoCont)) && (*mm_data != MIDI_SYSEX)) { register byte *cmt_data = ((byte *) buff) + bufftail; *((long *) cmt_data) = *((long *) mm_data); bufftail = (bufftail + 4) & BUFF_MASK; if (bufftail == buffhead) { /* filled buffer faster than client emptied it */ set_error(BUFFOVFL); } } /* see if we have a sysex message to copy to buffer */ if (xbuff && !exclFilter && ((ThePacketPtr->flags & midiContMask) || *mm_data == MIDI_SYSEX)) { int i; register byte *x_data = xbuff + xbuftail; /* iterate over data in message */ /* NOTE: in the previous implementation, I thought Sysex messages were * always starting at the beginning of the buffer, but that didn't work. * This implementation assumes nothing -- it is slower because of additional * testing and parsing inside the loop, but seems to work. */ for (i = ThePacketPtr->len - 6; i > 0; i--) { if (xbuf_flush) { /* we're searching for beginning of message */ if (*mm_data == MIDI_SYSEX) { xbuf_flush = false; sysex_insert(MIDI_SYSEX); } } else { /* we're scanning to the end of the message */ if (*mm_data == MIDI_SYSEX) { /* found it, insert proper EOX */ sysex_insert(MIDI_EOX); sysex_insert(MIDI_SYSEX); } else if (*mm_data == MIDI_EOX) { /* found it */ sysex_insert(MIDI_EOX); xbuf_flush = true; } else sysex_insert(*mm_data); } mm_data++; } } alldone: /* Restore the systems A5 world. */ SetA5(SysA5); return(RetVal); } /* Sign out from the MIDI Manager. */ void finish_midimgr(void) { if (GManualPatch && patch_flag) { SavePatch(timePortID, timePortResInfoID, "timePortInfo"); SavePatch(inputPortID, inputPortResInfoID, "inputPortInfo"); SavePatch(outputPortID, outputPortResInfoID, "outputPortInfo"); } MIDISignOut(CMTclientID); } /* Alert user to Resource Manager Error. */ void ReportResError(char *Msg) { OSErr TheErr; char Buf[256]; if ( (TheErr = ResError()) != noErr) { gprintf(ERROR, "ResError %d: %s...Aborting.", TheErr, Msg); EXIT(1); } else { /* gprintf(ERROR, "%s OK\n", Msg); */ } } /**************************************************************************** * error handling * Effect: * various error conditions are flagged by setting bits in * the global midi_error_flags. it is up to the client to clear this * word when necessary. ****************************************************************************/ private void set_error(int bit) { midi_error_flags |= (1 << bit); } void midi_show_errors() { if (midi_error_flags & (1<numIDs; i++) { OSType id = (*clients)->list[i]; gprintf(TRANS, "%d: %c%c%c%c\n", i, (char) (id>>24), (char) ((id >> 16) & 0xFF), (char) ((id >> 8) & 0xFF), (char) (id & 0xFF)); } ports = MIDIGetPorts('amdr'); HLock((Handle) ports); for (i = 0; i < (*ports)->numIDs; i++) { OSType id = (*ports)->list[i]; gprintf(TRANS, "%d: %c%c%c%c\n", i, (char) (id>>24), (char) ((id >> 16) & 0xFF), (char) ((id >> 8) & 0xFF), (char) (id & 0xFF)); } HUnlock((Handle) ports); HUnlock((Handle) clients); #endif /* the work starts here */ err = MIDIConnectData('CMT ', 'Cout', 'amdr', 'Aout'); /* gprintf(TRANS, "Connected CMT.Cout to amdr.Aout: %d\n", err); */ err = MIDIConnectData('amdr', 'Ain ', 'CMT ', 'Bin '); /* gprintf(TRANS, "Connected amdr.Ain to CMT.Bin: %d\n", err); */ return; } HLock((Handle) PortInfoH); PortInfoP = *PortInfoH; if (GetHandleSize((Handle) PortInfoH) != 0) { /* Were we supposed to be sync'd to another client? */ if (PortInfoP->timeBase.clientID != noClient) { /* Yes, so make that client our time base. */ TheErr = MIDIConnectTime( PortInfoP->timeBase.clientID, PortInfoP->timeBase.portID, CMTclientID, timePortID ); #ifdef IGNORE /* Is the client still signed in? */ if (TheErr != midiVConnectErr) { /* Yes, so set our sync mode to external. */ MIDISetSync(ArpGlobals.TimeRefNum, midiExternalSync); } #endif } /* Were we somebody else's time base? */ for (i=0; inumConnects; i++) { MIDIConnectTime(CMTclientID, timePortID, PortInfoP->cList[i].clientID, PortInfoP->cList[i].portID); } } HUnlock((Handle) PortInfoH); ReleaseResource((Handle) PortInfoH); ReportResError("PatchPorts/ReleaseResource()"); /* SET UP INPUT PORT CONNECTIONS. */ PortInfoH = (MIDIPortInfoHdl) GetResource(portResType, inputPortResInfoID); if (PortInfoH == NULL) { ReportResError("PatchPorts/GetResource()"); } HLock((Handle) PortInfoH); PortInfoP = *PortInfoH; if (GetHandleSize((Handle) PortInfoH) != 0) { /* Were we connected to anyone? */ for (i=0; inumConnects; i++) { MIDIConnectData(CMTclientID, inputPortID, PortInfoP->cList[i].clientID, PortInfoP->cList[i].portID); } } HUnlock((Handle) PortInfoH); ReleaseResource((Handle) PortInfoH); ReportResError("PatchPorts/GetResource()"); /* SET UP OUTPUT PORT CONNECTIONS. */ PortInfoH = (MIDIPortInfoHdl) GetResource(portResType, outputPortResInfoID); if (PortInfoH == NULL) { ReportResError("PatchPorts/GetResource()"); } HLock((Handle) PortInfoH); PortInfoP = *PortInfoH; if (GetHandleSize((Handle) PortInfoH) != 0) { /* Were we connected to anyone? */ for (i=0; inumConnects; i++) { MIDIConnectData(CMTclientID, outputPortID, PortInfoP->cList[i].clientID, PortInfoP->cList[i].portID); } } HUnlock((Handle) PortInfoH); ReleaseResource((Handle) PortInfoH); ReportResError("PatchPorts/ReleaseResource()"); } /* Save current port connections (port info records) */ /* to application's 'port' resource. */ void SavePatch(OSType PortID, short PortInfoResID, char *PortInfoResName) { Handle PortResH; /* Handle to ptch resource. */ CursHandle WatchCurs; WatchCurs = GetCursor(watchCursor); HLock((Handle) WatchCurs); SetCursor(*WatchCurs); HUnlock((Handle) WatchCurs); /* Remove existing port info resource. */ PortResH = GetResource(portResType, PortInfoResID); /* gprintf(TRANS, "PortResH: %lx, *PortResH: %lx\n", PortResH, *PortResH); */ if (PortResH) { ReportResError("SavePatch/GetResource()"); RmveResource(PortResH); ReportResError("SavePatch/RmveResource()"); DisposHandle(PortResH); UpdateResFile(CurResFile()); ReportResError("SavePatch/UpdateResFile()"); } /* Get new configurateion. */ PortResH = (Handle) MIDIGetPortInfo(CMTclientID, PortID); /* Save new configurateion. */ CtoPstr(PortInfoResName); AddResource(PortResH, portResType, PortInfoResID, (ConstStr255Param) PortInfoResName); PtoCstr((unsigned char *) PortInfoResName); ReportResError("SavePatch/AddResource()"); WriteResource(PortResH); ReportResError("SavePatch/WriteResource()"); UpdateResFile(CurResFile()); ReportResError("SavePatch/UpdateResFile()"); ReleaseResource(PortResH); ReportResError("SavePatch/ReleaseResource()"); InitCursor(); } #endif /* NYQUIST */ nyquist-3.05/cmt/tempomap.h0000644000175000000620000000137410144436365014754 0ustar stevestaff/* tempomap.h -- list of tempo changes */ typedef struct tempochange_struct { struct tempochange_struct *next; time_type rtime; long beat; long tempo; } tempochange_node, *tempochange_type; typedef struct tempomap_struct { tempochange_type entries; tempochange_type hint; } tempomap_node, *tempomap_type; #define tempochange_alloc() (tempochange_type) memget(sizeof(tempochange_node)) #define tempochange_free(tc) memfree(tc, sizeof(tempochange_node)) #define tempomap_alloc() (tempomap_type) memget(sizeof(tempomap_node)) tempomap_type tempomap_create(void); void tempomap_free(tempomap_type tm); void tempomap_insert(tempomap_type tempomap, long beat, long tempo); time_type tempomap_lookup(tempomap_type tempomap, long beat); nyquist-3.05/cmt/swlogic.h0000644000175000000620000001032010144436365014570 0ustar stevestaff/******************************************************************** * swlogic.h - switch logic, loaded from various versions of switch.h * * Copyright 1989 Carnegie Mellon University * *********************************************************************/ /* * When included, one of the following should be defined: * AZTEC (manx compiler, implies AMIGA) * THINK_C (Think C compiler, implies Macintosh) * __MWERKS__ (Metrowerks C compiler, implies Macintosh) * LATTICE & DOS (Lattice compiler for IBM PC/AT/XT/CLONES) * MICROSOFT & DOS (Microsoft compiler, implies IBM PC/AT/XT/CLONES) * UNIX (emulator for UNIX) * UNIX_ITC (ITC code for RS6000) * UNIX_MACH (MACH ukernel system) */ /*------------------------------------------*/ /* Other switches that might be defined in switches.h are as follows: */ /* APPLICATION, SPACE_FOR_PLAY, MAX_CHANNELS */ /*------------------------------------------*/ /* We're moving toward the elimination of switches.h, so try to map * predefined constants into our standard constants shown above: */ /* CHANGE LOG * -------------------------------------------------------------------- * 28Apr03 dm new conditional compilation structure * 28Apr03 rbd remove macro redefinitions: MICROSOFT */ /* Microsoft C compiler: */ #ifdef _MSC_VER #endif #ifdef _MSDOS #define DOS #endif /* Quick C compiler: */ #ifndef DOS #ifdef MICROSOFT #define DOS #endif #endif /* Borland C compiler: */ #ifdef __BORLANDC__ #define BORLAND #define DOS #endif /* Borland Turbo C compiler: */ #ifdef __TURBOC__ #define BORLAND] #define DOS #endif /* SGI systems */ #ifdef sgi #ifndef UNIX #define UNIX #endif #define UNIX_IRIX #define MAX_CHANNELS 32 #endif /* APPLICATION -- define APPLICATION if you want to disable * looking for command line switches in the midi interface. * I think this feature is here for the Piano Tutor project * and you should not define APPLICATION for CMU Midi Toolkit * projects (APPLICATION is a poor choice of terms): */ /* memory space management (system dependent): * SPACE_FOR_PLAY must be enough space to allow * seq to play a score. This may include space for * note-off events, I/O buffers, etc. */ #ifndef SPACE_FOR_PLAY #define SPACE_FOR_PLAY 10000L #endif /* How many MIDI channels are there? MACINTOSH can use 2 ports, * so it supports 32 channels. Others have one port, 16 channels. * On the other hand, if you don't have all the MIDI ports plugged * into MIDI interfaces, CMT will just hang, so I'll compile with * just 16 channels. The 32 channel option for the Mac is untested. */ #ifndef MAX_CHANNELS #define MAX_CHANNELS 16 #endif /*------------------------------------------*/ /* Now we get to the "logic": define things as a function of what * was defined in switches.h */ #ifdef THINK_C #define MACINTOSH #endif #ifdef __MWERKS__ #define MACINTOSH #endif #ifdef MACINTOSH #define MACINTOSH_OR_DOS #define MACINTOSH_OR_UNIX /* I don't know if THINK_C defines this and we need it for a few prototypes... */ #ifndef __STDC__ #define __STDC__ #endif #ifndef TAB_WIDTH #define TAB_WIDTH 4 #endif #endif #ifndef TAB_WIDTH #define TAB_WIDTH 8 #endif /* * If MIDIMGR is defined, compile for the Apple MIDI Manager * (Non MIDI manager code is no longer supported) */ #ifdef MACINTOSH /* under Nyquist, the MidiMgr is not used, so you can't * receive or send Midi as in CMU MIDI Toolkit; however, * much of CMU MIDI Toolkit is used for Midi file IO */ #ifndef NYQUIST #define MIDIMGR #endif #define USE_VSPRINTF #endif #ifdef BORLAND #define DOS #endif #ifdef LATTICE322 #define DOS #define OLD_PROTOTYPES #endif #ifdef UNIX_ITC #define UNIX #define ITC #endif #ifdef UNIX_MACH #define UNIX #define ITC #endif /* USE_VSPRINTF says vsprintf() is defined */ #ifdef ITC #define USE_VSPRINTF #endif #ifdef AZTEC #define USE_VSPRINTF #endif /* DOTS_FOR_ARGS says ANSI "..." notation is recognized */ #ifdef __STDC__ #define DOTS_FOR_ARGS #endif #ifdef UNIX_ITC #define DOTS_FOR_ARGS #endif #ifdef BORLAND #define DOTS_FOR_ARGS #endif #ifdef MICROSOFT #define DOTS_FOR_ARGS #endif #ifdef DOS #define MACINTOSH_OR_DOS #else #define huge #endif #ifdef UNIX #define MACINTOSH_OR_UNIX #endif #define SWITCHES nyquist-3.05/cmt/timebase.c0000644000175000000620000002311410144436365014712 0ustar stevestaff/* timebase.c -- management of calls, time bases and heaps for moxc */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 2-Apr-91 | JDW : further changes * 21-Mar-92 | GWL : abort recovery * 28-Apr-03 | DM : true->TRUE *****************************************************************************/ #include "stdio.h" #include "cext.h" #include "userio.h" #include "midifns.h" #include "timebase.h" #include "moxc.h" timebase_type timebase_queue = NULL; /* waiting to run timebase queue */ call_type callfree = NULL; /* free list */ private void fatal(); /**************************************************************************** * timebase_create * Inputs: * maxsize is the initial size of the heap * Outputs: * returns an initialized timebase_type ****************************************************************************/ timebase_type timebase_create(maxsize) int maxsize; { static char *error_msg = "Out of memory in timebase_create()"; timebase_type base = (timebase_type) memget(sizeof(timebase_node)); if (!base) fatal(error_msg); base->next = NULL; base->next_time = MAXTIME; base->virt_base = 0L; base->real_base = 0L; base->rate = 256L; base->heap_size = 0; base->heap_max = maxsize; base->heap = (call_type *) memget(sizeof(call_type) * maxsize); if (!base->heap) fatal(error_msg); return base; } /**************************************************************************** * callinsert * Inputs: * timebase_type base: the time base and heap * call_type call: the call to insert in heap * Outputs: none * Implementation: * linear insertion; to be changed to heap ****************************************************************************/ void callinsert(base, call) timebase_type base; call_type call; { int i; register call_type *heap = base->heap; /* handle overflow -- this should never be executed if the user * gives the right initial heap size */ base->heap_size++; if (base->heap_size >= base->heap_max) { call_type *new_heap = (call_type *) memget((base->heap_max << 1) * sizeof(call_type)); int i; call_type *oldptr; call_type *newptr; if (!new_heap) { gprintf(TRANS, "Out of space, can't allocate new heap\n"); EXIT(1); } oldptr = base->heap; newptr = new_heap; for (i = base->heap_max; i > 0; i--) *newptr++ = *oldptr++; memfree((char *) heap, base->heap_max * sizeof(call_type)); base->heap = heap = new_heap; base->heap_max = (base->heap_max << 1); } /* now do the heap insert */ i = base->heap_size; while (i > 1) { int parent = i >> 1; if (heap[parent]->u.e.time < call->u.e.time || (heap[parent]->u.e.time == call->u.e.time && heap[parent]->u.e.priority <= call->u.e.priority)) break; heap[i] = heap[parent]; i = parent; } heap[i] = call; /* if next_time might change, reinsert base into queue */ if (heap[1] == call) { remove_base(base); insert_base(base); } } /**************************************************************************** * callshow * Inputs: * calltype call: the call to show * Effect: * prints a description of call * Assumes: * call is not null ****************************************************************************/ void callshow(call) call_type call; { int i; gprintf(TRANS,"address: %lx\n", (ulong)call); gprintf(TRANS,"time: %ld\n", call->u.e.time); gprintf(TRANS,"routine: %lx\n", (ulong)call->u.e.routine); gprintf(TRANS,"parameters:"); for (i = 0; i < MAX_CALL_ARGS; i++) { gprintf(TRANS, " %d", call->u.e.p.arg[i]); } gprintf(TRANS, "\n"); } /*************************************************************** * fatal * * Input : msg: a message to be displayed * Effect: print message and exit program ***************************************************************/ private void fatal(msg) char *msg; { gprintf(FATAL, msg); EXIT(1); } /*************************************************************** * timebase_free * * Input : a time base * Effect: deallocate the time base ***************************************************************/ void timebase_free(timebase) timebase_type timebase; { remove_base(timebase); if (timebase->heap) { memfree((char *) timebase->heap, (timebase->heap_max * sizeof(call_type))); } memfree((char *) timebase, sizeof(timebase_node)); } /*************************************************************** * insert_base * * Input : a time base not in the list * Effect: insert timebase at the appropriate spot in the list * computes the next_time field from the top of the heap ***************************************************************/ void insert_base(timebase) timebase_type timebase; { register timebase_type *ptr = &timebase_queue; register time_type next_time = MAXTIME; /* compute next_time */ if (timebase->heap_size != 0) { register call_type call = timebase->heap[1]; /* virt to real calculation */ next_time = (virt_to_real_256(timebase, call->u.e.time) & 0xFFFFFF00) + call->u.e.priority; /* gprintf(TRANS, "insert next_time is %ld, vt %ld, rb %ld, vb %ld rt %ld\n", next_time, timebase->heap[1]->u.e.time, timebase->real_base, timebase->virt_base, timebase->rate); */ } timebase->next_time = next_time; if (next_time != MAXTIME) { /* insert into the list */ while (TRUE) { if (! *ptr) { *ptr = timebase; timebase->next = NULL; return; } else if ((*ptr)->next_time >= next_time) { timebase->next = *ptr; *ptr = timebase; return; } else ptr = &((*ptr)->next); } } } /*************************************************************** * remove_base * * Input : timebase * Effect: if timebase is in the queue, remove it ***************************************************************/ void remove_base(timebase) timebase_type timebase; { timebase_type *ptr = &timebase_queue; while (*ptr) { if (*ptr == timebase) { *ptr = timebase->next; return; } else ptr = &((*ptr)->next); } } /*************************************************************** * remove_call * * Input : a timebase -- passed as a global * Assumes: a_timebase->heap_size > 0 * Returns: the earliest call in the queue * Effect: removes the earliest call in the queue ***************************************************************/ call_type remove_call(timebase_type a_timebase) { register call_type *heap = a_timebase->heap; call_type result = heap[1]; register call_type large; int i = 1; int child = i << 1;; large = heap[a_timebase->heap_size--]; while (child <= a_timebase->heap_size) { if (child + 1 <= a_timebase->heap_size) { if (heap[child + 1]->u.e.time < heap[child]->u.e.time || (heap[child + 1]->u.e.time == heap[child]->u.e.time && heap[child + 1]->u.e.priority < heap[child]->u.e.priority)) child++; } /* child is now the index of the least child */ if (large->u.e.time < heap[child]->u.e.time || (large->u.e.time == heap[child]->u.e.time && large->u.e.priority <= heap[child]->u.e.priority)) break; /* swap */ heap[i] = heap[child]; i = child; child = i << 1; } heap[i] = large; return result; } /*************************************************************** * set_rate * * Input : timebase and new rate * Effect: makes the current rate of timebase be rate ***************************************************************/ void set_rate(base, rate) timebase_type base; time_type rate; { if (base == timebase) base->virt_base = virttime; else base->virt_base = real_to_virt(base, eventtime); base->real_base = eventtime; base->rate = rate; /* gprintf(TRANS, "new real_base %ld virt_base %ld\n", base->real_base, base->virt_base); */ remove_base(base); insert_base(base); } /*************************************************************** * set_virttime * * Input : virtual time * Effect: makes the current virtual time of timebase be vtime ***************************************************************/ void set_virttime(base, vtime) timebase_type base; time_type vtime; { base->real_base = eventtime; base->virt_base = vtime; if (base == timebase) virttime = vtime; remove_base(base); insert_base(base); } /*************************************************************** * timebase_use * * Input : a timebase to use for scheduling * Effect: sets up globals: timebase, virttime ***************************************************************/ void timebase_use(base) register timebase_type base; { if (timebase != base) { timebase = base; virttime = real_to_virt(base, eventtime); } } nyquist-3.05/cmt/seqmwrite.h0000644000175000000620000000017610144436365015151 0ustar stevestaff/* seqmwrite.h -- midi file writer */ void seq_write_smf(seq_type seq, FILE *outfile); /* LISP: (SEQ-WRITE-SMF SEQ FILE) */ nyquist-3.05/cmt/seqmread.c0000644000175000000620000003212610144436365014725 0ustar stevestaff/* * seqmread.c * * Convert a MIDI file to a seq. */ /* Copyright 1989 Carnegie Mellon University */ /***************************************************************************** * Change Log * Date | who : Change *-----------+----------------------------------------------------------------- * 17-Feb-92 | GWL : only one stdio.h * : fix to satisfy compiler: void returns, time_type giotime(), int filegetc() *****************************************************************************/ #include "switches.h" #include "stdio.h" #include "cext.h" #include "cmdline.h" #include "midifns.h" /* to get time_type */ #include "timebase.h" #include "moxc.h" /* to get debug declared */ #include "seq.h" #include "seqread.h" /* to get scale */ #include "seqmread.h" #include "userio.h" #include "ctype.h" #include "midifile.h" #include "tempomap.h" int filegetc(); void initfuncs(); void prtime(); void snding_free(); typedef struct snding_struct { struct snding_struct *next; event_type event_ptr; int pitch; int channel; } snding_node, *snding_type; #define snding_alloc() (snding_type) memget(sizeof(snding_node)) #define snding_free(s) memfree(s, sizeof(snding_node)) snding_type snding_list = NULL; tempomap_type the_tempomap; event_type initial_clock; /* remember the first clock event */ long prev_ticksize; /* remember the previous ticksize */ int sysex_id = 0; void smf_noteoff(); void smf_error(); void smf_header(); void smf_trackstart(); void smf_trackend(); void smf_noteon(); void smf_pressure(); void smf_parameter(); void smf_pitchbend(); void smf_program(); void smf_chanpressure(); void smf_sysex(); void smf_metamisc(); void smf_metaseq(); void smf_metaeot(); void smf_timesig(); void smf_smpte(); void smf_tempo(); void smf_keysig(); void smf_metaspecial(); void smf_metatext(); void smf_arbitrary(); private seq_type the_score; static FILE *F; int filegetc() { /* int temp = getc(F); printf(" %x ", temp);*/ return(int)(getc(F)); } void seq_read_smf(seq, fp) seq_type seq; FILE *fp; { F = fp; initfuncs(); sysex_id = 0; /* sysex in seq has to correspond to a symbol */ the_score = seq; /* current sequence is a global within this module */ if (!seq) return; the_tempomap = tempomap_create(); /* insert an initial clock to correspond to the default midifile tempo (tempomap_create creates a corresponding initial entry in the tempomap) (see smf_tempo for explanation of the scale() call) */ initial_clock = insert_clock(the_score, 0L, 0, 500L << 16); /* scale(24 * 500000, 1 << 16, 24000) */ if (!the_tempomap) return; Mf_getc = filegetc; midifile(); /* fmac_close(F); -- do not close the file because the caller might try to * close it (in fact XLISP insists on closing it as a side effect of * garbage collection. */ gprintf(TRANS, "\nLoaded Midi file with %ld note(s), %ld ctrl(s).\n\n", seq_notecount(seq), seq_ctrlcount(seq)); seq_reset(seq); while (snding_list) { snding_type snding = snding_list; snding_list = snding_list->next; gprintf(TRANS, "Note-on (key %d, chan %d) has no matching noteoff\n", snding->pitch, snding->channel + 1); snding_free(snding); } tempomap_free(the_tempomap); } /* gio_time -- get the time in millisec for Adagio */ /* * Since Adagio times are (in their precise form) 1/256 ms, we want * a similar time for midifiles, whose natural unit would be microseconds. * We'll shift the microsecond time by 2 to get 1/250 ms = 4 us units * and convert using the scale function when necessary. * Real time is the time of the last tempo change (last_tempo_time) * which is in 4us units + elapsed time. * Elapsed time is the elapsed beats times the beat duration. * Elapsed beats is Mf_currtime - last_tempo_beat. * Beat duration is the specified tempo / division, where specified tempo * is in microseconds, and division is parts per quarternote. */ unsigned long divisions = 24L; time_type gio_time() { return (tempomap_lookup(the_tempomap, Mf_currtime) + 125L) / 250L; } void smf_header(format,ntrks,division) { /* gprintf(TRANS, "Header format=%d ntrks=%d division=%d\n", format,ntrks,division); */ if (format > 1) gprintf(TRANS, "Warning: format %d midi file may not work.\n", format); divisions = division; /* adjust the initial tempochange */ the_tempomap->entries->tempo = 500000L / division; } void smf_trackstart() { /* gprintf(TRANS, "Track start\n"); */ } void smf_trackend() { /* gprintf(TRANS, "Track end\n"); */ } void smf_noteon(chan,pitch,vol) { snding_type snding; if (vol == 0) { /* convert to a noteoff */ smf_noteoff(chan, pitch, 0); return; } /* prtime(); gprintf(TRANS, "Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); */ /* get ready to remember the sounding note */ snding = snding_alloc(); snding->next = snding_list; snding_list = snding; /* enter an event into score and remember it */ snding->event_ptr = insert_note(the_score, gio_time(), 0, chan + 1, pitch, 0L, vol); snding->pitch = pitch; snding->channel = chan; } void smf_noteoff(chan,pitch,vol) { snding_type *snding_ptr; register snding_type snding; /* prtime(); gprintf(TRANS, "Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); */ /* search for the snding record */ for (snding_ptr = &snding_list; (snding = *snding_ptr) && ((snding->pitch != pitch) || (snding->channel != chan)); snding_ptr = &(snding->next)) /* printf("* search *\n") */; if (!snding) { gprintf(TRANS, "Note off %d, channel %d ignored: no note on\n", pitch, chan + 1); } else { event_type event = snding->event_ptr; event->u.note.ndur += (gio_time() - event->ntime) << 8; /* free the snding record */ *snding_ptr = snding->next; snding_free(snding); } } void smf_pressure(chan,pitch,press) { prtime(); gprintf(TRANS, "Pressure, chan=%d pitch=%d press=%d (IGNORED)\n", chan + 1, pitch, press); } void smf_parameter(chan,control,value) { int ctrl = 0; /* prtime(); gprintf(TRANS, "Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value); */ /* see if the control is one of the standard Adagio controls that can be encoded in a special way. If not, ctrl remains at zero. */ switch (control) { case PORTASWITCH: ctrl = PSWITCH_CTRL; break; case MODWHEEL: ctrl = MODWHEEL_CTRL; break; case VOLUME: ctrl = VOLUME_CTRL; break; } if (ctrl) /* then do special ctrl insert and save storage */ insert_ctrl(the_score, gio_time(), 0, ctrl, chan + 1, value); else insert_macctrl(the_score, gio_time(), 0, control, chan + 1, value); } /* smf_pitchbend -- handle a pitch bend event */ /* * NOTE: the midifile code from Tim Thompson has the msb and lsb bytes swapped. * Thus the parameter msb is really the low order byte and lsb is high order. */ void smf_pitchbend(chan,msb,lsb) { /* prtime(); gprintf(TRANS, "Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb); */ insert_ctrl(the_score, gio_time(), 0, BEND_CTRL, chan + 1, ((lsb << 7) + msb) >> 6); } void smf_program(chan,program) { /* prtime(); gprintf(TRANS, "Program, chan=%d program=%d\n",chan+1,program); */ insert_ctrl(the_score, gio_time(), 0, PROGRAM_CTRL, chan + 1, program); } void smf_chanpressure(chan,press) { /* prtime(); gprintf(TRANS, "Channel pressure, chan=%d pressure=%d\n",chan+1,press); */ insert_ctrl(the_score, gio_time(), 0, TOUCH_CTRL, chan + 1, press); } void smf_sysex(leng,mess) int leng; char *mess; { char symb[10]; def_type defn; int i; sprintf(symb, "X%d", sysex_id++); if (leng > 255) { gprintf(TRANS, "sysex too long (%d bytes), ignored\n", leng - 2); return; } /* need to end up with a prefix of [0][length], so add 2 to length; note that this will copy past the end of the message -- this is slightly dangerous and definitely crufty: */ defn = insert_def(the_score, symb, (unsigned char *) mess, leng + 2); /* now fix up the definition by inserting the prefix bytes: */ for (i = leng + 1; i > 1; i--) defn->definition[i] = defn->definition[i - 2]; defn->definition[0] = 0; defn->definition[1] = leng; insert_macro(the_score, gio_time(), 0, defn, 1, 0, NULL); /* prtime(); gprintf(TRANS, "Sysex, leng=%d (IGNORED)\n",leng); */ } void smf_metamisc(type,leng,mess) char *mess; { prtime(); gprintf(TRANS, "Meta event, unrecognized, type=0x%02x leng=%d (IGNORED)\n", type, leng); } void smf_metaspecial(type,leng,mess) char *mess; { prtime(); gprintf(TRANS, "Meta event, sequencer-specific, type=0x%02x leng=%d (IGNORED)\n", type, leng); } void smf_metatext(type,leng,mess) char *mess; { static char *ttype[] = { NULL, "Text Event", /* type=0x01 */ "Copyright Notice", /* type=0x02 */ "Sequence/Track Name", "Instrument Name", /* ... */ "Lyric", "Marker", "Cue Point", /* type=0x07 */ "Unrecognized" }; int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; if ( type < 1 || type > unrecognized ) type = unrecognized; } void smf_metaseq(num) { prtime(); gprintf(TRANS, "Meta event, sequence number = %d (IGNORED)\n",num); } void smf_metaeot() { /* prtime(); gprintf(TRANS, "Meta event, end of track\n"); */ } void smf_keysig(sf,mi) { /* prtime(); gprintf(TRANS, "Key signature, sharp/flats=%d minor=%d\n",sf,mi); */ } /* smf_tempo -- handle a midifile tempo change */ /* * NOTE: if divisions is positive, it gives time units per quarter, and * tempo is microsec per division. The product is microsec per quarter. * To convert to ticksize (parameter to insert_clock), we divide by 24*1000 * to get units of millisec and 24ths of quarter notes. insert_clock * expects this to have a 16 bit fractional part. */ void smf_tempo(tempo) long tempo; { time_type ctime = gio_time(); long ticksize = scale(tempo, 1024L, 375L); /* (tempo / 24000) << 16; microsec/clock converted to ms/quarter, shifted 16*/ /* prtime(); gprintf(TRANS, "Tempo, microseconds-per-MIDI-quarter-note = %ld\n",tempo); */ tempomap_insert(the_tempomap, Mf_currtime, tempo / divisions); if (ctime == 0) { /* we already have a clock event at t=0 -> fix it */ initial_clock->u.clock.ticksize = ticksize; } else { /* we need a new one */ /* NOTE: after the first clock, insert clock events 1/2 tick early to make sure ticksize is set before clock_tick() wakes up and reads it. */ insert_clock(the_score, ctime - (prev_ticksize >> 17), 0, ticksize); prev_ticksize = ticksize; } } void smf_timesig(nn,dd,cc,bb) { /* int denom = 1; while ( dd-- > 0 ) denom *= 2; prtime(); gprintf(TRANS, "Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */ } void smf_smpte(hr,mn,se,fr,ff) { prtime(); gprintf(TRANS, "SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d (IGNORED)\n", hr, mn, se, fr, ff); } void smf_arbitrary(leng,mess) char *mess; { prtime(); gprintf(TRANS, "Arbitrary bytes, leng=%d (IGNORED)\n",leng); } void smf_error(msg) char *msg; { gprintf(ERROR, msg); } void prtime() { gprintf(TRANS, "Time=%ld/%ld ",Mf_currtime, gio_time()); } void initfuncs() { Mf_error = smf_error; Mf_header = smf_header; Mf_starttrack = smf_trackstart; Mf_endtrack = smf_trackend; Mf_on = smf_noteon; Mf_off = smf_noteoff; Mf_pressure = smf_pressure; Mf_controller = smf_parameter; Mf_pitchbend = smf_pitchbend; Mf_program = smf_program; Mf_chanpressure = smf_chanpressure; Mf_sysex = smf_sysex; Mf_metamisc = smf_metamisc; Mf_seqnum = smf_metaseq; Mf_eot = smf_metaeot; Mf_timesig = smf_timesig; Mf_smpte = smf_smpte; Mf_tempo = smf_tempo; Mf_keysig = smf_keysig; Mf_sqspecific = smf_metaspecial; Mf_text = smf_metatext; Mf_arbitrary = smf_arbitrary; } nyquist-3.05/cmt/seqwrite.c0000644000175000000620000002165010144436365014767 0ustar stevestaff/* seqwrite -- write a seq in Adagio format to a file */ /*************************************************************************** * Change Log * Date | Change *-----------+-------------------------------------------------------------- * 11-Mar-94 | Created Change Log * 11-Mar-94 | PLu : Added private to function defs. * 28-Apr-03 | DM : changed for portability, true->TRUE, false->FALSE ****************************************************************************/ #include "switches.h" #include #include "cext.h" #include "midifns.h" #include "timebase.h" #include "seq.h" #include "seqwrite.h" #include "userio.h" #include "record.h" private boolean next_event_time(); private void write_event(); private void write_velocity(FILE *f, int velocity); private void write_voice(); private void write_rest(FILE *f, event_type ev, boolean abs_flag); private void write_time(); private boolean clock_started; private long clock_half_tick; private int new_tempo; /* non-zero indicates a pending tempo change... */ private time_type tempo_change_at; private int macro_count; private int call_count; private int deframp_count; private int seti_count; private int last_velocity; private int last_voice = seq_dflt_voice; /* next_event_time -- get the time of the next event */ /* * NOTE: clock events are ignored (unless this is the first clock event) */ private boolean next_event_time(event, next_time) event_type event; time_type *next_time; { while (event) { if (vc_ctrl(event->nvoice) == ESC_CTRL && event->value == CLOCK_VALUE && clock_started) { /* this is a clock event, ignore it: */ event = event->next; } else { *next_time = event->ntime; return TRUE; } } return FALSE; } /* seq_write -- write a seq to a file */ /* * NOTE: if abs_flag, then write using absolute times ('T'), otherwise use * relative timing ('N'). Also, only selected channels are written. */ void seq_write(seq_type seq, FILE *f, boolean abs_flag) { event_type ev = seq_events(seq); last_velocity = seq_dflt_loud; last_voice = seq_dflt_voice; fprintf(f, "!MSEC\n"); clock_started = FALSE; tempo_change_at = 0; macro_count = 0; call_count = 0; deframp_count = 0; seti_count = 0; while (ev) { write_event(seq, ev, f, abs_flag); ev = ev->next; } if (macro_count) gprintf(TRANS, "%d macros ignored.\n", macro_count); if (call_count) gprintf(TRANS, "%d calls ignored.\n", call_count); if (deframp_count) gprintf(TRANS, "%d deframps ignored.\n", deframp_count); if (seti_count) gprintf(TRANS, "%d setis ignored.\n", seti_count); } private char ctrl_letter[] = "?KMOXYZ"; /* write_event -- write a single event to a file */ /**/ private void write_event(seq, event, f, abs_flag) seq_type seq; event_type event; FILE *f; boolean abs_flag; { int voice = vc_voice(event->nvoice); /* process all current (and earlier) events */ if (is_note(event)) { /*** a note or rest ***/ /* if this note is not a rest, write it */ if (event->value != NO_PITCH && (seq_channel_mask(seq) & (1 << (voice - 1)))) { write_pitch(f, event->value); fprintf(f, " U%ld ", event->u.note.ndur >> 8); write_velocity(f, (int) (event->u.note.ndur & 0xFF)); write_voice(f, voice); write_time(f, event, abs_flag); } } else { /*** a control command ***/ switch (vc_ctrl(event->nvoice)) { case PSWITCH_CTRL: case MODWHEEL_CTRL: case TOUCH_CTRL: case VOLUME_CTRL: case BEND_CTRL: fprintf(f, "%c%d ", ctrl_letter[vc_ctrl(event->nvoice)], event->value); write_voice(f, voice); write_time(f, event, abs_flag); break; case PROGRAM_CTRL: fprintf(f, "Z%d ", event->value + 1); write_voice(f, voice); write_time(f, event, abs_flag); break; case ESC_CTRL: switch (event->value) { case CALL_VALUE: call_count++; write_rest(f, event, abs_flag); /* !call's are not written because there isn't enough * information. A future version of seq should store * the hash table entry instead of the address of the * routine (then we could get string name of the call) * and the number of arguments. */ break; case CLOCK_VALUE: /* design for !clock: for absolute (absflag) files, put the clocks (if any) at the end where they can be edited out easily. For relative files, keep the clocks in-line. On each clock, write a !tempo command inferred by the clock and followed by the !clock. Because the clock event comes before the actual tempo change, the chnage must be delayed by a half tick except for the first one. */ if (abs_flag) break; new_tempo = (2500L << 16) / event->u.clock.ticksize; if (clock_started) { tempo_change_at = event->ntime + clock_half_tick; } else { fprintf(f, "!tempo %d\n", new_tempo); fprintf(f, "!clock\n"); clock_started = TRUE; } clock_half_tick = (event->u.clock.ticksize) >> 17; break; case MACCTRL_VALUE: fprintf(f, "~%d(%d) ", event->u.macctrl.ctrl_number, event->u.macctrl.value); write_voice(f, voice); write_time(f, event, abs_flag); break; case MACRO_VALUE: macro_count++; write_rest(f, event, abs_flag); /* macros are not written because there isn't enough * information. A future version of seq should store * the number of arguments in the event, or better yet, * in the definition. Send complaints to RBD! */ break; case CTRLRAMP_VALUE: fprintf(f, "!ramp ~%d(%d) ~%d(%d) U%d U%d ", event->u.ramp.ctrl, event->u.ramp.u.ctrl.from_value, event->u.ramp.ctrl, event->u.ramp.u.ctrl.to_value, (int)event->u.ramp.step, (int)event->u.ramp.dur); write_voice(f, voice); write_time(f, event, abs_flag); break; case DEFRAMP_VALUE: deframp_count++; write_rest(f, event, abs_flag); /* See MACRO_VALUE above for why this isn't implemented. */ break; case SETI_VALUE: seti_count++; write_rest(f, event, abs_flag); /* !seti and !setv are not implemented -- a future version * of seq should save more information so we can reconstruct * the Adagio source command. */ break; default: gprintf(TRANS, "unexpected ESC_CTRL value\n"); break; } break; default: gprintf(TRANS, "unexpected seq data\n"); break; } } } /* write_rest -- write a rest (in place of an event) */ /**/ private void write_rest(FILE *f, event_type ev, boolean abs_flag) { fprintf(f, "R "); write_time(f, ev, abs_flag); } /* write_time -- write the final field on the line with N or T command */ /**/ private void write_time(f, event, abs_flag) FILE *f; event_type event; boolean abs_flag; { time_type next_time; if (abs_flag) { fprintf(f, "T%ld\n", event->ntime); return; } if (next_event_time(event->next, &next_time)) { if (tempo_change_at && (next_time >= tempo_change_at)) { fprintf(f, "N%ld\n!TEMPO %d\n!CLOCK\nR U%ld\n", tempo_change_at - event->ntime, new_tempo, next_time - tempo_change_at); tempo_change_at = 0; } else { fprintf(f, "N%ld\n", next_time - event->ntime); } } else { fprintf(f, "\n"); } } /* write_velocity -- write the velocity field */ /**/ private void write_velocity(FILE *f, int velocity) { if (last_velocity != velocity) { last_velocity = velocity; fprintf(f, "L%d ", velocity); } } /* write_voice -- write the voice field */ /**/ private void write_voice(f, voice) FILE *f; int voice; { if (last_voice != voice) { last_voice = voice; fprintf(f, "V%d ", voice); } } nyquist-3.05/cmt/midicode.h0000644000175000000620000000324710144436365014710 0ustar stevestaff/************************************************************************ * * Midi codes * Copyright 1989 Carnegie Mellon University * ************************************************************************* * Change Log * Date | Change *-----------+------------------------------------------------------------ * 11-Mar-94 | PLu : Port to IRI ************************************************************************/ #define MIDI_DATA(d) (0x7f & (d)) #define MIDI_CHANNEL(c) (0x0f & ((c) - 1)) #define MIDI_PORT(c) (((c) - 1) >> 4) #define MIDI_PROGRAM(p) MIDI_DATA((p) - 1) #define MIDI_STATUS_BIT 0x80 #define MIDI_COMMON 0x70 #define MIDI_CODE_MASK 0xf0 #define MIDI_CHN_MASK 0x0f #define MIDI_REALTIME 0xf8 #define MIDI_CHAN_MODE 0xfa #define MIDI_OFF_NOTE 0x80 #define MIDI_ON_NOTE 0x90 #define MIDI_POLY_TOUCH 0xa0 #define MIDI_CTRL 0xb0 #define MIDI_CH_PROGRAM 0xc0 #define MIDI_TOUCH 0xd0 #define MIDI_BEND 0xe0 #ifdef UNIX_IRIX_MIDIFNS #define CMT_MIDI_SYSEX 0xf0 #define CMT_MIDI_EOX 0xf7 #else #define MIDI_SYSEX 0xf0 #define MIDI_EOX 0xf7 #endif #define MIDI_Q_FRAME 0xf1 #define MIDI_SONG_POINTER 0xf2 #define MIDI_SONG_SELECT 0xf3 #define MIDI_F4 0xf4 #define MIDI_F5 0xf5 #define MIDI_TUNE_REQ 0xf6 #define MIDI_TIME_CLOCK 0xf8 #define MIDI_F9 0xf9 #define MIDI_START 0xfa #define MIDI_CONTINUE 0xfb #define MIDI_STOP 0xfc #define MIDI_FD 0xfd #define MIDI_ACTIVE_SENSING 0xfe #define MIDI_SYS_RESET 0xff #define MIDI_LOCAL 0x7a #define MIDI_LOCAL_OFF 0x00 #define MIDI_LOCAL_ON 0x7f #define MIDI_ALL_OFF 0x7b #define MIDI_OMNI_OFF 0x7c #define MIDI_OMNI_ON 0x7d #define MIDI_MONO_ON 0x7e #define MIDI_POLY_ON 0x7f nyquist-3.05/cmt/userio.h0000644000175000000620000000506110144436365014435 0ustar stevestaff/* Copyright 1989 Carnegie Mellon University */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 5-Apr |JDW : Further changes *****************************************************************************/ /* classes of output for gprintf */ #ifdef MACINTOSH #undef false #undef true #include #define TRANS (long) 0 #define ERROR (long) 1 #define FATAL (long) 2 #define GDEBUG (long) 3 #endif #ifdef DONT_USE_CMT_IO #define TRANS stdout #define ERROR stdout #define FATAL stdout #define GDEBUG stdout #endif #ifndef TRANS /* default */ #define TRANS 0 #define ERROR 1 #define FATAL 2 #define GDEBUG 3 #endif #define CR '\n' #define ABORT_CHAR 0x03 #ifdef NYQUIST #define BREAK_CHAR 0x02 #else #define BREAK_CHAR 0x07 #endif #define BREAK_LEVEL 1 #define ABORT_LEVEL 2 #define read_to_eol(ch) if (ch != CR) { char temp[100]; ggets(temp); } extern char fileopen_name[]; extern int abort_flag; extern int redirect_flag; /* added by Ning Hu, Apr 2001 */ boolean get_ascii(char *c); /* polls for an ascii character */ #ifdef DOTS_FOR_ARGS /* was (defined(ITC_MACH) && defined(__STDC__)) || defined(MACINTOSH) || defined(AZTEC) || (defined(AMIGA) && defined(LATTICE)) || defined(UNIX_ITC) */ void gprintf(long where, char *format, ...); /* general printf */ #else void gprintf(); #endif char *ggets(char *str); /* general gets */ int wait_ascii(void); /* a waiting version of get_ascii */ void clean_exit(void); /* exit the program after cleaning up */ void io_init(void); /* overall initialization */ void abort_check(void); /* exit if aborted */ int check_aborted(void); /* looks to see if user typed ctrl-C */ int askbool(char *prompt, int deflt); FILE *fileopen(char *deflt, char *extension, char *mode, char *prompt); void readln(FILE *fp); void gflush(void); int gputchar(int c); int ggetchar(); char *ggets(char *str); boolean ascii_input(char *c); void unget_ascii(char c); boolean check_ascii(void); #ifdef MACINTOSH boolean get_file_info(char *filename, OSType *file_type, OSType *file_creator); boolean put_file_info(char *filename, OSType file_type, OSType file_creator); #endif #ifdef DONT_USE_CMT_IO #define ggetchar getchar #define ggets gets #define gprintf fprintf #define gputchar putchar #define gprintf fprintf #define gputchar putchar #endif #ifdef MICROSOFT void c_break(int sig); #endif nyquist-3.05/cmt/midifns.c0000644000175000000620000014350611466723256014570 0ustar stevestaff/***************************************************************************** * midifns.c * Copyright 1989 Carnegie Mellon University * Date | Change *-----------+----------------------------------------------------------------- * 29-Mar-88 | Created from IBM PC version of mpu.c * | Added settime() * 02-May-88 | AMIGA 2000 version. portable version. * 12-Oct-88 | JCD : Exclusive AMIGA Version. * 13-Apr-89 | JCD : New portable version. * 19-Apr-89 | JCD : Amiga CAMD Version added. * 5-Apr-91 | JDW : Further modification * 17-Feb-92 | GWL : incorporate JMN's new mpu.c * 8-Jun-92 | JDZ : add support for ITC midi interface * 16-Dec-92 | RBD : replace JMN's mpu.c with LMS's mpu.c * 11-Mar-94 | PLu : port to IRIX * 25-Apr-97 | RBD : it looks like SGI changed their interface. I * | made it compile again, but MIDI does not work, so * | took out calls to actually send/recv MIDI data * 28-Apr-03 | DM : Renamed random -> cmtrand, true->TRUE, false->FALSE * | Use features rather than system names in #ifdef's *****************************************************************************/ #include "switches.h" #ifdef UNIX #include #include #ifndef OPEN_MAX /* this is here for compiling the UNIX version under AIX. This is a BSDism */ #define OPEN_MAX 2000 #endif /* OPEN_MAX */ #endif /* UNIX */ #ifdef UNIX_MACH #include "machmidi.h" #endif #ifdef AMIGA #ifdef AZTEC #include "functions.h" #endif /* AZTEC */ #include "midi/camd.h" #include "clib/camd_protos.h" /* note: azt_camd_pragmas.h was produced by running MAPFD on the * lib/camd_lib.fd file included in the CAMD disk from Commodore. * The "CamdClient" calls are manually removed from */ #ifdef AZTEC #include "pragmas/azt_camd_pragmas.h" #else /* !AZTEC */ #include "pragmas/lat_camd_pragmas.h" #endif /* AZTEC */ #include "camdmidi.h" #include "ctype.h" #endif /* AMIGA */ #ifdef UNIX_IRIX /* #define UNIX_IRIX_MIDIFNS -- this would enable actual midi I/O * if the actual midi I/O code worked */ /* IRIX changed the MIDI interface, * retain this for older systems: */ #ifdef UNIX_IRIX_MIDIFNS #include #endif #endif #include "stdio.h" #include "cext.h" #include "midicode.h" #include "cmdline.h" #include "pitch.h" #include "midifns.h" #include "userio.h" #include "string.h" #ifdef MACINTOSH_OR_DOS #ifndef WINDOWS #include "midibuff.h" #endif #endif #ifdef UNIX_ITC /* was ITC */ #include "sys/param.h" /* since boolean is defined, block its definition in midistruct.h. * CMT defines boolean as ushort, but midistruct.h uses int. * This is not a problem on RS/6000s, but beware! */ /* the following would be included if we had the BSD switch set. I think we should try to avoid BSDisms; when fixed, the following should be removed */ #define NBBY 8 #include "sys/select.h" /* defines fd_set */ #define MIDI_HAS_BOOLEAN #include "midistruct.h" #include "cmtio.h" #endif /* UNIX_ITC */ #ifdef DOS #ifndef WINDOWS #include "timer.h" #include "mpu.h" #endif /* ifndef WINDOWS */ #endif /* ifdef DOS */ #ifndef BREAKTEST #define BREAKTEST #endif #ifdef __APPLE__ #include #include #include #else #ifdef UNIX #ifndef UNIX_IRIX #include "sys/time.h" #include "sys/timeb.h" #include "cmtio.h" #else #include #include #include #ifdef UNIX_IRIX_MIDIFNS #include #include #endif /* UNIX_IRIX_MIDIFNS */ #endif /* UNIX_IRIX */ #endif /* UNIX */ #endif /* __APPLE__ */ #ifdef ITC static int ignore_realtime = 0; #endif /* ITC */ #ifdef MACINTOSH /* added for ThinkC 7: */ #include /* port numbers are in the range 0..MAX_PORTS-1 */ #define CHANNELS_PER_PORT 16 #define MAX_PORTS ((MAX_CHANNELS + CHANNELS_PER_PORT - 1) / CHANNELS_PER_PORT) /* here are some MIDIMGR specific definitions */ #ifdef MIDIMGR #include "MIDI.h" #include "midimgr.h" #define TICKS_TO_MS(t) t #define MS_TO_TICKS(t) t #else /* here are some non-MIDIMGR definitions for the Mac */ /**************************************************************************** * * DMH: constants from macmidi.c * ****************************************************************************/ /* the modem port, also called port A */ #define portA 0 /* the printer port, also called port B */ #define portB 1 /* a tick is 1/60 of a second * * the following tables and routines are used to convert * between ticks and milliseconds */ #define TICKS_TO_MS(t) (((t) * 50) / 3) #define MS_TO_TICKS(t) (((t) * 3) / 50) #endif /* def MIDIMGR */ #endif /* def MACINTOSH */ #ifdef WINDOWS #define huge #endif /**************************************************************************** * * exported flags * ****************************************************************************/ boolean miditrace = FALSE; /* enables printed trace of MIDI output */ boolean musictrace = FALSE; /* enables printed trace of commands */ #ifdef MACINTOSH_OR_DOS boolean ctrlFilter = TRUE; /* suppress continuous controller data */ boolean exclFilter = TRUE; /* suppress exclusive messages */ boolean realFilter = TRUE; /* suppress realtime messages */ #endif /**************************************************************************** * * exported variables * ****************************************************************************/ public int keyloud; /* set to velocity of last getkey event */ /* public long error; */ public short midi_error_flags = 0; /* The following midifns_syntax lists command line switches and options. Since these are machine dependent, use conditional compilation. Conditional compilation within a string is a bit tricky: you want to write "\" for line continuation within the string, but "\" gets eaten by the macro preprocessor. That's why we define macros like AMIGAINPORT. Regretably it doesn't work for all compilers. */ /* Lattice and RT/Unix aren't happy expanding the embedded macros below, so I made a separate declaration of midifns_syntax for Unix */ #ifdef UNIX public char *midifns_syntax = "blockTurn off midi THRU;\ miditraceTrace low-level midi functions;\ noalloffDo not send alloff message when done;\ traceTrace music operations;\ tuneLoad a tuning file"; #else #ifdef MACINTOSH #ifdef MIDIMGR public char *midifns_syntax = "miditraceTrace low-level midi functions;\ noalloffDo not send alloff message when done;\ patchRemember/reuse Midi Mgr patches;\ traceTrace music operations;\ keepKeep other processes running;\ tuneLoad a tuning file"; #else /* no MIDIMGR */ public char *midifns_syntax = "miditraceTrace low-level midi functions;\ noalloffDo not send alloff message when done;\ patchRemember/reuse Midi Mgr patches;\ traceTrace music operations;\ tuneLoad a tuning file"; #endif /* MIDIMGR */ #else #ifdef AMIGA public char *midifns_syntax = "blockTurn off midi THRU;\ inportInpur port number;\ miditraceTrace low-level midi functions;\ noalloffDo not send alloff message when done;\ outportOutput port number;\ traceTrace music operations;\ tuneLoad a tuning file"; #else /* not UNIX or MACINTOSH or MIDIMGR or AMIGA */ #ifdef DOS public char *midifns_syntax = "miditraceTrace low-level midi functions;\ noalloffDo not send alloff message when done;\ traceTrace music operations;\ tuneLoad a tuning file"; #endif /* DOS */ #endif /* AMIGA */ #endif /* MACINTOSH */ #endif /* UNIX */ #ifdef MACINTOSH boolean do_midi_thru = FALSE; /* exported: copy midi in to midi out */ #endif /**************************************************************************** * * local module variables * ****************************************************************************/ private int initialized = FALSE; /* set by musicinit, cleared by musicterm */ private boolean tune_flag = FALSE; /* set by musicinit, never cleared */ #ifdef DOS private boolean metroflag = FALSE; /* flag to turn on metronome */ #endif private int user_scale = FALSE; /* TRUE if user-defined scale */ private int bend[MAX_CHANNELS]; /* current pitch bend on channel */ short cur_midi_prgm[MAX_CHANNELS]; private pitch_table pit_tab[128]; /* scale definition */ #ifdef DOS private ulong timeoffset = 0; public boolean exclerr = FALSE; public byte xcodemask; /* mask (00 or FF) */ public byte xcode; /* mfr code */ #endif #ifdef MACINTOSH_OR_DOS boolean sysex_pending = FALSE; #endif #ifdef AMIGA #define CONTCONT ((CMF_Ctrl & ~CMF_CtrlSwitch) | CMF_PitchBend | \ CMF_ChanPress) #endif /* def AMIGA */ #ifdef UNIX private ulong timeoffset = 0; #endif #ifdef UNIX_IRIX_MIDIFNS static MIport *miport; static int ignore_realtime = 0; private byte *sysex_p; private int sysex_n; #endif #ifdef ITC mi_id midiconn; #endif #ifdef MACINTOSH private ulong ticksAtStart = 0L; /* clock ticks at time of last musicinit or timereset * ASSUME: tick clock never wraps. this is a good assumption, since * the tick clock is set to zero when the power is turned on and the * tick counter is 32 bits. the Macintosh would need to be on for * 828.5 days for the tick counter to wrap around! */ #endif /* def MACINTOSH */ /**************************************************************************** * * functions declared in this module * ****************************************************************************/ private void fixup(); private void midi_init(); extern boolean check_ascii(); /*userio.c*/ private void musicterm(); /**************************************************************************** * alloff * Inputs: * none * Effect: * Sends MIDI all notes off command on every channel. ****************************************************************************/ #define ALL_NOTES_OFF 0x7B /*DMH: from macmidi.c*/ void alloff() { int c; if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"alloff()\n"); for (c = 1; c <= MAX_CHANNELS; c++) { midi_write(3, MIDI_PORT(c), (byte) (0xb0 | MIDI_CHANNEL(c)), ALL_NOTES_OFF, 0); } } /*************************************************************** * eventwait * * Input : wakeup time, -1 means forever * Output : none * Return: none * Effect: waits until ascii or midi input or timeout ***************************************************************/ #ifdef UNIX_ITC void eventwait(timeout) long timeout; { struct timeval unix_timeout; struct timeval *waitspec = NULL; fd_set readfds; struct rlimit file_limit; FD_ZERO(&readfds); FD_SET(MI_CONNECTION(midiconn), &readfds); FD_SET(fileno(stdin), &readfds); if (timeout >= 0) { timeout -= gettime(); /* convert to millisecond delay */ unix_timeout.tv_sec = timeout / 1000; /* remainder become microsecs: */ unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000; waitspec = &unix_timeout; } getrlimit(RLIMIT_NOFILE, &file_limit); select(file_limit.rlim_max+1, &readfds, 0, 0, waitspec); return; } #else /* !UNIX_ITC */ #ifdef UNIX /* see machmidi.c for UNIX_MACH implementation */ #ifndef UNIX_MACH #ifdef UNIX_IRIX_MIDIFNS void eventwait(timeout) long timeout; { struct timeval unix_timeout; struct timeval *waitspec = NULL; fd_set readfds; FD_ZERO(&readfds); FD_SET(mdGetFd(miport), &readfds); FD_SET(fileno(stdin), &readfds); if (timeout >= 0) { timeout -= gettime(); /* convert to millisecond delay */ unix_timeout.tv_sec = timeout / 1000; /* remainder become microsecs: */ unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000; waitspec = &unix_timeout; } select(FD_SETSIZE, &readfds, 0, 0, waitspec); return; } #else #ifdef BUFFERED_SYNCHRONOUS_INPUT void eventwait(timeout) long timeout; { struct timeval unix_timeout; struct timeval *waitspec = NULL; struct rlimit file_limit; if (timeout >= 0) { timeout -= gettime(); /* convert to millisecond delay */ unix_timeout.tv_sec = timeout / 1000; /* remainder become microsecs: */ unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000; waitspec = &unix_timeout; getrlimit(RLIMIT_NOFILE, &file_limit); select(file_limit.rlim_max+1, 0, 0, 0, waitspec); } else { int c = getc(stdin); ungetc(c, stdin); } return; } #else void eventwait(timeout) long timeout; { struct timeval unix_timeout; struct timeval *waitspec = NULL; int readfds = 1 << IOinputfd; struct rlimit file_limit; if (timeout >= 0) { timeout -= gettime(); /* convert to millisecond delay */ unix_timeout.tv_sec = timeout / 1000; /* remainder become microsecs: */ unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000; waitspec = &unix_timeout; } getrlimit(RLIMIT_NOFILE, &file_limit); select(file_limit.rlim_max+1, &readfds, 0, 0, waitspec); return; } #endif /* BUFFERED_SYNCHRONOUS_INPUT */ #endif /* UNIX_IRIX */ #endif /* UNIX_MACH */ #endif /* UNIX */ /* I wanted to put an else here, but this confused a Unix C compiler */ #endif /* UNIX_ITC */ #ifdef AMIGA /* see camdmidi.c for Amiga implementation */ #else #ifndef UNIX /* since I couldn't use an else above, have to check UNIX here */ #ifdef WINDOWS void eventwait(timeout) long timeout; { if (timeout >= 0) { gprintf(TRANS, "eventwait: not implemented\n"); return; } else { int c = getc(stdin); ungetc(c, stdin); } return; } #else void eventwait(timeout) long timeout; { while (timeout > gettime() || timeout == -1) { if (check_ascii() || check_midi()) return; } } #endif /* WINDOWS */ #endif /* UNIX */ #endif /* AMIGA */ /**************************************************************************** * exclusive * Inputs: * boolean onflag -- set to TRUE to receive midi exclusive data * Effect: * Tells module to read exclusive messages into buffer ****************************************************************************/ void exclusive(boolean onflag) { if (!initialized) fixup(); if (musictrace) gprintf(TRANS, "exclusive: %d\n", onflag); #ifdef AMIGA if (onflag) SetMidiFilters(cmt_mi, cmt_mi->PortFilter, cmt_mi->TypeFilter | CMF_SysEx, cmt_mi->ChanFilter); else SetMidiFilters(cmt_mi, cmt_mi->PortFilter, cmt_mi->TypeFilter & ~CMF_SysEx, cmt_mi->ChanFilter); #endif #ifdef MACINTOSH_OR_DOS exclFilter = !onflag; #endif } /**************************************************************************** * fixup * Effect: * Print error message and call musicinit ****************************************************************************/ private void fixup() { gprintf(ERROR, "You forgot to call musicinit. I'll do it for you.\n"); musicinit(); } #ifdef UNIX_IRIX_MIDIFNS private void flush_sysex(void); #endif long get_excl(byte *buffer, long len) { long ret = 0; #ifdef UNIX_IRIX_MIDIFNS byte *sxp = sysex_p; long l = len; #endif #ifdef UNIX_ITC /* was ITC */ ret = mi_getx(midiconn, FALSE, len, (char *) buffer); #endif #ifdef UNIX_MACH ret = mi_getx(midiconn, FALSE, len, (unsigned char *)buffer); #endif #ifdef UNIX_IRIX_MIDIFNS if (!sysex_p) return 0; if (len > sysex_n) len = sysex_n; while (l--) { *buffer = *(sxp++); if (*(buffer++) == CMT_MIDI_EOX) { flush_sysex(); break; } } ret = len - l - 1; #endif #ifdef AMIGA ret = GetSysEx(cmt_mi, (UBYTE *) buffer, len); AMIGA_ERROR_CHECK; #endif #ifdef MACINTOSH_OR_DOS #ifndef WINDOWS /* I'm not sure the following line is a good thing: it forces the * caller to wait until a full sysex message is received and the * 1st 4 bytes are fetched via getbuf() before a sysex message can * be read via get_excl(). Without this, both mm.c and exget.c * were fetching ahead and getting out of sync with getbuf(). I * fixed mm.c and exget.c to work (by checking for EOX), but I added * this line (which should never have any effect) just to make the * DOS interface behave more like the Amiga and Mac interfaces. The * drawback is that you can't fetch bytes until the EOX is seen, * because nothing goes into the getbuf() buffer until then. */ if (!sysex_pending) return 0; while (len-- && (xbufhead != xbuftail)) { *buffer = xbuff[xbufhead++]; ret++; if (*buffer == MIDI_EOX) { sysex_pending = FALSE; break; } buffer++; xbufhead &= xbufmask; } #endif #endif return ret; } /**************************************************************************** * getbuf * Inputs: * boolean waitflag: TRUE if routine should wait for data * byte * p: Pointer to data destination * Result: boolean * TRUE if data was written to *p * FALSE if data not written to *p * Effect: * copies data from buffer to *p * will wait for buffer to become nonempty if waitflag is TRUE * * Modified 24 May 1988 for AMIGA (JCD) ****************************************************************************/ #ifdef UNIX_IRIX_MIDIFNS private void setup_sysex(MDevent *event, u_char *buffer); #endif /* UNIX_IRIX */ boolean getbuf(boolean waitflag, unsigned char * p) { #ifdef UNIX_IRIX_MIDIFNS MDevent event; int ret; #endif /* UNIX_IRIX */ if (!initialized) fixup(); #ifdef UNIX #ifdef UNIX_IRIX_MIDIFNS /* current IRIX version ignores the waitflag (it never waits) */ if (sysex_p) flush_sysex(); if (ignore_realtime == 0) { ret = mdReceive(miport, &event, 1); if (ret) { if (event.msg[0] != 0xF0) { *((u_long*) p) = *((u_long*) event.msg); } else { setup_sysex(&event, p); } } return ret; } else { do /* skip realtime messages */ { ret = mdReceive(miport, &event, 1); if (ret == -1) return ret; } while (event.msg[0] == 0xf8); if (event.msg[0] != 0xF0) { *((u_long*) p) = *((u_long*) event.msg); } else { setup_sysex(&event, p); } return ret; } #endif /* UNIX_IRIX */ #ifdef UNIX_ITC if (ignore_realtime == 0) { return(mi_get(midiconn, waitflag, (char *) p)); } else { boolean ret=false; /* filter out realtime msgs */ do { ret = mi_get(midiconn, waitflag, (char *) p); if (ret == FALSE) return(ret); } while(p[0] == 0xf8); return(ret); } #else /* UNIX_ITC */ #ifndef UNIX_IRIX if (waitflag) { gprintf(ERROR, "getbuf called with waitflag!"); EXIT(1); } return FALSE; #endif /* UNIX_IRIX */ #endif /* UNIX_ITC */ #endif /* UNIX */ #ifdef MACINTOSH_OR_DOS #ifndef WINDOWS if (sysex_pending) { /* flush sysex to keep buffers in sync */ while (xbuff[xbufhead++] != MIDI_EOX) { xbufhead &= xbufmask; if (xbufhead == xbuftail) break; } sysex_pending = FALSE; } if (waitflag) while (buffhead == bufftail) /* wait */ ; else if (buffhead == bufftail) return(false); *(long *)p = *(long *)(((char *)buff)+buffhead); buffhead = (buffhead + 4) & BUFF_MASK; if (*p == MIDI_SYSEX) { /* if sys-ex, remember to fetch from xbuff */ sysex_pending = TRUE; } return(true); #else return FALSE; #endif /* WINDOWS */ #endif /* MACINTOSH_OR_DOS */ #ifdef AMIGA if (waitflag) { do { WaitMidi(cmt_mi, &cmt_msg); AMIGA_ERROR_CHECK; } while (amigaerrflags); } else { AMIGA_ERROR_CHECK; if (!GetMidi(cmt_mi, &cmt_msg)) return(false); } *(long *)p = *(long *)&cmt_msg; clearmsg(cmt_msg); return(true); #endif /* AMIGA */ } #ifdef UNIX_IRIX_MIDIFNS private void setup_sysex(MDevent *event, u_char *buffer) /* N.B. do not leak memory remember to call free(sysex_p) */ { u_char *sxp = (u_char *) event->sysexmsg; int i; for (i=0;i<4;i++) *(buffer++) = *(sxp++); sysex_p = event->sysexmsg; sysex_n = event->msglen; } private void flush_sysex() { mdFree(sysex_p); sysex_p = 0; sysex_n = 0; } #endif #ifdef MACINTOSH_OR_DOS #ifndef WINDOWS public boolean check_midi() { if (buffhead == bufftail) return FALSE; else return TRUE; } #endif #endif /**************************************************************************** * getkey * Inputs: * boolean waitflag: TRUE if wait until key depression, FALSE if * return immediately * Result: int * key number of key which has been depressed * It returns -1 if waitflag is FALSE and no key has been pressed * If waitflag is TRUE this routine will block until a key is pressed * Effect: * reads a key ****************************************************************************/ /*DMH: in previous version, macmidi.c subtracted 12 from msg to get key at each occurence...*/ short getkey(boolean waitflag) { byte msg[4]; short k; if (!initialized) fixup(); while (TRUE) { /* process data until you find a note */ /* look for data and exit if none found */ /* NOTE: waitflag will force waiting until data arrives */ if (!getbuf(waitflag, msg)) { /* nothing there */ k = -1; break; } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) { if (msg[2] == 0) { /* velocity 0 -> note off */ keyloud = 0; k = msg[1] + 128; } else { keyloud = msg[2]; k = msg[1]; } break; } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) { keyloud = 0; k = msg[1] + 128; break; } } if (musictrace) { if (k != -1) gprintf(TRANS,"getkey got %d\n", k); } return k; } /**************************************************************************** * gettime * Result: ulong * current timestamp since the last call to * musicinit or timereset * Effect: * fakes it ****************************************************************************/ ulong gettime() /*DMH: ulong is from mpu->midifns conversion, for Mac*/ { #if HAS_GETTIMEOFDAY struct timeval timeval; #endif #if HAS_FTIME struct timeb ftime_res; #endif register ulong ticks = 0L; BREAKTEST /* abort if user typed Ctrl Break */ if (!initialized) fixup(); #ifdef MACINTOSH #ifdef MIDIMGR ticks = MIDIGetCurTime(OutputRefNum) - ticksAtStart; #else ticks = TickCount() - ticksAtStart; #endif if (initialized) abort_check(); /* give user a chance to abort */ ticks = TICKS_TO_MS(ticks); #endif #ifdef AMIGA ticks = (*camdtime - timeoffset) << 1; /* return milliseconds */ #endif #ifdef DOS #ifndef WINDOWS ticks = elapsedtime(timeoffset, readtimer()); /* return milliseconds */ /* gprintf(TRANS, "currtime = %ld, timeoffset = %ld\n", currtime, timeoffset); */ #endif #endif /* ifdef DOS */ #if HAS_GETTIMEOFDAY gettimeofday(&timeval, 0); ticks = timeval.tv_sec * 1000 + timeval.tv_usec / 1000 - timeoffset; #endif #if HAS_FTIME ftime(&ftime_res); ticks = ((ftime_res.time - timeoffset) * 1000) + ftime_res.millitm; #endif /* if (miditrace) gprintf(TRANS, "."); */ return(ticks); } /**************************************************************************** * l_rest * Inputs: * long time: Amount of time to rest * Effect: * Waits until the amount of time specified has lapsed ****************************************************************************/ void l_rest(time) long time; { if (!initialized) fixup(); l_restuntil(time + gettime()); } /**************************************************************************** * l_restuntil * Inputs: * long time: Event time to rest until * Effect: * Waits until the specified time has been reached (absolute time) ****************************************************************************/ void l_restuntil(time) long time; { #ifdef MACINTOSH ulong now = gettime(); ulong junk; /* changed from ulong for ThinkC 7, back to ulong for CW5 */ #endif #ifdef AMIGA while (time > gettime()) eventwait(time); #else for(; (time_type) time > gettime();); #endif #ifdef MACINTOSH now = gettime(); if (time > now) Delay(MS_TO_TICKS(time - now), &junk); /* else time <= now, so return immediately */ #endif } /**************************************************************************** * metronome * Inputs: * boolean onflag: TRUE or FALSE * Effect: * enables (true) or disables (false) MPU-401 metronome function. * must be called before musicinit ****************************************************************************/ void metronome(boolean onflag) { #ifdef DOS metroflag = onflag; #endif } /**************************************************************************** * midi_bend * Inputs: * int channel: midi channel on which to send data * int value: pitch bend value * Effect: * Sends a midi pitch bend message ****************************************************************************/ void midi_bend(int channel, int value) { if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"midi_bend: ch %d, val %d\n", channel, value - (1 << 13)); bend[MIDI_CHANNEL(channel)] = value; midi_write(3, MIDI_PORT(channel), (byte) (MIDI_BEND | MIDI_CHANNEL(channel)), (byte) MIDI_DATA(value), (byte) MIDI_DATA(value >> 7)); } /**************************************************************************** * midi_buffer * Inputs: * byte * buffer: the buffer address * int size: number of bytes in buffer * Returns: * FALSE if size is less than 16 or buffer is NULL, otherwise TRUE * Effect: DOS, MAC: * tells interrupt routine to store system exclusive messages in * buffer. The largest power of 2 bytes less than size will be * used. xbufhead and xbuftail will be initialized to zero, * and xbuftail will be one greater than the index of the last * system exclusive byte read. Since there may already be a buffer * and therefore the normal midi message buffer may have the first * 4 bytes of some sysex messages, clear the normal midi buffer too. * AMIGA: * adds buffer to midi interface * ****************************************************************************/ boolean midi_buffer(byte huge *buffer, ulong size) { if (!buffer) return FALSE; #ifdef AMIGA if (!SetSysExQueue(cmt_mi, (UBYTE *) buffer, (ULONG) size)) return(false); cu_register(remove_sysex_buffer, buffer); #endif #ifdef MACINTOSH_OR_DOS #ifndef WINDOWS { int mask = 0x000F; if (size < 16) return(false); while (mask < size && mask > 0) mask = ((mask << 1) | 1); midi_flush(); xbuff = NULL; /* turn off buffering */ xbufmask = mask >> 1; xbufhead = xbuftail = 0; xbuff = buffer; /* set buffer, turn on buffering */ } #endif #endif #ifdef UNIX return FALSE; #else exclusive(TRUE); return TRUE; #endif } /* midi_clock -- send a midi time clock message */ /**/ void midi_clock() { if (!initialized) fixup(); if (musictrace) gprintf(TRANS, "+"); midi_write(1, 0, MIDI_TIME_CLOCK, 0, 0); } /**************************************************************************** * midi_cont * Inputs: * boolean onflag: TRUE or FALSE * Effect: * enables (true) or disables (false) continuous control ****************************************************************************/ void midi_cont(boolean onflag) { if (!initialized) fixup(); if (onflag) { #ifdef AMIGA SetMidiFilters(cmt_mi, cmt_mi->PortFilter, cmt_mi->TypeFilter | CONTCONT, cmt_mi->ChanFilter); #endif #ifdef DOS #ifndef WINDOWS mPutCmd(BENDERON); #endif #endif } else { #ifdef AMIGA SetMidiFilters(cmt_mi, cmt_mi->PortFilter, cmt_mi->TypeFilter & ~CONTCONT, cmt_mi->ChanFilter); #endif } #ifdef MACINTOSH_OR_DOS ctrlFilter = !onflag; #endif if (musictrace) gprintf(TRANS,"midi_cont: %d\n", onflag); } /**************************************************************************** * midi_ctrl * Inputs: * int channel: midi channel on which to send data * int control: control number * int value: control value * Effect: * Sends a midi control change message ****************************************************************************/ void midi_ctrl(int channel, int control, int value) { if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"midi_ctrl: ch %d, ctrl %d, val %d\n", channel, control, value); midi_write(3, MIDI_PORT(channel), (byte) (MIDI_CTRL | MIDI_CHANNEL(channel)), (byte) MIDI_DATA(control), (byte) MIDI_DATA(value)); } /**************************************************************************** * midi_exclusive * Inputs: * byte *msg: pointer to a midi exclusive message, terminated by 0xF7 * Effect: * Sends a midi exclusive message * Bugs: * 18-mar-94 PLu : This function does not know which port to send to in * case of multiple midi-ports (MAC, IRIX) ****************************************************************************/ #ifdef MACINTOSH #define INTERBYTE_DELAY 10 #endif void midi_exclusive(msg) unsigned char *msg; /* the data to be sent */ { #ifdef ITC int count, done, tosend, willsend; unsigned char *m; mi_status ret; #endif #ifdef UNIX_IRIX_MIDIFNS unsigned char *m; MDevent mdevent; #endif #ifdef MACINTOSH #ifndef NYQUIST int i; /* for DX7 delay loop */ int count = 0; /* counter for formatting midi byte trace */ MIDIPacket TheMIDIPacket; unsigned char prev = 0; boolean first_packet = TRUE; #endif #endif /* * if user mistakenly called midi_exclusive instead of exclusive, * the argument will be TRUE or FALSE, both of which are highly * unlikely valid arguments for midi_exclusive: */ if (msg == (byte *) FALSE || msg == (byte *) TRUE) { gprintf(ERROR,"midi_exclusive: invalid argument %u.\n", msg); EXIT(1); } if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"midi_exclusive\n"); #ifdef AMIGA PutSysEx(cmt_mi, msg); #endif #ifdef MACINTOSH #ifndef NYQUIST /* if NYQUIST, do nothing */ #ifdef MIDIMGR while (prev != MIDI_EOX) { int len = 0; while (prev != MIDI_EOX && len < 249) { TheMIDIPacket.data[len++] = prev = *msg++; } TheMIDIPacket.len = 6 + len; TheMIDIPacket.tStamp = 0; if (first_packet && (prev != MIDI_EOX)) { TheMIDIPacket.flags = midiTimeStampCurrent + midiStartCont; first_packet = FALSE; } else if (first_packet) { TheMIDIPacket.flags = midiTimeStampCurrent + midiNoCont; } else if (prev == MIDI_EOX) { TheMIDIPacket.flags = midiTimeStampCurrent + midiEndCont; } else { TheMIDIPacket.flags = midiTimeStampCurrent + midiMidCont; } MIDIWritePacket(OutputRefNum, &TheMIDIPacket); } #else while (*msg != MIDI_EOX) { Xmit(0, *msg); msg++; count++; /* this is a delay loop, without which your DX7 will crash */ for (i = INTERBYTE_DELAY; i > 0; i--) abort_check(); } Xmit(0, MIDI_EOX); #endif /* MIDIMGR */ #endif /* NYQUIST */ #endif /* MACINTOSH */ #ifdef DOS #ifndef WINDOWS do { mPutData(*msg); } while (*msg++ != MIDI_EOX); #endif #endif #ifdef ITC for (m = msg, tosend = 1; (*m) != MIDI_EOX; m++, tosend++); for (count = 0; count < tosend; count += done) { willsend = min(16384, tosend); ret = mi_exclusive(midiconn, 1, msg, (short) willsend); if (ret != MI_SUCCESS) { gprintf(GWARN, "Got %d from mi_exclusive\n", ret); } done = willsend; } #endif #ifdef UNIX_IRIX_MIDIFNS /* we don't know which device to sent SYSEX messages to so port zero is assumed. */ for (m = msg, mdevent.msglen = 1; (*m) != CMT_MIDI_EOX; m++, mdevent.msglen++); mdevent.sysexmsg = msg; if (mdSend(miport, &mdevent, 1) == -1) { gprintf(GWARN, "could not send SYSEX message\n"); } #endif if (miditrace) { do { gprintf(TRANS, "~%2x", *msg); #ifdef UNIX_IRIX_MIDIFNS } while (*msg++ != CMT_MIDI_EOX); #else } while (*msg++ != MIDI_EOX); #endif } } /**************************************************************************** * midi_note * Inputs: * int channel: midi channel on which to send data * int pitch: midi pitch code * int velocity: velocity with which to sound it (0=> release) * Effect: * Sends a midi note-play request out ****************************************************************************/ void midi_note(int channel, int pitch, int velocity) { if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"midi_note: ch %d, key %d, vel %d\n", channel, pitch, velocity); if (user_scale) { /* check for correct pitch bend */ if ((pit_tab[pitch].pbend != bend[MIDI_CHANNEL(channel)]) && (velocity != 0)) { midi_bend(channel, pit_tab[pitch].pbend); bend[channel] = pit_tab[pitch].pbend; } pitch = pit_tab[pitch].ppitch; } midi_write(3, MIDI_PORT(channel), (byte) (MIDI_ON_NOTE | MIDI_CHANNEL(channel)), (byte) MIDI_DATA(pitch), (byte) MIDI_DATA(velocity)); } /**************************************************************************** * midi_program * Inputs: * int channel: Channel on which to send midi program change request * int program: Program number to send (decremented by 1 before * being sent as midi data) * Effect: * Sends a program change request out the channel ****************************************************************************/ void midi_program(int channel, int program) { #ifdef MACINTOSH int port, midi_chan; #endif if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"midi_program: ch %d, prog %d\n", channel, program); channel = MIDI_CHANNEL(channel); if (cur_midi_prgm[channel] != program) { midi_write(2, MIDI_PORT(channel), (byte) (MIDI_CH_PROGRAM | channel), (byte) (MIDI_PROGRAM(program)), 0); cur_midi_prgm[channel] = program; } } /**************************************************************************** * midi_real * Inputs: * boolean onflag: TRUE or FALSE * Effect: * enables (true) or disables (false) midi realtime messages F8-FF ****************************************************************************/ void midi_real(boolean onflag) { if (!initialized) fixup(); #ifdef UNIX_ITC { mi_status ret; ret = mi_realtime(midiconn, onflag); if (ret != MI_SUCCESS) { gprintf(ERROR, "Warning: bad ret = %d in midi_real\n", ret); } } #endif /* UNIX_ITC */ #ifdef ITC ignore_realtime = !onflag; #endif /* ITC */ #ifdef AMIGA if (onflag) { SetMidiFilters(cmt_mi, cmt_mi->PortFilter, cmt_mi->TypeFilter | CMF_RealTime, cmt_mi->ChanFilter); } else { SetMidiFilters(cmt_mi, cmt_mi->PortFilter, cmt_mi->TypeFilter & ~CMF_RealTime, cmt_mi->ChanFilter); } #endif #ifdef MACINTOSH_OR_DOS realFilter = !onflag; #endif if (musictrace) gprintf(TRANS,"midi_real: %d\n", onflag); } /* midi_start -- send a midi start message */ /**/ void midi_start() { if (!initialized) fixup(); if (musictrace) gprintf(TRANS, "`"); midi_write(1, 0, MIDI_START, 0, 0); } /* midi_stop -- send a midi stop message */ /**/ void midi_stop() { if (!initialized) fixup(); if (musictrace) gprintf(TRANS, "'"); midi_write(1, 0 /* ignored */, MIDI_STOP, 0, 0); } /**************************************************************************** * midi_thru * Inputs: * boolean onflag: TRUE or FALSE * Effect: * DOS: enables (true) or disables (false) midi thru info from * MPU-401 to host. (Default is set; reset with cmdline -block.) * AMIGA: enables (true) or disables (false) midi route from AMIGA * midi input to AMIGA midi output. ****************************************************************************/ void midi_thru(boolean onflag) /* DMH: midi thru is not supported on the MAC or DOS */ { if (!initialized) fixup(); #ifndef MIDI_THRU gprintf(ERROR, "midi_thru called but not implemented\n"); #else #ifdef AMIGA MidiThru(0L, (long) onflag); #endif #ifdef MACINTOSH /* this currently does not do anything - Mac driver doesn't * support THRU */ do_midi_thru = onflag; #endif #endif if (musictrace) gprintf(TRANS,"midi_thru: %d\n", onflag); } /**************************************************************************** * midi_touch * Inputs: * int channel: midi channel on which to send data * int value: control value * Effect: * Sends a midi after touch message ****************************************************************************/ void midi_touch(int channel, int value) { if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"midi_touch: ch %d, val %d\n",channel,value); midi_write(2, MIDI_PORT(channel), (byte) (MIDI_TOUCH | MIDI_CHANNEL(channel)), (byte) MIDI_DATA(value), 0); } /**************************************************************************** * midi_write * Inputs: * UBYTE n: number of characters to send (1, 2 or 3); int port: the port number (usually 0), on MAC, this may be 1 * char c1,c2,c3: Character(s) to write to MIDI data port * Effect: * Writes the data to the serial interface designated by port **************************************************************************** * Change log * Date | Change *-----------+---------------------------------------------------------------- * 15-Mar-94 | PLu : Added IRIX version ****************************************************************************/ #ifdef UNIX #ifdef UNIX_IRIX_MIDIFNS void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { MDevent event; if (port < 0) return; * ((u_long *) event.msg) = 0xe0000000 | ((port & 0x1f) << 24) | (c1 << 16) | (c2 << 8) | c3; if (mdSend(miport, &event, 1) == -1) gprintf(ERROR, "Can not send midi message in midi_write"); midi_write_trace(n, port, c1, c2, c3); } #else #ifdef ITC void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { unsigned char outb[3]; mi_channel mch; mi_status ret; if (port < 0) return; outb[0] = c1; outb[1] = c2; outb[2] = c3; mch = (16*port)+((int)MI_CHANNEL(c1)); ret = mi_put(midiconn, mch, outb); if (ret != MI_SUCCESS) gprintf(ERROR, "Warning: bad ret = %d in midi_write\n", (int)ret); midi_write_trace(n, port, c1, c2, c3); } #else void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { /* no output */ midi_write_trace(n, port, c1, c2, c3); } #endif /* ITC */ #endif /* UNIX_IRIX */ #endif /* UNIX */ #ifdef DOS #ifndef WINDOWS void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { if (n >= 1) mPutData(c1); if (n >= 2) mPutData(c2); if (n >= 3) mPutData(c3); midi_write_trace(n, port, c1, c2, c3); } #else void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { midi_write_trace(n, port, c1, c2, c3); } #endif #endif #ifdef MACINTOSH #ifdef MIDIMGR void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { MIDIPacket TheMIDIPacket; TheMIDIPacket.flags = midiTimeStampCurrent; TheMIDIPacket.len = 6 + n; TheMIDIPacket.tStamp = 0; TheMIDIPacket.data[0] = c1; TheMIDIPacket.data[1] = c2; TheMIDIPacket.data[2] = c3; MIDIWritePacket(OutputRefNum, &TheMIDIPacket); midi_write_trace(n, port, c1, c2, c3); } #else void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { #ifndef NYQUIST Xmit(port, c1); if (n >= 2) Xmit(port, c2); if (n >= 3) Xmit(port, c3); #endif midi_write_trace(n, port, c1, c2, c3); } #endif #endif void midi_write_trace(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3) { if (miditrace) { /* to indicate bytes going out on port 1, put message in brackets * with the port number, e.g. [1:~90~3c~64] */ if (port > 0) gprintf(TRANS, "[%d:", port); if (n >= 1) gprintf(TRANS, "~%2x", c1); if (n >= 2) gprintf(TRANS, "~%2x", c2); if (n >= 3) gprintf(TRANS, "~%2x", c3); if (port > 0) gprintf(TRANS, "]", port); } } /***************************************************************** * set_pitch_default *****************************************************************/ private void set_pitch_default() { int i; for (i = 0; i < 128; i++) { pit_tab[i].pbend = 8192; pit_tab[i].ppitch = i; } } /***************************************************************** * read_tuning *****************************************************************/ void read_tuning(filename) char *filename; { int index, pit, lineno = 0; float bend; FILE *fpp; user_scale = TRUE; set_pitch_default(); fpp = fileopen(filename, "tun", "r", "Tuning definition file"); while ((fscanf(fpp, "%d %d %f\n", &index, &pit, &bend) > 2) && (lineno < 128)) { lineno++; if (index >= 0 && index <= 127) { pit_tab[index].pbend = (int)(8192 * bend/100 + 8192); pit_tab[index].ppitch = pit; } } } /**************************************************************************** * musicinit * Effect: ****************************************************************************/ void musicinit() { int i; char *filename; if (!tune_flag) { /* do this code only once */ miditrace = cl_switch("miditrace"); musictrace = cl_switch("trace"); } if (!initialized) { cu_register((cu_fn_type) musicterm, NULL); midi_init(); } initialized = TRUE; /* this does some random cleanup activity */ #ifndef APPLICATION if (!tune_flag) { /* do this code only once */ #ifdef DOS #ifndef WINDOWS #if 0 version = mPutGetCmd(GETMPUVER); revision = mPutGetCmd(GETMPUREV); gprintf(TRANS, "MPU version %d.%d%c\n", version >> 4, version & 0x0f, revision + 'A' - 1); #endif mPutCmd(UARTMODE); mPutCmd(NOREALTIME); /* initially prevent Real Time MIDI info */ mPutCmd(EXCLUSIVOFF); /* initially prevent Sys-Ex data */ #endif #endif tune_flag = TRUE; filename = cl_option("tune"); if (filename != NULL) read_tuning(filename); } /* now that flags are set, print the trace message */ if (musictrace) gprintf(TRANS, "musicinit()\n"); if (user_scale) { for (i = 0; i < MAX_CHANNELS; i++) { midi_bend(i, 8192); bend[i] = 8192; } } #endif /* ifndef APPLICATION */ for (i = 0; i < MAX_CHANNELS; i++) { /* initialize to impossible values so that the * next call to midi_bend or midi_program will * not match and therefore send an output: */ bend[i] = -1; cur_midi_prgm[i] = -1; } #ifdef MIDI_THRU midi_thru(!(cl_switch("block"))); /* set MIDI thru */ #endif timereset(); /* Reset clock */ #ifdef AMIGA event_mask |= (1L << ascii_signal()) | (1L << cmt_mi->AlarmSigBit) | (1L << cmt_mi->RecvSigBit); #endif } /**************************************************************************** * musicterm * Effect: * Miscellaneous cleanup of things done by musicinit. ****************************************************************************/ private void musicterm() { if (musictrace) gprintf(TRANS, "musicterm()\n"); initialized = FALSE; } /**************************************************************************** * cmtrand * Inputs: * int lo: Lower limit of value * int hi: Upper limit of value * Result: int * random number (lo <= result <= hi) ****************************************************************************/ long randseed = 1534781L; short cmtrand(short lo, short hi) { randseed *= 13L; randseed += 1874351L; return((short)(lo + (((hi + 1 - lo) * ((0x00ffff00 & randseed) >> 8)) >> 16))); } #ifdef AMIGA /* remove_sysex_buffer -- a cleanup procedure for the Amiga */ /**/ void remove_sysex_buffer(void *obj) { ClearSysExQueue(cmt_mi); } #endif /* AMIGA */ /**************************************************************************** * settime * Inputs: new time * Effect: * Sets the current time to the new time. * DMH: for MAC, sets the clock to absTime * implemented by adjusting ticksATStart ****************************************************************************/ void settime(newtime) time_type newtime; { if (musictrace) gprintf(TRANS, "settime(%lu)\n", newtime); #ifdef AMIGA timeoffset = *camdtime - (newtime >> 1); #endif #ifdef MACINTOSH #ifdef MIDIMGR ticksAtStart = MIDIGetCurTime(OutputRefNum); #else ticksAtStart = TickCount() - MS_TO_TICKS(newtime); #endif #endif } /**************************************************************************** * timereset * Effect: * Resets the time. * DMH: for MAC, implemented by setting ticksAtStart to * current value of system tick counter * JMN: for DOS, resets the time on the MPU-401. Ticks is reset to 0 ****************************************************************************/ void timereset() { #if HAS_GETTIMEOFDAY struct timeval timeval; #endif #if HAS_FTIME struct timeb ftime_res; #endif if (!initialized) fixup(); if (musictrace) gprintf(TRANS,"timereset()\n"); #ifdef AMIGA timeoffset = *camdtime; #endif #ifdef DOS #ifndef WINDOWS timeoffset = (ulong) readtimer(); #endif #endif #ifdef MACINTOSH #ifdef MIDIMGR ticksAtStart = MIDIGetCurTime(OutputRefNum); #else ticksAtStart = TickCount(); #endif #endif #if HAS_GETTIMEOFDAY gettimeofday(&timeval, 0); timeoffset = timeval.tv_sec * 1000 + timeval.tv_usec / 1000 - timeoffset; #endif #if HAS_FTIME ftime(&ftime_res); timeoffset = ftime_res.time; #endif } /**************************************************************************** * trace * Inputs: * boolean flag: TRUE for trace on * Effect: * turns tracing on (flag == TRUE) or off (flag == FALSE) ****************************************************************************/ void trace(boolean flag) { musictrace = flag; } /**************************************************************************** * tracemidi * Inputs: * boolean flag: TRUE for trace on * Effect: * turns midi tracing on (flag == TRUE) or off (flag == FALSE) ****************************************************************************/ void tracemidi(boolean flag) { miditrace = flag; } /*********************************************************************** * * midi and timer initialization * ***********************************************************************/ #ifdef DOS /* binary value of hex char */ private int xval(int c) { int i; static char t[]="0123456789abcdef"; for (i=0; i<16; i++) if(tolower(c)==t[i]) return(i); return (-1); } /* binary value of hex string */ private int atox(char *t) { int i=0; int x; while(*t) { if ((x=xval(*t++))<0)return (0); i=(i<<4)+x; } return (i); } #endif /* def DOS */ private void midi_init() { #ifdef UNIX_IRIX_MIDIFNS #define PBUFLEN 4 MIconfig *config; static u_int pbuf[] = { MI_STAMPING, MINOSTAMP, MI_BLOCKING, MINONBLOCKING}; #endif #ifdef UNIX_MACH mach_midi_init(); #else #ifdef ITC midiconn = mi_open(NULL); if (midiconn == NULL) { gprintf(FATAL, "could not open a MIDI device\n"); EXIT(1); } cu_register((cu_fn_type) mi_close, (void *) midiconn); #endif #endif #ifdef AMIGA amiga_midi_init(); #endif /* def AMIGA */ #ifdef DOS #ifndef WINDOWS int err; int irq=SEARCHIRQ; int base=MPUBASEADDR; char *t; if (t=getenv("MPUIRQ")) { if (musictrace) gprintf(TRANS,"MPUIRQ %s\n",t); irq=atoi(t); } if (t=getenv("MPUBASE")) { if (musictrace) gprintf(TRANS,"MPUBASE %s\n",t); base=atox(t); } if(err = mOpen(base, irq)) { mClose(err); EXIT(1); } cu_register((cu_fn_type) mClose, 0); cu_register((cu_fn_type) mPutCmd, (cu_parm_type) MPURESET); initializetimer(); cu_register((cu_fn_type) restoretimer, NULL); #endif #endif #ifdef MACINTOSH #ifndef NYQUIST /* if NYQUIST, do nothing */ #ifdef MIDIMGR setup_midimgr(); /* this registers itself for cleanup */ #else init_abort_handler(); cu_register(cleanup_abort_handler, NULL); setupMIDI(portA, 0x80); cu_register(restoreMIDI, (long) portA); /* only initialize portB if necessary */ if (MAX_CHANNELS > CHANNELS_PER_PORT) { setupMIDI(portB, 0x80); cu_register(restoreMIDI, (long) portB); } #endif #endif /* NYQUIST */ #ifdef MIDIMGR ticksAtStart = MIDIGetCurTime(OutputRefNum); #else ticksAtStart = TickCount(); /* reset the clock */ #endif #endif /* def MACINTOSH */ if (!(cl_switch("noalloff"))) cu_register((cu_fn_type) alloff, NULL); } #ifdef DOS /**************************************************************************** * set_x_mfr * Inputs: * unsigned char mfr: Manufacturer ID for MIDI * Result: void * * Effect: * Sets the xcode and xcodemask to allow only these sysex messages ****************************************************************************/ void set_x_mfr(mfr) unsigned char mfr; { xcode = mfr; xcodemask = 0xFF; } /**************************************************************************** * clear_x_mfr * Result: void * * Effect: * Clears sysex manufacturer code filter; accepts all sysex messages ****************************************************************************/ void clear_x_mfr() { xcode = 0; xcodemask = 0; } #endif /* DOS */ nyquist-3.05/cmt/tempomap.c0000644000175000000620000000637210144436365014752 0ustar stevestaff/* tempomap.c -- used by midifile reader to record and lookup time maps */ /* * This module is designed to provide tempo change list insert and * lookup facilities. The exact interpretation of beat and tempo are * defined in one function, elapsed_time, which takes a tempo and a * number of beats, and returns time. */ #include "cext.h" #include "midifns.h" #include "timebase.h" #include "moxc.h" #include "seq.h" #include "tempomap.h" static time_type elapsed_time(); /* tempomap_create -- create a tempomap */ /**/ tempomap_type tempomap_create() { tempochange_type tempochange = tempochange_alloc(); tempomap_type tempomap = tempomap_alloc(); tempomap->hint = tempomap->entries = tempochange; tempochange->beat = 0L; /* default tempo is 120 (= 50000microsec/beat) and 24 divisions/quarter */ /* this may be overridden by a tempomap_insert */ tempochange->tempo = 500000L / 24; tempochange->rtime = 0L; tempochange->next = NULL; return tempomap; } /* tempomap_free -- deallocate storage for tempo map */ /**/ void tempomap_free(tm) tempomap_type tm; { while (tm->entries) { tempochange_type tc = tm->entries; tm->entries = tc->next; tempochange_free(tc); } memfree(tm, sizeof(tempomap_node)); } /* tempomap_insert -- insert a tempo change into the map */ /**/ void tempomap_insert(tempomap, beat, tempo) tempomap_type tempomap; long beat; /* beat division number */ long tempo; /* microseconds per beat division */ { tempochange_type tempochange = tempochange_alloc(); register tempochange_type prev; register tempochange_type next; tempochange->tempo = tempo; tempochange->beat = beat; if ((!(tempomap->hint->next)) || (tempomap->hint->beat > beat)) tempomap->hint = tempomap->entries; /* find the insert point */ for (prev = tempomap->hint; (next = prev->next) && (next->beat <= beat); prev = next); /* make the insert */ tempochange->next = next; prev->next = tempochange; tempomap->hint = prev; /* update the real time of each change */ for (tempochange = prev; tempochange->next; tempochange = tempochange->next) { tempochange->next->rtime = tempochange->rtime + elapsed_time(tempochange->tempo, tempochange->next->beat - tempochange->beat); } } /* tempomap_lookup -- convert beat to 4us time */ /* * The returned time is real time in units of 4us. */ time_type tempomap_lookup(tempomap, beat) tempomap_type tempomap; long beat; { register tempochange_type prev; register tempochange_type next; if ((!(tempomap->hint->next)) || (tempomap->hint->beat > beat)) tempomap->hint = tempomap->entries; /* find the last inflection point */ for (prev = tempomap->hint; (next = prev->next) && (next->beat <= beat); prev = next); /* interpolate */ return prev->rtime + elapsed_time(prev->tempo, beat - prev->beat); } /* elapsed_time -- compute the real elapsed time at a given tempo */ /* * the time returned is in units of 4us. */ static time_type elapsed_time(tempo, beat) long tempo; long beat; { return (time_type)((tempo * beat) >> 2); } nyquist-3.05/cmt/seqread.c0000644000175000000620000016266011466723256014565 0ustar stevestaff/**************************************************************************** seqread.c -- Phase 1 of adagio compilation... this module parses adagio programs and builds a linked list structure consisting of notes and control changes in time order. Copyright 1989 Carnegie Mellon University *****************************************************************************/ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 31-Dec-85 | Created changelog * 31-Dec-85 | Add c:\ to include directives * 31-Dec-85 | Added standard command scanner, metronome variable, need to add * | cmdline_help procedure * 31-Dec-85 | Call intr_init * 31-Dec-85 | Set musictrace from command line via -trace * 31-Dec-85 | Added -poll * 1-Jan-86 | Put error messages out to stderr * 1-Jan-86 | Set IsAT. Can be later overridden by -at and -xt switches, * | currently only used for diagnostics (may be needed for * | compatibles, who knows? In which case remove the tests which * | confirm the type of processor) * 1-Jan-86 | Removed dur-adjusted message * 1-Jan-86 | Added miditrace * 18-Jan-86 | Shortened durations by 1/200 s to avoid roundoff problems -- * | see buildnote for details. * 3-Mar-86 | Allow octave and accidentals in either order after pitch name. * | Default octave is now one that gets nearest previous pitch, * | the tritone (half an octave) interval is descending by default. * | Special commands handled by table search, !Rate command added * | to scale all times by a percentage (50 = half speed). * 9-Mar-86 | Use space to limit amount of storage allocation. Otherwise * | exhausting storage in phase1 caused phase2 to fail. * 12-Mar-86 | Broke off command line parser into adagio.c, only parser remains * 24-Mar-86 | Changed representation from note_struct to event_struct * | Parse M, N, O, X, and Y as control change commands * 23-May-86 | Added , and ; syntax: "," means "N0\n", ";" means "\n" * 16-Jul-86 | modify to only call toupper/lower with upper/lower case as * | parameter to be compatible with standard C functions * 7-Aug-86 | fixed bug with default pitches and rests * 5-Jul-87 | F.H: Introduced new memory handling from Mac version. * | Changed: init() * | ins_event() * | ins_ctrl() * | ins_note() * | Deleted: reverse() * | nalloc() * | Introduced: event_alloc() * | phase1_FreeMem() * | system.h & system.c dependencies * 10-Feb-88 | fixed parseend to accept blanks and tabs, * | fixed rate scaling of durations * 11-Jun-88 | commented out gprintf of \n to ERROR after parsing finished. * 13-Oct-88 | JCD : exclusive AMIGA version. * 13-Apr-89 | JCD : New portable version. * 31-Jan-90 | GWL : Cleaned up for LATTICE * 30-Jun-90 | RBD : further changes * 2-Apr-91 | JDW : further changes * 30-Jun-91 | RBD : parse '+' and '/' in durations, * after space is comment * 28-Apr-03 | DM : changes for portability *****************************************************************************/ #include "switches.h" #include #include #include "cext.h" #include "cmdline.h" #include "midifns.h" /* to get time_type */ #include "timebase.h" #include "moxc.h" /* to get debug declared */ #include "seq.h" #include "seqread.h" #include "userio.h" /* ctype.h used to be included only by UNIX and AMIGA, surely everyone wants this? */ #include "ctype.h" #ifndef toupper /* we're already taking precautions, so inline version of toupper is ok: */ #define toupper(c) ((c)-'a'+'A') /* CAUTION: AZTEC V5.0 defines an inline version of toupper called _toupper, but they got it wrong! */ #endif /* cmtcmd.h references amiga message ports */ #ifdef AMIGA #ifdef LATTICE #include "amiga.h" #endif #include "exec/exec.h" #endif #include "cmtcmd.h" /* public stuff */ extern long space; /* remaining free bytes */ extern int abort_flag; /**************************************************************************** The following are used to simulate fixed point with the radix point 8 bits from the right: ****************************************************************************/ #define precise(x) (((time_type) x) << 8) #define seqround(x) ((((time_type) x) + 128) >> 8) #define trunc(x) (((time_type) x) >> 8) #define nullstring(s) (s[0] == EOS) /**************************************************************************** * Routines local to this module: ****************************************************************************/ private void do_a_rest(); private time_type doabsdur(); private int doabspitch(); private void doclock(); private void docomment(); private void doctrl(); private void dodef(); private time_type dodur(); private void doerror(); private int doloud(); void domacro(); private void donextdur(); private int dopitch(); private void doprogram(); private void dorate(); private void doset(); private void dospecial(); private time_type dosymdur(); private void dotempo(); private void dotime(); private void dovoice(); private void fferror(); private void init(); private int issymbol(); private void marker(); private void parseend(); private void parsefield(); private boolean parsenote(); private boolean parseparm(); private int scan(); private int scan1(); private long scanint(); private void scansymb(); private long scansgnint(); /**************************************************************************** * data structures for parser lookup tables ****************************************************************************/ struct durt { /* duration translation table */ char symbol; time_type value; }; #define durtable_len 7 struct durt durtable[durtable_len] = { {'W', 4800L}, {'H', 2400L}, {'Q', 1200L}, {'I', 600L}, {'S', 300L}, {'%', 150L}, {'^', 75L} }; struct loudt { /* loudness translation table */ char symbol[4]; int value; }; struct loudt loudtable[] = { {"PPP", 20}, {"PP\0", 26}, {"P\0\0", 34}, {"MP\0", 44}, {"MF\0", 58}, {"F\0\0", 75}, {"FF\0", 98}, {"FFF", 127} }; char too_many_error[] = "Too many parameters"; private char *ssymbols[] = {"TEMPO", "RATE", "CSEC", "MSEC", "SETI", "SETV", "CALL", "RAMP", "CLOCK", "DEF", "END"}; #define sym_tempo 0 #define sym_rate 1 #define sym_csec 2 #define sym_msec 3 #define sym_seti 4 #define sym_setv 5 #define sym_call 6 #define sym_ramp 7 #define sym_clock 8 #define sym_def 9 #define sym_end 10 /* number of symbols */ #define sym_n 11 #define linesize 100 private char line[linesize]; /* the input line */ private char token[linesize]; /* a token scanned from the input line */ private boolean pitch_flag; /* set when a pitch is indicated */ /* (if controls changes are given, only allocate a note event if * a pitch was specified -- i.e. when pitch_flag is set) */ private boolean rest_flag; /* set when a rest (R) is found */ /* this flag is NOT inherited by the next line */ private boolean symbolic_dur_flag; /* TRUE if last dur was not absolute * (if this is set, then the default duration is changed * accordingly when the tempo is changed.) */ #define nctrl 8 private boolean ctrlflag[nctrl]; /* TRUE if control change was present * ctrlflag[0] TRUE if ANY control change * was present */ private int ctrlval[nctrl]; /* the new value of the control */ #define nmacroctrl 10 short macctrlx; /* index into the following: */ short macctrlnum[nmacroctrl]; /* macro ctrl number, e.g. for ~4(67), or * number of parameters for a symbolic macro */ short macctrlparmx[nmacroctrl]; /* ctrl value for ctrl change, or index of * parameters for symbolic macro */ short macctrlparms[nmacroctrl*nmacroparms]; /* parameters for symbolic macros */ short macctrlnextparm; def_type macctrldef[nmacroctrl]; /* definition for symbolic macro */ private time_type time_scale; /* 1000 if centisec, 100 if millisec */ /* note: user_specified_time * (time_scale / rate) = millisec */ /**************************************************************************** * * variables private to this module * ****************************************************************************/ private boolean end_flag = FALSE; /* set "true" when "!END" is seen */ /**************************************************************************** * state variables * Because each line of an Adagio score inherits properties from the previous * line, it makes sense to implement the parser as a collection of routines * that make small changes to some global state. For example, pitch is a * global variable. When the field G4 is encountered, the dopitch routine * assigns the pitch number for G4 to the variable pitch. After all fields * are processed, these variables describe the current note and contain the * default parameters for the next note as well. * * Global variables that are used in this way by the parsing rountines are: ****************************************************************************/ private int linex, /* index of the next character to be scanned */ lineno, /* current line number */ fieldx, /* index of the current character within a field */ pitch, /* pitch of note */ loud, /* loudness of note */ voice, /* voice (midi channel) of note */ artic; /* articulation (a percentage of duration) */ private boolean ndurp; /* set when a next (N) is indicated */ /* (next time defaults to the current time plus duration unless * overridden by a next (N) command whose presence is signalled * by ndurp.) */ private time_type thetime, /* the starting time of the note */ rate, /* time rate -- scales time and duration, default = 100 */ ntime, /* the starting time of the next note */ dur, /* the duration of the note */ tempo, /* the current tempo */ start, /* the reference time (time of last !tempo or !rate cmd) */ ticksize; /* set by !clock command, zero for no clock */ private int pitchtable[7] = { 69, 71, 60, 62, 64, 65, 67 }; extern char score_na[name_length]; private seq_type the_score; /* this is the score we are parsing */ /* def_append -- append a byte to the current definition */ /* * The def data structure: * [code][offset][code][offset]...[0][length][data][data][data]... * where code is 1:nmacroparms for %n, * nmacroparms+1 for %v, * nmacroparms+2:nmacroparms*2+1 for ^n * and offset is the byte offset (from the offset byte) to the data * where the parameter should be substituted * and length is the number of data bytes */ boolean def_append(def, nparms, data) unsigned char def[]; int nparms; int data; { int base = (nparms << 1) + 1; /* this byte is the length */ /* first parameter has to be able to reference last byte: */ if ((def[base])++ >= (254 - (nparms << 1))) { fferror("Data too long"); return FALSE; } def[base + def[base]] = data; return TRUE; } def_type def_lookup(symbol) char *symbol; { def_type defn = seq_dictionary(the_score); while (defn) { if (strcmp(defn->symbol, symbol) == 0) { return defn; } defn = defn->next; } return NULL; } void def_parm(def, nparms, code) unsigned char def[]; int nparms; int code; { int i, j; /* in order to insert a 2-byte parameter descriptor, the offsets from * previous descriptors (that precede the data) need to be increased by 2: */ for (i = 1; i < (nparms << 1); i += 2) { def[i] += 2; } /* now i is index of length; work backwards from the last byte, moving * everything up by 2 bytes to make room for the new descriptor: */ for (j = i + def[i] + 2; j > i; j--) { def[j] = def[j - 2]; } /* now i is index of offset; insert the descriptor code (first byte) * and the offset to the parameter location in the message (second byte) */ def[i - 1] = code; def[i] = def[i + 2] + 2; } /**************************************************************************** * do_a_rest * Effect: parses a rest (R) command ****************************************************************************/ private void do_a_rest() { if (token[fieldx]) fferror("Nothing expected after rest"); rest_flag = TRUE; } /**************************************************************************** * doabsdur * Effect: parses an absolute dur (U) command ****************************************************************************/ private time_type doabsdur() { time_type result=1000L; register char c; if (isdigit(token[fieldx])) { result = precise(scanint()); /* allow comma or paren for use in parameter lists */ if ((c = token[fieldx]) && (c != ',') && (c != ')') && (c != '+')) { fferror("U must be followed by digits only"); } if (time_scale == 1000) result *= 10; /* convert to ms */ } else fferror("No digit after U"); return result; } /**************************************************************************** * doabspitch * Effect: parses an absolute pitch (P) command ****************************************************************************/ private int doabspitch() { int result = 60; int startx = fieldx; register char c; int savex; if (isdigit (token[fieldx])) { result = (int) scanint(); /* allow comma or paren for abspitch in parameter */ if ((c = token[fieldx]) && c != ',' && c != ')') fferror("P must be followed by digits only"); else if (result < minpitch) { savex = fieldx; fieldx = startx; fferror("Minimum pitch of 0 will be used"); result = minpitch; fieldx = savex; } else if (result > maxpitch) { savex = fieldx; fieldx = startx; fferror("Maximum pitch of 127 will be used"); result = maxpitch; fieldx = savex; } } else fferror("No digits after P"); return result; } /* doartic -- compute an articulation factor */ /* NOTE: artic is a percentage that scales the duration of notes but not the time to the next note onset. It is applied to the final computed duration after all other scaling is applied. */ private void doartic() { if (isdigit(token[fieldx])) { artic = (int) scanint(); if (token[fieldx]) fferror("Only digits were expected here"); } else fferror("No digits after /"); } /* docall -- parse a call in the form !CALL fn(p1,p2,p3) */ /**/ private void docall() { boolean error_flag = TRUE; ndurp = FALSE; linex += scan(); if (token[0] == 0) fferror("Function name expected"); else { char symbol[100]; struct symb_descr *desc; long value[SEQ_MAX_PARMS]; int i=0; scansymb(symbol); if (fieldx == 1) fferror("Routine name expected"); else if (token[fieldx] != '(') fferror("Open paren expected"); else { desc = &HASHENTRY(lookup(symbol)); if (!desc->symb_type) { fieldx = 0; fferror("Function not defined"); } else if (desc->symb_type != fn_symb_type) { fieldx = 0; gprintf(TRANS, "desc->symb_type is %d\n", desc->symb_type); fferror("This is not a function"); } else { error_flag = FALSE; fieldx++; /* skip over paren */ for (i = 0; i < SEQ_MAX_PARMS; i++) value[i] = 0; i = 0; /* note that no params "()" is legal */ while (i < SEQ_MAX_PARMS && token[fieldx] != ')' && parseparm(&value[i])) { i++; if (token[fieldx] == ',') { fieldx++; } else if (token[fieldx] != ')') { fferror("Unexpected character"); error_flag = TRUE; break; } } fieldx++; if (i > SEQ_MAX_PARMS) fferror("Too many parameters"); } while (TRUE) { linex += scan(); if (nullstring(token)) { break; } switch (token[0]) { case 'T': fieldx = 1; dotime(); break; case 'V': fieldx = 1; dovoice(); break; case 'N': fieldx = 1; donextdur(); break; default: fferror("Unexpected character"); } } if (!error_flag) insert_call(the_score, seqround(thetime), lineno, voice, desc->ptr.routine, value, i); /* advance the time only if an N field was given */ if (ndurp) thetime += ntime; } } } /* doclock -- insert a clock command */ /* * derivation: if there is no previous clock running, then start the * clock on time. Otherwise, start the clock half a tick early. * ticksize = (beattime / 24) = ((60sec/tempo)/24) = * ((60000ms/tempo)/24) = (60000/24)/tempo = 2500/tempo */ private void doclock() { int oldticksize = ticksize; ticksize = (2500L << 16) / tempo; insert_clock(the_score, seqround(thetime) - (oldticksize >> 17), lineno, ticksize); } /**************************************************************************** * docomment * Effect: parses a comment (*) command ****************************************************************************/ private void docomment() { line[linex] = '\n'; /* force end of line to skip comment line */ line[linex+1] = EOS; } /**************************************************************************** * doctrl * Inputs: * n: control number * Effect: parses a control (K, M, O, X, or Y) command ****************************************************************************/ private void doctrl(n) int n; { ctrlval[n] = (int) scanint(); if (token[fieldx]) { fferror("Only digits expected here"); } else { ctrlflag[n] = TRUE; ctrlflag[0] = TRUE; /* ctrlflag[0] set if any flag is set */ } } private void dodef() { /* maximum def size is 256 + 9 parms * 2 + 2 = 276 */ unsigned char def[280]; char symbol[100]; int nparms = 0; int nibcount = 0; int data = 0; register char c; linex += scan(); if (!token[0]) fferror("Symbol expected"); else { strcpy(symbol, token); def[0] = def[1] = 0; while (TRUE) { linex += scan1(&line[linex]); c = token[0]; if (!c) { linex--; if (nibcount & 1) { fferror("Expected pairs of hex digits: one missing"); return; } break; } else if (c == ' ' || c == '\t' || c == '\n') continue; else if (isdigit(c)) { data = (data << 4) + (c - '0'); nibcount++; if (!(nibcount & 1)) { if (!def_append(def, nparms, data)) return; data = 0; } } else if ('A' <= c && c <= 'F') { data = (data << 4) + (c - 'A') + 10; nibcount++; if (!(nibcount & 1)) { if (!def_append(def, nparms, data)) return; data = 0; } } else if (c == 'V') { data = data << 4; nibcount++; /* v without a leading nibble is equivalent to 0v: */ if (nibcount & 1) nibcount++; if (!def_append(def, nparms, data)) return; def_parm(def, nparms++, nmacroparms+1); } else if (c == '%') { linex += scan1(&line[linex]); c = token[0]; if (c < '1' || c > ('0' + nmacroparms)) { fferror(parm_expected_error); break; } if (!def_append(def, nparms, 0)) return; def_parm(def, nparms++, c - '0'); } else if (c == '^') { linex += scan1(&line[linex]); c = token[0]; if (c < '1' || c > ('0' + nmacroparms)) { fferror(parm_expected_error); break; } if (!def_append(def, nparms, 0)) return; def_parm(def, nparms++, (c - '0') + nmacroparms + 1); } else { /* something unexpected here -- just exit */ linex--; fferror("Unexpected data"); return; } } insert_def(the_score, symbol, def, (nparms << 1) + def[(nparms << 1) + 1] + 2); } } /**************************************************************************** * dodur * Effect: parses a duration (sum of dosymdur and/or doabsdur) * sets symbolic_dur_flag (according to the first addend in mixed arithmetic) * * Returns: duration in "precise" units ****************************************************************************/ private time_type dodur() { time_type result = 0L; symbolic_dur_flag = TRUE; if (token[fieldx-1] == 'U') { result = doabsdur(); symbolic_dur_flag = FALSE; } else result = dosymdur(); while (token[fieldx] == '+') { fieldx += 2; if (token[fieldx-1] == 'U') result += doabsdur(); else result += dosymdur(); } return scale(result, 100L, rate); } /**************************************************************************** * doerror * Effect: parse an unrecognized field by reporting an error ****************************************************************************/ private void doerror() { fieldx = 0; fferror("Bad field"); } /**************************************************************************** * doloud * Effect: parse a loudness (L) command ****************************************************************************/ private int doloud() { int i, j; int result; int oldfieldx = fieldx; int newfieldx; char symbol[100]; if (!token[fieldx] || token[fieldx]==')' || token[fieldx]==',') { fferror("L must be followed by loudness indication"); return 100; } if (isdigit(token[fieldx])) { result = (int) scanint(); newfieldx = fieldx; if (token[fieldx] && token[fieldx]!=')' && token[fieldx]!=',') fferror("Digits expected after L"); else if (result > 127) { fieldx = oldfieldx; fferror("Maximum loudness of 127 will be used"); fieldx = newfieldx; result = 127; } else if (result == 0) { fieldx = oldfieldx; fferror("Minimum loudness of 1 will be used"); fieldx = newfieldx; result = 1; } return result; } scansymb(symbol); newfieldx = fieldx; if ((i = strlen(symbol)) > 3 ) { /* maximum is 3, e.g. "ppp" */ fieldx = oldfieldx; fferror("Loudness field too long"); fieldx = newfieldx; return 100; } symbol[i + 1] = '\0'; /* pad short symbols with 0 */ /* e.g. "p\0" -> "p\0\0" */ for (i = 0; i <= 7; i++) { /* loop through possibilities */ for (j = 0; j <= 2; j++) { /* test 3 characters */ if (symbol[j] != loudtable[i].symbol[j]) break; } if (j == 3) { return loudtable[i].value; } } fieldx = oldfieldx; fferror("Bad loudness indication"); fieldx = newfieldx; return 100; } void domacro() { int control_num; int value; if (isdigit(token[1])) { control_num = (int) scanint(); if (token[fieldx] == '(') { fieldx++; if (!isdigit(token[fieldx])) { fferror("Control value expected"); } else { value = (int) scanint(); if (token[fieldx] != ')') { fferror("Missing close paren"); } else { fieldx++; if (token[fieldx]) fferror("Nothing expected after paren"); else if (macctrlx < nmacroctrl - 1) { macctrlnum[macctrlx] = control_num; macctrlparmx[macctrlx] = value; macctrldef[macctrlx] = NULL; macctrlx++; } else fferror("Too many controls"); } } } else fferror("Missing paren"); } else { def_type def; char symbol[100]; scansymb(symbol); if (fieldx == 1) fferror("Macro name expected"); else if (token[fieldx] != '(') fferror("Open paren expected"); else { fieldx++; def = def_lookup(symbol); if (!def) { fieldx = 1; fferror("Undefined macro"); } else { long val; macctrlnum[macctrlx] = 0; macctrlparmx[macctrlx] = macctrlnextparm; macctrldef[macctrlx] = def; while (token[fieldx] != ')' && parseparm(&val)) { macctrlparms[macctrlnextparm++] = (short) val; macctrlnum[macctrlx]++; if (token[fieldx] == ',') { fieldx++; } else if (token[fieldx] != ')') { fferror("Unexpected character"); break; } } fieldx++; macctrlx++; } } } } /**************************************************************************** * donextdur * Effect: parse a next (N) command * Implementation: * The syntax is N followed by a duration, so save dur and use dosymdur() * to parse the duration field. * The form N is parsed directly with scanint(). ****************************************************************************/ private void donextdur() { ndurp = TRUE; /* flag that N was given */ if (isdigit(token[fieldx])) { ntime = precise(scanint()); ntime = scale(ntime, (ulong)time_scale, rate); if (token[fieldx]) fferror("Only digits were expected here"); } else { fieldx++; ntime = dodur(); } } /**************************************************************************** * dopitch * Effect: parses a pitch command ****************************************************************************/ private int dopitch() { int p, octave=0; int octflag = FALSE; /* set if octave is specified */ int oldfieldx = fieldx; p = pitchtable[token[fieldx-1]-'A']; while (TRUE) { if (token[fieldx] == 'S') { /* sharp */ p++; fieldx++; } else if (token[fieldx] == 'N') { /* skip */ fieldx++; } else if (token[fieldx] == 'F') { /* flat */ p--; fieldx++; } else if (isdigit(token[fieldx]) && !octflag) { /* octave */ octave = (int) scanint(); octflag = TRUE; } else break; /* none of the above */ } if (octflag) p = (p-48) + 12 * octave; /* adjust p to given octave */ else { /* adjust p to note nearest the default pitch */ int octdiff = (p + 126 - pitch) / 12; p = p + 120 - (octdiff * 12); } if (p > maxpitch) { /* pitch in range? */ int newfield = fieldx; fieldx = oldfieldx; fferror("Pitch too high"); fieldx = newfield; p = maxpitch; } /* We really should test for end-of-field, but we don't know if we're in a parameter list, so comma may or may not be legal */ return p; } /**************************************************************************** * doprogram * Effect: parses a program change (Z) command ****************************************************************************/ private void doprogram() { register int program = (int) scanint(); ctrlflag[PROGRAM_CTRL] = ctrlflag[0] = TRUE; if (token[fieldx]) { fferror("Z must be followed by digits only"); } else if (program < minprogram) { fieldx = 1; fferror("Minimum program of 1 will be used"); program = minprogram; } else if (program > maxprogram) { fieldx = 1; fferror("Maximum program of 128 will be used"); program = maxprogram; } ctrlval[PROGRAM_CTRL] = program - 1; } private void doramp() { int values[2]; time_type stepsize = 100L; /* default 10 per second */ int index = 0; ndurp = FALSE; values[0] = values[1] = 0; while (TRUE) { linex += scan(); fieldx = 1; if (nullstring(token)) { break; } else if (index == 2) { /* must be stepsize in dur syntax */ stepsize = dodur(); } else { int ctrlx = 0; static int ctrl_map[] = { -BEND_CTRL, VOLUME, -TOUCH_CTRL, MODWHEEL }; switch (token[0]) { case 'M': ctrlx++; /* modwheel */ case 'O': ctrlx++; /* aftertouch */ case 'X': ctrlx++; /* volume */ case 'Y': /* pitch bend */ if (index < 2) { macctrlnum[index] = ctrl_map[ctrlx]; macctrlparmx[index] = (int) scanint(); if (token[fieldx]) fferror("Only digits expected here"); macctrldef[index] = NULL; } else fferror("Unexpected control"); break; case '~': if (index < 2) { domacro(); if (token[fieldx]) fferror("Unexpected character"); } else fferror("Unexpected control"); break; case 'T': if (index < 2) fferror("Control expected"); dotime(); break; case 'V': if (index < 2) fferror("Control expected"); dovoice(); break; case 'N': if (index < 2) fferror("Control expected"); donextdur(); break; default: if (index < 2) fferror("Control expected"); dur = dodur(); break; } if (index == 1 && (macctrlnum[0] != macctrlnum[1] || macctrldef[0] != macctrldef[1])) { fferror("Controls do not match"); } } index++; } if (index < 3) fferror("Expected 2 controls and step size"); else { if (macctrldef[0]) { int i, j, n; n = 0; i = macctrlparmx[0]; j = macctrlparmx[1]; while (n < macctrlnum[0]) { if (macctrlparms[i] != macctrlparms[j]) break; n++; i++; j++; } if (n >= macctrlnum[0]) n = 0; /* Note: duration shortened to prevent overlap with next ramp */ insert_deframp(the_score, seqround(thetime), lineno, voice, seqround(stepsize), trunc(dur) - 1, macctrldef[0], macctrlnum[0], macctrlparms + macctrlparmx[0], n, macctrlparms[j]); } else { /* Note: duration shortened to prevent overlap with next ramp */ insert_ctrlramp(the_score, seqround(thetime), lineno, voice, seqround(stepsize), trunc(dur) - 1, macctrlnum[0], macctrlparmx[0], macctrlparmx[1]); } } /* advance the time only if an N field was given */ if (ndurp) thetime += ntime; else thetime += dur; } /**************************************************************************** * dorate * Effect: parses a !rate command ****************************************************************************/ private void dorate() { linex += scan(); if (!token[0]) fferror("rate number expected"); else { long oldrate = rate; rate = (int) scanint(); if (token[fieldx]) fferror("Only digits expected here"); if (rate == 0) { fieldx = 0; fferror("Rate 100 will be used here"); rate = 100L; } start = thetime; /* adjust dur in case it is inherited by next note */ dur = (dur * oldrate); dur = dur / rate; } } private void doset(vec_flag) boolean vec_flag; { ndurp = FALSE; linex += scan(); if (!token[0]) fferror("Variable name expected"); else { struct symb_descr *desc = &HASHENTRY(lookup(token)); if (!desc->symb_type) fferror("Called function not defined"); else if (vec_flag && (desc->symb_type != vec_symb_type)) { fferror("This is not an array"); } else if (!vec_flag && (desc->symb_type != var_symb_type)) { fferror("This is not a variable"); } else { int numargs = 1 + vec_flag; int value[2]; int i; int *address = desc->ptr.intptr; value[0] = value[1] = 0; i = 0; while (TRUE) { linex += scan(); if (nullstring(token)) { break; } else if (isdigit(token[0]) || token[0] == '-' || token[0] == '+') { if (i < numargs) { value[i++] = (int) scansgnint(); if (token[fieldx]) fferror("Only digits expected here"); } else fferror(too_many_error); } else { switch (token[0]) { case 'T': fieldx = 1; dotime(); break; case 'V': fieldx = 1; dovoice(); break; case 'N': fieldx = 1; donextdur(); break; default: fieldx++; if (i < numargs) { value[i++] = seqround(dodur()); } else fferror(too_many_error); break; } } } if (vec_flag && i != 2) fferror("No index given"); if (vec_flag) { if (value[0] >= desc->size) { fferror("Subscript out of bounds"); return; } /* reduce to the seti case: */ address += value[0]; /* compute the vector address */ value[0] = value[1]; /* set up value[] and i as if */ i--; /* this were seti, not setv */ } if (i != 1) fferror("No value given"); insert_seti(the_score, seqround(thetime), lineno, voice, address, value[0]); /* advance the time only if an N field was given */ if (ndurp) thetime += ntime; } } } /**************************************************************************** * dospecial * Effect: parses special (those starting with "!") commands ****************************************************************************/ private void dospecial() { switch (issymbol()) { case sym_tempo: dotempo(); break; case sym_rate: dorate(); break; case sym_csec: /* adjust dur for inheritance by next note */ dur = (dur * 1000L) / time_scale; time_scale = 1000L; break; case sym_msec: dur = (dur * 100L) / time_scale; time_scale = 100L; break; case sym_seti: doset(FALSE); break; case sym_setv: doset(TRUE); break; case sym_call: docall(); break; case sym_ramp: doramp(); break; case sym_clock: doclock(); break; case sym_def: dodef(); break; case sym_end: end_flag = TRUE; break; default: fferror("Special command expected"); } parseend(); /* flush the rest of the line */ } /**************************************************************************** * dosymdur * Effect: parses a duration (^, %, S, I, Q, H, or W) command ****************************************************************************/ private time_type dosymdur() { int i, dotcnt = 0; long dotfactor; time_type result = 0; for (i = 0; i < durtable_len; i++) { if (durtable[i].symbol == token[fieldx-1]) { /* the shift right is because durs are stored doubled because * otherwise a 64th note would have the value 75/2: */ result = precise(durtable[i].value) >> 1; break; } } if (i == durtable_len) { fieldx--; fferror("Duration expected: one of W, H, Q, I, S, %, or ^"); return 0L; } while (token[fieldx]) { if (token[fieldx] == 'T') { /* triplet notation */ result = (result * 2) / 3; /* lose a bit but avoid scale() */ fieldx++; } else if (token[fieldx] == '.') { /* dotted notation */ dotcnt++; fieldx++; } else if (token[fieldx] == '/') { long divisor; fieldx++; divisor = scanint(); if (divisor > 0) result = result / divisor; else fferror("non-zero integer expected"); } else if (isdigit(token[fieldx])) { /* numbers are multipliers */ result = result * scanint(); } else break; } dotfactor = 1L; for (i=1; i<=dotcnt; i++) dotfactor = dotfactor * 2; result = (2 * result) - (result / dotfactor); return scale(result, 100L, tempo); /* time in milliseconds */ } /**************************************************************************** * dotempo * Effect: parses a !tempo command ****************************************************************************/ private void dotempo() { linex += scan(); if (!token[0]) fferror("Tempo number expected"); else { long oldtempo = tempo; tempo = scanint(); if (token[fieldx]) fferror("Only digits expected here"); if (tempo == 0) { fieldx = 0; fferror("Tempo 100 will be used here"); tempo = 100L; } start = thetime; /* adjust dur in case it is inherited by next note */ if (symbolic_dur_flag) { dur = (dur * oldtempo); dur = dur / tempo; } } } /**************************************************************************** * dotime * Effect: parses a time (T) command * Implementation: see implementation of donextdur() ****************************************************************************/ private void dotime() { if (isdigit(token[fieldx])) { thetime = precise(scanint()); thetime = scale(thetime, (ulong)time_scale, rate); if (token[fieldx] ) fferror("Only digits were expected here"); } else { fieldx++; thetime = dodur(); } thetime += start; /* time is relative to start */ } /**************************************************************************** * dovoice * Effect: parse a voice (V) command (the voice is the MIDI channel) ****************************************************************************/ private void dovoice() { if (isdigit(token[fieldx])) { voice = (int) scanint(); if (token[fieldx]) fferror("V must be followed by digits only"); if (voice > MAX_CHANNELS) { char msg[40]; sprintf(msg, "number too high, using %d instead", MAX_CHANNELS); fferror(msg); voice = MAX_CHANNELS; } else if (voice < 1) { fferror("number too low, using 1 instead"); voice = 1; } } else fferror("No digit after V"); } /**************************************************************************** * fferror * Inputs: * char *s: an error message string * Effect: * prints the line with the error * puts a cursor (^) at the error location * prints the error message (s) * Implementation: * this routine prints a carat under the character that * was copied into token[fieldx]. E.g. if fieldx = 0, the * carat will point to the first character in the field. ****************************************************************************/ private void fferror(s) char *s; { gprintf(ERROR, "%3d | %s", lineno, line); marker(linex-strlen(token)+fieldx+1+6); gprintf(ERROR, "Error: %s.\n", s); } /**************************************************************************** * init * Effect: * initializes the state variables ****************************************************************************/ private void init() { int i; end_flag = FALSE; /* initial (default) values for all state variables */ symbolic_dur_flag = TRUE; /* default dur is symbolic */ for (i = 0; i < nctrl; i++) { /* no initial control changes */ ctrlflag[i] = FALSE; ctrlval[i] = 0; } lineno = 0; pitch = seq_dflt_pitch; loud = seq_dflt_loud; voice = seq_dflt_voice; time_scale = 1000L; tempo = 100L; rate = 100L; dur = precise(600); /* default dur is quarter note */ thetime = precise(0); start = thetime; ntime = 0L; ticksize = 0L; artic = 100; } /**************************************************************************** * ins_a_note * Returns: * boolean: TRUE on success, FALSE if not enough memory * Effect: * note events (if any) corresponding to the current line are inserted * Implementation: * if a note on should occur after a note off and doesn't, and the * two notes have the same pitch, then the note off can cancel the * note on. to make it unlikely that roundoff will cause this situation, * dur is decreased by one half of a clock tick before rounding. * also, phase2 gives precedence to note-offs that are simultaneous * with note-ons. ****************************************************************************/ private boolean ins_a_note() { long the_dur = (trunc(dur) * artic + 50) / 100; int the_pitch = pitch; event_type note; if (rest_flag) the_pitch = NO_PITCH; note = insert_note(the_score, seqround(thetime), lineno, voice, the_pitch, the_dur, loud); if (!note) return FALSE; return TRUE; /* success! */ } /**************************************************************************** * ins_ctrls * Returns: * boolean: TRUE on success, FALSE if not enough memory * Effect: * control events corresponding to current line are inserted in score * Implementation: * ctrlflag[i] is TRUE if control i was specified in this line, so * insert one control change for each ctrlflag[i] that is TRUE ****************************************************************************/ private boolean ins_ctrls() { int i; event_type ctrl; for (i = 1; i < nctrl; i++) { if (ctrlflag[i]) { ctrl = insert_ctrl(the_score, seqround(thetime), lineno, i, voice, ctrlval[i]); if (!ctrl) return FALSE; ctrlflag[i] = FALSE; ctrlval[i] = 0; } } return TRUE; /* success! */ } /**************************************************************************** * issymbol * Outputs: returns symbol number, or -1 if no match * Assumes: token[1] has the symbol to look up (token[0] == '!') ****************************************************************************/ private int issymbol() { int i, symb_num; char *sym; for (symb_num = 0; symb_num < sym_n; symb_num++) { sym = ssymbols[symb_num]; i = 1; while (TRUE) { if (token[i] != *sym) break; if (*sym == 0) return symb_num; sym++; i++; } } return -1; } /**************************************************************************** * marker * Inputs: * int count: the number of characters to indent * Effect: * prints a carat (^) at the position specified on file stderr ****************************************************************************/ private void marker(count) int count; { int i; char s[128]; for (i=0; i<(count-1); s[i++]=' ') /* */ ; s[count-1] = '^'; s[count] = '\0'; gprintf(ERROR,"%s\n",s); } /***************************************************************** * parseend * Effect: * parse the note terminator, either ",", ";", EOS or "\n" * ****************************************************************/ private void parseend() { boolean done = FALSE; while (!done) { linex += scan1(&line[linex]); switch (token[0]) { case ',': ndurp = TRUE; /* switch that next time was specified */ ntime = 0L; done = TRUE; break; case ';': case '\n': case EOS: done = TRUE; break; case ' ': case '\t': break; /* skip over blanks and scan1 again */ default: fferror("Unexpected token"); linex += scan(); /* flush the token */ break; } } } /**************************************************************************** * parsefield * Effect: looks at first character of token and calls a parsing routine * ****************************************************************************/ private void parsefield() { fieldx = 1; switch (token[0]) { case 'T' : dotime(); break; case 'U': case 'W': case 'H': case 'Q': case 'S': case 'I': case '%': case '^': dur = dodur(); break; case 'R': do_a_rest(); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': pitch = dopitch(); pitch_flag = TRUE; break; case 'P': pitch = doabspitch(); pitch_flag = TRUE; break; case 'L': loud = doloud(); break; case 'N': donextdur(); break; /* case 'J': * doctrl(1); * break; */ case 'K': doctrl(PSWITCH_CTRL); break; case 'M': doctrl(MODWHEEL_CTRL); break; case 'O': doctrl(TOUCH_CTRL); break; case 'X': doctrl(VOLUME_CTRL); break; case 'Y': doctrl(BEND_CTRL); break; case 'Z': doprogram(); break; case 'V': dovoice(); break; case '~': domacro(); break; case '*': docomment(); break; case '#': doartic(); break; default : doerror(); break; } } /**************************************************************************** * parsenote * Effect: * parses a note line -- control events (if any) and note event (if * present) are inserted into score * Assumes: * line contains a string to be parsed ****************************************************************************/ private boolean parsenote() { boolean out_of_memory = FALSE; int i; ndurp = FALSE; rest_flag = FALSE; /* this loop reads tokens for a note */ while (token[0]) { parsefield(); linex += scan(); } parseend(); /* take care of note terminator */ /* * insert ctrl's first so that will come before the note. */ if (ctrlflag[0]) { out_of_memory |= !ins_ctrls(); /* don't reset ctrlflag[0], it's used below */ } /* * insert macro's */ for (i = 0; i < macctrlx; i++) { event_type ctrl; if (macctrldef[i] == NULL) { ctrl = insert_macctrl(the_score, seqround(thetime), lineno, macctrlnum[i], voice, macctrlparmx[i]); } else { ctrl = insert_macro(the_score, seqround(thetime), lineno, macctrldef[i], voice, macctrlnum[i], &(macctrlparms[macctrlparmx[i]])); } out_of_memory |= (ctrl == NULL); } /* insert a note if * (1) a pitch was specified OR * (2) no control was specified and this is not a rest * (it's a pitch by default) * * NOTE: program changes during rests are advised since * synthesizers may not be able to process a program * change followed immediately by a note-on. In fact, this * is why we insert notes whose pitch is NO_PITCH -- so that * the program change can be processed during the rest. */ if (pitch_flag || (!ctrlflag[0] && !rest_flag && (macctrlx == 0))) { out_of_memory |= !ins_a_note(); } if (ndurp) thetime += ntime; else thetime += dur; return out_of_memory; } private boolean parseparm(valptr) long *valptr; { register char c = token[fieldx]; if (isdigit(c) || c == '-') { *valptr = scansgnint(); return TRUE; } else { switch (c) { case 'P': fieldx++; *valptr = doabspitch(); return TRUE; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': fieldx++; *valptr = dopitch(); return TRUE; case 'U': case 'W': case 'H': case 'Q': case 'I': case 'S': case '%': case '^': fieldx++; *valptr = seqround(dodur()); return TRUE; case 'L': fieldx++; *valptr = doloud(); return TRUE; case '\'': fieldx++; *valptr = token[fieldx]; fieldx++; if (token[fieldx] != '\'') { fferror("single quote expected"); } fieldx++; return TRUE; default: fferror("Parameter expected"); return FALSE; } } } /**************************************************************************** * scale * Inputs: * time_type x * int (ulong?) n, d * Outputs: * returns time_type: result of scaling x by n/d ****************************************************************************/ public time_type scale(x, n, d) ulong x; ulong n, d; { ulong lo = (x & 0xFFFFL) * n; ulong hi = (x >> 16) * n; ulong res = hi / d; lo = (((hi - (res * d)) << 16) + lo + (d >> 1)) / d; return (time_type)( (res << 16) + lo ); } /**************************************************************************** * scan * Inputs: * char *start: the string to scan * Outputs: * returns int: the index of the next char in start to scan * Effect: * skips over leading blanks * copies characters from start into token, converting to upper case * scanning stops on delimiter: one of space, tab, newline, semicolon ****************************************************************************/ private int scan() { char *start = line + linex; register char c; register int i = 0; register int j = 0; register int parens = 0; while (((c = start[i]) == ' ') || (c == '\t')) i++; while ((c = start[i]) != ' ' && c != '\n' && c != '\t' && c != EOS && (c != ',' || token[0] == '~' || parens > 0) && c != ';') { if (islower(start[i])) token[j] = toupper(start[i]); else token[j] = start[i]; if (c == '(') parens++; else if (c == ')') parens--; j++; i++; } token[j] = '\0'; fieldx = 0; if (parens) fferror("Unbalanced parens"); return i; } /**************************************************************************** * scan1 * Inputs: * char *start: the string to scan * Outputs: * returns int: the index of the next char in start to scan * Effect: * copies one char from start into token, converting to upper case ****************************************************************************/ private int scan1(start) char *start; { int i = 0; token[0] = *start; if (islower(token[0])) token[0] = toupper(token[0]); if (!nullstring(token)) { token[1] = '\0'; i = 1; } fieldx = 0; return i; } /**************************************************************************** * scanint * Outputs: * returns long: the scanned integer * Effect: * scans an unsigned long from token, starting at fieldx * fieldx is incremented to end of the integer ****************************************************************************/ private long scanint() { long i = 0; char c; while ((c = token[fieldx])) { if (isdigit(c)) { i = (i*10) + (c - '0'); fieldx++; } else return i; } return i; } private long scansgnint() { if (token[fieldx] == '-') { fieldx++; return -scanint(); } else { if (token[fieldx] == '+') { fieldx++; } return scanint(); } } /* scansymb -- scan a symbol from the token */ /**/ private void scansymb(str) char *str; { char c; while ((c = token[fieldx])) { if (isdigit(c) || isalpha(c) || c == '_') { *str++ = c; fieldx++; } else break; } *str = EOS; } /**************************************************************************** * seq_read * Inputs: * seq_type seq: the sequence to receive the score * FILE *fp: input file * Outputs: * none * Effect: * parses score from input file and builds score data structure ****************************************************************************/ void seq_read(seq, fp) seq_type seq; FILE *fp; { boolean out_of_memory = FALSE; /* set when no more memory */ /* printf("seq_read: chunklist is 0x%x\n", seq->chunklist); */ the_score = seq; /* current sequence is a global within this module */ if (!seq) return; init(); lineno = 0; /* make sure line is well terminated or scan might run off the end */ line[linesize - 1] = EOS; line[linesize - 2] = '\n'; /* this loop reads lines */ while ((fgets(line, linesize - 2, fp) != NULL) && !out_of_memory && !check_aborted() && !end_flag) { lineno++; linex = 0; /* this loop reads notes from a line */ while ((line[linex] != EOS) && !out_of_memory) { /* loop invariant: line[linex] is first char of next note */ ctrlflag[0] = FALSE; /* other ctrlflags are reset by ins_ctrls() */ macctrlx = 0; macctrlnextparm = 0; pitch_flag = FALSE; linex += scan(); if (!nullstring(token)) { if (token[0] == '*') docomment(); else if (token[0] == '!') dospecial(); else out_of_memory = parsenote(); } else parseend(); } } if (out_of_memory) { gprintf(ERROR, "Out of note memory at line %d,\n", lineno-1); gprintf(ERROR, " the rest of your file will be ignored.\n"); } if (check_aborted()) { gprintf(ERROR, "User aborted score input,\n"); gprintf(ERROR, " the rest of your file will be ignored.\n"); if (abort_flag == BREAK_LEVEL) abort_flag = 0; } /* fclose(fp); -- don't close the file; if you do, Nyquist's garbage collector will close Nyquist's copy, and closing the file twice in Linux will crash Nyquist */ gprintf(TRANS, "\nLoaded Adagio file with %ld note(s), %ld ctrl(s).\n\n", seq_notecount(the_score), seq_ctrlcount(the_score)); } nyquist-3.05/cmt/cleanup.h0000644000175000000620000000036310144436365014556 0ustar stevestaff/* cleanup.c -- registers work to do upon exit */ typedef void *cu_parm_type; typedef void (*cu_fn_type)(cu_parm_type); void cu_register(cu_fn_type fn, cu_parm_type obj); void cu_unregister(void *obj); void cu_cleanup(void); #define CLEANUP nyquist-3.05/cmt/mem.h0000644000175000000620000000030710144436365013703 0ustar stevestaff#ifdef AMIGA #include "stddef.h" #endif extern long *mem_free_list[]; void *memget(register size_t size); void memfree(register void *ptr, register size_t size); void meminit(void); #define MEM nyquist-3.05/cmt/cleanup.c0000644000175000000620000000266110144436365014554 0ustar stevestaff/* cleanup.c -- registers work to do upon exit */ #include "stdio.h" #include "cext.h" typedef struct cleanup_struct { struct cleanup_struct *next; cu_fn_type fn; cu_parm_type obj; } cleanup_node, *cleanup_type; cleanup_type cleanup_list = NULL; /* cu_register -- remember function and arg to call in order to clean up */ /**/ void cu_register(cu_fn_type fn, cu_parm_type obj) { cleanup_type cu = (cleanup_type) memget(sizeof(cleanup_node)); cu->fn = fn; cu->obj = obj; cu->next = cleanup_list; cleanup_list = cu; } /* cu_unregister -- erase memory of obj (should be unique in cleanup list) */ /**/ void cu_unregister(obj) void *obj; { cleanup_type *cu = &cleanup_list; while (*cu) { if ((*cu)->obj == obj) { cleanup_type found = *cu; *cu = (*cu)->next; /* splice out found */ memfree((char *) found, sizeof(cleanup_node)); return; } cu = &((*cu)->next); } } /* cu_cleanup -- call the registered functions */ /**/ void cu_cleanup() { while (cleanup_list) { cleanup_type cu = cleanup_list; #ifdef CU_TRACE gprintf(GTRANS, "cu_cleanup: node %lx fn %lx obj %lx\n", cu, cu->fn, cu->obj); #endif cu->fn(cu->obj); cleanup_list = cu->next; memfree((char *) cu, sizeof(cleanup_node)); } #ifdef CU_TRACE gprintf(GTRANS, "cu_cleanup done.\n"); fflush(stdout); #endif } nyquist-3.05/cmt/midimgr.h0000644000175000000620000000074610144436365014564 0ustar stevestaff#define portResType 'port' #define timePortResInfoID 128 #define inputPortResInfoID 129 #define outputPortResInfoID 130 extern short InputRefNum; /* Input port reference number. */ extern short OutputRefNum; /* Output port reference number. */ extern short TimeRefNum; /* Time base port reference number. */ void setup_midimgr(void); void finish_midimgr(void); void midi_show_errors(); nyquist-3.05/cmt/midifns.h0000644000175000000620000000727510144436365014571 0ustar stevestaff/* midifns.h -- definitions for users of midifns.c */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 5-Mar-92 | GWL : insert definitions and logs from JMN's mpu.h * for LATTICE322, only variable type in prototypes * 28-Apr-03 | DM : random() is now named cmtrand() to avoid conflicts *****************************************************************************/ #ifndef _MIDIFNS_H_ #define _MIDIFNS_H_ /* declaration types */ typedef unsigned long time_type; typedef long sgnd_time_type; /* Maximum time value: */ #define MAXTIME 0xFFFFFFFFL #define delay_type long /* controller numbers */ #define MODWHEEL 1 #define BREATH 2 #define FOOT 4 #define PORTARATE 5 #define VOLUME 7 #define SUSTAIN 64 #define PORTASWITCH 65 #include "midierr.h" extern char *midifns_syntax; /* support for allocating sysex buffer - examples in mm.c & exget.c */ #ifdef DOS #define midibuff_alloc(size) (byte huge *) halloc(size, 1) #endif #ifndef midibuff_alloc #define midibuff_alloc (byte *) MALLOC #endif /* DMH: from mpu.h -- definitions for users of mpu.c */ #ifdef OLD_PROTOTYPES void eventwait(); void exclusive(boolean); boolean getbuf(boolean, unsigned char * ); long get_excl(); boolean getxbuf(); boolean testxbuf(); short getkey(boolean); ulong gettime(void); /*DMH: note- now unsigned*/ void l_rest(long); void l_restuntil(long); void metronome(boolean); void midi_bend(short,short); boolean midi_buffer(byte * , ulong); void midi_cont(boolean); void midi_clock(); void midi_ctrl(short, short, short); void midi_exclusive(unsigned char * ); void midi_note(short, short, short); void midi_program(short, short); void midi_real(); void midi_start(); void midi_stop(); #ifdef AMIGA /* MIDI_THRU defined means that it is really implemented. */ #define MIDI_THRU #endif void midi_thru();/*boolean onflag*/ void midi_touch(short, short); void midi_write(); void musicinit(); short cmtrand(short, short); void read_tuning();/*char *filename*/ void settime(); void synth_init();/*void*/ void timereset(); void trace(); void tracemidi(); boolean is_exclusive(void); unsigned char get_exclusive(void); #else void alloff(void); void eventwait(long timeout); void exclusive(boolean onflag); long get_excl(byte *buffer, long len); boolean getbuf(boolean waitflag, unsigned char * p); short getkey(boolean waitflag); ulong gettime(void); void l_rest(long time); void l_restuntil(long time); void metronome(boolean onflag); void midi_bend(int channel, int value); boolean midi_buffer(byte *buffer, ulong size); void midi_clock(void); void midi_cont(boolean onflag); void midi_ctrl(int channel, int control, int value); void midi_exclusive(unsigned char *msg); void midi_flush(); void midi_note(int channel, int pitch, int velocity); void midi_program(int channel, int program); void midi_real(boolean onflag); void midi_start(void); void midi_stop(void); void midi_thru(boolean onflag); void midi_touch(int channel, int value); void read_tuning(char *filename); void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3); void midi_write_trace(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3); void musicinit(void); void settime(time_type newtime); void timereset(void); void trace(boolean flag); void tracemidi(boolean flag); boolean check_midi(void); #endif /* ifdef OLD_PROTOTYPES */ #ifdef AMIGA byte *head_of_excl(); byte *tail_of_excl(); #endif #endif /* _MIDIFNS_H_ */ nyquist-3.05/cmt/seqwrite.h0000644000175000000620000000031110144436365014763 0ustar stevestaff/* seqwrite.h -- write adagio format file */ /* Copyright 1994 Carnegie Mellon University */ void seq_write(seq_type seq, FILE *f, boolean abs_flag); /* LISP: (SEQ-WRITE SEQ FILE BOOLEAN) */ nyquist-3.05/cmt/cmdline.h0000644000175000000620000000036210144436365014541 0ustar stevestaff/* Copyright 1989 Carnegie Mellon University */ char *cl_arg(int n); boolean cl_init(char *av[], int ac); long cl_int_option(char *name, long deflt); char *cl_option(char *name); boolean cl_switch(char *name); boolean cl_syntax(char *name); nyquist-3.05/cmt/moxc.h0000644000175000000620000000220210144436365014067 0ustar stevestaff/* moxc.h -- functions exported by moxie.c */ /* Copyright 1989 Carnegie Mellon University */ #define maxparms 8 extern timebase_type timebase; extern time_type eventtime, virttime; extern int debug; extern int mididecode; extern int moxcdone; void catchup(void); void callallcancel(void); #ifdef DOTS_FOR_ARGS void cause(delay_type delay, ...); void causepri(delay_type delay, int pri, ...); #else void cause(); void causepri(); #endif void m_rest(time_type time); void m_restuntil(time_type time); void quit(void); boolean moxcinit(int argc, char * argv[]); void moxcrun(void); void moxcwait(time_type dateoftimeout); void asciievent(char k); void bendchange(int chan, int value); void coda(void); void ctrlchange(int chan, int ctrl, int value); void keydown(int chan, int key, int vel); void keyup(int chan, int key); void mainscore(void); void midievent(byte midi_data[4]); void peddown(int chan); void pedup(int chan); void prgmchange(int chan, int prgm); void touchchange(int chan, int value); #ifdef AMIGA void buttonchange(int number, int value); void propchange(int number, int value); #endif void sysex(void); nyquist-3.05/cmt/cmtio.h0000644000175000000620000000021310144436365014234 0ustar stevestaff#define NOCHAR -2 int IOinputfd; int IOnochar; int IOsetup(int inputfd); int IOcleanup(void); int IOgetchar(void); int IOwaitchar(void); nyquist-3.05/cmt/cmtcmd.c0000644000175000000620000000166310144436365014375 0ustar stevestaff/* cmtcmd.c -- routines for the moxc side of the command interface */ #include "switches.h" #include "stdio.h" #ifdef AMIGA #include "exec/types.h" #include "exec/exec.h" #endif #include "cmtcmd.h" #include "cext.h" #include "userio.h" #include "string.h" #define HASHELEM(p) ((p).symbol_name) #define HASHVAL 50 #define HASHENTRIES 50 #define HASHENTER lookup #define HASHNOCOPY #include "hashrout.h" void defvar(name, addr) char *name; int *addr; { int i = lookup(name); HASHENTRY(i).symb_type = var_symb_type; HASHENTRY(i).ptr.intptr = addr; } void defun(name, addr) char *name; int (*addr)(); { int i = lookup(name); HASHENTRY(i).symb_type = fn_symb_type; HASHENTRY(i).ptr.routine = addr; } void defvec(name, addr, size) char *name; int *addr; int size; { int i = lookup(name); HASHENTRY(i).symb_type = vec_symb_type; HASHENTRY(i).size = size; HASHENTRY(i).ptr.intptr = addr; } nyquist-3.05/cmt/seqread.h0000644000175000000620000000042710144436365014554 0ustar stevestaff/* seqread.h -- header file for users of seqread.c */ /* Copyright 1989 Carnegie Mellon University */ #define name_length 255 void seq_read(seq_type seq, FILE *fp); /* LISP: (SEQ-READ SEQ FILE) */ time_type scale(ulong, ulong, ulong); /*now public for smf_write, smf_read*/ nyquist-3.05/cmt/seq.h0000644000175000000620000002630211524127024013710 0ustar stevestaff/* seq.h -- definitions for seq, the MIDI Toolkit sequence data type */ #define minpitch 0 #define maxpitch 127 #define NO_PITCH (maxpitch+1) #define minprogram 1 #define maxprogram 128 /* keep these two lines in sync */ #define nmacroparms 4 #define parm_expected_error "Parameter number [1-4] expected" #define seq_dflt_loud 127 #define seq_dflt_voice 1 #define seq_dflt_pitch 60 struct clock_struct { time_type ticksize; }; struct ctrlramp_struct { unsigned char from_value; unsigned char to_value; }; struct deframp_struct { unsigned char *definition; short parameter[nmacroparms]; unsigned char parm_num; short to_value; }; struct macctrl_struct { unsigned char ctrl_number; unsigned char value; }; struct macro_struct { unsigned char *definition; short parameter[nmacroparms]; }; struct note_struct { long ndur; /* duration */ /* char nloud; loudness (MIDI velocity) now stored as low order byte * of ndur */ }; struct ramp_struct { time_type dur; short ctrl; /* encode pitch bend and after touch as negative */ short step; union { struct ctrlramp_struct ctrl; struct deframp_struct def; } u; }; struct seti_struct { int *int_to_set; int value; }; #define SEQ_MAX_PARMS 8 struct cause_struct { int (*routine)(); /* make a structure so we can copy by value */ struct seq_arg_struct { long a[SEQ_MAX_PARMS]; } args; }; typedef struct event_struct { struct event_struct *next; time_type ntime; /* start time */ short nline; /* line number from source code */ unsigned char nvoice; /* adagio voice (MIDI Channel) * if this is a control change, high order 4 bits * contain the control number, otherwise high order * 4 bits are 0 (see is_note macro below) */ unsigned char value; /* this is a note pitch or a control value. It goes * here rather than in the union to achieve word * alignment (!). Also, value is used for extra commands * such as call, seti, setv. */ union { struct cause_struct call; struct clock_struct clock; struct macctrl_struct macctrl; struct macro_struct macro; struct note_struct note; struct ramp_struct ramp; struct seti_struct seti; } u; } event_node, *event_type; #define PSWITCH_CTRL 1 #define MODWHEEL_CTRL 2 #define TOUCH_CTRL 3 #define VOLUME_CTRL 4 #define BEND_CTRL 5 #define PROGRAM_CTRL 6 #define ESC_CTRL 7 #define CALL_VALUE 0 #define CLOCK_VALUE 1 #define MACCTRL_VALUE 2 #define MACRO_VALUE 3 #define CTRLRAMP_VALUE 4 #define DEFRAMP_VALUE 5 #define SETI_VALUE 6 #define commonsize (sizeof(struct event_struct) - sizeof(struct cause_struct)) #define rampcommon (sizeof(struct ramp_struct) - sizeof(struct deframp_struct)) #define ctrlsize commonsize #define callsize (commonsize + sizeof(struct cause_struct)) #define clocksize (commonsize + sizeof(struct clock_struct)) #define ctrlrampsize (commonsize + rampcommon + sizeof(struct ctrlramp_struct)) #define deframpsize (commonsize + sizeof(struct ramp_struct)) #define macctrlsize (commonsize + sizeof(struct macctrl_struct)) #define macrosize (commonsize + sizeof(struct macro_struct)) #define notesize (commonsize + sizeof(struct note_struct)) #define setisize (commonsize + sizeof(struct seti_struct)) #define ctrl_voice(c, v) (((c) << 5) + ((v) - 1)) #define vc_ctrl(v) ((v) >> 5) #define vc_voice(v) (((v) & 0x1F) + 1) #define is_note(n) (((n)->nvoice & 0xE0) == 0) #define CHUNK_SIZE 2000 typedef struct def_struct { struct def_struct *next; char *symbol; unsigned char *definition; } def_node, *def_type; typedef struct chunk_struct { struct chunk_struct *next; short free; union { char data[CHUNK_SIZE]; struct info_struct { short refcount; struct chunk_struct *last_chunk; /* where to allocate memory */ def_type dictionary; /* macro defns, routine addresses */ event_type eventlist; /* first event in sequence */ ulong used_mask; /* tells what channels are actually present */ long ctrlcount; long notecount; time_type duration; /* time of the last event+dur in score */ } info; } u; } chunk_node, *chunk_type; typedef struct seq_struct { void (*cause_noteoff_fn)(struct seq_struct *, time_type, int, int); void (*midi_bend_fn)(struct seq_struct * seq, int voice, int value); void (*midi_ctrl_fn)(struct seq_struct * seq, int voice, int ctrl, int value); void (*midi_program_fn)(struct seq_struct * seq, int voice, int prog); void (*midi_touch_fn)(struct seq_struct * seq, int voice, int value); void (*noteoff_fn)(struct seq_struct * seq, int voice, int pitch); void (*noteon_fn)(struct seq_struct * seq, int chan, int pitch, int vel); void (*free_fn)(struct seq_struct * seq); void (*reset_fn)(struct seq_struct * seq); void (*stopfunc)(struct seq_struct *); chunk_type chunklist; /* event_type eventlist; seq->eventlist is now seq->eventlist->chunklist */ event_type current; boolean runflag; /* normally true, set to false as a flag for * processes started by score to terminate */ boolean note_enable; /* normally true, set to false as a flag to * suppress note output, e.g. when indexing * to a particular time point */ boolean cycleflag; /* normally false, set to true to make the * sequence cycle every cycledur */ int transpose; int loudness; time_type cycledur; timebase_type timebase; time_type rate; /* remembers rate across pauses */ boolean paused; /* remembers if seq has been stopped or not */ short noteoff_count; /* keeps track of pending events, such as * note off commands. When this count goes * to zero, the score is finished */ ulong channel_mask; } seq_node, *seq_type; extern seq_type sequence; chunk_type chunk_create(boolean first_flag); #define seq_cause_noteoff(seq, delay, voice, pitch) \ (*(((seq_type) seq)->cause_noteoff_fn))(seq, delay, voice, pitch) #define seq_midi_bend(seq, voice, value) \ (*(((seq_type) seq)->midi_bend_fn))(seq, voice, value) #define seq_midi_ctrl(seq, voice, ctrl, value) \ (*(((seq_type) seq)->midi_ctrl_fn))(seq, voice, ctrl, value) #define seq_midi_program(seq, voice, prog) \ (*(((seq_type) seq)->midi_program_fn))(seq, voice, prog) #define seq_midi_touch(seq, voice, value) \ (*(((seq_type) seq)->midi_touch_fn))(seq, voice, value) #define seq_noteoff(seq, voice, pitch) \ (*(((seq_type) seq)->noteoff_fn))(seq, voice, pitch) #define seq_noteon(seq, voice, pitch, vel) \ (*(((seq_type) seq)->noteon_fn))(seq, voice, pitch, vel) #define seq_free(seq) (*(((seq_type) seq)->free_fn))(seq) #define seq_register(seq) \ cu_register((cu_fn_type) (((seq_type) seq)->free_fn), seq) #define seq_reset(seq) (*(((seq_type) seq)->reset_fn))(seq) /* LISP: void (SEQ-RESET SEQ) */ extern boolean seq_print; /* debugging switch */ void seq_extensions(void); /* to be defined outside of seq -- user dependent */ event_type insert_call(seq_type seq, time_type ctime, int cline, int voice, int (*addr)(), long value[], int n); event_type insert_clock(seq_type seq, time_type ctime, int cline, time_type ticksize); event_type insert_ctrl(seq_type seq, time_type ctime, int cline, int ctrl, int voice, int value); /* LISP: (SEQ-INSERT-CTRL SEQ FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM) */ event_type insert_ctrlramp(seq_type seq, time_type rtime, int rline, int voice, time_type step, time_type dur, int ctrl, int v1, int v2); /* LISP: (SEQ-INSERT-RAMP SEQ FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM) */ def_type insert_def(seq_type seq, char *symbol, unsigned char *definition, int deflen); event_type insert_deframp(seq_type seq, time_type rtime, int rline, int voice, time_type step, time_type dur, def_type def, int nparms, short parms[], int parm_num, int to_value); event_type insert_macctrl(seq_type seq, time_type ctime, int cline, int ctrl, int voice, int value); /* LISP: (SEQ-INSERT-MACCTRL SEQ FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM) */ event_type insert_macro(seq_type seq, time_type ctime, int cline, def_type def, int voice, int nparms, short *parms); event_type insert_note(seq_type seq, time_type ntime, int nline, int voice, int pitch, time_type dur, int loud); /* LISP: (SEQ-INSERT-NOTE SEQ FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM FIXNUM) */ event_type insert_seti(seq_type seq, time_type stime, int sline, int voice, int *addr, int value); void noop(seq_type seq); seq_type seq_alloc(void); void seq_at_end(seq_type seq, void (*fn)(seq_type)); void seq_cause_noteoff_meth(seq_type seq, time_type delay, int voice, int pitch); #define seq_channel_mask(seq) ((seq)->channel_mask) seq_type seq_copy(seq_type from_seq); /* LISP: (SEQ-COPY SEQ) */ seq_type seq_create(void); /* LISP: (SEQ-CREATE) */ void seq_cycle(seq_type seq, boolean flag, time_type dur); #define seq_duration(seq) (((seq_type) seq)->chunklist->u.info.duration) void seq_end_event(seq_type seq); #define seq_events(seq) (((seq_type) seq)->chunklist ? \ (((seq_type) seq)->chunklist->u.info.eventlist) : NULL) #define seq_dictionary(seq) (seq)->chunklist->u.info.dictionary #define seq_eventlist(seq) (seq)->chunklist->u.info.eventlist #define seq_ctrlcount(seq) (seq)->chunklist->u.info.ctrlcount #define seq_notecount(seq) (seq)->chunklist->u.info.notecount #define seq_used_mask(seq) (seq)->chunklist->u.info.used_mask void seq_free_chunks(seq_type seq); seq_type seq_init(seq_type seq, int create_chunk); #define seq_loudness(seq) (((seq_type) seq)->loudness) void seq_midi_bend_meth(seq_type seq, int voice, int value); void seq_midi_ctrl_meth(seq_type seq, int voice, int ctrl, int value); void seq_midi_program_meth(seq_type seq, int voice, int prog); void seq_midi_touch_meth(seq_type seq, int voice, int value); void seq_noteon_meth(seq_type seq, int voice, int pitch, int vel); void seq_noteoff_meth(seq_type seq, int chan, int pitch); time_type seq_pause(seq_type seq, boolean flag); void seq_play(seq_type seq); #define seq_rate(seq) ((seq_type) seq)->rate void seq_reset_meth(seq_type seq); #define seq_runflag(seq) ((seq_type) seq)->runflag #define seq_set_channel_mask(seq, cm) ((seq)->channel_mask) = (cm) void seq_set_loudness(seq_type seq, int offset); void seq_set_rate(seq_type seq, time_type rate); #define seq_set_timebase(seq, tb) ((seq_type) seq)->timebase = (tb) void seq_set_transpose(seq_type seq, int trans); void seq_start_time(seq_type seq, time_type start_time); void seq_stop(seq_type seq); #define seq_timebase(seq) ((seq_type) seq)->timebase #define seq_transpose(seq) ((seq_type) seq)->transpose nyquist-3.05/cmt/mem.c0000644000175000000620000000524110144436365013700 0ustar stevestaff/* mem.c -- fast memory allocation/deallocation module */ /* Allocate large chunks of memory using malloc. From the chunks, allocate memory as needed on long-word boundaries. Memory is freed by linking memory onto a freelist. An array of freelists, one for each size, is maintained and checked before going to the chunck for more memory. The freelist array only holds lists of nodes up to a certain size. After that, malloc is used directly. */ /* CHANGE LOG ---------------------------------------------------------------------- 28-Apr-03 | DM : fix #includes for portability ---------------------------------------------------------------------- */ #include "switches.h" #include #include #include "cext.h" #include "userio.h" /* how many bytes in the largest node managed in mem_free_list array */ #define MAX_SIZE_FOR_FREELIST 256 long *mem_free_list[MAX_SIZE_FOR_FREELIST/4]; #define MEM_CHUNK_SIZE 4096 char *mem_chunk; long mem_chunk_remaining = 0; void meminit() { int i; for (i = 0; i < MAX_SIZE_FOR_FREELIST/4; i++) { mem_free_list[i] = NULL; } } void *memget(register size_t size) { if (size > MAX_SIZE_FOR_FREELIST) { /* gprintf(TRANS, "memget calling MALLOC\n"); */ return MALLOC(size); } else { long **p = mem_free_list + ((size - 1) >> 2); if (*p) { register long *result = *p; *p = (long *) *result; /* gprintf(TRANS, "memget->%lx\n", result); */ return (char *) result; } else if ((size_t) mem_chunk_remaining >= size) { register char *result = mem_chunk; size = (size + 3) & ~3; /* round up to multiple of 4 */ mem_chunk += size; mem_chunk_remaining -= size; /* gprintf(TRANS, "memget->%lx\n", result); */ return result; /* note that we throw away remaining chunk when there isn't enough */ } else if ((mem_chunk = (char *) MALLOC(MEM_CHUNK_SIZE))) { register char *result = mem_chunk; /* gprintf(TRANS, "mem_chunk at %lx\n", mem_chunk); */ size = (size + 3) & ~3; /* round up to multiple of 4 */ mem_chunk += size; mem_chunk_remaining = MEM_CHUNK_SIZE - size; /* gprintf(TRANS, "memget->%lx\n", result); */ return result; } else { return NULL; } } } void memfree(register void *ptr, register size_t size) { register long **p = (long **) ptr; if (size > MAX_SIZE_FOR_FREELIST) { FREE(ptr); } else { register long **head_ptr = mem_free_list + ((size - 1) >> 2); *p = *head_ptr; *head_ptr = (long *) p; } } nyquist-3.05/cmt/midifile.h0000644000175000000620000000167711524127024014712 0ustar stevestaffextern void midifile(void); extern int (*Mf_getc)(void); extern void (*Mf_header)(int,int,int); extern void (*Mf_starttrack)(void); extern void (*Mf_endtrack)(void); extern void (*Mf_on)(int,int,int); extern void (*Mf_off)(int,int,int); extern void (*Mf_pressure)(int,int,int); extern void (*Mf_controller)(int,int,int); extern void (*Mf_pitchbend)(int,int,int); extern void (*Mf_program)(int,int); extern void (*Mf_chanpressure)(int,int); extern void (*Mf_sysex)(int,char*); extern void (*Mf_metamisc)(int,int,char*); extern void (*Mf_sqspecific)(int,char*); extern void (*Mf_seqnum)(int); extern void (*Mf_text)(int,int,char*); extern void (*Mf_eot)(void); extern void (*Mf_timesig)(int,int,int,int); extern void (*Mf_smpte)(int,int,int,int,int); extern void (*Mf_tempo)(int); extern void (*Mf_keysig)(int,int); extern void (*Mf_arbitrary)(int,char*); extern void (*Mf_error)(char *); extern long Mf_currtime; extern int Mf_nomerge; extern int Mf_skipinit; nyquist-3.05/cmt/mfmidi.h0000644000175000000620000000117010144436365014371 0ustar stevestaff#define NOTEOFF 0x80 #define NOTEON 0x90 #define PRESSURE 0xa0 #define CONTROLLER 0xb0 #define PITCHBEND 0xe0 #define PROGRAM 0xc0 #define CHANPRESSURE 0xd0 /* These are the strings used in keynote to identify Standard MIDI File */ /* meta text messages. */ #define METATEXT "Text Event" #define METACOPYRIGHT "Copyright Notice" #define METASEQUENCE "Sequence/Track Name" #define METAINSTRUMENT "Instrument Name" #define METALYRIC "Lyric" #define METAMARKER "Marker" #define METACUE "Cue Point" #define METAUNRECOGNIZED "Unrecognized" nyquist-3.05/cmt/pitch.h0000644000175000000620000000022710144436365014235 0ustar stevestaff/* mbc code */ /* Copyright 1989 Carnegie Mellon University */ typedef struct pitch_struct { int ppitch; int pbend; } pitch_table; /* end */ nyquist-3.05/cmt/musiprog.h0000644000175000000620000000175310144436365015000 0ustar stevestaff/* musiprog.h -- include file for cmt application programs */ #include "stdio.h" #include "cext.h" #include "midifns.h" #include "userio.h" #include "timebase.h" #include "moxc.h" /* * override the definition of l_rest - l_rest is not recommended because * it stops polling for input. If you really want to use it, use #undef * to make it visible. */ #define l_rest(d) m_rest(d) #define l_restuntil(t) m_restuntil(t) /* * The default implementation of rest() and restuntil() poll for * input during the rest. You might call rest() or restuntil() from * mainscore(), but it is generally a bad idea to rest at all. If * you are in a rest(), you get an event, e.g. keydown(), and you * make a nested call to rest(), the original rest will be locked out * until the nested one returns. It's better to use cause(). */ #define rest(x) l_rest( (long) x ) #define restuntil(x) l_restuntil( (long) x) #define repeat(var, count) {int var; for (var=1; var <= count; var++) { #define endrep ;}} nyquist-3.05/cmt/cmdline.c0000644000175000000620000004012111466723256014537 0ustar stevestaff/* cmdline.c -- command line parsing routines */ /* Copyright 1989 Carnegie Mellon University */ /* * This module is designed to allow various modules to scan (and rescan) * the command line for applicable arguments. The goal is to hide as * much information about switches and their names as possible so that * switches become more consistent across applications and so that the * author of an application need not do a lot of work to provide numerous * options. Instead, each module scans the command line for its own * arguments. * * Command lines are of the following form: * command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3 * Note that there are three kinds of command line parameters: * (1) A Switch is a "-" followed by a name, e.g. "-s1" * (2) An Option is a Switch followed by a space and name, e.g. "-s2 opt2" * (3) An Argument is a name by itself, e.g. "arg1" * Note also that a switch followed by an argument looks just like an * option, so a list of valid option names is necessary to disambiguate. * * Long names are good for readability, but single character abbreviations * are nice for experienced users. cmdline.c allows single character * abbreviations provided that they are unambiguous. These are * recognized with no extra work by the programmer. If an * isolated '?' is encountered in the command line, then all of * the options and switches are printed as help and for debugging. * * Given that we must tell this module about option names and switch * names, how should we do it? We can't wait until modules are * initialized, since often modules want to read the command line * at initialization time. In the original implementation, the * main program was supposed to provide names for the whole program, * but this violates modularity: when an option is added to a module, * the main program has to be modified too. This is a real pain when * different machines support different options and you want to have * a single machine-independent main program. The solution is to * have the main program import strings describing the options and * switches used by each module. These are passed into cmdline.c * before initialization of other modules is begun. * * A main program that uses cmdline.c should do the following: * call cl_syntax(s) for each module's option/switch string. * The string s should have the following format: * "opt1description;opt2description;...;switch1description;..." * where opt1 and opt2 are option names (without the preceding "-"), and * switch1 is a switch name. The and indicate whether the * name is an option or a switch. The descriptions are arbitrary strings * (without semicolons) that are printed out for the user when "?" * is typed on the command line. * * After calling cl_syntax, main() should call * cl_init(argv, argc) * cl_init will report an error (to STDERR) if it finds any illegal * switch or option names in argv, and help will be printed if "?" * is found in argv. If cl_init returns false, then the user has been * given an error message or help, and main should probably exit. * * Afterward, switches, options, and arguments can be accessed by * calling cl_switch, cl_option, and cl_arg. If cl_switch or cl_option * is called with a switch name that was not mentioned in the call to * cl_init, an error will result. This indicates that the application * author omitted a valid switch or option name when calling cl_init. * This is an error because the full set of names is needed for error * checking and to distinguish arguments from options. * */ /***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 13-Jun-86 | Created Change Log * 6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines * 20-Sep-89 | Redesigned the interface, adding cl_syntax call. * 2-Apr-91 | JDW : further changes * 27-Dec-93 | "@file" as first arg reads command line args from file * 11-Mar-94 | PLu: Add private to cl_search() definition. * 28-Apr-03 | DM: true->TRUE, false->FALSE *****************************************************************************/ /* stdlib.h not on PMAX */ #ifndef mips #include "stdlib.h" #endif #include "stdio.h" #include "cext.h" #include "userio.h" #include "cmdline.h" #include "ctype.h" #include "string.h" #define syntax_max 10 /* allow for 10 syntax strings */ private char *syntax[syntax_max]; private int n_syntax = 0; /* number of strings so far */ private char **argv; /* command line argument vector */ private int argc; /* length of argv */ private boolean cl_rdy = FALSE; /* set to TRUE when initialized */ #define cl_OPT 1 #define cl_SW 2 #define cl_INIT 3 #define cl_ARG 4 /***************************************************************************** * Routines local to this module *****************************************************************************/ private char *cl_search(); private int find_string(); private void indirect_command(char *filename, char *oldarg0); private void ready_check(); /**************************************************************** * cl_arg * Inputs: * n: the index of the arg needed * Results: * pointer to the nth arg, or NULL if none exists * arg 0 is the command name *****************************************************************/ char *cl_arg(n) int n; { return (n <= 0 ? argv[0] : cl_search((char *)NULL, cl_ARG, n)); } /* cl_help -- print help from syntax strings */ /**/ void cl_help() { register int i, j; int count = 0; /* see if there are any switches or flags */ for (i = 0; i < n_syntax; i++) { register char *ptr = syntax[i]; register char c = *ptr++; while (c != EOS) { while (c != EOS && !(isalnum(c))) c = *ptr++; if (c != EOS) { count++; gprintf(TRANS, "-"); j = 1; while (c != EOS && c != '<') { gprintf(TRANS, "%c", c); c = *ptr++; j++; } if (c != EOS) { c = *ptr++; if (c == 'o') { gprintf(TRANS, " xxx"); j += 4; } } /* attempt to tab */ do { gprintf(TRANS, " "); } while (j++ < 16); while (c != EOS && c != '>') c = *ptr++; if (c != EOS) c = *ptr++; while (c != EOS && c != ';') { gprintf(TRANS, "%c", c); c = *ptr++; } gprintf(TRANS, "\n"); } } } if (!count) gprintf(TRANS, "No switches or options exist.\n"); } /***************************************************************************** * cl_init * Inputs: * char *switches[]: array of switch names * int nsw: number of switch names * char *options[]: array of option names * int nopt: number of option names * char *av: array of command line fields (argv) * int ac: number of command line fields (argc) * Effect: * Checks that all command line entries are valid. * Saves info for use by other routines. * Returns: * TRUE if syntax checks OK, otherwise false *****************************************************************************/ boolean cl_init(av, ac) char *av[]; int ac; { argv = av; argc = ac; /* check for help request */ if (argc == 2 && strcmp(argv[1], "?") == 0) { cl_help(); return FALSE; /* avoid cl_search which would complain about "?" */ } /* check for indirection */ if (argc == 2 && *(argv[1]) == '@') { /* read new args from file */ indirect_command(av[1] + 1, av[0]); } /* check command line syntax: */ cl_rdy = TRUE; return (cl_rdy = (cl_search("true", cl_INIT, 0) != NULL)); } /**************************************************************** * cl_int_option * Inputs: * char *name: name of option * long default: default value for option * Result: * returns long encoding of the option, deflt if none * Implementation: * call cl_option and sscanf result *****************************************************************/ long cl_int_option(name, deflt) char *name; long deflt; { char *opt = cl_option(name); if (opt) { if (sscanf(opt, "%ld", &deflt) != 1) { gprintf(TRANS, "Warning: option %s %s not an integer, ignored\n", name, opt); } } return deflt; } /**************************************************************** * cl_search * Inputs: * char *name: name of field, must be non-null if opt_sw == cl_INIT * int opt_sw: option, switch, init, or arg * int n: argument number (if opt_sw is cl_ARG) * Result: * returns pointer to option value/switch if one exists, otherwise null * Implementation: * parse the command line until name or arg is found * see if the option is followed by a string that does * not start with "-" *****************************************************************/ private char *cl_search(name, opt_sw, n) char *name; int opt_sw; int n; /* if opt_sw is cl_ARG, n > 0 tells which one */ { register int i = 1; /* index into command line */ boolean abbr; boolean result = TRUE; ready_check(); /* parse command line: */ while (i < argc) { register char *arg = argv[i]; /* arguments that start with '-' should be quoted and quotes must be removed by the application */ if (*arg == '-') { int arg_type = find_string(arg + 1, &abbr); if (arg_type == cl_OPT) { i += 1; /* skip name and option */ /* don't look for '-' because the option might be a * negative number */ if (i >= argc /* || *arg == '-' */) { if (opt_sw == cl_INIT) { gprintf(ERROR, "missing argument after %s\n", arg); result = FALSE; } } else if (opt_sw == cl_OPT && (strcmp(arg + 1, name) == 0 || (abbr && *(arg + 1) == name[0]))) { return argv[i]; } } else if (arg_type == cl_SW) { if (opt_sw == cl_SW && (strcmp(arg + 1, name) == 0 || (abbr && *(arg + 1) == name[0]))) return arg; } else if (opt_sw == cl_INIT) { gprintf(ERROR, "invalid switch: %s\n", arg); result = FALSE; } } else if (opt_sw == cl_ARG) { if (n == 1) return arg; n--; } i++; /* skip to next field */ } if (opt_sw == cl_INIT) { /* return name or NULL to represent TRUE or FALSE */ return (result ? name : NULL); } return NULL; } /**************************************************************** * cl_option * Inputs: * char *name: option name * Outputs: * returns char *: the option string if found, otherwise null ****************************************************************/ char *cl_option(name) char *name; { return cl_search(name, cl_OPT, 0); } /**************************************************************** * cl_switch * Inputs: * char *name: switch name * Outputs: * boolean: TRUE if switch found ****************************************************************/ boolean cl_switch(name) char *name; { return (boolean)(cl_search(name, cl_SW, 0) != NULL); } /* cl_syntax -- install a string specifying options and switches */ /**/ boolean cl_syntax(char *s) { if (n_syntax < syntax_max) { syntax[n_syntax++] = s; return TRUE; } else { gprintf(ERROR, "cl_syntax: out of room\n"); return FALSE; } } /**************************************************************** * find_string * Inputs: * char *s: string to find, terminated by any non-alphanumeric * boolean *abbr: set TRUE if s is an abbreviation, otherwise false * Effect: * Looks for s in syntax strings * Returns: * 0 = FALSE = not found, 1 = cl_OPT = option, 2 = cl_SW = switch *****************************************************************/ private int find_string(s, abbr) char *s; boolean *abbr; { int found_it = FALSE; int i; *abbr = FALSE; for (i = 0; i < n_syntax; i++) { /* loop through strings */ register char *syntax_ptr = syntax[i]; while (*syntax_ptr != EOS) { register char *s_ptr = s; while (*syntax_ptr != EOS && !(isalnum(*syntax_ptr))) syntax_ptr++; while (*s_ptr != EOS && (*s_ptr++ == *syntax_ptr)) syntax_ptr++; /* only increment if there's a match */ if (!(isalnum(*s_ptr)) && *syntax_ptr == '<') { syntax_ptr++; /* advance to the type field */ if (*syntax_ptr == 's') return cl_SW; if (*syntax_ptr != 'o') gprintf(ERROR, "(internal error) bad cl_syntax string: %s\n", syntax[i]); return cl_OPT; } /* no match, so go to next */ while (*syntax_ptr != ';' && *syntax_ptr != EOS) syntax_ptr++; if (*syntax_ptr == ';') syntax_ptr++; } } /* no match, maybe there is a single character match */ if (s[0] == EOS || s[1] != EOS) return FALSE; for (i = 0; i < n_syntax; i++) { /* loop through strings */ char *syntax_ptr = syntax[i]; while (*syntax_ptr != EOS) { while (*syntax_ptr != EOS && !(isalnum(*syntax_ptr))) syntax_ptr++; if (s[0] == *syntax_ptr) { if (found_it) return FALSE; /* ambiguous */ /* else, find the type */ while (*syntax_ptr != '<' && *syntax_ptr != EOS) syntax_ptr++; syntax_ptr++; if (*syntax_ptr == 's') found_it = cl_SW; else if (*syntax_ptr == 'o') found_it = cl_OPT; else return FALSE; /* error in string syntax */ } /* no match, so go to next */ while (*syntax_ptr != ';' && *syntax_ptr != EOS) syntax_ptr++; if (*syntax_ptr == ';') syntax_ptr++; } } if (found_it) *abbr = TRUE; return found_it; } /* get_arg -- get an argument from a file */ /**/ boolean get_arg(file, arg) FILE *file; char *arg; { int c; while ((c = getc(file)) != EOF && isspace(c)) ; if (c == EOF) return FALSE; ungetc(c, file); while ((c = getc(file)) != EOF && !isspace(c)) { *arg++ = c; } *arg = 0; return TRUE; } /* indirect_command -- get argv, argc from a file */ /**/ private void indirect_command(filename, oldarg0) char *filename; char *oldarg0; { FILE *argfile = fopen(filename, "r"); if (!argfile) { argv = (char **) malloc(sizeof(char *)); argv[0] = oldarg0; argc = 1; } else { int i = 1; char arg[100]; while (get_arg(argfile, arg)) i++; fclose(argfile); argfile = fopen(filename, "r"); argv = (char **) malloc(sizeof(char *) * i); argv[0] = oldarg0; argc = i; i = 1; while (get_arg(argfile, arg)) { argv[i] = (char *) malloc(strlen(arg) + 1); strcpy(argv[i], arg); i++; } fclose(argfile); } } /**************************************************************** * ready_check * Effect: * Halt program if cl_rdy is not true. *****************************************************************/ private void ready_check() { if (!cl_rdy) { gprintf(ERROR, "Internal error: cl_init was not called, see cmdline.c\n"); EXIT(1); } } nyquist-3.05/ffts/0002755000175000000620000000000011537433131013130 5ustar stevestaffnyquist-3.05/ffts/src/0002755000175000000620000000000011537433131013717 5ustar stevestaffnyquist-3.05/ffts/src/matlib.c0000644000175000000620000001556511466723256015360 0ustar stevestaff/* a few routines from a vector/matrix library */ #include "matlib.h" void xpose(float *indata, long iRsiz, float *outdata, long oRsiz, long Nrows, long Ncols){ /* not in-place matrix transpose */ /* INPUTS */ /* *indata = input data array */ /* iRsiz = offset to between rows of input data array */ /* oRsiz = offset to between rows of output data array */ /* Nrows = number of rows in input data array */ /* Ncols = number of columns in input data array */ /* OUTPUTS */ /* *outdata = output data array */ float *irow; /* pointer to input row start */ float *ocol; /* pointer to output col start */ float *idata; /* pointer to input data */ float *odata; /* pointer to output data */ long RowCnt; /* row counter */ long ColCnt; /* col counter */ float T0; /* data storage */ float T1; /* data storage */ float T2; /* data storage */ float T3; /* data storage */ float T4; /* data storage */ float T5; /* data storage */ float T6; /* data storage */ float T7; /* data storage */ const long inRsizd1 = iRsiz; const long inRsizd2 = 2*iRsiz; const long inRsizd3 = inRsizd2+iRsiz; const long inRsizd4 = 4*iRsiz; const long inRsizd5 = inRsizd3+inRsizd2; const long inRsizd6 = inRsizd4+inRsizd2; const long inRsizd7 = inRsizd4+inRsizd3; const long inRsizd8 = 8*iRsiz; ocol = outdata; irow = indata; for (RowCnt=Nrows/8; RowCnt>0; RowCnt--){ idata = irow; odata = ocol; for (ColCnt=Ncols; ColCnt>0; ColCnt--){ T0 = *idata; T1 = *(idata+inRsizd1); T2 = *(idata+inRsizd2); T3 = *(idata+inRsizd3); T4 = *(idata+inRsizd4); T5 = *(idata+inRsizd5); T6 = *(idata+inRsizd6); T7 = *(idata+inRsizd7); *odata = T0; *(odata+1) = T1; *(odata+2) = T2; *(odata+3) = T3; *(odata+4) = T4; *(odata+5) = T5; *(odata+6) = T6; *(odata+7) = T7; idata++; odata += oRsiz; } irow += inRsizd8; ocol += 8; } if (Nrows%8 != 0){ for (ColCnt=Ncols; ColCnt>0; ColCnt--){ idata = irow++; odata = ocol; ocol += oRsiz; for (RowCnt=Nrows%8; RowCnt>0; RowCnt--){ T0 = *idata; *odata++ = T0; idata += iRsiz; } } } } void cxpose(float *indata, long iRsiz, float *outdata, long oRsiz, long Nrows, long Ncols){ /* not in-place complex float matrix transpose */ /* INPUTS */ /* *indata = input data array */ /* iRsiz = offset to between rows of input data array */ /* oRsiz = offset to between rows of output data array */ /* Nrows = number of rows in input data array */ /* Ncols = number of columns in input data array */ /* OUTPUTS */ /* *outdata = output data array */ float *irow; /* pointer to input row start */ float *ocol; /* pointer to output col start */ float *idata; /* pointer to input data */ float *odata; /* pointer to output data */ long RowCnt; /* row counter */ long ColCnt; /* col counter */ float T0r; /* data storage */ float T0i; /* data storage */ float T1r; /* data storage */ float T1i; /* data storage */ float T2r; /* data storage */ float T2i; /* data storage */ float T3r; /* data storage */ float T3i; /* data storage */ const long inRsizd1 = 2*iRsiz; const long inRsizd1i = 2*iRsiz + 1; const long inRsizd2 = 4*iRsiz; const long inRsizd2i = 4*iRsiz + 1; const long inRsizd3 = inRsizd2+inRsizd1; const long inRsizd3i = inRsizd2+inRsizd1 + 1; const long inRsizd4 = 8*iRsiz; ocol = outdata; irow = indata; for (RowCnt=Nrows/4; RowCnt>0; RowCnt--){ idata = irow; odata = ocol; for (ColCnt=Ncols; ColCnt>0; ColCnt--){ T0r = *idata; T0i = *(idata +1); T1r = *(idata+inRsizd1); T1i = *(idata+inRsizd1i); T2r = *(idata+inRsizd2); T2i = *(idata+inRsizd2i); T3r = *(idata+inRsizd3); T3i = *(idata+inRsizd3i); *odata = T0r; *(odata+1) = T0i; *(odata+2) = T1r; *(odata+3) = T1i; *(odata+4) = T2r; *(odata+5) = T2i; *(odata+6) = T3r; *(odata+7) = T3i; idata+=2; odata += 2*oRsiz; } irow += inRsizd4; ocol += 8; } if (Nrows%4 != 0){ for (ColCnt=Ncols; ColCnt>0; ColCnt--){ idata = irow; odata = ocol; for (RowCnt=Nrows%4; RowCnt>0; RowCnt--){ T0r = *idata; T0i = *(idata+1); *odata = T0r; *(odata+1) = T0i; odata+=2; idata += 2*iRsiz; } irow+=2; ocol += 2*oRsiz; } } } void cvprod(float *a, float *b, float *out, long N){ /* complex vector product, can be in-place */ /* product of complex vector *a times complex vector *b */ /* INPUTS */ /* N vector length */ /* *a complex vector length N complex numbers */ /* *b complex vector length N complex numbers */ /* OUTPUTS */ /* *out complex vector length N */ long OutCnt; /* output counter */ float A0R; /* A storage */ float A0I; /* A storage */ float A1R; /* A storage */ float A1I; /* A storage */ float A2R; /* A storage */ float A2I; /* A storage */ float A3R; /* A storage */ float A3I; /* A storage */ float B0R; /* B storage */ float B0I; /* B storage */ float B1R; /* B storage */ float B1I; /* B storage */ float B2R; /* B storage */ float B2I; /* B storage */ float B3R; /* B storage */ float B3I; /* B storage */ float T0R; /* TMP storage */ float T0I; /* TMP storage */ float T1R; /* TMP storage */ float T1I; /* TMP storage */ float T2R; /* TMP storage */ float T2I; /* TMP storage */ float T3R; /* TMP storage */ float T3I; /* TMP storage */ if (N>=4){ A0R = *a; B0R = *b; A0I = *(a +1); B0I = *(b +1); A1R = *(a +2); B1R = *(b +2); A1I = *(a +3); B1I = *(b +3); A2R = *(a +4); B2R = *(b +4); A2I = *(a +5); B2I = *(b +5); A3R = *(a +6); B3R = *(b +6); A3I = *(a +7); B3I = *(b +7); T0R = A0R * B0R; T0I = (A0R * B0I); T1R = A1R * B1R; T1I = (A1R * B1I); T2R = A2R * B2R; T2I = (A2R * B2I); T3R = A3R * B3R; T3I = (A3R * B3I); T0R -= (A0I * B0I); T0I = A0I * B0R + T0I; T1R -= (A1I * B1I); T1I = A1I * B1R + T1I; T2R -= (A2I * B2I); T2I = A2I * B2R + T2I; T3R -= (A3I * B3I); T3I = A3I * B3R + T3I; for (OutCnt=N/4-1; OutCnt > 0; OutCnt--){ a += 8; b += 8; A0R = *a; B0R = *b; A0I = *(a +1); B0I = *(b +1); A1R = *(a +2); B1R = *(b +2); A1I = *(a +3); B1I = *(b +3); A2R = *(a +4); B2R = *(b +4); A2I = *(a +5); B2I = *(b +5); A3R = *(a +6); B3R = *(b +6); A3I = *(a +7); B3I = *(b +7); *out = T0R; *(out +1) = T0I; *(out +2) = T1R; *(out +3) = T1I; *(out +4) = T2R; *(out +5) = T2I; *(out +6) = T3R; *(out +7) = T3I; T0R = A0R * B0R; T0I = (A0R * B0I); T1R = A1R * B1R; T1I = (A1R * B1I); T2R = A2R * B2R; T2I = (A2R * B2I); T3R = A3R * B3R; T3I = (A3R * B3I); T0R -= (A0I * B0I); T0I = A0I * B0R + T0I; T1R -= (A1I * B1I); T1I = A1I * B1R + T1I; T2R -= (A2I * B2I); T2I = A2I * B2R + T2I; T3R -= (A3I * B3I); T3I = A3I * B3R + T3I; out += 8; } a += 8; b += 8; *out = T0R; *(out +1) = T0I; *(out +2) = T1R; *(out +3) = T1I; *(out +4) = T2R; *(out +5) = T2I; *(out +6) = T3R; *(out +7) = T3I; out += 8; } for (OutCnt=N%4; OutCnt > 0; OutCnt--){ A0R = *a++; B0R = *b++; A0I = *a++; B0I = *b++; T0R = A0R * B0R; T0I = (A0R * B0I); T0R -= (A0I * B0I); T0I = A0I * B0R + T0I; *out++ = T0R; *out++ = T0I; } } nyquist-3.05/ffts/src/fftlib.c0000644000175000000620000017015611466723256015354 0ustar stevestaff/******************************************************************* lower level fft stuff including routines called in fftext.c and fft2d.c *******************************************************************/ #include "fftlib.h" #include #define MCACHE (11-(sizeof(float)/8)) // fft's with M bigger than this bust primary cache #ifdef WIN32 #define inline __inline #endif // some math constants to 40 decimal places #define MYPI 3.141592653589793238462643383279502884197 // pi #define MYROOT2 1.414213562373095048801688724209698078569 // sqrt(2) #define MYCOSPID8 0.9238795325112867561281831893967882868224 // cos(pi/8) #define MYSINPID8 0.3826834323650897717284599840303988667613 // sin(pi/8) /************************************************* routines to initialize tables used by fft routines **************************************************/ void fftCosInit(long M, float *Utbl){ /* Compute Utbl, the cosine table for ffts */ /* of size (pow(2,M)/4 +1) */ /* INPUTS */ /* M = log2 of fft size */ /* OUTPUTS */ /* *Utbl = cosine table */ unsigned long fftN = POW2(M); unsigned long i1; Utbl[0] = 1.0; for (i1 = 1; i1 < fftN/4; i1++) Utbl[i1] = cos( (2.0 * MYPI * i1) / fftN ); Utbl[fftN/4] = 0.0; } void fftBRInit(long M, short *BRLow){ /* Compute BRLow, the bit reversed table for ffts */ /* of size pow(2,M/2 -1) */ /* INPUTS */ /* M = log2 of fft size */ /* OUTPUTS */ /* *BRLow = bit reversed counter table */ long Mroot_1 = M / 2 - 1; long Nroot_1 = POW2(Mroot_1); long i1; long bitsum; long bitmask; long bit; for (i1 = 0; i1 < Nroot_1; i1++){ bitsum = 0; bitmask = 1; for (bit=1; bit <= Mroot_1; bitmask<<=1, bit++) if (i1 & bitmask) bitsum = bitsum + (Nroot_1 >> bit); BRLow[i1] = bitsum; }; } /************************************************ parts of ffts1 *************************************************/ inline void bitrevR2(float *ioptr, long M, short *BRLow); inline void bitrevR2(float *ioptr, long M, short *BRLow){ /*** bit reverse and first radix 2 stage of forward or inverse fft ***/ float f0r; float f0i; float f1r; float f1i; float f2r; float f2i; float f3r; float f3i; float f4r; float f4i; float f5r; float f5i; float f6r; float f6i; float f7r; float f7i; float t0r; float t0i; float t1r; float t1i; float *p0r; float *p1r; float *IOP; float *iolimit; long Colstart; long iCol; unsigned long posA; unsigned long posAi; unsigned long posB; unsigned long posBi; const unsigned long Nrems2 = POW2((M+3)/2); const unsigned long Nroot_1_ColInc = POW2(M)-Nrems2; const unsigned long Nroot_1 = POW2(M/2-1)-1; const unsigned long ColstartShift = (M+1)/2 +1; posA = POW2(M); // 1/2 of POW2(M) complexes posAi = posA + 1; posB = posA + 2; posBi = posB + 1; iolimit = ioptr + Nrems2; for (; ioptr < iolimit; ioptr += POW2(M/2+1)){ for (Colstart = Nroot_1; Colstart >= 0; Colstart--){ iCol = Nroot_1; p0r = ioptr+ Nroot_1_ColInc + BRLow[Colstart]*4; IOP = ioptr + (Colstart << ColstartShift); p1r = IOP + BRLow[iCol]*4; f0r = *(p0r); f0i = *(p0r+1); f1r = *(p0r+posA); f1i = *(p0r+posAi); for (; iCol > Colstart;){ f2r = *(p0r+2); f2i = *(p0r+(2+1)); f3r = *(p0r+posB); f3i = *(p0r+posBi); f4r = *(p1r); f4i = *(p1r+1); f5r = *(p1r+posA); f5i = *(p1r+posAi); f6r = *(p1r+2); f6i = *(p1r+(2+1)); f7r = *(p1r+posB); f7i = *(p1r+posBi); t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r + f3r; t1i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; f0r = f4r + f5r; f0i = f4i + f5i; f5r = f4r - f5r; f5i = f4i - f5i; f2r = f6r + f7r; f2i = f6i + f7i; f7r = f6r - f7r; f7i = f6i - f7i; *(p1r) = t0r; *(p1r+1) = t0i; *(p1r+2) = f1r; *(p1r+(2+1)) = f1i; *(p1r+posA) = t1r; *(p1r+posAi) = t1i; *(p1r+posB) = f3r; *(p1r+posBi) = f3i; *(p0r) = f0r; *(p0r+1) = f0i; *(p0r+2) = f5r; *(p0r+(2+1)) = f5i; *(p0r+posA) = f2r; *(p0r+posAi) = f2i; *(p0r+posB) = f7r; *(p0r+posBi) = f7i; p0r -= Nrems2; f0r = *(p0r); f0i = *(p0r+1); f1r = *(p0r+posA); f1i = *(p0r+posAi); iCol -= 1; p1r = IOP + BRLow[iCol]*4; }; f2r = *(p0r+2); f2i = *(p0r+(2+1)); f3r = *(p0r+posB); f3i = *(p0r+posBi); t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r + f3r; t1i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; *(p0r) = t0r; *(p0r+1) = t0i; *(p0r+2) = f1r; *(p0r+(2+1)) = f1i; *(p0r+posA) = t1r; *(p0r+posAi) = t1i; *(p0r+posB) = f3r; *(p0r+posBi) = f3i; }; }; } inline void fft2pt(float *ioptr); inline void fft2pt(float *ioptr){ /*** RADIX 2 fft ***/ float f0r, f0i, f1r, f1i; float t0r, t0i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[2]; f1i = ioptr[3]; /* Butterflys */ /* f0 - - t0 f1 - 1 - f1 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; /* store result */ ioptr[0] = t0r; ioptr[1] = t0i; ioptr[2] = f1r; ioptr[3] = f1i; } inline void fft4pt(float *ioptr); inline void fft4pt(float *ioptr){ /*** RADIX 4 fft ***/ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float t0r, t0i, t1r, t1i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[4]; f1i = ioptr[5]; f2r = ioptr[2]; f2i = ioptr[3]; f3r = ioptr[6]; f3i = ioptr[7]; /* Butterflys */ /* f0 - - t0 - - f0 f1 - 1 - f1 - - f1 f2 - - f2 - 1 - f2 f3 - 1 - t1 - -i - f3 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r - t1i; f3i = f1i + t1r; f1r = f1r + t1i; f1i = f1i - t1r; /* store result */ ioptr[0] = f0r; ioptr[1] = f0i; ioptr[2] = f1r; ioptr[3] = f1i; ioptr[4] = f2r; ioptr[5] = f2i; ioptr[6] = f3r; ioptr[7] = f3i; } inline void fft8pt(float *ioptr); inline void fft8pt(float *ioptr){ /*** RADIX 8 fft ***/ float w0r = 1.0/MYROOT2; /* cos(pi/4) */ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t0r, t0i, t1r, t1i; const float Two = 2.0; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[8]; f1i = ioptr[9]; f2r = ioptr[4]; f2i = ioptr[5]; f3r = ioptr[12]; f3i = ioptr[13]; f4r = ioptr[2]; f4i = ioptr[3]; f5r = ioptr[10]; f5i = ioptr[11]; f6r = ioptr[6]; f6i = ioptr[7]; f7r = ioptr[14]; f7i = ioptr[15]; /* Butterflys */ /* f0 - - t0 - - f0 - - f0 f1 - 1 - f1 - - f1 - - f1 f2 - - f2 - 1 - f2 - - f2 f3 - 1 - t1 - -i - f3 - - f3 f4 - - t0 - - f4 - 1 - t0 f5 - 1 - f5 - - f5 - w3 - f4 f6 - - f6 - 1 - f6 - -i - t1 f7 - 1 - t1 - -i - f7 - iw3- f6 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r - t1i; f3i = f1i + t1r; f1r = f1r + t1i; f1i = f1i - t1r; t0r = f4r + f5r; t0i = f4i + f5i; f5r = f4r - f5r; f5i = f4i - f5i; t1r = f6r - f7r; t1i = f6i - f7i; f6r = f6r + f7r; f6i = f6i + f7i; f4r = t0r + f6r; f4i = t0i + f6i; f6r = t0r - f6r; f6i = t0i - f6i; f7r = f5r - t1i; f7i = f5i + t1r; f5r = f5r + t1i; f5i = f5i - t1r; t0r = f0r - f4r; t0i = f0i - f4i; f0r = f0r + f4r; f0i = f0i + f4i; t1r = f2r - f6i; t1i = f2i + f6r; f2r = f2r + f6i; f2i = f2i - f6r; f4r = f1r - f5r * w0r - f5i * w0r; f4i = f1i + f5r * w0r - f5i * w0r; f1r = f1r * Two - f4r; f1i = f1i * Two - f4i; f6r = f3r + f7r * w0r - f7i * w0r; f6i = f3i + f7r * w0r + f7i * w0r; f3r = f3r * Two - f6r; f3i = f3i * Two - f6i; /* store result */ ioptr[0] = f0r; ioptr[1] = f0i; ioptr[2] = f1r; ioptr[3] = f1i; ioptr[4] = f2r; ioptr[5] = f2i; ioptr[6] = f3r; ioptr[7] = f3i; ioptr[8] = t0r; ioptr[9] = t0i; ioptr[10] = f4r; ioptr[11] = f4i; ioptr[12] = t1r; ioptr[13] = t1i; ioptr[14] = f6r; ioptr[15] = f6i; } inline void bfR2(float *ioptr, long M, long NDiffU); inline void bfR2(float *ioptr, long M, long NDiffU){ /*** 2nd radix 2 stage ***/ unsigned long pos; unsigned long posi; unsigned long pinc; unsigned long pnext; unsigned long NSameU; unsigned long SameUCnt; float *pstrt; float *p0r, *p1r, *p2r, *p3r; float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; const float Two = 2.0; pinc = NDiffU * 2; // 2 floats per complex pnext = pinc * 4; pos = 2; posi = pos+1; NSameU = POW2(M) / 4 /NDiffU; // 4 Us at a time pstrt = ioptr; p0r = pstrt; p1r = pstrt+pinc; p2r = p1r+pinc; p3r = p2r+pinc; /* Butterflys */ /* f0 - - f4 f1 - 1 - f5 f2 - - f6 f3 - 1 - f7 */ /* Butterflys */ /* f0 - - f4 f1 - 1 - f5 f2 - - f6 f3 - 1 - f7 */ for (SameUCnt = NSameU; SameUCnt > 0 ; SameUCnt--){ f0r = *p0r; f1r = *p1r; f0i = *(p0r + 1); f1i = *(p1r + 1); f2r = *p2r; f3r = *p3r; f2i = *(p2r + 1); f3i = *(p3r + 1); f4r = f0r + f1r; f4i = f0i + f1i; f5r = f0r - f1r; f5i = f0i - f1i; f6r = f2r + f3r; f6i = f2i + f3i; f7r = f2r - f3r; f7i = f2i - f3i; *p0r = f4r; *(p0r + 1) = f4i; *p1r = f5r; *(p1r + 1) = f5i; *p2r = f6r; *(p2r + 1) = f6i; *p3r = f7r; *(p3r + 1) = f7i; f0r = *(p0r + pos); f1i = *(p1r + posi); f0i = *(p0r + posi); f1r = *(p1r + pos); f2r = *(p2r + pos); f3i = *(p3r + posi); f2i = *(p2r + posi); f3r = *(p3r + pos); f4r = f0r + f1i; f4i = f0i - f1r; f5r = f0r - f1i; f5i = f0i + f1r; f6r = f2r + f3i; f6i = f2i - f3r; f7r = f2r - f3i; f7i = f2i + f3r; *(p0r + pos) = f4r; *(p0r + posi) = f4i; *(p1r + pos) = f5r; *(p1r + posi) = f5i; *(p2r + pos) = f6r; *(p2r + posi) = f6i; *(p3r + pos) = f7r; *(p3r + posi) = f7i; p0r += pnext; p1r += pnext; p2r += pnext; p3r += pnext; } } inline void bfR4(float *ioptr, long M, long NDiffU); inline void bfR4(float *ioptr, long M, long NDiffU){ /*** 1 radix 4 stage ***/ unsigned long pos; unsigned long posi; unsigned long pinc; unsigned long pnext; unsigned long pnexti; unsigned long NSameU; unsigned long SameUCnt; float *pstrt; float *p0r, *p1r, *p2r, *p3r; float w1r = 1.0/MYROOT2; /* cos(pi/4) */ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t1r, t1i; const float Two = 2.0; pinc = NDiffU * 2; // 2 floats per complex pnext = pinc * 4; pnexti = pnext + 1; pos = 2; posi = pos+1; NSameU = POW2(M) / 4 /NDiffU; // 4 pts per butterfly pstrt = ioptr; p0r = pstrt; p1r = pstrt+pinc; p2r = p1r+pinc; p3r = p2r+pinc; /* Butterflys */ /* f0 - - f0 - - f4 f1 - 1 - f5 - - f5 f2 - - f6 - 1 - f6 f3 - 1 - f3 - -i - f7 */ /* Butterflys */ /* f0 - - f4 - - f4 f1 - -i - t1 - - f5 f2 - - f2 - w1 - f6 f3 - -i - f7 - iw1- f7 */ f0r = *p0r; f1r = *p1r; f2r = *p2r; f3r = *p3r; f0i = *(p0r + 1); f1i = *(p1r + 1); f2i = *(p2r + 1); f3i = *(p3r + 1); f5r = f0r - f1r; f5i = f0i - f1i; f0r = f0r + f1r; f0i = f0i + f1i; f6r = f2r + f3r; f6i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; for (SameUCnt = NSameU-1; SameUCnt > 0 ; SameUCnt--){ f7r = f5r - f3i; f7i = f5i + f3r; f5r = f5r + f3i; f5i = f5i - f3r; f4r = f0r + f6r; f4i = f0i + f6i; f6r = f0r - f6r; f6i = f0i - f6i; f2r = *(p2r + pos); f2i = *(p2r + posi); f1r = *(p1r + pos); f1i = *(p1r + posi); f3i = *(p3r + posi); f0r = *(p0r + pos); f3r = *(p3r + pos); f0i = *(p0r + posi); *p3r = f7r; *p0r = f4r; *(p3r + 1) = f7i; *(p0r + 1) = f4i; *p1r = f5r; *p2r = f6r; *(p1r + 1) = f5i; *(p2r + 1) = f6i; f7r = f2r - f3i; f7i = f2i + f3r; f2r = f2r + f3i; f2i = f2i - f3r; f4r = f0r + f1i; f4i = f0i - f1r; t1r = f0r - f1i; t1i = f0i + f1r; f5r = t1r - f7r * w1r + f7i * w1r; f5i = t1i - f7r * w1r - f7i * w1r; f7r = t1r * Two - f5r; f7i = t1i * Two - f5i; f6r = f4r - f2r * w1r - f2i * w1r; f6i = f4i + f2r * w1r - f2i * w1r; f4r = f4r * Two - f6r; f4i = f4i * Two - f6i; f3r = *(p3r + pnext); f0r = *(p0r + pnext); f3i = *(p3r + pnexti); f0i = *(p0r + pnexti); f2r = *(p2r + pnext); f2i = *(p2r + pnexti); f1r = *(p1r + pnext); f1i = *(p1r + pnexti); *(p2r + pos) = f6r; *(p1r + pos) = f5r; *(p2r + posi) = f6i; *(p1r + posi) = f5i; *(p3r + pos) = f7r; *(p0r + pos) = f4r; *(p3r + posi) = f7i; *(p0r + posi) = f4i; f6r = f2r + f3r; f6i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; f5r = f0r - f1r; f5i = f0i - f1i; f0r = f0r + f1r; f0i = f0i + f1i; p3r += pnext; p0r += pnext; p1r += pnext; p2r += pnext; } f7r = f5r - f3i; f7i = f5i + f3r; f5r = f5r + f3i; f5i = f5i - f3r; f4r = f0r + f6r; f4i = f0i + f6i; f6r = f0r - f6r; f6i = f0i - f6i; f2r = *(p2r + pos); f2i = *(p2r + posi); f1r = *(p1r + pos); f1i = *(p1r + posi); f3i = *(p3r + posi); f0r = *(p0r + pos); f3r = *(p3r + pos); f0i = *(p0r + posi); *p3r = f7r; *p0r = f4r; *(p3r + 1) = f7i; *(p0r + 1) = f4i; *p1r = f5r; *p2r = f6r; *(p1r + 1) = f5i; *(p2r + 1) = f6i; f7r = f2r - f3i; f7i = f2i + f3r; f2r = f2r + f3i; f2i = f2i - f3r; f4r = f0r + f1i; f4i = f0i - f1r; t1r = f0r - f1i; t1i = f0i + f1r; f5r = t1r - f7r * w1r + f7i * w1r; f5i = t1i - f7r * w1r - f7i * w1r; f7r = t1r * Two - f5r; f7i = t1i * Two - f5i; f6r = f4r - f2r * w1r - f2i * w1r; f6i = f4i + f2r * w1r - f2i * w1r; f4r = f4r * Two - f6r; f4i = f4i * Two - f6i; *(p2r + pos) = f6r; *(p1r + pos) = f5r; *(p2r + posi) = f6i; *(p1r + posi) = f5i; *(p3r + pos) = f7r; *(p0r + pos) = f4r; *(p3r + posi) = f7i; *(p0r + posi) = f4i; } inline void bfstages(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt); inline void bfstages(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt){ /*** RADIX 8 Stages ***/ unsigned long pos; unsigned long posi; unsigned long pinc; unsigned long pnext; unsigned long NSameU; unsigned long Uinc; unsigned long Uinc2; unsigned long Uinc4; unsigned long DiffUCnt; unsigned long SameUCnt; unsigned long U2toU3; float *pstrt; float *p0r, *p1r, *p2r, *p3r; float *u0r, *u0i, *u1r, *u1i, *u2r, *u2i; float w0r, w0i, w1r, w1i, w2r, w2i, w3r, w3i; float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t0r, t0i, t1r, t1i; const float Two = 2.0; pinc = NDiffU * 2; // 2 floats per complex pnext = pinc * 8; pos = pinc * 4; posi = pos + 1; NSameU = POW2(M) / 8 /NDiffU; // 8 pts per butterfly Uinc = NSameU * Ustride; Uinc2 = Uinc * 2; Uinc4 = Uinc * 4; U2toU3 = (POW2(M) / 8)*Ustride; for (; StageCnt > 0 ; StageCnt--){ u0r = &Utbl[0]; u0i = &Utbl[POW2(M-2)*Ustride]; u1r = u0r; u1i = u0i; u2r = u0r; u2i = u0i; w0r = *u0r; w0i = *u0i; w1r = *u1r; w1i = *u1i; w2r = *u2r; w2i = *u2i; w3r = *(u2r+U2toU3); w3i = *(u2i-U2toU3); pstrt = ioptr; p0r = pstrt; p1r = pstrt+pinc; p2r = p1r+pinc; p3r = p2r+pinc; /* Butterflys */ /* f0 - - t0 - - f0 - - f0 f1 - w0- f1 - - f1 - - f1 f2 - - f2 - w1- f2 - - f4 f3 - w0- t1 - iw1- f3 - - f5 f4 - - t0 - - f4 - w2- t0 f5 - w0- f5 - - f5 - w3- t1 f6 - - f6 - w1- f6 - iw2- f6 f7 - w0- t1 - iw1- f7 - iw3- f7 */ for (DiffUCnt = NDiffU; DiffUCnt > 0 ; DiffUCnt--){ f0r = *p0r; f0i = *(p0r + 1); f1r = *p1r; f1i = *(p1r + 1); for (SameUCnt = NSameU-1; SameUCnt > 0 ; SameUCnt--){ f2r = *p2r; f2i = *(p2r + 1); f3r = *p3r; f3i = *(p3r + 1); t0r = f0r + f1r * w0r + f1i * w0i; t0i = f0i - f1r * w0i + f1i * w0r; f1r = f0r * Two - t0r; f1i = f0i * Two - t0i; f4r = *(p0r + pos); f4i = *(p0r + posi); f5r = *(p1r + pos); f5i = *(p1r + posi); f6r = *(p2r + pos); f6i = *(p2r + posi); f7r = *(p3r + pos); f7i = *(p3r + posi); t1r = f2r - f3r * w0r - f3i * w0i; t1i = f2i + f3r * w0i - f3i * w0r; f2r = f2r * Two - t1r; f2i = f2i * Two - t1i; f0r = t0r + f2r * w1r + f2i * w1i; f0i = t0i - f2r * w1i + f2i * w1r; f2r = t0r * Two - f0r; f2i = t0i * Two - f0i; f3r = f1r + t1r * w1i - t1i * w1r; f3i = f1i + t1r * w1r + t1i * w1i; f1r = f1r * Two - f3r; f1i = f1i * Two - f3i; t0r = f4r + f5r * w0r + f5i * w0i; t0i = f4i - f5r * w0i + f5i * w0r; f5r = f4r * Two - t0r; f5i = f4i * Two - t0i; t1r = f6r - f7r * w0r - f7i * w0i; t1i = f6i + f7r * w0i - f7i * w0r; f6r = f6r * Two - t1r; f6i = f6i * Two - t1i; f4r = t0r + f6r * w1r + f6i * w1i; f4i = t0i - f6r * w1i + f6i * w1r; f6r = t0r * Two - f4r; f6i = t0i * Two - f4i; f7r = f5r + t1r * w1i - t1i * w1r; f7i = f5i + t1r * w1r + t1i * w1i; f5r = f5r * Two - f7r; f5i = f5i * Two - f7i; t0r = f0r - f4r * w2r - f4i * w2i; t0i = f0i + f4r * w2i - f4i * w2r; f0r = f0r * Two - t0r; f0i = f0i * Two - t0i; t1r = f1r - f5r * w3r - f5i * w3i; t1i = f1i + f5r * w3i - f5i * w3r; f1r = f1r * Two - t1r; f1i = f1i * Two - t1i; *(p0r + pos) = t0r; *(p1r + pos) = t1r; *(p0r + posi) = t0i; *(p1r + posi) = t1i; *p0r = f0r; *p1r = f1r; *(p0r + 1) = f0i; *(p1r + 1) = f1i; p0r += pnext; f0r = *p0r; f0i = *(p0r + 1); p1r += pnext; f1r = *p1r; f1i = *(p1r + 1); f4r = f2r - f6r * w2i + f6i * w2r; f4i = f2i - f6r * w2r - f6i * w2i; f6r = f2r * Two - f4r; f6i = f2i * Two - f4i; f5r = f3r - f7r * w3i + f7i * w3r; f5i = f3i - f7r * w3r - f7i * w3i; f7r = f3r * Two - f5r; f7i = f3i * Two - f5i; *p2r = f4r; *p3r = f5r; *(p2r + 1) = f4i; *(p3r + 1) = f5i; *(p2r + pos) = f6r; *(p3r + pos) = f7r; *(p2r + posi) = f6i; *(p3r + posi) = f7i; p2r += pnext; p3r += pnext; } f2r = *p2r; f2i = *(p2r + 1); f3r = *p3r; f3i = *(p3r + 1); t0r = f0r + f1r * w0r + f1i * w0i; t0i = f0i - f1r * w0i + f1i * w0r; f1r = f0r * Two - t0r; f1i = f0i * Two - t0i; f4r = *(p0r + pos); f4i = *(p0r + posi); f5r = *(p1r + pos); f5i = *(p1r + posi); f6r = *(p2r + pos); f6i = *(p2r + posi); f7r = *(p3r + pos); f7i = *(p3r + posi); t1r = f2r - f3r * w0r - f3i * w0i; t1i = f2i + f3r * w0i - f3i * w0r; f2r = f2r * Two - t1r; f2i = f2i * Two - t1i; f0r = t0r + f2r * w1r + f2i * w1i; f0i = t0i - f2r * w1i + f2i * w1r; f2r = t0r * Two - f0r; f2i = t0i * Two - f0i; f3r = f1r + t1r * w1i - t1i * w1r; f3i = f1i + t1r * w1r + t1i * w1i; f1r = f1r * Two - f3r; f1i = f1i * Two - f3i; if (DiffUCnt == NDiffU/2) Uinc4 = -Uinc4; u0r += Uinc4; u0i -= Uinc4; u1r += Uinc2; u1i -= Uinc2; u2r += Uinc; u2i -= Uinc; pstrt += 2; t0r = f4r + f5r * w0r + f5i * w0i; t0i = f4i - f5r * w0i + f5i * w0r; f5r = f4r * Two - t0r; f5i = f4i * Two - t0i; t1r = f6r - f7r * w0r - f7i * w0i; t1i = f6i + f7r * w0i - f7i * w0r; f6r = f6r * Two - t1r; f6i = f6i * Two - t1i; f4r = t0r + f6r * w1r + f6i * w1i; f4i = t0i - f6r * w1i + f6i * w1r; f6r = t0r * Two - f4r; f6i = t0i * Two - f4i; f7r = f5r + t1r * w1i - t1i * w1r; f7i = f5i + t1r * w1r + t1i * w1i; f5r = f5r * Two - f7r; f5i = f5i * Two - f7i; w0r = *u0r; w0i = *u0i; w1r = *u1r; w1i = *u1i; if (DiffUCnt <= NDiffU/2) w0r = -w0r; t0r = f0r - f4r * w2r - f4i * w2i; t0i = f0i + f4r * w2i - f4i * w2r; f0r = f0r * Two - t0r; f0i = f0i * Two - t0i; f4r = f2r - f6r * w2i + f6i * w2r; f4i = f2i - f6r * w2r - f6i * w2i; f6r = f2r * Two - f4r; f6i = f2i * Two - f4i; *(p0r + pos) = t0r; *p2r = f4r; *(p0r + posi) = t0i; *(p2r + 1) = f4i; w2r = *u2r; w2i = *u2i; *p0r = f0r; *(p2r + pos) = f6r; *(p0r + 1) = f0i; *(p2r + posi) = f6i; p0r = pstrt; p2r = pstrt + pinc + pinc; t1r = f1r - f5r * w3r - f5i * w3i; t1i = f1i + f5r * w3i - f5i * w3r; f1r = f1r * Two - t1r; f1i = f1i * Two - t1i; f5r = f3r - f7r * w3i + f7i * w3r; f5i = f3i - f7r * w3r - f7i * w3i; f7r = f3r * Two - f5r; f7i = f3i * Two - f5i; *(p1r + pos) = t1r; *p3r = f5r; *(p1r + posi) = t1i; *(p3r + 1) = f5i; w3r = *(u2r+U2toU3); w3i = *(u2i-U2toU3); *p1r = f1r; *(p3r + pos) = f7r; *(p1r + 1) = f1i; *(p3r + posi) = f7i; p1r = pstrt + pinc; p3r = p2r + pinc; } NSameU /= 8; Uinc /= 8; Uinc2 /= 8; Uinc4 = Uinc * 4; NDiffU *= 8; pinc *= 8; pnext *= 8; pos *= 8; posi = pos + 1; } } void fftrecurs(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt); void fftrecurs(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt){ /* recursive bfstages calls to maximize on chip cache efficiency */ long i1; if (M <= MCACHE) // fits on chip ? bfstages(ioptr, M, Utbl, Ustride, NDiffU, StageCnt); /* RADIX 8 Stages */ else{ for (i1=0; i1<8; i1++){ fftrecurs(&ioptr[i1*POW2(M-3)*2], M-3, Utbl, 8*Ustride, NDiffU, StageCnt-1); /* RADIX 8 Stages */ } bfstages(ioptr, M, Utbl, Ustride, POW2(M-3), 1); /* RADIX 8 Stage */ } } void ffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow){ /* Compute in-place complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = output data array */ long StageCnt; long NDiffU; switch (M){ case 0: break; case 1: for (;Rows>0;Rows--){ fft2pt(ioptr); /* a 2 pt fft */ ioptr += 2*POW2(M); } break; case 2: for (;Rows>0;Rows--){ fft4pt(ioptr); /* a 4 pt fft */ ioptr += 2*POW2(M); } break; case 3: for (;Rows>0;Rows--){ fft8pt(ioptr); /* an 8 pt fft */ ioptr += 2*POW2(M); } break; default: for (;Rows>0;Rows--){ bitrevR2(ioptr, M, BRLow); /* bit reverse and first radix 2 stage */ StageCnt = (M-1) / 3; // number of radix 8 stages NDiffU = 2; // one radix 2 stage already complete if ( (M-1-(StageCnt * 3)) == 1 ){ bfR2(ioptr, M, NDiffU); /* 1 radix 2 stage */ NDiffU *= 2; } if ( (M-1-(StageCnt * 3)) == 2 ){ bfR4(ioptr, M, NDiffU); /* 1 radix 4 stage */ NDiffU *= 4; } if (M <= MCACHE) bfstages(ioptr, M, Utbl, 1, NDiffU, StageCnt); /* RADIX 8 Stages */ else{ fftrecurs(ioptr, M, Utbl, 1, NDiffU, StageCnt); /* RADIX 8 Stages */ } ioptr += 2*POW2(M); } } } /************************************************ parts of iffts1 *************************************************/ inline void scbitrevR2(float *ioptr, long M, short *BRLow, float scale); inline void scbitrevR2(float *ioptr, long M, short *BRLow, float scale){ /*** scaled bit reverse and first radix 2 stage forward or inverse fft ***/ float f0r; float f0i; float f1r; float f1i; float f2r; float f2i; float f3r; float f3i; float f4r; float f4i; float f5r; float f5i; float f6r; float f6i; float f7r; float f7i; float t0r; float t0i; float t1r; float t1i; float *p0r; float *p1r; float *IOP; float *iolimit; long Colstart; long iCol; unsigned long posA; unsigned long posAi; unsigned long posB; unsigned long posBi; const unsigned long Nrems2 = POW2((M+3)/2); const unsigned long Nroot_1_ColInc = POW2(M)-Nrems2; const unsigned long Nroot_1 = POW2(M/2-1)-1; const unsigned long ColstartShift = (M+1)/2 +1; posA = POW2(M); // 1/2 of POW2(M) complexes posAi = posA + 1; posB = posA + 2; posBi = posB + 1; iolimit = ioptr + Nrems2; for (; ioptr < iolimit; ioptr += POW2(M/2+1)){ for (Colstart = Nroot_1; Colstart >= 0; Colstart--){ iCol = Nroot_1; p0r = ioptr+ Nroot_1_ColInc + BRLow[Colstart]*4; IOP = ioptr + (Colstart << ColstartShift); p1r = IOP + BRLow[iCol]*4; f0r = *(p0r); f0i = *(p0r+1); f1r = *(p0r+posA); f1i = *(p0r+posAi); for (; iCol > Colstart;){ f2r = *(p0r+2); f2i = *(p0r+(2+1)); f3r = *(p0r+posB); f3i = *(p0r+posBi); f4r = *(p1r); f4i = *(p1r+1); f5r = *(p1r+posA); f5i = *(p1r+posAi); f6r = *(p1r+2); f6i = *(p1r+(2+1)); f7r = *(p1r+posB); f7i = *(p1r+posBi); t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r + f3r; t1i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; f0r = f4r + f5r; f0i = f4i + f5i; f5r = f4r - f5r; f5i = f4i - f5i; f2r = f6r + f7r; f2i = f6i + f7i; f7r = f6r - f7r; f7i = f6i - f7i; *(p1r) = scale*t0r; *(p1r+1) = scale*t0i; *(p1r+2) = scale*f1r; *(p1r+(2+1)) = scale*f1i; *(p1r+posA) = scale*t1r; *(p1r+posAi) = scale*t1i; *(p1r+posB) = scale*f3r; *(p1r+posBi) = scale*f3i; *(p0r) = scale*f0r; *(p0r+1) = scale*f0i; *(p0r+2) = scale*f5r; *(p0r+(2+1)) = scale*f5i; *(p0r+posA) = scale*f2r; *(p0r+posAi) = scale*f2i; *(p0r+posB) = scale*f7r; *(p0r+posBi) = scale*f7i; p0r -= Nrems2; f0r = *(p0r); f0i = *(p0r+1); f1r = *(p0r+posA); f1i = *(p0r+posAi); iCol -= 1; p1r = IOP + BRLow[iCol]*4; }; f2r = *(p0r+2); f2i = *(p0r+(2+1)); f3r = *(p0r+posB); f3i = *(p0r+posBi); t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r + f3r; t1i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; *(p0r) = scale*t0r; *(p0r+1) = scale*t0i; *(p0r+2) = scale*f1r; *(p0r+(2+1)) = scale*f1i; *(p0r+posA) = scale*t1r; *(p0r+posAi) = scale*t1i; *(p0r+posB) = scale*f3r; *(p0r+posBi) = scale*f3i; }; }; } inline void ifft2pt(float *ioptr, float scale); inline void ifft2pt(float *ioptr, float scale){ /*** RADIX 2 ifft ***/ float f0r, f0i, f1r, f1i; float t0r, t0i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[2]; f1i = ioptr[3]; /* Butterflys */ /* f0 - - t0 f1 - 1 - f1 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; /* store result */ ioptr[0] = scale*t0r; ioptr[1] = scale*t0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; } inline void ifft4pt(float *ioptr, float scale); inline void ifft4pt(float *ioptr, float scale){ /*** RADIX 4 ifft ***/ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float t0r, t0i, t1r, t1i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[4]; f1i = ioptr[5]; f2r = ioptr[2]; f2i = ioptr[3]; f3r = ioptr[6]; f3i = ioptr[7]; /* Butterflys */ /* f0 - - t0 - - f0 f1 - 1 - f1 - - f1 f2 - - f2 - 1 - f2 f3 - 1 - t1 - i - f3 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r + t1i; f3i = f1i - t1r; f1r = f1r - t1i; f1i = f1i + t1r; /* store result */ ioptr[0] = scale*f0r; ioptr[1] = scale*f0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; ioptr[4] = scale*f2r; ioptr[5] = scale*f2i; ioptr[6] = scale*f3r; ioptr[7] = scale*f3i; } inline void ifft8pt(float *ioptr, float scale); inline void ifft8pt(float *ioptr, float scale){ /*** RADIX 8 ifft ***/ float w0r = 1.0/MYROOT2; /* cos(pi/4) */ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t0r, t0i, t1r, t1i; const float Two = 2.0; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[8]; f1i = ioptr[9]; f2r = ioptr[4]; f2i = ioptr[5]; f3r = ioptr[12]; f3i = ioptr[13]; f4r = ioptr[2]; f4i = ioptr[3]; f5r = ioptr[10]; f5i = ioptr[11]; f6r = ioptr[6]; f6i = ioptr[7]; f7r = ioptr[14]; f7i = ioptr[15]; /* Butterflys */ /* f0 - - t0 - - f0 - - f0 f1 - 1 - f1 - - f1 - - f1 f2 - - f2 - 1 - f2 - - f2 f3 - 1 - t1 - i - f3 - - f3 f4 - - t0 - - f4 - 1 - t0 f5 - 1 - f5 - - f5 - w3 - f4 f6 - - f6 - 1 - f6 - i - t1 f7 - 1 - t1 - i - f7 - iw3- f6 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r + t1i; f3i = f1i - t1r; f1r = f1r - t1i; f1i = f1i + t1r; t0r = f4r + f5r; t0i = f4i + f5i; f5r = f4r - f5r; f5i = f4i - f5i; t1r = f6r - f7r; t1i = f6i - f7i; f6r = f6r + f7r; f6i = f6i + f7i; f4r = t0r + f6r; f4i = t0i + f6i; f6r = t0r - f6r; f6i = t0i - f6i; f7r = f5r + t1i; f7i = f5i - t1r; f5r = f5r - t1i; f5i = f5i + t1r; t0r = f0r - f4r; t0i = f0i - f4i; f0r = f0r + f4r; f0i = f0i + f4i; t1r = f2r + f6i; t1i = f2i - f6r; f2r = f2r - f6i; f2i = f2i + f6r; f4r = f1r - f5r * w0r + f5i * w0r; f4i = f1i - f5r * w0r - f5i * w0r; f1r = f1r * Two - f4r; f1i = f1i * Two - f4i; f6r = f3r + f7r * w0r + f7i * w0r; f6i = f3i - f7r * w0r + f7i * w0r; f3r = f3r * Two - f6r; f3i = f3i * Two - f6i; /* store result */ ioptr[0] = scale*f0r; ioptr[1] = scale*f0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; ioptr[4] = scale*f2r; ioptr[5] = scale*f2i; ioptr[6] = scale*f3r; ioptr[7] = scale*f3i; ioptr[8] = scale*t0r; ioptr[9] = scale*t0i; ioptr[10] = scale*f4r; ioptr[11] = scale*f4i; ioptr[12] = scale*t1r; ioptr[13] = scale*t1i; ioptr[14] = scale*f6r; ioptr[15] = scale*f6i; } inline void ibfR2(float *ioptr, long M, long NDiffU); inline void ibfR2(float *ioptr, long M, long NDiffU){ /*** 2nd radix 2 stage ***/ unsigned long pos; unsigned long posi; unsigned long pinc; unsigned long pnext; unsigned long NSameU; unsigned long SameUCnt; float *pstrt; float *p0r, *p1r, *p2r, *p3r; float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; const float Two = 2.0; pinc = NDiffU * 2; // 2 floats per complex pnext = pinc * 4; pos = 2; posi = pos+1; NSameU = POW2(M) / 4 /NDiffU; // 4 Us at a time pstrt = ioptr; p0r = pstrt; p1r = pstrt+pinc; p2r = p1r+pinc; p3r = p2r+pinc; /* Butterflys */ /* f0 - - f4 f1 - 1 - f5 f2 - - f6 f3 - 1 - f7 */ /* Butterflys */ /* f0 - - f4 f1 - 1 - f5 f2 - - f6 f3 - 1 - f7 */ for (SameUCnt = NSameU; SameUCnt > 0 ; SameUCnt--){ f0r = *p0r; f1r = *p1r; f0i = *(p0r + 1); f1i = *(p1r + 1); f2r = *p2r; f3r = *p3r; f2i = *(p2r + 1); f3i = *(p3r + 1); f4r = f0r + f1r; f4i = f0i + f1i; f5r = f0r - f1r; f5i = f0i - f1i; f6r = f2r + f3r; f6i = f2i + f3i; f7r = f2r - f3r; f7i = f2i - f3i; *p0r = f4r; *(p0r + 1) = f4i; *p1r = f5r; *(p1r + 1) = f5i; *p2r = f6r; *(p2r + 1) = f6i; *p3r = f7r; *(p3r + 1) = f7i; f0r = *(p0r + pos); f1i = *(p1r + posi); f0i = *(p0r + posi); f1r = *(p1r + pos); f2r = *(p2r + pos); f3i = *(p3r + posi); f2i = *(p2r + posi); f3r = *(p3r + pos); f4r = f0r - f1i; f4i = f0i + f1r; f5r = f0r + f1i; f5i = f0i - f1r; f6r = f2r - f3i; f6i = f2i + f3r; f7r = f2r + f3i; f7i = f2i - f3r; *(p0r + pos) = f4r; *(p0r + posi) = f4i; *(p1r + pos) = f5r; *(p1r + posi) = f5i; *(p2r + pos) = f6r; *(p2r + posi) = f6i; *(p3r + pos) = f7r; *(p3r + posi) = f7i; p0r += pnext; p1r += pnext; p2r += pnext; p3r += pnext; } } inline void ibfR4(float *ioptr, long M, long NDiffU); inline void ibfR4(float *ioptr, long M, long NDiffU){ /*** 1 radix 4 stage ***/ unsigned long pos; unsigned long posi; unsigned long pinc; unsigned long pnext; unsigned long pnexti; unsigned long NSameU; unsigned long SameUCnt; float *pstrt; float *p0r, *p1r, *p2r, *p3r; float w1r = 1.0/MYROOT2; /* cos(pi/4) */ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t1r, t1i; const float Two = 2.0; pinc = NDiffU * 2; // 2 floats per complex pnext = pinc * 4; pnexti = pnext + 1; pos = 2; posi = pos+1; NSameU = POW2(M) / 4 /NDiffU; // 4 pts per butterfly pstrt = ioptr; p0r = pstrt; p1r = pstrt+pinc; p2r = p1r+pinc; p3r = p2r+pinc; /* Butterflys */ /* f0 - - f0 - - f4 f1 - 1 - f5 - - f5 f2 - - f6 - 1 - f6 f3 - 1 - f3 - -i - f7 */ /* Butterflys */ /* f0 - - f4 - - f4 f1 - -i - t1 - - f5 f2 - - f2 - w1 - f6 f3 - -i - f7 - iw1- f7 */ f0r = *p0r; f1r = *p1r; f2r = *p2r; f3r = *p3r; f0i = *(p0r + 1); f1i = *(p1r + 1); f2i = *(p2r + 1); f3i = *(p3r + 1); f5r = f0r - f1r; f5i = f0i - f1i; f0r = f0r + f1r; f0i = f0i + f1i; f6r = f2r + f3r; f6i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; for (SameUCnt = NSameU-1; SameUCnt > 0 ; SameUCnt--){ f7r = f5r + f3i; f7i = f5i - f3r; f5r = f5r - f3i; f5i = f5i + f3r; f4r = f0r + f6r; f4i = f0i + f6i; f6r = f0r - f6r; f6i = f0i - f6i; f2r = *(p2r + pos); f2i = *(p2r + posi); f1r = *(p1r + pos); f1i = *(p1r + posi); f3i = *(p3r + posi); f0r = *(p0r + pos); f3r = *(p3r + pos); f0i = *(p0r + posi); *p3r = f7r; *p0r = f4r; *(p3r + 1) = f7i; *(p0r + 1) = f4i; *p1r = f5r; *p2r = f6r; *(p1r + 1) = f5i; *(p2r + 1) = f6i; f7r = f2r + f3i; f7i = f2i - f3r; f2r = f2r - f3i; f2i = f2i + f3r; f4r = f0r - f1i; f4i = f0i + f1r; t1r = f0r + f1i; t1i = f0i - f1r; f5r = t1r - f7r * w1r - f7i * w1r; f5i = t1i + f7r * w1r - f7i * w1r; f7r = t1r * Two - f5r; f7i = t1i * Two - f5i; f6r = f4r - f2r * w1r + f2i * w1r; f6i = f4i - f2r * w1r - f2i * w1r; f4r = f4r * Two - f6r; f4i = f4i * Two - f6i; f3r = *(p3r + pnext); f0r = *(p0r + pnext); f3i = *(p3r + pnexti); f0i = *(p0r + pnexti); f2r = *(p2r + pnext); f2i = *(p2r + pnexti); f1r = *(p1r + pnext); f1i = *(p1r + pnexti); *(p2r + pos) = f6r; *(p1r + pos) = f5r; *(p2r + posi) = f6i; *(p1r + posi) = f5i; *(p3r + pos) = f7r; *(p0r + pos) = f4r; *(p3r + posi) = f7i; *(p0r + posi) = f4i; f6r = f2r + f3r; f6i = f2i + f3i; f3r = f2r - f3r; f3i = f2i - f3i; f5r = f0r - f1r; f5i = f0i - f1i; f0r = f0r + f1r; f0i = f0i + f1i; p3r += pnext; p0r += pnext; p1r += pnext; p2r += pnext; } f7r = f5r + f3i; f7i = f5i - f3r; f5r = f5r - f3i; f5i = f5i + f3r; f4r = f0r + f6r; f4i = f0i + f6i; f6r = f0r - f6r; f6i = f0i - f6i; f2r = *(p2r + pos); f2i = *(p2r + posi); f1r = *(p1r + pos); f1i = *(p1r + posi); f3i = *(p3r + posi); f0r = *(p0r + pos); f3r = *(p3r + pos); f0i = *(p0r + posi); *p3r = f7r; *p0r = f4r; *(p3r + 1) = f7i; *(p0r + 1) = f4i; *p1r = f5r; *p2r = f6r; *(p1r + 1) = f5i; *(p2r + 1) = f6i; f7r = f2r + f3i; f7i = f2i - f3r; f2r = f2r - f3i; f2i = f2i + f3r; f4r = f0r - f1i; f4i = f0i + f1r; t1r = f0r + f1i; t1i = f0i - f1r; f5r = t1r - f7r * w1r - f7i * w1r; f5i = t1i + f7r * w1r - f7i * w1r; f7r = t1r * Two - f5r; f7i = t1i * Two - f5i; f6r = f4r - f2r * w1r + f2i * w1r; f6i = f4i - f2r * w1r - f2i * w1r; f4r = f4r * Two - f6r; f4i = f4i * Two - f6i; *(p2r + pos) = f6r; *(p1r + pos) = f5r; *(p2r + posi) = f6i; *(p1r + posi) = f5i; *(p3r + pos) = f7r; *(p0r + pos) = f4r; *(p3r + posi) = f7i; *(p0r + posi) = f4i; } inline void ibfstages(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt); inline void ibfstages(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt){ /*** RADIX 8 Stages ***/ unsigned long pos; unsigned long posi; unsigned long pinc; unsigned long pnext; unsigned long NSameU; unsigned long Uinc; unsigned long Uinc2; unsigned long Uinc4; unsigned long DiffUCnt; unsigned long SameUCnt; unsigned long U2toU3; float *pstrt; float *p0r, *p1r, *p2r, *p3r; float *u0r, *u0i, *u1r, *u1i, *u2r, *u2i; float w0r, w0i, w1r, w1i, w2r, w2i, w3r, w3i; float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t0r, t0i, t1r, t1i; const float Two = 2.0; pinc = NDiffU * 2; // 2 floats per complex pnext = pinc * 8; pos = pinc * 4; posi = pos + 1; NSameU = POW2(M) / 8 /NDiffU; // 8 pts per butterfly Uinc = NSameU * Ustride; Uinc2 = Uinc * 2; Uinc4 = Uinc * 4; U2toU3 = (POW2(M) / 8)*Ustride; for (; StageCnt > 0 ; StageCnt--){ u0r = &Utbl[0]; u0i = &Utbl[POW2(M-2)*Ustride]; u1r = u0r; u1i = u0i; u2r = u0r; u2i = u0i; w0r = *u0r; w0i = *u0i; w1r = *u1r; w1i = *u1i; w2r = *u2r; w2i = *u2i; w3r = *(u2r+U2toU3); w3i = *(u2i-U2toU3); pstrt = ioptr; p0r = pstrt; p1r = pstrt+pinc; p2r = p1r+pinc; p3r = p2r+pinc; /* Butterflys */ /* f0 - - t0 - - f0 - - f0 f1 - w0- f1 - - f1 - - f1 f2 - - f2 - w1- f2 - - f4 f3 - w0- t1 - iw1- f3 - - f5 f4 - - t0 - - f4 - w2- t0 f5 - w0- f5 - - f5 - w3- t1 f6 - - f6 - w1- f6 - iw2- f6 f7 - w0- t1 - iw1- f7 - iw3- f7 */ for (DiffUCnt = NDiffU; DiffUCnt > 0 ; DiffUCnt--){ f0r = *p0r; f0i = *(p0r + 1); f1r = *p1r; f1i = *(p1r + 1); for (SameUCnt = NSameU-1; SameUCnt > 0 ; SameUCnt--){ f2r = *p2r; f2i = *(p2r + 1); f3r = *p3r; f3i = *(p3r + 1); t0r = f0r + f1r * w0r - f1i * w0i; t0i = f0i + f1r * w0i + f1i * w0r; f1r = f0r * Two - t0r; f1i = f0i * Two - t0i; f4r = *(p0r + pos); f4i = *(p0r + posi); f5r = *(p1r + pos); f5i = *(p1r + posi); f6r = *(p2r + pos); f6i = *(p2r + posi); f7r = *(p3r + pos); f7i = *(p3r + posi); t1r = f2r - f3r * w0r + f3i * w0i; t1i = f2i - f3r * w0i - f3i * w0r; f2r = f2r * Two - t1r; f2i = f2i * Two - t1i; f0r = t0r + f2r * w1r - f2i * w1i; f0i = t0i + f2r * w1i + f2i * w1r; f2r = t0r * Two - f0r; f2i = t0i * Two - f0i; f3r = f1r + t1r * w1i + t1i * w1r; f3i = f1i - t1r * w1r + t1i * w1i; f1r = f1r * Two - f3r; f1i = f1i * Two - f3i; t0r = f4r + f5r * w0r - f5i * w0i; t0i = f4i + f5r * w0i + f5i * w0r; f5r = f4r * Two - t0r; f5i = f4i * Two - t0i; t1r = f6r - f7r * w0r + f7i * w0i; t1i = f6i - f7r * w0i - f7i * w0r; f6r = f6r * Two - t1r; f6i = f6i * Two - t1i; f4r = t0r + f6r * w1r - f6i * w1i; f4i = t0i + f6r * w1i + f6i * w1r; f6r = t0r * Two - f4r; f6i = t0i * Two - f4i; f7r = f5r + t1r * w1i + t1i * w1r; f7i = f5i - t1r * w1r + t1i * w1i; f5r = f5r * Two - f7r; f5i = f5i * Two - f7i; t0r = f0r - f4r * w2r + f4i * w2i; t0i = f0i - f4r * w2i - f4i * w2r; f0r = f0r * Two - t0r; f0i = f0i * Two - t0i; t1r = f1r - f5r * w3r + f5i * w3i; t1i = f1i - f5r * w3i - f5i * w3r; f1r = f1r * Two - t1r; f1i = f1i * Two - t1i; *(p0r + pos) = t0r; *(p0r + posi) = t0i; *p0r = f0r; *(p0r + 1) = f0i; p0r += pnext; f0r = *p0r; f0i = *(p0r + 1); *(p1r + pos) = t1r; *(p1r + posi) = t1i; *p1r = f1r; *(p1r + 1) = f1i; p1r += pnext; f1r = *p1r; f1i = *(p1r + 1); f4r = f2r - f6r * w2i - f6i * w2r; f4i = f2i + f6r * w2r - f6i * w2i; f6r = f2r * Two - f4r; f6i = f2i * Two - f4i; f5r = f3r - f7r * w3i - f7i * w3r; f5i = f3i + f7r * w3r - f7i * w3i; f7r = f3r * Two - f5r; f7i = f3i * Two - f5i; *p2r = f4r; *(p2r + 1) = f4i; *(p2r + pos) = f6r; *(p2r + posi) = f6i; p2r += pnext; *p3r = f5r; *(p3r + 1) = f5i; *(p3r + pos) = f7r; *(p3r + posi) = f7i; p3r += pnext; } f2r = *p2r; f2i = *(p2r + 1); f3r = *p3r; f3i = *(p3r + 1); t0r = f0r + f1r * w0r - f1i * w0i; t0i = f0i + f1r * w0i + f1i * w0r; f1r = f0r * Two - t0r; f1i = f0i * Two - t0i; f4r = *(p0r + pos); f4i = *(p0r + posi); f5r = *(p1r + pos); f5i = *(p1r + posi); f6r = *(p2r + pos); f6i = *(p2r + posi); f7r = *(p3r + pos); f7i = *(p3r + posi); t1r = f2r - f3r * w0r + f3i * w0i; t1i = f2i - f3r * w0i - f3i * w0r; f2r = f2r * Two - t1r; f2i = f2i * Two - t1i; f0r = t0r + f2r * w1r - f2i * w1i; f0i = t0i + f2r * w1i + f2i * w1r; f2r = t0r * Two - f0r; f2i = t0i * Two - f0i; f3r = f1r + t1r * w1i + t1i * w1r; f3i = f1i - t1r * w1r + t1i * w1i; f1r = f1r * Two - f3r; f1i = f1i * Two - f3i; if (DiffUCnt == NDiffU/2) Uinc4 = -Uinc4; u0r += Uinc4; u0i -= Uinc4; u1r += Uinc2; u1i -= Uinc2; u2r += Uinc; u2i -= Uinc; pstrt += 2; t0r = f4r + f5r * w0r - f5i * w0i; t0i = f4i + f5r * w0i + f5i * w0r; f5r = f4r * Two - t0r; f5i = f4i * Two - t0i; t1r = f6r - f7r * w0r + f7i * w0i; t1i = f6i - f7r * w0i - f7i * w0r; f6r = f6r * Two - t1r; f6i = f6i * Two - t1i; f4r = t0r + f6r * w1r - f6i * w1i; f4i = t0i + f6r * w1i + f6i * w1r; f6r = t0r * Two - f4r; f6i = t0i * Two - f4i; f7r = f5r + t1r * w1i + t1i * w1r; f7i = f5i - t1r * w1r + t1i * w1i; f5r = f5r * Two - f7r; f5i = f5i * Two - f7i; w0r = *u0r; w0i = *u0i; w1r = *u1r; w1i = *u1i; if (DiffUCnt <= NDiffU/2) w0r = -w0r; t0r = f0r - f4r * w2r + f4i * w2i; t0i = f0i - f4r * w2i - f4i * w2r; f0r = f0r * Two - t0r; f0i = f0i * Two - t0i; f4r = f2r - f6r * w2i - f6i * w2r; f4i = f2i + f6r * w2r - f6i * w2i; f6r = f2r * Two - f4r; f6i = f2i * Two - f4i; *(p0r + pos) = t0r; *p2r = f4r; *(p0r + posi) = t0i; *(p2r + 1) = f4i; w2r = *u2r; w2i = *u2i; *p0r = f0r; *(p2r + pos) = f6r; *(p0r + 1) = f0i; *(p2r + posi) = f6i; p0r = pstrt; p2r = pstrt + pinc + pinc; t1r = f1r - f5r * w3r + f5i * w3i; t1i = f1i - f5r * w3i - f5i * w3r; f1r = f1r * Two - t1r; f1i = f1i * Two - t1i; f5r = f3r - f7r * w3i - f7i * w3r; f5i = f3i + f7r * w3r - f7i * w3i; f7r = f3r * Two - f5r; f7i = f3i * Two - f5i; *(p1r + pos) = t1r; *p3r = f5r; *(p1r + posi) = t1i; *(p3r + 1) = f5i; w3r = *(u2r+U2toU3); w3i = *(u2i-U2toU3); *p1r = f1r; *(p3r + pos) = f7r; *(p1r + 1) = f1i; *(p3r + posi) = f7i; p1r = pstrt + pinc; p3r = p2r + pinc; } NSameU /= 8; Uinc /= 8; Uinc2 /= 8; Uinc4 = Uinc * 4; NDiffU *= 8; pinc *= 8; pnext *= 8; pos *= 8; posi = pos + 1; } } void ifftrecurs(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt); void ifftrecurs(float *ioptr, long M, float *Utbl, long Ustride, long NDiffU, long StageCnt){ /* recursive bfstages calls to maximize on chip cache efficiency */ long i1; if (M <= MCACHE) ibfstages(ioptr, M, Utbl, Ustride, NDiffU, StageCnt); /* RADIX 8 Stages */ else{ for (i1=0; i1<8; i1++){ ifftrecurs(&ioptr[i1*POW2(M-3)*2], M-3, Utbl, 8*Ustride, NDiffU, StageCnt-1); /* RADIX 8 Stages */ } ibfstages(ioptr, M, Utbl, Ustride, POW2(M-3), 1); /* RADIX 8 Stage */ } } void iffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow){ /* Compute in-place inverse complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = output data array */ long StageCnt; long NDiffU; const float scale = 1.0/POW2(M); switch (M){ case 0: break; case 1: for (;Rows>0;Rows--){ ifft2pt(ioptr, scale); /* a 2 pt fft */ ioptr += 2*POW2(M); } break; case 2: for (;Rows>0;Rows--){ ifft4pt(ioptr, scale); /* a 4 pt fft */ ioptr += 2*POW2(M); } break; case 3: for (;Rows>0;Rows--){ ifft8pt(ioptr, scale); /* an 8 pt fft */ ioptr += 2*POW2(M); } break; default: for (;Rows>0;Rows--){ scbitrevR2(ioptr, M, BRLow, scale); /* bit reverse and first radix 2 stage */ StageCnt = (M-1) / 3; // number of radix 8 stages NDiffU = 2; // one radix 2 stage already complete if ( (M-1-(StageCnt * 3)) == 1 ){ ibfR2(ioptr, M, NDiffU); /* 1 radix 2 stage */ NDiffU *= 2; } if ( (M-1-(StageCnt * 3)) == 2 ){ ibfR4(ioptr, M, NDiffU); /* 1 radix 4 stage */ NDiffU *= 4; } if (M <= MCACHE) ibfstages(ioptr, M, Utbl, 1, NDiffU, StageCnt); /* RADIX 8 Stages */ else{ ifftrecurs(ioptr, M, Utbl, 1, NDiffU, StageCnt); /* RADIX 8 Stages */ } ioptr += 2*POW2(M); } } } /************************************************ parts of rffts1 *************************************************/ inline void rfft1pt(float *ioptr); inline void rfft1pt(float *ioptr){ /*** RADIX 2 rfft ***/ float f0r, f0i; float t0r, t0i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; /* finish rfft */ t0r = f0r + f0i; t0i = f0r - f0i; /* store result */ ioptr[0] = t0r; ioptr[1] = t0i; } inline void rfft2pt(float *ioptr); inline void rfft2pt(float *ioptr){ /*** RADIX 4 rfft ***/ float f0r, f0i, f1r, f1i; float t0r, t0i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[2]; f1i = ioptr[3]; /* Butterflys */ /* f0 - - t0 f1 - 1 - f1 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f1i - f0i; /* finish rfft */ f0r = t0r + t0i; f0i = t0r - t0i; /* store result */ ioptr[0] = f0r; ioptr[1] = f0i; ioptr[2] = f1r; ioptr[3] = f1i; } inline void rfft4pt(float *ioptr); inline void rfft4pt(float *ioptr){ /*** RADIX 8 rfft ***/ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float t0r, t0i, t1r, t1i; float w0r = 1.0/MYROOT2; /* cos(pi/4) */ const float Two = 2.0; const float scale = 0.5; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[4]; f1i = ioptr[5]; f2r = ioptr[2]; f2i = ioptr[3]; f3r = ioptr[6]; f3i = ioptr[7]; /* Butterflys */ /* f0 - - t0 - - f0 f1 - 1 - f1 - - f1 f2 - - f2 - 1 - f2 f3 - 1 - t1 - -i - f3 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = f2i - t0i; // neg for rfft f3r = f1r - t1i; f3i = f1i + t1r; f1r = f1r + t1i; f1i = f1i - t1r; /* finish rfft */ t0r = f0r + f0i; /* compute Re(x[0]) */ t0i = f0r - f0i; /* compute Re(x[N/2]) */ t1r = f1r + f3r; t1i = f1i - f3i; f0r = f1i + f3i; f0i = f3r - f1r; f1r = t1r + w0r * f0r + w0r * f0i; f1i = t1i - w0r * f0r + w0r * f0i; f3r = Two * t1r - f1r; f3i = f1i - Two * t1i; /* store result */ ioptr[4] = f2r; ioptr[5] = f2i; ioptr[0] = t0r; ioptr[1] = t0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; ioptr[6] = scale*f3r; ioptr[7] = scale*f3i; } inline void rfft8pt(float *ioptr); inline void rfft8pt(float *ioptr){ /*** RADIX 16 rfft ***/ float w0r = 1.0/MYROOT2; /* cos(pi/4) */ float w1r = MYCOSPID8; /* cos(pi/8) */ float w1i = MYSINPID8; /* sin(pi/8) */ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t0r, t0i, t1r, t1i; const float Two = 2.0; const float scale = 0.5; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; f1r = ioptr[8]; f1i = ioptr[9]; f2r = ioptr[4]; f2i = ioptr[5]; f3r = ioptr[12]; f3i = ioptr[13]; f4r = ioptr[2]; f4i = ioptr[3]; f5r = ioptr[10]; f5i = ioptr[11]; f6r = ioptr[6]; f6i = ioptr[7]; f7r = ioptr[14]; f7i = ioptr[15]; /* Butterflys */ /* f0 - - t0 - - f0 - - f0 f1 - 1 - f1 - - f1 - - f1 f2 - - f2 - 1 - f2 - - f2 f3 - 1 - t1 - -i - f3 - - f3 f4 - - t0 - - f4 - 1 - t0 f5 - 1 - f5 - - f5 - w3 - f4 f6 - - f6 - 1 - f6 - -i - t1 f7 - 1 - t1 - -i - f7 - iw3- f6 */ t0r = f0r + f1r; t0i = f0i + f1i; f1r = f0r - f1r; f1i = f0i - f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r - t1i; f3i = f1i + t1r; f1r = f1r + t1i; f1i = f1i - t1r; t0r = f4r + f5r; t0i = f4i + f5i; f5r = f4r - f5r; f5i = f4i - f5i; t1r = f6r - f7r; t1i = f6i - f7i; f6r = f6r + f7r; f6i = f6i + f7i; f4r = t0r + f6r; f4i = t0i + f6i; f6r = t0r - f6r; f6i = t0i - f6i; f7r = f5r - t1i; f7i = f5i + t1r; f5r = f5r + t1i; f5i = f5i - t1r; t0r = f0r - f4r; t0i = f4i - f0i; // neg for rfft f0r = f0r + f4r; f0i = f0i + f4i; t1r = f2r - f6i; t1i = f2i + f6r; f2r = f2r + f6i; f2i = f2i - f6r; f4r = f1r - f5r * w0r - f5i * w0r; f4i = f1i + f5r * w0r - f5i * w0r; f1r = f1r * Two - f4r; f1i = f1i * Two - f4i; f6r = f3r + f7r * w0r - f7i * w0r; f6i = f3i + f7r * w0r + f7i * w0r; f3r = f3r * Two - f6r; f3i = f3i * Two - f6i; /* finish rfft */ f5r = f0r + f0i; /* compute Re(x[0]) */ f5i = f0r - f0i; /* compute Re(x[N/2]) */ f0r = f2r + t1r; f0i = f2i - t1i; f7r = f2i + t1i; f7i = t1r - f2r; f2r = f0r + w0r * f7r + w0r * f7i; f2i = f0i - w0r * f7r + w0r * f7i; t1r = Two * f0r - f2r; t1i = f2i - Two * f0i; f0r = f1r + f6r; f0i = f1i - f6i; f7r = f1i + f6i; f7i = f6r - f1r; f1r = f0r + w1r * f7r + w1i * f7i; f1i = f0i - w1i * f7r + w1r * f7i; f6r = Two * f0r - f1r; f6i = f1i - Two * f0i; f0r = f3r + f4r; f0i = f3i - f4i; f7r = f3i + f4i; f7i = f4r - f3r; f3r = f0r + w1i * f7r + w1r * f7i; f3i = f0i - w1r * f7r + w1i * f7i; f4r = Two * f0r - f3r; f4i = f3i - Two * f0i; /* store result */ ioptr[8] = t0r; ioptr[9] = t0i; ioptr[0] = f5r; ioptr[1] = f5i; ioptr[4] = scale*f2r; ioptr[5] = scale*f2i; ioptr[12] = scale*t1r; ioptr[13] = scale*t1i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; ioptr[6] = scale*f3r; ioptr[7] = scale*f3i; ioptr[10] = scale*f4r; ioptr[11] = scale*f4i; ioptr[14] = scale*f6r; ioptr[15] = scale*f6i; } inline void frstage(float *ioptr, long M, float *Utbl); inline void frstage(float *ioptr, long M, float *Utbl){ /* Finish RFFT */ unsigned long pos; unsigned long posi; unsigned long diffUcnt; float *p0r, *p1r; float *u0r, *u0i; float w0r, w0i; float f0r, f0i, f1r, f1i, f4r, f4i, f5r, f5i; float t0r, t0i, t1r, t1i; const float Two = 2.0; pos = POW2(M-1); posi = pos + 1; p0r = ioptr; p1r = ioptr + pos/2; u0r = Utbl + POW2(M-3); w0r = *u0r, f0r = *(p0r); f0i = *(p0r + 1); f4r = *(p0r + pos); f4i = *(p0r + posi); f1r = *(p1r); f1i = *(p1r + 1); f5r = *(p1r + pos); f5i = *(p1r + posi); t0r = Two * f0r + Two * f0i; /* compute Re(x[0]) */ t0i = Two * f0r - Two * f0i; /* compute Re(x[N/2]) */ t1r = f4r + f4r; t1i = -f4i - f4i; f0r = f1r + f5r; f0i = f1i - f5i; f4r = f1i + f5i; f4i = f5r - f1r; f1r = f0r + w0r * f4r + w0r * f4i; f1i = f0i - w0r * f4r + w0r * f4i; f5r = Two * f0r - f1r; f5i = f1i - Two * f0i; *(p0r) = t0r; *(p0r + 1) = t0i; *(p0r + pos) = t1r; *(p0r + posi) = t1i; *(p1r) = f1r; *(p1r + 1) = f1i; *(p1r + pos) = f5r; *(p1r + posi) = f5i; u0r = Utbl + 1; u0i = Utbl + (POW2(M-2)-1); w0r = *u0r, w0i = *u0i; p0r = (ioptr + 2); p1r = (ioptr + (POW2(M-2)-1)*2); /* Butterflys */ /* f0 - t0 - - f0 f5 - t1 - w0 - f5 f1 - t0 - - f1 f4 - t1 -iw0 - f4 */ for (diffUcnt = POW2(M-3)-1; diffUcnt > 0 ; diffUcnt--){ f0r = *(p0r); f0i = *(p0r + 1); f5r = *(p1r + pos); f5i = *(p1r + posi); f1r = *(p1r); f1i = *(p1r + 1); f4r = *(p0r + pos); f4i = *(p0r + posi); t0r = f0r + f5r; t0i = f0i - f5i; t1r = f0i + f5i; t1i = f5r - f0r; f0r = t0r + w0r * t1r + w0i * t1i; f0i = t0i - w0i * t1r + w0r * t1i; f5r = Two * t0r - f0r; f5i = f0i - Two * t0i; t0r = f1r + f4r; t0i = f1i - f4i; t1r = f1i + f4i; t1i = f4r - f1r; f1r = t0r + w0i * t1r + w0r * t1i; f1i = t0i - w0r * t1r + w0i * t1i; f4r = Two * t0r - f1r; f4i = f1i - Two * t0i; *(p0r) = f0r; *(p0r + 1) = f0i; *(p1r + pos) = f5r; *(p1r + posi) = f5i; w0r = *++u0r; w0i = *--u0i; *(p1r) = f1r; *(p1r + 1) = f1i; *(p0r + pos) = f4r; *(p0r + posi) = f4i; p0r += 2; p1r -= 2; }; } void rffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow){ /* Compute in-place real fft on the rows of the input array */ /* The result is the complex spectra of the positive frequencies */ /* except the location for the first complex number contains the real */ /* values for DC and Nyquest */ /* INPUTS */ /* *ioptr = real input data array */ /* M = log2 of fft size */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = output data array in the following order */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ float scale; long StageCnt; long NDiffU; M=M-1; switch (M){ case -1: break; case 0: for (;Rows>0;Rows--){ rfft1pt(ioptr); /* a 2 pt fft */ ioptr += 2*POW2(M); } case 1: for (;Rows>0;Rows--){ rfft2pt(ioptr); /* a 4 pt fft */ ioptr += 2*POW2(M); } break; case 2: for (;Rows>0;Rows--){ rfft4pt(ioptr); /* an 8 pt fft */ ioptr += 2*POW2(M); } break; case 3: for (;Rows>0;Rows--){ rfft8pt(ioptr); /* a 16 pt fft */ ioptr += 2*POW2(M); } break; default: scale = 0.5; for (;Rows>0;Rows--){ scbitrevR2(ioptr, M, BRLow, scale); /* bit reverse and first radix 2 stage */ StageCnt = (M-1) / 3; // number of radix 8 stages NDiffU = 2; // one radix 2 stage already complete if ( (M-1-(StageCnt * 3)) == 1 ){ bfR2(ioptr, M, NDiffU); /* 1 radix 2 stage */ NDiffU *= 2; } if ( (M-1-(StageCnt * 3)) == 2 ){ bfR4(ioptr, M, NDiffU); /* 1 radix 4 stage */ NDiffU *= 4; } if (M <= MCACHE){ bfstages(ioptr, M, Utbl, 2, NDiffU, StageCnt); /* RADIX 8 Stages */ frstage(ioptr, M+1, Utbl); } else{ fftrecurs(ioptr, M, Utbl, 2, NDiffU, StageCnt); /* RADIX 8 Stages */ frstage(ioptr, M+1, Utbl); } ioptr += 2*POW2(M); } } } /************************************************ parts of riffts1 *************************************************/ inline void rifft1pt(float *ioptr, float scale); inline void rifft1pt(float *ioptr, float scale){ /*** RADIX 2 rifft ***/ float f0r, f0i; float t0r, t0i; /* bit reversed load */ f0r = ioptr[0]; f0i = ioptr[1]; /* finish rfft */ t0r = f0r + f0i; t0i = f0r - f0i; /* store result */ ioptr[0] = scale*t0r; ioptr[1] = scale*t0i; } inline void rifft2pt(float *ioptr, float scale); inline void rifft2pt(float *ioptr, float scale){ /*** RADIX 4 rifft ***/ float f0r, f0i, f1r, f1i; float t0r, t0i; const float Two = 2.0; /* bit reversed load */ t0r = ioptr[0]; t0i = ioptr[1]; f1r = Two * ioptr[2]; f1i = Two * ioptr[3]; /* start rifft */ f0r = t0r + t0i; f0i = t0r - t0i; /* Butterflys */ /* f0 - - t0 f1 - 1 - f1 */ t0r = f0r + f1r; t0i = f0i - f1i; f1r = f0r - f1r; f1i = f0i + f1i; /* store result */ ioptr[0] = scale*t0r; ioptr[1] = scale*t0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; } inline void rifft4pt(float *ioptr, float scale); inline void rifft4pt(float *ioptr, float scale){ /*** RADIX 8 rifft ***/ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float t0r, t0i, t1r, t1i; float w0r = 1.0/MYROOT2; /* cos(pi/4) */ const float Two = 2.0; /* bit reversed load */ t0r = ioptr[0]; t0i = ioptr[1]; f2r = ioptr[2]; f2i = ioptr[3]; f1r = Two * ioptr[4]; f1i = Two * ioptr[5]; f3r = ioptr[6]; f3i = ioptr[7]; /* start rfft */ f0r = t0r + t0i; /* compute Re(x[0]) */ f0i = t0r - t0i; /* compute Re(x[N/2]) */ t1r = f2r + f3r; t1i = f2i - f3i; t0r = f2r - f3r; t0i = f2i + f3i; f2r = t1r - w0r * t0r - w0r * t0i; f2i = t1i + w0r * t0r - w0r * t0i; f3r = Two * t1r - f2r; f3i = f2i - Two * t1i; /* Butterflys */ /* f0 - - t0 - - f0 f1 - 1 - f1 - - f1 f2 - - f2 - 1 - f2 f3 - 1 - t1 - i - f3 */ t0r = f0r + f1r; t0i = f0i - f1i; f1r = f0r - f1r; f1i = f0i + f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r + t1i; f3i = f1i - t1r; f1r = f1r - t1i; f1i = f1i + t1r; /* store result */ ioptr[0] = scale*f0r; ioptr[1] = scale*f0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; ioptr[4] = scale*f2r; ioptr[5] = scale*f2i; ioptr[6] = scale*f3r; ioptr[7] = scale*f3i; } inline void rifft8pt(float *ioptr, float scale); inline void rifft8pt(float *ioptr, float scale){ /*** RADIX 16 rifft ***/ float w0r = 1.0/MYROOT2; /* cos(pi/4) */ float w1r = MYCOSPID8; /* cos(pi/8) */ float w1i = MYSINPID8; /* sin(pi/8) */ float f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; float f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; float t0r, t0i, t1r, t1i; const float Two = 2.0; /* bit reversed load */ t0r = ioptr[0]; t0i = ioptr[1]; f4r = ioptr[2]; f4i = ioptr[3]; f2r = ioptr[4]; f2i = ioptr[5]; f6r = ioptr[6]; f6i = ioptr[7]; f1r = Two * ioptr[8]; f1i = Two * ioptr[9]; f5r = ioptr[10]; f5i = ioptr[11]; f3r = ioptr[12]; f3i = ioptr[13]; f7r = ioptr[14]; f7i = ioptr[15]; /* start rfft */ f0r = t0r + t0i; /* compute Re(x[0]) */ f0i = t0r - t0i; /* compute Re(x[N/2]) */ t0r = f2r + f3r; t0i = f2i - f3i; t1r = f2r - f3r; t1i = f2i + f3i; f2r = t0r - w0r * t1r - w0r * t1i; f2i = t0i + w0r * t1r - w0r * t1i; f3r = Two * t0r - f2r; f3i = f2i - Two * t0i; t0r = f4r + f7r; t0i = f4i - f7i; t1r = f4r - f7r; t1i = f4i + f7i; f4r = t0r - w1i * t1r - w1r * t1i; f4i = t0i + w1r * t1r - w1i * t1i; f7r = Two * t0r - f4r; f7i = f4i - Two * t0i; t0r = f6r + f5r; t0i = f6i - f5i; t1r = f6r - f5r; t1i = f6i + f5i; f6r = t0r - w1r * t1r - w1i * t1i; f6i = t0i + w1i * t1r - w1r * t1i; f5r = Two * t0r - f6r; f5i = f6i - Two * t0i; /* Butterflys */ /* f0 - - t0 - - f0 - - f0 f1* - 1 - f1 - - f1 - - f1 f2 - - f2 - 1 - f2 - - f2 f3 - 1 - t1 - i - f3 - - f3 f4 - - t0 - - f4 - 1 - t0 f5 - 1 - f5 - - f5 - w3 - f4 f6 - - f6 - 1 - f6 - i - t1 f7 - 1 - t1 - i - f7 - iw3- f6 */ t0r = f0r + f1r; t0i = f0i - f1i; f1r = f0r - f1r; f1i = f0i + f1i; t1r = f2r - f3r; t1i = f2i - f3i; f2r = f2r + f3r; f2i = f2i + f3i; f0r = t0r + f2r; f0i = t0i + f2i; f2r = t0r - f2r; f2i = t0i - f2i; f3r = f1r + t1i; f3i = f1i - t1r; f1r = f1r - t1i; f1i = f1i + t1r; t0r = f4r + f5r; t0i = f4i + f5i; f5r = f4r - f5r; f5i = f4i - f5i; t1r = f6r - f7r; t1i = f6i - f7i; f6r = f6r + f7r; f6i = f6i + f7i; f4r = t0r + f6r; f4i = t0i + f6i; f6r = t0r - f6r; f6i = t0i - f6i; f7r = f5r + t1i; f7i = f5i - t1r; f5r = f5r - t1i; f5i = f5i + t1r; t0r = f0r - f4r; t0i = f0i - f4i; f0r = f0r + f4r; f0i = f0i + f4i; t1r = f2r + f6i; t1i = f2i - f6r; f2r = f2r - f6i; f2i = f2i + f6r; f4r = f1r - f5r * w0r + f5i * w0r; f4i = f1i - f5r * w0r - f5i * w0r; f1r = f1r * Two - f4r; f1i = f1i * Two - f4i; f6r = f3r + f7r * w0r + f7i * w0r; f6i = f3i - f7r * w0r + f7i * w0r; f3r = f3r * Two - f6r; f3i = f3i * Two - f6i; /* store result */ ioptr[0] = scale*f0r; ioptr[1] = scale*f0i; ioptr[2] = scale*f1r; ioptr[3] = scale*f1i; ioptr[4] = scale*f2r; ioptr[5] = scale*f2i; ioptr[6] = scale*f3r; ioptr[7] = scale*f3i; ioptr[8] = scale*t0r; ioptr[9] = scale*t0i; ioptr[10] = scale*f4r; ioptr[11] = scale*f4i; ioptr[12] = scale*t1r; ioptr[13] = scale*t1i; ioptr[14] = scale*f6r; ioptr[15] = scale*f6i; } inline void ifrstage(float *ioptr, long M, float *Utbl); inline void ifrstage(float *ioptr, long M, float *Utbl){ /* Start RIFFT */ unsigned long pos; unsigned long posi; unsigned long diffUcnt; float *p0r, *p1r; float *u0r, *u0i; float w0r, w0i; float f0r, f0i, f1r, f1i, f4r, f4i, f5r, f5i; float t0r, t0i, t1r, t1i; const float Two = 2.0; pos = POW2(M-1); posi = pos + 1; p0r = ioptr; p1r = ioptr + pos/2; u0r = Utbl + POW2(M-3); w0r = *u0r, f0r = *(p0r); f0i = *(p0r + 1); f4r = *(p0r + pos); f4i = *(p0r + posi); f1r = *(p1r); f1i = *(p1r + 1); f5r = *(p1r + pos); f5i = *(p1r + posi); t0r = f0r + f0i; t0i = f0r - f0i; t1r = f4r + f4r; t1i = -f4i - f4i; f0r = f1r + f5r; f0i = f1i - f5i; f4r = f1r - f5r; f4i = f1i + f5i; f1r = f0r - w0r * f4r - w0r * f4i; f1i = f0i + w0r * f4r - w0r * f4i; f5r = Two * f0r - f1r; f5i = f1i - Two * f0i; *(p0r) = t0r; *(p0r + 1) = t0i; *(p0r + pos) = t1r; *(p0r + posi) = t1i; *(p1r) = f1r; *(p1r + 1) = f1i; *(p1r + pos) = f5r; *(p1r + posi) = f5i; u0r = Utbl + 1; u0i = Utbl + (POW2(M-2)-1); w0r = *u0r, w0i = *u0i; p0r = (ioptr + 2); p1r = (ioptr + (POW2(M-2)-1)*2); /* Butterflys */ /* f0 - t0 - f0 f1 - t1 -w0- f1 f2 - t0 - f2 f3 - t1 -iw0- f3 */ for (diffUcnt = POW2(M-3)-1; diffUcnt > 0 ; diffUcnt--){ f0r = *(p0r); f0i = *(p0r + 1); f5r = *(p1r + pos); f5i = *(p1r + posi); f1r = *(p1r); f1i = *(p1r + 1); f4r = *(p0r + pos); f4i = *(p0r + posi); t0r = f0r + f5r; t0i = f0i - f5i; t1r = f0r - f5r; t1i = f0i + f5i; f0r = t0r - w0i * t1r - w0r * t1i; f0i = t0i + w0r * t1r - w0i * t1i; f5r = Two * t0r - f0r; f5i = f0i - Two * t0i; t0r = f1r + f4r; t0i = f1i - f4i; t1r = f1r - f4r; t1i = f1i + f4i; f1r = t0r - w0r * t1r - w0i * t1i; f1i = t0i + w0i * t1r - w0r * t1i; f4r = Two * t0r - f1r; f4i = f1i - Two * t0i; *(p0r) = f0r; *(p0r + 1) = f0i; *(p1r + pos) = f5r; *(p1r + posi) = f5i; w0r = *++u0r; w0i = *--u0i; *(p1r) = f1r; *(p1r + 1) = f1i; *(p0r + pos) = f4r; *(p0r + posi) = f4i; p0r += 2; p1r -= 2; }; } void riffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow){ /* Compute in-place real ifft on the rows of the input array */ /* data order as from rffts1 */ /* INPUTS */ /* *ioptr = input data array in the following order */ /* M = log2 of fft size */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = real output data array */ float scale; long StageCnt; long NDiffU; scale = 1.0/POW2(M); M=M-1; switch (M){ case -1: break; case 0: for (;Rows>0;Rows--){ rifft1pt(ioptr, scale); /* a 2 pt fft */ ioptr += 2*POW2(M); } case 1: for (;Rows>0;Rows--){ rifft2pt(ioptr, scale); /* a 4 pt fft */ ioptr += 2*POW2(M); } break; case 2: for (;Rows>0;Rows--){ rifft4pt(ioptr, scale); /* an 8 pt fft */ ioptr += 2*POW2(M); } break; case 3: for (;Rows>0;Rows--){ rifft8pt(ioptr, scale); /* a 16 pt fft */ ioptr += 2*POW2(M); } break; default: for (;Rows>0;Rows--){ ifrstage(ioptr, M+1, Utbl); scbitrevR2(ioptr, M, BRLow, scale); /* bit reverse and first radix 2 stage */ StageCnt = (M-1) / 3; // number of radix 8 stages NDiffU = 2; // one radix 2 stage already complete if ( (M-1-(StageCnt * 3)) == 1 ){ ibfR2(ioptr, M, NDiffU); /* 1 radix 2 stage */ NDiffU *= 2; } if ( (M-1-(StageCnt * 3)) == 2 ){ ibfR4(ioptr, M, NDiffU); /* 1 radix 4 stage */ NDiffU *= 4; } if (M <= MCACHE){ ibfstages(ioptr, M, Utbl, 2, NDiffU, StageCnt); /* RADIX 8 Stages */ } else{ ifftrecurs(ioptr, M, Utbl, 2, NDiffU, StageCnt); /* RADIX 8 Stages */ } ioptr += 2*POW2(M); } } } nyquist-3.05/ffts/src/dxpose.c0000644000175000000620000000422411466723256015400 0ustar stevestaff/********************* This matrix transpose is in a seperate file because it should always be double precision. *********************/ #include "dxpose.h" void dxpose(xdouble *indata, long iRsiz, xdouble *outdata, long oRsiz, long Nrows, long Ncols){ /* not in-place double precision matrix transpose */ /* INPUTS */ /* *indata = input data array */ /* iRsiz = offset to between rows of input data array */ /* oRsiz = offset to between rows of output data array */ /* Nrows = number of rows in input data array */ /* Ncols = number of columns in input data array */ /* OUTPUTS */ /* *outdata = output data array */ xdouble *irow; /* pointer to input row start */ xdouble *ocol; /* pointer to output col start */ xdouble *idata; /* pointer to input data */ xdouble *odata; /* pointer to output data */ long RowCnt; /* row counter */ long ColCnt; /* col counter */ xdouble T0; /* data storage */ xdouble T1; /* data storage */ xdouble T2; /* data storage */ xdouble T3; /* data storage */ xdouble T4; /* data storage */ xdouble T5; /* data storage */ xdouble T6; /* data storage */ xdouble T7; /* data storage */ const long inRsizd1 = iRsiz; const long inRsizd2 = 2*iRsiz; const long inRsizd3 = inRsizd2+iRsiz; const long inRsizd4 = 4*iRsiz; const long inRsizd5 = inRsizd3+inRsizd2; const long inRsizd6 = inRsizd4+inRsizd2; const long inRsizd7 = inRsizd4+inRsizd3; const long inRsizd8 = 8*iRsiz; ocol = outdata; irow = indata; for (RowCnt=Nrows/8; RowCnt>0; RowCnt--){ idata = irow; odata = ocol; for (ColCnt=Ncols; ColCnt>0; ColCnt--){ T0 = *idata; T1 = *(idata+inRsizd1); T2 = *(idata+inRsizd2); T3 = *(idata+inRsizd3); T4 = *(idata+inRsizd4); T5 = *(idata+inRsizd5); T6 = *(idata+inRsizd6); T7 = *(idata+inRsizd7); *odata = T0; *(odata+1) = T1; *(odata+2) = T2; *(odata+3) = T3; *(odata+4) = T4; *(odata+5) = T5; *(odata+6) = T6; *(odata+7) = T7; idata++; odata += oRsiz; } irow += inRsizd8; ocol += 8; } if (Nrows%8 != 0){ for (ColCnt=Ncols; ColCnt>0; ColCnt--){ idata = irow++; odata = ocol; ocol += oRsiz; for (RowCnt=Nrows%8; RowCnt>0; RowCnt--){ T0 = *idata; *odata++ = T0; idata += iRsiz; } } } } nyquist-3.05/ffts/src/fft2d.h0000644000175000000620000001160511466723256015111 0ustar stevestaff/******************************************************************* This file extends the fftlib with 2d and 3d complex fft's and 2d real fft's. All fft's return results in-place. Temporary buffers for transposing columns are maintained privately via calls to fft2dInit, fft2dFree, fft3dInit, and fft3dFree. Note that you can call fft2dInit and fft3dInit repeatedly with the same sizes, the extra calls will be ignored. So, you could make a macro to call fft2dInit every time you call fft2d. *** Warning *** fft2dFree and fft3dFree also call fftFree so you must re-init all 1d fft sizes you are going to continue using *******************************************************************/ int fft2dInit(long M2, long M); // init for fft2d, ifft2d, rfft2d, and rifft2d // malloc storage for columns of 2d ffts then call fftinit for both row and column ffts sizes /* INPUTS */ /* M = log2 of number of columns */ /* M2 = log2 of number of rows */ /* of 2d matrix to be fourier transformed */ /* OUTPUTS */ /* private storage for columns of 2d ffts */ /* calls fftInit for cosine and bit reversed tables */ void fft2dFree(); // free storage for columns of all 2d&3d ffts and call fftFree to free all BRLow and Utbl storage void fft2d(float *data, long M2, long M); /* Compute 2D complex fft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ void ifft2d(float *data, long M2, long M); /* Compute 2D complex ifft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ int fft3dInit(long L, long M2, long M); // init for fft3d, ifft3d // malloc storage for 4 columns and 4 pages of 3d ffts // then call fftinit for page, row and column ffts sizes /* M = log2 of number of columns */ /* M2 = log2 of number of rows */ /* L = log2 of number of pages */ /* of 3d matrix to be fourier transformed */ /* OUTPUTS */ /* private storage for columns and pages of 3d ffts */ /* calls fftInit for cosine and bit reversed tables */ void fft3dFree(); // free storage for columns of all 2d&3d ffts and call fftFree to free all BRLow and Utbl storage void fft3d(float *data, long M3, long M2, long M); /* Compute 2D complex fft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M3 = log2 of fft size number of pages */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ void ifft3d(float *data, long M3, long M2, long M); /* Compute 2D complex ifft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M3 = log2 of fft size number of pages */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ void rfft2d(float *data, long M2, long M); /* Compute 2D real fft and return results in-place */ /* First performs real fft on rows using size from M to compute positive frequencies */ /* then performs transform on columns using size from M2 to compute wavenumbers */ /* If you think of the result as a complex pow(2,M2) by pow(2,M-1) matrix */ /* then the first column contains the positive wavenumber spectra of DC frequency */ /* followed by the positive wavenumber spectra of the nyquest frequency */ /* since these are two positive wavenumber spectra the first complex value */ /* of each is really the real values for the zero and nyquest wavenumber packed together */ /* All other columns contain the positive and negative wavenumber spectra of a positive frequency */ /* See rspect2dprod for multiplying two of these spectra together- ex. for fast convolution */ /* INPUTS */ /* *data = input data array */ /* M2 = log2 of fft size number of rows in */ /* M = log2 of fft size number of columns in */ /* OUTPUTS */ /* *data = output data array */ void rifft2d(float *data, long M2, long M); /* Compute 2D real ifft and return results in-place */ /* The input must be in the order as outout from rfft2d */ /* INPUTS */ /* *data = input data array */ /* M2 = log2 of fft size number of rows out */ /* M = log2 of fft size number of columns out */ /* OUTPUTS */ /* *data = output data array */ void rspect2dprod(float *data1, float *data2, float *outdata, long N2, long N1); // When multiplying a pair of 2d spectra from rfft2d care must be taken to multiply the // four real values seperately from the complex ones. This routine does it correctly. // the result can be stored in-place over one of the inputs /* *data1 = input data array first spectra */ /* *data2 = input data array second spectra */ /* N2 = fft size number of rows into rfft2d for both data1 and data2 */ /* N1 = fft size number of columns into rfft2d for both data1 and data2 */ nyquist-3.05/ffts/src/fftlib.h0000644000175000000620000000601111466723256015345 0ustar stevestaff#define MYRECIPLN2 1.442695040888963407359924681001892137426 // 1.0/log(2) /* some useful conversions between a number and its power of 2 */ #define LOG2(a) (MYRECIPLN2*log(a)) // floating point logarithm base 2 #define POW2(m) ((unsigned long) 1 << (m)) // integer power of 2 for m<32 /******************************************************************* lower level fft stuff called by routines in fftext.c and fft2d.c *******************************************************************/ void fftCosInit(long M, float *Utbl); /* Compute Utbl, the cosine table for ffts */ /* of size (pow(2,M)/4 +1) */ /* INPUTS */ /* M = log2 of fft size */ /* OUTPUTS */ /* *Utbl = cosine table */ void fftBRInit(long M, short *BRLow); /* Compute BRLow, the bit reversed table for ffts */ /* of size pow(2,M/2 -1) */ /* INPUTS */ /* M = log2 of fft size */ /* OUTPUTS */ /* *BRLow = bit reversed counter table */ void ffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow); /* Compute in-place complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = output data array */ void iffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow); /* Compute in-place inverse complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = output data array */ void rffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow); /* Compute in-place real fft on the rows of the input array */ /* The result is the complex spectra of the positive frequencies */ /* except the location for the first complex number contains the real */ /* values for DC and Nyquest */ /* INPUTS */ /* *ioptr = real input data array */ /* M = log2 of fft size */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = output data array in the following order */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ void riffts1(float *ioptr, long M, long Rows, float *Utbl, short *BRLow); /* Compute in-place real ifft on the rows of the input array */ /* data order as from rffts1 */ /* INPUTS */ /* *ioptr = input data array in the following order */ /* M = log2 of fft size */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ /* Rows = number of rows in ioptr array (use Rows of 1 if ioptr is a 1 dimensional array) */ /* *Utbl = cosine table */ /* *BRLow = bit reversed counter table */ /* OUTPUTS */ /* *ioptr = real output data array */ nyquist-3.05/ffts/src/fftext.c0000644000175000000620000001333211466723256015376 0ustar stevestaff/******************************************************************* This file extends the fftlib with calls to maintain the cosine and bit reversed tables for you (including mallocs and free's). Call the init routine for each fft size you will be using. Then you can call the fft routines below which will make the fftlib library call with the appropriate tables passed. When you are done with all fft's you can call fftfree to release the storage for the tables. Note that you can call fftinit repeatedly with the same size, the extra calls will be ignored. So, you could make a macro to call fftInit every time you call ffts. For example you could have someting like: #define FFT(a,n) if(!fftInit(roundtol(LOG2(n)))) ffts(a,roundtol(LOG2(n)),1);else printf("fft error\n"); *******************************************************************/ #include #include "fftlib.h" #include "matlib.h" #include "fftext.h" // pointers to storage of Utbl's and BRLow's static float *UtblArray[8*sizeof(long)] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; static short *BRLowArray[8*sizeof(long)/2] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; int fftInit(long M){ // malloc and init cosine and bit reversed tables for a given size fft, ifft, rfft, rifft /* INPUTS */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* OUTPUTS */ /* private cosine and bit reversed tables */ int theError = 1; /*** I did NOT test cases with M>27 ***/ if ((M >= 0) && (M < 8*sizeof(long))){ theError = 0; if (UtblArray[M] == 0){ // have we not inited this size fft yet? // init cos table UtblArray[M] = (float *) malloc( (POW2(M)/4+1)*sizeof(float) ); if (UtblArray[M] == 0) theError = 2; else{ fftCosInit(M, UtblArray[M]); } if (M > 1){ if (BRLowArray[M/2] == 0){ // init bit reversed table for cmplx fft BRLowArray[M/2] = (short *) malloc( POW2(M/2-1)*sizeof(short) ); if (BRLowArray[M/2] == 0) theError = 2; else{ fftBRInit(M, BRLowArray[M/2]); } } } if (M > 2){ if (BRLowArray[(M-1)/2] == 0){ // init bit reversed table for real fft BRLowArray[(M-1)/2] = (short *) malloc( POW2((M-1)/2-1)*sizeof(short) ); if (BRLowArray[(M-1)/2] == 0) theError = 2; else{ fftBRInit(M-1, BRLowArray[(M-1)/2]); } } } } }; return theError; } void fftFree(){ // release storage for all private cosine and bit reversed tables long i1; for (i1=8*sizeof(long)/2-1; i1>=0; i1--){ if (BRLowArray[i1] != 0){ free(BRLowArray[i1]); BRLowArray[i1] = 0; }; }; for (i1=8*sizeof(long)-1; i1>=0; i1--){ if (UtblArray[i1] != 0){ free(UtblArray[i1]); UtblArray[i1] = 0; }; }; } /************************************************* The following calls are easier than calling to fftlib directly. Just make sure fftlib has been called for each M first. **************************************************/ void ffts(float *data, long M, long Rows){ /* Compute in-place complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = output data array */ ffts1(data, M, Rows, UtblArray[M], BRLowArray[M/2]); } void iffts(float *data, long M, long Rows){ /* Compute in-place inverse complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = output data array */ iffts1(data, M, Rows, UtblArray[M], BRLowArray[M/2]); } void rffts(float *data, long M, long Rows){ /* Compute in-place real fft on the rows of the input array */ /* The result is the complex spectra of the positive frequencies */ /* except the location for the first complex number contains the real */ /* values for DC and Nyquest */ /* See rspectprod for multiplying two of these spectra together- ex. for fast convolution */ /* INPUTS */ /* *ioptr = real input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = output data array in the following order */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ rffts1(data, M, Rows, UtblArray[M], BRLowArray[(M-1)/2]); } void riffts(float *data, long M, long Rows){ /* Compute in-place real ifft on the rows of the input array */ /* data order as from rffts */ /* INPUTS */ /* *ioptr = input data array in the following order */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = real output data array */ riffts1(data, M, Rows, UtblArray[M], BRLowArray[(M-1)/2]); } void rspectprod(float *data1, float *data2, float *outdata, long N){ // When multiplying a pair of spectra from rfft care must be taken to multiply the // two real values seperately from the complex ones. This routine does it correctly. // the result can be stored in-place over one of the inputs /* INPUTS */ /* *data1 = input data array first spectra */ /* *data2 = input data array second spectra */ /* N = fft input size for both data1 and data2 */ /* OUTPUTS */ /* *outdata = output data array spectra */ if(N>1){ outdata[0] = data1[0] * data2[0]; // multiply the zero freq values outdata[1] = data1[1] * data2[1]; // multiply the nyquest freq values cvprod(data1 + 2, data2 + 2, outdata + 2, N/2-1); // multiply the other positive freq values } else{ outdata[0] = data1[0] * data2[0]; } } nyquist-3.05/ffts/src/fft2d.c0000644000175000000620000003215511466723256015107 0ustar stevestaff/******************************************************************* This file extends the fftlib with 2d and 3d complex fft's and 2d real fft's. All fft's return results in-place. Temporary buffers for transposing columns are maintained privately via calls to fft2dInit, fft2dFree, fft3dInit, and fft3dFree. Note that you can call fft2dInit and fft3dInit repeatedly with the same sizes, the extra calls will be ignored. So, you could make a macro to call fft2dInit every time you call fft2d. *** Warning *** fft2dFree and fft3dFree also call fftFree so you must re-init all 1d fft sizes you are going to continue using *******************************************************************/ #include #include #include "fftlib.h" #include "fftext.h" #include "matlib.h" #include "dxpose.h" #include "fft2d.h" // use trick of using a real double transpose in place of a complex transpose if it fits #define cxpose(a,b,c,d,e,f) (2*sizeof(float)==sizeof(xdouble)) ? dxpose((xdouble *)(a), b, (xdouble *)(c), d, e, f) : cxpose(a,b,c,d,e,f); // for this trick to work you must NOT replace the xdouble declarations in // dxpose with float declarations. // pointers for temporary storage for four columns static float *Array2d[8*sizeof(long)] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; int fft2dInit(long M2, long M){ // init for fft2d, ifft2d, rfft2d, and rifft2d // malloc storage for 4 columns of 2d ffts then call fftinit for both row and column ffts sizes /* INPUTS */ /* M = log2 of number of columns */ /* M2 = log2 of number of rows */ /* of 2d matrix to be fourier transformed */ /* OUTPUTS */ /* private storage for columns of 2d ffts */ /* calls fftInit for cosine and bit reversed tables */ int theError = 1; if ((M2 >= 0) && (M2 < 8*sizeof(long))){ theError = 0; if (Array2d[M2] == 0){ Array2d[M2] = (float *) malloc( 4*2*POW2(M2)*sizeof(float) ); if (Array2d[M2] == 0) theError = 2; else{ theError = fftInit(M2); } } if (theError == 0) theError = fftInit(M); } return theError; } void fft2dFree(){ // free storage for columns of 2d ffts and call fftFree to free all BRLow and Utbl storage long i1; for (i1=8*sizeof(long)-1; i1>=0; i1--){ if (Array2d[i1] != 0){ free(Array2d[i1]); Array2d[i1] = 0; }; }; fftFree(); } void fft2d(float *data, long M2, long M){ /* Compute 2D complex fft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ long i1; if((M2>0)&&(M>0)){ ffts(data, M, POW2(M2)); if (M>2) for (i1=0; i10)&&(M>0)){ iffts(data, M, POW2(M2)); if (M>2) for (i1=0; i1= 0) && (L < 8*sizeof(long))){ theError = 0; if (Array2d[L] == 0){ Array2d[L] = (float *) malloc( 4*2*POW2(L)*sizeof(float) ); if (Array2d[L] == 0) theError = 2; else{ theError = fftInit(L); } } if (theError == 0){ if (Array2d[M2] == 0){ Array2d[M2] = (float *) malloc( 4*2*POW2(M2)*sizeof(float) ); if (Array2d[M2] == 0) theError = 2; else{ theError = fftInit(M2); } } } if (theError == 0) theError = fftInit(M); } return theError; } void fft3dFree(){ // free storage for columns of all 2d&3d ffts and call fftFree to free all BRLow and Utbl storage fft2dFree(); } void fft3d(float *data, long M3, long M2, long M){ /* Compute 2D complex fft and return results in-place */ /* INPUTS */ /* *data = input data array */ /* M3 = log2 of fft size number of pages */ /* M2 = log2 of fft size number of rows */ /* M = log2 of fft size number of columns */ /* OUTPUTS */ /* *data = output data array */ long i1; long i2; const long N = POW2(M); const long N2 = POW2(M2); const long N3 = POW2(M3); if((M3>0)&&(M2>0)&&(M>0)){ ffts(data, M, N3*N2); if (M>2) for (i2=0; i22) for (i1=0; i10)&&(M2>0)&&(M>0)){ iffts(data, M, N3*N2); if (M>2) for (i2=0; i22) for (i1=0; i10)&&(M>0)){ rffts(data, M, POW2(M2)); if (M==1){ cxpose(data, POW2(M)/2, Array2d[M2]+POW2(M2)*2, POW2(M2), POW2(M2), 1); xpose(Array2d[M2]+POW2(M2)*2, 2, Array2d[M2], POW2(M2), POW2(M2), 2); rffts(Array2d[M2], M2, 2); cxpose(Array2d[M2], POW2(M2), data, POW2(M)/2, 1, POW2(M2)); } else if (M==2){ cxpose(data, POW2(M)/2, Array2d[M2]+POW2(M2)*2, POW2(M2), POW2(M2), 1); xpose(Array2d[M2]+POW2(M2)*2, 2, Array2d[M2], POW2(M2), POW2(M2), 2); rffts(Array2d[M2], M2, 2); cxpose(Array2d[M2], POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); ffts(Array2d[M2], M2, 1); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 1, POW2(M2)); } else{ cxpose(data, POW2(M)/2, Array2d[M2]+POW2(M2)*2, POW2(M2), POW2(M2), 1); xpose(Array2d[M2]+POW2(M2)*2, 2, Array2d[M2], POW2(M2), POW2(M2), 2); rffts(Array2d[M2], M2, 2); cxpose(Array2d[M2], POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 3); ffts(Array2d[M2], M2, 3); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 3, POW2(M2)); for (i1=4; i10)&&(M>0)){ if (M==1){ cxpose(data, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); riffts(Array2d[M2], M2, 2); xpose(Array2d[M2], POW2(M2), Array2d[M2]+POW2(M2)*2, 2, 2, POW2(M2)); cxpose(Array2d[M2]+POW2(M2)*2, POW2(M2), data, POW2(M)/2, 1, POW2(M2)); } else if (M==2){ cxpose(data, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); riffts(Array2d[M2], M2, 2); xpose(Array2d[M2], POW2(M2), Array2d[M2]+POW2(M2)*2, 2, 2, POW2(M2)); cxpose(Array2d[M2]+POW2(M2)*2, POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); iffts(Array2d[M2], M2, 1); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 1, POW2(M2)); } else{ cxpose(data, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 1); riffts(Array2d[M2], M2, 2); xpose(Array2d[M2], POW2(M2), Array2d[M2]+POW2(M2)*2, 2, 2, POW2(M2)); cxpose(Array2d[M2]+POW2(M2)*2, POW2(M2), data, POW2(M)/2, 1, POW2(M2)); cxpose(data + 2, POW2(M)/2, Array2d[M2], POW2(M2), POW2(M2), 3); iffts(Array2d[M2], M2, 3); cxpose(Array2d[M2], POW2(M2), data + 2, POW2(M)/2, 3, POW2(M2)); for (i1=4; i1 1) && (N1>1)){ outdata[0] = data1[0] * data2[0]; // multiply the zero freq, zero wavenumber values outdata[1] = data1[1] * data2[1]; // multiply the zero freq, nyquest wavenumber values cvprod(data1 + 2, data2 + 2, outdata + 2, N/2-1); outdata[N] = data1[N] * data2[N]; // multiply the nyquest freq, zero wavenumber values outdata[N+1] = data1[N+1] * data2[N+1]; // multiply the nyquest freq, nyquest wavenumber values cvprod(data1 + N+2, data2 + N+2, outdata + N+2, N/2-1); } else{ // really 1D rfft spectra N = N2 * N1; // one of these is a 1 if(N>1){ outdata[0] = data1[0] * data2[0]; // multiply the zero freq values outdata[1] = data1[1] * data2[1]; // multiply the nyquest freq values cvprod(data1 + 2, data2 + 2, outdata + 2, N/2-1); // multiply the other positive freq values } else{ outdata[0] = data1[0] * data2[0]; } } }nyquist-3.05/ffts/src/files0000644000175000000620000000104111466723256014751 0ustar stevestafftr "\r" "\n" < dxpose.c > tmp.c mv tmp.c dxpose.c tr "\r" "\n" < dxpose.h > tmp.c mv tmp.c dxpose.h tr "\r" "\n" < fft2d.c > tmp.c mv tmp.c fft2d.c tr "\r" "\n" < fft2d.h > tmp.c mv tmp.c fft2d.h tr "\r" "\n" < fftext.c > tmp.c mv tmp.c fftext.c tr "\r" "\n" < fftext.h > tmp.c mv tmp.c fftext.h tr "\r" "\n" < fftlib.c > tmp.c mv tmp.c fftlib.c tr "\r" "\n" < fftlib.h > tmp.c mv tmp.c fftlib.h tr "\r" "\n" < files > tmp.c mv tmp.c n" < files tr "\r" "\n" < matlib.c > tmp.c mv tmp.c matlib.c tr "\r" "\n" < matlib.h > tmp.c mv tmp.c matlib.h nyquist-3.05/ffts/src/fftext.h0000644000175000000620000001124111466723256015400 0ustar stevestaff/******************************************************************* This file extends the fftlib with calls to maintain the cosine and bit reversed tables for you (including mallocs and free's). Call the init routine for each fft size you will be using. Then you can call the fft routines below which will make the fftlib library call with the appropriate tables passed. When you are done with all fft's you can call fftfree to release the storage for the tables. Note that you can call fftinit repeatedly with the same size, the extra calls will be ignored. So, you could make a macro to call fftInit every time you call ffts. For example you could have someting like: #define FFT(a,n) if(!fftInit(roundtol(LOG2(n)))) ffts(a,roundtol(LOG2(n)),1);else printf("fft error\n"); *******************************************************************/ int fftInit(long M); // malloc and init cosine and bit reversed tables for a given size fft, ifft, rfft, rifft /* INPUTS */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* OUTPUTS */ /* private cosine and bit reversed tables */ void fftFree(); // release storage for all private cosine and bit reversed tables void ffts(float *data, long M, long Rows); /* Compute in-place complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = output data array */ void iffts(float *data, long M, long Rows); /* Compute in-place inverse complex fft on the rows of the input array */ /* INPUTS */ /* *ioptr = input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = output data array */ void rffts(float *data, long M, long Rows); /* Compute in-place real fft on the rows of the input array */ /* The result is the complex spectra of the positive frequencies */ /* except the location for the first complex number contains the real */ /* values for DC and Nyquest */ /* See rspectprod for multiplying two of these spectra together- ex. for fast convolution */ /* INPUTS */ /* *ioptr = real input data array */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = output data array in the following order */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ void riffts(float *data, long M, long Rows); /* Compute in-place real ifft on the rows of the input array */ /* data order as from rffts */ /* INPUTS */ /* *ioptr = input data array in the following order */ /* M = log2 of fft size (ex M=10 for 1024 point fft) */ /* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */ /* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */ /* OUTPUTS */ /* *ioptr = real output data array */ void rspectprod(float *data1, float *data2, float *outdata, long N); // When multiplying a pair of spectra from rfft care must be taken to multiply the // two real values seperately from the complex ones. This routine does it correctly. // the result can be stored in-place over one of the inputs /* INPUTS */ /* *data1 = input data array first spectra */ /* *data2 = input data array second spectra */ /* N = fft input size for both data1 and data2 */ /* OUTPUTS */ /* *outdata = output data array spectra */ // The following is FYI //Note that most of the fft routines require full matrices, ie Rsiz==Ncols //This is how I like to define a real matrix: //struct matrix { // real matrix // float *d; // pointer to data // long Nrows; // number of rows in the matrix // long Ncols; // number of columns in the matrix (can be less than Rsiz) // long Rsiz; // number of floats from one row to the next //}; //typedef struct matrix matrix; // CACHEFILLMALLOC and CEILCACHELINE can be used instead of malloc to make // arrays that start exactly on a cache line start. // First we CACHEFILLMALLOC a void * (use this void * when free'ing), // then we set our array pointer equal to the properly cast CEILCACHELINE of this void * // example: // aInit = CACHEFILLMALLOC( NUMFLOATS*sizeof(float) ); // a = (float *) CEILCACHELINE(ainit); // ... main body of code ... // free(aInit); // // To disable this alignment, set CACHELINESIZE to 1 //#define CACHELINESIZE 32 // Bytes per cache line //#define CACHELINEFILL (CACHELINESIZE-1) //#define CEILCACHELINE(p) ((((unsigned long)p+CACHELINEFILL)/CACHELINESIZE)*CACHELINESIZE) //#define CACHEFILLMALLOC(n) malloc((n)+CACHELINEFILL) nyquist-3.05/ffts/src/dxpose.h0000644000175000000620000000134011466723256015401 0ustar stevestaff/********************* This matrix transpose is in a seperate file because it should always be double precision. *********************/ typedef double_t xdouble; // I use double_t so that global search and replace on double won't // change this to float accidentally. void dxpose(xdouble *indata, long iRsiz, xdouble *outdata, long oRsiz, long Nrows, long Ncols); /* not in-place double precision matrix transpose */ /* INPUTS */ /* *indata = input data array */ /* iRsiz = offset to between rows of input data array */ /* oRsiz = offset to between rows of output data array */ /* Nrows = number of rows in input data array */ /* Ncols = number of columns in input data array */ /* OUTPUTS */ /* *outdata = output data array */ nyquist-3.05/ffts/src/matlib.h0000644000175000000620000000237611466723256015361 0ustar stevestaff/* a few routines from a vector/matrix library */ void xpose(float *indata, long iRsiz, float *outdata, long oRsiz, long Nrows, long Ncols); /* not in-place matrix transpose */ /* INPUTS */ /* *indata = input data array */ /* iRsiz = offset to between rows of input data array */ /* oRsiz = offset to between rows of output data array */ /* Nrows = number of rows in input data array */ /* Ncols = number of columns in input data array */ /* OUTPUTS */ /* *outdata = output data array */ void cxpose(float *indata, long iRsiz, float *outdata, long oRsiz, long Nrows, long Ncols); /* not in-place complex matrix transpose */ /* INPUTS */ /* *indata = input data array */ /* iRsiz = offset to between rows of input data array */ /* oRsiz = offset to between rows of output data array */ /* Nrows = number of rows in input data array */ /* Ncols = number of columns in input data array */ /* OUTPUTS */ /* *outdata = output data array */ void cvprod(float *a, float *b, float *out, long N); /* complex vector product, can be in-place */ /* product of complex vector *a times complex vector *b */ /* INPUTS */ /* N vector length */ /* *a complex vector length N complex numbers */ /* *b complex vector length N complex numbers */ /* OUTPUTS */ /* *out complex vector length N */ nyquist-3.05/ffts/Matlab-testing/0002755000175000000620000000000011537433131016003 5ustar stevestaffnyquist-3.05/ffts/Matlab-testing/rfft2dTestML.m0000644000175000000620000000244011466723256020452 0ustar stevestaff% program to test 2d real fft % let user select file then open it [fname, pname] = uigetfile('*.dr2', 'select conv file'); cd(pname); fidout=fopen(fname,'r'); % read header info N=fread(fidout,1,'long'); M=fread(fidout,1,'long'); % read in data %status=fseek(fidout,Nheader,'bof'); a=fread(fidout,N*M,'float'); a=reshape(a,N,M); c=fread(fidout,N*M,'float'); c=reshape(c,N,M); c=c(1:2:N,:)+j*c(2:2:N,:); fclose(fidout); c2=fft2(a); % Remember Matlab is column major order, C is row major order % Matlab starts with index of 1, f and k start at 0 %%%% check the real transforms of DC and Nyquest frequencies % check the four real values maxerr=abs(real(c(1,1))-c2(1,1)); % 0 f, 0 k maxerr=max(maxerr,abs(imag(c(1,1))-c2(1,M/2+1))); % 0 f, M/2 k maxerr=max(maxerr,abs(real(c(1,M/2+1))-c2(N/2+1,1)));% N/2 f, 0 k maxerr=max(maxerr,abs(imag(c(1,M/2+1))-c2(N/2+1,M/2+1)));% N/2 f, M/2 k %check the rest of the pos wavenumbers of DC and Nyquest frequencies maxerr=max(maxerr,max(abs(c(1,2:M/2)-c2(1,2:M/2)))); %f = 0, k=1 to M/2-1 maxerr=max(maxerr,max(abs(c(1,M/2+2:M)-c2(N/2+1,2:M/2))));%f = N/2, k=1 to M/2-1 %%%% % check all the other positive frequencies at all wavenumbers % f from 1 to N/2-1, k from 0 to M-1 (wraps around through negative k) maxerr=max(maxerr,max(max(abs(c(2:N/2,:)-c2(2:N/2,:))))) nyquist-3.05/ffts/Matlab-testing/convTest.c0000644000175000000620000000452211466723256017770 0ustar stevestaff/* A program to test fast 1d real convolution */ #include #include #include #include #include "fftlib.h" #include "fftext.h" #if macintosh #include #endif #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) //#define BIPRAND(a) round(100*(2.0/(RAND_MAX+1.0)*a-1.0)) void main(){ const long N2 = 2; /* the number ffts to test */ long N = 2048; /* size of FFTs, must be power of 2 */ long kernSize = 1003; /* kernal size must be less than N */ long dataSize = N-kernSize+1; /* data size */ float *a; float *b; long i1; long i2; long TheErr; long M; FILE *fdataout; /* output file */ unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a[0])); printf(" randseed = %10u\n", randseed); srand(randseed); M = roundtol(LOG2(N)); N = POW2(M); printf("fft size = %6d, ", N); if (dataSize <= 0) TheErr = 22; else TheErr = 0; if(!TheErr){ TheErr = fftInit(M); } a = (float *) calloc(N2*N,sizeof(float) ); // calloc to zero pad data to fill N if (a == 0) TheErr = 2; if(!TheErr){ b = (float *) calloc(N2*N,sizeof(float) ); // calloc to zero pad data to fill N if (b == 0) TheErr = 2; } if(!TheErr){ fdataout = fopen("convdat.cnv", "wb"); if (fdataout == NULL) TheErr = -50; } if(!TheErr){ /* write sizes to fdataout */ fwrite(&dataSize, sizeof(dataSize), 1, fdataout); fwrite(&kernSize, sizeof(kernSize), 1, fdataout); fwrite(&N2, sizeof(N2), 1, fdataout); /* set up a simple test case and write to fdataout */ for (i2=0; i2 #include #include #include #include "fftlib.h" #include "fftext.h" #include "fft2d.h" #if macintosh #include #endif #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) void main(){ long N2 = 64; /* the number of rows in 2d ffts, must be power of 2 */ long N = 256; /* the number of cols in 2d ffts, must be power of 2 */ float *a; float maxerrfft; long i1; long TheErr; long M; long M2; FILE *fdataout; /* output file */ unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a[0])); printf(" randseed = %10u\n", randseed); srand(randseed); M = roundtol(LOG2(N)); N = POW2(M); M2 = roundtol(LOG2(N2)); N2 = POW2(M2); printf("fft size = %6d X%6d, ", N2, N); TheErr = 0; if(!TheErr){ TheErr = fft2dInit(M2, M); } a = (float *) malloc(N2*N*sizeof(float) ); if (a == 0) TheErr = 2; if(!TheErr){ fdataout = fopen("fftdat.dr2", "wb"); if (fdataout == NULL) TheErr = -50; } if(!TheErr){ /* write sizes to fdataout */ fwrite(&N, sizeof(N), 1, fdataout); fwrite(&N2, sizeof(N2), 1, fdataout); /* set up a simple test case and write to fdataout */ for (i1=0; i1 #include #include #include #include "fftlib.h" #include "fftext.h" #include "fft2d.h" #if macintosh #include #endif #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) //#define BIPRAND(a) round(100*(2.0/(RAND_MAX+1.0)*a-1.0)) void main(){ long N = 256; /* the number of cols in 2d ffts, must be power of 2 */ long N2 = 64; /* the number of rows in 2d ffts, must be power of 2 */ long kernSize = 53; /* kernal cols must be less than N */ long kernSize2 = 29; /* kernal rows must be less than N2*/ long dataSize = N-kernSize+1; /* data cols */ long dataSize2 = N2-kernSize2+1; /* data rows */ float *a; float *b; long i1; long i2; long TheErr; long M; long M2; FILE *fdataout; /* output file */ unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a[0])); printf(" randseed = %10u\n", randseed); srand(randseed); M = roundtol(LOG2(N)); N = POW2(M); M2 = roundtol(LOG2(N2)); N2 = POW2(M2); printf("fft size = %6d X%6d, ", N2, N); if ((dataSize <= 0)||(dataSize2 <= 0)) TheErr = 22; else TheErr = 0; if(!TheErr){ TheErr = fft2dInit(M2, M); } a = (float *) calloc(N2*N,sizeof(float) ); // calloc to zero pad data to fill N to N2 if (a == 0) TheErr = 2; if(!TheErr){ b = (float *) calloc(N2*N,sizeof(float) ); // calloc to zero pad data to fill N to N2 if (b == 0) TheErr = 2; } if(!TheErr){ fdataout = fopen("conv2ddat.c2d", "wb"); if (fdataout == NULL) TheErr = -50; } if(!TheErr){ /* write sizes to fdataout */ fwrite(&dataSize, sizeof(dataSize), 1, fdataout); fwrite(&dataSize2, sizeof(dataSize2), 1, fdataout); fwrite(&kernSize, sizeof(kernSize), 1, fdataout); fwrite(&kernSize2, sizeof(kernSize2), 1, fdataout); /* set up a simple test case and write to fdataout */ for (i2=0; i2 /* uses four1 from numerical recipes in C to verify iffts */ /*change fmin in numerical recipes to fminnr to avoid conflict with fp.h */ #include #include #include #include #include "fftlib.h" #include "fftext.h" #if macintosh #include #endif #define NSIZES 24 /* the number of different fft sizes to test */ #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) typedef struct{ float Re; float Im; } Complex; void main(){ long fftSize[NSIZES] = /* size of FFTs, must be powers of 2 */ {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216}; Complex *a1; const long N2 = 2; /* the number ffts to test at each size */ long isize; long i1; long TheErr; long N; long M; float maxerrifft; float maxerrfft; unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a1[0].Re)); printf(" randseed = %10u\n", randseed); for (isize = 0; isize < NSIZES; isize++){ srand(randseed); N = fftSize[isize]; printf("ffts size = %8d, ", N); M = roundtol(LOG2(N)); TheErr = fftInit(M); if(!TheErr){ a1 = (Complex *) malloc( N2*N*sizeof(Complex) ); if (a1 == 0) TheErr = 2; } if(!TheErr){ /* set up a1 simple test case */ for (i1=0; i1 /* uses fourn from numerical recipes in C to verify ifft2d */ /*change fmin in numerical recipes to fminnr to avoid conflict with fp.h */ #include #include #include #include #include "fftlib.h" #include "fftext.h" #include "fft2d.h" #if macintosh #include #endif #define NSIZES 24 /* the number of different ffts col sizes to test */ #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) //#define BIPRAND(a) round(100*(2.0/(RAND_MAX+1.0)*a-1.0)) typedef struct{ float Re; float Im; } Complex; void main(){ long fftSize[NSIZES] = /* size of FFTs cols, must be powers of 2 */ {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216}; Complex *a1; long N2 = 64; /* the number of rows in the 2d fft */ long isize; long i1; long TheErr; long N; long M; long M2; float maxerrifft; float maxerrfft; unsigned long nn[2]; unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a1[0].Re)); printf(" randseed = %10u\n", randseed); for (isize = 0; isize < NSIZES; isize++){ srand(randseed); N = fftSize[isize]; M = roundtol(LOG2(N)); N = POW2(M); M2 = roundtol(LOG2(N2)); N2 = POW2(M2); printf("ffts size = %6d X%6d, ", N2, N); nn[0] = N2; nn[1] = N; TheErr = fft2dInit(M2, M); if(!TheErr){ a1 = (Complex *) malloc(N2*N*sizeof(Complex) ); if (a1 == 0) TheErr = 2; } if(!TheErr){ /* set up a simple test case */ for (i1=0; i1 /* uses fourn from numerical recipes in C to verify ifft3d */ /*change fmin in numerical recipes to fminnr to avoid conflict with fp.h */ #include #include #include #include #include "fftlib.h" #include "fftext.h" #include "fft2d.h" #if macintosh #include #endif #define NSIZES 24 /* the number of different ffts col sizes to test */ #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) typedef struct{ float Re; float Im; } Complex; void main(){ long fftSize[NSIZES] = /* size of FFTs cols, must be powers of 2 */ {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216}; Complex *a1; long isize; long i1; long TheErr; long N; long M; long N2 = 16; /* the number of rows in the 3d fft */ long M2; long N3 = 32; /* the number of pages in the 3d fft */ long M3; float maxerrifft; float maxerrfft; unsigned long nn[3]; unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a1[0].Re)); printf(" randseed = %10u\n", randseed); for (isize = 0; isize < NSIZES; isize++){ srand(randseed); N = fftSize[isize]; M = roundtol(LOG2(N)); N = POW2(M); M2 = roundtol(LOG2(N2)); N2 = POW2(M2); M3 = roundtol(LOG2(N3)); N3 = POW2(M3); printf("ffts size = %5d X%5d X%6d, ", N3, N2, N); nn[0] = N3; nn[1] = N2; nn[2] = N; TheErr = fft3dInit(M3, M2, M); if(!TheErr){ a1 = (Complex *) malloc(N3*N2*N*sizeof(Complex) ); if (a1 == 0) TheErr = 2; } if(!TheErr){ /* set up a simple test case */ for (i1=0; i1 /* uses realft from numerical recipes in C to verify riffts */ /*change fmin in numerical recipes to fminnr to avoid conflict with fp.h */ #include #include #include #include #include "fftlib.h" #include "fftext.h" #if macintosh #include #endif #define NSIZES 24 /* the number of different fft sizes to test */ #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) void main(){ long fftSize[NSIZES] = /* size of FFTs, must be powers of 2 */ {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216}; float *a; const long N2 = 2; /* the number ffts to test at each size */ long isize; long i1; long i2; long TheErr; long N; long M; float maxerrifft; float maxerrfft; unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a[0])); printf(" randseed = %10u\n", randseed); for (isize = 0; isize < NSIZES; isize++){ srand(randseed); N = fftSize[isize]; printf("rffts size = %8d, ", N); M = roundtol(LOG2(N)); TheErr = 0; TheErr = fftInit(M); if(!TheErr){ a = (float *) malloc(N2*N*sizeof(float) ); if (a == 0) TheErr = 2; } if(!TheErr){ /* set up a simple test case */ for (i1=0; i1 /* uses rlft3 from numerical recipes in C to verify rifft2d */ /*change fmin in numerical recipes to fminnr to avoid conflict with fp.h */ #include #include #include #include #include "fftlib.h" #include "fftext.h" #include "fft2d.h" #include // uses ugly tensors from numerical recipes; so can call rlft3 #if macintosh #include #endif #define NSIZES 24 /* the number of different ffts sizes to test */ #define BIPRAND(a) (2.0/(RAND_MAX+1.0)*a-1.0) void main(){ long fftSize[NSIZES] = /* size of FFTs, must be powers of 2 */ {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216}; float *a; long N2 = 64; /* the number of rows in 2d ffts, must be power of 2 */ long isize; long i1; long i2; long TheErr; long N; long M; long M2; float maxerrifft; float maxerrfft; float ***NRtensdata; /* needed for rlft3 */ float **NRmatdata; /* needed for rlft3 */ float *specdata; /* needed for rlft3 */ float t1,t2; unsigned int randseed = 777; int rannum; #if macintosh UnsignedWide TheTime1; Microseconds(&TheTime1); randseed = TheTime1.lo; #endif printf(" %6d Byte Floats \n", sizeof(a[0])); printf(" randseed = %10u\n", randseed); for (isize = 0; isize < NSIZES; isize++){ srand(randseed); N = fftSize[isize]; M = roundtol(LOG2(N)); N = POW2(M); M2 = roundtol(LOG2(N2)); N2 = POW2(M2); printf("rffts size = %6d X%6d, ", N2, N); TheErr = 0; TheErr = fft2dInit(M2, M); if(!TheErr){ NRmatdata=matrix(1,1,1,2*N2); specdata = &NRmatdata[1][1]; NRtensdata=f3tensor(1,1,1,N2,1,N); // uses ugly tensors from NRUTIL; so can call rlft3 a = &NRtensdata[1][1][1]; if ((a == 0)||(specdata == 0)) TheErr = 2; } if(!TheErr){ /* set up a simple test case */ for (i1=0; i1 #include #include #include #include "fftlib.h" #include "fftext.h" #if macintosh #include #endif #define NSIZES 3 /* the number of different fft sizes to time */ void main(){ float *a; long fftSize[NSIZES] = {2048, 32768, 524288}; /* size of FFTs, must be powers of 2 */ long fftRepeats[NSIZES] = {2000, 50, 1}; /* number of timing loops */ long isize; long i1; long TheErr; long N; long M; #if macintosh UnsignedWide TheTime1; UnsignedWide TheTime2; double TheTime; #endif printf(" %6d Byte Floats \n", sizeof(a[0])); for (isize = 0; isize < NSIZES; isize++){ N = fftSize[isize]; printf("rffts size = %9d ", N); M = roundtol(LOG2(N)); TheErr = fftInit(M); if(!TheErr){ a = (float *) malloc(N*sizeof(float)); if (a == 0) TheErr = 2; } if(!TheErr){ /* set up a simple test case */ for (i1=0; i1 #include #include #include #include "fftlib.h" #include "fftext.h" #if macintosh #include #endif #define NSIZES 3 /* the number of different ffts sizes to time */ typedef struct{ float Re; float Im; } Complex; void main(){ long fftSize[NSIZES] = {1024, 16384, 262144}; /* size of FFTs, must be powers of 2 */ long fftRepeats[NSIZES] = {2000, 50, 1}; /* number of timing loops */ Complex *a; long isize; long i1; long TheErr; long N; long M; #if macintosh UnsignedWide TheTime1; UnsignedWide TheTime2; double TheTime; #endif printf(" %6d Byte Floats \n", sizeof(a[0].Re)); for (isize = 0; isize < NSIZES; isize++){ N = fftSize[isize]; printf("ffts size = %7d, ", N); M = roundtol(LOG2(N)); TheErr = fftInit(M); if(!TheErr){ a = (Complex *) malloc(N*sizeof(Complex) ); if (a == 0) TheErr = 2; } if(!TheErr){ /* set up a simple test case */ for (i1=0; i1 0 && identifier.charAt(len - 1) == ' '); if (len == 0) { // not found int openParenLoc = findOpenParen(text, pos - start); identifier = getSalIdentifier(text, openParenLoc); identLoc = start + openParenLoc - identifier.length(); forceExact = true; } } else { // generate completion list for Lisp // look back for unmatched open paren, then forward for identifier // look back a maximum of 100 characters int openParenLoc = findOpenParen(text, pos - start); openParenLoc++; identifier = getIdentifier(text, openParenLoc); identLoc = start + openParenLoc; int len = identifier.length(); forceExact = (len > 0 && identifier.charAt(len - 1) == ' '); } //System.out.println("keyTyped identifier is: |" + identifier + "|"); // put up words list WordList.printList(identifier, pane, identLoc, pos + 1, forceExact, isSal); } } // get an identifier starting at pos -- if a complete identifier (terminated by something) // is found, the identifier is terminated by a space character static String getIdentifier(String text, int pos) { int idEnd = pos; // search forward to find identifier String lispIdChars = "~!@$%^&*-_+={}|:<>?/"; if (text.length() == 0 || pos < 0) return text; // special cases while (true) { if (idEnd == text.length()) { text = text.substring(pos); // still typing break; } char idChar = text.charAt(idEnd); if (!Character.isLetterOrDigit(idChar) && lispIdChars.indexOf(idChar) == -1) { text = text.substring(pos, idEnd) + " "; // complete break; // idEnd is one past last character } idEnd++; } return text; } static int findColumnOf(String text, int pos) { int col = 0; pos--; while (pos >= 0 && text.charAt(pos) != '\n') { col++; pos--; } return col; } private void insertIndentation(int p) { String text; int desired = 0; // desired indentation of the previous line // initialized because compiler can't figure out that it's // initialized below before it is used try { text = pane.getText(0, p); } catch (Exception e) { System.out.println("exception in insertIndentation"); return; } int indent; if (isSal) { indent = salIndentAmount(p); desired = TextColor.indentBefore; } else { indent = autoIndentAmount(text, p); } String indentation = ""; while (indent > 0) { indentation += " "; indent--; } // System.out.println("before replaceSelection(indentation)"); pane.replaceSelection(indentation); // System.out.println("after replaceSelection(indentation)"); if (isSal) { // indent the previous line as well // first find the beginning of the previous line int prevStart = p - 1; // index of newline // System.out.println("prevStart " + prevStart + " char |" + // text.charAt(prevStart) + "|"); assert(text.charAt(prevStart) == '\n'); while (prevStart - 1 >= 0 && text.charAt(prevStart - 1) != '\n') prevStart--; // System.out.println("PREV LINE BEGIN " + prevStart + " in |" + // text + "|"); // find the actual indentation of the previous line int prevIndent = 0; // search forward from prevStart for nonspace while (text.charAt(prevStart + prevIndent) == ' ' || text.charAt(prevStart + prevIndent) == '\t') prevIndent++; // System.out.println("PREV INDENT " + prevIndent + // " DESIRED " + desired); // adjust the indentation int delta = desired - prevIndent; p = pane.getSelectionStart() + delta; if (delta > 0) { indentation = ""; while (delta > 0) { indentation += " "; delta--; } // System.out.println("INSERT " + delta + // " SPACES AT " + prevStart); pane.setSelectionStart(prevStart); pane.setSelectionEnd(prevStart); pane.replaceSelection(indentation); } else if (delta < 0) { // System.out.println("BACKSPACE " + -delta + // " AT " + prevStart); pane.setSelectionStart(prevStart); pane.setSelectionEnd(prevStart - delta); pane.replaceSelection(""); } // System.out.println("MOVE CARET TO " + p); pane.setSelectionStart(p); pane.setSelectionEnd(p); } } private int salIndentAmount(int p) { // how much is the default indentation? // p is position AFTER a newline, so back up one to get // the index of the newline character // System.out.println("salIndentAmount " + p); TextColor.format(this, p - 1); // System.out.println("salIndent return " + TextColor.indentAfter); return TextColor.indentAfter; } // find auto-indent position: // first, go back and find open paren that would match a close paren // second search forward to find identifier // if identifier is defun, defmacro, let, let*, or prog, etc. // indent to paren posn + 2 // else indent to the first thing after the identifier int autoIndentAmount(String text, int pos) { int openParenLoc = findOpenParen(text, pos); // System.out.println("autoIndent: openParenLoc = " + openParenLoc); if (openParenLoc == -1) return 0; String ident = getIdentifier(text, openParenLoc + 1); if (ident.equals("defun ") || ident.equals("defmacro ") || ident.equals("let ") || ident.equals("let* ") || ident.equals("dotimes ") || ident.equals("dolist ") || ident.equals("simrep ") || ident.equals("seqrep ") || ident.equals("prog ") || ident.equals("prog* ") || ident.equals("progv ")) { pos = openParenLoc + 2; } else { pos = openParenLoc + ident.length(); System.out.println("auto-indent, pos " + pos + ", ident " + ident + ", length " + ident.length()); while (pos < text.length() && Character.isWhitespace(text.charAt(pos))) { if (text.charAt(pos) == '\n') { // if the end of the line looks like "(foo \n" then the tab position // will be indented two from the open paren (ignore the identifier): pos = openParenLoc + 2; break; } pos++; } // System.out.println("pos " + pos); } return findColumnOf(text, pos); } public static boolean inComment(String text, int pos) // search back to newline for ";" indicating comment // assumes text[pos] is not escaped or in string { boolean inString = false; while (pos > 0) { char c = text.charAt(pos); if (c == ';') return true; if (c == '\n') return false; pos = backup(text, pos, false); } return false; } static String SalIdChars = "{}(),[]\n #\""; public static String getSalIdentifier(String docText, int pos) { // System.out.println("|" + docText + "| " + pos); int start = pos; if (pos < 0) return ""; // special case: no place to search from // allow back up over single open paren if (docText.charAt(pos) == '(') start = start - 1; while (start >= 0 && SalIdChars.indexOf(docText.charAt(start)) == -1) { start--; } // protect from bogus arguments if (start < -1 || pos >= docText.length()) return ""; // if id is terminated by open paren, substitute blank so that // when we search lisp-syntax wordlist we get a more precise match. // E.g. "osc(" becomes "osc " which will not match "osc-enable ..." if (docText.charAt(pos) == '(') return docText.substring(start + 1, pos) + " "; else return docText.substring(start + 1, pos + 1); } public static int findOpenParen(String docText, int pos) { int findx = -1; try { boolean inString = false; // need to get it from text color findx = backup(docText, pos, inString); if (findx == pos - 1 && findx > 0 && docText.charAt(findx) == '\\') { // escaped paren return pos; } else if (inComment(docText, findx)) { // in comment return pos; } // at this point we know there is a closed paren. // go back until you find the matching open paren. int closed = 1; while (findx >= 0 && closed > 0) { char c = docText.charAt(findx); if (c == '(' || c == ')') { if (!inComment(docText, findx)) { if (c == '(') closed--; else if (c == ')') closed++; } } if (closed > 0) // not done, back up findx = backup(docText, findx, false); } } catch( Exception e ) { // System.out.println("findOpenParen " + e); } // System.out.println("findOpenParen returns " + findx); return findx; } private static int backup(String text, int pos, boolean inString) // find an index in text before pos by skipping over strings // and escaped characters of the form #\A, but do not consider // comment lines. If findx is zero, return result is -1. { int findx = pos - 1; while (true) { if (findx < 0) { return findx; } char c = text.charAt(findx); if (inString) { if (c == '"') { // could it be escaped? if (findx > 0) { char pre = text.charAt(findx - 1); if (pre == '"') findx--; // escaped as "" else if (pre == '\\') findx--; // escaped as \" else inString = false; } else inString = false; } // else keep searching for string closing } else { // not inString // test for escaped character if (findx > 0) { char pre = text.charAt(findx - 1); if (pre == '\\') findx--; // escaped else inString = (c == '"'); } // else if c == '"' then ... // internal error: text begins with quote, but // inString is false. Just ignore it because it // may be that the coloring hasn't run yet // and all will become well. } if (!inString || findx <= 0) { return findx; } findx--; } } void synchronousUpdate() { // System.out.println("synchronousUpdate called"); final CodePane codePane = this; final JViewport v = getViewport(); final Point pt = v.getViewPosition(); final Dimension e = v.getExtentSize(); EventQueue.invokeLater( new Runnable() { public void run() { // System.out.println("calling TextColor"); codePane.evenParens = TextColor.format(codePane, 0); // System.out.println("returned from TextColor"); codePane.updateFontSize(fontSize); } }); } void blinkParen(int pos) { try { String docText = doc.getText(0, pos); int openParenLoc = findOpenParen(docText, pos); if (openParenLoc >= 0 && openParenLoc < pos) { blink(openParenLoc); } } catch (Exception e) { System.out.println(e); } } // the blink interface: call blink(loc) to make a character blink void blink(int loc) { timer.start(); blinkOn = true; blinkLoc = loc; } public void updateFontSize(int size) { final MutableAttributeSet attributeSet = new SimpleAttributeSet(); StyleConstants.setFontSize(attributeSet, size); doc.setCharacterAttributes(0, 1000000, attributeSet, false); } public void setFontSize(int size) { fontSize = size; updateFontSize(size); } } nyquist-3.05/jnyqide/SalWordList.java0000644000175000000620000000326311466723256016720 0ustar stevestaff// // SalWordList.java // nyquist // // Created by Roger Dannenberg on 12/18/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // package jnyqide; import java.util.HashMap; import java.util.Map; public class SalWordList { public static String[] reservedWords = { "below", "by", "else", "finally", "for", "function", "in", "over", "repeat", "then", "from", "to", "unless", "until", "variable", "when", "while", "with" }; public static String[] commandWords = { "begin", "end", "chdir", "define", "open", "exec", "exit", "display", "load", "loop", "open", "print", "if", "return", "set", // "system", "play" }; public static Map reservedWordsTable; public static Map commandWordsTable; static public void init() { int i; reservedWordsTable = new HashMap(); for (i = 0; i < reservedWords.length; i++) { reservedWordsTable.put(reservedWords[i], null); } commandWordsTable = new HashMap(); for (i = 0; i < commandWords.length; i++) { commandWordsTable.put(commandWords[i], null); } } static public boolean isReservedWord(String word) { boolean rslt = reservedWordsTable.containsKey(word); // System.out.println("Sal:isReservedWord " + word + " -> " + rslt); return rslt; } static public boolean isCommandWord(String word) { boolean rslt = commandWordsTable.containsKey(word); // System.out.println("Sal:isCommandWord " + word + " -> " + rslt); return rslt; } } nyquist-3.05/jnyqide/Pair.java0000644000175000000620000000110411466723256015374 0ustar stevestaffpackage jnyqide; import java.io.*; import java.util.*; public class Pair { private double time, value; public Pair(){ time = 0; value = 0; } public Pair(double t, double v){ if (t < 0) { System.out.println("Warning: negative time scale input."); } // plotted functions are not signals, so you shouldn't expect them to stay within [-1, 1] //if (v < -1 || v > 1){ // System.out.println("Warning: Value is out of bounds."); //} time = t; value = v; } public double getTime(){ return time; } public double getValue(){ return value; } }nyquist-3.05/jnyqide/TextColor.java0000644000175000000620000013361111466723256016435 0ustar stevestaffpackage jnyqide; import javax.swing.*; // import java.awt.*; -- includes List, which conflicts import java.awt.Color; import java.awt.event.*; import java.awt.Point; import java.awt.Dimension; import javax.swing.text.*; import javax.swing.border.*; import javax.swing.event.*; import java.util.*; /* import java.util.Iterator; import java.util.List; import java.util.HashSet; import java.util.Set; import java.util.Point; */ import java.io.*; public class TextColor { static final boolean TCDEBUG = false; static final String TEXT_FONT = "Courier"; static final int TEXT_SIZE = 12; static final Color COLOR_NORMAL = Color.black; static final Color COLOR_COMMENT = new Color(0, 100, 0); // darkish green static final Color COLOR_BUILTIN = Color.blue; static final Color COLOR_STRING = new Color(130, 140, 0); // brown static final Color COLOR_ERROR = new Color(250, 0, 0); static final Color COLOR_COMMAND = new Color(0, 0, 196); // darkBlue; static final Color COLOR_RESERVED = new Color(96, 0, 196); // purple static final Color COLOR_KEYWORD = new Color(255, 128, 128); // pink static final Color COLOR_HIGHLIGHT_FG = Color.black; static final Color COLOR_HIGHLIGHT_BG = Color.lightGray; static final Color COLOR_BLINK_FG = Color.white; static final Color COLOR_BLINK_BG = Color.black; // TextColor is set up to be non-reentrant, with some state saved // as static variables that can be referenced by helper functions // like setColor. For example, you call format to colorize the // visible portions of a window. It saves some state that setColor // (called from many places) can use to find the document, the // visible region, etc. When format returns, TextColor is ready // for another call to fix another window. static DefaultStyledDocument doc; // the document being colorized static int start; // the start of the visible region static int end; // the end of the visible region static int indentPos; // where we want indent information static int indentBefore; // special return values for editing static int indentAfter; public static SimpleAttributeSet attrNormal, attrComment, attrBuiltin, attrString, attrError, attrCommand, attrKeyword, attrReserved, attrHighlight, attrBlink; private static SimpleAttributeSet newTextAttr(Color color) { SimpleAttributeSet attr = new SimpleAttributeSet(); attr.addAttribute(StyleConstants.ColorConstants.Foreground, color); StyleConstants.setFontFamily(attr, TEXT_FONT); StyleConstants.setFontSize(attr, TEXT_SIZE); return attr; } private static SimpleAttributeSet newTextHighlight(Color fg, Color bg) { SimpleAttributeSet attr = new SimpleAttributeSet(); attr.addAttribute(StyleConstants.ColorConstants.Foreground, fg); attr.addAttribute(StyleConstants.ColorConstants.Background, bg); return attr; } // public static Set keywords = new HashSet(); public static void init() { // System.out.println("initializing TextColor.java"); attrNormal = newTextAttr(COLOR_NORMAL); attrComment = newTextAttr(COLOR_COMMENT); attrBuiltin = newTextAttr(COLOR_BUILTIN); attrCommand = newTextAttr(COLOR_COMMAND); attrKeyword = newTextAttr(COLOR_KEYWORD); attrReserved = newTextAttr(COLOR_RESERVED); attrError = newTextAttr(COLOR_ERROR); attrString = newTextAttr(COLOR_STRING); attrHighlight = newTextHighlight(COLOR_HIGHLIGHT_FG, COLOR_HIGHLIGHT_BG); attrBlink = newTextHighlight(COLOR_BLINK_FG, COLOR_BLINK_BG); } public static boolean format(CodePane codePane, int nlLoc) { JTextPane pane = codePane.pane; doc = codePane.doc; JViewport v = codePane.getViewport(); indentBefore = 0; indentAfter = 0; indentPos = nlLoc; // position of interest for indentation info //System.out.println("format begin"); Point point = v.getViewPosition(); start = pane.viewToModel(point); //System.out.print("text loc for origin: "); //System.out.println(start); Dimension extent = v.getExtentSize(); point.translate(extent.width, extent.height); end = pane.viewToModel(point); //System.out.print("text loc for bottom right: "); //System.out.println(end); boolean b; int docLength = doc.getLength(); String docText; try { docText = doc.getText(0, docLength); } catch(Exception e ) { System.out.println(e); return false; } if (codePane.isSal && (docLength == 0 || docText.charAt(0) != '(')) { b = formatVisibleSal(codePane, docText, docLength); } else { b = formatVisible(codePane, docText, docLength); } // System.out.println("format end: isSal " + codePane.isSal + // " indentBefore " + indentBefore + // " After " + indentAfter); return b; } public static void setColor(int pos, int len, SimpleAttributeSet color) { // if color region overlaps visible region, update doc with color if (!(end < pos || pos + len < start)) { doc.setCharacterAttributes(pos, len, color, true); } } static final int INDENT = 2; // how much to indent // these are codes for different bracket types: static final int ONESHOT = 0; static final int IF_THEN = 1; static final int COMMAND = 2; static final int BRACE = 3; static final int BRACKET = 4; static final int PAREN = 5; static final int IF = 6; static final int BEGIN = 7; static final int TOP = 8; // imaginary initial/final brackets used // to detect and mark any unclosed real brackets like begin, (, etc. // debugging support (I guess I should have used enumerated type): static String[] stateName = { "ONESHOT", "IF_THEN", "COMMAND", "BRACE", "BRACKET", "PAREN", "IF", "BEGIN", "TOP" }; // find the column of pos in text by searching back to newline public static int columnFor(String text, int pos) { int col = 0; while (pos > 0 && text.charAt(pos - 1) != '\n') { col++; pos--; } return col; } // placed here so it is accessible by inner classes -- not ideal static int lineIndent; public static boolean formatVisibleSal(CodePane pane, final String docText, int docLength) { // start and end give the visible range over which we actually // change the document. // // Parse the whole file (well, almost): // Use a stack for matching tokens and to compute indent: // The stack contains the indentation to restore to when // the matching close token is found. Also, if the close // token does not match the top of the stack, there is some // balance problem -- use precedence to decide what to match to, e.g. // and END will skip an unclosed open-paren to match a BEGIN because // BEGIN/END has higher precedence. // // This idea breaks down when there are local syntax errors, e.g. // if you type a "todo" list at the top of a file, and the text // is (intentionally) full of SAL syntax errors (because it's not // supposed to be SAL), then far down in the file, you may find // indentation breaks down completely. To work around this problem // the syntax coloring is RESET whenever "define" appears // // In SAL, IF-THEN-ELSE does not have close tokens, so indentation // is very tricky. IF is actually closed by THEN, but THEN must // be followed by a statement. We record this by pushing IF_THEN, // meaning that there's an IF-THEN construct holding a place for // a possible ELSE. Then we push a COMMAND, // a placeholder for the next statement. After any statement word, // we pop COMMAND. If we find an ELSE, we pop the matching IF-THEN. // If we get a statement when we're not expecting COMMAND, we pop // all the IF-THEN's because the statement is going to stop any // ELSE from matching and therefore we have to pop the indentation // level back before any pending IF-THENs. // // Note that indentBefore and indentAfter and indentPos are used // so that indentation can be computed and inserted from external // editing functions. These basically serve as probes into the // parsing algorithm. // // Coloring: // as for LISP: // known functions are in blue // strings are in brown // comments are in green // as in Common Music SAL: // reserved words are in purple // keyword parameters are in pink // commands are in dark blue // boolean allMatched = true; boolean afterNewline = true; // set to true after each newline, and // false after first token after each newline; used for indentation lineIndent = 0; // will hold the correct indentation for the // current line when a newline is reached. // This is in contrast to the ParseStack.indent number, which is // the "nominal" indentation that will be adjusted if the first // token on the line closes an open bracket (e.g. begin or "(") // or if the first token is not an expected command word class ParseState { public int indent; // the indentation level public int indent2; // indent level if not a command public int elseIndent; // used only for IF and IF_THEN to // remember indentation for a possible ELSE clause public int pos; // location of the token public int len; // length of the token public int state; // the saved state public ParseState(int i, int i2, int p, int l, int s) { indent = i; indent2 = i2; pos = p; len = l; state = s; elseIndent = 0; } }; class ParseStack { public Stack stack; public int indent; public int indent2; // the indentation if a command is continued public ParseStack() { stack = new Stack(); stack.push(new ParseState(0, 0, 0, 0, TOP)); indent = 0; indent2 = 0; } // push an indentation level on the stack, the keyword responsible // starts at pos and had length len. The new indentation level will // be at the column of pos + offset public void push(int offset, int offset2, int pos, int len, int state) { offset += columnFor(docText, pos) - indent; pushOffset(offset, offset2, pos, len, state); } // pushOffset is like push except the offset is relative to the // current indentation, not the position of the keyword (useful // for "define function foo()" where function causes the indent // (because you can have "define var" that does not indent), but // you want to indent relative to define rather than function. public void pushOffset(int offset, int offset2, int pos, int len, int state) { stack.push(new ParseState(indent, indent2, pos, len, state)); indent += offset; indent2 = indent + offset2; if (TCDEBUG) { System.out.println("pushOffset " + offset + " indent " + indent); } } // pop stack back to a matching token: bracket tokens have // priorities, e.g. begin is higher priority than "(", so // and "end" will jump over an unmatched "(" to find a "begin" // This is done to obtain more reasonable warnings to user, // otherwise, for example, "begin ( end" would all be red // instead of just showing the "(" in red. If anything is // unmatched, return false so caller knows there is an error // somewhere. boolean pop(int state) { boolean matched = true; // System.out.println("pop " + stack); while (!stack.empty() && stack.peek().state <= state) { ParseState ps = stack.pop(); indent = ps.indent; indent2 = ps.indent2; // System.out.println("pop indent " + indent + " indent2 " + indent2); if (ps.state == state) return matched; if (ps.state != IF_THEN) { // ignore these ; matched = false; setColor(ps.pos, ps.len, attrError); } } if (TCDEBUG) System.out.println("pop return false at end"); return false; } // after a command like define, the indentation level // is incremented, but the level should be returned as soon as // a command word is encountered public void popCommandAndIfThen() { // System.out.println("popCommand"); if (stack.peek().state == COMMAND) { pop(COMMAND); if (TCDEBUG) { System.out.println(" --> poppedCommand"); print(); } } else while (stack.peek().state == IF_THEN) { pop(IF_THEN); lineIndent = indent2 = indent; if (TCDEBUG) { System.out.println(" --> popped IF_THEN"); print(); } } } // add COMMAND to stack after an IF_THEN in response to "else" // this is tricky because the column inherits from the IF_THEN, // not the current indent value, and indent gets elseIndent public int ifElseCommand(int pos, int len) { ParseState ps = stack.peek(); if (ps.state == IF_THEN) { // good, "else" follows if...then // rather than popping IF_THEN and pushing COMMAND, just // change ps: indent = indent2 = ps.elseIndent + INDENT; ps.pos = pos; ps.len = len; ps.state = COMMAND; return ps.elseIndent; } return 0; } public void startCommand() { // remove COMMAND if present and retain indentation // otherwise pop out of IF_THEN's if (stack.peek().state == COMMAND) { ParseState ps = stack.pop(); indent2 = indent = ps.indent; // back up indentation to prepare for an ELSE: ps = stack.peek(); if (ps.state == IF_THEN) { indent2 = indent = ps.elseIndent; } //lineIndent = indent; //indent = indent2 = ps.indent; } else { popCommandAndIfThen(); } } public void convertCommand(int pos, int len, int state) { // remove COMMAND if present and replace with state if (stack.peek().state == COMMAND) { ParseState ps = stack.peek(); ps.pos = pos; ps.len = len; ps.state = state; } else { popCommandAndIfThen(); pushOffset(0, len + 1, pos, len, state); } } public void finishCommand() { // remove COMMAND if present if (stack.peek().state == COMMAND) { pop(COMMAND); } else { popCommandAndIfThen(); } } public boolean convertIf() { if (stack.peek().state == IF) { ParseState ps = stack.peek(); ps.state = IF_THEN; return true; } else { return false; } } public void print() { ParseState state = stack.peek(); System.out.println("State: indent " + state.indent + " indent2 " + state.indent2 + " pos " + state.pos + " len " + state.len + " state " + stateName[state.state] + " (cur) indent " + indent + " (cur) indent2 " + indent + " (cur) lineIndent " + lineIndent); for (int i = 0; i < stack.size(); i++) { System.out.print(stateName[stack.get(i).state] + " " + stack.get(i).indent + " "); } System.out.println(); } //public boolean expectingStmt() { // int s = stack.peek().state; // return (s == BEGIN || s == TOP); // } }; //System.out.println("formatVisibleSal"); try { // To parse the file, we use a state machine with these states: // comment -- in a comment started by ";" // word -- in normal text, possibly a keyword // hash -- we detected a hash mark (this state is implied) // escape -- we detected a backslash (this state is implied) // hashComment -- we're in a comment #| ... |# // string -- in a string // barSymbol -- in a symbol like |...| // space -- in space between other tokens // normal -- this state is orthogonal to the others. // it records when we are accumulating a run of normal // (black) characters. To make things run a little faster // we don't color each black character individually but // group them together into a run. It also helps at the end // of the string to be able to color what's left. boolean normal = false; int normalStart = 0; // start of normal black characters boolean comment = false; int commentStart = 0; boolean word = false; int wordStart = 0; boolean string = false; int stringStart = 0; boolean barSymbol = false; int barSymbolStart = 0; boolean space = false; int spaceStart = 0; int pos; ParseStack stack = new ParseStack(); // originally, this code accumulated words in buf, but this // caused many string allocations and ran very slowly, so now // we just mark where the word begins and when the word ends // we extract a string from docText // process document text while you have not reached the end // of the visible area and while there are unmatched parens // (i.e. the parenStack isn't empty, but stop if you reach // the end of the whole file. // // System.out.println("begin parse loop, docLength " + docLength); for (pos = 0; pos < docLength && (pos < end || !stack.stack.empty()); pos++) { char c = docText.charAt(pos); // System.out.print("CHAR |" + c + "| "); if (comment) { if (c == '\n') { if (pos >= start) { setColor(commentStart, pos - commentStart, attrComment); } comment = false; } // note that escape chars are ignored in comments } else if (string) { if (c == '"') { if (pos >= start) setColor(stringStart, pos - stringStart + 1, attrString); string = false; } else if (c == '\\') { // skip the quoted char pos++; } } else if (word) { // see if the word ends because of a character or end of text boolean terminated = (c == ' ' || c == '(' || c == ')' || c == '\n' || c == '"' || c == '{' || c == '}' || c == '[' || c == ']'); if (terminated || pos >= docLength - 1) { word = false; int stop = pos; if (!terminated) stop++; String buf = docText.substring(wordStart, stop); if (TCDEBUG) System.out.println("formatVisibleSal: " + buf); buf = buf.toLowerCase(); // for simplified lookup SimpleAttributeSet color; // WordList.printList(buf); // to get words list. if (SalWordList.isReservedWord(buf)) { color = attrReserved; // note that "then" is not included here because // "then" in a "for" clause does not need to be // followed by a COMMAND if (buf.equals("function") || buf.equals("finally")) { if (afterNewline) { lineIndent = stack.indent; } stack.startCommand(); stack.pushOffset(INDENT, 0, wordStart, buf.length(), COMMAND); } else if (buf.equals("else")) { int i = stack.ifElseCommand(wordStart, 4); if (afterNewline) { lineIndent = i; } if (TCDEBUG) { System.out.println("ifElseCommand"); stack.print(); } } else if (buf.equals("when") || buf.equals("unless")) { stack.push(INDENT, buf.length() + 1 - INDENT, wordStart, buf.length(), COMMAND); } else if (buf.equals("variable")) { stack.startCommand(); stack.indent2 = columnFor(docText, wordStart) + buf.length() + 1; } else if (buf.equals("with") || buf.equals("while") || buf.equals("until")) { stack.startCommand(); stack.push(0, buf.length() + 1, wordStart, buf.length(), COMMAND); // stack.indent2 = columnFor(docText, wordStart) + // buf.length() + 1; } else if (buf.equals("then")) { if (TCDEBUG) { System.out.println("at then"); stack.print(); } // if there's an if on the stack, pop it if (stack.convertIf()) { if (afterNewline) { lineIndent = stack.indent; } stack.pushOffset(INDENT, INDENT, wordStart, 4, COMMAND); } else { stack.indent2 = columnFor(docText, wordStart) + buf.length() + 1; } if (TCDEBUG) { System.out.println("after then"); stack.print(); } } else if (buf.equals("for")) { stack.popCommandAndIfThen(); stack.indent2 = stack.indent + INDENT; } afterNewline = false; } else if (SalWordList.isCommandWord(buf)) { stack.indent2 = stack.indent; color = attrCommand; if (afterNewline) { lineIndent = stack.indent; } if (buf.equals("define")) { // reset syntax coloring stack.pop(TOP); // color unmatched stuff stack = new ParseStack(); // reset stack } else if (buf.equals("begin") || buf.equals("loop")) { stack.push(INDENT, INDENT, wordStart, 5, BEGIN); } else if (buf.equals("end")) { if (!stack.pop(BEGIN)) { allMatched = false; setColor(wordStart, 3, attrError); } if (TCDEBUG) { System.out.println("end token after stack.pop"); stack.print(); } // if this is the first word on the line, then // match indentation to the matching BEGIN if (afterNewline) { lineIndent = stack.indent; } stack.finishCommand(); if (TCDEBUG) { System.out.println("end end"); stack.print(); } } else if (buf.equals("if")) { if (TCDEBUG) { System.out.println("at if"); stack.print(); } // int i = stack.indent; stack.convertCommand(wordStart, 2, IF); stack.stack.peek().elseIndent = stack.indent; // stack.indent = stack.indent2 = i; // stack.push(0, 0, wordStart, 2, IF); if (TCDEBUG) { System.out.println("after if"); stack.print(); } } else if (buf.equals("print")) { stack.startCommand(); stack.indent2 = columnFor(docText, wordStart) + buf.length() + 1; } else { stack.startCommand(); stack.indent2 = stack.indent + INDENT + INDENT; } afterNewline = false; } else if (WordList.isKeyword(buf)) { if (afterNewline) { lineIndent = stack.indent2; afterNewline = false; } color = attrBuiltin; } else if (buf.charAt(buf.length() - 1) == ':') { if (afterNewline) { lineIndent = stack.indent2; afterNewline = false; } color = attrKeyword; } else { if (afterNewline) {// && stack.expectingStmt()) { lineIndent = stack.indent2; if (TCDEBUG) { System.out.println("buf " + buf + " afterNewline " + afterNewline + " lineIndent becomes " + lineIndent); } afterNewline = false; } color = attrNormal; } // System.out.println(color); if (color != attrNormal) { setColor(normalStart, wordStart - normalStart, attrNormal); setColor(wordStart, pos - wordStart + 1, color); normal = true; normalStart = pos + 1; } else { // continue normal (black) color } } else if (c == '\\') { pos++; // skip the quoted char } if (terminated) { pos = pos - 1; // reexamine character at pos continue; // back to for loop, skip indentation tests } // Starts } else if (c == ' ' || c == '\t' || c == '\n') { space = true; spaceStart = pos; if (!normal) normalStart = pos; normal = true; } else if (c == ';') { // Comment Start comment = true; commentStart = pos; space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = false; } else if (c == '"') { // String start if (afterNewline) { lineIndent = stack.indent2; afterNewline = false; } string = true; stringStart = pos; space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = false; } else if (c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']') { // Paren/Brace start and end if ((c == '(' || c == '{' || c == '[') && afterNewline) { lineIndent = stack.indent2; afterNewline = false; } space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = false; if (pos >= start) setColor(pos, 1, attrNormal); if (c == '(' ) stack.push(1, 0, pos, 1, PAREN); else if (c == '{') stack.push(1, 0, pos, 1, BRACE); else if (c == '[') stack.push(1, 0, pos, 1, BRACKET); else { // must be ')' or '}' or ']' if (afterNewline) { lineIndent = stack.indent - 1; } if (stack.pop(c == ')' ? PAREN : (c == ']' ? BRACKET : BRACE))) { // System.out.println("after ), ], or }: indent " + stack.indent); } else { allMatched = false; setColor(pos, 1, attrError); } } //System.out.println("highlight/blink " + c + " pos " + pos + // " highlightLoc " + pane.highlightLoc + // " blinkLoc " + pane.blinkLoc); // there could be a race condition here, but failure // is not critical -- this just blinks the closing paren if (pane != null && pane.blinkLoc == pos && pane.blinkOn) { setColor(pos, 1, attrBlink); } else if (pane != null && pane.highlightLoc == pos) { setColor(pos, 1, attrHighlight); } } else { // Word start word = true; wordStart = pos; if (!normal) normalStart = pos; normal = true; if (c == '\\' && pos + 1 < docLength) { pos++; // parse the quoted char } } if (c == '\n') { // possibly store indentation info //System.out.println(pos + " indentPos " + indentPos + // " indent " + stack.indent); if (pos == indentPos) { indentBefore = lineIndent; indentAfter = stack.indent; } lineIndent = stack.indent; afterNewline = true; if (TCDEBUG) { System.out.println("at newline"); stack.print(); } } /* System.out.print("At end of loop, pos "); System.out.println(pos); */ } // END FOR LOOP //System.out.println("end parse loop"); if (normal) { setColor(normalStart, pos - normalStart + 1, attrNormal); } else if (comment) { setColor(commentStart, pos - commentStart + 1, attrComment); } else if (string) { setColor(stringStart, pos - stringStart + 1, attrString); } // set error color to any unmatched tokens on stack: if (!stack.pop(TOP)) allMatched = false; } catch(Exception e ) { System.out.println(e); e.printStackTrace(); } //System.out.println("salFormatVisible returns " + allMatched); return allMatched; } public static boolean formatVisible(CodePane pane, String docText, int docLength) // start and end give the visible range over which we actually // change the document. { boolean evenParens = false; try { //System.out.println(docText); // To parse the file, we use a state machine with these states: // comment -- in a comment started by ";" // word -- in normal text, possibly a keyword // hash -- we detected a hash mark (this state is implied) // escape -- we detected a backslash (this state is implied) // hashComment -- we're in a comment #| ... |# // string -- in a string // barSymbol -- in a symbol like |...| // space -- in space between other tokens // normal -- this state is orthogonal to the others. // it records when we are accumulating a run of normal // (black) characters. To make things run a little faster // we don't color each black character individually but // group them together into a run. It also helps at the end // of the string to be able to color what's left. boolean normal = false; int normalStart = 0; // start of normal black characters boolean comment = false; int commentStart = 0; boolean word = false; int wordStart = 0; boolean string = false; int stringStart = 0; boolean hashComment = false; int hashCommentStart = 0; boolean barSymbol = false; int barSymbolStart = 0; boolean space = false; int spaceStart = 0; int pos; Stack parenStack = new Stack(); // originally, this code accumulated words in buf, but this // caused many string allocations and ran very slowly, so now // we just mark where the word begins and when the word ends // we extract a string from docText // process document text while you have not reached the end // of the visible area and while there are unmatched parens // (i.e. the parenStack isn't empty, but stop if you reach // the end of the whole file. // //System.out.println("begin parse loop"); for (pos = 0; pos < docLength && (pos < end || !parenStack.empty()); pos++) { char c = docText.charAt(pos); if (comment) { if (c == '\n') { if (pos >= start) { setColor(commentStart, pos - commentStart, attrComment); } comment = false; } // note that escape chars are ignored in comments } else if (string) { if (c == '"') { if (pos >= start) setColor(stringStart, pos - stringStart + 1, attrString); string = false; } else if (c == '\\') { // skip the quoted char pos++; } } else if (word) { // see if the word ends because of a character or end of text boolean terminated = (c == ' ' || c == '(' || c == ')' || c == '\n' || c == '"'); if (terminated || pos >= docLength - 1) { word = false; int stop = pos; if (!terminated) stop++; String buf = docText.substring(wordStart, stop); // WordList.printList(buf); // to get words list. if (WordList.isKeyword(buf)) { setColor(normalStart, wordStart - normalStart, attrNormal); setColor(wordStart, pos - wordStart + 1, attrBuiltin); normal = true; normalStart = pos + 1; } else { // continue normal (black) color } } else if (c == '\\') { pos++; // skip the quoted char } if (terminated) pos = pos - 1; // reexamine character at pos } else if (hashComment) { if (c == '|' && pos + 1 < docLength && docText.charAt(pos + 1) == '#') { pos++; if (pos >= start) { if (normal) { setColor(normalStart, hashCommentStart - normalStart, attrNormal); } setColor(hashCommentStart, pos - hashCommentStart + 1, attrComment); } normal = false; hashComment = false; } else if (c == '\\') pos++; // skip the quoted char } else if (barSymbol) { if (c == '|') { if (pos >= start) { if (normal) { setColor(normalStart, wordStart - normalStart, attrNormal); } normal = false; setColor(wordStart, pos - wordStart, attrNormal); } } else if (c == '\\') pos++; // skip the quoted char // Starts } else if (c == ' ' || c == '\t' || c == '\n') { space = true; spaceStart = pos; if (!normal) normalStart = pos; normal = true; } else if (c == ';') { // Comment Start comment = true; commentStart = pos; space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = false; } else if (c == '"') { // String start string = true; stringStart = pos; space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = false; } else if (c == '(' || c == ')') { // Paren start and end space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = false; if (pos >= start) setColor(pos, 1, attrNormal); if (c == '(' ) { parenStack.push(new Integer(pos)); } else { if (parenStack.empty()) { if (pos >= start) setColor(pos, 1, attrError); } else { // System.out.println("pop stack"); parenStack.pop(); } } //System.out.println("highlight/blink " + c + " pos " + pos + // " highlightLoc " + pane.highlightLoc + // " blinkLoc " + pane.blinkLoc); // there could be a race condition here, but failure // is not critical -- this just blinks the closing paren if (pane != null && pane.blinkLoc == pos && pane.blinkOn) { setColor(pos, 1, attrBlink); } else if (pane != null && pane.highlightLoc == pos) { setColor(pos, 1, attrHighlight); } } else if (c == '#') { space = false; if (pos >= start && normal) { setColor(normalStart, pos - normalStart, attrNormal); } normal = true; normalStart = pos; if (pos + 1 < docLength) { char c2 = docText.charAt(pos + 1); if (c2 == '\'' || c2 == 'x' || c2 == 'o' || c2 == 'b' || c2 == ':') { // ignore all these: #' #x #o #b #: word = true; wordStart = pos; pos++; } else if (c2 == '|') { hashComment = true; hashCommentStart = pos; pos++; normal = false; } else { word = true; wordStart = pos; } } } else { // Word start word = true; wordStart = pos; if (!normal) normalStart = pos; normal = true; if (c == '\\' && pos + 1 < docLength) { pos++; // parse the quoted char } } /* System.out.print("At end of loop, pos "); System.out.println(pos); */ } // END FOR LOOP //System.out.println("end parse loop"); if (normal) { setColor(normalStart, pos - normalStart + 1, attrNormal); } else if (comment) { setColor(commentStart, pos - commentStart + 1, attrComment); } else if (hashComment) { setColor(hashCommentStart, pos - hashCommentStart + 1, attrComment); } else if (string) { setColor(stringStart, pos - stringStart + 1, attrString); } evenParens = parenStack.empty(); while( !parenStack.empty()) { int parenPos = ((Integer)parenStack.pop()).intValue(); if (pos >= start) setColor(parenPos, 1, attrError); } } catch(Exception e ) { System.out.println(e); } return evenParens; } } nyquist-3.05/jnyqide/NyqPlot.java0000644000175000000620000000640111466723256016114 0ustar stevestaffpackage jnyqide; import java.io.*; import java.util.*; import java.awt.*; import javax.swing.*; // Note: Modifications to move plots from a JInternalFrame to a fixed JPanel // are marked with //JPANEL: public class NyqPlot { /** * main method takes 1 parameter from command line * @param args name of input file */ public static void plot(String plotFilename, PlotFrame plotFrame) { if (plotFrame == null) { System.out.println("null plotFrame in plot"); return; } BufferedReader input = null; try { input = new BufferedReader(new FileReader(plotFilename)); } catch( FileNotFoundException fnfx ) { System.out.println("File not found: " + plotFilename); return; } // End try/catch block ///////////////////////////////////////////////// // Read File ///////////////////////////////////////////////// Vector dataPoints = new Vector(); String line; StringTokenizer st; boolean firsttime = true; Double num1 = new Double(0); double innum1 = 0; double innum2 = 0; double minx = 0; double miny = 0; double maxx = 0; double maxy = 0; System.out.println("plot reading file"); try { while ((line = input.readLine()) != null) { //Read another line from the file st = new StringTokenizer(line); if (st.countTokens() != 2) { System.out.println("input must have two numbers per line"); return; } String word1 = st.nextToken(); String word2 = st.nextToken(); innum1 = num1.valueOf(word1).doubleValue(); innum2 = num1.valueOf(word2).doubleValue(); if (firsttime == true) { // initializes mins and maxes to real values minx = innum1; maxx = innum1; miny = innum2; maxy = innum2; firsttime = false; } if (innum1 < minx){minx = innum1;} if (innum1 > maxx){maxx = innum1;} if (innum2 < miny){miny = innum2;} if (innum2 > maxy){maxy = innum2;} Pair currentPair = new Pair(innum1, innum2); dataPoints.add(currentPair); } //while ((line = input.readLine()) != null) input.close(); //Close the file } catch( IOException iox ) { System.out.println(iox ); } // End try/catch block // printData(dataPoints); //System.out.println("Min X = " + minx + " Max X = " + maxx); //System.out.println("Min Y = " + miny + " Max Y = " + maxy); // Plotting stuff /* Color [] colors = new Color [4]; colors[0] = Color.red; colors[1] = Color.yellow; colors[2] = Color.green; colors[3] = Color.blue; double [][][] graphstuff = new double [1][2][dataPoints.size()]; for(int i = 0; i < dataPoints.size(); i++){ graphstuff[0][0][i] = ((Pair) dataPoints.get(i)).getNum1(); graphstuff[0][1][i] = ((Pair) dataPoints.get(i)).getNum2(); } GRAph myGraph = new GRAph(colors); myGraph.graphit(minx,maxx,miny,maxy,graphstuff); */ plotFrame.PlotData(dataPoints, minx, miny, maxx, maxy); //JPANEL: JInternalFrame plotFrame = new PlotFrame(jDesktop, dataPoints, minx, miny, maxx, maxy); //JPANEL: JPanel plotFrame = new PlotFrame(jDesktop, dataPoints, minx, miny, maxx, maxy); //JPANEL: plotFrame.setVisible(true); } public static void printData(Vector input){ for(int i = 0; i < input.size(); i++){ System.out.println( ((Pair) input.get(i)).getTime() + " " + ((Pair) input.get(i)).getValue()); } } } nyquist-3.05/jnyqide/README.txt0000644000175000000620000001352511466723256015346 0ustar stevestaff15-392 Final Project Description Dave Mowatt dmowatt@andrew.cmu.edu Source Code: Main.java - main executable Creates a MainFrame swing window nyquist/ - All the ide files for text editing nyquist/MainFrame.java - root frame for the IDE This uses a basic swing interface, with a menu bar, quick-action buttons, and the basic components of the nyquist IDE: the input window (upper left), the output window (left side), and a desktop for all the opened files. nyquist/NyquistThread.java - i/o to nyquist executable Executes nyquist and maintains the input/output streams for communication to and from the input and output windows inside of MainFrame. The executable path (currently "nyquist.exe" or "ny" should be set to reflect whatever location the nyquist executable is on that particular machine. nyquist/NyquistFile.java - data for one open file in nyquist On a new instance, creates an empty file. Save will write to the current file unless it is a new file - where SaveAs will automatically be called. (If the file is new then the java File file variable will be null) Whenever a file is modified, a * will be placed next to the file's name in the title bar. nyquist/LispFileFilter.java* - filters out .lsp files. colortext/ - All the files relating to text coloring and paren checking colortext/SyntaxThread.java - maintains syntax highlighting for one document This is also used on the input window, where the paren balencing is used to prevent invalid input to nyquist. colortext/ColorText.java - text highlighting functions formatAll will go through the entire file to find the balanced parens, strings, comments, and the keywords. The keywords are currently in a list at the bottom, just append any missing ones or read them in from a file. The format() functions take in the syntax thread that is calling them. This is so they will automatically exit as soon as the thread's document is changed. That way if the user types another letter while the current check is running, it will stop the current one and start a new check from the beginning. nyquistplot/ - All the files for plotting nyquistplot/Pair.java - Stores the x, y coordinates of one data point time is along the x axis, v is along the y axis nyquistplot/NyqPlot.java - Handles reading in the data, finding mins/maxes Pretty straightforward, reads in the data storing the sonud data, then creates a graph based on that. nyquistplot/PlotFrame.java - Plots a graph of the file Upon creation, draws the full graph to an image. From then on, parts of that image are drawn to the double buffered window. This is so scrolling can be done easily without re-drawing the image again. The full graph image should be re-drawn on scaling. nyquistplot/PlotMouseAdapter.java* - Handles data for mouse scrolling/zooming Counts how far the mouse has been dragged to just store the change on how far to scroll. * not currently used, but the framework is there ----- design notes for SAL ----- to move to SAL, we must support two languages: XLISP and SAL when you open an edit window, the type, XLISP or SAL, should become a property of the window. I think we can just assume XLISP unless the file extension is SAL. Another option would be to try to detect the file type if the extension is not .lsp, .sal, or .ny. Maybe we could compute the ratio of parens to non-parens, but this might fail for data files (lists of numbers, in XLISP syntax), so we could add other features like counts of SAL keywords, etc. Let's try the simple file extension test first. When you open a new file, the editor should know whether it's a new lisp window or a new sal window. We won't support a new text window, but users can edit text and ignore syntax coloring if they want to. Syntax editor is needed for SAL. Coloring should match SAL examples on the CLM/SAL web pages, which look very good. Indentation should be suggested by the editor when you type newline. It would be great if TAB would indent the line instead of inserting a TAB. The IDE needs know when the user is in SAL mode or LISP mode. SAL prompts with "SAL>", so the sequence "\nSAL> " should put the IDE into SAL mode. In SAL mode, the IDE should expect SAL to be entered into the input window. Input should only be parsed when the user types two newlines in a row -- that allows multiple line input. Also, in SAL mode, errors need to be detected, parsed, and used to position the cursor at the error location in an edit window. ----- notes on Java ----- DETECTING A MAC if (System.getProperty("mrj.version") == null) { mb.add(createJUnitMenu()); } else { // the Mac specific code will go here } from http://java.sun.com/developer/technicalArticles/JavaLP/JavaToMac2/ public boolean isMac() { return System.getProperty("mrj.version") != null; } from http://www.kfu.com/~nsayer/Java/reflection.html LOADING CLASSES ONLY ON MAC That is, we really want to do this: if (isMac()) { new SpecialMacHandler(this); } but we will land in hot water because the class loader doesn't know what isMac() will return. It will only see that SpecialMacHandler wants com.apple.mrj.MRJApplicationUtils and fail to start the program on non-Macs. We must achieve the same end without referencing the class directly in the code. Reflection offers us the way. The reflected version of the same code looks like this: if (isMac()) { try { Object[] args = { this }; Class[] arglist = { Program.class }; Class mac_class = class.forName("SpecialMacHandler"); Constructor new_one = mac_class.getConstructor(arglist); new_one.newInstance(args); } catch(Exception e) { System.out.println(e); } } from http://www.kfu.com/~nsayer/Java/reflection.html nyquist-3.05/jnyqide/UPICFrame.java0000644000175000000620000015221311537432156016217 0ustar stevestaff// Code: Dmitry Portnoy, 5/1/09 // Revised 2011 by Roger B. Dannenberg /* Graphics organization: mainframe -- the MainFrame UPICFrame -- this editor, a JInternalFrame mainPanel -- a JPanel topPanel -- a JPanel dataPanel -- a JPanel, border "Current Envelope" varNameLabel -- a JLabel ("Name:") varName -- a JTextField waveformNameLabel -- a JLabel ("Waveform:") waveformName -- a JComboBox envNameLabel -- a JLabel("Envelope:") envName -- a JComboBox rangePanel - a JPanel, border "Range" update - JButton("Update Range") jMaxTL - a JLabel("Stop Time") jMaxT - a JTextField jMinAL - a JLabel("Min Freq") jMinA - a JTextField jMaxAL - a JLabel("Max Freq") jMaxA - a JTextField undoPanel - a JPanel, border "Undo/Redo" undo - a JButton("Undo") redo - a JButton("Redo") canvas - a PiecewiseCanvas (a JPanel) if endpoints are specified, e.g. if times[0] is 0 or last value in times matches the ending time, then use PWLV or PWEV version Be careful not to drop first/last point unless the time matches the begin/end time. */ /* Design notes by Dannenberg: Too much data to treat this like envelopes. Instead, load/save data a a file. Menu items: save, save as, revert, clear Use variable name box to give a variable name for the data. Use waveform name drop-down box to name waveforms. Use envelope name drop-down box to name envelopes. File format will be a waveform name, envelope name, and list of lists of alternating time value coordinates. File will have the format: ------------ ;; data saved from NyquistIDE UPIC editor set data-name = { { waveform envelope first list } { waveform envelope second list } ... } ------------ It's up to the user to interpret this data, but we'll add some functions to do this. */ package jnyqide; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.awt.image.*; import java.util.*; import java.text.*; import java.io.*; import javax.imageio.ImageIO; @SuppressWarnings("serial") public class UPICFrame extends JInternalFrame implements ActionListener { double EPSILON = 0.00000001; // small number -- allow for rounding error int LEFT_BORDER = 3; // inset everything by 3 pixels int TOP_BORDER = 3; int BOTTOM_BORDER = 5; int RIGHT_BORDER = 5; MainFrame mainframe; private JPanel mainPanel; private JTextPane jInputArea; private PiecewiseCanvas canvas; private JTextField jMaxT; private double maxT; private JTextField jMinHz; private double minHz; private JTextField jMaxHz; private double maxHz; private JCheckBox jLinear; private boolean isLinear = true; private JTextField varName; private String currentVarName; private JComboBox envName; private String currentEnvName = "upic-env"; private JComboBox waveformName; private String currentWaveformName = "*sine-table*"; private boolean showCs; private boolean showGrandStaff; private boolean showPicture; // when saving envelopes, we copy current envelope to the collection, // but this makes the combobox think that an envelope was selected, // and we get a request to save the same envelope were saving. To // avoid this, the "saving" flag is used to disable the check. private boolean saving = false; private File file; // the file backing the current data private String name; // name of file //hashtable for storing envelopes private Hashtable envColl; static double initTime=0.0; static double finalTime=1.0; static boolean displayCoord = false; static boolean valueType=false; static DecimalFormat form = new DecimalFormat("#.###"); private boolean modified; // tells when any aspect of envelope // has changed // envelope is modified by: entering a point, deleting a point, changing // the end-time (update), or clearing // modified is reset when envelope is loaded or saved private JButton MakeButton(String name, String cmd) { JButton b = new JButton(name); b.addActionListener(this); b.setActionCommand(cmd); return b; } private void AddMenuItem(JMenu menu, String name, String cmd, int code) { AddMenuItem(menu, name, cmd, code, false, false); } private void AddMenuItem(JMenu menu, String name, String cmd, int code, boolean shift) { AddMenuItem(menu, name, cmd, code, shift, false); } private void AddMenuItem(JMenu menu, String name, String cmd, int code, boolean shift, boolean check) { int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); JMenuItem item; if (check) { item = new JCheckBoxMenuItem(name); } else { item = new JMenuItem(name); } item.setActionCommand(cmd); item.addActionListener(this); if (code != -1) { item.setAccelerator(KeyStroke.getKeyStroke(code, keyMask | (shift ? java.awt.event.InputEvent.SHIFT_MASK : 0))); } menu.add(item); } private JComboBox MakeCombo(String cmd) { JComboBox b = new JComboBox(); b.setPreferredSize(new Dimension(150, 20)); b.setEditable(true); b.addActionListener(this); b.setActionCommand(cmd); return b; } // Constructor public UPICFrame(final MainFrame parent, JTextPane inputArea) { super(); mainframe = parent; jInputArea = inputArea; mainPanel = (JPanel) getContentPane(); envColl = new Hashtable(); name = "UPIC Editor"; setTitle(name); setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); final UPICFrame upicFrame = this; modified = false; addInternalFrameListener( new InternalFrameListener() { public void internalFrameClosing(InternalFrameEvent e) { //System.out.println("FrameClosing"); int r = JOptionPane.OK_OPTION; if (upicFrame.modified) { r = JOptionPane.showConfirmDialog(upicFrame, "Really close without saving?", "Alert", JOptionPane.OK_CANCEL_OPTION); } if (r == JOptionPane.OK_OPTION) { upicFrame.dispose(); } } public void internalFrameOpened(InternalFrameEvent e) { } public void internalFrameClosed(InternalFrameEvent e) { parent.disconnectUPIC(); //System.out.println("FrameClosed"); } public void internalFrameIconified(InternalFrameEvent e) { } public void internalFrameDeiconified(InternalFrameEvent e) { } public void internalFrameActivated(InternalFrameEvent e) { } public void internalFrameDeactivated(InternalFrameEvent e) { } } ); System.out.println("EnvelopeFrame constructor 1"); JMenuBar menuBar = new JMenuBar(); // File Menu JMenu fileMenu = new JMenu("File"); AddMenuItem(fileMenu, "Load", "loadUpicData", java.awt.event.KeyEvent.VK_K); AddMenuItem(fileMenu, "Open", "openUpicData", java.awt.event.KeyEvent.VK_O); AddMenuItem(fileMenu, "Save", "saveUpicData", java.awt.event.KeyEvent.VK_S); AddMenuItem(fileMenu, "Save As...", "saveUpicDataAs", java.awt.event.KeyEvent.VK_S, true); AddMenuItem(fileMenu, "Revert", "revertUpicData", -1); AddMenuItem(fileMenu, "Clear", "clearUpicData", -1); JMenu backgroundMenu = new JMenu("Background"); AddMenuItem(backgroundMenu, "C's", "showCs", java.awt.event.KeyEvent.VK_C, false, true); AddMenuItem(backgroundMenu, "Grand Staff", "showGrandStaff", java.awt.event.KeyEvent.VK_G, false, true); AddMenuItem(backgroundMenu, "Show Picture", "showPicture", java.awt.event.KeyEvent.VK_V, false, true); AddMenuItem(backgroundMenu, "Load Picture...", "loadPicture", -1); menuBar.add(fileMenu); menuBar.add(backgroundMenu); setJMenuBar(menuBar); JLabel varNameLabel = new JLabel("Name: "); varName = new JTextField("upicdata", 10); currentVarName = "upicdata"; JLabel waveformNameLabel = new JLabel("Waveform:"); waveformName = MakeCombo("waveformNameSelected"); JLabel envNameLabel = new JLabel("Envelope:"); envName = MakeCombo("envNameSelected"); JPanel dataPanel = new JPanel(); GridBagLayout layout0 = new GridBagLayout(); dataPanel.setLayout(layout0); GridBagConstraints cons0 = new GridBagConstraints(); cons0.fill = GridBagConstraints.NONE; cons0.anchor = GridBagConstraints.EAST; cons0.insets = new Insets(2, 2, 2, 2); // TEST cons0.weightx = 0; cons0.weighty = 0; cons0.gridy = 0; cons0.gridx = 0; cons0.gridheight = 1; cons0.gridwidth = 1; dataPanel.add(varNameLabel, cons0); cons0.anchor = GridBagConstraints.WEST; cons0.gridx = 1; cons0.fill = GridBagConstraints.HORIZONTAL; //TEST dataPanel.add(varName, cons0); cons0.anchor = GridBagConstraints.EAST; cons0.fill = GridBagConstraints.NONE; cons0.gridy = 1; cons0.gridx = 0; dataPanel.add(waveformNameLabel, cons0); cons0.anchor = GridBagConstraints.WEST; cons0.gridx = 1; dataPanel.add(waveformName, cons0); cons0.gridy = 2; cons0.gridx = 0; dataPanel.add(envNameLabel, cons0); cons0.anchor = GridBagConstraints.WEST; cons0.gridx = 1; dataPanel.add(envName, cons0); // panel to contain time and amplitude parameters JPanel rangePanel = new JPanel(); //JPanel paramPanel = new JPanel(); //paramPanel.setBorder(BorderFactory.createTitledBorder("Range")); rangePanel.setLayout(new GridBagLayout()); rangePanel.setBorder(BorderFactory.createTitledBorder("Range")); //TEST //paramPanel.setLayout(new GridBagLayout()); jMaxT = new JTextField("20.0", 5); maxT = 20.0; jMinHz = new JTextField("20.0", 5); minHz = 20.0; jMaxHz = new JTextField("2000.0", 5); maxHz = 2000; jLinear = new JCheckBox("linear", true); showCs = false; showGrandStaff = false; showPicture = false; JLabel jMaxTL = new JLabel("Stop Time: "); JLabel jMinHzL = new JLabel("Min Freq: "); JLabel jMaxHzL = new JLabel("Max Freq: "); JButton update = new JButton("Update Range"); cons0.gridx = 0; cons0.gridy = 0; cons0.gridwidth = 2; rangePanel.add(update, cons0); cons0.gridwidth = 1; cons0.gridx = 2; cons0.gridy = 0; rangePanel.add(jMaxTL, cons0); cons0.gridx = 3; cons0.gridy = 0; rangePanel.add(jMaxT, cons0); cons0.gridx = 0; cons0.gridy = 1; rangePanel.add(jMinHzL, cons0); cons0.gridx = 2; rangePanel.add(jMaxHzL, cons0); cons0.gridx = 1; rangePanel.add(jMinHz, cons0); cons0.gridx = 3; rangePanel.add(jMaxHz, cons0); cons0.gridx = 4; rangePanel.add(jLinear, cons0); update.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (getMaxT() <= 0) { JOptionPane.showMessageDialog(mainPanel, "Stop Time cannot be negative or zero"); } else if (getMinHz() > getMaxHz()) { JOptionPane.showMessageDialog(mainPanel, "Minimum frequency cannot be greater than maximum frequency"); } else if ((canvas.endTime() > getMaxT())) { JOptionPane.showMessageDialog(mainPanel, "Stop Time is less than the time of an existing envelope point"); } else if (getMinHz() < 20.0) { JOptionPane.showMessageDialog(mainPanel, "Minimum frequency cannot be less than 20 Hz"); } else { setModified(); maxT = getMaxT(); minHz = getMinHz(); maxHz = getMaxHz(); isLinear = getLinear(); canvas.history.save(canvas); canvas.repaint(); return; } // an error occurred, reset the Range (using complete restore) canvas.restore(); } }); JPanel undoPanel = new JPanel(); undoPanel.setLayout(new GridBagLayout()); undoPanel.setBorder(BorderFactory.createTitledBorder("Undo/Redo")); JButton undo = new JButton("Undo"); undo.setActionCommand("undo"); undo.addActionListener(this); JButton redo = new JButton("Redo"); redo.setActionCommand("redo"); redo.addActionListener(this); cons0.gridx = 0; cons0.gridy = 0; undoPanel.add(undo, cons0); cons0.gridy = 1; undoPanel.add(redo, cons0); //insert components into the larger panels cons0.fill = GridBagConstraints.NONE; cons0.anchor = GridBagConstraints.WEST; cons0.weightx = 0; cons0.weighty = 0; cons0.gridx = 0; cons0.gridy = 0; cons0.gridheight = 1; cons0.gridwidth = 1; //cons0.insets = new Insets(5,0,0,5); //paramPanel.add(rangePanel, cons0); // cons0.fill = GridBagConstraints.NONE; // cons0.anchor = GridBagConstraints.CENTER; // cons0.weightx = 0; // cons0.weighty = 0; // cons0.gridx = 0; // cons0.gridy = 1; // cons0.gridheight = 1; // cons0.gridwidth = 1; // //cons0.insets = new Insets(0,0,0,5); // paramPanel.add(update, cons0); JPanel topPanel = new JPanel(); //topPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 0)); topPanel.setLayout(new GridBagLayout()); cons0.anchor = GridBagConstraints.NORTHWEST; cons0.gridx = 0; cons0.gridy = 0; topPanel.add(dataPanel, cons0); cons0.gridx = 1; topPanel.add(rangePanel, cons0); //TEST cons0.gridx = 2; topPanel.add(undoPanel, cons0); canvas = new PiecewiseCanvas(); //insert panels into main frame and display mainPanel.add(BorderLayout.NORTH, topPanel); mainPanel.add(BorderLayout.CENTER, canvas); pack(); //resize and center the window //Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setLocation(100, 100); setSize(650, 580); // setBackground(Color.white); setResizable(true); setVisible(true); setClosable(true); setMaximizable(true); setIconifiable(true); clearUpicData(true); System.out.println("UPICFrame constructor 2 after setIconifiable"); repaint(); } public boolean waveformNameSelected() { String name = (String) waveformName.getSelectedItem(); if (name == null || name.equals("")) return false; currentWaveformName = name; return true; } public void waveformNewName() { if (waveformNameSelected()) { waveformName.addItem(currentWaveformName); } } public boolean envNameSelected() { String name = (String) envName.getSelectedItem(); if (name == null) return false; String originalName = currentEnvName; currentEnvName = name.trim(); if (!originalName.equals(currentEnvName)) { modified = true; } // make name be the selected name envName.setSelectedItem(name); currentEnvName = name; return true; } public void envNewName() { if (envNameSelected()) { envName.addItem(currentEnvName); } } public void varNameSelected() { if (saving) return; // ignore selection generated by "save" button // If the name is different from the current envelope name, do // a "save". Then switch to editing the newly selected envelope. String name = (String) varName.getText(); // when we load the JComboBox with new names, the contentsChanged // method of JComboBox invokes a selection action, even if nothing // is selected. I don't know why, but we have to handle the null // selection case. if (name == null) return; String originalName = currentVarName; currentVarName = varName.getText().trim(); if (!originalName.equals(currentVarName)) { modified = true; } varName.setText(name); currentVarName = name; } //public double getMinT() { return Double.parseDouble(minT.getText().trim()); } public double getMaxT() { return Double.parseDouble(jMaxT.getText().trim()); } public double getMinHz() { return Double.parseDouble(jMinHz.getText().trim()); } public double getMaxHz() { return Double.parseDouble(jMaxHz.getText().trim()); } public boolean getLinear() { return jLinear.isSelected(); } public boolean within(double x, double y, double eps) { return Math.abs(x - y) < eps; } // prompt for a file name and write the data public boolean saveUpicDataAs() { // select a file and write to it. Return true if success. JFileChooser chooser = new JFileChooser(); SalFileFilter salFilter = new SalFileFilter(); chooser.setFileFilter(salFilter); File tmpfile; String tmp; File curdir = new File(mainframe.currentDir); chooser.setCurrentDirectory(curdir); while (true) { // loop until file is chosen int returnVal = chooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { tmpfile = chooser.getSelectedFile(); tmp = tmpfile.getName(); System.out.println("You chose to save this file: " + tmp); tmp = tmp.toLowerCase(); if (tmp.endsWith(".sal")) break; JOptionPane dialog = new JOptionPane(); System.out.println("creating dialog"); int result = dialog.showConfirmDialog(this, "Do you really want to save a file without a " + ".lsp or .sal extension?", "Warning", JOptionPane.YES_NO_OPTION); System.out.println("return from dialog " + result); if (result == JOptionPane.YES_OPTION) break; } else { // file chooser cancel, early return return false; } } name = tmp; file = tmpfile; mainframe.changeDirectory(mainframe.fileDirectory(file)); modified = true; // for saveUpicData, do not need to add "*" return saveUpicData(); } private void setModified() { if (modified) return; setTitle(name + "*"); modified = true; } public boolean saveUpicData() // saves the file if there is a file name, otherwise calls saveAs. // returns false if the operation fails or is cancelled. // returns true if save succeeds or if file is unmodified. { if (modified) { if (file == null) return saveUpicDataAs(); else { try { FileWriter saveFileStream = new FileWriter(file); BufferedWriter out = new BufferedWriter(saveFileStream); String s = ";; data saved from NyquistIDE UPIC editor\n"; s += String.format( ";!; maxT %g minHz %g maxHz %g linear %s\n", maxT, minHz, maxHz, (isLinear ? "t" : "nil")); s += String.format("set %s = {\n", varName.getText().trim()); out.write(s); for (Curve c : canvas.curves) { if (c.times.size() > 0) { out.write(String.format("{ %s %s\n", c.waveform, c.envelope)); for (int i = 0; i < c.times.size(); i++) { out.write(String.format(" %.4f %.1f", c.times.get(i), c.freqs.get(i))); } out.write(" }\n\n"); } } out.write("}\n"); out.close(); } catch(Exception e) { System.out.println("exception in saveUpicData" + e); return false; // did not save file } modified = false; setTitle(name); } } return true; } public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); // File Menu options if (cmd.equals("saveUpicData")) saveUpicData(); else if (cmd.equals("loadUpicData")) { saveUpicData(); mainframe.loadFile(file); } else if (cmd.equals("saveUpicDataAs")) saveUpicDataAs(); else if (cmd.equals("openUpicData")) openUpicData(); else if (cmd.equals("clearUpicData")) clearUpicData(false); else if (cmd.equals("envNameSelected")) envNameSelected(); else if (cmd.equals("waveformNameSelected")) waveformNameSelected(); else if (cmd.equals("showCs")) { showCs = ((JCheckBoxMenuItem) e.getSource()).getState(); canvas.history.save(canvas); canvas.repaint(); } else if (cmd.equals("showGrandStaff")) { showGrandStaff = ((JCheckBoxMenuItem) e.getSource()).getState(); canvas.history.save(canvas); canvas.repaint(); } else if (cmd.equals("showPicture")) { showPicture = ((JCheckBoxMenuItem) e.getSource()).getState(); canvas.history.save(canvas); canvas.repaint(); } else if (cmd.equals("loadPicture")) { canvas.loadPicture(); canvas.repaint(); } else if (cmd.equals("undo")) { canvas.history.undo(); canvas.restore(); } else if (cmd.equals("redo")) { canvas.history.redo(); canvas.restore(); } else if (cmd.equals("comboBoxEdited")) { if (e.getSource() == envName) envNewName(); else if (e.getSource() == waveformName) waveformNewName(); else System.out.println("COMBOBOXEDITED not handled\n"); } else System.out.println("ACTION NOT HANDLED: " + cmd); } public void clearUpicData(boolean init) { canvas.clearUpicData(init); waveformName.removeAllItems(); waveformName.addItem("*sine-table*"); waveformName.addItem("*tri-table*"); waveformName.addItem("*saw-table*"); waveformName.setSelectedItem("*sine-table*"); envName.removeAllItems(); envName.addItem("upic-env"); envName.setSelectedItem("upic-env"); } public void addToComboBox(JComboBox cb, String s) { int n = cb.getItemCount(); for (int i = 0; i < n; i++) { if (s.equals(cb.getItemAt(i))) return; } cb.addItem(s); } public void readUpicData(File fileToOpen) { clearUpicData(false); name = fileToOpen.getName(); setTitle(name); double maxt = 20, minhz = 0, maxhz = 2000; boolean islinear = true; // this disabled saving state for undo: canvas.mouseDown = true; try { Scanner sc = new Scanner(fileToOpen); String next = sc.next(); while (next.charAt(0) == ';') { if (next.equals(";!;")) { // parse parameters if (!sc.next().equals("maxT") ) throw new Exception("syntax - maxT"); maxt = Double.parseDouble(sc.next()); if (!sc.next().equals("minHz") ) throw new Exception("syntax - minHz"); minhz = Double.parseDouble(sc.next()); if (!sc.next().equals("maxHz") ) throw new Exception("syntax - maxHz"); maxhz = Double.parseDouble(sc.next()); if (!sc.next().equals("linear") ) throw new Exception("syntax - linear"); islinear = !sc.next().equals("nil"); if (maxt < 0 || minhz < 20.0 || maxhz < minhz) { throw new Exception("bad maxt, minhz, maxhz"); } } sc.nextLine(); next = sc.next(); } // next tokens are (s)et variable = if (!next.equals("set")) throw new Exception("syntax - set"); currentVarName = sc.next(); varName.setText(currentVarName); if (!sc.next().equals("=")) throw new Exception("syntax - ="); // now read the first { if (!sc.next().equals("{")) throw new Exception("syntax - {"); // read lists next = sc.next(); while (next.equals("{")) { String waveform = sc.next(); addToComboBox(waveformName, waveform); String envelope = sc.next(); addToComboBox(envName, envelope); System.out.println("waveform " + waveform + " env " + envelope); canvas.startNewCurve(); next = sc.next(); while (!next.equals("}")) { // System.out.println("time " + next); double time = Double.parseDouble(next); double freq = Double.parseDouble(sc.next()); if (time < 0) time = 0; canvas.insertInOrder(time, freq); next = sc.next(); } next = sc.next(); } if (!next.equals("}")) { throw new Exception("syntax"); } // make sure whole thing fits on canvas maxT = Math.max(canvas.endTime(), maxt); minHz = Math.min(canvas.lowHz(), minhz); maxHz = Math.max(canvas.highHz(), maxhz); isLinear = islinear; jMaxT.setText(String.valueOf(maxT)); jMinHz.setText(String.valueOf(minHz)); jMaxHz.setText(String.valueOf(maxHz)); jLinear.setSelected(isLinear); } catch (Exception e) { System.out.println("readUpicData " + e); JOptionPane.showMessageDialog(this, "A problem was encountered reading a upic data file, data may have been lost"); } canvas.mouseDown = false; } public void openUpicData() { JFileChooser chooser = new JFileChooser(); SalFileFilter salFilter = new SalFileFilter(); chooser.addChoosableFileFilter(salFilter); File curdir = new File(mainframe.currentDir); chooser.setCurrentDirectory(curdir); int returnVal = chooser.showOpenDialog(this); System.out.println("openUpicData chooser returns " + returnVal); file = null; // in case open fails if (returnVal == JFileChooser.APPROVE_OPTION) { file = chooser.getSelectedFile(); mainframe.changeDirectory(mainframe.fileDirectory(file)); System.out.println("reading from " + file); readUpicData(file); modified = false; } } /* data = data.toLowerCase(); //System.out.println("openUpicData: data |" + data + "| len " + data.length()); envName.removeAllItems(); // clear and reload combo box while (data.length() > 0) { int eolx = data.indexOf("\n"); if (eolx < 0) return; // shouldn't happen, but bail if it does String line = data.substring(0, eolx); //System.out.println("openUpicData: line " + line); data = data.substring(eolx + 1); String name = line.substring(0, line.indexOf(' ')); System.out.println("openUpicData: name " + name); String env = line.substring(name.length() + 1); System.out.println("openUpicData: env " + env); if (name.length() > 0) envColl.put(name, env); envName.addItem(name); } */ private class State { public double maxT; public double minHz; public double maxHz; public boolean linear; public boolean cs; public boolean gs; public boolean picture; public State(double stop, double low, double hi, boolean lin, boolean showcs, boolean showgs, boolean showpic) { maxT = stop; minHz = low; maxHz = hi; linear = lin; cs = showcs; gs = showgs; picture = showpic; } } private class History { /* consider a sequence of undo/redo to be a single edit operation -- thus * the end of the versions list is set to the latest undo/redo selection */ private boolean undoRedo = false; private ArrayList> history = new ArrayList>(); private ArrayList state_history = new ArrayList(); private int version = -1; @SuppressWarnings("unchecked") public void save(PiecewiseCanvas canvas) { history.add((ArrayList) canvas.curves.clone()); state_history.add(new State(maxT, minHz, maxHz, isLinear, showCs, showGrandStaff, showPicture)); version = history.size() - 1; System.out.println("Saved version " + version); undoRedo = false; /* clear flag for next undoRedo sequence */ } public boolean canGet() { boolean result = version >= 0 && version < history.size(); System.out.println("canGet returns " + result + " version " + version); return result; } public ArrayList getCurves() { return history.get(version); } public State getState() { return state_history.get(version); } @SuppressWarnings("unchecked") private void processUndoRedo() { if (!undoRedo) { /* extend with copy of the version */ history.add((ArrayList) (history.get(version).clone())); state_history.add(state_history.get(version)); } else { /* replace with different version */ history.set(history.size() - 1, (ArrayList) (history.get(version).clone())); state_history.set(state_history.size() - 1, state_history.get(version)); } undoRedo = true; } public void undo() { if (version > 0) { version--; processUndoRedo(); } } public void redo() { if (version < history.size() - 1) { version++; processUndoRedo(); } } } private class Curve { public String waveform; public String envelope; public ArrayList times; public ArrayList freqs; public Curve(String wave, String env) { waveform = wave; envelope = env; times = new ArrayList(); freqs = new ArrayList(); } } // Class for the drawing area //private class PiecewiseCanvas extends Canvas implements MouseListener, private class PiecewiseCanvas extends JPanel implements MouseListener, MouseMotionListener, KeyListener { private int currentHz; private int currentTime; public BufferedImage image = null; public boolean selectCheck = false; public int selection; public History history; public boolean mouseDown = false; // used to detect version for undo private boolean changed = false; // used to detect version for undo // Vectors to store the absolute parameters of the points in the // envelope. public ArrayList curves = new ArrayList(); public int selectedCurve; private int left, top, width, height; private BufferedImage background; // Constructor public PiecewiseCanvas() { setBackground(Color.white); addMouseListener(this); addMouseMotionListener(this); addKeyListener(this); selection = -1; history = new History(); history.save(this); selectedCurve = -1; background = null; } public void loadPicture() { JFileChooser chooser = new JFileChooser(); File curdir = new File(mainframe.currentDir); chooser.setCurrentDirectory(curdir); int returnVal = chooser.showOpenDialog(this); File file = null; // in case open fails if (returnVal == JFileChooser.APPROVE_OPTION) { file = chooser.getSelectedFile(); mainframe.changeDirectory(mainframe.fileDirectory(file)); System.out.println("reading image from " + file); try { background = ImageIO.read(file); } catch (Exception e) { System.out.println("Image read failed " + e); JOptionPane.showMessageDialog(this, "Could not open image file"); background = null; } } } public double endTime() { double m = 0; for (Curve c : curves) { for (double time : c.times) { m = Math.max(m, time); } } return m; } public double lowHz() { double low = 20000; for (Curve c : curves) { for (double hz : c.freqs) { low = Math.min(low, hz); } } return low; } public double highHz() { double high = 0; for (Curve c : curves) { for (double hz : c.freqs) { high = Math.max(high, hz); } } return high; } // erase the canvas and clear the parameter vectors - // completely reset the envelope public void clearUpicData(boolean init) { curves.clear(); if (!init) setModified(); repaint(); history.save(this); } // Allow JPanel to accept keyboard events public boolean isFocusable() { return true; } //try to make the canvas the correct size public Dimension getMinimumSize() { return new Dimension(0, 0); } public Dimension getPreferredSize() { return new Dimension(575, 256); } public double impliedAmp() { return 0.0; } /* public Dimension getMaximumSize() { return getPreferredSize(); }*/ // draw the graphics inside the full canvas, so use these // functions to get the size and coordinates of the drawing // area that is usable private int graphLeft() { return LEFT_BORDER; } private int graphWidth() { return getWidth() - (LEFT_BORDER + RIGHT_BORDER); } private int graphTop() { return TOP_BORDER; } private int graphHeight() { return getHeight() - (TOP_BORDER + BOTTOM_BORDER); } private int clipX(int x) { return Math.max(LEFT_BORDER, Math.min(left + width, x)); } private int clipY(int y) { return Math.max(BOTTOM_BORDER, Math.min(top + height, y)); } // public String getExpression() { // String env; // // /*if (type == PWL_TYPE) env = (valueType ? "pwlv" : "pwl"); // else env = (valueType ? "pwev" : "pwe");*/ // // env = "pwlv"; // // return outputEnv(env, true, 0.0, // getMinT(), // getMaxT(), getMinHz(), getMaxHz()); // } //draw the canvas image public void paint(Graphics g) { super.paint(g); Graphics2D drawArea = (Graphics2D) g; if (showCs) { // draw line for C in all octaves double hz = 16.3516; while (hz < maxHz) { drawPitch(drawArea, hz); hz *= 2; } } if (showPicture && (background != null)) { drawArea.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); int x = time2x(0); int y = hz2y(maxHz); int w = time2x(maxT) - x; int h = hz2y(minHz) - y; drawArea.drawImage(background, x, y, w, h, null); } if (showGrandStaff) { // draw GrandStaff lines drawPitch(drawArea, 698.456); // top line F drawPitch(drawArea, 587.330); // D drawPitch(drawArea, 493.883); // B drawPitch(drawArea, 391.995); // G drawPitch(drawArea, 329.628); // E drawPitch(drawArea, 220.000); // A drawPitch(drawArea, 174.614); // F drawPitch(drawArea, 146.832); // D drawPitch(drawArea, 123.471); // B drawPitch(drawArea, 97.9989); // G } connectTheDots(drawArea); drawArea.dispose(); } private void drawPitch(Graphics2D g, double hz) { g.setColor(Color.lightGray); int y = hz2y(hz); g.drawLine(time2x(0), y, time2x(maxT), y); } private void draw_connect(Graphics2D g, double t1, double a1, double t2, double a2) { int x1 = time2x(t1); int x2 = time2x(t2); int y1 = hz2y(a1); int y2 = hz2y(a2); g.drawLine(x1, y1, x2, y2); } private void cacheSize() { left = graphLeft(); top = graphTop(); width = graphWidth() - 1; height = graphHeight() - 1; } //connect adjacent points in the envelope by lines private void connectTheDots(Graphics2D g) { cacheSize(); for (int j = 0; j < curves.size(); j++) { g.setColor(selectedCurve == j ? Color.red : Color.blue); Curve c = curves.get(j); if (c.times.size() > 0) { //connect the points in the envelope double t1 = c.times.get(0); double a1 = c.freqs.get(0); for (int i = 1; i < c.times.size(); i++) { double t2 = c.times.get(i); double a2 = c.freqs.get(i); draw_connect(g, t1, a1, t2, a2); t1 = t2; a1 = a2; } } } } @SuppressWarnings("unchecked") public void restore() { if (history.canGet()) { curves = (ArrayList) (history.getCurves().clone()); State state = history.getState(); maxT = state.maxT; jMaxT.setText(String.valueOf(state.maxT)); minHz = state.minHz; jMinHz.setText(String.valueOf(state.minHz)); maxHz = state.maxHz; jMaxHz.setText(String.valueOf(state.maxHz)); isLinear = state.linear; jLinear.setSelected(state.linear); showCs = state.cs; showGrandStaff = state.gs; showPicture = state.picture; selection = -1; repaint(); } } //set time and amplitude on click by inserting the point into the vectors. public void mousePressed(MouseEvent e) { requestFocus(); cacheSize(); // check for curve selection if (e.getButton() == MouseEvent.BUTTON3) { for (int x = 0; x < curves.size(); x++) { Curve c = curves.get(x); for (int y = 0; y < c.times.size(); y++) { if (Math.abs(time2x(c.times.get(y)) - e.getX()) <= 8 && Math.abs(hz2y(c.freqs.get(y)) - e.getY()) <= 8) { selectedCurve = x; repaint(); System.out.println("Selected curve " + x); System.out.println("e.getX(): " + e.getX()+ ", e.getY: " + e.getY()); System.out.println("c.times.get(y): " + c.times.get(y) + ", c.freqs.get(y): " + c.freqs.get(y)); return; } } } selectedCurve = -1; repaint(); System.out.println("No curve selected"); return; } // not button3, so start a new curve startNewCurve(); mouseDown = true; System.out.println("mouseDown true\n"); this.requestFocus(); currentTime = e.getX(); currentHz = e.getY(); insertInOrder(x2time(currentTime), y2hz(currentHz)); repaint(); } public void mouseDragged(MouseEvent e) { // if this is not the left button drawing event, return if (!mouseDown) return; currentTime = clipX(e.getX()); currentHz = clipY(e.getY()); if (currentTime <= left + width && currentTime >= left && currentHz >= top && currentHz <= top + height) { insertInOrder(x2time(currentTime), y2hz(currentHz)); repaint(); } } public void startNewCurve() { curves.add(new Curve((String) waveformName.getSelectedItem(), (String) envName.getSelectedItem())); } public void mouseReleased(MouseEvent e) { requestFocus(); // otherwise, delete key may not work if (e.getButton() != MouseEvent.BUTTON1) return; if (changed) { history.save(this); changed = false; } mouseDown = false; } // convert time coordinate to time in seconds private double x2time(int x) { return (x - left) * maxT / width; } private int time2x(double time) { return (int) Math.round(time * width / maxT) + left; } // convert amp coordinate to real amplitude private double y2hz(int y) { double mx, mn, r; if (isLinear) { mx = maxHz; mn = minHz; r = mx - mn; return mx - ((y - top) * r / height); } mx = Math.log(maxHz); mn = Math.log(minHz); r = mx - mn; return Math.exp(mx - ((y - top) * r / height)); } private int hz2y(double hz) { double mx, mn; if (isLinear) { mx = maxHz; mn = minHz; } else { mx = Math.log(maxHz); mn = Math.log(minHz); hz = Math.log(hz); } double r = mx - mn; return (int) Math.round((mx - hz) * height / r) + top; } private void addPoint(int i, double absT, double absA) { addPoint(curves.size() - 1, i, absT, absA); } private void addPoint(int curve, int i, double absT, double absA) { //System.out.println("addPoint: " + i + " " + absT + " " + absA); Curve c = curves.get(curve); c.times.add(i, absT); c.freqs.add(i, Math.max(absA, 0.0)); //System.out.println("addPoint time: " + absT + ", text " + form.format(absT)); selection = i; changed = true; setModified(); } //insert the time and amplitude in the vectors in time sorted order private void insertInOrder(double time, double amp) { Curve c = curves.get(curves.size() - 1); int i = c.times.size(); while (i > 0 && time < c.times.get(i - 1)) { i--; } addPoint(i, time, amp); } // Check if mouse click corresponds to existing envelope point // return index of point or -1 if no point is close // private int getSelection(int x, int y) { // int cutoff = 7; // int bestDist = cutoff * 2; // int bestIndex = -1; // if (times == null) return bestIndex; // for (int i = 0; i < times.get(curCurve).size(); i++) { // int xi = time2x(times.get(curCurve).get(i)); // int yi = hz2y(freqs.get(curCurve).get(i)); // int dx = Math.abs(x - xi); // int dy = Math.abs(y - yi); // if (dx < cutoff && dy < cutoff && dx + dy < bestDist) { // bestDist = dx + dy; // bestIndex = i; // } // } // selection = bestIndex; // return bestIndex; // } //Check if mouse click corresponds with existing envelope point (to select point) // private boolean checkSelection(int time, int amp) { // int i = getSelection(time, amp); // if (i < 0) return false; // repaint(); // return true; // } //output the envelope as a string // public String outputEnv(String envType, boolean valueType, double minTime, double maxTime, double minHertz, double maxHertz) { // String outputStr = "(sim"; // // for (int j = 0; j < times.size() - 1; j++) { // int start = 0; // outputStr += " (osc-tri (" + envType; // // if (valueType) { // insert initial value // if (within(times.get(j).get(0), 0.0, EPSILON)) { // outputStr += " " + form.format(freqs.get(j).get(0)); // start = 1; // } else // outputStr += " " + form.format(impliedAmp()); // } // // for (int i = start; i < freqs.get(j).size(); i++) { // double time = times.get(j).get(i); // double amp = freqs.get(j).get(i); // // if (time == 1) // break; // // outputStr += " " + form.format(time) + " " + form.format(amp); // } // // if (valueType) { // we're already ending with a value // if (within(times.get(j).lastElement(), maxTime, EPSILON)) { // // we're done because we output at maxTime // } else // outputStr += " " + form.format(maxTime) + " " + form.format(impliedAmp()); // } else // outputStr += " " + form.format(maxTime); // // outputStr += "))"; // } // outputStr += ")"; // return outputStr; // } // parse envelope from string and prepare to edit // public void setEnv(String envData) { // // System.out.println("\nCALLED setEnv\n"); // // // System.out.println("setEnv: envData " + envData.substring(0, 100) + " ... " + envData.substring(envData.length()-5)); // if (envData == null) return; // just in case // //check if envelope exists in collection // //boolean nameIsEnv = false; // // // trim the open and close parens from envData // int startx = envData.indexOf("(") + 5; // // if no open paren, startx will be 0 // int endx = envData.lastIndexOf(")"); // if (endx < 0) endx = envData.length(); // envData = envData.substring(startx, endx); // // int x = 0; // while (envData.indexOf("(") > -1) { // String strCurve = envData.substring(envData.indexOf("(")+10, envData.indexOf(")")); // envData = envData.substring(envData.indexOf(")")+2); // // StringTokenizer st = new StringTokenizer(strCurve); // String type = st.nextToken(); // System.out.println("setEnv: type " + type); // // valueType = type.endsWith("v"); // // if (times.size() <= x) { // times.add(new Vector()); // freqs.add(new Vector()); // } // // times.get(x).removeAllElements(); // freqs.get(x).removeAllElements(); // int i = 0; // // pretend mouse is down to avoid making each point undo-able // boolean save = mouseDown; // mouseDown = false; // double time, amp; // if (valueType) { // first element is value // amp = new Double(st.nextToken().trim()); // addPoint(x, i++, 0.0, amp); // } // while (st.countTokens() >= 2) { // String token1 = st.nextToken().trim(); // time = new Double(token1); // String token2 = st.nextToken().trim(); // amp = new Double(token2); // addPoint(x, i++, time, amp); // /*System.out.println("time " + token1 + " amp " + token2 + // " size " + times.get(x).size());*/ // } // // mouseDown = save; // restore the mouseDown state // if (!valueType) { // last element is time // maxT.setText(st.nextToken()); // } // // x++; // } // // times.add(new Vector()); // freqs.add(new Vector()); // curCurve = x; // System.out.println("curCurve: " + curCurve); // // modified = false; // repaint(); // } public void keyPressed(KeyEvent event) { System.out.println("key event detected"); if (event.getKeyCode() == KeyEvent.VK_DELETE) { curves.remove(selectedCurve); selectedCurve = -1; canvas.history.save(canvas); System.out.println("curve should be deleted"); repaint(); } } //fill rest of mouse functions public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseClicked(MouseEvent e) {} public void mouseMoved(MouseEvent e) {} public void keyReleased(KeyEvent event) {} public void keyTyped(KeyEvent event) {} } } nyquist-3.05/jnyqide/NyquistWords.txt0000644000175000000620000010721111537432671017075 0ustar stevestaff* expr ...) part19.html#index1460 *a4-hertz* part9.html#index789 *applyhook* part19.html#index1298 *autonorm* part9.html#index790 *autonorm-max-samples* part9.html#index792 *autonorm-previous-peak* part9.html#index793 *autonorm-target* part9.html#index794 *autonorm-type* part9.html#index795 *autonormflag* part9.html#index791 *breakenable* part19.html#index1293 *breakenable* part19.html#index1293 *control-srate* part9.html#index797 *control-srate* part9.html#index797 *debug-io* part19.html#index1292 *default-control-srate* part9.html#index802 *default-plot-file* part8.html#index629 *default-sf-bits* part9.html#index798 *default-sf-dir* part9.html#index799 *default-sf-format* part9.html#index800 *default-sf-srate* part9.html#index801 *default-sound-srate* part9.html#index803 *error-output* part19.html#index1290 *evalhook* part19.html#index1297 *file-separator* part9.html#index804 *float-format* part19.html#index1304 *gc-flag* part19.html#index1301 *gc-hook* part19.html#index1302 *integer-format* part19.html#index1303 *loud* part4.html#index130 *obarray* part19.html#index1287 *print-case* part19.html#index1305 *readtable* part19.html#index1299 *rslt* part9.html#index805 *sound-srate* part9.html#index806 *sound-srate* part9.html#index806 *soundenable* part9.html#index807 *standard-input* part19.html#index1288 *standard-output* part19.html#index1289 *start* part4.html#index133 *stop* part4.html#index134 *sustain* part4.html#index132 *table* part9.html#index788 *trace-output* part19.html#index1291 *tracelimit* part19.html#index1296 *tracelist* part19.html#index1294 *tracenable* part19.html#index1295 *tracenable* part19.html#index1295 *transpose* part4.html#index131 *unbound* part19.html#index1300 *warp* part4.html#index129 + expr ...) part19.html#index1458 - expr ...) part19.html#index1459 / expr ...) part19.html#index1461 1+ expr) part19.html#index1462 1- expr) part19.html#index1463 < n1 n2 ...) part19.html#index1483 abs expr) part19.html#index1471 abs-env beh) part8.html#index546 add-action-to-workspace symbol) part14.html#index1144 add-to-workspace symbol) part14.html#index1141 address-of expr) part19.html#index1612 agc input range rise-time fall-time [lookahead]) part15.html#index1170 alloc num) part19.html#index1602 allpass2 signal hz [q]) part8.html#index438 allpoles-from-lpc snd lpc-frame) part12.html#index970 alpass sound decay hz [minhz]) part8.html#index401 amosc pitch modulation [table phase]) part8.html#index367 and expr ...) part19.html#index1407 append expr ...) part19.html#index1353 apply fun args) part19.html#index1308 apply-banded-bass-boost s lowp highp num-bands num-boost gain) part15.html#index1198 apply-banded-delay s lowp highp num-bands lowd highd fb wet) part15.html#index1196 apply-banded-treble-boost s lowp highp num-bands num-boost gain) part15.html#index1200 arc-sine-dist ) part14.html#index1069 aref array n) part19.html#index1337 areson sound center bandwidth n) part8.html#index423 args name) part13.html#index983 arrayp expr) part19.html#index1391 assoc expr alist :test test :test-not test-not) part19.html#index1357 at time beh) part8.html#index547 at-abs time beh) part8.html#index549 atan expr[expr2]) part19.html#index1479 atom expr) part19.html#index1379 atone sound cutoff) part8.html#index418 autonorm-off ) part8.html#index608 autonorm-on ) part8.html#index607 backquote expr) part19.html#index1312 baktrace [n]) part19.html#index1450 bandpass2 signal hz [q]) part8.html#index436 bernoulli-dist px1 [x1 x2]) part14.html#index1076 beta-dist a b) part14.html#index1074 bigendianp ) part19.html#index1608 bilateral-exponential-dist xmu tau [low high]) part14.html#index1062 binomial-dist n p) part14.html#index1078 biquad signal b0 b1 b2 a0 a1 a2) part8.html#index432 biquad-m signal b0 b1 b2 a0 a1 a2) part8.html#index433 block name expr ...) part19.html#index1430 both-case-p chr) part19.html#index1524 boundp sym) part19.html#index1395 bowed step bowpress-env) part8.html#index496 bowed-freq step bowpress-env freq-env) part8.html#index498 break [bmsg[arg]]) part19.html#index1445 build-harmonic n table-size) part8.html#index334 buzz n pitch modulation) part8.html#index371 car expr) part19.html#index1341 case expr case ...) part19.html#index1412 catch sym expr ...) part19.html#index1418 cauchy-dist tau [low high]) part14.html#index1064 cdr expr) part19.html#index1342 cerror cmsg emsg[arg]) part19.html#index1444 char string index) part19.html#index1521 char-code chr) part19.html#index1526 char-downcase chr) part19.html#index1529 char-equalp chr1 chr2 ...) part19.html#index1541 char-greaterp chr1 chr2 ...) part19.html#index1544 char-int chr) part19.html#index1531 char-lessp chr1 chr2 ...) part19.html#index1539 char-not-equalp chr1 chr2 ...) part19.html#index1542 char-not-greaterp chr1 chr2 ...) part19.html#index1540 char-not-lessp chr1 chr2 ...) part19.html#index1543 char-upcase chr) part19.html#index1528 char/= chr1 chr2 ...) part19.html#index1536 char< chr1 chr2 ...) part19.html#index1533 char<= chr1 chr2 ...) part19.html#index1534 char= chr1 chr2 ...) part19.html#index1535 char> chr1 chr2 ...) part19.html#index1538 char>= chr1 chr2 ...) part19.html#index1537 characterp expr) part19.html#index1390 chorus snd maxdepth depth rate saturation) part15.html#index1191 clarinet step breath-env) part8.html#index474 clarinet-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise) part8.html#index480 clarinet-freq step breath-env freq-env) part8.html#index477 clean-up) part19.html#index1446 clip sound peak) part8.html#index514 close stream) part19.html#index1561 code-char code) part19.html#index1527 comb sound decay hz) part8.html#index402 compress input map rise-time fall-time [lookahead]) part15.html#index1168 compress-map compress-ratio compress-threshold expand-ratio expand-ratio :limit limit :transition transition) part15.html#index1166 cond pair ...) part19.html#index1406 congen gate risetime falltime) part8.html#index404 cons expr1 expr2) part19.html#index1351 consp expr) part19.html#index1386 const value [duration]) part8.html#index322 continue) part19.html#index1448 continuous-control-warp beh) part8.html#index551 continuous-sound-warp beh) part8.html#index552 control sound) part8.html#index321 control-srate-abs srate beh) part8.html#index553 control-warp warp-fn signal [wrate]) part8.html#index338 convolve sound response) part8.html#index407 cos expr) part19.html#index1477 cue sound) part8.html#index318 cue-file filename) part8.html#index319 current-path ) part13.html#index995 cxxr expr) part19.html#index1343 cxxxr expr) part19.html#index1344 cxxxxr expr) part19.html#index1345 db-average input) part15.html#index1167 db-to-linear x) part8.html#index283 decf symbol) part13.html#index987 defmacro sym fargs expr ...) part19.html#index1323 defun sym fargs expr ...) part19.html#index1322 delete expr :test test :test-not test-not) part19.html#index1374 delete-if test list) part19.html#index1375 delete-if-not test list) part19.html#index1376 describe symbol [description]) part14.html#index1143 diff a b) part8.html#index585 digit-char n) part19.html#index1530 digit-char-p chr) part19.html#index1525 do (binding ...) (texpr rexpr ...) expr ...) part19.html#index1423 do* (binding ...) (texpr rexpr ...) expr ...) part19.html#index1424 dolist (sym expr [rexpr]) expr ...) part19.html#index1425 dotimes (sym expr [rexpr]) expr ...) part19.html#index1426 dribble [fname]) part19.html#index1599 drum tracknum patternnum bpm) part15.html#index1241 drum-loop snd duration numtimes) part15.html#index1242 dtmf-tone key len space) part15.html#index1211 echoenabled flag) part19.html#index1617 endp list) part19.html#index1385 env t1 t2 t4 l1 l2 l3 [dur]) part8.html#index324 eq expr1 expr2) part19.html#index1402 eq-band signal hz gain width) part8.html#index443 eq-highshelf signal hz gain [slope]) part8.html#index441 eq-lowshelf signal hz gain [slope]) part8.html#index439 eql expr1 expr2) part19.html#index1403 equal expr1 expr2) part19.html#index1404 error emsg[arg]) part19.html#index1443 errset expr [pflag]) part19.html#index1449 eval expr) part19.html#index1307 evalhook expr ehook ahook [env]) part19.html#index1453 evenp expr) part19.html#index1400 event-dur event) part14.html#index1092 event-end event) part14.html#index1096 event-expression event) part14.html#index1094 event-get-attr event attribute [default]) part14.html#index1101 event-has-attr event attribute) part14.html#index1100 event-set-attr event attribute value) part14.html#index1102 event-set-dur event dur) part14.html#index1093 event-set-expression event dur) part14.html#index1095 event-set-time event time) part14.html#index1091 event-time event) part14.html#index1090 exit ) part19.html#index1613 exp x-expr) part19.html#index1481 exp-dec hold halfdec length) part8.html#index325 expand num) part19.html#index1601 exponential-dist delta [high]) part14.html#index1059 expr-get-attr expression attribute [default]) part14.html#index1098 expr-has-attr expression attribute) part14.html#index1097 expr-set-attr expr attribute value) part14.html#index1099 expt x-expr y-expr) part19.html#index1480 extract start stop beh) part8.html#index555 extract-abs start stop beh) part8.html#index556 fboundp sym) part19.html#index1396 feedback-delay sound delay feedback) part8.html#index410 filep expr) part19.html#index1394 find-in-xlisp-path filename) part19.html#index1575 first expr) part19.html#index1346 flange snd) part15.html#index1186 flatc expr) part19.html#index1553 flatsize expr) part19.html#index1552 flet (binding ...) expr ...) part19.html#index1415 float expr) part19.html#index1457 floatp expr) part19.html#index1388 flute step breath-env) part8.html#index490 flute-all step breath-env freq-env vibrato-freq vibrato-gain jet-delay noise) part8.html#index494 flute-freq step breath-env freq-env) part8.html#index492 fmfb pitch index [dur]) part8.html#index369 fmlfo freq [table phase]) part8.html#index332 fmosc pitch modulation [table phase]) part8.html#index368 follow sound floor risetime falltime lookahead) part8.html#index284 force-srate srate sound) part8.html#index327 format stream fmt arg ...) part19.html#index1555 fourth expr) part19.html#index1349 funcall fun arg ...) part19.html#index1309 function expr) part19.html#index1311 gamma-dist nu [high]) part14.html#index1061 gate sound lookahead risetime falltime floor threshold) part8.html#index288 gaussian-dist xmu sigma [low high]) part14.html#index1072 gc ) part19.html#index1600 gcd n1 n2 ...) part19.html#index1472 gensym [tag]) part19.html#index1324 geometric-dist p) part14.html#index1080 get sym prop) part19.html#index1333 get-duration dur) part8.html#index303 get-env name) part19.html#index1593 get-lambda-expression closure) part19.html#index1314 get-loud ) part8.html#index304 get-output-stream-list stream) part19.html#index1591 get-output-stream-string stream) part19.html#index1590 get-slider-value index) part8.html#index642 get-sustain ) part8.html#index305 get-temp-path ) part19.html#index1569 get-transpose ) part8.html#index306 get-user ) part19.html#index1572 get-warp ) part8.html#index307 go sym) part19.html#index1434 grindef name) part13.html#index981 hash sym n) part19.html#index1331 highpass2 signal hz [q]) part8.html#index435 highpass4 signal hz) part8.html#index448 highpass6 signal hz) part8.html#index449 highpass8 signal hz) part8.html#index450 hp sound cutoff) part8.html#index416 hyperbolic-cosine-dist [low high]) part14.html#index1066 hz-to-step freq) part8.html#index290 hzosc hz [table phase]) part8.html#index358 if texpr expr1[expr2]) part19.html#index1409 incf symbol) part13.html#index985 info ) part19.html#index1603 int-char int) part19.html#index1532 integerp expr) part19.html#index1387 integrate signal) part8.html#index350 intern pname) part19.html#index1325 interpolate x x1 y1 x2 y2) part14.html#index1148 intersection a b) part14.html#index1150 jcrev sound decay mix) part8.html#index458 labels (binding ...) expr ...) part19.html#index1416 lambda args expr ...) part19.html#index1313 last list) part19.html#index1355 length expr) part19.html#index1361 length-of-beat bpm) part15.html#index1243 let (binding ...) expr ...) part19.html#index1413 let* (binding ...) expr ...) part19.html#index1414 lfo freq [duration table phase]) part8.html#index330 linear-dist g) part14.html#index1057 linear-to-db x) part8.html#index291 list expr ...) part19.html#index1352 listdir path) part19.html#index1564 listp expr) part19.html#index1384 load fname [:verbose verbose] [:print print]) part19.html#index1596 local-to-global local-time) part8.html#index308 log x) part8.html#index293 logand expr ...) part19.html#index1490 logior expr ...) part19.html#index1491 logistic-dist alpha beta [low high]) part14.html#index1067 lognot expr) part19.html#index1493 logxor expr ...) part19.html#index1492 loop expr ...) part19.html#index1422 loud volume beh) part8.html#index557 loud-abs volume beh) part8.html#index558 lower-case-p chr) part19.html#index1523 lowpass2 signal hz [q]) part8.html#index434 lowpass4 signal hz) part8.html#index445 lowpass6 signal hz) part8.html#index446 lowpass8 signal hz) part8.html#index447 lp sound cutoff) part8.html#index413 lpc-frame-err frame) part12.html#index974 lpc-frame-filter-coefs frame) part12.html#index975 lpc-frame-rms1 frame) part12.html#index972 lpc-frame-rms2 frame) part12.html#index973 lpreson snd lpc-iterator skiptime) part12.html#index971 macroexpand form) part19.html#index1315 macroexpand-1 form) part19.html#index1316 macrolet (binding ...) expr ...) part19.html#index1417 make-accumulate sub-pattern :for for :max maximum :min minimum :name name :trace trace) part14.html#index1028 make-accumulation items :name name :trace trace) part14.html#index1022 make-array size) part19.html#index1338 make-copier sub-pattern :repeat repeat :merge merge :for for :name name :trace trace) part14.html#index1025 make-cycle items :for for :name name :trace trace) part14.html#index1007 make-eval expr :for for :name name :trace trace) part14.html#index1037 make-heap items :for for :max max :name name :trace trace) part14.html#index1019 make-length pattern length-pattern :name name :trace trace) part14.html#index1044 make-line items :for for :name name :trace trace) part14.html#index1010 make-lpanal-iterator sound framedur skiptime npoles) part12.html#index966 make-lpc-file-iterator filename) part12.html#index967 make-markov rules :past past :produces produces :for for :name name :trace trace) part14.html#index1048 make-palindrome items :elide elide :for for :name name :trace trace) part14.html#index1016 make-product x y :for for :name name :trace trace) part14.html#index1034 make-random items :for for :name name :trace trace) part14.html#index1013 make-string-input-stream str[start[end]]) part19.html#index1588 make-string-output-stream) ) part19.html#index1589 make-sum x y :for for :name name :trace trace) part14.html#index1031 make-symbol pname) part19.html#index1326 make-window pattern length-pattern skip-pattern :name name :trace trace) part14.html#index1047 maketable sound) part8.html#index333 mandolin step dur [detune]) part8.html#index500 mapc fcn list1 list ...) part19.html#index1364 mapcar fcn list1 list ...) part19.html#index1365 mapl fcn list1 list ...) part19.html#index1366 maplist fcn list1 list ...) part19.html#index1367 markov-create-rules sequence order [generalize]) part14.html#index1051 max expr ...) part19.html#index1469 member expr list :test test :test-not test-not) part19.html#index1356 midi-show the-seq [out-file]) part15.html#index1206 midi-show-file file-name) part15.html#index1203 min expr ...) part19.html#index1467 minusp expr) part19.html#index1397 modalbar preset step dur) part8.html#index510 mult a [b ...]) part8.html#index582 mult beh1 beh2 ...) part8.html#index582 nband input gains) part15.html#index1177 nband-range input gains lowf highf) part15.html#index1174 nconc list ...) part19.html#index1373 noise [duration]) part8.html#index538 not expr) part19.html#index1383 notch2 signal hz [q]) part8.html#index437 nrev sound decay mix) part8.html#index454 nstring-downcase str :start start :end end) part19.html#index1504 nstring-upcase str :start start :end end) part19.html#index1503 nth n list) part19.html#index1362 nthcdr n list) part19.html#index1363 null expr) part19.html#index1382 numberp expr) part19.html#index1381 Ny:all part2.html#index67 objectp expr) part19.html#index1393 oddp expr) part19.html#index1401 open fname :direction direction) part19.html#index1557 open-binary fname :direction direction) part19.html#index1558 or expr ...) part19.html#index1408 osc pitch [duration table phase]) part8.html#index355 osc-enable flag) part8.html#index309 osc-note pitch [duration env loud table]) part8.html#index529 osc-pulse hz bias [compare-shape]) part8.html#index363 osc-saw hz) part8.html#index359 osc-tri hz) part8.html#index361 pan sound where) part8.html#index341 params-scale params keyword amount) part14.html#index1147 params-transpose params keyword amount) part14.html#index1146 partial pitch env) part8.html#index356 patternp expression) part14.html#index1145 peak expression maxlen) part8.html#index687 peek addrs) part19.html#index1606 peek-char [flag[stream]]) part19.html#index1578 phaser snd) part15.html#index1184 piano-midi midi-file-name) part15.html#index1164 piano-midi2file midi-file-name sound-file-name) part15.html#index1165 piano-note duration step dynamic) part15.html#index1161 piano-note-2 step dynamic) part15.html#index1163 pitshift sound shift mix) part8.html#index470 pl-center snd) part15.html#index1233 pl-doppler snd r) part15.html#index1238 pl-left snd) part15.html#index1232 pl-pan2d snd x y) part15.html#index1236 pl-position snd x y config) part15.html#index1237 pl-rear snd) part15.html#index1235 pl-right snd) part15.html#index1234 play sound part8.html#index591 play-file filename) part8.html#index606 pluck pitch [duration final-amplitude]) part8.html#index372 plusp expr) part19.html#index1399 poisson-dist delta) part14.html#index1082 poke addrs value) part19.html#index1607 pop lis) part13.html#index990 power x y) part13.html#index1001 pprint expr[stream]) part19.html#index1550 prcrev sound decay mix) part8.html#index462 prin1 expr[stream]) part19.html#index1548 princ expr[stream]) part19.html#index1549 print expr [stream]) part19.html#index1547 prod beh1 beh2 ...) part8.html#index343 prod beh1 beh2 ...) part8.html#index343 profile flag) part19.html#index1454 prog (binding ...) expr ...) part19.html#index1428 prog* (binding ...) expr ...) part19.html#index1429 prog1 expr1 expr ...) part19.html#index1436 prog2 expr1 expr2 expr ...) part19.html#index1437 progn expr ...) part19.html#index1438 progv slist vlist expr ...) part19.html#index1435 prologic l c r s) part15.html#index1229 psetq [sym expr] ...) part19.html#index1320 push val lis) part13.html#index989 putprop sym val prop) part19.html#index1334 pwe t1 l1 t2 l2 ... tn) part8.html#index390 pwe-list breakpoints) part8.html#index391 pwer i1 l1 i2 l2 ... in) part8.html#index394 pwer-list breakpoints) part8.html#index395 pwev l1 t2 l2 t3 t3 ... tn ln) part8.html#index392 pwev-list breakpoints) part8.html#index393 pwevr l1 i2 l2 i3 i3 ... in ln) part8.html#index397 pwevr-list breakpoints) part8.html#index398 pwl t1 l1 t2 l2 ... tn) part8.html#index382 pwl-list breakpoints) part8.html#index383 pwlr i1 l1 i2 l2 ... in) part8.html#index386 pwlr-list breakpoints) part8.html#index387 pwlv l1 t2 l2 t3 t3 ... tn ln) part8.html#index384 pwlv-list breakpoints) part8.html#index385 pwlvr l1 i2 l2 i3 i3 ... in ln) part8.html#index388 pwlvr-list breakpoints) part8.html#index389 quantize sound steps) part8.html#index530 quote expr) part19.html#index1310 ramp [duration]) part11.html#index947 random n) part19.html#index1473 read [stream[eof[rflag]]]) part19.html#index1546 read-byte [stream]) part19.html#index1585 read-char [stream]) part19.html#index1576 read-float [stream[length]]) part19.html#index1582 read-int [stream[length]]) part19.html#index1580 read-line [stream]) part19.html#index1584 real-random from to) part13.html#index1000 recip sound) part8.html#index533 rem expr ...) part19.html#index1464 remove expr list :test test :test-not test-not) part19.html#index1358 remove-if test list) part19.html#index1359 remove-if-not test list) part19.html#index1360 remprop sym prop) part19.html#index1335 require-from fnsymbol filename [path]) part13.html#index993 resample sound srate) part8.html#index344 reson sound center bandwidth n) part8.html#index419 rest expr) part19.html#index1350 restore fname) part19.html#index1598 return [expr]) part19.html#index1431 return-from name[value]) part19.html#index1432 reverb snd time) part15.html#index1207 reverse expr) part19.html#index1354 rms sound [rate window-size]) part8.html#index532 room ) part19.html#index1604 rplaca list expr) part19.html#index1371 rplacd list expr) part19.html#index1372 rrandom ) part19.html#index1474 s-abs sound) part8.html#index516 s-add-to expression maxlen filename [offset]) part8.html#index618 s-exp sound) part8.html#index520 s-log sound) part8.html#index522 s-max sound1 sound2) part8.html#index525 s-min sound1 sound2) part8.html#index527 s-overwrite expression maxlen filename [offset]) part8.html#index621 s-plot sound [dur n]) part8.html#index627 s-print-tree sound) part8.html#index630 s-read filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag) part8.html#index615 s-read-reverse filename :time-offset offset :srate sr :dur dur :nchans chans :format format :mode mode :bits n :swap flag) part15.html#index1183 s-rest [duration]) part8.html#index537 s-reverse snd) part15.html#index1179 s-save expression maxlen filename :format format :mode mode :bits bits :swap flag :play play) part8.html#index611 s-sqrt sound) part8.html#index518 sampler pitch modulation [sample npoints]) part8.html#index378 save fname) part19.html#index1597 save-lpc-file lpc-iterator filename) part12.html#index968 save-workspace ) part14.html#index1142 sax step breath-env) part8.html#index487 sax-all step breath-env freq-env vibrato-freq vibrato-gain reed-stiffness noise blow-pos reed-table-offset) part8.html#index488 sax-freq step breath-env freq-env) part8.html#index485 scale scale sound) part8.html#index345 scale-db db sound) part8.html#index346 scale-srate sound scale) part8.html#index347 score-adjacent-events score function :from-index i :to-index j :from-time x :to-time y) part14.html#index1126 score-append score1 score2 ...) part14.html#index1112 score-apply score function :from-index i :to-index j :from-time x :to-time y) part14.html#index1127 score-filter-length score cutoff) part14.html#index1120 score-filter-overlap score) part14.html#index1123 score-gen :k1 e1 :k2 e2 ...) part14.html#index1087 score-get-begin score) part14.html#index1116 score-get-end score) part14.html#index1118 score-indexof score function :from-index i :to-index j :from-time x :to-time y) part14.html#index1128 score-last-indexof score function :from-index i :to-index j :from-time x :to-time y) part14.html#index1129 score-merge score1 score2 ...) part14.html#index1111 score-must-have-begin-end score) part14.html#index1119 score-play score) part14.html#index1125 score-print score) part14.html#index1124 score-randomize-start score amt :from-index i :to-index j :from-time x :to-time y) part14.html#index1130 score-read-smf filename) part14.html#index1136 score-repeat score n) part14.html#index1121 score-scale score keyword amount :from-index i :to-index j :from-time x :to-time y) part14.html#index1108 score-select score predicate :from-index i :to-index j :from-time x :to-time y :reject flag) part14.html#index1113 score-set-begin score time) part14.html#index1115 score-set-end score time) part14.html#index1117 score-shift score offset :from-index i :to-index j :from-time x :to-time y) part14.html#index1105 score-sort score [copy-flag]) part14.html#index1104 score-sorted score) part14.html#index1103 score-stretch score factor :dur dur-flag :time time-flag :from-index i :to-index j :from-time x :to-time y) part14.html#index1106 score-stretch-to-length score length) part14.html#index1122 score-sustain score factor :from-index i :to-index j :from-time x :to-time y) part14.html#index1109 score-transpose score keyword amount :from-index i :to-index j :from-time x :to-time y) part14.html#index1107 score-voice score replacement-list :from-index i :to-index j :from-time x :to-time y) part14.html#index1110 score-write-smf score filename [programs]) part14.html#index1138 second expr) part19.html#index1347 Self part19.html#index1286 seq beh1 [beh2 ...]) part8.html#index574 seqrep var limit beh) part8.html#index575 set sym expr) part19.html#index1318 set-control-srate rate) part8.html#index294 set-difference a b) part14.html#index1155 set-logical-stop beh time) part8.html#index579 set-pitch-names ) part8.html#index298 set-sound-srate rate) part8.html#index296 setdir path[verbose]) part19.html#index1562 setf [place expr] ...) part19.html#index1321 setq [sym expr] ...) part19.html#index1319 setup-console ) part19.html#index1614 sf-granulate filename grain-dur grain-dev ioi ioi-dev pitch-dev [file-start file-end]) part15.html#index1202 sf-info filename) part8.html#index624 shape signal table origin) part8.html#index425 shift-time sound shift) part8.html#index348 show-lpc-data lpc-iterator iniframe endframe [poles?]) part12.html#index969 sim [beh1 beh2 ...]) part8.html#index576 simrep var limit beh) part8.html#index577 sin expr) part19.html#index1476 sine pitch [duration]) part8.html#index357 siosc pitch modulation tables) part8.html#index376 sitar step dur) part8.html#index512 slope signal) part8.html#index352 snd-abs sound) part8.html#index644 snd-add sound1 sound) part8.html#index648 snd-allpoles snd lpc-coefs gain) part12.html#index977 snd-alpass sound delay feedback) part8.html#index713 snd-alpasscv sound delay feedback) part8.html#index714 snd-alpassvv sound delay feedback maxdelay) part8.html#index715 snd-amosc sound step sr hz t0 am phase) part8.html#index747 snd-areson sound hz bw normalization) part8.html#index716 snd-aresoncv sound hz bw normalization) part8.html#index717 snd-aresonvc sound hz bw normalization) part8.html#index718 snd-aresonvv sound hz bw normalization) part8.html#index719 snd-atone sound hz) part8.html#index720 snd-atonev sound hz) part8.html#index721 snd-avg sound blocksize stepsize operation) part8.html#index652 snd-bandedwg freq bowpress-env preset sr) part8.html#index757 snd-biquad sound b0 b1 b2 a1 a2 z1init z2init) part8.html#index722 snd-bowed freq bowpress-env sr) part8.html#index759 snd-bowed-freq freq bowpress-env freq-env sr) part8.html#index761 snd-buzz n sr hz t0 fm) part8.html#index751 snd-chase sound risetime falltime) part8.html#index723 snd-clarinet freq breath-env sr) part8.html#index763 snd-clarinet-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise sr) part8.html#index767 snd-clarinet-freq freq breath-env freq-env sr) part8.html#index765 snd-clip sound peak) part8.html#index657 snd-compose f g) part8.html#index660 snd-congen gate risetime falltime) part8.html#index724 snd-const value t0 srate duration) part8.html#index633 snd-convolve sound response) part8.html#index725 snd-copy sound) part8.html#index673 snd-coterm s1 s2) part8.html#index637 snd-delay sound delay feedback) part8.html#index726 snd-delaycv sound delay feedback) part8.html#index727 snd-down srate sound) part8.html#index675 snd-exp sound) part8.html#index676 snd-extent sound maxsamples) part8.html#index256 snd-fetch sound) part8.html#index259 snd-fetch-array sound len step) part8.html#index261 snd-fft sound length skip window) part10.html#index812 snd-flatten sound maxlen) part8.html#index262 snd-flute freq breath-env sr) part8.html#index768 snd-flute-all freq vibrato-freq vibrato-gain freq-env breath-env jet-delay noise sr) part8.html#index772 snd-flute-freq freq breath-env freq-env sr) part8.html#index770 snd-fmfb t0 hz sr index dur) part8.html#index749 snd-fmfbv t0 hz sr index) part8.html#index750 snd-fmosc s step sr hz t0 fm phase) part8.html#index748 snd-follow sound floor risetime falltime lookahead) part8.html#index677 snd-from-array t0 sr array) part8.html#index252 snd-fromarraystream t0 sr object) part8.html#index253 snd-fromobject t0 sr object) part8.html#index254 snd-gate sound lookahead risetime falltime floor threshold) part8.html#index680 snd-ifft time srate iterator skip window) part10.html#index814 snd-inverse signal start srate) part8.html#index684 snd-length sound maxlen) part8.html#index263 snd-log sound) part8.html#index685 snd-lpanal samps npoles) part12.html#index976 snd-lpreson snd lpc-iterator skiptime) part12.html#index978 snd-mandolin t0 freq dur body-size detune sr) part8.html#index774 snd-max expression maxlen) part8.html#index688 snd-maxsamp sound) part8.html#index264 snd-maxv sound1 sound2) part8.html#index690 snd-modalbar t0 freq preset dur sr) part8.html#index776 snd-multiseq array closure) part8.html#index785 snd-normalize sound) part8.html#index692 snd-offset sound offset) part8.html#index649 snd-oneshot sound threshold ontime) part8.html#index693 snd-osc s step sr hz t0 d phase) part8.html#index753 snd-overwrite expression maxlen filename offset format mode bits swap) part8.html#index636 snd-partial sr hz t0 env) part8.html#index754 snd-play expression) part8.html#index265 snd-pluck sr hz t0 d final-amp) part8.html#index752 snd-print expression maxlen) part8.html#index274 snd-print-tree sound) part8.html#index266 snd-prod sound1 sound2) part8.html#index696 snd-pwl t0 sr lis) part8.html#index699 snd-quantize sound steps) part8.html#index701 snd-read filename offset t0 format channels mode bits swap sr dur) part8.html#index634 snd-recip sound) part8.html#index702 snd-resample f rate) part8.html#index703 snd-resamplev f rate g) part8.html#index705 snd-reson sound hz bw normalization) part8.html#index728 snd-resoncv sound hz bw normalization) part8.html#index729 snd-resonvc sound hz bw normalization) part8.html#index730 snd-resonvv sound hz bw normalization) part8.html#index731 snd-samples sound limit) part8.html#index268 snd-save expression maxlen filename format mode bits swap play) part8.html#index635 snd-sax freq breath-env sr) part8.html#index778 snd-sax-all freq vibrato-freq vibrato-gain freq-env breath-env reed-stiffness noise blow-pos reed-table-offset sr) part8.html#index781 snd-sax-freq freq freq-env breath-env sr) part8.html#index780 snd-scale scale sound) part8.html#index708 snd-seq sound closure) part8.html#index784 snd-set-latency latency) part8.html#index316 snd-set-logical-stop sound time) part8.html#index276 snd-shape signal table origin) part8.html#index709 snd-sine t0 hz sr d) part8.html#index755 snd-siosc tables sr hz t0 fm) part8.html#index756 snd-sitar t0 freq dur sr) part8.html#index782 snd-slider index t0 srate duration) part8.html#index643 snd-sqrt sound) part8.html#index646 snd-srate sound) part8.html#index271 snd-sref sound time) part8.html#index277 snd-stkchorus sound delay depth freq mix sr) part8.html#index732 snd-stkpitshift sound shift mix sr) part8.html#index736 snd-stkrev rev-type sound decay mix sr) part8.html#index740 snd-stop-time sound) part8.html#index278 snd-t0 sound) part8.html#index273 snd-tapf sound offset vardelay maxdelay) part8.html#index670 snd-tapv sound offset vardelay maxdelay) part8.html#index665 snd-time sound) part8.html#index272 snd-tone sound hz) part8.html#index744 snd-tonev sound hz) part8.html#index746 snd-trigger s closure) part8.html#index786 snd-up srate sound) part8.html#index710 snd-white t0 sr d) part8.html#index640 snd-xform sound sr time start stop scale) part8.html#index711 snd-yin sound minstep maxstep rate) part8.html#index712 snd-zero t0 srate) part8.html#index641 soften-clipping snd cutoff) part15.html#index1172 sort list test) part19.html#index1377 sound sound) part8.html#index320 sound-off ) part8.html#index610 sound-on ) part8.html#index609 sound-srate-abs srate beh) part8.html#index559 sound-warp warp-fn signal [wrate]) part8.html#index349 soundfilename name) part8.html#index626 soundp sound) part8.html#index279 span snd amt) part15.html#index1225 speed-dial thelist) part15.html#index1212 sqrt expr) part19.html#index1482 sref sound time) part8.html#index248 sref-inverse sound value) part8.html#index250 stats ) part8.html#index280 step-to-hz pitch) part8.html#index302 stereo-chorus snd) part15.html#index1190 stereoize snd) part15.html#index1217 stkchorus sound depth freq mix [delay]) part8.html#index466 strcat expr ...) part19.html#index1505 streamp expr) part19.html#index1392 stretch factor beh) part8.html#index561 stretch-abs factor beh) part8.html#index562 string expr) part19.html#index1495 string-downcase str :start start :end end) part19.html#index1502 string-equalp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1516 string-greaterp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1519 string-left-trim bag str) part19.html#index1499 string-lessp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1514 string-not-equalp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1517 string-not-greaterp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1515 string-not-lessp str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1518 string-right-trim bag str) part19.html#index1500 string-search pat str :start start :end end) part19.html#index1496 string-trim bag str) part19.html#index1498 string-upcase str :start start :end end) part19.html#index1501 string/= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1511 string< str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1508 string<= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1509 string= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1510 string> str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1513 string>= str1 str2 :start1 start1 :end1 end1 :start2 start2 :end2 end2) part19.html#index1512 stringp expr) part19.html#index1389 sublis alist expr :test test :test-not test-not) part19.html#index1369 subseq string start[end]) part19.html#index1507 subsetp a b) part14.html#index1156 subst to from expr :test test :test-not test-not) part19.html#index1368 sum a [b ...]) part8.html#index580 sustain factor beh) part8.html#index563 sustain-abs factor beh) part8.html#index567 swapchannels snd) part15.html#index1226 symbol-function sym) part19.html#index1329 symbol-name sym) part19.html#index1327 symbol-plist sym) part19.html#index1330 symbol-value sym) part19.html#index1328 symbolp expr) part19.html#index1380 tagbody expr ...) part19.html#index1433 tan expr) part19.html#index1478 tapv sound offset vardelay maxdelay) part8.html#index451 terpri [stream]) part19.html#index1551 third expr) part19.html#index1348 throw sym[expr]) part19.html#index1419 timed-seq score) part8.html#index587 tone sound cutoff) part8.html#index415 top-level) part19.html#index1447 trace sym) part19.html#index1441 transpose amount beh) part8.html#index568 transpose-abs amount beh) part8.html#index569 trigger s beh) part8.html#index578 truncate expr) part19.html#index1456 type-of expr) part19.html#index1605 union a b) part14.html#index1152 unless texpr expr ...) part19.html#index1411 untrace sym) part19.html#index1442 unwind-protect expr cexpr ...) part19.html#index1420 upper-case-p chr) part19.html#index1522 vector expr ...) part19.html#index1339 warp fn beh) part8.html#index570 warp-abs fn beh) part8.html#index571 wg-glass-harm step bowpress-env) part8.html#index506 wg-tibetan-bowl step bowpress-env) part8.html#index508 wg-tuned-bar step bowpress-env) part8.html#index504 wg-uniform-bar step bowpress-env) part8.html#index502 when test action) part19.html#index1410 when texpr expr ...) part19.html#index1410 while test expr1 expr2 ...) part13.html#index991 widen snd amt) part15.html#index1220 write-byte byte[stream]) part19.html#index1586 write-char ch[stream]) part19.html#index1579 write-float ch[stream[length]]) part19.html#index1583 write-int ch[stream[length]]) part19.html#index1581 yin sound minstep maxstep stepsize) part8.html#index539 zerop expr) part19.html#index1398 nyquist-3.05/jnyqide/Trie.java0000644000175000000620000000664711466723256015425 0ustar stevestaff/* package jnyqide; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Trie { Node root; /** * Creates an WordMode object with the given dictionary. * * @param strs * A list of strings containing the words in dictionary file which * contains the list of valid words sorted by frequency */ /* public Trie() { root = new Node(); } public void addWord(String word) { char[] letters = word.toCharArray(); Node n = root; for(int i = 0; i < letters.length; i++) { if(n.get((int)letters[i]) == null) { Node x = n.addNode((int)letters[i]); x.parent = n; n = x; } else n = n.get((int)letters[i]); } if(letters[letters.length-1] == ')') word = "(" + word; n.addWord(word); while(n.parent != null) { n = n.parent; n.addWord(word); } } /* Since you are not allowed to use anything from java.util (except for the * Iterator interface and AbstractList), you must create your own implementation * of a list. (You may choose to extend AbstractList if you would like) * * If you would like to return an AbstractList, * **Hint: What are the methods you need to implement in order to extend * AbstractList? Also, in order for the AbstractList to function, * what other methods must you override? */ // if full, must match all letters /* public List getWordsFor(String s, Boolean full) { char[] letters = s.toCharArray(); Node n = root; for(int i = 0; i < letters.length; i++) { if(n.get((int)letters[i]) == null) return (full ? null : n.unmodifiableList); else n = n.get((int)letters[i]); } return n.unmodifiableList; } public List getAllWordsFor(String s) { List r = new ArrayList(); List l = getWordsFor("", false); int i = 0; while (i < l.size()) { if (l.get(i).toString().contains(s)) { r.add(l.get(i).toString()); } i++; } return r; } private class Node { Node parent; Node nodes [] = new Node [128]; ArrayList words = new ArrayList (); List unmodifiableList; public Node() { parent = null; unmodifiableList = Collections.unmodifiableList(new AbstractList() { public int size() { return words.size(); } public String get(int i) { return (String) words.get(i); } }); } public Node get(int index) { return nodes[index]; } public Node addNode(int i) { if(nodes[i] == null) nodes[i] = new Node(); return nodes[i]; } public void addWord(String str) { words.add(str); // System.out.println("( " + str + " ) is added to Trie"); } } } */nyquist-3.05/jnyqide/manifest.txt0000644000175000000620000000003111466723256016203 0ustar stevestaffMain-Class: jnyqide/Main nyquist-3.05/jnyqide/PlotFrame.java0000644000175000000620000003151511466723256016403 0ustar stevestaffpackage jnyqide; import javax.swing.*; import java.awt.*; import java.util.*; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ // Note: originally this code put plots in JInternalFrames. The code to // support this is commented out and marked with "JPANEL:" public class PlotFrame extends JPanel { //JPANEL: JInternalFrame { double minX, minY, height, width; // range of data values to be plotted double minXlabel, minYlabel, xSpacing, ySpacing; int numXlines, numYlines; // number of lines to be plotted double minLabel, spacing; // computed by AxisLayout int numLines; // computed by AxisLayout double xExtent, yExtent; // value range of plot area Vector data; PlotMouseAdapter mouse; Graphics g; // the whole thing, including labels Graphics gGraph; // the graph image without labels Image buffer; Image graphBuffer; int bufferHeight; // size of plot with labels int bufferWidth; // size of plot with labels //JPANEL: int offsetWindowSide = 3; // To clear the side bar //JPANEL: int offsetWindowTop = 21; // To clear the title bar int offsetX = 40; // how wide is label space to left of gGraph int offsetRight = 10; // how wide is space to right of gGraph int offsetY = 5; // how high is space above of gGraph int dotSize = 3; // diameter of data points on the plot image int textHeight = 20; // width of plot area (without labels) int graphBufferWidth; // height of plot area (without labels) int graphBufferHeight; int axisMinSpacing = 30; //JPANEL: int gadgetHeight = 10; public void CalcBufferSize() { graphBufferWidth = bufferWidth - offsetX - offsetRight; graphBufferWidth = Math.max(10, graphBufferWidth); graphBufferHeight = bufferHeight - textHeight; //JPANEL: - gadgetHeight; graphBufferHeight = Math.max(10, graphBufferHeight); } public PlotFrame(JPanel jPanel) { minX = 0; minY = -1; width = 1; height = 2; xExtent = 1; yExtent = 2; data = new Vector(); data.add(new Pair(0.0, 0.0)); data.add(new Pair(1.0, 0.0)); mouse = new PlotMouseAdapter(this); setPreferredSize(new Dimension(400, 100)); // setResizable(true); addMouseMotionListener(mouse); addMouseListener(mouse); setVisible(true); jPanel.add(this, BorderLayout.CENTER); CalcBufferSize(); renderGraph(); } public void PlotData(Vector d, double minx, double miny, double maxx, double maxy) { //System.out.println("PlotData called."); minX = minx; minY = miny; height = maxy - miny; width = maxx - minx; data = d; //System.out.println("PlotData calling repaint"); renderGraph(); repaint(); } //JPANEL: This is old code to put a plot in a JInternalFrame // public PlotFrame(JDesktopPane jDesktop, Vector d, double minx, double miny, // double maxx, double maxy) { // minX = minx; // minY = miny; // height = maxy - miny; // width = maxx - minx; // data = d; // mouse = new PlotMouseAdapter(this); // // setSize(new Dimension(720, 520)); // //JPANEL: setResizable(true); // //JPANEL: this.setClosable(true); // //JPANEL: this.setIconifiable(true); // // addMouseMotionListener(mouse); // addMouseListener(mouse); // // //JPANEL: setTitle("Plot"); // setVisible(true); // jDesktop.add(this); // CalcBufferSize(); // // renderGraph(); // } // // private int degree(double n) // { // int deg = 0; // while (n < 10) { // n *= 10.0; // deg++; // } // return deg; // } // (END JPANEL:) // do label layouts for x and y axes. Returns values by setting // spacing, minLabel, and numLines // public void AxisLayout(int buffersize, int axisMinSpacing, double minval, double range) { if (range < 0.000001) range = 1.0; // convert range of zero // compute axis layout // first, figure out about how many label divisions there can be int nlabels = buffersize / axisMinSpacing; if (nlabels <= 0) nlabels = 1; // avoid divide by zero // now figure out what that is in terms of the data // spacing is a proposed spacing for labels in terms of actual data spacing = range / nlabels; // now increase spacing to nearest multiple of 0.1, 0.2, 0.5, ... // first, get spacing between 0.1 and 1.0 double tens = 1.0; //System.out.print("spacing "); System.out.println(spacing); while (spacing < 0.1) { spacing = spacing * 10.0; tens = tens * 0.1; } while (spacing > 1.0) { spacing = spacing * 0.1; tens = tens * 10.0; } // now 0.1 <= spacing <= 1.0, and spacing * tens is original value // adjust spacing up to 0.2, 0.5, or 1.0 // this will result in greater than minimum spacing if (spacing < 0.2) spacing = 0.2; else if (spacing < 0.5) spacing = 0.5; else spacing = 1.0; // now translate back to original power of ten spacing = spacing * tens; // figure out minLabel, the first multiple of spacing less or equal to minval // the extra 0.1% added by multiplying by 1.001 is there so that if // minval is already very close to a multiple of spacing, it is used // Sometimes this happens due to floating point rounding even when // minval is an exact multiple of spacing. minLabel = ((int) ((minval / spacing) * 1.001)) * spacing; // (int) rounds toward zero, so if minval is negative, subtract one if (minLabel > minval + spacing * 0.0001) minLabel -= spacing; // since spacing may have increased, we may not need so many divisions to // span the range of the data numLines = (int) ((minval + range - minLabel) / spacing); // increase by one in case we rounded down if (numLines < (minval + range - minLabel) / spacing) numLines += 1; // increase by one again. E.g. if the graph is divided in two, there are // three lines. (Always one more line than division.) numLines += 1; System.out.print("minLabel "); System.out.print(minLabel); System.out.print(" spacing "); System.out.println(spacing); System.out.print(" numLines " + numLines); } public void renderGraph() { System.out.println("renderGraph"); if (gGraph == null) { System.out.print("creating graphbuffer"); System.out.print(graphBufferWidth); System.out.print(", "); System.out.println(graphBufferHeight); graphBuffer = createImage(graphBufferWidth, graphBufferHeight); //System.out.println(graphBuffer); if (graphBuffer == null) return; // Why does this fail? gGraph = graphBuffer.getGraphics(); } gGraph.setColor(new Color(220, 220, 220)); gGraph.fillRect(0, 0, graphBufferWidth, graphBufferHeight); System.out.println("calling AxisLayout"); AxisLayout(graphBufferWidth, axisMinSpacing, minX, width); //System.out.print("return from AxisLayout"); xExtent = spacing * (numLines - 1); minXlabel = minLabel; xSpacing = spacing; numXlines = numLines; AxisLayout(graphBufferHeight, axisMinSpacing, minY, height); yExtent = spacing * (numLines - 1); minYlabel = minLabel; ySpacing = spacing; numYlines = numLines; // draw graph as lines first, then overlay circles ListIterator iter = data.listIterator(); Pair prev = (Pair) iter.next(); int x1 = (int) ((prev.getTime() - minXlabel) / xExtent * graphBufferWidth); int y1 = (int) ((1.0 - ((prev.getValue() - minYlabel) / yExtent)) * graphBufferHeight); Color pointColor = new Color(220, 220, 0); while (iter.hasNext()) { Pair p = (Pair) iter.next(); gGraph.setColor(Color.black); int x2 = (int) ((p.getTime() - minXlabel) / xExtent * graphBufferWidth); int y2 = (int) ((1.0 - ((p.getValue() - minYlabel) / yExtent)) * graphBufferHeight); gGraph.drawLine(x1, y1, x2, y2); gGraph.setColor(pointColor); x1 = x1 - dotSize / 2; y1 = y1 - dotSize / 2; gGraph.fillOval(x1, y1, dotSize, dotSize); gGraph.setColor(Color.black); gGraph.drawOval(x1, y1, dotSize, dotSize); x1 = x2; y1 = y2; } // draw the last point gGraph.setColor(pointColor); x1 = x1 - dotSize / 2; y1 = y1 - dotSize / 2; gGraph.fillOval(x1, y1, dotSize, dotSize); gGraph.setColor(Color.black); gGraph.drawOval(x1, y1, dotSize, dotSize); double x = minXlabel; for (int i = 0; i < numXlines; i++) { //System.out.println(x); int axisX = (int) (((x - minXlabel) / ((numXlines - 1) * xSpacing)) * graphBufferWidth + 0.5); gGraph.setColor(new Color(170, 170, 170)); gGraph.drawLine(axisX, 0, axisX, graphBufferHeight ); x += xSpacing; } double y = minYlabel; for (int i = 0; i < numYlines; i++) { //double y = minYlabel; y < minYlabel + height; y += ySpacing) { int axisY = (int) ((1.0 - ((y - minYlabel) / ((numYlines - 1) * ySpacing))) * graphBufferHeight + 0.5); gGraph.setColor(new Color(170, 170, 170)); gGraph.drawLine(0, axisY, graphBufferWidth, axisY ); y += ySpacing; } } public void paint(Graphics g2) { // Graphics g = getContentPane().getGraphics(); System.out.println("Painting..."); // because the window can be resized, check if we have the right width and height //System.out.print("graph dim "); System.out.print(getWidth()); //System.out.print(", "); System.out.println(getHeight()); if ((getHeight() != bufferHeight) || (getWidth() != bufferWidth)) { g = null; // delete any existing double buffer to force an update gGraph = null; // the plot image is here, update this too //System.out.println("recalculate width and height"); } if (g == null) { // create matching image buffer for double buffer update bufferHeight = getHeight(); bufferWidth = getWidth(); buffer = createImage(bufferWidth, bufferHeight); g = buffer.getGraphics(); CalcBufferSize(); } if (gGraph == null) { renderGraph(); } if (g2 != null) { g.setColor(new Color(150, 150, 150)); g.fillRect(0, 0, bufferWidth, bufferHeight); //JPANEL: - gadgetHeight); if (gGraph != null) { g.drawImage(graphBuffer, offsetX, offsetY, offsetX + graphBufferWidth, offsetY + graphBufferHeight, 0, 0, graphBufferWidth, graphBufferHeight, this); } double x = minXlabel; for (int i = 0; i < numXlines; i++) { int axisX = (int) (((x - minXlabel) / (xSpacing * (numXlines - 1))) * graphBufferWidth + 0.5); g.setColor(Color.black); String s = Double.toString(Math.round(x * 1000) / 1000.0); g.drawString(s, offsetX + axisX - s.length() * 2 - (i == numXlines - 1 ? s.length() * 2 : 0), offsetY + graphBufferHeight + textHeight - 8); x += xSpacing; } double y = minYlabel; for (int i = 0; i < numYlines; i++) { int axisY = (int) (((y - minYlabel) / (ySpacing * (numYlines - 1))) * graphBufferHeight + 0.5); g.setColor(Color.black); String s = Double.toString(Math.round(y * 1000) / 1000.0); // note: offset top string to fit within graphics area g.drawString(s, offsetX - s.length() * 5 - 5, offsetY + graphBufferHeight - axisY + (i == numYlines - 1 ? textHeight - 8 : 0)); y += ySpacing; } } super.paint(g2); //JPANEL: g2.drawImage(buffer, offsetWindowSide, offsetWindowTop, this ); g2.drawImage(buffer, 0, 0, this ); } } nyquist-3.05/jnyqide/closeFile.gif0000644000175000000620000000220211466723256016232 0ustar stevestaffGIF89aֵ{kƥZcZ{ƭƽ!s{{kssZB1s!cJJc{1{R{c{!Zk)RZs!c{ccJJ9)Jk{J!1RcscJJs{1s{c{RJ)sc)sZޔs{Bk9k)RsJ9!s֭{sRcs11έ掠BJRcs)19s)9J1Jc{c9s1JJ)R!sZZB{s{19B{9s)sZcƜJkR{J{J!J{9c1)s9kcB!JsZsRk9Rs1JkJsBk!9Z)R9sJ1kB9cRsJkBc!Bs1c)Z)c1{1c֔)9Rck!1JJ)R1ZZcsBZ!1s9Z!J99ck{{9Jk!9kB{!J甜)9Z)B{!J{9RB9Z{c!9{)s!!{Z{JcBckIImmUmmU𠠤!,l H(\Ȑ@ H1bD}0p"iX}?lxRȊQ&3dK ݹPǠ,nԉǥFv(Q*&e!This GIF file was assembled with GIF Construction Set from: Alchemy Mindworks Inc. P.O. Box 500 Beeton, Ontario L0G 1A0 CANADA. This comment block will not appear in files created with a registered version of GIF Construction Set;nyquist-3.05/jnyqide/ReplaceDialog.java0000644000175000000620000001235311466723256017204 0ustar stevestaff/* * Copyright (c) 1997 John Jensen. All rights reserved. * * This software is FREE FOR COMMERCIAL AND NON-COMMERCIAL USE, * provided the following condition is met. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that any copy or derivative of this software or documentation * retaining the name "John Jensen" also retains this condition and the * following disclaimer. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * CopyrightVersion 1.0 */ package jnyqide; import java.util.*; import java.awt.*; import java.awt.event.*; import jnyqide.*; class ReplaceDialog extends Dialog implements WindowListener, ActionListener { private Button fbutton,rbutton,cbutton; private TextField pattern; private TextField replace; private MainFrame mainFrame; private NyquistFile nyquistFile; private Properties strings; private boolean foundOnce = false; public ReplaceDialog(NyquistFile tf, MainFrame mainFrame_) { super(mainFrame_, "Replace", true); mainFrame = mainFrame_; setBackground(Color.lightGray); nyquistFile = tf; Panel p1 = new Panel(); GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints constraints = new GridBagConstraints(); p1.setLayout(gridbag); Label flabel = new Label("Find"); constraints.anchor = GridBagConstraints.NORTHWEST; gridbag.setConstraints(flabel, constraints); pattern = new TextField(); pattern.setColumns(35); if(tf.pane.getSelectedText() == null) // BWP pattern.setText(mainFrame.findPattern); else // BWP pattern.setText(tf.pane.getSelectedText()); // BWP constraints.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(pattern, constraints); p1.add(flabel); p1.add(pattern); Label rlabel = new Label("Replace"); constraints.anchor = GridBagConstraints.WEST; constraints.gridwidth = 1; gridbag.setConstraints(rlabel, constraints); replace = new TextField(); replace.setColumns(35); replace.setText(mainFrame.replacePattern); constraints.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(replace, constraints); p1.add(rlabel); p1.add(replace); add("Center", p1); Panel p3 = new Panel(); fbutton = new Button("Find Next"); fbutton.addActionListener(this); p3.add(fbutton); rbutton = new Button("Replace"); rbutton.addActionListener(this); p3.add(rbutton); cbutton = new Button("Close"); cbutton.addActionListener(this); p3.add(cbutton); add("South",p3); Dimension size = new Dimension(400,120); setSize(size); Point tfloc = tf.getLocation(); Point mfloc = mainFrame.getLocation(); setLocation(mfloc.x + tfloc.x, mfloc.y + tfloc.y + 75); addWindowListener(this); setVisible(true); } public void windowDeiconified(WindowEvent event) {} public void windowIconified(WindowEvent event) {} public void windowActivated(WindowEvent event) {} public void windowDeactivated(WindowEvent event) {} public void windowOpened(WindowEvent event) {} public void windowClosed(WindowEvent event) {} public void windowClosing(WindowEvent event) { mainFrame.findPattern = pattern.getText(); mainFrame.replacePattern = replace.getText(); dispose(); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() == cbutton) { mainFrame.findPattern = pattern.getText(); mainFrame.replacePattern = replace.getText(); dispose(); return; } if (evt.getSource() == fbutton) foundOnce = nyquistFile.find(pattern.getText()); else if (evt.getSource() == rbutton) { if (!foundOnce) { String selection= nyquistFile.copy(false,false); if (selection != null) foundOnce = selection.equals(pattern.getText()); } if (foundOnce) nyquistFile.paste(replace.getText()); foundOnce = nyquistFile.find(pattern.getText()); } if (!foundOnce) { NotFoundDialog nf = new NotFoundDialog(mainFrame, strings, getLocation()); nf.setVisible(true); } } } nyquist-3.05/jnyqide/MiniBrowser.java0000644000175000000620000000435211466723256016751 0ustar stevestaffpackage jnyqide; import java.awt.*; import javax.swing.*; import javax.swing.text.html.*; import javax.swing.event.*; import java.net.URL; public class MiniBrowser extends JInternalFrame { JEditorPane urlPane; class Hyperactive implements HyperlinkListener { public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { JEditorPane pane = (JEditorPane) e.getSource(); if (e instanceof HTMLFrameHyperlinkEvent) { HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e; //System.out.println("Target = " + evt.getTarget()); HTMLDocument doc = (HTMLDocument) pane.getDocument(); doc.processHTMLFrameHyperlinkEvent(evt); } else { try { urlPane.setPage(e.getURL()); } catch (Throwable t) { t.printStackTrace(); } } } } } public MiniBrowser(String title) { super(title); urlPane = new JEditorPane(); urlPane.setEditable(false); urlPane.addHyperlinkListener(new Hyperactive()); JScrollPane sp = new JScrollPane(urlPane); sp.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); sp.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); setVisible(false); setClosable(true); getContentPane().add(sp); setResizable(true); setPreferredSize(new Dimension(400, 400)); setLocation(50, 100); setSize(700, 400); setDefaultCloseOperation(HIDE_ON_CLOSE); } public void setPage(String url) { try { // hard-wired URL for testing only!: // System.out.println("setPage actual input: " + url); // url = "file://doc/nyquist/doc/part8.html"; URL u = new URL(url); System.out.println("MiniBrowser.setPage: " + u); urlPane.setPage(u); } catch (Exception ex) { System.out.println( "Exception from urlPane.setPage: " + ex); } } } nyquist-3.05/jnyqide/NyquistFile.java0000644000175000000620000005004711537224066016761 0ustar stevestaffpackage jnyqide; import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.event.*; import javax.swing.*; import javax.swing.text.*; import javax.swing.undo.*; import jnyqide.*; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ // BWP -- added "implements ActionListener" public class NyquistFile extends JInternalFrame implements ActionListener, ComponentListener { DefaultStyledDocument doc; JTextPane pane; public final CodePane filePane; JLabel statusBar = new JLabel(); UndoManager undo; File file; public boolean modified = false; NyquistFile thisFile; MainFrame myParent; //BWP String lastFound = ""; //BWP -- BUG, shouldn't these be global? //String revertTo = ""; //BWP public File getFile() { return file; } // BWP: Constructors now take a MainFrame object to associate // the document window with the parent window for Find // and Find/Replace operations public NyquistFile(MainFrame parent, int fontSize) { // BWP this(null, parent, fontSize); // BWP modified = true; setTitle(getTitle()+"*"); } public void readFile(File file) { if (file != null) { try { FileInputStream openFileStream = new FileInputStream(file); byte b[] = new byte[1000]; // read 1K at a time int pos = 0; //System.out.println("starting to read file"); doc.remove(0, doc.getLength()); // clear the current content while (openFileStream.available() > 0) { int count = openFileStream.read(b); doc.insertString(pos, new String(b, 0, count), TextColor.attrNormal); pos += count; } } catch (Exception e2) { System.out.println(e2); } } } public void determineType() { String name = file.getName(); filePane.isSal = name.toLowerCase().endsWith(".sal"); } public NyquistFile(File f, MainFrame parent, int fontSize) { super(); setTitle(f != null ? f.getName() : "Untitled"); file = f; thisFile = this; myParent = parent; int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); // Menu Bar for top of Document Windows JMenuBar myMenuBar = new JMenuBar(); // File Menu JMenu myFileMenu = new JMenu("File"); JMenuItem myLoad = new JMenuItem("Load"); myLoad.setActionCommand("load"); myLoad.addActionListener(this); myLoad.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_K, keyMask)); JMenuItem mySave = new JMenuItem("Save"); mySave.setActionCommand("save"); mySave.addActionListener(this); mySave.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, keyMask)); JMenuItem mySaveAs = new JMenuItem("Save As..."); mySaveAs.setActionCommand("save as"); mySaveAs.addActionListener(this); mySaveAs.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, keyMask | java.awt.event.InputEvent.SHIFT_MASK)); JMenuItem myRevert = new JMenuItem("Revert"); myRevert.setActionCommand("revert"); myRevert.addActionListener(this); JMenuItem myClose = new JMenuItem("Close"); myClose.setActionCommand("close"); myClose.addActionListener(this); myClose.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_W, keyMask)); myFileMenu.add(myLoad); myFileMenu.add(mySave); myFileMenu.add(mySaveAs); myFileMenu.add(myRevert); myFileMenu.add(myClose); // Edit Menu JMenu myEditMenu = new JMenu("Edit"); JMenuItem myCut = new JMenuItem("Cut"); myCut.setActionCommand("cut"); myCut.addActionListener(this); myCut.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, keyMask)); JMenuItem myCopy = new JMenuItem("Copy"); myCopy.setActionCommand("copy"); myCopy.addActionListener(this); myCopy.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, keyMask)); JMenuItem myPaste = new JMenuItem("Paste"); myPaste.setActionCommand("paste"); myPaste.addActionListener(this); myPaste.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, keyMask)); JMenuItem myFind = new JMenuItem("Find..."); myFind.setActionCommand("find"); myFind.addActionListener(this); myFind.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, keyMask)); JMenuItem myNext = new JMenuItem("Find Next"); myNext.setActionCommand("next"); myNext.addActionListener(this); myNext.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, keyMask)); JMenuItem myReplace = new JMenuItem("Replace"); myReplace.setActionCommand("replace"); myReplace.addActionListener(this); myReplace.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, keyMask)); JMenuItem mySelect = new JMenuItem("Select Expression"); mySelect.setActionCommand("select expression"); mySelect.addActionListener(this); mySelect.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E, keyMask)); myEditMenu.add(myCut); myEditMenu.add(myCopy); myEditMenu.add(myPaste); myEditMenu.addSeparator(); myEditMenu.add(myFind); myEditMenu.add(myNext); myEditMenu.add(myReplace); myEditMenu.add(mySelect); // Set up Menu Bar myMenuBar.add(myFileMenu); myMenuBar.add(myEditMenu); thisFile.setJMenuBar(myMenuBar); /* BWP END */ // end menu stuff filePane = new CodePane(null, null, statusBar, fontSize); pane = filePane.pane; System.out.println("NyquistFile creation, this " + this + " pane = " + pane); doc = filePane.doc; getContentPane().add(filePane); statusBar.setPreferredSize(new Dimension(200, 8)); getContentPane().add(statusBar, java.awt.BorderLayout.SOUTH); statusBar.setText(""); if (file != null) { readFile(file); determineType(); } /////////////// BWP BEGIN // Right-Click Menu for the Document Window JPopupMenu myContext = new JPopupMenu(); JMenuItem contextCut = new JMenuItem("Cut"); contextCut.setActionCommand("context cut"); contextCut.setName("context cut"); contextCut.addActionListener(this); JMenuItem contextCopy = new JMenuItem("Copy"); contextCopy.setActionCommand("context copy"); contextCopy.setName("context copy"); contextCopy.addActionListener(this); JMenuItem contextPaste = new JMenuItem("Paste"); contextPaste.setActionCommand("context paste"); contextPaste.setName("context paste"); contextPaste.addActionListener(this); JMenuItem contextFind = new JMenuItem("Find"); contextFind.setActionCommand("context find"); contextFind.setName("context find"); contextFind.addActionListener(this); JMenuItem contextReplace = new JMenuItem("Replace"); contextReplace.setActionCommand("context replace"); contextReplace.setName("context replace"); contextReplace.addActionListener(this); JMenuItem contextSelect = new JMenuItem("Select Expression"); contextSelect.setActionCommand("context select"); contextSelect.setName("context select"); contextSelect.addActionListener(this); myContext.add(contextCut); myContext.add(contextCopy); myContext.add(contextPaste); myContext.addSeparator(); myContext.add(contextFind); myContext.add(contextReplace); myContext.add(contextSelect); MouseListener popupListener = new PopupListener(myContext, pane); pane.addMouseListener(popupListener); //////////////// BWP END setLocation(50+10, 50+10); setSize(600, 500); setBackground(Color.white); setResizable(true); setVisible(true); this.setClosable(true); this.setMaximizable(true); this.setIconifiable(true); setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); System.out.println("Adding component listener"); filePane.addComponentListener(this); doc.addDocumentListener( new DocumentListener() { public void changedUpdate(DocumentEvent e) { } public void removeUpdate(DocumentEvent e) { //filePane.synchronousUpdate(null); if (!modified) { modified = true; thisFile.setTitle(thisFile.getTitle() + "*"); } } public void insertUpdate(DocumentEvent e) { // System.out.println("insertUpdate calls thread.update"); //filePane.synchronousUpdate(null); if (!modified) { modified = true; thisFile.setTitle(thisFile.getTitle() + "*"); } } }); //revertTo = pane.getText(); // BWP } public void doFileSave() { if (file != null) save(file.getParent()); else saveAs(""); } //// BWP BEGIN public void actionPerformed(ActionEvent e) { //System.out.println(e.getActionCommand()); // File Menu options if (e.getActionCommand().equals("load")) { doFileSave(); myParent.loadFile(file); } else if (e.getActionCommand().equals("save")) { doFileSave(); } else if (e.getActionCommand().equals("save as")) { if (file != null) saveAs(file.getParent()); else saveAs(""); } else if (e.getActionCommand().equals("revert")) { if (modified && file != null) { readFile(file); myParent.loadFile(file); //pane.setText(revertTo); modified = false; thisFile.setTitle(thisFile.getTitle().substring(0, thisFile.getTitle().length() - 1)); } } else if (e.getActionCommand().equals("close")) { int input = 1; if (modified) input = JOptionPane.showConfirmDialog(null, "Close without saving?", "Closing...", JOptionPane.YES_NO_OPTION); else this.dispose(); if (input == 0) this.dispose(); // Edit Menu options } else if (e.getActionCommand().equals("cut")) { pane.cut(); } else if (e.getActionCommand().equals("copy")) { pane.copy(); } else if (e.getActionCommand().equals("paste")) { pane.paste(); } else if (e.getActionCommand().equals("find")) { FindDialog findDialog = new FindDialog(thisFile, myParent); } else if (e.getActionCommand().equals("next")) { if (!lastFound.equals("")) find(lastFound); } else if (e.getActionCommand().equals("replace")) { ReplaceDialog replaceDialog = new ReplaceDialog(thisFile, myParent); } else if (e.getActionCommand().equals("select expression")) { myParent.doEditSelectExpression(e); // Context Menu Options } else if (e.getActionCommand().equals("context cut")) { pane.cut(); } else if (e.getActionCommand().equals("context copy")) { pane.copy(); } else if (e.getActionCommand().equals("context paste")) { pane.paste(); } else if (e.getActionCommand().equals("context find")) { FindDialog findDialog = new FindDialog(thisFile, myParent); } else if (e.getActionCommand().equals("context replace")) { ReplaceDialog replaceDialog = new ReplaceDialog(thisFile, myParent); } else if (e.getActionCommand().equals("context select")) { myParent.doEditSelectExpression(e); } //// BWP END } public void componentResized(ComponentEvent e) { System.out.println(e.getComponent().getClass().getName() + " --- Resized "); filePane.synchronousUpdate(); } public void componentHidden(ComponentEvent e) { System.out.println(e.getComponent().getClass().getName() + " --- Hidden "); } public void componentMoved(ComponentEvent e) { System.out.println(e.getComponent().getClass().getName() + " --- Moved "); } public void componentShown(ComponentEvent e) { System.out.println(e.getComponent().getClass().getName() + " --- Shown "); } String currentSelection() { System.out.println("currentSelection: this " + this + " pane " + pane); int p = pane.getSelectionStart(); int q = pane.getSelectionEnd(); try { return doc.getText(p, q - p); } catch(Exception e) { System.out.println(e); return ""; } } public void setCursor(int line, int col) { try { // because getText raises an exception BadLocationException String text = doc.getText(0, doc.getLength()); int i = 0; int j = 0; while (j < line - 1) if (text.charAt(i++) == '\n') j++; final int pos = i + col - 1; EventQueue.invokeLater( new Runnable() { public void run() { System.out.println("Automatically move caret to " + pos); pane.select(pos, pos); } }); } catch(Exception e) { System.out.println(e); } } public void selectExpression() { int docLength; String text; try { docLength = doc.getLength(); text = doc.getText(0, docLength); } catch (Exception e) { System.out.println(e); return; } int p = pane.getSelectionStart(); int openParenLoc = CodePane.findOpenParen(text, p); if (openParenLoc == p) return; if (openParenLoc < 0) return; // no open paren enclosing start of selection // now findx is the beginning of the expression and closed == 0 // go forward from p to find close paren int closed = 0; while (p < text.length() && closed < 1) { char c = text.charAt(p); if (c == '(' || c == ')') { if (!CodePane.inComment(text, p)) { if (c == '(') closed--; else if (c == ')') closed++; } } if (closed < 1) // not done, keep going p = forward(text, p, false); } pane.select(openParenLoc, p + 1); // add one to include close paren } private static int forward(String text, int pos, boolean inString) // find an index in text after pos by skipping over strings and // escaped characters of the form #\A, also skip comment // lines. If pos is text.length() - 1, return text.length() { boolean comment = false; boolean string = false; while (pos < text.length()) { char c = text.charAt(pos); if (comment) { if (c == '\n') { comment = false; } } else if (string) { if (c == '"') { // skip string string = false; } } else if (c == '\\') { // skip quoted char pos++; } else if (c == '"') { string = true; } else if (c == ';') { comment = true; } pos++; if (!comment && !string) return pos; } return pos; } public boolean find(String pat) { String docText = ""; int start = pane.getSelectionEnd(); //System.out.print("location "); //System.out.println(start); try { docText = doc.getText(0, doc.getLength()); } catch(Exception e) {System.out.println(e);} //System.out.print(docText); int found = docText.indexOf(pat, start); if (found == -1) { found = docText.indexOf(pat, 0); } if (found == -1) return false; pane.select(found, found + pat.length()); return true; } public String copy(boolean a, boolean b) { String selectedText = pane.getSelectedText(); pane.copy(); return selectedText; } public boolean paste(String text) { pane.replaceSelection(text); return true; } public String getAbsolutePath() { return file.getAbsolutePath(); } public boolean save(String currentDir) // saves the file if there is a file name, otherwise calls saveAs. // returns false if the operation fails or is cancelled. // returns true if save succeeds or if file is unmodified. { if (modified) { if (file == null) return saveAs(currentDir); else { try { long length = file.length(); long newLength = doc.getLength(); System.out.println("existing " + length + " new " + newLength); String msg = null; if (length > 0 && newLength == 0) { msg = "Replace existing file with an empty document?"; } else if (length > newLength * 2) { msg = "Replace file with new document that is less than 1/2 the existing size?"; } if (msg != null) { int n = JOptionPane.showConfirmDialog(this, msg, "WARNING", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (n == JOptionPane.NO_OPTION) return false; } FileOutputStream saveFileStream = new FileOutputStream(file); String fileStr = doc.getText(0, doc.getLength()); saveFileStream.write(fileStr.getBytes()); saveFileStream.flush(); } catch(Exception e) { System.out.println(e); return false; // did not save file } modified = false; thisFile.setTitle(thisFile.getTitle().substring( 0, thisFile.getTitle().length() - 1)); } } //revertTo = pane.getText(); return true; } public boolean saveAs(String currentDir) { // select a file and write to it. Return true if success. JFileChooser chooser = new JFileChooser(); LispFileFilter filter = new LispFileFilter(); SalFileFilter salFilter = new SalFileFilter(); String name; // new file name chooser.setFileFilter(filter); chooser.setFileFilter(salFilter); File curdir = new File(currentDir); chooser.setCurrentDirectory(curdir); while (true) { // loop until file is chosen int returnVal = chooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { file = chooser.getSelectedFile(); name = file.getName(); System.out.println("You chose to save this file: " + name); String lower = name.toLowerCase(); if (lower.endsWith(".sal") || lower.endsWith(".lsp")) break; JOptionPane dialog = new JOptionPane(); System.out.println("creating dialog"); int result = dialog.showConfirmDialog(this, "Do you really want to save a file without a " + ".lsp or .sal extension?", "Warning", JOptionPane.YES_NO_OPTION); System.out.println("return from dialog " + result); if (result == JOptionPane.YES_OPTION) break; } else { // file chooser cancel, early return return false; } } setTitle(name + "*"); determineType(); modified = true; return save(currentDir); } } nyquist-3.05/jnyqide/openFile.gif0000644000175000000620000000215411466723256016074 0ustar stevestaffGIF89aֵ{kƥZcZ{ƭƽ!s{{kssZB1s!cJJc{1{R{c{!Zk)RZs!c{ccJJ9)Jk{J!1RcscJJs{1s{c{RJ)sc)sZޔs{Bk9k)RsJ9!s֭{sRcs11έ掠BJRcs)19s)9J1Jc{c9s1JJ)R!sZZB{s{19B{9s)sZcƜJkR{J{J!J{9c1)s9kcB!JsZsRk9Rs1JkJsBk!9Z)R9sJ1kB9cRsJkBc!Bs1c)Z)c1{1c֔)9Rck!1JJ)R1ZZcsBZ!1s9Z!J99ck{{9Jk!9kB{!J甜)9Z)B{!J{9RB9Z{c!9{)s!!{Z{JcBckIImmUmmU𠠤!,V H*4BF"E} /q߿}C2HңGKDqeȗM@fM>δi"<{lF"+" !This GIF file was assembled with GIF Construction Set from: Alchemy Mindworks Inc. P.O. Box 500 Beeton, Ontario L0G 1A0 CANADA. This comment block will not appear in files created with a registered version of GIF Construction Set;nyquist-3.05/jnyqide/SalFileFilter.java0000644000175000000620000000135611466723256017177 0ustar stevestaff// // SalFileFilter.java // nyquist // // Created by Roger Dannenberg on 12/23/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // package jnyqide; import javax.swing.filechooser.*; import java.io.File; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ public class SalFileFilter extends FileFilter { public SalFileFilter() { } public boolean accept(File f) { if (f.getName().endsWith(".sal")) return true; for (int x = 0; x < f.getName().length(); x++) { if ((f.getName().charAt(x) == '.')) return false; } return true; } public String getDescription() { return "Sal files."; } } nyquist-3.05/jnyqide/WordList.java0000644000175000000620000002237511466723256016265 0ustar stevestaffpackage jnyqide; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.ArrayList; import javax.swing.JTextArea; import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; public class WordList { //public static Trie wordsTrie = new Trie(); public static JTextArea textArea; public static JTextPane pane; public static int startPos; public static int endPos; public static Map URLLinks = new HashMap(); public static ArrayList words = new ArrayList (); public static String getlink(String word) { // strip off syntax help from word, e.g. (osc-tri hz) -> osc System.out.println("getlink " + word); if (word.charAt(0) == '(') { int i = word.indexOf(" "); if (i <= 0) i = word.length() - 1; // remove ")" word = word.substring(1, i); } else /* maybe SAL mode */ { int i = word.indexOf("("); if (i > 0) word = word.substring(0, i); } String s = URLLinks.get(word); System.out.println("getlink(" + word + ")->" + s); if (s == null) return "home.html"; return s; } public static void init(JTextArea a) { textArea = a; //System.out.println("initializing WordList.java"); try { BufferedReader inf; try { inf = new BufferedReader(new FileReader("NyquistWords.txt")); System.out.println("\n\n***********************Opened NyquistWords.txt*********\n\n"); } catch (IOException e) { System.out.println("could not find NyquistWords.txt, trying jnyqide/NyquistWords.txt"); inf = new BufferedReader(new FileReader("jnyqide/NyquistWords.txt")); } String word, link; while ((word = inf.readLine()) != null) { //wordsTrie.addWord(word); words.add(word); link = inf.readLine(); if ((link == null) || (link.equals(""))) link = "home.html"; //char[] letters = word.toCharArray(); //if (letters[letters.length-1] == ')') word = "(" + word; //URLLinks.put(word, link); // word is usually an expression, e.g. // "transpose-abs amount beh)", so parse out the first word int i = word.indexOf(" "); if (i >= 0) word = word.substring(0, i); i = word.indexOf(")"); if (i >= 0) word = word.substring(0, i); URLLinks.put(word, link); } inf.close(); } catch (IOException e) { System.out.println("Error: could not open NyquistWords.txt"); } } public static String removeChar(String word, char c) { int loc = word.indexOf(c); while (loc >= 0) { word = word.substring(0, loc) + word.substring(loc + 1); loc = word.indexOf(c); } return word; } public static void appendSyntaxTip(StringBuffer s, String word, boolean sal) { // let's keep the brackets until we copy the hint string into an editor // first, remove brackets // word = removeChar(removeChar(word, '['), ']'); // if this is a lisp expression, append close paren if (word.charAt(word.length() - 1) == ')') { if (sal) { // make it prefix with commas int loc = word.indexOf(' '); // end of function name int loc2 = loc + 1; // trim the space if (loc < 0) { loc = word.indexOf(')'); loc2 = loc; // don't trim the ')' } if (loc < 0) { System.out.println("appendSyntaxTip internal error: |" + word + "|"); return; } // now loc is the character after the function name and // loc2 is the character to place after the open paren word = word.substring(0, loc) + "(" + word.substring(loc2); // insert commas after tokens starting after open paren loc = loc + 1; while (loc < word.length()) { // advance to token while (loc < word.length() && (word.charAt(loc) == ' ' || word.charAt(loc) == '[' || word.charAt(loc) == ']')) loc++; // retain starting location for keyword processing loc2 = loc; // advance to end of word while (loc < word.length() && word.charAt(loc) != ' ' && word.charAt(loc) != '[' && word.charAt(loc) != ']') loc++; // convert to keyword or maybe add comma if (loc < word.length()) { if (word.charAt(loc2) == ':') { word = word.substring(0, loc2) + // before keyword word.substring(loc2 + 1, loc) + // after ':' ":" + word.substring(loc); // insert comma if this is not the last parameter, // determined by looking ahead for a space } else if (word.indexOf(' ', loc) > 0) { word = word.substring(0, loc) + "," + word.substring(loc); loc = loc + 1; // skip the comma } } // System.out.println("word |" + word + "| loc " + loc); } } else { s.append("("); } } s.append(word); s.append("\n"); } public static void getAllWordsFor(String str, StringBuffer s, boolean sal) { for (int i = 0; i < words.size(); i++) { String word = (String) words.get(i); int pos = word.indexOf(str); if (pos >= 0) { int sp = word.indexOf(" "); if (sp < 0 || sp > pos) { appendSyntaxTip(s, word, sal); } } } } public static boolean isKeyword(String str) { String s = URLLinks.get(str); return s != null; /* str = str.toLowerCase(); for (int i = 0; i < words.size(); i++) { String word = (String) words.get(i); int pos = word.indexOf(str); if (pos == 0 && (word.length() == str.length() || (word.charAt(str.length() - 1) == ' ' || word.charAt(str.length() - 1) == ')'))) { return true; } } return false; */ } public static void getWordsFor(String str, StringBuffer s, boolean sal) { for (int i = 0; i < words.size(); i++) { String word = (String) words.get(i); int pos = word.indexOf(str); if (pos == 0) { appendSyntaxTip(s, word, sal); } } } public static void printList(String str, JTextPane jTextPane, int start, int end, boolean forceExact, boolean sal) { //List l; //System.out.println("printList: prefFullSearch = " + MainFrame.prefFullSearch); //if (MainFrame.prefFullSearch) l = wordsTrie.getAllWordsFor(str.toLowerCase()); //else l = wordsTrie.getWordsFor(str.toLowerCase(), false); //System.out.println(l); //StringBuffer s = new StringBuffer(); //if (l != null) { // Iterator iter = l.iterator(); // while (iter.hasNext()) { // s.append(iter.next()).append("\n"); // } //} StringBuffer s = new StringBuffer(); str = str.toLowerCase(); if (MainFrame.prefFullSearch && !forceExact) getAllWordsFor(str, s, sal); else getWordsFor(str, s, sal); textArea.setText(s.toString()); pane = jTextPane; startPos = start; endPos = end; // haven't inserted character yet } public static void replaceWithTemplate(String template) { // templates were displayed in textArea based on what the user // typed. Now, the user has clicked on a template. Replace what // the user typed (and parens) with the template string. String before; try { before = pane.getText(startPos - 1, 1); if (before.equals("(")) startPos--; } catch (Exception ex) { } String after; try { after = pane.getText(endPos, 1); while (Character.isWhitespace(after.charAt(0))) { endPos++; after = pane.getText(endPos, 1); } if (after.equals(")")) endPos++; } catch (Exception ex) { } pane.select(startPos, endPos); // remove those pesky brackets (denoting "optional") template = removeChar(removeChar(template, '['), ']'); pane.replaceSelection(template); } } nyquist-3.05/jnyqide/Jslide.java0000755000175000000620000001462711466723256015734 0ustar stevestaffpackage jnyqide; import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.event.*; import java.util.*; public class Jslide extends JFrame implements ActionListener { MainFrame myParent; static final int numSliders = 8; static final int numEqualizers = 10; /* Sliders and labels that will be used on the gui*/ JSlider[] js; float[][] eqState; /* Buttons that will appear on the Equalizer*/ JButton setEqValue = new JButton("Set"); JButton loadEqValue = new JButton("Load"); JButton restore = new JButton("Reset"); JComboBox eqList = new JComboBox(); JPanel p1 = new JPanel(); JPanel GraphEqPanel; String extension = ""; // Create text fields to display slider position String[] labels = {"84", "167", "330", "652", "1.3k", "2.5k", "5k", "10k"}; JLabel[] jlabels; boolean modified = false; public Jslide(MainFrame parent) { myParent = parent; /*Open the file and set sliders to the default*/ //fileName = "eq" + extension + ".dat"; //setAllSliders(fileName); /* Action listener for the restore button. This * restores all slider values to zero. Right now * this has no effect on the file itself. */ js = new JSlider[numSliders]; eqState = new float[numEqualizers][numSliders]; for (int i = 0; i < numSliders; i++) { js[i] = initializeSlider(); for (int j = 0; j < numEqualizers; j++) eqState[j][i] = 0; } setEqValue.addActionListener(this); setEqValue.setActionCommand("set-eq-value"); loadEqValue.addActionListener(this); loadEqValue.setActionCommand("load-eq-value"); restore.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("reset listener"); for (int i = 0; i < numSliders; i++) { js[i].setValue(0); } } } ); /*Create individual Panels to be added to the Pane*/ /* Slider panel*/ p1.setBackground(Color.WHITE); p1.setSize(500,300); p1.setLayout(new GridLayout(1, 8)); /* Panel with all the labels*/ JPanel p2 = new JPanel(); p2.setBackground(Color.WHITE); p2.setLayout(new GridLayout(1, 8)); /* add the sliders and labels */ jlabels = new JLabel[numSliders]; for (int i = 0; i < numSliders; i++) { p1.add(js[i]); jlabels[i] = new JLabel(labels[i]); p2.add(jlabels[i]); } /* Combo box with a liste of numbers of equalizer values*/ String[] eqNums = {"0","1", "2", "3", "4","5","6","7","8","9"}; eqList = new JComboBox(eqNums); eqList.addActionListener(this); eqList.setActionCommand("eq-selection"); /*Panel the buttons, and the combo box on it*/ JPanel pA = new JPanel(); pA.setLayout(new GridLayout(1,4)); pA.setBackground(Color.WHITE); pA.add(setEqValue); pA.add(loadEqValue); pA.add(restore); pA.add(eqList); pA.setSize(50,50); GraphEqPanel = new JPanel(); GraphEqPanel.setLayout(new BorderLayout()); GraphEqPanel.setBackground(Color.WHITE); GraphEqPanel.setSize(300,300); GraphEqPanel.add(p1, BorderLayout.NORTH); GraphEqPanel.add(p2, BorderLayout.CENTER); GraphEqPanel.add(pA, BorderLayout.SOUTH); loadEqValue(); } //Close constructor public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if (command.equals("eq-selection")) { equalizerSelected(); } else if (command.equals("set-eq-value")) { setEqValue(); } else if (command.equals("load-eq-value")) { loadEqValue(); } } public void equalizerSelected() { String name = (String) eqList.getSelectedItem(); int index = new Integer(name); // load values from state for (int i = 0; i < numSliders; i++) { js[i].setValue((int) eqState[index][i]); } } public void setEqValue() { // store slider values into state String name = (String) eqList.getSelectedItem(); int index = new Integer(name); // store value into state String definition = "(define-eq " + name + " #("; for (int i = 0; i < numSliders; i++) { eqState[index][i] = js[i].getValue(); definition += (" " + eqState[index][i]); } definition += "))\n\n"; myParent.sendInput(definition); } public void loadEqValue() { myParent.callFunction("get-eq-data", ""); } /** * Public function that returns the graphic equalizer panel * @return */ public JPanel getGraphEq() { return GraphEqPanel; } /**The getter for the GUI sliders * @return db value as an int */ private int get_db_val(JSlider j){ return j.getValue(); } /** * A Private method that will initialize the sliders. This is * to clean up the code and make it shorter. * @param j */ private JSlider initializeSlider() { JSlider j = new JSlider(JSlider.VERTICAL, -15,15,0); j.setMajorTickSpacing(10); j.setMinorTickSpacing(2); j.setPaintTicks(true); j.setPaintLabels(true); j.setForeground(Color.BLACK); j.setBorder(BorderFactory.createEtchedBorder()); return j; } public void loadEqData(String data) { System.out.println("loadEqData " + data); while (true) { int i = data.indexOf("\n"); if (i < 0) { equalizerSelected(); // load sliders from eqState return; } String line = data.substring(0, i); System.out.println("loadEqData line " + line); data = data.substring(i + 1); // string has 9 numbers StringTokenizer st = new StringTokenizer(line); String name = st.nextToken(); int index = new Integer(name); for (i = 0; i < numSliders; i++) { eqState[index][i] = new Float(st.nextToken()); } } } } nyquist-3.05/jnyqide/NyquistThread.java0000644000175000000620000004071611511430074017301 0ustar stevestaffpackage jnyqide; import java.io.*; import javax.swing.*; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ public class NyquistThread extends Thread { Process myProcess; InputStream stdout; InputStreamReader isrStdout; BufferedReader brStdout; OutputStream stdin; byte b[]; // JTextPane textIn; JTextArea textOut; Runnable update; String plotFilename; boolean plotNow = false; boolean envelopeNow = false; boolean editNow = false; boolean eqNow = false; boolean preferenceDataSent = false; boolean initialLoad = false; String envData; String eqData; PlotFrame plotFrame; MainFrame mainFrame; // used to find current directory String soundBrowser; // path for sound browser String scoreEditFileName; public NyquistThread() { } /* public void setInputArea( JTextPane in ) { textIn = in; }*/ public String StringFromFile(String filename, String default_string) { try { BufferedReader br = new BufferedReader(new FileReader(filename)); default_string = br.readLine(); br.close(); } catch (Exception e) { // do nothing } return default_string; } public void start(JTextArea out, Runnable u, PlotFrame plot, MainFrame main) { textOut = out; update = u; plotFrame = plot; mainFrame = main; try { // Get the current working directory where we can find lib and runtime // get the "." file present in all directories //java.io.File f = new java.io.File("."); // get the absolute path to the "." file //String cwd2 = f.getAbsolutePath(); // return the absolute path minus the "." //cwd2 = cwd2.substring(0, cwd2.length() - 2); // the code above works, but the following is simpler: // find full path to instruments.txt String cwd = System.getProperty("user.dir"); soundBrowser = cwd.concat("/lib/instruments.txt"); System.out.println("soundBrowser file is " + soundBrowser); // build XLISPPATH environment specification String path = System.getenv("XLISPPATH"); // use getenv if (path == null) { // getenv failed, use a default setting path = cwd + "/lib/;" + cwd + "/runtime/;"; } // if xlisppath file exists, use it instead path = "XLISPPATH=" + StringFromFile("xlisppath", path); // construct SystemRoot for environment from file String systemroot = StringFromFile("systemroot", "SystemRoot=C:/windows"); // See if we can get the USER String user = System.getenv("USER"); if (user == null) user = ""; user = StringFromFile("user", user); // file value overrides all if (user == "") user = "IGNORE="; // default value else user = "USER=" + user; // Construct the environment for nyquist subprocess System.out.println(path); System.out.println(user); // make environment from 3 strings String[] envp = {path, user, systemroot}; System.out.println("envp has " + systemroot); try { myProcess = Runtime.getRuntime().exec( "./ny", envp ); } catch (Exception e3) { System.out.println("no ./ny found, trying ./nyquist"); try { myProcess = Runtime.getRuntime().exec("./nyquist", envp); } catch (Exception e4) { System.out.println("no ./nyquist found, trying ny"); // try using PATH to find ny (for linux systems where // ny is installed) myProcess = Runtime.getRuntime().exec("ny", envp); // if this one fails, we'll take the exception below } } System.out.print("myProcess: " + myProcess); stdout = myProcess.getInputStream(); isrStdout = new InputStreamReader(stdout); brStdout = new BufferedReader(isrStdout); stdin = myProcess.getOutputStream(); stdin.write(6); // control-f turns off console echo for Mac and Linux stdin.flush(); } catch( Exception e2 ) { System.out.println(e2); } b = new byte[1000]; if (brStdout != null) { super.start(); } else { textOut.append("Nyquist (ny or nyquist) not found or could not be started."); } } public void run() { final int max_buf_len = 256; StringBuffer buffer = new StringBuffer(max_buf_len); int buffer_index = 0; boolean nyquist_is_running = true; // this is tricky -- we want to accumulate lines to test // for plot commands, but we want to append chars to // textOut even if there is no end-of-line. // // We're going to flush the buffer after every line. // That will be expensive if lines are very short, but // that's pretty rare. So we'll loop until we either // accumulate a line or there are no characters ready. // To avoid re-appending characters to textOut, use // buffer_index to remember how many characters were // output from the current line. // // Algorithm: // accumulate chars while input is ready and newline not found // if we have a newline, test for plot command // append characters to text box // if we have a newline, reset the buffer String line = null; //String debug_strings[] = new String[100]; //int debug_strings_x = 0; while (nyquist_is_running) { try { // initialLoad is true when we see text that indicates // Nyquist has just started. But we want to wait for the // first prompt. We do this by delaying this process a bit // hoping that Nyquist will finish output and issue the // prompt. Then we process the input until we are about to // block, meaning that (maybe) Nyquist has finished output // and is waiting at the prompt. if (initialLoad && !brStdout.ready()) { mainFrame.sendPreferenceData(); initialLoad = false; } // block until you read at least one character int ic = brStdout.read(); //System.out.println("got char"); if (ic != -1) buffer.append((char) ic); // read many characters to avoid the overhead of single // character output. On the other hand, it's expensive // to build huge buffers if Nyquist outputs a giant // list, so limit the buffer length to max_buf_len. while (brStdout.ready() && ic != '\n' && ic != -1 && buffer.length() < max_buf_len) { //System.out.println("block on char in while"); ic = brStdout.read(); //System.out.println("got it"); if (ic != -1) buffer.append((char) ic); } if ((char) ic == '\n') { line = new String(buffer); testForPlot(line); } else if (buffer.length() >= max_buf_len) { // pretend we found a line in order to flush // characters building up in buffer line = " "; } else if (ic == -1) { buffer.append("The Nyquist process has terminated. Please save your files and exit.\n"); nyquist_is_running = false; } textOut.append(buffer.substring(buffer_index)); buffer_index = buffer.length(); if (line != null) { // end of line, reset the buffer line = null; buffer.setLength(0); buffer_index = 0; // limit number of lines and characters in the textOut box int lines = textOut.getLineCount(); if (lines > 5000 || textOut.getLineEndOffset(lines - 1) > 50000) { // take out about 100 lines at a time: textOut.replaceRange("", 0, textOut.getLineStartOffset( Math.max(1, lines - 4900))); } } // cause the scroll to go to the end of the new text SwingUtilities.invokeLater(update); } catch (Throwable t) { t.printStackTrace(); } } } private NyquistFile findFile(String filename) { JInternalFrame[] frames = mainFrame.jDesktop.getAllFrames(); int i; for (i = 0; i < frames.length; i++) { if (frames[i] instanceof NyquistFile) { NyquistFile nyquistFile = (NyquistFile) frames[i]; System.out.println("findFile search: " + nyquistFile.file.getName() + " file " + nyquistFile.file + " getAbsolutePath " + nyquistFile.file.getAbsolutePath()); if (nyquistFile.file.getAbsolutePath().equals(filename)) return nyquistFile; } } return null; } // testForPlot looks for Nyquist output that the jNyqIDE wants to know // about -- originally just plot command output, but now there are many // Lisp functions that communicate and synchronize with the jNyqIDE public void testForPlot(String output) { int iNameStart; int iNameStop; //System.out.print("plot's text output:"); //System.out.println(output); if (!plotNow) { iNameStart = output.indexOf("s-plot: writing "); if (iNameStart >= 0) { iNameStop = output.indexOf(" ..."); plotFilename = output.substring(iNameStart + 16, iNameStop); // Nyquist file should be absolute or current directories // should be synchronized. Appending the current directory // causes problems when Nyquist already prints a full path //if (!mainFrame.currentDir.equals("")) { // plotFilename = mainFrame.currentDir + plotFilename; //} System.out.println("file:" + plotFilename + ":"); plotNow = true; } } // this is not ...else if... because output can have many lines if (plotNow) { iNameStart = output.indexOf(" points from"); // now, the file is written and closed so we can open it if (iNameStart >= 0) { System.out.println("Calling NyqPlot.plot"); NyqPlot.plot(plotFilename, plotFrame); plotNow = false; } } // test for loading workspace and saving workspace if (output.indexOf("workspace loaded") >= 0) { mainFrame.workspaceLoaded = true; } else if (output.indexOf("workspace saved") >= 0) { mainFrame.workspaceSaved = true; } else if (!envelopeNow) { // test for envelope data int index = output.indexOf("get-env-data: begin"); if (index >= 0) { output = output.substring(index); envData = ""; envelopeNow = true; } } if (envelopeNow) { envData += output; int index = envData.indexOf("get-env-data: end"); // remove first line if (index >= 0) { int begin = envData.indexOf("\n"); envData = envData.substring(begin + 1, index); mainFrame.loadEnvData(envData); envelopeNow = false; } } if (!eqNow) { int index = output.indexOf("get-eq-data: begin"); if (index >= 0) { output = output.substring(index); eqData = ""; eqNow = true; } } if (eqNow) { eqData += output; int index = eqData.indexOf("get-eq-data: end"); // remove first line if (index >= 0) { int begin = eqData.indexOf("\n"); eqData = eqData.substring(begin + 1, index); mainFrame.loadEqData(eqData); eqNow = false; } } if (!editNow) { iNameStart = output.indexOf("score-edit: writing "); if (iNameStart >= 0) { iNameStop = output.indexOf(" ..."); scoreEditFileName = output.substring(iNameStart + 20, iNameStop); if (!mainFrame.currentDir.equals("")) { scoreEditFileName = mainFrame.currentDir + scoreEditFileName; } System.out.println("file:" + scoreEditFileName + ":"); editNow = true; } } if (editNow) { iNameStart = output.indexOf("score-edit: wrote "); if (iNameStart >= 0) { Piano_Roll.scoreEdit(scoreEditFileName); editNow = false; } } if (!preferenceDataSent) { iNameStart = output.indexOf("by Roger B. Dannenberg"); if (iNameStart >= 0) { try { Thread.sleep(200); } catch (InterruptedException ie) { } initialLoad = true; preferenceDataSent = true; } } // System.out.println("OUTPUT FOR PROMPT SEARCH: " + output); // determine command input mode from prompt by Nyquist: int promptLoc = output.indexOf("> "); if (output.indexOf("Entering SAL mode ...") >= 0) { mainFrame.setSalMode(true); } else if (output.indexOf("Returning to Lisp ...") >= 0) { mainFrame.setSalMode(false); } else if (output.indexOf("[ back to top level ]") >= 0) { mainFrame.setSalMode(false); } else if (output.indexOf("if continued: return from BREAK") >= 0) { mainFrame.setSalMode(false); } else if (promptLoc == 2 && output.indexOf(">>> in ") == 0) { System.out.println("... detected >>> in (error line location) "); int lineLoc = output.indexOf(", line "); int colLoc = output.indexOf(", col "); if (lineLoc > 0 && colLoc > 0) { String filename = output.substring(7, lineLoc); String lineString = output.substring(lineLoc + 7, colLoc); String colString = output.substring(colLoc + 6, output.length() - 2); NyquistFile nf = findFile(filename); System.out.println("nf.setCursor line " + lineString + " col " + colString + " file " + filename + " nf " + nf); if (isDigits(lineString) && isDigits(colString) && nf != null) { nf.setCursor(Integer.parseInt(lineString), Integer.parseInt(colString)); } } } else if (promptLoc >= 0) { if (output.indexOf("SAL> ") == 0) { mainFrame.setSalMode(true); // System.out.println("in SAL mode"); } else if (isDigits(output.substring(0, promptLoc))) { mainFrame.setSalMode(false); // System.out.println("in LISP mode"); } } } private boolean isDigits(String s) { // returns true if all chars in s are digits for (int i = 0; i < s.length(); i++) if (!Character.isDigit(s.charAt(i))) return false; return true; } public OutputStream getStdin() { return stdin; } public void sendInput(String s) { sendInput(s, false); } public void sendInput(String s, boolean hide) { try { //System.out.println("Sending:" + hide + ": " + s); if (!hide) textOut.append(s); stdin.write( s.getBytes() ); stdin.flush(); } catch (Exception e) { System.out.println(e); } } } nyquist-3.05/jnyqide/keywords.txt0000644000175000000620000001043411466723256016254 0ustar stevestaffabs abs-env address-of and alloc alpass allpass2 amosc append apply aref areson arrayp assoc at atom at-abs atone autonorm-off autonorm-on backquote baktrace bandpass2 biquad biquad-m block both-case-p boundp break build-harmonic buzz car catch cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr case cerror char code-char char-code char-upcase char-downcase char-int char< char<= char= char/= char> char-lessp char-not-greaterp char-equalp char-not-equalp char-not-lessp char-greaterp characterp clean-up clip close comb cond const cons consp congen const continue continuous-control-warp continuous-sound-warp control control-srate-abs control-warp convolve cos cue cue-file db-to-linear defmacro defun delete delete-if delete-if-not diff digit-char digit-char-p display do do* dolist dotimes do dribble endp env errset eq eq-band eq-highshelf eq-lowshelf eql equal error eval evalhook evenp exit exp expand expt exp-dec extract extract-abs fboundp feedback-delay first flatc flatsize flet float floatp fmosc fmlfo force-srate format fourth funcall function gc gcd gensym get get-duration get-lambda-expression get-loud get-output-stream-list get-sustain get-transpose get-warp go hash highpass2 highpass4 highpass6 highpass8 hp hz-to-step hzosc if int-char integerp integrate intern labels lambda last length let let* lfo linear-to-db list listp load local-to-global log logand logior lognot logxor loop loud loud-abs lower-case-p lowpass2 lowpass4 lowpass6 lowpass8 lp macroexpand macroexpand-1 macrolet maketable make-array make-string-input-stream make-string-output-stream make-symbol mapc mapcar mapl maplist max member min minusp mult nconc noise not notch2 nstring-upcase nstring-downcase nth nthcdr null numberp objectp oddp open open-binary or osc osc-note osc-pulse osc-saw osc-tri pan partial peak peek peek-char play play-file pluck plusp poke print prin1 princ pprint prod profile prog prog* progv progl prog2 progn psetq push putprop pwe pwe-list pwer pwer-list pwev pwev-list pwevr pwevr-list pwl pwl-list pwlr pwlr-list pwlv pwlv-list pwlvr pwlvr-list quantize quote ramp random read read-byte read-char read-int read-float read-line recip return return-from rplaca rplacd ref resample reson rest rem remove remove-if remove-if-not remprop restore reverse rms room s-abs s-add-to s-exp s-log s-max s-min s-overwrite s-plot s-print-tree s-read s-rest s-save s-sqrt sampler save scale scale-db scale-srate second send seq seq-create seq-get seq-next seq-reset seqrep set set-control-srate set-logical-stop set-pitch-names set-sound-srate setdir setf setq setup-console sf-info shape shift-time sim simrep sin sine siosc slope snd-abs snd-add snd-alpass snd-alpasscv snd-alpassvv snd-amosc snd-areson snd-aresoncv snd-aresonvc snd-aresonvv snd-atone snd-atonev snd-avg snd-biquad snd-buzz snd-chase snd-clip snd-compose snd-congen snd-const snd-convolve snd-copy snd-coterm snd-delay snd-delaycv snd-down snd-exp snd-extent snd-fetch snd-fetch-array snd-fft snd-flatten snd-fmosc snd-follow snd-from-array snd-fromarraystream snd-fromobject snd-gate snd-ifft snd-inverse snd-length snd-log snd-max snd-maxv snd-maxsamp snd-multiseq snd-normalize snd-osc snd-overwrite snd-partial snd-play snd-pluck snd-print snd-print-tree snd-prod snd-pwl snd-quantize snd-read snd-recip snd-resample snd-resamplev snd-reson snd-resoncv snd-resonvc snd-resonvv snd-samples snd-save snd-scale snd-seq snd-set-logical-stop snd-shape snd-sine snd-siosc snd-sqrt snd-srate snd-sref snd-stop-time snd-tapv snd-time snd-tone snd-tonev snd-t0 snd-up snd-white snd-xform snd-zero sort sound sound-off sound-on sound-srate-abs sound-warp sound-srate-abs soundfilename soundp sublis subst sum sqrt sref sref-inverse stats step-to-hz streamp strcat stretch stretch-abs string string-search string-trim string-left-trim string-lessp string-not-greaterp string-equalp string-not-equalp string-not-lessp string-greaterp string-right-trim string-upcase string-downcase stringp string< string<= string/= string>= string> subseq sustain sustain-abs synbol-function symbol-name symbol-plist symbol-value symbolp system tagbody tan terpri third throw timed-seq type-of tone top-level trace transpose transpose-abs truncate unless untrace unwind-protect upper-case-p vector warp warp-abs when while write-byte write-char write-int write-float zerop 1+ 1- / + - * = < > <= >= /= nyquist-3.05/jnyqide/NotFoundDialog.java0000644000175000000620000000466411466723256017373 0ustar stevestaff/* * Copyright (c) 1997 John Jensen. All rights reserved. * * This software is FREE FOR COMMERCIAL AND NON-COMMERCIAL USE, * provided the following condition is met. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that any copy or derivative of this software or documentation * retaining the name "John Jensen" also retains this condition and the * following disclaimer. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * CopyrightVersion 1.0 */ package jnyqide; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; class NotFoundDialog extends Dialog implements WindowListener, ActionListener { private Button okButton; public NotFoundDialog(MainFrame mainFrame, Properties strings, Point loc) { super(mainFrame, "", true); Panel north = new Panel(); north.add(new Label("Not Found")); add("North", north); okButton = new Button("Ok"); okButton.addActionListener(this); Panel south = new Panel(); south.add(okButton); add("South", south); Dimension size = new Dimension(200,110); setSize(size); setLocation(loc); // setLocation(textFrame.getPlace(size)); addWindowListener(this); } public void windowDeiconified(WindowEvent event) {} public void windowIconified(WindowEvent event) {} public void windowActivated(WindowEvent event) {} public void windowDeactivated(WindowEvent event) {} public void windowOpened(WindowEvent event) {} public void windowClosed(WindowEvent event) {} public void windowClosing(WindowEvent event) { dispose(); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() == okButton) dispose(); } } nyquist-3.05/jnyqide/EnvelopeFrame.java0000644000175000000620000014334411466723256017246 0ustar stevestaff// Code: Chris Yealy, 5/2/06 // Edited: Derek D'Souza 5/3/07 // Edited: Roger Dannenberg 23Jul07 // eq editor needs to do same with workspace /* Saving and Restoring: * the Save button saves one envelope locally, to Nyquist, and saves the * updated workspace * the Load button loads all envelopes from Nyquist for editing. If no * envelopes are loaded, suggests (load "workspace") * selecting an envelope from the list saves the current envelope * (locally, to Nyquist, and to the workspace) and switches the editor * to the selected envelope * delete button removes the envelope from the workspace after a confirm */ /* Graphics organization: myParent -- the MainFrame EnvelopeFrame -- this editor, a JInternalFrame mainPanel -- a JPanel topPanel -- a JPanel envNamePanel -- a JPanel, border "Current Envelope" currEnvNameLabel -- a JLabel("Name:") currEnvName -- a JTextField("ENVELOPE", 20) saveEnv -- a JButtton("Save") envTypeLabel - a JTextField("Type", ...) envTypes - a JComboBox envListPanel -- a JPanel, border "Saved Envelopes List" envName -- a JComboBox loadEnv -- a JButton("load") deleteEnv -- a JButton("delete") envPointsPanel - a JPanel, border Envelope Points envTimesLabel - a JLabel("Time:") envTimes - JComboBox envAmplitudesLabel - a JLabel("Amplitudes:") envAmplitudes - JTextField addPoint - a JButton("Add Point") deletePoint - a JButton("Delete Point") updatePoint - a JButton("Update Point") paramPanel -- a JPanel rangePanel - a JPanel, border "Range Parameters" maxTL - a JLabel("Stop Time") maxT - a JTextField minAL - a JLabel("Min. Amplitude") maxAL - a JLabel("Max. Amplitude") minA - a JTextField maxA - a JTextField update - JButton("Update Range" envEditPanel -- a JPanel, border "Graphic Envelope Editor" envEditButtonPanel - a JPanel undo - a JButton("Undo") redo - a JButton("Redo") clear - a JButton("Clear") dispCoord - a JButton("Coordinates") output - a JButton("Output Envelope") canvas - a PiecewiseCanvas (a JPanel) to drag point: on mouse pressed, set selection to index of point on mouse drag, delete selection and insert new point if endpoints are specified, e.g. if times[0] is 0 or last value in times matches the ending time, then use PWLV or PWEV version Be careful not to drop first/last point unless the time matches the begin/end time. */ package jnyqide; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.awt.image.BufferedImage; import java.util.Vector; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Enumeration; import java.io.File; import java.lang.Math.*; import java.text.DecimalFormat; import jnyqide.*; public class EnvelopeFrame extends JInternalFrame implements ActionListener { double EPSILON = 0.00000001; // small number -- allow for rounding error int LEFT_BORDER = 3; // inset everything by 3 pixels int TOP_BORDER = 3; int BOTTOM_BORDER = 5; int RIGHT_BORDER = 5; MainFrame myParent; //JComponents for envelope window private JComboBox envTypes; private JPanel mainPanel; private JTextPane jInputArea; //private JPanel canvasPanel; private PiecewiseCanvas canvas; private JTextField envAmplitudes; // private JTextField minT; private JTextField maxT; private JTextField minA; private JTextField maxA; private JTextField currEnvName; private JComboBox envName; private JComboBox envTimes; private JButton dispCoord; private String currentEnvName; public String[] types = {"Piecewise Linear", "Piecewise Exponential"}; public int PWL_TYPE = 0; public int PWE_TYPE = 1; // when saving envelopes, we copy current envelope to the collection, // but this makes the combobox think that an envelope was selected, // and we get a request to save the same envelope were saving. To // avoid this, the "saving" flag is used to disable the check. private boolean saving = false; //hashtable for storing envelopes private Hashtable envColl; static double initTime=0.0; static double finalTime=1.0; static boolean displayCoord = false; static boolean valueType=false; static DecimalFormat form = new DecimalFormat("#.###"); private boolean modified; // tells when any aspect of envelope // has changed // envelope is modified by: entering a point, deleting a point, changing // the end-time (update), or clearing // modified is reset when envelope is loaded or saved // Constructor public EnvelopeFrame(final MainFrame parent, JTextPane inputArea) { super(); setTitle("Untitled"); myParent = parent; jInputArea = inputArea; //canvasPanel = new JPanel(); //canvasPanel.setPreferredSize(new Dimension(575, 256)); mainPanel = (JPanel) getContentPane(); envColl = new Hashtable(); setTitle("Piecewise Envelope Generator"); setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); final EnvelopeFrame envelopeFrame = this; modified = false; addInternalFrameListener( new InternalFrameListener() { public void internalFrameClosing(InternalFrameEvent e) { //System.out.println("FrameClosing"); int r = JOptionPane.OK_OPTION; if (envelopeFrame.modified) { r = JOptionPane.showConfirmDialog(envelopeFrame, "Really close without saving?", "Alert", JOptionPane.OK_CANCEL_OPTION); } if (r == JOptionPane.OK_OPTION) { envelopeFrame.dispose(); } } public void internalFrameOpened(InternalFrameEvent e) { } public void internalFrameClosed(InternalFrameEvent e) { parent.disconnectEnv(); //System.out.println("FrameClosed"); } public void internalFrameIconified(InternalFrameEvent e) { } public void internalFrameDeiconified(InternalFrameEvent e) { } public void internalFrameActivated(InternalFrameEvent e) { } public void internalFrameDeactivated(InternalFrameEvent e) { } } ); System.out.println("EnvelopeFrame constructor 1"); JLabel currEnvNameLabel = new JLabel("Name: "); currEnvName = new JTextField("envelope", 10); currentEnvName = "envelope"; JButton saveEnv = new JButton("Save"); saveEnv.addActionListener(this); saveEnv.setActionCommand("saveEnvelopes"); JLabel currEnvTypeLabel = new JLabel("Type: "); envTypes = new JComboBox(types); envTypes.addActionListener(this); envTypes.setActionCommand("envTypeChanged"); // components for envelope list panel envName = new JComboBox(); envName.setEditable(false); envName.addActionListener(this); envName.setActionCommand("envNameSelected"); JButton loadEnv = new JButton("Load"); loadEnv.addActionListener(this); loadEnv.setActionCommand("loadEnvelope"); JButton deleteEnv = new JButton("Delete"); deleteEnv.addActionListener(this); deleteEnv.setActionCommand("deleteEnvelope"); JPanel envNamePanel = new JPanel(); envNamePanel.setBorder(BorderFactory.createTitledBorder("Current Envelope")); GridBagLayout layout0 = new GridBagLayout(); envNamePanel.setLayout(layout0); GridBagConstraints cons0 = new GridBagConstraints(); cons0.fill = GridBagConstraints.NONE; cons0.anchor = GridBagConstraints.EAST; cons0.weightx = 0; cons0.weighty = 0; cons0.gridx = 0; cons0.gridy = 0; cons0.gridheight = 1; cons0.gridwidth = 1; envNamePanel.add(currEnvNameLabel, cons0); cons0.anchor = GridBagConstraints.WEST; cons0.gridx = 1; envNamePanel.add(currEnvName, cons0); cons0.anchor = GridBagConstraints.CENTER; cons0.gridx = 2; envNamePanel.add(saveEnv, cons0); cons0.anchor = GridBagConstraints.EAST; cons0.gridx = 0; cons0.gridy = 1; envNamePanel.add(currEnvTypeLabel, cons0); cons0.anchor = GridBagConstraints.WEST; cons0.gridx = 1; cons0.gridwidth = 2; envNamePanel.add(envTypes, cons0); JPanel envListPanel = new JPanel(); envListPanel.setBorder(BorderFactory.createTitledBorder("Saved Envelopes List")); envListPanel.add(envName); envListPanel.add(loadEnv); envListPanel.add(deleteEnv); envTimes = new JComboBox(); envTimes.setEditable(true); envTimes.addActionListener(this); envTimes.setActionCommand("envTimeChange"); envTimes.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { System.out.println("itemStateChanged " + e); } }); JLabel envTimesLabel = new JLabel("Time: "); envAmplitudes = new JTextField(6); JLabel envAmplitudesLabel = new JLabel("Ampl: "); envTimes.setPreferredSize(envAmplitudes.getPreferredSize()); JButton addPoint = new JButton("Add Point"); addPoint.addActionListener(this); addPoint.setActionCommand("addPoint"); JButton deletePoint = new JButton("Delete Point"); deletePoint.addActionListener(this); deletePoint.setActionCommand("deletePoint"); JButton updatePoint = new JButton("Update Point"); updatePoint.addActionListener(this); updatePoint.setActionCommand("updatePoint"); GridBagLayout layout1 = new GridBagLayout(); JPanel envPointsPanel = new JPanel(); envPointsPanel.setBorder(BorderFactory.createTitledBorder("Envelope Points")); envPointsPanel.setLayout(layout1); GridBagConstraints cons = new GridBagConstraints(); cons.fill = GridBagConstraints.NONE; cons.anchor = GridBagConstraints.EAST; cons.weightx = 0; cons.weighty = 0; cons.gridx = 0; cons.gridy = 0; cons.gridheight = 1; cons.gridwidth = 1; envPointsPanel.add(envTimesLabel, cons); cons.anchor = GridBagConstraints.WEST; cons.gridx = 1; envPointsPanel.add(envTimes, cons); cons.anchor = GridBagConstraints.EAST; cons.gridx = 0; cons.gridy = 1; envPointsPanel.add(envAmplitudesLabel, cons); cons.anchor = GridBagConstraints.WEST; cons.gridx = 1; envPointsPanel.add(envAmplitudes, cons); cons.anchor = GridBagConstraints.CENTER; cons.gridx = 2; cons.gridy = 0; envPointsPanel.add(addPoint, cons); cons.gridy = 1; envPointsPanel.add(deletePoint, cons); cons.gridy = 2; envPointsPanel.add(updatePoint, cons); // panel to contain time and amplitude parameters JPanel rangePanel = new JPanel(); JPanel paramPanel = new JPanel(); paramPanel.setBorder(BorderFactory.createTitledBorder("Range")); rangePanel.setLayout(new GridBagLayout()); paramPanel.setLayout(layout1); // components for parameter panel ActionListener stateChange = new ActionListener() { public void actionPerformed(ActionEvent e) { canvas.history.save(canvas); } }; maxT = new JTextField("1.0", 5); minA = new JTextField("0.0", 5); maxA = new JTextField("1.0", 5); JLabel maxTL = new JLabel("Stop: "); JLabel minAL = new JLabel("Min: "); JLabel maxAL = new JLabel("Max: "); cons.gridx = 2; cons.gridy = 0; rangePanel.add(maxTL, cons); cons.gridx = 3; cons.gridy = 0; rangePanel.add(maxT, cons); cons.gridx = 0; cons.gridy = 1; rangePanel.add(minAL, cons); cons.gridx = 2; rangePanel.add(maxAL, cons); cons.gridx = 1; rangePanel.add(minA, cons); cons.gridx = 3; rangePanel.add(maxA, cons); JButton update = new JButton("Update Range"); update.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (getMaxT() <= 0) { JOptionPane.showMessageDialog(mainPanel, "Stop Time cannot be negative or zero"); } else if (getMinA() > getMaxA()) { JOptionPane.showMessageDialog(mainPanel, "Minimum Amplitude cannot be greater than Maximum Amplitude"); } else if ((canvas.times.size() > 0) && (getMaxT() < canvas.times.lastElement())) { JOptionPane.showMessageDialog(mainPanel, "Stop Time is less than the time of an existing envelope point"); } else { modified = true; canvas.history.save(canvas); canvas.repaint(); return; } // an error occurred, reset the Range (using complete restore) canvas.restore(); } }); //insert components into the larger panels cons.fill = GridBagConstraints.NONE; cons.anchor = GridBagConstraints.WEST; cons.weightx = 0; cons.weighty = 0; cons.gridx = 0; cons.gridy = 0; cons.gridheight = 1; cons.gridwidth = 1; //cons.insets = new Insets(5,0,0,5); paramPanel.add(rangePanel, cons); cons.fill = GridBagConstraints.NONE; cons.anchor = GridBagConstraints.CENTER; cons.weightx = 0; cons.weighty = 0; cons.gridx = 0; cons.gridy = 1; cons.gridheight = 1; cons.gridwidth = 1; //cons.insets = new Insets(0,0,0,5); paramPanel.add(update, cons); // components for envelope edit panel JButton undo = new JButton("Undo"); undo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { canvas.history.undo(); canvas.restore(); } }); JButton redo = new JButton("Redo"); redo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { canvas.history.redo(); canvas.restore(); } }); JButton clear = new JButton("Clear"); clear.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("calling canvas.clear\n"); canvas.clear(); } }); dispCoord = new JButton("Coordinates"); dispCoord.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { displayCoord = !displayCoord; canvas.repaint(); } }); JButton output = new JButton("Output Envelope"); output.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String outputStr = canvas.getExpression(); jInputArea.setText(jInputArea.getText().concat(outputStr)); } }); JPanel envEditButtonPanel = new JPanel(); envEditButtonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 0)); envEditButtonPanel.add(undo); envEditButtonPanel.add(redo); envEditButtonPanel.add(clear); envEditButtonPanel.add(dispCoord); envEditButtonPanel.add(output); JPanel topPanel = new JPanel(); //topPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 0)); topPanel.setLayout(new GridBagLayout()); cons.anchor = GridBagConstraints.NORTHWEST; cons.gridx = 0; cons.gridy = 0; topPanel.add(envNamePanel, cons); cons.gridx = 1; topPanel.add(envListPanel, cons); cons.gridx = 0; cons.gridy = 1; topPanel.add(envPointsPanel, cons); cons.gridx = 1; topPanel.add(paramPanel, cons); JPanel envEditPanel = new JPanel(); envEditPanel.setBorder(BorderFactory.createTitledBorder( "Graphical Envelope Editor")); //envEditPanel.setLayout(new BoxLayout(envEditPanel, BoxLayout.Y_AXIS)); envEditPanel.setLayout(new BorderLayout()); envEditPanel.add(BorderLayout.NORTH, envEditButtonPanel); canvas = new PiecewiseCanvas(); //canvasPanel.add(canvas); //canvasPanel.setBorder(BorderFactory.createEtchedBorder()); envEditPanel.add(BorderLayout.CENTER, canvas); //insert panels into main frame and display //mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); //mainPanel.setBorder(BorderFactory.createEmptyBorder()); //canvasPanel.add(canvas); mainPanel.add(BorderLayout.NORTH, topPanel); mainPanel.add(BorderLayout.CENTER, envEditPanel); pack(); //resize and center the window Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setLocation(100, 100); setSize(650, 580); // setBackground(Color.white); setResizable(true); setVisible(true); setClosable(true); setMaximizable(true); setIconifiable(true); System.out.println("EnvelopeFrame constructor 2 after setIcnifiable"); // synchronize env data by loading data from Nyquist process loadEnvelopes(); repaint(); // canvas.repaint(); } public void envNameSelected() { if (saving) return; // ignore selection generated by "save" button // If the name is different from the current envelope name, do // a "save". Then switch to editing the newly selected envelope. String name = (String) envName.getSelectedItem(); // when we load the JComboBox with new names, the contentsChanged // method of JComboBox invokes a selection action, even if nothing // is selected. I don't know why, but we have to handle the null // selection case. if (name == null) return; String originalName = currentEnvName; currentEnvName = currEnvName.getText().trim(); if (!originalName.equals(currentEnvName)) { modified = true; } if (modified) { Object[] options = { "OK", "CANCEL" }; int i = JOptionPane.showOptionDialog(mainPanel, currentEnvName + " is being edited. Save it?", "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); if (i == JOptionPane.OK_OPTION) { saveEnvelopes(); } } // store envelope under old name String edited = canvas.getExpression(); System.out.println("expression existed, putting " + currentEnvName + " " + edited + ", changing currentEnvName to " + name); if (currentEnvName.length() > 0) envColl.put(currentEnvName, edited); // install name as new envelope to edit String expression = envColl.get(name); canvas.setEnv(expression); currEnvName.setText(name); // make name be the selected name envName.setSelectedItem(name); // } currentEnvName = name; } //public double getMinT() { return Double.parseDouble(minT.getText().trim()); } public double getMaxT() { return Double.parseDouble(maxT.getText().trim()); } public double getMinA() { return Double.parseDouble(minA.getText().trim()); } public double getMaxA() { return Double.parseDouble(maxA.getText().trim()); } public int getEnvType() { if (envTypes != null) { String env = (String) envTypes.getSelectedItem(); if (env.matches(types[PWL_TYPE])) return PWL_TYPE; return PWE_TYPE; } else /* initializing */ return PWL_TYPE; } public boolean within(double x, double y, double eps) { return Math.abs(x - y) < eps; } // write current envelope definition to Nyquist public void saveEnvelopes() { // make sure current envelope has been stored in collection if (currEnvName.getText().length() == 0) { JOptionPane.showMessageDialog(mainPanel, "Please Enter an Envelope Name"); return; } currentEnvName = currEnvName.getText().trim(); // now write all to Nyquist saving = true; boolean foundIt = false; for (Enumeration keys = envColl.keys(); keys.hasMoreElements(); ) { String name = (String) keys.nextElement(); // update envelope collection with current envelope if (name.equals(currentEnvName)) { envColl.remove(name); //envName.removeItem(name); envColl.put(currentEnvName, canvas.getExpression()); //envName.addItem(currentEnvName); foundIt = true; } String expression = envColl.get(name); String defn = "(define-env '" + name + " '" + expression + ")"; System.out.print("in saveEnvelopes: " + defn); myParent.sendInputLn(defn); // send to Nyquist for evaluation } // if the current envelope was not in the list, add it and save it if (!foundIt) { String expr = canvas.getExpression(); envColl.put(currentEnvName, expr); envName.addItem(currentEnvName); String defn = "(define-env '" + currentEnvName + " '" + expr + ")"; System.out.print("in saveEnvelopes: " + defn); myParent.sendInputLn(defn); // send to Nyquist for evaluation } envName.setSelectedItem(currentEnvName); modified = false; saving = false; System.out.println("modified false in saveEnvelopes\n"); } public void loadEnvelopes() { myParent.callFunction("get-env-data", ""); } public void deleteEnvelope() { Object[] options = { "OK", "CANCEL" }; int i = JOptionPane.showOptionDialog(mainPanel, "Deletion cannot be undone, click OK to continue", "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); if (i != JOptionPane.OK_OPTION) return; // it appears as though currentEnvName gets changed when you remove // it from the envName comboBox, so make a local copy. Previously, // we were calling DELETE-ENV after the name changed! String name = currentEnvName; // delete the envelope from hashtable envColl.remove(name); // delete the envelope from the combobox envName.removeItem(name); // delete the envelope from the workspace myParent.sendInputLn( "(delete-env '" + name + ")"); } public void actionPerformed(ActionEvent e) { //System.out.println(e.getActionCommand()); String actionCommand = e.getActionCommand(); // File Menu options if (actionCommand.equals("saveEnvelopes")) { saveEnvelopes(); } else if (actionCommand.equals("loadEnvelope")) { loadEnvelopes(); } else if (actionCommand.equals("deleteEnvelope")) { deleteEnvelope(); } else if (actionCommand.equals("envNameSelected")) { envNameSelected(); } else if (actionCommand.equals("envTypeChanged")) { int type = getEnvType(); if (type != canvas.type) { canvas.type = type; canvas.history.save(canvas); canvas.repaint(); } //set initial amplitude and time parameters if (canvas.times.size() < 1) { if (type == PWE_TYPE) { minA.setText("1.0"); maxA.setText("2.0"); } else { minA.setText("0.0"); maxA.setText("1.0"); } } canvas.repaint(); validate(); setVisible(true); } else if (actionCommand.equals("deletePoint")) { int index = envTimes.getSelectedIndex(); System.out.println("at deletePoint, index " + index); if (index >= 0) { canvas.selection = index; System.out.println("at deletePoint before deleteSelection"); canvas.deleteSelection(); index = envTimes.getSelectedIndex(); System.out.println("deletePoint new index " + index); if (index >= 0) { canvas.selection = index; envAmplitudes.setText(form.format(canvas.amps.get(index))); } canvas.repaint(); } } else if (actionCommand.equals("addPoint")) { String text = (String) envTimes.getSelectedItem(); if (text.equals("")) return; double time = Double.parseDouble(text.trim()); text = envAmplitudes.getText(); double amp = Double.parseDouble(text.trim()); canvas.insertInOrder(time, amp); canvas.repaint(); } else if (actionCommand.equals("updatePoint")) { String text = (String) envTimes.getSelectedItem(); if (text.equals("")) return; double time = Double.parseDouble(text.trim()); text = envAmplitudes.getText(); double amp = Double.parseDouble(text.trim()); System.out.println("updatePoint selection " + canvas.selection); canvas.deleteSelection(); canvas.insertInOrder(time, amp); canvas.repaint(); } else if (actionCommand.equals("envTimeChange")) { // sometimes this action gets called in the middle of // doing an update and in an inconsistent state. If this // happens, don't try to set amplitude text. if (canvas.amps.size() != envTimes.getItemCount()) return; int index = envTimes.getSelectedIndex(); System.out.println("envTimeChange " + index); if (index >= 0) { canvas.selection = index; envAmplitudes.setText(form.format(canvas.amps.get(index))); canvas.repaint(); // update selection marker } } else { System.out.println("ACTION NOT HANDLED: " + actionCommand); } } public void loadEnvData(String data) { data = data.toLowerCase(); System.out.println("loadEnvData: data |" + data + "| len " + data.length()); envName.removeAllItems(); // clear and reload combo box envTimes.removeAllItems(); // clear times envAmplitudes.setText(""); // clear amplitude box while (data.length() > 0) { int eolx = data.indexOf("\n"); if (eolx < 0) return; // shouldn't happen, but bail if it does String line = data.substring(0, eolx); System.out.println("loadEnvData: line " + line); data = data.substring(eolx + 1); String name = line.substring(0, line.indexOf(' ')); System.out.println("loadEnvData: name " + name); String env = line.substring(name.length() + 1); System.out.println("loadEnvData: env " + env); if (name.length() > 0) envColl.put(name, env); envName.addItem(name); } } private class State { public int type; public double maxT; public double minA; public double maxA; public State(int t, double stop, double low, double hi) { type = t; maxT = stop; minA = low; maxA = hi; } } private class History { /* consider a sequence of undo/redo to be a single edit operation -- thus * the end of the versions list is set to the latest undo/redo selection */ private boolean undoRedo = false; private Vector> t_history = new Vector>(); private Vector> a_history = new Vector>(); private Vector state_history = new Vector(); private int version = -1; public void save(PiecewiseCanvas canvas) { t_history.add((Vector) (canvas.times.clone())); a_history.add((Vector) (canvas.amps.clone())); state_history.add(new State(canvas.type, getMaxT(), getMinA(), getMaxA())); version = t_history.size() - 1; System.out.println("Saved version " + version); undoRedo = false; /* clear flag for next undoRedo sequence */ } public boolean canGet() { boolean result = version >= 0 && version < t_history.size(); System.out.println("canGet returns " + result + " version " + version); return result; } public Vector getTimes() { return t_history.get(version); } public Vector getAmps() { return a_history.get(version); } public State getState() { return state_history.get(version); } private void processUndoRedo() { if (!undoRedo) { /* extend with copy of the version */ t_history.add((Vector) (t_history.get(version).clone())); a_history.add((Vector) (a_history.get(version).clone())); state_history.add(state_history.get(version)); } else { /* replace with different version */ t_history.set(t_history.size() - 1, (Vector) (t_history.get(version).clone())); a_history.set(t_history.size() - 1, (Vector) (a_history.get(version).clone())); state_history.set(state_history.size() - 1, state_history.get(version)); } undoRedo = true; } public void undo() { if (version > 0) { version--; processUndoRedo(); } } public void redo() { if (version < t_history.size() - 1) { version++; processUndoRedo(); } } } // Class for the drawing area //private class PiecewiseCanvas extends Canvas implements MouseListener, private class PiecewiseCanvas extends JPanel implements MouseListener, MouseMotionListener, KeyListener { private int currentAmp; private int currentTime; public BufferedImage image = null; public boolean selectCheck = false; public int selection; public History history; private boolean mouseDown = false; // used to detect version for undo private boolean changed = false; // used to detect version for undo // Vectors to store the absolute parameters of the points in the // envelope. public Vector times = new Vector(); public Vector amps = new Vector(); public int type = PWL_TYPE; /* PWL_TYPE or PWE_TYPE */ // Constructor public PiecewiseCanvas() { setBackground(Color.white); addMouseListener(this); addMouseMotionListener(this); addKeyListener(this); selection = -1; history = new History(); history.save(this); } public boolean isValueType() { if (times.size() == 0) return false; return (times.get(0) == 0 || within(times.lastElement(), getMaxT(), EPSILON)); } public boolean isImpliedFirstPoint() { return (times.size() == 0) || !within(times.get(0), 0, EPSILON); } public boolean isImpliedLastPoint() { return (times.size() == 0) || !within(times.lastElement(), getMaxT(), EPSILON); } // Allow JPanel to accept keyboard events public boolean isFocusable() { return true; } //try to make the canvas the correct size public Dimension getMinimumSize() { return new Dimension(0, 0); } public Dimension getPreferredSize() { return new Dimension(575, 256); } public double impliedAmp() { return (type == PWL_TYPE ? 0.0 : 1.0); } /* public Dimension getMaximumSize() { return getPreferredSize(); }*/ // draw the graphics inside the full canvas, so use these // functions to get the size and coordinates of the drawing // area that is usable private int graphLeft() { return LEFT_BORDER; } private int graphRight() { return getWidth() - RIGHT_BORDER; } private int graphWidth() { return getWidth() - (LEFT_BORDER + RIGHT_BORDER); } private int graphTop() { return TOP_BORDER; } private int graphBottom() { return getHeight() - BOTTOM_BORDER; } private int graphHeight() { return getHeight() - (TOP_BORDER + BOTTOM_BORDER); } private int clipX(int x) { return Math.max(LEFT_BORDER, Math.min(graphRight(), x)); } private int clipY(int y) { return Math.max(BOTTOM_BORDER, Math.min(graphBottom(), y)); } public String getExpression() { boolean valueType = isValueType(); String env; if (type == PWL_TYPE) env = (valueType ? "pwlv" : "pwl"); else env = (valueType ? "pwev" : "pwe"); return outputEnv(env, valueType, 0.0, // getMinT(), getMaxT(), getMinA(), getMaxA()); } //draw the canvas image public void paint(Graphics g) { super.paint(g); // test: g.drawLine(0, 0, 100, 100); Graphics2D drawArea = (Graphics2D) g; canvas.drawCircles(drawArea); canvas.drawSelectionCircle(drawArea); canvas.connectTheDots(drawArea); drawArea.dispose(); } //erase the canvas, then draw all of the points in the envelope private void drawCircles(Graphics2D g) { //erase the previous image //clearCanvas(g); double maxTime = getMaxT(); // is the initial point implicit? if (isImpliedFirstPoint()) { // implied double amp = impliedAmp(); int y = amp2y(amp); // System.out.println("implied: amp " + amp + " y " + y); drawDot(g, graphLeft(), y); if (displayCoord) { g.drawString("(0," + form.format(amp) + ")", graphLeft(), y - 3); } } // is the final point implicit? if (isImpliedLastPoint()) { double amp = impliedAmp(); int y = amp2y(amp); drawDot(g, graphRight(), y); if (displayCoord) { g.drawString("(" + form.format(getMaxT()) + "," + form.format(amp) + ")", graphWidth() - 36, y - 9); } } //draw points for each point in the envelope for (int i = 0; i < times.size(); i++) { int t = time2x(times.get(i)); int a = amp2y(amps.get(i)); if (displayCoord) g.drawString("(" + form.format(times.get(i)) + "," + form.format(amps.get(i)) + ")", t, a); drawDot(g, t, a); //System.out.println("drawDot t " + t + " a " + a + " width " + // getWidth()); } } //given coordinates, draw a circle on the canvas private void drawDot(Graphics2D g, int t, int a) { //draw a black circle at the specified point g.setColor(Color.black); //System.out.println("drawDot: " + t + "," + a); g.fillOval(t - 2, a - 2, 5, 5); } // given coordinates, draw a circle around selected envelope point private void drawSelectionCircle(Graphics2D g) { if (selection >= 0 && selection < times.size()) { int t = time2x(times.get(selection)); int a = amp2y(amps.get(selection)); //draw a red circle around the specified point g.setColor(Color.red); g.drawOval(t - 4, a - 4, 9, 9); } } private void draw_connect(Graphics2D g, double t1, double a1, double t2, double a2) { int x1 = time2x(t1); int x2 = time2x(t2); int y1 = amp2y(a1); int y2 = amp2y(a2); if (type == PWL_TYPE) { g.drawLine(x1, y1, x2, y2); } else { // pwe type, graph is linear along a log scale if (a1 <= EPSILON || a2 <= EPSILON) { g.drawLine(x1, y1, x1, graphBottom()); g.drawLine(x1, graphBottom(), x2, graphBottom()); g.drawLine(x2, graphBottom(), x2, y2); } else { double log1 = Math.log(a1); double log2 = Math.log(a2); int startline = y1; double logIncr = (log2 - log1) / (x2 - x1); for (int j = x1 + 1; j <= x2; j++) { double loga = log1 + logIncr * (j - x1); int a = amp2y(Math.exp(loga)); g.drawLine(j - 1, startline, j, a); startline = a; } } } } //connect adjacent points in the envelope by lines (pwl, pwlv) or by an // exponential curve (pwe, pwev) private void connectTheDots(Graphics2D g) { g.setColor(Color.blue); // System.out.println("connectTheDots\n"); if (times.size() > 0) { if (isImpliedFirstPoint()) { draw_connect(g, 0, impliedAmp(), times.get(0), amps.get(0)); } if (isImpliedLastPoint()) { draw_connect(g, times.lastElement(), amps.lastElement(), getMaxT(), impliedAmp()); } //connect the non-endpoints in the envelope double t1 = times.get(0); double a1 = amps.get(0); for (int i = 0; i < times.size() - 1; i++) { double t2 = times.get(i + 1); double a2 = amps.get(i + 1); draw_connect(g, t1, a1, t2, a2); t1 = t2; a1 = a2; } } else { // size == 0, so both points are implied draw_connect(g, 0, impliedAmp(), getMaxT(), impliedAmp()); } } // erase the canvas and clear the parameter vectors - // completely reset the envelope public void clear() { if (times != null) times.removeAllElements(); if (amps != null) amps.removeAllElements(); envTimes.removeAllItems(); modified = true; repaint(); history.save(this); } public void restore() { if (history.canGet()) { times = (Vector) (history.getTimes().clone()); amps = (Vector) (history.getAmps().clone()); State state = history.getState(); type = state.type; maxT.setText(String.valueOf(state.maxT)); minA.setText(String.valueOf(state.minA)); maxA.setText(String.valueOf(state.maxA)); envTypes.setSelectedItem(types[type]); selection = -1; // put times in combo box envTimes.removeAllItems(); for (int i = 0; i < times.size(); i++) { envTimes.insertItemAt(form.format(times.get(i)), i); } envAmplitudes.setText(""); repaint(); } } //set time and amplitude on click by inserting the point into the vectors. // if delete is checked, try to delete a point from the envelope public void mousePressed(MouseEvent e) { mouseDown = true; System.out.println("mouseDown true\n"); this.requestFocus(); currentTime = e.getX(); currentAmp = e.getY(); selectCheck = checkSelection(currentTime, currentAmp); if (selectCheck) { return; } insertInOrder(x2time(currentTime), y2amp(currentAmp)); repaint(); } public void mouseDragged(MouseEvent e) { currentTime = clipX(e.getX()); currentAmp = clipY(e.getY()); if (currentTime <= graphRight() && currentTime >= graphLeft() && currentAmp >= graphTop() && currentAmp <= graphBottom()) { deleteSelection(); insertInOrder(x2time(currentTime), y2amp(currentAmp)); repaint(); } } public void mouseReleased(MouseEvent e) { System.out.println("mouseReleased\n"); if (changed) { history.save(this); changed = false; } mouseDown = false; System.out.println("mouseDown false\n"); } // convert time coordinate to time in seconds private double x2time(int x) { return (x - graphLeft()) * getMaxT() / graphWidth(); } private int time2x(double time) { int x = (int) Math.round(time * graphWidth() / getMaxT()) + graphLeft(); return x; } // convert amp coordinate to real amplitude private double y2amp(int y) { double maxAmp = getMaxA(); double aRange = maxAmp - getMinA(); double amp = maxAmp - ((y - graphTop()) * aRange / graphHeight()); return amp; } private int amp2y(double amp) { double maxAmp = getMaxA(); double aRange = maxAmp - getMinA(); int y = (int) Math.round((maxAmp - amp) * graphHeight() / aRange) + graphTop(); // System.out.println("amp2y: amp " + amp + " y " + y); return y; } private void deleteSelection() { if (selection < 0 || selection >= times.size()) return; times.remove(selection); amps.remove(selection); modified = true; System.out.println("deleteSelection at " + selection); envTimes.removeItemAt(selection); // make the Amp: box correspond to the new selection: String amp = ""; if (times.size() > 0) { int index = envTimes.getSelectedIndex(); if (index >= 0) amp = form.format(amps.get(index)); } envAmplitudes.setText(amp); selection = -1; if (!mouseDown) history.save(this); } private void addPoint(int i, double absT, double absA) { System.out.println("addPoint: " + i + " " + absT + " " + absA); times.add(i, absT); amps.add(i, absA); envTimes.insertItemAt(form.format(absT), i); System.out.println("addPoint time: " + absT + ", text " + form.format(absT)); envTimes.setSelectedIndex(i); envAmplitudes.setText(form.format(amps.get(i))); selection = i; changed = true; if (!mouseDown) history.save(this); } //insert the time and amplitude in the vectors in time sorted order private void insertInOrder(double time, double amp) { int i = 0; modified = true; if (times != null) { while (i < times.size() && time > times.get(i)) i++; } addPoint(i, time, amp); // System.out.println("absT: " + absT + " absA: " + absA + " i: " + i); return; } // Check if mouse click corresponds to existing envelope point // return index of point or -1 if no point is close private int getSelection(int x, int y) { int cutoff = 7; int bestDist = cutoff * 2; int bestIndex = -1; if (times == null) return bestIndex; for (int i = 0; i < times.size(); i++) { int xi = time2x(times.get(i)); int yi = amp2y(amps.get(i)); int dx = Math.abs(x - xi); int dy = Math.abs(y - yi); if (dx < cutoff && dy < cutoff && dx + dy < bestDist) { bestDist = dx + dy; bestIndex = i; } } selection = bestIndex; return bestIndex; } //Check if mouse click corresponds with existing envelope point (to select point) private boolean checkSelection(int time, int amp) { int i = getSelection(time, amp); if (i < 0) return false; envTimes.setSelectedIndex(i); envAmplitudes.setText(form.format(amps.get(i))); repaint(); return true; } //output the envelope as a string public String outputEnv(String envType, boolean valueType, double minTime, double maxTime, double minAmp, double maxAmp) { String outputStr = new String(); int start = 0; outputStr += ("(" + envType + " "); if (valueType) { // insert initial value if (within(times.get(0), 0.0, EPSILON)) { outputStr += (form.format(amps.get(0)) + " "); start = 1; } else outputStr += form.format(impliedAmp()) + " "; } for (int i = start; i < amps.size(); i++) { double time = times.get(i); double amp = amps.get(i); outputStr += form.format(time) + " " + form.format(amp) + " "; } if (valueType) { // we're already ending with a value if (within(times.lastElement(), maxTime, EPSILON)) { // we're done because we output at maxTime } else { outputStr += form.format(maxTime) + " " + form.format(impliedAmp()); } } else { outputStr += form.format(maxTime); } outputStr += ")"; return outputStr; } // parse envelope from string and prepare to edit public void setEnv(String envData) { System.out.println("setEnv: envData " + envData); if (envData == null) return; // just in case //check if envelope exists in collection boolean nameIsEnv = false; // trim the open and close parens from envData int startx = envData.indexOf("(") + 1; // if no open paren, startx will be 0 int endx = envData.indexOf(")"); if (endx < 0) endx = envData.length(); envData = envData.substring(startx, endx); System.out.println("setEnv: envData(2) " + envData); StringTokenizer st = new StringTokenizer(envData); String type = st.nextToken(); System.out.println("setEnv: type " + type); envTypes.setSelectedItem(type); //clear(); valueType = type.endsWith("v"); int limit = (valueType ? 2 : 1); times.removeAllElements(); amps.removeAllElements(); int i = 0; // pretend mouse is down to avoid making each point undo-able boolean save = mouseDown; mouseDown = false; double time, amp; if (valueType) { // first element is value amp = new Double(st.nextToken().trim()); addPoint(i++, 0.0, amp); } while (st.countTokens() >= 2) { String token1 = st.nextToken().trim(); time = new Double(token1); String token2 = st.nextToken().trim(); amp = new Double(token2); addPoint(i++, time, amp); System.out.println("time " + token1 + " amp " + token2 + " size " + times.size()); } mouseDown = save; // restore the mouseDown state if (!valueType) { // last element is time maxT.setText(st.nextToken()); } System.out.println("times " + times + " amps " + amps); //calculateDraws(true); modified = false; repaint(); } public void keyPressed(KeyEvent event) { //Graphics2D drawArea = image.createGraphics(); if (event.getKeyCode() == KeyEvent.VK_DELETE) { deleteSelection(); repaint(); } } //fill rest of mouse functions public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseClicked(MouseEvent e) {} public void mouseMoved(MouseEvent e) {} public void keyReleased(KeyEvent event) {} public void keyTyped(KeyEvent event) {} } } nyquist-3.05/jnyqide/PreferencesDialog.java0000644000175000000620000004460411524554371020071 0ustar stevestaff/* * Preferences dialog based on ReplaceDialog.java */ // Current elements are: // // Restore Defaults // [] Automatically insert close-parentheses // <-|--> Relative height of completion box // package jnyqide; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.io.File; import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext; import jnyqide.*; class PreferencesDialog extends JInternalFrame implements ActionListener { private MainFrame mainFrame; private JScrollPane scrollPane; private JPanel panel; private JButton defaultPrefs; // "Restore Defaults" private JCheckBox startInSalMode; // "Start in SAL mode (not Lisp)" private JCheckBox salShowLisp; // "Show translation of SAL to Lisp" private JCheckBox parenAutoInsert; // "Automatically insert close-parentheses" private JCheckBox enableSound; // "Enable sound output in PLAY command" private JCheckBox autoNorm; // "AutoNorm" private JCheckBox salTraceBack; // "Print SAL traceback on SAL error" private JCheckBox salBreak; // "Enable XLISP break on SAL error" private JCheckBox xlispBreak; // "Enable XLISP break on XLISP error" private JCheckBox xlispTraceBack; // "Print XLISP traceback on XLISP error" private JCheckBox printGC; // "Print info about garbage collection" private JCheckBox fullSearch; // "Use full search for code completion" private JCheckBox internalBrowser; // "Use window in jNyqIDE for help browser" private JCheckBox onlineManual; // "Use online manual instead of local copy" private JScrollBar completionListPercent; // "Relative height of completion box" private JComboBox audioRate; // "Audio Sample Rate" private JTextField controlRate; // "Control Sample Rate" private JComboBox fontSize; // "Font Size" private JButton sfDirectory; // "Set Default Sound File Directory" private JButton initialDirectory; // "Set Initial Directory" private JFileChooser startfd; private JFileChooser fd; private String[] audioRates = { "96000", "48000", "44100", "22050", "16000", "11025", "8000" }; private String currentFontSize; private String[] fontSizes = { "6", "7", "8", "9", "10", "11", "12", "14", "16", "18", "20", "24", "28", "32", "36" }; protected JCheckBox makeCheckBox(String doc, boolean val) { //JPanel contentPane = (JPanel) getContentPane(); JCheckBox cb = new JCheckBox(doc, val); cb.setAlignmentX(Component.LEFT_ALIGNMENT); //contentPane.add(cb); panel.add(cb); return cb; } public PreferencesDialog(MainFrame mainFrame_) { super(); final PreferencesDialog preferencesDialog = this; //super(mainFrame_, "Preferences", true); // initialize Dialog setTitle("Preferences"); mainFrame = mainFrame_; addInternalFrameListener(new InternalFrameListener() { public void internalFrameClosing(InternalFrameEvent e) { mainFrame.prefStartInSalMode = startInSalMode.isSelected(); boolean enable = salShowLisp.isSelected(); mainFrame.setBoolean("*sal-compiler-debug*", enable); mainFrame.prefSalShowLisp = enable; mainFrame.prefParenAutoInsert = parenAutoInsert.isSelected(); enable = enableSound.isSelected(); mainFrame.callFunction( enable ? "sound-on" : "sound-off", ""); mainFrame.prefEnableSound = enable; enable = autoNorm.isSelected(); mainFrame.callFunction( enable ? "autonorm-on" : "autonorm-off", ""); mainFrame.prefAutoNorm = enable; enable = salTraceBack.isSelected(); mainFrame.callFunction("sal-tracenable", mainFrame.tOrNil(enable)); mainFrame.prefSalTraceBack = enable; enable = salBreak.isSelected(); mainFrame.callFunction("sal-breakenable", mainFrame.tOrNil(enable)); mainFrame.prefSalBreak = enable; enable = (xlispBreak.isSelected() || xlispTraceBack.isSelected()); mainFrame.callFunction("xlisp-breakenable", mainFrame.tOrNil(enable)); mainFrame.prefXlispBreak = enable; enable = xlispTraceBack.isSelected(); mainFrame.callFunction("xlisp-tracenable", mainFrame.tOrNil(enable)); mainFrame.prefXlispTraceBack = enable; enable = printGC.isSelected(); if (enable != mainFrame.prefPrintGC) { mainFrame.setBoolean("*gc-flag*", enable); mainFrame.prefPrintGC = enable; } mainFrame.prefFullSearch = fullSearch.isSelected(); mainFrame.prefInternalBrowser = internalBrowser.isSelected(); mainFrame.prefOnlineManual = onlineManual.isSelected(); if ((int) mainFrame.prefCompletionListPercent != (int) (completionListPercent.getValue())) { mainFrame.prefCompletionListPercent = completionListPercent.getValue(); mainFrame.tileCompletion(); } String rateString = (String) audioRate.getSelectedItem(); //audioRate.setSize(50, 20); int rate = validate(rateString); if (rate > 0 && !rateString.equals(mainFrame.prefAudioRate)) { mainFrame.callFunction("set-sound-srate", rateString); mainFrame.prefAudioRate = rateString; } rateString = controlRate.getText(); rate = validate(rateString); if (rate > 0 && !rateString.equals(mainFrame.prefControlRate)) { mainFrame.callFunction("set-control-srate ", rateString); mainFrame.prefControlRate = rateString; } String fontString = (String) fontSize.getSelectedItem(); int size = validate(fontString); if (size > 0 && !fontString.equals(mainFrame.prefFontSize)) { mainFrame.prefFontSize = fontString; mainFrame.setFontSize(size); } File file = startfd.getSelectedFile(); System.out.println("startfd.getSelectedFile() -> " + file); if (file != null) { String dir = file.toString().replaceAll("\\\\", "/"); System.out.println("startfd.getSelectedFile: " + dir); if (dir != null && dir.length() > 0) { mainFrame.prefDirectory = dir; mainFrame.changeDirectory(dir); } } else { mainFrame.prefDirectory = ""; } file = fd.getSelectedFile(); if (file != null) { String dir = file.toString().replaceAll("\\\\", "/"); System.out.println("fd.getSelectedFile: " + dir); if (dir != null && dir.length() > 0) { mainFrame.prefSFDirectory = dir; mainFrame.setVariable("*default-sf-dir*", "\"" + dir + "\""); } } else { mainFrame.prefSFDirectory = ""; } mainFrame.prefsHaveBeenSet = true; dispose(); } public void internalFrameOpened(InternalFrameEvent e) { } public void internalFrameClosed(InternalFrameEvent e) { mainFrame.disconnectPreferences(); //System.out.println("FrameClosed"); } public void internalFrameIconified(InternalFrameEvent e) { } public void internalFrameDeiconified(InternalFrameEvent e) { } public void internalFrameActivated(InternalFrameEvent e) { } public void internalFrameDeactivated(InternalFrameEvent e) { } }); panel = new JPanel(); scrollPane = new JScrollPane(panel); JPanel contentPane = (JPanel) getContentPane(); contentPane.add(scrollPane, BorderLayout.CENTER); //contentPane panel.setLayout( new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.add(new JLabel("Preferences are updated when you close this Preferences Window")); panel.add(Box.createRigidArea(new Dimension(0, 10))); // button to restore default preferences defaultPrefs = new JButton("Restore Defaults"); defaultPrefs.addActionListener(this); defaultPrefs.setAlignmentX(Component.LEFT_ALIGNMENT); panel.add(defaultPrefs); panel.add(Box.createRigidArea(new Dimension(0, 10))); // Start in Sal mode (not Lisp)" startInSalMode = makeCheckBox("Start in SAL mode (not Lisp)", mainFrame.prefStartInSalMode); // Show translation of SAL to Lisp salShowLisp = makeCheckBox("Show translation of SAL to Lisp", mainFrame.prefSalShowLisp); // Automatically insert close-parenthesis (checkbox) parenAutoInsert = makeCheckBox( "Automatically insert close-parentheses", mainFrame.prefParenAutoInsert); // Enable sound output (checkbox) enableSound = makeCheckBox("Enable sound output in PLAY command", mainFrame.prefEnableSound); // AutoNorm (checkbox) autoNorm = makeCheckBox("AutoNorm", mainFrame.prefAutoNorm); // Enable SAL Stack Traceback on Error salTraceBack = makeCheckBox("Print SAL traceback on SAL error", mainFrame.prefSalTraceBack); // break into XLISP debugger on SAL error salBreak = makeCheckBox("Enable XLISP break on SAL error", mainFrame.prefSalBreak); // Enable XLISP Break when XLISP encounters error xlispBreak = makeCheckBox("Enable XLISP break on XLISP error", mainFrame.prefXlispBreak); // print XLISP TraceBack on XLISP error xlispTraceBack = makeCheckBox("Print XLISP traceback on XLISP error", mainFrame.prefXlispTraceBack); // printGC printGC = makeCheckBox("Print info about garbage collection", mainFrame.prefPrintGC); // Use full search for code completion (checkbox) fullSearch = makeCheckBox("Use full search for code completion", mainFrame.prefFullSearch); // Use internal window for manual (checkbox) internalBrowser = makeCheckBox("Use window in jNyqIDE for help browser", mainFrame.prefInternalBrowser); // Use online manual (checkbox) onlineManual = makeCheckBox("Use online manual instead of local copy", mainFrame.prefOnlineManual); panel.add(Box.createRigidArea(new Dimension(0, 10))); // Relative height of completion box (slider) panel.add(new JLabel("Relative height of completion box", JLabel.CENTER)); completionListPercent = new JScrollBar(JScrollBar.HORIZONTAL, (int) mainFrame.prefCompletionListPercent, 1, 0, 100); panel.add(completionListPercent); panel.add(Box.createRigidArea(new Dimension(0, 10))); // Audio Sample Rate (editable combobox) panel.add(new JLabel("Audio Sample Rate")); audioRate = new JComboBox(audioRates); // Set correct selection for (int i = 0; i < audioRates.length; i++) { if (mainFrame.prefAudioRate.equals(audioRates[i])) { audioRate.setSelectedIndex(i); break; } } audioRate.setEditable(true); audioRate.setAlignmentX(Component.LEFT_ALIGNMENT); audioRate.setMaximumSize( new Dimension(100, audioRate.getPreferredSize().height)); panel.add(audioRate); panel.add(Box.createRigidArea(new Dimension(0, 10))); // Control Rate (text field) panel.add(new JLabel("Control Sample Rate")); controlRate = new JTextField(mainFrame.prefControlRate); controlRate.setAlignmentX(Component.LEFT_ALIGNMENT); controlRate.setMaximumSize( new Dimension(100, controlRate.getPreferredSize().height)); panel.add(controlRate); panel.add(Box.createRigidArea(new Dimension(0, 10))); // Font Size (editable combobox) panel.add(new JLabel("Font Size")); fontSize = new JComboBox(fontSizes); // Set correct selection for (int i = 0; i < fontSizes.length; i++) { if (mainFrame.prefFontSize.equals(fontSizes[i])) { fontSize.setSelectedIndex(i); break; } } fontSize.setEditable(true); fontSize.setAlignmentX(Component.LEFT_ALIGNMENT); fontSize.setMaximumSize( new Dimension(100, fontSize.getPreferredSize().height)); panel.add(fontSize); panel.add(Box.createRigidArea(new Dimension(0, 10))); // Select Startup Directory (button) startfd = new JFileChooser("Select Initial Directory"); startfd.setCurrentDirectory(new File(mainFrame.prefDirectory)); startfd.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); initialDirectory = new JButton("Set Initial Directory"); initialDirectory.addActionListener(this); initialDirectory.setAlignmentX(Component.LEFT_ALIGNMENT); panel.add(initialDirectory); // Select Sound File Output Directory (button) fd = new JFileChooser("Select Default Soundfile Directory"); fd.setCurrentDirectory(new File(mainFrame.prefSFDirectory)); fd.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); sfDirectory = new JButton("Set Default Soundfile Directory"); sfDirectory.addActionListener(this); sfDirectory.setAlignmentX(Component.LEFT_ALIGNMENT); panel.add(sfDirectory); panel.add(Box.createVerticalGlue()); /* * The Nyquist IDE has a preferences dialog with a couple of things you * can change. It would be great to have a graphical way to set things * like the normalization style, default audio and control sample rates, * whether to play sounds or save audio to disk or both when calling the * play function, whether to apply reverb and/or EQ to the output signal * when using PLAY, a default sound file directory, whether to print a * stack trace when an error is encountered, etc. (All of these things * can be set in Nyquist, but most users do not know how.) */ pack(); Dimension size = new Dimension(400, 400); setSize(size); Point mfloc = mainFrame.getLocation(); setLocation(mfloc.x + 25, mfloc.y + 25); setResizable(true); setVisible(true); setClosable(true); setMaximizable(true); setIconifiable(true); repaint(); } private int validate(String s) { try { int temp = Integer.parseInt(s); if (temp > 0) return temp; } catch (Exception e) { } return -1; } /* // On Mac OS X, we can select directories using the native file open dialog void getDirectoryUsingFileDialog(String title) { boolean saveUseJFC = Prefs.useJFileChooser; Prefs.useJFileChooser = false; System.setProperty("apple.awt.fileDialogForDirectories", "true"); OpenDialog od = new OpenDialog(title, defaultDir, null); if (od.getDirectory()==null) directory = null; else directory = od.getDirectory() + od.getFileName() + "/"; defaultDir = directory; System.setProperty("apple.awt.fileDialogForDirectories", "false"); Prefs.useJFileChooser = saveUseJFC; } */ public void actionPerformed(ActionEvent evt) { if (evt.getSource() == sfDirectory) { fd.showOpenDialog(this); } else if (evt.getSource() == initialDirectory) { startfd.showOpenDialog(this); } else if (evt.getSource() == defaultPrefs) { startInSalMode.setSelected(mainFrame.prefStartInSalModeDefault); salShowLisp.setSelected(mainFrame.prefSalShowLispDefault); parenAutoInsert.setSelected( mainFrame.prefParenAutoInsertDefault); enableSound.setSelected(mainFrame.prefEnableSoundDefault); autoNorm.setSelected(mainFrame.prefAutoNormDefault); salTraceBack.setSelected(mainFrame.prefSalTraceBackDefault); salBreak.setSelected(mainFrame.prefSalBreakDefault); xlispBreak.setSelected(mainFrame.prefXlispBreakDefault); xlispTraceBack.setSelected(mainFrame.prefXlispTraceBackDefault); printGC.setSelected(mainFrame.prefPrintGCDefault); fullSearch.setSelected(mainFrame.prefFullSearchDefault); internalBrowser.setSelected(mainFrame.prefInternalBrowserDefault); onlineManual.setSelected(mainFrame.prefOnlineManualDefault); completionListPercent.setValue( (int) (mainFrame.prefCompletionListPercentDefault + 0.5)); audioRate.setSelectedItem(mainFrame.prefAudioRateDefault); controlRate.setText(mainFrame.prefControlRateDefault); fontSize.setSelectedItem(mainFrame.prefFontSizeDefault); startfd.setSelectedFile(null); fd.setSelectedFile(null); } } } nyquist-3.05/jnyqide/InstrumentCharacteristics.java0000644000175000000620000002445211466723256021720 0ustar stevestaffpackage jnyqide; import java.util.ArrayList; import java.io.BufferedReader; /*** ** Class: InstrumentCharacteristics ** Author: Priyanka Raghavan and Roger B. Dannenberg ** Description: The instrument characteristics class reads from ** the instruments.txt file and stores the ** instrument characteristics such as the subcategory,name,library. ** The characteristics include the implementation and parameter ** description. The different parameters are added as an arraylist. * * Syntax for the instruments.txt file: * (see instruments.txt for examples, it should be clear) * Each sound is described by a function declaration preceded by * a category like this: * category:subcategory[function](parameters) * where category and subcategory determine what appears in the * pull-down lists in the browser, and function is the lisp * function to call (if omitted, then subcategory is also the * function name). parameters is a comma-separated list of * parameter declarations. Each parameter is of the form * type name = default (low:high) * where type is "int" or "float", name is the parameter name * (if the parameter is a keyword parameter, it is prefixed with * a colon), and low:high gives the range for a slider. * After the function declaration, there can be specifications for * the implementation of the function. There should be either * a pair of implementations for LISP and SAL, or a single * REQUIRE. The LISP and SAL implementation is specified as follows: * LISP-SOURCE * * SAL-SOURCE * * and the REQUIRE is specified as follows: * REQUIRE "path to implementation file to be loaded" * After the implementation specifications (if any), the * sound description is terminated by the following line: * END-SOUND * There may be any number of these sound specifications (instruments) * in the file. * When a user selects an instrument in the browser, the appropriate * implementation is constructed (using SAL-SOURCE or LISP-SOURCE if * present, otherwise using REQUIRE to load a file) and the function * is called with parameters chosen by sliders. * **/ public class InstrumentCharacteristics { private String categoryName; private String subcategoryName; private String functionName; private ArrayList parameterList; private String lispImplementation; private String salImplementation; private String require; private static char buffer; private static boolean bufferp; private static String line; InstrumentCharacteristics() { bufferp = false; parameterList = new ArrayList(); } public String getCategoryName() { return categoryName; } public void setCategoryName(String name) { categoryName = name; } public void setSubcategoryName(String subname) { subcategoryName = subname; } public String getSubcategoryName() { return subcategoryName; } public String getFunctionName() { return functionName; } public void addParameter(String name, String minValue, String maxValue, String defaultValue, String type) { Parameter parameter = new Parameter(name, minValue, maxValue, defaultValue, type); parameterList.add(parameter); } public ArrayList getParameters(){ return parameterList; } public String getLispImplementation() { return lispImplementation; } public String getSalImplementation() { return salImplementation; } public String getRequire() { return require; } public String readImplementation(BufferedReader br) throws Exception { String implementation = ""; while ((line = br.readLine()) != null && line.indexOf("REQUIRE") != 0 && line.indexOf("LISP-SOURCE") != 0 && line.indexOf("SAL-SOURCE") != 0 && line.indexOf("END-SOUND") != 0) { implementation = implementation + line + "\n"; } return implementation; } public boolean readData(BufferedReader br) { categoryName = getToken(br); // category if (categoryName == null) return false; if (getNonSpace(br) != ':') { System.out.println("expected : after " + categoryName); return false; } subcategoryName = getToken(br); int c = getNonSpace(br); functionName = subcategoryName; if (c == '[') { functionName = getToken(br); if (getNonSpace(br) != ']') { System.out.println("expected ] after " + functionName); return false; } } else ungetChar(c); if (getNonSpace(br) != '(') { System.out.println("no ( after " + functionName); return false; } while ((c = getNonSpace(br)) != ')') { ungetChar(c); Parameter p = readParameter(br); if (p == null) { System.out.println("syntax error for parameter in " + subcategoryName); return false; } parameterList.add(p); } // get a file to load or an implementation to execute require = null; lispImplementation = null; salImplementation = null; try { // read eol after function spec line = br.readLine(); line = ""; // force a readline on first entry to loop while (true) { while (line != null && line.length() < 3) { // skip blank lines -- we're not checking too carefully // but a char count of 3 allows only CRLF and maybe a // space or tab line = br.readLine(); } if (line == null) { System.out.println( "expected LISP-SOURCE or SAL-SOURCE, REQUIRE or " + "END-SOUND, not " + line); return false; } int reqPos = line.indexOf("REQUIRE"); if (reqPos >= 0) { reqPos += 8; // length of "REQUIRE " require = line.substring(reqPos, line.length()); line = br.readLine(); } else if (line.indexOf("LISP-SOURCE") == 0) { // read until LISP-END lispImplementation = readImplementation(br); } else if (line.indexOf("SAL-SOURCE") == 0) { // read until SAL-END salImplementation = readImplementation(br); } else if (line.indexOf("END-SOUND") == 0) { return true; } else { System.out.println( "expected REQUIRE, LISP-SOURCE, SAL-SOURCE, or " + "END-SOUND, not " + line); return false; } } } catch (Exception e) { return false; } } private Parameter readParameter(BufferedReader br) { Parameter p = new Parameter(); String tok = getToken(br); if (tok == null) { System.out.println("expected parameter type: " + tok); return null; } p.setType(tok); int param1 = getNonSpace(br); if (param1 != ':') { ungetChar(param1); } tok = getToken(br); if (tok == null) { System.out.println("expected parameter name: " + tok); return null; } if (param1 == ':') tok = ":" + tok; p.setName(tok); if (getNonSpace(br) != '=') { System.out.println("expected = after parameter: " + tok); return null; } tok = getToken(br); if (tok == null) { System.out.println("expected default value: " + tok); return null; } p.setDefaultValue(tok); if (getNonSpace(br) != '(') { System.out.println("expected ( after default value: " + tok); return null; } tok = getToken(br); if (tok == null) { System.out.println("expected min value: " + tok); return null; } p.setMinValue(tok); if (getNonSpace(br) != ':') { System.out.println("expected : after min value: " + tok); return null; } tok = getToken(br); if (tok == null) { System.out.println("expected max value: " + tok); return null; } p.setMaxValue(tok); if (getNonSpace(br) != ')') { System.out.println("expected ) after max value: " + tok); return null; } int c = getNonSpace(br); if (c != ',') ungetChar(c); return p; } private int getNonSpace(BufferedReader br) { int c; while ((c = getChar(br)) != -1 && Character.isWhitespace(c)); return c; } private int getChar(BufferedReader br) { if (bufferp) { bufferp = false; return buffer; } try { return br.read(); } catch (Exception e) { return -1; } } private void ungetChar(int c) { if (c == -1) return; // ignore EOF buffer = (char) c; bufferp = true; } private String getToken(BufferedReader br) { int c = getNonSpace(br); StringBuffer token = new StringBuffer(); while (c != -1 && (Character.isLetterOrDigit(c) || c == '-' || c == '.')) { token.append((char) c); c = getChar(br); } ungetChar(c); String s = new String(token); if (s.length() == 0) return null; // System.out.println("gettoken: " + token); return s; } } /** ** Class: Parameter ** Author: Priyanka Raghavan ** Description: This class is used to store parameter values like ** name, minvalue, maxvalue, default value, and type (integer,string, etc.) ** **/ class Parameter{ String name; String minValue; String maxValue; String defaultValue; String type; float value; Parameter() { } Parameter(String name, String minValue, String maxValue, String defaultValue, String type) { this.name = name; this.minValue = minValue; this.maxValue = maxValue; this.defaultValue = defaultValue; this.type=type; value = 0.0f; } public void setName(String name) { this.name=name; } public void setMinValue(String value) { minValue = value; } public void setMaxValue(String value) { maxValue = value; } public void setDefaultValue(String defaultvalue) { defaultValue = defaultvalue; } public String getName() { return name; } public String getMinValue() { return minValue; } public String getMaxValue() { return maxValue; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getDefaultValue() { return defaultValue; } public float getValue() { return value; } public void setValue(float f) { value = f; } } nyquist-3.05/jnyqide/MainFrame_AboutBox.java0000644000175000000620000000601711466723256020153 0ustar stevestaffpackage jnyqide; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ public class MainFrame_AboutBox extends JDialog implements ActionListener { JPanel panel1 = new JPanel(); JPanel panel2 = new JPanel(); JPanel insetsPanel1 = new JPanel(); JPanel insetsPanel2 = new JPanel(); JPanel insetsPanel3 = new JPanel(); JButton button1 = new JButton(); JLabel imageLabel = new JLabel(); JLabel label1 = new JLabel(); JLabel label2 = new JLabel(); JLabel label3 = new JLabel(); JLabel label4 = new JLabel(); BorderLayout borderLayout1 = new BorderLayout(); BorderLayout borderLayout2 = new BorderLayout(); FlowLayout flowLayout1 = new FlowLayout(); GridLayout gridLayout1 = new GridLayout(); String product = "jNyqIDE - Nyquist Integrated Development Environment"; String version = "Version 2.0"; String copyright = "Copyright (c) 2002-2006"; String comments = "Jesse Clark, David Howard, David Mowatt, David Deangelis, and Roger B. Dannenberg"; public MainFrame_AboutBox(Frame parent) { super(parent); enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } pack(); } //Component initialization private void jbInit() throws Exception { //imageLabel.setIcon(new ImageIcon(MainFrame_AboutBox.class.getResource("[Your Image]"))); this.setTitle("About"); setResizable(false); panel1.setLayout(borderLayout1); panel2.setLayout(borderLayout2); insetsPanel1.setLayout(flowLayout1); insetsPanel2.setLayout(flowLayout1); insetsPanel2.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); gridLayout1.setRows(4); gridLayout1.setColumns(1); label1.setText(product); label2.setText(version); label3.setText(copyright); label4.setText(comments); insetsPanel3.setLayout(gridLayout1); insetsPanel3.setBorder(BorderFactory.createEmptyBorder(10, 60, 10, 10)); button1.setText("Ok"); button1.addActionListener(this); insetsPanel2.add(imageLabel, null); panel2.add(insetsPanel2, BorderLayout.WEST); this.getContentPane().add(panel1, null); insetsPanel3.add(label1, null); insetsPanel3.add(label2, null); insetsPanel3.add(label3, null); insetsPanel3.add(label4, null); panel2.add(insetsPanel3, BorderLayout.CENTER); insetsPanel1.add(button1, null); panel1.add(insetsPanel1, BorderLayout.SOUTH); panel1.add(panel2, BorderLayout.NORTH); } //Overridden so we can exit when window is closed protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { cancel(); } super.processWindowEvent(e); } //Close the dialog void cancel() { dispose(); } //Close the dialog on a button event public void actionPerformed(ActionEvent e) { if (e.getSource() == button1) { cancel(); } } } nyquist-3.05/jnyqide/PopupListener.java0000644000175000000620000000207011466723256017315 0ustar stevestaffpackage jnyqide; import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.event.*; import javax.swing.*; import javax.swing.text.*; import javax.swing.undo.*; import jnyqide.*; class PopupListener extends MouseAdapter { JPopupMenu popup; JTextPane pane; PopupListener(JPopupMenu popupMenu, JTextPane textPane) { popup = popupMenu; pane = textPane; } public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { MenuElement[] items = popup.getSubElements(); for (int i = 0; i < items.length; i++) { String name = items[i].getComponent().getName(); if (name.equals("context copy") || name.equals("context cut")) { ((JMenuItem) items[i]).setEnabled(pane.getSelectedText() != null); } } popup.show(e.getComponent(), e.getX(), e.getY()); } } }nyquist-3.05/jnyqide/FindDialog.java0000644000175000000620000000745011466723256016513 0ustar stevestaff/* * Copyright (c) 1997 John Jensen. All rights reserved. * * This software is FREE FOR COMMERCIAL AND NON-COMMERCIAL USE, * provided the following condition is met. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that any copy or derivative of this software or documentation * retaining the name "John Jensen" also retains this condition and the * following disclaimer. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * CopyrightVersion 1.0 */ package jnyqide; import java.util.*; import java.awt.*; import java.awt.event.*; import jnyqide.*; class FindDialog extends Dialog implements WindowListener, ActionListener { private Button fbutton,cbutton; private MainFrame mainFrame; private NyquistFile nyquistFile; private TextField pattern; private Properties strings; public FindDialog(NyquistFile tf, MainFrame mainFrame_) { super(mainFrame_, "Find", true); setBackground(Color.lightGray); nyquistFile = tf; mainFrame = mainFrame_; Panel p1 = new Panel(); p1.setLayout(new FlowLayout()); p1.add(new Label("Find:")); pattern = new TextField(); pattern.setColumns(35); if (tf.pane.getSelectedText() == null) // BWP pattern.setText(mainFrame.findPattern); else // BWP pattern.setText(tf.pane.getSelectedText()); // BWP p1.add(pattern); p1.doLayout(); add("North", p1); Panel p2 = new Panel(); fbutton = new Button("Find Next"); fbutton.addActionListener(this); p2.add(fbutton); cbutton = new Button("Close"); cbutton.addActionListener(this); p2.add(cbutton); add("South",p2); Dimension size = new Dimension(400, 110); setSize(size); Point tfloc = tf.getLocation(); Point mfloc = mainFrame.getLocation(); setLocation(mfloc.x + tfloc.x, mfloc.y + tfloc.y + 85); addWindowListener(this); setVisible(true); } public void windowDeiconified(WindowEvent event) {} public void windowIconified(WindowEvent event) {} public void windowActivated(WindowEvent event) {} public void windowDeactivated(WindowEvent event) {} public void windowOpened(WindowEvent event) {} public void windowClosed(WindowEvent event) {} public void windowClosing(WindowEvent event) { mainFrame.findPattern = pattern.getText(); nyquistFile.lastFound = pattern.getText(); // BWP dispose(); } public void actionPerformed(ActionEvent evt) { if (evt.getSource() == cbutton) { mainFrame.findPattern = pattern.getText(); nyquistFile.lastFound = pattern.getText(); dispose(); return; } if (evt.getSource() == fbutton) if (!nyquistFile.find(pattern.getText())) { NotFoundDialog nf = new NotFoundDialog(mainFrame, strings, getLocation()); nf.setVisible(true); } } } nyquist-3.05/jnyqide/BareBonesBrowserLaunch.java0000644000175000000620000000613011466723256021044 0ustar stevestaff///////////////////////////////////////////////////////// // Bare Bones Browser Launch // // Version 1.5 // // December 10, 2005 // // Modified by RBD, 2008 to test for htmlview in linux// // Supports: Mac OS X, GNU/Linux, Unix, Windows XP // // Example Usage: // // String url = "http://www.centerkey.com/"; // // BareBonesBrowserLaunch.openURL(url); // // Public Domain Software -- Free to Use as You Like // ///////////////////////////////////////////////////////// package jnyqide; // this line was added by RBD import java.lang.reflect.Method; import javax.swing.JOptionPane; public class BareBonesBrowserLaunch { private static final String errMsg = "Error attempting to launch web browser"; public static void openURL(String url) { String osName = System.getProperty("os.name"); System.out.println("BareBonesBrowserLaunch: url=" + url + " osName:" + osName); try { if (osName.startsWith("Mac OS")) { System.out.println("BareBonesBrowserLaunch: Mac OS detected"); // try a new way Runtime.getRuntime().exec(new String[] {"/usr/bin/open", url}); // here's the old way that does not handle #name suffix on url // Class fileMgr = Class.forName("com.apple.eio.FileManager"); // System.out.println("fileMgr=" + fileMgr); // Method openURL = fileMgr.getDeclaredMethod("openURL", // new Class[] {String.class}); // openURL.invoke(null, new Object[] {url}); System.out.println("openURL invoked with " + url); } else if (osName.startsWith("Windows")) { Runtime.getRuntime().exec( "rundll32 url.dll, FileProtocolHandler " + "\"" + url + "\""); // quote url or lose "#" suffixes } else { //assume Unix or Linux String[] browsers = { "htmlview", "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; int count; for (count = 0; count < browsers.length; count++) { if (Runtime.getRuntime().exec( new String[] {"which", browsers[count]}).waitFor() == 0) { break; } } if (count >= browsers.length) throw new Exception("Could not find web browser"); System.out.println("Found browser: " + browsers[count]); System.out.println("sending url: " + url); Runtime.getRuntime().exec(new String[] {browsers[count], url}); } } catch (Exception e) { JOptionPane.showMessageDialog(null, errMsg + ":\n" + e.getLocalizedMessage()); } } } nyquist-3.05/jnyqide/browser.java0000644000175000000620000003426011466723256016175 0ustar stevestaffpackage jnyqide; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTextArea; import javax.swing.ListModel; import javax.swing.border.Border; import javax.swing.border.EtchedBorder; import javax.swing.SpringLayout; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; /*** ** Class: Browser ** Author: Priyanka Raghavan and Roger B. Dannenberg ** Description: This is the frame class that implements the sound browser. **/ class Browser extends JInternalFrame { NyquistThread nyquistThread; MainFrame mainFrame; ArrayList instruments; InstrumentCharacteristics currentInstr; /** * @ desc Default constructor, takes the nyquist thread from main frame * @author prirags - removed all references to the log factory */ public Browser(MainFrame mainFrame, NyquistThread nyquistThread) { this.mainFrame = mainFrame; this.nyquistThread=nyquistThread; instruments = new ArrayList(); currentInstr = null; try { System.out.println("in Browser()"); initGUI(); setLocation(50+10, 50+10); setSize(600, 500); setResizable(true); setVisible(true); setClosable(true); setMaximizable(true); setIconifiable(true); // setDefaultCloseOperation(JInternalFrame.DO_NOTHING_ON_CLOSE); System.out.println("at end of Browser()"); } catch (Exception exception) { exception.printStackTrace(); } } /** * @ desc intializes gui elements * @author prirags - removed all references to the log factory */ private void initGUI() { setTitle("Sound Browser"); this.setSize(800, 513); jPanel1 = new JPanel(new SpringLayout()); Border etchedLine; etchedLine = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); this.getContentPane().add(jPanel1, BorderLayout.NORTH); jPanel1.setBorder(etchedLine); // jPanel1.setPreferredSize(new java.awt.Dimension(638, 101)); categoryLabel = new JLabel(); jPanel1.add(categoryLabel); categoryLabel.setText("Sound Category:"); ComboBoxModel categoryComboModel = new DefaultComboBoxModel(); categoryCombo = new JComboBox(); categoryCombo.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent evt) { if (evt.getStateChange() != evt.SELECTED) return; if (subcategoryCombo == null) return; // just in case // set up subcategory subcategoryCombo.removeAllItems(); subcategoryCombo.addItem("Select One"); String category = (String) evt.getItem(); System.out.println("category is " + category); for (int i = 0; i < instruments.size(); i++) { if (((InstrumentCharacteristics) instruments.get(i)). getCategoryName().equalsIgnoreCase(category)) { subcategoryCombo.addItem( ((InstrumentCharacteristics) instruments. get(i)).getSubcategoryName()); } } } }); jPanel1.add(categoryCombo); categoryCombo.setModel(categoryComboModel); // categoryCombo.setPreferredSize(new java.awt.Dimension(306, 25)); subcategoryLabel = new JLabel(); jPanel1.add(subcategoryLabel); subcategoryLabel.setText("Sound Name:"); ComboBoxModel subcategoryComboModel = new DefaultComboBoxModel(); subcategoryCombo = new JComboBox(); subcategoryCombo.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent evt) { for (int i = 0; i < instruments.size(); i++) { InstrumentCharacteristics ic = (InstrumentCharacteristics) instruments.get(i); String name = (String) evt.getItem(); if (ic.getSubcategoryName().equalsIgnoreCase(name)) { currentInstr = ic; visitSound(); } } } }); jPanel1.add(subcategoryCombo); subcategoryCombo.setModel(subcategoryComboModel); // subcategoryCombo.setPreferredSize(new java.awt.Dimension(304, 28)); SpringUtilities.makeCompactGrid(jPanel1, 2, 2, 6, 6, 6, 6); jPanel3 = new JPanel(new SpringLayout()); this.getContentPane().add(jPanel3, BorderLayout.CENTER); etchedLine = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); jPanel3.setBorder(etchedLine); // jPanel3.setPreferredSize(new java.awt.Dimension(638, 148)); BorderLayout bl = new BorderLayout(); bl.setHgap(6); bl.setVgap(6); jPanel2 = new JPanel(bl); this.getContentPane().add(jPanel2, BorderLayout.SOUTH); etchedLine = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); jPanel2.setBorder(etchedLine); // jPanel2.setPreferredSize(new java.awt.Dimension(791, 159)); playButton = new JButton(); playButton.setText("PLAY"); // playButton.setPreferredSize(new java.awt.Dimension(100, 36)); // playButton.setBounds(4, -5, 100, 36); playButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { playSound(); } }); // try this: // (west: (north: play button)) // center: (north: // (center: "Lisp Expression that produced the sound") // center: scrolling text)) bl = new BorderLayout(); bl.setHgap(6); bl.setVgap(6); JPanel jPanel2a = new JPanel(bl); jPanel2.add(jPanel2a, BorderLayout.WEST); jPanel2a.add(playButton, BorderLayout.NORTH); bl = new BorderLayout(); bl.setHgap(6); bl.setVgap(6); JPanel jPanel2b = new JPanel(bl); jPanel2.add(jPanel2b, BorderLayout.CENTER); bl = new BorderLayout(); bl.setHgap(6); bl.setVgap(6); JPanel jPanel2b1 = new JPanel(bl); jPanel2b.add(jPanel2b1, BorderLayout.NORTH); JLabel label = new JLabel("Lisp Expression that produced the sound:"); label.setHorizontalAlignment(label.CENTER); jPanel2b1.add(label, BorderLayout.CENTER); jScrollPane1 = new JScrollPane(); expArea = new JTextArea(); jScrollPane1.setViewportView(expArea); // expArea.setPreferredSize(new java.awt.Dimension(650, 60)); jPanel2b.add(jScrollPane1, BorderLayout.CENTER); jScrollPane1.setPreferredSize(new java.awt.Dimension(700, 62)); // SpringUtilities.makeCompactGrid(jPanel2, 2, 2, 6, 6, 6, 6); categoryCombo.addItem("Select One"); // read the instrument.txt text file from lib // and create the InstrumentCharacteristic objects. // BufferedReader br; try { br = new BufferedReader( new FileReader(nyquistThread.soundBrowser)); } catch (Exception e) { System.out.println("ERROR -- could not open " + nyquistThread.soundBrowser); return; } while (true) { InstrumentCharacteristics ic = new InstrumentCharacteristics(); if (!ic.readData(br)) break; System.out.println("new IC: " + ic.getCategoryName() + ":" + ic.getSubcategoryName()); instruments.add(ic); boolean foundIt = false; for (int k = 0; k < categoryCombo.getItemCount(); k++) { if (categoryCombo.getItemAt(k).toString(). equalsIgnoreCase(ic.getCategoryName())) { foundIt = true; break; } } //end of for if (!foundIt) { System.out.println("Added " + ic.getCategoryName()); categoryCombo.addItem(ic.getCategoryName()); } } } private JPanel jPanel1; private JComboBox subcategoryCombo; private JLabel subcategoryLabel; private JLabel categoryLabel; private JComboBox categoryCombo; private JScrollPane jScrollPane1; private JPanel jPanel3; private JTextArea expArea; private JButton playButton; private JPanel jPanel2; private JLabel[] paramLabels = null; private JSlider[] paramSliders = null; public void newParameterCount(int n) { // make array for new labels and sliders JLabel[] newParamLabels = paramLabels; JSlider[] newParamSliders = paramSliders; int oldN = 0; if (paramLabels != null) { oldN = paramLabels.length; } if (n > oldN) { newParamLabels = new JLabel[n]; newParamSliders = new JSlider[n]; } // make old labels and sliders invisible before reuse if (paramLabels != null) { // paramLabel0.setVisible(false); for (int i = 0; i < oldN; i++) { paramLabels[i].setVisible(false); newParamLabels[i] = paramLabels[i]; paramSliders[i].setVisible(false); newParamSliders[i] = paramSliders[i]; } } else { // paramLabel0 = new JLabel(); // paramLabel0.setText("SLIDERS"); // jPanel3.add(paramLabel0); } // if we don't have enough, make more if (n > oldN) { for (int i = oldN; i < n; i++) { newParamLabels[i] = new JLabel(); jPanel3.add(newParamLabels[i]); newParamSliders[i] = new JSlider(); jPanel3.add(newParamSliders[i]); } paramLabels = newParamLabels; paramSliders = newParamSliders; } SpringUtilities.makeCompactGrid(jPanel3, n, 2, 6, 6, 6, 6); // now we have n labels and sliders in arrays // we also have paramLabel0 } public void visitSound() { System.out.println("visitSound called: " + currentInstr.getSubcategoryName()); /* * This hides the labels and the sliders that could have * been created in previous runs */ int numParams = currentInstr.getParameters().size(); newParameterCount(numParams); System.out.println("visitSound: numParams " + numParams); for(int i = 0; i < numParams; i++) { Parameter p = (Parameter) (currentInstr.getParameters().get(i)); paramLabels[i].setText(p.getName().toUpperCase()); System.out.println("Parameter" + p.getName()); paramLabels[i].setVisible(true); if (p.getType().equals("int")) { final JSlider s = paramSliders[i]; int max = Integer.parseInt(p.getMaxValue()); s.setMaximum(max); int min = Integer.parseInt(p.getMinValue()); s.setMinimum(min); int range = max - min; int major = 1; while (major < range) major *= 10; s.setMajorTickSpacing(major / 10); s.setMinorTickSpacing(major / 100); System.out.println("major " + major); s.setPaintTicks(true); s.setPaintLabels(true); s.setValue(Integer.parseInt(p.getDefaultValue())); } else if (p.getType().equals("float")) { final float min = Float.valueOf(p.getMinValue()).floatValue(); final float max = Float.valueOf(p.getMaxValue()).floatValue(); final float width = max - min; final Parameter param = p; final JSlider s = paramSliders[i]; float fval = Float.valueOf(p.getDefaultValue()).floatValue(); param.setValue(fval); s.setMinimum(0); s.setMaximum(1000); s.setValue((int) ((fval - min) / width * 1000)); java.util.Hashtable labels = new java.util.Hashtable(3); labels.put(new Integer(0), new JLabel(p.getMinValue())); labels.put(new Integer(500), new JLabel(new Float((max + min) / 2.0f). toString())); labels.put(new Integer(1000), new JLabel(p.getMaxValue())); s.setLabelTable(labels); s.setPaintTicks(false); s.setPaintLabels(true); // s.setBorder(new TitledBorder("border text")); s.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { int j = s.getValue(); float f = min + (j * width / 1000.0f); param.setValue(f); } }); } else { System.out.println("Expected int or float in " + i + " |" + p.getType() + "|"); } if (numParams > 1) { paramSliders[i].setOrientation(JSlider.HORIZONTAL); } else { paramSliders[i].setOrientation(JSlider.HORIZONTAL); } paramSliders[i].setVisible(true); } } public void playSound() { boolean isSal = mainFrame.jScrollPane.isSal; /* debugging System.out.println("isSal: " + isSal + "\n" + currentInstr.getFunctionName() + "\nSal: " + currentInstr.getSalImplementation() + "\nLisp: " + currentInstr.getLispImplementation() + "\nReq: " + currentInstr.getRequire()); end debugging */ String cmd = (isSal ? "play " : "(play (") + currentInstr.getFunctionName(); String sep = (isSal ? ", " : " "); if (isSal) cmd = cmd + "("; boolean first = isSal; for (int i = 0; i < currentInstr.getParameters().size(); i++) { Parameter p = (Parameter) currentInstr.getParameters().get(i); // is this a keyword parameter? If so, put it in if (p.getName().charAt(0) == ':') { if (!first) cmd = cmd + sep; cmd = cmd + p.getName(); first = false; } String actual; if (p.getType().equals("int")) { actual = new Integer(paramSliders[i].getValue()).toString(); } else if (p.getType().equals("float")) { actual = new Float(p.getValue()).toString(); } else { actual = ""; System.out.println("bad parameter type"); } if (!first) cmd = cmd + sep; first = false; cmd = cmd + actual; } if (!isSal) cmd = cmd + ")"; // to match (play cmd = cmd + ")\n"; String impl = (isSal ? currentInstr.getSalImplementation() : currentInstr.getLispImplementation()); if (impl == null && currentInstr.getRequire() != null) { impl = currentInstr.getRequire(); if (isSal) { impl = "if ! fboundp(quote(" + currentInstr.getFunctionName() + ")) then load " + impl + "\n"; } else { impl = "(if (not (fboundp '" + currentInstr.getFunctionName() + ")) (load " + impl + "))\n"; } } if (impl != null) { if (isSal) { // for SAL, need one command cmd = "begin\n " + impl + " " + cmd + "end\n"; } else { cmd = impl + cmd; // lisp can take sequence of commands } } cmd = cmd + "\n"; // need extra newline to cause parser to run expArea.setText(cmd); mainFrame.sendInput(cmd); } } nyquist-3.05/jnyqide/SpecialMacHandler.java0000644000175000000620000000415511466723256020011 0ustar stevestaffpackage jnyqide; import jnyqide.*; import com.apple.eawt.ApplicationAdapter; import com.apple.eawt.ApplicationEvent; import com.apple.eawt.Application; /* import com.apple.mrj.*; */ import javax.swing.SwingUtilities; /* OLD CODE -- the MRJ classes are deprecated. public class SpecialMacHandler implements MRJQuitHandler, MRJPrefsHandler, MRJAboutHandler { MainFrame us; public SpecialMacHandler(jnyqide.MainFrame theProgram) { us = theProgram; System.setProperty("com.apple.macos.useScreenMenubar", "true"); System.setProperty("com.apple.mrj.application.apple.menu.about.name", "jNyqIDE"); MRJApplicationUtils.registerAboutHandler(this); MRJApplicationUtils.registerPrefsHandler(this); MRJApplicationUtils.registerQuitHandler(this); System.out.println("\n\n\nRegistered handlers for Mac Application Menu\n\n\n"); } public void handleAbout() { us.About(); } public void handlePrefs() { us.Prefs(); } public void handleQuit() { System.out.println("handleQuit in SpecialMacHandler.java called"); SwingUtilities.invokeLater(new Runnable() { public void run() { us.Quit(); } }); throw new IllegalStateException("Let the quit handler do it"); } } */ public class SpecialMacHandler extends ApplicationAdapter { MainFrame us; public SpecialMacHandler(jnyqide.MainFrame theProgram) { System.out.println("SpecialMacHandler created"); us = theProgram; Application app = Application.getApplication(); app.addApplicationListener(this); app.setEnabledPreferencesMenu(true); } public void handleAbout(ApplicationEvent e) { e.setHandled(true); us.About(); } public void handlePreferences(ApplicationEvent e) { us.Prefs(); } public void handleQuit(ApplicationEvent e) { System.out.println("handleQuit in SpecialMacHandler called"); SwingUtilities.invokeLater(new Runnable() { public void run() { us.Quit(); } }); } } nyquist-3.05/jnyqide/help.gif0000644000175000000620000000016610144436365015256 0ustar stevestaffGIF89a!,@;8D"%p8X WdՅqߧ:pa繢݈-#2齆ԊRF]$;nyquist-3.05/jnyqide/PlotMouseAdapter.java0000644000175000000620000000233011466723256017733 0ustar stevestaffpackage jnyqide; import javax.swing.event.MouseInputAdapter; import java.awt.event.MouseEvent; import javax.swing.*; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ public class PlotMouseAdapter extends MouseInputAdapter { int dx, dy; int startx, starty; int shiftx, shifty; boolean shifting; PlotFrame frame; public PlotMouseAdapter(PlotFrame f) { dx = 0; dy = 0; shiftx = 0; shifty = 0; shifting = false; frame = f; } public void mouseDragged(MouseEvent e) { System.out.println("mouseDragged"); if (!shifting) { shifting = true; startx = e.getX(); starty = e.getY(); } dx = e.getX() - startx; dy = e.getY() - starty; frame.repaint(); } public void mouseClicked( MouseEvent e ) { } public void mouseReleased( MouseEvent e ) { shiftx += dx; shifty += dy; shifting = false; } public int getShiftX() { return shiftx+dx; } public int getShiftY() { return shifty+dy; } }nyquist-3.05/jnyqide/Main.java0000644000175000000620000000413111466723256015370 0ustar stevestaffpackage jnyqide; import javax.swing.UIManager; import java.awt.*; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ public class Main { boolean packFrame = false; //Construct the application public Main() { String osName = System.getProperty("os.name"); System.out.println(osName); if (osName.startsWith("Linux")) { // motif style has some extra buttons to iconify internal frames // but this obscures windows, and metal looks better anyway try { UIManager.setLookAndFeel( "javax.swing.plaf.metal.MetalLookAndFeel"); } catch (Exception e) { System.out.println(e); } } MainFrame frame = new MainFrame(); //Validate frames that have preset sizes //Pack frames that have useful preferred size info, e.g. from their layout if (packFrame) { frame.pack(); } else { frame.validate(); } //Center the window Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); // subtract 20 here because otherwise Mac OS X frames will be too tall // to access resize nbutton System.out.print("initial frame height "); System.out.println(frameSize.height); System.out.print("screen height "); System.out.println(screenSize.height); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height - 40; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } System.out.print("finall frame height "); System.out.println(frameSize.height); frame.setSize(frameSize); frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); frame.setVisible(true); frame.tileCompletion(); } //Main method public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch(Exception e) { e.printStackTrace(); } new Main(); } } nyquist-3.05/jnyqide/SpringUtilities.java0000644000175000000620000001767611466723256017664 0ustar stevestaffpackage jnyqide; import javax.swing.*; import javax.swing.SpringLayout; import java.awt.*; /** * A 1.4 file that provides utility methods for * creating form- or grid-style layouts with SpringLayout. * These utilities are used by several programs, such as * SpringBox and SpringCompactGrid. */ public class SpringUtilities { /** * A debugging utility that prints to stdout the component's * minimum, preferred, and maximum sizes. */ public static void printSizes(Component c) { System.out.println("minimumSize = " + c.getMinimumSize()); System.out.println("preferredSize = " + c.getPreferredSize()); System.out.println("maximumSize = " + c.getMaximumSize()); } /** * Aligns the first rows * cols * components of parent in * a grid. Each component is as big as the maximum * preferred width and height of the components. * The parent is made just big enough to fit them all. * * @param rows number of rows * @param cols number of columns * @param initialX x location to start the grid at * @param initialY y location to start the grid at * @param xPad x padding between cells * @param yPad y padding between cells */ public static void makeGrid(Container parent, int rows, int cols, int initialX, int initialY, int xPad, int yPad) { SpringLayout layout; try { layout = (SpringLayout)parent.getLayout(); } catch (ClassCastException exc) { System.err.println("The first argument to makeGrid must use SpringLayout."); return; } Spring xPadSpring = Spring.constant(xPad); Spring yPadSpring = Spring.constant(yPad); Spring initialXSpring = Spring.constant(initialX); Spring initialYSpring = Spring.constant(initialY); int max = rows * cols; //Calculate Springs that are the max of the width/height so that all //cells have the same size. Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)). getWidth(); Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)). getWidth(); for (int i = 1; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints( parent.getComponent(i)); maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth()); maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight()); } //Apply the new width/height Spring. This forces all the //components to have the same size. for (int i = 0; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints( parent.getComponent(i)); cons.setWidth(maxWidthSpring); cons.setHeight(maxHeightSpring); } //Then adjust the x/y constraints of all the cells so that they //are aligned in a grid. SpringLayout.Constraints lastCons = null; SpringLayout.Constraints lastRowCons = null; for (int i = 0; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints( parent.getComponent(i)); if (i % cols == 0) { //start of new row lastRowCons = lastCons; cons.setX(initialXSpring); } else { //x position depends on previous component cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST), xPadSpring)); } if (i / cols == 0) { //first row cons.setY(initialYSpring); } else { //y position depends on previous row cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH), yPadSpring)); } lastCons = cons; } //Set the parent's size. SpringLayout.Constraints pCons = layout.getConstraints(parent); pCons.setConstraint(SpringLayout.SOUTH, Spring.sum( Spring.constant(yPad), lastCons.getConstraint(SpringLayout.SOUTH))); pCons.setConstraint(SpringLayout.EAST, Spring.sum( Spring.constant(xPad), lastCons.getConstraint(SpringLayout.EAST))); } /* Used by makeCompactGrid. */ private static SpringLayout.Constraints getConstraintsForCell( int row, int col, Container parent, int cols) { SpringLayout layout = (SpringLayout) parent.getLayout(); Component c = parent.getComponent(row * cols + col); return layout.getConstraints(c); } /** * Aligns the first rows * cols * components of parent in * a grid. Each component in a column is as wide as the maximum * preferred width of the components in that column; * height is similarly determined for each row. * The parent is made just big enough to fit them all. * * @param rows number of rows * @param cols number of columns * @param initialX x location to start the grid at * @param initialY y location to start the grid at * @param xPad x padding between cells * @param yPad y padding between cells */ public static void makeCompactGrid(Container parent, int rows, int cols, int initialX, int initialY, int xPad, int yPad) { SpringLayout layout; try { layout = (SpringLayout)parent.getLayout(); } catch (ClassCastException exc) { System.err.println("The first argument to makeCompactGrid must use SpringLayout."); return; } //Align all cells in each column and make them the same width. Spring x = Spring.constant(initialX); for (int c = 0; c < cols; c++) { Spring width = Spring.constant(0); for (int r = 0; r < rows; r++) { width = Spring.max(width, getConstraintsForCell(r, c, parent, cols). getWidth()); } for (int r = 0; r < rows; r++) { SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols); constraints.setX(x); constraints.setWidth(width); } x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); } //Align all cells in each row and make them the same height. Spring y = Spring.constant(initialY); for (int r = 0; r < rows; r++) { Spring height = Spring.constant(0); for (int c = 0; c < cols; c++) { height = Spring.max(height, getConstraintsForCell(r, c, parent, cols). getHeight()); } for (int c = 0; c < cols; c++) { SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols); constraints.setY(y); constraints.setHeight(height); } y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); } //Set the parent's size. SpringLayout.Constraints pCons = layout.getConstraints(parent); pCons.setConstraint(SpringLayout.SOUTH, y); pCons.setConstraint(SpringLayout.EAST, x); } } nyquist-3.05/jnyqide/Piano_Roll.java0000755000175000000620000011024711466723256016553 0ustar stevestaff/* * Ming Yang Koh (mykoh@andrew.cmu.edu) * Eugene Ang (ewee@andrew.cmu.edu) * Priscilla (cyp@andrew.cmu.edu) * * PianoRoll application which takes in an array of strings * and creates a graphical representation of a piano roll * */ /* SOME NOTES BY ROGER B. DANNENBERG: This software is not ready for real use. Some problems include: 1) there's no way to zoom in on scores or scroll the score view 2) there's no display of pitch information 3) there's no way to edit anything but pitch and time 4) there's no way to copy a note and its attributes, so any new note will lack attributes that might be necessary 5) there's no color coding of note types, e.g. instrumentation 6) everytime you modify the score, the score is written to a file; instead the file should be written explicitly 7) when the file is written, you should tell Nyquist to evaluate (score-restore) to read in the score and assign it to the global variable it came from 8) the score write command probably does not put the score name (a lisp variable name) as the first line 9) it looks like there's one representation for the score data as read from the file and another for a display list -- this should be simplified to one structure with accessor methods if necessary to translate into different representation for display 10) the score window should be resizable 11) should the score window be a subwindow to the jNyqIDE main window? How does it work? See xm.lsp for SCORE-EDIT, the function that you call to open a score editor, and SCORE-RESTORE, the function this editor should call to return score data to Nyquist. Also see NyquistThread.java for code that opens the score editor. Look for "score-edit: writing " around line 230. */ package jnyqide; import java.io.*; import java.awt.event.MouseListener; import java.awt.event.MouseEvent; import java.awt.event.WindowListener; import java.awt.event.WindowEvent; import java.awt.*; import javax.swing.*; import java.util.StringTokenizer; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class Piano_Roll { // global variable to store the String // for the time being, the Invariant will be, each String will // contain 3 ints: x, y, and duration. // let user click and select centre left or right. center is to move to new location // left and right is for user to drag along the axis // start of global variables in Piano_Roll class static ScoreManipulator sm = new ScoreManipulator(); static Piano_Roll.ScoreManipulator.Event[] inputArray = new Piano_Roll.ScoreManipulator.Event[0]; static int currentOption = 2; // 0 = add, 1 = delete, 2 = arrange //static Piano_Roll.ScoreManipulator.Event[] inputArray = new Piano_Roll.ScoreManipulator.Event[0]; static String filename; static String scoreName; // START OF BAOPANEL CLASS static class BaoPanel extends JPanel implements MouseListener { private static final long serialVersionUID = 1L; // for dragNotStretch : 0 = drag, 1 = stretch from // left(change start time), 2 = stretch from right(change dur) private int dragNotStretch; private int pitchStartCoord = 500, pitchHeight = 10, WINDOWWIDTH = 1024, maxClickableWidth = 946, lengthUnit = 3; /* * each box shown on screen is 3 pixels wide * each box represents 0.1 seconds * the screen will hold approximately 90 seconds of music */ private int selectedIndex = -1, lastClickedX; /*drawing horizontal lines of grid * if pitchHeight is 10, then there will be... * 49 segments. 49 pitches + 1 pitchless * A1 to G7 */ // START OF PAINTCOMPONENT FUNCTION TO DRAW OUT THE SCREEN protected void paintComponent (Graphics g) { int inputArrayLength = inputArray.length; int tempX, tempY, tempDur; super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; Color oldColor = g2.getColor(); g2.setColor(Color.BLACK); // drawing horizontal lines of grid for(int i=20; i <= pitchStartCoord; i+= pitchHeight){ g2.draw3DRect(0, i-10, WINDOWWIDTH, pitchHeight, false); } /* drawing vertical lines of grid, * as well as the blue vertical markers * to mark out every second */ for(int i=0, j=0; i <= WINDOWWIDTH; i += lengthUnit, j++){ if(j == 15){ g2.setColor(Color.BLUE); g2.draw3DRect(i, 10, 1, pitchStartCoord, false); j = 0; g2.setColor(Color.BLACK); } g2.draw3DRect(i, 10, lengthUnit, pitchStartCoord, false); } g2.setColor(Color.BLUE); //drawing the notes onto the grid for(int i = 0; i < inputArrayLength; i++){ tempX = inputArray[i].getTime(); tempY = pitchHeight * (inputArray[i].getPitch()); tempDur = inputArray[i].getDur(); /* the lowest pitch starts from bottom * need to check if its zero, if so, then plot it in special area. * this for loop is also responsible to draw the yellow sides * for user to recognise that its the area for stretching notes */ if(tempY != 0) { g2.fill3DRect(tempX+lengthUnit, (tempY+10), (tempDur-(2*lengthUnit)), 10, false); g2.setColor(Color.YELLOW); g2.fill3DRect(tempX, (tempY+10), lengthUnit, 10, false); g2.fill3DRect((tempX+tempDur-lengthUnit), (tempY+10), lengthUnit, 10, false); g2.setColor(Color.BLUE); } else{ g2.setColor(Color.BLACK); g2.fill3DRect(tempX, (tempY+10), tempDur, 10, false); g2.setColor(Color.BLUE); } } // setting back colour to prevent future // screw-ups, eg, the border colours etc.. g2.setColor(oldColor); addMouseListener(this); } // START OF DETERMINEACTION FUNCTION FOR DIFFERENTIATING // DRAG AND STRETCH.. private void determineAction(MouseEvent e){ int arraySize = inputArray.length; for(int i = 0; i < arraySize; i++){ if(inputArray[i].checkWithinDuration(e.getX(), e.getY())){ selectedIndex = i; dragNotStretch = inputArray[i].checkDragNotStretch(e.getX(), e.getY()); return; } } } /* whenever theres a change in the array, * 1) change the array, * 2) as well as call the function to notify's eugene's part */ /* * START OF MOUSELISTENERS * RESPONSIBLE FOR ALL THE USER INPUTS/CHANGES * TO THE SCORE */ /* * mouseReleased basically first differentiates * different actions before doing anthing, that * refers to: add, delete or drag/stretch * * then, it will proceed to do the specifed action * within the case of drag/stretch, then the code * will differentiate drag or stretch and proceed * on respectively * * the check of selectedIndex != -1 ensures the user * is operating on a certain notes. * */ public void mouseReleased(MouseEvent e) { // *** IF DRAG/STRETCH if(currentOption == 2){ /* * the following are done in drag/stretch action: * a)ensure that bounds are kept, ie no * notes are dragged out of the screen, or * 'dragged into itself..' * b)changing the Event in the array and subsequently * send it to the score through the changeScore, * add_Event or delete_Event functions * */ if(selectedIndex != -1){ int originalTime = inputArray[selectedIndex].getTime(), originalDur = inputArray[selectedIndex].getDur(), newX = e.getX(), newY = e.getY(); if(newX >= maxClickableWidth){ selectedIndex = -1; return; } // *** DRAG action if(dragNotStretch == 0){ int originalPitch = inputArray[selectedIndex].getPitch(); int newStartTime = newX - lastClickedX + originalTime; int newPitch = ((newY-10)/10); if(newStartTime + inputArray[selectedIndex].getDur() >= maxClickableWidth){ selectedIndex = -1; return; } if((originalPitch == 0) && (((newY - 10)/10) != 0)){ selectedIndex = -1; return; } // the following ensures the notes stay within bounds if(newStartTime < 0) newStartTime = 0; if(newPitch > 49) newPitch = 49; else if(newPitch < 0) newPitch = 1; inputArray[selectedIndex].setStartTime(newStartTime); inputArray[selectedIndex].setPitch(newPitch); } else if(dragNotStretch == 1){ // stretch from left if(newX > originalTime + originalDur - 12) newX = originalTime + originalDur - 12; inputArray[selectedIndex].setDur( originalDur + originalTime - newX); inputArray[selectedIndex].setStartTime(newX); } else { // stretch from right if(newX < originalTime + 12) newX = originalTime + 12; inputArray[selectedIndex].setDur(newX - originalTime); } //sends the data back to The middleman to send it back to nyquist inputArray = sm.my_score.changeScore( inputArray[selectedIndex].getIndex(), inputArray[selectedIndex].getTime(), inputArray[selectedIndex].getDur(), inputArray[selectedIndex].getPitch()); repaint(); revalidate(); selectedIndex = -1; //end of drag or stretch. selectedIndex back to -1.. sm.writeFile(); } } // *** IF DELETE else if(currentOption == 1){ if(selectedIndex != -1){ inputArray = sm.my_score.del_Event(inputArray[selectedIndex]); repaint(); revalidate(); //at end. selectedIndex back to -1 selectedIndex = -1; sm.writeFile(); return; } } // *** IF ADD else if(currentOption == 0){ int tempY = (e.getY()-10)/10; if((e.getX() + 20) > maxClickableWidth){ return; } if( !(tempY <= 49 && tempY >=0)){ return; } inputArray = sm.my_score.add_Event(new Piano_Roll.ScoreManipulator.Event(e.getX(), tempY, 20 , -1)); repaint(); revalidate(); //at end. selectedIndex back to -1 selectedIndex = -1; sm.writeFile(); return; } } /* * mousePressed just does 2 things * a) determine if its a drag or stretch action, * as well as determining the Event manipulated * b) logging down te x-coordinate of the click, * for use of dragging nicely later */ public void mousePressed(MouseEvent e) { determineAction(e); lastClickedX = e.getX(); } public void mouseEntered(MouseEvent e) {/* do nothing*/} public void mouseExited(MouseEvent e) { /* do nothing*/} public void mouseClicked(MouseEvent e) { /* do nothing*/} } /* * addComponentsToPane function deals with the layout * and components outside the grid, such as text, buttons * and xaxis and yaxis scales.. * */ public static void addComponentsToPane (Container pane) { // zero is center alignment.... // can use HTML ways to edit the font/type JLabel topLabel = new JLabel("" + "Piano roll display:", 0); JLabel bottomLabel = new JLabel( "
    • To stretch, " + "click on the yellow sections of notes
    • To transpose," + " click on blue section of notes
    ", 0); topLabel.setPreferredSize(new Dimension(1024, 50)); JLabel leftPanel = new JLabel(); JLabel bottomCenterLabel = new JLabel(); ImageIcon xAxis = new ImageIcon("xAxis.jpg"); ImageIcon yAxis = new ImageIcon("xxx.jpg"); bottomCenterLabel.setIcon(xAxis); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); // for center panel JPanel subCenterPanel = new BaoPanel(); mainPanel.add(bottomCenterLabel, BorderLayout.SOUTH); mainPanel.add(subCenterPanel, BorderLayout.CENTER); // for left panel leftPanel.setIcon(yAxis); leftPanel.setPreferredSize(new Dimension(30, 800)); //for bottom panel JPanel bottomPanel = new JPanel(); JPanel subBottomPanel = new JPanel(); bottomPanel.setLayout(new BorderLayout()); // setting up the buttons, and adding listeners JButton okButton = new JButton("Add"); JButton deleteButton = new JButton("Delete"); JButton arrangeButton = new JButton("Drag/Stretch"); okButton.addActionListener(new okButtonListener( okButton, deleteButton, arrangeButton)); deleteButton.addActionListener(new deleteButtonListener( okButton, deleteButton, arrangeButton)); arrangeButton.addActionListener(new arrangeButtonListener( okButton, deleteButton, arrangeButton)); arrangeButton.setEnabled(false); subBottomPanel.setLayout(new FlowLayout()); subBottomPanel.add(okButton); subBottomPanel.add(deleteButton); subBottomPanel.add(arrangeButton); // combining the 2 sub panels together to form the bottomPanel bottomPanel.add(bottomLabel, BorderLayout.CENTER); bottomPanel.add(subBottomPanel, BorderLayout.EAST); JLabel fillerLabel2 = new JLabel(""); fillerLabel2.setSize(10, 600); fillerLabel2.setVisible(true); // combining all the panels together to // form the bulk of the screen pane.add(topLabel, BorderLayout.NORTH); pane.add(mainPanel, BorderLayout.CENTER); pane.add(bottomPanel, BorderLayout.SOUTH); pane.add(leftPanel, BorderLayout.WEST); pane.add(fillerLabel2, BorderLayout.EAST); } /* * below are the 3 listener classes that deal with the 3 main * operations: add, delete, drag/drop. * * what they do is to initialise the buttons and to set * the respective buttons to become enabled/disabled * when clicked. * * the MouseReleased function will deal with user inputs * eg, drags or deletes instead of the listeners below * */ private static class okButtonListener implements ActionListener { private JButton ok, delete, arrange; public okButtonListener(JButton ok, JButton delete, JButton arrange){ this.ok = ok; this.delete = delete; this.arrange = arrange; } public void actionPerformed(ActionEvent e){ currentOption = 0; ok.setEnabled(false); delete.setEnabled(true); arrange.setEnabled(true); } } private static class deleteButtonListener implements ActionListener { private JButton ok, delete, arrange; public deleteButtonListener(JButton ok, JButton delete, JButton arrange){ this.ok = ok; this.delete = delete; this.arrange = arrange; } public void actionPerformed(ActionEvent e){ currentOption = 1; ok.setEnabled(true); delete.setEnabled(false); arrange.setEnabled(true); } } private static class arrangeButtonListener implements ActionListener { private JButton ok, delete, arrange; public arrangeButtonListener(JButton ok, JButton delete, JButton arrange){ this.ok = ok; this.delete = delete; this.arrange = arrange; } public void actionPerformed(ActionEvent e){ currentOption = 2; ok.setEnabled(true); delete.setEnabled(true); arrange.setEnabled(false); } } /** * Create the GUI and show it. For thread safety, * this method should be invoked from the * event-dispatching thread. */ private static void createAndShowGUI() { //Create and set up the window. JFrame.setDefaultLookAndFeelDecorated(true); JFrame frame = new JFrame("Piano Bao : by Priscilla, Eugene and Damon. "); frame.setResizable(false); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.addWindowListener(new prepareToComeBackListener()); //Set up the content pane. //frame is the most most outermost enclosure frame.getContentPane().setLayout(new BorderLayout()); addComponentsToPane(frame.getContentPane()); //Display the window, crops off exactly where the grid stops printing frame.setSize(984, 672); frame.setVisible(true); } public static void scoreEdit(String scoresaveFilename) { //Schedule a job for the event-dispatching thread: //creating and showing this application's GUI. if (scoresaveFilename == null) { System.out.println("Error. No file argument."); return; } filename = scoresaveFilename; try { BufferedReader in = new BufferedReader(new FileReader(filename)); scoreName = in.readLine(); String str; //make score object while ((str = in.readLine()) != null) { sm.my_score.addNote(sm.makeNote(str)); } in.close(); //parse it to Event list, for GUI functions inputArray = sm.my_score.toEventList(); } catch (IOException e) { System.out.println("IOException caught: " + e.getMessage()); } javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } private static class prepareToComeBackListener implements WindowListener{ public void windowActivated(WindowEvent e){} public void windowClosed(WindowEvent e){ currentOption = 2; } public void windowClosing(WindowEvent e){/*do nothing*/} public void windowDeactivated(WindowEvent e){/*do nothing*/} public void windowDeiconified(WindowEvent e){/*do nothing*/} public void windowIconified(WindowEvent e){/*do nothing*/} public void windowOpened(WindowEvent e){/*do nothing*/} } // This is a data structure that stores and // changes notes from a Nyquist score. It // nests another data structure, ScoreNote. public static class ScoreManipulator { public ScoreNote my_score; // a collection of notes, with functions to // add, delete and change the collection. public ScoreManipulator() { my_score = new ScoreNote(); } // takes in a String of the following format: // start_time duration pitch option_str1 ... option_strn // and parses it into a Note object. public Note makeNote(String str) { int numTokens; StringTokenizer st = new StringTokenizer(str); if ( (numTokens = st.countTokens()) < 3) { System.out.println("ERROR in makeNote: some string too short: " + str); return null; } String st_time, dur, pitch; // the remainder of the string must be the options String []opts = new String[numTokens - 3]; int numOpts = 0; st_time = st.nextToken(); dur = st.nextToken(); pitch = st.nextToken(); while (st.hasMoreTokens()) { opts[numOpts] = st.nextToken(); numOpts++; } //System.out.println("st_time " + st_time + " dur " + dur + // " pitch " + pitch + " opts " + opts); double stime = Double.parseDouble(st_time); double duration = Double.parseDouble(dur); int ptch = -9999; if (!pitch.equals("NIL")) ptch = Integer.parseInt(pitch); return new Note(stime,duration,ptch,opts,numOpts); } public void writeFile() { try { FileWriter fwr = new FileWriter(filename); fwr.write(my_score.writeScore()); fwr.close(); } catch (IOException e) { System.out.println("writeFile: IOException."); } } // The Note class stores information about a Nyquist // score note such that it is easy to access the fields // that we need in this piano roll application. // Notice that the field pitch can be zero (0). public class Note { // fields private double start_time; // Note's starting time private double duration; private int pitch, numopts; private String []options; // all other information that the piano roll will // not use, but that we must preserve public Note(double st_time, double dur, int pitch, String []opts, int numopts) { start_time = st_time; duration = dur; this.pitch = pitch; this.numopts = numopts; options = opts; } //accessors public double get_start() { return start_time; } public double get_dur() { return duration; } public int get_pitch() { return pitch; } public int get_numopts() { return numopts; } public String [] get_opts() { return options; } // for debugging public void PrintNote() { System.out.print("Start: " + start_time + " Duration: " + duration + " Pitch: " + pitch); for (int i = 0; i < numopts; i++) { System.out.print(" Opt string " + i + ": " + options[i]); } System.out.println(); } } // ScoreNote is a collection of notes. // It also has a collection of functions // such as add, delete and change that // is used by the GUI functions to change // the score when the user drags/shifts/adds/ // deletes notes. public class ScoreNote { private Note[] score; // the collection of notes private int num_notes; // capacity of the score private int notes_used; // number of notes in the // collection that are // presently non-empty. public ScoreNote() { num_notes = 0; notes_used = 0; score = new Note[0]; } //adds a Note to the data structure sorted //in order of start time. //Invariant: score starts out sorted. This is //true at the start => invariant is preserved //each time we call this public void addNote(Note newnote) { // If there exists a note in the score of the exact // pitch duration and start time, then don't add it // in. for(int j = 0; j < notes_used; j++) { if(score[j].get_start() == newnote.get_start() && score[j].get_pitch() == newnote.get_pitch() && score[j].get_dur() == newnote.get_dur()){ return; } } if (notes_used >= num_notes) { if (notes_used == 0) { score = new Note[10]; num_notes = 10; } else { Note [] tempscore = new Note[num_notes * 2]; for (int i = 0; i < notes_used; i++) { tempscore[i] = score[i]; } score = tempscore; num_notes *= 2; } } for (int i = 0; i < notes_used; i++) { // when we find the index that newnote should be in, // place it there and return if (score[i].get_start() >= newnote.get_start()) { shift_right(i); score[i] = newnote; notes_used++; return; } } // otherwise, newnote's start time is // the largest in the score, and we // put it at the back of the array. score[notes_used] = newnote; notes_used++; } // shifts all notes in the array after and including // index by one to the right. public void shift_right(int index) { for (int i = notes_used - 1; i >= index; i--) { score[i+1] = score[i]; } } // deletes the note specified by index from the score // while maintaining the invariant that notes in score // are sorted by start time. public void delNote(int index) { if (index < 0 || index >= notes_used) { System.out.println("del_note: Error! index out of bounds!"); return; } shift_left(index); notes_used--; } // shifts all notes in score after // index by one to the left. public void shift_left(int index) { for (int i = index; i < notes_used; i++) { score[i] = score[i+1]; } } // accessor for number of used notes in the score public int getLength() { return notes_used; } // accessor for a note at the particular index public Note getNote(int index) { if (index < 0 || index >= notes_used) { System.out.println("getNote: trying to index note out of bounds!"); return null; } return score[index]; } // makes an incremental change to the score, but makes sure to // preserve the invariant that score remains sorted by start time. public Event[] changeScore(int index, int new_start, int new_dur, int new_pitch) { if (index < 0 || index >= notes_used) { System.out.println("changeScore: index out of bounds!"); return null; } // make the new note Note note = new Note( (double)(new_start / 10), (double)(new_dur / 10), convertPitch(new_pitch), score[index].get_opts(), score[index].get_numopts() ); // delNote and addNote both preserve the invariant that // the notes in score are sorted in order of start time. delNote(index); addNote(note); // add one more layer of abstraction for the convenience of // the GUI functions, by using Event objects rather than // Note objects. The difference is basically in the standards // of time and note values, documented below. return toEventList(); } // converts from a MIDI note to a note in // our representation and vice versa. public int convertPitch(int pitch) { if (pitch == 0) return pitch; return 84 - (pitch - 1); } // Gets the list for the GUI functions to manipulate. // Invariant: the size of the event list returned is // exactly the number of notes in our score. public Event [] toEventList() { Event [] result = new Event[notes_used]; int num_events = 0; for (int i = 0; i < notes_used; i++) { Note temp = score[i]; // Note: we multiply by 10 for convenience of computation, // as Event stores time and duration as integers, not doubles. int start = (int)(temp.get_start() * 10); int dur = (int)(temp.get_dur() * 10); Event new_event = new Event(start,convertPitch(temp.get_pitch()),dur,i); result[i] = new_event; num_events++; } // size the array return shape_Event_List(result,num_events); } // The original event list may have some redundant // blank entries at the end. We use this shape_Event_List // to size it nicely to the number of events that are actually // needed. public Event [] shape_Event_List(Event [] original, int num_events) { if (original == null) { System.out.println("shape_Event_List: null array given."); return null; } Event [] result = new Event [num_events]; for (int i = 0; i < num_events; i++) { result[i] = original[i]; } return result; } // When the user clicks to add a new note, // this function is called to add an event into the // existing Event array. public Event [] add_Event(Event e) { // create new note String [] def_string = new String[1]; def_string[0] = "(NOTE)"; Note newnote = new Note(e.getTime()/10, e.getDur()/10, convertPitch(e.getPitch()), def_string, 1); // add it to score addNote(newnote); // return new list of events return toEventList(); } // When user clicks to delete a note from // the piano roll, this function is called // to cleanly remove the event, maintaining // the invariant that the notes in score are // sorted in order of start time. public Event [] del_Event(Event e) { delNote(e.getIndex()); return toEventList(); } // This function outputs a string // that represents the score // in the format of the default file // from which we parsed the original score public String writeScore() { String result = scoreName + "\n"; for (int i = 0; i < notes_used; i++) { result += Double.toString(score[i].get_start()); result += " "; result += Double.toString(score[i].get_dur()); result += " "; if (score[i].get_pitch() == -9999) result += "NIL"; else result += Integer.toString(score[i].get_pitch()); for (int j = 0; j < score[i].get_numopts(); j++) { result += " "; result += (score[i].get_opts())[j]; } result += "\n"; } return result; } // debugging function public void PrintScore() { System.out.println("Printing Score.."); System.out.println("Variables: notes_used = " + notes_used + " num_notes = " + num_notes); for (int i = 0; i < notes_used; i++) { Note temp = getNote(i); temp.PrintNote(); } System.out.println("Done Printing Score!"); } } /* the Event class, which defines a stretch of note on the piano roll 15-392 - Pianobao project Most of the fields in the Event object are derived from those in the Note class. The GUI functions use Events as the representation of the actual Note, for simplicity. For example, start time and duration are ints in Event but are doubles in Note. Also, the values of start time and duration are 10 times larger than its counterparts in Note because the scaling prevents the notes from being too small in the piano roll picture. Another point to note is that the pitch in Event is not in standard MIDI format, while that in Note is. This is because it was easier to use a range of 0-49 (these are graphical coordinates) when plotting the pitch-axis in a GUI, and this range corresponds to the MIDI pitches 36-84 (C2 -> C4). The index field the index of the array in which this Event resides. This is for book-keeping purposes. the values stored in this Event object is a graphical location on the interface. A set of value converters will parse these coordinates into actual musical values when we need to update the score in Nyquist. */ public static class Event { private int time, pitch, dur, index; public Event(int startTime, int givenPitch, int duration, int index) { time = startTime; pitch = givenPitch; dur = duration; this.index = index; } public Event(int startTime, int givenPitch) { time = startTime; pitch = givenPitch; dur = 1; } /* checks whether the given x and y coordiante is within this particular event 20 is the pitchHeight. Basically works by checking whether the coordinates clicked is within the rectangle of the Event on screen */ public boolean checkWithinDuration(int timeX, int pitchY) { return (((pitchY) <= ((pitch*10) + 20 )) && (pitchY >= ((10*pitch) + 10)) && (timeX >= time) && (timeX <= (time + dur)) ); } // uses coordinates of user's click to determine whether // user intends to drag the note or stretch its duration. // returns : 0 if drag, // 1 if stretch from left, // 2 if stretch from right (change dur) public int checkDragNotStretch(int timeX, int pitchY) { if ((timeX <= (time+3)) && (timeX >= time)) { return 1; } if ((timeX <= (time + dur)) && (timeX >= dur + time - 3)){ return 2; } return 0; } //accessors public int getTime() { return time; } public int getPitch() { return pitch; } public int getDur() { return dur; } public int getIndex() { return index; } //mutators public void editEvent(int startTime, int givenPitch, int duration) { time = startTime; pitch = givenPitch; dur = duration; return; } public void setDur(int duration) {dur = duration;} public void setStartTime(int startTime) {time = startTime;} public void setPitch(int newPitch) {pitch = newPitch;} public void setIndex(int newIndex) {index = newIndex;} public String toString(){ return "Event of Pitch: " + pitch + " , start time = " + time + " , duration = " + dur + ", index = " + index + "\n"; } } // end of Event class } } nyquist-3.05/jnyqide/MainFrame.java0000644000175000000620000017167111537224066016353 0ustar stevestaffpackage jnyqide; import java.awt.*; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.*; import java.beans.*; import javax.swing.*; import javax.swing.text.*; import javax.swing.event.*; import javax.swing.undo.*; import javax.swing.text.html.*; // import javax.swing.JOptionPane.*; import javax.swing.filechooser.FileFilter; import java.io.*; import jnyqide.*; // this won't work on non-Mac, so use reflection tricks below // import com.apple.mrj.*; // import Mac menu support import java.lang.reflect.*; // import Constructor class import java.util.prefs.*; import java.util.Collection; import java.net.URL; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ class ScrollUpdate implements Runnable { MainFrame frame; ScrollUpdate(MainFrame mainframe) { frame = mainframe; } public void run() { frame.ScrollToEnd(); } } public class MainFrame extends JFrame { JPanel contentPane; JMenuBar jMenuBar1 = new JMenuBar(); JMenu jMenuFile = new JMenu(); JMenu jMenuEdit = new JMenu(); JMenu jMenuProcess = new JMenu(); JMenu jMenuWindow = new JMenu(); JMenu jMenuHelp = new JMenu(); JToolBar jToolBar = new JToolBar(); float test_value = 0.0F; ImageIcon image1; ImageIcon image2; ImageIcon image3; public JLabel statusBar = new JLabel(); JButton salLispButton; BorderLayout borderLayout1 = new BorderLayout(); JDesktopPane jDesktop; public CodePane jScrollPane; // accessed by CodePane sometimes: public JTextArea jOutputArea; JTextArea jListOutputArea; JScrollPane jOutputPane; JScrollPane jListOutputPane; JInternalFrame jOutputFrame; JInternalFrame jListOutputFrame; MiniBrowser miniBrowser; NyquistThread nyquistThread; JInternalFrame jFrame; // used by TextColor to communicate result back to MainFrame // public static boolean evenParens; String currentDir = ""; Runnable update = new ScrollUpdate(this); PlotFrame plotFrame; File homeDir = new File("."); public String findPattern = ""; public String replacePattern = ""; boolean packFrame = false; EnvelopeFrame envelopeEditor; /* BEGIN UPIC */ UPICFrame upicEditor; /* END UPIC */ Jslide eqEditor; public Preferences prefs; public static final boolean prefStartInSalModeDefault = true; public static final boolean prefSalShowLispDefault = false; public static final boolean prefParenAutoInsertDefault = false; public static final boolean prefEnableSoundDefault = true; public static final boolean prefAutoNormDefault = true; public static final boolean prefSalTraceBackDefault = true; public static final boolean prefSalBreakDefault = false; public static final boolean prefXlispBreakDefault = true; public static final boolean prefXlispTraceBackDefault = false; public static final boolean prefPrintGCDefault = false; public static final boolean prefFullSearchDefault = true; public static final boolean prefInternalBrowserDefault = false; public static final boolean prefOnlineManualDefault = false; public static final double prefCompletionListPercentDefault = 60.0; public static final String prefAudioRateDefault = "44100"; public static final String prefControlRateDefault = "2205"; public static final String prefFontSizeDefault = "12"; public static boolean prefStartInSalMode = prefStartInSalModeDefault; public static boolean prefSalShowLisp = prefSalShowLispDefault; public static boolean prefParenAutoInsert = prefParenAutoInsertDefault; public static boolean prefEnableSound = prefEnableSoundDefault; public static boolean prefAutoNorm = prefAutoNormDefault; public static boolean prefSalTraceBack = prefSalTraceBackDefault; public static boolean prefSalBreak = prefSalBreakDefault; public static boolean prefXlispBreak = prefXlispBreakDefault; public static boolean prefXlispTraceBack = prefXlispTraceBackDefault; public static boolean prefPrintGC = prefPrintGCDefault; public static boolean prefFullSearch = prefFullSearchDefault; public static boolean prefInternalBrowser = prefInternalBrowserDefault; public static boolean prefOnlineManual = prefOnlineManualDefault; public static double prefCompletionListPercent = prefCompletionListPercentDefault; public static String prefAudioRate = prefAudioRateDefault; public static String prefControlRate = prefControlRateDefault; public static String prefFontSize = prefFontSizeDefault; public static String prefDirectory = ""; public static String prefSFDirectory = ""; public static boolean prefsHaveBeenSet = false; public boolean workspaceLoaded = false; public boolean workspaceSaved = false; public static final String onlineManualURL = "http://www.cs.cmu.edu/~rbd/doc/nyquist/"; // inputStrings allows user to type ^P to get previous entry, // or ^D for next entry. This is tricky. The desired behavior is: // There is a history list of everything executed in order. // Typing ^P moves a cursor back in history, ^D forward. When you type // Enter, a new string is placed at the front of history, and the // cursor is set to the front of history as well. // To implement this behavior, inputStringsX is the front of history. // It wraps around when it reaches inputStringsLen. To be precise, // inputStringsX is the indeX of the location where the next input // string will go. inputStringsCursor is the position controlled // by ^P and ^D. inputSringsCursor is set // to inputStringsX when the user types Enter. // Sending input is tricky because you could be in Lisp or SAL mode. // Either way, you want to indent multi-line input by the prompt size // (2 for lisp, 4 for Sal) and you want an extra return after Sal // commands. You DO NOT want the last 2 returns to be followed by // spaces since SAL looks at the end of input to determine when a // command is complete. // // Use cases: // calling a function like replay (R): // use callFunction() // user types return after code in input box: // use SendInputLn // // Support functions: // callFunction -- build expression and call SendInputLn // setVariable -- build expression and call SendInputLn // SendInputLn -- fix up indentation, append newline or 2, SendInput // SendInput -- just send text to Nyquist int inputStringsX = 0; int inputStringsCursor = 0; int inputStringsLen = 20; String inputStrings[] = new String[inputStringsLen]; // some "features" for system dependent code public boolean hasRightMouseButton = true; //Construct the frame public MainFrame() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { mainFrameInit(); } catch(Exception e) { e.printStackTrace(); } } public boolean isMac() { // System.out.println("mrj.version" + System.getProperty("mrj.version")); // return System.getProperty("mrj.version") != null; // The code above seems not to work on Leopard; the following // suggested by Raymond Martin: final String strOS; try { strOS = System.getProperty("os.name"); } catch(final SecurityException e) { System.out.println("In isMac: error " + e); return(false); } System.out.println("strOS " + strOS); return(strOS.indexOf("Mac OS") >= 0); } PreferencesDialog preferencesDialog; public void disconnectPreferences() { preferencesDialog = null; } protected void setVariable(String var, String val) { String input; if (jScrollPane.isSal) { input = "set " + var + " = " + val; } else { input = "(setf " + var + " " + val + ")"; } sendInputLn(input); } String tOrNil(boolean val) { return (val ? "t" : "nil"); } protected void setBoolean(String var, boolean val) { setVariable(var, tOrNil(val)); } // invoke a function call in Nyquist with 0 or 1 parameters // (pass "" for 0 parameters) protected void callFunction(String fn, String parameter) { String input; if (jScrollPane.isSal) { input = "exec " + fn + "(" + parameter + ")"; } else { input = "(" + fn + (parameter.length() > 0 ? " " : "") + parameter + ")"; } sendInputLn(input); } public void Prefs() { // ignore if preferences is already open if (preferencesDialog != null) return; preferencesDialog = new PreferencesDialog(this); jDesktop.add(preferencesDialog); jDesktop.getDesktopManager().activateFrame(preferencesDialog); } // create a button private JButton buttonInit(String name, String tip, ActionListener listener) { JButton button = new JButton(); button.setText(name); button.setActionCommand(name); button.setToolTipText(tip); button.addActionListener(listener); jToolBar.add(button); return button; } private void menuAddItem(JMenu menu, String name, char mnemonic, KeyStroke accelerator, ActionListener listener) { JMenuItem item = new JMenuItem(); item.setText(name); item.setActionCommand(name); if (mnemonic != '\000') item.setMnemonic(mnemonic); if (accelerator != null) item.setAccelerator(accelerator); item.addActionListener(listener); menu.add(item); } public void handlePrefs() { System.out.println("handlePrefs called"); } //Component initialization private void mainFrameInit() throws Exception { // if this is a Mac, we want some menu items on the application menu, // which is accessed via some special apple code, but the apple code // is not going to be installed if you are running windows or linux, // so we use java reflection here to load the special code ONLY if // we're on a Mac // // The special code ultimately calls back to the methods About(), // Prefs(), and Quit() in this class. The "normal" Windows/Linux // code should do the same. if (isMac()) { hasRightMouseButton = false; try { Object[] args = { this }; Class[] arglist = { MainFrame.class }; Class mac_class = Class.forName("jnyqide.SpecialMacHandler"); /* Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); Class mac_class = cl.loadClass("SpecialMacHandler"); */ System.out.println("got the class\n"); Constructor new_one = mac_class.getConstructor(arglist); System.out.println("got the constructor\n"); new_one.newInstance(args); System.out.println("isMac, so created instance of SpecialMacHandler"); } catch(Exception e) { System.out.println(e); } } prefs = Preferences.userNodeForPackage(Main.class); prefStartInSalMode = prefs.getBoolean("start-with-sal", prefStartInSalMode); prefSalShowLisp = prefs.getBoolean("sal-show-lisp", prefSalShowLisp); prefParenAutoInsert = prefs.getBoolean("paren-auto-insert", prefParenAutoInsert); prefEnableSound = prefs.getBoolean("sound-enable", prefEnableSound); prefAutoNorm = prefs.getBoolean("auto-norm", prefAutoNorm); prefSalTraceBack = prefs.getBoolean("sal-traceback", prefSalTraceBack); prefSalBreak = prefs.getBoolean("sal-break", prefSalBreak); prefXlispBreak = prefs.getBoolean("xlisp-break", prefXlispBreak); prefXlispTraceBack = prefs.getBoolean("xlisp-traceback", prefXlispTraceBack); // if XlispTracBack, then we need to set XlispBreak: prefXlispBreak = prefXlispBreak || prefXlispTraceBack; prefPrintGC = prefs.getBoolean("print-gc", prefPrintGC); prefFullSearch = prefs.getBoolean("completion-list-full-search", prefFullSearch); prefInternalBrowser = prefs.getBoolean("internal-browser", prefInternalBrowser); prefOnlineManual = prefs.getBoolean("online-manual", prefOnlineManual); prefCompletionListPercent = prefs.getDouble("completion-list-percent", prefCompletionListPercent); prefAudioRate = prefs.get("audio-rate", prefAudioRate); prefControlRate = prefs.get("control-rate", prefControlRate); prefFontSize = prefs.get("font-size", prefFontSize); prefDirectory = prefs.get("initial-directory", prefDirectory); prefSFDirectory = prefs.get("default-sf-directory", prefSFDirectory); prefsHaveBeenSet = false; image1 = new ImageIcon("openFile.gif"); image2 = new ImageIcon("closeFile.gif"); image3 = new ImageIcon("help.gif"); //setIconImage(Toolkit.getDefaultToolkit().createImage(MainFrame.class.getResource("[Your Icon]"))); contentPane = (JPanel) this.getContentPane(); contentPane.setLayout(borderLayout1); this.setSize(new Dimension(400, 300)); this.setTitle("Nyquist IDE"); statusBar.setText(" "); ActionListener menuButtonListener = new ActionListener() { public void actionPerformed(ActionEvent e) { menuButtonHandler(e); } }; // Menu Bar jMenuFile.setText("File"); menuAddItem(jMenuFile, "New", 'n', KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), menuButtonListener); menuAddItem(jMenuFile, "Open", 'o', KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), menuButtonListener); if (!isMac()) { // if isMac(), Quit (not Exit) and Prefs are on the // application menu menuAddItem(jMenuFile, "Preferences...", '\000', null, menuButtonListener); menuAddItem(jMenuFile, "Exit", '\000', null, menuButtonListener); } jMenuEdit.setText("Edit"); menuAddItem(jMenuEdit, "Previous", 'p', KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), menuButtonListener); menuAddItem(jMenuEdit, "Next", 'n', KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), menuButtonListener); menuAddItem(jMenuEdit, "Select Expression", 'e', KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), menuButtonListener); jMenuHelp.setText("Help"); if (!isMac()) { // if isMac(), About is on the application menu menuAddItem(jMenuHelp, "About", 'h', null, menuButtonListener); } menuAddItem(jMenuHelp, "Manual", 'm', null, menuButtonListener); jMenuProcess.setText("Process"); menuAddItem(jMenuProcess, "Replay", 'r', null, menuButtonListener); menuAddItem(jMenuProcess, "Plot", 'p', null, menuButtonListener); menuAddItem(jMenuProcess, "Copy to Lisp", 'u', KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_U, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), menuButtonListener); menuAddItem(jMenuProcess, "Mark", 'a', null, menuButtonListener); jMenuWindow.setText("Window"); menuAddItem(jMenuWindow, "Tile", 't', null, menuButtonListener); menuAddItem(jMenuWindow, "Browse", 'b', null, menuButtonListener); menuAddItem(jMenuWindow, "EQ", 'q', null, menuButtonListener); menuAddItem(jMenuWindow, "Envelope Edit", 'e', null, menuButtonListener); /* BEGIN UPIC */ menuAddItem(jMenuWindow, "UPIC Edit", 'u', null, menuButtonListener); /* END UPIC */ buttonInit("Info", "Print Lisp memory status", menuButtonListener); buttonInit("Break", "Break/interrupt Lisp interpreter", menuButtonListener); // removed "Up" and "Cont" just to make some real-estate // buttonInit("Up", "Return from this break level", menuButtonListener); // buttonInit("Cont", "Continue Lisp execution", menuButtonListener); salLispButton = buttonInit("Sal", "Change Mode", menuButtonListener); buttonInit("Top", "Exit to Lisp top-level", menuButtonListener); buttonInit("Replay", "Replay the last sound", menuButtonListener); int i; for (i = 0; i < 11; i++) { String name = "F" + (i + 2); String tip = "Evaluate (" + name + ")"; buttonInit(name, tip, menuButtonListener); } buttonInit("Browse", "Browse Sound/Instrument/Effect Library", menuButtonListener); buttonInit("EQ", "Equalizer Control Panel", menuButtonListener); buttonInit("EnvEdit", "Open Graphical Envelope Editor", menuButtonListener); // buttonNew.setIcon(image1); buttonInit("New File", "New File", menuButtonListener); // buttonOpen.setIcon(image1); buttonInit("Open File", "Open File", menuButtonListener); // buttonSave.setIcon(image3); buttonInit("Save File", "Save File", menuButtonListener); buttonInit("Load", "Load File into Nyquist", menuButtonListener); buttonInit("Mark", "Get elapsed audio play time", menuButtonListener); jMenuBar1.add(jMenuFile); jMenuBar1.add(jMenuEdit); jMenuBar1.add(jMenuProcess); jMenuBar1.add(jMenuWindow); jMenuBar1.add(jMenuHelp); this.setJMenuBar(jMenuBar1); //MRJApplicationUtils.registerPrefsHandler(this); jOutputArea = new JTextArea(); jOutputArea.setFont(new Font("Courier", Font.PLAIN, 12)); jOutputArea.setLineWrap(true); jOutputArea.setEditable(false); jOutputPane = new JScrollPane( jOutputArea ); jOutputPane.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); jOutputPane.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); jListOutputArea = new JTextArea(); jListOutputArea.setLineWrap(true); jListOutputArea.setEditable(false); // add mouse listener jListOutputArea.addMouseListener(new MouseListener () { public void mouseExited(MouseEvent e) { }; public void mouseEntered(MouseEvent e) { }; public void mousePressed(MouseEvent e) { }; public void mouseReleased(MouseEvent e) { }; public void mouseClicked(MouseEvent e) { // System.out.println(e.paramString()); int pos = jListOutputArea.viewToModel(e.getPoint()); int start = 0, end = 0; String line = ""; // System.out.println("text posn = " + pos); try { int lineno = jListOutputArea.getLineOfOffset(pos); // System.out.println("line no = " + lineno); start = jListOutputArea.getLineStartOffset(lineno); end = jListOutputArea.getLineEndOffset(lineno); // System.out.println("start = " + start + " end = " + end); // skip newline by subtracting one from length if (end > start + 1) { line = jListOutputArea.getText(start, end - start - 1); // WordList.replaceWithTemplate(line); } // otherwise nothing selected } catch (Exception ex) { ex.printStackTrace(System.err); } // System.out.println("event: " + e); if (SwingUtilities.isRightMouseButton(e) || // for Mac, allow option click (which java sees as alt key) (e.getModifiers() & InputEvent.ALT_MASK) != 0) { String ext = WordList.getlink(line); System.out.println(line + " : " + ext); String url, urlbase; if (prefOnlineManual) urlbase = onlineManualURL; else urlbase = findManualURL(""); url = urlbase + ext; if (prefInternalBrowser) { miniBrowser.setVisible(true); System.out.println("URL is: " + url); miniBrowser.setPage(url); } else BareBonesBrowserLaunch.openURL(url); } else { // System.out.println(e.paramString()); WordList.replaceWithTemplate(line); } } }); jListOutputPane = new JScrollPane( jListOutputArea ); jListOutputPane.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); jListOutputPane.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); jScrollPane = new CodePane(new Dimension(400, 200), this, statusBar, Integer.parseInt(prefFontSize)); // Top panel for command entry, plot, and toolbar JPanel jCommands = new JPanel( new BorderLayout() ); JPanel jInputAndPlot = new JPanel(new BorderLayout(3, 0)); jInputAndPlot.add(jScrollPane, BorderLayout.WEST); System.out.println("\n\n\n\n\n\n\nadded jScrollPane " + jScrollPane + " to panel\n\n\n\n\n\n"); jCommands.add(jToolBar, BorderLayout.SOUTH); jCommands.add(jInputAndPlot, BorderLayout.CENTER); jCommands.setPreferredSize(new Dimension(300, 150)); // Main desktop jDesktop = new JDesktopPane(); jDesktop.setPreferredSize( new Dimension(300, 300) ); jOutputFrame = new JInternalFrame("Output"); // make this wide enough so XLISP GC messages do not wrap // (it's annoying) //jOutputFrame.setSize(new Dimension(500, 530 / 3)); jOutputFrame.setVisible(true); jOutputFrame.getContentPane().add(jOutputPane); jOutputFrame.setResizable( true ); //jOutputFrame.setLocation(0, (530 * 2) / 3); jDesktop.add( jOutputFrame ); String clTitle = "Completion List" + (hasRightMouseButton ? " - Right Click for Help" : " - Option Click for Help"); jListOutputFrame = new JInternalFrame(clTitle); //jListOutputFrame.setSize( new Dimension (500, (530 * 2) / 3)); jListOutputFrame.setVisible(true); jListOutputFrame.getContentPane().add(jListOutputPane); jListOutputFrame.setResizable(true); //jListOutputFrame.setLocation(0,0); jDesktop.add(jListOutputFrame); contentPane.add( jCommands, BorderLayout.NORTH); contentPane.add( jDesktop, BorderLayout.CENTER ); contentPane.add(statusBar, BorderLayout.SOUTH); setSize( new Dimension(800, 800) ); miniBrowser = new MiniBrowser("Nyquist Manual"); jDesktop.add(miniBrowser); TextColor.init(); WordList.init(jListOutputArea); SalWordList.init(); plotFrame = new PlotFrame(jInputAndPlot); nyquistThread = new NyquistThread(); nyquistThread.start(jOutputArea, update, plotFrame, this); System.out.print("jDesktop size: "); System.out.println(jDesktop.getSize().toString()); contentPane.setTransferHandler(new TransferHandler() { public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) { for (DataFlavor transferFlavor : transferFlavors) { if (transferFlavor.isFlavorJavaFileListType()) return true; } return false; } public boolean importData(JComponent comp, Transferable t) { try { Collection files = (Collection) t.getTransferData(DataFlavor.javaFileListFlavor); for (File file : files) { openFile(file); } return true; } catch (Exception e) { System.out.println("Drop failed: "+e.getMessage()); } return false; } }); // set size and location for jOutputFrame and jListOutputFrame // now this is done in Main after making desktop visible (otherwise // you can't get dimensions of the desktop and layout is faulty) // tileCompletion(); } public void sendPreferenceData() { // send Nyquist the preference values (assumes in Lisp mode) sendInputLn(";; transferring preference data from jNyqIDE to Nyquist"); sendInputLn("(progn"); setBoolean("*sal-compiler-debug*", prefSalShowLisp); callFunction(prefEnableSound ? "sound-on" : "sound-off", ""); callFunction(prefAutoNorm ? "autonorm-on" : "autonorm-off", ""); callFunction("sal-tracenable", tOrNil(prefSalTraceBack)); callFunction("sal-breakenable", tOrNil(prefSalBreak)); callFunction("xlisp-breakenable", tOrNil(prefXlispBreak)); callFunction("xlisp-tracenable", tOrNil(prefXlispTraceBack)); setBoolean("*gc-flag*", prefPrintGC); callFunction("set-sound-srate", prefAudioRate); callFunction("set-control-srate", prefControlRate); setFontSize(Integer.parseInt(prefFontSize)); if (prefDirectory != null && prefDirectory.length() > 0) { changeDirectory(prefDirectory); } if (prefSFDirectory != null && prefSFDirectory.length() > 0) { String dirString = escape_backslashes(prefSFDirectory); setVariable("*default-sf-dir*", "\"" + dirString + "\""); } else { // no preference, suggest Java temp dir. The Java temp dir // will be used as *default-sf-dir* only if *default-sf-dir* // was set to "", meaning previous methods to identify a temp // directory failed to produce anything. String tempdir = System.getProperty("java.io.tmpdir"); if (!(tempdir.endsWith("/") || tempdir.endsWith("\\"))) tempdir = tempdir + "/"; // flip backslash to slash to avoid quote problems tempdir = "\"" + tempdir.replaceAll("\\\\", "/") + "\""; callFunction("suggest-default-sf-dir", tempdir); } setBoolean("*sal-secondary-prompt*", false); sendInputLn(";; end preference data transfer"); sendInputLn(")"); if (prefStartInSalMode) { callFunction("sal", ""); } } //File | Exit action performed public void menuButtonHandler(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd == "New" || cmd == "New File") doFileNew(e); else if (cmd == "Open" || cmd == "Open File") doFileOpen(e); else if (cmd == "Save" || cmd == "Save File") doFileSave(e); else if (cmd == "Save As...") doFileSaveAs(e); else if (cmd == "Load" || cmd == "Load...") doFileLoad(e); else if (cmd == "Mark") doProcessMark(e); else if (cmd == "Preferences...") Prefs(); else if (cmd == "Exit") { SwingUtilities.invokeLater(new Runnable() { public void run() { Quit(); } }); // throw new IllegalStateException("Let the quit handler do it"); } else if (cmd == "Find...") doEditFind(e); else if (cmd == "Replace...") doEditReplace(e); else if (cmd == "Previous") doEditPrevious(e); else if (cmd == "Next") doEditNext(e); else if (cmd == "Select Expression") doEditSelectExpression(e); else if (cmd == "About") About(); else if (cmd == "Manual") doHelpManual(e); else if (cmd == "Replay") doProcessReplay(e); else if (cmd == "Plot") doProcessPlot(e); else if (cmd == "Tile") doWindowTile(e); else if (cmd == "Browse") doWindowBrowse(e); else if (cmd == "EQ") doWindowEQ(e); else if (cmd == "EnvEdit" || cmd == "Envelope Edit") doWindowEnvelope(e); /* BEGIN UPIC */ else if (cmd == "UPIC Edit") doWindowUPIC(e); /* END UPIC */ else if (cmd == "Info") doProcessInfo(e); else if (cmd == "Break") doProcessBreak(e); else if (cmd == "Up") doProcessUp(e); else if (cmd == "Cont") doProcessCont(e); else if (cmd == "Top") doProcessTop(e); else if (cmd == "Lisp") doProcessLisp(e); else if (cmd == "Sal") doProcessSal(e); else if (cmd == "Copy to Lisp") doProcessCopyToLisp(e); // do this last so other commands starting with "F" get handled else if (cmd.charAt(0) == 'F') doProcessFn(e); else System.out.println("menu or button command not expected: " + cmd); } public void Quit() { System.out.println("Quit() called in MainFrame.java"); // close prefs? int r = JOptionPane.OK_OPTION; if (preferencesDialog != null) { r = JOptionPane.showConfirmDialog(this, "Really close without closing (saving) preferences?", "alert", JOptionPane.OK_CANCEL_OPTION); } if (r != JOptionPane.OK_OPTION) return; // do not quit if (prefsHaveBeenSet) { prefs.putBoolean("start-with-sal", prefStartInSalMode); prefs.putBoolean("sal-show-lisp", prefSalShowLisp); prefs.putBoolean("paren-auto-insert", prefParenAutoInsert); prefs.putBoolean("sound-enable", prefEnableSound); prefs.putBoolean("auto-norm", prefAutoNorm); prefs.putBoolean("sal-traceback", prefSalTraceBack); prefs.putBoolean("sal-break", prefSalBreak); prefs.putBoolean("xlisp-break", prefXlispBreak); prefs.putBoolean("xlisp-traceback", prefXlispTraceBack); prefs.putBoolean("print-gc", prefPrintGC); prefs.putBoolean("completion-list-full-search", prefFullSearch); prefs.putBoolean("internal-browser", prefInternalBrowser); prefs.putBoolean("online-manual", prefOnlineManual); prefs.putDouble("completion-list-percent", prefCompletionListPercent); prefs.put("audio-rate", prefAudioRate); prefs.put("control-rate", prefControlRate); prefs.put("font-size", prefFontSize); prefs.put("initial-directory", prefDirectory); prefs.put("default-sf-directory", prefSFDirectory); prefsHaveBeenSet = false; } JInternalFrame[] frames = jDesktop.getAllFrames(); boolean flag = false; int i; for (i = 0; i < frames.length; i++) { if (frames[i] instanceof NyquistFile) { NyquistFile nyquistFile = (NyquistFile) frames[i]; if (nyquistFile.modified) flag = true; } } r = JOptionPane.OK_OPTION; if (flag) { r = JOptionPane.showConfirmDialog(this, "Really close without saving?", "alert", JOptionPane.OK_CANCEL_OPTION); } if (r != JOptionPane.OK_OPTION) return; // do not quit if (workspaceLoaded) { r = JOptionPane.showConfirmDialog(this, "Save workspace to current directory before exiting?", "alert", JOptionPane.YES_NO_CANCEL_OPTION); if (r == JOptionPane.YES_OPTION) { workspaceSaved = false; // interface with NyquistThread callFunction("save-workspace", ""); i = 0; while (!workspaceSaved && i < 10000) { // allow 10s try { Thread.sleep(200); } catch (InterruptedException ie) { } i += 200; } if (!workspaceSaved) { r = JOptionPane.showConfirmDialog(this, "Timed out waiting for workspace save.\n" + "Your workspace data may not be saved.\n" + "Exit anyway?", "alert", JOptionPane.OK_CANCEL_OPTION); } } if (r == JOptionPane.CANCEL_OPTION) return; // do not quit } System.out.println("Sending (exit) to Nyquist..."); // try to shut down Nyquist before it is orphaned // Sal need special syntax to exit the Nyquist process: if (jScrollPane.isSal) sendInputLn("exit nyquist"); else callFunction("exit", ""); try { Thread.sleep(200); // does it help Nyquist's exit to stall? } catch (InterruptedException ie) { } System.out.println("Exiting from NyquistIDE"); System.exit(0); } public void prepareNewNyquistFile(final NyquistFile file) { jDesktop.add(file); jDesktop.getDesktopManager().activateFrame(file); jDesktop.setSelectedFrame(file); file.addInternalFrameListener( new InternalFrameListener() { public void internalFrameClosing(InternalFrameEvent e) { //System.out.println("FrameClosing"); int r = JOptionPane.OK_OPTION; if (file.modified) { r = JOptionPane.showConfirmDialog(file, "Really close without saving?", "alert", JOptionPane.OK_CANCEL_OPTION); } if (r == JOptionPane.OK_OPTION) { file.dispose(); } } public void internalFrameOpened(InternalFrameEvent e) { } public void internalFrameClosed(InternalFrameEvent e) { //System.out.println("FrameClosed"); } public void internalFrameIconified(InternalFrameEvent e) { } public void internalFrameDeiconified(InternalFrameEvent e) { } public void internalFrameActivated(InternalFrameEvent e) { } public void internalFrameDeactivated(InternalFrameEvent e) { } } ); } public void doFileNew(ActionEvent e) { final NyquistFile file = new NyquistFile(this, Integer.parseInt(prefFontSize)); prepareNewNyquistFile(file); } public String fileDirectory(File file) { String path = file.getAbsolutePath(); String name = file.getName(); return path.substring(0, path.length() - name.length()); } //File | Exit action performed public void doFileOpen(ActionEvent e) { JFileChooser chooser = new JFileChooser(); LispFileFilter lispFilter = new LispFileFilter(); SalFileFilter salFilter = new SalFileFilter(); // last one seems to be the default setting for user, so set according // to current mode if (jScrollPane.isSal) { chooser.setFileFilter(lispFilter); chooser.addChoosableFileFilter(salFilter); } else { chooser.setFileFilter(salFilter); chooser.addChoosableFileFilter(lispFilter); } // note if current directory setting fails on some platform, // consider this code using getCanonicalPath(): // File f = new File(new File(".").getCanonicalPath()); File curdir = new File(currentDir); chooser.setCurrentDirectory(curdir); int returnVal = chooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { System.out.println("You chose to open this file: " + chooser.getSelectedFile().getAbsoluteFile()); openFile(chooser.getSelectedFile()); } } private void openFile(File fileToOpen) { // see if file is already open JInternalFrame[] frames = jDesktop.getAllFrames(); int i; for (i = 0; i < frames.length; i++) { if (frames[i] instanceof NyquistFile) { NyquistFile file = (NyquistFile) frames[i]; if (file.getFile() != null && file.getFile().getAbsolutePath().equals( fileToOpen.getAbsolutePath())) { jDesktop.setSelectedFrame(file); try { file.setSelected(true); } catch(PropertyVetoException ve) { //System.out.println("setSelected was vetoed"); } JInternalFrame jInternalFrame = jDesktop.getSelectedFrame(); if (jInternalFrame instanceof NyquistFile) { NyquistFile nf = (NyquistFile) jInternalFrame; //System.out.println("selected is " + // nf.getAbsolutePath()); } else { //System.out.println("selected not a NyquistFile"); } return; } } } // Didn't find it. Open it in a new frame. final NyquistFile file = new NyquistFile(fileToOpen, this, Integer.parseInt(prefFontSize)); changeDirectory(fileDirectory(fileToOpen)); prepareNewNyquistFile(file); } public void doFileSave(ActionEvent e) { if (jDesktop.getSelectedFrame() instanceof NyquistFile) { NyquistFile file = (NyquistFile)jDesktop.getSelectedFrame(); if (file.save(currentDir)) { changeDirectory(fileDirectory(file.getFile())); } } } public void doFileSaveAs(ActionEvent e) { if (jDesktop.getSelectedFrame() instanceof NyquistFile) { NyquistFile file = (NyquistFile)jDesktop.getSelectedFrame(); if (file.saveAs(currentDir)) { changeDirectory(fileDirectory(file.getFile())); } } } public void doFileLoad(ActionEvent e) { JInternalFrame frame = jDesktop.getSelectedFrame(); if (frame instanceof NyquistFile) { NyquistFile file = (NyquistFile) frame; if (file.save(currentDir)) { loadFile(file.getFile()); } } } //Edit | Find action performed public void doEditFind(ActionEvent e) { JInternalFrame frame = jDesktop.getSelectedFrame(); if (frame instanceof NyquistFile) { NyquistFile file = (NyquistFile) frame; FindDialog findDialog = new FindDialog(file, this); } } //Edit | Replace action performed public void doEditReplace(ActionEvent e) { JInternalFrame frame = jDesktop.getSelectedFrame(); if (frame instanceof NyquistFile) { NyquistFile file = (NyquistFile) frame; ReplaceDialog replaceDialog = new ReplaceDialog(file, this); } } public void filterCRLF(StringBuffer buf) { //int i = buf.toString().indexOf("\r\n"); // note: buf.indexOf() doesn't work on Mac //while (i >= 0) { // buf.replace(i, i + 2, "\n"); // i = buf.toString().indexOf("\r\n", i); //} buf.replace(0, buf.length(), buf.toString().replaceAll("\r\n", "\n")); } public String trimNewline(String s) { int len = s.length(); while (len > 0 && (s.charAt(len - 1) == '\n' || s.charAt(len - 1) == '\r')) { len = len - 1; } return s.substring(0, len); } //Edit | Previous action performed public void doEditPrevious(ActionEvent e) { inputStringsCursor = inputStringsCursor - 1; if (inputStringsCursor < 0) inputStringsCursor = inputStringsLen - 1; String text = inputStrings[inputStringsCursor]; if (text != null) { // remove the newline at the end jScrollPane.pane.setText(trimNewline(text)); } } //Edit | Next action performed public void doEditNext(ActionEvent e) { inputStringsCursor = inputStringsCursor + 1; if (inputStringsCursor >= inputStringsLen) inputStringsCursor = 0; String text = inputStrings[inputStringsCursor]; if (text != null) { jScrollPane.pane.setText(trimNewline(text)); } } //Edit | Select Expression public void doEditSelectExpression(ActionEvent e) { JInternalFrame frame = jDesktop.getSelectedFrame(); if (frame instanceof NyquistFile) { NyquistFile file = (NyquistFile) frame; file.selectExpression(); } } //Help | About action performed public void About() { MainFrame_AboutBox dlg = new MainFrame_AboutBox(this); Dimension dlgSize = dlg.getPreferredSize(); Dimension frmSize = getSize(); Point loc = getLocation(); dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y); dlg.setModal(true); dlg.setVisible(true); Graphics g = jFrame.getContentPane().getGraphics(); g.setColor(Color.cyan); g.fillRect(50, 50, 100, 100); } public String findManualURL(String ext) { String url = ""; try { url = homeDir.getCanonicalPath(); } catch (Exception e) { System.out.println("findManualURL exception: " + e); } String osName = System.getProperty("os.name"); if (osName.startsWith("Mac OS")) { // from ./NyquistIDE.app/Contents/Resources/Java to . // note: I tried this using homeDir.getParentFile(), but // it always returns null, so I'm string parsing instead int i; for (i = 0; i < 4; i++) { int pos = url.lastIndexOf('/'); if (pos >= 0) { url = url.substring(0, pos); } System.out.println(url); } url += "/nyquist"; } else if (osName.startsWith("Windows")) { // file://C:/ does not work, file:///C:/ does work url = "/" + url; } url = "file://" + url + "/doc/" + ext; return url; } public void doHelpManual(ActionEvent e) { if (prefInternalBrowser) { miniBrowser.setVisible(true); miniBrowser.setPage(findManualURL("title.html")); } else { // separate browser gets to use frames (with index) by // opening home.html String url = findManualURL("home.html"); System.out.println("Try to open: " + url); BareBonesBrowserLaunch.openURL(url); } } public void doProcessReplay(ActionEvent e) { callFunction("r", ""); } public void disconnectEnv() { // no more envelopeFrame, so kill pointer envelopeEditor = null; } public void disconnectEq() { // no more equalizer panel, so kill pointer eqEditor = null; } /* BEGIN UPIC */ public void disconnectUPIC() { // no more upicFrame, so kill pointer upicEditor = null; } /* END UPIC */ public boolean workspaceWarning(String description) { // return true if OK to proceed if (workspaceLoaded) return true; Object[] options = { "CANCEL", "LOAD", "SKIP" }; int i = JOptionPane.showOptionDialog(this, "No workspace has been loaded. If you save " + description + ",\nany existing workspace will be overwritten without\n" + "further notice. You should probably click CANCEL,\n" + "open workspace.lsp, load it into Nyquist, and then\n" + "revisit this editor.\n\n" + "Click SKIP to proceed at your own risk.\n" + "Click LOAD to load workspace.lsp from the current directory.\n" + "Click CANCEL to resume without opening a new editor window.\n\n" + "(If you have no workspace to load, select SKIP.)\n", "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); System.out.println("dialog returns " + i); if (i == 2) { // skip (proceed) option workspaceLoaded = true; } else if (i == 1) { // load workspace callFunction("load", "\"workspace\""); i = 0; while (!workspaceLoaded && i < 10000) { // alow 10s try { Thread.sleep(200); } catch (InterruptedException ie) { } i += 200; } if (!workspaceLoaded) { JOptionPane.showMessageDialog(this, "Timed out waiting for workspace load.\n" + "Maybe it does not exist in this directory?", "alert", JOptionPane.INFORMATION_MESSAGE); } } // otherwise OK_OPTION selected, return false meaning do not proceed return workspaceLoaded; } public void doWindowEnvelope(ActionEvent e) { // only one editor instance allowed if (envelopeEditor != null) { JOptionPane.showMessageDialog(this, "Envelope editor is already open.", "alert", JOptionPane.INFORMATION_MESSAGE); return; } // open an envelope window if (!workspaceWarning("envelopes")) return; final EnvelopeFrame envelopeFrame = new EnvelopeFrame(this, jScrollPane.pane); final MainFrame mainFrame = this; envelopeEditor = envelopeFrame; envelopeFrame.validate(); jDesktop.add(envelopeFrame); jDesktop.getDesktopManager().activateFrame(envelopeFrame); jDesktop.setSelectedFrame(envelopeFrame); } /* BEGIN UPIC */ public void doWindowUPIC(ActionEvent e) { // only one editor instance allowed if (upicEditor != null) { JOptionPane.showMessageDialog(this, "UPIC editor is already open.", "alert", JOptionPane.INFORMATION_MESSAGE); return; } // open a UPIC window final UPICFrame upicFrame = new UPICFrame(this, jScrollPane.pane); upicEditor = upicFrame; upicFrame.validate(); jDesktop.add(upicFrame); jDesktop.getDesktopManager().activateFrame(upicFrame); jDesktop.setSelectedFrame(upicFrame); } /* END UPIC */ public void doWindowEQ(ActionEvent e) { /* Code added by Rivera Create a slider object that is the graphic equalizer * Then add that slider object to the desktop, It will display * directly to the right of the output, given the outputs frame * width of 500 */ if (eqEditor != null) { JOptionPane.showMessageDialog(this, "Equalizer editor is already open.", "alert", JOptionPane.INFORMATION_MESSAGE); return; } if (!workspaceWarning("equalizers")) return; final Jslide jslide = new Jslide(this); eqEditor = jslide; final MainFrame mainFrame = this; final JInternalFrame jEq = new JInternalFrame("Equalizer", true, true); jEq.setSize(new Dimension(350, 300)); jEq.setLocation(500, 0); jEq.setVisible(true); jEq.getContentPane().add(jslide.getGraphEq()); jDesktop.add(jEq); jEq.addInternalFrameListener( new InternalFrameListener() { public void internalFrameClosing(InternalFrameEvent e) { //System.out.println("FrameClosing"); int r = JOptionPane.OK_OPTION; if (jslide.modified) { r = JOptionPane.showConfirmDialog(jEq, "Really close without saving?", "alert", JOptionPane.OK_CANCEL_OPTION); } if (r == JOptionPane.OK_OPTION) { jEq.dispose(); } } public void internalFrameOpened(InternalFrameEvent e) { } public void internalFrameClosed(InternalFrameEvent e) { mainFrame.disconnectEq(); //System.out.println("FrameClosed"); } public void internalFrameIconified(InternalFrameEvent e) { } public void internalFrameDeiconified(InternalFrameEvent e) { } public void internalFrameActivated(InternalFrameEvent e) { } public void internalFrameDeactivated(InternalFrameEvent e) { } } ); System.out.print("jOutputFrame size: "); System.out.println(jOutputFrame.getSize().toString()); System.out.print("Available space in jDesktop: "); System.out.println(jDesktop.getInsets().toString()); System.out.print("jDesktop size: "); System.out.println(jDesktop.getSize().toString()); } public void doProcessInfo(ActionEvent e) { callFunction("info", ""); } public void doProcessBreak(ActionEvent e) { sendInput("\02\n"); } public void doProcessCont(ActionEvent e) { callFunction("continue", ""); } public void doProcessTop(ActionEvent e) { // don't use callFunction because isSal might be wrong // using (top) will work in both Lisp and Sal modes sendInputLn("(top)"); } public void doProcessSal(ActionEvent e) { callFunction("sal", ""); } public void doProcessLisp(ActionEvent e) { sendInputLn("exit"); } public void doProcessUp(ActionEvent e) { callFunction("up", ""); } public void doProcessMark(ActionEvent e) { sendInput(Character.toString('\001'), true); } /* this is an old test function to simulate a slider change... public void doProcessTest(ActionEvent e) { sendInput(Character.toString('\016'), true); // begin message sendInput("S", true); // command is "slider change" test_value += 1.0; sendInput("5 ", true); // which slider sendInput(Float.toString(test_value), true); // new value sendInput(Character.toString('\021'), true); // end message } */ public void doProcessFn(ActionEvent e) { callFunction(e.getActionCommand(), ""); } // Plot command public void doProcessPlot(ActionEvent e) { NyqPlot.plot("points.dat", plotFrame); } // Process | Copy to Lisp Command public void doProcessCopyToLisp(ActionEvent e) { JInternalFrame frame = jDesktop.getSelectedFrame(); if (frame instanceof NyquistFile) { NyquistFile file = (NyquistFile) frame; String selection = file.currentSelection(); jScrollPane.pane.setText(selection); sendCommandToNyquist(); } } // adjust completion window and output windows only public void tileCompletion() { // place output frame at left, full height Dimension dim = jDesktop.getSize(); // something goes wrong at initialization, so hack in a reasonable value if (dim.width == 0 || dim.height == 0) { System.out.println("desktop size is zero, guessing 800 by 612"); dim = new Dimension(800, 612); } else { System.out.println("desktop size is actually " + dim); } //System.out.print("jDesktop size: "); //System.out.println(dim.toString()); int loc = (int) (dim.height * prefCompletionListPercent * 0.01); jOutputFrame.setLocation(0, loc); jListOutputFrame.setLocation(0, 0); // make output_width based on width of "desktop", which is the // area that contains the output frame and all the file (editor) // frames. int output_width = 530; if (dim.width < 600) output_width = dim.width - 100; if (output_width < 100) output_width = dim.width / 2; jOutputFrame.setSize(output_width, dim.height - loc); jListOutputFrame.setSize(output_width, loc); System.out.println("jListOutputFrame.setSize " + output_width + " " + loc + " " + dim); } // Window Tile command -- organize window placement public void doWindowTile(ActionEvent e) { tileCompletion(); // place output frame at left, full height Dimension dim = jDesktop.getSize(); System.out.println("jDesktop.getSize(): " + dim); int output_width = 530; // for now this is constant, see tileCompletion // organize windows // if there are 3 or less or width is less than 1200, // use one column int cols = 1; JInternalFrame[] frames = jDesktop.getAllFrames(); int num_frames = frames.length - 2; // don't count jOutput Frame or // completion frame if (!miniBrowser.isVisible()) num_frames--; // don't count browser frame if (num_frames <= 0) return; // nothing to tile if (num_frames > 3 && dim.width >= 1200) { cols = 2; } int frames_per_col = (num_frames + cols - 1) / cols; int frame_spacing = dim.height / frames_per_col; // allow overlap if necessary int frame_height = Math.max(frame_spacing, 100); int frame_width = (dim.width - output_width) / cols; int i; int col = 0; int row = 0; for (i = 0; i < frames.length; i++) { if (frames[i] != jOutputFrame && frames[i] != jListOutputFrame && frames[i].isVisible()) { //NyquistFile nyquistFile = (NyquistFile) frames[i]; JInternalFrame nyquistFile = (JInternalFrame) frames[i]; nyquistFile.setLocation(output_width + col * frame_width, row * frame_spacing); nyquistFile.setSize(frame_width, frame_height); row = row + 1; if (row >= frames_per_col) { row = 0; col = col + 1; } } } } // Window Browse command -- create a browse/demo window public void doWindowBrowse(ActionEvent e) { // place output frame at left, full height loadBrowserFrame(); } //Overridden so we can exit (if confirmed) when window is closed protected void processWindowEvent(WindowEvent e) { // super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { Quit(); } } // convert backslash to escaped backslash in path for nyquist public String escape_backslashes(String path) { String escaped = ""; int i = 0; while (i < path.length()) { char c = path.charAt(i); escaped = escaped + c; if (c == '\\') escaped = escaped + c; i++; } return escaped; } // set current directory public void changeDirectory(String dir) { System.out.println("changeDirectory: currentDir " + currentDir + " to " + dir); if (!currentDir.equals(dir)) { currentDir = dir; String escapedDir = escape_backslashes(dir); callFunction("setdir", "\"" + escapedDir + "\""); } } // tell nyquist to load a file public void loadFile(File file) { changeDirectory(fileDirectory(file)); String path = escape_backslashes(file.getAbsolutePath()); // if we're in lisp, pop out of any debug/break prompts before loading // don't do this is we're in sal because it will exit Sal - not good if (jScrollPane.isSal) { // callFunction would also work, but I prefer to use the "native" // Sal load command sendInputLn("load \"" + path + "\""); } else { callFunction("top", ""); callFunction("sal-load", "\"" + path + "\""); } } // send data to Nyquist process after fixing indentation and appending // a newline public void sendInputLn(String text) { // fix text with indentation if there are multiple lines String newlines = (jScrollPane.isSal ? "\n\n" : "\n"); sendInput( text.replaceAll("\n", (jScrollPane.isSal ? "\n " : "\n ")) + newlines, false); } public void setSalMode(final boolean sal) { jScrollPane.isSal = sal; SwingUtilities.invokeLater(new Runnable() { public void run() { String name = (sal ? "Lisp" : "Sal"); salLispButton.setText(name); salLispButton.setActionCommand(name); salLispButton.setToolTipText(sal ? "Switch to Lisp Mode" : "Switch to SAL Mode"); } }); } // send data to Nyquist process public void sendInput(String text) { sendInput(text, false); } public void sendInput(String text, boolean hide) { SwingUtilities.invokeLater(update); System.out.println("sendInput: " + text + "(" + hide + ")"); nyquistThread.sendInput(text, hide); } public void sendCommandToNyquist() { StringBuffer text = new StringBuffer(jScrollPane.pane.getText()); inputStrings[inputStringsX] = new String(text); // for some reason, text sometimes ends up // with a CR LF at end. Make sure it's gone // before we output to Nyquist filterCRLF(text); // System.out.println("text |" + text + "| pos " + pos); // SAL wants newline before multiline input to make input prettier //if (jScrollPane.isSal && // inputStrings[inputStringsX].indexOf("\n") >= 0) // sendInput("\n"); sendInputLn(inputStrings[inputStringsX]); // System.out.println("text sent to Nyquist"); inputStringsX++; if (inputStringsX >= inputStringsLen) { inputStringsX = 0; } inputStringsCursor = inputStringsX; jScrollPane.pane.setText(""); } public void ScrollToEnd() { JScrollBar scroll = jOutputPane.getVerticalScrollBar(); scroll.setValue(scroll.getMaximum() - scroll.getVisibleAmount()); } public void loadBrowserFrame() { Browser frame = new Browser(this, nyquistThread); // Validate frames that have preset sizes // Pack frames that have useful preferred size info, e.g. from their layout if (packFrame) { frame.pack(); } else { frame.validate(); } jDesktop.add(frame); } public void loadEnvData(String data) { if (envelopeEditor != null) { envelopeEditor.loadEnvData(data); } /* BEGIN UPIC */ /* if (upicEditor != null) { upicEditor.loadEnvData(data); } */ /* END UPIC */ } public void loadEqData(String data) { if (eqEditor != null) { eqEditor.loadEqData(data); } } public void setFontSize(int s) { JInternalFrame[] frames = jDesktop.getAllFrames(); int i; for (i = 0; i < frames.length; i++) { if (frames[i] instanceof NyquistFile) { NyquistFile nyquistFile = (NyquistFile) frames[i]; CodePane pane = nyquistFile.filePane; pane.setFontSize(s); } } jScrollPane.setFontSize(s); jOutputArea.setFont(new Font("Courier", Font.PLAIN, s)); } } nyquist-3.05/jnyqide/LispFileFilter.java0000644000175000000620000000113411466723256017361 0ustar stevestaffpackage jnyqide; import javax.swing.filechooser.*; import java.io.File; /** *

    Title:

    *

    Description:

    *

    Copyright: Copyright (c) 2002

    *

    Company:

    * @author unascribed * @version 1.0 */ public class LispFileFilter extends FileFilter { public LispFileFilter() { } public boolean accept(File f) { if (f.getName().endsWith(".lsp")) return true; for (int x = 0; x < f.getName().length(); x++) { if ((f.getName().charAt(x) == '.')) return false; } return true; } public String getDescription() { return "Lisp files."; } } nyquist-3.05/nyqwin.dsp0000644000175000000620000005606311466723256014246 0ustar stevestaff# Microsoft Developer Studio Project File - Name="nyqwin" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=nyqwin - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "nyqwin.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "nyqwin.mak" CFG="nyqwin - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "nyqwin - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "nyqwin - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "nyqwin - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir ".\WinRel" # PROP BASE Intermediate_Dir ".\WinRel" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\NyqWinRel" # PROP Intermediate_Dir ".\NyqWinRel" # PROP Ignore_Export_Lib 0 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /YX /c # ADD CPP /nologo /W3 /GX /O2 /I ".\xlisp" /I ".\snd" /I ".\nyqsrc" /I ".\tran" /I ".\cmt" /I ".\sys\win\msvc" /I ".\fft" /I ".\portaudio\pa_common" /I ".\nyqstk" /I ".\nyqstk\include" /D "NDEBUG" /D "WIN32" /D "CMTSTUFF" /D "WINGUI" /D "PA_NO_ASIO" /D "PA_NO_DS" /D "STK_NYQUIST" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 wsock32.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /machine:I386 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "nyqwin - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir ".\WinDebug" # PROP BASE Intermediate_Dir ".\WinDebug" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\NyqWinDebug" # PROP Intermediate_Dir ".\NyqWinDebug" # PROP Ignore_Export_Lib 0 # ADD BASE CPP /nologo /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /YX /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I ".\xlisp" /I ".\snd" /I ".\nyqsrc" /I ".\tran" /I ".\cmt" /I ".\sys\win\msvc" /I ".\fft" /I ".\portaudio\pa_common" /I ".\nyqstk" /I ".\nyqstk\include" /D "PA_NO_ASIO" /D "PA_NO_DS" /D "CMTSTUFF" /D "WINGUI" /D "STK_NYQUIST" /D "WIN32" /D "_DEBUG" /D "DEBUG_INPUT" /YX /FD /c # SUBTRACT CPP /Fr # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 # ADD LINK32 wsock32.lib winmm.lib kernel32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 # SUBTRACT LINK32 /pdb:none !ENDIF # Begin Target # Name "nyqwin - Win32 Release" # Name "nyqwin - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" # Begin Source File SOURCE=.\tran\abs.c # End Source File # Begin Source File SOURCE=.\nyqsrc\add.c # End Source File # Begin Source File SOURCE=.\tran\allpoles.c # End Source File # Begin Source File SOURCE=.\tran\alpass.c # End Source File # Begin Source File SOURCE=.\tran\alpasscv.c # End Source File # Begin Source File SOURCE=.\tran\alpassvv.c # End Source File # Begin Source File SOURCE=.\tran\amosc.c # End Source File # Begin Source File SOURCE=.\tran\areson.c # End Source File # Begin Source File SOURCE=.\tran\aresoncv.c # End Source File # Begin Source File SOURCE=.\tran\aresonvc.c # End Source File # Begin Source File SOURCE=.\tran\aresonvv.c # End Source File # Begin Source File SOURCE=.\tran\atone.c # End Source File # Begin Source File SOURCE=.\tran\atonev.c # End Source File # Begin Source File SOURCE=.\snd\audiowin32.c # End Source File # Begin Source File SOURCE=.\nyqsrc\avg.c # End Source File # Begin Source File SOURCE=.\tran\biquad.c # End Source File # Begin Source File SOURCE=.\tran\buzz.c # End Source File # Begin Source File SOURCE=.\cmt\cext.c # End Source File # Begin Source File SOURCE=.\tran\chase.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Clarinet.cpp # End Source File # Begin Source File SOURCE=.\cmt\cleanup.c # End Source File # Begin Source File SOURCE=.\tran\clip.c # End Source File # Begin Source File SOURCE=.\cmt\cmdline.c # End Source File # Begin Source File SOURCE=.\cmt\cmtcmd.c # End Source File # Begin Source File SOURCE=.\nyqsrc\compose.c # End Source File # Begin Source File SOURCE=.\tran\congen.c # End Source File # Begin Source File SOURCE=.\tran\const.c # End Source File # Begin Source File SOURCE=.\nyqsrc\convolve.c # End Source File # Begin Source File SOURCE=.\tran\coterm.c # End Source File # Begin Source File SOURCE=.\nyqsrc\debug.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Delay.cpp # End Source File # Begin Source File SOURCE=.\tran\delaycc.c # End Source File # Begin Source File SOURCE=.\tran\delaycv.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\DelayL.cpp # End Source File # Begin Source File SOURCE=.\nyqsrc\downsample.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Envelope.cpp # End Source File # Begin Source File SOURCE=.\tran\eqbandvvv.c # End Source File # Begin Source File SOURCE=.\tran\exp.c # End Source File # Begin Source File SOURCE=.\xlisp\extern.c # End Source File # Begin Source File SOURCE=.\nyqsrc\falloc.c # End Source File # Begin Source File SOURCE=.\nyqsrc\ffilterkit.c # End Source File # Begin Source File SOURCE=.\nyqsrc\fft.c # End Source File # Begin Source File SOURCE=.\fft\fftn.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Filter.cpp # End Source File # Begin Source File SOURCE=.\tran\fmosc.c # End Source File # Begin Source File SOURCE=.\tran\follow.c # End Source File # Begin Source File SOURCE=.\tran\fromarraystream.c # End Source File # Begin Source File SOURCE=.\tran\fromobject.c # End Source File # Begin Source File SOURCE=.\tran\gate.c # End Source File # Begin Source File SOURCE=.\nyqstk\globals.h # End Source File # Begin Source File SOURCE=.\nyqsrc\handlers.c # End Source File # Begin Source File SOURCE=.\snd\ieeecvt.c # End Source File # Begin Source File SOURCE=.\tran\ifft.c # End Source File # Begin Source File SOURCE=.\nyqstk\instr.cpp # End Source File # Begin Source File SOURCE=.\nyqstk\instr.h # End Source File # Begin Source File SOURCE=.\tran\instrclar.c # End Source File # Begin Source File SOURCE=.\tran\instrclarall.c # End Source File # Begin Source File SOURCE=.\tran\instrclarfreq.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Instrmnt.cpp # End Source File # Begin Source File SOURCE=.\tran\instrsax.c # End Source File # Begin Source File SOURCE=.\tran\instrsaxall.c # End Source File # Begin Source File SOURCE=.\tran\instrsaxfreq.c # End Source File # Begin Source File SOURCE=.\tran\integrate.c # End Source File # Begin Source File SOURCE=.\nyqsrc\inverse.c # End Source File # Begin Source File SOURCE=.\nyqsrc\local.c # End Source File # Begin Source File SOURCE=.\tran\log.c # End Source File # Begin Source File SOURCE=.\sys\win\wingui\longque.cpp # End Source File # Begin Source File SOURCE=.\tran\lpreson.c # End Source File # Begin Source File SOURCE=.\tran\maxv.c # End Source File # Begin Source File SOURCE=.\cmt\mem.c # End Source File # Begin Source File SOURCE=.\cmt\midifile.c # End Source File # Begin Source File SOURCE=.\cmt\midifns.c # End Source File # Begin Source File SOURCE=.\cmt\moxc.c # End Source File # Begin Source File SOURCE=.\nyqsrc\multiread.c # End Source File # Begin Source File SOURCE=.\nyqsrc\multiseq.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Noise.cpp # End Source File # Begin Source File SOURCE=.\tran\offset.c # End Source File # Begin Source File SOURCE=.\tran\oneshot.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\OneZero.cpp # End Source File # Begin Source File SOURCE=.\tran\osc.c # End Source File # Begin Source File SOURCE=.\tran\partial.c # End Source File # Begin Source File SOURCE=.\xlisp\path.c # End Source File # Begin Source File SOURCE=.\tran\pluck.c # End Source File # Begin Source File SOURCE=.\tran\prod.c # End Source File # Begin Source File SOURCE=.\tran\pwl.c # End Source File # Begin Source File SOURCE=.\tran\quantize.c # End Source File # Begin Source File SOURCE=.\tran\recip.c # End Source File # Begin Source File SOURCE=.\cmt\record.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\ReedTabl.cpp # End Source File # Begin Source File SOURCE=.\nyqsrc\resamp.c # End Source File # Begin Source File SOURCE=.\nyqsrc\resampv.c # End Source File # Begin Source File SOURCE=.\tran\reson.c # End Source File # Begin Source File SOURCE=.\tran\resoncv.c # End Source File # Begin Source File SOURCE=.\tran\resonvc.c # End Source File # Begin Source File SOURCE=.\tran\resonvv.c # End Source File # Begin Source File SOURCE=.\tran\sampler.c # End Source File # Begin Source File SOURCE=.\nyqsrc\samples.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Saxofony.cpp # End Source File # Begin Source File SOURCE=.\tran\scale.c # End Source File # Begin Source File SOURCE=.\cmt\seq.c # End Source File # Begin Source File SOURCE=.\nyqsrc\seqext.c # End Source File # Begin Source File SOURCE=.\nyqsrc\seqfnint.c # End Source File # Begin Source File SOURCE=.\nyqsrc\seqinterf.c # End Source File # Begin Source File SOURCE=.\cmt\seqmread.c # End Source File # Begin Source File SOURCE=.\cmt\seqmwrite.c # End Source File # Begin Source File SOURCE=.\cmt\seqread.c # End Source File # Begin Source File SOURCE=.\cmt\seqwrite.c # End Source File # Begin Source File SOURCE=.\tran\shape.c # End Source File # Begin Source File SOURCE=.\tran\sine.c # End Source File # Begin Source File SOURCE=.\tran\siosc.c # End Source File # Begin Source File SOURCE=.\tran\slope.c # End Source File # Begin Source File SOURCE=.\snd\snd.c # End Source File # Begin Source File SOURCE=.\snd\sndcvt.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndfail.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndfnint.c # End Source File # Begin Source File SOURCE=.\snd\sndheader.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndmax.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndread.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndseq.c # End Source File # Begin Source File SOURCE=.\snd\sndwin32.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sndwritepa.c # End Source File # Begin Source File SOURCE=.\nyqsrc\sound.c # End Source File # Begin Source File SOURCE=.\tran\sqrt.c # End Source File # Begin Source File SOURCE=.\nyqsrc\stats.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\Stk.cpp # End Source File # Begin Source File SOURCE=.\nyqstk\stkinit.cpp # End Source File # Begin Source File SOURCE=.\tran\tapf.c # End Source File # Begin Source File SOURCE=.\tran\tapv.c # End Source File # Begin Source File SOURCE=.\cmt\tempomap.c # End Source File # Begin Source File SOURCE=.\sys\win\wingui\textio.cpp # End Source File # Begin Source File SOURCE=.\cmt\timebase.c # End Source File # Begin Source File SOURCE=.\tran\tone.c # End Source File # Begin Source File SOURCE=.\tran\tonev.c # End Source File # Begin Source File SOURCE=.\tran\upsample.c # End Source File # Begin Source File SOURCE=.\nyqstk\src\WaveLoop.cpp # End Source File # Begin Source File SOURCE=.\tran\white.c # End Source File # Begin Source File SOURCE=.\sys\win\msvc\winfun.c # End Source File # Begin Source File SOURCE=.\sys\win\wingui\winguistuff.c # End Source File # Begin Source File SOURCE=.\sys\win\wingui\winmain.cpp # End Source File # Begin Source File SOURCE=.\sys\win\wingui\winmain.rc # End Source File # Begin Source File SOURCE=.\nyqstk\src\WvIn.cpp # End Source File # Begin Source File SOURCE=.\xlisp\xlbfun.c # End Source File # Begin Source File SOURCE=.\xlisp\xlcont.c # End Source File # Begin Source File SOURCE=.\xlisp\xldbug.c # End Source File # Begin Source File SOURCE=.\xlisp\xldmem.c # End Source File # Begin Source File SOURCE=.\xlisp\xleval.c # End Source File # Begin Source File SOURCE=.\sys\win\wingui\xlextstart.c # End Source File # Begin Source File SOURCE=.\xlisp\xlfio.c # End Source File # Begin Source File SOURCE=.\xlisp\xlftab.c # End Source File # Begin Source File SOURCE=.\xlisp\xlglob.c # End Source File # Begin Source File SOURCE=.\xlisp\xlimage.c # End Source File # Begin Source File SOURCE=.\xlisp\xlinit.c # End Source File # Begin Source File SOURCE=.\xlisp\xlio.c # End Source File # Begin Source File SOURCE=.\xlisp\xlisp.c # End Source File # Begin Source File SOURCE=.\sys\win\wingui\xlispfns.c # End Source File # Begin Source File SOURCE=.\xlisp\xljump.c # End Source File # Begin Source File SOURCE=.\xlisp\xllist.c # End Source File # Begin Source File SOURCE=.\xlisp\xlmath.c # End Source File # Begin Source File SOURCE=.\xlisp\xlobj.c # End Source File # Begin Source File SOURCE=.\xlisp\xlpp.c # End Source File # Begin Source File SOURCE=.\xlisp\xlprin.c # End Source File # Begin Source File SOURCE=.\xlisp\xlread.c # End Source File # Begin Source File SOURCE=.\xlisp\xlstr.c # End Source File # Begin Source File SOURCE=.\xlisp\xlsubr.c # End Source File # Begin Source File SOURCE=.\xlisp\xlsym.c # End Source File # Begin Source File SOURCE=.\xlisp\xlsys.c # End Source File # Begin Source File SOURCE=.\nyqsrc\yin.c # End Source File # Begin Source File SOURCE=.\nyqsrc\yin.h # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" # Begin Source File SOURCE=.\nyqsrc\add.h # End Source File # Begin Source File SOURCE=.\tran\alpass.h # End Source File # Begin Source File SOURCE=.\tran\amosc.h # End Source File # Begin Source File SOURCE=.\tran\areson.h # End Source File # Begin Source File SOURCE=.\tran\aresoncv.h # End Source File # Begin Source File SOURCE=.\tran\aresonvc.h # End Source File # Begin Source File SOURCE=.\tran\aresonvv.h # End Source File # Begin Source File SOURCE=.\tran\atone.h # End Source File # Begin Source File SOURCE=.\tran\atonev.h # End Source File # Begin Source File SOURCE=.\snd\audiont.h # End Source File # Begin Source File SOURCE=.\snd\audiowin32.h # End Source File # Begin Source File SOURCE=.\nyqsrc\avg.h # End Source File # Begin Source File SOURCE=.\tran\biquad.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\button.h # End Source File # Begin Source File SOURCE=.\cmt\cext.h # End Source File # Begin Source File SOURCE=.\tran\chase.h # End Source File # Begin Source File SOURCE=.\cmt\cleanup.h # End Source File # Begin Source File SOURCE=.\tran\clip.h # End Source File # Begin Source File SOURCE=.\cmt\cmdline.h # End Source File # Begin Source File SOURCE=.\cmt\cmtcmd.h # End Source File # Begin Source File SOURCE=.\nyqsrc\compose.h # End Source File # Begin Source File SOURCE=.\tran\congen.h # End Source File # Begin Source File SOURCE=.\tran\const.h # End Source File # Begin Source File SOURCE=.\tran\convolve.h # End Source File # Begin Source File SOURCE=.\tran\coterm.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\cppext.h # End Source File # Begin Source File SOURCE=.\nyqsrc\debug.h # End Source File # Begin Source File SOURCE=.\tran\delay.h # End Source File # Begin Source File SOURCE=.\tran\delaycv.h # End Source File # Begin Source File SOURCE=.\nyqsrc\downsample.h # End Source File # Begin Source File SOURCE=.\tran\exp.h # End Source File # Begin Source File SOURCE=.\xlisp\extern.h # End Source File # Begin Source File SOURCE=.\nyqsrc\falloc.h # End Source File # Begin Source File SOURCE=.\nyqsrc\ffilterkit.h # End Source File # Begin Source File SOURCE=.\nyqsrc\fft.h # End Source File # Begin Source File SOURCE=.\fft\fftn.h # End Source File # Begin Source File SOURCE=.\tran\fmosc.h # End Source File # Begin Source File SOURCE=.\tran\follow.h # End Source File # Begin Source File SOURCE=.\tran\fromarraystream.h # End Source File # Begin Source File SOURCE=.\tran\fromobject.h # End Source File # Begin Source File SOURCE=.\tran\gate.h # End Source File # Begin Source File SOURCE=.\snd\ieeecvt.h # End Source File # Begin Source File SOURCE=.\tran\ifft.h # End Source File # Begin Source File SOURCE=.\tran\instrclarall.h # End Source File # Begin Source File SOURCE=.\tran\instrsaxall.h # End Source File # Begin Source File SOURCE=.\tran\integrate.h # End Source File # Begin Source File SOURCE=.\nyqsrc\inverse.h # End Source File # Begin Source File SOURCE=.\tran\log.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\longque.h # End Source File # Begin Source File SOURCE=.\tran\maxv.h # End Source File # Begin Source File SOURCE=.\cmt\mem.h # End Source File # Begin Source File SOURCE=.\cmt\midifile.h # End Source File # Begin Source File SOURCE=.\cmt\midifns.h # End Source File # Begin Source File SOURCE=.\cmt\moxc.h # End Source File # Begin Source File SOURCE=.\nyqsrc\multiread.h # End Source File # Begin Source File SOURCE=.\nyqsrc\multiseq.h # End Source File # Begin Source File SOURCE=.\tran\offset.h # End Source File # Begin Source File SOURCE=.\tran\oneshot.h # End Source File # Begin Source File SOURCE=.\tran\osc.h # End Source File # Begin Source File SOURCE=.\tran\partial.h # End Source File # Begin Source File SOURCE=.\tran\pluck.h # End Source File # Begin Source File SOURCE=.\tran\prod.h # End Source File # Begin Source File SOURCE=.\tran\pwl.h # End Source File # Begin Source File SOURCE=.\tran\quantize.h # End Source File # Begin Source File SOURCE=.\tran\recip.h # End Source File # Begin Source File SOURCE=.\cmt\record.h # End Source File # Begin Source File SOURCE=.\nyqsrc\resamp.h # End Source File # Begin Source File SOURCE=.\nyqsrc\resampv.h # End Source File # Begin Source File SOURCE=.\tran\reson.h # End Source File # Begin Source File SOURCE=.\tran\resoncv.h # End Source File # Begin Source File SOURCE=.\tran\resonvc.h # End Source File # Begin Source File SOURCE=.\tran\resonvv.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\resource.h # End Source File # Begin Source File SOURCE=.\tran\sampler.h # End Source File # Begin Source File SOURCE=.\nyqsrc\samples.h # End Source File # Begin Source File SOURCE=.\tran\scale.h # End Source File # Begin Source File SOURCE=.\cmt\seq.h # End Source File # Begin Source File SOURCE=.\nyqsrc\seqext.h # End Source File # Begin Source File SOURCE=.\nyqsrc\seqinterf.h # End Source File # Begin Source File SOURCE=.\cmt\seqmread.h # End Source File # Begin Source File SOURCE=.\cmt\seqmwrite.h # End Source File # Begin Source File SOURCE=.\cmt\seqread.h # End Source File # Begin Source File SOURCE=.\cmt\seqwrite.h # End Source File # Begin Source File SOURCE=.\tran\shape.h # End Source File # Begin Source File SOURCE=.\tran\sine.h # End Source File # Begin Source File SOURCE=.\tran\siosc.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\slider.h # End Source File # Begin Source File SOURCE=.\tran\slope.h # End Source File # Begin Source File SOURCE=.\snd\snd.h # End Source File # Begin Source File SOURCE=.\snd\sndheader.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndmax.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndread.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndseq.h # End Source File # Begin Source File SOURCE=.\snd\sndwin32.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sndwrite.h # End Source File # Begin Source File SOURCE=.\nyqsrc\sound.h # End Source File # Begin Source File SOURCE=.\tran\tapv.h # End Source File # Begin Source File SOURCE=.\cmt\tempomap.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\textio.h # End Source File # Begin Source File SOURCE=.\cmt\timebase.h # End Source File # Begin Source File SOURCE=.\tran\tone.h # End Source File # Begin Source File SOURCE=.\tran\tonev.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\typein.h # End Source File # Begin Source File SOURCE=.\tran\upsample.h # End Source File # Begin Source File SOURCE=.\cmt\userio.h # End Source File # Begin Source File SOURCE=.\tran\white.h # End Source File # Begin Source File SOURCE=.\sys\win\msvc\winfun.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\winmain.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\winmain2.h # End Source File # Begin Source File SOURCE=.\xlisp\xldmem.h # End Source File # Begin Source File SOURCE=.\xlisp\xlisp.h # End Source File # Begin Source File SOURCE=.\sys\win\wingui\xlispfns.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" # Begin Source File SOURCE=.\sys\win\wingui\nycon.ico # End Source File # End Group # Begin Group "portaudio-c" # PROP Default_Filter "" # Begin Source File SOURCE=.\portaudio\pa_common\pa_allocation.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_converters.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_cpuload.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_dither.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_front.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_process.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_skeleton.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_stream.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_win\pa_win_hostapis.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_win\pa_win_util.c # End Source File # Begin Source File SOURCE=.\portaudio\pa_win_wmme\pa_win_wmme.c # End Source File # End Group # Begin Group "portaudio-h" # PROP Default_Filter "" # Begin Source File SOURCE=.\portaudio\pa_common\pa_allocation.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_converters.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_cpuload.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_dither.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_process.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_stream.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\pa_util.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_win_wmme\pa_win_wmme.h # End Source File # Begin Source File SOURCE=.\portaudio\pa_common\portaudio.h # End Source File # End Group # End Target # End Project nyquist-3.05/convert.dsp0000644000175000000620000001177210144436365014371 0ustar stevestaff# Microsoft Developer Studio Project File - Name="convert" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=convert - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "convert.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "convert.mak" CFG="convert - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "convert - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "convert - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "convert - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 !ELSEIF "$(CFG)" == "convert - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "convert___Win32_Debug" # PROP BASE Intermediate_Dir "convert___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "f:\tmp\convert-debug" # PROP Intermediate_Dir "f:\tmp\convert-debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "convert - Win32 Release" # Name "convert - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\snd\audiowin32.c # End Source File # Begin Source File SOURCE=.\snd\convert.c # End Source File # Begin Source File SOURCE=.\snd\ieeecvt.c # End Source File # Begin Source File SOURCE=.\snd\snd.c # End Source File # Begin Source File SOURCE=.\snd\sndcvt.c # End Source File # Begin Source File SOURCE=.\snd\sndheader.c # End Source File # Begin Source File SOURCE=.\snd\sndwin32.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\snd\audiowin32.h # End Source File # Begin Source File SOURCE=.\snd\ieeecvt.h # End Source File # Begin Source File SOURCE=.\snd\snd.h # End Source File # Begin Source File SOURCE=.\snd\sndconfig.h # End Source File # Begin Source File SOURCE=.\snd\sndhead.h # End Source File # Begin Source File SOURCE=.\snd\sndheader.h # End Source File # Begin Source File SOURCE=.\snd\sndwin32.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nyquist-3.05/releasenyqwin.bat0000644000175000000620000000222511466723256015556 0ustar stevestaffrmdir /s /q nyqrelwin mkdir nyqrelwin xcopy runtime nyqrelwin\runtime /s /i del nyqrelwin\runtime\CVS /q rmdir nyqrelwin\runtime\CVS /q copy sys\win\msvc\system.lsp nyqrelwin\runtime xcopy doc nyqrelwin\doc /s /i del nyqrelwin\doc\CVS /q rmdir nyqrelwin\doc\CVS /q xcopy lib nyqrelwin\lib /s /i del nyqrelwin\lib\CVS /q rmdir nyqrelwin\lib\CVS /q xcopy demos nyqrelwin\demos /s /i del nyqrelwin\demos\CVS /q rmdir nyqrelwin\demos\CVS /q del nyqrelwin\demos\pmorales\CVS /q rmdir nyqrelwin\demos\pmorales\CVS /q del nyqrelwin\demos\jones\docs /q rmdir nyqrelwin\demos\jones\docs /q del nyqrelwin\demos\jones\nydoc /q rmdir nyqrelwin\demos\jones\nydoc /q del nyqrelwin\demos\jones\sjlib /q rmdir nyqrelwin\demos\jones\sjlib /q del nyqrelwin\demos\jones /q rmdir nyqrelwin\demos\jones /q del nyqrelwin\demos\plight\kit /q rmdir nyqrelwin\demos\plight\kit /q del nyqrelwin\demos\plight /q rmdir nyqrelwin\demos\plight /q copy NyqWinRel\nyqwin.exe nyqrelwin copy liblo\test-client\Release\osc-test-client.exe nyqrelwin copy liblo\ser-to-osc\Release\ser-to-osc.exe nyqrelwin copy advantages nyqrelwin copy readme.txt nyqrelwin copy todo.txt nyqrelwin copy license.txt nyqrelwin nyquist-3.05/portaudio/0002755000175000000620000000000011537433131014174 5ustar stevestaffnyquist-3.05/portaudio/src/0002755000175000000620000000000011537433131014763 5ustar stevestaffnyquist-3.05/portaudio/src/common/0002755000175000000620000000000011537433131016253 5ustar stevestaffnyquist-3.05/portaudio/src/common/pa_allocation.h0000644000175000000620000000744611466723256021255 0ustar stevestaff#ifndef PA_ALLOCATION_H #define PA_ALLOCATION_H /* * $Id: pa_allocation.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library allocation context header * memory allocation context for tracking allocation groups * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Allocation Group prototypes. An Allocation Group makes it easy to allocate multiple blocks of memory and free them all simultanously. An allocation group is useful for keeping track of multiple blocks of memory which are allocated at the same time (such as during initialization) and need to be deallocated at the same time. The allocation group maintains a list of allocated blocks, and can deallocate them all simultaneously which can be usefull for cleaning up after a partially initialized object fails. The allocation group implementation is built on top of the lower level allocation functions defined in pa_util.h */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct { long linkCount; struct PaUtilAllocationGroupLink *linkBlocks; struct PaUtilAllocationGroupLink *spareLinks; struct PaUtilAllocationGroupLink *allocations; }PaUtilAllocationGroup; /** Create an allocation group. */ PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void ); /** Destroy an allocation group, but not the memory allocated through the group. */ void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ); /** Allocate a block of memory though an allocation group. */ void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ); /** Free a block of memory that was previously allocated though an allocation group. Calling this function is a relatively time consuming operation. Under normal circumstances clients should call PaUtil_FreeAllAllocations to free all allocated blocks simultaneously. @see PaUtil_FreeAllAllocations */ void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ); /** Free all blocks of memory which have been allocated through the allocation group. This function doesn't destroy the group itself. */ void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_ALLOCATION_H */ nyquist-3.05/portaudio/src/common/pa_dither.h0000644000175000000620000000645411466723256020405 0ustar stevestaff#ifndef PA_DITHER_H #define PA_DITHER_H /* * $Id: pa_dither.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library triangular dither generator * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Phil Burk, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Functions for generating dither noise */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** @brief State needed to generate a dither signal */ typedef struct PaUtilTriangularDitherGenerator{ unsigned long previous; unsigned long randSeed1; unsigned long randSeed2; } PaUtilTriangularDitherGenerator; /** @brief Initialize dither state */ void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState ); /** @brief Calculate 2 LSB dither signal with a triangular distribution. Ranged for adding to a 1 bit right-shifted 32 bit integer prior to >>15. eg:
        signed long in = *
        signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
        signed short out = (signed short)(((in>>1) + dither) >> 15);
    
    @return A signed long with a range of +32767 to -32768 */ signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); /** @brief Calculate 2 LSB dither signal with a triangular distribution. Ranged for adding to a pre-scaled float.
        float in = *
        float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
        // use smaller scaler to prevent overflow when we add the dither
        signed short out = (signed short)(in*(32766.0f) + dither );
    
    @return A float with a range of -2.0 to +1.99999. */ float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_DITHER_H */ nyquist-3.05/portaudio/src/common/pa_endianness.h0000644000175000000620000001242511466723256021250 0ustar stevestaff#ifndef PA_ENDIANNESS_H #define PA_ENDIANNESS_H /* * $Id: pa_endianness.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library current platform endianness macros * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Phil Burk, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Configure endianness symbols for the target processor. Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols to be defined. The one that is defined reflects the endianness of the target platform and may be used to implement conditional compilation of byte-order dependent code. If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt is made to override that setting. This may be useful if you have a better way of determining the platform's endianness. The autoconf mechanism uses this for example. A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time and runtime endiannes and raise an assertion if they don't match. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* If this is an apple, we need to do detect endianness this way */ #if defined(__APPLE__) /* we need to do some endian detection that is sensitive to harware arch */ #if defined(__LITTLE_ENDIAN__) #if !defined( PA_LITTLE_ENDIAN ) #define PA_LITTLE_ENDIAN #endif #if defined( PA_BIG_ENDIAN ) #undef PA_BIG_ENDIAN #endif #else #if !defined( PA_BIG_ENDIAN ) #define PA_BIG_ENDIAN #endif #if defined( PA_LITTLE_ENDIAN ) #undef PA_LITTLE_ENDIAN #endif #endif #else /* this is not an apple, so first check the existing defines, and, failing that, detect well-known architechtures. */ #if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN) /* endianness define has been set externally, such as by autoconf */ #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN) #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please #endif #else /* endianness define has not been set externally */ /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(LITTLE_ENDIAN) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */ #else #define PA_BIG_ENDIAN #endif #endif #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN) /* If the following error is raised, you either need to modify the code above to automatically determine the endianness from other symbols defined on your platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally. */ #error pa_endianness.h was unable to automatically determine the endianness of the target platform #endif #endif /* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness, and raises an assertion if they don't match. must be included in the context in which this macro is used. */ #if defined(PA_LITTLE_ENDIAN) #define PA_VALIDATE_ENDIANNESS \ { \ const long nativeOne = 1; \ assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \ } #elif defined(PA_BIG_ENDIAN) #define PA_VALIDATE_ENDIANNESS \ { \ const long nativeOne = 1; \ assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \ } #endif #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_ENDIANNESS_H */ nyquist-3.05/portaudio/src/common/pa_front.c0000644000175000000620000015203511466723256020246 0ustar stevestaff/* * $Id: pa_front.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library Multi-Host API front end * Validate function parameters and manage multiple host APIs. * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Implements public PortAudio API, checks some errors, forwards to host API implementations. Implements the functions defined in the PortAudio API, checks for some parameter and state inconsistencies and forwards API requests to specific Host API implementations (via the interface declared in pa_hostapi.h), and Streams (via the interface declared in pa_stream.h). This file handles initialization and termination of Host API implementations via initializers stored in the paHostApiInitializers global variable. Some utility functions declared in pa_util.h are implemented in this file. All PortAudio API functions can be conditionally compiled with logging code. To compile with logging, define the PA_LOG_API_CALLS precompiler symbol. @todo Consider adding host API specific error text in Pa_GetErrorText() for paUnanticipatedHostError @todo Consider adding a new error code for when (inputParameters == NULL) && (outputParameters == NULL) @todo review whether Pa_CloseStream() should call the interface's CloseStream function if aborting the stream returns an error code. @todo Create new error codes if a NULL buffer pointer, or a zero frame count is passed to Pa_ReadStream or Pa_WriteStream. */ #include #include #include #include /* needed by PA_VALIDATE_ENDIANNESS */ #include "portaudio.h" #include "pa_util.h" #include "pa_endianness.h" #include "pa_types.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_trace.h" /* still usefull?*/ #include "pa_debugprint.h" #define PA_VERSION_ 1899 #define PA_VERSION_TEXT_ "PortAudio V19-devel (built " __DATE__ ")" int Pa_GetVersion( void ) { return PA_VERSION_; } const char* Pa_GetVersionText( void ) { return PA_VERSION_TEXT_; } #define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024 static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0}; static PaHostErrorInfo lastHostErrorInfo_ = { (PaHostApiTypeId)-1, 0, lastHostErrorText_ }; void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, const char *errorText ) { lastHostErrorInfo_.hostApiType = hostApiType; lastHostErrorInfo_.errorCode = errorCode; strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ ); } static PaUtilHostApiRepresentation **hostApis_ = 0; static int hostApisCount_ = 0; static int initializationCount_ = 0; static int deviceCount_ = 0; PaUtilStreamRepresentation *firstOpenStream_ = NULL; #define PA_IS_INITIALISED_ (initializationCount_ != 0) static int CountHostApiInitializers( void ) { int result = 0; while( paHostApiInitializers[ result ] != 0 ) ++result; return result; } static void TerminateHostApis( void ) { /* terminate in reverse order from initialization */ PA_DEBUG(("TerminateHostApis in \n")); while( hostApisCount_ > 0 ) { --hostApisCount_; hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] ); } hostApisCount_ = 0; deviceCount_ = 0; if( hostApis_ != 0 ) PaUtil_FreeMemory( hostApis_ ); hostApis_ = 0; PA_DEBUG(("TerminateHostApis out\n")); } static PaError InitializeHostApis( void ) { PaError result = paNoError; int i, initializerCount, baseDeviceIndex; initializerCount = CountHostApiInitializers(); hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory( sizeof(PaUtilHostApiRepresentation*) * initializerCount ); if( !hostApis_ ) { result = paInsufficientMemory; goto error; } hostApisCount_ = 0; deviceCount_ = 0; baseDeviceIndex = 0; for( i=0; i< initializerCount; ++i ) { hostApis_[hostApisCount_] = NULL; PA_DEBUG(( "before paHostApiInitializers[%d].\n",i)); result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ ); if( result != paNoError ) goto error; PA_DEBUG(( "after paHostApiInitializers[%d].\n",i)); if( hostApis_[hostApisCount_] ) { PaUtilHostApiRepresentation* hostApi = hostApis_[hostApisCount_]; assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount ); assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount ); hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex; if( hostApi->info.defaultInputDevice != paNoDevice ) hostApi->info.defaultInputDevice += baseDeviceIndex; if( hostApi->info.defaultOutputDevice != paNoDevice ) hostApi->info.defaultOutputDevice += baseDeviceIndex; baseDeviceIndex += hostApi->info.deviceCount; deviceCount_ += hostApi->info.deviceCount; ++hostApisCount_; } } return result; error: TerminateHostApis(); return result; } /* FindHostApi() finds the index of the host api to which belongs and returns it. if is non-null, the host specific device index is returned in it. returns -1 if is out of range. */ static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex ) { int i=0; if( !PA_IS_INITIALISED_ ) return -1; if( device < 0 ) return -1; while( i < hostApisCount_ && device >= hostApis_[i]->info.deviceCount ) { device -= hostApis_[i]->info.deviceCount; ++i; } if( i >= hostApisCount_ ) return -1; if( hostSpecificDeviceIndex ) *hostSpecificDeviceIndex = device; return i; } static void AddOpenStream( PaStream* stream ) { ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_; firstOpenStream_ = (PaUtilStreamRepresentation*)stream; } static void RemoveOpenStream( PaStream* stream ) { PaUtilStreamRepresentation *previous = NULL; PaUtilStreamRepresentation *current = firstOpenStream_; while( current != NULL ) { if( ((PaStream*)current) == stream ) { if( previous == NULL ) { firstOpenStream_ = current->nextOpenStream; } else { previous->nextOpenStream = current->nextOpenStream; } return; } else { previous = current; current = current->nextOpenStream; } } } static void CloseOpenStreams( void ) { /* we call Pa_CloseStream() here to ensure that the same destruction logic is used for automatically closed streams */ while( firstOpenStream_ != NULL ) Pa_CloseStream( firstOpenStream_ ); } PaError Pa_Initialize( void ) { PaError result; PA_LOGAPI_ENTER( "Pa_Initialize" ); if( PA_IS_INITIALISED_ ) { ++initializationCount_; result = paNoError; } else { PA_VALIDATE_TYPE_SIZES; PA_VALIDATE_ENDIANNESS; PaUtil_InitializeClock(); PaUtil_ResetTraceMessages(); result = InitializeHostApis(); if( result == paNoError ) ++initializationCount_; } PA_LOGAPI_EXIT_PAERROR( "Pa_Initialize", result ); return result; } PaError Pa_Terminate( void ) { PaError result; PA_LOGAPI_ENTER( "Pa_Terminate" ); if( PA_IS_INITIALISED_ ) { if( --initializationCount_ == 0 ) { CloseOpenStreams(); TerminateHostApis(); PaUtil_DumpTraceMessages(); } result = paNoError; } else { result= paNotInitialized; } PA_LOGAPI_EXIT_PAERROR( "Pa_Terminate", result ); return result; } const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ) { return &lastHostErrorInfo_; } const char *Pa_GetErrorText( PaError errorCode ) { const char *result; switch( errorCode ) { case paNoError: result = "Success"; break; case paNotInitialized: result = "PortAudio not initialized"; break; /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */ case paUnanticipatedHostError: result = "Unanticipated host error"; break; case paInvalidChannelCount: result = "Invalid number of channels"; break; case paInvalidSampleRate: result = "Invalid sample rate"; break; case paInvalidDevice: result = "Invalid device"; break; case paInvalidFlag: result = "Invalid flag"; break; case paSampleFormatNotSupported: result = "Sample format not supported"; break; case paBadIODeviceCombination: result = "Illegal combination of I/O devices"; break; case paInsufficientMemory: result = "Insufficient memory"; break; case paBufferTooBig: result = "Buffer too big"; break; case paBufferTooSmall: result = "Buffer too small"; break; case paNullCallback: result = "No callback routine specified"; break; case paBadStreamPtr: result = "Invalid stream pointer"; break; case paTimedOut: result = "Wait timed out"; break; case paInternalError: result = "Internal PortAudio error"; break; case paDeviceUnavailable: result = "Device unavailable"; break; case paIncompatibleHostApiSpecificStreamInfo: result = "Incompatible host API specific stream info"; break; case paStreamIsStopped: result = "Stream is stopped"; break; case paStreamIsNotStopped: result = "Stream is not stopped"; break; case paInputOverflowed: result = "Input overflowed"; break; case paOutputUnderflowed: result = "Output underflowed"; break; case paHostApiNotFound: result = "Host API not found"; break; case paInvalidHostApi: result = "Invalid host API"; break; case paCanNotReadFromACallbackStream: result = "Can't read from a callback stream"; break; case paCanNotWriteToACallbackStream: result = "Can't write to a callback stream"; break; case paCanNotReadFromAnOutputOnlyStream: result = "Can't read from an output only stream"; break; case paCanNotWriteToAnInputOnlyStream: result = "Can't write to an input only stream"; break; default: if( errorCode > 0 ) result = "Invalid error code (value greater than zero)"; else result = "Invalid error code"; break; } return result; } PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ) { PaHostApiIndex result; int i; PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiTypeIdToHostApiIndex" ); PA_LOGAPI(("\tPaHostApiTypeId type: %d\n", type )); if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; } else { result = paHostApiNotFound; for( i=0; i < hostApisCount_; ++i ) { if( hostApis_[i]->info.type == type ) { result = i; break; } } } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_HostApiTypeIdToHostApiIndex", "PaHostApiIndex: %d", result ); return result; } PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, PaHostApiTypeId type ) { PaError result; int i; if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; } else { result = paHostApiNotFound; for( i=0; i < hostApisCount_; ++i ) { if( hostApis_[i]->info.type == type ) { *hostApi = hostApis_[i]; result = paNoError; break; } } } return result; } PaError PaUtil_DeviceIndexToHostApiDeviceIndex( PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi ) { PaError result; PaDeviceIndex x; x = device - hostApi->privatePaFrontInfo.baseDeviceIndex; if( x < 0 || x >= hostApi->info.deviceCount ) { result = paInvalidDevice; } else { *hostApiDevice = x; result = paNoError; } return result; } PaHostApiIndex Pa_GetHostApiCount( void ) { int result; PA_LOGAPI_ENTER( "Pa_GetHostApiCount" ); if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; } else { result = hostApisCount_; } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetHostApiCount", "PaHostApiIndex: %d", result ); return result; } PaHostApiIndex Pa_GetDefaultHostApi( void ) { int result; PA_LOGAPI_ENTER( "Pa_GetDefaultHostApi" ); if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; } else { result = paDefaultHostApiIndex; /* internal consistency check: make sure that the default host api index is within range */ if( result < 0 || result >= hostApisCount_ ) { result = paInternalError; } } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDefaultHostApi", "PaHostApiIndex: %d", result ); return result; } const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi ) { PaHostApiInfo *info; PA_LOGAPI_ENTER_PARAMS( "Pa_GetHostApiInfo" ); PA_LOGAPI(("\tPaHostApiIndex hostApi: %d\n", hostApi )); if( !PA_IS_INITIALISED_ ) { info = NULL; PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); PA_LOGAPI(("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n" )); } else if( hostApi < 0 || hostApi >= hostApisCount_ ) { info = NULL; PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); PA_LOGAPI(("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n" )); } else { info = &hostApis_[hostApi]->info; PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); PA_LOGAPI(("\tPaHostApiInfo*: 0x%p\n", info )); PA_LOGAPI(("\t{\n" )); PA_LOGAPI(("\t\tint structVersion: %d\n", info->structVersion )); PA_LOGAPI(("\t\tPaHostApiTypeId type: %d\n", info->type )); PA_LOGAPI(("\t\tconst char *name: %s\n", info->name )); PA_LOGAPI(("\t}\n" )); } return info; } PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex ) { PaDeviceIndex result; PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiDeviceIndexToPaDeviceIndex" ); PA_LOGAPI(("\tPaHostApiIndex hostApi: %d\n", hostApi )); PA_LOGAPI(("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex )); if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; } else { if( hostApi < 0 || hostApi >= hostApisCount_ ) { result = paInvalidHostApi; } else { if( hostApiDeviceIndex < 0 || hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount ) { result = paInvalidDevice; } else { result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex; } } } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_HostApiDeviceIndexToPaDeviceIndex", "PaDeviceIndex: %d", result ); return result; } PaDeviceIndex Pa_GetDeviceCount( void ) { PaDeviceIndex result; PA_LOGAPI_ENTER( "Pa_GetDeviceCount" ); if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; } else { result = deviceCount_; } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDeviceCount", "PaDeviceIndex: %d", result ); return result; } PaDeviceIndex Pa_GetDefaultInputDevice( void ) { PaHostApiIndex hostApi; PaDeviceIndex result; PA_LOGAPI_ENTER( "Pa_GetDefaultInputDevice" ); hostApi = Pa_GetDefaultHostApi(); if( hostApi < 0 ) { result = paNoDevice; } else { result = hostApis_[hostApi]->info.defaultInputDevice; } PA_LOGAPI_EXIT_T( "Pa_GetDefaultInputDevice", "PaDeviceIndex: %d", result ); return result; } PaDeviceIndex Pa_GetDefaultOutputDevice( void ) { PaHostApiIndex hostApi; PaDeviceIndex result; PA_LOGAPI_ENTER( "Pa_GetDefaultOutputDevice" ); hostApi = Pa_GetDefaultHostApi(); if( hostApi < 0 ) { result = paNoDevice; } else { result = hostApis_[hostApi]->info.defaultOutputDevice; } PA_LOGAPI_EXIT_T( "Pa_GetDefaultOutputDevice", "PaDeviceIndex: %d", result ); return result; } const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ) { int hostSpecificDeviceIndex; int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex ); PaDeviceInfo *result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetDeviceInfo" ); PA_LOGAPI(("\tPaDeviceIndex device: %d\n", device )); if( hostApiIndex < 0 ) { result = NULL; PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" )); PA_LOGAPI(("\tPaDeviceInfo* NULL [ invalid device index ]\n" )); } else { result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ]; PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" )); PA_LOGAPI(("\tPaDeviceInfo*: 0x%p:\n", result )); PA_LOGAPI(("\t{\n" )); PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion )); PA_LOGAPI(("\t\tconst char *name: %s\n", result->name )); PA_LOGAPI(("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi )); PA_LOGAPI(("\t\tint maxInputChannels: %d\n", result->maxInputChannels )); PA_LOGAPI(("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels )); PA_LOGAPI(("\t}\n" )); } return result; } /* SampleFormatIsValid() returns 1 if sampleFormat is a sample format defined in portaudio.h, or 0 otherwise. */ static int SampleFormatIsValid( PaSampleFormat format ) { switch( format & ~paNonInterleaved ) { case paFloat32: return 1; case paInt16: return 1; case paInt32: return 1; case paInt24: return 1; case paInt8: return 1; case paUInt8: return 1; case paCustomFormat: return 1; default: return 0; } } /* NOTE: make sure this validation list is kept syncronised with the one in pa_hostapi.h ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream() conform to the expected values as described below. This function is also designed to be used with the proposed Pa_IsFormatSupported() function. There are basically two types of validation that could be performed: Generic conformance validation, and device capability mismatch validation. This function performs only generic conformance validation. Validation that would require knowledge of device capabilities is not performed because of potentially complex relationships between combinations of parameters - for example, even if the sampleRate seems ok, it might not be for a duplex stream - we have no way of checking this in an API-neutral way, so we don't try. On success the function returns PaNoError and fills in hostApi, hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure the function returns an error code indicating the first encountered parameter error. If ValidateOpenStreamParameters() returns paNoError, the following assertions are guaranteed to be true. - at least one of inputParameters & outputParmeters is valid (not NULL) - if inputParameters & outputParameters are both valid, that inputParameters->device & outputParameters->device both use the same host api PaDeviceIndex inputParameters->device - is within range (0 to Pa_GetDeviceCount-1) Or: - is paUseHostApiSpecificDeviceSpecification and inputParameters->hostApiSpecificStreamInfo is non-NULL and refers to a valid host api int inputParameters->channelCount - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0 - upper bound is NOT validated against device capabilities PaSampleFormat inputParameters->sampleFormat - is one of the sample formats defined in portaudio.h void *inputParameters->hostApiSpecificStreamInfo - if supplied its hostApi field matches the input device's host Api PaDeviceIndex outputParmeters->device - is within range (0 to Pa_GetDeviceCount-1) int outputParmeters->channelCount - if inputDevice is valid, channelCount is > 0 - upper bound is NOT validated against device capabilities PaSampleFormat outputParmeters->sampleFormat - is one of the sample formats defined in portaudio.h void *outputParmeters->hostApiSpecificStreamInfo - if supplied its hostApi field matches the output device's host Api double sampleRate - is not an 'absurd' rate (less than 1000. or greater than 200000.) - sampleRate is NOT validated against device capabilities PaStreamFlags streamFlags - unused platform neutral flags are zero - paNeverDropInput is only used for full-duplex callback streams with variable buffer size (paFramesPerBufferUnspecified) */ static PaError ValidateOpenStreamParameters( const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, PaUtilHostApiRepresentation **hostApi, PaDeviceIndex *hostApiInputDevice, PaDeviceIndex *hostApiOutputDevice ) { int inputHostApiIndex = -1, /* Surpress uninitialised var warnings: compiler does */ outputHostApiIndex = -1; /* not see that if inputParameters and outputParame- */ /* ters are both nonzero, these indices are set. */ if( (inputParameters == NULL) && (outputParameters == NULL) ) { return paInvalidDevice; /** @todo should be a new error code "invalid device parameters" or something */ } else { if( inputParameters == NULL ) { *hostApiInputDevice = paNoDevice; } else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) { if( inputParameters->hostApiSpecificStreamInfo ) { inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType ); if( inputHostApiIndex != -1 ) { *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification; *hostApi = hostApis_[inputHostApiIndex]; } else { return paInvalidDevice; } } else { return paInvalidDevice; } } else { if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ ) return paInvalidDevice; inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice ); if( inputHostApiIndex < 0 ) return paInternalError; *hostApi = hostApis_[inputHostApiIndex]; if( inputParameters->channelCount <= 0 ) return paInvalidChannelCount; if( !SampleFormatIsValid( inputParameters->sampleFormat ) ) return paSampleFormatNotSupported; if( inputParameters->hostApiSpecificStreamInfo != NULL ) { if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType != (*hostApi)->info.type ) return paIncompatibleHostApiSpecificStreamInfo; } } if( outputParameters == NULL ) { *hostApiOutputDevice = paNoDevice; } else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) { if( outputParameters->hostApiSpecificStreamInfo ) { outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType ); if( outputHostApiIndex != -1 ) { *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification; *hostApi = hostApis_[outputHostApiIndex]; } else { return paInvalidDevice; } } else { return paInvalidDevice; } } else { if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ ) return paInvalidDevice; outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice ); if( outputHostApiIndex < 0 ) return paInternalError; *hostApi = hostApis_[outputHostApiIndex]; if( outputParameters->channelCount <= 0 ) return paInvalidChannelCount; if( !SampleFormatIsValid( outputParameters->sampleFormat ) ) return paSampleFormatNotSupported; if( outputParameters->hostApiSpecificStreamInfo != NULL ) { if( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType != (*hostApi)->info.type ) return paIncompatibleHostApiSpecificStreamInfo; } } if( (inputParameters != NULL) && (outputParameters != NULL) ) { /* ensure that both devices use the same API */ if( inputHostApiIndex != outputHostApiIndex ) return paBadIODeviceCombination; } } /* Check for absurd sample rates. */ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) ) return paInvalidSampleRate; if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 ) return paInvalidFlag; if( streamFlags & paNeverDropInput ) { /* must be a callback stream */ if( !streamCallback ) return paInvalidFlag; /* must be a full duplex stream */ if( (inputParameters == NULL) || (outputParameters == NULL) ) return paInvalidFlag; /* must use paFramesPerBufferUnspecified */ if( framesPerBuffer != paFramesPerBufferUnspecified ) return paInvalidFlag; } return paNoError; } PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaError result; PaUtilHostApiRepresentation *hostApi = 0; PaDeviceIndex hostApiInputDevice = paNoDevice, hostApiOutputDevice = paNoDevice; PaStreamParameters hostApiInputParameters, hostApiOutputParameters; PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; #ifdef PA_LOG_API_CALLS PA_LOGAPI_ENTER_PARAMS( "Pa_IsFormatSupported" ); if( inputParameters == NULL ){ PA_LOGAPI(("\tPaStreamParameters *inputParameters: NULL\n" )); }else{ PA_LOGAPI(("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters )); PA_LOGAPI(("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device )); PA_LOGAPI(("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount )); PA_LOGAPI(("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat )); PA_LOGAPI(("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency )); PA_LOGAPI(("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo )); } if( outputParameters == NULL ){ PA_LOGAPI(("\tPaStreamParameters *outputParameters: NULL\n" )); }else{ PA_LOGAPI(("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters )); PA_LOGAPI(("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device )); PA_LOGAPI(("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount )); PA_LOGAPI(("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat )); PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency )); PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo )); } PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); #endif if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result ); return result; } result = ValidateOpenStreamParameters( inputParameters, outputParameters, sampleRate, 0, paNoFlag, 0, &hostApi, &hostApiInputDevice, &hostApiOutputDevice ); if( result != paNoError ) { PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result ); return result; } if( inputParameters ) { hostApiInputParameters.device = hostApiInputDevice; hostApiInputParameters.channelCount = inputParameters->channelCount; hostApiInputParameters.sampleFormat = inputParameters->sampleFormat; hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency; hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo; hostApiInputParametersPtr = &hostApiInputParameters; } else { hostApiInputParametersPtr = NULL; } if( outputParameters ) { hostApiOutputParameters.device = hostApiOutputDevice; hostApiOutputParameters.channelCount = outputParameters->channelCount; hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat; hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency; hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo; hostApiOutputParametersPtr = &hostApiOutputParameters; } else { hostApiOutputParametersPtr = NULL; } result = hostApi->IsFormatSupported( hostApi, hostApiInputParametersPtr, hostApiOutputParametersPtr, sampleRate ); #ifdef PA_LOG_API_CALLS PA_LOGAPI(("Pa_OpenStream returned:\n" )); if( result == paFormatIsSupported ) PA_LOGAPI(("\tPaError: 0 [ paFormatIsSupported ]\n" )); else PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); #endif return result; } PaError Pa_OpenStream( PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result; PaUtilHostApiRepresentation *hostApi = 0; PaDeviceIndex hostApiInputDevice = paNoDevice, hostApiOutputDevice = paNoDevice; PaStreamParameters hostApiInputParameters, hostApiOutputParameters; PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; #ifdef PA_LOG_API_CALLS PA_LOGAPI_ENTER_PARAMS( "Pa_OpenStream" ); PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream )); if( inputParameters == NULL ){ PA_LOGAPI(("\tPaStreamParameters *inputParameters: NULL\n" )); }else{ PA_LOGAPI(("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters )); PA_LOGAPI(("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device )); PA_LOGAPI(("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount )); PA_LOGAPI(("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat )); PA_LOGAPI(("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency )); PA_LOGAPI(("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo )); } if( outputParameters == NULL ){ PA_LOGAPI(("\tPaStreamParameters *outputParameters: NULL\n" )); }else{ PA_LOGAPI(("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters )); PA_LOGAPI(("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device )); PA_LOGAPI(("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount )); PA_LOGAPI(("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat )); PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency )); PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo )); } PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer )); PA_LOGAPI(("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags )); PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback )); PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData )); #endif if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; PA_LOGAPI(("Pa_OpenStream returned:\n" )); PA_LOGAPI(("\t*(PaStream** stream): undefined\n" )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); return result; } /* Check for parameter errors. NOTE: make sure this validation list is kept syncronised with the one in pa_hostapi.h */ if( stream == NULL ) { result = paBadStreamPtr; PA_LOGAPI(("Pa_OpenStream returned:\n" )); PA_LOGAPI(("\t*(PaStream** stream): undefined\n" )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); return result; } result = ValidateOpenStreamParameters( inputParameters, outputParameters, sampleRate, framesPerBuffer, streamFlags, streamCallback, &hostApi, &hostApiInputDevice, &hostApiOutputDevice ); if( result != paNoError ) { PA_LOGAPI(("Pa_OpenStream returned:\n" )); PA_LOGAPI(("\t*(PaStream** stream): undefined\n" )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); return result; } if( inputParameters ) { hostApiInputParameters.device = hostApiInputDevice; hostApiInputParameters.channelCount = inputParameters->channelCount; hostApiInputParameters.sampleFormat = inputParameters->sampleFormat; hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency; hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo; hostApiInputParametersPtr = &hostApiInputParameters; } else { hostApiInputParametersPtr = NULL; } if( outputParameters ) { hostApiOutputParameters.device = hostApiOutputDevice; hostApiOutputParameters.channelCount = outputParameters->channelCount; hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat; hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency; hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo; hostApiOutputParametersPtr = &hostApiOutputParameters; } else { hostApiOutputParametersPtr = NULL; } result = hostApi->OpenStream( hostApi, stream, hostApiInputParametersPtr, hostApiOutputParametersPtr, sampleRate, framesPerBuffer, streamFlags, streamCallback, userData ); if( result == paNoError ) AddOpenStream( *stream ); PA_LOGAPI(("Pa_OpenStream returned:\n" )); PA_LOGAPI(("\t*(PaStream** stream): 0x%p\n", *stream )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); return result; } PaError Pa_OpenDefaultStream( PaStream** stream, int inputChannelCount, int outputChannelCount, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, PaStreamCallback *streamCallback, void *userData ) { PaError result; PaStreamParameters hostApiInputParameters, hostApiOutputParameters; PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; PA_LOGAPI_ENTER_PARAMS( "Pa_OpenDefaultStream" ); PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream )); PA_LOGAPI(("\tint inputChannelCount: %d\n", inputChannelCount )); PA_LOGAPI(("\tint outputChannelCount: %d\n", outputChannelCount )); PA_LOGAPI(("\tPaSampleFormat sampleFormat: %d\n", sampleFormat )); PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer )); PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback )); PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData )); if( inputChannelCount > 0 ) { hostApiInputParameters.device = Pa_GetDefaultInputDevice(); if( hostApiInputParameters.device == paNoDevice ) return paDeviceUnavailable; hostApiInputParameters.channelCount = inputChannelCount; hostApiInputParameters.sampleFormat = sampleFormat; /* defaultHighInputLatency is used below instead of defaultLowInputLatency because it is more important for the default stream to work reliably than it is for it to work with the lowest latency. */ hostApiInputParameters.suggestedLatency = Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency; hostApiInputParameters.hostApiSpecificStreamInfo = NULL; hostApiInputParametersPtr = &hostApiInputParameters; } else { hostApiInputParametersPtr = NULL; } if( outputChannelCount > 0 ) { hostApiOutputParameters.device = Pa_GetDefaultOutputDevice(); if( hostApiOutputParameters.device == paNoDevice ) return paDeviceUnavailable; hostApiOutputParameters.channelCount = outputChannelCount; hostApiOutputParameters.sampleFormat = sampleFormat; /* defaultHighOutputLatency is used below instead of defaultLowOutputLatency because it is more important for the default stream to work reliably than it is for it to work with the lowest latency. */ hostApiOutputParameters.suggestedLatency = Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency; hostApiOutputParameters.hostApiSpecificStreamInfo = NULL; hostApiOutputParametersPtr = &hostApiOutputParameters; } else { hostApiOutputParametersPtr = NULL; } result = Pa_OpenStream( stream, hostApiInputParametersPtr, hostApiOutputParametersPtr, sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData ); PA_LOGAPI(("Pa_OpenDefaultStream returned:\n" )); PA_LOGAPI(("\t*(PaStream** stream): 0x%p", *stream )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); return result; } PaError PaUtil_ValidateStreamPointer( PaStream* stream ) { if( !PA_IS_INITIALISED_ ) return paNotInitialized; if( stream == NULL ) return paBadStreamPtr; if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC ) return paBadStreamPtr; return paNoError; } PaError Pa_CloseStream( PaStream* stream ) { PaUtilStreamInterface *interface; PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_CloseStream" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); /* always remove the open stream from our list, even if this function eventually returns an error. Otherwise CloseOpenStreams() will get stuck in an infinite loop */ RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */ if( result == paNoError ) { interface = PA_STREAM_INTERFACE(stream); /* abort the stream if it isn't stopped */ result = interface->IsStopped( stream ); if( result == 1 ) result = paNoError; else if( result == 0 ) result = interface->Abort( stream ); if( result == paNoError ) /** @todo REVIEW: shouldn't we close anyway? */ result = interface->Close( stream ); } PA_LOGAPI_EXIT_PAERROR( "Pa_CloseStream", result ); return result; } PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_SetStreamFinishedCallback" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); PA_LOGAPI(("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback )); if( result == paNoError ) { result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); if( result == 0 ) { result = paStreamIsNotStopped ; } if( result == 1 ) { PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback; result = paNoError; } } PA_LOGAPI_EXIT_PAERROR( "Pa_SetStreamFinishedCallback", result ); return result; } PaError Pa_StartStream( PaStream *stream ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_StartStream" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) { result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); if( result == 0 ) { result = paStreamIsNotStopped ; } else if( result == 1 ) { result = PA_STREAM_INTERFACE(stream)->Start( stream ); } } PA_LOGAPI_EXIT_PAERROR( "Pa_StartStream", result ); return result; } PaError Pa_StopStream( PaStream *stream ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_StopStream" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) { result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); if( result == 0 ) { result = PA_STREAM_INTERFACE(stream)->Stop( stream ); } else if( result == 1 ) { result = paStreamIsStopped; } } PA_LOGAPI_EXIT_PAERROR( "Pa_StopStream", result ); return result; } PaError Pa_AbortStream( PaStream *stream ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_AbortStream" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) { result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); if( result == 0 ) { result = PA_STREAM_INTERFACE(stream)->Abort( stream ); } else if( result == 1 ) { result = paStreamIsStopped; } } PA_LOGAPI_EXIT_PAERROR( "Pa_AbortStream", result ); return result; } PaError Pa_IsStreamStopped( PaStream *stream ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamStopped" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamStopped", result ); return result; } PaError Pa_IsStreamActive( PaStream *stream ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamActive" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) result = PA_STREAM_INTERFACE(stream)->IsActive( stream ); PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamActive", result ); return result; } const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ) { PaError error = PaUtil_ValidateStreamPointer( stream ); const PaStreamInfo *result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamInfo" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( error != paNoError ) { result = 0; PA_LOGAPI(("Pa_GetStreamInfo returned:\n" )); PA_LOGAPI(("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n", result, error, Pa_GetErrorText( error ) )); } else { result = &PA_STREAM_REP( stream )->streamInfo; PA_LOGAPI(("Pa_GetStreamInfo returned:\n" )); PA_LOGAPI(("\tconst PaStreamInfo*: 0x%p:\n", result )); PA_LOGAPI(("\t{" )); PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion )); PA_LOGAPI(("\t\tPaTime inputLatency: %f\n", result->inputLatency )); PA_LOGAPI(("\t\tPaTime outputLatency: %f\n", result->outputLatency )); PA_LOGAPI(("\t\tdouble sampleRate: %f\n", result->sampleRate )); PA_LOGAPI(("\t}\n" )); } return result; } PaTime Pa_GetStreamTime( PaStream *stream ) { PaError error = PaUtil_ValidateStreamPointer( stream ); PaTime result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamTime" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( error != paNoError ) { result = 0; PA_LOGAPI(("Pa_GetStreamTime returned:\n" )); PA_LOGAPI(("\tPaTime: 0 [PaError error:%d ( %s )]\n", result, error, Pa_GetErrorText( error ) )); } else { result = PA_STREAM_INTERFACE(stream)->GetTime( stream ); PA_LOGAPI(("Pa_GetStreamTime returned:\n" )); PA_LOGAPI(("\tPaTime: %g\n", result )); } return result; } double Pa_GetStreamCpuLoad( PaStream* stream ) { PaError error = PaUtil_ValidateStreamPointer( stream ); double result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamCpuLoad" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( error != paNoError ) { result = 0.0; PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" )); PA_LOGAPI(("\tdouble: 0.0 [PaError error: %d ( %s )]\n", error, Pa_GetErrorText( error ) )); } else { result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream ); PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" )); PA_LOGAPI(("\tdouble: %g\n", result )); } return result; } PaError Pa_ReadStream( PaStream* stream, void *buffer, unsigned long frames ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_ReadStream" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) { if( frames == 0 ) { /* XXX: Should we not allow the implementation to signal any overflow condition? */ result = paNoError; } else if( buffer == 0 ) { result = paBadBufferPtr; } else { result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); if( result == 0 ) { result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames ); } else if( result == 1 ) { result = paStreamIsStopped; } } } PA_LOGAPI_EXIT_PAERROR( "Pa_ReadStream", result ); return result; } PaError Pa_WriteStream( PaStream* stream, const void *buffer, unsigned long frames ) { PaError result = PaUtil_ValidateStreamPointer( stream ); PA_LOGAPI_ENTER_PARAMS( "Pa_WriteStream" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( result == paNoError ) { if( frames == 0 ) { /* XXX: Should we not allow the implementation to signal any underflow condition? */ result = paNoError; } else if( buffer == 0 ) { result = paBadBufferPtr; } else { result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); if( result == 0 ) { result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames ); } else if( result == 1 ) { result = paStreamIsStopped; } } } PA_LOGAPI_EXIT_PAERROR( "Pa_WriteStream", result ); return result; } signed long Pa_GetStreamReadAvailable( PaStream* stream ) { PaError error = PaUtil_ValidateStreamPointer( stream ); signed long result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamReadAvailable" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( error != paNoError ) { result = 0; PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" )); PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) )); } else { result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream ); PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); } return result; } signed long Pa_GetStreamWriteAvailable( PaStream* stream ) { PaError error = PaUtil_ValidateStreamPointer( stream ); signed long result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamWriteAvailable" ); PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); if( error != paNoError ) { result = 0; PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" )); PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) )); } else { result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream ); PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" )); PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); } return result; } PaError Pa_GetSampleSize( PaSampleFormat format ) { int result; PA_LOGAPI_ENTER_PARAMS( "Pa_GetSampleSize" ); PA_LOGAPI(("\tPaSampleFormat format: %d\n", format )); switch( format & ~paNonInterleaved ) { case paUInt8: case paInt8: result = 1; break; case paInt16: result = 2; break; case paInt24: result = 3; break; case paFloat32: case paInt32: result = 4; break; default: result = paSampleFormatNotSupported; break; } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetSampleSize", "int: %d", result ); return (PaError) result; } nyquist-3.05/portaudio/src/common/pa_trace.c0000644000175000000620000000624511466723256020215 0ustar stevestaff/* * $Id: pa_trace.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library Trace Facility * Store trace information in real-time for later printing. * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Event trace mechanism for debugging. */ #include #include #include #include "pa_trace.h" #if PA_TRACE_REALTIME_EVENTS static char *traceTextArray[PA_MAX_TRACE_RECORDS]; static int traceIntArray[PA_MAX_TRACE_RECORDS]; static int traceIndex = 0; static int traceBlock = 0; /*********************************************************************/ void PaUtil_ResetTraceMessages() { traceIndex = 0; } /*********************************************************************/ void PaUtil_DumpTraceMessages() { int i; int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS; printf("DumpTraceMessages: traceIndex = %d\n", traceIndex ); for( i=0; iprevious = 0; state->randSeed1 = 22222; state->randSeed2 = 5555555; } signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state ) { signed long current, highPass; /* Generate two random numbers. */ state->randSeed1 = (state->randSeed1 * 196314165) + 907633515; state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; /* Generate triangular distribution about 0. * Shift before adding to prevent overflow which would skew the distribution. * Also shift an extra bit for the high pass filter. */ #define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1) current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) + (((signed long)state->randSeed2)>>DITHER_SHIFT_); /* High pass filter to reduce audibility. */ highPass = current - state->previous; state->previous = current; return highPass; } /* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */ #define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<randSeed1 = (state->randSeed1 * 196314165) + 907633515; state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; /* Generate triangular distribution about 0. * Shift before adding to prevent overflow which would skew the distribution. * Also shift an extra bit for the high pass filter. */ #define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1) current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) + (((signed long)state->randSeed2)>>DITHER_SHIFT_); /* High pass filter to reduce audibility. */ highPass = current - state->previous; state->previous = current; return ((float)highPass) * const_float_dither_scale_; } /* The following alternate dither algorithms (from musicdsp.org) could be considered */ /*Noise shaped dither (March 2000) ------------------- This is a simple implementation of highpass triangular-PDF dither with 2nd-order noise shaping, for use when truncating floating point audio data to fixed point. The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz sample rate) compared to triangular-PDF dither. The code below assumes input data is in the range +1 to -1 and doesn't check for overloads! To save time when generating dither for multiple channels you can do things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again. int r1, r2; //rectangular-PDF random numbers float s1, s2; //error feedback buffers float s = 0.5f; //set to 0.0f for no noise shaping float w = pow(2.0,bits-1); //word length (usually bits=16) float wi= 1.0f/w; float d = wi / RAND_MAX; //dither amplitude (2 lsb) float o = wi * 0.5f; //remove dc offset float in, tmp; int out; //for each sample... r2=r1; //can make HP-TRI dither by r1=rand(); //subtracting previous rand() in += s * (s1 + s1 - s2); //error feedback tmp = in + o + d * (float)(r1 - r2); //dc offset and dither out = (int)(w * tmp); //truncate downwards if(tmp<0.0f) out--; //this is faster than floor() s2 = s1; s1 = in - wi * (float)out; //error -- paul.kellett@maxim.abel.co.uk http://www.maxim.abel.co.uk */ /* 16-to-8-bit first-order dither Type : First order error feedforward dithering code References : Posted by Jon Watte Notes : This is about as simple a dithering algorithm as you can implement, but it's likely to sound better than just truncating to N bits. Note that you might not want to carry forward the full difference for infinity. It's probably likely that the worst performance hit comes from the saturation conditionals, which can be avoided with appropriate instructions on many DSPs and integer SIMD type instructions, or CMOV. Last, if sound quality is paramount (such as when going from > 16 bits to 16 bits) you probably want to use a higher-order dither function found elsewhere on this site. Code : // This code will down-convert and dither a 16-bit signed short // mono signal into an 8-bit unsigned char signal, using a first // order forward-feeding error term dither. #define uchar unsigned char void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory ) { int m = *memory; while( count-- > 0 ) { int i = *input++; i += m; int j = i + 32768 - 128; uchar o; if( j < 0 ) { o = 0; } else if( j > 65535 ) { o = 255; } else { o = (uchar)((j>>8)&0xff); } m = ((j-32768+128)-i); *output++ = o; } *memory = m; } */ nyquist-3.05/portaudio/src/common/pa_cpuload.h0000644000175000000620000000524111466723256020546 0ustar stevestaff#ifndef PA_CPULOAD_H #define PA_CPULOAD_H /* * $Id: pa_cpuload.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library CPU Load measurement functions * Portable CPU load measurement facility. * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 2002 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Functions to assist in measuring the CPU utilization of a callback stream. Used to implement the Pa_GetStreamCpuLoad() function. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct { double samplingPeriod; double measurementStartTime; double averageLoad; } PaUtilCpuLoadMeasurer; /**< @todo need better name than measurer */ void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ); void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ); void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ); void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer ); double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_CPULOAD_H */ nyquist-3.05/portaudio/src/common/pa_process.c0000644000175000000620000017717111466723256020604 0ustar stevestaff/* * $Id: pa_process.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library * streamCallback <-> host buffer processing adapter * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Buffer Processor implementation. The code in this file is not optimised yet - although it's not clear that it needs to be. there may appear to be redundancies that could be factored into common functions, but the redundanceis are left intentionally as each appearance may have different optimisation possibilities. The optimisations which are planned involve only converting data in-place where possible, rather than copying to the temp buffer(s). Note that in the extreme case of being able to convert in-place, and there being no conversion necessary there should be some code which short-circuits the operation. @todo Consider cache tilings for intereave<->deinterleave. @todo implement timeInfo->currentTime int PaUtil_BeginBufferProcessing() @todo specify and implement some kind of logical policy for handling the underflow and overflow stream flags when the underflow/overflow overlaps multiple user buffers/callbacks. @todo provide support for priming the buffers with data from the callback. The client interface is now implemented through PaUtil_SetNoInput() which sets bp->hostInputChannels[0][0].data to zero. However this is currently only implemented in NonAdaptingProcess(). It shouldn't be needed for AdaptingInputOnlyProcess() (no priming should ever be requested for AdaptingInputOnlyProcess()). Not sure if additional work should be required to make it work with AdaptingOutputOnlyProcess, but it definitely is required for AdaptingProcess. @todo implement PaUtil_SetNoOutput for AdaptingProcess @todo don't allocate temp buffers for blocking streams unless they are needed. At the moment they are needed, but perhaps for host APIs where the implementation passes a buffer to the host they could be used. */ #include #include /* memset() */ #include "pa_process.h" #include "pa_util.h" #define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024 #define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) ) /* greatest common divisor - PGCD in French */ static unsigned long GCD( unsigned long a, unsigned long b ) { return (b==0) ? a : GCD( b, a%b); } /* least common multiple - PPCM in French */ static unsigned long LCM( unsigned long a, unsigned long b ) { return (a*b) / GCD(a,b); } #define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b)) static unsigned long CalculateFrameShift( unsigned long M, unsigned long N ) { unsigned long result = 0; unsigned long i; unsigned long lcm; assert( M > 0 ); assert( N > 0 ); lcm = LCM( M, N ); for( i = M; i < lcm; i += M ) result = PA_MAX_( result, i % N ); return result; } PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, int inputChannelCount, PaSampleFormat userInputSampleFormat, PaSampleFormat hostInputSampleFormat, int outputChannelCount, PaSampleFormat userOutputSampleFormat, PaSampleFormat hostOutputSampleFormat, double sampleRate, PaStreamFlags streamFlags, unsigned long framesPerUserBuffer, unsigned long framesPerHostBuffer, PaUtilHostBufferSizeMode hostBufferSizeMode, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaError bytesPerSample; unsigned long tempInputBufferSize, tempOutputBufferSize; if( streamFlags & paNeverDropInput ) { /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */ if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) || framesPerUserBuffer != paFramesPerBufferUnspecified ) return paInvalidFlag; } /* initialize buffer ptrs to zero so they can be freed if necessary in error */ bp->tempInputBuffer = 0; bp->tempInputBufferPtrs = 0; bp->tempOutputBuffer = 0; bp->tempOutputBufferPtrs = 0; bp->framesPerUserBuffer = framesPerUserBuffer; bp->framesPerHostBuffer = framesPerHostBuffer; bp->inputChannelCount = inputChannelCount; bp->outputChannelCount = outputChannelCount; bp->hostBufferSizeMode = hostBufferSizeMode; bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0; bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0; if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */ { bp->useNonAdaptingProcess = 1; bp->initialFramesInTempInputBuffer = 0; bp->initialFramesInTempOutputBuffer = 0; if( hostBufferSizeMode == paUtilFixedHostBufferSize || hostBufferSizeMode == paUtilBoundedHostBufferSize ) { bp->framesPerTempBuffer = framesPerHostBuffer; } else /* unknown host buffer size */ { bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_; } } else { bp->framesPerTempBuffer = framesPerUserBuffer; if( hostBufferSizeMode == paUtilFixedHostBufferSize && framesPerHostBuffer % framesPerUserBuffer == 0 ) { bp->useNonAdaptingProcess = 1; bp->initialFramesInTempInputBuffer = 0; bp->initialFramesInTempOutputBuffer = 0; } else { bp->useNonAdaptingProcess = 0; if( inputChannelCount > 0 && outputChannelCount > 0 ) { /* full duplex */ if( hostBufferSizeMode == paUtilFixedHostBufferSize ) { unsigned long frameShift = CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer ); if( framesPerUserBuffer > framesPerHostBuffer ) { bp->initialFramesInTempInputBuffer = frameShift; bp->initialFramesInTempOutputBuffer = 0; } else { bp->initialFramesInTempInputBuffer = 0; bp->initialFramesInTempOutputBuffer = frameShift; } } else /* variable host buffer size, add framesPerUserBuffer latency */ { bp->initialFramesInTempInputBuffer = 0; bp->initialFramesInTempOutputBuffer = framesPerUserBuffer; } } else { /* half duplex */ bp->initialFramesInTempInputBuffer = 0; bp->initialFramesInTempOutputBuffer = 0; } } } bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; if( inputChannelCount > 0 ) { bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat ); if( bytesPerSample > 0 ) { bp->bytesPerHostInputSample = bytesPerSample; } else { result = bytesPerSample; goto error; } bytesPerSample = Pa_GetSampleSize( userInputSampleFormat ); if( bytesPerSample > 0 ) { bp->bytesPerUserInputSample = bytesPerSample; } else { result = bytesPerSample; goto error; } bp->inputConverter = PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags ); bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat ); bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; tempInputBufferSize = bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount; bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize ); if( bp->tempInputBuffer == 0 ) { result = paInsufficientMemory; goto error; } if( bp->framesInTempInputBuffer > 0 ) memset( bp->tempInputBuffer, 0, tempInputBufferSize ); if( userInputSampleFormat & paNonInterleaved ) { bp->tempInputBufferPtrs = (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount ); if( bp->tempInputBufferPtrs == 0 ) { result = paInsufficientMemory; goto error; } } bp->hostInputChannels[0] = (PaUtilChannelDescriptor*) PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2); if( bp->hostInputChannels[0] == 0 ) { result = paInsufficientMemory; goto error; } bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount]; } if( outputChannelCount > 0 ) { bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat ); if( bytesPerSample > 0 ) { bp->bytesPerHostOutputSample = bytesPerSample; } else { result = bytesPerSample; goto error; } bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat ); if( bytesPerSample > 0 ) { bp->bytesPerUserOutputSample = bytesPerSample; } else { result = bytesPerSample; goto error; } bp->outputConverter = PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags ); bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat ); bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1; tempOutputBufferSize = bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount; bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize ); if( bp->tempOutputBuffer == 0 ) { result = paInsufficientMemory; goto error; } if( bp->framesInTempOutputBuffer > 0 ) memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); if( userOutputSampleFormat & paNonInterleaved ) { bp->tempOutputBufferPtrs = (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount ); if( bp->tempOutputBufferPtrs == 0 ) { result = paInsufficientMemory; goto error; } } bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*) PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 ); if( bp->hostOutputChannels[0] == 0 ) { result = paInsufficientMemory; goto error; } bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount]; } PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator ); bp->samplePeriod = 1. / sampleRate; bp->streamCallback = streamCallback; bp->userData = userData; return result; error: if( bp->tempInputBuffer ) PaUtil_FreeMemory( bp->tempInputBuffer ); if( bp->tempInputBufferPtrs ) PaUtil_FreeMemory( bp->tempInputBufferPtrs ); if( bp->hostInputChannels[0] ) PaUtil_FreeMemory( bp->hostInputChannels[0] ); if( bp->tempOutputBuffer ) PaUtil_FreeMemory( bp->tempOutputBuffer ); if( bp->tempOutputBufferPtrs ) PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); if( bp->hostOutputChannels[0] ) PaUtil_FreeMemory( bp->hostOutputChannels[0] ); return result; } void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp ) { if( bp->tempInputBuffer ) PaUtil_FreeMemory( bp->tempInputBuffer ); if( bp->tempInputBufferPtrs ) PaUtil_FreeMemory( bp->tempInputBufferPtrs ); if( bp->hostInputChannels[0] ) PaUtil_FreeMemory( bp->hostInputChannels[0] ); if( bp->tempOutputBuffer ) PaUtil_FreeMemory( bp->tempOutputBuffer ); if( bp->tempOutputBufferPtrs ) PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); if( bp->hostOutputChannels[0] ) PaUtil_FreeMemory( bp->hostOutputChannels[0] ); } void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp ) { unsigned long tempInputBufferSize, tempOutputBufferSize; bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; if( bp->framesInTempInputBuffer > 0 ) { tempInputBufferSize = bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount; memset( bp->tempInputBuffer, 0, tempInputBufferSize ); } if( bp->framesInTempOutputBuffer > 0 ) { tempOutputBufferSize = bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount; memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); } } unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp ) { return bp->initialFramesInTempInputBuffer; } unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bp ) { return bp->initialFramesInTempOutputBuffer; } void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp, unsigned long frameCount ) { if( frameCount == 0 ) bp->hostInputFrameCount[0] = bp->framesPerHostBuffer; else bp->hostInputFrameCount[0] = frameCount; } void PaUtil_SetNoInput( PaUtilBufferProcessor* bp ) { assert( bp->inputChannelCount > 0 ); bp->hostInputChannels[0][0].data = 0; } void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data, unsigned int stride ) { assert( channel < bp->inputChannelCount ); bp->hostInputChannels[0][channel].data = data; bp->hostInputChannels[0][channel].stride = stride; } void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp, unsigned int firstChannel, void *data, unsigned int channelCount ) { unsigned int i; unsigned int channel = firstChannel; unsigned char *p = (unsigned char*)data; if( channelCount == 0 ) channelCount = bp->inputChannelCount; assert( firstChannel < bp->inputChannelCount ); assert( firstChannel + channelCount <= bp->inputChannelCount ); for( i=0; i< channelCount; ++i ) { bp->hostInputChannels[0][channel+i].data = p; p += bp->bytesPerHostInputSample; bp->hostInputChannels[0][channel+i].stride = channelCount; } } void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data ) { assert( channel < bp->inputChannelCount ); bp->hostInputChannels[0][channel].data = data; bp->hostInputChannels[0][channel].stride = 1; } void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp, unsigned long frameCount ) { bp->hostInputFrameCount[1] = frameCount; } void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data, unsigned int stride ) { assert( channel < bp->inputChannelCount ); bp->hostInputChannels[1][channel].data = data; bp->hostInputChannels[1][channel].stride = stride; } void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp, unsigned int firstChannel, void *data, unsigned int channelCount ) { unsigned int i; unsigned int channel = firstChannel; unsigned char *p = (unsigned char*)data; if( channelCount == 0 ) channelCount = bp->inputChannelCount; assert( firstChannel < bp->inputChannelCount ); assert( firstChannel + channelCount <= bp->inputChannelCount ); for( i=0; i< channelCount; ++i ) { bp->hostInputChannels[1][channel+i].data = p; p += bp->bytesPerHostInputSample; bp->hostInputChannels[1][channel+i].stride = channelCount; } } void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data ) { assert( channel < bp->inputChannelCount ); bp->hostInputChannels[1][channel].data = data; bp->hostInputChannels[1][channel].stride = 1; } void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp, unsigned long frameCount ) { if( frameCount == 0 ) bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer; else bp->hostOutputFrameCount[0] = frameCount; } void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp ) { assert( bp->outputChannelCount > 0 ); bp->hostOutputChannels[0][0].data = 0; } void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data, unsigned int stride ) { assert( channel < bp->outputChannelCount ); assert( data != NULL ); bp->hostOutputChannels[0][channel].data = data; bp->hostOutputChannels[0][channel].stride = stride; } void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp, unsigned int firstChannel, void *data, unsigned int channelCount ) { unsigned int i; unsigned int channel = firstChannel; unsigned char *p = (unsigned char*)data; if( channelCount == 0 ) channelCount = bp->outputChannelCount; assert( firstChannel < bp->outputChannelCount ); assert( firstChannel + channelCount <= bp->outputChannelCount ); for( i=0; i< channelCount; ++i ) { PaUtil_SetOutputChannel( bp, channel + i, p, channelCount ); p += bp->bytesPerHostOutputSample; } } void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data ) { assert( channel < bp->outputChannelCount ); PaUtil_SetOutputChannel( bp, channel, data, 1 ); } void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp, unsigned long frameCount ) { bp->hostOutputFrameCount[1] = frameCount; } void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data, unsigned int stride ) { assert( channel < bp->outputChannelCount ); assert( data != NULL ); bp->hostOutputChannels[1][channel].data = data; bp->hostOutputChannels[1][channel].stride = stride; } void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp, unsigned int firstChannel, void *data, unsigned int channelCount ) { unsigned int i; unsigned int channel = firstChannel; unsigned char *p = (unsigned char*)data; if( channelCount == 0 ) channelCount = bp->outputChannelCount; assert( firstChannel < bp->outputChannelCount ); assert( firstChannel + channelCount <= bp->outputChannelCount ); for( i=0; i< channelCount; ++i ) { PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount ); p += bp->bytesPerHostOutputSample; } } void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, unsigned int channel, void *data ) { assert( channel < bp->outputChannelCount ); PaUtil_Set2ndOutputChannel( bp, channel, data, 1 ); } void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags ) { bp->timeInfo = timeInfo; /* the first streamCallback will be called to process samples which are currently in the input buffer before the ones starting at the timeInfo time */ bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod; bp->timeInfo->currentTime = 0; /** FIXME: @todo time info currentTime not implemented */ /* the first streamCallback will be called to generate samples which will be outputted after the frames currently in the output buffer have been outputted. */ bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod; bp->callbackStatusFlags = callbackStatusFlags; bp->hostInputFrameCount[1] = 0; bp->hostOutputFrameCount[1] = 0; } /* NonAdaptingProcess() is a simple buffer copying adaptor that can handle both full and half duplex copies. It processes framesToProcess frames, broken into blocks bp->framesPerTempBuffer long. This routine can be used when the streamCallback doesn't care what length the buffers are, or when framesToProcess is an integer multiple of bp->framesPerTempBuffer, in which case streamCallback will always be called with bp->framesPerTempBuffer samples. */ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, int *streamCallbackResult, PaUtilChannelDescriptor *hostInputChannels, PaUtilChannelDescriptor *hostOutputChannels, unsigned long framesToProcess ) { void *userInput, *userOutput; unsigned char *srcBytePtr, *destBytePtr; unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i; unsigned long frameCount; unsigned long framesToGo = framesToProcess; unsigned long framesProcessed = 0; if( *streamCallbackResult == paContinue ) { do { frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo ); /* configure user input buffer and convert input data (host -> user) */ if( bp->inputChannelCount == 0 ) { /* no input */ userInput = 0; } else /* there are input channels */ { /* could use more elaborate logic here and sometimes process buffers in-place. */ destBytePtr = (unsigned char *)bp->tempInputBuffer; if( bp->userInputIsInterleaved ) { destSampleStrideSamples = bp->inputChannelCount; destChannelStrideBytes = bp->bytesPerUserInputSample; userInput = bp->tempInputBuffer; } else /* user input is not interleaved */ { destSampleStrideSamples = 1; destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample; /* setup non-interleaved ptrs */ for( i=0; iinputChannelCount; ++i ) { bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + i * bp->bytesPerUserInputSample * frameCount; } userInput = bp->tempInputBufferPtrs; } if( !bp->hostInputChannels[0][0].data ) { /* no input was supplied (see PaUtil_SetNoInput), so zero the input buffer */ for( i=0; iinputChannelCount; ++i ) { bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount ); destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ } } else { for( i=0; iinputChannelCount; ++i ) { bp->inputConverter( destBytePtr, destSampleStrideSamples, hostInputChannels[i].data, hostInputChannels[i].stride, frameCount, &bp->ditherGenerator ); destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ /* advance src ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } } } /* configure user output buffer */ if( bp->outputChannelCount == 0 ) { /* no output */ userOutput = 0; } else /* there are output channels */ { if( bp->userOutputIsInterleaved ) { userOutput = bp->tempOutputBuffer; } else /* user output is not interleaved */ { for( i = 0; i < bp->outputChannelCount; ++i ) { bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + i * bp->bytesPerUserOutputSample * frameCount; } userOutput = bp->tempOutputBufferPtrs; } } *streamCallbackResult = bp->streamCallback( userInput, userOutput, frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); if( *streamCallbackResult == paAbort ) { /* callback returned paAbort, don't advance framesProcessed and framesToGo, they will be handled below */ } else { bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod; /* convert output data (user -> host) */ if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) { /* could use more elaborate logic here and sometimes process buffers in-place. */ srcBytePtr = (unsigned char *)bp->tempOutputBuffer; if( bp->userOutputIsInterleaved ) { srcSampleStrideSamples = bp->outputChannelCount; srcChannelStrideBytes = bp->bytesPerUserOutputSample; } else /* user output is not interleaved */ { srcSampleStrideSamples = 1; srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample; } for( i=0; ioutputChannelCount; ++i ) { bp->outputConverter( hostOutputChannels[i].data, hostOutputChannels[i].stride, srcBytePtr, srcSampleStrideSamples, frameCount, &bp->ditherGenerator ); srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } } framesProcessed += frameCount; framesToGo -= frameCount; } } while( framesToGo > 0 && *streamCallbackResult == paContinue ); } if( framesToGo > 0 ) { /* zero any remaining frames output. There will only be remaining frames if the callback has returned paComplete or paAbort */ frameCount = framesToGo; if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) { for( i=0; ioutputChannelCount; ++i ) { bp->outputZeroer( hostOutputChannels[i].data, hostOutputChannels[i].stride, frameCount ); /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } } framesProcessed += frameCount; } return framesProcessed; } /* AdaptingInputOnlyProcess() is a half duplex input buffer processor. It converts data from the input buffers into the temporary input buffer, when the temporary input buffer is full, it calls the streamCallback. */ static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp, int *streamCallbackResult, PaUtilChannelDescriptor *hostInputChannels, unsigned long framesToProcess ) { void *userInput, *userOutput; unsigned char *destBytePtr; unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i; unsigned long frameCount; unsigned long framesToGo = framesToProcess; unsigned long framesProcessed = 0; userOutput = 0; do { frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer ) ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer ) : framesToGo; /* convert frameCount samples into temp buffer */ if( bp->userInputIsInterleaved ) { destBytePtr = ((unsigned char*)bp->tempInputBuffer) + bp->bytesPerUserInputSample * bp->inputChannelCount * bp->framesInTempInputBuffer; destSampleStrideSamples = bp->inputChannelCount; destChannelStrideBytes = bp->bytesPerUserInputSample; userInput = bp->tempInputBuffer; } else /* user input is not interleaved */ { destBytePtr = ((unsigned char*)bp->tempInputBuffer) + bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; destSampleStrideSamples = 1; destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; /* setup non-interleaved ptrs */ for( i=0; iinputChannelCount; ++i ) { bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer; } userInput = bp->tempInputBufferPtrs; } for( i=0; iinputChannelCount; ++i ) { bp->inputConverter( destBytePtr, destSampleStrideSamples, hostInputChannels[i].data, hostInputChannels[i].stride, frameCount, &bp->ditherGenerator ); destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ /* advance src ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } bp->framesInTempInputBuffer += frameCount; if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer ) { /** @todo (non-critical optimisation) The conditional below implements the continue/complete/abort mechanism simply by continuing on iterating through the input buffer, but not passing the data to the callback. With care, the outer loop could be terminated earlier, thus some unneeded conversion cycles would be saved. */ if( *streamCallbackResult == paContinue ) { bp->timeInfo->outputBufferDacTime = 0; *streamCallbackResult = bp->streamCallback( userInput, userOutput, bp->framesPerUserBuffer, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; } bp->framesInTempInputBuffer = 0; } framesProcessed += frameCount; framesToGo -= frameCount; }while( framesToGo > 0 ); return framesProcessed; } /* AdaptingOutputOnlyProcess() is a half duplex output buffer processor. It converts data from the temporary output buffer, to the output buffers, when the temporary output buffer is empty, it calls the streamCallback. */ static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp, int *streamCallbackResult, PaUtilChannelDescriptor *hostOutputChannels, unsigned long framesToProcess ) { void *userInput, *userOutput; unsigned char *srcBytePtr; unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i; unsigned long frameCount; unsigned long framesToGo = framesToProcess; unsigned long framesProcessed = 0; do { if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue ) { userInput = 0; /* setup userOutput */ if( bp->userOutputIsInterleaved ) { userOutput = bp->tempOutputBuffer; } else /* user output is not interleaved */ { for( i = 0; i < bp->outputChannelCount; ++i ) { bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; } userOutput = bp->tempOutputBufferPtrs; } bp->timeInfo->inputBufferAdcTime = 0; *streamCallbackResult = bp->streamCallback( userInput, userOutput, bp->framesPerUserBuffer, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); if( *streamCallbackResult == paAbort ) { /* if the callback returned paAbort, we disregard its output */ } else { bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; } } if( bp->framesInTempOutputBuffer > 0 ) { /* convert frameCount frames from user buffer to host buffer */ frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo ); if( bp->userOutputIsInterleaved ) { srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + bp->bytesPerUserOutputSample * bp->outputChannelCount * (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); srcSampleStrideSamples = bp->outputChannelCount; srcChannelStrideBytes = bp->bytesPerUserOutputSample; } else /* user output is not interleaved */ { srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + bp->bytesPerUserOutputSample * (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); srcSampleStrideSamples = 1; srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; } for( i=0; ioutputChannelCount; ++i ) { bp->outputConverter( hostOutputChannels[i].data, hostOutputChannels[i].stride, srcBytePtr, srcSampleStrideSamples, frameCount, &bp->ditherGenerator ); srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } bp->framesInTempOutputBuffer -= frameCount; } else { /* no more user data is available because the callback has returned paComplete or paAbort. Fill the remainder of the host buffer with zeros. */ frameCount = framesToGo; for( i=0; ioutputChannelCount; ++i ) { bp->outputZeroer( hostOutputChannels[i].data, hostOutputChannels[i].stride, frameCount ); /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } } framesProcessed += frameCount; framesToGo -= frameCount; }while( framesToGo > 0 ); return framesProcessed; } /* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from tempOutputBuffer to hostOutputChannels. This includes data conversion and interleaving. */ static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp) { unsigned long maxFramesToCopy; PaUtilChannelDescriptor *hostOutputChannels; unsigned int frameCount; unsigned char *srcBytePtr; unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i; /* copy frames from user to host output buffers */ while( bp->framesInTempOutputBuffer > 0 && ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) ) { maxFramesToCopy = bp->framesInTempOutputBuffer; /* select the output buffer set (1st or 2nd) */ if( bp->hostOutputFrameCount[0] > 0 ) { hostOutputChannels = bp->hostOutputChannels[0]; frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy ); } else { hostOutputChannels = bp->hostOutputChannels[1]; frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy ); } if( bp->userOutputIsInterleaved ) { srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + bp->bytesPerUserOutputSample * bp->outputChannelCount * (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); srcSampleStrideSamples = bp->outputChannelCount; srcChannelStrideBytes = bp->bytesPerUserOutputSample; } else /* user output is not interleaved */ { srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + bp->bytesPerUserOutputSample * (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); srcSampleStrideSamples = 1; srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; } for( i=0; ioutputChannelCount; ++i ) { assert( hostOutputChannels[i].data != NULL ); bp->outputConverter( hostOutputChannels[i].data, hostOutputChannels[i].stride, srcBytePtr, srcSampleStrideSamples, frameCount, &bp->ditherGenerator ); srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } if( bp->hostOutputFrameCount[0] > 0 ) bp->hostOutputFrameCount[0] -= frameCount; else bp->hostOutputFrameCount[1] -= frameCount; bp->framesInTempOutputBuffer -= frameCount; } } /* AdaptingProcess is a full duplex adapting buffer processor. It converts data from the temporary output buffer into the host output buffers, then from the host input buffers into the temporary input buffers. Calling the streamCallback when necessary. When processPartialUserBuffers is 0, all available input data will be consumed and all available output space will be filled. When processPartialUserBuffers is non-zero, as many full user buffers as possible will be processed, but partial buffers will not be consumed. */ static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp, int *streamCallbackResult, int processPartialUserBuffers ) { void *userInput, *userOutput; unsigned long framesProcessed = 0; unsigned long framesAvailable; unsigned long endProcessingMinFrameCount; unsigned long maxFramesToCopy; PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels; unsigned int frameCount; unsigned char *destBytePtr; unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i, j; framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */ if( processPartialUserBuffers ) endProcessingMinFrameCount = 0; else endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1); /* Fill host output with remaining frames in user output (tempOutputBuffer) */ CopyTempOutputBuffersToHostOutputBuffers( bp ); while( framesAvailable > endProcessingMinFrameCount ) { if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue ) { /* the callback will not be called any more, so zero what remains of the host output buffers */ for( i=0; i<2; ++i ) { frameCount = bp->hostOutputFrameCount[i]; if( frameCount > 0 ) { hostOutputChannels = bp->hostOutputChannels[i]; for( j=0; joutputChannelCount; ++j ) { bp->outputZeroer( hostOutputChannels[j].data, hostOutputChannels[j].stride, frameCount ); /* advance dest ptr for next iteration */ hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) + frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample; } bp->hostOutputFrameCount[i] = 0; } } } /* copy frames from host to user input buffers */ while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer && ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) ) { maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer; /* select the input buffer set (1st or 2nd) */ if( bp->hostInputFrameCount[0] > 0 ) { hostInputChannels = bp->hostInputChannels[0]; frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy ); } else { hostInputChannels = bp->hostInputChannels[1]; frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy ); } /* configure conversion destination pointers */ if( bp->userInputIsInterleaved ) { destBytePtr = ((unsigned char*)bp->tempInputBuffer) + bp->bytesPerUserInputSample * bp->inputChannelCount * bp->framesInTempInputBuffer; destSampleStrideSamples = bp->inputChannelCount; destChannelStrideBytes = bp->bytesPerUserInputSample; } else /* user input is not interleaved */ { destBytePtr = ((unsigned char*)bp->tempInputBuffer) + bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; destSampleStrideSamples = 1; destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; } for( i=0; iinputChannelCount; ++i ) { bp->inputConverter( destBytePtr, destSampleStrideSamples, hostInputChannels[i].data, hostInputChannels[i].stride, frameCount, &bp->ditherGenerator ); destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ /* advance src ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } if( bp->hostInputFrameCount[0] > 0 ) bp->hostInputFrameCount[0] -= frameCount; else bp->hostInputFrameCount[1] -= frameCount; bp->framesInTempInputBuffer += frameCount; /* update framesAvailable and framesProcessed based on input consumed unless something is very wrong this will also correspond to the amount of output generated */ framesAvailable -= frameCount; framesProcessed += frameCount; } /* call streamCallback */ if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer && bp->framesInTempOutputBuffer == 0 ) { if( *streamCallbackResult == paContinue ) { /* setup userInput */ if( bp->userInputIsInterleaved ) { userInput = bp->tempInputBuffer; } else /* user input is not interleaved */ { for( i = 0; i < bp->inputChannelCount; ++i ) { bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample; } userInput = bp->tempInputBufferPtrs; } /* setup userOutput */ if( bp->userOutputIsInterleaved ) { userOutput = bp->tempOutputBuffer; } else /* user output is not interleaved */ { for( i = 0; i < bp->outputChannelCount; ++i ) { bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; } userOutput = bp->tempOutputBufferPtrs; } /* call streamCallback */ *streamCallbackResult = bp->streamCallback( userInput, userOutput, bp->framesPerUserBuffer, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; bp->framesInTempInputBuffer = 0; if( *streamCallbackResult == paAbort ) bp->framesInTempOutputBuffer = 0; else bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; } else { /* paComplete or paAbort has already been called. */ bp->framesInTempInputBuffer = 0; } } /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) Means to process the user output provided by the callback. Has to be called after each callback. */ CopyTempOutputBuffersToHostOutputBuffers( bp ); } return framesProcessed; } unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult ) { unsigned long framesToProcess, framesToGo; unsigned long framesProcessed = 0; if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */ && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ ) { assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) == (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) ); } assert( *streamCallbackResult == paContinue || *streamCallbackResult == paComplete || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */ if( bp->useNonAdaptingProcess ) { if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) { /* full duplex non-adapting process, splice buffers if they are different lengths */ framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */ do{ unsigned long noInputInputFrameCount; unsigned long *hostInputFrameCount; PaUtilChannelDescriptor *hostInputChannels; unsigned long noOutputOutputFrameCount; unsigned long *hostOutputFrameCount; PaUtilChannelDescriptor *hostOutputChannels; unsigned long framesProcessedThisIteration; if( !bp->hostInputChannels[0][0].data ) { /* no input was supplied (see PaUtil_SetNoInput) NonAdaptingProcess knows how to deal with this */ noInputInputFrameCount = framesToGo; hostInputFrameCount = &noInputInputFrameCount; hostInputChannels = 0; } else if( bp->hostInputFrameCount[0] != 0 ) { hostInputFrameCount = &bp->hostInputFrameCount[0]; hostInputChannels = bp->hostInputChannels[0]; } else { hostInputFrameCount = &bp->hostInputFrameCount[1]; hostInputChannels = bp->hostInputChannels[1]; } if( !bp->hostOutputChannels[0][0].data ) { /* no output was supplied (see PaUtil_SetNoOutput) NonAdaptingProcess knows how to deal with this */ noOutputOutputFrameCount = framesToGo; hostOutputFrameCount = &noOutputOutputFrameCount; hostOutputChannels = 0; } if( bp->hostOutputFrameCount[0] != 0 ) { hostOutputFrameCount = &bp->hostOutputFrameCount[0]; hostOutputChannels = bp->hostOutputChannels[0]; } else { hostOutputFrameCount = &bp->hostOutputFrameCount[1]; hostOutputChannels = bp->hostOutputChannels[1]; } framesToProcess = PA_MIN_( *hostInputFrameCount, *hostOutputFrameCount ); assert( framesToProcess != 0 ); framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult, hostInputChannels, hostOutputChannels, framesToProcess ); *hostInputFrameCount -= framesProcessedThisIteration; *hostOutputFrameCount -= framesProcessedThisIteration; framesProcessed += framesProcessedThisIteration; framesToGo -= framesProcessedThisIteration; }while( framesToGo > 0 ); } else { /* half duplex non-adapting process, just process 1st and 2nd buffer */ /* process first buffer */ framesToProcess = (bp->inputChannelCount != 0) ? bp->hostInputFrameCount[0] : bp->hostOutputFrameCount[0]; framesProcessed = NonAdaptingProcess( bp, streamCallbackResult, bp->hostInputChannels[0], bp->hostOutputChannels[0], framesToProcess ); /* process second buffer if provided */ framesToProcess = (bp->inputChannelCount != 0) ? bp->hostInputFrameCount[1] : bp->hostOutputFrameCount[1]; if( framesToProcess > 0 ) { framesProcessed += NonAdaptingProcess( bp, streamCallbackResult, bp->hostInputChannels[1], bp->hostOutputChannels[1], framesToProcess ); } } } else /* block adaption necessary*/ { if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) { /* full duplex */ if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed ) { framesProcessed = AdaptingProcess( bp, streamCallbackResult, 0 /* dont process partial user buffers */ ); } else { framesProcessed = AdaptingProcess( bp, streamCallbackResult, 1 /* process partial user buffers */ ); } } else if( bp->inputChannelCount != 0 ) { /* input only */ framesToProcess = bp->hostInputFrameCount[0]; framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult, bp->hostInputChannels[0], framesToProcess ); framesToProcess = bp->hostInputFrameCount[1]; if( framesToProcess > 0 ) { framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult, bp->hostInputChannels[1], framesToProcess ); } } else { /* output only */ framesToProcess = bp->hostOutputFrameCount[0]; framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult, bp->hostOutputChannels[0], framesToProcess ); framesToProcess = bp->hostOutputFrameCount[1]; if( framesToProcess > 0 ) { framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult, bp->hostOutputChannels[1], framesToProcess ); } } } return framesProcessed; } int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp ) { return (bp->framesInTempOutputBuffer) ? 0 : 1; } unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp, void **buffer, unsigned long frameCount ) { PaUtilChannelDescriptor *hostInputChannels; unsigned int framesToCopy; unsigned char *destBytePtr; void **nonInterleavedDestPtrs; unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i; hostInputChannels = bp->hostInputChannels[0]; framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount ); if( bp->userInputIsInterleaved ) { destBytePtr = (unsigned char*)*buffer; destSampleStrideSamples = bp->inputChannelCount; destChannelStrideBytes = bp->bytesPerUserInputSample; for( i=0; iinputChannelCount; ++i ) { bp->inputConverter( destBytePtr, destSampleStrideSamples, hostInputChannels[i].data, hostInputChannels[i].stride, framesToCopy, &bp->ditherGenerator ); destBytePtr += destChannelStrideBytes; /* skip to next source channel */ /* advance dest ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } /* advance callers dest pointer (buffer) */ *buffer = ((unsigned char *)*buffer) + framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample; } else { /* user input is not interleaved */ nonInterleavedDestPtrs = (void**)*buffer; destSampleStrideSamples = 1; for( i=0; iinputChannelCount; ++i ) { destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i]; bp->inputConverter( destBytePtr, destSampleStrideSamples, hostInputChannels[i].data, hostInputChannels[i].stride, framesToCopy, &bp->ditherGenerator ); /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */ destBytePtr += bp->bytesPerUserInputSample * framesToCopy; nonInterleavedDestPtrs[i] = destBytePtr; /* advance dest ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } } bp->hostInputFrameCount[0] -= framesToCopy; return framesToCopy; } unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp, const void ** buffer, unsigned long frameCount ) { PaUtilChannelDescriptor *hostOutputChannels; unsigned int framesToCopy; unsigned char *srcBytePtr; void **nonInterleavedSrcPtrs; unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ unsigned int i; hostOutputChannels = bp->hostOutputChannels[0]; framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); if( bp->userOutputIsInterleaved ) { srcBytePtr = (unsigned char*)*buffer; srcSampleStrideSamples = bp->outputChannelCount; srcChannelStrideBytes = bp->bytesPerUserOutputSample; for( i=0; ioutputChannelCount; ++i ) { bp->outputConverter( hostOutputChannels[i].data, hostOutputChannels[i].stride, srcBytePtr, srcSampleStrideSamples, framesToCopy, &bp->ditherGenerator ); srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } /* advance callers source pointer (buffer) */ *buffer = ((unsigned char *)*buffer) + framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample; } else { /* user output is not interleaved */ nonInterleavedSrcPtrs = (void**)*buffer; srcSampleStrideSamples = 1; for( i=0; ioutputChannelCount; ++i ) { srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i]; bp->outputConverter( hostOutputChannels[i].data, hostOutputChannels[i].stride, srcBytePtr, srcSampleStrideSamples, framesToCopy, &bp->ditherGenerator ); /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */ srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy; nonInterleavedSrcPtrs[i] = srcBytePtr; /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } } bp->hostOutputFrameCount[0] += framesToCopy; return framesToCopy; } unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount ) { PaUtilChannelDescriptor *hostOutputChannels; unsigned int framesToZero; unsigned int i; hostOutputChannels = bp->hostOutputChannels[0]; framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); for( i=0; ioutputChannelCount; ++i ) { bp->outputZeroer( hostOutputChannels[i].data, hostOutputChannels[i].stride, framesToZero ); /* advance dest ptr for next iteration */ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; } bp->hostOutputFrameCount[0] += framesToZero; return framesToZero; } nyquist-3.05/portaudio/src/common/pa_util.h0000644000175000000620000001257311466723256020102 0ustar stevestaff#ifndef PA_UTIL_H #define PA_UTIL_H /* * $Id: pa_util.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library implementation utilities header * common implementation utilities and interfaces * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Prototypes for utility functions used by PortAudio implementations. @todo Document and adhere to the alignment guarantees provided by PaUtil_AllocateMemory(). */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct PaUtilHostApiRepresentation; /** Retrieve a specific host API representation. This function can be used by implementations to retrieve a pointer to their representation in host api specific extension functions which aren't passed a rep pointer by pa_front.c. @param hostApi A pointer to a host API represenation pointer. Apon success this will receive the requested representation pointer. @param type A valid host API type identifier. @returns An error code. If the result is PaNoError then a pointer to the requested host API representation will be stored in *hostApi. If the host API specified by type is not found, this function returns paHostApiNotFound. */ PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, PaHostApiTypeId type ); /** Convert a PortAudio device index into a host API specific device index. @param hostApiDevice Pointer to a device index, on success this will recieve the converted device index value. @param device The PortAudio device index to convert. @param hostApi The host api which the index should be converted for. @returns On success returns PaNoError and places the converted index in the hostApiDevice parameter. */ PaError PaUtil_DeviceIndexToHostApiDeviceIndex( PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi ); /** Set the host error information returned by Pa_GetLastHostErrorInfo. This function and the paUnanticipatedHostError error code should be used as a last resort. Implementors should use existing PA error codes where possible, or nominate new ones. Note that at it is always better to use PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an ambiguous or inaccurate PaError code. @param hostApiType The host API which encountered the error (ie of the caller) @param errorCode The error code returned by the native API function. @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo makes a copy of the string, so it is not necessary for the pointer to remain valid after the call to PaUtil_SetLastHostErrorInfo() returns. */ void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, const char *errorText ); /* the following functions are implemented in a platform platform specific .c file */ /** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */ void *PaUtil_AllocateMemory( long size ); /** Realease block if non-NULL. block may be NULL */ void PaUtil_FreeMemory( void *block ); /** Return the number of currently allocated blocks. This function can be used for detecting memory leaks. @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If it isn't, this function will always return 0. */ int PaUtil_CountCurrentlyAllocatedBlocks( void ); /** Initialize the clock used by PaUtil_GetTime(). Call this before calling PaUtil_GetTime. @see PaUtil_GetTime */ void PaUtil_InitializeClock( void ); /** Return the system time in seconds. Used to implement CPU load functions @see PaUtil_InitializeClock */ double PaUtil_GetTime( void ); /* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_UTIL_H */ nyquist-3.05/portaudio/src/common/pa_converters.c0000644000175000000620000020366711466723256021320 0ustar stevestaff/* * $Id: pa_converters.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library sample conversion mechanism * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Phil Burk, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Conversion functions implementations. If the C9x function lrintf() is available, define PA_USE_C99_LRINTF to use it @todo Consider whether functions which dither but don't clip should exist, V18 automatically enabled clipping whenever dithering was selected. Perhaps we should do the same. @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither, Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24_Dither, Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither, Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither, @todo review the converters marked REVIEW: Float32_To_Int32, Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip, Int32_To_Int16_Dither, Int32_To_Int8_Dither, Int16_To_Int32 */ #include "pa_converters.h" #include "pa_dither.h" #include "pa_endianness.h" #include "pa_types.h" PaSampleFormat PaUtil_SelectClosestAvailableFormat( PaSampleFormat availableFormats, PaSampleFormat format ) { PaSampleFormat result; format &= ~paNonInterleaved; availableFormats &= ~paNonInterleaved; if( (format & availableFormats) == 0 ) { /* NOTE: this code depends on the sample format constants being in descending order of quality - ie best quality is 0 FIXME: should write an assert which checks that all of the known constants conform to that requirement. */ if( format != 0x01 ) { /* scan for better formats */ result = format; do { result >>= 1; } while( (result & availableFormats) == 0 && result != 0 ); } else { result = 0; } if( result == 0 ){ /* scan for worse formats */ result = format; do { result <<= 1; } while( (result & availableFormats) == 0 && result != paCustomFormat ); if( (result & availableFormats) == 0 ) result = paSampleFormatNotSupported; } }else{ result = format; } return result; } /* -------------------------------------------------------------------------- */ #define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \ switch( format & ~paNonInterleaved ){ \ case paFloat32: \ float32 \ case paInt32: \ int32 \ case paInt24: \ int24 \ case paInt16: \ int16 \ case paInt8: \ int8 \ case paUInt8: \ uint8 \ default: return 0; \ } /* -------------------------------------------------------------------------- */ #define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination ) \ if( flags & paClipOff ){ /* no clip */ \ if( flags & paDitherOff ){ /* no dither */ \ return paConverters. source ## _To_ ## destination; \ }else{ /* dither */ \ return paConverters. source ## _To_ ## destination ## _Dither; \ } \ }else{ /* clip */ \ if( flags & paDitherOff ){ /* no dither */ \ return paConverters. source ## _To_ ## destination ## _Clip; \ }else{ /* dither */ \ return paConverters. source ## _To_ ## destination ## _DitherClip; \ } \ } /* -------------------------------------------------------------------------- */ #define PA_SELECT_CONVERTER_DITHER_( flags, source, destination ) \ if( flags & paDitherOff ){ /* no dither */ \ return paConverters. source ## _To_ ## destination; \ }else{ /* dither */ \ return paConverters. source ## _To_ ## destination ## _Dither; \ } /* -------------------------------------------------------------------------- */ #define PA_USE_CONVERTER_( source, destination )\ return paConverters. source ## _To_ ## destination; /* -------------------------------------------------------------------------- */ #define PA_UNITY_CONVERSION_( wordlength )\ return paConverters. Copy_ ## wordlength ## _To_ ## wordlength; /* -------------------------------------------------------------------------- */ PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat, PaStreamFlags flags ) { PA_SELECT_FORMAT_( sourceFormat, /* paFloat32: */ PA_SELECT_FORMAT_( destinationFormat, /* paFloat32: */ PA_UNITY_CONVERSION_( 32 ), /* paInt32: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ), /* paInt24: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ), /* paInt16: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ), /* paInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ), /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 ) ), /* paInt32: */ PA_SELECT_FORMAT_( destinationFormat, /* paFloat32: */ PA_USE_CONVERTER_( Int32, Float32 ), /* paInt32: */ PA_UNITY_CONVERSION_( 32 ), /* paInt24: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ), /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ), /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ), /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 ) ), /* paInt24: */ PA_SELECT_FORMAT_( destinationFormat, /* paFloat32: */ PA_USE_CONVERTER_( Int24, Float32 ), /* paInt32: */ PA_USE_CONVERTER_( Int24, Int32 ), /* paInt24: */ PA_UNITY_CONVERSION_( 24 ), /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ), /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ), /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 ) ), /* paInt16: */ PA_SELECT_FORMAT_( destinationFormat, /* paFloat32: */ PA_USE_CONVERTER_( Int16, Float32 ), /* paInt32: */ PA_USE_CONVERTER_( Int16, Int32 ), /* paInt24: */ PA_USE_CONVERTER_( Int16, Int24 ), /* paInt16: */ PA_UNITY_CONVERSION_( 16 ), /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ), /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 ) ), /* paInt8: */ PA_SELECT_FORMAT_( destinationFormat, /* paFloat32: */ PA_USE_CONVERTER_( Int8, Float32 ), /* paInt32: */ PA_USE_CONVERTER_( Int8, Int32 ), /* paInt24: */ PA_USE_CONVERTER_( Int8, Int24 ), /* paInt16: */ PA_USE_CONVERTER_( Int8, Int16 ), /* paInt8: */ PA_UNITY_CONVERSION_( 8 ), /* paUInt8: */ PA_USE_CONVERTER_( Int8, UInt8 ) ), /* paUInt8: */ PA_SELECT_FORMAT_( destinationFormat, /* paFloat32: */ PA_USE_CONVERTER_( UInt8, Float32 ), /* paInt32: */ PA_USE_CONVERTER_( UInt8, Int32 ), /* paInt24: */ PA_USE_CONVERTER_( UInt8, Int24 ), /* paInt16: */ PA_USE_CONVERTER_( UInt8, Int16 ), /* paInt8: */ PA_USE_CONVERTER_( UInt8, Int8 ), /* paUInt8: */ PA_UNITY_CONVERSION_( 8 ) ) ) } /* -------------------------------------------------------------------------- */ #ifdef PA_NO_STANDARD_CONVERTERS /* -------------------------------------------------------------------------- */ PaUtilConverterTable paConverters = { 0, /* PaUtilConverter *Float32_To_Int32; */ 0, /* PaUtilConverter *Float32_To_Int32_Dither; */ 0, /* PaUtilConverter *Float32_To_Int32_Clip; */ 0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */ 0, /* PaUtilConverter *Float32_To_Int24; */ 0, /* PaUtilConverter *Float32_To_Int24_Dither; */ 0, /* PaUtilConverter *Float32_To_Int24_Clip; */ 0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */ 0, /* PaUtilConverter *Float32_To_Int16; */ 0, /* PaUtilConverter *Float32_To_Int16_Dither; */ 0, /* PaUtilConverter *Float32_To_Int16_Clip; */ 0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */ 0, /* PaUtilConverter *Float32_To_Int8; */ 0, /* PaUtilConverter *Float32_To_Int8_Dither; */ 0, /* PaUtilConverter *Float32_To_Int8_Clip; */ 0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */ 0, /* PaUtilConverter *Float32_To_UInt8; */ 0, /* PaUtilConverter *Float32_To_UInt8_Dither; */ 0, /* PaUtilConverter *Float32_To_UInt8_Clip; */ 0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */ 0, /* PaUtilConverter *Int32_To_Float32; */ 0, /* PaUtilConverter *Int32_To_Int24; */ 0, /* PaUtilConverter *Int32_To_Int24_Dither; */ 0, /* PaUtilConverter *Int32_To_Int16; */ 0, /* PaUtilConverter *Int32_To_Int16_Dither; */ 0, /* PaUtilConverter *Int32_To_Int8; */ 0, /* PaUtilConverter *Int32_To_Int8_Dither; */ 0, /* PaUtilConverter *Int32_To_UInt8; */ 0, /* PaUtilConverter *Int32_To_UInt8_Dither; */ 0, /* PaUtilConverter *Int24_To_Float32; */ 0, /* PaUtilConverter *Int24_To_Int32; */ 0, /* PaUtilConverter *Int24_To_Int16; */ 0, /* PaUtilConverter *Int24_To_Int16_Dither; */ 0, /* PaUtilConverter *Int24_To_Int8; */ 0, /* PaUtilConverter *Int24_To_Int8_Dither; */ 0, /* PaUtilConverter *Int24_To_UInt8; */ 0, /* PaUtilConverter *Int24_To_UInt8_Dither; */ 0, /* PaUtilConverter *Int16_To_Float32; */ 0, /* PaUtilConverter *Int16_To_Int32; */ 0, /* PaUtilConverter *Int16_To_Int24; */ 0, /* PaUtilConverter *Int16_To_Int8; */ 0, /* PaUtilConverter *Int16_To_Int8_Dither; */ 0, /* PaUtilConverter *Int16_To_UInt8; */ 0, /* PaUtilConverter *Int16_To_UInt8_Dither; */ 0, /* PaUtilConverter *Int8_To_Float32; */ 0, /* PaUtilConverter *Int8_To_Int32; */ 0, /* PaUtilConverter *Int8_To_Int24 */ 0, /* PaUtilConverter *Int8_To_Int16; */ 0, /* PaUtilConverter *Int8_To_UInt8; */ 0, /* PaUtilConverter *UInt8_To_Float32; */ 0, /* PaUtilConverter *UInt8_To_Int32; */ 0, /* PaUtilConverter *UInt8_To_Int24; */ 0, /* PaUtilConverter *UInt8_To_Int16; */ 0, /* PaUtilConverter *UInt8_To_Int8; */ 0, /* PaUtilConverter *Copy_8_To_8; */ 0, /* PaUtilConverter *Copy_16_To_16; */ 0, /* PaUtilConverter *Copy_24_To_24; */ 0 /* PaUtilConverter *Copy_32_To_32; */ }; /* -------------------------------------------------------------------------- */ #else /* PA_NO_STANDARD_CONVERTERS is not defined */ /* -------------------------------------------------------------------------- */ #define PA_CLIP_( val, min, max )\ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */ static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */ static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */ /* -------------------------------------------------------------------------- */ static void Float32_To_Int32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* REVIEW */ #ifdef PA_USE_C99_LRINTF float scaled = *src * 0x7FFFFFFF; *dest = lrintf(scaled-0.5f); #else double scaled = *src * 0x7FFFFFFF; *dest = (PaInt32) scaled; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int32_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; while( count-- ) { /* REVIEW */ #ifdef PA_USE_C99_LRINTF float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ float dithered = ((float)*src * (2147483646.0f)) + dither; *dest = lrintf(dithered - 0.5f); #else double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ double dithered = ((double)*src * (2147483646.0)) + dither; *dest = (PaInt32) dithered; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int32_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { /* REVIEW */ #ifdef PA_USE_C99_LRINTF float scaled = *src * 0x7FFFFFFF; PA_CLIP_( scaled, -2147483648.f, 2147483647.f ); *dest = lrintf(scaled-0.5f); #else double scaled = *src * 0x7FFFFFFF; PA_CLIP_( scaled, -2147483648., 2147483647. ); *dest = (PaInt32) scaled; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int32_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; while( count-- ) { /* REVIEW */ #ifdef PA_USE_C99_LRINTF float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ float dithered = ((float)*src * (2147483646.0f)) + dither; PA_CLIP_( dithered, -2147483648.f, 2147483647.f ); *dest = lrintf(dithered-0.5f); #else double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ double dithered = ((double)*src * (2147483646.0)) + dither; PA_CLIP_( dithered, -2147483648., 2147483647. ); *dest = (PaInt32) dithered; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; PaInt32 temp; (void) ditherGenerator; /* unused parameter */ while( count-- ) { /* convert to 32 bit and drop the low 8 bits */ double scaled = *src * 0x7FFFFFFF; temp = (PaInt32) scaled; #if defined(PA_LITTLE_ENDIAN) dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(temp >> 24); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 8); #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; PaInt32 temp; while( count-- ) { /* convert to 32 bit and drop the low 8 bits */ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ double dithered = ((double)*src * (2147483646.0)) + dither; temp = (PaInt32) dithered; #if defined(PA_LITTLE_ENDIAN) dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(temp >> 24); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 8); #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; PaInt32 temp; (void) ditherGenerator; /* unused parameter */ while( count-- ) { /* convert to 32 bit and drop the low 8 bits */ double scaled = *src * 0x7FFFFFFF; PA_CLIP_( scaled, -2147483648., 2147483647. ); temp = (PaInt32) scaled; #if defined(PA_LITTLE_ENDIAN) dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(temp >> 24); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 8); #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; PaInt32 temp; while( count-- ) { /* convert to 32 bit and drop the low 8 bits */ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ double dithered = ((double)*src * (2147483646.0)) + dither; PA_CLIP_( dithered, -2147483648., 2147483647. ); temp = (PaInt32) dithered; #if defined(PA_LITTLE_ENDIAN) dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(temp >> 24); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 8); #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { #ifdef PA_USE_C99_LRINTF float tempf = (*src * (32767.0f)) ; *dest = lrintf(tempf-0.5f); #else short samp = (short) (*src * (32767.0f)); *dest = samp; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; while( count-- ) { float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ float dithered = (*src * (32766.0f)) + dither; #ifdef PA_USE_C99_LRINTF *dest = lrintf(dithered-0.5f); #else *dest = (PaInt16) dithered; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { #ifdef PA_USE_C99_LRINTF long samp = lrintf((*src * (32767.0f)) -0.5f); #else long samp = (PaInt32) (*src * (32767.0f)); #endif PA_CLIP_( samp, -0x8000, 0x7FFF ); *dest = (PaInt16) samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ float dithered = (*src * (32766.0f)) + dither; PaInt32 samp = (PaInt32) dithered; PA_CLIP_( samp, -0x8000, 0x7FFF ); #ifdef PA_USE_C99_LRINTF *dest = lrintf(samp-0.5f); #else *dest = (PaInt16) samp; #endif src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { signed char samp = (signed char) (*src * (127.0f)); *dest = samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ float dithered = (*src * (126.0f)) + dither; PaInt32 samp = (PaInt32) dithered; *dest = (signed char) samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int8_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { PaInt32 samp = (PaInt32)(*src * (127.0f)); PA_CLIP_( samp, -0x80, 0x7F ); *dest = (signed char) samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int8_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); /* use smaller scaler to prevent overflow when we add the dither */ float dithered = (*src * (126.0f)) + dither; PaInt32 samp = (PaInt32) dithered; PA_CLIP_( samp, -0x80, 0x7F ); *dest = (signed char) samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_UInt8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f)))); *dest = samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_UInt8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* IMPLEMENT ME */ src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_UInt8_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* IMPLEMENT ME */ src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Float32_To_UInt8_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* IMPLEMENT ME */ src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_Float32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; float *dest = (float*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { *dest = (float) ((double)*src * const_1_div_2147483648_); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_Int24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { /* REVIEW */ #if defined(PA_LITTLE_ENDIAN) dest[0] = (unsigned char)(*src >> 8); dest[1] = (unsigned char)(*src >> 16); dest[2] = (unsigned char)(*src >> 24); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(*src >> 24); dest[1] = (unsigned char)(*src >> 16); dest[2] = (unsigned char)(*src >> 8); #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Int32_To_Int24_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { (void) destinationBuffer; /* unused parameters */ (void) destinationStride; /* unused parameters */ (void) sourceBuffer; /* unused parameters */ (void) sourceStride; /* unused parameters */ (void) count; /* unused parameters */ (void) ditherGenerator; /* unused parameters */ /* IMPLEMENT ME */ } /* -------------------------------------------------------------------------- */ static void Int32_To_Int16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { *dest = (PaInt16) ((*src) >> 16); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_Int16_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; PaInt32 dither; while( count-- ) { /* REVIEW */ dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); *dest = (PaInt16) ((((*src)>>1) + dither) >> 15); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_Int8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { *dest = (signed char) ((*src) >> 24); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_Int8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; PaInt32 dither; while( count-- ) { /* REVIEW */ dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); *dest = (signed char) ((((*src)>>1) + dither) >> 23); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_UInt8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (unsigned char)(((*src) >> 24) + 128); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int32_To_UInt8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt32 *src = (PaInt32*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* IMPLEMENT ME */ src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int24_To_Float32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; float *dest = (float*)destinationBuffer; PaInt32 temp; (void) ditherGenerator; /* unused parameter */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) temp = (((long)src[0]) << 8); temp = temp | (((long)src[1]) << 16); temp = temp | (((long)src[2]) << 24); #elif defined(PA_BIG_ENDIAN) temp = (((long)src[0]) << 24); temp = temp | (((long)src[1]) << 16); temp = temp | (((long)src[2]) << 8); #endif *dest = (float) ((double)temp * const_1_div_2147483648_); src += sourceStride * 3; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int24_To_Int32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; PaInt32 *dest = (PaInt32*) destinationBuffer; PaInt32 temp; (void) ditherGenerator; /* unused parameter */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) temp = (((long)src[0]) << 8); temp = temp | (((long)src[1]) << 16); temp = temp | (((long)src[2]) << 24); #elif defined(PA_BIG_ENDIAN) temp = (((long)src[0]) << 24); temp = temp | (((long)src[1]) << 16); temp = temp | (((long)src[2]) << 8); #endif *dest = temp; src += sourceStride * 3; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int24_To_Int16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; PaInt16 temp; (void) ditherGenerator; /* unused parameter */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) /* src[0] is discarded */ temp = (((PaInt16)src[1])); temp = temp | (PaInt16)(((PaInt16)src[2]) << 8); #elif defined(PA_BIG_ENDIAN) /* src[2] is discarded */ temp = (PaInt16)(((PaInt16)src[0]) << 8); temp = temp | (((PaInt16)src[1])); #endif *dest = temp; src += sourceStride * 3; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int24_To_Int16_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { (void) destinationBuffer; /* unused parameters */ (void) destinationStride; /* unused parameters */ (void) sourceBuffer; /* unused parameters */ (void) sourceStride; /* unused parameters */ (void) count; /* unused parameters */ (void) ditherGenerator; /* unused parameters */ /* IMPLEMENT ME */ } /* -------------------------------------------------------------------------- */ static void Int24_To_Int8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) /* src[0] is discarded */ /* src[1] is discarded */ *dest = src[2]; #elif defined(PA_BIG_ENDIAN) /* src[2] is discarded */ /* src[1] is discarded */ *dest = src[0]; #endif src += sourceStride * 3; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int24_To_Int8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { (void) destinationBuffer; /* unused parameters */ (void) destinationStride; /* unused parameters */ (void) sourceBuffer; /* unused parameters */ (void) sourceStride; /* unused parameters */ (void) count; /* unused parameters */ (void) ditherGenerator; /* unused parameters */ /* IMPLEMENT ME */ } /* -------------------------------------------------------------------------- */ static void Int24_To_UInt8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) /* src[0] is discarded */ /* src[1] is discarded */ *dest = (unsigned char)(src[2] + 128); #elif defined(PA_BIG_ENDIAN) *dest = (unsigned char)(src[0] + 128); /* src[1] is discarded */ /* src[2] is discarded */ #endif src += sourceStride * 3; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int24_To_UInt8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { (void) destinationBuffer; /* unused parameters */ (void) destinationStride; /* unused parameters */ (void) sourceBuffer; /* unused parameters */ (void) sourceStride; /* unused parameters */ (void) count; /* unused parameters */ (void) ditherGenerator; /* unused parameters */ /* IMPLEMENT ME */ } /* -------------------------------------------------------------------------- */ static void Int16_To_Float32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*)sourceBuffer; float *dest = (float*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */ *dest = samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int16_To_Int32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* REVIEW: we should consider something like (*src << 16) | (*src & 0xFFFF) */ *dest = *src << 16; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int16_To_Int24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*) sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; PaInt16 temp; (void) ditherGenerator; /* unused parameter */ while( count-- ) { temp = *src; #if defined(PA_LITTLE_ENDIAN) dest[0] = 0; dest[1] = (unsigned char)(temp); dest[2] = (unsigned char)(temp >> 8); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp); dest[2] = 0; #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Int16_To_Int8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (signed char)((*src) >> 8); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int16_To_Int8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* IMPLEMENT ME */ src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int16_To_UInt8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (unsigned char)(((*src) >> 8) + 128); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int16_To_UInt8_Dither( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaInt16 *src = (PaInt16*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { /* IMPLEMENT ME */ src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int8_To_Float32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { signed char *src = (signed char*)sourceBuffer; float *dest = (float*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { float samp = *src * const_1_div_128_; *dest = samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int8_To_Int32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { signed char *src = (signed char*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (*src) << 24; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int8_To_Int24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { signed char *src = (signed char*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) dest[0] = 0; dest[1] = 0; dest[2] = (*src); #elif defined(PA_BIG_ENDIAN) dest[0] = (*src); dest[1] = 0; dest[2] = 0; #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Int8_To_Int16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { signed char *src = (signed char*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (PaInt16)((*src) << 8); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Int8_To_UInt8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { signed char *src = (signed char*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (unsigned char)(*src + 128); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void UInt8_To_Float32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; float *dest = (float*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { float samp = (*src - 128) * const_1_div_128_; *dest = samp; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void UInt8_To_Int32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; PaInt32 *dest = (PaInt32*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (*src - 128) << 24; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void UInt8_To_Int24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void) ditherGenerator; /* unused parameters */ while( count-- ) { #if defined(PA_LITTLE_ENDIAN) dest[0] = 0; dest[1] = 0; dest[2] = (unsigned char)(*src - 128); #elif defined(PA_BIG_ENDIAN) dest[0] = (unsigned char)(*src - 128); dest[1] = 0; dest[2] = 0; #endif src += sourceStride; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void UInt8_To_Int16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; PaInt16 *dest = (PaInt16*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (PaInt16)((*src - 128) << 8); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void UInt8_To_Int8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; signed char *dest = (signed char*)destinationBuffer; (void)ditherGenerator; /* unused parameter */ while( count-- ) { (*dest) = (signed char)(*src - 128); src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Copy_8_To_8( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { *dest = *src; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Copy_16_To_16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaUint16 *src = (PaUint16 *)sourceBuffer; PaUint16 *dest = (PaUint16 *)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { *dest = *src; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Copy_24_To_24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { unsigned char *src = (unsigned char*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; src += sourceStride * 3; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Copy_32_To_32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { PaUint32 *dest = (PaUint32 *)destinationBuffer; PaUint32 *src = (PaUint32 *)sourceBuffer; (void) ditherGenerator; /* unused parameter */ while( count-- ) { *dest = *src; src += sourceStride; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ PaUtilConverterTable paConverters = { Float32_To_Int32, /* PaUtilConverter *Float32_To_Int32; */ Float32_To_Int32_Dither, /* PaUtilConverter *Float32_To_Int32_Dither; */ Float32_To_Int32_Clip, /* PaUtilConverter *Float32_To_Int32_Clip; */ Float32_To_Int32_DitherClip, /* PaUtilConverter *Float32_To_Int32_DitherClip; */ Float32_To_Int24, /* PaUtilConverter *Float32_To_Int24; */ Float32_To_Int24_Dither, /* PaUtilConverter *Float32_To_Int24_Dither; */ Float32_To_Int24_Clip, /* PaUtilConverter *Float32_To_Int24_Clip; */ Float32_To_Int24_DitherClip, /* PaUtilConverter *Float32_To_Int24_DitherClip; */ Float32_To_Int16, /* PaUtilConverter *Float32_To_Int16; */ Float32_To_Int16_Dither, /* PaUtilConverter *Float32_To_Int16_Dither; */ Float32_To_Int16_Clip, /* PaUtilConverter *Float32_To_Int16_Clip; */ Float32_To_Int16_DitherClip, /* PaUtilConverter *Float32_To_Int16_DitherClip; */ Float32_To_Int8, /* PaUtilConverter *Float32_To_Int8; */ Float32_To_Int8_Dither, /* PaUtilConverter *Float32_To_Int8_Dither; */ Float32_To_Int8_Clip, /* PaUtilConverter *Float32_To_Int8_Clip; */ Float32_To_Int8_DitherClip, /* PaUtilConverter *Float32_To_Int8_DitherClip; */ Float32_To_UInt8, /* PaUtilConverter *Float32_To_UInt8; */ Float32_To_UInt8_Dither, /* PaUtilConverter *Float32_To_UInt8_Dither; */ Float32_To_UInt8_Clip, /* PaUtilConverter *Float32_To_UInt8_Clip; */ Float32_To_UInt8_DitherClip, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */ Int32_To_Float32, /* PaUtilConverter *Int32_To_Float32; */ Int32_To_Int24, /* PaUtilConverter *Int32_To_Int24; */ Int32_To_Int24_Dither, /* PaUtilConverter *Int32_To_Int24_Dither; */ Int32_To_Int16, /* PaUtilConverter *Int32_To_Int16; */ Int32_To_Int16_Dither, /* PaUtilConverter *Int32_To_Int16_Dither; */ Int32_To_Int8, /* PaUtilConverter *Int32_To_Int8; */ Int32_To_Int8_Dither, /* PaUtilConverter *Int32_To_Int8_Dither; */ Int32_To_UInt8, /* PaUtilConverter *Int32_To_UInt8; */ Int32_To_UInt8_Dither, /* PaUtilConverter *Int32_To_UInt8_Dither; */ Int24_To_Float32, /* PaUtilConverter *Int24_To_Float32; */ Int24_To_Int32, /* PaUtilConverter *Int24_To_Int32; */ Int24_To_Int16, /* PaUtilConverter *Int24_To_Int16; */ Int24_To_Int16_Dither, /* PaUtilConverter *Int24_To_Int16_Dither; */ Int24_To_Int8, /* PaUtilConverter *Int24_To_Int8; */ Int24_To_Int8_Dither, /* PaUtilConverter *Int24_To_Int8_Dither; */ Int24_To_UInt8, /* PaUtilConverter *Int24_To_UInt8; */ Int24_To_UInt8_Dither, /* PaUtilConverter *Int24_To_UInt8_Dither; */ Int16_To_Float32, /* PaUtilConverter *Int16_To_Float32; */ Int16_To_Int32, /* PaUtilConverter *Int16_To_Int32; */ Int16_To_Int24, /* PaUtilConverter *Int16_To_Int24; */ Int16_To_Int8, /* PaUtilConverter *Int16_To_Int8; */ Int16_To_Int8_Dither, /* PaUtilConverter *Int16_To_Int8_Dither; */ Int16_To_UInt8, /* PaUtilConverter *Int16_To_UInt8; */ Int16_To_UInt8_Dither, /* PaUtilConverter *Int16_To_UInt8_Dither; */ Int8_To_Float32, /* PaUtilConverter *Int8_To_Float32; */ Int8_To_Int32, /* PaUtilConverter *Int8_To_Int32; */ Int8_To_Int24, /* PaUtilConverter *Int8_To_Int24 */ Int8_To_Int16, /* PaUtilConverter *Int8_To_Int16; */ Int8_To_UInt8, /* PaUtilConverter *Int8_To_UInt8; */ UInt8_To_Float32, /* PaUtilConverter *UInt8_To_Float32; */ UInt8_To_Int32, /* PaUtilConverter *UInt8_To_Int32; */ UInt8_To_Int24, /* PaUtilConverter *UInt8_To_Int24; */ UInt8_To_Int16, /* PaUtilConverter *UInt8_To_Int16; */ UInt8_To_Int8, /* PaUtilConverter *UInt8_To_Int8; */ Copy_8_To_8, /* PaUtilConverter *Copy_8_To_8; */ Copy_16_To_16, /* PaUtilConverter *Copy_16_To_16; */ Copy_24_To_24, /* PaUtilConverter *Copy_24_To_24; */ Copy_32_To_32 /* PaUtilConverter *Copy_32_To_32; */ }; /* -------------------------------------------------------------------------- */ #endif /* PA_NO_STANDARD_CONVERTERS */ /* -------------------------------------------------------------------------- */ PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat ) { switch( destinationFormat & ~paNonInterleaved ){ case paFloat32: return paZeroers.Zero32; case paInt32: return paZeroers.Zero32; case paInt24: return paZeroers.Zero24; case paInt16: return paZeroers.Zero16; case paInt8: return paZeroers.Zero8; case paUInt8: return paZeroers.ZeroU8; default: return 0; } } /* -------------------------------------------------------------------------- */ #ifdef PA_NO_STANDARD_ZEROERS /* -------------------------------------------------------------------------- */ PaUtilZeroerTable paZeroers = { 0, /* PaUtilZeroer *ZeroU8; */ 0, /* PaUtilZeroer *Zero8; */ 0, /* PaUtilZeroer *Zero16; */ 0, /* PaUtilZeroer *Zero24; */ 0, /* PaUtilZeroer *Zero32; */ }; /* -------------------------------------------------------------------------- */ #else /* PA_NO_STANDARD_ZEROERS is not defined */ /* -------------------------------------------------------------------------- */ static void ZeroU8( void *destinationBuffer, signed int destinationStride, unsigned int count ) { unsigned char *dest = (unsigned char*)destinationBuffer; while( count-- ) { *dest = 128; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Zero8( void *destinationBuffer, signed int destinationStride, unsigned int count ) { unsigned char *dest = (unsigned char*)destinationBuffer; while( count-- ) { *dest = 0; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Zero16( void *destinationBuffer, signed int destinationStride, unsigned int count ) { PaUint16 *dest = (PaUint16 *)destinationBuffer; while( count-- ) { *dest = 0; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ static void Zero24( void *destinationBuffer, signed int destinationStride, unsigned int count ) { unsigned char *dest = (unsigned char*)destinationBuffer; while( count-- ) { dest[0] = 0; dest[1] = 0; dest[2] = 0; dest += destinationStride * 3; } } /* -------------------------------------------------------------------------- */ static void Zero32( void *destinationBuffer, signed int destinationStride, unsigned int count ) { PaUint32 *dest = (PaUint32 *)destinationBuffer; while( count-- ) { *dest = 0; dest += destinationStride; } } /* -------------------------------------------------------------------------- */ PaUtilZeroerTable paZeroers = { ZeroU8, /* PaUtilZeroer *ZeroU8; */ Zero8, /* PaUtilZeroer *Zero8; */ Zero16, /* PaUtilZeroer *Zero16; */ Zero24, /* PaUtilZeroer *Zero24; */ Zero32, /* PaUtilZeroer *Zero32; */ }; /* -------------------------------------------------------------------------- */ #endif /* PA_NO_STANDARD_ZEROERS */ nyquist-3.05/portaudio/src/common/pa_ringbuffer.h0000644000175000000620000001506011466723256021250 0ustar stevestaff#ifndef PA_RINGBUFFER_H #define PA_RINGBUFFER_H /* * $Id: pa_ringbuffer.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library * Ring Buffer utility. * * Author: Phil Burk, http://www.softsynth.com * modified for SMP safety on OS X by Bjorn Roche. * also allowed for const where possible. * Note that this is safe only for a single-thread reader * and a single-thread writer. * * This program is distributed with the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct PaUtilRingBuffer { long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */ long writeIndex; /* Index of next writable byte. Set by PaUtil_AdvanceRingBufferWriteIndex. */ long readIndex; /* Index of next readable byte. Set by PaUtil_AdvanceRingBufferReadIndex. */ long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ long smallMask; /* Used for fitting indices to buffer. */ char *buffer; }PaUtilRingBuffer; /** Initialize Ring Buffer. @param rbuf The ring buffer. @param numBytes The number of bytes in the buffer and must be power of 2. @param dataPtr A pointer to a previously allocated area where the data will be maintained. It must be numBytes long. @return -1 if numBytes is not a power of 2, otherwise 0. */ long PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, long numBytes, void *dataPtr ); /** Clear buffer. Should only be called when buffer is NOT being read. @param rbuf The ring buffer. */ void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ); /** Retrieve the number of bytes available in the ring buffer for writing. @param rbuf The ring buffer. @return The number of bytes available for writing. */ long PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf ); /** Retrieve the number of bytes available in the ring buffer for reading. @param rbuf The ring buffer. @return The number of bytes available for reading. */ long PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf ); /** Write data to the ring buffer. @param rbuf The ring buffer. @param data The address of new data to write to the buffer. @param numBytes The number of bytes to be written. @return The number of bytes written. */ long PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, long numBytes ); /** Read data from the ring buffer. @param rbuf The ring buffer. @param data The address where the data should be stored. @param numBytes The number of bytes to be read. @return The number of bytes read. */ long PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, long numBytes ); /** Get address of region(s) to which we can write data. @param rbuf The ring buffer. @param numBytes The number of bytes desired. @param dataPtr1 The address where the first (or only) region pointer will be stored. @param sizePtr1 The address where the first (or only) region length will be stored. @param dataPtr2 The address where the second region pointer will be stored if the first region is too small to satisfy numBytes. @param sizePtr2 The address where the second region length will be stored if the first region is too small to satisfy numBytes. @return The room available to be written or numBytes, whichever is smaller. */ long PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ); /** Advance the write index to the next location to be written. @param rbuf The ring buffer. @param numBytes The number of bytes to advance. @return The new position. */ long PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, long numBytes ); /** Get address of region(s) from which we can write data. @param rbuf The ring buffer. @param numBytes The number of bytes desired. @param dataPtr1 The address where the first (or only) region pointer will be stored. @param sizePtr1 The address where the first (or only) region length will be stored. @param dataPtr2 The address where the second region pointer will be stored if the first region is too small to satisfy numBytes. @param sizePtr2 The address where the second region length will be stored if the first region is too small to satisfy numBytes. @return The number of bytes available for reading. */ long PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ); /** Advance the read index to the next location to be read. @param rbuf The ring buffer. @param numBytes The number of bytes to advance. @return The new position. */ long PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, long numBytes ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_RINGBUFFER_H */ nyquist-3.05/portaudio/src/common/pa_debugprint.c0000644000175000000620000000644411466723256021263 0ustar stevestaff/* * $Id: pa_debugprint.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library Multi-Host API front end * Validate function parameters and manage multiple host APIs. * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2006 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Implements log function. PaUtil_SetLogPrintFunction can be user called to replace the provided DefaultLogPrint function, which writes to stderr. One can NOT pass var_args across compiler/dll boundaries as it is not "byte code/abi portable". So the technique used here is to allocate a local a static array, write in it, then callback the user with a pointer to its start. @todo Consider allocating strdump using dynamic allocation. @todo Consider reentrancy and possibly corrupted strdump buffer. */ #include #include #include "pa_debugprint.h" static PaUtilLogCallback userCB=0; void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb) { userCB = cb; } /* If your platform doesnt have vsnprintf, you are stuck with a VERY dangerous alternative, vsprintf (with no n) */ #if (_MSC_VER) && (_MSC_VER <= 1400) #define VSNPRINTF _vsnprintf #else #define VSNPRINTF vsnprintf #endif #define SIZEDUMP 1024 static char strdump[SIZEDUMP]; void PaUtil_DebugPrint( const char *format, ... ) { if (userCB) { va_list ap; va_start( ap, format ); VSNPRINTF( strdump, SIZEDUMP, format, ap ); userCB(strdump); va_end( ap ); } else { va_list ap; va_start( ap, format ); vfprintf( stderr, format, ap ); va_end( ap ); fflush( stderr ); } } nyquist-3.05/portaudio/src/common/pa_converters.h0000644000175000000620000002376211466723256021321 0ustar stevestaff#ifndef PA_CONVERTERS_H #define PA_CONVERTERS_H /* * $Id: pa_converters.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library sample conversion mechanism * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Phil Burk, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Conversion functions used to convert buffers of samples from one format to another. */ #include "portaudio.h" /* for PaSampleFormat */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct PaUtilTriangularDitherGenerator; /** Choose an available sample format which is most appropriate for representing the requested format. If the requested format is not available higher quality formats are considered before lower quality formates. @param availableFormats A variable containing the logical OR of all available formats. @param format The desired format. @return The most appropriate available format for representing the requested format. */ PaSampleFormat PaUtil_SelectClosestAvailableFormat( PaSampleFormat availableFormats, PaSampleFormat format ); /* high level conversions functions for use by implementations */ /** The generic sample converter prototype. Sample converters convert count samples from sourceBuffer to destinationBuffer. The actual type of the data pointed to by these parameters varys for different converter functions. @param destinationBuffer A pointer to the first sample of the destination. @param destinationStride An offset between successive destination samples expressed in samples (not bytes.) It may be negative. @param sourceBuffer A pointer to the first sample of the source. @param sourceStride An offset between successive source samples expressed in samples (not bytes.) It may be negative. @param count The number of samples to convert. @param ditherState State information used to calculate dither. Converters that do not perform dithering will ignore this parameter, in which case NULL or invalid dither state may be passed. */ typedef void PaUtilConverter( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ); /** Find a sample converter function for the given source and destinations formats and flags (clip and dither.) @return A pointer to a PaUtilConverter which will perform the requested conversion, or NULL if the given format conversion is not supported. For conversions where clipping or dithering is not necessary, the clip and dither flags are ignored and a non-clipping or dithering version is returned. If the source and destination formats are the same, a function which copies data of the appropriate size will be returned. */ PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat, PaStreamFlags flags ); /** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to destinationBuffer. The actual type of the data pointed to varys for different zeroer functions. @param destinationBuffer A pointer to the first sample of the destination. @param destinationStride An offset between successive destination samples expressed in samples (not bytes.) It may be negative. @param count The number of samples to zero. */ typedef void PaUtilZeroer( void *destinationBuffer, signed int destinationStride, unsigned int count ); /** Find a buffer zeroer function for the given destination format. @return A pointer to a PaUtilZeroer which will perform the requested zeroing. */ PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat ); /*----------------------------------------------------------------------------*/ /* low level functions and data structures which may be used for substituting conversion functions */ /** The type used to store all sample conversion functions. @see paConverters; */ typedef struct{ PaUtilConverter *Float32_To_Int32; PaUtilConverter *Float32_To_Int32_Dither; PaUtilConverter *Float32_To_Int32_Clip; PaUtilConverter *Float32_To_Int32_DitherClip; PaUtilConverter *Float32_To_Int24; PaUtilConverter *Float32_To_Int24_Dither; PaUtilConverter *Float32_To_Int24_Clip; PaUtilConverter *Float32_To_Int24_DitherClip; PaUtilConverter *Float32_To_Int16; PaUtilConverter *Float32_To_Int16_Dither; PaUtilConverter *Float32_To_Int16_Clip; PaUtilConverter *Float32_To_Int16_DitherClip; PaUtilConverter *Float32_To_Int8; PaUtilConverter *Float32_To_Int8_Dither; PaUtilConverter *Float32_To_Int8_Clip; PaUtilConverter *Float32_To_Int8_DitherClip; PaUtilConverter *Float32_To_UInt8; PaUtilConverter *Float32_To_UInt8_Dither; PaUtilConverter *Float32_To_UInt8_Clip; PaUtilConverter *Float32_To_UInt8_DitherClip; PaUtilConverter *Int32_To_Float32; PaUtilConverter *Int32_To_Int24; PaUtilConverter *Int32_To_Int24_Dither; PaUtilConverter *Int32_To_Int16; PaUtilConverter *Int32_To_Int16_Dither; PaUtilConverter *Int32_To_Int8; PaUtilConverter *Int32_To_Int8_Dither; PaUtilConverter *Int32_To_UInt8; PaUtilConverter *Int32_To_UInt8_Dither; PaUtilConverter *Int24_To_Float32; PaUtilConverter *Int24_To_Int32; PaUtilConverter *Int24_To_Int16; PaUtilConverter *Int24_To_Int16_Dither; PaUtilConverter *Int24_To_Int8; PaUtilConverter *Int24_To_Int8_Dither; PaUtilConverter *Int24_To_UInt8; PaUtilConverter *Int24_To_UInt8_Dither; PaUtilConverter *Int16_To_Float32; PaUtilConverter *Int16_To_Int32; PaUtilConverter *Int16_To_Int24; PaUtilConverter *Int16_To_Int8; PaUtilConverter *Int16_To_Int8_Dither; PaUtilConverter *Int16_To_UInt8; PaUtilConverter *Int16_To_UInt8_Dither; PaUtilConverter *Int8_To_Float32; PaUtilConverter *Int8_To_Int32; PaUtilConverter *Int8_To_Int24; PaUtilConverter *Int8_To_Int16; PaUtilConverter *Int8_To_UInt8; PaUtilConverter *UInt8_To_Float32; PaUtilConverter *UInt8_To_Int32; PaUtilConverter *UInt8_To_Int24; PaUtilConverter *UInt8_To_Int16; PaUtilConverter *UInt8_To_Int8; PaUtilConverter *Copy_8_To_8; /* copy without any conversion */ PaUtilConverter *Copy_16_To_16; /* copy without any conversion */ PaUtilConverter *Copy_24_To_24; /* copy without any conversion */ PaUtilConverter *Copy_32_To_32; /* copy without any conversion */ } PaUtilConverterTable; /** A table of pointers to all required converter functions. PaUtil_SelectConverter() uses this table to lookup the appropriate conversion functions. The fields of this structure are initialized with default conversion functions. Fields may be NULL, indicating that no conversion function is available. User code may substitue optimised conversion functions by assigning different function pointers to these fields. @note If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined, PortAudio's standard converters will not be compiled, and all fields of this structure will be initialized to NULL. In such cases, users should supply their own conversion functions if the require PortAudio to open a stream that requires sample conversion. @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter */ extern PaUtilConverterTable paConverters; /** The type used to store all buffer zeroing functions. @see paZeroers; */ typedef struct{ PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */ PaUtilZeroer *Zero8; PaUtilZeroer *Zero16; PaUtilZeroer *Zero24; PaUtilZeroer *Zero32; } PaUtilZeroerTable; /** A table of pointers to all required zeroer functions. PaUtil_SelectZeroer() uses this table to lookup the appropriate conversion functions. The fields of this structure are initialized with default conversion functions. User code may substitue optimised conversion functions by assigning different function pointers to these fields. @note If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined, PortAudio's standard zeroers will not be compiled, and all fields of this structure will be initialized to NULL. In such cases, users should supply their own zeroing functions for the sample sizes which they intend to use. @see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer */ extern PaUtilZeroerTable paZeroers; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_CONVERTERS_H */ nyquist-3.05/portaudio/src/common/pa_allocation.c0000644000175000000620000001540711466723256021244 0ustar stevestaff/* * $Id: pa_allocation.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library allocation group implementation * memory allocation group for tracking allocation groups * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Allocation Group implementation. */ #include "pa_allocation.h" #include "pa_util.h" /* Maintain 3 singly linked lists... linkBlocks: the buffers used to allocate the links spareLinks: links available for use in the allocations list allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory() Link block size is doubled every time new links are allocated. */ #define PA_INITIAL_LINK_COUNT_ 16 struct PaUtilAllocationGroupLink { struct PaUtilAllocationGroupLink *next; void *buffer; }; /* Allocate a block of links. The first link will have it's buffer member pointing to the block, and it's next member set to . The remaining links will have NULL buffer members, and each link will point to the next link except the last, which will point to */ static struct PaUtilAllocationGroupLink *AllocateLinks( long count, struct PaUtilAllocationGroupLink *nextBlock, struct PaUtilAllocationGroupLink *nextSpare ) { struct PaUtilAllocationGroupLink *result; int i; result = (struct PaUtilAllocationGroupLink *)PaUtil_AllocateMemory( sizeof(struct PaUtilAllocationGroupLink) * count ); if( result ) { /* the block link */ result[0].buffer = result; result[0].next = nextBlock; /* the spare links */ for( i=1; ilinkCount = PA_INITIAL_LINK_COUNT_; result->linkBlocks = &links[0]; result->spareLinks = &links[1]; result->allocations = 0; } else { PaUtil_FreeMemory( links ); } } return result; } void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ) { struct PaUtilAllocationGroupLink *current = group->linkBlocks; struct PaUtilAllocationGroupLink *next; while( current ) { next = current->next; PaUtil_FreeMemory( current->buffer ); current = next; } PaUtil_FreeMemory( group ); } void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ) { struct PaUtilAllocationGroupLink *links, *link; void *result = 0; /* allocate more links if necessary */ if( !group->spareLinks ) { /* double the link count on each block allocation */ links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks ); if( links ) { group->linkCount += group->linkCount; group->linkBlocks = &links[0]; group->spareLinks = &links[1]; } } if( group->spareLinks ) { result = PaUtil_AllocateMemory( size ); if( result ) { link = group->spareLinks; group->spareLinks = link->next; link->buffer = result; link->next = group->allocations; group->allocations = link; } } return result; } void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ) { struct PaUtilAllocationGroupLink *current = group->allocations; struct PaUtilAllocationGroupLink *previous = 0; if( buffer == 0 ) return; /* find the right link and remove it */ while( current ) { if( current->buffer == buffer ) { if( previous ) { previous->next = current->next; } else { group->allocations = current->next; } current->buffer = 0; current->next = group->spareLinks; group->spareLinks = current; break; } previous = current; current = current->next; } PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */ } void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ) { struct PaUtilAllocationGroupLink *current = group->allocations; struct PaUtilAllocationGroupLink *previous = 0; /* free all buffers in the allocations list */ while( current ) { PaUtil_FreeMemory( current->buffer ); current->buffer = 0; previous = current; current = current->next; } /* link the former allocations list onto the front of the spareLinks list */ if( previous ) { previous->next = group->spareLinks; group->spareLinks = group->allocations; group->allocations = 0; } } nyquist-3.05/portaudio/src/common/pa_process.h0000644000175000000620000007623611466723256020611 0ustar stevestaff#ifndef PA_PROCESS_H #define PA_PROCESS_H /* * $Id: pa_process.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library callback buffer processing adapters * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Phil Burk, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Buffer Processor prototypes. A Buffer Processor performs buffer length adaption, coordinates sample format conversion, and interleaves/deinterleaves channels.

    Overview

    The "Buffer Processor" (PaUtilBufferProcessor) manages conversion of audio data from host buffers to user buffers and back again. Where required, the buffer processor takes care of converting between host and user sample formats, interleaving and deinterleaving multichannel buffers, and adapting between host and user buffers with different lengths. The buffer processor may be used with full and half duplex streams, for both callback streams and blocking read/write streams. One of the important capabilities provided by the buffer processor is the ability to adapt between user and host buffer sizes of different lengths with minimum latency. Although this task is relatively easy to perform when the host buffer size is an integer multiple of the user buffer size, the problem is more complicated when this is not the case - especially for full-duplex callback streams. Where necessary the adaption is implemented by internally buffering some input and/or output data. The buffer adation algorithm used by the buffer processor was originally implemented by Stephan Letz for the ASIO version of PortAudio, and is described in his Callback_adaption_.pdf which is included in the distribution. The buffer processor performs sample conversion using the functions provided by pa_converters.c. The following sections provide an overview of how to use the buffer processor. Interested readers are advised to consult the host API implementations for examples of buffer processor usage.

    Initialization, resetting and termination

    When a stream is opened, the buffer processor should be initialized using PaUtil_InitializeBufferProcessor. This function initializes internal state and allocates temporary buffers as neccesary according to the supplied configuration parameters. Some of the parameters correspond to those requested by the user in their call to Pa_OpenStream(), others reflect the requirements of the host API implementation - they indicate host buffer sizes, formats, and the type of buffering which the Host API uses. The buffer processor should be initialized for callback streams and blocking read/write streams. Call PaUtil_ResetBufferProcessor to clear any sample data which is present in the buffer processor before starting to use it (for example when Pa_StartStream is called). When the buffer processor is no longer used call PaUtil_TerminateBufferProcessor.

    Using the buffer processor for a callback stream

    The buffer processor's role in a callback stream is to take host input buffers process them with the stream callback, and fill host output buffers. For a full duplex stream, the buffer processor handles input and output simultaneously due to the requirements of the minimum-latency buffer adation algorithm. When a host buffer becomes available, the implementation should call the buffer processor to process the buffer. The buffer processor calls the stream callback to consume and/or produce audio data as necessary. The buffer processor will convert sample formats, interleave/deinterleave channels, and slice or chunk the data to the appropriate buffer lengths according to the requirements of the stream callback and the host API. To process a host buffer (or a pair of host buffers for a full-duplex stream) use the following calling sequence: -# Call PaUtil_BeginBufferProcessing -# For a stream which takes input: - Call PaUtil_SetInputFrameCount with the number of frames in the host input buffer. - Call one of the following functions one or more times to tell the buffer processor about the host input buffer(s): PaUtil_SetInputChannel, PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel. Which function you call will depend on whether the host buffer(s) are interleaved or not. - If the available host data is split accross two buffers (for example a data range at the end of a circular buffer and another range at the beginning of the circular buffer), also call PaUtil_Set2ndInputFrameCount, PaUtil_Set2ndInputChannel, PaUtil_Set2ndInterleavedInputChannels, PaUtil_Set2ndNonInterleavedInputChannel as necessary to tell the buffer processor about the second buffer. -# For a stream which generates output: - Call PaUtil_SetOutputFrameCount with the number of frames in the host output buffer. - Call one of the following functions one or more times to tell the buffer processor about the host output buffer(s): PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel. Which function you call will depend on whether the host buffer(s) are interleaved or not. - If the available host output buffer space is split accross two buffers (for example a data range at the end of a circular buffer and another range at the beginning of the circular buffer), call PaUtil_Set2ndOutputFrameCount, PaUtil_Set2ndOutputChannel, PaUtil_Set2ndInterleavedOutputChannels, PaUtil_Set2ndNonInterleavedOutputChannel as necessary to tell the buffer processor about the second buffer. -# Call PaUtil_EndBufferProcessing, this function performs the actual data conversion and processing.

    Using the buffer processor for a blocking read/write stream

    Blocking read/write streams use the buffer processor to convert and copy user output data to a host buffer, and to convert and copy host input data to the user's buffer. The buffer processor does not perform any buffer adaption. When using the buffer processor in a blocking read/write stream the input and output conversion are performed separately by the PaUtil_CopyInput and PaUtil_CopyOutput functions. To copy data from a host input buffer to the buffer(s) which the user supplies to Pa_ReadStream, use the following calling sequence. - Repeat the following three steps until the user buffer(s) have been filled with samples from the host input buffers: -# Call PaUtil_SetInputFrameCount with the number of frames in the host input buffer. -# Call one of the following functions one or more times to tell the buffer processor about the host input buffer(s): PaUtil_SetInputChannel, PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel. Which function you call will depend on whether the host buffer(s) are interleaved or not. -# Call PaUtil_CopyInput with the user buffer pointer (or a copy of the array of buffer pointers for a non-interleaved stream) passed to Pa_ReadStream, along with the number of frames in the user buffer(s). Be careful to pass a copy of the user buffer pointers to PaUtil_CopyInput because PaUtil_CopyInput advances the pointers to the start of the next region to copy. - PaUtil_CopyInput will not copy more data than is available in the host buffer(s), so the above steps need to be repeated until the user buffer(s) are full. To copy data to the host output buffer from the user buffers(s) supplied to Pa_WriteStream use the following calling sequence. - Repeat the following three steps until all frames from the user buffer(s) have been copied to the host API: -# Call PaUtil_SetOutputFrameCount with the number of frames in the host output buffer. -# Call one of the following functions one or more times to tell the buffer processor about the host output buffer(s): PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel. Which function you call will depend on whether the host buffer(s) are interleaved or not. -# Call PaUtil_CopyOutput with the user buffer pointer (or a copy of the array of buffer pointers for a non-interleaved stream) passed to Pa_WriteStream, along with the number of frames in the user buffer(s). Be careful to pass a copy of the user buffer pointers to PaUtil_CopyOutput because PaUtil_CopyOutput advances the pointers to the start of the next region to copy. - PaUtil_CopyOutput will not copy more data than fits in the host buffer(s), so the above steps need to be repeated until all user data is copied. */ #include "portaudio.h" #include "pa_converters.h" #include "pa_dither.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** @brief Mode flag passed to PaUtil_InitializeBufferProcessor indicating the type of buffering that the host API uses. The mode used depends on whether the host API or the implementation manages the buffers, and how these buffers are used (scatter gather, circular buffer). */ typedef enum { /** The host buffer size is a fixed known size. */ paUtilFixedHostBufferSize, /** The host buffer size may vary, but has a known maximum size. */ paUtilBoundedHostBufferSize, /** Nothing is known about the host buffer size. */ paUtilUnknownHostBufferSize, /** The host buffer size varies, and the client does not require the buffer processor to consume all of the input and fill all of the output buffer. This is useful when the implementation has access to the host API's circular buffer and only needs to consume/fill some of it, not necessarily all of it, with each call to the buffer processor. This is the only mode where PaUtil_EndBufferProcessing() may not consume the whole buffer. */ paUtilVariableHostBufferSizePartialUsageAllowed }PaUtilHostBufferSizeMode; /** @brief An auxilliary data structure used internally by the buffer processor to represent host input and output buffers. */ typedef struct PaUtilChannelDescriptor{ void *data; unsigned int stride; /**< stride in samples, not bytes */ }PaUtilChannelDescriptor; /** @brief The main buffer processor data structure. Allocate one of these, initialize it with PaUtil_InitializeBufferProcessor and terminate it with PaUtil_TerminateBufferProcessor. */ typedef struct { unsigned long framesPerUserBuffer; unsigned long framesPerHostBuffer; PaUtilHostBufferSizeMode hostBufferSizeMode; int useNonAdaptingProcess; unsigned long framesPerTempBuffer; unsigned int inputChannelCount; unsigned int bytesPerHostInputSample; unsigned int bytesPerUserInputSample; int userInputIsInterleaved; PaUtilConverter *inputConverter; PaUtilZeroer *inputZeroer; unsigned int outputChannelCount; unsigned int bytesPerHostOutputSample; unsigned int bytesPerUserOutputSample; int userOutputIsInterleaved; PaUtilConverter *outputConverter; PaUtilZeroer *outputZeroer; unsigned long initialFramesInTempInputBuffer; unsigned long initialFramesInTempOutputBuffer; void *tempInputBuffer; /**< used for slips, block adaption, and conversion. */ void **tempInputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */ unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */ void *tempOutputBuffer; /**< used for slips, block adaption, and conversion. */ void **tempOutputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */ unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */ PaStreamCallbackTimeInfo *timeInfo; PaStreamCallbackFlags callbackStatusFlags; unsigned long hostInputFrameCount[2]; PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors. pointers are NULL for half-duplex output processing. hostInputChannels[i].data is NULL when the caller calls PaUtil_SetNoInput() */ unsigned long hostOutputFrameCount[2]; PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors. pointers are NULL for half-duplex input processing. hostOutputChannels[i].data is NULL when the caller calls PaUtil_SetNoOutput() */ PaUtilTriangularDitherGenerator ditherGenerator; double samplePeriod; PaStreamCallback *streamCallback; void *userData; } PaUtilBufferProcessor; /** @name Initialization, termination, resetting and info */ /*@{*/ /** Initialize a buffer processor's representation stored in a PaUtilBufferProcessor structure. Be sure to call PaUtil_TerminateBufferProcessor after finishing with a buffer processor. @param bufferProcessor The buffer processor structure to initialize. @param inputChannelCount The number of input channels as passed to Pa_OpenStream or 0 for an output-only stream. @param userInputSampleFormat Format of user input samples, as passed to Pa_OpenStream. This parameter is ignored for ouput-only streams. @param hostInputSampleFormat Format of host input samples. This parameter is ignored for output-only streams. See note about host buffer interleave below. @param outputChannelCount The number of output channels as passed to Pa_OpenStream or 0 for an input-only stream. @param userOutputSampleFormat Format of user output samples, as passed to Pa_OpenStream. This parameter is ignored for input-only streams. @param hostOutputSampleFormat Format of host output samples. This parameter is ignored for input-only streams. See note about host buffer interleave below. @param sampleRate Sample rate of the stream. The more accurate this is the better - it is used for updating time stamps when adapting buffers. @param streamFlags Stream flags as passed to Pa_OpenStream, this parameter is used for selecting special sample conversion options such as clipping and dithering. @param framesPerUserBuffer Number of frames per user buffer, as requested by the framesPerBuffer parameter to Pa_OpenStream. This parameter may be zero to indicate that the user will accept any (and varying) buffer sizes. @param framesPerHostBuffer Specifies the number of frames per host buffer for the fixed buffer size mode, and the maximum number of frames per host buffer for the bounded host buffer size mode. It is ignored for the other modes. @param hostBufferSizeMode A mode flag indicating the size variability of host buffers that will be passed to the buffer processor. See PaUtilHostBufferSizeMode for further details. @param streamCallback The user stream callback passed to Pa_OpenStream. @param userData The user data field passed to Pa_OpenStream. @note The interleave flag is ignored for host buffer formats. Host interleave is determined by the use of different SetInput and SetOutput functions. @return An error code indicating whether the initialization was successful. If the error code is not PaNoError, the buffer processor was not initialized and should not be used. @see Pa_OpenStream, PaUtilHostBufferSizeMode, PaUtil_TerminateBufferProcessor */ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor, int inputChannelCount, PaSampleFormat userInputSampleFormat, PaSampleFormat hostInputSampleFormat, int outputChannelCount, PaSampleFormat userOutputSampleFormat, PaSampleFormat hostOutputSampleFormat, double sampleRate, PaStreamFlags streamFlags, unsigned long framesPerUserBuffer, /* 0 indicates don't care */ unsigned long framesPerHostBuffer, PaUtilHostBufferSizeMode hostBufferSizeMode, PaStreamCallback *streamCallback, void *userData ); /** Terminate a buffer processor's representation. Deallocates any temporary buffers allocated by PaUtil_InitializeBufferProcessor. @param bufferProcessor The buffer processor structure to terminate. @see PaUtil_InitializeBufferProcessor. */ void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor ); /** Clear any internally buffered data. If you call PaUtil_InitializeBufferProcessor in your OpenStream routine, make sure you call PaUtil_ResetBufferProcessor in your StartStream call. @param bufferProcessor The buffer processor to reset. */ void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bufferProcessor ); /** Retrieve the input latency of a buffer processor. @param bufferProcessor The buffer processor examine. @return The input latency introduced by the buffer processor, in frames. @see PaUtil_GetBufferProcessorOutputLatency */ unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bufferProcessor ); /** Retrieve the output latency of a buffer processor. @param bufferProcessor The buffer processor examine. @return The output latency introduced by the buffer processor, in frames. @see PaUtil_GetBufferProcessorInputLatency */ unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bufferProcessor ); /*@}*/ /** @name Host buffer pointer configuration Functions to set host input and output buffers, used by both callback streams and blocking read/write streams. */ /*@{*/ /** Set the number of frames in the input host buffer(s) specified by the PaUtil_Set*InputChannel functions. @param bufferProcessor The buffer processor. @param frameCount The number of host input frames. A 0 frameCount indicates to use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor. @see PaUtil_SetNoInput, PaUtil_SetInputChannel, PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel */ void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor, unsigned long frameCount ); /** Indicate that no input is avalable. This function should be used when priming the output of a full-duplex stream opened with the paPrimeOutputBuffersUsingStreamCallback flag. Note that it is not necessary to call this or any othe PaUtil_Set*Input* functions for ouput-only streams. @param bufferProcessor The buffer processor. */ void PaUtil_SetNoInput( PaUtilBufferProcessor* bufferProcessor ); /** Provide the buffer processor with a pointer to a host input channel. @param bufferProcessor The buffer processor. @param channel The channel number. @param data The buffer. @param stride The stride from one sample to the next, in samples. For interleaved host buffers, the stride will usually be the same as the number of channels in the buffer. */ void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data, unsigned int stride ); /** Provide the buffer processor with a pointer to an number of interleaved host input channels. @param bufferProcessor The buffer processor. @param firstChannel The first channel number. @param data The buffer. @param channelCount The number of interleaved channels in the buffer. If channelCount is zero, the number of channels specified to PaUtil_InitializeBufferProcessor will be used. */ void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor, unsigned int firstChannel, void *data, unsigned int channelCount ); /** Provide the buffer processor with a pointer to one non-interleaved host output channel. @param bufferProcessor The buffer processor. @param channel The channel number. @param data The buffer. */ void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data ); /** Use for the second buffer half when the input buffer is split in two halves. @see PaUtil_SetInputFrameCount */ void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor, unsigned long frameCount ); /** Use for the second buffer half when the input buffer is split in two halves. @see PaUtil_SetInputChannel */ void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data, unsigned int stride ); /** Use for the second buffer half when the input buffer is split in two halves. @see PaUtil_SetInterleavedInputChannels */ void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor, unsigned int firstChannel, void *data, unsigned int channelCount ); /** Use for the second buffer half when the input buffer is split in two halves. @see PaUtil_SetNonInterleavedInputChannel */ void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data ); /** Set the number of frames in the output host buffer(s) specified by the PaUtil_Set*OutputChannel functions. @param bufferProcessor The buffer processor. @param frameCount The number of host output frames. A 0 frameCount indicates to use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor. @see PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel */ void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor, unsigned long frameCount ); /** Indicate that the output will be discarded. This function should be used when implementing the paNeverDropInput mode for full duplex streams. @param bufferProcessor The buffer processor. */ void PaUtil_SetNoOutput( PaUtilBufferProcessor* bufferProcessor ); /** Provide the buffer processor with a pointer to a host output channel. @param bufferProcessor The buffer processor. @param channel The channel number. @param data The buffer. @param stride The stride from one sample to the next, in samples. For interleaved host buffers, the stride will usually be the same as the number of channels in the buffer. */ void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data, unsigned int stride ); /** Provide the buffer processor with a pointer to a number of interleaved host output channels. @param bufferProcessor The buffer processor. @param firstChannel The first channel number. @param data The buffer. @param channelCount The number of interleaved channels in the buffer. If channelCount is zero, the number of channels specified to PaUtil_InitializeBufferProcessor will be used. */ void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor, unsigned int firstChannel, void *data, unsigned int channelCount ); /** Provide the buffer processor with a pointer to one non-interleaved host output channel. @param bufferProcessor The buffer processor. @param channel The channel number. @param data The buffer. */ void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data ); /** Use for the second buffer half when the output buffer is split in two halves. @see PaUtil_SetOutputFrameCount */ void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor, unsigned long frameCount ); /** Use for the second buffer half when the output buffer is split in two halves. @see PaUtil_SetOutputChannel */ void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data, unsigned int stride ); /** Use for the second buffer half when the output buffer is split in two halves. @see PaUtil_SetInterleavedOutputChannels */ void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor, unsigned int firstChannel, void *data, unsigned int channelCount ); /** Use for the second buffer half when the output buffer is split in two halves. @see PaUtil_SetNonInterleavedOutputChannel */ void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor, unsigned int channel, void *data ); /*@}*/ /** @name Buffer processing functions for callback streams */ /*@{*/ /** Commence processing a host buffer (or a pair of host buffers in the full-duplex case) for a callback stream. @param bufferProcessor The buffer processor. @param timeInfo Timing information for the first sample of the host buffer(s). This information may be adjusted when buffer adaption is being performed. @param callbackStatusFlags Flags indicating whether underruns and overruns have occurred since the last time the buffer processor was called. */ void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor, PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags ); /** Finish processing a host buffer (or a pair of host buffers in the full-duplex case) for a callback stream. @param bufferProcessor The buffer processor. @param callbackResult On input, indicates a previous callback result, and on exit, the result of the user stream callback, if it is called. On entry callbackResult should contain one of { paContinue, paComplete, or paAbort}. If paComplete is passed, the stream callback will not be called but any audio that was generated by previous stream callbacks will be copied to the output buffer(s). You can check whether the buffer processor's internal buffer is empty by calling PaUtil_IsBufferProcessorOutputEmpty. If the stream callback is called its result is stored in *callbackResult. If the stream callback returns paComplete or paAbort, all output buffers will be full of valid data - some of which may be zeros to acount for data that wasn't generated by the terminating callback. @return The number of frames processed. This usually corresponds to the number of frames specified by the PaUtil_Set*FrameCount functions, exept in the paUtilVariableHostBufferSizePartialUsageAllowed buffer size mode when a smaller value may be returned. */ unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor, int *callbackResult ); /** Determine whether any callback generated output remains in the bufffer processor's internal buffers. This method may be used to determine when to continue calling PaUtil_EndBufferProcessing() after the callback has returned a callbackResult of paComplete. @param bufferProcessor The buffer processor. @return Returns non-zero when callback generated output remains in the internal buffer and zero (0) when there internal buffer contains no callback generated data. */ int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bufferProcessor ); /*@}*/ /** @name Buffer processing functions for blocking read/write streams */ /*@{*/ /** Copy samples from host input channels set up by the PaUtil_Set*InputChannels functions to a user supplied buffer. This function is intended for use with blocking read/write streams. Copies the minimum of the number of user frames (specified by the frameCount parameter) and the number of available host frames (specified in a previous call to SetInputFrameCount()). @param bufferProcessor The buffer processor. @param buffer A pointer to the user buffer pointer, or a pointer to a pointer to an array of user buffer pointers for a non-interleaved stream. It is important that this parameter points to a copy of the user buffer pointers, not to the actual user buffer pointers, because this function updates the pointers before returning. @param frameCount The number of frames of data in the buffer(s) pointed to by the buffer parameter. @return The number of frames copied. The buffer pointer(s) pointed to by the buffer parameter are advanced to point to the frame(s) following the last one filled. */ unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bufferProcessor, void **buffer, unsigned long frameCount ); /* Copy samples from a user supplied buffer to host output channels set up by the PaUtil_Set*OutputChannels functions. This function is intended for use with blocking read/write streams. Copies the minimum of the number of user frames (specified by the frameCount parameter) and the number of host frames (specified in a previous call to SetOutputFrameCount()). @param bufferProcessor The buffer processor. @param buffer A pointer to the user buffer pointer, or a pointer to a pointer to an array of user buffer pointers for a non-interleaved stream. It is important that this parameter points to a copy of the user buffer pointers, not to the actual user buffer pointers, because this function updates the pointers before returning. @param frameCount The number of frames of data in the buffer(s) pointed to by the buffer parameter. @return The number of frames copied. The buffer pointer(s) pointed to by the buffer parameter are advanced to point to the frame(s) following the last one copied. */ unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bufferProcessor, const void ** buffer, unsigned long frameCount ); /* Zero samples in host output channels set up by the PaUtil_Set*OutputChannels functions. This function is useful for flushing streams. Zeros the minimum of frameCount and the number of host frames specified in a previous call to SetOutputFrameCount(). @param bufferProcessor The buffer processor. @param frameCount The maximum number of frames to zero. @return The number of frames zeroed. */ unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bufferProcessor, unsigned long frameCount ); /*@}*/ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_PROCESS_H */ nyquist-3.05/portaudio/src/common/pa_ringbuffer.c0000644000175000000620000002575111466723256021253 0ustar stevestaff/* * $Id: pa_ringbuffer.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library * Ring Buffer utility. * * Author: Phil Burk, http://www.softsynth.com * modified for SMP safety on Mac OS X by Bjorn Roche * modified for SMP safety on Linux by Leland Lucius * also, allowed for const where possible * Note that this is safe only for a single-thread reader and a * single-thread writer. * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src */ #include #include #include #include "pa_ringbuffer.h" #include /**************** * First, we'll define some memory barrier primitives based on the system. * right now only OS X, FreeBSD, and Linux are supported. In addition to providing * memory barriers, these functions should ensure that data cached in registers * is written out to cache where it can be snooped by other CPUs. (ie, the volatile * keyword should not be required) * * the primitives that must be defined are: * * PaUtil_FullMemoryBarrier() * PaUtil_ReadMemoryBarrier() * PaUtil_WriteMemoryBarrier() * ****************/ #if defined(__APPLE__) # include /* Here are the memory barrier functions. Mac OS X only provides full memory barriers, so the three types of barriers are the same, however, these barriers are superior to compiler-based ones. */ # define PaUtil_FullMemoryBarrier() OSMemoryBarrier() # define PaUtil_ReadMemoryBarrier() OSMemoryBarrier() # define PaUtil_WriteMemoryBarrier() OSMemoryBarrier() #elif defined(__GNUC__) /* GCC >= 4.1 has built-in intrinsics. We'll use those */ # if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) # define PaUtil_FullMemoryBarrier() __sync_synchronize() # define PaUtil_ReadMemoryBarrier() __sync_synchronize() # define PaUtil_WriteMemoryBarrier() __sync_synchronize() /* as a fallback, GCC understands volatile asm and "memory" to mean it * should not reorder memory read/writes */ # elif defined( __PPC__ ) # define PaUtil_FullMemoryBarrier() asm volatile("sync":::"memory") # define PaUtil_ReadMemoryBarrier() asm volatile("sync":::"memory") # define PaUtil_WriteMemoryBarrier() asm volatile("sync":::"memory") # elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || defined( __i686__ ) || defined( __x86_64__ ) # define PaUtil_FullMemoryBarrier() asm volatile("mfence":::"memory") # define PaUtil_ReadMemoryBarrier() asm volatile("lfence":::"memory") # define PaUtil_WriteMemoryBarrier() asm volatile("sfence":::"memory") # else # ifdef ALLOW_SMP_DANGERS # warning Memory barriers not defined on this system or system unknown # warning For SMP safety, you should fix this. # define PaUtil_FullMemoryBarrier() # define PaUtil_ReadMemoryBarrier() # define PaUtil_WriteMemoryBarrier() # else # error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed. # endif # endif #else # ifdef ALLOW_SMP_DANGERS # warning Memory barriers not defined on this system or system unknown # warning For SMP safety, you should fix this. # define PaUtil_FullMemoryBarrier() # define PaUtil_ReadMemoryBarrier() # define PaUtil_WriteMemoryBarrier() # else # error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed. # endif #endif /*************************************************************************** * Initialize FIFO. * numBytes must be power of 2, returns -1 if not. */ long PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, long numBytes, void *dataPtr ) { if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */ rbuf->bufferSize = numBytes; rbuf->buffer = (char *)dataPtr; PaUtil_FlushRingBuffer( rbuf ); rbuf->bigMask = (numBytes*2)-1; rbuf->smallMask = (numBytes)-1; return 0; } /*************************************************************************** ** Return number of bytes available for reading. */ long PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf ) { PaUtil_ReadMemoryBarrier(); return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); } /*************************************************************************** ** Return number of bytes available for writing. */ long PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf ) { /* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */ return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf)); } /*************************************************************************** ** Clear buffer. Should only be called when buffer is NOT being read. */ void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ) { rbuf->writeIndex = rbuf->readIndex = 0; } /*************************************************************************** ** Get address of region(s) to which we can write data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ) { long index; long available = PaUtil_GetRingBufferWriteAvailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if write is not contiguous. */ index = rbuf->writeIndex & rbuf->smallMask; if( (index + numBytes) > rbuf->bufferSize ) { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = firstHalf; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; } return numBytes; } /*************************************************************************** */ long PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, long numBytes ) { /* we need to ensure that previous writes are seen before we update the write index */ PaUtil_WriteMemoryBarrier(); return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; } /*************************************************************************** ** Get address of region(s) from which we can read data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ) { long index; long available = PaUtil_GetRingBufferReadAvailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if read is not contiguous. */ index = rbuf->readIndex & rbuf->smallMask; if( (index + numBytes) > rbuf->bufferSize ) { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = firstHalf; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; } return numBytes; } /*************************************************************************** */ long PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, long numBytes ) { /* we need to ensure that previous writes are always seen before updating the index. */ PaUtil_WriteMemoryBarrier(); return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; } /*************************************************************************** ** Return bytes written. */ long PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, long numBytes ) { long size1, size2, numWritten; void *data1, *data2; numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); if( size2 > 0 ) { memcpy( data1, data, size1 ); data = ((char *)data) + size1; memcpy( data2, data, size2 ); } else { memcpy( data1, data, size1 ); } PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten ); return numWritten; } /*************************************************************************** ** Return bytes read. */ long PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, long numBytes ) { long size1, size2, numRead; void *data1, *data2; numRead = PaUtil_GetRingBufferReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); if( size2 > 0 ) { memcpy( data, data1, size1 ); data = ((char *)data) + size1; memcpy( data, data2, size2 ); } else { memcpy( data, data1, size1 ); } PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead ); return numRead; } nyquist-3.05/portaudio/src/common/pa_types.h0000644000175000000620000000733011466723256020264 0ustar stevestaff#ifndef PA_TYPES_H #define PA_TYPES_H /* * Portable Audio I/O Library * integer type definitions * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2006 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Definition of 16 and 32 bit integer types (PaInt16, PaInt32 etc) SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script when it is used. Otherwise we default to the common 32 bit values, if your platform doesn't use configure, and doesn't use the default values below you will need to explicitly define these symbols in your make file. A PA_VALIDATE_SIZES macro is provided to assert that the values set in this file are correct. */ #ifndef SIZEOF_SHORT #define SIZEOF_SHORT 2 #endif #ifndef SIZEOF_INT #define SIZEOF_INT 4 #endif #ifndef SIZEOF_LONG #define SIZEOF_LONG 4 #endif #if SIZEOF_SHORT == 2 typedef signed short PaInt16; typedef unsigned short PaUint16; #elif SIZEOF_INT == 2 typedef signed int PaInt16; typedef unsigned int PaUint16; #else #error pa_types.h was unable to determine which type to use for 16bit integers on the target platform #endif #if SIZEOF_SHORT == 4 typedef signed short PaInt32; typedef unsigned short PaUint32; #elif SIZEOF_INT == 4 typedef signed int PaInt32; typedef unsigned int PaUint32; #elif SIZEOF_LONG == 4 typedef signed long PaInt32; typedef unsigned long PaUint32; #else #error pa_types.h was unable to determine which type to use for 32bit integers on the target platform #endif /* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to ensure that PortAudio was configured correctly, and raises an assertion if they don't match the expected values. must be included in the context in which this macro is used. */ #define PA_VALIDATE_TYPE_SIZES \ { \ assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \ assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \ assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \ assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \ } #endif /* PA_TYPES_H */ nyquist-3.05/portaudio/src/common/pa_hostapi.h0000644000175000000620000002344311466723256020572 0ustar stevestaff#ifndef PA_HOSTAPI_H #define PA_HOSTAPI_H /* * $Id: pa_hostapi.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library * host api representation * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Interface used by pa_front to virtualize functions which operate on host APIs. */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** **FOR THE USE OF pa_front.c ONLY** Do NOT use fields in this structure, they my change at any time. Use functions defined in pa_util.h if you think you need functionality which can be derived from here. */ typedef struct PaUtilPrivatePaFrontHostApiInfo { unsigned long baseDeviceIndex; }PaUtilPrivatePaFrontHostApiInfo; /** The common header for all data structures whose pointers are passed through the hostApiSpecificStreamInfo field of the PaStreamParameters structure. Note that in order to keep the public PortAudio interface clean, this structure is not used explicitly when declaring hostApiSpecificStreamInfo data structures. However, some code in pa_front depends on the first 3 members being equivalent with this structure. @see PaStreamParameters */ typedef struct PaUtilHostApiSpecificStreamInfoHeader { unsigned long size; /**< size of whole structure including this header */ PaHostApiTypeId hostApiType; /**< host API for which this data is intended */ unsigned long version; /**< structure version */ } PaUtilHostApiSpecificStreamInfoHeader; /** A structure representing the interface to a host API. Contains both concrete data and pointers to functions which implement the interface. */ typedef struct PaUtilHostApiRepresentation { PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo; /** The host api implementation should populate the info field. In the case of info.defaultInputDevice and info.defaultOutputDevice the values stored should be 0 based indices within the host api's own device index range (0 to deviceCount). These values will be converted to global device indices by pa_front after PaUtilHostApiInitializer() returns. */ PaHostApiInfo info; PaDeviceInfo** deviceInfos; /** (*Terminate)() is guaranteed to be called with a valid parameter, which was previously returned from the same implementation's initializer. */ void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi ); /** The inputParameters and outputParameters pointers should not be saved as they will not remain valid after OpenStream is called. The following guarantees are made about parameters to (*OpenStream)(): [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be kept in sync with the one for ValidateOpenStreamParameters and Pa_OpenStream in pa_front.c] PaHostApiRepresentation *hostApi - is valid for this implementation PaStream** stream - is non-null - at least one of inputParameters & outputParmeters is valid (not NULL) - if inputParameters & outputParmeters are both valid, that inputParameters->device & outputParmeters->device both use the same host api PaDeviceIndex inputParameters->device - is within range (0 to Pa_CountDevices-1) Or: - is paUseHostApiSpecificDeviceSpecification and inputParameters->hostApiSpecificStreamInfo is non-NULL and refers to a valid host api int inputParameters->numChannels - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0 - upper bound is NOT validated against device capabilities PaSampleFormat inputParameters->sampleFormat - is one of the sample formats defined in portaudio.h void *inputParameters->hostApiSpecificStreamInfo - if supplied its hostApi field matches the input device's host Api PaDeviceIndex outputParmeters->device - is within range (0 to Pa_CountDevices-1) int outputParmeters->numChannels - if inputDevice is valid, numInputChannels is > 0 - upper bound is NOT validated against device capabilities PaSampleFormat outputParmeters->sampleFormat - is one of the sample formats defined in portaudio.h void *outputParmeters->hostApiSpecificStreamInfo - if supplied its hostApi field matches the output device's host Api double sampleRate - is not an 'absurd' rate (less than 1000. or greater than 200000.) - sampleRate is NOT validated against device capabilities PaStreamFlags streamFlags - unused platform neutral flags are zero - paNeverDropInput is only used for full-duplex callback streams with variable buffer size (paFramesPerBufferUnspecified) [*END PA FRONT VALIDATIONS*] The following validations MUST be performed by (*OpenStream)(): - check that input device can support numInputChannels - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if inputStreamInfo is supplied, validate its contents, or return an error if no inputStreamInfo is expected - check that output device can support numOutputChannels - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if outputStreamInfo is supplied, validate its contents, or return an error if no outputStreamInfo is expected - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate - alter sampleRate to a close allowable rate if necessary - validate inputLatency and outputLatency - validate any platform specific flags, if flags are supplied they must be valid. */ PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi, PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerCallback, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); } PaUtilHostApiRepresentation; /** Prototype for the initialization function which must be implemented by every host API. @see paHostApiInitializers */ typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex ); /** paHostApiInitializers is a NULL-terminated array of host API initialization functions. These functions are called by pa_front to initialize the host APIs when the client calls Pa_Initialize(). There is a platform specific file which defines paHostApiInitializers for that platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example. */ extern PaUtilHostApiInitializer *paHostApiInitializers[]; /** The index of the default host API in the paHostApiInitializers array. There is a platform specific file which defines paDefaultHostApiIndex for that platform, see pa_win/pa_win_hostapis.c for example. */ extern int paDefaultHostApiIndex; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_HOSTAPI_H */ nyquist-3.05/portaudio/src/common/pa_skeleton.c0000644000175000000620000006671211466723256020750 0ustar stevestaff/* * $Id: pa_skeleton.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library skeleton implementation * demonstrates how to use the common functions to implement support * for a host API * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Skeleton implementation of support for a host API. @note This file is provided as a starting point for implementing support for a new host API. IMPLEMENT ME comments are used to indicate functionality which much be customised for each implementation. */ #include /* strlen() */ #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" /* prototypes for functions declared in this file */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* IMPLEMENT ME: a macro like the following one should be used for reporting host errors */ #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) /* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ } PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; int i, deviceCount; PaSkeletonHostApiRepresentation *skeletonHostApi; PaDeviceInfo *deviceInfoArray; skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) ); if( !skeletonHostApi ) { result = paInsufficientMemory; goto error; } skeletonHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !skeletonHostApi->allocations ) { result = paInsufficientMemory; goto error; } *hostApi = &skeletonHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */ (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */ (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ (*hostApi)->info.deviceCount = 0; deviceCount = 0; /* IMPLEMENT ME */ if( deviceCount > 0 ) { (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); if( !(*hostApi)->deviceInfos ) { result = paInsufficientMemory; goto error; } /* allocate all device info structs in a contiguous block */ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount ); if( !deviceInfoArray ) { result = paInsufficientMemory; goto error; } for( i=0; i < deviceCount; ++i ) { PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg: deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, srcName ); deviceInfo->name = deviceName; */ deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */ deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */ deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */ deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */ deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */ deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */ deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */ (*hostApi)->deviceInfos[i] = deviceInfo; ++(*hostApi)->info.deviceCount; } } (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if( skeletonHostApi ) { if( skeletonHostApi->allocations ) { PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); } PaUtil_FreeMemory( skeletonHostApi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; /* IMPLEMENT ME: - clean up any resources not handled by the allocation group */ if( skeletonHostApi->allocations ) { PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); } PaUtil_FreeMemory( skeletonHostApi ); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support outputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } /* IMPLEMENT ME: - if a full duplex stream is requested, check that the combination of input and output parameters is supported if necessary - check that the device supports sampleRate Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - check that input device can support inputSampleFormat, or that we have the capability to convert from inputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format */ /* suppress unused variable warnings */ (void) sampleRate; return paFormatIsSupported; } /* PaSkeletonStream - a stream data structure specifically for this implementation */ typedef struct PaSkeletonStream { /* IMPLEMENT ME: rename this */ PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; /* IMPLEMENT ME: - implementation specific data goes here */ unsigned long framesPerHostCallback; /* just an example */ } PaSkeletonStream; /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; PaSkeletonStream *stream = 0; unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */ int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ /* IMPLEMENT ME - establish which host formats are available */ hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); } else { inputChannelCount = 0; inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ /* IMPLEMENT ME - establish which host formats are available */ hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); } else { outputChannelCount = 0; outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ } /* IMPLEMENT ME: ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate - alter sampleRate to a close allowable rate if possible / necessary - validate suggestedInputLatency and suggestedOutputLatency parameters, use default values where necessary */ /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) ); if( !stream ) { result = paInsufficientMemory; goto error; } if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &skeletonHostApi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &skeletonHostApi->blockingStreamInterface, streamCallback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); /* we assume a fixed host buffer size in this example, but the buffer processor can also support bounded and unknown host buffer sizes by passing paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of paUtilFixedHostBufferSize below. */ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, streamCallback, userData ); if( result != paNoError ) goto error; /* IMPLEMENT ME: initialise the following fields with estimated or actual values. */ stream->streamRepresentation.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor); stream->streamRepresentation.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor); stream->streamRepresentation.streamInfo.sampleRate = sampleRate; /* IMPLEMENT ME: - additional stream setup + opening */ stream->framesPerHostCallback = framesPerHostBuffer; *s = (PaStream*)stream; return result; error: if( stream ) PaUtil_FreeMemory( stream ); return result; } /* ExampleHostProcessingLoop() illustrates the kind of processing which may occur in a host implementation. */ static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData ) { PaSkeletonStream *stream = (PaSkeletonStream*)userData; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ int callbackResult; unsigned long framesProcessed; PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* IMPLEMENT ME: - generate timing information - handle buffer slips */ /* If you need to byte swap or shift inputBuffer to convert it into a portaudio format, do it here. */ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ ); /* depending on whether the host buffers are interleaved, non-interleaved or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. */ PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, /* first channel of inputBuffer is channel 0 */ inputBuffer, 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, /* first channel of outputBuffer is channel 0 */ outputBuffer, 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() in general you would pass paContinue for normal operation, and paComplete to drain the buffer processor's internal output buffer. You can check whether the buffer processor's output buffer is empty using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) */ callbackResult = paContinue; framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); /* If you need to byte swap or shift outputBuffer to convert it to host format, do it here. */ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); if( callbackResult == paContinue ) { /* nothing special to do */ } else if( callbackResult == paAbort ) { /* IMPLEMENT ME - finish playback immediately */ /* once finished, call the finished callback */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } else { /* User callback has asked us to stop with paComplete or other non-zero value */ /* IMPLEMENT ME - finish playback once currently queued audio has completed */ /* once finished, call the finished callback */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaSkeletonStream *stream = (PaSkeletonStream*)s; /* IMPLEMENT ME: - additional stream closing + cleanup */ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); return result; } static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaSkeletonStream *stream = (PaSkeletonStream*)s; PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); /* IMPLEMENT ME, see portaudio.h for required behavior */ /* suppress unused function warning. the code in ExampleHostProcessingLoop or something similar should be implemented to feed samples to and from the host after StartStream() is called. */ (void) ExampleHostProcessingLoop; return result; } static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior */ return result; } static PaError AbortStream( PaStream *s ) { PaError result = paNoError; PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior */ return result; } static PaError IsStreamStopped( PaStream *s ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior */ return 0; } static PaError IsStreamActive( PaStream *s ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior */ return 0; } static PaTime GetStreamTime( PaStream *s ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } static double GetStreamCpuLoad( PaStream* s ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError; } static signed long GetStreamReadAvailable( PaStream* s ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } static signed long GetStreamWriteAvailable( PaStream* s ) { PaSkeletonStream *stream = (PaSkeletonStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } nyquist-3.05/portaudio/src/common/pa_cpuload.c0000644000175000000620000000730211466723256020541 0ustar stevestaff/* * $Id: pa_cpuload.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library CPU Load measurement functions * Portable CPU load measurement facility. * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 2002 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Functions to assist in measuring the CPU utilization of a callback stream. Used to implement the Pa_GetStreamCpuLoad() function. @todo Dynamically calculate the coefficients used to smooth the CPU Load Measurements over time to provide a uniform characterisation of CPU Load independent of rate at which PaUtil_BeginCpuLoadMeasurement / PaUtil_EndCpuLoadMeasurement are called. */ #include "pa_cpuload.h" #include #include "pa_util.h" /* for PaUtil_GetTime() */ void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ) { assert( sampleRate > 0 ); measurer->samplingPeriod = 1. / sampleRate; measurer->averageLoad = 0.; } void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer ) { measurer->averageLoad = 0.; } void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ) { measurer->measurementStartTime = PaUtil_GetTime(); } void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ) { double measurementEndTime, secondsFor100Percent, measuredLoad; if( framesProcessed > 0 ){ measurementEndTime = PaUtil_GetTime(); assert( framesProcessed > 0 ); secondsFor100Percent = framesProcessed * measurer->samplingPeriod; measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent; /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */ /** FIXME @todo these coefficients shouldn't be hardwired */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) + (LOWPASS_COEFFICIENT_1 * measuredLoad); } } double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ) { return measurer->averageLoad; } nyquist-3.05/portaudio/src/common/pa_debugprint.h0000644000175000000620000001166111466723256021265 0ustar stevestaff#ifndef PA_LOG_H #define PA_LOG_H /* * Log file redirector function * Copyright (c) 1999-2006 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ void PaUtil_DebugPrint( const char *format, ... ); /* The basic format for log messages is described below. If you need to add any log messages, please follow this format. Function entry (void function): "FunctionName called.\n" Function entry (non void function): "FunctionName called:\n" "\tParam1Type param1: param1Value\n" "\tParam2Type param2: param2Value\n" (etc...) Function exit (no return value): "FunctionName returned.\n" Function exit (simple return value): "FunctionName returned:\n" "\tReturnType: returnValue\n" If the return type is an error code, the error text is displayed in () If the return type is not an error code, but has taken a special value because an error occurred, then the reason for the error is shown in [] If the return type is a struct ptr, the struct is dumped. See the code below for examples */ /** PA_DEBUG() provides a simple debug message printing facility. The macro passes it's argument to a printf-like function called PaUtil_DebugPrint() which prints to stderr and always flushes the stream after printing. Because preprocessor macros cannot directly accept variable length argument lists, calls to the macro must include an additional set of parenthesis, eg: PA_DEBUG(("errorno: %d", 1001 )); */ #ifdef PA_ENABLE_DEBUG_OUTPUT #define PA_DEBUG(x) PaUtil_DebugPrint x ; #else #define PA_DEBUG(x) #endif #ifdef PA_LOG_API_CALLS #define PA_LOGAPI(x) PaUtil_DebugPrint x #define PA_LOGAPI_ENTER(functionName) PaUtil_DebugPrint( functionName " called.\n" ) #define PA_LOGAPI_ENTER_PARAMS(functionName) PaUtil_DebugPrint( functionName " called:\n" ) #define PA_LOGAPI_EXIT(functionName) PaUtil_DebugPrint( functionName " returned.\n" ) #define PA_LOGAPI_EXIT_PAERROR( functionName, result ) \ PaUtil_DebugPrint( functionName " returned:\n" ); \ PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ) #define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) \ PaUtil_DebugPrint( functionName " returned:\n" ); \ PaUtil_DebugPrint("\t" resultFormatString "\n", result ) #define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) \ PaUtil_DebugPrint( functionName " returned:\n" ); \ if( result > 0 ) \ PaUtil_DebugPrint("\t" positiveResultFormatString "\n", result ); \ else \ PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ) #else #define PA_LOGAPI(x) #define PA_LOGAPI_ENTER(functionName) #define PA_LOGAPI_ENTER_PARAMS(functionName) #define PA_LOGAPI_EXIT(functionName) #define PA_LOGAPI_EXIT_PAERROR( functionName, result ) #define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) #define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) #endif typedef void (*PaUtilLogCallback ) (const char *log); /** Install user provided log function */ void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_LOG_H */ nyquist-3.05/portaudio/src/common/pa_stream.c0000644000175000000620000001225611466723256020411 0ustar stevestaff/* * $Id: pa_stream.c,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 2002 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Interface used by pa_front to virtualize functions which operate on streams. */ #include "pa_stream.h" void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, PaError (*Close)( PaStream* ), PaError (*Start)( PaStream* ), PaError (*Stop)( PaStream* ), PaError (*Abort)( PaStream* ), PaError (*IsStopped)( PaStream* ), PaError (*IsActive)( PaStream* ), PaTime (*GetTime)( PaStream* ), double (*GetCpuLoad)( PaStream* ), PaError (*Read)( PaStream*, void *, unsigned long ), PaError (*Write)( PaStream*, const void *, unsigned long ), signed long (*GetReadAvailable)( PaStream* ), signed long (*GetWriteAvailable)( PaStream* ) ) { streamInterface->Close = Close; streamInterface->Start = Start; streamInterface->Stop = Stop; streamInterface->Abort = Abort; streamInterface->IsStopped = IsStopped; streamInterface->IsActive = IsActive; streamInterface->GetTime = GetTime; streamInterface->GetCpuLoad = GetCpuLoad; streamInterface->Read = Read; streamInterface->Write = Write; streamInterface->GetReadAvailable = GetReadAvailable; streamInterface->GetWriteAvailable = GetWriteAvailable; } void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation, PaUtilStreamInterface *streamInterface, PaStreamCallback *streamCallback, void *userData ) { streamRepresentation->magic = PA_STREAM_MAGIC; streamRepresentation->nextOpenStream = 0; streamRepresentation->streamInterface = streamInterface; streamRepresentation->streamCallback = streamCallback; streamRepresentation->streamFinishedCallback = 0; streamRepresentation->userData = userData; streamRepresentation->streamInfo.inputLatency = 0.; streamRepresentation->streamInfo.outputLatency = 0.; streamRepresentation->streamInfo.sampleRate = 0.; } void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ) { streamRepresentation->magic = 0; } PaError PaUtil_DummyRead( PaStream* stream, void *buffer, unsigned long frames ) { (void)stream; /* unused parameter */ (void)buffer; /* unused parameter */ (void)frames; /* unused parameter */ return paCanNotReadFromACallbackStream; } PaError PaUtil_DummyWrite( PaStream* stream, const void *buffer, unsigned long frames ) { (void)stream; /* unused parameter */ (void)buffer; /* unused parameter */ (void)frames; /* unused parameter */ return paCanNotWriteToACallbackStream; } signed long PaUtil_DummyGetReadAvailable( PaStream* stream ) { (void)stream; /* unused parameter */ return paCanNotReadFromACallbackStream; } signed long PaUtil_DummyGetWriteAvailable( PaStream* stream ) { (void)stream; /* unused parameter */ return paCanNotWriteToACallbackStream; } double PaUtil_DummyGetCpuLoad( PaStream* stream ) { (void)stream; /* unused parameter */ return 0.0; } nyquist-3.05/portaudio/src/common/pa_stream.h0000644000175000000620000001611311466723256020412 0ustar stevestaff#ifndef PA_STREAM_H #define PA_STREAM_H /* * $Id: pa_stream.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library * stream interface * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Interface used by pa_front to virtualize functions which operate on streams. */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define PA_STREAM_MAGIC (0x18273645) /** A structure representing an (abstract) interface to a host API. Contains pointers to functions which implement the interface. All PaStreamInterface functions are guaranteed to be called with a non-null, valid stream parameter. */ typedef struct { PaError (*Close)( PaStream* stream ); PaError (*Start)( PaStream *stream ); PaError (*Stop)( PaStream *stream ); PaError (*Abort)( PaStream *stream ); PaError (*IsStopped)( PaStream *stream ); PaError (*IsActive)( PaStream *stream ); PaTime (*GetTime)( PaStream *stream ); double (*GetCpuLoad)( PaStream* stream ); PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ); PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ); signed long (*GetReadAvailable)( PaStream* stream ); signed long (*GetWriteAvailable)( PaStream* stream ); } PaUtilStreamInterface; /** Initialize the fields of a PaUtilStreamInterface structure. */ void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, PaError (*Close)( PaStream* ), PaError (*Start)( PaStream* ), PaError (*Stop)( PaStream* ), PaError (*Abort)( PaStream* ), PaError (*IsStopped)( PaStream* ), PaError (*IsActive)( PaStream* ), PaTime (*GetTime)( PaStream* ), double (*GetCpuLoad)( PaStream* ), PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ), PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ), signed long (*GetReadAvailable)( PaStream* stream ), signed long (*GetWriteAvailable)( PaStream* stream ) ); /** Dummy Read function for use in interfaces to a callback based streams. Pass to the Read parameter of PaUtil_InitializeStreamInterface. @return An error code indicating that the function has no effect because the stream is a callback stream. */ PaError PaUtil_DummyRead( PaStream* stream, void *buffer, unsigned long frames ); /** Dummy Write function for use in an interfaces to callback based streams. Pass to the Write parameter of PaUtil_InitializeStreamInterface. @return An error code indicating that the function has no effect because the stream is a callback stream. */ PaError PaUtil_DummyWrite( PaStream* stream, const void *buffer, unsigned long frames ); /** Dummy GetReadAvailable function for use in interfaces to callback based streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface. @return An error code indicating that the function has no effect because the stream is a callback stream. */ signed long PaUtil_DummyGetReadAvailable( PaStream* stream ); /** Dummy GetWriteAvailable function for use in interfaces to callback based streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface. @return An error code indicating that the function has no effect because the stream is a callback stream. */ signed long PaUtil_DummyGetWriteAvailable( PaStream* stream ); /** Dummy GetCpuLoad function for use in an interface to a read/write stream. Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface. @return Returns 0. */ double PaUtil_DummyGetCpuLoad( PaStream* stream ); /** Non host specific data for a stream. This data is used by pa_front to forward to the appropriate functions in the streamInterface structure. */ typedef struct PaUtilStreamRepresentation { unsigned long magic; /**< set to PA_STREAM_MAGIC */ struct PaUtilStreamRepresentation *nextOpenStream; /**< field used by multi-api code */ PaUtilStreamInterface *streamInterface; PaStreamCallback *streamCallback; PaStreamFinishedCallback *streamFinishedCallback; void *userData; PaStreamInfo streamInfo; } PaUtilStreamRepresentation; /** Initialize a PaUtilStreamRepresentation structure. @see PaUtil_InitializeStreamRepresentation */ void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation, PaUtilStreamInterface *streamInterface, PaStreamCallback *streamCallback, void *userData ); /** Clean up a PaUtilStreamRepresentation structure previously initialized by a call to PaUtil_InitializeStreamRepresentation. @see PaUtil_InitializeStreamRepresentation */ void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ); /** Check that the stream pointer is valid. @return Returns paNoError if the stream pointer appears to be OK, otherwise returns an error indicating the cause of failure. */ PaError PaUtil_ValidateStreamPointer( PaStream *stream ); /** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation. @see PaUtilStreamRepresentation */ #define PA_STREAM_REP( stream )\ ((PaUtilStreamRepresentation*) (stream) ) /** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface. @see PaUtilStreamRepresentation, PaUtilStreamInterface */ #define PA_STREAM_INTERFACE( stream )\ PA_STREAM_REP( (stream) )->streamInterface #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_STREAM_H */ nyquist-3.05/portaudio/src/common/pa_trace.h0000644000175000000620000000502211466723256020212 0ustar stevestaff#ifndef PA_TRACE_H #define PA_TRACE_H /* * $Id: pa_trace.h,v 1.1 2010/11/04 20:43:52 rbd Exp $ * Portable Audio I/O Library Trace Facility * Store trace information in real-time for later printing. * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src @brief Event trace mechanism for debugging. Allows data to be written to the buffer at interrupt time and dumped later. */ #define PA_TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */ #define PA_MAX_TRACE_RECORDS (2048) #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #if PA_TRACE_REALTIME_EVENTS void PaUtil_ResetTraceMessages(); void PaUtil_AddTraceMessage( const char *msg, int data ); void PaUtil_DumpTraceMessages(); #else #define PaUtil_ResetTraceMessages() /* noop */ #define PaUtil_AddTraceMessage(msg,data) /* noop */ #define PaUtil_DumpTraceMessages() /* noop */ #endif #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_TRACE_H */ nyquist-3.05/portaudio/src/SConscript0000644000175000000620000002133111466723256017006 0ustar stevestaffimport os.path, copy, sys def checkSymbol(conf, header, library=None, symbol=None, autoAdd=True, critical=False, pkgName=None): """ Check for symbol in library, optionally look only for header. @param conf: Configure instance. @param header: The header file where the symbol is declared. @param library: The library in which the symbol exists, if None it is taken to be the standard C library. @param symbol: The symbol to look for, if None only the header will be looked up. @param autoAdd: Automatically link with this library if check is positive. @param critical: Raise on error? @param pkgName: Optional name of pkg-config entry for library, to determine build parameters. @return: True/False """ origEnv = conf.env.Copy() # Copy unmodified environment so we can restore it upon error env = conf.env if library is None: library = "c" # Standard library autoAdd = False if pkgName is not None: origLibs = copy.copy(env.get("LIBS", None)) try: env.ParseConfig("pkg-config --silence-errors %s --cflags --libs" % pkgName) except: pass else: # I see no other way of checking that the parsing succeeded, if it did add no more linking parameters if env.get("LIBS", None) != origLibs: autoAdd = False try: if not conf.CheckCHeader(header, include_quotes="<>"): raise ConfigurationError("missing header %s" % header) if symbol is not None and not conf.CheckLib(library, symbol, language="C", autoadd=autoAdd): raise ConfigurationError("missing symbol %s in library %s" % (symbol, library)) except ConfigurationError: conf.env = origEnv if not critical: return False raise return True import SCons.Errors # Import common variables # Could use '#' to refer to top-level SConstruct directory, but looks like env.SConsignFile doesn't interpret this at least :( sconsDir = os.path.abspath(os.path.join("build", "scons")) try: Import("Platform", "Posix", "ConfigurationError", "ApiVer") except SCons.Errors.UserError: # The common objects must be exported first SConscript(os.path.join(sconsDir, "SConscript_common")) Import("Platform", "Posix", "ConfigurationError", "ApiVer") Import("env") # This will be manipulated env = env.Copy() # We operate with a set of needed libraries and optional libraries, the latter stemming from host API implementations. # For libraries of both types we record a set of values that is used to look for the library in question, during # configuration. If the corresponding library for a host API implementation isn't found, the implementation is left out. neededLibs = [] optionalImpls = {} if Platform in Posix: env.Append(CPPPATH=os.path.join("os", "unix")) neededLibs += [("pthread", "pthread.h", "pthread_create"), ("m", "math.h", "sin")] if env["useALSA"]: optionalImpls["ALSA"] = ("asound", "alsa/asoundlib.h", "snd_pcm_open") if env["useJACK"]: optionalImpls["JACK"] = ("jack", "jack/jack.h", "jack_client_new") if env["useOSS"]: # TODO: It looks like the prefix for soundcard.h depends on the platform optionalImpls["OSS"] = ("oss", "sys/soundcard.h", None) if env["useASIHPI"]: optionalImpls["ASIHPI"] = ("hpi", "asihpi/hpi.h", "HPI_SubSysCreate") else: raise ConfigurationError("unknown platform %s" % Platform) if Platform == "darwin": env.Append(LINKFLAGS=["-framework CoreAudio", "-framework AudioToolBox"]) env.Append(CPPDEFINES=["PA_USE_COREAUDIO"]) elif Platform == "cygwin": env.Append(LIBS=["winmm"]) elif Platform == "irix": neededLibs += [("audio", "dmedia/audio.h", "alOpenPort"), ("dmedia", "dmedia/dmedia.h", "dmGetUST")] env.Append(CPPDEFINES=["PA_USE_SGI"]) def CheckCTypeSize(context, tp): """ Check size of C type. @param context: A configuration context. @param tp: The type to check. @return: Size of type, in bytes. """ context.Message("Checking the size of C type %s..." % tp) ret = context.TryRun(""" #include int main() { printf("%%d", sizeof(%s)); return 0; } """ % tp, ".c") if not ret[0]: context.Result(" Couldn't obtain size of type %s!" % tp) return None assert ret[1] sz = int(ret[1]) context.Result("%d" % sz) return sz """ if sys.byteorder == "little": env.Append(CPPDEFINES=["PA_LITTLE_ENDIAN"]) elif sys.byteorder == "big": env.Append(CPPDEFINES=["PA_BIG_ENDIAN"]) else: raise ConfigurationError("unknown byte order: %s" % sys.byteorder) """ if env["enableDebugOutput"]: env.Append(CPPDEFINES=["PA_ENABLE_DEBUG_OUTPUT"]) # Start configuration # Use an absolute path for conf_dir, otherwise it gets created both relative to current directory and build directory conf = env.Configure(log_file=os.path.join(sconsDir, "sconf.log"), custom_tests={"CheckCTypeSize": CheckCTypeSize}, conf_dir=os.path.join(sconsDir, ".sconf_temp")) conf.env.Append(CPPDEFINES=["SIZEOF_SHORT=%d" % conf.CheckCTypeSize("short")]) conf.env.Append(CPPDEFINES=["SIZEOF_INT=%d" % conf.CheckCTypeSize("int")]) conf.env.Append(CPPDEFINES=["SIZEOF_LONG=%d" % conf.CheckCTypeSize("long")]) if checkSymbol(conf, "time.h", "rt", "clock_gettime"): conf.env.Append(CPPDEFINES=["HAVE_CLOCK_GETTIME"]) if checkSymbol(conf, "time.h", symbol="nanosleep"): conf.env.Append(CPPDEFINES=["HAVE_NANOSLEEP"]) if conf.CheckCHeader("sys/soundcard.h"): conf.env.Append(CPPDEFINES=["HAVE_SYS_SOUNDCARD_H"]) if conf.CheckCHeader("linux/soundcard.h"): conf.env.Append(CPPDEFINES=["HAVE_LINUX_SOUNDCARD_H"]) if conf.CheckCHeader("machine/soundcard.h"): conf.env.Append(CPPDEFINES=["HAVE_MACHINE_SOUNDCARD_H"]) # Look for needed libraries and link with them for lib, hdr, sym in neededLibs: checkSymbol(conf, hdr, lib, sym, critical=True) # Look for host API libraries, if a library isn't found disable corresponding host API implementation. for name, val in optionalImpls.items(): lib, hdr, sym = val if checkSymbol(conf, hdr, lib, sym, critical=False, pkgName=name.lower()): conf.env.Append(CPPDEFINES=["PA_USE_%s=1" % name.upper()]) else: del optionalImpls[name] # Configuration finished env = conf.Finish() # PA infrastructure CommonSources = [os.path.join("common", f) for f in "pa_allocation.c pa_converters.c pa_cpuload.c pa_dither.c pa_front.c \ pa_process.c pa_skeleton.c pa_stream.c pa_trace.c pa_debugprint.c pa_ringbuffer.c".split()] # Host API implementations ImplSources = [] if Platform in Posix: ImplSources += [os.path.join("os", "unix", f) for f in "pa_unix_hostapis.c pa_unix_util.c".split()] if "ALSA" in optionalImpls: ImplSources.append(os.path.join("hostapi", "alsa", "pa_linux_alsa.c")) if "JACK" in optionalImpls: ImplSources.append(os.path.join("hostapi", "jack", "pa_jack.c")) if "OSS" in optionalImpls: ImplSources.append(os.path.join("hostapi", "oss", "pa_unix_oss.c")) if "ASIHPI" in optionalImpls: ImplSources.append(os.path.join("hostapi", "asihpi", "pa_linux_asihpi.c")) sources = CommonSources + ImplSources sharedLibEnv = env.Copy() if Platform in Posix: # Add soname to library, this is so a reference is made to the versioned library in programs linking against libportaudio.so sharedLibEnv.AppendUnique(SHLINKFLAGS="-Wl,-soname=libportaudio.so.%d" % int(ApiVer.split(".")[0])) sharedLib = sharedLibEnv.SharedLibrary(target="portaudio", source=sources) staticLib = env.StaticLibrary(target="portaudio", source=sources) if Platform in Posix: prefix = env["prefix"] includeDir = os.path.join(prefix, "include") libDir = os.path.join(prefix, "lib") testNames = ["patest_sine", "paqa_devs", "paqa_errs", "patest1", "patest_buffer", "patest_callbackstop", "patest_clip", \ "patest_dither", "patest_hang", "patest_in_overflow", "patest_latency", "patest_leftright", "patest_longsine", \ "patest_many", "patest_maxsines", "patest_multi_sine", "patest_out_underflow", "patest_pink", "patest_prime", \ "patest_read_record", "patest_record", "patest_ringmix", "patest_saw", "patest_sine8", "patest_sine", \ "patest_sine_time", "patest_start_stop", "patest_stop", "patest_sync", "patest_toomanysines", \ "patest_underflow", "patest_wire", "patest_write_sine", "pa_devs", "pa_fuzz", "pa_minlat", \ "patest_sine_channelmaps",] # The test directory ("bin") should be in the top-level PA directory tests = [env.Program(target=os.path.join("#", "bin", name), source=[os.path.join("#", "test", name + ".c"), staticLib]) for name in testNames] # Detect host APIs hostApis = [] for cppdef in env["CPPDEFINES"]: if cppdef.startswith("PA_USE_"): hostApis.append(cppdef[7:-2]) Return("sources", "sharedLib", "staticLib", "tests", "env", "hostApis") nyquist-3.05/portaudio/src/hostapi/0002755000175000000620000000000011537433131016432 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/dsound/0002755000175000000620000000000011537433131017726 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/dsound/pa_win_ds.c0000644000175000000620000027266711466723256022072 0ustar stevestaff/* * $Id: pa_win_ds.c,v 1.1 2010/11/04 21:04:36 rbd Exp $ * Portable Audio I/O Library DirectSound implementation * * Authors: Phil Burk, Robert Marsanyi & Ross Bencina * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2007 Ross Bencina, Phil Burk, Robert Marsanyi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src @todo implement paInputOverflow callback status flag @todo implement paNeverDropInput. @todo implement host api specific extension to set i/o buffer sizes in frames @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.) @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into a native portaudio error code. Standard DirectSound result codes are documented at msdn. @todo implement IsFormatSupported @todo call PaUtil_SetLastHostErrorInfo with a specific error string (currently just "DSound error"). @todo make sure all buffers have been played before stopping the stream when the stream callback returns paComplete @todo retrieve default devices using the DRVM_MAPPER_PREFERRED_GET functions used in the wmme api these wave device ids can be aligned with the directsound devices either by retrieving the system interface device name using DRV_QUERYDEVICEINTERFACE or by using the wave device id retrieved in KsPropertySetEnumerateCallback. old TODOs from phil, need to work out if these have been done: O- fix "patest_stop.c" */ #include #include /* strlen() */ #include #include /* We are only using DX3 in here, no need to polute the namespace - davidv */ #define DIRECTSOUND_VERSION 0x0300 #include #ifdef PAWIN_USE_WDMKS_DEVICE_INFO #include #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_debugprint.h" #include "pa_win_ds.h" #include "pa_win_ds_dynlink.h" #include "pa_win_waveformat.h" #include "pa_win_wdmks_utils.h" #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ #pragma comment( lib, "dsound.lib" ) #pragma comment( lib, "winmm.lib" ) #endif /* provided in newer platform sdks and x64 */ #ifndef DWORD_PTR #define DWORD_PTR DWORD #endif #define PRINT(x) PA_DEBUG(x); #define ERR_RPT(x) PRINT(x) #define DBUG(x) PRINT(x) #define DBUGX(x) PRINT(x) #define PA_USE_HIGH_LATENCY (0) #if PA_USE_HIGH_LATENCY #define PA_WIN_9X_LATENCY (500) #define PA_WIN_NT_LATENCY (600) #else #define PA_WIN_9X_LATENCY (140) #define PA_WIN_NT_LATENCY (280) #endif #define PA_WIN_WDM_LATENCY (120) #define SECONDS_PER_MSEC (0.001) #define MSEC_PER_SECOND (1000) /* prototypes for functions declared in this file */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* FIXME: should convert hr to a string */ #define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \ PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" ) /************************************************* DX Prototypes **********/ static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ); /************************************************************************************/ /********************** Structures **************************************************/ /************************************************************************************/ /* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct PaWinDsDeviceInfo { PaDeviceInfo inheritedDeviceInfo; GUID guid; GUID *lpGUID; double sampleRates[3]; char deviceInputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ char deviceOutputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ } PaWinDsDeviceInfo; typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ char comWasInitialized; } PaWinDsHostApiRepresentation; /* PaWinDsStream - a stream data structure specifically for this implementation */ typedef struct PaWinDsStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; /* DirectSound specific data. */ /* Output */ LPDIRECTSOUND pDirectSound; LPDIRECTSOUNDBUFFER pDirectSoundOutputBuffer; DWORD outputBufferWriteOffsetBytes; /* last write position */ INT outputBufferSizeBytes; INT bytesPerOutputFrame; /* Try to detect play buffer underflows. */ LARGE_INTEGER perfCounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */ LARGE_INTEGER previousPlayTime; UINT previousPlayCursor; UINT outputUnderflowCount; BOOL outputIsRunning; /* use double which lets us can play for several thousand years with enough precision */ double dsw_framesWritten; double framesPlayed; /* Input */ LPDIRECTSOUNDCAPTURE pDirectSoundCapture; LPDIRECTSOUNDCAPTUREBUFFER pDirectSoundInputBuffer; INT bytesPerInputFrame; UINT readOffset; /* last read position */ UINT inputSize; MMRESULT timerID; int framesPerDSBuffer; double framesWritten; double secondsPerHostByte; /* Used to optimize latency calculation for outTime */ PaStreamCallbackFlags callbackFlags; /* FIXME - move all below to PaUtilStreamRepresentation */ volatile int isStarted; volatile int isActive; volatile int stopProcessing; /* stop thread once existing buffers have been returned */ volatile int abortProcessing; /* stop thread immediately */ } PaWinDsStream; /************************************************************************************ ** Duplicate the input string using the allocations allocator. ** A NULL string is converted to a zero length string. ** If memory cannot be allocated, NULL is returned. **/ static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const char* src ) { char *result = 0; if( src != NULL ) { size_t len = strlen(src); result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) ); if( result ) memcpy( (void *) result, src, len+1 ); } else { result = (char*)PaUtil_GroupAllocateMemory( allocations, 1 ); if( result ) result[0] = '\0'; } return result; } /************************************************************************************ ** DSDeviceNameAndGUID, DSDeviceNameAndGUIDVector used for collecting preliminary ** information during device enumeration. */ typedef struct DSDeviceNameAndGUID{ char *name; // allocated from parent's allocations, never deleted by this structure GUID guid; LPGUID lpGUID; void *pnpInterface; // wchar_t* interface path, allocated using the DS host api's allocation group } DSDeviceNameAndGUID; typedef struct DSDeviceNameAndGUIDVector{ PaUtilAllocationGroup *allocations; PaError enumerationError; int count; int free; DSDeviceNameAndGUID *items; // Allocated using LocalAlloc() } DSDeviceNameAndGUIDVector; typedef struct DSDeviceNamesAndGUIDs{ PaWinDsHostApiRepresentation *winDsHostApi; DSDeviceNameAndGUIDVector inputNamesAndGUIDs; DSDeviceNameAndGUIDVector outputNamesAndGUIDs; } DSDeviceNamesAndGUIDs; static PaError InitializeDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector, PaUtilAllocationGroup *allocations ) { PaError result = paNoError; guidVector->allocations = allocations; guidVector->enumerationError = paNoError; guidVector->count = 0; guidVector->free = 8; guidVector->items = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * guidVector->free ); if( guidVector->items == NULL ) result = paInsufficientMemory; return result; } static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector ) { PaError result = paNoError; DSDeviceNameAndGUID *newItems; int i; /* double size of vector */ int size = guidVector->count + guidVector->free; guidVector->free += size; newItems = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * size * 2 ); if( newItems == NULL ) { result = paInsufficientMemory; } else { for( i=0; i < guidVector->count; ++i ) { newItems[i].name = guidVector->items[i].name; if( guidVector->items[i].lpGUID == NULL ) { newItems[i].lpGUID = NULL; } else { newItems[i].lpGUID = &newItems[i].guid; memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) );; } newItems[i].pnpInterface = guidVector->items[i].pnpInterface; } LocalFree( guidVector->items ); guidVector->items = newItems; } return result; } /* it's safe to call DSDeviceNameAndGUIDVector multiple times */ static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector ) { PaError result = paNoError; if( guidVector->items != NULL ) { if( LocalFree( guidVector->items ) != NULL ) result = paInsufficientMemory; /** @todo this isn't the correct error to return from a deallocation failure */ guidVector->items = NULL; } return result; } /************************************************************************************ ** Collect preliminary device information during DirectSound enumeration */ static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ) { DSDeviceNameAndGUIDVector *namesAndGUIDs = (DSDeviceNameAndGUIDVector*)lpContext; PaError error; (void) lpszDrvName; /* unused variable */ if( namesAndGUIDs->free == 0 ) { error = ExpandDSDeviceNameAndGUIDVector( namesAndGUIDs ); if( error != paNoError ) { namesAndGUIDs->enumerationError = error; return FALSE; } } /* Set GUID pointer, copy GUID to storage in DSDeviceNameAndGUIDVector. */ if( lpGUID == NULL ) { namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = NULL; } else { namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = &namesAndGUIDs->items[namesAndGUIDs->count].guid; memcpy( &namesAndGUIDs->items[namesAndGUIDs->count].guid, lpGUID, sizeof(GUID) ); } namesAndGUIDs->items[namesAndGUIDs->count].name = DuplicateDeviceNameString( namesAndGUIDs->allocations, lpszDesc ); if( namesAndGUIDs->items[namesAndGUIDs->count].name == NULL ) { namesAndGUIDs->enumerationError = paInsufficientMemory; return FALSE; } namesAndGUIDs->items[namesAndGUIDs->count].pnpInterface = 0; ++namesAndGUIDs->count; --namesAndGUIDs->free; return TRUE; } #ifdef PAWIN_USE_WDMKS_DEVICE_INFO static void *DuplicateWCharString( PaUtilAllocationGroup *allocations, wchar_t *source ) { size_t len; wchar_t *result; len = wcslen( source ); result = (wchar_t*)PaUtil_GroupAllocateMemory( allocations, (long) ((len+1) * sizeof(wchar_t)) ); wcscpy( result, source ); return result; } static BOOL CALLBACK KsPropertySetEnumerateCallback( PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data, LPVOID context ) { int i; DSDeviceNamesAndGUIDs *deviceNamesAndGUIDs = (DSDeviceNamesAndGUIDs*)context; if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ) { for( i=0; i < deviceNamesAndGUIDs->outputNamesAndGUIDs.count; ++i ) { if( deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID && memcmp( &data->DeviceId, deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) { deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].pnpInterface = (char*)DuplicateWCharString( deviceNamesAndGUIDs->winDsHostApi->allocations, data->Interface ); break; } } } else if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ) { for( i=0; i < deviceNamesAndGUIDs->inputNamesAndGUIDs.count; ++i ) { if( deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID && memcmp( &data->DeviceId, deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) { deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].pnpInterface = (char*)DuplicateWCharString( deviceNamesAndGUIDs->winDsHostApi->allocations, data->Interface ); break; } } } return TRUE; } static GUID pawin_CLSID_DirectSoundPrivate = { 0x11ab3ec0, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca }; static GUID pawin_DSPROPSETID_DirectSoundDevice = { 0x84624f82, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca }; static GUID pawin_IID_IKsPropertySet = { 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93 }; /* FindDevicePnpInterfaces fills in the pnpInterface fields in deviceNamesAndGUIDs with UNICODE file paths to the devices. The DS documentation mentions at least two techniques by which these Interface paths can be found using IKsPropertySet on the DirectSound class object. One is using the DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION property, and the other is using DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE. I tried both methods and only the second worked. I found two postings on the net from people who had the same problem with the first method, so I think the method used here is more common/likely to work. The probem is that IKsPropertySet_Get returns S_OK but the fields of the device description are not filled in. The mechanism we use works by registering an enumeration callback which is called for every DSound device. Our callback searches for a device in our deviceNamesAndGUIDs list with the matching GUID and copies the pointer to the Interface path. Note that we could have used this enumeration callback to perform the original device enumeration, however we choose not to so we can disable this step easily. Apparently the IKsPropertySet mechanism was added in DirectSound 9c 2004 http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.mmedia/2004-12/0099.html -- rossb */ static void FindDevicePnpInterfaces( DSDeviceNamesAndGUIDs *deviceNamesAndGUIDs ) { IClassFactory *pClassFactory; if( paWinDsDSoundEntryPoints.DllGetClassObject(&pawin_CLSID_DirectSoundPrivate, &IID_IClassFactory, (PVOID *) &pClassFactory) == S_OK ){ IKsPropertySet *pPropertySet; if( pClassFactory->lpVtbl->CreateInstance( pClassFactory, NULL, &pawin_IID_IKsPropertySet, (PVOID *) &pPropertySet) == S_OK ){ DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data; ULONG bytesReturned; data.Callback = KsPropertySetEnumerateCallback; data.Context = deviceNamesAndGUIDs; IKsPropertySet_Get( pPropertySet, &pawin_DSPROPSETID_DirectSoundDevice, DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, NULL, 0, &data, sizeof(data), &bytesReturned ); IKsPropertySet_Release( pPropertySet ); } pClassFactory->lpVtbl->Release( pClassFactory ); } /* The following code fragment, which I chose not to use, queries for the device interface for a device with a specific GUID: ULONG BytesReturned; DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA Property; memset (&Property, 0, sizeof(Property)); Property.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; Property.DeviceId = *lpGUID; hr = IKsPropertySet_Get( pPropertySet, &pawin_DSPROPSETID_DirectSoundDevice, DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W, NULL, 0, &Property, sizeof(Property), &BytesReturned ); if( hr == S_OK ) { //pnpInterface = Property.Interface; } */ } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ /* GUIDs for emulated devices which we blacklist below. are there more than two of them?? */ GUID IID_IRolandVSCEmulated1 = {0xc2ad1800, 0xb243, 0x11ce, 0xa8, 0xa4, 0x00, 0xaa, 0x00, 0x6c, 0x45, 0x01}; GUID IID_IRolandVSCEmulated2 = {0xc2ad1800, 0xb243, 0x11ce, 0xa8, 0xa4, 0x00, 0xaa, 0x00, 0x6c, 0x45, 0x02}; #define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */ static double defaultSampleRateSearchOrder_[] = { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; /************************************************************************************ ** Extract capabilities from an output device, and add it to the device info list ** if successful. This function assumes that there is enough room in the ** device info list to accomodate all entries. ** ** The device will not be added to the device list if any errors are encountered. */ static PaError AddOutputDeviceInfoFromDirectSound( PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID, char *pnpInterface ) { PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep; PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[hostApi->info.deviceCount]; PaDeviceInfo *deviceInfo = &winDsDeviceInfo->inheritedDeviceInfo; HRESULT hr; LPDIRECTSOUND lpDirectSound; DSCAPS caps; int deviceOK = TRUE; PaError result = paNoError; int i; /* Copy GUID to the device info structure. Set pointer. */ if( lpGUID == NULL ) { winDsDeviceInfo->lpGUID = NULL; } else { memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; } if( lpGUID ) { if (IsEqualGUID (&IID_IRolandVSCEmulated1,lpGUID) || IsEqualGUID (&IID_IRolandVSCEmulated2,lpGUID) ) { PA_DEBUG(("BLACKLISTED: %s \n",name)); return paNoError; } } /* Create a DirectSound object for the specified GUID Note that using CoCreateInstance doesn't work on windows CE. */ hr = paWinDsDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL ); /** try using CoCreateInstance because DirectSoundCreate was hanging under some circumstances - note this was probably related to the #define BOOL short bug which has now been fixed @todo delete this comment and the following code once we've ensured there is no bug. */ /* hr = CoCreateInstance( &CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (void**)&lpDirectSound ); if( hr == S_OK ) { hr = IDirectSound_Initialize( lpDirectSound, lpGUID ); } */ if( hr != DS_OK ) { if (hr == DSERR_ALLOCATED) PA_DEBUG(("AddOutputDeviceInfoFromDirectSound %s DSERR_ALLOCATED\n",name)); DBUG(("Cannot create DirectSound for %s. Result = 0x%x\n", name, hr )); if (lpGUID) DBUG(("%s's GUID: {0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x, 0x%x} \n", name, lpGUID->Data1, lpGUID->Data2, lpGUID->Data3, lpGUID->Data4[0], lpGUID->Data4[1], lpGUID->Data4[2], lpGUID->Data4[3], lpGUID->Data4[4], lpGUID->Data4[5], lpGUID->Data4[6], lpGUID->Data4[7])); deviceOK = FALSE; } else { /* Query device characteristics. */ memset( &caps, 0, sizeof(caps) ); caps.dwSize = sizeof(caps); hr = IDirectSound_GetCaps( lpDirectSound, &caps ); if( hr != DS_OK ) { DBUG(("Cannot GetCaps() for DirectSound device %s. Result = 0x%x\n", name, hr )); deviceOK = FALSE; } else { #ifndef PA_NO_WMME if( caps.dwFlags & DSCAPS_EMULDRIVER ) { /* If WMME supported, then reject Emulated drivers because they are lousy. */ deviceOK = FALSE; } #endif if( deviceOK ) { deviceInfo->maxInputChannels = 0; winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; /* DS output capabilities only indicate supported number of channels using two flags which indicate mono and/or stereo. We assume that stereo devices may support more than 2 channels (as is the case with 5.1 devices for example) and so set deviceOutputChannelCountIsKnown to 0 (unknown). In this case OpenStream will try to open the device when the user requests more than 2 channels, rather than returning an error. */ if( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) { deviceInfo->maxOutputChannels = 2; winDsDeviceInfo->deviceOutputChannelCountIsKnown = 0; } else { deviceInfo->maxOutputChannels = 1; winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; } #ifdef PAWIN_USE_WDMKS_DEVICE_INFO if( pnpInterface ) { int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 0 ); if( count > 0 ) { deviceInfo->maxOutputChannels = count; winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; } } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */ deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */ deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */ deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */ /* initialize defaultSampleRate */ if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) { /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */ deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i ) { if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ) { deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i]; break; } } } else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate ) { if( caps.dwMinSecondarySampleRate == 0 ) { /* ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !! ** But it supports continuous sampling. ** So fake range of rates, and hope it really supports it. */ deviceInfo->defaultSampleRate = 44100.0f; DBUG(("PA - Reported rates both zero. Setting to fake values for device #%s\n", name )); } else { deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; } } else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) { /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000. ** But we know that they really support a range of rates! ** So when we see a ridiculous set of rates, assume it is a range. */ deviceInfo->defaultSampleRate = 44100.0f; DBUG(("PA - Sample rate range used instead of two odd values for device #%s\n", name )); } else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate ); // dwFlags | DSCAPS_CONTINUOUSRATE } } IDirectSound_Release( lpDirectSound ); } if( deviceOK ) { deviceInfo->name = name; if( lpGUID == NULL ) hostApi->info.defaultOutputDevice = hostApi->info.deviceCount; hostApi->info.deviceCount++; } return result; } /************************************************************************************ ** Extract capabilities from an input device, and add it to the device info list ** if successful. This function assumes that there is enough room in the ** device info list to accomodate all entries. ** ** The device will not be added to the device list if any errors are encountered. */ static PaError AddInputDeviceInfoFromDirectSoundCapture( PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID, char *pnpInterface ) { PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep; PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[hostApi->info.deviceCount]; PaDeviceInfo *deviceInfo = &winDsDeviceInfo->inheritedDeviceInfo; HRESULT hr; LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; DSCCAPS caps; int deviceOK = TRUE; PaError result = paNoError; /* Copy GUID to the device info structure. Set pointer. */ if( lpGUID == NULL ) { winDsDeviceInfo->lpGUID = NULL; } else { winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); } hr = paWinDsDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL ); /** try using CoCreateInstance because DirectSoundCreate was hanging under some circumstances - note this was probably related to the #define BOOL short bug which has now been fixed @todo delete this comment and the following code once we've ensured there is no bug. */ /* hr = CoCreateInstance( &CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSoundCapture, (void**)&lpDirectSoundCapture ); */ if( hr != DS_OK ) { DBUG(("Cannot create Capture for %s. Result = 0x%x\n", name, hr )); deviceOK = FALSE; } else { /* Query device characteristics. */ memset( &caps, 0, sizeof(caps) ); caps.dwSize = sizeof(caps); hr = IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps ); if( hr != DS_OK ) { DBUG(("Cannot GetCaps() for Capture device %s. Result = 0x%x\n", name, hr )); deviceOK = FALSE; } else { #ifndef PA_NO_WMME if( caps.dwFlags & DSCAPS_EMULDRIVER ) { /* If WMME supported, then reject Emulated drivers because they are lousy. */ deviceOK = FALSE; } #endif if( deviceOK ) { deviceInfo->maxInputChannels = caps.dwChannels; winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; deviceInfo->maxOutputChannels = 0; winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; #ifdef PAWIN_USE_WDMKS_DEVICE_INFO if( pnpInterface ) { int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 1 ); if( count > 0 ) { deviceInfo->maxInputChannels = count; winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; } } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */ deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */ deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */ deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */ /* constants from a WINE patch by Francois Gouget, see: http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html --- Date: Fri, 14 May 2004 10:38:12 +0200 (CEST) From: Francois Gouget To: Ross Bencina Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library [snip] I give you permission to use the patch below under the BSD license. http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html [snip] */ #ifndef WAVE_FORMAT_48M08 #define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */ #define WAVE_FORMAT_48S08 0x00002000 /* 48 kHz, Stereo, 8-bit */ #define WAVE_FORMAT_48M16 0x00004000 /* 48 kHz, Mono, 16-bit */ #define WAVE_FORMAT_48S16 0x00008000 /* 48 kHz, Stereo, 16-bit */ #define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */ #define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */ #define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */ #define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */ #endif /* defaultSampleRate */ if( caps.dwChannels == 2 ) { if( caps.dwFormats & WAVE_FORMAT_4S16 ) deviceInfo->defaultSampleRate = 44100.0; else if( caps.dwFormats & WAVE_FORMAT_48S16 ) deviceInfo->defaultSampleRate = 48000.0; else if( caps.dwFormats & WAVE_FORMAT_2S16 ) deviceInfo->defaultSampleRate = 22050.0; else if( caps.dwFormats & WAVE_FORMAT_1S16 ) deviceInfo->defaultSampleRate = 11025.0; else if( caps.dwFormats & WAVE_FORMAT_96S16 ) deviceInfo->defaultSampleRate = 96000.0; else deviceInfo->defaultSampleRate = 0.; } else if( caps.dwChannels == 1 ) { if( caps.dwFormats & WAVE_FORMAT_4M16 ) deviceInfo->defaultSampleRate = 44100.0; else if( caps.dwFormats & WAVE_FORMAT_48M16 ) deviceInfo->defaultSampleRate = 48000.0; else if( caps.dwFormats & WAVE_FORMAT_2M16 ) deviceInfo->defaultSampleRate = 22050.0; else if( caps.dwFormats & WAVE_FORMAT_1M16 ) deviceInfo->defaultSampleRate = 11025.0; else if( caps.dwFormats & WAVE_FORMAT_96M16 ) deviceInfo->defaultSampleRate = 96000.0; else deviceInfo->defaultSampleRate = 0.; } else deviceInfo->defaultSampleRate = 0.; } } IDirectSoundCapture_Release( lpDirectSoundCapture ); } if( deviceOK ) { deviceInfo->name = name; if( lpGUID == NULL ) hostApi->info.defaultInputDevice = hostApi->info.deviceCount; hostApi->info.deviceCount++; } return result; } /***********************************************************************************/ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; int i, deviceCount; PaWinDsHostApiRepresentation *winDsHostApi; DSDeviceNamesAndGUIDs deviceNamesAndGUIDs; PaWinDsDeviceInfo *deviceInfoArray; char comWasInitialized = 0; /* If COM is already initialized CoInitialize will either return FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different threading mode. In either case we shouldn't consider it an error but we need to be careful to not call CoUninitialize() if RPC_E_CHANGED_MODE was returned. */ HRESULT hr = CoInitialize(NULL); if( FAILED(hr) && hr != RPC_E_CHANGED_MODE ) return paUnanticipatedHostError; if( hr != RPC_E_CHANGED_MODE ) comWasInitialized = 1; /* initialise guid vectors so they can be safely deleted on error */ deviceNamesAndGUIDs.winDsHostApi = NULL; deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL; deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL; PaWinDs_InitializeDSoundEntryPoints(); winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) ); if( !winDsHostApi ) { result = paInsufficientMemory; goto error; } winDsHostApi->comWasInitialized = comWasInitialized; winDsHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !winDsHostApi->allocations ) { result = paInsufficientMemory; goto error; } *hostApi = &winDsHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paDirectSound; (*hostApi)->info.name = "Windows DirectSound"; (*hostApi)->info.deviceCount = 0; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; /* DSound - enumerate devices to count them and to gather their GUIDs */ result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations ); if( result != paNoError ) goto error; result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations ); if( result != paNoError ) goto error; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs ); paWinDsDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs ); if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError ) { result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError; goto error; } if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError ) { result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError; goto error; } deviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + deviceNamesAndGUIDs.outputNamesAndGUIDs.count; #ifdef PAWIN_USE_WDMKS_DEVICE_INFO if( deviceCount > 0 ) { deviceNamesAndGUIDs.winDsHostApi = winDsHostApi; FindDevicePnpInterfaces( &deviceNamesAndGUIDs ); } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ if( deviceCount > 0 ) { /* allocate array for pointers to PaDeviceInfo structs */ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); if( !(*hostApi)->deviceInfos ) { result = paInsufficientMemory; goto error; } /* allocate all PaDeviceInfo structs in a contiguous block */ deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory( winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount ); if( !deviceInfoArray ) { result = paInsufficientMemory; goto error; } for( i=0; i < deviceCount; ++i ) { PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = 0; (*hostApi)->deviceInfos[i] = deviceInfo; } for( i=0; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count; ++i ) { result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi, deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name, deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID, deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface ); if( result != paNoError ) goto error; } for( i=0; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count; ++i ) { result = AddOutputDeviceInfoFromDirectSound( winDsHostApi, deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name, deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID, deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface ); if( result != paNoError ) goto error; } } result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); if( result != paNoError ) goto error; result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); if( result != paNoError ) goto error; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if( winDsHostApi ) { if( winDsHostApi->allocations ) { PaUtil_FreeAllAllocations( winDsHostApi->allocations ); PaUtil_DestroyAllocationGroup( winDsHostApi->allocations ); } PaUtil_FreeMemory( winDsHostApi ); } TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); if( comWasInitialized ) CoUninitialize(); return result; } /***********************************************************************************/ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; char comWasInitialized = winDsHostApi->comWasInitialized; /* IMPLEMENT ME: - clean up any resources not handled by the allocation group */ if( winDsHostApi->allocations ) { PaUtil_FreeAllAllocations( winDsHostApi->allocations ); PaUtil_DestroyAllocationGroup( winDsHostApi->allocations ); } PaUtil_FreeMemory( winDsHostApi ); PaWinDs_TerminateDSoundEntryPoints(); if( comWasInitialized ) CoUninitialize(); } /* Set minimal latency based on whether NT or Win95. * NT has higher latency. */ static int PaWinDS_GetMinSystemLatency( void ) { int minLatencyMsec; /* Set minimal latency based on whether NT or other OS. * NT has higher latency. */ OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof( osvi ); GetVersionEx( &osvi ); DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); /* Check for NT */ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) { minLatencyMsec = PA_WIN_NT_LATENCY; } else if(osvi.dwMajorVersion >= 5) { minLatencyMsec = PA_WIN_WDM_LATENCY; } else { minLatencyMsec = PA_WIN_9X_LATENCY; } return minLatencyMsec; } static PaError ValidateWinDirectSoundSpecificStreamInfo( const PaStreamParameters *streamParameters, const PaWinDirectSoundStreamInfo *streamInfo ) { if( streamInfo ) { if( streamInfo->size != sizeof( PaWinDirectSoundStreamInfo ) || streamInfo->version != 1 ) { return paIncompatibleHostApiSpecificStreamInfo; } } return paNoError; } /***********************************************************************************/ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaError result; PaWinDsDeviceInfo *inputWinDsDeviceInfo, *outputWinDsDeviceInfo; PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaWinDirectSoundStreamInfo *inputStreamInfo, *outputStreamInfo; if( inputParameters ) { inputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ inputParameters->device ]; inputDeviceInfo = &inputWinDsDeviceInfo->inheritedDeviceInfo; inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputWinDsDeviceInfo->deviceInputChannelCountIsKnown && inputChannelCount > inputDeviceInfo->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ inputStreamInfo = (PaWinDirectSoundStreamInfo*)inputParameters->hostApiSpecificStreamInfo; result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); if( result != paNoError ) return result; } else { inputChannelCount = 0; } if( outputParameters ) { outputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ outputParameters->device ]; outputDeviceInfo = &outputWinDsDeviceInfo->inheritedDeviceInfo; outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputWinDsDeviceInfo->deviceOutputChannelCountIsKnown && outputChannelCount > outputDeviceInfo->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ outputStreamInfo = (PaWinDirectSoundStreamInfo*)outputParameters->hostApiSpecificStreamInfo; result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); if( result != paNoError ) return result; } else { outputChannelCount = 0; } /* IMPLEMENT ME: - if a full duplex stream is requested, check that the combination of input and output parameters is supported if necessary - check that the device supports sampleRate Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format */ return paFormatIsSupported; } /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Latency can be optionally set by user by setting ** an environment variable. For example, to set latency to 200 msec, put: ** ** set PA_MIN_LATENCY_MSEC=200 ** ** in the AUTOEXEC.BAT file and reboot. ** If the environment variable is not set, then the latency will be determined ** based on the OS. Windows NT has higher latency than Win95. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") #define PA_ENV_BUF_SIZE (32) static int PaWinDs_GetMinLatencyFrames( double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; DWORD hresult; int minLatencyMsec = 0; /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { minLatencyMsec = atoi( envbuf ); } else { minLatencyMsec = PaWinDS_GetMinSystemLatency(); #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif } return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC); } static HRESULT InitInputBuffer( PaWinDsStream *stream, PaSampleFormat sampleFormat, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer, PaWinWaveFormatChannelMask channelMask ) { DSCBUFFERDESC captureDesc; PaWinWaveFormat waveFormat; HRESULT result; stream->bytesPerInputFrame = nChannels * Pa_GetSampleSize(sampleFormat); stream->inputSize = bytesPerBuffer; // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); captureDesc.dwSize = sizeof(DSCBUFFERDESC); captureDesc.dwFlags = 0; captureDesc.dwBufferBytes = bytesPerBuffer; captureDesc.lpwfxFormat = (WAVEFORMATEX*)&waveFormat; // Create the capture buffer // first try WAVEFORMATEXTENSIBLE. if this fails, fall back to WAVEFORMATEX PaWin_InitializeWaveFormatExtensible( &waveFormat, nChannels, sampleFormat, nFrameRate, channelMask ); if( IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, &captureDesc, &stream->pDirectSoundInputBuffer, NULL) != DS_OK ) { PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, nFrameRate ); if ((result = IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, &captureDesc, &stream->pDirectSoundInputBuffer, NULL)) != DS_OK) return result; } stream->readOffset = 0; // reset last read position to start of buffer return DS_OK; } static HRESULT InitOutputBuffer( PaWinDsStream *stream, PaSampleFormat sampleFormat, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer, PaWinWaveFormatChannelMask channelMask ) { /** @todo FIXME: if InitOutputBuffer returns an error I'm not sure it frees all resources cleanly */ DWORD dwDataLen; DWORD playCursor; HRESULT result; LPDIRECTSOUNDBUFFER pPrimaryBuffer; HWND hWnd; HRESULT hr; PaWinWaveFormat waveFormat; DSBUFFERDESC primaryDesc; DSBUFFERDESC secondaryDesc; unsigned char* pDSBuffData; LARGE_INTEGER counterFrequency; int bytesPerSample = Pa_GetSampleSize(sampleFormat); stream->outputBufferSizeBytes = bytesPerBuffer; stream->outputIsRunning = FALSE; stream->outputUnderflowCount = 0; stream->dsw_framesWritten = 0; stream->bytesPerOutputFrame = nChannels * bytesPerSample; // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the // applications's window. Also if that window is closed before the Buffer is closed // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.) // So we will use GetDesktopWindow() which was suggested by Miller Puckette. // hWnd = GetForegroundWindow(); // // FIXME: The example code I have on the net creates a hidden window that // is managed by our code - I think we should do that - one hidden // window for the whole of Pa_DS // hWnd = GetDesktopWindow(); // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz. // Exclusize also prevents unexpected sounds from other apps during a performance. if ((hr = IDirectSound_SetCooperativeLevel( stream->pDirectSound, hWnd, DSSCL_EXCLUSIVE)) != DS_OK) { return hr; } // ----------------------------------------------------------------------- // Create primary buffer and set format just so we can specify our custom format. // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz. // Setup the primary buffer description ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); primaryDesc.dwSize = sizeof(DSBUFFERDESC); primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth primaryDesc.dwBufferBytes = 0; primaryDesc.lpwfxFormat = NULL; // Create the buffer if ((result = IDirectSound_CreateSoundBuffer( stream->pDirectSound, &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result; // Set the primary buffer's format // first try WAVEFORMATEXTENSIBLE. if this fails, fall back to WAVEFORMATEX PaWin_InitializeWaveFormatExtensible( &waveFormat, nChannels, sampleFormat, nFrameRate, channelMask ); if( IDirectSoundBuffer_SetFormat( pPrimaryBuffer, (WAVEFORMATEX*)&waveFormat) != DS_OK ) { PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, nFrameRate ); if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, (WAVEFORMATEX*)&waveFormat)) != DS_OK) return result; } // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); secondaryDesc.dwSize = sizeof(DSBUFFERDESC); secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; secondaryDesc.dwBufferBytes = bytesPerBuffer; secondaryDesc.lpwfxFormat = (WAVEFORMATEX*)&waveFormat; // Create the secondary buffer if ((result = IDirectSound_CreateSoundBuffer( stream->pDirectSound, &secondaryDesc, &stream->pDirectSoundOutputBuffer, NULL)) != DS_OK) return result; // Lock the DS buffer if ((result = IDirectSoundBuffer_Lock( stream->pDirectSoundOutputBuffer, 0, stream->outputBufferSizeBytes, (LPVOID*)&pDSBuffData, &dwDataLen, NULL, 0, 0)) != DS_OK) return result; // Zero the DS buffer ZeroMemory(pDSBuffData, dwDataLen); // Unlock the DS buffer if ((result = IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result; if( QueryPerformanceFrequency( &counterFrequency ) ) { int framesInBuffer = bytesPerBuffer / (nChannels * bytesPerSample); stream->perfCounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate; } else { stream->perfCounterTicksPerBuffer.QuadPart = 0; } // Let DSound set the starting write position because if we set it to zero, it looks like the // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. hr = IDirectSoundBuffer_GetCurrentPosition( stream->pDirectSoundOutputBuffer, &playCursor, &stream->outputBufferWriteOffsetBytes ); if( hr != DS_OK ) { return hr; } stream->dsw_framesWritten = stream->outputBufferWriteOffsetBytes / stream->bytesPerOutputFrame; /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */ return DS_OK; } /***********************************************************************************/ /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; PaWinDsStream *stream = 0; PaWinDsDeviceInfo *inputWinDsDeviceInfo, *outputWinDsDeviceInfo; PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames; PaWinDirectSoundStreamInfo *inputStreamInfo, *outputStreamInfo; PaWinWaveFormatChannelMask inputChannelMask, outputChannelMask; if( inputParameters ) { inputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ inputParameters->device ]; inputDeviceInfo = &inputWinDsDeviceInfo->inheritedDeviceInfo; inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate); /* IDEA: the following 3 checks could be performed by default by pa_front unless some flag indicated otherwise */ /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputWinDsDeviceInfo->deviceInputChannelCountIsKnown && inputChannelCount > inputDeviceInfo->maxInputChannels ) return paInvalidChannelCount; /* validate hostApiSpecificStreamInfo */ inputStreamInfo = (PaWinDirectSoundStreamInfo*)inputParameters->hostApiSpecificStreamInfo; result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); if( result != paNoError ) return result; if( inputStreamInfo && inputStreamInfo->flags & paWinDirectSoundUseChannelMask ) inputChannelMask = inputStreamInfo->channelMask; else inputChannelMask = PaWin_DefaultChannelMask( inputChannelCount ); } else { inputChannelCount = 0; inputSampleFormat = 0; suggestedInputLatencyFrames = 0; } if( outputParameters ) { outputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ outputParameters->device ]; outputDeviceInfo = &outputWinDsDeviceInfo->inheritedDeviceInfo; outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate); /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support outputChannelCount */ if( outputWinDsDeviceInfo->deviceOutputChannelCountIsKnown && outputChannelCount > outputDeviceInfo->maxOutputChannels ) return paInvalidChannelCount; /* validate hostApiSpecificStreamInfo */ outputStreamInfo = (PaWinDirectSoundStreamInfo*)outputParameters->hostApiSpecificStreamInfo; result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); if( result != paNoError ) return result; if( outputStreamInfo && outputStreamInfo->flags & paWinDirectSoundUseChannelMask ) outputChannelMask = outputStreamInfo->channelMask; else outputChannelMask = PaWin_DefaultChannelMask( outputChannelCount ); } else { outputChannelCount = 0; outputSampleFormat = 0; suggestedOutputLatencyFrames = 0; } /* IMPLEMENT ME: ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() ) - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate - alter sampleRate to a close allowable rate if possible / necessary - validate suggestedInputLatency and suggestedOutputLatency parameters, use default values where necessary */ /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) ); if( !stream ) { result = paInsufficientMemory; goto error; } memset( stream, 0, sizeof(PaWinDsStream) ); /* initialize all stream variables to 0 */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &winDsHostApi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &winDsHostApi->blockingStreamInterface, streamCallback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); if( inputParameters ) { /* IMPLEMENT ME - establish which host formats are available */ PaSampleFormat nativeInputFormats = paInt16; //PaSampleFormat nativeFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32; hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( nativeInputFormats, inputParameters->sampleFormat ); } else { hostInputSampleFormat = 0; } if( outputParameters ) { /* IMPLEMENT ME - establish which host formats are available */ PaSampleFormat nativeOutputFormats = paInt16; //PaSampleFormat nativeOutputFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32; hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( nativeOutputFormats, outputParameters->sampleFormat ); } else { hostOutputSampleFormat = 0; } result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */ /* This next mode is required because DS can split the host buffer when it wraps around. */ paUtilVariableHostBufferSizePartialUsageAllowed, streamCallback, userData ); if( result != paNoError ) goto error; stream->streamRepresentation.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */ stream->streamRepresentation.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */ stream->streamRepresentation.streamInfo.sampleRate = sampleRate; /* DirectSound specific initialization */ { HRESULT hr; int bytesPerDirectSoundBuffer; int userLatencyFrames; int minLatencyFrames; stream->timerID = 0; /* Get system minimum latency. */ minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate ); /* Let user override latency by passing latency parameter. */ userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames) ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames; if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames; /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */ if( framesPerBuffer == paFramesPerBufferUnspecified ) { /* App support variable framesPerBuffer */ stream->framesPerDSBuffer = minLatencyFrames; stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate; } else { /* Round up to number of buffers needed to guarantee that latency. */ int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer; if( numUserBuffers < 1 ) numUserBuffers = 1; numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */ stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers; stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate; } { /** @todo REVIEW: this calculation seems incorrect to me - rossb. */ int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate); PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency )); } /* ------------------ OUTPUT */ if( outputParameters ) { /* PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ]; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device)); */ int bytesPerSample = Pa_GetSampleSize(hostOutputSampleFormat); bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * bytesPerSample; if( bytesPerDirectSoundBuffer < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } hr = paWinDsDSoundEntryPoints.DirectSoundCreate( ((PaWinDsDeviceInfo*)hostApi->deviceInfos[outputParameters->device])->lpGUID, &stream->pDirectSound, NULL ); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } hr = InitOutputBuffer( stream, hostOutputSampleFormat, (unsigned long) (sampleRate + 0.5), (WORD)outputParameters->channelCount, bytesPerDirectSoundBuffer, outputChannelMask ); DBUG(("InitOutputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } /* Calculate value used in latency calculation to avoid real-time divides. */ stream->secondsPerHostByte = 1.0 / (stream->bufferProcessor.bytesPerHostOutputSample * outputChannelCount * sampleRate); } /* ------------------ INPUT */ if( inputParameters ) { /* PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ]; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device)); */ int bytesPerSample = Pa_GetSampleSize(hostInputSampleFormat); bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * bytesPerSample; if( bytesPerDirectSoundBuffer < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } hr = paWinDsDSoundEntryPoints.DirectSoundCaptureCreate( ((PaWinDsDeviceInfo*)hostApi->deviceInfos[inputParameters->device])->lpGUID, &stream->pDirectSoundCapture, NULL ); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n")); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } hr = InitInputBuffer( stream, hostInputSampleFormat, (unsigned long) (sampleRate + 0.5), (WORD)inputParameters->channelCount, bytesPerDirectSoundBuffer, inputChannelMask ); DBUG(("InitInputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr)); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } } } *s = (PaStream*)stream; return result; error: if( stream ) PaUtil_FreeMemory( stream ); return result; } /************************************************************************************ * Determine how much space can be safely written to in DS buffer. * Detect underflows and overflows. * Does not allow writing into safety gap maintained by DirectSound. */ static HRESULT QueryOutputSpace( PaWinDsStream *stream, long *bytesEmpty ) { HRESULT hr; DWORD playCursor; DWORD writeCursor; long numBytesEmpty; long playWriteGap; // Query to see how much room is in buffer. hr = IDirectSoundBuffer_GetCurrentPosition( stream->pDirectSoundOutputBuffer, &playCursor, &writeCursor ); if( hr != DS_OK ) { return hr; } // Determine size of gap between playIndex and WriteIndex that we cannot write into. playWriteGap = writeCursor - playCursor; if( playWriteGap < 0 ) playWriteGap += stream->outputBufferSizeBytes; // unwrap /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */ /* Attempt to detect playCursor wrap-around and correct it. */ if( stream->outputIsRunning && (stream->perfCounterTicksPerBuffer.QuadPart != 0) ) { /* How much time has elapsed since last check. */ LARGE_INTEGER currentTime; LARGE_INTEGER elapsedTime; long bytesPlayed; long bytesExpected; long buffersWrapped; QueryPerformanceCounter( ¤tTime ); elapsedTime.QuadPart = currentTime.QuadPart - stream->previousPlayTime.QuadPart; stream->previousPlayTime = currentTime; /* How many bytes does DirectSound say have been played. */ bytesPlayed = playCursor - stream->previousPlayCursor; if( bytesPlayed < 0 ) bytesPlayed += stream->outputBufferSizeBytes; // unwrap stream->previousPlayCursor = playCursor; /* Calculate how many bytes we would have expected to been played by now. */ bytesExpected = (long) ((elapsedTime.QuadPart * stream->outputBufferSizeBytes) / stream->perfCounterTicksPerBuffer.QuadPart); buffersWrapped = (bytesExpected - bytesPlayed) / stream->outputBufferSizeBytes; if( buffersWrapped > 0 ) { playCursor += (buffersWrapped * stream->outputBufferSizeBytes); bytesPlayed += (buffersWrapped * stream->outputBufferSizeBytes); } /* Maintain frame output cursor. */ stream->framesPlayed += (bytesPlayed / stream->bytesPerOutputFrame); } numBytesEmpty = playCursor - stream->outputBufferWriteOffsetBytes; if( numBytesEmpty < 0 ) numBytesEmpty += stream->outputBufferSizeBytes; // unwrap offset /* Have we underflowed? */ if( numBytesEmpty > (stream->outputBufferSizeBytes - playWriteGap) ) { if( stream->outputIsRunning ) { stream->outputUnderflowCount += 1; } stream->outputBufferWriteOffsetBytes = writeCursor; numBytesEmpty = stream->outputBufferSizeBytes - playWriteGap; } *bytesEmpty = numBytesEmpty; return hr; } /***********************************************************************************/ static PaError Pa_TimeSlice( PaWinDsStream *stream ) { PaError result = 0; /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/ long numFrames = 0; long bytesEmpty = 0; long bytesFilled = 0; long bytesToXfer = 0; long framesToXfer = 0; long numInFramesReady = 0; long numOutFramesReady = 0; long bytesProcessed; HRESULT hresult; double outputLatency = 0; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */ /* Input */ LPBYTE lpInBuf1 = NULL; LPBYTE lpInBuf2 = NULL; DWORD dwInSize1 = 0; DWORD dwInSize2 = 0; /* Output */ LPBYTE lpOutBuf1 = NULL; LPBYTE lpOutBuf2 = NULL; DWORD dwOutSize1 = 0; DWORD dwOutSize2 = 0; /* How much input data is available? */ if( stream->bufferProcessor.inputChannelCount > 0 ) { HRESULT hr; DWORD capturePos; DWORD readPos; long filled = 0; // Query to see how much data is in buffer. // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly // so let's pass a pointer just to be safe. hr = IDirectSoundCaptureBuffer_GetCurrentPosition( stream->pDirectSoundInputBuffer, &capturePos, &readPos ); if( hr == DS_OK ) { filled = readPos - stream->readOffset; if( filled < 0 ) filled += stream->inputSize; // unwrap offset bytesFilled = filled; } // FIXME: what happens if IDirectSoundCaptureBuffer_GetCurrentPosition fails? framesToXfer = numInFramesReady = bytesFilled / stream->bytesPerInputFrame; outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte; /** @todo Check for overflow */ } /* How much output room is available? */ if( stream->bufferProcessor.outputChannelCount > 0 ) { UINT previousUnderflowCount = stream->outputUnderflowCount; QueryOutputSpace( stream, &bytesEmpty ); framesToXfer = numOutFramesReady = bytesEmpty / stream->bytesPerOutputFrame; /* Check for underflow */ if( stream->outputUnderflowCount != previousUnderflowCount ) stream->callbackFlags |= paOutputUnderflow; } if( (numInFramesReady > 0) && (numOutFramesReady > 0) ) { framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady; } if( framesToXfer > 0 ) { PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* The outputBufferDacTime parameter should indicates the time at which the first sample of the output buffer is heard at the DACs. */ timeInfo.currentTime = PaUtil_GetTime(); timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency; PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags ); stream->callbackFlags = 0; /* Input */ if( stream->bufferProcessor.inputChannelCount > 0 ) { bytesToXfer = framesToXfer * stream->bytesPerInputFrame; hresult = IDirectSoundCaptureBuffer_Lock ( stream->pDirectSoundInputBuffer, stream->readOffset, bytesToXfer, (void **) &lpInBuf1, &dwInSize1, (void **) &lpInBuf2, &dwInSize2, 0); if (hresult != DS_OK) { ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult)); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult ); goto error2; } numFrames = dwInSize1 / stream->bytesPerInputFrame; PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 ); /* Is input split into two regions. */ if( dwInSize2 > 0 ) { numFrames = dwInSize2 / stream->bytesPerInputFrame; PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 ); } } /* Output */ if( stream->bufferProcessor.outputChannelCount > 0 ) { bytesToXfer = framesToXfer * stream->bytesPerOutputFrame; hresult = IDirectSoundBuffer_Lock ( stream->pDirectSoundOutputBuffer, stream->outputBufferWriteOffsetBytes, bytesToXfer, (void **) &lpOutBuf1, &dwOutSize1, (void **) &lpOutBuf2, &dwOutSize2, 0); if (hresult != DS_OK) { ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult)); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult ); goto error1; } numFrames = dwOutSize1 / stream->bytesPerOutputFrame; PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 ); /* Is output split into two regions. */ if( dwOutSize2 > 0 ) { numFrames = dwOutSize2 / stream->bytesPerOutputFrame; PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 ); } } result = paContinue; numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result ); stream->framesWritten += numFrames; if( stream->bufferProcessor.outputChannelCount > 0 ) { /* FIXME: an underflow could happen here */ /* Update our buffer offset and unlock sound buffer */ bytesProcessed = numFrames * stream->bytesPerOutputFrame; stream->outputBufferWriteOffsetBytes = (stream->outputBufferWriteOffsetBytes + bytesProcessed) % stream->outputBufferSizeBytes; IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2); stream->dsw_framesWritten += numFrames; } error1: if( stream->bufferProcessor.inputChannelCount > 0 ) { /* FIXME: an overflow could happen here */ /* Update our buffer offset and unlock sound buffer */ bytesProcessed = numFrames * stream->bytesPerInputFrame; stream->readOffset = (stream->readOffset + bytesProcessed) % stream->inputSize; IDirectSoundCaptureBuffer_Unlock( stream->pDirectSoundInputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2); } error2: PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames ); } return result; } /*******************************************************************/ static HRESULT ZeroAvailableOutputSpace( PaWinDsStream *stream ) { HRESULT hr; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; DWORD dwsize1 = 0; DWORD dwsize2 = 0; long bytesEmpty; hr = QueryOutputSpace( stream, &bytesEmpty ); // updates framesPlayed if (hr != DS_OK) return hr; if( bytesEmpty == 0 ) return DS_OK; // Lock free space in the DS hr = IDirectSoundBuffer_Lock( stream->pDirectSoundOutputBuffer, stream->outputBufferWriteOffsetBytes, bytesEmpty, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0); if (hr == DS_OK) { // Copy the buffer into the DS ZeroMemory(lpbuf1, dwsize1); if(lpbuf2 != NULL) { ZeroMemory(lpbuf2, dwsize2); } // Update our buffer offset and unlock sound buffer stream->outputBufferWriteOffsetBytes = (stream->outputBufferWriteOffsetBytes + dwsize1 + dwsize2) % stream->outputBufferSizeBytes; IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); stream->dsw_framesWritten += bytesEmpty / stream->bytesPerOutputFrame; } return hr; } static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD dw1, DWORD dw2) { PaWinDsStream *stream; /* suppress unused variable warnings */ (void) uID; (void) uMsg; (void) dw1; (void) dw2; stream = (PaWinDsStream *) dwUser; if( stream == NULL ) return; if( stream->isActive ) { if( stream->abortProcessing ) { stream->isActive = 0; } else if( stream->stopProcessing ) { if( stream->bufferProcessor.outputChannelCount > 0 ) { ZeroAvailableOutputSpace( stream ); /* clear isActive when all sound played */ if( stream->framesPlayed >= stream->framesWritten ) { stream->isActive = 0; } } else { stream->isActive = 0; } } else { if( Pa_TimeSlice( stream ) != 0) /* Call time slice independant of timing method. */ { /* FIXME implement handling of paComplete and paAbort if possible */ stream->stopProcessing = 1; } } if( !stream->isActive ) { if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } } } /*********************************************************************************** When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaWinDsStream *stream = (PaWinDsStream*)s; // Cleanup the sound buffers if( stream->pDirectSoundOutputBuffer ) { IDirectSoundBuffer_Stop( stream->pDirectSoundOutputBuffer ); IDirectSoundBuffer_Release( stream->pDirectSoundOutputBuffer ); stream->pDirectSoundOutputBuffer = NULL; } if( stream->pDirectSoundInputBuffer ) { IDirectSoundCaptureBuffer_Stop( stream->pDirectSoundInputBuffer ); IDirectSoundCaptureBuffer_Release( stream->pDirectSoundInputBuffer ); stream->pDirectSoundInputBuffer = NULL; } if( stream->pDirectSoundCapture ) { IDirectSoundCapture_Release( stream->pDirectSoundCapture ); stream->pDirectSoundCapture = NULL; } if( stream->pDirectSound ) { IDirectSound_Release( stream->pDirectSound ); stream->pDirectSound = NULL; } PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); return result; } /***********************************************************************************/ static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaWinDsStream *stream = (PaWinDsStream*)s; HRESULT hr; PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); if( stream->bufferProcessor.inputChannelCount > 0 ) { // Start the buffer playback if( stream->pDirectSoundInputBuffer != NULL ) // FIXME: not sure this check is necessary { hr = IDirectSoundCaptureBuffer_Start( stream->pDirectSoundInputBuffer, DSCBSTART_LOOPING ); } DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } } stream->framesWritten = 0; stream->callbackFlags = 0; stream->abortProcessing = 0; stream->stopProcessing = 0; stream->isActive = 1; if( stream->bufferProcessor.outputChannelCount > 0 ) { /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */ result = Pa_TimeSlice( stream ); if( result != paNoError ) return result; // FIXME - what if finished? QueryPerformanceCounter( &stream->previousPlayTime ); stream->previousPlayCursor = 0; stream->framesPlayed = 0; hr = IDirectSoundBuffer_SetCurrentPosition( stream->pDirectSoundOutputBuffer, 0 ); DBUG(("PaHost_StartOutput: IDirectSoundBuffer_SetCurrentPosition returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } // Start the buffer playback in a loop. if( stream->pDirectSoundOutputBuffer != NULL ) // FIXME: not sure this needs to be checked here { hr = IDirectSoundBuffer_Play( stream->pDirectSoundOutputBuffer, 0, 0, DSBPLAY_LOOPING ); DBUG(("PaHost_StartOutput: IDirectSoundBuffer_Play returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } stream->outputIsRunning = TRUE; } } /* Create timer that will wake us up so we can fill the DSound buffer. */ { int resolution; int framesPerWakeup = stream->framesPerDSBuffer / 4; int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate; if( msecPerWakeup < 10 ) msecPerWakeup = 10; else if( msecPerWakeup > 100 ) msecPerWakeup = 100; resolution = msecPerWakeup/4; stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback, (DWORD_PTR) stream, TIME_PERIODIC ); } if( stream->timerID == 0 ) { stream->isActive = 0; result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } stream->isStarted = TRUE; error: return result; } /***********************************************************************************/ static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaWinDsStream *stream = (PaWinDsStream*)s; HRESULT hr; int timeoutMsec; stream->stopProcessing = 1; /* Set timeout at 20% beyond maximum time we might wait. */ timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate); while( stream->isActive && (timeoutMsec > 0) ) { Sleep(10); timeoutMsec -= 10; } if( stream->timerID != 0 ) { timeKillEvent(stream->timerID); /* Stop callback timer. */ stream->timerID = 0; } if( stream->bufferProcessor.outputChannelCount > 0 ) { // Stop the buffer playback if( stream->pDirectSoundOutputBuffer != NULL ) { stream->outputIsRunning = FALSE; // FIXME: what happens if IDirectSoundBuffer_Stop returns an error? hr = IDirectSoundBuffer_Stop( stream->pDirectSoundOutputBuffer ); } } if( stream->bufferProcessor.inputChannelCount > 0 ) { // Stop the buffer capture if( stream->pDirectSoundInputBuffer != NULL ) { // FIXME: what happens if IDirectSoundCaptureBuffer_Stop returns an error? hr = IDirectSoundCaptureBuffer_Stop( stream->pDirectSoundInputBuffer ); } } stream->isStarted = FALSE; return result; } /***********************************************************************************/ static PaError AbortStream( PaStream *s ) { PaWinDsStream *stream = (PaWinDsStream*)s; stream->abortProcessing = 1; return StopStream( s ); } /***********************************************************************************/ static PaError IsStreamStopped( PaStream *s ) { PaWinDsStream *stream = (PaWinDsStream*)s; return !stream->isStarted; } /***********************************************************************************/ static PaError IsStreamActive( PaStream *s ) { PaWinDsStream *stream = (PaWinDsStream*)s; return stream->isActive; } /***********************************************************************************/ static PaTime GetStreamTime( PaStream *s ) { /* suppress unused variable warnings */ (void) s; return PaUtil_GetTime(); } /***********************************************************************************/ static double GetStreamCpuLoad( PaStream* s ) { PaWinDsStream *stream = (PaWinDsStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } /*********************************************************************************** As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError; } /***********************************************************************************/ static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError; } /***********************************************************************************/ static signed long GetStreamReadAvailable( PaStream* s ) { PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } /***********************************************************************************/ static signed long GetStreamWriteAvailable( PaStream* s ) { PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } nyquist-3.05/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.h0000644000175000000620000000633411466723256023611 0ustar stevestaff/* * Interface for dynamically loading directsound and providing a dummy * implementation if it isn't present. * * Author: Ross Bencina (some portions Phil Burk & Robert Marsanyi) * * For PortAudio Portable Real-Time Audio Library * For more information see: http://www.portaudio.com * Copyright (c) 1999-2006 Phil Burk, Robert Marsanyi and Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src */ #ifndef INCLUDED_PA_DSOUND_DYNLINK_H #define INCLUDED_PA_DSOUND_DYNLINK_H /* on Borland compilers, WIN32 doesn't seem to be defined by default, which breaks dsound.h. Adding the define here fixes the problem. - rossb. */ #ifdef __BORLANDC__ #if !defined(WIN32) #define WIN32 #endif #endif /* We are only using DX3 in here, no need to polute the namespace - davidv */ #define DIRECTSOUND_VERSION 0x0300 #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct { HINSTANCE hInstance_; HRESULT (WINAPI *DllGetClassObject)(REFCLSID , REFIID , LPVOID *); HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID); HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN); HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID); }PaWinDsDSoundEntryPoints; extern PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints; void PaWinDs_InitializeDSoundEntryPoints(void); void PaWinDs_TerminateDSoundEntryPoints(void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* INCLUDED_PA_DSOUND_DYNLINK_H */ nyquist-3.05/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.c0000644000175000000620000001745311466723256023610 0ustar stevestaff/* * Interface for dynamically loading directsound and providing a dummy * implementation if it isn't present. * * Author: Ross Bencina (some portions Phil Burk & Robert Marsanyi) * * For PortAudio Portable Real-Time Audio Library * For more information see: http://www.portaudio.com * Copyright (c) 1999-2006 Phil Burk, Robert Marsanyi and Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src */ #include "pa_win_ds_dynlink.h" PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 }; static HRESULT WINAPI DummyDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { (void)rclsid; /* unused parameter */ (void)riid; /* unused parameter */ (void)ppv; /* unused parameter */ return CLASS_E_CLASSNOTAVAILABLE; } static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter) { (void)lpcGuidDevice; /* unused parameter */ (void)ppDS; /* unused parameter */ (void)pUnkOuter; /* unused parameter */ return E_NOTIMPL; } static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext) { (void)lpDSEnumCallback; /* unused parameter */ (void)lpContext; /* unused parameter */ return E_NOTIMPL; } static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext) { (void)lpDSEnumCallback; /* unused parameter */ (void)lpContext; /* unused parameter */ return E_NOTIMPL; } static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) { (void)lpcGUID; /* unused parameter */ (void)lplpDSC; /* unused parameter */ (void)pUnkOuter; /* unused parameter */ return E_NOTIMPL; } static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext) { (void)lpDSCEnumCallback; /* unused parameter */ (void)lpContext; /* unused parameter */ return E_NOTIMPL; } static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext) { (void)lpDSCEnumCallback; /* unused parameter */ (void)lpContext; /* unused parameter */ return E_NOTIMPL; } void PaWinDs_InitializeDSoundEntryPoints(void) { paWinDsDSoundEntryPoints.hInstance_ = LoadLibrary("dsound.dll"); if( paWinDsDSoundEntryPoints.hInstance_ != NULL ) { paWinDsDSoundEntryPoints.DllGetClassObject = (HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DllGetClassObject" ); if( paWinDsDSoundEntryPoints.DllGetClassObject == NULL ) paWinDsDSoundEntryPoints.DllGetClassObject = DummyDllGetClassObject; paWinDsDSoundEntryPoints.DirectSoundCreate = (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCreate" ); if( paWinDsDSoundEntryPoints.DirectSoundCreate == NULL ) paWinDsDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate; paWinDsDSoundEntryPoints.DirectSoundEnumerateW = (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" ); if( paWinDsDSoundEntryPoints.DirectSoundEnumerateW == NULL ) paWinDsDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW; paWinDsDSoundEntryPoints.DirectSoundEnumerateA = (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" ); if( paWinDsDSoundEntryPoints.DirectSoundEnumerateA == NULL ) paWinDsDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA; paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" ); if( paWinDsDSoundEntryPoints.DirectSoundCaptureCreate == NULL ) paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" ); if( paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL ) paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" ); if( paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL ) paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA; } else { /* initialize with dummy entry points to make live easy when ds isn't present */ paWinDsDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate; paWinDsDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW; paWinDsDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA; paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA; } } void PaWinDs_TerminateDSoundEntryPoints(void) { if( paWinDsDSoundEntryPoints.hInstance_ != NULL ) { /* ensure that we crash reliably if the entry points arent initialised */ paWinDsDSoundEntryPoints.DirectSoundCreate = 0; paWinDsDSoundEntryPoints.DirectSoundEnumerateW = 0; paWinDsDSoundEntryPoints.DirectSoundEnumerateA = 0; paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = 0; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0; paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0; FreeLibrary( paWinDsDSoundEntryPoints.hInstance_ ); paWinDsDSoundEntryPoints.hInstance_ = NULL; } }nyquist-3.05/portaudio/src/hostapi/alsa/0002755000175000000620000000000011537433131017352 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/alsa/pa_linux_alsa.c0000644000175000000620000036764311466723256022371 0ustar stevestaff/* * $Id: pa_linux_alsa.c,v 1.1 2010/11/04 21:04:36 rbd Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * ALSA implementation by Joshua Haberman and Arve Knudsen * * Copyright (c) 2002 Joshua Haberman * Copyright (c) 2005-2007 Arve Knudsen * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostapi_src */ #define ALSA_PCM_NEW_HW_PARAMS_API #define ALSA_PCM_NEW_SW_PARAMS_API #include #undef ALSA_PCM_NEW_HW_PARAMS_API #undef ALSA_PCM_NEW_SW_PARAMS_API #include #include /* strlen() */ #include #include #include #include #include #include #include /* For sig_atomic_t */ #include "portaudio.h" #include "pa_util.h" #include "pa_unix_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_endianness.h" #include "pa_debugprint.h" #include "pa_linux_alsa.h" /* Check return value of ALSA function, and map it to PaError */ #define ENSURE_(expr, code) \ do { \ if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \ { \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), paUnixMainThread) ) \ { \ PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \ } \ PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ if( (code) == paUnanticipatedHostError ) \ PA_DEBUG(( "Host error description: %s\n", snd_strerror( aErr_ ) )); \ result = (code); \ goto error; \ } \ } while( 0 ); #define ASSERT_CALL_(expr, success) \ aErr_ = (expr); \ assert( success == aErr_ ); static int aErr_; /* Used with ENSURE_ */ static int numPeriods_ = 4; int PaAlsa_SetNumPeriods( int numPeriods ) { numPeriods_ = numPeriods; return paNoError; } typedef enum { StreamDirection_In, StreamDirection_Out } StreamDirection; typedef struct { PaSampleFormat hostSampleFormat; unsigned long framesPerBuffer; int numUserChannels, numHostChannels; int userInterleaved, hostInterleaved; PaDeviceIndex device; /* Keep the device index */ snd_pcm_t *pcm; snd_pcm_uframes_t bufferSize; snd_pcm_format_t nativeFormat; unsigned int nfds; int ready; /* Marked ready from poll */ void **userBuffers; snd_pcm_uframes_t offset; StreamDirection streamDir; snd_pcm_channel_area_t *channelAreas; /* Needed for channel adaption */ } PaAlsaStreamComponent; /* Implementation specific stream structure */ typedef struct PaAlsaStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaUnixThread thread; unsigned long framesPerUserBuffer, maxFramesPerHostBuffer; int primeBuffers; int callbackMode; /* bool: are we running in callback mode? */ int pcmsSynced; /* Have we successfully synced pcms */ int rtSched; /* the callback thread uses these to poll the sound device(s), waiting * for data to be ready/available */ struct pollfd* pfds; int pollTimeout; /* Used in communication between threads */ volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */ volatile sig_atomic_t callbackAbort; /* Drop frames? */ volatile sig_atomic_t isActive; /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */ PaUnixMutex stateMtx; /* Used to synchronize access to stream state */ int neverDropInput; PaTime underrun; PaTime overrun; PaAlsaStreamComponent capture, playback; } PaAlsaStream; /* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct PaAlsaHostApiRepresentation { PaUtilHostApiRepresentation baseHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; PaHostApiIndex hostApiIndex; } PaAlsaHostApiRepresentation; typedef struct PaAlsaDeviceInfo { PaDeviceInfo baseDeviceInfo; char *alsaName; int isPlug; int minInputChannels; int minOutputChannels; } PaAlsaDeviceInfo; /* prototypes for functions declared in this file */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *callback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi ); static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ); static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ); /* Callback prototypes */ static void *CallbackThreadFunc( void *userData ); /* Blocking prototypes */ static signed long GetStreamReadAvailable( PaStream* s ); static signed long GetStreamWriteAvailable( PaStream* s ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device ) { return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device]; } static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...) { } PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; PaAlsaHostApiRepresentation *alsaHostApi = NULL; PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory ); PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); alsaHostApi->hostApiIndex = hostApiIndex; *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paALSA; (*hostApi)->info.name = "ALSA"; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError ); PA_ENSURE( BuildDeviceList( alsaHostApi ) ); PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); PA_ENSURE( PaUnixThreading_Initialize() ); return result; error: if( alsaHostApi ) { if( alsaHostApi->allocations ) { PaUtil_FreeAllAllocations( alsaHostApi->allocations ); PaUtil_DestroyAllocationGroup( alsaHostApi->allocations ); } PaUtil_FreeMemory( alsaHostApi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; assert( hostApi ); if( alsaHostApi->allocations ) { PaUtil_FreeAllAllocations( alsaHostApi->allocations ); PaUtil_DestroyAllocationGroup( alsaHostApi->allocations ); } PaUtil_FreeMemory( alsaHostApi ); snd_config_update_free_global(); } /** Determine max channels and default latencies. * * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero, * and a suitable result returned. The device is closed before returning. */ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking, PaAlsaDeviceInfo* devInfo, int* canMmap ) { PaError result = paNoError; snd_pcm_hw_params_t *hwParams; snd_pcm_uframes_t lowLatency = 512, highLatency = 2048; unsigned int minChans, maxChans; int* minChannels, * maxChannels; double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate = &devInfo->baseDeviceInfo.defaultSampleRate; double defaultSr = *defaultSampleRate; assert( pcm ); if( StreamDirection_In == mode ) { minChannels = &devInfo->minInputChannels; maxChannels = &devInfo->baseDeviceInfo.maxInputChannels; defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowInputLatency; defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighInputLatency; } else { minChannels = &devInfo->minOutputChannels; maxChannels = &devInfo->baseDeviceInfo.maxOutputChannels; defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowOutputLatency; defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency; } ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError ); snd_pcm_hw_params_alloca( &hwParams ); snd_pcm_hw_params_any( pcm, hwParams ); *canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED ) >= 0 || snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED ) >= 0; if( defaultSr >= 0 ) { /* Could be that the device opened in one mode supports samplerates that the other mode wont have, * so try again .. */ if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 ) { defaultSr = -1.; PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ )); } } if( defaultSr < 0. ) /* Default sample rate not set */ { unsigned int sampleRate = 44100; /* Will contain approximate rate returned by alsa-lib */ if( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0) { result = paUnanticipatedHostError; goto error; } ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError ); } ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError ); assert( maxChans <= INT_MAX ); assert( maxChans > 0 ); /* Weird linking issue could cause wrong version of ALSA symbols to be called, resulting in zeroed values */ /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */ if( isPlug && maxChans > 128 ) { maxChans = 128; PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans )); } /* TWEAKME: * * Giving values for default min and max latency is not * straightforward. Here are our objectives: * * * for low latency, we want to give the lowest value * that will work reliably. This varies based on the * sound card, kernel, CPU, etc. I think it is better * to give sub-optimal latency than to give a number * too low and cause dropouts. My conservative * estimate at this point is to base it on 4096-sample * latency at 44.1 kHz, which gives a latency of 23ms. * * for high latency we want to give a large enough * value that dropouts are basically impossible. This * doesn't really require as much tweaking, since * providing too large a number will just cause us to * select the nearest setting that will work at stream * config time. */ ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError ); /* Have to reset hwParams, to set new buffer size */ ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError ); *minChannels = (int)minChans; *maxChannels = (int)maxChans; *defaultSampleRate = defaultSr; *defaultLowLatency = (double) lowLatency / *defaultSampleRate; *defaultHighLatency = (double) highLatency / *defaultSampleRate; end: snd_pcm_close( pcm ); return result; error: goto end; } /* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate * wether input/output is available) */ static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo ) { deviceInfo->structVersion = -1; deviceInfo->name = NULL; deviceInfo->hostApi = -1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->defaultLowInputLatency = -1.; deviceInfo->defaultLowOutputLatency = -1.; deviceInfo->defaultHighInputLatency = -1.; deviceInfo->defaultHighOutputLatency = -1.; deviceInfo->defaultSampleRate = -1.; } /* Helper struct */ typedef struct { char *alsaName; char *name; int isPlug; int hasPlayback; int hasCapture; } HwDevInfo; HwDevInfo predefinedNames[] = { { "center_lfe", NULL, 0, 1, 0 }, /* { "default", NULL, 0, 1, 0 }, */ /* { "dmix", NULL, 0, 1, 0 }, */ /* { "dpl", NULL, 0, 1, 0 }, */ /* { "dsnoop", NULL, 0, 1, 0 }, */ { "front", NULL, 0, 1, 0 }, { "iec958", NULL, 0, 1, 0 }, /* { "modem", NULL, 0, 1, 0 }, */ { "rear", NULL, 0, 1, 0 }, { "side", NULL, 0, 1, 0 }, /* { "spdif", NULL, 0, 0, 0 }, */ { "surround40", NULL, 0, 1, 0 }, { "surround41", NULL, 0, 1, 0 }, { "surround50", NULL, 0, 1, 0 }, { "surround51", NULL, 0, 1, 0 }, { "surround71", NULL, 0, 1, 0 }, { NULL, NULL, 0, 1, 0 } }; static const HwDevInfo *FindDeviceName( const char *name ) { int i; for( i = 0; predefinedNames[i].alsaName; i++ ) { if( strcmp( name, predefinedNames[i].alsaName ) == 0 ) { return &predefinedNames[i]; } } return NULL; } static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi, char **dst, const char *src) { PaError result = paNoError; int len = strlen( src ) + 1; /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */ PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), paInsufficientMemory ); strncpy( *dst, src, len ); error: return result; } /* Disregard some standard plugins */ static int IgnorePlugin( const char *pluginId ) { static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee", "file", "null", "shm", "cards", "rate_convert", NULL}; int i = 0; while( ignoredPlugins[i] ) { if( !strcmp( pluginId, ignoredPlugins[i] ) ) { return 1; } ++i; } return 0; } /** Open PCM device. * * Wrapper around snd_pcm_open which may repeatedly retry opening a device if it is busy, for * a certain time. This is because dmix may temporarily hold on to a device after it (dmix) * has been opened and closed. * @param mode: Open mode (e.g., SND_PCM_BLOCKING). * @param waitOnBusy: Retry opening busy device for up to one second? **/ static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy ) { int tries = 0, maxTries = waitOnBusy ? 100 : 0; int ret = snd_pcm_open( pcmp, name, stream, mode ); for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries ) { Pa_Sleep( 10 ); ret = snd_pcm_open( pcmp, name, stream, mode ); if( -EBUSY != ret ) { PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", __FUNCTION__, tries )); } } if( -EBUSY == ret ) { PA_DEBUG(( "%s: Failed to open busy device '%s'\n", __FUNCTION__, name )); } return ret; } static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking, PaAlsaDeviceInfo* devInfo, int* devIdx ) { PaError result = 0; PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo; snd_pcm_t *pcm; int canMmap = -1; PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; /* Zero fields */ InitializeDeviceInfo( baseDeviceInfo ); /* to determine device capabilities, we must open the device and query the * hardware parameter configuration space */ /* Query capture */ if( deviceName->hasCapture && OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) >= 0 ) { if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo, &canMmap ) != paNoError ) { /* Error */ PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName)); goto end; } } /* Query playback */ if( deviceName->hasPlayback && OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) >= 0 ) { if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo, &canMmap ) != paNoError ) { /* Error */ PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName)); goto end; } } if( 0 == canMmap ) { PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceName->alsaName)); goto end; } baseDeviceInfo->structVersion = 2; baseDeviceInfo->hostApi = alsaApi->hostApiIndex; baseDeviceInfo->name = deviceName->name; devInfo->alsaName = deviceName->alsaName; devInfo->isPlug = deviceName->isPlug; /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object. * Should now be safe to add device info, unless the device supports neither capture nor playback */ if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 ) { /* Make device default if there isn't already one or it is the ALSA "default" device */ if( (baseApi->info.defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName, "default" )) && baseDeviceInfo->maxInputChannels > 0 ) { baseApi->info.defaultInputDevice = *devIdx; PA_DEBUG(("Default input device: %s\n", deviceName->name)); } if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName, "default" )) && baseDeviceInfo->maxOutputChannels > 0 ) { baseApi->info.defaultOutputDevice = *devIdx; PA_DEBUG(("Default output device: %s\n", deviceName->name)); } PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx)); baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo; (*devIdx) += 1; } end: return result; } /* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) { PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; PaAlsaDeviceInfo *deviceInfoArray; int cardIdx = -1, devIdx = 0; snd_ctl_card_info_t *cardInfo; PaError result = paNoError; size_t numDeviceNames = 0, maxDeviceNames = 1, i; HwDevInfo *hwDevInfos = NULL; snd_config_t *topNode = NULL; snd_pcm_info_t *pcmInfo; int res; int blocking = SND_PCM_NONBLOCK; char alsaCardName[50]; #ifdef PA_ENABLE_DEBUG_OUTPUT PaTime startTime = PaUtil_GetTime(); #endif if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) ) blocking = 0; /* These two will be set to the first working input and output device, respectively */ baseApi->info.defaultInputDevice = paNoDevice; baseApi->info.defaultOutputDevice = paNoDevice; /* Gather info about hw devices * snd_card_next() modifies the integer passed to it to be: * the index of the first card if the parameter is -1 * the index of the next card if the parameter is the index of a card * -1 if there are no more cards * * The function itself returns 0 if it succeeded. */ cardIdx = -1; snd_ctl_card_info_alloca( &cardInfo ); snd_pcm_info_alloca( &pcmInfo ); while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) { char *cardName; int devIdx = -1; snd_ctl_t *ctl; char buf[50]; snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx ); /* Acquire name of card */ if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 ) { /* Unable to open card :( */ PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName )); continue; } snd_ctl_card_info( ctl, cardInfo ); PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) ); while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 ) { char *alsaDeviceName, *deviceName; size_t len; int hasPlayback = 0, hasCapture = 0; snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx ); /* Obtain info about this particular device */ snd_pcm_info_set_device( pcmInfo, devIdx ); snd_pcm_info_set_subdevice( pcmInfo, 0 ); snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE ); if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) { hasCapture = 1; } snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK ); if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) { hasPlayback = 1; } if( !hasPlayback && !hasCapture ) { /* Error */ continue; } /* The length of the string written by snprintf plus terminating 0 */ len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1; PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), paInsufficientMemory ); snprintf( deviceName, len, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ); ++numDeviceNames; if( !hwDevInfos || numDeviceNames > maxDeviceNames ) { maxDeviceNames *= 2; PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ), paInsufficientMemory ); } PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) ); hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName; hwDevInfos[ numDeviceNames - 1 ].name = deviceName; hwDevInfos[ numDeviceNames - 1 ].isPlug = 0; hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback; hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture; } snd_ctl_close( ctl ); } /* Iterate over plugin devices */ if( NULL == snd_config ) { /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */ ENSURE_( snd_config_update(), paUnanticipatedHostError ); PA_DEBUG(( "Updating snd_config\n" )); } assert( snd_config ); if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 ) { snd_config_iterator_t i, next; snd_config_for_each( i, next, topNode ) { const char *tpStr = "unknown", *idStr = NULL; int err = 0; char *alsaDeviceName, *deviceName; const HwDevInfo *predefined = NULL; snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;; if( (err = snd_config_search( n, "type", &tp )) < 0 ) { if( -ENOENT != err ) { ENSURE_(err, paUnanticipatedHostError); } } else { ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError ); } ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError ); if( IgnorePlugin( idStr ) ) { PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr )); continue; } PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr )); PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, strlen(idStr) + 6 ), paInsufficientMemory ); strcpy( alsaDeviceName, idStr ); PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, strlen(idStr) + 1 ), paInsufficientMemory ); strcpy( deviceName, idStr ); ++numDeviceNames; if( !hwDevInfos || numDeviceNames > maxDeviceNames ) { maxDeviceNames *= 2; PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ), paInsufficientMemory ); } predefined = FindDeviceName( alsaDeviceName ); hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName; hwDevInfos[numDeviceNames - 1].name = deviceName; hwDevInfos[numDeviceNames - 1].isPlug = 1; if( predefined ) { hwDevInfos[numDeviceNames - 1].hasPlayback = predefined->hasPlayback; hwDevInfos[numDeviceNames - 1].hasCapture = predefined->hasCapture; } else { hwDevInfos[numDeviceNames - 1].hasPlayback = 1; hwDevInfos[numDeviceNames - 1].hasCapture = 1; } } } else PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) )); /* allocate deviceInfo memory based on the number of devices */ PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory ); /* allocate all device info structs in a contiguous block */ PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory ); /* Loop over list of cards, filling in info. If a device is deemed unavailable (can't get name), * it's ignored. * * Note that we do this in two stages. This is a workaround owing to the fact that the 'dmix' * plugin may cause the underlying hardware device to be busy for a short while even after it * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes * for this. */ for( i = 0, devIdx = 0; i < numDeviceNames; ++i ) { PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i]; HwDevInfo* hwInfo = &hwDevInfos[i]; if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) ) { continue; } PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) ); } assert( devIdx < numDeviceNames ); /* Now inspect 'dmix' and 'default' plugins */ for( i = 0; i < numDeviceNames; ++i ) { PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i]; HwDevInfo* hwInfo = &hwDevInfos[i]; if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) ) { continue; } PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) ); } free( hwDevInfos ); baseApi->info.deviceCount = devIdx; /* Number of successfully queried devices */ #ifdef PA_ENABLE_DEBUG_OUTPUT PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime )); #endif end: return result; error: /* No particular action */ goto end; } /* Check against known device capabilities */ static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode ) { PaError result = paNoError; int maxChans; const PaAlsaDeviceInfo *deviceInfo = NULL; assert( parameters ); if( parameters->device != paUseHostApiSpecificDeviceSpecification ) { assert( parameters->device < hostApi->info.deviceCount ); PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination ); deviceInfo = GetDeviceInfo( hostApi, parameters->device ); } else { const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo; PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice ); PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1, paIncompatibleHostApiSpecificStreamInfo ); PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice ); /* Skip further checking */ return paNoError; } assert( deviceInfo ); assert( parameters->hostApiSpecificStreamInfo == NULL ); maxChans = (StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels : deviceInfo->baseDeviceInfo.maxOutputChannels); PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount ); error: return result; } /* Given an open stream, what sample formats are available? */ static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm ) { PaSampleFormat available = 0; snd_pcm_hw_params_t *hwParams; snd_pcm_hw_params_alloca( &hwParams ); snd_pcm_hw_params_any( pcm, hwParams ); if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0) available |= paFloat32; if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0) available |= paInt32; #ifdef PA_LITTLE_ENDIAN if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0) available |= paInt24; #elif defined PA_BIG_ENDIAN if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0) available |= paInt24; #endif if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0) available |= paInt16; if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0) available |= paUInt8; if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) available |= paInt8; return available; } static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat ) { switch( paFormat ) { case paFloat32: return SND_PCM_FORMAT_FLOAT; case paInt16: return SND_PCM_FORMAT_S16; case paInt24: #ifdef PA_LITTLE_ENDIAN return SND_PCM_FORMAT_S24_3LE; #elif defined PA_BIG_ENDIAN return SND_PCM_FORMAT_S24_3BE; #endif case paInt32: return SND_PCM_FORMAT_S32; case paInt8: return SND_PCM_FORMAT_S8; case paUInt8: return SND_PCM_FORMAT_U8; default: return SND_PCM_FORMAT_UNKNOWN; } } /** Open an ALSA pcm handle. * * The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a * device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin * device. */ static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection streamDir, snd_pcm_t **pcm ) { PaError result = paNoError; int ret; char dnameArray[50]; const char* deviceName = dnameArray; const PaAlsaDeviceInfo *deviceInfo = NULL; PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo; if( !streamInfo ) { int usePlug = 0; deviceInfo = GetDeviceInfo( hostApi, params->device ); /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */ if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) ) usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) ); if( usePlug ) snprintf( dnameArray, 50, "plug%s", deviceInfo->alsaName ); else deviceName = deviceInfo->alsaName; } else deviceName = streamInfo->deviceString; PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName )); if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK, 1 )) < 0 ) { /* Not to be closed */ *pcm = NULL; ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination ); } ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError ); end: return result; error: goto end; } static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters, double sampleRate, StreamDirection streamDir ) { PaError result = paNoError; snd_pcm_t *pcm = NULL; PaSampleFormat availableFormats; /* We are able to adapt to a number of channels less than what the device supports */ unsigned int numHostChannels; PaSampleFormat hostFormat; snd_pcm_hw_params_t *hwParams; snd_pcm_hw_params_alloca( &hwParams ); if( !parameters->hostApiSpecificStreamInfo ) { const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device ); numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels : devInfo->minOutputChannels ); } else numHostChannels = parameters->channelCount; PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) ); snd_pcm_hw_params_any( pcm, hwParams ); if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 ) { result = paInvalidSampleRate; goto error; } if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 ) { result = paInvalidChannelCount; goto error; } /* See if we can find a best possible match */ availableFormats = GetAvailableFormats( pcm ); PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) ); ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError ); { /* It happens that this call fails because the device is busy */ int ret = 0; if( (ret = snd_pcm_hw_params( pcm, hwParams )) < 0) { if( -EINVAL == ret ) { /* Don't know what to return here */ result = paBadIODeviceCombination; goto error; } else if( -EBUSY == ret ) { result = paDeviceUnavailable; PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ )); } else { result = paUnanticipatedHostError; } ENSURE_( ret, result ); } } end: if( pcm ) { snd_pcm_close( pcm ); } return result; error: goto end; } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { int inputChannelCount = 0, outputChannelCount = 0; PaSampleFormat inputSampleFormat, outputSampleFormat; PaError result = paFormatIsSupported; if( inputParameters ) { PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) ); inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; } if( outputParameters ) { PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) ); outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; } if( inputChannelCount ) { if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In )) != paNoError ) goto error; } if ( outputChannelCount ) { if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out )) != paNoError ) goto error; } return paFormatIsSupported; error: return result; } static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *params, StreamDirection streamDir, int callbackMode ) { PaError result = paNoError; PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat; assert( params->channelCount > 0 ); /* Make sure things have an initial value */ memset( self, 0, sizeof (PaAlsaStreamComponent) ); if( NULL == params->hostApiSpecificStreamInfo ) { const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device ); self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels : devInfo->minOutputChannels ); } else { /* We're blissfully unaware of the minimum channelCount */ self->numHostChannels = params->channelCount; } self->device = params->device; PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) ); self->nfds = snd_pcm_poll_descriptors_count( self->pcm ); hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat ); self->hostSampleFormat = hostSampleFormat; self->nativeFormat = Pa2AlsaFormat( hostSampleFormat ); self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved); self->numUserChannels = params->channelCount; self->streamDir = streamDir; if( !callbackMode && !self->userInterleaved ) { /* Pre-allocate non-interleaved user provided buffers */ PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ), paInsufficientMemory ); } error: return result; } static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self ) { snd_pcm_close( self->pcm ); if( self->userBuffers ) PaUtil_FreeMemory( self->userBuffers ); } /* static int nearbyint_(float value) { if( value - (int)value > .5 ) return (int)ceil( value ); return (int)floor( value ); } */ /** Initiate configuration, preparing for determining a period size suitable for both capture and playback components. * */ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *self, const PaStreamParameters *params, int primeBuffers, snd_pcm_hw_params_t *hwParams, double *sampleRate ) { /* Configuration consists of setting all of ALSA's parameters. * These parameters come in two flavors: hardware parameters * and software paramters. Hardware parameters will affect * the way the device is initialized, software parameters * affect the way ALSA interacts with me, the user-level client. */ PaError result = paNoError; snd_pcm_access_t accessMode, alternateAccessMode; int dir = 0; snd_pcm_t *pcm = self->pcm; double sr = *sampleRate; unsigned int minPeriods = 2; /* self->framesPerBuffer = framesPerHostBuffer; */ /* ... fill up the configuration space with all possibile * combinations of parameters this device will accept */ ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError ); /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */ dir = 0; ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); if( self->userInterleaved ) { accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; } else { accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; } /* If requested access mode fails, try alternate mode */ if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) { int err = 0; if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0) { result = paUnanticipatedHostError; if( -EINVAL == err ) { PaUtil_SetLastHostErrorInfo( paALSA, err, "PA ALSA requires that a device supports mmap access" ); } else { PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) ); } goto error; } /* Flip mode */ self->hostInterleaved = !self->userInterleaved; } ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate ); ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError ); /* reject if there's no sample rate within 1% of the one requested */ if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 ) { PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr )); PA_ENSURE( paInvalidSampleRate ); } ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount ); *sampleRate = sr; end: return result; error: /* No particular action */ goto end; } /** Finish the configuration of the component's ALSA device. * * As part of this method, the component's bufferSize attribute will be set. * @param latency: The latency for this component. */ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams, const PaStreamParameters *params, int primeBuffers, double sampleRate, PaTime* latency ) { PaError result = paNoError; snd_pcm_sw_params_t* swParams; snd_pcm_uframes_t bufSz = 0; *latency = -1.; snd_pcm_sw_params_alloca( &swParams ); bufSz = params->suggestedLatency * sampleRate; ENSURE_( snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError ); /* Set the parameters! */ { int r = snd_pcm_hw_params( self->pcm, hwParams ); #ifdef PA_ENABLE_DEBUG_OUTPUT if( r < 0 ) { snd_output_t *output = NULL; snd_output_stdio_attach( &output, stderr, 0 ); snd_pcm_hw_params_dump( hwParams, output ); } #endif ENSURE_(r, paUnanticipatedHostError ); } ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError ); /* Latency in seconds */ *latency = self->bufferSize / sampleRate; /* Now software parameters... */ ENSURE_( snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError ); ENSURE_( snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); ENSURE_( snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError ); /* Silence buffer in the case of underrun */ if( !primeBuffers ) /* XXX: Make sense? */ { snd_pcm_uframes_t boundary; ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError ); ENSURE_( snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError ); ENSURE_( snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError ); } ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError ); /* Set the parameters! */ ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); error: return result; } static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams, const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback, PaStreamFlags streamFlags, void *userData ) { PaError result = paNoError; assert( self ); memset( self, 0, sizeof (PaAlsaStream) ); if( NULL != callback ) { PaUtil_InitializeStreamRepresentation( &self->streamRepresentation, &alsaApi->callbackStreamInterface, callback, userData ); self->callbackMode = 1; } else { PaUtil_InitializeStreamRepresentation( &self->streamRepresentation, &alsaApi->blockingStreamInterface, NULL, userData ); } self->framesPerUserBuffer = framesPerUserBuffer; self->neverDropInput = streamFlags & paNeverDropInput; /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */ /* if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback ) self->primeBuffers = 1; */ memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) ); memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) ); if( inParams ) { PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) ); } if( outParams ) { PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) ); } assert( self->capture.nfds || self->playback.nfds ); PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds + self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory ); PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate ); ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError ); error: return result; } /** Free resources associated with stream, and eventually stream itself. * * Frees allocated memory, and terminates individual StreamComponents. */ static void PaAlsaStream_Terminate( PaAlsaStream *self ) { assert( self ); if( self->capture.pcm ) { PaAlsaStreamComponent_Terminate( &self->capture ); } if( self->playback.pcm ) { PaAlsaStreamComponent_Terminate( &self->playback ); } PaUtil_FreeMemory( self->pfds ); ASSERT_CALL_( PaUnixMutex_Terminate( &self->stateMtx ), paNoError ); PaUtil_FreeMemory( self ); } /** Calculate polling timeout * * @param frames Time to wait * @return Polling timeout in milliseconds */ static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames ) { assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 ); /* Period in msecs, rounded up */ return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate ); } /** Determine size per host buffer. * * During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size * gets configured for the device. * @param accurate: If the configured period size is non-integer, this will be set to 0. */ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params, unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate ) { PaError result = paNoError; unsigned long bufferSize = params->suggestedLatency * sampleRate, framesPerHostBuffer; int dir = 0; { snd_pcm_uframes_t tmp; snd_pcm_hw_params_get_buffer_size_min( hwParams, &tmp ); bufferSize = PA_MAX( bufferSize, tmp ); snd_pcm_hw_params_get_buffer_size_max( hwParams, &tmp ); bufferSize = PA_MIN( bufferSize, tmp ); } assert( bufferSize > 0 ); if( framesPerUserBuffer != paFramesPerBufferUnspecified ) { /* Preferably the host buffer size should be a multiple of the user buffer size */ if( bufferSize > framesPerUserBuffer ) { snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer; if( remainder > framesPerUserBuffer / 2. ) bufferSize += framesPerUserBuffer - remainder; else bufferSize -= remainder; assert( bufferSize % framesPerUserBuffer == 0 ); } else if( framesPerUserBuffer % bufferSize != 0 ) { /* Find a good compromise between user specified latency and buffer size */ if( bufferSize > framesPerUserBuffer * .75 ) { bufferSize = framesPerUserBuffer; } else { snd_pcm_uframes_t newSz = framesPerUserBuffer; while( newSz / 2 >= bufferSize ) { if( framesPerUserBuffer % (newSz / 2) != 0 ) { /* No use dividing any further */ break; } newSz /= 2; } bufferSize = newSz; } assert( framesPerUserBuffer % bufferSize == 0 ); } } /* Using the base number of periods, we try to approximate the suggested latency (+1 period), finding a combination of period/buffer size which best fits these constraints */ { unsigned numPeriods = numPeriods_, maxPeriods = 0; /* It may be that the device only supports 2 periods for instance */ dir = 0; ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError ); assert( maxPeriods > 1 ); numPeriods = PA_MIN( maxPeriods, numPeriods ); if( framesPerUserBuffer != paFramesPerBufferUnspecified ) { /* Try to get a power-of-two of the user buffer size. */ framesPerHostBuffer = framesPerUserBuffer; if( framesPerHostBuffer < bufferSize ) { while( bufferSize / framesPerHostBuffer > numPeriods ) { framesPerHostBuffer *= 2; } /* One extra period is preferrable to one less (should be more robust) */ if( bufferSize / framesPerHostBuffer < numPeriods ) { framesPerHostBuffer /= 2; } } else { while( bufferSize / framesPerHostBuffer < numPeriods ) { if( framesPerUserBuffer % (framesPerHostBuffer / 2) != 0 ) { /* Can't be divided any further */ break; } framesPerHostBuffer /= 2; } } if( framesPerHostBuffer < framesPerUserBuffer ) { assert( framesPerUserBuffer % framesPerHostBuffer == 0 ); if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) { if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) framesPerHostBuffer *= 2; else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) framesPerHostBuffer /= 2; } } else { assert( framesPerHostBuffer % framesPerUserBuffer == 0 ); if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) { if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer += framesPerUserBuffer; else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer -= framesPerUserBuffer; } } } else { framesPerHostBuffer = bufferSize / numPeriods; } } assert( framesPerHostBuffer > 0 ); { snd_pcm_uframes_t min = 0, max = 0; ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError ); if( framesPerHostBuffer < min ) { PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__, framesPerHostBuffer, min )); framesPerHostBuffer = min; } else if( framesPerHostBuffer > max ) { PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__, framesPerHostBuffer, max )); framesPerHostBuffer = max; } assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max ); dir = 0; ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError ); if( dir != 0 ) { PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir )); *accurate = 0; } } self->framesPerBuffer = framesPerHostBuffer; error: return result; } /* We need to determine how many frames per host buffer (period) to use. Our * goals are to provide the best possible performance, but also to * honor the requested latency settings as closely as we can. Therefore this * decision is based on: * * - the period sizes that playback and/or capture support. The * host buffer size has to be one of these. * - the number of periods that playback and/or capture support. * * We want to make period_size*(num_periods-1) to be as close as possible * to latency*rate for both playback and capture. * * This method will determine suitable period sizes for capture and playback handles, and report the maximum number of * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size, * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size, * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size. * * The framesPerBuffer attributes of the individual capture and playback components of the stream are set to corresponding * values determined here. Since these should be reported as * * This is one of those blocks of code that will just take a lot of * refinement to be any good. * * In the full-duplex case it is possible that the routine was unable * to find a number of frames per buffer acceptable to both devices * TODO: Implement an algorithm to find the value closest to acceptance * by both devices, to minimize difference between period sizes? * * @param determinedFramesPerHostBuffer: The determined host buffer size. */ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters, const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture, snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode ) { PaError result = paNoError; unsigned long framesPerHostBuffer = 0; int dir = 0; int accurate = 1; unsigned numPeriods = numPeriods_; if( self->capture.pcm && self->playback.pcm ) { if( framesPerUserBuffer == paFramesPerBufferUnspecified ) { /* Come up with a common desired latency */ snd_pcm_uframes_t desiredBufSz, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize, minCapture, minPlayback, maxCapture, maxPlayback; dir = 0; ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError ); dir = 0; ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError ); dir = 0; ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError ); dir = 0; ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError ); minPeriodSize = PA_MAX( minPlayback, minCapture ); maxPeriodSize = PA_MIN( maxPlayback, maxCapture ); PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination ); desiredBufSz = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency ) * sampleRate); /* Clamp desiredBufSz */ { snd_pcm_uframes_t maxBufferSize; snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback; ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError ); maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback ); desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize ); } /* Find the closest power of 2 */ e = ilogb( minPeriodSize ); if( minPeriodSize & (minPeriodSize - 1) ) e += 1; periodSize = (snd_pcm_uframes_t)pow( 2, e ); while( periodSize <= maxPeriodSize ) { if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 && snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 ) { /* OK! */ break; } periodSize *= 2; } optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize ); optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize ); /* Find the closest power of 2 */ e = ilogb( optimalPeriodSize ); if( optimalPeriodSize & (optimalPeriodSize - 1) ) e += 1; optimalPeriodSize = (snd_pcm_uframes_t)pow( 2, e ); while( optimalPeriodSize >= periodSize ) { if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) >= 0 && snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, optimalPeriodSize, 0 ) >= 0 ) { break; } optimalPeriodSize /= 2; } if( optimalPeriodSize > periodSize ) periodSize = optimalPeriodSize; if( periodSize <= maxPeriodSize ) { /* Looks good, the periodSize _should_ be acceptable by both devices */ ENSURE_( snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ), paUnanticipatedHostError ); self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize; framesPerHostBuffer = periodSize; } else { /* Unable to find a common period size, oh well */ optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize ); optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize ); self->capture.framesPerBuffer = optimalPeriodSize; dir = 0; ENSURE_( snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ), paUnanticipatedHostError ); self->playback.framesPerBuffer = optimalPeriodSize; dir = 0; ENSURE_( snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ), paUnanticipatedHostError ); framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer ); *hostBufferSizeMode = paUtilBoundedHostBufferSize; } } else { /* We choose the simple route and determine a suitable number of frames per buffer for one component of * the stream, then we hope that this will work for the other component too (it should!). */ unsigned maxPeriods = 0; PaAlsaStreamComponent* first = &self->capture, * second = &self->playback; const PaStreamParameters* firstStreamParams = inputParameters; snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback; dir = 0; ENSURE_( snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError ); if( maxPeriods < numPeriods ) { /* The playback component is trickier to get right, try that first */ first = &self->playback; second = &self->capture; firstStreamParams = outputParameters; firstHwParams = hwParamsPlayback; secondHwParams = hwParamsCapture; } PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer, sampleRate, firstHwParams, &accurate ) ); second->framesPerBuffer = first->framesPerBuffer; dir = 0; ENSURE_( snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ), paUnanticipatedHostError ); if( self->capture.framesPerBuffer == self->playback.framesPerBuffer ) { framesPerHostBuffer = self->capture.framesPerBuffer; } else { framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer ); *hostBufferSizeMode = paUtilBoundedHostBufferSize; } } } else /* half-duplex is a slightly simpler case */ { if( self->capture.pcm ) { PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer, sampleRate, hwParamsCapture, &accurate) ); framesPerHostBuffer = self->capture.framesPerBuffer; } else { assert( self->playback.pcm ); PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer, sampleRate, hwParamsPlayback, &accurate ) ); framesPerHostBuffer = self->playback.framesPerBuffer; } } PA_UNLESS( framesPerHostBuffer != 0, paInternalError ); self->maxFramesPerHostBuffer = framesPerHostBuffer; if( !accurate ) { /* Don't know the exact size per host buffer */ *hostBufferSizeMode = paUtilBoundedHostBufferSize; /* Raise upper bound */ ++self->maxFramesPerHostBuffer; } error: return result; } /** Set up ALSA stream parameters. * */ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters* outParams, double sampleRate, unsigned long framesPerUserBuffer, double* inputLatency, double* outputLatency, PaUtilHostBufferSizeMode* hostBufferSizeMode ) { PaError result = paNoError; double realSr = sampleRate; snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback; snd_pcm_hw_params_alloca( &hwParamsCapture ); snd_pcm_hw_params_alloca( &hwParamsPlayback ); if( self->capture.pcm ) PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture, &realSr ) ); if( self->playback.pcm ) PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback, &realSr ) ); PA_ENSURE( PaAlsaStream_DetermineFramesPerBuffer( self, realSr, inParams, outParams, framesPerUserBuffer, hwParamsCapture, hwParamsPlayback, hostBufferSizeMode ) ); if( self->capture.pcm ) { assert( self->capture.framesPerBuffer != 0 ); PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr, inputLatency ) ); PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerBuffer, *inputLatency )); } if( self->playback.pcm ) { assert( self->playback.framesPerBuffer != 0 ); PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr, outputLatency ) ); PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerBuffer, *outputLatency )); } /* Should be exact now */ self->streamRepresentation.streamInfo.sampleRate = realSr; /* this will cause the two streams to automatically start/stop/prepare in sync. * We only need to execute these operations on one of the pair. * A: We don't want to do this on a blocking stream. */ if( self->callbackMode && self->capture.pcm && self->playback.pcm ) { int err = snd_pcm_link( self->capture.pcm, self->playback.pcm ); if( err == 0 ) self->pcmsSynced = 1; else PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) )); } { unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX, self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX ); self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */ /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */ /* self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000); */ } if( self->callbackMode ) { /* If the user expects a certain number of frames per callback we will either have to rely on block adaption * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number * of host buffer frames with what the user specified */ if( self->framesPerUserBuffer != paFramesPerBufferUnspecified ) { /* self->alignFrames = 1; */ /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely * on block adaption */ /* if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm && self->capture.framesPerBuffer != self->playback.framesPerBuffer) ) self->useBlockAdaption = 1; else self->alignFrames = 1; */ } } error: return result; } static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback* callback, void *userData ) { PaError result = paNoError; PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; PaAlsaStream *stream = NULL; PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; int numInputChannels = 0, numOutputChannels = 0; PaTime inputLatency, outputLatency; /* Operate with fixed host buffer size by default, since other modes will invariably lead to block adaption */ /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */ PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize; if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; if( inputParameters ) { PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) ); numInputChannels = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; } if( outputParameters ) { PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) ); numOutputChannels = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; } /* XXX: Why do we support this anyway? */ if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL ) { PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ )); framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") ); } PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory ); PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate, framesPerBuffer, callback, streamFlags, userData ) ); PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer, &inputLatency, &outputLatency, &hostBufferSizeMode ) ); hostInputSampleFormat = stream->capture.hostSampleFormat; hostOutputSampleFormat = stream->playback.hostSampleFormat; PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, numInputChannels, inputSampleFormat, hostInputSampleFormat, numOutputChannels, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, stream->maxFramesPerHostBuffer, hostBufferSizeMode, callback, userData ) ); /* Ok, buffer processor is initialized, now we can deduce it's latency */ if( numInputChannels > 0 ) stream->streamRepresentation.streamInfo.inputLatency = inputLatency + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ); if( numOutputChannels > 0 ) stream->streamRepresentation.streamInfo.outputLatency = outputLatency + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ); *s = (PaStream*)stream; return result; error: if( stream ) { PA_DEBUG(( "%s: Stream in error, terminating\n", __FUNCTION__ )); PaAlsaStream_Terminate( stream ); } return result; } static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaAlsaStream *stream = (PaAlsaStream*)s; PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaAlsaStream_Terminate( stream ); return result; } static void SilenceBuffer( PaAlsaStream *stream ) { const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t frames = (snd_pcm_uframes_t)snd_pcm_avail_update( stream->playback.pcm ), offset; snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames ); snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat ); snd_pcm_mmap_commit( stream->playback.pcm, offset, frames ); } /** Start/prepare pcm(s) for streaming. * * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will * be started automatically as the user writes to output. * * The capture pcm, however, will simply be prepared and started. */ static PaError AlsaStart( PaAlsaStream *stream, int priming ) { PaError result = paNoError; if( stream->playback.pcm ) { if( stream->callbackMode ) { if( !priming ) { /* Buffer isn't primed, so prepare and silence */ ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); SilenceBuffer( stream ); } ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); } else ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); } if( stream->capture.pcm && !stream->pcmsSynced ) { ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */ ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); } end: return result; error: goto end; } /** Utility function for determining if pcms are in running state. * */ #if 0 static int IsRunning( PaAlsaStream *stream ) { int result = 0; PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) ); if( stream->capture.pcm ) { snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm ); if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN || capture_state == SND_PCM_STATE_DRAINING ) { result = 1; goto end; } } if( stream->playback.pcm ) { snd_pcm_state_t playback_state = snd_pcm_state( stream->playback.pcm ); if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN || playback_state == SND_PCM_STATE_DRAINING ) { result = 1; goto end; } } end: ASSERT_CALL_( PaUnixMutex_Unlock( &stream->stateMtx ), paNoError ); return result; error: goto error; } #endif static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaAlsaStream* stream = (PaAlsaStream*)s; int streamStarted = 0; /* So we can know wether we need to take the stream down */ /* Ready the processor */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); /* Set now, so we can test for activity further down */ stream->isActive = 1; if( stream->callbackMode ) { PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched ) ); } else { PA_ENSURE( AlsaStart( stream, 0 ) ); streamStarted = 1; } end: return result; error: if( streamStarted ) { AbortStream( stream ); } stream->isActive = 0; goto end; } /** Stop PCM handle, either softly or abruptly. */ static PaError AlsaStop( PaAlsaStream *stream, int abort ) { PaError result = paNoError; /* XXX: snd_pcm_drain tends to lock up, avoid it until we find out more */ abort = 1; /* if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name, "dmix" ) ) { abort = 1; } else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo( stream->playback.device )->name, "dmix" ) ) { abort = 1; } */ if( abort ) { if( stream->playback.pcm ) { ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError ); } if( stream->capture.pcm && !stream->pcmsSynced ) { ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError ); } PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ )); } else { if( stream->playback.pcm ) { ENSURE_( snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError ); if( snd_pcm_drain( stream->playback.pcm ) < 0 ) { PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ )); } } if( stream->capture.pcm && !stream->pcmsSynced ) { /* We don't need to retrieve any remaining frames */ if( snd_pcm_drain( stream->capture.pcm ) < 0 ) { PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ )); } } } end: return result; error: goto end; } /** Stop or abort stream. * * If a stream is in callback mode we will have to inspect wether the background thread has * finished, or we will have to take it out. In either case we join the thread before * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish * buffers (drain) * * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function */ static PaError RealStop( PaAlsaStream *stream, int abort ) { PaError result = paNoError; /* First deal with the callback thread, cancelling and/or joining * it if necessary */ if( stream->callbackMode ) { PaError threadRes; stream->callbackAbort = abort; if( !abort ) { PA_DEBUG(( "Stopping callback\n" )); } PA_ENSURE( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) ); if( threadRes != paNoError ) { PA_DEBUG(( "Callback thread returned: %d\n", threadRes )); } #if 0 if( watchdogRes != paNoError ) PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes )); #endif stream->callback_finished = 0; } else { PA_ENSURE( AlsaStop( stream, abort ) ); } stream->isActive = 0; end: return result; error: goto end; } static PaError StopStream( PaStream *s ) { return RealStop( (PaAlsaStream *) s, 0 ); } static PaError AbortStream( PaStream *s ) { return RealStop( (PaAlsaStream * ) s, 1 ); } /** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback * returning !paContinue is not considered) * */ static PaError IsStreamStopped( PaStream *s ) { PaAlsaStream *stream = (PaAlsaStream *)s; /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */ return !IsStreamActive( s ) && !stream->callback_finished; } static PaError IsStreamActive( PaStream *s ) { PaAlsaStream *stream = (PaAlsaStream*)s; return stream->isActive; } static PaTime GetStreamTime( PaStream *s ) { PaAlsaStream *stream = (PaAlsaStream*)s; snd_timestamp_t timestamp; snd_pcm_status_t* status; snd_pcm_status_alloca( &status ); /* TODO: what if we have both? does it really matter? */ /* TODO: if running in callback mode, this will mean * libasound routines are being called from multiple threads. * need to verify that libasound is thread-safe. */ if( stream->capture.pcm ) { snd_pcm_status( stream->capture.pcm, status ); } else if( stream->playback.pcm ) { snd_pcm_status( stream->playback.pcm, status ); } snd_pcm_status_get_tstamp( status, ×tamp ); return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6; } static double GetStreamCpuLoad( PaStream* s ) { PaAlsaStream *stream = (PaAlsaStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ) { unsigned long approx = (unsigned long) sampleRate; int dir = 0; double fraction = sampleRate - approx; assert( pcm && hwParams ); if( fraction > 0.0 ) { if( fraction > 0.5 ) { ++approx; dir = -1; } else dir = 1; } return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir ); } /* Return exact sample rate in param sampleRate */ static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ) { unsigned int num, den; int err; assert( hwParams ); err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den ); *sampleRate = (double) num / den; return err; } /* Utility functions for blocking/callback interfaces */ /* Atomic restart of stream (we don't want the intermediate state visible) */ static PaError AlsaRestart( PaAlsaStream *stream ) { PaError result = paNoError; PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) ); PA_ENSURE( AlsaStop( stream, 0 ) ); PA_ENSURE( AlsaStart( stream, 0 ) ); PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ )); error: PA_ENSURE( PaUnixMutex_Unlock( &stream->stateMtx ) ); return result; } /** Recover from xrun state. * */ static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self ) { PaError result = paNoError; snd_pcm_status_t *st; PaTime now = PaUtil_GetTime(); snd_timestamp_t t; snd_pcm_status_alloca( &st ); if( self->playback.pcm ) { snd_pcm_status( self->playback.pcm, st ); if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) { snd_pcm_status_get_trigger_tstamp( st, &t ); self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); } } if( self->capture.pcm ) { snd_pcm_status( self->capture.pcm, st ); if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) { snd_pcm_status_get_trigger_tstamp( st, &t ); self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); } } PA_ENSURE( AlsaRestart( self ) ); end: return result; error: goto end; } /** Decide if we should continue polling for specified direction, eventually adjust the poll timeout. * */ static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll ) { PaError result = paNoError; snd_pcm_sframes_t delay, margin; int err; const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL; *continuePoll = 1; if( StreamDirection_In == streamDir ) { component = &stream->capture; otherComponent = &stream->playback; } else { component = &stream->playback; otherComponent = &stream->capture; } /* ALSA docs say that negative delay should indicate xrun, but in my experience snd_pcm_delay returns -EPIPE */ if( (err = snd_pcm_delay( otherComponent->pcm, &delay )) < 0 ) { if( err == -EPIPE ) { /* Xrun */ *continuePoll = 0; goto error; } ENSURE_( err, paUnanticipatedHostError ); } if( StreamDirection_Out == streamDir ) { /* Number of eligible frames before capture overrun */ delay = otherComponent->bufferSize - delay; } margin = delay - otherComponent->framesPerBuffer / 2; if( margin < 0 ) { PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" )); *continuePoll = 0; } else if( margin < otherComponent->framesPerBuffer ) { *pollTimeout = CalculatePollTimeout( stream, margin ); PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout )); } error: return result; } /* Callback interface */ static void OnExit( void *data ) { PaAlsaStream *stream = (PaAlsaStream *) data; assert( data ); PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); stream->callback_finished = 1; /* Let the outside world know stream was stopped in callback */ PA_DEBUG(( "%s: Stopping ALSA handles\n", __FUNCTION__ )); AlsaStop( stream, stream->callbackAbort ); PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ )); /* Eventually notify user all buffers have played */ if( stream->streamRepresentation.streamFinishedCallback ) { stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } stream->isActive = 0; } static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo ) { snd_pcm_status_t *capture_status, *playback_status; snd_timestamp_t capture_timestamp, playback_timestamp; PaTime capture_time = 0., playback_time = 0.; snd_pcm_status_alloca( &capture_status ); snd_pcm_status_alloca( &playback_status ); if( stream->capture.pcm ) { snd_pcm_sframes_t capture_delay; snd_pcm_status( stream->capture.pcm, capture_status ); snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); capture_time = capture_timestamp.tv_sec + ((PaTime)capture_timestamp.tv_usec / 1000000.0); timeInfo->currentTime = capture_time; capture_delay = snd_pcm_status_get_delay( capture_status ); timeInfo->inputBufferAdcTime = timeInfo->currentTime - (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate; } if( stream->playback.pcm ) { snd_pcm_sframes_t playback_delay; snd_pcm_status( stream->playback.pcm, playback_status ); snd_pcm_status_get_tstamp( playback_status, &playback_timestamp ); playback_time = playback_timestamp.tv_sec + ((PaTime)playback_timestamp.tv_usec / 1000000.0); if( stream->capture.pcm ) /* Full duplex */ { /* Hmm, we have both a playback and a capture timestamp. * Hopefully they are the same... */ if( fabs( capture_time - playback_time ) > 0.01 ) PA_DEBUG(("Capture time and playback time differ by %f\n", fabs(capture_time-playback_time))); } else timeInfo->currentTime = playback_time; playback_delay = snd_pcm_status_get_delay( playback_status ); timeInfo->outputBufferDacTime = timeInfo->currentTime + (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate; } } /** Called after buffer processing is finished. * * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime. * * @param numFrames The number of frames that has been processed * @param xrun Return whether an xrun has occurred */ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun ) { PaError result = paNoError; int res; /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed * afterwards */ if( !self->ready ) goto end; res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); if( res == -EPIPE || res == -ESTRPIPE ) { *xrun = 1; } else { ENSURE_( res, paUnanticipatedHostError ); } end: error: return result; } /* Extract buffer from channel area */ static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset ) { return (unsigned char *) area->addr + (area->first + offset * area->step) / 8; } /** Do necessary adaption between user and host channels. * @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and duplicating mono information if host outputs come in pairs. */ static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames ) { PaError result = paNoError; unsigned char *p; int i; int unusedChans = self->numHostChannels - self->numUserChannels; unsigned char *src, *dst; int convertMono = (self->numHostChannels % 2) == 0 && (self->numUserChannels % 2) != 0; assert( StreamDirection_Out == self->streamDir ); if( self->hostInterleaved ) { int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset ); /* Start after the last user channel */ p = buffer + self->numUserChannels * swidth; if( convertMono ) { /* Convert the last user channel into stereo pair */ src = buffer + (self->numUserChannels - 1) * swidth; for( i = 0; i < numFrames; ++i ) { dst = src + swidth; memcpy( dst, src, swidth ); src += self->numHostChannels * swidth; } /* Don't touch the channel we just wrote to */ p += swidth; --unusedChans; } if( unusedChans > 0 ) { /* Silence unused output channels */ for( i = 0; i < numFrames; ++i ) { memset( p, 0, swidth * unusedChans ); p += self->numHostChannels * swidth; } } } else { /* We extract the last user channel */ if( convertMono ) { ENSURE_( snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas + (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError ); --unusedChans; } if( unusedChans > 0 ) { snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames, self->nativeFormat ); } } error: return result; } static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred ) { PaError result = paNoError; int xrun = 0; if( self->capture.pcm ) { PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) ); } if( self->playback.pcm ) { if( self->playback.numHostChannels > self->playback.numUserChannels ) { PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) ); } PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) ); } error: *xrunOccurred = xrun; return result; } /** Update the number of available frames. * */ static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred ) { PaError result = paNoError; snd_pcm_sframes_t framesAvail = snd_pcm_avail_update( self->pcm ); *xrunOccurred = 0; if( -EPIPE == framesAvail ) { *xrunOccurred = 1; framesAvail = 0; } else { ENSURE_( framesAvail, paUnanticipatedHostError ); } *numFrames = framesAvail; error: return result; } /** Fill in pollfd objects. */ static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds ) { PaError result = paNoError; int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds ); (void)ret; /* Prevent unused variable warning if asserts are turned off */ assert( ret == self->nfds ); self->ready = 0; return result; } /** Examine results from poll(). * * @param pfds pollfds to inspect * @param shouldPoll Should we continue to poll * @param xrun Has an xrun occurred */ static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, struct pollfd* pfds, int* shouldPoll, int* xrun ) { PaError result = paNoError; unsigned short revents; ENSURE_( snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError ); if( revents != 0 ) { if( revents & POLLERR ) { *xrun = 1; } else self->ready = 1; *shouldPoll = 0; } error: return result; } /** Return the number of available frames for this stream. * * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback. * * @param queryCapture Check available for capture * @param queryPlayback Check available for playback * @param available The returned number of frames * @param xrunOccurred Return whether an xrun has occurred */ static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long *available, int *xrunOccurred ) { PaError result = paNoError; unsigned long captureFrames, playbackFrames; *xrunOccurred = 0; assert( queryCapture || queryPlayback ); if( queryCapture ) { assert( self->capture.pcm ); PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) ); if( *xrunOccurred ) { goto end; } } if( queryPlayback ) { assert( self->playback.pcm ); PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) ); if( *xrunOccurred ) { goto end; } } if( queryCapture && queryPlayback ) { *available = PA_MIN( captureFrames, playbackFrames ); /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/ } else if( queryCapture ) { *available = captureFrames; } else { *available = playbackFrames; } end: error: return result; } /** Wait for and report available buffer space from ALSA. * * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more. * Both of these operations can uncover xrun conditions. * * @concern Xruns Both polling and querying available frames can report an xrun condition. * * @param framesAvail Return the number of available frames * @param xrunOccurred Return whether an xrun has occurred */ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred ) { PaError result = paNoError; int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL; int pollTimeout = self->pollTimeout; int xrun = 0; assert( self ); assert( framesAvail ); if( !self->callbackMode ) { /* In blocking mode we will only wait if necessary */ PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL, framesAvail, &xrun ) ); if( xrun ) { goto end; } if( *framesAvail > 0 ) { /* Mark pcms ready from poll */ if( self->capture.pcm ) self->capture.ready = 1; if( self->playback.pcm ) self->playback.ready = 1; goto end; } } while( pollPlayback || pollCapture ) { int totalFds = 0; struct pollfd *capturePfds = NULL, *playbackPfds = NULL; pthread_testcancel(); if( pollCapture ) { capturePfds = self->pfds; PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) ); totalFds += self->capture.nfds; } if( pollPlayback ) { playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0); PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) ); totalFds += self->playback.nfds; } if( poll( self->pfds, totalFds, pollTimeout ) < 0 ) { /* XXX: Depend on preprocessor condition? */ if( errno == EINTR ) { /* gdb */ continue; } /* TODO: Add macro for checking system calls */ PA_ENSURE( paInternalError ); } /* check the return status of our pfds */ if( pollCapture ) { PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) ); } if( pollPlayback ) { PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) ); } if( xrun ) { break; } /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two. * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will * stop polling. */ if( self->capture.pcm && self->playback.pcm ) { if( pollCapture && !pollPlayback ) { PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) ); } else if( pollPlayback && !pollCapture ) { PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) ); } } } if( !xrun ) { /* Get the number of available frames for the pcms that are marked ready. * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for * the other direction is returned. Output is normally preferred over capture however, so capture frames may be * discarded to avoid overrun unless paNeverDropInput is specified. */ int captureReady = self->capture.pcm ? self->capture.ready : 0, playbackReady = self->playback.pcm ? self->playback.ready : 0; PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) ); if( self->capture.pcm && self->playback.pcm ) { if( !self->playback.ready && !self->neverDropInput ) { /* Drop input, a period's worth */ assert( self->capture.ready ); PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerBuffer, *framesAvail ), &xrun ); *framesAvail = 0; self->capture.ready = 0; } } else if( self->capture.pcm ) assert( self->capture.ready ); else assert( self->playback.ready ); } end: error: if( xrun ) { /* Recover from the xrun state */ PA_ENSURE( PaAlsaStream_HandleXrun( self ) ); *framesAvail = 0; } else { if( 0 != *framesAvail ) { /* If we're reporting frames eligible for processing, one of the handles better be ready */ PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError ); } } *xrunOccurred = xrun; return result; } /** Register per-channel ALSA buffer information with buffer processor. * * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the * number of host and user channels is taken into account. * * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames. */ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* self, PaUtilBufferProcessor* bp, unsigned long* numFrames, int* xrun ) { PaError result = paNoError; const snd_pcm_channel_area_t *areas, *area; void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) = StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel; unsigned char *buffer, *p; int i; unsigned long framesAvail; /* This _must_ be called before mmap_begin */ PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) ); if( *xrun ) { *numFrames = 0; goto end; } ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError ); if( self->hostInterleaved ) { int swidth = snd_pcm_format_size( self->nativeFormat, 1 ); p = buffer = ExtractAddress( areas, self->offset ); for( i = 0; i < self->numUserChannels; ++i ) { /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */ setChannel( bp, i, p, self->numHostChannels ); p += swidth; } } else { for( i = 0; i < self->numUserChannels; ++i ) { area = areas + i; buffer = ExtractAddress( area, self->offset ); setChannel( bp, i, buffer, 1 ); } } /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */ self->channelAreas = (snd_pcm_channel_area_t *)areas; end: error: return result; } /** Initiate buffer processing. * * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set. * * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is * calculated. * * @param numFrames On entrance the number of available frames, on exit the number of received frames * @param xrunOccurred Return whether an xrun has occurred */ static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream* self, unsigned long* numFrames, int* xrunOccurred ) { PaError result = paNoError; unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0; int xrun = 0; if( *xrunOccurred ) { *numFrames = 0; return result; } /* If we got here at least one of the pcm's should be marked ready */ PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError ); /* Extract per-channel ALSA buffer pointers and register them with the buffer processor. * It is possible that a direction is not marked ready however, because it is out of sync with the other. */ if( self->capture.pcm && self->capture.ready ) { captureFrames = *numFrames; PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames, &xrun ) ); } if( self->playback.pcm && self->playback.ready ) { playbackFrames = *numFrames; PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames, &xrun ) ); } if( xrun ) { /* Nothing more to do */ assert( 0 == commonFrames ); goto end; } commonFrames = PA_MIN( captureFrames, playbackFrames ); /* assert( commonFrames <= *numFrames ); */ if( commonFrames > *numFrames ) { /* Hmmm ... how come there are more frames available than we requested!? Blah. */ PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__, commonFrames, *numFrames, self->callbackMode )); if( self->capture.pcm ) { PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready )); } if( self->playback.pcm ) { PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready )); } commonFrames = 0; goto end; } /* Inform PortAudio of the number of frames we got. * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply * discard the excess input or call the callback with paOutputOverflow flagged. */ if( self->capture.pcm ) { if( self->capture.ready ) { PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames ); } else { /* We have input underflow */ PaUtil_SetNoInput( &self->bufferProcessor ); } } if( self->playback.pcm ) { if( self->playback.ready ) { PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames ); } else { /* We have output underflow, but keeping input data (paNeverDropInput) */ assert( self->neverDropInput ); assert( self->capture.pcm != NULL ); PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ )); PaUtil_SetNoOutput( &self->bufferProcessor ); } } end: *numFrames = commonFrames; error: if( xrun ) { PA_ENSURE( PaAlsaStream_HandleXrun( self ) ); *numFrames = 0; } *xrunOccurred = xrun; return result; } /** Callback thread's function. * * Roughly, the workflow can be described in the following way: The number of available frames that can be processed * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected). */ static void *CallbackThreadFunc( void *userData ) { PaError result = paNoError; PaAlsaStream *stream = (PaAlsaStream*) userData; PaStreamCallbackTimeInfo timeInfo = {0, 0, 0}; snd_pcm_sframes_t startThreshold = 0; int callbackResult = paContinue; PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */ int streamStarted = 0; assert( stream ); /* Execute OnExit when exiting */ pthread_cleanup_push( &OnExit, stream ); /* Not implemented */ assert( !stream->primeBuffers ); /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the * stream is started immediately. The latter involves signaling the waiting main thread. */ if( stream->primeBuffers ) { snd_pcm_sframes_t avail; if( stream->playback.pcm ) ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); if( stream->capture.pcm && !stream->pcmsSynced ) ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); /* We can't be certain that the whole ring buffer is available for priming, but there should be * at least one period */ avail = snd_pcm_avail_update( stream->playback.pcm ); startThreshold = avail - (avail % stream->playback.framesPerBuffer); assert( startThreshold >= stream->playback.framesPerBuffer ); } else { PA_ENSURE( PaUnixThread_PrepareNotify( &stream->thread ) ); /* Buffer will be zeroed */ PA_ENSURE( AlsaStart( stream, 0 ) ); PA_ENSURE( PaUnixThread_NotifyParent( &stream->thread ) ); streamStarted = 1; } while( 1 ) { unsigned long framesAvail, framesGot; int xrun = 0; pthread_testcancel(); /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output). */ if( PaUnixThread_StopRequested( &stream->thread ) && paContinue == callbackResult ) { PA_DEBUG(( "Setting callbackResult to paComplete\n" )); callbackResult = paComplete; } if( paContinue != callbackResult ) { stream->callbackAbort = (paAbort == callbackResult); if( stream->callbackAbort || /** @concern BlockAdaption: Go on if adaption buffers are empty */ PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) { goto end; } PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ )); /* There is still buffered output that needs to be processed */ } /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have * a number of available frames. */ PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); if( xrun ) { assert( 0 == framesAvail ); continue; /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due * to constant xruns, it might be desirable to notify the user of this. */ } /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller * portions at a time than is available as a whole. Therefore we should be prepared to process several * chunks successively. The buffers are passed to the PA buffer processor. */ while( framesAvail > 0 ) { xrun = 0; pthread_testcancel(); /** @concern Xruns Under/overflows are to be reported to the callback */ if( stream->underrun > 0.0 ) { cbFlags |= paOutputUnderflow; stream->underrun = 0.0; } if( stream->overrun > 0.0 ) { cbFlags |= paInputOverflow; stream->overrun = 0.0; } if( stream->capture.pcm && stream->playback.pcm ) { /** @concern FullDuplex It's possible that only one direction is being processed to avoid an * under- or overflow, this should be reported correspondingly */ if( !stream->capture.ready ) { cbFlags |= paInputUnderflow; PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ )); } else if( !stream->playback.ready ) { cbFlags |= paOutputOverflow; PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ )); } } #if 0 CallbackUpdate( &stream->threading ); #endif CalculateTimeInfo( stream, &timeInfo ); PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); cbFlags = 0; /* CPU load measurement should include processing activivity external to the stream callback */ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); framesGot = framesAvail; if( paUtilFixedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode ) { /* We've committed to a fixed host buffer size, stick to that */ framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0; } else { /* We've committed to an upper bound on the size of host buffers */ assert( paUtilBoundedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode ); framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer ); } PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); /* Check the host buffer size against the buffer processor configuration */ framesAvail -= framesGot; if( framesGot > 0 ) { assert( !xrun ); PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) ); } PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot ); if( 0 == framesGot ) { /* Go back to polling for more frames */ break; } if( paContinue != callbackResult ) break; } } /* Match pthread_cleanup_push */ pthread_cleanup_pop( 1 ); end: PA_DEBUG(( "%s: Thread %d exiting\n ", __FUNCTION__, pthread_self() )); PaUnixThreading_EXIT( result ); error: goto end; } /* Blocking interface */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaError result = paNoError; PaAlsaStream *stream = (PaAlsaStream*)s; unsigned long framesGot, framesAvail; void *userBuffer; snd_pcm_t *save = stream->playback.pcm; assert( stream ); PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream ); /* Disregard playback */ stream->playback.pcm = NULL; if( stream->overrun > 0. ) { result = paInputOverflowed; stream->overrun = 0.0; } if( stream->capture.userInterleaved ) { userBuffer = buffer; } else { /* Copy channels into local array */ userBuffer = stream->capture.userBuffers; memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels ); } /* Start stream if in prepared state */ if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED ) { ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); } while( frames > 0 ) { int xrun = 0; PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); framesGot = PA_MIN( framesAvail, frames ); PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); if( framesGot > 0 ) { framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot ); PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) ); frames -= framesGot; } } end: stream->playback.pcm = save; return result; error: goto end; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaError result = paNoError; signed long err; PaAlsaStream *stream = (PaAlsaStream*)s; snd_pcm_uframes_t framesGot, framesAvail; const void *userBuffer; snd_pcm_t *save = stream->capture.pcm; assert( stream ); PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream ); /* Disregard capture */ stream->capture.pcm = NULL; if( stream->underrun > 0. ) { result = paOutputUnderflowed; stream->underrun = 0.0; } if( stream->playback.userInterleaved ) userBuffer = buffer; else /* Copy channels into local array */ { userBuffer = stream->playback.userBuffers; memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels ); } while( frames > 0 ) { int xrun = 0; snd_pcm_uframes_t hwAvail; PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); framesGot = PA_MIN( framesAvail, frames ); PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); if( framesGot > 0 ) { framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot ); PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) ); frames -= framesGot; } /* Start stream after one period of samples worth */ /* Frames residing in buffer */ PA_ENSURE( err = GetStreamWriteAvailable( stream ) ); framesAvail = err; hwAvail = stream->playback.bufferSize - framesAvail; if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED && hwAvail >= stream->playback.framesPerBuffer ) { ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); } } end: stream->capture.pcm = save; return result; error: goto end; } /* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */ static signed long GetStreamReadAvailable( PaStream* s ) { PaError result = paNoError; PaAlsaStream *stream = (PaAlsaStream*)s; unsigned long avail; int xrun; PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) ); if( xrun ) { PA_ENSURE( PaAlsaStream_HandleXrun( stream ) ); PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) ); if( xrun ) PA_ENSURE( paInputOverflowed ); } return (signed long)avail; error: return result; } static signed long GetStreamWriteAvailable( PaStream* s ) { PaError result = paNoError; PaAlsaStream *stream = (PaAlsaStream*)s; unsigned long avail; int xrun; PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) ); if( xrun ) { snd_pcm_sframes_t savail; PA_ENSURE( PaAlsaStream_HandleXrun( stream ) ); savail = snd_pcm_avail_update( stream->playback.pcm ); /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */ ENSURE_( savail, paUnanticipatedHostError ); avail = (unsigned long) savail; } return (signed long)avail; error: return result; } /* Extensions */ void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info ) { info->size = sizeof (PaAlsaStreamInfo); info->hostApiType = paALSA; info->version = 1; info->deviceString = NULL; } void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable ) { PaAlsaStream *stream = (PaAlsaStream *) s; stream->rtSched = enable; } #if 0 void PaAlsa_EnableWatchdog( PaStream *s, int enable ) { PaAlsaStream *stream = (PaAlsaStream *) s; stream->thread.useWatchdog = enable; } #endif PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) { PaAlsaStream *stream = (PaAlsaStream *) s; snd_pcm_info_t* pcmInfo; PaError result = paNoError; /* XXX: More descriptive error? */ PA_UNLESS( stream->capture.pcm, paDeviceUnavailable ); snd_pcm_info_alloca( &pcmInfo ); PA_ENSURE( snd_pcm_info( stream->capture.pcm, pcmInfo ) ); *card = snd_pcm_info_get_card( pcmInfo ); error: return result; } PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) { PaAlsaStream *stream = (PaAlsaStream *) s; snd_pcm_info_t* pcmInfo; PaError result = paNoError; /* XXX: More descriptive error? */ PA_UNLESS( stream->playback.pcm, paDeviceUnavailable ); snd_pcm_info_alloca( &pcmInfo ); PA_ENSURE( snd_pcm_info( stream->playback.pcm, pcmInfo ) ); *card = snd_pcm_info_get_card( pcmInfo ); error: return result; } nyquist-3.05/portaudio/src/hostapi/oss/0002755000175000000620000000000011537433131017236 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/oss/low_latency_tip.txt0000644000175000000620000000604711466723256023213 0ustar stevestaffFrom: "Benno Senoner" To: Subject: Re: [music-dsp] coding realtime guitar efx on a "pc" Date: Saturday, June 30, 2001 8:19 AM Andr, you are solving your problem the wrong way: you need to use a single threaded solution which does this: - set the audio I/O parameters to fragnum=4 fragsize=128 bytes (=32samples) if you use stereo or fragsize=64 bytes (=32 samples) if you use mono. (do not forget to activate fulltuplex with using the _TRIGGER_ stuff) (you need to frist deactivate audio and then start the trigger after the DAC is prefilled (see below)) This will give you a total input to output latency of 4x32 samples = 128 samples which at 44.1kHz correspond to 2.9msec latency. now set your process to SCHED_FIFO (see man sched_setscheduler) after the initialization your code should do more than less this: - write() 4 x 32 samples to the audio fd in order to prefill the DAC. Without this you will get dropouts. while(1) { read() 32 samples from ADC perform_dsp_stuff() on the 32 samples write() 32 samples to DAC } If you use a low latency kernel and pay attention to all the stuff above, then you will get rock solid 3msec latencies (plus eventual converter latencies but these are in the 1-2msec range AFAIK). Using multiple threads , pipes etc, only complicates your life and often makes it impossible to achieve these low latences. Realtime/audio programming is not an easy task , this is why people often fail to get the desired results even if their hardware is low-latency capable. The problem is that the final latency depends on the hardware you use, the application and the operating system. cheers, Benno. http://www.linuxaudiodev.org The Home of Linux Audio Development On Sat, 30 Jun 2001, you wrote: > On 2001-06-29 21:38 +0200, Benno Senoner wrote: > > > OSS/Free refuses to use a low # of frags ? > > > > That's a myth. > > I hope it is. :-) > > The fact is that ioctl(SNDCTL_DSP_SETFRAGMENT) succeeds with > values as low a 0x10007 (one 128-B fragment) but the latency is > still high enough to be clearly noticeable, which suggests that > it's *way* above 2/3 ms. This is on an otherwise idle machine > equipped with a SB PCI 128. > > But maybe it's me who's doing something wrong. I've been careful > to flush stdio buffers or use unbuffered I/O (write(2)) but I > may have let something else through. > > For example, since the signal processing and the I/O are done by > two different vanilla processes communicating via pipes, it may > be a scheduling granularity problem (E.G. the kernel giving the > I/O process a time slice every 20 ms). > > -- > Andr Majorel > http://www.teaser.fr/~amajorel/ > > dupswapdrop -- the music-dsp mailing list and website: subscription info, > FAQ, source code archive, list archive, book reviews, dsp links > http://shoko.calarts.edu/musicdsp/ -- dupswapdrop -- the music-dsp mailing list and website: subscription info, FAQ, source code archive, list archive, book reviews, dsp links http://shoko.calarts.edu/musicdsp/ nyquist-3.05/portaudio/src/hostapi/oss/pa_unix_oss.c0000644000175000000620000020475511466723256021757 0ustar stevestaff/* * $Id: pa_unix_oss.c,v 1.1 2010/11/04 21:04:37 rbd Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * OSS implementation by: * Douglas Repetto * Phil Burk * Dominic Mazzoni * Arve Knudsen * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostapi_src */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SOUNDCARD_H # include # define DEVICE_NAME_BASE "/dev/dsp" #elif defined(HAVE_LINUX_SOUNDCARD_H) # include # define DEVICE_NAME_BASE "/dev/dsp" #elif defined(HAVE_MACHINE_SOUNDCARD_H) # include /* JH20010905 */ # define DEVICE_NAME_BASE "/dev/audio" #else # error No sound card header file #endif #include "portaudio.h" #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_unix_util.h" #include "pa_debugprint.h" static int sysErr_; static pthread_t mainThread_; /* Check return value of system call, and map it to PaError */ #define ENSURE_(expr, code) \ do { \ if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \ { \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ { \ PaUtil_SetLastHostErrorInfo( paALSA, sysErr_, strerror( errno ) ); \ } \ \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = (code); \ goto error; \ } \ } while( 0 ); #ifndef AFMT_S16_NE #define AFMT_S16_NE Get_AFMT_S16_NE() /********************************************************************* * Some versions of OSS do not define AFMT_S16_NE. So check CPU. * PowerPC is Big Endian. X86 is Little Endian. */ static int Get_AFMT_S16_NE( void ) { long testData = 1; char *ptr = (char *) &testData; int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */ return isLittle ? AFMT_S16_LE : AFMT_S16_BE; } #endif /* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; PaHostApiIndex hostApiIndex; } PaOSSHostApiRepresentation; /** Per-direction structure for PaOssStream. * * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback, * but with different number of channels we will have to adapt between the number of user and host * channels for at least one direction, since the configuration space is the same for both directions * of an OSS device. */ typedef struct { int fd; const char *devName; int userChannelCount, hostChannelCount; int userInterleaved; void *buffer; PaSampleFormat userFormat, hostFormat; double latency; unsigned long hostFrames, numBufs; void **userBuffers; /* For non-interleaved blocking */ } PaOssStreamComponent; /** Implementation specific representation of a PaStream. * */ typedef struct PaOssStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaUtilThreading threading; int sharedDevice; unsigned long framesPerHostBuffer; int triggered; /* Have the devices been triggered yet (first start) */ int isActive; int isStopped; int lastPosPtr; double lastStreamBytes; int framesProcessed; double sampleRate; int callbackMode; int callbackStop, callbackAbort; PaOssStreamComponent *capture, *playback; unsigned long pollTimeout; sem_t semaphore; } PaOssStream; typedef enum { StreamMode_In, StreamMode_Out } StreamMode; /* prototypes for functions declared in this file */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi ); /** Initialize the OSS API implementation. * * This function will initialize host API datastructures and query host devices for information. * * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here * * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function, * this happens with the usual "error" label. */ PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; PaOSSHostApiRepresentation *ossHostApi = NULL; PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ), paInsufficientMemory ); PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); ossHostApi->hostApiIndex = hostApiIndex; /* Initialize host API structure */ *hostApi = &ossHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paOSS; (*hostApi)->info.name = "OSS"; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PA_ENSURE( BuildDeviceList( ossHostApi ) ); PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); mainThread_ = pthread_self(); return result; error: if( ossHostApi ) { if( ossHostApi->allocations ) { PaUtil_FreeAllAllocations( ossHostApi->allocations ); PaUtil_DestroyAllocationGroup( ossHostApi->allocations ); } PaUtil_FreeMemory( ossHostApi ); } return result; } PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels, int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency, PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations ) { PaError result = paNoError; deviceInfo->structVersion = 2; if( allocations ) { size_t len = strlen( name ) + 1; PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory ); strncpy( (char *)deviceInfo->name, name, len ); } else deviceInfo->name = name; deviceInfo->hostApi = hostApiIndex; deviceInfo->maxInputChannels = maxInputChannels; deviceInfo->maxOutputChannels = maxOutputChannels; deviceInfo->defaultLowInputLatency = defaultLowInputLatency; deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency; deviceInfo->defaultHighInputLatency = defaultHighInputLatency; deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency; deviceInfo->defaultSampleRate = defaultSampleRate; error: return result; } static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount, double *defaultLowLatency, double *defaultHighLatency ) { PaError result = paNoError; int numChannels, maxNumChannels; int busy = 0; int devHandle = -1; int sr; *maxChannelCount = 0; /* Default value in case this fails */ if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK )) < 0 ) { if( errno == EBUSY || errno == EAGAIN ) { PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName )); } else { PA_DEBUG(( "%s: Can't access device: %s\n", __FUNCTION__, strerror( errno ) )); } return paDeviceUnavailable; } /* Negotiate for the maximum number of channels for this device. PLB20010927 * Consider up to 16 as the upper number of channels. * Variable maxNumChannels should contain the actual upper limit after the call. * Thanks to John Lazzaro and Heiko Purnhagen for suggestions. */ maxNumChannels = 0; for( numChannels = 1; numChannels <= 16; numChannels++ ) { int temp = numChannels; if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 ) { busy = EAGAIN == errno || EBUSY == errno; /* ioctl() failed so bail out if we already have stereo */ if( maxNumChannels >= 2 ) break; } else { /* ioctl() worked but bail out if it does not support numChannels. * We don't want to leave gaps in the numChannels supported. */ if( (numChannels > 2) && (temp != numChannels) ) break; if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */ } } /* A: We're able to open a device for capture if it's busy playing back and vice versa, * but we can't configure anything */ if( 0 == maxNumChannels && busy ) { result = paDeviceUnavailable; goto error; } /* The above negotiation may fail for an old driver so try this older technique. */ if( maxNumChannels < 1 ) { int stereo = 1; if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 ) { maxNumChannels = 1; } else { maxNumChannels = (stereo) ? 2 : 1; } PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels )); } /* During channel negotiation, the last ioctl() may have failed. This can * also cause sample rate negotiation to fail. Hence the following, to return * to a supported number of channels. SG20011005 */ { /* use most reasonable default value */ int temp = PA_MIN( maxNumChannels, 2 ); ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError ); } /* Get supported sample rate closest to 44100 Hz */ if( *defaultSampleRate < 0 ) { sr = 44100; if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 ) { result = paUnanticipatedHostError; goto error; } *defaultSampleRate = sr; } *maxChannelCount = maxNumChannels; /* TODO */ *defaultLowLatency = 512. / *defaultSampleRate; *defaultHighLatency = 2048. / *defaultSampleRate; error: if( devHandle >= 0 ) close( devHandle ); return result; } /** Query OSS device. * * This is where PaDeviceInfo objects are constructed and filled in with relevant information. * * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed * in place. */ static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo ) { PaError result = paNoError; double sampleRate = -1.; int maxInputChannels, maxOutputChannels; PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency; PaError tmpRes = paNoError; int busy = 0; *deviceInfo = NULL; /* douglas: we have to do this querying in a slightly different order. apparently some sound cards will give you different info based on their settins. e.g. a card might give you stereo at 22kHz but only mono at 44kHz. the correct order for OSS is: format, channels, sample rate */ /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is * opened in, it may have more channels available for capture than playback and vice versa. Therefore * we will open the device in both read- and write-only mode to determine the supported number. */ if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency, &defaultHighInputLatency )) != paNoError ) { if( tmpRes != paDeviceUnavailable ) { PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName )); /* PA_ENSURE( tmpRes ); */ } ++busy; } if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency, &defaultHighOutputLatency )) != paNoError ) { if( tmpRes != paDeviceUnavailable ) { PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName )); /* PA_ENSURE( tmpRes ); */ } ++busy; } assert( 0 <= busy && busy <= 2 ); if( 2 == busy ) /* Both directions are unavailable to us */ { result = paDeviceUnavailable; goto error; } PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory ); PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels, defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate, ossApi->allocations ) ); error: return result; } /** Query host devices. * * Loop over host devices and query their capabilitiesu * * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object * per device, these are placed in the host api representation's deviceInfos array. */ static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi ) { PaError result = paNoError; PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep; int i; int numDevices = 0, maxDeviceInfos = 1; PaDeviceInfo **deviceInfos = NULL; /* These two will be set to the first working input and output device, respectively */ commonApi->info.defaultInputDevice = paNoDevice; commonApi->info.defaultOutputDevice = paNoDevice; /* Find devices by calling QueryDevice on each * potential device names. When we find a valid one, * add it to a linked list. * A: Set an arbitrary of 100 devices, should probably be a smarter way. */ for( i = 0; i < 100; i++ ) { char deviceName[32]; PaDeviceInfo *deviceInfo; int testResult; struct stat stbuf; if( i == 0 ) snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE); else snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i); /* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */ if( stat( deviceName, &stbuf ) < 0 ) { if( ENOENT != errno ) PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) )); continue; } if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError ) { if( testResult != paDeviceUnavailable ) PA_ENSURE( testResult ); continue; } ++numDevices; if( !deviceInfos || numDevices > maxDeviceInfos ) { maxDeviceInfos *= 2; PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ), paInsufficientMemory ); } { int devIdx = numDevices - 1; deviceInfos[devIdx] = deviceInfo; if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 ) commonApi->info.defaultInputDevice = devIdx; if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 ) commonApi->info.defaultOutputDevice = devIdx; } } /* Make an array of PaDeviceInfo pointers out of the linked list */ PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices)); commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices ); memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) ); commonApi->info.deviceCount = numDevices; error: free( deviceInfos ); return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi; if( ossHostApi->allocations ) { PaUtil_FreeAllAllocations( ossHostApi->allocations ); PaUtil_DestroyAllocationGroup( ossHostApi->allocations ); } PaUtil_FreeMemory( ossHostApi ); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaError result = paNoError; PaDeviceIndex device; PaDeviceInfo *deviceInfo; char *deviceName; int inputChannelCount, outputChannelCount; int tempDevHandle = -1; int flags; PaSampleFormat inputSampleFormat, outputSampleFormat; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } if (inputChannelCount == 0 && outputChannelCount == 0) return paInvalidChannelCount; /* if full duplex, make sure that they're the same device */ if (inputChannelCount > 0 && outputChannelCount > 0 && inputParameters->device != outputParameters->device) return paInvalidDevice; /* if full duplex, also make sure that they're the same number of channels */ if (inputChannelCount > 0 && outputChannelCount > 0 && inputChannelCount != outputChannelCount) return paInvalidChannelCount; /* open the device so we can do more tests */ if( inputChannelCount > 0 ) { result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi); if (result != paNoError) return result; } else { result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi); if (result != paNoError) return result; } deviceInfo = hostApi->deviceInfos[device]; deviceName = (char *)deviceInfo->name; flags = O_NONBLOCK; if (inputChannelCount > 0 && outputChannelCount > 0) flags |= O_RDWR; else if (inputChannelCount > 0) flags |= O_RDONLY; else flags |= O_WRONLY; ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable ); /* PaOssStream_Configure will do the rest of the checking for us */ /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */ /* everything succeeded! */ error: if( tempDevHandle >= 0 ) close( tempDevHandle ); return result; } /** Validate stream parameters. * * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device */ static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode ) { int maxChans; assert( parameters ); if( parameters->device == paUseHostApiSpecificDeviceSpecification ) { return paInvalidDevice; } maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels : deviceInfo->maxOutputChannels); if( parameters->channelCount > maxChans ) { return paInvalidChannelCount; } return paNoError; } static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters, int callbackMode, int fd, const char *deviceName ) { PaError result = paNoError; assert( component ); memset( component, 0, sizeof (PaOssStreamComponent) ); component->fd = fd; component->devName = deviceName; component->userChannelCount = parameters->channelCount; component->userFormat = parameters->sampleFormat; component->latency = parameters->suggestedLatency; component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved); if( !callbackMode && !component->userInterleaved ) { /* Pre-allocate non-interleaved user provided buffers */ PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ), paInsufficientMemory ); } error: return result; } static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component ) { assert( component ); if( component->fd >= 0 ) close( component->fd ); if( component->buffer ) PaUtil_FreeMemory( component->buffer ); if( component->userBuffers ) PaUtil_FreeMemory( component->userBuffers ); PaUtil_FreeMemory( component ); } static PaError ModifyBlocking( int fd, int blocking ) { PaError result = paNoError; int fflags; ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError ); if( blocking ) fflags &= ~O_NONBLOCK; else fflags |= O_NONBLOCK; ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError ); error: return result; } static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev ) { PaError result = paNoError; int flags = O_NONBLOCK, duplex = 0; int enableBits = 0; *idev = *odev = -1; if( idevName && odevName ) { duplex = 1; flags |= O_RDWR; } else if( idevName ) flags |= O_RDONLY; else flags |= O_WRONLY; /* open first in nonblocking mode, in case it's busy... * A: then unset the non-blocking attribute */ assert( flags & O_NONBLOCK ); if( idevName ) { ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable ); PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */ /* Initially disable */ enableBits = ~PCM_ENABLE_INPUT; ENSURE_( ioctl( *idev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); } if( odevName ) { if( !idevName ) { ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable ); PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */ /* Initially disable */ enableBits = ~PCM_ENABLE_OUTPUT; ENSURE_( ioctl( *odev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); } else { ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError ); } } error: return result; } static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, PaStreamCallback callback, void *userData, PaStreamFlags streamFlags, PaOSSHostApiRepresentation *ossApi ) { PaError result = paNoError; int idev, odev; PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep; const char *idevName = NULL, *odevName = NULL; assert( stream ); memset( stream, 0, sizeof (PaOssStream) ); stream->isStopped = 1; PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) ); if( inputParameters && outputParameters ) { if( inputParameters->device == outputParameters->device ) stream->sharedDevice = 1; } if( inputParameters ) idevName = hostApi->deviceInfos[inputParameters->device]->name; if( outputParameters ) odevName = hostApi->deviceInfos[outputParameters->device]->name; PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) ); if( inputParameters ) { PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory ); PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) ); } if( outputParameters ) { PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory ); PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) ); } if( callback != NULL ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &ossApi->callbackStreamInterface, callback, userData ); stream->callbackMode = 1; } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &ossApi->blockingStreamInterface, callback, userData ); } ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError ); error: return result; } static void PaOssStream_Terminate( PaOssStream *stream ) { assert( stream ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_TerminateThreading( &stream->threading ); if( stream->capture ) PaOssStreamComponent_Terminate( stream->capture ); if( stream->playback ) PaOssStreamComponent_Terminate( stream->playback ); sem_destroy( &stream->semaphore ); PaUtil_FreeMemory( stream ); } /** Translate from PA format to OSS native. * */ static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat ) { switch( paFormat ) { case paUInt8: *ossFormat = AFMT_U8; break; case paInt8: *ossFormat = AFMT_S8; break; case paInt16: *ossFormat = AFMT_S16_NE; break; default: return paInternalError; /* This shouldn't happen */ } return paNoError; } /** Return the PA-compatible formats that this device can support. * */ static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats ) { PaError result = paNoError; int mask = 0; PaSampleFormat frmts = 0; ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError ); if( mask & AFMT_U8 ) frmts |= paUInt8; if( mask & AFMT_S8 ) frmts |= paInt8; if( mask & AFMT_S16_NE ) frmts |= paInt16; else result = paSampleFormatNotSupported; *availableFormats = frmts; error: return result; } static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component ) { return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount; } /** Buffer size in bytes. * */ static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component ) { return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs; } static int CalcHigherLogTwo( int n ) { int log2 = 0; while( (1<userChannelCount; int frgmt; int numBufs; int bytesPerBuf; unsigned long bufSz; unsigned long fragSz; audio_buf_info bufInfo; /* We may have a situation where only one component (the master) is configured, if both point to the same device. * In that case, the second component will copy settings from the other */ if( !master ) { /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size. * The hardware need not respect the requested fragment size, so we may have to adapt. */ if( framesPerBuffer == paFramesPerBufferUnspecified ) { bufSz = (unsigned long)(component->latency * sampleRate); fragSz = bufSz / 4; } else { fragSz = framesPerBuffer; bufSz = (unsigned long)(component->latency * sampleRate) + fragSz; /* Latency + 1 buffer */ } PA_ENSURE( GetAvailableFormats( component, &availableFormats ) ); hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat ); /* OSS demands at least 2 buffers, and 16 bytes per buffer */ numBufs = (int)PA_MAX( bufSz / fragSz, 2 ); bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 ); /* The fragment parameters are encoded like this: * Most significant byte: number of fragments * Least significant byte: exponent of fragment size (i.e., for 256, 8) */ frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff); ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError ); /* A: according to the OSS programmer's guide parameters should be set in this order: * format, channels, rate */ /* This format should be deemed good before we get this far */ PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) ); nativeFormat = temp; ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError ); PA_UNLESS( temp == nativeFormat, paInternalError ); /* try to set the number of channels */ ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported ); /* XXX: Should be paInvalidChannelCount? */ /* It's possible that the minimum number of host channels is greater than what the user requested */ PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount ); /* try to set the sample rate */ ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate ); /* reject if there's no sample rate within 1% of the one requested */ if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 ) { PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr )); PA_ENSURE( paInvalidSampleRate ); } ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError ); component->numBufs = bufInfo.fragstotal; /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */ ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError ); component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans; component->hostChannelCount = chans; component->hostFormat = hostFormat; } else { component->hostFormat = master->hostFormat; component->hostFrames = master->hostFrames; component->hostChannelCount = master->hostChannelCount; component->numBufs = master->numBufs; } PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ), paInsufficientMemory ); error: return result; } static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames ) { PaError result = paNoError; size_t len = *frames * PaOssStreamComponent_FrameSize( component ); ssize_t bytesRead; ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError ); *frames = bytesRead / PaOssStreamComponent_FrameSize( component ); /* TODO: Handle condition where number of frames read doesn't equal number of frames requested */ error: return result; } static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames ) { PaError result = paNoError; size_t len = *frames * PaOssStreamComponent_FrameSize( component ); ssize_t bytesWritten; ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError ); *frames = bytesWritten / PaOssStreamComponent_FrameSize( component ); /* TODO: Handle condition where number of frames written doesn't equal number of frames requested */ error: return result; } /** Configure the stream according to input/output parameters. * * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by * the user, if so we'll record the actual number of host channels and adapt later. */ static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer, double *inputLatency, double *outputLatency ) { PaError result = paNoError; int duplex = stream->capture && stream->playback; unsigned long framesPerHostBuffer = 0; /* We should request full duplex first thing after opening the device */ if( duplex && stream->sharedDevice ) ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError ); if( stream->capture ) { PaOssStreamComponent *component = stream->capture; PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, NULL ) ); assert( component->hostChannelCount > 0 ); assert( component->hostFrames > 0 ); *inputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate; } if( stream->playback ) { PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL; PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out, master ) ); assert( component->hostChannelCount > 0 ); assert( component->hostFrames > 0 ); *outputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate; } if( duplex ) framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames ); else if( stream->capture ) framesPerHostBuffer = stream->capture->hostFrames; else if( stream->playback ) framesPerHostBuffer = stream->playback->hostFrames; stream->framesPerHostBuffer = framesPerHostBuffer; stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate ); /* Period in usecs, rounded up */ stream->sampleRate = stream->streamRepresentation.streamInfo.sampleRate = sampleRate; error: return result; } /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ /** Open a PA OSS stream. * * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both * directions are the same device we will demand the same number of channels. The number of channels can range * from 1 to the maximum supported by the device. * * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback * must reflect this, in addition the host latency per device should approximate the corresponding * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that * both capture and playback can agree on (they can be different devices), the buffer processor can adapt * between host and user buffer size, but the ratio should preferably be integral. */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi; PaOssStream *stream = NULL; int inputChannelCount = 0, outputChannelCount = 0; PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0; const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0; int bpInitialized = 0; double inLatency = 0., outLatency = 0.; int i = 0; /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ if( inputParameters ) { /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ inputDeviceInfo = hostApi->deviceInfos[inputParameters->device]; PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) ); inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; } if( outputParameters ) { outputDeviceInfo = hostApi->deviceInfos[outputParameters->device]; PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) ); outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; } /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same * device is opened for both directions */ if( inputChannelCount > 0 && outputChannelCount > 0 ) { if( inputParameters->device == outputParameters->device ) { if( inputParameters->channelCount != outputParameters->channelCount ) return paInvalidChannelCount; } } /* Round framesPerBuffer to the next power-of-two to make OSS happy. */ if( framesPerBuffer != paFramesPerBufferUnspecified ) { framesPerBuffer &= INT_MAX; for (i = 1; framesPerBuffer > i; i <<= 1) ; framesPerBuffer = i; } /* allocate and do basic initialization of the stream structure */ PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory ); PA_ENSURE( PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi ) ); PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) ); PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); if( inputParameters ) { inputHostFormat = stream->capture->hostFormat; stream->streamRepresentation.streamInfo.inputLatency = inLatency + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) / sampleRate; } if( outputParameters ) { outputHostFormat = stream->playback->hostFormat; stream->streamRepresentation.streamInfo.outputLatency = outLatency + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) / sampleRate; } /* Initialize buffer processor with fixed host buffer size. * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will * convert between the two. */ PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat, outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer, paUtilFixedHostBufferSize, streamCallback, userData ) ); bpInitialized = 1; *s = (PaStream*)stream; return result; error: if( bpInitialized ) PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); if( stream ) PaOssStream_Terminate( stream ); return result; } /*! Poll on I/O filedescriptors. Poll till we've determined there's data for read or write. In the full-duplex case, we don't want to hang around forever waiting for either input or output frames, so whenever we have a timed out filedescriptor we check if we're nearing under/overrun for the other direction (critical limit set at one buffer). If so, we exit the waiting state, and go on with what we got. We align the number of frames on a host buffer boundary because it is possible that the buffer size differs for the two directions and the host buffer size is a compromise between the two. */ static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames ) { PaError result = paNoError; int pollPlayback = 0, pollCapture = 0; int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail; audio_buf_info bufInfo; /* int ofs = 0, nfds = stream->nfds; */ fd_set readFds, writeFds; int nfds = 0; struct timeval selectTimeval = {0, 0}; unsigned long timeout = stream->pollTimeout; /* In usecs */ int captureFd = -1, playbackFd = -1; assert( stream ); assert( frames ); if( stream->capture ) { pollCapture = 1; captureFd = stream->capture->fd; /* stream->capture->pfd->events = POLLIN; */ } if( stream->playback ) { pollPlayback = 1; playbackFd = stream->playback->fd; /* stream->playback->pfd->events = POLLOUT; */ } FD_ZERO( &readFds ); FD_ZERO( &writeFds ); while( pollPlayback || pollCapture ) { pthread_testcancel(); /* select may modify the timeout parameter */ selectTimeval.tv_usec = timeout; nfds = 0; if( pollCapture ) { FD_SET( captureFd, &readFds ); nfds = captureFd + 1; } if( pollPlayback ) { FD_SET( playbackFd, &writeFds ); nfds = PA_MAX( nfds, playbackFd + 1 ); } ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError ); /* if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 ) { ENSURE_( -1, paUnanticipatedHostError ); } */ pthread_testcancel(); if( pollCapture ) { if( FD_ISSET( captureFd, &readFds ) ) { FD_CLR( captureFd, &readFds ); pollCapture = 0; } /* if( stream->capture->pfd->revents & POLLIN ) { --nfds; ++ofs; pollCapture = 0; } */ else if( stream->playback ) /* Timed out, go on with playback? */ { /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n", __FUNCTION__, stream->pollTimeout ));*/ } } if( pollPlayback ) { if( FD_ISSET( playbackFd, &writeFds ) ) { FD_CLR( playbackFd, &writeFds ); pollPlayback = 0; } /* if( stream->playback->pfd->revents & POLLOUT ) { --nfds; pollPlayback = 0; } */ else if( stream->capture ) /* Timed out, go on with capture? */ { /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n", __FUNCTION__, stream->pollTimeout ));*/ } } } if( stream->capture ) { ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError ); captureAvail = bufInfo.fragments * stream->capture->hostFrames; if( !captureAvail ) PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ )); captureAvail = captureAvail == 0 ? INT_MAX : captureAvail; /* Disregard if zero */ } if( stream->playback ) { ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError ); playbackAvail = bufInfo.fragments * stream->playback->hostFrames; if( !playbackAvail ) { PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ )); } playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail; /* Disregard if zero */ } commonAvail = PA_MIN( captureAvail, playbackAvail ); if( commonAvail == INT_MAX ) commonAvail = 0; commonAvail -= commonAvail % stream->framesPerHostBuffer; assert( commonAvail != INT_MAX ); assert( commonAvail >= 0 ); *frames = commonAvail; error: return result; } /** Prepare stream for capture/playback. * * In order to synchronize capture and playback properly we use the SETTRIGGER command. */ static PaError PaOssStream_Prepare( PaOssStream *stream ) { PaError result = paNoError; int enableBits = 0; if( stream->triggered ) return result; if( stream->playback ) { size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback ); memset( stream->playback->buffer, 0, bufSz ); /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer * OSS will complain. */ PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) ); while (1) { if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 ) break; } PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) ); } if( stream->sharedDevice ) { enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT; ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); } else { if( stream->capture ) { enableBits = PCM_ENABLE_INPUT; ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); } if( stream->playback ) { enableBits = PCM_ENABLE_OUTPUT; ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); } } /* Ok, we have triggered the stream */ stream->triggered = 1; error: return result; } /** Stop audio processing * */ static PaError PaOssStream_Stop( PaOssStream *stream, int abort ) { PaError result = paNoError; /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST. * Also disable capture/playback till the stream is started again */ if( stream->capture ) { ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError ); } if( stream->playback && !stream->sharedDevice ) { ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError ); } error: return result; } /** Clean up after thread exit. * * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here */ static void OnExit( void *data ) { PaOssStream *stream = (PaOssStream *) data; assert( data ); PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); PaOssStream_Stop( stream, stream->callbackAbort ); PA_DEBUG(( "OnExit: Stoppage\n" )); /* Eventually notify user all buffers have played */ if( stream->streamRepresentation.streamFinishedCallback ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); stream->callbackAbort = 0; /* Clear state */ stream->isActive = 0; } static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail ) { PaError result = paNoError; if( stream->capture ) { PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount ); PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail ); } if( stream->playback ) { PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount ); PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail ); } return result; } /** Thread procedure for callback processing. * * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the * callback should be used for buffer priming. When the stream is cancelled a separate function will * take care of the transition to the Callback Finished state (the stream isn't considered Stopped * before StopStream() or AbortStream() are called). */ static void *PaOSS_AudioThreadProc( void *userData ) { PaError result = paNoError; PaOssStream *stream = (PaOssStream*)userData; unsigned long framesAvail = 0, framesProcessed = 0; int callbackResult = paContinue; int triggered = stream->triggered; /* See if SNDCTL_DSP_TRIGGER has been issued already */ int initiateProcessing = triggered; /* Already triggered? */ PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */ /* #if ( SOUND_VERSION > 0x030904 ) audio_errinfo errinfo; #endif */ assert( stream ); pthread_cleanup_push( &OnExit, stream ); /* Execute OnExit when exiting */ /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and * playback in sync, when the stream is restarted after being stopped we simply start by reading/ * writing. */ PA_ENSURE( PaOssStream_Prepare( stream ) ); /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */ if( initiateProcessing ) { /* Make sure devices are in blocking mode */ if( stream->capture ) ModifyBlocking( stream->capture->fd, 1 ); if( stream->playback ) ModifyBlocking( stream->playback->fd, 1 ); } while( 1 ) { pthread_testcancel(); if( stream->callbackStop && callbackResult == paContinue ) { PA_DEBUG(( "Setting callbackResult to paComplete\n" )); callbackResult = paComplete; } /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless * the stream has been recently started, we will have to go right ahead and read/write in blocking * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch * to non-blocking mode. */ if( !initiateProcessing ) { /* Wait on available frames */ PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) ); assert( framesAvail % stream->framesPerHostBuffer == 0 ); } else { framesAvail = stream->framesPerHostBuffer; } while( framesAvail > 0 ) { unsigned long frames = framesAvail; pthread_testcancel(); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* Read data */ if ( stream->capture ) { PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) ); if( frames < framesAvail ) { PA_DEBUG(( "Read %lu less frames than requested\n", framesAvail - frames )); framesAvail = frames; } } #if ( SOUND_VERSION >= 0x030904 ) /* Check with OSS to see if there have been any under/overruns since last time we checked. */ /* if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 ) { if( errinfo.play_underruns ) cbFlags |= paOutputUnderflow ; if( errinfo.record_underruns ) cbFlags |= paInputUnderflow ; } else PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) )); */ #endif PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); cbFlags = 0; PA_ENSURE( SetUpBuffers( stream, framesAvail ) ); framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); assert( framesProcessed == framesAvail ); PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); if ( stream->playback ) { frames = framesAvail; PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) ); if( frames < framesAvail ) { /* TODO: handle bytesWritten != bytesRequested (slippage?) */ PA_DEBUG(( "Wrote %lu less frames than requested\n", framesAvail - frames )); } } framesAvail -= framesProcessed; stream->framesProcessed += framesProcessed; if( callbackResult != paContinue ) break; } if( initiateProcessing || !triggered ) { /* Non-blocking */ if( stream->capture ) PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) ); if( stream->playback && !stream->sharedDevice ) PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) ); initiateProcessing = 0; sem_post( &stream->semaphore ); } if( callbackResult != paContinue ) { stream->callbackAbort = callbackResult == paAbort; if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) break; } } pthread_cleanup_pop( 1 ); error: pthread_exit( NULL ); } /** Close the stream. * */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaOssStream *stream = (PaOssStream*)s; assert( stream ); PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaOssStream_Terminate( stream ); return result; } /** Start the stream. * * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual * callback will be repeatedly called in a separate thread. If a separate thread is started this function * will block untill it has started processing audio, otherwise audio processing is started directly. */ static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaOssStream *stream = (PaOssStream*)s; stream->isActive = 1; stream->isStopped = 0; stream->lastPosPtr = 0; stream->lastStreamBytes = 0; stream->framesProcessed = 0; /* only use the thread for callback streams */ if( stream->bufferProcessor.streamCallback ) { PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) ); sem_wait( &stream->semaphore ); } else PA_ENSURE( PaOssStream_Prepare( stream ) ); error: return result; } static PaError RealStop( PaOssStream *stream, int abort ) { PaError result = paNoError; if( stream->callbackMode ) { if( abort ) stream->callbackAbort = 1; else stream->callbackStop = 1; PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) ); stream->callbackStop = stream->callbackAbort = 0; } else PA_ENSURE( PaOssStream_Stop( stream, abort ) ); stream->isStopped = 1; error: return result; } /** Stop the stream. * * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued * buffers. */ static PaError StopStream( PaStream *s ) { return RealStop( (PaOssStream *)s, 0 ); } /** Abort the stream. * * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing * the OSS device. */ static PaError AbortStream( PaStream *s ) { return RealStop( (PaOssStream *)s, 1 ); } /** Is the stream in the Stopped state. * */ static PaError IsStreamStopped( PaStream *s ) { PaOssStream *stream = (PaOssStream*)s; return (stream->isStopped); } /** Is the stream in the Active state. * */ static PaError IsStreamActive( PaStream *s ) { PaOssStream *stream = (PaOssStream*)s; return (stream->isActive); } static PaTime GetStreamTime( PaStream *s ) { PaOssStream *stream = (PaOssStream*)s; count_info info; int delta; if( stream->playback ) { if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) { delta = ( info.bytes - stream->lastPosPtr ) /* & 0x000FFFFF*/; return (float)(stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate; } } else { if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) { delta = (info.bytes - stream->lastPosPtr) /*& 0x000FFFFF*/; return (float)(stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate; } } /* the ioctl failed, but we can still give a coarse estimate */ return stream->framesProcessed / stream->sampleRate; } static double GetStreamCpuLoad( PaStream* s ) { PaOssStream *stream = (PaOssStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaOssStream *stream = (PaOssStream*)s; int bytesRequested, bytesRead; unsigned long framesRequested; void *userBuffer; /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers, * so we copy the user provided pointers */ if( stream->bufferProcessor.userInputIsInterleaved ) userBuffer = buffer; else /* Copy channels into local array */ { userBuffer = stream->capture->userBuffers; memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount ); } while( frames ) { framesRequested = PA_MIN( frames, stream->capture->hostFrames ); bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture ); bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested ); if ( bytesRequested != bytesRead ) return paUnanticipatedHostError; PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames ); PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount ); PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested ); frames -= framesRequested; } return paNoError; } static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ) { PaOssStream *stream = (PaOssStream*)s; int bytesRequested, bytesWritten; unsigned long framesConverted; const void *userBuffer; /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers, * so we copy the user provided pointers */ if( stream->bufferProcessor.userOutputIsInterleaved ) userBuffer = buffer; else { /* Copy channels into local array */ userBuffer = stream->playback->userBuffers; memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount ); } while( frames ) { PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames ); PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount ); framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames ); frames -= framesConverted; bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback ); bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested ); if ( bytesRequested != bytesWritten ) return paUnanticipatedHostError; } return paNoError; } static signed long GetStreamReadAvailable( PaStream* s ) { PaOssStream *stream = (PaOssStream*)s; audio_buf_info info; if( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ) < 0 ) return paUnanticipatedHostError; return info.fragments * stream->capture->hostFrames; } /* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */ static signed long GetStreamWriteAvailable( PaStream* s ) { PaOssStream *stream = (PaOssStream*)s; int delay = 0; if( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ) < 0 ) return paUnanticipatedHostError; return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback ); } nyquist-3.05/portaudio/src/hostapi/oss/recplay.c0000644000175000000620000000436511466723256021062 0ustar stevestaff/* * recplay.c * Phil Burk * Minimal record and playback test. * */ #include #include #include #ifndef __STDC__ /* #include */ #endif /* __STDC__ */ #include #ifdef __STDC__ #include #else /* __STDC__ */ #include #endif /* __STDC__ */ #include #define NUM_BYTES (64*1024) #define BLOCK_SIZE (4*1024) #define AUDIO "/dev/dsp" char buffer[NUM_BYTES]; int audioDev = 0; main (int argc, char *argv[]) { int numLeft; char *ptr; int num; int samplesize; /********** RECORD ********************/ /* Open audio device. */ audioDev = open (AUDIO, O_RDONLY, 0); if (audioDev == -1) { perror (AUDIO); exit (-1); } /* Set to 16 bit samples. */ samplesize = 16; ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); if (samplesize != 16) { perror("Unable to set the sample size."); exit(-1); } /* Record in blocks */ printf("Begin recording.\n"); numLeft = NUM_BYTES; ptr = buffer; while( numLeft >= BLOCK_SIZE ) { if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 ) { perror (AUDIO); exit (-1); } else { printf("Read %d bytes\n", num); ptr += num; numLeft -= num; } } close( audioDev ); /********** PLAYBACK ********************/ /* Open audio device for writing. */ audioDev = open (AUDIO, O_WRONLY, 0); if (audioDev == -1) { perror (AUDIO); exit (-1); } /* Set to 16 bit samples. */ samplesize = 16; ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); if (samplesize != 16) { perror("Unable to set the sample size."); exit(-1); } /* Play in blocks */ printf("Begin playing.\n"); numLeft = NUM_BYTES; ptr = buffer; while( numLeft >= BLOCK_SIZE ) { if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 ) { perror (AUDIO); exit (-1); } else { printf("Wrote %d bytes\n", num); ptr += num; numLeft -= num; } } close( audioDev ); } nyquist-3.05/portaudio/src/hostapi/coreaudio/0002755000175000000620000000000011537433131020404 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c0000644000175000000620000005465511466723256025123 0ustar stevestaff/* * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation) * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostapi_src */ #include "pa_mac_core_utilities.h" PaError PaMacCore_SetUnixError( int err, int line ) { PaError ret; const char *errorText; if( err == 0 ) { return paNoError; } ret = paNoError; errorText = strerror( err ); /** Map Unix error to PaError. Pretty much the only one that maps is ENOMEM. */ if( err == ENOMEM ) ret = paInsufficientMemory; else ret = paInternalError; DBUG(("%d on line %d: msg='%s'\n", err, line, errorText)); PaUtil_SetLastHostErrorInfo( paCoreAudio, err, errorText ); return ret; } /* * Translates MacOS generated errors into PaErrors */ PaError PaMacCore_SetError(OSStatus error, int line, int isError) { /*FIXME: still need to handle possible ComponentResult values.*/ /* unfortunately, they don't seem to be documented anywhere.*/ PaError result; const char *errorType; const char *errorText; switch (error) { case kAudioHardwareNoError: return paNoError; case kAudioHardwareNotRunningError: errorText = "Audio Hardware Not Running"; result = paInternalError; break; case kAudioHardwareUnspecifiedError: errorText = "Unspecified Audio Hardware Error"; result = paInternalError; break; case kAudioHardwareUnknownPropertyError: errorText = "Audio Hardware: Unknown Property"; result = paInternalError; break; case kAudioHardwareBadPropertySizeError: errorText = "Audio Hardware: Bad Property Size"; result = paInternalError; break; case kAudioHardwareIllegalOperationError: errorText = "Audio Hardware: Illegal Operation"; result = paInternalError; break; case kAudioHardwareBadDeviceError: errorText = "Audio Hardware: Bad Device"; result = paInvalidDevice; break; case kAudioHardwareBadStreamError: errorText = "Audio Hardware: BadStream"; result = paBadStreamPtr; break; case kAudioHardwareUnsupportedOperationError: errorText = "Audio Hardware: Unsupported Operation"; result = paInternalError; break; case kAudioDeviceUnsupportedFormatError: errorText = "Audio Device: Unsupported Format"; result = paSampleFormatNotSupported; break; case kAudioDevicePermissionsError: errorText = "Audio Device: Permissions Error"; result = paDeviceUnavailable; break; /* Audio Unit Errors: http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_units/chapter_5_section_3.html */ case kAudioUnitErr_InvalidProperty: errorText = "Audio Unit: Invalid Property"; result = paInternalError; break; case kAudioUnitErr_InvalidParameter: errorText = "Audio Unit: Invalid Parameter"; result = paInternalError; break; case kAudioUnitErr_NoConnection: errorText = "Audio Unit: No Connection"; result = paInternalError; break; case kAudioUnitErr_FailedInitialization: errorText = "Audio Unit: Initialization Failed"; result = paInternalError; break; case kAudioUnitErr_TooManyFramesToProcess: errorText = "Audio Unit: Too Many Frames"; result = paInternalError; break; case kAudioUnitErr_IllegalInstrument: errorText = "Audio Unit: Illegal Instrument"; result = paInternalError; break; case kAudioUnitErr_InstrumentTypeNotFound: errorText = "Audio Unit: Instrument Type Not Found"; result = paInternalError; break; case kAudioUnitErr_InvalidFile: errorText = "Audio Unit: Invalid File"; result = paInternalError; break; case kAudioUnitErr_UnknownFileType: errorText = "Audio Unit: Unknown File Type"; result = paInternalError; break; case kAudioUnitErr_FileNotSpecified: errorText = "Audio Unit: File Not Specified"; result = paInternalError; break; case kAudioUnitErr_FormatNotSupported: errorText = "Audio Unit: Format Not Supported"; result = paInternalError; break; case kAudioUnitErr_Uninitialized: errorText = "Audio Unit: Unitialized"; result = paInternalError; break; case kAudioUnitErr_InvalidScope: errorText = "Audio Unit: Invalid Scope"; result = paInternalError; break; case kAudioUnitErr_PropertyNotWritable: errorText = "Audio Unit: PropertyNotWritable"; result = paInternalError; break; case kAudioUnitErr_InvalidPropertyValue: errorText = "Audio Unit: Invalid Property Value"; result = paInternalError; break; case kAudioUnitErr_PropertyNotInUse: errorText = "Audio Unit: Property Not In Use"; result = paInternalError; break; case kAudioUnitErr_Initialized: errorText = "Audio Unit: Initialized"; result = paInternalError; break; case kAudioUnitErr_InvalidOfflineRender: errorText = "Audio Unit: Invalid Offline Render"; result = paInternalError; break; case kAudioUnitErr_Unauthorized: errorText = "Audio Unit: Unauthorized"; result = paInternalError; break; case kAudioUnitErr_CannotDoInCurrentContext: errorText = "Audio Unit: cannot do in current context"; result = paInternalError; break; default: errorText = "Unknown Error"; result = paInternalError; } if (isError) errorType = "Error"; else errorType = "Warning"; char str[20]; // see if it appears to be a 4-char-code *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error); if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) { str[0] = str[5] = '\''; str[6] = '\0'; } else { // no, format it as an integer sprintf(str, "%d", (int)error); } DBUG(("%s on line %d: err='%s', msg=%s\n", errorType, line, str, errorText)); PaUtil_SetLastHostErrorInfo( paCoreAudio, error, errorText ); return result; } /* * This function computes an appropriate ring buffer size given * a requested latency (in seconds), sample rate and framesPerBuffer. * * The returned ringBufferSize is computed using the following * constraints: * - it must be at least 4. * - it must be at least 3x framesPerBuffer. * - it must be at least 2x the suggestedLatency. * - it must be a power of 2. * This function attempts to compute the minimum such size. * * FEEDBACK: too liberal/conservative/another way? */ long computeRingBufferSize( const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, long inputFramesPerBuffer, long outputFramesPerBuffer, double sampleRate ) { long ringSize; int index; int i; double latencyTimesChannelCount ; long framesPerBufferTimesChannelCount ; VVDBUG(( "computeRingBufferSize()\n" )); assert( inputParameters || outputParameters ); if( outputParameters && inputParameters ) { latencyTimesChannelCount = MAX( inputParameters->suggestedLatency * inputParameters->channelCount, outputParameters->suggestedLatency * outputParameters->channelCount ); framesPerBufferTimesChannelCount = MAX( inputFramesPerBuffer * inputParameters->channelCount, outputFramesPerBuffer * outputParameters->channelCount ); } else if( outputParameters ) { latencyTimesChannelCount = outputParameters->suggestedLatency * outputParameters->channelCount; framesPerBufferTimesChannelCount = outputFramesPerBuffer * outputParameters->channelCount; } else /* we have inputParameters */ { latencyTimesChannelCount = inputParameters->suggestedLatency * inputParameters->channelCount; framesPerBufferTimesChannelCount = inputFramesPerBuffer * inputParameters->channelCount; } ringSize = (long) ( latencyTimesChannelCount * sampleRate * 2 + .5); VDBUG( ( "suggested latency * channelCount: %d\n", (int) (latencyTimesChannelCount*sampleRate) ) ); if( ringSize < framesPerBufferTimesChannelCount * 3 ) ringSize = framesPerBufferTimesChannelCount * 3 ; VDBUG(("framesPerBuffer*channelCount:%d\n",(int)framesPerBufferTimesChannelCount)); VDBUG(("Ringbuffer size (1): %d\n", (int)ringSize )); /* make sure it's at least 4 */ ringSize = MAX( ringSize, 4 ); /* round up to the next power of 2 */ index = -1; for( i=0; i> i & 0x01 ) index = i; assert( index > 0 ); if( ringSize <= ( 0x01 << index ) ) ringSize = 0x01 << index ; else ringSize = 0x01 << ( index + 1 ); VDBUG(( "Final Ringbuffer size (2): %d\n", (int)ringSize )); return ringSize; } /* * Durring testing of core audio, I found that serious crashes could occur * if properties such as sample rate were changed multiple times in rapid * succession. The function below has some fancy logic to make sure that changes * are acknowledged before another is requested. That seems to help a lot. */ OSStatus propertyProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void* inClientData ) { MutexAndBool *mab = (MutexAndBool *) inClientData; mab->once = TRUE; pthread_mutex_unlock( &(mab->mutex) ); return noErr; } /* sets the value of the given property and waits for the change to be acknowledged, and returns the final value, which is not guaranteed by this function to be the same as the desired value. Obviously, this function can only be used for data whose input and output are the same size and format, and their size and format are known in advance.*/ PaError AudioDeviceSetPropertyNowAndWaitForChange( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData, void *outPropertyData ) { OSStatus macErr; int unixErr; MutexAndBool mab; UInt32 outPropertyDataSize = inPropertyDataSize; /* First, see if it already has that value. If so, return. */ macErr = AudioDeviceGetProperty( inDevice, inChannel, isInput, inPropertyID, &outPropertyDataSize, outPropertyData ); if( macErr ) goto failMac2; if( inPropertyDataSize!=outPropertyDataSize ) return paInternalError; if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) return paNoError; /* setup and lock mutex */ mab.once = FALSE; unixErr = pthread_mutex_init( &mab.mutex, NULL ); if( unixErr ) goto failUnix2; unixErr = pthread_mutex_lock( &mab.mutex ); if( unixErr ) goto failUnix; /* add property listener */ macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc, &mab ); if( macErr ) goto failMac; /* set property */ macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel, isInput, inPropertyID, inPropertyDataSize, inPropertyData ); if( macErr ) { /* we couldn't set the property, so we'll just unlock the mutex and move on. */ pthread_mutex_unlock( &mab.mutex ); } /* wait for property to change */ unixErr = pthread_mutex_lock( &mab.mutex ); if( unixErr ) goto failUnix; /* now read the property back out */ macErr = AudioDeviceGetProperty( inDevice, inChannel, isInput, inPropertyID, &outPropertyDataSize, outPropertyData ); if( macErr ) goto failMac; /* cleanup */ AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); unixErr = pthread_mutex_unlock( &mab.mutex ); if( unixErr ) goto failUnix2; unixErr = pthread_mutex_destroy( &mab.mutex ); if( unixErr ) goto failUnix2; return paNoError; failUnix: pthread_mutex_destroy( &mab.mutex ); AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); failUnix2: DBUG( ("Error #%d while setting a device property: %s\n", unixErr, strerror( unixErr ) ) ); return paUnanticipatedHostError; failMac: pthread_mutex_destroy( &mab.mutex ); AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); failMac2: return ERR( macErr ); } /* * Sets the sample rate the HAL device. * if requireExact: set the sample rate or fail. * * otherwise : set the exact sample rate. * If that fails, check for available sample rates, and choose one * higher than the requested rate. If there isn't a higher one, * just use the highest available. */ PaError setBestSampleRateForDevice( const AudioDeviceID device, const bool isOutput, const bool requireExact, const Float64 desiredSrate ) { /*FIXME: changing the sample rate is disruptive to other programs using the device, so it might be good to offer a custom flag to not change the sample rate and just do conversion. (in my casual tests, there is no disruption unless the sample rate really does need to change) */ const bool isInput = isOutput ? 0 : 1; Float64 srate; UInt32 propsize = sizeof( Float64 ); OSErr err; AudioValueRange *ranges; int i=0; Float64 max = -1; /*the maximum rate available*/ Float64 best = -1; /*the lowest sample rate still greater than desired rate*/ VDBUG(("Setting sample rate for device %ld to %g.\n",device,(float)desiredSrate)); /* -- try setting the sample rate -- */ err = AudioDeviceSetPropertyNowAndWaitForChange( device, 0, isInput, kAudioDevicePropertyNominalSampleRate, propsize, &desiredSrate, &srate ); if( err ) return err; /* -- if the rate agrees, and we got no errors, we are done -- */ if( !err && srate == desiredSrate ) return paNoError; /* -- we've failed if the rates disagree and we are setting input -- */ if( requireExact ) return paInvalidSampleRate; /* -- generate a list of available sample rates -- */ err = AudioDeviceGetPropertyInfo( device, 0, isInput, kAudioDevicePropertyAvailableNominalSampleRates, &propsize, NULL ); if( err ) return ERR( err ); ranges = (AudioValueRange *)calloc( 1, propsize ); if( !ranges ) return paInsufficientMemory; err = AudioDeviceGetProperty( device, 0, isInput, kAudioDevicePropertyAvailableNominalSampleRates, &propsize, ranges ); if( err ) { free( ranges ); return ERR( err ); } VDBUG(("Requested sample rate of %g was not available.\n", (float)desiredSrate)); VDBUG(("%lu Available Sample Rates are:\n",propsize/sizeof(AudioValueRange))); #ifdef MAC_CORE_VERBOSE_DEBUG for( i=0; i max ) max = ranges[i].mMaximum; if( ranges[i].mMinimum > desiredSrate ) { if( best < 0 ) best = ranges[i].mMinimum; else if( ranges[i].mMinimum < best ) best = ranges[i].mMinimum; } } if( best < 0 ) best = max; VDBUG( ("Maximum Rate %g. best is %g.\n", max, best ) ); free( ranges ); /* -- set the sample rate -- */ propsize = sizeof( best ); err = AudioDeviceSetPropertyNowAndWaitForChange( device, 0, isInput, kAudioDevicePropertyNominalSampleRate, propsize, &best, &srate ); if( err ) return err; if( err ) return ERR( err ); /* -- if the set rate matches, we are done -- */ if( srate == best ) return paNoError; /* -- otherwise, something wierd happened: we didn't set the rate, and we got no errors. Just bail. */ return paInternalError; } /* Attempts to set the requestedFramesPerBuffer. If it can't set the exact value, it settles for something smaller if available. If nothing smaller is available, it uses the smallest available size. actualFramesPerBuffer will be set to the actual value on successful return. OK to pass NULL to actualFramesPerBuffer. The logic is very simmilar too setBestSampleRate only failure here is not usually catastrophic. */ PaError setBestFramesPerBuffer( const AudioDeviceID device, const bool isOutput, UInt32 requestedFramesPerBuffer, UInt32 *actualFramesPerBuffer ) { UInt32 afpb; const bool isInput = !isOutput; UInt32 propsize = sizeof(UInt32); OSErr err; Float64 min = -1; /*the min blocksize*/ Float64 best = -1; /*the best blocksize*/ int i=0; AudioValueRange *ranges; if( actualFramesPerBuffer == NULL ) actualFramesPerBuffer = &afpb; /* -- try and set exact FPB -- */ err = AudioDeviceSetProperty( device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propsize, &requestedFramesPerBuffer); err = AudioDeviceGetProperty( device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propsize, actualFramesPerBuffer); if( err ) return ERR( err ); if( *actualFramesPerBuffer == requestedFramesPerBuffer ) return paNoError; /* we are done */ /* -- fetch available block sizes -- */ err = AudioDeviceGetPropertyInfo( device, 0, isInput, kAudioDevicePropertyBufferSizeRange, &propsize, NULL ); if( err ) return ERR( err ); ranges = (AudioValueRange *)calloc( 1, propsize ); if( !ranges ) return paInsufficientMemory; err = AudioDeviceGetProperty( device, 0, isInput, kAudioDevicePropertyBufferSizeRange, &propsize, ranges ); if( err ) { free( ranges ); return ERR( err ); } VDBUG(("Requested block size of %lu was not available.\n", requestedFramesPerBuffer )); VDBUG(("%lu Available block sizes are:\n",propsize/sizeof(AudioValueRange))); #ifdef MAC_CORE_VERBOSE_DEBUG for( i=0; i best ) best = ranges[i].mMaximum; } } if( best == -1 ) best = min; VDBUG( ("Minimum FPB %g. best is %g.\n", min, best ) ); free( ranges ); /* --- set the buffer size (ignore errors) -- */ requestedFramesPerBuffer = (UInt32) best ; propsize = sizeof( UInt32 ); err = AudioDeviceSetProperty( device, NULL, 0, isInput, kAudioDevicePropertyBufferSize, propsize, &requestedFramesPerBuffer ); /* --- read the property to check that it was set -- */ err = AudioDeviceGetProperty( device, 0, isInput, kAudioDevicePropertyBufferSize, &propsize, actualFramesPerBuffer ); if( err ) return ERR( err ); return paNoError; } nyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h0000644000175000000620000001323311466723256024714 0ustar stevestaff/* * Internal interfaces for PortAudio Apple AUHAL implementation * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file pa_mac_core @ingroup hostapi_src @author Bjorn Roche @brief AUHAL implementation of PortAudio */ #ifndef PA_MAC_CORE_INTERNAL_H__ #define PA_MAC_CORE_INTERNAL_H__ #include #include #include "portaudio.h" #include "pa_util.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_allocation.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_ringbuffer.h" #include "pa_mac_core_blocking.h" /* function prototypes */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ #define RING_BUFFER_ADVANCE_DENOMINATOR (4) PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); signed long GetStreamReadAvailable( PaStream* stream ); signed long GetStreamWriteAvailable( PaStream* stream ); /* PaMacAUHAL - host api datastructure specific to this implementation */ typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ long devCount; AudioDeviceID *devIds; /*array of all audio devices*/ AudioDeviceID defaultIn; AudioDeviceID defaultOut; } PaMacAUHAL; /* stream data structure specifically for this implementation */ typedef struct PaMacCoreStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; /* implementation specific data goes here */ bool bufferProcessorIsInitialized; AudioUnit inputUnit; AudioUnit outputUnit; AudioDeviceID inputDevice; AudioDeviceID outputDevice; size_t userInChan; size_t userOutChan; size_t inputFramesPerBuffer; size_t outputFramesPerBuffer; PaMacBlio blio; /* We use this ring buffer when input and out devs are different. */ PaUtilRingBuffer inputRingBuffer; /* We may need to do SR conversion on input. */ AudioConverterRef inputSRConverter; /* We need to preallocate an inputBuffer for reading data. */ AudioBufferList inputAudioBufferList; AudioTimeStamp startTime; /* FIXME: instead of volatile, these should be properly memory barriered */ volatile PaStreamCallbackFlags xrunFlags; volatile bool isTimeSet; volatile enum { STOPPED = 0, /* playback is completely stopped, and the user has called StopStream(). */ CALLBACK_STOPPED = 1, /* callback has requested stop, but user has not yet called StopStream(). */ STOPPING = 2, /* The stream is in the process of closing because the user has called StopStream. This state is just used internally; externally it is indistinguishable from ACTIVE.*/ ACTIVE = 3 /* The stream is active and running. */ } state; double sampleRate; //these may be different from the stream sample rate due to SR conversion: double outDeviceSampleRate; double inDeviceSampleRate; } PaMacCoreStream; #endif /* PA_MAC_CORE_INTERNAL_H__ */ nyquist-3.05/portaudio/src/hostapi/coreaudio/notes.txt0000644000175000000620000002135411466723256022313 0ustar stevestaffNotes on status of CoreAudio Implementation of PortAudio Document Last Updated December 9, 2005 There are currently two implementations of PortAudio for Mac Core Audio. The original is in pa_mac_core_old.c, and the newer, default implementation is in pa_mac_core.c. Only pa_mac_core.c is currently developed and supported as it uses apple's current core audio technology. To select use the old implementation, replace pa_mac_core.c with pa_mac_core_old.c (eg. "cp pa_mac_core_auhal.c pa_mac_core.c"), then run configure and make as usual. ------------------------------------------- Notes on Newer/Default AUHAL implementation: by Bjorn Roche Last Updated December 9, 2005 Principle of Operation: This implementation uses AUHAL for audio I/O. To some extent, it also operates at the "HAL" Layer, though this behavior can be limited by platform specific flags (see pa_mac_core.h for details). The default settings should be reasonable: they don't change the SR of the device and don't cause interruptions if other devices are using the device. Major Software Elements Used: Apple's HAL AUs provide output SR conversion transparently, however, only on output, so this implementation uses AudioConverters to convert the sample rate on input. A PortAudio ring buffer is used to buffer input when sample rate conversion is required or when separate audio units are used for duplex IO. Finally, a PortAudio buffer processor is used to convert formats and provide additional buffers if needed. Internally, interleaved floating point data streams are used exclusively - the audio unit converts from the audio hardware's native format to interleaved float PCM and PortAudio's Buffer processor is used for conversion to user formats. Simplex Input: Simplex input uses a single callback. If sample rate conversion is required, a ring buffer and AudioConverter are used as well. Simplex output: Simplex output uses a single callback. No ring buffer or audio converter is used because AUHAL does its own output SR conversion. Duplex, one device (no SR conversion): When one device is used, a single callback is used. This achieves very low latency. Duplex, separate devices or SR conversion: When SR conversion is required, data must be buffered before it is converted and data is not always available at the same times on input and output, so SR conversion requires the same treatment as separate devices. The input callback reads data and puts it in the ring buffer. The output callback reads the data off the ring buffer, into an audio converter and finally to the buffer processor. Platform Specific Options: By using the flags in pa_mac_core.h, the user may specify several options. For example, the user can specify the sample-rate conversion quality, and the extent to which PA will attempt to "play nice" and to what extent it will interrupt other apps to improve performance. For example, if 44100 Hz sample rate is requested but the device is set at 48000 Hz, PA can either change the device for optimal playback ("Pro" mode), which may interrupt other programs playing back audio, or simple use a sample-rate coversion, which allows for friendlier sharing of the device ("Play Nice" mode). Additionally, the user may define a "channel mapping" by calling paSetupMacCoreChannelMap() on their stream info structure before opening the stream with it. See below for creating a channel map. Known issues: - Buffering: No buffering beyond that provided by core audio is provided except where absolutely needed for the implementation to work. This may cause issues with large framesPerBuffer settings and it also means that no additional latency will be provided even if a large latency setting is selected. - Latency: Latency settings are generally ignored. They may be used as a hint for buffer size in paHostFramesPerBufferUnspecified, or the value may be used in cases where additional buffering is needed, such as doing input and output on seperate devices. Latency settings are always automatically bound to "safe" values, however, so setting extreme values here should not be an issue. - Buffer Size: paHostFramesPerBufferUnspecified and specific host buffer sizes are supported. paHostFramesPerBufferUnspecified works best in "pro" mode, where the buffer size and sample rate of the audio device is most likely to match the expected values. In the case of paHostFramesPerBuffer, an appropriate framesPerBuffer value will be used that guarantees minimum requested latency if that's possible. - Timing info. It reports on stream time, but I'm probably doing something wrong since patest_sine_time often reports negative latency numbers. Also, there are currently issues with some devices whehn plugging/unplugging devices. - xrun detection: The only xrun detection performed is when reading and writing the ring buffer. There is probably more that can be done. - abort/stop issues: stopping a stream is always a complete operation, but latency should be low enough to make the lack of a separate abort unnecessary. Apple clarifies its AudioOutputUnitStop() call here: http://lists.apple.com/archives/coreaudio-api/2005/Dec/msg00055.html - blocking interface: should work fine. - multichannel: It has been tested successfully on multichannel hardware from MOTU: traveler and 896HD. Also Presonus firepod and others. It is believed to work with all Core Audio devices, including virtual devices such as soundflower. - sample rate conversion quality: By default, SR conversion is the maximum available. This can be tweaked using flags pa_mac_core.h. Note that the AU render quyality property is used to set the sample rate conversion quality as "documented" here: http://lists.apple.com/archives/coreaudio-api/2004/Jan/msg00141.html - x86/Universal Binary: Universal binaries can be build. Creating a channel map: How to create the map array - Text taken From AUHAL.rtfd : [3] Channel Maps Clients can tell the AUHAL units which channels of the device they are interested in. For example, the client may be processing stereo data, but outputting to a six-channel device. This is done by using the kAudioOutputUnitProperty_ChannelMap property. To use this property: For Output: Create an array of SInt32 that is the size of the number of channels of the device (Get the Format of the AUHAL's output Element == 0) Initialize each of the array's values to -1 (-1 indicates that that channel is NOT to be presented in the conversion.) Next, for each channel of your app's output, set: channelMapArray[deviceOutputChannel] = desiredAppOutputChannel. For example: we have a 6 channel output device and our application has a stereo source it wants to provide to the device. Suppose we want that stereo source to go to the 3rd and 4th channels of the device. The channel map would look like this: { -1, -1, 0, 1, -1, -1 } Where the formats are: Input Element == 0: 2 channels (- client format - settable) Output Element == 0: 6 channels (- device format - NOT settable) So channel 2 (zero-based) of the device will take the first channel of output and channel 3 will take the second channel of output. (This translates to the 3rd and 4th plugs of the 6 output plugs of the device of course!) For Input: Create an array of SInt32 that is the size of the number of channels of the format you require for input. Get (or Set in this case as needed) the AUHAL's output Element == 1. Next, for each channel of input you require, set: channelMapArray[desiredAppInputChannel] = deviceOutputChannel; For example: we have a 6 channel input device from which we wish to receive stereo input from the 3rd and 4th channels. The channel map looks like this: { 2, 3 } Where the formats are: Input Element == 0: 2 channels (- device format - NOT settable) Output Element == 0: 6 channels (- client format - settable) ---------------------------------------- Notes on Original implementation: by Phil Burk and Darren Gibbs Last updated March 20, 2002 WHAT WORKS Output with very low latency, <10 msec. Half duplex input or output. Full duplex on the same CoreAudio device. The paFLoat32, paInt16, paInt8, paUInt8 sample formats. Pa_GetCPULoad() Pa_StreamTime() KNOWN BUGS OR LIMITATIONS We do not yet support simultaneous input and output on different devices. Note that some CoreAudio devices like the Roland UH30 look like one device but are actually two different CoreAudio devices. The Built-In audio is typically one CoreAudio device. Mono doesn't work. DEVICE MAPPING CoreAudio devices can support both input and output. But the sample rates supported may be different. So we have map one or two PortAudio device to each CoreAudio device depending on whether it supports input, output or both. When we query devices, we first get a list of CoreAudio devices. Then we scan the list and add a PortAudio device for each CoreAudio device that supports input. Then we make a scan for output devices. nyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.h0000644000175000000620000001611011466723256025110 0ustar stevestaff/* * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation) * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostapi_src */ #ifndef PA_MAC_CORE_UTILITIES_H__ #define PA_MAC_CORE_UTILITIES_H__ #include #include "portaudio.h" #include "pa_util.h" #include #include #ifndef MIN #define MIN(a, b) (((a)<(b))?(a):(b)) #endif #ifndef MAX #define MAX(a, b) (((a)<(b))?(b):(a)) #endif #define ERR(mac_error) PaMacCore_SetError(mac_error, __LINE__, 1 ) #define WARNING(mac_error) PaMacCore_SetError(mac_error, __LINE__, 0 ) /* Help keep track of AUHAL element numbers */ #define INPUT_ELEMENT (1) #define OUTPUT_ELEMENT (0) /* Normal level of debugging: fine for most apps that don't mind the occational warning being printf'ed */ /* */ #define MAC_CORE_DEBUG #ifdef MAC_CORE_DEBUG # define DBUG(MSG) do { printf("||PaMacCore (AUHAL)|| "); printf MSG ; fflush(stdout); } while(0) #else # define DBUG(MSG) #endif /* Verbose Debugging: useful for developement */ /* #define MAC_CORE_VERBOSE_DEBUG */ #ifdef MAC_CORE_VERBOSE_DEBUG # define VDBUG(MSG) do { printf("||PaMacCore (v )|| "); printf MSG ; fflush(stdout); } while(0) #else # define VDBUG(MSG) #endif /* Very Verbose Debugging: Traces every call. */ /* #define MAC_CORE_VERY_VERBOSE_DEBUG */ #ifdef MAC_CORE_VERY_VERBOSE_DEBUG # define VVDBUG(MSG) do { printf("||PaMacCore (vv)|| "); printf MSG ; fflush(stdout); } while(0) #else # define VVDBUG(MSG) #endif #define UNIX_ERR(err) PaMacCore_SetUnixError( err, __LINE__ ) PaError PaMacCore_SetUnixError( int err, int line ); /* * Translates MacOS generated errors into PaErrors */ PaError PaMacCore_SetError(OSStatus error, int line, int isError); /* * This function computes an appropriate ring buffer size given * a requested latency (in seconds), sample rate and framesPerBuffer. * * The returned ringBufferSize is computed using the following * constraints: * - it must be at least 4. * - it must be at least 3x framesPerBuffer. * - it must be at least 2x the suggestedLatency. * - it must be a power of 2. * This function attempts to compute the minimum such size. * */ long computeRingBufferSize( const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, long inputFramesPerBuffer, long outputFramesPerBuffer, double sampleRate ); /* * Durring testing of core audio, I found that serious crashes could occur * if properties such as sample rate were changed multiple times in rapid * succession. The function below has some fancy logic to make sure that changes * are acknowledged before another is requested. That seems to help a lot. */ typedef struct { bool once; /* I didn't end up using this. bdr */ pthread_mutex_t mutex; } MutexAndBool ; OSStatus propertyProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void* inClientData ); /* sets the value of the given property and waits for the change to be acknowledged, and returns the final value, which is not guaranteed by this function to be the same as the desired value. Obviously, this function can only be used for data whose input and output are the same size and format, and their size and format are known in advance.*/ PaError AudioDeviceSetPropertyNowAndWaitForChange( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, UInt32 inPropertyDataSize, const void *inPropertyData, void *outPropertyData ); /* * Sets the sample rate the HAL device. * if requireExact: set the sample rate or fail. * * otherwise : set the exact sample rate. * If that fails, check for available sample rates, and choose one * higher than the requested rate. If there isn't a higher one, * just use the highest available. */ PaError setBestSampleRateForDevice( const AudioDeviceID device, const bool isOutput, const bool requireExact, const Float64 desiredSrate ); /* Attempts to set the requestedFramesPerBuffer. If it can't set the exact value, it settles for something smaller if available. If nothing smaller is available, it uses the smallest available size. actualFramesPerBuffer will be set to the actual value on successful return. OK to pass NULL to actualFramesPerBuffer. The logic is very simmilar too setBestSampleRate only failure here is not usually catastrophic. */ PaError setBestFramesPerBuffer( const AudioDeviceID device, const bool isOutput, UInt32 requestedFramesPerBuffer, UInt32 *actualFramesPerBuffer ); #endif /* PA_MAC_CORE_UTILITIES_H__*/ nyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core.c0000644000175000000620000027047011466723256023023 0ustar stevestaff/* * Implementation of the PortAudio API for Apple AUHAL * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file pa_mac_core @ingroup hostapi_src @author Bjorn Roche @brief AUHAL implementation of PortAudio */ /* FIXME: not all error conditions call PaUtil_SetLastHostErrorInfo() * PaMacCore_SetError() will do this. */ #include "pa_mac_core_internal.h" #include /* strlen(), memcmp() etc. */ #include #include "pa_mac_core.h" #include "pa_mac_core_utilities.h" #include "pa_mac_core_blocking.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* prototypes for functions declared in this file */ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); /* * Function declared in pa_mac_core.h. Sets up a PaMacCoreStreamInfoStruct * with the requested flags and initializes channel map. */ void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, const unsigned long flags ) { bzero( data, sizeof( PaMacCoreStreamInfo ) ); data->size = sizeof( PaMacCoreStreamInfo ); data->hostApiType = paCoreAudio; data->version = 0x01; data->flags = flags; data->channelMap = NULL; data->channelMapSize = 0; } /* * Function declared in pa_mac_core.h. Adds channel mapping to a PaMacCoreStreamInfoStruct */ void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, const unsigned long channelMapSize ) { data->channelMap = channelMap; data->channelMapSize = channelMapSize; } static char *channelName = NULL; static int channelNameSize = 0; static bool ensureChannelNameSize( int size ) { if( size >= channelNameSize ) { free( channelName ); channelName = (char *) malloc( ( channelNameSize = size ) + 1 ); if( !channelName ) { channelNameSize = 0; return false; } } return true; } /* * Function declared in pa_mac_core.h. retrives channel names. */ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ) { struct PaUtilHostApiRepresentation *hostApi; PaError err; OSStatus error; err = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); assert(err == paNoError); PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; UInt32 size = 0; error = AudioDeviceGetPropertyInfo( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyChannelName, &size, NULL ); if( error ) { //try the CFString CFStringRef name; bool isDeviceName = false; size = sizeof( name ); error = AudioDeviceGetProperty( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyChannelNameCFString, &size, &name ); if( error ) { //as a last-ditch effort, get the device name. Later we'll append the channel number. size = sizeof( name ); error = AudioDeviceGetProperty( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyDeviceNameCFString, &size, &name ); if( error ) return NULL; isDeviceName = true; } if( isDeviceName ) { name = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%@: %d"), name, channelIndex + 1 ); } CFIndex length = CFStringGetLength(name); while( ensureChannelNameSize( length * sizeof(UniChar) + 1 ) ) { if( CFStringGetCString( name, channelName, channelNameSize, kCFStringEncodingUTF8 ) ) { if( isDeviceName ) CFRelease( name ); return channelName; } if( length == 0 ) ++length; length *= 2; } if( isDeviceName ) CFRelease( name ); return NULL; } //continue with C string: if( !ensureChannelNameSize( size ) ) return NULL; error = AudioDeviceGetProperty( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyChannelName, &size, channelName ); if( error ) { ERR( error ); return NULL; } return channelName; } AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("PaMacCore_GetStreamInputHandle()\n")); return ( stream->inputDevice ); } AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("PaMacCore_GetStreamOutputHandle()\n")); return ( stream->outputDevice ); } #ifdef __cplusplus } #endif /* __cplusplus */ #define RING_BUFFER_ADVANCE_DENOMINATOR (4) static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static void setStreamStartTime( PaStream *stream ); static OSStatus AudioIOProc( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData ); static double GetStreamCpuLoad( PaStream* stream ); static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput); static PaError OpenAndSetupOneAudioUnit( const PaMacCoreStream *stream, const PaStreamParameters *inStreamParams, const PaStreamParameters *outStreamParams, const UInt32 requestedFramesPerBuffer, UInt32 *actualInputFramesPerBuffer, UInt32 *actualOutputFramesPerBuffer, const PaMacAUHAL *auhalHostApi, AudioUnit *audioUnit, AudioConverterRef *srConverter, AudioDeviceID *audioDevice, const double sampleRate, void *refCon ); /* for setting errors. */ #define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) /* * Callback for setting over/underrun flags. * */ static OSStatus xrunCallback( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void* inClientData) { PaMacCoreStream *stream = (PaMacCoreStream *) inClientData; if( stream->state != ACTIVE ) return 0; //if the stream isn't active, we don't care if the device is dropping if( isInput ) OSAtomicOr32( paInputUnderflow, (uint32_t *)&(stream->xrunFlags) ); else OSAtomicOr32( paOutputOverflow, (uint32_t *)&(stream->xrunFlags) ); return 0; } /* * Callback called when starting or stopping a stream. */ static void startStopCallback( void * inRefCon, AudioUnit ci, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement ) { PaMacCoreStream *stream = (PaMacCoreStream *) inRefCon; UInt32 isRunning; UInt32 size = sizeof( isRunning ); assert( !AudioUnitGetProperty( ci, kAudioOutputUnitProperty_IsRunning, inScope, inElement, &isRunning, &size ) ); if( isRunning ) return; //We are only interested in when we are stopping // -- if we are using 2 I/O units, we only need one notification! if( stream->inputUnit && stream->outputUnit && stream->inputUnit != stream->outputUnit && ci == stream->inputUnit ) return; PaStreamFinishedCallback *sfc = stream->streamRepresentation.streamFinishedCallback; if( stream->state == STOPPING ) stream->state = STOPPED ; if( sfc ) sfc( stream->streamRepresentation.userData ); } /*currently, this is only used in initialization, but it might be modified to be used when the list of devices changes.*/ static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) { UInt32 size; UInt32 propsize; VVDBUG(("gatherDeviceInfo()\n")); /* -- free any previous allocations -- */ if( auhalHostApi->devIds ) PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); auhalHostApi->devIds = NULL; /* -- figure out how many devices there are -- */ AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &propsize, NULL ); auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); /* -- copy the device IDs -- */ auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( auhalHostApi->allocations, propsize ); if( !auhalHostApi->devIds ) return paInsufficientMemory; AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &propsize, auhalHostApi->devIds ); #ifdef MAC_CORE_VERBOSE_DEBUG { int i; for( i=0; idevCount; ++i ) printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); } #endif size = sizeof(AudioDeviceID); auhalHostApi->defaultIn = kAudioDeviceUnknown; auhalHostApi->defaultOut = kAudioDeviceUnknown; /* determine the default device. */ /* I am not sure how these calls to AudioHardwareGetProperty() could fail, but in case they do, we use the first available device as the default. */ if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, &auhalHostApi->defaultIn) ) { int i; auhalHostApi->defaultIn = kAudioDeviceUnknown; VDBUG(("Failed to get default input device from OS.")); VDBUG((" I will substitute the first available input Device.")); for( i=0; idevCount; ++i ) { PaDeviceInfo devInfo; if( 0 != GetChannelInfo( auhalHostApi, &devInfo, auhalHostApi->devIds[i], TRUE ) ) if( devInfo.maxInputChannels ) { auhalHostApi->defaultIn = auhalHostApi->devIds[i]; break; } } } if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &auhalHostApi->defaultOut) ) { int i; auhalHostApi->defaultIn = kAudioDeviceUnknown; VDBUG(("Failed to get default output device from OS.")); VDBUG((" I will substitute the first available output Device.")); for( i=0; idevCount; ++i ) { PaDeviceInfo devInfo; if( 0 != GetChannelInfo( auhalHostApi, &devInfo, auhalHostApi->devIds[i], FALSE ) ) if( devInfo.maxOutputChannels ) { auhalHostApi->defaultOut = auhalHostApi->devIds[i]; break; } } } VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) ); VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) ); return paNoError; } static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput) { UInt32 propSize; PaError err = paNoError; UInt32 i; int numChannels = 0; AudioBufferList *buflist = NULL; UInt32 frameLatency; VVDBUG(("GetChannelInfo()\n")); /* Get the number of channels from the stream configuration. Fail if we can't get this. */ err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL)); if (err) return err; buflist = PaUtil_AllocateMemory(propSize); if( !buflist ) return paInsufficientMemory; err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist)); if (err) goto error; for (i = 0; i < buflist->mNumberBuffers; ++i) numChannels += buflist->mBuffers[i].mNumberChannels; if (isInput) deviceInfo->maxInputChannels = numChannels; else deviceInfo->maxOutputChannels = numChannels; if (numChannels > 0) /* do not try to retrieve the latency if there is no channels. */ { /* Get the latency. Don't fail if we can't get this. */ /* default to something reasonable */ deviceInfo->defaultLowInputLatency = .01; deviceInfo->defaultHighInputLatency = .10; deviceInfo->defaultLowOutputLatency = .01; deviceInfo->defaultHighOutputLatency = .10; propSize = sizeof(UInt32); err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency)); if (!err) { /** FEEDBACK: * This code was arrived at by trial and error, and some extentive, but not exhaustive * testing. Sebastien Beaulieu has suggested using * kAudioDevicePropertyLatency + kAudioDevicePropertySafetyOffset + buffer size instead. * At the time this code was written, many users were reporting dropouts with audio * programs that probably used this formula. This was probably * around 10.4.4, and the problem is probably fixed now. So perhaps * his formula should be reviewed and used. * */ double secondLatency = frameLatency / deviceInfo->defaultSampleRate; if (isInput) { deviceInfo->defaultLowInputLatency = 3 * secondLatency; deviceInfo->defaultHighInputLatency = 3 * 10 * secondLatency; } else { deviceInfo->defaultLowOutputLatency = 3 * secondLatency; deviceInfo->defaultHighOutputLatency = 3 * 10 * secondLatency; } } } PaUtil_FreeMemory( buflist ); return paNoError; error: PaUtil_FreeMemory( buflist ); return err; } static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex ) { Float64 sampleRate; char *name; PaError err = paNoError; UInt32 propSize; VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId)); memset(deviceInfo, 0, sizeof(deviceInfo)); deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; /* Get the device name. Fail if we can't get it. */ err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); if (err) return err; name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize); if ( !name ) return paInsufficientMemory; err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); if (err) return err; deviceInfo->name = name; /* Try to get the default sample rate. Don't fail if we can't get this. */ propSize = sizeof(Float64); err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate)); if (err) deviceInfo->defaultSampleRate = 0.0; else deviceInfo->defaultSampleRate = sampleRate; /* Get the maximum number of input and output channels. Fail if we can't get this. */ err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 1); if (err) return err; err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 0); if (err) return err; return paNoError; } PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; int i; PaMacAUHAL *auhalHostApi; PaDeviceInfo *deviceInfoArray; VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex)); auhalHostApi = (PaMacAUHAL*)PaUtil_AllocateMemory( sizeof(PaMacAUHAL) ); if( !auhalHostApi ) { result = paInsufficientMemory; goto error; } auhalHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !auhalHostApi->allocations ) { result = paInsufficientMemory; goto error; } auhalHostApi->devIds = NULL; auhalHostApi->devCount = 0; /* get the info we need about the devices */ result = gatherDeviceInfo( auhalHostApi ); if( result != paNoError ) goto error; *hostApi = &auhalHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paCoreAudio; (*hostApi)->info.name = "Core Audio"; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; (*hostApi)->info.deviceCount = 0; if( auhalHostApi->devCount > 0 ) { (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount); if( !(*hostApi)->deviceInfos ) { result = paInsufficientMemory; goto error; } /* allocate all device info structs in a contiguous block */ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount ); if( !deviceInfoArray ) { result = paInsufficientMemory; goto error; } for( i=0; i < auhalHostApi->devCount; ++i ) { int err; err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i], auhalHostApi->devIds[i], hostApiIndex ); if (err == paNoError) { /* copy some info and set the defaults */ (*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i]; if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn) (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut) (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; (*hostApi)->info.deviceCount++; } else { /* there was an error. we need to shift the devices down, so we ignore this one */ int j; auhalHostApi->devCount--; for( j=i; jdevCount; ++j ) auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1]; i--; } } } (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &auhalHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if( auhalHostApi ) { if( auhalHostApi->allocations ) { PaUtil_FreeAllAllocations( auhalHostApi->allocations ); PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); } PaUtil_FreeMemory( auhalHostApi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; VVDBUG(("Terminate()\n")); /* IMPLEMENT ME: - clean up any resources not handled by the allocation group TODO: Double check that everything is handled by alloc group */ if( auhalHostApi->allocations ) { PaUtil_FreeAllAllocations( auhalHostApi->allocations ); PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); } PaUtil_FreeMemory( auhalHostApi ); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; VVDBUG(("IsFormatSupported(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld sampleRate=%g\n", inputParameters ? inputParameters->channelCount : -1, inputParameters ? inputParameters->sampleFormat : -1, outputParameters ? outputParameters->channelCount : -1, outputParameters ? outputParameters->sampleFormat : -1, (float) sampleRate )); /** These first checks are standard PA checks. We do some fancier checks later. */ if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support outputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; } else { outputChannelCount = 0; } /* FEEDBACK */ /* I think the only way to check a given format SR combo is */ /* to try opening it. This could be disruptive, is that Okay? */ /* The alternative is to just read off available sample rates, */ /* but this will not work %100 of the time (eg, a device that */ /* supports N output at one rate but only N/2 at a higher rate.)*/ /* The following code opens the device with the requested parameters to see if it works. */ { PaError err; PaStream *s; err = OpenStream( hostApi, &s, inputParameters, outputParameters, sampleRate, 1024, 0, (PaStreamCallback *)1, NULL ); if( err != paNoError && err != paInvalidSampleRate ) DBUG( ( "OpenStream @ %g returned: %d: %s\n", (float) sampleRate, err, Pa_GetErrorText( err ) ) ); if( err ) return err; err = CloseStream( s ); if( err ) { /* FEEDBACK: is this more serious? should we assert? */ DBUG( ( "WARNING: could not close Stream. %d: %s\n", err, Pa_GetErrorText( err ) ) ); } } return paFormatIsSupported; } static PaError OpenAndSetupOneAudioUnit( const PaMacCoreStream *stream, const PaStreamParameters *inStreamParams, const PaStreamParameters *outStreamParams, const UInt32 requestedFramesPerBuffer, UInt32 *actualInputFramesPerBuffer, UInt32 *actualOutputFramesPerBuffer, const PaMacAUHAL *auhalHostApi, AudioUnit *audioUnit, AudioConverterRef *srConverter, AudioDeviceID *audioDevice, const double sampleRate, void *refCon ) { ComponentDescription desc; Component comp; /*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/ AudioStreamBasicDescription desiredFormat; OSStatus result = noErr; PaError paResult = paNoError; int line = 0; UInt32 callbackKey; AURenderCallbackStruct rcbs; unsigned long macInputStreamFlags = paMacCorePlayNice; unsigned long macOutputStreamFlags = paMacCorePlayNice; SInt32 const *inChannelMap = NULL; SInt32 const *outChannelMap = NULL; unsigned long inChannelMapSize = 0; unsigned long outChannelMapSize = 0; VVDBUG(("OpenAndSetupOneAudioUnit(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld, requestedFramesPerBuffer=%ld\n", inStreamParams ? inStreamParams->channelCount : -1, inStreamParams ? inStreamParams->sampleFormat : -1, outStreamParams ? outStreamParams->channelCount : -1, outStreamParams ? outStreamParams->sampleFormat : -1, requestedFramesPerBuffer )); /* -- handle the degenerate case -- */ if( !inStreamParams && !outStreamParams ) { *audioUnit = NULL; *audioDevice = kAudioDeviceUnknown; return paNoError; } /* -- get the user's api specific info, if they set any -- */ if( inStreamParams && inStreamParams->hostApiSpecificStreamInfo ) { macInputStreamFlags= ((PaMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) ->flags; inChannelMap = ((PaMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) ->channelMap; inChannelMapSize = ((PaMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) ->channelMapSize; } if( outStreamParams && outStreamParams->hostApiSpecificStreamInfo ) { macOutputStreamFlags= ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) ->flags; outChannelMap = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) ->channelMap; outChannelMapSize = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) ->channelMapSize; } /* Override user's flags here, if desired for testing. */ /* * The HAL AU is a Mac OS style "component". * the first few steps deal with that. * Later steps work on a combination of Mac OS * components and the slightly lower level * HAL. */ /* -- describe the output type AudioUnit -- */ /* Note: for the default AudioUnit, we could use the * componentSubType value kAudioUnitSubType_DefaultOutput; * but I don't think that's relevant here. */ desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; /* -- find the component -- */ comp = FindNextComponent( NULL, &desc ); if( !comp ) { DBUG( ( "AUHAL component not found." ) ); *audioUnit = NULL; *audioDevice = kAudioDeviceUnknown; return paUnanticipatedHostError; } /* -- open it -- */ result = OpenAComponent( comp, audioUnit ); if( result ) { DBUG( ( "Failed to open AUHAL component." ) ); *audioUnit = NULL; *audioDevice = kAudioDeviceUnknown; return ERR( result ); } /* -- prepare a little error handling logic / hackery -- */ #define ERR_WRAP(mac_err) do { result = mac_err ; line = __LINE__ ; if ( result != noErr ) goto error ; } while(0) /* -- if there is input, we have to explicitly enable input -- */ if( inStreamParams ) { UInt32 enableIO = 1; ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, INPUT_ELEMENT, &enableIO, sizeof(enableIO) ) ); } /* -- if there is no output, we must explicitly disable output -- */ if( !outStreamParams ) { UInt32 enableIO = 0; ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, OUTPUT_ELEMENT, &enableIO, sizeof(enableIO) ) ); } /* -- set the devices -- */ /* make sure input and output are the same device if we are doing input and output. */ if( inStreamParams && outStreamParams ) { assert( outStreamParams->device == inStreamParams->device ); } if( inStreamParams ) { *audioDevice = auhalHostApi->devIds[inStreamParams->device] ; ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, INPUT_ELEMENT, audioDevice, sizeof(AudioDeviceID) ) ); } if( outStreamParams && outStreamParams != inStreamParams ) { *audioDevice = auhalHostApi->devIds[outStreamParams->device] ; ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, OUTPUT_ELEMENT, audioDevice, sizeof(AudioDeviceID) ) ); } /* -- add listener for dropouts -- */ ERR_WRAP( AudioDeviceAddPropertyListener( *audioDevice, 0, outStreamParams ? false : true, kAudioDeviceProcessorOverload, xrunCallback, (void *)stream) ); /* -- listen for stream start and stop -- */ ERR_WRAP( AudioUnitAddPropertyListener( *audioUnit, kAudioOutputUnitProperty_IsRunning, startStopCallback, (void *)stream ) ); /* -- set format -- */ bzero( &desiredFormat, sizeof(desiredFormat) ); desiredFormat.mFormatID = kAudioFormatLinearPCM ; desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; desiredFormat.mFramesPerPacket = 1; desiredFormat.mBitsPerChannel = sizeof( float ) * 8; result = 0; /* set device format first, but only touch the device if the user asked */ if( inStreamParams ) { /*The callback never calls back if we don't set the FPB */ /*This seems wierd, because I would think setting anything on the device would be disruptive.*/ paResult = setBestFramesPerBuffer( *audioDevice, FALSE, requestedFramesPerBuffer, actualInputFramesPerBuffer ); if( paResult ) goto error; if( macInputStreamFlags & paMacCoreChangeDeviceParameters ) { bool requireExact; requireExact=macInputStreamFlags & paMacCoreFailIfConversionRequired; paResult = setBestSampleRateForDevice( *audioDevice, FALSE, requireExact, sampleRate ); if( paResult ) goto error; } if( actualInputFramesPerBuffer && actualOutputFramesPerBuffer ) *actualOutputFramesPerBuffer = *actualInputFramesPerBuffer ; } if( outStreamParams && !inStreamParams ) { /*The callback never calls back if we don't set the FPB */ /*This seems wierd, because I would think setting anything on the device would be disruptive.*/ paResult = setBestFramesPerBuffer( *audioDevice, TRUE, requestedFramesPerBuffer, actualOutputFramesPerBuffer ); if( paResult ) goto error; if( macOutputStreamFlags & paMacCoreChangeDeviceParameters ) { bool requireExact; requireExact=macOutputStreamFlags & paMacCoreFailIfConversionRequired; paResult = setBestSampleRateForDevice( *audioDevice, TRUE, requireExact, sampleRate ); if( paResult ) goto error; } } /* -- set the quality of the output converter -- */ if( outStreamParams ) { UInt32 value = kAudioConverterQuality_Max; switch( macOutputStreamFlags & 0x0700 ) { case 0x0100: /*paMacCore_ConversionQualityMin:*/ value=kRenderQuality_Min; break; case 0x0200: /*paMacCore_ConversionQualityLow:*/ value=kRenderQuality_Low; break; case 0x0300: /*paMacCore_ConversionQualityMedium:*/ value=kRenderQuality_Medium; break; case 0x0400: /*paMacCore_ConversionQualityHigh:*/ value=kRenderQuality_High; break; } ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, OUTPUT_ELEMENT, &value, sizeof(value) ) ); } /* now set the format on the Audio Units. */ if( outStreamParams ) { desiredFormat.mSampleRate =sampleRate; desiredFormat.mBytesPerPacket=sizeof(float)*outStreamParams->channelCount; desiredFormat.mBytesPerFrame =sizeof(float)*outStreamParams->channelCount; desiredFormat.mChannelsPerFrame = outStreamParams->channelCount; ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, OUTPUT_ELEMENT, &desiredFormat, sizeof(AudioStreamBasicDescription) ) ); } if( inStreamParams ) { AudioStreamBasicDescription sourceFormat; UInt32 size = sizeof( AudioStreamBasicDescription ); /* keep the sample rate of the device, or we confuse AUHAL */ ERR_WRAP( AudioUnitGetProperty( *audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, INPUT_ELEMENT, &sourceFormat, &size ) ); desiredFormat.mSampleRate = sourceFormat.mSampleRate; desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount; desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount; desiredFormat.mChannelsPerFrame = inStreamParams->channelCount; ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, INPUT_ELEMENT, &desiredFormat, sizeof(AudioStreamBasicDescription) ) ); } /* set the maximumFramesPerSlice */ /* not doing this causes real problems (eg. the callback might not be called). The idea of setting both this and the frames per buffer on the device is that we'll be most likely to actually get the frame size we requested in the callback with the minimum latency. */ if( outStreamParams ) { UInt32 size = sizeof( *actualOutputFramesPerBuffer ); ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Input, OUTPUT_ELEMENT, actualOutputFramesPerBuffer, sizeof(*actualOutputFramesPerBuffer) ) ); ERR_WRAP( AudioUnitGetProperty( *audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, OUTPUT_ELEMENT, actualOutputFramesPerBuffer, &size ) ); } if( inStreamParams ) { /*UInt32 size = sizeof( *actualInputFramesPerBuffer );*/ ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, INPUT_ELEMENT, actualInputFramesPerBuffer, sizeof(*actualInputFramesPerBuffer) ) ); /* Don't know why this causes problems ERR_WRAP( AudioUnitGetProperty( *audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, //Output, INPUT_ELEMENT, actualInputFramesPerBuffer, &size ) ); */ } /* -- if we have input, we may need to setup an SR converter -- */ /* even if we got the sample rate we asked for, we need to do the conversion in case another program changes the underlying SR. */ /* FIXME: I think we need to monitor stream and change the converter if the incoming format changes. */ if( inStreamParams ) { AudioStreamBasicDescription desiredFormat; AudioStreamBasicDescription sourceFormat; UInt32 sourceSize = sizeof( sourceFormat ); bzero( &desiredFormat, sizeof(desiredFormat) ); desiredFormat.mSampleRate = sampleRate; desiredFormat.mFormatID = kAudioFormatLinearPCM ; desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; desiredFormat.mFramesPerPacket = 1; desiredFormat.mBitsPerChannel = sizeof( float ) * 8; desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount; desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount; desiredFormat.mChannelsPerFrame = inStreamParams->channelCount; /* get the source format */ ERR_WRAP( AudioUnitGetProperty( *audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, INPUT_ELEMENT, &sourceFormat, &sourceSize ) ); if( desiredFormat.mSampleRate != sourceFormat.mSampleRate ) { UInt32 value = kAudioConverterQuality_Max; switch( macInputStreamFlags & 0x0700 ) { case 0x0100: /*paMacCore_ConversionQualityMin:*/ value=kAudioConverterQuality_Min; break; case 0x0200: /*paMacCore_ConversionQualityLow:*/ value=kAudioConverterQuality_Low; break; case 0x0300: /*paMacCore_ConversionQualityMedium:*/ value=kAudioConverterQuality_Medium; break; case 0x0400: /*paMacCore_ConversionQualityHigh:*/ value=kAudioConverterQuality_High; break; } VDBUG(( "Creating sample rate converter for input" " to convert from %g to %g\n", (float)sourceFormat.mSampleRate, (float)desiredFormat.mSampleRate ) ); /* create our converter */ ERR_WRAP( AudioConverterNew( &sourceFormat, &desiredFormat, srConverter ) ); /* Set quality */ ERR_WRAP( AudioConverterSetProperty( *srConverter, kAudioConverterSampleRateConverterQuality, sizeof( value ), &value ) ); } } /* -- set IOProc (callback) -- */ callbackKey = outStreamParams ? kAudioUnitProperty_SetRenderCallback : kAudioOutputUnitProperty_SetInputCallback ; rcbs.inputProc = AudioIOProc; rcbs.inputProcRefCon = refCon; ERR_WRAP( AudioUnitSetProperty( *audioUnit, callbackKey, kAudioUnitScope_Output, outStreamParams ? OUTPUT_ELEMENT : INPUT_ELEMENT, &rcbs, sizeof(rcbs)) ); if( inStreamParams && outStreamParams && *srConverter ) ERR_WRAP( AudioUnitSetProperty( *audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Output, INPUT_ELEMENT, &rcbs, sizeof(rcbs)) ); /* channel mapping. */ if(inChannelMap) { UInt32 mapSize = inChannelMapSize *sizeof(SInt32); //for each channel of desired input, map the channel from //the device's output channel. ERR_WRAP( AudioUnitSetProperty(*audioUnit, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, INPUT_ELEMENT, inChannelMap, mapSize)); } if(outChannelMap) { UInt32 mapSize = outChannelMapSize *sizeof(SInt32); //for each channel of desired output, map the channel from //the device's output channel. ERR_WRAP(AudioUnitSetProperty(*audioUnit, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, OUTPUT_ELEMENT, outChannelMap, mapSize)); } /* initialize the audio unit */ ERR_WRAP( AudioUnitInitialize(*audioUnit) ); if( inStreamParams && outStreamParams ) VDBUG( ("Opened device %ld for input and output.\n", *audioDevice ) ); else if( inStreamParams ) VDBUG( ("Opened device %ld for input.\n", *audioDevice ) ); else if( outStreamParams ) VDBUG( ("Opened device %ld for output.\n", *audioDevice ) ); return paNoError; #undef ERR_WRAP error: CloseComponent( *audioUnit ); *audioUnit = NULL; if( result ) return PaMacCore_SetError( result, line, 1 ); return paResult; } /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; PaMacCoreStream *stream = 0; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n", inputParameters ? inputParameters->channelCount : -1, inputParameters ? inputParameters->sampleFormat : -1, outputParameters ? outputParameters->channelCount : -1, outputParameters ? outputParameters->sampleFormat : -1, (float) sampleRate, framesPerBuffer )); VDBUG( ("Opening Stream.\n") ); /*These first few bits of code are from paSkeleton with few modifications.*/ if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* Host supports interleaved float32 */ hostInputSampleFormat = paFloat32; } else { inputChannelCount = 0; inputSampleFormat = hostInputSampleFormat = paFloat32; /* Surpress 'uninitialised var' warnings. */ } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* Host supports interleaved float32 */ hostOutputSampleFormat = paFloat32; } else { outputChannelCount = 0; outputSampleFormat = hostOutputSampleFormat = paFloat32; /* Surpress 'uninitialized var' warnings. */ } /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ stream = (PaMacCoreStream*)PaUtil_AllocateMemory( sizeof(PaMacCoreStream) ); if( !stream ) { result = paInsufficientMemory; goto error; } /* If we fail after this point, we my be left in a bad state, with some data structures setup and others not. So, first thing we do is initialize everything so that if we fail, we know what hasn't been touched. */ stream->inputAudioBufferList.mBuffers[0].mData = NULL; stream->inputRingBuffer.buffer = NULL; bzero( &stream->blio, sizeof( PaMacBlio ) ); /* stream->blio.inputRingBuffer.buffer = NULL; stream->blio.outputRingBuffer.buffer = NULL; stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0; stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat); stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0; stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat); */ stream->inputSRConverter = NULL; stream->inputUnit = NULL; stream->outputUnit = NULL; stream->inputFramesPerBuffer = 0; stream->outputFramesPerBuffer = 0; stream->bufferProcessorIsInitialized = FALSE; /* assert( streamCallback ) ; */ /* only callback mode is implemented */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &auhalHostApi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &auhalHostApi->blockingStreamInterface, BlioCallback, &stream->blio ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); /* -- handle paFramesPerBufferUnspecified -- */ if( framesPerBuffer == paFramesPerBufferUnspecified ) { long requested = 64; if( inputParameters ) requested = MAX( requested, inputParameters->suggestedLatency * sampleRate / 2 ); if( outputParameters ) requested = MAX( requested, outputParameters->suggestedLatency *sampleRate / 2 ); VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n", requested ) ); if( requested <= 64 ) { /*requested a realtively low latency. make sure this is in range of devices */ /*try to get the device's min natural buffer size and use that (but no smaller than 64).*/ AudioValueRange audioRange; UInt32 size = sizeof( audioRange ); if( inputParameters ) { WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device], 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &audioRange ) ); if( result ) requested = MAX( requested, audioRange.mMinimum ); } size = sizeof( audioRange ); if( outputParameters ) { WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device], 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &audioRange ) ); if( result ) requested = MAX( requested, audioRange.mMinimum ); } } else { /* requested a realtively high latency. make sure this is in range of devices */ /*try to get the device's max natural buffer size and use that (but no larger than 1024).*/ AudioValueRange audioRange; UInt32 size = sizeof( audioRange ); requested = MIN( requested, 1024 ); if( inputParameters ) { WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device], 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &audioRange ) ); if( result ) requested = MIN( requested, audioRange.mMaximum ); } size = sizeof( audioRange ); if( outputParameters ) { WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device], 0, false, kAudioDevicePropertyBufferFrameSizeRange, &size, &audioRange ) ); if( result ) requested = MIN( requested, audioRange.mMaximum ); } } /* -- double check ranges -- */ if( requested > 1024 ) requested = 1024; if( requested < 64 ) requested = 64; VDBUG(("After querying hardware, setting block size to %ld.\n", requested)); framesPerBuffer = requested; } /* -- Now we actually open and setup streams. -- */ if( inputParameters && outputParameters && outputParameters->device == inputParameters->device ) { /* full duplex. One device. */ UInt32 inputFramesPerBuffer = (UInt32) stream->inputFramesPerBuffer; UInt32 outputFramesPerBuffer = (UInt32) stream->outputFramesPerBuffer; result = OpenAndSetupOneAudioUnit( stream, inputParameters, outputParameters, framesPerBuffer, &inputFramesPerBuffer, &outputFramesPerBuffer, auhalHostApi, &(stream->inputUnit), &(stream->inputSRConverter), &(stream->inputDevice), sampleRate, stream ); stream->inputFramesPerBuffer = inputFramesPerBuffer; stream->outputFramesPerBuffer = outputFramesPerBuffer; stream->outputUnit = stream->inputUnit; stream->outputDevice = stream->inputDevice; if( result != paNoError ) goto error; } else { /* full duplex, different devices OR simplex */ UInt32 outputFramesPerBuffer = (UInt32) stream->outputFramesPerBuffer; UInt32 inputFramesPerBuffer = (UInt32) stream->inputFramesPerBuffer; result = OpenAndSetupOneAudioUnit( stream, NULL, outputParameters, framesPerBuffer, NULL, &outputFramesPerBuffer, auhalHostApi, &(stream->outputUnit), NULL, &(stream->outputDevice), sampleRate, stream ); if( result != paNoError ) goto error; result = OpenAndSetupOneAudioUnit( stream, inputParameters, NULL, framesPerBuffer, &inputFramesPerBuffer, NULL, auhalHostApi, &(stream->inputUnit), &(stream->inputSRConverter), &(stream->inputDevice), sampleRate, stream ); if( result != paNoError ) goto error; stream->inputFramesPerBuffer = inputFramesPerBuffer; stream->outputFramesPerBuffer = outputFramesPerBuffer; } if( stream->inputUnit ) { const size_t szfl = sizeof(float); /* setup the AudioBufferList used for input */ bzero( &stream->inputAudioBufferList, sizeof( AudioBufferList ) ); stream->inputAudioBufferList.mNumberBuffers = 1; stream->inputAudioBufferList.mBuffers[0].mNumberChannels = inputChannelCount; stream->inputAudioBufferList.mBuffers[0].mDataByteSize = stream->inputFramesPerBuffer*inputChannelCount*szfl; stream->inputAudioBufferList.mBuffers[0].mData = (float *) calloc( stream->inputFramesPerBuffer*inputChannelCount, szfl ); if( !stream->inputAudioBufferList.mBuffers[0].mData ) { result = paInsufficientMemory; goto error; } /* * If input and output devs are different or we are doing SR conversion, * we also need a * ring buffer to store inpt data while waiting for output * data. */ if( (stream->outputUnit && stream->inputUnit != stream->outputUnit) || stream->inputSRConverter ) { /* May want the ringSize ot initial position in ring buffer to depend somewhat on sample rate change */ void *data; long ringSize; ringSize = computeRingBufferSize( inputParameters, outputParameters, stream->inputFramesPerBuffer, stream->outputFramesPerBuffer, sampleRate ); /*ringSize <<= 4; *//*16x bigger, for testing */ /*now, we need to allocate memory for the ring buffer*/ data = calloc( ringSize, szfl ); if( !data ) { result = paInsufficientMemory; goto error; } /* now we can initialize the ring buffer */ PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, ringSize*szfl, data ) ; /* advance the read point a little, so we are reading from the middle of the buffer */ if( stream->outputUnit ) PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, ringSize*szfl / RING_BUFFER_ADVANCE_DENOMINATOR ); } } /* -- initialize Blio Buffer Processors -- */ if( !streamCallback ) { long ringSize; ringSize = computeRingBufferSize( inputParameters, outputParameters, stream->inputFramesPerBuffer, stream->outputFramesPerBuffer, sampleRate ); result = initializeBlioRingBuffers( &stream->blio, inputParameters?inputParameters->sampleFormat:0 , outputParameters?outputParameters->sampleFormat:0 , MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer), ringSize, inputParameters?inputChannelCount:0 , outputParameters?outputChannelCount:0 ) ; if( result != paNoError ) goto error; } /* -- initialize Buffer Processor -- */ { unsigned long maxHostFrames = stream->inputFramesPerBuffer; if( stream->outputFramesPerBuffer > maxHostFrames ) maxHostFrames = stream->outputFramesPerBuffer; result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, /* If sample rate conversion takes place, the buffer size will not be known. */ maxHostFrames, stream->inputSRConverter ? paUtilUnknownHostBufferSize : paUtilBoundedHostBufferSize, streamCallback ? streamCallback : BlioCallback, streamCallback ? userData : &stream->blio ); if( result != paNoError ) goto error; } stream->bufferProcessorIsInitialized = TRUE; /* IMPLEMENT ME: initialise the following fields with estimated or actual values. I think this is okay the way it is br 12/1/05 maybe need to change input latency estimate if IO devs differ */ stream->streamRepresentation.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)/sampleRate; stream->streamRepresentation.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)/sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate; stream->sampleRate = sampleRate; stream->outDeviceSampleRate = 0; if( stream->outputUnit ) { Float64 rate; UInt32 size = sizeof( rate ); result = ERR( AudioDeviceGetProperty( stream->outputDevice, 0, FALSE, kAudioDevicePropertyNominalSampleRate, &size, &rate ) ); if( result ) goto error; stream->outDeviceSampleRate = rate; } stream->inDeviceSampleRate = 0; if( stream->inputUnit ) { Float64 rate; UInt32 size = sizeof( rate ); result = ERR( AudioDeviceGetProperty( stream->inputDevice, 0, TRUE, kAudioDevicePropertyNominalSampleRate, &size, &rate ) ); if( result ) goto error; stream->inDeviceSampleRate = rate; } stream->userInChan = inputChannelCount; stream->userOutChan = outputChannelCount; stream->isTimeSet = FALSE; stream->state = STOPPED; stream->xrunFlags = 0; *s = (PaStream*)stream; return result; error: CloseStream( stream ); return result; } PaTime GetStreamTime( PaStream *s ) { /* FIXME: I am not at all sure this timing info stuff is right. patest_sine_time reports negative latencies, which is wierd.*/ PaMacCoreStream *stream = (PaMacCoreStream*)s; AudioTimeStamp timeStamp; VVDBUG(("GetStreamTime()\n")); if ( !stream->isTimeSet ) return (PaTime)0; if ( stream->outputDevice ) { AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp); return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->outDeviceSampleRate; } else if ( stream->inputDevice ) { AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp); return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->inDeviceSampleRate; } else { return (PaTime)0; } } static void setStreamStartTime( PaStream *stream ) { /* FIXME: I am not at all sure this timing info stuff is right. patest_sine_time reports negative latencies, which is wierd.*/ PaMacCoreStream *s = (PaMacCoreStream *) stream; VVDBUG(("setStreamStartTime()\n")); if( s->outputDevice ) AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime); else if( s->inputDevice ) AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime); else bzero( &s->startTime, sizeof( s->startTime ) ); //FIXME: we need a memory barier here s->isTimeSet = TRUE; } static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp) { VVDBUG(("TimeStampToSecs()\n")); //printf( "ATS: %lu, %g, %g\n", timeStamp->mFlags, timeStamp->mSampleTime, timeStamp->mRateScalar ); if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid) return (timeStamp->mSampleTime / stream->sampleRate); else return 0; } #define RING_BUFFER_EMPTY (1000) static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter, UInt32*ioDataSize, void** outData, void*inUserData ) { void *dummyData; long dummySize; PaUtilRingBuffer *rb = (PaUtilRingBuffer *) inUserData; VVDBUG(("ringBufferIOProc()\n")); assert( sizeof( UInt32 ) == sizeof( long ) ); if( PaUtil_GetRingBufferReadAvailable( rb ) == 0 ) { *outData = NULL; *ioDataSize = 0; return RING_BUFFER_EMPTY; } PaUtil_GetRingBufferReadRegions( rb, *ioDataSize, outData, (long *)ioDataSize, &dummyData, &dummySize ); assert( *ioDataSize ); PaUtil_AdvanceRingBufferReadIndex( rb, *ioDataSize ); return noErr; } /* * Called by the AudioUnit API to process audio from the sound card. * This is where the magic happens. */ /* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */ static OSStatus AudioIOProc( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData ) { unsigned long framesProcessed = 0; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; PaMacCoreStream *stream = (PaMacCoreStream*)inRefCon; const bool isRender = inBusNumber == OUTPUT_ELEMENT; int callbackResult = paContinue ; VVDBUG(("AudioIOProc()\n")); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* -----------------------------------------------------------------*\ This output may be useful for debugging, But printing durring the callback is a bad enough idea that this is not enabled by enableing the usual debugging calls. \* -----------------------------------------------------------------*/ /* static int renderCount = 0; static int inputCount = 0; printf( "------------------- starting reder/input\n" ); if( isRender ) printf("Render callback (%d):\t", ++renderCount); else printf("Input callback (%d):\t", ++inputCount); printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount ); printf( "--- inBusNumber: %lu\n", inBusNumber ); printf( "--- inNumberFrames: %lu\n", inNumberFrames ); printf( "--- %x ioData\n", (unsigned) ioData ); if( ioData ) { int i=0; printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers ); for( i=0; imNumberBuffers; ++i ) printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize ); } ----------------------------------------------------------------- */ if( !stream->isTimeSet ) setStreamStartTime( stream ); if( isRender ) { AudioTimeStamp currentTime; timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp); AudioDeviceGetCurrentTime(stream->outputDevice, ¤tTime); timeInfo.currentTime = TimeStampToSecs(stream, ¤tTime); } if( isRender && stream->inputUnit == stream->outputUnit ) timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp); if( !isRender ) { AudioTimeStamp currentTime; timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp); AudioDeviceGetCurrentTime(stream->inputDevice, ¤tTime); timeInfo.currentTime = TimeStampToSecs(stream, ¤tTime); } //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime ); if( isRender && stream->inputUnit == stream->outputUnit && !stream->inputSRConverter ) { /* --------- Full Duplex, One Device, no SR Conversion ------- * * This is the lowest latency case, and also the simplest. * Input data and output data are available at the same time. * we do not use the input SR converter or the input ring buffer. * */ OSStatus err = 0; unsigned long frames; /* -- start processing -- */ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), &timeInfo, stream->xrunFlags ); stream->xrunFlags = 0; //FIXME: this flag also gets set outside by a callback, which calls the xrunCallback function. It should be in the same thread as the main audio callback, but the apple docs just use the word "usually" so it may be possible to loose an xrun notification, if that callback happens here. /* -- compute frames. do some checks -- */ assert( ioData->mNumberBuffers == 1 ); assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); frames = ioData->mBuffers[0].mDataByteSize; frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; /* -- copy and process input data -- */ err= AudioUnitRender(stream->inputUnit, ioActionFlags, inTimeStamp, INPUT_ELEMENT, inNumberFrames, &stream->inputAudioBufferList ); /* FEEDBACK: I'm not sure what to do when this call fails */ assert( !err ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, stream->inputAudioBufferList.mBuffers[0].mData, stream->inputAudioBufferList.mBuffers[0].mNumberChannels); /* -- Copy and process output data -- */ PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), 0, ioData->mBuffers[0].mData, ioData->mBuffers[0].mNumberChannels); /* -- complete processing -- */ framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); } else if( isRender ) { /* -------- Output Side of Full Duplex (Separate Devices or SR Conversion) * -- OR Simplex Output * * This case handles output data as in the full duplex case, * and, if there is input data, reads it off the ring buffer * and into the PA buffer processor. If sample rate conversion * is required on input, that is done here as well. */ unsigned long frames; /* Sometimes, when stopping a duplex stream we get erroneous xrun flags, so if this is our last run, clear the flags. */ int xrunFlags = stream->xrunFlags; /* if( xrunFlags & paInputUnderflow ) printf( "input underflow.\n" ); if( xrunFlags & paInputOverflow ) printf( "input overflow.\n" ); */ if( stream->state == STOPPING || stream->state == CALLBACK_STOPPED ) xrunFlags = 0; /* -- start processing -- */ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), &timeInfo, xrunFlags ); stream->xrunFlags = 0; /* FEEDBACK: we only send flags to Buf Proc once */ /* -- Copy and process output data -- */ assert( ioData->mNumberBuffers == 1 ); frames = ioData->mBuffers[0].mDataByteSize; frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), 0, ioData->mBuffers[0].mData, ioData->mBuffers[0].mNumberChannels); /* -- copy and process input data, and complete processing -- */ if( stream->inputUnit ) { const int flsz = sizeof( float ); /* Here, we read the data out of the ring buffer, through the audio converter. */ int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels; if( stream->inputSRConverter ) { OSStatus err; UInt32 size; float data[ inChan * frames ]; size = sizeof( data ); err = AudioConverterFillBuffer( stream->inputSRConverter, ringBufferIOProc, &stream->inputRingBuffer, &size, (void *)&data ); if( err == RING_BUFFER_EMPTY ) { /*the ring buffer callback underflowed */ err = 0; bzero( ((char *)data) + size, sizeof(data)-size ); stream->xrunFlags |= paInputUnderflow; } ERR( err ); assert( !err ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, data, inChan ); framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); } else { /* Without the AudioConverter is actually a bit more complex because we have to do a little buffer processing that the AudioConverter would otherwise handle for us. */ void *data1, *data2; long size1, size2; PaUtil_GetRingBufferReadRegions( &stream->inputRingBuffer, inChan*frames*flsz, &data1, &size1, &data2, &size2 ); if( size1 / ( flsz * inChan ) == frames ) { /* simplest case: all in first buffer */ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, data1, inChan ); framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1 ); } else if( ( size1 + size2 ) / ( flsz * inChan ) < frames ) { /*we underflowed. take what data we can, zero the rest.*/ unsigned char data[frames*inChan*flsz]; if( size1 ) memcpy( data, data1, size1 ); if( size2 ) memcpy( data+size1, data2, size2 ); bzero( data+size1+size2, frames*flsz*inChan - size1 - size2 ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, data, inChan ); framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); PaUtil_AdvanceRingBufferReadIndex( &stream->inputRingBuffer, size1+size2 ); /* flag underflow */ stream->xrunFlags |= paInputUnderflow; } else { /*we got all the data, but split between buffers*/ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), size1 / ( flsz * inChan ) ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, data1, inChan ); PaUtil_Set2ndInputFrameCount( &(stream->bufferProcessor), size2 / ( flsz * inChan ) ); PaUtil_Set2ndInterleavedInputChannels( &(stream->bufferProcessor), 0, data2, inChan ); framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1+size2 ); } } } else { framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); } } else { /* ------------------ Input * * First, we read off the audio data and put it in the ring buffer. * if this is an input-only stream, we need to process it more, * otherwise, we let the output case deal with it. */ OSStatus err = 0; int chan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels ; /* FIXME: looping here may not actually be necessary, but it was something I tried in testing. */ do { err= AudioUnitRender(stream->inputUnit, ioActionFlags, inTimeStamp, INPUT_ELEMENT, inNumberFrames, &stream->inputAudioBufferList ); if( err == -10874 ) inNumberFrames /= 2; } while( err == -10874 && inNumberFrames > 1 ); /* FEEDBACK: I'm not sure what to do when this call fails */ ERR( err ); assert( !err ); if( stream->inputSRConverter || stream->outputUnit ) { /* If this is duplex or we use a converter, put the data into the ring buffer. */ long bytesIn, bytesOut; bytesIn = sizeof( float ) * inNumberFrames * chan; bytesOut = PaUtil_WriteRingBuffer( &stream->inputRingBuffer, stream->inputAudioBufferList.mBuffers[0].mData, bytesIn ); if( bytesIn != bytesOut ) stream->xrunFlags |= paInputOverflow ; } else { /* for simplex input w/o SR conversion, just pop the data into the buffer processor.*/ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), &timeInfo, stream->xrunFlags ); stream->xrunFlags = 0; PaUtil_SetInputFrameCount( &(stream->bufferProcessor), inNumberFrames); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, stream->inputAudioBufferList.mBuffers[0].mData, chan ); framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); } if( !stream->outputUnit && stream->inputSRConverter ) { /* ------------------ Simplex Input w/ SR Conversion * * if this is a simplex input stream, we need to read off the buffer, * do our sample rate conversion and pass the results to the buffer * processor. * The logic here is complicated somewhat by the fact that we don't * know how much data is available, so we loop on reasonably sized * chunks, and let the BufferProcessor deal with the rest. * */ /*This might be too big or small depending on SR conversion*/ float data[ chan * inNumberFrames ]; OSStatus err; do { /*Run the buffer processor until we are out of data*/ UInt32 size; long f; size = sizeof( data ); err = AudioConverterFillBuffer( stream->inputSRConverter, ringBufferIOProc, &stream->inputRingBuffer, &size, (void *)data ); if( err != RING_BUFFER_EMPTY ) ERR( err ); assert( err == 0 || err == RING_BUFFER_EMPTY ); f = size / ( chan * sizeof(float) ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), f ); if( f ) { PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), &timeInfo, stream->xrunFlags ); stream->xrunFlags = 0; PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, data, chan ); framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); } } while( callbackResult == paContinue && !err ); } } switch( callbackResult ) { case paContinue: break; case paComplete: case paAbort: stream->isTimeSet = FALSE; stream->state = CALLBACK_STOPPED ; if( stream->outputUnit ) AudioOutputUnitStop(stream->outputUnit); if( stream->inputUnit ) AudioOutputUnitStop(stream->inputUnit); break; } PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); return noErr; } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { /* This may be called from a failed OpenStream. Therefore, each piece of info is treated seperately. */ PaError result = paNoError; PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("CloseStream()\n")); VDBUG( ( "Closing stream.\n" ) ); if( stream ) { if( stream->outputUnit ) AudioDeviceRemovePropertyListener( stream->outputDevice, 0, false, kAudioDeviceProcessorOverload, xrunCallback ); if( stream->inputUnit && stream->outputUnit != stream->inputUnit ) AudioDeviceRemovePropertyListener( stream->inputDevice, 0, true, kAudioDeviceProcessorOverload, xrunCallback ); if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { AudioUnitUninitialize( stream->outputUnit ); CloseComponent( stream->outputUnit ); } stream->outputUnit = NULL; if( stream->inputUnit ) { AudioUnitUninitialize( stream->inputUnit ); CloseComponent( stream->inputUnit ); stream->inputUnit = NULL; } if( stream->inputRingBuffer.buffer ) free( (void *) stream->inputRingBuffer.buffer ); stream->inputRingBuffer.buffer = NULL; /*TODO: is there more that needs to be done on error from AudioConverterDispose?*/ if( stream->inputSRConverter ) ERR( AudioConverterDispose( stream->inputSRConverter ) ); stream->inputSRConverter = NULL; if( stream->inputAudioBufferList.mBuffers[0].mData ) free( stream->inputAudioBufferList.mBuffers[0].mData ); stream->inputAudioBufferList.mBuffers[0].mData = NULL; result = destroyBlioRingBuffers( &stream->blio ); if( result ) return result; if( stream->bufferProcessorIsInitialized ) PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); } return result; } static PaError StartStream( PaStream *s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; OSStatus result = noErr; VVDBUG(("StartStream()\n")); VDBUG( ( "Starting stream.\n" ) ); #define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) /*FIXME: maybe want to do this on close/abort for faster start? */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); if( stream->inputSRConverter ) ERR_WRAP( AudioConverterReset( stream->inputSRConverter ) ); /* -- start -- */ stream->state = ACTIVE; if( stream->inputUnit ) { ERR_WRAP( AudioOutputUnitStart(stream->inputUnit) ); } if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) ); } //setStreamStartTime( stream ); //stream->isTimeSet = TRUE; return paNoError; #undef ERR_WRAP } // it's not clear from appl's docs that this really waits // until all data is flushed. static ComponentResult BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioUnitElement element ) { Boolean isRunning = 1; while( isRunning ) { UInt32 s = sizeof( isRunning ); ComponentResult err = AudioUnitGetProperty( audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global, element, &isRunning, &s ); if( err ) return err; Pa_Sleep( 100 ); } return noErr; } static PaError StopStream( PaStream *s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; OSStatus result = noErr; PaError paErr; VVDBUG(("StopStream()\n")); VDBUG( ("Waiting for BLIO.\n") ); waitUntilBlioWriteBufferIsFlushed( &stream->blio ); VDBUG( ( "Stopping stream.\n" ) ); stream->isTimeSet = FALSE; stream->state = STOPPING; #define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) /* -- stop and reset -- */ if( stream->inputUnit == stream->outputUnit && stream->inputUnit ) { ERR_WRAP( AudioOutputUnitStop(stream->inputUnit) ); ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->inputUnit,0) ); ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->inputUnit,1) ); ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 1) ); ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 0) ); } else { if( stream->inputUnit ) { ERR_WRAP(AudioOutputUnitStop(stream->inputUnit) ); ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->inputUnit,1) ); ERR_WRAP(AudioUnitReset(stream->inputUnit,kAudioUnitScope_Global,1)); } if( stream->outputUnit ) { ERR_WRAP(AudioOutputUnitStop(stream->outputUnit)); ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->outputUnit,0) ); ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0)); } } if( stream->inputRingBuffer.buffer ) { PaUtil_FlushRingBuffer( &stream->inputRingBuffer ); bzero( (void *)stream->inputRingBuffer.buffer, stream->inputRingBuffer.bufferSize ); /* advance the write point a little, so we are reading from the middle of the buffer. We'll need extra at the end because testing has shown that this helps. */ if( stream->outputUnit ) PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, stream->inputRingBuffer.bufferSize / RING_BUFFER_ADVANCE_DENOMINATOR ); } stream->xrunFlags = 0; stream->state = STOPPED; paErr = resetBlioRingBuffers( &stream->blio ); if( paErr ) return paErr; /* //stream->isTimeSet = FALSE; */ VDBUG( ( "Stream Stopped.\n" ) ); return paNoError; #undef ERR_WRAP } static PaError AbortStream( PaStream *s ) { VVDBUG(("AbortStream()->StopStream()\n")); VDBUG( ( "Aborting stream.\n" ) ); /* We have nothing faster than StopStream. */ return StopStream(s); } static PaError IsStreamStopped( PaStream *s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("IsStreamStopped()\n")); return stream->state == STOPPED ? 1 : 0; } static PaError IsStreamActive( PaStream *s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("IsStreamActive()\n")); return ( stream->state == ACTIVE || stream->state == STOPPING ); } static double GetStreamCpuLoad( PaStream* s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("GetStreamCpuLoad()\n")); return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } nyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c0000644000175000000620000004652411466723256024674 0ustar stevestaff/* * Implementation of the PortAudio API for Apple AUHAL * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src This file contains the implementation required for blocking I/O. It is separated from pa_mac_core.c simply to ease development. */ #include "pa_mac_core_blocking.h" #include "pa_mac_core_internal.h" #include #ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS # define OSAtomicOr32( a, b ) ( (*(b)) |= (a) ) # define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) ) #else # include #endif /* * This fnuction determines the size of a particular sample format. * if the format is not recognized, this returns zero. */ static size_t computeSampleSizeFromFormat( PaSampleFormat format ) { switch( format ) { case paFloat32: return 4; case paInt32: return 4; case paInt24: return 3; case paInt16: return 2; case paInt8: case paUInt8: return 1; default: return 0; } } /* * Same as computeSampleSizeFromFormat, except that if * the size is not a power of two, it returns the next power of two up */ static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format ) { switch( format ) { case paFloat32: return 4; case paInt32: return 4; case paInt24: return 4; case paInt16: return 2; case paInt8: case paUInt8: return 1; default: return 0; } } /* * Functions for initializing, resetting, and destroying BLIO structures. * */ /* This should be called with the relevant info when initializing a stream for callback. */ PaError initializeBlioRingBuffers( PaMacBlio *blio, PaSampleFormat inputSampleFormat, PaSampleFormat outputSampleFormat, size_t framesPerBuffer, long ringBufferSize, int inChan, int outChan ) { void *data; int result; /* zeroify things */ bzero( blio, sizeof( PaMacBlio ) ); /* this is redundant, but the buffers are used to check if the bufffers have been initialized, so we do it explicitly. */ blio->inputRingBuffer.buffer = NULL; blio->outputRingBuffer.buffer = NULL; /* initialize simple data */ blio->ringBufferFrames = ringBufferSize; blio->inputSampleFormat = inputSampleFormat; blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat); blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); blio->outputSampleFormat = outputSampleFormat; blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat); blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat); blio->framesPerBuffer = framesPerBuffer; blio->inChan = inChan; blio->outChan = outChan; blio->statusFlags = 0; blio->errors = paNoError; #ifdef PA_MAC_BLIO_MUTEX blio->isInputEmpty = false; blio->isOutputFull = false; #endif /* setup ring buffers */ #ifdef PA_MAC_BLIO_MUTEX result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 ); if( result ) goto error; result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) ); if( result ) goto error; result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) ); if( result ) goto error; result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) ); #endif if( inChan ) { data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan ); if( !data ) { result = paInsufficientMemory; goto error; } assert( 0 == PaUtil_InitializeRingBuffer( &blio->inputRingBuffer, ringBufferSize*blio->inputSampleSizePow2*inChan, data ) ); } if( outChan ) { data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan ); if( !data ) { result = paInsufficientMemory; goto error; } assert( 0 == PaUtil_InitializeRingBuffer( &blio->outputRingBuffer, ringBufferSize*blio->outputSampleSizePow2*outChan, data ) ); } result = resetBlioRingBuffers( blio ); if( result ) goto error; return 0; error: destroyBlioRingBuffers( blio ); return result; } #ifdef PA_MAC_BLIO_MUTEX PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty ) { PaError result = paNoError; if( isEmpty == blio->isInputEmpty ) goto done; /* we need to update the value. Here's what we do: * - Lock the mutex, so noone else can write. * - update the value. * - unlock. * - broadcast to all listeners. */ result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); if( result ) goto done; blio->isInputEmpty = isEmpty; result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); if( result ) goto done; result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) ); if( result ) goto done; done: return result; } PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull ) { PaError result = paNoError; if( isFull == blio->isOutputFull ) goto done; /* we need to update the value. Here's what we do: * - Lock the mutex, so noone else can write. * - update the value. * - unlock. * - broadcast to all listeners. */ result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); if( result ) goto done; blio->isOutputFull = isFull; result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); if( result ) goto done; result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) ); if( result ) goto done; done: return result; } #endif /* This should be called after stopping or aborting the stream, so that on next start, the buffers will be ready. */ PaError resetBlioRingBuffers( PaMacBlio *blio ) { #ifdef PA_MAC__BLIO_MUTEX int result; #endif blio->statusFlags = 0; if( blio->outputRingBuffer.buffer ) { PaUtil_FlushRingBuffer( &blio->outputRingBuffer ); bzero( blio->outputRingBuffer.buffer, blio->outputRingBuffer.bufferSize ); /* Advance buffer */ PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan ); //PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize ); /* Update isOutputFull. */ #ifdef PA_MAC__BLIO_MUTEX result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize ); if( result ) goto error; #endif /* printf( "------%d\n" , blio->framesPerBuffer ); printf( "------%d\n" , blio->outChan ); printf( "------%d\n" , blio->outputSampleSize ); printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize ); */ } if( blio->inputRingBuffer.buffer ) { PaUtil_FlushRingBuffer( &blio->inputRingBuffer ); bzero( blio->inputRingBuffer.buffer, blio->inputRingBuffer.bufferSize ); /* Update isInputEmpty. */ #ifdef PA_MAC__BLIO_MUTEX result = blioSetIsInputEmpty( blio, true ); if( result ) goto error; #endif } return paNoError; #ifdef PA_MAC__BLIO_MUTEX error: return result; #endif } /*This should be called when you are done with the blio. It can safely be called multiple times if there are no exceptions. */ PaError destroyBlioRingBuffers( PaMacBlio *blio ) { PaError result = paNoError; if( blio->inputRingBuffer.buffer ) { free( blio->inputRingBuffer.buffer ); #ifdef PA_MAC__BLIO_MUTEX result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) ); if( result ) return result; result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) ); if( result ) return result; #endif } blio->inputRingBuffer.buffer = NULL; if( blio->outputRingBuffer.buffer ) { free( blio->outputRingBuffer.buffer ); #ifdef PA_MAC__BLIO_MUTEX result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) ); if( result ) return result; result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) ); if( result ) return result; #endif } blio->outputRingBuffer.buffer = NULL; return result; } /* * this is the BlioCallback function. It expects to recieve a PaMacBlio Object * pointer as userData. * */ int BlioCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { PaMacBlio *blio = (PaMacBlio*)userData; long avail; long toRead; long toWrite; /* set flags returned by OS: */ OSAtomicOr32( statusFlags, &blio->statusFlags ) ; /* --- Handle Input Buffer --- */ if( blio->inChan ) { avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer ); /* check for underflow */ if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan ) OSAtomicOr32( paInputOverflow, &blio->statusFlags ); toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan ); /* copy the data */ /*printf( "reading %d\n", toRead );*/ assert( toRead == PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead ) ); #ifdef PA_MAC__BLIO_MUTEX /* Priority inversion. See notes below. */ blioSetIsInputEmpty( blio, false ); #endif } /* --- Handle Output Buffer --- */ if( blio->outChan ) { avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); /* check for underflow */ if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan ) OSAtomicOr32( paOutputUnderflow, &blio->statusFlags ); toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan ); if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan ) bzero( ((char *)output)+toWrite, frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite ); /* copy the data */ /*printf( "writing %d\n", toWrite );*/ assert( toWrite == PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite ) ); #ifdef PA_MAC__BLIO_MUTEX /* We have a priority inversion here. However, we will only have to wait if this was true and is now false, which means we've got some room in the buffer. Hopefully problems will be minimized. */ blioSetIsOutputFull( blio, false ); #endif } return paContinue; } PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ) { PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; char *cbuf = (char *) buffer; PaError ret = paNoError; VVDBUG(("ReadStream()\n")); while( frames > 0 ) { long avail; long toRead; do { avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); /* printf( "Read Buffer is %%%g full: %ld of %ld.\n", 100 * (float)avail / (float) blio->inputRingBuffer.bufferSize, avail, blio->inputRingBuffer.bufferSize ); */ if( avail == 0 ) { #ifdef PA_MAC_BLIO_MUTEX /**block when empty*/ ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); if( ret ) return ret; while( blio->isInputEmpty ) { ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) ); if( ret ) return ret; } ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); if( ret ) return ret; #else Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); #endif } } while( avail == 0 ); toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan ); toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ; PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead ); cbuf += toRead; frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan ); if( toRead == avail ) { #ifdef PA_MAC_BLIO_MUTEX /* we just emptied the buffer, so we need to mark it as empty. */ ret = blioSetIsInputEmpty( blio, true ); if( ret ) return ret; /* of course, in the meantime, the callback may have put some sats in, so so check for that, too, to avoid a race condition. */ if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) { blioSetIsInputEmpty( blio, false ); if( ret ) return ret; } #endif } } /* Report either paNoError or paInputOverflowed. */ /* may also want to report other errors, but this is non-standard. */ ret = blio->statusFlags & paInputOverflow; /* report underflow only once: */ if( ret ) { OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags ); ret = paInputOverflowed; } return ret; } PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ) { PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; char *cbuf = (char *) buffer; PaError ret = paNoError; VVDBUG(("WriteStream()\n")); while( frames > 0 ) { long avail = 0; long toWrite; do { avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); /* printf( "Write Buffer is %%%g full: %ld of %ld.\n", 100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize, avail, blio->outputRingBuffer.bufferSize ); */ if( avail == 0 ) { #ifdef PA_MAC_BLIO_MUTEX /*block while full*/ ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); if( ret ) return ret; while( blio->isOutputFull ) { ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) ); if( ret ) return ret; } ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); if( ret ) return ret; #else Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); #endif } } while( avail == 0 ); toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan ); toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ; PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite ); cbuf += toWrite; frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan ); #ifdef PA_MAC_BLIO_MUTEX if( toWrite == avail ) { /* we just filled up the buffer, so we need to mark it as filled. */ ret = blioSetIsOutputFull( blio, true ); if( ret ) return ret; /* of course, in the meantime, we may have emptied the buffer, so so check for that, too, to avoid a race condition. */ if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) { blioSetIsOutputFull( blio, false ); if( ret ) return ret; } } #endif } /* Report either paNoError or paOutputUnderflowed. */ /* may also want to report other errors, but this is non-standard. */ ret = blio->statusFlags & paOutputUnderflow; /* report underflow only once: */ if( ret ) { OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags ); ret = paOutputUnderflowed; } return ret; } /* * */ void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ) { if( blio->outputRingBuffer.buffer ) { long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); while( avail != blio->outputRingBuffer.bufferSize ) { if( avail == 0 ) Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); } } } signed long GetStreamReadAvailable( PaStream* stream ) { PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; VVDBUG(("GetStreamReadAvailable()\n")); return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) / ( blio->outputSampleSizeActual * blio->outChan ); } signed long GetStreamWriteAvailable( PaStream* stream ) { PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; VVDBUG(("GetStreamWriteAvailable()\n")); return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) / ( blio->outputSampleSizeActual * blio->outChan ); } nyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h0000644000175000000620000001104311466723256024665 0ustar stevestaff/* * Internal blocking interfaces for PortAudio Apple AUHAL implementation * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src */ #ifndef PA_MAC_CORE_BLOCKING_H_ #define PA_MAC_CORE_BLOCKING_H_ #include "pa_ringbuffer.h" #include "portaudio.h" #include "pa_mac_core_utilities.h" /* * Number of miliseconds to busy wait whil waiting for data in blocking calls. */ #define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5) /* * Define exactly one of these blocking methods * PA_MAC_BLIO_MUTEX is not actively maintained. */ #define PA_MAC_BLIO_BUSY_WAIT /* #define PA_MAC_BLIO_MUTEX */ typedef struct { PaUtilRingBuffer inputRingBuffer; PaUtilRingBuffer outputRingBuffer; size_t ringBufferFrames; PaSampleFormat inputSampleFormat; size_t inputSampleSizeActual; size_t inputSampleSizePow2; PaSampleFormat outputSampleFormat; size_t outputSampleSizeActual; size_t outputSampleSizePow2; size_t framesPerBuffer; int inChan; int outChan; //PaStreamCallbackFlags statusFlags; uint32_t statusFlags; PaError errors; /* Here we handle blocking, using condition variables. */ #ifdef PA_MAC_BLIO_MUTEX volatile bool isInputEmpty; pthread_mutex_t inputMutex; pthread_cond_t inputCond; volatile bool isOutputFull; pthread_mutex_t outputMutex; pthread_cond_t outputCond; #endif } PaMacBlio; /* * These functions operate on condition and related variables. */ PaError initializeBlioRingBuffers( PaMacBlio *blio, PaSampleFormat inputSampleFormat, PaSampleFormat outputSampleFormat, size_t framesPerBuffer, long ringBufferSize, int inChan, int outChan ); PaError destroyBlioRingBuffers( PaMacBlio *blio ); PaError resetBlioRingBuffers( PaMacBlio *blio ); int BlioCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ); void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ); #endif /*PA_MAC_CORE_BLOCKING_H_*/ nyquist-3.05/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c0000644000175000000620000010466111466723256023657 0ustar stevestaff/* * $Id: pa_mac_core_old.c,v 1.1 2010/11/04 21:04:36 rbd Exp $ * pa_mac_core.c * Implementation of PortAudio for Mac OS X CoreAudio * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Authors: Ross Bencina and Phil Burk * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ #include #include #include #include #include #include #include "portaudio.h" #include "pa_trace.h" #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" // ===== constants ===== // ===== structs ===== #pragma mark structs // PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation typedef struct PaMacCore_HAR { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; AudioDeviceID *macCoreDeviceIds; } PaMacCoreHostApiRepresentation; typedef struct PaMacCore_DI { PaDeviceInfo inheritedDeviceInfo; } PaMacCoreDeviceInfo; // PaMacCoreStream - a stream data structure specifically for this implementation typedef struct PaMacCore_S { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; int primeStreamUsingCallback; AudioDeviceID inputDevice; AudioDeviceID outputDevice; // Processing thread management -------------- // HANDLE abortEvent; // HANDLE processingThread; // DWORD processingThreadId; char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle int processingThreadPriority; int highThreadPriority; int throttledThreadPriority; unsigned long throttledSleepMsecs; int isStopped; volatile int isActive; volatile int stopProcessing; // stop thread once existing buffers have been returned volatile int abortProcessing; // stop thread immediately // DWORD allBuffersDurationMs; // used to calculate timeouts } PaMacCoreStream; // Data needed by the CoreAudio callback functions typedef struct PaMacCore_CD { PaMacCoreStream *stream; PaStreamCallback *callback; void *userData; PaUtilConverter *inputConverter; PaUtilConverter *outputConverter; void *inputBuffer; void *outputBuffer; int inputChannelCount; int outputChannelCount; PaSampleFormat inputSampleFormat; PaSampleFormat outputSampleFormat; PaUtilTriangularDitherGenerator *ditherGenerator; } PaMacClientData; // ===== CoreAudio-PortAudio bridge functions ===== #pragma mark CoreAudio-PortAudio bridge functions // Maps CoreAudio OSStatus codes to PortAudio PaError codes static PaError conv_err(OSStatus error) { PaError result; switch (error) { case kAudioHardwareNoError: result = paNoError; break; case kAudioHardwareNotRunningError: result = paInternalError; break; case kAudioHardwareUnspecifiedError: result = paInternalError; break; case kAudioHardwareUnknownPropertyError: result = paInternalError; break; case kAudioHardwareBadPropertySizeError: result = paInternalError; break; case kAudioHardwareIllegalOperationError: result = paInternalError; break; case kAudioHardwareBadDeviceError: result = paInvalidDevice; break; case kAudioHardwareBadStreamError: result = paBadStreamPtr; break; case kAudioHardwareUnsupportedOperationError: result = paInternalError; break; case kAudioDeviceUnsupportedFormatError: result = paSampleFormatNotSupported; break; case kAudioDevicePermissionsError: result = paDeviceUnavailable; break; default: result = paInternalError; } return result; } /* This function is unused static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate) { struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription)); streamDescription->mSampleRate = sampleRate; streamDescription->mFormatID = kAudioFormatLinearPCM; streamDescription->mFormatFlags = 0; streamDescription->mFramesPerPacket = 1; if (parameters->sampleFormat & paNonInterleaved) { streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved; streamDescription->mChannelsPerFrame = 1; streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat); streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat); } else { streamDescription->mChannelsPerFrame = parameters->channelCount; } streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame; streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket; if (parameters->sampleFormat & paFloat32) { streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat; streamDescription->mBitsPerChannel = 32; } else if (parameters->sampleFormat & paInt32) { streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; streamDescription->mBitsPerChannel = 32; } else if (parameters->sampleFormat & paInt24) { streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; streamDescription->mBitsPerChannel = 24; } else if (parameters->sampleFormat & paInt16) { streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; streamDescription->mBitsPerChannel = 16; } else if (parameters->sampleFormat & paInt8) { streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; streamDescription->mBitsPerChannel = 8; } else if (parameters->sampleFormat & paInt32) { streamDescription->mBitsPerChannel = 8; } return streamDescription; } */ static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime) { PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo)); timeInfo->inputBufferAdcTime = inputTime->mSampleTime; timeInfo->currentTime = now->mSampleTime; timeInfo->outputBufferDacTime = outputTime->mSampleTime; return timeInfo; } // ===== support functions ===== #pragma mark support functions static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi) { if( macCoreHostApi->allocations ) { PaUtil_FreeAllAllocations( macCoreHostApi->allocations ); PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations ); } PaUtil_FreeMemory( macCoreHostApi ); } static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput) { UInt32 propSize; PaError err = paNoError; UInt32 i; int numChannels = 0; AudioBufferList *buflist; err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL)); buflist = PaUtil_AllocateMemory(propSize); err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist)); if (!err) { for (i = 0; i < buflist->mNumberBuffers; ++i) { numChannels += buflist->mBuffers[i].mNumberChannels; } if (isInput) deviceInfo->maxInputChannels = numChannels; else deviceInfo->maxOutputChannels = numChannels; int frameLatency; propSize = sizeof(UInt32); err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency)); if (!err) { double secondLatency = frameLatency / deviceInfo->defaultSampleRate; if (isInput) { deviceInfo->defaultLowInputLatency = secondLatency; deviceInfo->defaultHighInputLatency = secondLatency; } else { deviceInfo->defaultLowOutputLatency = secondLatency; deviceInfo->defaultHighOutputLatency = secondLatency; } } } PaUtil_FreeMemory(buflist); return err; } static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex ) { PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; PaError err = paNoError; UInt32 propSize; err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); // FIXME: this allocation should be part of the allocations group char *name = PaUtil_AllocateMemory(propSize); err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); if (!err) { deviceInfo->name = name; } Float64 sampleRate; propSize = sizeof(Float64); err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate)); if (!err) { deviceInfo->defaultSampleRate = sampleRate; } // Get channel info err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1); err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0); return err; } static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; PaUtilHostApiRepresentation *hostApi; PaMacCoreDeviceInfo *deviceInfoArray; // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized. hostApi = &macCoreHostApi->inheritedHostApiRep; hostApi->info.deviceCount = 0; hostApi->info.defaultInputDevice = paNoDevice; hostApi->info.defaultOutputDevice = paNoDevice; UInt32 propsize; AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL); int numDevices = propsize / sizeof(AudioDeviceID); hostApi->info.deviceCount = numDevices; if (numDevices > 0) { hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices ); if( !hostApi->deviceInfos ) { return paInsufficientMemory; } // allocate all device info structs in a contiguous block deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory( macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices ); if( !deviceInfoArray ) { return paInsufficientMemory; } macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize); AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds); AudioDeviceID defaultInputDevice, defaultOutputDevice; propsize = sizeof(AudioDeviceID); AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice); AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice); UInt32 i; for (i = 0; i < numDevices; ++i) { if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) { hostApi->info.defaultInputDevice = i; } if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) { hostApi->info.defaultOutputDevice = i; } InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex); hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo); } } return result; } static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput) { UInt32 propSize = sizeof(AudioStreamBasicDescription); AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize); streamDescription->mSampleRate = sampleRate; streamDescription->mFormatID = 0; streamDescription->mFormatFlags = 0; streamDescription->mBytesPerPacket = 0; streamDescription->mFramesPerPacket = 0; streamDescription->mBytesPerFrame = 0; streamDescription->mChannelsPerFrame = 0; streamDescription->mBitsPerChannel = 0; streamDescription->mReserved = 0; OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription); PaUtil_FreeMemory(streamDescription); return result; } static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount) { int frameSpacing, channelSpacing; if (destination->inputSampleFormat & paNonInterleaved) { frameSpacing = 1; channelSpacing = destination->inputChannelCount; } else { frameSpacing = destination->inputChannelCount; channelSpacing = 1; } AudioBuffer const *inputBuffer = &source->mBuffers[0]; void *coreAudioBuffer = inputBuffer->mData; void *portAudioBuffer = destination->inputBuffer; UInt32 i, streamNumber, streamChannel; for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) { if (streamChannel >= inputBuffer->mNumberChannels) { ++streamNumber; inputBuffer = &source->mBuffers[streamNumber]; coreAudioBuffer = inputBuffer->mData; streamChannel = 0; } destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator); coreAudioBuffer += sizeof(Float32); portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing; } return noErr; } static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount) { int frameSpacing, channelSpacing; if (source->outputSampleFormat & paNonInterleaved) { frameSpacing = 1; channelSpacing = source->outputChannelCount; } else { frameSpacing = source->outputChannelCount; channelSpacing = 1; } AudioBuffer *outputBuffer = &destination->mBuffers[0]; void *coreAudioBuffer = outputBuffer->mData; void *portAudioBuffer = source->outputBuffer; UInt32 i, streamNumber, streamChannel; for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) { if (streamChannel >= outputBuffer->mNumberChannels) { ++streamNumber; outputBuffer = &destination->mBuffers[streamNumber]; coreAudioBuffer = outputBuffer->mData; streamChannel = 0; } source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL); coreAudioBuffer += sizeof(Float32); portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing; } return noErr; } static OSStatus AudioIOProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData) { PaMacClientData *clientData = (PaMacClientData *)inClientData; PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); AudioBuffer *outputBuffer = &outOutputData->mBuffers[0]; unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32)); if (clientData->inputBuffer) { CopyInputData(clientData, inInputData, frameCount); } PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); if (clientData->outputBuffer) { CopyOutputData(outOutputData, clientData, frameCount); } PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); if (result == paComplete || result == paAbort) { Pa_StopStream(clientData->stream); } PaUtil_FreeMemory( timeInfo ); return noErr; } // This is not for input-only streams, this is for streams where the input device is different from the output device static OSStatus AudioInputProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData) { PaMacClientData *clientData = (PaMacClientData *)inClientData; PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); AudioBuffer const *inputBuffer = &inInputData->mBuffers[0]; unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32)); CopyInputData(clientData, inInputData, frameCount); PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); if( result == paComplete || result == paAbort ) Pa_StopStream(clientData->stream); PaUtil_FreeMemory( timeInfo ); return noErr; } // This is not for output-only streams, this is for streams where the input device is different from the output device static OSStatus AudioOutputProc( AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* inClientData) { PaMacClientData *clientData = (PaMacClientData *)inClientData; //PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); AudioBuffer *outputBuffer = &outOutputData->mBuffers[0]; unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32)); //clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); CopyOutputData(outOutputData, clientData, frameCount); PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); return noErr; } static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput) { PaError result = paNoError; double actualSampleRate; UInt32 propSize = sizeof(double); result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate)); result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate)); if (result == paNoError && actualSampleRate != sampleRate) { result = paInvalidSampleRate; } return result; } static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput) { PaError result = paNoError; UInt32 preferredFramesPerBuffer = framesPerBuffer; // while (preferredFramesPerBuffer > UINT32_MAX) { // preferredFramesPerBuffer /= 2; // } UInt32 actualFramesPerBuffer; UInt32 propSize = sizeof(UInt32); result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer)); result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer)); if (result != paNoError) { // do nothing } else if (actualFramesPerBuffer > framesPerBuffer) { result = paBufferTooSmall; } else if (actualFramesPerBuffer < framesPerBuffer) { result = paBufferTooBig; } return result; } static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput) { PaError err = paNoError; err = SetSampleRate(device, sampleRate, isInput); if( err == paNoError ) err = SetFramesPerBuffer(device, framesPerBuffer, isInput); return err; } // ===== PortAudio functions ===== #pragma mark PortAudio functions #ifdef __cplusplus extern "C" { #endif // __cplusplus PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif // __cplusplus static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi; CleanUp(macCoreHostApi); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi; PaDeviceInfo *deviceInfo; PaError result = paNoError; if (inputParameters) { deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; if (inputParameters->channelCount > deviceInfo->maxInputChannels) result = paInvalidChannelCount; else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) { result = paInvalidSampleRate; } } if (outputParameters && result == paNoError) { deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; if (outputParameters->channelCount > deviceInfo->maxOutputChannels) result = paInvalidChannelCount; else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) { result = paInvalidSampleRate; } } return result; } static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError err = paNoError; PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi; PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream)); stream->isActive = 0; stream->isStopped = 1; stream->inputDevice = kAudioDeviceUnknown; stream->outputDevice = kAudioDeviceUnknown; PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, ( (streamCallback) ? &macCoreHostApi->callbackStreamInterface : &macCoreHostApi->blockingStreamInterface ), streamCallback, userData ); PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); *s = (PaStream*)stream; PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData)); clientData->stream = stream; clientData->callback = streamCallback; clientData->userData = userData; clientData->inputBuffer = 0; clientData->outputBuffer = 0; clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator)); PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator); if (inputParameters != NULL) { stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device]; clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags); clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount); clientData->inputChannelCount = inputParameters->channelCount; clientData->inputSampleFormat = inputParameters->sampleFormat; err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1); } if (err == paNoError && outputParameters != NULL) { stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device]; clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags); clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount); clientData->outputChannelCount = outputParameters->channelCount; clientData->outputSampleFormat = outputParameters->sampleFormat; err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0); } if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) { AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice; AudioDeviceAddIOProc(device, AudioIOProc, clientData); } else { // using different devices for input and output AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData); AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData); } return err; } // Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. static PaError CloseStream( PaStream* s ) { PaError err = paNoError; PaMacCoreStream *stream = (PaMacCoreStream*)s; PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); if (stream->inputDevice != kAudioDeviceUnknown) { if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc)); } else { err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc)); err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc)); } } else { err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc)); } return err; } static PaError StartStream( PaStream *s ) { PaError err = paNoError; PaMacCoreStream *stream = (PaMacCoreStream*)s; if (stream->inputDevice != kAudioDeviceUnknown) { if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc)); } else { err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc)); err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc)); } } else { err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc)); } stream->isActive = 1; stream->isStopped = 0; return err; } static PaError AbortStream( PaStream *s ) { PaError err = paNoError; PaMacCoreStream *stream = (PaMacCoreStream*)s; if (stream->inputDevice != kAudioDeviceUnknown) { if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc)); } else { err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc)); err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc)); } } else { err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc)); } stream->isActive = 0; stream->isStopped = 1; return err; } static PaError StopStream( PaStream *s ) { // TODO: this should be nicer than abort return AbortStream(s); } static PaError IsStreamStopped( PaStream *s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; return stream->isStopped; } static PaError IsStreamActive( PaStream *s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; return stream->isActive; } static PaTime GetStreamTime( PaStream *s ) { OSStatus err; PaTime result; PaMacCoreStream *stream = (PaMacCoreStream*)s; AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp)); if (stream->inputDevice != kAudioDeviceUnknown) { err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp); } else { err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp); } result = err ? 0 : timeStamp->mSampleTime; PaUtil_FreeMemory(timeStamp); return result; } static double GetStreamCpuLoad( PaStream* s ) { PaMacCoreStream *stream = (PaMacCoreStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } // As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { return paInternalError; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { return paInternalError; } static signed long GetStreamReadAvailable( PaStream* s ) { return paInternalError; } static signed long GetStreamWriteAvailable( PaStream* s ) { return paInternalError; } // HostAPI-specific initialization function PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) ); if( !macCoreHostApi ) { result = paInsufficientMemory; goto error; } macCoreHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !macCoreHostApi->allocations ) { result = paInsufficientMemory; goto error; } *hostApi = &macCoreHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paCoreAudio; (*hostApi)->info.name = "CoreAudio"; result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex); if (result != paNoError) { goto error; } // Set up the proper callbacks to this HostApi's functions (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if( macCoreHostApi ) { CleanUp(macCoreHostApi); } return result; } nyquist-3.05/portaudio/src/hostapi/asio/0002755000175000000620000000000011537433131017365 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/asio/pa_asio.cpp0000644000175000000620000031510611466723256021523 0ustar stevestaff/* * $Id: pa_asio.cpp,v 1.1 2010/11/04 21:04:36 rbd Exp $ * Portable Audio I/O Library for ASIO Drivers * * Author: Stephane Letz * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /* Modification History 08-03-01 First version : Stephane Letz 08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk 08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz 08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz 08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil 08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when the stream is stopped : Stephane Letz 08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when the stream is stopped : Stephane Letz 10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz 10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz 10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil 10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk 10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz 11-06-01 Rename functions : Stephane Letz 11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz 12-04-02 Add Mac includes for and : Phil Burk 13-04-02 Removes another compiler warning : Stephane Letz 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz 12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina 18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B. 21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina ** NOTE maintanance history is now stored in CVS ** */ /** @file @ingroup hostapi_src Note that specific support for paInputUnderflow, paOutputOverflow and paNeverDropInput is not necessary or possible with this driver due to the synchronous full duplex double-buffered architecture of ASIO. @todo check that CoInitialize()/CoUninitialize() are always correctly paired, even in error cases. @todo implement host api specific extension to set i/o buffer sizes in frames @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable @todo implement IsFormatSupported @todo work out how to implement stream stoppage from callback and implement IsStreamActive properly. Stream stoppage could be implemented using a high-priority thread blocked on an Event which is signalled by the callback. Or, we could just call ASIO stop from the callback and see what happens. @todo rigorously check asio return codes and convert to pa error codes @todo Different channels of a multichannel stream can have different sample formats, but we assume that all are the same as the first channel for now. Fixing this will require the block processor to maintain per-channel conversion functions - could get nasty. @todo investigate whether the asio processNow flag needs to be honoured @todo handle asioMessages() callbacks in a useful way, or at least document what cases we don't handle. @todo miscellaneous other FIXMEs @todo provide an asio-specific method for setting the systems specific value (aka main window handle) - check that this matches the value passed to PaAsio_ShowControlPanel, or remove it entirely from PaAsio_ShowControlPanel. - this would allow PaAsio_ShowControlPanel to be called for the currently open stream (at present all streams must be closed). */ #include #include #include //#include #include #include #include "portaudio.h" #include "pa_asio.h" #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_debugprint.h" /* This version of pa_asio.cpp is currently only targetted at Win32, It would require a few tweaks to work with pre-OS X Macintosh. To make configuration easier, we define WIN32 here to make sure that the ASIO SDK knows this is Win32. */ #ifndef WIN32 #define WIN32 #endif #include "asiosys.h" #include "asio.h" #include "asiodrivers.h" #include "iasiothiscallresolver.h" /* #if MAC #include #include #include #else */ /* #include #include #include */ /* #endif */ /* external references */ extern AsioDrivers* asioDrivers ; bool loadAsioDriver(char *name); /* We are trying to be compatible with CARBON but this has not been thoroughly tested. */ /* not tested at all since new code was introduced. */ #define CARBON_COMPATIBLE (0) /* prototypes for functions declared in this file */ extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ); static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* our ASIO callback functions */ static void bufferSwitch(long index, ASIOBool processNow); static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); static void sampleRateChanged(ASIOSampleRate sRate); static long asioMessages(long selector, long value, void* message, double* opt); static ASIOCallbacks asioCallbacks_ = { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo }; #define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \ PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText ) static void PaAsio_SetLastSystemError( DWORD errorCode ) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf ); LocalFree( lpMsgBuf ); } #define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \ PaAsio_SetLastSystemError( errorCode ) static const char* PaAsio_GetAsioErrorText( ASIOError asioError ) { const char *result; switch( asioError ){ case ASE_OK: case ASE_SUCCESS: result = "Success"; break; case ASE_NotPresent: result = "Hardware input or output is not present or available"; break; case ASE_HWMalfunction: result = "Hardware is malfunctioning"; break; case ASE_InvalidParameter: result = "Input parameter invalid"; break; case ASE_InvalidMode: result = "Hardware is in a bad mode or used in a bad mode"; break; case ASE_SPNotAdvancing: result = "Hardware is not running when sample position is inquired"; break; case ASE_NoClock: result = "Sample clock or rate cannot be determined or is not present"; break; case ASE_NoMemory: result = "Not enough memory for completing the request"; break; default: result = "Unknown ASIO error"; break; } return result; } #define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \ PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) ) // Atomic increment and decrement operations #if MAC /* need to be implemented on Mac */ inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast(v));} inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast(v));} #elif WINDOWS inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast(v));} inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast(v));} #endif typedef struct PaAsioDriverInfo { ASIODriverInfo asioDriverInfo; long inputChannelCount, outputChannelCount; long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity; bool postOutput; } PaAsioDriverInfo; /* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; void *systemSpecific; /* the ASIO C API only allows one ASIO driver to be open at a time, so we keep track of whether we have the driver open here, and use this information to return errors from OpenStream if the driver is already open. openAsioDeviceIndex will be PaNoDevice if there is no device open and a valid pa_asio (not global) device index otherwise. openAsioDriverInfo is populated with the driver info for the currently open device (if any) */ PaDeviceIndex openAsioDeviceIndex; PaAsioDriverInfo openAsioDriverInfo; } PaAsioHostApiRepresentation; /* Retrieve driver names from ASIO, returned in a char** allocated in . */ static char **GetAsioDriverNames( PaUtilAllocationGroup *group, long driverCount ) { char **result = 0; int i; result =(char**)PaUtil_GroupAllocateMemory( group, sizeof(char*) * driverCount ); if( !result ) goto error; result[0] = (char*)PaUtil_GroupAllocateMemory( group, 32 * driverCount ); if( !result[0] ) goto error; for( i=0; igetDriverNames( result, driverCount ); error: return result; } static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type) { switch (type) { case ASIOSTInt16MSB: case ASIOSTInt16LSB: return paInt16; case ASIOSTFloat32MSB: case ASIOSTFloat32LSB: case ASIOSTFloat64MSB: case ASIOSTFloat64LSB: return paFloat32; case ASIOSTInt32MSB: case ASIOSTInt32LSB: case ASIOSTInt32MSB16: case ASIOSTInt32LSB16: case ASIOSTInt32MSB18: case ASIOSTInt32MSB20: case ASIOSTInt32MSB24: case ASIOSTInt32LSB18: case ASIOSTInt32LSB20: case ASIOSTInt32LSB24: return paInt32; case ASIOSTInt24MSB: case ASIOSTInt24LSB: return paInt24; default: return paCustomFormat; } } void AsioSampleTypeLOG(ASIOSampleType type) { switch (type) { case ASIOSTInt16MSB: PA_DEBUG(("ASIOSTInt16MSB\n")); break; case ASIOSTInt16LSB: PA_DEBUG(("ASIOSTInt16LSB\n")); break; case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break; case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break; case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break; case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break; case ASIOSTInt32MSB: PA_DEBUG(("ASIOSTInt32MSB\n")); break; case ASIOSTInt32LSB: PA_DEBUG(("ASIOSTInt32LSB\n")); break; case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break; case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break; case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break; case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break; case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break; case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break; case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break; case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break; case ASIOSTInt24MSB: PA_DEBUG(("ASIOSTInt24MSB\n")); break; case ASIOSTInt24LSB: PA_DEBUG(("ASIOSTInt24LSB\n")); break; default: PA_DEBUG(("Custom Format%d\n",type));break; } } static int BytesPerAsioSample( ASIOSampleType sampleType ) { switch (sampleType) { case ASIOSTInt16MSB: case ASIOSTInt16LSB: return 2; case ASIOSTFloat64MSB: case ASIOSTFloat64LSB: return 8; case ASIOSTFloat32MSB: case ASIOSTFloat32LSB: case ASIOSTInt32MSB: case ASIOSTInt32LSB: case ASIOSTInt32MSB16: case ASIOSTInt32LSB16: case ASIOSTInt32MSB18: case ASIOSTInt32MSB20: case ASIOSTInt32MSB24: case ASIOSTInt32LSB18: case ASIOSTInt32LSB20: case ASIOSTInt32LSB24: return 4; case ASIOSTInt24MSB: case ASIOSTInt24LSB: return 3; default: return 0; } } static void Swap16( void *buffer, long shift, long count ) { unsigned short *p = (unsigned short*)buffer; unsigned short temp; (void) shift; /* unused parameter */ while( count-- ) { temp = *p; *p++ = (unsigned short)((temp<<8) | (temp>>8)); } } static void Swap24( void *buffer, long shift, long count ) { unsigned char *p = (unsigned char*)buffer; unsigned char temp; (void) shift; /* unused parameter */ while( count-- ) { temp = *p; *p = *(p+2); *(p+2) = temp; p += 3; } } #define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24)); static void Swap32( void *buffer, long shift, long count ) { unsigned long *p = (unsigned long*)buffer; unsigned long temp; (void) shift; /* unused parameter */ while( count-- ) { temp = *p; *p++ = PA_SWAP32_( temp); } } static void SwapShiftLeft32( void *buffer, long shift, long count ) { unsigned long *p = (unsigned long*)buffer; unsigned long temp; while( count-- ) { temp = *p; temp = PA_SWAP32_( temp); *p++ = temp << shift; } } static void ShiftRightSwap32( void *buffer, long shift, long count ) { unsigned long *p = (unsigned long*)buffer; unsigned long temp; while( count-- ) { temp = *p >> shift; *p++ = PA_SWAP32_( temp); } } static void ShiftLeft32( void *buffer, long shift, long count ) { unsigned long *p = (unsigned long*)buffer; unsigned long temp; while( count-- ) { temp = *p; *p++ = temp << shift; } } static void ShiftRight32( void *buffer, long shift, long count ) { unsigned long *p = (unsigned long*)buffer; unsigned long temp; while( count-- ) { temp = *p; *p++ = temp >> shift; } } #define PA_SWAP_( x, y ) temp=x; x = y; y = temp; static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count ) { double *in = (double*)buffer; float *out = (float*)buffer; unsigned char *p; unsigned char temp; (void) shift; /* unused parameter */ while( count-- ) { p = (unsigned char*)in; PA_SWAP_( p[0], p[7] ); PA_SWAP_( p[1], p[6] ); PA_SWAP_( p[2], p[5] ); PA_SWAP_( p[3], p[4] ); *out++ = (float) (*in++); } } static void ConvertFloat64ToFloat32( void *buffer, long shift, long count ) { double *in = (double*)buffer; float *out = (float*)buffer; (void) shift; /* unused parameter */ while( count-- ) *out++ = (float) (*in++); } static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count ) { float *in = ((float*)buffer) + (count-1); double *out = ((double*)buffer) + (count-1); unsigned char *p; unsigned char temp; (void) shift; /* unused parameter */ while( count-- ) { *out = *in--; p = (unsigned char*)out; PA_SWAP_( p[0], p[7] ); PA_SWAP_( p[1], p[6] ); PA_SWAP_( p[2], p[5] ); PA_SWAP_( p[3], p[4] ); out--; } } static void ConvertFloat32ToFloat64( void *buffer, long shift, long count ) { float *in = ((float*)buffer) + (count-1); double *out = ((double*)buffer) + (count-1); (void) shift; /* unused parameter */ while( count-- ) *out-- = *in--; } #ifdef MAC #define PA_MSB_IS_NATIVE_ #undef PA_LSB_IS_NATIVE_ #endif #ifdef WINDOWS #undef PA_MSB_IS_NATIVE_ #define PA_LSB_IS_NATIVE_ #endif typedef void PaAsioBufferConverter( void *, long, long ); static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift ) { *shift = 0; *converter = 0; switch (type) { case ASIOSTInt16MSB: /* dest: paInt16, no conversion necessary, possible byte swap*/ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap16; #endif break; case ASIOSTInt16LSB: /* dest: paInt16, no conversion necessary, possible byte swap*/ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap16; #endif break; case ASIOSTFloat32MSB: /* dest: paFloat32, no conversion necessary, possible byte swap*/ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTFloat32LSB: /* dest: paFloat32, no conversion necessary, possible byte swap*/ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTFloat64MSB: /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap64ConvertFloat64ToFloat32; #else *converter = ConvertFloat64ToFloat32; #endif break; case ASIOSTFloat64LSB: /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap64ConvertFloat64ToFloat32; #else *converter = ConvertFloat64ToFloat32; #endif break; case ASIOSTInt32MSB: /* dest: paInt32, no conversion necessary, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTInt32LSB: /* dest: paInt32, no conversion necessary, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTInt32MSB16: /* dest: paInt32, 16 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 16; break; case ASIOSTInt32MSB18: /* dest: paInt32, 14 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 14; break; case ASIOSTInt32MSB20: /* dest: paInt32, 12 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 12; break; case ASIOSTInt32MSB24: /* dest: paInt32, 8 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 8; break; case ASIOSTInt32LSB16: /* dest: paInt32, 16 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 16; break; case ASIOSTInt32LSB18: /* dest: paInt32, 14 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 14; break; case ASIOSTInt32LSB20: /* dest: paInt32, 12 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 12; break; case ASIOSTInt32LSB24: /* dest: paInt32, 8 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = SwapShiftLeft32; #else *converter = ShiftLeft32; #endif *shift = 8; break; case ASIOSTInt24MSB: /* dest: paInt24, no conversion necessary, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap24; #endif break; case ASIOSTInt24LSB: /* dest: paInt24, no conversion necessary, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap24; #endif break; } } static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift ) { *shift = 0; *converter = 0; switch (type) { case ASIOSTInt16MSB: /* src: paInt16, no conversion necessary, possible byte swap*/ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap16; #endif break; case ASIOSTInt16LSB: /* src: paInt16, no conversion necessary, possible byte swap*/ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap16; #endif break; case ASIOSTFloat32MSB: /* src: paFloat32, no conversion necessary, possible byte swap*/ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTFloat32LSB: /* src: paFloat32, no conversion necessary, possible byte swap*/ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTFloat64MSB: /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/ #ifdef PA_LSB_IS_NATIVE_ *converter = ConvertFloat32ToFloat64Swap64; #else *converter = ConvertFloat32ToFloat64; #endif break; case ASIOSTFloat64LSB: /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/ #ifdef PA_MSB_IS_NATIVE_ *converter = ConvertFloat32ToFloat64Swap64; #else *converter = ConvertFloat32ToFloat64; #endif break; case ASIOSTInt32MSB: /* src: paInt32, no conversion necessary, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTInt32LSB: /* src: paInt32, no conversion necessary, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap32; #endif break; case ASIOSTInt32MSB16: /* src: paInt32, 16 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 16; break; case ASIOSTInt32MSB18: /* src: paInt32, 14 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 14; break; case ASIOSTInt32MSB20: /* src: paInt32, 12 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 12; break; case ASIOSTInt32MSB24: /* src: paInt32, 8 bit shift, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 8; break; case ASIOSTInt32LSB16: /* src: paInt32, 16 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 16; break; case ASIOSTInt32LSB18: /* src: paInt32, 14 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 14; break; case ASIOSTInt32LSB20: /* src: paInt32, 12 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 12; break; case ASIOSTInt32LSB24: /* src: paInt32, 8 bit shift, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = ShiftRightSwap32; #else *converter = ShiftRight32; #endif *shift = 8; break; case ASIOSTInt24MSB: /* src: paInt24, no conversion necessary, possible byte swap */ #ifdef PA_LSB_IS_NATIVE_ *converter = Swap24; #endif break; case ASIOSTInt24LSB: /* src: paInt24, no conversion necessary, possible byte swap */ #ifdef PA_MSB_IS_NATIVE_ *converter = Swap24; #endif break; } } typedef struct PaAsioDeviceInfo { PaDeviceInfo commonDeviceInfo; long minBufferSize; long maxBufferSize; long preferredBufferSize; long bufferGranularity; ASIOChannelInfo *asioChannelInfos; } PaAsioDeviceInfo; PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device, long *minLatency, long *maxLatency, long *preferredLatency, long *granularity ) { PaError result; PaUtilHostApiRepresentation *hostApi; PaDeviceIndex hostApiDevice; result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); if( result == paNoError ) { result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); if( result == paNoError ) { PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; *minLatency = asioDeviceInfo->minBufferSize; *maxLatency = asioDeviceInfo->maxBufferSize; *preferredLatency = asioDeviceInfo->preferredBufferSize; *granularity = asioDeviceInfo->bufferGranularity; } } return result; } /* load the asio driver named by and return statistics about the driver in info. If no error occurred, the driver will remain open and must be closed by the called by calling ASIOExit() - if an error is returned the driver will already be closed. */ static PaError LoadAsioDriver( const char *driverName, PaAsioDriverInfo *driverInfo, void *systemSpecific ) { PaError result = paNoError; ASIOError asioError; int asioIsInitialized = 0; if( !loadAsioDriver( const_cast(driverName) ) ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" ); goto error; } memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) ); driverInfo->asioDriverInfo.asioVersion = 2; driverInfo->asioDriverInfo.sysRef = systemSpecific; if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } else { asioIsInitialized = 1; } if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount, &driverInfo->outputChannelCount)) != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize, &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize, &driverInfo->bufferGranularity)) != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } if( ASIOOutputReady() == ASE_OK ) driverInfo->postOutput = true; else driverInfo->postOutput = false; return result; error: if( asioIsInitialized ) ASIOExit(); return result; } #define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ 13 /* must be the same number of elements as in the array below */ static ASIOSampleRate defaultSampleRateSearchOrder_[] = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; /* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */ typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID); IsDebuggerPresentPtr IsDebuggerPresent_ = 0; //FARPROC IsDebuggerPresent_ = 0; // this is the current way to do it apparently according to davidv PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; int i, driverCount; PaAsioHostApiRepresentation *asioHostApi; PaAsioDeviceInfo *deviceInfoArray; char **names; PaAsioDriverInfo paAsioDriverInfo; asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) ); if( !asioHostApi ) { result = paInsufficientMemory; goto error; } asioHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !asioHostApi->allocations ) { result = paInsufficientMemory; goto error; } asioHostApi->systemSpecific = 0; asioHostApi->openAsioDeviceIndex = paNoDevice; *hostApi = &asioHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paASIO; (*hostApi)->info.name = "ASIO"; (*hostApi)->info.deviceCount = 0; #ifdef WINDOWS /* use desktop window as system specific ptr */ asioHostApi->systemSpecific = GetDesktopWindow(); CoInitialize(NULL); #endif /* MUST BE CHECKED : to force fragments loading on Mac */ loadAsioDriver( "dummy" ); /* driverCount is the number of installed drivers - not necessarily the number of installed physical devices. */ #if MAC driverCount = asioDrivers->getNumFragments(); #elif WINDOWS driverCount = asioDrivers->asioGetNumDev(); #endif if( driverCount > 0 ) { names = GetAsioDriverNames( asioHostApi->allocations, driverCount ); if( !names ) { result = paInsufficientMemory; goto error; } /* allocate enough space for all drivers, even if some aren't installed */ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount ); if( !(*hostApi)->deviceInfos ) { result = paInsufficientMemory; goto error; } /* allocate all device info structs in a contiguous block */ deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory( asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount ); if( !deviceInfoArray ) { result = paInsufficientMemory; goto error; } IsDebuggerPresent_ = GetProcAddress( LoadLibrary( "Kernel32.dll" ), "IsDebuggerPresent" ); for( i=0; i < driverCount; ++i ) { PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i])); // Since portaudio opens ALL ASIO drivers, and no one else does that, // we face fact that some drivers were not meant for it, drivers which act // like shells on top of REAL drivers, for instance. // so we get duplicate handles, locks and other problems. // so lets NOT try to load any such wrappers. // The ones i [davidv] know of so far are: if ( strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0 || strcmp (names[i],"ASIO Multimedia Driver") == 0 || strncmp(names[i],"Premiere",8) == 0 //"Premiere Elements Windows Sound 1.0" || strncmp(names[i],"Adobe",5) == 0 //"Adobe Default Windows Sound 1.5" || strncmp(names[i],"ReaRoute ASIO",13) == 0 //Reaper www.reaper.fm <- fix your stuff man. ) { PA_DEBUG(("BLACKLISTED!!!\n")); continue; } if( IsDebuggerPresent_ && IsDebuggerPresent_() ) { /* ASIO Digidesign Driver uses PACE copy protection which quits out if a debugger is running. So we don't load it if a debugger is running. */ if( strcmp(names[i], "ASIO Digidesign Driver") == 0 ) { PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n")); continue; } } /* Attempt to load the asio driver... */ if( LoadAsioDriver( names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError ) { PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = names[i]; PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i,deviceInfo->name)); PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriverInfo.inputChannelCount)); PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriverInfo.outputChannelCount)); PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriverInfo.bufferMinSize)); PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriverInfo.bufferMaxSize)); PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize)); PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriverInfo.bufferGranularity)); deviceInfo->maxInputChannels = paAsioDriverInfo.inputChannelCount; deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount; deviceInfo->defaultSampleRate = 0.; bool foundDefaultSampleRate = false; for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j ) { ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] ); if( asioError != ASE_NoClock && asioError != ASE_NotPresent ) { deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j]; foundDefaultSampleRate = true; break; } } PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate)); if( foundDefaultSampleRate ){ /* calculate default latency values from bufferPreferredSize for default low latency, and bufferPreferredSize * 3 for default high latency. use the default sample rate to convert from samples to seconds. Without knowing what sample rate the user will use this is the best we can do. */ double defaultLowLatency = paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate; deviceInfo->defaultLowInputLatency = defaultLowLatency; deviceInfo->defaultLowOutputLatency = defaultLowLatency; long defaultHighLatencyBufferSize = paAsioDriverInfo.bufferPreferredSize * 3; if( defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize ) defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize; double defaultHighLatency = defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate; if( defaultHighLatency < defaultLowLatency ) defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */ deviceInfo->defaultHighInputLatency = defaultHighLatency; deviceInfo->defaultHighOutputLatency = defaultHighLatency; }else{ deviceInfo->defaultLowInputLatency = 0.; deviceInfo->defaultLowOutputLatency = 0.; deviceInfo->defaultHighInputLatency = 0.; deviceInfo->defaultHighOutputLatency = 0.; } PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency)); PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency)); PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency)); PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency)); asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize; asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize; asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize; asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity; asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory( asioHostApi->allocations, sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels + deviceInfo->maxOutputChannels) ); if( !asioDeviceInfo->asioChannelInfos ) { result = paInsufficientMemory; goto error; } int a; for( a=0; a < deviceInfo->maxInputChannels; ++a ){ asioDeviceInfo->asioChannelInfos[a].channel = a; asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue; ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] ); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } } for( a=0; a < deviceInfo->maxOutputChannels; ++a ){ int b = deviceInfo->maxInputChannels + a; asioDeviceInfo->asioChannelInfos[b].channel = a; asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse; ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] ); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } } /* unload the driver */ ASIOExit(); (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; ++(*hostApi)->info.deviceCount; } } } if( (*hostApi)->info.deviceCount > 0 ) { (*hostApi)->info.defaultInputDevice = 0; (*hostApi)->info.defaultOutputDevice = 0; } else { (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; } (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if( asioHostApi ) { if( asioHostApi->allocations ) { PaUtil_FreeAllAllocations( asioHostApi->allocations ); PaUtil_DestroyAllocationGroup( asioHostApi->allocations ); } PaUtil_FreeMemory( asioHostApi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi; /* IMPLEMENT ME: - clean up any resources not handled by the allocation group */ if( asioHostApi->allocations ) { PaUtil_FreeAllAllocations( asioHostApi->allocations ); PaUtil_DestroyAllocationGroup( asioHostApi->allocations ); } PaUtil_FreeMemory( asioHostApi ); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaError result = paNoError; PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi; PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaDeviceIndex asioDeviceIndex; ASIOError asioError; if( inputParameters && outputParameters ) { /* full duplex ASIO stream must use the same device for input and output */ if( inputParameters->device != outputParameters->device ) return paBadIODeviceCombination; } if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; asioDeviceIndex = inputParameters->device; /* validate inputStreamInfo */ /** @todo do more validation here */ // if( inputParameters->hostApiSpecificStreamInfo ) // return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; asioDeviceIndex = outputParameters->device; /* validate outputStreamInfo */ /** @todo do more validation here */ // if( outputParameters->hostApiSpecificStreamInfo ) // return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } /* if an ASIO device is open we can only get format information for the currently open device */ if( asioHostApi->openAsioDeviceIndex != paNoDevice && asioHostApi->openAsioDeviceIndex != asioDeviceIndex ) { return paDeviceUnavailable; } /* NOTE: we load the driver and use its current settings rather than the ones in our device info structure which may be stale */ /* open the device if it's not already open */ if( asioHostApi->openAsioDeviceIndex == paNoDevice ) { result = LoadAsioDriver( asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name, driverInfo, asioHostApi->systemSpecific ); if( result != paNoError ) return result; } /* check that input device can support inputChannelCount */ if( inputChannelCount > 0 ) { if( inputChannelCount > driverInfo->inputChannelCount ) { result = paInvalidChannelCount; goto done; } } /* check that output device can support outputChannelCount */ if( outputChannelCount ) { if( outputChannelCount > driverInfo->outputChannelCount ) { result = paInvalidChannelCount; goto done; } } /* query for sample rate support */ asioError = ASIOCanSampleRate( sampleRate ); if( asioError == ASE_NoClock || asioError == ASE_NotPresent ) { result = paInvalidSampleRate; goto done; } done: /* close the device if it wasn't already open */ if( asioHostApi->openAsioDeviceIndex == paNoDevice ) { ASIOExit(); /* not sure if we should check for errors here */ } if( result == paNoError ) return paFormatIsSupported; else return result; } /* PaAsioStream - a stream data structure specifically for this implementation */ typedef struct PaAsioStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaAsioHostApiRepresentation *asioHostApi; unsigned long framesPerHostCallback; /* ASIO driver info - these may not be needed for the life of the stream, but store them here until we work out how format conversion is going to work. */ ASIOBufferInfo *asioBufferInfos; ASIOChannelInfo *asioChannelInfos; long inputLatency, outputLatency; // actual latencies returned by asio long inputChannelCount, outputChannelCount; bool postOutput; void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */ void **inputBufferPtrs[2]; void **outputBufferPtrs[2]; PaAsioBufferConverter *inputBufferConverter; long inputShift; PaAsioBufferConverter *outputBufferConverter; long outputShift; volatile bool stopProcessing; int stopPlayoutCount; HANDLE completedBuffersPlayedEvent; bool streamFinishedCallbackCalled; volatile int isActive; volatile bool zeroOutput; /* all future calls to the callback will output silence */ volatile long reenterCount; volatile long reenterError; PaStreamCallbackFlags callbackFlags; } PaAsioStream; static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */ static void ZeroOutputBuffers( PaAsioStream *stream, long index ) { int i; for( i=0; i < stream->outputChannelCount; ++i ) { void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index]; int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type ); memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample ); } } static unsigned long SelectHostBufferSize( unsigned long suggestedLatencyFrames, PaAsioDriverInfo *driverInfo ) { unsigned long result; if( suggestedLatencyFrames == 0 ) { result = driverInfo->bufferPreferredSize; } else{ if( suggestedLatencyFrames <= (unsigned long)driverInfo->bufferMinSize ) { result = driverInfo->bufferMinSize; } else if( suggestedLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize ) { result = driverInfo->bufferMaxSize; } else { if( driverInfo->bufferGranularity == -1 ) { /* power-of-two */ result = 2; while( result < suggestedLatencyFrames ) result *= 2; if( result < (unsigned long)driverInfo->bufferMinSize ) result = driverInfo->bufferMinSize; if( result > (unsigned long)driverInfo->bufferMaxSize ) result = driverInfo->bufferMaxSize; } else if( driverInfo->bufferGranularity == 0 ) { /* the documentation states that bufferGranularity should be zero when bufferMinSize, bufferMaxSize and bufferPreferredSize are the same. We assume that is the case. */ result = driverInfo->bufferPreferredSize; } else { /* modulo granularity */ unsigned long remainder = suggestedLatencyFrames % driverInfo->bufferGranularity; if( remainder == 0 ) { result = suggestedLatencyFrames; } else { result = suggestedLatencyFrames + (driverInfo->bufferGranularity - remainder); if( result > (unsigned long)driverInfo->bufferMaxSize ) result = driverInfo->bufferMaxSize; } } } } return result; } /* returns channelSelectors if present */ static PaError ValidateAsioSpecificStreamInfo( const PaStreamParameters *streamParameters, const PaAsioStreamInfo *streamInfo, int deviceChannelCount, int **channelSelectors ) { if( streamInfo ) { if( streamInfo->size != sizeof( PaAsioStreamInfo ) || streamInfo->version != 1 ) { return paIncompatibleHostApiSpecificStreamInfo; } if( streamInfo->flags & paAsioUseChannelSelectors ) *channelSelectors = streamInfo->channelSelectors; if( !(*channelSelectors) ) return paIncompatibleHostApiSpecificStreamInfo; for( int i=0; i < streamParameters->channelCount; ++i ){ if( (*channelSelectors)[i] < 0 || (*channelSelectors)[i] >= deviceChannelCount ){ return paInvalidChannelCount; } } } return paNoError; } /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi; PaAsioStream *stream = 0; PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo; unsigned long framesPerHostBuffer; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; unsigned long suggestedInputLatencyFrames; unsigned long suggestedOutputLatencyFrames; PaDeviceIndex asioDeviceIndex; ASIOError asioError; int asioIsInitialized = 0; int asioBuffersCreated = 0; int completedBuffersPlayedEventInited = 0; int i; PaAsioDriverInfo *driverInfo; int *inputChannelSelectors = 0; int *outputChannelSelectors = 0; bool isExternal = false; /* unless we move to using lower level ASIO calls, we can only have one device open at a time */ if( asioHostApi->openAsioDeviceIndex != paNoDevice ){ PA_DEBUG(("OpenStream paDeviceUnavailable\n")); return paDeviceUnavailable; } if( inputParameters && outputParameters ) { /* full duplex ASIO stream must use the same device for input and output */ if( inputParameters->device != outputParameters->device ){ PA_DEBUG(("OpenStream paBadIODeviceCombination\n")); return paBadIODeviceCombination; } } if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f); /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; asioDeviceIndex = inputParameters->device; PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex]; /* validate hostApiSpecificStreamInfo */ inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo; result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo, asioDeviceInfo->commonDeviceInfo.maxInputChannels, &inputChannelSelectors ); if( result != paNoError ) return result; } else { inputChannelCount = 0; inputSampleFormat = 0; suggestedInputLatencyFrames = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f); /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; asioDeviceIndex = outputParameters->device; PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex]; /* validate hostApiSpecificStreamInfo */ outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo; result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo, asioDeviceInfo->commonDeviceInfo.maxOutputChannels, &outputChannelSelectors ); if( result != paNoError ) return result; } else { outputChannelCount = 0; outputSampleFormat = 0; suggestedOutputLatencyFrames = 0; } driverInfo = &asioHostApi->openAsioDriverInfo; /* NOTE: we load the driver and use its current settings rather than the ones in our device info structure which may be stale */ result = LoadAsioDriver( asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name, driverInfo, asioHostApi->systemSpecific ); if( result == paNoError ) asioIsInitialized = 1; else{ PA_DEBUG(("OpenStream ERROR1\n")); goto error; } /* check that input device can support inputChannelCount */ if( inputChannelCount > 0 ) { if( inputChannelCount > driverInfo->inputChannelCount ) { result = paInvalidChannelCount; PA_DEBUG(("OpenStream ERROR2\n")); goto error; } } /* check that output device can support outputChannelCount */ if( outputChannelCount ) { if( outputChannelCount > driverInfo->outputChannelCount ) { result = paInvalidChannelCount; PA_DEBUG(("OpenStream ERROR3\n")); goto error; } } /* davidv: listing ASIO Clock sources, there is an ongoing investigation by me about whether or not call ASIOSetSampleRate if an external Clock is used. A few drivers expected different things here */ { ASIOClockSource clocks[32]; long numSources=32; asioError = ASIOGetClockSources(clocks, &numSources); if( asioError != ASE_OK ){ PA_DEBUG(("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText(asioError) )); }else{ PA_DEBUG(("INFO ASIOGetClockSources listing %d clocks\n", numSources )); for (int i=0;icompletedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); if( stream->completedBuffersPlayedEvent == NULL ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); PA_DEBUG(("OpenStream ERROR6\n")); goto error; } completedBuffersPlayedEventInited = 1; stream->asioBufferInfos = 0; /* for deallocation in error */ stream->asioChannelInfos = 0; /* for deallocation in error */ stream->bufferPtrs = 0; /* for deallocation in error */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &asioHostApi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &asioHostApi->blockingStreamInterface, streamCallback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory( sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) ); if( !stream->asioBufferInfos ) { result = paInsufficientMemory; PA_DEBUG(("OpenStream ERROR7\n")); goto error; } for( i=0; i < inputChannelCount; ++i ) { ASIOBufferInfo *info = &stream->asioBufferInfos[i]; info->isInput = ASIOTrue; if( inputChannelSelectors ){ // inputChannelSelectors values have already been validated in // ValidateAsioSpecificStreamInfo() above info->channelNum = inputChannelSelectors[i]; }else{ info->channelNum = i; } info->buffers[0] = info->buffers[1] = 0; } for( i=0; i < outputChannelCount; ++i ){ ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i]; info->isInput = ASIOFalse; if( outputChannelSelectors ){ // outputChannelSelectors values have already been validated in // ValidateAsioSpecificStreamInfo() above info->channelNum = outputChannelSelectors[i]; }else{ info->channelNum = i; } info->buffers[0] = info->buffers[1] = 0; } framesPerHostBuffer = SelectHostBufferSize( (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames ) ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames), driverInfo ); PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n", framesPerHostBuffer)); asioError = ASIOCreateBuffers( stream->asioBufferInfos, inputChannelCount+outputChannelCount, framesPerHostBuffer, &asioCallbacks_ ); if( asioError != ASE_OK && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize ) { PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) )); /* Some buggy drivers (like the Hoontech DSP24) give incorrect [min, preferred, max] values They should work with the preferred size value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize computed in SelectHostBufferSize, we try again with the preferred size. */ framesPerHostBuffer = driverInfo->bufferPreferredSize; PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n", framesPerHostBuffer)); ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos, inputChannelCount+outputChannelCount, framesPerHostBuffer, &asioCallbacks_ ); if( asioError2 == ASE_OK ) asioError = ASE_OK; } if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); PA_DEBUG(("OpenStream ERROR9\n")); goto error; } asioBuffersCreated = 1; stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory( sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) ); if( !stream->asioChannelInfos ) { result = paInsufficientMemory; PA_DEBUG(("OpenStream ERROR10\n")); goto error; } for( i=0; i < inputChannelCount + outputChannelCount; ++i ) { stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum; stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput; asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] ); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); PA_DEBUG(("OpenStream ERROR11\n")); goto error; } } stream->bufferPtrs = (void**)PaUtil_AllocateMemory( 2 * sizeof(void*) * (inputChannelCount + outputChannelCount) ); if( !stream->bufferPtrs ) { result = paInsufficientMemory; PA_DEBUG(("OpenStream ERROR12\n")); goto error; } if( inputChannelCount > 0 ) { stream->inputBufferPtrs[0] = stream-> bufferPtrs; stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount]; for( i=0; iinputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0]; stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1]; } } else { stream->inputBufferPtrs[0] = 0; stream->inputBufferPtrs[1] = 0; } if( outputChannelCount > 0 ) { stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2]; stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount]; for( i=0; ioutputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0]; stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1]; } } else { stream->outputBufferPtrs[0] = 0; stream->outputBufferPtrs[1] = 0; } if( inputChannelCount > 0 ) { /* FIXME: assume all channels use the same type for now */ ASIOSampleType inputType = stream->asioChannelInfos[0].type; PA_DEBUG(("ASIO Input type:%d",inputType)); AsioSampleTypeLOG(inputType); hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType ); SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift ); } else { hostInputSampleFormat = 0; stream->inputBufferConverter = 0; } if( outputChannelCount > 0 ) { /* FIXME: assume all channels use the same type for now */ ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type; PA_DEBUG(("ASIO Output type:%d",outputType)); AsioSampleTypeLOG(outputType); hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType ); SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift ); } else { hostOutputSampleFormat = 0; stream->outputBufferConverter = 0; } result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, streamCallback, userData ); if( result != paNoError ){ PA_DEBUG(("OpenStream ERROR13\n")); goto error; } ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency ); stream->streamRepresentation.streamInfo.inputLatency = (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) + stream->inputLatency) / sampleRate; // seconds stream->streamRepresentation.streamInfo.outputLatency = (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) + stream->outputLatency) / sampleRate; // seconds stream->streamRepresentation.streamInfo.sampleRate = sampleRate; // the code below prints the ASIO latency which doesn't include the // buffer processor latency. it reports the added latency separately PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", stream->inputLatency, (long)((stream->inputLatency*1000)/ sampleRate), PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor), (long)((PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)*1000)/ sampleRate) )); PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", stream->outputLatency, (long)((stream->outputLatency*1000)/ sampleRate), PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor), (long)((PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)*1000)/ sampleRate) )); stream->asioHostApi = asioHostApi; stream->framesPerHostCallback = framesPerHostBuffer; stream->inputChannelCount = inputChannelCount; stream->outputChannelCount = outputChannelCount; stream->postOutput = driverInfo->postOutput; stream->isActive = 0; asioHostApi->openAsioDeviceIndex = asioDeviceIndex; *s = (PaStream*)stream; return result; error: PA_DEBUG(("goto errored\n")); if( stream ) { if( completedBuffersPlayedEventInited ) CloseHandle( stream->completedBuffersPlayedEvent ); if( stream->asioBufferInfos ) PaUtil_FreeMemory( stream->asioBufferInfos ); if( stream->asioChannelInfos ) PaUtil_FreeMemory( stream->asioChannelInfos ); if( stream->bufferPtrs ) PaUtil_FreeMemory( stream->bufferPtrs ); PaUtil_FreeMemory( stream ); } if( asioBuffersCreated ) ASIODisposeBuffers(); if( asioIsInitialized ) ASIOExit(); return result; } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaAsioStream *stream = (PaAsioStream*)s; /* IMPLEMENT ME: - additional stream closing + cleanup */ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); stream->asioHostApi->openAsioDeviceIndex = paNoDevice; CloseHandle( stream->completedBuffersPlayedEvent ); PaUtil_FreeMemory( stream->asioBufferInfos ); PaUtil_FreeMemory( stream->asioChannelInfos ); PaUtil_FreeMemory( stream->bufferPtrs ); PaUtil_FreeMemory( stream ); ASIODisposeBuffers(); ASIOExit(); return result; } static void bufferSwitch(long index, ASIOBool directProcess) { //TAKEN FROM THE ASIO SDK // the actual processing callback. // Beware that this is normally in a seperate thread, hence be sure that // you take care about thread synchronization. This is omitted here for // simplicity. // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs // to be created though it will only set the timeInfo.samplePosition and // timeInfo.systemTime fields and the according flags ASIOTime timeInfo; memset( &timeInfo, 0, sizeof (timeInfo) ); // get the time stamp of the buffer, not necessary if no // synchronization to other media is required if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK) timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid; // Call the real callback bufferSwitchTimeInfo( &timeInfo, index, directProcess ); } // conversion from 64 bit ASIOSample/ASIOTimeStamp to double float #if NATIVE_INT64 #define ASIO64toDouble(a) (a) #else const double twoRaisedTo32 = 4294967296.; #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32) #endif static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess ) { // the actual processing callback. // Beware that this is normally in a seperate thread, hence be sure that // you take care about thread synchronization. /* The SDK says the following about the directProcess flag: suggests to the host whether it should immediately start processing (directProcess == ASIOTrue), or whether its process should be deferred because the call comes from a very low level (for instance, a high level priority interrupt), and direct processing would cause timing instabilities for the rest of the system. If in doubt, directProcess should be set to ASIOFalse. We just ignore directProcess. This could cause incompatibilities with drivers which really don't want the audio processing to occur in this callback, but none have been identified yet. */ (void) directProcess; /* suppress unused parameter warning */ #if 0 // store the timeInfo for later use asioDriverInfo.tInfo = *timeInfo; // get the time stamp of the buffer, not necessary if no // synchronization to other media is required if (timeInfo->timeInfo.flags & kSystemTimeValid) asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime); else asioDriverInfo.nanoSeconds = 0; if (timeInfo->timeInfo.flags & kSamplePositionValid) asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); else asioDriverInfo.samples = 0; if (timeInfo->timeCode.flags & kTcValid) asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); else asioDriverInfo.tcSamples = 0; // get the system reference time asioDriverInfo.sysRefTime = get_sys_reference_time(); #endif #if 0 // a few debug messages for the Windows device driver developer // tells you the time when driver got its interrupt and the delay until the app receives // the event notification. static double last_samples = 0; char tmp[128]; sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples)); OutputDebugString (tmp); last_samples = asioDriverInfo.samples; #endif if( !theAsioStream ) return 0L; // Keep sample position // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo; // protect against reentrancy if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) ) { theAsioStream->reenterError++; //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError)); return 0L; } int buffersDone = 0; do { if( buffersDone > 0 ) { // this is a reentered buffer, we missed processing it on time // set the input overflow and output underflow flags as appropriate if( theAsioStream->inputChannelCount > 0 ) theAsioStream->callbackFlags |= paInputOverflow; if( theAsioStream->outputChannelCount > 0 ) theAsioStream->callbackFlags |= paOutputUnderflow; } else { if( theAsioStream->zeroOutput ) { ZeroOutputBuffers( theAsioStream, index ); // Finally if the driver supports the ASIOOutputReady() optimization, // do it here, all data are in place if( theAsioStream->postOutput ) ASIOOutputReady(); if( theAsioStream->stopProcessing ) { if( theAsioStream->stopPlayoutCount < 2 ) { ++theAsioStream->stopPlayoutCount; if( theAsioStream->stopPlayoutCount == 2 ) { theAsioStream->isActive = 0; if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 ) theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData ); theAsioStream->streamFinishedCallbackCalled = true; SetEvent( theAsioStream->completedBuffersPlayedEvent ); } } } } else { #if 0 // test code to try to detect slip conditions... these may work on some systems // but neither of them work on the RME Digi96 // check that sample delta matches buffer size (otherwise we must have skipped // a buffer. static double last_samples = -512; double samples; //if( timeInfo->timeCode.flags & kTcValid ) // samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); //else samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); int delta = samples - last_samples; //printf( "%d\n", delta); last_samples = samples; if( delta > theAsioStream->framesPerHostCallback ) { if( theAsioStream->inputChannelCount > 0 ) theAsioStream->callbackFlags |= paInputOverflow; if( theAsioStream->outputChannelCount > 0 ) theAsioStream->callbackFlags |= paOutputUnderflow; } // check that the buffer index is not the previous index (which would indicate // that a buffer was skipped. static int previousIndex = 1; if( index == previousIndex ) { if( theAsioStream->inputChannelCount > 0 ) theAsioStream->callbackFlags |= paInputOverflow; if( theAsioStream->outputChannelCount > 0 ) theAsioStream->callbackFlags |= paOutputUnderflow; } previousIndex = index; #endif int i; PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer ); PaStreamCallbackTimeInfo paTimeInfo; // asio systemTime is supposed to be measured according to the same // clock as timeGetTime paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001); /* patch from Paul Boege */ paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - ((double)theAsioStream->inputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate); paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + ((double)theAsioStream->outputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate); /* old version is buggy because the buffer processor also adds in its latency to the time parameters paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency; paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency; */ #if 1 // detect underflows by checking inter-callback time > 2 buffer period static double previousTime = -1; if( previousTime > 0 ){ double delta = paTimeInfo.currentTime - previousTime; if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){ if( theAsioStream->inputChannelCount > 0 ) theAsioStream->callbackFlags |= paInputOverflow; if( theAsioStream->outputChannelCount > 0 ) theAsioStream->callbackFlags |= paOutputUnderflow; } } previousTime = paTimeInfo.currentTime; #endif // note that the above input and output times do not need to be // adjusted for the latency of the buffer processor -- the buffer // processor handles that. if( theAsioStream->inputBufferConverter ) { for( i=0; iinputChannelCount; i++ ) { theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i], theAsioStream->inputShift, theAsioStream->framesPerHostCallback ); } } PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags ); /* reset status flags once they've been passed to the callback */ theAsioStream->callbackFlags = 0; PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ ); for( i=0; iinputChannelCount; ++i ) PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] ); PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ ); for( i=0; ioutputChannelCount; ++i ) PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] ); int callbackResult; if( theAsioStream->stopProcessing ) callbackResult = paComplete; else callbackResult = paContinue; unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult ); if( theAsioStream->outputBufferConverter ) { for( i=0; ioutputChannelCount; i++ ) { theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i], theAsioStream->outputShift, theAsioStream->framesPerHostCallback ); } } PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed ); // Finally if the driver supports the ASIOOutputReady() optimization, // do it here, all data are in place if( theAsioStream->postOutput ) ASIOOutputReady(); if( callbackResult == paContinue ) { /* nothing special to do */ } else if( callbackResult == paAbort ) { /* finish playback immediately */ theAsioStream->isActive = 0; if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 ) theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData ); theAsioStream->streamFinishedCallbackCalled = true; SetEvent( theAsioStream->completedBuffersPlayedEvent ); theAsioStream->zeroOutput = true; } else /* paComplete or other non-zero value indicating complete */ { /* Finish playback once currently queued audio has completed. */ theAsioStream->stopProcessing = true; if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) ) { theAsioStream->zeroOutput = true; theAsioStream->stopPlayoutCount = 0; } } } } ++buffersDone; }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 ); return 0L; } static void sampleRateChanged(ASIOSampleRate sRate) { // TAKEN FROM THE ASIO SDK // do whatever you need to do if the sample rate changed // usually this only happens during external sync. // Audio processing is not stopped by the driver, actual sample rate // might not have even changed, maybe only the sample rate status of an // AES/EBU or S/PDIF digital input at the audio device. // You might have to update time/sample related conversion routines, etc. (void) sRate; /* unused parameter */ PA_DEBUG( ("sampleRateChanged : %d \n", sRate)); } static long asioMessages(long selector, long value, void* message, double* opt) { // TAKEN FROM THE ASIO SDK // currently the parameters "value", "message" and "opt" are not used. long ret = 0; (void) message; /* unused parameters */ (void) opt; PA_DEBUG( ("asioMessages : %d , %d \n", selector, value)); switch(selector) { case kAsioSelectorSupported: if(value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest || value == kAsioLatenciesChanged // the following three were added for ASIO 2.0, you don't necessarily have to support them || value == kAsioSupportsTimeInfo || value == kAsioSupportsTimeCode || value == kAsioSupportsInputMonitor) ret = 1L; break; case kAsioBufferSizeChange: //printf("kAsioBufferSizeChange \n"); break; case kAsioResetRequest: // defer the task and perform the reset of the driver during the next "safe" situation // You cannot reset the driver right now, as this code is called from the driver. // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction // Afterwards you initialize the driver again. /*FIXME: commented the next line out */ //asioDriverInfo.stopped; // In this sample the processing will just stop ret = 1L; break; case kAsioResyncRequest: // This informs the application, that the driver encountered some non fatal data loss. // It is used for synchronization purposes of different media. // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the // Windows Multimedia system, which could loose data because the Mutex was hold too long // by another thread. // However a driver can issue it in other situations, too. ret = 1L; break; case kAsioLatenciesChanged: // This will inform the host application that the drivers were latencies changed. // Beware, it this does not mean that the buffer sizes have changed! // You might need to update internal delay data. ret = 1L; //printf("kAsioLatenciesChanged \n"); break; case kAsioEngineVersion: // return the supported ASIO version of the host application // If a host applications does not implement this selector, ASIO 1.0 is assumed // by the driver ret = 2L; break; case kAsioSupportsTimeInfo: // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback // is supported. // For compatibility with ASIO 1.0 drivers the host application should always support // the "old" bufferSwitch method, too. ret = 1; break; case kAsioSupportsTimeCode: // informs the driver wether application is interested in time code info. // If an application does not need to know about time code, the driver has less work // to do. ret = 0; break; } return ret; } static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaAsioStream *stream = (PaAsioStream*)s; ASIOError asioError; if( stream->outputChannelCount > 0 ) { ZeroOutputBuffers( stream, 0 ); ZeroOutputBuffers( stream, 1 ); } PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); stream->stopProcessing = false; stream->zeroOutput = false; /* Reentrancy counter initialisation */ stream->reenterCount = -1; stream->reenterError = 0; stream->callbackFlags = 0; if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); } if( result == paNoError ) { theAsioStream = stream; asioError = ASIOStart(); if( asioError == ASE_OK ) { stream->isActive = 1; stream->streamFinishedCallbackCalled = false; } else { theAsioStream = 0; result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); } } return result; } static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaAsioStream *stream = (PaAsioStream*)s; ASIOError asioError; if( stream->isActive ) { stream->stopProcessing = true; /* wait for the stream to finish playing out enqueued buffers. timeout after four times the stream latency. @todo should use a better time out value - if the user buffer length is longer than the asio buffer size then that should be taken into account. */ if( WaitForSingleObject( theAsioStream->completedBuffersPlayedEvent, (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) ) == WAIT_TIMEOUT ) { PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" )); } } asioError = ASIOStop(); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); } theAsioStream = 0; stream->isActive = 0; if( !stream->streamFinishedCallbackCalled ) { if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } return result; } static PaError AbortStream( PaStream *s ) { PaError result = paNoError; PaAsioStream *stream = (PaAsioStream*)s; ASIOError asioError; stream->zeroOutput = true; asioError = ASIOStop(); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); } else { // make sure that the callback is not still in-flight when ASIOStop() // returns. This has been observed to happen on the Hoontech DSP24 for // example. int count = 2000; // only wait for 2 seconds, rather than hanging. while( theAsioStream->reenterCount != -1 && count > 0 ) { Sleep(1); --count; } } /* it is questionable whether we should zero theAsioStream if ASIOStop() returns an error, because the callback could still be active. We assume not - this is based on the fact that ASIOStop is unlikely to fail if the callback is running - it's more likely to fail because the callback is not running. */ theAsioStream = 0; stream->isActive = 0; if( !stream->streamFinishedCallbackCalled ) { if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } return result; } static PaError IsStreamStopped( PaStream *s ) { //PaAsioStream *stream = (PaAsioStream*)s; (void) s; /* unused parameter */ return theAsioStream == 0; } static PaError IsStreamActive( PaStream *s ) { PaAsioStream *stream = (PaAsioStream*)s; return stream->isActive; } static PaTime GetStreamTime( PaStream *s ) { (void) s; /* unused parameter */ return (double)timeGetTime() * .001; } static double GetStreamCpuLoad( PaStream* s ) { PaAsioStream *stream = (PaAsioStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaAsioStream *stream = (PaAsioStream*)s; /* IMPLEMENT ME, see portaudio.h for required behavior*/ (void) stream; /* unused parameters */ (void) buffer; (void) frames; return paNoError; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaAsioStream *stream = (PaAsioStream*)s; /* IMPLEMENT ME, see portaudio.h for required behavior*/ (void) stream; /* unused parameters */ (void) buffer; (void) frames; return paNoError; } static signed long GetStreamReadAvailable( PaStream* s ) { PaAsioStream *stream = (PaAsioStream*)s; /* IMPLEMENT ME, see portaudio.h for required behavior*/ (void) stream; /* unused parameter */ return 0; } static signed long GetStreamWriteAvailable( PaStream* s ) { PaAsioStream *stream = (PaAsioStream*)s; /* IMPLEMENT ME, see portaudio.h for required behavior*/ (void) stream; /* unused parameter */ return 0; } PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ) { PaError result = paNoError; PaUtilHostApiRepresentation *hostApi; PaDeviceIndex hostApiDevice; ASIODriverInfo asioDriverInfo; ASIOError asioError; int asioIsInitialized = 0; PaAsioHostApiRepresentation *asioHostApi; PaAsioDeviceInfo *asioDeviceInfo; result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); if( result != paNoError ) goto error; result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); if( result != paNoError ) goto error; /* In theory we could proceed if the currently open device was the same one for which the control panel was requested, however because the window pointer is not available until this function is called we currently need to call ASIOInit() again here, which of course can't be done safely while a stream is open. */ asioHostApi = (PaAsioHostApiRepresentation*)hostApi; if( asioHostApi->openAsioDeviceIndex != paNoDevice ) { result = paDeviceUnavailable; goto error; } asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; if( !loadAsioDriver( const_cast(asioDeviceInfo->commonDeviceInfo.name) ) ) { result = paUnanticipatedHostError; goto error; } /* CRUCIAL!!! */ memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) ); asioDriverInfo.asioVersion = 2; asioDriverInfo.sysRef = systemSpecific; asioError = ASIOInit( &asioDriverInfo ); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } else { asioIsInitialized = 1; } PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) )); PA_DEBUG(("asioVersion: ASIOInit(): %ld\n", asioDriverInfo.asioVersion )); PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion )); PA_DEBUG(("Name: ASIOInit(): %s\n", asioDriverInfo.name )); PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n", asioDriverInfo.errorMessage )); asioError = ASIOControlPanel(); if( asioError != ASE_OK ) { PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) )); result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); goto error; } PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) )); asioError = ASIOExit(); if( asioError != ASE_OK ) { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); asioIsInitialized = 0; goto error; } PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) )); return result; error: if( asioIsInitialized ) ASIOExit(); return result; } PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, const char** channelName ) { PaError result = paNoError; PaUtilHostApiRepresentation *hostApi; PaDeviceIndex hostApiDevice; PaAsioDeviceInfo *asioDeviceInfo; result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); if( result != paNoError ) goto error; result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); if( result != paNoError ) goto error; asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){ result = paInvalidChannelCount; goto error; } *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name; return paNoError; error: return result; } PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, const char** channelName ) { PaError result = paNoError; PaUtilHostApiRepresentation *hostApi; PaDeviceIndex hostApiDevice; PaAsioDeviceInfo *asioDeviceInfo; result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); if( result != paNoError ) goto error; result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); if( result != paNoError ) goto error; asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){ result = paInvalidChannelCount; goto error; } *channelName = asioDeviceInfo->asioChannelInfos[ asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name; return paNoError; error: return result; } nyquist-3.05/portaudio/src/hostapi/asio/Callback_adaptation_.pdf0000644000175000000620000014253711466723256024144 0ustar stevestaff%PDF-1.2 % 2 0 obj << /Length 1731 /Filter /FlateDecode >> stream HWr6>!vO2ts C|p(0" s9g}-\TĚ̏1ߺ?oV[nE2 fnGd؟^,+=؅̑`lL۬TBRQT$QqN V'Efv8\}qBL1qKܷ0i.`YBU אf4$U)lD%r<Ѣ\nƀ21:2 ]HB`J,X~یdL}eDi$;%(`TR~V*rᰤeƘ峘9i¸xa@YL U5!luM2TDR(lVbΘ@Zb0oUVjYmY}eAg':p)֘l]&H1u%O jmFEDiNa(5|#U ǨaB(Mx:TZՏ$SV4l4e$=0-լ-ՌZaZ$KYVEu= xL)rpY_ڽVV{Ơ&QDm KFꝦ8 -f\K@ԇWQ C/hڿzY.~CY!LXSVD'g?5Qn3;ĞH6[ͧd6 #0_R^*)kI);gL:X:ʣl !;?Ͷm: 4ݦJ0dT0͝9 "%܋f\׉}߮:ꍝ(]nBB˶K@*BqLwVbJ2KQFa)جYk #!.ۣcbc )9PKkD%幩f'ӾV(:v)jZ&S"q)Qn;I2 o eVFBǫL7f3mu4WaUv,W&vo|زƔPx1P0p{MnWRܒqlCQm\KMp|q_j+^،qh;fʄ6Gu+&G`G66O$,`q}'US8lZ$l8ŵ'6s{]hυGH+69ndg} nqQȣ^!P.\ŔQ&m"XW62v‰NꙆʔanNy:3۝0aŲ40%, h`~xr32i^&WMG5 vwvd9u١_@47xX쩩,&Ū㳰Yc?PE3,xؐkY fT_y%8A9zxfPs2ʎ endstream endobj 3 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F3 6 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 11 0 obj << /Length 2123 /Filter /FlateDecode >> stream HWێFC?*ƨ;f q$f}[3)R!_U}!G͈ͪSs?o#G8_yi 'wKS9/2$ݫ"YF}Q`)1Xn&o׺HQOٞ{|\L^guRI[O~o"̽|Drx0b:b Ǭ,9n4"zቃVd@iI>F&K"A!c4 Ƚr*d$3 }udU VTNdʘsMYEtjMDQ ɘ J&cD&{RUn/b,6*3Js˄mi +{UV7dy}4ZQͷqssKAH L(E8[h&"1J@=n 8WX(QҞ0 S>Sd.T0YCeQU&+I^[UuOd1벮+^N\>/AF*o}<cˠJѯؑԠaJE3gJ}J6Fݐ;7Klj-jlUh&UR8sv1BTO@9FL;.XwuBSC3}ծ>a4tPR΄{/vVIoRۙd׶8㦊@޻p6 ivxSd\tqiFs`/wXN] &#@9]>!t0o^R;hlEa;dfd6\tұrSo`~7#T{>[@puNP8b80+Јg;t P5jo;Мk=;V=gE!6 ʬSZJ9a@I9$sS{Le{Aa[EBehNmN:ݐ=YsùڽVş'X* rL7+Fm NhwmQM\'B&;Dj^m ۏ`2<ʮ=ԉfO 6΁{Pm3?c*+whHdO@/~31sX$gb ؀d;׵wĀv$aҙ #cw-@!lSΎ,&h :i70걓EH"GG()nr,z!ԭw]bz@B.CW&w=P1^$ "~} j@S9|58OG}Q46kXAs':[O"PHa1t`a밌aa֋Y T ='\ENs Hm?ͯz_ym|?>O70 WfzsW"dĝէnm x P^m> /ExtGState << /GS1 8 0 R >> >> endobj 14 0 obj << /Length 1921 /Filter /FlateDecode >> stream HWnF<*Eswy5qKE}H@I+ EXq3{H"E3ggz9|ǁr;c.?= wU3q]rMOG<>υ# vEUêne U92-J(Tk勯ˏ*H@YC)g[4DDߑp.lD t! ܧ5v`!i|r[X0v{:Ǔ?h ޓZݐQ8$HT_c"`1*b[ `gb*DEKCl:zTϡlXXySwˉ,#Hb!jX,` ة ܶxV-,Ҩhi; +v",9aYYm0 a@I",BFPdCʒLWK13sX#xqˡ H$/q>"V?c#$ FP3HFSddɛ`$#,b$5N37H V'ID\1xπ*F2aFxB7`$+1R[?#HVlƖxxP0gGy Edo%V<Lj !JdIPgBƐyf ٷʐ l:mHIeH=^?P/.6&*kBE==O6gCS74mAhvSWu{fʍL:Mz`ONR͠6K%wyaӔCrufaio;QU(ג{ˌnhK7[!Y"a)ʁwES}5  j]VHK}fS7- ÄÅ!/41cr^iEDvO,Ya\I2pRo%NA?Eb{󡨪t=05,(q)亩qkezGSѰ[akDB/~jаcJf}>y1+==>6nSxc5ն ~&:"w;Fp$ -zռAuUs&꒺8僋JzdxwE%:sʽ޽odY~1w@e\7iuȒc(ӂnOz/ZDXP7pݽXL5 [^\=K1QnRۙ6< WU\D}hȀ~4۹,MW̊> /ExtGState << /GS1 8 0 R >> >> endobj 17 0 obj << /Length 2160 /Filter /FlateDecode >> stream HWَ8_:e7m3ӓ\7!΃,ӶYђϽ)+Uw9`T`%p2aA(hb^I0K4d Ʀ*~*Z5-~U|Ϥ;)ШoEݷ$ l~@ays MD.VxF6Djo%6udSRS;Za5"ĮQ笨lqk@u{sa-l ƘsÜ\6ұ,M ce^s}օa椀hHQJu&NY*xRu.YE"}=dB+ȶ7~ߒA! w i"2yd"ee`W8𠒩Y*1 VXr~VUgMVuJAЬ#_1 1UXĩA9\x Gli$SNAu_ɗ2iw9.aYI;kg"[ޓ/Kcޖ@ia$"m51:Wmw&FP4Зsp.Q͎(<]Q&8tC?RiFe->t,]V2T M@oLY|UCǜqI`}dl%Ka>)@ϻ{m8$R@_ l@Z=C\0lXJds$k`}>견5=`ADVdyqPSyïݜT?~A^#^!J0ىe<@)}ux{ۿm0-HBcQ '? S|L!Ip;0C>LpR 6iFI/cD1;<|)/%nb?ҏJ~R8?m\VV]F.^$lk@.| zBu۪;w> m7dk49X{|H<[ߔ̵]B6'Tωߝԭ8 Z'۫@d &D'`(yfpCKGŞzbTs#Փ@t\UOd^,Q r|>{/ e 6VfThb,$:9g;jQJuΨYb6rp2nW?cOcPrluE]2N$rѳ13fur} 뵗F8oh So n7ÊAÁnw&?y>o[`OğCe h0zf P \ť-. #3h|5Fv#l<9{xٓWq%Lko#Xah WH0vR&-%3ua%8t꡴iU?Nߩ<[Z˿nn!c@+-( N?`- 0\ަP6+Ny ڨw$2† U>mu9,THSݗ{tl Pҭɀv> kӁ/:9§1>piDX ;=oj\qjN6vq{elC(x10в]6<6MQ6&Kr ?u~/dvζ3gr讞zbh 2SچIӻ$3 4sU h>ՓRJxSX/h?;- endstream endobj 18 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 20 0 obj << /Length 1738 /Filter /FlateDecode >> stream HWnFüP^xKM}H@+ EXu{gv)KQA59{\_ϝOWPB0:ٻ ֵ㹞KbOJx $MY7hW+UA +p+hk|:xAlGBC(sB{$ |A;2-OShG5N͉8ǠLnͿiƂGIɘ?r4O1cT7baO@GT9B}с7'v\Y,Mu= 8ᰈX C;W= Ϸ8:]mrhg;iaҞ)sYLZV#-CIB7%X!|N )&uYdI ENQɠd5>$E { MWI?*um߃s'Y{|]VY I^ # +)aYnwmB%y\(/Q ^gOI۶:/MGqp,=;IT=(һ("+t8+PDFQ:K_T%I/* "Ex-ҋEӒEDFQ|\QDl_E3.)sQk$EA21~[qXy6wVϱQGZm ەޡ;K8xBΑ} $l q$ȥvdVY`WzqtFPh`43#{45 N-G&-92RSÆ צXE簪u)FػS0E gUu| ר FlT A*/:+ c3_eUuKV=`+4jXwh$4TH%{t܃eL{큚Ue.U«e{jUVۤX",p0\smU)SXIR|I}W8w ^8yԍ ;d`sjĈm.וŷB08dMc ܥ ԝB8Pr,[d& ] ) qMfn!k;nMjt5$5b[4:܎ogט!=/"Uu&?z6Y2}Im)͸}P X+zK ^Qe:^ T[l̴D(踍:)xUy@f#H|a5Zrk])LK/%x@*GV7 vUGÛ4[y^> /ExtGState << /GS1 8 0 R >> >> endobj 25 0 obj << /Length 1283 /Filter /FlateDecode >> stream HWnF @J(r%@ĽJ }@IF"^H. }`ڝ9s6Lo(q@?}vӟܗvOWa!D߭SRB@;<`yHӤ8[á7P$աԍ[CdIN֐ͅxvIV ~E\ %P@6YO<fWwXvu#=lJ7eS:,Ŀ8!_*nY_h4%0S Wc(<:zOc軫9K|X_<xǾGܬQH֓T:]j2b!_-$Mx]ƫOetCTjnu'*NRIpChŰy]v<Ϸ2xjB>54YXFltz*6)̃#Y*FQ.+OA<$~ïeUVbujgɴfY &XJ$6Q^HABKKXijX3k;5)92Xg h ݛUQiZ&Xj}2t>pBε)0knڙ0jPuȜڼ\&ښ`<;m~O~hぺ'`06`qI0M #'$m4.b9lLL4<ݞFs >@r(d zZohzyIۨp/} ,%s&wp).ճ_NGIVBF΂Ru_Qă+bhDž Ka~Aa* <[aAOny,fWq+:(y;aVGdMtGIh{D n3"z 7k {Vy71zq֢S38,ޏ51WbGGC-saQ":*4ўIM~-$0o\]C,KO8Xf'8>#@ endstream endobj 26 0 obj << /ProcSet [/PDF /Text ] /Font << /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 28 0 obj << /Length 1309 /Filter /FlateDecode >> stream HWn6<ʩŐ},M)q}Pl*Q+K,'IQ7KNR%pf83gFVˏ0X%(D>v3 O 3z6̊*J 8͟prEmF8>&|.MOšpLQާ Wz2wFF eձ̡R۽*WypUQ㇏Q&zPqe߬K.vc%P= 8*-f@񓮈`8ZZ[Wز`m .LIsu\^xZڿ;u$erW}#v|l${~A6-a@z2D͉O'֓L܊Ot^Ç?=CW +ĶK<s0Kwӆ?BcujD{ '?G"r EY6buÉP]I=fUdq(QY}5돘 [܈*cDN1Nù <ۇP  C9VPϾiZ)]6Ԧv@ ,-RUK{s{9"#6jRoIFR6pj S}u-Rc8m N y%< 9*-r=j6x Dag:UMuhAu0tr~4qy`,d9ii, Ɋ.M q T1Ftj7<(t {f5yty v]Mip oq~>MB$Q/:ݣ޽ˉu[%^xZ{fWqr#*V}El׋oU,_)٬eDeeV,TgACPh͙JFӑy :lzAI@]~ZTVT^]Dj ]<—SSAa8vt7k^raVS5{Дzn_j(a-ɷ+~afE5W!tF!~,~ȄLsB&%`0GK++ OߦRyA0KY[%o-J*b&*9&ʅM۫hTG3ΣHٟW? endstream endobj 29 0 obj << /ProcSet [/PDF /Text ] /Font << /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 31 0 obj << /Length 1378 /Filter /FlateDecode >> stream HWnF<ʮH.pIAR4ʓڢ,"-⒔eץw̜93;|?@a@/aMO?p_N,bcß4-{X,.ɷuw:]-D2K6 'hqG!s6A!U"ۦqCaSuxp+aq~~? (*nza(,܌:4McHrR8WbEC߱)Kl2t#'c+fMNn̸z[vev59Hr*^*>en[\ 5knUVcFI]EI#us#C\~H G] n xJ֐Dh[;pYPᆴe\]6, LFv{t Vknw1ś'0U܎J凛M˒|y$ٸ`g&*ȈYbc{lXW͓WǮ]JI#Bn2c"=j˩ft9Z Sե?V#Eim(rɦ{CS򪩘7!y$h@t 1D.wBvLu/`K5@[4DZ ('!V#]'hҰg=hka\Þkzhl|jТӶwWB||@^e۾G(E͠GYq?*#GEcm\ ['7#~2~Łw8XTro .r |t>U_ۡW)/JI)dɘ; w"v1C= =3q\l/_ǭhsXlp.ҴO:"/!ŢL:)zn CY\0J@}dP7XcV{U z̙mp94W3HpSB\(}e+Q"Ypq>ϗ^q(u,VQMwkDNv/fL$G4,e K tZ.\("_Xa1W)o endstream endobj 32 0 obj << /ProcSet [/PDF /Text ] /Font << /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 34 0 obj << /Length 1284 /Filter /FlateDecode >> stream HWnV I(ލKH)بU- 2HF[;wTir9sv9@`x ȁ;_c;ç+yǸ~H߄vF\/#_s T5~uQnK+:ZuswN /e 0=!BT&O'u|W>[U[Nƃ  QiÝކD؄9^*~Oȷ}4 %LAcBÄs5GhUU OY0{eA ݞa8RF'ٟϤa+'%v|_'% I[&$Cn%r]aR nPmhcVm0X~ٮɩhŵ g^_Bt٦i ѮQ-KIm6ΛSL/h d8mA ny̖#j̕4,Σ .dMW+Bv\WC33wQC׀0TXXrgSaěaN=,2 qb⻽^b6 \^Ffaa0%3ėZLn(Ӿ U%©MIj4]ͨ'`ݱ0Jq}.ar&2f[iT3ZBnV4r !% wdͱ";%U81!{[5ZMhdljz:ƖL*Qqbm]hD8@c"2}XJ %_ꀞ͢R;vV,8́ U8Z+v VOq7Bq{/y5+FtFx5So.5\~0r9P,O}ǧhɻxɑ^Z%yp<zY8uO;yR2Fi̫֙>D"OhEEuXh8:(J\C\KcY&Ãg} h|2dZmֲE]F_> /ExtGState << /GS1 8 0 R >> >> endobj 37 0 obj << /Length 692 /Filter /FlateDecode >> stream H|Tr0<8}s4 -Ƀ, XT$_#ɐ4M:%ٳgy* Gc ÿ tG`;^Qؘ%c9pwUH՜?vh$6z$$!3pπ.Ve ^5W+b !iaDcEQ{VAkؽ:ˊYhk 5->"NFH“#4XS¦eaY,R X Fƥ(x*y7mDW|Ԍi9Ƭۺ~vTKX++x^ON;FtF;kǝ\:kK [EV;(Z(bDz'~S9Dg3W^.$Yr@t{O&2@we`[l`Z w{^ߢV;u&=I9!B < YQq% 9mȊ=ŷ5͟vIZ:Z8epꧠ",qvJa!WCknFTs-07> tZq!J0\G8[SxdvzΌQ\_:+. WG">gخb )\/K4%~ܰ'{=}~(+!C2 p>)iM) S^? P endstream endobj 38 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 39 0 obj << /Type /Halftone /HalftoneType 1 /HalftoneName (Default) /Frequency 60 /Angle 45 /SpotFunction /Round >> endobj 8 0 obj << /Type /ExtGState /SA false /OP false /HT /Default >> endobj 40 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-167 -216 1009 913] /FontName /HDMHLH+TimesNewRomanPSMT /ItalicAngle 0 /StemV 0 /XHeight 447 /CharSet (/less/three/i/G/t/S/eacute/equal/asterisk/bracketleft/j/u/I/quotedblleft/U/d/greater/five/k/v/comma/plus/bracketright/D/six/m/L/hyphen/w/W/l/seven/n/M/y/period/x/at/H/b/o/N/z/B/eight/Y/bullet/c/C/p/nin\ e/O/slash/T/zero/e/q/P/colon/parenleft/one/A/space/E/r/a/f/percent/two/quotedblright/h/s/R/F/g/parenright) /FontFile3 41 0 R >> endobj 41 0 obj << /Filter /FlateDecode /Length 10588 /Subtype /Type1C >> stream HdiTSWX{}ŭ6zܷ V@A ;b! ! bX:BdM+Z+qqq:x#ډ|={^;ey>t8oP"PdJRC>Ln.$FrTrXs]\>d%$Yrec CG$ &mYA8茸%Zن ;dA^4#A2$ȶ d]=pA0 ˃=q]oчE89v pqv_xXEvGa^\v7{<{='=Ser9Ks;_2oVt]yqjju~ ͝"و$D*I7\ ?}F9OOS UiV͹ݨf(?q곴;vJhߕF e!,@K(e J*A%W5éo[IMJv#y m&c4R(ίYUE%)J !u2xP AN7PMZŰ KKW\ȘUDwjf ( pyأO\mpj$ p1Aٸ9VO?~}NEy d`#:›šB׭GMЩbp)= .d]{nA`}xon 3 B@"<(g͏[Z1&pEDyV7%[zT/O/cLN5|Z^;~ɻR&O:iNZD*Wj(um}~#a0ThΖ>KHUkbQul@44 C-]k(o7\S</zR;͢ˑb՚󍄱ї%,7QrSag "^/4tǪ^o2JSn45TFYL~C3”0E~ ÆkZE+ޡh A$gjZԥ qyel6"8F(H\%zYk'\7bCwI娰6t9-WHE"͘Ee[:*Zo--'Η-(KuŹxx_I ?OG㸿t>ik3b̪zk{l&O&d&0YrۈVKe6*-mxk%DYr3Ƿ!|9~±6N }v/p' /}eq-!cm1FCVpx )~׎o&оK} W\>v5"*s$L BEt pJk1pˁ8SS>;D,~.D9Mzo㷌S4l ( I&гlリ3$\$B(E;-³" PI;wl4G^E̘Y/5$,Ae4\AϧU%6$6Ȫrϣ%JU`tZ[5,\V+`(vK%#}Ek5+pp[ \}O-f"n b>9?G 6t=y֕$;f'լٰ{[$`DR$[S"6- 櫔 Ri_iOw=Y; 2J8( 6vCq r82#0HPD9GA QTVW㛙7RMܮO٦nC7hh~]-<[4ȇЍ%M?fTgIEZǵ뼬#!9(; cLJ^0@ 7-$ih=&džnlvk_XճR{G5`.Z+D+l aG2$.J`8/3B};z0US-#]WT5N0cRoe\hDj͉MbZ&p& h/ܴBN+i)nmg/wʁQf7+눯C #3L#e3rf𥾟:PAvƳq1AYMԑ\z~VI5pl{ tN"hzpǷ>\ pC hCC$eU7 Aș&YOhdb5z5#zY{Ym{ܸs}5&\kJ E%ohX2߂~W3^Q15v7l5Oxa Xq(S(&;H?iYhe5aZ_LKf1-q>I??F{#9؜:+(ݰ>iuvOaxVIFό8h;\Om53I&g+ nX#"ᙘjnLJ%9Y-%iݹ[|#ОUABVئaԧۆA9`3 TӾ?q p4i*pc4梅e+u@Vr@sFZ'ַ# IJ/Y@swEyg`4 hA;Hb[- ܀!bѲ`5Z"2dv;d!WOdA[:_-~c嗠-S+ {ý {oay9b#rW9yXsY'[کxyZCcr3VFXRu;Adʶ%EEEG S$6NH .CQتy텟:Uo:Ow Q(;;ݵ/v^ʔi}NoH3? D[Khԥãda6tu} &HE:RYY#=cs/ޑݵ;.' iLb'+s.5x,yyūyu#p|DRC%eZH+)e1 bA&l*fs#i2*^kTu#pca%< OO14*h1k&gK8M//ܨuU,.ؽ70Y+Ӹ:+-Bm6G{D?DJBȵ|MNP gpAJzd;$rkz\9מ;@ToДSVؽn=vy<77hD,h"S4B"qbx ߁ a,Håp/4`}߯{`blkQ4 An rp4oI@]6/g!dBȟF~r2` D [&г#gnT7_{ɜCݺz ?yZz:ty[b漨tVi=C|)de"*/f"D$ "qn2@abAw%v-%ڇhM0Tzyu=٥2ЮI_n I iXTx0*Okfӽޟµ2k%ꨪ̇*bN8.; Jd_Eg\&Ksqv)N)7ԕwZr]2ڰpoޱ뎶uvڂm "b@DB7!^*>0!$! IL (o~ ::֝ٝ>vssN;ss~;~GE)؁TI 7q3Pت'bm2W) ǰRɆ!&IGїYU1FL j9B$dI; IY+((OC7kGIm|D<{$o6O[bj!5۵1$#lK0RÛgbbOi&@|6h_Jwo鵮o׎ ̠R6Y;1`f<[+K yg_+ӓCJ^/r/:/kG_0F1`Ba Q0>u~]BF4ԭla]:rSىXIU V cJKJV#Ri-*Le9~p0tY>!'vDF{KSSJ3@z:Ggd{ujnRqդ#&PR:cNK أ=Gv0"L)uü*3Q2MSfKws?U]]5=EUI`-lg9rZGuYE:Ԛm\P'F]q<5n'{).>͗'[#"4./K^ ׳W%/M`}Mo >qB.Iޕ&Õ['\B9rAKqVmVEq3 AxO'96.;i.ŭ#KӍ^'3*Φ7*M}͸͸\SJ\K닋H|t(g~#nQZHU;;Ssmm/P4\wlޓ$*-HQVt_8j5Z 65aiɊ2 xgx :l}?𸠏ut} [x>ک5;&Фl8XATHJ+5:Vwh Oϋ-daV@cTKr~VV>OQL9,EaM 17A}~@CR7say11Ϡ:x3PM': Ԧ~BNPʼnI$$ogN+ɍ(qۮc׷m\;#ޞGNO vM:(rXXjN&?r8.y0; G;\anY\!- ufudeǭil2x 6)/u ჾZP#[Y=遺,OB\%lbtOHؠƻb_sȞːgf/2x?X_G^T+<%y?@G(dfa_d+ W- S8l>sT0z!2=Ϙ$ ̡qI+iSBH `MFH87ߙ)4Bh`Hs ܭ#00Zq6Pq[%={7y^uУ'N loӗ8=. Lf=NmJn,l 3IU2-*awv8Qw8I_I lPTKTX<˖:R \&"L!~i:+ HI/Vr4/5;com{mUQz<6չhC@h($nL秺?~8[22:=luxnAmmqZfEyH l`d$49+8'l`e`5M//T,;-ដc}ca;YüWgcD4Rt(?+LQAZXxq3;];8\דD+c)\]㲘o%$1Ua&^Zz?E:B+m Ρ d|b';LWyD ;Rא? j \PiV).(@d'TʡkvC4J^Cxn:#)vsd8[ 0>$!&`F 3@|Gu܇RB E\糘T OZC05*A6(ɴpr(ש&`T lBFa $k]`jFGri9o >-'(#^g ZwITk^6L)JUJ{)LJ%VT,aЈ~ >{>}5B ףY@4xgg4䣝>5/ W, @ﮊ~ NRjG("9F5j5@x}S(y !#sUQ`4cfZPJb ,'v~LcH)WGGO@xEZ4뵨bL:(/PU.& Bx]kхcnrSl-%eE=;ī%717O# One0b4ǼaZJb(˳;Yv (;n 3IU )JsJokBjlccCw7;ȇX-FPRm*Y*EE:*uSu30ZN~Qh0IAr `r;ʑ[3G?8HvM٣@Q>b v@1{ YHwvVӏNc:p>gn'8';'[lV!ݒ6ȚBҴ$M @Hb6|6;i؀C d$4 ڭiXv֦1|Fd?L?0}?~>xܕ^.[;( `#z!0{?{c-~Fص舼Ze?wer,ZWd DG'0&'IwO,y[t]hPSm )bIjFlbnmYi^jݩ;C₨|Djk8bOcğ`94r3ɢd!^^lѫP t532E,x &뢊`/^l Q+߫2% Ө9؝D~}+ м < WQf'\ hΪdP= !uRyr.t4]\8bF\IFT/o5svnd+I,|{ ޞg) z5hSׄ_ݑ'7ֈեG^ ݊[XMDPo(A/C v9kB_r_SH@;7gZJL9lzpIIK1O]2'؝(VNmcdXDC>sc`cڈ$@$|GH {NHʨ2]hVjq4K61QeYqNa씧:!~R}.Gc̓njnG ^Z\ ˯_M8s{qj 7#V{0P)'ߞ҈>6E0r_o_S4/VُMLԋ{v`jbAuA藳YZE5T_UaCCLP%kPLfBgLAI+ݴ|$/#3V GC".6dh<D47rxa2PjWZ+O:L Ж+E|30Kn-=3 zfh`I:Ae]$opk'+nt>`r(GM07G Y'IE.첛mzb30U%@S63} M4pQ>k26 c!p̟dҾn0+ёI0Ezn=[ZLjjlg 3㦰 I< B/:=ER=#f! u_sC;cCA8$)x%rD1uM`gC (FybͪvjŜm!}9@SZQpJ"^]x=|Kǃ!=U.÷B)$եᗎMI\b ;-xU<0^HA{E9]*)IdrL'MJCDz8opժr&%pLo - e/; 8CܶaK8׹ȨY#&gbBP'$;$Zt^`VM=AkOf`#yNG 2@.CS!>YO%1+#M;ggCmY]^bfپm'`42_+]yxH0)1'7dUUIʎbštQ^WB4NWֱ╪4* ŋWU"`Ϯ''KCIQLqg0Lnt})ĵN ٩qa&Mnov%# "3ȁ싧L[/)3jOB2rƱQ]9C9lZc~4ڻalƑ 蕉)uɉZ#-kn9-+xS~"k%"R$Ѷ6c-E(OP>+nul䀾_ju</6lQhufnrg]Y޹݄4wmR, sb-{tx!ߚ"=yR[$%Ru酙rI9@/;uQ_SD~0dw endstream endobj 42 0 obj << /Type /FontDescriptor /Ascent 662 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-184 -226 1009 913] /FontName /HDMHMJ+TimesNewRomanPS-BoldMT /ItalicAngle 0 /StemV 0 /XHeight 457 /CharSet (/three/bracketright/i/t/asterisk/quotedblright/G/equal/R/four/I/u/U/plus/d/quotedblleft/five/k/v/comma/m/w/hyphen/l/seven/n/M/y/period/percent/x/H/b/o/B/N/z/bullet/slash/c/p/C/zero/T/e/D/q/colon/parenl\ eft/one/A/space/r/f/a/semicolon/E/two/parenright/h/s/g/P/bracketleft/F) /FontFile3 43 0 R >> endobj 43 0 obj << /Filter /FlateDecode /Length 8304 /Subtype /Type1C >> stream HtTmPSWF,RݪłHTP # _@B>IDZ1 $|J@ "bnGΨmθ 9ݰ;y3gy3s<`P?N؝.Y$% 5 dxeE,,! L ]/ﺐ MPD2;)5gcfzl%8P<Աy*z,Ix9~_GP{ \KybGi;t"B[**'tDhKtapmeh4h܆՞+\䏶&$$‘(Hʗ~IQv"W=|QA -0n9._\lA "s۽s+í0 p(A\B$C4׹#Yqz 4hQPr3?;pxpuHy>qi̊X3  Qe!.W)U{I4v:=D[ZNod2LB+(UqyZB[G:ٚ.|ufemm X7e-"Pd]nֶtTmX }*+}zBuGKI yd#1訳u_REm>-PfdRkuGrNϙ&kùA`uunuHTѪ"C /2)[fԤ1ijaEޠؕ!Vy rw[C*-**ܛ<?R%R <1GFI{ˆvS6M̉ghc \B> 6d~w>Q,rz GzD|!Rl!*QO Is9#=j&\r'̓LxX\ɏ]vtEQ))DA& 1g5eޱᡄ/@<6Y:MoJt _pI08\d\LgVEi rTaRRB[{ #|ra2nY5ybG;XB^Lw-{nՂjD!^erf|X[[rm#J돘=[T(E%EG@"2͙9|AJ9ۤZA3Rx6In.K/FAU *UłjX{0\ǿ#1%8 !hI1*!  + bQOZVww\')J-jK,פha(x%]$췄|=eh|@䮿G;&8>X@ɸe|΃Y 'Vd5:"M!҇;DYV$Ԩ~h"5=S4~kJp+*_, eiff.w4\K9L1K h1È9Gl|-c&DO͙3>Bط- kp>$Dd$0F\ %NShV(Fn9Fo{ |o_`S7j^}x)#HFju:mDHlp2bprp1YLyP!p)ym6_J*}񙾵=k q,<1jr%>FX .^}f =Q:^n 6~W5AS]ZG@HEH"?NUg:[>u馴W~{4NVbKK%cDS{Aֱ4C`V>B8s J2=/Ð] Occ(5qDҬ<\'6r0[{Ŀb.>(-Q<`AV 5oZn=F.E Q~ՠN2ŸwkT}ʷh}]dWD,l&T'|qB 3}•o 5=~uW7o#پEc蹎,m٩hՉD!Uz"~^|]<nUdN 57j)-Dꁰq azS%o~3Ty T^,PjFѾ[aQPV]WLn2{,3,ו((Ø(>[JC-]gYT2f>^rйCa$xEӟAxcS_>T]EWdgeveMo[X|2 D{B+@mUEV_%!) Q ǭS8 g8@EaزzrΔMeMYzScIiF1~a:4x1ٔC E-<;zBt3iDB-p{%emLlWoB LN׿gS{; ql{ DR -jh}G%_U ޹@/; > bu݋,$z ;q|`vtB?ƩX33)hۜ4{f憶zo6kƺfJ;k=2\ (:h>Op$N3[|(#H(ښ ?K=Jy*XbP Z:YvE8*c+lD-c FS" +Jd|$BV>J۽z"hT扚jܵSۮCNEbNKv:rkE[h҇)=S }Zdtd/ժp\se!.kz@8rƛ}~7p;i ֢4Sm0 eiLJU m܆0j WUDxC`wuHyW'9É})IXb!S+1RHAI:C18 I:+TZ"6ԯuʀCf큉@kK5-LV!,UlQ dFOٟDLm=zG<{z\_lAZl}s#2]A}?:C^!]h+m.F z5f u:\[[^b8y~"-O{ᓼ0ei`y`"@ a NXk[5$mcoMB7*UJRSk,$R8eve/и# ȑd7.S;TB 3A$JAS W c^o(Oa HA#QIG*rL釢?(;W#iޱL"!LVeUw0vmSo,#!q %ג;`l7 G.zK xMsB&IQJMJ.| "$FjMbd̝Sm0 }uӔ<}ױag881ȯ_%ҥV!RQ;ވI<Ć}4D|}H}< Z):į5dRzAGkkִ35mk 7񕕆O)"( YarFpGQpOZ"+L&b;w sC+b]@kq98ե!xVbsjE|I+D$2Uɭ* %8 g˯&8;q]z yXr}b 6| Ľ`IV/g;F?TCa_zZ,R1\#9Z%_!ψ/iet?8=hwwyMi֣pHvby}=e=IY/@F1kl +:a#-Eɗȧdvb MS=&jA9>jh@U{.*&SkQEqUq]ǔK"U3p(:Ѷ+{6H'V5Xt7 Tc'zW\eVa^Ù(h?#PMzn+lmMh/ƎJ of\XlԽ_;m&%4-Z+Z 6lC;,/?"JIJAUsF E /3 r'q7sb+-+&&s$R Qvt0/GC>7XzE#JN\dPn(*#ilp<2{,Ȏv[gGsXWrQr 9BnOb~aq5F/=¡ӯW &KY!F >s 9Lvu5@CEWwBlLu&JކZgk Fá=𞫇 _yDZx> endobj 45 0 obj << /Filter /FlateDecode /Length 5656 /Subtype /Type1C >> stream HtiTSgo{Ј̽nm3TDlJA)I!Đ!$!d\ l\¾Ⱦ+RTZ(qFE9˳ޗٮ z.!!_)Hcq!oc\-ڥuK\v0Qyk{n{;8uy!oC@|@&g0WIVAFr W=tm6CNP b{6{a,fw tôaXVXs}o{?%<0֪R. --K`-pia.q9ʒs"LT*D:Ui›ʪ)ꚰ&M"(L$dE\8C7G?OUDG+DJIQ2aʒ* ma# MNQ Uh(10.E Z?RX&#ej yT#f<١7/DNzcaя,mKm0N` T{՞7TbTوT Ic=XW[b@˨cQ%sȪ39*DU%j"^~sIKƓ%sr"EMEirj10(CaZ]q-,Wߏ>h*!^ygјyp6. s`xgDwqwB/A{=d_\M7i FZ' J)7Z`x2lji+MyNdfյwnWu\'wuNֶ.L [NO졯0sW}DY8b47R vߖ0HSjP23/WiN!OJ /D 8m*${%ڎVZC/"g|^߹-_`RP"4GI 2BʭEm@b: hnnPjjw}9\"S9 a<]f9G#c)3jjoJ,_#/j2jɖԊ(,V*F X+m\XYGhD9qĩ9*(ýE}+Qi J^gџ6WɛC$͍; J"`6}CHyxVP> j*OkuyXi9?Q|0= K>, F;N4b'4Hisf`sewd[SMV poWd:e[L*#YĔ(n{2gG͗"S+Z_/%F>w#%QdTjH\b߿˪qy t~ -ƨlds#w=G|VCVƘE +8:R##TwXu/MKbhnrfz;uyZSVbݱ\"_Vd)4y4O]Rar}!P*skjLG?6uh9b?ؖB;x+Eh0['woٞ+s) le%vԟ2⦪\,Y]d˴b"/+WlfSA\r?iGѶVt [U1ġA9+9T$yg9v`}5|LX,P C%GF'F jء8Qxn)}./cTi4qm+g0ʢ7t;'ʊA35C ݭzN|&1muhgYd9ogg1<֓.h&aV_x.נ4wܞ̺%pZ]+[gjR/]1ܼ`"$B; !\&za]]\uVwvJvĺrgy6o?MYl/iH{Õp<|~@[Ib%yGl ` '.aކΦ^qw3[sO_û;2ʖ;*egvu|sы| 1Hnܙ>v .{BkkVNdF]Td.t|XR=?U;De,o OHERD!ҡ:Q~}HF^e"\Q+̮( ʊShuzk2ఛ̩+mY-oBqLJȫRVne@UEޡĽ so5ߍÄqx.{̀i#{"Sz\ĭRMB%\m~)%J'907>r%+NV&&(%Nr,J*Id)cH#N%}XA{wWDth 4!<Ќ[k¡0GsG#p-*dk? ~\ :0JWUp:U$.9vuoq+ v18YlYC?&+d b+:k]b/m%x~^j!M?QbDL w6@ *ض Un&)VUci H:jVJތ*V>* ,e 2-*V/ρqytjfFQ;#?^MZf1c.2ɧ8$^gpzM3Ѭ6)du֒ qB[| :cEN:w~"<Ɖ T%W֪qީ"~B!\)z(B1pi]FkLSs->YOݠ\gE Z=+Ur޶\.I[ˀ(!_v n$*uh }?~vkrXY"֏N;"ThfWS -CUՊZ[Vnk7;'i->[ s`-zLJԩp+2kh07rw~W^Y<.ŭZjLMZR4yܵ-F>{pC8 DhC?)OI-ٳU~Z MUp]m:(<]}݃#][:= |j2^64EK4[1KoPr4aM< ̬H@}mеQ.xDst (eT=)Du+0a*~x>Ip e?mkgzFm acǁ'O=Ev>?6Kd|?nsO%0>7cb ]GR0r|71pJ nռS4p(*V,eS5ԒXBP{,IFHM*΂lv28'mh @.K0_fQV ʔqӈ4O>e Yʤwex޿qkĒD(I,r"~!e2Z.t;{nq^??3zf5)wܲ9e9Dt8~ɤ@]z?r-T,-h ! Leq."31Q(^&|<&$TXrxQ>l؏#ށS` W c{ EWH,&[.Rk5k}SRe40M(3DYv qe~]]a[9;ɾpxϾCP\\G>l[~`:->{QT1h V}.Q1@QowjHTUJQ8U19aefi4fz^\ VVցty]%<J+j'q$om\߻XfZ =Ik.DDN,+DRB[K+nR!Cm^O`9$)T,F¾ɄɃnd OWPQ@$l baTMerB.хX:çǕC lb,B }4($=ѵ=s>/` ##KX }1N1BZ*n"yGMOd R+>pLv<O %\> ߇'M/vXX`W˥5RzZ9q_N@Q@x\#[artarcqrqT8PLFtf+쵎?yLQue&1"ԉNciE3lm&BӍ5 ׂߏ~Ns*+2RsUU\<6?1\&5-! u_sX`G֎vlj~_rZ \O0}Ų(s`ɍj\]>$JX"00ݾksD?㭞id/SE"B2"8-q4PuU]9^f&a_?E2_60WkGa0>o.Qk5n!Zg8n6v$A91/cxK#I3I);ir] 9&'( i@Cx4M2j XyV#Q eؓ(̌M ;oIW?Qߠ<"ww.m ~ a.qWV 8l0> endobj 5 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 555 500 500 1000 833 278 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 394 220 394 520 778 722 722 722 667 722 778 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 556 500 500 500 500 500 556 556 556 556 500 400 500 500 500 350 540 556 747 747 1000 333 333 549 1000 778 713 549 549 549 500 576 494 713 823 549 274 300 330 768 722 500 500 333 570 549 500 549 612 500 500 1000 250 722 722 778 1000 722 500 1000 500 500 333 333 549 494 500 722 167 500 333 333 556 556 500 250 333 500 1000 722 667 722 667 667 389 389 389 389 778 778 778 778 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 46 0 R /BaseFont /HDMHMJ+TimesNewRomanPS-BoldMT /FontDescriptor 42 0 R >> endobj 6 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 420 500 500 833 778 214 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 422 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275 400 541 778 611 611 667 611 667 722 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 500 500 500 500 400 500 500 500 350 523 500 760 760 980 333 333 549 889 722 713 549 549 549 500 576 494 713 823 549 274 276 310 768 667 500 500 389 675 549 500 549 612 500 500 889 250 611 611 722 944 667 500 889 556 556 333 333 549 494 444 556 167 500 333 333 500 500 500 250 333 556 1000 611 611 611 611 611 333 333 333 333 722 722 778 722 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 46 0 R /BaseFont /HDMHNM+TimesNewRomanPS-ItalicMT /FontDescriptor 44 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /Name /F5 /Encoding 47 0 R /BaseFont /Times-Roman >> endobj 22 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /Encoding 47 0 R /BaseFont /Courier >> endobj 23 0 obj << /Type /Font /Subtype /Type1 /Name /F9 /Encoding 47 0 R /BaseFont /Courier-Bold >> endobj 46 0 obj << /Type /Encoding /Differences [ 0/.null 9/nonmarkingreturn 13/nonmarkingreturn 128/Adieresis ] >> endobj 47 0 obj << /Type /Encoding /Differences [ 0/.notdef 8/.notdef/space 13/.notdef 29/.notdef 128/Adieresis 202/space ] >> endobj 1 0 obj << /Type /Page /Parent 9 0 R /Resources 3 0 R /Contents 2 0 R >> endobj 10 0 obj << /Type /Page /Parent 9 0 R /Resources 12 0 R /Contents 11 0 R >> endobj 13 0 obj << /Type /Page /Parent 9 0 R /Resources 15 0 R /Contents 14 0 R >> endobj 16 0 obj << /Type /Page /Parent 9 0 R /Resources 18 0 R /Contents 17 0 R >> endobj 19 0 obj << /Type /Page /Parent 9 0 R /Resources 21 0 R /Contents 20 0 R >> endobj 24 0 obj << /Type /Page /Parent 9 0 R /Resources 26 0 R /Contents 25 0 R >> endobj 27 0 obj << /Type /Page /Parent 9 0 R /Resources 29 0 R /Contents 28 0 R >> endobj 30 0 obj << /Type /Page /Parent 9 0 R /Resources 32 0 R /Contents 31 0 R >> endobj 33 0 obj << /Type /Page /Parent 9 0 R /Resources 35 0 R /Contents 34 0 R >> endobj 36 0 obj << /Type /Page /Parent 9 0 R /Resources 38 0 R /Contents 37 0 R >> endobj 9 0 obj << /Type /Pages /Kids [1 0 R 10 0 R 13 0 R 16 0 R 19 0 R 24 0 R 27 0 R 30 0 R 33 0 R 36 0 R] /Count 10 /MediaBox [0 0 595 842] >> endobj 48 0 obj << /Type /Catalog /Pages 9 0 R >> endobj 49 0 obj << /CreationDate (D:20011113180235) /Producer (Acrobat Distiller 3.02 for Power Macintosh) /Author (stephG4) /Creator (AppleWorks: LaserWriter 8 FU2-8.7.1) /Title (Callback adaptation) >> endobj xref 0 50 0000000000 65535 f 0000048145 00000 n 0000000016 00000 n 0000001820 00000 n 0000043970 00000 n 0000045177 00000 n 0000046394 00000 n 0000047606 00000 n 0000017725 00000 n 0000048972 00000 n 0000048225 00000 n 0000001944 00000 n 0000004141 00000 n 0000048308 00000 n 0000004256 00000 n 0000006251 00000 n 0000048391 00000 n 0000006366 00000 n 0000008600 00000 n 0000048474 00000 n 0000008715 00000 n 0000010527 00000 n 0000047705 00000 n 0000047801 00000 n 0000048557 00000 n 0000010664 00000 n 0000012021 00000 n 0000048640 00000 n 0000012148 00000 n 0000013531 00000 n 0000048723 00000 n 0000013658 00000 n 0000015110 00000 n 0000048806 00000 n 0000015237 00000 n 0000016595 00000 n 0000048889 00000 n 0000016722 00000 n 0000017487 00000 n 0000017602 00000 n 0000017796 00000 n 0000018332 00000 n 0000029012 00000 n 0000029518 00000 n 0000037913 00000 n 0000038223 00000 n 0000047902 00000 n 0000048018 00000 n 0000049117 00000 n 0000049167 00000 n trailer << /Size 50 /Root 48 0 R /Info 49 0 R /ID [<771b01795fd0dc9985670387ad003bc2><771b01795fd0dc9985670387ad003bc2>] >> startxref 49371 %%EOF nyquist-3.05/portaudio/src/hostapi/asio/iasiothiscallresolver.cpp0000644000175000000620000005534111466723256024524 0ustar stevestaff/* IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for the top level description - this comment describes the technical details of the implementation. The latest version of this file is available from: http://www.audiomulch.com/~rossb/code/calliasio please email comments to Ross Bencina BACKGROUND The IASIO interface declared in the Steinberg ASIO 2 SDK declares functions with no explicit calling convention. This causes MSVC++ to default to using the thiscall convention, which is a proprietary convention not implemented by some non-microsoft compilers - notably borland BCC, C++Builder, and gcc. MSVC++ is the defacto standard compiler used by Steinberg. As a result of this situation, the ASIO sdk will compile with any compiler, however attempting to execute the compiled code will cause a crash due to different default calling conventions on non-Microsoft compilers. IASIOThiscallResolver solves the problem by providing an adapter class that delegates to the IASIO interface using the correct calling convention (thiscall). Due to the lack of support for thiscall in the Borland and GCC compilers, the calls have been implemented in assembly language. A number of macros are defined for thiscall function calls with different numbers of parameters, with and without return values - it may be possible to modify the format of these macros to make them work with other inline assemblers. THISCALL DEFINITION A number of definitions of the thiscall calling convention are floating around the internet. The following definition has been validated against output from the MSVC++ compiler: For non-vararg functions, thiscall works as follows: the object (this) pointer is passed in ECX. All arguments are passed on the stack in right to left order. The return value is placed in EAX. The callee clears the passed arguments from the stack. FINDING FUNCTION POINTERS FROM AN IASIO POINTER The first field of a COM object is a pointer to its vtble. Thus a pointer to an object implementing the IASIO interface also points to a pointer to that object's vtbl. The vtble is a table of function pointers for all of the virtual functions exposed by the implemented interfaces. If we consider a variable declared as a pointer to IASO: IASIO *theAsioDriver theAsioDriver points to: object implementing IASIO { IASIOvtbl *vtbl other data } in other words, theAsioDriver points to a pointer to an IASIOvtbl vtbl points to a table of function pointers: IASIOvtbl ( interface IASIO : public IUnknown ) { (IUnknown functions) 0 virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0; 4 virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0; 8 virtual ULONG STDMETHODCALLTYPE (*Release)() = 0; (IASIO functions) 12 virtual ASIOBool (*init)(void *sysHandle) = 0; 16 virtual void (*getDriverName)(char *name) = 0; 20 virtual long (*getDriverVersion)() = 0; 24 virtual void (*getErrorMessage)(char *string) = 0; 28 virtual ASIOError (*start)() = 0; 32 virtual ASIOError (*stop)() = 0; 36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0; 40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0; 44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize, long *preferredSize, long *granularity) = 0; 48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0; 52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0; 56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0; 60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0; 64 virtual ASIOError (*setClockSource)(long reference) = 0; 68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; 72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0; 76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) = 0; 80 virtual ASIOError (*disposeBuffers)() = 0; 84 virtual ASIOError (*controlPanel)() = 0; 88 virtual ASIOError (*future)(long selector,void *opt) = 0; 92 virtual ASIOError (*outputReady)() = 0; }; The numbers in the left column show the byte offset of each function ptr from the beginning of the vtbl. These numbers are used in the code below to select different functions. In order to find the address of a particular function, theAsioDriver must first be dereferenced to find the value of the vtbl pointer: mov eax, theAsioDriver mov edx, [theAsioDriver] // edx now points to vtbl[0] Then an offset must be added to the vtbl pointer to select a particular function, for example vtbl+44 points to the slot containing a pointer to the getBufferSize function. Finally vtbl+x must be dereferenced to obtain the value of the function pointer stored in that address: call [edx+44] // call the function pointed to by // the value in the getBufferSize field of the vtbl SEE ALSO Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same problem by providing a new COM interface which wraps IASIO with an interface that uses portable calling conventions. OpenASIO must be compiled with MSVC, and requires that you ship the OpenASIO DLL with your application. ACKNOWLEDGEMENTS Ross Bencina: worked out the thiscall details above, wrote the original Borland asm macros, and a patch for asio.cpp (which is no longer needed). Thanks to Martin Fay for introducing me to the issues discussed here, and to Rene G. Ceballos for assisting with asm dumps from MSVC++. Antti Silvast: converted the original calliasio to work with gcc and NASM by implementing the asm code in a separate file. Fraser Adams: modified the original calliasio containing the Borland inline asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax for gcc. This seems a neater approach for gcc than to have a separate .asm file and it means that we only need one version of the thiscall patch. Fraser Adams: rewrote the original calliasio patch in the form of the IASIOThiscallResolver class in order to avoid modifications to files from the Steinberg SDK, which may have had potential licence issues. Andrew Baldwin: contributed fixes for compatibility problems with more recent versions of the gcc assembler. */ // We only need IASIOThiscallResolver at all if we are on Win32. For other // platforms we simply bypass the IASIOThiscallResolver definition to allow us // to be safely #include'd whatever the platform to keep client code portable #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver // is not used. #if !defined(_MSC_VER) #include #include // We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is // #include'd before it in client code, we do NOT want to do this test here. #define iasiothiscallresolver_sourcefile 1 #include "iasiothiscallresolver.h" #undef iasiothiscallresolver_sourcefile // iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want // this macro defined in this translation unit. #undef ASIOInit // theAsioDriver is a global pointer to the current IASIO instance which the // ASIO SDK uses to perform all actions on the IASIO interface. We substitute // our own forwarding interface into this pointer. extern IASIO* theAsioDriver; // The following macros define the inline assembler for BORLAND first then gcc #if defined(__BCPLUSPLUS__) || defined(__BORLANDC__) #define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\ void *this_ = (thisPtr); \ __asm { \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ } #define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\ void *this_ = (thisPtr); \ void *doubleParamPtr_ (¶m1); \ __asm { \ mov eax, doubleParamPtr_ ; \ push [eax+4] ; \ push [eax] ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param2 ; \ push eax ; \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ void *this_ = (thisPtr); \ __asm { \ mov eax, param4 ; \ push eax ; \ mov eax, param3 ; \ push eax ; \ mov eax, param2 ; \ push eax ; \ mov eax, param1 ; \ push eax ; \ mov ecx, this_ ; \ mov eax, [ecx] ; \ call [eax+funcOffset] ; \ mov resultName, eax ; \ } #elif defined(__GNUC__) #define CALL_THISCALL_0( resultName, thisPtr, funcOffset ) \ __asm__ __volatile__ ("movl (%1), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"c"(thisPtr) /* Input Operands */ \ ); \ #define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 ) \ __asm__ __volatile__ ("pushl %0\n\t" \ "movl (%1), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ : /* Output Operands */ \ :"r"(param1), /* Input Operands */ \ "c"(thisPtr) \ ); \ #define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 ) \ __asm__ __volatile__ ("pushl %1\n\t" \ "movl (%2), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"r"(param1), /* Input Operands */ \ "c"(thisPtr) \ ); \ #define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \ __asm__ __volatile__ ("pushl 4(%1)\n\t" \ "pushl (%1)\n\t" \ "movl (%2), %%edx\n\t" \ "call *"#funcOffset"(%%edx);\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"a"(¶m1), /* Input Operands */ \ /* Note: Using "r" above instead of "a" fails */ \ /* when using GCC 3.3.3, and maybe later versions*/\ "c"(thisPtr) \ ); \ #define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 ) \ __asm__ __volatile__ ("pushl %1\n\t" \ "pushl %2\n\t" \ "movl (%3), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"r"(param2), /* Input Operands */ \ "r"(param1), \ "c"(thisPtr) \ ); \ #define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ __asm__ __volatile__ ("pushl %1\n\t" \ "pushl %2\n\t" \ "pushl %3\n\t" \ "pushl %4\n\t" \ "movl (%5), %%edx\n\t" \ "call *"#funcOffset"(%%edx)\n\t" \ :"=a"(resultName) /* Output Operands */ \ :"r"(param4), /* Input Operands */ \ "r"(param3), \ "r"(param2), \ "r"(param1), \ "c"(thisPtr) \ ); \ #endif // Our static singleton instance. IASIOThiscallResolver IASIOThiscallResolver::instance; // Constructor called to initialize static Singleton instance above. Note that // it is important not to clear that_ incase it has already been set by the call // to placement new in ASIOInit(). IASIOThiscallResolver::IASIOThiscallResolver() { } // Constructor called from ASIOInit() below IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that) : that_( that ) { } // Implement IUnknown methods as assert(false). IASIOThiscallResolver is not // really a COM object, just a wrapper which will work with the ASIO SDK. // If you wanted to use ASIO without the SDK you might want to implement COM // aggregation in these methods. HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv) { (void)riid; // suppress unused variable warning assert( false ); // this function should never be called by the ASIO SDK. *ppv = NULL; return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef() { assert( false ); // this function should never be called by the ASIO SDK. return 1; } ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release() { assert( false ); // this function should never be called by the ASIO SDK. return 1; } // Implement the IASIO interface methods by performing the vptr manipulation // described above then delegating to the real implementation. ASIOBool IASIOThiscallResolver::init(void *sysHandle) { ASIOBool result; CALL_THISCALL_1( result, that_, 12, sysHandle ); return result; } void IASIOThiscallResolver::getDriverName(char *name) { CALL_VOID_THISCALL_1( that_, 16, name ); } long IASIOThiscallResolver::getDriverVersion() { ASIOBool result; CALL_THISCALL_0( result, that_, 20 ); return result; } void IASIOThiscallResolver::getErrorMessage(char *string) { CALL_VOID_THISCALL_1( that_, 24, string ); } ASIOError IASIOThiscallResolver::start() { ASIOBool result; CALL_THISCALL_0( result, that_, 28 ); return result; } ASIOError IASIOThiscallResolver::stop() { ASIOBool result; CALL_THISCALL_0( result, that_, 32 ); return result; } ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels) { ASIOBool result; CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels ); return result; } ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency) { ASIOBool result; CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency ); return result; } ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) { ASIOBool result; CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity ); return result; } ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate) { ASIOBool result; CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate ); return result; } ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate) { ASIOBool result; CALL_THISCALL_1( result, that_, 52, sampleRate ); return result; } ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate) { ASIOBool result; CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate ); return result; } ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources) { ASIOBool result; CALL_THISCALL_2( result, that_, 60, clocks, numSources ); return result; } ASIOError IASIOThiscallResolver::setClockSource(long reference) { ASIOBool result; CALL_THISCALL_1( result, that_, 64, reference ); return result; } ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) { ASIOBool result; CALL_THISCALL_2( result, that_, 68, sPos, tStamp ); return result; } ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info) { ASIOBool result; CALL_THISCALL_1( result, that_, 72, info ); return result; } ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) { ASIOBool result; CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks ); return result; } ASIOError IASIOThiscallResolver::disposeBuffers() { ASIOBool result; CALL_THISCALL_0( result, that_, 80 ); return result; } ASIOError IASIOThiscallResolver::controlPanel() { ASIOBool result; CALL_THISCALL_0( result, that_, 84 ); return result; } ASIOError IASIOThiscallResolver::future(long selector,void *opt) { ASIOBool result; CALL_THISCALL_2( result, that_, 88, selector, opt ); return result; } ASIOError IASIOThiscallResolver::outputReady() { ASIOBool result; CALL_THISCALL_0( result, that_, 92 ); return result; } // Implement our substitute ASIOInit() method ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info) { // To ensure that our instance's vptr is correctly constructed, even if // ASIOInit is called prior to main(), we explicitly call its constructor // (potentially over the top of an existing instance). Note that this is // pretty ugly, and is only safe because IASIOThiscallResolver has no // destructor and contains no objects with destructors. new((void*)&instance) IASIOThiscallResolver( theAsioDriver ); // Interpose between ASIO client code and the real driver. theAsioDriver = &instance; // Note that we never need to switch theAsioDriver back to point to the // real driver because theAsioDriver is reset to zero in ASIOExit(). // Delegate to the real ASIOInit return ::ASIOInit(info); } #endif /* !defined(_MSC_VER) */ #endif /* Win32 */ nyquist-3.05/portaudio/src/hostapi/asio/iasiothiscallresolver.h0000644000175000000620000002222211466723256024161 0ustar stevestaff// **************************************************************************** // File: IASIOThiscallResolver.h // Description: The IASIOThiscallResolver class implements the IASIO // interface and acts as a proxy to the real IASIO interface by // calling through its vptr table using the thiscall calling // convention. To put it another way, we interpose // IASIOThiscallResolver between ASIO SDK code and the driver. // This is necessary because most non-Microsoft compilers don't // implement the thiscall calling convention used by IASIO. // // iasiothiscallresolver.cpp contains the background of this // problem plus a technical description of the vptr // manipulations. // // In order to use this mechanism one simply has to add // iasiothiscallresolver.cpp to the list of files to compile // and #include // // Note that this #include must come after the other ASIO SDK // #includes, for example: // // #include // #include // #include // #include // #include // // Actually the important thing is to #include // after . We have // incorporated a test to enforce this ordering. // // The code transparently takes care of the interposition by // using macro substitution to intercept calls to ASIOInit() // and ASIOExit(). We save the original ASIO global // "theAsioDriver" in our "that" variable, and then set // "theAsioDriver" to equal our IASIOThiscallResolver instance. // // Whilst this method of resolving the thiscall problem requires // the addition of #include to client // code it has the advantage that it does not break the terms // of the ASIO licence by publishing it. We are NOT modifying // any Steinberg code here, we are merely implementing the IASIO // interface in the same way that we would need to do if we // wished to provide an open source ASIO driver. // // For compilation with MinGW -lole32 needs to be added to the // linker options. For BORLAND, linking with Import32.lib is // sufficient. // // The dependencies are with: CoInitialize, CoUninitialize, // CoCreateInstance, CLSIDFromString - used by asiolist.cpp // and are required on Windows whether ThiscallResolver is used // or not. // // Searching for the above strings in the root library path // of your compiler should enable the correct libraries to be // identified if they aren't immediately obvious. // // Note that the current implementation of IASIOThiscallResolver // is not COM compliant - it does not correctly implement the // IUnknown interface. Implementing it is not necessary because // it is not called by parts of the ASIO SDK which call through // theAsioDriver ptr. The IUnknown methods are implemented as // assert(false) to ensure that the code fails if they are // ever called. // Restrictions: None. Public Domain & Open Source distribute freely // You may use IASIOThiscallResolver commercially as well as // privately. // You the user assume the responsibility for the use of the // files, binary or text, and there is no guarantee or warranty, // expressed or implied, including but not limited to the // implied warranties of merchantability and fitness for a // particular purpose. You assume all responsibility and agree // to hold no entity, copyright holder or distributors liable // for any loss of data or inaccurate representations of data // as a result of using IASIOThiscallResolver. // Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from // Andrew Baldwin, and volatile for whole gcc asm blocks, // both for compatibility with newer gcc versions. Cleaned up // Borland asm to use one less register. // 1.3 Switched to including assert.h for better compatibility. // Wrapped entire .h and .cpp contents with a check for // _MSC_VER to provide better compatibility with MS compilers. // Changed Singleton implementation to use static instance // instead of freestore allocated instance. Removed ASIOExit // macro as it is no longer needed. // 1.2 Removed semicolons from ASIOInit and ASIOExit macros to // allow them to be embedded in expressions (if statements). // Cleaned up some comments. Removed combase.c dependency (it // doesn't compile with BCB anyway) by stubbing IUnknown. // 1.1 Incorporated comments from Ross Bencina including things // such as changing name from ThiscallResolver to // IASIOThiscallResolver, tidying up the constructor, fixing // a bug in IASIOThiscallResolver::ASIOExit() and improving // portability through the use of conditional compilation // 1.0 Initial working version. // Created: 6/09/2003 // Authors: Fraser Adams // Ross Bencina // Rene G. Ceballos // Martin Fay // Antti Silvast // Andrew Baldwin // // **************************************************************************** #ifndef included_iasiothiscallresolver_h #define included_iasiothiscallresolver_h // We only need IASIOThiscallResolver at all if we are on Win32. For other // platforms we simply bypass the IASIOThiscallResolver definition to allow us // to be safely #include'd whatever the platform to keep client code portable #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver // is not used. #if !defined(_MSC_VER) // The following is in order to ensure that this header is only included after // the other ASIO headers (except for the case of iasiothiscallresolver.cpp). // We need to do this because IASIOThiscallResolver works by eclipsing the // original definition of ASIOInit() with a macro (see below). #if !defined(iasiothiscallresolver_sourcefile) #if !defined(__ASIO_H) #error iasiothiscallresolver.h must be included AFTER asio.h #endif #endif #include #include /* From ASIO SDK */ class IASIOThiscallResolver : public IASIO { private: IASIO* that_; // Points to the real IASIO static IASIOThiscallResolver instance; // Singleton instance // Constructors - declared private so construction is limited to // our Singleton instance IASIOThiscallResolver(); IASIOThiscallResolver(IASIO* that); public: // Methods from the IUnknown interface. We don't fully implement IUnknown // because the ASIO SDK never calls these methods through theAsioDriver ptr. // These methods are implemented as assert(false). virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); // Methods from the IASIO interface, implemented as forwarning calls to that. virtual ASIOBool init(void *sysHandle); virtual void getDriverName(char *name); virtual long getDriverVersion(); virtual void getErrorMessage(char *string); virtual ASIOError start(); virtual ASIOError stop(); virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); virtual ASIOError setClockSource(long reference); virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); virtual ASIOError getChannelInfo(ASIOChannelInfo *info); virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); virtual ASIOError disposeBuffers(); virtual ASIOError controlPanel(); virtual ASIOError future(long selector,void *opt); virtual ASIOError outputReady(); // Class method, see ASIOInit() macro below. static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit }; // Replace calls to ASIOInit with our interposing version. // This macro enables us to perform thiscall resolution simply by #including // after the asio #includes (this file _must_ be // included _after_ the asio #includes) #define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) #endif /* !defined(_MSC_VER) */ #endif /* Win32 */ #endif /* included_iasiothiscallresolver_h */ nyquist-3.05/portaudio/src/hostapi/asio/Pa_ASIO.pdf0000644000175000000620000014313211466723256021250 0ustar stevestaff%PDF-1.2 % 1 0 obj << /Type /XObject /Subtype /Image /Name /Im1 /Width 243 /Height 270 /BitsPerComponent 8 /ColorSpace 2 0 R /Length 4603 /Filter /FlateDecode >> stream H , YYZv1 /=O~2_ ei7cQv?ݑP ~901p)8#h%g5W EG U7e'5ukH{TUƳ}w*[u*U1OI yUQ&] D^0C{-_kY\`d>fif}yCxr-ЅlC\}S4mb23;y`MrtpF u95ƥ[$:Cxa)T H "߄{bmZ1򎩐=2svM)s೧dgt+\FIa􈸆chiex9.q4dsz64Uj57HQS LU~pkAlI=10K3KF쨱&uϽ5WȬ&EÚ [N-SeM*yêkd.#CA6dEkM_>Xq9F˪, v-Ͻ5bf f,\ޛ690'K!3pSYګn̓ýoFѩ)}{6kyUCR[oMW;BL&\`W$|;S1F@G>s'^X8/Ȟ2;g2z`R&8%2EqG)jKnq82,(r8 ?yBudNwD{+6`m#|Q2\,>n06/!9fy~9B4.s5%c$Σw!]qW9{ {U iod\j`mca,^ǀ?68>^Dz9,) Ӏ;p?DCbvi@$D#2" TF;MmU$kAUD;NLAĢ]"¥oGTެNV$3sKY[~7f6d4sُToǻ07r{dΔeV݀`e3-8=kߕY 0&Ε' w˓2[%Ms|_-3E] U?VT3%o}̻-io2'9>zo0 Uy5x>6uL+sU]܇eto=;i ^dֿ}kW'޺UnKύW HپQŕ;B5SR#V 7).q.O\L?lAUÉPEQ|<2 Ʌ-X磡Mw=xT{!'~d[ f '\v'ad]]f1A?0hK\C X]36)y~hDX/rJȞ $78VGldx CcB%GO TyRȿo縩Pm ˞eo aInWb@O7|v+pPȧad([KlډM٥ӭIݶw45iʎZ熜lijc(3цX6uLnF2TyYQ1'N2p6HQ rXh}LuX` 19 msW{ŰLFl@HCG닐_8_h[BMjk}r#NJnD[=(J;vG :$ ynY6eB:٦gA7گ&fŕ2yy|'FPEEZXȚEm&n"ʼ,KO?L52Yskh\?Zk\0q|T[MZ%8.άRTLY]Ys ;1l}Ygubw7_^lInz&(nt?<`znԬqR#"ߘ' =䂑1B\A|~U@ba>u:3xc> stream HVmS8n`oI?㆖^>(Ԓ+!)3yvW%j4a"$ E]-(FaYߓ>ޛf9§ΪJ+E[lFpQ<F ȹHNhU>'1f&Mt z|3HX 3@e@_L^}w2pm"y,)Gh1b>qm7BKG 3wf"^ p, iԘk8Zpv{ >w^“u(\X-91gr,ZI  FiBm{s(vn@V4v JEƒ8r{ YYaUjdՓQNa׹pD+UaDY*ZpR;Iڮv#y4iW M< E/!\vKؼ/gC%%!>$p ~Ѫp߻SP翔Ҳ m[5vS*ŰB ZO1I_YUPQwP08jBbx/T-VxX(qC8B nǕgyoG(99 aZZB!(i_yRs=v]>ԃi[bc6ۏMFq 1\R^,>/b 5RhLOK77RK!l.Z9C@SVcNE?i,|묣l%}ꡡZӵąTGcR( 4P>R%yGbHk*+q%݃Ƚ͖"g܃P $Z;|C;_67ݘdE6 ,ɞx|@R|%Hl Nd#%-_2ZUH0|U(PImpsވVUdqֈ:> p<:]Ꚃ+C4aU0֣y߅ ޔōiT(Q'atxoWwM~t7I> /XObject << /Im1 1 0 R >> /ExtGState << /GS1 10 0 R >> /ColorSpace << /CS1 2 0 R >> >> endobj 2 0 obj [/Indexed /DeviceRGB 31 12 0 R] endobj 12 0 obj << /Filter /ASCII85Decode /Length 124 >> stream s8W*!!!(HqdXct#lK[ZWb0":,AO&LG endstream endobj 14 0 obj << /Length 1977 /Filter /FlateDecode >> stream HWr8 y8Vfa&[SܥHE~vBl%"ŠoO7~]_#ՒQWHI+J_bf本7ӊx^OC'6nqAf_z$'E$Y`U\'^c2Y9xfl_b!J,pXOgƵ+ڊ,YY{KB h<<B@ȨƌA,42*9KB; ѢW. h)%\Mh$~=vz8Mr"؄O/V|. QfXL7@n~꺦԰<WS K&D'Vc=%2%+"| E A6u>ԛ 6/H}6,Դ-y~(Jn~g~lCm`HJG6cȷ%@طklsCG<<6zl.CHh5HƺmPL<#ٟ M1gom'D꽉Rd2As .,LTaE +Ң帗M ԵTQ:E0Ui \[!)<+amf7K8WaC*sjV<3@b%iHcGZ>4Tg>Z{Q)yPJQ\{ 1 =P;Iy פ9FI;a%˾8- [ 8I+% 5]̍ e#QʨH dm8H9l>2K`8erv%TW,:ԂƫQCw0F)_mpicvH[n…`͛4tg}75BfO<|7{V7CƑy4Rc [i|ݘX]M!y,*l{\/`,㋻կ%,`D8k/>_/ey֠32/VqWN9-{bЂYMlLpy3qq9rccV.EBgK(q= /7;S뤇Gwݮ"($CM he뼅sk\Zz —r۟Z@7}> /ExtGState << /GS1 10 0 R >> >> endobj 19 0 obj << /Length 2177 /Filter /FlateDecode >> stream HWr<) +.ki%M<)E$P 0JJJ&>adw\?I IREv톒ͧ18nhx]VM0M.b<)r5\J(w8k_<5xRӷ;<8r=֝~Mx+0~b+)\HS 0ߟ%OcAu;"B7~nQ#B&\\{)Ju=OA al>{^U'y1ں+'Mv6sA|MC{av/pS/Ra|zB97[/'#:L1@$eCHw]S$"ϗHS{_%K "u:9-2DʪңA9ECtV۲:*$1 ]Þ҂4;ԏ|y 6x8ޱ4AA#2#fձGlfSs5*ߧ ?Mw?sc/KY2rlUc)rh[x4ZQ幭}dwDI!d)QgaAz$C9ƀ}" -N ckA@xɾEh3bX$- {)ųK^52= g?uJu+pn R7)h  ?e>TĊuC$w+~B,|B쵁_%ԑrUЍ( 00up6!|>Q/f5-nOqA~pKIo iy)OUؒr>epn.vE7~GY ,ajEW. ]$JjxbP<.n:s56%=׋kO}ƏyU_;dUyhŽPp{]Tk'wtQ0c0KkRY9z[^X=H, qn uTXŰ`%) VȻ (HDknoG endstream endobj 20 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R /F7 16 0 R /F9 17 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 22 0 obj << /Length 2371 /Filter /FlateDecode >> stream HWnFC? , o n Q!^2aߪpHΌ,b hXsԩ(dWliH?#$d܄?>Qo )|ZO4o~UpDjPVZ kQߚ}H Q{Q|&Ϫ^h|!egSuu=tGٛBAx ђ{71𠊃ʱ@3 Sr=bic`V9{0g'Ը'WɌF.xȬ@ "zyM.ӡ6ޚ'39; u3s3#M_r>BJṜ8aLΘ"O+:Ll쳡<212;SBCnWg `ѿ-en[2-Yuos'<dDhFYZ(}e3 ;\4ngz{ 6p/=XYvFS92%Gs?U;zpM|>uB &FH$o tѕKGYW)(<> ] fTD̆-JJ/Fq<M`:i\3l2EuBfj?TPF3OB3)0[n=ɦu^Œ_Q'ҞZQ"skk."08y5̫rّ,`o ޳'/5Z, hlA>]Fp1~8˵|wQ/F#GV8I1~X 2<ܐaX7vӣ-^IN:8X sw_-?3[pA2Kr>z"1_.Rh",G< /Q?v=) BjKo5Djf_Amn;HAUHNh\  {Cw]}q6ShOD˦E{5IQ;U{xX_DXV#+lOWX6yK{ a6k- E6͹(r]7} 31XUZ)K:.;jerU1<@cTn $,3OEXw7`&u endstream endobj 23 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 25 0 obj << /Length 2239 /Filter /FlateDecode >> stream HWks6(Zvi6;M[$dq͇~Ń)I$3VDsFYoΖ, 0"Ruu7oy & ]ξ,sdQdq#q./_ 67#ʃC{@xإ.w}n٨CVzT d5F  |Zq[k/5itX'{\8 6\.Ekt 4mo+Rt]NdMXs$б6Ml |"ITNXdCIK&~LA\mZ8LhW ~q F g1o8@e&k.>]|=dzhDE,c.z <^:2) p*~o>‹N72K* k@JEYҶHKEn2E\c?uaЍj_3\{,^];".W7؈6~QpId_:x<^\gIHk=C"KQ,CTI aTӒΞt'z/.7=ΚUva 1*cA]?$PnBƊF$nJn^ nh4`nF4un[t);' ʜZJ|O;LYW;UE@,cy[<avQlHaH^*g. bD4?CAVv0|;J֐VQ$Sg{i9M0#/ t\X.a-2u+;k Ew[T"]prP겶_i&l VH@FUaA=4mpf.y`1i"fVg47f6}9b2W{Td4q#aeβAݔM3*Io:k؂ @A\\q2W#W=GdƻÆhXdvSCoj,( ^۪nט_hе9(0F%ڿ,9]83<GΗ`S\v\vge۴UapaoZ7`fad45ݤXt).I0"ZX_d& 0POO"S׈4U΀4š:w΂Yg1hkzep,;㈘+~x4C'9b|V䚏?A/H>]n"%e밗MAAJÒ,t?˗i2 Q'<ɒMYGFsFmy>[U8g O^y4κOGSGsMlŋ"p-(87$e.@r0d>\ZAϺ]-f$-2aS?8;v[̬ՅqDt2Jt=^c*uDgün渿+rl|}[s!XɹzJ +6mSF2;76 4G݀$6d]GCL B!wupB{;W:6k*]u^Qۡ6hv4]N`'X{L#t+^ IsmCɻeӇ|~Jl`+fky?0`Uw_i ʂxj}ͲshjHA58g'< ϐ+N8Tx]P jhsOHkQf'k@ mK a"x@d0'?T83h~a#1둾,֍6> /ExtGState << /GS1 10 0 R >> >> endobj 28 0 obj << /Length 1630 /Filter /FlateDecode >> stream HW]w8yLײ}I?g탰E-JH2ҦgOˣ;wެF1`ڌ,`Ռbx~d`GqV}JVїVZ@]%Z= J'Xw0“*n[om6U%-l.-4(a' ^}[5"bv< ]XlkXUVVC4Zwd>F.F{+6+x]iހji S PCIgLJvi@I?ɦ-Z= eJ "Dᶅ'Qڀ [BXনdG;#,|A5,o߽;a`Q}}EY 1 8 $f hψ ]Ţ (K5GE)v0^B:b >EAlkoPnfl"Rȍe7k3ƕr#!8- xyl>O<0W *2z `lv;`2C;']{"^I2Du~?~&tx{KԲA wÿ˦k<f ,]Zz%Y]c̃VZQND'm;E9Q.oa N &gYx<Ȟs~v<\fS5@,Rp8MdC8cqN6(%o=YI",c$M"ddpo]vpm]+t{@K}1c}l1pؕ f'Jĕ$gj$V5/ zgw)|@jJtkUpS[֋)Kazr=/]yhPIVS4htlو0jBrPQ9z/ XXxӌm-0 wXYv~V bEŕsáC!gL7T)la:k4-lXY{NC77$^^{h6~rr -gwÛ<Е.g^>錏vrq/ڄBM( BYF'<7XJ'x%7 D6\wn}/[!.:7rrOzحnq#}Q^\`.I,7HTҗ6`;% 5M>'42*jb8_Kg^w~탖irwFR[*:/^X ^’SF'N mOLtoa.wDN5Go˰܊RNX[{aнT`Jg4:>j41l8μAw ,~R^~KoW`J endstream endobj 29 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 30 0 obj << /Type /Halftone /HalftoneType 1 /HalftoneName (Default) /Frequency 60 /Angle 45 /SpotFunction /Round >> endobj 10 0 obj << /Type /ExtGState /SA false /OP false /HT /Default >> endobj 31 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-167 -216 1009 913] /FontName /HAMKMH+TimesNewRomanPSMT /ItalicAngle 0 /StemV 0 /XHeight 447 /CharSet (/three/K/i/G/t/S/eacute/q/bracketleft/four/j/u/I/quotedblleft/U/d/bracketright/five/k/v/comma/greater/equal/less/underscore/six/m/L/hyphen/w/W/V/l/seven/n/M/y/period/x/at/H/b/o/N/z/B/eight/Y/slash/c/C/\ p/O/nine/bullet/T/zero/e/D/P/colon/parenleft/one/A/space/E/r/a/f/quoteright/two/parenright/h/s/R/g/F/quotedblright) /FontFile3 32 0 R >> endobj 32 0 obj << /Filter /FlateDecode /Length 10382 /Subtype /Type1C >> stream HdyTSgƿe7ˢ"K]QED@ !-*a\j=(YTd";B"(p:֥~_;ysp8@@WqJF⋤ nQD mf~BHX P7f8X@0f^5 [؁7:`,̶h8gpZ`!؛7 c u@@)@,K@)r8^n" wScR|ނ<s37 TsPZ?W`\GnC֟l^,Q:~0aβv]}ߎE\diүuqrJ>p[=S+#ʄLrb!I,;!}Gʴ:@܉jh)h] -5М@Gڇ;Oz8EHFPI! j5cd_ ]щn&'0Y#/DJōO-'i9"l!K92g,ING$cB{M>0 &PAК1 nokn-#d>z(B`@ɫC #zj?JIL/fEiTJYVM>ZSJWVVU 'KG>x-_GIILRdW@hzhai3U#IXN):>)c59&St:W ? rH8- EB[`(#~]ر{ 8@HyaLH*wlešqG"^eҁO >i?]jY+YܰhquPq[Q\:Kf vfpϯ} w 3l64xUO_}@ y8zVH" 29*J}8[~_r1 Z'GGO}Ǚ1K;J nBsN~T ]7ѭGO gu6* a1 # mBE(Hxdc ;lgzD]b/"(IQ"Q'&I%iȃDF W+>eI^w::VDFR~i$#tfV1:UPP+P!he*V@a>%?ݪdw^0BvY;hJ=Qn3;Bz=Z h˝?QCx37[*bEh* ar@\|4|2d}\ͮ'!Bʙ8O/'ĺMvә ?v{ӑSR6NY8oOI!0ê(,R3:3[{Џ+{]s;MwSPW/.ڤn1Bl/N"|d=2r.1CD#ȜBh90#2^P9տl4Iy0Lxu-]\S\نM:vܽrqj5/#:93̣9qq\TVDK {y-RPb/75dmJ`mum08 Z (!MÑ0Ġ"DyM7o ICW o)}Iz#?>uCGthԃ{AC̭@sC#leZp ;!n0F!p_%AD`29(hNik{.g/i./<۝P͟cseR&X<83@6&U” MN{b9~}~[LQ%8Z%&eڣHKǑ.TxWq-a9"8D3 kZ@xzVo+l&D[[S(Pd,WM(2K*R޵kh1+eGruލXaB8AE$Zí -R܂ kmܑז gs3rCCѻv$z qh_ ?zNv=};Q?Iy{n߅HpKys4pJ|.טr$Z~o>cbQ$aG%hsaLL3b2 TeC;\,^P/٣8F+fD@HpָR} mY9}u0jT*C9,^fMi@U\)PT,ˤ| M 0Q1OV,#$JA^BAO`TrJ*(;XuC8쁮"y3$>y4W tt2;)30Q2DAy hc{HN˚%zamDNЁɡ5d䶞.P un_Fms+ J$Q4KB1A2d*P9}7/Ez^QUQ^w$ CD ]S Z ~l,7p@( *yzOy5qcU@YJ0s={;AKNE#7=Z-&0WXA<}TVsW33KSd{͙>Y&?cQ^L$ǣ|p-;*=2+Baecew򎱐7 u:Y?pmE/6=1F&[mETiԕu'@EiU+qIg3-jg?<6s|`gv+xsQ]tR$37~e{ ;:贊n y k-U* zjkc\CƽZߺUsNnP54k 4APSjE<,<4-Dwӧr9np Gg?S̬E`_6`H8Xv\^,҂9)IU|2[̭jZ ?h 1, ƫp/'!.> E+{9X98Q/ĝo,z\5fv3i zm=E ~J ! &,IHB B /y%šU2g]s&M_;~?/Vi=ѹVIk5jS'%>obe%d`qjy{1A9]ilT *J = ٗ,4w)@2ڦ#zq[#Ƿ<8^m ժJ JE?@cնZJOsz%.qVq'5TuP#Tu;1WpbE8G_sT|dqq (u /t 33_wyAp]asqy~®D!$ H"ߛf cpI;&8 pȅkoíK2S"#p3aa>rU[2f-Z$ og~nUL?6!@K,5G3h& xy@3DßWIKƀpY T tE PTAx_#=+2אJLW !5]d{c%I !(=YS!ul^sc~8Yvfi:+ټ`ywXt;qL߮Ŵl+ _+ qU$zn=E-[m3VIYre&%ğf \+δ- ߐ52\}rN׊k>ʋlxnmI*JTAnXͦblmff꓈x,ޘLҾNsXڗoSgcl:;')ĖJK4m9(=6[5K#M-Mc4-oV*gMMfHۈ[' 9j/qw`e&ےm\iwo B֍ u3˕yCֳ>y(n%Clz[Wo ̯E~ԭwjy A@.+SX[p_+47•+$?:)!"K]DD̐H%3->~_K<p)@:ғlOl/L( kݤe{![a+x8s/UhɡNgd'ͧ:HSex~徼H8`_{lI+oioW6gsLdƞz^TLc4̃GC 5ufyy]GOCRjj6 ܪHغ rO1'7Iuj%T}3d &F9WթD֚,PXօ8|S@@ Хu-Rmw*>m)]a*7Ć+-a;j/(Vc2]ZͻhuԔN.]\Q&"ao#1#JY3 uڮ@@ jRTVtd0xǖ1kOADhD9 FNsKgUbm=0}ԯ3pG(o&!{>AG?dx_ԇH\Pwh G-n7z;OMaP'>)&ĵg%uTݹ ֨9z"3Y6T`IbMěE1Ă=xHYA+5u R)w'/q2魲@E2gE3Q^ Jܞ=5PA4Goq"S%7GF[/eKiIX񘛞f9JXQB,}]._;w$`9=NН kEXsOŴ eXMW TX1GE|5r.)ZmFMRQ8\^:>''HO2LU!ۊ1èa5[Y2c3wG,5=q"nmi꩎y~SZS/b|Y e[4F|`,?tWWS~zW[ukw6W:YU"J I$_H1$7IF*EV(Skuu[O \8g7ζ{yywJؼ]KsV֭31Ka浣עkn=rfQlЃ nA.g0ұXDa+Ct'iL.ck抋ɁiaR^2$"Kw2yy 0kztt7c}2ļKp6q;GYCJL/ }{*:<8gHYӁuhZeP3LC퐤 Q&\бee&K\3+afY7C׍O }2YWDAODL<Yq."0b)88PaS) Cz HA3Lwzpd_X>9g1]W_ao xu 6Y$ j|>s5.uXBHnڌlHReޜہ$YǕp eek*PTWK%\zPSuxPөN B$aaDz'9H/:#%cǚcGт\yի̯8v;*NU L} (ZA:w 8q S!~>{QU9TV; pvpشdח!YF- K NOe~}[Ry6ҒVʳڧ^C mns F4;3E &XL-3M-'ibRxZTM5ev> )v+#gE\48̣ɍjS&#m$QmOXҙYUtY7P!I2ܫ⇰ȝB&P4F`gL{Dž*Co3}*>{2fW+LUaW["a*.OZEE-F{#w8FU%B .yjfRl(/ :4Ъ/ bDn4rɚOr4c210j (]qDpD }1GFw n<eTIhfj hDTuF+d;f!-pct $I>? a_ebn1;is#ww/=w@ga{zfIE6lR'a圫d~ɼ3/gdd桯3 ÷ݗ'p[N7\'aDjnbl8"j8+; oբVh$Dl"򂈲+.p.k=aꐄԭf':}aGj^"wmV YZ1wNH1cZ:p>g_P7SmZH򡚪6ҵ˅Qv- $\Ɨ i`lǀ!@p,feQ65M4YIt :|`z?{=x=TƄE W+xYO zf6-*oE#b!Dkv–hZSDe\ #Bh#GɣGwQ ΃om?n|M.[VJV){DVXӓz?T!X:[%v-hS^ƸCg͵oi6Oq%#CnO%."mȤzh:Ȁ}mPH+VqXk W̬7XQQUNwT !8) V>d?ZL x85&Idʒ߾Is1Z> {Z[`9I u9m0n'j7O+.5 ᅢ]5eD}ߚ5oJlרrB-mǗOnRۺbU? 8;猑ڇ[;۩[J{/ߜʹLj')kv˰$ann:d֧9z)MQ)mhvLA{.=jئŅpz\mք4Q{J96s%HMyuGrw`:CuF.]IP%IKIit:H,lc䘍P-U^C~5pFv,W<9(d3vi7 +HAsh/k` 2Dq_s|˝R41: VEH>>$}>׊Cvˌ"+1Y♲t d#>1]yOį;/,&{cqqsSNWyʃnd7f}u`^ $]eS;d> rdËD$-ӕ"8vl)CTn[x-TXN̓ds~"`MC"&]啷dZ7s{ܻ] ~֨ә4v"cdP#@t~]0p7.n F* pPt=R.^Or8!1-4&LG6|?1˨#PG,0r!y_`=W_ By{,1IXrON՞6ZS5-л 2$zx®P5AEJEYs}'N/-?(Wk?cC񎻓FX!u8a͌ɝr-!@[y%K!{!`BqONWFIOڮX5VByu_˻;k=^?X ̍pċz#8ƯsoG픐u_+wX=ssPksv46Ob'KDciƿHJdƾPn4RI&V>Lp\=XSAH=xa*O8դe߷9n6Lh6ǰI:6,D27ݘB7dgZ^@˪A O`^Ş|z*H3&,}l7Ne~i؜"뿞Eg7鳭J]`q=떩bj$fZA*h ,†GB ype#akP \<-D['͹u}XvbTk NI*Tfy[ 5/Hb|{K): Egb>5k6Vcz.UHMU!Ƥ~etzC#cp7}>Kz lRPRȣOo5C #vj endstream endobj 33 0 obj << /Type /FontDescriptor /Ascent 662 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-184 -226 1009 913] /FontName /HAMKNJ+TimesNewRomanPS-BoldMT /ItalicAngle 0 /StemV 0 /XHeight 457 /CharSet (/three/parenright/i/t/S/asterisk/G/equal/four/I/u/plus/d/greater/five/k/v/comma/underscore/six/m/L/w/hyphen/l/seven/n/y/x/period/X/M/H/b/o/z/B/bullet/N/slash/c/p/O/C/T/e/D/P/colon/q/one/A/space/r/f/a/E\ /Q/two/parenleft/h/s/R/g/F/less) /FontFile3 34 0 R >> endobj 34 0 obj << /Filter /FlateDecode /Length 8393 /Subtype /Type1C >> stream HU{TSG@ͥb7ޫPKW[c]Z=" >1$!@ $!Pky)5@DL_ҺU[j]nms$=ggؙ~}3wFF>zךTD-Pߍ ݚ!Gc)Bg_Ft+|ه վ S)Y⾆mB6{F}H""e'n" \C(YH(lDي#}5lsDN"?{{Fz=m?xa^BIN=&6b8RoK 3W {xIR~S//BxN- \r #S|o_a&ae^%!y!c!."n!Ω)LJsq|59A9pC$߀q7a#C/z<>̍:B}]ѓtBHAxO{oY/^̎۹xȇ nIF@ H%<BD~ҡu]w$LpnI|'Co p7籿u4YnBJU2Zu&j˦5mg3'+lLc 6h0#Wi24yx^vJI*kFc4P]ufc25 ԌW7tVO4tS( :wO7f2wuQi1ֶuMΔaEF}^m877h68C[LLtTlmVm:%,U 3 *l[qc_9 ]d6Ѧ쬺 J*Tk8SAje&!mm\ܨ*#|G6 cl =B7)iCuTkKYQ#XT_`}8tr_?_ruT ͌L\J0\bk2W%^>x~Cد&kxnK9=v1I xV[ҳ4n1h Rؒҧ%W's`fLNfKF;[=.Xpy|(=FFo ~DF^O[ZZߋ#EEl1g(r)\xwl!0 ͺ s\(q\iu\f(z|f V%o/1;ZMjJDH6ޭj-M1,. ,:6SiP8{2餛S40L_t|hhIȊ'4{ܚ+ bb?:c93$ q7p9\Kmn\zzxvc:G%g;vJ%&fety{c7bGXxp[0;~YE u1pMBm*)-Ue*(]ȻUi\7]w@]wiM{u[܈a7}FrO ݘ+ ^c!Dž2M?F\huP…'\s79 %fsܹGtȹ˸Wjp<sa'8/ּ4|暆C!& l \ 96 ,(/,$%b:O\@e&Ͼҋ +dVESsgǠ̩#-Kd6VUb7YHKMo = PV݇oĬ{T}$-E!u&h.-EEA" $!`C>@A^ZbEAZbUtjntݞ=dzc揙sw~mcx={k/^/^#tx6 hN r IRg:,0慮gXPԤ*Ӓ3@Frx7!2x`0.n5v$XxgsY56m)ڋ&JBZ+¢`_7#(QH&FEK;ACmOTLs) T|' 36rJ^i8;æmMJ 汗oDCJ1y'(y.]G0W 8ׄE 1Üm 8qn;6z(`.nkE@vܑXX׻ZrK:&`yG 27xt_G<:f(5߾ tL? knMeqHyp g;!~Kd] sIN[SV:cK ` #7"[ELvJ~΁v<}U鹀.gпQh cOWڒh.!iTzFS S'08wT`63X3km`JO.B~ԣѶ?tC=Mh*y0I6Ls0I ?$zzTktGqYۈ0a>Ys,(#eZPRrOouSheLZS̬9?։N̍@=Ku~H'pcmb" ɱ9TbaZIf%Ȭu 7x_=ؑOuᱽ^щ+a>{%{XubB%OU2>QzwH<$hf+]c:]ˡy, Kl@KM) cȚ4|ʒtFrֱ%zWuF]RQ架%^JJ B#Ĕn;6e73n <\O/**j+Xvk_j8QlzamL6;l㱪#u}%&3V\5&u/0]qtCQ\&ZVy ^׹}NG|J 0{2>$~J>amsj 4n}NB1eySl%q.K {#ѡMq+J+K5@SM6'pvA VWLիna!dHW3dہnP} B{7XCnWQDȍ Q*$`AM K|g$AiS΍cB5HsesM'dȰtAfKHn]=Z8E+3bb,+90dBs/Hh1Ќy#A`N3\zqM9K@wǪOuCNcCȐNP̊1W}XjdGp7TwWHY8.T?+͔ii"52RrZ DZ귗KAkPSgGk8mF|=lvj"II0I=SD.s-7 x,E/vNwg۞F;;ayU.5>VɭD άWoa+d'Xd:}>|Y"PETzA{/G7ʿNzI.wqކ>p|<@d1޻]y|faSI>XoFz[REx[K㓣*"i@`X5&E,q+ˇLBxb1~ޝuE˧;'wx%~OB~^#X]9Fmz˘YyÈuP_])Eb z>}4[ƿ W>鿀&3_ IN~ȱÂ[{1lCFcE}+Ro_S R&w"̽!8Y1w;'MP.ŷ,/e0LJa1˸*zcD*~5ɥ;>BbC)ƎfEgh,wB%.斮%W2?MҦZ!3C&oACnhD/Fhc{v-r\S}Dy= [BɚeL/{q;2|#ۡWZqO)1ߞؓY_FZMvŎ-N'j&SצV@uE57(Xa2_3FMx)b?׾e~.³K֥Ï63'##M2 * 9I0y`g'Bel,ʤ=cm(C1`*Z~mD 6cbb2u4|%Լ FEG|Ĕ/3ȝ=簹}KA*X*)w ~1ƕpT3kPNKZJ%|ME#P ìfܦs8t&G#rjSׯ,"#*?VS`귲\67 Y/>8[b'Q̒V>m[j\MCR>qB}r ;*XMܵU^ҝ{~lIvvvP]-0gξEB.aPpb PBoW3)(8sMa\">O E"+p k =+jm:ْ|s|8i~+R5&iҩ0+;3^?1Ht'-> E څuj5cHO{1:'!I'HI=sh k?&O 1j1 GpUEO؊7 aEG,p}}vq} Ŗ,ԈRT*5"o+W nzN:Hō TE3ve? Qb?snl4{t e\.qPWo%LMɸa,\;=IW1+fKƚef΂}Gd}hPKMCuIPkzMD7Ňg1UUQWh -̈́ Y8~lH~YGS. #Պ@-=#2EE,Z Ʃ8rr Jk/C9<$\"XԺ6ѐ$Q!hK;8~5jA,5CP%*F!XTMnуZ2WCAw=Vrq˺y?z_jhbw5`Y3O^R?Q*4<t3j1B)WCUwY,\E>/iG0Y Mx;S1Hۯt^'ۗwfɎ>{y*V%j 1ߨ/DLПPHZzB I PN>2C>jj9cvq?OЭhB6*Tdz89IZWAi{t6m!Ɇv_Jᩴ dڠնZ]a]c,sJdOr3cmKfM&/G$M2Vhu]Lo6:3ͰKR[iިUNH(b@lvNd" C^w?Ryym: 8R1\)=PR1jk|5{ON6ki8U+~WgOF^_baVoȻLazP}2j=J|8G!׼+;}BnNOZΐ$C.cmOn}f7 >0Fٱ_ X  ``7!8I5cG- endstream endobj 35 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 70 /FontBBox [-189 -216 986 913] /FontName /HAMKOM+TimesNewRomanPS-ItalicMT /ItalicAngle -15 /StemV 0 /XHeight 442 /CharSet (/i/t/S/u/I/d/comma/m/w/W/l/n/M/x/period/y/b/o/z/c/p/O/T/e/q/P/A/space/r/f/a/h/s/g) /FontFile3 36 0 R >> endobj 36 0 obj << /Filter /FlateDecode /Length 6001 /Subtype /Type1C >> stream HtTkX3 KL:hK˶vvEŔb ",B{$CI `E@yvmeWZkn_„g8=={?X,=;CC7DIҰ$^8!&,!Mg=W8V:xCaĉ{ .qj-p/!6BvB|( g XB(MP&TA!ރ,h PZ4BP7kk%7_ =yxz,k){{x?\"\e.^v ʏVj`hGCs:w5{.G;#ynÈqZϞ휺zu rv^e \ZgT gIJQQS:RTP)12SAӣeT*xP$D'Dդ&}#ERɂYgA)z .^vϹJʞWOJ&%GS%slH5dzu[i0cFm}uQαq|ڿ䣒% J\ Q9x\a[; ?l]AIjCՊ+p B [{MذkܪBԖ1J?`~Df u56ml3zCۏ3%&D Y^@6))jeeAޯ"hMlAvP$ 23FhWVq<8N)R.1図g9G-[("|>NI rps76cM=ٟYwҲV/s 5Zq$P3S KDE2,T f9[7D5mh1՛u{q8Ks.do  Rzйq-t:`U 7\e6__~D$>Bv|en m*_@`0;D vbT^C/8m`8XO _x8pbdQM?zt4i.MʃLjh_X xɮ^uW#/&* 'Dqጢp~.<6LGfmxLB>JץAK:{{'ȩkCݓhd#Sv`4}?Xrː>TWt*6lz"i6aYR%ȿl$$HP rpdE1Y~2:iN2(iQ6]D{A)[7au(H>>OwDTR͡8,PED37>܈ #F|uTV"vs{/[=Ha[馑s==( 3Bw: !t"GI5B<)!V8J6lԂ` E^P%۲cJ!уWuF/p2m\삭?56q;,VCqE4=k,YJ LGvXq3X{\Q[uAg1 jrd sW64+fEMzsw?g^|v_S=֫)XI)'hd ??AyWk$A[7ӋPi*lw;8'ćw /?y2 ? $> "Ysxk2-j|&JAU2 )9UUFT`U'OWw@hJV ̚C^^G#qiwřgZIY aF [3Shei+2^NrZ̧ xTi$UEyX2FG7?&Ɵwn7?z@SAb`xs..Ɛ1Y|mn;6ݼ<_m)Ƙ0ltM/Ƈ#4X$Xx O\AM]y%xgwqv5˜Kky\wRڕ4XE !$M@;#'y@! H0hP@"c-25:u[nXνwoJڑlΒgdڃ, X=vߘƆoZhVR>U{RkU IF)SbuSr9jZZ4Nn':f-A_QmfU#Hblݔŗ>X5 3Fgx񹻎mboCHEmFtFG ok(,QD^@@TxV+ỷs&qo\C+[ʋt}W̿@Rp28:U%vPh—l'=c@z54h5F{JÀ} -4h2/۾/{+[7ПΡ>}2txg.dD&,L,\^`D㱉He'a{ie%0n:18ǃGq(iG%RsY<"oj v"#;_wwm@d#U9Y0?@nrE/Zq;XTB̋֠np\/> 6s@hjU@STKJR/SVjC9 ]oV>I' elN9iQ.Q?.B@'qI|OX*|RUQ/.?Q"DerF QxQ :Z:X5f 6+$M"_U+Hx&C y6xwev~Ň~ @]CG+#[o( ,>8lFXߔkLJć0醢GŇ?d\aeq.(l- nVa7*=2wsWsXp92l?,طMf8& 4`Қ,&vnCt[O@WmMD-+ԦUc?ʲ)#Jk., Mf  2k^&ײd #P:*|$cɓ49Z/z|V=9^4,67zBnr.fCrhMt. mXcs;6%6/8k-Y Y\ g%8댠I](ja#u86zpL8c/'5HI]EF$Rn̤QH,XLTReBhWy(48ޖe_Du5AZ^ovB7k⭖:r7\ GvBϯib:*U@-m;[ĵ􂃬<m)qA%jrE& L)3u;4Jse W AV`2*18Un$FSr,fa&q察3 Fth5цBh-0u2)МT!#xKC('~rg.돯?t9l. 7c֩e" PBrW49ևPЪa.^(s}.;%Ԋ|u G^""YW\Nzpua":%&"fa +qC4"b)y,`PjjD.|Znjb5sۖ Ƴm 3g7<ω̍F_v~/;6cE˓7^o)%J{$)`?Z~-\AMyo;s^2g_wZ띎:=΢2 ,BH6!BYBp$B%5Qj9P½FNmXB{g~(UfX-:s/p8DV-ݖ5vm46g|eCJSb8Jh[-v j:vcZ]nqٮhC>¤4G1=skjCÒ %= JOd3K 籢:Asw:{P3>J<cַa<;+#7ҿd^(.yWM_"o#tT4`)\XWj04hz;mطM aPn& v_::}N(?nS!.X$D$k d,Ң̂3f3h1YZѪ8=->SɂE4*AQ@P?'WEk*{}1sgX30a"wՠIZ'mjE(>h v3fmqe&R]^wn߅t(uTqaAh|dc89ʍ2ӿLb~`4}8{yW;3-/P2-PM fj(q~2#y׻9'?[ endstream endobj 6 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 408 500 500 833 778 180 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 778 722 722 667 611 722 722 722 444 444 444 444 444 444 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 500 500 500 500 400 500 500 500 350 453 500 760 760 980 333 333 549 889 722 713 549 549 549 500 576 494 713 823 549 274 276 310 768 667 500 444 333 564 549 500 549 612 500 500 1000 250 722 722 722 889 722 500 1000 444 444 333 333 549 494 500 722 167 500 333 333 556 556 500 250 333 444 1000 722 611 722 611 611 333 333 333 333 722 722 778 722 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 37 0 R /BaseFont /HAMKMH+TimesNewRomanPSMT /FontDescriptor 31 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 555 500 500 1000 833 278 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 394 220 394 520 778 722 722 722 667 722 778 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 556 500 500 500 500 500 556 556 556 556 500 400 500 500 500 350 540 556 747 747 1000 333 333 549 1000 778 713 549 549 549 500 576 494 713 823 549 274 300 330 768 722 500 500 333 570 549 500 549 612 500 500 1000 250 722 722 778 1000 722 500 1000 500 500 333 333 549 494 500 722 167 500 333 333 556 556 500 250 333 500 1000 722 667 722 667 667 389 389 389 389 778 778 778 778 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 37 0 R /BaseFont /HAMKNJ+TimesNewRomanPS-BoldMT /FontDescriptor 33 0 R >> endobj 8 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 420 500 500 833 778 214 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 422 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275 400 541 778 611 611 667 611 667 722 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 500 500 500 500 400 500 500 500 350 523 500 760 760 980 333 333 549 889 722 713 549 549 549 500 576 494 713 823 549 274 276 310 768 667 500 500 389 675 549 500 549 612 500 500 889 250 611 611 722 944 667 500 889 556 556 333 333 549 494 444 556 167 500 333 333 500 500 500 250 333 556 1000 611 611 611 611 611 333 333 333 333 722 722 778 722 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 37 0 R /BaseFont /HAMKOM+TimesNewRomanPS-ItalicMT /FontDescriptor 35 0 R >> endobj 9 0 obj << /Type /Font /Subtype /Type1 /Name /F5 /Encoding 38 0 R /BaseFont /Times-Roman >> endobj 16 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /Encoding 38 0 R /BaseFont /Helvetica-Bold >> endobj 17 0 obj << /Type /Font /Subtype /Type1 /Name /F9 /Encoding 38 0 R /BaseFont /Helvetica >> endobj 37 0 obj << /Type /Encoding /Differences [ 0/.null 9/nonmarkingreturn 13/nonmarkingreturn 128/Adieresis ] >> endobj 38 0 obj << /Type /Encoding /Differences [ 0/.notdef 8/.notdef/space 13/.notdef 29/.notdef 128/Adieresis 202/space ] >> endobj 3 0 obj << /Type /Page /Parent 11 0 R /Resources 5 0 R /Contents 4 0 R /Rotate -180 >> endobj 13 0 obj << /Type /Page /Parent 11 0 R /Resources 15 0 R /Contents 14 0 R /Rotate -180 >> endobj 18 0 obj << /Type /Page /Parent 11 0 R /Resources 20 0 R /Contents 19 0 R /Rotate -180 >> endobj 21 0 obj << /Type /Page /Parent 11 0 R /Resources 23 0 R /Contents 22 0 R /Rotate -180 >> endobj 24 0 obj << /Type /Page /Parent 11 0 R /Resources 26 0 R /Contents 25 0 R /Rotate -180 >> endobj 27 0 obj << /Type /Page /Parent 11 0 R /Resources 29 0 R /Contents 28 0 R /Rotate -180 >> endobj 11 0 obj << /Type /Pages /Kids [3 0 R 13 0 R 18 0 R 21 0 R 24 0 R 27 0 R] /Count 6 /MediaBox [0 0 595 842] >> endobj 39 0 obj << /Type /Catalog /Pages 11 0 R >> endobj 40 0 obj << /CreationDate (D:20011113175920) /Producer (Acrobat Distiller 3.02 for Power Macintosh) /Author (stephG4) /Creator (AppleWorks: LaserWriter 8 FU2-8.7.1) /Title (Pa_ASIO1) >> endobj xref 0 41 0000000000 65535 f 0000000016 00000 n 0000006474 00000 n 0000048862 00000 n 0000004795 00000 n 0000006279 00000 n 0000044683 00000 n 0000045890 00000 n 0000047107 00000 n 0000048319 00000 n 0000018231 00000 n 0000049441 00000 n 0000006521 00000 n 0000048956 00000 n 0000006720 00000 n 0000008771 00000 n 0000048418 00000 n 0000048521 00000 n 0000049053 00000 n 0000008909 00000 n 0000011160 00000 n 0000049150 00000 n 0000011298 00000 n 0000013743 00000 n 0000049247 00000 n 0000013859 00000 n 0000016172 00000 n 0000049344 00000 n 0000016288 00000 n 0000017992 00000 n 0000018108 00000 n 0000018303 00000 n 0000018848 00000 n 0000029322 00000 n 0000029789 00000 n 0000038273 00000 n 0000038591 00000 n 0000048619 00000 n 0000048735 00000 n 0000049558 00000 n 0000049609 00000 n trailer << /Size 41 /Root 39 0 R /Info 40 0 R /ID [<22d1064700ff024bdc4ec712f949bc29><22d1064700ff024bdc4ec712f949bc29>] >> startxref 49802 %%EOF nyquist-3.05/portaudio/src/hostapi/asio/ASIO-README.txt0000644000175000000620000001033611466723256021630 0ustar stevestaffASIO-README.txt This document contains information to help you compile PortAudio with ASIO support. If you find any omissions or errors in this document please notify Ross Bencina . Building PortAudio with ASIO support ------------------------------------ To build PortAudio with ASIO support you need to compile and link with pa_asio.c, and files from the ASIO SDK (see below), along with the common files from pa_common/ and platform specific files from pa_win/ (for Win32) or pa_mac/ (for Macintosh). If you are compiling with a non-Microsoft compiler on windows, also compile and link with iasiothiscallresolver.cpp (see below for an explanation). For some platforms (MingW, possibly Mac), you may simply be able to type: ./configure --with-host_os=mingw --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2] make ./configure --with-host_os=darwin --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2] make and life will be good. Obtaining the ASIO SDK ---------------------- In order to build PortAudio with ASIO support, you need to download the ASIO SDK (version 2.0) from Steinberg. Steinberg makes the ASIO SDK available to anyone free of charge, however they do not permit its source code to be distributed. NOTE: In some cases the ASIO SDK may require patching, see below for further details. http://www.steinberg.net/en/ps/support/3rdparty/asio_sdk/ If the above link is broken search Google for: "download steinberg ASIO SDK" Building the ASIO SDK on Macintosh ---------------------------------- To build the ASIO SDK on Macintosh you need to compile and link with the following files from the ASIO SDK: host/asiodrivers.cpp host/mac/asioshlib.cpp host/mac/codefragements.cpp Building the ASIO SDK on Windows -------------------------------- To build the ASIO SDK on Windows you need to compile and link with the following files from the ASIO SDK: asio_sdk\common\asio.cpp asio_sdk\host\asiodrivers.cpp asio_sdk\host\pc\asiolist.cpp You may also need to adjust your include paths to support inclusion of header files from the above directories. The ASIO SDK depends on the following COM API functions: CoInitialize, CoUninitialize, CoCreateInstance, CLSIDFromString For compilation with MinGW you will need to link with -lole32, for Borland link with Import32.lib. Non-Microsoft (MSVC) Compilers on Windows including Borland and GCC ------------------------------------------------------------------- Steinberg did not specify a calling convention in the IASIO interface definition. This causes the Microsoft compiler to use the proprietary thiscall convention which is not compatible with other compilers, such as compilers from Borland (BCC and C++Builder) and GNU (gcc). Steinberg's ASIO SDK will compile but crash on initialization if compiled with a non-Microsoft compiler on Windows. PortAudio solves this problem using the iasiothiscallresolver library which is included in the distribution. When building ASIO support for non-Microsoft compilers, be sure to compile and link with iasiothiscallresolver.cpp. Note that iasiothiscallresolver includes conditional directives which cause it to have no effect if it is compiled with a Microsoft compiler, or on the Macintosh. If you use configure and make (see above), this should be handled automatically for you. For further information about the IASIO thiscall problem see this page: http://www.audiomulch.com/~rossb/code/calliasio Macintosh ASIO SDK Bug Patch ---------------------------- There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Below is a patch that you can apply. In codefragments.cpp replace getFrontProcessDirectory function with the following one (GetFrontProcess replaced by GetCurrentProcess). bool CodeFragments::getFrontProcessDirectory(void *specs) { FSSpec *fss = (FSSpec *)specs; ProcessInfoRec pif; ProcessSerialNumber psn; memset(&psn,0,(long)sizeof(ProcessSerialNumber)); // if(GetFrontProcess(&psn) == noErr) // wrong !!! if(GetCurrentProcess(&psn) == noErr) // correct !!! { pif.processName = 0; pif.processAppSpec = fss; pif.processInfoLength = sizeof(ProcessInfoRec); if(GetProcessInformation(&psn, &pif) == noErr) return true; } return false; } --- nyquist-3.05/portaudio/src/hostapi/jack/0002755000175000000620000000000011537433131017342 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/jack/pa_jack.c0000644000175000000620000017301711466723256021120 0ustar stevestaff/* * $Id: pa_jack.c,v 1.1 2010/11/04 21:04:36 rbd Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * JACK Implementation by Joshua Haberman * * Copyright (c) 2004 Stefan Westerfeld * Copyright (c) 2004 Arve Knudsen * Copyright (c) 2002 Joshua Haberman * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostapi_src */ #include #include #include #include #include #include #include #include /* EBUSY */ #include /* sig_atomic_t */ #include #include #include #include #include "pa_util.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_process.h" #include "pa_allocation.h" #include "pa_cpuload.h" #include "pa_ringbuffer.h" #include "pa_debugprint.h" static int aErr_; static PaError paErr_; /* For use with ENSURE_PA */ static pthread_t mainThread_; static char *jackErr_ = NULL; static const char* clientName_ = "PortAudio"; #define STRINGIZE_HELPER(expr) #expr #define STRINGIZE(expr) STRINGIZE_HELPER(expr) /* Check PaError */ #define ENSURE_PA(expr) \ do { \ if( (paErr_ = (expr)) < paNoError ) \ { \ if( (paErr_) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ { \ if (! jackErr_ ) jackErr_ = "unknown error";\ PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \ } \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = paErr_; \ goto error; \ } \ } while( 0 ) #define UNLESS(expr, code) \ do { \ if( (expr) == 0 ) \ { \ if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ { \ if (!jackErr_) jackErr_ = "unknown error";\ PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \ } \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = (code); \ goto error; \ } \ } while( 0 ) #define ASSERT_CALL(expr, success) \ aErr_ = (expr); \ assert( aErr_ == success ); /* * Functions that directly map to the PortAudio stream interface */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); /*static PaTime GetStreamInputLatency( PaStream *stream );*/ /*static PaTime GetStreamOutputLatency( PaStream *stream );*/ static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); /* * Data specific to this API */ struct PaJackStream; typedef struct { PaUtilHostApiRepresentation commonHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *deviceInfoMemory; jack_client_t *jack_client; int jack_buffer_size; PaHostApiIndex hostApiIndex; pthread_mutex_t mtx; pthread_cond_t cond; unsigned long inputBase, outputBase; /* For dealing with the process thread */ volatile int xrun; /* Received xrun notification from JACK? */ struct PaJackStream * volatile toAdd, * volatile toRemove; struct PaJackStream *processQueue; volatile sig_atomic_t jackIsDown; } PaJackHostApiRepresentation; /* PaJackStream - a stream data structure specifically for this implementation */ typedef struct PaJackStream { PaUtilStreamRepresentation streamRepresentation; PaUtilBufferProcessor bufferProcessor; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaJackHostApiRepresentation *hostApi; /* our input and output ports */ jack_port_t **local_input_ports; jack_port_t **local_output_ports; /* the input and output ports of the client we are connecting to */ jack_port_t **remote_input_ports; jack_port_t **remote_output_ports; int num_incoming_connections; int num_outgoing_connections; jack_client_t *jack_client; /* The stream is running if it's still producing samples. * The stream is active if samples it produced are still being heard. */ volatile sig_atomic_t is_running; volatile sig_atomic_t is_active; /* Used to signal processing thread that stream should start or stop, respectively */ volatile sig_atomic_t doStart, doStop, doAbort; jack_nframes_t t0; PaUtilAllocationGroup *stream_memory; /* These are useful in the process callback */ int callbackResult; int isSilenced; int xrun; /* These are useful for the blocking API */ int isBlockingStream; PaUtilRingBuffer inFIFO; PaUtilRingBuffer outFIFO; volatile sig_atomic_t data_available; sem_t data_semaphore; int bytesPerFrame; int samplesPerFrame; struct PaJackStream *next; } PaJackStream; #define TRUE 1 #define FALSE 0 /* * Functions specific to this API */ static int JackCallback( jack_nframes_t frames, void *userData ); /* * * Implementation * */ /* ---- blocking emulation layer ---- */ /* Allocate buffer. */ static PaError BlockingInitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame ) { long numBytes = numFrames * bytesPerFrame; char *buffer = (char *) malloc( numBytes ); if( buffer == NULL ) return paInsufficientMemory; memset( buffer, 0, numBytes ); return (PaError) PaUtil_InitializeRingBuffer( rbuf, numBytes, buffer ); } /* Free buffer. */ static PaError BlockingTermFIFO( PaUtilRingBuffer *rbuf ) { if( rbuf->buffer ) free( rbuf->buffer ); rbuf->buffer = NULL; return paNoError; } static int BlockingCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { struct PaJackStream *stream = (PaJackStream *)userData; long numBytes = stream->bytesPerFrame * framesPerBuffer; /* This may get called with NULL inputBuffer during initial setup. */ if( inputBuffer != NULL ) { PaUtil_WriteRingBuffer( &stream->inFIFO, inputBuffer, numBytes ); } if( outputBuffer != NULL ) { int numRead = PaUtil_ReadRingBuffer( &stream->outFIFO, outputBuffer, numBytes ); /* Zero out remainder of buffer if we run out of data. */ memset( (char *)outputBuffer + numRead, 0, numBytes - numRead ); } if( !stream->data_available ) { stream->data_available = 1; sem_post( &stream->data_semaphore ); } return paContinue; } static PaError BlockingBegin( PaJackStream *stream, int minimum_buffer_size ) { long doRead = 0; long doWrite = 0; PaError result = paNoError; long numFrames; doRead = stream->local_input_ports != NULL; doWrite = stream->local_output_ports != NULL; /* */ stream->samplesPerFrame = 2; stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame; /* */ numFrames = 32; while (numFrames < minimum_buffer_size) numFrames *= 2; if( doRead ) { ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) ); } if( doWrite ) { long numBytes; ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) ); /* Make Write FIFO appear full initially. */ numBytes = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO ); PaUtil_AdvanceRingBufferWriteIndex( &stream->outFIFO, numBytes ); } stream->data_available = 0; sem_init( &stream->data_semaphore, 0, 0 ); error: return result; } static void BlockingEnd( PaJackStream *stream ) { BlockingTermFIFO( &stream->inFIFO ); BlockingTermFIFO( &stream->outFIFO ); sem_destroy( &stream->data_semaphore ); } static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames ) { PaError result = paNoError; PaJackStream *stream = (PaJackStream *)s; long bytesRead; char *p = (char *) data; long numBytes = stream->bytesPerFrame * numFrames; while( numBytes > 0 ) { bytesRead = PaUtil_ReadRingBuffer( &stream->inFIFO, p, numBytes ); numBytes -= bytesRead; p += bytesRead; if( numBytes > 0 ) { /* see write for an explanation */ if( stream->data_available ) stream->data_available = 0; else sem_wait( &stream->data_semaphore ); } } return result; } static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames ) { PaError result = paNoError; PaJackStream *stream = (PaJackStream *)s; long bytesWritten; char *p = (char *) data; long numBytes = stream->bytesPerFrame * numFrames; while( numBytes > 0 ) { bytesWritten = PaUtil_WriteRingBuffer( &stream->outFIFO, p, numBytes ); numBytes -= bytesWritten; p += bytesWritten; if( numBytes > 0 ) { /* we use the following algorithm: * (1) write data * (2) if some data didn't fit into the ringbuffer, set data_available to 0 * to indicate to the audio that if space becomes available, we want to know * (3) retry to write data (because it might be that between (1) and (2) * new space in the buffer became available) * (4) if this failed, we are sure that the buffer is really empty and * we will definitely receive a notification when it becomes available * thus we can safely sleep * * if the algorithm bailed out in step (3) before, it leaks a count of 1 * on the semaphore; however, it doesn't matter, because if we block in (4), * we also do it in a loop */ if( stream->data_available ) stream->data_available = 0; else sem_wait( &stream->data_semaphore ); } } return result; } static signed long BlockingGetStreamReadAvailable( PaStream* s ) { PaJackStream *stream = (PaJackStream *)s; int bytesFull = PaUtil_GetRingBufferReadAvailable( &stream->inFIFO ); return bytesFull / stream->bytesPerFrame; } static signed long BlockingGetStreamWriteAvailable( PaStream* s ) { PaJackStream *stream = (PaJackStream *)s; int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO ); return bytesEmpty / stream->bytesPerFrame; } static PaError BlockingWaitEmpty( PaStream *s ) { PaJackStream *stream = (PaJackStream *)s; while( PaUtil_GetRingBufferReadAvailable( &stream->outFIFO ) > 0 ) { stream->data_available = 0; sem_wait( &stream->data_semaphore ); } return 0; } /* ---- jack driver ---- */ /* BuildDeviceList(): * * The process of determining a list of PortAudio "devices" from * JACK's client/port system is fairly involved, so it is separated * into its own routine. */ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) { /* Utility macros for the repetitive process of allocating memory */ /* JACK has no concept of a device. To JACK, there are clients * which have an arbitrary number of ports. To make this * intelligible to PortAudio clients, we will group each JACK client * into a device, and make each port of that client a channel */ PaError result = paNoError; PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep; const char **jack_ports = NULL; char **client_names = NULL; char *regex_pattern = NULL; int port_index, client_index, i; double globalSampleRate; regex_t port_regex; unsigned long numClients = 0, numPorts = 0; char *tmp_client_name = NULL; commonApi->info.defaultInputDevice = paNoDevice; commonApi->info.defaultOutputDevice = paNoDevice; commonApi->info.deviceCount = 0; /* Parse the list of ports, using a regex to grab the client names */ ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 ); /* since we are rebuilding the list of devices, free all memory * associated with the previous list */ PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory ); regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 ); tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() ); /* We can only retrieve the list of clients indirectly, by first * asking for a list of all ports, then parsing the port names * according to the client_name:port_name convention (which is * enforced by jackd) * A: If jack_get_ports returns NULL, there's nothing for us to do */ UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError ); /* Find number of ports */ while( jack_ports[numPorts] ) ++numPorts; /* At least there will be one port per client :) */ UNLESS( client_names = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, numPorts * sizeof (char *) ), paInsufficientMemory ); /* Build a list of clients from the list of ports */ for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ ) { int client_seen = FALSE; regmatch_t match_info; const char *port = jack_ports[port_index]; /* extract the client name from the port name, using a regex * that parses the clientname:portname syntax */ UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError ); assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size()); memcpy( tmp_client_name, port + match_info.rm_so, match_info.rm_eo - match_info.rm_so ); tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0'; /* do we know about this port's client yet? */ for( i = 0; i < numClients; i++ ) { if( strcmp( tmp_client_name, client_names[i] ) == 0 ) client_seen = TRUE; } if (client_seen) continue; /* A: Nothing to see here, move along */ UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, strlen(tmp_client_name) + 1), paInsufficientMemory ); /* The alsa_pcm client should go in spot 0. If this * is the alsa_pcm client AND we are NOT about to put * it in spot 0 put it in spot 0 and move whatever * was already in spot 0 to the end. */ if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && numClients > 0 ) { /* alsa_pcm goes in spot 0 */ strcpy( client_names[ numClients ], client_names[0] ); strcpy( client_names[0], tmp_client_name ); } else { /* put the new client at the end of the client list */ strcpy( client_names[ numClients ], tmp_client_name ); } ++numClients; } /* Now we have a list of clients, which will become the list of * PortAudio devices. */ /* there is one global sample rate all clients must conform to */ globalSampleRate = jack_get_sample_rate( jackApi->jack_client ); UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, sizeof(PaDeviceInfo*) * numClients ), paInsufficientMemory ); assert( commonApi->info.deviceCount == 0 ); /* Create a PaDeviceInfo structure for every client */ for( client_index = 0; client_index < numClients; client_index++ ) { PaDeviceInfo *curDevInfo; const char **clientPorts = NULL; UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, sizeof(PaDeviceInfo) ), paInsufficientMemory ); UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, strlen(client_names[client_index]) + 1 ), paInsufficientMemory ); strcpy( (char *)curDevInfo->name, client_names[client_index] ); curDevInfo->structVersion = 2; curDevInfo->hostApi = jackApi->hostApiIndex; /* JACK is very inflexible: there is one sample rate the whole * system must run at, and all clients must speak IEEE float. */ curDevInfo->defaultSampleRate = globalSampleRate; /* To determine how many input and output channels are available, * we re-query jackd with more specific parameters. */ sprintf( regex_pattern, "%s:.*", client_names[client_index] ); /* ... what are your output ports (that we could input from)? */ clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, NULL, JackPortIsOutput); curDevInfo->maxInputChannels = 0; curDevInfo->defaultLowInputLatency = 0.; curDevInfo->defaultHighInputLatency = 0.; if( clientPorts ) { jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] ); curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency = jack_port_get_latency( p ) / globalSampleRate; for( i = 0; clientPorts[i] != NULL; i++) { /* The number of ports returned is the number of output channels. * We don't care what they are, we just care how many */ curDevInfo->maxInputChannels++; } free(clientPorts); } /* ... what are your input ports (that we could output to)? */ clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, NULL, JackPortIsInput); curDevInfo->maxOutputChannels = 0; curDevInfo->defaultLowOutputLatency = 0.; curDevInfo->defaultHighOutputLatency = 0.; if( clientPorts ) { jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] ); curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency = jack_port_get_latency( p ) / globalSampleRate; for( i = 0; clientPorts[i] != NULL; i++) { /* The number of ports returned is the number of input channels. * We don't care what they are, we just care how many */ curDevInfo->maxOutputChannels++; } free(clientPorts); } /* Add this client to the list of devices */ commonApi->deviceInfos[client_index] = curDevInfo; ++commonApi->info.deviceCount; if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 ) commonApi->info.defaultInputDevice = client_index; if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 ) commonApi->info.defaultOutputDevice = client_index; } error: regfree( &port_regex ); free( jack_ports ); return result; } static void UpdateSampleRate( PaJackStream *stream, double sampleRate ) { /* XXX: Maybe not the cleanest way of going about this? */ stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate; } static void JackErrorCallback( const char *msg ) { if( pthread_self() == mainThread_ ) { assert( msg ); jackErr_ = realloc( jackErr_, strlen( msg ) + 1 ); strcpy( jackErr_, msg ); } } static void JackOnShutdown( void *arg ) { PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg; PaJackStream *stream = jackApi->processQueue; PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ )); for( ; stream; stream = stream->next ) { stream->is_active = 0; } /* Make sure that the main thread doesn't get stuck waiting on the condition */ ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 ); jackApi->jackIsDown = 1; ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 ); ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 ); } static int JackSrCb( jack_nframes_t nframes, void *arg ) { PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg; double sampleRate = (double)nframes; PaJackStream *stream = jackApi->processQueue; /* Update all streams in process queue */ PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate )); for( ; stream; stream = stream->next ) { if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate ) { PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ )); UpdateSampleRate( stream, sampleRate ); } } return 0; } static int JackXRunCb(void *arg) { PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg; assert( hostApi ); hostApi->xrun = TRUE; PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ )); return 0; } PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; PaJackHostApiRepresentation *jackHostApi; int activated = 0; jack_status_t jackStatus = 0; *hostApi = NULL; /* Initialize to NULL */ UNLESS( jackHostApi = (PaJackHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory ); UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); mainThread_ = pthread_self(); ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 ); ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 ); /* Try to become a client of the JACK server. If we cannot do * this, then this API cannot be used. * * Without the JackNoStartServer option, the jackd server is started * automatically which we do not want. */ jackHostApi->jack_client = jack_client_open( clientName_, JackNoStartServer, &jackStatus ); if( !jackHostApi->jack_client ) { /* the V19 development docs say that if an implementation * detects that it cannot be used, it should return a NULL * interface and paNoError */ PA_DEBUG(( "%s: Couldn't connect to JACK, status: %d\n", __FUNCTION__, jackStatus )); result = paNoError; goto error; } jackHostApi->hostApiIndex = hostApiIndex; *hostApi = &jackHostApi->commonHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paJACK; (*hostApi)->info.name = "JACK Audio Connection Kit"; /* Build a device list by querying the JACK server */ ENSURE_PA( BuildDeviceList( jackHostApi ) ); /* Register functions */ (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, BlockingReadStream, BlockingWriteStream, BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable ); jackHostApi->inputBase = jackHostApi->outputBase = 0; jackHostApi->xrun = 0; jackHostApi->toAdd = jackHostApi->toRemove = NULL; jackHostApi->processQueue = NULL; jackHostApi->jackIsDown = 0; jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi ); jack_set_error_function( JackErrorCallback ); jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client ); /* Don't check for error, may not be supported (deprecated in at least jackdmp) */ jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi ); UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError ); UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError ); UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError ); activated = 1; return result; error: if( activated ) ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); if( jackHostApi ) { if( jackHostApi->jack_client ) ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); if( jackHostApi->deviceInfoMemory ) { PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); } PaUtil_FreeMemory( jackHostApi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; /* note: this automatically disconnects all ports, since a deactivated * client is not allowed to have any ports connected */ ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 ); ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 ); ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); if( jackHostApi->deviceInfoMemory ) { PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); } PaUtil_FreeMemory( jackHostApi ); free( jackErr_ ); } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { int inputChannelCount = 0, outputChannelCount = 0; PaSampleFormat inputSampleFormat, outputSampleFormat; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } /* The following check is not necessary for JACK. - if a full duplex stream is requested, check that the combination of input and output parameters is supported Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format */ /* check that the device supports sampleRate */ #define ABS(x) ( (x) > 0 ? (x) : -(x) ) if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 ) return paInvalidSampleRate; #undef ABS return paFormatIsSupported; } /* Basic stream initialization */ static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels, int numOutputChannels ) { PaError result = paNoError; assert( stream ); memset( stream, 0, sizeof (PaJackStream) ); UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); stream->jack_client = hostApi->jack_client; stream->hostApi = hostApi; if( numInputChannels > 0 ) { UNLESS( stream->local_input_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), paInsufficientMemory ); memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels ); UNLESS( stream->remote_output_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), paInsufficientMemory ); memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels ); } if( numOutputChannels > 0 ) { UNLESS( stream->local_output_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), paInsufficientMemory ); memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); UNLESS( stream->remote_input_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), paInsufficientMemory ); memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); } stream->num_incoming_connections = numInputChannels; stream->num_outgoing_connections = numOutputChannels; error: return result; } /*! * Free resources associated with stream, and eventually stream itself. * * Frees allocated memory, and closes opened pcms. */ static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor ) { int i; assert( stream ); if( stream->isBlockingStream ) BlockingEnd( stream ); for( i = 0; i < stream->num_incoming_connections; ++i ) { if( stream->local_input_ports[i] ) ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 ); } for( i = 0; i < stream->num_outgoing_connections; ++i ) { if( stream->local_output_ports[i] ) ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 ); } if( terminateStreamRepresentation ) PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); if( terminateBufferProcessor ) PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); if( stream->stream_memory ) { PaUtil_FreeAllAllocations( stream->stream_memory ); PaUtil_DestroyAllocationGroup( stream->stream_memory ); } PaUtil_FreeMemory( stream ); } static PaError WaitCondition( PaJackHostApiRepresentation *hostApi ) { PaError result = paNoError; int err = 0; PaTime pt = PaUtil_GetTime(); struct timespec ts; ts.tv_sec = (time_t) floor( pt + 1 ); ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000); /* XXX: Best enclose in loop, in case of spurious wakeups? */ err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts ); /* Make sure we didn't time out */ UNLESS( err != ETIMEDOUT, paTimedOut ); UNLESS( !err, paInternalError ); error: return result; } static PaError AddStream( PaJackStream *stream ) { PaError result = paNoError; PaJackHostApiRepresentation *hostApi = stream->hostApi; /* Add to queue of streams that should be processed */ ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); if( !hostApi->jackIsDown ) { hostApi->toAdd = stream; /* Unlock mutex and await signal from processing thread */ result = WaitCondition( stream->hostApi ); } ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); ENSURE_PA( result ); UNLESS( !hostApi->jackIsDown, paDeviceUnavailable ); error: return result; } /* Remove stream from processing queue */ static PaError RemoveStream( PaJackStream *stream ) { PaError result = paNoError; PaJackHostApiRepresentation *hostApi = stream->hostApi; /* Add to queue over streams that should be processed */ ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); if( !hostApi->jackIsDown ) { hostApi->toRemove = stream; /* Unlock mutex and await signal from processing thread */ result = WaitCondition( stream->hostApi ); } ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); ENSURE_PA( result ); error: return result; } /* Add stream to JACK callback processing queue */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; PaJackStream *stream = NULL; char *port_string = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() ); unsigned long regexSz = jack_client_name_size() + 3; char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regexSz ); const char **jack_ports = NULL; /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */ int i; int inputChannelCount, outputChannelCount; const double jackSr = jack_get_sample_rate( jackHostApi->jack_client ); PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; int bpInitialized = 0, srInitialized = 0; /* Initialized buffer processor and stream representation? */ unsigned long ofs; /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 ) { streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback; /*return paInvalidFlag;*/ /* This implementation does not support buffer priming */ } if( framesPerBuffer != paFramesPerBufferUnspecified ) { /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */ /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/ /* TODO: Add descriptive error code? */ } /* Preliminary checks */ if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } /* ... check that the sample rate exactly matches the ONE acceptable rate * A: This rate isn't necessarily constant though? */ #define ABS(x) ( (x) > 0 ? (x) : -(x) ) if( ABS(sampleRate - jackSr) > 1 ) return paInvalidSampleRate; #undef ABS UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory ); ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) ); /* the blocking emulation, if necessary */ stream->isBlockingStream = !streamCallback; if( stream->isBlockingStream ) { float latency = 0.001; /* 1ms is the absolute minimum we support */ int minimum_buffer_frames = 0; if( inputParameters && inputParameters->suggestedLatency > latency ) latency = inputParameters->suggestedLatency; else if( outputParameters && outputParameters->suggestedLatency > latency ) latency = outputParameters->suggestedLatency; /* the latency the user asked for indicates the minimum buffer size in frames */ minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client )); /* we also need to be able to store at least three full jack buffers to avoid dropouts */ if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames ) minimum_buffer_frames = jackHostApi->jack_buffer_size * 3; /* setup blocking API data structures (FIXME: can fail) */ BlockingBegin( stream, minimum_buffer_frames ); /* install our own callback for the blocking API */ streamCallback = BlockingCallback; userData = stream; PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &jackHostApi->blockingStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &jackHostApi->callbackStreamInterface, streamCallback, userData ); } srInitialized = 1; PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr ); /* create the JACK ports. We cannot connect them until audio * processing begins */ /* Register a unique set of ports for this stream * TODO: Robust allocation of new port names */ ofs = jackHostApi->inputBase; for( i = 0; i < inputChannelCount; i++ ) { snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i ); UNLESS( stream->local_input_ports[i] = jack_port_register( jackHostApi->jack_client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory ); } jackHostApi->inputBase += inputChannelCount; ofs = jackHostApi->outputBase; for( i = 0; i < outputChannelCount; i++ ) { snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i ); UNLESS( stream->local_output_ports[i] = jack_port_register( jackHostApi->jack_client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory ); } jackHostApi->outputBase += outputChannelCount; /* look up the jack_port_t's for the remote ports. We could do * this at stream start time, but doing it here ensures the * name lookup only happens once. */ if( inputChannelCount > 0 ) { int err = 0; /* Get output ports of our capture device */ snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name ); UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, NULL, JackPortIsOutput ), paUnanticipatedHostError ); for( i = 0; i < inputChannelCount && jack_ports[i]; i++ ) { if( (stream->remote_output_ports[i] = jack_port_by_name( jackHostApi->jack_client, jack_ports[i] )) == NULL ) { err = 1; break; } } free( jack_ports ); UNLESS( !err, paInsufficientMemory ); /* Fewer ports than expected? */ UNLESS( i == inputChannelCount, paInternalError ); } if( outputChannelCount > 0 ) { int err = 0; /* Get input ports of our playback device */ snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name ); UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, NULL, JackPortIsInput ), paUnanticipatedHostError ); for( i = 0; i < outputChannelCount && jack_ports[i]; i++ ) { if( (stream->remote_input_ports[i] = jack_port_by_name( jackHostApi->jack_client, jack_ports[i] )) == 0 ) { err = 1; break; } } free( jack_ports ); UNLESS( !err , paInsufficientMemory ); /* Fewer ports than expected? */ UNLESS( i == outputChannelCount, paInternalError ); } ENSURE_PA( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, paFloat32, /* hostInputSampleFormat */ outputChannelCount, outputSampleFormat, paFloat32, /* hostOutputSampleFormat */ jackSr, streamFlags, framesPerBuffer, 0, /* Ignored */ paUtilUnknownHostBufferSize, /* Buffer size may vary on JACK's discretion */ streamCallback, userData ) ); bpInitialized = 1; if( stream->num_incoming_connections > 0 ) stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] ) - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor )) / sampleRate; if( stream->num_outgoing_connections > 0 ) stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] ) - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor )) / sampleRate; stream->streamRepresentation.streamInfo.sampleRate = jackSr; stream->t0 = jack_frame_time( jackHostApi->jack_client ); /* A: Time should run from Pa_OpenStream */ /* Add to queue of opened streams */ ENSURE_PA( AddStream( stream ) ); *s = (PaStream*)stream; return result; error: if( stream ) CleanUpStream( stream, srInitialized, bpInitialized ); return result; } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaJackStream *stream = (PaJackStream*)s; /* Remove this stream from the processing queue */ ENSURE_PA( RemoveStream( stream ) ); error: CleanUpStream( stream, 1, 1 ); return result; } static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames ) { PaError result = paNoError; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; int chn; int framesProcessed; const double sr = jack_get_sample_rate( stream->jack_client ); /* Shouldn't change during the process callback */ PaStreamCallbackFlags cbFlags = 0; /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers, * when these are empty we can finally mark the stream as inactive */ if( stream->callbackResult != paContinue && PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) { stream->is_active = 0; if( stream->streamRepresentation.streamFinishedCallback ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ )); goto end; } timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr; if( stream->num_incoming_connections > 0 ) timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] ) / sr; if( stream->num_outgoing_connections > 0 ) timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] ) / sr; PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); if( stream->xrun ) { /* XXX: Any way to tell which of these occurred? */ cbFlags = paOutputUnderflow | paInputOverflow; stream->xrun = FALSE; } PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); if( stream->num_incoming_connections > 0 ) PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames ); if( stream->num_outgoing_connections > 0 ) PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames ); for( chn = 0; chn < stream->num_incoming_connections; chn++ ) { jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) jack_port_get_buffer( stream->local_input_ports[chn], frames ); PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor, chn, channel_buf ); } for( chn = 0; chn < stream->num_outgoing_connections; chn++ ) { jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) jack_port_get_buffer( stream->local_output_ports[chn], frames ); PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor, chn, channel_buf ); } framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &stream->callbackResult ); /* We've specified a host buffer size mode where every frame should be consumed by the buffer processor */ assert( framesProcessed == frames ); PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); end: return result; } /* Update the JACK callback's stream processing queue. */ static PaError UpdateQueue( PaJackHostApiRepresentation *hostApi ) { PaError result = paNoError; int queueModified = 0; const double jackSr = jack_get_sample_rate( hostApi->jack_client ); int err; if( (err = pthread_mutex_trylock( &hostApi->mtx )) != 0 ) { assert( err == EBUSY ); return paNoError; } if( hostApi->toAdd ) { if( hostApi->processQueue ) { PaJackStream *node = hostApi->processQueue; /* Advance to end of queue */ while( node->next ) node = node->next; node->next = hostApi->toAdd; } else { /* The only queue entry. */ hostApi->processQueue = (PaJackStream *)hostApi->toAdd; } /* If necessary, update stream state */ if( hostApi->toAdd->streamRepresentation.streamInfo.sampleRate != jackSr ) UpdateSampleRate( hostApi->toAdd, jackSr ); hostApi->toAdd = NULL; queueModified = 1; } if( hostApi->toRemove ) { int removed = 0; PaJackStream *node = hostApi->processQueue, *prev = NULL; assert( hostApi->processQueue ); while( node ) { if( node == hostApi->toRemove ) { if( prev ) prev->next = node->next; else hostApi->processQueue = (PaJackStream *)node->next; removed = 1; break; } prev = node; node = node->next; } UNLESS( removed, paInternalError ); hostApi->toRemove = NULL; PA_DEBUG(( "%s: Removed stream from processing queue\n", __FUNCTION__ )); queueModified = 1; } if( queueModified ) { /* Signal that we've done what was asked of us */ ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 ); } error: ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); return result; } /* Audio processing callback invoked periodically from JACK. */ static int JackCallback( jack_nframes_t frames, void *userData ) { PaError result = paNoError; PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)userData; PaJackStream *stream = NULL; int xrun = hostApi->xrun; hostApi->xrun = 0; assert( hostApi ); ENSURE_PA( UpdateQueue( hostApi ) ); /* Process each stream */ stream = hostApi->processQueue; for( ; stream; stream = stream->next ) { if( xrun ) /* Don't override if already set */ stream->xrun = 1; /* See if this stream is to be started */ if( stream->doStart ) { /* If we can't obtain a lock, we'll try next time */ int err = pthread_mutex_trylock( &stream->hostApi->mtx ); if( !err ) { if( stream->doStart ) /* Could potentially change before obtaining the lock */ { stream->is_active = 1; stream->doStart = 0; PA_DEBUG(( "%s: Starting stream\n", __FUNCTION__ )); ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); stream->callbackResult = paContinue; stream->isSilenced = 0; } ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); } else assert( err == EBUSY ); } else if( stream->doStop || stream->doAbort ) /* Should we stop/abort stream? */ { if( stream->callbackResult == paContinue ) /* Ok, make it stop */ { PA_DEBUG(( "%s: Stopping stream\n", __FUNCTION__ )); stream->callbackResult = stream->doStop ? paComplete : paAbort; } } if( stream->is_active ) ENSURE_PA( RealProcess( stream, frames ) ); /* If we have just entered inactive state, silence output */ if( !stream->is_active && !stream->isSilenced ) { int i; /* Silence buffer after entering inactive state */ PA_DEBUG(( "Silencing the output\n" )); for( i = 0; i < stream->num_outgoing_connections; ++i ) { jack_default_audio_sample_t *buffer = jack_port_get_buffer( stream->local_output_ports[i], frames ); memset( buffer, 0, sizeof (jack_default_audio_sample_t) * frames ); } stream->isSilenced = 1; } if( stream->doStop || stream->doAbort ) { /* See if RealProcess has acted on the request */ if( !stream->is_active ) /* Ok, signal to the main thread that we've carried out the operation */ { /* If we can't obtain a lock, we'll try next time */ int err = pthread_mutex_trylock( &stream->hostApi->mtx ); if( !err ) { stream->doStop = stream->doAbort = 0; ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); } else assert( err == EBUSY ); } } } return 0; error: return -1; } static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaJackStream *stream = (PaJackStream*)s; int i; /* Ready the processor */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); /* Connect the ports. Note that the ports may already have been connected by someone else in * the meantime, in which case JACK returns EEXIST. */ if( stream->num_incoming_connections > 0 ) { for( i = 0; i < stream->num_incoming_connections; i++ ) { int r = jack_connect( stream->jack_client, jack_port_name( stream->remote_output_ports[i] ), jack_port_name( stream->local_input_ports[i] ) ); UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError ); } } if( stream->num_outgoing_connections > 0 ) { for( i = 0; i < stream->num_outgoing_connections; i++ ) { int r = jack_connect( stream->jack_client, jack_port_name( stream->local_output_ports[i] ), jack_port_name( stream->remote_input_ports[i] ) ); UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError ); } } stream->xrun = FALSE; /* Enable processing */ ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); stream->doStart = 1; /* Wait for stream to be started */ result = WaitCondition( stream->hostApi ); /* do { err = pthread_cond_timedwait( &stream->hostApi->cond, &stream->hostApi->mtx, &ts ); } while( !stream->is_active && !err ); */ if( result != paNoError ) /* Something went wrong, call off the stream start */ { stream->doStart = 0; stream->is_active = 0; /* Cancel any processing */ } ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); ENSURE_PA( result ); stream->is_running = TRUE; PA_DEBUG(( "%s: Stream started\n", __FUNCTION__ )); error: return result; } static PaError RealStop( PaJackStream *stream, int abort ) { PaError result = paNoError; int i; if( stream->isBlockingStream ) BlockingWaitEmpty ( stream ); ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); if( abort ) stream->doAbort = 1; else stream->doStop = 1; /* Wait for stream to be stopped */ result = WaitCondition( stream->hostApi ); ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); ENSURE_PA( result ); UNLESS( !stream->is_active, paInternalError ); PA_DEBUG(( "%s: Stream stopped\n", __FUNCTION__ )); error: stream->is_running = FALSE; /* Disconnect ports belonging to this stream */ if( !stream->hostApi->jackIsDown ) /* XXX: Well? */ { for( i = 0; i < stream->num_incoming_connections; i++ ) { if( jack_port_connected( stream->local_input_ports[i] ) ) { UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_input_ports[i] ), paUnanticipatedHostError ); } } for( i = 0; i < stream->num_outgoing_connections; i++ ) { if( jack_port_connected( stream->local_output_ports[i] ) ) { UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_output_ports[i] ), paUnanticipatedHostError ); } } } return result; } static PaError StopStream( PaStream *s ) { assert(s); return RealStop( (PaJackStream *)s, 0 ); } static PaError AbortStream( PaStream *s ) { assert(s); return RealStop( (PaJackStream *)s, 1 ); } static PaError IsStreamStopped( PaStream *s ) { PaJackStream *stream = (PaJackStream*)s; return !stream->is_running; } static PaError IsStreamActive( PaStream *s ) { PaJackStream *stream = (PaJackStream*)s; return stream->is_active; } static PaTime GetStreamTime( PaStream *s ) { PaJackStream *stream = (PaJackStream*)s; /* A: Is this relevant?? --> TODO: what if we're recording-only? */ return (jack_frame_time( stream->jack_client ) - stream->t0) / (PaTime)jack_get_sample_rate( stream->jack_client ); } static double GetStreamCpuLoad( PaStream* s ) { PaJackStream *stream = (PaJackStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } PaError PaJack_SetClientName( const char* name ) { if( strlen( name ) > jack_client_name_size() ) { /* OK, I don't know any better error code */ return paInvalidFlag; } clientName_ = name; return paNoError; } PaError PaJack_GetClientName(const char** clientName) { PaError result = paNoError; PaJackHostApiRepresentation* jackHostApi = NULL; PaJackHostApiRepresentation** ref = &jackHostApi; ENSURE_PA( PaUtil_GetHostApiRepresentation( (PaUtilHostApiRepresentation**)ref, paJACK ) ); *clientName = jack_get_client_name( jackHostApi->jack_client ); error: return result; } nyquist-3.05/portaudio/src/hostapi/wmme/0002755000175000000620000000000011537433131017377 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/wmme/pa_win_wmme.c0000644000175000000620000044153111466723256022066 0ustar stevestaff/* * $Id: pa_win_wmme.c,v 1.1 2010/11/04 21:04:37 rbd Exp $ * pa_win_wmme.c * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Authors: Ross Bencina and Phil Burk * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /* Modification History: PLB = Phil Burk JM = Julien Maillard RDB = Ross Bencina PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) PLB20010413 - check for excessive numbers of channels PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC including conditional inclusion of memory.h, and explicit typecasting on memory allocation PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory PLB20010816 - pass process instead of thread to SetPriorityClass() PLB20010927 - use number of frames instead of real-time for CPULoad calculation. JM20020118 - prevent hung thread when buffers underflow. PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices refactoring, renaming and fixed a few edge case bugs RDB20020531 - converted to V19 framework ** NOTE maintanance history is now stored in CVS ** */ /** @file @ingroup hostaip_src @todo Fix buffer catch up code, can sometimes get stuck (perhaps fixed now, needs to be reviewed and tested.) @todo implement paInputUnderflow, paOutputOverflow streamCallback statusFlags, paNeverDropInput. @todo BUG: PA_MME_SET_LAST_WAVEIN/OUT_ERROR is used in functions which may be called asynchronously from the callback thread. this is bad. @todo implement inputBufferAdcTime in callback thread @todo review/fix error recovery and cleanup in marked functions @todo implement timeInfo for stream priming @todo handle the case where the callback returns paAbort or paComplete during stream priming. @todo review input overflow and output underflow handling in ReadStream and WriteStream Non-critical stuff for the future: @todo Investigate supporting host buffer formats > 16 bits @todo define UNICODE and _UNICODE in the project settings and see what breaks @todo refactor conversion of MMSYSTEM errors into PA arrors into a single function. @todo cleanup WAVEFORMATEXTENSIBLE retry in InitializeWaveHandles to not use a for loop */ /* How it works: For both callback and blocking read/write streams we open the MME devices in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever it has finished with a buffer (either filled it for input, or played it for output). Where necessary we block waiting for Event objects using WaitMultipleObjects(). When implementing a PA callback stream, we set up a high priority thread which waits on the MME buffer Events and drains/fills the buffers when they are ready. When implementing a PA blocking read/write stream, we simply wait on these Events (when necessary) inside the ReadStream() and WriteStream() functions. */ #include #include #include #include #include #ifndef UNDER_CE #include #endif #include /* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ #ifndef __MWERKS__ #include #include #endif /* __MWERKS__ */ #include "portaudio.h" #include "pa_trace.h" #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_debugprint.h" #include "pa_win_wmme.h" #include "pa_win_waveformat.h" #ifdef PAWIN_USE_WDMKS_DEVICE_INFO #include "pa_win_wdmks_utils.h" #ifndef DRV_QUERYDEVICEINTERFACE #define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) #endif #ifndef DRV_QUERYDEVICEINTERFACESIZE #define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) #endif #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ #if (defined(UNDER_CE)) #pragma comment(lib, "Coredll.lib") #elif (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ #pragma comment(lib, "winmm.lib") #endif /* provided in newer platform sdks */ #ifndef DWORD_PTR #define DWORD_PTR DWORD #endif /************************************************* Constants ********/ #define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */ #if PA_MME_USE_HIGH_DEFAULT_LATENCY_ #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4) #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4) #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16) #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */ #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */ #else #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2) #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2) #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16) #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */ #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */ #endif /* Use higher latency for NT because it is even worse at real-time operation than Win9x. */ #define PA_MME_WIN_NT_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2) #define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_) #define PA_MME_MIN_TIMEOUT_MSEC_ (1000) static const char constInputMapperSuffix_[] = " - Input"; static const char constOutputMapperSuffix_[] = " - Output"; /********************************************************************/ typedef struct PaWinMmeStream PaWinMmeStream; /* forward declaration */ /* prototypes for functions declared in this file */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* macros for setting last host error information */ #ifdef UNICODE #define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \ { \ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ } #define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \ { \ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ } #else /* !UNICODE */ #define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \ { \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ } #define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \ { \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ } #endif /* UNICODE */ static void PaMme_SetLastSystemError( DWORD errorCode ) { char *lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf ); LocalFree( lpMsgBuf ); } #define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \ PaMme_SetLastSystemError( errorCode ) /* PaError returning wrappers for some commonly used win32 functions note that we allow passing a null ptr to have no effect. */ static PaError CreateEventWithPaError( HANDLE *handle, LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName ) { PaError result = paNoError; *handle = NULL; *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName ); if( *handle == NULL ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); } return result; } static PaError ResetEventWithPaError( HANDLE handle ) { PaError result = paNoError; if( handle ) { if( ResetEvent( handle ) == 0 ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); } } return result; } static PaError CloseHandleWithPaError( HANDLE handle ) { PaError result = paNoError; if( handle ) { if( CloseHandle( handle ) == 0 ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); } } return result; } /* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; int inputDeviceCount, outputDeviceCount; /** winMmeDeviceIds is an array of WinMme device ids. fields in the range [0, inputDeviceCount) are input device ids, and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output device ids. */ UINT *winMmeDeviceIds; } PaWinMmeHostApiRepresentation; typedef struct { PaDeviceInfo inheritedDeviceInfo; DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */ char deviceInputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ char deviceOutputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ } PaWinMmeDeviceInfo; /************************************************************************* * Returns recommended device ID. * On the PC, the recommended device can be specified by the user by * setting an environment variable. For example, to use device #1. * * set PA_RECOMMENDED_OUTPUT_DEVICE=1 * * The user should first determine the available device ID by using * the supplied application "pa_devs". */ #define PA_ENV_BUF_SIZE_ (32) #define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE") #define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE") static PaDeviceIndex GetEnvDefaultDeviceID( char *envName ) { PaDeviceIndex recommendedIndex = paNoDevice; DWORD hresult; char envbuf[PA_ENV_BUF_SIZE_]; #ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */ /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) ) { recommendedIndex = atoi( envbuf ); } #endif return recommendedIndex; } static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi ) { PaDeviceIndex device; /* input */ device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ ); if( device != paNoDevice && ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) && hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 ) { hostApi->inheritedHostApiRep.info.defaultInputDevice = device; } /* output */ device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ ); if( device != paNoDevice && ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) && hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 ) { hostApi->inheritedHostApiRep.info.defaultOutputDevice = device; } } /** Convert external PA ID to a windows multimedia device ID */ static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device ) { assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount ); return hostApi->winMmeDeviceIds[ device ]; } static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx ) { MMRESULT mmresult; switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) ) { case MMSYSERR_NOERROR: return paNoError; case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ return paDeviceUnavailable; case MMSYSERR_NODRIVER: /* No device driver is present. */ return paDeviceUnavailable; case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ return paInsufficientMemory; case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ return paSampleFormatNotSupported; case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ /* falls through */ default: PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); return paUnanticipatedHostError; } } static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx ) { MMRESULT mmresult; switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) ) { case MMSYSERR_NOERROR: return paNoError; case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ return paDeviceUnavailable; case MMSYSERR_NODRIVER: /* No device driver is present. */ return paDeviceUnavailable; case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ return paInsufficientMemory; case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ return paSampleFormatNotSupported; case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ /* falls through */ default: PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); return paUnanticipatedHostError; } } static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo, PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int winMmeDeviceId, int channels, double sampleRate ) { PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo; PaWinWaveFormat waveFormat; if( sampleRate == 11025.0 && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16)) || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){ return paNoError; } if( sampleRate == 22050.0 && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16)) || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){ return paNoError; } if( sampleRate == 44100.0 && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16)) || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){ return paNoError; } /* first, attempt to query the device using WAVEFORMATEXTENSIBLE, if this fails we fall back to WAVEFORMATEX */ /* @todo at the moment we only query with 16 bit sample format and directout speaker config*/ PaWin_InitializeWaveFormatExtensible( &waveFormat, channels, paInt16, sampleRate, PAWIN_SPEAKER_DIRECTOUT ); if( waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ) == paNoError ) return paNoError; PaWin_InitializeWaveFormatEx( &waveFormat, channels, paInt16, sampleRate ); return waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ); } #define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */ static double defaultSampleRateSearchOrder_[] = { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId, PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels ) { PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; int i; deviceInfo->defaultSampleRate = 0.; for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i ) { double sampleRate = defaultSampleRateSearchOrder_[ i ]; PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate ); if( paerror == paNoError ) { deviceInfo->defaultSampleRate = sampleRate; break; } } } #ifdef PAWIN_USE_WDMKS_DEVICE_INFO static int QueryWaveInKSFilterMaxChannels( int waveInDeviceId, int *maxChannels ) { void *devicePath; DWORD devicePathSize; int result = 0; if( waveInMessage((HWAVEIN)waveInDeviceId, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&devicePathSize, 0 ) != MMSYSERR_NOERROR ) return 0; devicePath = PaUtil_AllocateMemory( devicePathSize ); if( !devicePath ) return 0; /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */ if( waveInMessage((HWAVEIN)waveInDeviceId, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)devicePath, devicePathSize ) == MMSYSERR_NOERROR ) { int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( devicePath, /* isInput= */ 1 ); if( count > 0 ) { *maxChannels = count; result = 1; } } PaUtil_FreeMemory( devicePath ); return result; } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success ) { PaError result = paNoError; char *deviceName; /* non-const ptr */ MMRESULT mmresult; WAVEINCAPS wic; PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; *success = 0; mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) ); if( mmresult == MMSYSERR_NOMEM ) { result = paInsufficientMemory; goto error; } else if( mmresult != MMSYSERR_NOERROR ) { /* instead of returning paUnanticipatedHostError we return paNoError, but leave success set as 0. This allows Pa_Initialize to just ignore this device, without failing the entire initialisation process. */ return paNoError; } if( winMmeInputDeviceId == WAVE_MAPPER ) { /* Append I/O suffix to WAVE_MAPPER device. */ deviceName = (char *)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, wic.szPname ); strcat( deviceName, constInputMapperSuffix_ ); } else { deviceName = (char*)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( wic.szPname ) + 1 ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, wic.szPname ); } deviceInfo->name = deviceName; if( wic.wChannels == 0xFFFF || wic.wChannels < 1 || wic.wChannels > 255 ){ /* For Windows versions using WDM (possibly Windows 98 ME and later) * the kernel mixer sits between the application and the driver. As a result, * wave*GetDevCaps often kernel mixer channel counts, which are unlimited. * When this happens we assume the device is stereo and set a flag * so that other channel counts can be tried with OpenStream -- i.e. when * device*ChannelCountIsKnown is false, OpenStream will try whatever * channel count you supply. * see also InitializeOutputDeviceInfo() below. */ PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", wic.wChannels )); deviceInfo->maxInputChannels = 2; winMmeDeviceInfo->deviceInputChannelCountIsKnown = 0; }else{ deviceInfo->maxInputChannels = wic.wChannels; winMmeDeviceInfo->deviceInputChannelCountIsKnown = 1; } #ifdef PAWIN_USE_WDMKS_DEVICE_INFO winMmeDeviceInfo->deviceInputChannelCountIsKnown = QueryWaveInKSFilterMaxChannels( winMmeInputDeviceId, &deviceInfo->maxInputChannels ); #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ winMmeDeviceInfo->dwFormats = wic.dwFormats; DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId, QueryInputWaveFormatEx, deviceInfo->maxInputChannels ); *success = 1; error: return result; } #ifdef PAWIN_USE_WDMKS_DEVICE_INFO static int QueryWaveOutKSFilterMaxChannels( int waveOutDeviceId, int *maxChannels ) { void *devicePath; DWORD devicePathSize; int result = 0; if( waveOutMessage((HWAVEOUT)waveOutDeviceId, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&devicePathSize, 0 ) != MMSYSERR_NOERROR ) return 0; devicePath = PaUtil_AllocateMemory( devicePathSize ); if( !devicePath ) return 0; /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */ if( waveOutMessage((HWAVEOUT)waveOutDeviceId, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)devicePath, devicePathSize ) == MMSYSERR_NOERROR ) { int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( devicePath, /* isInput= */ 0 ); if( count > 0 ) { *maxChannels = count; result = 1; } } PaUtil_FreeMemory( devicePath ); return result; } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success ) { PaError result = paNoError; char *deviceName; /* non-const ptr */ MMRESULT mmresult; WAVEOUTCAPS woc; PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; *success = 0; mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) ); if( mmresult == MMSYSERR_NOMEM ) { result = paInsufficientMemory; goto error; } else if( mmresult != MMSYSERR_NOERROR ) { /* instead of returning paUnanticipatedHostError we return paNoError, but leave success set as 0. This allows Pa_Initialize to just ignore this device, without failing the entire initialisation process. */ return paNoError; } if( winMmeOutputDeviceId == WAVE_MAPPER ) { /* Append I/O suffix to WAVE_MAPPER device. */ deviceName = (char *)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, woc.szPname ); strcat( deviceName, constOutputMapperSuffix_ ); } else { deviceName = (char*)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, strlen( woc.szPname ) + 1 ); if( !deviceName ) { result = paInsufficientMemory; goto error; } strcpy( deviceName, woc.szPname ); } deviceInfo->name = deviceName; if( woc.wChannels == 0xFFFF || woc.wChannels < 1 || woc.wChannels > 255 ){ /* For Windows versions using WDM (possibly Windows 98 ME and later) * the kernel mixer sits between the application and the driver. As a result, * wave*GetDevCaps often kernel mixer channel counts, which are unlimited. * When this happens we assume the device is stereo and set a flag * so that other channel counts can be tried with OpenStream -- i.e. when * device*ChannelCountIsKnown is false, OpenStream will try whatever * channel count you supply. * see also InitializeInputDeviceInfo() above. */ PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", woc.wChannels )); deviceInfo->maxOutputChannels = 2; winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 0; }else{ deviceInfo->maxOutputChannels = woc.wChannels; winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; } #ifdef PAWIN_USE_WDMKS_DEVICE_INFO winMmeDeviceInfo->deviceOutputChannelCountIsKnown = QueryWaveOutKSFilterMaxChannels( winMmeOutputDeviceId, &deviceInfo->maxOutputChannels ); #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ winMmeDeviceInfo->dwFormats = woc.dwFormats; DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId, QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels ); *success = 1; error: return result; } static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency ) { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof( osvi ); GetVersionEx( &osvi ); /* Check for NT */ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) { *defaultLowLatency = PA_MME_WIN_NT_DEFAULT_LATENCY_; } else if(osvi.dwMajorVersion >= 5) { *defaultLowLatency = PA_MME_WIN_WDM_DEFAULT_LATENCY_; } else { *defaultLowLatency = PA_MME_WIN_9X_DEFAULT_LATENCY_; } *defaultHighLatency = *defaultLowLatency * 2; } PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; int i; PaWinMmeHostApiRepresentation *winMmeHostApi; int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount; PaWinMmeDeviceInfo *deviceInfoArray; int deviceInfoInitializationSucceeded; PaTime defaultLowLatency, defaultHighLatency; DWORD waveInPreferredDevice, waveOutPreferredDevice; DWORD preferredDeviceStatusFlags; winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) ); if( !winMmeHostApi ) { result = paInsufficientMemory; goto error; } winMmeHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !winMmeHostApi->allocations ) { result = paInsufficientMemory; goto error; } *hostApi = &winMmeHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paMME; (*hostApi)->info.name = "MME"; /* initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized. */ (*hostApi)->info.deviceCount = 0; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; winMmeHostApi->inputDeviceCount = 0; winMmeHostApi->outputDeviceCount = 0; #if !defined(DRVM_MAPPER_PREFERRED_GET) /* DRVM_MAPPER_PREFERRED_GET is defined in mmddk.h but we avoid a dependency on the DDK by defining it here */ #define DRVM_MAPPER_PREFERRED_GET (0x2000+21) #endif /* the following calls assume that if wave*Message fails the preferred device parameter won't be modified */ preferredDeviceStatusFlags = 0; waveInPreferredDevice = -1; waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD)&waveInPreferredDevice, (DWORD)&preferredDeviceStatusFlags ); preferredDeviceStatusFlags = 0; waveOutPreferredDevice = -1; waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD)&waveOutPreferredDevice, (DWORD)&preferredDeviceStatusFlags ); maximumPossibleDeviceCount = 0; inputDeviceCount = waveInGetNumDevs(); if( inputDeviceCount > 0 ) maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ outputDeviceCount = waveOutGetNumDevs(); if( outputDeviceCount > 0 ) maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ if( maximumPossibleDeviceCount > 0 ){ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount ); if( !(*hostApi)->deviceInfos ) { result = paInsufficientMemory; goto error; } /* allocate all device info structs in a contiguous block */ deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount ); if( !deviceInfoArray ) { result = paInsufficientMemory; goto error; } winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory( winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount ); if( !winMmeHostApi->winMmeDeviceIds ) { result = paInsufficientMemory; goto error; } GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency ); if( inputDeviceCount > 0 ){ /* -1 is the WAVE_MAPPER */ for( i = -1; i < inputDeviceCount; ++i ){ UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; deviceInfo->maxInputChannels = 0; wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; deviceInfo->maxOutputChannels = 0; wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; deviceInfo->defaultLowInputLatency = defaultLowLatency; deviceInfo->defaultLowOutputLatency = defaultLowLatency; deviceInfo->defaultHighInputLatency = defaultHighLatency; deviceInfo->defaultHighOutputLatency = defaultHighLatency; result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, winMmeDeviceId, &deviceInfoInitializationSucceeded ); if( result != paNoError ) goto error; if( deviceInfoInitializationSucceeded ){ if( (*hostApi)->info.defaultInputDevice == paNoDevice ){ /* if there is currently no default device, use the first one available */ (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; }else if( winMmeDeviceId == waveInPreferredDevice ){ /* set the default device to the system preferred device */ (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; } winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; winMmeHostApi->inputDeviceCount++; (*hostApi)->info.deviceCount++; } } } if( outputDeviceCount > 0 ){ /* -1 is the WAVE_MAPPER */ for( i = -1; i < outputDeviceCount; ++i ){ UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; deviceInfo->maxInputChannels = 0; wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; deviceInfo->maxOutputChannels = 0; wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; deviceInfo->defaultLowInputLatency = defaultLowLatency; deviceInfo->defaultLowOutputLatency = defaultLowLatency; deviceInfo->defaultHighInputLatency = defaultHighLatency; deviceInfo->defaultHighOutputLatency = defaultHighLatency; result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, winMmeDeviceId, &deviceInfoInitializationSucceeded ); if( result != paNoError ) goto error; if( deviceInfoInitializationSucceeded ){ if( (*hostApi)->info.defaultOutputDevice == paNoDevice ){ /* if there is currently no default device, use the first one available */ (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; }else if( winMmeDeviceId == waveOutPreferredDevice ){ /* set the default device to the system preferred device */ (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; } winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; winMmeHostApi->outputDeviceCount++; (*hostApi)->info.deviceCount++; } } } } InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if( winMmeHostApi ) { if( winMmeHostApi->allocations ) { PaUtil_FreeAllAllocations( winMmeHostApi->allocations ); PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations ); } PaUtil_FreeMemory( winMmeHostApi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; if( winMmeHostApi->allocations ) { PaUtil_FreeAllAllocations( winMmeHostApi->allocations ); PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations ); } PaUtil_FreeMemory( winMmeHostApi ); } static PaError IsInputChannelCountSupported( PaWinMmeDeviceInfo* deviceInfo, int channelCount ) { PaError result = paNoError; if( channelCount > 0 && deviceInfo->deviceInputChannelCountIsKnown && channelCount > deviceInfo->inheritedDeviceInfo.maxInputChannels ){ result = paInvalidChannelCount; } return result; } static PaError IsOutputChannelCountSupported( PaWinMmeDeviceInfo* deviceInfo, int channelCount ) { PaError result = paNoError; if( channelCount > 0 && deviceInfo->deviceOutputChannelCountIsKnown && channelCount > deviceInfo->inheritedDeviceInfo.maxOutputChannels ){ result = paInvalidChannelCount; } return result; } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo; int inputChannelCount, outputChannelCount; int inputMultipleDeviceChannelCount, outputMultipleDeviceChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo; UINT winMmeInputDeviceId, winMmeOutputDeviceId; unsigned int i; PaError paerror; /* The calls to QueryFormatSupported below are intended to detect invalid sample rates. If we assume that the channel count and format are OK, then the only thing that could fail is the sample rate. This isn't strictly true, but I can't think of a better way to test that the sample rate is valid. */ if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; inputStreamInfo = inputParameters->hostApiSpecificStreamInfo; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; if( inputParameters->device == paUseHostApiSpecificDeviceSpecification && inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) ) { inputMultipleDeviceChannelCount = 0; for( i=0; i< inputStreamInfo->deviceCount; ++i ) { inputMultipleDeviceChannelCount += inputStreamInfo->devices[i].channelCount; inputDeviceInfo = hostApi->deviceInfos[ inputStreamInfo->devices[i].device ]; /* check that input device can support inputChannelCount */ if( inputStreamInfo->devices[i].channelCount < 1 ) return paInvalidChannelCount; paerror = IsInputChannelCountSupported( (PaWinMmeDeviceInfo*)inputDeviceInfo, inputStreamInfo->devices[i].channelCount ); if( paerror != paNoError ) return paerror; /* test for valid sample rate, see comment above */ winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputStreamInfo->devices[i].device ); paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputStreamInfo->devices[i].channelCount, sampleRate ); if( paerror != paNoError ) return paInvalidSampleRate; } if( inputMultipleDeviceChannelCount != inputChannelCount ) return paIncompatibleHostApiSpecificStreamInfo; } else { if( inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) ) return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the input device */ inputDeviceInfo = hostApi->deviceInfos[ inputParameters->device ]; /* check that input device can support inputChannelCount */ paerror = IsInputChannelCountSupported( (PaWinMmeDeviceInfo*)inputDeviceInfo, inputChannelCount ); if( paerror != paNoError ) return paerror; /* test for valid sample rate, see comment above */ winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device ); paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputChannelCount, sampleRate ); if( paerror != paNoError ) return paInvalidSampleRate; } } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; outputStreamInfo = outputParameters->hostApiSpecificStreamInfo; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; if( outputParameters->device == paUseHostApiSpecificDeviceSpecification && outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) ) { outputMultipleDeviceChannelCount = 0; for( i=0; i< outputStreamInfo->deviceCount; ++i ) { outputMultipleDeviceChannelCount += outputStreamInfo->devices[i].channelCount; outputDeviceInfo = hostApi->deviceInfos[ outputStreamInfo->devices[i].device ]; /* check that output device can support outputChannelCount */ if( outputStreamInfo->devices[i].channelCount < 1 ) return paInvalidChannelCount; paerror = IsOutputChannelCountSupported( (PaWinMmeDeviceInfo*)outputDeviceInfo, outputStreamInfo->devices[i].channelCount ); if( paerror != paNoError ) return paerror; /* test for valid sample rate, see comment above */ winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputStreamInfo->devices[i].device ); paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputStreamInfo->devices[i].channelCount, sampleRate ); if( paerror != paNoError ) return paInvalidSampleRate; } if( outputMultipleDeviceChannelCount != outputChannelCount ) return paIncompatibleHostApiSpecificStreamInfo; } else { if( outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) ) return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the output device */ outputDeviceInfo = hostApi->deviceInfos[ outputParameters->device ]; /* check that output device can support outputChannelCount */ paerror = IsOutputChannelCountSupported( (PaWinMmeDeviceInfo*)outputDeviceInfo, outputChannelCount ); if( paerror != paNoError ) return paerror; /* test for valid sample rate, see comment above */ winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device ); paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputChannelCount, sampleRate ); if( paerror != paNoError ) return paInvalidSampleRate; } } /* - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate for mme all we can do is test that the input and output devices support the requested sample rate and number of channels. we cannot test for full duplex compatibility. */ return paFormatIsSupported; } static void SelectBufferSizeAndCount( unsigned long baseBufferSize, unsigned long requestedLatency, unsigned long baseBufferCount, unsigned long minimumBufferCount, unsigned long maximumBufferSize, unsigned long *hostBufferSize, unsigned long *hostBufferCount ) { unsigned long sizeMultiplier, bufferCount, latency; unsigned long nextLatency, nextBufferSize; int baseBufferSizeIsPowerOfTwo; sizeMultiplier = 1; bufferCount = baseBufferCount; /* count-1 below because latency is always determined by one less than the total number of buffers. */ latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1); if( latency > requestedLatency ) { /* reduce number of buffers without falling below suggested latency */ nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2); while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency ) { --bufferCount; nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2); } }else if( latency < requestedLatency ){ baseBufferSizeIsPowerOfTwo = (! (baseBufferSize & (baseBufferSize - 1))); if( baseBufferSizeIsPowerOfTwo ){ /* double size of buffers without exceeding requestedLatency */ nextBufferSize = (baseBufferSize * (sizeMultiplier*2)); nextLatency = nextBufferSize * (bufferCount-1); while( nextBufferSize <= maximumBufferSize && nextLatency < requestedLatency ) { sizeMultiplier *= 2; nextBufferSize = (baseBufferSize * (sizeMultiplier*2)); nextLatency = nextBufferSize * (bufferCount-1); } }else{ /* increase size of buffers upto first excess of requestedLatency */ nextBufferSize = (baseBufferSize * (sizeMultiplier+1)); nextLatency = nextBufferSize * (bufferCount-1); while( nextBufferSize <= maximumBufferSize && nextLatency < requestedLatency ) { ++sizeMultiplier; nextBufferSize = (baseBufferSize * (sizeMultiplier+1)); nextLatency = nextBufferSize * (bufferCount-1); } if( nextLatency < requestedLatency ) ++sizeMultiplier; } /* increase number of buffers until requestedLatency is reached */ latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1); while( latency < requestedLatency ) { ++bufferCount; latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1); } } *hostBufferSize = baseBufferSize * sizeMultiplier; *hostBufferCount = bufferCount; } static void ReselectBufferCount( unsigned long bufferSize, unsigned long requestedLatency, unsigned long baseBufferCount, unsigned long minimumBufferCount, unsigned long *hostBufferCount ) { unsigned long bufferCount, latency; unsigned long nextLatency; bufferCount = baseBufferCount; /* count-1 below because latency is always determined by one less than the total number of buffers. */ latency = bufferSize * (bufferCount-1); if( latency > requestedLatency ) { /* reduce number of buffers without falling below suggested latency */ nextLatency = bufferSize * (bufferCount-2); while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency ) { --bufferCount; nextLatency = bufferSize * (bufferCount-2); } }else if( latency < requestedLatency ){ /* increase number of buffers until requestedLatency is reached */ latency = bufferSize * (bufferCount-1); while( latency < requestedLatency ) { ++bufferCount; latency = bufferSize * (bufferCount-1); } } *hostBufferCount = bufferCount; } /* CalculateBufferSettings() fills the framesPerHostInputBuffer, hostInputBufferCount, framesPerHostOutputBuffer and hostOutputBufferCount parameters based on the values of the other parameters. */ static PaError CalculateBufferSettings( unsigned long *framesPerHostInputBuffer, unsigned long *hostInputBufferCount, unsigned long *framesPerHostOutputBuffer, unsigned long *hostOutputBufferCount, int inputChannelCount, PaSampleFormat hostInputSampleFormat, PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo, int outputChannelCount, PaSampleFormat hostOutputSampleFormat, PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo, double sampleRate, unsigned long framesPerBuffer ) { PaError result = paNoError; int effectiveInputChannelCount, effectiveOutputChannelCount; int hostInputFrameSize = 0; unsigned int i; if( inputChannelCount > 0 ) { int hostInputSampleSize = Pa_GetSampleSize( hostInputSampleFormat ); if( hostInputSampleSize < 0 ) { result = hostInputSampleSize; goto error; } if( inputStreamInfo && ( inputStreamInfo->flags & paWinMmeUseMultipleDevices ) ) { /* set effectiveInputChannelCount to the largest number of channels on any one device. */ effectiveInputChannelCount = 0; for( i=0; i< inputStreamInfo->deviceCount; ++i ) { if( inputStreamInfo->devices[i].channelCount > effectiveInputChannelCount ) effectiveInputChannelCount = inputStreamInfo->devices[i].channelCount; } } else { effectiveInputChannelCount = inputChannelCount; } hostInputFrameSize = hostInputSampleSize * effectiveInputChannelCount; if( inputStreamInfo && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) ) { if( inputStreamInfo->bufferCount <= 0 || inputStreamInfo->framesPerBuffer <= 0 ) { result = paIncompatibleHostApiSpecificStreamInfo; goto error; } *framesPerHostInputBuffer = inputStreamInfo->framesPerBuffer; *hostInputBufferCount = inputStreamInfo->bufferCount; } else { unsigned long hostBufferSizeBytes, hostBufferCount; unsigned long minimumBufferCount = (outputChannelCount > 0) ? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ : PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_; unsigned long maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostInputFrameSize); if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ ) maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_; /* compute the following in bytes, then convert back to frames */ SelectBufferSizeAndCount( ((framesPerBuffer == paFramesPerBufferUnspecified) ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ : framesPerBuffer ) * hostInputFrameSize, /* baseBufferSize */ ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, maximumBufferSize, &hostBufferSizeBytes, &hostBufferCount ); *framesPerHostInputBuffer = hostBufferSizeBytes / hostInputFrameSize; *hostInputBufferCount = hostBufferCount; } } else { *framesPerHostInputBuffer = 0; *hostInputBufferCount = 0; } if( outputChannelCount > 0 ) { if( outputStreamInfo && ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) ) { if( outputStreamInfo->bufferCount <= 0 || outputStreamInfo->framesPerBuffer <= 0 ) { result = paIncompatibleHostApiSpecificStreamInfo; goto error; } *framesPerHostOutputBuffer = outputStreamInfo->framesPerBuffer; *hostOutputBufferCount = outputStreamInfo->bufferCount; if( inputChannelCount > 0 ) /* full duplex */ { if( *framesPerHostInputBuffer != *framesPerHostOutputBuffer ) { if( inputStreamInfo && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) ) { /* a custom StreamInfo was used for specifying both input and output buffer sizes, the larger buffer size must be a multiple of the smaller buffer size */ if( *framesPerHostInputBuffer < *framesPerHostOutputBuffer ) { if( *framesPerHostOutputBuffer % *framesPerHostInputBuffer != 0 ) { result = paIncompatibleHostApiSpecificStreamInfo; goto error; } } else { assert( *framesPerHostInputBuffer > *framesPerHostOutputBuffer ); if( *framesPerHostInputBuffer % *framesPerHostOutputBuffer != 0 ) { result = paIncompatibleHostApiSpecificStreamInfo; goto error; } } } else { /* a custom StreamInfo was not used for specifying the input buffer size, so use the output buffer size, and approximately the same latency. */ *framesPerHostInputBuffer = *framesPerHostOutputBuffer; *hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *framesPerHostInputBuffer) + 1; if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ ) *hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_; } } } } else { unsigned long hostBufferSizeBytes, hostBufferCount; unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_; unsigned long maximumBufferSize; int hostOutputFrameSize; int hostOutputSampleSize; hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat ); if( hostOutputSampleSize < 0 ) { result = hostOutputSampleSize; goto error; } if( outputStreamInfo && ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) ) { /* set effectiveOutputChannelCount to the largest number of channels on any one device. */ effectiveOutputChannelCount = 0; for( i=0; i< outputStreamInfo->deviceCount; ++i ) { if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount ) effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount; } } else { effectiveOutputChannelCount = outputChannelCount; } hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount; maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize); if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ ) maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_; /* compute the following in bytes, then convert back to frames */ SelectBufferSizeAndCount( ((framesPerBuffer == paFramesPerBufferUnspecified) ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ : framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */ ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, maximumBufferSize, &hostBufferSizeBytes, &hostBufferCount ); *framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize; *hostOutputBufferCount = hostBufferCount; if( inputChannelCount > 0 ) { /* ensure that both input and output buffer sizes are the same. if they don't match at this stage, choose the smallest one and use that for input and output */ if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer ) { if( framesPerHostInputBuffer < framesPerHostOutputBuffer ) { unsigned long framesPerHostBuffer = *framesPerHostInputBuffer; minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_; ReselectBufferCount( framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */ ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, &hostBufferCount ); *framesPerHostOutputBuffer = framesPerHostBuffer; *hostOutputBufferCount = hostBufferCount; } else { unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer; minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_; ReselectBufferCount( framesPerHostBuffer * hostInputFrameSize, /* bufferSize */ ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, &hostBufferCount ); *framesPerHostInputBuffer = framesPerHostBuffer; *hostInputBufferCount = hostBufferCount; } } } } } else { *framesPerHostOutputBuffer = 0; *hostOutputBufferCount = 0; } error: return result; } typedef struct { HANDLE bufferEvent; void *waveHandles; unsigned int deviceCount; /* unsigned int channelCount; */ WAVEHDR **waveHeaders; /* waveHeaders[device][buffer] */ unsigned int bufferCount; unsigned int currentBufferIndex; unsigned int framesPerBuffer; unsigned int framesUsedInCurrentBuffer; }PaWinMmeSingleDirectionHandlesAndBuffers; /* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */ static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ); static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long bytesPerHostSample, double sampleRate, PaWinMmeDeviceAndChannelCount *devices, unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput ); static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError ); static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long hostBufferCount, PaSampleFormat hostSampleFormat, unsigned long framesPerHostBuffer, PaWinMmeDeviceAndChannelCount *devices, int isInput ); static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput ); static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ) { handlesAndBuffers->bufferEvent = 0; handlesAndBuffers->waveHandles = 0; handlesAndBuffers->deviceCount = 0; handlesAndBuffers->waveHeaders = 0; handlesAndBuffers->bufferCount = 0; } static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long bytesPerHostSample, double sampleRate, PaWinMmeDeviceAndChannelCount *devices, unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput ) { PaError result; MMRESULT mmresult; signed int i, j; /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() has already been called to zero some fields */ result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL ); if( result != paNoError ) goto error; if( isInput ) handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount ); else handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount ); if( !handlesAndBuffers->waveHandles ) { result = paInsufficientMemory; goto error; } handlesAndBuffers->deviceCount = deviceCount; for( i = 0; i < (signed int)deviceCount; ++i ) { if( isInput ) ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0; else ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0; } for( i = 0; i < (signed int)deviceCount; ++i ) { PaWinWaveFormat waveFormat; UINT winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device ); /* @todo: consider providing a flag or #define to not try waveformat extensible this could just initialize j to 1 the first time round. */ for( j = 0; j < 2; ++j ) { if( j == 0 ) { /* first, attempt to open the device using WAVEFORMATEXTENSIBLE, if this fails we fall back to WAVEFORMATEX */ /* @todo at the moment we only use 16 bit sample format */ PaWin_InitializeWaveFormatExtensible( &waveFormat, devices[i].channelCount, paInt16, sampleRate, channelMask ); } else { /* retry with WAVEFORMATEX */ PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount, paInt16, sampleRate ); } /* REVIEW: consider not firing an event for input when a full duplex stream is being used. this would probably depend on the neverDropInput flag. */ if( isInput ) { mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, (WAVEFORMATEX*)&waveFormat, (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT ); } else { mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, (WAVEFORMATEX*)&waveFormat, (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT ); } if( mmresult == MMSYSERR_NOERROR ) { break; /* success */ } else if( j == 0 ) { continue; /* try again with WAVEFORMATEX */ } else { switch( mmresult ) { case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ result = paDeviceUnavailable; break; case MMSYSERR_NODRIVER: /* No device driver is present. */ result = paDeviceUnavailable; break; case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ result = paInsufficientMemory; break; case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ /* falls through */ case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ /* This can also occur if we try to open the device with an unsupported * number of channels. This is attempted when device*ChannelCountIsKnown is * set to 0. */ /* falls through */ default: result = paUnanticipatedHostError; if( isInput ) { PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); } else { PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); } } goto error; } } } return result; error: TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ ); return result; } static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError ) { PaError result = paNoError; MMRESULT mmresult; signed int i; if( handlesAndBuffers->waveHandles ) { for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i ) { if( isInput ) { if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] ) mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] ); else mmresult = MMSYSERR_NOERROR; } else { if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] ) mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] ); else mmresult = MMSYSERR_NOERROR; } if( mmresult != MMSYSERR_NOERROR && !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */ { result = paUnanticipatedHostError; if( isInput ) { PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); } else { PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); } /* note that we don't break here, we try to continue closing devices */ } } PaUtil_FreeMemory( handlesAndBuffers->waveHandles ); handlesAndBuffers->waveHandles = 0; } if( handlesAndBuffers->bufferEvent ) { result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent ); handlesAndBuffers->bufferEvent = 0; } return result; } static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long hostBufferCount, PaSampleFormat hostSampleFormat, unsigned long framesPerHostBuffer, PaWinMmeDeviceAndChannelCount *devices, int isInput ) { PaError result = paNoError; MMRESULT mmresult; WAVEHDR *deviceWaveHeaders; signed int i, j; /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() has already been called to zero some fields */ /* allocate an array of pointers to arrays of wave headers, one array of wave headers per device */ handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount ); if( !handlesAndBuffers->waveHeaders ) { result = paInsufficientMemory; goto error; } for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i ) handlesAndBuffers->waveHeaders[i] = 0; handlesAndBuffers->bufferCount = hostBufferCount; for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i ) { int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) * framesPerHostBuffer * devices[i].channelCount; if( bufferBytes < 0 ) { result = paInternalError; goto error; } /* Allocate an array of wave headers for device i */ deviceWaveHeaders = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*hostBufferCount ); if( !deviceWaveHeaders ) { result = paInsufficientMemory; goto error; } for( j=0; j < (signed int)hostBufferCount; ++j ) deviceWaveHeaders[j].lpData = 0; handlesAndBuffers->waveHeaders[i] = deviceWaveHeaders; /* Allocate a buffer for each wave header */ for( j=0; j < (signed int)hostBufferCount; ++j ) { deviceWaveHeaders[j].lpData = (char *)PaUtil_AllocateMemory( bufferBytes ); if( !deviceWaveHeaders[j].lpData ) { result = paInsufficientMemory; goto error; } deviceWaveHeaders[j].dwBufferLength = bufferBytes; deviceWaveHeaders[j].dwUser = 0xFFFFFFFF; /* indicates that *PrepareHeader() has not yet been called, for error clean up code */ if( isInput ) { mmresult = waveInPrepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); goto error; } } else /* output */ { mmresult = waveOutPrepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); goto error; } } deviceWaveHeaders[j].dwUser = devices[i].channelCount; } } return result; error: TerminateWaveHeaders( handlesAndBuffers, isInput ); return result; } static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput ) { signed int i, j; WAVEHDR *deviceWaveHeaders; if( handlesAndBuffers->waveHeaders ) { for( i = handlesAndBuffers->deviceCount-1; i >= 0 ; --i ) { deviceWaveHeaders = handlesAndBuffers->waveHeaders[i]; /* wave headers for device i */ if( deviceWaveHeaders ) { for( j = handlesAndBuffers->bufferCount-1; j >= 0; --j ) { if( deviceWaveHeaders[j].lpData ) { if( deviceWaveHeaders[j].dwUser != 0xFFFFFFFF ) { if( isInput ) waveInUnprepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); else waveOutUnprepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); } PaUtil_FreeMemory( deviceWaveHeaders[j].lpData ); } } PaUtil_FreeMemory( deviceWaveHeaders ); } } PaUtil_FreeMemory( handlesAndBuffers->waveHeaders ); handlesAndBuffers->waveHeaders = 0; } } /* PaWinMmeStream - a stream data structure specifically for this implementation */ /* note that struct PaWinMmeStream is typedeffed to PaWinMmeStream above. */ struct PaWinMmeStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; int primeStreamUsingCallback; PaWinMmeSingleDirectionHandlesAndBuffers input; PaWinMmeSingleDirectionHandlesAndBuffers output; /* Processing thread management -------------- */ HANDLE abortEvent; HANDLE processingThread; DWORD processingThreadId; char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */ int processingThreadPriority; int highThreadPriority; int throttledThreadPriority; unsigned long throttledSleepMsecs; int isStopped; volatile int isActive; volatile int stopProcessing; /* stop thread once existing buffers have been returned */ volatile int abortProcessing; /* stop thread immediately */ DWORD allBuffersDurationMs; /* used to calculate timeouts */ }; /* updates deviceCount if PaWinMmeUseMultipleDevices is used */ static PaError ValidateWinMmeSpecificStreamInfo( const PaStreamParameters *streamParameters, const PaWinMmeStreamInfo *streamInfo, char *throttleProcessingThreadOnOverload, unsigned long *deviceCount ) { if( streamInfo ) { if( streamInfo->size != sizeof( PaWinMmeStreamInfo ) || streamInfo->version != 1 ) { return paIncompatibleHostApiSpecificStreamInfo; } if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread ) *throttleProcessingThreadOnOverload = 0; if( streamInfo->flags & paWinMmeUseMultipleDevices ) { if( streamParameters->device != paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; *deviceCount = streamInfo->deviceCount; } } return paNoError; } static PaError RetrieveDevicesFromStreamParameters( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *streamParameters, const PaWinMmeStreamInfo *streamInfo, PaWinMmeDeviceAndChannelCount *devices, unsigned long deviceCount ) { PaError result = paNoError; unsigned int i; int totalChannelCount; PaDeviceIndex hostApiDevice; if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices ) { totalChannelCount = 0; for( i=0; i < deviceCount; ++i ) { /* validate that the device number is within range */ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, streamInfo->devices[i].device, hostApi ); if( result != paNoError ) return result; devices[i].device = hostApiDevice; devices[i].channelCount = streamInfo->devices[i].channelCount; totalChannelCount += devices[i].channelCount; } if( totalChannelCount != streamParameters->channelCount ) { /* channelCount must match total channels specified by multiple devices */ return paInvalidChannelCount; /* REVIEW use of this error code */ } } else { devices[0].device = streamParameters->device; devices[0].channelCount = streamParameters->channelCount; } return result; } static PaError ValidateInputChannelCounts( struct PaUtilHostApiRepresentation *hostApi, PaWinMmeDeviceAndChannelCount *devices, unsigned long deviceCount ) { unsigned int i; PaWinMmeDeviceInfo *inputDeviceInfo; PaError paerror; for( i=0; i < deviceCount; ++i ) { if( devices[i].channelCount < 1 ) return paInvalidChannelCount; inputDeviceInfo = (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ]; paerror = IsInputChannelCountSupported( inputDeviceInfo, devices[i].channelCount ); if( paerror != paNoError ) return paerror; } return paNoError; } static PaError ValidateOutputChannelCounts( struct PaUtilHostApiRepresentation *hostApi, PaWinMmeDeviceAndChannelCount *devices, unsigned long deviceCount ) { unsigned int i; PaWinMmeDeviceInfo *outputDeviceInfo; PaError paerror; for( i=0; i < deviceCount; ++i ) { if( devices[i].channelCount < 1 ) return paInvalidChannelCount; outputDeviceInfo = (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ]; paerror = IsOutputChannelCountSupported( outputDeviceInfo, devices[i].channelCount ); if( paerror != paNoError ) return paerror; } return paNoError; } /* the following macros are intended to improve the readability of the following code */ #define PA_IS_INPUT_STREAM_( stream ) ( stream ->input.waveHandles ) #define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->output.waveHandles ) #define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->input.waveHandles && stream ->output.waveHandles ) #define PA_IS_HALF_DUPLEX_STREAM_( stream ) ( !(stream ->input.waveHandles && stream ->output.waveHandles) ) static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result; PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; PaWinMmeStream *stream = 0; int bufferProcessorIsInitialized = 0; int streamRepresentationIsInitialized = 0; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; double suggestedInputLatency, suggestedOutputLatency; PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo; PaWinWaveFormatChannelMask inputChannelMask, outputChannelMask; unsigned long framesPerHostInputBuffer; unsigned long hostInputBufferCount; unsigned long framesPerHostOutputBuffer; unsigned long hostOutputBufferCount; unsigned long framesPerBufferProcessorCall; PaWinMmeDeviceAndChannelCount *inputDevices = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */ unsigned long inputDeviceCount = 0; PaWinMmeDeviceAndChannelCount *outputDevices = 0; unsigned long outputDeviceCount = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */ char throttleProcessingThreadOnOverload = 1; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; suggestedInputLatency = inputParameters->suggestedLatency; inputDeviceCount = 1; /* validate input hostApiSpecificStreamInfo */ inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo; result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo, &throttleProcessingThreadOnOverload, &inputDeviceCount ); if( result != paNoError ) return result; inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount ); if( !inputDevices ) return paInsufficientMemory; result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount ); if( result != paNoError ) return result; result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount ); if( result != paNoError ) return result; hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); if( inputDeviceCount != 1 ){ /* always use direct speakers when using multi-device multichannel mode */ inputChannelMask = PAWIN_SPEAKER_DIRECTOUT; } else { if( inputStreamInfo && inputStreamInfo->flags & paWinMmeUseChannelMask ) inputChannelMask = inputStreamInfo->channelMask; else inputChannelMask = PaWin_DefaultChannelMask( inputDevices[0].channelCount ); } } else { inputChannelCount = 0; inputSampleFormat = 0; suggestedInputLatency = 0.; inputStreamInfo = 0; hostInputSampleFormat = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; suggestedOutputLatency = outputParameters->suggestedLatency; outputDeviceCount = 1; /* validate output hostApiSpecificStreamInfo */ outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo; result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo, &throttleProcessingThreadOnOverload, &outputDeviceCount ); if( result != paNoError ) return result; outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount ); if( !outputDevices ) return paInsufficientMemory; result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount ); if( result != paNoError ) return result; result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount ); if( result != paNoError ) return result; hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); if( outputDeviceCount != 1 ){ /* always use direct speakers when using multi-device multichannel mode */ outputChannelMask = PAWIN_SPEAKER_DIRECTOUT; } else { if( outputStreamInfo && outputStreamInfo->flags & paWinMmeUseChannelMask ) outputChannelMask = outputStreamInfo->channelMask; else outputChannelMask = PaWin_DefaultChannelMask( outputDevices[0].channelCount ); } } else { outputChannelCount = 0; outputSampleFormat = 0; outputStreamInfo = 0; hostOutputSampleFormat = 0; suggestedOutputLatency = 0.; } /* IMPLEMENT ME: - alter sampleRate to a close allowable rate if possible / necessary */ /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ result = CalculateBufferSettings( &framesPerHostInputBuffer, &hostInputBufferCount, &framesPerHostOutputBuffer, &hostOutputBufferCount, inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo, outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo, sampleRate, framesPerBuffer ); if( result != paNoError ) goto error; stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) ); if( !stream ) { result = paInsufficientMemory; goto error; } InitializeSingleDirectionHandlesAndBuffers( &stream->input ); InitializeSingleDirectionHandlesAndBuffers( &stream->output ); stream->abortEvent = 0; stream->processingThread = 0; stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload; PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, ( (streamCallback) ? &winMmeHostApi->callbackStreamInterface : &winMmeHostApi->blockingStreamInterface ), streamCallback, userData ); streamRepresentationIsInitialized = 1; PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); if( inputParameters && outputParameters ) /* full duplex */ { if( framesPerHostInputBuffer < framesPerHostOutputBuffer ) { assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */ framesPerBufferProcessorCall = framesPerHostInputBuffer; } else { assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */ framesPerBufferProcessorCall = framesPerHostOutputBuffer; } } else if( inputParameters ) { framesPerBufferProcessorCall = framesPerHostInputBuffer; } else if( outputParameters ) { framesPerBufferProcessorCall = framesPerHostOutputBuffer; } stream->input.framesPerBuffer = framesPerHostInputBuffer; stream->output.framesPerBuffer = framesPerHostOutputBuffer; result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerBufferProcessorCall, paUtilFixedHostBufferSize, streamCallback, userData ); if( result != paNoError ) goto error; bufferProcessorIsInitialized = 1; stream->streamRepresentation.streamInfo.inputLatency = (double)(PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) +(framesPerHostInputBuffer * (hostInputBufferCount-1))) / sampleRate; stream->streamRepresentation.streamInfo.outputLatency = (double)(PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) +(framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate; stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0; /* time to sleep when throttling due to >100% cpu usage. -a quater of a buffer's duration */ stream->throttledSleepMsecs = (unsigned long)(stream->bufferProcessor.framesPerHostBuffer * stream->bufferProcessor.samplePeriod * .25 * 1000); stream->isStopped = 1; stream->isActive = 0; /* for maximum compatibility with multi-device multichannel drivers, we first open all devices, then we prepare all buffers, finally we start all devices ( in StartStream() ). teardown in reverse order. */ if( inputParameters ) { result = InitializeWaveHandles( winMmeHostApi, &stream->input, stream->bufferProcessor.bytesPerHostInputSample, sampleRate, inputDevices, inputDeviceCount, inputChannelMask, 1 /* isInput */ ); if( result != paNoError ) goto error; } if( outputParameters ) { result = InitializeWaveHandles( winMmeHostApi, &stream->output, stream->bufferProcessor.bytesPerHostOutputSample, sampleRate, outputDevices, outputDeviceCount, outputChannelMask, 0 /* isInput */ ); if( result != paNoError ) goto error; } if( inputParameters ) { result = InitializeWaveHeaders( &stream->input, hostInputBufferCount, hostInputSampleFormat, framesPerHostInputBuffer, inputDevices, 1 /* isInput */ ); if( result != paNoError ) goto error; } if( outputParameters ) { result = InitializeWaveHeaders( &stream->output, hostOutputBufferCount, hostOutputSampleFormat, framesPerHostOutputBuffer, outputDevices, 0 /* not isInput */ ); if( result != paNoError ) goto error; stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->output.bufferCount) / sampleRate); } else { stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->input.bufferCount) / sampleRate); } if( streamCallback ) { /* abort event is only needed for callback streams */ result = CreateEventWithPaError( &stream->abortEvent, NULL, TRUE, FALSE, NULL ); if( result != paNoError ) goto error; } *s = (PaStream*)stream; return result; error: if( stream ) { if( stream->abortEvent ) CloseHandle( stream->abortEvent ); TerminateWaveHeaders( &stream->output, 0 /* not isInput */ ); TerminateWaveHeaders( &stream->input, 1 /* isInput */ ); TerminateWaveHandles( &stream->output, 0 /* not isInput */, 1 /* currentlyProcessingAnError */ ); TerminateWaveHandles( &stream->input, 1 /* isInput */, 1 /* currentlyProcessingAnError */ ); if( bufferProcessorIsInitialized ) PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); if( streamRepresentationIsInitialized ) PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); } return result; } /* return non-zero if all current buffers are done */ static int BuffersAreDone( WAVEHDR **waveHeaders, unsigned int deviceCount, int bufferIndex ) { unsigned int i; for( i=0; i < deviceCount; ++i ) { if( !(waveHeaders[i][ bufferIndex ].dwFlags & WHDR_DONE) ) { return 0; } } return 1; } static int CurrentInputBuffersAreDone( PaWinMmeStream *stream ) { return BuffersAreDone( stream->input.waveHeaders, stream->input.deviceCount, stream->input.currentBufferIndex ); } static int CurrentOutputBuffersAreDone( PaWinMmeStream *stream ) { return BuffersAreDone( stream->output.waveHeaders, stream->output.deviceCount, stream->output.currentBufferIndex ); } /* return non-zero if any buffers are queued */ static int NoBuffersAreQueued( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ) { unsigned int i, j; if( handlesAndBuffers->waveHandles ) { for( i=0; i < handlesAndBuffers->bufferCount; ++i ) { for( j=0; j < handlesAndBuffers->deviceCount; ++j ) { if( !( handlesAndBuffers->waveHeaders[ j ][ i ].dwFlags & WHDR_DONE) ) { return 0; } } } } return 1; } #define PA_CIRCULAR_INCREMENT_( current, max )\ ( (((current) + 1) >= (max)) ? (0) : (current+1) ) #define PA_CIRCULAR_DECREMENT_( current, max )\ ( ((current) == 0) ? ((max)-1) : (current-1) ) static signed long GetAvailableFrames( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ) { signed long result = 0; unsigned int i; if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, handlesAndBuffers->currentBufferIndex ) ) { /* we could calculate the following in O(1) if we kept track of the last done buffer */ result = handlesAndBuffers->framesPerBuffer - handlesAndBuffers->framesUsedInCurrentBuffer; i = PA_CIRCULAR_INCREMENT_( handlesAndBuffers->currentBufferIndex, handlesAndBuffers->bufferCount ); while( i != handlesAndBuffers->currentBufferIndex ) { if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, i ) ) { result += handlesAndBuffers->framesPerBuffer; i = PA_CIRCULAR_INCREMENT_( i, handlesAndBuffers->bufferCount ); } else break; } } return result; } static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream ) { PaError result = paNoError; MMRESULT mmresult; unsigned int i; for( i=0; i < stream->input.deviceCount; ++i ) { stream->input.waveHeaders[i][ stream->input.currentBufferIndex ].dwFlags &= ~WHDR_DONE; mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[i], &stream->input.waveHeaders[i][ stream->input.currentBufferIndex ], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); } } stream->input.currentBufferIndex = PA_CIRCULAR_INCREMENT_( stream->input.currentBufferIndex, stream->input.bufferCount ); stream->input.framesUsedInCurrentBuffer = 0; return result; } static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream ) { PaError result = paNoError; MMRESULT mmresult; unsigned int i; for( i=0; i < stream->output.deviceCount; ++i ) { mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[i], &stream->output.waveHeaders[i][ stream->output.currentBufferIndex ], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); } } stream->output.currentBufferIndex = PA_CIRCULAR_INCREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount ); stream->output.framesUsedInCurrentBuffer = 0; return result; } /* requeue all but the most recent input with the driver. Used for catching up after a total input buffer underrun */ static PaError CatchUpInputBuffers( PaWinMmeStream *stream ) { PaError result = paNoError; unsigned int i; for( i=0; i < stream->input.bufferCount - 1; ++i ) { result = AdvanceToNextInputBuffer( stream ); if( result != paNoError ) break; } return result; } /* take the most recent output and duplicate it to all other output buffers and requeue them. Used for catching up after a total output buffer underrun. */ static PaError CatchUpOutputBuffers( PaWinMmeStream *stream ) { PaError result = paNoError; unsigned int i, j; unsigned int previousBufferIndex = PA_CIRCULAR_DECREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount ); for( i=0; i < stream->output.bufferCount - 1; ++i ) { for( j=0; j < stream->output.deviceCount; ++j ) { if( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData != stream->output.waveHeaders[j][ previousBufferIndex ].lpData ) { CopyMemory( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData, stream->output.waveHeaders[j][ previousBufferIndex ].lpData, stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].dwBufferLength ); } } result = AdvanceToNextOutputBuffer( stream ); if( result != paNoError ) break; } return result; } static DWORD WINAPI ProcessingThreadProc( void *pArg ) { PaWinMmeStream *stream = (PaWinMmeStream *)pArg; HANDLE events[3]; int eventCount = 0; DWORD result = paNoError; DWORD waitResult; DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5); int hostBuffersAvailable; signed int hostInputBufferIndex, hostOutputBufferIndex; PaStreamCallbackFlags statusFlags; int callbackResult; int done = 0; unsigned int channel, i; unsigned long framesProcessed; /* prepare event array for call to WaitForMultipleObjects() */ if( stream->input.bufferEvent ) events[eventCount++] = stream->input.bufferEvent; if( stream->output.bufferEvent ) events[eventCount++] = stream->output.bufferEvent; events[eventCount++] = stream->abortEvent; statusFlags = 0; /** @todo support paInputUnderflow, paOutputOverflow and paNeverDropInput */ /* loop until something causes us to stop */ do{ /* wait for MME to signal that a buffer is available, or for the PA abort event to be signaled. When this indicates that one or more buffers are available NoBuffersAreQueued() and Current*BuffersAreDone are used below to poll for additional done buffers. NoBuffersAreQueued() will fail to identify an underrun/overflow if the driver doesn't mark all done buffers prior to signalling the event. Some drivers do this (eg RME Digi96, and others don't eg VIA PC 97 input). This isn't a huge problem, it just means that we won't always be able to detect underflow/overflow. */ waitResult = WaitForMultipleObjects( eventCount, events, FALSE /* wait all = FALSE */, timeout ); if( waitResult == WAIT_FAILED ) { result = paUnanticipatedHostError; /** @todo FIXME/REVIEW: can't return host error info from an asyncronous thread */ done = 1; } else if( waitResult == WAIT_TIMEOUT ) { /* if a timeout is encountered, continue */ } if( stream->abortProcessing ) { /* Pa_AbortStream() has been called, stop processing immediately */ done = 1; } else if( stream->stopProcessing ) { /* Pa_StopStream() has been called or the user callback returned non-zero, processing will continue until all output buffers are marked as done. The stream will stop immediately if it is input-only. */ if( PA_IS_OUTPUT_STREAM_(stream) ) { if( NoBuffersAreQueued( &stream->output ) ) done = 1; /* Will cause thread to return. */ } else { /* input only stream */ done = 1; /* Will cause thread to return. */ } } else { hostBuffersAvailable = 1; /* process all available host buffers */ do { hostInputBufferIndex = -1; hostOutputBufferIndex = -1; if( PA_IS_INPUT_STREAM_(stream) ) { if( CurrentInputBuffersAreDone( stream ) ) { if( NoBuffersAreQueued( &stream->input ) ) { /** @todo if all of the other buffers are also ready then we discard all but the most recent. This is an input buffer overflow. FIXME: these buffers should be passed to the callback in a paNeverDropInput stream. note that it is also possible for an input overflow to happen while the callback is processing a buffer. that is handled further down. */ result = CatchUpInputBuffers( stream ); if( result != paNoError ) done = 1; statusFlags |= paInputOverflow; } hostInputBufferIndex = stream->input.currentBufferIndex; } } if( PA_IS_OUTPUT_STREAM_(stream) ) { if( CurrentOutputBuffersAreDone( stream ) ) { /* ok, we have an output buffer */ if( NoBuffersAreQueued( &stream->output ) ) { /* if all of the other buffers are also ready, catch up by copying the most recently generated buffer into all but one of the output buffers. note that this catch up code only handles the case where all buffers have been played out due to this thread not having woken up at all. a more common case occurs when this thread is woken up, processes one buffer, but takes too long, and as a result all the other buffers have become un-queued. that case is handled further down. */ result = CatchUpOutputBuffers( stream ); if( result != paNoError ) done = 1; statusFlags |= paOutputUnderflow; } hostOutputBufferIndex = stream->output.currentBufferIndex; } } if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) || (PA_IS_HALF_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) ) { PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */ if( PA_IS_OUTPUT_STREAM_(stream) ) { /* set timeInfo.currentTime and calculate timeInfo.outputBufferDacTime from the current wave out position */ MMTIME mmtime; double timeBeforeGetPosition, timeAfterGetPosition; double time; long framesInBufferRing; long writePosition; long playbackPosition; HWAVEOUT firstWaveOutDevice = ((HWAVEOUT*)stream->output.waveHandles)[0]; mmtime.wType = TIME_SAMPLES; timeBeforeGetPosition = PaUtil_GetTime(); waveOutGetPosition( firstWaveOutDevice, &mmtime, sizeof(MMTIME) ); timeAfterGetPosition = PaUtil_GetTime(); timeInfo.currentTime = timeAfterGetPosition; /* approximate time at which wave out position was measured as half way between timeBeforeGetPosition and timeAfterGetPosition */ time = timeBeforeGetPosition + (timeAfterGetPosition - timeBeforeGetPosition) * .5; framesInBufferRing = stream->output.bufferCount * stream->bufferProcessor.framesPerHostBuffer; playbackPosition = mmtime.u.sample % framesInBufferRing; writePosition = stream->output.currentBufferIndex * stream->bufferProcessor.framesPerHostBuffer + stream->output.framesUsedInCurrentBuffer; if( playbackPosition >= writePosition ){ timeInfo.outputBufferDacTime = time + ((double)( writePosition + (framesInBufferRing - playbackPosition) ) * stream->bufferProcessor.samplePeriod ); }else{ timeInfo.outputBufferDacTime = time + ((double)( writePosition - playbackPosition ) * stream->bufferProcessor.samplePeriod ); } } PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, statusFlags ); /* reset status flags once they have been passed to the buffer processor */ statusFlags = 0; if( PA_IS_INPUT_STREAM_(stream) ) { PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); channel = 0; for( i=0; iinput.deviceCount; ++i ) { /* we have stored the number of channels in the buffer in dwUser */ int channelCount = (int)stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser; PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel, stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData + stream->input.framesUsedInCurrentBuffer * channelCount * stream->bufferProcessor.bytesPerHostInputSample, channelCount ); channel += channelCount; } } if( PA_IS_OUTPUT_STREAM_(stream) ) { PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); channel = 0; for( i=0; ioutput.deviceCount; ++i ) { /* we have stored the number of channels in the buffer in dwUser */ int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser; PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData + stream->output.framesUsedInCurrentBuffer * channelCount * stream->bufferProcessor.bytesPerHostOutputSample, channelCount ); channel += channelCount; } } callbackResult = paContinue; framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); stream->input.framesUsedInCurrentBuffer += framesProcessed; stream->output.framesUsedInCurrentBuffer += framesProcessed; PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); if( callbackResult == paContinue ) { /* nothing special to do */ } else if( callbackResult == paAbort ) { stream->abortProcessing = 1; done = 1; /** @todo FIXME: should probably reset the output device immediately once the callback returns paAbort */ result = paNoError; } else { /* User callback has asked us to stop with paComplete or other non-zero value */ stream->stopProcessing = 1; /* stop once currently queued audio has finished */ result = paNoError; } if( PA_IS_INPUT_STREAM_(stream) && stream->stopProcessing == 0 && stream->abortProcessing == 0 && stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer ) { if( NoBuffersAreQueued( &stream->input ) ) { /** @todo need to handle PaNeverDropInput here where necessary */ result = CatchUpInputBuffers( stream ); if( result != paNoError ) done = 1; statusFlags |= paInputOverflow; } result = AdvanceToNextInputBuffer( stream ); if( result != paNoError ) done = 1; } if( PA_IS_OUTPUT_STREAM_(stream) && !stream->abortProcessing ) { if( stream->stopProcessing && stream->output.framesUsedInCurrentBuffer < stream->output.framesPerBuffer ) { /* zero remaining samples in output output buffer and flush */ stream->output.framesUsedInCurrentBuffer += PaUtil_ZeroOutput( &stream->bufferProcessor, stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); /* we send the entire buffer to the output devices, but we could just send a partial buffer, rather than zeroing the unused samples. */ } if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer ) { /* check for underflow before enquing the just-generated buffer, but recover from underflow after enquing it. This ensures that the most recent audio segment is repeated */ int outputUnderflow = NoBuffersAreQueued( &stream->output ); result = AdvanceToNextOutputBuffer( stream ); if( result != paNoError ) done = 1; if( outputUnderflow && !done && !stream->stopProcessing ) { /* Recover from underflow in the case where the underflow occured while processing the buffer we just finished */ result = CatchUpOutputBuffers( stream ); if( result != paNoError ) done = 1; statusFlags |= paOutputUnderflow; } } } if( stream->throttleProcessingThreadOnOverload != 0 ) { if( stream->stopProcessing || stream->abortProcessing ) { if( stream->processingThreadPriority != stream->highThreadPriority ) { SetThreadPriority( stream->processingThread, stream->highThreadPriority ); stream->processingThreadPriority = stream->highThreadPriority; } } else if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. ) { if( stream->processingThreadPriority != stream->throttledThreadPriority ) { SetThreadPriority( stream->processingThread, stream->throttledThreadPriority ); stream->processingThreadPriority = stream->throttledThreadPriority; } /* sleep to give other processes a go */ Sleep( stream->throttledSleepMsecs ); } else { if( stream->processingThreadPriority != stream->highThreadPriority ) { SetThreadPriority( stream->processingThread, stream->highThreadPriority ); stream->processingThreadPriority = stream->highThreadPriority; } } } } else { hostBuffersAvailable = 0; } } while( hostBuffersAvailable && stream->stopProcessing == 0 && stream->abortProcessing == 0 && !done ); } } while( !done ); stream->isActive = 0; if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); return result; } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result; PaWinMmeStream *stream = (PaWinMmeStream*)s; result = CloseHandleWithPaError( stream->abortEvent ); if( result != paNoError ) goto error; TerminateWaveHeaders( &stream->output, 0 /* not isInput */ ); TerminateWaveHeaders( &stream->input, 1 /* isInput */ ); TerminateWaveHandles( &stream->output, 0 /* not isInput */, 0 /* not currentlyProcessingAnError */ ); TerminateWaveHandles( &stream->input, 1 /* isInput */, 0 /* not currentlyProcessingAnError */ ); PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); error: /** @todo REVIEW: what is the best way to clean up a stream if an error is detected? */ return result; } static PaError StartStream( PaStream *s ) { PaError result; PaWinMmeStream *stream = (PaWinMmeStream*)s; MMRESULT mmresult; unsigned int i, j; int callbackResult; unsigned int channel; unsigned long framesProcessed; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); if( PA_IS_INPUT_STREAM_(stream) ) { for( i=0; iinput.bufferCount; ++i ) { for( j=0; jinput.deviceCount; ++j ) { stream->input.waveHeaders[j][i].dwFlags &= ~WHDR_DONE; mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[j], &stream->input.waveHeaders[j][i], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); goto error; } } } stream->input.currentBufferIndex = 0; stream->input.framesUsedInCurrentBuffer = 0; } if( PA_IS_OUTPUT_STREAM_(stream) ) { for( i=0; ioutput.deviceCount; ++i ) { if( (mmresult = waveOutPause( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); goto error; } } for( i=0; ioutput.bufferCount; ++i ) { if( stream->primeStreamUsingCallback ) { stream->output.framesUsedInCurrentBuffer = 0; do{ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, paPrimingOutput | ((stream->input.bufferCount > 0 ) ? paInputUnderflow : 0)); if( stream->input.bufferCount > 0 ) PaUtil_SetNoInput( &stream->bufferProcessor ); PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); channel = 0; for( j=0; joutput.deviceCount; ++j ) { /* we have stored the number of channels in the buffer in dwUser */ int channelCount = (int)stream->output.waveHeaders[j][i].dwUser; PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, stream->output.waveHeaders[j][i].lpData + stream->output.framesUsedInCurrentBuffer * channelCount * stream->bufferProcessor.bytesPerHostOutputSample, channelCount ); /* we have stored the number of channels in the buffer in dwUser */ channel += channelCount; } callbackResult = paContinue; framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); stream->output.framesUsedInCurrentBuffer += framesProcessed; if( callbackResult != paContinue ) { /** @todo fix this, what do we do if callback result is non-zero during stream priming? for complete: play out primed waveHeaders as usual for abort: clean up immediately. */ } }while( stream->output.framesUsedInCurrentBuffer != stream->output.framesPerBuffer ); } else { for( j=0; joutput.deviceCount; ++j ) { ZeroMemory( stream->output.waveHeaders[j][i].lpData, stream->output.waveHeaders[j][i].dwBufferLength ); } } /* we queue all channels of a single buffer frame (accross all devices, because some multidevice multichannel drivers work better this way */ for( j=0; joutput.deviceCount; ++j ) { mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[j], &stream->output.waveHeaders[j][i], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); goto error; } } } stream->output.currentBufferIndex = 0; stream->output.framesUsedInCurrentBuffer = 0; } stream->isStopped = 0; stream->isActive = 1; stream->stopProcessing = 0; stream->abortProcessing = 0; result = ResetEventWithPaError( stream->input.bufferEvent ); if( result != paNoError ) goto error; result = ResetEventWithPaError( stream->output.bufferEvent ); if( result != paNoError ) goto error; if( stream->streamRepresentation.streamCallback ) { /* callback stream */ result = ResetEventWithPaError( stream->abortEvent ); if( result != paNoError ) goto error; /* Create thread that waits for audio buffers to be ready for processing. */ stream->processingThread = CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ); if( !stream->processingThread ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); goto error; } /** @todo could have mme specific stream parameters to allow the user to set the callback thread priorities */ stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL; stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL; if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); goto error; } stream->processingThreadPriority = stream->highThreadPriority; } else { /* blocking read/write stream */ } if( PA_IS_INPUT_STREAM_(stream) ) { for( i=0; i < stream->input.deviceCount; ++i ) { mmresult = waveInStart( ((HWAVEIN*)stream->input.waveHandles)[i] ); PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult)); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); goto error; } } } if( PA_IS_OUTPUT_STREAM_(stream) ) { for( i=0; i < stream->output.deviceCount; ++i ) { if( (mmresult = waveOutRestart( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); goto error; } } } return result; error: /** @todo FIXME: implement recovery as best we can This should involve rolling back to a state as-if this function had never been called */ return result; } static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaWinMmeStream *stream = (PaWinMmeStream*)s; int timeout; DWORD waitResult; MMRESULT mmresult; signed int hostOutputBufferIndex; unsigned int channel, waitCount, i; /** @todo REVIEW: the error checking in this function needs review. the basic idea is to return from this function in a known state - for example there is no point avoiding calling waveInReset just because the thread times out. */ if( stream->processingThread ) { /* callback stream */ /* Tell processing thread to stop generating more data and to let current data play out. */ stream->stopProcessing = 1; /* Calculate timeOut longer than longest time it could take to return all buffers. */ timeout = (int)(stream->allBuffersDurationMs * 1.5); if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) timeout = PA_MME_MIN_TIMEOUT_MSEC_; PA_DEBUG(("WinMME StopStream: waiting for background thread.\n")); waitResult = WaitForSingleObject( stream->processingThread, timeout ); if( waitResult == WAIT_TIMEOUT ) { /* try to abort */ stream->abortProcessing = 1; SetEvent( stream->abortEvent ); waitResult = WaitForSingleObject( stream->processingThread, timeout ); if( waitResult == WAIT_TIMEOUT ) { PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n")); result = paTimedOut; } } CloseHandle( stream->processingThread ); stream->processingThread = NULL; } else { /* blocking read / write stream */ if( PA_IS_OUTPUT_STREAM_(stream) ) { if( stream->output.framesUsedInCurrentBuffer > 0 ) { /* there are still unqueued frames in the current buffer, so flush them */ hostOutputBufferIndex = stream->output.currentBufferIndex; PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); channel = 0; for( i=0; ioutput.deviceCount; ++i ) { /* we have stored the number of channels in the buffer in dwUser */ int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser; PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData + stream->output.framesUsedInCurrentBuffer * channelCount * stream->bufferProcessor.bytesPerHostOutputSample, channelCount ); channel += channelCount; } PaUtil_ZeroOutput( &stream->bufferProcessor, stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); /* we send the entire buffer to the output devices, but we could just send a partial buffer, rather than zeroing the unused samples. */ AdvanceToNextOutputBuffer( stream ); } timeout = (stream->allBuffersDurationMs / stream->output.bufferCount) + 1; if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) timeout = PA_MME_MIN_TIMEOUT_MSEC_; waitCount = 0; while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount ) { /* wait for MME to signal that a buffer is available */ waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout ); if( waitResult == WAIT_FAILED ) { break; } else if( waitResult == WAIT_TIMEOUT ) { /* keep waiting */ } ++waitCount; } } } if( PA_IS_OUTPUT_STREAM_(stream) ) { for( i =0; i < stream->output.deviceCount; ++i ) { mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); } } } if( PA_IS_INPUT_STREAM_(stream) ) { for( i=0; i < stream->input.deviceCount; ++i ) { mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] ); if( mmresult != MMSYSERR_NOERROR ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); } } } stream->isStopped = 1; stream->isActive = 0; return result; } static PaError AbortStream( PaStream *s ) { PaError result = paNoError; PaWinMmeStream *stream = (PaWinMmeStream*)s; int timeout; DWORD waitResult; MMRESULT mmresult; unsigned int i; /** @todo REVIEW: the error checking in this function needs review. the basic idea is to return from this function in a known state - for example there is no point avoiding calling waveInReset just because the thread times out. */ if( stream->processingThread ) { /* callback stream */ /* Tell processing thread to abort immediately */ stream->abortProcessing = 1; SetEvent( stream->abortEvent ); } if( PA_IS_OUTPUT_STREAM_(stream) ) { for( i =0; i < stream->output.deviceCount; ++i ) { mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] ); if( mmresult != MMSYSERR_NOERROR ) { PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); return paUnanticipatedHostError; } } } if( PA_IS_INPUT_STREAM_(stream) ) { for( i=0; i < stream->input.deviceCount; ++i ) { mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] ); if( mmresult != MMSYSERR_NOERROR ) { PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); return paUnanticipatedHostError; } } } if( stream->processingThread ) { /* callback stream */ PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n")); /* Calculate timeOut longer than longest time it could take to return all buffers. */ timeout = (int)(stream->allBuffersDurationMs * 1.5); if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) timeout = PA_MME_MIN_TIMEOUT_MSEC_; waitResult = WaitForSingleObject( stream->processingThread, timeout ); if( waitResult == WAIT_TIMEOUT ) { PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n")); return paTimedOut; } CloseHandle( stream->processingThread ); stream->processingThread = NULL; } stream->isStopped = 1; stream->isActive = 0; return result; } static PaError IsStreamStopped( PaStream *s ) { PaWinMmeStream *stream = (PaWinMmeStream*)s; return stream->isStopped; } static PaError IsStreamActive( PaStream *s ) { PaWinMmeStream *stream = (PaWinMmeStream*)s; return stream->isActive; } static PaTime GetStreamTime( PaStream *s ) { (void) s; /* unused parameter */ return PaUtil_GetTime(); } static double GetStreamCpuLoad( PaStream* s ) { PaWinMmeStream *stream = (PaWinMmeStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaError result = paNoError; PaWinMmeStream *stream = (PaWinMmeStream*)s; void *userBuffer; unsigned long framesRead = 0; unsigned long framesProcessed; signed int hostInputBufferIndex; DWORD waitResult; DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5); unsigned int channel, i; if( PA_IS_INPUT_STREAM_(stream) ) { /* make a local copy of the user buffer pointer(s). this is necessary because PaUtil_CopyInput() advances these pointers every time it is called. */ if( stream->bufferProcessor.userInputIsInterleaved ) { userBuffer = buffer; } else { userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.inputChannelCount ); if( !userBuffer ) return paInsufficientMemory; for( i = 0; ibufferProcessor.inputChannelCount; ++i ) ((void**)userBuffer)[i] = ((void**)buffer)[i]; } do{ if( CurrentInputBuffersAreDone( stream ) ) { if( NoBuffersAreQueued( &stream->input ) ) { /** @todo REVIEW: consider what to do if the input overflows. do we requeue all of the buffers? should we be running a thread to make sure they are always queued? */ result = paInputOverflowed; } hostInputBufferIndex = stream->input.currentBufferIndex; PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->input.framesPerBuffer - stream->input.framesUsedInCurrentBuffer ); channel = 0; for( i=0; iinput.deviceCount; ++i ) { /* we have stored the number of channels in the buffer in dwUser */ int channelCount = (int)stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser; PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel, stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData + stream->input.framesUsedInCurrentBuffer * channelCount * stream->bufferProcessor.bytesPerHostInputSample, channelCount ); channel += channelCount; } framesProcessed = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, frames - framesRead ); stream->input.framesUsedInCurrentBuffer += framesProcessed; if( stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer ) { result = AdvanceToNextInputBuffer( stream ); if( result != paNoError ) break; } framesRead += framesProcessed; }else{ /* wait for MME to signal that a buffer is available */ waitResult = WaitForSingleObject( stream->input.bufferEvent, timeout ); if( waitResult == WAIT_FAILED ) { result = paUnanticipatedHostError; break; } else if( waitResult == WAIT_TIMEOUT ) { /* if a timeout is encountered, continue, perhaps we should give up eventually */ } } }while( framesRead < frames ); } else { result = paCanNotReadFromAnOutputOnlyStream; } return result; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaError result = paNoError; PaWinMmeStream *stream = (PaWinMmeStream*)s; const void *userBuffer; unsigned long framesWritten = 0; unsigned long framesProcessed; signed int hostOutputBufferIndex; DWORD waitResult; DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5); unsigned int channel, i; if( PA_IS_OUTPUT_STREAM_(stream) ) { /* make a local copy of the user buffer pointer(s). this is necessary because PaUtil_CopyOutput() advances these pointers every time it is called. */ if( stream->bufferProcessor.userOutputIsInterleaved ) { userBuffer = buffer; } else { userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.outputChannelCount ); if( !userBuffer ) return paInsufficientMemory; for( i = 0; ibufferProcessor.outputChannelCount; ++i ) ((const void**)userBuffer)[i] = ((const void**)buffer)[i]; } do{ if( CurrentOutputBuffersAreDone( stream ) ) { if( NoBuffersAreQueued( &stream->output ) ) { /** @todo REVIEW: consider what to do if the output underflows. do we requeue all the existing buffers with zeros? should we run a separate thread to keep the buffers enqueued at all times? */ result = paOutputUnderflowed; } hostOutputBufferIndex = stream->output.currentBufferIndex; PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); channel = 0; for( i=0; ioutput.deviceCount; ++i ) { /* we have stored the number of channels in the buffer in dwUser */ int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser; PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData + stream->output.framesUsedInCurrentBuffer * channelCount * stream->bufferProcessor.bytesPerHostOutputSample, channelCount ); channel += channelCount; } framesProcessed = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames - framesWritten ); stream->output.framesUsedInCurrentBuffer += framesProcessed; if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer ) { result = AdvanceToNextOutputBuffer( stream ); if( result != paNoError ) break; } framesWritten += framesProcessed; } else { /* wait for MME to signal that a buffer is available */ waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout ); if( waitResult == WAIT_FAILED ) { result = paUnanticipatedHostError; break; } else if( waitResult == WAIT_TIMEOUT ) { /* if a timeout is encountered, continue, perhaps we should give up eventually */ } } }while( framesWritten < frames ); } else { result = paCanNotWriteToAnInputOnlyStream; } return result; } static signed long GetStreamReadAvailable( PaStream* s ) { PaWinMmeStream *stream = (PaWinMmeStream*)s; if( PA_IS_INPUT_STREAM_(stream) ) return GetAvailableFrames( &stream->input ); else return paCanNotReadFromAnOutputOnlyStream; } static signed long GetStreamWriteAvailable( PaStream* s ) { PaWinMmeStream *stream = (PaWinMmeStream*)s; if( PA_IS_OUTPUT_STREAM_(stream) ) return GetAvailableFrames( &stream->output ); else return paCanNotWriteToAnInputOnlyStream; } /* NOTE: the following functions are MME-stream specific, and are called directly by client code. We need to check for many more error conditions here because we don't have the benefit of pa_front.c's parameter checking. */ static PaError GetWinMMEStreamPointer( PaWinMmeStream **stream, PaStream *s ) { PaError result; PaUtilHostApiRepresentation *hostApi; PaWinMmeHostApiRepresentation *winMmeHostApi; result = PaUtil_ValidateStreamPointer( s ); if( result != paNoError ) return result; result = PaUtil_GetHostApiRepresentation( &hostApi, paMME ); if( result != paNoError ) return result; winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; /* note, the following would be easier if there was a generic way of testing that a stream belongs to a specific host API */ if( PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->callbackStreamInterface || PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->blockingStreamInterface ) { /* s is a WinMME stream */ *stream = (PaWinMmeStream *)s; return paNoError; } else { return paIncompatibleStreamHostApi; } } int PaWinMME_GetStreamInputHandleCount( PaStream* s ) { PaWinMmeStream *stream; PaError result = GetWinMMEStreamPointer( &stream, s ); if( result == paNoError ) return (PA_IS_INPUT_STREAM_(stream)) ? stream->input.deviceCount : 0; else return result; } HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* s, int handleIndex ) { PaWinMmeStream *stream; PaError result = GetWinMMEStreamPointer( &stream, s ); if( result == paNoError && PA_IS_INPUT_STREAM_(stream) && handleIndex >= 0 && (unsigned int)handleIndex < stream->input.deviceCount ) return ((HWAVEIN*)stream->input.waveHandles)[handleIndex]; else return 0; } int PaWinMME_GetStreamOutputHandleCount( PaStream* s) { PaWinMmeStream *stream; PaError result = GetWinMMEStreamPointer( &stream, s ); if( result == paNoError ) return (PA_IS_OUTPUT_STREAM_(stream)) ? stream->output.deviceCount : 0; else return result; } HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* s, int handleIndex ) { PaWinMmeStream *stream; PaError result = GetWinMMEStreamPointer( &stream, s ); if( result == paNoError && PA_IS_OUTPUT_STREAM_(stream) && handleIndex >= 0 && (unsigned int)handleIndex < stream->output.deviceCount ) return ((HWAVEOUT*)stream->output.waveHandles)[handleIndex]; else return 0; } nyquist-3.05/portaudio/src/hostapi/wdmks/0002755000175000000620000000000011537433131017557 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/wdmks/pa_win_wdmks.c0000644000175000000620000032053411466723256022425 0ustar stevestaff/* * $Id: pa_win_wdmks.c,v 1.1 2010/11/04 21:04:37 rbd Exp $ * PortAudio Windows WDM-KS interface * * Author: Andrew Baldwin * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src @brief Portaudio WDM-KS host API. @note This is the implementation of the Portaudio host API using the Windows WDM/Kernel Streaming API in order to enable very low latency playback and recording on all modern Windows platforms (e.g. 2K, XP) Note: This API accesses the device drivers below the usual KMIXER component which is normally used to enable multi-client mixing and format conversion. That means that it will lock out all other users of a device for the duration of active stream using those devices */ #include /* Debugging/tracing support */ #define PA_LOGE_ #define PA_LOGL_ #ifdef __GNUC__ #include #define _WIN32_WINNT 0x0501 #define WINVER 0x0501 #endif #include /* strlen() */ #include #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "portaudio.h" #include "pa_debugprint.h" #include #include #ifdef __GNUC__ #undef PA_LOGE_ #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__)) #undef PA_LOGL_ #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__)) /* These defines are set in order to allow the WIndows DirectX * headers to compile with a GCC compiler such as MinGW * NOTE: The headers may generate a few warning in GCC, but * they should compile */ #define _INC_MMSYSTEM #define _INC_MMREG #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ #define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid) #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n ) #if !defined( DEFINE_WAVEFORMATEX_GUID ) #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 #endif #define WAVE_FORMAT_ADPCM 0x0002 #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #define WAVE_FORMAT_ALAW 0x0006 #define WAVE_FORMAT_MULAW 0x0007 #define WAVE_FORMAT_MPEG 0x0050 #define WAVE_FORMAT_DRM 0x0009 #define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data) #endif #ifdef _MSC_VER #define DYNAMIC_GUID(data) {data} #define _INC_MMREG #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ #undef DEFINE_GUID #define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data} #define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data) #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n) #if !defined( DEFINE_WAVEFORMATEX_GUID ) #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 #endif #define WAVE_FORMAT_ADPCM 0x0002 #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #define WAVE_FORMAT_ALAW 0x0006 #define WAVE_FORMAT_MULAW 0x0007 #define WAVE_FORMAT_MPEG 0x0050 #define WAVE_FORMAT_DRM 0x0009 #endif #include #include #include #include #include /* These next definitions allow the use of the KSUSER DLL */ typedef KSDDKAPI DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE); extern HMODULE DllKsUser; extern KSCREATEPIN* FunctionKsCreatePin; /* Forward definition to break circular type reference between pin and filter */ struct __PaWinWdmFilter; typedef struct __PaWinWdmFilter PaWinWdmFilter; /* The Pin structure * A pin is an input or output node, e.g. for audio flow */ typedef struct __PaWinWdmPin { HANDLE handle; PaWinWdmFilter* parentFilter; unsigned long pinId; KSPIN_CONNECT* pinConnect; unsigned long pinConnectSize; KSDATAFORMAT_WAVEFORMATEX* ksDataFormatWfx; KSPIN_COMMUNICATION communication; KSDATARANGE* dataRanges; KSMULTIPLE_ITEM* dataRangesItem; KSPIN_DATAFLOW dataFlow; KSPIN_CINSTANCES instances; unsigned long frameSize; int maxChannels; unsigned long formats; int bestSampleRate; } PaWinWdmPin; /* The Filter structure * A filter has a number of pins and a "friendly name" */ struct __PaWinWdmFilter { HANDLE handle; int pinCount; PaWinWdmPin** pins; TCHAR filterName[MAX_PATH]; TCHAR friendlyName[MAX_PATH]; int maxInputChannels; int maxOutputChannels; unsigned long formats; int usageCount; int bestSampleRate; }; /* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct __PaWinWdmHostApiRepresentation { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup* allocations; PaWinWdmFilter** filters; int filterCount; } PaWinWdmHostApiRepresentation; typedef struct __PaWinWdmDeviceInfo { PaDeviceInfo inheritedDeviceInfo; PaWinWdmFilter* filter; } PaWinWdmDeviceInfo; typedef struct __DATAPACKET { KSSTREAM_HEADER Header; OVERLAPPED Signal; } DATAPACKET; /* PaWinWdmStream - a stream data structure specifically for this implementation */ typedef struct __PaWinWdmStream { PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaWinWdmPin* recordingPin; PaWinWdmPin* playbackPin; char* hostBuffer; unsigned long framesPerHostIBuffer; unsigned long framesPerHostOBuffer; int bytesPerInputFrame; int bytesPerOutputFrame; int streamStarted; int streamActive; int streamStop; int streamAbort; int oldProcessPriority; HANDLE streamThread; HANDLE events[5]; /* 2 play + 2 record packets + abort events */ DATAPACKET packets[4]; /* 2 play + 2 record */ PaStreamFlags streamFlags; /* These values handle the case where the user wants to use fewer * channels than the device has */ int userInputChannels; int deviceInputChannels; int userOutputChannels; int deviceOutputChannels; int inputSampleSize; int outputSampleSize; } PaWinWdmStream; #include HMODULE DllKsUser = NULL; KSCREATEPIN* FunctionKsCreatePin = NULL; /* prototypes for functions declared in this file */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ /* Low level I/O functions */ static PaError WdmSyncIoctl(HANDLE handle, unsigned long ioctlNumber, void* inBuffer, unsigned long inBufferCount, void* outBuffer, unsigned long outBufferCount, unsigned long* bytesReturned); static PaError WdmGetPropertySimple(HANDLE handle, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount, void* instance, unsigned long instanceCount); static PaError WdmSetPropertySimple(HANDLE handle, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount, void* instance, unsigned long instanceCount); static PaError WdmGetPinPropertySimple(HANDLE handle, unsigned long pinId, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount); static PaError WdmGetPinPropertyMulti(HANDLE handle, unsigned long pinId, const GUID* const guidPropertySet, unsigned long property, KSMULTIPLE_ITEM** ksMultipleItem); /** Pin management functions */ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error); static void PinFree(PaWinWdmPin* pin); static void PinClose(PaWinWdmPin* pin); static PaError PinInstantiate(PaWinWdmPin* pin); /*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */ static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state); static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format); static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format); /* Filter management functions */ static PaWinWdmFilter* FilterNew( TCHAR* filterName, TCHAR* friendlyName, PaError* error); static void FilterFree(PaWinWdmFilter* filter); static PaWinWdmPin* FilterCreateRenderPin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error); static PaWinWdmPin* FilterFindViableRenderPin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error); static PaError FilterCanCreateRenderPin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex); static PaWinWdmPin* FilterCreateCapturePin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error); static PaWinWdmPin* FilterFindViableCapturePin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error); static PaError FilterCanCreateCapturePin( PaWinWdmFilter* filter, const WAVEFORMATEX* pwfx); static PaError FilterUse( PaWinWdmFilter* filter); static void FilterRelease( PaWinWdmFilter* filter); /* Interface functions */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* Utility functions */ static unsigned long GetWfexSize(const WAVEFORMATEX* wfex); static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi); static BOOL PinWrite(HANDLE h, DATAPACKET* p); static BOOL PinRead(HANDLE h, DATAPACKET* p); static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples); static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples); static DWORD WINAPI ProcessingThread(LPVOID pParam); /* Function bodies */ static unsigned long GetWfexSize(const WAVEFORMATEX* wfex) { if( wfex->wFormatTag == WAVE_FORMAT_PCM ) { return sizeof( WAVEFORMATEX ); } else { return (sizeof( WAVEFORMATEX ) + wfex->cbSize); } } /* Low level pin/filter access functions */ static PaError WdmSyncIoctl( HANDLE handle, unsigned long ioctlNumber, void* inBuffer, unsigned long inBufferCount, void* outBuffer, unsigned long outBufferCount, unsigned long* bytesReturned) { PaError result = paNoError; OVERLAPPED overlapped; int boolResult; unsigned long dummyBytesReturned; unsigned long error; if( !bytesReturned ) { /* User a dummy as the caller hasn't supplied one */ bytesReturned = &dummyBytesReturned; } FillMemory((void *)&overlapped,sizeof(overlapped),0); overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if( !overlapped.hEvent ) { result = paInsufficientMemory; goto error; } overlapped.hEvent = (HANDLE)((DWORD_PTR)overlapped.hEvent | 0x1); boolResult = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, &overlapped); if( !boolResult ) { error = GetLastError(); if( error == ERROR_IO_PENDING ) { error = WaitForSingleObject(overlapped.hEvent,INFINITE); if( error != WAIT_OBJECT_0 ) { result = paUnanticipatedHostError; goto error; } } else if((( error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) && ( ioctlNumber == IOCTL_KS_PROPERTY ) && ( outBufferCount == 0 )) { boolResult = TRUE; } else { result = paUnanticipatedHostError; } } if( !boolResult ) *bytesReturned = 0; error: if( overlapped.hEvent ) { CloseHandle( overlapped.hEvent ); } return result; } static PaError WdmGetPropertySimple(HANDLE handle, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount, void* instance, unsigned long instanceCount) { PaError result; KSPROPERTY* ksProperty; unsigned long propertyCount; propertyCount = sizeof(KSPROPERTY) + instanceCount; ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount ); if( !ksProperty ) { return paInsufficientMemory; } FillMemory((void*)ksProperty,sizeof(ksProperty),0); ksProperty->Set = *guidPropertySet; ksProperty->Id = property; ksProperty->Flags = KSPROPERTY_TYPE_GET; if( instance ) { memcpy( (void*)(((char*)ksProperty)+sizeof(KSPROPERTY)), instance, instanceCount ); } result = WdmSyncIoctl( handle, IOCTL_KS_PROPERTY, ksProperty, propertyCount, value, valueCount, NULL); PaUtil_FreeMemory( ksProperty ); return result; } static PaError WdmSetPropertySimple( HANDLE handle, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount, void* instance, unsigned long instanceCount) { PaError result; KSPROPERTY* ksProperty; unsigned long propertyCount = 0; propertyCount = sizeof(KSPROPERTY) + instanceCount; ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount ); if( !ksProperty ) { return paInsufficientMemory; } ksProperty->Set = *guidPropertySet; ksProperty->Id = property; ksProperty->Flags = KSPROPERTY_TYPE_SET; if( instance ) { memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount); } result = WdmSyncIoctl( handle, IOCTL_KS_PROPERTY, ksProperty, propertyCount, value, valueCount, NULL); PaUtil_FreeMemory( ksProperty ); return result; } static PaError WdmGetPinPropertySimple( HANDLE handle, unsigned long pinId, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount) { PaError result; KSP_PIN ksPProp; ksPProp.Property.Set = *guidPropertySet; ksPProp.Property.Id = property; ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; ksPProp.PinId = pinId; ksPProp.Reserved = 0; result = WdmSyncIoctl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), value, valueCount, NULL); return result; } static PaError WdmGetPinPropertyMulti( HANDLE handle, unsigned long pinId, const GUID* const guidPropertySet, unsigned long property, KSMULTIPLE_ITEM** ksMultipleItem) { PaError result; unsigned long multipleItemSize = 0; KSP_PIN ksPProp; ksPProp.Property.Set = *guidPropertySet; ksPProp.Property.Id = property; ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; ksPProp.PinId = pinId; ksPProp.Reserved = 0; result = WdmSyncIoctl( handle, IOCTL_KS_PROPERTY, &ksPProp.Property, sizeof(KSP_PIN), NULL, 0, &multipleItemSize); if( result != paNoError ) { return result; } *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); if( !*ksMultipleItem ) { return paInsufficientMemory; } result = WdmSyncIoctl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), (void*)*ksMultipleItem, multipleItemSize, NULL); if( result != paNoError ) { PaUtil_FreeMemory( ksMultipleItem ); } return result; } /* Create a new pin object belonging to a filter The pin object holds all the configuration information about the pin before it is opened, and then the handle of the pin after is opened */ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error) { PaWinWdmPin* pin; PaError result; unsigned long i; KSMULTIPLE_ITEM* item = NULL; KSIDENTIFIER* identifier; KSDATARANGE* dataRange; PA_LOGE_; PA_DEBUG(("Creating pin %d:\n",pinId)); /* Allocate the new PIN object */ pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) ); if( !pin ) { result = paInsufficientMemory; goto error; } /* Zero the pin object */ /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */ pin->parentFilter = parentFilter; pin->pinId = pinId; /* Allocate a connect structure */ pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX); pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize ); if( !pin->pinConnect ) { result = paInsufficientMemory; goto error; } /* Configure the connect structure with default values */ pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard; pin->pinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING; pin->pinConnect->Interface.Flags = 0; pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard; pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE; pin->pinConnect->Medium.Flags = 0; pin->pinConnect->PinId = pinId; pin->pinConnect->PinToHandle = NULL; pin->pinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL; pin->pinConnect->Priority.PrioritySubClass = 1; pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1); pin->ksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX); pin->ksDataFormatWfx->DataFormat.Flags = 0; pin->ksDataFormatWfx->DataFormat.Reserved = 0; pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; pin->ksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; pin->ksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; pin->frameSize = 0; /* Unknown until we instantiate pin */ /* Get the COMMUNICATION property */ result = WdmGetPinPropertySimple( parentFilter->handle, pinId, &KSPROPSETID_Pin, KSPROPERTY_PIN_COMMUNICATION, &pin->communication, sizeof(KSPIN_COMMUNICATION)); if( result != paNoError ) goto error; if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/ (pin->communication != KSPIN_COMMUNICATION_SINK) && (pin->communication != KSPIN_COMMUNICATION_BOTH) ) { PA_DEBUG(("Not source/sink\n")); result = paInvalidDevice; goto error; } /* Get dataflow information */ result = WdmGetPinPropertySimple( parentFilter->handle, pinId, &KSPROPSETID_Pin, KSPROPERTY_PIN_DATAFLOW, &pin->dataFlow, sizeof(KSPIN_DATAFLOW)); if( result != paNoError ) goto error; /* Get the INTERFACE property list */ result = WdmGetPinPropertyMulti( parentFilter->handle, pinId, &KSPROPSETID_Pin, KSPROPERTY_PIN_INTERFACES, &item); if( result != paNoError ) goto error; identifier = (KSIDENTIFIER*)(item+1); /* Check that at least one interface is STANDARD_STREAMING */ result = paUnanticipatedHostError; for( i = 0; i < item->Count; i++ ) { if( !memcmp( (void*)&identifier[i].Set, (void*)&KSINTERFACESETID_Standard, sizeof( GUID ) ) && ( identifier[i].Id == KSINTERFACE_STANDARD_STREAMING ) ) { result = paNoError; break; } } if( result != paNoError ) { PA_DEBUG(("No standard streaming\n")); goto error; } /* Don't need interfaces any more */ PaUtil_FreeMemory( item ); item = NULL; /* Get the MEDIUM properties list */ result = WdmGetPinPropertyMulti( parentFilter->handle, pinId, &KSPROPSETID_Pin, KSPROPERTY_PIN_MEDIUMS, &item); if( result != paNoError ) goto error; identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */ /* Check that at least one medium is STANDARD_DEVIO */ result = paUnanticipatedHostError; for( i = 0; i < item->Count; i++ ) { if( !memcmp( (void*)&identifier[i].Set, (void*)&KSMEDIUMSETID_Standard, sizeof( GUID ) ) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) ) { result = paNoError; break; } } if( result != paNoError ) { PA_DEBUG(("No standard devio\n")); goto error; } /* Don't need mediums any more */ PaUtil_FreeMemory( item ); item = NULL; /* Get DATARANGES */ result = WdmGetPinPropertyMulti( parentFilter->handle, pinId, &KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &pin->dataRangesItem); if( result != paNoError ) goto error; pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1); /* Check that at least one datarange supports audio */ result = paUnanticipatedHostError; dataRange = pin->dataRanges; pin->maxChannels = 0; pin->bestSampleRate = 0; pin->formats = 0; for( i = 0; i dataRangesItem->Count; i++) { PA_DEBUG(("DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat)))); /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */ if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) || !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_PCM, sizeof ( GUID ) ) || ( !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof ( GUID ) ) && ( !memcmp((void*)&dataRange->MajorFormat, (void*)&KSDATAFORMAT_TYPE_AUDIO, sizeof ( GUID ) ) ) ) ) { result = paNoError; /* Record the maximum possible channels with this pin */ PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels)); if( (int)((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels ) { pin->maxChannels = ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels; /*PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels));*/ } /* Record the formats (bit depths) that are supported */ if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 16 ) { pin->formats |= paInt16; PA_DEBUG(("Format 16 bit supported\n")); } if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 24 ) { pin->formats |= paInt24; PA_DEBUG(("Format 24 bit supported\n")); } if( ( pin->bestSampleRate != 48000) && (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 48000) && (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 48000) ) { pin->bestSampleRate = 48000; PA_DEBUG(("48kHz supported\n")); } else if(( pin->bestSampleRate != 48000) && ( pin->bestSampleRate != 44100 ) && (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 44100) && (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 44100) ) { pin->bestSampleRate = 44100; PA_DEBUG(("44.1kHz supported\n")); } else { pin->bestSampleRate = ((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency; } } dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); } if( result != paNoError ) goto error; /* Get instance information */ result = WdmGetPinPropertySimple( parentFilter->handle, pinId, &KSPROPSETID_Pin, KSPROPERTY_PIN_CINSTANCES, &pin->instances, sizeof(KSPIN_CINSTANCES)); if( result != paNoError ) goto error; /* Success */ *error = paNoError; PA_DEBUG(("Pin created successfully\n")); PA_LOGL_; return pin; error: /* Error cleanup */ PaUtil_FreeMemory( item ); if( pin ) { PaUtil_FreeMemory( pin->pinConnect ); PaUtil_FreeMemory( pin->dataRangesItem ); PaUtil_FreeMemory( pin ); } *error = result; PA_LOGL_; return NULL; } /* Safely free all resources associated with the pin */ static void PinFree(PaWinWdmPin* pin) { PA_LOGE_; if( pin ) { PinClose(pin); if( pin->pinConnect ) { PaUtil_FreeMemory( pin->pinConnect ); } if( pin->dataRangesItem ) { PaUtil_FreeMemory( pin->dataRangesItem ); } PaUtil_FreeMemory( pin ); } PA_LOGL_; } /* If the pin handle is open, close it */ static void PinClose(PaWinWdmPin* pin) { PA_LOGE_; if( pin == NULL ) { PA_DEBUG(("Closing NULL pin!")); PA_LOGL_; return; } if( pin->handle != NULL ) { PinSetState( pin, KSSTATE_PAUSE ); PinSetState( pin, KSSTATE_STOP ); CloseHandle( pin->handle ); pin->handle = NULL; FilterRelease(pin->parentFilter); } PA_LOGL_; } /* Set the state of this (instantiated) pin */ static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state) { PaError result; PA_LOGE_; if( pin == NULL ) return paInternalError; if( pin->handle == NULL ) return paInternalError; result = WdmSetPropertySimple( pin->handle, &KSPROPSETID_Connection, KSPROPERTY_CONNECTION_STATE, &state, sizeof(state), NULL, 0); PA_LOGL_; return result; } static PaError PinInstantiate(PaWinWdmPin* pin) { PaError result; unsigned long createResult; KSALLOCATOR_FRAMING ksaf; KSALLOCATOR_FRAMING_EX ksafex; PA_LOGE_; if( pin == NULL ) return paInternalError; if(!pin->pinConnect) return paInternalError; FilterUse(pin->parentFilter); createResult = FunctionKsCreatePin( pin->parentFilter->handle, pin->pinConnect, GENERIC_WRITE | GENERIC_READ, &pin->handle ); PA_DEBUG(("Pin create result = %x\n",createResult)); if( createResult != ERROR_SUCCESS ) { FilterRelease(pin->parentFilter); pin->handle = NULL; return paInvalidDevice; } result = WdmGetPropertySimple( pin->handle, &KSPROPSETID_Connection, KSPROPERTY_CONNECTION_ALLOCATORFRAMING, &ksaf, sizeof(ksaf), NULL, 0); if( result != paNoError ) { result = WdmGetPropertySimple( pin->handle, &KSPROPSETID_Connection, KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, &ksafex, sizeof(ksafex), NULL, 0); if( result == paNoError ) { pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize; } } else { pin->frameSize = ksaf.FrameSize; } PA_LOGL_; return paNoError; } /* NOT USED static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state) { PaError result; if( state == NULL ) return paInternalError; if( pin == NULL ) return paInternalError; if( pin->handle == NULL ) return paInternalError; result = WdmGetPropertySimple( pin->handle, KSPROPSETID_Connection, KSPROPERTY_CONNECTION_STATE, state, sizeof(KSSTATE), NULL, 0); return result; } */ static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format) { unsigned long size; void* newConnect; PA_LOGE_; if( pin == NULL ) return paInternalError; if( format == NULL ) return paInternalError; size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX); if( pin->pinConnectSize != size ) { newConnect = PaUtil_AllocateMemory( size ); if( newConnect == NULL ) return paInsufficientMemory; memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) ); PaUtil_FreeMemory( pin->pinConnect ); pin->pinConnect = (KSPIN_CONNECT*)newConnect; pin->pinConnectSize = size; pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1); pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT); } memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) ); pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8)); PA_LOGL_; return paNoError; } static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format) { KSDATARANGE_AUDIO* dataRange; unsigned long count; GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) ); PaError result = paInvalidDevice; PA_LOGE_; if( format->wFormatTag == WAVE_FORMAT_EXTENSIBLE ) { guid = ((WAVEFORMATEXTENSIBLE*)format)->SubFormat; } dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges; for(count = 0; countdataRangesItem->Count; count++) { if(( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_AUDIO,sizeof(GUID)) ) || ( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_WILDCARD,sizeof(GUID)) )) { /* This is an audio or wildcard datarange... */ if(( !memcmp(&(dataRange->DataRange.SubFormat),&KSDATAFORMAT_SUBTYPE_WILDCARD,sizeof(GUID)) ) || ( !memcmp(&(dataRange->DataRange.SubFormat),&guid,sizeof(GUID)) )) { if(( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WILDCARD,sizeof(GUID)) ) || ( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX,sizeof(GUID) ))) { PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count)); PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize)); PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels)); PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample)); PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency)); if( dataRange->MaximumChannels < format->nChannels ) { result = paInvalidChannelCount; continue; } if( dataRange->MinimumBitsPerSample > format->wBitsPerSample ) { result = paSampleFormatNotSupported; continue; } if( dataRange->MaximumBitsPerSample < format->wBitsPerSample ) { result = paSampleFormatNotSupported; continue; } if( dataRange->MinimumSampleFrequency > format->nSamplesPerSec ) { result = paInvalidSampleRate; continue; } if( dataRange->MaximumSampleFrequency < format->nSamplesPerSec ) { result = paInvalidSampleRate; continue; } /* Success! */ PA_LOGL_; return paNoError; } } } dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize); } PA_LOGL_; return result; } /** * Create a new filter object */ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError* error) { PaWinWdmFilter* filter; PaError result; int pinId; int valid; /* Allocate the new filter object */ filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) ); if( !filter ) { result = paInsufficientMemory; goto error; } /* Zero the filter object - done by AllocateMemory */ /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */ /* Copy the filter name */ _tcsncpy(filter->filterName, filterName, MAX_PATH); /* Copy the friendly name */ _tcsncpy(filter->friendlyName, friendlyName, MAX_PATH); /* Open the filter handle */ result = FilterUse(filter); if( result != paNoError ) { goto error; } /* Get pin count */ result = WdmGetPinPropertySimple ( filter->handle, 0, &KSPROPSETID_Pin, KSPROPERTY_PIN_CTYPES, &filter->pinCount, sizeof(filter->pinCount) ); if( result != paNoError) { goto error; } /* Allocate pointer array to hold the pins */ filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount ); if( !filter->pins ) { result = paInsufficientMemory; goto error; } /* Create all the pins we can */ filter->maxInputChannels = 0; filter->maxOutputChannels = 0; filter->bestSampleRate = 0; valid = 0; for(pinId = 0; pinId < filter->pinCount; pinId++) { /* Create the pin with this Id */ PaWinWdmPin* newPin; newPin = PinNew(filter, pinId, &result); if( result == paInsufficientMemory ) goto error; if( newPin != NULL ) { filter->pins[pinId] = newPin; valid = 1; /* Get the max output channel count */ if(( newPin->dataFlow == KSPIN_DATAFLOW_IN ) && (( newPin->communication == KSPIN_COMMUNICATION_SINK) || ( newPin->communication == KSPIN_COMMUNICATION_BOTH))) { if(newPin->maxChannels > filter->maxOutputChannels) filter->maxOutputChannels = newPin->maxChannels; filter->formats |= newPin->formats; } /* Get the max input channel count */ if(( newPin->dataFlow == KSPIN_DATAFLOW_OUT ) && (( newPin->communication == KSPIN_COMMUNICATION_SINK) || ( newPin->communication == KSPIN_COMMUNICATION_BOTH))) { if(newPin->maxChannels > filter->maxInputChannels) filter->maxInputChannels = newPin->maxChannels; filter->formats |= newPin->formats; } if(newPin->bestSampleRate > filter->bestSampleRate) { filter->bestSampleRate = newPin->bestSampleRate; } } } if(( filter->maxInputChannels == 0) && ( filter->maxOutputChannels == 0)) { /* No input or output... not valid */ valid = 0; } if( !valid ) { /* No valid pin was found on this filter so we destroy it */ result = paDeviceUnavailable; goto error; } /* Close the filter handle for now * It will be opened later when needed */ FilterRelease(filter); *error = paNoError; return filter; error: /* Error cleanup */ if( filter ) { for( pinId = 0; pinId < filter->pinCount; pinId++ ) PinFree(filter->pins[pinId]); PaUtil_FreeMemory( filter->pins ); if( filter->handle ) CloseHandle( filter->handle ); PaUtil_FreeMemory( filter ); } *error = result; return NULL; } /** * Free a previously created filter */ static void FilterFree(PaWinWdmFilter* filter) { int pinId; PA_LOGL_; if( filter ) { for( pinId = 0; pinId < filter->pinCount; pinId++ ) PinFree(filter->pins[pinId]); PaUtil_FreeMemory( filter->pins ); if( filter->handle ) CloseHandle( filter->handle ); PaUtil_FreeMemory( filter ); } PA_LOGE_; } /** * Reopen the filter handle if necessary so it can be used **/ static PaError FilterUse(PaWinWdmFilter* filter) { assert( filter ); PA_LOGE_; if( filter->handle == NULL ) { /* Open the filter */ filter->handle = CreateFile( filter->filterName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if( filter->handle == NULL ) { return paDeviceUnavailable; } } filter->usageCount++; PA_LOGL_; return paNoError; } /** * Release the filter handle if nobody is using it **/ static void FilterRelease(PaWinWdmFilter* filter) { assert( filter ); assert( filter->usageCount > 0 ); PA_LOGE_; filter->usageCount--; if( filter->usageCount == 0 ) { if( filter->handle != NULL ) { CloseHandle( filter->handle ); filter->handle = NULL; } } PA_LOGL_; } /** * Create a render (playback) Pin using the supplied format **/ static PaWinWdmPin* FilterCreateRenderPin(PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error) { PaError result; PaWinWdmPin* pin; assert( filter ); pin = FilterFindViableRenderPin(filter,wfex,&result); if(!pin) { goto error; } result = PinSetFormat(pin,wfex); if( result != paNoError ) { goto error; } result = PinInstantiate(pin); if( result != paNoError ) { goto error; } *error = paNoError; return pin; error: *error = result; return NULL; } /** * Find a pin that supports the given format **/ static PaWinWdmPin* FilterFindViableRenderPin(PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error) { int pinId; PaWinWdmPin* pin; PaError result = paDeviceUnavailable; *error = paNoError; assert( filter ); for( pinId = 0; pinIdpinCount; pinId++ ) { pin = filter->pins[pinId]; if( pin != NULL ) { if(( pin->dataFlow == KSPIN_DATAFLOW_IN ) && (( pin->communication == KSPIN_COMMUNICATION_SINK) || ( pin->communication == KSPIN_COMMUNICATION_BOTH))) { result = PinIsFormatSupported( pin, wfex ); if( result == paNoError ) { return pin; } } } } *error = result; return NULL; } /** * Check if there is a pin that should playback * with the supplied format **/ static PaError FilterCanCreateRenderPin(PaWinWdmFilter* filter, const WAVEFORMATEX* wfex) { PaWinWdmPin* pin; PaError result; assert ( filter ); pin = FilterFindViableRenderPin(filter,wfex,&result); /* result will be paNoError if pin found * or else an error code indicating what is wrong with the format **/ return result; } /** * Create a capture (record) Pin using the supplied format **/ static PaWinWdmPin* FilterCreateCapturePin(PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error) { PaError result; PaWinWdmPin* pin; assert( filter ); pin = FilterFindViableCapturePin(filter,wfex,&result); if(!pin) { goto error; } result = PinSetFormat(pin,wfex); if( result != paNoError ) { goto error; } result = PinInstantiate(pin); if( result != paNoError ) { goto error; } *error = paNoError; return pin; error: *error = result; return NULL; } /** * Find a capture pin that supports the given format **/ static PaWinWdmPin* FilterFindViableCapturePin(PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error) { int pinId; PaWinWdmPin* pin; PaError result = paDeviceUnavailable; *error = paNoError; assert( filter ); for( pinId = 0; pinIdpinCount; pinId++ ) { pin = filter->pins[pinId]; if( pin != NULL ) { if(( pin->dataFlow == KSPIN_DATAFLOW_OUT ) && (( pin->communication == KSPIN_COMMUNICATION_SINK) || ( pin->communication == KSPIN_COMMUNICATION_BOTH))) { result = PinIsFormatSupported( pin, wfex ); if( result == paNoError ) { return pin; } } } } *error = result; return NULL; } /** * Check if there is a pin that should playback * with the supplied format **/ static PaError FilterCanCreateCapturePin(PaWinWdmFilter* filter, const WAVEFORMATEX* wfex) { PaWinWdmPin* pin; PaError result; assert ( filter ); pin = FilterFindViableCapturePin(filter,wfex,&result); /* result will be paNoError if pin found * or else an error code indicating what is wrong with the format **/ return result; } /** * Build the list of available filters * Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which * have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these * devices initialise a PaWinWdmFilter structure by calling our NewFilter() * function. We enumerate devices twice, once to count how many there are, * and once to initialize the PaWinWdmFilter structures. */ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) { PaError result = paNoError; HDEVINFO handle = NULL; int device; int invalidDevices; int slot; SP_DEVICE_INTERFACE_DATA interfaceData; SP_DEVICE_INTERFACE_DATA aliasData; SP_DEVINFO_DATA devInfoData; int noError; const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR)); unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))]; SP_DEVICE_INTERFACE_DETAIL_DATA* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA*)interfaceDetailsArray; TCHAR friendlyName[MAX_PATH]; HKEY hkey; DWORD sizeFriendlyName; DWORD type; PaWinWdmFilter* newFilter; GUID* category = (GUID*)&KSCATEGORY_AUDIO; GUID* alias_render = (GUID*)&KSCATEGORY_RENDER; GUID* alias_capture = (GUID*)&KSCATEGORY_CAPTURE; DWORD hasAlias; PA_LOGE_; devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); /* Open a handle to search for devices (filters) */ handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if( handle == NULL ) { return paUnanticipatedHostError; } PA_DEBUG(("Setup called\n")); /* First let's count the number of devices so we can allocate a list */ invalidDevices = 0; for( device = 0;;device++ ) { interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); interfaceData.Reserved = 0; aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); aliasData.Reserved = 0; noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData); PA_DEBUG(("Enum called\n")); if( !noError ) break; /* No more devices */ /* Check this one has the render or capture alias */ hasAlias = 0; noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData); PA_DEBUG(("noError = %d\n",noError)); if(noError) { if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has render alias\n",device)); hasAlias |= 1; /* Has render alias */ } else { PA_DEBUG(("Device %d has no render alias\n",device)); } } noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData); if(noError) { if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has capture alias\n",device)); hasAlias |= 2; /* Has capture alias */ } else { PA_DEBUG(("Device %d has no capture alias\n",device)); } } if(!hasAlias) invalidDevices++; /* This was not a valid capture or render audio device */ } /* Remember how many there are */ wdmHostApi->filterCount = device-invalidDevices; PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices)); /* Now allocate the list of pointers to devices */ wdmHostApi->filters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * device ); if( !wdmHostApi->filters ) { if(handle != NULL) SetupDiDestroyDeviceInfoList(handle); return paInsufficientMemory; } /* Now create filter objects for each interface found */ slot = 0; for( device = 0;;device++ ) { interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); interfaceData.Reserved = 0; aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); aliasData.Reserved = 0; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); devInfoData.Reserved = 0; noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData); if( !noError ) break; /* No more devices */ /* Check this one has the render or capture alias */ hasAlias = 0; noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData); if(noError) { if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has render alias\n",device)); hasAlias |= 1; /* Has render alias */ } } noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData); if(noError) { if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has capture alias\n",device)); hasAlias |= 2; /* Has capture alias */ } } if(!hasAlias) continue; /* This was not a valid capture or render audio device */ noError = SetupDiGetDeviceInterfaceDetail(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData); if( noError ) { /* Try to get the "friendly name" for this interface */ sizeFriendlyName = sizeof(friendlyName); /* Fix contributed by Ben Allison * Removed KEY_SET_VALUE from flags on following call * as its causes failure when running without admin rights * and it was not required */ hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE); if(hkey!=INVALID_HANDLE_VALUE) { noError = RegQueryValueEx(hkey,TEXT("FriendlyName"),0,&type,(BYTE*)friendlyName,&sizeFriendlyName); if( noError == ERROR_SUCCESS ) { PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName)); RegCloseKey(hkey); } else { friendlyName[0] = 0; } } newFilter = FilterNew(devInterfaceDetails->DevicePath,friendlyName,&result); if( result == paNoError ) { PA_DEBUG(("Filter created\n")); wdmHostApi->filters[slot] = newFilter; slot++; } else { PA_DEBUG(("Filter NOT created\n")); /* As there are now less filters than we initially thought * we must reduce the count by one */ wdmHostApi->filterCount--; } } } /* Clean up */ if(handle != NULL) SetupDiDestroyDeviceInfoList(handle); return paNoError; } PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; int i, deviceCount; PaWinWdmHostApiRepresentation *wdmHostApi; PaWinWdmDeviceInfo *deviceInfoArray; PaWinWdmFilter* pFilter; PaWinWdmDeviceInfo *wdmDeviceInfo; PaDeviceInfo *deviceInfo; PA_LOGE_; /* Attempt to load the KSUSER.DLL without which we cannot create pins We will unload this on termination */ if(DllKsUser == NULL) { DllKsUser = LoadLibrary(TEXT("ksuser.dll")); if(DllKsUser == NULL) goto error; } FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin"); if(FunctionKsCreatePin == NULL) goto error; wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) ); if( !wdmHostApi ) { result = paInsufficientMemory; goto error; } wdmHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !wdmHostApi->allocations ) { result = paInsufficientMemory; goto error; } result = BuildFilterList( wdmHostApi ); if( result != paNoError ) { goto error; } deviceCount = wdmHostApi->filterCount; *hostApi = &wdmHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paWDMKS; (*hostApi)->info.name = "Windows WDM-KS"; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; if( deviceCount > 0 ) { (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo*) * deviceCount ); if( !(*hostApi)->deviceInfos ) { result = paInsufficientMemory; goto error; } /* allocate all device info structs in a contiguous block */ deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory( wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * deviceCount ); if( !deviceInfoArray ) { result = paInsufficientMemory; goto error; } for( i=0; i < deviceCount; ++i ) { wdmDeviceInfo = &deviceInfoArray[i]; deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo; pFilter = wdmHostApi->filters[i]; if( pFilter == NULL ) continue; wdmDeviceInfo->filter = pFilter; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; deviceInfo->name = (char*)pFilter->friendlyName; PA_DEBUG(("Device found name: %s\n",(char*)pFilter->friendlyName)); deviceInfo->maxInputChannels = pFilter->maxInputChannels; if(deviceInfo->maxInputChannels > 0) { /* Set the default input device to the first device we find with * more than zero input channels **/ if((*hostApi)->info.defaultInputDevice == paNoDevice) { (*hostApi)->info.defaultInputDevice = i; } } deviceInfo->maxOutputChannels = pFilter->maxOutputChannels; if(deviceInfo->maxOutputChannels > 0) { /* Set the default output device to the first device we find with * more than zero output channels **/ if((*hostApi)->info.defaultOutputDevice == paNoDevice) { (*hostApi)->info.defaultOutputDevice = i; } } /* These low values are not very useful because * a) The lowest latency we end up with can depend on many factors such * as the device buffer sizes/granularities, sample rate, channels and format * b) We cannot know the device buffer sizes until we try to open/use it at * a particular setting * So: we give 512x48000Hz frames as the default low input latency **/ deviceInfo->defaultLowInputLatency = (512.0/48000.0); deviceInfo->defaultLowOutputLatency = (512.0/48000.0); deviceInfo->defaultHighInputLatency = (4096.0/48000.0); deviceInfo->defaultHighOutputLatency = (4096.0/48000.0); deviceInfo->defaultSampleRate = (double)(pFilter->bestSampleRate); (*hostApi)->deviceInfos[i] = deviceInfo; } } (*hostApi)->info.deviceCount = deviceCount; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); PA_LOGL_; return result; error: if( DllKsUser != NULL ) { FreeLibrary( DllKsUser ); DllKsUser = NULL; } if( wdmHostApi ) { PaUtil_FreeMemory( wdmHostApi->filters ); if( wdmHostApi->allocations ) { PaUtil_FreeAllAllocations( wdmHostApi->allocations ); PaUtil_DestroyAllocationGroup( wdmHostApi->allocations ); } PaUtil_FreeMemory( wdmHostApi ); } PA_LOGL_; return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; int i; PA_LOGE_; if( wdmHostApi->filters ) { for( i=0; ifilterCount; i++) { if( wdmHostApi->filters[i] != NULL ) { FilterFree( wdmHostApi->filters[i] ); wdmHostApi->filters[i] = NULL; } } } PaUtil_FreeMemory( wdmHostApi->filters ); if( wdmHostApi->allocations ) { PaUtil_FreeAllAllocations( wdmHostApi->allocations ); PaUtil_DestroyAllocationGroup( wdmHostApi->allocations ); } PaUtil_FreeMemory( wdmHostApi ); PA_LOGL_; } static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount) { PA_LOGE_; PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat )); PA_DEBUG(( "sampleRate = %f\n" , sampleRate )); PA_DEBUG(( "chanelCount = %d\n", channelCount )); pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; pwfext->Format.nChannels = channelCount; pwfext->Format.nSamplesPerSec = (int)sampleRate; if(channelCount == 1) pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; else pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; if(sampleFormat == paFloat32) { pwfext->Format.nBlockAlign = channelCount * 4; pwfext->Format.wBitsPerSample = 32; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 32; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } else if(sampleFormat == paInt32) { pwfext->Format.nBlockAlign = channelCount * 4; pwfext->Format.wBitsPerSample = 32; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 32; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } else if(sampleFormat == paInt24) { pwfext->Format.nBlockAlign = channelCount * 3; pwfext->Format.wBitsPerSample = 24; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 24; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } else if(sampleFormat == paInt16) { pwfext->Format.nBlockAlign = channelCount * 2; pwfext->Format.wBitsPerSample = 16; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 16; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign; PA_LOGL_; } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; PaWinWdmFilter* pFilter; int result = paFormatIsSupported; WAVEFORMATEXTENSIBLE wfx; PA_LOGE_; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ /* Check that the input format is supported */ FillWFEXT(&wfx,paInt16,sampleRate,inputChannelCount); pFilter = wdmHostApi->filters[inputParameters->device]; result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx); if( result != paNoError ) { /* Try a WAVE_FORMAT_PCM instead */ wfx.Format.wFormatTag = WAVE_FORMAT_PCM; wfx.Format.cbSize = 0; wfx.Samples.wValidBitsPerSample = 0; wfx.dwChannelMask = 0; wfx.SubFormat = GUID_NULL; result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx); if( result != paNoError ) return result; } } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support outputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ /* Check that the output format is supported */ FillWFEXT(&wfx,paInt16,sampleRate,outputChannelCount); pFilter = wdmHostApi->filters[outputParameters->device]; result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx); if( result != paNoError ) { /* Try a WAVE_FORMAT_PCM instead */ wfx.Format.wFormatTag = WAVE_FORMAT_PCM; wfx.Format.cbSize = 0; wfx.Samples.wValidBitsPerSample = 0; wfx.dwChannelMask = 0; wfx.SubFormat = GUID_NULL; result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx); if( result != paNoError ) return result; } } else { outputChannelCount = 0; } /* IMPLEMENT ME: - if a full duplex stream is requested, check that the combination of input and output parameters is supported if necessary - check that the device supports sampleRate Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - check that input device can support inputSampleFormat, or that we have the capability to convert from inputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format */ if((inputChannelCount == 0)&&(outputChannelCount == 0)) result = paSampleFormatNotSupported; /* Not right error */ PA_LOGL_; return result; } /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; PaWinWdmStream *stream = 0; /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */ PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; int userInputChannels,userOutputChannels; int size; PaWinWdmFilter* pFilter; WAVEFORMATEXTENSIBLE wfx; PA_LOGE_; PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate)); PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerBuffer)); if( inputParameters ) { userInputChannels = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support stream->userInputChannels */ if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { userInputChannels = 0; inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ } if( outputParameters ) { userOutputChannels = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support stream->userInputChannels */ if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { userOutputChannels = 0; outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ } /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) ); if( !stream ) { result = paInsufficientMemory; goto error; } /* Zero the stream object */ /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &wdmHostApi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &wdmHostApi->blockingStreamInterface, streamCallback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); /* Instantiate the input pin if necessary */ if(userInputChannels > 0) { result = paSampleFormatNotSupported; pFilter = wdmHostApi->filters[inputParameters->device]; stream->userInputChannels = userInputChannels; if(((inputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0) { /* inputSampleFormat is supported, so try to use it */ hostInputSampleFormat = inputSampleFormat; FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels); stream->bytesPerInputFrame = wfx.Format.nBlockAlign; stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result); stream->deviceInputChannels = stream->userInputChannels; } if(result != paNoError) { /* Search through all PaSampleFormats to find one that works */ hostInputSampleFormat = paFloat32; do { FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels); stream->bytesPerInputFrame = wfx.Format.nBlockAlign; stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result); stream->deviceInputChannels = stream->userInputChannels; if(stream->recordingPin == NULL) result = paSampleFormatNotSupported; if(result != paNoError) hostInputSampleFormat <<= 1; } while(result != paNoError && hostInputSampleFormat <= paUInt8); } if(result != paNoError) { /* None of the PaSampleFormats worked. Set the hostInputSampleFormat to the best fit * and try a PCM format. **/ hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pFilter->formats, inputSampleFormat ); /* Try a WAVE_FORMAT_PCM instead */ wfx.Format.wFormatTag = WAVE_FORMAT_PCM; wfx.Format.cbSize = 0; wfx.Samples.wValidBitsPerSample = 0; wfx.dwChannelMask = 0; wfx.SubFormat = GUID_NULL; stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result); if(stream->recordingPin == NULL) result = paSampleFormatNotSupported; } if( result != paNoError ) { /* Some or all KS devices can only handle the exact number of channels * they specify. But PortAudio clients expect to be able to * at least specify mono I/O on a multi-channel device * If this is the case, then we will do the channel mapping internally **/ if( stream->userInputChannels < pFilter->maxInputChannels ) { FillWFEXT(&wfx,hostInputSampleFormat,sampleRate,pFilter->maxInputChannels); stream->bytesPerInputFrame = wfx.Format.nBlockAlign; stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result); stream->deviceInputChannels = pFilter->maxInputChannels; if( result != paNoError ) { /* Try a WAVE_FORMAT_PCM instead */ wfx.Format.wFormatTag = WAVE_FORMAT_PCM; wfx.Format.cbSize = 0; wfx.Samples.wValidBitsPerSample = 0; wfx.dwChannelMask = 0; wfx.SubFormat = GUID_NULL; stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result); } } } if(stream->recordingPin == NULL) { goto error; } switch(hostInputSampleFormat) { case paInt16: stream->inputSampleSize = 2; break; case paInt24: stream->inputSampleSize = 3; break; case paInt32: case paFloat32: stream->inputSampleSize = 4; break; } stream->recordingPin->frameSize /= stream->bytesPerInputFrame; PA_DEBUG(("Pin output frames: %d\n",stream->recordingPin->frameSize)); } else { stream->recordingPin = NULL; stream->bytesPerInputFrame = 0; } /* Instantiate the output pin if necessary */ if(userOutputChannels > 0) { result = paSampleFormatNotSupported; pFilter = wdmHostApi->filters[outputParameters->device]; stream->userOutputChannels = userOutputChannels; if(((outputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0) { hostOutputSampleFormat = outputSampleFormat; FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels); stream->bytesPerOutputFrame = wfx.Format.nBlockAlign; stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result); stream->deviceOutputChannels = stream->userOutputChannels; } if(result != paNoError) { hostOutputSampleFormat = paFloat32; do { FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels); stream->bytesPerOutputFrame = wfx.Format.nBlockAlign; stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result); stream->deviceOutputChannels = stream->userOutputChannels; if(stream->playbackPin == NULL) result = paSampleFormatNotSupported; if(result != paNoError) hostOutputSampleFormat <<= 1; } while(result != paNoError && hostOutputSampleFormat <= paUInt8); } if(result != paNoError) { hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pFilter->formats, outputSampleFormat ); /* Try a WAVE_FORMAT_PCM instead */ wfx.Format.wFormatTag = WAVE_FORMAT_PCM; wfx.Format.cbSize = 0; wfx.Samples.wValidBitsPerSample = 0; wfx.dwChannelMask = 0; wfx.SubFormat = GUID_NULL; stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result); if(stream->playbackPin == NULL) result = paSampleFormatNotSupported; } if( result != paNoError ) { /* Some or all KS devices can only handle the exact number of channels * they specify. But PortAudio clients expect to be able to * at least specify mono I/O on a multi-channel device * If this is the case, then we will do the channel mapping internally **/ if( stream->userOutputChannels < pFilter->maxOutputChannels ) { FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,pFilter->maxOutputChannels); stream->bytesPerOutputFrame = wfx.Format.nBlockAlign; stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result); stream->deviceOutputChannels = pFilter->maxOutputChannels; if( result != paNoError ) { /* Try a WAVE_FORMAT_PCM instead */ wfx.Format.wFormatTag = WAVE_FORMAT_PCM; wfx.Format.cbSize = 0; wfx.Samples.wValidBitsPerSample = 0; wfx.dwChannelMask = 0; wfx.SubFormat = GUID_NULL; stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result); } } } if(stream->playbackPin == NULL) { goto error; } switch(hostOutputSampleFormat) { case paInt16: stream->outputSampleSize = 2; break; case paInt24: stream->outputSampleSize = 3; break; case paInt32: case paFloat32: stream->outputSampleSize = 4; break; } stream->playbackPin->frameSize /= stream->bytesPerOutputFrame; PA_DEBUG(("Pin output frames: %d\n",stream->playbackPin->frameSize)); } else { stream->playbackPin = NULL; stream->bytesPerOutputFrame = 0; } /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */ /* Record the buffer length */ if(inputParameters) { /* Calculate the frames from the user's value - add a bit to round up */ stream->framesPerHostIBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001); if(stream->framesPerHostIBuffer > (unsigned long)sampleRate) { /* Upper limit is 1 second */ stream->framesPerHostIBuffer = (unsigned long)sampleRate; } else if(stream->framesPerHostIBuffer < stream->recordingPin->frameSize) { stream->framesPerHostIBuffer = stream->recordingPin->frameSize; } PA_DEBUG(("Input frames chosen:%ld\n",stream->framesPerHostIBuffer)); } if(outputParameters) { /* Calculate the frames from the user's value - add a bit to round up */ stream->framesPerHostOBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001); if(stream->framesPerHostOBuffer > (unsigned long)sampleRate) { /* Upper limit is 1 second */ stream->framesPerHostOBuffer = (unsigned long)sampleRate; } else if(stream->framesPerHostOBuffer < stream->playbackPin->frameSize) { stream->framesPerHostOBuffer = stream->playbackPin->frameSize; } PA_DEBUG(("Output frames chosen:%ld\n",stream->framesPerHostOBuffer)); } /* Host buffer size is bounded to the largest of the input and output frame sizes */ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, stream->userInputChannels, inputSampleFormat, hostInputSampleFormat, stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, max(stream->framesPerHostOBuffer,stream->framesPerHostIBuffer), paUtilBoundedHostBufferSize, streamCallback, userData ); if( result != paNoError ) goto error; stream->streamRepresentation.streamInfo.inputLatency = ((double)stream->framesPerHostIBuffer) / sampleRate; stream->streamRepresentation.streamInfo.outputLatency = ((double)stream->framesPerHostOBuffer) / sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate; PA_DEBUG(("BytesPerInputFrame = %d\n",stream->bytesPerInputFrame)); PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->bytesPerOutputFrame)); /* Allocate all the buffers for host I/O */ size = 2 * (stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame); PA_DEBUG(("Buffer size = %d\n",size)); stream->hostBuffer = (char*)PaUtil_AllocateMemory(size); PA_DEBUG(("Buffer allocated\n")); if( !stream->hostBuffer ) { PA_DEBUG(("Cannot allocate host buffer!\n")); result = paInsufficientMemory; goto error; } PA_DEBUG(("Buffer start = %p\n",stream->hostBuffer)); /* memset(stream->hostBuffer,0,size); */ /* Set up the packets */ stream->events[0] = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(stream->events[0]); /* Record buffer 1 */ stream->events[1] = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(stream->events[1]); /* Record buffer 2 */ stream->events[2] = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(stream->events[2]); /* Play buffer 1 */ stream->events[3] = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(stream->events[3]); /* Play buffer 2 */ stream->events[4] = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(stream->events[4]); /* Abort event */ if(stream->userInputChannels > 0) { DATAPACKET *p = &(stream->packets[0]); p->Signal.hEvent = stream->events[0]; p->Header.Data = stream->hostBuffer; p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame; p->Header.DataUsed = 0; p->Header.Size = sizeof(p->Header); p->Header.PresentationTime.Numerator = 1; p->Header.PresentationTime.Denominator = 1; p = &(stream->packets[1]); p->Signal.hEvent = stream->events[1]; p->Header.Data = stream->hostBuffer + stream->framesPerHostIBuffer*stream->bytesPerInputFrame; p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame; p->Header.DataUsed = 0; p->Header.Size = sizeof(p->Header); p->Header.PresentationTime.Numerator = 1; p->Header.PresentationTime.Denominator = 1; } if(stream->userOutputChannels > 0) { DATAPACKET *p = &(stream->packets[2]); p->Signal.hEvent = stream->events[2]; p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame; p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; p->Header.Size = sizeof(p->Header); p->Header.PresentationTime.Numerator = 1; p->Header.PresentationTime.Denominator = 1; p = &(stream->packets[3]); p->Signal.hEvent = stream->events[3]; p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; p->Header.Size = sizeof(p->Header); p->Header.PresentationTime.Numerator = 1; p->Header.PresentationTime.Denominator = 1; } stream->streamStarted = 0; stream->streamActive = 0; stream->streamStop = 0; stream->streamAbort = 0; stream->streamFlags = streamFlags; stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; *s = (PaStream*)stream; PA_LOGL_; return result; error: size = 5; while(size--) { if(stream->events[size] != NULL) { CloseHandle(stream->events[size]); stream->events[size] = NULL; } } if(stream->hostBuffer) PaUtil_FreeMemory( stream->hostBuffer ); if(stream->playbackPin) PinClose(stream->playbackPin); if(stream->recordingPin) PinClose(stream->recordingPin); if( stream ) PaUtil_FreeMemory( stream ); PA_LOGL_; return result; } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; int size; PA_LOGE_; assert(!stream->streamStarted); assert(!stream->streamActive); PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); size = 5; while(size--) { if(stream->events[size] != NULL) { CloseHandle(stream->events[size]); stream->events[size] = NULL; } } if(stream->hostBuffer) PaUtil_FreeMemory( stream->hostBuffer ); if(stream->playbackPin) PinClose(stream->playbackPin); if(stream->recordingPin) PinClose(stream->recordingPin); PaUtil_FreeMemory( stream ); PA_LOGL_; return result; } /* Write the supplied packet to the pin Asynchronous Should return false on success */ static BOOL PinWrite(HANDLE h, DATAPACKET* p) { unsigned long cbReturned = 0; return DeviceIoControl(h,IOCTL_KS_WRITE_STREAM,NULL,0, &p->Header,p->Header.Size,&cbReturned,&p->Signal); } /* Read to the supplied packet from the pin Asynchronous Should return false on success */ static BOOL PinRead(HANDLE h, DATAPACKET* p) { unsigned long cbReturned = 0; return DeviceIoControl(h,IOCTL_KS_READ_STREAM,NULL,0, &p->Header,p->Header.Size,&cbReturned,&p->Signal); } /* Copy the first interleaved channel of 16 bit data to the other channels */ static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples) { unsigned short* data = (unsigned short*)buffer; int channel; unsigned short sourceSample; while( samples-- ) { sourceSample = *data++; channel = channels-1; while( channel-- ) { *data++ = sourceSample; } } } /* Copy the first interleaved channel of 24 bit data to the other channels */ static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples) { unsigned char* data = (unsigned char*)buffer; int channel; unsigned char sourceSample[3]; while( samples-- ) { sourceSample[0] = data[0]; sourceSample[1] = data[1]; sourceSample[2] = data[2]; data += 3; channel = channels-1; while( channel-- ) { data[0] = sourceSample[0]; data[1] = sourceSample[1]; data[2] = sourceSample[2]; data += 3; } } } /* Copy the first interleaved channel of 32 bit data to the other channels */ static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples) { unsigned long* data = (unsigned long*)buffer; int channel; unsigned long sourceSample; while( samples-- ) { sourceSample = *data++; channel = channels-1; while( channel-- ) { *data++ = sourceSample; } } } static DWORD WINAPI ProcessingThread(LPVOID pParam) { PaWinWdmStream *stream = (PaWinWdmStream*)pParam; PaStreamCallbackTimeInfo ti; int cbResult = paContinue; int inbuf = 0; int outbuf = 0; int pending = 0; PaError result; unsigned long wait; unsigned long eventSignaled; int fillPlaybuf = 0; int emptyRecordbuf = 0; int framesProcessed; unsigned long timeout; int i; int doChannelCopy; int priming = 0; PaStreamCallbackFlags underover = 0; PA_LOGE_; ti.inputBufferAdcTime = 0.0; ti.currentTime = 0.0; ti.outputBufferDacTime = 0.0; /* Get double buffering going */ /* Submit buffers */ if(stream->playbackPin) { result = PinSetState(stream->playbackPin, KSSTATE_RUN); PA_DEBUG(("play state run = %d;",(int)result)); SetEvent(stream->events[outbuf+2]); outbuf = (outbuf+1)&1; SetEvent(stream->events[outbuf+2]); outbuf = (outbuf+1)&1; pending += 2; priming += 4; } if(stream->recordingPin) { result = PinSetState(stream->recordingPin, KSSTATE_RUN); PA_DEBUG(("recording state run = %d;",(int)result)); PinRead(stream->recordingPin->handle,&stream->packets[inbuf]); inbuf = (inbuf+1)&1; /* Increment and wrap */ PinRead(stream->recordingPin->handle,&stream->packets[inbuf]); inbuf = (inbuf+1)&1; /* Increment and wrap */ /* FIXME - do error checking */ pending += 2; } PA_DEBUG(("Out buffer len:%f\n",(2000*stream->framesPerHostOBuffer) / stream->streamRepresentation.streamInfo.sampleRate)); PA_DEBUG(("In buffer len:%f\n",(2000*stream->framesPerHostIBuffer) / stream->streamRepresentation.streamInfo.sampleRate)); timeout = max( ((2000*(DWORD)stream->framesPerHostOBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate), ((2000*(DWORD)stream->framesPerHostIBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate)); timeout = max(timeout,1); PA_DEBUG(("Timeout = %ld\n",timeout)); while(!stream->streamAbort) { fillPlaybuf = 0; emptyRecordbuf = 0; /* Wait for next input or output buffer to be finished with*/ assert(pending>0); if(stream->streamStop) { PA_DEBUG(("ss1:pending=%d ",pending)); } wait = WaitForMultipleObjects(5, stream->events, FALSE, 0); if( wait == WAIT_TIMEOUT ) { /* No (under|over)flow has ocurred */ wait = WaitForMultipleObjects(5, stream->events, FALSE, timeout); eventSignaled = wait - WAIT_OBJECT_0; } else { eventSignaled = wait - WAIT_OBJECT_0; if( eventSignaled < 2 ) { underover |= paInputOverflow; PA_DEBUG(("Input overflow\n")); } else if(( eventSignaled < 4 )&&(!priming)) { underover |= paOutputUnderflow; PA_DEBUG(("Output underflow\n")); } } if(stream->streamStop) { PA_DEBUG(("ss2:wait=%ld",wait)); } if(wait == WAIT_FAILED) { PA_DEBUG(("Wait fail = %ld! ",wait)); break; } if(wait == WAIT_TIMEOUT) { continue; } if(eventSignaled < 2) { /* Recording input buffer has been filled */ if(stream->playbackPin) { /* First check if also the next playback buffer has been signaled */ wait = WaitForSingleObject(stream->events[outbuf+2],0); if(wait == WAIT_OBJECT_0) { /* Yes, so do both buffers at same time */ fillPlaybuf = 1; pending--; /* Was this an underflow situation? */ if( underover ) underover |= paOutputUnderflow; /* Yes! */ } } emptyRecordbuf = 1; pending--; } else if(eventSignaled < 4) { /* Playback output buffer has been emptied */ if(stream->recordingPin) { /* First check if also the next recording buffer has been signaled */ wait = WaitForSingleObject(stream->events[inbuf],0); if(wait == WAIT_OBJECT_0) { /* Yes, so do both buffers at same time */ emptyRecordbuf = 1; pending--; /* Was this an overflow situation? */ if( underover ) underover |= paInputOverflow; /* Yes! */ } } fillPlaybuf = 1; pending--; } else { /* Abort event! */ assert(stream->streamAbort); /* Should have been set */ PA_DEBUG(("ABORTING ")); break; } ResetEvent(stream->events[eventSignaled]); if(stream->streamStop) { PA_DEBUG(("Stream stop! pending=%d",pending)); cbResult = paComplete; /* Stop, but play remaining buffers */ } /* Do necessary buffer processing (which will invoke user callback if necessary */ doChannelCopy = 0; if(cbResult==paContinue) { PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) == (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) ) PaUtil_BeginBufferProcessing(&stream->bufferProcessor,&ti,underover); underover = 0; /* Reset the (under|over)flow status */ if(fillPlaybuf) { PaUtil_SetOutputFrameCount(&stream->bufferProcessor,0); if( stream->userOutputChannels == 1 ) { /* Write the single user channel to the first interleaved block */ PaUtil_SetOutputChannel(&stream->bufferProcessor,0,stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels); /* We will do a copy to the other channels after the data has been written */ doChannelCopy = 1; } else { for(i=0;iuserOutputChannels;i++) { /* Only write the user output channels. Leave the rest blank */ PaUtil_SetOutputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[outbuf+2].Header.Data))+(i*stream->outputSampleSize),stream->deviceOutputChannels); } } } if(emptyRecordbuf) { PaUtil_SetInputFrameCount(&stream->bufferProcessor,stream->packets[inbuf].Header.DataUsed/stream->bytesPerInputFrame); for(i=0;iuserInputChannels;i++) { /* Only read as many channels as the user wants */ PaUtil_SetInputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[inbuf].Header.Data))+(i*stream->inputSampleSize),stream->deviceInputChannels); } } /* Only call the EndBufferProcessing function is the total input frames == total output frames */ if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) == (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) ) framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult); else framesProcessed = 0; if( doChannelCopy ) { /* Copy the first output channel to the other channels */ switch(stream->outputSampleSize) { case 2: DuplicateFirstChannelInt16(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer); break; case 3: DuplicateFirstChannelInt24(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer); break; case 4: DuplicateFirstChannelInt32(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer); break; default: assert(0); /* Unsupported format! */ break; } } PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); } else { fillPlaybuf = 0; emptyRecordbuf = 0; } /* if(cbResult != paContinue) { PA_DEBUG(("cbResult=%d, pending=%d:",cbResult,pending)); } */ /* Submit buffers */ if((fillPlaybuf)&&(cbResult!=paAbort)) { if(!PinWrite(stream->playbackPin->handle,&stream->packets[outbuf+2])) outbuf = (outbuf+1)&1; /* Increment and wrap */ pending++; if( priming ) priming--; /* Have to prime twice */ } if((emptyRecordbuf)&&(cbResult==paContinue)) { stream->packets[inbuf].Header.DataUsed = 0; /* Reset for reuse */ PinRead(stream->recordingPin->handle,&stream->packets[inbuf]); inbuf = (inbuf+1)&1; /* Increment and wrap */ pending++; } if(pending==0) { PA_DEBUG(("pending==0 finished...;")); break; } if((!stream->playbackPin)&&(cbResult!=paContinue)) { PA_DEBUG(("record only cbResult=%d...;",cbResult)); break; } } PA_DEBUG(("Finished thread")); /* Finished, either normally or aborted */ if(stream->playbackPin) { result = PinSetState(stream->playbackPin, KSSTATE_PAUSE); result = PinSetState(stream->playbackPin, KSSTATE_STOP); } if(stream->recordingPin) { result = PinSetState(stream->recordingPin, KSSTATE_PAUSE); result = PinSetState(stream->recordingPin, KSSTATE_STOP); } stream->streamActive = 0; if((!stream->streamStop)&&(!stream->streamAbort)) { /* Invoke the user stream finished callback */ /* Only do it from here if not being stopped/aborted by user */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } stream->streamStop = 0; stream->streamAbort = 0; /* Reset process priority if necessary */ if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS) { SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority); stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; } PA_LOGL_; ExitThread(0); return 0; } static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; DWORD dwID; BOOL ret; int size; PA_LOGE_; stream->streamStop = 0; stream->streamAbort = 0; size = 5; while(size--) { if(stream->events[size] != NULL) { ResetEvent(stream->events[size]); } } PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess()); /* Uncomment the following line to enable dynamic boosting of the process * priority to real time for best low latency support * Disabled by default because RT processes can easily block the OS */ /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); PA_DEBUG(("Class ret = %d;",ret));*/ stream->streamStarted = 1; stream->streamThread = CreateThread(NULL, 0, ProcessingThread, stream, 0, &dwID); if(stream->streamThread == NULL) { stream->streamStarted = 0; result = paInsufficientMemory; goto end; } ret = SetThreadPriority(stream->streamThread,THREAD_PRIORITY_TIME_CRITICAL); PA_DEBUG(("Priority ret = %d;",ret)); /* Make the stream active */ stream->streamActive = 1; end: PA_LOGL_; return result; } static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; int doCb = 0; PA_LOGE_; if(stream->streamActive) { doCb = 1; stream->streamStop = 1; while(stream->streamActive) { PA_DEBUG(("W.")); Sleep(10); /* Let thread sleep for 10 msec */ } } PA_DEBUG(("Terminating thread")); if(stream->streamStarted && stream->streamThread) { TerminateThread(stream->streamThread,0); stream->streamThread = NULL; } stream->streamStarted = 0; if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS) { SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority); stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; } if(doCb) { /* Do user callback now after all state has been reset */ /* This means it should be safe for the called function */ /* to invoke e.g. StartStream */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } PA_LOGL_; return result; } static PaError AbortStream( PaStream *s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; int doCb = 0; PA_LOGE_; if(stream->streamActive) { doCb = 1; stream->streamAbort = 1; SetEvent(stream->events[4]); /* Signal immediately */ while(stream->streamActive) { Sleep(10); } } if(stream->streamStarted && stream->streamThread) { TerminateThread(stream->streamThread,0); stream->streamThread = NULL; } stream->streamStarted = 0; if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS) { SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority); stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; } if(doCb) { /* Do user callback now after all state has been reset */ /* This means it should be safe for the called function */ /* to invoke e.g. StartStream */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } stream->streamActive = 0; stream->streamStarted = 0; PA_LOGL_; return result; } static PaError IsStreamStopped( PaStream *s ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; int result = 0; PA_LOGE_; if(!stream->streamStarted) result = 1; PA_LOGL_; return result; } static PaError IsStreamActive( PaStream *s ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; int result = 0; PA_LOGE_; if(stream->streamActive) result = 1; PA_LOGL_; return result; } static PaTime GetStreamTime( PaStream* s ) { PA_LOGE_; PA_LOGL_; (void)s; return PaUtil_GetTime(); } static double GetStreamCpuLoad( PaStream* s ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; double result; PA_LOGE_; result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); PA_LOGL_; return result; } /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; PA_LOGE_; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; return paNoError; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; PA_LOGE_; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; return paNoError; } static signed long GetStreamReadAvailable( PaStream* s ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; PA_LOGE_; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; return 0; } static signed long GetStreamWriteAvailable( PaStream* s ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; PA_LOGE_; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; return 0; }nyquist-3.05/portaudio/src/hostapi/wdmks/readme.txt0000644000175000000620000001005411466723256021566 0ustar stevestaffNotes about WDM-KS host API --------------------------- Status history -------------- 10th November 2005: Made following changes: * OpenStream: Try all PaSampleFormats internally if the the chosen format is not supported natively. This fixed several problems with soundcards that soundcards that did not take kindly to using 24-bit 3-byte formats. * OpenStream: Make the minimum framesPerHostIBuffer (and framesPerHostOBuffer) the default frameSize for the playback/recording pin. * ProcessingThread: Added a switch to only call PaUtil_EndBufferProcessing if the total input frames equals the total output frames 5th September 2004: This is the first public version of the code. It should be considered an alpha release with zero guarantee not to crash on any particular system. So far it has only been tested in the author's development environment, which means a Win2k/SP2 PIII laptop with integrated SoundMAX driver and USB Tascam US-428 compiled with both MinGW (GCC 3.3) and MSVC++6 using the MS DirectX 9 SDK. It has been most widely tested with the MinGW build, with most of the test programs (particularly paqa_devs and paqa_errs) passing. There are some notable failures: patest_out_underflow and both of the blocking I/O tests (as blocking I/O is not implemented). At this point the code needs to be tested with a much wider variety of configurations and feedback provided from testers regarding both working and failing cases. What is the WDM-KS host API? ---------------------------- PortAudio for Windows currently has 3 functional host implementations. MME uses the oldest Windows audio API which does not offer good play/record latency. DirectX improves this, but still imposes a penalty of 10s of milliseconds due to the system mixing of streams from multiple applications. ASIO offers very good latency, but requires special drivers which are not always available for cheaper audio hardware. Also, when ASIO drivers are available, they are not always so robust because they bypass all of the standardised Windows device driver architecture and hit the hardware their own way. Alternatively there are a couple of free (but closed source) ASIO implementations which connect to the lower level Windows "Kernel Streaming" API, but again these require special installation by the user, and can be limited in functionality or difficult to use. This is where the PortAudio "WDM-KS" host implementation comes in. It directly connects PortAudio to the same Kernel Streaming API which those ASIO bridges use. This avoids the mixing penatly of DirectX, giving at least as good latency as any ASIO driver, but it has the advantage of working with ANY Windows audio hardware which is available through the normal MME/DirectX routes without the user requiring any additional device drivers to be installed, and allowing all device selection to be done through the normal PortAudio API. Note that in general you should only be using this host API if your application has a real requirement for very low latency audio (<20ms), either because you are generating sounds in real-time based upon user input, or you a processing recorded audio in real time. The only thing to be aware of is that using the KS interface will block that device from being used by the rest of system through the higher level APIs, or conversely, if the system is using a device, the KS API will not be able to use it. MS recommend that you should keep the device open only when your application has focus. In PortAudio terms, this means having a stream Open on a WDMKS device. Usage ----- To add the WDMKS backend to your program which is already using PortAudio, you must undefine PA_NO_WDMKS from your build file, and include the pa_win_wdmks\pa_win_wdmks.c into your build. The file should compile in both C and C++. You will need a DirectX SDK installed on your system for the ks.h and ksmedia.h header files. You will need to link to the system "setupapi" library. Note that if you use MinGW, you will get more warnings from the DX header files when using GCC(C), and still a few warnings with G++(CPP).nyquist-3.05/portaudio/src/hostapi/asihpi/0002755000175000000620000000000011537433131017707 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/asihpi/pa_linux_asihpi.c0000644000175000000620000035014311466723256023246 0ustar stevestaff/* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * PortAudio v18 version of AudioScience HPI driver by Fred Gleason * PortAudio v19 version of AudioScience HPI driver by Ludwig Schwardt * * Copyright (c) 2003 Fred Gleason * Copyright (c) 2005,2006 Ludwig Schwardt * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /* * Modification History * 12/2003 - Initial version * 09/2005 - v19 version [rewrite] */ /** @file @ingroup hostapi_src @brief Host API implementation supporting AudioScience cards via the Linux HPI interface.

    Overview

    This is a PortAudio implementation for the AudioScience HPI Audio API on the Linux platform. AudioScience makes a range of audio adapters customised for the broadcasting industry, with support for both Windows and Linux. More information on their products can be found on their website: http://www.audioscience.com Documentation for the HPI API can be found at: http://www.audioscience.com/internet/download/sdk/spchpi.pdf The Linux HPI driver itself (a kernel module + library) can be downloaded from: http://www.audioscience.com/internet/download/linux_drivers.htm

    Implementation strategy

    *Note* Ideally, AudioScience cards should be handled by the PortAudio ALSA implementation on Linux, as ALSA is the preferred Linux soundcard API. The existence of this host API implementation might therefore seem a bit flawed. Unfortunately, at the time of the creation of this implementation (June 2006), the PA ALSA implementation could not make use of the existing AudioScience ALSA driver. PA ALSA uses the "memory-mapped" (mmap) ALSA access mode to interact with the ALSA library, while the AudioScience ALSA driver only supports the "read-write" access mode. The appropriate solution to this problem is to add "read-write" support to PortAudio ALSA, thereby extending the range of soundcards it supports (AudioScience cards are not the only ones with this problem). Given the author's limited knowledge of ALSA and the simplicity of the HPI API, the second-best solution was born... The following mapping between HPI and PA was followed: HPI subsystem => PortAudio host API HPI adapter => nothing specific HPI stream => PortAudio device Each HPI stream is either input or output (not both), and can support different channel counts, sampling rates and sample formats. It is therefore a more natural fit to a PA device. A PA stream can therefore combine two HPI streams (one input and one output) into a "full-duplex" stream. These HPI streams can even be on different physical adapters. The two streams ought to be sample-synchronised when they reside on the same adapter, as most AudioScience adapters derive their ADC and DAC clocks from one master clock. When combining two adapters into one full-duplex stream, however, the use of a word clock connection between the adapters is strongly recommended. The HPI interface is inherently blocking, making use of read and write calls to transfer data between user buffers and driver buffers. The callback interface therefore requires a helper thread ("callback engine") which periodically transfers data (one thread per PA stream, in fact). The current implementation explicitly sleeps via Pa_Sleep() until enough samples can be transferred (select() or poll() would be better, but currently seems impossible...). The thread implementation makes use of the Unix thread helper functions and some pthread calls here and there. If a unified PA thread exists, this host API implementation might also compile on Windows, as this is the only real Linux-specific part of the code. There is no inherent fixed buffer size in the HPI interface, as in some other host APIs. The PortAudio implementation contains a buffer that is allocated during OpenStream and used to transfer data between the callback and the HPI driver buffer. The size of this buffer is quite flexible and is derived from latency suggestions and matched to the requested callback buffer size as far as possible. It can become quite huge, as the AudioScience cards are typically geared towards higher-latency applications and contain large hardware buffers. The HPI interface natively supports most common sample formats and sample rates (some conversion is done on the adapter itself). Stream time is measured based on the number of processed frames, which is adjusted by the number of frames currently buffered by the HPI driver. There is basic support for detecting overflow and underflow. The HPI interface does not explicitly indicate this, so thresholds on buffer levels are used in combination with stream state. Recovery from overflow and underflow is left to the PA client. Blocking streams are also implemented. It makes use of the same polling routines that the callback interface uses, in order to prevent the allocation of variable-sized buffers during reading and writing. The framesPerBuffer parameter is therefore still relevant, and this can be increased in the blocking case to improve efficiency. The implementation contains extensive reporting macros (slightly modified PA_ENSURE and PA_UNLESS versions) and a useful stream dump routine to provide debugging feedback. Output buffer priming via the user callback (i.e. paPrimeOutputBuffersUsingStreamCallback and friends) is not implemented yet. All output is primed with silence. Please send bug reports etc. to Ludwig Schwardt */ #include #include #include #include /* strlen() */ #include /* pthreads and friends */ #include /* assert */ #include /* ceil, floor */ #include /* HPI API */ #include "portaudio.h" /* PortAudio API */ #include "pa_util.h" /* PA_DEBUG, other small utilities */ #include "pa_unix_util.h" /* Unix threading utilities */ #include "pa_allocation.h" /* Group memory allocation */ #include "pa_hostapi.h" /* Host API structs */ #include "pa_stream.h" /* Stream interface structs */ #include "pa_cpuload.h" /* CPU load measurer */ #include "pa_process.h" /* Buffer processor */ #include "pa_converters.h" /* PaUtilZeroer */ #include "pa_debugprint.h" /* -------------------------------------------------------------------------- */ /* * Defines */ /* Error reporting and assertions */ /** Evaluate expression, and return on any PortAudio errors */ #define PA_ENSURE_(expr) \ do { \ PaError paError = (expr); \ if( UNLIKELY( paError < paNoError ) ) \ { \ PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = paError; \ goto error; \ } \ } while (0); /** Assert expression, else return the provided PaError */ #define PA_UNLESS_(expr, paError) \ do { \ if( UNLIKELY( (expr) == 0 ) ) \ { \ PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = (paError); \ goto error; \ } \ } while( 0 ); /** Check return value of HPI function, and map it to PaError */ #define PA_ASIHPI_UNLESS_(expr, paError) \ do { \ HW16 hpiError = (expr); \ /* If HPI error occurred */ \ if( UNLIKELY( hpiError ) ) \ { \ char szError[256]; \ HPI_GetErrorText( hpiError, szError ); \ PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ /* This message will always be displayed, even if debug info is disabled */ \ PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ if( (paError) == paUnanticipatedHostError ) \ { \ PA_DEBUG(( "Host error description: %s\n", szError )); \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ { \ PaUtil_SetLastHostErrorInfo( paInDevelopment, hpiError, szError ); \ } \ } \ /* If paNoError is specified, continue as usual */ \ /* (useful if you only want to print out the debug messages above) */ \ if( (paError) < 0 ) \ { \ result = (paError); \ goto error; \ } \ } \ } while( 0 ); /** Report HPI error code and text */ #define PA_ASIHPI_REPORT_ERROR_(hpiErrorCode) \ do { \ char szError[256]; \ HPI_GetErrorText( hpiError, szError ); \ PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ { \ PaUtil_SetLastHostErrorInfo( paInDevelopment, (hpiErrorCode), szError ); \ } \ } while( 0 ); /* Defaults */ /** Sample formats available natively on AudioScience hardware */ #define PA_ASIHPI_AVAILABLE_FORMATS_ (paFloat32 | paInt32 | paInt24 | paInt16 | paUInt8) /** Enable background bus mastering (BBM) for buffer transfers, if available (see HPI docs) */ #define PA_ASIHPI_USE_BBM_ 1 /** Minimum number of frames in HPI buffer (for either data or available space). If buffer contains less data/space, it indicates xrun or completion. */ #define PA_ASIHPI_MIN_FRAMES_ 1152 /** Minimum polling interval in milliseconds, which determines minimum host buffer size */ #define PA_ASIHPI_MIN_POLLING_INTERVAL_ 10 /* -------------------------------------------------------------------------- */ /* * Structures */ /** Host API global data */ typedef struct PaAsiHpiHostApiRepresentation { /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ PaUtilHostApiRepresentation baseHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ PaHostApiIndex hostApiIndex; /** HPI subsystem pointer */ HPI_HSUBSYS *subSys; } PaAsiHpiHostApiRepresentation; /** Device data */ typedef struct PaAsiHpiDeviceInfo { /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ /** Common PortAudio device information */ PaDeviceInfo baseDeviceInfo; /* implementation specific data goes here */ /** HPI subsystem (required for most HPI calls) */ HPI_HSUBSYS *subSys; /** Adapter index */ HW16 adapterIndex; /** Adapter model number (hex) */ HW16 adapterType; /** Adapter HW/SW version */ HW16 adapterVersion; /** Adapter serial number */ HW32 adapterSerialNumber; /** Stream number */ HW16 streamIndex; /** 0=Input, 1=Output (HPI streams are either input or output but not both) */ HW16 streamIsOutput; } PaAsiHpiDeviceInfo; /** Stream state as defined by PortAudio. It seems that the host API implementation has to keep track of the PortAudio stream state. Please note that this is NOT the same as the state of the underlying HPI stream. By separating these two concepts, a lot of flexibility is gained. There is a rough match between the two, of course, but forcing a precise match is difficult. For example, HPI_STATE_DRAINED can occur during the Active state of PortAudio (due to underruns) and also during CallBackFinished in the case of an output stream. Similarly, HPI_STATE_STOPPED mostly coincides with the Stopped PortAudio state, by may also occur in the CallbackFinished state when recording is finished. Here is a rough match-up: PortAudio state => HPI state --------------- --------- Active => HPI_STATE_RECORDING, HPI_STATE_PLAYING, (HPI_STATE_DRAINED) Stopped => HPI_STATE_STOPPED CallbackFinished => HPI_STATE_STOPPED, HPI_STATE_DRAINED */ typedef enum PaAsiHpiStreamState { paAsiHpiStoppedState=0, paAsiHpiActiveState=1, paAsiHpiCallbackFinishedState=2 } PaAsiHpiStreamState; /** Stream component data (associated with one direction, i.e. either input or output) */ typedef struct PaAsiHpiStreamComponent { /** Device information (HPI handles, etc) */ PaAsiHpiDeviceInfo *hpiDevice; /** Stream handle, as passed to HPI interface. HACK: we assume types HPI_HISTREAM and HPI_HOSTREAM are the same... (both are HW32 up to version 3.00 of ASIHPI, and hopefully they stay that way) */ HPI_HISTREAM hpiStream; /** Stream format, as passed to HPI interface */ HPI_FORMAT hpiFormat; /** Number of bytes per frame, derived from hpiFormat and saved for convenience */ HW32 bytesPerFrame; /** Size of hardware (on-card) buffer of stream in bytes */ HW32 hardwareBufferSize; /** Size of host (BBM) buffer of stream in bytes (if used) */ HW32 hostBufferSize; /** Upper limit on the utilization of output stream buffer (both hardware and host). This prevents large latencies in an output-only stream with a potentially huge buffer and a fast data generator, which would otherwise keep the hardware buffer filled to capacity. See also the "Hardware Buffering=off" option in the AudioScience WAV driver. */ HW32 outputBufferCap; /** Sample buffer (halfway station between HPI and buffer processor) */ HW8 *tempBuffer; /** Sample buffer size, in bytes */ HW32 tempBufferSize; } PaAsiHpiStreamComponent; /** Stream data */ typedef struct PaAsiHpiStream { /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ PaUtilStreamRepresentation baseStreamRep; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ /** Separate structs for input and output sides of stream */ PaAsiHpiStreamComponent *input, *output; /** Polling interval (in milliseconds) */ HW32 pollingInterval; /** Are we running in callback mode? */ int callbackMode; /** Number of frames to transfer at a time to/from HPI */ unsigned long maxFramesPerHostBuffer; /** Indicates that the stream is in the paNeverDropInput mode */ int neverDropInput; /** Contains copy of user buffers, used by blocking interface to transfer non-interleaved data. It went here instead of to each stream component, as the stream component buffer setup in PaAsiHpi_SetupBuffers doesn't know the stream details such as callbackMode. (Maybe a problem later if ReadStream and WriteStream happens concurrently on same stream.) */ void **blockingUserBufferCopy; /* Thread-related variables */ /** Helper thread which will deliver data to user callback */ PaUnixThread thread; /** PortAudio stream state (Active/Stopped/CallbackFinished) */ volatile sig_atomic_t state; /** Hard abort, i.e. drop frames? */ volatile sig_atomic_t callbackAbort; /** True if stream stopped via exiting callback with paComplete/paAbort flag (as opposed to explicit call to StopStream/AbortStream) */ volatile sig_atomic_t callbackFinished; } PaAsiHpiStream; /** Stream state information, collected together for convenience */ typedef struct PaAsiHpiStreamInfo { /** HPI stream state (HPI_STATE_STOPPED, HPI_STATE_PLAYING, etc.) */ HW16 state; /** Size (in bytes) of recording/playback data buffer in HPI driver */ HW32 bufferSize; /** Amount of data (in bytes) available in the buffer */ HW32 dataSize; /** Number of frames played/recorded since last stream reset */ HW32 frameCounter; /** Amount of data (in bytes) in hardware (on-card) buffer. This differs from dataSize if bus mastering (BBM) is used, which introduces another driver-level buffer to which dataSize/bufferSize then refers. */ HW32 auxDataSize; /** Total number of data frames currently buffered by HPI driver (host + hw buffers) */ HW32 totalBufferedData; /** Size of immediately available data (for input) or space (for output) in frames. This only checks the first-level buffer (typically host buffer). This amount can be transferred immediately. */ HW32 availableFrames; /** Indicates that hardware buffer is getting too full */ int overflow; /** Indicates that hardware buffer is getting too empty */ int underflow; } PaAsiHpiStreamInfo; /* -------------------------------------------------------------------------- */ /* * Function prototypes */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* The only exposed function in the entire host API implementation */ PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); /* Stream prototypes */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream **s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream *s ); static PaError StartStream( PaStream *s ); static PaError StopStream( PaStream *s ); static PaError AbortStream( PaStream *s ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *s ); static PaTime GetStreamTime( PaStream *s ); static double GetStreamCpuLoad( PaStream *s ); /* Blocking prototypes */ static PaError ReadStream( PaStream *s, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream *s ); static signed long GetStreamWriteAvailable( PaStream *s ); /* Callback prototypes */ static void *CallbackThreadFunc( void *userData ); /* Functions specific to this API */ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ); static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ); static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat ); static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters, double sampleRate, PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat ); static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, HPI_HISTREAM *hpiStream ); static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, HPI_HOSTREAM *hpiStream ); static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ); static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream ); static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ); static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ); static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ); static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ); static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ); static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ); static void PaAsiHpi_OnThreadExit( void *userData ); static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, PaStreamCallbackFlags *cbFlags ); static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ); static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream* stream, unsigned long* numFrames, PaStreamCallbackFlags *cbFlags ); static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, PaStreamCallbackFlags *cbFlags ); /* ========================================================================== * ============================= IMPLEMENTATION ============================= * ========================================================================== */ /* --------------------------- Host API Interface --------------------------- */ /** Enumerate all PA devices (= HPI streams). This compiles a list of all HPI adapters, and registers a PA device for each input and output stream it finds. Most errors are ignored, as missing or erroneous devices are simply skipped. @param hpiHostApi Pointer to HPI host API struct @return PortAudio error code (only paInsufficientMemory in practice) */ static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ) { PaError result = paNoError; PaUtilHostApiRepresentation *hostApi = &hpiHostApi->baseHostApiRep; PaHostApiInfo *baseApiInfo = &hostApi->info; PaAsiHpiDeviceInfo *hpiDeviceList; HW16 adapterList[ HPI_MAX_ADAPTERS ]; HW16 numAdapters; HW16 hpiError = 0; int i, j, deviceCount = 0, deviceIndex = 0; assert( hpiHostApi ); assert( hpiHostApi->subSys ); /* Look for adapters (not strictly necessary, as AdapterOpen can do the same, but this */ /* way we have less errors since we do not try to open adapters we know aren't there) */ /* Errors not considered critical here (subsystem may report 0 devices), but report them */ /* in debug mode. */ PA_ASIHPI_UNLESS_( HPI_SubSysFindAdapters( hpiHostApi->subSys, &numAdapters, adapterList, HPI_MAX_ADAPTERS ), paNoError ); /* First open and count the number of devices (= number of streams), to ease memory allocation */ for( i=0; i < HPI_MAX_ADAPTERS; ++i ) { HW16 inStreams, outStreams; HW16 version; HW32 serial; HW16 type; /* If no adapter found at this index, skip it */ if( adapterList[i] == 0 ) continue; /* Try to open adapter */ hpiError = HPI_AdapterOpen( hpiHostApi->subSys, i ); /* Report error and skip to next device on failure */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); continue; } hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, &outStreams, &inStreams, &version, &serial, &type ); /* Skip to next device on failure */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); continue; } else { /* Assign default devices if available and increment device count */ if( (baseApiInfo->defaultInputDevice == paNoDevice) && (inStreams > 0) ) baseApiInfo->defaultInputDevice = deviceCount; deviceCount += inStreams; if( (baseApiInfo->defaultOutputDevice == paNoDevice) && (outStreams > 0) ) baseApiInfo->defaultOutputDevice = deviceCount; deviceCount += outStreams; } } /* Register any discovered devices */ if( deviceCount > 0 ) { /* Memory allocation */ PA_UNLESS_( hostApi->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory( hpiHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ), paInsufficientMemory ); /* Allocate all device info structs in a contiguous block */ PA_UNLESS_( hpiDeviceList = (PaAsiHpiDeviceInfo*) PaUtil_GroupAllocateMemory( hpiHostApi->allocations, sizeof(PaAsiHpiDeviceInfo) * deviceCount ), paInsufficientMemory ); /* Now query devices again for information */ for( i=0; i < HPI_MAX_ADAPTERS; ++i ) { HW16 inStreams, outStreams; HW16 version; HW32 serial; HW16 type; /* If no adapter found at this index, skip it */ if( adapterList[i] == 0 ) continue; /* Assume adapter is still open from previous round */ hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, &outStreams, &inStreams, &version, &serial, &type ); /* Report error and skip to next device on failure */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); continue; } else { PA_DEBUG(( "Found HPI Adapter ID=%4X Idx=%d #In=%d #Out=%d S/N=%d HWver=%c%d DSPver=%03d\n", type, i, inStreams, outStreams, serial, ((version>>3)&0xf)+'A', /* Hw version major */ version&0x7, /* Hw version minor */ ((version>>13)*100)+((version>>7)&0x3f) /* DSP code version */ )); } /* First add all input streams as devices */ for( j=0; j < inStreams; ++j ) { PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; char srcName[72]; char *deviceName; memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); /* Set implementation-specific device details */ hpiDevice->subSys = hpiHostApi->subSys; hpiDevice->adapterIndex = i; hpiDevice->adapterType = type; hpiDevice->adapterVersion = version; hpiDevice->adapterSerialNumber = serial; hpiDevice->streamIndex = j; hpiDevice->streamIsOutput = 0; /* Set common PortAudio device stats */ baseDeviceInfo->structVersion = 2; /* Make sure name string is owned by API info structure */ sprintf( srcName, "Adapter %d (%4X) - Input Stream %d", i+1, type, j+1 ); PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); strcpy( deviceName, srcName ); baseDeviceInfo->name = deviceName; baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; baseDeviceInfo->maxInputChannels = HPI_MAX_CHANNELS; baseDeviceInfo->maxOutputChannels = 0; /* Default latency values for interactive performance */ baseDeviceInfo->defaultLowInputLatency = 0.01; baseDeviceInfo->defaultLowOutputLatency = -1.0; /* Default latency values for robust non-interactive applications (eg. playing sound files) */ baseDeviceInfo->defaultHighInputLatency = 0.2; baseDeviceInfo->defaultHighOutputLatency = -1.0; /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, * so this default is as good as any */ baseDeviceInfo->defaultSampleRate = 44100; /* Store device in global PortAudio list */ hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; } /* Now add all output streams as devices (I know, the repetition is painful) */ for( j=0; j < outStreams; ++j ) { PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; char srcName[72]; char *deviceName; memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); /* Set implementation-specific device details */ hpiDevice->subSys = hpiHostApi->subSys; hpiDevice->adapterIndex = i; hpiDevice->adapterType = type; hpiDevice->adapterVersion = version; hpiDevice->adapterSerialNumber = serial; hpiDevice->streamIndex = j; hpiDevice->streamIsOutput = 1; /* Set common PortAudio device stats */ baseDeviceInfo->structVersion = 2; /* Make sure name string is owned by API info structure */ sprintf( srcName, "Adapter %d (%4X) - Output Stream %d", i+1, type, j+1 ); PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); strcpy( deviceName, srcName ); baseDeviceInfo->name = deviceName; baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; baseDeviceInfo->maxInputChannels = 0; baseDeviceInfo->maxOutputChannels = HPI_MAX_CHANNELS; /* Default latency values for interactive performance. */ baseDeviceInfo->defaultLowInputLatency = -1.0; baseDeviceInfo->defaultLowOutputLatency = 0.01; /* Default latency values for robust non-interactive applications (eg. playing sound files). */ baseDeviceInfo->defaultHighInputLatency = -1.0; baseDeviceInfo->defaultHighOutputLatency = 0.2; /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, * so this default is as good as any */ baseDeviceInfo->defaultSampleRate = 44100; /* Store device in global PortAudio list */ hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; } } } /* Finally acknowledge checked devices */ baseApiInfo->deviceCount = deviceIndex; error: return result; } /** Initialize host API implementation. This is the only function exported beyond this file. It is called by PortAudio to initialize the host API. It stores API info, finds and registers all devices, and sets up callback and blocking interfaces. @param hostApi Pointer to host API struct @param hostApiIndex Index of current (HPI) host API @return PortAudio error code */ PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; PaAsiHpiHostApiRepresentation *hpiHostApi = NULL; PaHostApiInfo *baseApiInfo; /* Allocate host API structure */ PA_UNLESS_( hpiHostApi = (PaAsiHpiHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaAsiHpiHostApiRepresentation) ), paInsufficientMemory ); PA_UNLESS_( hpiHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); hpiHostApi->hostApiIndex = hostApiIndex; hpiHostApi->subSys = NULL; /* Try to initialize HPI subsystem */ if( ( hpiHostApi->subSys = HPI_SubSysCreate() ) == NULL) { /* the V19 development docs say that if an implementation * detects that it cannot be used, it should return a NULL * interface and paNoError */ PA_DEBUG(( "Could not open HPI interface\n" )); result = paNoError; *hostApi = NULL; goto error; } else { HW32 hpiVersion; PA_ASIHPI_UNLESS_( HPI_SubSysGetVersion( hpiHostApi->subSys, &hpiVersion ), paUnanticipatedHostError ); PA_DEBUG(( "HPI interface v%d.%02d\n", hpiVersion >> 8, 10*((hpiVersion & 0xF0) >> 4) + (hpiVersion & 0x0F) )); } *hostApi = &hpiHostApi->baseHostApiRep; baseApiInfo = &((*hostApi)->info); /* Fill in common API details */ baseApiInfo->structVersion = 1; baseApiInfo->type = paAudioScienceHPI; baseApiInfo->name = "AudioScience HPI"; baseApiInfo->deviceCount = 0; baseApiInfo->defaultInputDevice = paNoDevice; baseApiInfo->defaultOutputDevice = paNoDevice; PA_ENSURE_( PaAsiHpi_BuildDeviceList( hpiHostApi ) ); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &hpiHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &hpiHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); /* Store identity of main thread */ PA_ENSURE_( PaUnixThreading_Initialize() ); return result; error: /* Clean up memory */ Terminate( (PaUtilHostApiRepresentation *)hpiHostApi ); return result; } /** Terminate host API implementation. This closes all HPI adapters and frees the HPI subsystem. It also frees the host API struct memory. It should be called once for every PaAsiHpi_Initialize call. @param Pointer to host API struct */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; int i; PaError result = paNoError; if( hpiHostApi ) { /* Get rid of HPI-specific structures */ if( hpiHostApi->subSys ) { HW16 lastAdapterIndex = HPI_MAX_ADAPTERS; /* Iterate through device list and close adapters */ for( i=0; i < hostApi->info.deviceCount; ++i ) { PaAsiHpiDeviceInfo *hpiDevice = (PaAsiHpiDeviceInfo *) hostApi->deviceInfos[ i ]; /* Close adapter only if it differs from previous one */ if( hpiDevice->adapterIndex != lastAdapterIndex ) { /* Ignore errors (report only during debugging) */ PA_ASIHPI_UNLESS_( HPI_AdapterClose( hpiHostApi->subSys, hpiDevice->adapterIndex ), paNoError ); lastAdapterIndex = hpiDevice->adapterIndex; } } /* Finally dismantle HPI subsystem */ HPI_SubSysFree( hpiHostApi->subSys ); } if( hpiHostApi->allocations ) { PaUtil_FreeAllAllocations( hpiHostApi->allocations ); PaUtil_DestroyAllocationGroup( hpiHostApi->allocations ); } PaUtil_FreeMemory( hpiHostApi ); } error: return; } /** Converts PortAudio sample format to equivalent HPI format. @param paFormat PortAudio sample format @return HPI sample format */ static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ) { /* Ignore interleaving flag */ switch( paFormat & ~paNonInterleaved ) { case paFloat32: return HPI_FORMAT_PCM32_FLOAT; case paInt32: return HPI_FORMAT_PCM32_SIGNED; case paInt24: return HPI_FORMAT_PCM24_SIGNED; case paInt16: return HPI_FORMAT_PCM16_SIGNED; case paUInt8: return HPI_FORMAT_PCM8_UNSIGNED; /* Default is 16-bit signed */ case paInt8: default: return HPI_FORMAT_PCM16_SIGNED; } } /** Converts HPI sample format to equivalent PortAudio format. @param paFormat HPI sample format @return PortAudio sample format */ static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat ) { switch( hpiFormat ) { case HPI_FORMAT_PCM32_FLOAT: return paFloat32; case HPI_FORMAT_PCM32_SIGNED: return paInt32; case HPI_FORMAT_PCM24_SIGNED: return paInt24; case HPI_FORMAT_PCM16_SIGNED: return paInt16; case HPI_FORMAT_PCM8_UNSIGNED: return paUInt8; /* Default is custom format (e.g. for HPI MP3 format) */ default: return paCustomFormat; } } /** Creates HPI format struct based on PortAudio parameters. This also does some checks to see whether the desired format is valid, and whether the device allows it. This only checks the format of one half (input or output) of the PortAudio stream. @param hostApi Pointer to host API struct @param parameters Pointer to stream parameter struct @param sampleRate Desired sample rate @param hpiDevice Pointer to HPI device struct @param hpiFormat Resulting HPI format returned here @return PortAudio error code (typically indicating a problem with stream format) */ static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters, double sampleRate, PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat ) { int maxChannelCount = 0; PaSampleFormat hostSampleFormat = 0; HW16 hpiError = 0; /* Unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( parameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; else { assert( parameters->device < hostApi->info.deviceCount ); *hpiDevice = (PaAsiHpiDeviceInfo*) hostApi->deviceInfos[ parameters->device ]; } /* Validate streamInfo - this implementation doesn't use custom stream info */ if( parameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* Check that device can support channel count */ if( (*hpiDevice)->streamIsOutput ) { maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxOutputChannels; } else { maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxInputChannels; } if( (maxChannelCount == 0) || (parameters->channelCount > maxChannelCount) ) return paInvalidChannelCount; /* All standard sample formats are supported by the buffer adapter, and this implementation doesn't support any custom sample formats */ if( parameters->sampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* Switch to closest HPI native format */ hostSampleFormat = PaUtil_SelectClosestAvailableFormat(PA_ASIHPI_AVAILABLE_FORMATS_, parameters->sampleFormat ); /* Setup format + info objects */ hpiError = HPI_FormatCreate( hpiFormat, (HW16)parameters->channelCount, PaAsiHpi_PaToHpiFormat( hostSampleFormat ), (HW32)sampleRate, 0, 0 ); if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); switch( hpiError ) { case HPI_ERROR_INVALID_FORMAT: return paSampleFormatNotSupported; case HPI_ERROR_INVALID_SAMPLERATE: case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: return paInvalidSampleRate; case HPI_ERROR_INVALID_CHANNELS: return paInvalidChannelCount; } } return paNoError; } /** Open HPI input stream with given format. This attempts to open HPI input stream with desired format. If the format is not supported or the device is unavailable, the stream is closed and a PortAudio error code is returned. @param hostApi Pointer to host API struct @param hpiDevice Pointer to HPI device struct @param hpiFormat Pointer to HPI format struct @return PortAudio error code (typically indicating a problem with stream format or device) */ static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, HPI_HISTREAM *hpiStream ) { PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; PaError result = paNoError; HW16 hpiError = 0; /* Catch misplaced output devices, as they typically have 0 input channels */ PA_UNLESS_( !hpiDevice->streamIsOutput, paInvalidChannelCount ); /* Try to open input stream */ PA_ASIHPI_UNLESS_( HPI_InStreamOpen( hpiHostApi->subSys, hpiDevice->adapterIndex, hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); /* Set input format (checking it in the process) */ /* Could also use HPI_InStreamQueryFormat, but this economizes the process */ hpiError = HPI_InStreamSetFormat( hpiHostApi->subSys, *hpiStream, (HPI_FORMAT*)hpiFormat ); if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); PA_ASIHPI_UNLESS_( HPI_InStreamClose( hpiHostApi->subSys, *hpiStream ), paNoError ); switch( hpiError ) { case HPI_ERROR_INVALID_FORMAT: return paSampleFormatNotSupported; case HPI_ERROR_INVALID_SAMPLERATE: case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: return paInvalidSampleRate; case HPI_ERROR_INVALID_CHANNELS: return paInvalidChannelCount; default: /* In case anything else went wrong */ return paInvalidDevice; } } error: return result; } /** Open HPI output stream with given format. This attempts to open HPI output stream with desired format. If the format is not supported or the device is unavailable, the stream is closed and a PortAudio error code is returned. @param hostApi Pointer to host API struct @param hpiDevice Pointer to HPI device struct @param hpiFormat Pointer to HPI format struct @return PortAudio error code (typically indicating a problem with stream format or device) */ static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, HPI_HOSTREAM *hpiStream ) { PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; PaError result = paNoError; HW16 hpiError = 0; /* Catch misplaced input devices, as they typically have 0 output channels */ PA_UNLESS_( hpiDevice->streamIsOutput, paInvalidChannelCount ); /* Try to open output stream */ PA_ASIHPI_UNLESS_( HPI_OutStreamOpen( hpiHostApi->subSys, hpiDevice->adapterIndex, hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); /* Check output format (format is set on first write to output stream) */ hpiError = HPI_OutStreamQueryFormat( hpiHostApi->subSys, *hpiStream, (HPI_FORMAT*)hpiFormat ); if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); PA_ASIHPI_UNLESS_( HPI_OutStreamClose( hpiHostApi->subSys, *hpiStream ), paNoError ); switch( hpiError ) { case HPI_ERROR_INVALID_FORMAT: return paSampleFormatNotSupported; case HPI_ERROR_INVALID_SAMPLERATE: case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: return paInvalidSampleRate; case HPI_ERROR_INVALID_CHANNELS: return paInvalidChannelCount; default: /* In case anything else went wrong */ return paInvalidDevice; } } error: return result; } /** Checks whether the desired stream formats and devices are supported (for both input and output). This is done by actually opening the appropriate HPI streams and closing them again. @param hostApi Pointer to host API struct @param inputParameters Pointer to stream parameter struct for input side of stream @param outputParameters Pointer to stream parameter struct for output side of stream @param sampleRate Desired sample rate @return PortAudio error code (paFormatIsSupported on success) */ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { PaError result = paFormatIsSupported; PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; PaAsiHpiDeviceInfo *hpiDevice = NULL; HPI_FORMAT hpiFormat; /* Input stream */ if( inputParameters ) { HPI_HISTREAM hpiStream; PA_DEBUG(( "%s: Checking input params: dev=%d, sr=%d, chans=%d, fmt=%d\n", __FUNCTION__, inputParameters->device, (int)sampleRate, inputParameters->channelCount, inputParameters->sampleFormat )); /* Create and validate format */ PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, &hpiDevice, &hpiFormat ) ); /* Open stream to further check format */ PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); /* Close stream again */ PA_ASIHPI_UNLESS_( HPI_InStreamClose( hpiHostApi->subSys, hpiStream ), paNoError ); } /* Output stream */ if( outputParameters ) { HPI_HOSTREAM hpiStream; PA_DEBUG(( "%s: Checking output params: dev=%d, sr=%d, chans=%d, fmt=%d\n", __FUNCTION__, outputParameters->device, (int)sampleRate, outputParameters->channelCount, outputParameters->sampleFormat )); /* Create and validate format */ PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, &hpiDevice, &hpiFormat ) ); /* Open stream to further check format */ PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); /* Close stream again */ PA_ASIHPI_UNLESS_( HPI_OutStreamClose( hpiHostApi->subSys, hpiStream ), paNoError ); } error: return result; } /* ---------------------------- Stream Interface ---------------------------- */ /** Obtain HPI stream information. This obtains info such as stream state and available data/space in buffers. It also estimates whether an underflow or overflow occurred. @param streamComp Pointer to stream component (input or output) to query @param info Pointer to stream info struct that will contain result @return PortAudio error code (either paNoError, paDeviceUnavailable or paUnanticipatedHostError) */ static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ) { PaError result = paDeviceUnavailable; HW16 state; HW32 bufferSize, dataSize, frameCounter, auxDataSize, threshold; HW32 hwBufferSize, hwDataSize; assert( streamComp ); assert( info ); /* First blank the stream info struct, in case something goes wrong below. This saves the caller from initializing the struct. */ info->state = 0; info->bufferSize = 0; info->dataSize = 0; info->frameCounter = 0; info->auxDataSize = 0; info->totalBufferedData = 0; info->availableFrames = 0; info->underflow = 0; info->overflow = 0; if( streamComp->hpiDevice && streamComp->hpiStream ) { /* Obtain detailed stream info (either input or output) */ if( streamComp->hpiDevice->streamIsOutput ) { PA_ASIHPI_UNLESS_( HPI_OutStreamGetInfoEx( streamComp->hpiDevice->subSys, streamComp->hpiStream, &state, &bufferSize, &dataSize, &frameCounter, &auxDataSize ), paUnanticipatedHostError ); } else { PA_ASIHPI_UNLESS_( HPI_InStreamGetInfoEx( streamComp->hpiDevice->subSys, streamComp->hpiStream, &state, &bufferSize, &dataSize, &frameCounter, &auxDataSize ), paUnanticipatedHostError ); } /* Load stream info */ info->state = state; info->bufferSize = bufferSize; info->dataSize = dataSize; info->frameCounter = frameCounter; info->auxDataSize = auxDataSize; /* Determine total buffered data */ info->totalBufferedData = dataSize; if( streamComp->hostBufferSize > 0 ) info->totalBufferedData += auxDataSize; info->totalBufferedData /= streamComp->bytesPerFrame; /* Determine immediately available frames */ info->availableFrames = streamComp->hpiDevice->streamIsOutput ? bufferSize - dataSize : dataSize; info->availableFrames /= streamComp->bytesPerFrame; /* Minimum space/data required in buffers */ threshold = PA_MIN( streamComp->tempBufferSize, streamComp->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_ ); /* Obtain hardware buffer stats first, to simplify things */ hwBufferSize = streamComp->hardwareBufferSize; hwDataSize = streamComp->hostBufferSize > 0 ? auxDataSize : dataSize; /* Underflow is a bit tricky */ info->underflow = streamComp->hpiDevice->streamIsOutput ? /* Stream seems to start in drained state sometimes, so ignore initial underflow */ (frameCounter > 0) && ( (state == HPI_STATE_DRAINED) || (hwDataSize == 0) ) : /* Input streams check the first-level (host) buffer for underflow */ (state != HPI_STATE_STOPPED) && (dataSize < threshold); /* Check for overflow in second-level (hardware) buffer for both input and output */ info->overflow = (state != HPI_STATE_STOPPED) && (hwBufferSize - hwDataSize < threshold); return paNoError; } error: return result; } /** Display stream component information for debugging purposes. @param streamComp Pointer to stream component (input or output) to query @param stream Pointer to stream struct which contains the component above */ static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream ) { PaAsiHpiStreamInfo streamInfo; assert( streamComp ); assert( stream ); /* Name of soundcard/device used by component */ PA_DEBUG(( "device: %s\n", streamComp->hpiDevice->baseDeviceInfo.name )); /* Unfortunately some overlap between input and output here */ if( streamComp->hpiDevice->streamIsOutput ) { /* Settings on the user side (as experienced by user callback) */ PA_DEBUG(( "user: %d-bit, %d ", 8*stream->bufferProcessor.bytesPerUserOutputSample, stream->bufferProcessor.outputChannelCount)); if( stream->bufferProcessor.userOutputIsInterleaved ) { PA_DEBUG(( "interleaved channels, " )); } else { PA_DEBUG(( "non-interleaved channels, " )); } PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", stream->bufferProcessor.framesPerUserBuffer, 1000*stream->baseStreamRep.streamInfo.outputLatency )); /* Settings on the host side (internal to PortAudio host API) */ PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", 8*stream->bufferProcessor.bytesPerHostOutputSample, stream->bufferProcessor.outputChannelCount, stream->bufferProcessor.framesPerHostBuffer )); } else { /* Settings on the user side (as experienced by user callback) */ PA_DEBUG(( "user: %d-bit, %d ", 8*stream->bufferProcessor.bytesPerUserInputSample, stream->bufferProcessor.inputChannelCount)); if( stream->bufferProcessor.userInputIsInterleaved ) { PA_DEBUG(( "interleaved channels, " )); } else { PA_DEBUG(( "non-interleaved channels, " )); } PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", stream->bufferProcessor.framesPerUserBuffer, 1000*stream->baseStreamRep.streamInfo.inputLatency )); /* Settings on the host side (internal to PortAudio host API) */ PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", 8*stream->bufferProcessor.bytesPerHostInputSample, stream->bufferProcessor.inputChannelCount, stream->bufferProcessor.framesPerHostBuffer )); } switch( stream->bufferProcessor.hostBufferSizeMode ) { case paUtilFixedHostBufferSize: PA_DEBUG(( "[fixed] " )); break; case paUtilBoundedHostBufferSize: PA_DEBUG(( "[bounded] " )); break; case paUtilUnknownHostBufferSize: PA_DEBUG(( "[unknown] " )); break; case paUtilVariableHostBufferSizePartialUsageAllowed: PA_DEBUG(( "[variable] " )); break; } PA_DEBUG(( "(%d max)\n", streamComp->tempBufferSize / streamComp->bytesPerFrame )); /* HPI hardware settings */ PA_DEBUG(( "HPI: adapter %d stream %d, %d-bit, %d-channel, %d Hz\n", streamComp->hpiDevice->adapterIndex, streamComp->hpiDevice->streamIndex, 8 * streamComp->bytesPerFrame / streamComp->hpiFormat.wChannels, streamComp->hpiFormat.wChannels, streamComp->hpiFormat.dwSampleRate )); /* Stream state and buffer levels */ PA_DEBUG(( "HPI: " )); PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ); switch( streamInfo.state ) { case HPI_STATE_STOPPED: PA_DEBUG(( "[STOPPED] " )); break; case HPI_STATE_PLAYING: PA_DEBUG(( "[PLAYING] " )); break; case HPI_STATE_RECORDING: PA_DEBUG(( "[RECORDING] " )); break; case HPI_STATE_DRAINED: PA_DEBUG(( "[DRAINED] " )); break; default: PA_DEBUG(( "[unknown state] " )); break; } if( streamComp->hostBufferSize ) { PA_DEBUG(( "host = %d/%d B, ", streamInfo.dataSize, streamComp->hostBufferSize )); PA_DEBUG(( "hw = %d/%d (%d) B, ", streamInfo.auxDataSize, streamComp->hardwareBufferSize, streamComp->outputBufferCap )); } else { PA_DEBUG(( "hw = %d/%d B, ", streamInfo.dataSize, streamComp->hardwareBufferSize )); } PA_DEBUG(( "count = %d", streamInfo.frameCounter )); if( streamInfo.overflow ) { PA_DEBUG(( " [overflow]" )); } else if( streamInfo.underflow ) { PA_DEBUG(( " [underflow]" )); } PA_DEBUG(( "\n" )); } /** Display stream information for debugging purposes. @param stream Pointer to stream to query */ static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ) { assert( stream ); PA_DEBUG(( "\n------------------------- STREAM INFO FOR %p ---------------------------\n", stream )); /* General stream info (input+output) */ if( stream->baseStreamRep.streamCallback ) { PA_DEBUG(( "[callback] " )); } else { PA_DEBUG(( "[blocking] " )); } PA_DEBUG(( "sr=%d Hz, poll=%d ms, max %d frames/buf ", (int)stream->baseStreamRep.streamInfo.sampleRate, stream->pollingInterval, stream->maxFramesPerHostBuffer )); switch( stream->state ) { case paAsiHpiStoppedState: PA_DEBUG(( "[stopped]\n" )); break; case paAsiHpiActiveState: PA_DEBUG(( "[active]\n" )); break; case paAsiHpiCallbackFinishedState: PA_DEBUG(( "[cb fin]\n" )); break; default: PA_DEBUG(( "[unknown state]\n" )); break; } if( stream->callbackMode ) { PA_DEBUG(( "cb info: thread=%p, cbAbort=%d, cbFinished=%d\n", stream->thread.thread, stream->callbackAbort, stream->callbackFinished )); } PA_DEBUG(( "----------------------------------- Input ------------------------------------\n" )); if( stream->input ) { PaAsiHpi_StreamComponentDump( stream->input, stream ); } else { PA_DEBUG(( "*none*\n" )); } PA_DEBUG(( "----------------------------------- Output ------------------------------------\n" )); if( stream->output ) { PaAsiHpi_StreamComponentDump( stream->output, stream ); } else { PA_DEBUG(( "*none*\n" )); } PA_DEBUG(( "-------------------------------------------------------------------------------\n\n" )); } /** Determine buffer sizes and allocate appropriate stream buffers. This attempts to allocate a BBM (host) buffer for the HPI stream component (either input or output, as both have similar buffer needs). Not all AudioScience adapters support BBM, in which case the hardware buffer has to suffice. The size of the HPI host buffer is chosen as a multiple of framesPerPaHostBuffer, and also influenced by the suggested latency and the estimated minimum polling interval. The HPI host and hardware buffer sizes are stored, and an appropriate cap for the hardware buffer is also calculated. Finally, the temporary stream buffer which serves as the PortAudio host buffer for this implementation is allocated. This buffer contains an integer number of user buffers, to simplify buffer adaption in the buffer processor. The function returns paBufferTooBig if the HPI interface cannot allocate an HPI host buffer of the desired size. @param streamComp Pointer to stream component struct @param pollingInterval Polling interval for stream, in milliseconds @param framesPerPaHostBuffer Size of PortAudio host buffer, in frames @param suggestedLatency Suggested latency for stream component, in seconds @return PortAudio error code (possibly paBufferTooBig or paInsufficientMemory) */ static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ) { PaError result = paNoError; PaAsiHpiStreamInfo streamInfo; unsigned long hpiBufferSize = 0, paHostBufferSize = 0; assert( streamComp ); assert( streamComp->hpiDevice ); /* Obtain size of hardware buffer of HPI stream, since we will be activating BBM shortly and afterwards the buffer size will refer to the BBM (host-side) buffer. This is necessary to enable reliable detection of xruns. */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ) ); streamComp->hardwareBufferSize = streamInfo.bufferSize; hpiBufferSize = streamInfo.bufferSize; /* Check if BBM (background bus mastering) is to be enabled */ if( PA_ASIHPI_USE_BBM_ ) { HW32 bbmBufferSize = 0, preLatencyBufferSize = 0; HW16 hpiError = 0; PaTime pollingOverhead; /* Check overhead of Pa_Sleep() call (minimum sleep duration in ms -> OS dependent) */ pollingOverhead = PaUtil_GetTime(); Pa_Sleep( 0 ); pollingOverhead = 1000*(PaUtil_GetTime() - pollingOverhead); PA_DEBUG(( "polling overhead = %f ms (length of 0-second sleep)\n", pollingOverhead )); /* Obtain minimum recommended size for host buffer (in bytes) */ PA_ASIHPI_UNLESS_( HPI_StreamEstimateBufferSize( &streamComp->hpiFormat, pollingInterval + (HW32)ceil( pollingOverhead ), &bbmBufferSize ), paUnanticipatedHostError ); /* BBM places more stringent requirements on buffer size (see description */ /* of HPI_StreamEstimateBufferSize in HPI API document) */ bbmBufferSize *= 3; /* Make sure the BBM buffer contains multiple PA host buffers */ if( bbmBufferSize < 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer ) bbmBufferSize = 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer; /* Try to honor latency suggested by user by growing buffer (no decrease possible) */ if( suggestedLatency > 0.0 ) { PaTime bufferDuration = ((PaTime)bbmBufferSize) / streamComp->bytesPerFrame / streamComp->hpiFormat.dwSampleRate; /* Don't decrease buffer */ if( bufferDuration < suggestedLatency ) { /* Save old buffer size, to be retried if new size proves too big */ preLatencyBufferSize = bbmBufferSize; bbmBufferSize = (HW32)ceil( suggestedLatency * streamComp->bytesPerFrame * streamComp->hpiFormat.dwSampleRate ); } } /* Choose closest memory block boundary (HPI API document states that "a buffer size of Nx4096 - 20 makes the best use of memory" (under the entry for HPI_StreamEstimateBufferSize)) */ bbmBufferSize = ((HW32)ceil((bbmBufferSize + 20)/4096.0))*4096 - 20; streamComp->hostBufferSize = bbmBufferSize; /* Allocate BBM host buffer (this enables bus mastering transfers in background) */ if( streamComp->hpiDevice->streamIsOutput ) hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); else hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); /* Indicate that BBM is disabled */ streamComp->hostBufferSize = 0; /* Retry with smaller buffer size (transfers will still work, but not via BBM) */ if( hpiError == HPI_ERROR_INVALID_DATASIZE ) { /* Retry BBM allocation with smaller size if requested latency proved too big */ if( preLatencyBufferSize > 0 ) { PA_DEBUG(( "Retrying BBM allocation with smaller size (%d vs. %d bytes)\n", preLatencyBufferSize, bbmBufferSize )); bbmBufferSize = preLatencyBufferSize; if( streamComp->hpiDevice->streamIsOutput ) hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); else hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); /* Another round of error checking */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); /* No escapes this time */ if( hpiError == HPI_ERROR_INVALID_DATASIZE ) { result = paBufferTooBig; goto error; } else if( hpiError != HPI_ERROR_INVALID_OPERATION ) { result = paUnanticipatedHostError; goto error; } } else { streamComp->hostBufferSize = bbmBufferSize; hpiBufferSize = bbmBufferSize; } } else { result = paBufferTooBig; goto error; } } /* If BBM not supported, foreground transfers will be used, but not a show-stopper */ /* Anything else is an error */ else if( hpiError != HPI_ERROR_INVALID_OPERATION ) { result = paUnanticipatedHostError; goto error; } } else { hpiBufferSize = bbmBufferSize; } } /* Final check of buffer size */ paHostBufferSize = streamComp->bytesPerFrame * framesPerPaHostBuffer; if( hpiBufferSize < 3*paHostBufferSize ) { result = paBufferTooBig; goto error; } /* Set cap on output buffer size, based on latency suggestions */ if( streamComp->hpiDevice->streamIsOutput ) { PaTime latency = suggestedLatency > 0.0 ? suggestedLatency : streamComp->hpiDevice->baseDeviceInfo.defaultHighOutputLatency; streamComp->outputBufferCap = (HW32)ceil( latency * streamComp->bytesPerFrame * streamComp->hpiFormat.dwSampleRate ); /* The cap should not be too small, to prevent underflow */ if( streamComp->outputBufferCap < 4*paHostBufferSize ) streamComp->outputBufferCap = 4*paHostBufferSize; } else { streamComp->outputBufferCap = 0; } /* Temp buffer size should be multiple of PA host buffer size (or 1x, if using fixed blocks) */ streamComp->tempBufferSize = paHostBufferSize; /* Allocate temp buffer */ PA_UNLESS_( streamComp->tempBuffer = (HW8 *)PaUtil_AllocateMemory( streamComp->tempBufferSize ), paInsufficientMemory ); error: return result; } /** Opens PortAudio stream. This determines a suitable value for framesPerBuffer, if the user didn't specify it, based on the suggested latency. It then opens each requested stream direction with the appropriate stream format, and allocates the required stream buffers. It sets up the various PortAudio structures dealing with streams, and estimates the stream latency. See pa_hostapi.h for a list of validity guarantees made about OpenStream parameters. @param hostApi Pointer to host API struct @param s List of open streams, where successfully opened stream will go @param inputParameters Pointer to stream parameter struct for input side of stream @param outputParameters Pointer to stream parameter struct for output side of stream @param sampleRate Desired sample rate @param framesPerBuffer Desired number of frames per buffer passed to user callback (or chunk size for blocking stream) @param streamFlags Stream flags @param streamCallback Pointer to user callback function (zero for blocking interface) @param userData Pointer to user data that will be passed to callback function along with data @return PortAudio error code */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream **s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; PaAsiHpiStream *stream = NULL; unsigned long framesPerHostBuffer = framesPerBuffer; int inputChannelCount = 0, outputChannelCount = 0; PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; PaTime maxSuggestedLatency = 0.0; /* Validate platform-specific flags -> none expected for HPI */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform-specific flag */ /* Create blank stream structure */ PA_UNLESS_( stream = (PaAsiHpiStream *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStream) ), paInsufficientMemory ); memset( stream, 0, sizeof(PaAsiHpiStream) ); /* If the number of frames per buffer is unspecified, we have to come up with one. */ if( framesPerHostBuffer == paFramesPerBufferUnspecified ) { if( inputParameters ) maxSuggestedLatency = inputParameters->suggestedLatency; if( outputParameters && (outputParameters->suggestedLatency > maxSuggestedLatency) ) maxSuggestedLatency = outputParameters->suggestedLatency; /* Use suggested latency if available */ if( maxSuggestedLatency > 0.0 ) framesPerHostBuffer = (unsigned long)ceil( maxSuggestedLatency * sampleRate ); else /* AudioScience cards like BIG buffers by default */ framesPerHostBuffer = 4096; } /* Lower bounds on host buffer size, due to polling and HPI constraints */ if( 1000.0*framesPerHostBuffer/sampleRate < PA_ASIHPI_MIN_POLLING_INTERVAL_ ) framesPerHostBuffer = (unsigned long)ceil( sampleRate * PA_ASIHPI_MIN_POLLING_INTERVAL_ / 1000.0 ); /* if( framesPerHostBuffer < PA_ASIHPI_MIN_FRAMES_ ) framesPerHostBuffer = PA_ASIHPI_MIN_FRAMES_; */ /* Efficient if host buffer size is integer multiple of user buffer size */ if( framesPerBuffer > 0 ) framesPerHostBuffer = (unsigned long)ceil( (double)framesPerHostBuffer / framesPerBuffer ) * framesPerBuffer; /* Buffer should always be a multiple of 4 bytes to facilitate 32-bit PCI transfers. By keeping the frames a multiple of 4, this is ensured even for 8-bit mono sound. */ framesPerHostBuffer = (framesPerHostBuffer / 4) * 4; /* Polling is based on time length (in milliseconds) of user-requested block size */ stream->pollingInterval = (HW32)ceil( 1000.0*framesPerHostBuffer/sampleRate ); assert( framesPerHostBuffer > 0 ); /* Open underlying streams, check formats and allocate buffers */ if( inputParameters ) { /* Create blank stream component structure */ PA_UNLESS_( stream->input = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), paInsufficientMemory ); memset( stream->input, 0, sizeof(PaAsiHpiStreamComponent) ); /* Create/validate format */ PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, &stream->input->hpiDevice, &stream->input->hpiFormat ) ); /* Open stream and set format */ PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, stream->input->hpiDevice, &stream->input->hpiFormat, &stream->input->hpiStream ) ); inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; hostInputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); stream->input->bytesPerFrame = inputChannelCount * Pa_GetSampleSize( hostInputSampleFormat ); assert( stream->input->bytesPerFrame > 0 ); /* Allocate host and temp buffers of appropriate size */ PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->input, stream->pollingInterval, framesPerHostBuffer, inputParameters->suggestedLatency ) ); } if( outputParameters ) { /* Create blank stream component structure */ PA_UNLESS_( stream->output = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), paInsufficientMemory ); memset( stream->output, 0, sizeof(PaAsiHpiStreamComponent) ); /* Create/validate format */ PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, &stream->output->hpiDevice, &stream->output->hpiFormat ) ); /* Open stream and check format */ PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, stream->output->hpiDevice, &stream->output->hpiFormat, &stream->output->hpiStream ) ); outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; hostOutputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->output->hpiFormat.wFormat ); stream->output->bytesPerFrame = outputChannelCount * Pa_GetSampleSize( hostOutputSampleFormat ); /* Allocate host and temp buffers of appropriate size */ PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->output, stream->pollingInterval, framesPerHostBuffer, outputParameters->suggestedLatency ) ); } /* Determine maximum frames per host buffer (least common denominator of input/output) */ if( inputParameters && outputParameters ) { stream->maxFramesPerHostBuffer = PA_MIN( stream->input->tempBufferSize / stream->input->bytesPerFrame, stream->output->tempBufferSize / stream->output->bytesPerFrame ); } else { stream->maxFramesPerHostBuffer = inputParameters ? stream->input->tempBufferSize / stream->input->bytesPerFrame : stream->output->tempBufferSize / stream->output->bytesPerFrame; } assert( stream->maxFramesPerHostBuffer > 0 ); /* Initialize various other stream parameters */ stream->neverDropInput = streamFlags & paNeverDropInput; stream->state = paAsiHpiStoppedState; /* Initialize either callback or blocking interface */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, &hpiHostApi->callbackStreamInterface, streamCallback, userData ); stream->callbackMode = 1; } else { PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, &hpiHostApi->blockingStreamInterface, streamCallback, userData ); /* Pre-allocate non-interleaved user buffer pointers for blocking interface */ PA_UNLESS_( stream->blockingUserBufferCopy = PaUtil_AllocateMemory( sizeof(void *) * PA_MAX( inputChannelCount, outputChannelCount ) ), paInsufficientMemory ); stream->callbackMode = 0; } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); /* Following pa_linux_alsa's lead, we operate with fixed host buffer size by default, */ /* since other modes will invariably lead to block adaption (maybe Bounded better?) */ PA_ENSURE_( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, streamCallback, userData ) ); stream->baseStreamRep.streamInfo.structVersion = 1; stream->baseStreamRep.streamInfo.sampleRate = sampleRate; /* Determine input latency from buffer processor and buffer sizes */ if( stream->input ) { PaTime bufferDuration = ( stream->input->hostBufferSize + stream->input->hardwareBufferSize ) / sampleRate / stream->input->bytesPerFrame; stream->baseStreamRep.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) + bufferDuration - stream->maxFramesPerHostBuffer / sampleRate; assert( stream->baseStreamRep.streamInfo.inputLatency > 0.0 ); } /* Determine output latency from buffer processor and buffer sizes */ if( stream->output ) { PaTime bufferDuration = ( stream->output->hostBufferSize + stream->output->hardwareBufferSize ) / sampleRate / stream->output->bytesPerFrame; /* Take buffer size cap into account (see PaAsiHpi_WaitForFrames) */ if( !stream->input && (stream->output->outputBufferCap > 0) ) { bufferDuration = PA_MIN( bufferDuration, stream->output->outputBufferCap / sampleRate / stream->output->bytesPerFrame ); } stream->baseStreamRep.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) + bufferDuration - stream->maxFramesPerHostBuffer / sampleRate; assert( stream->baseStreamRep.streamInfo.outputLatency > 0.0 ); } /* Report stream info, for debugging purposes */ PaAsiHpi_StreamDump( stream ); /* Save initialized stream to PA stream list */ *s = (PaStream*)stream; return result; error: CloseStream( (PaStream*)stream ); return result; } /** Close PortAudio stream. When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. This closes the underlying HPI streams and deallocates stream buffers and structs. @param s Pointer to PortAudio stream @return PortAudio error code */ static PaError CloseStream( PaStream *s ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream*)s; /* If stream is already gone, all is well */ if( stream == NULL ) return paNoError; /* Generic stream cleanup */ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->baseStreamRep ); /* Implementation-specific details - close internal streams */ if( stream->input ) { /* Close HPI stream (freeing BBM host buffer in the process, if used) */ if( stream->input->hpiStream ) { PA_ASIHPI_UNLESS_( HPI_InStreamClose( stream->input->hpiDevice->subSys, stream->input->hpiStream ), paUnanticipatedHostError ); } /* Free temp buffer and stream component */ PaUtil_FreeMemory( stream->input->tempBuffer ); PaUtil_FreeMemory( stream->input ); } if( stream->output ) { /* Close HPI stream (freeing BBM host buffer in the process, if used) */ if( stream->output->hpiStream ) { PA_ASIHPI_UNLESS_( HPI_OutStreamClose( stream->output->hpiDevice->subSys, stream->output->hpiStream ), paUnanticipatedHostError ); } /* Free temp buffer and stream component */ PaUtil_FreeMemory( stream->output->tempBuffer ); PaUtil_FreeMemory( stream->output ); } PaUtil_FreeMemory( stream->blockingUserBufferCopy ); PaUtil_FreeMemory( stream ); error: return result; } /** Prime HPI output stream with silence. This resets the output stream and uses PortAudio helper routines to fill the temp buffer with silence. It then writes two host buffers to the stream. This is supposed to be called before the stream is started. It has no effect on input-only streams. @param stream Pointer to stream struct @return PortAudio error code */ static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ) { PaError result = paNoError; PaAsiHpiStreamComponent *out; PaUtilZeroer *zeroer; PaSampleFormat outputFormat; HPI_DATA data; assert( stream ); out = stream->output; /* Only continue if stream has output channels */ if( !out ) return result; assert( out->tempBuffer ); /* Clear all existing data in hardware playback buffer */ PA_ASIHPI_UNLESS_( HPI_OutStreamReset( out->hpiDevice->subSys, out->hpiStream ), paUnanticipatedHostError ); /* Fill temp buffer with silence */ outputFormat = PaAsiHpi_HpiToPaFormat( out->hpiFormat.wFormat ); zeroer = PaUtil_SelectZeroer( outputFormat ); zeroer(out->tempBuffer, 1, out->tempBufferSize / Pa_GetSampleSize(outputFormat) ); /* Write temp buffer to hardware fifo twice, to get started */ PA_ASIHPI_UNLESS_( HPI_DataCreate( &data, &out->hpiFormat, out->tempBuffer, out->tempBufferSize ), paUnanticipatedHostError ); PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( out->hpiDevice->subSys, out->hpiStream, &data ), paUnanticipatedHostError ); PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( out->hpiDevice->subSys, out->hpiStream, &data ), paUnanticipatedHostError ); error: return result; } /** Start HPI streams (both input + output). This starts all HPI streams in the PortAudio stream. Output streams are first primed with silence, if required. After this call the PA stream is in the Active state. @todo Implement priming via the user callback @param stream Pointer to stream struct @param outputPrimed True if output is already primed (if false, silence will be loaded before starting) @return PortAudio error code */ static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ) { PaError result = paNoError; if( stream->input ) { PA_ASIHPI_UNLESS_( HPI_InStreamStart( stream->input->hpiDevice->subSys, stream->input->hpiStream ), paUnanticipatedHostError ); } if( stream->output ) { if( !outputPrimed ) { /* Buffer isn't primed, so load stream with silence */ PA_ENSURE_( PaAsiHpi_PrimeOutputWithSilence( stream ) ); } PA_ASIHPI_UNLESS_( HPI_OutStreamStart( stream->output->hpiDevice->subSys, stream->output->hpiStream ), paUnanticipatedHostError ); } stream->state = paAsiHpiActiveState; stream->callbackFinished = 0; /* Report stream info for debugging purposes */ /* PaAsiHpi_StreamDump( stream ); */ error: return result; } /** Start PortAudio stream. If the stream has a callback interface, this starts a helper thread to feed the user callback. The thread will then take care of starting the HPI streams, and this function will block until the streams actually start. In the case of a blocking interface, the HPI streams are simply started. @param s Pointer to PortAudio stream @return PortAudio error code */ static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream*)s; assert( stream ); /* Ready the processor */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); if( stream->callbackMode ) { /* Create and start callback engine thread */ /* Also waits 1 second for stream to be started by engine thread (otherwise aborts) */ PA_ENSURE_( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., 0 ) ); } else { PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); } error: return result; } /** Stop HPI streams (input + output), either softly or abruptly. If abort is false, the function blocks until the output stream is drained, otherwise it stops immediately and discards data in the stream hardware buffers. This function is safe to call from the callback engine thread as well as the main thread. @param stream Pointer to stream struct @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) @return PortAudio error code */ static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ) { PaError result = paNoError; assert( stream ); /* Input channels */ if( stream->input ) { PA_ASIHPI_UNLESS_( HPI_InStreamReset( stream->input->hpiDevice->subSys, stream->input->hpiStream ), paUnanticipatedHostError ); } /* Output channels */ if( stream->output ) { if( !abort ) { /* Wait until HPI output stream is drained */ while( 1 ) { PaAsiHpiStreamInfo streamInfo; PaTime timeLeft; /* Obtain number of samples waiting to be played */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ) ); /* Check if stream is drained */ if( (streamInfo.state != HPI_STATE_PLAYING) && (streamInfo.dataSize < stream->output->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_) ) break; /* Sleep amount of time represented by remaining samples */ timeLeft = 1000.0 * streamInfo.dataSize / stream->output->bytesPerFrame / stream->baseStreamRep.streamInfo.sampleRate; Pa_Sleep( (long)ceil( timeLeft ) ); } } PA_ASIHPI_UNLESS_( HPI_OutStreamReset( stream->output->hpiDevice->subSys, stream->output->hpiStream ), paUnanticipatedHostError ); } /* Report stream info for debugging purposes */ /* PaAsiHpi_StreamDump( stream ); */ error: return result; } /** Stop or abort PortAudio stream. This function is used to explicitly stop the PortAudio stream (via StopStream/AbortStream), as opposed to the situation when the callback finishes with a result other than paContinue. If a stream is in callback mode we will have to inspect whether the background thread has finished, or we will have to take it out. In either case we join the thread before returning. In blocking mode, we simply tell HPI to stop abruptly (abort) or finish buffers (drain). The PortAudio stream will be in the Stopped state after a call to this function. Don't call this from the callback engine thread! @param stream Pointer to stream struct @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) @return PortAudio error code */ static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ) { PaError result = paNoError; /* First deal with the callback thread, cancelling and/or joining it if necessary */ if( stream->callbackMode ) { PaError threadRes; stream->callbackAbort = abort; if( abort ) { PA_DEBUG(( "Aborting callback\n" )); } else { PA_DEBUG(( "Stopping callback\n" )); } PA_ENSURE_( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) ); if( threadRes != paNoError ) { PA_DEBUG(( "Callback thread returned: %d\n", threadRes )); } } else { PA_ENSURE_( PaAsiHpi_StopStream( stream, abort ) ); } stream->state = paAsiHpiStoppedState; error: return result; } /** Stop PortAudio stream. This blocks until the output buffers are drained. @param s Pointer to PortAudio stream @return PortAudio error code */ static PaError StopStream( PaStream *s ) { return PaAsiHpi_ExplicitStop( (PaAsiHpiStream *) s, 0 ); } /** Abort PortAudio stream. This discards any existing data in output buffers and stops the stream immediately. @param s Pointer to PortAudio stream @return PortAudio error code */ static PaError AbortStream( PaStream *s ) { return PaAsiHpi_ExplicitStop( (PaAsiHpiStream * ) s, 1 ); } /** Determine whether the stream is stopped. A stream is considered to be stopped prior to a successful call to StartStream and after a successful call to StopStream or AbortStream. If a stream callback returns a value other than paContinue the stream is NOT considered to be stopped (it is in CallbackFinished state). @param s Pointer to PortAudio stream @return Returns one (1) when the stream is stopped, zero (0) when the stream is running, or a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. */ static PaError IsStreamStopped( PaStream *s ) { PaAsiHpiStream *stream = (PaAsiHpiStream*)s; assert( stream ); return stream->state == paAsiHpiStoppedState ? 1 : 0; } /** Determine whether the stream is active. A stream is active after a successful call to StartStream(), until it becomes inactive either as a result of a call to StopStream() or AbortStream(), or as a result of a return value other than paContinue from the stream callback. In the latter case, the stream is considered inactive after the last buffer has finished playing. @param s Pointer to PortAudio stream @return Returns one (1) when the stream is active (i.e. playing or recording audio), zero (0) when not playing, or a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. */ static PaError IsStreamActive( PaStream *s ) { PaAsiHpiStream *stream = (PaAsiHpiStream*)s; assert( stream ); return stream->state == paAsiHpiActiveState ? 1 : 0; } /** Returns current stream time. This corresponds to the system clock. The clock should run continuously while the stream is open, i.e. between calls to OpenStream() and CloseStream(), therefore a frame counter is not good enough. @param s Pointer to PortAudio stream @return Stream time, in seconds */ static PaTime GetStreamTime( PaStream *s ) { return PaUtil_GetTime(); } /** Returns CPU load. @param s Pointer to PortAudio stream @return CPU load (0.0 if blocking interface is used) */ static double GetStreamCpuLoad( PaStream *s ) { PaAsiHpiStream *stream = (PaAsiHpiStream*)s; return stream->callbackMode ? PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) : 0.0; } /* --------------------------- Callback Interface --------------------------- */ /** Exit routine which is called when callback thread quits. This takes care of stopping the HPI streams (either waiting for output to finish, or abruptly). It also calls the user-supplied StreamFinished callback, and sets the stream state to CallbackFinished if it was reached via a non-paContinue return from the user callback function. @param userData A pointer to an open stream previously created with Pa_OpenStream */ static void PaAsiHpi_OnThreadExit( void *userData ) { PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; assert( stream ); PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); PA_DEBUG(( "%s: Stopping HPI streams\n", __FUNCTION__ )); PaAsiHpi_StopStream( stream, stream->callbackAbort ); PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ )); /* Eventually notify user all buffers have played */ if( stream->baseStreamRep.streamFinishedCallback ) { stream->baseStreamRep.streamFinishedCallback( stream->baseStreamRep.userData ); } /* Unfortunately both explicit calls to Stop/AbortStream (leading to Stopped state) and implicit stops via paComplete/paAbort (leading to CallbackFinished state) end up here - need another flag to remind us which is the case */ if( stream->callbackFinished ) stream->state = paAsiHpiCallbackFinishedState; } /** Wait until there is enough frames to fill a host buffer. The routine attempts to sleep until at least a full host buffer can be retrieved from the input HPI stream and passed to the output HPI stream. It will first sleep until enough output space is available, as this is usually easily achievable. If it is an output-only stream, it will also sleep if the hardware buffer is too full, thereby throttling the filling of the output buffer and reducing output latency. The routine then blocks until enough input samples are available, unless this will cause an output underflow. In the process, input overflows and output underflows are indicated. @param stream Pointer to stream struct @param framesAvail Returns the number of available frames @param cbFlags Overflows and underflows indicated in here @return PortAudio error code (only paUnanticipatedHostError expected) */ static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, PaStreamCallbackFlags *cbFlags ) { PaError result = paNoError; double sampleRate; unsigned long framesTarget; HW32 outputData = 0, outputSpace = 0, inputData = 0, framesLeft = 0; assert( stream ); assert( stream->input || stream->output ); sampleRate = stream->baseStreamRep.streamInfo.sampleRate; /* We have to come up with this much frames on both input and output */ framesTarget = stream->bufferProcessor.framesPerHostBuffer; assert( framesTarget > 0 ); while( 1 ) { PaAsiHpiStreamInfo info; /* Check output first, as this takes priority in the default full-duplex mode */ if( stream->output ) { PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); /* Wait until enough space is available in output buffer to receive a full block */ if( info.availableFrames < framesTarget ) { framesLeft = framesTarget - info.availableFrames; Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); continue; } /* Wait until the data in hardware buffer has dropped to a sensible level. Without this, the hardware buffer quickly fills up in the absence of an input stream to regulate its data rate (if data generation is fast). This leads to large latencies, as the AudioScience hardware buffers are humongous. This is similar to the default "Hardware Buffering=off" option in the AudioScience WAV driver. */ if( !stream->input && (stream->output->outputBufferCap > 0) && ( info.totalBufferedData > stream->output->outputBufferCap / stream->output->bytesPerFrame ) ) { framesLeft = info.totalBufferedData - stream->output->outputBufferCap / stream->output->bytesPerFrame; Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); continue; } outputData = info.totalBufferedData; outputSpace = info.availableFrames; /* Report output underflow to callback */ if( info.underflow ) { *cbFlags |= paOutputUnderflow; } } /* Now check input side */ if( stream->input ) { PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); /* If a full block of samples hasn't been recorded yet, wait for it if possible */ if( info.availableFrames < framesTarget ) { framesLeft = framesTarget - info.availableFrames; /* As long as output is not disrupted in the process, wait for a full block of input samples */ if( !stream->output || (outputData > framesLeft) ) { Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); continue; } } inputData = info.availableFrames; /** @todo The paInputOverflow flag should be set in the callback containing the first input sample following the overflow. That means the block currently sitting at the fore-front of recording, i.e. typically the one containing the newest (last) sample in the HPI buffer system. This is most likely not the same as the current block of data being passed to the callback. The current overflow should ideally be noted in an overflow list of sorts, with an indication of when it should be reported. The trouble starts if there are several separate overflow incidents, given a big input buffer. Oh well, something to try out later... */ if( info.overflow ) { *cbFlags |= paInputOverflow; } } break; } /* Full-duplex stream */ if( stream->input && stream->output ) { if( outputSpace >= framesTarget ) *framesAvail = outputSpace; /* If input didn't make the target, keep the output count instead (input underflow) */ if( (inputData >= framesTarget) && (inputData < outputSpace) ) *framesAvail = inputData; } else { *framesAvail = stream->input ? inputData : outputSpace; } error: return result; } /** Obtain recording, current and playback timestamps of stream. The current time is determined by the system clock. This "now" timestamp occurs at the forefront of recording (and playback in the full-duplex case), which happens later than the input timestamp by an amount equal to the total number of recorded frames in the input buffer. The output timestamp indicates when the next generated sample will actually be played. This happens after all the samples currently in the output buffer are played. The output timestamp therefore follows the current timestamp by an amount equal to the number of frames yet to be played back in the output buffer. If the current timestamp is the present, the input timestamp is in the past and the output timestamp is in the future. @param stream Pointer to stream struct @param timeInfo Pointer to timeInfo struct that will contain timestamps */ static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ) { PaAsiHpiStreamInfo streamInfo; double sampleRate; assert( stream ); assert( timeInfo ); sampleRate = stream->baseStreamRep.streamInfo.sampleRate; /* The current time ("now") is at the forefront of both recording and playback */ timeInfo->currentTime = GetStreamTime( (PaStream *)stream ); /* The last sample in the input buffer was recorded just now, so the first sample happened (number of recorded samples)/sampleRate ago */ timeInfo->inputBufferAdcTime = timeInfo->currentTime; if( stream->input ) { PaAsiHpi_GetStreamInfo( stream->input, &streamInfo ); timeInfo->inputBufferAdcTime -= streamInfo.totalBufferedData / sampleRate; } /* The first of the outgoing samples will be played after all the samples in the output buffer is done */ timeInfo->outputBufferDacTime = timeInfo->currentTime; if( stream->output ) { PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ); timeInfo->outputBufferDacTime += streamInfo.totalBufferedData / sampleRate; } } /** Read from HPI input stream and register buffers. This reads data from the HPI input stream (if it exists) and registers the temp stream buffers of both input and output streams with the buffer processor. In the process it also handles input underflows in the full-duplex case. @param stream Pointer to stream struct @param numFrames On entrance the number of available frames, on exit the number of received frames @param cbFlags Indicates overflows and underflows @return PortAudio error code */ static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream *stream, unsigned long *numFrames, PaStreamCallbackFlags *cbFlags ) { PaError result = paNoError; assert( stream ); if( *numFrames > stream->maxFramesPerHostBuffer ) *numFrames = stream->maxFramesPerHostBuffer; if( stream->input ) { PaAsiHpiStreamInfo info; HPI_DATA data; HW32 framesToGet = *numFrames; /* Check for overflows and underflows yet again */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); if( info.overflow ) { *cbFlags |= paInputOverflow; } /* Input underflow if less than expected number of samples pitch up */ if( framesToGet > info.availableFrames ) { PaUtilZeroer *zeroer; PaSampleFormat inputFormat; /* Never call an input-only stream with InputUnderflow set */ if( stream->output ) *cbFlags |= paInputUnderflow; framesToGet = info.availableFrames; /* Fill temp buffer with silence (to make up for missing input samples) */ inputFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); zeroer = PaUtil_SelectZeroer( inputFormat ); zeroer(stream->input->tempBuffer, 1, stream->input->tempBufferSize / Pa_GetSampleSize(inputFormat) ); } /* Setup HPI data structure around temp buffer */ HPI_DataCreate( &data, &stream->input->hpiFormat, stream->input->tempBuffer, framesToGet * stream->input->bytesPerFrame ); /* Read block of data into temp buffer */ PA_ASIHPI_UNLESS_( HPI_InStreamRead( stream->input->hpiDevice->subSys, stream->input->hpiStream, &data ), paUnanticipatedHostError ); /* Register temp buffer with buffer processor (always FULL buffer) */ PaUtil_SetInputFrameCount( &stream->bufferProcessor, *numFrames ); /* HPI interface only allows interleaved channels */ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->input->tempBuffer, stream->input->hpiFormat.wChannels ); } if( stream->output ) { /* Register temp buffer with buffer processor */ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, *numFrames ); /* HPI interface only allows interleaved channels */ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->output->tempBuffer, stream->output->hpiFormat.wChannels ); } error: return result; } /** Flush output buffers to HPI output stream. This completes the processing cycle by writing the temp buffer to the HPI interface. Additional output underflows are caught before data is written to the stream, as this action typically remedies the underflow and hides it in the process. @param stream Pointer to stream struct @param numFrames The number of frames to write to the output stream @param cbFlags Indicates overflows and underflows */ static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, PaStreamCallbackFlags *cbFlags ) { PaError result = paNoError; assert( stream ); if( stream->output ) { PaAsiHpiStreamInfo info; HPI_DATA data; /* Check for underflows after the (potentially time-consuming) callback */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); if( info.underflow ) { *cbFlags |= paOutputUnderflow; } /* Setup HPI data structure around temp buffer */ HPI_DataCreate( &data, &stream->output->hpiFormat, stream->output->tempBuffer, numFrames * stream->output->bytesPerFrame ); /* Write temp buffer to HPI stream */ PA_ASIHPI_UNLESS_( HPI_OutStreamWrite( stream->output->hpiDevice->subSys, stream->output->hpiStream, &data ), paUnanticipatedHostError ); } error: return result; } /** Main callback engine. This function runs in a separate thread and does all the work of fetching audio data from the AudioScience card via the HPI interface, feeding it to the user callback via the buffer processor, and delivering the resulting output data back to the card via HPI calls. It is started and terminated when the PortAudio stream is started and stopped, and starts the HPI streams on startup. @param userData A pointer to an open stream previously created with Pa_OpenStream. */ static void *CallbackThreadFunc( void *userData ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; int callbackResult = paContinue; assert( stream ); /* Cleanup routine stops streams on thread exit */ pthread_cleanup_push( &PaAsiHpi_OnThreadExit, stream ); /* Start HPI streams and notify parent when we're done */ PA_ENSURE_( PaUnixThread_PrepareNotify( &stream->thread ) ); /* Buffer will be primed with silence */ PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); PA_ENSURE_( PaUnixThread_NotifyParent( &stream->thread ) ); /* MAIN LOOP */ while( 1 ) { PaStreamCallbackFlags cbFlags = 0; unsigned long framesAvail, framesGot; pthread_testcancel(); /** @concern StreamStop if the main thread has requested a stop and the stream has not * been effectively stopped we signal this condition by modifying callbackResult * (we'll want to flush buffered output). */ if( PaUnixThread_StopRequested( &stream->thread ) && (callbackResult == paContinue) ) { PA_DEBUG(( "Setting callbackResult to paComplete\n" )); callbackResult = paComplete; } /* Start winding down thread if requested */ if( callbackResult != paContinue ) { stream->callbackAbort = (callbackResult == paAbort); if( stream->callbackAbort || /** @concern BlockAdaption: Go on if adaption buffers are empty */ PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) { goto end; } PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ )); /* There is still buffered output that needs to be processed */ } /* SLEEP */ /* Wait for data (or buffer space) to become available. This basically sleeps and polls the HPI interface until a full block of frames can be moved. */ PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the data from the HPI interface and pass it to the PA buffer processor. We should be prepared to process several chunks successively. */ while( framesAvail > 0 ) { PaStreamCallbackTimeInfo timeInfo = {0, 0, 0}; pthread_testcancel(); framesGot = framesAvail; if( stream->bufferProcessor.hostBufferSizeMode == paUtilFixedHostBufferSize ) { /* We've committed to a fixed host buffer size, stick to that */ framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0; } else { /* We've committed to an upper bound on the size of host buffers */ assert( stream->bufferProcessor.hostBufferSizeMode == paUtilBoundedHostBufferSize ); framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer ); } /* Obtain buffer timestamps */ PaAsiHpi_CalculateTimeInfo( stream, &timeInfo ); PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); /* CPU load measurement should include processing activivity external to the stream callback */ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); if( framesGot > 0 ) { /* READ FROM HPI INPUT STREAM */ PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); /* Input overflow in a full-duplex stream makes for interesting times */ if( stream->input && stream->output && (cbFlags & paInputOverflow) ) { /* Special full-duplex paNeverDropInput mode */ if( stream->neverDropInput ) { PaUtil_SetNoOutput( &stream->bufferProcessor ); cbFlags |= paOutputOverflow; } } /* CALL USER CALLBACK WITH INPUT DATA, AND OBTAIN OUTPUT DATA */ PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); /* Clear overflow and underflow information (but PaAsiHpi_EndProcessing might still show up output underflow that will carry over to next round) */ cbFlags = 0; /* WRITE TO HPI OUTPUT STREAM */ PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); /* Advance frame counter */ framesAvail -= framesGot; } PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot ); if( framesGot == 0 ) { /* Go back to polling for more frames */ break; } if( callbackResult != paContinue ) break; } } /* This code is unreachable, but important to include regardless because it * is possibly a macro with a closing brace to match the opening brace in * pthread_cleanup_push() above. The documentation states that they must * always occur in pairs. */ pthread_cleanup_pop( 1 ); end: /* Indicates normal exit of callback, as opposed to the thread getting killed explicitly */ stream->callbackFinished = 1; PA_DEBUG(( "%s: Thread %d exiting (callbackResult = %d)\n ", __FUNCTION__, pthread_self(), callbackResult )); /* Exit from thread and report any PortAudio error in the process */ PaUnixThreading_EXIT( result ); error: goto end; } /* --------------------------- Blocking Interface --------------------------- */ /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ /** Read data from input stream. This reads the indicated number of frames into the supplied buffer from an input stream, and blocks until this is done. @param s Pointer to PortAudio stream @param buffer Pointer to buffer that will receive interleaved data (or an array of pointers to a buffer for each non-interleaved channel) @param frames Number of frames to read from stream @return PortAudio error code (also indicates overflow via paInputOverflowed) */ static PaError ReadStream( PaStream *s, void *buffer, unsigned long frames ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream*)s; PaAsiHpiStreamInfo info; void *userBuffer; assert( stream ); PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); /* Check for input overflow since previous call to ReadStream */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); if( info.overflow ) { result = paInputOverflowed; } /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ if( stream->bufferProcessor.userInputIsInterleaved ) { userBuffer = buffer; } else { /* Copy channels into local array */ userBuffer = stream->blockingUserBufferCopy; memcpy( userBuffer, buffer, sizeof (void *) * stream->input->hpiFormat.wChannels ); } while( frames > 0 ) { unsigned long framesGot, framesAvail; PaStreamCallbackFlags cbFlags = 0; PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); framesGot = PA_MIN( framesAvail, frames ); PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); if( framesGot > 0 ) { framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot ); PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); /* Advance frame counter */ frames -= framesGot; } } error: return result; } /** Write data to output stream. This writes the indicated number of frames from the supplied buffer to an output stream, and blocks until this is done. @param s Pointer to PortAudio stream @param buffer Pointer to buffer that provides interleaved data (or an array of pointers to a buffer for each non-interleaved channel) @param frames Number of frames to write to stream @return PortAudio error code (also indicates underflow via paOutputUnderflowed) */ static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream*)s; PaAsiHpiStreamInfo info; const void *userBuffer; assert( stream ); PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); /* Check for output underflow since previous call to WriteStream */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); if( info.underflow ) { result = paOutputUnderflowed; } /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ if( stream->bufferProcessor.userOutputIsInterleaved ) { userBuffer = buffer; } else { /* Copy channels into local array */ userBuffer = stream->blockingUserBufferCopy; memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->output->hpiFormat.wChannels ); } while( frames > 0 ) { unsigned long framesGot, framesAvail; PaStreamCallbackFlags cbFlags = 0; PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); framesGot = PA_MIN( framesAvail, frames ); PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); if( framesGot > 0 ) { framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot ); PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); /* Advance frame counter */ frames -= framesGot; } } error: return result; } /** Number of frames that can be read from input stream without blocking. @param s Pointer to PortAudio stream @return Number of frames, or PortAudio error code */ static signed long GetStreamReadAvailable( PaStream *s ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream*)s; PaAsiHpiStreamInfo info; assert( stream ); PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); /* Round down to the nearest host buffer multiple */ result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; if( info.overflow ) { result = paInputOverflowed; } error: return result; } /** Number of frames that can be written to output stream without blocking. @param s Pointer to PortAudio stream @return Number of frames, or PortAudio error code */ static signed long GetStreamWriteAvailable( PaStream *s ) { PaError result = paNoError; PaAsiHpiStream *stream = (PaAsiHpiStream*)s; PaAsiHpiStreamInfo info; assert( stream ); PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); /* Round down to the nearest host buffer multiple */ result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; if( info.underflow ) { result = paOutputUnderflowed; } error: return result; } nyquist-3.05/portaudio/src/hostapi/wasapi/0002755000175000000620000000000011537433131017716 5ustar stevestaffnyquist-3.05/portaudio/src/hostapi/wasapi/pa_win_wasapi.cpp0000644000175000000620000020235711466723256023265 0ustar stevestaff/* * Portable Audio I/O Library WASAPI implementation * Copyright (c) 2006-2007 David Viens * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup hostaip_src @brief WASAPI implementation of support for a host API. @note pa_wasapi currently requires VC 2005, and the latest Vista SDK */ #if _MSC_VER >= 1400 #include #include //must be before other Wasapi headers #include #include #include #include #include #include #include // PKEY_Device_FriendlyName #endif #include "pa_util.h" #include "pa_allocation.h" #include "pa_hostapi.h" #include "pa_stream.h" #include "pa_cpuload.h" #include "pa_process.h" #include "pa_debugprint.h" /* davidv : work in progress. try using with 48000 , then 44100 and shared mode FIRST. */ #define PORTAUDIO_SHAREMODE AUDCLNT_SHAREMODE_SHARED //#define PORTAUDIO_SHAREMODE AUDCLNT_SHAREMODE_EXCLUSIVE /* prototypes for functions declared in this file */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); static PaError AbortStream( PaStream *stream ); static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* IMPLEMENT ME: a macro like the following one should be used for reporting host errors */ #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) /* PaWinWasapiHostApiRepresentation - host api datastructure specific to this implementation */ //dummy entry point for other compilers and sdks //currently built using RC1 SDK (5600) #if _MSC_VER < 1400 PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){ return paNoError; } #else #define MAX_STR_LEN 512 /* These are fields that can be gathered from IDevice and IAudioDevice PRIOR to Initialize, and done in first pass i assume that neither of these will cause the Driver to "load", but again, who knows how they implement their stuff */ typedef struct PaWinWasapiDeviceInfo { //hmm is it wise to keep a reference until Terminate? //TODO Check if that interface requires the driver to be loaded! IMMDevice * device; //Fields filled from IDevice //from GetId WCHAR szDeviceID[MAX_STR_LEN]; //from GetState DWORD state; //Fields filled from IMMEndpoint'sGetDataFlow EDataFlow flow; //Fields filled from IAudioDevice (_prior_ to Initialize) //from GetDevicePeriod( REFERENCE_TIME DefaultDevicePeriod; REFERENCE_TIME MinimumDevicePeriod; //from GetMixFormat WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use! } PaWinWasapiDeviceInfo; typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ //in case we later need the synch IMMDeviceEnumerator * enumerator; //this is the REAL number of devices, whether they are usefull to PA or not! UINT deviceCount; WCHAR defaultRenderer [MAX_STR_LEN]; WCHAR defaultCapturer [MAX_STR_LEN]; PaWinWasapiDeviceInfo *devInfo; }PaWinWasapiHostApiRepresentation; /* PaWinWasapiStream - a stream data structure specifically for this implementation */ typedef struct PaWinWasapiSubStream{ IAudioClient *client; WAVEFORMATEXTENSIBLE wavex; UINT32 bufferSize; REFERENCE_TIME latency; REFERENCE_TIME period; unsigned long framesPerHostCallback; /* just an example */ }PaWinWasapiSubStream; typedef struct PaWinWasapiStream { /* IMPLEMENT ME: rename this */ PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; /* IMPLEMENT ME: - implementation specific data goes here */ //input PaWinWasapiSubStream in; IAudioCaptureClient *cclient; IAudioEndpointVolume *inVol; //output PaWinWasapiSubStream out; IAudioRenderClient *rclient; IAudioEndpointVolume *outVol; bool running; bool closeRequest; DWORD dwThreadId; HANDLE hThread; HANDLE hNotificationEvent; GUID session; }PaWinWasapiStream; #define PRINT(x) PA_DEBUG(x); void logAUDCLNT_E(HRESULT res){ char *text = 0; switch(res){ case S_OK: return; break; case E_POINTER :text ="E_POINTER"; break; case E_INVALIDARG :text ="E_INVALIDARG"; break; case AUDCLNT_E_NOT_INITIALIZED :text ="AUDCLNT_E_NOT_INITIALIZED"; break; case AUDCLNT_E_ALREADY_INITIALIZED :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break; case AUDCLNT_E_WRONG_ENDPOINT_TYPE :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; case AUDCLNT_E_DEVICE_INVALIDATED :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break; case AUDCLNT_E_NOT_STOPPED :text ="AUDCLNT_E_NOT_STOPPED"; break; case AUDCLNT_E_BUFFER_TOO_LARGE :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break; case AUDCLNT_E_OUT_OF_ORDER :text ="AUDCLNT_E_OUT_OF_ORDER"; break; case AUDCLNT_E_UNSUPPORTED_FORMAT :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break; case AUDCLNT_E_INVALID_SIZE :text ="AUDCLNT_E_INVALID_SIZE"; break; case AUDCLNT_E_DEVICE_IN_USE :text ="AUDCLNT_E_DEVICE_IN_USE"; break; case AUDCLNT_E_BUFFER_OPERATION_PENDING :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; case AUDCLNT_E_THREAD_NOT_REGISTERED :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break; case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; case AUDCLNT_E_ENDPOINT_CREATE_FAILED :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; case AUDCLNT_E_SERVICE_NOT_RUNNING :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break; // case AUDCLNT_E_CPUUSAGE_EXCEEDED :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break; //Header error? case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; case AUDCLNT_E_EXCLUSIVE_MODE_ONLY :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; case AUDCLNT_E_EVENTHANDLE_NOT_SET :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; case AUDCLNT_E_INCORRECT_BUFFER_SIZE :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; case AUDCLNT_E_BUFFER_SIZE_ERROR :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break; case AUDCLNT_S_BUFFER_EMPTY :text ="AUDCLNT_S_BUFFER_EMPTY"; break; case AUDCLNT_S_THREAD_ALREADY_REGISTERED :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; default: text =" dunno!"; return ; break; } PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n",res,text)); } inline double nano100ToMillis(const REFERENCE_TIME &ref){ // 1 nano = 0.000000001 seconds //100 nano = 0.0000001 seconds //100 nano = 0.0001 milliseconds return ((double)ref)*0.0001; } inline double nano100ToSeconds(const REFERENCE_TIME &ref){ // 1 nano = 0.000000001 seconds //100 nano = 0.0000001 seconds //100 nano = 0.0001 milliseconds return ((double)ref)*0.0000001; } #ifndef IF_FAILED_JUMP #define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label; #endif //AVRT is the new "multimedia schedulling stuff" typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCTSTR,LPDWORD); typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY); HMODULE hDInputDLL = 0; FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup=0; FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup=0; FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup=0; FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics=0; FAvSetMmThreadPriority pAvSetMmThreadPriority=0; #define setupPTR(fun, type, name) { \ fun = (type) GetProcAddress(hDInputDLL,name); \ if(fun == NULL) { \ PRINT(("GetProcAddr failed for %s" ,name)); \ return false; \ } \ } \ bool setupAVRT(){ hDInputDLL = LoadLibraryA("avrt.dll"); if(hDInputDLL == NULL) return false; setupPTR(pAvRtCreateThreadOrderingGroup, FAvRtCreateThreadOrderingGroup, "AvRtCreateThreadOrderingGroup"); setupPTR(pAvRtDeleteThreadOrderingGroup, FAvRtDeleteThreadOrderingGroup, "AvRtDeleteThreadOrderingGroup"); setupPTR(pAvRtWaitOnThreadOrderingGroup, FAvRtWaitOnThreadOrderingGroup, "AvRtWaitOnThreadOrderingGroup"); setupPTR(pAvSetMmThreadCharacteristics, FAvSetMmThreadCharacteristics, "AvSetMmThreadCharacteristicsA"); setupPTR(pAvSetMmThreadPriority, FAvSetMmThreadPriority, "AvSetMmThreadPriority"); return true; } PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { if (!setupAVRT()){ PRINT(("Windows WASAPI : No AVRT! (not VISTA?)")); return paNoError; } CoInitialize(NULL); PaError result = paNoError; PaWinWasapiHostApiRepresentation *paWasapi; PaDeviceInfo *deviceInfoArray; paWasapi = (PaWinWasapiHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWasapiHostApiRepresentation) ); if( !paWasapi ){ result = paInsufficientMemory; goto error; } paWasapi->allocations = PaUtil_CreateAllocationGroup(); if( !paWasapi->allocations ){ result = paInsufficientMemory; goto error; } *hostApi = &paWasapi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paWASAPI; (*hostApi)->info.name = "Windows WASAPI"; (*hostApi)->info.deviceCount = 0; //so far, we must investigate each (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ HRESULT hResult = S_OK; IMMDeviceCollection* spEndpoints=0; paWasapi->enumerator = 0; hResult = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&paWasapi->enumerator); IF_FAILED_JUMP(hResult, error); //getting default device ids in the eMultimedia "role" { { IMMDevice* defaultRenderer=0; hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &defaultRenderer); IF_FAILED_JUMP(hResult, error); WCHAR* pszDeviceId = NULL; hResult = defaultRenderer->GetId(&pszDeviceId); IF_FAILED_JUMP(hResult, error); StringCchCopyW(paWasapi->defaultRenderer, MAX_STR_LEN-1, pszDeviceId); CoTaskMemFree(pszDeviceId); defaultRenderer->Release(); } { IMMDevice* defaultCapturer=0; hResult = paWasapi->enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &defaultCapturer); IF_FAILED_JUMP(hResult, error); WCHAR* pszDeviceId = NULL; hResult = defaultCapturer->GetId(&pszDeviceId); IF_FAILED_JUMP(hResult, error); StringCchCopyW(paWasapi->defaultCapturer, MAX_STR_LEN-1, pszDeviceId); CoTaskMemFree(pszDeviceId); defaultCapturer->Release(); } } hResult = paWasapi->enumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spEndpoints); IF_FAILED_JUMP(hResult, error); hResult = spEndpoints->GetCount(&paWasapi->deviceCount); IF_FAILED_JUMP(hResult, error); paWasapi->devInfo = new PaWinWasapiDeviceInfo[paWasapi->deviceCount]; { for (size_t step=0;stepdeviceCount;++step) memset(&paWasapi->devInfo[step],0,sizeof(PaWinWasapiDeviceInfo)); } if( paWasapi->deviceCount > 0 ) { (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( paWasapi->allocations, sizeof(PaDeviceInfo*) * paWasapi->deviceCount ); if( !(*hostApi)->deviceInfos ){ result = paInsufficientMemory; goto error; } /* allocate all device info structs in a contiguous block */ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount ); if( !deviceInfoArray ){ result = paInsufficientMemory; goto error; } for( UINT i=0; i < paWasapi->deviceCount; ++i ){ PA_DEBUG(("i:%d\n",i)); PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; hResult = spEndpoints->Item(i, &paWasapi->devInfo[i].device); IF_FAILED_JUMP(hResult, error); //getting ID { WCHAR* pszDeviceId = NULL; hResult = paWasapi->devInfo[i].device->GetId(&pszDeviceId); IF_FAILED_JUMP(hResult, error); StringCchCopyW(paWasapi->devInfo[i].szDeviceID, MAX_STR_LEN-1, pszDeviceId); CoTaskMemFree(pszDeviceId); if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer)==0){ //we found the default input! (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; } if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer)==0){ //we found the default output! (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; } } DWORD state=0; hResult = paWasapi->devInfo[i].device->GetState(&paWasapi->devInfo[i].state); IF_FAILED_JUMP(hResult, error); if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE){ PRINT(("WASAPI device:%d is not currently available (state:%d)\n",i,state)); //spDevice->Release(); //continue; } { IPropertyStore* spProperties; hResult = paWasapi->devInfo[i].device->OpenPropertyStore(STGM_READ, &spProperties); IF_FAILED_JUMP(hResult, error); //getting "Friendly" Name { PROPVARIANT value; PropVariantInit(&value); hResult = spProperties->GetValue(PKEY_Device_FriendlyName, &value); IF_FAILED_JUMP(hResult, error); deviceInfo->name = 0; char* deviceName = (char*)PaUtil_GroupAllocateMemory( paWasapi->allocations, MAX_STR_LEN + 1 ); if( !deviceName ){ result = paInsufficientMemory; goto error; } if (value.pwszVal) wcstombs(deviceName, value.pwszVal,MAX_STR_LEN-1); //todo proper size else{ sprintf(deviceName,"baddev%d",i); } deviceInfo->name = deviceName; PropVariantClear(&value); } #if 0 DWORD numProps = 0; hResult = spProperties->GetCount(&numProps); IF_FAILED_JUMP(hResult, error); { for (DWORD i=0;iGetAt(i,&pkey); PROPVARIANT value; PropVariantInit(&value); hResult = spProperties->GetValue(pkey, &value); switch(value.vt){ case 11: PRINT(("property*%u*\n",value.ulVal)); break; case 19: PRINT(("property*%d*\n",value.boolVal)); break; case 31: { char temp[512]; wcstombs(temp, value.pwszVal,MAX_STR_LEN-1); PRINT(("property*%s*\n",temp)); } break; default:break; } PropVariantClear(&value); } } #endif /* These look interresting... but they are undocumented PKEY_AudioEndpoint_FormFactor PKEY_AudioEndpoint_ControlPanelPageProvider PKEY_AudioEndpoint_Association PKEY_AudioEndpoint_PhysicalSpeakerConfig PKEY_AudioEngine_DeviceFormat */ spProperties->Release(); } //getting the Endpoint data { IMMEndpoint *endpoint=0; hResult = paWasapi->devInfo[i].device->QueryInterface(__uuidof(IMMEndpoint),(void **)&endpoint); if (SUCCEEDED(hResult)){ hResult = endpoint->GetDataFlow(&paWasapi->devInfo[i].flow); endpoint->Release(); } } //Getting a temporary IAudioDevice for more fields //we make sure NOT to call Initialize yet! { IAudioClient *myClient=0; hResult = paWasapi->devInfo[i].device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); IF_FAILED_JUMP(hResult, error); hResult = myClient->GetDevicePeriod( &paWasapi->devInfo[i].DefaultDevicePeriod, &paWasapi->devInfo[i].MinimumDevicePeriod); IF_FAILED_JUMP(hResult, error); hResult = myClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat); if (hResult != S_OK){ /*davidv: this happened with my hardware, previously for that same device in DirectSound: Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f} so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat*/ logAUDCLNT_E(hResult); goto error; } myClient->Release(); } //we can now fill in portaudio device data deviceInfo->maxInputChannels = 0; //for now deviceInfo->maxOutputChannels = 0; //for now switch(paWasapi->devInfo[i].flow){ case eRender: //hum not exaclty maximum, more like "default" deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat->nChannels; deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); deviceInfo->defaultLowOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); break; case eCapture: //hum not exaclty maximum, more like "default" deviceInfo->maxInputChannels = paWasapi->devInfo[i].MixFormat->nChannels; deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); deviceInfo->defaultLowInputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); break; default: PRINT(("WASAPI device:%d bad Data FLow! \n",i)); goto error; break; } deviceInfo->defaultSampleRate = (double)paWasapi->devInfo[i].MixFormat->nSamplesPerSec; (*hostApi)->deviceInfos[i] = deviceInfo; ++(*hostApi)->info.deviceCount; } } spEndpoints->Release(); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); return result; error: if (spEndpoints) spEndpoints->Release(); if (paWasapi->enumerator) paWasapi->enumerator->Release(); if( paWasapi ) { if( paWasapi->allocations ) { PaUtil_FreeAllAllocations( paWasapi->allocations ); PaUtil_DestroyAllocationGroup( paWasapi->allocations ); } PaUtil_FreeMemory( paWasapi ); } return result; } static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; paWasapi->enumerator->Release(); for (UINT i=0;ideviceCount;++i){ PaWinWasapiDeviceInfo *info = &paWasapi->devInfo[i]; if (info->device) info->device->Release(); if (info->MixFormat) CoTaskMemFree(info->MixFormat); } delete [] paWasapi->devInfo; CoUninitialize(); if( paWasapi->allocations ){ PaUtil_FreeAllAllocations( paWasapi->allocations ); PaUtil_DestroyAllocationGroup( paWasapi->allocations ); } PaUtil_FreeMemory( paWasapi ); } static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in){ const WAVEFORMATEX *old = (WAVEFORMATEX *)in; switch (old->wFormatTag){ case WAVE_FORMAT_EXTENSIBLE:{ PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n")); if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){ PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n")); } else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){ PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n")); } else{ PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n", in->SubFormat.Data1, in->SubFormat.Data2, in->SubFormat.Data3, (int)in->SubFormat.Data4[0], (int)in->SubFormat.Data4[1], (int)in->SubFormat.Data4[2], (int)in->SubFormat.Data4[3], (int)in->SubFormat.Data4[4], (int)in->SubFormat.Data4[5], (int)in->SubFormat.Data4[6], (int)in->SubFormat.Data4[7])); } PRINT(("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample)); PRINT(("dwChannelMask=0x%X\n",in->dwChannelMask)); }break; case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break; case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break; default : PRINT(("wFormatTag=UNKNOWN(%d)\n",old->wFormatTag)); break; } PRINT(("nChannels =%d\n",old->nChannels)); PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec)); PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec)); PRINT(("nBlockAlign =%d\n",old->nBlockAlign)); PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample)); PRINT(("cbSize =%d\n",old->cbSize)); } /* WAVEFORMATXXX is always interleaved */ static PaSampleFormat waveformatToPaFormat(const WAVEFORMATEXTENSIBLE *in){ const WAVEFORMATEX *old = (WAVEFORMATEX*)in; switch (old->wFormatTag){ case WAVE_FORMAT_EXTENSIBLE: { if (in->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT){ if (in->Samples.wValidBitsPerSample == 32) return paFloat32; else return paCustomFormat; } else if (in->SubFormat == KSDATAFORMAT_SUBTYPE_PCM){ switch (old->wBitsPerSample){ case 32: return paInt32; break; case 24: return paInt24;break; case 8: return paUInt8;break; case 16: return paInt16;break; default: return paCustomFormat;break; } } else return paCustomFormat; } break; case WAVE_FORMAT_IEEE_FLOAT: return paFloat32; break; case WAVE_FORMAT_PCM: { switch (old->wBitsPerSample){ case 32: return paInt32; break; case 24: return paInt24;break; case 8: return paUInt8;break; case 16: return paInt16;break; default: return paCustomFormat;break; } } break; default: return paCustomFormat; break; } return paCustomFormat; } static PaError waveformatFromParams(WAVEFORMATEXTENSIBLE*wavex, const PaStreamParameters * params, double sampleRate){ size_t bytesPerSample = 0; switch( params->sampleFormat & ~paNonInterleaved ){ case paFloat32: case paInt32: bytesPerSample=4;break; case paInt16: bytesPerSample=2;break; case paInt24: bytesPerSample=3;break; case paInt8: case paUInt8: bytesPerSample=1;break; case paCustomFormat: default: return paSampleFormatNotSupported;break; } memset(wavex,0,sizeof(WAVEFORMATEXTENSIBLE)); WAVEFORMATEX *old = (WAVEFORMATEX *)wavex; old->nChannels = (WORD)params->channelCount; old->nSamplesPerSec = (DWORD)sampleRate; old->wBitsPerSample = (WORD)(bytesPerSample*8); old->nAvgBytesPerSec = (DWORD)(old->nSamplesPerSec * old->nChannels * bytesPerSample); old->nBlockAlign = (WORD)(old->nChannels * bytesPerSample); //WAVEFORMATEX if (params->channelCount <=2 && (bytesPerSample == 2 || bytesPerSample == 1)){ old->cbSize = 0; old->wFormatTag = WAVE_FORMAT_PCM; } //WAVEFORMATEXTENSIBLE else{ old->wFormatTag = WAVE_FORMAT_EXTENSIBLE; old->cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX); if ((params->sampleFormat & ~paNonInterleaved) == paFloat32) wavex->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; else wavex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wavex->Samples.wValidBitsPerSample = old->wBitsPerSample; //no extra padding! switch(params->channelCount){ case 1: wavex->dwChannelMask = SPEAKER_FRONT_CENTER; break; case 2: wavex->dwChannelMask = 0x1 | 0x2; break; case 4: wavex->dwChannelMask = 0x1 | 0x2 | 0x10 | 0x20; break; case 6: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20; break; case 8: wavex->dwChannelMask = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80; break; default: wavex->dwChannelMask = 0; break; } } return paNoError; } /* #define paFloat32 ((PaSampleFormat) 0x00000001) #define paInt32 ((PaSampleFormat) 0x00000002) #define paInt24 ((PaSampleFormat) 0x00000004) #define paInt16 ((PaSampleFormat) 0x00000008) */ //lifted from pa_wdmks static void wasapiFillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount) { PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat )); PA_DEBUG(( "sampleRate = %f\n" , sampleRate )); PA_DEBUG(( "chanelCount = %d\n", channelCount )); pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; pwfext->Format.nChannels = channelCount; pwfext->Format.nSamplesPerSec = (int)sampleRate; if(channelCount == 1) pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; else pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; if(sampleFormat == paFloat32) { pwfext->Format.nBlockAlign = channelCount * 4; pwfext->Format.wBitsPerSample = 32; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 32; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; } else if(sampleFormat == paInt32) { pwfext->Format.nBlockAlign = channelCount * 4; pwfext->Format.wBitsPerSample = 32; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 32; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } else if(sampleFormat == paInt24) { pwfext->Format.nBlockAlign = channelCount * 3; pwfext->Format.wBitsPerSample = 24; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 24; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } else if(sampleFormat == paInt16) { pwfext->Format.nBlockAlign = channelCount * 2; pwfext->Format.wBitsPerSample = 16; pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); pwfext->Samples.wValidBitsPerSample = 16; pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; } pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign; } /* #define FORMATTESTS 4 const int BestToWorst[FORMATTESTS]={paFloat32,paInt32,paInt24,paInt16}; */ #define FORMATTESTS 3 const int BestToWorst[FORMATTESTS]={paFloat32,paInt24,paInt16}; static PaError GetClosestFormat(IAudioClient * myClient, double sampleRate,const PaStreamParameters * params, AUDCLNT_SHAREMODE *shareMode, WAVEFORMATEXTENSIBLE *outWavex) { //TODO we should try exclusive first and shared after *shareMode = PORTAUDIO_SHAREMODE; PaError answer = paInvalidSampleRate; waveformatFromParams(outWavex,params,sampleRate); WAVEFORMATEX *sharedClosestMatch=0; HRESULT hResult=!S_OK; if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,(WAVEFORMATEX*)outWavex,NULL); else hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&outWavex,&sharedClosestMatch); if (hResult == S_OK) answer = paFormatIsSupported; else if (sharedClosestMatch){ WAVEFORMATEXTENSIBLE* ext = (WAVEFORMATEXTENSIBLE*)sharedClosestMatch; int closestMatchSR = (int)sharedClosestMatch->nSamplesPerSec; if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE) memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEXTENSIBLE)); else memcpy(outWavex,sharedClosestMatch,sizeof(WAVEFORMATEX)); CoTaskMemFree(sharedClosestMatch); if ((int)sampleRate == closestMatchSR) answer = paFormatIsSupported; else answer = paInvalidSampleRate; }else { //it doesnt suggest anything?? ok lets show it the MENU! //ok fun time as with pa_win_mme, we know only a refusal of the user-requested //sampleRate+num Channel is disastrous, as the portaudio buffer processor converts between anything //so lets only use the number for (int i=0;ichannelCount); if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,(WAVEFORMATEX*)&ext,NULL); else hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&ext,&sharedClosestMatch); if (hResult == S_OK){ memcpy(outWavex,&ext,sizeof(WAVEFORMATEXTENSIBLE)); answer = paFormatIsSupported; break; } } if (answer!=paFormatIsSupported) { //try MIX format? //why did it HAVE to come to this .... WAVEFORMATEX pcm16WaveFormat; memset(&pcm16WaveFormat,0,sizeof(WAVEFORMATEX)); pcm16WaveFormat.wFormatTag = WAVE_FORMAT_PCM; pcm16WaveFormat.nChannels = 2; pcm16WaveFormat.nSamplesPerSec = (DWORD)sampleRate; pcm16WaveFormat.nBlockAlign = 4; pcm16WaveFormat.nAvgBytesPerSec = pcm16WaveFormat.nSamplesPerSec*pcm16WaveFormat.nBlockAlign; pcm16WaveFormat.wBitsPerSample = 16; pcm16WaveFormat.cbSize = 0; if (*shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,(WAVEFORMATEX*)&pcm16WaveFormat,NULL); else hResult = myClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)&pcm16WaveFormat,&sharedClosestMatch); if (hResult == S_OK){ memcpy(outWavex,&pcm16WaveFormat,sizeof(WAVEFORMATEX)); answer = paFormatIsSupported; } } logAUDCLNT_E(hResult); } return answer; } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ) { int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; IAudioClient *myClient=0; HRESULT hResult = paWasapi->devInfo[inputParameters->device].device->Activate( __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); if (hResult != S_OK){ logAUDCLNT_E(hResult); return paInvalidDevice; } WAVEFORMATEXTENSIBLE wavex; AUDCLNT_SHAREMODE shareMode; PaError answer = GetClosestFormat(myClient,sampleRate,inputParameters,&shareMode,&wavex); myClient->Release(); if (answer !=paFormatIsSupported) return answer; } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) return paSampleFormatNotSupported; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support outputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; IAudioClient *myClient=0; HRESULT hResult = paWasapi->devInfo[outputParameters->device].device->Activate( __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&myClient); if (hResult != S_OK){ logAUDCLNT_E(hResult); return paInvalidDevice; } WAVEFORMATEXTENSIBLE wavex; AUDCLNT_SHAREMODE shareMode; PaError answer = GetClosestFormat(myClient,sampleRate,outputParameters,&shareMode,&wavex); myClient->Release(); if (answer !=paFormatIsSupported) return answer; } else { outputChannelCount = 0; } return paFormatIsSupported; } /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ) { PaError result = paNoError; PaWinWasapiHostApiRepresentation *paWasapi = (PaWinWasapiHostApiRepresentation*)hostApi; PaWinWasapiStream *stream = 0; int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; stream = (PaWinWasapiStream*)PaUtil_AllocateMemory( sizeof(PaWinWasapiStream) ); if( !stream ){ result = paInsufficientMemory; goto error; } if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ PaWinWasapiDeviceInfo &info = paWasapi->devInfo[inputParameters->device]; HRESULT hResult = info.device->Activate( __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&stream->in.client); if (hResult != S_OK) return paInvalidDevice; hResult = info.device->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&stream->inVol); if (hResult != S_OK) return paInvalidDevice; AUDCLNT_SHAREMODE shareMode; PaError answer = GetClosestFormat(stream->in.client,sampleRate,inputParameters,&shareMode,&stream->in.wavex); if (answer !=paFormatIsSupported) return answer; //stream->out.period = info.DefaultDevicePeriod; stream->in.period = info.MinimumDevicePeriod; hResult = stream->in.client->Initialize( shareMode, 0, //no flags stream->in.period, 0,//stream->out.period, (WAVEFORMATEX*)&stream->in.wavex, &stream->session ); if (hResult != S_OK){ logAUDCLNT_E(hResult); return paInvalidDevice; } hResult = stream->in.client->GetBufferSize(&stream->in.bufferSize); if (hResult != S_OK) return paInvalidDevice; hResult = stream->in.client->GetStreamLatency(&stream->in.latency); if (hResult != S_OK) return paInvalidDevice; double periodsPerSecond = 1.0/nano100ToSeconds(stream->in.period); double samplesPerPeriod = (double)(stream->in.wavex.Format.nSamplesPerSec)/periodsPerSecond; //this is the number of samples that are required at each period stream->in.framesPerHostCallback = (unsigned long)samplesPerPeriod;//unrelated to channels /* IMPLEMENT ME - establish which host formats are available */ hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat ); } else { inputChannelCount = 0; inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ PaWinWasapiDeviceInfo &info = paWasapi->devInfo[outputParameters->device]; HRESULT hResult = info.device->Activate( __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&stream->out.client); if (hResult != S_OK) return paInvalidDevice; AUDCLNT_SHAREMODE shareMode; PaError answer = GetClosestFormat(stream->out.client,sampleRate,outputParameters,&shareMode,&stream->out.wavex); if (answer !=paFormatIsSupported) return answer; LogWAVEFORMATEXTENSIBLE(&stream->out.wavex); // stream->out.period = info.DefaultDevicePeriod; stream->out.period = info.MinimumDevicePeriod; /*For an exclusive-mode stream that uses event-driven buffering, the caller must specify nonzero values for hnsPeriodicity and hnsBufferDuration, and the values of these two parameters must be equal */ if (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE){ hResult = stream->out.client->Initialize( shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, stream->out.period, stream->out.period, (WAVEFORMATEX*)&stream->out.wavex, &stream->session ); } else{ hResult = stream->out.client->Initialize( shareMode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, (WAVEFORMATEX*)&stream->out.wavex, &stream->session ); } if (hResult != S_OK){ logAUDCLNT_E(hResult); return paInvalidDevice; } hResult = info.device->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&stream->outVol); if (hResult != S_OK) return paInvalidDevice; hResult = stream->out.client->GetBufferSize(&stream->out.bufferSize); if (hResult != S_OK) return paInvalidDevice; hResult = stream->out.client->GetStreamLatency(&stream->out.latency); if (hResult != S_OK) return paInvalidDevice; double periodsPerSecond = 1.0/nano100ToSeconds(stream->out.period); double samplesPerPeriod = (double)(stream->out.wavex.Format.nSamplesPerSec)/periodsPerSecond; //this is the number of samples that are required at each period stream->out.framesPerHostCallback = stream->out.bufferSize; //(unsigned long)samplesPerPeriod;//unrelated to channels /* IMPLEMENT ME - establish which host formats are available */ hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat ); } else { outputChannelCount = 0; outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ } /* IMPLEMENT ME: ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate - alter sampleRate to a close allowable rate if possible / necessary - validate suggestedInputLatency and suggestedOutputLatency parameters, use default values where necessary */ /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &paWasapi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &paWasapi->blockingStreamInterface, streamCallback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); if (outputParameters && inputParameters){ //serious problem #1 if (stream->in.period != stream->out.period){ PRINT(("OpenStream: period discrepancy\n")); goto error; } //serious problem #2 if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback){ PRINT(("OpenStream: framesPerHostCallback discrepancy\n")); goto error; } } unsigned long framesPerHostCallback = (outputParameters)? stream->out.framesPerHostCallback: stream->in.framesPerHostCallback; /* we assume a fixed host buffer size in this example, but the buffer processor can also support bounded and unknown host buffer sizes by passing paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of paUtilFixedHostBufferSize below. */ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerHostCallback, paUtilFixedHostBufferSize, streamCallback, userData ); if( result != paNoError ) goto error; /* IMPLEMENT ME: initialise the following fields with estimated or actual values. */ stream->streamRepresentation.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) + ((inputParameters)?nano100ToSeconds(stream->in.latency) :0); stream->streamRepresentation.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) + ((outputParameters)?nano100ToSeconds(stream->out.latency) :0); stream->streamRepresentation.streamInfo.sampleRate = sampleRate; *s = (PaStream*)stream; return result; error: if( stream ) PaUtil_FreeMemory( stream ); return result; } /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. */ #define SAFE_RELEASE(punk) \ if ((punk) != NULL) \ { (punk)->Release(); (punk) = NULL; } static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* IMPLEMENT ME: - additional stream closing + cleanup */ SAFE_RELEASE(stream->out.client); SAFE_RELEASE(stream->in.client); SAFE_RELEASE(stream->cclient); SAFE_RELEASE(stream->rclient); SAFE_RELEASE(stream->inVol); SAFE_RELEASE(stream->outVol); CloseHandle(stream->hThread); CloseHandle(stream->hNotificationEvent); PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); return result; } DWORD WINAPI ProcThread(void *client); static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaWinWasapiStream *stream = (PaWinWasapiStream*)s; PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); HRESULT hResult=S_OK; if (stream->out.client){ hResult = stream->out.client->GetService(__uuidof(IAudioRenderClient),(void**)&stream->rclient); logAUDCLNT_E(hResult); if (hResult!=S_OK) return paUnanticipatedHostError; } if (stream->in.client){ hResult = stream->in.client->GetService(__uuidof(IAudioCaptureClient),(void**)&stream->cclient); logAUDCLNT_E(hResult); if (hResult!=S_OK) return paUnanticipatedHostError; } // Create a thread for this client. stream->hThread = CreateThread( NULL, // no security attribute 0, // default stack size ProcThread, (LPVOID) stream, // thread parameter 0, // not suspended &stream->dwThreadId); // returns thread ID if (stream->hThread == NULL) return paUnanticipatedHostError; return paNoError; } static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ stream->closeRequest = true; //todo something MUCH better than this while(stream->closeRequest) Sleep(100); /* IMPLEMENT ME, see portaudio.h for required behavior */ stream->running = false; return result; } static PaError AbortStream( PaStream *s ) { PaError result = paNoError; PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ stream->closeRequest = true; //todo something MUCH better than this while(stream->closeRequest) Sleep(100); /* IMPLEMENT ME, see portaudio.h for required behavior */ return result; } static PaError IsStreamStopped( PaStream *s ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; return !stream->running; } static PaError IsStreamActive( PaStream *s ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; return stream->running; } static PaTime GetStreamTime( PaStream *s ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ //this is lame ds and mme does the same thing, quite useless method imho //why dont we fetch the time in the pa callbacks? //at least its doing to be clocked to something return PaUtil_GetTime(); } static double GetStreamCpuLoad( PaStream* s ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } /* As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. */ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError; } static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError; } static signed long GetStreamReadAvailable( PaStream* s ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } static signed long GetStreamWriteAvailable( PaStream* s ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0; } /* ExampleHostProcessingLoop() illustrates the kind of processing which may occur in a host implementation. */ static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, void *outputBuffer, long outputFrames, void *userData ) { PaWinWasapiStream *stream = (PaWinWasapiStream*)userData; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ int callbackResult; unsigned long framesProcessed; PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* IMPLEMENT ME: - generate timing information - handle buffer slips */ /* If you need to byte swap or shift inputBuffer to convert it into a portaudio format, do it here. */ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ ); /* depending on whether the host buffers are interleaved, non-interleaved or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. */ if( stream->bufferProcessor.inputChannelCount > 0 ) { PaUtil_SetInputFrameCount( &stream->bufferProcessor, inputFrames ); PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, /* first channel of inputBuffer is channel 0 */ inputBuffer, 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ } if( stream->bufferProcessor.outputChannelCount > 0 ) { PaUtil_SetOutputFrameCount( &stream->bufferProcessor, outputFrames); PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, /* first channel of outputBuffer is channel 0 */ outputBuffer, 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ } /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() in general you would pass paContinue for normal operation, and paComplete to drain the buffer processor's internal output buffer. You can check whether the buffer processor's output buffer is empty using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) */ callbackResult = paContinue; framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); /* If you need to byte swap or shift outputBuffer to convert it to host format, do it here. */ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); if( callbackResult == paContinue ) { /* nothing special to do */ } else if( callbackResult == paAbort ) { /* IMPLEMENT ME - finish playback immediately */ /* once finished, call the finished callback */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } else { /* User callback has asked us to stop with paComplete or other non-zero value */ /* IMPLEMENT ME - finish playback once currently queued audio has completed */ /* once finished, call the finished callback */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } } void MMCSS_activate(){ DWORD stuff=0; HANDLE thCarac = pAvSetMmThreadCharacteristics("Pro Audio",&stuff); if (!thCarac){ PRINT(("AvSetMmThreadCharacteristics failed!\n")); } BOOL prio = pAvSetMmThreadPriority(thCarac,AVRT_PRIORITY_NORMAL); if (!prio){ PRINT(("AvSetMmThreadPriority failed!\n")); } //debug { HANDLE hh = GetCurrentThread(); int currprio = GetThreadPriority(hh); DWORD currclass = GetPriorityClass(GetCurrentProcess()); PRINT(("currprio 0x%X currclass 0x%X\n",currprio,currclass)); } } DWORD WINAPI ProcThread(void* param){ HRESULT hResult; MMCSS_activate(); PaWinWasapiStream *stream = (PaWinWasapiStream*)param; stream->hNotificationEvent = CreateEvent(NULL, FALSE, //bManualReset are we sure?? FALSE, "PAWASA"); hResult = stream->out.client->SetEventHandle(stream->hNotificationEvent); if (hResult != S_OK) logAUDCLNT_E(hResult); if (stream->out.client){ hResult = stream->out.client->Start(); if (hResult != S_OK) logAUDCLNT_E(hResult); } stream->running = true; bool bOne = false; while( !stream->closeRequest ) { //lets wait but have a 1 second timeout DWORD dwResult = WaitForSingleObject(stream->hNotificationEvent, 1000); switch( dwResult ) { case WAIT_OBJECT_0: { unsigned long usingBS = stream->out.framesPerHostCallback; BYTE* indata = 0; BYTE* outdata = 0; hResult = stream->rclient->GetBuffer(usingBS, &outdata); if (hResult != S_OK || !outdata) { //logAUDCLNT_E(hResult); //most probably shared mode and hResult=AUDCLNT_E_BUFFER_TOO_LARGE UINT32 padding = 0; hResult = stream->out.client->GetCurrentPadding(&padding); if (padding == 0) break; usingBS = usingBS-padding; if (usingBS == 0) break;//huh? hResult = stream->rclient->GetBuffer(usingBS, &outdata); if (hResult != S_OK)//what can we do NOW?? break; //logAUDCLNT_E(hResult); } WaspiHostProcessingLoop(indata, usingBS ,outdata, usingBS, stream); hResult = stream->rclient->ReleaseBuffer(usingBS, 0); if (hResult != S_OK) logAUDCLNT_E(hResult); /* This was suggested, but in my tests it doesnt seem to improve the locking behaviour some drivers have running in exclusive mode. if(!ResetEvent(stream->hNotificationEvent)){ logAUDCLNT_E(hResult); } */ } break; } } stream->out.client->Stop(); stream->closeRequest = false; return 0; } #endif //VC 2005 #if 0 if(bFirst) { float masteur; hResult = stream->outVol->GetMasterVolumeLevelScalar(&masteur); if (hResult != S_OK) logAUDCLNT_E(hResult); float chan1, chan2; hResult = stream->outVol->GetChannelVolumeLevelScalar(0, &chan1); if (hResult != S_OK) logAUDCLNT_E(hResult); hResult = stream->outVol->GetChannelVolumeLevelScalar(1, &chan2); if (hResult != S_OK) logAUDCLNT_E(hResult); BOOL bMute; hResult = stream->outVol->GetMute(&bMute); if (hResult != S_OK) logAUDCLNT_E(hResult); stream->outVol->SetMasterVolumeLevelScalar(0.5, NULL); stream->outVol->SetChannelVolumeLevelScalar(0, 0.5, NULL); stream->outVol->SetChannelVolumeLevelScalar(1, 0.5, NULL); stream->outVol->SetMute(FALSE, NULL); bFirst = false; } #endifnyquist-3.05/portaudio/src/os/0002755000175000000620000000000011537433131015404 5ustar stevestaffnyquist-3.05/portaudio/src/os/unix/0002755000175000000620000000000011537433131016367 5ustar stevestaffnyquist-3.05/portaudio/src/os/unix/pa_unix_util.c0000644000175000000620000004533411466723256021255 0ustar stevestaff/* * $Id: pa_unix_util.c,v 1.1 2010/11/04 21:04:15 rbd Exp $ * Portable Audio I/O Library * UNIX platform-specific support functions * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup unix_src */ #include #include #include #include #include #include #include /* For memset */ #include #include #include "pa_util.h" #include "pa_unix_util.h" #include "pa_debugprint.h" /* Track memory allocations to avoid leaks. */ #if PA_TRACK_MEMORY static int numAllocations_ = 0; #endif void *PaUtil_AllocateMemory( long size ) { void *result = malloc( size ); #if PA_TRACK_MEMORY if( result != NULL ) numAllocations_ += 1; #endif return result; } void PaUtil_FreeMemory( void *block ) { if( block != NULL ) { free( block ); #if PA_TRACK_MEMORY numAllocations_ -= 1; #endif } } int PaUtil_CountCurrentlyAllocatedBlocks( void ) { #if PA_TRACK_MEMORY return numAllocations_; #else return 0; #endif } void Pa_Sleep( long msec ) { #ifdef HAVE_NANOSLEEP struct timespec req = {0}, rem = {0}; PaTime time = msec / 1.e3; req.tv_sec = (time_t)time; assert(time - req.tv_sec < 1.0); req.tv_nsec = (long)((time - req.tv_sec) * 1.e9); nanosleep(&req, &rem); /* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */ #else while( msec > 999 ) /* For OpenBSD and IRIX, argument */ { /* to usleep must be < 1000000. */ usleep( 999000 ); msec -= 999; } usleep( msec * 1000 ); #endif } /* *** NOT USED YET: *** static int usePerformanceCounter_; static double microsecondsPerTick_; */ void PaUtil_InitializeClock( void ) { /* TODO */ } PaTime PaUtil_GetTime( void ) { #ifdef HAVE_CLOCK_GETTIME struct timespec tp; clock_gettime(CLOCK_REALTIME, &tp); return (PaTime)(tp.tv_sec + tp.tv_nsec / 1.e9); #else struct timeval tv; gettimeofday( &tv, NULL ); return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec; #endif } PaError PaUtil_InitializeThreading( PaUtilThreading *threading ) { (void) paUtilErr_; return paNoError; } void PaUtil_TerminateThreading( PaUtilThreading *threading ) { } PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data ) { pthread_create( &threading->callbackThread, NULL, threadRoutine, data ); return paNoError; } PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult ) { PaError result = paNoError; void *pret; if( exitResult ) *exitResult = paNoError; /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ if( !wait ) pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */ pthread_join( threading->callbackThread, &pret ); #ifdef PTHREAD_CANCELED if( pret && PTHREAD_CANCELED != pret ) #else /* !wait means the thread may have been canceled */ if( pret && wait ) #endif { if( exitResult ) *exitResult = *(PaError *) pret; free( pret ); } return result; } /* Threading */ /* paUnixMainThread * We have to be a bit careful with defining this global variable, * as explained below. */ #ifdef __apple__ /* apple/gcc has a "problem" with global vars and dynamic libs. Initializing it seems to fix the problem. Described a bit in this thread: http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html */ pthread_t paUnixMainThread = 0; #else /*pthreads are opaque. We don't know that asigning it an int value always makes sense, so we don't initialize it unless we have to.*/ pthread_t paUnixMainThread = 0; #endif PaError PaUnixThreading_Initialize() { paUnixMainThread = pthread_self(); return paNoError; } static PaError BoostPriority( PaUnixThread* self ) { PaError result = paNoError; struct sched_param spm = { 0 }; /* Priority should only matter between contending FIFO threads? */ spm.sched_priority = 1; assert( self ); if( pthread_setschedparam( self->thread, SCHED_FIFO, &spm ) != 0 ) { PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */ PA_DEBUG(( "Failed bumping priority\n" )); result = 0; } else { result = 1; /* Success */ } error: return result; } PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild, int rtSched ) { PaError result = paNoError; pthread_attr_t attr; int started = 0; memset( self, 0, sizeof (PaUnixThread) ); PaUnixMutex_Initialize( &self->mtx ); PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 ); self->parentWaiting = 0 != waitForChild; /* Spawn thread */ /* Temporarily disabled since we should test during configuration for presence of required mman.h header */ #if 0 #if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1) if( rtSched ) { if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 ) { int savedErrno = errno; /* In case errno gets overwritten */ assert( savedErrno != EINVAL ); /* Most likely a programmer error */ PA_UNLESS( (savedErrno == EPERM), paInternalError ); PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ )); } else PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ )); } #endif #endif PA_UNLESS( !pthread_attr_init( &attr ), paInternalError ); /* Priority relative to other processes */ PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError ); PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError ); started = 1; if( rtSched ) { #if 0 if( self->useWatchdog ) { int err; struct sched_param wdSpm = { 0 }; /* Launch watchdog, watchdog sets callback thread priority */ int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) ); wdSpm.sched_priority = prio; PA_UNLESS( !pthread_attr_init( &attr ), paInternalError ); PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError ); PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError ); PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError ); PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError ); if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) ) { PA_UNLESS( err == EPERM, paInternalError ); /* Permission error, go on without realtime privileges */ PA_DEBUG(( "Failed bumping priority\n" )); } else { int policy; self->watchdogRunning = 1; PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 ); /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */ if( wdSpm.sched_priority != prio ) { PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority )); PA_ENSURE( paInternalError ); } } } else #endif PA_ENSURE( BoostPriority( self ) ); { int policy; struct sched_param spm; pthread_getschedparam(self->thread, &policy, &spm); } } if( self->parentWaiting ) { PaTime till; struct timespec ts; int res = 0; PaTime now; PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); /* Wait for stream to be started */ now = PaUtil_GetTime(); till = now + waitForChild; while( self->parentWaiting && !res ) { if( waitForChild > 0 ) { ts.tv_sec = (time_t) floor( till ); ts.tv_nsec = (long) ((till - floor( till )) * 1e9); res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts ); } else { res = pthread_cond_wait( &self->cond, &self->mtx.mtx ); } } PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) ); PA_UNLESS( !res || ETIMEDOUT == res, paInternalError ); PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now )); if( ETIMEDOUT == res ) { PA_ENSURE( paTimedOut ); } } end: return result; error: if( started ) { PaUnixThread_Terminate( self, 0, NULL ); } goto end; } PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult ) { PaError result = paNoError; void* pret; if( exitResult ) { *exitResult = paNoError; } #if 0 if( watchdogExitResult ) *watchdogExitResult = paNoError; if( th->watchdogRunning ) { pthread_cancel( th->watchdogThread ); PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 ); if( pret && pret != PTHREAD_CANCELED ) { if( watchdogExitResult ) *watchdogExitResult = *(PaError *) pret; free( pret ); } } #endif /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ /* TODO: Make join time out */ self->stopRequested = wait; if( !wait ) { PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread )); /* XXX: Safe to call this if the thread has exited on its own? */ pthread_cancel( self->thread ); } PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread )); PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 ); if( pret && PTHREAD_CANCELED != pret ) { if( exitResult ) { *exitResult = *(PaError*)pret; } free( pret ); } error: PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError ); PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 ); return result; } PaError PaUnixThread_PrepareNotify( PaUnixThread* self ) { PaError result = paNoError; PA_UNLESS( self->parentWaiting, paInternalError ); PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); self->locked = 1; error: return result; } PaError PaUnixThread_NotifyParent( PaUnixThread* self ) { PaError result = paNoError; PA_UNLESS( self->parentWaiting, paInternalError ); if( !self->locked ) { PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); self->locked = 1; } self->parentWaiting = 0; pthread_cond_signal( &self->cond ); PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) ); self->locked = 0; error: return result; } int PaUnixThread_StopRequested( PaUnixThread* self ) { return self->stopRequested; } PaError PaUnixMutex_Initialize( PaUnixMutex* self ) { PaError result = paNoError; PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 ); return result; } PaError PaUnixMutex_Terminate( PaUnixMutex* self ) { PaError result = paNoError; PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 ); return result; } /** Lock mutex. * * We're disabling thread cancellation while the thread is holding a lock, so mutexes are * properly unlocked at termination time. */ PaError PaUnixMutex_Lock( PaUnixMutex* self ) { PaError result = paNoError; int oldState; PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 ); PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 ); error: return result; } /** Unlock mutex. * * Thread cancellation is enabled again after the mutex is properly unlocked. */ PaError PaUnixMutex_Unlock( PaUnixMutex* self ) { PaError result = paNoError; int oldState; PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 ); PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 ); error: return result; } #if 0 static void OnWatchdogExit( void *userData ) { PaAlsaThreading *th = (PaAlsaThreading *) userData; struct sched_param spm = { 0 }; assert( th ); PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */ PA_DEBUG(( "Watchdog exiting\n" )); } static void *WatchdogFunc( void *userData ) { PaError result = paNoError, *pres = NULL; int err; PaAlsaThreading *th = (PaAlsaThreading *) userData; unsigned intervalMsec = 500; const PaTime maxSeconds = 3.; /* Max seconds between callbacks */ PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed; double cpuLoad, avgCpuLoad = 0.; int throttled = 0; assert( th ); /* Execute OnWatchdogExit when exiting */ pthread_cleanup_push( &OnWatchdogExit, th ); /* Boost priority of callback thread */ PA_ENSURE( result = BoostPriority( th ) ); if( !result ) { /* Boost failed, might as well exit */ pthread_exit( NULL ); } cpuTimeThen = th->callbackCpuTime; { int policy; struct sched_param spm = { 0 }; pthread_getschedparam( pthread_self(), &policy, &spm ); PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority )); } while( 1 ) { double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff; /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */ pthread_testcancel(); Pa_Sleep( intervalMsec ); pthread_testcancel(); if( PaUtil_GetTime() - th->callbackTime > maxSeconds ) { PA_DEBUG(( "Watchdog: Terminating callback thread\n" )); /* Tell thread to terminate */ err = pthread_kill( th->callbackThread, SIGKILL ); pthread_exit( NULL ); } PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) )); /* Check if we should throttle, or unthrottle :P */ cpuTimeNow = th->callbackCpuTime; cpuTimeElapsed = cpuTimeNow - cpuTimeThen; cpuTimeThen = cpuTimeNow; timeNow = PaUtil_GetTime(); timeElapsed = timeNow - timeThen; timeThen = timeNow; cpuLoad = cpuTimeElapsed / timeElapsed; avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1; /* if( throttled ) PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed )); */ if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 ) { static int policy; static struct sched_param spm = { 0 }; static const struct sched_param defaultSpm = { 0 }; PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority )); pthread_getschedparam( th->callbackThread, &policy, &spm ); if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) ) { throttled = 1; } else PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) )); /* Give other processes a go, before raising priority again */ PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime )); Pa_Sleep( th->throttledSleepTime ); /* Reset callback priority */ if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 ) { PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) )); } if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 ) intervalMsec = 50; else intervalMsec = 100; /* lowpassCoeff = .97; lowpassCoeff1 = .99999 - lowpassCoeff; */ } else if( throttled && avgCpuLoad < .8 ) { intervalMsec = 500; throttled = 0; /* lowpassCoeff = .9; lowpassCoeff1 = .99999 - lowpassCoeff; */ } } pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */ error: /* Shouldn't get here in the normal case */ /* Pass on error code */ pres = malloc( sizeof (PaError) ); *pres = result; pthread_exit( pres ); } static void CallbackUpdate( PaAlsaThreading *th ) { th->callbackTime = PaUtil_GetTime(); th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer ); } /* static void *CanaryFunc( void *userData ) { const unsigned intervalMsec = 1000; PaUtilThreading *th = (PaUtilThreading *) userData; while( 1 ) { th->canaryTime = PaUtil_GetTime(); pthread_testcancel(); Pa_Sleep( intervalMsec ); } pthread_exit( NULL ); } */ #endif nyquist-3.05/portaudio/src/os/unix/pa_unix_util.h0000644000175000000620000001736711466723256021267 0ustar stevestaff/* * $Id: pa_unix_util.h,v 1.1 2010/11/04 21:04:15 rbd Exp $ * Portable Audio I/O Library * UNIX platform-specific support functions * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup unix_src */ #ifndef PA_UNIX_UTIL_H #define PA_UNIX_UTIL_H #include "pa_cpuload.h" #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) ) #define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) ) /* Utilize GCC branch prediction for error tests */ #if defined __GNUC__ && __GNUC__ >= 3 #define UNLIKELY(expr) __builtin_expect( (expr), 0 ) #else #define UNLIKELY(expr) (expr) #endif #define STRINGIZE_HELPER(expr) #expr #define STRINGIZE(expr) STRINGIZE_HELPER(expr) #define PA_UNLESS(expr, code) \ do { \ if( UNLIKELY( (expr) == 0 ) ) \ { \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = (code); \ goto error; \ } \ } while (0); static PaError paUtilErr_; /* Used with PA_ENSURE */ /* Check PaError */ #define PA_ENSURE(expr) \ do { \ if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \ { \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = paUtilErr_; \ goto error; \ } \ } while (0); #define PA_ASSERT_CALL(expr, success) \ paUtilErr_ = (expr); \ assert( success == paUtilErr_ ); #define PA_ENSURE_SYSTEM(expr, success) \ do { \ if( UNLIKELY( (paUtilErr_ = (expr)) != success ) ) \ { \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ if( pthread_equal(pthread_self(), paUnixMainThread) ) \ { \ PaUtil_SetLastHostErrorInfo( paALSA, paUtilErr_, strerror( paUtilErr_ ) ); \ } \ PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ result = paUnanticipatedHostError; \ goto error; \ } \ } while( 0 ); typedef struct { pthread_t callbackThread; } PaUtilThreading; PaError PaUtil_InitializeThreading( PaUtilThreading *threading ); void PaUtil_TerminateThreading( PaUtilThreading *threading ); PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data ); PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult ); /* State accessed by utility functions */ /* void PaUnix_SetRealtimeScheduling( int rt ); void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm ); PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s ); PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult ); void PaUtil_CallbackUpdate( PaUtilThreading *th ); */ extern pthread_t paUnixMainThread; typedef struct { pthread_mutex_t mtx; } PaUnixMutex; PaError PaUnixMutex_Initialize( PaUnixMutex* self ); PaError PaUnixMutex_Terminate( PaUnixMutex* self ); PaError PaUnixMutex_Lock( PaUnixMutex* self ); PaError PaUnixMutex_Unlock( PaUnixMutex* self ); typedef struct { pthread_t thread; int parentWaiting; int stopRequested; int locked; PaUnixMutex mtx; pthread_cond_t cond; volatile sig_atomic_t stopRequest; } PaUnixThread; /** Initialize global threading state. */ PaError PaUnixThreading_Initialize(); /** Perish, passing on eventual error code. * * A thin wrapper around pthread_exit, will automatically pass on any error code to the joining thread. * If the result indicates an error, i.e. it is not equal to paNoError, this function will automatically * allocate a pointer so the error is passed on with pthread_exit. If the result indicates that all is * well however, only a NULL pointer will be handed to pthread_exit. Thus, the joining thread should * check whether a non-NULL result pointer is obtained from pthread_join and make sure to free it. * @param result: The error code to pass on to the joining thread. */ #define PaUnixThreading_EXIT(result) \ do { \ PaError* pres = NULL; \ if( paNoError != (result) ) \ { \ pres = malloc( sizeof (PaError) ); \ *pres = (result); \ } \ pthread_exit( pres ); \ } while (0); /** Spawn a thread. * * Intended for spawning the callback thread from the main thread. This function can even block (for a certain * time or indefinitely) untill notified by the callback thread (using PaUnixThread_NotifyParent), which can be * useful in order to make sure that callback has commenced before returning from Pa_StartStream. * @param threadFunc: The function to be executed in the child thread. * @param waitForChild: If not 0, wait for child thread to call PaUnixThread_NotifyParent. Less than 0 means * wait for ever, greater than 0 wait for the specified time. * @param rtSched: Enable realtime scheduling? * @return: If timed out waiting on child, paTimedOut. */ PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild, int rtSched ); /** Terminate thread. * * @param wait: If true, request that background thread stop and wait untill it does, else cancel it. * @param exitResult: If non-null this will upon return contain the exit status of the thread. */ PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult ); /** Prepare to notify waiting parent thread. * * An internal lock must be held before the parent is notified in PaUnixThread_NotifyParent, call this to * acquire it beforehand. * @return: If parent is not waiting, paInternalError. */ PaError PaUnixThread_PrepareNotify( PaUnixThread* self ); /** Notify waiting parent thread. * * @return: If parent timed out waiting, paTimedOut. If parent was never waiting, paInternalError. */ PaError PaUnixThread_NotifyParent( PaUnixThread* self ); /** Has the parent thread requested this thread to stop? */ int PaUnixThread_StopRequested( PaUnixThread* self ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif nyquist-3.05/portaudio/src/os/unix/pa_unix_hostapis.c0000644000175000000620000000540711466723256022127 0ustar stevestaff/* * $Id: pa_unix_hostapis.c,v 1.1 2010/11/04 21:04:15 rbd Exp $ * Portable Audio I/O Library UNIX initialization table * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup unix_src */ #include "pa_hostapi.h" PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); /* Added for IRIX, Pieter, oct 2, 2003: */ PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); /* Linux AudioScience HPI */ PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaUtilHostApiInitializer *paHostApiInitializers[] = { #ifdef PA_USE_OSS PaOSS_Initialize, #endif #ifdef PA_USE_ALSA PaAlsa_Initialize, #endif #ifdef PA_USE_JACK PaJack_Initialize, #endif /* Added for IRIX, Pieter, oct 2, 2003: */ #ifdef PA_USE_SGI PaSGI_Initialize, #endif #ifdef PA_USE_ASIHPI PaAsiHpi_Initialize, #endif 0 /* NULL terminated array */ }; int paDefaultHostApiIndex = 0; nyquist-3.05/portaudio/src/os/win/0002755000175000000620000000000011537433131016201 5ustar stevestaffnyquist-3.05/portaudio/src/os/win/pa_win_waveformat.c0000644000175000000620000001402411466723256022067 0ustar stevestaff/* * PortAudio Portable Real-Time Audio Library * Windows WAVEFORMAT* data structure utilities * portaudio.h should be included before this file. * * Copyright (c) 2007 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ #include #include #include "portaudio.h" #include "pa_win_waveformat.h" #if !defined(WAVE_FORMAT_EXTENSIBLE) #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif #if !defined(WAVE_FORMAT_IEEE_FLOAT) #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif static GUID pawin_ksDataFormatSubtypePcm = { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; static GUID pawin_ksDataFormatSubtypeIeeeFloat = { (USHORT)(WAVE_FORMAT_IEEE_FLOAT), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, int numChannels, PaSampleFormat sampleFormat, double sampleRate ) { WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; int bytesPerSample = Pa_GetSampleSize(sampleFormat); unsigned long bytesPerFrame = numChannels * bytesPerSample; if( sampleFormat == paFloat32 ) waveFormatEx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; else waveFormatEx->wFormatTag = WAVE_FORMAT_PCM; waveFormatEx->nChannels = (WORD)numChannels; waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; waveFormatEx->nBlockAlign = (WORD)bytesPerFrame; waveFormatEx->wBitsPerSample = bytesPerSample * 8; waveFormatEx->cbSize = 0; } void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, int numChannels, PaSampleFormat sampleFormat, double sampleRate, PaWinWaveFormatChannelMask channelMask ) { WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; int bytesPerSample = Pa_GetSampleSize(sampleFormat); unsigned long bytesPerFrame = numChannels * bytesPerSample; waveFormatEx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; waveFormatEx->nChannels = (WORD)numChannels; waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; waveFormatEx->nBlockAlign = (WORD)bytesPerFrame; waveFormatEx->wBitsPerSample = bytesPerSample * 8; waveFormatEx->cbSize = 22; *((WORD*)&waveFormat->fields[PAWIN_INDEXOF_WVALIDBITSPERSAMPLE]) = waveFormatEx->wBitsPerSample; *((DWORD*)&waveFormat->fields[PAWIN_INDEXOF_DWCHANNELMASK]) = channelMask; if( sampleFormat == paFloat32 ) *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = pawin_ksDataFormatSubtypeIeeeFloat; else *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = pawin_ksDataFormatSubtypePcm; } PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ) { switch( numChannels ){ case 1: return PAWIN_SPEAKER_MONO; case 2: return PAWIN_SPEAKER_STEREO; case 3: return PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_FRONT_RIGHT; case 4: return PAWIN_SPEAKER_QUAD; case 5: return PAWIN_SPEAKER_QUAD | PAWIN_SPEAKER_FRONT_CENTER; case 6: /* The meaning of the PAWIN_SPEAKER_5POINT1 flag has changed over time: http://msdn2.microsoft.com/en-us/library/aa474707.aspx We use PAWIN_SPEAKER_5POINT1 (not PAWIN_SPEAKER_5POINT1_SURROUND) because on some cards (eg Audigy) PAWIN_SPEAKER_5POINT1_SURROUND results in a virtual mixdown placing the rear output in the front _and_ rear speakers. */ return PAWIN_SPEAKER_5POINT1; /* case 7: */ case 8: return PAWIN_SPEAKER_7POINT1; } /* Apparently some Audigy drivers will output silence if the direct-out constant (0) is used. So this is not ideal. */ return PAWIN_SPEAKER_DIRECTOUT; /* Note that Alec Rogers proposed the following as an alternate method to generate the default channel mask, however it doesn't seem to be an improvement over the above, since some drivers will matrix outputs mapping to non-present speakers accross multiple physical speakers. if(nChannels==1) { pwfFormat->dwChannelMask = SPEAKER_FRONT_CENTER; } else { pwfFormat->dwChannelMask = 0; for(i=0; idwChannelMask = (pwfFormat->dwChannelMask << 1) | 0x1; } */ } nyquist-3.05/portaudio/src/os/win/pa_x86_plain_converters.c0000644000175000000620000011616211466723256023127 0ustar stevestaff/* * Plain Intel IA32 assembly implementations of PortAudio sample converter functions. * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup win_src */ #include "pa_x86_plain_converters.h" #include "pa_converters.h" #include "pa_dither.h" /* the main reason these versions are faster than the equivalent C versions is that float -> int casting is expensive in C on x86 because the rounding mode needs to be changed for every cast. these versions only set the rounding mode once outside the loop. small additional speed gains are made by the way that clamping is implemented. TODO: o- inline dither code o- implement Dither only (no-clip) versions o- implement int8 and uint8 versions o- test thouroughly o- the packed 24 bit functions could benefit from unrolling and avoiding byte and word sized register access. */ /* -------------------------------------------------------------------------- */ /* #define PA_CLIP_( val, min, max )\ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } */ /* the following notes were used to determine whether a floating point value should be saturated (ie >1 or <-1) by loading it into an integer register. these should be rewritten so that they make sense. an ieee floating point value 1.xxxxxxxxxxxxxxxxxxxx? is less than or equal to 1 and greater than or equal to -1 either: if the mantissa is 0 and the unbiased exponent is 0 OR if the unbiased exponent < 0 this translates to: if the mantissa is 0 and the biased exponent is 7F or if the biased exponent is less than 7F therefore the value is greater than 1 or less than -1 if the mantissa is not 0 and the biased exponent is 7F or if the biased exponent is greater than 7F in other words, if we mask out the sign bit, the value is greater than 1 or less than -1 if its integer representation is greater than: 0 01111111 0000 0000 0000 0000 0000 000 0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000 */ /* -------------------------------------------------------------------------- */ static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/ static const double int32Scaler_ = 0x7FFFFFFF; static const double ditheredInt32Scaler_ = 0x7FFFFFFE; static const double int24Scaler_ = 0x7FFFFF; static const double ditheredInt24Scaler_ = 0x7FFFFE; static const double int16Scaler_ = 0x7FFF; static const double ditheredInt16Scaler_ = 0x7FFE; #define PA_DITHER_BITS_ (15) /* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */ #define PA_FLOAT_DITHER_SCALE_ (1.0 / ((1< source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 and int32 mov eax, sourceStride imul eax, edx mov ecx, count imul ecx, eax add ecx, esi mov edi, destinationBuffer mov ebx, destinationStride imul ebx, edx fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld int32Scaler_ // stack: (int)0x7FFFFFFF Float32_To_Int32_loop: // load unscaled value into st(0) fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF /* note: we could store to a temporary qword here which would cause wraparound distortion instead of int indefinite 0x10. that would be more work, and given that not enabling clipping is only advisable when you know that your signal isn't going to clip it isn't worth it. */ fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF add edi, ebx // increment destination ptr //lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int32_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int32_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; signed long *dest = (signed long*)destinationBuffer; (void) ditherGenerator; // unused parameter while( count-- ) { // REVIEW double scaled = *src * 0x7FFFFFFF; PA_CLIP_( scaled, -2147483648., 2147483647. ); *dest = (signed long) scaled; src += sourceStride; dest += destinationStride; } */ short savedFpuControlWord; (void) ditherGenerator; /* unused parameter */ __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 and int32 mov eax, sourceStride imul eax, edx mov ecx, count imul ecx, eax add ecx, esi mov edi, destinationBuffer mov ebx, destinationStride imul ebx, edx fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld int32Scaler_ // stack: (int)0x7FFFFFFF Float32_To_Int32_Clip_loop: mov edx, dword ptr [esi] // load floating point value into integer register and edx, 0x7FFFFFFF // mask off sign cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 jg Float32_To_Int32_Clip_clamp // load unscaled value into st(0) fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF jmp Float32_To_Int32_Clip_stored Float32_To_Int32_Clip_clamp: mov edx, dword ptr [esi] // load floating point value into integer register shr edx, 31 // move sign bit into bit 0 add esi, eax // increment source ptr //lea esi, [esi+eax] add edx, 0x7FFFFFFF // convert to maximum range integers mov dword ptr [edi], edx Float32_To_Int32_Clip_stored: //add edi, ebx // increment destination ptr lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int32_Clip_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int32_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; signed long *dest = (signed long*)destinationBuffer; while( count-- ) { // REVIEW double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); // use smaller scaler to prevent overflow when we add the dither double dithered = ((double)*src * (2147483646.0)) + dither; PA_CLIP_( dithered, -2147483648., 2147483647. ); *dest = (signed long) dithered; src += sourceStride; dest += destinationStride; } */ short savedFpuControlWord; // spill storage: signed long sourceByteStride; signed long highpassedDither; // dither state: unsigned long ditherPrevious = ditherGenerator->previous; unsigned long ditherRandSeed1 = ditherGenerator->randSeed1; unsigned long ditherRandSeed2 = ditherGenerator->randSeed2; __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 and int32 mov eax, sourceStride imul eax, edx mov ecx, count imul ecx, eax add ecx, esi mov edi, destinationBuffer mov ebx, destinationStride imul ebx, edx fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld ditheredInt32Scaler_ // stack: int scaler Float32_To_Int32_DitherClip_loop: mov edx, dword ptr [esi] // load floating point value into integer register and edx, 0x7FFFFFFF // mask off sign cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 jg Float32_To_Int32_DitherClip_clamp // load unscaled value into st(0) fld dword ptr [esi] // stack: value, int scaler add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler /* // call PaUtil_GenerateFloatTriangularDither with C calling convention mov sourceByteStride, eax // save eax mov sourceEnd, ecx // save ecx push ditherGenerator // pass ditherGenerator parameter on stack call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler pop edx // clear parameter off stack mov ecx, sourceEnd // restore ecx mov eax, sourceByteStride // restore eax */ // generate dither mov sourceByteStride, eax // save eax mov edx, 196314165 mov eax, ditherRandSeed1 mul edx // eax:edx = eax * 196314165 //add eax, 907633515 lea eax, [eax+907633515] mov ditherRandSeed1, eax mov edx, 196314165 mov eax, ditherRandSeed2 mul edx // eax:edx = eax * 196314165 //add eax, 907633515 lea eax, [eax+907633515] mov edx, ditherRandSeed1 shr edx, PA_DITHER_SHIFT_ mov ditherRandSeed2, eax shr eax, PA_DITHER_SHIFT_ //add eax, edx // eax -> current lea eax, [eax+edx] mov edx, ditherPrevious neg edx lea edx, [eax+edx] // highpass = current - previous mov highpassedDither, edx mov ditherPrevious, eax // previous = current mov eax, sourceByteStride // restore eax fild highpassedDither fmul const_float_dither_scale_ // end generate dither, dither signal in st(0) faddp st(1), st(0) // stack: dither + value*(int scaler), int scaler fistp dword ptr [edi] // pop st(0) into dest, stack: int scaler jmp Float32_To_Int32_DitherClip_stored Float32_To_Int32_DitherClip_clamp: mov edx, dword ptr [esi] // load floating point value into integer register shr edx, 31 // move sign bit into bit 0 add esi, eax // increment source ptr //lea esi, [esi+eax] add edx, 0x7FFFFFFF // convert to maximum range integers mov dword ptr [edi], edx Float32_To_Int32_DitherClip_stored: //add edi, ebx // increment destination ptr lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int32_DitherClip_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } ditherGenerator->previous = ditherPrevious; ditherGenerator->randSeed1 = ditherRandSeed1; ditherGenerator->randSeed2 = ditherRandSeed2; } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; signed long temp; (void) ditherGenerator; // unused parameter while( count-- ) { // convert to 32 bit and drop the low 8 bits double scaled = *src * 0x7FFFFFFF; temp = (signed long) scaled; dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); src += sourceStride; dest += destinationStride * 3; } */ short savedFpuControlWord; signed long tempInt32; (void) ditherGenerator; /* unused parameter */ __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 mov eax, sourceStride imul eax, edx mov ecx, count imul ecx, eax add ecx, esi mov edi, destinationBuffer mov edx, 3 // sizeof int24 mov ebx, destinationStride imul ebx, edx fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld int24Scaler_ // stack: (int)0x7FFFFF Float32_To_Int24_loop: // load unscaled value into st(0) fld dword ptr [esi] // stack: value, (int)0x7FFFFF add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF mov edx, tempInt32 mov byte ptr [edi], DL shr edx, 8 //mov byte ptr [edi+1], DL //mov byte ptr [edi+2], DH mov word ptr [edi+1], DX //add edi, ebx // increment destination ptr lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int24_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; signed long temp; (void) ditherGenerator; // unused parameter while( count-- ) { // convert to 32 bit and drop the low 8 bits double scaled = *src * 0x7FFFFFFF; PA_CLIP_( scaled, -2147483648., 2147483647. ); temp = (signed long) scaled; dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); src += sourceStride; dest += destinationStride * 3; } */ short savedFpuControlWord; signed long tempInt32; (void) ditherGenerator; /* unused parameter */ __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 mov eax, sourceStride imul eax, edx mov ecx, count imul ecx, eax add ecx, esi mov edi, destinationBuffer mov edx, 3 // sizeof int24 mov ebx, destinationStride imul ebx, edx fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld int24Scaler_ // stack: (int)0x7FFFFF Float32_To_Int24_Clip_loop: mov edx, dword ptr [esi] // load floating point value into integer register and edx, 0x7FFFFFFF // mask off sign cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 jg Float32_To_Int24_Clip_clamp // load unscaled value into st(0) fld dword ptr [esi] // stack: value, (int)0x7FFFFF add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF mov edx, tempInt32 jmp Float32_To_Int24_Clip_store Float32_To_Int24_Clip_clamp: mov edx, dword ptr [esi] // load floating point value into integer register shr edx, 31 // move sign bit into bit 0 add esi, eax // increment source ptr //lea esi, [esi+eax] add edx, 0x7FFFFF // convert to maximum range integers Float32_To_Int24_Clip_store: mov byte ptr [edi], DL shr edx, 8 //mov byte ptr [edi+1], DL //mov byte ptr [edi+2], DH mov word ptr [edi+1], DX //add edi, ebx // increment destination ptr lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int24_Clip_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int24_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; unsigned char *dest = (unsigned char*)destinationBuffer; signed long temp; while( count-- ) { // convert to 32 bit and drop the low 8 bits // FIXME: the dither amplitude here appears to be too small by 8 bits double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); // use smaller scaler to prevent overflow when we add the dither double dithered = ((double)*src * (2147483646.0)) + dither; PA_CLIP_( dithered, -2147483648., 2147483647. ); temp = (signed long) dithered; dest[0] = (unsigned char)(temp >> 8); dest[1] = (unsigned char)(temp >> 16); dest[2] = (unsigned char)(temp >> 24); src += sourceStride; dest += destinationStride * 3; } */ short savedFpuControlWord; // spill storage: signed long sourceByteStride; signed long highpassedDither; // dither state: unsigned long ditherPrevious = ditherGenerator->previous; unsigned long ditherRandSeed1 = ditherGenerator->randSeed1; unsigned long ditherRandSeed2 = ditherGenerator->randSeed2; signed long tempInt32; __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 mov eax, sourceStride imul eax, edx mov ecx, count imul ecx, eax add ecx, esi mov edi, destinationBuffer mov edx, 3 // sizeof int24 mov ebx, destinationStride imul ebx, edx fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld ditheredInt24Scaler_ // stack: int scaler Float32_To_Int24_DitherClip_loop: mov edx, dword ptr [esi] // load floating point value into integer register and edx, 0x7FFFFFFF // mask off sign cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 jg Float32_To_Int24_DitherClip_clamp // load unscaled value into st(0) fld dword ptr [esi] // stack: value, int scaler add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler /* // call PaUtil_GenerateFloatTriangularDither with C calling convention mov sourceByteStride, eax // save eax mov sourceEnd, ecx // save ecx push ditherGenerator // pass ditherGenerator parameter on stack call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler pop edx // clear parameter off stack mov ecx, sourceEnd // restore ecx mov eax, sourceByteStride // restore eax */ // generate dither mov sourceByteStride, eax // save eax mov edx, 196314165 mov eax, ditherRandSeed1 mul edx // eax:edx = eax * 196314165 //add eax, 907633515 lea eax, [eax+907633515] mov ditherRandSeed1, eax mov edx, 196314165 mov eax, ditherRandSeed2 mul edx // eax:edx = eax * 196314165 //add eax, 907633515 lea eax, [eax+907633515] mov edx, ditherRandSeed1 shr edx, PA_DITHER_SHIFT_ mov ditherRandSeed2, eax shr eax, PA_DITHER_SHIFT_ //add eax, edx // eax -> current lea eax, [eax+edx] mov edx, ditherPrevious neg edx lea edx, [eax+edx] // highpass = current - previous mov highpassedDither, edx mov ditherPrevious, eax // previous = current mov eax, sourceByteStride // restore eax fild highpassedDither fmul const_float_dither_scale_ // end generate dither, dither signal in st(0) faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler fistp tempInt32 // pop st(0) into tempInt32, stack: int scaler mov edx, tempInt32 jmp Float32_To_Int24_DitherClip_store Float32_To_Int24_DitherClip_clamp: mov edx, dword ptr [esi] // load floating point value into integer register shr edx, 31 // move sign bit into bit 0 add esi, eax // increment source ptr //lea esi, [esi+eax] add edx, 0x7FFFFF // convert to maximum range integers Float32_To_Int24_DitherClip_store: mov byte ptr [edi], DL shr edx, 8 //mov byte ptr [edi+1], DL //mov byte ptr [edi+2], DH mov word ptr [edi+1], DX //add edi, ebx // increment destination ptr lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int24_DitherClip_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } ditherGenerator->previous = ditherPrevious; ditherGenerator->randSeed1 = ditherRandSeed1; ditherGenerator->randSeed2 = ditherRandSeed2; } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; signed short *dest = (signed short*)destinationBuffer; (void)ditherGenerator; // unused parameter while( count-- ) { short samp = (short) (*src * (32767.0f)); *dest = samp; src += sourceStride; dest += destinationStride; } */ short savedFpuControlWord; (void) ditherGenerator; /* unused parameter */ __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 mov eax, sourceStride imul eax, edx // source byte stride mov ecx, count imul ecx, eax add ecx, esi // source end ptr = count * source byte stride + source ptr mov edi, destinationBuffer mov edx, 2 // sizeof int16 mov ebx, destinationStride imul ebx, edx // destination byte stride fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld int16Scaler_ // stack: (int)0x7FFF Float32_To_Int16_loop: // load unscaled value into st(0) fld dword ptr [esi] // stack: value, (int)0x7FFF add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF add edi, ebx // increment destination ptr //lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int16_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16_Clip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; signed short *dest = (signed short*)destinationBuffer; (void)ditherGenerator; // unused parameter while( count-- ) { long samp = (signed long) (*src * (32767.0f)); PA_CLIP_( samp, -0x8000, 0x7FFF ); *dest = (signed short) samp; src += sourceStride; dest += destinationStride; } */ short savedFpuControlWord; (void) ditherGenerator; /* unused parameter */ __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 mov eax, sourceStride imul eax, edx // source byte stride mov ecx, count imul ecx, eax add ecx, esi // source end ptr = count * source byte stride + source ptr mov edi, destinationBuffer mov edx, 2 // sizeof int16 mov ebx, destinationStride imul ebx, edx // destination byte stride fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld int16Scaler_ // stack: (int)0x7FFF Float32_To_Int16_Clip_loop: mov edx, dword ptr [esi] // load floating point value into integer register and edx, 0x7FFFFFFF // mask off sign cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 jg Float32_To_Int16_Clip_clamp // load unscaled value into st(0) fld dword ptr [esi] // stack: value, (int)0x7FFF add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF jmp Float32_To_Int16_Clip_stored Float32_To_Int16_Clip_clamp: mov edx, dword ptr [esi] // load floating point value into integer register shr edx, 31 // move sign bit into bit 0 add esi, eax // increment source ptr //lea esi, [esi+eax] add dx, 0x7FFF // convert to maximum range integers mov word ptr [edi], dx // store clamped into into dest Float32_To_Int16_Clip_stored: add edi, ebx // increment destination ptr //lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int16_Clip_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } } /* -------------------------------------------------------------------------- */ static void Float32_To_Int16_DitherClip( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride, unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) { /* float *src = (float*)sourceBuffer; signed short *dest = (signed short*)destinationBuffer; (void)ditherGenerator; // unused parameter while( count-- ) { float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); // use smaller scaler to prevent overflow when we add the dither float dithered = (*src * (32766.0f)) + dither; signed long samp = (signed long) dithered; PA_CLIP_( samp, -0x8000, 0x7FFF ); *dest = (signed short) samp; src += sourceStride; dest += destinationStride; } */ short savedFpuControlWord; // spill storage: signed long sourceByteStride; signed long highpassedDither; // dither state: unsigned long ditherPrevious = ditherGenerator->previous; unsigned long ditherRandSeed1 = ditherGenerator->randSeed1; unsigned long ditherRandSeed2 = ditherGenerator->randSeed2; __asm{ // esi -> source ptr // eax -> source byte stride // edi -> destination ptr // ebx -> destination byte stride // ecx -> source end ptr // edx -> temp mov esi, sourceBuffer mov edx, 4 // sizeof float32 mov eax, sourceStride imul eax, edx // source byte stride mov ecx, count imul ecx, eax add ecx, esi // source end ptr = count * source byte stride + source ptr mov edi, destinationBuffer mov edx, 2 // sizeof int16 mov ebx, destinationStride imul ebx, edx // destination byte stride fwait fstcw savedFpuControlWord fldcw fpuControlWord_ fld ditheredInt16Scaler_ // stack: int scaler Float32_To_Int16_DitherClip_loop: mov edx, dword ptr [esi] // load floating point value into integer register and edx, 0x7FFFFFFF // mask off sign cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 jg Float32_To_Int16_DitherClip_clamp // load unscaled value into st(0) fld dword ptr [esi] // stack: value, int scaler add esi, eax // increment source ptr //lea esi, [esi+eax] fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler /* // call PaUtil_GenerateFloatTriangularDither with C calling convention mov sourceByteStride, eax // save eax mov sourceEnd, ecx // save ecx push ditherGenerator // pass ditherGenerator parameter on stack call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler pop edx // clear parameter off stack mov ecx, sourceEnd // restore ecx mov eax, sourceByteStride // restore eax */ // generate dither mov sourceByteStride, eax // save eax mov edx, 196314165 mov eax, ditherRandSeed1 mul edx // eax:edx = eax * 196314165 //add eax, 907633515 lea eax, [eax+907633515] mov ditherRandSeed1, eax mov edx, 196314165 mov eax, ditherRandSeed2 mul edx // eax:edx = eax * 196314165 //add eax, 907633515 lea eax, [eax+907633515] mov edx, ditherRandSeed1 shr edx, PA_DITHER_SHIFT_ mov ditherRandSeed2, eax shr eax, PA_DITHER_SHIFT_ //add eax, edx // eax -> current lea eax, [eax+edx] // current = randSeed1>>x + randSeed2>>x mov edx, ditherPrevious neg edx lea edx, [eax+edx] // highpass = current - previous mov highpassedDither, edx mov ditherPrevious, eax // previous = current mov eax, sourceByteStride // restore eax fild highpassedDither fmul const_float_dither_scale_ // end generate dither, dither signal in st(0) faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler fistp word ptr [edi] // store scaled int into dest, stack: int scaler jmp Float32_To_Int16_DitherClip_stored Float32_To_Int16_DitherClip_clamp: mov edx, dword ptr [esi] // load floating point value into integer register shr edx, 31 // move sign bit into bit 0 add esi, eax // increment source ptr //lea esi, [esi+eax] add dx, 0x7FFF // convert to maximum range integers mov word ptr [edi], dx // store clamped into into dest Float32_To_Int16_DitherClip_stored: add edi, ebx // increment destination ptr //lea edi, [edi+ebx] cmp esi, ecx // has src ptr reached end? jne Float32_To_Int16_DitherClip_loop ffree st(0) fincstp fwait fnclex fldcw savedFpuControlWord } ditherGenerator->previous = ditherPrevious; ditherGenerator->randSeed1 = ditherRandSeed1; ditherGenerator->randSeed2 = ditherRandSeed2; } /* -------------------------------------------------------------------------- */ void PaUtil_InitializeX86PlainConverters( void ) { paConverters.Float32_To_Int32 = Float32_To_Int32; paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip; paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip; paConverters.Float32_To_Int24 = Float32_To_Int24; paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip; paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip; paConverters.Float32_To_Int16 = Float32_To_Int16; paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip; paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip; } #endif /* -------------------------------------------------------------------------- */ nyquist-3.05/portaudio/src/os/win/pa_x86_plain_converters.h0000644000175000000620000000415511466723256023132 0ustar stevestaff/* * Plain Intel IA32 assembly implementations of PortAudio sample converter functions. * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup win_src */ #ifndef PA_X86_PLAIN_CONVERTERS_H #define PA_X86_PLAIN_CONVERTERS_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** @brief Install optimised converter functions suitable for all IA32 processors It is recommended to call PaUtil_InitializeX86PlainConverters prior to calling Pa_Initialize */ void PaUtil_InitializeX86PlainConverters( void ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_X86_PLAIN_CONVERTERS_H */ nyquist-3.05/portaudio/src/os/win/pa_win_wdmks_utils.c0000644000175000000620000002355511466723256022272 0ustar stevestaff/* * PortAudio Portable Real-Time Audio Library * Windows WDM KS utilities * * Copyright (c) 1999 - 2007 Andrew Baldwin, Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ #include #include #include #include #include // just for some development printfs #include "portaudio.h" #include "pa_util.h" #include "pa_win_wdmks_utils.h" static PaError WdmGetPinPropertySimple( HANDLE handle, unsigned long pinId, unsigned long property, void* value, unsigned long valueSize ) { DWORD bytesReturned; KSP_PIN ksPProp; ksPProp.Property.Set = KSPROPSETID_Pin; ksPProp.Property.Id = property; ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; ksPProp.PinId = pinId; ksPProp.Reserved = 0; if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), value, valueSize, &bytesReturned, NULL ) == 0 || bytesReturned != valueSize ) { return paUnanticipatedHostError; } else { return paNoError; } } static PaError WdmGetPinPropertyMulti( HANDLE handle, unsigned long pinId, unsigned long property, KSMULTIPLE_ITEM** ksMultipleItem) { unsigned long multipleItemSize = 0; KSP_PIN ksPProp; DWORD bytesReturned; *ksMultipleItem = 0; ksPProp.Property.Set = KSPROPSETID_Pin; ksPProp.Property.Id = property; ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; ksPProp.PinId = pinId; ksPProp.Reserved = 0; if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp.Property, sizeof(KSP_PIN), NULL, 0, &multipleItemSize, NULL ) == 0 && GetLastError() != ERROR_MORE_DATA ) { return paUnanticipatedHostError; } *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); if( !*ksMultipleItem ) { return paInsufficientMemory; } if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), (void*)*ksMultipleItem, multipleItemSize, &bytesReturned, NULL ) == 0 || bytesReturned != multipleItemSize ) { PaUtil_FreeMemory( ksMultipleItem ); return paUnanticipatedHostError; } return paNoError; } static int GetKSFilterPinCount( HANDLE deviceHandle ) { DWORD result; if( WdmGetPinPropertySimple( deviceHandle, 0, KSPROPERTY_PIN_CTYPES, &result, sizeof(result) ) == paNoError ){ return result; }else{ return 0; } } static KSPIN_COMMUNICATION GetKSFilterPinPropertyCommunication( HANDLE deviceHandle, int pinId ) { KSPIN_COMMUNICATION result; if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_COMMUNICATION, &result, sizeof(result) ) == paNoError ){ return result; }else{ return KSPIN_COMMUNICATION_NONE; } } static KSPIN_DATAFLOW GetKSFilterPinPropertyDataflow( HANDLE deviceHandle, int pinId ) { KSPIN_DATAFLOW result; if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_DATAFLOW, &result, sizeof(result) ) == paNoError ){ return result; }else{ return (KSPIN_DATAFLOW)0; } } static int KSFilterPinPropertyIdentifiersInclude( HANDLE deviceHandle, int pinId, unsigned long property, const GUID *identifierSet, unsigned long identifierId ) { KSMULTIPLE_ITEM* item = NULL; KSIDENTIFIER* identifier; int i; int result = 0; if( WdmGetPinPropertyMulti( deviceHandle, pinId, property, &item) != paNoError ) return 0; identifier = (KSIDENTIFIER*)(item+1); for( i = 0; i < (int)item->Count; i++ ) { if( !memcmp( (void*)&identifier[i].Set, (void*)identifierSet, sizeof( GUID ) ) && ( identifier[i].Id == identifierId ) ) { result = 1; break; } } PaUtil_FreeMemory( item ); return result; } /* return the maximum channel count supported by any pin on the device. if isInput is non-zero we query input pins, otherwise output pins. */ int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput ) { HANDLE deviceHandle; int pinCount, pinId, i; int result = 0; KSPIN_DATAFLOW requiredDataflowDirection = (isInput ? KSPIN_DATAFLOW_OUT : KSPIN_DATAFLOW_IN ); if( !wcharDevicePath ) return 0; deviceHandle = CreateFileW( (LPCWSTR)wcharDevicePath, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); if( deviceHandle == INVALID_HANDLE_VALUE ) return 0; pinCount = GetKSFilterPinCount( deviceHandle ); for( pinId = 0; pinId < pinCount; ++pinId ) { KSPIN_COMMUNICATION communication = GetKSFilterPinPropertyCommunication( deviceHandle, pinId ); KSPIN_DATAFLOW dataflow = GetKSFilterPinPropertyDataflow( deviceHandle, pinId ); if( ( dataflow == requiredDataflowDirection ) && (( communication == KSPIN_COMMUNICATION_SINK) || ( communication == KSPIN_COMMUNICATION_BOTH)) && ( KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, KSPROPERTY_PIN_INTERFACES, &KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_STREAMING ) || KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, KSPROPERTY_PIN_INTERFACES, &KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_LOOPED_STREAMING ) ) && KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, KSPROPERTY_PIN_MEDIUMS, &KSMEDIUMSETID_Standard, KSMEDIUM_STANDARD_DEVIO ) ) { KSMULTIPLE_ITEM* item = NULL; if( WdmGetPinPropertyMulti( deviceHandle, pinId, KSPROPERTY_PIN_DATARANGES, &item ) == paNoError ) { KSDATARANGE *dataRange = (KSDATARANGE*)(item+1); for( i=0; i < item->Count; ++i ){ if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) || memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0 || memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0 || ( ( memcmp( (void*)&dataRange->MajorFormat, (void*)&KSDATAFORMAT_TYPE_AUDIO, sizeof(GUID) ) == 0 ) && ( memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof(GUID) ) == 0 ) ) ) { KSDATARANGE_AUDIO *dataRangeAudio = (KSDATARANGE_AUDIO*)dataRange; /* printf( ">>> %d %d %d %d %S\n", isInput, dataflow, communication, dataRangeAudio->MaximumChannels, devicePath ); if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX, sizeof(GUID) ) == 0 ) printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WAVEFORMATEX\n" ); else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_DSOUND, sizeof(GUID) ) == 0 ) printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_DSOUND\n" ); else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WILDCARD, sizeof(GUID) ) == 0 ) printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WILDCARD\n" ); else printf( "\tspecifier: ?\n" ); */ /* We assume that very high values for MaximumChannels are not useful and indicate that the driver isn't prepared to tell us the real number of channels which it supports. */ if( dataRangeAudio->MaximumChannels < 0xFFFFUL && (int)dataRangeAudio->MaximumChannels > result ) result = (int)dataRangeAudio->MaximumChannels; } dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); } PaUtil_FreeMemory( item ); } } } CloseHandle( deviceHandle ); return result; } nyquist-3.05/portaudio/src/os/win/pa_win_wdmks_utils.h0000644000175000000620000000470511466723256022273 0ustar stevestaff#ifndef PA_WIN_WDMKS_UTILS_H #define PA_WIN_WDMKS_UTILS_H /* * PortAudio Portable Real-Time Audio Library * Windows WDM KS utilities * * Copyright (c) 1999 - 2007 Ross Bencina, Andrew Baldwin * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @brief Utilities for working with the Windows WDM KS API */ #ifdef __cplusplus extern "C" { #endif /** Query for the maximum number of channels supported by any pin of the specified device. Returns 0 if the query fails for any reason. @param wcharDevicePath A system level PnP interface path, supplied as a WCHAR unicode string. Declard as void* to avoid introducing a dependency on wchar_t here. @param isInput A flag specifying whether to query for input (non-zero) or output (zero) channels. */ int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_WIN_WDMKS_UTILS_H */nyquist-3.05/portaudio/src/os/win/pa_win_hostapis.c0000644000175000000620000000613111466723256021546 0ustar stevestaff/* * $Id: pa_win_hostapis.c,v 1.1 2010/11/04 21:04:15 rbd Exp $ * Portable Audio I/O Library Windows initialization table * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup win_src Win32 host API initialization function table. @todo Consider using PA_USE_WMME etc instead of PA_NO_WMME. This is what the Unix version does, we should consider being consistent. */ #include "pa_hostapi.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ PaUtilHostApiInitializer *paHostApiInitializers[] = { #ifndef PA_NO_WMME PaWinMme_Initialize, #endif #ifndef PA_NO_DS PaWinDs_Initialize, #endif #ifndef PA_NO_ASIO PaAsio_Initialize, #endif /* #ifndef PA_NO_WASAPI PaWinWasapi_Initialize, #endif #ifndef PA_NO_WDMKS PaWinWdm_Initialize, #endif */ PaSkeleton_Initialize, /* just for testing */ 0 /* NULL terminated array */ }; int paDefaultHostApiIndex = 0; nyquist-3.05/portaudio/src/os/win/pa_win_util.c0000644000175000000620000000733011466723256020673 0ustar stevestaff/* * $Id: pa_win_util.c,v 1.1 2010/11/04 21:04:15 rbd Exp $ * Portable Audio I/O Library * Win32 platform-specific support functions * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup win_src Win32 platform-specific support functions. @todo Implement workaround for QueryPerformanceCounter() skipping forward bug. (see msdn kb Q274323). */ #include #include /* for timeGetTime() */ #include "pa_util.h" /* Track memory allocations to avoid leaks. */ #if PA_TRACK_MEMORY static int numAllocations_ = 0; #endif void *PaUtil_AllocateMemory( long size ) { void *result = GlobalAlloc( GPTR, size ); #if PA_TRACK_MEMORY if( result != NULL ) numAllocations_ += 1; #endif return result; } void PaUtil_FreeMemory( void *block ) { if( block != NULL ) { GlobalFree( block ); #if PA_TRACK_MEMORY numAllocations_ -= 1; #endif } } int PaUtil_CountCurrentlyAllocatedBlocks( void ) { #if PA_TRACK_MEMORY return numAllocations_; #else return 0; #endif } void Pa_Sleep( long msec ) { Sleep( msec ); } static int usePerformanceCounter_; static double secondsPerTick_; void PaUtil_InitializeClock( void ) { LARGE_INTEGER ticksPerSecond; if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 ) { usePerformanceCounter_ = 1; secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart; } else { usePerformanceCounter_ = 0; } } double PaUtil_GetTime( void ) { LARGE_INTEGER time; if( usePerformanceCounter_ ) { /* FIXME: according to this knowledge-base article, QueryPerformanceCounter can skip forward by seconds! http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323& it may be better to use the rtdsc instruction using inline asm, however then a method is needed to calculate a ticks/seconds ratio. */ QueryPerformanceCounter( &time ); return time.QuadPart * secondsPerTick_; } else { #ifndef UNDER_CE return timeGetTime() * .001; #else return GetTickCount() * .001; #endif } } nyquist-3.05/portaudio/src/os/mac_osx/0002755000175000000620000000000011537433131017035 5ustar stevestaffnyquist-3.05/portaudio/src/os/mac_osx/pa_mac_hostapis.c0000644000175000000620000000550311466723256022347 0ustar stevestaff/* * $Id: pa_mac_hostapis.c,v 1.1 2010/11/04 21:04:15 rbd Exp $ * Portable Audio I/O Library Macintosh initialization table * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup macosx_src Mac OS host API initialization function table. */ #include "pa_hostapi.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaMacSm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); PaError PaMacAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } #endif /* __cplusplus */ PaUtilHostApiInitializer *paHostApiInitializers[] = { #ifdef PA_USE_COREAUDIO PaMacCore_Initialize, #endif #ifdef PA_USE_SM PaMacSm_Initialize, #endif #ifdef PA_USE_JACK PaJack_Initialize, #endif #ifdef PA_USE_ASIO PaMacAsio_Initialize, #endif PaSkeleton_Initialize, /* just for testing */ 0 /* NULL terminated array */ }; int paDefaultHostApiIndex = 0; nyquist-3.05/portaudio/aclocal.m40000644000175000000620000000375110144436365016045 0ustar stevestaff dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page dnl also defines GSTUFF_PKG_ERRORS on error AC_DEFUN(PKG_CHECK_MODULES, [ succeeded=no if test -z "$PKG_CONFIG"; then AC_PATH_PROG(PKG_CONFIG, pkg-config, no) fi if test "$PKG_CONFIG" = "no" ; then echo "*** The pkg-config script could not be found. Make sure it is" echo "*** in your path, or set the PKG_CONFIG environment variable" echo "*** to the full path to pkg-config." echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." else PKG_CONFIG_MIN_VERSION=0.9.0 if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then AC_MSG_CHECKING(for $2) if $PKG_CONFIG --exists "$2" ; then AC_MSG_RESULT(yes) succeeded=yes AC_MSG_CHECKING($1_CFLAGS) $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` AC_MSG_RESULT($$1_CFLAGS) AC_MSG_CHECKING($1_LIBS) $1_LIBS=`$PKG_CONFIG --libs "$2"` AC_MSG_RESULT($$1_LIBS) else $1_CFLAGS="" $1_LIBS="" ## If we have a custom action on failure, don't print errors, but ## do set a variable so people can do so. $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` ifelse([$4], ,echo $$1_PKG_ERRORS,) fi AC_SUBST($1_CFLAGS) AC_SUBST($1_LIBS) else echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." echo "*** See http://www.freedesktop.org/software/pkgconfig" fi fi if test $succeeded = yes; then ifelse([$3], , :, [$3]) else ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) fi ]) nyquist-3.05/portaudio/README.txt0000644000175000000620000001044211466723256015704 0ustar stevestaffREADME for PortAudio /* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Copyright (c) 1999-2006 Phil Burk and Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ PortAudio is a portable audio I/O library designed for cross-platform support of audio. It uses either a callback mechanism to request audio processing, or blocking read/write calls to buffer data between the native audio subsystem and the client. Audio can be processed in various formats, including 32 bit floating point, and will be converted to the native format internally. Documentation: Documentation is available in "/doc/html/index.html" Also see "src/common/portaudio.h" for API spec. Also see http://www.portaudio.com/docs/ And see "tests/patest_saw.c" for an example. For information on compiling programs with PortAudio, please see the tutorial at: http://portaudio.com/trac/wiki/TutorialDir/TutorialStart Important Files and Folders: include/portaudio.h = header file for PortAudio API. Specifies API. src/common/ = platform independant code, host independant code for all implementations. src/os = os specific (but host api neutral) code src/hostapi = implementations for different host apis pablio = simple blocking read/write interface Host API Implementations: src/hostapi/alsa = Advanced Linux Sound Architecture (ALSA) src/hostapi/asihpi = AudioScience HPI src/hostapi/asio = ASIO for Windows and Macintosh src/hostapi/coreaudio = Macintosh Core Audio for OS X src/hostapi/dsound = Windows Direct Sound src/hostapi/jack = JACK Audio Connection Kit src/hostapi/oss = Unix Open Sound System (OSS) src/hostapi/wasapi = Windows Vista WASAPI src/hostapi/wdmks = Windows WDM Kernel Streaming src/hostapi/wmme = Windows MME (most widely supported) Test Programs: tests/pa_fuzz.c = guitar fuzz box tests/pa_devs.c = print a list of available devices tests/pa_minlat.c = determine minimum latency for your machine tests/paqa_devs.c = self test that opens all devices tests/paqa_errs.c = test error detection and reporting tests/patest_clip.c = hear a sine wave clipped and unclipped tests/patest_dither.c = hear effects of dithering (extremely subtle) tests/patest_pink.c = fun with pink noise tests/patest_record.c = record and playback some audio tests/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad(). tests/patest_sine.c = output a sine wave in a simple PA app tests/patest_sync.c = test syncronization of audio and video tests/patest_wire.c = pass input to output, wire simulator nyquist-3.05/portaudio/Makefile.in0000644000175000000620000001211011466723256016245 0ustar stevestaff# # PortAudio V19 Makefile.in # # Dominic Mazzoni # Modifications by Mikael Magnusson # top_srcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ top_builddir = . PREFIX = @prefix@ prefix = $(PREFIX) exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ includedir = @includedir@ CC = @CC@ CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/common -I$(top_srcdir)/src/os/unix @CFLAGS@ @DEFS@ LIBS = @LIBS@ AR = @AR@ RANLIB = @RANLIB@ LIBTOOL = @LIBTOOL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ SHARED_FLAGS = @SHARED_FLAGS@ LDFLAGS = @LDFLAGS@ DLL_LIBS = @DLL_LIBS@ CXXFLAGS = @CXXFLAGS@ NASM = @NASM@ NASMOPT = @NASMOPT@ LN_S = @LN_S@ LT_RELEASE=@LT_RELEASE@ LT_CURRENT=@LT_CURRENT@ LT_REVISION=@LT_REVISION@ LT_AGE=@LT_AGE@ OTHER_OBJS = @OTHER_OBJS@ PALIB = libportaudio.la PAINC = include/portaudio.h PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined -export-symbols-regex "(Pa|PaMacCore)_.*" -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) #MAKEFILE = Makefile COMMON_OBJS = \ src/common/pa_allocation.o \ src/common/pa_converters.o \ src/common/pa_cpuload.o \ src/common/pa_dither.o \ src/common/pa_debugprint.o \ src/common/pa_front.o \ src/common/pa_process.o \ src/common/pa_skeleton.o \ src/common/pa_stream.o \ src/common/pa_trace.o TESTS = \ bin/paqa_devs \ bin/paqa_errs \ bin/patest1 \ bin/patest_buffer \ bin/patest_callbackstop \ bin/patest_clip \ bin/patest_dither \ bin/patest_hang \ bin/patest_in_overflow \ bin/patest_latency \ bin/patest_leftright \ bin/patest_longsine \ bin/patest_many \ bin/patest_maxsines \ bin/patest_multi_sine \ bin/patest_out_underflow \ bin/patest_pink \ bin/patest_prime \ bin/patest_read_record \ bin/patest_read_write_wire \ bin/patest_record \ bin/patest_ringmix \ bin/patest_saw \ bin/patest_sine8 \ bin/patest_sine \ bin/patest_sine_channelmaps \ bin/patest_sine_formats \ bin/patest_sine_time \ bin/patest_start_stop \ bin/patest_stop \ bin/patest_stop_playout \ bin/patest_toomanysines \ bin/patest_underflow \ bin/patest_wire \ bin/patest_write_sine \ bin/pa_devs \ bin/pa_fuzz \ bin/pa_minlat # Most of these don't compile yet. Put them in TESTS, above, if # you want to try to compile them... ALL_TESTS = \ $(TESTS) \ bin/patest_sync \ bin/debug_convert \ bin/debug_dither_calc \ bin/debug_dual \ bin/debug_multi_in \ bin/debug_multi_out \ bin/debug_record \ bin/debug_record_reuse \ bin/debug_sine_amp \ bin/debug_sine \ bin/debug_sine_formats \ bin/debug_srate \ bin/debug_test1 OBJS = $(COMMON_OBJS) $(OTHER_OBJS) LTOBJS:= $(OBJS:.o=.lo) SUBDIRS = @ENABLE_CXX_TRUE@SUBDIRS += bindings/cpp all: lib/$(PALIB) all-recursive tests tests: bin-stamp $(TESTS) lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC) $(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS) $(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS) install: lib/$(PALIB) portaudio-2.0.pc $(INSTALL) -d $(DESTDIR)$(libdir) $(LIBTOOL) --mode=install $(INSTALL) lib/$(PALIB) $(DESTDIR)$(libdir) $(INSTALL) -d $(DESTDIR)$(includedir) $(INSTALL_DATA) -m 644 $(top_srcdir)/$(PAINC) $(DESTDIR)$(includedir)/portaudio.h $(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig $(INSTALL) -m 644 portaudio-2.0.pc $(DESTDIR)$(libdir)/pkgconfig/portaudio-2.0.pc @echo "" @echo "------------------------------------------------------------" @echo "PortAudio was successfully installed." @echo "" @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" @echo "to make the shared object available. You may also need to" @echo "modify your LD_LIBRARY_PATH environment variable to include" @echo "the directory $(libdir)" @echo "------------------------------------------------------------" @echo "" $(MAKE) install-recursive uninstall: $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB) $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h $(MAKE) uninstall-recursive clean: $(LIBTOOL) --mode=clean rm -f $(LTOBJS) $(ALL_TESTS) lib/$(PALIB) rm -f bin-stamp lib-stamp -rm -rf bin lib distclean: clean rm -f config.log config.status Makefile libtool portaudio-2.0.pc %.o: %.c $(MAKEFILE) $(PAINC) $(CC) -c $(CFLAGS) $< -o $@ %.lo: %.c $(MAKEFILE) $(PAINC) $(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@ %.o: %.cpp $(MAKEFILE) $(PAINC) $(CXX) -c $(CXXFLAGS) $< -o $@ %.o: %.asm $(NASM) $(NASMOPT) -o $@ $< bin-stamp: -mkdir bin touch $@ lib-stamp: -mkdir lib -mkdir -p \ src/common \ src/hostapi/alsa \ src/hostapi/asihpi \ src/hostapi/asio \ src/hostapi/coreaudio \ src/hostapi/dsound \ src/hostapi/jack \ src/hostapi/oss \ src/hostapi/wasapi \ src/hostapi/wdmks \ src/hostapi/wmme \ src/os/mac_osx \ src/os/unix \ src/os/win touch $@ Makefile: Makefile.in config.status $(SHELL) config.status all-recursive: for dir in $(SUBDIRS); do make -C $$dir all; done install-recursive: for dir in $(SUBDIRS); do make -C $$dir install; done uninstall-recursive: for dir in $(SUBDIRS); do make -C $$dir uninstall; done nyquist-3.05/portaudio/config.sub0000755000175000000620000007242511466723256016202 0ustar stevestaff#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-02-22' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic4x | c4x*) basic_machine=tic4x-unknown os=-coff ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nyquist-3.05/portaudio/doc/0002755000175000000620000000000011537433131014741 5ustar stevestaffnyquist-3.05/portaudio/doc/src/0002755000175000000620000000000011537433131015530 5ustar stevestaffnyquist-3.05/portaudio/doc/src/srcguide.dox0000644000175000000620000000127711466723256020071 0ustar stevestaff/* define all of the file groups used to structure the documentation. */ /** @defgroup common_src Source code common to all implementations */ /** @defgroup win_src Source code common to all Windows implementations */ /** @defgroup unix_src Source code common to all Unix implementations */ /** @defgroup macosx_src Source code common to all Macintosh implementations */ /** @defgroup hostaip_src Source code for specific Host APIs */ /** @defgroup test_src Test and example programs */ /** @page srcguide A guide to the PortAudio sources. - \ref common_src - \ref win_src - \ref unix_src - \ref macosx_src - \ref hostaip_src - \ref test_src */nyquist-3.05/portaudio/doc/src/mainpage.dox0000644000175000000620000000302411466723256020035 0ustar stevestaff/* doxygen index page */ /** @mainpage PortAudio is an open-source cross-platform C library for audio input and output. It is designed to simplify the porting of audio applications between various platforms, and also to simplify the development of audio software in general by hiding the complexities of device interfacing. See the PortAudio website for further information http://www.portaudio.com This documentation pertains to PortAudio V19, API version 2.0 which is currently under development. API version 2.0 differs in a number of ways from previous versions, please consult the enhancement proposals for further details: http://www.portaudio.com/docs/proposals/index.html This documentation is under construction. Things you might be interested in include: - The PortAudio API 2.0, as documented in portaudio.h - Tutorials for the V19 API, currently housed on the PortAudio Wiki: http://www.portaudio.com/trac/wiki/TutorialDir/TutorialStart - Implementation status is documented here: http://www.portaudio.com/docs/proposals/status.html - @ref srcguide - The @ref License If you're interested in contributing to PortAudio, you may be interested in: - The doxygen generated TODO List. Feel free to pick an item off TODO list and fix/implement it. You may want to enquire about status on the PortAudio mailing list first. - Our issue tracking system: http://www.portaudio.com/trac - Coding guidelines: http://www.portaudio.com/docs/proposals/014-StyleGuide.html */nyquist-3.05/portaudio/doc/src/license.dox0000644000175000000620000000313711466723256017703 0ustar stevestaff/** @page License PortAudio License PortAudio Portable Real-Time Audio Library
    Copyright (c) 1999-2006 Ross Bencina, Phil Burk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    The text above constitutes the entire PortAudio license; however, the PortAudio community also makes the following non-binding requests: Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. It is also requested that these non-binding requests be included along with the license above. */nyquist-3.05/portaudio/doc/utils/0002755000175000000620000000000011537433131016101 5ustar stevestaffnyquist-3.05/portaudio/doc/utils/checkfiledocs.py0000644000175000000620000000461511466723256021260 0ustar stevestaffimport os import os.path import string paRootDirectory = '../../' paHtmlDocDirectory = os.path.join( paRootDirectory, "doc", "html" ) ##this script assumes that html doxygen documentation has been generated ## ##it then walks the entire portaudio source tree and check that ##- every source file (.c,.h,.cpp) has a doxygen comment block containing ## - a @file directive ## - a @brief directive ## - a @ingroup directive ##- it also checks that a corresponding html documentation file has been generated. ## ##This can be used as a first-level check to make sure the documentation is in order. ## ##The idea is to get a list of which files are missing doxygen documentation. # recurse from top and return a list of all with the given # extensions. ignore .svn directories. return absolute paths def recursiveFindFiles( top, extensions, includePaths ): result = [] for (dirpath, dirnames, filenames) in os.walk(top): if not '.svn' in dirpath: for f in filenames: if os.path.splitext(f)[1] in extensions: if includePaths: result.append( os.path.abspath( os.path.join( dirpath, f ) ) ) else: result.append( f ) return result # generate the html file name that doxygen would use for # a particular source file. this is a brittle conversion # which i worked out by trial and error def doxygenHtmlDocFileName( sourceFile ): return sourceFile.replace( '_', '__' ).replace( '.', '_8' ) + '.html' sourceFiles = recursiveFindFiles( paRootDirectory, [ '.c', '.h', '.cpp' ], True ); docFiles = recursiveFindFiles( paHtmlDocDirectory, [ '.html' ], False ); currentFile = "" def printError( f, message ): global currentFile if f != currentFile: currentFile = f print f, ":" print "\t!", message for f in sourceFiles: if not doxygenHtmlDocFileName( os.path.basename(f) ) in docFiles: printError( f, "no doxygen generated doc page" ) s = file( f, 'rt' ).read() if not '/**' in s: printError( f, "no doxygen /** block" ) if not '@file' in s: printError( f, "no doxygen @file tag" ) if not '@brief' in s: printError( f, "no doxygen @brief tag" ) if not '@ingroup' in s: printError( f, "no doxygen @ingroup tag" ) nyquist-3.05/portaudio/config.doxy0000644000175000000620000001603110144436365016352 0ustar stevestaff# Doxyfile 1.2.13-20020210 #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- PROJECT_NAME = PortAudio PROJECT_NUMBER = 2.0 OUTPUT_DIRECTORY = "./docs/" OUTPUT_LANGUAGE = English EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = INTERNAL_DOCS = NO STRIP_CODE_COMMENTS = YES CASE_SENSE_NAMES = YES SHORT_NAMES = NO HIDE_SCOPE_NAMES = NO VERBATIM_HEADERS = YES SHOW_INCLUDE_FILES = YES JAVADOC_AUTOBRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES ALIASES = ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ./pa_common ./pa_win_wmme ./pa_asio ./pa_win_ds ./pa_linux_alsa ./pa_unix_oss ./pa_jack ./pa_tests FILE_PATTERNS = *.h *.c *.cpp RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = doxygen_html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO HIDE_UNDOC_RELATIONS = NO HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES TEMPLATE_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO CGI_NAME = search.cgi CGI_URL = DOC_URL = DOC_ABSPATH = BIN_ABSPATH = /usr/local/bin/ EXT_DOC_PATHS = nyquist-3.05/portaudio/include/0002755000175000000620000000000011537433131015617 5ustar stevestaffnyquist-3.05/portaudio/include/portaudio.h0000644000175000000620000012412611466723256020015 0ustar stevestaff#ifndef PORTAUDIO_H #define PORTAUDIO_H /* * $Id: portaudio.h,v 1.1 2010/11/04 20:17:54 rbd Exp $ * PortAudio Portable Real-Time Audio Library * PortAudio API Header File * Latest version available at: http://www.portaudio.com/ * * Copyright (c) 1999-2002 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @brief The PortAudio API. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** Retrieve the release number of the currently running PortAudio build, eg 1900. */ int Pa_GetVersion( void ); /** Retrieve a textual description of the current PortAudio build, eg "PortAudio V19-devel 13 October 2002". */ const char* Pa_GetVersionText( void ); /** Error codes returned by PortAudio functions. Note that with the exception of paNoError, all PaErrorCodes are negative. */ typedef int PaError; typedef enum PaErrorCode { paNoError = 0, paNotInitialized = -10000, paUnanticipatedHostError, paInvalidChannelCount, paInvalidSampleRate, paInvalidDevice, paInvalidFlag, paSampleFormatNotSupported, paBadIODeviceCombination, paInsufficientMemory, paBufferTooBig, paBufferTooSmall, paNullCallback, paBadStreamPtr, paTimedOut, paInternalError, paDeviceUnavailable, paIncompatibleHostApiSpecificStreamInfo, paStreamIsStopped, paStreamIsNotStopped, paInputOverflowed, paOutputUnderflowed, paHostApiNotFound, paInvalidHostApi, paCanNotReadFromACallbackStream, /**< @todo review error code name */ paCanNotWriteToACallbackStream, /**< @todo review error code name */ paCanNotReadFromAnOutputOnlyStream, /**< @todo review error code name */ paCanNotWriteToAnInputOnlyStream, /**< @todo review error code name */ paIncompatibleStreamHostApi, paBadBufferPtr } PaErrorCode; /** Translate the supplied PortAudio error code into a human readable message. */ const char *Pa_GetErrorText( PaError errorCode ); /** Library initialization function - call this before using PortAudio. This function initialises internal data structures and prepares underlying host APIs for use. With the exception of Pa_GetVersion(), Pa_GetVersionText(), and Pa_GetErrorText(), this function MUST be called before using any other PortAudio API functions. If Pa_Initialize() is called multiple times, each successful call must be matched with a corresponding call to Pa_Terminate(). Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not required to be fully nested. Note that if Pa_Initialize() returns an error code, Pa_Terminate() should NOT be called. @return paNoError if successful, otherwise an error code indicating the cause of failure. @see Pa_Terminate */ PaError Pa_Initialize( void ); /** Library termination function - call this when finished using PortAudio. This function deallocates all resources allocated by PortAudio since it was initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has been called multiple times, each call must be matched with a corresponding call to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically close any PortAudio streams that are still open. Pa_Terminate() MUST be called before exiting a program which uses PortAudio. Failure to do so may result in serious resource leaks, such as audio devices not being available until the next reboot. @return paNoError if successful, otherwise an error code indicating the cause of failure. @see Pa_Initialize */ PaError Pa_Terminate( void ); /** The type used to refer to audio devices. Values of this type usually range from 0 to (Pa_GetDeviceCount()-1), and may also take on the PaNoDevice and paUseHostApiSpecificDeviceSpecification values. @see Pa_GetDeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification */ typedef int PaDeviceIndex; /** A special PaDeviceIndex value indicating that no device is available, or should be used. @see PaDeviceIndex */ #define paNoDevice ((PaDeviceIndex)-1) /** A special PaDeviceIndex value indicating that the device(s) to be used are specified in the host api specific stream info structure. @see PaDeviceIndex */ #define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) /* Host API enumeration mechanism */ /** The type used to enumerate to host APIs at runtime. Values of this type range from 0 to (Pa_GetHostApiCount()-1). @see Pa_GetHostApiCount */ typedef int PaHostApiIndex; /** Retrieve the number of available host APIs. Even if a host API is available it may have no devices available. @return A non-negative value indicating the number of available host APIs or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. @see PaHostApiIndex */ PaHostApiIndex Pa_GetHostApiCount( void ); /** Retrieve the index of the default host API. The default host API will be the lowest common denominator host API on the current platform and is unlikely to provide the best performance. @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) indicating the default host API index or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. */ PaHostApiIndex Pa_GetDefaultHostApi( void ); /** Unchanging unique identifiers for each supported host API. This type is used in the PaHostApiInfo structure. The values are guaranteed to be unique and to never change, thus allowing code to be written that conditionally uses host API specific extensions. New type ids will be allocated when support for a host API reaches "public alpha" status, prior to that developers should use the paInDevelopment type id. @see PaHostApiInfo */ typedef enum PaHostApiTypeId { paInDevelopment=0, /* use while developing support for a new host API */ paDirectSound=1, paMME=2, paASIO=3, paSoundManager=4, paCoreAudio=5, paOSS=7, paALSA=8, paAL=9, paBeOS=10, paWDMKS=11, paJACK=12, paWASAPI=13, paAudioScienceHPI=14 } PaHostApiTypeId; /** A structure containing information about a particular host API. */ typedef struct PaHostApiInfo { /** this is struct version 1 */ int structVersion; /** The well known unique identifier of this host API @see PaHostApiTypeId */ PaHostApiTypeId type; /** A textual description of the host API for display on user interfaces. */ const char *name; /** The number of devices belonging to this host API. This field may be used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate all devices for this host API. @see Pa_HostApiDeviceIndexToDeviceIndex */ int deviceCount; /** The default input device for this host API. The value will be a device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice if no default input device is available. */ PaDeviceIndex defaultInputDevice; /** The default output device for this host API. The value will be a device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice if no default output device is available. */ PaDeviceIndex defaultOutputDevice; } PaHostApiInfo; /** Retrieve a pointer to a structure containing information about a specific host Api. @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) @return A pointer to an immutable PaHostApiInfo structure describing a specific host API. If the hostApi parameter is out of range or an error is encountered, the function returns NULL. The returned structure is owned by the PortAudio implementation and must not be manipulated or freed. The pointer is only guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). */ const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); /** Convert a static host API unique identifier, into a runtime host API index. @param type A unique host API identifier belonging to the PaHostApiTypeId enumeration. @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. The paHostApiNotFound error code indicates that the host API specified by the type parameter is not available. @see PaHostApiTypeId */ PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); /** Convert a host-API-specific device index to standard PortAudio device index. This function may be used in conjunction with the deviceCount field of PaHostApiInfo to enumerate all devices for the specified host API. @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) @param hostApiDeviceIndex A valid per-host device index in the range 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. A paInvalidHostApi error code indicates that the host API index specified by the hostApi parameter is out of range. A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter is out of range. @see PaHostApiInfo */ PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex ); /** Structure used to return information about a host error condition. */ typedef struct PaHostErrorInfo{ PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ long errorCode; /**< the error code returned */ const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ }PaHostErrorInfo; /** Return information about the last host error encountered. The error information returned by Pa_GetLastHostErrorInfo() will never be modified asyncronously by errors occurring in other PortAudio owned threads (such as the thread that manages the stream callback.) This function is provided as a last resort, primarily to enhance debugging by providing clients with access to all available error information. @return A pointer to an immutable structure constaining information about the host error. The values in this structure will only be valid if a PortAudio function has previously returned the paUnanticipatedHostError error code. */ const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); /* Device enumeration and capabilities */ /** Retrieve the number of available devices. The number of available devices may be zero. @return A non-negative value indicating the number of available devices or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. */ PaDeviceIndex Pa_GetDeviceCount( void ); /** Retrieve the index of the default input device. The result can be used in the inputDevice parameter to Pa_OpenStream(). @return The default input device index for the default host API, or paNoDevice if no default input device is available or an error was encountered. */ PaDeviceIndex Pa_GetDefaultInputDevice( void ); /** Retrieve the index of the default output device. The result can be used in the outputDevice parameter to Pa_OpenStream(). @return The default output device index for the defualt host API, or paNoDevice if no default output device is available or an error was encountered. @note On the PC, the user can specify a default device by setting an environment variable. For example, to use device #1.
     set PA_RECOMMENDED_OUTPUT_DEVICE=1
    
    The user should first determine the available device ids by using the supplied application "pa_devs". */ PaDeviceIndex Pa_GetDefaultOutputDevice( void ); /** The type used to represent monotonic time in seconds that can be used for syncronisation. The type is used for the outTime argument to the PaStreamCallback and as the result of Pa_GetStreamTime(). @see PaStreamCallback, Pa_GetStreamTime */ typedef double PaTime; /** A type used to specify one or more sample formats. Each value indicates a possible format for sound data passed to and from the stream callback, Pa_ReadStream and Pa_WriteStream. The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 and aUInt8 are usually implemented by all implementations. The floating point representation (paFloat32) uses +1.0 and -1.0 as the maximum and minimum respectively. paUInt8 is an unsigned 8 bit format where 128 is considered "ground" The paNonInterleaved flag indicates that a multichannel buffer is passed as a set of non-interleaved pointers. @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo @see paFloat32, paInt16, paInt32, paInt24, paInt8 @see paUInt8, paCustomFormat, paNonInterleaved */ typedef unsigned long PaSampleFormat; #define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ #define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ #define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ #define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ #define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ #define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ #define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */ #define paNonInterleaved ((PaSampleFormat) 0x80000000) /** A structure providing information and capabilities of PortAudio devices. Devices may support input, output or both input and output. */ typedef struct PaDeviceInfo { int structVersion; /* this is struct version 2 */ const char *name; PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/ int maxInputChannels; int maxOutputChannels; /* Default latency values for interactive performance. */ PaTime defaultLowInputLatency; PaTime defaultLowOutputLatency; /* Default latency values for robust non-interactive applications (eg. playing sound files). */ PaTime defaultHighInputLatency; PaTime defaultHighOutputLatency; double defaultSampleRate; } PaDeviceInfo; /** Retrieve a pointer to a PaDeviceInfo structure containing information about the specified device. @return A pointer to an immutable PaDeviceInfo structure. If the device parameter is out of range the function returns NULL. @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) @note PortAudio manages the memory referenced by the returned pointer, the client must not manipulate or free the memory. The pointer is only guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). @see PaDeviceInfo, PaDeviceIndex */ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); /** Parameters for one direction (input or output) of a stream. */ typedef struct PaStreamParameters { /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) specifying the device to be used or the special constant paUseHostApiSpecificDeviceSpecification which indicates that the actual device(s) to use are specified in hostApiSpecificStreamInfo. This field must not be set to paNoDevice. */ PaDeviceIndex device; /** The number of channels of sound to be delivered to the stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). It can range from 1 to the value of maxInputChannels in the PaDeviceInfo record for the device specified by the device parameter. */ int channelCount; /** The sample format of the buffer provided to the stream callback, a_ReadStream() or Pa_WriteStream(). It may be any of the formats described by the PaSampleFormat enumeration. */ PaSampleFormat sampleFormat; /** The desired latency in seconds. Where practical, implementations should configure their latency based on these parameters, otherwise they may choose the closest viable latency instead. Unless the suggested latency is greater than the absolute upper limit for the device implementations should round the suggestedLatency up to the next practial value - ie to provide an equal or higher latency than suggestedLatency wherever possibe. Actual latency values for an open stream may be retrieved using the inputLatency and outputLatency fields of the PaStreamInfo structure returned by Pa_GetStreamInfo(). @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo */ PaTime suggestedLatency; /** An optional pointer to a host api specific data structure containing additional information for device setup and/or stream processing. hostApiSpecificStreamInfo is never required for correct operation, if not used it should be set to NULL. */ void *hostApiSpecificStreamInfo; } PaStreamParameters; /** Return code for Pa_IsFormatSupported indicating success. */ #define paFormatIsSupported (0) /** Determine whether it would be possible to open a stream with the specified parameters. @param inputParameters A structure that describes the input parameters used to open a stream. The suggestedLatency field is ignored. See PaStreamParameters for a description of these parameters. inputParameters must be NULL for output-only streams. @param outputParameters A structure that describes the output parameters used to open a stream. The suggestedLatency field is ignored. See PaStreamParameters for a description of these parameters. outputParameters must be NULL for input-only streams. @param sampleRate The required sampleRate. For full-duplex streams it is the sample rate for both input and output @return Returns 0 if the format is supported, and an error code indicating why the format is not supported otherwise. The constant paFormatIsSupported is provided to compare with the return value for success. @see paFormatIsSupported, PaStreamParameters */ PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); /* Streaming types and functions */ /** A single PaStream can provide multiple channels of real-time streaming audio input and output to a client application. A stream provides access to audio hardware represented by one or more PaDevices. Depending on the underlying Host API, it may be possible to open multiple streams using the same device, however this behavior is implementation defined. Portable applications should assume that a PaDevice may be simultaneously used by at most one PaStream. Pointers to PaStream objects are passed between PortAudio functions that operate on streams. @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, Pa_GetStreamTime, Pa_GetStreamCpuLoad */ typedef void PaStream; /** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() or Pa_OpenDefaultStream() to indicate that the stream callback will accept buffers of any size. */ #define paFramesPerBufferUnspecified (0) /** Flags used to control the behavior of a stream. They are passed as parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be ORed together. @see Pa_OpenStream, Pa_OpenDefaultStream @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags */ typedef unsigned long PaStreamFlags; /** @see PaStreamFlags */ #define paNoFlag ((PaStreamFlags) 0) /** Disable default clipping of out of range samples. @see PaStreamFlags */ #define paClipOff ((PaStreamFlags) 0x00000001) /** Disable default dithering. @see PaStreamFlags */ #define paDitherOff ((PaStreamFlags) 0x00000002) /** Flag requests that where possible a full duplex stream will not discard overflowed input samples without calling the stream callback. This flag is only valid for full duplex callback streams and only when used in combination with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using this flag incorrectly results in a paInvalidFlag error being returned from Pa_OpenStream and Pa_OpenDefaultStream. @see PaStreamFlags, paFramesPerBufferUnspecified */ #define paNeverDropInput ((PaStreamFlags) 0x00000004) /** Call the stream callback to fill initial output buffers, rather than the default behavior of priming the buffers with zeros (silence). This flag has no effect for input-only and blocking read/write streams. @see PaStreamFlags */ #define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) /** A mask specifying the platform specific bits. @see PaStreamFlags */ #define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) /** Timing information for the buffers passed to the stream callback. */ typedef struct PaStreamCallbackTimeInfo{ PaTime inputBufferAdcTime; PaTime currentTime; PaTime outputBufferDacTime; } PaStreamCallbackTimeInfo; /** Flag bit constants for the statusFlags to PaStreamCallback. @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, paPrimingOutput */ typedef unsigned long PaStreamCallbackFlags; /** In a stream opened with paFramesPerBufferUnspecified, indicates that input data is all silence (zeros) because no real data is available. In a stream opened without paFramesPerBufferUnspecified, it indicates that one or more zero samples have been inserted into the input buffer to compensate for an input underflow. @see PaStreamCallbackFlags */ #define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) /** In a stream opened with paFramesPerBufferUnspecified, indicates that data prior to the first sample of the input buffer was discarded due to an overflow, possibly because the stream callback is using too much CPU time. Otherwise indicates that data prior to one or more samples in the input buffer was discarded. @see PaStreamCallbackFlags */ #define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) /** Indicates that output data (or a gap) was inserted, possibly because the stream callback is using too much CPU time. @see PaStreamCallbackFlags */ #define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) /** Indicates that output data will be discarded because no room is available. @see PaStreamCallbackFlags */ #define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) /** Some of all of the output data will be used to prime the stream, input data may be zero. @see PaStreamCallbackFlags */ #define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) /** Allowable return values for the PaStreamCallback. @see PaStreamCallback */ typedef enum PaStreamCallbackResult { paContinue=0, paComplete=1, paAbort=2 } PaStreamCallbackResult; /** Functions of type PaStreamCallback are implemented by PortAudio clients. They consume, process or generate audio in response to requests from an active PortAudio stream. @param input and @param output are arrays of interleaved samples, the format, packing and number of channels used by the buffers are determined by parameters to Pa_OpenStream(). @param frameCount The number of sample frames to be processed by the stream callback. @param timeInfo The time in seconds when the first sample of the input buffer was received at the audio input, the time in seconds when the first sample of the output buffer will begin being played at the audio output, and the time in seconds when the stream callback was called. See also Pa_GetStreamTime() @param statusFlags Flags indicating whether input and/or output buffers have been inserted or will be dropped to overcome underflow or overflow conditions. @param userData The value of a user supplied pointer passed to Pa_OpenStream() intended for storing synthesis data etc. @return The stream callback should return one of the values in the PaStreamCallbackResult enumeration. To ensure that the callback continues to be called, it should return paContinue (0). Either paComplete or paAbort can be returned to finish stream processing, after either of these values is returned the callback will not be called again. If paAbort is returned the stream will finish as soon as possible. If paComplete is returned, the stream will continue until all buffers generated by the callback have been played. This may be useful in applications such as soundfile players where a specific duration of output is required. However, it is not necessary to utilise this mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also be used to stop the stream. The callback must always fill the entire output buffer irrespective of its return value. @see Pa_OpenStream, Pa_OpenDefaultStream @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call PortAudio API functions from within the stream callback. */ typedef int PaStreamCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ); /** Opens a stream for either input, output or both. @param stream The address of a PaStream pointer which will receive a pointer to the newly opened stream. @param inputParameters A structure that describes the input parameters used by the opened stream. See PaStreamParameters for a description of these parameters. inputParameters must be NULL for output-only streams. @param outputParameters A structure that describes the output parameters used by the opened stream. See PaStreamParameters for a description of these parameters. outputParameters must be NULL for input-only streams. @param sampleRate The desired sampleRate. For full-duplex streams it is the sample rate for both input and output @param framesPerBuffer The number of frames passed to the stream callback function, or the preferred block granularity for a blocking read/write stream. The special value paFramesPerBufferUnspecified (0) may be used to request that the stream callback will recieve an optimal (and possibly varying) number of frames based on host requirements and the requested latency settings. Note: With some host APIs, the use of non-zero framesPerBuffer for a callback stream may introduce an additional layer of buffering which could introduce additional latency. PortAudio guarantees that the additional latency will be kept to the theoretical minimum however, it is strongly recommended that a non-zero framesPerBuffer value only be used when your algorithm requires a fixed number of frames per stream callback. @param streamFlags Flags which modify the behaviour of the streaming process. This parameter may contain a combination of flags ORed together. Some flags may only be relevant to certain buffer formats. @param streamCallback A pointer to a client supplied function that is responsible for processing and filling input and output buffers. If this parameter is NULL the stream will be opened in 'blocking read/write' mode. In blocking mode, the client can receive sample data using Pa_ReadStream and write sample data using Pa_WriteStream, the number of samples that may be read or written without blocking is returned by Pa_GetStreamReadAvailable and Pa_GetStreamWriteAvailable respectively. @param userData A client supplied pointer which is passed to the stream callback function. It could for example, contain a pointer to instance data necessary for processing the audio buffers. This parameter is ignored if streamCallback is NULL. @return Upon success Pa_OpenStream() returns paNoError and places a pointer to a valid PaStream in the stream argument. The stream is inactive (stopped). If a call to Pa_OpenStream() fails, a non-zero error code is returned (see PaError for possible error codes) and the value of stream is invalid. @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable */ PaError Pa_OpenStream( PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData ); /** A simplified version of Pa_OpenStream() that opens the default input and/or output devices. @param stream The address of a PaStream pointer which will receive a pointer to the newly opened stream. @param numInputChannels The number of channels of sound that will be supplied to the stream callback or returned by Pa_ReadStream. It can range from 1 to the value of maxInputChannels in the PaDeviceInfo record for the default input device. If 0 the stream is opened as an output-only stream. @param numOutputChannels The number of channels of sound to be delivered to the stream callback or passed to Pa_WriteStream. It can range from 1 to the value of maxOutputChannels in the PaDeviceInfo record for the default output dvice. If 0 the stream is opened as an output-only stream. @param sampleFormat The sample format of both the input and output buffers provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. sampleFormat may be any of the formats described by the PaSampleFormat enumeration. @param sampleRate Same as Pa_OpenStream parameter of the same name. @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. @param streamCallback Same as Pa_OpenStream parameter of the same name. @param userData Same as Pa_OpenStream parameter of the same name. @return As for Pa_OpenStream @see Pa_OpenStream, PaStreamCallback */ PaError Pa_OpenDefaultStream( PaStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, PaStreamCallback *streamCallback, void *userData ); /** Closes an audio stream. If the audio stream is active it discards any pending buffers as if Pa_AbortStream() had been called. */ PaError Pa_CloseStream( PaStream *stream ); /** Functions of type PaStreamFinishedCallback are implemented by PortAudio clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback function. Once registered they are called when the stream becomes inactive (ie once a call to Pa_StopStream() will not block). A stream will become inactive after the stream callback returns non-zero, or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio output, if the stream callback returns paComplete, or Pa_StopStream is called, the stream finished callback will not be called until all generated sample data has been played. @param userData The userData parameter supplied to Pa_OpenStream() @see Pa_SetStreamFinishedCallback */ typedef void PaStreamFinishedCallback( void *userData ); /** Register a stream finished callback function which will be called when the stream becomes inactive. See the description of PaStreamFinishedCallback for further details about when the callback will be called. @param stream a pointer to a PaStream that is in the stopped state - if the stream is not stopped, the stream's finished callback will remain unchanged and an error code will be returned. @param streamFinishedCallback a pointer to a function with the same signature as PaStreamFinishedCallback, that will be called when the stream becomes inactive. Passing NULL for this parameter will un-register a previously registered stream finished callback function. @return on success returns paNoError, otherwise an error code indicating the cause of the error. @see PaStreamFinishedCallback */ PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); /** Commences audio processing. */ PaError Pa_StartStream( PaStream *stream ); /** Terminates audio processing. It waits until all pending audio buffers have been played before it returns. */ PaError Pa_StopStream( PaStream *stream ); /** Terminates audio processing immediately without waiting for pending buffers to complete. */ PaError Pa_AbortStream( PaStream *stream ); /** Determine whether the stream is stopped. A stream is considered to be stopped prior to a successful call to Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. If a stream callback returns a value other than paContinue the stream is NOT considered to be stopped. @return Returns one (1) when the stream is stopped, zero (0) when the stream is running or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive */ PaError Pa_IsStreamStopped( PaStream *stream ); /** Determine whether the stream is active. A stream is active after a successful call to Pa_StartStream(), until it becomes inactive either as a result of a call to Pa_StopStream() or Pa_AbortStream(), or as a result of a return value other than paContinue from the stream callback. In the latter case, the stream is considered inactive after the last buffer has finished playing. @return Returns one (1) when the stream is active (ie playing or recording audio), zero (0) when not playing or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped */ PaError Pa_IsStreamActive( PaStream *stream ); /** A structure containing unchanging information about an open stream. @see Pa_GetStreamInfo */ typedef struct PaStreamInfo { /** this is struct version 1 */ int structVersion; /** The input latency of the stream in seconds. This value provides the most accurate estimate of input latency available to the implementation. It may differ significantly from the suggestedLatency value passed to Pa_OpenStream(). The value of this field will be zero (0.) for output-only streams. @see PaTime */ PaTime inputLatency; /** The output latency of the stream in seconds. This value provides the most accurate estimate of output latency available to the implementation. It may differ significantly from the suggestedLatency value passed to Pa_OpenStream(). The value of this field will be zero (0.) for input-only streams. @see PaTime */ PaTime outputLatency; /** The sample rate of the stream in Hertz (samples per second). In cases where the hardware sample rate is inaccurate and PortAudio is aware of it, the value of this field may be different from the sampleRate parameter passed to Pa_OpenStream(). If information about the actual hardware sample rate is not available, this field will have the same value as the sampleRate parameter passed to Pa_OpenStream(). */ double sampleRate; } PaStreamInfo; /** Retrieve a pointer to a PaStreamInfo structure containing information about the specified stream. @return A pointer to an immutable PaStreamInfo structure. If the stream parameter invalid, or an error is encountered, the function returns NULL. @param stream A pointer to an open stream previously created with Pa_OpenStream. @note PortAudio manages the memory referenced by the returned pointer, the client must not manipulate or free the memory. The pointer is only guaranteed to be valid until the specified stream is closed. @see PaStreamInfo */ const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); /** Determine the current time for the stream according to the same clock used to generate buffer timestamps. This time may be used for syncronising other events to the audio stream, for example synchronizing audio to MIDI. @return The stream's current time in seconds, or 0 if an error occurred. @see PaTime, PaStreamCallback */ PaTime Pa_GetStreamTime( PaStream *stream ); /** Retrieve CPU usage information for the specified stream. The "CPU Load" is a fraction of total CPU time consumed by a callback stream's audio processing routines including, but not limited to the client supplied stream callback. This function does not work with blocking read/write streams. This function may be called from the stream callback function or the application. @return A floating point value, typically between 0.0 and 1.0, where 1.0 indicates that the stream callback is consuming the maximum number of CPU cycles possible to maintain real-time operation. A value of 0.5 would imply that PortAudio and the stream callback was consuming roughly 50% of the available CPU time. The return value may exceed 1.0. A value of 0.0 will always be returned for a blocking read/write stream, or if an error occurrs. */ double Pa_GetStreamCpuLoad( PaStream* stream ); /** Read samples from an input stream. The function doesn't return until the entire buffer has been filled - this may involve waiting for the operating system to supply the data. @param stream A pointer to an open stream previously created with Pa_OpenStream. @param buffer A pointer to a buffer of sample frames. The buffer contains samples in the format specified by the inputParameters->sampleFormat field used to open the stream, and the number of channels specified by inputParameters->numChannels. If non-interleaved samples were requested, buffer is a pointer to the first element of an array of non-interleaved buffer pointers, one for each channel. @param frames The number of frames to be read into buffer. This parameter is not constrained to a specific range, however high performance applications will want to match this parameter to the framesPerBuffer parameter used when opening the stream. @return On success PaNoError will be returned, or PaInputOverflowed if input data was discarded by PortAudio after the previous call and before this call. */ PaError Pa_ReadStream( PaStream* stream, void *buffer, unsigned long frames ); /** Write samples to an output stream. This function doesn't return until the entire buffer has been consumed - this may involve waiting for the operating system to consume the data. @param stream A pointer to an open stream previously created with Pa_OpenStream. @param buffer A pointer to a buffer of sample frames. The buffer contains samples in the format specified by the outputParameters->sampleFormat field used to open the stream, and the number of channels specified by outputParameters->numChannels. If non-interleaved samples were requested, buffer is a pointer to the first element of an array of non-interleaved buffer pointers, one for each channel. @param frames The number of frames to be written from buffer. This parameter is not constrained to a specific range, however high performance applications will want to match this parameter to the framesPerBuffer parameter used when opening the stream. @return On success PaNoError will be returned, or paOutputUnderflowed if additional output data was inserted after the previous call and before this call. */ PaError Pa_WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); /** Retrieve the number of frames that can be read from the stream without waiting. @return Returns a non-negative value representing the maximum number of frames that can be read from the stream without blocking or busy waiting or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. */ signed long Pa_GetStreamReadAvailable( PaStream* stream ); /** Retrieve the number of frames that can be written to the stream without waiting. @return Returns a non-negative value representing the maximum number of frames that can be written to the stream without blocking or busy waiting or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. */ signed long Pa_GetStreamWriteAvailable( PaStream* stream ); /* Miscellaneous utilities */ /** Retrieve the size of a given sample format in bytes. @return The size in bytes of a single sample in the specified format, or paSampleFormatNotSupported if the format is not supported. */ PaError Pa_GetSampleSize( PaSampleFormat format ); /** Put the caller to sleep for at least 'msec' milliseconds. This function is provided only as a convenience for authors of portable code (such as the tests and examples in the PortAudio distribution.) The function may sleep longer than requested so don't rely on this for accurate musical timing. */ void Pa_Sleep( long msec ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PORTAUDIO_H */ nyquist-3.05/portaudio/include/pa_win_wmme.h0000644000175000000620000001472411466723256020313 0ustar stevestaff#ifndef PA_WIN_WMME_H #define PA_WIN_WMME_H /* * $Id: pa_win_wmme.h,v 1.1 2010/11/04 20:17:54 rbd Exp $ * PortAudio Portable Real-Time Audio Library * MME specific extensions * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @brief WMME-specific PortAudio API extension header file. */ #include "portaudio.h" #include "pa_win_waveformat.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define paWinMmeUseLowLevelLatencyParameters (0x01) #define paWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */ #define paWinMmeUseChannelMask (0x04) /* By default, the mme implementation drops the processing thread's priority to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100% This flag disables any priority throttling. The processing thread will always run at THREAD_PRIORITY_TIME_CRITICAL. */ #define paWinMmeDontThrottleOverloadedProcessingThread (0x08) typedef struct PaWinMmeDeviceAndChannelCount{ PaDeviceIndex device; int channelCount; }PaWinMmeDeviceAndChannelCount; typedef struct PaWinMmeStreamInfo{ unsigned long size; /**< sizeof(PaWinMmeStreamInfo) */ PaHostApiTypeId hostApiType; /**< paMME */ unsigned long version; /**< 1 */ unsigned long flags; /* low-level latency setting support These settings control the number and size of host buffers in order to set latency. They will be used instead of the generic parameters to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters flag. If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters are supplied for both input and output in a full duplex stream, then the input and output framesPerBuffer must be the same, or the larger of the two must be a multiple of the smaller, otherwise a paIncompatibleHostApiSpecificStreamInfo error will be returned from Pa_OpenStream(). */ unsigned long framesPerBuffer; unsigned long bufferCount; /* formerly numBuffers */ /* multiple devices per direction support If flags contains the PaWinMmeUseMultipleDevices flag, this functionality will be used, otherwise the device parameter to Pa_OpenStream() will be used instead. If devices are specified here, the corresponding device parameter to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification, otherwise an paInvalidDevice error will result. The total number of channels accross all specified devices must agree with the corresponding channelCount parameter to Pa_OpenStream() otherwise a paInvalidChannelCount error will result. */ PaWinMmeDeviceAndChannelCount *devices; unsigned long deviceCount; /* support for WAVEFORMATEXTENSIBLE channel masks. If flags contains paWinMmeUseChannelMask this allows you to specify which speakers to address in a multichannel stream. Constants for channelMask are specified in pa_win_waveformat.h */ PaWinWaveFormatChannelMask channelMask; }PaWinMmeStreamInfo; /** Retrieve the number of wave in handles used by a PortAudio WinMME stream. Returns zero if the stream is output only. @return A non-negative value indicating the number of wave in handles or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. @see PaWinMME_GetStreamInputHandle */ int PaWinMME_GetStreamInputHandleCount( PaStream* stream ); /** Retrieve a wave in handle used by a PortAudio WinMME stream. @param stream The stream to query. @param handleIndex The zero based index of the wave in handle to retrieve. This should be in the range [0, PaWinMME_GetStreamInputHandleCount(stream)-1]. @return A valid wave in handle, or NULL if an error occurred. @see PaWinMME_GetStreamInputHandle */ HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex ); /** Retrieve the number of wave out handles used by a PortAudio WinMME stream. Returns zero if the stream is input only. @return A non-negative value indicating the number of wave out handles or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered. @see PaWinMME_GetStreamOutputHandle */ int PaWinMME_GetStreamOutputHandleCount( PaStream* stream ); /** Retrieve a wave out handle used by a PortAudio WinMME stream. @param stream The stream to query. @param handleIndex The zero based index of the wave out handle to retrieve. This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1]. @return A valid wave out handle, or NULL if an error occurred. @see PaWinMME_GetStreamOutputHandleCount */ HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_WIN_WMME_H */ nyquist-3.05/portaudio/include/pa_asio.h0000644000175000000620000001144311466723256017417 0ustar stevestaff#ifndef PA_ASIO_H #define PA_ASIO_H /* * $Id: pa_asio.h,v 1.1 2010/11/04 20:17:54 rbd Exp $ * PortAudio Portable Real-Time Audio Library * ASIO specific extensions * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @brief ASIO-specific PortAudio API extension header file. */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** Retrieve legal latency settings for the specificed device, in samples. @param device The global index of the device about which the query is being made. @param minLatency A pointer to the location which will recieve the minimum latency value. @param maxLatency A pointer to the location which will recieve the maximum latency value. @param preferredLatency A pointer to the location which will recieve the preferred latency value. @param granularity A pointer to the location which will recieve the granularity. This value determines which values between minLatency and maxLatency are available. ie the step size, if granularity is -1 then available latency settings are powers of two. @see ASIOGetBufferSize in the ASIO SDK. @todo This function should have a better name, any suggestions? */ PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device, long *minLatency, long *maxLatency, long *preferredLatency, long *granularity ); /** Display the ASIO control panel for the specified device. @param device The global index of the device whose control panel is to be displayed. @param systemSpecific On Windows, the calling application's main window handle, on Macintosh this value should be zero. */ PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ); /** Retrieve a pointer to a string containing the name of the specified input channel. The string is valid until Pa_Terminate is called. The string will be no longer than 32 characters including the null terminator. */ PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, const char** channelName ); /** Retrieve a pointer to a string containing the name of the specified input channel. The string is valid until Pa_Terminate is called. The string will be no longer than 32 characters including the null terminator. */ PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, const char** channelName ); #define paAsioUseChannelSelectors (0x01) typedef struct PaAsioStreamInfo{ unsigned long size; /**< sizeof(PaAsioStreamInfo) */ PaHostApiTypeId hostApiType; /**< paASIO */ unsigned long version; /**< 1 */ unsigned long flags; /* Support for opening only specific channels of an ASIO device. If the paAsioUseChannelSelectors flag is set, channelSelectors is a pointer to an array of integers specifying the device channels to use. When used, the length of the channelSelectors array must match the corresponding channelCount parameter to Pa_OpenStream() otherwise a crash may result. The values in the selectors array must specify channels within the range of supported channels for the device or paInvalidChannelCount will result. */ int *channelSelectors; }PaAsioStreamInfo; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_ASIO_H */ nyquist-3.05/portaudio/include/pa_mac_core.h0000644000175000000620000001515111466723256020234 0ustar stevestaff#ifndef PA_MAC_CORE_H #define PA_MAC_CORE_H /* * PortAudio Portable Real-Time Audio Library * Macintosh Core Audio specific extensions * portaudio.h should be included before this file. * * Copyright (c) 2005-2006 Bjorn Roche * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ #include //#include #ifdef __cplusplus extern "C" { #endif /* * A pointer to a paMacCoreStreamInfo may be passed as * the hostApiSpecificStreamInfo in the PaStreamParameters struct * when opening a stream or querying the format. Use NULL, for the * defaults. Note that for duplex streams, flags for input and output * should be the same or behaviour is undefined. */ typedef struct { unsigned long size; /**size of whole structure including this header */ PaHostApiTypeId hostApiType; /**host API for which this data is intended */ unsigned long version; /**structure version */ unsigned long flags; /* flags to modify behaviour */ SInt32 const * channelMap; /* Channel map for HAL channel mapping , if not needed, use NULL;*/ unsigned long channelMapSize; /* Channel map size for HAL channel mapping , if not needed, use 0;*/ } PaMacCoreStreamInfo; /* * Functions */ /* Use this function to initialize a paMacCoreStreamInfo struct * using the requested flags. Note that channel mapping is turned * off after a call to this function. * @param data The datastructure to initialize * @param flags The flags to initialize the datastructure with. */ void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, unsigned long flags ); /* call this after pa_SetupMacCoreStreamInfo to use channel mapping as described in notes.txt. * @param data The stream info structure to assign a channel mapping to * @param channelMap The channel map array, as described in notes.txt. This array pointer will be used directly (ie the underlying data will not be copied), so the caller should not free the array until after the stream has been opened. * @param channelMapSize The size of the channel map array. */ void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, unsigned long channelMapSize ); /* * Retrieve the AudioDeviceID of the input device assigned to an open stream * * @param s The stream to query. * * @return A valid AudioDeviceID, or NULL if an error occurred. */ AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ); /* * Retrieve the AudioDeviceID of the output device assigned to an open stream * * @param s The stream to query. * * @return A valid AudioDeviceID, or NULL if an error occurred. */ AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ); /* * Returns a statically allocated string with the device's name * for the given channel. NULL will be returned on failure. * * This function's implemenation is not complete! * * @param device The PortAudio device index. * @param channel The channel number who's name is requested. * @return a statically allocated string with the name of the device. * Because this string is statically allocated, it must be * coppied if it is to be saved and used by the user after * another call to this function. * */ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); /* * Flags */ /* * The following flags alter the behaviour of PA on the mac platform. * they can be ORed together. These should work both for opening and * checking a device. */ /* Allows PortAudio to change things like the device's frame size, * which allows for much lower latency, but might disrupt the device * if other programs are using it, even when you are just Querying * the device. */ #define paMacCoreChangeDeviceParameters (0x01) /* In combination with the above flag, * causes the stream opening to fail, unless the exact sample rates * are supported by the device. */ #define paMacCoreFailIfConversionRequired (0x02) /* These flags set the SR conversion quality, if required. The wierd ordering * allows Maximum Quality to be the default.*/ #define paMacCoreConversionQualityMin (0x0100) #define paMacCoreConversionQualityMedium (0x0200) #define paMacCoreConversionQualityLow (0x0300) #define paMacCoreConversionQualityHigh (0x0400) #define paMacCoreConversionQualityMax (0x0000) /* * Here are some "preset" combinations of flags (above) to get to some * common configurations. THIS IS OVERKILL, but if more flags are added * it won't be. */ /*This is the default setting: do as much sample rate conversion as possible * and as little mucking with the device as possible. */ #define paMacCorePlayNice (0x00) /*This setting is tuned for pro audio apps. It allows SR conversion on input and output, but it tries to set the appropriate SR on the device.*/ #define paMacCorePro (0x01) /*This is a setting to minimize CPU usage and still play nice.*/ #define paMacCoreMinimizeCPUButPlayNice (0x0100) /*This is a setting to minimize CPU usage, even if that means interrupting the device. */ #define paMacCoreMinimizeCPU (0x0101) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_MAC_CORE_H */ nyquist-3.05/portaudio/include/pa_linux_alsa.h0000644000175000000620000000623411466723256020625 0ustar stevestaff#ifndef PA_LINUX_ALSA_H #define PA_LINUX_ALSA_H /* * $Id: pa_linux_alsa.h,v 1.1 2010/11/04 20:17:54 rbd Exp $ * PortAudio Portable Real-Time Audio Library * ALSA-specific extensions * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file * ALSA-specific PortAudio API extension header file. */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif typedef struct PaAlsaStreamInfo { unsigned long size; PaHostApiTypeId hostApiType; unsigned long version; const char *deviceString; } PaAlsaStreamInfo; /** Initialize host API specific structure, call this before setting relevant attributes. */ void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info ); /** Instruct whether to enable real-time priority when starting the audio thread. * * If this is turned on by the stream is started, the audio callback thread will be created * with the FIFO scheduling policy, which is suitable for realtime operation. **/ void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable ); #if 0 void PaAlsa_EnableWatchdog( PaStream *s, int enable ); #endif /** Get the ALSA-lib card index of this stream's input device. */ PaError PaAlsa_GetStreamInputCard( PaStream *s, int *card ); /** Get the ALSA-lib card index of this stream's output device. */ PaError PaAlsa_GetStreamOutputCard( PaStream *s, int *card ); /** Set the number of periods (buffer fragments) to configure devices with. * * By default the number of periods is 4, this is the lowest number of periods that works well on * the author's soundcard. * @param numPeriods The number of periods. */ PaError PaAlsa_SetNumPeriods( int numPeriods ); #ifdef __cplusplus } #endif #endif nyquist-3.05/portaudio/include/pa_jack.h0000644000175000000620000000532111466723256017372 0ustar stevestaff#ifndef PA_JACK_H #define PA_JACK_H /* * $Id: * PortAudio Portable Real-Time Audio Library * JACK-specific extensions * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file * JACK-specific PortAudio API extension header file. */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif /** Set the JACK client name. * * During Pa_Initialize, When PA JACK connects as a client of the JACK server, it requests a certain * name, which is for instance prepended to port names. By default this name is "PortAudio". The * JACK server may append a suffix to the client name, in order to avoid clashes among clients that * try to connect with the same name (e.g., different PA JACK clients). * * This function must be called before Pa_Initialize, otherwise it won't have any effect. Note that * the string is not copied, but instead referenced directly, so it must not be freed for as long as * PA might need it. * @sa PaJack_GetClientName */ PaError PaJack_SetClientName( const char* name ); /** Get the JACK client name used by PA JACK. * * The caller is responsible for freeing the returned pointer. */ PaError PaJack_GetClientName(const char** clientName); #ifdef __cplusplus } #endif #endif nyquist-3.05/portaudio/include/pa_win_ds.h0000644000175000000620000000723311466723256017751 0ustar stevestaff#ifndef PA_WIN_DS_H #define PA_WIN_DS_H /* * $Id: pa_win_ds.h,v 1.1 2010/11/04 20:17:54 rbd Exp $ * PortAudio Portable Real-Time Audio Library * DirectSound specific extensions * * Copyright (c) 1999-2007 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @brief DirectSound-specific PortAudio API extension header file. */ #include "portaudio.h" #include "pa_win_waveformat.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define paWinDirectSoundUseLowLevelLatencyParameters (0x01) #define paWinDirectSoundUseChannelMask (0x04) typedef struct PaWinDirectSoundStreamInfo{ unsigned long size; /**< sizeof(PaWinDirectSoundStreamInfo) */ PaHostApiTypeId hostApiType; /**< paDirectSound */ unsigned long version; /**< 1 */ unsigned long flags; /* low-level latency setting support TODO ** NOT IMPLEMENTED ** These settings control the number and size of host buffers in order to set latency. They will be used instead of the generic parameters to Pa_OpenStream() if flags contains the paWinDirectSoundUseLowLevelLatencyParameters flag. If PaWinDirectSoundStreamInfo structures with paWinDirectSoundUseLowLevelLatencyParameters are supplied for both input and output in a full duplex stream, then the input and output framesPerBuffer must be the same, or the larger of the two must be a multiple of the smaller, otherwise a paIncompatibleHostApiSpecificStreamInfo error will be returned from Pa_OpenStream(). unsigned long framesPerBuffer; */ /* support for WAVEFORMATEXTENSIBLE channel masks. If flags contains paWinDirectSoundUseChannelMask this allows you to specify which speakers to address in a multichannel stream. Constants for channelMask are specified in pa_win_waveformat.h */ PaWinWaveFormatChannelMask channelMask; }PaWinDirectSoundStreamInfo; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_WIN_DS_H */ nyquist-3.05/portaudio/include/pa_win_waveformat.h0000644000175000000620000002023411466723256021512 0ustar stevestaff#ifndef PA_WIN_WAVEFORMAT_H #define PA_WIN_WAVEFORMAT_H /* * PortAudio Portable Real-Time Audio Library * Windows WAVEFORMAT* data structure utilities * portaudio.h should be included before this file. * * Copyright (c) 2007 Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. It is also * requested that these non-binding requests be included along with the * license above. */ /** @file @brief Windows specific PortAudio API extension and utilities header file. */ #ifdef __cplusplus extern "C" { #endif /* The following #defines for speaker channel masks are the same as those in ksmedia.h, except with PAWIN_ prepended, KSAUDIO_ removed in some cases, and casts to PaWinWaveFormatChannelMask added. */ typedef unsigned long PaWinWaveFormatChannelMask; /* Speaker Positions: */ #define PAWIN_SPEAKER_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1) #define PAWIN_SPEAKER_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x2) #define PAWIN_SPEAKER_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x4) #define PAWIN_SPEAKER_LOW_FREQUENCY ((PaWinWaveFormatChannelMask)0x8) #define PAWIN_SPEAKER_BACK_LEFT ((PaWinWaveFormatChannelMask)0x10) #define PAWIN_SPEAKER_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20) #define PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER ((PaWinWaveFormatChannelMask)0x40) #define PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER ((PaWinWaveFormatChannelMask)0x80) #define PAWIN_SPEAKER_BACK_CENTER ((PaWinWaveFormatChannelMask)0x100) #define PAWIN_SPEAKER_SIDE_LEFT ((PaWinWaveFormatChannelMask)0x200) #define PAWIN_SPEAKER_SIDE_RIGHT ((PaWinWaveFormatChannelMask)0x400) #define PAWIN_SPEAKER_TOP_CENTER ((PaWinWaveFormatChannelMask)0x800) #define PAWIN_SPEAKER_TOP_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1000) #define PAWIN_SPEAKER_TOP_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x2000) #define PAWIN_SPEAKER_TOP_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x4000) #define PAWIN_SPEAKER_TOP_BACK_LEFT ((PaWinWaveFormatChannelMask)0x8000) #define PAWIN_SPEAKER_TOP_BACK_CENTER ((PaWinWaveFormatChannelMask)0x10000) #define PAWIN_SPEAKER_TOP_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20000) /* Bit mask locations reserved for future use */ #define PAWIN_SPEAKER_RESERVED ((PaWinWaveFormatChannelMask)0x7FFC0000) /* Used to specify that any possible permutation of speaker configurations */ #define PAWIN_SPEAKER_ALL ((PaWinWaveFormatChannelMask)0x80000000) /* DirectSound Speaker Config */ #define PAWIN_SPEAKER_DIRECTOUT 0 #define PAWIN_SPEAKER_MONO (PAWIN_SPEAKER_FRONT_CENTER) #define PAWIN_SPEAKER_STEREO (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT) #define PAWIN_SPEAKER_QUAD (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) #define PAWIN_SPEAKER_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_BACK_CENTER) #define PAWIN_SPEAKER_5POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) #define PAWIN_SPEAKER_7POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER | PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER) #define PAWIN_SPEAKER_5POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) #define PAWIN_SPEAKER_7POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) /* According to the Microsoft documentation: The following are obsolete 5.1 and 7.1 settings (they lack side speakers). Note this means that the default 5.1 and 7.1 settings (KSAUDIO_SPEAKER_5POINT1 and KSAUDIO_SPEAKER_7POINT1 are similarly obsolete but are unchanged for compatibility reasons). */ #define PAWIN_SPEAKER_5POINT1_BACK PAWIN_SPEAKER_5POINT1 #define PAWIN_SPEAKER_7POINT1_WIDE PAWIN_SPEAKER_7POINT1 /* DVD Speaker Positions */ #define PAWIN_SPEAKER_GROUND_FRONT_LEFT PAWIN_SPEAKER_FRONT_LEFT #define PAWIN_SPEAKER_GROUND_FRONT_CENTER PAWIN_SPEAKER_FRONT_CENTER #define PAWIN_SPEAKER_GROUND_FRONT_RIGHT PAWIN_SPEAKER_FRONT_RIGHT #define PAWIN_SPEAKER_GROUND_REAR_LEFT PAWIN_SPEAKER_BACK_LEFT #define PAWIN_SPEAKER_GROUND_REAR_RIGHT PAWIN_SPEAKER_BACK_RIGHT #define PAWIN_SPEAKER_TOP_MIDDLE PAWIN_SPEAKER_TOP_CENTER #define PAWIN_SPEAKER_SUPER_WOOFER PAWIN_SPEAKER_LOW_FREQUENCY /* PaWinWaveFormat is defined here to provide compatibility with compilation environments which don't have headers defining WAVEFORMATEXTENSIBLE (e.g. older versions of MSVC, Borland C++ etc. The fields for WAVEFORMATEX and WAVEFORMATEXTENSIBLE are declared as an unsigned char array here to avoid clients who include this file having a dependency on windows.h and mmsystem.h, and also to to avoid having to write separate packing pragmas for each compiler. */ #define PAWIN_SIZEOF_WAVEFORMATEX 18 #define PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE (PAWIN_SIZEOF_WAVEFORMATEX + 22) typedef struct{ unsigned char fields[ PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE ]; unsigned long extraLongForAlignment; /* ensure that compiler aligns struct to DWORD */ } PaWinWaveFormat; /* WAVEFORMATEXTENSIBLE fields: union { WORD wValidBitsPerSample; WORD wSamplesPerBlock; WORD wReserved; } Samples; DWORD dwChannelMask; GUID SubFormat; */ #define PAWIN_INDEXOF_WVALIDBITSPERSAMPLE (PAWIN_SIZEOF_WAVEFORMATEX+0) #define PAWIN_INDEXOF_DWCHANNELMASK (PAWIN_SIZEOF_WAVEFORMATEX+2) #define PAWIN_INDEXOF_SUBFORMAT (PAWIN_SIZEOF_WAVEFORMATEX+6) /* Use the following two functions to initialize the waveformat structure. */ void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, int numChannels, PaSampleFormat sampleFormat, double sampleRate ); void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, int numChannels, PaSampleFormat sampleFormat, double sampleRate, PaWinWaveFormatChannelMask channelMask ); /* Map a channel count to a speaker channel mask */ PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PA_WIN_WAVEFORMAT_H */nyquist-3.05/portaudio/build/0002755000175000000620000000000011537433131015273 5ustar stevestaffnyquist-3.05/portaudio/build/vc_7/0002755000175000000620000000000011537433131016131 5ustar stevestaffnyquist-3.05/portaudio/build/msvc/0002755000175000000620000000000011537433131016243 5ustar stevestaffnyquist-3.05/portaudio/build/msvc/portaudio.dsw0000644000175000000620000000103711466723256021002 0ustar stevestaffMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "portaudio"=".\portaudio.dsp" - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### nyquist-3.05/portaudio/build/msvc/portaudio.vcproj0000644000175000000620000011741111466723256021514 0ustar stevestaff nyquist-3.05/portaudio/build/msvc/portaudio.def0000644000175000000620000000312211466723256020740 0ustar stevestaffEXPORTS ; Pa_GetVersion @1 Pa_GetVersionText @2 Pa_GetErrorText @3 Pa_Initialize @4 Pa_Terminate @5 Pa_GetHostApiCount @6 Pa_GetDefaultHostApi @7 Pa_GetHostApiInfo @8 Pa_HostApiTypeIdToHostApiIndex @9 Pa_HostApiDeviceIndexToDeviceIndex @10 Pa_GetLastHostErrorInfo @11 Pa_GetDeviceCount @12 Pa_GetDefaultInputDevice @13 Pa_GetDefaultOutputDevice @14 Pa_GetDeviceInfo @15 Pa_IsFormatSupported @16 Pa_OpenStream @17 Pa_OpenDefaultStream @18 Pa_CloseStream @19 Pa_SetStreamFinishedCallback @20 Pa_StartStream @21 Pa_StopStream @22 Pa_AbortStream @23 Pa_IsStreamStopped @24 Pa_IsStreamActive @25 Pa_GetStreamInfo @26 Pa_GetStreamTime @27 Pa_GetStreamCpuLoad @28 Pa_ReadStream @29 Pa_WriteStream @30 Pa_GetStreamReadAvailable @31 Pa_GetStreamWriteAvailable @32 Pa_GetSampleSize @33 Pa_Sleep @34 PaAsio_GetAvailableLatencyValues @50 PaAsio_ShowControlPanel @51 PaUtil_InitializeX86PlainConverters @52 PaAsio_GetInputChannelName @53 PaAsio_GetOutputChannelName @54 PaUtil_SetDebugPrintFunction @55nyquist-3.05/portaudio/build/msvc/portaudio.sln0000644000175000000620000000232411466723256021001 0ustar stevestaff Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portaudio", "portaudio.vcproj", "{0A18A071-125E-442F-AFF7-A3F68ABECF99}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug|Win32 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug|Win32 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.ActiveCfg = Debug|x64 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.Build.0 = Debug|x64 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.ActiveCfg = Release|Win32 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|Win32.Build.0 = Release|Win32 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.ActiveCfg = Release|x64 {0A18A071-125E-442F-AFF7-A3F68ABECF99}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal nyquist-3.05/portaudio/build/msvc/readme.txt0000644000175000000620000000622111466723256020253 0ustar stevestaffHello This is a small list of steps in order to build portaudio (Currently v19-devel) into a VC6 DLL and lib file. This DLL contains all 3 current win32 PA APIS (MM/DS/ASIO) 1)Copy the source dirs that comes with the ASIO SDK inside src\hostapi\asio\ASIOSDK so you should now have example: portaudio19svn\src\hostapi\asio\ASIOSDK\common portaudio19svn\src\hostapi\asio\ASIOSDK\host portaudio19svn\src\hostapi\asio\ASIOSDK\host\sample portaudio19svn\src\hostapi\asio\ASIOSDK\host\pc portaudio19svn\src\hostapi\asio\ASIOSDK\host\mac (not needed) You dont need "driver" 2) *If you have Visual Studio 6.0*, please make sure you have it updated with the latest (and final) microsoft libraries for it, namely: Service pack 5: Latest known URL: http://msdn2.microsoft.com/en-us/vstudio/aa718363.aspx Yes there EXISTS a service pack 6 , but the processor pack (below) isnt compatible with it. Processor Pack(only works with above SP5) Latest known URL: http://msdn2.microsoft.com/en-us/vstudio/Aa718349.aspx This isnt absolutely required for portaudio, but if you plan on using SSE intrinsics and similar things. Up to you to decide upon Service pack 5 or 6 depending on your need for intrinsics. Platform SDK (Feb 2003) : Latest known URL: http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm (This will allow your code base to be x64 friendly, with correct defines for LONG_PTR and such) NOTE A) Yes you have to use IE activex scripts to install that - wont work in Firefox, you may have to temporarily change tyour default browser(aint life unfair) NOTE B) Dont forget to hit "Register PSDK Directories with Visual Studio". you can make sure its right in VC6 if you open tools/options/directories/include files and you see SDK 2003 as the FIRST entry (it must be the same for libs) DirectX 9.0 SDK Update - (Summer 2003) Latest known URL: http://www.microsoft.com/downloads/details.aspx?familyid=9216652f-51e0-402e-b7b5-feb68d00f298&displaylang=en Again register the links in VC6, and check inside vc6 if headers are in second place right after SDk 2003 *If you have 7.0(VC.NET/2001) or 7.1(VC.2003) * then I suggest you open portaudio.dsp (and convert if needed) *If you have Visual Studio 2005*, I suggest you open the portaudio.sln file which contains 4 configurations. Win32/x64 in both Release and Debug variants hit compile and hope for the best. 3)Now in any project, in which you require portaudio, you can just link with portaudio_x86.lib, (or _x64) and of course include the relevant headers (portaudio.h, and/or pa_asio.h , pa_x86_plain_converters.h) See (*) 4) Your new exe should now use portaudio_xXX.dll. Have fun! (*): you may want to add/remove some DLL entry points. Right now those 6 entries are _not_ from portaudio.h (from portaudio.def) (...) PaAsio_GetAvailableLatencyValues @50 PaAsio_ShowControlPanel @51 PaUtil_InitializeX86PlainConverters @52 PaAsio_GetInputChannelName @53 PaAsio_GetOutputChannelName @54 PaUtil_SetLogPrintFunction @55 ----- David Viens, davidv@plogue.comnyquist-3.05/portaudio/build/msvc/portaudio.dsp0000644000175000000620000002073611466723256021002 0ustar stevestaff# Microsoft Developer Studio Project File - Name="portaudio" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=portaudio - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "portaudio.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "portaudio.mak" CFG="portaudio - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "portaudio - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "portaudio - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "portaudio - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release_x86" # PROP BASE Intermediate_Dir "Release_x86" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release_x86" # PROP Intermediate_Dir "Release_x86" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\src\common" /I "..\..\include" /I ".\\" /I "..\..\src\os\win" /D "WIN32" /D "NDEBUG" /D "_USRDLL" /D "PA_ENABLE_DEBUG_OUTPUT" /D "_CRT_SECURE_NO_DEPRECATE" /D "PAWIN_USE_WDMKS_DEVICE_INFO" /FD /c # SUBTRACT CPP /YX /Yc /Yu # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /machine:I386 /out:"./Release_x86/portaudio_x86.dll" !ELSEIF "$(CFG)" == "portaudio - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug_x86" # PROP BASE Intermediate_Dir "Debug_x86" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug_x86" # PROP Intermediate_Dir "Debug_x86" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\src\common" /I "..\..\include" /I ".\\" /I "..\..\src\os\win" /D "WIN32" /D "_DEBUG" /D "_USRDLL" /D "PA_ENABLE_DEBUG_OUTPUT" /D "_CRT_SECURE_NO_DEPRECATE" /D "PAWIN_USE_WDMKS_DEVICE_INFO" /FD /GZ /c # SUBTRACT CPP /YX /Yc /Yu # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /debug /machine:I386 /out:"./Debug_x86/portaudio_x86.dll" /pdbtype:sept !ENDIF # Begin Target # Name "portaudio - Win32 Release" # Name "portaudio - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Group "common" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\common\pa_allocation.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_converters.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_cpuload.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_debugprint.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_dither.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_front.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_process.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_skeleton.c # End Source File # Begin Source File SOURCE=..\..\src\common\pa_stream.c # End Source File # End Group # Begin Group "hostapi" # PROP Default_Filter "" # Begin Group "ASIO" # PROP Default_Filter "" # Begin Group "ASIOSDK" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\asio.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\host\ASIOConvertSamples.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\host\asiodrivers.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\host\pc\asiolist.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\combase.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\debugmessage.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # Begin Source File SOURCE=..\..\src\hostapi\asio\ASIOSDK\common\register.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # End Group # Begin Source File SOURCE=..\..\src\hostapi\asio\pa_asio.cpp # ADD CPP /I "..\..\src\hostapi\asio\ASIOSDK\host" /I "..\..\src\hostapi\asio\ASIOSDK\host\pc" /I "..\..\src\hostapi\asio\ASIOSDK\common" # End Source File # End Group # Begin Group "dsound" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\hostapi\dsound\pa_win_ds.c # End Source File # Begin Source File SOURCE=..\..\src\hostapi\dsound\pa_win_ds_dynlink.c # End Source File # End Group # Begin Group "wmme" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\hostapi\wmme\pa_win_wmme.c # End Source File # End Group # Begin Group "wasapi" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\hostapi\wasapi\pa_win_wasapi.cpp # End Source File # End Group # Begin Group "wdm-ks" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\hostapi\wdmks\pa_win_wdmks.c # End Source File # End Group # End Group # Begin Group "os" # PROP Default_Filter "" # Begin Group "win" # PROP Default_Filter "" # Begin Source File SOURCE=..\..\src\os\win\pa_win_hostapis.c # End Source File # Begin Source File SOURCE=..\..\src\os\win\pa_win_util.c # End Source File # Begin Source File SOURCE=..\..\src\os\win\pa_win_waveformat.c # End Source File # Begin Source File SOURCE=..\..\src\os\win\pa_win_wdmks_utils.c # End Source File # Begin Source File SOURCE=..\..\src\os\win\pa_x86_plain_converters.c # End Source File # End Group # End Group # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # Begin Source File SOURCE=.\portaudio.def # End Source File # End Group # End Target # End Project nyquist-3.05/portaudio/build/scons/0002755000175000000620000000000011537433131016420 5ustar stevestaffnyquist-3.05/portaudio/build/scons/SConscript_common0000644000175000000620000000220411466723256022011 0ustar stevestaffimport os.path, sys class ConfigurationError(Exception): def __init__(self, reason): Exception.__init__(self, "Configuration failed: %s" % reason) env = Environment() # sunos, aix, hpux, irix, sunos appear to be platforms known by SCons, assuming they're POSIX compliant Posix = ("linux", "darwin", "sunos", "aix", "hpux", "irix", "sunos") Windows = ("win32", "cygwin") if env["PLATFORM"] == "posix": if sys.platform[:5] == "linux": Platform = "linux" else: raise ConfigurationError("Unknown platform %s" % sys.platform) else: if not env["PLATFORM"] in ("win32", "cygwin") + Posix: raise ConfigurationError("Unknown platform %s" % env["PLATFORM"]) Platform = env["PLATFORM"] # Inspired by the versioning scheme followed by Qt, it seems sensible enough. There are three components: major, minor # and micro. Major changes with each subtraction from the API (backward-incompatible, i.e. V19 vs. V18), minor changes # with each addition to the API (backward-compatible), micro changes with each revision of the source code. ApiVer = "2.0.0" Export("Platform", "Posix", "ConfigurationError", "ApiVer") nyquist-3.05/portaudio/build/scons/SConscript_opts0000644000175000000620000001005611466723256021512 0ustar stevestaffimport os.path, sys def _PackageOption(pkgName, default=1): """ Allow user to choose whether a package should be used if available. This results in a commandline option use, where Pkgname is the name of the package with a capitalized first letter. @param pkgName: Name of package. @param default: The default value for this option ("yes"/"no"). """ return BoolOption("use%s" % pkgName[0].upper() + pkgName[1:], "use %s if available" % (pkgName), default) def _BoolOption(opt, explanation, default=1): """ Allow user to enable/disable a certain option. This results in a commandline option enable

    The cl:debug:mv function can be used to debug multiple value expressions:

  • POSIX Threads for Windows – REFERENCE - Pthreads-w32